From 4d66775a569c628d8cbc29f888e48d61835cf2eb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 23 Oct 2014 12:54:13 +0200 Subject: [PATCH 0001/2553] stream: improve bad window update detection Ignore more valid ACKs in FIN shutdown phase. Improve heuristic for window shrinking in case of packet loss. --- src/stream-tcp.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index d4ea8d909173..dcde855a5f57 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4251,7 +4251,7 @@ static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p) if (p->flags & PKT_PSEUDO_STREAM_END) return 0; - if (ssn->state != TCP_TIME_WAIT) + if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK)) return 0; if (p->tcph->th_flags != TH_ACK) return 0; @@ -4288,9 +4288,10 @@ static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p) * * The logic we use here is: * - packet seq > next_seq - * - packet acq > next_seq (packet acks unseen data) + * - packet ack > next_seq (packet acks unseen data) * - packet shrinks window more than it's own data size - * (in case of no data, any shrinking is rejected) + * - packet shrinks window more than the diff between it's ack and the + * last_ack value * * Packets coming in after packet loss can look quite a bit like this. */ @@ -4304,7 +4305,7 @@ static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p) if (p->flags & PKT_PSEUDO_STREAM_END) return 0; - if (ssn->state < TCP_ESTABLISHED) + if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED) return 0; if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0) @@ -4333,12 +4334,25 @@ static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p) p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len); SCLogDebug("%"PRIu64", pkt_win %u, stream win %u", p->pcap_cnt, pkt_win, ostream->window); - SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u stream->last_ack %u, diff %u (%u)", - p->pcap_cnt, seq, ack, ostream->next_seq, stream->last_ack, - ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack); - - StreamTcpSetEvent(p, STREAM_PKT_BAD_WINDOW_UPDATE); - return 1; + SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)", + p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win, + ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack); + + /* get the expected window shrinking from looking at ack vs last_ack. + * Observed a lot of just a little overrunning that value. So added some + * margin that is still ok. To make sure this isn't a loophole to still + * close the window, this is limited to windows above 1024. Both values + * are rather arbitrary. */ + uint32_t adiff = ack - ostream->last_ack; + if (((pkt_win > 1024) && (diff > (adiff + 32))) || + ((pkt_win <= 1024) && (diff > adiff))) + { + SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u " + "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win); + SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state); + StreamTcpSetEvent(p, STREAM_PKT_BAD_WINDOW_UPDATE); + return 1; + } } } From 74ffa2b26456f5e01eea45ece9b77cf8443c5160 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 18 Oct 2014 13:20:52 +0200 Subject: [PATCH 0002/2553] lua: move function to common utils LuaStateNeedProto function can be used for any protocol so let's move it out of the http file. --- src/util-lua-common.c | 20 ++++++++++++++++++++ src/util-lua-common.h | 2 ++ src/util-lua-http.c | 20 -------------------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/util-lua-common.c b/src/util-lua-common.c index d89007738e36..54c236de87d3 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -747,4 +747,24 @@ int LuaRegisterFunctions(lua_State *luastate) return 0; } +int LuaStateNeedProto(lua_State *luastate, AppProto alproto) +{ + AppProto flow_alproto = 0; + int locked = 0; + Flow *flow = LuaStateGetFlow(luastate, &locked); + if (flow == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + if (locked == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + FLOWLOCK_RDLOCK(flow); + flow_alproto = flow->alproto; + FLOWLOCK_UNLOCK(flow); + } else { + flow_alproto = flow->alproto; + } + + return (alproto == flow_alproto); + +} + #endif /* HAVE_LUA */ diff --git a/src/util-lua-common.h b/src/util-lua-common.h index fe048fe68e0d..2e0df28751a1 100644 --- a/src/util-lua-common.h +++ b/src/util-lua-common.h @@ -35,6 +35,8 @@ void LuaPushTableKeyValueArray(lua_State *luastate, const char *key, const uint8 int LuaRegisterFunctions(lua_State *luastate); +int LuaStateNeedProto(lua_State *luastate, AppProto alproto); + #endif /* HAVE_LUA */ #endif /* __UTIL_LUA_COMMON_H__ */ diff --git a/src/util-lua-http.c b/src/util-lua-http.c index e5957afdd47e..3d97b0f640ac 100644 --- a/src/util-lua-http.c +++ b/src/util-lua-http.c @@ -56,26 +56,6 @@ #include "util-lua.h" #include "util-lua-common.h" -int LuaStateNeedProto(lua_State *luastate, AppProto alproto) -{ - AppProto flow_alproto = 0; - int locked = 0; - Flow *flow = LuaStateGetFlow(luastate, &locked); - if (flow == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - if (locked == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(flow); - flow_alproto = flow->alproto; - FLOWLOCK_UNLOCK(flow); - } else { - flow_alproto = flow->alproto; - } - - return (alproto == flow_alproto); - -} - static int HttpGetRequestHost(lua_State *luastate) { if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP))) From 667b9a5220bd85453f3bbbf5aadb156673a741e4 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 18 Oct 2014 19:38:12 +0200 Subject: [PATCH 0003/2553] lua: add export of dns.rrname Add the capability for a lua script to ask for rrname in DNS query. --- src/Makefile.am | 1 + src/detect-lua-extensions.c | 2 + src/detect-lua.c | 19 +++++++ src/util-lua-dns.c | 100 ++++++++++++++++++++++++++++++++++++ src/util-lua-dns.h | 33 ++++++++++++ 5 files changed, 155 insertions(+) create mode 100644 src/util-lua-dns.c create mode 100644 src/util-lua-dns.h diff --git a/src/Makefile.am b/src/Makefile.am index 8213892f1805..ee9b654e2394 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -321,6 +321,7 @@ util-logopenfile.h util-logopenfile.c \ util-logopenfile-tile.h util-logopenfile-tile.c \ util-lua.c util-lua.h \ util-lua-common.c util-lua-common.h \ +util-lua-dns.c util-lua-dns.h \ util-lua-http.c util-lua-http.h \ util-magic.c util-magic.h \ util-memcmp.c util-memcmp.h \ diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index 6d63e708e1b9..c58ffa2843e9 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -65,6 +65,7 @@ #include "util-lua.h" #include "util-lua-common.h" #include "util-lua-http.h" +#include "util-lua-dns.h" static const char luaext_key_ld[] = "suricata:luajitdata"; static const char luaext_key_det_ctx[] = "suricata:det_ctx"; @@ -613,6 +614,7 @@ int LuaRegisterExtensions(lua_State *lua_state) LuaRegisterFunctions(lua_state); LuaRegisterHttpFunctions(lua_state); + LuaRegisterDnsFunctions(lua_state); return 0; } diff --git a/src/detect-lua.c b/src/detect-lua.c index 21a318104c5a..d711cb6eb1bf 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -155,6 +155,8 @@ void DetectLuaRegister(void) #define DATATYPE_HTTP_RESPONSE_HEADERS (1<<13) #define DATATYPE_HTTP_RESPONSE_HEADERS_RAW (1<<14) +#define DATATYPE_DNS_RRNAME (1<<15) + #ifdef HAVE_LUAJIT static void *LuaStatePoolAlloc(void) { @@ -938,7 +940,22 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) SCLogError(SC_ERR_LUA_ERROR, "alloc error"); goto error; } + } else if (strncmp(k, "dns", 3) == 0 && strcmp(v, "true") == 0) { + + ld->alproto = ALPROTO_DNS; + + if (strcmp(k, "dns.rrname") == 0) + ld->flags |= DATATYPE_DNS_RRNAME; + else { + SCLogError(SC_ERR_LUA_ERROR, "unsupported dns data type %s", k); + goto error; + } + ld->buffername = SCStrdup(k); + if (ld->buffername == NULL) { + SCLogError(SC_ERR_LUA_ERROR, "alloc error"); + goto error; + } } else { SCLogError(SC_ERR_LUA_ERROR, "unsupported data type %s", k); goto error; @@ -1026,6 +1043,8 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); else SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + } else if (luajit->alproto == ALPROTO_DNS) { + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSQUERY_MATCH); } else { SCLogError(SC_ERR_LUA_ERROR, "luajit can't be used with protocol %s", AppLayerGetProtoName(luajit->alproto)); diff --git a/src/util-lua-dns.c b/src/util-lua-dns.c new file mode 100644 index 000000000000..8ac0688d0136 --- /dev/null +++ b/src/util-lua-dns.c @@ -0,0 +1,100 @@ +/* Copyright (C) 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 Eric Leblond + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "app-layer-dns-common.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util-privs.h" +#include "util-buffer.h" +#include "util-proto-name.h" +#include "util-logopenfile.h" +#include "util-time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" +#include "util-lua-common.h" + +static int DnsGetDnsRrname(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &tx->query_list, next) { + char *c; + size_t input_len; + c = BytesToString((uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)), query->len); + if (c != NULL) { + int ret; + input_len = strlen(c); + /* sanity check */ + if (input_len > (size_t)(2 * query->len)) { + SCFree(c); + return LuaCallbackError(luastate, "invalid length"); + } + ret = LuaPushStringBuffer(luastate, (uint8_t *)c, input_len); + SCFree(c); + return ret; + } + } + + return LuaCallbackError(luastate, "no query"); +} + +/** \brief register http lua extensions in a luastate */ +int LuaRegisterDnsFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, DnsGetDnsRrname); + lua_setglobal(luastate, "DnsGetDnsRrname"); + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-dns.h b/src/util-lua-dns.h new file mode 100644 index 000000000000..582fdea75715 --- /dev/null +++ b/src/util-lua-dns.h @@ -0,0 +1,33 @@ +/* Copyright (C) 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 Eric Leblond + */ + +#ifndef __UTIL_LUA_DNS_H__ +#define __UTIL_LUA_DNS_H__ + +#ifdef HAVE_LUA + +int LuaRegisterDnsFunctions(lua_State *luastate); + +#endif /* HAVE_LUA */ + +#endif /* __UTIL_LUA_HTTP_H__ */ From a1d8439b2537e366cdb308f7b14155a1b503ee26 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Fri, 29 Aug 2014 14:22:09 +0200 Subject: [PATCH 0004/2553] iprep: extends cidr support Implements new API to expand the IP reputation to netblocks with CIDR notation A new object 'srepCIDRTree' is kept in the DetectionEngineCtx, which contains two tree (one for ipv4 and one for ipv6) where the reputation values are stored. --- src/detect.h | 4 + src/reputation.c | 200 ++++++++++++++++++++++++++++++++++++++++------- src/reputation.h | 15 +++- 3 files changed, 188 insertions(+), 31 deletions(-) diff --git a/src/detect.h b/src/detect.h index a3a7d4a7defc..cc23fe3028d4 100644 --- a/src/detect.h +++ b/src/detect.h @@ -39,6 +39,7 @@ #include "util-error.h" #include "util-radix-tree.h" #include "util-file.h" +#include "reputation.h" #include "detect-mark.h" @@ -586,6 +587,9 @@ typedef struct DetectEngineCtx_ { /* 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 */ diff --git a/src/reputation.c b/src/reputation.c index f84c1a8808f9..f8f4c620538b 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -57,11 +57,116 @@ static uint32_t SRepGetVersion(void) return srep_version; } +void SRepResetVersion(void) +{ + srep_version = 0; +} + static uint32_t SRepGetEffectiveVersion(void) { return SC_ATOMIC_GET(srep_eversion); } +static void SRepCIDRFreeUserData(void *data) +{ + if (data != NULL) + SCFree(data); + + return; +} + +static void SRepCIDRAddNetblock(SRepCIDRTree *cidr_ctx, char *ip, int cat, int value) +{ + SReputation *user_data = NULL; + if ((user_data = SCMalloc(sizeof(SReputation))) == NULL) { + SCLogError(SC_ERR_FATAL, "Error allocating memory. Exiting"); + exit(EXIT_FAILURE); + } + memset(user_data, 0x00, sizeof(SReputation)); + + user_data->version = SRepGetVersion(); + user_data->rep[cat] = value; + + if (strchr(ip, ':') != NULL) { + if (cidr_ctx->srepIPV6_tree[cat] == NULL) { + cidr_ctx->srepIPV6_tree[cat] = SCRadixCreateRadixTree(SRepCIDRFreeUserData, NULL); + if (cidr_ctx->srepIPV6_tree[cat] == NULL) { + SCLogDebug("Error initializing Reputation IPV6 with CIDR module for cat %d", cat); + exit(EXIT_FAILURE); + } + SCLogDebug("Reputation IPV6 with CIDR module for cat %d initialized", cat); + } + + SCLogDebug("adding ipv6 host %s", ip); + if (SCRadixAddKeyIPV6String(ip, cidr_ctx->srepIPV6_tree[cat], (void *)user_data) == NULL) { + SCLogWarning(SC_ERR_INVALID_VALUE, + "failed to add ipv6 host %s", ip); + } + + } else { + if (cidr_ctx->srepIPV4_tree[cat] == NULL) { + cidr_ctx->srepIPV4_tree[cat] = SCRadixCreateRadixTree(SRepCIDRFreeUserData, NULL); + if (cidr_ctx->srepIPV4_tree[cat] == NULL) { + SCLogDebug("Error initializing Reputation IPV4 with CIDR module for cat %d", cat); + exit(EXIT_FAILURE); + } + SCLogDebug("Reputation IPV4 with CIDR module for cat %d initialized", cat); + } + + SCLogDebug("adding ipv4 host %s", ip); + if (SCRadixAddKeyIPV4String(ip, cidr_ctx->srepIPV4_tree[cat], (void *)user_data) == NULL) { + SCLogWarning(SC_ERR_INVALID_VALUE, + "failed to add ipv4 host %s", ip); + } + } +} + +static uint8_t SRepCIDRGetIPv4IPRep(SRepCIDRTree *cidr_ctx, uint8_t *ipv4_addr, uint8_t cat) +{ + void *user_data = NULL; + (void)SCRadixFindKeyIPV4BestMatch(ipv4_addr, cidr_ctx->srepIPV4_tree[cat], &user_data); + if (user_data == NULL) + return 0; + + SReputation *r = (SReputation *)user_data; + return r->rep[cat]; +} + +static uint8_t SRepCIDRGetIPv6IPRep(SRepCIDRTree *cidr_ctx, uint8_t *ipv6_addr, uint8_t cat) +{ + void *user_data = NULL; + (void)SCRadixFindKeyIPV6BestMatch(ipv6_addr, cidr_ctx->srepIPV6_tree[cat], &user_data); + if (user_data == NULL) + return 0; + + SReputation *r = (SReputation *)user_data; + return r->rep[cat]; +} + +uint8_t SRepCIDRGetIPRepSrc(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version) +{ + uint8_t rep = 0; + + if (PKT_IS_IPV4(p)) + rep = SRepCIDRGetIPv4IPRep(cidr_ctx, (uint8_t *)GET_IPV4_SRC_ADDR_PTR(p), cat); + else if (PKT_IS_IPV6(p)) + rep = SRepCIDRGetIPv6IPRep(cidr_ctx, (uint8_t *)GET_IPV6_SRC_ADDR(p), cat); + + return rep; +} + +uint8_t SRepCIDRGetIPRepDst(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version) +{ + uint8_t rep = 0; + + if (PKT_IS_IPV4(p)) + rep = SRepCIDRGetIPv4IPRep(cidr_ctx, (uint8_t *)GET_IPV4_DST_ADDR_PTR(p), cat); + else if (PKT_IS_IPV6(p)) + rep = SRepCIDRGetIPv6IPRep(cidr_ctx, (uint8_t *)GET_IPV6_DST_ADDR(p), cat); + + return rep; +} + /** \brief Increment effective reputation version after * a rule/reputatio reload is complete. */ void SRepReloadComplete(void) @@ -162,7 +267,7 @@ static int SRepCatSplitLine(char *line, uint8_t *cat, char *shortname, size_t sh * \retval 1 header * \retval -1 boo */ -static int SRepSplitLine(char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) +static int SRepSplitLine(SRepCIDRTree *cidr_ctx, char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) { size_t line_len = strlen(line); char *ptrs[3] = {NULL,NULL,NULL}; @@ -200,11 +305,6 @@ static int SRepSplitLine(char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) if (strcmp(ptrs[0], "ip") == 0) return 1; - uint32_t addr; - if (inet_pton(AF_INET, ptrs[0], &addr) <= 0) { - return -1; - } - int c = atoi(ptrs[1]); if (c < 0 || c >= SREP_MAX_CATS) { return -1; @@ -215,9 +315,20 @@ static int SRepSplitLine(char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) return -1; } - *ip = addr; - *cat = c; - *value = v; + if (strchr(ptrs[0], '/') != NULL) { + SRepCIDRAddNetblock(cidr_ctx, ptrs[0], c, v); + return 1; + } else { + uint32_t addr; + if (inet_pton(AF_INET, ptrs[0], &addr) <= 0) { + return -1; + } + + *ip = addr; + *cat = c; + *value = v; + } + return 0; } @@ -246,7 +357,24 @@ uint8_t SRepCatGetByShortname(char *shortname) return 0; } -int SRepLoadCatFile(char *filename) +static int SRepLoadCatFile(char *filename) +{ + int r = 0; + FILE *fp = fopen(filename, "r"); + + if (fp == NULL) { + SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file %s: %s", filename, strerror(errno)); + return -1; + } + + r = SRepLoadCatFileFromFD(fp); + + fclose(fp); + fp = NULL; + return r; +} + +int SRepLoadCatFileFromFD(FILE *fp) { char line[8192] = ""; Address a; @@ -256,12 +384,6 @@ int SRepLoadCatFile(char *filename) BUG_ON(SRepGetVersion() > 0); - FILE *fp = fopen(filename, "r"); - if (fp == NULL) { - SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file %s: %s", filename, strerror(errno)); - return -1; - } - while(fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len == 0) @@ -290,8 +412,6 @@ int SRepLoadCatFile(char *filename) SCLogError(SC_ERR_NO_REPUTATION, "bad line \"%s\"", line); } } - fclose(fp); - fp = NULL; SCLogDebug("IP Rep categories:"); int i; @@ -303,19 +423,31 @@ int SRepLoadCatFile(char *filename) return 0; } -static int SRepLoadFile(char *filename) +static int SRepLoadFile(SRepCIDRTree *cidr_ctx, char *filename) { - char line[8192] = ""; - Address a; - memset(&a, 0x00, sizeof(a)); - a.family = AF_INET; - + int r = 0; FILE *fp = fopen(filename, "r"); + if (fp == NULL) { - SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file \"%s\": %s", filename, strerror(errno)); + SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file %s: %s", filename, strerror(errno)); return -1; } + r = SRepLoadFileFromFD(cidr_ctx, fp); + + fclose(fp); + fp = NULL; + return r; + +} + +int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp) +{ + char line[8192] = ""; + Address a; + memset(&a, 0x00, sizeof(a)); + a.family = AF_INET; + while(fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len == 0) @@ -338,7 +470,7 @@ static int SRepLoadFile(char *filename) uint32_t ip = 0; uint8_t cat = 0, value = 0; - int r = SRepSplitLine(line, &ip, &cat, &value); + int r = SRepSplitLine(cidr_ctx, line, &ip, &cat, &value); if (r < 0) { SCLogError(SC_ERR_NO_REPUTATION, "bad line \"%s\"", line); } else if (r == 0) { @@ -394,8 +526,6 @@ static int SRepLoadFile(char *filename) } } } - fclose(fp); - fp = NULL; return 0; } @@ -459,6 +589,18 @@ int SRepInit(DetectEngineCtx *de_ctx) char *sfile = NULL; char *filename = NULL; int init = 0; + int i = 0; + + de_ctx->srepCIDR_ctx = (SRepCIDRTree *)SCMalloc(sizeof(SRepCIDRTree)); + if (de_ctx->srepCIDR_ctx == NULL) + exit(EXIT_FAILURE); + memset(de_ctx->srepCIDR_ctx, 0, sizeof(SRepCIDRTree)); + SRepCIDRTree *cidr_ctx = de_ctx->srepCIDR_ctx; + + for (i = 0; i < SREP_MAX_CATS; i++) { + cidr_ctx->srepIPV4_tree[i] = NULL; + cidr_ctx->srepIPV6_tree[i] = NULL; + } if (SRepGetVersion() == 0) { SC_ATOMIC_INIT(srep_eversion); @@ -502,7 +644,7 @@ int SRepInit(DetectEngineCtx *de_ctx) sfile = SRepCompleteFilePath(file->val); SCLogInfo("Loading reputation file: %s", sfile); - r = SRepLoadFile(sfile); + r = SRepLoadFile(cidr_ctx, sfile); if (r < 0){ if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); diff --git a/src/reputation.h b/src/reputation.h index 4e35830d82ff..d489b1ff807c 100644 --- a/src/reputation.h +++ b/src/reputation.h @@ -26,17 +26,22 @@ #ifndef __REPUTATION_H__ #define __REPUTATION_H__ -#include "detect.h" #include "host.h" #define SREP_MAX_CATS 60 + +typedef struct SRepCIDRTree_ { + SCRadixTree *srepIPV4_tree[SREP_MAX_CATS]; + SCRadixTree *srepIPV6_tree[SREP_MAX_CATS]; +} SRepCIDRTree; + typedef struct SReputation_ { uint32_t version; uint8_t rep[SREP_MAX_CATS]; } SReputation; uint8_t SRepCatGetByShortname(char *shortname); -int SRepInit(DetectEngineCtx *de_ctx); +int SRepInit(struct DetectEngineCtx_ *de_ctx); void SRepReloadComplete(void); int SRepHostTimedOut(Host *); @@ -76,6 +81,12 @@ typedef struct IPReputationCtx_ { SCMutex reputationIPV6_lock; }IPReputationCtx; +uint8_t SRepCIDRGetIPRepSrc(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version); +uint8_t SRepCIDRGetIPRepDst(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version); +void SRepResetVersion(); +int SRepLoadCatFileFromFD(FILE *fp); +int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp); + /** Reputation Data */ //TODO: Add a timestamp here to know the last update of this reputation. typedef struct Reputation_ { From 5499cb71b097be10751fd873e7d784b42902edca Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Wed, 3 Sep 2014 15:30:08 +0200 Subject: [PATCH 0005/2553] detect-iprep: extends cidr Adds new API to check if an IP address is belong to a netblock and gets the value. --- src/detect-iprep.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/detect-iprep.c b/src/detect-iprep.c index 820bfee3aeaa..9a386056cdd2 100644 --- a/src/detect-iprep.c +++ b/src/detect-iprep.c @@ -197,11 +197,15 @@ int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, switch(rd->cmd) { case DETECT_IPREP_CMD_ANY: val = GetHostRepSrc(p, rd->cat, version); + if (val == 0) + val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val > 0) { if (RepMatch(rd->op, val, rd->val) == 1) return 1; } val = GetHostRepDst(p, rd->cat, version); + if (val == 0) + val = SRepCIDRGetIPRepDst(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } @@ -210,6 +214,8 @@ int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, case DETECT_IPREP_CMD_SRC: val = GetHostRepSrc(p, rd->cat, version); SCLogDebug("checking src -- val %u (looking for cat %u, val %u)", val, rd->cat, rd->val); + if (val == 0) + val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } @@ -218,6 +224,8 @@ int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, case DETECT_IPREP_CMD_DST: SCLogDebug("checking dst"); val = GetHostRepDst(p, rd->cat, version); + if (val == 0) + val = SRepCIDRGetIPRepDst(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } @@ -225,9 +233,13 @@ int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, case DETECT_IPREP_CMD_BOTH: val = GetHostRepSrc(p, rd->cat, version); + if (val == 0) + val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val == 0 || RepMatch(rd->op, val, rd->val) == 0) return 0; val = GetHostRepDst(p, rd->cat, version); + if (val == 0) + val = SRepCIDRGetIPRepDst(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } From 395d5b7f61ff4738f9e677fbd84346ca66fb51af Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Fri, 5 Sep 2014 15:58:44 +0200 Subject: [PATCH 0006/2553] iprep: add unit tests for cidr Implements unit tests to test the new API --- src/detect-iprep.c | 624 +++++++++++++++++++++++++++++++++++++++++++++ src/reputation.c | 158 +++++++++++- 2 files changed, 773 insertions(+), 9 deletions(-) diff --git a/src/detect-iprep.c b/src/detect-iprep.c index 9a386056cdd2..89b297a5f19c 100644 --- a/src/detect-iprep.c +++ b/src/detect-iprep.c @@ -41,6 +41,9 @@ #include "detect-engine-state.h" #include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-fmemopen.h" #include "reputation.h" #include "host.h" @@ -394,6 +397,618 @@ void DetectIPRepFree (void *ptr) } #ifdef UNITTESTS +FILE *DetectIPRepGenerateCategoriesDummy() +{ + FILE *fd = NULL; + const char *buffer = "1,BadHosts,Know bad hosts"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen()"); + + return fd; +} + +FILE *DetectIPRepGenerateCategoriesDummy2() +{ + FILE *fd = NULL; + const char *buffer = + "1,BadHosts,Know bad hosts\n" + "2,GoodHosts,Know good hosts\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen()"); + + return fd; +} + +FILE *DetectIPRepGenerateNetworksDummy() +{ + FILE *fd = NULL; + const char *buffer = "10.0.0.0/24,1,20"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen()"); + + return fd; +} + +FILE *DetectIPRepGenerateNetworksDummy2() +{ + FILE *fd = NULL; + const char *buffer = + "0.0.0.0/0,1,10\n" + "192.168.0.0/16,2,127"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen()"); + + return fd; +} + +static int DetectIPRepTest01(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("10.0.0.1"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:any,BadHosts,>,1; sid:1;rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest02(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("10.0.0.1"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:src,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest03(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->dst.addr_data32[0] = UTHSetIPv4Address("10.0.0.2"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:dst,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest04(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("10.0.0.1"); + p->dst.addr_data32[0] = UTHSetIPv4Address("10.0.0.2"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:both,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest05(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("1.0.0.1"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:any,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest06(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("1.0.0.1"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:any,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest07(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->dst.addr_data32[0] = UTHSetIPv4Address("1.0.0.2"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:any,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest08(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("1.0.0.1"); + p->dst.addr_data32[0] = UTHSetIPv4Address("1.0.0.2"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:any,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest09(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); + p->dst.addr_data32[0] = UTHSetIPv4Address("192.168.0.2"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy2(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy2(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"test\"; iprep:src,BadHosts,>,9; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} #endif /* UNITTESTS */ /** @@ -402,5 +1017,14 @@ void DetectIPRepFree (void *ptr) void IPRepRegisterTests(void) { #ifdef UNITTESTS + UtRegisterTest("DetectIPRepTest01", DetectIPRepTest01, 1); + UtRegisterTest("DetectIPRepTest02", DetectIPRepTest02, 1); + UtRegisterTest("DetectIPRepTest03", DetectIPRepTest03, 1); + UtRegisterTest("DetectIPRepTest04", DetectIPRepTest04, 1); + UtRegisterTest("DetectIPRepTest05", DetectIPRepTest05, 0); + UtRegisterTest("DetectIPRepTest06", DetectIPRepTest06, 0); + UtRegisterTest("DetectIPRepTest07", DetectIPRepTest07, 0); + UtRegisterTest("DetectIPRepTest08", DetectIPRepTest08, 0); + UtRegisterTest("DetectIPRepTest09", DetectIPRepTest09, 1); #endif /* UNITTESTS */ } diff --git a/src/reputation.c b/src/reputation.c index f8f4c620538b..bce8946ad7bd 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -665,41 +665,70 @@ int SRepInit(DetectEngineCtx *de_ctx) } #ifdef UNITTESTS + +#include "conf-yaml-loader.h" +#include "detect-engine.h" +#include "stream-tcp-private.h" +#include "stream-tcp-reassemble.h" +#include "stream-tcp.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + static int SRepTest01(void) { char str[] = "1.2.3.4,1,2"; + int result = 0; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return 0; + } + SRepInit(de_ctx); uint32_t ip = 0; uint8_t cat = 0, value = 0; - if (SRepSplitLine(str, &ip, &cat, &value) != 0) { - return 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &ip, &cat, &value) != 0) { + goto end; } char ipstr[16]; PrintInet(AF_INET, (const void *)&ip, ipstr, sizeof(ipstr)); if (strcmp(ipstr, "1.2.3.4") != 0) - return 0; + goto end; if (cat != 1) - return 0; + goto end; if (value != 2) - return 0; + goto end; - return 1; + result = 1; + +end: + DetectEngineCtxFree(de_ctx); + return result; } static int SRepTest02(void) { char str[] = "1.1.1.1,"; + int result = 0; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return 0; + } + SRepInit(de_ctx); uint32_t ip = 0; uint8_t cat = 0, value = 0; - if (SRepSplitLine(str, &ip, &cat, &value) == 0) { - return 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &ip, &cat, &value) == 0) { + goto end; } - return 1; + result = 1; + +end: + DetectEngineCtxFree(de_ctx); + return result; } static int SRepTest03(void) @@ -727,7 +756,115 @@ static int SRepTest03(void) return 1; } +static int SRepTest04(void) +{ + int result = 0; + + DetectEngineCtx *de_ctx; + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + SRepInit(de_ctx); + + char str[] = "10.0.0.0/16,1,2"; + + uint32_t ip = 0; + uint8_t cat = 0, value = 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &ip, &cat, &value) != 1) { + goto end; + } + + result = 1; + +end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int SRepTest05(void) +{ + Packet *p = NULL; + int result = 0; + uint8_t *buf = (uint8_t *)"Hi all!"; + uint16_t buflen = strlen((char *)buf); + + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + if (p == NULL) { + return result; + } + + p->src.addr_data32[0] = UTHSetIPv4Address("10.0.0.1"); + + DetectEngineCtx *de_ctx; + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return result; + } + SRepInit(de_ctx); + + char str[] = "10.0.0.0/16,1,20"; + + uint32_t ip = 0; + uint8_t cat = 0, value = 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &ip, &cat, &value) != 1) { + goto end; + } + cat = 1; + value = SRepCIDRGetIPRepSrc(de_ctx->srepCIDR_ctx, p, cat, 0); + if (value != 20) { + goto end; + } + result = 1; + +end: + UTHFreePacket(p); + DetectEngineCtxFree(de_ctx); + return result; +} +static int SRepTest06(void) +{ + Packet *p = NULL; + int result = 0; + uint8_t *buf = (uint8_t *)"Hi all!"; + uint16_t buflen = strlen((char *)buf); + + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + if (p == NULL) { + return result; + } + + p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); + + DetectEngineCtx *de_ctx; + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return result; + } + SRepInit(de_ctx); + + char str[] = + "0.0.0.0/0,1,10\n" + "192.168.0.0/16,2,127"; + + uint32_t ip = 0; + uint8_t cat = 0, value = 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &ip, &cat, &value) != 1) { + goto end; + } + cat = 1; + value = SRepCIDRGetIPRepSrc(de_ctx->srepCIDR_ctx, p, cat, 0); + if (value != 10) { + goto end; + } + result = 1; + +end: + UTHFreePacket(p); + DetectEngineCtxFree(de_ctx); + return result; +} #endif /** Global trees that hold host reputation for IPV4 and IPV6 hosts */ @@ -2162,6 +2299,9 @@ void SCReputationRegisterTests(void) UtRegisterTest("SRepTest01", SRepTest01, 1); UtRegisterTest("SRepTest02", SRepTest02, 1); UtRegisterTest("SRepTest03", SRepTest03, 1); + UtRegisterTest("SRepTest04", SRepTest04, 1); + UtRegisterTest("SRepTest05", SRepTest05, 1); + UtRegisterTest("SRepTest06", SRepTest06, 1); #endif /* UNITTESTS */ } From 2d43dae9346c7521e994f8270b62a5ee0fc6561c Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Thu, 23 Oct 2014 11:30:38 +0200 Subject: [PATCH 0007/2553] PF_RING: force cluster type if vlan is disabled If vlan is disabled the cluster_flow mode will still take VLAN tags into account due to using pf_ring's 6-tuple mode. So this forces to use pf_ring's 5-tuple mode. Bug #1292 --- src/source-pfring.c | 13 +++++++++++++ src/source-pfring.h | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index 45527fd99b30..753afe7f3b15 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -521,6 +521,19 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->vlan_disabled = 1; } + /* Since VLAN is disabled we force the cluster type to CLUSTER_FLOW_5_TUPLE */ + if (ptv->vlan_disabled == 1 && ptv->ctype == CLUSTER_FLOW) { + SCLogInfo("VLAN disabled, setting cluster type to CLUSTER_FLOW_5_TUPLE"); + rc = pfring_set_cluster(ptv->pd, ptv->cluster_id, CLUSTER_FLOW_5_TUPLE); + + if (rc != 0) { + SCLogError(SC_ERR_PF_RING_SET_CLUSTER_FAILED, "pfring_set_cluster " + "returned %d for cluster-id: %d", rc, ptv->cluster_id); + pfconf->DerefFunc(pfconf); + return TM_ECODE_FAILED; + } + } + *data = (void *)ptv; pfconf->DerefFunc(pfconf); diff --git a/src/source-pfring.h b/src/source-pfring.h index 7439828fb5d3..e0878454e12d 100644 --- a/src/source-pfring.h +++ b/src/source-pfring.h @@ -60,5 +60,5 @@ void PfringLoadConfig(void); /* We don't have to use an enum that sucks in our code */ #define CLUSTER_FLOW 0 #define CLUSTER_ROUND_ROBIN 1 - +#define CLUSTER_FLOW_5_TUPLE 4 #endif /* __SOURCE_PFRING_H__ */ From 07fffa6a7d1b32363b7e892019dc50927177888a Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Thu, 23 Oct 2014 11:43:04 +0200 Subject: [PATCH 0008/2553] Fixes comments for pfring section in suricata.yaml Bug #1301 --- suricata.yaml.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 562085ed3767..715c53e4cc49 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -872,7 +872,7 @@ mpipe: size16384: 0 # PF_RING configuration. for use with native PF_RING support -# for more info see http://www.ntop.org/PF_RING.html +# for more info see http://www.ntop.org/products/pf_ring/ pfring: - interface: eth0 # Number of receive threads (>1 will enable experimental flow pinned @@ -884,8 +884,8 @@ pfring: # clusterid. cluster-id: 99 - # Default PF_RING cluster type. PF_RING can load balance per flow or per hash. - # This is only supported in versions of PF_RING > 4.1.1. + # Default PF_RING cluster type. PF_RING can load balance per flow. + # Possible values are cluster_flow or cluster_round_robin. cluster-type: cluster_flow # bpf filter for this interface #bpf-filter: tcp From b2b1239ddfcadf15cda248f4297e727343e2171c Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Mon, 6 Oct 2014 11:40:58 -0400 Subject: [PATCH 0009/2553] Make AppLayerProfiling functions inline The entire body of these functions are protected by ifdef PROFILING. If the functions are inlined, then this check removes the need for the function entirely. Previously, the empty function was still called, even when not built for profiling. The functions showed as being 0.25% of total CPU time without being built for profiling. --- src/app-layer.c | 10 ++-------- src/app-layer.h | 24 ++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 4c7770c1ac13..77c2d4f95ae2 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -656,20 +656,14 @@ void AppLayerDestroyCtxThread(AppLayerThreadCtx *app_tctx) SCReturn; } -/* profiling */ - -void AppLayerProfilingReset(AppLayerThreadCtx *app_tctx) +void AppLayerProfilingResetInternal(AppLayerThreadCtx *app_tctx) { -#ifdef PROFILING PACKET_PROFILING_APP_RESET(app_tctx); -#endif } -void AppLayerProfilingStore(AppLayerThreadCtx *app_tctx, Packet *p) +void AppLayerProfilingStoreInternal(AppLayerThreadCtx *app_tctx, Packet *p) { -#ifdef PROFILING PACKET_PROFILING_APP_STORE(app_tctx, p); -#endif } /***** Unittests *****/ diff --git a/src/app-layer.h b/src/app-layer.h index 5d4f51ca3211..ca221d2dc1d8 100644 --- a/src/app-layer.h +++ b/src/app-layer.h @@ -31,6 +31,8 @@ #include "stream-tcp-reassemble.h" #include "stream.h" +#include "util-profiling.h" + #define APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER \ (~STREAM_TOSERVER & ~STREAM_TOCLIENT) @@ -108,8 +110,26 @@ AppLayerThreadCtx *AppLayerGetCtxThread(ThreadVars *tv); void AppLayerDestroyCtxThread(AppLayerThreadCtx *tctx); -void AppLayerProfilingReset(AppLayerThreadCtx *tctx); -void AppLayerProfilingStore(AppLayerThreadCtx *tctx, Packet *p); +/***** Profiling *****/ + +void AppLayerProfilingResetInternal(AppLayerThreadCtx *app_tctx); + +static inline void AppLayerProfilingReset(AppLayerThreadCtx *app_tctx) +{ +#ifdef PROFILING + AppLayerProfilingResetInternal(app_tctx); +#endif +} + +void AppLayerProfilingStoreInternal(AppLayerThreadCtx *app_tctx, Packet *p); + +static inline void AppLayerProfilingStore(AppLayerThreadCtx *app_tctx, Packet *p) +{ +#ifdef PROFILING + AppLayerProfilingStoreInternal(app_tctx, p); +#endif +} + /***** Unittests *****/ From 033409a042eccc1cba0d87b07fbd1c6ee7cb0cfe Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 26 Oct 2014 09:02:08 +0100 Subject: [PATCH 0010/2553] iprep: cleanup ctx on shutdown ~~Dr.M~~ Error #1: LEAK 480 direct bytes 0x0aae7fc0-0x0aae81a0 + 0 indirect bytes ~~Dr.M~~ # 0 replace_malloc [/work/drmemory_package/common/alloc_replace.c:2373] ~~Dr.M~~ # 1 SRepInit [.../Suricata/src/reputation.c:594] ~~Dr.M~~ # 2 DetectEngineCtxInit [.../src/detect-engine.c:844] ~~Dr.M~~ # 3 main [.../Suricata/src/suricata.c:2230] --- src/detect-engine.c | 1 + src/reputation.c | 20 ++++++++++++++++++++ src/reputation.h | 1 + 3 files changed, 22 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 6c60a8540f62..6b80748fbecb 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -916,6 +916,7 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) } DetectEngineCtxFreeThreadKeywordData(de_ctx); + SRepDestroy(de_ctx); SCFree(de_ctx); //DetectAddressGroupPrintMemory(); //DetectSigGroupPrintMemory(); diff --git a/src/reputation.c b/src/reputation.c index bce8946ad7bd..23484f08b05c 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -664,6 +664,26 @@ int SRepInit(DetectEngineCtx *de_ctx) return 0; } +void SRepDestroy(DetectEngineCtx *de_ctx) { + if (de_ctx->srepCIDR_ctx != NULL) { + int i; + for (i = 0; i < SREP_MAX_CATS; i++) { + if (de_ctx->srepCIDR_ctx->srepIPV4_tree[i] != NULL) { + SCRadixReleaseRadixTree(de_ctx->srepCIDR_ctx->srepIPV4_tree[i]); + de_ctx->srepCIDR_ctx->srepIPV4_tree[i] = NULL; + } + + if (de_ctx->srepCIDR_ctx->srepIPV6_tree[i] != NULL) { + SCRadixReleaseRadixTree(de_ctx->srepCIDR_ctx->srepIPV6_tree[i]); + de_ctx->srepCIDR_ctx->srepIPV6_tree[i] = NULL; + } + } + + SCFree(de_ctx->srepCIDR_ctx); + de_ctx->srepCIDR_ctx = NULL; + } +} + #ifdef UNITTESTS #include "conf-yaml-loader.h" diff --git a/src/reputation.h b/src/reputation.h index d489b1ff807c..347731fe7b4c 100644 --- a/src/reputation.h +++ b/src/reputation.h @@ -42,6 +42,7 @@ typedef struct SReputation_ { uint8_t SRepCatGetByShortname(char *shortname); int SRepInit(struct DetectEngineCtx_ *de_ctx); +void SRepDestroy(struct DetectEngineCtx_ *de_ctx); void SRepReloadComplete(void); int SRepHostTimedOut(Host *); From b2e80a0f661942dc2ee1899417039954c1856187 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 26 Oct 2014 10:07:15 +0100 Subject: [PATCH 0011/2553] stream: improve tracking with pkt loss in async If 3whs SYN/ACK and ACK are missing we can still pick up the session if in async-oneside mode. -> syn <- syn/ack <= missing -> ack <= missing -> data Bug 1190. --- src/stream-tcp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index dcde855a5f57..844d8e176376 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -1501,8 +1501,11 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, ,ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_seq); - ssn->client.wscale = TCP_WSCALE_MAX; - ssn->server.wscale = TCP_WSCALE_MAX; + /* if SYN had wscale, assume it to be supported. Otherwise + * we know it not to be supported. */ + if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) { + ssn->client.wscale = TCP_WSCALE_MAX; + } /* Set the timestamp values used to validate the timestamp of * received packets.*/ @@ -1521,6 +1524,9 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, ssn->flags |= STREAMTCP_FLAG_SACKOK; } + StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, + &ssn->client, p, pq); + } else { SCLogDebug("ssn %p: default case", ssn); } From 1656148490272a9b1f13dff7f5534e13e9b46bd2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 30 Oct 2014 10:16:40 +0100 Subject: [PATCH 0012/2553] stream/async: fix session setup issues For these 2 cases: 1. Missing SYN: -> syn <= missing <- syn/ack -> ack -> data 2. Missing SYN and 3whs ACK: -> syn <= missing <- syn/ack -> ack <= missing -> data Fix session pickup. The next_win settings weren't correctly set, so that packets were rejected. Bug 1190. --- src/stream-tcp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 844d8e176376..76b256bc9986 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -850,6 +850,8 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, ssn->client.last_ack = TCP_GET_ACK(p); ssn->server.last_ack = TCP_GET_SEQ(p); + ssn->server.next_win = ssn->server.last_ack + ssn->server.window; + /** If the client has a wscale option the server had it too, * so set the wscale for the server to max. Otherwise none * will have the wscale opt just like it should. */ @@ -1768,7 +1770,8 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, ssn->server.next_win = ssn->server.last_ack + ssn->server.window; if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) { - ssn->client.window = TCP_GET_WINDOW(p); + ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; + ssn->client.next_win = ssn->client.last_ack + ssn->client.window; ssn->server.next_win = ssn->server.last_ack + ssn->server.window; /* window scaling for midstream pickups, we can't do much From 503cc3de690be563762956f6639fcec16e7a1d79 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 30 Oct 2014 11:07:38 +0100 Subject: [PATCH 0013/2553] stream/async: improve handling of syn/ack pickup If we picked up the ssn with a syn/ack, we don't need to make more assumptions about sack and wscale after that. --- src/stream-tcp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 76b256bc9986..5bb30f614a8c 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -1774,11 +1774,13 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, ssn->client.next_win = ssn->client.last_ack + ssn->client.window; ssn->server.next_win = ssn->server.last_ack + ssn->server.window; - /* window scaling for midstream pickups, we can't do much - * other than assume that it's set to the max value: 14 */ - ssn->server.wscale = TCP_WSCALE_MAX; - ssn->client.wscale = TCP_WSCALE_MAX; - ssn->flags |= STREAMTCP_FLAG_SACKOK; + if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) { + /* window scaling for midstream pickups, we can't do much + * other than assume that it's set to the max value: 14 */ + ssn->server.wscale = TCP_WSCALE_MAX; + ssn->client.wscale = TCP_WSCALE_MAX; + ssn->flags |= STREAMTCP_FLAG_SACKOK; + } } StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); From a781fc5c2ea047c7ea3774edbf890001987b82cc Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Wed, 29 Oct 2014 15:43:42 -0400 Subject: [PATCH 0014/2553] Make suricata_ctl_flags be volatile The global variable suricata_ctl_flags needs to volatile, otherwise the compiler might not cause the variable to be read every time because it doesn't know other threads might write the variable. This was causing Suricata to not exit under some conditions. --- src/source-af-packet.c | 1 - src/source-erf-dag.c | 1 - src/source-mpipe.c | 2 -- src/source-napatech.c | 1 - src/source-pcap-file.c | 1 - src/source-pcap.c | 2 -- src/source-pfring.c | 1 - src/suricata.c | 2 +- src/suricata.h | 4 ++-- 9 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index f5858ac52248..1d67f0a51e48 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -96,7 +96,6 @@ #endif /* HAVE_AF_PACKET */ -extern uint8_t suricata_ctl_flags; extern int max_pending_packets; #ifndef HAVE_AF_PACKET diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index dbbd0774288e..a68910c35505 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -91,7 +91,6 @@ NoErfDagSupportExit(ThreadVars *tv, void *initdata, void **data) #define BYTES_PER_LOOP (4 * 1024 * 1024) /* 4 MB */ extern int max_pending_packets; -extern uint8_t suricata_ctl_flags; typedef struct ErfDagThreadVars_ { ThreadVars *tv; diff --git a/src/source-mpipe.c b/src/source-mpipe.c index a7278463676f..5bac179ab326 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -76,8 +76,6 @@ #define min(a,b) (((a) < (b)) ? (a) : (b)) -extern uint8_t suricata_ctl_flags; - /** storage for mpipe device names */ typedef struct MpipeDevice_ { char *dev; /**< the device (e.g. "xgbe1") */ diff --git a/src/source-napatech.c b/src/source-napatech.c index 18abd3aa6d09..6c577fecc2a1 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -79,7 +79,6 @@ TmEcode NoNapatechSupportExit(ThreadVars *tv, void *initdata, void **data) #include extern int max_pending_packets; -extern uint8_t suricata_ctl_flags; typedef struct NapatechThreadVars_ { ThreadVars *tv; diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index d4232bcebb6c..3202b0d8d4c7 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -57,7 +57,6 @@ #endif /* __SC_CUDA_SUPPORT__ */ -extern uint8_t suricata_ctl_flags; extern int max_pending_packets; //static int pcap_max_read_packets = 0; diff --git a/src/source-pcap.c b/src/source-pcap.c index 0bc76b9ce78a..bf51ff91ea88 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -54,8 +54,6 @@ #endif /* __SC_CUDA_SUPPORT__ */ -extern uint8_t suricata_ctl_flags; - #define PCAP_STATE_DOWN 0 #define PCAP_STATE_UP 1 diff --git a/src/source-pfring.c b/src/source-pfring.c index 753afe7f3b15..fb4aed73a7c1 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -71,7 +71,6 @@ TmEcode DecodePfring(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue TmEcode DecodePfringThreadDeinit(ThreadVars *tv, void *data); extern int max_pending_packets; -extern uint8_t suricata_ctl_flags; #ifndef HAVE_PFRING diff --git a/src/suricata.c b/src/suricata.c index 954982793956..5d756eb6d4c6 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -202,7 +202,7 @@ SC_ATOMIC_DECLARE(unsigned int, engine_stage); #define DEFAULT_MAX_PENDING_PACKETS 1024 /** suricata engine control flags */ -uint8_t suricata_ctl_flags = 0; +volatile uint8_t suricata_ctl_flags = 0; /** Run mode selected */ int run_mode = RUNMODE_UNKNOWN; diff --git a/src/suricata.h b/src/suricata.h index de0fb02f1122..573be0bb0aa9 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* 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 @@ -162,7 +162,7 @@ typedef struct SCInstance_ { /* memset to zeros, and mutex init! */ void GlobalInits(); -extern uint8_t suricata_ctl_flags; +extern volatile uint8_t suricata_ctl_flags; /* uppercase to lowercase conversion lookup table */ uint8_t g_u8_lowercasetable[256]; From c2dc6867425ec5abb964e1625f7dfaa6fcce3d1b Mon Sep 17 00:00:00 2001 From: David Abarbanel Date: Tue, 6 Nov 2012 09:45:36 -0500 Subject: [PATCH 0015/2553] SMTP MIME Email Message decoder --- rules/files.rules | 2 + rules/smtp-events.rules | 9 + src/Makefile.am | 2 + src/app-layer-smtp.c | 962 ++++++++++++- src/app-layer-smtp.h | 21 + src/detect-engine-file.c | 46 + src/detect-engine-file.h | 6 + src/detect-fileext.c | 9 +- src/detect-filemagic.c | 9 +- src/detect-filemd5.c | 9 +- src/detect-filename.c | 8 +- src/detect-filesize.c | 9 +- src/detect-filestore.c | 8 +- src/log-file.c | 30 + src/log-filestore.c | 59 +- src/mime-decode.c | 2841 ++++++++++++++++++++++++++++++++++++++ src/mime-decode.h | 240 ++++ src/suricata.c | 2 + src/util-base64.c | 146 ++ src/util-base64.h | 54 + suricata.yaml.in | 17 + 21 files changed, 4444 insertions(+), 45 deletions(-) create mode 100644 src/mime-decode.c create mode 100644 src/mime-decode.h create mode 100644 src/util-base64.c create mode 100644 src/util-base64.h diff --git a/rules/files.rules b/rules/files.rules index 0f770902f8d9..467735ee0461 100644 --- a/rules/files.rules +++ b/rules/files.rules @@ -43,3 +43,5 @@ # Alert and store pdf attachment but not pdf file #alert http any any -> any any (msg:"FILE pdf claimed, but not pdf"; flow:established,to_client; fileext:"pdf"; filemagic:!"PDF document"; filestore; sid:22; rev:1;) +# Alert and store files over SMTP +#alert smtp any any -> any any (msg:"File Found over SMTP and stored"; filestore; sid:27; rev:1;) diff --git a/rules/smtp-events.rules b/rules/smtp-events.rules index a20c6155a167..52b4647f9618 100644 --- a/rules/smtp-events.rules +++ b/rules/smtp-events.rules @@ -16,3 +16,12 @@ alert smtp any any -> any any (msg:"SURICATA SMTP no server welcome message"; fl alert smtp any any -> any any (msg:"SURICATA SMTP tls rejected"; flow:established; app-layer-event:smtp.tls_rejected; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220007; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP data command rejected"; flow:established,to_client; app-layer-event:smtp.data_command_rejected; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220008; rev:1;) +# SMTP MIME events +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime parser failed"; flow:established; app-layer-event:smtp.mime_parse_failed; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220009; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime malformed message found"; flow:established; app-layer-event:smtp.mime_malformed_msg; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220010; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime base64-decoding failed"; flow:established; app-layer-event:smtp.mime_invalid_base64; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220011; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime header name len exceeded"; flow:established; app-layer-event:smtp.mime_long_header_name; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220012; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime header value len exceeded"; flow:established; app-layer-event:smtp.mime_long_header_value; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220013; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime quoted-printable-decoding failed"; flow:established; app-layer-event:smtp.mime_invalid_qp; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220014; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime line len exceeded"; flow:established; app-layer-event:smtp.mime_long_line; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220015; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime encoded line len exceeded"; flow:established; app-layer-event:smtp.mime_long_enc_line; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220016; rev:1;) diff --git a/src/Makefile.am b/src/Makefile.am index ee9b654e2394..6d6be901fae6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -214,6 +214,7 @@ log-httplog.c log-httplog.h \ log-pcap.c log-pcap.h \ log-tcp-data.c log-tcp-data.h \ log-tlslog.c log-tlslog.h \ +mime-decode.c mime-decode.h \ output.c output.h \ output-file.c output-file.h \ output-filedata.c output-filedata.h \ @@ -283,6 +284,7 @@ tm-threads.c tm-threads.h tm-threads-common.h \ unix-manager.c unix-manager.h \ util-action.c util-action.h \ util-atomic.c util-atomic.h \ +util-base64.c util-base64.h \ util-bloomfilter-counting.c util-bloomfilter-counting.h \ util-bloomfilter.c util-bloomfilter.h \ util-buffer.c util-buffer.h \ diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index fc3b9f7dadb4..0d5ef040e8e7 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -113,6 +113,25 @@ SCEnumCharMap smtp_decoder_event_table[ ] = { SMTP_DECODER_EVENT_TLS_REJECTED }, { "DATA_COMMAND_REJECTED", SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED }, + + /* MIME Events */ + { "MIME_PARSE_FAILED", + SMTP_DECODER_EVENT_MIME_PARSE_FAILED }, + { "MIME_MALFORMED_MSG", + SMTP_DECODER_EVENT_MIME_MALFORMED_MSG }, + { "MIME_INVALID_BASE64", + SMTP_DECODER_EVENT_MIME_INVALID_BASE64 }, + { "MIME_INVALID_QP", + SMTP_DECODER_EVENT_MIME_INVALID_QP }, + { "MIME_LONG_LINE", + SMTP_DECODER_EVENT_MIME_LONG_LINE }, + { "MIME_LONG_ENC_LINE", + SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE }, + { "MIME_LONG_HEADER_NAME", + SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME }, + { "MIME_LONG_HEADER_VALUE", + SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE }, + { NULL, -1 }, }; @@ -183,10 +202,185 @@ SCEnumCharMap smtp_reply_map[ ] = { { "555", SMTP_REPLY_555 }, { NULL, -1 }, }; -//static void SMTPParserReset(void) -//{ -// return; -//} + +typedef struct SMTPConfig { + + int decode_mime; + MimeDecConfig mime_config; + +} SMTPConfig; + +/* Create SMTP config structure */ +static SMTPConfig smtp_config = { 0, { 0, 0, 0, 0 } }; + +/** + * \brief Configure SMTP Mime Decoder by parsing out 'smtp-mime' section of YAML + * config file + * + * \return none + */ +static void SMTPConfigure(void) { + + SCEnter(); + int ret = 0, val; + intmax_t imval; + + ConfNode *config = ConfGetNode("smtp-mime"); + if (config != NULL) { + + ret = ConfGetChildValueBool(config, "decode-mime", &val); + if (ret) { + smtp_config.decode_mime = val; + } + + ret = ConfGetChildValueBool(config, "decode-base64", &val); + if (ret) { + smtp_config.mime_config.decode_base64 = val; + } + + ret = ConfGetChildValueBool(config, "decode-quoted-printable", &val); + if (ret) { + smtp_config.mime_config.decode_quoted_printable = val; + } + + ret = ConfGetChildValueInt(config, "header-value-depth", &imval); + if (ret) { + smtp_config.mime_config.header_value_depth = (uint32_t) imval; + } + + ret = ConfGetChildValueBool(config, "extract-urls", &val); + if (ret) { + smtp_config.mime_config.extract_urls = val; + } + } + + /* Pass mime config data to MimeDec API */ + MimeDecSetConfig(&smtp_config.mime_config); + + SCReturn; +} + +static int ProcessDataChunk(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + Flow *flow = (Flow *) state->data; + SMTPState *smtp_state = (SMTPState *) flow->alstate; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + FileContainer *files = NULL; + uint16_t flags = 0; + + /* Set flags */ + if (flow->flags & FLOW_FILE_NO_STORE_TS) { + flags |= FILE_NOSTORE; + } + + if (flow->flags & FLOW_FILE_NO_MAGIC_TS) { + flags |= FILE_NOMAGIC; + } + + if (flow->flags & FLOW_FILE_NO_MD5_TS) { + flags |= FILE_NOMD5; + } + + /* Determine whether to process files */ + if ((flags & (FILE_NOSTORE | FILE_NOMAGIC | FILE_NOMD5)) == + (FILE_NOSTORE | FILE_NOMAGIC | FILE_NOMD5)) { + SCLogDebug("File content ignored"); + return 0; + } + + /* Find file */ + if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { + + /* Make sure file container allocated */ + if (smtp_state->files_ts == NULL) { + smtp_state->files_ts = FileContainerAlloc(); + if (smtp_state->files_ts == NULL) { + ret = MIME_DEC_ERR_MEM; + SCLogError(SC_ERR_MEM_ALLOC, "Could not create file container"); + goto end; + } + } + files = smtp_state->files_ts; + + /* Open file if necessary */ + if (state->body_begin) { + + if (SCLogDebugEnabled()) { + SCLogDebug("Opening file...%u bytes", len); + printf("File - "); + for (uint32_t i = 0; i < entity->filename_len; i++) { + printf("%c", entity->filename[i]); + } + printf("\n"); + } + + /* Set storage flag if applicable since only the first file in the + * flow seems to be processed by the 'filestore' detector */ + if (files->head != NULL && (files->head->flags & FILE_STORE)) { + flags |= FILE_STORE; + } + + if (FileOpenFile(files, (uint8_t *) entity->filename, entity->filename_len, + (uint8_t *) chunk, len, flags) == NULL) { + ret = MIME_DEC_ERR_DATA; + SCLogDebug("FileOpenFile() failed"); + } + + /* If close in the same chunk, then pass in empty bytes */ + if (state->body_end) { + + SCLogDebug("Closing file...%u bytes", len); + + if (files->tail->state == FILE_STATE_OPENED) { + ret = FileCloseFile(files, (uint8_t *) NULL, 0, flags); + if (ret != 0) { + SCLogDebug("FileCloseFile() failed: %d", ret); + } + } else { + SCLogDebug("File already closed"); + } + } + } else if (state->body_end) { + /* Close file */ + SCLogDebug("Closing file...%u bytes", len); + + if (files->tail->state == FILE_STATE_OPENED) { + ret = FileCloseFile(files, (uint8_t *) chunk, len, flags); + if (ret != 0) { + SCLogDebug("FileCloseFile() failed: %d", ret); + } + } else { + SCLogDebug("File already closed"); + } + } else { + /* Append data chunk to file */ + SCLogDebug("Appending file...%u bytes", len); + + /* 0 is ok, -2 is not stored, -1 is error */ + ret = FileAppendData(files, (uint8_t *) chunk, len); + if (ret == -2) { + ret = 0; + SCLogDebug("FileAppendData() - file no longer being extracted"); + } else if (ret < 0) { + SCLogDebug("FileAppendData() failed: %d", ret); + } + } + + if (ret == MIME_DEC_OK) { + SCLogDebug("Successfully processed file data!"); + } + } else { + SCLogDebug("Body not a Ctnt_attachment"); + } + + if (files != NULL) { + FilePrune(files); + } +end: + SCReturnInt(ret); +} /** * \internal @@ -496,6 +690,53 @@ static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, * the command buffer to be used by the reply handler to match * the reply received */ SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f); + + if (smtp_config.decode_mime) { + /* Complete parsing task */ + int ret = MimeDecParseComplete(state->mime_state); + if (ret != MIME_DEC_OK) { + + AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_PARSE_FAILED); + SCLogDebug("MimeDecParseComplete() function failed"); + } + + /* Generate decoder events */ + MimeDecEntity *msg = state->mime_state->msg; + if (msg->anomaly_flags & ANOM_INVALID_BASE64) { + AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_INVALID_BASE64); + } + if (msg->anomaly_flags & ANOM_INVALID_QP) { + AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_INVALID_QP); + } + if (msg->anomaly_flags & ANOM_LONG_LINE) { + AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_LONG_LINE); + } + if (msg->anomaly_flags & ANOM_LONG_ENC_LINE) { + AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE); + } + if (msg->anomaly_flags & ANOM_LONG_HEADER_NAME) { + AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME); + } + if (msg->anomaly_flags & ANOM_LONG_HEADER_VALUE) { + AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE); + } + if (msg->anomaly_flags & ANOM_MALFORMED_MSG) { + AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG); + } + } + } + + /* If DATA, then parse out a MIME message */ + if (state->current_command == SMTP_COMMAND_DATA && + (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + if (smtp_config.decode_mime) { + int ret = MimeDecParseLine((const char *) state->current_line, + state->current_line_len, state->mime_state); + if (ret != MIME_DEC_OK) { + SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret); + } + } } return 0; @@ -665,6 +906,30 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, } else if (state->current_line_len >= 4 && SCMemcmpLowercase("data", state->current_line, 4) == 0) { state->current_command = SMTP_COMMAND_DATA; + + if (smtp_config.decode_mime) { + /* Re-init the MIME parser */ + if (state->mime_state != NULL) { + MimeDecDeInitParser(state->mime_state); + } + state->mime_state = MimeDecInitParser(f, ProcessDataChunk); + if (state->mime_state == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to " + "allocate data"); + return MIME_DEC_ERR_MEM; + } + + /* Add new MIME message to end of list */ + if (state->msg_head == NULL) { + state->msg_head = state->mime_state->msg; + state->msg_tail = state->mime_state->msg; + } + else { + state->msg_tail->next = state->mime_state->msg; + state->msg_tail = state->mime_state->msg; + } + } + } else if (state->current_line_len >= 4 && SCMemcmpLowercase("bdat", state->current_line, 4) == 0) { r = SMTPParseCommandBDAT(state); @@ -821,6 +1086,16 @@ static void SMTPStateFree(void *p) SCFree(smtp_state->tc_db); } + FileContainerFree(smtp_state->files_ts); + + /* Free MIME parser */ + if (smtp_state->mime_state != NULL) { + MimeDecDeInitParser(smtp_state->mime_state); + } + + /* Free list of MIME message recursively */ + MimeDecFreeEntity(smtp_state->msg_head); + SCFree(smtp_state); return; @@ -927,6 +1202,8 @@ void RegisterSMTPParsers(void) SMTPSetMpmState(); + SMTPConfigure(); + #ifdef UNITTESTS AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMTP, SMTPParserRegisterTests); #endif @@ -3614,6 +3891,677 @@ int SMTPParserTest13(void) return result; } +/** + * \test Test DATA command w/MIME message. + */ +int SMTPParserTest14(void) +{ + int result = 0; + Flow f; + int r = 0; + + /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ + uint8_t welcome_reply[] = { + 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, + 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36, + 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, + 0x0d, 0x0a + }; + uint32_t welcome_reply_len = sizeof(welcome_reply); + + /* EHLO boo.com */ + uint8_t request1[] = { + 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, + 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a + }; + uint32_t request1_len = sizeof(request1); + /* 250-mx.google.com at your service, [117.198.115.50] + * 250-SIZE 35882577 + * 250-8BITMIME + * 250-STARTTLS + * 250 ENHANCEDSTATUSCODES + */ + uint8_t reply1[] = { + 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, + 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, + 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, + 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, + 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, + 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, + 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, + 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, + 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, + 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, + 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, + 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a + }; + uint32_t reply1_len = sizeof(reply1); + + /* MAIL FROM:asdff@asdf.com */ + uint8_t request2[] = { + 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, + 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, + 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, + 0x0d, 0x0a + }; + uint32_t request2_len = sizeof(request2); + /* 250 2.1.0 Ok */ + uint8_t reply2[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + uint32_t reply2_len = sizeof(reply2); + + /* RCPT TO:bimbs@gmail.com */ + uint8_t request3[] = { + 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, + 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, + 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, + 0x0a + }; + uint32_t request3_len = sizeof(request3); + /* 250 2.1.5 Ok */ + uint8_t reply3[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + uint32_t reply3_len = sizeof(reply3); + + /* DATA */ + uint8_t request4[] = { + 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a + }; + uint32_t request4_len = sizeof(request4); + /* 354 End data with .|| */ + uint8_t reply4[] = { + 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, + 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, + 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, + 0x4c, 0x46, 0x3e, 0x0d, 0x0a + }; + uint32_t reply4_len = sizeof(reply4); + + /* MIME_MSG */ + uint64_t filesize = 133; + uint8_t request4_msg[] = { + 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, + 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, + 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, + 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, + 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, + 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69, + 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, + 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66, + 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D, + 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78, + 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41, + 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61, + 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, + 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43, + 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41, + 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65, + 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, + 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, + 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C, + 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C, + 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F, + 0x41, 0x3D, 0x3D, 0x0D,0x0A }; + uint32_t request4_msg_len = sizeof(request4_msg); + + /* DATA COMPLETED */ + uint8_t request4_end[] = { + 0x0d, 0x0a, 0x2e, 0x0d, 0x0a + }; + uint32_t request4_end_len = sizeof(request4_end); + /* 250 2.0.0 Ok: queued as 6A1AF20BF2 */ + uint8_t reply4_end[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, + 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, + 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42, + 0x46, 0x32, 0x0d, 0x0a + }; + uint32_t reply4_end_len = sizeof(reply4_end); + + /* QUIT */ + uint8_t request5[] = { + 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a + }; + uint32_t request5_len = sizeof(request5); + /* 221 2.0.0 Bye */ + uint8_t reply5[] = { + 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a + }; + uint32_t reply5_len = sizeof(reply5); + + TcpSession ssn; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + + StreamTcpInitConfig(TRUE); + void *thread_local_data = SMTPLocalStorageAlloc(); + + /* EHLO Request */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + request1, request1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + SMTPState *smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != 0) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* Welcome reply */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + welcome_reply, welcome_reply_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* EHLO Reply */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + reply1, reply1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* MAIL FROM Request */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + request2, request2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* MAIL FROM Reply */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + reply2, reply2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* RCPT TO Request */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + request3, request3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* RCPT TO Reply */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + reply3, reply3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* Enable mime decoding */ + smtp_config.decode_mime = 1; + smtp_config.mime_config.decode_base64 = 1; + smtp_config.mime_config.decode_quoted_printable = 1; + MimeDecSetConfig(&smtp_config.mime_config); + + /* DATA request */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + request4, request4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_DATA || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* Data reply */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + reply4, reply4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* DATA message */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + request4_msg, request4_msg_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->mime_state == NULL || smtp_state->msg_head == NULL || /* MIME data structures */ + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* DATA . request */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + request4_end, request4_end_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || + smtp_state->mime_state == NULL || smtp_state->msg_head == NULL || /* MIME data structures */ + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + SMTPState *state = (SMTPState *) f.alstate; + FileContainer *files = state->files_ts; + if (files != NULL && files->head != NULL) { + File *file = files->head; + + if(strncmp((const char *)file->name, "test.exe", 8) != 0){ + printf("smtp-mime file name is incorrect"); + goto end; + } + if(file->size != filesize){ + printf("smtp-mime file size %lu is incorrect", file->size); + goto end; + } + uint8_t org_binary[] = {0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, + 0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, + 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36, + 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36, + 0x5C, 0x7A, 0x00, 0x00, 0x38,}; + uint64_t z; + for (z=0; z <= filesize; z++){ + if(org_binary[z] != file->chunks_head->data[z]){ + printf("smtp-mime file data incorrect\n"); + goto end; + } + } + } + + /* DATA . reply */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + reply4_end, reply4_end_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* QUIT Request */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + request5, request5_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + /* QUIT Reply */ + r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + reply5, reply5_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + result = 1; + end: + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + SMTPLocalStorageFree(thread_local_data); + return result; +} + +int SMTPProcessDataChunkTest01(void){ + Flow f; + FLOW_INITIALIZE(&f); + f.flags = FLOW_FILE_NO_STORE_TS; + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + int ret; + ret = ProcessDataChunk(NULL, 0, state); + + return ret; +} + + +int SMTPProcessDataChunkTest02(void){ + char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, + 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, + 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, + 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, + 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, + 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69, + 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, + 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66, + 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D, + 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78, + 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41, + 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61, + 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, + 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43, + 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41, + 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65, + 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, + 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, + 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C, + 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C, + 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F, + 0x41, 0x3D, 0x3D, 0x0D, 0x0A,}; + + Flow f; + FLOW_INITIALIZE(&f); + f.alstate = SMTPStateAlloc(); + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + state->body_begin = 1; + int ret; + ret = ProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + + + return ret; +} + + + +int SMTPProcessDataChunkTest03(void){ + char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, }; + char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, }; + char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, }; + char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, }; + char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, }; + char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, }; + char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, }; + char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, }; + char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, }; + char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, }; + char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, }; + char mimemsg12[] = {0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, }; + + Flow f; + FLOW_INITIALIZE(&f); + f.alstate = SMTPStateAlloc(); + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + int ret; + + state->body_begin = 1; + ret = ProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + if(ret) goto end; + state->body_begin = 0; + ret = ProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state); + if(ret) goto end; + ret = ProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state); + if(ret) goto end; + ret = ProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state); + if(ret) goto end; + ret = ProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state); + if(ret) goto end; + ret = ProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state); + if(ret) goto end; + ret = ProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state); + if(ret) goto end; + ret = ProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state); + if(ret) goto end; + ret = ProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state); + if(ret) goto end; + ret = ProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state); + if(ret) goto end; + ret = ProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state); + if(ret) goto end; + state->body_end = 1; + ret = ProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state); + if(ret) goto end; + + end: + return ret; +} + + +int SMTPProcessDataChunkTest04(void){ + char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, }; + char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, }; + char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, }; + char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, }; + char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, }; + char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, }; + char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, }; + char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, }; + char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, }; + char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, }; + char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, }; + + Flow f; + FLOW_INITIALIZE(&f); + f.alstate = SMTPStateAlloc(); + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + int ret = MIME_DEC_OK; + + state->body_begin = 1; + if(ProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end; + if(ProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end; + if(ProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end; + if(ProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end; + if(ProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end; + if(ProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end; + if(ProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end; + state->body_begin = 0; + state->body_end = 1; + if(ProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end; + state->body_end = 0; + if(ProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end; + if(ProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end; + if(ProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end; + + end: + return ret; +} + +int SMTPProcessDataChunkTest05(void){ + char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, + 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C, + 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F, + 0x41, 0x3D, 0x3D, 0x0D, 0x0A,}; + + Flow f; + FLOW_INITIALIZE(&f); + f.alstate = SMTPStateAlloc(); + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + state->body_begin = 1; + int ret; + uint64_t file_size = 0; + ret = ProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + state->body_begin = 0; + if(ret){goto end;} + SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate; + FileContainer *files = smtp_state->files_ts; + File *file = files->head; + file_size = file->size; + + FileDisableStoring(&f, STREAM_TOSERVER); + FileDisableMagic(&f, STREAM_TOSERVER); + FileDisableMd5(&f, STREAM_TOSERVER); + ret = ProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + if(ret){goto end;} + printf("%u\t%u\n", (uint32_t) file->size, (uint32_t) file_size); + if(file->size == file_size){ + return 0; + }else{ + return 1; + } + + end: + return ret; +} + #endif /* UNITTESTS */ void SMTPParserRegisterTests(void) @@ -3632,6 +4580,12 @@ void SMTPParserRegisterTests(void) UtRegisterTest("SMTPParserTest11", SMTPParserTest11, 1); UtRegisterTest("SMTPParserTest12", SMTPParserTest12, 1); UtRegisterTest("SMTPParserTest13", SMTPParserTest13, 1); + UtRegisterTest("SMTPParserTest14", SMTPParserTest14, 1); + UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01, 0); + UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02, 0); + UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03, 0); + UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04, 0); + UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05, 0); #endif /* UNITTESTS */ return; diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 0a29a35b3705..94d8eb840484 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -25,6 +25,7 @@ #define __APP_LAYER_SMTP_H__ #include "decode-events.h" +#include "mime-decode.h" enum { SMTP_DECODER_EVENT_INVALID_REPLY, @@ -36,6 +37,16 @@ enum { SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE, SMTP_DECODER_EVENT_TLS_REJECTED, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED, + + /* MIME Events */ + SMTP_DECODER_EVENT_MIME_PARSE_FAILED, + SMTP_DECODER_EVENT_MIME_MALFORMED_MSG, + SMTP_DECODER_EVENT_MIME_INVALID_BASE64, + SMTP_DECODER_EVENT_MIME_INVALID_QP, + SMTP_DECODER_EVENT_MIME_LONG_LINE, + SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE, + SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME, + SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE, }; typedef struct SMTPState_ { @@ -89,6 +100,16 @@ typedef struct SMTPState_ { * handler */ uint16_t cmds_idx; + /* SMTP Mime decoding and file extraction */ + /** the list of files sent to the server */ + FileContainer *files_ts; + /** the first message contained in the session */ + MimeDecEntity *msg_head; + /** the last message contained in the session */ + MimeDecEntity *msg_tail; + /** the mime decoding parser state */ + MimeDecParseState *mime_state; + } SMTPState; void RegisterSMTPParsers(void); diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index ca502c9b758c..655adffcaad8 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -51,6 +51,7 @@ #include "app-layer-smb.h" #include "app-layer-dcerpc-common.h" #include "app-layer-dcerpc.h" +#include "app-layer-smtp.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -240,3 +241,48 @@ int DetectFileInspectHttp(ThreadVars *tv, return r; } + +/** + * \brief Inspect the file inspecting keywords against the SMTP transactions. + * + * \param tv thread vars + * \param det_ctx detection engine thread ctx + * \param f flow + * \param s signature to inspect + * \param alstate state + * \param flags direction flag + * + * \retval 0 no match + * \retval 1 match + * \retval 2 can't match + * \retval 3 can't match filestore signature + * + * \note flow is not locked at this time + */ +int DetectFileInspectSmtp(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id) +{ + SCEnter(); + + int r = 0; + SMTPState *smtp_state = NULL; + FileContainer *ffc; + + smtp_state = (SMTPState *)alstate; + if (smtp_state == NULL) { + SCLogDebug("no SMTP state"); + goto end; + } + + if (flags & STREAM_TOSERVER) + ffc = smtp_state->files_ts; + else + goto end; + + r = DetectFileInspect(tv, det_ctx, f, s, flags, ffc); + +end: + SCReturnInt(r); +} diff --git a/src/detect-engine-file.h b/src/detect-engine-file.h index 91e2f21ebf1d..365ed8a99fb7 100644 --- a/src/detect-engine-file.h +++ b/src/detect-engine-file.h @@ -28,4 +28,10 @@ int DetectFileInspectHttp(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + +int DetectFileInspectSmtp(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, + Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id); + #endif /* __DETECT_ENGINE_FILE_H__ */ diff --git a/src/detect-fileext.c b/src/detect-fileext.c index 98b8bcb90f05..7b5e9103d4f3 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -211,14 +211,15 @@ static int DetectFileextSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } - AppLayerHtpNeedFileInspection(); - s->alproto = ALPROTO_HTTP; + if (s->alproto == ALPROTO_HTTP) { + AppLayerHtpNeedFileInspection(); + } + s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_FILENAME); return 0; diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 9edecd2cfc9c..5dd28ec8195b 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -392,15 +392,14 @@ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, char *st SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } - AppLayerHtpNeedFileInspection(); - - /** \todo remove this once we support more than http */ - s->alproto = ALPROTO_HTTP; + if (s->alproto == ALPROTO_HTTP) { + AppLayerHtpNeedFileInspection(); + } s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MAGIC); return 0; diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index a81ba25d6d5b..1bb0cf3ac88b 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -324,15 +324,14 @@ static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } - AppLayerHtpNeedFileInspection(); - - /** \todo remove this once we support more than http */ - s->alproto = ALPROTO_HTTP; + if (s->alproto == ALPROTO_HTTP) { + AppLayerHtpNeedFileInspection(); + } s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MD5); return 0; diff --git a/src/detect-filename.c b/src/detect-filename.c index c8cea7f3590f..06ccc70bd0d6 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -215,14 +215,14 @@ static int DetectFilenameSetup (DetectEngineCtx *de_ctx, Signature *s, char *str SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } - AppLayerHtpNeedFileInspection(); - - s->alproto = ALPROTO_HTTP; + if (s->alproto == ALPROTO_HTTP) { + AppLayerHtpNeedFileInspection(); + } s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_FILENAME); return 0; diff --git a/src/detect-filesize.c b/src/detect-filesize.c index d8c49bcf7888..e826e3c9b5f4 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -310,15 +310,14 @@ static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *str SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } - AppLayerHtpNeedFileInspection(); - - /** \todo remove this once we support more than http */ - s->alproto = ALPROTO_HTTP; + if (s->alproto == ALPROTO_HTTP) { + AppLayerHtpNeedFileInspection(); + } s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_SIZE); SCReturnInt(0); diff --git a/src/detect-filestore.c b/src/detect-filestore.c index f9bfdf55c25b..e88c95eeb688 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -414,14 +414,14 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *st SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); s->filestore_sm = sm; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } - AppLayerHtpNeedFileInspection(); - - s->alproto = ALPROTO_HTTP; + if (s->alproto == ALPROTO_HTTP) { + AppLayerHtpNeedFileInspection(); + } s->flags |= SIG_FLAG_FILESTORE; return 0; diff --git a/src/log-file.c b/src/log-file.c index 8cb7a662bb2c..92b066df544a 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -55,6 +55,8 @@ #include "util-logopenfile.h" #include "app-layer-htp.h" +#include "app-layer-smtp.h" +#include "mime-decode.h" #include "util-memcmp.h" #include "stream-tcp-reassemble.h" @@ -144,6 +146,31 @@ static void LogFileMetaGetUserAgent(FILE *fp, const Packet *p, const File *ff) fprintf(fp, ""); } +static void LogFileMetaGetSmtp(FILE *fp, const Packet *p, const File *ff) { + + SMTPState *state = (SMTPState *) p->flow->alstate; + if (state != NULL && state->msg_tail != NULL) { + + /* Message Id */ + if (state->msg_tail->msg_id != NULL) { + + fprintf(fp, "\"message-id\": \""); + PrintRawJsonFp(fp, (uint8_t *) state->msg_tail->msg_id, + (int) state->msg_tail->msg_id_len); + fprintf(fp, "\", "); + } + + /* Sender */ + MimeDecField *field = MimeDecFindField(state->msg_tail, "From"); + if (field != NULL) { + fprintf(fp, "\"sender\": \""); + PrintRawJsonFp(fp, (uint8_t *) field->value, + (int) field->value_len); + fprintf(fp, "\", "); + } + } +} + /** * \internal * \brief Write meta data on a single line json record @@ -231,6 +258,9 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const fprintf(fp, "\"http_user_agent\": \""); LogFileMetaGetUserAgent(fp, p, ff); fprintf(fp, "\", "); + } else if (p->flow->alproto == ALPROTO_SMTP) { + /* Only applicable to SMTP */ + LogFileMetaGetSmtp(fp, p, ff); } fprintf(fp, "\"filename\": \""); diff --git a/src/log-filestore.c b/src/log-filestore.c index 989b51dee512..771cc8105dbd 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -53,6 +53,8 @@ #include "util-logopenfile.h" #include "app-layer-htp.h" +#include "app-layer-smtp.h" +#include "mime-decode.h" #include "util-memcmp.h" #include "stream-tcp-reassemble.h" @@ -139,8 +141,29 @@ static void LogFilestoreMetaGetUserAgent(FILE *fp, const Packet *p, const File * fprintf(fp, ""); } -static void LogFilestoreLogCreateMetaFile(const Packet *p, const File *ff, const char *filename, int ipver) -{ +static void LogFilestoreMetaGetSmtp(FILE *fp, Packet *p, File *ff) { + + SMTPState *state = (SMTPState *) p->flow->alstate; + if (state != NULL && state->msg_tail != NULL) { + + /* Message Id */ + if (state->msg_tail->msg_id != NULL) { + fprintf(fp, "MESSAGE-ID: "); + PrintRawUriFp(fp, (uint8_t *) state->msg_tail->msg_id, state->msg_tail->msg_id_len); + fprintf(fp, "\n"); + } + + /* Sender */ + MimeDecField *field = MimeDecFindField(state->msg_tail, "From"); + if (field != NULL) { + fprintf(fp, "SENDER: "); + PrintRawUriFp(fp, (uint8_t *) field->value, field->value_len); + fprintf(fp, "\n"); + } + } +} + +static void LogFilestoreLogCreateMetaFile(const Packet *p, const File *ff, char *filename, int ipver) { char metafilename[PATH_MAX] = ""; snprintf(metafilename, sizeof(metafilename), "%s.meta", filename); FILE *fp = fopen(metafilename, "w+"); @@ -180,18 +203,26 @@ static void LogFilestoreLogCreateMetaFile(const Packet *p, const File *ff, const fprintf(fp, "SRC PORT: %" PRIu16 "\n", sp); fprintf(fp, "DST PORT: %" PRIu16 "\n", dp); } - fprintf(fp, "HTTP URI: "); - LogFilestoreMetaGetUri(fp, p, ff); - fprintf(fp, "\n"); - fprintf(fp, "HTTP HOST: "); - LogFilestoreMetaGetHost(fp, p, ff); - fprintf(fp, "\n"); - fprintf(fp, "HTTP REFERER: "); - LogFilestoreMetaGetReferer(fp, p, ff); - fprintf(fp, "\n"); - fprintf(fp, "HTTP USER AGENT: "); - LogFilestoreMetaGetUserAgent(fp, p, ff); - fprintf(fp, "\n"); + + /* Only applicable to HTTP traffic */ + if (ff->txid != 0) { + fprintf(fp, "HTTP URI: "); + LogFilestoreMetaGetUri(fp, p, ff); + fprintf(fp, "\n"); + fprintf(fp, "HTTP HOST: "); + LogFilestoreMetaGetHost(fp, p, ff); + fprintf(fp, "\n"); + fprintf(fp, "HTTP REFERER: "); + LogFilestoreMetaGetReferer(fp, p, ff); + fprintf(fp, "\n"); + fprintf(fp, "HTTP USER AGENT: "); + LogFilestoreMetaGetUserAgent(fp, p, ff); + fprintf(fp, "\n"); + } else if (p->flow->alproto == ALPROTO_SMTP) { + /* Only applicable to SMTP */ + LogFilestoreMetaGetSmtp(fp, p, ff); + } + fprintf(fp, "FILENAME: "); PrintRawUriFp(fp, ff->name, ff->name_len); fprintf(fp, "\n"); diff --git a/src/mime-decode.c b/src/mime-decode.c new file mode 100644 index 000000000000..fdca4f07bc0f --- /dev/null +++ b/src/mime-decode.c @@ -0,0 +1,2841 @@ +/* Copyright (C) 2012 BAE Systems + * + * 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 David Abarbanel + * + */ + +#include +#include +#include "mime-decode.h" + +#include "util-spm-bs.h" +#include "util-unittest.h" + +/* Character constants */ +#ifndef CR +#define CR 13 +#define LF 10 +#endif + +#define CRLF "\r\n" +#define COLON 58 +#define DASH 45 +#define PRINTABLE_START 33 +#define PRINTABLE_END 126 +#define UC_START 65 +#define UC_END 90 +#define LC_START 97 +#define LC_END 122 +#define UC_LC_DIFF 32 +#define EOL_LEN 2 + +/* Base-64 constants */ +#define BASE64_STR "Base64" + +/* Mime Constants */ +#define MAX_LINE_LEN 998 /* Def in RFC 2045, excluding CRLF sequence */ +#define MAX_ENC_LINE_LEN 76 /* Def in RFC 2045, excluding CRLF sequence */ +#define MAX_HEADER_NAME 75 /* 75 + ":" = 76 */ +#define MAX_HEADER_VALUE 2000 /* Default - arbitrary limit */ +#define BOUNDARY_BUF 256 +#define CTNT_TYPE_STR "Content-Type" +#define CTNT_DISP_STR "Content-Disposition" +#define CTNT_TRAN_STR "Content-Transfer-Encoding" +#define MSG_ID_STR "Message-ID" +#define BND_START_STR "boundary=\"" +#define TOK_END_STR "\"" +#define MSG_STR "message/" +#define MULTIPART_STR "multipart/" +#define QP_STR "quoted-printable" +#define TXT_STR "text/plain" +#define HTML_STR "text/html" +#define URL_STR "http://" + +/* Memory Usage Constants */ +#define STACK_FREE_NODES 10 + +/* Other Constants */ +#define MAX_IP4_CHARS 15 +#define MAX_IP6_CHARS 39 + +/* Globally hold configuration data */ +static MimeDecConfig mime_dec_config = { 1, 1, 1, MAX_HEADER_VALUE }; + +/* Mime Parser String translation */ +static const char *StateFlags[] = { "NONE", + "HEADER_READY", + "HEADER_STARTED", + "HEADER_DONE", + "BODY_STARTED", + "BODY_DONE", + "BODY_END_BOUND", + "PARSE_DONE", + "PARSE_ERROR", + NULL }; + +/* URL executable file extensions */ +static const char *UrlExeExts[] = { ".exe", + ".vbs", + ".bin", + ".cmd", + ".bat", + ".jar", + ".js", + NULL }; + +/** + * \brief Function used to print character strings that are not null-terminated + * + * \param log_level The logging level in which to print + * \param label A label for the string to print + * \param src The source string + * \param len The length of the string + * + * \return none + */ +void PrintChars(int log_level, char *label, char *src, uint32_t len) { + + if (log_level <= sc_log_global_log_level) { + + static uint32_t max_len = 100; + char tempbuf[max_len]; + + if (len == 0) { + SCLog(log_level, "PrintChars() - length is 0\n"); + } else { + uint32_t llen = strlen(label); + + /* Add label and source */ + int num = snprintf(tempbuf, llen +4 < max_len ? llen + 4 : max_len, "[%s] ", label); + strncpy(tempbuf + num, src, len + num < max_len ? len + num : max_len - num - 1); + + SCLog(log_level, "%s", tempbuf); + } + } +} + +/** + * \brief Set global config policy + * + * \param config Config policy to set + * \return none + */ +void MimeDecSetConfig(MimeDecConfig *config) { + + if (config != NULL) { + mime_dec_config = *config; + + /* Set to default */ + if (mime_dec_config.header_value_depth == 0) { + mime_dec_config.header_value_depth = MAX_HEADER_VALUE; + } + } else { + SCLogWarning(SC_ERR_MISSING_CONFIG_PARAM, "Invalid null configuration parameters"); + } +} + +/** + * \brief Get global config policy + * + * \return config data structure + */ +MimeDecConfig * MimeDecGetConfig(void) { + return &mime_dec_config; +} + +/** + * \brief Recursively frees a mime entity tree + * + * \param entity The root entity + * + * \return none + * + */ +void MimeDecFreeEntity (MimeDecEntity *entity) { + + if (entity != NULL) { + + MimeDecFreeField(entity->field_list); + MimeDecFreeUrl(entity->url_list); + SCFree(entity->filename); + + /* Use recursion */ + MimeDecFreeEntity(entity->child); + MimeDecFreeEntity(entity->next); + + SCFree(entity); + } +} + +/** + * \brief Iteratively frees a header field entry list + * + * \param field The header field + * + * \return none + * + */ +void MimeDecFreeField(MimeDecField *field) { + + MimeDecField *temp, *curr; + + if (field != NULL) { + + curr = field; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Free contents of node */ + SCFree(temp->name); + SCFree(temp->value); + + /* Now free node data */ + SCFree(temp); + } + } +} + +/** + * \brief Iteratively frees a URL entry list + * + * \param url The url entry + * + * \return none + * + */ +void MimeDecFreeUrl(MimeDecUrl *url) { + + MimeDecUrl *temp, *curr; + + if (url != NULL) { + + curr = url; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node data */ + SCFree(temp->url); + SCFree(temp); + } + } +} + +/** + * \brief Creates and adds a header field entry to an entity + * + * The entity is optional. If NULL is specified, than a new stand-alone field + * is created. + * + * \param entity The parent entity + * + * \return The field object, or NULL if the operation fails + * + */ +MimeDecField * MimeDecAddField(MimeDecEntity *entity) { + + MimeDecField *node = SCMalloc(sizeof(MimeDecField)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(node, 0x00, sizeof(MimeDecField)); + + if (entity != NULL) { + + /* If list is empty, then set as head of list */ + if (entity->field_list == NULL) { + entity->field_list = node; + } else { + /* Otherwise add to beginning of list since these are out-of-order in + * the message */ + node->next = entity->field_list; + entity->field_list = node; + } + } + + return node; +} + +/** + * \brief Searches for a header field with the specified name (case insensitive) + * + * \param entity The entity to search + * \param name The header name (case insensitive) + * + * \return The field object, or NULL if not found + * + */ +MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name) { + MimeDecField *curr = entity->field_list; + + while (curr != NULL) { + + if (strncasecmp(curr->name, name, curr->name_len) == 0) { + break; + } + curr = curr->next; + } + + return curr; +} + +/** + * \brief Creates and adds a URL entry to the specified entity + * + * The entity is optional and if NULL is specified, then a new list will be created. + * + * \param entity The entity + * + * \return URL entry or NULL if the operation fails + * + */ +MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity) { + + MimeDecUrl *node = SCMalloc(sizeof(MimeDecUrl)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(node, 0x00, sizeof(MimeDecUrl)); + + if (entity != NULL) { + + /* If list is empty, then set as head of list */ + if (entity->url_list == NULL) { + entity->url_list = node; + } else { + /* Otherwise add to beginning of list since these are out-of-order in + * the message */ + node->next = entity->url_list; + entity->url_list = node; + } + } + + return node; +} + +/** + * \brief Creates and adds a child entity to the specified parent entity + * + * \param parent The parent entity + * + * \return The child entity, or NULL if the operation fails + * + */ +MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent) { + + MimeDecEntity *curr, *node = SCMalloc(sizeof(MimeDecEntity)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(node, 0x00, sizeof(MimeDecEntity)); + + /* If parent is NULL then just return the new pointer */ + if (parent != NULL) { + if (parent->child == NULL) { + parent->child = node; + } else { + curr = parent->child; + while (curr->next != NULL) { + curr = curr->next; + } + curr->next = node; + } + } + + return node; +} + +/** + * \brief Creates a mime header field and fills in its values and adds it to the + * specified entity + * + * \param entity Entity in which to add the field + * \param name String containing the name + * \param nlen Length of the name + * \param value String containing the value + * \param vlen Length of the value + * \param copy_name_value Flag indicating whether to make copies of the name and + * value or just point to them + * + * \return The field or NULL if the operation fails + */ +MimeDecField * MimeDecFillField(MimeDecEntity *entity, const char *name, + uint32_t nlen, const char *value, uint32_t vlen, int copy_name_value) { + + MimeDecField *field = MimeDecAddField(entity); + if (unlikely(field == NULL)) { + return NULL; + } + + if (nlen > 0) { + if (copy_name_value) { + field->name = SCMalloc(nlen); + if (unlikely(field->name == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + SCFree(field); + return NULL; + } + strncpy(field->name, name, nlen); + } else { + field->name = (char *) name; + } + field->name_len = nlen; + } + + if (vlen > 0) { + if (copy_name_value) { + field->value = SCMalloc(vlen); + if (unlikely(field->value == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + SCFree(field); + return NULL; + } + strncpy(field->value, value, vlen); + } else { + field->value = (char *) value; + } + field->value_len = vlen; + } + + return field; +} + +/** + * \brief Pushes a node onto a stack and returns the new node. + * + * \param stack The top of the stack + * + * \return pointer to a new node, otherwise NULL if it fails + */ +static MimeDecStackNode * PushStack(MimeDecStack *stack) { + + /* Attempt to pull from free nodes list */ + MimeDecStackNode *node = stack->free_nodes; + if (node == NULL) { + node = SCMalloc(sizeof(MimeDecStackNode)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + } else { + /* Move free nodes pointer over */ + stack->free_nodes = stack->free_nodes->next; + stack->free_nodes_cnt--; + } + memset(node, 0x00, sizeof(MimeDecStackNode)); + + /* Push to top of stack */ + node->next = stack->top; + stack->top = node; + + /* Return a pointer to the top of the stack */ + return node; +} + +/** + * \brief Pops the top node from the stack and returns the next node. + * + * \param stack The top of the stack + * + * \return pointer to the next node, otherwise NULL if no nodes remain + */ +static MimeDecStackNode * PopStack(MimeDecStack *stack) { + + /* Move stack pointer to next item */ + MimeDecStackNode *curr = stack->top; + if (curr != NULL) { + curr = curr->next; + } + + /* Always free alloc'd memory */ + SCFree(stack->top->bdef); + + /* Now move head to free nodes list */ + if (stack->free_nodes_cnt < STACK_FREE_NODES) { + stack->top->next = stack->free_nodes; + stack->free_nodes = stack->top; + stack->free_nodes_cnt++; + } else { + SCFree(stack->top); + } + stack->top = curr; + + /* Return a pointer to the top of the stack */ + return curr; +} + +/** + * \brief Frees the stack along with the free-nodes list + * + * \param stack The stack pointer + * + * \return none + */ +static void FreeMimeDecStack(MimeDecStack *stack) { + + MimeDecStackNode *temp, *curr; + + if (stack != NULL) { + + /* Top of stack */ + curr = stack->top; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node */ + SCFree(temp->bdef); + SCFree(temp); + } + + /* Free nodes */ + curr = stack->free_nodes; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node */ + SCFree(temp); + } + + SCFree(stack); + } +} + +/** + * \brief Adds a data value to the data values linked list + * + * \param dv The head of the linked list (NULL if new list) + * + * \return pointer to a new node, otherwise NULL if it fails + */ +static DataValue * AddDataValue(DataValue *dv) { + + DataValue *curr, *node = SCMalloc(sizeof(DataValue)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(node, 0x00, sizeof(DataValue)); + + if (dv != NULL) { + curr = dv; + while (curr->next != NULL) { + curr = curr->next; + } + + curr->next = node; + } + + return node; +} + +/** + * \brief Frees a linked list of data values starting at the head + * + * \param dv The head of the linked list + * + * \return none + */ +static void FreeDataValue(DataValue *dv) { + DataValue *temp, *curr; + + if (dv != NULL) { + curr = dv; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node */ + SCFree(temp->value); + SCFree(temp); + } + } +} + +/** + * \brief Converts a list of data values into a single value (returns dynamically + * allocated memory) + * + * \param dv The head of the linked list (NULL if new list) + * \param len The output length of the single value + * + * \return pointer to a single value, otherwise NULL if it fails or is zero-length + */ +static char * GetFullValue(DataValue *dv, uint32_t *len) { + + DataValue *curr; + uint32_t offset = 0; + char *val = NULL; + + /* First calculate total length */ + *len = 0; + curr = dv; + while (curr != NULL) { + *len += curr->value_len; + + /* Add CRLF except on last one */ + if (curr->next != NULL) { + *len += 2; + } + curr = curr->next; + } + + /* Must have at least one character in the value */ + if (*len > 0) { + val = SCMalloc(*len); + if (unlikely(val == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + *len = 0; + return NULL; + } + + curr = dv; + while (curr != NULL) { + strncpy(val + offset, (char *) curr->value, curr->value_len); + offset += curr->value_len; + + /* Add CRLF except on last one */ + if (curr->next != NULL) { + strncpy(val + offset, CRLF, 2); + offset += 2; + } + curr = curr->next; + } + } + + return val; +} + +/** + * \brief Find a string while searching up to N characters within a source + * string + * + * \param src The source string (not null-terminated) + * \param len The length of the source string + * \param find The string to find (null-terminated) + * + * \return Pointer to the position it was found, otherwise NULL if not found + */ +static inline char * FindString(const char *src, uint32_t len, const char *find) { + + /* Use utility search function */ + return (char *) BasicSearchNocase((uint8_t *) src, len, (uint8_t *) find, strlen(find)); +} + +/** + * \brief Get a line (CRLF or just CR or LF) from a buffer (similar to GetToken) + * + * \param buf The input buffer (not null-terminated) + * \param blen The length of the input buffer + * \param remainPtr Pointer to remaining after tokenizing iteration + * \param tokLen Output token length (if non-null line) + * + * \return Pointer to line + */ +static char * GetLine(char *buf, uint32_t blen, char **remainPtr, + uint32_t *tokLen) { + + uint32_t i; + char *tok; + + /* So that it can be used just like strtok_r */ + if (buf == NULL) { + buf = *remainPtr; + } else { + *remainPtr = buf; + } + tok = buf; + + /* length must be specified */ + for (i = 0; i < blen && buf[i] != 0; i++) { + + /* Found delimiter */ + if (buf[i] == CR || buf[i] == LF) { + + /* Add another if we find either CRLF or LFCR */ + *remainPtr += (i + 1); + if ((i + 1 < blen) && buf[i] != buf[i + 1] && + (buf[i + 1] == CR || buf[i + 1] == LF)) { + (*remainPtr)++; + } + break; + } + } + + /* If no delimiter found, then point to end of buffer */ + if (buf == *remainPtr) { + (*remainPtr) += i; + } + + /* Calculate token length */ + *tokLen = (buf + i) - tok; + + return tok; +} + +/** + * \brief Get token from buffer and return pointer to it + * + * \param buf The input buffer (not null-terminated) + * \param blen The length of the input buffer + * \param delims Character delimiters (null-terminated) + * \param remainPtr Pointer to remaining after tokenizing iteration + * \param tokLen Output token length (if non-null line) + * + * \return Pointer to token, or NULL if not found + */ +static char * GetToken(char *buf, uint32_t blen, const char *delims, + char **remainPtr, uint32_t *tokenLen) { + + uint32_t i, j, delimFound = 0; + char *tok = NULL; + + /* So that it can be used just like strtok_r */ + if (buf == NULL) { + buf = *remainPtr; + } else { + *remainPtr = buf; + } + + /* Must specify length */ + for (i = 0; i < blen && buf[i] != 0; i++) { + + /* Look for delimiters */ + for (j = 0; delims[j] != 0; j++) { + if (buf[i] == delims[j]) { + /* Data must be found before delimiter matters */ + if (tok != NULL) { + (*remainPtr) += (i + 1); + } + delimFound = 1; + break; + } + } + + /* If at least one non-delimiter found, then a token is found */ + if (tok == NULL && !delimFound) { + tok = buf + i; + } else { + /* Reset delimiter */ + delimFound = 0; + } + + /* If delimiter found, then break out of loop */ + if (buf != *remainPtr) { + break; + } + } + + /* Make sure remaining points to end of buffer if delimiters not found */ + if (tok != NULL) { + if (buf == *remainPtr) { + (*remainPtr) += i; + } + + /* Calculate token length */ + *tokenLen = (buf + i) - tok; + } + + return tok; +} + +/** + * \brief Stores the final MIME header value into the current entity on the + * stack. + * + * \param state The parser state + * + * \return MIME_DEC_OK if stored, otherwise a negative number indicating error + */ +static int StoreMimeHeader(MimeDecParseState *state) { + + int ret = MIME_DEC_OK, stored = 0; + char *val; + uint32_t vlen; + + /* Lets save the most recent header */ + if (state->hname != NULL || state->hvalue != NULL) { + SCLogDebug("Storing last header"); + val = GetFullValue(state->hvalue, &vlen); + if (val != NULL) { + + if (state->hname == NULL) { + SCLogDebug("Error: Invalid parser state - header value without" + " name"); + ret = MIME_DEC_ERR_PARSE; + } else if (state->stack->top != NULL) { + /* Store each header name and value */ + if (MimeDecFillField(state->stack->top->data, state->hname, + state->hlen, val, vlen, 0) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "MimeDecFillField() function failed"); + ret = MIME_DEC_ERR_MEM; + } else { + stored = 1; + } + } else { + SCLogDebug("Error: Stack pointer missing"); + ret = MIME_DEC_ERR_DATA; + } + } else if (state->hvalue != NULL) { + /* Memory allocation must have failed since val is NULL */ + SCLogError(SC_ERR_MEM_ALLOC, "GetFullValue() function failed"); + ret = MIME_DEC_ERR_MEM; + } + + /* Do cleanup here */ + if (!stored) { + SCFree(state->hname); + } + state->hname = NULL; + FreeDataValue(state->hvalue); + state->hvalue = NULL; + state->hvlen = 0; + } + + return ret; +} + +/** + * \brief Function determines whether a url string points to an executable + * based on file extension only. + * + * \param url The url string + * \param len The url string length + * + * \retval 1 The url points to an EXE + * \retval 0 The url does NOT point to an EXE + */ +static int IsExeUrl(char *url, uint32_t len) { + + int isExeUrl = 0; + uint32_t i, extLen; + char *ext; + + /* Now check for executable extensions and if not found, cut off at first '/' */ + for (i = 0; UrlExeExts[i] != NULL; i++) { + extLen = strlen(UrlExeExts[i]); + ext = FindString(url, len, UrlExeExts[i]); + if (ext != NULL && (ext + extLen - url == len || ext[extLen] == '?')) { + isExeUrl = 1; + break; + } + } + + return isExeUrl; +} + +/** + * \brief Function determines whether a host string is a numeric IP v4 address + * + * \param urlhost The host string + * \param len The host string length + * + * \retval 1 The host is a numeric IP + * \retval 0 The host is NOT a numeric IP + */ +static int IsIpv4Host(char *urlhost, uint32_t len) { + + struct sockaddr_in sa; + + char tempIp[MAX_IP4_CHARS + 1]; + + /* Cut off at '/' */ + uint32_t i = 0; + for (i = 0; i < len && urlhost[i] != 0; i++) { + + if (urlhost[i] == '/') { + break; + } + } + + /* Too many chars */ + if (i > MAX_IP4_CHARS) { + return 0; + } + + /* Create null-terminated string */ + strncpy(tempIp, urlhost, i); + tempIp[i] = 0; + + return inet_pton(AF_INET, tempIp, &(sa.sin_addr)); +} + +/** + * \brief Function determines whether a host string is a numeric IP v6 address + * + * \param urlhost The host string + * \param len The host string length + * + * \retval 1 The host is a numeric IP + * \retval 0 The host is NOT a numeric IP + */ +static int IsIpv6Host(char *urlhost, uint32_t len) { + + struct sockaddr_in sa; + + char tempIp[MAX_IP6_CHARS + 1]; + + /* Cut off at '/' */ + uint32_t i = 0; + for (i = 0; i < len && urlhost[i] != 0; i++) { + + if (urlhost[i] == '/') { + break; + } + } + + /* Too many chars */ + if (i > MAX_IP6_CHARS) { + return 0; + } + + /* Create null-terminated string */ + strncpy(tempIp, urlhost, i); + tempIp[i] = 0; + + return inet_pton(AF_INET6, tempIp, &(sa.sin_addr)); +} + +/** + * \brief Traverses through the list of URLs for an exact match of the specified + * string + * + * \param entity The MIME entity + * \param url The matching URL string + * \param url_len The matching URL string length + * + * \return URL object or NULL if not found + */ +static MimeDecUrl * FindExistingUrl(MimeDecEntity *entity, char *url, + uint32_t url_len) { + + uint32_t len; + MimeDecUrl *curr = entity->url_list; + + while (curr != NULL) { + + /* Get smaller length */ + len = curr->url_len < url_len ? curr->url_len : url_len; + if (strncasecmp(curr->url, url, len) == 0) { + break; + } + + curr = curr->next; + } + + return curr; +} + +/** + * \brief This function searches a text or html line for a URL string + * + * URLS are generally truncated to the 'host.domain' format because + * some email messages contain dozens or even hundreds of URLs with + * the same host, but with only small variations in path. + * + * The exception is that URLs with executable file extensions are stored + * with the full path. + * + * Numeric IPs, malformed numeric IPs, and URLs pointing to executables are + * also flagged as URLs of interest. + * + * \param line the line + * \param len the line length + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int FindUrlStrings(const char *line, uint32_t len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + char *fptr, *remptr, *tok = NULL, *tempUrl; + uint32_t tokLen, i, tempUrlLen; + uint8_t urlStrLen = 0, flags = 0; + + remptr = (char *) line; + do { + SCLogDebug("Looking for URL String starting with: %s", URL_STR); + + /* Check for token definition */ + fptr = FindString(remptr, len - (remptr - line), URL_STR); + if (fptr != NULL) { + + urlStrLen = strlen(URL_STR); + fptr += urlStrLen; /* Start at end of start string */ + tok = GetToken(fptr, len - (fptr - line), " \"\'<>]\t", &remptr, + &tokLen); + if (tok == fptr) { + SCLogDebug("Found url string"); + + /* First copy to temp URL string */ + tempUrl = SCMalloc(urlStrLen + tokLen); + if (unlikely(tempUrl == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + + PrintChars(SC_LOG_DEBUG, "RAW URL", tok, tokLen); + + /* Copy over to temp URL while decoding */ + tempUrlLen = 0; + for (i = 0; i < tokLen && tok[i] != 0; i++) { + + // URL decoding would probably go here + + tempUrl[tempUrlLen] = tok[i]; + tempUrlLen++; + } + + /* Determine if URL points to an EXE */ + if (IsExeUrl(tempUrl, tempUrlLen)) { + flags |= URL_IS_EXE; + + PrintChars(SC_LOG_DEBUG, "EXE URL", tempUrl, tempUrlLen); + } else { + /* Not an EXE URL */ + /* Cut off length at first '/' */ + tok = FindString(tempUrl, tempUrlLen, "/"); + if (tok != NULL) { + tempUrlLen = tok - tempUrl; + } + } + + /* Make sure remaining URL exists */ + if (tempUrlLen > 0) { + + /* Now look for numeric IP */ + if (IsIpv4Host(tempUrl, tempUrlLen)) { + flags |= URL_IS_IP4; + + PrintChars(SC_LOG_DEBUG, "IP URL4", tempUrl, tempUrlLen); + } else if (IsIpv6Host(tempUrl, tempUrlLen)) { + flags |= URL_IS_IP6; + + PrintChars(SC_LOG_DEBUG, "IP URL6", tempUrl, tempUrlLen); + } + + /* Update URL list */ + MimeDecUrl *url = FindExistingUrl(entity, tempUrl, + tempUrlLen); + if (url == NULL) { + + /* Add URL list item */ + url = MimeDecAddUrl(entity); + url->url = tempUrl; + url->url_len = tempUrlLen; + url->url_flags |= flags; + } else { + SCFree(tempUrl); + } + + /* Increment counter */ + url->url_cnt++; + } else { + SCFree(tempUrl); + } + } + } + } while (fptr != NULL); + + return ret; +} + +/** + * \brief This function is a pre-processor for handling decoded data chunks that + * then invokes the caller's callback function for further processing + * + * \param chunk The decoded chunk + * \param len The decoded chunk length (varies) + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + char *remainPtr, *tok; + uint32_t tokLen; + + MimeDecConfig *mdcfg = MimeDecGetConfig(); + if (mdcfg != NULL && mdcfg->extract_urls) { + /* If plain text or html, then look for URLs */ + if ((entity->ctnt_flags & CTNT_IS_TEXT) || + (entity->ctnt_flags & CTNT_IS_HTML)) { + + /* Remainder from previous line */ + if (state->linerem_len > 0) { + // TODO + } else { + /* No remainder from previous line */ + /* Parse each line one by one */ + remainPtr = (char *) chunk; + do { + tok = GetLine(remainPtr, len - (remainPtr - (char *) chunk), + &remainPtr, &tokLen); + if (tok != remainPtr) { + // DEBUG - ADDED + /* If last token found without CR/LF delimiter, then save + * and reconstruct with next chunk + */ + if (tok + tokLen - (char *) chunk == len) { + PrintChars(SC_LOG_DEBUG, "LAST CHUNK LINE - CUTOFF", + tok, tokLen); + SCLogDebug("\nCHUNK CUTOFF CHARS: %d delim %ld\n", tokLen, len - (tok + tokLen - (char *) chunk)); + } else { + /* Search line for URL */ + ret = FindUrlStrings(tok, tokLen, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: FindUrlStrings() function" + " failed: %d", ret); + break; + } + } + } + } while (tok != remainPtr && remainPtr - (char *) chunk < len); + } + } + } + + /* Now invoke callback */ + if (state->dataChunkProcessor != NULL) { + ret = state->dataChunkProcessor(chunk, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: state->dataChunkProcessor() callback function" + " failed"); + } + } + + /* Reset data chunk buffer */ + state->data_chunk_len = 0; + + /* Mark body / file as no longer at beginning */ + state->body_begin = 0; + + return ret; +} + +/** + * \brief Processes a remainder (line % 4 = remainder) from the previous line + * such that all base64 decoding attempts are divisible by 4 + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * \param force Flag indicating whether decoding should always occur + * + * \return Number of bytes pulled from the current buffer + */ +static uint8_t ProcessBase64Remainder(const char *buf, uint32_t len, + MimeDecParseState *state, int force) { + + uint32_t ret; + uint8_t remainder = 0, remdec = 0; + + SCLogDebug("Base64 line remainder found: %u", state->bvr_len); + + /* Fill in block with first few bytes of current line */ + remainder = B64_BLOCK - state->bvr_len; + remainder = remainder < len ? remainder : len; + strncpy(state->bvremain + state->bvr_len, buf, remainder); + state->bvr_len += remainder; + + /* If data chunk buffer will be full, then clear it now */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, + state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function failed"); + } + } + + /* Only decode if divisible by 4 */ + if (state->bvr_len == B64_BLOCK || force) { + remdec = DecodeBase64(state->data_chunk + state->data_chunk_len, + state->bvremain, state->bvr_len); + if (remdec > 0) { + + /* Track decoded length */ + state->stack->top->data->decoded_body_len += remdec; + + /* Update length */ + state->data_chunk_len += remdec; + + /* If data chunk buffer is now full, then clear */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, + state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function " + "failed"); + } + } + } else { + /* Track failed base64 */ + state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64; + state->msg->anomaly_flags |= ANOM_INVALID_BASE64; + SCLogDebug("Error: DecodeBase64() function failed"); + PrintChars(SC_LOG_DEBUG, "Base64 failed string", state->bvremain, state->bvr_len); + } + + /* Reset remaining */ + state->bvr_len = 0; + } + + return remainder; +} + +/** + * \brief Processes a body line by base64-decoding and passing to the data chunk + * processing callback function when the buffer is read + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessBase64BodyLine(const char *buf, uint32_t len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + uint8_t rem1 = 0, rem2 = 0; + uint32_t numDecoded, remaining, offset, avail, tobuf; + + /* Track long line */ + if (len > MAX_ENC_LINE_LEN) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_ENC_LINE; + state->msg->anomaly_flags |= ANOM_LONG_ENC_LINE; + SCLogDebug("Error: Max encoded input line length exceeded %u > %u", + len, MAX_ENC_LINE_LEN); + } + + /* First process remaining from previous line */ + if (state->bvr_len > 0) { + + SCLogDebug("Base64 line remainder found: %u", state->bvr_len); + + /* Process remainder and return number of bytes pulled from current buffer */ + rem1 = ProcessBase64Remainder(buf, len, state, 0); + } + + /* No error and at least some more data needs to be decoded */ + if ((int) (len - rem1) > 0) { + + /* Determine whether we need to save a remainder if not divisible by 4 */ + rem2 = (len - rem1) % B64_BLOCK; + if (rem2 > 0) { + + SCLogDebug("Base64 saving remainder: %u", rem2); + + strncpy(state->bvremain, buf + (len - rem2), rem2); + state->bvr_len = rem2; + } + + /* Process remaining in loop in case buffer fills up */ + remaining = len - rem1 - rem2; + offset = rem1; + while (remaining > 0) { + + /* Determine amount to add to buffer */ + avail = (DATA_CHUNK_SIZE - state->data_chunk_len) * B64_BLOCK / ASCII_BLOCK; + tobuf = avail > remaining ? remaining : avail; + while (tobuf % 4 != 0) { + tobuf--; + } + + if (tobuf < B64_BLOCK) { + SCLogDebug("Error: Invalid state for decoding base-64 block"); + return MIME_DEC_ERR_PARSE; + } + + SCLogDebug("Decoding: %u", len - rem1 - rem2); + + numDecoded = DecodeBase64(state->data_chunk + state->data_chunk_len, + buf + offset, tobuf); + if (numDecoded > 0) { + + /* Track decoded length */ + state->stack->top->data->decoded_body_len += numDecoded; + + /* Update length */ + state->data_chunk_len += numDecoded; + + if ((int) (DATA_CHUNK_SIZE - state->data_chunk_len) < 0) { + SCLogDebug("Error: Invalid Chunk length: %u", + state->data_chunk_len); + ret = MIME_DEC_ERR_PARSE; + break; + } + + /* If buffer full, then invoke callback */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, + state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() " + "function failed"); + } + } + } else { + /* Track failed base64 */ + state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64; + state->msg->anomaly_flags |= ANOM_INVALID_BASE64; + SCLogDebug("Error: DecodeBase64() function failed"); + PrintChars(SC_LOG_DEBUG, "Base64 failed string", (char *) (buf + offset), tobuf); + } + + /* Update counts */ + remaining -= tobuf; + offset += tobuf; + } + } + + return ret; +} + +/** + * \brief Decoded a hex character into its equivalent byte value for + * quoted-printable decoding + * + * \param h The hex char + * + * \return byte value on success, -1 if failed + **/ +static int16_t DecodeQPChar(char h) { + uint16_t res = 0; + + /* 0-9 */ + if (h >= 48 && h <= 57) { + res = h - 48; + } else if (h >= 65 && h <= 70) { + /* A-F */ + res = h - 55; + } else { + /* Invalid */ + res = -1; + } + + return res; + +} + +/** + * \brief Processes a quoted-printable encoded body line by decoding and passing + * to the data chunk processing callback function when the buffer is read + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessQuotedPrintableBodyLine(const char *buf, uint32_t len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + uint32_t remaining, offset; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + char c, h1, h2, val; + int16_t res; + + /* Track long line */ + if (len > MAX_ENC_LINE_LEN) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_ENC_LINE; + state->msg->anomaly_flags |= ANOM_LONG_ENC_LINE; + SCLogDebug("Error: Max encoded input line length exceeded %u > %u", + len, MAX_ENC_LINE_LEN); + } + + remaining = len; + offset = 0; + while (remaining > 0) { + + c = *(buf + offset); + + /* Copy over normal character */ + if (c != '=') { + state->data_chunk[state->data_chunk_len] = c; + state->data_chunk_len++; + entity->decoded_body_len += 1; + + /* Add CRLF sequence if end of line */ + if (remaining == 1) { + memcpy(state->data_chunk + state->data_chunk_len, CRLF, EOL_LEN); + state->data_chunk_len += EOL_LEN; + entity->decoded_body_len += EOL_LEN; + } + } else if (remaining > 1) { + /* If last character handle as soft line break by ignoring, + otherwise process as escaped '=' character */ + + /* Not enough characters */ + if (remaining < 3) { + entity->anomaly_flags |= ANOM_INVALID_QP; + state->msg->anomaly_flags |= ANOM_INVALID_QP; + SCLogDebug("Error: Quoted-printable decoding failed"); + } else { + h1 = *(buf + offset + 1); + res = DecodeQPChar(h1); + if (res < 0) { + entity->anomaly_flags |= ANOM_INVALID_QP; + state->msg->anomaly_flags |= ANOM_INVALID_QP; + SCLogDebug("Error: Quoted-printable decoding failed"); + } else { + val = (res << 4); /* Shift result left */ + h2 = *(buf + offset + 2); + res = DecodeQPChar(h2); + if (res < 0) { + entity->anomaly_flags |= ANOM_INVALID_QP; + state->msg->anomaly_flags |= ANOM_INVALID_QP; + SCLogDebug("Error: Quoted-printable decoding failed"); + } else { + /* Decoding sequence succeeded */ + val += res; + + state->data_chunk[state->data_chunk_len] = val; + state->data_chunk_len++; + entity->decoded_body_len++; + + /* Add CRLF sequence if end of line */ + if (remaining == 3) { + memcpy(state->data_chunk + state->data_chunk_len, + CRLF, EOL_LEN); + state->data_chunk_len += EOL_LEN; + entity->decoded_body_len += EOL_LEN; + } + + /* Account for extra 2 characters in 3-characted QP + * sequence */ + remaining -= 2; + offset += 2; + } + } + } + } + + /* Change by 1 */ + remaining--; + offset++; + + /* If buffer full, then invoke callback */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < EOL_LEN + 1) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, + state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function " + "failed"); + } + } + } + + return ret; +} + +/** + * \brief Processes a body line by base64-decoding (if applicable) and passing to + * the data chunk processing callback function + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessBodyLine(const char *buf, uint32_t len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + uint32_t remaining, offset, avail, tobuf; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + + SCLogDebug("Processing body line"); + + /* Track length */ + entity->body_len += len + 2; /* With CRLF */ + + /* Process base-64 content if enabled */ + MimeDecConfig *mdcfg = MimeDecGetConfig(); + if (mdcfg != NULL && mdcfg->decode_base64 && + (entity->ctnt_flags & CTNT_IS_BASE64)) { + + ret = ProcessBase64BodyLine(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBase64BodyLine() function failed"); + } + } else if (mdcfg != NULL && mdcfg->decode_quoted_printable && + (entity->ctnt_flags & CTNT_IS_QP)) { + /* Process quoted-printable content if enabled */ + ret = ProcessQuotedPrintableBodyLine(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessQuotedPrintableBodyLine() function " + "failed"); + } + } else { + /* Process non-decoded content */ + remaining = len; + offset = 0; + while (remaining > 0) { + + /* Plan to add CRLF to the end of each line */ + avail = DATA_CHUNK_SIZE - state->data_chunk_len; + tobuf = avail > remaining + EOL_LEN ? remaining : avail - EOL_LEN; + + /* Copy over to buffer */ + memcpy(state->data_chunk + state->data_chunk_len, buf + offset, tobuf); + state->data_chunk_len += tobuf; + + /* Now always add a CRLF to the end */ + if (tobuf == remaining) { + memcpy(state->data_chunk + state->data_chunk_len, CRLF, EOL_LEN); + state->data_chunk_len += EOL_LEN; + } + + if ((int) (DATA_CHUNK_SIZE - state->data_chunk_len) < 0) { + SCLogDebug("Error: Invalid Chunk length: %u", + state->data_chunk_len); + ret = MIME_DEC_ERR_PARSE; + break; + } + + /* If buffer full, then invoke callback */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < EOL_LEN + 1) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, + state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function " + "failed"); + } + } + + remaining -= tobuf; + offset += tobuf; + } + } + + return ret; +} + +/** + * \brief Find the start of a header name on the current line + * + * \param buf The input line (not null-terminated) + * \param blen The length of the input line + * \param glen The output length of the header name + * + * \return Pointer to header name, or NULL if not found + */ +static char * FindMimeHeaderStart(const char *buf, uint32_t blen, uint32_t *hlen) { + + uint32_t i, valid = 0; + char *hname = NULL; + + /* Init */ + *hlen = 0; + + /* Look for sequence of printable characters followed by ':', or + CRLF then printable characters followed by ':' */ + for (i = 0; i < blen && buf[i] != 0; i++) { + + /* If ready for printable characters and found one, then increment */ + if (buf[i] != COLON && buf[i] >= PRINTABLE_START && + buf[i] <= PRINTABLE_END) { + valid++; + } else if (valid > 0 && buf[i] == COLON) { + /* If ready for printable characters, found some, and found colon + * delimiter, then a match is found */ + hname = (char *) buf + i - valid; + *hlen = valid; + break; + } else { + /* Otherwise reset and quit */ + break; + } + } + + return hname; +} + +/** + * \brief Find full header name and value on the current line based on the + * current state + * + * \param buf The current line (no CRLF) + * \param blen The length of the current line + * \param state The current state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int FindMimeHeader(const char *buf, uint32_t blen, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + char *hname, *hval = NULL; + DataValue *dv; + uint32_t hlen, vlen; + int finish_header = 0, new_header = 0; + MimeDecConfig *mdcfg = MimeDecGetConfig(); + + /* Find first header */ + hname = FindMimeHeaderStart(buf, blen, &hlen); + if (hname != NULL) { + + /* Warn and track but don't do anything yet */ + if (hlen > MAX_HEADER_NAME) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_NAME; + state->msg->anomaly_flags |= ANOM_LONG_HEADER_NAME; + SCLogDebug("Error: Header name exceeds limit (%u > %u)", + hlen, MAX_HEADER_NAME); + } + + /* Value starts after 'header:' (normalize spaces) */ + hval = hname + hlen + 1; + if (hval - buf >= blen) { + SCLogDebug("No Header value found"); + hval = NULL; + } else { + while (hval[0] == ' ') { + + /* If last character before end of bounds, set to NULL */ + if (hval - buf >= blen - 1) { + SCLogDebug("No Header value found"); + hval = NULL; + break; + } + + hval++; + } + } + + /* If new header found, then previous header is finished */ + if (state->state_flag == HEADER_STARTED) { + finish_header = 1; + } + + /* Now process new header */ + new_header = 1; + + /* Must wait for next line to determine if finished */ + state->state_flag = HEADER_STARTED; + } else if (blen == 0) { + /* Found body */ + /* No more headers */ + state->state_flag = HEADER_DONE; + + finish_header = 1; + + SCLogDebug("All Header processing finished"); + } else if (state->state_flag == HEADER_STARTED) { + /* Found multi-line value (ie. Received header) */ + /* If max header value exceeded, flag it */ + vlen = blen; + if ((mdcfg != NULL) && (state->hvlen + vlen > mdcfg->header_value_depth)) { + SCLogDebug("Error: Header value of length (%u) is too long", + state->hvlen + vlen); + vlen = mdcfg->header_value_depth - state->hvlen; + state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + state->msg->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + } + if (vlen > 0) { + dv = AddDataValue(state->hvalue); + if (dv == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "AddDataValue() function failed"); + return MIME_DEC_ERR_MEM; + } + if (state->hvalue == NULL) { + state->hvalue = dv; + } + + dv->value = SCMalloc(vlen); + if (unlikely(dv->value == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + strncpy(dv->value, (char *) buf, vlen); + dv->value_len = vlen; + state->hvlen += vlen; + } + } else { + /* Likely a body without headers */ + SCLogDebug("No headers found"); + + state->state_flag = BODY_STARTED; + + /* Flag beginning of body */ + state->body_begin = 1; + state->body_end = 0; + + ret = ProcessBodyLine(buf, blen, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyLine() function failed"); + return ret; + } + } + + /* If we need to finish a header, then do so below and then cleanup */ + if (finish_header) { + + /* Store the header value */ + ret = StoreMimeHeader(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: StoreMimeHeader() function failed"); + return ret; + } + } + + /* When next header is found, we always create a new one */ + if (new_header) { + + /* Copy name and value to state */ + state->hname = SCMalloc(hlen); + if (unlikely(state->hname == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + strncpy(state->hname, hname, hlen); + state->hlen = hlen; + + if (state->hvalue != NULL) { + SCLogDebug("Error: Parser failed due to unexpected header " + "value"); + return MIME_DEC_ERR_DATA; + } + + if (hval != NULL) { + + /* If max header value exceeded, flag it */ + vlen = blen - (hval - buf); + if ((mdcfg != NULL) && (state->hvlen + vlen > mdcfg->header_value_depth)) { + SCLogDebug("Error: Header value of length (%u) is too long", + state->hvlen + vlen); + vlen = mdcfg->header_value_depth - state->hvlen; + state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + state->msg->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + } + if (vlen > 0) { + + state->hvalue = AddDataValue(NULL); + if (state->hvalue == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "AddDataValue() function failed"); + return MIME_DEC_ERR_MEM; + } + state->hvalue->value = SCMalloc(vlen); + if (unlikely(state->hvalue->value == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + strncpy(state->hvalue->value, hval, vlen); + state->hvalue->value_len = vlen; + state->hvlen += vlen; + } + } + } + + return ret; +} + +/** + * \brief Finds a mime header token within the specified field + * + * \param field The current field + * \param search_start The start of the search (ie. boundary=\") + * \param search_end The end of the search (ie. \") + * \param tlen The output length of the token (if found) + * + * \return A pointer to the token if found, otherwise NULL if not found + */ +static char * FindMimeHeaderToken(MimeDecField *field, char *search_start, + char *search_end, uint32_t *tlen) { + + char *fptr, *tptr = NULL, *tok = NULL; + + SCLogDebug("Looking for token: %s", search_start); + + /* Check for token definition */ + fptr = FindString(field->value, field->value_len, search_start); + if (fptr != NULL) { + fptr += strlen(search_start); /* Start at end of start string */ + tok = GetToken(fptr, field->value_len - (fptr - field->value), search_end, + &tptr, tlen); + if (tok != NULL) { + SCLogDebug("Found mime token"); + } + } + + return tok; +} + +/** + * \brief Processes the current line for mime headers and also does post-processing + * when all headers found + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeHeaders(const char *buf, uint32_t len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + MimeDecField *field; + char *bptr = NULL, *rptr = NULL; + uint32_t blen = 0; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + + /* Look for mime header in current line */ + ret = FindMimeHeader(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: FindMimeHeader() function failed: %d", ret); + return ret; + } + + /* Post-processing after all headers done */ + if (state->state_flag == HEADER_DONE) { + + /* First determine encoding by looking at Content-Transfer-Encoding */ + field = MimeDecFindField(entity, CTNT_TRAN_STR); + if (field != NULL) { + /* Look for base64 */ + if (FindString(field->value, field->value_len, BASE64_STR)) { + SCLogDebug("Base64 encoding found"); + entity->ctnt_flags |= CTNT_IS_BASE64; + } else if (FindString(field->value, field->value_len, QP_STR)) { + /* Look for quoted-printable */ + SCLogDebug("quoted-printable encoding found"); + entity->ctnt_flags |= CTNT_IS_QP; + } + } + + /* Check for file attachment in content disposition */ + field = MimeDecFindField(entity, CTNT_DISP_STR); + if (field != NULL) { + bptr = FindMimeHeaderToken(field, "filename=\"", TOK_END_STR, &blen); + if (bptr != NULL) { + SCLogDebug("File attachment found in disposition"); + entity->ctnt_flags |= CTNT_IS_ATTACHMENT; + + /* Copy over using dynamic memory */ + entity->filename = SCMalloc(blen); + if (unlikely(entity->filename == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + strncpy(entity->filename, bptr, blen); + entity->filename_len = blen; + } + } + + /* Check for boundary, encapsulated message, and file name in Content-Type */ + field = MimeDecFindField(entity, CTNT_TYPE_STR); + if (field != NULL) { + + /* Check if child entity boundary definition found */ + bptr = FindMimeHeaderToken(field, BND_START_STR, TOK_END_STR, &blen); + if (bptr != NULL) { + state->found_child = 1; + + entity->ctnt_flags |= CTNT_IS_MULTIPART; + + /* Store boundary in parent node */ + state->stack->top->bdef = SCMalloc(blen); + if (unlikely(state->stack->top->bdef == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + strncpy(state->stack->top->bdef, bptr, blen); + state->stack->top->bdef_len = blen; + } + + /* Look for file name (if not already found) */ + if (!(entity->ctnt_flags & CTNT_IS_ATTACHMENT)) { + bptr = FindMimeHeaderToken(field, "name=\"", TOK_END_STR, &blen); + if (bptr != NULL) { + SCLogDebug("File attachment found"); + entity->ctnt_flags |= CTNT_IS_ATTACHMENT; + + /* Copy over using dynamic memory */ + entity->filename = SCMalloc(blen); + if (unlikely(entity->filename == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + strncpy(entity->filename, bptr, blen); + entity->filename_len = blen; + } + } + + /* Pull out short-hand content type */ + entity->ctnt_type = GetToken(field->value, field->value_len, " \r\n;", + &rptr, &entity->ctnt_type_len); + if (entity->ctnt_type != NULL) { + + /* Check for encapsulated message */ + if (FindString(entity->ctnt_type, entity->ctnt_type_len, MSG_STR)) { + SCLogDebug("Found encapsulated message entity"); + + entity->ctnt_flags |= CTNT_IS_ENV; + + /* Create and push child to stack */ + MimeDecEntity *child = MimeDecAddEntity(entity); + child->ctnt_flags |= (CTNT_IS_ENCAP | CTNT_IS_MSG); + PushStack(state->stack); + state->stack->top->data = child; + + /* Mark as encapsulated child */ + state->stack->top->is_encap = 1; + + /* Ready to parse headers */ + state->state_flag = HEADER_READY; + } else if (FindString(entity->ctnt_type, entity->ctnt_type_len, + MULTIPART_STR)) { + /* Check for multipart */ + SCLogDebug("Found multipart entity"); + entity->ctnt_flags |= CTNT_IS_MULTIPART; + } else if (FindString(entity->ctnt_type, entity->ctnt_type_len, + TXT_STR)) { + /* Check for plain text */ + SCLogDebug("Found plain text entity"); + entity->ctnt_flags |= CTNT_IS_TEXT; + } else if (FindString(entity->ctnt_type, entity->ctnt_type_len, + HTML_STR)) { + /* Check for html */ + SCLogDebug("Found html entity"); + entity->ctnt_flags |= CTNT_IS_HTML; + } + } + } + + /* Store pointer to Message-ID */ + field = MimeDecFindField(entity, MSG_ID_STR); + if (field != NULL) { + entity->msg_id = field->value; + entity->msg_id_len = field->value_len; + } + + /* Flag beginning of body */ + state->body_begin = 1; + state->body_end = 0; + } + + return ret; +} + +/** + * \brief Indicates to the parser that the body of an entity has completed + * processing on the previous line + * + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessBodyComplete(MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + + SCLogDebug("Process body complete called"); + + /* Mark the file as hitting the end */ + state->body_end = 1; + + if (state->bvr_len > 0) { + SCLogDebug("Found (%u) remaining base64 bytes not processed", + state->bvr_len); + + /* Process the remainder */ + ret = ProcessBase64Remainder(NULL, 0, state, 1); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBase64BodyLine() function failed"); + } + } + + /* Invoke pre-processor and callback with remaining data */ + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function failed"); + } + + /* Now reset */ + state->body_begin = 0; + state->body_end = 0; + + return ret; +} + +/** + * \brief When a mime boundary is found, look for end boundary and also do stack + * management + * + * \param buf The current line + * \param len The length of the line + * \param bdef_len The length of the current boundary + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeBoundary(const char *buf, uint32_t len, uint32_t bdef_len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + char *rptr; + MimeDecEntity *child; + + SCLogDebug("PROCESSING BOUNDARY - START: %d", + state->state_flag); + + /* If previous line was not an end boundary, then we process the body as + * completed */ + if (state->state_flag != BODY_END_BOUND) { + + /* First lets complete the body */ + ret = ProcessBodyComplete(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyComplete() function failed"); + return ret; + } + } else { + /* If last line was an end boundary, then now we are ready to parse + * headers again */ + state->state_flag = HEADER_READY; + } + + /* Update remaining buffer */ + rptr = (char *) buf + bdef_len + 2; + + /* If entity is encapsulated and current and parent didn't define the boundary, + * then pop out */ + if (state->stack->top->is_encap && state->stack->top->bdef_len == 0) { + + if (state->stack->top->next == NULL) { + SCLogDebug("Error: Missing parent entity from stack"); + return MIME_DEC_ERR_DATA; + } + + if (state->stack->top->next->bdef_len == 0) { + + SCLogDebug("POPPED ENCAPSULATED CHILD FROM STACK: %p=%p", + state->stack->top, state->stack->top->data); + + /* If end of boundary found, pop the child off the stack */ + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + } + } + + /* Now check for end of nested boundary */ + if (len - (rptr - buf) > 1 && rptr[0] == DASH && rptr[1] == DASH) { + + SCLogDebug("FOUND END BOUNDARY, POPPING: %p=%p", + state->stack->top, state->stack->top->data); + + /* If end of boundary found, pop the child off the stack */ + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + + /* If current is an encapsulated message with a boundary definition, + * then pop him as well */ + if (state->stack->top->is_encap && state->stack->top->bdef_len != 0) { + + SCLogDebug("FOUND END BOUNDARY AND ENCAP, POPPING: %p=%p", + state->stack->top, state->stack->top->data); + + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + } + + state->state_flag = BODY_END_BOUND; + } else if (state->found_child) { + /* Otherwise process new child */ + SCLogDebug("Child entity created"); + + /* Create and push child to stack */ + child = MimeDecAddEntity(state->stack->top->data); + child->ctnt_flags |= CTNT_IS_BODYPART; + PushStack(state->stack); + state->stack->top->data = child; + + /* Reset flag */ + state->found_child = 0; + } else { + /* Otherwise process sibling */ + if (state->stack->top->next == NULL) { + SCLogDebug("Error: Missing parent entity from stack"); + return MIME_DEC_ERR_DATA; + } + + SCLogDebug("SIBLING CREATED, POPPING PARENT: %p=%p", + state->stack->top, state->stack->top->data); + + /* First pop current to get access to parent */ + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + + /* Create and push child to stack */ + child = MimeDecAddEntity(state->stack->top->data); + child->ctnt_flags |= CTNT_IS_BODYPART; + PushStack(state->stack); + state->stack->top->data = child; + } + + /* After boundary look for headers */ + if (state->state_flag != BODY_END_BOUND) { + state->state_flag = HEADER_READY; + } + + SCLogDebug("PROCESSING BOUNDARY - END: %d", state->state_flag); + + return ret; +} + +/** + * \brief Processes the MIME Entity body based on the input line and current + * state of the parser + * + * \param buf The current line + * \param len The length of the line + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeBody(const char *buf, uint32_t len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + char temp[BOUNDARY_BUF]; + char *bstart; + int body_found = 0; + uint32_t tlen; + + /* Ignore empty lines */ + if (len == 0) { + return ret; + } + + /* First look for boundary */ + MimeDecStackNode *node = state->stack->top; + if (node == NULL) { + SCLogDebug("Error: Invalid stack state"); + return MIME_DEC_ERR_PARSE; + } + + /* Traverse through stack to find a boundary definition */ + if (state->state_flag == BODY_END_BOUND || node->bdef == NULL) { + + /* If not found, then use parent's boundary */ + node = node->next; + while (node != NULL && node->bdef == NULL) { + SCLogDebug("Traversing through stack for node with boundary"); + node = node->next; + } + } + + /* This means no boundary / parent w/boundary was found so we are in the body */ + if (node == NULL) { + body_found = 1; + } else { + + /* Now look for start of boundary */ + if (len > 1 && buf[0] == '-' && buf[1] == '-') { + + tlen = node->bdef_len + 2; + strncpy(temp, "--", 2); + strncpy(temp + 2, node->bdef, node->bdef_len); + temp[tlen] = 0; + + SCLogDebug("Boundary to search: [%s]", temp); + + /* Find either next boundary or end boundary */ + bstart = FindString(buf, len, temp); + if (bstart != NULL) { + ret = ProcessMimeBoundary(buf, len, node->bdef_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessMimeBoundary() function " + "failed"); + return ret; + } + } else { + /* Otherwise add value to body */ + body_found = 1; + } + } else { + /* Otherwise add value to body */ + body_found = 1; + } + } + + /* Process body line */ + if (body_found) { + state->state_flag = BODY_STARTED; + + ret = ProcessBodyLine(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyLine() function failed"); + return ret; + } + } + + return ret; +} + +/** + * \brief Processes the MIME Entity based on the input line and current state of + * the parser + * + * \param buf The current line + * \param len The length of the line + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeEntity(const char *buf, uint32_t len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + + SCLogDebug("START FLAG: %s", StateFlags[state->state_flag]); + + /* Track long line */ + if (len > MAX_LINE_LEN) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_LINE; + state->msg->anomaly_flags |= ANOM_LONG_LINE; + SCLogDebug("Error: Max input line length exceeded %u > %u", len, + MAX_LINE_LEN); + } + + /* Looking for headers */ + if (state->state_flag == HEADER_READY || + state->state_flag == HEADER_STARTED) { + + SCLogDebug("Processing Headers"); + + /* Process message headers */ + ret = ProcessMimeHeaders(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessMimeHeaders() function failed: %d", + ret); + return ret; + } + } else { + /* Processing body */ + SCLogDebug("Processing Body of: %p", state->stack->top); + + ret = ProcessMimeBody(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessMimeBody() function failed: %d", + ret); + return ret; + } + } + + SCLogDebug("END FLAG: %s", StateFlags[state->state_flag]); + + return ret; +} + +/** + * \brief Init the parser by allocating memory for the state and top-level entity + * + * \param data A caller-specified pointer to data for access within the data chunk + * processor callback function + * \param dcpfunc The data chunk processor callback function + * + * \return A pointer to the state object, or NULL if the operation fails + */ +MimeDecParseState * MimeDecInitParser(void *data, + int (*dcpfunc)(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state)) { + + MimeDecParseState *state; + MimeDecEntity *mimeMsg; + + state = SCMalloc(sizeof(MimeDecParseState)); + if (unlikely(state == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(state, 0x00, sizeof(MimeDecParseState)); + + state->stack = SCMalloc(sizeof(MimeDecStack)); + if (unlikely(state->stack == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(state->stack, 0x00, sizeof(MimeDecStack)); + + mimeMsg = SCMalloc(sizeof(MimeDecEntity)); + if (unlikely(mimeMsg == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(mimeMsg, 0x00, sizeof(MimeDecEntity)); + mimeMsg->ctnt_flags |= CTNT_IS_MSG; + + /* Init state */ + state->msg = mimeMsg; + PushStack(state->stack); + if (state->stack->top == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + state->stack->top->data = mimeMsg; + state->state_flag = HEADER_READY; + state->data = data; + state->dataChunkProcessor = dcpfunc; + + return state; +} + +/** + * \brief De-Init parser by freeing up any residual memory + * + * \param state The parser state + * + * \return none + */ +void MimeDecDeInitParser(MimeDecParseState *state) { + + uint32_t cnt = 0; + + while (state->stack->top != NULL) { + + SCLogDebug("Remaining on stack: [%p]=>[%p]", + state->stack->top, state->stack->top->data); + + PopStack(state->stack); + cnt++; + } + + if (cnt > 1) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Warning: Stack is not empty upon completion of " + "processing (%u items remaining)", cnt); + } + + SCFree(state->hname); + FreeDataValue(state->hvalue); + FreeMimeDecStack(state->stack); + SCFree(state); +} + +/** + * \brief Called to indicate that the last message line has been processed and + * the parsing operation is complete + * + * This function should be called directly by the caller. + * + * \param state The parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +int MimeDecParseComplete(MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + + SCLogDebug("Parsing flagged as completed"); + + /* Store the header value */ + ret = StoreMimeHeader(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: StoreMimeHeader() function failed"); + return ret; + } + + /* Lets complete the body */ + ret = ProcessBodyComplete(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyComplete() function failed"); + return ret; + } + + if (state->stack->top == NULL) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + + /* If encapsulated, pop off the stack */ + if (state->stack->top->is_encap) { + PopStack(state->stack); + if (state->stack->top == NULL) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + } + + /* Look extra stack items remaining */ + if (state->stack->top->next != NULL) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Warning: Message has unclosed message part boundary"); + } + + state->state_flag = PARSE_DONE; + + return ret; +} + +/** + * \brief Parse a line of a MIME message and update the parser state + * + * \param line A string representing the line (w/out CRLF) + * \param len The length of the line + * \param state The parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +int MimeDecParseLine(const char *line, const uint32_t len, + MimeDecParseState *state) { + + int ret = MIME_DEC_OK; + + /* For debugging purposes */ + if (len > 0) { + PrintChars(SC_LOG_DEBUG, "\nSMTP LINE", (char *) line, len); + } else { + SCLogDebug("\nSMTP LINE - EMPTY"); + } + + /* Process the entity */ + ret = ProcessMimeEntity(line, len, state); + if (ret != MIME_DEC_OK) { + state->state_flag = PARSE_ERROR; + SCLogDebug("Error: ProcessMimeEntity() function failed: %d", ret); + } + + return ret; +} + +/** + * \brief Parses an entire message when available in its entirety (wraps the + * line-based parsing functions) + * + * \param buf Buffer pointing to the full message + * \param blen Length of the buffer + * \param data Caller data to be available in callback + * \param dcpfunc Callback for processing each decoded body data chunk + * + * \return A pointer to the decoded MIME message, or NULL if the operation fails + */ +MimeDecEntity * MimeDecParseFullMsg(const char *buf, uint32_t blen, void *data, + int (*dcpfunc)(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state)) { + + int ret = MIME_DEC_OK; + char *remainPtr, *tok; + uint32_t tokLen; + + MimeDecParseState *state = MimeDecInitParser(data, dcpfunc); + if (state == NULL) { + SCLogDebug("Error: MimeDecInitParser() function failed to create " + "state"); + return NULL; + } + + MimeDecEntity *msg = state->msg; + + /* Parse each line one by one */ + remainPtr = (char *) buf; + char *line = NULL; + do { + tok = GetLine(remainPtr, blen - (remainPtr - buf), &remainPtr, &tokLen); + if (tok != remainPtr) { + + line = tok; + + /* Parse the line */ + ret = MimeDecParseLine(line, tokLen, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: MimeDecParseLine() function failed: %d", + ret); + break; + } + } + + } while (tok != remainPtr && remainPtr - buf < blen); + + if (ret == MIME_DEC_OK) { + SCLogDebug("Message parser was successful"); + + /* Now complete message */ + ret = MimeDecParseComplete(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: MimeDecParseComplete() function failed"); + } + } + + /* De-allocate memory for parser */ + MimeDecDeInitParser(state); + + if (ret != MIME_DEC_OK) { + MimeDecFreeEntity(msg); + msg = NULL; + } + + return msg; +} + +#ifdef UNITTESTS + +/* Helper body chunk callback function */ +static int TestDataChunkCallback(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state) { + + uint32_t *line_count = (uint32_t *) state->data; + + if (state->body_begin) { + SCLogDebug("Body begin (len=%u)", len); + } + + /* Add up the line counts */ + if (len > 0) { + + char *remainPtr; + char *tok; + uint32_t tokLen; + + PrintChars(SC_LOG_DEBUG, (char *) "CHUNK", (char *) chunk, len); + + /* Parse each line one by one */ + remainPtr = (char *) chunk; + do { + tok = GetLine(remainPtr, len - (remainPtr - (char *) chunk), + &remainPtr, &tokLen); + if (tok != NULL && tok != remainPtr) { + (*line_count)++; + } + + } while (tok != NULL && tok != remainPtr && + remainPtr - (char *) chunk < len); + + SCLogDebug("line count (len=%u): %u", len, *line_count); + } + + if (state->body_end) { + SCLogDebug("Body end (len=%u)", len); + } + + return MIME_DEC_OK; +} + +/* Test simple case of line counts */ +static int MimeDecParseLineTest01(void) { + int ret = MIME_DEC_OK; + + uint32_t expected_count = 3; + uint32_t line_count = 0; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, + TestDataChunkCallback); + + char str[256]; + strcpy(str, "From: Sender1"); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, "To: Recipient1"); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, "Content-Type: text/plain"); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, ""); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, "A simple message line 1"); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, "A simple message line 2"); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, "A simple message line 3"); + ret = MimeDecParseLine(str, strlen(str), state); + + /* Completed */ + ret = MimeDecParseComplete(state); + if (ret != MIME_DEC_OK) { + return ret; + } + + MimeDecEntity *msg = state->msg; + if (msg->next != NULL || msg->child != NULL) { + SCLogInfo("Error: Invalid sibling or child message"); + return -1; + } + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + SCLogInfo("LINE COUNT FINISHED: %d", line_count); + + if (expected_count != line_count) { + SCLogInfo("Error: Line count is invalid: expected - %d actual - %d", + expected_count, line_count); + return -1; + } + + return ret; +} + +/* Test simple case of EXE URL extraction */ +static int MimeDecParseLineTest02(void) { + int ret = MIME_DEC_OK; + + uint32_t expected_count = 2; + uint32_t line_count = 0; + + MimeDecGetConfig()->decode_base64 = 1; + MimeDecGetConfig()->decode_quoted_printable = 1; + MimeDecGetConfig()->extract_urls = 1; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, + TestDataChunkCallback); + + char str[256]; + strcpy(str, "From: Sender1"); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, "To: Recipient1"); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, "Content-Type: text/plain"); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, ""); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, "A simple message line 1"); + ret = MimeDecParseLine(str, strlen(str), state); + + strcpy(str, "A simple message line 2 click on http://www.test.com/malware.exe?" + "hahah hopefully you click this link"); + ret = MimeDecParseLine(str, strlen(str), state); + + /* Completed */ + ret = MimeDecParseComplete(state); + if (ret != MIME_DEC_OK) { + return ret; + } + + MimeDecEntity *msg = state->msg; + if (msg->url_list == NULL || (msg->url_list != NULL && + !(msg->url_list->url_flags & URL_IS_EXE))) { + SCLogInfo("Warning: Expected EXE URL not found"); + return -1; + } + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + SCLogInfo("LINE COUNT FINISHED: %d", line_count); + + if (expected_count != line_count) { + SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", + expected_count, line_count); + return -1; + } + + return ret; +} + +/* Test full message with linebreaks */ +static int MimeDecParseFullMsgTest01(void) { + int ret = MIME_DEC_OK; + + uint32_t expected_count = 3; + uint32_t line_count = 0; + + char msg[] = "From: Sender1\r\n" + "To: Recipient1\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Line 1\r\n" + "Line 2\r\n" + "Line 3\r\n"; + + MimeDecEntity *entity = MimeDecParseFullMsg(msg, strlen(msg), &line_count, + TestDataChunkCallback); + if (entity == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return -1; + } + + if (expected_count != line_count) { + SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", + expected_count, line_count); + return -1; + } + + return ret; +} + +static int MimeBase64DecodeTest01(void){ + + int ret = -1; + + char *msg = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@" + "#$%^&*()-=_+,./;'[]<>?:"; + char *base64msg = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QU" + "VJTVFVWV1hZWjEyMzQ1Njc4OTBAIyQlXiYqKCktPV8rLC4vOydbXTw+Pzo="; + + char *dst; + dst = (char *)malloc(strlen(msg)-1); + + ret = DecodeBase64((uint8_t *)dst, base64msg, strlen(base64msg)); + + if(strcmp(dst, msg) == 0){ + ret = 0; + } + + return ret; +} + +static int MimeIsExeURLTest01(void){ + int ret = -1; + char *url1 = "http://www.google.com/"; + char *url2 = "http://www.google.com/test.exe"; + + if(IsExeUrl(url1, strlen(url1)) != 0){ + SCLogDebug("Debug: URL1 error"); + goto end; + } + if(IsExeUrl(url2, strlen(url2)) != 1){ + SCLogDebug("Debug: URL2 error"); + goto end; + } + ret = 0; + + end: + + return ret; +} + +static int MimeIsIpv4HostTest01(void) { + + if(IsIpv4Host("192.168.1.1", 11) != 1) { + return 1; + } + + if(IsIpv4Host("999.oogle.com", 14) != 0) { + return 1; + } + + if(IsIpv4Host("0:0:0:0:0:0:0:0", 15) != 0) { + return 1; + } + + if (IsIpv4Host("192.168.255.255", 15) != 1) { + return 1; + } + + if (IsIpv4Host("192.168.255.255/testurl.html", 28) != 1) { + return 1; + } + + if (IsIpv4Host("www.google.com", 14) != 0) { + return 1; + } + + return 0; +} + +static int MimeIsIpv6HostTest01(void) { + + if(IsIpv6Host("0:0:0:0:0:0:0:0", 19) != 1) { + return 1; + } + + if(IsIpv6Host("0000:0000:0000:0000:0000:0000:0000:0000", 39) != 1) { + return 1; + } + + if(IsIpv6Host("0:0:0:0:0:0:0:0", 19) != 1) { + return 1; + } + + if(IsIpv6Host("192:168:1:1:0:0:0:0", 19) != 1) { + return 1; + } + + if(IsIpv6Host("999.oogle.com", 14) != 0) { + return 1; + } + + if (IsIpv6Host("192.168.255.255", 15) != 0) { + return 1; + } + + if (IsIpv6Host("192.168.255.255/testurl.html", 28) != 0) { + return 1; + } + + if (IsIpv6Host("www.google.com", 14) != 0) { + return 1; + } + + return 0; +} + +#endif /* UNITTESTS */ + +void MimeDecRegisterTests(void) { +#ifdef UNITTESTS + UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01, 0); + UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02, 0); + UtRegisterTest("MimeDecParseFullMsgTest01", MimeDecParseFullMsgTest01, 0); + UtRegisterTest("MimeBase64DecodeTest01", MimeBase64DecodeTest01, 0); + UtRegisterTest("MimeIsExeURLTest01", MimeIsExeURLTest01, 0); + UtRegisterTest("MimeIsIpv4HostTest01", MimeIsIpv4HostTest01, 0); + UtRegisterTest("MimeIsIpv6HostTest01", MimeIsIpv6HostTest01, 0); +#endif /* UNITTESTS */ +} diff --git a/src/mime-decode.h b/src/mime-decode.h new file mode 100644 index 000000000000..381907c66eca --- /dev/null +++ b/src/mime-decode.h @@ -0,0 +1,240 @@ +/* Copyright (C) 2012 BAE Systems + * + * 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 David Abarbanel + * + */ + +#ifndef MIME_DECODE_H_ +#define MIME_DECODE_H_ + +#include +#include +#include + +#include "suricata.h" +#include "util-base64.h" +#include "util-debug.h" + +/* Header Flags */ + +/* Content Flags */ +#define CTNT_IS_MSG 1 +#define CTNT_IS_ENV 2 +#define CTNT_IS_ENCAP 4 +#define CTNT_IS_BODYPART 8 +#define CTNT_IS_MULTIPART 16 +#define CTNT_IS_ATTACHMENT 32 +#define CTNT_IS_BASE64 64 +#define CTNT_IS_QP 128 +#define CTNT_IS_TEXT 256 +#define CTNT_IS_HTML 512 + +/* URL Flags */ +#define URL_IS_IP4 1 +#define URL_IS_IP6 2 +#define URL_IS_EXE 4 + +/* Anomaly Flags */ +#define ANOM_INVALID_BASE64 1 /* invalid base64 chars */ +#define ANOM_INVALID_QP 2 /* invalid qouted-printable chars */ +#define ANOM_LONG_HEADER_NAME 4 /* header is abnormally long */ +#define ANOM_LONG_HEADER_VALUE 8 /* header value is abnormally long + * (includes multi-line) */ +#define ANOM_LONG_LINE 16 /* Lines that exceed 998 octets */ +#define ANOM_LONG_ENC_LINE 32 /* Lines that exceed 76 octets */ +#define ANOM_MALFORMED_MSG 64 /* Misc msg format errors found */ + +/* Pubicly exposed size constants */ +#define DATA_CHUNK_SIZE 3072 /* Should be divisible by 3 */ +#define LINEREM_SIZE 256 + +/* Mime Parser Constants */ +#define HEADER_READY 0x01 +#define HEADER_STARTED 0x02 +#define HEADER_DONE 0x03 +#define BODY_STARTED 0x04 +#define BODY_DONE 0x05 +#define BODY_END_BOUND 0x06 +#define PARSE_DONE 0x07 +#define PARSE_ERROR 0x08 + +/** + * \brief Mime Decoder Error Codes + */ +typedef enum MimeDecRetCode { + MIME_DEC_OK = 0, + MIME_DEC_MORE = 1, + MIME_DEC_ERR_DATA = -1, + MIME_DEC_ERR_MEM = -2, + MIME_DEC_ERR_PARSE = -3 +} MimeDecRetCode; + +/** + * \brief Structure for containing configuration options + * + */ +typedef struct MimeDecConfig { + int decode_base64; /**< Decode base64 bodies */ + int decode_quoted_printable; /**< Decode quoted-printable bodies */ + int extract_urls; /**< Extract and store URLs in data structure */ + uint32_t header_value_depth; /**< Depth of which to store header values + (Default is 2000) */ +} MimeDecConfig; + +/** + * \brief This represents a header field name and associated value + */ +typedef struct MimeDecField { + char *name; /**< Name of the header field */ + uint32_t name_len; /**< Length of the name */ + char *value; /**< Value of the header field */ + uint32_t value_len; /**< Length of the value */ + struct MimeDecField *next; /**< Pointer to next field */ +} MimeDecField; + +/** + * \brief This represents a URL value node in a linked list + * + * Since HTML can sometimes contain a high number of URLs, this + * structure only features the URL host name/IP or those that are + * pointing to an executable file (see url_flags to determine which). + */ +typedef struct MimeDecUrl { + char *url; /**< String representation of full or partial URL */ + uint32_t url_len; /**< Length of the URL string */ + uint32_t url_flags; /**< Flags indicating type of URL */ + uint32_t url_cnt; /**< Count of URLs with same value */ + struct MimeDecUrl *next; /**< Pointer to next URL */ +} MimeDecUrl; + +/** + * \brief This represents the MIME Entity (or also top level message) in a + * child-sibling tree + */ +typedef struct MimeDecEntity { + MimeDecField *field_list; /**< Pointer to list of header fields */ + MimeDecUrl *url_list; /**< Pointer to list of URLs */ + uint32_t body_len; /**< Length of body (prior to any decoding) */ + uint32_t decoded_body_len; /**< Length of body after decoding */ + uint32_t header_flags; /**< Flags indicating header characteristics */ + uint32_t ctnt_flags; /**< Flags indicating type of content */ + uint32_t anomaly_flags; /**< Flags indicating an anomaly in the message */ + char *filename; /**< Name of file attachment */ + uint32_t filename_len; /**< Length of file attachment name */ + char *ctnt_type; /**< Quick access pointer to short-hand content type field */ + uint32_t ctnt_type_len; /**< Length of content type field value */ + char *msg_id; /**< Quick access pointer to message Id */ + uint32_t msg_id_len; /**< Quick access pointer to message Id */ + struct MimeDecEntity *next; /**< Pointer to list of sibling entities */ + struct MimeDecEntity *child; /**< Pointer to list of child entities */ +} MimeDecEntity; + +/** + * \brief Structure contains boundary and entity for the current node (entity) + * in the stack + * + */ +typedef struct MimeDecStackNode { + MimeDecEntity *data; /**< Pointer to the entity data structure */ + char *bdef; /**< Copy of boundary definition for child entity */ + uint32_t bdef_len; /**< Boundary length for child entity */ + int is_encap; /**< Flag indicating entity is encapsulated in message */ + struct MimeDecStackNode *next; /**< Pointer to next item on the stack */ +} MimeDecStackNode; + +/** + * \brief Structure holds the top of the stack along with some free reusable nodes + * + */ +typedef struct MimeDecStack { + MimeDecStackNode *top; /**< Pointer to the top of the stack */ + MimeDecStackNode *free_nodes; /**< Pointer to the list of free nodes */ + uint32_t free_nodes_cnt; /**< Count of free nodes in the list */ +} MimeDecStack; + +/** + * \brief Structure contains a list of value and lengths for robust data processing + * + */ +typedef struct DataValue { + char *value; /**< Copy of data value */ + uint32_t value_len; /**< Length of data value */ + struct DataValue *next; /**< Pointer to next value in the list */ +} DataValue; + +/** + * \brief Structure contains the current state of the MIME parser + * + */ +typedef struct MimeDecParseState { + MimeDecEntity *msg; /**< Pointer to the top-level message entity */ + MimeDecStack *stack; /**< Pointer to the top of the entity stack */ + char *hname; /**< Copy of the last known header name */ + uint32_t hlen; /**< Length of the last known header name */ + DataValue *hvalue; /**< Pointer to the incomplete header value list */ + uint32_t hvlen; /**< Total length of value list */ + char linerem[LINEREM_SIZE]; /**< Remainder from previous line (for URL extraction) */ + uint16_t linerem_len; /**< Length of remainder from previous line */ + char bvremain[B64_BLOCK]; /**< Remainder from base64-decoded line */ + uint8_t bvr_len; /**< Length of remainder from base64-decoded line */ + uint8_t data_chunk[DATA_CHUNK_SIZE]; /**< Buffer holding data chunk */ + uint32_t data_chunk_len; /**< Length of data chunk */ + int found_child; /**< Flag indicating a child entity was found */ + int body_begin; /**< Currently at beginning of body */ + int body_end; /**< Currently at end of body */ + uint8_t state_flag; /**< Flag representing current state of parser */ + void *data; /**< Pointer to data specific to the caller */ + int (*dataChunkProcessor) (const uint8_t *chunk, uint32_t len, + struct MimeDecParseState *state); /**< Data chunk processing function callback */ +} MimeDecParseState; + +/* Config functions */ +void MimeDecSetConfig(MimeDecConfig *config); +MimeDecConfig * MimeDecGetConfig(void); + +/* Memory functions */ +void MimeDecFreeEntity(MimeDecEntity *entity); +void MimeDecFreeField(MimeDecField *field); +void MimeDecFreeUrl(MimeDecUrl *url); + +/* List functions */ +MimeDecField * MimeDecAddField(MimeDecEntity *entity); +MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name); +MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity); +MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent); + +/* Helper functions */ +MimeDecField * MimeDecFillField(MimeDecEntity *entity, const char *name, + uint32_t nlen, const char *value, uint32_t vlen, int copy_name_value); + +/* Parser functions */ +MimeDecParseState * MimeDecInitParser(void *data, int (*dcpfunc)(const uint8_t *chunk, + uint32_t len, MimeDecParseState *state)); +void MimeDecDeInitParser(MimeDecParseState *state); +int MimeDecParseComplete(MimeDecParseState *state); +int MimeDecParseLine(const char *line, const uint32_t len, MimeDecParseState *state); +MimeDecEntity * MimeDecParseFullMsg(const char *buf, uint32_t blen, void *data, + int (*dcpfunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); + +/* Test functions */ +void MimeDecRegisterTests(void); + +#endif diff --git a/src/suricata.c b/src/suricata.c index 5d756eb6d4c6..13cdd8ea1fe7 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -151,6 +151,8 @@ #include "util-coredump-config.h" +#include "mime-decode.h" + #include "defrag.h" #include "runmodes.h" diff --git a/src/util-base64.c b/src/util-base64.c new file mode 100644 index 000000000000..40194d3270ed --- /dev/null +++ b/src/util-base64.c @@ -0,0 +1,146 @@ +/* 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 David Abarbanel + * + */ + +#include "util-base64.h" + +/* Constants */ +#define BASE64_TABLE_MAX 122 + +/* Base64 character to index conversion table */ +/* Characters are mapped as "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" */ +static const int b64table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, + -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51 }; + +/** + * \brief Gets a base64-decoded value from an encoded character + * + * \param c The encoded character + * + * \return The decoded value (0 or above), or -1 if the parameter is invalid + */ +static inline int GetBase64Value(char c) { + + int val = -1; + + /* Pull from conversion table */ + if (c <= BASE64_TABLE_MAX) { + val = b64table[(int) c]; + } + + return val; +} + +/** + * \brief Decodes a 4-byte base64-encoded block into a 3-byte ascii-encoded block + * + * \param ascii the 3-byte ascii output block + * \param b64 the 4-byte base64 input block + * + * \return none + */ +static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK]) { + + ascii[0] = (uint8_t) (b64[0] << 2) | (b64[1] >> 4); + ascii[1] = (uint8_t) (b64[1] << 4) | (b64[2] >> 2); + ascii[2] = (uint8_t) (b64[2] << 6) | (b64[3]); +} + +/** + * \brief Decodes a base64-encoded string buffer into an ascii-encoded byte buffer + * + * \param dest The destination byte buffer + * \param src The source string + * \param len The length of the source string + * + * \return Number of bytes decoded, or 0 if no data is decoded or it fails + */ +uint32_t DecodeBase64(uint8_t *dest, const char *src, uint32_t len) { + + int val; + uint32_t padding = 0, numDecoded = 0, bbidx = 0, valid = 1, i; + uint8_t *dptr = dest; + uint8_t b64[B64_BLOCK]; + + /* Traverse through each alpha-numeric letter in the source array */ + for(i = 0; i < len && src[i] != 0; i++) { + + /* Get decimal representation */ + val = GetBase64Value(src[i]); + if (val < 0) { + + /* Invalid character found, so decoding fails */ + if (src[i] != '=') { + valid = 0; + numDecoded = 0; + break; + } + padding++; + } + + /* For each alpha-numeric letter in the source array, find the numeric + * value */ + b64[bbidx++] = (val > 0 ? val : 0); + + /* Decode every 4 base64 bytes into 3 ascii bytes */ + if (bbidx == B64_BLOCK) { + + /* For every 4 bytes, add 3 bytes but deduct the '=' padded blocks */ + numDecoded += ASCII_BLOCK - (padding < B64_BLOCK ? + padding : ASCII_BLOCK); + + /* Decode base-64 block into ascii block and move pointer */ + DecodeBase64Block(dptr, b64); + dptr += ASCII_BLOCK; + + /* Reset base-64 block and index */ + bbidx = 0; + padding = 0; + } + } + + /* Finish remaining b64 bytes by padding */ + if (valid && bbidx > 0) { + + /* Decode remaining */ + numDecoded += ASCII_BLOCK - (B64_BLOCK - bbidx); + DecodeBase64Block(dptr, b64); + } + + if (numDecoded == 0) { + SCLogDebug("base64 decoding failed"); + } + + return numDecoded; +} diff --git a/src/util-base64.h b/src/util-base64.h new file mode 100644 index 000000000000..5e7c39c8a438 --- /dev/null +++ b/src/util-base64.h @@ -0,0 +1,54 @@ +/* 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 David Abarbanel + * + */ + +#ifndef __UTIL_BASE64_H_ +#define __UTIL_BASE64_H_ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-spm-bm.h" + +/* Constants */ +#define ASCII_BLOCK 3 +#define B64_BLOCK 4 + +/* Function prototypes */ +uint32_t DecodeBase64(uint8_t *dest, const char *src, uint32_t len); + +#endif diff --git a/suricata.yaml.in b/suricata.yaml.in index 715c53e4cc49..f1da99ba0708 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1294,6 +1294,23 @@ app-layer: # double-decode-path: no # double-decode-query: no +# Configure SMTP-MIME Decoder enhancements +smtp-mime: + + # Decode MIME messages from SMTP transactions (may be resource intensive) + # This field supercedes all others because it turns the entire process on or off + decode-mime: no + + # Decode MIME entity bodies (ie. base64, quoted-printable, etc.) + decode-base64: yes + decode-quoted-printable: yes + + # Maximum bytes per header data value stored in the data structure (default is 2000) + header-value-depth: 2000 + + # Extract URLs and save in state data structure + extract-urls: yes + # Profiling settings. Only effective if Suricata has been built with the # the --enable-profiling configure flag. # From 7850d896a8a3b285aa2575a312a98337f177e620 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Tue, 28 Jan 2014 15:33:26 -0800 Subject: [PATCH 0016/2553] smtp-mime: add server reply codes returned from outlook server --- src/app-layer-smtp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 0d5ef040e8e7..606f795d980d 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -147,10 +147,12 @@ enum { SMTP_REPLY_214, SMTP_REPLY_220, SMTP_REPLY_221, + SMTP_REPLY_235, SMTP_REPLY_250, SMTP_REPLY_251, SMTP_REPLY_252, + SMTP_REPLY_334, SMTP_REPLY_354, SMTP_REPLY_421, @@ -177,10 +179,12 @@ SCEnumCharMap smtp_reply_map[ ] = { { "214", SMTP_REPLY_214 }, { "220", SMTP_REPLY_220 }, { "221", SMTP_REPLY_221 }, + { "235", SMTP_REPLY_235 }, { "250", SMTP_REPLY_250 }, { "251", SMTP_REPLY_251 }, { "252", SMTP_REPLY_252 }, + { "334", SMTP_REPLY_334 }, { "354", SMTP_REPLY_354 }, { "421", SMTP_REPLY_421 }, From 31f8f5cf20e12b780ddf2b7705e1206e71ecf0e2 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Wed, 2 Apr 2014 12:48:01 -0700 Subject: [PATCH 0017/2553] eve-log: SMTP JSON logger --- src/Makefile.am | 2 + src/log-filestore.c | 2 +- src/mime-decode.c | 6 + src/mime-decode.h | 1 + src/output-json-email-common.c | 254 +++++++++++++++++++++++++++++++++ src/output-json-email-common.h | 40 ++++++ src/output-json-file.c | 15 +- src/output-json-smtp.c | 237 ++++++++++++++++++++++++++++++ src/output-json-smtp.h | 29 ++++ src/suricata.c | 3 + src/tm-modules.c | 1 + src/tm-threads-common.h | 1 + 12 files changed, 585 insertions(+), 6 deletions(-) create mode 100644 src/output-json-email-common.c create mode 100644 src/output-json-email-common.h create mode 100644 src/output-json-smtp.c create mode 100644 src/output-json-smtp.h diff --git a/src/Makefile.am b/src/Makefile.am index 6d6be901fae6..48d894803850 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -222,10 +222,12 @@ output-flow.c output-flow.h \ output-json-alert.c output-json-alert.h \ output-json-dns.c output-json-dns.h \ output-json-drop.c output-json-drop.h \ +output-json-email-common.c output-json-email-common.h \ output-json-file.c output-json-file.h \ output-json-flow.c output-json-flow.h \ output-json-netflow.c output-json-netflow.h \ output-json-http.c output-json-http.h \ +output-json-smtp.c output-json-smtp.h \ output-json-ssh.c output-json-ssh.h \ output-json-tls.c output-json-tls.h \ output-lua.c output-lua.h \ diff --git a/src/log-filestore.c b/src/log-filestore.c index 771cc8105dbd..f962b3a398dc 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -141,7 +141,7 @@ static void LogFilestoreMetaGetUserAgent(FILE *fp, const Packet *p, const File * fprintf(fp, ""); } -static void LogFilestoreMetaGetSmtp(FILE *fp, Packet *p, File *ff) { +static void LogFilestoreMetaGetSmtp(FILE *fp, const Packet *p, const File *ff) { SMTPState *state = (SMTPState *) p->flow->alstate; if (state != NULL && state->msg_tail != NULL) { diff --git a/src/mime-decode.c b/src/mime-decode.c index fdca4f07bc0f..3068511b5985 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -79,6 +79,7 @@ /* Globally hold configuration data */ static MimeDecConfig mime_dec_config = { 1, 1, 1, MAX_HEADER_VALUE }; +#ifdef DEBUG /* Mime Parser String translation */ static const char *StateFlags[] = { "NONE", "HEADER_READY", @@ -90,6 +91,7 @@ static const char *StateFlags[] = { "NONE", "PARSE_DONE", "PARSE_ERROR", NULL }; +#endif /* URL executable file extensions */ static const char *UrlExeExts[] = { ".exe", @@ -1019,10 +1021,14 @@ static int FindUrlStrings(const char *line, uint32_t len, } else { /* Not an EXE URL */ /* Cut off length at first '/' */ + /* If seems that BAESystems had done the following + in support of PEScan. We don't want it for logging. + Therefore its been removed. tok = FindString(tempUrl, tempUrlLen, "/"); if (tok != NULL) { tempUrlLen = tok - tempUrl; } + */ } /* Make sure remaining URL exists */ diff --git a/src/mime-decode.h b/src/mime-decode.h index 381907c66eca..e5188b74da97 100644 --- a/src/mime-decode.h +++ b/src/mime-decode.h @@ -34,6 +34,7 @@ #include "util-debug.h" /* Header Flags */ +#define HDR_IS_LOGGED 1 /* Content Flags */ #define CTNT_IS_MSG 1 diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c new file mode 100644 index 000000000000..15a8b3143684 --- /dev/null +++ b/src/output-json-email-common.c @@ -0,0 +1,254 @@ +/* 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 Tom DeCanio + * + * Implements json common email logging portion of the engine. + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "tm-threads-common.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" +#include "app-layer-parser.h" +#include "output.h" +#include "app-layer-smtp.h" +#include "app-layer.h" +#include "util-privs.h" +#include "util-buffer.h" +#include "util-byte.h" + +#include "util-logopenfile.h" +#include "util-crypt.h" + +#include "output-json.h" +#include "output-json-email-common.h" + +#ifdef HAVE_LIBJANSSON +#include + +/* JSON format logging */ +static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, + json_t *js, + const Packet *p) +{ + SMTPState *smtp_state; + MimeDecParseState *mime_state; + MimeDecEntity *entity; + char *protos = NULL; + + /* no flow, no smtp state */ + if (p->flow == NULL) { + SCReturnInt(TM_ECODE_FAILED); + } + + json_t *sjs = json_object(); + if (sjs == NULL) { + SCReturnInt(TM_ECODE_FAILED); + } + + /* check if we have SMTP state or not */ + FLOWLOCK_WRLOCK(p->flow); /* WRITE lock before we updated flow logged id */ + AppProto proto = FlowGetAppProtocol(p->flow); + switch (proto) { + case ALPROTO_SMTP: + smtp_state = (SMTPState *)FlowGetAppState(p->flow); + if (smtp_state == NULL) { + SCLogDebug("no smtp state, so no request logging"); + FLOWLOCK_UNLOCK(p->flow); + SCReturnInt(TM_ECODE_FAILED); + } + mime_state = smtp_state->mime_state; + entity = smtp_state->msg_tail; + protos = "smtp"; + break; + default: + /* don't know how we got here */ + FLOWLOCK_UNLOCK(p->flow); + SCReturnInt(TM_ECODE_FAILED); + } + if ((mime_state != NULL) && + (mime_state->state_flag == PARSE_DONE)) { + + if (entity == NULL) { + FLOWLOCK_UNLOCK(p->flow); + SCReturnInt(TM_ECODE_FAILED); + } + + if ((entity->header_flags & HDR_IS_LOGGED) == 0) { + MimeDecField *field; + //printf("email LOG\n"); + + /* From: */ + field = MimeDecFindField(entity, "From"); + if (field != NULL) { + char *s = BytesToString((uint8_t *)field->value, + (size_t)field->value_len); + if (likely(s != NULL)) { + //printf("From: \"%s\"\n", s); + json_object_set_new(sjs, "from", json_string(s)); + SCFree(s); + } + } + + /* To: */ + char *to_line = NULL; + field = MimeDecFindField(entity, "To"); + if (field != NULL) { + json_t *js_to = json_array(); + if (likely(js_to != NULL)) { + char *savep; + char *p; + to_line = BytesToString((uint8_t *)field->value, + (size_t)field->value_len); + //printf("to_line:: TO: \"%s\" (%d)\n", to_line, strlen(to_line)); + p = strtok_r(to_line, ",", &savep); + //printf("got another addr: \"%s\"\n", p); + json_array_append_new(js_to, json_string(p)); + while ((p = strtok_r(NULL, ",", &savep)) != NULL) { + //printf("got another addr: \"%s\"\n", p); + json_array_append_new(js_to, json_string(&p[strspn(p, " ")])); + } + json_object_set_new(sjs, "to", js_to); + } + } + + /* Cc: */ + char *cc_line = NULL; + field = MimeDecFindField(entity, "Cc"); + if (field != NULL) { + json_t *js_cc = json_array(); + if (likely(js_cc != NULL)) { + char *savep; + char *p; + cc_line = BytesToString((uint8_t *)field->value, + (size_t)field->value_len); + //printf("cc_line:: CC: \"%s\" (%d)\n", to_line, strlen(to_line)); + p = strtok_r(cc_line, ",", &savep); + //printf("got another addr: \"%s\"\n", p); + json_array_append_new(js_cc, json_string(p)); + while ((p = strtok_r(NULL, ",", &savep)) != NULL) { + //printf("got another addr: \"%s\"\n", p); + json_array_append_new(js_cc, json_string(&p[strspn(p, " ")])); + } + json_object_set_new(sjs, "cc", js_cc); + } + } + + /* Subject: */ + field = MimeDecFindField(entity, "Subject"); + if (field != NULL) { + char *s = strndup(field->value, (int) field->value_len); + if (likely(s != NULL)) { + //printf("Subject: \"%s\"\n", s); + json_object_set_new(sjs, "subject", json_string(s)); + SCFree(s); + } + } + + entity->header_flags |= HDR_IS_LOGGED; + + entity = (MimeDecEntity *)mime_state->stack->top->data; + int attch_cnt = 0; + int url_cnt = 0; + json_t *js_attch = json_array(); + json_t *js_url = json_array(); + for (entity = entity->child; entity != NULL; entity = entity->next) { + if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { + + char *s = BytesToString((uint8_t *)entity->filename, + (size_t)entity->filename_len); + //printf("found attachment \"%s\"\n", s); + json_array_append_new(js_attch, + json_string(s)); + SCFree(s); + attch_cnt += 1; + } + if (entity->url_list != NULL) { + MimeDecUrl *url; + for (url = entity->url_list; url != NULL; url = url->next) { + char *s = BytesToString((uint8_t *)url->url, + (size_t)url->url_len); + if (s != NULL) { + //printf("URL: \"%s\"\n", s); + json_array_append_new(js_url, + json_string(s)); + SCFree(s); + url_cnt += 1; + } + } + } + } + if (attch_cnt > 0) { + json_object_set_new(sjs, "attachment", js_attch); + } else { + json_decref(js_attch); + } + if (url_cnt > 0) { + json_object_set_new(sjs, "url", js_url); + } else { + json_decref(js_url); + } + json_object_set_new(js, protos, sjs); + + FLOWLOCK_UNLOCK(p->flow); + SCReturnInt(TM_ECODE_OK); + } + } + + FLOWLOCK_UNLOCK(p->flow); + SCReturnInt(TM_ECODE_DONE); +} + +int JsonEmailLogger(ThreadVars *tv, void *thread_data, const Packet *p) { + SCEnter(); + JsonEmailLogThread *jhl = (JsonEmailLogThread *)thread_data; + MemBuffer *buffer = (MemBuffer *)jhl->buffer; + + json_t *js = CreateJSONHeader((Packet *)p, 1, "smtp"); + if (unlikely(js == NULL)) + return TM_ECODE_OK; + + /* reset */ + MemBufferReset(buffer); + + if (JsonEmailLogJson(jhl, js, p) == TM_ECODE_OK) { + OutputJSONBuffer(js, jhl->emaillog_ctx->file_ctx, buffer); + } + json_object_del(js, "smtp"); + + json_object_clear(js); + json_decref(js); + + SCReturnInt(TM_ECODE_OK); +} + +#endif diff --git a/src/output-json-email-common.h b/src/output-json-email-common.h new file mode 100644 index 000000000000..b073d932b530 --- /dev/null +++ b/src/output-json-email-common.h @@ -0,0 +1,40 @@ +/* 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 Tom DeCanio + */ + +#ifndef __OUTPUT_JSON_EMAIL_COMMON_H__ +#define __OUTPUT_JSON_EMAIL_COMMON_H__ + +typedef struct OutputJsonEmailCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; /** Store mode */ +} OutputJsonEmailCtx; + + +typedef struct JsonEmailLogThread_ { + OutputJsonEmailCtx *emaillog_ctx; + MemBuffer *buffer; +} JsonEmailLogThread; + +int JsonEmailLogger(ThreadVars *tv, void *thread_data, const Packet *p); + +#endif /* __OUTPUT_JSON_EMAIL_COMMON_H__ */ diff --git a/src/output-json-file.c b/src/output-json-file.c index aacb60c6c16d..93250fb4f636 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -187,11 +187,16 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F return; } - json_object_set_new(hjs, "url", LogFileMetaGetUri(p, ff)); - json_object_set_new(hjs, "hostname", LogFileMetaGetHost(p, ff)); - json_object_set_new(hjs, "http_refer", LogFileMetaGetReferer(p, ff)); - json_object_set_new(hjs, "http_user_agent", LogFileMetaGetUserAgent(p, ff)); - json_object_set_new(js, "http", hjs); + switch (p->flow->alproto) { + case ALPROTO_HTTP: + json_object_set_new(hjs, "url", LogFileMetaGetUri(p, ff)); + json_object_set_new(hjs, "hostname", LogFileMetaGetHost(p, ff)); + json_object_set_new(hjs, "http_refer", LogFileMetaGetReferer(p, ff)); + json_object_set_new(hjs, "http_user_agent", LogFileMetaGetUserAgent(p, ff)); + json_object_set_new(js, "http", hjs); + break; + } + json_t *fjs = json_object(); if (unlikely(fjs == NULL)) { diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c new file mode 100644 index 000000000000..db6374ebf036 --- /dev/null +++ b/src/output-json-smtp.c @@ -0,0 +1,237 @@ +/* Copyright (C) 2007-2013 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 Tom DeCanio + * + * Implements SMTP JSON logging portion of the engine. + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "app-layer-smtp.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util-privs.h" +#include "util-buffer.h" +#include "util-proto-name.h" +#include "util-logopenfile.h" +#include "util-time.h" + +#include "output-json.h" +#include "output-json-email-common.h" + +#ifdef HAVE_LIBJANSSON +#include + +static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p) +{ + SCEnter(); + + SCReturnInt(JsonEmailLogger(tv, thread_data, p)); +} + +#define DEFAULT_LOG_FILENAME "smtp.json" +OutputCtx *OutputSmtpLogInit(ConfNode *conf) +{ + LogFileCtx *file_ctx = LogFileNewCtx(); + if(file_ctx == NULL) { + SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + LogFileFreeCtx(file_ctx); + return NULL; + } + + OutputJsonEmailCtx *email_ctx = SCMalloc(sizeof(OutputJsonEmailCtx)); + if (unlikely(email_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + return NULL; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + SCFree(email_ctx); + return NULL; + } + + email_ctx->file_ctx = file_ctx; + + output_ctx->data = email_ctx; + output_ctx->DeInit = NULL; + + /* enable the logger for the app layer */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); + + return output_ctx; +} + +static OutputCtx *OutputSmtpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AlertJsonThread *ajt = parent_ctx->data; + + OutputJsonEmailCtx *email_ctx = SCMalloc(sizeof(OutputJsonEmailCtx)); + if (unlikely(email_ctx == NULL)) + return NULL; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(email_ctx); + return NULL; + } + + email_ctx->file_ctx = ajt->file_ctx; + + output_ctx->data = email_ctx; + output_ctx->DeInit = NULL; + + /* enable the logger for the app layer */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); + + return output_ctx; +} + +#define OUTPUT_BUFFER_SIZE 65535 +static TmEcode JsonSmtpLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + JsonEmailLogThread *aft = SCMalloc(sizeof(JsonEmailLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(JsonEmailLogThread)); + + if(initdata == NULL) + { + SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + /* Use the Ouptut Context (file pointer and mutex) */ + aft->emaillog_ctx = ((OutputCtx *)initdata)->data; + + aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode JsonSmtpLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonEmailLogThread *aft = (JsonEmailLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + MemBufferFree(aft->buffer); + /* clear memory */ + memset(aft, 0, sizeof(JsonEmailLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +/** \internal + * \brief Condition function for SMTP logger + * \retval bool true or false -- log now? + */ +static int JsonSmtpCondition(ThreadVars *tv, const Packet *p) { + if (p->flow == NULL) { + return FALSE; + } + + if (!(PKT_IS_TCP(p))) { + return FALSE; + } + + FLOWLOCK_RDLOCK(p->flow); + uint16_t proto = FlowGetAppProtocol(p->flow); + if (proto != ALPROTO_SMTP) + goto dontlog; + + SMTPState *smtp_state = (SMTPState *)FlowGetAppState(p->flow); + if (smtp_state == NULL) { + SCLogDebug("no smtp state, so no request logging"); + goto dontlog; + } + + FLOWLOCK_UNLOCK(p->flow); + return TRUE; +dontlog: + FLOWLOCK_UNLOCK(p->flow); + return FALSE; +} + +void TmModuleJsonSmtpLogRegister (void) { + tmm_modules[TMM_JSONSMTPLOG].name = "JsonSmtpLog"; + tmm_modules[TMM_JSONSMTPLOG].ThreadInit = JsonSmtpLogThreadInit; + tmm_modules[TMM_JSONSMTPLOG].ThreadDeinit = JsonSmtpLogThreadDeinit; + tmm_modules[TMM_JSONSMTPLOG].RegisterTests = NULL; + tmm_modules[TMM_JSONSMTPLOG].cap_flags = 0; + tmm_modules[TMM_JSONSMTPLOG].flags = TM_FLAG_LOGAPI_TM; + + /* register as separate module */ + OutputRegisterPacketModule("JsonSmtpLog", "smtp-json-log", + OutputSmtpLogInit, + JsonSmtpLogger, + JsonSmtpCondition); + + /* also register as child of eve-log */ + OutputRegisterPacketSubModule("eve-log", "JsonSmtpLog", + "eve-log.smtp", + OutputSmtpLogInitSub, + JsonSmtpLogger, + JsonSmtpCondition); +} + +#else + +static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) +{ + SCLogInfo("Can't init JSON output - JSON support was disabled during build."); + return TM_ECODE_FAILED; +} + +void TmModuleJsonSmtpLogRegister (void) +{ + tmm_modules[TMM_JSONSMTPLOG].name = "JsonSmtpLog"; + tmm_modules[TMM_JSONSMTPLOG].ThreadInit = OutputJsonThreadInit; +} + +#endif diff --git a/src/output-json-smtp.h b/src/output-json-smtp.h new file mode 100644 index 000000000000..d38187c706b8 --- /dev/null +++ b/src/output-json-smtp.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2010 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 Tom DeCanio + */ + +#ifndef __OUTPUT_JSON_SMTP_H__ +#define __OUTPUT_JSON_SMTP_H__ + +void TmModuleJsonSmtpLogRegister (void); + +#endif /* __OUTPUT_JSON_SMTP_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 13cdd8ea1fe7..853904f3a3c6 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -93,6 +93,7 @@ #include "log-pcap.h" #include "log-file.h" #include "output-json-file.h" +#include "output-json-smtp.h" #include "log-filestore.h" #include "log-tcp-data.h" @@ -870,6 +871,8 @@ void RegisterAllModules() TmModuleJsonDropLogRegister(); /* json log */ TmModuleOutputJsonRegister(); + /* email logs */ + TmModuleJsonSmtpLogRegister(); /* http log */ TmModuleLogHttpLogRegister(); TmModuleJsonHttpLogRegister(); diff --git a/src/tm-modules.c b/src/tm-modules.c index 791938e6b10f..8503f02686f2 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -260,6 +260,7 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_JSONFILELOG); CASE_CODE (TMM_JSONFLOWLOG); CASE_CODE (TMM_JSONNETFLOWLOG); + CASE_CODE (TMM_JSONSMTPLOG); CASE_CODE (TMM_JSONSSHLOG); CASE_CODE (TMM_JSONTLSLOG); CASE_CODE (TMM_OUTPUTJSON); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 867190d745d3..0137e1027917 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -88,6 +88,7 @@ typedef enum { TMM_JSONDROPLOG, TMM_JSONHTTPLOG, TMM_JSONDNSLOG, + TMM_JSONSMTPLOG, TMM_JSONSSHLOG, TMM_JSONTLSLOG, TMM_JSONFILELOG, From 260872ccd9da6aead91a61c04d36168916b24357 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 28 Jul 2014 16:36:15 +0200 Subject: [PATCH 0018/2553] smtp layer: fix unittests Synchronize test 14 with the new application layer API and improve debug messages. --- src/app-layer-smtp.c | 118 +++++++++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 38 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 606f795d980d..2e0f2802eb42 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -4068,127 +4068,147 @@ int SMTPParserTest14(void) uint32_t reply5_len = sizeof(reply5); TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - void *thread_local_data = SMTPLocalStorageAlloc(); - /* EHLO Request */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + SCMutexLock(&f.m); + /* Welcome reply */ + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->input_len != 0 || - smtp_state->cmds_cnt != 1 || + smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != 0) { - printf("smtp parser in inconsistent state\n"); + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } - /* Welcome reply */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, + request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } + SCMutexLock(&f.m); /* EHLO Reply */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } + SCMutexLock(&f.m); /* MAIL FROM Request */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } + SCMutexLock(&f.m); /* MAIL FROM Reply */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } + SCMutexLock(&f.m); /* RCPT TO Request */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } + SCMutexLock(&f.m); /* RCPT TO Reply */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } @@ -4198,46 +4218,55 @@ int SMTPParserTest14(void) smtp_config.mime_config.decode_quoted_printable = 1; MimeDecSetConfig(&smtp_config.mime_config); + SCMutexLock(&f.m); /* DATA request */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_DATA || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } + SCMutexLock(&f.m); /* Data reply */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply4, reply4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } + SCMutexLock(&f.m); /* DATA message */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4_msg, request4_msg_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || @@ -4245,17 +4274,20 @@ int SMTPParserTest14(void) smtp_state->mime_state == NULL || smtp_state->msg_head == NULL || /* MIME data structures */ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } + SCMutexLock(&f.m); /* DATA . request */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4_end, request4_end_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || @@ -4263,7 +4295,7 @@ int SMTPParserTest14(void) smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || smtp_state->mime_state == NULL || smtp_state->msg_head == NULL || /* MIME data structures */ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } @@ -4306,57 +4338,67 @@ int SMTPParserTest14(void) } } + SCMutexLock(&f.m); /* DATA . reply */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply4_end, reply4_end_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } + SCMutexLock(&f.m); /* QUIT Request */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5, request5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } + SCMutexLock(&f.m); /* QUIT Reply */ - r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply5, reply5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); goto end; } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); + printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; } result = 1; - end: +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - SMTPLocalStorageFree(thread_local_data); return result; } From 6467a5d563dacc72ac5d01655affbe59209a641f Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Mon, 28 Jul 2014 18:25:13 -0700 Subject: [PATCH 0019/2553] app-layer-smtp: fix Test14. Was running one byte past end of buffer. Declare Unit Test 14's data as static. --- src/app-layer-smtp.c | 63 ++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 2e0f2802eb42..475a21e3e43a 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -3905,7 +3905,7 @@ int SMTPParserTest14(void) int r = 0; /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ - uint8_t welcome_reply[] = { + static uint8_t welcome_reply[] = { 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, @@ -3913,21 +3913,21 @@ int SMTPParserTest14(void) 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, 0x0d, 0x0a }; - uint32_t welcome_reply_len = sizeof(welcome_reply); + static uint32_t welcome_reply_len = sizeof(welcome_reply); /* EHLO boo.com */ - uint8_t request1[] = { + static uint8_t request1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; - uint32_t request1_len = sizeof(request1); + static uint32_t request1_len = sizeof(request1); /* 250-mx.google.com at your service, [117.198.115.50] * 250-SIZE 35882577 * 250-8BITMIME * 250-STARTTLS * 250 ENHANCEDSTATUSCODES */ - uint8_t reply1[] = { + static uint8_t reply1[] = { 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, @@ -3946,56 +3946,56 @@ int SMTPParserTest14(void) 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a }; - uint32_t reply1_len = sizeof(reply1); + static uint32_t reply1_len = sizeof(reply1); /* MAIL FROM:asdff@asdf.com */ - uint8_t request2[] = { + static uint8_t request2[] = { 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; - uint32_t request2_len = sizeof(request2); + static uint32_t request2_len = sizeof(request2); /* 250 2.1.0 Ok */ - uint8_t reply2[] = { + static uint8_t reply2[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a }; - uint32_t reply2_len = sizeof(reply2); + static uint32_t reply2_len = sizeof(reply2); /* RCPT TO:bimbs@gmail.com */ - uint8_t request3[] = { + static uint8_t request3[] = { 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; - uint32_t request3_len = sizeof(request3); + static uint32_t request3_len = sizeof(request3); /* 250 2.1.5 Ok */ - uint8_t reply3[] = { + static uint8_t reply3[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a }; - uint32_t reply3_len = sizeof(reply3); + static uint32_t reply3_len = sizeof(reply3); /* DATA */ - uint8_t request4[] = { + static uint8_t request4[] = { 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a }; - uint32_t request4_len = sizeof(request4); + static uint32_t request4_len = sizeof(request4); /* 354 End data with .|| */ - uint8_t reply4[] = { + static uint8_t reply4[] = { 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d, 0x0a }; - uint32_t reply4_len = sizeof(reply4); + static uint32_t reply4_len = sizeof(reply4); /* MIME_MSG */ - uint64_t filesize = 133; - uint8_t request4_msg[] = { + static uint64_t filesize = 133; + static uint8_t request4_msg[] = { 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, @@ -4038,34 +4038,34 @@ int SMTPParserTest14(void) 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C, 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F, 0x41, 0x3D, 0x3D, 0x0D,0x0A }; - uint32_t request4_msg_len = sizeof(request4_msg); + static uint32_t request4_msg_len = sizeof(request4_msg); /* DATA COMPLETED */ - uint8_t request4_end[] = { + static uint8_t request4_end[] = { 0x0d, 0x0a, 0x2e, 0x0d, 0x0a }; - uint32_t request4_end_len = sizeof(request4_end); + static uint32_t request4_end_len = sizeof(request4_end); /* 250 2.0.0 Ok: queued as 6A1AF20BF2 */ - uint8_t reply4_end[] = { + static uint8_t reply4_end[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42, 0x46, 0x32, 0x0d, 0x0a }; - uint32_t reply4_end_len = sizeof(reply4_end); + static uint32_t reply4_end_len = sizeof(reply4_end); /* QUIT */ - uint8_t request5[] = { + static uint8_t request5[] = { 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a }; - uint32_t request5_len = sizeof(request5); + static uint32_t request5_len = sizeof(request5); /* 221 2.0.0 Bye */ - uint8_t reply5[] = { + static uint8_t reply5[] = { 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a }; - uint32_t reply5_len = sizeof(reply5); + static uint32_t reply5_len = sizeof(reply5); TcpSession ssn; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -4312,7 +4312,8 @@ int SMTPParserTest14(void) printf("smtp-mime file size %lu is incorrect", file->size); goto end; } - uint8_t org_binary[] = {0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, + static uint8_t org_binary[] = { + 0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00, @@ -4330,7 +4331,7 @@ int SMTPParserTest14(void) 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36, 0x5C, 0x7A, 0x00, 0x00, 0x38,}; uint64_t z; - for (z=0; z <= filesize; z++){ + for (z=0; z < filesize; z++){ if(org_binary[z] != file->chunks_head->data[z]){ printf("smtp-mime file data incorrect\n"); goto end; From 471967aafd3efd5f03e8f2fd9d256ad9745575a1 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Fri, 1 Aug 2014 13:27:33 -0700 Subject: [PATCH 0020/2553] mime-decode: don't scan attachment's data for URLs. move event pointer lookup inside extract_urls and protect pointer walk. --- src/mime-decode.c | 131 +++++++++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 47 deletions(-) diff --git a/src/mime-decode.c b/src/mime-decode.c index 3068511b5985..0af3d74e5e5d 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -164,26 +164,58 @@ MimeDecConfig * MimeDecGetConfig(void) { } /** - * \brief Recursively frees a mime entity tree + * \brief Follow the 'next' pointers to the leaf + * + * \param node The root entity + * + * \return Pointer to leaf on 'next' side + * + */ +static MimeDecEntity *findLastSibling(MimeDecEntity *node) +{ + if (node == NULL) + return NULL; + while(node->next != NULL) + node = node->next; + return node; +} + +/** + * \brief Frees a mime entity tree * * \param entity The root entity * * \return none * */ -void MimeDecFreeEntity (MimeDecEntity *entity) { - - if (entity != NULL) { - - MimeDecFreeField(entity->field_list); - MimeDecFreeUrl(entity->url_list); - SCFree(entity->filename); - - /* Use recursion */ - MimeDecFreeEntity(entity->child); - MimeDecFreeEntity(entity->next); - - SCFree(entity); +void MimeDecFreeEntity (MimeDecEntity *entity) +{ + if (entity == NULL) + return; + MimeDecEntity *lastSibling = findLastSibling(entity); + while (entity != NULL) + { + /** + * Move child to next + * Transform tree into list + */ + if (entity->child != NULL) + { + lastSibling->next = entity->child; + lastSibling = findLastSibling(lastSibling); + } + + /** + * Move to next element + */ + MimeDecEntity *old = entity; + entity = entity->next; + + MimeDecFreeField(old->field_list); + MimeDecFreeUrl(old->url_list); + SCFree(old->filename); + + SCFree(old); } } @@ -1085,47 +1117,52 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; - MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; char *remainPtr, *tok; uint32_t tokLen; MimeDecConfig *mdcfg = MimeDecGetConfig(); if (mdcfg != NULL && mdcfg->extract_urls) { - /* If plain text or html, then look for URLs */ - if ((entity->ctnt_flags & CTNT_IS_TEXT) || - (entity->ctnt_flags & CTNT_IS_HTML)) { - - /* Remainder from previous line */ - if (state->linerem_len > 0) { - // TODO - } else { - /* No remainder from previous line */ - /* Parse each line one by one */ - remainPtr = (char *) chunk; - do { - tok = GetLine(remainPtr, len - (remainPtr - (char *) chunk), - &remainPtr, &tokLen); - if (tok != remainPtr) { - // DEBUG - ADDED - /* If last token found without CR/LF delimiter, then save - * and reconstruct with next chunk - */ - if (tok + tokLen - (char *) chunk == len) { - PrintChars(SC_LOG_DEBUG, "LAST CHUNK LINE - CUTOFF", - tok, tokLen); - SCLogDebug("\nCHUNK CUTOFF CHARS: %d delim %ld\n", tokLen, len - (tok + tokLen - (char *) chunk)); - } else { - /* Search line for URL */ - ret = FindUrlStrings(tok, tokLen, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: FindUrlStrings() function" - " failed: %d", ret); - break; + if ((state->stack != NULL) && (state->stack->top != NULL)) { + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + /* If plain text or html, then look for URLs */ + if (((entity->ctnt_flags & CTNT_IS_TEXT) || + (entity->ctnt_flags & CTNT_IS_HTML)) && + ((entity->ctnt_flags & CTNT_IS_ATTACHMENT) == 0)) { + + /* Remainder from previous line */ + if (state->linerem_len > 0) { + // TODO + } else { + /* No remainder from previous line */ + /* Parse each line one by one */ + remainPtr = (char *) chunk; + do { + tok = GetLine(remainPtr, len - (remainPtr - (char *) chunk), + &remainPtr, &tokLen); + if (tok != remainPtr) { + // DEBUG - ADDED + /* If last token found without CR/LF delimiter, then save + * and reconstruct with next chunk + */ + if (tok + tokLen - (char *) chunk == len) { + PrintChars(SC_LOG_DEBUG, "LAST CHUNK LINE - CUTOFF", + tok, tokLen); + SCLogDebug("\nCHUNK CUTOFF CHARS: %d delim %ld\n", tokLen, len - (tok + tokLen - (char *) chunk)); + } else { + /* Search line for URL */ + ret = FindUrlStrings(tok, tokLen, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: FindUrlStrings() function" + " failed: %d", ret); + break; + } } } - } - } while (tok != remainPtr && remainPtr - (char *) chunk < len); + } while (tok != remainPtr && remainPtr - (char *) chunk < len); + } } + } else { + SCLogDebug("Error: Stack pointer missing"); } } From 746da75615b7d60871b82b86b10a97d54e8eef78 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Thu, 14 Aug 2014 12:07:53 -0700 Subject: [PATCH 0021/2553] eve-log: catch and log URLs in basic text emails without mime encapsulation. expand pointer walk protection. --- src/mime-decode.c | 28 +++++++++++++++------------- src/output-json-email-common.c | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/mime-decode.c b/src/mime-decode.c index 0af3d74e5e5d..6332ff1450f4 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -1090,7 +1090,6 @@ static int FindUrlStrings(const char *line, uint32_t len, } else { SCFree(tempUrl); } - /* Increment counter */ url->url_cnt++; } else { @@ -1120,12 +1119,14 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, char *remainPtr, *tok; uint32_t tokLen; - MimeDecConfig *mdcfg = MimeDecGetConfig(); - if (mdcfg != NULL && mdcfg->extract_urls) { - if ((state->stack != NULL) && (state->stack->top != NULL)) { + if ((state->stack != NULL) && (state->stack->top != NULL) && + (state->stack->top->data != NULL)) { + MimeDecConfig *mdcfg = MimeDecGetConfig(); + if (mdcfg != NULL && mdcfg->extract_urls) { MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; /* If plain text or html, then look for URLs */ if (((entity->ctnt_flags & CTNT_IS_TEXT) || + (entity->ctnt_flags & CTNT_IS_MSG) || (entity->ctnt_flags & CTNT_IS_HTML)) && ((entity->ctnt_flags & CTNT_IS_ATTACHMENT) == 0)) { @@ -1161,18 +1162,19 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, } while (tok != remainPtr && remainPtr - (char *) chunk < len); } } - } else { - SCLogDebug("Error: Stack pointer missing"); } - } - /* Now invoke callback */ - if (state->dataChunkProcessor != NULL) { - ret = state->dataChunkProcessor(chunk, len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: state->dataChunkProcessor() callback function" - " failed"); + /* Now invoke callback */ + if (state->dataChunkProcessor != NULL) { + ret = state->dataChunkProcessor(chunk, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: state->dataChunkProcessor() callback function" + " failed"); + } } + } else { + SCLogDebug("Error: Stack pointer missing"); + ret = MIME_DEC_ERR_DATA; } /* Reset data chunk buffer */ diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 15a8b3143684..129eb5df5a39 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -166,7 +166,7 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, /* Subject: */ field = MimeDecFindField(entity, "Subject"); if (field != NULL) { - char *s = strndup(field->value, (int) field->value_len); + char *s = BytesToString((uint8_t *)field->value, (size_t) field->value_len); if (likely(s != NULL)) { //printf("Subject: \"%s\"\n", s); json_object_set_new(sjs, "subject", json_string(s)); @@ -181,6 +181,20 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, int url_cnt = 0; json_t *js_attch = json_array(); json_t *js_url = json_array(); + if (entity->url_list != NULL) { + MimeDecUrl *url; + for (url = entity->url_list; url != NULL; url = url->next) { + char *s = BytesToString((uint8_t *)url->url, + (size_t)url->url_len); + if (s != NULL) { + //printf("URL: \"%s\"\n", s); + json_array_append_new(js_url, + json_string(s)); + SCFree(s); + url_cnt += 1; + } + } + } for (entity = entity->child; entity != NULL; entity = entity->next) { if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { From f1c160ed223b58e1f9124e410acc6262b25166b2 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Thu, 21 Aug 2014 12:34:06 -0700 Subject: [PATCH 0022/2553] smtp: turn on smtp mime decoding and enable smtp eve logging. --- suricata.yaml.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index f1da99ba0708..12230ff14dd7 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -110,6 +110,7 @@ outputs: force-magic: no # force logging magic on all logged files force-md5: no # force logging of md5 checksums #- drop + - smtp - ssh # bi-directional flows #- flow @@ -1299,7 +1300,7 @@ smtp-mime: # Decode MIME messages from SMTP transactions (may be resource intensive) # This field supercedes all others because it turns the entire process on or off - decode-mime: no + decode-mime: yes # Decode MIME entity bodies (ie. base64, quoted-printable, etc.) decode-base64: yes From 3e10ee4608060bef42fa224491d8fe5a132285b1 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Tue, 7 Oct 2014 15:23:15 -0700 Subject: [PATCH 0023/2553] PR review comment. Use protocol to discern log type. --- src/log-filestore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/log-filestore.c b/src/log-filestore.c index f962b3a398dc..109dabbbd149 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -205,7 +205,7 @@ static void LogFilestoreLogCreateMetaFile(const Packet *p, const File *ff, char } /* Only applicable to HTTP traffic */ - if (ff->txid != 0) { + if (p->flow->alproto == ALPROTO_HTTP) { fprintf(fp, "HTTP URI: "); LogFilestoreMetaGetUri(fp, p, ff); fprintf(fp, "\n"); From e5c36952d65d27b39359c970d0b9f0c6ef69de3b Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Tue, 7 Oct 2014 15:44:06 -0700 Subject: [PATCH 0024/2553] app-layer-smtp: move old smtp-mime section in suricata.yaml into app-layer-protocols.smtp.mine section and update code to accomodate. --- src/app-layer-smtp.c | 6 +++--- suricata.yaml.in | 36 +++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 475a21e3e43a..e0fd88d8cfff 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -218,7 +218,7 @@ typedef struct SMTPConfig { static SMTPConfig smtp_config = { 0, { 0, 0, 0, 0 } }; /** - * \brief Configure SMTP Mime Decoder by parsing out 'smtp-mime' section of YAML + * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML * config file * * \return none @@ -229,7 +229,7 @@ static void SMTPConfigure(void) { int ret = 0, val; intmax_t imval; - ConfNode *config = ConfGetNode("smtp-mime"); + ConfNode *config = ConfGetNode("app-layer.protocols.smtp.mime"); if (config != NULL) { ret = ConfGetChildValueBool(config, "decode-mime", &val); @@ -1171,7 +1171,7 @@ static int SMTPRegisterPatternsForProtocolDetection(void) } /** - * \brief Register the SMPT Protocol parser. + * \brief Register the SMTP Protocol parser. */ void RegisterSMTPParsers(void) { diff --git a/suricata.yaml.in b/suricata.yaml.in index 12230ff14dd7..29dacf4db0a0 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1159,6 +1159,25 @@ app-layer: enabled: yes smtp: enabled: yes + # Configure SMTP-MIME Decoder + mime: + # Decode MIME messages from SMTP transactions + # (may be resource intensive) + # This field supercedes all others because it turns the entire + # process on or off + decode-mime: yes + + # Decode MIME entity bodies (ie. base64, quoted-printable, etc.) + decode-base64: yes + decode-quoted-printable: yes + + # Maximum bytes per header data value stored in the data structure + # (default is 2000) + header-value-depth: 2000 + + # Extract URLs and save in state data structure + extract-urls: yes + imap: enabled: detection-only msn: @@ -1295,23 +1314,6 @@ app-layer: # double-decode-path: no # double-decode-query: no -# Configure SMTP-MIME Decoder enhancements -smtp-mime: - - # Decode MIME messages from SMTP transactions (may be resource intensive) - # This field supercedes all others because it turns the entire process on or off - decode-mime: yes - - # Decode MIME entity bodies (ie. base64, quoted-printable, etc.) - decode-base64: yes - decode-quoted-printable: yes - - # Maximum bytes per header data value stored in the data structure (default is 2000) - header-value-depth: 2000 - - # Extract URLs and save in state data structure - extract-urls: yes - # Profiling settings. Only effective if Suricata has been built with the # the --enable-profiling configure flag. # From 1ab5f72fddf13079442438e47e3947ba20553dce Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Thu, 9 Oct 2014 12:23:09 -0700 Subject: [PATCH 0025/2553] mime-decode: remove "comparison between signed and unsigned integer expressions" warnings --- src/mime-decode.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mime-decode.c b/src/mime-decode.c index 6332ff1450f4..a1f8b226ca9f 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -872,7 +872,7 @@ static int IsExeUrl(char *url, uint32_t len) { for (i = 0; UrlExeExts[i] != NULL; i++) { extLen = strlen(UrlExeExts[i]); ext = FindString(url, len, UrlExeExts[i]); - if (ext != NULL && (ext + extLen - url == len || ext[extLen] == '?')) { + if (ext != NULL && (ext + extLen - url == (int)len || ext[extLen] == '?')) { isExeUrl = 1; break; } @@ -1145,7 +1145,7 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, /* If last token found without CR/LF delimiter, then save * and reconstruct with next chunk */ - if (tok + tokLen - (char *) chunk == len) { + if (tok + tokLen - (char *) chunk == (int)len) { PrintChars(SC_LOG_DEBUG, "LAST CHUNK LINE - CUTOFF", tok, tokLen); SCLogDebug("\nCHUNK CUTOFF CHARS: %d delim %ld\n", tokLen, len - (tok + tokLen - (char *) chunk)); @@ -1159,7 +1159,7 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, } } } - } while (tok != remainPtr && remainPtr - (char *) chunk < len); + } while (tok != remainPtr && remainPtr - (char *) chunk < (int)len); } } } @@ -1671,14 +1671,14 @@ static int FindMimeHeader(const char *buf, uint32_t blen, /* Value starts after 'header:' (normalize spaces) */ hval = hname + hlen + 1; - if (hval - buf >= blen) { + if (hval - buf >= (int)blen) { SCLogDebug("No Header value found"); hval = NULL; } else { while (hval[0] == ' ') { /* If last character before end of bounds, set to NULL */ - if (hval - buf >= blen - 1) { + if (hval - buf >= (int)blen - 1) { SCLogDebug("No Header value found"); hval = NULL; break; @@ -2542,7 +2542,7 @@ MimeDecEntity * MimeDecParseFullMsg(const char *buf, uint32_t blen, void *data, } } - } while (tok != remainPtr && remainPtr - buf < blen); + } while (tok != remainPtr && remainPtr - buf < (int)blen); if (ret == MIME_DEC_OK) { SCLogDebug("Message parser was successful"); From 4503ffeee92591d6d832083fc20c2833c47b5043 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Thu, 9 Oct 2014 12:52:30 -0700 Subject: [PATCH 0026/2553] mime-decode: fix minor memory leak if Mime parser initialization were to fail. --- src/mime-decode.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mime-decode.c b/src/mime-decode.c index a1f8b226ca9f..6d34d0f6f8a5 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -2349,6 +2349,7 @@ MimeDecParseState * MimeDecInitParser(void *data, state->stack = SCMalloc(sizeof(MimeDecStack)); if (unlikely(state->stack == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + SCFree(state); return NULL; } memset(state->stack, 0x00, sizeof(MimeDecStack)); @@ -2356,6 +2357,8 @@ MimeDecParseState * MimeDecInitParser(void *data, mimeMsg = SCMalloc(sizeof(MimeDecEntity)); if (unlikely(mimeMsg == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + SCFree(state->stack); + SCFree(state); return NULL; } memset(mimeMsg, 0x00, sizeof(MimeDecEntity)); @@ -2366,6 +2369,8 @@ MimeDecParseState * MimeDecInitParser(void *data, PushStack(state->stack); if (state->stack->top == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + SCFree(state->stack); + SCFree(state); return NULL; } state->stack->top->data = mimeMsg; From c279f07d2a315529a169f06fe748f0777282290f Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Thu, 9 Oct 2014 14:13:03 -0700 Subject: [PATCH 0027/2553] mime-decode: clean up after MimeDecParseFullMsgTest01. --- src/mime-decode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mime-decode.c b/src/mime-decode.c index 6d34d0f6f8a5..5c685ebde42f 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -2760,6 +2760,8 @@ static int MimeDecParseFullMsgTest01(void) { return -1; } + MimeDecFreeEntity(entity); + if (expected_count != line_count) { SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", expected_count, line_count); From f55c94cb5423cbbd21434085af02b30e6594f147 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Thu, 9 Oct 2014 15:16:50 -0700 Subject: [PATCH 0028/2553] smtp-mime: preinitialize base64 decoder space Preinit with zeros. --- src/util-base64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-base64.c b/src/util-base64.c index 40194d3270ed..a80c058f14d4 100644 --- a/src/util-base64.c +++ b/src/util-base64.c @@ -91,7 +91,7 @@ uint32_t DecodeBase64(uint8_t *dest, const char *src, uint32_t len) { int val; uint32_t padding = 0, numDecoded = 0, bbidx = 0, valid = 1, i; uint8_t *dptr = dest; - uint8_t b64[B64_BLOCK]; + uint8_t b64[B64_BLOCK] = { 0,0,0,0 }; /* Traverse through each alpha-numeric letter in the source array */ for(i = 0; i < len && src[i] != 0; i++) { From 106bbc78e12298dee953cd79330fefaa21106eb6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 09:40:35 +0200 Subject: [PATCH 0029/2553] mime: refactor buffer use Turn all buffers into uint8_t (from char) and no longer use the string functions like strncpy/strncasecmp on them. Store url and field names as lowercase, and also search/compare them as lowercase. This allows us to use SCMemcmp. --- src/app-layer-smtp.c | 2 +- src/mime-decode.c | 390 ++++++++++++++++----------------- src/mime-decode.h | 30 +-- src/output-json-email-common.c | 8 +- src/util-base64.c | 4 +- src/util-base64.h | 2 +- 6 files changed, 215 insertions(+), 221 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index e0fd88d8cfff..c0fecefc587d 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -735,7 +735,7 @@ static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { if (smtp_config.decode_mime) { - int ret = MimeDecParseLine((const char *) state->current_line, + int ret = MimeDecParseLine((const uint8_t *) state->current_line, state->current_line_len, state->mime_state); if (ret != MIME_DEC_OK) { SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret); diff --git a/src/mime-decode.c b/src/mime-decode.c index 5c685ebde42f..24cb8968e18d 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -28,6 +28,7 @@ #include "util-spm-bs.h" #include "util-unittest.h" +#include "util-memcmp.h" /* Character constants */ #ifndef CR @@ -56,10 +57,10 @@ #define MAX_HEADER_NAME 75 /* 75 + ":" = 76 */ #define MAX_HEADER_VALUE 2000 /* Default - arbitrary limit */ #define BOUNDARY_BUF 256 -#define CTNT_TYPE_STR "Content-Type" -#define CTNT_DISP_STR "Content-Disposition" -#define CTNT_TRAN_STR "Content-Transfer-Encoding" -#define MSG_ID_STR "Message-ID" +#define CTNT_TYPE_STR "content-type" +#define CTNT_DISP_STR "content-disposition" +#define CTNT_TRAN_STR "content-transfer-encoding" +#define MSG_ID_STR "message-id" #define BND_START_STR "boundary=\"" #define TOK_END_STR "\"" #define MSG_STR "message/" @@ -113,7 +114,7 @@ static const char *UrlExeExts[] = { ".exe", * * \return none */ -void PrintChars(int log_level, char *label, char *src, uint32_t len) { +static void PrintChars(int log_level, char *label, const uint8_t *src, uint32_t len) { if (log_level <= sc_log_global_log_level) { @@ -127,7 +128,11 @@ void PrintChars(int log_level, char *label, char *src, uint32_t len) { /* Add label and source */ int num = snprintf(tempbuf, llen +4 < max_len ? llen + 4 : max_len, "[%s] ", label); - strncpy(tempbuf + num, src, len + num < max_len ? len + num : max_len - num - 1); + size_t copy = len; + if ((len + num + 1) > max_len) + copy = max_len - (num + 1); + memcpy(tempbuf + num, src, copy); + tempbuf[copy] = '\0'; SCLog(log_level, "%s", tempbuf); } @@ -311,10 +316,10 @@ MimeDecField * MimeDecAddField(MimeDecEntity *entity) { } /** - * \brief Searches for a header field with the specified name (case insensitive) + * \brief Searches for a header field with the specified name * * \param entity The entity to search - * \param name The header name (case insensitive) + * \param name The header name (lowercase) * * \return The field object, or NULL if not found * @@ -323,9 +328,11 @@ MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name) { MimeDecField *curr = entity->field_list; while (curr != NULL) { - - if (strncasecmp(curr->name, name, curr->name_len) == 0) { - break; + /* name is stored lowercase */ + if (strlen(name) == curr->name_len) { + if (SCMemcmp(curr->name, name, curr->name_len) == 0) { + break; + } } curr = curr->next; } @@ -410,13 +417,11 @@ MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent) { * \param nlen Length of the name * \param value String containing the value * \param vlen Length of the value - * \param copy_name_value Flag indicating whether to make copies of the name and - * value or just point to them * * \return The field or NULL if the operation fails */ -MimeDecField * MimeDecFillField(MimeDecEntity *entity, const char *name, - uint32_t nlen, const char *value, uint32_t vlen, int copy_name_value) { +static MimeDecField * MimeDecFillField(MimeDecEntity *entity, uint8_t *name, + uint32_t nlen, const uint8_t *value, uint32_t vlen) { MimeDecField *field = MimeDecAddField(entity); if (unlikely(field == NULL)) { @@ -424,32 +429,17 @@ MimeDecField * MimeDecFillField(MimeDecEntity *entity, const char *name, } if (nlen > 0) { - if (copy_name_value) { - field->name = SCMalloc(nlen); - if (unlikely(field->name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); - SCFree(field); - return NULL; - } - strncpy(field->name, name, nlen); - } else { - field->name = (char *) name; - } + /* convert to lowercase and store */ + uint32_t u; + for (u = 0; u < nlen; u++) + name[u] = tolower(name[u]); + + field->name = (uint8_t *)name; field->name_len = nlen; } if (vlen > 0) { - if (copy_name_value) { - field->value = SCMalloc(vlen); - if (unlikely(field->value == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); - SCFree(field); - return NULL; - } - strncpy(field->value, value, vlen); - } else { - field->value = (char *) value; - } + field->value = (uint8_t *)value; field->value_len = vlen; } @@ -618,11 +608,11 @@ static void FreeDataValue(DataValue *dv) { * * \return pointer to a single value, otherwise NULL if it fails or is zero-length */ -static char * GetFullValue(DataValue *dv, uint32_t *len) { +static uint8_t * GetFullValue(DataValue *dv, uint32_t *len) { DataValue *curr; uint32_t offset = 0; - char *val = NULL; + uint8_t *val = NULL; /* First calculate total length */ *len = 0; @@ -639,7 +629,7 @@ static char * GetFullValue(DataValue *dv, uint32_t *len) { /* Must have at least one character in the value */ if (*len > 0) { - val = SCMalloc(*len); + val = SCCalloc(1, *len); if (unlikely(val == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); *len = 0; @@ -648,12 +638,12 @@ static char * GetFullValue(DataValue *dv, uint32_t *len) { curr = dv; while (curr != NULL) { - strncpy(val + offset, (char *) curr->value, curr->value_len); + memcpy(val + offset, curr->value, curr->value_len); offset += curr->value_len; /* Add CRLF except on last one */ if (curr->next != NULL) { - strncpy(val + offset, CRLF, 2); + memcpy(val + offset, CRLF, 2); offset += 2; } curr = curr->next; @@ -665,18 +655,19 @@ static char * GetFullValue(DataValue *dv, uint32_t *len) { /** * \brief Find a string while searching up to N characters within a source - * string + * buffer * * \param src The source string (not null-terminated) * \param len The length of the source string * \param find The string to find (null-terminated) + * \param find_len length of the 'find' string * * \return Pointer to the position it was found, otherwise NULL if not found */ -static inline char * FindString(const char *src, uint32_t len, const char *find) { - +static inline uint8_t * FindBuffer(const uint8_t *src, uint32_t len, const uint8_t *find, uint32_t find_len) +{ /* Use utility search function */ - return (char *) BasicSearchNocase((uint8_t *) src, len, (uint8_t *) find, strlen(find)); + return BasicSearchNocase(src, len, find, find_len); } /** @@ -689,11 +680,11 @@ static inline char * FindString(const char *src, uint32_t len, const char *find) * * \return Pointer to line */ -static char * GetLine(char *buf, uint32_t blen, char **remainPtr, +static uint8_t * GetLine(uint8_t *buf, uint32_t blen, uint8_t **remainPtr, uint32_t *tokLen) { uint32_t i; - char *tok; + uint8_t *tok; /* So that it can be used just like strtok_r */ if (buf == NULL) { @@ -741,11 +732,11 @@ static char * GetLine(char *buf, uint32_t blen, char **remainPtr, * * \return Pointer to token, or NULL if not found */ -static char * GetToken(char *buf, uint32_t blen, const char *delims, - char **remainPtr, uint32_t *tokenLen) { +static uint8_t * GetToken(uint8_t *buf, uint32_t blen, const char *delims, + uint8_t **remainPtr, uint32_t *tokenLen) { uint32_t i, j, delimFound = 0; - char *tok = NULL; + uint8_t *tok = NULL; /* So that it can be used just like strtok_r */ if (buf == NULL) { @@ -807,7 +798,7 @@ static char * GetToken(char *buf, uint32_t blen, const char *delims, static int StoreMimeHeader(MimeDecParseState *state) { int ret = MIME_DEC_OK, stored = 0; - char *val; + uint8_t *val; uint32_t vlen; /* Lets save the most recent header */ @@ -823,7 +814,7 @@ static int StoreMimeHeader(MimeDecParseState *state) { } else if (state->stack->top != NULL) { /* Store each header name and value */ if (MimeDecFillField(state->stack->top->data, state->hname, - state->hlen, val, vlen, 0) == NULL) { + state->hlen, val, vlen) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "MimeDecFillField() function failed"); ret = MIME_DEC_ERR_MEM; } else { @@ -862,16 +853,16 @@ static int StoreMimeHeader(MimeDecParseState *state) { * \retval 1 The url points to an EXE * \retval 0 The url does NOT point to an EXE */ -static int IsExeUrl(char *url, uint32_t len) { +static int IsExeUrl(const uint8_t *url, uint32_t len) { int isExeUrl = 0; uint32_t i, extLen; - char *ext; + uint8_t *ext; /* Now check for executable extensions and if not found, cut off at first '/' */ for (i = 0; UrlExeExts[i] != NULL; i++) { extLen = strlen(UrlExeExts[i]); - ext = FindString(url, len, UrlExeExts[i]); + ext = FindBuffer(url, len, (uint8_t *)UrlExeExts[i], strlen(UrlExeExts[i])); if (ext != NULL && (ext + extLen - url == (int)len || ext[extLen] == '?')) { isExeUrl = 1; break; @@ -890,7 +881,7 @@ static int IsExeUrl(char *url, uint32_t len) { * \retval 1 The host is a numeric IP * \retval 0 The host is NOT a numeric IP */ -static int IsIpv4Host(char *urlhost, uint32_t len) { +static int IsIpv4Host(const uint8_t *urlhost, uint32_t len) { struct sockaddr_in sa; @@ -911,8 +902,8 @@ static int IsIpv4Host(char *urlhost, uint32_t len) { } /* Create null-terminated string */ - strncpy(tempIp, urlhost, i); - tempIp[i] = 0; + memcpy(tempIp, urlhost, i); + tempIp[i] = '\0'; return inet_pton(AF_INET, tempIp, &(sa.sin_addr)); } @@ -926,7 +917,7 @@ static int IsIpv4Host(char *urlhost, uint32_t len) { * \retval 1 The host is a numeric IP * \retval 0 The host is NOT a numeric IP */ -static int IsIpv6Host(char *urlhost, uint32_t len) { +static int IsIpv6Host(const uint8_t *urlhost, uint32_t len) { struct sockaddr_in sa; @@ -947,8 +938,8 @@ static int IsIpv6Host(char *urlhost, uint32_t len) { } /* Create null-terminated string */ - strncpy(tempIp, urlhost, i); - tempIp[i] = 0; + memcpy(tempIp, urlhost, i); + tempIp[i] = '\0'; return inet_pton(AF_INET6, tempIp, &(sa.sin_addr)); } @@ -958,25 +949,23 @@ static int IsIpv6Host(char *urlhost, uint32_t len) { * string * * \param entity The MIME entity - * \param url The matching URL string + * \param url The matching URL string (lowercase) * \param url_len The matching URL string length * * \return URL object or NULL if not found */ -static MimeDecUrl * FindExistingUrl(MimeDecEntity *entity, char *url, - uint32_t url_len) { - - uint32_t len; +static MimeDecUrl *FindExistingUrl(MimeDecEntity *entity, uint8_t *url, uint32_t url_len) +{ MimeDecUrl *curr = entity->url_list; while (curr != NULL) { - - /* Get smaller length */ - len = curr->url_len < url_len ? curr->url_len : url_len; - if (strncasecmp(curr->url, url, len) == 0) { - break; + if (url_len == curr->url_len) { + /* search url and stored url are both in + * lowercase, so we can do an exact match */ + if (SCMemcmp(curr->url, url, url_len) == 0) { + break; + } } - curr = curr->next; } @@ -991,7 +980,7 @@ static MimeDecUrl * FindExistingUrl(MimeDecEntity *entity, char *url, * the same host, but with only small variations in path. * * The exception is that URLs with executable file extensions are stored - * with the full path. + * with the full path. They are stored in lowercase. * * Numeric IPs, malformed numeric IPs, and URLs pointing to executables are * also flagged as URLs of interest. @@ -1002,21 +991,21 @@ static MimeDecUrl * FindExistingUrl(MimeDecEntity *entity, char *url, * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -static int FindUrlStrings(const char *line, uint32_t len, +static int FindUrlStrings(const uint8_t *line, uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; - char *fptr, *remptr, *tok = NULL, *tempUrl; + uint8_t *fptr, *remptr, *tok = NULL, *tempUrl; uint32_t tokLen, i, tempUrlLen; uint8_t urlStrLen = 0, flags = 0; - remptr = (char *) line; + remptr = (uint8_t *)line; do { SCLogDebug("Looking for URL String starting with: %s", URL_STR); /* Check for token definition */ - fptr = FindString(remptr, len - (remptr - line), URL_STR); + fptr = FindBuffer(remptr, len - (remptr - line), (uint8_t *)URL_STR, strlen(URL_STR)); if (fptr != NULL) { urlStrLen = strlen(URL_STR); @@ -1041,7 +1030,8 @@ static int FindUrlStrings(const char *line, uint32_t len, // URL decoding would probably go here - tempUrl[tempUrlLen] = tok[i]; + /* url is all lowercase */ + tempUrl[tempUrlLen] = tolower(tok[i]); tempUrlLen++; } @@ -1078,15 +1068,16 @@ static int FindUrlStrings(const char *line, uint32_t len, } /* Update URL list */ - MimeDecUrl *url = FindExistingUrl(entity, tempUrl, - tempUrlLen); + MimeDecUrl *url = FindExistingUrl(entity, tempUrl, tempUrlLen); if (url == NULL) { /* Add URL list item */ url = MimeDecAddUrl(entity); - url->url = tempUrl; - url->url_len = tempUrlLen; - url->url_flags |= flags; + if (url != NULL) { + url->url = tempUrl; + url->url_len = tempUrlLen; + url->url_flags |= flags; + } } else { SCFree(tempUrl); } @@ -1116,7 +1107,7 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; - char *remainPtr, *tok; + uint8_t *remainPtr, *tok; uint32_t tokLen; if ((state->stack != NULL) && (state->stack->top != NULL) && @@ -1136,19 +1127,19 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, } else { /* No remainder from previous line */ /* Parse each line one by one */ - remainPtr = (char *) chunk; + remainPtr = (uint8_t *)chunk; do { - tok = GetLine(remainPtr, len - (remainPtr - (char *) chunk), + tok = GetLine(remainPtr, len - (remainPtr - (uint8_t *)chunk), &remainPtr, &tokLen); if (tok != remainPtr) { // DEBUG - ADDED /* If last token found without CR/LF delimiter, then save * and reconstruct with next chunk */ - if (tok + tokLen - (char *) chunk == (int)len) { + if (tok + tokLen - (uint8_t *) chunk == (int)len) { PrintChars(SC_LOG_DEBUG, "LAST CHUNK LINE - CUTOFF", tok, tokLen); - SCLogDebug("\nCHUNK CUTOFF CHARS: %d delim %ld\n", tokLen, len - (tok + tokLen - (char *) chunk)); + SCLogDebug("\nCHUNK CUTOFF CHARS: %d delim %ld\n", tokLen, len - (tok + tokLen - (uint8_t *) chunk)); } else { /* Search line for URL */ ret = FindUrlStrings(tok, tokLen, state); @@ -1159,7 +1150,7 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, } } } - } while (tok != remainPtr && remainPtr - (char *) chunk < (int)len); + } while (tok != remainPtr && remainPtr - (uint8_t *) chunk < (int)len); } } } @@ -1197,7 +1188,7 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, * * \return Number of bytes pulled from the current buffer */ -static uint8_t ProcessBase64Remainder(const char *buf, uint32_t len, +static uint8_t ProcessBase64Remainder(const uint8_t *buf, uint32_t len, MimeDecParseState *state, int force) { uint32_t ret; @@ -1208,7 +1199,7 @@ static uint8_t ProcessBase64Remainder(const char *buf, uint32_t len, /* Fill in block with first few bytes of current line */ remainder = B64_BLOCK - state->bvr_len; remainder = remainder < len ? remainder : len; - strncpy(state->bvremain + state->bvr_len, buf, remainder); + memcpy(state->bvremain + state->bvr_len, buf, remainder); state->bvr_len += remainder; /* If data chunk buffer will be full, then clear it now */ @@ -1225,7 +1216,7 @@ static uint8_t ProcessBase64Remainder(const char *buf, uint32_t len, /* Only decode if divisible by 4 */ if (state->bvr_len == B64_BLOCK || force) { remdec = DecodeBase64(state->data_chunk + state->data_chunk_len, - state->bvremain, state->bvr_len); + state->bvremain, state->bvr_len); if (remdec > 0) { /* Track decoded length */ @@ -1270,7 +1261,7 @@ static uint8_t ProcessBase64Remainder(const char *buf, uint32_t len, * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -static int ProcessBase64BodyLine(const char *buf, uint32_t len, +static int ProcessBase64BodyLine(const uint8_t *buf, uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; @@ -1303,7 +1294,7 @@ static int ProcessBase64BodyLine(const char *buf, uint32_t len, SCLogDebug("Base64 saving remainder: %u", rem2); - strncpy(state->bvremain, buf + (len - rem2), rem2); + memcpy(state->bvremain, buf + (len - rem2), rem2); state->bvr_len = rem2; } @@ -1359,7 +1350,7 @@ static int ProcessBase64BodyLine(const char *buf, uint32_t len, state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64; state->msg->anomaly_flags |= ANOM_INVALID_BASE64; SCLogDebug("Error: DecodeBase64() function failed"); - PrintChars(SC_LOG_DEBUG, "Base64 failed string", (char *) (buf + offset), tobuf); + PrintChars(SC_LOG_DEBUG, "Base64 failed string", buf + offset, tobuf); } /* Update counts */ @@ -1407,13 +1398,13 @@ static int16_t DecodeQPChar(char h) { * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -static int ProcessQuotedPrintableBodyLine(const char *buf, uint32_t len, +static int ProcessQuotedPrintableBodyLine(const uint8_t *buf, uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; uint32_t remaining, offset; MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; - char c, h1, h2, val; + uint8_t c, h1, h2, val; int16_t res; /* Track long line */ @@ -1521,7 +1512,7 @@ static int ProcessQuotedPrintableBodyLine(const char *buf, uint32_t len, * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -static int ProcessBodyLine(const char *buf, uint32_t len, +static int ProcessBodyLine(const uint8_t *buf, uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; @@ -1606,10 +1597,10 @@ static int ProcessBodyLine(const char *buf, uint32_t len, * * \return Pointer to header name, or NULL if not found */ -static char * FindMimeHeaderStart(const char *buf, uint32_t blen, uint32_t *hlen) { +static uint8_t * FindMimeHeaderStart(const uint8_t *buf, uint32_t blen, uint32_t *hlen) { uint32_t i, valid = 0; - char *hname = NULL; + uint8_t *hname = NULL; /* Init */ *hlen = 0; @@ -1625,7 +1616,7 @@ static char * FindMimeHeaderStart(const char *buf, uint32_t blen, uint32_t *hlen } else if (valid > 0 && buf[i] == COLON) { /* If ready for printable characters, found some, and found colon * delimiter, then a match is found */ - hname = (char *) buf + i - valid; + hname = (uint8_t *) buf + i - valid; *hlen = valid; break; } else { @@ -1647,11 +1638,11 @@ static char * FindMimeHeaderStart(const char *buf, uint32_t blen, uint32_t *hlen * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -static int FindMimeHeader(const char *buf, uint32_t blen, +static int FindMimeHeader(const uint8_t *buf, uint32_t blen, MimeDecParseState *state) { int ret = MIME_DEC_OK; - char *hname, *hval = NULL; + uint8_t *hname, *hval = NULL; DataValue *dv; uint32_t hlen, vlen; int finish_header = 0, new_header = 0; @@ -1732,7 +1723,7 @@ static int FindMimeHeader(const char *buf, uint32_t blen, SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); return MIME_DEC_ERR_MEM; } - strncpy(dv->value, (char *) buf, vlen); + memcpy(dv->value, buf, vlen); dv->value_len = vlen; state->hvlen += vlen; } @@ -1773,7 +1764,7 @@ static int FindMimeHeader(const char *buf, uint32_t blen, SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); return MIME_DEC_ERR_MEM; } - strncpy(state->hname, hname, hlen); + memcpy(state->hname, hname, hlen); state->hlen = hlen; if (state->hvalue != NULL) { @@ -1805,7 +1796,7 @@ static int FindMimeHeader(const char *buf, uint32_t blen, SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); return MIME_DEC_ERR_MEM; } - strncpy(state->hvalue->value, hval, vlen); + memcpy(state->hvalue->value, hval, vlen); state->hvalue->value_len = vlen; state->hvlen += vlen; } @@ -1825,15 +1816,15 @@ static int FindMimeHeader(const char *buf, uint32_t blen, * * \return A pointer to the token if found, otherwise NULL if not found */ -static char * FindMimeHeaderToken(MimeDecField *field, char *search_start, +static uint8_t * FindMimeHeaderToken(MimeDecField *field, char *search_start, char *search_end, uint32_t *tlen) { - char *fptr, *tptr = NULL, *tok = NULL; + uint8_t *fptr, *tptr = NULL, *tok = NULL; SCLogDebug("Looking for token: %s", search_start); /* Check for token definition */ - fptr = FindString(field->value, field->value_len, search_start); + fptr = FindBuffer(field->value, field->value_len, (const uint8_t *)search_start, strlen(search_start)); if (fptr != NULL) { fptr += strlen(search_start); /* Start at end of start string */ tok = GetToken(fptr, field->value_len - (fptr - field->value), search_end, @@ -1856,12 +1847,12 @@ static char * FindMimeHeaderToken(MimeDecField *field, char *search_start, * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -static int ProcessMimeHeaders(const char *buf, uint32_t len, +static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; MimeDecField *field; - char *bptr = NULL, *rptr = NULL; + uint8_t *bptr = NULL, *rptr = NULL; uint32_t blen = 0; MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; @@ -1879,10 +1870,10 @@ static int ProcessMimeHeaders(const char *buf, uint32_t len, field = MimeDecFindField(entity, CTNT_TRAN_STR); if (field != NULL) { /* Look for base64 */ - if (FindString(field->value, field->value_len, BASE64_STR)) { + if (FindBuffer(field->value, field->value_len, (const uint8_t *)BASE64_STR, strlen(BASE64_STR))) { SCLogDebug("Base64 encoding found"); entity->ctnt_flags |= CTNT_IS_BASE64; - } else if (FindString(field->value, field->value_len, QP_STR)) { + } else if (FindBuffer(field->value, field->value_len, (const uint8_t *)QP_STR, strlen(QP_STR))) { /* Look for quoted-printable */ SCLogDebug("quoted-printable encoding found"); entity->ctnt_flags |= CTNT_IS_QP; @@ -1903,7 +1894,7 @@ static int ProcessMimeHeaders(const char *buf, uint32_t len, SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); return MIME_DEC_ERR_MEM; } - strncpy(entity->filename, bptr, blen); + memcpy(entity->filename, bptr, blen); entity->filename_len = blen; } } @@ -1925,7 +1916,7 @@ static int ProcessMimeHeaders(const char *buf, uint32_t len, SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); return MIME_DEC_ERR_MEM; } - strncpy(state->stack->top->bdef, bptr, blen); + memcpy(state->stack->top->bdef, bptr, blen); state->stack->top->bdef_len = blen; } @@ -1942,7 +1933,7 @@ static int ProcessMimeHeaders(const char *buf, uint32_t len, SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); return MIME_DEC_ERR_MEM; } - strncpy(entity->filename, bptr, blen); + memcpy(entity->filename, bptr, blen); entity->filename_len = blen; } } @@ -1953,7 +1944,9 @@ static int ProcessMimeHeaders(const char *buf, uint32_t len, if (entity->ctnt_type != NULL) { /* Check for encapsulated message */ - if (FindString(entity->ctnt_type, entity->ctnt_type_len, MSG_STR)) { + if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)MSG_STR, strlen(MSG_STR))) + { SCLogDebug("Found encapsulated message entity"); entity->ctnt_flags |= CTNT_IS_ENV; @@ -1969,18 +1962,21 @@ static int ProcessMimeHeaders(const char *buf, uint32_t len, /* Ready to parse headers */ state->state_flag = HEADER_READY; - } else if (FindString(entity->ctnt_type, entity->ctnt_type_len, - MULTIPART_STR)) { + } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)MULTIPART_STR, strlen(MULTIPART_STR))) + { /* Check for multipart */ SCLogDebug("Found multipart entity"); entity->ctnt_flags |= CTNT_IS_MULTIPART; - } else if (FindString(entity->ctnt_type, entity->ctnt_type_len, - TXT_STR)) { + } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)TXT_STR, strlen(TXT_STR))) + { /* Check for plain text */ SCLogDebug("Found plain text entity"); entity->ctnt_flags |= CTNT_IS_TEXT; - } else if (FindString(entity->ctnt_type, entity->ctnt_type_len, - HTML_STR)) { + } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)HTML_STR, strlen(HTML_STR))) + { /* Check for html */ SCLogDebug("Found html entity"); entity->ctnt_flags |= CTNT_IS_HTML; @@ -2054,11 +2050,11 @@ static int ProcessBodyComplete(MimeDecParseState *state) { * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -static int ProcessMimeBoundary(const char *buf, uint32_t len, uint32_t bdef_len, +static int ProcessMimeBoundary(const uint8_t *buf, uint32_t len, uint32_t bdef_len, MimeDecParseState *state) { int ret = MIME_DEC_OK; - char *rptr; + uint8_t *rptr; MimeDecEntity *child; SCLogDebug("PROCESSING BOUNDARY - START: %d", @@ -2081,7 +2077,7 @@ static int ProcessMimeBoundary(const char *buf, uint32_t len, uint32_t bdef_len, } /* Update remaining buffer */ - rptr = (char *) buf + bdef_len + 2; + rptr = (uint8_t *) buf + bdef_len + 2; /* If entity is encapsulated and current and parent didn't define the boundary, * then pop out */ @@ -2189,12 +2185,12 @@ static int ProcessMimeBoundary(const char *buf, uint32_t len, uint32_t bdef_len, * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -static int ProcessMimeBody(const char *buf, uint32_t len, +static int ProcessMimeBody(const uint8_t *buf, uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; - char temp[BOUNDARY_BUF]; - char *bstart; + uint8_t temp[BOUNDARY_BUF]; + uint8_t *bstart; int body_found = 0; uint32_t tlen; @@ -2230,14 +2226,13 @@ static int ProcessMimeBody(const char *buf, uint32_t len, if (len > 1 && buf[0] == '-' && buf[1] == '-') { tlen = node->bdef_len + 2; - strncpy(temp, "--", 2); - strncpy(temp + 2, node->bdef, node->bdef_len); - temp[tlen] = 0; + memcpy(temp, "--", 2); + memcpy(temp + 2, node->bdef, node->bdef_len); - SCLogDebug("Boundary to search: [%s]", temp); +// SCLogDebug("Boundary to search: [%s]", temp); /* Find either next boundary or end boundary */ - bstart = FindString(buf, len, temp); + bstart = FindBuffer((const uint8_t *)buf, len, temp, tlen); if (bstart != NULL) { ret = ProcessMimeBoundary(buf, len, node->bdef_len, state); if (ret != MIME_DEC_OK) { @@ -2278,7 +2273,7 @@ static int ProcessMimeBody(const char *buf, uint32_t len, * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -static int ProcessMimeEntity(const char *buf, uint32_t len, +static int ProcessMimeEntity(const uint8_t *buf, uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; @@ -2479,14 +2474,14 @@ int MimeDecParseComplete(MimeDecParseState *state) { * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -int MimeDecParseLine(const char *line, const uint32_t len, +int MimeDecParseLine(const uint8_t *line, const uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; /* For debugging purposes */ if (len > 0) { - PrintChars(SC_LOG_DEBUG, "\nSMTP LINE", (char *) line, len); + PrintChars(SC_LOG_DEBUG, "\nSMTP LINE", line, len); } else { SCLogDebug("\nSMTP LINE - EMPTY"); } @@ -2512,12 +2507,12 @@ int MimeDecParseLine(const char *line, const uint32_t len, * * \return A pointer to the decoded MIME message, or NULL if the operation fails */ -MimeDecEntity * MimeDecParseFullMsg(const char *buf, uint32_t blen, void *data, +MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, int (*dcpfunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)) { int ret = MIME_DEC_OK; - char *remainPtr, *tok; + uint8_t *remainPtr, *tok; uint32_t tokLen; MimeDecParseState *state = MimeDecInitParser(data, dcpfunc); @@ -2530,8 +2525,8 @@ MimeDecEntity * MimeDecParseFullMsg(const char *buf, uint32_t blen, void *data, MimeDecEntity *msg = state->msg; /* Parse each line one by one */ - remainPtr = (char *) buf; - char *line = NULL; + remainPtr = (uint8_t *) buf; + uint8_t *line = NULL; do { tok = GetLine(remainPtr, blen - (remainPtr - buf), &remainPtr, &tokLen); if (tok != remainPtr) { @@ -2585,23 +2580,23 @@ static int TestDataChunkCallback(const uint8_t *chunk, uint32_t len, /* Add up the line counts */ if (len > 0) { - char *remainPtr; - char *tok; + uint8_t *remainPtr; + uint8_t *tok; uint32_t tokLen; - PrintChars(SC_LOG_DEBUG, (char *) "CHUNK", (char *) chunk, len); + PrintChars(SC_LOG_DEBUG, "CHUNK", chunk, len); /* Parse each line one by one */ - remainPtr = (char *) chunk; + remainPtr = (uint8_t *) chunk; do { - tok = GetLine(remainPtr, len - (remainPtr - (char *) chunk), + tok = GetLine(remainPtr, len - (remainPtr - (uint8_t *) chunk), &remainPtr, &tokLen); if (tok != NULL && tok != remainPtr) { (*line_count)++; } } while (tok != NULL && tok != remainPtr && - remainPtr - (char *) chunk < len); + remainPtr - (uint8_t *) chunk < len); SCLogDebug("line count (len=%u): %u", len, *line_count); } @@ -2624,27 +2619,26 @@ static int MimeDecParseLineTest01(void) { MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - char str[256]; - strcpy(str, "From: Sender1"); - ret = MimeDecParseLine(str, strlen(str), state); + char *str = "From: Sender1"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, "To: Recipient1"); - ret = MimeDecParseLine(str, strlen(str), state); + str = "To: Recipient1"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, "Content-Type: text/plain"); - ret = MimeDecParseLine(str, strlen(str), state); + str = "Content-Type: text/plain"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, ""); - ret = MimeDecParseLine(str, strlen(str), state); + str = ""; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, "A simple message line 1"); - ret = MimeDecParseLine(str, strlen(str), state); + str = "A simple message line 1"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, "A simple message line 2"); - ret = MimeDecParseLine(str, strlen(str), state); + str = "A simple message line 2"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, "A simple message line 3"); - ret = MimeDecParseLine(str, strlen(str), state); + str = "A simple message line 3"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); /* Completed */ ret = MimeDecParseComplete(state); @@ -2689,25 +2683,24 @@ static int MimeDecParseLineTest02(void) { MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - char str[256]; - strcpy(str, "From: Sender1"); - ret = MimeDecParseLine(str, strlen(str), state); + char *str = "From: Sender1"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, "To: Recipient1"); - ret = MimeDecParseLine(str, strlen(str), state); + str = "To: Recipient1"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, "Content-Type: text/plain"); - ret = MimeDecParseLine(str, strlen(str), state); + str = "Content-Type: text/plain"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, ""); - ret = MimeDecParseLine(str, strlen(str), state); + str = ""; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, "A simple message line 1"); - ret = MimeDecParseLine(str, strlen(str), state); + str = "A simple message line 1"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); - strcpy(str, "A simple message line 2 click on http://www.test.com/malware.exe?" - "hahah hopefully you click this link"); - ret = MimeDecParseLine(str, strlen(str), state); + str = "A simple message line 2 click on http://www.test.com/malware.exe?" + "hahah hopefully you click this link"; + ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); /* Completed */ ret = MimeDecParseComplete(state); @@ -2753,7 +2746,7 @@ static int MimeDecParseFullMsgTest01(void) { "Line 2\r\n" "Line 3\r\n"; - MimeDecEntity *entity = MimeDecParseFullMsg(msg, strlen(msg), &line_count, + MimeDecEntity *entity = MimeDecParseFullMsg((uint8_t *)msg, strlen(msg), &line_count, TestDataChunkCallback); if (entity == NULL) { SCLogInfo("Warning: Message failed to parse"); @@ -2780,12 +2773,13 @@ static int MimeBase64DecodeTest01(void){ char *base64msg = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QU" "VJTVFVWV1hZWjEyMzQ1Njc4OTBAIyQlXiYqKCktPV8rLC4vOydbXTw+Pzo="; - char *dst; - dst = (char *)malloc(strlen(msg)-1); + uint8_t *dst = SCMalloc(strlen(msg)-1); + if (dst == NULL) + return 0; - ret = DecodeBase64((uint8_t *)dst, base64msg, strlen(base64msg)); + ret = DecodeBase64(dst, (const uint8_t *)base64msg, strlen(base64msg)); - if(strcmp(dst, msg) == 0){ + if (memcmp(dst, msg, strlen(msg)) == 0) { ret = 0; } @@ -2797,11 +2791,11 @@ static int MimeIsExeURLTest01(void){ char *url1 = "http://www.google.com/"; char *url2 = "http://www.google.com/test.exe"; - if(IsExeUrl(url1, strlen(url1)) != 0){ + if(IsExeUrl((const uint8_t *)url1, strlen(url1)) != 0){ SCLogDebug("Debug: URL1 error"); goto end; } - if(IsExeUrl(url2, strlen(url2)) != 1){ + if(IsExeUrl((const uint8_t *)url2, strlen(url2)) != 1){ SCLogDebug("Debug: URL2 error"); goto end; } @@ -2814,27 +2808,27 @@ static int MimeIsExeURLTest01(void){ static int MimeIsIpv4HostTest01(void) { - if(IsIpv4Host("192.168.1.1", 11) != 1) { + if(IsIpv4Host((const uint8_t *)"192.168.1.1", 11) != 1) { return 1; } - if(IsIpv4Host("999.oogle.com", 14) != 0) { + if(IsIpv4Host((const uint8_t *)"999.oogle.com", 14) != 0) { return 1; } - if(IsIpv4Host("0:0:0:0:0:0:0:0", 15) != 0) { + if(IsIpv4Host((const uint8_t *)"0:0:0:0:0:0:0:0", 15) != 0) { return 1; } - if (IsIpv4Host("192.168.255.255", 15) != 1) { + if (IsIpv4Host((const uint8_t *)"192.168.255.255", 15) != 1) { return 1; } - if (IsIpv4Host("192.168.255.255/testurl.html", 28) != 1) { + if (IsIpv4Host((const uint8_t *)"192.168.255.255/testurl.html", 28) != 1) { return 1; } - if (IsIpv4Host("www.google.com", 14) != 0) { + if (IsIpv4Host((const uint8_t *)"www.google.com", 14) != 0) { return 1; } @@ -2843,35 +2837,35 @@ static int MimeIsIpv4HostTest01(void) { static int MimeIsIpv6HostTest01(void) { - if(IsIpv6Host("0:0:0:0:0:0:0:0", 19) != 1) { + if(IsIpv6Host((const uint8_t *)"0:0:0:0:0:0:0:0", 19) != 1) { return 1; } - if(IsIpv6Host("0000:0000:0000:0000:0000:0000:0000:0000", 39) != 1) { + if(IsIpv6Host((const uint8_t *)"0000:0000:0000:0000:0000:0000:0000:0000", 39) != 1) { return 1; } - if(IsIpv6Host("0:0:0:0:0:0:0:0", 19) != 1) { + if(IsIpv6Host((const uint8_t *)"0:0:0:0:0:0:0:0", 19) != 1) { return 1; } - if(IsIpv6Host("192:168:1:1:0:0:0:0", 19) != 1) { + if(IsIpv6Host((const uint8_t *)"192:168:1:1:0:0:0:0", 19) != 1) { return 1; } - if(IsIpv6Host("999.oogle.com", 14) != 0) { + if(IsIpv6Host((const uint8_t *)"999.oogle.com", 14) != 0) { return 1; } - if (IsIpv6Host("192.168.255.255", 15) != 0) { + if (IsIpv6Host((const uint8_t *)"192.168.255.255", 15) != 0) { return 1; } - if (IsIpv6Host("192.168.255.255/testurl.html", 28) != 0) { + if (IsIpv6Host((const uint8_t *)"192.168.255.255/testurl.html", 28) != 0) { return 1; } - if (IsIpv6Host("www.google.com", 14) != 0) { + if (IsIpv6Host((const uint8_t *)"www.google.com", 14) != 0) { return 1; } diff --git a/src/mime-decode.h b/src/mime-decode.h index e5188b74da97..bd3183b1db33 100644 --- a/src/mime-decode.h +++ b/src/mime-decode.h @@ -104,9 +104,9 @@ typedef struct MimeDecConfig { * \brief This represents a header field name and associated value */ typedef struct MimeDecField { - char *name; /**< Name of the header field */ + uint8_t *name; /**< Name of the header field */ uint32_t name_len; /**< Length of the name */ - char *value; /**< Value of the header field */ + uint8_t *value; /**< Value of the header field */ uint32_t value_len; /**< Length of the value */ struct MimeDecField *next; /**< Pointer to next field */ } MimeDecField; @@ -119,7 +119,7 @@ typedef struct MimeDecField { * pointing to an executable file (see url_flags to determine which). */ typedef struct MimeDecUrl { - char *url; /**< String representation of full or partial URL */ + uint8_t *url; /**< String representation of full or partial URL (lowercase) */ uint32_t url_len; /**< Length of the URL string */ uint32_t url_flags; /**< Flags indicating type of URL */ uint32_t url_cnt; /**< Count of URLs with same value */ @@ -138,11 +138,11 @@ typedef struct MimeDecEntity { uint32_t header_flags; /**< Flags indicating header characteristics */ uint32_t ctnt_flags; /**< Flags indicating type of content */ uint32_t anomaly_flags; /**< Flags indicating an anomaly in the message */ - char *filename; /**< Name of file attachment */ + uint8_t *filename; /**< Name of file attachment */ uint32_t filename_len; /**< Length of file attachment name */ - char *ctnt_type; /**< Quick access pointer to short-hand content type field */ + uint8_t *ctnt_type; /**< Quick access pointer to short-hand content type field */ uint32_t ctnt_type_len; /**< Length of content type field value */ - char *msg_id; /**< Quick access pointer to message Id */ + uint8_t *msg_id; /**< Quick access pointer to message Id */ uint32_t msg_id_len; /**< Quick access pointer to message Id */ struct MimeDecEntity *next; /**< Pointer to list of sibling entities */ struct MimeDecEntity *child; /**< Pointer to list of child entities */ @@ -155,7 +155,7 @@ typedef struct MimeDecEntity { */ typedef struct MimeDecStackNode { MimeDecEntity *data; /**< Pointer to the entity data structure */ - char *bdef; /**< Copy of boundary definition for child entity */ + uint8_t *bdef; /**< Copy of boundary definition for child entity */ uint32_t bdef_len; /**< Boundary length for child entity */ int is_encap; /**< Flag indicating entity is encapsulated in message */ struct MimeDecStackNode *next; /**< Pointer to next item on the stack */ @@ -176,7 +176,7 @@ typedef struct MimeDecStack { * */ typedef struct DataValue { - char *value; /**< Copy of data value */ + uint8_t *value; /**< Copy of data value */ uint32_t value_len; /**< Length of data value */ struct DataValue *next; /**< Pointer to next value in the list */ } DataValue; @@ -188,13 +188,13 @@ typedef struct DataValue { typedef struct MimeDecParseState { MimeDecEntity *msg; /**< Pointer to the top-level message entity */ MimeDecStack *stack; /**< Pointer to the top of the entity stack */ - char *hname; /**< Copy of the last known header name */ + uint8_t *hname; /**< Copy of the last known header name */ uint32_t hlen; /**< Length of the last known header name */ DataValue *hvalue; /**< Pointer to the incomplete header value list */ uint32_t hvlen; /**< Total length of value list */ - char linerem[LINEREM_SIZE]; /**< Remainder from previous line (for URL extraction) */ + uint8_t linerem[LINEREM_SIZE]; /**< Remainder from previous line (for URL extraction) */ uint16_t linerem_len; /**< Length of remainder from previous line */ - char bvremain[B64_BLOCK]; /**< Remainder from base64-decoded line */ + uint8_t bvremain[B64_BLOCK]; /**< Remainder from base64-decoded line */ uint8_t bvr_len; /**< Length of remainder from base64-decoded line */ uint8_t data_chunk[DATA_CHUNK_SIZE]; /**< Buffer holding data chunk */ uint32_t data_chunk_len; /**< Length of data chunk */ @@ -223,16 +223,16 @@ MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity); MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent); /* Helper functions */ -MimeDecField * MimeDecFillField(MimeDecEntity *entity, const char *name, - uint32_t nlen, const char *value, uint32_t vlen, int copy_name_value); +//MimeDecField * MimeDecFillField(MimeDecEntity *entity, const char *name, +// uint32_t nlen, const char *value, uint32_t vlen, int copy_name_value); /* Parser functions */ MimeDecParseState * MimeDecInitParser(void *data, int (*dcpfunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); void MimeDecDeInitParser(MimeDecParseState *state); int MimeDecParseComplete(MimeDecParseState *state); -int MimeDecParseLine(const char *line, const uint32_t len, MimeDecParseState *state); -MimeDecEntity * MimeDecParseFullMsg(const char *buf, uint32_t blen, void *data, +int MimeDecParseLine(const uint8_t *line, const uint32_t len, MimeDecParseState *state); +MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, int (*dcpfunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); /* Test functions */ diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 129eb5df5a39..019cc9436b0c 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -108,7 +108,7 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, //printf("email LOG\n"); /* From: */ - field = MimeDecFindField(entity, "From"); + field = MimeDecFindField(entity, "from"); if (field != NULL) { char *s = BytesToString((uint8_t *)field->value, (size_t)field->value_len); @@ -121,7 +121,7 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, /* To: */ char *to_line = NULL; - field = MimeDecFindField(entity, "To"); + field = MimeDecFindField(entity, "to"); if (field != NULL) { json_t *js_to = json_array(); if (likely(js_to != NULL)) { @@ -143,7 +143,7 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, /* Cc: */ char *cc_line = NULL; - field = MimeDecFindField(entity, "Cc"); + field = MimeDecFindField(entity, "cc"); if (field != NULL) { json_t *js_cc = json_array(); if (likely(js_cc != NULL)) { @@ -164,7 +164,7 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, } /* Subject: */ - field = MimeDecFindField(entity, "Subject"); + field = MimeDecFindField(entity, "subject"); if (field != NULL) { char *s = BytesToString((uint8_t *)field->value, (size_t) field->value_len); if (likely(s != NULL)) { diff --git a/src/util-base64.c b/src/util-base64.c index a80c058f14d4..f4b508a0199b 100644 --- a/src/util-base64.c +++ b/src/util-base64.c @@ -50,7 +50,7 @@ static const int b64table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, * * \return The decoded value (0 or above), or -1 if the parameter is invalid */ -static inline int GetBase64Value(char c) { +static inline int GetBase64Value(uint8_t c) { int val = -1; @@ -86,7 +86,7 @@ static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64 * * \return Number of bytes decoded, or 0 if no data is decoded or it fails */ -uint32_t DecodeBase64(uint8_t *dest, const char *src, uint32_t len) { +uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len) { int val; uint32_t padding = 0, numDecoded = 0, bbidx = 0, valid = 1, i; diff --git a/src/util-base64.h b/src/util-base64.h index 5e7c39c8a438..fb1a90a3b577 100644 --- a/src/util-base64.h +++ b/src/util-base64.h @@ -49,6 +49,6 @@ #define B64_BLOCK 4 /* Function prototypes */ -uint32_t DecodeBase64(uint8_t *dest, const char *src, uint32_t len); +uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len); #endif From c712ab2299ab9ef111a500cbf2cd2f89788bc3ca Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 13:54:42 +0200 Subject: [PATCH 0030/2553] Fix compiler warning --- src/mime-decode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mime-decode.c b/src/mime-decode.c index 24cb8968e18d..5d03a51ff972 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -997,7 +997,7 @@ static int FindUrlStrings(const uint8_t *line, uint32_t len, int ret = MIME_DEC_OK; MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; uint8_t *fptr, *remptr, *tok = NULL, *tempUrl; - uint32_t tokLen, i, tempUrlLen; + uint32_t tokLen = 0, i, tempUrlLen; uint8_t urlStrLen = 0, flags = 0; remptr = (uint8_t *)line; From d72f8c7de5608558cf6d0bfd7cf96c40cb03ecb6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 14:11:03 +0200 Subject: [PATCH 0031/2553] output smtp: clean up memory at shutdown --- src/output-json-smtp.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index db6374ebf036..c0b332c1b154 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -61,6 +61,26 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p) SCReturnInt(JsonEmailLogger(tv, thread_data, p)); } +static void OutputSmtpLogDeInitCtx(OutputCtx *output_ctx) +{ + OutputJsonEmailCtx *email_ctx = output_ctx->data; + if (email_ctx != NULL) { + LogFileFreeCtx(email_ctx->file_ctx); + SCFree(email_ctx); + } + SCFree(output_ctx); +} + +static void OutputSmtpLogDeInitCtxSub(OutputCtx *output_ctx) +{ + SCLogDebug("cleaning up sub output_ctx %p", output_ctx); + OutputJsonEmailCtx *email_ctx = output_ctx->data; + if (email_ctx != NULL) { + SCFree(email_ctx); + } + SCFree(output_ctx); +} + #define DEFAULT_LOG_FILENAME "smtp.json" OutputCtx *OutputSmtpLogInit(ConfNode *conf) { @@ -91,7 +111,7 @@ OutputCtx *OutputSmtpLogInit(ConfNode *conf) email_ctx->file_ctx = file_ctx; output_ctx->data = email_ctx; - output_ctx->DeInit = NULL; + output_ctx->DeInit = OutputSmtpLogDeInitCtx; /* enable the logger for the app layer */ AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); @@ -116,7 +136,7 @@ static OutputCtx *OutputSmtpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) email_ctx->file_ctx = ajt->file_ctx; output_ctx->data = email_ctx; - output_ctx->DeInit = NULL; + output_ctx->DeInit = OutputSmtpLogDeInitCtxSub; /* enable the logger for the app layer */ AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); From bffceb71156ee39a3aa2289b1a094c313e861217 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 15:22:30 +0200 Subject: [PATCH 0032/2553] mime decode: remove unused url counter --- src/mime-decode.c | 2 -- src/mime-decode.h | 1 - 2 files changed, 3 deletions(-) diff --git a/src/mime-decode.c b/src/mime-decode.c index 5d03a51ff972..51bcda825e09 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -1081,8 +1081,6 @@ static int FindUrlStrings(const uint8_t *line, uint32_t len, } else { SCFree(tempUrl); } - /* Increment counter */ - url->url_cnt++; } else { SCFree(tempUrl); } diff --git a/src/mime-decode.h b/src/mime-decode.h index bd3183b1db33..c6d13af330c2 100644 --- a/src/mime-decode.h +++ b/src/mime-decode.h @@ -122,7 +122,6 @@ typedef struct MimeDecUrl { uint8_t *url; /**< String representation of full or partial URL (lowercase) */ uint32_t url_len; /**< Length of the URL string */ uint32_t url_flags; /**< Flags indicating type of URL */ - uint32_t url_cnt; /**< Count of URLs with same value */ struct MimeDecUrl *next; /**< Pointer to next URL */ } MimeDecUrl; From f91d52a0d2c91a02b8203cb4c14ae611e8bd427d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 15:25:46 +0200 Subject: [PATCH 0033/2553] mime decode: fix memory leak --- src/mime-decode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mime-decode.c b/src/mime-decode.c index 51bcda825e09..a34d6a7142d0 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -806,7 +806,6 @@ static int StoreMimeHeader(MimeDecParseState *state) { SCLogDebug("Storing last header"); val = GetFullValue(state->hvalue, &vlen); if (val != NULL) { - if (state->hname == NULL) { SCLogDebug("Error: Invalid parser state - header value without" " name"); @@ -833,6 +832,7 @@ static int StoreMimeHeader(MimeDecParseState *state) { /* Do cleanup here */ if (!stored) { SCFree(state->hname); + SCFree(val); } state->hname = NULL; FreeDataValue(state->hvalue); From dd4b506cc28aeb893c76acbda43019d039a59e59 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 16:16:54 +0200 Subject: [PATCH 0034/2553] decode mime: fix scan-build issues --- src/mime-decode.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/mime-decode.c b/src/mime-decode.c index a34d6a7142d0..f2f9d24a5009 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -299,17 +299,14 @@ MimeDecField * MimeDecAddField(MimeDecEntity *entity) { } memset(node, 0x00, sizeof(MimeDecField)); - if (entity != NULL) { - - /* If list is empty, then set as head of list */ - if (entity->field_list == NULL) { - entity->field_list = node; - } else { - /* Otherwise add to beginning of list since these are out-of-order in - * the message */ - node->next = entity->field_list; - entity->field_list = node; - } + /* If list is empty, then set as head of list */ + if (entity->field_list == NULL) { + entity->field_list = node; + } else { + /* Otherwise add to beginning of list since these are out-of-order in + * the message */ + node->next = entity->field_list; + entity->field_list = node; } return node; @@ -692,6 +689,9 @@ static uint8_t * GetLine(uint8_t *buf, uint32_t blen, uint8_t **remainPtr, } else { *remainPtr = buf; } + if (buf == NULL) + return NULL; + tok = buf; /* length must be specified */ @@ -744,6 +744,8 @@ static uint8_t * GetToken(uint8_t *buf, uint32_t blen, const char *delims, } else { *remainPtr = buf; } + if (buf == NULL) + return NULL; /* Must specify length */ for (i = 0; i < blen && buf[i] != 0; i++) { From cd55b657c21ff5e35d8abe7009195a6a858323a5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 16:22:40 +0200 Subject: [PATCH 0035/2553] mime decode: improve MimeDecParseLineTest01 and MimeDecParseLineTest02 tests --- src/mime-decode.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/mime-decode.c b/src/mime-decode.c index f2f9d24a5009..771cfe6d91a0 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -2620,26 +2620,29 @@ static int MimeDecParseLineTest01(void) { TestDataChunkCallback); char *str = "From: Sender1"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = "To: Recipient1"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = "Content-Type: text/plain"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = ""; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = "A simple message line 1"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = "A simple message line 2"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = "A simple message line 3"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + if (ret != MIME_DEC_OK) { + return ret; + } /* Completed */ ret = MimeDecParseComplete(state); if (ret != MIME_DEC_OK) { @@ -2684,24 +2687,27 @@ static int MimeDecParseLineTest02(void) { TestDataChunkCallback); char *str = "From: Sender1"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = "To: Recipient1"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = "Content-Type: text/plain"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = ""; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = "A simple message line 1"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); str = "A simple message line 2 click on http://www.test.com/malware.exe?" "hahah hopefully you click this link"; - ret = MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + if (ret != MIME_DEC_OK) { + return ret; + } /* Completed */ ret = MimeDecParseComplete(state); if (ret != MIME_DEC_OK) { From de44a5af94d18d54004511fac92952040dd9971c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 16:46:01 +0200 Subject: [PATCH 0036/2553] decode mime: clean up includes --- src/mime-decode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mime-decode.c b/src/mime-decode.c index 771cfe6d91a0..8029a4891e2f 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -22,8 +22,8 @@ * */ -#include -#include +#include "suricata-common.h" + #include "mime-decode.h" #include "util-spm-bs.h" From 9a573c570498f79f8f9e0c19d41fe186568f3019 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 16:59:15 +0200 Subject: [PATCH 0037/2553] output smtp: fix call --- src/output-json-smtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index c0b332c1b154..10b307b93e4b 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -57,8 +57,8 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p) { SCEnter(); - - SCReturnInt(JsonEmailLogger(tv, thread_data, p)); + int r = JsonEmailLogger(tv, thread_data, p); + SCReturnInt(r); } static void OutputSmtpLogDeInitCtx(OutputCtx *output_ctx) From 595acf2dfc5d451196d83e9a3d2017ed6d429b2d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 17:30:09 +0200 Subject: [PATCH 0038/2553] mime decode: reshuffle data structures to reduce structure sizes --- src/mime-decode.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mime-decode.h b/src/mime-decode.h index c6d13af330c2..20a8ce79f161 100644 --- a/src/mime-decode.h +++ b/src/mime-decode.h @@ -106,8 +106,8 @@ typedef struct MimeDecConfig { typedef struct MimeDecField { uint8_t *name; /**< Name of the header field */ uint32_t name_len; /**< Length of the name */ - uint8_t *value; /**< Value of the header field */ uint32_t value_len; /**< Length of the value */ + uint8_t *value; /**< Value of the header field */ struct MimeDecField *next; /**< Pointer to next field */ } MimeDecField; @@ -137,12 +137,12 @@ typedef struct MimeDecEntity { uint32_t header_flags; /**< Flags indicating header characteristics */ uint32_t ctnt_flags; /**< Flags indicating type of content */ uint32_t anomaly_flags; /**< Flags indicating an anomaly in the message */ - uint8_t *filename; /**< Name of file attachment */ uint32_t filename_len; /**< Length of file attachment name */ + uint8_t *filename; /**< Name of file attachment */ uint8_t *ctnt_type; /**< Quick access pointer to short-hand content type field */ uint32_t ctnt_type_len; /**< Length of content type field value */ - uint8_t *msg_id; /**< Quick access pointer to message Id */ uint32_t msg_id_len; /**< Quick access pointer to message Id */ + uint8_t *msg_id; /**< Quick access pointer to message Id */ struct MimeDecEntity *next; /**< Pointer to list of sibling entities */ struct MimeDecEntity *child; /**< Pointer to list of child entities */ } MimeDecEntity; @@ -189,18 +189,18 @@ typedef struct MimeDecParseState { MimeDecStack *stack; /**< Pointer to the top of the entity stack */ uint8_t *hname; /**< Copy of the last known header name */ uint32_t hlen; /**< Length of the last known header name */ - DataValue *hvalue; /**< Pointer to the incomplete header value list */ uint32_t hvlen; /**< Total length of value list */ + DataValue *hvalue; /**< Pointer to the incomplete header value list */ uint8_t linerem[LINEREM_SIZE]; /**< Remainder from previous line (for URL extraction) */ uint16_t linerem_len; /**< Length of remainder from previous line */ uint8_t bvremain[B64_BLOCK]; /**< Remainder from base64-decoded line */ uint8_t bvr_len; /**< Length of remainder from base64-decoded line */ uint8_t data_chunk[DATA_CHUNK_SIZE]; /**< Buffer holding data chunk */ + uint8_t state_flag; /**< Flag representing current state of parser */ uint32_t data_chunk_len; /**< Length of data chunk */ int found_child; /**< Flag indicating a child entity was found */ int body_begin; /**< Currently at beginning of body */ int body_end; /**< Currently at end of body */ - uint8_t state_flag; /**< Flag representing current state of parser */ void *data; /**< Pointer to data specific to the caller */ int (*dataChunkProcessor) (const uint8_t *chunk, uint32_t len, struct MimeDecParseState *state); /**< Data chunk processing function callback */ From 6035470ffbb0325501e4802646a7946521370139 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 17:36:56 +0200 Subject: [PATCH 0039/2553] mime: style updates --- src/mime-decode.c | 218 ++++++++++++++++++++++------------------------ src/mime-decode.h | 4 +- 2 files changed, 107 insertions(+), 115 deletions(-) diff --git a/src/mime-decode.c b/src/mime-decode.c index 8029a4891e2f..31d4bcb0acd3 100644 --- a/src/mime-decode.c +++ b/src/mime-decode.c @@ -114,8 +114,8 @@ static const char *UrlExeExts[] = { ".exe", * * \return none */ -static void PrintChars(int log_level, char *label, const uint8_t *src, uint32_t len) { - +static void PrintChars(int log_level, char *label, const uint8_t *src, uint32_t len) +{ if (log_level <= sc_log_global_log_level) { static uint32_t max_len = 100; @@ -145,8 +145,8 @@ static void PrintChars(int log_level, char *label, const uint8_t *src, uint32_t * \param config Config policy to set * \return none */ -void MimeDecSetConfig(MimeDecConfig *config) { - +void MimeDecSetConfig(MimeDecConfig *config) +{ if (config != NULL) { mime_dec_config = *config; @@ -164,7 +164,8 @@ void MimeDecSetConfig(MimeDecConfig *config) { * * \return config data structure */ -MimeDecConfig * MimeDecGetConfig(void) { +MimeDecConfig * MimeDecGetConfig(void) +{ return &mime_dec_config; } @@ -232,8 +233,8 @@ void MimeDecFreeEntity (MimeDecEntity *entity) * \return none * */ -void MimeDecFreeField(MimeDecField *field) { - +void MimeDecFreeField(MimeDecField *field) +{ MimeDecField *temp, *curr; if (field != NULL) { @@ -261,8 +262,8 @@ void MimeDecFreeField(MimeDecField *field) { * \return none * */ -void MimeDecFreeUrl(MimeDecUrl *url) { - +void MimeDecFreeUrl(MimeDecUrl *url) +{ MimeDecUrl *temp, *curr; if (url != NULL) { @@ -290,8 +291,8 @@ void MimeDecFreeUrl(MimeDecUrl *url) { * \return The field object, or NULL if the operation fails * */ -MimeDecField * MimeDecAddField(MimeDecEntity *entity) { - +MimeDecField * MimeDecAddField(MimeDecEntity *entity) +{ MimeDecField *node = SCMalloc(sizeof(MimeDecField)); if (unlikely(node == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); @@ -347,8 +348,8 @@ MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name) { * \return URL entry or NULL if the operation fails * */ -MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity) { - +MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity) +{ MimeDecUrl *node = SCMalloc(sizeof(MimeDecUrl)); if (unlikely(node == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); @@ -380,8 +381,8 @@ MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity) { * \return The child entity, or NULL if the operation fails * */ -MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent) { - +MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent) +{ MimeDecEntity *curr, *node = SCMalloc(sizeof(MimeDecEntity)); if (unlikely(node == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); @@ -418,8 +419,8 @@ MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent) { * \return The field or NULL if the operation fails */ static MimeDecField * MimeDecFillField(MimeDecEntity *entity, uint8_t *name, - uint32_t nlen, const uint8_t *value, uint32_t vlen) { - + uint32_t nlen, const uint8_t *value, uint32_t vlen) +{ MimeDecField *field = MimeDecAddField(entity); if (unlikely(field == NULL)) { return NULL; @@ -450,8 +451,8 @@ static MimeDecField * MimeDecFillField(MimeDecEntity *entity, uint8_t *name, * * \return pointer to a new node, otherwise NULL if it fails */ -static MimeDecStackNode * PushStack(MimeDecStack *stack) { - +static MimeDecStackNode * PushStack(MimeDecStack *stack) +{ /* Attempt to pull from free nodes list */ MimeDecStackNode *node = stack->free_nodes; if (node == NULL) { @@ -482,8 +483,8 @@ static MimeDecStackNode * PushStack(MimeDecStack *stack) { * * \return pointer to the next node, otherwise NULL if no nodes remain */ -static MimeDecStackNode * PopStack(MimeDecStack *stack) { - +static MimeDecStackNode * PopStack(MimeDecStack *stack) +{ /* Move stack pointer to next item */ MimeDecStackNode *curr = stack->top; if (curr != NULL) { @@ -514,12 +515,11 @@ static MimeDecStackNode * PopStack(MimeDecStack *stack) { * * \return none */ -static void FreeMimeDecStack(MimeDecStack *stack) { - +static void FreeMimeDecStack(MimeDecStack *stack) +{ MimeDecStackNode *temp, *curr; if (stack != NULL) { - /* Top of stack */ curr = stack->top; while (curr != NULL) { @@ -552,8 +552,8 @@ static void FreeMimeDecStack(MimeDecStack *stack) { * * \return pointer to a new node, otherwise NULL if it fails */ -static DataValue * AddDataValue(DataValue *dv) { - +static DataValue * AddDataValue(DataValue *dv) +{ DataValue *curr, *node = SCMalloc(sizeof(DataValue)); if (unlikely(node == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); @@ -580,7 +580,8 @@ static DataValue * AddDataValue(DataValue *dv) { * * \return none */ -static void FreeDataValue(DataValue *dv) { +static void FreeDataValue(DataValue *dv) +{ DataValue *temp, *curr; if (dv != NULL) { @@ -605,8 +606,8 @@ static void FreeDataValue(DataValue *dv) { * * \return pointer to a single value, otherwise NULL if it fails or is zero-length */ -static uint8_t * GetFullValue(DataValue *dv, uint32_t *len) { - +static uint8_t * GetFullValue(DataValue *dv, uint32_t *len) +{ DataValue *curr; uint32_t offset = 0; uint8_t *val = NULL; @@ -678,8 +679,8 @@ static inline uint8_t * FindBuffer(const uint8_t *src, uint32_t len, const uint8 * \return Pointer to line */ static uint8_t * GetLine(uint8_t *buf, uint32_t blen, uint8_t **remainPtr, - uint32_t *tokLen) { - + uint32_t *tokLen) +{ uint32_t i; uint8_t *tok; @@ -733,8 +734,8 @@ static uint8_t * GetLine(uint8_t *buf, uint32_t blen, uint8_t **remainPtr, * \return Pointer to token, or NULL if not found */ static uint8_t * GetToken(uint8_t *buf, uint32_t blen, const char *delims, - uint8_t **remainPtr, uint32_t *tokenLen) { - + uint8_t **remainPtr, uint32_t *tokenLen) +{ uint32_t i, j, delimFound = 0; uint8_t *tok = NULL; @@ -797,8 +798,8 @@ static uint8_t * GetToken(uint8_t *buf, uint32_t blen, const char *delims, * * \return MIME_DEC_OK if stored, otherwise a negative number indicating error */ -static int StoreMimeHeader(MimeDecParseState *state) { - +static int StoreMimeHeader(MimeDecParseState *state) +{ int ret = MIME_DEC_OK, stored = 0; uint8_t *val; uint32_t vlen; @@ -855,8 +856,8 @@ static int StoreMimeHeader(MimeDecParseState *state) { * \retval 1 The url points to an EXE * \retval 0 The url does NOT point to an EXE */ -static int IsExeUrl(const uint8_t *url, uint32_t len) { - +static int IsExeUrl(const uint8_t *url, uint32_t len) +{ int isExeUrl = 0; uint32_t i, extLen; uint8_t *ext; @@ -883,10 +884,9 @@ static int IsExeUrl(const uint8_t *url, uint32_t len) { * \retval 1 The host is a numeric IP * \retval 0 The host is NOT a numeric IP */ -static int IsIpv4Host(const uint8_t *urlhost, uint32_t len) { - +static int IsIpv4Host(const uint8_t *urlhost, uint32_t len) +{ struct sockaddr_in sa; - char tempIp[MAX_IP4_CHARS + 1]; /* Cut off at '/' */ @@ -919,10 +919,9 @@ static int IsIpv4Host(const uint8_t *urlhost, uint32_t len) { * \retval 1 The host is a numeric IP * \retval 0 The host is NOT a numeric IP */ -static int IsIpv6Host(const uint8_t *urlhost, uint32_t len) { - +static int IsIpv6Host(const uint8_t *urlhost, uint32_t len) +{ struct sockaddr_in sa; - char tempIp[MAX_IP6_CHARS + 1]; /* Cut off at '/' */ @@ -994,8 +993,8 @@ static MimeDecUrl *FindExistingUrl(MimeDecEntity *entity, uint8_t *url, uint32_t * \return MIME_DEC_OK on success, otherwise < 0 on failure */ static int FindUrlStrings(const uint8_t *line, uint32_t len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; uint8_t *fptr, *remptr, *tok = NULL, *tempUrl; @@ -1104,8 +1103,8 @@ static int FindUrlStrings(const uint8_t *line, uint32_t len, * \return MIME_DEC_OK on success, otherwise < 0 on failure */ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; uint8_t *remainPtr, *tok; uint32_t tokLen; @@ -1156,8 +1155,8 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, } /* Now invoke callback */ - if (state->dataChunkProcessor != NULL) { - ret = state->dataChunkProcessor(chunk, len, state); + if (state->DataChunkProcessorFunc != NULL) { + ret = state->DataChunkProcessorFunc(chunk, len, state); if (ret != MIME_DEC_OK) { SCLogDebug("Error: state->dataChunkProcessor() callback function" " failed"); @@ -1189,8 +1188,8 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, * \return Number of bytes pulled from the current buffer */ static uint8_t ProcessBase64Remainder(const uint8_t *buf, uint32_t len, - MimeDecParseState *state, int force) { - + MimeDecParseState *state, int force) +{ uint32_t ret; uint8_t remainder = 0, remdec = 0; @@ -1262,8 +1261,8 @@ static uint8_t ProcessBase64Remainder(const uint8_t *buf, uint32_t len, * \return MIME_DEC_OK on success, otherwise < 0 on failure */ static int ProcessBase64BodyLine(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; uint8_t rem1 = 0, rem2 = 0; uint32_t numDecoded, remaining, offset, avail, tobuf; @@ -1370,7 +1369,8 @@ static int ProcessBase64BodyLine(const uint8_t *buf, uint32_t len, * * \return byte value on success, -1 if failed **/ -static int16_t DecodeQPChar(char h) { +static int16_t DecodeQPChar(char h) +{ uint16_t res = 0; /* 0-9 */ @@ -1399,8 +1399,8 @@ static int16_t DecodeQPChar(char h) { * \return MIME_DEC_OK on success, otherwise < 0 on failure */ static int ProcessQuotedPrintableBodyLine(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; uint32_t remaining, offset; MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; @@ -1513,8 +1513,8 @@ static int ProcessQuotedPrintableBodyLine(const uint8_t *buf, uint32_t len, * \return MIME_DEC_OK on success, otherwise < 0 on failure */ static int ProcessBodyLine(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; uint32_t remaining, offset, avail, tobuf; MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; @@ -1597,8 +1597,8 @@ static int ProcessBodyLine(const uint8_t *buf, uint32_t len, * * \return Pointer to header name, or NULL if not found */ -static uint8_t * FindMimeHeaderStart(const uint8_t *buf, uint32_t blen, uint32_t *hlen) { - +static uint8_t * FindMimeHeaderStart(const uint8_t *buf, uint32_t blen, uint32_t *hlen) +{ uint32_t i, valid = 0; uint8_t *hname = NULL; @@ -1639,8 +1639,8 @@ static uint8_t * FindMimeHeaderStart(const uint8_t *buf, uint32_t blen, uint32_t * \return MIME_DEC_OK on success, otherwise < 0 on failure */ static int FindMimeHeader(const uint8_t *buf, uint32_t blen, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; uint8_t *hname, *hval = NULL; DataValue *dv; @@ -1746,7 +1746,6 @@ static int FindMimeHeader(const uint8_t *buf, uint32_t blen, /* If we need to finish a header, then do so below and then cleanup */ if (finish_header) { - /* Store the header value */ ret = StoreMimeHeader(state); if (ret != MIME_DEC_OK) { @@ -1757,7 +1756,6 @@ static int FindMimeHeader(const uint8_t *buf, uint32_t blen, /* When next header is found, we always create a new one */ if (new_header) { - /* Copy name and value to state */ state->hname = SCMalloc(hlen); if (unlikely(state->hname == NULL)) { @@ -1774,7 +1772,6 @@ static int FindMimeHeader(const uint8_t *buf, uint32_t blen, } if (hval != NULL) { - /* If max header value exceeded, flag it */ vlen = blen - (hval - buf); if ((mdcfg != NULL) && (state->hvlen + vlen > mdcfg->header_value_depth)) { @@ -1784,8 +1781,8 @@ static int FindMimeHeader(const uint8_t *buf, uint32_t blen, state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_VALUE; state->msg->anomaly_flags |= ANOM_LONG_HEADER_VALUE; } - if (vlen > 0) { + if (vlen > 0) { state->hvalue = AddDataValue(NULL); if (state->hvalue == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "AddDataValue() function failed"); @@ -1817,8 +1814,8 @@ static int FindMimeHeader(const uint8_t *buf, uint32_t blen, * \return A pointer to the token if found, otherwise NULL if not found */ static uint8_t * FindMimeHeaderToken(MimeDecField *field, char *search_start, - char *search_end, uint32_t *tlen) { - + char *search_end, uint32_t *tlen) +{ uint8_t *fptr, *tptr = NULL, *tok = NULL; SCLogDebug("Looking for token: %s", search_start); @@ -1848,8 +1845,8 @@ static uint8_t * FindMimeHeaderToken(MimeDecField *field, char *search_start, * \return MIME_DEC_OK on success, otherwise < 0 on failure */ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; MimeDecField *field; uint8_t *bptr = NULL, *rptr = NULL; @@ -1865,7 +1862,6 @@ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, /* Post-processing after all headers done */ if (state->state_flag == HEADER_DONE) { - /* First determine encoding by looking at Content-Transfer-Encoding */ field = MimeDecFindField(entity, CTNT_TRAN_STR); if (field != NULL) { @@ -1902,12 +1898,10 @@ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, /* Check for boundary, encapsulated message, and file name in Content-Type */ field = MimeDecFindField(entity, CTNT_TYPE_STR); if (field != NULL) { - /* Check if child entity boundary definition found */ bptr = FindMimeHeaderToken(field, BND_START_STR, TOK_END_STR, &blen); if (bptr != NULL) { state->found_child = 1; - entity->ctnt_flags |= CTNT_IS_MULTIPART; /* Store boundary in parent node */ @@ -1942,7 +1936,6 @@ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, entity->ctnt_type = GetToken(field->value, field->value_len, " \r\n;", &rptr, &entity->ctnt_type_len); if (entity->ctnt_type != NULL) { - /* Check for encapsulated message */ if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, (const uint8_t *)MSG_STR, strlen(MSG_STR))) @@ -2007,8 +2000,8 @@ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -static int ProcessBodyComplete(MimeDecParseState *state) { - +static int ProcessBodyComplete(MimeDecParseState *state) +{ int ret = MIME_DEC_OK; SCLogDebug("Process body complete called"); @@ -2051,8 +2044,8 @@ static int ProcessBodyComplete(MimeDecParseState *state) { * \return MIME_DEC_OK on success, otherwise < 0 on failure */ static int ProcessMimeBoundary(const uint8_t *buf, uint32_t len, uint32_t bdef_len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; uint8_t *rptr; MimeDecEntity *child; @@ -2104,7 +2097,6 @@ static int ProcessMimeBoundary(const uint8_t *buf, uint32_t len, uint32_t bdef_l /* Now check for end of nested boundary */ if (len - (rptr - buf) > 1 && rptr[0] == DASH && rptr[1] == DASH) { - SCLogDebug("FOUND END BOUNDARY, POPPING: %p=%p", state->stack->top, state->stack->top->data); @@ -2118,7 +2110,6 @@ static int ProcessMimeBoundary(const uint8_t *buf, uint32_t len, uint32_t bdef_l /* If current is an encapsulated message with a boundary definition, * then pop him as well */ if (state->stack->top->is_encap && state->stack->top->bdef_len != 0) { - SCLogDebug("FOUND END BOUNDARY AND ENCAP, POPPING: %p=%p", state->stack->top, state->stack->top->data); @@ -2172,7 +2163,6 @@ static int ProcessMimeBoundary(const uint8_t *buf, uint32_t len, uint32_t bdef_l } SCLogDebug("PROCESSING BOUNDARY - END: %d", state->state_flag); - return ret; } @@ -2186,8 +2176,8 @@ static int ProcessMimeBoundary(const uint8_t *buf, uint32_t len, uint32_t bdef_l * \return MIME_DEC_OK on success, otherwise < 0 on failure */ static int ProcessMimeBody(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; uint8_t temp[BOUNDARY_BUF]; uint8_t *bstart; @@ -2229,8 +2219,6 @@ static int ProcessMimeBody(const uint8_t *buf, uint32_t len, memcpy(temp, "--", 2); memcpy(temp + 2, node->bdef, node->bdef_len); -// SCLogDebug("Boundary to search: [%s]", temp); - /* Find either next boundary or end boundary */ bstart = FindBuffer((const uint8_t *)buf, len, temp, tlen); if (bstart != NULL) { @@ -2274,8 +2262,8 @@ static int ProcessMimeBody(const uint8_t *buf, uint32_t len, * \return MIME_DEC_OK on success, otherwise < 0 on failure */ static int ProcessMimeEntity(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; SCLogDebug("START FLAG: %s", StateFlags[state->state_flag]); @@ -2328,9 +2316,9 @@ static int ProcessMimeEntity(const uint8_t *buf, uint32_t len, * \return A pointer to the state object, or NULL if the operation fails */ MimeDecParseState * MimeDecInitParser(void *data, - int (*dcpfunc)(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state)) { - + int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state)) +{ MimeDecParseState *state; MimeDecEntity *mimeMsg; @@ -2371,7 +2359,7 @@ MimeDecParseState * MimeDecInitParser(void *data, state->stack->top->data = mimeMsg; state->state_flag = HEADER_READY; state->data = data; - state->dataChunkProcessor = dcpfunc; + state->DataChunkProcessorFunc = DataChunkProcessorFunc; return state; } @@ -2383,12 +2371,11 @@ MimeDecParseState * MimeDecInitParser(void *data, * * \return none */ -void MimeDecDeInitParser(MimeDecParseState *state) { - +void MimeDecDeInitParser(MimeDecParseState *state) +{ uint32_t cnt = 0; while (state->stack->top != NULL) { - SCLogDebug("Remaining on stack: [%p]=>[%p]", state->stack->top, state->stack->top->data); @@ -2418,8 +2405,8 @@ void MimeDecDeInitParser(MimeDecParseState *state) { * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ -int MimeDecParseComplete(MimeDecParseState *state) { - +int MimeDecParseComplete(MimeDecParseState *state) +{ int ret = MIME_DEC_OK; SCLogDebug("Parsing flagged as completed"); @@ -2475,8 +2462,8 @@ int MimeDecParseComplete(MimeDecParseState *state) { * \return MIME_DEC_OK on success, otherwise < 0 on failure */ int MimeDecParseLine(const uint8_t *line, const uint32_t len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ int ret = MIME_DEC_OK; /* For debugging purposes */ @@ -2509,8 +2496,8 @@ int MimeDecParseLine(const uint8_t *line, const uint32_t len, */ MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, int (*dcpfunc)(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state)) { - + MimeDecParseState *state)) +{ int ret = MIME_DEC_OK; uint8_t *remainPtr, *tok; uint32_t tokLen; @@ -2569,8 +2556,8 @@ MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *dat /* Helper body chunk callback function */ static int TestDataChunkCallback(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state) { - + MimeDecParseState *state) +{ uint32_t *line_count = (uint32_t *) state->data; if (state->body_begin) { @@ -2609,7 +2596,8 @@ static int TestDataChunkCallback(const uint8_t *chunk, uint32_t len, } /* Test simple case of line counts */ -static int MimeDecParseLineTest01(void) { +static int MimeDecParseLineTest01(void) +{ int ret = MIME_DEC_OK; uint32_t expected_count = 3; @@ -2672,7 +2660,8 @@ static int MimeDecParseLineTest01(void) { } /* Test simple case of EXE URL extraction */ -static int MimeDecParseLineTest02(void) { +static int MimeDecParseLineTest02(void) +{ int ret = MIME_DEC_OK; uint32_t expected_count = 2; @@ -2738,7 +2727,8 @@ static int MimeDecParseLineTest02(void) { } /* Test full message with linebreaks */ -static int MimeDecParseFullMsgTest01(void) { +static int MimeDecParseFullMsgTest01(void) +{ int ret = MIME_DEC_OK; uint32_t expected_count = 3; @@ -2770,8 +2760,8 @@ static int MimeDecParseFullMsgTest01(void) { return ret; } -static int MimeBase64DecodeTest01(void){ - +static int MimeBase64DecodeTest01(void) +{ int ret = -1; char *msg = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@" @@ -2792,7 +2782,8 @@ static int MimeBase64DecodeTest01(void){ return ret; } -static int MimeIsExeURLTest01(void){ +static int MimeIsExeURLTest01(void) +{ int ret = -1; char *url1 = "http://www.google.com/"; char *url2 = "http://www.google.com/test.exe"; @@ -2812,8 +2803,8 @@ static int MimeIsExeURLTest01(void){ return ret; } -static int MimeIsIpv4HostTest01(void) { - +static int MimeIsIpv4HostTest01(void) +{ if(IsIpv4Host((const uint8_t *)"192.168.1.1", 11) != 1) { return 1; } @@ -2841,8 +2832,8 @@ static int MimeIsIpv4HostTest01(void) { return 0; } -static int MimeIsIpv6HostTest01(void) { - +static int MimeIsIpv6HostTest01(void) +{ if(IsIpv6Host((const uint8_t *)"0:0:0:0:0:0:0:0", 19) != 1) { return 1; } @@ -2880,7 +2871,8 @@ static int MimeIsIpv6HostTest01(void) { #endif /* UNITTESTS */ -void MimeDecRegisterTests(void) { +void MimeDecRegisterTests(void) +{ #ifdef UNITTESTS UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01, 0); UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02, 0); diff --git a/src/mime-decode.h b/src/mime-decode.h index 20a8ce79f161..836c568e92f3 100644 --- a/src/mime-decode.h +++ b/src/mime-decode.h @@ -202,7 +202,7 @@ typedef struct MimeDecParseState { int body_begin; /**< Currently at beginning of body */ int body_end; /**< Currently at end of body */ void *data; /**< Pointer to data specific to the caller */ - int (*dataChunkProcessor) (const uint8_t *chunk, uint32_t len, + int (*DataChunkProcessorFunc) (const uint8_t *chunk, uint32_t len, struct MimeDecParseState *state); /**< Data chunk processing function callback */ } MimeDecParseState; @@ -232,7 +232,7 @@ void MimeDecDeInitParser(MimeDecParseState *state); int MimeDecParseComplete(MimeDecParseState *state); int MimeDecParseLine(const uint8_t *line, const uint32_t len, MimeDecParseState *state); MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, - int (*dcpfunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); + int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); /* Test functions */ void MimeDecRegisterTests(void); From 54df86658c13752474203562de05bc04a4143229 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 25 Oct 2014 17:44:57 +0200 Subject: [PATCH 0040/2553] mime: rename mime-decode.[ch] to util-decode-mime.[ch] --- src/Makefile.am | 2 +- src/app-layer-smtp.h | 2 +- src/log-file.c | 2 +- src/log-filestore.c | 2 +- src/suricata.c | 2 +- src/{mime-decode.c => util-decode-mime.c} | 2 +- src/{mime-decode.h => util-decode-mime.h} | 0 7 files changed, 6 insertions(+), 6 deletions(-) rename src/{mime-decode.c => util-decode-mime.c} (99%) rename src/{mime-decode.h => util-decode-mime.h} (100%) diff --git a/src/Makefile.am b/src/Makefile.am index 48d894803850..938c6acfa45c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -214,7 +214,6 @@ log-httplog.c log-httplog.h \ log-pcap.c log-pcap.h \ log-tcp-data.c log-tcp-data.h \ log-tlslog.c log-tlslog.h \ -mime-decode.c mime-decode.h \ output.c output.h \ output-file.c output-file.h \ output-filedata.c output-filedata.h \ @@ -308,6 +307,7 @@ util-debug-filters.c util-debug-filters.h \ util-decode-asn1.c util-decode-asn1.h \ util-decode-der.c util-decode-der.h \ util-decode-der-get.c util-decode-der-get.h \ +util-decode-mime.c util-decode-mime.h \ util-device.c util-device.h \ util-enum.c util-enum.h \ util-error.c util-error.h \ diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 94d8eb840484..cf11e7d02cfc 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -25,7 +25,7 @@ #define __APP_LAYER_SMTP_H__ #include "decode-events.h" -#include "mime-decode.h" +#include "util-decode-mime.h" enum { SMTP_DECODER_EVENT_INVALID_REPLY, diff --git a/src/log-file.c b/src/log-file.c index 92b066df544a..562f6ee0d6ad 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -56,7 +56,7 @@ #include "app-layer-htp.h" #include "app-layer-smtp.h" -#include "mime-decode.h" +#include "util-decode-mime.h" #include "util-memcmp.h" #include "stream-tcp-reassemble.h" diff --git a/src/log-filestore.c b/src/log-filestore.c index 109dabbbd149..5fb19a8411f4 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -54,7 +54,7 @@ #include "app-layer-htp.h" #include "app-layer-smtp.h" -#include "mime-decode.h" +#include "util-decode-mime.h" #include "util-memcmp.h" #include "stream-tcp-reassemble.h" diff --git a/src/suricata.c b/src/suricata.c index 853904f3a3c6..d0c084a76c39 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -152,7 +152,7 @@ #include "util-coredump-config.h" -#include "mime-decode.h" +#include "util-decode-mime.h" #include "defrag.h" diff --git a/src/mime-decode.c b/src/util-decode-mime.c similarity index 99% rename from src/mime-decode.c rename to src/util-decode-mime.c index 31d4bcb0acd3..4f43eda857f8 100644 --- a/src/mime-decode.c +++ b/src/util-decode-mime.c @@ -24,7 +24,7 @@ #include "suricata-common.h" -#include "mime-decode.h" +#include "util-decode-mime.h" #include "util-spm-bs.h" #include "util-unittest.h" diff --git a/src/mime-decode.h b/src/util-decode-mime.h similarity index 100% rename from src/mime-decode.h rename to src/util-decode-mime.h From f979e92f68d40f2fe5969507aebb408bf73f00bb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Oct 2014 09:18:31 +0100 Subject: [PATCH 0041/2553] decode mime: refactor & cleanup Partly to work around cppchecks: [src/util-decode-mime.c:1085]: (error) Memory leak: url --- src/util-decode-mime.c | 52 ++++++++++++++++++------------------------ src/util-decode-mime.h | 1 - 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 4f43eda857f8..1a45878f4c5c 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -348,7 +348,7 @@ MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name) { * \return URL entry or NULL if the operation fails * */ -MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity) +static MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity, uint8_t *url, uint32_t url_len, uint8_t flags) { MimeDecUrl *node = SCMalloc(sizeof(MimeDecUrl)); if (unlikely(node == NULL)) { @@ -357,17 +357,18 @@ MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity) } memset(node, 0x00, sizeof(MimeDecUrl)); - if (entity != NULL) { + node->url = url; + node->url_len = url_len; + node->url_flags = flags; - /* If list is empty, then set as head of list */ - if (entity->url_list == NULL) { - entity->url_list = node; - } else { - /* Otherwise add to beginning of list since these are out-of-order in - * the message */ - node->next = entity->url_list; - entity->url_list = node; - } + /* If list is empty, then set as head of list */ + if (entity->url_list == NULL) { + entity->url_list = node; + } else { + /* Otherwise add to beginning of list since these are out-of-order in + * the message */ + node->next = entity->url_list; + entity->url_list = node; } return node; @@ -1056,29 +1057,20 @@ static int FindUrlStrings(const uint8_t *line, uint32_t len, /* Make sure remaining URL exists */ if (tempUrlLen > 0) { + if (!(FindExistingUrl(entity, tempUrl, tempUrlLen))) { + /* Now look for numeric IP */ + if (IsIpv4Host(tempUrl, tempUrlLen)) { + flags |= URL_IS_IP4; - /* Now look for numeric IP */ - if (IsIpv4Host(tempUrl, tempUrlLen)) { - flags |= URL_IS_IP4; + PrintChars(SC_LOG_DEBUG, "IP URL4", tempUrl, tempUrlLen); + } else if (IsIpv6Host(tempUrl, tempUrlLen)) { + flags |= URL_IS_IP6; - PrintChars(SC_LOG_DEBUG, "IP URL4", tempUrl, tempUrlLen); - } else if (IsIpv6Host(tempUrl, tempUrlLen)) { - flags |= URL_IS_IP6; - - PrintChars(SC_LOG_DEBUG, "IP URL6", tempUrl, tempUrlLen); - } - - /* Update URL list */ - MimeDecUrl *url = FindExistingUrl(entity, tempUrl, tempUrlLen); - if (url == NULL) { + PrintChars(SC_LOG_DEBUG, "IP URL6", tempUrl, tempUrlLen); + } /* Add URL list item */ - url = MimeDecAddUrl(entity); - if (url != NULL) { - url->url = tempUrl; - url->url_len = tempUrlLen; - url->url_flags |= flags; - } + MimeDecAddUrl(entity, tempUrl, tempUrlLen, flags); } else { SCFree(tempUrl); } diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h index 836c568e92f3..0b3b2d22b115 100644 --- a/src/util-decode-mime.h +++ b/src/util-decode-mime.h @@ -218,7 +218,6 @@ void MimeDecFreeUrl(MimeDecUrl *url); /* List functions */ MimeDecField * MimeDecAddField(MimeDecEntity *entity); MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name); -MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity); MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent); /* Helper functions */ From cb4440324e5f59c70b2013c953dea1f9d51730ae Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Oct 2014 16:14:09 +0100 Subject: [PATCH 0042/2553] mime: redo PrintChars using PrintRawDataFp --- src/util-decode-mime.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 1a45878f4c5c..d8846d0073d0 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -29,6 +29,7 @@ #include "util-spm-bs.h" #include "util-unittest.h" #include "util-memcmp.h" +#include "util-print.h" /* Character constants */ #ifndef CR @@ -116,27 +117,12 @@ static const char *UrlExeExts[] = { ".exe", */ static void PrintChars(int log_level, char *label, const uint8_t *src, uint32_t len) { +#ifdef DEBUG if (log_level <= sc_log_global_log_level) { - - static uint32_t max_len = 100; - char tempbuf[max_len]; - - if (len == 0) { - SCLog(log_level, "PrintChars() - length is 0\n"); - } else { - uint32_t llen = strlen(label); - - /* Add label and source */ - int num = snprintf(tempbuf, llen +4 < max_len ? llen + 4 : max_len, "[%s] ", label); - size_t copy = len; - if ((len + num + 1) > max_len) - copy = max_len - (num + 1); - memcpy(tempbuf + num, src, copy); - tempbuf[copy] = '\0'; - - SCLog(log_level, "%s", tempbuf); - } + printf("[%s]\n", label); + PrintRawDataFp(stdout, (uint8_t *)src, len); } +#endif } /** @@ -2460,9 +2446,9 @@ int MimeDecParseLine(const uint8_t *line, const uint32_t len, /* For debugging purposes */ if (len > 0) { - PrintChars(SC_LOG_DEBUG, "\nSMTP LINE", line, len); + PrintChars(SC_LOG_DEBUG, "SMTP LINE", line, len); } else { - SCLogDebug("\nSMTP LINE - EMPTY"); + SCLogDebug("SMTP LINE - EMPTY"); } /* Process the entity */ From 56b74c8b5ba4c238ac9da6485fe293078ca71cda Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Oct 2014 23:57:56 +0100 Subject: [PATCH 0043/2553] smtp: make TX aware Store mime decoding context per transaction. For this the parser creates a TX when the mime body decoding starts. --- src/app-layer-smtp.c | 188 ++++++++++++++++++++++++++++++++++++++----- src/app-layer-smtp.h | 24 ++++-- src/log-file.c | 17 ++-- src/log-filestore.c | 15 ++-- 4 files changed, 207 insertions(+), 37 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index c0fecefc587d..4c414b4ea92e 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -54,6 +54,8 @@ #include "decode-events.h" #include "conf.h" +#include "util-mem.h" + #define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510 #define SMTP_COMMAND_BUFFER_STEPS 5 @@ -264,6 +266,17 @@ static void SMTPConfigure(void) { SCReturn; } +static SMTPTransaction *SMTPTransactionCreate(void) +{ + SMTPTransaction *tx = SCCalloc(1, sizeof(*tx)); + if (tx == NULL) { + return NULL; + } + + tx->mime_state = NULL; + return tx; +} + static int ProcessDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state) { @@ -350,7 +363,7 @@ static int ProcessDataChunk(const uint8_t *chunk, uint32_t len, /* Close file */ SCLogDebug("Closing file...%u bytes", len); - if (files->tail->state == FILE_STATE_OPENED) { + if (files && files->tail && files->tail->state == FILE_STATE_OPENED) { ret = FileCloseFile(files, (uint8_t *) chunk, len, flags); if (ret != 0) { SCLogDebug("FileCloseFile() failed: %d", ret); @@ -697,7 +710,7 @@ static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, if (smtp_config.decode_mime) { /* Complete parsing task */ - int ret = MimeDecParseComplete(state->mime_state); + int ret = MimeDecParseComplete(state->curr_tx->mime_state); if (ret != MIME_DEC_OK) { AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_PARSE_FAILED); @@ -705,7 +718,7 @@ static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, } /* Generate decoder events */ - MimeDecEntity *msg = state->mime_state->msg; + MimeDecEntity *msg = state->curr_tx->mime_state->msg; if (msg->anomaly_flags & ANOM_INVALID_BASE64) { AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_INVALID_BASE64); } @@ -736,7 +749,7 @@ static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, if (smtp_config.decode_mime) { int ret = MimeDecParseLine((const uint8_t *) state->current_line, - state->current_line_len, state->mime_state); + state->current_line_len, state->curr_tx->mime_state); if (ret != MIME_DEC_OK) { SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret); } @@ -911,26 +924,29 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, SCMemcmpLowercase("data", state->current_line, 4) == 0) { state->current_command = SMTP_COMMAND_DATA; + SMTPTransaction *tx = SMTPTransactionCreate(); + if (tx == NULL) + return -1; + state->curr_tx = tx; + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + tx->tx_id = state->tx_cnt++; + if (smtp_config.decode_mime) { - /* Re-init the MIME parser */ - if (state->mime_state != NULL) { - MimeDecDeInitParser(state->mime_state); - } - state->mime_state = MimeDecInitParser(f, ProcessDataChunk); - if (state->mime_state == NULL) { + tx->mime_state = MimeDecInitParser(f, ProcessDataChunk); + if (tx->mime_state == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to " "allocate data"); return MIME_DEC_ERR_MEM; } /* Add new MIME message to end of list */ - if (state->msg_head == NULL) { - state->msg_head = state->mime_state->msg; - state->msg_tail = state->mime_state->msg; + if (tx->msg_head == NULL) { + tx->msg_head = tx->mime_state->msg; + tx->msg_tail = tx->mime_state->msg; } else { - state->msg_tail->next = state->mime_state->msg; - state->msg_tail = state->mime_state->msg; + tx->msg_tail->next = tx->mime_state->msg; + tx->msg_tail = tx->mime_state->msg; } } @@ -1046,6 +1062,8 @@ static void *SMTPStateAlloc(void) } smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS; + TAILQ_INIT(&smtp_state->tx_list); + return smtp_state; } @@ -1072,6 +1090,14 @@ static void SMTPLocalStorageFree(void *pmq) return; } +static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state) +{ + if (tx->mime_state != NULL) { + MimeDecDeInitParser(tx->mime_state); + } + SCFree(tx); +} + /** * \internal * \brief Function to free SMTP state memory. @@ -1091,7 +1117,7 @@ static void SMTPStateFree(void *p) } FileContainerFree(smtp_state->files_ts); - +#if 0 /* Free MIME parser */ if (smtp_state->mime_state != NULL) { MimeDecDeInitParser(smtp_state->mime_state); @@ -1099,6 +1125,15 @@ static void SMTPStateFree(void *p) /* Free list of MIME message recursively */ MimeDecFreeEntity(smtp_state->msg_head); +#endif + + SMTPTransaction *tx = NULL; + while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) { + //SCLogInfo("TODO remove tx->tx_id %"PRIu64, tx->tx_id); + + TAILQ_REMOVE(&smtp_state->tx_list, tx, next); + SMTPTransactionFree(tx, smtp_state); + } SCFree(smtp_state); @@ -1170,6 +1205,115 @@ static int SMTPRegisterPatternsForProtocolDetection(void) return 0; } +static void SMTPStateTransactionFree (void *state, uint64_t tx_id) +{ + SCLogInfo("freeing tx %"PRIu64" from state %p", tx_id, state); +#if 0 + if (smtp_state->mime_state != NULL) { + MimeDecDeInitParser(smtp_state->mime_state); + } +#endif + SMTPState *smtp_state = state; + SMTPTransaction *tx = NULL; + TAILQ_FOREACH(tx, &smtp_state->tx_list, next) { + if (tx_id < tx->tx_id) + break; + else if (tx_id > tx->tx_id) + continue; + + if (tx == smtp_state->curr_tx) + smtp_state->curr_tx = NULL; +#if 0 + if (tx->decoder_events != NULL) { + if (tx->decoder_events->cnt <= smtp_state->events) + smtp_state->events -= tx->decoder_events->cnt; + else + smtp_state->events = 0; + } +#endif + TAILQ_REMOVE(&smtp_state->tx_list, tx, next); + SMTPTransactionFree(tx, state); + break; + } + + +} + +/** \todo slow */ +static uint64_t SMTPStateGetTxCnt(void *state) +{ + uint64_t cnt = 0; + SMTPState *smtp_state = state; + if (smtp_state) { + SMTPTransaction *tx = NULL; + + if (smtp_state->curr_tx == NULL) + return 0ULL; + + TAILQ_FOREACH(tx, &smtp_state->tx_list, next) { + cnt++; + } + } + SCLogDebug("returning %"PRIu64, cnt); + return cnt; +} + +static void *SMTPStateGetTx(void *state, uint64_t id) +{ + SMTPState *smtp_state = state; + if (smtp_state) { + SMTPTransaction *tx = NULL; + + if (smtp_state->curr_tx == NULL) + return NULL; + if (smtp_state->curr_tx->tx_id == id) + return smtp_state->curr_tx; + + TAILQ_FOREACH(tx, &smtp_state->tx_list, next) { + if (tx->tx_id == id) + return tx; + } + } + SCLogInfo("returning NULL"); + return NULL; + +} + +static int SMTPStateGetAlstateProgressCompletionStatus(uint8_t direction) { +// int status = (direction & STREAM_TOSERVER) ? PARSE_DONE : 0; +// SCLogInfo("returning %s", status ? "PARSE_DONE" : "0"); + return PARSE_DONE; +} + +static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction) +{ + SMTPTransaction *tx = vtx; + + if (direction & STREAM_TOSERVER) { + if (tx && tx->mime_state && tx->mime_state->state_flag == PARSE_DONE) { +// SCLogInfo("returning PARSE_DONE"); + return PARSE_DONE; + } else + return 0; + } else + return 1; +} + +static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction) +{ + if (state == NULL) + return NULL; + + SMTPState *smtp_state = (SMTPState *)state; + + if (direction & STREAM_TOCLIENT) { + SCReturnPtr(NULL, "FileContainer"); + } else { + SCLogDebug("smtp_state->files_ts %p", smtp_state->files_ts); + SCReturnPtr(smtp_state->files_ts, "FileContainer"); + } +} + /** * \brief Register the SMTP Protocol parser. */ @@ -1199,6 +1343,14 @@ void RegisterSMTPParsers(void) AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc, SMTPLocalStorageFree); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree); + AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetFiles); + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt); + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx); + AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_SMTP, + SMTPStateGetAlstateProgressCompletionStatus); } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); @@ -4271,7 +4423,7 @@ int SMTPParserTest14(void) if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->mime_state == NULL || smtp_state->msg_head == NULL || /* MIME data structures */ + smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state l.%d\n", __LINE__); @@ -4293,7 +4445,7 @@ int SMTPParserTest14(void) smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || - smtp_state->mime_state == NULL || smtp_state->msg_head == NULL || /* MIME data structures */ + smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state l.%d\n", __LINE__); goto end; diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index cf11e7d02cfc..8676d30b2cbe 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -26,6 +26,7 @@ #include "decode-events.h" #include "util-decode-mime.h" +#include "queue.h" enum { SMTP_DECODER_EVENT_INVALID_REPLY, @@ -49,7 +50,24 @@ enum { SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE, }; +typedef struct SMTPTransaction_ { + /** id of this tx, starting at 0 */ + uint64_t tx_id; + /** the first message contained in the session */ + MimeDecEntity *msg_head; + /** the last message contained in the session */ + MimeDecEntity *msg_tail; + /** the mime decoding parser state */ + MimeDecParseState *mime_state; + + TAILQ_ENTRY(SMTPTransaction_) next; +} SMTPTransaction; + typedef struct SMTPState_ { + SMTPTransaction *curr_tx; + TAILQ_HEAD(, SMTPTransaction_) tx_list; /**< transaction list */ + uint64_t tx_cnt; + /* current input that is being parsed */ uint8_t *input; int32_t input_len; @@ -103,12 +121,6 @@ typedef struct SMTPState_ { /* SMTP Mime decoding and file extraction */ /** the list of files sent to the server */ FileContainer *files_ts; - /** the first message contained in the session */ - MimeDecEntity *msg_head; - /** the last message contained in the session */ - MimeDecEntity *msg_tail; - /** the mime decoding parser state */ - MimeDecParseState *mime_state; } SMTPState; diff --git a/src/log-file.c b/src/log-file.c index 562f6ee0d6ad..439ca3227fe1 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -146,22 +146,25 @@ static void LogFileMetaGetUserAgent(FILE *fp, const Packet *p, const File *ff) fprintf(fp, ""); } -static void LogFileMetaGetSmtp(FILE *fp, const Packet *p, const File *ff) { - +static void LogFileMetaGetSmtp(FILE *fp, const Packet *p, const File *ff) +{ SMTPState *state = (SMTPState *) p->flow->alstate; - if (state != NULL && state->msg_tail != NULL) { + if (state != NULL) { + SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, state, ff->txid); + if (tx == NULL || tx->msg_tail == NULL) + return; /* Message Id */ - if (state->msg_tail->msg_id != NULL) { + if (tx->msg_tail->msg_id != NULL) { fprintf(fp, "\"message-id\": \""); - PrintRawJsonFp(fp, (uint8_t *) state->msg_tail->msg_id, - (int) state->msg_tail->msg_id_len); + PrintRawJsonFp(fp, (uint8_t *) tx->msg_tail->msg_id, + (int) tx->msg_tail->msg_id_len); fprintf(fp, "\", "); } /* Sender */ - MimeDecField *field = MimeDecFindField(state->msg_tail, "From"); + MimeDecField *field = MimeDecFindField(tx->msg_tail, "from"); if (field != NULL) { fprintf(fp, "\"sender\": \""); PrintRawJsonFp(fp, (uint8_t *) field->value, diff --git a/src/log-filestore.c b/src/log-filestore.c index 5fb19a8411f4..51ad673b9e05 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -141,20 +141,23 @@ static void LogFilestoreMetaGetUserAgent(FILE *fp, const Packet *p, const File * fprintf(fp, ""); } -static void LogFilestoreMetaGetSmtp(FILE *fp, const Packet *p, const File *ff) { - +static void LogFilestoreMetaGetSmtp(FILE *fp, const Packet *p, const File *ff) +{ SMTPState *state = (SMTPState *) p->flow->alstate; - if (state != NULL && state->msg_tail != NULL) { + if (state != NULL) { + SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, state, ff->txid); + if (tx == NULL || tx->msg_tail == NULL) + return; /* Message Id */ - if (state->msg_tail->msg_id != NULL) { + if (tx->msg_tail->msg_id != NULL) { fprintf(fp, "MESSAGE-ID: "); - PrintRawUriFp(fp, (uint8_t *) state->msg_tail->msg_id, state->msg_tail->msg_id_len); + PrintRawUriFp(fp, (uint8_t *) tx->msg_tail->msg_id, tx->msg_tail->msg_id_len); fprintf(fp, "\n"); } /* Sender */ - MimeDecField *field = MimeDecFindField(state->msg_tail, "From"); + MimeDecField *field = MimeDecFindField(tx->msg_tail, "from"); if (field != NULL) { fprintf(fp, "SENDER: "); PrintRawUriFp(fp, (uint8_t *) field->value, field->value_len); From d0357c6169553ee89e754653da0687c014fd4153 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Oct 2014 23:59:11 +0100 Subject: [PATCH 0044/2553] smtp: add file inspection engine Fix file inspection engine. TODO: test --- src/detect-engine-file.c | 19 ++++++++++++++++--- src/detect-engine.c | 7 +++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index 655adffcaad8..a16c382427c2 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -265,8 +265,7 @@ int DetectFileInspectSmtp(ThreadVars *tv, void *tx, uint64_t tx_id) { SCEnter(); - - int r = 0; + int r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; SMTPState *smtp_state = NULL; FileContainer *ffc; @@ -281,7 +280,21 @@ int DetectFileInspectSmtp(ThreadVars *tv, else goto end; - r = DetectFileInspect(tv, det_ctx, f, s, flags, ffc); + int match = DetectFileInspect(tv, det_ctx, f, s, flags, ffc); + if (match == 1) { + r = DETECT_ENGINE_INSPECT_SIG_MATCH; + } else if (match == 2) { + if (r != 1) { + SCLogDebug("sid %u can't match on this transaction", s->id); + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + } else if (match == 3) { + if (r != 1) { + SCLogDebug("sid %u can't match on this transaction (filestore sig)", s->id); + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; + } + } + end: SCReturnInt(r); diff --git a/src/detect-engine.c b/src/detect-engine.c index 6b80748fbecb..c3934397923a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -247,6 +247,13 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_DNSQUERY_INSPECT, 0, DetectEngineInspectDnsQueryName }, + { IPPROTO_TCP, + ALPROTO_SMTP, + DETECT_SM_LIST_FILEMATCH, + DE_STATE_FLAG_FILE_TS_INSPECT, + DE_STATE_FLAG_FILE_TS_INSPECT, + 0, + DetectFileInspectSmtp }, }; struct tmp_t data_toclient[] = { From 2b9ef8752738815ee070ac69de05adbfd2f2a787 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Oct 2014 23:59:49 +0100 Subject: [PATCH 0045/2553] smtp: convert logger to tx logger Move from packet logger to tx logger. --- src/output-json-email-common.c | 36 ++++++++++--------------- src/output-json-email-common.h | 2 +- src/output-json-smtp.c | 49 ++++++---------------------------- 3 files changed, 23 insertions(+), 64 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 019cc9436b0c..5b1e19f4199a 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -56,50 +56,39 @@ #include /* JSON format logging */ -static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, - json_t *js, - const Packet *p) +static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) { SMTPState *smtp_state; MimeDecParseState *mime_state; MimeDecEntity *entity; char *protos = NULL; - /* no flow, no smtp state */ - if (p->flow == NULL) { - SCReturnInt(TM_ECODE_FAILED); - } - json_t *sjs = json_object(); if (sjs == NULL) { SCReturnInt(TM_ECODE_FAILED); } /* check if we have SMTP state or not */ - FLOWLOCK_WRLOCK(p->flow); /* WRITE lock before we updated flow logged id */ AppProto proto = FlowGetAppProtocol(p->flow); switch (proto) { case ALPROTO_SMTP: - smtp_state = (SMTPState *)FlowGetAppState(p->flow); + smtp_state = (SMTPState *)state; if (smtp_state == NULL) { SCLogDebug("no smtp state, so no request logging"); - FLOWLOCK_UNLOCK(p->flow); SCReturnInt(TM_ECODE_FAILED); } - mime_state = smtp_state->mime_state; - entity = smtp_state->msg_tail; + SMTPTransaction *tx = vtx; + mime_state = tx->mime_state; + entity = tx->msg_tail; protos = "smtp"; + SCLogDebug("lets go mime_state %p, entity %p, state_flag %u", mime_state, entity, mime_state ? mime_state->state_flag : 0); break; default: /* don't know how we got here */ - FLOWLOCK_UNLOCK(p->flow); SCReturnInt(TM_ECODE_FAILED); } - if ((mime_state != NULL) && - (mime_state->state_flag == PARSE_DONE)) { - + if ((mime_state != NULL)) { if (entity == NULL) { - FLOWLOCK_UNLOCK(p->flow); SCReturnInt(TM_ECODE_FAILED); } @@ -176,6 +165,9 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, entity->header_flags |= HDR_IS_LOGGED; + if (mime_state->stack == NULL || mime_state->stack->top == NULL || mime_state->stack->top->data == NULL) + SCReturnInt(TM_ECODE_OK); + entity = (MimeDecEntity *)mime_state->stack->top->data; int attch_cnt = 0; int url_cnt = 0; @@ -233,16 +225,16 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, } json_object_set_new(js, protos, sjs); - FLOWLOCK_UNLOCK(p->flow); +// FLOWLOCK_UNLOCK(p->flow); SCReturnInt(TM_ECODE_OK); } } - FLOWLOCK_UNLOCK(p->flow); +// FLOWLOCK_UNLOCK(p->flow); SCReturnInt(TM_ECODE_DONE); } -int JsonEmailLogger(ThreadVars *tv, void *thread_data, const Packet *p) { +int JsonEmailLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) { SCEnter(); JsonEmailLogThread *jhl = (JsonEmailLogThread *)thread_data; MemBuffer *buffer = (MemBuffer *)jhl->buffer; @@ -254,7 +246,7 @@ int JsonEmailLogger(ThreadVars *tv, void *thread_data, const Packet *p) { /* reset */ MemBufferReset(buffer); - if (JsonEmailLogJson(jhl, js, p) == TM_ECODE_OK) { + if (JsonEmailLogJson(jhl, js, p, f, state, tx, tx_id) == TM_ECODE_OK) { OutputJSONBuffer(js, jhl->emaillog_ctx->file_ctx, buffer); } json_object_del(js, "smtp"); diff --git a/src/output-json-email-common.h b/src/output-json-email-common.h index b073d932b530..7a95954c77bd 100644 --- a/src/output-json-email-common.h +++ b/src/output-json-email-common.h @@ -35,6 +35,6 @@ typedef struct JsonEmailLogThread_ { MemBuffer *buffer; } JsonEmailLogThread; -int JsonEmailLogger(ThreadVars *tv, void *thread_data, const Packet *p); +int JsonEmailLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id); #endif /* __OUTPUT_JSON_EMAIL_COMMON_H__ */ diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 10b307b93e4b..f541ff891f0a 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -54,10 +54,10 @@ #ifdef HAVE_LIBJANSSON #include -static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p) +static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) { SCEnter(); - int r = JsonEmailLogger(tv, thread_data, p); + int r = JsonEmailLogger(tv, thread_data, p, f, state, tx, tx_id); SCReturnInt(r); } @@ -187,37 +187,6 @@ static TmEcode JsonSmtpLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -/** \internal - * \brief Condition function for SMTP logger - * \retval bool true or false -- log now? - */ -static int JsonSmtpCondition(ThreadVars *tv, const Packet *p) { - if (p->flow == NULL) { - return FALSE; - } - - if (!(PKT_IS_TCP(p))) { - return FALSE; - } - - FLOWLOCK_RDLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_SMTP) - goto dontlog; - - SMTPState *smtp_state = (SMTPState *)FlowGetAppState(p->flow); - if (smtp_state == NULL) { - SCLogDebug("no smtp state, so no request logging"); - goto dontlog; - } - - FLOWLOCK_UNLOCK(p->flow); - return TRUE; -dontlog: - FLOWLOCK_UNLOCK(p->flow); - return FALSE; -} - void TmModuleJsonSmtpLogRegister (void) { tmm_modules[TMM_JSONSMTPLOG].name = "JsonSmtpLog"; tmm_modules[TMM_JSONSMTPLOG].ThreadInit = JsonSmtpLogThreadInit; @@ -227,17 +196,15 @@ void TmModuleJsonSmtpLogRegister (void) { tmm_modules[TMM_JSONSMTPLOG].flags = TM_FLAG_LOGAPI_TM; /* register as separate module */ - OutputRegisterPacketModule("JsonSmtpLog", "smtp-json-log", - OutputSmtpLogInit, - JsonSmtpLogger, - JsonSmtpCondition); + OutputRegisterTxModule("JsonSmtpLog", "smtp-json-log", + OutputSmtpLogInit, ALPROTO_SMTP, + JsonSmtpLogger); /* also register as child of eve-log */ - OutputRegisterPacketSubModule("eve-log", "JsonSmtpLog", + OutputRegisterTxSubModule("eve-log", "JsonSmtpLog", "eve-log.smtp", - OutputSmtpLogInitSub, - JsonSmtpLogger, - JsonSmtpCondition); + OutputSmtpLogInitSub, ALPROTO_SMTP, + JsonSmtpLogger); } #else From 08b06bac3f8d155c3398f9881445d863cf04f781 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 28 Oct 2014 10:41:32 +0100 Subject: [PATCH 0046/2553] smtp: register file truncate callback Tag files as truncated from this callback so storing/logging displays the correct info. --- src/app-layer-smtp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 4c414b4ea92e..51d9730baa95 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1314,6 +1314,16 @@ static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction) } } +static void SMTPStateTruncate(void *state, uint8_t direction) +{ + FileContainer *fc = SMTPStateGetFiles(state, direction); + if (fc != NULL) { + SCLogDebug("truncating stream, closing files in %s direction (container %p)", + direction & STREAM_TOCLIENT ? "STREAM_TOCLIENT" : "STREAM_TOSERVER", fc); + FileTruncateAllOpenFiles(fc); + } +} + /** * \brief Register the SMTP Protocol parser. */ @@ -1351,6 +1361,7 @@ void RegisterSMTPParsers(void) AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx); AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgressCompletionStatus); + AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate); } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); From d67289b60e32436a6c351394096120fee0f9839f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 28 Oct 2014 10:45:21 +0100 Subject: [PATCH 0047/2553] output-filedata: close files even w/o data If there is no data chunk but the file is closed/truncated anyway, logging is still required. --- src/output-filedata.c | 54 ++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/output-filedata.c b/src/output-filedata.c index cd624437a09a..8f466bafc6a0 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -91,6 +91,32 @@ int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, Outpu SC_ATOMIC_DECLARE(unsigned int, file_id); +static int CallLoggers(ThreadVars *tv, OutputLoggerThreadStore *store_list, + Packet *p, const File *ff, const FileData *ffd, uint8_t flags) +{ + OutputFiledataLogger *logger = list; + OutputLoggerThreadStore *store = store_list; + int file_logged = 0; + + while (logger && store) { + BUG_ON(logger->LogFunc == NULL); + + SCLogDebug("logger %p", logger); + PACKET_PROFILING_TMM_START(p, logger->module_id); + logger->LogFunc(tv, store->thread_data, (const Packet *)p, ff, ffd, flags); + PACKET_PROFILING_TMM_END(p, logger->module_id); + + file_logged = 1; + + logger = logger->next; + store = store->next; + + BUG_ON(logger == NULL && store != NULL); + BUG_ON(logger != NULL && store == NULL); + } + return file_logged; +} + static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) { BUG_ON(thread_data == NULL); @@ -144,6 +170,14 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P continue; } + /* if we have no data chunks left to log, we should still + * close the logger(s) */ + if (ff->chunks_head == NULL && (file_trunc || file_close)) { + CallLoggers(tv, store, p, ff, NULL, OUTPUT_FILEDATA_FLAG_CLOSE); + ff->flags |= FILE_STORED; + continue; + } + FileData *ffd; for (ffd = ff->chunks_head; ffd != NULL; ffd = ffd->next) { uint8_t flags = 0; @@ -189,24 +223,8 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P if (ffd->next == NULL && ff->state >= FILE_STATE_CLOSED) flags |= OUTPUT_FILEDATA_FLAG_CLOSE; - logger = list; - store = op_thread_data->store; - while (logger && store) { - BUG_ON(logger->LogFunc == NULL); - - SCLogDebug("logger %p", logger); - PACKET_PROFILING_TMM_START(p, logger->module_id); - logger->LogFunc(tv, store->thread_data, (const Packet *)p, (const File *)ff, - (const FileData *)write_ffd, flags); - PACKET_PROFILING_TMM_END(p, logger->module_id); - file_logged = 1; - - logger = logger->next; - store = store->next; - - BUG_ON(logger == NULL && store != NULL); - BUG_ON(logger != NULL && store == NULL); - } + /* do the actual logging */ + file_logged = CallLoggers(tv, store, p, ff, write_ffd, flags); if (file_logged) { ffd->stored = 1; From d209699a4119774a99baf73d157bed97014fb4a6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 28 Oct 2014 17:45:52 +0100 Subject: [PATCH 0048/2553] smtp: expand tx use Instead of just using TX for mime decoding, it is now also used for tracking decoder events. --- src/app-layer-smtp.c | 138 +++++++++++++++++++++---------------------- src/app-layer-smtp.h | 3 + 2 files changed, 71 insertions(+), 70 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 51d9730baa95..c08ce7231579 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -266,6 +266,18 @@ static void SMTPConfigure(void) { SCReturn; } +void SMTPSetEvent(SMTPState *s, uint8_t e) +{ + SCLogDebug("setting event %u", e); + + if (s->curr_tx != NULL) { + AppLayerDecoderEventsSetEventRaw(&s->curr_tx->decoder_events, e); +// s->events++; + return; + } + SCLogDebug("couldn't set event %u", e); +} + static SMTPTransaction *SMTPTransactionCreate(void) { SMTPTransaction *tx = SCCalloc(1, sizeof(*tx)); @@ -652,8 +664,7 @@ static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) || (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) { /* decoder event */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE); + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE); /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP, * STARTTLS as the last command in pipelined mode */ } @@ -680,8 +691,7 @@ static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f, if (state->bdat_chunk_idx > state->bdat_chunk_len) { state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; /* decoder event */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED); + SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED); SCReturnInt(-1); } else if (state->bdat_chunk_idx == state->bdat_chunk_len) { state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; @@ -713,41 +723,43 @@ static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, int ret = MimeDecParseComplete(state->curr_tx->mime_state); if (ret != MIME_DEC_OK) { - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_PARSE_FAILED); + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED); SCLogDebug("MimeDecParseComplete() function failed"); } /* Generate decoder events */ MimeDecEntity *msg = state->curr_tx->mime_state->msg; if (msg->anomaly_flags & ANOM_INVALID_BASE64) { - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_INVALID_BASE64); + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64); } if (msg->anomaly_flags & ANOM_INVALID_QP) { - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_INVALID_QP); + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP); } if (msg->anomaly_flags & ANOM_LONG_LINE) { - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_LONG_LINE); + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE); } if (msg->anomaly_flags & ANOM_LONG_ENC_LINE) { - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE); + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE); } if (msg->anomaly_flags & ANOM_LONG_HEADER_NAME) { - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME); + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME); } if (msg->anomaly_flags & ANOM_LONG_HEADER_VALUE) { - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE); + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE); } if (msg->anomaly_flags & ANOM_MALFORMED_MSG) { - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG); + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG); } } + state->curr_tx->done = 1; + SCLogDebug("marked tx as done"); } /* If DATA, then parse out a MIME message */ if (state->current_command == SMTP_COMMAND_DATA && (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - if (smtp_config.decode_mime) { + if (smtp_config.decode_mime && state->curr_tx->mime_state) { int ret = MimeDecParseLine((const uint8_t *) state->current_line, state->current_line_len, state->curr_tx->mime_state); if (ret != MIME_DEC_OK) { @@ -777,8 +789,7 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, * reply code */ if (state->current_line_len < 3) { /* decoder event */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_INVALID_REPLY); + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); return -1; } @@ -806,8 +817,7 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, 3); if (mpm_cnt == 0) { /* set decoder event - reply code invalid */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_INVALID_REPLY); + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); SCLogDebug("invalid reply code %02x %02x %02x", state->current_line[0], state->current_line[1], state->current_line[2]); SCReturnInt(-1); @@ -820,7 +830,7 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, if (reply_code == SMTP_REPLY_220) SCReturnInt(0); else - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_INVALID_REPLY); + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); } else { /* decoder event - unable to match reply with request */ SCLogDebug("unable to match reply with request"); @@ -839,8 +849,7 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, APP_LAYER_PARSER_NO_REASSEMBLY); } else { /* decoder event */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_TLS_REJECTED); + SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED); } } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) { if (reply_code == SMTP_REPLY_354) { @@ -848,8 +857,7 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; } else { /* decoder event */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED); + SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED); } } else { /* we don't care for any other command for now */ @@ -907,9 +915,19 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, AppLayerParserState *pstate) { SCEnter(); + SMTPTransaction *tx = state->curr_tx; + + if (state->curr_tx == NULL || state->curr_tx->done) { + tx = SMTPTransactionCreate(); + if (tx == NULL) + return -1; + state->curr_tx = tx; + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + tx->tx_id = state->tx_cnt++; + } if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE); + SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE); } /* there are 2 commands that can push it into this COMMAND_DATA mode - @@ -923,14 +941,6 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, } else if (state->current_line_len >= 4 && SCMemcmpLowercase("data", state->current_line, 4) == 0) { state->current_command = SMTP_COMMAND_DATA; - - SMTPTransaction *tx = SMTPTransactionCreate(); - if (tx == NULL) - return -1; - state->curr_tx = tx; - TAILQ_INSERT_TAIL(&state->tx_list, tx, next); - tx->tx_id = state->tx_cnt++; - if (smtp_config.decode_mime) { tx->mime_state = MimeDecInitParser(f, ProcessDataChunk); if (tx->mime_state == NULL) { @@ -1095,6 +1105,18 @@ static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state) if (tx->mime_state != NULL) { MimeDecDeInitParser(tx->mime_state); } + /* Free list of MIME message recursively */ + MimeDecFreeEntity(tx->msg_head); + + if (tx->decoder_events != NULL) { + AppLayerDecoderEventsFreeEvents(&tx->decoder_events); +#if 0 + if (tx->decoder_events->cnt <= smtp_state->events) + smtp_state->events -= tx->decoder_events->cnt; + else + smtp_state->events = 0; +#endif + } SCFree(tx); } @@ -1117,20 +1139,9 @@ static void SMTPStateFree(void *p) } FileContainerFree(smtp_state->files_ts); -#if 0 - /* Free MIME parser */ - if (smtp_state->mime_state != NULL) { - MimeDecDeInitParser(smtp_state->mime_state); - } - - /* Free list of MIME message recursively */ - MimeDecFreeEntity(smtp_state->msg_head); -#endif SMTPTransaction *tx = NULL; while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) { - //SCLogInfo("TODO remove tx->tx_id %"PRIu64, tx->tx_id); - TAILQ_REMOVE(&smtp_state->tx_list, tx, next); SMTPTransactionFree(tx, smtp_state); } @@ -1179,7 +1190,7 @@ int SMTPStateGetEventInfo(const char *event_name, return -1; } - *event_type = APP_LAYER_EVENT_TYPE_GENERAL; + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; return 0; } @@ -1207,12 +1218,6 @@ static int SMTPRegisterPatternsForProtocolDetection(void) static void SMTPStateTransactionFree (void *state, uint64_t tx_id) { - SCLogInfo("freeing tx %"PRIu64" from state %p", tx_id, state); -#if 0 - if (smtp_state->mime_state != NULL) { - MimeDecDeInitParser(smtp_state->mime_state); - } -#endif SMTPState *smtp_state = state; SMTPTransaction *tx = NULL; TAILQ_FOREACH(tx, &smtp_state->tx_list, next) { @@ -1223,14 +1228,6 @@ static void SMTPStateTransactionFree (void *state, uint64_t tx_id) if (tx == smtp_state->curr_tx) smtp_state->curr_tx = NULL; -#if 0 - if (tx->decoder_events != NULL) { - if (tx->decoder_events->cnt <= smtp_state->events) - smtp_state->events -= tx->decoder_events->cnt; - else - smtp_state->events = 0; - } -#endif TAILQ_REMOVE(&smtp_state->tx_list, tx, next); SMTPTransactionFree(tx, state); break; @@ -1274,29 +1271,18 @@ static void *SMTPStateGetTx(void *state, uint64_t id) return tx; } } - SCLogInfo("returning NULL"); return NULL; } static int SMTPStateGetAlstateProgressCompletionStatus(uint8_t direction) { -// int status = (direction & STREAM_TOSERVER) ? PARSE_DONE : 0; -// SCLogInfo("returning %s", status ? "PARSE_DONE" : "0"); - return PARSE_DONE; + return 1; } static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction) { SMTPTransaction *tx = vtx; - - if (direction & STREAM_TOSERVER) { - if (tx && tx->mime_state && tx->mime_state->state_flag == PARSE_DONE) { -// SCLogInfo("returning PARSE_DONE"); - return PARSE_DONE; - } else - return 0; - } else - return 1; + return tx->done; } static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction) @@ -1324,6 +1310,17 @@ static void SMTPStateTruncate(void *state, uint8_t direction) } } +static AppLayerDecoderEvents *SMTPGetEvents(void *state, uint64_t tx_id) +{ + SCLogDebug("get SMTP events for TX %"PRIu64, tx_id); + + SMTPTransaction *tx = SMTPStateGetTx(state, tx_id); + if (tx != NULL) { + return tx->decoder_events; + } + return NULL; +} + /** * \brief Register the SMTP Protocol parser. */ @@ -1350,6 +1347,7 @@ void RegisterSMTPParsers(void) SMTPParseServerRecord); AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo); + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents); AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc, SMTPLocalStorageFree); diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 8676d30b2cbe..d5e936a93849 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -53,6 +53,7 @@ enum { typedef struct SMTPTransaction_ { /** id of this tx, starting at 0 */ uint64_t tx_id; + int done; /** the first message contained in the session */ MimeDecEntity *msg_head; /** the last message contained in the session */ @@ -60,6 +61,8 @@ typedef struct SMTPTransaction_ { /** the mime decoding parser state */ MimeDecParseState *mime_state; + AppLayerDecoderEvents *decoder_events; /**< per tx events */ + TAILQ_ENTRY(SMTPTransaction_) next; } SMTPTransaction; From 9d33131d37f633a1ab67e69df5857eec19e45126 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 28 Oct 2014 18:25:33 +0100 Subject: [PATCH 0049/2553] smtp: improve ProcessDataChunk error checking --- src/app-layer-smtp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index c08ce7231579..e58eccb0d44e 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -366,6 +366,7 @@ static int ProcessDataChunk(const uint8_t *chunk, uint32_t len, ret = FileCloseFile(files, (uint8_t *) NULL, 0, flags); if (ret != 0) { SCLogDebug("FileCloseFile() failed: %d", ret); + ret = MIME_DEC_ERR_DATA; } } else { SCLogDebug("File already closed"); @@ -379,6 +380,7 @@ static int ProcessDataChunk(const uint8_t *chunk, uint32_t len, ret = FileCloseFile(files, (uint8_t *) chunk, len, flags); if (ret != 0) { SCLogDebug("FileCloseFile() failed: %d", ret); + ret = MIME_DEC_ERR_DATA; } } else { SCLogDebug("File already closed"); @@ -394,10 +396,11 @@ static int ProcessDataChunk(const uint8_t *chunk, uint32_t len, SCLogDebug("FileAppendData() - file no longer being extracted"); } else if (ret < 0) { SCLogDebug("FileAppendData() failed: %d", ret); + ret = MIME_DEC_ERR_DATA; } } - if (ret == MIME_DEC_OK) { + if (ret == 0) { SCLogDebug("Successfully processed file data!"); } } else { From 5461294a5208382ce57a34658f4d6802677c39a7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 28 Oct 2014 18:26:38 +0100 Subject: [PATCH 0050/2553] smtp: fix SMTPParserTest14 on 32bit --- src/app-layer-smtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index e58eccb0d44e..88b4f605ddd9 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -4473,7 +4473,7 @@ int SMTPParserTest14(void) goto end; } if(file->size != filesize){ - printf("smtp-mime file size %lu is incorrect", file->size); + printf("smtp-mime file size %"PRIu64" is incorrect", file->size); goto end; } static uint8_t org_binary[] = { From 20a175f3155a1d53dfc4967f23c34b5781c39ded Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 28 Oct 2014 18:56:28 +0100 Subject: [PATCH 0051/2553] mime: improve error checking --- src/util-decode-mime.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index d8846d0073d0..410c243d577c 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -408,6 +408,9 @@ MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent) static MimeDecField * MimeDecFillField(MimeDecEntity *entity, uint8_t *name, uint32_t nlen, const uint8_t *value, uint32_t vlen) { + if (nlen == 0 && vlen == 0) + return NULL; + MimeDecField *field = MimeDecAddField(entity); if (unlikely(field == NULL)) { return NULL; @@ -1924,6 +1927,8 @@ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, /* Create and push child to stack */ MimeDecEntity *child = MimeDecAddEntity(entity); + if (child == NULL) + return MIME_DEC_ERR_MEM; child->ctnt_flags |= (CTNT_IS_ENCAP | CTNT_IS_MSG); PushStack(state->stack); state->stack->top->data = child; @@ -2105,6 +2110,8 @@ static int ProcessMimeBoundary(const uint8_t *buf, uint32_t len, uint32_t bdef_l /* Create and push child to stack */ child = MimeDecAddEntity(state->stack->top->data); + if (child == NULL) + return MIME_DEC_ERR_MEM; child->ctnt_flags |= CTNT_IS_BODYPART; PushStack(state->stack); state->stack->top->data = child; @@ -2130,6 +2137,8 @@ static int ProcessMimeBoundary(const uint8_t *buf, uint32_t len, uint32_t bdef_l /* Create and push child to stack */ child = MimeDecAddEntity(state->stack->top->data); + if (child == NULL) + return MIME_DEC_ERR_MEM; child->ctnt_flags |= CTNT_IS_BODYPART; PushStack(state->stack); state->stack->top->data = child; From ebd6737b658d2f7af5d9053c44f421806fc43431 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 28 Oct 2014 20:03:32 +0100 Subject: [PATCH 0052/2553] mime: fix compiler warning --- src/util-decode-mime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 410c243d577c..4e3035bb38f1 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -2570,7 +2570,7 @@ static int TestDataChunkCallback(const uint8_t *chunk, uint32_t len, } } while (tok != NULL && tok != remainPtr && - remainPtr - (uint8_t *) chunk < len); + (uint32_t)(remainPtr - (uint8_t *) chunk) < len); SCLogDebug("line count (len=%u): %u", len, *line_count); } From 9d2a0c39e543d35c81cd66c5bd424750a938e888 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 30 Oct 2014 18:23:15 +0100 Subject: [PATCH 0053/2553] mime: fix output issues When multiple email addresses were in the 'to' field, sometimes they would be logged as "\r\n \"Name\" ". The \r\n was added by GetFullValue in the mime decoder, for unknown reasons. Disabling this seems to have no drawbacks. --- src/util-decode-mime.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 4e3035bb38f1..187740ea874b 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -608,10 +608,12 @@ static uint8_t * GetFullValue(DataValue *dv, uint32_t *len) while (curr != NULL) { *len += curr->value_len; +#if 0 /* Add CRLF except on last one */ if (curr->next != NULL) { *len += 2; } +#endif curr = curr->next; } @@ -629,11 +631,13 @@ static uint8_t * GetFullValue(DataValue *dv, uint32_t *len) memcpy(val + offset, curr->value, curr->value_len); offset += curr->value_len; +#if 0 /* VJ unclear why this is needed ? */ /* Add CRLF except on last one */ if (curr->next != NULL) { memcpy(val + offset, CRLF, 2); offset += 2; } +#endif curr = curr->next; } } From f7c2c219cd4b268a4bbb105dbd14e1d0b36b8ea0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 31 Oct 2014 13:41:39 +0100 Subject: [PATCH 0054/2553] filestore: fix crash if keyword setup fails SigMatch would be added to list, then the alproto check failed, leading to freeing of sm. But as it was still in the list, the list now contained a dangling pointer. --- src/detect-filestore.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect-filestore.c b/src/detect-filestore.c index e88c95eeb688..f16fc4aa1edd 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -411,9 +411,6 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *st sm->ctx = NULL; } - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - s->filestore_sm = sm; - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; @@ -423,6 +420,9 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *st AppLayerHtpNeedFileInspection(); } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + s->filestore_sm = sm; + s->flags |= SIG_FLAG_FILESTORE; return 0; From 7c3b22da22d917104e266430c86d5b8b936d94ae Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 31 Oct 2014 14:53:38 +0100 Subject: [PATCH 0055/2553] smtp: don't create a new tx for rset/quit A tx is considered complete after the data command completed. However, this would lead to RSET and QUIT commands setting up a new tx. This patch simply adds a check that refuses to setup a new tx when these commands are encountered after the data portion is complete. --- src/app-layer-smtp.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 88b4f605ddd9..414a6e6721b6 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -914,13 +914,28 @@ static int SMTPParseCommandBDAT(SMTPState *state) return 0; } +/* consider 'rset' and 'quit' to be part of the existing state */ +static int NoNewTx(SMTPState *state) +{ + if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + if (state->current_line_len >= 4 && + SCMemcmpLowercase("rset", state->current_line, 4) == 0) { + return 1; + } else if (state->current_line_len >= 4 && + SCMemcmpLowercase("quit", state->current_line, 4) == 0) { + return 1; + } + } + return 0; +} + static int SMTPProcessRequest(SMTPState *state, Flow *f, AppLayerParserState *pstate) { SCEnter(); SMTPTransaction *tx = state->curr_tx; - if (state->curr_tx == NULL || state->curr_tx->done) { + if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state))) { tx = SMTPTransactionCreate(); if (tx == NULL) return -1; From 27007cc7d5c559d12bb15018f43a8006b6bffeca Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 31 Oct 2014 14:56:14 +0100 Subject: [PATCH 0056/2553] Fix Coverity issue in SMTP output ** CID 1250327: Uninitialized pointer read (UNINIT) /src/output-json-email-common.c: 117 in JsonEmailLogJson() /src/output-json-email-common.c: 139 in JsonEmailLogJson() --- src/output-json-email-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 5b1e19f4199a..f12a0e181227 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -114,7 +114,7 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packe if (field != NULL) { json_t *js_to = json_array(); if (likely(js_to != NULL)) { - char *savep; + char *savep = NULL; char *p; to_line = BytesToString((uint8_t *)field->value, (size_t)field->value_len); @@ -136,7 +136,7 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packe if (field != NULL) { json_t *js_cc = json_array(); if (likely(js_cc != NULL)) { - char *savep; + char *savep = NULL; char *p; cc_line = BytesToString((uint8_t *)field->value, (size_t)field->value_len); From 6c2ae469be6a79b1405ca793f15c74c0fba0e3a8 Mon Sep 17 00:00:00 2001 From: Christophe M Date: Tue, 29 Jul 2014 16:20:34 +0200 Subject: [PATCH 0057/2553] Fix to output a JSON buffer to an Unix domain socket. Create the JSON buffer and write to it like regular file. Upper function SCConfLogOpenGeneric already handle it properly. Closes issue #1246. --- src/output-json.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index b37e9ad1733d..69ea7cf19141 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -347,7 +347,7 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) SCMutexLock(&file_ctx->fp_mutex); if (json_out == ALERT_SYSLOG) { syslog(alert_syslog_level, "%s", js_s); - } else if (json_out == ALERT_FILE) { + } else if (json_out == ALERT_FILE || json_out == ALERT_UNIX_DGRAM || json_out == ALERT_UNIX_STREAM) { MemBufferWriteString(buffer, "%s\n", js_s); file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), MEMBUFFER_OFFSET(buffer), file_ctx); @@ -457,7 +457,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) } } - if (json_ctx->json_out == ALERT_FILE) { + if (json_ctx->json_out == ALERT_FILE || json_ctx->json_out == ALERT_UNIX_DGRAM || json_ctx->json_out == ALERT_UNIX_STREAM) { if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME) < 0) { LogFileFreeCtx(json_ctx->file_ctx); From 0b28943487424f4831072a7161b33ebb5fc22211 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Nov 2014 10:39:53 +0100 Subject: [PATCH 0058/2553] Update Changelog for 2.1beta2 release --- ChangeLog | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8e3cb6766f34..720e846fdd7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2.1beta2 -- 2014-11-06 + +Feature #549: Extract file attachments from emails +Feature #1312: Lua output support +Feature #899: MPLS over Ethernet support +Feature #707: ip reputation files - network range inclusion availability (cidr) +Feature #383: Stream logging +Feature #1263: Lua: Access to Stream Payloads +Feature #1264: Lua: access to TCP quad / Flow Tuple +Bug #1048: PF_RING/DNA config - suricata.yaml +Bug #1230: byte_extract, within combination not working +Bug #1257: Flow switch is missing from the eve-log section in suricata.yaml +Bug #1259: AF_PACKET IPS is broken in 2.1beta1 +Bug #1260: flow logging at shutdown broken +Bug #1279: BUG: NULL pointer dereference when suricata was debug mode. +Bug #1280: BUG: IPv6 address vars issue +Bug #1285: Lua - http.request_line not working (2.1) +Bug #1287: Lua Output has dependency on eve-log:http +Bug #1288: Filestore keyword in wrong place will cause entire rule not to trigger +Bug #1294: Configure doesn't use --with-libpcap-libraries when testing PF_RING library +Bug #1301: suricata yaml - PF_RING load balance per hash option +Bug #1308: http_header keyword not matching when SYN|ACK and ACK missing (master) +Bug #1311: EVE output Unix domain socket not working (2.1) + 2.1beta1 -- 2014-08-12 Feature #1155: Log packet payloads in eve alerts From 5a0409959f418027b41f5c75f30d3b03cc9dab14 Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Wed, 23 Jul 2014 11:12:59 +0200 Subject: [PATCH 0059/2553] App-layer: Add Modbus protocol parser Decode Modbus request and response messages, and extracts MODBUS Application Protocol header and the code function. In case of read/write function, extracts message contents (read/write address, quantity, count, data to write). Links request and response messages in a transaction according to Transaction Identifier (transaction management based on DNS source code). MODBUS Messaging on TCP/IP Implementation Guide V1.0b (http://www.modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf) MODBUS Application Protocol Specification V1.1b3 (http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf) Based on DNS source code. Signed-off-by: David DIALLO --- Makefile.am | 1 + rules/Makefile.am | 1 + rules/modbus-events.rules | 18 + src/Makefile.am | 1 + src/app-layer-modbus.c | 2401 +++++++++++++++++++++++++++++++++++++ src/app-layer-modbus.h | 128 ++ src/app-layer-parser.c | 2 + src/app-layer-protos.h | 1 + src/util-error.c | 1 + src/util-error.h | 1 + suricata.yaml.in | 16 + 11 files changed, 2571 insertions(+) create mode 100644 rules/modbus-events.rules create mode 100644 src/app-layer-modbus.c create mode 100644 src/app-layer-modbus.h diff --git a/Makefile.am b/Makefile.am index 5e534ee07bc7..d6c72ef21153 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,6 +41,7 @@ endif @test -e "$(e_sysconfrulesdir)smtp-events.rules" || install -m 600 "$(top_srcdir)/rules/smtp-events.rules" "$(e_sysconfrulesdir)" @test -e "$(e_sysconfrulesdir)http-events.rules" || install -m 600 "$(top_srcdir)/rules/http-events.rules" "$(e_sysconfrulesdir)" @test -e "$(e_sysconfrulesdir)dns-events.rules" || install -m 600 "$(top_srcdir)/rules/dns-events.rules" "$(e_sysconfrulesdir)" + @test -e "$(e_sysconfrulesdir)modbus-events.rules" || install -m 600 "$(top_srcdir)/rules/modbus-events.rules" "$(e_sysconfrulesdir)" @echo "" @echo "You can now start suricata by running as root something like '$(bindir)/suricata -c $(e_sysconfdir)/suricata.yaml -i eth0'." @echo "" diff --git a/rules/Makefile.am b/rules/Makefile.am index bb11b919f186..cd3404336817 100644 --- a/rules/Makefile.am +++ b/rules/Makefile.am @@ -5,4 +5,5 @@ smtp-events.rules \ http-events.rules \ dns-events.rules \ tls-events.rules \ +modbus-events.rules \ files.rules diff --git a/rules/modbus-events.rules b/rules/modbus-events.rules new file mode 100644 index 000000000000..f87997150c63 --- /dev/null +++ b/rules/modbus-events.rules @@ -0,0 +1,18 @@ +# Modbus Protocol version field is incorrect (Modbus version = 0) +alert modbus any any -> any any (msg:"SURICATA Modbus invalid Protocol version"; app-layer-event:modbus.invalid_protocol_id; sid:2250001; rev:1;) +# Response (answer) we didn't see a Request for. Could be packet loss. +alert modbus any any -> any any (msg:"SURICATA Modbus unsolicited response"; app-layer-event:modbus.unsolicited_response; sid:2250002; rev:1;) +# Malformed request or response. Malformed means length field is wrong +alert modbus any any -> any any (msg:"SURICATA Modbus invalid Length"; app-layer-event:modbus.invalid_length; sid:2250003; rev:1;) +# Unit identifier field is incorrect +alert modbus any any -> any any (msg:"SURICATA Modbus invalid Unit Identifier"; app-layer-event:modbus.invalid_unit_identifier; sid:2250004; rev:1;) +# Modbus Function code is incorrect +alert modbus any any -> any any (msg:"SURICATA Modbus invalid Function code"; app-layer-event:modbus.invalid_function_code; sid:2250005; rev:1;) +# Modbus Request/Response value field is incorrect +alert modbus any any -> any any (msg:"SURICATA Modbus invalid Value"; app-layer-event:modbus.invalid_value; sid:2250006; rev:1;) +# Modbus Expception code is incorrect +alert modbus any any -> any any (msg:"SURICATA Modbus Exception code invalid"; flow:to_client; app-layer-event:modbus.invalid_exception_code; sid:2250007; rev:1;) +# Value field in Modbus Response does not match with Modbus Request +alert modbus any any -> any any (msg:"SURICATA Modbus Data mismatch"; flow:to_client; app-layer-event:modbus.value_mismatch; sid:2250008; rev:1;) +# Request Flood Detected +alert modbus any any -> any any (msg:"SURICATA Modbus Request flood detected"; flow:to_server; app-layer-event:modbus.flooded; sid:2250009; rev:1;) diff --git a/src/Makefile.am b/src/Makefile.am index 938c6acfa45c..5b2b3cc88769 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,6 +26,7 @@ app-layer-htp.c app-layer-htp.h \ app-layer-htp-file.c app-layer-htp-file.h \ app-layer-htp-libhtp.c app-layer-htp-libhtp.h \ app-layer-htp-mem.c app-layer-htp-mem.h \ +app-layer-modbus.c app-layer-modbus.h \ app-layer-parser.c app-layer-parser.h \ app-layer-protos.c app-layer-protos.h \ app-layer-smb2.c app-layer-smb2.h \ diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c new file mode 100644 index 000000000000..7d23bcacc402 --- /dev/null +++ b/src/app-layer-modbus.c @@ -0,0 +1,2401 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author David DIALLO + * + * App-layer parser for Modbus protocol + * + */ + +#include "suricata-common.h" + +#include "util-debug.h" +#include "util-byte.h" +#include "util-enum.h" +#include "util-mem.h" +#include "util-misc.h" + +#include "stream.h" + +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer-modbus.h" + +#include "app-layer-detect-proto.h" + +#include "conf.h" +#include "decode.h" + +SCEnumCharMap modbus_decoder_event_table[ ] = { + /* Modbus Application Data Unit messages - ADU Modbus */ + { "INVALID_PROTOCOL_ID", MODBUS_DECODER_EVENT_INVALID_PROTOCOL_ID }, + { "UNSOLICITED_RESPONSE", MODBUS_DECODER_EVENT_UNSOLICITED_RESPONSE }, + { "INVALID_LENGTH", MODBUS_DECODER_EVENT_INVALID_LENGTH }, + { "INVALID_UNIT_IDENTIFIER", MODBUS_DECODER_EVENT_INVALID_UNIT_IDENTIFIER}, + + /* Modbus Protocol Data Unit messages - PDU Modbus */ + { "INVALID_FUNCTION_CODE", MODBUS_DECODER_EVENT_INVALID_FUNCTION_CODE }, + { "INVALID_VALUE", MODBUS_DECODER_EVENT_INVALID_VALUE }, + { "INVALID_EXCEPTION_CODE", MODBUS_DECODER_EVENT_INVALID_EXCEPTION_CODE }, + { "VALUE_MISMATCH", MODBUS_DECODER_EVENT_VALUE_MISMATCH }, + + /* Modbus Decoder event */ + { "FLOODED", MODBUS_DECODER_EVENT_FLOODED}, + { NULL, -1 }, +}; + +/* Modbus Application Data Unit (ADU) length range. */ +#define MODBUS_MIN_ADU_LEN 2 +#define MODBUS_MAX_ADU_LEN 254 + +/* Modbus Protocol version. */ +#define MODBUS_PROTOCOL_VER 0 + +/* Modbus Unit Identifier range. */ +#define MODBUS_MIN_INVALID_UNIT_ID 247 +#define MODBUS_MAX_INVALID_UNIT_ID 255 + +/* Modbus Quantity range. */ +#define MODBUS_MIN_QUANTITY 0 +#define MODBUS_MAX_QUANTITY_IN_BIT_ACCESS 2000 +#define MODBUS_MAX_QUANTITY_IN_WORD_ACCESS 125 + +/* Modbus Count range. */ +#define MODBUS_MIN_COUNT 1 +#define MODBUS_MAX_COUNT 250 + +/* Modbus Function Code. */ +#define MODBUS_FUNC_NONE 0x00 +#define MODBUS_FUNC_READCOILS 0x01 +#define MODBUS_FUNC_READDISCINPUTS 0x02 +#define MODBUS_FUNC_READHOLDREGS 0x03 +#define MODBUS_FUNC_READINPUTREGS 0x04 +#define MODBUS_FUNC_WRITESINGLECOIL 0x05 +#define MODBUS_FUNC_WRITESINGLEREG 0x06 +#define MODBUS_FUNC_READEXCSTATUS 0x07 +#define MODBUS_FUNC_DIAGNOSTIC 0x08 +#define MODBUS_FUNC_GETCOMEVTCOUNTER 0x0b +#define MODBUS_FUNC_GETCOMEVTLOG 0x0c +#define MODBUS_FUNC_WRITEMULTCOILS 0x0f +#define MODBUS_FUNC_WRITEMULTREGS 0x10 +#define MODBUS_FUNC_REPORTSERVERID 0x11 +#define MODBUS_FUNC_READFILERECORD 0x14 +#define MODBUS_FUNC_WRITEFILERECORD 0x15 +#define MODBUS_FUNC_MASKWRITEREG 0x16 +#define MODBUS_FUNC_READWRITEMULTREGS 0x17 +#define MODBUS_FUNC_READFIFOQUEUE 0x18 +#define MODBUS_FUNC_ENCAPINTTRANS 0x2b +#define MODBUS_FUNC_MASK 0x7f +#define MODBUS_FUNC_ERRORMASK 0x80 + +/* Modbus Diagnostic functions: Subfunction Code. */ +#define MODBUS_SUBFUNC_QUERY_DATA 0x00 +#define MODBUS_SUBFUNC_RESTART_COM 0x01 +#define MODBUS_SUBFUNC_DIAG_REGS 0x02 +#define MODBUS_SUBFUNC_CHANGE_DELIMITER 0x03 +#define MODBUS_SUBFUNC_LISTEN_MODE 0x04 +#define MODBUS_SUBFUNC_CLEAR_REGS 0x0a +#define MODBUS_SUBFUNC_BUS_MSG_COUNT 0x0b +#define MODBUS_SUBFUNC_COM_ERR_COUNT 0x0c +#define MODBUS_SUBFUNC_EXCEPT_ERR_COUNT 0x0d +#define MODBUS_SUBFUNC_SERVER_MSG_COUNT 0x0e +#define MODBUS_SUBFUNC_SERVER_NO_RSP_COUNT 0x0f +#define MODBUS_SUBFUNC_SERVER_NAK_COUNT 0x10 +#define MODBUS_SUBFUNC_SERVER_BUSY_COUNT 0x11 +#define MODBUS_SUBFUNC_SERVER_CHAR_COUNT 0x12 +#define MODBUS_SUBFUNC_CLEAR_COUNT 0x14 + +/* Modbus Encapsulated Interface Transport function: MEI type. */ +#define MODBUS_MEI_ENCAPINTTRANS_CAN 0x0d +#define MODBUS_MEI_ENCAPINTTRANS_READ 0x0e + +/* Modbus Exception Codes. */ +#define MODBUS_ERROR_CODE_ILLEGAL_FUNCTION 0x01 +#define MODBUS_ERROR_CODE_ILLEGAL_DATA_ADDRESS 0x02 +#define MODBUS_ERROR_CODE_ILLEGAL_DATA_VALUE 0x03 +#define MODBUS_ERROR_CODE_SERVER_DEVICE_FAILURE 0x04 +#define MODBUS_ERROR_CODE_MEMORY_PARITY_ERROR 0x08 + +/* Modbus Application Protocol (MBAP) header. */ +struct ModbusHeader_ { + uint16_t transactionId; + uint16_t protocolId; + uint16_t length; + uint8_t unitId; +} __attribute__((__packed__)); +typedef struct ModbusHeader_ ModbusHeader; + +/* Modbus Read/Write function and Access Types. */ +#define MODBUS_TYP_WRITE_SINGLE (MODBUS_TYP_WRITE | MODBUS_TYP_SINGLE) +#define MODBUS_TYP_WRITE_MULTIPLE (MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE) +#define MODBUS_TYP_READ_WRITE_MULTIPLE (MODBUS_TYP_READ | MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE) + +/* Macro to convert quantity value (in bit) into count value (in word): count = Ceil(quantity/8) */ +#define CEIL(quantity) (((quantity) + 7)>>3) + +/* Modbus Default unreplied Modbus requests are considered a flood */ +#define MODBUS_CONFIG_DEFAULT_REQUEST_FLOOD 500 + +static uint32_t request_flood = MODBUS_CONFIG_DEFAULT_REQUEST_FLOOD; + +int ModbusStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type) { + *event_id = SCMapEnumNameToValue(event_name, modbus_decoder_event_table); + + if (*event_id == -1) { + SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in " + "modbus's enum map table.", event_name); + /* yes this is fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +void ModbusSetEvent(ModbusState *modbus, uint8_t e) { + if (modbus && modbus->curr) { + SCLogDebug("modbus->curr->decoder_events %p", modbus->curr->decoder_events); + AppLayerDecoderEventsSetEventRaw(&modbus->curr->decoder_events, e); + SCLogDebug("modbus->curr->decoder_events %p", modbus->curr->decoder_events); + modbus->events++; + } else + SCLogDebug("couldn't set event %u", e); +} + +AppLayerDecoderEvents *ModbusGetEvents(void *state, uint64_t id) { + ModbusState *modbus = (ModbusState *) state; + ModbusTransaction *tx; + + if (modbus->curr && modbus->curr->tx_num == (id + 1)) + return modbus->curr->decoder_events; + + TAILQ_FOREACH(tx, &modbus->tx_list, next) { + if (tx->tx_num == (id+1)) + return tx->decoder_events; + } + + return NULL; +} + +int ModbusHasEvents(void *state) { + return (((ModbusState *) state)->events > 0); +} + +int ModbusGetAlstateProgress(void *modbus_tx, uint8_t direction) { + ModbusTransaction *tx = (ModbusTransaction *) modbus_tx; + ModbusState *modbus = tx->modbus; + + if (tx->replied == 1) + return 1; + + /* Check flood limit */ + if ((modbus->givenup == 1) && + ((modbus->transaction_max - tx->tx_num) > request_flood)) + return 1; + + return 0; +} + +/** \brief Get value for 'complete' status in Modbus + */ +int ModbusGetAlstateProgressCompletionStatus(uint8_t direction) { + return 1; +} + +void *ModbusGetTx(void *alstate, uint64_t tx_id) { + ModbusState *modbus = (ModbusState *) alstate; + ModbusTransaction *tx = NULL; + + if (modbus->curr && modbus->curr->tx_num == tx_id + 1) + return modbus->curr; + + TAILQ_FOREACH(tx, &modbus->tx_list, next) { + SCLogDebug("tx->tx_num %"PRIu64", tx_id %"PRIu64, tx->tx_num, (tx_id+1)); + if (tx->tx_num != (tx_id+1)) + continue; + + SCLogDebug("returning tx %p", tx); + return tx; + } + + return NULL; +} + +uint64_t ModbusGetTxCnt(void *alstate) { + return ((uint64_t) ((ModbusState *) alstate)->transaction_max); +} + +/** \internal + * \brief Find the Modbus Transaction in the state based on Transaction ID. + * + * \param modbus Pointer to Modbus state structure + * \param transactionId Transaction ID of the transaction + * + * \retval tx or NULL if not found + */ +static ModbusTransaction *ModbusTxFindByTransaction(const ModbusState *modbus, + const uint16_t transactionId) { + ModbusTransaction *tx = NULL; + + if (modbus->curr == NULL) + return NULL; + + /* fast path */ + if ((modbus->curr->transactionId == transactionId) && + !(modbus->curr->replied)) { + return modbus->curr; + /* slow path, iterate list */ + } else { + TAILQ_FOREACH(tx, &modbus->tx_list, next) { + if ((tx->transactionId == transactionId) && + !(modbus->curr->replied)) + return tx; + } + } + /* not found */ + return NULL; +} + +/** \internal + * \brief Allocate a Modbus Transaction and + * add it into Transaction list of Modbus State + * + * \param modbus Pointer to Modbus state structure + * + * \retval Pointer to Transaction or NULL pointer + */ +static ModbusTransaction *ModbusTxAlloc(ModbusState *modbus) { + ModbusTransaction *tx; + + tx = (ModbusTransaction *) SCCalloc(1, sizeof(ModbusTransaction)); + if (unlikely(tx == NULL)) + return NULL; + + modbus->transaction_max++; + modbus->unreplied_cnt++; + + /* Check flood limit */ + if ((request_flood != 0) && (modbus->unreplied_cnt > request_flood)) { + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_FLOODED); + modbus->givenup = 1; + } + + modbus->curr = tx; + + SCLogDebug("modbus->transaction_max updated to %"PRIu64, modbus->transaction_max); + + TAILQ_INSERT_TAIL(&modbus->tx_list, tx, next); + + tx->modbus = modbus; + tx->tx_num = modbus->transaction_max; + + return tx; +} + +/** \internal + * \brief Free a Modbus Transaction + * + * \retval Pointer to Transaction or NULL pointer + */ +static void ModbusTxFree(ModbusTransaction *tx) { + SCEnter(); + if (tx->data != NULL) + SCFree(tx->data); + + AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + + SCFree(tx); + SCReturn; +} + +/** + * \brief Modbus transaction cleanup callback + */ +void ModbusStateTxFree(void *state, uint64_t tx_id) { + SCEnter(); + ModbusState *modbus = (ModbusState *) state; + ModbusTransaction *tx = NULL, *ttx; + + SCLogDebug("state %p, id %"PRIu64, modbus, tx_id); + + TAILQ_FOREACH_SAFE(tx, &modbus->tx_list, next, ttx) { + SCLogDebug("tx %p tx->tx_num %"PRIu64", tx_id %"PRIu64, tx, tx->tx_num, (tx_id+1)); + + if (tx->tx_num != (tx_id+1)) + continue; + + if (tx == modbus->curr) + modbus->curr = NULL; + + if (tx->decoder_events != NULL) { + if (tx->decoder_events->cnt <= modbus->events) + modbus->events -= tx->decoder_events->cnt; + else + modbus->events = 0; + } + + modbus->unreplied_cnt--; + + /* Check flood limit */ + if ((modbus->givenup == 1) && + (request_flood != 0) && + (modbus->unreplied_cnt < request_flood) ) + modbus->givenup = 0; + + TAILQ_REMOVE(&modbus->tx_list, tx, next); + ModbusTxFree(tx); + break; + } + SCReturn; +} + +/** \internal + * \brief Extract 8bits data from pointer the received input data + * + * \param res Pointer to the result + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusExtractUint8(uint8_t *res, + uint8_t *input, + uint16_t *offset) { + SCEnter(); + *res = *(input + *offset); + *offset += sizeof(uint8_t); + SCReturn; +} + +/** \internal + * \brief Extract 16bits data from pointer the received input data + * + * \param res Pointer to the result + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusExtractUint16(uint16_t *res, + uint8_t *input, + uint16_t *offset) { + SCEnter(); + ByteExtractUint16(res, BYTE_BIG_ENDIAN, sizeof(uint16_t), (const uint8_t *) (input + *offset)); + *offset += sizeof(uint16_t); + SCReturn; +} + +/** \internal + * \brief Check length field in Modbus header according to code function + * + * \param modbus Pointer to Modbus state structure + * \param length Length field in Modbus Header + * \param len Length according to code functio + */ +static int ModbusCheckHeaderLength(ModbusState *modbus, + uint16_t length, + uint16_t len) { + SCEnter(); + if (length != len) { + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_LENGTH); + SCReturnInt(-1); + } + SCReturnInt(0); +} + +/** \internal + * \brief Check Modbus header + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param header Pointer to Modbus header state in which the value to be stored + */ +static void ModbusCheckHeader(ModbusState *modbus, + ModbusHeader *header) +{ + SCEnter(); + /* MODBUS protocol is identified by the value 0. */ + if (header->protocolId != MODBUS_PROTOCOL_VER) + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_PROTOCOL_ID); + + /* Check Length field that is a byte count of the following fields */ + if ((header->length < MODBUS_MIN_ADU_LEN) || + (header->length > MODBUS_MAX_ADU_LEN) ) + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_LENGTH); + + /* Check Unit Identifier field that is not in invalid range */ + if ((header->length > MODBUS_MIN_INVALID_UNIT_ID) && + (header->length < MODBUS_MAX_INVALID_UNIT_ID) ) + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_UNIT_IDENTIFIER); + + SCReturn; +} + +/** \internal + * \brief Parse Exception Response and verify protocol compliance. + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusExceptionResponse(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint16_t *offset) +{ + SCEnter(); + uint8_t exception; + + /* Exception code (1 byte) */ + ModbusExtractUint8(&exception, input, offset); + + switch (exception) { + case MODBUS_ERROR_CODE_ILLEGAL_FUNCTION: + case MODBUS_ERROR_CODE_SERVER_DEVICE_FAILURE: + break; + case MODBUS_ERROR_CODE_ILLEGAL_DATA_VALUE: + if (tx->function == MODBUS_FUNC_DIAGNOSTIC) { + break; + } + /* Fallthrough */ + case MODBUS_ERROR_CODE_ILLEGAL_DATA_ADDRESS: + if ( (tx->type & MODBUS_TYP_ACCESS_FUNCTION_MASK) || + (tx->function == MODBUS_FUNC_READFIFOQUEUE) || + (tx->function == MODBUS_FUNC_ENCAPINTTRANS)) { + break; + } + /* Fallthrough */ + case MODBUS_ERROR_CODE_MEMORY_PARITY_ERROR: + if ( (tx->function == MODBUS_FUNC_READFILERECORD) || + (tx->function == MODBUS_FUNC_WRITEFILERECORD) ) { + break; + } + /* Fallthrough */ + default: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_EXCEPTION_CODE); + break; + } + + SCReturn; +} + +/** \internal + * \brief Parse Read data Request, complete Transaction structure + * and verify protocol compliance. + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusParseReadRequest(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint16_t *offset) +{ + SCEnter(); + uint16_t quantity; + uint8_t type = tx->type; + + /* Starting Address (2 bytes) */ + ModbusExtractUint16(&(tx->read.address), input, offset); + + /* Quantity (2 bytes) */ + ModbusExtractUint16(&(tx->read.quantity), input, offset); + quantity = tx->read.quantity; + + /* Check Quantity range */ + if (type & MODBUS_TYP_BIT_ACCESS_MASK) { + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_BIT_ACCESS)) + goto error; + } else { + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_WORD_ACCESS)) + goto error; + } + + if (~type & MODBUS_TYP_WRITE) + /* Except from Read/Write Multiple Registers function (code 23) */ + /* The length of all Read Data function requests is 6 bytes */ + /* Modbus Application Protocol Specification V1.1b3 from 6.1 to 6.4 */ + ModbusCheckHeaderLength(modbus, tx->length, 6); + + goto end; + +error: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_VALUE); +end: + SCReturn; +} + +/** \internal + * \brief Parse Read data Response and verify protocol compliance + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusParseReadResponse(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint16_t *offset) +{ + SCEnter(); + uint8_t count; + + /* Count (1 bytes) */ + ModbusExtractUint8(&count, input, offset); + + /* Check Count range and value according to the request */ + if ((tx->type) & MODBUS_TYP_BIT_ACCESS_MASK) { + if ( (count < MODBUS_MIN_COUNT) || + (count > MODBUS_MAX_COUNT) || + (count != CEIL(tx->read.quantity))) + goto error; + } else { + if ( (count == MODBUS_MIN_COUNT) || + (count > MODBUS_MAX_COUNT) || + (count != (2 * (tx->read.quantity)))) + goto error; + } + + /* Except from Read/Write Multiple Registers function (code 23) */ + /* The length of all Read Data function responses is (3 bytes + count) */ + /* Modbus Application Protocol Specification V1.1b3 from 6.1 to 6.4 */ + ModbusCheckHeaderLength(modbus, tx->length, 3 + count); + goto end; + +error: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_VALUE_MISMATCH); +end: + SCReturn; +} + +/** \internal + * \brief Parse Write data Request, complete Transaction structure + * and verify protocol compliance. + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + * + * \retval On success returns 0 or on failure returns -1. + */ +static int ModbusParseWriteRequest(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint16_t *offset) +{ + SCEnter(); + uint16_t quantity = 1, word; + uint8_t byte, count = 1, type = tx->type; + + int i = 0; + + /* Starting/Output/Register Address (2 bytes) */ + ModbusExtractUint16(&(tx->write.address), input, offset); + + if (type & MODBUS_TYP_SINGLE) { + /* The length of Write Single Coil (code 5) and */ + /* Write Single Register (code 6) requests is 6 bytes */ + /* Modbus Application Protocol Specification V1.1b3 6.5 and 6.6 */ + if (ModbusCheckHeaderLength(modbus, tx->length, 6)) + goto end; + } else if (type & MODBUS_TYP_MULTIPLE) { + /* Quantity (2 bytes) */ + ModbusExtractUint16(&quantity, input, offset); + tx->write.quantity = quantity; + + /* Count (1 bytes) */ + ModbusExtractUint8(&count, input, offset); + tx->write.count = count; + + if (type & MODBUS_TYP_BIT_ACCESS_MASK) { + /* Check Quantity range and conversion in byte (count) */ + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_BIT_ACCESS) || + (quantity != CEIL(count))) + goto error; + + /* The length of Write Multiple Coils (code 15) request is (7 + count) */ + /* Modbus Application Protocol Specification V1.1b3 6.11 */ + if (ModbusCheckHeaderLength(modbus, tx->length, 7 + count)) + goto end; + } else { + /* Check Quantity range and conversion in byte (count) */ + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_WORD_ACCESS) || + (count != (2 * quantity))) + goto error; + + if (type & MODBUS_TYP_READ) { + /* The length of Read/Write Multiple Registers function (code 23) */ + /* request is (11 bytes + count) */ + /* Modbus Application Protocol Specification V1.1b3 6.17 */ + if (ModbusCheckHeaderLength(modbus, tx->length, 11 + count)) + goto end; + } else { + /* The length of Write Multiple Coils (code 15) and */ + /* Write Multiple Registers (code 16) functions requests is (7 bytes + count) */ + /* Modbus Application Protocol Specification V1.1b3 from 6.11 and 6.12 */ + if (ModbusCheckHeaderLength(modbus, tx->length, 7 + count)) + goto end; + } + } + } else { + /* Mask Write Register function (And_Mask and Or_Mask) */ + quantity = 2; + + /* The length of Mask Write Register (code 22) function request is 8 */ + /* Modbus Application Protocol Specification V1.1b3 6.16 */ + if (ModbusCheckHeaderLength(modbus, tx->length, 8)) + goto end; + } + + if (type & MODBUS_TYP_COILS) { + /* Output value (data block) unit is count */ + tx->data = (uint16_t *) SCCalloc(1, count * sizeof(uint16_t)); + if (unlikely(tx->data == NULL)) + SCReturnInt(-1); + + if (type & MODBUS_TYP_SINGLE) { + /* Outputs value (2 bytes) */ + ModbusExtractUint16(&word, input, offset); + tx->data[i] = word; + + if ((word != 0x00) && (word != 0xFF00)) + goto error; + } else { + for (i = 0; i < count; i++) { + /* Outputs value (1 byte) */ + ModbusExtractUint8(&byte, input, offset); + tx->data[i] = (uint16_t) byte; + } + } + } else { + /* Registers value (data block) unit is quantity */ + tx->data = (uint16_t *) SCCalloc(1, quantity * sizeof(uint16_t)); + if (unlikely(tx->data == NULL)) + SCReturnInt(-1); + + for (i = 0; i < quantity; i++) { + /* Outputs/Registers value (2 bytes) */ + ModbusExtractUint16(&word, input, offset); + tx->data[i] = word; + } + } + goto end; + +error: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_VALUE); +end: + SCReturnInt(0); +} + +/** \internal + * \brief Parse Write data Response and verify protocol compliance + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusParseWriteResponse(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint16_t *offset) +{ + SCEnter(); + uint16_t address, quantity, word; + uint8_t type = tx->type; + + /* Starting Address (2 bytes) */ + ModbusExtractUint16(&address, input, offset); + + if (address != tx->write.address) + goto error; + + if (type & MODBUS_TYP_SINGLE) { + /* Outputs/Registers value (2 bytes) */ + ModbusExtractUint16(&word, input, offset); + + /* Check with Outputs/Registers from request */ + if (word != tx->data[0]) + goto error; + } else if (type & MODBUS_TYP_MULTIPLE) { + /* Quantity (2 bytes) */ + ModbusExtractUint16(&quantity, input, offset); + + /* Check Quantity range */ + if (type & MODBUS_TYP_BIT_ACCESS_MASK) { + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_WORD_ACCESS)) + goto error; + } else { + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_BIT_ACCESS)) + goto error; + } + + /* Check Quantity value according to the request */ + if (quantity != tx->write.quantity) + goto error; + } else { + /* And_Mask value (2 bytes) */ + ModbusExtractUint16(&word, input, offset); + + /* Check And_Mask value according to the request */ + if (word != tx->data[0]) + goto error; + + /* And_Or_Mask value (2 bytes) */ + ModbusExtractUint16(&word, input, offset); + + /* Check Or_Mask value according to the request */ + if (word != tx->data[1]) + goto error; + + /* The length of Mask Write Register (code 22) function response is 8 */ + /* Modbus Application Protocol Specification V1.1b3 6.16 */ + ModbusCheckHeaderLength(modbus, tx->length, 8); + goto end; + } + + /* Except from Mask Write Register (code 22) */ + /* The length of all Write Data function responses is 6 */ + /* Modbus Application Protocol Specification V1.1b3 6.5, 6.6, 6.11, 6.12 and 6.17 */ + ModbusCheckHeaderLength(modbus, tx->length, 6); + goto end; + +error: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_VALUE_MISMATCH); +end: + SCReturn; +} + +/** \internal + * \brief Parse Diagnostic Request, complete Transaction + * structure (Category) and verify protocol compliance. + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + * + * \retval Reserved category function returns 1 otherwise returns 0. + */ +static int ModbusParseDiagnosticRequest(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint16_t *offset) +{ + SCEnter(); + uint16_t data; + + /* Sub-function (2 bytes) */ + ModbusExtractUint16(&(tx->subFunction), input, offset); + + /* Data (2 bytes) */ + ModbusExtractUint16(&data, input, offset); + + if (tx->subFunction != MODBUS_SUBFUNC_QUERY_DATA) { + switch (tx->subFunction) { + case MODBUS_SUBFUNC_RESTART_COM: + if ((data != 0x00) || (data != 0xFF00)) + goto error; + break; + + case MODBUS_SUBFUNC_CHANGE_DELIMITER: + if ((data & 0xFF) != 0x00) + goto error; + break; + + case MODBUS_SUBFUNC_LISTEN_MODE: + /* No answer is expected then mark tx as completed. */ + tx->replied = 1; + /* Fallthrough */ + case MODBUS_SUBFUNC_DIAG_REGS: + case MODBUS_SUBFUNC_CLEAR_REGS: + case MODBUS_SUBFUNC_BUS_MSG_COUNT: + case MODBUS_SUBFUNC_COM_ERR_COUNT: + case MODBUS_SUBFUNC_EXCEPT_ERR_COUNT: + case MODBUS_SUBFUNC_SERVER_MSG_COUNT: + case MODBUS_SUBFUNC_SERVER_NO_RSP_COUNT: + case MODBUS_SUBFUNC_SERVER_NAK_COUNT: + case MODBUS_SUBFUNC_SERVER_BUSY_COUNT: + case MODBUS_SUBFUNC_SERVER_CHAR_COUNT: + case MODBUS_SUBFUNC_CLEAR_COUNT: + if (data != 0x00) + goto error; + break; + + default: + /* Set function code category */ + tx->category = MODBUS_CAT_RESERVED; + SCReturnInt(1); + } + + /* The length of all Diagnostic Requests is 6 */ + /* Modbus Application Protocol Specification V1.1b3 6.8 */ + ModbusCheckHeaderLength(modbus, tx->length, 6); + } + + goto end; + +error: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_VALUE); +end: + SCReturnInt(0); +} + +/* Modbus Function Code Categories structure. */ +typedef struct ModbusFunctionCodeRange_ { + uint8_t function; + uint8_t category; +} ModbusFunctionCodeRange; + +/* Modbus Function Code Categories table. */ +static ModbusFunctionCodeRange modbusFunctionCodeRanges[] = { + { 0, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 9, MODBUS_CAT_RESERVED }, + { 15, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 41, MODBUS_CAT_RESERVED }, + { 43, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 65, MODBUS_CAT_USER_DEFINED }, + { 73, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 90, MODBUS_CAT_RESERVED }, + { 92, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 100, MODBUS_CAT_USER_DEFINED }, + { 111, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 125, MODBUS_CAT_RESERVED }, + { 128, MODBUS_CAT_NONE } +}; + +/** \internal + * \brief Parse the Modbus Protocol Data Unit (PDU) Request + * + * \param tx Pointer to Modbus Transaction structure + * \param ModbusPdu Pointer the Modbus PDU state in which the value to be stored + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusParseRequestPDU(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint16_t *offset) +{ + SCEnter(); + uint8_t count; + + int i = 0; + + /* Standard function codes used on MODBUS application layer protocol (1 byte) */ + ModbusExtractUint8(&(tx->function), input, offset); + + /* Set default function code category */ + tx->category = MODBUS_CAT_NONE; + + /* Set default function primary table */ + tx->type = MODBUS_TYP_NONE; + + switch (tx->function) { + case MODBUS_FUNC_NONE: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_FUNCTION_CODE); + break; + + case MODBUS_FUNC_READCOILS: + /* Set function type */ + tx->type = (MODBUS_TYP_COILS | MODBUS_TYP_READ); + break; + + case MODBUS_FUNC_READDISCINPUTS: + /* Set function type */ + tx->type = (MODBUS_TYP_DISCRETES | MODBUS_TYP_READ); + break; + + case MODBUS_FUNC_READHOLDREGS: + /* Set function type */ + tx->type = (MODBUS_TYP_HOLDING | MODBUS_TYP_READ); + break; + + case MODBUS_FUNC_READINPUTREGS: + /* Set function type */ + tx->type = (MODBUS_TYP_INPUT | MODBUS_TYP_READ); + break; + + case MODBUS_FUNC_WRITESINGLECOIL: + /* Set function type */ + tx->type = (MODBUS_TYP_COILS | MODBUS_TYP_WRITE_SINGLE); + break; + + case MODBUS_FUNC_WRITESINGLEREG: + /* Set function type */ + tx->type = (MODBUS_TYP_HOLDING | MODBUS_TYP_WRITE_SINGLE); + break; + + case MODBUS_FUNC_WRITEMULTCOILS: + /* Set function type */ + tx->type = (MODBUS_TYP_COILS | MODBUS_TYP_WRITE_MULTIPLE); + break; + + case MODBUS_FUNC_WRITEMULTREGS: + /* Set function type */ + tx->type = (MODBUS_TYP_HOLDING | MODBUS_TYP_WRITE_MULTIPLE); + break; + + case MODBUS_FUNC_MASKWRITEREG: + /* Set function type */ + tx->type = (MODBUS_TYP_HOLDING | MODBUS_TYP_WRITE); + break; + + case MODBUS_FUNC_READWRITEMULTREGS: + /* Set function type */ + tx->type = (MODBUS_TYP_HOLDING | MODBUS_TYP_READ_WRITE_MULTIPLE); + break; + + case MODBUS_FUNC_READFILERECORD: + case MODBUS_FUNC_WRITEFILERECORD: + /* Count/length (1 bytes) */ + ModbusExtractUint8(&count, input, offset); + + /* Modbus Application Protocol Specification V1.1b3 6.14 and 6.15 */ + ModbusCheckHeaderLength(modbus, tx->length, 2 + count); + break; + + case MODBUS_FUNC_DIAGNOSTIC: + if(ModbusParseDiagnosticRequest(tx, modbus, input, offset)) + goto end; + break; + + case MODBUS_FUNC_READEXCSTATUS: + case MODBUS_FUNC_GETCOMEVTCOUNTER: + case MODBUS_FUNC_GETCOMEVTLOG: + case MODBUS_FUNC_REPORTSERVERID: + /* Modbus Application Protocol Specification V1.1b3 6.7, 6.9, 6.10 and 6.13 */ + ModbusCheckHeaderLength(modbus, tx->length, 2); + break; + + case MODBUS_FUNC_READFIFOQUEUE: + /* Modbus Application Protocol Specification V1.1b3 6.18 */ + ModbusCheckHeaderLength(modbus, tx->length, 4); + break; + + case MODBUS_FUNC_ENCAPINTTRANS: + /* MEI type (1 byte) */ + ModbusExtractUint8(&(tx->mei), input, offset); + + if (tx->mei == MODBUS_MEI_ENCAPINTTRANS_READ) { + /* Modbus Application Protocol Specification V1.1b3 6.21 */ + ModbusCheckHeaderLength(modbus, tx->length, 5); + } else if (tx->mei != MODBUS_MEI_ENCAPINTTRANS_CAN) { + /* Set function code category */ + tx->category = MODBUS_CAT_RESERVED; + goto end; + } + break; + + default: + /* Check if request is error. */ + if (tx->function & MODBUS_FUNC_ERRORMASK) { + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_FUNCTION_CODE); + goto end; + } + + /* Get and store function code category */ + for (i = 0; modbusFunctionCodeRanges[i].category != MODBUS_CAT_NONE; i++) { + if (tx->function <= modbusFunctionCodeRanges[i].function) + break; + tx->category = modbusFunctionCodeRanges[i].category; + } + goto end; + } + + /* Set function code category */ + tx->category = MODBUS_CAT_PUBLIC_ASSIGNED; + + if (tx->type & MODBUS_TYP_READ) + ModbusParseReadRequest(tx, modbus, input, offset); + + if (tx->type & MODBUS_TYP_WRITE) + ModbusParseWriteRequest(tx, modbus, input, offset); + +end: + SCReturn; +} + +/** \internal + * \brief Parse the Modbus Protocol Data Unit (PDU) Response + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer the Modbus PDU state in which the value to be stored + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusParseResponsePDU(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint16_t *offset) +{ + SCEnter(); + uint8_t count, error = FALSE, function, mei; + + /* Standard function codes used on MODBUS application layer protocol (1 byte) */ + ModbusExtractUint8(&function, input, offset); + + /* Check if response is error */ + if(function & MODBUS_FUNC_ERRORMASK) { + function &= MODBUS_FUNC_MASK; + error = TRUE; + } + + if (tx->category == MODBUS_CAT_PUBLIC_ASSIGNED) { + /* Check if response is error. */ + if (error) { + ModbusExceptionResponse(tx, modbus, input, offset); + } else { + switch(function) { + case MODBUS_FUNC_READEXCSTATUS: + /* Modbus Application Protocol Specification V1.1b3 6.7 */ + ModbusCheckHeaderLength(modbus, tx->length, 3); + goto end; + + case MODBUS_FUNC_GETCOMEVTCOUNTER: + /* Modbus Application Protocol Specification V1.1b3 6.9 */ + ModbusCheckHeaderLength(modbus, tx->length, 6); + goto end; + + case MODBUS_FUNC_READFILERECORD: + case MODBUS_FUNC_WRITEFILERECORD: + /* Count/length (1 bytes) */ + ModbusExtractUint8(&count, input, offset); + + /* Modbus Application Protocol Specification V1.1b3 6.14 and 6.15 */ + ModbusCheckHeaderLength(modbus, tx->length, 2 + count); + goto end; + + case MODBUS_FUNC_ENCAPINTTRANS: + /* MEI type (1 byte) */ + ModbusExtractUint8(&mei, input, offset); + + if (mei != tx->mei) + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_VALUE_MISMATCH); + goto end; + } + + if (tx->type & MODBUS_TYP_READ) + ModbusParseReadResponse(tx, modbus, input, offset); + /* Read/Write response contents none write response part */ + else if (tx->type & MODBUS_TYP_WRITE) + ModbusParseWriteResponse(tx, modbus, input, offset); + } + } + +end: + SCReturn; +} + +/** \internal + * \brief Parse the Modbus Application Protocol (MBAP) header + * + * \param header Pointer the Modbus header state in which the value to be stored + * \param input Pointer the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusParseHeader(ModbusHeader *header, + uint8_t *input, + uint16_t *offset) +{ + SCEnter(); + /* Transaction Identifier (2 bytes) */ + ModbusExtractUint16(&(header->transactionId), input, offset); + + /* Protocol Identifier (2 bytes) */ + ModbusExtractUint16(&(header->protocolId), input, offset); + + /* Length (2 bytes) */ + ModbusExtractUint16(&(header->length), input, offset); + + /* Unit Identifier (1 byte) */ + ModbusExtractUint8(&(header->unitId), input, offset); + + SCReturn; +} + +/** \internal + * + * \brief This function is called to retrieve a Modbus Request + * + * \param state Modbus state structure for the parser + * \param input Input line of the command + * \param input_len Length of the request + * + * \retval 1 when the command is parsed, 0 otherwise + */ +static int ModbusParseRequest(Flow *f, + void *state, + AppLayerParserState *pstate, + uint8_t *input, + uint32_t input_len, + void *local_data) +{ + SCEnter(); + ModbusState *modbus = (ModbusState *) state; + ModbusTransaction *tx; + ModbusHeader header; + + while (input_len > 0) { + uint16_t adu_len, offset = 0; + uint8_t *ptr = input; + + /* Modbus header is 7 bytes long */ + if (input_len < sizeof(ModbusHeader)) + SCReturnInt(0); + + /* Extract MODBUS Header */ + ModbusParseHeader(&header, ptr, &offset); + + /* Compute ADU length. */ + adu_len = sizeof(ModbusHeader) + header.length - 1; + if (adu_len > input_len) + SCReturnInt(0); + + /* Allocate a Transaction Context and add it to Transaction list */ + tx = ModbusTxAlloc(modbus); + if (tx == NULL) + SCReturnInt(0); + + /* Check MODBUS Header */ + ModbusCheckHeader(modbus, &header); + + /* Store Transaction ID & PDU length */ + tx->transactionId = header.transactionId; + tx->length = header.length; + + /* Extract MODBUS PDU and fill Transaction Context */ + ModbusParseRequestPDU(tx, modbus, ptr, &offset); + + /* Update input line and remaining input length of the command */ + input += adu_len; + input_len -= adu_len; + } + + SCReturnInt(1); +} + +/** \internal + * \brief This function is called to retrieve a Modbus response + * + * \param state Pointer to Modbus state structure for the parser + * \param input Input line of the command + * \param input_len Length of the request + * + * \retval 1 when the command is parsed, 0 otherwise + */ +static int ModbusParseResponse(Flow *f, + void *state, + AppLayerParserState *pstate, + uint8_t *input, + uint32_t input_len, + void *local_data) +{ + SCEnter(); + ModbusHeader header; + ModbusState *modbus = (ModbusState *) state; + ModbusTransaction *tx; + + while (input_len > 0) { + uint16_t adu_len, offset = 0; + uint8_t *ptr = input; + + /* Modbus header is 7 bytes long */ + if (input_len < sizeof(ModbusHeader)) + SCReturnInt(0); + + /* Extract MODBUS Header */ + ModbusParseHeader(&header, ptr, &offset); + + /* Compute ADU length */ + adu_len = sizeof(ModbusHeader) + header.length - 1; + if (adu_len > input_len) + SCReturnInt(0); + + /* Find the transaction context thanks to transaction ID (and function code) */ + tx = ModbusTxFindByTransaction(modbus, header.transactionId); + if (tx == NULL) { + /* Allocate a Transaction Context if not previous request */ + /* and add it to Transaction list */ + tx = ModbusTxAlloc(modbus); + if (tx == NULL) + SCReturnInt(0); + + SCLogDebug("MODBUS_DECODER_EVENT_UNSOLICITED_RESPONSE"); + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_UNSOLICITED_RESPONSE); + } else { + /* Store PDU length */ + tx->length = header.length; + + /* Extract MODBUS PDU and fill Transaction Context */ + ModbusParseResponsePDU(tx, modbus, ptr, &offset); + } + + /* Check and store MODBUS Header */ + ModbusCheckHeader(modbus, &header); + + /* Mark as completed */ + tx->replied = 1; + + /* Update input line and remaining input length of the command */ + input += adu_len; + input_len -= adu_len; + } + + SCReturnInt(1); +} + +/** \internal + * \brief Function to allocate the Modbus state memory + */ +static void *ModbusStateAlloc(void) +{ + ModbusState *modbus; + + modbus = (ModbusState *) SCCalloc(1, sizeof(ModbusState)); + if (unlikely(modbus == NULL)) + return NULL; + + TAILQ_INIT(&modbus->tx_list); + + return (void *) modbus; +} + +/** \internal + * \brief Function to free the Modbus state memory + */ +static void ModbusStateFree(void *state) +{ + SCEnter(); + ModbusState *modbus = (ModbusState *) state; + ModbusTransaction *tx = NULL, *ttx; + + if (state) { + TAILQ_FOREACH_SAFE(tx, &modbus->tx_list, next, ttx) { + ModbusTxFree(tx); + } + + SCFree(state); + } + SCReturn; +} + +static uint16_t ModbusProbingParser(uint8_t *input, + uint32_t input_len, + uint32_t *offset) +{ + ModbusHeader *header = (ModbusHeader *) input; + + /* Modbus header is 7 bytes long */ + if (input_len < sizeof(ModbusHeader)) + return ALPROTO_UNKNOWN; + + /* MODBUS protocol is identified by the value 0. */ + if (header->protocolId != 0) + return ALPROTO_FAILED; + + return ALPROTO_MODBUS; +} + +/** + * \brief Function to register the Modbus protocol parsers and other functions + */ +void RegisterModbusParsers(void) +{ + SCEnter(); + char *proto_name = "modbus"; + + /* Modbus application protocol V1.1b3 */ + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_MODBUS, proto_name); + + if (RunmodeIsUnittests()) { + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "502", + ALPROTO_MODBUS, + 0, sizeof(ModbusHeader), + STREAM_TOSERVER, + ModbusProbingParser); + } else { + /* if we have no config, we enable the default port 502 */ + if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, + proto_name, ALPROTO_MODBUS, + 0, sizeof(ModbusHeader), + ModbusProbingParser)) { + SCLogWarning(SC_ERR_MODBUS_CONFIG, "no Modbus TCP config found, " + "enabling Modbus detection on " + "port 502."); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "502", + ALPROTO_MODBUS, + 0, sizeof(ModbusHeader), + STREAM_TOSERVER, + ModbusProbingParser); + } + } + + ConfNode *p = ConfGetNode("app-layer.protocols.modbus.request-flood"); + if (p != NULL) { + uint32_t value; + if (ParseSizeStringU32(p->val, &value) < 0) { + SCLogError(SC_ERR_MODBUS_CONFIG, "invalid value for request-flood %s", p->val); + } else { + request_flood = value; + } + } + SCLogInfo("Modbus request flood protection level: %u", request_flood); + } else { + SCLogInfo("Protocol detection and parser disabled for %s protocol.", proto_name); + return; + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) { + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOSERVER, ModbusParseRequest); + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOCLIENT, ModbusParseResponse); + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateAlloc, ModbusStateFree); + + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetEvents); + AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusHasEvents); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTx); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTxCnt); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateTxFree); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetAlstateProgress); + AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_MODBUS, + ModbusGetAlstateProgressCompletionStatus); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateGetEventInfo); + + AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOSERVER); + } else { + SCLogInfo("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); + } +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_MODBUS, ModbusParserRegisterTests); +#endif + + SCReturn; +} + +/* UNITTESTS */ +#ifdef UNITTESTS +#include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" + +#include "flow-util.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +#include "stream-tcp.h" +#include "stream-tcp-private.h" + +/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */ +/* Example of a request to read discrete outputs 20-38 */ +static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Starting Address */ 0x78, 0x90, + /* Quantity of coils */ 0x00, 0x13 }; + +static uint8_t readCoilsRsp[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Byte count */ 0x03, + /* Coil Status */ 0xCD, 0x6B, 0x05 }; + +static uint8_t readCoilsErrorRsp[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x03, + /* Unit ID */ 0x00, + /* Function code */ 0x81, + /* Exception code */ 0x05}; + +/* Modbus Application Protocol Specification V1.1b3 6.12: Write Multiple registers */ +/* Example of a request to write two registers starting at 2 to 00 0A and 01 02 hex */ +static uint8_t writeMultipleRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x0B, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x00, 0x02, + /* Byte count */ 0x04, + /* Registers Value */ 0x00, 0x0A, + 0x01, 0x02}; + +static uint8_t writeMultipleRegistersRsp[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x00, 0x02}; + +/* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */ +/* Example of a request to read six registers starting at register 4, */ +/* and to write three registers starting at register 15 */ +static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x11, + /* Unit ID */ 0x00, + /* Function code */ 0x17, + /* Read Starting Address */ 0x00, 0x03, + /* Quantity to Read */ 0x00, 0x06, + /* Write Starting Address */ 0x00, 0x0E, + /* Quantity to Write */ 0x00, 0x03, + /* Write Byte count */ 0x06, + /* Write Registers Value */ 0x12, 0x34, + 0x56, 0x78, + 0x9A, 0xBC}; + +/* Mismatch value in Byte count 0x0B instead of 0x0C */ +static uint8_t readWriteMultipleRegistersRsp[] = {/* Transaction ID */ 0x12, 0x34, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x0E, + /* Unit ID */ 0x00, + /* Function code */ 0x17, + /* Byte count */ 0x0B, + /* Read Registers Value */ 0x00, 0xFE, + 0x0A, 0xCD, + 0x00, 0x01, + 0x00, 0x03, + 0x00, 0x0D, + 0x00}; + +/* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */ +/* Example of a request to to remote device to its Listen Only MOde for Modbus Communications. */ +static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x08, + /* Sub-function code */ 0x00, 0x04, + /* Data */ 0x00, 0x00}; + +static uint8_t invalidProtocolIdReq[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x01, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Starting Address */ 0x78, 0x90, + /* Quantity of coils */ 0x00, 0x13 }; + +static uint8_t invalidLengthWriteMultipleRegistersReq[] = { + /* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x09, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x00, 0x02, + /* Byte count */ 0x04, + /* Registers Value */ 0x00, 0x0A, + 0x01, 0x02}; + +/** \test Send Modbus Read Coils request/response. */ +static int ModbusParserTest01(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readCoilsReq, sizeof(readCoilsReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 1, tx->function); + printf("expected address %" PRIu8 ", got %" PRIu8 ": ", 0x7890, tx->read.address); + printf("expected quantity %" PRIu8 ", got %" PRIu8 ": ", 19, tx->read.quantity); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + readCoilsRsp, sizeof(readCoilsRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send Modbus Write Multiple registers request/response. */ +static int ModbusParserTest02(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 16) || (tx->write.address != 0x01) || (tx->write.quantity != 2) || + (tx->write.count != 4) || (tx->data[0] != 0x000A) || (tx->data[1] != 0x0102)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %" PRIu8 ", got %" PRIu8 ": ", 0x01, tx->write.address); + printf("expected write quantity %" PRIu8 ", got %" PRIu8 ": ", 2, tx->write.quantity); + printf("expected write count %" PRIu8 ", got %" PRIu8 ": ", 4, tx->write.count); + printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x000A, tx->data[0]); + printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x0102, tx->data[1]); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send Modbus Read/Write Multiple registers request/response with mismatch value. */ +static int ModbusParserTest03(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus Data mismatch\"; " + "app-layer-event: " + "modbus.value_mismatch; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readWriteMultipleRegistersReq, sizeof(readWriteMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 23) || (tx->read.address != 0x03) || (tx->read.quantity != 6) || + (tx->write.address != 0x0E) || (tx->write.quantity != 3) || (tx->write.count != 6) || + (tx->data[0] != 0x1234) || (tx->data[1] != 0x5678) || (tx->data[2] != 0x9ABC)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 23, tx->function); + printf("expected read address %" PRIu8 ", got %" PRIu8 ": ", 0x03, tx->read.address); + printf("expected read quantity %" PRIu8 ", got %" PRIu8 ": ", 6, tx->read.quantity); + printf("expected write address %" PRIu8 ", got %" PRIu8 ": ", 0x0E, tx->write.address); + printf("expected write quantity %" PRIu8 ", got %" PRIu8 ": ", 3, tx->write.quantity); + printf("expected write count %" PRIu8 ", got %" PRIu8 ": ", 6, tx->write.count); + printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x1234, tx->data[0]); + printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x5678, tx->data[1]); + printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x9ABC, tx->data[2]); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + readWriteMultipleRegistersRsp, sizeof(readWriteMultipleRegistersRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send Modbus Force Listen Only Mode request. */ +static int ModbusParserTest04(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + forceListenOnlyMode, sizeof(forceListenOnlyMode)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 8) || (tx->subFunction != 4)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 8, tx->function); + printf("expected sub-function %" PRIu8 ", got %" PRIu8 ": ", 0x04, tx->subFunction); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send Modbus invalid Protocol version in request. */ +static int ModbusParserTest05(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Protocol version\"; " + "app-layer-event: " + "modbus.invalid_protocol_id; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidProtocolIdReq, sizeof(invalidProtocolIdReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send Modbus unsolicited response. */ +static int ModbusParserTest06(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus unsolicited response\"; " + "app-layer-event: " + "modbus.unsolicited_response; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + readCoilsRsp, sizeof(readCoilsRsp)); + if (r != 0) { + printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send Modbus invalid Length request. */ +static int ModbusParserTest07(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidLengthWriteMultipleRegistersReq, + sizeof(invalidLengthWriteMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send Modbus Read Coils request and error response with Exception code invalid. */ +static int ModbusParserTest08(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus Exception code invalid\"; " + "app-layer-event: " + "modbus.invalid_exception_code; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readCoilsReq, sizeof(readCoilsReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 1, tx->function); + printf("expected address %" PRIu8 ", got %" PRIu8 ": ", 0x7890, tx->read.address); + printf("expected quantity %" PRIu8 ", got %" PRIu8 ": ", 19, tx->read.quantity); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + readCoilsErrorRsp, sizeof(readCoilsErrorRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Modbus fragmentation - 1 ADU over 2 TCP packets. */ +static int ModbusParserTest09(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + uint32_t input_len = sizeof(readCoilsReq), part2_len = 3; + uint8_t *input = readCoilsReq; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + input, input_len - part2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + input, input_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 1, tx->function); + printf("expected address %" PRIu8 ", got %" PRIu8 ": ", 0x7890, tx->read.address); + printf("expected quantity %" PRIu8 ", got %" PRIu8 ": ", 19, tx->read.quantity); + goto end; + } + + input_len = sizeof(readCoilsRsp); + part2_len = 10; + input = readCoilsRsp; + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + input, input_len - part2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + input, input_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */ +static int ModbusParserTest10(void) { + uint32_t input_len = sizeof(readCoilsReq) + sizeof(writeMultipleRegistersReq); + uint8_t *input, *ptr; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + input = (uint8_t *) SCMalloc (input_len * sizeof(uint8_t)); + if (unlikely(input == NULL)) + goto end; + + memcpy(input, readCoilsReq, sizeof(readCoilsReq)); + memcpy(input + sizeof(readCoilsReq), writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq)); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + input, input_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + if (modbus_state->transaction_max !=2) { + printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 2, modbus_state->transaction_max); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 1); + + if ((tx->function != 16) || (tx->write.address != 0x01) || (tx->write.quantity != 2) || + (tx->write.count != 4) || (tx->data[0] != 0x000A) || (tx->data[1] != 0x0102)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %" PRIu8 ", got %" PRIu8 ": ", 0x01, tx->write.address); + printf("expected write quantity %" PRIu8 ", got %" PRIu8 ": ", 2, tx->write.quantity); + printf("expected write count %" PRIu8 ", got %" PRIu8 ": ", 4, tx->write.count); + printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x000A, tx->data[0]); + printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x0102, tx->data[1]); + goto end; + } + + input_len = sizeof(readCoilsRsp) + sizeof(writeMultipleRegistersRsp); + + ptr = (uint8_t *) SCRealloc (input, input_len * sizeof(uint8_t)); + if (unlikely(ptr == NULL)) + goto end; + input = ptr; + + memcpy(input, readCoilsRsp, sizeof(readCoilsRsp)); + memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + input, sizeof(input_len)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + result = 1; +end: + if (input != NULL) + SCFree(input); + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} +#endif /* UNITTESTS */ + +void ModbusParserRegisterTests(void) { +#ifdef UNITTESTS + UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request", ModbusParserTest01, 1); + UtRegisterTest("ModbusParserTest02 - Modbus Write Multiple registers request", ModbusParserTest02, 1); + UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request", ModbusParserTest03, 1); + UtRegisterTest("ModbusParserTest04 - Modbus Force Listen Only Mode request", ModbusParserTest04, 1); + UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version", ModbusParserTest05, 1); + UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response", ModbusParserTest06, 1); + UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request", ModbusParserTest07, 1); + UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid", ModbusParserTest08, 1); + UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets", ModbusParserTest09, 1); + UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet", ModbusParserTest10, 1); +#endif /* UNITTESTS */ +} diff --git a/src/app-layer-modbus.h b/src/app-layer-modbus.h new file mode 100644 index 000000000000..fba43db74a0d --- /dev/null +++ b/src/app-layer-modbus.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author David DIALLO + */ + +#ifndef __APP_LAYER_MODBUS_H__ +#define __APP_LAYER_MODBUS_H__ + +#include "decode.h" + +#include "queue.h" + +/* Modbus Application Data Unit (ADU) + * and Protocol Data Unit (PDU) messages */ +enum { + MODBUS_DECODER_EVENT_INVALID_PROTOCOL_ID, + MODBUS_DECODER_EVENT_UNSOLICITED_RESPONSE, + MODBUS_DECODER_EVENT_INVALID_LENGTH, + MODBUS_DECODER_EVENT_INVALID_UNIT_IDENTIFIER, + MODBUS_DECODER_EVENT_INVALID_FUNCTION_CODE, + MODBUS_DECODER_EVENT_INVALID_VALUE, + MODBUS_DECODER_EVENT_INVALID_EXCEPTION_CODE, + MODBUS_DECODER_EVENT_VALUE_MISMATCH, + MODBUS_DECODER_EVENT_FLOODED, +}; + +/* Modbus Function Code Categories. */ +#define MODBUS_CAT_NONE 0x0 +#define MODBUS_CAT_PUBLIC_ASSIGNED (1<<0) +#define MODBUS_CAT_PUBLIC_UNASSIGNED (1<<1) +#define MODBUS_CAT_USER_DEFINED (1<<2) +#define MODBUS_CAT_RESERVED (1<<3) +#define MODBUS_CAT_ALL 0xFF + +/* Modbus Read/Write function and Access Types. */ +#define MODBUS_TYP_NONE 0x0 +#define MODBUS_TYP_ACCESS_MASK 0x03 +#define MODBUS_TYP_READ (1<<0) +#define MODBUS_TYP_WRITE (1<<1) +#define MODBUS_TYP_ACCESS_FUNCTION_MASK 0x3C +#define MODBUS_TYP_BIT_ACCESS_MASK 0x0C +#define MODBUS_TYP_DISCRETES (1<<2) +#define MODBUS_TYP_COILS (1<<3) +#define MODBUS_TYP_WORD_ACCESS_MASK 0x30 +#define MODBUS_TYP_INPUT (1<<4) +#define MODBUS_TYP_HOLDING (1<<5) +#define MODBUS_TYP_SINGLE (1<<6) +#define MODBUS_TYP_MULTIPLE (1<<7) +#define MODBUS_TYP_WRITE_SINGLE (MODBUS_TYP_WRITE | MODBUS_TYP_SINGLE) +#define MODBUS_TYP_WRITE_MULTIPLE (MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE) +#define MODBUS_TYP_READ_WRITE_MULTIPLE (MODBUS_TYP_READ | MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE) + +/* Modbus Transaction Structure, request/response. */ +typedef struct ModbusTransaction_ { + struct ModbusState_ *modbus; + + uint64_t tx_num; /**< internal: id */ + uint16_t transactionId; + uint16_t length; + uint8_t function; + uint8_t category; + uint8_t type; + union { + uint16_t subFunction; + uint8_t mei; + struct { + struct { + uint16_t address; + uint16_t quantity; + } read; + struct { + uint16_t address; + uint16_t quantity; + uint8_t count; + } write; + }; + }; + uint16_t *data; /**< to store data to write, bit is converted in 16bits. */ + + AppLayerDecoderEvents *decoder_events; /**< per tx events */ + + uint8_t replied; /**< bool indicating request is replied to. */ + + TAILQ_ENTRY(ModbusTransaction_) next; +} ModbusTransaction; + +/* Modbus State Structure. */ +typedef struct ModbusState_ { + TAILQ_HEAD(, ModbusTransaction_) tx_list; /**< transaction list */ + ModbusTransaction *curr; /**< ptr to current tx */ + uint64_t transaction_max; + uint32_t unreplied_cnt; /**< number of unreplied requests */ + uint16_t events; + uint8_t givenup; /**< bool indicating flood. */ +} ModbusState; + +void RegisterModbusParsers(void); +void ModbusParserRegisterTests(void); + +#endif /* __APP_LAYER_MODBUS_H__ */ diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index e665cceed6a1..ec45b0caf8a6 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -57,6 +57,7 @@ #include "app-layer-smtp.h" #include "app-layer-dns-udp.h" #include "app-layer-dns-tcp.h" +#include "app-layer-modbus.h" #include "conf.h" #include "util-spm.h" @@ -1033,6 +1034,7 @@ void AppLayerParserRegisterProtocolParsers(void) RegisterSMTPParsers(); RegisterDNSUDPParsers(); RegisterDNSTCPParsers(); + RegisterModbusParsers(); /** IMAP */ AppLayerProtoDetectRegisterProtocol(ALPROTO_IMAP, "imap"); diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index 39c729c41a33..ecfc4569e84b 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -41,6 +41,7 @@ enum { ALPROTO_IRC, ALPROTO_DNS, + ALPROTO_MODBUS, /* used by the probing parser when alproto detection fails * permanently for that particular stream */ diff --git a/src/util-error.c b/src/util-error.c index b0d67508524a..8da681ac3dc5 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -293,6 +293,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_WARN_XFF_INVALID_HEADER); CASE_CODE (SC_ERR_THRESHOLD_SETUP); CASE_CODE (SC_ERR_DNS_CONFIG); + CASE_CODE (SC_ERR_MODBUS_CONFIG); CASE_CODE (SC_ERR_CONF_YAML_ERROR); CASE_CODE (SC_ERR_CONF_NAME_TOO_LONG); CASE_CODE (SC_ERR_APP_LAYER_PROTOCOL_DETECTION); diff --git a/src/util-error.h b/src/util-error.h index ada12d53c964..7d7155290513 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -269,6 +269,7 @@ typedef enum { SC_WARN_XFF_INVALID_HEADER, SC_ERR_THRESHOLD_SETUP, SC_ERR_DNS_CONFIG, + SC_ERR_MODBUS_CONFIG, SC_ERR_CONF_YAML_ERROR, SC_ERR_CONF_NAME_TOO_LONG, SC_ERR_APP_LAYER_PROTOCOL_DETECTION, diff --git a/suricata.yaml.in b/suricata.yaml.in index 29dacf4db0a0..70be178badd6 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1028,6 +1028,7 @@ rule-files: - smtp-events.rules # available in suricata sources under rules dir - dns-events.rules # available in suricata sources under rules dir - tls-events.rules # available in suricata sources under rules dir + - modbus-events.rules # available in suricata sources under rules dir classification-file: @e_sysconfdir@classification.config reference-config-file: @e_sysconfdir@reference.config @@ -1081,6 +1082,8 @@ vars: DNP3_PORTS: 20000 + MODBUS_PORTS: 502 + # Set the order of alerts bassed on actions # The default order is pass, drop, reject, alert # action-order: @@ -1186,6 +1189,19 @@ app-layer: enabled: yes detection-ports: dp: 139 + # Note: Modbus probe parser is minimalist due to the poor significant field + # Only Modbus message length (greater than Modbus header length) + # And Protocol ID (equal to 0) are checked in probing parser + # It is important to enable detection port and define Modbus port + # to avoid false positive + modbus: + # How many unreplied Modbus requests are considered a flood. + # If the limit is reached, app-layer-event:modbus.flooded; will match. + #request-flood: 500 + + enabled: yes + detection-ports: + dp: 502 # smb2 detection is disabled internally inside the engine. #smb2: # enabled: yes From b3bf2f99394158285caae51e9773f519318b54ad Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Thu, 14 Aug 2014 16:53:30 +0200 Subject: [PATCH 0060/2553] Detect: Add Modbus keyword management Add the modbus.function and subfunction) keywords for public function match in rules (Modbus layer). Matching based on code function, and if necessary, sub-function code or based on category (assigned, unassigned, public, user or reserved) and negation is permitted. Add the modbus.access keyword for read/write Modbus function match in rules (Modbus layer). Matching based on access type (read or write), and/or function type (discretes, coils, input or holding) and, if necessary, read or write address access, and, if necessary, value to write. For address and value matching, "<", ">" and "<>" is permitted. Based on TLS source code and file size source code (address and value matching). Signed-off-by: David DIALLO --- src/Makefile.am | 1 + src/detect-engine.c | 3 + src/detect-modbus.c | 895 ++++++++++++++++++++++++++++++++++++++++++++ src/detect-modbus.h | 64 ++++ src/detect-parse.c | 2 + src/detect.c | 2 + src/detect.h | 2 + 7 files changed, 969 insertions(+) create mode 100644 src/detect-modbus.c create mode 100644 src/detect-modbus.h diff --git a/src/Makefile.am b/src/Makefile.am index 5b2b3cc88769..407018119a3d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -194,6 +194,7 @@ detect-uricontent.c detect-uricontent.h \ detect-urilen.c detect-urilen.h \ detect-window.c detect-window.h \ detect-within.c detect-within.h \ +detect-modbus.c detect-modbus.h \ flow-bit.c flow-bit.h \ flow.c flow.h \ flow-hash.c flow-hash.h \ diff --git a/src/detect-engine.c b/src/detect-engine.c index c3934397923a..d9655762aa39 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1596,6 +1596,9 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_DNSQUERY_MATCH: return "dns query"; + case DETECT_SM_LIST_MODBUS_MATCH: + return "modbus"; + case DETECT_SM_LIST_POSTMATCH: return "post-match"; diff --git a/src/detect-modbus.c b/src/detect-modbus.c new file mode 100644 index 000000000000..4c23e348106b --- /dev/null +++ b/src/detect-modbus.c @@ -0,0 +1,895 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author David DIALLO + * + * Implements the Modbus function and access keywords + * You can specify a: + * - concrete function like Modbus: + * function 8, subfunction 4 (diagnostic: Force Listen Only Mode) + * - data (in primary table) register access (r/w) like Modbus: + * access read coils, address 1000 (.i.e Read coils: at address 1000) + * - write data value at specific address Modbus: + * access write, address 1500<>2000, value >2000 (Write multiple coils/register: + * at address between 1500 and 2000 value greater than 2000) + */ + +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-modbus.h" + +#include "util-debug.h" + +#include "app-layer-modbus.h" + +#include "stream-tcp.h" + +/** + * \brief Regex for parsing the Modbus function string + */ +#define PARSE_REGEX_FUNCTION "^\\s*\"?\\s*function\\s*(!?[A-z0-9]+)(,\\s*subfunction\\s+(\\d+))?\\s*\"?\\s*$" +static pcre *function_parse_regex; +static pcre_extra *function_parse_regex_study; + +/** + * \brief Regex for parsing the Modbus access string + */ +#define PARSE_REGEX_ACCESS "^\\s*\"?\\s*access\\s*(read|write)\\s*(discretes|coils|input|holding)?(,\\s*address\\s+([<>]?\\d+)(<>\\d+)?(,\\s*value\\s+([<>]?\\d+)(<>\\d+)?)?)?\\s*\"?\\s*$" +static pcre *access_parse_regex; +static pcre_extra *access_parse_regex_study; + +#define MAX_SUBSTRINGS 30 + +void DetectModbusRegisterTests(void); + +/** \internal + * + * \brief this function will free memory associated with DetectModbus + * + * \param ptr pointer to DetectModbus + */ +static void DetectModbusFree(void *ptr) { + SCEnter(); + DetectModbus *modbus = (DetectModbus *) ptr; + + if(modbus) { + if (modbus->subfunction) + SCFree(modbus->subfunction); + + if (modbus->address) + SCFree(modbus->address); + + if (modbus->data) + SCFree(modbus->data); + + SCFree(modbus); + } +} + +/** \internal + * + * \brief This function is used to parse Modbus parameters in access mode + * + * \param str Pointer to the user provided id option + * + * \retval Pointer to DetectModbusData on success or NULL on failure + */ +static DetectModbus *DetectModbusAccessParse(char *str) +{ + SCEnter(); + DetectModbus *modbus = NULL; + + char arg[MAX_SUBSTRINGS]; + int ov[MAX_SUBSTRINGS], ret, res; + + ret = pcre_exec(access_parse_regex, access_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); + + if (ret < 1) + goto error; + + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 1, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + /* We have a correct Modbus option */ + modbus = (DetectModbus *) SCCalloc(1, sizeof(DetectModbus)); + if (unlikely(modbus == NULL)) + goto error; + + if (strcmp(arg, "read") == 0) + modbus->type = MODBUS_TYP_READ; + else if (strcmp(arg, "write") == 0) + modbus->type = MODBUS_TYP_WRITE; + else + goto error; + + if (ret > 2) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 2, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + if (*arg != '\0') { + if (strcmp(arg, "discretes") == 0) { + if (modbus->type == MODBUS_TYP_WRITE) + /* Discrete access is only read access. */ + goto error; + + modbus->type |= MODBUS_TYP_DISCRETES; + } + else if (strcmp(arg, "coils") == 0) { + modbus->type |= MODBUS_TYP_COILS; + } + else if (strcmp(arg, "input") == 0) { + if (modbus->type == MODBUS_TYP_WRITE) { + /* Input access is only read access. */ + goto error; + } + + modbus->type |= MODBUS_TYP_INPUT; + } + else if (strcmp(arg, "holding") == 0) { + modbus->type |= MODBUS_TYP_HOLDING; + } + else + goto error; + } + + if (ret > 4) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 4, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + /* We have a correct address option */ + modbus->address = (DetectModbusValue *) SCCalloc(1, sizeof(DetectModbusValue)); + if (unlikely(modbus->address == NULL)) + goto error; + + if (arg[0] == '>') { + modbus->address->min = atoi((const char*) (arg+1)); + modbus->address->mode = DETECT_MODBUS_GT; + } else if (arg[0] == '<') { + modbus->address->min = atoi((const char*) (arg+1)); + modbus->address->mode = DETECT_MODBUS_LT; + } else { + modbus->address->min = atoi((const char*) arg); + } + SCLogDebug("and min/equal address %d", modbus->address->min); + + if (ret > 5) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 5, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + if (*arg != '\0') { + modbus->address->max = atoi((const char*) (arg+2)); + modbus->address->mode = DETECT_MODBUS_RA; + SCLogDebug("and max address %d", modbus->address->max); + } + + if (ret > 7) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 7, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + if (modbus->address->mode != DETECT_MODBUS_EQ) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords (address range and value)."); + goto error; + } + + /* We have a correct address option */ + modbus->data = (DetectModbusValue *) SCCalloc(1, sizeof(DetectModbusValue)); + if (unlikely(modbus->data == NULL)) + goto error; + + if (arg[0] == '>') { + modbus->data->min = atoi((const char*) (arg+1)); + modbus->data->mode = DETECT_MODBUS_GT; + } else if (arg[0] == '<') { + modbus->data->min = atoi((const char*) (arg+1)); + modbus->data->mode = DETECT_MODBUS_LT; + } else { + modbus->data->min = atoi((const char*) arg); + } + SCLogDebug("and min/equal value %d", modbus->data->min); + + if (ret > 8) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 8, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + if (*arg != '\0') { + modbus->data->max = atoi((const char*) (arg+2)); + modbus->data->mode = DETECT_MODBUS_RA; + SCLogDebug("and max value %d", modbus->data->max); + } + } + } + } + } + } + + SCReturnPtr(modbus, "DetectModbusAccess"); + +error: + if (modbus != NULL) + DetectModbusFree(modbus); + + SCReturnPtr(NULL, "DetectModbus"); +} + +/** \internal + * + * \brief This function is used to parse Modbus parameters in function mode + * + * \param str Pointer to the user provided id option + * + * \retval id_d pointer to DetectModbusData on success + * \retval NULL on failure + */ +static DetectModbus *DetectModbusFunctionParse(char *str) +{ + SCEnter(); + DetectModbus *modbus = NULL; + + char arg[MAX_SUBSTRINGS], *ptr = arg; + int ov[MAX_SUBSTRINGS], res, ret; + + ret = pcre_exec(function_parse_regex, function_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); + + if (ret < 1) + goto error; + + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 1, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + /* We have a correct Modbus function option */ + modbus = (DetectModbus *) SCCalloc(1, sizeof(DetectModbus)); + if (unlikely(modbus == NULL)) + goto error; + + if (isdigit(ptr[0])) { + modbus->function = atoi((const char*) ptr); + SCLogDebug("will look for modbus function %d", modbus->function); + + if (ret > 2) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 3, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + /* We have a correct address option */ + modbus->subfunction =(uint16_t *) SCCalloc(1, sizeof(uint16_t)); + if (modbus->subfunction == NULL) + goto error; + + *(modbus->subfunction) = atoi((const char*) arg); + SCLogDebug("and subfunction %d", *(modbus->subfunction)); + } + } else { + uint8_t neg = 0; + + if (ptr[0] == '!') { + neg = 1; + ptr++; + } + + if (strcmp("assigned", ptr) == 0) + modbus->category = MODBUS_CAT_PUBLIC_ASSIGNED; + else if (strcmp("unassigned", ptr) == 0) + modbus->category = MODBUS_CAT_PUBLIC_UNASSIGNED; + else if (strcmp("public", ptr) == 0) + modbus->category = MODBUS_CAT_PUBLIC_ASSIGNED | MODBUS_CAT_PUBLIC_UNASSIGNED; + else if (strcmp("user", ptr) == 0) + modbus->category = MODBUS_CAT_USER_DEFINED; + else if (strcmp("reserved", ptr) == 0) + modbus->category = MODBUS_CAT_RESERVED; + else if (strcmp("all", ptr) == 0) + modbus->category = MODBUS_CAT_ALL; + + if (neg) + modbus->category = ~modbus->category; + SCLogDebug("will look for modbus category function %d", modbus->category); + } + + SCReturnPtr(modbus, "DetectModbusFunction"); + +error: + if (modbus != NULL) + DetectModbusFree(modbus); + + SCReturnPtr(NULL, "DetectModbus"); +} + +/** \internal + * + * \brief this function is used to add the parsed "id" option into the current signature + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Current Signature + * \param str Pointer to the user provided "id" option + * + * \retval 0 on Success or -1 on Failure + */ +static int DetectModbusSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCEnter(); + DetectModbus *modbus = NULL; + SigMatch *sm = NULL; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_MODBUS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + goto error; + } + + if ((modbus = DetectModbusFunctionParse(str)) == NULL) { + if ((modbus = DetectModbusAccessParse(str)) == NULL) { + SCLogError(SC_ERR_PCRE_MATCH, "invalid modbus option"); + goto error; + } + } + + /* Okay so far so good, lets get this into a SigMatch and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_AL_MODBUS; + sm->ctx = (void *) modbus; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MODBUS_MATCH); + s->alproto = ALPROTO_MODBUS; + + SCReturnInt(0); + +error: + if (modbus != NULL) + DetectModbusFree(modbus); + if (sm != NULL) + SCFree(sm); + SCReturnInt(-1); +} + +/** + * \brief Registration function for Modbus keyword + */ +void DetectModbusRegister(void) { + SCEnter(); + sigmatch_table[DETECT_AL_MODBUS].name = "modbus"; + sigmatch_table[DETECT_AL_MODBUS].Match = NULL; + sigmatch_table[DETECT_AL_MODBUS].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_MODBUS].alproto = ALPROTO_MODBUS; + sigmatch_table[DETECT_AL_MODBUS].Setup = DetectModbusSetup; + sigmatch_table[DETECT_AL_MODBUS].Free = DetectModbusFree; + sigmatch_table[DETECT_AL_MODBUS].RegisterTests = DetectModbusRegisterTests; + + const char *eb; + int eo, opts = 0; + + SCLogDebug("registering modbus rule option"); + + /* Function PARSE_REGEX */ + function_parse_regex = pcre_compile(PARSE_REGEX_FUNCTION, opts, &eb, &eo, NULL); + if (function_parse_regex == NULL) { + SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", + PARSE_REGEX_FUNCTION, eo, eb); + goto error; + } + + function_parse_regex_study = pcre_study(function_parse_regex, 0, &eb); + if (eb != NULL) { + SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + goto error; + } + + /* Access PARSE_REGEX */ + access_parse_regex = pcre_compile(PARSE_REGEX_ACCESS, opts, &eb, &eo, NULL); + if (access_parse_regex == NULL) { + SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", + PARSE_REGEX_ACCESS, eo, eb); + goto error; + } + + access_parse_regex_study = pcre_study(access_parse_regex, 0, &eb); + if (eb != NULL) { + SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + goto error; + } + +error: + SCReturn; +} + +#ifdef UNITTESTS /* UNITTESTS */ +#include "detect-engine.h" + +#include "util-unittest.h" + +/** \test Signature containing a function. */ +static int DetectModbusTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus function\"; " + "modbus: function 1; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || + (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + + if (modbus->function != 1) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 1, modbus->function); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a function and a subfunction. */ +static int DetectModbusTest02(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus function and subfunction\"; " + "modbus: function 8, subfunction 4; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || + (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + + if ((modbus->function != 8) || (*modbus->subfunction != 4)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 1, modbus->function); + printf("expected subfunction %" PRIu8 ", got %" PRIu16 ": ", 4, *modbus->subfunction); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a function category. */ +static int DetectModbusTest03(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.function\"; " + "modbus: function reserved; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || + (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + + if (modbus->category != MODBUS_CAT_RESERVED) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", MODBUS_CAT_RESERVED, modbus->category); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a negative function category. */ +static int DetectModbusTest04(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + uint8_t category = ~MODBUS_CAT_PUBLIC_ASSIGNED; + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus function\"; " + "modbus: function !assigned; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || + (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + + if (modbus->category != category) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", ~MODBUS_CAT_PUBLIC_ASSIGNED, modbus->category); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a access type. */ +static int DetectModbusTest05(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.access\"; " + "modbus: access read; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || + (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + + if (modbus->type != MODBUS_TYP_READ) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", MODBUS_TYP_READ, modbus->type); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a access function. */ +static int DetectModbusTest06(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + uint8_t type = (MODBUS_TYP_READ | MODBUS_TYP_DISCRETES); + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.access\"; " + "modbus: access read discretes; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || + (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + + if (modbus->type != type) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a read access at an address. */ +static int DetectModbusTest07(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + DetectModbusMode mode = DETECT_MODBUS_EQ; + + uint8_t type = MODBUS_TYP_READ; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.access\"; " + "modbus: access read, address 1000; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || + (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + + if ((modbus->type != type) || + ((*modbus->address).mode != mode) || + ((*modbus->address).min != 1000)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); + printf("expected mode %" PRIu8 ", got %" PRIu16 ": ", mode, (*modbus->address).mode); + printf("expected address %" PRIu8 ", got %" PRIu16 ": ", 1000, (*modbus->address).min); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a write access at a range of address. */ +static int DetectModbusTest08(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + DetectModbusMode mode = DETECT_MODBUS_GT; + + uint8_t type = (MODBUS_TYP_WRITE | MODBUS_TYP_COILS); + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.access\"; " + "modbus: access write coils, address >500; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || + (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + + if ((modbus->type != type) || + ((*modbus->address).mode != mode) || + ((*modbus->address).min != 500)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); + printf("expected mode %" PRIu8 ", got %" PRIu16 ": ", mode, (*modbus->address).mode); + printf("expected address %" PRIu8 ", got %" PRIu16 ": ", 500, (*modbus->address).min); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a write access at a address a range of value. */ +static int DetectModbusTest09(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + DetectModbusMode addressMode = DETECT_MODBUS_EQ; + DetectModbusMode valueMode = DETECT_MODBUS_RA; + + uint8_t type = (MODBUS_TYP_WRITE | MODBUS_TYP_HOLDING); + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.access\"; " + "modbus: access write holding, address 100, value 500<>1000; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || + (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + + if ((modbus->type != type) || + ((*modbus->address).mode != addressMode) || + ((*modbus->address).min != 100) || + ((*modbus->data).mode != valueMode) || + ((*modbus->data).min != 500) || + ((*modbus->data).max != 1000)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); + printf("expected address mode %" PRIu8 ", got %" PRIu16 ": ", addressMode, (*modbus->address).mode); + printf("expected address %" PRIu8 ", got %" PRIu16 ": ", 500, (*modbus->address).min); + printf("expected value mode %" PRIu8 ", got %" PRIu16 ": ", valueMode, (*modbus->data).mode); + printf("expected min value %" PRIu8 ", got %" PRIu16 ": ", 500, (*modbus->data).min); + printf("expected max value %" PRIu8 ", got %" PRIu16 ": ", 1000, (*modbus->data).max); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for DetectModbus + */ +void DetectModbusRegisterTests(void) { +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("DetectModbusTest01 - Testing function", DetectModbusTest01, 1); + UtRegisterTest("DetectModbusTest02 - Testing function and subfunction", DetectModbusTest02, 1); + UtRegisterTest("DetectModbusTest03 - Testing category function", DetectModbusTest03, 1); + UtRegisterTest("DetectModbusTest04 - Testing category function in negative", DetectModbusTest04, 1); + UtRegisterTest("DetectModbusTest05 - Testing access type", DetectModbusTest05, 1); + UtRegisterTest("DetectModbusTest06 - Testing access function", DetectModbusTest06, 1); + UtRegisterTest("DetectModbusTest07 - Testing access at address", DetectModbusTest07, 1); + UtRegisterTest("DetectModbusTest08 - Testing a range of address", DetectModbusTest08, 1); + UtRegisterTest("DetectModbusTest09 - Testing write a range of value", DetectModbusTest09, 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-modbus.h b/src/detect-modbus.h new file mode 100644 index 000000000000..6675cde8b201 --- /dev/null +++ b/src/detect-modbus.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author David DIALLO + */ + +#ifndef __DETECT_MODBUS_H__ +#define __DETECT_MODBUS_H__ + +#include "app-layer-modbus.h" + +typedef enum { + DETECT_MODBUS_EQ = 0, /** < EQual operator */ + DETECT_MODBUS_LT, /** < "Less Than" operator */ + DETECT_MODBUS_GT, /** < "Greater Than" operator */ + DETECT_MODBUS_RA, /** < RAnge operator */ +} DetectModbusMode; + +typedef struct DetectModbusValue_ { + uint16_t min; /** < Modbus minimum [range] or equal value to match */ + uint16_t max; /** < Modbus maximum value [range] to match */ + DetectModbusMode mode; /** < Modbus operator used in the address/data signature */ +} DetectModbusValue; + +typedef struct DetectModbus_ { + uint8_t category; /** < Modbus function code category to match */ + uint8_t function; /** < Modbus function code to match */ + uint16_t *subfunction; /** < Modbus subfunction to match */ + uint8_t type; /** < Modbus access type to match */ + DetectModbusValue *address; /** < Modbus address to match */ + DetectModbusValue *data; /** < Modbus data to match */ +} DetectModbus; + +/* prototypes */ +void DetectModbusRegister (void); + +#endif /* __DETECT_MODBUS_H__ */ diff --git a/src/detect-parse.c b/src/detect-parse.c index b19c2b7e3656..8145b2c1abb1 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1461,6 +1461,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_DNSQUERY_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_MODBUS_MATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_APP_EVENT]) sig->flags |= SIG_FLAG_STATE_MATCH; diff --git a/src/detect.c b/src/detect.c index f4f0d54e3daa..737bb3409c7f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -165,6 +165,7 @@ #include "detect-http-stat-code.h" #include "detect-ssl-version.h" #include "detect-ssl-state.h" +#include "detect-modbus.h" #include "action-globals.h" #include "tm-threads.h" @@ -4813,6 +4814,7 @@ void SigTableSetup(void) DetectLuaRegister(); DetectIPRepRegister(); DetectDnsQueryRegister(); + DetectModbusRegister(); DetectAppLayerProtocolRegister(); } diff --git a/src/detect.h b/src/detect.h index cc23fe3028d4..df2690d290e1 100644 --- a/src/detect.h +++ b/src/detect.h @@ -121,6 +121,7 @@ enum DetectSigmatchListEnum { 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, @@ -1149,6 +1150,7 @@ enum { DETECT_IPREP, DETECT_AL_DNS_QUERY, + DETECT_AL_MODBUS, /* make sure this stays last */ DETECT_TBLSIZE, From 55c50812407556c1276c3e6b6f7e98e869427214 Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Tue, 22 Jul 2014 09:49:58 +0200 Subject: [PATCH 0061/2553] Detect-engine: Add Modbus detection engine Management of Modbus Tx Based on DNS source code. Signed-off-by: David DIALLO --- src/Makefile.am | 1 + src/detect-engine-modbus.c | 1345 ++++++++++++++++++++++++++++++++++++ src/detect-engine-modbus.h | 41 ++ src/detect-engine-state.h | 1 + src/detect-engine.c | 19 +- src/runmode-unittests.c | 2 + 6 files changed, 1408 insertions(+), 1 deletion(-) create mode 100644 src/detect-engine-modbus.c create mode 100644 src/detect-engine-modbus.h diff --git a/src/Makefile.am b/src/Makefile.am index 407018119a3d..d788afdc576f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -92,6 +92,7 @@ detect-engine.c detect-engine.h \ detect-engine-content-inspection.c detect-engine-content-inspection.h \ detect-engine-dcepayload.c detect-engine-dcepayload.h \ detect-engine-dns.c detect-engine-dns.h \ +detect-engine-modbus.c detect-engine-modbus.h \ detect-engine-event.c detect-engine-event.h \ detect-engine-file.c detect-engine-file.h \ detect-engine-hcbd.c detect-engine-hcbd.h \ diff --git a/src/detect-engine-modbus.c b/src/detect-engine-modbus.c new file mode 100644 index 000000000000..cced4966341a --- /dev/null +++ b/src/detect-engine-modbus.c @@ -0,0 +1,1345 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file + * + * \author David DIALLO + * + * Based on detect-engine-dns.c + */ + +#include "suricata-common.h" + +#include "app-layer.h" +#include "app-layer-modbus.h" + +#include "detect.h" +#include "detect-modbus.h" + +#include "detect-engine-modbus.h" + +#include "flow.h" + +#include "util-debug.h" + +/** \internal + * + * \brief Value match detection code + * + * \param value Modbus value context (min, max and mode) + * \param min Minimum value to compare + * \param inter Interval or maximum (min + inter) value to compare + * + * \retval 1 match or 0 no match + */ +static int DetectEngineInspectModbusValueMatch(DetectModbusValue *value, + uint16_t min, + uint16_t inter) +{ + SCEnter(); + uint16_t max = min + inter; + + int ret = 0; + + switch (value->mode) { + case DETECT_MODBUS_EQ: + if ((value->min >= min) && (value->min <= max)) + ret = 1; + break; + + case DETECT_MODBUS_LT: + if (value->min > min) + ret = 1; + break; + + case DETECT_MODBUS_GT: + if (value->min < max) + ret = 1; + break; + + case DETECT_MODBUS_RA: + if ((value->max > min) && (value->min < max)) + ret = 1; + break; + } + + SCReturnInt(ret); +} + +/** \internal + * + * \brief Do data (and address) inspection & validation for a signature + * + * \param tx Pointer to Modbus Transaction + * \param address Address inspection + * \param data Pointer to data signature structure to match + * + * \retval 0 no match or 1 match + */ +static int DetectEngineInspectModbusData(ModbusTransaction *tx, + uint16_t address, + DetectModbusValue *data) +{ + SCEnter(); + uint16_t offset, value = 0, type = tx->type; + + if (type & MODBUS_TYP_SINGLE) { + /* Output/Register(s) Value */ + if (type & MODBUS_TYP_COILS) + value = (tx->data[0])? 1 : 0; + else + value = tx->data[0]; + } else if (type & MODBUS_TYP_MULTIPLE) { + int i, size = (int) sizeof(tx->data); + + offset = address - (tx->write.address + 1); + + /* In case of Coils, offset is in bit (convert in byte) */ + if (type & MODBUS_TYP_COILS) + offset >>= 3; + + for (i=0; i< size; i++) { + /* Select the correct register/coils amongst the output value */ + if (!(offset--)) { + value = tx->data[i]; + break; + } + } + + /* In case of Coils, offset is now in the bit is the rest of previous convert */ + if (type & MODBUS_TYP_COILS) { + offset = (address - (tx->write.address + 1)) & 0x7; + value = (value >> offset) & 0x1; + } + } else { + /* It is not possible to define the value that is writing for Mask */ + /* Write Register function because the current content is not available.*/ + SCReturnInt(0); + } + + SCReturnInt(DetectEngineInspectModbusValueMatch(data, value, 0)); +} + +/** \internal + * + * \brief Do address inspection & validation for a signature + * + * \param tx Pointer to Modbus Transaction + * \param address Pointer to address signature structure to match + * \param access Access mode (READ or WRITE) + * + * \retval 0 no match or 1 match + */ +static int DetectEngineInspectModbusAddress(ModbusTransaction *tx, + DetectModbusValue *address, + uint8_t access) +{ + SCEnter(); + int ret = 0; + + /* Check if read/write address of request is at/in the address range of signature */ + if (access == MODBUS_TYP_READ) { + /* In the PDU Coils are addresses starting at zero */ + /* therefore Coils numbered 1-16 are addressed as 0-15 */ + ret = DetectEngineInspectModbusValueMatch(address, + tx->read.address + 1, + tx->read.quantity - 1); + } else { + /* In the PDU Registers are addresses starting at zero */ + /* therefore Registers numbered 1-16 are addressed as 0-15 */ + if (tx->type & MODBUS_TYP_SINGLE) + ret = DetectEngineInspectModbusValueMatch(address, + tx->write.address + 1, + 0); + else + ret = DetectEngineInspectModbusValueMatch(address, + tx->write.address + 1, + tx->write.quantity - 1); + } + + SCReturnInt(ret); +} + +/** \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect ( and sm: SigMatch to inspect) + * \param f Flow + * \param flags App layer flags + * \param alstate App layer state + * \param txv Pointer to Modbus Transaction structure + * + * \retval 0 no match or 1 match + */ +int DetectEngineInspectModbus(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, + Flow *f, + uint8_t flags, + void *alstate, + void *txv, + uint64_t tx_id) +{ + SCEnter(); + ModbusTransaction *tx = (ModbusTransaction *)txv; + SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MODBUS_MATCH]; + DetectModbus *modbus = (DetectModbus *) sm->ctx; + + int ret = 0; + + if (modbus == NULL) { + SCLogDebug("no modbus state, no match"); + SCReturnInt(0); + } + + if (modbus->type == MODBUS_TYP_NONE) { + if (modbus->category == MODBUS_CAT_NONE) { + if (modbus->function == tx->function) { + if (modbus->subfunction != NULL) { + SCLogDebug("looking for Modbus server function %d and subfunction %d", + modbus->function, *(modbus->subfunction)); + ret = (*(modbus->subfunction) == (tx->subFunction))? 1 : 0; + } else { + SCLogDebug("looking for Modbus server function %d", modbus->function); + ret = 1; + } + } + } else { + SCLogDebug("looking for Modbus category function %d", modbus->category); + ret = (tx->category & modbus->category)? 1 : 0; + } + } else { + uint8_t access = modbus->type & MODBUS_TYP_ACCESS_MASK; + uint8_t function = modbus->type & MODBUS_TYP_ACCESS_FUNCTION_MASK; + + if ((access & tx->type) && ((function == MODBUS_TYP_NONE) || (function & tx->type))) { + if (modbus->address != NULL) { + ret = DetectEngineInspectModbusAddress(tx, modbus->address, access); + + if (ret && (modbus->data != NULL)) { + ret = DetectEngineInspectModbusData(tx, modbus->address->min, modbus->data); + } + } else { + SCLogDebug("looking for Modbus access type %d and function type %d", access, function); + ret = 1; + } + } + } + + SCReturnInt(ret); +} + +#ifdef UNITTESTS /* UNITTESTS */ +#include "app-layer-parser.h" + +#include "detect-parse.h" + +#include "detect-engine.h" + +#include "flow-util.h" + +#include "stream-tcp.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */ +/* Example of a request to read discrete outputs 20-38 */ +static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Starting Address */ 0x78, 0x90, + /* Quantity of coils */ 0x00, 0x13 }; + +/* Modbus Application Protocol Specification V1.1b3 6.4: Read Input Registers */ +/* Example of a request to read input register 9 */ +static uint8_t readInputsRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x05, + /* Unit ID */ 0x00, + /* Function code */ 0x04, + /* Starting Address */ 0x00, 0x08, + /* Quantity of Registers */ 0x00, 0x60}; + +/* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */ +/* Example of a request to read six registers starting at register 4, */ +/* and to write three registers starting at register 15 */ +static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x11, + /* Unit ID */ 0x00, + /* Function code */ 0x17, + /* Read Starting Address */ 0x00, 0x03, + /* Quantity to Read */ 0x00, 0x06, + /* Write Starting Address */ 0x00, 0x0E, + /* Quantity to Write */ 0x00, 0x03, + /* Write Byte count */ 0x06, + /* Write Registers Value */ 0x12, 0x34, /* 15 */ + 0x56, 0x78, /* 16 */ + 0x9A, 0xBC};/* 17 */ + +/* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */ +/* Example of a request to to remote device to its Listen Only MOde for Modbus Communications. */ +static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x08, + /* Sub-function code */ 0x00, 0x04, + /* Data */ 0x00, 0x00}; + +/* Modbus Application Protocol Specification V1.1b3 Annex A */ +/* Modbus Reserved Function codes, Subcodes and MEI types */ +static uint8_t encapsulatedInterfaceTransport[] = { + /* Transaction ID */ 0x00, 0x10, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x05, + /* Unit ID */ 0x00, + /* Function code */ 0x2B, + /* MEI Type */ 0x0F, + /* Data */ 0x00, 0x00}; + +static uint8_t unassigned[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x02, + /* Unit ID */ 0x00, + /* Function code */ 0x12}; + +/** \test Test code function. */ +static int DetectEngineInspectModbusTest01(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus code function\"; " + "modbus: function 23; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readWriteMultipleRegistersReq, sizeof(readWriteMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test code function and code subfunction. */ +static int DetectEngineInspectModbusTest02(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus function and subfunction\"; " + "modbus: function 8, subfunction 4; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, forceListenOnlyMode, sizeof(forceListenOnlyMode)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test function category. */ +static int DetectEngineInspectModbusTest03(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus category function\"; " + "modbus: function reserved; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + encapsulatedInterfaceTransport, sizeof(encapsulatedInterfaceTransport)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test negative function category. */ +static int DetectEngineInspectModbusTest04(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus category function\"; " + "modbus: function !assigned; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, unassigned, sizeof(unassigned)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test access type. */ +static int DetectEngineInspectModbusTest05(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access type\"; " + "modbus: access read; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readCoilsReq, sizeof(readCoilsReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test access function. */ +static int DetectEngineInspectModbusTest06(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access type\"; " + "modbus: access read input; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readInputsRegistersReq, sizeof(readInputsRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test read access at an address. */ +static int DetectEngineInspectModbusTest07(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus address access\"; " + "modbus: access read, address 30870; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readCoilsReq, sizeof(readCoilsReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test read access at a range of address. */ +static int DetectEngineInspectModbusTest08(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + /* readInputsRegistersReq, Starting Address = 0x08, Quantity of Registers = 0x60 */ + /* Read access address from 9 to 104 */ + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address <9; sid:1;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 9; sid:2;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 5<>9; sid:3;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address <10; sid:4;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 5<>10; sid:5;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address >103; sid:6;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 103<>110; sid:7;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 104; sid:8;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address >104; sid:9;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 104<>110; sid:10;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readInputsRegistersReq, sizeof(readInputsRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 did match but should not have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 2))) { + printf("sid 2 didn't match but should have: "); + goto end; + } + + if (PacketAlertCheck(p, 3)) { + printf("sid 3 did match but should not have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 4))) { + printf("sid 4 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 5))) { + printf("sid 5 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 6))) { + printf("sid 6 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 7))) { + printf("sid 7 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 8))) { + printf("sid 8 didn't match but should have: "); + goto end; + } + + if (PacketAlertCheck(p, 9)) { + printf("sid 9 did match but should not have: "); + goto end; + } + + if (PacketAlertCheck(p, 10)) { + printf("sid 10 did match but should not have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test write access at a address in a range of value. */ +static int DetectEngineInspectModbusTest09(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + /* readWriteMultipleRegistersReq, Write Starting Address = 0x0E, Quantity to Write = 0x03 */ + /* Write access register address 15 = 0x1234 (4660) */ + /* Write access register address 16 = 0x5678 (22136) */ + /* Write access register address 17 = 0x9ABC (39612) */ + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 15, value <4660; sid:1;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 16, value <22137; sid:2;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 17, value 39612; sid:3;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 15, value 4661; sid:4;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 16, value 20000<>22136; sid:5;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 17, value 30000<>39613; sid:6;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 15, value 4659<>5000; sid:7;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 16, value 22136<>30000; sid:8;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 17, value >39611; sid:9;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 15, value >4660; sid:10;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readWriteMultipleRegistersReq, sizeof(readWriteMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 did match but should not have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 2))) { + printf("sid 2 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 3))) { + printf("sid 3 didn't match but should have: "); + goto end; + } + + if (PacketAlertCheck(p, 4)) { + printf("sid 4 did match but should not have: "); + goto end; + } + + if (PacketAlertCheck(p, 5)) { + printf("sid 5 did match but should not have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 6))) { + printf("sid 6 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 7))) { + printf("sid 7 didn't match but should have: "); + goto end; + } + + if (PacketAlertCheck(p, 8)) { + printf("sid 8 did match but should not have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 9))) { + printf("sid 9 didn't match but should have: "); + goto end; + } + + if (PacketAlertCheck(p, 10)) { + printf("sid 10 did match but should not have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} +#endif /* UNITTESTS */ + +void DetectEngineInspectModbusRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectEngineInspectModbusTest01 - Code function", DetectEngineInspectModbusTest01, 1); + UtRegisterTest("DetectEngineInspectModbusTest02 - code function and code subfunction", DetectEngineInspectModbusTest02, 1); + UtRegisterTest("DetectEngineInspectModbusTest03 - Function category", DetectEngineInspectModbusTest03, 1); + UtRegisterTest("DetectEngineInspectModbusTest04 - Negative function category", DetectEngineInspectModbusTest04, 1); + UtRegisterTest("DetectEngineInspectModbusTest05 - Access type", DetectEngineInspectModbusTest05, 1); + UtRegisterTest("DetectEngineInspectModbusTest06 - Access function", DetectEngineInspectModbusTest06, 1); + UtRegisterTest("DetectEngineInspectModbusTest07 - Read access at an address", DetectEngineInspectModbusTest07, 1); + UtRegisterTest("DetectEngineInspectModbusTest08 - Read access at a range of address", DetectEngineInspectModbusTest08, 1); + UtRegisterTest("DetectEngineInspectModbusTest09 - Write access at an address a range of value", DetectEngineInspectModbusTest09, 1); +#endif /* UNITTESTS */ + return; +} diff --git a/src/detect-engine-modbus.h b/src/detect-engine-modbus.h new file mode 100644 index 000000000000..e140f975a5ec --- /dev/null +++ b/src/detect-engine-modbus.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file + * + * \author David DIALLO + */ + +#ifndef __DETECT_ENGINE_MODBUS_H__ +#define __DETECT_ENGINE_MODBUS_H__ + +int DetectEngineInspectModbus(ThreadVars *, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *, Signature *, + Flow *, uint8_t, void *, void *, uint64_t); + +void DetectEngineInspectModbusRegisterTests(void); +#endif /* __DETECT_ENGINE_MODBUS_H__ */ diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index cd3e63ea4c35..9f497551185f 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -76,6 +76,7 @@ #define DE_STATE_FLAG_SIG_CANT_MATCH (1 << 16) #define DE_STATE_FLAG_DNSQUERY_INSPECT (1 << 17) #define DE_STATE_FLAG_APP_EVENT_INSPECT (1 << 18) +#define DE_STATE_FLAG_MODBUS_INSPECT (1 << 19) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine.c b/src/detect-engine.c index d9655762aa39..11f117addaff 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -59,6 +59,7 @@ #include "detect-engine-hrhhd.h" #include "detect-engine-file.h" #include "detect-engine-dns.h" +#include "detect-engine-modbus.h" #include "detect-engine.h" #include "detect-engine-state.h" @@ -254,6 +255,14 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_FILE_TS_INSPECT, 0, DetectFileInspectSmtp }, + /* Modbus */ + { IPPROTO_TCP, + ALPROTO_MODBUS, + DETECT_SM_LIST_MODBUS_MATCH, + DE_STATE_FLAG_MODBUS_INSPECT, + DE_STATE_FLAG_MODBUS_INSPECT, + 0, + DetectEngineInspectModbus }, }; struct tmp_t data_toclient[] = { @@ -305,7 +314,15 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_HSCD_INSPECT, DE_STATE_FLAG_HSCD_INSPECT, 1, - DetectEngineInspectHttpStatCode } + DetectEngineInspectHttpStatCode }, + /* Modbus */ + { IPPROTO_TCP, + ALPROTO_MODBUS, + DETECT_SM_LIST_MODBUS_MATCH, + DE_STATE_FLAG_MODBUS_INSPECT, + DE_STATE_FLAG_MODBUS_INSPECT, + 0, + DetectEngineInspectModbus } }; size_t i; diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 479e1323d479..d77f78b6892e 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -50,6 +50,7 @@ #include "detect-engine-hrhhd.h" #include "detect-engine-state.h" #include "detect-engine-tag.h" +#include "detect-engine-modbus.h" #include "detect-fast-pattern.h" #include "flow.h" #include "flow-timeout.h" @@ -249,6 +250,7 @@ void RunUnittests(int list_unittests, char *regex_arg) DetectEngineHttpUARegisterTests(); DetectEngineHttpHHRegisterTests(); DetectEngineHttpHRHRegisterTests(); + DetectEngineInspectModbusRegisterTests(); DetectEngineRegisterTests(); SCLogRegisterTests(); MagicRegisterTests(); From ff41c1c452cdc88eed329c57f40f759cc25c4a96 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Wed, 5 Nov 2014 15:07:06 -0500 Subject: [PATCH 0062/2553] Correct size increase in SigGroupHeadStore() The code was increasing the size of the allocated memory by 16, but only increasing the stored size by 10. Now uses one variable for both places. --- src/detect-engine-siggroup.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 1a6cdcb97815..9c41831e07b7 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -125,8 +125,9 @@ void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh) if (de_ctx->sgh_array_cnt < de_ctx->sgh_array_size) { de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh; } else { + int increase = 16; ptmp = SCRealloc(de_ctx->sgh_array, - sizeof(SigGroupHead *) * (16 + de_ctx->sgh_array_size)); + sizeof(SigGroupHead *) * (increase + de_ctx->sgh_array_size)); if (ptmp == NULL) { SCFree(de_ctx->sgh_array); de_ctx->sgh_array = NULL; @@ -134,7 +135,7 @@ void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh) } de_ctx->sgh_array = ptmp; - de_ctx->sgh_array_size += 10; + de_ctx->sgh_array_size += increase; de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh; } de_ctx->sgh_array_cnt++; From 18e2de320b2ddde0d18d0ec4c5501e249e1ea2ea Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 7 Nov 2014 10:50:23 -0500 Subject: [PATCH 0063/2553] Coding style cleanup in detect-modbus files. --- src/detect-modbus.c | 6 ++++-- src/detect-modbus.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/detect-modbus.c b/src/detect-modbus.c index 4c23e348106b..306ca001a8d5 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -398,7 +398,8 @@ static int DetectModbusSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) /** * \brief Registration function for Modbus keyword */ -void DetectModbusRegister(void) { +void DetectModbusRegister(void) +{ SCEnter(); sigmatch_table[DETECT_AL_MODBUS].name = "modbus"; sigmatch_table[DETECT_AL_MODBUS].Match = NULL; @@ -880,7 +881,8 @@ static int DetectModbusTest09(void) /** * \brief this function registers unit tests for DetectModbus */ -void DetectModbusRegisterTests(void) { +void DetectModbusRegisterTests(void) +{ #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectModbusTest01 - Testing function", DetectModbusTest01, 1); UtRegisterTest("DetectModbusTest02 - Testing function and subfunction", DetectModbusTest02, 1); diff --git a/src/detect-modbus.h b/src/detect-modbus.h index 6675cde8b201..408fb7aff809 100644 --- a/src/detect-modbus.h +++ b/src/detect-modbus.h @@ -59,6 +59,6 @@ typedef struct DetectModbus_ { } DetectModbus; /* prototypes */ -void DetectModbusRegister (void); +void DetectModbusRegister(void); #endif /* __DETECT_MODBUS_H__ */ From 5cdb21ec34b20b72d457055470cae485201a002e Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 7 Nov 2014 11:33:38 -0500 Subject: [PATCH 0064/2553] Remove an unused define COUNTER_DETECT_ALERTS The only place this exists in the code is when it is defined. --- src/detect.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/detect.h b/src/detect.h index df2690d290e1..04ea0d8b0167 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* 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 @@ -43,8 +43,6 @@ #include "detect-mark.h" -#define COUNTER_DETECT_ALERTS 1 - #define DETECT_MAX_RULE_SIZE 8192 /* forward declarations for the structures from detect-engine-sigorder.h */ From fa72082491d9e0c3241c5b3f3001a30d5ab0c5a6 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Mon, 10 Nov 2014 14:46:11 -0500 Subject: [PATCH 0065/2553] Don't write target.tvar.idx in DetectFlowintParse Match functions should not be writing to the SigMatch context. So just use a local variable instead. --- src/detect-flowint.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 6ae36551d58d..5c3bc193a83d 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -121,9 +121,9 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, * return zero(not match). */ if (sfd->targettype == FLOWINT_TARGET_VAR) { - sfd->target.tvar.idx = VariableNameGetIdx(det_ctx->de_ctx, sfd->target.tvar.name, DETECT_FLOWINT); + uint16_t tvar_idx = VariableNameGetIdx(det_ctx->de_ctx, sfd->target.tvar.name, DETECT_FLOWINT); - fvt = FlowVarGet(p->flow, sfd->target.tvar.idx); + fvt = FlowVarGet(p->flow, tvar_idx); /* We don't have that variable initialized yet */ if (fvt == NULL) targetval = 0; @@ -451,8 +451,8 @@ void DetectFlowintPrintData(DetectFlowintData *sfd) sfd->name, sfd->modifier, sfd->idx); switch(sfd->targettype) { case FLOWINT_TARGET_VAR: - SCLogDebug("target_var: %s, target_idx: %"PRIu16, - sfd->target.tvar.name, sfd->target.tvar.idx); + SCLogDebug("target_var: %s", + sfd->target.tvar.name); break; case FLOWINT_TARGET_VAL: SCLogDebug("Value: %"PRIu32"; ", sfd->target.value); From c547d391523b761c67ebd0524ab603e5d8e7bdcc Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Mon, 10 Nov 2014 14:48:29 -0500 Subject: [PATCH 0066/2553] Fix bug in DetectFlowintParse() - Assigning to both parts of a Union sfd->target.value was always being set, even if the targettype was not FLOWINT_TARGET_VAL. This would cause the tvar to be overwritten with garbage data. --- src/detect-flowint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 5c3bc193a83d..fae82cc4bd97 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -322,6 +322,7 @@ DetectFlowintData *DetectFlowintParse(DetectEngineCtx *de_ctx, char *rawstr) " Values should be between 0 and %"PRIu32, UINT32_MAX); goto error; } + sfd->target.value = (uint32_t) value_long; } else { sfd->targettype = FLOWINT_TARGET_VAR; sfd->target.tvar.name = SCStrdup(varval); @@ -342,7 +343,6 @@ DetectFlowintData *DetectFlowintParse(DetectEngineCtx *de_ctx, char *rawstr) } if (de_ctx != NULL) sfd->idx = VariableNameGetIdx(de_ctx, varname, DETECT_FLOWINT); - sfd->target.value = (uint32_t) value_long; sfd->modifier = modifier; pcre_free_substring(varname); From e6f83a586c13e2dda6eb52dac00d60684bf46919 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Mon, 10 Nov 2014 15:01:36 -0500 Subject: [PATCH 0067/2553] DetectFlowintData - remove unused idx in TargetVar. The idx inside TargetVar inside DetectFlowintData is never used, so remove it. --- src/detect-flowint.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/detect-flowint.h b/src/detect-flowint.h index 973321ad0df7..1c433e23e0de 100644 --- a/src/detect-flowint.h +++ b/src/detect-flowint.h @@ -55,7 +55,6 @@ enum { /** If the target is another var, get the name and the idx */ typedef struct TargetVar_ { - uint16_t idx; char *name; } TargetVar; From 8dcd99209e4468c18960e983d24e61fe15373b1d Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Mon, 10 Nov 2014 15:07:34 -0500 Subject: [PATCH 0068/2553] Update copyright year in detect-flowbits files. --- src/detect-flowint.c | 2 +- src/detect-flowint.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-flowint.c b/src/detect-flowint.c index fae82cc4bd97..5da2fb88eda1 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* 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 diff --git a/src/detect-flowint.h b/src/detect-flowint.h index 1c433e23e0de..9a18efd50d31 100644 --- a/src/detect-flowint.h +++ b/src/detect-flowint.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* 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 From 16941468ceb4f7b33ce7a7873406c04106ce650a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Nov 2014 16:46:21 +0100 Subject: [PATCH 0069/2553] lua: in streaming api, indicate open/close The SCStreamingBuffer call now also returns two booleans: data, data_open, data_close = SCStreamingBuffer() The first indicates this is the first data of this type for this TCP session or HTTP transaction. The second indicates this is the last data. Ticket #1317. --- src/util-lua-common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util-lua-common.c b/src/util-lua-common.c index 54c236de87d3..82013485f2e3 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -113,7 +113,9 @@ static int LuaCallbackStreamingBufferPushToStack(lua_State *luastate, const LuaS { //PrintRawDataFp(stdout, (uint8_t *)b->data, b->data_len); lua_pushlstring (luastate, (const char *)b->data, b->data_len); - return 1; + lua_pushboolean (luastate, (b->flags & OUTPUT_STREAMING_FLAG_OPEN)); + lua_pushboolean (luastate, (b->flags & OUTPUT_STREAMING_FLAG_CLOSE)); + return 3; } /** \internal From 1ad2a231fea2c75fc9396ab305a2319054425f83 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Wed, 5 Nov 2014 12:16:18 +0100 Subject: [PATCH 0070/2553] pfring: fixes memleaks This fixes some memory leaks Bug #1184 --- src/source-pfring.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/source-pfring.c b/src/source-pfring.c index fb4aed73a7c1..6f483ff741d4 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -406,12 +406,14 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->interface = SCStrdup(pfconf->iface); if (unlikely(ptv->interface == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate device string"); + SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } ptv->livedev = LiveGetDevice(pfconf->iface); if (ptv->livedev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); + SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } @@ -443,6 +445,7 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->interface, ptv->interface); pfconf->DerefFunc(pfconf); + SCFree(ptv); return TM_ECODE_FAILED; } else { pfring_set_application_name(ptv->pd, PROG_NAME); From ee8da21e3626bc02b878a0523f9f6294d134ff05 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 1 Dec 2014 10:36:52 +0100 Subject: [PATCH 0071/2553] pcre: fix var capture for non relative matches Var capture setup depended on the match being relative due to a logic error. --- src/detect-pcre.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index d87bc5cb0555..1c649f21ff18 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -737,6 +737,11 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst sm->ctx = (void *)pd; SigMatchAppendSMToList(s, sm, sm_list); + if (pd->capidx != 0) { + if (DetectFlowvarPostMatchSetup(s, pd->capidx) < 0) + goto error_nofree; + } + if (!(pd->flags & DETECT_PCRE_RELATIVE)) goto okay; @@ -760,11 +765,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst tmp->flags |= DETECT_PCRE_RELATIVE_NEXT; } - if (pd->capidx != 0) { - if (DetectFlowvarPostMatchSetup(s, pd->capidx) < 0) - goto error_nofree; - } - okay: ret = 0; SCReturnInt(ret); From e98346b555b39e689a1c2c6d0e643d0846ff61f6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 31 Oct 2014 23:37:04 +0100 Subject: [PATCH 0072/2553] Introduce stats log API, convert existing output Convert regular 'stats.log' output to this new API. In addition to the current stats value, also give the last value. This makes it easy to display the difference. --- src/Makefile.am | 2 + src/counters.c | 317 +++++++++++++++------------------------- src/counters.h | 21 --- src/log-stats.c | 231 +++++++++++++++++++++++++++++ src/log-stats.h | 29 ++++ src/output-stats.c | 234 +++++++++++++++++++++++++++++ src/output-stats.h | 53 +++++++ src/output.c | 70 +++++++++ src/output.h | 8 + src/runmodes.c | 9 +- src/suricata.c | 4 + src/tm-modules.c | 2 + src/tm-threads-common.h | 2 + 13 files changed, 757 insertions(+), 225 deletions(-) create mode 100644 src/log-stats.c create mode 100644 src/log-stats.h create mode 100644 src/output-stats.c create mode 100644 src/output-stats.h diff --git a/src/Makefile.am b/src/Makefile.am index d788afdc576f..6fac36e750bc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -215,6 +215,7 @@ log-file.c log-file.h \ log-filestore.c log-filestore.h \ log-httplog.c log-httplog.h \ log-pcap.c log-pcap.h \ +log-stats.c log-stats.h \ log-tcp-data.c log-tcp-data.h \ log-tlslog.c log-tlslog.h \ output.c output.h \ @@ -234,6 +235,7 @@ output-json-ssh.c output-json-ssh.h \ output-json-tls.c output-json-tls.h \ output-lua.c output-lua.h \ output-packet.c output-packet.h \ +output-stats.c output-stats.h \ output-streaming.c output-streaming.h \ output-tx.c output-tx.h \ output-json.c output-json.h \ diff --git a/src/counters.c b/src/counters.c index 9aae1fe52d9e..5ea17c55e2cb 100644 --- a/src/counters.c +++ b/src/counters.c @@ -19,6 +19,7 @@ * \file * * \author Anoop Saldanha + * \author Victor Julien * * Performance counters */ @@ -43,14 +44,33 @@ /* Used to parse the interval for Timebased counters */ #define SC_PERF_PCRE_TIMEBASED_INTERVAL "^(?:(\\d+)([shm]))(?:(\\d+)([shm]))?(?:(\\d+)([shm]))?$" +/* Time interval for syncing the local counters with the global ones */ +#define SC_PERF_WUT_TTS 3 + +/* Time interval at which the mgmt thread o/p the stats */ +#define SC_PERF_MGMTT_TTS 8 + +static void *stats_thread_data = NULL; static SCPerfOPIfaceContext *sc_perf_op_ctx = NULL; static time_t sc_start_time; /** refresh interval in seconds */ static uint32_t sc_counter_tts = SC_PERF_MGMTT_TTS; /** is the stats counter enabled? */ static char sc_counter_enabled = TRUE; -/** append or overwrite? 1: append, 0: overwrite */ -static char sc_counter_append = TRUE; + +static int SCPerfOutputCounterFileIface(ThreadVars *tv); + +/** stats table is filled each interval and passed to the + * loggers. Initialized at first use. */ +static StatsTable stats_table = { NULL, 0, 0, {0 , 0}}; + +/** + * \brief The output interface dispatcher for the counter api + */ +void SCPerfOutputCounters(ThreadVars *tv) +{ + SCPerfOutputCounterFileIface(tv); +} /** * \brief Adds a value of type uint64_t to the local counter. @@ -126,65 +146,6 @@ void SCPerfCounterSetUI64(uint16_t id, SCPerfCounterArray *pca, return; } -/** - * \brief Get the filename with path to the stats log file. - * - * This function returns a string containing the log filename. It uses - * allocated memory simply to drop into the existing code a little better - * where a SCStrdup was used. So as before, it is up to the caller to free - * the memory. - * - * \retval An allocated string containing the log filename on success or NULL on - * failure. - */ -static char *SCPerfGetLogFilename(ConfNode *stats) -{ - char *log_dir = NULL; - char *log_filename = NULL; - const char* filename = NULL; - - log_dir = ConfigGetLogDirectory(); - - if ( (log_filename = SCMalloc(PATH_MAX)) == NULL) { - return NULL; - } - - if (stats != NULL) { - filename = ConfNodeLookupChildValue(stats, "filename"); - if (filename == NULL) { - filename = SC_PERF_DEFAULT_LOG_FILENAME; - } - } else { - filename = SC_PERF_DEFAULT_LOG_FILENAME; - } - - if (snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, - filename) < 0) { - SCLogError(SC_ERR_SPRINTF, "Sprintf Error"); - SCFree(log_filename); - return NULL; - } - - return log_filename; -} - -/** - * \brief Reopen the log file. - * - * \retval 1 if successful, otherwise 0. - */ -static int SCPerfFileReopen(SCPerfOPIfaceContext *sc_perf_op_ctx) -{ - fclose(sc_perf_op_ctx->fp); - if ((sc_perf_op_ctx->fp = fopen(sc_perf_op_ctx->file, "w+")) == NULL) { - SCLogError(SC_ERR_FOPEN, "Failed to reopen file \"%s\"." - "Stats logging will now be disabled.", - sc_perf_op_ctx->file); - return 0; - } - return 1; -} - /** * \brief Initializes the output interface context * @@ -193,73 +154,14 @@ static int SCPerfFileReopen(SCPerfOPIfaceContext *sc_perf_op_ctx) static void SCPerfInitOPCtx(void) { SCEnter(); - - ConfNode *root = ConfGetNode("outputs"); - ConfNode *node = NULL; - ConfNode *stats = NULL; - if (root != NULL) { - TAILQ_FOREACH(node, &root->head, next) { - if (strncmp(node->val, "stats", 5) == 0) { - stats = node->head.tqh_first; - } - } - } - /* Check if the stats module is enabled or not */ - if (stats != NULL) { - const char *enabled = ConfNodeLookupChildValue(stats, "enabled"); - if (enabled != NULL && ConfValIsFalse(enabled)) { - sc_counter_enabled = FALSE; - SCLogDebug("Stats module has been disabled"); - SCReturn; - } - const char *interval = ConfNodeLookupChildValue(stats, "interval"); - if (interval != NULL) - sc_counter_tts = (uint32_t) atoi(interval); - - const char *append = ConfNodeLookupChildValue(stats, "append"); - if (append != NULL) - sc_counter_append = ConfValIsTrue(append); - } - - /* Store the engine start time */ - time(&sc_start_time); - if ( (sc_perf_op_ctx = SCMalloc(sizeof(SCPerfOPIfaceContext))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCPerfInitOPCtx. Exiting..."); exit(EXIT_FAILURE); } memset(sc_perf_op_ctx, 0, sizeof(SCPerfOPIfaceContext)); - sc_perf_op_ctx->iface = SC_PERF_IFACE_FILE; - - if ( (sc_perf_op_ctx->file = SCPerfGetLogFilename(stats)) == NULL) { - SCLogInfo("Error retrieving Perf Counter API output file path"); - } - - char *mode; - if (sc_counter_append) - mode = "a+"; - else - mode = "w+"; - - if ( (sc_perf_op_ctx->fp = fopen(sc_perf_op_ctx->file, mode)) == NULL) { - SCLogError(SC_ERR_FOPEN, "fopen error opening file \"%s\". Resorting " - "to using the standard output for output", - sc_perf_op_ctx->file); - - SCFree(sc_perf_op_ctx->file); - - /* Let us use the standard output for output */ - sc_perf_op_ctx->fp = stdout; - if ( (sc_perf_op_ctx->file = SCStrdup("stdout")) == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - } - else { - /* File opened, register for rotation notification. */ - OutputRegisterFileRotationFlag(&sc_perf_op_ctx->rotation_flag); - } + /* Store the engine start time */ + time(&sc_start_time); /* init the lock used by SCPerfClubTMInst */ if (SCMutexInit(&sc_perf_op_ctx->pctmi_lock, NULL) != 0) { @@ -285,14 +187,6 @@ static void SCPerfReleaseOPCtx() SCPerfClubTMInst *temp = NULL; pctmi = sc_perf_op_ctx->pctmi; - OutputUnregisterFileRotationFlag(&sc_perf_op_ctx->rotation_flag); - - if (sc_perf_op_ctx->fp != NULL) - fclose(sc_perf_op_ctx->fp); - - if (sc_perf_op_ctx->file != NULL) - SCFree(sc_perf_op_ctx->file); - while (pctmi != NULL) { if (pctmi->tm_name != NULL) SCFree(pctmi->tm_name); @@ -308,6 +202,12 @@ static void SCPerfReleaseOPCtx() SCFree(sc_perf_op_ctx); sc_perf_op_ctx = NULL; + /* free stats table */ + if (stats_table.stats != NULL) { + SCFree(stats_table.stats); + memset(&stats_table, 0, sizeof(stats_table)); + } + return; } @@ -349,6 +249,17 @@ static void *SCPerfMgmtThread(void *arg) return NULL; } + TmModule *tm = &tmm_modules[TMM_STATSLOGGER]; + BUG_ON(tm->ThreadInit == NULL); + int r = tm->ThreadInit(tv_local, NULL, &stats_thread_data); + if (r != 0 || stats_thread_data == NULL) { + SCLogError(SC_ERR_THREAD_INIT, "Perf Counter API " + "ThreadInit failed"); + TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); + return NULL; + } + SCLogDebug("stats_thread_data %p", &stats_thread_data); + TmThreadsSetFlag(tv_local, THV_INIT_DONE); while (run) { if (TmThreadsCheckFlag(tv_local, THV_PAUSE)) { @@ -364,7 +275,7 @@ static void *SCPerfMgmtThread(void *arg) SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time); SCCtrlMutexUnlock(tv_local->ctrl_mutex); - SCPerfOutputCounters(); + SCPerfOutputCounters(tv_local); if (TmThreadsCheckFlag(tv_local, THV_KILL)) { run = 0; @@ -633,68 +544,91 @@ static uint64_t SCPerfOutputCalculateCounterValue(SCPerfCounter *pc) return pc->value; } + /** * \brief The file output interface for the Perf Counter api */ -static int SCPerfOutputCounterFileIface() +static int SCPerfOutputCounterFileIface(ThreadVars *tv) { - SCPerfClubTMInst *pctmi = NULL; - SCPerfCounter *pc = NULL; + const SCPerfClubTMInst *pctmi = NULL; + const SCPerfCounter *pc = NULL; SCPerfCounter **pc_heads = NULL; uint64_t ui64_temp = 0; uint64_t ui64_result = 0; - struct timeval tval; - struct tm *tms; - uint32_t u = 0; int flag = 0; + void *td = stats_thread_data; - if (sc_perf_op_ctx->fp == NULL) { - SCLogDebug("perf_op_ctx->fp is NULL"); - return 0; - } + if (stats_table.nstats == 0) { + uint32_t nstats = 0; - if (sc_perf_op_ctx->rotation_flag) { - SCLogDebug("Rotating log file"); - sc_perf_op_ctx->rotation_flag = 0; - if (!SCPerfFileReopen(sc_perf_op_ctx)) { - /* Rotation failed, error already logged. */ - return 0; + pctmi = sc_perf_op_ctx->pctmi; + while (pctmi != NULL) { + if (pctmi->size == 0) { + pctmi = pctmi->next; + continue; + } + + if ((pc_heads = SCMalloc(pctmi->size * sizeof(SCPerfCounter *))) == NULL) + return 0; + memset(pc_heads, 0, pctmi->size * sizeof(SCPerfCounter *)); + + for (u = 0; u < pctmi->size; u++) { + pc_heads[u] = pctmi->head[u]->head; + SCMutexLock(&pctmi->head[u]->m); + } + + flag = 1; + while (flag) { + if (pc_heads[0] == NULL) + break; + + for (u = 0; u < pctmi->size; u++) { + if (pc_heads[u] != NULL) + pc_heads[u] = pc_heads[u]->next; + if (pc_heads[u] == NULL) + flag = 0; + } + + /* count */ + nstats++; + } + + for (u = 0; u < pctmi->size; u++) + SCMutexUnlock(&pctmi->head[u]->m); + + pctmi = pctmi->next; + SCFree(pc_heads); + + } + if (nstats == 0) { + SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "no counters registered"); + return -1; + } + + stats_table.nstats = nstats; + stats_table.stats = SCCalloc(stats_table.nstats, sizeof(StatsRecord)); + if (stats_table.stats == NULL) { + stats_table.nstats = 0; + SCLogError(SC_ERR_MEM_ALLOC, "could not alloc memory for stats"); + return -1; } + + stats_table.start_time = sc_start_time; } + StatsRecord *table = stats_table.stats; - memset(&tval, 0, sizeof(struct timeval)); - - gettimeofday(&tval, NULL); - struct tm local_tm; - tms = SCLocalTime(tval.tv_sec, &local_tm); - - /* Calculate the Engine uptime */ - int up_time = (int)difftime(tval.tv_sec, sc_start_time); - int sec = up_time % 60; // Seconds in a minute - int in_min = up_time / 60; - int min = in_min % 60; // Minutes in a hour - int in_hours = in_min / 60; - int hours = in_hours % 24; // Hours in a day - int days = in_hours / 24; - - fprintf(sc_perf_op_ctx->fp, "----------------------------------------------" - "---------------------\n"); - fprintf(sc_perf_op_ctx->fp, "Date: %" PRId32 "/%" PRId32 "/%04d -- " - "%02d:%02d:%02d (uptime: %"PRId32"d, %02dh %02dm %02ds)\n", - tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, - tms->tm_min, tms->tm_sec, days, hours, min, sec); - fprintf(sc_perf_op_ctx->fp, "----------------------------------------------" - "---------------------\n"); - fprintf(sc_perf_op_ctx->fp, "%-25s | %-25s | %-s\n", "Counter", "TM Name", - "Value"); - fprintf(sc_perf_op_ctx->fp, "----------------------------------------------" - "---------------------\n"); + int table_i = 0; pctmi = sc_perf_op_ctx->pctmi; while (pctmi != NULL) { + if (pctmi->size == 0) { + pctmi = pctmi->next; + continue; + } + if ((pc_heads = SCMalloc(pctmi->size * sizeof(SCPerfCounter *))) == NULL) return 0; memset(pc_heads, 0, pctmi->size * sizeof(SCPerfCounter *)); @@ -722,20 +656,24 @@ static int SCPerfOutputCounterFileIface() flag = 0; } - fprintf(sc_perf_op_ctx->fp, "%-25s | %-25s | %-" PRIu64 "\n", - pc->cname, pctmi->tm_name, ui64_result); + /* store in the table */ + table[table_i].name = pc->cname; + table[table_i].tm_name = pctmi->tm_name; + table[table_i].pvalue = table[table_i].value; + table[table_i].value = ui64_result; + table_i++; } for (u = 0; u < pctmi->size; u++) SCMutexUnlock(&pctmi->head[u]->m); pctmi = pctmi->next; - SCFree(pc_heads); - fflush(sc_perf_op_ctx->fp); } + /* invoke logger(s) */ + OutputStatsLog(tv, td, &stats_table); return 1; } @@ -1294,29 +1232,6 @@ double SCPerfGetLocalCounterValue(uint16_t id, SCPerfCounterArray *pca) return pca->head[id].ui64_cnt; } -/** - * \brief The output interface dispatcher for the counter api - */ -void SCPerfOutputCounters() -{ - switch (sc_perf_op_ctx->iface) { - case SC_PERF_IFACE_FILE: - SCPerfOutputCounterFileIface(); - - break; - case SC_PERF_IFACE_CONSOLE: - /* yet to be implemented */ - - break; - case SC_PERF_IFACE_SYSLOG: - /* yet to be implemented */ - - break; - } - - return; -} - /** * \brief Releases the resources alloted by the Perf Counter API */ diff --git a/src/counters.h b/src/counters.h index 123a34f723c6..a1617d403757 100644 --- a/src/counters.h +++ b/src/counters.h @@ -27,12 +27,6 @@ /* forward declaration of the ThreadVars structure */ struct ThreadVars_; -/* Time interval for syncing the local counters with the global ones */ -#define SC_PERF_WUT_TTS 3 - -/* Time interval at which the mgmt thread o/p the stats */ -#define SC_PERF_MGMTT_TTS 8 - /** * \brief Data type for different kind of Perf counters that can be registered */ @@ -147,21 +141,8 @@ typedef struct SCPerfClubTMInst_ { * \brief Holds the output interface context for the counter api */ typedef struct SCPerfOPIfaceContext_ { - /* the iface to be used for output */ - uint32_t iface; - - /* the file to be used if the output interface used is SC_PERF_IFACE_FILE */ - char *file; - - /* more interfaces to be supported later. For now just a file */ - FILE *fp; - SCPerfClubTMInst *pctmi; SCMutex pctmi_lock; - - /* Flag set on file rotation notification. */ - int rotation_flag; - } SCPerfOPIfaceContext; /* the initialization functions */ @@ -186,8 +167,6 @@ SCPerfCounterArray * SCPerfGetAllCountersArray(SCPerfContext *); int SCPerfUpdateCounterArray(SCPerfCounterArray *, SCPerfContext *); double SCPerfGetLocalCounterValue(uint16_t, SCPerfCounterArray *); -void SCPerfOutputCounters(void); - /* functions used to free the resources alloted by the Perf counter API */ void SCPerfReleaseResources(void); void SCPerfReleasePerfCounterS(SCPerfCounter *); diff --git a/src/log-stats.c b/src/log-stats.c new file mode 100644 index 000000000000..fafd4c285281 --- /dev/null +++ b/src/log-stats.c @@ -0,0 +1,231 @@ +/* Copyright (C) 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 + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "log-stats.h" +#include "util-privs.h" +#include "util-buffer.h" + +#include "util-logopenfile.h" +#include "util-time.h" + +#define DEFAULT_LOG_FILENAME "stats.log" +#define MODULE_NAME "LogStatsLog" +#define OUTPUT_BUFFER_SIZE 65535 + +TmEcode LogStatsLogThreadInit(ThreadVars *, void *, void **); +TmEcode LogStatsLogThreadDeinit(ThreadVars *, void *); +void LogStatsLogExitPrintStats(ThreadVars *, void *); +static void LogStatsLogDeInitCtx(OutputCtx *); + +typedef struct LogStatsFileCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; /** Store mode */ +} LogStatsFileCtx; + +typedef struct LogStatsLogThread_ { + LogStatsFileCtx *statslog_ctx; + MemBuffer *buffer; +} LogStatsLogThread; + +int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) +{ + SCEnter(); + LogStatsLogThread *aft = (LogStatsLogThread *)thread_data; + + struct timeval tval; + struct tm *tms; + + gettimeofday(&tval, NULL); + struct tm local_tm; + tms = SCLocalTime(tval.tv_sec, &local_tm); + + /* Calculate the Engine uptime */ + int up_time = (int)difftime(tval.tv_sec, st->start_time); + int sec = up_time % 60; // Seconds in a minute + int in_min = up_time / 60; + int min = in_min % 60; // Minutes in a hour + int in_hours = in_min / 60; + int hours = in_hours % 24; // Hours in a day + int days = in_hours / 24; + + MemBufferWriteString(aft->buffer, "----------------------------------------------" + "---------------------\n"); + MemBufferWriteString(aft->buffer, "Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d (uptime: %"PRId32"d, %02dh %02dm %02ds)\n", + tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, + tms->tm_min, tms->tm_sec, days, hours, min, sec); + MemBufferWriteString(aft->buffer, "----------------------------------------------" + "---------------------\n"); + MemBufferWriteString(aft->buffer, "%-25s | %-25s | %-s\n", "Counter", "TM Name", + "Value"); + MemBufferWriteString(aft->buffer, "----------------------------------------------" + "---------------------\n"); + + uint32_t u = 0; + for (u = 0; u < st->nstats; u++) { + if (st->stats[u].name == NULL) + break; + MemBufferWriteString(aft->buffer, "%-25s | %-25s | %-" PRIu64 "\n", + st->stats[u].name, st->stats[u].tm_name, st->stats[u].value); + } + + SCMutexLock(&aft->statslog_ctx->file_ctx->fp_mutex); + aft->statslog_ctx->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), + MEMBUFFER_OFFSET(aft->buffer), aft->statslog_ctx->file_ctx); + SCMutexUnlock(&aft->statslog_ctx->file_ctx->fp_mutex); + + MemBufferReset(aft->buffer); + + SCReturnInt(0); +} + +TmEcode LogStatsLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + LogStatsLogThread *aft = SCMalloc(sizeof(LogStatsLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(LogStatsLogThread)); + + if(initdata == NULL) + { + SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + + /* Use the Ouptut Context (file pointer and mutex) */ + aft->statslog_ctx= ((OutputCtx *)initdata)->data; + + *data = (void *)aft; + return TM_ECODE_OK; +} + +TmEcode LogStatsLogThreadDeinit(ThreadVars *t, void *data) +{ + LogStatsLogThread *aft = (LogStatsLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + MemBufferFree(aft->buffer); + /* clear memory */ + memset(aft, 0, sizeof(LogStatsLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +void LogStatsLogExitPrintStats(ThreadVars *tv, void *data) +{ + LogStatsLogThread *aft = (LogStatsLogThread *)data; + if (aft == NULL) { + return; + } +} + +/** \brief Create a new http log LogFileCtx. + * \param conf Pointer to ConfNode containing this loggers configuration. + * \return NULL if failure, LogFileCtx* to the file_ctx if succesful + * */ +OutputCtx *LogStatsLogInitCtx(ConfNode *conf) +{ + LogFileCtx *file_ctx = LogFileNewCtx(); + if (file_ctx == NULL) { + SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + LogFileFreeCtx(file_ctx); + return NULL; + } + + LogStatsFileCtx *statslog_ctx = SCMalloc(sizeof(LogStatsFileCtx)); + if (unlikely(statslog_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + return NULL; + } + memset(statslog_ctx, 0x00, sizeof(LogStatsFileCtx)); + + statslog_ctx->file_ctx = file_ctx; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + SCFree(statslog_ctx); + return NULL; + } + + output_ctx->data = statslog_ctx; + output_ctx->DeInit = LogStatsLogDeInitCtx; + + SCLogDebug("STATS log output initialized"); + + OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); + return output_ctx; +} + +static void LogStatsLogDeInitCtx(OutputCtx *output_ctx) +{ + LogStatsFileCtx *statslog_ctx = (LogStatsFileCtx *)output_ctx->data; + OutputUnregisterFileRotationFlag(&statslog_ctx->file_ctx->rotation_flag); + LogFileFreeCtx(statslog_ctx->file_ctx); + SCFree(statslog_ctx); + SCFree(output_ctx); +} + +void TmModuleLogStatsLogRegister (void) +{ + tmm_modules[TMM_LOGSTATSLOG].name = MODULE_NAME; + tmm_modules[TMM_LOGSTATSLOG].ThreadInit = LogStatsLogThreadInit; + tmm_modules[TMM_LOGSTATSLOG].ThreadExitPrintStats = LogStatsLogExitPrintStats; + tmm_modules[TMM_LOGSTATSLOG].ThreadDeinit = LogStatsLogThreadDeinit; + tmm_modules[TMM_LOGSTATSLOG].RegisterTests = NULL; + tmm_modules[TMM_LOGSTATSLOG].cap_flags = 0; + tmm_modules[TMM_LOGSTATSLOG].flags = TM_FLAG_LOGAPI_TM; + + OutputRegisterStatsModule(MODULE_NAME, "stats", LogStatsLogInitCtx, LogStatsLogger); +} diff --git a/src/log-stats.h b/src/log-stats.h new file mode 100644 index 000000000000..957104f3c7fc --- /dev/null +++ b/src/log-stats.h @@ -0,0 +1,29 @@ +/* Copyright (C) 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 + */ + +#ifndef __LOG_STATS_H__ +#define __LOG_STATS_H__ + +void TmModuleLogStatsLogRegister (void); + +#endif /* __LOG_HTTPLOG_H__ */ diff --git a/src/output-stats.c b/src/output-stats.c new file mode 100644 index 000000000000..df6fa1b09b37 --- /dev/null +++ b/src/output-stats.c @@ -0,0 +1,234 @@ +/* Copyright (C) 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 + * + * Stats Logger Output registration functions + */ + +#include "suricata-common.h" +#include "tm-modules.h" +#include "output-stats.h" + +typedef struct OutputLoggerThreadStore_ { + void *thread_data; + struct OutputLoggerThreadStore_ *next; +} OutputLoggerThreadStore; + +/** per thread data for this module, contains a list of per thread + * data for the packet loggers. */ +typedef struct OutputLoggerThreadData_ { + OutputLoggerThreadStore *store; +} OutputLoggerThreadData; + +/* logger instance, a module + a output ctx, + * it's perfectly valid that have multiple instances of the same + * log module (e.g. http.log) with different output ctx'. */ +typedef struct OutputStatsLogger_ { + StatsLogger LogFunc; + OutputCtx *output_ctx; + struct OutputStatsLogger_ *next; + const char *name; + TmmId module_id; +} OutputStatsLogger; + +static OutputStatsLogger *list = NULL; + +int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, OutputCtx *output_ctx) +{ + int module_id = TmModuleGetIdByName(name); + if (module_id < 0) + return -1; + + OutputStatsLogger *op = SCMalloc(sizeof(*op)); + if (op == NULL) + return -1; + memset(op, 0x00, sizeof(*op)); + + op->LogFunc = LogFunc; + op->output_ctx = output_ctx; + op->name = name; + op->module_id = (TmmId) module_id; + + if (list == NULL) + list = op; + else { + OutputStatsLogger *t = list; + while (t->next) + t = t->next; + t->next = op; + } + + SCLogDebug("OutputRegisterStatsLogger happy"); + return 0; +} + +TmEcode OutputStatsLog(ThreadVars *tv, void *thread_data, StatsTable *st) +{ + BUG_ON(thread_data == NULL); + BUG_ON(list == NULL); + + OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; + OutputStatsLogger *logger = list; + OutputLoggerThreadStore *store = op_thread_data->store; + + BUG_ON(logger == NULL && store != NULL); + BUG_ON(logger != NULL && store == NULL); + BUG_ON(logger == NULL && store == NULL); + + logger = list; + store = op_thread_data->store; + while (logger && store) { + BUG_ON(logger->LogFunc == NULL); + + logger->LogFunc(tv, store->thread_data, st); + + logger = logger->next; + store = store->next; + + BUG_ON(logger == NULL && store != NULL); + BUG_ON(logger != NULL && store == NULL); + } + + return TM_ECODE_OK; +} + +/** \brief thread init for the tx logger + * This will run the thread init functions for the individual registered + * loggers */ +static TmEcode OutputStatsLogThreadInit(ThreadVars *tv, void *initdata, void **data) +{ + OutputLoggerThreadData *td = SCMalloc(sizeof(*td)); + if (td == NULL) + return TM_ECODE_FAILED; + memset(td, 0x00, sizeof(*td)); + + *data = (void *)td; + + SCLogDebug("OutputStatsLogThreadInit happy (*data %p)", *data); + + OutputStatsLogger *logger = list; + while (logger) { + TmModule *tm_module = TmModuleGetByName((char *)logger->name); + if (tm_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "TmModuleGetByName for %s failed", logger->name); + exit(EXIT_FAILURE); + } + + if (tm_module->ThreadInit) { + void *retptr = NULL; + if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); +/* todo */ BUG_ON(ts == NULL); + memset(ts, 0x00, sizeof(*ts)); + + /* store thread handle */ + ts->thread_data = retptr; + + if (td->store == NULL) { + td->store = ts; + } else { + OutputLoggerThreadStore *tmp = td->store; + while (tmp->next != NULL) + tmp = tmp->next; + tmp->next = ts; + } + + SCLogDebug("%s is now set up", logger->name); + } + } + + logger = logger->next; + } + + SCLogDebug("OutputStatsLogThreadInit happy (*data %p)", *data); + return TM_ECODE_OK; +} + +static TmEcode OutputStatsLogThreadDeinit(ThreadVars *tv, void *thread_data) +{ + OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; + OutputLoggerThreadStore *store = op_thread_data->store; + OutputStatsLogger *logger = list; + + while (logger && store) { + TmModule *tm_module = TmModuleGetByName((char *)logger->name); + if (tm_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "TmModuleGetByName for %s failed", logger->name); + exit(EXIT_FAILURE); + } + + if (tm_module->ThreadDeinit) { + tm_module->ThreadDeinit(tv, store->thread_data); + } + + OutputLoggerThreadStore *next_store = store->next; + SCFree(store); + store = next_store; + logger = logger->next; + } + return TM_ECODE_OK; +} + +static void OutputStatsLogExitPrintStats(ThreadVars *tv, void *thread_data) +{ + OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; + OutputLoggerThreadStore *store = op_thread_data->store; + OutputStatsLogger *logger = list; + + while (logger && store) { + TmModule *tm_module = TmModuleGetByName((char *)logger->name); + if (tm_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "TmModuleGetByName for %s failed", logger->name); + exit(EXIT_FAILURE); + } + + if (tm_module->ThreadExitPrintStats) { + tm_module->ThreadExitPrintStats(tv, store->thread_data); + } + + logger = logger->next; + store = store->next; + } +} + +void TmModuleStatsLoggerRegister (void) +{ + tmm_modules[TMM_STATSLOGGER].name = "__stats_logger__"; + tmm_modules[TMM_STATSLOGGER].ThreadInit = OutputStatsLogThreadInit; + //tmm_modules[TMM_STATSLOGGER].Func = OutputStatsLog; + tmm_modules[TMM_STATSLOGGER].ThreadExitPrintStats = OutputStatsLogExitPrintStats; + tmm_modules[TMM_STATSLOGGER].ThreadDeinit = OutputStatsLogThreadDeinit; + tmm_modules[TMM_STATSLOGGER].cap_flags = 0; +} + +void OutputStatsShutdown(void) +{ + OutputStatsLogger *logger = list; + while (logger) { + OutputStatsLogger *next_logger = logger->next; + SCFree(logger); + logger = next_logger; + } + list = NULL; +} diff --git a/src/output-stats.h b/src/output-stats.h new file mode 100644 index 000000000000..adb3d117610a --- /dev/null +++ b/src/output-stats.h @@ -0,0 +1,53 @@ +/* Copyright (C) 2007-2013 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 + * + * Stats Logger Output registration functions + */ + +#ifndef __OUTPUT_STATS_H__ +#define __OUTPUT_STATS_H__ + +typedef struct StatsRecord_ { + const char *name; + const char *tm_name; + uint64_t value; /**< total value */ + uint64_t pvalue; /**< prev value (may be higher for memuse counters) */ +} StatsRecord; + +typedef struct StatsTable_ { + StatsRecord *stats; + uint32_t nstats; + time_t start_time; + struct timeval ts; +} StatsTable; + +TmEcode OutputStatsLog(ThreadVars *tv, void *thread_data, StatsTable *st); + +typedef int (*StatsLogger)(ThreadVars *, void *thread_data, const StatsTable *); + +int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, OutputCtx *); + +void TmModuleStatsLoggerRegister (void); + +void OutputStatsShutdown(void); + +#endif /* __OUTPUT_STATS_H__ */ diff --git a/src/output.c b/src/output.c index 9229eb17b448..1146b7b22673 100644 --- a/src/output.c +++ b/src/output.c @@ -497,6 +497,76 @@ OutputRegisterStreamingSubModule(const char *parent_name, const char *name, exit(EXIT_FAILURE); } +/** + * \brief Register a stats data output module. + * + * This function will register an output module so it can be + * configured with the configuration file. + * + * \retval Returns 0 on success, -1 on failure. + */ +void +OutputRegisterStatsModule(const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *), StatsLogger StatsLogFunc) +{ + if (unlikely(StatsLogFunc == NULL)) { + goto error; + } + + OutputModule *module = SCCalloc(1, sizeof(*module)); + if (unlikely(module == NULL)) { + goto error; + } + + module->name = name; + module->conf_name = conf_name; + module->InitFunc = InitFunc; + module->StatsLogFunc = StatsLogFunc; + TAILQ_INSERT_TAIL(&output_modules, module, entries); + + SCLogDebug("Stats logger \"%s\" registered.", name); + return; +error: + SCLogError(SC_ERR_FATAL, "Fatal error encountered. Exiting..."); + exit(EXIT_FAILURE); +} + +/** + * \brief Register a stats data output sub-module. + * + * This function will register an output module so it can be + * configured with the configuration file. + * + * \retval Returns 0 on success, -1 on failure. + */ +void +OutputRegisterStatsSubModule(const char *parent_name, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), + StatsLogger StatsLogFunc) +{ + if (unlikely(StatsLogFunc == NULL)) { + goto error; + } + + OutputModule *module = SCCalloc(1, sizeof(*module)); + if (unlikely(module == NULL)) { + goto error; + } + + module->name = name; + module->conf_name = conf_name; + module->parent_name = parent_name; + module->InitSubFunc = InitFunc; + module->StatsLogFunc = StatsLogFunc; + TAILQ_INSERT_TAIL(&output_modules, module, entries); + + SCLogDebug("Stats logger \"%s\" registered.", name); + return; +error: + SCLogError(SC_ERR_FATAL, "Fatal error encountered. Exiting..."); + exit(EXIT_FAILURE); +} + /** * \brief Get an output module by name. * diff --git a/src/output.h b/src/output.h index 85092c31413c..9a4add0efb53 100644 --- a/src/output.h +++ b/src/output.h @@ -36,6 +36,7 @@ #include "output-filedata.h" #include "output-flow.h" #include "output-streaming.h" +#include "output-stats.h" typedef struct OutputModule_ { const char *name; @@ -51,6 +52,7 @@ typedef struct OutputModule_ { FiledataLogger FiledataLogFunc; FlowLogger FlowLogFunc; StreamingLogger StreamingLogFunc; + StatsLogger StatsLogFunc; AppProto alproto; enum OutputStreamingType stream_type; @@ -98,6 +100,12 @@ void OutputRegisterStreamingSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type); +void OutputRegisterStatsModule(const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *), StatsLogger StatsLogFunc); +void OutputRegisterStatsSubModule(const char *parent_name, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), + StatsLogger StatsLogFunc); + OutputModule *OutputGetModuleByConfName(const char *name); void OutputDeregisterAll(void); diff --git a/src/runmodes.c b/src/runmodes.c index 847fadcb1070..76f9022f86f1 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -447,6 +447,7 @@ void RunModeShutDown(void) OutputTxShutdown(); OutputFileShutdown(); OutputFiledataShutdown(); + OutputStatsShutdown(); /* Close any log files. */ RunModeOutput *output; @@ -490,6 +491,11 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu OutputRegisterFlowLogger(module->name, module->FlowLogFunc, output_ctx); return; } + /* stats logger doesn't run in the packet path */ + if (module->StatsLogFunc) { + OutputRegisterStatsLogger(module->name, module->StatsLogFunc, output_ctx); + return; + } TmModule *tm_module = TmModuleGetByName(module->name); if (tm_module == NULL) { @@ -636,9 +642,6 @@ void RunModeInitializeOutputs(void) TAILQ_FOREACH(output, &outputs->head, next) { - if (strcmp(output->val, "stats") == 0) - continue; - output_config = ConfNodeLookupChild(output, output->val); if (output_config == NULL) { /* Shouldn't happen. */ diff --git a/src/suricata.c b/src/suricata.c index d0c084a76c39..e7053ab96502 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -96,6 +96,7 @@ #include "output-json-smtp.h" #include "log-filestore.h" #include "log-tcp-data.h" +#include "log-stats.h" #include "output-json.h" @@ -892,6 +893,8 @@ void RegisterAllModules() TmModuleJsonDnsLogRegister(); /* tcp streaming data */ TmModuleLogTcpDataLogRegister(); + /* log stats */ + TmModuleLogStatsLogRegister(); TmModuleJsonAlertLogRegister(); /* flow/netflow */ @@ -904,6 +907,7 @@ void RegisterAllModules() TmModuleFileLoggerRegister(); TmModuleFiledataLoggerRegister(); TmModuleStreamingLoggerRegister(); + TmModuleStatsLoggerRegister(); TmModuleDebugList(); /* nflog */ TmModuleReceiveNFLOGRegister(); diff --git a/src/tm-modules.c b/src/tm-modules.c index 8503f02686f2..19caeca72724 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -250,6 +250,7 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_DECODEAFP); CASE_CODE (TMM_PACKETLOGGER); CASE_CODE (TMM_TXLOGGER); + CASE_CODE (TMM_STATSLOGGER); CASE_CODE (TMM_FILELOGGER); CASE_CODE (TMM_FILEDATALOGGER); CASE_CODE (TMM_STREAMINGLOGGER); @@ -267,6 +268,7 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_FLOWMANAGER); CASE_CODE (TMM_FLOWRECYCLER); CASE_CODE (TMM_LUALOG); + CASE_CODE (TMM_LOGSTATSLOG); CASE_CODE (TMM_SIZE); } diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 0137e1027917..059ba7b12d5f 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -81,6 +81,7 @@ typedef enum { TMM_DECODENAPATECH, TMM_PACKETLOGGER, TMM_TXLOGGER, + TMM_STATSLOGGER, TMM_FILELOGGER, TMM_FILEDATALOGGER, TMM_STREAMINGLOGGER, @@ -96,6 +97,7 @@ typedef enum { TMM_DECODENFLOG, TMM_JSONFLOWLOG, TMM_JSONNETFLOWLOG, + TMM_LOGSTATSLOG, TMM_FLOWMANAGER, TMM_FLOWRECYCLER, From a95c95f74c345c0a6fd00f536cde0d46ee614335 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Nov 2014 12:27:09 +0100 Subject: [PATCH 0073/2553] stats: introduce global config As the stats api calls the loggers at a global interval, the global interval should be configured globally. # global stats configuration stats: enabled: yes # The interval field (in seconds) controls at what interval # the loggers are invoked. interval: 8 If this config isn't found, the old config will be supported. --- src/counters.c | 30 ++++++++++++++++++++++++++++++ suricata.yaml.in | 10 +++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/counters.c b/src/counters.c index 5ea17c55e2cb..ec28d2e062db 100644 --- a/src/counters.c +++ b/src/counters.c @@ -146,6 +146,23 @@ void SCPerfCounterSetUI64(uint16_t id, SCPerfCounterArray *pca, return; } +static ConfNode *GetConfig(void) { + ConfNode *stats = ConfGetNode("stats"); + if (stats != NULL) + return stats; + + ConfNode *root = ConfGetNode("outputs"); + ConfNode *node = NULL; + if (root != NULL) { + TAILQ_FOREACH(node, &root->head, next) { + if (strcmp(node->val, "stats") == 0) { + return node->head.tqh_first; + } + } + } + return NULL; +} + /** * \brief Initializes the output interface context * @@ -160,6 +177,19 @@ static void SCPerfInitOPCtx(void) } memset(sc_perf_op_ctx, 0, sizeof(SCPerfOPIfaceContext)); + ConfNode *stats = GetConfig(); + if (stats != NULL) { + const char *enabled = ConfNodeLookupChildValue(stats, "enabled"); + if (enabled != NULL && ConfValIsFalse(enabled)) { + sc_counter_enabled = FALSE; + SCLogDebug("Stats module has been disabled"); + SCReturn; + } + const char *interval = ConfNodeLookupChildValue(stats, "interval"); + if (interval != NULL) + sc_counter_tts = (uint32_t) atoi(interval); + } + /* Store the engine start time */ time(&sc_start_time); diff --git a/suricata.yaml.in b/suricata.yaml.in index 70be178badd6..4e8efd08b98c 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -72,6 +72,13 @@ unix-command: enabled: no #filename: custom.socket +# global stats configuration +stats: + enabled: yes + # The interval field (in seconds) controls at what interval + # the loggers are invoked. + interval: 8 + # Configure the type of alert (and other) logging you would like. outputs: @@ -235,12 +242,9 @@ outputs: log-packet-header: yes # Stats.log contains data from various counters of the suricata engine. - # The interval field (in seconds) tells after how long output will be written - # on the log file. - stats: enabled: yes filename: stats.log - interval: 8 # a line based alerts log similar to fast.log into syslog - syslog: From 6252d24e0b45f57b8e5545c41292aa41863147a6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 4 Nov 2014 10:34:28 +0100 Subject: [PATCH 0074/2553] stats: initialize after outputs Initialize stats after outputs so that we can check if we need to initialize the stats api at all. --- src/runmode-unix-socket.c | 2 +- src/suricata.c | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index ec53b3f6fffd..d8d55a10d8fd 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -334,11 +334,11 @@ TmEcode UnixSocketPcapFilesCheck(void *data) return TM_ECODE_FAILED; } PcapFilesFree(cfile); - SCPerfInitCounterApi(); DefragInit(); FlowInitConfig(FLOW_QUIET); StreamTcpInitConfig(STREAM_VERBOSE); RunModeInitializeOutputs(); + SCPerfInitCounterApi(); RunModeDispatch(RUNMODE_PCAP_FILE, NULL, this->de_ctx); FlowManagerThreadSpawn(); FlowRecyclerThreadSpawn(); diff --git a/src/suricata.c b/src/suricata.c index e7053ab96502..c9a2084a953d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2073,10 +2073,6 @@ static int PostConfLoadedSetup(SCInstance *suri) StorageInit(); CIDRInit(); SigParsePrepare(); - //PatternMatchPrepare(mpm_ctx, MPM_B2G); - if (suri->run_mode != RUNMODE_UNIX_SOCKET) { - SCPerfInitCounterApi(); - } #ifdef PROFILING SCProfilingRulesGlobalInit(); SCProfilingKeywordsGlobalInit(); @@ -2287,6 +2283,7 @@ int main(int argc, char **argv) if (suri.run_mode != RUNMODE_UNIX_SOCKET) { RunModeInitializeOutputs(); + SCPerfInitCounterApi(); } if (ParseInterfacesList(suri.run_mode, suri.pcap_dev) != TM_ECODE_OK) { From 51a540c27efa3b22f550d7f3da734dcebdc4b204 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Nov 2014 13:00:26 +0100 Subject: [PATCH 0075/2553] stats: disable stats if no loggers are enabled --- src/counters.c | 6 ++++++ src/output-stats.c | 7 +++++++ src/output-stats.h | 2 ++ src/util-error.c | 1 + src/util-error.h | 1 + 5 files changed, 17 insertions(+) diff --git a/src/counters.c b/src/counters.c index ec28d2e062db..6f2333ce97f0 100644 --- a/src/counters.c +++ b/src/counters.c @@ -190,6 +190,12 @@ static void SCPerfInitOPCtx(void) sc_counter_tts = (uint32_t) atoi(interval); } + if (!OutputStatsLoggersRegistered()) { + SCLogWarning(SC_WARN_NO_STATS_LOGGERS, "stats are enabled but no loggers are active"); + sc_counter_enabled = FALSE; + SCReturn; + } + /* Store the engine start time */ time(&sc_start_time); diff --git a/src/output-stats.c b/src/output-stats.c index df6fa1b09b37..a6752fc5b7ae 100644 --- a/src/output-stats.c +++ b/src/output-stats.c @@ -222,6 +222,13 @@ void TmModuleStatsLoggerRegister (void) tmm_modules[TMM_STATSLOGGER].cap_flags = 0; } +int OutputStatsLoggersRegistered(void) +{ + if (list != NULL) + return 1; + return 0; +} + void OutputStatsShutdown(void) { OutputStatsLogger *logger = list; diff --git a/src/output-stats.h b/src/output-stats.h index adb3d117610a..6ca89f931bed 100644 --- a/src/output-stats.h +++ b/src/output-stats.h @@ -48,6 +48,8 @@ int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, OutputCtx * void TmModuleStatsLoggerRegister (void); +int OutputStatsLoggersRegistered(void); + void OutputStatsShutdown(void); #endif /* __OUTPUT_STATS_H__ */ diff --git a/src/util-error.c b/src/util-error.c index 8da681ac3dc5..454f8f3ff21b 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -300,6 +300,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_PCIE_INIT_FAILED); CASE_CODE (SC_WARN_LUA_SCRIPT); CASE_CODE (SC_ERR_LUA_SCRIPT); + CASE_CODE (SC_WARN_NO_STATS_LOGGERS); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 7d7155290513..21fc61116042 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -289,6 +289,7 @@ typedef enum { SC_WARN_NFLOG_SETSOCKOPT, SC_WARN_LUA_SCRIPT, SC_ERR_LUA_SCRIPT, + SC_WARN_NO_STATS_LOGGERS, } SCError; const char *SCErrorToString(SCError); From 5d95b081721b54eb33355bd79e299ef3eca388f4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Nov 2014 13:30:14 +0100 Subject: [PATCH 0076/2553] output streaming: cleanup at runmode destruction --- src/output-streaming.c | 11 +++++++++++ src/output-streaming.h | 2 ++ src/runmodes.c | 2 ++ 3 files changed, 15 insertions(+) diff --git a/src/output-streaming.c b/src/output-streaming.c index 41bbae266ad7..35e40d0c6244 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -452,3 +452,14 @@ void TmModuleStreamingLoggerRegister (void) { tmm_modules[TMM_STREAMINGLOGGER].ThreadDeinit = OutputStreamingLogThreadDeinit; tmm_modules[TMM_STREAMINGLOGGER].cap_flags = 0; } + +void OutputStreamingShutdown(void) +{ + OutputStreamingLogger *logger = list; + while (logger) { + OutputStreamingLogger *next_logger = logger->next; + SCFree(logger); + logger = next_logger; + } + list = NULL; +} diff --git a/src/output-streaming.h b/src/output-streaming.h index ff924dc0022a..8b3037422875 100644 --- a/src/output-streaming.h +++ b/src/output-streaming.h @@ -50,4 +50,6 @@ int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, Out void TmModuleStreamingLoggerRegister (void); +void OutputStreamingShutdown(void); + #endif /* __OUTPUT_STREAMING_H__ */ diff --git a/src/runmodes.c b/src/runmodes.c index 76f9022f86f1..166e627addc3 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -447,6 +447,7 @@ void RunModeShutDown(void) OutputTxShutdown(); OutputFileShutdown(); OutputFiledataShutdown(); + OutputStreamingShutdown(); OutputStatsShutdown(); /* Close any log files. */ @@ -462,6 +463,7 @@ void RunModeShutDown(void) tx_logger_module = NULL; file_logger_module = NULL; filedata_logger_module = NULL; + streaming_logger_module = NULL; } /** \internal From 75397ed7508ac6cd870b3bb49a59d46b3c3f51cf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 4 Nov 2014 09:17:10 +0100 Subject: [PATCH 0077/2553] stats: expose stats to Lua output Register with type 'stats': function init (args) local needs = {} needs["type"] = "stats" return needs end The stats are passed as an array of tables: { 1, { name=, tmname=, value=, pvalue=}} { 2, { name=, tmname=, value=, pvalue=}} etc Name is the counter name (e.g. decoder.invalid), tm_name is the thread name (e.g. AFPacketeth05), value is current value, and pvalue is the value of the last time the script was invoked. --- src/output-lua.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/output-lua.c b/src/output-lua.c index 1e15de44c66d..7f7514eef460 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -358,6 +358,60 @@ static int LuaFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) return 0; } + + +static int LuaStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) +{ + SCEnter(); + LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data; + + SCMutexLock(&td->lua_ctx->m); + + lua_State *luastate = td->lua_ctx->luastate; + /* get the lua function to call */ + lua_getglobal(td->lua_ctx->luastate, "log"); + + /* create lua array, which is really just a table. The key is an int (1-x), + * the value another table with named fields: name, tm_name, value, pvalue. + * { 1, { name=, tmname=, value=, pvalue=}} + * { 2, { name=, tmname=, value=, pvalue=}} + * etc + */ + lua_newtable(luastate); + uint32_t u = 0; + for (; u < st->nstats; u++) { + lua_pushinteger(luastate, u + 1); + + lua_newtable(luastate); + + lua_pushstring(luastate, "name"); + lua_pushstring(luastate, st->stats[u].name); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "tmname"); + lua_pushstring(luastate, st->stats[u].tm_name); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "value"); + lua_pushinteger(luastate, st->stats[u].value); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "pvalue"); + lua_pushinteger(luastate, st->stats[u].pvalue); + lua_settable(luastate, -3); + + lua_settable(luastate, -3); + } + + int retval = lua_pcall(td->lua_ctx->luastate, 1, 0, 0); + if (retval != 0) { + SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1)); + } + SCMutexUnlock(&td->lua_ctx->m); + return 0; + +} + typedef struct LogLuaScriptOptions_ { AppProto alproto; int packet; @@ -367,6 +421,7 @@ typedef struct LogLuaScriptOptions_ { int tcp_data; int http_body; int flow; + int stats; } LogLuaScriptOptions; /** \brief load and evaluate the script @@ -471,6 +526,8 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { options->flow = 1; else if (strcmp(k, "filter") == 0 && strcmp(v, "tcp") == 0) options->tcp_data = 1; + else if (strcmp(k, "type") == 0 && strcmp(v, "stats") == 0) + options->stats = 1; else SCLogInfo("unknown key and/or value: k='%s', v='%s'", k, v); } @@ -712,6 +769,8 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) om->StreamingLogFunc = LuaStreamingLogger; } else if (opts.flow) { om->FlowLogFunc = LuaFlowLogger; + } else if (opts.stats) { + om->StatsLogFunc = LuaStatsLogger; } else { SCLogError(SC_ERR_LUA_ERROR, "failed to setup thread module"); SCFree(om); From 6277d2e0e47fecc72807e09938307b18934a03df Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 3 Dec 2014 13:09:15 +0100 Subject: [PATCH 0078/2553] MemBuffer: add expansion call For some of the buffer users it's hard to predict how big the data will be. In the stats.log case this depends on chosen runmode and number of threads. To deal with this case a 'MemBufferExpand' call is added. This realloc's the buffer. --- src/util-buffer.c | 28 ++++++++++++++++++++++++++++ src/util-buffer.h | 6 ++++++ 2 files changed, 34 insertions(+) diff --git a/src/util-buffer.c b/src/util-buffer.c index 8dd108e8ef37..d4f50b06a41b 100644 --- a/src/util-buffer.c +++ b/src/util-buffer.c @@ -51,6 +51,34 @@ MemBuffer *MemBufferCreateNew(uint32_t size) return buffer; } +/** \brief expand membuffer by size of 'expand_by' + * + * If expansion failed, buffer will still be valid. + * + * \retval result 0 ok, -1 expansion failed + */ +int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by) { + if (((*buffer)->size + expand_by) > MAX_LIMIT) { + SCLogWarning(SC_ERR_MEM_BUFFER_API, "Mem buffer asked to create " + "buffer with size greater than API limit - %d", MAX_LIMIT); + return -1; + } + + uint32_t total_size = (*buffer)->size + sizeof(MemBuffer) + expand_by; + + MemBuffer *tbuffer = SCRealloc(*buffer, total_size); + if (unlikely(tbuffer == NULL)) { + return -1; + } + + *buffer = tbuffer; + (*buffer)->size += expand_by; + (*buffer)->buffer = (uint8_t *)tbuffer + sizeof(MemBuffer); + + SCLogDebug("expanded buffer by %u, size is now %u", expand_by, (*buffer)->size); + return 0; +} + void MemBufferFree(MemBuffer *buffer) { SCFree(buffer); diff --git a/src/util-buffer.h b/src/util-buffer.h index 5c592ae43a32..602b4df06864 100644 --- a/src/util-buffer.h +++ b/src/util-buffer.h @@ -31,6 +31,7 @@ typedef struct MemBuffer_ { } MemBuffer; MemBuffer *MemBufferCreateNew(uint32_t size); +int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by); void MemBufferFree(MemBuffer *buffer); /** @@ -53,6 +54,11 @@ void MemBufferFree(MemBuffer *buffer); */ #define MEMBUFFER_OFFSET(mem_buffer) (mem_buffer)->offset +/** + * \brief Get the MemBuffers current size. + */ +#define MEMBUFFER_SIZE(mem_buffer) (mem_buffer)->size + /** * \brief Write a buffer to the file pointer. * From 81c42f49163bc01c441f0f3e9703b0393fb64860 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 3 Dec 2014 13:22:46 +0100 Subject: [PATCH 0079/2553] log-stats: expand membuffer if necessary Many threads could lead to a membuffer size requirement bigger than 64k. So use the expansion call to grow the buffer as needed. --- src/log-stats.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/log-stats.c b/src/log-stats.c index fafd4c285281..1ae4246208e9 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -47,7 +47,7 @@ #define DEFAULT_LOG_FILENAME "stats.log" #define MODULE_NAME "LogStatsLog" -#define OUTPUT_BUFFER_SIZE 65535 +#define OUTPUT_BUFFER_SIZE 16384 TmEcode LogStatsLogThreadInit(ThreadVars *, void *, void **); TmEcode LogStatsLogThreadDeinit(ThreadVars *, void *); @@ -102,8 +102,18 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) for (u = 0; u < st->nstats; u++) { if (st->stats[u].name == NULL) break; - MemBufferWriteString(aft->buffer, "%-25s | %-25s | %-" PRIu64 "\n", - st->stats[u].name, st->stats[u].tm_name, st->stats[u].value); + + char line[1024]; + size_t len = snprintf(line, sizeof(line), "%-25s | %-25s | %-" PRIu64 "\n", + st->stats[u].name, st->stats[u].tm_name, st->stats[u].value); + + /* since we can have many threads, the buffer might not be big enough. + * Expand if necessary. */ + if (MEMBUFFER_OFFSET(aft->buffer) + len > MEMBUFFER_SIZE(aft->buffer)) { + MemBufferExpand(&aft->buffer, OUTPUT_BUFFER_SIZE); + } + + MemBufferWriteString(aft->buffer, "%s", line); } SCMutexLock(&aft->statslog_ctx->file_ctx->fp_mutex); From 7025aabe7528ef614c80e5f4f0d270cda56cfd4c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 4 Dec 2014 16:39:13 +0100 Subject: [PATCH 0080/2553] Runmodes: remove 'auto' runmodes Remove 'auto' runmodes from all capture methods. It wasn't reliable enough, as it didn't enforce inspection order of packets. --- src/runmode-af-packet.c | 62 ------ src/runmode-ipfw.c | 25 --- src/runmode-napatech.c | 18 +- src/runmode-nfq.c | 45 ---- src/runmode-pcap-file.c | 164 --------------- src/runmode-pcap.c | 51 ----- src/runmode-pfring.c | 52 ----- src/util-runmodes.c | 450 ---------------------------------------- 8 files changed, 2 insertions(+), 865 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 9d38d30680b7..33dd70094d26 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -66,9 +66,6 @@ const char *RunModeAFPGetDefaultMode(void) void RunModeIdsAFPRegister(void) { - RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "auto", - "Multi threaded af-packet mode", - RunModeIdsAFPAuto); RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "single", "Single threaded af-packet mode", RunModeIdsAFPSingle); @@ -411,65 +408,6 @@ int AFPRunModeIsIPS() return has_ips; } -/** - * \brief RunModeIdsAFPAuto set up the following thread packet handlers: - * - Receive thread (from live iface) - * - Decode thread - * - Stream thread - * - Detect: If we have only 1 cpu, it will setup one Detect thread - * If we have more than one, it will setup num_cpus - 1 - * starting from the second cpu available. - * - Respond/Reject thread - * - Outputs thread - * By default the threads will use the first cpu available - * except the Detection threads if we have more than one cpu. - * - * \param de_ctx Pointer to the Detection Engine. - * - * \retval 0 If all goes well. (If any problem is detected the engine will - * exit()). - */ -int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) -{ - SCEnter(); - -#ifdef HAVE_AF_PACKET - int ret; - char *live_dev = NULL; - - RunModeInitialize(); - - TimeModeSetLive(); - - (void)ConfGet("af-packet.live-interface", &live_dev); - - if (AFPPeersListInit() != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); - exit(EXIT_FAILURE); - } - - ret = RunModeSetLiveCaptureAuto(de_ctx, - ParseAFPConfig, - AFPConfigGeThreadsCount, - "ReceiveAFP", - "DecodeAFP", "RecvAFP", - live_dev); - if (ret != 0) { - SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); - exit(EXIT_FAILURE); - } - - /* In IPS mode each threads must have a peer */ - if (AFPPeersListCheck() != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); - exit(EXIT_FAILURE); - } - - SCLogInfo("RunModeIdsAFPAuto initialised"); -#endif - SCReturnInt(0); -} - int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); diff --git a/src/runmode-ipfw.c b/src/runmode-ipfw.c index 718f859a4f9f..03bb02e55fb8 100644 --- a/src/runmode-ipfw.c +++ b/src/runmode-ipfw.c @@ -58,9 +58,6 @@ const char *RunModeIpsIPFWGetDefaultMode(void) void RunModeIpsIPFWRegister(void) { default_mode = "autofp"; - RunModeRegisterNewRunMode(RUNMODE_IPFW, "auto", - "Multi threaded IPFW IPS mode", - RunModeIpsIPFWAuto); RunModeRegisterNewRunMode(RUNMODE_IPFW, "autofp", "Multi threaded IPFW IPS mode with respect to flow", @@ -73,28 +70,6 @@ void RunModeIpsIPFWRegister(void) return; } -int RunModeIpsIPFWAuto(DetectEngineCtx *de_ctx) -{ - SCEnter(); - int ret = 0; -#ifdef IPFW - - RunModeInitialize(); - - TimeModeSetLive(); - - LiveDeviceHasNoStats(); - - ret = RunModeSetIPSAuto(de_ctx, - IPFWGetThread, - "ReceiveIPFW", - "VerdictIPFW", - "DecodeIPFW"); -#endif /* IPFW */ - return ret; -} - - int RunModeIpsIPFWAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); diff --git a/src/runmode-napatech.c b/src/runmode-napatech.c index e064bb1674d5..0c9be2a233d3 100644 --- a/src/runmode-napatech.c +++ b/src/runmode-napatech.c @@ -45,9 +45,8 @@ // need NapatechStreamDevConf structure #include "source-napatech.h" -#define NT_RUNMODE_AUTO 1 -#define NT_RUNMODE_AUTOFP 2 -#define NT_RUNMODE_WORKERS 4 +#define NT_RUNMODE_AUTOFP 1 +#define NT_RUNMODE_WORKERS 2 static const char *default_mode = NULL; #ifdef HAVE_NAPATECH @@ -63,9 +62,6 @@ void RunModeNapatechRegister(void) { #ifdef HAVE_NAPATECH default_mode = "autofp"; - RunModeRegisterNewRunMode(RUNMODE_NAPATECH, "auto", - "Multi threaded Napatech mode", - RunModeNapatechAuto); RunModeRegisterNewRunMode(RUNMODE_NAPATECH, "autofp", "Multi threaded Napatech mode. Packets from " "each flow are assigned to a single detect " @@ -211,11 +207,6 @@ int NapatechInit(DetectEngineCtx *de_ctx, int runmode) } switch(runmode) { - case NT_RUNMODE_AUTO: - ret = RunModeSetLiveCaptureAuto(de_ctx, NapatechConfigParser, NapatechGetThreadsCount, - "NapatechStream", "NapatechDecode", - "RxNT", NULL); - break; case NT_RUNMODE_AUTOFP: ret = RunModeSetLiveCaptureAutoFp(de_ctx, NapatechConfigParser, NapatechGetThreadsCount, "NapatechStream", "NapatechDecode", @@ -237,11 +228,6 @@ int NapatechInit(DetectEngineCtx *de_ctx, int runmode) return 0; } -int RunModeNapatechAuto(DetectEngineCtx *de_ctx) -{ - return NapatechInit(de_ctx, NT_RUNMODE_AUTO); -} - int RunModeNapatechAutoFp(DetectEngineCtx *de_ctx) { return NapatechInit(de_ctx, NT_RUNMODE_AUTOFP); diff --git a/src/runmode-nfq.c b/src/runmode-nfq.c index 4f8fe808aa3f..edf7bc7e553b 100644 --- a/src/runmode-nfq.c +++ b/src/runmode-nfq.c @@ -56,10 +56,6 @@ const char *RunModeIpsNFQGetDefaultMode(void) void RunModeIpsNFQRegister(void) { default_mode = "autofp"; - RunModeRegisterNewRunMode(RUNMODE_NFQ, "auto", - "Multi threaded NFQ IPS mode", - RunModeIpsNFQAuto); - RunModeRegisterNewRunMode(RUNMODE_NFQ, "autofp", "Multi threaded NFQ IPS mode with respect to flow", RunModeIpsNFQAutoFp); @@ -70,47 +66,6 @@ void RunModeIpsNFQRegister(void) return; } -/** - * \brief RunModeIpsNFQAuto set up the following thread packet handlers: - * - Receive thread (from NFQ) - * - Decode thread - * - Stream thread - * - Detect: If we have only 1 cpu, it will setup one Detect thread - * If we have more than one, it will setup num_cpus - 1 - * starting from the second cpu available. - * - Veredict thread (NFQ) - * - Respond/Reject thread - * - Outputs thread - * By default the threads will use the first cpu available - * except the Detection threads if we have more than one cpu. - * - * \param de_ctx Pointer to the Detection Engine. - * - * \retval 0 If all goes well. (If any problem is detected the engine will - * exit()). - */ -int RunModeIpsNFQAuto(DetectEngineCtx *de_ctx) -{ - SCEnter(); - int ret = 0; -#ifdef NFQ - - RunModeInitialize(); - - TimeModeSetLive(); - - LiveDeviceHasNoStats(); - - ret = RunModeSetIPSAuto(de_ctx, - NFQGetThread, - "ReceiveNFQ", - "VerdictNFQ", - "DecodeNFQ"); -#endif /* NFQ */ - return ret; -} - - int RunModeIpsNFQAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index ffc3d3ea0779..9b2c25010067 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -49,9 +49,6 @@ void RunModeFilePcapRegister(void) RunModeRegisterNewRunMode(RUNMODE_PCAP_FILE, "single", "Single threaded pcap file mode", RunModeFilePcapSingle); - RunModeRegisterNewRunMode(RUNMODE_PCAP_FILE, "auto", - "Multi threaded pcap file mode", - RunModeFilePcapAuto); default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_PCAP_FILE, "autofp", "Multi threaded pcap file mode. Packets from " @@ -130,167 +127,6 @@ int RunModeFilePcapSingle(DetectEngineCtx *de_ctx) return 0; } -/* - * \brief RunModeFilePcapAuto set up the following thread packet handlers: - * - Receive thread (from pcap file) - * - Decode thread - * - Stream thread - * - Detect: If we have only 1 cpu, it will setup one Detect thread - * If we have more than one, it will setup num_cpus - 1 - * starting from the second cpu available. - * - Outputs thread - * By default the threads will use the first cpu available - * except the Detection threads if we have more than one cpu. - * - * \param de_ctx Pointer to the Detection Engine. - * - * \retval 0 If all goes well. (If any problem is detected the engine will - * exit()). - */ -int RunModeFilePcapAuto(DetectEngineCtx *de_ctx) -{ - SCEnter(); - char tname[TM_THREAD_NAME_MAX]; - uint16_t cpu = 0; - TmModule *tm_module; - RunModeInitialize(); - - if (de_ctx == NULL) { - SCLogError(SC_ERR_RUNMODE, "can't mix runmode 'auto' and disabled detect"); - return -1; - } - - /* Available cpus */ - uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); - - char *file = NULL; - if (ConfGet("pcap-file.file", &file) == 0) { - SCLogError(SC_ERR_RUNMODE, "Failed retrieving pcap-file from Conf"); - exit(EXIT_FAILURE); - } - SCLogDebug("file %s", file); - - TimeModeSetOffline(); - - /* create the threads */ - ThreadVars *tv_receivepcap = - TmThreadCreatePacketHandler("ReceivePcapFile", - "packetpool", "packetpool", - "detect-queue1", "simple", - "pktacqloop"); - if (tv_receivepcap == NULL) { - SCLogError(SC_ERR_FATAL, "threading setup failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName("ReceivePcapFile"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName failed for ReceivePcap"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receivepcap, tm_module, file); - - tm_module = TmModuleGetByName("DecodePcapFile"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName DecodePcap failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receivepcap, tm_module, NULL); - - tm_module = TmModuleGetByName("StreamTcp"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receivepcap, tm_module, (void *)de_ctx); - - TmThreadSetCPU(tv_receivepcap, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - /* start with cpu 1 so that if we're creating an odd number of detect - * threads we're not creating the most on CPU0. */ - if (ncpus > 0) - cpu = 1; - - /* always create at least one thread */ - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); - if (thread_max == 0) - thread_max = ncpus * threading_detect_ratio; - if (thread_max < 1) - thread_max = 1; - - int thread; - for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "failed to strdup thread name"); - exit(EXIT_FAILURE); - } - SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); - - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, - "detect-queue1", "simple", - "alert-queue1", "simple", - "1slot"); - if (tv_detect_ncpu == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); - - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; - - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); - - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - if ((cpu + 1) == ncpus) - cpu = 0; - else - cpu++; - } - - ThreadVars *tv_outputs = - TmThreadCreatePacketHandler("Outputs", - "alert-queue1", "simple", - "packetpool", "packetpool", - "varslot"); - if (tv_outputs == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadCreatePacketHandler for Outputs failed"); - exit(EXIT_FAILURE); - } - - SetupOutputs(tv_outputs); - - TmThreadSetCPU(tv_outputs, OUTPUT_CPU_SET); - - if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - return 0; -} - /** * \brief RunModeFilePcapAutoFp set up the following thread packet handlers: * - Receive thread (from pcap file) diff --git a/src/runmode-pcap.c b/src/runmode-pcap.c index 1ea1ba5976a6..17d9e692ee5c 100644 --- a/src/runmode-pcap.c +++ b/src/runmode-pcap.c @@ -53,9 +53,6 @@ void RunModeIdsPcapRegister(void) RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "single", "Single threaded pcap live mode", RunModeIdsPcapSingle); - RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "auto", - "Multi threaded pcap live mode", - RunModeIdsPcapAuto); default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "autofp", "Multi threaded pcap live mode. Packets from " @@ -265,54 +262,6 @@ int RunModeIdsPcapSingle(DetectEngineCtx *de_ctx) SCReturnInt(0); } - -/** - * \brief RunModeIdsPcapAuto set up the following thread packet handlers: - * - Receive thread (from iface pcap) - * - Decode thread - * - Stream thread - * - Detect: If we have only 1 cpu, it will setup one Detect thread - * If we have more than one, it will setup num_cpus - 1 - * starting from the second cpu available. - * - Respond/Reject thread - * - Outputs thread - * By default the threads will use the first cpu available - * except the Detection threads if we have more than one cpu. - * - * \param de_ctx Pointer to the Detection Engine. - * - * \retval 0 If all goes well. (If any problem is detected the engine will - * exit()). - */ -int RunModeIdsPcapAuto(DetectEngineCtx *de_ctx) -{ - /* tname = Detect + cpuid, this is 11bytes length as max */ - char *live_dev = NULL; - int ret; - - SCEnter(); - - RunModeInitialize(); - TimeModeSetLive(); - - (void) ConfGet("pcap.single-pcap-dev", &live_dev); - - ret = RunModeSetLiveCaptureAuto(de_ctx, - ParsePcapConfig, - PcapConfigGeThreadsCount, - "ReceivePcap", - "DecodePcap", "RecvPcap", - live_dev); - if (ret != 0) { - SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); - exit(EXIT_FAILURE); - } - - SCLogInfo("RunModeIdsPcapAuto initialised"); - - SCReturnInt(0); -} - /** * \brief RunModIdsPcapAutoFp set up the following thread packet handlers: * - Receive thread (from pcap device) diff --git a/src/runmode-pfring.c b/src/runmode-pfring.c index 287594642876..21c22fc2e6b0 100644 --- a/src/runmode-pfring.c +++ b/src/runmode-pfring.c @@ -54,9 +54,6 @@ const char *RunModeIdsPfringGetDefaultMode(void) void RunModeIdsPfringRegister(void) { - RunModeRegisterNewRunMode(RUNMODE_PFRING, "auto", - "Multi threaded pfring mode", - RunModeIdsPfringAuto); default_mode_autofp = "autofp"; RunModeRegisterNewRunMode(RUNMODE_PFRING, "autofp", "Multi threaded pfring mode. Packets from " @@ -421,55 +418,6 @@ static int GetDevAndParser(char **live_dev, ConfigIfaceParserFunc *parser) } #endif -/** - * \brief RunModeIdsPfringAuto set up the following thread packet handlers: - * - Receive thread (from pfring) - * - Decode thread - * - Stream thread - * - Detect: If we have only 1 cpu, it will setup one Detect thread - * If we have more than one, it will setup num_cpus - 1 - * starting from the second cpu available. - * - Respond/Reject thread - * - Outputs thread - * By default the threads will use the first cpu available - * except the Detection threads if we have more than one cpu. - * - * \param de_ctx Pointer to the Detection Engine. - * - * \retval 0 If all goes well. (If any problem is detected the engine will - * exit()). - */ -int RunModeIdsPfringAuto(DetectEngineCtx *de_ctx) -{ - SCEnter(); -/* We include only if pfring is enabled */ -#ifdef HAVE_PFRING - int ret; - char *live_dev = NULL; - ConfigIfaceParserFunc tparser; - - RunModeInitialize(); - - TimeModeSetLive(); - - ret = GetDevAndParser(&live_dev, &tparser); - if (ret != 0) { - SCLogError(SC_ERR_MISSING_CONFIG_PARAM, - "Unable to get parser and interface params"); - exit(EXIT_FAILURE); - } - - ret = RunModeSetLiveCaptureAuto(de_ctx, tparser, PfringConfigGeThreadsCount, - "ReceivePfring", "DecodePfring", - "RxPFR", live_dev); - if (ret != 0) { - SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); - exit(EXIT_FAILURE); - } -#endif /* HAVE_PFRING */ - return 0; -} - int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); diff --git a/src/util-runmodes.c b/src/util-runmodes.c index e4cd5e0139d1..293ff43f8485 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -47,250 +47,6 @@ #include "util-runmodes.h" -int RunModeSetLiveCaptureAuto(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc ConfigParser, - ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, - const char *live_dev) -{ - /* Available cpus */ - uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); - int nlive = LiveGetDeviceCount(); - TmModule *tm_module; - char tname[TM_THREAD_NAME_MAX]; - int thread; - - if (de_ctx == NULL) { - SCLogError(SC_ERR_RUNMODE, "can't use runmode 'auto' when detection is disabled"); - return -1; - } - - if ((nlive <= 1) && (live_dev != NULL)) { - void *aconf; - SCLogDebug("live_dev %s", live_dev); - - aconf = ConfigParser(live_dev); - if (aconf == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Single dev: Failed to allocate config"); - exit(EXIT_FAILURE); - } - - if (ModThreadsCount(aconf) > 1) { - SCLogWarning(SC_ERR_UNIMPLEMENTED, "'Auto' running mode does not honor 'threads'" - " variable (set on '%s'). Please use another mode as" - " 'autofp' or 'worker'", - live_dev); - } - - /* create the threads */ - ThreadVars *tv_receive = - TmThreadCreatePacketHandler(recv_mod_name, - "packetpool", "packetpool", - "pickup-queue", "simple", - "pktacqloop"); - if (tv_receive == NULL) { - SCLogError(SC_ERR_THREAD_CREATE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receive, tm_module, aconf); - - TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { - SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - } else { - SCLogInfo("Using %d live device(s).", nlive); - - for (thread = 0; thread < nlive; thread++) { - char *live_dev = LiveGetDeviceName(thread); - char *tnamec = NULL; - void *aconf; - - if (live_dev == NULL) { - SCLogError(SC_ERR_INVALID_VALUE, "Multidev: Failed to lookup live dev %d", thread); - exit(EXIT_FAILURE); - } - SCLogDebug("live_dev %s", live_dev); - - aconf = ConfigParser(live_dev); - if (aconf == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate config for %s (%d)", - live_dev, thread); - exit(EXIT_FAILURE); - } - - if (ModThreadsCount(aconf) > 1) { - SCLogWarning(SC_ERR_UNIMPLEMENTED, "'Auto' running mode does not honor 'threads'" - " variable (set on '%s'). Please use another mode as" - " 'autofp' or 'worker'", - live_dev); - } - - snprintf(tname, sizeof(tname),"%s-%s", thread_name, live_dev); - tnamec = SCStrdup(tname); - if (unlikely(tnamec == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } - - /* create the threads */ - ThreadVars *tv_receive = - TmThreadCreatePacketHandler(tnamec, - "packetpool", "packetpool", - "pickup-queue", "simple", - "pktacqloop"); - if (tv_receive == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receive, tm_module, (void *)aconf); - - TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { - SCLogError(SC_ERR_INVALID_VALUE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - } - } - - ThreadVars *tv_decode1 = - TmThreadCreatePacketHandler("Decode & Stream", - "pickup-queue", "simple", - "stream-queue1", "simple", - "varslot"); - if (tv_decode1 == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed for Decode1"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName(decode_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName %s failed", decode_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); - - tm_module = TmModuleGetByName("StreamTcp"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); - - TmThreadSetCPU(tv_decode1, DECODE_CPU_SET); - - if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - /* always create at least one thread */ - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); - if (thread_max == 0) - thread_max = ncpus * threading_detect_ratio; - if (thread_max < 1) - thread_max = 1; - - for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname),"Detect%"PRIu16, thread+1); - - char *thread_name = SCStrdup(tname); - - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } - - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, - "stream-queue1", "simple", - "verdict-queue", "simple", - "1slot"); - if (tv_detect_ncpu == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); - - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); - - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; - - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { - SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - } - - ThreadVars *tv_rreject = - TmThreadCreatePacketHandler("RespondReject", - "verdict-queue", "simple", - "alert-queue", "simple", - "1slot"); - if (tv_rreject == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName("RespondReject"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for RespondReject failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_rreject, tm_module, NULL); - - TmThreadSetCPU(tv_rreject, REJECT_CPU_SET); - - if (TmThreadSpawn(tv_rreject) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - ThreadVars *tv_outputs = - TmThreadCreatePacketHandler("Outputs", - "alert-queue", "simple", - "packetpool", "packetpool", - "varslot"); - if (tv_outputs == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadCreatePacketHandler for Outputs failed"); - exit(EXIT_FAILURE); - } - - SetupOutputs(tv_outputs); - - TmThreadSetCPU(tv_outputs, OUTPUT_CPU_SET); - - if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - return 0; -} - /** \brief create a queue string for autofp to pass to * the flow queue handler. * @@ -709,212 +465,6 @@ int RunModeSetLiveCaptureSingle(DetectEngineCtx *de_ctx, } -int RunModeSetIPSAuto(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name) -{ - SCEnter(); - char tname[TM_THREAD_NAME_MAX]; - TmModule *tm_module ; - char *cur_queue = NULL; - - /* Available cpus */ - uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); - int nqueue = LiveGetDeviceCount(); - - if (de_ctx == NULL) { - SCLogError(SC_ERR_RUNMODE, "can't use runmode 'auto' when detection is disabled"); - return -1; - } - - for (int i = 0; i < nqueue; i++) { - /* create the threads */ - cur_queue = LiveGetDeviceName(i); - if (cur_queue == NULL) { - SCLogError(SC_ERR_RUNMODE, "invalid queue number"); - exit(EXIT_FAILURE); - } - memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Recv-Q%s", cur_queue); - - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "failed to create thread name"); - exit(EXIT_FAILURE); - } - ThreadVars *tv_receivenfq = - TmThreadCreatePacketHandler(thread_name, - "packetpool", "packetpool", - "pickup-queue", "simple", - "1slot_noinout"); - if (tv_receivenfq == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName failed for %s", recv_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receivenfq, tm_module, (void *) ConfigParser(i)); - - TmThreadSetCPU(tv_receivenfq, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receivenfq) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - } - - /* decode and stream */ - ThreadVars *tv_decode = - TmThreadCreatePacketHandler("Decode1", - "pickup-queue", "simple", - "decode-queue", "simple", - "varslot"); - if (tv_decode == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed for Decode1"); - exit(EXIT_FAILURE); - } - - tm_module = TmModuleGetByName(decode_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", decode_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_decode,tm_module,NULL); - - tm_module = TmModuleGetByName("StreamTcp"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_decode, tm_module, NULL); - - TmThreadSetCPU(tv_decode, DECODE_CPU_SET); - - if (TmThreadSpawn(tv_decode) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - /* always create at least one thread */ - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); - if (thread_max == 0) - thread_max = ncpus * threading_detect_ratio; - if (thread_max < 1) - thread_max = 1; - - int thread; - for (thread = 0; thread < thread_max; thread++) { - memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "thread name creation failed"); - exit(EXIT_FAILURE); - } - SCLogDebug("Assigning %s affinity", thread_name); - - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, - "decode-queue", "simple", - "verdict-queue", "simple", - "1slot"); - if (tv_detect_ncpu == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); - - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); - - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; - - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - } - - /* create the threads */ - for (int i = 0; i < nqueue; i++) { - memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Verdict%"PRIu16, i); - - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "thread name creation failed"); - exit(EXIT_FAILURE); - } - ThreadVars *tv_verdict = - TmThreadCreatePacketHandler(thread_name, - "verdict-queue", "simple", - "alert-queue", "simple", - "varslot"); - if (tv_verdict == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName(verdict_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", verdict_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_verdict, tm_module, (void *)ConfigParser(i)); - - tm_module = TmModuleGetByName("RespondReject"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for RespondReject failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_verdict, tm_module, NULL); - - TmThreadSetCPU(tv_verdict, VERDICT_CPU_SET); - - if (TmThreadSpawn(tv_verdict) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - }; - - ThreadVars *tv_outputs = - TmThreadCreatePacketHandler("Outputs", - "alert-queue", "simple", - "packetpool", "packetpool", - "varslot"); - - if (tv_outputs == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadCreatePacketHandler for Outputs failed"); - exit(EXIT_FAILURE); - } - - TmThreadSetCPU(tv_outputs, OUTPUT_CPU_SET); - - SetupOutputs(tv_outputs); - if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - return 0; - -} - /** * \param de_ctx detection engine, can be NULL */ From 234d18ab6882f7c49798ca545865f542f4b39776 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 4 Dec 2014 16:42:55 +0100 Subject: [PATCH 0081/2553] threading: remove '1slot' functions No longer in use after the 'auto' runmode removal. All runmodes now use either varslot or pktacqloop support. --- src/tm-threads.c | 443 +---------------------------------------------- 1 file changed, 1 insertion(+), 442 deletions(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index 7cd06e9ea5b3..0c9d50a9eb4d 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -120,439 +120,6 @@ TmEcode TmDummyFunc(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack return TM_ECODE_OK; } -/* 1 slot functions */ -void *TmThreadsSlot1NoIn(void *td) -{ - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); - - ThreadVars *tv = (ThreadVars *)td; - TmSlot *s = (TmSlot *)tv->tm_slots; - char run = 1; - TmEcode r = TM_ECODE_OK; - - /* Set the thread name */ - if (SCSetThreadName(tv->name) < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } - - if (tv->thread_setup_flags != 0) - TmThreadSetupOptions(tv); - - /* Drop the capabilities for this thread */ - SCDropCaps(tv); - - PacketPoolInit(); - - if (s->SlotThreadInit != NULL) { - void *slot_data = NULL; - r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); - if (r != TM_ECODE_OK) { - EngineKill(); - - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; - } - (void)SC_ATOMIC_SET(s->slot_data, slot_data); - } - memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); - memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); - - TmThreadsSetFlag(tv, THV_INIT_DONE); - - while (run) { - if (TmThreadsCheckFlag(tv, THV_PAUSE)) { - TmThreadsSetFlag(tv, THV_PAUSED); - TmThreadTestThreadUnPaused(tv); - TmThreadsUnsetFlag(tv, THV_PAUSED); - } - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - - r = SlotFunc(tv, NULL, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); - - /* handle error */ - if (r == TM_ECODE_FAILED) { - TmqhReleasePacketsToPacketPool(&s->slot_pre_pq); - - SCMutexLock(&s->slot_post_pq.mutex_q); - TmqhReleasePacketsToPacketPool(&s->slot_post_pq); - SCMutexUnlock(&s->slot_post_pq.mutex_q); - - TmThreadsSetFlag(tv, THV_FAILED); - break; - } - - /* handle pre queue */ - while (s->slot_pre_pq.top != NULL) { - Packet *extra_p = PacketDequeue(&s->slot_pre_pq); - if (extra_p != NULL) - tv->tmqh_out(tv, extra_p); - } - - /* handle post queue */ - if (s->slot_post_pq.top != NULL) { - SCMutexLock(&s->slot_post_pq.mutex_q); - while (s->slot_post_pq.top != NULL) { - Packet *extra_p = PacketDequeue(&s->slot_post_pq); - if (extra_p != NULL) - tv->tmqh_out(tv, extra_p); - } - SCMutexUnlock(&s->slot_post_pq.mutex_q); - } - - if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCPerfSyncCounters(tv); - run = 0; - } - } /* while (run) */ - - PacketPoolDestroy(); - - TmThreadsSetFlag(tv, THV_RUNNING_DONE); - TmThreadWaitForFlag(tv, THV_DEINIT); - - if (s->SlotThreadExitPrintStats != NULL) { - s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); - } - - if (s->SlotThreadDeinit != NULL) { - r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); - if (r != TM_ECODE_OK) { - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; - } - } - - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); - return NULL; -} - -void *TmThreadsSlot1NoOut(void *td) -{ - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); - - ThreadVars *tv = (ThreadVars *)td; - TmSlot *s = (TmSlot *)tv->tm_slots; - Packet *p = NULL; - char run = 1; - TmEcode r = TM_ECODE_OK; - - /* Set the thread name */ - if (SCSetThreadName(tv->name) < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } - - if (tv->thread_setup_flags != 0) - TmThreadSetupOptions(tv); - - /* Drop the capabilities for this thread */ - SCDropCaps(tv); - - PacketPoolInit(); - - if (s->SlotThreadInit != NULL) { - void *slot_data = NULL; - r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); - if (r != TM_ECODE_OK) { - EngineKill(); - - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; - } - (void)SC_ATOMIC_SET(s->slot_data, slot_data); - } - memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); - memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); - - TmThreadsSetFlag(tv, THV_INIT_DONE); - - while (run) { - if (TmThreadsCheckFlag(tv, THV_PAUSE)) { - TmThreadsSetFlag(tv, THV_PAUSED); - TmThreadTestThreadUnPaused(tv); - TmThreadsUnsetFlag(tv, THV_PAUSED); - } - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - - p = tv->tmqh_in(tv); - - PACKET_PROFILING_TMM_START(p, s->tm_id); - r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), /* no outqh no pq */ NULL, - /* no outqh no pq */ NULL); - PACKET_PROFILING_TMM_END(p, s->tm_id); - - /* handle error */ - if (r == TM_ECODE_FAILED) { - TmqhOutputPacketpool(tv, p); - TmThreadsSetFlag(tv, THV_FAILED); - break; - } - - if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCPerfSyncCounters(tv); - run = 0; - } - } /* while (run) */ - - PacketPoolDestroy(); - - TmThreadsSetFlag(tv, THV_RUNNING_DONE); - TmThreadWaitForFlag(tv, THV_DEINIT); - - if (s->SlotThreadExitPrintStats != NULL) { - s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); - } - - if (s->SlotThreadDeinit != NULL) { - r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); - if (r != TM_ECODE_OK) { - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; - } - } - - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); - return NULL; -} - -void *TmThreadsSlot1NoInOut(void *td) -{ - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); - - ThreadVars *tv = (ThreadVars *)td; - TmSlot *s = (TmSlot *)tv->tm_slots; - char run = 1; - TmEcode r = TM_ECODE_OK; - - /* Set the thread name */ - if (SCSetThreadName(tv->name) < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } - - if (tv->thread_setup_flags != 0) - TmThreadSetupOptions(tv); - - /* Drop the capabilities for this thread */ - SCDropCaps(tv); - - PacketPoolInit(); - - SCLogDebug("%s starting", tv->name); - - if (s->SlotThreadInit != NULL) { - void *slot_data = NULL; - r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); - if (r != TM_ECODE_OK) { - EngineKill(); - - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; - } - (void)SC_ATOMIC_SET(s->slot_data, slot_data); - } - memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); - memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); - - TmThreadsSetFlag(tv, THV_INIT_DONE); - - while (run) { - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - if (TmThreadsCheckFlag(tv, THV_PAUSE)) { - TmThreadsSetFlag(tv, THV_PAUSED); - TmThreadTestThreadUnPaused(tv); - TmThreadsUnsetFlag(tv, THV_PAUSED); - } - - r = SlotFunc(tv, NULL, SC_ATOMIC_GET(s->slot_data), /* no outqh, no pq */NULL, NULL); - - /* handle error */ - if (r == TM_ECODE_FAILED) { - TmThreadsSetFlag(tv, THV_FAILED); - break; - } - - if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCPerfSyncCounters(tv); - run = 0; - } - } /* while (run) */ - - PacketPoolDestroy(); - - TmThreadsSetFlag(tv, THV_RUNNING_DONE); - TmThreadWaitForFlag(tv, THV_DEINIT); - - if (s->SlotThreadExitPrintStats != NULL) { - s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); - } - - if (s->SlotThreadDeinit != NULL) { - r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); - if (r != TM_ECODE_OK) { - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; - } - } - - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); - return NULL; -} - -void *TmThreadsSlot1(void *td) -{ - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); - - ThreadVars *tv = (ThreadVars *)td; - TmSlot *s = (TmSlot *)tv->tm_slots; - Packet *p = NULL; - char run = 1; - TmEcode r = TM_ECODE_OK; - - /* Set the thread name */ - if (SCSetThreadName(tv->name) < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } - - if (tv->thread_setup_flags != 0) - TmThreadSetupOptions(tv); - - /* Drop the capabilities for this thread */ - SCDropCaps(tv); - - PacketPoolInit(); - - SCLogDebug("%s starting", tv->name); - - if (s->SlotThreadInit != NULL) { - void *slot_data = NULL; - r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); - if (r != TM_ECODE_OK) { - EngineKill(); - - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; - } - (void)SC_ATOMIC_SET(s->slot_data, slot_data); - } - memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); - SCMutexInit(&s->slot_pre_pq.mutex_q, NULL); - memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - SCMutexInit(&s->slot_post_pq.mutex_q, NULL); - - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); - - TmThreadsSetFlag(tv, THV_INIT_DONE); - - while (run) { - if (TmThreadsCheckFlag(tv, THV_PAUSE)) { - TmThreadsSetFlag(tv, THV_PAUSED); - TmThreadTestThreadUnPaused(tv); - TmThreadsUnsetFlag(tv, THV_PAUSED); - } - - /* input a packet */ - p = tv->tmqh_in(tv); - - if (p != NULL) { - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - PACKET_PROFILING_TMM_START(p, s->tm_id); - r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, - &s->slot_post_pq); - PACKET_PROFILING_TMM_END(p, s->tm_id); - - /* handle error */ - if (r == TM_ECODE_FAILED) { - TmqhReleasePacketsToPacketPool(&s->slot_pre_pq); - - SCMutexLock(&s->slot_post_pq.mutex_q); - TmqhReleasePacketsToPacketPool(&s->slot_post_pq); - SCMutexUnlock(&s->slot_post_pq.mutex_q); - - TmqhOutputPacketpool(tv, p); - TmThreadsSetFlag(tv, THV_FAILED); - break; - } - - while (s->slot_pre_pq.top != NULL) { - /* handle new packets from this func */ - Packet *extra_p = PacketDequeue(&s->slot_pre_pq); - if (extra_p != NULL) { - tv->tmqh_out(tv, extra_p); - } - } - - /* output the packet */ - tv->tmqh_out(tv, p); - } - if (s->slot_post_pq.top != NULL) { - SCMutexLock(&s->slot_post_pq.mutex_q); - while (s->slot_post_pq.top != NULL) { - /* handle new packets from this func */ - Packet *extra_p = PacketDequeue(&s->slot_post_pq); - if (extra_p != NULL) { - tv->tmqh_out(tv, extra_p); - } - } - SCMutexUnlock(&s->slot_post_pq.mutex_q); - } - - if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCPerfSyncCounters(tv); - run = 0; - } - } /* while (run) */ - - PacketPoolDestroy(); - - TmThreadsSetFlag(tv, THV_RUNNING_DONE); - TmThreadWaitForFlag(tv, THV_DEINIT); - - if (s->SlotThreadExitPrintStats != NULL) { - s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); - } - - if (s->SlotThreadDeinit != NULL) { - r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); - if (r != TM_ECODE_OK) { - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; - } - } - - SCLogDebug("%s ending", tv->name); - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); - return NULL; -} - /** * \brief Separate run function so we can call it recursively. * @@ -1004,15 +571,7 @@ TmEcode TmThreadSetSlots(ThreadVars *tv, char *name, void *(*fn_p)(void *)) } } - if (strcmp(name, "1slot") == 0) { - tv->tm_func = TmThreadsSlot1; - } else if (strcmp(name, "1slot_noout") == 0) { - tv->tm_func = TmThreadsSlot1NoOut; - } else if (strcmp(name, "1slot_noin") == 0) { - tv->tm_func = TmThreadsSlot1NoIn; - } else if (strcmp(name, "1slot_noinout") == 0) { - tv->tm_func = TmThreadsSlot1NoInOut; - } else if (strcmp(name, "varslot") == 0) { + if (strcmp(name, "varslot") == 0) { tv->tm_func = TmThreadsSlotVar; } else if (strcmp(name, "pktacqloop") == 0) { tv->tm_func = TmThreadsSlotPktAcqLoop; From 7b4987abc3e2b33d395e6139e70818ec7124cf3c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 4 Dec 2014 16:46:51 +0100 Subject: [PATCH 0082/2553] Runmode: handle value 'auto' Auto now selects the default runmode for the capture method. --- src/runmodes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runmodes.c b/src/runmodes.c index 166e627addc3..4f658ce56e00 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -272,7 +272,7 @@ void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_c } } - if (custom_mode == NULL) { + if (custom_mode == NULL || strcmp(custom_mode, "auto") == 0) { switch (runmode) { case RUNMODE_PCAP_DEV: custom_mode = RunModeIdsGetDefaultMode(); From c174c9d779121cc73016eef213f7175fe76244c2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 4 Dec 2014 17:01:02 +0100 Subject: [PATCH 0083/2553] af-packet: threads: auto, default to workers Add a new default value for the 'threads:' setting in af-packet: "auto". This will create as many capture threads as there are cores. Default runmode of af-packet to workers. --- src/runmode-af-packet.c | 19 ++++++++++++++----- suricata.yaml.in | 9 ++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 33dd70094d26..64b198598950 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -57,11 +57,11 @@ extern int max_pending_packets; -static const char *default_mode_autofp = NULL; +static const char *default_mode_workers = NULL; const char *RunModeAFPGetDefaultMode(void) { - return default_mode_autofp; + return default_mode_workers; } void RunModeIdsAFPRegister(void) @@ -73,7 +73,7 @@ void RunModeIdsAFPRegister(void) "Workers af-packet mode, each thread does all" " tasks from acquisition to logging", RunModeIdsAFPWorkers); - default_mode_autofp = "autofp"; + default_mode_workers = "workers"; RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "autofp", "Multi socket AF_PACKET mode. Packets from " "each flow are assigned to a single detect " @@ -173,13 +173,22 @@ void *ParseAFPConfig(const char *iface) } if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { - aconf->threads = 1; + aconf->threads = 0; } else { if (threadsstr != NULL) { - aconf->threads = (uint8_t)atoi(threadsstr); + if (strcmp(threadsstr, "auto") == 0) { + aconf->threads = 0; + } else { + aconf->threads = (uint8_t)atoi(threadsstr); + } } } if (aconf->threads == 0) { + aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); + if (aconf->threads) + SCLogInfo("Using %d AF_PACKET threads for interface %s", aconf->threads, iface); + } + if (aconf->threads <= 0) { aconf->threads = 1; } diff --git a/suricata.yaml.in b/suricata.yaml.in index 4e8efd08b98c..ed34f7619083 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -367,9 +367,8 @@ nflog: # Set threads to > 1 to use PACKET_FANOUT support af-packet: - interface: eth0 - # Number of receive threads (>1 will enable experimental flow pinned - # runmode) - threads: 1 + # Number of receive threads. "auto" uses the number of cores + threads: auto # Default clusterid. AF_PACKET will load balance packets based on flow. # All threads/processes that will participate need to have the same # clusterid. @@ -420,7 +419,7 @@ af-packet: #copy-mode: ips #copy-iface: eth1 - interface: eth1 - threads: 1 + threads: auto cluster-id: 98 cluster-type: cluster_flow defrag: yes @@ -428,7 +427,7 @@ af-packet: # disable-promisc: no # Put default values here - interface: default - #threads: 2 + #threads: auto #use-mmap: yes legacy: From b4bb6e67ba10a432c84f2e81fcbbebc911999110 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 4 Dec 2014 17:49:31 +0100 Subject: [PATCH 0084/2553] util-ioctl: Add function to get number of RSS queues on iface The number of RSS queues can be fetched via a standard ioctl which is independant of hardware. --- src/util-ioctl.c | 33 +++++++++++++++++++++++++++++++++ src/util-ioctl.h | 1 + 2 files changed, 34 insertions(+) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index f46004213e28..b3a0f224784e 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -210,3 +210,36 @@ int GetIfaceOffloading(char *pcap_dev) #endif } +int GetIfaceRSSQueuesNum(const char *pcap_dev) +{ +#ifdef HAVE_LINUX_ETHTOOL_H + struct ifreq ifr; + struct ethtool_rxnfc nfccmd; + int fd; + + (void)strlcpy(ifr.ifr_name, pcap_dev, sizeof(ifr.ifr_name)); + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + return -1; + } + + nfccmd.cmd = ETHTOOL_GRXRINGS; + ifr.ifr_data = (void*) &nfccmd; + + if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { + if (errno != ENOTSUP) { + SCLogWarning(SC_ERR_SYSCALL, + "Failure when trying to get number of RSS queue ioctl: %d", + errno); + } + close(fd); + return 0; + } + close(fd); + SCLogInfo("Found %d RX RSS queues for '%s'", (int)nfccmd.data, + pcap_dev); + return (int)nfccmd.data; +#else + return 0; +#endif +} diff --git a/src/util-ioctl.h b/src/util-ioctl.h index 7bc5055710ba..d293a4d04760 100644 --- a/src/util-ioctl.h +++ b/src/util-ioctl.h @@ -24,3 +24,4 @@ int GetIfaceMTU(char *pcap_dev); int GetIfaceMaxPacketSize(char *pcap_dev); int GetIfaceOffloading(char *pcap_dev); +int GetIfaceRSSQueuesNum(const char *pcap_dev); From 123c58af4b402235ec1d558f3a01a236f4f0fa65 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 4 Dec 2014 18:11:22 +0100 Subject: [PATCH 0085/2553] util-ioctl: add message in case of failure --- src/util-ioctl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index b3a0f224784e..28a72f796189 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -220,6 +220,9 @@ int GetIfaceRSSQueuesNum(const char *pcap_dev) (void)strlcpy(ifr.ifr_name, pcap_dev, sizeof(ifr.ifr_name)); fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { + SCLogWarning(SC_ERR_SYSCALL, + "Failure when opening socket for ioctl: %d", + errno); return -1; } From 56373e5b347fb939ca0e2c9addb5cefd2947f979 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 4 Dec 2014 17:58:25 +0100 Subject: [PATCH 0086/2553] af-packet: no more threads than RSS queues If we manage to read the number of RSS queues from an interface, this means that the optimal number of capture threads is equal to the minimum of this number and of the number of cores on the system. This patch implements this logic thanks to the newly introduced function GetIfaceRSSQueuesNum. --- src/runmode-af-packet.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 64b198598950..4c071f3529a7 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -52,6 +52,7 @@ #include "util-affinity.h" #include "util-device.h" #include "util-runmodes.h" +#include "util-ioctl.h" #include "source-af-packet.h" @@ -184,7 +185,17 @@ void *ParseAFPConfig(const char *iface) } } if (aconf->threads == 0) { + int rss_queues; aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); + /* Get the number of RSS queues and take the min */ + rss_queues = GetIfaceRSSQueuesNum(iface); + if (rss_queues > 0) { + if (rss_queues < aconf->threads) { + aconf->threads = rss_queues; + SCLogInfo("More core than RSS queues, using %d threads for interface %s", + aconf->threads, iface); + } + } if (aconf->threads) SCLogInfo("Using %d AF_PACKET threads for interface %s", aconf->threads, iface); } From f8f2ff49de3da00cdd5b350299484955466f6040 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 3 Dec 2014 16:07:00 +0100 Subject: [PATCH 0087/2553] defrag: don't crash when out of memory Handle memory allocation errors in defrag better. Could lead to crashes if malloc errors happened. --- src/defrag.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/defrag.c b/src/defrag.c index 7d38dec1c9e5..71225b8da9f3 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -291,7 +291,7 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (rp == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for " "fragmentation re-assembly, dumping fragments."); - goto remove_tracker; + goto error_remove_tracker; } PKT_SET_SRC(rp, PKT_SRC_DEFRAG); rp->recursion_level = p->recursion_level; @@ -311,7 +311,7 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (frag->offset == 0) { if (PacketCopyData(rp, frag->pkt, frag->len) == -1) - goto remove_tracker; + goto error_remove_tracker; hlen = frag->hlen; ip_hdr_offset = frag->ip_hdr_offset; @@ -327,12 +327,12 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (pkt_end > (int)MAX_PAYLOAD_SIZE) { SCLogWarning(SC_ERR_REASSEMBLY, "Failed re-assemble " "fragmented packet, exceeds size of packet buffer."); - goto remove_tracker; + goto error_remove_tracker; } if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim, frag->pkt + frag->data_offset + frag->ltrim, frag->data_len - frag->ltrim) == -1) { - goto remove_tracker; + goto error_remove_tracker; } if (frag->offset + frag->data_len > fragmentable_len) fragmentable_len = frag->offset + frag->data_len; @@ -350,12 +350,16 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) old, rp->ip4h->ip_len + rp->ip4h->ip_off); SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len); -remove_tracker: - /** \todo check locking */ tracker->remove = 1; DefragTrackerFreeFrags(tracker); done: return rp; + +error_remove_tracker: + tracker->remove = 1; + DefragTrackerFreeFrags(tracker); + PacketFreeOrRelease(rp); + return NULL; } /** @@ -405,7 +409,7 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (rp == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for " "fragmentation re-assembly, dumping fragments."); - goto remove_tracker; + goto error_remove_tracker; } PKT_SET_SRC(rp, PKT_SRC_DEFRAG); @@ -428,11 +432,11 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) * IPv6 headers. We also copy in its data, but remove the * fragmentation header. */ if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1) - goto remove_tracker; + goto error_remove_tracker; if (PacketCopyDataOffset(rp, frag->frag_hdr_offset, frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr), frag->data_len) == -1) - goto remove_tracker; + goto error_remove_tracker; ip_hdr_offset = frag->ip_hdr_offset; /* This is the start of the fragmentable portion of the @@ -445,13 +449,13 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) * and the frag header. */ unfragmentable_len = (fragmentable_offset - ip_hdr_offset) - IPV6_HEADER_LEN; if (unfragmentable_len >= fragmentable_offset) - goto remove_tracker; + goto error_remove_tracker; } else { if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim, frag->pkt + frag->data_offset + frag->ltrim, frag->data_len - frag->ltrim) == -1) - goto remove_tracker; + goto error_remove_tracker; if (frag->offset + frag->data_len > fragmentable_len) fragmentable_len = frag->offset + frag->data_len; } @@ -468,12 +472,16 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) + unfragmentable_len + fragmentable_len); -remove_tracker: - /** \todo check locking */ tracker->remove = 1; DefragTrackerFreeFrags(tracker); done: return rp; + +error_remove_tracker: + tracker->remove = 1; + DefragTrackerFreeFrags(tracker); + PacketFreeOrRelease(rp); + return NULL; } /** From c3c144d50417ce79b84e5611567e790fa398a38e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 3 Dec 2014 16:08:19 +0100 Subject: [PATCH 0088/2553] http: don't crash when normalizing uri on low memory --- src/app-layer-htp-libhtp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/app-layer-htp-libhtp.c b/src/app-layer-htp-libhtp.c index fbe2df54f846..69d862208d5f 100644 --- a/src/app-layer-htp-libhtp.c +++ b/src/app-layer-htp-libhtp.c @@ -201,11 +201,13 @@ bstr *SCHTPGenerateNormalizedUri(htp_tx_t *tx, htp_uri_t *uri, int uri_include_a if (uri->query != NULL) { bstr *query = bstr_dup(uri->query); - uint64_t flags = 0; - htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, query, &flags); - bstr_add_c_noex(r, "?"); - bstr_add_noex(r, query); - bstr_free(query); + if (query) { + uint64_t flags = 0; + htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, query, &flags); + bstr_add_c_noex(r, "?"); + bstr_add_noex(r, query); + bstr_free(query); + } } if (uri->fragment != NULL) { From fa1081158572bee6c126f7068837baf5955eb102 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 5 Dec 2014 10:16:48 +0100 Subject: [PATCH 0089/2553] ioctl: make all string args const pointers --- src/util-ioctl.c | 8 ++++---- src/util-ioctl.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 28a72f796189..7ea8f22a427f 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -47,7 +47,7 @@ * * \param Name of a network interface */ -int GetIfaceMaxHWHeaderLength(char *pcap_dev) +int GetIfaceMaxHWHeaderLength(const char *pcap_dev) { if ((!strcmp("eth", pcap_dev)) || @@ -76,7 +76,7 @@ int GetIfaceMaxHWHeaderLength(char *pcap_dev) * \param Name of link * \retval -1 in case of error, 0 if MTU can not be found */ -int GetIfaceMTU(char *pcap_dev) +int GetIfaceMTU(const char *pcap_dev) { #ifdef SIOCGIFMTU struct ifreq ifr; @@ -115,7 +115,7 @@ int GetIfaceMTU(char *pcap_dev) * \param Name of a network interface * \retval 0 in case of error */ -int GetIfaceMaxPacketSize(char *pcap_dev) +int GetIfaceMaxPacketSize(const char *pcap_dev) { int ll_header = GetIfaceMaxHWHeaderLength(pcap_dev); int mtu = 0; @@ -150,7 +150,7 @@ int GetIfaceMaxPacketSize(char *pcap_dev) * \param Name of link * \retval -1 in case of error, 0 if none, 1 if some */ -int GetIfaceOffloading(char *pcap_dev) +int GetIfaceOffloading(const char *pcap_dev) { #if defined (ETHTOOL_GGRO) && defined (ETHTOOL_GFLAGS) struct ifreq ifr; diff --git a/src/util-ioctl.h b/src/util-ioctl.h index d293a4d04760..3931c1fe0919 100644 --- a/src/util-ioctl.h +++ b/src/util-ioctl.h @@ -21,7 +21,7 @@ * \author Eric Leblond */ -int GetIfaceMTU(char *pcap_dev); -int GetIfaceMaxPacketSize(char *pcap_dev); -int GetIfaceOffloading(char *pcap_dev); +int GetIfaceMTU(const char *pcap_dev); +int GetIfaceMaxPacketSize(const char *pcap_dev); +int GetIfaceOffloading(const char *pcap_dev); int GetIfaceRSSQueuesNum(const char *pcap_dev); From e951afb911b4b3975ea03a519e0fc082c32b0316 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 5 Dec 2014 10:17:15 +0100 Subject: [PATCH 0090/2553] afpacket: only check offloading once per iface Instead of once per thread per iface. --- src/runmode-af-packet.c | 5 +++++ src/source-af-packet.c | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 4c071f3529a7..29817d22be30 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -341,6 +341,11 @@ void *ParseAFPConfig(const char *iface) } } + if (GetIfaceOffloading(iface) == 1) { + SCLogWarning(SC_ERR_AFP_CREATE, + "Using AF_PACKET with GRO or LRO activated can lead to capture problems"); + } + return aconf; } diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 1d67f0a51e48..174fcb0e9d4d 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1502,11 +1502,6 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) goto socket_err; } - if (GetIfaceOffloading(devname) == 1) { - SCLogWarning(SC_ERR_AFP_CREATE, - "Using mmap mode with GRO or LRO activated can lead to capture problems"); - } - /* Allocate RX ring */ #define DEFAULT_ORDER 3 for (order = DEFAULT_ORDER; order >= 0; order--) { From d951de2f199d67d0e516cfd11db1612ffee0d71a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 20 Nov 2014 14:18:03 +0100 Subject: [PATCH 0091/2553] Bug 977: -T / --init-errors-fatal to process all rules Have -T / --init-errors-fatal process all rules so that it's easier to debug problems in ruleset. Otherwise it can be a lengthy fix, test error cycle if multiple rules have issues. Convert empty rulefile error into a warning. Bug #977 --- src/detect-parse.c | 13 -------- src/detect.c | 77 +++++++++++++++++++++++----------------------- src/suricata.c | 6 +--- 3 files changed, 39 insertions(+), 57 deletions(-) diff --git a/src/detect-parse.c b/src/detect-parse.c index 8145b2c1abb1..92501e016ea3 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1535,12 +1535,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (sig != NULL) { SigFree(sig); } - - if (de_ctx->failure_fatal == 1) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature parsing failed: " - "\"%s\"", sigstr); - exit(EXIT_FAILURE); - } return NULL; } @@ -1578,13 +1572,6 @@ Signature *SigInit(DetectEngineCtx *de_ctx, char *sigstr) if (sig != NULL) { SigFree(sig); } - - if (de_ctx->failure_fatal == 1) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature parsing failed: " - "\"%s\"", sigstr); - exit(EXIT_FAILURE); - } - /* if something failed, restore the old signum count * since we didn't install it */ de_ctx->signum = oldsignum; diff --git a/src/detect.c b/src/detect.c index 737bb3409c7f..c1cd88542bae 100644 --- a/src/detect.c +++ b/src/detect.c @@ -282,7 +282,8 @@ char *DetectLoadCompleteSigPath(char *sig_file) * \param sigs_tot Will store number of signatures processed in the file * \retval Number of rules loaded successfully, -1 on error */ -int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) +static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, + int *goodsigs, int *badsigs) { Signature *sig = NULL; int good = 0, bad = 0; @@ -290,6 +291,9 @@ int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) size_t offset = 0; int lineno = 0, multiline = 0; + (*goodsigs) = 0; + (*badsigs) = 0; + if (sig_file == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "opening rule file null"); return -1; @@ -336,7 +340,6 @@ int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) de_ctx->rule_line = lineno - multiline; sig = DetectEngineAppendSig(de_ctx, line); - (*sigs_tot)++; if (sig != NULL) { if (rule_engine_analysis_set || fp_engine_analysis_set) { sig->mpm_sm = RetrieveFPForSigV2(sig); @@ -356,16 +359,15 @@ int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) if (rule_engine_analysis_set) { EngineAnalysisRulesFailure(line, sig_file, lineno - multiline); } - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } bad++; } multiline = 0; } fclose(fp); - return good; + (*goodsigs) = good; + (*badsigs) = bad; + return 0; } /** @@ -383,11 +385,17 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl ConfNode *file = NULL; int ret = 0; int r = 0; - int cnt = 0; int cntf = 0; - int sigtotal = 0; char *sfile = NULL; + int goodsigs = 0; + int badsigs = 0; + + int badfiles = 0; + + int goodtotal = 0; + int badtotal = 0; + if (RunmodeGetCurrent() == RUNMODE_ENGINE_ANALYSIS) { fp_engine_analysis_set = SetupFPAnalyzer(); rule_engine_analysis_set = SetupRuleAnalyzer(); @@ -401,21 +409,18 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl sfile = DetectLoadCompleteSigPath(file->val); SCLogDebug("Loading rule file: %s", sfile); - r = DetectLoadSigFile(de_ctx, sfile, &sigtotal); cntf++; - if (r > 0) { - cnt += r; - } else if (r == 0){ + r = DetectLoadSigFile(de_ctx, sfile, &goodsigs, &badsigs); + if (r < 0) { + badfiles++; + } + if (goodsigs == 0) { SCLogWarning(SC_ERR_NO_RULES, "No rules loaded from %s", sfile); - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } - } else if (r < 0){ - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } } SCFree(sfile); + + goodtotal += goodsigs; + badtotal += badsigs; } } } @@ -423,40 +428,34 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl /* If a Signature file is specified from commandline, parse it too */ if (sig_file != NULL) { SCLogInfo("Loading rule file: %s", sig_file); - r = DetectLoadSigFile(de_ctx, sig_file, &sigtotal); cntf++; - if (r > 0) { - cnt += r; - } else if (r == 0) { - SCLogError(SC_ERR_NO_RULES, "No rules loaded from %s", sig_file); - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } - } else if (r < 0){ - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } + r = DetectLoadSigFile(de_ctx, sig_file, &goodsigs, &badsigs); + if (r < 0) { + badfiles++; } + if (goodsigs == 0) { + SCLogWarning(SC_ERR_NO_RULES, "No rules loaded from %s", sig_file); + } + + goodtotal += goodsigs; + badtotal += badsigs; } /* now we should have signatures to work with */ - if (cnt <= 0) { + if (goodsigs <= 0) { if (cntf > 0) { - SCLogError(SC_ERR_NO_RULES_LOADED, "%d rule files specified, but no rule was loaded at all!", cntf); - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } - ret = -1; + SCLogWarning(SC_ERR_NO_RULES_LOADED, "%d rule files specified, but no rule was loaded at all!", cntf); } else { SCLogInfo("No signatures supplied."); goto end; } } else { /* we report the total of files and rules successfully loaded and failed */ - SCLogInfo("%" PRId32 " rule files processed. %" PRId32 " rules successfully loaded, %" PRId32 " rules failed", cntf, cnt, sigtotal-cnt); + SCLogInfo("%" PRId32 " rule files processed. %" PRId32 " rules successfully loaded, %" PRId32 " rules failed", cntf, goodtotal, badtotal); } - if (ret < 0 && de_ctx->failure_fatal) { + if ((badtotal || badfiles) && de_ctx->failure_fatal) { + ret = -1; goto end; } diff --git a/src/suricata.c b/src/suricata.c index c9a2084a953d..31a2411fe7bd 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1917,11 +1917,7 @@ static void SetupDelayedDetect(DetectEngineCtx *de_ctx, SCInstance *suri) static int LoadSignatures(DetectEngineCtx *de_ctx, SCInstance *suri) { if (SigLoadSignatures(de_ctx, suri->sig_file, suri->sig_file_exclusive) < 0) { - if (suri->sig_file == NULL) { - SCLogError(SC_ERR_OPENING_FILE, "Signature file has not been provided"); - } else { - SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); - } + SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); if (de_ctx->failure_fatal) return TM_ECODE_FAILED; } From 68e6c4e94b8b7e5d61ea7062ff21d2678bedde32 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Wed, 19 Nov 2014 13:48:41 -0500 Subject: [PATCH 0092/2553] Correct flow memory usage bookkeeping error Fix bug 1321 where flow_memuse was incremented more on allocation than free. --- src/flow-util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flow-util.c b/src/flow-util.c index 7bd685743a41..b4b54c188e45 100644 --- a/src/flow-util.c +++ b/src/flow-util.c @@ -79,7 +79,8 @@ void FlowFree(Flow *f) FLOW_DESTROY(f); SCFree(f); - (void) SC_ATOMIC_SUB(flow_memuse, sizeof(Flow)); + size_t size = sizeof(Flow) + FlowStorageSize(); + (void) SC_ATOMIC_SUB(flow_memuse, size); } /** From 0bb2b15491995c66e2b600e5e71c70ffd0de1513 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 20 Nov 2014 14:31:34 +0100 Subject: [PATCH 0093/2553] ipv6: check for MLD messages with HL not 1 MLD messages should have a hop limit of 1 only. All others are invalid. Written at MLD talk of Enno Rey, Antonios Atlasis & Jayson Salazar during Deepsec 2014. --- rules/decoder-events.rules | 3 ++- src/decode-events.h | 1 + src/decode-icmpv6.c | 9 +++++++++ src/detect-engine-event.h | 1 + 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/rules/decoder-events.rules b/rules/decoder-events.rules index cee0b065c46b..d731dc8ddd9a 100644 --- a/rules/decoder-events.rules +++ b/rules/decoder-events.rules @@ -56,6 +56,7 @@ alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown type"; decode-even alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown code"; decode-event:icmpv6.unknown_code; sid:2200030; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 truncated packet"; decode-event:icmpv6.ipv6_trunc_pkt; sid:2200031; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown version"; decode-event:icmpv6.ipv6_unknown_version; sid:2200032; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 MLD hop limit not 1"; decode-event:icmpv6.mld_message_with_invalid_hl; sid:2200102; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP packet too small"; decode-event:tcp.pkt_too_small; sid:2200033; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP header length too small"; decode-event:tcp.hlen_too_small; sid:2200034; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP invalid option length"; decode-event:tcp.invalid_optlen; sid:2200035; rev:1;) @@ -122,5 +123,5 @@ alert pkthdr any any -> any any (msg:"SURICATA MPLS bad implicit null label"; de alert pkthdr any any -> any any (msg:"SURICATA MPLS reserved label"; decode-event:mpls.bad_label_reserved; sid: 2200100; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA MPLS unknown payload type"; decode-event:mpls.unknown_payload_type; sid: 2200101; rev:1;) -# next sid is 2200102 +# next sid is 2200103 diff --git a/src/decode-events.h b/src/decode-events.h index 658b997312a6..d9cceb1648ea 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -57,6 +57,7 @@ enum { ICMPV6_PKT_TOO_SMALL, /**< icmpv6 smaller than minimum size */ ICMPV6_IPV6_UNKNOWN_VER, /**< unknown version in icmpv6 packet */ ICMPV6_IPV6_TRUNC_PKT, /**< truncated icmpv6 packet */ + ICMPV6_MLD_MESSAGE_WITH_INVALID_HL, /**< invalid MLD that doesn't have HL 1 */ /* IPV6 EVENTS */ IPV6_PKT_TOO_SMALL, /**< ipv6 packet smaller than minimum size */ diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index 71623ab0403b..4cd62ef96434 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -298,18 +298,27 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, if (p->icmpv6h->code != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } + if (IPV6_GET_HLIM(p) != 1) { + ENGINE_SET_EVENT(p, ICMPV6_MLD_MESSAGE_WITH_INVALID_HL); + } break; case MLD_LISTENER_REPORT: SCLogDebug("MLD_LISTENER_REPORT"); if (p->icmpv6h->code != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } + if (IPV6_GET_HLIM(p) != 1) { + ENGINE_SET_EVENT(p, ICMPV6_MLD_MESSAGE_WITH_INVALID_HL); + } break; case MLD_LISTENER_REDUCTION: SCLogDebug("MLD_LISTENER_REDUCTION"); if (p->icmpv6h->code != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } + if (IPV6_GET_HLIM(p) != 1) { + ENGINE_SET_EVENT(p, ICMPV6_MLD_MESSAGE_WITH_INVALID_HL); + } break; default: SCLogDebug("ICMPV6 Message type %" PRIu8 " not " diff --git a/src/detect-engine-event.h b/src/detect-engine-event.h index 1057399cc1e2..6270ca094be2 100644 --- a/src/detect-engine-event.h +++ b/src/detect-engine-event.h @@ -70,6 +70,7 @@ struct DetectEngineEvents_ { { "icmpv6.pkt_too_small", ICMPV6_PKT_TOO_SMALL,}, { "icmpv6.ipv6_unknown_version", ICMPV6_IPV6_UNKNOWN_VER,}, { "icmpv6.ipv6_trunc_pkt", ICMPV6_IPV6_TRUNC_PKT,}, + { "icmpv6.mld_message_with_invalid_hl", ICMPV6_MLD_MESSAGE_WITH_INVALID_HL,}, /* IPV6 EVENTS */ { "ipv6.pkt_too_small", IPV6_PKT_TOO_SMALL, }, From 096b85ab683856ec0e718a879c1698d01b42a331 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 10 Dec 2014 17:31:57 +0100 Subject: [PATCH 0094/2553] stream: don't send EOF to AppLayer too soon Sending EOF too soon results in the AppLayer cleaning up prematurely. --- src/stream-tcp-reassemble.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 2d1170a14c90..5333c3e6caee 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -1919,7 +1919,10 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {\ flag |= STREAM_START; \ } \ - if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) { \ + if (ssn->state == TCP_CLOSED) { \ + flag |= STREAM_EOF; \ + } \ + if (p->flags & PKT_PSEUDO_STREAM_END) { \ flag |= STREAM_EOF; \ } \ if ((p)->flowflags & FLOW_PKT_TOSERVER) { \ @@ -1937,7 +1940,10 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {\ flag |= STREAM_START; \ } \ - if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) { \ + if (ssn->state == TCP_CLOSED) { \ + flag |= STREAM_EOF; \ + } \ + if (p->flags & PKT_PSEUDO_STREAM_END) { \ flag |= STREAM_EOF; \ } \ if ((p)->flowflags & FLOW_PKT_TOSERVER) { \ From 9f22c878e89ff91481c26f73539d03e42b44d08c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 8 Dec 2014 14:49:16 +0100 Subject: [PATCH 0095/2553] unix-manager: fix cppcheck errors This patch fixes the following errors: [src/unix-manager.c:306]: (error) Memory pointed to by 'client' is freed twice. [src/unix-manager.c:313]: (error) Memory pointed to by 'client' is freed twice. [src/unix-manager.c:323]: (error) Memory pointed to by 'client' is freed twice. [src/unix-manager.c:334]: (error) Memory pointed to by 'client' is freed twice. Unix manager was treating the packet after closing the socket if message was too long. --- src/unix-manager.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/unix-manager.c b/src/unix-manager.c index 2d0a90641aa5..d28a7dac1d40 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -297,6 +297,7 @@ int UnixCommandAccept(UnixCommand *this) SCLogInfo("Command server: client message is too long, " "disconnect him."); close(client); + return 0; } buffer[ret] = 0; From c779065d3584f801f31159e28ab8d4446d984649 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 5 Dec 2014 14:32:56 +0100 Subject: [PATCH 0096/2553] Bug 1329: error out on invalid rule protocol Due to a logic error in AppLayerProtoDetectGetProtoByName invalid protocols would not be detected as such. Instead of ALPROTO_UNKNOWN ALPROTO_MAX was returned. Bug #1329 --- src/app-layer-detect-proto.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index b5b380cdbb22..762d140b1111 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1729,19 +1729,17 @@ AppProto AppLayerProtoDetectGetProtoByName(char *alproto_name) { SCEnter(); - AppProto a = ALPROTO_UNKNOWN; - + AppProto a; for (a = 0; a < ALPROTO_MAX; a++) { if (alpd_ctx.alproto_names[a] != NULL && strlen(alpd_ctx.alproto_names[a]) == strlen(alproto_name) && (SCMemcmp(alpd_ctx.alproto_names[a], alproto_name, strlen(alproto_name)) == 0)) { - goto end; + SCReturnCT(a, "AppProto"); } } - end: - SCReturnCT(a, "AppProto"); + SCReturnCT(ALPROTO_UNKNOWN, "AppProto"); } char *AppLayerProtoDetectGetProtoName(AppProto alproto) From 1faa94c314524a35452a5abbf19c2dd0a8fd01ae Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Wed, 5 Nov 2014 11:43:40 -0500 Subject: [PATCH 0097/2553] Make bad copy-mode be an error in runmode-tile. --- src/runmode-tile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runmode-tile.c b/src/runmode-tile.c index 9e12fd9e8512..1839234dddb9 100644 --- a/src/runmode-tile.c +++ b/src/runmode-tile.c @@ -130,7 +130,8 @@ void *ParseMpipeConfig(const char *iface) aconf->out_iface); aconf->copy_mode = MPIPE_COPY_MODE_TAP; } else { - SCLogInfo("Invalid mode (no in tap, ips)"); + SCLogError(SC_ERR_RUNMODE, "Invalid mode (expected tap or ips)"); + exit(EXIT_FAILURE); } } return aconf; From b9e20ab4b85dfa8a27393ad125e98015306596e2 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Wed, 3 Dec 2014 15:35:38 -0500 Subject: [PATCH 0098/2553] Clean up memory leaks in ac-tile code Free some memory at exit that was not getting freed. Change pid_pat_list to store copy of case-strings in the same block of memory as the array of pointers. --- src/util-mpm-ac-tile.c | 74 +++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index f74f04d2150f..0f270f24e06f 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -1196,24 +1196,42 @@ int SCACTilePreparePatterns(MpmCtx *mpm_ctx) SCFree(ctx->init_hash); ctx->init_hash = NULL; - /* handle no case patterns */ - ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACTilePatternList)); - if (ctx->pid_pat_list == NULL) { + /* Handle case patterns by storing a copy of the pattern to compare + * to each possible match (no-case). + * + * Allocate the memory for the array and each of the strings as one block. + */ + size_t string_space_needed = 0; + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { + /* Round up to next 8 byte aligned length */ + uint32_t space = ((ctx->parray[i]->len + 7) / 8) * 8; + string_space_needed += space; + } + } + + size_t pattern_list_size = (ctx->max_pat_id + 1) * sizeof(SCACTilePatternList); + size_t mem_size = string_space_needed + pattern_list_size; + void *mem_block = SCCalloc(1, mem_size); + if (mem_block == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACTilePatternList)); + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += mem_size; + /* Split the allocated block into pattern list array and string space. */ + ctx->pid_pat_list = mem_block; + uint8_t *string_space = mem_block + pattern_list_size; + /* Now make the copies of the no-case strings. */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { - ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len); - if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs, - ctx->parray[i]->original_pat, ctx->parray[i]->len); - ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; + uint32_t len = ctx->parray[i]->len; + uint32_t space = ((len + 7) / 8) * 8; + memcpy(string_space, ctx->parray[i]->original_pat, len); + ctx->pid_pat_list[ctx->parray[i]->id].cs = string_space; + ctx->pid_pat_list[ctx->parray[i]->id].patlen = len; + string_space += space; } } @@ -1338,33 +1356,6 @@ static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx) ctx->parray = NULL; } - if (ctx->state_table != NULL) { - SCFree(ctx->state_table); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (ctx->state_count * - ctx->bytes_per_state * ctx->alphabet_storage); - } - - if (ctx->output_table != NULL) { - int state; - for (state = 0; state < ctx->state_count; state++) { - if (ctx->output_table[state].pids != NULL) { - SCFree(ctx->output_table[state].pids); - } - } - SCFree(ctx->output_table); - } - - if (ctx->pid_pat_list != NULL) { - int i; - for (i = 0; i < (ctx->max_pat_id + 1); i++) { - if (ctx->pid_pat_list[i].cs != NULL) - SCFree(ctx->pid_pat_list[i].cs); - } - SCFree(ctx->pid_pat_list); - } - SCFree(ctx); search_ctx->init_ctx = NULL; } @@ -1383,7 +1374,10 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) /* Destroy Initialization data */ SCACTileDestroyInitCtx(mpm_ctx); - // TODO: Free Search tables + /* Free Search tables */ + SCFree(search_ctx->state_table); + SCFree(search_ctx->pid_pat_list); + SCFree(search_ctx->output_table); SCFree(search_ctx); mpm_ctx->ctx = NULL; From 3f86c5a83f7b4d936e7305fa67160623a4f2bea5 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Wed, 3 Dec 2014 15:55:22 -0500 Subject: [PATCH 0099/2553] Fix memory leak in ac-tile Incorrectly reallocing the goto table after it was freed by calling SCACTileReallocState() when really only want to realloc the output table. This was causing a large goto table to be allocated and never used or freed. --- src/util-mpm-ac-tile.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 0f270f24e06f..b4735527bcf0 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -523,32 +523,35 @@ static int SCACTileAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, return -1; } -static void SCACTileReallocState(SCACTileCtx *ctx, int new_state_count) +static void SCACTileReallocOutputTable(SCACTileCtx *ctx, int new_state_count) { - void *ptmp; - int size = 0; - /* reallocate space in the goto table to include a new state */ - size = ctx->allocated_state_count * sizeof(int32_t) * 256; - ptmp = SCRealloc(ctx->goto_table, size); + /* reallocate space in the output table for the new state */ + size_t size = ctx->allocated_state_count * sizeof(SCACTileOutputTable); + void *ptmp = SCRealloc(ctx->output_table, size); if (ptmp == NULL) { - SCFree(ctx->goto_table); - ctx->goto_table = NULL; + SCFree(ctx->output_table); + ctx->output_table = NULL; SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - ctx->goto_table = ptmp; + ctx->output_table = ptmp; +} - /* reallocate space in the output table for the new state */ - size = ctx->allocated_state_count * sizeof(SCACTileOutputTable); - ptmp = SCRealloc(ctx->output_table, size); +static void SCACTileReallocState(SCACTileCtx *ctx, int new_state_count) +{ + /* reallocate space in the goto table to include a new state */ + size_t size = ctx->allocated_state_count * sizeof(int32_t) * 256; + void *ptmp = SCRealloc(ctx->goto_table, size); if (ptmp == NULL) { - SCFree(ctx->output_table); - ctx->output_table = NULL; + SCFree(ctx->goto_table); + ctx->goto_table = NULL; SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - ctx->output_table = ptmp; + ctx->goto_table = ptmp; + + SCACTileReallocOutputTable(ctx, new_state_count); } /** @@ -1133,7 +1136,7 @@ static void SCACTilePrepareSearch(MpmCtx *mpm_ctx) SCACTileCtx *ctx = search_ctx->init_ctx; /* Resize the output table to be only as big as its final size. */ - SCACTileReallocState(ctx, ctx->state_count); + SCACTileReallocOutputTable(ctx, ctx->state_count); search_ctx->search = ctx->search; memcpy(search_ctx->translate_table, ctx->translate_table, sizeof(ctx->translate_table)); From 3f3481e4d2ceee85fb5e01aca7141a644a408be6 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Wed, 3 Dec 2014 16:42:01 -0500 Subject: [PATCH 0100/2553] Fix indentation --- src/detect-engine-mpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 6a81fde277e6..bff9ca8de791 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -2309,7 +2309,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) has_co_hhhd || has_co_hrhhd || has_co_dnsquery) -{ + { PatternMatchPreparePopulateMpm(de_ctx, sh); From b9787304868a07080ef761de54b451630ffb16e5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 11 Dec 2014 14:21:45 +0100 Subject: [PATCH 0101/2553] unix-socket: fix restart/shutdown cycle When cleaning up after a pcap was processed, the stats api was cleaned up before the stats threads were killed, leading to a BUG_ON triggering. --- src/runmode-unix-socket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index d8d55a10d8fd..83daaaf0c99b 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -295,13 +295,14 @@ TmEcode UnixSocketPcapFilesCheck(void *data) TmThreadKillThreadsFamily(TVT_PPT); TmThreadClearThreadsFamily(TVT_PPT); FlowKillFlowRecyclerThread(); - RunModeShutDown(); /* kill remaining mgt threads */ TmThreadKillThreadsFamily(TVT_MGMT); TmThreadClearThreadsFamily(TVT_MGMT); SCPerfReleaseResources(); + RunModeShutDown(); + /* mgt and ppt threads killed, we can run non thread-safe * shutdown functions */ FlowShutdown(); From 84e8217fd87281db1587042653a19878aa3f6f26 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 11 Dec 2014 14:49:17 +0100 Subject: [PATCH 0102/2553] unix-socket: allow socked in custom locations Allow the socket to be set in any location. This allows for easy setting up of a socket as a non-root user. --- scripts/suricatasc/suricatasc.in | 2 +- src/unix-manager.c | 46 +++++++++++++++++++------------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/scripts/suricatasc/suricatasc.in b/scripts/suricatasc/suricatasc.in index 30d482dcd280..12340a715d9d 100755 --- a/scripts/suricatasc/suricatasc.in +++ b/scripts/suricatasc/suricatasc.in @@ -25,7 +25,7 @@ parser.add_argument('socket', metavar='socket', nargs='?', help='socket file to args = parser.parse_args() if args.socket != None: - SOCKET_PATH = "@e_localstatedir@/" + args.socket[0] + SOCKET_PATH = args.socket else: SOCKET_PATH = "@e_localstatedir@/suricata-command.socket" diff --git a/src/unix-manager.c b/src/unix-manager.c index d28a7dac1d40..2026ab011aaf 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -102,26 +102,36 @@ int UnixNew(UnixCommand * this) TAILQ_INIT(&this->tasks); TAILQ_INIT(&this->clients); - /* Create socket dir */ - ret = mkdir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP); - if ( ret != 0 ) { - int err = errno; - if (err != EEXIST) { - SCLogError(SC_ERR_OPENING_FILE, - "Cannot create socket directory %s: %s", SOCKET_PATH, strerror(err)); - return 0; - } - } - if (ConfGet("unix-command.filename", &socketname) == 1) { - int socketlen = strlen(SOCKET_PATH) + strlen(socketname) + 2; - sockettarget = SCMalloc(socketlen); - if (unlikely(sockettarget == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); - return 0; + if (PathIsAbsolute(socketname)) { + sockettarget = SCStrdup(socketname); + if (unlikely(sockettarget == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); + return 0; + } + } else { + int socketlen = strlen(SOCKET_PATH) + strlen(socketname) + 2; + sockettarget = SCMalloc(socketlen); + if (unlikely(sockettarget == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); + return 0; + } + snprintf(sockettarget, socketlen, "%s/%s", SOCKET_PATH, socketname); + + /* Create socket dir */ + ret = mkdir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP); + if ( ret != 0 ) { + int err = errno; + if (err != EEXIST) { + SCFree(sockettarget); + SCLogError(SC_ERR_OPENING_FILE, + "Cannot create socket directory %s: %s", SOCKET_PATH, strerror(err)); + return 0; + } + } + } - snprintf(sockettarget, socketlen, "%s/%s", SOCKET_PATH, socketname); - SCLogInfo("Use unix socket file '%s'.", sockettarget); + SCLogInfo("Using unix socket file '%s'", sockettarget); } if (sockettarget == NULL) { sockettarget = SCStrdup(SOCKET_TARGET); From 55ccd3b17da45ea0fe234cddc99057a7eaf8e3fb Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 11 Dec 2014 20:01:59 +0100 Subject: [PATCH 0103/2553] suricatasc: now python 2 and 3 compatible Update code to support both python 2 and python 3. --- scripts/suricatasc/src/suricatasc.py | 55 ++++++++++++++++++---------- scripts/suricatasc/suricatasc.in | 20 +++++----- 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index d3babe188ea7..c941b4b51ee9 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -14,7 +14,10 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import simplejson as json +try: + import simplejson as json +except: + import json import re import readline from socket import socket, AF_UNIX, error @@ -69,7 +72,7 @@ def __call__(self, text, state): if state == 0: self.generator = self.complete(text) try: - return self.generator.next() + return next(self.generator) except StopIteration: return None return None @@ -86,11 +89,14 @@ def json_recv(self): data = "" while i < 5: i += 1 - data += self.socket.recv(SIZE) + if sys.version < '3': + data += self.socket.recv(SIZE) + else: + data += self.socket.recv(SIZE).decode('iso-8859-1') try: cmdret = json.loads(data) break - except json.decoder.JSONDecodeError: + except: sleep(0.3) return cmdret @@ -103,15 +109,18 @@ def send_command(self, command, arguments = None): if (arguments != None): cmdmsg['arguments'] = arguments if self.verbose: - print "SND: " + json.dumps(cmdmsg) - self.socket.send(json.dumps(cmdmsg)) + print("SND: " + json.dumps(cmdmsg)) + if sys.version < '3': + self.socket.send(json.dumps(cmdmsg)) + else: + self.socket.send(bytes(json.dumps(cmdmsg), 'iso-8859-1')) cmdret = self.json_recv() if cmdret == None: raise SuricataReturnException("Unable to get message from server") if self.verbose: - print "RCV: "+ json.dumps(cmdret) + print("RCV: "+ json.dumps(cmdret)) return cmdret @@ -119,14 +128,17 @@ def connect(self): try: self.socket = socket(AF_UNIX) self.socket.connect(self.sck_path) - except error, err: + except error as err: raise SuricataNetException(err) self.socket.settimeout(10) #send version if self.verbose: - print "SND: " + json.dumps({"version": VERSION}) - self.socket.send(json.dumps({"version": VERSION})) + print("SND: " + json.dumps({"version": VERSION})) + if sys.version < '3': + self.socket.send(json.dumps({"version": VERSION})) + else: + self.socket.send(bytes(json.dumps({"version": VERSION}), 'iso-8859-1')) # get return cmdret = self.json_recv() @@ -135,7 +147,7 @@ def connect(self): raise SuricataReturnException("Unable to get message from server") if self.verbose: - print "RCV: "+ json.dumps(cmdret) + print("RCV: "+ json.dumps(cmdret)) if cmdret["return"] == "NOK": raise SuricataReturnException("Error: %s" % (cmdret["message"])) @@ -192,27 +204,30 @@ def parse_command(self, command): return (cmd, arguments) def interactive(self): - print "Command list: " + ", ".join(self.cmd_list) + print("Command list: " + ", ".join(self.cmd_list)) try: readline.set_completer(SuricataCompleter(self.cmd_list)) readline.set_completer_delims(";") readline.parse_and_bind('tab: complete') while True: - command = raw_input(">>> ").strip() + if sys.version < '3': + command = raw_input(">>> ").strip() + else: + command = input(">>> ").strip() if command == "quit": break; try: (cmd, arguments) = self.parse_command(command) - except SuricataCommandException, err: - print err + except SuricataCommandException as err: + print(err) continue cmdret = self.send_command(cmd, arguments) #decode json message if cmdret["return"] == "NOK": - print "Error:" - print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': ')) + print("Error:") + print(json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))) else: - print "Success:" - print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': ')) + print("Success:") + print(json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))) except KeyboardInterrupt: - print "[!] Interrupted" + print("[!] Interrupted") diff --git a/scripts/suricatasc/suricatasc.in b/scripts/suricatasc/suricatasc.in index 12340a715d9d..ea00f09380d7 100755 --- a/scripts/suricatasc/suricatasc.in +++ b/scripts/suricatasc/suricatasc.in @@ -32,28 +32,28 @@ else: sc = SuricataSC(SOCKET_PATH, verbose=args.verbose) try: sc.connect() -except SuricataNetException, err: - print "Unable to connect to socket %s: %s" % (SOCKET_PATH, err) +except SuricataNetException as err: + print("Unable to connect to socket %s: %s" % (SOCKET_PATH, err)) sys.exit(1) -except SuricataReturnException, err: - print "Unable to negotiate version with server: %s" % (err) +except SuricataReturnException as err: + print("Unable to negotiate version with server: %s" % (err)) sys.exit(1) if args.command: (command, arguments) = sc.parse_command(args.command) - print sc.send_command(command, arguments) + print(sc.send_command(command, arguments)) sc.close() sys.exit(0) try: sc.interactive() -except SuricataNetException, err: - print "Communication error: %s" % (err) +except SuricataNetException as err: + print("Communication error: %s" % (err)) sys.exit(1) -except SuricataReturnException, err: - print "Invalid return from server: %s" % (err) +except SuricataReturnException as err: + print("Invalid return from server: %s" % (err)) sys.exit(1) -print "[+] Quit command client" +print("[+] Quit command client") sc.close() From e564ac77fdefa2229724e123e10d6c9822f18482 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 12 Dec 2014 10:10:46 +0100 Subject: [PATCH 0104/2553] suricatasc: exit with error if command returns NOK --- scripts/suricatasc/suricatasc.in | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/suricatasc/suricatasc.in b/scripts/suricatasc/suricatasc.in index ea00f09380d7..4b44204bcf50 100755 --- a/scripts/suricatasc/suricatasc.in +++ b/scripts/suricatasc/suricatasc.in @@ -41,9 +41,13 @@ except SuricataReturnException as err: if args.command: (command, arguments) = sc.parse_command(args.command) - print(sc.send_command(command, arguments)) + res = sc.send_command(command, arguments) + print(res) sc.close() - sys.exit(0) + if res['return'] == 'OK': + sys.exit(0) + else: + sys.exit(1) try: sc.interactive() From 83d9834e776e5fdd9f1df6e17e5c8b0517cd5184 Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Mon, 15 Dec 2014 16:45:39 +0100 Subject: [PATCH 0105/2553] fix CID 1257762: Logically dead code(DEADCODE) --- src/app-layer-modbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 7d23bcacc402..d2518b5313d3 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -829,7 +829,7 @@ static int ModbusParseDiagnosticRequest(ModbusTransaction *tx, if (tx->subFunction != MODBUS_SUBFUNC_QUERY_DATA) { switch (tx->subFunction) { case MODBUS_SUBFUNC_RESTART_COM: - if ((data != 0x00) || (data != 0xFF00)) + if ((data != 0x00) && (data != 0xFF00)) goto error; break; From bfc871ce852c8942160feb8c1c3641ba04e7c9aa Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Mon, 15 Dec 2014 16:51:11 +0100 Subject: [PATCH 0106/2553] Update AppLayerProtoDetectPrintProbingParsers with Modbus protocol --- src/app-layer-detect-proto.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 762d140b1111..123b3248816f 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -685,6 +685,8 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp printf(" alproto: ALPROTO_IRC\n"); else if (pp_pe->alproto == ALPROTO_DNS) printf(" alproto: ALPROTO_DNS\n"); + else if (pp_pe->alproto == ALPROTO_MODBUS) + printf(" alproto: ALPROTO_MODBUS\n"); else printf("impossible\n"); @@ -734,6 +736,8 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp printf(" alproto: ALPROTO_IRC\n"); else if (pp_pe->alproto == ALPROTO_DNS) printf(" alproto: ALPROTO_DNS\n"); + else if (pp_pe->alproto == ALPROTO_MODBUS) + printf(" alproto: ALPROTO_MODBUS\n"); else printf("impossible\n"); From bacbe113d0d91251835dab3bb4e0bda01fa04bc5 Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Mon, 15 Dec 2014 17:37:04 +0100 Subject: [PATCH 0107/2553] Add a warning in Modbus section of YAML file to remind user to modify stream depth (unlimited) --- suricata.yaml.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/suricata.yaml.in b/suricata.yaml.in index ed34f7619083..c9458e733da6 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1205,6 +1205,11 @@ app-layer: enabled: yes detection-ports: dp: 502 + # According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it + # is recommended to keep the TCP connection opened with a remote device + # and not to open and close it for each MODBUS/TCP transaction. In that + # case, it is important to set the depth of the stream reassembling as + # unlimited (stream.reassembly.depth: 0) # smb2 detection is disabled internally inside the engine. #smb2: # enabled: yes From 0bdf494b544cbc45bbc571ceefe83f750c9b3ef7 Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Mon, 15 Dec 2014 17:53:34 +0100 Subject: [PATCH 0108/2553] fix Cygwin build fails: array subscript has type char --- src/detect-modbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-modbus.c b/src/detect-modbus.c index 306ca001a8d5..d1e4ec507d53 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -292,7 +292,7 @@ static DetectModbus *DetectModbusFunctionParse(char *str) if (unlikely(modbus == NULL)) goto error; - if (isdigit(ptr[0])) { + if (isdigit((unsigned char)ptr[0])) { modbus->function = atoi((const char*) ptr); SCLogDebug("will look for modbus function %d", modbus->function); From 4e04cd2d1be85cbd41c34ea922302121d05d55c9 Mon Sep 17 00:00:00 2001 From: Duarte Silva Date: Fri, 5 Dec 2014 15:40:58 +0000 Subject: [PATCH 0109/2553] Adding XFF support to EVE alert output - Created app-layer-htp-xff.c and app-layer-htp-xff.h - Added entries in the Makefile.am - Added the necessary configuration options to EVE alert section - Updated Unified2 XFF configuration comments and removed unnecessary whitespace - Created a generic function to parse the configuration - Release the flow locks sooner and remove debug logging - Added XFF support to EVE alert output --- src/Makefile.am | 1 + src/alert-unified2-alert.c | 281 ++++++++++++------------------------- src/app-layer-htp-xff.c | 168 ++++++++++++++++++++++ src/app-layer-htp-xff.h | 48 +++++++ src/output-json-alert.c | 67 ++++++++- suricata.yaml.in | 31 ++-- 6 files changed, 393 insertions(+), 203 deletions(-) create mode 100644 src/app-layer-htp-xff.c create mode 100644 src/app-layer-htp-xff.h diff --git a/src/Makefile.am b/src/Makefile.am index 6fac36e750bc..2ef8b3f0e652 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,6 +26,7 @@ app-layer-htp.c app-layer-htp.h \ app-layer-htp-file.c app-layer-htp-file.h \ app-layer-htp-libhtp.c app-layer-htp-libhtp.h \ app-layer-htp-mem.c app-layer-htp-mem.h \ +app-layer-htp-xff.c app-layer-htp-xff.h \ app-layer-modbus.c app-layer-modbus.h \ app-layer-parser.c app-layer-parser.h \ app-layer-protos.c app-layer-protos.h \ diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 9a0a280682c0..330cf55bd98d 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -58,6 +58,7 @@ #include "app-layer-parser.h" #include "app-layer-htp.h" #include "app-layer.h" +#include "app-layer-htp-xff.h" #include "output.h" #include "alert-unified2-alert.h" @@ -179,29 +180,14 @@ typedef struct AlertUnified2Packet_ { uint8_t packet_data[4]; /**< packet data */ } Unified2Packet; -/** XFF is disabled */ -#define UNIFIED2_ALERT_XFF_DISABLED 1 -/** XFF extra data mode */ -#define UNIFIED2_ALERT_XFF_EXTRADATA 2 -/** XFF overwrite mode */ -#define UNIFIED2_ALERT_XFF_OVERWRITE 4 /** Extracted XFF IP is v4 */ #define UNIFIED2_ALERT_XFF_IPV4 8 /** Extracted XFF IP is v4 */ #define UNIFIED2_ALERT_XFF_IPV6 16 -/** Default XFF header name */ -#define UNIFIED2_ALERT_XFF_DEFAULT "X-Forwarded-For" -/** Single XFF IP maximum length */ -#define UNIFIED2_ALERT_XFF_MAXLEN 46 -/** XFF header value minimal length */ -#define UNIFIED2_ALERT_XFF_CHAIN_MINLEN 7 -/** XFF header value maximum length */ -#define UNIFIED2_ALERT_XFF_CHAIN_MAXLEN 256 typedef struct Unified2AlertFileCtx_ { LogFileCtx *file_ctx; - uint8_t xff_mode; /**< XFF operation mode */ - char *xff_header; /**< XFF Header name */ + HttpXFFCfg *xff_cfg; } Unified2AlertFileCtx; /** @@ -328,85 +314,6 @@ static int Unified2Write(Unified2AlertThread *aun) return 1; } -static int GetXFFIPFromTx(const Packet *p, uint64_t tx_id, char *xff_header, char *dstbuf, int dstbuflen) -{ - uint8_t xff_chain[UNIFIED2_ALERT_XFF_CHAIN_MAXLEN]; - HtpState *htp_state = NULL; - htp_tx_t *tx = NULL; - uint64_t total_txs = 0; - - htp_state = (HtpState *)FlowGetAppState(p->flow); - - if (htp_state == NULL) { - SCLogDebug("no http state, XFF IP cannot be retrieved"); - return 0; - } - - total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, htp_state); - if (tx_id >= total_txs) - return 0; - - tx = AppLayerParserGetTx(p->flow->proto, ALPROTO_HTTP, htp_state, tx_id); - if (tx == NULL) { - SCLogDebug("tx is NULL, XFF cannot be retrieved"); - return 0; - } - - htp_header_t *h_xff = NULL; - if (tx->request_headers != NULL) { - h_xff = htp_table_get_c(tx->request_headers, xff_header); - } - - if (h_xff != NULL && bstr_len(h_xff->value) >= UNIFIED2_ALERT_XFF_CHAIN_MINLEN && - bstr_len(h_xff->value) < UNIFIED2_ALERT_XFF_CHAIN_MAXLEN) { - - memcpy(xff_chain, bstr_ptr(h_xff->value), bstr_len(h_xff->value)); - xff_chain[bstr_len(h_xff->value)]=0; - /** Check for chained IP's separated by ", ", we will get the last one */ - uint8_t *p_xff = memrchr(xff_chain, ' ', bstr_len(h_xff->value)); - if (p_xff == NULL) { - p_xff = xff_chain; - } else { - p_xff++; - } - /** Sanity check on extracted IP for IPv4 and IPv6 */ - uint32_t ip[4]; - if ( inet_pton(AF_INET, (char *)p_xff, ip ) == 1 || - inet_pton(AF_INET6, (char *)p_xff, ip ) == 1 ) { - strlcpy(dstbuf, (char *)p_xff, dstbuflen); - return 1; // OK - } - } - return 0; -} - -/** - * \brief Function to return XFF IP if any... - * \retval 1 if the IP has been found and returned in dstbuf - * \retval 0 if the IP has not being found or error - */ -static int GetXFFIP(const Packet *p, char *xff_header, char *dstbuf, int dstbuflen) -{ - HtpState *htp_state = NULL; - uint64_t tx_id = 0; - uint64_t total_txs = 0; - - htp_state = (HtpState *)FlowGetAppState(p->flow); - if (htp_state == NULL) { - SCLogDebug("no http state, XFF IP cannot be retrieved"); - goto end; - } - - total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, htp_state); - for (; tx_id < total_txs; tx_id++) { - if (GetXFFIPFromTx(p, tx_id, xff_header, dstbuf, dstbuflen) == 1) - return 1; - } - -end: - return 0; // Not found -} - int Unified2Condition(ThreadVars *tv, const Packet *p) { if (likely(p->alerts.cnt == 0 && !(p->flags & PKT_HAS_TAG))) return FALSE; @@ -423,39 +330,42 @@ int Unified2Logger(ThreadVars *t, void *data, const Packet *p) { int ret = 0; Unified2AlertThread *aun = (Unified2AlertThread *)data; - aun->xff_flags = UNIFIED2_ALERT_XFF_DISABLED; + aun->xff_flags = XFF_DISABLED; + + HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg; /* overwrite mode can only work per u2 block, not per individual * alert. So we'll look for an XFF record once */ - if ((aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_OVERWRITE) && p->flow != NULL) { - FLOWLOCK_RDLOCK(p->flow); + if ((xff_cfg->mode & XFF_OVERWRITE) && p->flow != NULL) { + char buffer[XFF_MAXLEN]; + int have_xff_ip = 0; + FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { - char buffer[UNIFIED2_ALERT_XFF_MAXLEN]; + have_xff_ip = HttpXFFGetIP(p, xff_cfg->header, buffer, XFF_MAXLEN); + } + FLOWLOCK_UNLOCK(p->flow); - if (GetXFFIP(p, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN) == 1) { - /** Be sure that we have a nice zeroed buffer */ - memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); + if (have_xff_ip) { + /** Be sure that we have a nice zeroed buffer */ + memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); - /** We can only have override mode if packet IP version matches - * the XFF IP version, otherwise fall-back to extra data */ - if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { - SCLogDebug("valid ipv4 xff, setting flags %s", buffer); - if (PKT_IS_IPV4(p)) { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_OVERWRITE); - } else { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_EXTRADATA); - } - } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { - if (PKT_IS_IPV6(p)) { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_OVERWRITE); - } else { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_EXTRADATA); - } + /** We can only have override mode if packet IP version matches + * the XFF IP version, otherwise fall-back to extra data */ + if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { + if (PKT_IS_IPV4(p)) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_OVERWRITE); + } else { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_EXTRADATA); + } + } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { + if (PKT_IS_IPV6(p)) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_OVERWRITE); + } else { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_EXTRADATA); } } } - FLOWLOCK_UNLOCK(p->flow); } if (PKT_IS_IPV4(p)) { @@ -555,7 +465,7 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 aun->offset = 0; // If XFF is in extra data mode... - if (aun->xff_flags & UNIFIED2_ALERT_XFF_EXTRADATA) { + if (aun->xff_flags & XFF_EXTRADATA) { memset(dhdr, 0, sizeof(Unified2ExtraData)); if (aun->xff_flags & UNIFIED2_ALERT_XFF_IPV4) { @@ -661,8 +571,9 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 goto error; } /** If XFF is in overwrite mode... */ - if (aun->xff_flags & UNIFIED2_ALERT_XFF_OVERWRITE) { + if (aun->xff_flags & XFF_OVERWRITE) { BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV6); + if (p->flowflags & FLOW_PKT_TOCLIENT) { fakehdr.ip4h.s_ip_dst.s_addr = aun->xff_ip[0]; } else { @@ -703,7 +614,7 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 goto error; } /** If XFF is in overwrite mode... */ - if (aun->xff_flags & UNIFIED2_ALERT_XFF_OVERWRITE) { + if (aun->xff_flags & XFF_OVERWRITE) { BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV4); if (p->flowflags & FLOW_PKT_TOCLIENT) { @@ -923,7 +834,7 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) gphdr.src_ip = *(struct in6_addr*)GET_IPV6_SRC_ADDR(p); gphdr.dst_ip = *(struct in6_addr*)GET_IPV6_DST_ADDR(p); /** If XFF is in overwrite mode... */ - if (aun->xff_flags & UNIFIED2_ALERT_XFF_OVERWRITE) { + if (aun->xff_flags & XFF_OVERWRITE) { BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV4); if (p->flowflags & FLOW_PKT_TOCLIENT) { @@ -983,29 +894,31 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) if (unlikely(pa->s == NULL)) continue; - if ((aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_EXTRADATA) && p->flow != NULL) { + HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg; + + if ((xff_cfg->mode & XFF_EXTRADATA) && p->flow != NULL) { + char buffer[XFF_MAXLEN]; + int have_xff_ip = 0; + FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { - char buffer[UNIFIED2_ALERT_XFF_MAXLEN]; - int have_xff_ip = 0; - if (pa->flags & PACKET_ALERT_FLAG_TX) { - have_xff_ip = GetXFFIPFromTx(p, pa->tx_id, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); + have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg->header, buffer, XFF_MAXLEN); } else { - have_xff_ip = GetXFFIP(p, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); - } - if (have_xff_ip) { - memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); - - if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { - SCLogDebug("valid ipv4 xff, setting flag"); - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_EXTRADATA); - } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_EXTRADATA); - } + have_xff_ip = HttpXFFGetIP(p, xff_cfg->header, buffer, XFF_MAXLEN); } } FLOWLOCK_UNLOCK(p->flow); + + if (have_xff_ip) { + memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); + + if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_EXTRADATA); + } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_EXTRADATA); + } + } } /* reset length and offset */ @@ -1108,7 +1021,7 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) gphdr.src_ip = p->ip4h->s_ip_src.s_addr; gphdr.dst_ip = p->ip4h->s_ip_dst.s_addr; /** If XFF is in overwrite mode... */ - if (aun->xff_flags & UNIFIED2_ALERT_XFF_OVERWRITE) { + if (aun->xff_flags & XFF_OVERWRITE) { BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV6); if (p->flowflags & FLOW_PKT_TOCLIENT) { @@ -1158,30 +1071,31 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) if (unlikely(pa->s == NULL)) continue; - if ((aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_EXTRADATA) && p->flow != NULL) { + HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg; + + if ((xff_cfg->mode & XFF_EXTRADATA) && p->flow != NULL) { + char buffer[XFF_MAXLEN]; + int have_xff_ip = 0; + FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { - char buffer[UNIFIED2_ALERT_XFF_MAXLEN]; - int have_xff_ip = 0; - if (pa->flags & PACKET_ALERT_FLAG_TX) { - have_xff_ip = GetXFFIPFromTx(p, pa->tx_id, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); + have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg->header, buffer, XFF_MAXLEN); } else { - have_xff_ip = GetXFFIP(p, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); - } - if (have_xff_ip) { - SCLogDebug("buffer %s", buffer); - memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); - - if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { - SCLogDebug("valid ipv4 xff, setting flags %s", buffer); - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_EXTRADATA); - } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_EXTRADATA); - } + have_xff_ip = HttpXFFGetIP(p, xff_cfg->header, buffer, XFF_MAXLEN); } } FLOWLOCK_UNLOCK(p->flow); + + if (have_xff_ip) { + memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); + + if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_EXTRADATA); + } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_EXTRADATA); + } + } } /* reset length and offset */ @@ -1331,7 +1245,7 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) int ret = 0; LogFileCtx* file_ctx = NULL; OutputCtx* output_ctx = NULL; - ConfNode *xff_node = NULL; + HttpXFFCfg *xff_cfg = NULL; file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { @@ -1395,49 +1309,27 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) if (unlikely(output_ctx == NULL)) goto error; + xff_cfg = SCMalloc(sizeof(HttpXFFCfg)); + if (unlikely(xff_cfg == NULL)) { + goto error; + } + memset(xff_cfg, 0x00, sizeof(HttpXFFCfg)); + + if (conf != NULL) { + HttpXFFGetCfg(conf, xff_cfg); + } + Unified2AlertFileCtx *unified2alert_ctx = SCMalloc(sizeof(Unified2AlertFileCtx)); if (unlikely(unified2alert_ctx == NULL)) { goto error; } memset(unified2alert_ctx, 0x00, sizeof(Unified2AlertFileCtx)); + unified2alert_ctx->file_ctx = file_ctx; + unified2alert_ctx->xff_cfg = xff_cfg; output_ctx->data = unified2alert_ctx; - output_ctx->DeInit = Unified2AlertDeInitCtx; - if (conf != NULL) - xff_node = ConfNodeLookupChild(conf, "xff"); - - if (xff_node != NULL && ConfNodeChildValueIsTrue(xff_node, "enabled")) { - const char *xff_mode = ConfNodeLookupChildValue(xff_node, "mode"); - - if (xff_mode != NULL && strcasecmp(xff_mode, "overwrite") == 0) { - unified2alert_ctx->xff_mode |= UNIFIED2_ALERT_XFF_OVERWRITE; - } else { - if (xff_mode == NULL) { - SCLogWarning(SC_WARN_XFF_INVALID_MODE, "The unified2 output XFF mode hasn't been defined, falling back to extra-data mode"); - } - else if (strcasecmp(xff_mode, "extra-data") != 0) { - SCLogWarning(SC_WARN_XFF_INVALID_MODE, "The unified2 output XFF mode %s is invalid, falling back to extra-data mode", - xff_mode); - } - unified2alert_ctx->xff_mode |= UNIFIED2_ALERT_XFF_EXTRADATA; - } - - const char *xff_header = ConfNodeLookupChildValue(xff_node, "header"); - - if (xff_header != NULL) { - unified2alert_ctx->xff_header = (char *) xff_header; - } else { - SCLogWarning(SC_WARN_XFF_INVALID_HEADER, "The unified2 output XFF header hasn't been defined, using the default %s", - UNIFIED2_ALERT_XFF_DEFAULT); - unified2alert_ctx->xff_header = UNIFIED2_ALERT_XFF_DEFAULT; - } - } - else { - unified2alert_ctx->xff_mode = UNIFIED2_ALERT_XFF_DISABLED; - } - SCLogInfo("Unified2-alert initialized: filename %s, limit %"PRIu64" MB", filename, file_ctx->size_limit / (1024*1024)); @@ -1446,6 +1338,9 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) return output_ctx; error: + if (xff_cfg != NULL) { + SCFree(xff_cfg); + } if (output_ctx != NULL) { SCFree(output_ctx); } @@ -1462,6 +1357,10 @@ static void Unified2AlertDeInitCtx(OutputCtx *output_ctx) if (logfile_ctx != NULL) { LogFileFreeCtx(logfile_ctx); } + HttpXFFCfg *xff_cfg = unified2alert_ctx->xff_cfg; + if (xff_cfg != NULL) { + SCFree(xff_cfg); + } SCFree(unified2alert_ctx); } SCFree(output_ctx); diff --git a/src/app-layer-htp-xff.c b/src/app-layer-htp-xff.c new file mode 100644 index 000000000000..2abf972675ec --- /dev/null +++ b/src/app-layer-htp-xff.c @@ -0,0 +1,168 @@ +/* Copyright (C) 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 Ignacio Sanchez + * \author Duarte Silva + */ + +#include "suricata-common.h" +#include "conf.h" + +#include "app-layer-parser.h" +#include "app-layer-htp.h" +#include "app-layer-htp-xff.h" + +#include "util-misc.h" + +/** XFF header value minimal length */ +#define XFF_CHAIN_MINLEN 7 +/** XFF header value maximum length */ +#define XFF_CHAIN_MAXLEN 256 +/** Default XFF header name */ +#define XFF_DEFAULT "X-Forwarded-For" + +/** + * \brief Function to return XFF IP if any in the selected transaction. The + * caller needs to lock the flow. + * \retval 1 if the IP has been found and returned in dstbuf + * \retval 0 if the IP has not being found or error + */ +int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, char *xff_header, char *dstbuf, + int dstbuflen) +{ + uint8_t xff_chain[XFF_CHAIN_MAXLEN]; + HtpState *htp_state = NULL; + htp_tx_t *tx = NULL; + uint64_t total_txs = 0; + + htp_state = (HtpState *)FlowGetAppState(p->flow); + + if (htp_state == NULL) { + SCLogDebug("no http state, XFF IP cannot be retrieved"); + return 0; + } + + total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, htp_state); + if (tx_id >= total_txs) + return 0; + + tx = AppLayerParserGetTx(p->flow->proto, ALPROTO_HTTP, htp_state, tx_id); + if (tx == NULL) { + SCLogDebug("tx is NULL, XFF cannot be retrieved"); + return 0; + } + + htp_header_t *h_xff = NULL; + if (tx->request_headers != NULL) { + h_xff = htp_table_get_c(tx->request_headers, xff_header); + } + + if (h_xff != NULL && bstr_len(h_xff->value) >= XFF_CHAIN_MINLEN && + bstr_len(h_xff->value) < XFF_CHAIN_MAXLEN) { + + memcpy(xff_chain, bstr_ptr(h_xff->value), bstr_len(h_xff->value)); + xff_chain[bstr_len(h_xff->value)]=0; + /** Check for chained IP's separated by ", ", we will get the last one */ + uint8_t *p_xff = memrchr(xff_chain, ' ', bstr_len(h_xff->value)); + if (p_xff == NULL) { + p_xff = xff_chain; + } else { + p_xff++; + } + /** Sanity check on extracted IP for IPv4 and IPv6 */ + uint32_t ip[4]; + if ( inet_pton(AF_INET, (char *)p_xff, ip ) == 1 || + inet_pton(AF_INET6, (char *)p_xff, ip ) == 1 ) { + strlcpy(dstbuf, (char *)p_xff, dstbuflen); + return 1; // OK + } + } + return 0; +} + +/** + * \brief Function to return XFF IP if any. The caller needs to lock the flow. + * \retval 1 if the IP has been found and returned in dstbuf + * \retval 0 if the IP has not being found or error + */ +int HttpXFFGetIP(const Packet *p, char *xff_header, char *dstbuf, int dstbuflen) +{ + HtpState *htp_state = NULL; + uint64_t tx_id = 0; + uint64_t total_txs = 0; + + htp_state = (HtpState *)FlowGetAppState(p->flow); + if (htp_state == NULL) { + SCLogDebug("no http state, XFF IP cannot be retrieved"); + goto end; + } + + total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, htp_state); + for (; tx_id < total_txs; tx_id++) { + if (HttpXFFGetIPFromTx(p, tx_id, xff_header, dstbuf, dstbuflen) == 1) + return 1; + } + +end: + return 0; // Not found +} + +/** + * \brief Function to return XFF configuration from a configuration node. + */ +void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result) +{ + BUG_ON(conf == NULL || result == NULL); + + ConfNode *xff_node = NULL; + + if (conf != NULL) + xff_node = ConfNodeLookupChild(conf, "xff"); + + if (xff_node != NULL && ConfNodeChildValueIsTrue(xff_node, "enabled")) { + const char *xff_mode = ConfNodeLookupChildValue(xff_node, "mode"); + + if (xff_mode != NULL && strcasecmp(xff_mode, "overwrite") == 0) { + result->mode |= XFF_OVERWRITE; + } else { + if (xff_mode == NULL) { + SCLogWarning(SC_WARN_XFF_INVALID_MODE, "The XFF mode hasn't been defined, falling back to extra-data mode"); + } + else if (strcasecmp(xff_mode, "extra-data") != 0) { + SCLogWarning(SC_WARN_XFF_INVALID_MODE, "The XFF mode %s is invalid, falling back to extra-data mode", + xff_mode); + } + result->mode |= XFF_EXTRADATA; + } + + const char *xff_header = ConfNodeLookupChildValue(xff_node, "header"); + + if (xff_header != NULL) { + result->header = (char *) xff_header; + } else { + SCLogWarning(SC_WARN_XFF_INVALID_HEADER, "The XFF header hasn't been defined, using the default %s", + XFF_DEFAULT); + result->header = XFF_DEFAULT; + } + } + else { + result->mode = XFF_DISABLED; + } +} diff --git a/src/app-layer-htp-xff.h b/src/app-layer-htp-xff.h new file mode 100644 index 000000000000..45c74b75348c --- /dev/null +++ b/src/app-layer-htp-xff.h @@ -0,0 +1,48 @@ +/* Copyright (C) 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 Ignacio Sanchez + * \author Duarte Silva + */ + +#ifndef __APP_LAYER_HTP_XFF_H__ +#define __APP_LAYER_HTP_XFF_H__ + +/** XFF is disabled */ +#define XFF_DISABLED 1 +/** XFF extra data mode */ +#define XFF_EXTRADATA 2 +/** XFF overwrite mode */ +#define XFF_OVERWRITE 4 +/** Single XFF IP maximum length (default value based on IPv6 address length) */ +#define XFF_MAXLEN 46 + +typedef struct HttpXFFCfg_ { + uint8_t mode; /**< XFF operation mode */ + char *header; /**< XFF header name */ +} HttpXFFCfg; + +void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result); + +int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, char *xff_header, char *dstbuf, int dstbuflen); + +int HttpXFFGetIP(const Packet *p, char *xff_header, char *dstbuf, int dstbuflen); + +#endif /* __APP_LAYER_HTP_XFF_H__ */ diff --git a/src/output-json-alert.c b/src/output-json-alert.c index d4d9f72d43d7..266e96c7b00e 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -44,6 +44,8 @@ #include "detect-engine-mpm.h" #include "detect-reference.h" #include "app-layer-parser.h" +#include "app-layer-htp.h" +#include "app-layer-htp-xff.h" #include "util-classification-config.h" #include "util-syslog.h" @@ -74,6 +76,7 @@ typedef struct AlertJsonOutputCtx_ { LogFileCtx* file_ctx; uint8_t flags; + HttpXFFCfg *xff_cfg; } AlertJsonOutputCtx; typedef struct JsonAlertLogThread_ { @@ -250,6 +253,37 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) json_object_set_new(js, "packet", json_string((char *)encoded_packet)); } + HttpXFFCfg *xff_cfg = json_output_ctx->xff_cfg; + + /* xff header */ + if (!(xff_cfg->mode & XFF_DISABLED) && p->flow != NULL) { + int have_xff_ip = 0; + char buffer[XFF_MAXLEN]; + + FLOWLOCK_RDLOCK(p->flow); + if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { + if (pa->flags & PACKET_ALERT_FLAG_TX) { + have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg->header, buffer, XFF_MAXLEN); + } else { + have_xff_ip = HttpXFFGetIP(p, xff_cfg->header, buffer, XFF_MAXLEN); + } + } + FLOWLOCK_UNLOCK(p->flow); + + if (have_xff_ip) { + if (xff_cfg->mode & XFF_EXTRADATA) { + json_object_set_new(js, "xff", json_string(buffer)); + } + else if (xff_cfg->mode & XFF_OVERWRITE) { + if (p->flowflags & FLOW_PKT_TOCLIENT) { + json_object_set(js, "dest_ip", json_string(buffer)); + } else { + json_object_set(js, "src_ip", json_string(buffer)); + } + } + } + } + OutputJSONBuffer(js, aft->file_ctx, aft->json_buffer); json_object_del(js, "alert"); } @@ -413,6 +447,11 @@ static void JsonAlertLogDeInitCtxSub(OutputCtx *output_ctx) AlertJsonOutputCtx *json_output_ctx = (AlertJsonOutputCtx *) output_ctx->data; if (json_output_ctx != NULL) { + HttpXFFCfg *xff_cfg = json_output_ctx->xff_cfg; + if (xff_cfg != NULL) { + SCFree(xff_cfg); + } + SCFree(json_output_ctx); } SCFree(output_ctx); @@ -455,19 +494,27 @@ static OutputCtx *JsonAlertLogInitCtx(ConfNode *conf) static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) { AlertJsonThread *ajt = parent_ctx->data; + AlertJsonOutputCtx *json_output_ctx = NULL; + HttpXFFCfg *xff_cfg = NULL; OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; - AlertJsonOutputCtx *json_output_ctx = SCMalloc(sizeof(AlertJsonOutputCtx)); + json_output_ctx = SCMalloc(sizeof(AlertJsonOutputCtx)); if (unlikely(json_output_ctx == NULL)) { - SCFree(output_ctx); - return NULL; + goto error; } - memset(json_output_ctx, 0, sizeof(AlertJsonOutputCtx)); + + xff_cfg = SCMalloc(sizeof(HttpXFFCfg)); + if (unlikely(xff_cfg == NULL)) { + goto error; + } + memset(xff_cfg, 0, sizeof(HttpXFFCfg)); + json_output_ctx->file_ctx = ajt->file_ctx; + json_output_ctx->xff_cfg = xff_cfg; if (conf != NULL) { const char *payload = ConfNodeLookupChildValue(conf, "payload"); @@ -495,12 +542,24 @@ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) json_output_ctx->flags |= LOG_JSON_PACKET; } } + + HttpXFFGetCfg(conf, xff_cfg); } output_ctx->data = json_output_ctx; output_ctx->DeInit = JsonAlertLogDeInitCtxSub; return output_ctx; + +error: + if (json_output_ctx != NULL) { + SCFree(json_output_ctx); + } + if (output_ctx != NULL) { + SCFree(output_ctx); + } + + return NULL; } void TmModuleJsonAlertLogRegister (void) diff --git a/suricata.yaml.in b/suricata.yaml.in index c9458e733da6..dc4b9babd857 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -105,6 +105,20 @@ outputs: # payload-printable: yes # enable dumping payload in printable (lossy) format # packet: yes # enable dumping of packet (without stream segments) # http: yes # enable dumping of http fields + + # HTTP X-Forwarded-For support by adding an extra field or overwriting + # the source or destination IP address (depending on flow direction) + # with the one reported in the X-Forwarded-For HTTP header. This is + # helpful when reviewing alerts for traffic that is being reversed + # proxied. + xff: + enabled: no + # Two operation modes are available, "extra-data" and "overwrite". + mode: extra-data + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For - http: extended: yes # enable this for extended logging information # custom allows additional http fields to be included in eve-log @@ -136,10 +150,11 @@ outputs: # Sensor ID field of unified2 alerts. #sensor-id: 0 - # HTTP X-Forwarded-For support by adding the unified2 extra header that - # will contain the actual client IP address or by overwriting the source - # IP address (helpful when inspecting traffic that is being reversed - # proxied). + # HTTP X-Forwarded-For support by adding the unified2 extra header or + # overwriting the source or destination IP address (depending on flow + # direction) with the one reported in the X-Forwarded-For HTTP header. + # This is helpful when reviewing alerts for traffic that is being reversed + # proxied. xff: enabled: no # Two operation modes are available, "extra-data" and "overwrite". Note @@ -147,10 +162,10 @@ outputs: # X-Forwarded-For header is of a different version of the packet # received, it will fall-back to "extra-data" mode. mode: extra-data - # Header name were the actual IP address will be reported, if more than - # one IP address is present, the last IP address will be the one taken - # into consideration. - header: X-Forwarded-For + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For # a line based log of HTTP requests (no alerts) - http-log: From 496200dd08e20ecdc2ac2b8657587af417c86d58 Mon Sep 17 00:00:00 2001 From: Duarte Silva Date: Fri, 5 Dec 2014 15:52:16 +0000 Subject: [PATCH 0110/2553] Prepared everything for the proxy deployment configuration - Added the suricata.yaml configurations and updated the comments - Renamed the field in the configuration structure to something generic - Added two new constants and the warning codes --- src/alert-unified2-alert.c | 6 +++--- src/app-layer-htp-xff.c | 21 ++++++++++++++++++--- src/app-layer-htp-xff.h | 6 +++++- src/output-json-alert.c | 6 +++--- src/util-error.c | 1 + src/util-error.h | 1 + suricata.yaml.in | 16 ++++++++++++---- 7 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 330cf55bd98d..14432d46a88e 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -336,7 +336,7 @@ int Unified2Logger(ThreadVars *t, void *data, const Packet *p) /* overwrite mode can only work per u2 block, not per individual * alert. So we'll look for an XFF record once */ - if ((xff_cfg->mode & XFF_OVERWRITE) && p->flow != NULL) { + if ((xff_cfg->flags & XFF_OVERWRITE) && p->flow != NULL) { char buffer[XFF_MAXLEN]; int have_xff_ip = 0; @@ -896,7 +896,7 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg; - if ((xff_cfg->mode & XFF_EXTRADATA) && p->flow != NULL) { + if ((xff_cfg->flags & XFF_EXTRADATA) && p->flow != NULL) { char buffer[XFF_MAXLEN]; int have_xff_ip = 0; @@ -1073,7 +1073,7 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg; - if ((xff_cfg->mode & XFF_EXTRADATA) && p->flow != NULL) { + if ((xff_cfg->flags & XFF_EXTRADATA) && p->flow != NULL) { char buffer[XFF_MAXLEN]; int have_xff_ip = 0; diff --git a/src/app-layer-htp-xff.c b/src/app-layer-htp-xff.c index 2abf972675ec..2d931daeb333 100644 --- a/src/app-layer-htp-xff.c +++ b/src/app-layer-htp-xff.c @@ -140,7 +140,7 @@ void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result) const char *xff_mode = ConfNodeLookupChildValue(xff_node, "mode"); if (xff_mode != NULL && strcasecmp(xff_mode, "overwrite") == 0) { - result->mode |= XFF_OVERWRITE; + result->flags |= XFF_OVERWRITE; } else { if (xff_mode == NULL) { SCLogWarning(SC_WARN_XFF_INVALID_MODE, "The XFF mode hasn't been defined, falling back to extra-data mode"); @@ -149,7 +149,22 @@ void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result) SCLogWarning(SC_WARN_XFF_INVALID_MODE, "The XFF mode %s is invalid, falling back to extra-data mode", xff_mode); } - result->mode |= XFF_EXTRADATA; + result->flags |= XFF_EXTRADATA; + } + + const char *xff_deployment = ConfNodeLookupChildValue(xff_node, "deployment"); + + if (xff_deployment != NULL && strcasecmp(xff_deployment, "forward") == 0) { + result->flags |= XFF_FORWARD; + } else { + if (xff_deployment == NULL) { + SCLogWarning(SC_WARN_XFF_INVALID_DEPLOYMENT, "The XFF deployment hasn't been defined, falling back to reverse proxy deployment"); + } + else if (strcasecmp(xff_deployment, "reverse") != 0) { + SCLogWarning(SC_WARN_XFF_INVALID_DEPLOYMENT, "The XFF mode %s is invalid, falling back to reverse proxy deployment", + xff_deployment); + } + result->flags |= XFF_REVERSE; } const char *xff_header = ConfNodeLookupChildValue(xff_node, "header"); @@ -163,6 +178,6 @@ void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result) } } else { - result->mode = XFF_DISABLED; + result->flags = XFF_DISABLED; } } diff --git a/src/app-layer-htp-xff.h b/src/app-layer-htp-xff.h index 45c74b75348c..5ef20125d5e5 100644 --- a/src/app-layer-htp-xff.h +++ b/src/app-layer-htp-xff.h @@ -31,11 +31,15 @@ #define XFF_EXTRADATA 2 /** XFF overwrite mode */ #define XFF_OVERWRITE 4 +/** XFF is to be used in a reverse proxy deployment */ +#define XFF_REVERSE 8 +/** XFF is to be used in a forward proxy deployment */ +#define XFF_FORWARD 16 /** Single XFF IP maximum length (default value based on IPv6 address length) */ #define XFF_MAXLEN 46 typedef struct HttpXFFCfg_ { - uint8_t mode; /**< XFF operation mode */ + uint8_t flags; /**< XFF operation mode and deployment */ char *header; /**< XFF header name */ } HttpXFFCfg; diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 266e96c7b00e..4a07f60eae07 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -256,7 +256,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) HttpXFFCfg *xff_cfg = json_output_ctx->xff_cfg; /* xff header */ - if (!(xff_cfg->mode & XFF_DISABLED) && p->flow != NULL) { + if (!(xff_cfg->flags & XFF_DISABLED) && p->flow != NULL) { int have_xff_ip = 0; char buffer[XFF_MAXLEN]; @@ -271,10 +271,10 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) FLOWLOCK_UNLOCK(p->flow); if (have_xff_ip) { - if (xff_cfg->mode & XFF_EXTRADATA) { + if (xff_cfg->flags & XFF_EXTRADATA) { json_object_set_new(js, "xff", json_string(buffer)); } - else if (xff_cfg->mode & XFF_OVERWRITE) { + else if (xff_cfg->flags & XFF_OVERWRITE) { if (p->flowflags & FLOW_PKT_TOCLIENT) { json_object_set(js, "dest_ip", json_string(buffer)); } else { diff --git a/src/util-error.c b/src/util-error.c index 454f8f3ff21b..e8dd99390231 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -291,6 +291,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_THREAD_QUEUE); CASE_CODE (SC_WARN_XFF_INVALID_MODE); CASE_CODE (SC_WARN_XFF_INVALID_HEADER); + CASE_CODE (SC_WARN_XFF_INVALID_DEPLOYMENT); CASE_CODE (SC_ERR_THRESHOLD_SETUP); CASE_CODE (SC_ERR_DNS_CONFIG); CASE_CODE (SC_ERR_MODBUS_CONFIG); diff --git a/src/util-error.h b/src/util-error.h index 21fc61116042..8d5577d8efa3 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -267,6 +267,7 @@ typedef enum { SC_ERR_THREAD_QUEUE, SC_WARN_XFF_INVALID_MODE, SC_WARN_XFF_INVALID_HEADER, + SC_WARN_XFF_INVALID_DEPLOYMENT, SC_ERR_THRESHOLD_SETUP, SC_ERR_DNS_CONFIG, SC_ERR_MODBUS_CONFIG, diff --git a/suricata.yaml.in b/suricata.yaml.in index dc4b9babd857..89c4326959aa 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -109,12 +109,16 @@ outputs: # HTTP X-Forwarded-For support by adding an extra field or overwriting # the source or destination IP address (depending on flow direction) # with the one reported in the X-Forwarded-For HTTP header. This is - # helpful when reviewing alerts for traffic that is being reversed - # proxied. + # helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. xff: enabled: no # Two operation modes are available, "extra-data" and "overwrite". mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse # Header name where the actual IP address will be reported, if more # than one IP address is present, the last IP address will be the # one taken into consideration. @@ -153,8 +157,8 @@ outputs: # HTTP X-Forwarded-For support by adding the unified2 extra header or # overwriting the source or destination IP address (depending on flow # direction) with the one reported in the X-Forwarded-For HTTP header. - # This is helpful when reviewing alerts for traffic that is being reversed - # proxied. + # This is helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. xff: enabled: no # Two operation modes are available, "extra-data" and "overwrite". Note @@ -162,6 +166,10 @@ outputs: # X-Forwarded-For header is of a different version of the packet # received, it will fall-back to "extra-data" mode. mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse # Header name where the actual IP address will be reported, if more # than one IP address is present, the last IP address will be the # one taken into consideration. From 68f43ffffb6f964042234cc0d5fffef5d94287cd Mon Sep 17 00:00:00 2001 From: Duarte Silva Date: Fri, 5 Dec 2014 15:59:05 +0000 Subject: [PATCH 0111/2553] Implemented the diferent behaviour depending on the proxy deployment - In forward deployment mode the first IP will be returned - In reverse deployment mode the last IP will be retuned --- src/alert-unified2-alert.c | 10 +++++----- src/app-layer-htp-xff.c | 32 ++++++++++++++++++++++---------- src/app-layer-htp-xff.h | 4 ++-- src/output-json-alert.c | 4 ++-- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 14432d46a88e..4bfea39770fa 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -342,7 +342,7 @@ int Unified2Logger(ThreadVars *t, void *data, const Packet *p) FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { - have_xff_ip = HttpXFFGetIP(p, xff_cfg->header, buffer, XFF_MAXLEN); + have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); } FLOWLOCK_UNLOCK(p->flow); @@ -903,9 +903,9 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { if (pa->flags & PACKET_ALERT_FLAG_TX) { - have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg->header, buffer, XFF_MAXLEN); + have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN); } else { - have_xff_ip = HttpXFFGetIP(p, xff_cfg->header, buffer, XFF_MAXLEN); + have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); } } FLOWLOCK_UNLOCK(p->flow); @@ -1080,9 +1080,9 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { if (pa->flags & PACKET_ALERT_FLAG_TX) { - have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg->header, buffer, XFF_MAXLEN); + have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN); } else { - have_xff_ip = HttpXFFGetIP(p, xff_cfg->header, buffer, XFF_MAXLEN); + have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); } } FLOWLOCK_UNLOCK(p->flow); diff --git a/src/app-layer-htp-xff.c b/src/app-layer-htp-xff.c index 2d931daeb333..9337ba18f7a7 100644 --- a/src/app-layer-htp-xff.c +++ b/src/app-layer-htp-xff.c @@ -44,13 +44,14 @@ * \retval 1 if the IP has been found and returned in dstbuf * \retval 0 if the IP has not being found or error */ -int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, char *xff_header, char *dstbuf, - int dstbuflen) +int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, HttpXFFCfg *xff_cfg, + char *dstbuf, int dstbuflen) { uint8_t xff_chain[XFF_CHAIN_MAXLEN]; HtpState *htp_state = NULL; htp_tx_t *tx = NULL; uint64_t total_txs = 0; + uint8_t *p_xff = NULL; htp_state = (HtpState *)FlowGetAppState(p->flow); @@ -71,7 +72,7 @@ int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, char *xff_header, char * htp_header_t *h_xff = NULL; if (tx->request_headers != NULL) { - h_xff = htp_table_get_c(tx->request_headers, xff_header); + h_xff = htp_table_get_c(tx->request_headers, xff_cfg->header); } if (h_xff != NULL && bstr_len(h_xff->value) >= XFF_CHAIN_MINLEN && @@ -79,12 +80,23 @@ int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, char *xff_header, char * memcpy(xff_chain, bstr_ptr(h_xff->value), bstr_len(h_xff->value)); xff_chain[bstr_len(h_xff->value)]=0; - /** Check for chained IP's separated by ", ", we will get the last one */ - uint8_t *p_xff = memrchr(xff_chain, ' ', bstr_len(h_xff->value)); - if (p_xff == NULL) { + + if (xff_cfg->flags & XFF_REVERSE) { + /** Get the last IP address from the chain */ + p_xff = memrchr(xff_chain, ' ', bstr_len(h_xff->value)); + if (p_xff == NULL) { + p_xff = xff_chain; + } else { + p_xff++; + } + } + else { + /** Get the first IP address from the chain */ + p_xff = memchr(xff_chain, ',', bstr_len(h_xff->value)); + if (p_xff != NULL) { + xff_chain[bstr_len(h_xff->value) - strlen((char *)p_xff)]=0; + } p_xff = xff_chain; - } else { - p_xff++; } /** Sanity check on extracted IP for IPv4 and IPv6 */ uint32_t ip[4]; @@ -102,7 +114,7 @@ int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, char *xff_header, char * * \retval 1 if the IP has been found and returned in dstbuf * \retval 0 if the IP has not being found or error */ -int HttpXFFGetIP(const Packet *p, char *xff_header, char *dstbuf, int dstbuflen) +int HttpXFFGetIP(const Packet *p, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen) { HtpState *htp_state = NULL; uint64_t tx_id = 0; @@ -116,7 +128,7 @@ int HttpXFFGetIP(const Packet *p, char *xff_header, char *dstbuf, int dstbuflen) total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, htp_state); for (; tx_id < total_txs; tx_id++) { - if (HttpXFFGetIPFromTx(p, tx_id, xff_header, dstbuf, dstbuflen) == 1) + if (HttpXFFGetIPFromTx(p, tx_id, xff_cfg, dstbuf, dstbuflen) == 1) return 1; } diff --git a/src/app-layer-htp-xff.h b/src/app-layer-htp-xff.h index 5ef20125d5e5..ad4eb8acda65 100644 --- a/src/app-layer-htp-xff.h +++ b/src/app-layer-htp-xff.h @@ -45,8 +45,8 @@ typedef struct HttpXFFCfg_ { void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result); -int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, char *xff_header, char *dstbuf, int dstbuflen); +int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen); -int HttpXFFGetIP(const Packet *p, char *xff_header, char *dstbuf, int dstbuflen); +int HttpXFFGetIP(const Packet *p, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen); #endif /* __APP_LAYER_HTP_XFF_H__ */ diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 4a07f60eae07..ed6b3b4373dc 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -263,9 +263,9 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { if (pa->flags & PACKET_ALERT_FLAG_TX) { - have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg->header, buffer, XFF_MAXLEN); + have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN); } else { - have_xff_ip = HttpXFFGetIP(p, xff_cfg->header, buffer, XFF_MAXLEN); + have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); } } FLOWLOCK_UNLOCK(p->flow); From e586644c254a5b2b71e5e3dd847c7fd7ea264352 Mon Sep 17 00:00:00 2001 From: Duarte Silva Date: Fri, 12 Dec 2014 18:21:24 +0000 Subject: [PATCH 0112/2553] Fix and improvements - Added/removed missing/superfluous util-memrchr.h include - Improved the extraction of a IP from the XFF chain of IPs --- src/alert-unified2-alert.c | 2 -- src/app-layer-htp-xff.c | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 4bfea39770fa..26bacb28cc31 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -69,8 +69,6 @@ #include "util-optimize.h" -#include "util-memrchr.h" - #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif diff --git a/src/app-layer-htp-xff.c b/src/app-layer-htp-xff.c index 9337ba18f7a7..5be84bbdb75f 100644 --- a/src/app-layer-htp-xff.c +++ b/src/app-layer-htp-xff.c @@ -30,6 +30,7 @@ #include "app-layer-htp-xff.h" #include "util-misc.h" +#include "util-memrchr.h" /** XFF header value minimal length */ #define XFF_CHAIN_MINLEN 7 @@ -94,7 +95,7 @@ int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, HttpXFFCfg *xff_cfg, /** Get the first IP address from the chain */ p_xff = memchr(xff_chain, ',', bstr_len(h_xff->value)); if (p_xff != NULL) { - xff_chain[bstr_len(h_xff->value) - strlen((char *)p_xff)]=0; + xff_chain[bstr_len(h_xff->value) - (p_xff - xff_chain)]=0; } p_xff = xff_chain; } From 489ee20560235f763374b61f8c5ce9461753a7d3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 24 Nov 2014 23:17:37 +0100 Subject: [PATCH 0113/2553] Thread Registration API for ID's Create thread registration and unregistration API for assigning unique thread id's. Threadvars is static even if a thread restarts, so we can do the registration before the threads start. A thread is unregistered when the ThreadVars are freed. --- src/tm-threads.c | 142 +++++++++++++++++++++++++++++++++++++++++++---- src/tm-threads.h | 5 ++ 2 files changed, 137 insertions(+), 10 deletions(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index 0c9d50a9eb4d..f9dd12c07fe5 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -257,12 +257,11 @@ void *TmThreadsSlotPktAcqLoop(void *td) if (r == TM_ECODE_DONE) { EngineDone(); TmThreadsSetFlag(tv, THV_CLOSED | THV_INIT_DONE | THV_RUNNING_DONE); - pthread_exit((void *) -1); + goto error; } else { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; + goto error; } } (void)SC_ATOMIC_SET(slot->slot_data, slot_data); @@ -312,8 +311,7 @@ void *TmThreadsSlotPktAcqLoop(void *td) r = slot->SlotThreadDeinit(tv, SC_ATOMIC_GET(slot->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; + goto error; } } } @@ -322,6 +320,10 @@ void *TmThreadsSlotPktAcqLoop(void *td) TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; + +error: + pthread_exit((void *) -1); + return NULL; } @@ -368,8 +370,7 @@ void *TmThreadsSlotVar(void *td) EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; + goto error; } (void)SC_ATOMIC_SET(s->slot_data, slot_data); } @@ -461,8 +462,7 @@ void *TmThreadsSlotVar(void *td) r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; + goto error; } } } @@ -471,6 +471,10 @@ void *TmThreadsSlotVar(void *td) TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; + +error: + pthread_exit((void *) -1); + return NULL; } static void *TmThreadsManagement(void *td) @@ -1156,8 +1160,11 @@ ThreadVars *TmThreadCreatePacketHandler(char *name, char *inq_name, tv = TmThreadCreate(name, inq_name, inqh_name, outq_name, outqh_name, slots, NULL, 0); - if (tv != NULL) + if (tv != NULL) { tv->type = TVT_PPT; + tv->id = TmThreadsRegisterThread(tv, tv->type); + } + return tv; } @@ -1183,6 +1190,7 @@ ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), if (tv != NULL) { tv->type = TVT_MGMT; + tv->id = TmThreadsRegisterThread(tv, tv->type); TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); } @@ -1210,6 +1218,7 @@ ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, if (tv != NULL) { tv->type = TVT_MGMT; + tv->id = TmThreadsRegisterThread(tv, tv->type); TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); TmModule *m = TmModuleGetByName(module); @@ -1242,6 +1251,7 @@ ThreadVars *TmThreadCreateCmdThread(char *name, void *(fn_p)(void *), if (tv != NULL) { tv->type = TVT_CMD; + tv->id = TmThreadsRegisterThread(tv, tv->type); TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); } @@ -1562,6 +1572,8 @@ void TmThreadFree(ThreadVars *tv) s = s->slot_next; SCFree(ps); } + + TmThreadsUnregisterThread(tv->id); SCFree(tv); } @@ -1761,6 +1773,8 @@ void TmThreadPauseThreads() ThreadVars *tv = NULL; int i = 0; + TmThreadsListThreads(); + for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { @@ -1920,3 +1934,111 @@ ThreadVars *TmThreadsGetCallingThread(void) return NULL; } + +typedef struct Thread_ { + ThreadVars *tv; /**< threadvars structure */ + const char *name; + int type; + int in_use; /**< bool to indicate this is in use */ +} Thread; + +typedef struct Threads_ { + Thread *threads; + size_t threads_size; + int threads_cnt; +} Threads; + +static Threads thread_store = { NULL, 0, 0 }; +static SCMutex thread_store_lock = PTHREAD_MUTEX_INITIALIZER; + +void TmThreadsListThreads(void) +{ + Thread *t; + size_t s; + + SCMutexLock(&thread_store_lock); + + for (s = 0; s < thread_store.threads_size; s++) { + t = &thread_store.threads[s]; + if (t == NULL || t->in_use == 0) + continue; + SCLogInfo("Thread %"PRIuMAX", %s type %d, tv %p", (uintmax_t)s, t->name, t->type, t->tv); + } + + SCMutexUnlock(&thread_store_lock); +} + +#define STEP 32 +/** + * \retval id thread id, or 0 if not found + */ +int TmThreadsRegisterThread(ThreadVars *tv, const int type) +{ + SCMutexLock(&thread_store_lock); + if (thread_store.threads == NULL) { + thread_store.threads = SCCalloc(STEP, sizeof(Thread)); + BUG_ON(thread_store.threads == NULL); + thread_store.threads_size = STEP; + } + + size_t s; + for (s = 0; s < thread_store.threads_size; s++) { + if (thread_store.threads[s].in_use == 0) { + Thread *t = &thread_store.threads[s]; + t->name = tv->name; + t->type = type; + t->tv = tv; + t->in_use = 1; + + SCMutexUnlock(&thread_store_lock); + return (int)s; + } + } + + /* if we get here the array is completely filled */ + void *newmem = SCRealloc(thread_store.threads, ((thread_store.threads_size + STEP) * sizeof(Thread))); + BUG_ON(newmem == NULL); + thread_store.threads = newmem; + memset((uint8_t *)thread_store.threads + (thread_store.threads_size * sizeof(Thread)), 0x00, STEP); + + Thread *t = &thread_store.threads[thread_store.threads_size]; + t->name = tv->name; + t->type = type; + t->tv = tv; + t->in_use = 1; + + s = thread_store.threads_size; + thread_store.threads_size += STEP; + + SCMutexUnlock(&thread_store_lock); + return (int)s; +} +#undef STEP + +void TmThreadsUnregisterThread(const int id) +{ + SCMutexLock(&thread_store_lock); + if (id < 0 || id >= (int)thread_store.threads_size) + return; + + /* reset thread_id, which serves as clearing the record */ + thread_store.threads[id].in_use = 0; + + /* check if we have at least one registered thread left */ + size_t s; + for (s = 0; s < thread_store.threads_size; s++) { + Thread *t = &thread_store.threads[s]; + if (t->in_use == 1) { + goto end; + } + } + + /* if we get here no threads are registered */ + SCFree(thread_store.threads); + thread_store.threads = NULL; + thread_store.threads_size = 0; + thread_store.threads_cnt = 0; + +end: + SCMutexUnlock(&thread_store_lock); +} diff --git a/src/tm-threads.h b/src/tm-threads.h index 37c773553317..0684d28b0260 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -195,4 +195,9 @@ static inline TmEcode TmThreadsSlotProcessPkt(ThreadVars *tv, TmSlot *s, Packet return r; } + +void TmThreadsListThreads(void); +int TmThreadsRegisterThread(ThreadVars *tv, const int type); +void TmThreadsUnregisterThread(const int id); + #endif /* __TM_THREADS_H__ */ From a260cba32b4a521cc6a6b2a42fc3f8f2004c233b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Nov 2014 15:05:06 +0100 Subject: [PATCH 0114/2553] Give easy access for thread stream packet queue Access it from ThreadVars. This allows for easy injection of packets into the stream engine. --- src/threadvars.h | 3 +++ src/tm-threads.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/threadvars.h b/src/threadvars.h index 0e04af2ca93c..f8277b7758c5 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -87,6 +87,9 @@ typedef struct ThreadVars_ { void *(*tm_func)(void *); struct TmSlot_ *tm_slots; + /** stream packet queue for flow time out injection */ + struct PacketQueue_ *stream_pq; + uint8_t thread_setup_flags; /** the type of thread as defined in tm-threads.h (TVT_PPT, TVT_MGMT) */ diff --git a/src/tm-threads.c b/src/tm-threads.c index f9dd12c07fe5..bb8ab9be9056 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -270,6 +270,16 @@ void *TmThreadsSlotPktAcqLoop(void *td) SCMutexInit(&slot->slot_pre_pq.mutex_q, NULL); memset(&slot->slot_post_pq, 0, sizeof(PacketQueue)); SCMutexInit(&slot->slot_post_pq.mutex_q, NULL); + + /* get the 'pre qeueue' from module before the stream module */ + if (slot->slot_next != NULL && slot->slot_next->tm_id == TMM_STREAMTCP) { + SCLogDebug("pre-stream packetqueue %p (postq)", &s->slot_post_pq); + tv->stream_pq = &slot->slot_post_pq; + /* if the stream module is the first, get the threads input queue */ + } else if (slot == (TmSlot *)tv->tm_slots && slot->tm_id == TMM_STREAMTCP) { + tv->stream_pq = &trans_q[tv->inq->id]; + SCLogDebug("pre-stream packetqueue %p (inq)", &slot->slot_pre_pq); + } } tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); @@ -314,14 +324,19 @@ void *TmThreadsSlotPktAcqLoop(void *td) goto error; } } + + BUG_ON(slot->slot_pre_pq.len); + BUG_ON(slot->slot_post_pq.len); } + tv->stream_pq = NULL; SCLogDebug("%s ending", tv->name); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; error: + tv->stream_pq = NULL; pthread_exit((void *) -1); return NULL; } @@ -378,6 +393,19 @@ void *TmThreadsSlotVar(void *td) SCMutexInit(&s->slot_pre_pq.mutex_q, NULL); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); SCMutexInit(&s->slot_post_pq.mutex_q, NULL); + + /* special case: we need to access the stream queue + * from the flow timeout code */ + + /* get the 'pre qeueue' from module before the stream module */ + if (s->slot_next != NULL && s->slot_next->tm_id == TMM_STREAMTCP) { + SCLogDebug("pre-stream packetqueue %p (preq)", &s->slot_pre_pq); + tv->stream_pq = &s->slot_pre_pq; + /* if the stream module is the first, get the threads input queue */ + } else if (s == (TmSlot *)tv->tm_slots && s->tm_id == TMM_STREAMTCP) { + tv->stream_pq = &trans_q[tv->inq->id]; + SCLogDebug("pre-stream packetqueue %p (inq)", &s->slot_pre_pq); + } } tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); @@ -465,14 +493,18 @@ void *TmThreadsSlotVar(void *td) goto error; } } + BUG_ON(s->slot_pre_pq.len); + BUG_ON(s->slot_post_pq.len); } SCLogDebug("%s ending", tv->name); + tv->stream_pq = NULL; TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; error: + tv->stream_pq = NULL; pthread_exit((void *) -1); return NULL; } From 51a782fd8c2dfdfda1047b9fe1083ef5c7395a09 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Nov 2014 11:07:03 +0100 Subject: [PATCH 0115/2553] Define FlowThreadId and add it to the flow 16 bits id should be enough for threads for a while. --- src/flow-util.h | 2 ++ src/flow.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/flow-util.h b/src/flow-util.h index 8271c3320798..8ed6fd88040f 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -55,6 +55,7 @@ (f)->data_al_so_far[0] = 0; \ (f)->data_al_so_far[1] = 0; \ (f)->de_ctx_id = 0; \ + (f)->thread_id = 0; \ (f)->alparser = NULL; \ (f)->alstate = NULL; \ (f)->de_state = NULL; \ @@ -97,6 +98,7 @@ (f)->data_al_so_far[0] = 0; \ (f)->data_al_so_far[1] = 0; \ (f)->de_ctx_id = 0; \ + (f)->thread_id = 0; \ if ((f)->de_state != NULL) { \ SCMutexLock(&(f)->de_state_m); \ DetectEngineStateReset((f)->de_state, (STREAM_TOSERVER | STREAM_TOCLIENT)); \ diff --git a/src/flow.h b/src/flow.h index 802f61fd2a85..12cda835aa9c 100644 --- a/src/flow.h +++ b/src/flow.h @@ -272,6 +272,9 @@ typedef unsigned int FlowRefCount; typedef unsigned short FlowRefCount; #endif +/** Local Thread ID */ +typedef uint16_t FlowThreadId; + /** * \brief Flow data structure. * @@ -357,6 +360,9 @@ typedef struct Flow_ * de_state and stored sgh ptrs are reset. */ uint32_t de_ctx_id; + /** Thread ID for the stream/detect portion of this flow */ + FlowThreadId thread_id; + /** application level storage ptrs. * */ From 7f80516563cfd9dc590bec42eee9e46760501542 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Nov 2014 15:52:38 +0100 Subject: [PATCH 0116/2553] Introduce Flow timeout injection api Add function TmThreadsInjectPacketById that is to be used to inject flow timeout packets into the threads stream_pq queue. TmThreadsInjectPacketById will also wake up listening threads if applicable. Packets are passed all packets together in an NULL terminated array to reduce locking overhead. --- src/flow-timeout.c | 23 ++++++++++++++--------- src/tm-threads.c | 30 ++++++++++++++++++++++++++++++ src/tm-threads.h | 1 + 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 4f62d89d3a4b..d62addd9ab3f 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -481,15 +481,20 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) } } - SCMutexLock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); - PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p1); - if (p2 != NULL) - PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p2); - if (p3 != NULL) - PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p3); - SCMutexUnlock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); - if (stream_pseudo_pkt_decode_TV->inq != NULL) { - SCCondSignal(&trans_q[stream_pseudo_pkt_decode_TV->inq->id].cond_q); + /* inject the packet(s) into the appropriate thread */ + int thread_id = (int)f->thread_id; + Packet *packets[4] = { p1, p2 ? p2 : p3, p2 ? p3 : NULL, NULL }; /**< null terminated array of packets */ + if (unlikely(!(TmThreadsInjectPacketsById(packets, thread_id)))) { + FlowDeReference(&p1->flow); + TmqhOutputPacketpool(NULL, p1); + if (p2) { + FlowDeReference(&p2->flow); + TmqhOutputPacketpool(NULL, p2); + } + if (p3) { + FlowDeReference(&p3->flow); + TmqhOutputPacketpool(NULL, p3); + } } /* done, in case of error (no packet) we still tag flow as complete diff --git a/src/tm-threads.c b/src/tm-threads.c index bb8ab9be9056..59754c0ae451 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -2074,3 +2074,33 @@ void TmThreadsUnregisterThread(const int id) end: SCMutexUnlock(&thread_store_lock); } + +/** + * \retval r 1 if packet was accepted, 0 otherwise + * \note if packet was not accepted, it's still the responsibility + * of the caller. + */ +int TmThreadsInjectPacketsById(Packet **packets, int id) +{ + if (id < 0 || id >= (int)thread_store.threads_size) + return 0; + + Thread *t = &thread_store.threads[id]; + ThreadVars *tv = t->tv; + + if (tv == NULL || tv->stream_pq == NULL) + return 0; + + SCMutexLock(&tv->stream_pq->mutex_q); + while (*packets != NULL) { + PacketEnqueue(tv->stream_pq, *packets); + packets++; + } + SCMutexUnlock(&tv->stream_pq->mutex_q); + + /* wake up listening thread(s) if necessary */ + if (tv->inq != NULL) { + SCCondSignal(&trans_q[tv->inq->id].cond_q); + } + return 1; +} diff --git a/src/tm-threads.h b/src/tm-threads.h index 0684d28b0260..4d864d6ebe75 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -199,5 +199,6 @@ static inline TmEcode TmThreadsSlotProcessPkt(ThreadVars *tv, TmSlot *s, Packet void TmThreadsListThreads(void); int TmThreadsRegisterThread(ThreadVars *tv, const int type); void TmThreadsUnregisterThread(const int id); +int TmThreadsInjectPacketsById(Packet **, int id); #endif /* __TM_THREADS_H__ */ From 8c51b23e9436312e5939286a8335332b9bdfd70b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 10 Dec 2014 11:49:30 +0100 Subject: [PATCH 0117/2553] Thread registration: id's start at 1 Start thread id's at 1, so that in flow's we can use 0 to indicate a thread id hasn't been set in it yet. --- src/tm-threads.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index 59754c0ae451..60b18c1daf9b 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1994,7 +1994,7 @@ void TmThreadsListThreads(void) t = &thread_store.threads[s]; if (t == NULL || t->in_use == 0) continue; - SCLogInfo("Thread %"PRIuMAX", %s type %d, tv %p", (uintmax_t)s, t->name, t->type, t->tv); + SCLogInfo("Thread %"PRIuMAX", %s type %d, tv %p", (uintmax_t)s+1, t->name, t->type, t->tv); } SCMutexUnlock(&thread_store_lock); @@ -2023,7 +2023,7 @@ int TmThreadsRegisterThread(ThreadVars *tv, const int type) t->in_use = 1; SCMutexUnlock(&thread_store_lock); - return (int)s; + return (int)(s+1); } } @@ -2043,18 +2043,21 @@ int TmThreadsRegisterThread(ThreadVars *tv, const int type) thread_store.threads_size += STEP; SCMutexUnlock(&thread_store_lock); - return (int)s; + return (int)(s+1); } #undef STEP void TmThreadsUnregisterThread(const int id) { SCMutexLock(&thread_store_lock); - if (id < 0 || id >= (int)thread_store.threads_size) + if (id <= 0 || id > (int)thread_store.threads_size) return; + /* id is one higher than index */ + int idx = id - 1; + /* reset thread_id, which serves as clearing the record */ - thread_store.threads[id].in_use = 0; + thread_store.threads[idx].in_use = 0; /* check if we have at least one registered thread left */ size_t s; @@ -2080,12 +2083,14 @@ void TmThreadsUnregisterThread(const int id) * \note if packet was not accepted, it's still the responsibility * of the caller. */ -int TmThreadsInjectPacketsById(Packet **packets, int id) +int TmThreadsInjectPacketsById(Packet **packets, const int id) { - if (id < 0 || id >= (int)thread_store.threads_size) + if (id <= 0 || id > (int)thread_store.threads_size) return 0; - Thread *t = &thread_store.threads[id]; + int idx = id - 1; + + Thread *t = &thread_store.threads[idx]; ThreadVars *tv = t->tv; if (tv == NULL || tv->stream_pq == NULL) From 48eccf7d916333400e2cbca778c39ba733abe118 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Nov 2014 11:50:03 +0100 Subject: [PATCH 0118/2553] Assign thread_id to flow on first packet stream engine --- src/stream-tcp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 5bb30f614a8c..9e3d8fb34cbc 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4382,6 +4382,15 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); + /* assign the thread id to the flow */ + if (unlikely(p->flow->thread_id == 0)) { + p->flow->thread_id = (FlowThreadId)tv->id; +#ifdef DEBUG + } else if (unlikely((FlowThreadId)tv->id != p->flow->thread_id)) { + SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id, tv->id); +#endif + } + TcpSession *ssn = (TcpSession *)p->flow->protoctx; /* track TCP flags */ From c6ec92d9b14d24bb85755150b9ff47a0b480bbaf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 1 Dec 2014 13:53:30 +0100 Subject: [PATCH 0119/2553] flow-timeout: use live threads Use live threads. Disable old timeout code. --- src/flow-timeout.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/flow-timeout.c b/src/flow-timeout.c index d62addd9ab3f..5ab7b2b0eb61 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -527,12 +527,12 @@ static inline void FlowForceReassemblyForHash(void) int server_ok; uint32_t idx = 0; - +#if 0 /* We use this packet just for reassembly purpose */ Packet *reassemble_p = PacketGetFromAlloc(); if (reassemble_p == NULL) return; - +#endif for (idx = 0; idx < flow_config.hash_size; idx++) { FlowBucket *fb = &flow_hash[idx]; @@ -543,8 +543,9 @@ static inline void FlowForceReassemblyForHash(void) /* we need to loop through all the flows in the queue */ while (f != NULL) { +#if 0 PACKET_RECYCLE(reassemble_p); - +#endif FLOWLOCK_WRLOCK(f); /* Get the tcp session for the flow */ @@ -557,8 +558,11 @@ static inline void FlowForceReassemblyForHash(void) continue; } - (void)FlowForceReassemblyNeedReassembly(f, &server_ok, &client_ok); + if (FlowForceReassemblyNeedReassembly(f, &server_ok, &client_ok) == 1) + FlowForceReassemblyForFlowV2(f, server_ok, client_ok); + FLOWLOCK_UNLOCK(f); +#if 0 /* ah ah! We have some unattended toserver segments */ if (client_ok == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); @@ -653,15 +657,16 @@ static inline void FlowForceReassemblyForHash(void) } } } - +#endif /* next flow in the queue */ f = f->hnext; } FBLOCK_UNLOCK(fb); } - +#if 0 PKT_SET_SRC(reassemble_p, PKT_SRC_FFR_SHUTDOWN); TmqhOutputPacketpool(NULL, reassemble_p); +#endif return; } From 8e86f387a62e8b67be3c15285a43115117e2025c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 1 Dec 2014 18:48:03 +0100 Subject: [PATCH 0120/2553] flow-time: use live threads at shutdown Update pktacq loop to process flow timeouts in a running engine. Add a new step to the shutdown phase of packet acquisition loop threads (pktacqloop). The shutdown code lets the pktacqloop break out of it's packet acquisition loop. The thread then enters a flow timeout loop, where it processes packets from it's tv->stream_pq queue until it's empty _and_ the KILL flag is set. Make sure receive threads are done before moving on to flow hash cleanup (recycle all). Without this the flow recycler could start it's unconditional hash clean up while detect threads are still running on the flows. Update unix socket to match live modes. --- src/flow-timeout.c | 10 +-- src/runmode-unix-socket.c | 14 ++-- src/suricata.c | 12 ++-- src/threadvars.h | 2 + src/tm-threads.c | 146 +++++++++++++++++++++++++++++++++++--- src/tm-threads.h | 3 +- 6 files changed, 161 insertions(+), 26 deletions(-) diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 5ab7b2b0eb61..4f146ab83f81 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -523,10 +523,10 @@ static inline void FlowForceReassemblyForHash(void) { Flow *f; TcpSession *ssn; - int client_ok; - int server_ok; - + int client_ok = 0; + int server_ok = 0; uint32_t idx = 0; + #if 0 /* We use this packet just for reassembly purpose */ Packet *reassemble_p = PacketGetFromAlloc(); @@ -676,7 +676,7 @@ static inline void FlowForceReassemblyForHash(void) void FlowForceReassembly(void) { /* Do remember. We need to have packet acquire disabled by now */ - +#if 0 /** ----- Part 1 ------*/ /* Flush out unattended packets */ FlowForceReassemblyFlushPendingPseudoPackets(); @@ -721,7 +721,7 @@ void FlowForceReassembly(void) } SCMutexUnlock(&tv_root_lock); - +#endif /** ----- Part 3 ----- **/ /* Carry out flow reassembly for unattended flows */ FlowForceReassemblyForHash(); diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 83daaaf0c99b..54c85fe739c7 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -290,21 +290,23 @@ TmEcode UnixSocketPcapFilesCheck(void *data) /* handle graceful shutdown of the flow engine, it's helper * threads and the packet threads */ FlowKillFlowManagerThread(); - TmThreadDisableThreadsWithTMS(TM_FLAG_RECEIVE_TM | TM_FLAG_DECODE_TM); + TmThreadDisableReceiveThreads(); FlowForceReassembly(); - TmThreadKillThreadsFamily(TVT_PPT); - TmThreadClearThreadsFamily(TVT_PPT); + TmThreadDisablePacketThreads(); FlowKillFlowRecyclerThread(); - /* kill remaining mgt threads */ + /* kill the stats threads */ TmThreadKillThreadsFamily(TVT_MGMT); TmThreadClearThreadsFamily(TVT_MGMT); - SCPerfReleaseResources(); - RunModeShutDown(); + /* kill packet threads -- already in 'disabled' state */ + TmThreadKillThreadsFamily(TVT_PPT); + TmThreadClearThreadsFamily(TVT_PPT); /* mgt and ppt threads killed, we can run non thread-safe * shutdown functions */ + SCPerfReleaseResources(); + RunModeShutDown(); FlowShutdown(); HostCleanup(); StreamTcpFreeConfig(STREAM_VERBOSE); diff --git a/src/suricata.c b/src/suricata.c index 31a2411fe7bd..25dab7e14923 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2392,20 +2392,19 @@ int main(int argc, char **argv) FlowKillFlowManagerThread(); } - /* Disable packet acquire thread first */ - TmThreadDisableThreadsWithTMS(TM_FLAG_RECEIVE_TM | TM_FLAG_DECODE_TM); + /* Disable packet acquisition first */ + TmThreadDisableReceiveThreads(); if (suri.run_mode != RUNMODE_UNIX_SOCKET) { FlowForceReassembly(); + /* kill receive threads when they have processed all + * flow timeout packets */ + TmThreadDisablePacketThreads(); } SCPrintElapsedTime(&suri); if (suri.rule_reload == 1) { - /* Disable detect threads first. This is required by live rule swap */ - TmThreadDisableThreadsWithTMS(TM_FLAG_RECEIVE_TM | TM_FLAG_DECODE_TM | - TM_FLAG_STREAM_TM | TM_FLAG_DETECT_TM); - /* wait if live rule swap is in progress */ if (UtilSignalIsHandler(SIGUSR2, SignalHandlerSigusr2Idle)) { SCLogInfo("Live rule swap in progress. Waiting for it to end " @@ -2430,6 +2429,7 @@ int main(int argc, char **argv) FlowKillFlowRecyclerThread(); } + /* kill remaining threads */ TmThreadKillThreads(); if (suri.run_mode != RUNMODE_UNIX_SOCKET) { diff --git a/src/threadvars.h b/src/threadvars.h index f8277b7758c5..64c215bcca80 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -45,6 +45,8 @@ struct TmSlot_; #define THV_DEINIT (1 << 7) #define THV_RUNNING_DONE (1 << 8) /** thread has completed running and is entering * the de-init phase */ +#define THV_KILL_PKTACQ (1 << 9) /**< flag thread to stop packet acq */ +#define THV_FLOW_LOOP (1 << 10) /**< thread is in flow shutdown loop */ /** Thread flags set and read by threads, to control the threads, when they * encounter certain conditions like failure */ diff --git a/src/tm-threads.c b/src/tm-threads.c index 60b18c1daf9b..64964c308f51 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -185,6 +185,56 @@ TmEcode TmThreadsSlotVarRun(ThreadVars *tv, Packet *p, return TM_ECODE_OK; } +/** \internal + * + * \brief Process flow timeout packets + * + * Process flow timeout pseudo packets. During shutdown this loop + * is run until the flow engine kills the thread and the queue is + * empty. + */ +static int TmThreadTimeoutLoop(ThreadVars *tv, TmSlot *s) +{ + TmSlot *stream_slot = NULL, *slot = NULL; + int run = 1; + int r = TM_ECODE_OK; + + for (slot = s; slot != NULL; slot = slot->slot_next) { + if (slot->tm_id == TMM_STREAMTCP) { + stream_slot = slot; + break; + } + } + + if (tv->stream_pq == NULL || stream_slot == NULL) + return r; + + SCLogDebug("flow end loop starting"); + while(run) { + Packet *p; + if (tv->stream_pq->len != 0) { + SCMutexLock(&tv->stream_pq->mutex_q); + p = PacketDequeue(tv->stream_pq); + SCMutexUnlock(&tv->stream_pq->mutex_q); + BUG_ON(p == NULL); + + if ((r = TmThreadsSlotProcessPkt(tv, stream_slot, p) != TM_ECODE_OK)) { + if (r == TM_ECODE_FAILED) + run = 0; + } + } else { + usleep(1); + } + + if (tv->stream_pq->len == 0 && TmThreadsCheckFlag(tv, THV_KILL)) { + run = 0; + } + } + SCLogDebug("flow end loop complete"); + + return r; +} + /* pcap/nfq @@ -297,7 +347,7 @@ void *TmThreadsSlotPktAcqLoop(void *td) r = s->PktAcqLoop(tv, SC_ATOMIC_GET(s->slot_data), s); - if (r == TM_ECODE_FAILED || TmThreadsCheckFlag(tv, THV_KILL) + if (r == TM_ECODE_FAILED || TmThreadsCheckFlag(tv, THV_KILL_PKTACQ) || suricata_ctl_flags) { run = 0; } @@ -307,6 +357,11 @@ void *TmThreadsSlotPktAcqLoop(void *td) } SCPerfSyncCounters(tv); + TmThreadsSetFlag(tv, THV_FLOW_LOOP); + + /* process all pseudo packets the flow timeout may throw at us */ + TmThreadTimeoutLoop(tv, s); + PacketPoolDestroy(); TmThreadsSetFlag(tv, THV_RUNNING_DONE); @@ -1442,9 +1497,13 @@ void TmThreadKillThread(ThreadVars *tv) } /** - * \brief Disable all threads having the specified TMs. + * \brief Disable all threads having the specified TMs. + * + * Breaks out of the packet acquisition loop, and bumps + * into the 'flow loop', where it will process packets + * from the flow engine's shutdown handling. */ -void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) +void TmThreadDisableReceiveThreads(void) { /* value in seconds */ #define THREAD_KILL_MAX_WAIT_TIME 60 @@ -1471,7 +1530,7 @@ void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) while (slots != NULL) { TmModule *tm = TmModuleGetById(slots->tm_id); - if (tm->flags & tm_flags) { + if (tm->flags & TM_FLAG_RECEIVE_TM) { disable = 1; break; } @@ -1494,9 +1553,8 @@ void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) } } - /* we found our receive TV. Send it a KILL signal. This is all - * we need to do to kill receive threads */ - TmThreadsSetFlag(tv, THV_KILL); + /* we found a receive TV. Send it a KILL_PKTACQ signal. */ + TmThreadsSetFlag(tv, THV_KILL_PKTACQ); if (tv->inq != NULL) { int i; @@ -1509,7 +1567,8 @@ void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) SCLogDebug("signalled tv->inq->id %" PRIu32 "", tv->inq->id); } - while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + /* wait for it to enter the 'flow loop' stage */ + while (!TmThreadsCheckFlag(tv, THV_FLOW_LOOP)) { usleep(WAIT_TIME); total_wait_time += WAIT_TIME / 1000000.0; if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { @@ -1529,6 +1588,77 @@ void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) return; } +/** + * \brief Disable all threads having the specified TMs. + */ +void TmThreadDisablePacketThreads(void) +{ + /* value in seconds */ +#define THREAD_KILL_MAX_WAIT_TIME 60 + /* value in microseconds */ +#define WAIT_TIME 100 + + double total_wait_time = 0; + + ThreadVars *tv = NULL; + + SCMutexLock(&tv_root_lock); + + /* all receive threads are part of packet processing threads */ + tv = tv_root[TVT_PPT]; + + /* we do have to keep in mind that TVs are arranged in the order + * right from receive to log. The moment we fail to find a + * receive TM amongst the slots in a tv, it indicates we are done + * with all receive threads */ + while (tv) { + if (tv->inq != NULL) { + /* we wait till we dry out all the inq packets, before we + * kill this thread. Do note that you should have disabled + * packet acquire by now using TmThreadDisableReceiveThreads()*/ + if (!(strlen(tv->inq->name) == strlen("packetpool") && + strcasecmp(tv->inq->name, "packetpool") == 0)) { + PacketQueue *q = &trans_q[tv->inq->id]; + while (q->len != 0) { + usleep(1000); + } + } + } + + /* we found our receive TV. Send it a KILL signal. This is all + * we need to do to kill receive threads */ + TmThreadsSetFlag(tv, THV_KILL); + + if (tv->inq != NULL) { + int i; + for (i = 0; i < (tv->inq->reader_cnt + tv->inq->writer_cnt); i++) { + if (tv->inq->q_type == 0) + SCCondSignal(&trans_q[tv->inq->id].cond_q); + else + SCCondSignal(&data_queues[tv->inq->id].cond_q); + } + SCLogDebug("signalled tv->inq->id %" PRIu32 "", tv->inq->id); + } + + while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + usleep(WAIT_TIME); + total_wait_time += WAIT_TIME / 1000000.0; + if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { + SCLogError(SC_ERR_FATAL, "Engine unable to " + "disable detect thread - \"%s\". " + "Killing engine", tv->name); + exit(EXIT_FAILURE); + } + } + + tv = tv->next; + } + + SCMutexUnlock(&tv_root_lock); + + return; +} + TmSlot *TmThreadGetFirstTmSlotForPartialPattern(const char *tm_name) { ThreadVars *tv = NULL; diff --git a/src/tm-threads.h b/src/tm-threads.h index 4d864d6ebe75..9ffc9efba810 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -130,7 +130,8 @@ void TmThreadWaitForFlag(ThreadVars *, uint16_t); TmEcode TmThreadsSlotVarRun (ThreadVars *tv, Packet *p, TmSlot *slot); ThreadVars *TmThreadsGetTVContainingSlot(TmSlot *); -void TmThreadDisableThreadsWithTMS(uint8_t tm_flags); +void TmThreadDisablePacketThreads(void); +void TmThreadDisableReceiveThreads(void); TmSlot *TmThreadGetFirstTmSlotForPartialPattern(const char *); /** From 0ffaad66eb770b6ea48c9e34661b71ac1d64c325 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 1 Dec 2014 19:18:45 +0100 Subject: [PATCH 0121/2553] flow-time: disable remainder of the old timeout code Disable registration code that was looking for threadvars and slots as timeout handling is now done in a live engine. --- src/flow-timeout.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 4f146ab83f81..c14493fcc073 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -61,7 +61,7 @@ #include "app-layer.h" #include "util-profiling.h" - +#if 0 static TmSlot *stream_pseudo_pkt_stream_tm_slot = NULL; static ThreadVars *stream_pseudo_pkt_stream_TV = NULL; @@ -71,13 +71,14 @@ static ThreadVars *stream_pseudo_pkt_detect_prev_TV = NULL; static TmSlot *stream_pseudo_pkt_decode_tm_slot = NULL; static ThreadVars *stream_pseudo_pkt_decode_TV = NULL; - +#endif /** * \internal * \brief Flush out if we have any unattended packets. */ static inline void FlowForceReassemblyFlushPendingPseudoPackets(void) { +#if 0 /* we don't lock the queue, since flow manager is dead */ if (stream_pseudo_pkt_decode_tm_slot->slot_post_pq.len == 0) return; @@ -91,7 +92,7 @@ static inline void FlowForceReassemblyFlushPendingPseudoPackets(void) SCLogError(SC_ERR_TM_THREADS_ERROR, "Received error from FFR on " "flushing packets through decode->.. TMs"); } - +#endif return; } @@ -734,6 +735,7 @@ void FlowForceReassembly(void) */ void FlowForceReassemblySetup(int detect_disabled) { +#if 0 /* get StreamTCP TM's slot and TV containing this slot */ stream_pseudo_pkt_stream_tm_slot = TmSlotGetSlotForTM(TMM_STREAMTCP); if (stream_pseudo_pkt_stream_tm_slot == NULL) { @@ -812,4 +814,5 @@ void FlowForceReassemblySetup(int detect_disabled) } return; +#endif } From de4bda14e6f2b90fd1aa533327ae907205e25dd1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 2 Dec 2014 10:02:27 +0100 Subject: [PATCH 0122/2553] stream: handle flow timeout stream end packets Handle flow timeout packets in the stream engine. Previously the flow timeout code would call reassembly code directly. --- src/stream-tcp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 9e3d8fb34cbc..2d075797f8e2 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4440,6 +4440,23 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, if (ssn != NULL) SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto); } else { + /* special case for PKT_PSEUDO_STREAM_END packets: + * bypass the state handling and various packet checks, + * we care about reassembly here. */ + if (p->flags & PKT_PSEUDO_STREAM_END) { + if (PKT_IS_TOCLIENT(p)) { + ssn->client.last_ack = TCP_GET_ACK(p); + StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, + &ssn->server, p, pq); + } else { + ssn->server.last_ack = TCP_GET_ACK(p); + StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, + &ssn->client, p, pq); + } + /* straight to 'skip' as we already handled reassembly */ + goto skip; + } + /* check if the packet is in right direction, when we missed the SYN packet and picked up midstream session. */ if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK) From 6e69b51123aeb0696fc781215bc6571c6c159163 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 2 Dec 2014 17:40:31 +0100 Subject: [PATCH 0123/2553] flow timeout: cleanup Remove now unused old flow timeout code. --- src/flow-manager.c | 1 - src/flow-timeout.c | 277 +-------------------------------------------- 2 files changed, 1 insertion(+), 277 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index a42e6590b4f3..7fa2bb280a29 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -714,7 +714,6 @@ void FlowManagerThreadSpawn() flowmgr_number = (uint32_t)setting; SCLogInfo("using %u flow manager threads", flowmgr_number); - FlowForceReassemblySetup(g_detect_disabled); SCCtrlCondInit(&flow_manager_ctrl_cond, NULL); SCCtrlMutexInit(&flow_manager_ctrl_mutex, NULL); diff --git a/src/flow-timeout.c b/src/flow-timeout.c index c14493fcc073..a9d1f1460529 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -61,40 +61,6 @@ #include "app-layer.h" #include "util-profiling.h" -#if 0 -static TmSlot *stream_pseudo_pkt_stream_tm_slot = NULL; -static ThreadVars *stream_pseudo_pkt_stream_TV = NULL; - -static TmSlot *stream_pseudo_pkt_detect_tm_slot = NULL; -static ThreadVars *stream_pseudo_pkt_detect_TV = NULL; -static ThreadVars *stream_pseudo_pkt_detect_prev_TV = NULL; - -static TmSlot *stream_pseudo_pkt_decode_tm_slot = NULL; -static ThreadVars *stream_pseudo_pkt_decode_TV = NULL; -#endif -/** - * \internal - * \brief Flush out if we have any unattended packets. - */ -static inline void FlowForceReassemblyFlushPendingPseudoPackets(void) -{ -#if 0 - /* we don't lock the queue, since flow manager is dead */ - if (stream_pseudo_pkt_decode_tm_slot->slot_post_pq.len == 0) - return; - - SCMutexLock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); - Packet *p = PacketDequeue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq); - SCMutexUnlock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); - if (TmThreadsSlotProcessPkt(stream_pseudo_pkt_decode_TV, - stream_pseudo_pkt_decode_tm_slot, - p) != TM_ECODE_OK) { - SCLogError(SC_ERR_TM_THREADS_ERROR, "Received error from FFR on " - "flushing packets through decode->.. TMs"); - } -#endif - return; -} /** * \internal @@ -528,12 +494,6 @@ static inline void FlowForceReassemblyForHash(void) int server_ok = 0; uint32_t idx = 0; -#if 0 - /* We use this packet just for reassembly purpose */ - Packet *reassemble_p = PacketGetFromAlloc(); - if (reassemble_p == NULL) - return; -#endif for (idx = 0; idx < flow_config.hash_size; idx++) { FlowBucket *fb = &flow_hash[idx]; @@ -544,9 +504,6 @@ static inline void FlowForceReassemblyForHash(void) /* we need to loop through all the flows in the queue */ while (f != NULL) { -#if 0 - PACKET_RECYCLE(reassemble_p); -#endif FLOWLOCK_WRLOCK(f); /* Get the tcp session for the flow */ @@ -559,115 +516,17 @@ static inline void FlowForceReassemblyForHash(void) continue; } - if (FlowForceReassemblyNeedReassembly(f, &server_ok, &client_ok) == 1) + if (FlowForceReassemblyNeedReassembly(f, &server_ok, &client_ok) == 1) { FlowForceReassemblyForFlowV2(f, server_ok, client_ok); - - FLOWLOCK_UNLOCK(f); -#if 0 - /* ah ah! We have some unattended toserver segments */ - if (client_ok == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { - StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); - - ssn->client.last_ack = (ssn->client.seg_list_tail->seq + - ssn->client.seg_list_tail->payload_len); - - FlowForceReassemblyPseudoPacketSetup(reassemble_p, 1, f, ssn, 1); - StreamTcpReassembleHandleSegment(stream_pseudo_pkt_stream_TV, - stt->ra_ctx, ssn, &ssn->server, - reassemble_p, NULL); - FlowDeReference(&reassemble_p->flow); - } - /* oh oh! We have some unattended toclient segments */ - if (server_ok == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { - StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); - - ssn->server.last_ack = (ssn->server.seg_list_tail->seq + - ssn->server.seg_list_tail->payload_len); - - FlowForceReassemblyPseudoPacketSetup(reassemble_p, 0, f, ssn, 1); - StreamTcpReassembleHandleSegment(stream_pseudo_pkt_stream_TV, - stt->ra_ctx, ssn, &ssn->client, - reassemble_p, NULL); - FlowDeReference(&reassemble_p->flow); } FLOWLOCK_UNLOCK(f); - /* insert a pseudo packet in the toserver direction */ - if (client_ok) { - FLOWLOCK_WRLOCK(f); - Packet *p = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); - FLOWLOCK_UNLOCK(f); - - if (p == NULL) { - TmqhOutputPacketpool(NULL, reassemble_p); - FBLOCK_UNLOCK(fb); - return; - } - PKT_SET_SRC(p, PKT_SRC_FFR_SHUTDOWN); - - if (stream_pseudo_pkt_detect_prev_TV != NULL) { - stream_pseudo_pkt_detect_prev_TV-> - tmqh_out(stream_pseudo_pkt_detect_prev_TV, p); - } else { - TmSlot *s = stream_pseudo_pkt_detect_tm_slot; - while (s != NULL) { - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - SlotFunc(NULL, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, - &s->slot_post_pq); - s = s->slot_next; - } - - if (stream_pseudo_pkt_detect_TV != NULL) { - stream_pseudo_pkt_detect_TV-> - tmqh_out(stream_pseudo_pkt_detect_TV, p); - } else { - TmqhOutputPacketpool(NULL, p); - } - } - } - if (server_ok) { - FLOWLOCK_WRLOCK(f); - Packet *p = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); - FLOWLOCK_UNLOCK(f); - - if (p == NULL) { - TmqhOutputPacketpool(NULL, reassemble_p); - FBLOCK_UNLOCK(fb); - return; - } - PKT_SET_SRC(p, PKT_SRC_FFR_SHUTDOWN); - - if (stream_pseudo_pkt_detect_prev_TV != NULL) { - stream_pseudo_pkt_detect_prev_TV-> - tmqh_out(stream_pseudo_pkt_detect_prev_TV, p); - } else { - TmSlot *s = stream_pseudo_pkt_detect_tm_slot; - while (s != NULL) { - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - SlotFunc(NULL, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, - &s->slot_post_pq); - s = s->slot_next; - } - - if (stream_pseudo_pkt_detect_TV != NULL) { - stream_pseudo_pkt_detect_TV-> - tmqh_out(stream_pseudo_pkt_detect_TV, p); - } else { - TmqhOutputPacketpool(NULL, p); - } - } - } -#endif /* next flow in the queue */ f = f->hnext; } FBLOCK_UNLOCK(fb); } -#if 0 - PKT_SET_SRC(reassemble_p, PKT_SRC_FFR_SHUTDOWN); - TmqhOutputPacketpool(NULL, reassemble_p); -#endif return; } @@ -676,143 +535,9 @@ static inline void FlowForceReassemblyForHash(void) */ void FlowForceReassembly(void) { - /* Do remember. We need to have packet acquire disabled by now */ -#if 0 - /** ----- Part 1 ------*/ - /* Flush out unattended packets */ - FlowForceReassemblyFlushPendingPseudoPackets(); - - /** ----- Part 2 ----- **/ - /* Check if all threads are idle. We need this so that we have all - * packets freeds. As a consequence, no flows are in use */ - - SCMutexLock(&tv_root_lock); - - /* all receive threads are part of packet processing threads */ - ThreadVars *tv = tv_root[TVT_PPT]; - - /* we are doing this in order receive -> decode -> ... -> log */ - while (tv != NULL) { - if (tv->inq != NULL) { - /* we wait till we dry out all the inq packets, before we - * kill this thread. Do note that you should have disabled - * packet acquire by now using TmThreadDisableReceiveThreads()*/ - if (!(strlen(tv->inq->name) == strlen("packetpool") && - strcasecmp(tv->inq->name, "packetpool") == 0)) { - PacketQueue *q = &trans_q[tv->inq->id]; - while (q->len != 0) { - usleep(100); - } - TmThreadsSetFlag(tv, THV_PAUSE); - if (tv->inq->q_type == 0) - SCCondSignal(&trans_q[tv->inq->id].cond_q); - else - SCCondSignal(&data_queues[tv->inq->id].cond_q); - while (!TmThreadsCheckFlag(tv, THV_PAUSED)) { - if (tv->inq->q_type == 0) - SCCondSignal(&trans_q[tv->inq->id].cond_q); - else - SCCondSignal(&data_queues[tv->inq->id].cond_q); - usleep(100); - } - TmThreadsUnsetFlag(tv, THV_PAUSE); - } - } - tv = tv->next; - } - - SCMutexUnlock(&tv_root_lock); -#endif - /** ----- Part 3 ----- **/ /* Carry out flow reassembly for unattended flows */ FlowForceReassemblyForHash(); return; } -/** - * \param detect_disabled bool, indicating if we use a detection engine (true) - */ -void FlowForceReassemblySetup(int detect_disabled) -{ -#if 0 - /* get StreamTCP TM's slot and TV containing this slot */ - stream_pseudo_pkt_stream_tm_slot = TmSlotGetSlotForTM(TMM_STREAMTCP); - if (stream_pseudo_pkt_stream_tm_slot == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve the slot for STREAMTCP TM"); - exit(EXIT_FAILURE); - } - stream_pseudo_pkt_stream_TV = - TmThreadsGetTVContainingSlot(stream_pseudo_pkt_stream_tm_slot); - if (stream_pseudo_pkt_stream_TV == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve the TV containing STREAMTCP TM slot"); - exit(EXIT_FAILURE); - } - - if (!detect_disabled) { - /* get detect TM's slot and TV containing this slot */ - stream_pseudo_pkt_detect_tm_slot = TmSlotGetSlotForTM(TMM_DETECT); - if (stream_pseudo_pkt_detect_tm_slot == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve a slot for DETECT TM"); - exit(EXIT_FAILURE); - } - stream_pseudo_pkt_detect_TV = - TmThreadsGetTVContainingSlot(stream_pseudo_pkt_detect_tm_slot); - if (stream_pseudo_pkt_detect_TV == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve the TV containing the Detect TM slot"); - exit(EXIT_FAILURE); - } - if (stream_pseudo_pkt_detect_TV->tm_slots == stream_pseudo_pkt_detect_tm_slot) { - stream_pseudo_pkt_detect_prev_TV = stream_pseudo_pkt_detect_TV->prev; - } - if (strcasecmp(stream_pseudo_pkt_detect_TV->outqh_name, "packetpool") == 0) { - stream_pseudo_pkt_detect_TV = NULL; - } - } - - SCMutexLock(&tv_root_lock); - ThreadVars *tv = tv_root[TVT_PPT]; - int done = 0; - while (tv) { - TmSlot *slots = tv->tm_slots; - while (slots) { - TmModule *tm = TmModuleGetById(slots->tm_id); - if (tm->flags & TM_FLAG_DECODE_TM) { - done = 1; - stream_pseudo_pkt_decode_tm_slot = slots; - break; - } - slots = slots->slot_next; - } - if (done) - break; - tv = tv->next; - } - SCMutexUnlock(&tv_root_lock); - - if (stream_pseudo_pkt_decode_tm_slot == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve the slot for DECODE TM"); - exit(EXIT_FAILURE); - } - stream_pseudo_pkt_decode_TV = - TmThreadsGetTVContainingSlot(stream_pseudo_pkt_decode_tm_slot); - if (stream_pseudo_pkt_decode_TV == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve the TV containing the Decode TM slot"); - exit(EXIT_FAILURE); - } - - return; -#endif -} From 3499d682c475d7164324d42670bcc3fe6ac21ae7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 10 Dec 2014 16:41:03 +0100 Subject: [PATCH 0124/2553] flow timeout: cleanups Rename FlowForceReassemblyForFlowV2 to just FlowForceReassemblyForFlow as there is no V1. --- src/decode.c | 5 +---- src/decode.h | 3 +-- src/flow-manager.c | 2 +- src/flow-timeout.c | 26 +++++++++++++------------- src/flow-timeout.h | 2 +- src/source-pcap-file.c | 2 +- 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/decode.c b/src/decode.c index 8ad78bcf3212..87aa831b2448 100644 --- a/src/decode.c +++ b/src/decode.c @@ -539,12 +539,9 @@ const char *PktSrcToString(enum PktSrcEnum pkt_src) case PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO: pkt_src_str = "stream"; break; - case PKT_SRC_FFR_V2: + case PKT_SRC_FFR: pkt_src_str = "stream (flow timeout)"; break; - case PKT_SRC_FFR_SHUTDOWN: - pkt_src_str = "stream (engine shutdown)"; - break; } return pkt_src_str; } diff --git a/src/decode.h b/src/decode.h index 98839be6bcdb..bd9aeef61b99 100644 --- a/src/decode.h +++ b/src/decode.h @@ -52,8 +52,7 @@ enum PktSrcEnum { PKT_SRC_DECODER_TEREDO, PKT_SRC_DEFRAG, PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO, - PKT_SRC_FFR_V2, - PKT_SRC_FFR_SHUTDOWN, + PKT_SRC_FFR, }; #include "source-nflog.h" diff --git a/src/flow-manager.c b/src/flow-manager.c index 7fa2bb280a29..e8446f5398d0 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -244,7 +244,7 @@ static int FlowManagerFlowTimedOut(Flow *f, struct timeval *ts) int server = 0, client = 0; if (!(f->flags & FLOW_TIMEOUT_REASSEMBLY_DONE) && FlowForceReassemblyNeedReassembly(f, &server, &client) == 1) { - FlowForceReassemblyForFlowV2(f, server, client); + FlowForceReassemblyForFlow(f, server, client); return 0; } #ifdef DEBUG diff --git a/src/flow-timeout.c b/src/flow-timeout.c index a9d1f1460529..36391783f0c7 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -328,7 +328,7 @@ int FlowForceReassemblyNeedReassembly(Flow *f, int *server, int *client) * * \retval 0 This flow doesn't need any reassembly processing; 1 otherwise. */ -int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) +int FlowForceReassemblyForFlow(Flow *f, int server, int client) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; TcpSession *ssn; @@ -358,7 +358,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) if (p1 == NULL) { goto done; } - PKT_SET_SRC(p1, PKT_SRC_FFR_V2); + PKT_SET_SRC(p1, PKT_SRC_FFR); if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); @@ -367,7 +367,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p1); goto done; } - PKT_SET_SRC(p2, PKT_SRC_FFR_V2); + PKT_SET_SRC(p2, PKT_SRC_FFR); p3 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p3 == NULL) { @@ -377,7 +377,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p2); goto done; } - PKT_SET_SRC(p3, PKT_SRC_FFR_V2); + PKT_SET_SRC(p3, PKT_SRC_FFR); } else { p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); if (p2 == NULL) { @@ -385,7 +385,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p1); goto done; } - PKT_SET_SRC(p2, PKT_SRC_FFR_V2); + PKT_SET_SRC(p2, PKT_SRC_FFR); } } else if (client == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) { @@ -394,7 +394,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) if (p1 == NULL) { goto done; } - PKT_SET_SRC(p1, PKT_SRC_FFR_V2); + PKT_SET_SRC(p1, PKT_SRC_FFR); p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { @@ -402,13 +402,13 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p1); goto done; } - PKT_SET_SRC(p2, PKT_SRC_FFR_V2); + PKT_SET_SRC(p2, PKT_SRC_FFR); } else { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); if (p1 == NULL) { goto done; } - PKT_SET_SRC(p1, PKT_SRC_FFR_V2); + PKT_SET_SRC(p1, PKT_SRC_FFR); if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) { p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); @@ -417,7 +417,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p1); goto done; } - PKT_SET_SRC(p2, PKT_SRC_FFR_V2); + PKT_SET_SRC(p2, PKT_SRC_FFR); } } @@ -427,7 +427,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) if (p1 == NULL) { goto done; } - PKT_SET_SRC(p1, PKT_SRC_FFR_V2); + PKT_SET_SRC(p1, PKT_SRC_FFR); p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { @@ -435,13 +435,13 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p1); goto done; } - PKT_SET_SRC(p2, PKT_SRC_FFR_V2); + PKT_SET_SRC(p2, PKT_SRC_FFR); } else if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) { p1 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p1 == NULL) { goto done; } - PKT_SET_SRC(p1, PKT_SRC_FFR_V2); + PKT_SET_SRC(p1, PKT_SRC_FFR); } else { /* impossible */ BUG_ON(1); @@ -517,7 +517,7 @@ static inline void FlowForceReassemblyForHash(void) } if (FlowForceReassemblyNeedReassembly(f, &server_ok, &client_ok) == 1) { - FlowForceReassemblyForFlowV2(f, server_ok, client_ok); + FlowForceReassemblyForFlow(f, server_ok, client_ok); } FLOWLOCK_UNLOCK(f); diff --git a/src/flow-timeout.h b/src/flow-timeout.h index 036bd50ce7af..50e007ae066d 100644 --- a/src/flow-timeout.h +++ b/src/flow-timeout.h @@ -24,7 +24,7 @@ #ifndef __FLOW_TIMEOUT_H__ #define __FLOW_TIMEOUT_H__ -int FlowForceReassemblyForFlowV2(Flow *f, int server, int client); +int FlowForceReassemblyForFlow(Flow *f, int server, int client); int FlowForceReassemblyNeedReassembly(Flow *f, int *server, int *client); void FlowForceReassembly(void); void FlowForceReassemblySetup(int detect_disabled); diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 3202b0d8d4c7..8638bdd8d22a 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -419,7 +419,7 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P pcap_g.Decoder(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); #ifdef DEBUG - BUG_ON(p->pkt_src != PKT_SRC_WIRE && p->pkt_src != PKT_SRC_FFR_V2); + BUG_ON(p->pkt_src != PKT_SRC_WIRE && p->pkt_src != PKT_SRC_FFR); #endif PacketDecodeFinalize(tv, dtv, p); From cef609bb73c19e53ebd45247ffaa7db91a24b0d7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Dec 2014 15:50:29 +0100 Subject: [PATCH 0125/2553] threading: lock TmThreadKillThreadsFamily --- src/tm-threads.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tm-threads.c b/src/tm-threads.c index 64964c308f51..0246ec681b02 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1697,6 +1697,7 @@ void TmThreadKillThreadsFamily(int family) if ((family < 0) || (family >= TVT_MAX)) return; + SCMutexLock(&tv_root_lock); tv = tv_root[family]; while (tv) { @@ -1704,6 +1705,7 @@ void TmThreadKillThreadsFamily(int family) tv = tv->next; } + SCMutexUnlock(&tv_root_lock); } void TmThreadKillThreads(void) From c4e13246901c62851affd299e8f8e55395978304 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Dec 2014 17:15:38 +0100 Subject: [PATCH 0126/2553] flow-timeout: use packet pool Use packet pool for pseudo packets on flow timeout. Wait for a packet if necessary. For shutdown, alloc a new pool as the 'main()' thread calls this. --- src/flow-timeout.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 36391783f0c7..a3de51da6444 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -238,11 +238,13 @@ static inline Packet *FlowForceReassemblyPseudoPacketGet(int direction, TcpSession *ssn, int dummy) { - Packet *p; - - p = PacketGetFromAlloc(); - if (p == NULL) + PacketPoolWait(); + Packet *p = PacketPoolGetPacket(); + if (p == NULL) { return NULL; + } + + PACKET_PROFILING_START(p); return FlowForceReassemblyPseudoPacketSetup(p, direction, f, ssn, dummy); } @@ -535,9 +537,11 @@ static inline void FlowForceReassemblyForHash(void) */ void FlowForceReassembly(void) { + /* called by 'main()' which has no packet pool */ + PacketPoolInit(); /* Carry out flow reassembly for unattended flows */ FlowForceReassemblyForHash(); - + PacketPoolDestroy(); return; } From ffd224845945cd9a860f16cbbdc12a960c193eca Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 22 Dec 2014 13:10:53 +0100 Subject: [PATCH 0127/2553] flow manager: destroy packet pool on close --- src/flow-manager.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flow-manager.c b/src/flow-manager.c index e8446f5398d0..5aa975f7c488 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -541,6 +541,7 @@ static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) static TmEcode FlowManagerThreadDeinit(ThreadVars *t, void *data) { + PacketPoolDestroy(); SCFree(data); return TM_ECODE_OK; } From 8b2dd81628d504b06ede097807a31c27ccd715ac Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 22 Dec 2014 13:15:08 +0100 Subject: [PATCH 0128/2553] stats: stats threads don't need packet pools --- src/counters.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/counters.c b/src/counters.c index 6f2333ce97f0..01e80b4e17bd 100644 --- a/src/counters.c +++ b/src/counters.c @@ -276,7 +276,6 @@ static void *SCPerfMgmtThread(void *arg) tv_local->cap_flags = 0; SCDropCaps(tv_local); - PacketPoolInit(); if (sc_perf_op_ctx == NULL) { SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" @@ -356,7 +355,6 @@ static void *SCPerfWakeupThread(void *arg) tv_local->cap_flags = 0; SCDropCaps(tv_local); - PacketPoolInit(); if (sc_perf_op_ctx == NULL) { SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" From 60b50e1ca5116d6af5d9e233f3d8b6f8baba1c39 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 22 Dec 2014 17:00:56 +0100 Subject: [PATCH 0129/2553] packet-pool: free pending packets --- src/tmqh-packetpool.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index 38ca297c7054..b19845ff081e 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -294,6 +294,21 @@ void PacketPoolInit(void) void PacketPoolDestroy(void) { Packet *p = NULL; + PktPool *my_pool = GetThreadPacketPool(); + if (my_pool && my_pool->pending_head != NULL) { + p = my_pool->pending_head; + while (p) { + Packet *next_p = p->next; + PacketFree(p); + p = next_p; + my_pool->pending_count--; + } + BUG_ON(my_pool->pending_count); + my_pool->pending_pool = NULL; + my_pool->pending_head = NULL; + my_pool->pending_tail = NULL; + } + while ((p = PacketPoolGetPacket()) != NULL) { PacketFree(p); } From a095694945a72a53c32f35409ec9c2c1643e69f3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Dec 2014 10:16:49 +0100 Subject: [PATCH 0130/2553] host: register unittests Host unittests were not registered so they wouldn't run. --- src/host.h | 2 ++ src/runmode-unittests.c | 1 + 2 files changed, 3 insertions(+) diff --git a/src/host.h b/src/host.h index 2616b4b35b00..56a16dc47281 100644 --- a/src/host.h +++ b/src/host.h @@ -146,5 +146,7 @@ void HostMoveToSpare(Host *); uint32_t HostSpareQueueGetSize(void); void HostPrintStats (void); +void HostRegisterUnittests(void); + #endif /* __HOST_H__ */ diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index d77f78b6892e..10f540ae0316 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -213,6 +213,7 @@ void RunUnittests(int list_unittests, char *regex_arg) ConfYamlRegisterTests(); TmqhFlowRegisterTests(); FlowRegisterTests(); + HostRegisterUnittests(); SCSigRegisterSignatureOrderingTests(); SCRadixRegisterTests(); DefragRegisterTests(); From b69ca16553bd7002b2ac8df8608d1117b322560b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 12:55:19 +0100 Subject: [PATCH 0131/2553] stream: move utility functions This way they can be used by the *Inline* functions as well. --- src/stream-tcp-reassemble.c | 106 ++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 5333c3e6caee..c2d9fd601959 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2032,6 +2032,59 @@ static int StreamTcpReassembleRawCheckLimit(TcpSession *ssn, TcpStream *stream, SCReturnInt(1); } +/** + * \brief see if app layer is done with a segment + * + * \retval 1 app layer is done with this segment + * \retval 0 not done yet + */ +#define StreamTcpAppLayerSegmentProcessed(stream, segment) \ + (( ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \ + ( (segment)->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED ) ? 1 :0 )) + +/** \internal + * \brief check if we can remove a segment from our segment list + * + * If a segment is entirely before the oldest smsg, we can discard it. Otherwise + * we keep it around to be able to log it. + * + * \retval 1 yes + * \retval 0 no + */ +static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg) +{ + if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) { + /* not (seg is entirely before first smsg, skip) */ + if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toserver_smsg_head->seq))) { + SCReturnInt(0); + } + } else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) { + /* not (seg is entirely before first smsg, skip) */ + if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toclient_smsg_head->seq))) { + SCReturnInt(0); + } + } + + /* if proto detect isn't done, we're not returning */ + if (!(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream))) { + SCReturnInt(0); + } + + /* check app layer conditions */ + if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) { + if (!(StreamTcpAppLayerSegmentProcessed(stream, seg))) { + SCReturnInt(0); + } + } + + /* check raw reassembly conditions */ + if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) { + SCReturnInt(0); + } + + SCReturnInt(1); +} + static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg) { if (seg->prev == NULL) { @@ -2048,16 +2101,6 @@ static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg) stream->seg_list_tail = seg->prev; } -/** - * \brief see if app layer is done with a segment - * - * \retval 1 app layer is done with this segment - * \retval 0 not done yet - */ -#define StreamTcpAppLayerSegmentProcessed(stream, segment) \ - (( ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \ - ( (segment)->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED ) ? 1 :0 )) - /** * \brief Update the stream reassembly upon receiving a data segment * @@ -2719,49 +2762,6 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, SCReturnInt(0); } -/** \internal - * \brief check if we can remove a segment from our segment list - * - * If a segment is entirely before the oldest smsg, we can discard it. Otherwise - * we keep it around to be able to log it. - * - * \retval 1 yes - * \retval 0 no - */ -static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg) -{ - if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) { - /* not (seg is entirely before first smsg, skip) */ - if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toserver_smsg_head->seq))) { - SCReturnInt(0); - } - } else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) { - /* not (seg is entirely before first smsg, skip) */ - if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toclient_smsg_head->seq))) { - SCReturnInt(0); - } - } - - /* if proto detect isn't done, we're not returning */ - if (!(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream))) { - SCReturnInt(0); - } - - /* check app layer conditions */ - if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) { - if (!(StreamTcpAppLayerSegmentProcessed(stream, seg))) { - SCReturnInt(0); - } - } - - /* check raw reassembly conditions */ - if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) { - SCReturnInt(0); - } - - SCReturnInt(1); -} - /** \brief Remove idle TcpSegments from TcpSession * * \param f flow From dc5e2a515cb4b79df6ff01148ab809be3d5abfd2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 13:37:54 +0100 Subject: [PATCH 0132/2553] stream: improve inline mode GAP handling Don't conclude a GAP is 'final' until the missing data is ack'd. Further, cleanup and unify more with the non-inline code. --- src/stream-tcp-reassemble.c | 143 +++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 68 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index c2d9fd601959..2905726cc586 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2170,53 +2170,69 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, uint16_t payload_len = 0; uint32_t next_seq = ra_base_seq + 1; uint32_t data_sent = 0; + TcpSegment *seg = stream->seg_list; SCLogDebug("ra_base_seq %u", ra_base_seq); + /* Check if we have a gap at the start of the list. If last_ack is + * bigger than the list start and the list start is bigger than + * next_seq, we know we are missing data that has been ack'd. That + * won't get retransmitted, so it's a data gap. + */ + if (!(p->flow->flags & FLOW_NO_APPLAYER_INSPECTION)) { + if (SEQ_GT(seg->seq, next_seq) && SEQ_LT(seg->seq, stream->last_ack)) { + /* send gap signal */ + STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + NULL, 0, flags|STREAM_GAP); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + + /* set a GAP flag and make sure not bothering this stream anymore */ + SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); + stream->flags |= STREAMTCP_STREAM_FLAG_GAP; + + StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); + SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); +#ifdef DEBUG + dbg_app_layer_gap++; +#endif + SCReturnInt(0); + } + } + /* loop through the segments and fill one or more msgs */ - TcpSegment *seg = stream->seg_list; SCLogDebug("pre-loop seg %p", seg); for (; seg != NULL;) { - SCLogDebug("seg %p", seg); + SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32, + seg, seg->seq, seg->payload_len, + (uint32_t)(seg->seq + seg->payload_len)); if (p->flow->flags & FLOW_NO_APPLAYER_INSPECTION) { - if (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) { - SCLogDebug("removing seg %p seq %"PRIu32 - " len %"PRIu16"", seg, seg->seq, seg->payload_len); - - TcpSegment *next_seg = seg->next; - StreamTcpRemoveSegmentFromStream(stream, seg); - StreamTcpSegmentReturntoPool(seg); - seg = next_seg; - continue; - } else { - break; - } + SCLogDebug("FLOW_NO_APPLAYER_INSPECTION set, breaking out"); + break; + } - /* if app layer protocol has been detected, then remove all the segments - * which has been previously processed and reassembled */ - } else if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) && - (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && - StreamTcpAppLayerSegmentProcessed(stream, seg)) { - SCLogDebug("segment(%p) of length %"PRIu16" has been processed," - " so return it to pool", seg, seg->payload_len); + if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) { + SCLogDebug("removing segment"); TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; + } else if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { + TcpSegment *next_seg = seg->next; + seg = next_seg; + continue; } - /* If packets are fully before ra_base_seq, skip them. We do this - * because we've reassembled up to the ra_base_seq point already, - * so we won't do anything with segments before it anyway. */ - SCLogDebug("checking for pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32"" - " len %"PRIu16", combined %"PRIu32" and stream->last_ack " - "%"PRIu32"", ra_base_seq, seg, seg->seq, - seg->payload_len, seg->seq+seg->payload_len, stream->last_ack); - /* we've run into a sequence gap */ if (SEQ_GT(seg->seq, next_seq)) { + SCLogDebug("GAP: we expected %u, got %u. Diff %u", next_seq, seg->seq, seg->seq - next_seq); + + /* don't conclude it's a gap until we see that the data + * that is missing was acked. */ + if (SEQ_GT(seg->seq,stream->last_ack) && ssn->state != TCP_CLOSED) + break; /* first, pass on data before the gap */ if (data_len > 0) { @@ -2228,55 +2244,40 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, data, data_len, flags); AppLayerProfilingStore(ra_ctx->app_tctx, p); - - data_sent += data_len; data_len = 0; } - /* don't conclude it's a gap straight away. If ra_base_seq is lower - * than last_ack - the window, we consider it a gap. */ - if (SEQ_GT((stream->last_ack - stream->window), ra_base_seq)) - { - /* see what the length of the gap is, gap length is seg->seq - - * (ra_base_seq +1) */ + /* see what the length of the gap is, gap length is seg->seq - + * (ra_base_seq +1) */ #ifdef DEBUG - uint32_t gap_len = seg->seq - next_seq; - SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " - "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", - next_seq, seg->seq, stream->last_ack, gap_len); + uint32_t gap_len = seg->seq - next_seq; + SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " + "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", + next_seq, seg->seq, stream->last_ack, gap_len); #endif + /* We have missed the packet and end host has ack'd it, so + * IDS should advance it's ra_base_seq and should not consider this + * packet any longer, even if it is retransmitted, as end host will + * drop it anyway */ + ra_base_seq = seg->seq - 1; - /* We have missed the packet and end host has ack'd it, so - * IDS should advance it's ra_base_seq and should not consider this - * packet any longer, even if it is retransmitted, as end host will - * drop it anyway */ - ra_base_seq = seg->seq - 1; - - /* send gap signal */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags|STREAM_GAP); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_len = 0; + /* send gap signal */ + STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + NULL, 0, flags|STREAM_GAP); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + data_sent += data_len; - /* set a GAP flag and make sure not bothering this stream anymore */ - SCLogDebug("set STREAMTCP_STREAM_FLAG_GAP flag"); - stream->flags |= STREAMTCP_STREAM_FLAG_GAP; + /* set a GAP flag and make sure not bothering this stream anymore */ + SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); + stream->flags |= STREAMTCP_STREAM_FLAG_GAP; - StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); -#ifdef DEBUG - dbg_app_layer_gap++; -#endif - break; - } else { - SCLogDebug("possible GAP, but waiting to see if out of order " - "packets might solve that"); + StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); + SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); #ifdef DEBUG - dbg_app_layer_gap_candidate++; + dbg_app_layer_gap++; #endif - break; - } + break; } /* if the segment ends beyond ra_base_seq we need to consider it */ @@ -2434,6 +2435,12 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, /* store ra_base_seq in the stream */ if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { stream->ra_app_base_seq = ra_base_seq; + } else { + TcpSegment *tmp_seg = stream->seg_list; + while (tmp_seg != NULL) { + tmp_seg->flags &= ~SEGMENTTCP_FLAG_APPLAYER_PROCESSED; + tmp_seg = tmp_seg->next; + } } SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq); From 969abc2ccd0b85924dd5c3aea55fd441a7cd9588 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 16 Dec 2014 00:14:59 +0100 Subject: [PATCH 0133/2553] output-json: fix duplicate logging This patches is fixing a issue in the OutputJSONBuffer function. It was writing to file the content of the buffer starting from the start to the final offset. But as the writing is done for each JSON string we are duplicating the previous events if we are reusing the same buffer. Duplication was for example triggered when we have multiple alerts attached to a packet. In the case of two alerts, the first one was logged twice more as the second one. --- src/output-json-alert.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index ed6b3b4373dc..cd1168aa2d95 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -134,8 +134,6 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (p->alerts.cnt == 0) return TM_ECODE_OK; - MemBufferReset(aft->json_buffer); - json_t *js = CreateJSONHeader((Packet *)p, 0, "alert"); if (unlikely(js == NULL)) return TM_ECODE_OK; @@ -159,6 +157,8 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) return TM_ECODE_OK; } + MemBufferReset(aft->json_buffer); + json_object_set_new(ajs, "action", json_string(action)); json_object_set_new(ajs, "gid", json_integer(pa->s->gid)); json_object_set_new(ajs, "signature_id", json_integer(pa->s->id)); @@ -303,11 +303,11 @@ static int AlertJsonDecoderEvent(ThreadVars *tv, JsonAlertLogThread *aft, const if (p->alerts.cnt == 0) return TM_ECODE_OK; - MemBufferReset(buffer); - CreateIsoTimeString(&p->ts, timebuf, sizeof(timebuf)); for (i = 0; i < p->alerts.cnt; i++) { + MemBufferReset(buffer); + const PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { continue; From ff8dae3b751029a03f6c2f4f09f036969aa9d4d9 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 19 Dec 2014 15:06:30 +0100 Subject: [PATCH 0134/2553] app-layer: fix 'detection-only' keyword If we follow the description in the yaml file, we should disable parsing if 'detection-only' keyword is used. --- src/app-layer-parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index ec45b0caf8a6..c32f721c1251 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -280,7 +280,7 @@ int AppLayerParserConfParserEnabled(const char *ipproto, } else if (strcasecmp(node->val, "no") == 0) { goto disabled; } else if (strcasecmp(node->val, "detection-only") == 0) { - goto enabled; + goto disabled; } else { SCLogError(SC_ERR_FATAL, "Invalid value found for %s.", param); exit(EXIT_FAILURE); From 2745cd2ce9fb70974285271524a6f3e17df3f4c4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Jan 2015 17:42:28 +0100 Subject: [PATCH 0135/2553] packet pool: fix wrong free call --- src/tmqh-packetpool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index b19845ff081e..ef63ec4e83cd 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -223,7 +223,7 @@ void PacketPoolReturnPacket(Packet *p) PktPool *pool = p->pool; if (pool == NULL) { - free(p); + PacketFree(p); return; } From 6fa8922ccdb4e18d5d4beee84fc425ee1d9a3bdc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 6 Jan 2015 10:18:38 +0100 Subject: [PATCH 0136/2553] configure: add switch to disable __thread use Add --disable-threading-tls switch to force the posix thread local storage code paths even if __thread is available. Goal is to make it easier to QA the posix code path. --- configure.ac | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 6f691bab83d7..48fcad47c38b 100644 --- a/configure.ac +++ b/configure.ac @@ -224,13 +224,18 @@ esac AC_MSG_RESULT(ok) - # check if our target supports thread local storage - AC_MSG_CHECKING(for thread local storage __thread support) - AC_TRY_COMPILE([#include ], - [ static __thread int i; i = 1; i++; ], - [AC_DEFINE([TLS], [1], [Thread local storage]) - AC_MSG_RESULT([yes]) ], - [AC_MSG_RESULT([no])]) + # disable TLS on user request + AC_ARG_ENABLE(threading-tls, + AS_HELP_STRING([--disable-threading-tls], [Disable TLS (thread local storage)])], [enable_tls="$enableval"],[enable_tls=yes]) + AS_IF([test "x$enable_tls" = "xyes"], [ + # check if our target supports thread local storage + AC_MSG_CHECKING(for thread local storage __thread support) + AC_TRY_COMPILE([#include ], + [ static __thread int i; i = 1; i++; ], + [AC_DEFINE([TLS], [1], [Thread local storage]) + AC_MSG_RESULT([yes]) ], + [AC_MSG_RESULT([no])]) + ]) #Enable support for gcc compile time security options. There is no great way to do detection of valid cflags that I have found #AX_CFLAGS_GCC_OPTION don't seem to do a better job than the code below and are a pain because of extra m4 files etc. From 6e174128c832c7f3a50186d3e17429ade4ce06aa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 6 Jan 2015 10:20:40 +0100 Subject: [PATCH 0137/2553] packet pool: memory fixes for non-TLS If the posix TLS implementation is used, the packet pool is memset to 0 before use. Also use proper 'free' function. --- src/tmqh-packetpool.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index ef63ec4e83cd..bd8761e25aa1 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -66,7 +66,7 @@ static int pkt_pool_thread_key_initialized = 0; static void PktPoolThreadDestroy(void * buf) { - free(buf); + SCFreeAligned(buf); } static void TmqhPacketPoolInit(void) @@ -101,6 +101,8 @@ static PktPool *ThreadPacketPoolCreate(void) SCLogError(SC_ERR_MEM_ALLOC, "malloc failed"); exit(EXIT_FAILURE); } + memset(pool,0x0,sizeof(*pool)); + int r = pthread_setspecific(pkt_pool_thread_key, pool); if (r != 0) { SCLogError(SC_ERR_MEM_ALLOC, "pthread_setspecific failed with %d", r); From 623c2e78fdd7ed952e52aca92b240109019aad04 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 6 Jan 2015 10:22:37 +0100 Subject: [PATCH 0138/2553] packet pool: make pending pool use more robust Don't leave pointers dangling. --- src/tmqh-packetpool.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index bd8761e25aa1..6ef25c7d326f 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -254,6 +254,9 @@ void PacketPoolReturnPacket(Packet *p) SCMutexUnlock(&pool->return_stack.mutex); /* Clear the list of pending packets to return. */ my_pool->pending_pool = NULL; + my_pool->pending_head = NULL; + my_pool->pending_tail = NULL; + my_pool->pending_count = 0; } } else { /* Push onto return stack for this pool */ @@ -297,7 +300,7 @@ void PacketPoolDestroy(void) { Packet *p = NULL; PktPool *my_pool = GetThreadPacketPool(); - if (my_pool && my_pool->pending_head != NULL) { + if (my_pool && my_pool->pending_pool != NULL) { p = my_pool->pending_head; while (p) { Packet *next_p = p->next; From 105b4340c2ef9a404f72733aa8ba7b487c3f6ddf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 6 Jan 2015 13:20:55 +0100 Subject: [PATCH 0139/2553] thread local storage: add to build-info --- src/suricata.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/suricata.c b/src/suricata.c index 25dab7e14923..54ec61ec4a4b 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -641,6 +641,7 @@ void SCPrintBuildInfo(void) char *bits = "-bits"; char *endian = "-endian"; char features[2048] = ""; + char *tls = "pthread key"; #ifdef REVISION printf("This is %s version %s (rev %s)\n", PROG_NAME, PROG_VER, xstr(REVISION)); @@ -717,6 +718,9 @@ void SCPrintBuildInfo(void) #endif #ifdef PROFILE_LOCKING strlcat(features, "PROFILE_LOCKING ", sizeof(features)); +#endif +#ifdef TLS + strlcat(features, "TLS ", sizeof(features)); #endif if (strlen(features) == 0) { strlcat(features, "none", sizeof(features)); @@ -798,10 +802,14 @@ void SCPrintBuildInfo(void) #ifdef CLS printf("L1 cache line size (CLS)=%d\n", CLS); #endif +#ifdef TLS + tls = "__thread"; +#endif + printf("thread local storage method: %s\n", tls); printf("compiled with %s, linked against %s\n", HTP_VERSION_STRING_FULL, htp_get_version()); - + printf("\n"); #include "build-info.h" } From f32d79dfe0ce98cbfc793a3e9ed78278315d70c3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Jan 2015 13:17:51 +0100 Subject: [PATCH 0140/2553] smtp: fix tx handling Fix issue where SMTPStateGetTxCnt would return the actual active tx'. The 'GetCnt' API call is not named correctly. It should be 'GetMaxId', as this is actually the expected behavior. --- src/app-layer-smtp.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 414a6e6721b6..91dd244c203f 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1254,20 +1254,13 @@ static void SMTPStateTransactionFree (void *state, uint64_t tx_id) } -/** \todo slow */ +/** \retval cnt highest tx id */ static uint64_t SMTPStateGetTxCnt(void *state) { uint64_t cnt = 0; SMTPState *smtp_state = state; if (smtp_state) { - SMTPTransaction *tx = NULL; - - if (smtp_state->curr_tx == NULL) - return 0ULL; - - TAILQ_FOREACH(tx, &smtp_state->tx_list, next) { - cnt++; - } + cnt = smtp_state->tx_cnt; } SCLogDebug("returning %"PRIu64, cnt); return cnt; From 485f34134ea1bce824a64f0759396f66a48bc7d3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 6 Jan 2015 13:11:38 +0100 Subject: [PATCH 0141/2553] unix socket: support profiling --- src/runmode-unix-socket.c | 12 ++++++++++++ src/suricata.c | 16 ++++++++++------ src/util-profiling.c | 3 +++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 54c85fe739c7..bff022d6eb22 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -43,6 +43,8 @@ #include "host.h" #include "defrag.h" +#include "util-profiling.h" + static const char *default_mode = NULL; int unix_socket_mode_is_running = 0; @@ -312,6 +314,11 @@ TmEcode UnixSocketPcapFilesCheck(void *data) StreamTcpFreeConfig(STREAM_VERBOSE); DefragDestroy(); TmqResetQueues(); +#ifdef PROFILING + if (profiling_rules_enabled) + SCProfilingDump(); + SCProfilingDestroy(); +#endif } if (!TAILQ_EMPTY(&this->files)) { PcapFiles *cfile = TAILQ_FIRST(&this->files); @@ -337,6 +344,11 @@ TmEcode UnixSocketPcapFilesCheck(void *data) return TM_ECODE_FAILED; } PcapFilesFree(cfile); +#ifdef PROFILING + SCProfilingRulesGlobalInit(); + SCProfilingKeywordsGlobalInit(); + SCProfilingInit(); +#endif /* PROFILING */ DefragInit(); FlowInitConfig(FLOW_QUIET); StreamTcpInitConfig(STREAM_VERBOSE); diff --git a/src/suricata.c b/src/suricata.c index 54ec61ec4a4b..14bd1a6c93e6 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2078,9 +2078,11 @@ static int PostConfLoadedSetup(SCInstance *suri) CIDRInit(); SigParsePrepare(); #ifdef PROFILING - SCProfilingRulesGlobalInit(); - SCProfilingKeywordsGlobalInit(); - SCProfilingInit(); + if (suri->run_mode != RUNMODE_UNIX_SOCKET) { + SCProfilingRulesGlobalInit(); + SCProfilingKeywordsGlobalInit(); + SCProfilingInit(); + } #endif /* PROFILING */ SCReputationInitCtx(); SCProtoNameInit(); @@ -2491,9 +2493,11 @@ int main(int argc, char **argv) #endif #ifdef PROFILING - if (profiling_rules_enabled) - SCProfilingDump(); - SCProfilingDestroy(); + if (suri.run_mode != RUNMODE_UNIX_SOCKET) { + if (profiling_rules_enabled) + SCProfilingDump(); + SCProfilingDestroy(); + } #endif #ifdef OS_WIN32 diff --git a/src/util-profiling.c b/src/util-profiling.c index 4cdfdb57a7e6..7a1ce2909931 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -279,13 +279,16 @@ SCProfilingDestroy(void) if (profiling_packets_csv_enabled) { if (packet_profile_csv_fp != NULL) fclose(packet_profile_csv_fp); + packet_profile_csv_fp = NULL; } if (profiling_csv_file_name != NULL) SCFree(profiling_csv_file_name); + profiling_csv_file_name = NULL; if (profiling_file_name != NULL) SCFree(profiling_file_name); + profiling_file_name = NULL; #ifdef PROFILE_LOCKING LockRecordFreeHash(); From 2b81caf73ecf7b47cbe061d36702a0d8fdd3074d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 29 Dec 2014 10:04:37 -0600 Subject: [PATCH 0142/2553] Respect DESTDIR in install-conf and install-rules. --- Makefile.am | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Makefile.am b/Makefile.am index d6c72ef21153..faeb777d9328 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,38 +15,38 @@ install-data-am: install-full: install install-conf install-rules install-conf: - install -d "$(e_sysconfdir)" - @test -e "$(e_sysconfdir)/suricata.yaml" || install -m 600 "$(top_srcdir)/suricata.yaml" "$(e_sysconfdir)" - @test -e "$(e_sysconfdir)/classification.config" || install -m 600 "$(top_srcdir)/classification.config" "$(e_sysconfdir)" - @test -e "$(e_sysconfdir)/reference.config" || install -m 600 "$(top_srcdir)/reference.config" "$(e_sysconfdir)" - @test -e "$(e_sysconfdir)/threshold.config" || install -m 600 "$(top_srcdir)/threshold.config" "$(e_sysconfdir)" - install -d "$(e_logfilesdir)" - install -d "$(e_logcertsdir)" - install -d "$(e_rundir)" - install -m 770 -d "$(e_localstatedir)" + install -d "$(DESTDIR)$(e_sysconfdir)" + @test -e "$(DESTDIR)$(e_sysconfdir)/suricata.yaml" || install -m 600 "$(top_srcdir)/suricata.yaml" "$(DESTDIR)$(e_sysconfdir)" + @test -e "$(DESTDIR)$(e_sysconfdir)/classification.config" || install -m 600 "$(top_srcdir)/classification.config" "$(DESTDIR)$(e_sysconfdir)" + @test -e "$(DESTDIR)$(e_sysconfdir)/reference.config" || install -m 600 "$(top_srcdir)/reference.config" "$(DESTDIR)$(e_sysconfdir)" + @test -e "$(DESTDIR)$(e_sysconfdir)/threshold.config" || install -m 600 "$(top_srcdir)/threshold.config" "$(DESTDIR)$(e_sysconfdir)" + install -d "$(DESTDIR)$(e_logfilesdir)" + install -d "$(DESTDIR)$(e_logcertsdir)" + install -d "$(DESTDIR)$(e_rundir)" + install -m 770 -d "$(DESTDIR)$(e_localstatedir)" install-rules: - install -d "$(e_sysconfrulesdir)" + install -d "$(DESTDIR)$(e_sysconfrulesdir)" if HAVE_FETCH_COMMAND if HAVE_WGET_COMMAND - $(HAVE_WGET) -qO - http://rules.emergingthreats.net/open/suricata-2.0/emerging.rules.tar.gz | tar -x -z -C "$(e_sysconfdir)" -f - + $(HAVE_WGET) -qO - http://rules.emergingthreats.net/open/suricata-2.0/emerging.rules.tar.gz | tar -x -z -C "$(DESTDIR)$(e_sysconfdir)" -f - else - $(HAVE_CURL) -s http://rules.emergingthreats.net/open/suricata-2.0/emerging.rules.tar.gz | tar -x -z -C "$(e_sysconfdir)" -f - + $(HAVE_CURL) -s http://rules.emergingthreats.net/open/suricata-2.0/emerging.rules.tar.gz | tar -x -z -C "$(DESTDIR)$(e_sysconfdir)" -f - endif else @echo "UNABLE to load ruleset wget or curl are not installed on system." endif - @test -e "$(e_sysconfrulesdir)decoder-events.rules" || install -m 600 "$(top_srcdir)/rules/decoder-events.rules" "$(e_sysconfrulesdir)" - @test -e "$(e_sysconfrulesdir)stream-events.rules" || install -m 600 "$(top_srcdir)/rules/stream-events.rules" "$(e_sysconfrulesdir)" - @test -e "$(e_sysconfrulesdir)smtp-events.rules" || install -m 600 "$(top_srcdir)/rules/smtp-events.rules" "$(e_sysconfrulesdir)" - @test -e "$(e_sysconfrulesdir)http-events.rules" || install -m 600 "$(top_srcdir)/rules/http-events.rules" "$(e_sysconfrulesdir)" - @test -e "$(e_sysconfrulesdir)dns-events.rules" || install -m 600 "$(top_srcdir)/rules/dns-events.rules" "$(e_sysconfrulesdir)" - @test -e "$(e_sysconfrulesdir)modbus-events.rules" || install -m 600 "$(top_srcdir)/rules/modbus-events.rules" "$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)decoder-events.rules" || install -m 600 "$(top_srcdir)/rules/decoder-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)stream-events.rules" || install -m 600 "$(top_srcdir)/rules/stream-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)smtp-events.rules" || install -m 600 "$(top_srcdir)/rules/smtp-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)http-events.rules" || install -m 600 "$(top_srcdir)/rules/http-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)dns-events.rules" || install -m 600 "$(top_srcdir)/rules/dns-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)modbus-events.rules" || install -m 600 "$(top_srcdir)/rules/modbus-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @echo "" - @echo "You can now start suricata by running as root something like '$(bindir)/suricata -c $(e_sysconfdir)/suricata.yaml -i eth0'." + @echo "You can now start suricata by running as root something like '$(DESTDIR)$(bindir)/suricata -c $(DESTDIR)$(e_sysconfdir)/suricata.yaml -i eth0'." @echo "" @echo "If a library like libhtp.so is not found, you can run suricata with:" - @echo "'LD_LIBRARY_PATH="$(prefix)/lib" "$(bindir)/suricata" -c "$(e_sysconfdir)/suricata.yaml" -i eth0'." + @echo "'LD_LIBRARY_PATH="$(DESTDIR)$(prefix)/lib" "$(DESTDIR)$(bindir)/suricata" -c "$(DESTDIR)$(e_sysconfdir)/suricata.yaml" -i eth0'." @echo "" @echo "While rules are installed now, it's highly recommended to use a rule manager for maintaining rules." @echo "The two most common are Oinkmaster and Pulledpork. For a guide see:" From a1eab4a2e22d100229407f3e168662a42396eca7 Mon Sep 17 00:00:00 2001 From: Travis Green Date: Tue, 23 Dec 2014 15:10:21 -0700 Subject: [PATCH 0143/2553] Update reference.config Updated reference.config to match ET Open reference.config found here: https://rules.emergingthreats.net/open/suricata/reference.config Due to startup error shown here: root@xxxxxxx01:/etc/suricata/rules# /usr/bin/suricata -c /etc/suricata/suricata.yaml --pidfile /var/run/suricata.pid --af-packet 23/12/2014 -- 22:07:56 - - [ERRCODE: SC_ERR_REFERENCE_UNKNOWN(150)] - unknown reference key "osvdb". Supported keys are defined in reference.config file. Please have a look at the conf param "reference-config-file" <...> Killed --- reference.config | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/reference.config b/reference.config index 1d1b42d8984a..ff4f53ddbcd1 100644 --- a/reference.config +++ b/reference.config @@ -3,6 +3,7 @@ config reference: bugtraq http://www.securityfocus.com/bid/ config reference: bid http://www.securityfocus.com/bid/ config reference: cve http://cve.mitre.org/cgi-bin/cvename.cgi?name= +#config reference: cve http://cvedetails.com/cve/ config reference: secunia http://www.secunia.com/advisories/ #whitehats is unfortunately gone @@ -12,8 +13,14 @@ config reference: McAfee http://vil.nai.com/vil/content/v_ config reference: nessus http://cgi.nessus.org/plugins/dump.php3?id= config reference: url http:// config reference: et http://doc.emergingthreats.net/ -config reference: etpro http://doc.emergingthreatpro.com/ +config reference: etpro http://doc.emergingthreatspro.com/ config reference: telus http:// - -config reference: md5 http://www.threatexpert.com/report.aspx?md5= - +config reference: osvdb http://osvdb.org/show/osvdb/ +config reference: threatexpert http://www.threatexpert.com/report.aspx?md5= +config reference: md5 http://www.threatexpert.com/report.aspx?md5= +config reference: exploitdb http://www.exploit-db.com/exploits/ +config reference: openpacket https://www.openpacket.org/capture/grab/ +config reference: securitytracker http://securitytracker.com/id? +config reference: secunia http://secunia.com/advisories/ +config reference: xforce http://xforce.iss.net/xforce/xfdb/ +config reference: msft http://technet.microsoft.com/security/bulletin/ From 8e946b92b78633955cf23a2f79cbdeaa330a22eb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 14 Jan 2015 09:48:39 +0100 Subject: [PATCH 0144/2553] Fix compilation on OS X Yosemite Due to our unconditional declaration of the strlcat and strlcpy functions, compilation failed on OS X Yosemite. Bug #1192 --- configure.ac | 1 + src/suricata-common.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index 48fcad47c38b..fb4dfefe7098 100644 --- a/configure.ac +++ b/configure.ac @@ -164,6 +164,7 @@ AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([gettimeofday memset strcasecmp strchr strdup strerror strncasecmp strtol strtoul memchr memrchr]) + AC_CHECK_FUNCS([strlcpy strlcat]) # Add large file support AC_SYS_LARGEFILE diff --git a/src/suricata-common.h b/src/suricata-common.h index 43c76c19f7c5..9aafa7aa3583 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -323,8 +323,12 @@ typedef enum PacketProfileDetectId_ { #include "util-path.h" #include "util-conf.h" +#ifndef HAVE_STRLCAT size_t strlcat(char *, const char *src, size_t siz); +#endif +#ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); +#endif extern int coverage_unittests; extern int g_ut_modules; From baa55ba239172c444da62889c7e27ca37c550d0c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 14 Jan 2015 21:55:31 +0100 Subject: [PATCH 0145/2553] Fix Tilera compilation Use proper initializer for a static mutex declaration. Credits: Ken Steele --- src/tm-threads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index 0246ec681b02..1bce7526c9ba 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -2113,7 +2113,7 @@ typedef struct Threads_ { } Threads; static Threads thread_store = { NULL, 0, 0 }; -static SCMutex thread_store_lock = PTHREAD_MUTEX_INITIALIZER; +static SCMutex thread_store_lock = SCMUTEX_INITIALIZER; void TmThreadsListThreads(void) { From c51ce4d2c0265c5e2311c9cfd025b4613f82671e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 14 Jan 2015 23:49:54 +0100 Subject: [PATCH 0146/2553] Fix OS X 10.10 unittest failure Work around OS X 10.10 Yosemite returning EDEADLK on a rwlock wrlocked then tested by wrtrylock. All other OS' (and versions of OS X that I tested) seem to return EBUSY instead. --- src/threads.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/threads.c b/src/threads.c index 329890157391..6e58582534f6 100644 --- a/src/threads.c +++ b/src/threads.c @@ -89,7 +89,14 @@ int ThreadMacrosTest03RWLocks(void) int r = 0; r |= SCRWLockInit(&rwl_write, NULL); r |= SCRWLockWRLock(&rwl_write); +/* work around OS X 10.10 Yosemite returning EDEADLK. All other + * OS' (and versions of OS X that I tested) seem to return EBUSY + * instead. */ +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__==101000 + r |= (SCRWLockTryWRLock(&rwl_write) == EDEADLK)? 0 : 1; +#else r |= (SCRWLockTryWRLock(&rwl_write) == EBUSY)? 0 : 1; +#endif r |= SCRWLockUnlock(&rwl_write); r |= SCRWLockDestroy(&rwl_write); From 17dfd59bc31a21e103e2f1216443cd1418398aa9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Dec 2014 19:12:20 +0100 Subject: [PATCH 0147/2553] memcmp: compare the first byte as well MemcmpLowercase would not compare the first byte of both input buffers leading to two non-identical buffers to be considered the same. Affects SSE_4_1 and SSE_4_2 implementations of SCMemcmpLowercase, as well as the non-SIMD implementation. SSE_3 and Tile version are not affected. --- src/util-memcmp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-memcmp.h b/src/util-memcmp.h index 4a5be891ee17..875652b10921 100644 --- a/src/util-memcmp.h +++ b/src/util-memcmp.h @@ -41,12 +41,12 @@ void MemcmpRegisterTests(void); static inline int MemcmpLowercase(const void *s1, const void *s2, size_t n) { - size_t i; + ssize_t i; /* check backwards because we already tested the first * 2 to 4 chars. This way we are more likely to detect * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { + for (i = n - 1; i >= 0; i--) { if (((uint8_t *)s1)[i] != u8_tolower(*(((uint8_t *)s2)+i))) return 1; } From 0d910bed1d54e44e4a6aed8fcbeecf03b947d7a5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Dec 2014 19:41:32 +0100 Subject: [PATCH 0148/2553] Add test for memcmp issue. --- src/util-memcmp.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/util-memcmp.c b/src/util-memcmp.c index f5ab3d095f0a..c1b03490da92 100644 --- a/src/util-memcmp.c +++ b/src/util-memcmp.c @@ -339,6 +339,46 @@ static int MemcmpTest17 (void) return 1; } +struct MemcmpTest18Tests { + char *a; + char *b; + int result; +} memcmp_tests18_tests[] = { + { "abcdefgh", "!bcdefgh", 1, }, + { "?bcdefgh", "!bcdefgh", 1, }, + { "!bcdefgh", "abcdefgh", 1, }, + { "!bcdefgh", "?bcdefgh", 1, }, + { "zbcdefgh", "bbcdefgh", 1, }, + + { "abcdefgh12345678", "!bcdefgh12345678", 1, }, + { "?bcdefgh12345678", "!bcdefgh12345678", 1, }, + { "!bcdefgh12345678", "abcdefgh12345678", 1, }, + { "!bcdefgh12345678", "?bcdefgh12345678", 1, }, + { "bbcdefgh12345678", "zbcdefgh12345678", 1, }, + + { "abcdefgh", "abcdefgh", 0, }, + { "abcdefgh", "Abcdefgh", 0, }, + { "abcdefgh12345678", "Abcdefgh12345678", 0, }, + + { NULL, NULL, 0 }, + + }; + +static int MemcmpTest18 (void) +{ + struct MemcmpTest18Tests *t = memcmp_tests18_tests; + + while (t && t->a != NULL) { + + if (SCMemcmpLowercase(t->a, t->b, strlen(t->a)-1) != t->result) + return 0; + SCLogInfo("ok"); + t++; + } + + return 1; +} + #endif /* UNITTESTS */ void MemcmpRegisterTests(void) @@ -361,6 +401,7 @@ void MemcmpRegisterTests(void) UtRegisterTest("MemcmpTest15", MemcmpTest15, 1); UtRegisterTest("MemcmpTest16", MemcmpTest16, 1); UtRegisterTest("MemcmpTest17", MemcmpTest17, 1); + UtRegisterTest("MemcmpTest18", MemcmpTest18, 1); #endif /* UNITTESTS */ } From 43a1007788b453fdaffcd8e7ca74d47e0e510863 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Dec 2014 10:30:34 +0100 Subject: [PATCH 0149/2553] detect: add test for memcmp issue --- src/detect.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/detect.c b/src/detect.c index c1cd88542bae..54d035af6ce8 100644 --- a/src/detect.c +++ b/src/detect.c @@ -11562,6 +11562,65 @@ static int SigTestPorts01(void) return result; } +/** \test almost identical patterns */ +static int SigTestBug01(void) +{ + int result = 0; + Packet *p1 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + uint8_t payload[] = "!mymy"; + + memset(&tv, 0, sizeof(ThreadVars)); + + p1 = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(content:\"Omymy\"; nocase; sid:1;)"); + if (s == NULL) { + goto end; + } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(content:\"!mymy\"; nocase; sid:2;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sig 1 alerted on p1, but it should not: "); + goto end; + } + if (!(PacketAlertCheck(p1, 2))) { + printf("sig 2 did not p1, but it should have: "); + goto end; + } + + result = 1; +end: + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + UTHFreePackets(&p1, 1); + return result; +} + static const char *dummy_conf_string2 = "%YAML 1.1\n" "---\n" @@ -11966,6 +12025,7 @@ void SigRegisterTests(void) UtRegisterTest("DetectAddressYamlParsing04", DetectAddressYamlParsing04, 1); UtRegisterTest("SigTestPorts01", SigTestPorts01, 1); + UtRegisterTest("SigTestBug01", SigTestBug01, 1); DetectSimdRegisterTests(); #endif /* UNITTESTS */ From bcfd61416ff789520cfa793d7f69c80a52bd0964 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 12 Dec 2014 18:20:24 +0100 Subject: [PATCH 0150/2553] Fix a fix: defrag OOM condition ** CID 1257764: Dereference after null check (FORWARD_NULL) /src/defrag.c: 291 in Defrag4Reassemble() ** CID 1257763: Dereference after null check (FORWARD_NULL) /src/defrag.c: 409 in Defrag6Reassemble() In the error case 'rp' can be both NULL or non-NULL. --- src/defrag.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/defrag.c b/src/defrag.c index 71225b8da9f3..f005ade7de37 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -358,7 +358,8 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) error_remove_tracker: tracker->remove = 1; DefragTrackerFreeFrags(tracker); - PacketFreeOrRelease(rp); + if (rp != NULL) + PacketFreeOrRelease(rp); return NULL; } @@ -480,7 +481,8 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) error_remove_tracker: tracker->remove = 1; DefragTrackerFreeFrags(tracker); - PacketFreeOrRelease(rp); + if (rp != NULL) + PacketFreeOrRelease(rp); return NULL; } From 227a7de351ff3c93957dfed8292dcfa106fbb1b8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 8 Dec 2014 10:40:17 +0100 Subject: [PATCH 0151/2553] Global define of MIN Some OS' provide it automatically, so make sure we define it conditionally in one place. --- src/suricata-common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/suricata-common.h b/src/suricata-common.h index 9aafa7aa3583..deb0e077cc83 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -282,6 +282,10 @@ #define pcre_free_study pcre_free #endif +#ifndef MIN +#define MIN(x, y) (((x)<(y))?(x):(y)) +#endif + typedef enum PacketProfileDetectId_ { PROF_DETECT_MPM, PROF_DETECT_MPM_PACKET, /* PKT MPM */ From 5008d0a58b5696ad2069aa20838a33d901171ce5 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Thu, 16 Oct 2014 08:19:25 -0400 Subject: [PATCH 0152/2553] Remove the b2gm and b2gc MPMs These MPMs have code that looks like it won't work and updating them to for the new MPM optimization wasn't working. --- src/Makefile.am | 2 - src/util-mpm-b2gc.c | 2946 ------------------------------------------- src/util-mpm-b2gc.h | 153 --- src/util-mpm-b2gm.c | 2788 ---------------------------------------- src/util-mpm-b2gm.h | 143 --- suricata.yaml.in | 10 +- 6 files changed, 1 insertion(+), 6041 deletions(-) delete mode 100644 src/util-mpm-b2gc.c delete mode 100644 src/util-mpm-b2gc.h delete mode 100644 src/util-mpm-b2gm.c delete mode 100644 src/util-mpm-b2gm.h diff --git a/src/Makefile.am b/src/Makefile.am index 2ef8b3f0e652..cc1357e0f8b0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -344,9 +344,7 @@ util-mpm-ac.c util-mpm-ac.h \ util-mpm-ac-gfbs.c util-mpm-ac-gfbs.h \ util-mpm-ac-tile.c util-mpm-ac-tile.h \ util-mpm-ac-tile-small.c \ -util-mpm-b2gc.c util-mpm-b2gc.h \ util-mpm-b2g.c util-mpm-b2g.h \ -util-mpm-b2gm.c util-mpm-b2gm.h \ util-mpm-b3g.c util-mpm-b3g.h \ util-mpm.c util-mpm.h \ util-mpm-wumanber.c util-mpm-wumanber.h \ diff --git a/src/util-mpm-b2gc.c b/src/util-mpm-b2gc.c deleted file mode 100644 index b80100d5c3eb..000000000000 --- a/src/util-mpm-b2gc.c +++ /dev/null @@ -1,2946 +0,0 @@ -/* Copyright (C) 2007-2010 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 - * - * Implementation of the SBNDMq pattern matching algorithm that tries - * to be very limiting memory use and CPU cache efficient. - * - * Things to try: - * - 1 byte pattern checks use lowercase *buf for hash, limiting the hash - * - lookup array with pminlen and pminlenb like in B2gm - */ - -//#define PRINTMATCH - -#include "suricata-common.h" -#include "suricata.h" -#include "detect.h" - -#include "util-mpm-b2gc.h" -#include "util-print.h" -#include "util-bloomfilter.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-hashlist.h" -#include "util-optimize.h" -#include "util-memcmp.h" - -#include "conf.h" - -#ifdef B2GC_COUNTERS -#define COUNT(counter) \ - (counter) -#else -#define COUNT(counter) -#endif /* B2GC_COUNTERS */ - -/* Hash table used at ctx initialization to keep and ordered list of - * patterns. The ordered list is used to build the ordered lookup - * array. */ -static uint32_t b2gc_hash_size = 0; -static int8_t b2gc_hash_shift = 0; -static uint32_t b2gc_bloom_size = 0; -static void *b2g_func; - -#define B2GC_HASH16(a,b) (((a) << b2gc_hash_shift) | (b)) - -#define B2GC_PMINLEN_MAX 8 - -/* align pattern storage to these bytes. 1 disables. */ -#define B2GC_ALIGN_PATTERNS 2 - -void B2gcInitCtx (MpmCtx *); -void B2gcThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); -void B2gcDestroyCtx(MpmCtx *); -void B2gcThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); -int B2gcAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gcAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gcPreparePatterns(MpmCtx *mpm_ctx); -uint32_t B2gcSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gcSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#ifdef B2GC_SEARCH2 -uint32_t B2gcSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#endif -uint32_t B2gcSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gcSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); -void B2gcPrintInfo(MpmCtx *mpm_ctx); -void B2gcPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void B2gcRegisterTests(void); - -void MpmB2gcRegister (void) -{ - mpm_table[MPM_B2GC].name = "b2gc"; - mpm_table[MPM_B2GC].max_pattern_length = B2GC_WORD_SIZE; - - mpm_table[MPM_B2GC].InitCtx = B2gcInitCtx; - mpm_table[MPM_B2GC].InitThreadCtx = B2gcThreadInitCtx; - mpm_table[MPM_B2GC].DestroyCtx = B2gcDestroyCtx; - mpm_table[MPM_B2GC].DestroyThreadCtx = B2gcThreadDestroyCtx; - mpm_table[MPM_B2GC].AddPattern = B2gcAddPatternCS; - mpm_table[MPM_B2GC].AddPatternNocase = B2gcAddPatternCI; - mpm_table[MPM_B2GC].Prepare = B2gcPreparePatterns; - mpm_table[MPM_B2GC].Search = B2gcSearchWrap; - mpm_table[MPM_B2GC].Cleanup = NULL; - mpm_table[MPM_B2GC].PrintCtx = B2gcPrintInfo; - mpm_table[MPM_B2GC].PrintThreadCtx = B2gcPrintSearchStats; - mpm_table[MPM_B2GC].RegisterUnittests = B2gcRegisterTests; -} - -#ifdef PRINTMATCH -static void prt (uint8_t *buf, uint16_t buflen) -{ - uint16_t i; - - for (i = 0; i < buflen; i++) { - if (isprint(buf[i])) printf("%c", buf[i]); - else printf("\\x%02X", buf[i]); - } - //printf("\n"); -} -#endif - -void B2gcPrintInfo(MpmCtx *mpm_ctx) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - printf("MPM B2gc Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeofs:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" B2gcCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gcCtx)); - printf(" B2gcPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gcPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Hash size: %" PRIu32 "\n", ctx->hash_size); - printf("\n"); -} - -static inline int -memcmp_lowercase(const uint8_t *s1, const uint8_t *s2, const uint16_t n) -{ - size_t i; - - /* check backwards because we already tested the first - * 2 to 4 chars. This way we are more likely to detect - * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { - //if (u8_tolower(*(s2+i)) != u8_tolower(s1[i])) - if (s1[i] != u8_tolower(*(s2+i))) - return 1; - } - - return 0; -} - -static inline int -memcmp_lowercase2(uint8_t *s1, uint8_t *s2, uint16_t n) -{ - size_t i; - - /* check backwards because we already tested the first - * 2 to 4 chars. This way we are more likely to detect - * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { - //if (u8_tolower(*(s2+i)) != u8_tolower(s1[i])) - if (u8_tolower(s1[i]) != u8_tolower(*(s2+i))) - return 1; - } - - return 0; -} - -static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) -{ - uint16_t i; - for (i = 0; i < len; i++) { - d[i] = u8_tolower(s[i]); - } -} - -static inline B2gcPattern *B2gcAllocPattern(MpmCtx *mpm_ctx) -{ - B2gcPattern *p = SCMalloc(sizeof(B2gcPattern)); - if (unlikely(p == NULL)) - return NULL; - memset(p,0,sizeof(B2gcPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gcPattern); - return p; -} - -/** \internal - * \brief Free a init hash pattern - */ -static void B2gcFreePattern(MpmCtx *mpm_ctx, B2gcPattern *p) -{ - if (p != NULL) { - if (p->pat != NULL) { - SCFree(p->pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gcPattern); - } -} - -/** \internal - * \brief add a pattern to the mpm/b2g context - * - * \param pat ptr to the pattern - * \param patlen length of the pattern - * \param pid pattern id - * \param sid signature id (internal id) - * \param flags pattern MPM_PATTERN_* flags - */ -static int B2gcAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); - - if (patlen == 0) - return 0; - - /* detect duplicate pattern adds */ - B2gcPattern lookup_p = { patlen, flags, 0, pid, pat }; - - /* get a memory piece */ - B2gcPattern *p = HashListTableLookup(ctx->b2gc_init_hash, (void *)&lookup_p, sizeof(B2gcPattern)); - if (p == NULL) { - SCLogDebug("allocing new pattern"); - - p = B2gcAllocPattern(mpm_ctx); - if (p == NULL) - goto error; - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->pat = SCMalloc(patlen); - if (p->pat == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - - memcpy(p->pat, pat, patlen); - - /* put in the pattern hash */ - HashListTableAdd(ctx->b2gc_init_hash, (void *)p, sizeof(B2gcPattern)); - - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) - mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; -} - return 0; - -error: - B2gcFreePattern(mpm_ctx, p); - return -1; -} - -int B2gcAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return B2gcAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -int B2gcAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - return B2gcAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -static inline uint32_t B2gcBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint16_t i; - uint32_t hash = (uint32_t)u8_tolower(*d); - - for (i = 1; i < datalen; i++) { - d++; - hash += (u8_tolower(*d)) ^ i; - } - hash <<= (iter+1); - - hash %= hash_size; - return hash; -} - -static uint32_t B2gcHashPatternInitHash(HashListTable *ht, void *pattern, uint16_t len) -{ - BUG_ON(len != sizeof(B2gcPattern)); - BUG_ON(pattern == NULL); - - B2gcPattern *p = (B2gcPattern *)pattern; - uint32_t hash = 0; - - uint32_t u; - for (u = 0; u < p->len; u++) { - hash += (u8_tolower(p->pat[u])); - } - - return hash % ht->array_size; -} - -#define B2GC_SORTHASH_MODE_LL 0 -#define B2GC_SORTHASH_MODE_LU 1 -#define B2GC_SORTHASH_MODE_UL 2 -#define B2GC_SORTHASH_MODE_UU 3 -#define B2GC_SORTHASH_MODE_CS 4 - -/* copy of ctx->m for use in B2gcHashPatternSortHash */ -static B2GC_TYPE m; -static int b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LL; - -static uint32_t B2gcHashPatternSortHash(HashListTable *ht, void *pattern, uint16_t len) -{ - BUG_ON(len != sizeof(B2gcPattern)); - BUG_ON(pattern == NULL); - - B2gcPattern *p = (B2gcPattern *)pattern; - uint32_t hash = 0; - if (b2gc_sorthash_mode == B2GC_SORTHASH_MODE_LL) { - hash = B2GC_HASH16(u8_tolower(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); - } else if(b2gc_sorthash_mode == B2GC_SORTHASH_MODE_LU) { - hash = B2GC_HASH16(u8_tolower(p->pat[m - 2]), toupper(p->pat[m - 1])); - } else if(b2gc_sorthash_mode == B2GC_SORTHASH_MODE_UL) { - hash = B2GC_HASH16(toupper(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); - } else if (b2gc_sorthash_mode == B2GC_SORTHASH_MODE_UU) { - hash = B2GC_HASH16(toupper(p->pat[m - 2]), toupper(p->pat[m - 1])); - } else { - hash = B2GC_HASH16(p->pat[m - 2], p->pat[m - 1]); - } - SCReturnUInt(hash); -} - -static uint32_t B2gcHashPatternSortHash1(HashListTable *ht, void *pattern, uint16_t len) -{ - BUG_ON(len != sizeof(B2gcPattern)); - BUG_ON(pattern == NULL); - - B2gcPattern *p = (B2gcPattern *)pattern; - return (uint32_t)u8_tolower(p->pat[0]); -} - -static char B2gcHashPatternCompare(void *pattern1, uint16_t len1, - void *pattern2, uint16_t len2) -{ - BUG_ON(len1 != sizeof(B2gcPattern)); - BUG_ON(len2 != sizeof(B2gcPattern)); - - B2gcPattern *p1 = (B2gcPattern *)pattern1; - B2gcPattern *p2 = (B2gcPattern *)pattern2; - - if (p1->id != p2->id) { - return 0; - } - - return 1; -} - -static void B2gcHashPatternFree(void *pattern) -{ - B2gcPattern *p = (B2gcPattern *)pattern; - - SCFree(p->pat); - - SCFree(pattern); -} - -static void B2gcAddToMatchArray(MpmCtx *mpm_ctx, B2gcPattern *p, int j) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* u, u */ - uint16_t uuidx = B2GC_HASH16(toupper(p->pat[j]), toupper(p->pat[j + 1])); - ctx->B2GC[uuidx] = ctx->B2GC[uuidx] | (1 << (ctx->m - j)); - - /* l, l */ - uint16_t llidx = B2GC_HASH16(u8_tolower(p->pat[j]), u8_tolower(p->pat[j + 1])); - if (llidx != uuidx) { - ctx->B2GC[llidx] = ctx->B2GC[llidx] | (1 << (ctx->m - j)); - } - /* u, l */ - uint16_t ulidx = B2GC_HASH16(toupper(p->pat[j]), u8_tolower(p->pat[j + 1])); - if (ulidx != llidx && ulidx != uuidx) { - ctx->B2GC[ulidx] = ctx->B2GC[ulidx] | (1 << (ctx->m - j)); - } - /* l, u */ - uint16_t luidx = B2GC_HASH16(u8_tolower(p->pat[j]), toupper(p->pat[j + 1])); - if (luidx != ulidx && luidx != llidx && luidx != uuidx) { - ctx->B2GC[luidx] = ctx->B2GC[luidx] | (1 << (ctx->m - j)); - } - - SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); - } -} - -int B2gcBuildMatchArray(MpmCtx *mpm_ctx, HashListTable *b2gc_sort_hash) -{ - SCEnter(); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - ctx->B2GC = SCMalloc(sizeof(B2GC_TYPE) * ctx->hash_size); - if (ctx->B2GC == NULL) - return -1; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2GC_TYPE) * ctx->hash_size); - - memset(ctx->B2GC, 0x00, (b2gc_hash_size * sizeof(B2GC_TYPE))); - - uint32_t j; - - /* fill the match array */ - for (j = 0; j <= (ctx->m - B2GC_Q); j++) { - HashListTableBucket *next = NULL; - HashListTableBucket *buck = HashListTableGetListHead(b2gc_sort_hash); - - while (buck != NULL) { - /* get the next before we free "buck" */ - next = HashListTableGetListNext(buck); - - B2gcPattern *p = (B2gcPattern *) HashListTableGetListData(buck); - BUG_ON(p == NULL); - - if (p->len < ctx->m) - goto next; - - uint16_t h; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - B2gcAddToMatchArray(mpm_ctx, p, j); - } else { - h = B2GC_HASH16(p->pat[j],p->pat[j+1]); - ctx->B2GC[h] = ctx->B2GC[h] | (1 << (ctx->m - j)); - SCLogDebug("h %"PRIu16", ctx->B2GC[h] %"PRIu32" (cs)", h, ctx->B2GC[h]); - } - next: - buck = next; - } - } - - SCReturnInt(0); -} - -static void B2gcAddCopyToHash(MpmCtx *mpm_ctx, HashListTable *ht, B2gcPattern *p) -{ - B2gcPattern *pcopy = B2gcAllocPattern(mpm_ctx); - BUG_ON(pcopy == NULL); - pcopy->id = p->id; - pcopy->flags = p->flags; - pcopy->len = p->len; - - pcopy->pat = SCMalloc(pcopy->len); - BUG_ON(pcopy->pat == NULL); - - memcpy(pcopy->pat, p->pat, pcopy->len); - - HashListTableAdd(ht, (void *)pcopy, sizeof(B2gcPattern)); -} - -static int B2gcAddToHash(MpmCtx *mpm_ctx, HashListTable *b2gc_sort_hash, B2gcPattern *p) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - int added = 0; - //printf("%c.%c\n", p->pat[ctx->m - 2], p->pat[ctx->m - 1]); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* u, u */ - uint16_t uuidx = B2GC_HASH16(toupper(p->pat[ctx->m - 2]), toupper(p->pat[ctx->m - 1])); - b2gc_sorthash_mode = B2GC_SORTHASH_MODE_UU; - HashListTableAdd(b2gc_sort_hash, (void *)p, sizeof(B2gcPattern)); - added++; - - /* l, l */ - uint16_t llidx = B2GC_HASH16(u8_tolower(p->pat[ctx->m - 2]), u8_tolower(p->pat[ctx->m - 1])); - if (llidx != uuidx) { - b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LL; - B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); - added++; - } - /* u, l */ - uint16_t ulidx = B2GC_HASH16(toupper(p->pat[ctx->m - 2]), u8_tolower(p->pat[ctx->m - 1])); - if (ulidx != llidx && ulidx != uuidx) { - b2gc_sorthash_mode = B2GC_SORTHASH_MODE_UL; - B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); - added++; - } - /* l, u */ - uint16_t luidx = B2GC_HASH16(u8_tolower(p->pat[ctx->m - 2]), toupper(p->pat[ctx->m - 1])); - if (luidx != ulidx && luidx != llidx && luidx != uuidx) { - b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LU; - B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); - added++; - } - - SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); - } - - return added; -} - -static void B2gcPrepareHash(MpmCtx *mpm_ctx) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - HashListTable *b2gc_sort_hash = NULL; - HashListTable *b2gc_sort_hash1 = NULL; - - /* make sure ctx->m is set */ - BUG_ON(ctx->m == 0); - m = ctx->m; - - /* convert b2gc_init_hash to b2gc_sort_hash and count size */ - uint32_t size = B2GC_ALIGN_PATTERNS; - uint16_t size1 = 1; - - /* only used at init */ - b2gc_sort_hash = HashListTableInit(b2gc_hash_size, B2gcHashPatternSortHash, B2gcHashPatternCompare, B2gcHashPatternFree); - if (b2gc_sort_hash == NULL) { - exit(EXIT_FAILURE); - } - - b2gc_sort_hash1 = HashListTableInit(256, B2gcHashPatternSortHash1, B2gcHashPatternCompare, B2gcHashPatternFree); - if (b2gc_sort_hash1 == NULL) { - exit(EXIT_FAILURE); - } - - HashListTableBucket *next = NULL; - HashListTableBucket *buck = HashListTableGetListHead(ctx->b2gc_init_hash); - while (buck != NULL) { - /* get the next before we free "buck" */ - next = HashListTableGetListNext(buck); - - B2gcPattern *p = (B2gcPattern *) HashListTableGetListData(buck); - BUG_ON(p == NULL); - - //printf("init_hash: "); prt(p->pat,p->len);printf("\n"); - if (p->len > 1) { - uint32_t psize; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - //prt(p->pat, p->len);printf(" (m %u)\n", m); - int added = B2gcAddToHash(mpm_ctx, b2gc_sort_hash, p); - SCLogDebug("nocase pattern was added under different hash values %d times", added); - - uint32_t one = sizeof(B2gcPatternHdr) + ((p->len + (p->len % B2GC_ALIGN_PATTERNS))); - //uint32_t one = sizeof(B2gcPatternHdr) + ((p->len + (p->len % B2GC_ALIGN_PATTERNS)) * 2); - psize = one * added; - } else { - b2gc_sorthash_mode = B2GC_SORTHASH_MODE_CS; - HashListTableAdd(b2gc_sort_hash, (void *)p, sizeof(B2gcPattern)); - - psize = (sizeof(B2gcPatternHdr) + p->len + (p->len % B2GC_ALIGN_PATTERNS)); - } - - size += psize; - } else { - HashListTableAdd(b2gc_sort_hash1, (void *)p, sizeof(B2gcPattern)); - size1 += (sizeof(B2gcPattern1)); - } - - buck = next; - } - HashListTableFree(ctx->b2gc_init_hash); - ctx->b2gc_init_hash = NULL; - - SCLogDebug("size %u", size); - - /* alloc buf of size */ - ctx->patterns = SCMalloc(size); - BUG_ON(ctx->patterns == NULL); - memset(ctx->patterns, 0x00, size); - - ctx->patterns1 = SCMalloc(size1); - BUG_ON(ctx->patterns1 == NULL); - memset(ctx->patterns1, 0x00, size1); - - /* loop through sort list and copy to buf */ - - /* skip the first byte of the buffer */ - uint32_t offset = B2GC_ALIGN_PATTERNS; - - /* the hashlist is not sorted, it's in the order of insertion. - * We need it to be sorted by hash, so here we do something - * unclean: we bypass the hashlist api. */ - uint32_t a = 0; - for (a = 0; a < b2gc_sort_hash->array_size; a++) { - if ((buck = b2gc_sort_hash->array[a]) != NULL) { - while (buck != NULL) { - if (buck->data != NULL) { - uint32_t prev_offset = offset; - B2gcPattern *p = (B2gcPattern *) (buck->data); - BUG_ON(p == NULL); - BUG_ON(p->len == 1); - - uint16_t hash = a;//= B2GC_HASH16(u8_tolower(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); - if (ctx->pminlen[hash] == 0) { - ctx->pminlen[hash] = p->len; - } else if (p->len < ctx->pminlen[hash]) { - ctx->pminlen[hash] = p->len; - } - - if (ctx->ha[hash] == 0) - ctx->ha[hash] = offset; - - /* copy */ - B2gcPatternHdr *h = (B2gcPatternHdr *)&ctx->patterns[offset]; - h->id = p->id; - h->len = p->len; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - h->flags |= B2GC_FLAG_NOCASE; - } - - offset += sizeof(B2gcPatternHdr); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - memcpy_tolower(&ctx->patterns[offset], p->pat, p->len); - } else { - memcpy(&ctx->patterns[offset], p->pat, p->len); - } - offset += (p->len + (p->len % B2GC_ALIGN_PATTERNS)); - - h->np_offset = offset - prev_offset; - - SCLogDebug("h->offset %u", offset); - - ctx->pat_x_cnt++; - - } - buck = buck->bucknext; - } - } - } - - /* build the hash containing idx' to the pattern array */ - for (a = 0; a < b2gc_hash_size; a++) { - uint32_t offset = ctx->ha[a]; - uint32_t next_offset = 0; - - if (offset > 0) { - uint32_t b = a + 1; - while (b < b2gc_hash_size) { - if (ctx->ha[b] > 0) { - next_offset = ctx->ha[b]; - break; - } - - b++; - } - } - - while (offset > 0) { - B2gcPatternHdr *h = (B2gcPatternHdr *)&ctx->patterns[offset]; - BUG_ON(h == NULL); - BUG_ON(h->len <= 1); - - uint8_t *pattern = (uint8_t *)&ctx->patterns[offset + sizeof(B2gcPatternHdr)]; - BUG_ON(pattern == NULL); - //printf("hash %u (offset %u, h %u) sort_hash: ", a, offset, ctx->ha[a]);prt(pattern,h->len);printf("\n"); - - uint16_t hash = a; - - SCLogDebug("hash %u, offset %u", hash, offset); - - if (ctx->bloom[hash] == NULL) { - ctx->bloom[hash] = BloomFilterInit(b2gc_bloom_size, 2, B2gcBloomHash); - SCLogDebug("bloom created for hash %u", hash); - BUG_ON(ctx->bloom[hash] == NULL); - mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[hash]); - mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[hash]); - } - - if (ctx->pminlen[hash] > B2GC_PMINLEN_MAX) - ctx->pminlen[hash] = B2GC_PMINLEN_MAX; - - BloomFilterAdd(ctx->bloom[hash], pattern, ctx->pminlen[hash]); - - offset += h->np_offset; - - /* last item in the pattern storage is "final" too */ - if (offset == size) { - SCLogDebug("final pattern in the array"); - h->flags |= B2GC_FLAG_FINAL; - break; - } - - /* next_offset points to next hash */ - if (next_offset > 0 && offset == next_offset) { - SCLogDebug("last pattern for this hash"); - h->flags |= B2GC_FLAG_FINAL; - break; - } - } - } - - /* skip the first byte of the buffer */ - uint16_t offset1 = 1; - - for (a = 0; a < b2gc_sort_hash1->array_size; a++) { - buck = b2gc_sort_hash1->array[a]; - if (buck != NULL) { - while (buck != NULL) { - if (buck->data != NULL) { - B2gcPattern *p = (B2gcPattern *) (buck->data); - BUG_ON(p == NULL); - BUG_ON(p->len != 1); - - B2gcPattern1 *h = (B2gcPattern1 *)&ctx->patterns1[offset1]; - h->id = p->id; - h->pat = p->pat[0]; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - h->flags |= B2GC_FLAG_NOCASE; - } - - offset1 += (sizeof(B2gcPattern1)); - - ctx->pat_1_cnt++; - } - buck = buck->bucknext; - } - } - } - - /* build the hash containing idx' to the pattern array */ - offset1 = 1; - - B2gcPattern1 *ph1 = NULL; - uint8_t prevhash1 = 0; - while (offset1 < size1) { - B2gcPattern1 *h = (B2gcPattern1 *)&ctx->patterns1[offset1]; - - if (ctx->ha1[u8_tolower(h->pat)] == 0) - ctx->ha1[u8_tolower(h->pat)] = offset1; - - /* check the prev pattern for setting the final flag */ - if (ph1 != NULL) { - if (h->pat != prevhash1) { - SCLogDebug("setting final flag on %p", ph1); - ph1->flags |= B2GC_FLAG_FINAL; - } - } - - prevhash1 = u8_tolower(h->pat); - ph1 = h; - - offset1 += (sizeof(B2gcPattern1)); - - /* last item is "final" too */ - if (offset1 == size1) { - SCLogDebug("final pattern in the array"); - h->flags |= B2GC_FLAG_FINAL; - } - } - - B2gcBuildMatchArray(mpm_ctx, b2gc_sort_hash); - - /* free the hashes only used at init */ - HashListTableFree(b2gc_sort_hash); - b2gc_sort_hash = NULL; - - HashListTableFree(b2gc_sort_hash1); - b2gc_sort_hash1 = NULL; -} - -int B2gcPreparePatterns(MpmCtx *mpm_ctx) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - /* set 'm' to the smallest pattern size */ - ctx->m = mpm_ctx->minlen; - - /* make sure 'm' stays in bounds - m can be max WORD_SIZE - 1 */ - if (ctx->m >= B2GC_WORD_SIZE) { - ctx->m = B2GC_WORD_SIZE - 1; - } - if (ctx->m < 2) - ctx->m = 2; - - ctx->hash_size = b2gc_hash_size; - - /* alloc the hashes */ - ctx->ha = SCMalloc(b2gc_hash_size * sizeof(uint32_t)); - BUG_ON(ctx->ha == NULL); - memset(ctx->ha, 0x00, b2gc_hash_size * sizeof(uint32_t)); - - ctx->ha1 = SCMalloc(256 * sizeof(uint16_t)); - BUG_ON(ctx->ha1 == NULL); - memset(ctx->ha1, 0x00, 256 * sizeof(uint16_t)); - - /* alloc the bloom array */ - ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); - if (ctx->bloom == NULL) - exit(EXIT_FAILURE); - memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); - - /* alloc the pminlen array */ - ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); - if (ctx->pminlen == NULL) - exit(EXIT_FAILURE); - memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); - - B2gcPrepareHash(mpm_ctx); - - SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); - if (ctx->pat_1_cnt) { - ctx->Search = B2gcSearch1; - - ctx->MBSearch = b2g_func; - } - - return 0; -} - -void B2gcPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ -#ifdef B2GC_COUNTERS - B2gcThreadCtx *tctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; - - printf("B2gc Thread Search stats (tctx %p)\n", tctx); - printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); - printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); - printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); - printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); - printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); - printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); - printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); - printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); - printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); -#endif /* B2GC_COUNTERS */ -} - -/** - * \brief Function to get the user defined values for b2g algorithm from the - * config file 'suricata.yaml' - */ -static void B2gcGetConfig() -{ - ConfNode *b2g_conf; - const char *hash_val = NULL; - const char *bloom_val = NULL; - const char *algo = NULL; - - /* init defaults */ - b2gc_hash_size = HASHSIZE_LOW; - b2gc_hash_shift = B2GC_HASHSHIFT_LOW; - b2gc_bloom_size = BLOOMSIZE_MEDIUM; - b2g_func = B2GC_SEARCHFUNC; - - ConfNode *pm = ConfGetNode("pattern-matcher"); - - if (pm != NULL) { - - TAILQ_FOREACH(b2g_conf, &pm->head, next) { - if (strncmp(b2g_conf->val, "b2gc", 4) == 0) { - - algo = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "algo"); - hash_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "hash_size"); - bloom_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "bf_size"); - - if (algo != NULL) { - if (strcmp(algo, "B2gcSearch") == 0) { - b2g_func = B2gcSearch; - } else if (strcmp(algo, "B2gcSearchBNDMq") == 0) { - b2g_func = B2gcSearchBNDMq; - } - } - - if (hash_val != NULL) { - b2gc_hash_size = MpmGetHashSize(hash_val); - switch (b2gc_hash_size) { - case HASHSIZE_LOWEST: - b2gc_hash_shift = B2GC_HASHSHIFT_LOWEST; - break; - case HASHSIZE_LOW: - b2gc_hash_shift = B2GC_HASHSHIFT_LOW; - break; - case HASHSIZE_MEDIUM: - b2gc_hash_shift = B2GC_HASHSHIFT_MEDIUM; - break; - case HASHSIZE_HIGH: - b2gc_hash_shift = B2GC_HASHSHIFT_HIGH; - break; - case HASHSIZE_HIGHER: - b2gc_hash_shift = B2GC_HASHSHIFT_HIGHER; - break; - case HASHSIZE_MAX: - b2gc_hash_shift = B2GC_HASHSHIFT_MAX; - break; - } - } - if (bloom_val != NULL) - b2gc_bloom_size = MpmGetBloomSize(bloom_val); - - SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", - b2gc_hash_size, b2gc_bloom_size); - } - } - } -} - -void B2gcInitCtx (MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); - - if (mpm_ctx->ctx != NULL) - return; - - //BUG_ON(mpm_ctx->ctx != NULL); - - mpm_ctx->ctx = SCMalloc(sizeof(B2gcCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_ctx->ctx, 0, sizeof(B2gcCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gcCtx); - - /* Initialize the defaults value from the config file. The given check make - sure that we query config file only once for config values */ - if (b2gc_hash_size == 0) - B2gcGetConfig(); - - /* initialize the hash we use to speed up pattern insertions */ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - ctx->b2gc_init_hash = HashListTableInit(4096, B2gcHashPatternInitHash, B2gcHashPatternCompare, NULL); - if (ctx->b2gc_init_hash == NULL) { - exit(EXIT_FAILURE); - } - - /* init defaults search functions */ - ctx->Search = b2g_func; - - SCReturn; -} - -void B2gcDestroyCtx(MpmCtx *mpm_ctx) -{ - - SCLogDebug("mpm_ctx %p", mpm_ctx); - - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->b2gc_init_hash != NULL) { - HashListTableFree(ctx->b2gc_init_hash); - } - - if (ctx->B2GC != NULL) { - SCFree(ctx->B2GC); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2GC_TYPE) * ctx->hash_size); - } - - if (ctx->ha != NULL) { - SCFree(ctx->ha); - } - - if (ctx->ha1 != NULL) { - SCFree(ctx->ha1); - } - - if (ctx->patterns != NULL) { - SCFree(ctx->patterns); - } - - if (ctx->patterns1 != NULL) { - SCFree(ctx->patterns1); - } - - if (ctx->bloom) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); - - BloomFilterFree(ctx->bloom[h]); - } - - SCFree(ctx->bloom); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); - } - - if (ctx->pminlen) { - SCFree(ctx->pminlen); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gcCtx); -} - -void B2gcThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - if (sizeof(B2gcThreadCtx) > 0) { /* size can be null when optimized */ - mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gcThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_thread_ctx->ctx, 0, sizeof(B2gcThreadCtx)); - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(B2gcThreadCtx); - } -} - -void B2gcThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - B2gcThreadCtx *ctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; - - B2gcPrintSearchStats(mpm_thread_ctx); - - if (ctx != NULL) { /* can be NULL if B2gcThreadCtx is optimized to 0 */ - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(B2gcThreadCtx); - SCFree(mpm_thread_ctx->ctx); - } -} - -uint32_t B2gcSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; -} - -uint32_t B2gcSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; -#ifdef B2GC_COUNTERS - B2gcThreadCtx *tctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = ctx->m - B2GC_Q + 1, matches = 0; - B2GC_TYPE d; - - //printf("\n"); - //PrintRawDataFp(stdout, buf, buflen); - - SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32, - buflen, ctx->m, pos); - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (uint32_t)(buflen - B2GC_Q + 1)) { - //uint16_t h = B2GC_HASH16(u8_tolower(buf[pos - 1]),u8_tolower(buf[pos])); - uint16_t h = B2GC_HASH16(buf[pos - 1], buf[pos]); - d = ctx->B2GC[h]; - - if (d != 0) { - COUNT(tctx->stat_d0++); - uint32_t j = pos; - uint32_t first = pos - (ctx->m - B2GC_Q + 1); - - do { - j = j - 1; - - if (d >= (uint32_t)(1 << (ctx->m - 1))) { - if (j > first) - pos = j; - else { - /* get our patterns from the hash */ - h = B2GC_HASH16(buf[j + ctx->m - 2], buf[j + ctx->m - 1]); - if (ctx->pminlen[h] > 0 && (buflen - j) >= ctx->pminlen[h] && - BloomFilterTest(ctx->bloom[h], buf+pos-1, ctx->pminlen[h]) == 1) - { - uint32_t offset = ctx->ha[h]; - SCLogDebug("offset %u, hash %u", offset, h); - do { - B2gcPatternHdr *hdr = (B2gcPatternHdr *)&ctx->patterns[offset]; - //BUG_ON(hdr->len <= 1); - offset += hdr->np_offset; - SCLogDebug("next offset %u", offset); - - if (hdr->len <= (buflen - j)) { - if (hdr->flags & B2GC_FLAG_NOCASE) { - uint8_t *pattern = (uint8_t *)hdr + sizeof(B2gcPatternHdr); - //uint8_t *pattern = (uint8_t *)hdr + hdr->nc_offset; - SCLogDebug("nocase compare"); -#ifdef PRINTMATCH - prt(pattern, hdr->len);printf("\n"); - prt(buf+pos-1, hdr->len);printf("\n"); -#endif - if (SCMemcmpLowercase(pattern, buf+pos-1, hdr->len) == 0) { - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } - } else { - uint8_t *pattern = (uint8_t *)hdr + sizeof(B2gcPatternHdr); - SCLogDebug("case sensitive compare"); -#ifdef PRINTMATCH - prt(pattern, hdr->len);printf("\n"); - prt(buf+pos-1, hdr->len);printf("\n"); -#endif - if (SCMemcmp(pattern, buf+pos-1, hdr->len) == 0) { - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } - } - } - - if (hdr->flags & B2GC_FLAG_FINAL) { - SCLogDebug("final flag set, done matching"); - break; - } - } while(1); - } - } - } - - if (j == 0) { - break; - } - - h = B2GC_HASH16(buf[j - 1], buf[j]); - d = (d << 1) & ctx->B2GC[h]; - } while (d != 0); - } - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (ctx->m - B2GC_Q + 1)); - pos = pos + ctx->m - B2GC_Q + 1; - - SCLogDebug("pos %"PRIu32"", pos); - } - - SCLogDebug("matches %"PRIu32"", matches); - return matches; -} - -uint32_t B2gcSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; -#ifdef B2GC_COUNTERS - B2gcThreadCtx *tctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = 0, matches = 0; - B2GC_TYPE d; - uint32_t j; - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (buflen - ctx->m)) { - j = ctx->m - 1; - d = ~0; - - do { - uint16_t h = B2GC_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); - d = ((d << 1) & ctx->B2GC[h]); - j = j - 1; - } while (d != 0 && j != 0); - - /* (partial) match, move on to verification */ - if (d != 0) { - COUNT(tctx->stat_d0++); - //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); - -#if 0 - /* get our patterns from the hash */ - uint16_t h = B2GC_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); - B2gcPattern *hi = ctx->hash[h], *thi; - for (thi = hi; thi != NULL; thi = thi->next) { - COUNT(tctx->stat_d0_hashloop++); - //B2gcPattern *p = ctx->parray[thi->idx]; - - if (buflen - pos < thi->len) - continue; - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - - if (memcmp_lowercase(thi->ci, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (memcmp(thi->cs, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } -skip_loop: - //pos = pos + ctx->s0; - pos = pos + 1; -#endif - } else { - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (j + 1)); - - pos = pos + j + 1; - } - } - - //printf("Total matches %" PRIu32 "\n", matches); - return matches; -} - -uint32_t B2gcSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - SCEnter(); - - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - - if (buflen == 0) - SCReturnUInt(0); - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - while (buf <= bufend) { - uint8_t h = u8_tolower(*buf); - uint16_t offset = ctx->ha1[h]; - SCLogDebug("offset %u, h %02X, buf %02X", offset, h, *buf); - - if (offset > 0) { - do { - B2gcPattern1 *hdr = (B2gcPattern1 *)&ctx->patterns1[offset]; - offset += (sizeof(B2gcPattern1)); - - SCLogDebug("hdr flags %02x, id %u, pat %02X", hdr->flags, hdr->id, hdr->pat); - - if (hdr->flags & B2GC_FLAG_NOCASE) { - SCLogDebug("nocase compare, %02X", *buf); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } else { - SCLogDebug("case sensitive compare, %02X", *buf); - - if (*buf == hdr->pat) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } - } - - if (hdr->flags & B2GC_FLAG_FINAL) - break; - } while(1); - } - buf += 1; - } - - //printf("B2gcSearch1: after 1byte cnt %" PRIu32 "\n", cnt); - if (ctx->pat_x_cnt) { - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - } - SCReturnUInt(cnt); -} - -/* - * TESTS - */ - -#ifdef UNITTESTS -static int B2gcTestMacro01 (void) -{ - int result = 1; - - B2gcPatternHdr a; - B2gcPatternHdr *b = &a; - - memset(&a, 0xff, sizeof(a)); - - printf("ID %u\n", B2GC_GET_ID(b)); - printf("FLAGS %u\n", B2GC_GET_FLAGS(b)); - printf("LEN %u\n", B2GC_GET_LEN(b)); - - return result; -} - -static int B2gcTestInit01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->m == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->m); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -#if 0 -static int B2gcTestS0Init01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->s0); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestS0Init02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestS0Init03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", ctx->s0); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestS0Init04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestS0Init05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", ctx->s0); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} -#endif - -static int B2gcTestSearch01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -/* test patterns longer than 'm'. M is 4 here. */ -static int B2gcTestSearch04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -/* case insensitive test patterns longer than 'm'. M is 4 here. */ -static int B2gcTestSearch05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch05a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abCD", 4, 0, 0, 3, 0, 0); /* no match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 4, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 5, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 5) - result = 1; - else - printf("5 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch05b (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 2, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 3, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 4, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abXD", 4, 0, 0, 5, 0, 0); /* 0 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 5) - result = 1; - else - printf("5 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch05c (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch05d (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 1, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ABCD", 4); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch06a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch07 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt; - int i; - for (i = 0; i<100000;i++) - cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch07a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 30) - result = 1; - else - printf("30 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch08 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch09 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch10 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch11 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch13 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch17 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch18 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch19 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 0, 0, 0); /* 1 */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch20 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32, 0, 0, 0, 0, 0); /* 1 */ - //MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32, 0, 0, 0, 0, 0); /* 1 */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - //uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32); - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch21 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); /* 1 */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} -#endif /* UNITTESTS */ - -#if 0 -static int B2gcTestSearchXX (void) -{ - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - FILE *fp = fopen("/usr/share/dict/words", "r"); - if (fp == NULL) - exit(1); - - char *word; - char line[128]; - int w = 0; - int w_max = 4000; - - while((word = fgets(line, sizeof(line), fp)) != NULL) { - word[strlen(word) - 1] = '\0'; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)word, strlen(word), 0, 0, (uint32_t)w, 0, 0); - - w++; - - if (w_max == w) - break; - } - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - char *text = "Yes this is a text, it is not very long. But, it is still sufficient for testing our search! " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "Bjdhfahflkahsf;phf[hfihasfkhsfkjhalhflkafljhfkhakhfkahfkahfkjhdkffkjhafkhafkjakjfhkjahf;aj;jh"; - uint32_t len = strlen(text) - 1; - - int i; - uint32_t cnt; - for (i = 0; i < 100; i++) { - cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); - } - printf("cnt %u ", cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - fclose(fp); - - return 1; -} -#endif - -void B2gcRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("B2gcTestMacro01", B2gcTestMacro01, 1); - UtRegisterTest("B2gcTestInit01", B2gcTestInit01, 1); -/* - UtRegisterTest("B2gcTestS0Init01", B2gcTestS0Init01, 1); - UtRegisterTest("B2gcTestS0Init02", B2gcTestS0Init02, 1); - UtRegisterTest("B2gcTestS0Init03", B2gcTestS0Init03, 1); - UtRegisterTest("B2gcTestS0Init04", B2gcTestS0Init04, 1); - UtRegisterTest("B2gcTestS0Init05", B2gcTestS0Init05, 1); -*/ - UtRegisterTest("B2gcTestSearch01", B2gcTestSearch01, 1); - UtRegisterTest("B2gcTestSearch02", B2gcTestSearch02, 1); - UtRegisterTest("B2gcTestSearch03", B2gcTestSearch03, 1); - UtRegisterTest("B2gcTestSearch04", B2gcTestSearch04, 1); - UtRegisterTest("B2gcTestSearch05", B2gcTestSearch05, 1); - UtRegisterTest("B2gcTestSearch05a", B2gcTestSearch05a, 1); - UtRegisterTest("B2gcTestSearch05b", B2gcTestSearch05b, 1); - UtRegisterTest("B2gcTestSearch05c", B2gcTestSearch05c, 1); - UtRegisterTest("B2gcTestSearch05d", B2gcTestSearch05d, 1); - UtRegisterTest("B2gcTestSearch06", B2gcTestSearch06, 1); - UtRegisterTest("B2gcTestSearch06a", B2gcTestSearch06a, 1); - UtRegisterTest("B2gcTestSearch07", B2gcTestSearch07, 1); - UtRegisterTest("B2gcTestSearch07a", B2gcTestSearch07a, 1); - UtRegisterTest("B2gcTestSearch08", B2gcTestSearch08, 1); - UtRegisterTest("B2gcTestSearch09", B2gcTestSearch09, 1); - UtRegisterTest("B2gcTestSearch10", B2gcTestSearch10, 1); - UtRegisterTest("B2gcTestSearch11", B2gcTestSearch11, 1); - UtRegisterTest("B2gcTestSearch12", B2gcTestSearch12, 1); - UtRegisterTest("B2gcTestSearch13", B2gcTestSearch13, 1); - UtRegisterTest("B2gcTestSearch14", B2gcTestSearch14, 1); - UtRegisterTest("B2gcTestSearch15", B2gcTestSearch15, 1); - UtRegisterTest("B2gcTestSearch16", B2gcTestSearch16, 1); - UtRegisterTest("B2gcTestSearch17", B2gcTestSearch17, 1); - UtRegisterTest("B2gcTestSearch18", B2gcTestSearch18, 1); - UtRegisterTest("B2gcTestSearch19", B2gcTestSearch19, 1); - UtRegisterTest("B2gcTestSearch20", B2gcTestSearch20, 1); - UtRegisterTest("B2gcTestSearch21", B2gcTestSearch21, 1); -/* - UtRegisterTest("B2gcTestSearchXX", B2gcTestSearchXX, 1); -*/ -#endif /* UNITTESTS */ -} - diff --git a/src/util-mpm-b2gc.h b/src/util-mpm-b2gc.h deleted file mode 100644 index f72e389b74b5..000000000000 --- a/src/util-mpm-b2gc.h +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright (C) 2007-2010 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 - */ - -#ifndef __UTIL_MPM_B2GC_H__ -#define __UTIL_MPM_B2GC_H__ - -#include "util-mpm.h" -#include "util-bloomfilter.h" - -#define B2GC_HASHSHIFT_MAX 8 -#define B2GC_HASHSHIFT_HIGHER 7 -#define B2GC_HASHSHIFT_HIGH 6 -#define B2GC_HASHSHIFT_MEDIUM 5 -#define B2GC_HASHSHIFT_LOW 4 -#define B2GC_HASHSHIFT_LOWEST 3 - -//#define B2GC_HASHSHIFT 8 -//#define B2GC_HASHSHIFT 7 -//#define B2GC_HASHSHIFT 6 -//#define B2GC_HASHSHIFT 5 -#define B2GC_HASHSHIFT 4 -//#define B2GC_HASHSHIFT 3 - -//#define B2GC_TYPE uint64_t -#define B2GC_TYPE uint32_t -//#define B2GC_TYPE uint16_t -//#define B2GC_TYPE uint8_t -//#define B2GC_WORD_SIZE 64 -#define B2GC_WORD_SIZE 32 -//#define B2GC_WORD_SIZE 16 -//#define B2GC_WORD_SIZE 8 - -#define B2GC_Q 2 - -#define B2GC_SEARCHFUNC B2gcSearchBNDMq -//#define B2GC_SEARCHFUNC B2gcSearch - -//#define B2GC_SEARCH2 -//#define B2GC_COUNTERS - -#define B2GC_FLAG_NOCASE 0x01 -#define B2GC_FLAG_FINAL 0x02 -#define B2GC_FLAG_RES1 0x04 -#define B2GC_FLAG_RES2 0x08 - -/* Bits - * flg len id pat - * |xxxx|xxxx xxxx xx|xx xxxx xxxx xxxx xxxx|xx..xx| - */ - -typedef struct B2gcPatternHdr_ { - uint32_t np_offset; /* offset of the next pattern */ - uint8_t len; - uint8_t flags; - PatIntId id; -} B2gcPatternHdr; - -#define B2GC_GET_FLAGS(hdr) ((hdr)->flags) -#define B2GC_GET_LEN(hdr) ((hdr)->len) -#define B2GC_GET_ID(hdr) ((hdr)->id) - -/* 1 byte pattern structure fitting in a double word. - * flg id pad pat/char - * |xxxx|xxxx xxxx xxxx xxxx xx|xx|xxxx xxxx| - */ - -typedef struct B2gcPattern1_ { - uint8_t flags; - uint8_t pat; - PatIntId id; -} B2gcPattern1; - -#define B2GC1_GET_FLAGS(hdr) ((hdr)->flags) -#define B2GC1_GET_LEN(hdr) 1 -#define B2GC1_GET_ID(hdr) ((hdr)->id) -#define B2GC1_GET_CHAR(hdr) ((hdr)->pat) - -typedef struct B2gcPattern_ { - uint16_t len; - uint8_t flags; - uint8_t pad0; - PatIntId id; - uint8_t *pat; -} B2gcPattern; - -typedef struct B2gcCtx_ { - /* we store our own multi byte search func ptr here for B2gcSearch1 */ - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - /* hash for looking up the idx in the pattern array */ - uint16_t *ha1; - uint8_t *patterns1; - uint32_t pat_x_cnt; - uint32_t pat_1_cnt; - /* we store our own multi byte search func ptr here for B2gcSearch1 */ - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - B2GC_TYPE m; - uint32_t hash_size; - - B2GC_TYPE *B2GC; - - uint8_t *pminlen; /* array containing the minimal length */ - BloomFilter **bloom; - - uint32_t *ha; - /* patterns in the format |hdr|pattern|hdr|pattern|... */ - uint8_t *patterns; - - HashListTable *b2gc_init_hash; -} B2gcCtx; - -typedef struct B2gcThreadCtx_ { -#ifdef B2GC_COUNTERS - uint32_t stat_pminlen_calls; - uint32_t stat_pminlen_total; - uint32_t stat_bloom_calls; - uint32_t stat_bloom_hits; - uint32_t stat_calls; - uint32_t stat_m_total; - uint32_t stat_d0; - uint32_t stat_d0_hashloop; - uint32_t stat_loop_match; - uint32_t stat_loop_no_match; - uint32_t stat_num_shift; - uint32_t stat_total_shift; -#endif /* B2GC_COUNTERS */ -} B2gcThreadCtx; - -void MpmB2gcRegister(void); - - -#endif - diff --git a/src/util-mpm-b2gm.c b/src/util-mpm-b2gm.c deleted file mode 100644 index 2a0dfb14a665..000000000000 --- a/src/util-mpm-b2gm.c +++ /dev/null @@ -1,2788 +0,0 @@ -/* Copyright (C) 2007-2010 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 - * - * Implementation of the SBNDMq pattern matching algorithm. - * - * Future work: - * - parray contains 1 byte patterns while they are not used - * - 1 byte search hashes on tolower(*buf) reducing hash value - * - */ - -//#define PRINTMATCH - -#include "suricata-common.h" -#include "suricata.h" -#include "detect.h" -#include "util-bloomfilter.h" -#include "util-mpm-b2gm.h" -#include "util-print.h" -#include "util-hashlist.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-optimize.h" -#include "conf.h" - -#define INIT_HASH_SIZE 65536 - -#ifdef B2GM_COUNTERS -#define COUNT(counter) \ - (counter) -#else -#define COUNT(counter) -#endif /* B2GM_COUNTERS */ - -static uint32_t b2gm_hash_size = 0; -static uint32_t b2gm_bloom_size = 0; -static uint8_t b2gm_hash_shift = 0; -static void *b2g_func; - -#define B2GM_HASH16(a,b) (((a) << b2gm_hash_shift) | (b)) - -void B2gmInitCtx (MpmCtx *); -void B2gmThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); -void B2gmDestroyCtx(MpmCtx *); -void B2gmThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); -int B2gmAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gmAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gmPreparePatterns(MpmCtx *mpm_ctx); -uint32_t B2gmSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#ifdef B2GM_SEARCH2 -uint32_t B2gmSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#endif -uint32_t B2gmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gmSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); -void B2gmPrintInfo(MpmCtx *mpm_ctx); -void B2gmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void B2gmRegisterTests(void); - -void MpmB2gmRegister (void) -{ - mpm_table[MPM_B2GM].name = "b2gm"; - mpm_table[MPM_B2GM].max_pattern_length = B2GM_WORD_SIZE; - - mpm_table[MPM_B2GM].InitCtx = B2gmInitCtx; - mpm_table[MPM_B2GM].InitThreadCtx = B2gmThreadInitCtx; - mpm_table[MPM_B2GM].DestroyCtx = B2gmDestroyCtx; - mpm_table[MPM_B2GM].DestroyThreadCtx = B2gmThreadDestroyCtx; - mpm_table[MPM_B2GM].AddPattern = B2gmAddPatternCS; - mpm_table[MPM_B2GM].AddPatternNocase = B2gmAddPatternCI; - mpm_table[MPM_B2GM].Prepare = B2gmPreparePatterns; - mpm_table[MPM_B2GM].Search = B2gmSearchWrap; - mpm_table[MPM_B2GM].Cleanup = NULL; - mpm_table[MPM_B2GM].PrintCtx = B2gmPrintInfo; - mpm_table[MPM_B2GM].PrintThreadCtx = B2gmPrintSearchStats; - mpm_table[MPM_B2GM].RegisterUnittests = B2gmRegisterTests; -} - -#ifdef PRINTMATCH -static void prt (uint8_t *buf, uint16_t buflen) -{ - uint16_t i; - - for (i = 0; i < buflen; i++) { - if (isprint(buf[i])) printf("%c", buf[i]); - else printf("\\x%02X", buf[i]); - } - //printf("\n"); -} -#endif - -void B2gmPrintInfo(MpmCtx *mpm_ctx) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - printf("MPM B2gm Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeofs:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" B2gmCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmCtx)); - printf(" B2gmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmPattern)); - printf(" B2gmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Hash size: %" PRIu32 "\n", ctx->hash_size); - printf("\n"); -} - -static inline B2gmPattern *B2gmAllocPattern(MpmCtx *mpm_ctx) -{ - B2gmPattern *p = SCMalloc(sizeof(B2gmPattern)); - if (unlikely(p == NULL)) - return NULL; - memset(p,0,sizeof(B2gmPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gmPattern); - return p; -} - -static inline B2gmPattern * -B2gmAllocHashItem(MpmCtx *mpm_ctx) -{ - B2gmPattern *hi = SCMalloc(sizeof(B2gmPattern)); - if (unlikely(hi == NULL)) - return NULL; - memset(hi,0,sizeof(B2gmPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gmPattern); - return hi; -} - -static void B2gmHashFree(MpmCtx *mpm_ctx, B2gmPattern *hi) -{ - if (hi == NULL) - return; - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gmPattern); - B2gmPattern *t = hi->next; - SCFree(hi); - - B2gmHashFree(mpm_ctx, t); -} - -static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) -{ - uint16_t i; - for (i = 0; i < len; i++) { - d[i] = u8_tolower(s[i]); - } -} - -/* - * INIT HASH START - */ -static inline uint32_t B2gmInitHash(B2gmPattern *p) -{ - uint32_t hash = p->len * p->pat[0]; - if (p->len > 1) - hash += p->pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline uint32_t B2gmInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int B2gmInitHashAdd(B2gmCtx *ctx, B2gmPattern *p) -{ - uint32_t hash = B2gmInitHash(p); - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - B2gmPattern *tt = NULL; - B2gmPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - -static inline int B2gmCmpPattern(B2gmPattern *p, uint8_t *pat, uint16_t patlen, char flags); - -static inline B2gmPattern *B2gmInitHashLookup(B2gmCtx *ctx, uint8_t *pat, uint16_t patlen, char flags) -{ - uint32_t hash = B2gmInitHashRaw(pat,patlen); - - if (ctx->init_hash[hash] == NULL) { - return NULL; - } - - B2gmPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (B2gmCmpPattern(t,pat,patlen,flags) == 1) - return t; - } - - return NULL; -} - -static inline int B2gmCmpPattern(B2gmPattern *p, uint8_t *pat, uint16_t patlen, char flags) -{ - if (p->len != patlen) - return 0; - - if (p->flags != flags) - return 0; - - if (memcmp(p->pat, pat, patlen) != 0) - return 0; - - return 1; -} - -/* - * INIT HASH END - */ - -void B2gmFreePattern(MpmCtx *mpm_ctx, B2gmPattern *p) -{ - if (p != NULL) { - if (p->pat != NULL) { - SCFree(p->pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gmPattern); - } -} - -/** \internal - * \brief add a pattern to the mpm/b2g context - * - * \param pat ptr to the pattern - * \param patlen length of the pattern - * \param pid pattern id - * \param sid signature id (internal id) - * \param flags pattern MPM_PATTERN_* flags - */ -static int B2gmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); - - if (patlen == 0) - return 0; - - /* get a memory piece */ - B2gmPattern *p = B2gmInitHashLookup(ctx, pat, patlen, flags); - if (p == NULL) { - SCLogDebug("allocing new pattern"); - - B2gmPattern *p = B2gmAllocPattern(mpm_ctx); - if (p == NULL) - return -1; - - p->len = patlen; - p->flags = flags; - p->id = pid; - - /* setup the case insensitive part of the pattern */ - p->pat = SCMalloc(patlen); - if (p->pat == NULL) { - B2gmFreePattern(mpm_ctx, p); - return -1; - } - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - memcpy_tolower(p->pat, pat, patlen); - } else { - memcpy(p->pat, pat, patlen); - } - - /* put in the pattern hash */ - B2gmInitHashAdd(ctx, p); - - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - - mpm_ctx->pattern_cnt++; - - if (patlen == 1) { - ctx->pat_1_cnt++; - } else { - ctx->pat_x_cnt++; - } - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) - mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - return 0; -} - -int B2gmAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return B2gmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -int B2gmAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - return B2gmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -static uint32_t B2gmHashPatternSortHash1(HashListTable *ht, void *pattern, uint16_t len) -{ - BUG_ON(len != sizeof(B2gmPattern)); - BUG_ON(pattern == NULL); - - B2gmPattern *p = (B2gmPattern *)pattern; - return (uint32_t)p->pat[0]; -} - -static char B2gmHashPatternCompare(void *pattern1, uint16_t len1, - void *pattern2, uint16_t len2) -{ - BUG_ON(len1 != sizeof(B2gmPattern)); - BUG_ON(len2 != sizeof(B2gmPattern)); - - B2gmPattern *p1 = (B2gmPattern *)pattern1; - B2gmPattern *p2 = (B2gmPattern *)pattern2; - - if (p1->id != p2->id) { - return 0; - } - - return 1; -} - -static inline uint32_t B2gmBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint16_t i; - uint32_t hash = (uint32_t)u8_tolower(*d); - - for (i = 1; i < datalen; i++) { - d++; - hash += (u8_tolower(*d)) ^ i; - } - hash <<= (iter+1); - - hash %= hash_size; - return hash; -} - -static void B2gmPrepareHashAddPattern(MpmCtx *mpm_ctx, uint16_t idx, uint32_t i) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - if (ctx->lookup[idx].hash == NULL) { - B2gmPattern *hi = B2gmAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->pat = ctx->parray[i]->pat; - - ctx->lookup[idx].pminlen = ctx->parray[i]->len; - - ctx->lookup[idx].hash = hi; - } else { - B2gmPattern *hi = B2gmAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->pat = ctx->parray[i]->pat; - - if (ctx->parray[i]->len < ctx->lookup[idx].pminlen) - ctx->lookup[idx].pminlen = ctx->parray[i]->len; - - /* Append this HashItem to the list */ - B2gmPattern *thi = ctx->lookup[idx].hash; - while (thi->next) - thi = thi->next; - thi->next = hi; - } - return; -error: - return; -} - -static void B2gmPrepareHash(MpmCtx *mpm_ctx) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - uint16_t i; - uint16_t size1 = 1; - - HashListTable *b2gm_sort_hash1 = HashListTableInit(256, B2gmHashPatternSortHash1, B2gmHashPatternCompare, NULL); - if (b2gm_sort_hash1 == NULL) { - exit(EXIT_FAILURE); - } - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) - { - SCLogDebug("ctx->parray[i]->len %u", ctx->parray[i]->len); - - if(ctx->parray[i]->len == 1) { - HashListTableAdd(b2gm_sort_hash1, (void *)ctx->parray[i], sizeof(B2gmPattern)); - size1 += (sizeof(B2gmPattern1)); - } else { - if (ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE) { - /* u, u */ - uint16_t uuidx = B2GM_HASH16(toupper(ctx->parray[i]->pat[ctx->m - 2]), toupper(ctx->parray[i]->pat[ctx->m - 1])); - B2gmPrepareHashAddPattern(mpm_ctx, uuidx, i); - - /* l, l */ - uint16_t llidx = B2GM_HASH16(tolower(ctx->parray[i]->pat[ctx->m - 2]), tolower(ctx->parray[i]->pat[ctx->m - 1])); - if (llidx != uuidx) { - B2gmPrepareHashAddPattern(mpm_ctx, llidx, i); - } - /* u, l */ - uint16_t ulidx = B2GM_HASH16(toupper(ctx->parray[i]->pat[ctx->m - 2]), tolower(ctx->parray[i]->pat[ctx->m - 1])); - if (ulidx != llidx && ulidx != uuidx) { - B2gmPrepareHashAddPattern(mpm_ctx, ulidx, i); - } - /* l, u */ - uint16_t luidx = B2GM_HASH16(tolower(ctx->parray[i]->pat[ctx->m - 2]), toupper(ctx->parray[i]->pat[ctx->m - 1])); - if (luidx != ulidx && luidx != llidx && luidx != uuidx) { - B2gmPrepareHashAddPattern(mpm_ctx, luidx, i); - } - } else { - uint16_t uuidx = B2GM_HASH16(ctx->parray[i]->pat[ctx->m - 2], ctx->parray[i]->pat[ctx->m - 1]); - B2gmPrepareHashAddPattern(mpm_ctx, uuidx, i); - } - } - } - - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - B2gmPattern *hi = ctx->lookup[h].hash; - if (hi == NULL) - continue; - - ctx->lookup[h].bloom = BloomFilterInit(b2gm_bloom_size, 2, B2gmBloomHash); - if (ctx->lookup[h].bloom == NULL) - continue; - - mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->lookup[h].bloom); - mpm_ctx->memory_size += BloomFilterMemorySize(ctx->lookup[h].bloom); - - if (ctx->lookup[h].pminlen > 8) - ctx->lookup[h].pminlenb = 8; - else - ctx->lookup[h].pminlenb = (uint8_t)ctx->lookup[h].pminlen; - - B2gmPattern *thi = hi; - do { - SCLogDebug("adding \"%c%c\" to the bloom", thi->pat[0], thi->pat[1]); - BloomFilterAdd(ctx->lookup[h].bloom, thi->pat, ctx->lookup[h].pminlenb); - thi = thi->next; - } while (thi != NULL); - } - - /* build the 1 byte match array */ - SCLogDebug("size1 %u", size1); - ctx->patterns1 = SCMalloc(size1); - BUG_ON(ctx->patterns1 == NULL); - memset(ctx->patterns1, 0x00, size1); - - /* skip the first byte of the buffer */ - uint16_t offset1 = 1; - - uint32_t a; - for (a = 0; a < b2gm_sort_hash1->array_size; a++) { - HashListTableBucket *buck = b2gm_sort_hash1->array[a]; - if (buck != NULL) { - while (buck != NULL) { - if (buck->data != NULL) { - B2gmPattern *p = (B2gmPattern *) (buck->data); - BUG_ON(p == NULL); - BUG_ON(p->len != 1); - - B2gmPattern1 *h = (B2gmPattern1 *)&ctx->patterns1[offset1]; - h->id = p->id; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - h->flags |= B2GM_FLAG_NOCASE; - h->pat = p->pat[0]; - } else { - h->pat = p->pat[0]; - } - - offset1 += (sizeof(B2gmPattern1)); - } - buck = buck->bucknext; - } - } - } - - /* build the hash containing idx' to the pattern array */ - offset1 = 1; - - B2gmPattern1 *ph1 = NULL; - uint8_t prevhash1 = 0; - while (offset1 < size1) { - B2gmPattern1 *h = (B2gmPattern1 *)&ctx->patterns1[offset1]; - - if (ctx->ha1[u8_tolower(h->pat)] == 0) - ctx->ha1[u8_tolower(h->pat)] = offset1; - - /* check the prev pattern for setting the final flag */ - if (ph1 != NULL) { - if (u8_tolower(h->pat) != prevhash1) { - SCLogDebug("setting final flag on %p", ph1); - ph1->flags |= B2GM_FLAG_FINAL; - } - } - - prevhash1 = u8_tolower(h->pat); - ph1 = h; - - offset1 += (sizeof(B2gmPattern1)); - - /* last item is "final" too */ - if (offset1 == size1) { - SCLogDebug("final pattern in the array"); - h->flags |= B2GM_FLAG_FINAL; - } - - SCLogDebug("offset %u, size %u", offset1, size1); - } - - HashListTableFree(b2gm_sort_hash1); - b2gm_sort_hash1 = NULL; - return; -} - -static void B2gmAddToMatchArray(MpmCtx *mpm_ctx, B2gmPattern *p, int j) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* u, u */ - uint16_t uuidx = B2GM_HASH16(toupper(p->pat[j]), toupper(p->pat[j + 1])); - ctx->B2GM[uuidx] = ctx->B2GM[uuidx] | (1 << (ctx->m - j)); - - /* l, l */ - uint16_t llidx = B2GM_HASH16(u8_tolower(p->pat[j]), u8_tolower(p->pat[j + 1])); - if (llidx != uuidx) { - ctx->B2GM[llidx] = ctx->B2GM[llidx] | (1 << (ctx->m - j)); - } - /* u, l */ - uint16_t ulidx = B2GM_HASH16(toupper(p->pat[j]), u8_tolower(p->pat[j + 1])); - if (ulidx != llidx && ulidx != uuidx) { - ctx->B2GM[ulidx] = ctx->B2GM[ulidx] | (1 << (ctx->m - j)); - } - /* l, u */ - uint16_t luidx = B2GM_HASH16(u8_tolower(p->pat[j]), toupper(p->pat[j + 1])); - if (luidx != ulidx && luidx != llidx && luidx != uuidx) { - ctx->B2GM[luidx] = ctx->B2GM[luidx] | (1 << (ctx->m - j)); - } - - SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); - } -} - -int B2gmBuildMatchArray(MpmCtx *mpm_ctx) -{ - SCEnter(); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - ctx->B2GM = SCMalloc(sizeof(B2GM_TYPE) * ctx->hash_size); - if (ctx->B2GM == NULL) - return -1; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2GM_TYPE) * ctx->hash_size); - - memset(ctx->B2GM,0, b2gm_hash_size * sizeof(B2GM_TYPE)); - - uint32_t j; - uint32_t a; - - /* fill the match array */ - for (j = 0; j <= (ctx->m - B2GM_Q); j++) { - for (a = 0; a < ctx->pat_x_cnt; a++) { - if (ctx->parray[a]->len < ctx->m) - continue; - - uint16_t h; - if (ctx->parray[a]->flags & MPM_PATTERN_FLAG_NOCASE) { - B2gmAddToMatchArray(mpm_ctx, ctx->parray[a], j); - } else { - h = B2GM_HASH16(ctx->parray[a]->pat[j], ctx->parray[a]->pat[j+1]); - ctx->B2GM[h] = ctx->B2GM[h] | (1 << (ctx->m - j)); - SCLogDebug("h %"PRIu16", ctx->B2GM[h] %"PRIu32" (cs)", h, ctx->B2GM[h]); - } - } - } - - //ctx->s0 = 1; - SCReturnInt(0); -} - -int B2gmPreparePatterns(MpmCtx *mpm_ctx) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - /* alloc the lookup array */ - ctx->lookup = SCMalloc(b2gm_hash_size * sizeof(B2gmLookup)); - if (ctx->lookup == NULL) - goto error; - memset(ctx->lookup, 0x00, b2gm_hash_size * sizeof(B2gmLookup)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (b2gm_hash_size * sizeof(B2gmLookup)); - - /* alloc the pattern array */ - ctx->parray = (B2gmPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); - if (ctx->parray == NULL) - goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0; - uint32_t p = 0; - - for (i = 0; i < INIT_HASH_SIZE; i++) { - B2gmPattern *node = ctx->init_hash[i]; - B2gmPattern *nnode = NULL; - - for ( ; node != NULL; ) { - nnode = node->next; - node->next = NULL; - - ctx->parray[p] = node; - p++; - - node = nnode; - } - } - /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* set 'm' to the smallest pattern size */ - ctx->m = mpm_ctx->minlen; - - /* make sure 'm' stays in bounds - m can be max WORD_SIZE - 1 */ - if (ctx->m >= B2GM_WORD_SIZE) { - ctx->m = B2GM_WORD_SIZE - 1; - } - if (ctx->m < 2) - ctx->m = 2; - - ctx->hash_size = b2gm_hash_size; - B2gmPrepareHash(mpm_ctx); - B2gmBuildMatchArray(mpm_ctx); - - SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); - if (ctx->pat_1_cnt) { - ctx->Search = B2gmSearch1; - ctx->MBSearch = b2g_func; - } - - return 0; -error: - return -1; -} - -void B2gmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ -#ifdef B2GM_COUNTERS - B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; - - printf("B2gm Thread Search stats (tctx %p)\n", tctx); - printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); - printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); - printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); - printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); - printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); - printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); - printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); - printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); - printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); - printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); - printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", tctx->stat_bloom_calls ? (float)((float)((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls)*(float)100) : 0, tctx->stat_bloom_hits); - printf("Avg pminlen: %0.2f\n", tctx->stat_pminlen_calls ? (float)((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls) : 0); - printf("Test bug %"PRIu32"\n", tctx->stat_test_buf); - printf("Test bug ok %"PRIu32"\n", tctx->stat_test_buf_ok); - printf("Test bug fail %"PRIu32"\n\n", tctx->stat_test_buf_fail); -#endif /* B2GM_COUNTERS */ -} - -static inline int -memcmp_lowercase(const uint8_t *s1, const uint8_t *s2, const uint16_t n) -{ - size_t i; - - /* check backwards because we already tested the first - * 2 to 4 chars. This way we are more likely to detect - * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { - if (s1[i] != u8_tolower(*(s2+i))) - return 1; - } - - return 0; -} - -/** - * \brief Function to get the user defined values for b2g algorithm from the - * config file 'suricata.yaml' - */ -static void B2gmGetConfig() -{ - ConfNode *b2g_conf; - const char *hash_val = NULL; - const char *bloom_val = NULL; - const char *algo = NULL; - - /* init defaults */ - b2gm_hash_size = HASHSIZE_LOW; - b2gm_hash_shift = B2GM_HASHSHIFT_LOW; - b2gm_bloom_size = BLOOMSIZE_MEDIUM; - b2g_func = B2GM_SEARCHFUNC; - - ConfNode *pm = ConfGetNode("pattern-matcher"); - if (pm != NULL) { - TAILQ_FOREACH(b2g_conf, &pm->head, next) { - if (strcmp(b2g_conf->val, "b2gm") == 0) { - - algo = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "algo"); - hash_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "hash_size"); - bloom_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "bf_size"); - - if (algo != NULL) { - if (strcmp(algo, "B2gmSearch") == 0) { - b2g_func = B2gmSearch; - } else if (strcmp(algo, "B2gmSearchBNDMq") == 0) { - b2g_func = B2gmSearchBNDMq; - } - } - - if (hash_val != NULL) { - b2gm_hash_size = MpmGetHashSize(hash_val); - switch (b2gm_hash_size) { - case HASHSIZE_LOWEST: - b2gm_hash_shift = B2GM_HASHSHIFT_LOWEST; - break; - case HASHSIZE_LOW: - b2gm_hash_shift = B2GM_HASHSHIFT_LOW; - break; - case HASHSIZE_MEDIUM: - b2gm_hash_shift = B2GM_HASHSHIFT_MEDIUM; - break; - case HASHSIZE_HIGH: - b2gm_hash_shift = B2GM_HASHSHIFT_HIGH; - break; - case HASHSIZE_HIGHER: - b2gm_hash_shift = B2GM_HASHSHIFT_HIGHER; - break; - case HASHSIZE_MAX: - b2gm_hash_shift = B2GM_HASHSHIFT_MAX; - break; - } - } - - if (bloom_val != NULL) - b2gm_bloom_size = MpmGetBloomSize(bloom_val); - - SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", - b2gm_hash_size, b2gm_bloom_size); - } - } - } -} - -void B2gmInitCtx (MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); - - BUG_ON(mpm_ctx->ctx != NULL); - - mpm_ctx->ctx = SCMalloc(sizeof(B2gmCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_ctx->ctx, 0, sizeof(B2gmCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gmCtx); - - /* initialize the hash we use to speed up pattern insertions */ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(B2gmPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { - exit(EXIT_FAILURE); - } - - memset(ctx->init_hash, 0, sizeof(B2gmPattern *) * INIT_HASH_SIZE); - - /* Initialize the defaults value from the config file. The given check make - sure that we query config file only once for config values */ - if (b2gm_hash_size == 0) - B2gmGetConfig(); - - ctx->ha1 = SCMalloc(256 * sizeof(uint16_t)); - BUG_ON(ctx->ha1 == NULL); - memset(ctx->ha1, 0x00, 256 * sizeof(uint16_t)); - - /* init defaults search functions */ - ctx->Search = b2g_func; - - SCReturn; -} - -void B2gmDestroyCtx(MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p", mpm_ctx); - - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B2gmPattern *)); - } - - if (ctx->parray != NULL) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - B2gmFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B2gmPattern)); - } - - if (ctx->B2GM != NULL) { - SCFree(ctx->B2GM); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2GM_TYPE) * ctx->hash_size); - } - - if (ctx->lookup != NULL) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->lookup[h].bloom == NULL) - continue; - - B2gmHashFree(mpm_ctx, ctx->lookup[h].hash); - - mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->lookup[h].bloom); - mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->lookup[h].bloom); - - BloomFilterFree(ctx->lookup[h].bloom); - } - - SCFree(ctx->lookup); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2gmLookup) * ctx->hash_size); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gmCtx); -} - -void B2gmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - if (sizeof(B2gmThreadCtx) > 0) { /* size can be null when optimized */ - mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gmThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_thread_ctx->ctx, 0, sizeof(B2gmThreadCtx)); - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(B2gmThreadCtx); - } -} - -void B2gmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - B2gmThreadCtx *ctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; - - B2gmPrintSearchStats(mpm_thread_ctx); - - if (ctx != NULL) { /* can be NULL if B2gmThreadCtx is optimized to 0 */ - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(B2gmThreadCtx); - SCFree(mpm_thread_ctx->ctx); - } -} - -uint32_t B2gmSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; -} - -uint32_t B2gmSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; -#ifdef B2GM_COUNTERS - B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = ctx->m - B2GM_Q + 1, matches = 0; - B2GM_TYPE d; - - //printf("\n"); - //PrintRawDataFp(stdout, buf, buflen); - - SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32"", buflen, - ctx->m, pos); - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (uint32_t)(buflen - B2GM_Q + 1)) { - uint16_t h = B2GM_HASH16(buf[pos - 1],buf[pos]); - d = ctx->B2GM[h]; - - if (d != 0) { - COUNT(tctx->stat_d0++); - uint32_t j = pos; - uint32_t first = pos - (ctx->m - B2GM_Q + 1); - - do { - j = j - 1; - - if (d >= (uint32_t)(1 << (ctx->m - 1))) { - if (j > first) - pos = j; - else { - COUNT(tctx->stat_test_buf++); - h = B2GM_HASH16(buf[j + ctx->m - 2],buf[j + ctx->m - 1]); - - if (unlikely(ctx->lookup[h].pminlen > 0 && (buflen - j) >= ctx->lookup[h].pminlen && - BloomFilterTest(ctx->lookup[h].bloom, buf+j, ctx->lookup[h].pminlenb) == 1)) - { - COUNT(tctx->stat_test_buf_ok++); - /* get our patterns from the hash */ - B2gmPattern *hi = ctx->lookup[h].hash, *thi; - for (thi = hi; thi != NULL; thi = thi->next) { - if ((buflen - j) >= thi->len) { - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - - if (unlikely(memcmp_lowercase(thi->pat, buf+j, thi->len) == 0)) { -#ifdef PRINTMATCH - printf("CI Exact match: "); prt(thi->pat, thi->len); printf(" (id %u)\n", thi->id); -#endif - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (unlikely(memcmp(thi->pat, buf+j, thi->len) == 0)) { -#ifdef PRINTMATCH - printf("CS Exact match: "); prt(thi->pat, thi->len); printf(" (id %u)\n", thi->id); -#endif - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } - } else { - COUNT(tctx->stat_test_buf_fail++); - } - } - } - - if (j == 0) { - break; - } - - h = B2GM_HASH16(buf[j - 1],buf[j]); - d = (d << 1) & ctx->B2GM[h]; - } while (d != 0); - } - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (ctx->m - B2GM_Q + 1)); - pos = pos + ctx->m - B2GM_Q + 1; - - SCLogDebug("pos %"PRIu32"", pos); - } - - SCLogDebug("matches %"PRIu32"", matches); - return matches; -} - -uint32_t B2gmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; -#ifdef B2GM_COUNTERS - B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = 0, matches = 0; - B2GM_TYPE d; - uint32_t j; - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (buflen - ctx->m)) { - j = ctx->m - 1; - d = ~0; - - do { - uint16_t h = B2GM_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); - d = ((d << 1) & ctx->B2GM[h]); - j = j - 1; - } while (d != 0 && j != 0); - - /* (partial) match, move on to verification */ - if (d != 0) { - COUNT(tctx->stat_d0++); - //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); - - /* get our patterns from the hash */ - uint16_t h = B2GM_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); - - if (ctx->lookup[h].pminlen > 0) { - COUNT(tctx->stat_pminlen_calls++); - - if ((buflen - pos) < ctx->lookup[h].pminlen) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->lookup[h].bloom, buf+pos, ctx->lookup[h].pminlenb) == 0) { - COUNT(tctx->stat_bloom_hits++); - - //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); - goto skip_loop; - } - } - - B2gmPattern *hi = ctx->lookup[h].hash, *thi; - for (thi = hi; thi != NULL; thi = thi->next) { - COUNT(tctx->stat_d0_hashloop++); - //B2gmPattern *p = ctx->parray[thi->idx]; - - if (buflen - pos < thi->len) - continue; - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - - if (memcmp_lowercase(thi->pat, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (memcmp(thi->pat, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } - -skip_loop: - //pos = pos + ctx->s0; - pos = pos + 1; - } else { - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (j + 1)); - - pos = pos + j + 1; - } - } - - //printf("Total matches %" PRIu32 "\n", matches); - return matches; -} - -uint32_t B2gmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - SCEnter(); - - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - - if (buflen == 0) - SCReturnUInt(0); - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - while (buf <= bufend) { - uint8_t h = u8_tolower(*buf); - uint16_t offset = ctx->ha1[h]; - SCLogDebug("offset %u, h %02X, buf %02X", offset, h, *buf); - - if (offset > 0) { - do { - B2gmPattern1 *hdr = (B2gmPattern1 *)&ctx->patterns1[offset]; - offset += (sizeof(B2gmPattern1)); - - SCLogDebug("hdr flags %02x, id %u, pat %02X", hdr->flags, hdr->id, hdr->pat); - - if (hdr->flags & B2GM_FLAG_NOCASE) { - SCLogDebug("nocase compare, %02X", *buf); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } else { - SCLogDebug("case sensitive compare, %02X", *buf); - - if (*buf == hdr->pat) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } - } - - if (hdr->flags & B2GM_FLAG_FINAL) - break; - } while(1); - } - buf += 1; - } - - //printf("B2gcSearch1: after 1byte cnt %" PRIu32 "\n", cnt); - if (ctx->pat_x_cnt) { - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - } - SCReturnUInt(cnt); -} - -/* - * TESTS - */ - -#ifdef UNITTESTS -static int B2gmTestInit01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->m == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->m); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -#if 0 -static int B2gmTestS0Init01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->s0); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestS0Init02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestS0Init03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", ctx->s0); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestS0Init04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestS0Init05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", ctx->s0); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} -#endif - -static int B2gmTestSearch01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch02a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch02b (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch03a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"b", 1, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"f", 1, 0, 0, 2, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -/* test patterns longer than 'm'. M is 4 here. */ -static int B2gmTestSearch04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -/* case insensitive test patterns longer than 'm'. M is 4 here. */ -static int B2gmTestSearch05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch05a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abCD", 4, 0, 0, 3, 0, 0); /* no match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 4, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 5, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 5) - result = 1; - else - printf("5 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch07 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = 0 ; - int i; - for (i = 0; i<1000;i++) - cnt= ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch08 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch09 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch10 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch11 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch13 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch17 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch18 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch19 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 0, 0, 0); /* 1 */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch20 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32, 0, 0, 0, 0, 0); /* 1 */ - //MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32, 0, 0, 0, 0, 0); /* 1 */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - //uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32); - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch21 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); /* 1 */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} -#endif /* UNITTESTS */ - -#if 0 -static int B2gmTestSearchXX (void) -{ - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - FILE *fp = fopen("/usr/share/dict/words", "r"); - if (fp == NULL) - exit(1); - - char *word; - char line[128]; - int w = 0; - int w_max = 4000; - - while((word = fgets(line, sizeof(line), fp)) != NULL) { - word[strlen(word) - 1] = '\0'; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)word, strlen(word), 0, 0, (uint32_t)w, 0, 0); - - w++; - - if (w_max == w) - break; - } - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - char *text = "Yes this is a text, it is not very long. But, it is still sufficient for testing our search! " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "Bjdhfahflkahsf;phf[hfihasfkhsfkjhalhflkafljhfkhakhfkahfkahfkjhdkffkjhafkhafkjakjfhkjahf;aj;jh"; - uint32_t len = strlen(text) - 1; - - int i; - uint32_t cnt; - for (i = 0; i < 100; i++) { - cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); - } - - printf("cnt %u ", cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - fclose(fp); - - return 1; -} -#endif - -void B2gmRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("B2gmTestInit01", B2gmTestInit01, 1); -/* - UtRegisterTest("B2gmTestS0Init01", B2gmTestS0Init01, 1); - UtRegisterTest("B2gmTestS0Init02", B2gmTestS0Init02, 1); - UtRegisterTest("B2gmTestS0Init03", B2gmTestS0Init03, 1); - UtRegisterTest("B2gmTestS0Init04", B2gmTestS0Init04, 1); - UtRegisterTest("B2gmTestS0Init05", B2gmTestS0Init05, 1); -*/ - UtRegisterTest("B2gmTestSearch01", B2gmTestSearch01, 1); - UtRegisterTest("B2gmTestSearch02", B2gmTestSearch02, 1); - UtRegisterTest("B2gmTestSearch02a", B2gmTestSearch02a, 1); - UtRegisterTest("B2gmTestSearch02b", B2gmTestSearch02b, 1); - UtRegisterTest("B2gmTestSearch03", B2gmTestSearch03, 1); - UtRegisterTest("B2gmTestSearch03a", B2gmTestSearch03a, 1); - UtRegisterTest("B2gmTestSearch04", B2gmTestSearch04, 1); - UtRegisterTest("B2gmTestSearch05", B2gmTestSearch05, 1); - UtRegisterTest("B2gmTestSearch05a", B2gmTestSearch05a, 1); - UtRegisterTest("B2gmTestSearch06", B2gmTestSearch06, 1); - UtRegisterTest("B2gmTestSearch07", B2gmTestSearch07, 1); - UtRegisterTest("B2gmTestSearch08", B2gmTestSearch08, 1); - UtRegisterTest("B2gmTestSearch09", B2gmTestSearch09, 1); - UtRegisterTest("B2gmTestSearch10", B2gmTestSearch10, 1); - UtRegisterTest("B2gmTestSearch11", B2gmTestSearch11, 1); - UtRegisterTest("B2gmTestSearch12", B2gmTestSearch12, 1); - UtRegisterTest("B2gmTestSearch13", B2gmTestSearch13, 1); - UtRegisterTest("B2gmTestSearch14", B2gmTestSearch14, 1); - UtRegisterTest("B2gmTestSearch15", B2gmTestSearch15, 1); - UtRegisterTest("B2gmTestSearch16", B2gmTestSearch16, 1); - UtRegisterTest("B2gmTestSearch17", B2gmTestSearch17, 1); - UtRegisterTest("B2gmTestSearch18", B2gmTestSearch18, 1); - UtRegisterTest("B2gmTestSearch19", B2gmTestSearch19, 1); - UtRegisterTest("B2gmTestSearch20", B2gmTestSearch20, 1); - UtRegisterTest("B2gmTestSearch21", B2gmTestSearch21, 1); -/* - UtRegisterTest("B2gmTestSearchXX", B2gmTestSearchXX, 1); -*/ -#endif /* UNITTESTS */ -} - diff --git a/src/util-mpm-b2gm.h b/src/util-mpm-b2gm.h deleted file mode 100644 index 5b1316bf8564..000000000000 --- a/src/util-mpm-b2gm.h +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright (C) 2007-2010 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 - */ - -#ifndef __UTIL_MPM_B2GM_H__ -#define __UTIL_MPM_B2GM_H__ - -#include "util-mpm.h" -#include "util-bloomfilter.h" - -#define B2GM_HASHSHIFT_MAX 8 -#define B2GM_HASHSHIFT_HIGHER 7 -#define B2GM_HASHSHIFT_HIGH 6 -#define B2GM_HASHSHIFT_MEDIUM 5 -#define B2GM_HASHSHIFT_LOW 4 -#define B2GM_HASHSHIFT_LOWEST 3 - -//#define B2GM_TYPE uint64_t -#define B2GM_TYPE uint32_t -//#define B2GM_TYPE uint16_t -//#define B2GM_TYPE uint8_t - -//#define B2GM_WORD_SIZE 64 -#define B2GM_WORD_SIZE 32 -//#define B2GM_WORD_SIZE 16 -//#define B2GM_WORD_SIZE 8 - -#define B2GM_Q 2 - -#define B2GM_SEARCHFUNC B2gmSearchBNDMq -//#define B2GM_SEARCHFUNC B2gmSearch - -//#define B2GM_COUNTERS - -#define B2GM_FLAG_NOCASE 0x01 -#define B2GM_FLAG_FINAL 0x02 - -typedef struct B2gmPattern_ { - uint8_t len; - uint8_t flags; - uint16_t id; -#if __WORDSIZE == 64 - uint32_t pad; -#endif - uint8_t *pat; - struct B2gmPattern_ *next; -} B2gmPattern; - -typedef struct B2gmPattern1_ { - uint8_t flags; - uint8_t pat; - uint16_t id; -} B2gmPattern1; - -typedef struct B2gmLookup_ { - uint16_t pminlen; - uint8_t pminlenb; /* bloom */ - uint8_t pad0; -#if __WORDSIZE == 64 - uint32_t pad1; -#endif - BloomFilter *bloom; - B2gmPattern *hash; -} B2gmLookup; - -typedef struct B2gmCtx_ { - /* we store our own multi byte search func ptr here for B2gmSearch1 */ - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - /* hash for looking up the idx in the pattern array */ - uint16_t *ha1; - uint8_t *patterns1; - - /* we store our own multi byte search func ptr here for B2gmSearch1 */ - //uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - uint16_t pat_1_cnt; - uint16_t pat_x_cnt; -#if __WORDSIZE == 64 - uint32_t pad1; -#endif - - B2GM_TYPE *B2GM; - B2GM_TYPE m; -#if __WORDSIZE == 64 - uint32_t pad0; -#endif - - B2gmLookup *lookup; - - /* pattern arrays */ - B2gmPattern **parray; - - /* hash used during ctx initialization */ - B2gmPattern **init_hash; - //uint8_t s0; - uint32_t hash_size; -} B2gmCtx; - -typedef struct B2gmThreadCtx_ { -#ifdef B2GM_COUNTERS - uint32_t stat_pminlen_calls; - uint32_t stat_pminlen_total; - uint32_t stat_bloom_calls; - uint32_t stat_bloom_hits; - uint32_t stat_calls; - uint32_t stat_m_total; - uint32_t stat_d0; - uint32_t stat_d0_hashloop; - uint32_t stat_loop_match; - uint32_t stat_loop_no_match; - uint32_t stat_num_shift; - uint32_t stat_total_shift; - uint32_t stat_test_buf; - uint32_t stat_test_buf_ok; - uint32_t stat_test_buf_fail; -#endif /* B2GM_COUNTERS */ -} B2gmThreadCtx; - -void MpmB2gmRegister(void); - -#endif /* __UTIL_MPM_B2GM_H__ */ - diff --git a/suricata.yaml.in b/suricata.yaml.in index 89c4326959aa..04cb3b228571 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -586,7 +586,7 @@ cuda: cuda-streams: 2 # Select the multi pattern algorithm you want to run for scan/search the -# in the engine. The supported algorithms are b2g, b2gc, b2gm, b3g, wumanber, +# in the engine. The supported algorithms are b2g, b3g, wumanber, # ac and ac-gfbs. # # The mpm you choose also decides the distribution of mpm contexts for @@ -619,14 +619,6 @@ mpm-algo: ac # settings. pattern-matcher: - - b2gc: - search-algo: B2gSearchBNDMq - hash-size: low - bf-size: medium - - b2gm: - search-algo: B2gSearchBNDMq - hash-size: low - bf-size: medium - b2g: search-algo: B2gSearchBNDMq hash-size: low From b96645ded204c66670f2d09d2d06adb457c5c554 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 5 Sep 2014 17:14:34 -0400 Subject: [PATCH 0153/2553] Create a wrapper around DetectFlowvarProcessList() to check for empty list Creates an inline wrapper to check for flowvarlist == NULL before calling DetectFlowvarProcessList() to remove the overhead of checking since the list is usually empty. --- src/detect-flowvar.c | 47 +++++++++++++++++++------------------------- src/detect-flowvar.h | 18 ++++++++++++++--- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index b9f9696079fc..d764e085fdbf 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* 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 @@ -324,34 +324,27 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx /** \brief Handle flowvar candidate list in det_ctx: * - clean up the list - * - enforce storage for type ALWAYS (luajit) */ -void DetectFlowvarProcessList(DetectEngineThreadCtx *det_ctx, Flow *f) + * - enforce storage for type ALWAYS (luajit) + * Only called from DetectFlowvarProcessList() when flowvarlist is not NULL . + */ +void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f) { - DetectFlowvarList *fs, *next; - - SCLogDebug("det_ctx->flowvarlist %p", det_ctx->flowvarlist); + DetectFlowvarList *next; - if (det_ctx->flowvarlist != NULL) { - fs = det_ctx->flowvarlist; - while (fs != NULL) { - next = fs->next; + do { + next = fs->next; - if (fs->type == DETECT_FLOWVAR_TYPE_ALWAYS) { - BUG_ON(f == NULL); - SCLogDebug("adding to the flow %u:", fs->idx); - //PrintRawDataFp(stdout, fs->buffer, fs->len); - - FlowVarAddStr(f, fs->idx, fs->buffer, fs->len); - /* memory at fs->buffer is now the responsibility of - * the flowvar code. */ - } else { - SCFree(fs->buffer); - } - SCFree(fs); - fs = next; - } + if (fs->type == DETECT_FLOWVAR_TYPE_ALWAYS) { + BUG_ON(f == NULL); + SCLogDebug("adding to the flow %u:", fs->idx); + //PrintRawDataFp(stdout, fs->buffer, fs->len); - det_ctx->flowvarlist = NULL; - } + FlowVarAddStr(f, fs->idx, fs->buffer, fs->len); + /* memory at fs->buffer is now the responsibility of + * the flowvar code. */ + } else + SCFree(fs->buffer); + SCFree(fs); + fs = next; + } while (fs != NULL); } - diff --git a/src/detect-flowvar.h b/src/detect-flowvar.h index a2975f05210c..7ee12f02ccd7 100644 --- a/src/detect-flowvar.h +++ b/src/detect-flowvar.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* 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 @@ -37,7 +37,19 @@ void DetectFlowvarRegister (void); int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx); int DetectFlowvarStoreMatch(DetectEngineThreadCtx *, uint16_t, uint8_t *, uint16_t, int); -void DetectFlowvarProcessList(DetectEngineThreadCtx *det_ctx, Flow *); -#endif /* __DETECT_FLOWVAR_H__ */ +/* For use only by DetectFlowvarProcessList() */ +void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f); +static inline void DetectFlowvarProcessList(DetectEngineThreadCtx *det_ctx, Flow *f) +{ + DetectFlowvarList *fs = det_ctx->flowvarlist; + + SCLogDebug("det_ctx->flowvarlist %p", fs); + if (fs != NULL) { + det_ctx->flowvarlist = NULL; + DetectFlowvarProcessListInternal(fs, f); + } +} + +#endif /* __DETECT_FLOWVAR_H__ */ From e49d0a592428ab9fa3cc129f4ad0582fd2c75db9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 18 Aug 2014 13:19:07 +0200 Subject: [PATCH 0154/2553] MPM: build sid list from MPM matches Pmq add rule list: Array of uint32_t's to store (internal) sids from the MPM. AC: store sids in the pattern list, append to Pmq::rule_id_array on match. Detect: sort rule_id_array after it was set up by the MPM. Rule id's (Signature::num) are ordered, and the rule's with the lowest id are to be inspected first. As the MPM doesn't fill the array in order, but instead 'randomly' we need this sort step to assure proper inspection order. --- src/detect.c | 12 +++++++++++ src/util-mpm-ac.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++ src/util-mpm-ac.h | 8 +++++++ src/util-mpm.c | 22 +++++++++++++++++++ src/util-mpm.h | 6 ++++++ 5 files changed, 103 insertions(+) diff --git a/src/detect.c b/src/detect.c index 54d035af6ce8..9dd4b4e444f5 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1019,6 +1019,18 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } } } + + /* Sort the rule list to lets look at pmq. + * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ + if (det_ctx->pmq.rule_id_array_cnt) { + int DoSort(const void *a, const void *b) { + uint32_t x = *(uint32_t *)a; + uint32_t y = *(uint32_t *)b; + return x - y; + } + qsort(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt, + sizeof(uint32_t), DoSort); + } } #ifdef DEBUG diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index f8e2199a3961..ec16e415cfd7 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -357,6 +357,34 @@ static int SCACAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, /* we need the max pat id */ if (pid > ctx->max_pat_id) ctx->max_pat_id = pid; + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + //SCLogInfo("MPM added %u:%u", pid, sid); + } else { + /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ + + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + if (!found) { + uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + //SCLogInfo("p->sids_size %u", p->sids_size); + //SCLogInfo("MPM added %u:%u (append)", pid, sid); + } else { + //SCLogInfo("rule %u already part of pid %u", sid, pid); + } } return 0; @@ -1056,6 +1084,11 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) ctx->parray[i]->original_pat, ctx->parray[i]->len); ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; } + + /* ACPatternList now owns this memory */ + //SCLogInfo("ctx->parray[i]->sids_size %u", ctx->parray[i]->sids_size); + ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; + ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; } /* prepare the state table required by AC */ @@ -1237,6 +1270,8 @@ void SCACDestroyCtx(MpmCtx *mpm_ctx) for (i = 0; i < (ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); + if (ctx->pid_pat_list[i].sids != NULL) + SCFree(ctx->pid_pat_list[i].sids); } SCFree(ctx->pid_pat_list); } @@ -1294,6 +1329,11 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } else { @@ -1302,6 +1342,11 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k]].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k]].sids[x]; + } } matches++; } @@ -1333,6 +1378,11 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } else { @@ -1341,6 +1391,11 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k]].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k]].sids[x]; + } } matches++; } diff --git a/src/util-mpm-ac.h b/src/util-mpm-ac.h index 760fb70495c1..7519fffd620f 100644 --- a/src/util-mpm-ac.h +++ b/src/util-mpm-ac.h @@ -52,12 +52,20 @@ typedef struct SCACPattern_ { /* pattern id */ uint32_t id; + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; + struct SCACPattern_ *next; } SCACPattern; typedef struct SCACPatternList_ { uint8_t *cs; uint16_t patlen; + + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; } SCACPatternList; typedef struct SCACOutputTable_ { diff --git a/src/util-mpm.c b/src/util-mpm.c index df81e87a2602..cc40e0edc8c4 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -452,6 +452,16 @@ int PmqSetup(PatternMatcherQueue *pmq, uint32_t patmaxid) SCLogDebug("pmq->pattern_id_array %p, pmq->pattern_id_bitarray %p", pmq->pattern_id_array, pmq->pattern_id_bitarray); + + pmq->rule_id_array_size = 65536 * sizeof(uint32_t); + + pmq->rule_id_array = SCMalloc(pmq->rule_id_array_size); + if (pmq->rule_id_array == NULL) { + SCReturnInt(-1); + } + memset(pmq->rule_id_array, 0, pmq->rule_id_array_size); + pmq->rule_id_array_cnt = 0; + } SCReturnInt(0); @@ -510,6 +520,12 @@ void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst) } /** \todo now set merged flag? */ + + if (src->rule_id_array && dst->rule_id_array) { + for (u = 0; u < src->rule_id_array_cnt; u++) { + dst->rule_id_array[dst->rule_id_array_cnt++] = src->rule_id_array[u]; + } + } } /** \brief Reset a Pmq for reusage. Meant to be called after a single search. @@ -532,6 +548,7 @@ void PmqReset(PatternMatcherQueue *pmq) } pmq->pattern_id_array_cnt = 0; */ + pmq->rule_id_array_cnt = 0; } /** \brief Cleanup a Pmq @@ -552,6 +569,11 @@ void PmqCleanup(PatternMatcherQueue *pmq) pmq->pattern_id_bitarray = NULL; } + if (pmq->rule_id_array != NULL) { + SCFree(pmq->rule_id_array); + pmq->rule_id_array = NULL; + } + pmq->pattern_id_array_cnt = 0; } diff --git a/src/util-mpm.h b/src/util-mpm.h index f45ecfa4cb22..395c5cc8fbfe 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -106,6 +106,12 @@ typedef struct PatternMatcherQueue_ { uint8_t *pattern_id_bitarray; /** bitarray with pattern id matches */ uint32_t pattern_id_bitarray_size; /**< size in bytes */ + + /* used for storing rule id's */ + uint32_t rule_id_array_size; + uint32_t *rule_id_array; + uint32_t rule_id_array_cnt; + } PatternMatcherQueue; typedef struct MpmCtx_ { From f5df526f9bd49c745ebc1d1bf06ba23fff8d9ff6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 18 Aug 2014 13:51:40 +0200 Subject: [PATCH 0155/2553] Detect: create per sgh non-MPM rule array Array of rule id's that are not using MPM prefiltering. These will be merged with the MPM results array. Together these should lead to a list of all the rules that can possibly match. --- src/detect-engine-siggroup.c | 49 ++++++++++++++++++++++++++++++++++++ src/detect-engine-siggroup.h | 2 ++ src/detect.c | 2 ++ src/detect.h | 3 +++ 4 files changed, 56 insertions(+) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 9c41831e07b7..3dc16d46b402 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -205,6 +205,12 @@ void SigGroupHeadFree(SigGroupHead *sgh) sgh->match_array = NULL; } + if (sgh->non_mpm_id_array != NULL) { + SCFree(sgh->non_mpm_id_array); + sgh->non_mpm_id_array = NULL; + sgh->non_mpm_id_cnt = 0; + } + sgh->sig_cnt = 0; if (sgh->init != NULL) { @@ -1696,6 +1702,49 @@ void SigGroupHeadSetFilestoreCount(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return; } +/* build an array of rule id's for sigs with no mpm */ +int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +{ + Signature *s = NULL; + uint32_t sig = 0; + uint32_t non_mpm = 0; + + if (sgh == NULL) + return 0; + + BUG_ON(sgh->non_mpm_id_array != NULL); + + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; + + if (s->mpm_sm == NULL) + non_mpm++; + } + + if (non_mpm == 0) { + sgh->non_mpm_id_array = NULL; + return 0; + } + + sgh->non_mpm_id_array = SCMalloc(non_mpm * sizeof(uint32_t)); + BUG_ON(sgh->non_mpm_id_array == NULL); + memset(sgh->non_mpm_id_array, 0, non_mpm * sizeof(uint32_t)); + + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; + if (s->mpm_sm != NULL) + continue; + + BUG_ON(sgh->non_mpm_id_cnt >= non_mpm); + sgh->non_mpm_id_array[sgh->non_mpm_id_cnt++] = s->num; + } + return 0; +} + int SigGroupHeadBuildHeadArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index ff44aaf2886f..a9368ee19f89 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -91,4 +91,6 @@ void SigGroupHeadSetFilestoreCount(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *, SigGroupHead *); +int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh); + #endif /* __DETECT_ENGINE_SIGGROUP_H__ */ diff --git a/src/detect.c b/src/detect.c index 9dd4b4e444f5..3082cad4beb5 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4013,6 +4013,8 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SigGroupHeadSetFilesizeFlag(de_ctx, sgh); SigGroupHeadSetFilestoreCount(de_ctx, sgh); SCLogDebug("filestore count %u", sgh->filestore_cnt); + + SigGroupHeadBuildNonMpmArray(de_ctx, sgh); } if (de_ctx->decoder_event_sgh != NULL) { diff --git a/src/detect.h b/src/detect.h index 04ea0d8b0167..c5a8de180536 100644 --- a/src/detect.h +++ b/src/detect.h @@ -975,6 +975,9 @@ typedef struct SigGroupHead_ { * signatures to be inspected in a cache efficient way. */ SignatureHeader *head_array; + uint32_t *non_mpm_id_array; + uint32_t non_mpm_id_cnt; // size is cnt * sizeof(uint32_t) + /* pattern matcher instances */ MpmCtx *mpm_proto_other_ctx; From 1f57e25c0324fc32a2fb9dc457f7282687256ee3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 18 Aug 2014 16:05:16 +0200 Subject: [PATCH 0156/2553] detect: Add negated MPM to non-MPM array Treat negated MPM sigs as if non-MPM, so we consider them always. As MPM results and non-MPM rules lists are now merged and considered for further inspection, rules that need to be considerd when a pattern is absent are caught in the middle. As a HACK/workaround this patch adds them to the non-MPM list. This causes them to be inspected each time. --- src/detect-engine-siggroup.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 3dc16d46b402..f5397baa26f9 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -1721,6 +1721,8 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) if (s->mpm_sm == NULL) non_mpm++; + else if (s->flags & (SIG_FLAG_MPM_PACKET_NEG|SIG_FLAG_MPM_STREAM_NEG|SIG_FLAG_MPM_APPLAYER_NEG)) + non_mpm++; } if (non_mpm == 0) { @@ -1736,11 +1738,14 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) s = sgh->match_array[sig]; if (s == NULL) continue; - if (s->mpm_sm != NULL) - continue; - BUG_ON(sgh->non_mpm_id_cnt >= non_mpm); - sgh->non_mpm_id_array[sgh->non_mpm_id_cnt++] = s->num; + if (s->mpm_sm == NULL) { + BUG_ON(sgh->non_mpm_id_cnt >= non_mpm); + sgh->non_mpm_id_array[sgh->non_mpm_id_cnt++] = s->num; + } else if (s->flags & (SIG_FLAG_MPM_PACKET_NEG|SIG_FLAG_MPM_STREAM_NEG|SIG_FLAG_MPM_APPLAYER_NEG)) { + BUG_ON(sgh->non_mpm_id_cnt >= non_mpm); + sgh->non_mpm_id_array[sgh->non_mpm_id_cnt++] = s->num; + } } return 0; } From d1d895a8841b35c9bfd350f49a80636be9c19221 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 18 Aug 2014 16:05:49 +0200 Subject: [PATCH 0157/2553] Replace build match array with new filter logic Use MPM and non-MPM lists to build our match array. Both lists are sorted, and are merged and sorted into the match array. This disables the old match array building code and thus also bypasses the mask checking. --- src/detect.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index 3082cad4beb5..1f872e5d6a5d 100644 --- a/src/detect.c +++ b/src/detect.c @@ -773,6 +773,51 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) SCReturnPtr(smsg, "StreamMsg"); } +static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, SigGroupHead *sgh) +{ + uint32_t m = 0; + uint32_t n = 0; + + uint32_t mpm = -1; + uint32_t nonmpm = -1; + + det_ctx->match_array_cnt = 0; + while (1) { + if (m < det_ctx->pmq.rule_id_array_cnt) + mpm = det_ctx->pmq.rule_id_array[m]; + else + mpm = -1; + if (n < sgh->non_mpm_id_cnt) + nonmpm = sgh->non_mpm_id_array[n]; + else + nonmpm = -1; + + uint32_t id = MIN(mpm, nonmpm); + + if (id == (uint32_t)-1) + return; + else if (id == mpm) { + m++; + BUG_ON(m > det_ctx->pmq.rule_id_array_cnt); + } else if (id == nonmpm) { + n++; + BUG_ON(n > sgh->non_mpm_id_cnt); + } + + Signature *s = de_ctx->sig_array[id]; + + /* as the mpm list can contain duplicates, check for this here */ + if (det_ctx->match_array_cnt == 0 || det_ctx->match_array[det_ctx->match_array_cnt - 1] != s) + det_ctx->match_array[det_ctx->match_array_cnt++] = s; + + if (m >= det_ctx->pmq.rule_id_array_cnt && n >= sgh->non_mpm_id_cnt) + break; + + } + BUG_ON((det_ctx->pmq.rule_id_array_cnt + sgh->non_mpm_id_cnt) < det_ctx->match_array_cnt); +} + #define SMS_USE_FLOW_SGH 0x01 #define SMS_USED_PM 0x02 #define SMS_USED_STREAM_PM 0x04 @@ -1336,8 +1381,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PREFILTER); - /* build the match array */ - SigMatchSignaturesBuildMatchArray(det_ctx, p, mask, alproto); + DetectPrefilterMergeSort(de_ctx, det_ctx, det_ctx->sgh); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PREFILTER); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_RULES); @@ -1352,6 +1396,9 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh s = det_ctx->match_array[idx]; SCLogDebug("inspecting signature id %"PRIu32"", s->id); + if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NO_NEW_STATE) + goto next; + /* check if this signature has a requirement for flowvars of some type * and if so, if we actually have any in the flow. If not, the sig * can't match and we skip it. */ From 7876277119a5326dd183aac048a342e48294c24c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 19 Aug 2014 15:02:49 +0200 Subject: [PATCH 0158/2553] detect: move checks from prefilter to rule detect Move the prefilter checks to the main detect loop. --- src/detect.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index 1f872e5d6a5d..1e3d17f4b394 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1396,8 +1396,57 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh s = det_ctx->match_array[idx]; SCLogDebug("inspecting signature id %"PRIu32"", s->id); - if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NO_NEW_STATE) - goto next; + /* if the sig has alproto and the session as well they should match */ + if (likely(s->flags & SIG_FLAG_APPLAYER)) { + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { + if (s->alproto == ALPROTO_DCERPC) { + if (alproto != ALPROTO_SMB && alproto != ALPROTO_SMB2) { + SCLogDebug("DCERPC sig, alproto not SMB or SMB2"); + goto next; + } + } else { + SCLogDebug("alproto mismatch"); + goto next; + } + } + } + + if (unlikely(s->flags & SIG_FLAG_DSIZE)) { + if (likely(p->payload_len < s->dsize_low || p->payload_len > s->dsize_high)) { + SCLogDebug("kicked out as p->payload_len %u, dsize low %u, hi %u", + p->payload_len, s->dsize_low, s->dsize_high); + goto next; + } + } + + /* check for a pattern match of the one pattern in this sig. */ + if (likely(s->flags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_APPLAYER))) + { + /* filter out sigs that want pattern matches, but + * have no matches */ + if (!(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { + if (s->flags & SIG_FLAG_MPM_PACKET) { + if (!(s->flags & SIG_FLAG_MPM_PACKET_NEG)) { + goto next; + } + } else if (s->flags & SIG_FLAG_MPM_STREAM) { + /* filter out sigs that want pattern matches, but + * have no matches */ + if (!(s->flags & SIG_FLAG_MPM_STREAM_NEG)) { + goto next; + } + } else if (s->flags & SIG_FLAG_MPM_APPLAYER) { + if (!(s->flags & SIG_FLAG_MPM_APPLAYER_NEG)) { + goto next; + } + } + } + } + + if (s->flags & SIG_FLAG_STATE_MATCH) { + if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NO_NEW_STATE) + goto next; + } /* check if this signature has a requirement for flowvars of some type * and if so, if we actually have any in the flow. If not, the sig From 29074af9a6fc930ce772a4b70d7caff5eb59e97d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 19 Aug 2014 15:09:59 +0200 Subject: [PATCH 0159/2553] AC: use local bit array Use a local pattern bit array to making sure we don't match more than once, in addition to the pmq bitarray that is still used for results validation higher up in the rule matching process. Why: pmq->pattern_id_bitarray is currently sometimes used in a 'stateful' way, meaning that for a single packet we run multiple MPM's on the same pmq w/o resetting it. The new bitarray is used to determine wherther we need to append the patterns associated 'sids' list to the pmq rule_id_array. It has been observed that MPM1 matches for PAT1, and MPM2 matches for PAT1 as well. However, in MPM1 PAT1 doesn't have the same sids list. In this case MPM2 would not add it's sids to the list, leading to missed detection. --- src/util-mpm-ac.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index ec16e415cfd7..721954203552 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -1307,6 +1307,9 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ SCACPatternList *pid_pat_list = ctx->pid_pat_list; + uint8_t bitarray[pmq->pattern_id_array_size]; + memset(&bitarray, 0, pmq->pattern_id_array_size); + if (ctx->state_count < 32767) { register SC_AC_STATE_TYPE_U16 state = 0; SC_AC_STATE_TYPE_U16 (*state_table_u16)[256] = ctx->state_table_u16; @@ -1324,10 +1327,11 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); + bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; uint32_t x; @@ -1337,12 +1341,12 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + pmq->pattern_id_bitarray[(pids[k]) / 8] |= (1 << ((pids[k]) % 8)); + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - uint32_t x; for (x = 0; x < pid_pat_list[pids[k]].sids_size; x++) { pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k]].sids[x]; @@ -1373,10 +1377,11 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); + bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; uint32_t x; @@ -1386,10 +1391,11 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + pmq->pattern_id_bitarray[(pids[k]) / 8] |= (1 << ((pids[k]) % 8)); + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; uint32_t x; From edaefe5af259a8ac778eabb4958c92a0c632fc4d Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Wed, 3 Sep 2014 09:17:45 -0400 Subject: [PATCH 0160/2553] Fix AC-tile for new pattern ID array. --- src/util-mpm-ac-tile-small.c | 13 +++-- src/util-mpm-ac-tile.c | 94 ++++++++++++++++++++++++++++++++++-- src/util-mpm-ac-tile.h | 14 ++++-- 3 files changed, 107 insertions(+), 14 deletions(-) diff --git a/src/util-mpm-ac-tile-small.c b/src/util-mpm-ac-tile-small.c index cb468e5a2b19..8a0498654ded 100644 --- a/src/util-mpm-ac-tile-small.c +++ b/src/util-mpm-ac-tile-small.c @@ -37,6 +37,9 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, int i = 0; int matches = 0; + uint8_t bitarray[pmq->pattern_id_array_size]; + memset(&bitarray, 0, pmq->pattern_id_array_size); + uint8_t* restrict xlate = ctx->translate_table; STYPE *state_table = (STYPE*)ctx->state_table; STYPE state = 0; @@ -53,21 +56,21 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, state = SLOAD(state_table + index + c); c = xlate[BYTE1(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, bitarray); } i++; index = SINDEX(index, state); state = SLOAD(state_table + index + c); c = xlate[BYTE2(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, bitarray); } i++; index = SINDEX(index, state); state = SLOAD(state_table + index + c); c = xlate[BYTE3(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, bitarray); } data = data1; i++; @@ -75,7 +78,7 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, state = SLOAD(state_table + index + c); c = xlate[BYTE0(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, bitarray); } i++; } @@ -87,7 +90,7 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, state = SLOAD(state_table + index + c); c = xlate[buf[i+1]]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, bitarray); } } /* for (i = 0; i < buflen; i++) */ diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index b4735527bcf0..18d2d68e4c07 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -514,6 +514,34 @@ static int SCACTileAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, /* we need the max pat id */ if (pid > ctx->max_pat_id) ctx->max_pat_id = pid; + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + //SCLogInfo("MPM added %u:%u", pid, sid); + } else { + /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ + + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + if (!found) { + uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + //SCLogInfo("p->sids_size %u", p->sids_size); + //SCLogInfo("MPM added %u:%u (append)", pid, sid); + } else { + //SCLogInfo("rule %u already part of pid %u", sid, pid); + } } return 0; @@ -1236,6 +1264,11 @@ int SCACTilePreparePatterns(MpmCtx *mpm_ctx) ctx->pid_pat_list[ctx->parray[i]->id].patlen = len; string_space += space; } + + /* ACPatternList now owns this memory */ + //SCLogInfo("ctx->parray[i]->sids_size %u", ctx->parray[i]->sids_size); + ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; + ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; } /* prepare the state table required by AC */ @@ -1359,8 +1392,39 @@ static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx) ctx->parray = NULL; } + if (ctx->state_table != NULL) { + SCFree(ctx->state_table); + + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (ctx->state_count * + ctx->bytes_per_state * ctx->alphabet_storage); + } + + if (ctx->output_table != NULL) { + int state; + for (state = 0; state < ctx->state_count; state++) { + if (ctx->output_table[state].pids != NULL) { + SCFree(ctx->output_table[state].pids); + } + } + SCFree(ctx->output_table); + } + + if (ctx->pid_pat_list != NULL) { + int i; + for (i = 0; i < (ctx->max_pat_id + 1); i++) { + if (ctx->pid_pat_list[i].cs != NULL) + SCFree(ctx->pid_pat_list[i].cs); + if (ctx->pid_pat_list[i].sids != NULL) + SCFree(ctx->pid_pat_list[i].sids); + } + SCFree(ctx->pid_pat_list); + } + SCFree(ctx); search_ctx->init_ctx = NULL; + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCACTileCtx); } /** @@ -1403,13 +1467,13 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen, - uint16_t state, int i, int matches) + uint16_t state, int i, int matches, uint8_t *bitarray) { SCACTilePatternList *pid_pat_list = ctx->pid_pat_list; uint8_t *buf_offset = buf + i + 1; // Lift out of loop uint32_t no_of_entries = ctx->output_table[state].no_of_entries; uint32_t *pids = ctx->output_table[state].pids; - uint8_t *bitarray = pmq->pattern_id_bitarray; + uint8_t *pmq_bitarray = pmq->pattern_id_bitarray; uint32_t k; /* Where to start storing new patterns */ @@ -1429,7 +1493,15 @@ int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, ; } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); *new_pattern++ = lower_pid; + + // Add SIDs for this pattern + // TODO - Keep local pointer to update. + uint32_t x; + for (x = 0; x < pid_pat_list[lower_pid].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[lower_pid].sids[x]; + } } matches++; } @@ -1476,6 +1548,9 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct SCACTilePatternList *pid_pat_list = ctx->pid_pat_list; + uint8_t bitarray[pmq->pattern_id_array_size]; + memset(&bitarray, 0, pmq->pattern_id_array_size); + uint8_t* restrict xlate = ctx->translate_table; register int state = 0; int32_t (*state_table_u32)[256] = ctx->state_table; @@ -1493,22 +1568,31 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & - (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { + bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k]].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k]].sids[x]; + } } matches++; } diff --git a/src/util-mpm-ac-tile.h b/src/util-mpm-ac-tile.h index ce64c9b7d909..9682bd9ead09 100644 --- a/src/util-mpm-ac-tile.h +++ b/src/util-mpm-ac-tile.h @@ -40,12 +40,20 @@ typedef struct SCACTilePattern_ { /* pattern id */ uint32_t id; + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; + struct SCACTilePattern_ *next; } SCACTilePattern; typedef struct SCACTilePatternList_ { uint8_t *cs; uint16_t patlen; + + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; } SCACTilePatternList; typedef struct SCACTileOutputTable_ { @@ -85,8 +93,6 @@ typedef struct SCACTileCtx_ { SCACTileOutputTable *output_table; SCACTilePatternList *pid_pat_list; - /* the stuff below is only used at initialization time */ - /* hash used during ctx initialization */ SCACTilePattern **init_hash; @@ -101,9 +107,9 @@ typedef struct SCACTileCtx_ { int32_t *failure_table; /* Number of states used by ac-tile */ - int state_count; + uint32_t state_count; /* Number of states allocated for ac-tile. */ - int allocated_state_count; + uint32_t allocated_state_count; /* Largest Pattern Identifier. */ uint16_t max_pat_id; From d03f1244457e65831ab72f70f8ea606f1a5ea7a0 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Tue, 30 Sep 2014 10:58:35 -0400 Subject: [PATCH 0161/2553] Implement MPM opt for b2g, b3g, wumanber Found problems in b2gm and b2gc, so those are removed. --- src/util-mpm-ac-tile-small.c | 4 +- src/util-mpm-ac-tile.c | 4 +- src/util-mpm-ac.c | 4 +- src/util-mpm-b2g.c | 96 +++++++++++++++++++++++++++++++----- src/util-mpm-b2g.h | 5 ++ src/util-mpm-b3g.c | 88 ++++++++++++++++++++++++++++----- src/util-mpm-b3g.h | 8 ++- src/util-mpm-wumanber.c | 93 +++++++++++++++++++++++++++++----- src/util-mpm-wumanber.h | 5 ++ src/util-mpm.c | 18 ++++--- src/util-mpm.h | 3 +- 11 files changed, 279 insertions(+), 49 deletions(-) diff --git a/src/util-mpm-ac-tile-small.c b/src/util-mpm-ac-tile-small.c index 8a0498654ded..3390a917cb5d 100644 --- a/src/util-mpm-ac-tile-small.c +++ b/src/util-mpm-ac-tile-small.c @@ -37,8 +37,8 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, int i = 0; int matches = 0; - uint8_t bitarray[pmq->pattern_id_array_size]; - memset(&bitarray, 0, pmq->pattern_id_array_size); + uint8_t bitarray[pmq->pattern_id_bitarray_size]; + memset(bitarray, 0, pmq->pattern_id_bitarray_size); uint8_t* restrict xlate = ctx->translate_table; STYPE *state_table = (STYPE*)ctx->state_table; diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 18d2d68e4c07..e34911de961f 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -1548,8 +1548,8 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct SCACTilePatternList *pid_pat_list = ctx->pid_pat_list; - uint8_t bitarray[pmq->pattern_id_array_size]; - memset(&bitarray, 0, pmq->pattern_id_array_size); + uint8_t bitarray[pmq->pattern_id_bitarray_size]; + memset(bitarray, 0, pmq->pattern_id_bitarray_size); uint8_t* restrict xlate = ctx->translate_table; register int state = 0; diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 721954203552..f6c462ea2576 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -1307,8 +1307,8 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ SCACPatternList *pid_pat_list = ctx->pid_pat_list; - uint8_t bitarray[pmq->pattern_id_array_size]; - memset(&bitarray, 0, pmq->pattern_id_array_size); + uint8_t bitarray[pmq->pattern_id_bitarray_size]; + memset(bitarray, 0, pmq->pattern_id_bitarray_size); if (ctx->state_count < 32767) { register SC_AC_STATE_TYPE_U16 state = 0; diff --git a/src/util-mpm-b2g.c b/src/util-mpm-b2g.c index 31ef46b52589..b4e2fcb77b26 100644 --- a/src/util-mpm-b2g.c +++ b/src/util-mpm-b2g.c @@ -282,6 +282,12 @@ void B2gFreePattern(MpmCtx *mpm_ctx, B2gPattern *p) mpm_ctx->memory_size -= p->len; } + if (p && p->sids) { + SCFree(p->sids); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->sids_size * sizeof(uint32_t); + } + if (p) { SCFree(p); mpm_ctx->memory_cnt--; @@ -357,6 +363,13 @@ static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ } } + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(uint32_t); + //printf("B2gAddPattern: ci \""); prt(p->ci,p->len); //printf("\" cs \""); prt(p->cs,p->len); //printf("\"\n"); @@ -373,6 +386,27 @@ static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; + } else { + /* Multiple sids for the same pid, so keep an array of sids. */ + + /* TODO figure out how we can be called multiple times for the + * same CTX with the same sid */ + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + if (!found) { + uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + mpm_ctx->memory_size += sizeof(uint32_t); + } } return 0; @@ -458,6 +492,8 @@ static void B2gPrepareHash(MpmCtx *mpm_ctx) hi->id = ctx->parray[i]->id; hi->ci = ctx->parray[i]->ci; hi->cs = ctx->parray[i]->cs; + hi->sids = ctx->parray[i]->sids; + hi->sids_size = ctx->parray[i]->sids_size; } else { B2gPattern *hi = B2gAllocHashItem(mpm_ctx); @@ -470,6 +506,8 @@ static void B2gPrepareHash(MpmCtx *mpm_ctx) hi->id = ctx->parray[i]->id; hi->ci = ctx->parray[i]->ci; hi->cs = ctx->parray[i]->cs; + hi->sids = ctx->parray[i]->sids; + hi->sids_size = ctx->parray[i]->sids_size; /* Append this HashItem to the list */ B2gPattern *thi = &ctx->hash1[idx8]; @@ -518,6 +556,9 @@ static void B2gPrepareHash(MpmCtx *mpm_ctx) hi->id = ctx->parray[i]->id; hi->ci = ctx->parray[i]->ci; hi->cs = ctx->parray[i]->cs; + hi->sids = ctx->parray[i]->sids; + hi->sids_size = ctx->parray[i]->sids_size; + ctx->hash[idx] = hi; } else { B2gPattern *hi = B2gAllocHashItem(mpm_ctx); @@ -531,6 +572,9 @@ static void B2gPrepareHash(MpmCtx *mpm_ctx) hi->id = ctx->parray[i]->id; hi->ci = ctx->parray[i]->ci; hi->cs = ctx->parray[i]->cs; + hi->sids = ctx->parray[i]->sids; + hi->sids_size = ctx->parray[i]->sids_size; + if (ctx->parray[i]->len < ctx->pminlen[idx]) ctx->pminlen[idx] = ctx->parray[i]->len; @@ -948,6 +992,12 @@ uint32_t B2gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMa if (buflen < ctx->m) return 0; + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (pos <= (uint32_t)(buflen - B2G_Q + 1)) { uint16_t h = B2G_HASH16(u8_tolower(buf[pos - 1]),u8_tolower(buf[pos])); d = ctx->B2G[h]; @@ -1001,7 +1051,8 @@ uint32_t B2gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMa #endif COUNT(tctx->stat_loop_match++); - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, + bitarray, thi->sids, thi->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1013,7 +1064,8 @@ uint32_t B2gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMa #endif COUNT(tctx->stat_loop_match++); - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, + bitarray, thi->sids, thi->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1061,6 +1113,12 @@ uint32_t B2gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcher if (buflen < ctx->m) return 0; + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (pos <= (buflen - ctx->m)) { j = ctx->m - 1; d = ~0; @@ -1110,7 +1168,8 @@ uint32_t B2gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcher if (SCMemcmpLowercase(thi->ci, buf+pos, thi->len) == 0) { COUNT(tctx->stat_loop_match++); - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, + bitarray, thi->sids, thi->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1118,7 +1177,8 @@ uint32_t B2gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcher if (SCMemcmp(thi->cs, buf+pos, thi->len) == 0) { COUNT(tctx->stat_loop_match++); - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, + bitarray, thi->sids, thi->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1154,6 +1214,12 @@ uint32_t B2gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche //printf("BUF "); prt(buf,buflen); printf("\n"); + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (buf <= bufend) { uint8_t h8 = u8_tolower(*buf); hi = &ctx->hash1[h8]; @@ -1164,11 +1230,13 @@ uint32_t B2gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (h8 == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, + bitarray, thi->sids, thi->sids_size); } } else { if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, + bitarray, thi->sids, thi->sids_size); } } } @@ -1185,15 +1253,15 @@ uint32_t B2gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche if (h8 == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { //printf("CI Exact match: "); prt(p->ci, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B2gSearch1)\n"); // for (em = p->em; em; em = em->next) { - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) - cnt++; + if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size)) + cnt++; // } } } else { if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { //printf("CS Exact match: "); prt(p->cs, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B2gSearch1)\n"); // for (em = p->em; em; em = em->next) { - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) + if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size)) cnt++; // } } @@ -1229,6 +1297,12 @@ uint32_t B2gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche //printf("BUF "); prt(buf,buflen); printf("\n"); + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (buf <= bufend) { uint8_t h = u8_tolower(*buf); hi = &ctx->hash1[h]; @@ -1240,11 +1314,11 @@ uint32_t B2gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { if (u8_tolower(*buf) == thi->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, bitarray, thi->sids, thi->sids_size); } } else { if (*buf == thi->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, bitarray, thi->sids, thi->sids_size); } } } diff --git a/src/util-mpm-b2g.h b/src/util-mpm-b2g.h index 2d22b0ef58bf..8c002b63451e 100644 --- a/src/util-mpm-b2g.h +++ b/src/util-mpm-b2g.h @@ -59,6 +59,11 @@ typedef struct B2gPattern_ { uint8_t *original_pat; uint8_t *ci; /* case INsensitive */ uint8_t *cs; /* case sensitive */ + + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; + struct B2gPattern_ *next; } B2gPattern; diff --git a/src/util-mpm-b3g.c b/src/util-mpm-b3g.c index 12472528dc75..03b7fd6927f7 100644 --- a/src/util-mpm-b3g.c +++ b/src/util-mpm-b3g.c @@ -245,6 +245,12 @@ void B3gFreePattern(MpmCtx *mpm_ctx, B3gPattern *p) mpm_ctx->memory_size -= p->len; } + if (p && p->sids) { + SCFree(p->sids); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->sids_size * sizeof(uint32_t); + } + if (p) { SCFree(p); mpm_ctx->memory_cnt--; @@ -310,6 +316,13 @@ static int B3gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ //printf("\" cs \""); prt(p->cs,p->len); //printf("\" prefix_ci %" PRIu32 ", prefix_cs %" PRIu32 "\n", p->prefix_ci, p->prefix_cs); + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(uint32_t); + /* put in the pattern hash */ B3gInitHashAdd(ctx, p); @@ -322,6 +335,27 @@ static int B3gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; + } else { + /* Multiple sids for the same pid, so keep an array of sids. */ + + /* TODO figure out how we can be called multiple times for the + * same CTX with the same sid */ + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + if (!found) { + uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + mpm_ctx->memory_size += sizeof(uint32_t); + } } return 0; @@ -882,6 +916,12 @@ uint32_t B3gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMa if (buflen < ctx->m) return 0; + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (pos <= (uint32_t)(buflen - B3G_Q + 1)) { uint16_t h = B3G_HASH(u8_tolower(buf[pos - 1]), u8_tolower(buf[pos]),u8_tolower(buf[pos + 1])); d = ctx->B3G[h]; @@ -929,7 +969,7 @@ uint32_t B3gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMa if (memcmp_lowercase(p->ci, buf+j, p->len) == 0) { COUNT(tctx->stat_loop_match++); - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -940,7 +980,7 @@ uint32_t B3gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMa if (memcmp(p->cs, buf+j, p->len) == 0) { COUNT(tctx->stat_loop_match++); - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -982,6 +1022,12 @@ uint32_t B3gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcher if (buflen < ctx->m) return 0; + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (pos <= (buflen - ctx->m)) { j = ctx->m - 2; d = ~0; @@ -1030,7 +1076,7 @@ uint32_t B3gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcher if (memcmp_lowercase(p->ci, buf+pos, p->len) == 0) { COUNT(tctx->stat_loop_match++); - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1041,7 +1087,7 @@ uint32_t B3gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcher if (memcmp(p->cs, buf+pos, p->len) == 0) { COUNT(tctx->stat_loop_match++); - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1073,6 +1119,12 @@ uint32_t B3gSearch12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatch //printf("BUF "); prt(buf,buflen); printf("\n"); + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (buf <= bufend) { uint8_t h8 = u8_tolower(*buf); hi = &ctx->hash1[h8]; @@ -1083,11 +1135,11 @@ uint32_t B3gSearch12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatch if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (h8 == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } } else { if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } } } @@ -1103,11 +1155,11 @@ uint32_t B3gSearch12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatch if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (h8 == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } } else { if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } } } @@ -1139,6 +1191,12 @@ uint32_t B3gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche //printf("BUF "); prt(buf,buflen); printf("\n"); + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (buf <= bufend) { uint16_t h = u8_tolower(*buf) << b3g_hash_shift | u8_tolower(*(buf+1)); hi = ctx->hash2[h]; @@ -1153,13 +1211,13 @@ uint32_t B3gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (u8_tolower(*buf) == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { //printf("CI Exact match: "); prt(p->ci, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B3gSearch1)\n"); - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) + if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size)) cnt++; } } else { if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { //printf("CS Exact match: "); prt(p->cs, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B3gSearch1)\n"); - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) + if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size)) cnt++; } } @@ -1191,6 +1249,12 @@ uint32_t B3gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche //printf("BUF "); prt(buf,buflen); printf("\n"); + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (buf <= bufend) { uint8_t h = u8_tolower(*buf); hi = &ctx->hash1[h]; @@ -1204,11 +1268,11 @@ uint32_t B3gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (u8_tolower(*buf) == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } } else { if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } } } diff --git a/src/util-mpm-b3g.h b/src/util-mpm-b3g.h index 60107ac5f3b7..2d75caa335d1 100644 --- a/src/util-mpm-b3g.h +++ b/src/util-mpm-b3g.h @@ -58,9 +58,15 @@ typedef struct B3gPattern_ { uint8_t *cs; /* case sensitive */ uint8_t *ci; /* case INsensitive */ uint16_t len; - struct B3gPattern_ *next; uint8_t flags; uint32_t id; + + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; + + struct B3gPattern_ *next; + } B3gPattern; typedef struct B3gHashItem_ { diff --git a/src/util-mpm-wumanber.c b/src/util-mpm-wumanber.c index 15d7a23ccd19..4966821f6e5a 100644 --- a/src/util-mpm-wumanber.c +++ b/src/util-mpm-wumanber.c @@ -283,6 +283,12 @@ void WmFreePattern(MpmCtx *mpm_ctx, WmPattern *p) mpm_ctx->memory_size -= p->len; } + if (p && p->sids) { + SCFree(p->sids); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->sids_size * sizeof(uint32_t); + } + if (p) { SCFree(p); mpm_ctx->memory_cnt--; @@ -369,6 +375,33 @@ static int WmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(uint32_t); + + } else { + /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ + + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + if (!found) { + uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + mpm_ctx->memory_size += sizeof(uint32_t); + } } return 0; @@ -763,6 +796,12 @@ uint32_t WmSearch2Hash9(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMa buf+=(sl-1); + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (buf <= bufend) { h = HASH9(wm_tolower(*buf),(wm_tolower(*(buf-1)))); shift = ctx->shifttable[h]; @@ -808,7 +847,7 @@ uint32_t WmSearch2Hash9(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMa //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); @@ -820,7 +859,7 @@ uint32_t WmSearch2Hash9(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMa //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); @@ -865,6 +904,12 @@ uint32_t WmSearch2Hash12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM buf+=(sl-1); //buf++; + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (buf <= bufend) { //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); h = HASH12(wm_tolower(*buf),(wm_tolower(*(buf-1)))); @@ -911,7 +956,7 @@ uint32_t WmSearch2Hash12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); @@ -923,7 +968,7 @@ uint32_t WmSearch2Hash12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); @@ -967,6 +1012,12 @@ uint32_t WmSearch2Hash14(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM buf+=(sl-1); //buf++; + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (buf <= bufend) { //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); h = HASH14(wm_tolower(*buf),(wm_tolower(*(buf-1)))); @@ -1012,7 +1063,7 @@ uint32_t WmSearch2Hash14(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { COUNT(tctx->stat_loop_match++); - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1022,7 +1073,7 @@ uint32_t WmSearch2Hash14(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM if (memcmp(p->cs, buf-sl+1, p->len) == 0) { COUNT(tctx->stat_loop_match++); - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1065,6 +1116,12 @@ uint32_t WmSearch2Hash15(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM buf+=(sl-1); //buf++; + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (buf <= bufend) { //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); h = HASH15(wm_tolower(*buf),(wm_tolower(*(buf-1)))); @@ -1111,7 +1168,7 @@ uint32_t WmSearch2Hash15(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1122,7 +1179,7 @@ uint32_t WmSearch2Hash15(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1165,6 +1222,12 @@ uint32_t WmSearch2Hash16(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM buf+=(sl-1); //buf++; + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + while (buf <= bufend) { //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); h = HASH16(wm_tolower(*buf),(wm_tolower(*(buf-1)))); @@ -1210,7 +1273,7 @@ uint32_t WmSearch2Hash16(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { COUNT(tctx->stat_loop_match++); - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1220,7 +1283,7 @@ uint32_t WmSearch2Hash16(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM if (memcmp(p->cs, buf-sl+1, p->len) == 0) { COUNT(tctx->stat_loop_match++); - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } else { COUNT(tctx->stat_loop_no_match++); } @@ -1253,6 +1316,12 @@ uint32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcher //printf("BUF "); prt(buf,buflen); printf("\n"); + uint8_t *bitarray = NULL; + if (pmq) { + bitarray = alloca(pmq->pattern_id_bitarray_size); + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + } + if (mpm_ctx->minlen == 1) { while (buf <= bufend) { uint8_t h = wm_tolower(*buf); @@ -1267,11 +1336,11 @@ uint32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcher if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (wm_tolower(*buf) == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } } else { if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); } } } diff --git a/src/util-mpm-wumanber.h b/src/util-mpm-wumanber.h index 3d826536c2db..a8b0bdef5d6d 100644 --- a/src/util-mpm-wumanber.h +++ b/src/util-mpm-wumanber.h @@ -38,6 +38,11 @@ typedef struct WmPattern_ { uint16_t prefix_cs; uint8_t flags; uint32_t id; /* global pattern id */ + + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; + } WmPattern; typedef struct WmHashItem_ { diff --git a/src/util-mpm.c b/src/util-mpm.c index cc40e0edc8c4..cc466177f4a1 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -31,8 +31,6 @@ #include "util-mpm-wumanber.h" #include "util-mpm-b2g.h" #include "util-mpm-b3g.h" -#include "util-mpm-b2gc.h" -#include "util-mpm-b2gm.h" #include "util-mpm-ac.h" #include "util-mpm-ac-gfbs.h" #include "util-mpm-ac-bs.h" @@ -481,7 +479,8 @@ int PmqSetup(PatternMatcherQueue *pmq, uint32_t patmaxid) * \retval 1 (new) match */ int -MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t patid) +MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t patid, + uint8_t *bitarray, uint32_t *sids, uint32_t sids_size) { SCEnter(); @@ -489,13 +488,22 @@ MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t pati if (pmq != NULL && pmq->pattern_id_bitarray != NULL) { SCLogDebug("using pattern id arrays, storing %"PRIu32, patid); - if (!(pmq->pattern_id_bitarray[(patid / 8)] & (1<<(patid % 8)))) { + if ((bitarray[(patid / 8)] & (1<<(patid % 8))) == 0) { + bitarray[(patid / 8)] |= (1<<(patid % 8)); /* flag this pattern id as being added now */ pmq->pattern_id_bitarray[(patid / 8)] |= (1<<(patid % 8)); /* append the pattern_id to the array with matches */ pmq->pattern_id_array[pmq->pattern_id_array_cnt] = patid; pmq->pattern_id_array_cnt++; SCLogDebug("pattern_id_array_cnt %u", pmq->pattern_id_array_cnt); + + SCLogDebug("Adding %u sids", sids_size); + // Add SIDs for this pattern + uint32_t x; + for (x = 0; x < sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = sids[x]; + } + } } @@ -606,8 +614,6 @@ void MpmTableSetup(void) MpmWuManberRegister(); MpmB2gRegister(); MpmB3gRegister(); - MpmB2gcRegister(); - MpmB2gmRegister(); MpmACRegister(); MpmACBSRegister(); MpmACGfbsRegister(); diff --git a/src/util-mpm.h b/src/util-mpm.h index 395c5cc8fbfe..cf5a7335c9b4 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -249,7 +249,8 @@ void PmqFree(PatternMatcherQueue *); void MpmTableSetup(void); void MpmRegisterTests(void); -int MpmVerifyMatch(MpmThreadCtx *, PatternMatcherQueue *, uint32_t); +int MpmVerifyMatch(MpmThreadCtx *, PatternMatcherQueue *, uint32_t, + uint8_t *bitarray, uint32_t *sids, uint32_t sid_size); void MpmInitCtx(MpmCtx *mpm_ctx, uint16_t matcher); void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t, uint32_t); uint32_t MpmGetHashSize(const char *); From f83022d818616ccacf3e532564d38d9d51f19d74 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Wed, 1 Oct 2014 17:13:54 -0400 Subject: [PATCH 0162/2553] Implement MPM opt for ac-bs and ac-gfbs Copies sids changes from ac. --- src/util-mpm-ac-bs.c | 64 +++++++++++++++++++++++++++++++++++++++--- src/util-mpm-ac-bs.h | 8 ++++++ src/util-mpm-ac-gfbs.c | 64 +++++++++++++++++++++++++++++++++++++++--- src/util-mpm-ac-gfbs.h | 8 ++++++ 4 files changed, 136 insertions(+), 8 deletions(-) diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index faec5b2a591d..9ea9eed895c3 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -370,6 +370,29 @@ static int SCACBSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, /* we need the max pat id */ if (pid > ctx->max_pat_id) ctx->max_pat_id = pid; + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + } else { + /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ + + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + if (!found) { + uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + } } return 0; @@ -1196,6 +1219,10 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) ctx->parray[i]->original_pat, ctx->parray[i]->len); ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; } + + /* ACPatternList now owns this memory */ + ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; + ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; } /* prepare the state table required by AC */ @@ -1359,6 +1386,8 @@ void SCACBSDestroyCtx(MpmCtx *mpm_ctx) for (i = 0; i < (ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); + if (ctx->pid_pat_list[i].sids != NULL) + SCFree(ctx->pid_pat_list[i].sids); } SCFree(ctx->pid_pat_list); } @@ -1405,6 +1434,9 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ SCACBSPatternList *pid_pat_list = ctx->pid_pat_list; + uint8_t bitarray[pmq->pattern_id_bitarray_size]; + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + if (ctx->state_count < 32767) { register SC_AC_BS_STATE_TYPE_U16 state = 0; uint16_t no_of_entries; @@ -1464,19 +1496,31 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { + bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } @@ -1545,19 +1589,31 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { + bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } diff --git a/src/util-mpm-ac-bs.h b/src/util-mpm-ac-bs.h index 46e196dd442d..935bc77c2792 100644 --- a/src/util-mpm-ac-bs.h +++ b/src/util-mpm-ac-bs.h @@ -39,12 +39,20 @@ typedef struct SCACBSPattern_ { /* pattern id */ uint32_t id; + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; + struct SCACBSPattern_ *next; } SCACBSPattern; typedef struct SCACBSPatternList_ { uint8_t *cs; uint16_t patlen; + + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; } SCACBSPatternList; typedef struct SCACBSOutputTable_ { diff --git a/src/util-mpm-ac-gfbs.c b/src/util-mpm-ac-gfbs.c index 28b1fc2b3d03..8ccb8e3f4309 100644 --- a/src/util-mpm-ac-gfbs.c +++ b/src/util-mpm-ac-gfbs.c @@ -363,6 +363,29 @@ static int SCACGfbsAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, /* we need the max pat id */ if (pid > ctx->max_pat_id) ctx->max_pat_id = pid; + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + } else { + /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ + + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + if (!found) { + uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + } } return 0; @@ -1067,6 +1090,10 @@ int SCACGfbsPreparePatterns(MpmCtx *mpm_ctx) ctx->parray[i]->original_pat, ctx->parray[i]->len); ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; } + + /* ACPatternList now owns this memory */ + ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; + ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; } /* prepare the state table required by AC */ @@ -1236,6 +1263,8 @@ void SCACGfbsDestroyCtx(MpmCtx *mpm_ctx) for (i = 0; i < (ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); + if (ctx->pid_pat_list[i].sids != NULL) + SCFree(ctx->pid_pat_list[i].sids); } SCFree(ctx->pid_pat_list); } @@ -1268,6 +1297,9 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, SCACGfbsPatternList *pid_pat_list = ctx->pid_pat_list; + uint8_t bitarray[pmq->pattern_id_bitarray_size]; + memset(bitarray, 0, pmq->pattern_id_bitarray_size); + /* really hate the extra cmp here, but can't help it */ if (ctx->state_count < 32767) { /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ @@ -1377,19 +1409,31 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { + bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (pids[k] & 0x0000FFFF); + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } @@ -1502,19 +1546,31 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { + bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (pids[k] & 0x0000FFFF); + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + + uint32_t x; + for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { + pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; + } } matches++; } diff --git a/src/util-mpm-ac-gfbs.h b/src/util-mpm-ac-gfbs.h index e790c685b77f..5f1fc7bbad04 100644 --- a/src/util-mpm-ac-gfbs.h +++ b/src/util-mpm-ac-gfbs.h @@ -39,12 +39,20 @@ typedef struct SCACGfbsPattern_ { /* pattern id */ uint32_t id; + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; + struct SCACGfbsPattern_ *next; } SCACGfbsPattern; typedef struct SCACGfbsPatternList_ { uint8_t *cs; uint16_t patlen; + + /* sid(s) for this pattern */ + uint32_t sids_size; + uint32_t *sids; } SCACGfbsPatternList; typedef struct SCACGfbsOutputTable_ { From 23d2a1c4223d7c2b85f4aef23aca1c8cbee0853a Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 31 Oct 2014 13:22:55 -0400 Subject: [PATCH 0163/2553] Optimize DetectPrefilterMergeSort Fixup rebase changes to remove debug code --- src/detect.c | 81 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/src/detect.c b/src/detect.c index 1e3d17f4b394..6b7537a7db3e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -776,45 +776,64 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, SigGroupHead *sgh) { - uint32_t m = 0; - uint32_t n = 0; - uint32_t mpm = -1; uint32_t nonmpm = -1; det_ctx->match_array_cnt = 0; - while (1) { - if (m < det_ctx->pmq.rule_id_array_cnt) - mpm = det_ctx->pmq.rule_id_array[m]; - else - mpm = -1; - if (n < sgh->non_mpm_id_cnt) - nonmpm = sgh->non_mpm_id_array[n]; - else - nonmpm = -1; - + uint32_t *mpm_ptr = det_ctx->pmq.rule_id_array; + uint32_t *nonmpm_ptr = sgh->non_mpm_id_array; + uint32_t m_cnt = det_ctx->pmq.rule_id_array_cnt; + uint32_t n_cnt = sgh->non_mpm_id_cnt; + SCLogDebug("PMQ rule id array count %d", det_ctx->pmq.rule_id_array_cnt); + SCLogDebug("SGH non-MPM id count %d", sgh->non_mpm_id_cnt); + + /* Load first values. */ + if (likely(m_cnt)) { + mpm = *(mpm_ptr++); + m_cnt--; + } else + mpm = -1; + if (likely(n_cnt)) { + nonmpm = *(nonmpm_ptr++); + n_cnt--; + } else + nonmpm = -1; + + uint32_t previous_id = (uint32_t)-1; + Signature **sig_array = de_ctx->sig_array; + Signature **match_array = det_ctx->match_array; + Signature *s; + while (1) { uint32_t id = MIN(mpm, nonmpm); - if (id == (uint32_t)-1) - return; - else if (id == mpm) { - m++; - BUG_ON(m > det_ctx->pmq.rule_id_array_cnt); - } else if (id == nonmpm) { - n++; - BUG_ON(n > sgh->non_mpm_id_cnt); - } - - Signature *s = de_ctx->sig_array[id]; - - /* as the mpm list can contain duplicates, check for this here */ - if (det_ctx->match_array_cnt == 0 || det_ctx->match_array[det_ctx->match_array_cnt - 1] != s) - det_ctx->match_array[det_ctx->match_array_cnt++] = s; - - if (m >= det_ctx->pmq.rule_id_array_cnt && n >= sgh->non_mpm_id_cnt) + if (unlikely(id == (uint32_t)-1)) break; + else { + s = sig_array[id]; + + if (id == mpm) { + if (likely(m_cnt)) { + mpm = *(mpm_ptr++); + m_cnt--; + } else + mpm = -1; // TODO - at this point, just copy of remaining array onto the end of the list. + } else { // (id == nonmpm) + if (likely(n_cnt)) { + nonmpm = *(nonmpm_ptr++); + n_cnt--; + } else + nonmpm = -1; + } + } + /* As the mpm list can contain duplicates, check for that here. */ + if (likely(id != previous_id)) { + *match_array++ = s; + previous_id = id; + } } + det_ctx->match_array_cnt = match_array - det_ctx->match_array; + BUG_ON((det_ctx->pmq.rule_id_array_cnt + sgh->non_mpm_id_cnt) < det_ctx->match_array_cnt); } @@ -1384,6 +1403,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh DetectPrefilterMergeSort(de_ctx, det_ctx, det_ctx->sgh); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PREFILTER); + SCLogDebug("match array count %d", det_ctx->match_array_cnt); + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_RULES); /* inspect the sigs against the packet */ for (idx = 0; idx < det_ctx->match_array_cnt; idx++) { From d31db4ed1c91a72d2518ec9646d9812b0b9ba22c Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Tue, 30 Sep 2014 13:04:27 -0400 Subject: [PATCH 0164/2553] Fix clang warning Clang doesn't seem to like defining a function within a function. --- src/detect.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/detect.c b/src/detect.c index 6b7537a7db3e..430986aea78f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -837,6 +837,13 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, BUG_ON((det_ctx->pmq.rule_id_array_cnt + sgh->non_mpm_id_cnt) < det_ctx->match_array_cnt); } +static int DoSort(const void *a, const void *b) +{ + uint32_t x = *(uint32_t *)a; + uint32_t y = *(uint32_t *)b; + return x - y; +} + #define SMS_USE_FLOW_SGH 0x01 #define SMS_USED_PM 0x02 #define SMS_USED_STREAM_PM 0x04 @@ -1087,11 +1094,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, /* Sort the rule list to lets look at pmq. * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ if (det_ctx->pmq.rule_id_array_cnt) { - int DoSort(const void *a, const void *b) { - uint32_t x = *(uint32_t *)a; - uint32_t y = *(uint32_t *)b; - return x - y; - } qsort(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt, sizeof(uint32_t), DoSort); } From 104a9034787a09420e779ff921f3de437e0b7272 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 3 Oct 2014 13:30:57 -0400 Subject: [PATCH 0165/2553] Dynamically resize pmq->rule_id_array Rather than statically allocate 64K entries in every rule_id_array, increase the size only when needed. Created a new function MpmAddSids() to check the size before adding the new sids. If the array is not large enough, it calls MpmAddSidsResize() that calls realloc and does error checking. If the realloc fails, it prints an error and drops the new sids on the floor, which seems better than exiting Suricata. The size is increased to (current_size + new_count) * 2. This handles the case where new_count > current_size, which would not be handled by simply using current_size * 2. It should also be faster than simply reallocing to current_size + new_count, which would then require another realloc for each new addition. --- src/util-mpm-ac-bs.c | 54 ++++++++++++++--------------------- src/util-mpm-ac-gfbs.c | 50 +++++++++++++------------------- src/util-mpm-ac-tile.c | 40 +++++++++++--------------- src/util-mpm-ac.c | 65 ++++++++++++++++++------------------------ src/util-mpm.c | 57 +++++++++++++++++++++++++----------- src/util-mpm.h | 34 ++++++++++++++++++++-- 6 files changed, 160 insertions(+), 140 deletions(-) diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 9ea9eed895c3..6d58d6f61e4b 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -1490,23 +1490,21 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t k; for (k = 0; k < no_of_entries; k++) { if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; - - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = lower_pid; + + MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1517,10 +1515,7 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1583,23 +1578,21 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t k; for (k = 0; k < no_of_entries; k++) { if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; - - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = lower_pid; + + MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1610,10 +1603,7 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; } diff --git a/src/util-mpm-ac-gfbs.c b/src/util-mpm-ac-gfbs.c index 8ccb8e3f4309..5670f66828cd 100644 --- a/src/util-mpm-ac-gfbs.c +++ b/src/util-mpm-ac-gfbs.c @@ -1402,24 +1402,22 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t k = 0; for (k = 0; k < no_of_pid_entries; k++) { if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (pids[k] & 0x0000FFFF); + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (lower_pid); - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1430,10 +1428,7 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1539,24 +1534,22 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t k = 0; for (k = 0; k < no_of_pid_entries; k++) { if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (pids[k] & 0x0000FFFF); + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (lower_pid); - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1567,10 +1560,7 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; } diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index e34911de961f..21750f1a6ec0 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -1496,12 +1496,8 @@ int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, pmq_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); *new_pattern++ = lower_pid; - // Add SIDs for this pattern - // TODO - Keep local pointer to update. - uint32_t x; - for (x = 0; x < pid_pat_list[lower_pid].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[lower_pid].sids[x]; - } + MpmAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } @@ -1562,24 +1558,23 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct uint32_t k; for (k = 0; k < no_of_entries; k++) { if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= - (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = - pids[k] & 0x0000FFFF; - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_bitarray[(lower_pid) / 8] |= + (1 << ((lower_pid) % 8)); + pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = lower_pid; + + MpmAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1589,10 +1584,9 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k]].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k]].sids[x]; - } + + MpmAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index f6c462ea2576..9aed573efd0c 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -1321,23 +1321,21 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t k; for (k = 0; k < no_of_entries; k++) { if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; - - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = lower_pid; + + MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1347,10 +1345,7 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, pmq->pattern_id_bitarray[(pids[k]) / 8] |= (1 << ((pids[k]) % 8)); bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k]].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k]].sids[x]; - } + MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1371,23 +1366,21 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t k; for (k = 0; k < no_of_entries; k++) { if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; - - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k] & 0x0000FFFF].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k] & 0x0000FFFF].sids[x]; - } + pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = lower_pid; + + MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1398,10 +1391,7 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - uint32_t x; - for (x = 0; x < pid_pat_list[pids[k]].sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = pid_pat_list[pids[k]].sids[x]; - } + MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; } @@ -2067,16 +2057,17 @@ uint32_t SCACCudaPacketResultsProcessing(Packet *p, MpmCtx *mpm_ctx, * the only change */ for (k = 0; k < no_of_entries; k++) { if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + offset - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + offset - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (pmq->pattern_id_bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); + pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); } matches++; } else { diff --git a/src/util-mpm.c b/src/util-mpm.c index cc466177f4a1..cb11215f7b14 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* 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 @@ -451,29 +451,58 @@ int PmqSetup(PatternMatcherQueue *pmq, uint32_t patmaxid) SCLogDebug("pmq->pattern_id_array %p, pmq->pattern_id_bitarray %p", pmq->pattern_id_array, pmq->pattern_id_bitarray); - pmq->rule_id_array_size = 65536 * sizeof(uint32_t); + pmq->rule_id_array_size = 128; + pmq->rule_id_array_cnt = 0; - pmq->rule_id_array = SCMalloc(pmq->rule_id_array_size); + uint32_t bytes = pmq->rule_id_array_size * sizeof(uint32_t); + pmq->rule_id_array = SCMalloc(bytes); if (pmq->rule_id_array == NULL) { + pmq->rule_id_array_size = 0; SCReturnInt(-1); } - memset(pmq->rule_id_array, 0, pmq->rule_id_array_size); - pmq->rule_id_array_cnt = 0; - + // Don't need to zero memory since it is always written first. } SCReturnInt(0); } +/** \brief Add array of Signature IDs to rule ID array. + * + * Checks size of the array first + * + * \param pmq storage for match results + * \param new_size number of Signature IDs needing to be stored. + * + */ +void +MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size) +{ + /* Need to make the array bigger. Double the size needed to + * also handle the case that sids_size might still be + * larger than the old size. + */ + new_size = new_size * 2; + uint32_t *new_array = (uint32_t*)SCRealloc(pmq->rule_id_array, + new_size * sizeof(uint32_t)); + if (unlikely(new_array == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to realloc PatternMatchQueue" + " rule ID array. Some signature ID matches lost"); + return; + } + pmq->rule_id_array = new_array; + pmq->rule_id_array_size = new_size; +} + /** \brief Verify and store a match * * used at search runtime * * \param thread_ctx mpm thread ctx * \param pmq storage for match results - * \param list end match to check against (entire list will be checked) - * \param offset match offset in the buffer - * \param patlen length of the pattern we're checking + * \param patid pattern ID being checked + * \param bitarray Array of bits for patterns IDs found in current search + * \param sids pointer to array of Signature IDs + * \param sids_size number of Signature IDs in sids array. * * \retval 0 no match after all * \retval 1 (new) match @@ -497,13 +526,7 @@ MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t pati pmq->pattern_id_array_cnt++; SCLogDebug("pattern_id_array_cnt %u", pmq->pattern_id_array_cnt); - SCLogDebug("Adding %u sids", sids_size); - // Add SIDs for this pattern - uint32_t x; - for (x = 0; x < sids_size; x++) { - pmq->rule_id_array[pmq->rule_id_array_cnt++] = sids[x]; - } - + MpmAddSids(pmq, sids, sids_size); } } @@ -557,6 +580,7 @@ void PmqReset(PatternMatcherQueue *pmq) pmq->pattern_id_array_cnt = 0; */ pmq->rule_id_array_cnt = 0; + /* TODO: Realloc the rule id array smaller at some size? */ } /** \brief Cleanup a Pmq @@ -583,6 +607,7 @@ void PmqCleanup(PatternMatcherQueue *pmq) } pmq->pattern_id_array_cnt = 0; + pmq->pattern_id_array_size = 0; } /** \brief Cleanup and free a Pmq diff --git a/src/util-mpm.h b/src/util-mpm.h index cf5a7335c9b4..7c0ccc94a146 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* 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 @@ -108,9 +108,12 @@ typedef struct PatternMatcherQueue_ { uint32_t pattern_id_bitarray_size; /**< size in bytes */ /* used for storing rule id's */ - uint32_t rule_id_array_size; + /* Array of rule IDs found. */ uint32_t *rule_id_array; + /* Number of rule IDs in the array. */ uint32_t rule_id_array_cnt; + /* The number of slots allocated for storing rule IDs */ + uint32_t rule_id_array_size; } PatternMatcherQueue; @@ -263,4 +266,31 @@ int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags); +/* Resize ID array. Only called from MpmAddSids(). */ +void MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size); + +/** \brief Add array of Signature IDs to rule ID array. + * + * Checks size of the array first. Calls MpmAddSidsResize to increase + * The size of the array, since that is the slow path. + * + * \param pmq storage for match results + * \param sids pointer to array of Signature IDs + * \param sids_size number of Signature IDs in sids array. + * + */ +static inline void +MpmAddSids(PatternMatcherQueue *pmq, uint32_t *sids, uint32_t sids_size) +{ + uint32_t new_size = pmq->rule_id_array_cnt + sids_size; + if (new_size > pmq->rule_id_array_size) { + MpmAddSidsResize(pmq, new_size); + } + SCLogDebug("Adding %u sids", sids_size); + // Add SIDs for this pattern to the end of the array + memcpy(pmq->rule_id_array + pmq->rule_id_array_cnt, + sids, sids_size * sizeof(uint32_t)); + pmq->rule_id_array_cnt += sids_size; +} + #endif /* __UTIL_MPM_H__ */ From ab8b1158b07f4d58171d560bc3f34e4cc379e738 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Wed, 8 Oct 2014 14:36:29 -0400 Subject: [PATCH 0166/2553] Dynamically resize pattern id array as needed Rather than creating the array of size maxpatid, dynamically resize as needed. This also handles the case where duplicate pid are added to the array. Also fix error in bitarray allocation (local version) to always use bitarray_size. --- src/util-mpm-ac-bs.c | 9 ++++---- src/util-mpm-ac-gfbs.c | 8 +++---- src/util-mpm-ac.c | 5 ++--- src/util-mpm.c | 49 +++++++++++++++++++++++++++--------------- src/util-mpm.h | 17 +++++++++++++-- 5 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 6d58d6f61e4b..c706c0982192 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -1502,8 +1502,7 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = lower_pid; - + MpmAddPid(pmq, lower_pid); MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; @@ -1513,8 +1512,8 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + MpmAddPid(pmq, pids[k]); MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; @@ -1590,8 +1589,8 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = lower_pid; + MpmAddPid(pmq, lower_pid); MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; @@ -1601,8 +1600,8 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + MpmAddPid(pmq, pids[k]); MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; diff --git a/src/util-mpm-ac-gfbs.c b/src/util-mpm-ac-gfbs.c index 5670f66828cd..523aa0ff95ac 100644 --- a/src/util-mpm-ac-gfbs.c +++ b/src/util-mpm-ac-gfbs.c @@ -1415,8 +1415,8 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (lower_pid); + MpmAddPid(pmq, lower_pid); MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; @@ -1426,8 +1426,8 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + MpmAddPid(pmq, pids[k]); MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; @@ -1547,8 +1547,8 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (lower_pid); + MpmAddPid(pmq, lower_pid); MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; @@ -1558,8 +1558,8 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + MpmAddPid(pmq, pids[k]); MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 9aed573efd0c..7df1caa2a9bc 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -1333,8 +1333,7 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = lower_pid; - + MpmAddPid(pmq, lower_pid); MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; @@ -1344,7 +1343,7 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { pmq->pattern_id_bitarray[(pids[k]) / 8] |= (1 << ((pids[k]) % 8)); bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + MpmAddPid(pmq, pids[k]); MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; diff --git a/src/util-mpm.c b/src/util-mpm.c index cb11215f7b14..5a90e36139b9 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -430,14 +430,13 @@ int PmqSetup(PatternMatcherQueue *pmq, uint32_t patmaxid) memset(pmq, 0, sizeof(PatternMatcherQueue)); if (patmaxid > 0) { - pmq->pattern_id_array_size = patmaxid * sizeof(uint32_t); + pmq->pattern_id_array_size = 32; /* Intial size, TODO Make this configure option */ + pmq->pattern_id_array_cnt = 0; - pmq->pattern_id_array = SCMalloc(pmq->pattern_id_array_size); + pmq->pattern_id_array = SCCalloc(pmq->pattern_id_array_size, sizeof(uint32_t)); if (pmq->pattern_id_array == NULL) { SCReturnInt(-1); } - memset(pmq->pattern_id_array, 0, pmq->pattern_id_array_size); - pmq->pattern_id_array_cnt = 0; /* lookup bitarray */ pmq->pattern_id_bitarray_size = (patmaxid / 8) + 1; @@ -451,7 +450,7 @@ int PmqSetup(PatternMatcherQueue *pmq, uint32_t patmaxid) SCLogDebug("pmq->pattern_id_array %p, pmq->pattern_id_bitarray %p", pmq->pattern_id_array, pmq->pattern_id_bitarray); - pmq->rule_id_array_size = 128; + pmq->rule_id_array_size = 128; /* Initial size, TODO: Make configure option. */ pmq->rule_id_array_cnt = 0; uint32_t bytes = pmq->rule_id_array_size * sizeof(uint32_t); @@ -493,6 +492,31 @@ MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size) pmq->rule_id_array_size = new_size; } +/** \brief Increase the size of the Pattern rule ID array. + * + * \param pmq storage for match results + * \param new_size number of Signature IDs needing to be stored. + * + */ +void +MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size) +{ + /* Need to make the array bigger. Double the size needed to + * also handle the case that sids_size might still be + * larger than the old size. + */ + new_size = new_size * 2; + uint32_t *new_array = (uint32_t*)SCRealloc(pmq->pattern_id_array, + new_size * sizeof(uint32_t)); + if (unlikely(new_array == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to realloc PatternMatchQueue" + " pattern ID array. Some new Pattern ID matches were lost."); + return; + } + pmq->pattern_id_array = new_array; + pmq->pattern_id_array_size = new_size; +} + /** \brief Verify and store a match * * used at search runtime @@ -522,10 +546,7 @@ MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t pati /* flag this pattern id as being added now */ pmq->pattern_id_bitarray[(patid / 8)] |= (1<<(patid % 8)); /* append the pattern_id to the array with matches */ - pmq->pattern_id_array[pmq->pattern_id_array_cnt] = patid; - pmq->pattern_id_array_cnt++; - SCLogDebug("pattern_id_array_cnt %u", pmq->pattern_id_array_cnt); - + MpmAddPid(pmq, patid); MpmAddSids(pmq, sids, sids_size); } } @@ -570,15 +591,9 @@ void PmqReset(PatternMatcherQueue *pmq) return; memset(pmq->pattern_id_bitarray, 0, pmq->pattern_id_bitarray_size); - //memset(pmq->pattern_id_array, 0, pmq->pattern_id_array_size); - pmq->pattern_id_array_cnt = 0; -/* - uint32_t u; - for (u = 0; u < pmq->pattern_id_array_cnt; u++) { - pmq->pattern_id_bitarray[(pmq->pattern_id_array[u] / 8)] &= ~(1<<(pmq->pattern_id_array[u] % 8)); - } + pmq->pattern_id_array_cnt = 0; -*/ + pmq->rule_id_array_cnt = 0; /* TODO: Realloc the rule id array smaller at some size? */ } diff --git a/src/util-mpm.h b/src/util-mpm.h index 7c0ccc94a146..d1ebeef8d918 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -266,7 +266,7 @@ int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags); -/* Resize ID array. Only called from MpmAddSids(). */ +/* Resize Signature ID array. Only called from MpmAddSids(). */ void MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size); /** \brief Add array of Signature IDs to rule ID array. @@ -284,7 +284,7 @@ MpmAddSids(PatternMatcherQueue *pmq, uint32_t *sids, uint32_t sids_size) { uint32_t new_size = pmq->rule_id_array_cnt + sids_size; if (new_size > pmq->rule_id_array_size) { - MpmAddSidsResize(pmq, new_size); + MpmAddSidsResize(pmq, new_size); } SCLogDebug("Adding %u sids", sids_size); // Add SIDs for this pattern to the end of the array @@ -293,4 +293,17 @@ MpmAddSids(PatternMatcherQueue *pmq, uint32_t *sids, uint32_t sids_size) pmq->rule_id_array_cnt += sids_size; } +/* Resize Pattern ID array. Only called from MpmAddPid(). */ +void MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size); + +static inline void +MpmAddPid(PatternMatcherQueue *pmq, uint32_t patid) +{ + uint32_t new_size = pmq->pattern_id_array_cnt + 1; + if (new_size > pmq->pattern_id_array_size) + MpmAddPidResize(pmq, new_size); + pmq->pattern_id_array[pmq->pattern_id_array_cnt] = patid; + pmq->pattern_id_array_cnt = new_size; + SCLogDebug("pattern_id_array_cnt %u", pmq->pattern_id_array_cnt); +} #endif /* __UTIL_MPM_H__ */ From 1c03eb56d0a9af1ca8015638d96b0f676c010ff3 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Thu, 6 Nov 2014 14:57:53 -0500 Subject: [PATCH 0167/2553] Fix bug in MPM rule array handling In PmqMerge() use MpmAddSids() instead of blindly copying the src rule list onto the end of the dst rule list, since there might not be enough room in the dst list. MpmAddSids() will resize the dst array if needed. Also add code to MpmAddSids() MpmAddPid() to better handle the case that realloc fails to get more space. It first tries 2x the needed space, but if that fails, it tries for just 1x. If that fails resize returns 0. For MpmAddPid(), if resize fails, the new pid is lost. For MpmAddSids(), as many SIDs as will fit are added, but some will be lost. --- src/util-mpm.c | 40 +++++++++++++++++++++++++++------------- src/util-mpm.h | 16 +++++++++++----- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/util-mpm.c b/src/util-mpm.c index 5a90e36139b9..9a3da161d031 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -473,7 +473,7 @@ int PmqSetup(PatternMatcherQueue *pmq, uint32_t patmaxid) * \param new_size number of Signature IDs needing to be stored. * */ -void +int MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size) { /* Need to make the array bigger. Double the size needed to @@ -484,12 +484,21 @@ MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size) uint32_t *new_array = (uint32_t*)SCRealloc(pmq->rule_id_array, new_size * sizeof(uint32_t)); if (unlikely(new_array == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Failed to realloc PatternMatchQueue" - " rule ID array. Some signature ID matches lost"); - return; + /* Try again just big enough. */ + new_size = new_size / 2; + new_array = (SigIntId*)SCRealloc(pmq->rule_id_array, + new_size * sizeof(SigIntId)); + if (unlikely(new_array == NULL)) { + + SCLogError(SC_ERR_MEM_ALLOC, "Failed to realloc PatternMatchQueue" + " rule ID array. Some signature ID matches lost"); + return 0; + } } pmq->rule_id_array = new_array; pmq->rule_id_array_size = new_size; + + return new_size; } /** \brief Increase the size of the Pattern rule ID array. @@ -497,8 +506,9 @@ MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size) * \param pmq storage for match results * \param new_size number of Signature IDs needing to be stored. * + * \return 0 on failure. */ -void +int MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size) { /* Need to make the array bigger. Double the size needed to @@ -509,12 +519,20 @@ MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size) uint32_t *new_array = (uint32_t*)SCRealloc(pmq->pattern_id_array, new_size * sizeof(uint32_t)); if (unlikely(new_array == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Failed to realloc PatternMatchQueue" - " pattern ID array. Some new Pattern ID matches were lost."); - return; + // Failed to allocate 2x, so try 1x. + new_size = new_size / 2; + new_array = (uint32_t*)SCRealloc(pmq->pattern_id_array, + new_size * sizeof(uint32_t)); + if (unlikely(new_array == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to realloc PatternMatchQueue" + " pattern ID array. Some new Pattern ID matches were lost."); + return 0; + } } pmq->pattern_id_array = new_array; pmq->pattern_id_array_size = new_size; + + return new_size; } /** \brief Verify and store a match @@ -573,11 +591,7 @@ void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst) /** \todo now set merged flag? */ - if (src->rule_id_array && dst->rule_id_array) { - for (u = 0; u < src->rule_id_array_cnt; u++) { - dst->rule_id_array[dst->rule_id_array_cnt++] = src->rule_id_array[u]; - } - } + MpmAddSids(dst, src->rule_id_array, src->rule_id_array_cnt); } /** \brief Reset a Pmq for reusage. Meant to be called after a single search. diff --git a/src/util-mpm.h b/src/util-mpm.h index d1ebeef8d918..e88e717194a5 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -267,7 +267,7 @@ int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint32_t pid, uint32_t sid, uint8_t flags); /* Resize Signature ID array. Only called from MpmAddSids(). */ -void MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size); +int MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size); /** \brief Add array of Signature IDs to rule ID array. * @@ -284,7 +284,11 @@ MpmAddSids(PatternMatcherQueue *pmq, uint32_t *sids, uint32_t sids_size) { uint32_t new_size = pmq->rule_id_array_cnt + sids_size; if (new_size > pmq->rule_id_array_size) { - MpmAddSidsResize(pmq, new_size); + if (MpmAddSidsResize(pmq, new_size) == 0) { + // Failed to allocate larger memory for all the SIDS, but + // keep as many as we can. + sids_size = pmq->rule_id_array_size - pmq->rule_id_array_cnt; + } } SCLogDebug("Adding %u sids", sids_size); // Add SIDs for this pattern to the end of the array @@ -294,14 +298,16 @@ MpmAddSids(PatternMatcherQueue *pmq, uint32_t *sids, uint32_t sids_size) } /* Resize Pattern ID array. Only called from MpmAddPid(). */ -void MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size); +int MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size); static inline void MpmAddPid(PatternMatcherQueue *pmq, uint32_t patid) { uint32_t new_size = pmq->pattern_id_array_cnt + 1; - if (new_size > pmq->pattern_id_array_size) - MpmAddPidResize(pmq, new_size); + if (new_size > pmq->pattern_id_array_size) { + if (MpmAddPidResize(pmq, new_size) == 0) + return; + } pmq->pattern_id_array[pmq->pattern_id_array_cnt] = patid; pmq->pattern_id_array_cnt = new_size; SCLogDebug("pattern_id_array_cnt %u", pmq->pattern_id_array_cnt); From eaac9c8d938b5d898813438505429e2da1562e62 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 7 Nov 2014 10:52:08 -0500 Subject: [PATCH 0168/2553] fix check in PmqMerge --- src/util-mpm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util-mpm.c b/src/util-mpm.c index 9a3da161d031..157eb58700b3 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -591,7 +591,9 @@ void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst) /** \todo now set merged flag? */ - MpmAddSids(dst, src->rule_id_array, src->rule_id_array_cnt); + if (src->rule_id_array && dst->rule_id_array) { + MpmAddSids(dst, src->rule_id_array, src->rule_id_array_cnt); + } } /** \brief Reset a Pmq for reusage. Meant to be called after a single search. From 77269fbb2c5d6b6621a8c9198d8a3e2c02090e26 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Mon, 17 Nov 2014 10:24:27 -0500 Subject: [PATCH 0169/2553] Fix missing use of MpmAddPid() Found by Victor using ASAN. One place was not checking to resize the pid array before adding a new PID. --- src/util-mpm-ac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 7df1caa2a9bc..01263d177f37 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -1377,8 +1377,7 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = lower_pid; - + MpmAddPid(pmq, lower_pid); MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; @@ -1388,8 +1387,7 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } else { pmq->pattern_id_bitarray[(pids[k]) / 8] |= (1 << ((pids[k]) % 8)); bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - + MpmAddPid(pmq, pids[k]); MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; From 7a2095d851e9f67901125e7ff56f6572e4ca82c4 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 3 Oct 2014 17:12:06 -0400 Subject: [PATCH 0170/2553] In AC-Tile, convert from using pids for indexing to pattern index Use an MPM specific pattern index, which is simply an index starting at zero and incremented for each pattern added to the MPM, rather than the externally provided Pattern ID (pid), since that can be much larger than the number of patterns. The Pattern ID is shared across at MPMs. For example, an MPM with one pattern with pid=8000 would result in a max_pid of 8000, so the pid_pat_list would have 8000 entries. The pid_pat_list[] is replaced by a array of pattern indexes. The PID is moved to the SCACTilePatternList as a single value. The PatternList is also indexed by the Pattern Index. max_pat_id is no longer needed and mpm_ctx->pattern_cnt is used instead. The local bitarray is then also indexed by pattern index instead of PID, making it much smaller. The local bit array sets a bit for each pattern found for this MPM. It is only kept during one MPM search (stack allocated). One note, the local bit array is checked first and if the pattern has already been found, it will stop checking, but count a match. This could result in over counting matches of case-sensitve matches, since following case-insensitive matches will also be counted. For example, finding "Foo" in "foo Foo foo" would report finding "Foo" 2 times, mis-counting the third word as "Foo". --- src/util-mpm-ac-tile-small.c | 14 +-- src/util-mpm-ac-tile.c | 193 +++++++++++++++-------------------- src/util-mpm-ac-tile.h | 22 ++-- src/util-mpm.h | 7 +- 4 files changed, 107 insertions(+), 129 deletions(-) diff --git a/src/util-mpm-ac-tile-small.c b/src/util-mpm-ac-tile-small.c index 3390a917cb5d..a99da0634e6e 100644 --- a/src/util-mpm-ac-tile-small.c +++ b/src/util-mpm-ac-tile-small.c @@ -37,8 +37,8 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, int i = 0; int matches = 0; - uint8_t bitarray[pmq->pattern_id_bitarray_size]; - memset(bitarray, 0, pmq->pattern_id_bitarray_size); + uint8_t mpm_bitarray[ctx->mpm_bitarray_size]; + memset(mpm_bitarray, 0, ctx->mpm_bitarray_size); uint8_t* restrict xlate = ctx->translate_table; STYPE *state_table = (STYPE*)ctx->state_table; @@ -56,21 +56,21 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, state = SLOAD(state_table + index + c); c = xlate[BYTE1(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, bitarray); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } i++; index = SINDEX(index, state); state = SLOAD(state_table + index + c); c = xlate[BYTE2(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, bitarray); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } i++; index = SINDEX(index, state); state = SLOAD(state_table + index + c); c = xlate[BYTE3(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, bitarray); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } data = data1; i++; @@ -78,7 +78,7 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, state = SLOAD(state_table + index + c); c = xlate[BYTE0(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, bitarray); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } i++; } @@ -90,7 +90,7 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, state = SLOAD(state_table + index + c); c = xlate[buf[i+1]]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, bitarray); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } } /* for (i = 0; i < buflen; i++) */ diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 21750f1a6ec0..7c098835f441 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -511,10 +511,6 @@ static int SCACTileAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, mpm_ctx->minlen = patlen; } - /* we need the max pat id */ - if (pid > ctx->max_pat_id) - ctx->max_pat_id = pid; - p->sids_size = 1; p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); BUG_ON(p->sids == NULL); @@ -625,7 +621,7 @@ static inline int SCACTileInitNewState(MpmCtx *mpm_ctx) * \param pid The pattern id to add. * \param mpm_ctx Pointer to the mpm context. */ -static void SCACTileSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) +static void SCACTileSetOutputState(int32_t state, MpmPatternIndex pindex, MpmCtx *mpm_ctx) { void *ptmp; SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; @@ -636,24 +632,24 @@ static void SCACTileSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) /* Don't add the pattern more than once to the same state. */ for (i = 0; i < output_state->no_of_entries; i++) { - if (output_state->pids[i] == pid) + if (output_state->patterns[i] == pindex) return; } /* Increase the size of the array of pids for this state and add * the new pid. */ output_state->no_of_entries++; - ptmp = SCRealloc(output_state->pids, - output_state->no_of_entries * sizeof(uint32_t)); + ptmp = SCRealloc(output_state->patterns, + output_state->no_of_entries * sizeof(MpmPatternIndex)); if (ptmp == NULL) { - SCFree(output_state->pids); - output_state->pids = NULL; + SCFree(output_state->patterns); + output_state->patterns = NULL; SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - output_state->pids = ptmp; + output_state->patterns = ptmp; - output_state->pids[output_state->no_of_entries - 1] = pid; + output_state->patterns[output_state->no_of_entries - 1] = pindex; } /** @@ -667,7 +663,7 @@ static void SCACTileSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) * \param mpm_ctx Pointer to the mpm context. */ static void SCACTileEnter(uint8_t *pattern, uint16_t pattern_len, - uint32_t pid, MpmCtx *mpm_ctx) + MpmPatternIndex pindex, MpmCtx *mpm_ctx) { SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; SCACTileCtx *ctx = search_ctx->init_ctx; @@ -698,7 +694,7 @@ static void SCACTileEnter(uint8_t *pattern, uint16_t pattern_len, /* Add this pattern id, to the output table of the last state, where the * pattern ends in the trie */ - SCACTileSetOutputState(state, pid, mpm_ctx); + SCACTileSetOutputState(state, pindex, mpm_ctx); } /** @@ -717,7 +713,7 @@ static void SCACTileCreateGotoTable(MpmCtx *mpm_ctx) /* add each pattern to create the goto table */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { SCACTileEnter(ctx->parray[i]->ci, ctx->parray[i]->len, - ctx->parray[i]->id, mpm_ctx); + i, mpm_ctx); } int aa = 0; @@ -797,25 +793,25 @@ static void SCACTileClubOutputStates(int32_t dst_state, for (i = 0; i < output_src_state->no_of_entries; i++) { for (j = 0; j < output_dst_state->no_of_entries; j++) { - if (output_src_state->pids[i] == output_dst_state->pids[j]) { + if (output_src_state->patterns[i] == output_dst_state->patterns[j]) { break; } } if (j == output_dst_state->no_of_entries) { output_dst_state->no_of_entries++; - ptmp = SCRealloc(output_dst_state->pids, + ptmp = SCRealloc(output_dst_state->patterns, (output_dst_state->no_of_entries * sizeof(uint32_t))); if (ptmp == NULL) { - SCFree(output_dst_state->pids); - output_dst_state->pids = NULL; + SCFree(output_dst_state->patterns); + output_dst_state->patterns = NULL; SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - output_dst_state->pids = ptmp; + output_dst_state->patterns = ptmp; - output_dst_state->pids[output_dst_state->no_of_entries - 1] = - output_src_state->pids[i]; + output_dst_state->patterns[output_dst_state->no_of_entries - 1] = + output_src_state->patterns[i]; } } } @@ -1083,9 +1079,10 @@ static inline void SCACTileInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx continue; for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { - if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { - ctx->output_table[state].pids[k] &= 0x0000FFFF; - ctx->output_table[state].pids[k] |= 1 << 16; + if (ctx->pattern_list[ctx->output_table[state].patterns[k]].cs != NULL) { + /* TODO - Find better way to store this. */ + ctx->output_table[state].patterns[k] &= 0x0000FFFF; + ctx->output_table[state].patterns[k] |= 1 << 16; } } } @@ -1178,8 +1175,11 @@ static void SCACTilePrepareSearch(MpmCtx *mpm_ctx) search_ctx->output_table = ctx->output_table; ctx->output_table = NULL; - search_ctx->pid_pat_list = ctx->pid_pat_list; - ctx->pid_pat_list = NULL; + search_ctx->pattern_list = ctx->pattern_list; + ctx->pattern_list = NULL; + + /* One bit per pattern, rounded up to the next byte size. */ + search_ctx->mpm_bitarray_size = (mpm_ctx->pattern_cnt + 7) / 8; /* Can now free the Initialization data */ SCACTileDestroyInitCtx(mpm_ctx); @@ -1241,7 +1241,7 @@ int SCACTilePreparePatterns(MpmCtx *mpm_ctx) } } - size_t pattern_list_size = (ctx->max_pat_id + 1) * sizeof(SCACTilePatternList); + size_t pattern_list_size = mpm_ctx->pattern_cnt * sizeof(SCACTilePatternList); size_t mem_size = string_space_needed + pattern_list_size; void *mem_block = SCCalloc(1, mem_size); if (mem_block == NULL) { @@ -1251,7 +1251,7 @@ int SCACTilePreparePatterns(MpmCtx *mpm_ctx) mpm_ctx->memory_cnt++; mpm_ctx->memory_size += mem_size; /* Split the allocated block into pattern list array and string space. */ - ctx->pid_pat_list = mem_block; + ctx->pattern_list = mem_block; uint8_t *string_space = mem_block + pattern_list_size; /* Now make the copies of the no-case strings. */ @@ -1260,15 +1260,15 @@ int SCACTilePreparePatterns(MpmCtx *mpm_ctx) uint32_t len = ctx->parray[i]->len; uint32_t space = ((len + 7) / 8) * 8; memcpy(string_space, ctx->parray[i]->original_pat, len); - ctx->pid_pat_list[ctx->parray[i]->id].cs = string_space; - ctx->pid_pat_list[ctx->parray[i]->id].patlen = len; + ctx->pattern_list[i].cs = string_space; + ctx->pattern_list[i].patlen = len; string_space += space; } + ctx->pattern_list[i].pid = ctx->parray[i]->id; /* ACPatternList now owns this memory */ - //SCLogInfo("ctx->parray[i]->sids_size %u", ctx->parray[i]->sids_size); - ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; - ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; + ctx->pattern_list[i].sids_size = ctx->parray[i]->sids_size; + ctx->pattern_list[i].sids = ctx->parray[i]->sids; } /* prepare the state table required by AC */ @@ -1403,22 +1403,22 @@ static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx) if (ctx->output_table != NULL) { int state; for (state = 0; state < ctx->state_count; state++) { - if (ctx->output_table[state].pids != NULL) { - SCFree(ctx->output_table[state].pids); + if (ctx->output_table[state].patterns != NULL) { + SCFree(ctx->output_table[state].patterns); } } SCFree(ctx->output_table); } - if (ctx->pid_pat_list != NULL) { - int i; - for (i = 0; i < (ctx->max_pat_id + 1); i++) { - if (ctx->pid_pat_list[i].cs != NULL) - SCFree(ctx->pid_pat_list[i].cs); - if (ctx->pid_pat_list[i].sids != NULL) - SCFree(ctx->pid_pat_list[i].sids); + if (ctx->pattern_list != NULL) { + uint32_t i; + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (ctx->pattern_list[i].cs != NULL) + SCFree(ctx->pattern_list[i].cs); + if (ctx->pattern_list[i].sids != NULL) + SCFree(ctx->pattern_list[i].sids); } - SCFree(ctx->pid_pat_list); + SCFree(ctx->pattern_list); } SCFree(ctx); @@ -1443,7 +1443,7 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) /* Free Search tables */ SCFree(search_ctx->state_table); - SCFree(search_ctx->pid_pat_list); + SCFree(search_ctx->pattern_list); SCFree(search_ctx->output_table); SCFree(search_ctx); @@ -1467,45 +1467,53 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen, - uint16_t state, int i, int matches, uint8_t *bitarray) + uint16_t state, int i, int matches, + uint8_t *mpm_bitarray) { - SCACTilePatternList *pid_pat_list = ctx->pid_pat_list; + SCACTilePatternList *pattern_list = ctx->pattern_list; uint8_t *buf_offset = buf + i + 1; // Lift out of loop uint32_t no_of_entries = ctx->output_table[state].no_of_entries; - uint32_t *pids = ctx->output_table[state].pids; + uint32_t *patterns = ctx->output_table[state].patterns; uint8_t *pmq_bitarray = pmq->pattern_id_bitarray; uint32_t k; - /* Where to start storing new patterns */ - uint32_t *orig_pattern = pmq->pattern_id_array + pmq->pattern_id_array_cnt; - uint32_t *new_pattern = orig_pattern; - for (k = 0; k < no_of_entries; k++) { - uint16_t lower_pid = pids[k] & 0x0000FFFF; - if (pids[k] & 0xFFFF0000) { - uint16_t patlen = pid_pat_list[lower_pid].patlen; - if (SCMemcmp(pid_pat_list[lower_pid].cs, buf_offset - patlen, patlen) != 0) { - /* inside loop */ + MpmPatternIndex pindex = patterns[k] & 0x0000FFFF; + if (mpm_bitarray[pindex / 8] & (1 << (pindex % 8))) { + /* Pattern already seen by this MPM. */ + /* NOTE: This is faster then rechecking if it is a case-sensitive match + * since we know this pattern has already been seen, but imcrementing + * matches here could over report matches. For example if the case-sensitive + * pattern is "Foo" and the string is "Foo bar foo", matches would be reported + * as 2, when it should really be 1, since "foo" is not a true match. + */ + matches++; + continue; + } + uint32_t pid = pattern_list[pindex].pid; + /* Double check case-sensitve match now. */ + if (patterns[k] & 0xFFFF0000) { + uint16_t patlen = pattern_list[pindex].patlen; + if (SCMemcmp(pattern_list[pindex].cs, buf_offset - patlen, patlen) != 0) { + /* Case-sensitive match failed. */ continue; } } - if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { - ; - } else { - bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - *new_pattern++ = lower_pid; + /* New match found */ + mpm_bitarray[pindex / 8] |= (1 << (pindex % 8)); - MpmAddSids(pmq, pid_pat_list[lower_pid].sids, - pid_pat_list[lower_pid].sids_size); + if ((pmq_bitarray[pid / 8] & (1 << (pid % 8))) == 0) { + pmq_bitarray[(pid) / 8] |= (1 << ((pid) % 8)); + MpmAddPid(pmq, pid); } + + /* Always add the Signature IDs, since they could be different in the current MPM + * than in a previous MPM on the same PMQ when finding the same pattern. + */ + MpmAddSids(pmq, pattern_list[pindex].sids, + pattern_list[pindex].sids_size); matches++; } - /* Only update the pattern count if a new pattern was added. - * No need to compute it or dirty that cache data for no change. - */ - if (new_pattern != orig_pattern) - pmq->pattern_id_array_cnt = new_pattern - orig_pattern; return matches; } @@ -1542,10 +1550,8 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct int i = 0; int matches = 0; - SCACTilePatternList *pid_pat_list = ctx->pid_pat_list; - - uint8_t bitarray[pmq->pattern_id_bitarray_size]; - memset(bitarray, 0, pmq->pattern_id_bitarray_size); + uint8_t mpm_bitarray[ctx->mpm_bitarray_size]; + memset(mpm_bitarray, 0, ctx->mpm_bitarray_size); uint8_t* restrict xlate = ctx->translate_table; register int state = 0; @@ -1553,44 +1559,7 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct for (i = 0; i < buflen; i++) { state = state_table_u32[state & 0x00FFFFFF][xlate[buf[i]]]; if (SCHECK(state)) { - uint32_t no_of_entries = ctx->output_table[state].no_of_entries; - uint32_t *pids = ctx->output_table[state].pids; - uint32_t k; - for (k = 0; k < no_of_entries; k++) { - if (pids[k] & 0xFFFF0000) { - uint32_t lower_pid = pids[k] & 0x0000FFFF; - if (SCMemcmp(pid_pat_list[lower_pid].cs, - buf + i - pid_pat_list[lower_pid].patlen + 1, - pid_pat_list[lower_pid].patlen) != 0) { - /* inside loop */ - continue; - } - if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { - ; - } else { - bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_bitarray[(lower_pid) / 8] |= - (1 << ((lower_pid) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = lower_pid; - - MpmAddSids(pmq, pid_pat_list[lower_pid].sids, - pid_pat_list[lower_pid].sids_size); - } - matches++; - } else { - if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { - ; - } else { - bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - - MpmAddSids(pmq, pid_pat_list[pids[k]].sids, - pid_pat_list[pids[k]].sids_size); - } - matches++; - } - } + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } } /* for (i = 0; i < buflen; i++) */ diff --git a/src/util-mpm-ac-tile.h b/src/util-mpm-ac-tile.h index 9682bd9ead09..33a4ceac1714 100644 --- a/src/util-mpm-ac-tile.h +++ b/src/util-mpm-ac-tile.h @@ -51,15 +51,18 @@ typedef struct SCACTilePatternList_ { uint8_t *cs; uint16_t patlen; + /* Pattern Id */ + uint32_t pid; + /* sid(s) for this pattern */ uint32_t sids_size; uint32_t *sids; } SCACTilePatternList; typedef struct SCACTileOutputTable_ { - /* list of pattern sids */ - uint32_t *pids; - /* no of entries we have in pids */ + /* list of pattern indexes */ + MpmPatternIndex *patterns; + /* number of entries in pattern list */ uint32_t no_of_entries; } SCACTileOutputTable; @@ -90,8 +93,10 @@ typedef struct SCACTileCtx_ { void (*set_next_state)(struct SCACTileCtx_ *ctx, int state, int aa, int new_state, int outputs); + /* List of patterns that match for this state. Indexed by State Number */ SCACTileOutputTable *output_table; - SCACTilePatternList *pid_pat_list; + /* Indexed by MpmPatternIndex */ + SCACTilePatternList *pattern_list; /* hash used during ctx initialization */ SCACTilePattern **init_hash; @@ -111,9 +116,6 @@ typedef struct SCACTileCtx_ { /* Number of states allocated for ac-tile. */ uint32_t allocated_state_count; - /* Largest Pattern Identifier. */ - uint16_t max_pat_id; - uint32_t alpha_hist[256]; /* Number of characters in the compressed alphabet. */ uint16_t alphabet_size; @@ -147,8 +149,12 @@ typedef struct SCACTileSearchCtx_ { /* the all important memory hungry state_table */ void *state_table; + /* List of patterns that match for this state. Indexed by State Number */ SCACTileOutputTable *output_table; - SCACTilePatternList *pid_pat_list; + SCACTilePatternList *pattern_list; + + /* Number of bytes in the array of bits. One bit per pattern in this MPM. */ + uint32_t mpm_bitarray_size; /* MPM Creation data, only used at initialization. */ SCACTileCtx *init_ctx; diff --git a/src/util-mpm.h b/src/util-mpm.h index e88e717194a5..b94e0499185c 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -82,6 +82,9 @@ enum { #define DEFAULT_MPM MPM_AC #endif +/* Internal Pattern Index: 0 to pattern_cnt-1 */ +typedef uint32_t MpmPatternIndex; + typedef struct MpmMatchBucket_ { uint32_t len; } MpmMatchBucket; @@ -101,8 +104,8 @@ typedef struct PatternMatcherQueue_ { uint32_t *pattern_id_array; /** array with pattern id's that had a pattern match. These will be inspected futher by the detection engine. */ - uint32_t pattern_id_array_cnt; - uint32_t pattern_id_array_size; /**< size in bytes */ + uint32_t pattern_id_array_cnt; /**< Number currently stored */ + uint32_t pattern_id_array_size; /**< Allocated size in bytes */ uint8_t *pattern_id_bitarray; /** bitarray with pattern id matches */ uint32_t pattern_id_bitarray_size; /**< size in bytes */ From fa51118dfe05bc83afbe3732e3d03953a8280167 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 5 Sep 2014 17:21:28 -0400 Subject: [PATCH 0171/2553] Move type first in SigMatch array since it is used more often. --- src/detect.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect.h b/src/detect.h index c5a8de180536..b03a4929493c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -366,8 +366,8 @@ typedef struct SignatureHeader_ { /** \brief a single match condition for a signature */ typedef struct SigMatch_ { - uint16_t idx; /**< position in the signature */ uint8_t type; /**< match type */ + uint16_t idx; /**< position in the signature */ void *ctx; /**< plugin specific data */ struct SigMatch_ *next; struct SigMatch_ *prev; From 1c76fa50b1d89a1350e4c1842b755ded50b7ce95 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Mon, 6 Oct 2014 10:00:36 -0400 Subject: [PATCH 0172/2553] Prefetch the next signature pointer Read one signature pointer ahead to prefetch the value. Use a variable, sflags, for s->flags, since it is used many times and the compiles doesn't know that the signatures structure doesn't change, so it will reload s->flags. --- src/detect.c | 76 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/src/detect.c b/src/detect.c index 430986aea78f..ae5c7b0e7ac3 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1190,10 +1190,10 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh #ifdef PROFILING int smatch = 0; /* signature match: 1, no match: 0 */ #endif - uint32_t idx; uint8_t flags = 0; /* flow/state flags */ StreamMsg *smsg = NULL; Signature *s = NULL; + Signature *next_s = NULL; SigMatch *sm = NULL; uint16_t alversion = 0; int reset_de_state = 0; @@ -1405,22 +1405,37 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh DetectPrefilterMergeSort(de_ctx, det_ctx, det_ctx->sgh); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PREFILTER); - SCLogDebug("match array count %d", det_ctx->match_array_cnt); - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_RULES); /* inspect the sigs against the packet */ - for (idx = 0; idx < det_ctx->match_array_cnt; idx++) { + /* Prefetch the next signature. */ + SigIntId match_cnt = det_ctx->match_array_cnt; + Signature **match_array = det_ctx->match_array; + + uint32_t sflags, next_sflags = 0; + if (match_cnt) { + next_s = *match_array++; + next_sflags = next_s->flags; + } + + while (match_cnt--) { RULE_PROFILING_START(p); state_alert = 0; #ifdef PROFILING smatch = 0; #endif - s = det_ctx->match_array[idx]; + s = next_s; + sflags = next_sflags; + if (match_cnt) { + next_s = *match_array++; + next_sflags = next_s->flags; + } + uint8_t s_proto_flags = s->proto.flags; + SCLogDebug("inspecting signature id %"PRIu32"", s->id); /* if the sig has alproto and the session as well they should match */ - if (likely(s->flags & SIG_FLAG_APPLAYER)) { + if (likely(sflags & SIG_FLAG_APPLAYER)) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { if (s->alproto == ALPROTO_DCERPC) { if (alproto != ALPROTO_SMB && alproto != ALPROTO_SMB2) { @@ -1434,7 +1449,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } } - if (unlikely(s->flags & SIG_FLAG_DSIZE)) { + if (unlikely(sflags & SIG_FLAG_DSIZE)) { if (likely(p->payload_len < s->dsize_low || p->payload_len > s->dsize_high)) { SCLogDebug("kicked out as p->payload_len %u, dsize low %u, hi %u", p->payload_len, s->dsize_low, s->dsize_high); @@ -1443,30 +1458,29 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } /* check for a pattern match of the one pattern in this sig. */ - if (likely(s->flags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_APPLAYER))) + if (likely(sflags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_APPLAYER))) { /* filter out sigs that want pattern matches, but * have no matches */ if (!(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { - if (s->flags & SIG_FLAG_MPM_PACKET) { - if (!(s->flags & SIG_FLAG_MPM_PACKET_NEG)) { + if (sflags & SIG_FLAG_MPM_PACKET) { + if (!(sflags & SIG_FLAG_MPM_PACKET_NEG)) { goto next; } - } else if (s->flags & SIG_FLAG_MPM_STREAM) { + } else if (sflags & SIG_FLAG_MPM_STREAM) { /* filter out sigs that want pattern matches, but * have no matches */ - if (!(s->flags & SIG_FLAG_MPM_STREAM_NEG)) { + if (!(sflags & SIG_FLAG_MPM_STREAM_NEG)) { goto next; } - } else if (s->flags & SIG_FLAG_MPM_APPLAYER) { - if (!(s->flags & SIG_FLAG_MPM_APPLAYER_NEG)) { + } else if (sflags & SIG_FLAG_MPM_APPLAYER) { + if (!(sflags & SIG_FLAG_MPM_APPLAYER_NEG)) { goto next; } } } } - - if (s->flags & SIG_FLAG_STATE_MATCH) { + if (sflags & SIG_FLAG_STATE_MATCH) { if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NO_NEW_STATE) goto next; } @@ -1474,7 +1488,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* check if this signature has a requirement for flowvars of some type * and if so, if we actually have any in the flow. If not, the sig * can't match and we skip it. */ - if ((p->flags & PKT_HAS_FLOW) && (s->flags & SIG_FLAG_REQUIRE_FLOWVAR)) { + if ((p->flags & PKT_HAS_FLOW) && (sflags & SIG_FLAG_REQUIRE_FLOWVAR)) { FLOWLOCK_RDLOCK(pflow); int m = pflow->flowvar ? 1 : 0; FLOWLOCK_UNLOCK(pflow); @@ -1487,11 +1501,11 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } } - if ((s->proto.flags & DETECT_PROTO_IPV4) && !PKT_IS_IPV4(p)) { + if ((s_proto_flags & DETECT_PROTO_IPV4) && !PKT_IS_IPV4(p)) { SCLogDebug("ip version didn't match"); goto next; } - if ((s->proto.flags & DETECT_PROTO_IPV6) && !PKT_IS_IPV6(p)) { + if ((s_proto_flags & DETECT_PROTO_IPV6) && !PKT_IS_IPV6(p)) { SCLogDebug("ip version didn't match"); goto next; } @@ -1503,7 +1517,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* check the source & dst port in the sig */ if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) { - if (!(s->flags & SIG_FLAG_DP_ANY)) { + if (!(sflags & SIG_FLAG_DP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) goto next; DetectPort *dport = DetectPortLookupGroup(s->dp,p->dp); @@ -1512,7 +1526,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh goto next; } } - if (!(s->flags & SIG_FLAG_SP_ANY)) { + if (!(sflags & SIG_FLAG_SP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) goto next; DetectPort *sport = DetectPortLookupGroup(s->sp,p->sp); @@ -1521,13 +1535,13 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh goto next; } } - } else if ((s->flags & (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) != (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) { + } else if ((sflags & (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) != (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) { SCLogDebug("port-less protocol and sig needs ports"); goto next; } /* check the destination address */ - if (!(s->flags & SIG_FLAG_DST_ANY)) { + if (!(sflags & SIG_FLAG_DST_ANY)) { if (PKT_IS_IPV4(p)) { if (DetectAddressMatchIPv4(s->addr_dst_match4, s->addr_dst_match4_cnt, &p->dst) == 0) goto next; @@ -1537,7 +1551,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } } /* check the source address */ - if (!(s->flags & SIG_FLAG_SRC_ANY)) { + if (!(sflags & SIG_FLAG_SRC_ANY)) { if (PKT_IS_IPV4(p)) { if (DetectAddressMatchIPv4(s->addr_src_match4, s->addr_src_match4_cnt, &p->src) == 0) goto next; @@ -1553,7 +1567,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_PMATCH); /* if we have stream msgs, inspect against those first, * but not for a "dsize" signature */ - if (s->flags & SIG_FLAG_REQUIRE_STREAM) { + if (sflags & SIG_FLAG_REQUIRE_STREAM) { char pmatch = 0; if (smsg != NULL) { uint8_t pmq_idx = 0; @@ -1561,7 +1575,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh for ( ; smsg_inspect != NULL; smsg_inspect = smsg_inspect->next, pmq_idx++) { /* filter out sigs that want pattern matches, but * have no matches */ - if ((s->flags & SIG_FLAG_MPM_STREAM) && !(s->flags & SIG_FLAG_MPM_STREAM_NEG) && + if ((sflags & SIG_FLAG_MPM_STREAM) && !(sflags & SIG_FLAG_MPM_STREAM_NEG) && !(det_ctx->smsg_pmq[pmq_idx].pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { SCLogDebug("no match in this smsg"); continue; @@ -1587,13 +1601,13 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh if (pmatch == 0) { SCLogDebug("no match in smsg, fall back to packet payload"); - if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { + if (!(sflags & SIG_FLAG_REQUIRE_PACKET)) { if (p->flags & PKT_STREAM_ADD) goto next; } if (sms_runflags & SMS_USED_PM) { - if ((s->flags & SIG_FLAG_MPM_PACKET) && !(s->flags & SIG_FLAG_MPM_PACKET_NEG) && + if ((sflags & SIG_FLAG_MPM_PACKET) && !(sflags & SIG_FLAG_MPM_PACKET_NEG) && !(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { goto next; @@ -1609,7 +1623,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } } else { if (sms_runflags & SMS_USED_PM) { - if ((s->flags & SIG_FLAG_MPM_PACKET) && !(s->flags & SIG_FLAG_MPM_PACKET_NEG) && + if ((sflags & SIG_FLAG_MPM_PACKET) && !(sflags & SIG_FLAG_MPM_PACKET_NEG) && !(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { goto next; @@ -1651,7 +1665,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh s->sm_lists[DETECT_SM_LIST_HCDMATCH]); /* consider stateful sig matches */ - if (s->flags & SIG_FLAG_STATE_MATCH) { + if (sflags & SIG_FLAG_STATE_MATCH) { if (has_state == 0) { SCLogDebug("state matches but no state, we can't match"); goto next; @@ -1683,7 +1697,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SigMatchSignaturesRunPostMatch(th_v, de_ctx, det_ctx, p, s); - if (!(s->flags & SIG_FLAG_NOALERT)) { + if (!(sflags & SIG_FLAG_NOALERT)) { /* stateful sigs call PacketAlertAppend from DeStateDetectStartDetection */ if (!state_alert) PacketAlertAppend(det_ctx, s, p, 0, alert_flags); From 83ed01a2792b52a79dff6bf214477a73a7a20712 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 10 Oct 2014 10:34:48 -0400 Subject: [PATCH 0173/2553] Fix compiler warnings in ac-tile. Signed vs unsigned comparisons. --- src/util-mpm-ac-tile.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 7c098835f441..aa791b1e268b 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -1035,7 +1035,7 @@ static void SCACTileClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx) SCACTileCtx *ctx = search_ctx->init_ctx; int aa = 0; - int state = 0; + uint32_t state = 0; /* Allocate next-state table. */ int size = ctx->state_count * ctx->bytes_per_state * ctx->alphabet_storage; @@ -1071,7 +1071,7 @@ static inline void SCACTileInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; SCACTileCtx *ctx = search_ctx->init_ctx; - int state = 0; + uint32_t state = 0; uint32_t k = 0; for (state = 0; state < ctx->state_count; state++) { @@ -1401,7 +1401,7 @@ static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx) } if (ctx->output_table != NULL) { - int state; + uint32_t state; for (state = 0; state < ctx->state_count; state++) { if (ctx->output_table[state].patterns != NULL) { SCFree(ctx->output_table[state].patterns); From 783507038571aea7c27bf73cf3c53c25dc283d68 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 10 Oct 2014 13:55:55 -0400 Subject: [PATCH 0174/2553] Replace memcpy() in MpmAddSids with copy loop For the short size of most sids lists, a straight copy loop is faster. --- src/util-mpm.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/util-mpm.h b/src/util-mpm.h index b94e0499185c..ca1fb4348a20 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -285,6 +285,9 @@ int MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size); static inline void MpmAddSids(PatternMatcherQueue *pmq, uint32_t *sids, uint32_t sids_size) { + if (sids_size == 0) + return; + uint32_t new_size = pmq->rule_id_array_cnt + sids_size; if (new_size > pmq->rule_id_array_size) { if (MpmAddSidsResize(pmq, new_size) == 0) { @@ -295,8 +298,11 @@ MpmAddSids(PatternMatcherQueue *pmq, uint32_t *sids, uint32_t sids_size) } SCLogDebug("Adding %u sids", sids_size); // Add SIDs for this pattern to the end of the array - memcpy(pmq->rule_id_array + pmq->rule_id_array_cnt, - sids, sids_size * sizeof(uint32_t)); + uint32_t *ptr = pmq->rule_id_array + pmq->rule_id_array_cnt; + uint32_t *end = ptr + sids_size; + do { + *ptr++ = *sids++; + } while (ptr != end); pmq->rule_id_array_cnt += sids_size; } From 900def5caf67c8fd1552903c00ed87a839a907d7 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Mon, 13 Oct 2014 14:36:45 -0400 Subject: [PATCH 0175/2553] Create Specialized SCMemcmpNZ() when the length can't be zero. --- src/util-memcmp.h | 13 +++++++++---- src/util-mpm-ac-tile.c | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/util-memcmp.h b/src/util-memcmp.h index 875652b10921..9248f8422e83 100644 --- a/src/util-memcmp.h +++ b/src/util-memcmp.h @@ -365,14 +365,12 @@ static inline int SCMemcmpLowercase(const void *s1, const void *s2, size_t len) #include -static inline int SCMemcmp(const void *s1, const void *s2, size_t len) +/* Compare to non-zero sequence of bytes. */ +static inline int SCMemcmpNZ(const void *s1, const void *s2, size_t len) { uint64_t b1, w1, aligned1; uint64_t b2, w2, aligned2; - if (len == 0) - return 0; - /* Load aligned words containing the beginning of each string. * These loads don't trigger unaligned events. */ @@ -411,6 +409,13 @@ static inline int SCMemcmp(const void *s1, const void *s2, size_t len) return 0; } +/* Compare two sequences of bytes. */ +static inline int SCMemcmp(const void *s1, const void *s2, size_t len) +{ + if (len == 0) + return 0; + return SCMemcmpNZ(s1, s2, len); +} /** \brief Convert 8 characters to lower case using SIMD. * \param Word containing the 8 bytes. * \return Word containing 8-bytes each converted to lowercase. diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index aa791b1e268b..a3e0c7c5b3c4 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -1494,7 +1494,7 @@ int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, /* Double check case-sensitve match now. */ if (patterns[k] & 0xFFFF0000) { uint16_t patlen = pattern_list[pindex].patlen; - if (SCMemcmp(pattern_list[pindex].cs, buf_offset - patlen, patlen) != 0) { + if (SCMemcmpNZ(pattern_list[pindex].cs, buf_offset - patlen, patlen) != 0) { /* Case-sensitive match failed. */ continue; } From 923a77e952cece26b5142f67b06964838fda46ed Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Tue, 14 Oct 2014 16:08:59 -0400 Subject: [PATCH 0176/2553] Change Match() function to take const SigMatchCtx* The Match functions don't need a pointer to the SigMatch object, just the context pointer contained inside, so pass the Context to the Match function rather than the SigMatch object. This allows for further optimization. Change SigMatch->ctx to have type SigMatchCtx* rather than void* for better type checking. This requires adding type casts when using or assigning it. The SigMatch contex should not be changed by the Match() funciton, so pass it as a const SigMatchCtx*. --- src/detect-ack.c | 8 +- src/detect-app-layer-event.c | 10 +- src/detect-app-layer-protocol.c | 4 +- src/detect-asn1.c | 10 +- src/detect-bytejump.c | 10 +- src/detect-bytejump.h | 4 +- src/detect-bytetest.c | 12 +- src/detect-bytetest.h | 5 +- src/detect-content.c | 4 +- src/detect-csum.c | 58 +-- src/detect-dce-iface.c | 20 +- src/detect-dce-opnum.c | 12 +- src/detect-detection-filter.c | 6 +- src/detect-dsize.c | 8 +- src/detect-engine-alert.c | 2 +- src/detect-engine-content-inspection.c | 4 +- src/detect-engine-event.c | 12 +- src/detect-engine-file.c | 2 +- src/detect-engine-iponly.c | 4 +- src/detect-fast-pattern.c | 616 ++++++++++++------------- src/detect-filename.c | 2 +- src/detect-filesize.c | 4 +- src/detect-filestore.c | 6 +- src/detect-flags.c | 60 +-- src/detect-flow.c | 8 +- src/detect-flowbits.c | 18 +- src/detect-flowint.c | 8 +- src/detect-flowvar.c | 18 +- src/detect-fragbits.c | 16 +- src/detect-fragoffset.c | 8 +- src/detect-geoip.c | 8 +- src/detect-http-client-body.c | 68 +-- src/detect-http-header.c | 20 +- src/detect-http-hh.c | 68 +-- src/detect-http-hrh.c | 68 +-- src/detect-http-method.c | 4 +- src/detect-http-raw-header.c | 20 +- src/detect-http-raw-uri.c | 16 +- src/detect-http-server-body.c | 68 +-- src/detect-http-ua.c | 68 +-- src/detect-http-uri.c | 18 +- src/detect-icmp-id.c | 8 +- src/detect-icmp-seq.c | 8 +- src/detect-icode.c | 8 +- src/detect-id.c | 8 +- src/detect-ipopts.c | 16 +- src/detect-ipproto.c | 8 +- src/detect-iprep.c | 8 +- src/detect-isdataat.c | 8 +- src/detect-itype.c | 8 +- src/detect-lua.c | 12 +- src/detect-mark.c | 8 +- src/detect-pcre.c | 10 +- src/detect-pktvar.c | 8 +- src/detect-rpc.c | 8 +- src/detect-sameip.c | 4 +- src/detect-seq.c | 8 +- src/detect-ssl-state.c | 2 +- src/detect-stream_size.c | 16 +- src/detect-tag.c | 8 +- src/detect-threshold.c | 8 +- src/detect-tos.c | 8 +- src/detect-ttl.c | 8 +- src/detect-window.c | 8 +- src/detect.c | 4 +- src/detect.h | 12 +- 66 files changed, 803 insertions(+), 794 deletions(-) diff --git a/src/detect-ack.c b/src/detect-ack.c index 89d87131afc7..5a84c6f9f94d 100644 --- a/src/detect-ack.c +++ b/src/detect-ack.c @@ -42,7 +42,7 @@ /* prototypes */ static int DetectAckSetup(DetectEngineCtx *, Signature *, char *); static int DetectAckMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, SigMatch *); + Packet *, Signature *, const SigMatchCtx *); static void DetectAckRegisterTests(void); static void DetectAckFree(void *); @@ -70,9 +70,9 @@ void DetectAckRegister(void) * \retval 1 match */ static int DetectAckMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectAckData *data = (DetectAckData *)m->ctx; + const DetectAckData *data = (const DetectAckData *)ctx; /* This is only needed on TCP packets */ if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { @@ -112,7 +112,7 @@ static int DetectAckSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) if (-1 == ByteExtractStringUint32(&data->ack, 10, 0, optstr)) { goto error; } - sm->ctx = data; + sm->ctx = (SigMatchCtx*)data; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 2cabeef1f402..63d401173830 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -47,7 +47,7 @@ static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m); + Packet *p, Signature *s, const SigMatchCtx *ctx); static int DetectAppLayerEventAppMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectAppLayerEventSetupP1(DetectEngineCtx *, Signature *, char *); @@ -74,9 +74,9 @@ void DetectAppLayerEventRegister(void) static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectAppLayerEventData *aled = (DetectAppLayerEventData *)m->ctx; + const DetectAppLayerEventData *aled = (const DetectAppLayerEventData *)ctx; return AppLayerDecoderEventsIsEventSet(p->app_layer_events, aled->event_id); @@ -223,7 +223,7 @@ static int DetectAppLayerEventSetupP2(Signature *s, { AppLayerEventType event_type = 0; - if (DetectAppLayerEventParseAppP2(sm->ctx, s->proto.proto, + if (DetectAppLayerEventParseAppP2((DetectAppLayerEventData *)sm->ctx, s->proto.proto, &event_type) < 0) { /* DetectAppLayerEventParseAppP2 prints errors */ return -1; @@ -253,7 +253,7 @@ static int DetectAppLayerEventSetupP1(DetectEngineCtx *de_ctx, Signature *s, cha goto error; sm->type = DETECT_AL_APP_LAYER_EVENT; - sm->ctx = (void *)data; + sm->ctx = (SigMatchCtx *)data; if (s->alproto != ALPROTO_UNKNOWN) { if (s->alproto != data->alproto) { diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 92285d5d3abf..65af621e910c 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -208,7 +208,7 @@ int DetectAppLayerProtocolTest03(void) printf("signature alproto should be http\n"); goto end; } - data = s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx; + data = (DetectAppLayerProtocolData *)s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx; if (data->alproto != ALPROTO_HTTP || data->negated) { printf("if (data->alproto != ALPROTO_HTTP || data->negated)\n"); goto end; @@ -243,7 +243,7 @@ int DetectAppLayerProtocolTest04(void) printf("if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL)\n"); goto end; } - data = s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx; + data = (DetectAppLayerProtocolData*)s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx; if (data == NULL) { printf("if (data == NULL)\n"); goto end; diff --git a/src/detect-asn1.c b/src/detect-asn1.c index b88885d78da7..8b7ff06f393b 100644 --- a/src/detect-asn1.c +++ b/src/detect-asn1.c @@ -43,7 +43,7 @@ const char *ASN_DELIM = " \t,\n"; int DetectAsn1Match(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectAsn1Setup (DetectEngineCtx *, Signature *, char *); void DetectAsn1RegisterTests(void); void DetectAsn1Free(void *); @@ -76,7 +76,7 @@ void DetectAsn1Register(void) * checks that we want to perform, and the lenght of oversize check * \retval 1 if any of the options match, 0 if not */ -static uint8_t DetectAsn1Checks(Asn1Node *node, DetectAsn1Data *ad) +static uint8_t DetectAsn1Checks(Asn1Node *node, const DetectAsn1Data *ad) { /* oversize_length will check if a node has a length greater than @@ -138,7 +138,7 @@ static uint8_t DetectAsn1Checks(Asn1Node *node, DetectAsn1Data *ad) * \retval 1 match */ int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s, SigMatch *m) + Signature *s, const SigMatchCtx *ctx) { uint8_t ret = 0; @@ -147,7 +147,7 @@ int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, return 0; } - DetectAsn1Data *ad = (DetectAsn1Data *)m->ctx; + const DetectAsn1Data *ad = (const DetectAsn1Data *)ctx; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) @@ -303,7 +303,7 @@ int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, char *asn1str) goto error; sm->type = DETECT_ASN1; - sm->ctx = (void *)ad; + sm->ctx = (SigMatchCtx *)ad; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 0542af6675ad..2c9bd67b8840 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -107,12 +107,12 @@ void DetectBytejumpRegister (void) * \retval 0 no match */ int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, - SigMatch *m, uint8_t *payload, uint32_t payload_len, + const SigMatchCtx *ctx, uint8_t *payload, uint32_t payload_len, uint8_t flags, int32_t offset) { SCEnter(); - DetectBytejumpData *data = (DetectBytejumpData *)m->ctx; + const DetectBytejumpData *data = (const DetectBytejumpData *)ctx; uint8_t *ptr = NULL; uint8_t *jumpptr = NULL; int32_t len = 0; @@ -219,9 +219,9 @@ int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, } int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectBytejumpData *data = (DetectBytejumpData *)m->ctx; + const DetectBytejumpData *data = (const DetectBytejumpData *)ctx; uint8_t *ptr = NULL; uint8_t *jumpptr = NULL; uint16_t len = 0; @@ -713,7 +713,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) if (sm == NULL) goto error; sm->type = DETECT_BYTEJUMP; - sm->ctx = (void *)data; + sm->ctx = (SigMatchCtx *)data; SigMatchAppendSMToList(s, sm, sm_list); if (!(data->flags & DETECT_BYTEJUMP_RELATIVE)) diff --git a/src/detect-bytejump.h b/src/detect-bytejump.h index e7a8eabb657c..350514867c1d 100644 --- a/src/detect-bytejump.h +++ b/src/detect-bytejump.h @@ -113,8 +113,8 @@ DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset); * error as a match. */ int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m); -int DetectBytejumpDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, + Packet *p, Signature *s, const SigMatchCtx *ctx); +int DetectBytejumpDoMatch(DetectEngineThreadCtx *, Signature *, const SigMatchCtx *, uint8_t *, uint32_t, uint8_t, int32_t); #endif /* __DETECT_BYTEJUMP_H__ */ diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 47ede78f9cf8..d001fe900b0f 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -111,12 +111,12 @@ void DetectBytetestRegister (void) * \retval 1 match * \retval 0 no match */ -int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *m, uint8_t *payload, uint32_t payload_len, +int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, const SigMatchCtx *ctx, uint8_t *payload, uint32_t payload_len, uint8_t flags, int32_t offset, uint64_t value) { SCEnter(); - DetectBytetestData *data = (DetectBytetestData *)m->ctx; + const DetectBytetestData *data = (const DetectBytetestData *)ctx; uint8_t *ptr = NULL; int32_t len = 0; uint64_t val = 0; @@ -253,10 +253,10 @@ int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch } int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - return DetectBytetestDoMatch(det_ctx, s, m, p->payload, p->payload_len, - ((DetectBytetestData *)m->ctx)->flags, 0, 0); + return DetectBytetestDoMatch(det_ctx, s, ctx, p->payload, p->payload_len, + ((DetectBytetestData *)ctx)->flags, 0, 0); } DetectBytetestData *DetectBytetestParse(char *optstr, char **value, char **offset) @@ -650,7 +650,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) if (sm == NULL) goto error; sm->type = DETECT_BYTETEST; - sm->ctx = (void *)data; + sm->ctx = (SigMatchCtx *)data; SigMatchAppendSMToList(s, sm, sm_list); if (!(data->flags & DETECT_BYTETEST_RELATIVE)) diff --git a/src/detect-bytetest.h b/src/detect-bytetest.h index 55cc3961c8d2..09d453fab698 100644 --- a/src/detect-bytetest.h +++ b/src/detect-bytetest.h @@ -121,8 +121,9 @@ DetectBytetestData *DetectBytetestParse(char *optstr, char **value, * \todo The return seems backwards. We should return a non-zero error code. One of the error codes is "no match". As-is if someone accidentally does: if (DetectBytetestMatch(...)) { match }, then they catch an error as a match. */ int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m); -int DetectBytetestDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, uint8_t *, uint32_t, + Packet *p, Signature *s, const SigMatchCtx *ctx); +int DetectBytetestDoMatch(DetectEngineThreadCtx *, Signature *, + const SigMatchCtx *ctx, uint8_t *, uint32_t, uint8_t, int32_t, uint64_t); #endif /* __DETECT_BYTETEST_H__ */ diff --git a/src/detect-content.c b/src/detect-content.c index 64500e391b05..f965bcbc244b 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* 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 @@ -361,7 +361,7 @@ void DetectContentPrintAll(SigMatch *sm) for (; first_sm != NULL; first_sm = first_sm->next) { if (first_sm->type == DETECT_CONTENT) { SCLogDebug("Printing SigMatch DETECT_CONTENT %d", ++i); - DetectContentPrint(first_sm->ctx); + DetectContentPrint((DetectContentData*)first_sm->ctx); } } } diff --git a/src/detect-csum.c b/src/detect-csum.c index b6dc16c2a127..2cf5b4ce79f2 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -41,43 +41,43 @@ /* prototypes for the "ipv4-csum" rule keyword */ int DetectIPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectIPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectIPV4CsumFree(void *); /* prototypes for the "tcpv4-csum" rule keyword */ int DetectTCPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectTCPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectTCPV4CsumFree(void *); /* prototypes for the "tcpv6-csum" rule keyword */ int DetectTCPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectTCPV6CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectTCPV6CsumFree(void *); /* prototypes for the "udpv4-csum" rule keyword */ int DetectUDPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectUDPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectUDPV4CsumFree(void *); /* prototypes for the "udpv6-csum" rule keyword */ int DetectUDPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectUDPV6CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectUDPV6CsumFree(void *); /* prototypes for the "icmpv4-csum" rule keyword */ int DetectICMPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectICMPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectICMPV4CsumFree(void *); /* prototypes for the "icmpv6-csum" rule keyword */ int DetectICMPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectICMPV6CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectICMPV6CsumFree(void *); @@ -99,7 +99,7 @@ void DetectCsumRegisterTests(void); * DetectEngineCtx * (de_ctx) - A pointer to the detection engine context * Signature *(s) - Pointer to signature for the current Signature being * parsed from the rules - * SigMatch * (m) - Pointer to the head of the SigMatchs added to the + * SigMatchCtx * (m) - Pointer to the head of the SigMatchs added to the * current Signature being parsed * char * (csum_str) - Pointer to a string holding the keyword value * @@ -114,7 +114,7 @@ void DetectCsumRegisterTests(void); * Packet * (p) - Pointer to the Packet currently being handled * Signature * (s) - Pointer to the Signature, the packet is being * currently matched with - * SigMatch * (m) - Pointer to the keyword structure from the above + * SigMatchCtx * (m) - Pointer to the keyword structure from the above * Signature, the Packet is being currently matched * with * @@ -230,9 +230,9 @@ static int DetectCsumParseArg(const char *key, DetectCsumData *cd) * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectIPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip4h == NULL || PKT_IS_PSEUDOPKT(p)) return 0; @@ -285,7 +285,7 @@ static int DetectIPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -324,9 +324,9 @@ void DetectIPV4CsumFree(void *ptr) * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectTCPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip4h == NULL || p->tcph == NULL || p->proto != IPPROTO_TCP || PKT_IS_PSEUDOPKT(p)) return 0; @@ -380,7 +380,7 @@ static int DetectTCPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -419,9 +419,9 @@ void DetectTCPV4CsumFree(void *ptr) * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectTCPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip6h == NULL || p->tcph == NULL || p->proto != IPPROTO_TCP || PKT_IS_PSEUDOPKT(p)) return 0; @@ -475,7 +475,7 @@ static int DetectTCPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -514,9 +514,9 @@ void DetectTCPV6CsumFree(void *ptr) * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectUDPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip4h == NULL || p->udph == NULL || p->proto != IPPROTO_UDP || PKT_IS_PSEUDOPKT(p) || p->udph->uh_sum == 0) return 0; @@ -571,7 +571,7 @@ static int DetectUDPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -610,9 +610,9 @@ void DetectUDPV4CsumFree(void *ptr) * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectUDPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip6h == NULL || p->udph == NULL || p->proto != IPPROTO_UDP || PKT_IS_PSEUDOPKT(p)) return 0; @@ -706,9 +706,9 @@ void DetectUDPV6CsumFree(void *ptr) * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectICMPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip4h == NULL || p->icmpv4h == NULL || p->proto != IPPROTO_ICMP || PKT_IS_PSEUDOPKT(p)) return 0; @@ -762,7 +762,7 @@ static int DetectICMPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *cs if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -801,9 +801,9 @@ void DetectICMPV4CsumFree(void *ptr) * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectICMPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip6h == NULL || p->icmpv6h == NULL || p->proto != IPPROTO_ICMPV6 || PKT_IS_PSEUDOPKT(p) || (GET_PKT_LEN(p) - ((uint8_t *)p->icmpv6h - GET_PKT_DATA(p))) <= 0) { @@ -857,7 +857,7 @@ static int DetectICMPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *cs if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index aba6c2869c4b..029cebdfb63f 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -416,7 +416,7 @@ static int DetectDceIfaceTestParse01(void) } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -459,7 +459,7 @@ static int DetectDceIfaceTestParse02(void) } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -502,7 +502,7 @@ static int DetectDceIfaceTestParse03(void) } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + did = (DetectDceIfaceData *)temp->ctx; result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { @@ -541,7 +541,7 @@ static int DetectDceIfaceTestParse04(void) } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -581,7 +581,7 @@ static int DetectDceIfaceTestParse05(void) } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -624,7 +624,7 @@ static int DetectDceIfaceTestParse06(void) } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -667,7 +667,7 @@ static int DetectDceIfaceTestParse07(void) } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -708,7 +708,7 @@ static int DetectDceIfaceTestParse08(void) } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -747,7 +747,7 @@ static int DetectDceIfaceTestParse09(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,=1,any_frag") == 0); temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -790,7 +790,7 @@ static int DetectDceIfaceTestParse10(void) } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 559550797ede..3c6e6aad67f0 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -409,7 +409,7 @@ static int DetectDceOpnumTestParse02(void) if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -438,7 +438,7 @@ static int DetectDceOpnumTestParse03(void) if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -467,7 +467,7 @@ static int DetectDceOpnumTestParse04(void) if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -533,7 +533,7 @@ static int DetectDceOpnumTestParse05(void) if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -599,7 +599,7 @@ static int DetectDceOpnumTestParse06(void) if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -647,7 +647,7 @@ static int DetectDceOpnumTestParse07(void) if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 40cf0b278172..b16178cb6498 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -51,7 +51,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectDetectionFilterMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectDetectionFilterMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectDetectionFilterSetup(DetectEngineCtx *, Signature *, char *); void DetectDetectionFilterRegisterTests(void); void DetectDetectionFilterFree(void *); @@ -94,7 +94,7 @@ void DetectDetectionFilterRegister (void) return; } -int DetectDetectionFilterMatch (ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) +int DetectDetectionFilterMatch (ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { return 1; } @@ -253,7 +253,7 @@ int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *raw goto error; sm->type = DETECT_DETECTION_FILTER; - sm->ctx = (void *)df; + sm->ctx = (SigMatchCtx *)df; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 3e971f519011..9858a5f2a467 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -48,7 +48,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectDsizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectDsizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectDsizeSetup (DetectEngineCtx *, Signature *s, char *str); void DsizeRegisterTests(void); static void DetectDsizeFree(void *); @@ -103,7 +103,7 @@ void DetectDsizeRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectDsizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectDsizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; @@ -112,7 +112,7 @@ int DetectDsizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, SCReturnInt(0); } - DetectDsizeData *dd = (DetectDsizeData *)m->ctx; + const DetectDsizeData *dd = (const DetectDsizeData *)ctx; SCLogDebug("p->payload_len %"PRIu16"", p->payload_len); @@ -285,7 +285,7 @@ static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr } sm->type = DETECT_DSIZE; - sm->ctx = (void *)dd; + sm->ctx = (SigMatchCtx *)dd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index f59c030562e4..db9becc5cbf7 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -256,7 +256,7 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx while (sm) { /* tags are set only for alerts */ KEYWORD_PROFILING_START; - sigmatch_table[sm->type].Match(NULL, det_ctx, p, s, sm); + sigmatch_table[sm->type].Match(NULL, det_ctx, p, s, sm->ctx); KEYWORD_PROFILING_END(det_ctx, sm->type, 1); sm = sm->next; } diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index 0b7c23af9875..a434ca5ad8c8 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -439,7 +439,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx DETECT_BYTETEST_LITTLE: 0); } - if (DetectBytetestDoMatch(det_ctx, s, sm, buffer, buffer_len, flags, + if (DetectBytetestDoMatch(det_ctx, s, sm->ctx, buffer, buffer_len, flags, offset, value) != 1) { goto no_match; } @@ -465,7 +465,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx DETECT_BYTEJUMP_LITTLE: 0); } - if (DetectBytejumpDoMatch(det_ctx, s, sm, buffer, buffer_len, + if (DetectBytejumpDoMatch(det_ctx, s, sm->ctx, buffer, buffer_len, flags, offset) != 1) { goto no_match; } diff --git a/src/detect-engine-event.c b/src/detect-engine-event.c index d0badb5eceb5..737b5478998d 100644 --- a/src/detect-engine-event.c +++ b/src/detect-engine-event.c @@ -48,7 +48,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectEngineEventMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectEngineEventMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectEngineEventSetup (DetectEngineCtx *, Signature *, char *); static int DetectDecodeEventSetup (DetectEngineCtx *, Signature *, char *); static int DetectStreamEventSetup (DetectEngineCtx *, Signature *, char *); @@ -114,11 +114,11 @@ void DetectEngineEventRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectEngineEventMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectEngineEventMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { SCEnter(); - DetectEngineEventData *de = (DetectEngineEventData *)m->ctx; + const DetectEngineEventData *de = (const DetectEngineEventData *)ctx; if (ENGINE_ISSET_EVENT(p, de->event)) { SCLogDebug("de->event matched %u", de->event); @@ -214,7 +214,7 @@ static int _DetectEngineEventSetup (DetectEngineCtx *de_ctx, Signature *s, char goto error; sm->type = smtype; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; @@ -377,9 +377,9 @@ int EngineEventTestParse06 (void) goto error; sm->type = DETECT_DECODE_EVENT; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectEngineEventMatch(&tv,NULL,p,NULL,sm); + ret = DetectEngineEventMatch(&tv,NULL,p,NULL,sm->ctx); if(ret) { SCFree(p); diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index a16c382427c2..319936851b94 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -174,7 +174,7 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, if (sm != NULL && sm->next == NULL && sm->type == DETECT_FILESTORE && sm->ctx != NULL) { - DetectFilestoreData *fd = sm->ctx; + DetectFilestoreData *fd = (DetectFilestoreData *)sm->ctx; if (fd->scope > FILESTORE_SCOPE_DEFAULT) { KEYWORD_PROFILING_START; match = sigmatch_table[sm->type]. diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index a44c5bb8eb3e..fd8dedaec9d2 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -943,7 +943,7 @@ int IPOnlyMatchCompatSMs(ThreadVars *tv, while (sm != NULL) { BUG_ON(!(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)); KEYWORD_PROFILING_START; - if (sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm) > 0) { + if (sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm->ctx) > 0) { KEYWORD_PROFILING_END(det_ctx, sm->type, 1); sm = sm->next; continue; @@ -1070,7 +1070,7 @@ void IPOnlyMatchPacket(ThreadVars *tv, for ( ; sm != NULL; sm = sm->next) { KEYWORD_PROFILING_START; - (void)sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm); + (void)sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm->ctx); KEYWORD_PROFILING_END(det_ctx, sm->type, 1); } } diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index a54103e65e71..db721562d5f0 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -260,7 +260,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a return -1; } - cd = pm->ctx; + cd = (DetectContentData *)pm->ctx; if ((cd->flags & DETECT_CONTENT_NEGATED) && ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN) || @@ -285,7 +285,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a SigMatch *sm = NULL; for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { - DetectContentData *tmp_cd = sm->ctx; + DetectContentData *tmp_cd = (DetectContentData *)sm->ctx; if (tmp_cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern " "can be used on only one content in a rule"); @@ -1177,7 +1177,7 @@ int DetectFastPatternTest17(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; - DetectContentData *cd = sm->ctx; + DetectContentData *cd = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -1213,7 +1213,7 @@ int DetectFastPatternTest18(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; - DetectContentData *cd = sm->ctx; + DetectContentData *cd = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -1444,7 +1444,7 @@ int DetectFastPatternTest28(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -1474,7 +1474,7 @@ int DetectFastPatternTest29(void) "(content:\"one\"; content:\"two\"; within:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -1504,7 +1504,7 @@ int DetectFastPatternTest30(void) "(content:\"one\"; content:\"two\"; offset:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -1534,7 +1534,7 @@ int DetectFastPatternTest31(void) "(content:\"one\"; content:\"two\"; depth:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -1564,7 +1564,7 @@ int DetectFastPatternTest32(void) "(content:!\"one\"; fast_pattern; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_NEGATED && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -1683,7 +1683,7 @@ int DetectFastPatternTest37(void) "(content:\"oneoneone\"; content:\"oneonetwo\"; fast_pattern:3,4; content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1713,7 +1713,7 @@ int DetectFastPatternTest38(void) "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1743,7 +1743,7 @@ int DetectFastPatternTest39(void) "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1773,7 +1773,7 @@ int DetectFastPatternTest40(void) "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1803,7 +1803,7 @@ int DetectFastPatternTest41(void) "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1833,7 +1833,7 @@ int DetectFastPatternTest42(void) "(content:\"one\"; content:\"two\"; distance:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1863,7 +1863,7 @@ int DetectFastPatternTest43(void) "(content:\"one\"; content:\"two\"; within:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1893,7 +1893,7 @@ int DetectFastPatternTest44(void) "(content:\"one\"; content:\"two\"; offset:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1923,7 +1923,7 @@ int DetectFastPatternTest45(void) "(content:\"one\"; content:\"two\"; depth:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2019,7 +2019,7 @@ int DetectFastPatternTest49(void) "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_NEGATED && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -2229,7 +2229,7 @@ int DetectFastPatternTest56(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -2265,7 +2265,7 @@ int DetectFastPatternTest57(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -2496,7 +2496,7 @@ int DetectFastPatternTest67(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2526,7 +2526,7 @@ int DetectFastPatternTest68(void) "(uricontent:\"one\"; uricontent:\"two\"; within:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2556,7 +2556,7 @@ int DetectFastPatternTest69(void) "(uricontent:\"one\"; uricontent:\"two\"; offset:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2586,7 +2586,7 @@ int DetectFastPatternTest70(void) "(uricontent:\"one\"; uricontent:\"two\"; depth:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2616,7 +2616,7 @@ int DetectFastPatternTest71(void) "(uricontent:!\"one\"; fast_pattern; uricontent:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -2735,7 +2735,7 @@ int DetectFastPatternTest76(void) "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2765,7 +2765,7 @@ int DetectFastPatternTest77(void) "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2795,7 +2795,7 @@ int DetectFastPatternTest78(void) "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2825,7 +2825,7 @@ int DetectFastPatternTest79(void) "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2855,7 +2855,7 @@ int DetectFastPatternTest80(void) "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2885,7 +2885,7 @@ int DetectFastPatternTest81(void) "(uricontent:\"one\"; uricontent:\"two\"; distance:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2915,7 +2915,7 @@ int DetectFastPatternTest82(void) "(uricontent:\"one\"; uricontent:\"two\"; within:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2945,7 +2945,7 @@ int DetectFastPatternTest83(void) "(uricontent:\"one\"; uricontent:\"two\"; offset:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2975,7 +2975,7 @@ int DetectFastPatternTest84(void) "(uricontent:\"one\"; uricontent:\"two\"; depth:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3074,7 +3074,7 @@ int DetectFastPatternTest88(void) "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3198,7 +3198,7 @@ int DetectFastPatternTest93(void) "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3315,7 +3315,7 @@ int DetectFastPatternTest96(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -3351,7 +3351,7 @@ int DetectFastPatternTest97(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3582,7 +3582,7 @@ int DetectFastPatternTest107(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3612,7 +3612,7 @@ int DetectFastPatternTest108(void) "(uricontent:\"one\"; uricontent:\"two\"; within:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3642,7 +3642,7 @@ int DetectFastPatternTest109(void) "(uricontent:\"one\"; uricontent:\"two\"; offset:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3672,7 +3672,7 @@ int DetectFastPatternTest110(void) "(uricontent:\"one\"; uricontent:\"two\"; depth:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3702,7 +3702,7 @@ int DetectFastPatternTest111(void) "(content:!\"one\"; fast_pattern; http_uri; uricontent:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3821,7 +3821,7 @@ int DetectFastPatternTest116(void) "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3851,7 +3851,7 @@ int DetectFastPatternTest117(void) "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3881,7 +3881,7 @@ int DetectFastPatternTest118(void) "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3911,7 +3911,7 @@ int DetectFastPatternTest119(void) "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3941,7 +3941,7 @@ int DetectFastPatternTest120(void) "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3971,7 +3971,7 @@ int DetectFastPatternTest121(void) "(uricontent:\"one\"; uricontent:\"two\"; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4001,7 +4001,7 @@ int DetectFastPatternTest122(void) "(uricontent:\"one\"; uricontent:\"two\"; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4031,7 +4031,7 @@ int DetectFastPatternTest123(void) "(uricontent:\"one\"; uricontent:\"two\"; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4061,7 +4061,7 @@ int DetectFastPatternTest124(void) "(uricontent:\"one\"; uricontent:\"two\"; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4160,7 +4160,7 @@ int DetectFastPatternTest128(void) "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4279,7 +4279,7 @@ int DetectFastPatternTest133(void) "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4315,7 +4315,7 @@ int DetectFastPatternTest134(void) "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4423,7 +4423,7 @@ int DetectFastPatternTest137(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4457,7 +4457,7 @@ int DetectFastPatternTest138(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4686,7 +4686,7 @@ int DetectFastPatternTest148(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4716,7 +4716,7 @@ int DetectFastPatternTest149(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; within:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4746,7 +4746,7 @@ int DetectFastPatternTest150(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; offset:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4776,7 +4776,7 @@ int DetectFastPatternTest151(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; depth:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4806,7 +4806,7 @@ int DetectFastPatternTest152(void) "(content:!\"one\"; fast_pattern; http_client_body; content:\"two\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4925,7 +4925,7 @@ int DetectFastPatternTest157(void) "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4955,7 +4955,7 @@ int DetectFastPatternTest158(void) "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4985,7 +4985,7 @@ int DetectFastPatternTest159(void) "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5015,7 +5015,7 @@ int DetectFastPatternTest160(void) "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5045,7 +5045,7 @@ int DetectFastPatternTest161(void) "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5075,7 +5075,7 @@ int DetectFastPatternTest162(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5105,7 +5105,7 @@ int DetectFastPatternTest163(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5135,7 +5135,7 @@ int DetectFastPatternTest164(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5165,7 +5165,7 @@ int DetectFastPatternTest165(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5264,7 +5264,7 @@ int DetectFastPatternTest169(void) "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -5383,7 +5383,7 @@ int DetectFastPatternTest174(void) "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -5513,7 +5513,7 @@ int DetectFastPatternTest179(void) "content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -5621,7 +5621,7 @@ int DetectFastPatternTest182(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5655,7 +5655,7 @@ int DetectFastPatternTest183(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5884,7 +5884,7 @@ int DetectFastPatternTest193(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5914,7 +5914,7 @@ int DetectFastPatternTest194(void) "(content:\"one\"; http_header; content:\"two\"; http_header; within:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5944,7 +5944,7 @@ int DetectFastPatternTest195(void) "(content:\"one\"; http_header; content:\"two\"; http_header; offset:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5974,7 +5974,7 @@ int DetectFastPatternTest196(void) "(content:\"one\"; http_header; content:\"two\"; http_header; depth:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -6004,7 +6004,7 @@ int DetectFastPatternTest197(void) "(content:!\"one\"; fast_pattern; http_header; content:\"two\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6123,7 +6123,7 @@ int DetectFastPatternTest202(void) "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6153,7 +6153,7 @@ int DetectFastPatternTest203(void) "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6183,7 +6183,7 @@ int DetectFastPatternTest204(void) "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6213,7 +6213,7 @@ int DetectFastPatternTest205(void) "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6243,7 +6243,7 @@ int DetectFastPatternTest206(void) "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6273,7 +6273,7 @@ int DetectFastPatternTest207(void) "(content:\"one\"; http_header; content:\"two\"; http_header; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6303,7 +6303,7 @@ int DetectFastPatternTest208(void) "(content:\"one\"; http_header; content:\"two\"; http_header; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6333,7 +6333,7 @@ int DetectFastPatternTest209(void) "(content:\"one\"; http_header; content:\"two\"; http_header; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6363,7 +6363,7 @@ int DetectFastPatternTest210(void) "(content:\"one\"; http_header; content:\"two\"; http_header; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6462,7 +6462,7 @@ int DetectFastPatternTest214(void) "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6581,7 +6581,7 @@ int DetectFastPatternTest219(void) "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6619,7 +6619,7 @@ int DetectFastPatternTest220(void) "content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6727,7 +6727,7 @@ int DetectFastPatternTest223(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -6761,7 +6761,7 @@ int DetectFastPatternTest224(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6990,7 +6990,7 @@ int DetectFastPatternTest234(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7020,7 +7020,7 @@ int DetectFastPatternTest235(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; within:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7050,7 +7050,7 @@ int DetectFastPatternTest236(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; offset:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7080,7 +7080,7 @@ int DetectFastPatternTest237(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; depth:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7110,7 +7110,7 @@ int DetectFastPatternTest238(void) "(flow:to_server; content:!\"one\"; fast_pattern; http_raw_header; content:\"two\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7229,7 +7229,7 @@ int DetectFastPatternTest243(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7259,7 +7259,7 @@ int DetectFastPatternTest244(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7289,7 +7289,7 @@ int DetectFastPatternTest245(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7319,7 +7319,7 @@ int DetectFastPatternTest246(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7349,7 +7349,7 @@ int DetectFastPatternTest247(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7379,7 +7379,7 @@ int DetectFastPatternTest248(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7409,7 +7409,7 @@ int DetectFastPatternTest249(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7439,7 +7439,7 @@ int DetectFastPatternTest250(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7469,7 +7469,7 @@ int DetectFastPatternTest251(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7568,7 +7568,7 @@ int DetectFastPatternTest255(void) "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7687,7 +7687,7 @@ int DetectFastPatternTest260(void) "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7725,7 +7725,7 @@ int DetectFastPatternTest261(void) "content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7833,7 +7833,7 @@ int DetectFastPatternTest264(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7867,7 +7867,7 @@ int DetectFastPatternTest265(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8096,7 +8096,7 @@ int DetectFastPatternTest275(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8126,7 +8126,7 @@ int DetectFastPatternTest276(void) "(content:\"one\"; http_method; content:\"two\"; http_method; within:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8156,7 +8156,7 @@ int DetectFastPatternTest277(void) "(content:\"one\"; http_method; content:\"two\"; http_method; offset:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8186,7 +8186,7 @@ int DetectFastPatternTest278(void) "(content:\"one\"; http_method; content:\"two\"; http_method; depth:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8216,7 +8216,7 @@ int DetectFastPatternTest279(void) "(content:!\"one\"; fast_pattern; http_method; content:\"two\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8335,7 +8335,7 @@ int DetectFastPatternTest284(void) "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8365,7 +8365,7 @@ int DetectFastPatternTest285(void) "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8395,7 +8395,7 @@ int DetectFastPatternTest286(void) "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8425,7 +8425,7 @@ int DetectFastPatternTest287(void) "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8455,7 +8455,7 @@ int DetectFastPatternTest288(void) "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8485,7 +8485,7 @@ int DetectFastPatternTest289(void) "(content:\"one\"; http_method; content:\"two\"; http_method; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8515,7 +8515,7 @@ int DetectFastPatternTest290(void) "(content:\"one\"; http_method; content:\"two\"; http_method; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8545,7 +8545,7 @@ int DetectFastPatternTest291(void) "(content:\"one\"; http_method; content:\"two\"; http_method; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8575,7 +8575,7 @@ int DetectFastPatternTest292(void) "(content:\"one\"; http_method; content:\"two\"; http_method; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8674,7 +8674,7 @@ int DetectFastPatternTest296(void) "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8793,7 +8793,7 @@ int DetectFastPatternTest301(void) "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8831,7 +8831,7 @@ int DetectFastPatternTest302(void) "content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8939,7 +8939,7 @@ int DetectFastPatternTest305(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8973,7 +8973,7 @@ int DetectFastPatternTest306(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9202,7 +9202,7 @@ int DetectFastPatternTest316(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9232,7 +9232,7 @@ int DetectFastPatternTest317(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; within:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9262,7 +9262,7 @@ int DetectFastPatternTest318(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; offset:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9292,7 +9292,7 @@ int DetectFastPatternTest319(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; depth:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9322,7 +9322,7 @@ int DetectFastPatternTest320(void) "(content:!\"one\"; fast_pattern; http_cookie; content:\"two\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -9441,7 +9441,7 @@ int DetectFastPatternTest325(void) "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9471,7 +9471,7 @@ int DetectFastPatternTest326(void) "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9501,7 +9501,7 @@ int DetectFastPatternTest327(void) "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9531,7 +9531,7 @@ int DetectFastPatternTest328(void) "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9561,7 +9561,7 @@ int DetectFastPatternTest329(void) "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9591,7 +9591,7 @@ int DetectFastPatternTest330(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9621,7 +9621,7 @@ int DetectFastPatternTest331(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9651,7 +9651,7 @@ int DetectFastPatternTest332(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9681,7 +9681,7 @@ int DetectFastPatternTest333(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9780,7 +9780,7 @@ int DetectFastPatternTest337(void) "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -9899,7 +9899,7 @@ int DetectFastPatternTest342(void) "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -9937,7 +9937,7 @@ int DetectFastPatternTest343(void) "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -10045,7 +10045,7 @@ int DetectFastPatternTest346(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10079,7 +10079,7 @@ int DetectFastPatternTest347(void) result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10319,7 +10319,7 @@ int DetectFastPatternTest357(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10351,7 +10351,7 @@ int DetectFastPatternTest358(void) "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10383,7 +10383,7 @@ int DetectFastPatternTest359(void) "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10415,7 +10415,7 @@ int DetectFastPatternTest360(void) "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10446,7 +10446,7 @@ int DetectFastPatternTest361(void) "content:\"two\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -10571,7 +10571,7 @@ int DetectFastPatternTest366(void) "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10603,7 +10603,7 @@ int DetectFastPatternTest367(void) "content:\"three\"; http_raw_uri; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10635,7 +10635,7 @@ int DetectFastPatternTest368(void) "content:\"three\"; http_raw_uri; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10667,7 +10667,7 @@ int DetectFastPatternTest369(void) "content:\"three\"; http_raw_uri; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10699,7 +10699,7 @@ int DetectFastPatternTest370(void) "content:\"three\"; http_raw_uri; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10731,7 +10731,7 @@ int DetectFastPatternTest371(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10763,7 +10763,7 @@ int DetectFastPatternTest372(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10795,7 +10795,7 @@ int DetectFastPatternTest373(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10827,7 +10827,7 @@ int DetectFastPatternTest374(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10934,7 +10934,7 @@ int DetectFastPatternTest378(void) "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -11063,7 +11063,7 @@ int DetectFastPatternTest383(void) "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -11101,7 +11101,7 @@ int DetectFastPatternTest384(void) "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -11211,7 +11211,7 @@ int DetectFastPatternTest387(void) if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11248,7 +11248,7 @@ int DetectFastPatternTest388(void) goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11488,7 +11488,7 @@ int DetectFastPatternTest398(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11520,7 +11520,7 @@ int DetectFastPatternTest399(void) "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11552,7 +11552,7 @@ int DetectFastPatternTest400(void) "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11584,7 +11584,7 @@ int DetectFastPatternTest401(void) "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11615,7 +11615,7 @@ int DetectFastPatternTest402(void) "content:\"two\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -11740,7 +11740,7 @@ int DetectFastPatternTest407(void) "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11772,7 +11772,7 @@ int DetectFastPatternTest408(void) "content:\"three\"; http_stat_msg; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11804,7 +11804,7 @@ int DetectFastPatternTest409(void) "content:\"three\"; http_stat_msg; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11836,7 +11836,7 @@ int DetectFastPatternTest410(void) "content:\"three\"; http_stat_msg; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11868,7 +11868,7 @@ int DetectFastPatternTest411(void) "content:\"three\"; http_stat_msg; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11900,7 +11900,7 @@ int DetectFastPatternTest412(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11932,7 +11932,7 @@ int DetectFastPatternTest413(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11964,7 +11964,7 @@ int DetectFastPatternTest414(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11996,7 +11996,7 @@ int DetectFastPatternTest415(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12103,7 +12103,7 @@ int DetectFastPatternTest419(void) "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12232,7 +12232,7 @@ int DetectFastPatternTest424(void) "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12270,7 +12270,7 @@ int DetectFastPatternTest425(void) "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12381,7 +12381,7 @@ int DetectFastPatternTest428(void) goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12418,7 +12418,7 @@ int DetectFastPatternTest429(void) goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12658,7 +12658,7 @@ int DetectFastPatternTest439(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12690,7 +12690,7 @@ int DetectFastPatternTest440(void) "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12722,7 +12722,7 @@ int DetectFastPatternTest441(void) "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12754,7 +12754,7 @@ int DetectFastPatternTest442(void) "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12785,7 +12785,7 @@ int DetectFastPatternTest443(void) "content:\"two\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12910,7 +12910,7 @@ int DetectFastPatternTest448(void) "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12942,7 +12942,7 @@ int DetectFastPatternTest449(void) "content:\"three\"; http_stat_code; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12974,7 +12974,7 @@ int DetectFastPatternTest450(void) "content:\"three\"; http_stat_code; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13006,7 +13006,7 @@ int DetectFastPatternTest451(void) "content:\"three\"; http_stat_code; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13038,7 +13038,7 @@ int DetectFastPatternTest452(void) "content:\"three\"; http_stat_code; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13070,7 +13070,7 @@ int DetectFastPatternTest453(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13102,7 +13102,7 @@ int DetectFastPatternTest454(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13134,7 +13134,7 @@ int DetectFastPatternTest455(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13166,7 +13166,7 @@ int DetectFastPatternTest456(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13273,7 +13273,7 @@ int DetectFastPatternTest460(void) "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -13402,7 +13402,7 @@ int DetectFastPatternTest465(void) "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -13440,7 +13440,7 @@ int DetectFastPatternTest466(void) "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -13550,7 +13550,7 @@ int DetectFastPatternTest469(void) if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13587,7 +13587,7 @@ int DetectFastPatternTest470(void) goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13827,7 +13827,7 @@ int DetectFastPatternTest480(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13859,7 +13859,7 @@ int DetectFastPatternTest481(void) "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13891,7 +13891,7 @@ int DetectFastPatternTest482(void) "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13923,7 +13923,7 @@ int DetectFastPatternTest483(void) "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13954,7 +13954,7 @@ int DetectFastPatternTest484(void) "content:\"two\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14079,7 +14079,7 @@ int DetectFastPatternTest489(void) "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14111,7 +14111,7 @@ int DetectFastPatternTest490(void) "content:\"three\"; http_server_body; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14143,7 +14143,7 @@ int DetectFastPatternTest491(void) "content:\"three\"; http_server_body; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14175,7 +14175,7 @@ int DetectFastPatternTest492(void) "content:\"three\"; http_server_body; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14207,7 +14207,7 @@ int DetectFastPatternTest493(void) "content:\"three\"; http_server_body; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14239,7 +14239,7 @@ int DetectFastPatternTest494(void) "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14271,7 +14271,7 @@ int DetectFastPatternTest495(void) "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14303,7 +14303,7 @@ int DetectFastPatternTest496(void) "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14335,7 +14335,7 @@ int DetectFastPatternTest497(void) "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14442,7 +14442,7 @@ int DetectFastPatternTest501(void) "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14571,7 +14571,7 @@ int DetectFastPatternTest506(void) "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14609,7 +14609,7 @@ int DetectFastPatternTest507(void) "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14719,7 +14719,7 @@ int DetectFastPatternTest510(void) if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -14756,7 +14756,7 @@ int DetectFastPatternTest511(void) goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14996,7 +14996,7 @@ int DetectFastPatternTest521(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15028,7 +15028,7 @@ int DetectFastPatternTest522(void) "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15060,7 +15060,7 @@ int DetectFastPatternTest523(void) "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15092,7 +15092,7 @@ int DetectFastPatternTest524(void) "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15123,7 +15123,7 @@ int DetectFastPatternTest525(void) "content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15248,7 +15248,7 @@ int DetectFastPatternTest530(void) "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15280,7 +15280,7 @@ int DetectFastPatternTest531(void) "content:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15312,7 +15312,7 @@ int DetectFastPatternTest532(void) "content:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15344,7 +15344,7 @@ int DetectFastPatternTest533(void) "content:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15376,7 +15376,7 @@ int DetectFastPatternTest534(void) "content:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15408,7 +15408,7 @@ int DetectFastPatternTest535(void) "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15440,7 +15440,7 @@ int DetectFastPatternTest536(void) "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15472,7 +15472,7 @@ int DetectFastPatternTest537(void) "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15504,7 +15504,7 @@ int DetectFastPatternTest538(void) "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15611,7 +15611,7 @@ int DetectFastPatternTest542(void) "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15740,7 +15740,7 @@ int DetectFastPatternTest547(void) "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15778,7 +15778,7 @@ int DetectFastPatternTest548(void) "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15889,7 +15889,7 @@ int DetectFastPatternTest551(void) if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15926,7 +15926,7 @@ int DetectFastPatternTest552(void) goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16166,7 +16166,7 @@ int DetectFastPatternTest562(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16198,7 +16198,7 @@ int DetectFastPatternTest563(void) "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16230,7 +16230,7 @@ int DetectFastPatternTest564(void) "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16262,7 +16262,7 @@ int DetectFastPatternTest565(void) "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16293,7 +16293,7 @@ int DetectFastPatternTest566(void) "content:\"two\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -16418,7 +16418,7 @@ int DetectFastPatternTest571(void) "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16450,7 +16450,7 @@ int DetectFastPatternTest572(void) "content:\"three\"; http_user_agent; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16482,7 +16482,7 @@ int DetectFastPatternTest573(void) "content:\"three\"; http_user_agent; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16514,7 +16514,7 @@ int DetectFastPatternTest574(void) "content:\"three\"; http_user_agent; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16546,7 +16546,7 @@ int DetectFastPatternTest575(void) "content:\"three\"; http_user_agent; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16578,7 +16578,7 @@ int DetectFastPatternTest576(void) "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16610,7 +16610,7 @@ int DetectFastPatternTest577(void) "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16642,7 +16642,7 @@ int DetectFastPatternTest578(void) "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16674,7 +16674,7 @@ int DetectFastPatternTest579(void) "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16781,7 +16781,7 @@ int DetectFastPatternTest583(void) "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -16910,7 +16910,7 @@ int DetectFastPatternTest588(void) "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -16948,7 +16948,7 @@ int DetectFastPatternTest589(void) "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -17058,7 +17058,7 @@ int DetectFastPatternTest592(void) if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -17095,7 +17095,7 @@ int DetectFastPatternTest593(void) goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17335,7 +17335,7 @@ int DetectFastPatternTest603(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -17367,7 +17367,7 @@ int DetectFastPatternTest604(void) "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -17399,7 +17399,7 @@ int DetectFastPatternTest605(void) "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -17431,7 +17431,7 @@ int DetectFastPatternTest606(void) "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -17462,7 +17462,7 @@ int DetectFastPatternTest607(void) "content:\"two\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -17587,7 +17587,7 @@ int DetectFastPatternTest612(void) "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17619,7 +17619,7 @@ int DetectFastPatternTest613(void) "content:\"three\"; http_host; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17651,7 +17651,7 @@ int DetectFastPatternTest614(void) "content:\"three\"; http_host; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17683,7 +17683,7 @@ int DetectFastPatternTest615(void) "content:\"three\"; http_host; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17715,7 +17715,7 @@ int DetectFastPatternTest616(void) "content:\"three\"; http_host; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17747,7 +17747,7 @@ int DetectFastPatternTest617(void) "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17779,7 +17779,7 @@ int DetectFastPatternTest618(void) "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17811,7 +17811,7 @@ int DetectFastPatternTest619(void) "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17843,7 +17843,7 @@ int DetectFastPatternTest620(void) "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17950,7 +17950,7 @@ int DetectFastPatternTest624(void) "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18079,7 +18079,7 @@ int DetectFastPatternTest629(void) "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18117,7 +18117,7 @@ int DetectFastPatternTest630(void) "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && ud->flags & DETECT_CONTENT_NOCASE && @@ -18232,7 +18232,7 @@ int DetectFastPatternTest633(void) if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18270,7 +18270,7 @@ int DetectFastPatternTest634(void) goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18511,7 +18511,7 @@ int DetectFastPatternTest644(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18544,7 +18544,7 @@ int DetectFastPatternTest645(void) "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18577,7 +18577,7 @@ int DetectFastPatternTest646(void) "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18610,7 +18610,7 @@ int DetectFastPatternTest647(void) "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18642,7 +18642,7 @@ int DetectFastPatternTest648(void) "content:\"two\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && @@ -18768,7 +18768,7 @@ int DetectFastPatternTest653(void) "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18801,7 +18801,7 @@ int DetectFastPatternTest654(void) "content:\"three\"; http_raw_host; distance:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18834,7 +18834,7 @@ int DetectFastPatternTest655(void) "content:\"three\"; http_raw_host; within:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18867,7 +18867,7 @@ int DetectFastPatternTest656(void) "content:\"three\"; http_raw_host; offset:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18900,7 +18900,7 @@ int DetectFastPatternTest657(void) "content:\"three\"; http_raw_host; depth:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18933,7 +18933,7 @@ int DetectFastPatternTest658(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18966,7 +18966,7 @@ int DetectFastPatternTest659(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18999,7 +18999,7 @@ int DetectFastPatternTest660(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -19032,7 +19032,7 @@ int DetectFastPatternTest661(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -19140,7 +19140,7 @@ int DetectFastPatternTest665(void) "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && @@ -19270,7 +19270,7 @@ int DetectFastPatternTest670(void) "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && @@ -19350,42 +19350,42 @@ int DetectFastPatternTest671(void) SigGroupBuild(de_ctx); sm = s[0]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; + cd = (DetectContentData *)sm->ctx; if (cd->id != 0) { printf("sm = s[0]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); goto end; } sm = s[1]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; + cd = (DetectContentData *)sm->ctx; if (cd->id != 0) { printf("sm = s[1]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); goto end; } sm = s[2]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; + cd = (DetectContentData *)sm->ctx; if (cd->id != 1) { printf("sm = s[2]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); goto end; } sm = s[3]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; + cd = (DetectContentData *)sm->ctx; if (cd->id != 2) { printf("sm = s[3]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); goto end; } sm = s[4]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; + cd = (DetectContentData *)sm->ctx; if (cd->id != 2) { printf("sm = s[4]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); goto end; } sm = s[5]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; + cd = (DetectContentData *)sm->ctx; if (cd->id != 0) { printf("sm = s[5]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); goto end; diff --git a/src/detect-filename.c b/src/detect-filename.c index 06ccc70bd0d6..8e5ddc1c0fee 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -94,7 +94,7 @@ static int DetectFilenameMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, SCEnter(); int ret = 0; - DetectFilenameData *filename = m->ctx; + DetectFilenameData *filename = (DetectFilenameData *)m->ctx; if (file->name == NULL) SCReturnInt(0); diff --git a/src/detect-filesize.c b/src/detect-filesize.c index e826e3c9b5f4..17a01216b8a3 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -115,7 +115,7 @@ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, F { SCEnter(); - DetectFilesizeData *fsd = m->ctx; + DetectFilesizeData *fsd = (DetectFilesizeData *)m->ctx; int ret = 0; SCLogDebug("file size %"PRIu64", check %"PRIu64, file->size, fsd->size1); @@ -306,7 +306,7 @@ static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *str goto error; sm->type = DETECT_FILESIZE; - sm->ctx = (void *)fsd; + sm->ctx = (SigMatchCtx *)fsd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); diff --git a/src/detect-filestore.c b/src/detect-filestore.c index f16fc4aa1edd..42bb74faf661 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -236,7 +236,7 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack FileStoreFileById(ffc, det_ctx->filestore[u].file_id); } } else { - DetectFilestoreData *filestore = s->filestore_sm->ctx; + DetectFilestoreData *filestore = (DetectFilestoreData *)s->filestore_sm->ctx; uint16_t u; for (u = 0; u < det_ctx->filestore_cnt; u++) { @@ -406,9 +406,9 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *st fd->scope = FILESTORE_SCOPE_DEFAULT; } - sm->ctx = fd; + sm->ctx = (SigMatchCtx*)fd; } else { - sm->ctx = NULL; + sm->ctx = (SigMatchCtx*)NULL; } if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { diff --git a/src/detect-flags.c b/src/detect-flags.c index f06f0f444ec3..b5b1840a82b9 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -56,7 +56,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectFlagsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectFlagsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectFlagsSetup (DetectEngineCtx *, Signature *, char *); static void DetectFlagsFree(void *); @@ -108,12 +108,12 @@ void DetectFlagsRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { SCEnter(); uint8_t flags = 0; - DetectFlagsData *de = (DetectFlagsData *)m->ctx; + const DetectFlagsData *de = (const DetectFlagsData *)ctx; if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { SCReturnInt(0); @@ -497,7 +497,7 @@ static int DetectFlagsSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -600,9 +600,9 @@ static int FlagsTestParse03 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -655,9 +655,9 @@ static int FlagsTestParse04 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -710,9 +710,9 @@ static int FlagsTestParse05 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -765,9 +765,9 @@ static int FlagsTestParse06 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -820,9 +820,9 @@ static int FlagsTestParse07 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -875,9 +875,9 @@ static int FlagsTestParse08 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -930,9 +930,9 @@ static int FlagsTestParse09 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -985,9 +985,9 @@ static int FlagsTestParse10 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -1040,9 +1040,9 @@ static int FlagsTestParse11 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -1097,9 +1097,9 @@ static int FlagsTestParse12 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -1181,9 +1181,9 @@ static int FlagsTestParse15(void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if (ret) { if (de) @@ -1234,9 +1234,9 @@ static int FlagsTestParse16(void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if (ret) { if (de) @@ -1290,9 +1290,9 @@ static int FlagsTestParse17(void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if (ret == 0) { if (de) diff --git a/src/detect-flow.c b/src/detect-flow.c index 8f908419ff5c..a7edaed721ca 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -48,7 +48,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFlowMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectFlowMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectFlowSetup (DetectEngineCtx *, Signature *, char *); void DetectFlowRegisterTests(void); void DetectFlowFree(void *); @@ -107,7 +107,7 @@ void DetectFlowRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { SCEnter(); @@ -126,7 +126,7 @@ int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S } uint8_t cnt = 0; - DetectFlowData *fd = (DetectFlowData *)m->ctx; + const DetectFlowData *fd = (const DetectFlowData *)ctx; if ((fd->flags & FLOW_PKT_TOSERVER) && (p->flowflags & FLOW_PKT_TOSERVER)) { cnt++; @@ -317,7 +317,7 @@ int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, char *flowstr) goto error; sm->type = DETECT_FLOW; - sm->ctx = (void *)fd; + sm->ctx = (SigMatchCtx *)fd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 129403792482..9960348db955 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -50,7 +50,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFlowbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectFlowbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectFlowbitSetup (DetectEngineCtx *, Signature *, char *); void DetectFlowbitFree (void *); void FlowBitsRegisterTests(void); @@ -92,7 +92,7 @@ void DetectFlowbitsRegister (void) } -static int DetectFlowbitMatchToggle (Packet *p, DetectFlowbitsData *fd) +static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; @@ -101,7 +101,7 @@ static int DetectFlowbitMatchToggle (Packet *p, DetectFlowbitsData *fd) return 1; } -static int DetectFlowbitMatchUnset (Packet *p, DetectFlowbitsData *fd) +static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; @@ -110,7 +110,7 @@ static int DetectFlowbitMatchUnset (Packet *p, DetectFlowbitsData *fd) return 1; } -static int DetectFlowbitMatchSet (Packet *p, DetectFlowbitsData *fd) +static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; @@ -119,7 +119,7 @@ static int DetectFlowbitMatchSet (Packet *p, DetectFlowbitsData *fd) return 1; } -static int DetectFlowbitMatchIsset (Packet *p, DetectFlowbitsData *fd) +static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; @@ -127,7 +127,7 @@ static int DetectFlowbitMatchIsset (Packet *p, DetectFlowbitsData *fd) return FlowBitIsset(p->flow,fd->idx); } -static int DetectFlowbitMatchIsnotset (Packet *p, DetectFlowbitsData *fd) +static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; @@ -141,9 +141,9 @@ static int DetectFlowbitMatchIsnotset (Packet *p, DetectFlowbitsData *fd) * -1: error */ -int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectFlowbitsData *fd = (DetectFlowbitsData *)m->ctx; + const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx; if (fd == NULL) return 0; @@ -247,7 +247,7 @@ int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) goto error; sm->type = DETECT_FLOWBITS; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; switch (fb_cmd) { case DETECT_FLOWBITS_CMD_NOALERT: diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 5da2fb88eda1..9023d21096f4 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -52,7 +52,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectFlowintMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectFlowintSetup(DetectEngineCtx *, Signature *, char *); void DetectFlowintFree(void *); void DetectFlowintRegisterTests(void); @@ -105,9 +105,9 @@ void DetectFlowintRegister(void) * condition */ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectFlowintData *sfd =(DetectFlowintData *) m->ctx; + const DetectFlowintData *sfd = (const DetectFlowintData *)ctx; FlowVar *fv; FlowVar *fvt; uint32_t targetval; @@ -388,7 +388,7 @@ static int DetectFlowintSetup(DetectEngineCtx *de_ctx, Signature *s, char *rawst goto error; sm->type = DETECT_FLOWINT; - sm->ctx = (void *)sfd; + sm->ctx = (SigMatchCtx *)sfd; switch (sfd->modifier) { case FLOWINT_MODIFIER_SET: diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index d764e085fdbf..0746393e637c 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -44,9 +44,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFlowvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectFlowvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectFlowvarSetup (DetectEngineCtx *, Signature *, char *); -static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm); +static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx); static void DetectFlowvarDataFree(void *ptr); void DetectFlowvarRegister (void) @@ -114,10 +114,10 @@ static void DetectFlowvarDataFree(void *ptr) * -1: error */ -int DetectFlowvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectFlowvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { int ret = 0; - DetectFlowvarData *fd = (DetectFlowvarData *)m->ctx; + DetectFlowvarData *fd = (DetectFlowvarData *)ctx; /* we need a lock */ FLOWLOCK_RDLOCK(p->flow); @@ -197,7 +197,7 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws goto error; sm->type = DETECT_FLOWVAR; - sm->ctx = (void *)fd; + sm->ctx = (SigMatchCtx *)fd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -269,7 +269,7 @@ int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx) goto error; sm->type = DETECT_FLOWVAR_POSTMATCH; - sm->ctx = (void *)fv; + sm->ctx = (SigMatchCtx *)fv; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); return 0; @@ -284,15 +284,15 @@ int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx) * \param sm sigmatch containing the idx to store * \retval 1 or -1 in case of error */ -static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) +static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { DetectFlowvarList *fs, *prev; - DetectFlowvarData *fd; + const DetectFlowvarData *fd; if (det_ctx->flowvarlist == NULL || p->flow == NULL) return 1; - fd = (DetectFlowvarData *)sm->ctx; + fd = (const DetectFlowvarData *)ctx; prev = NULL; fs = det_ctx->flowvarlist; diff --git a/src/detect-fragbits.c b/src/detect-fragbits.c index 2be69b76d2eb..7a564ba01af5 100644 --- a/src/detect-fragbits.c +++ b/src/detect-fragbits.c @@ -65,7 +65,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectFragBitsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectFragBitsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectFragBitsSetup (DetectEngineCtx *, Signature *, char *); static void DetectFragBitsFree(void *); @@ -119,11 +119,11 @@ void DetectFragBitsRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectFragBitsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectFragBitsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { int ret = 0; uint16_t fragbits = 0; - DetectFragBitsData *de = (DetectFragBitsData *)m->ctx; + const DetectFragBitsData *de = (const DetectFragBitsData *)ctx; if (!de || !PKT_IS_IPV4(p) || !p || PKT_IS_PSEUDOPKT(p)) return ret; @@ -302,7 +302,7 @@ static int DetectFragBitsSetup (DetectEngineCtx *de_ctx, Signature *s, char *raw goto error; sm->type = DETECT_FRAGBITS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -446,9 +446,9 @@ static int FragBitsTestParse03 (void) goto error; sm->type = DETECT_FRAGBITS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFragBitsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFragBitsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -544,9 +544,9 @@ static int FragBitsTestParse04 (void) goto error; sm->type = DETECT_FRAGBITS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFragBitsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFragBitsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index 3c5cc1697daf..c887b7b97986 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -43,7 +43,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFragOffsetMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectFragOffsetMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectFragOffsetSetup(DetectEngineCtx *, Signature *, char *); void DetectFragOffsetRegisterTests(void); void DetectFragOffsetFree(void *); @@ -94,10 +94,10 @@ void DetectFragOffsetRegister (void) * \retval 1 match * */ -int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { uint16_t frag = 0; - DetectFragOffsetData *fragoff = (DetectFragOffsetData *)m->ctx; + const DetectFragOffsetData *fragoff = (const DetectFragOffsetData *)ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; @@ -230,7 +230,7 @@ static int DetectFragOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *f if (sm == NULL) goto error; sm->type = DETECT_FRAGOFFSET; - sm->ctx = (void *)fragoff; + sm->ctx = (SigMatchCtx *)fragoff; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-geoip.c b/src/detect-geoip.c index 5c7244969073..9bdbae052064 100644 --- a/src/detect-geoip.c +++ b/src/detect-geoip.c @@ -63,7 +63,7 @@ void DetectGeoipRegister(void) static int DetectGeoipMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, SigMatchCtx *); static int DetectGeoipSetup(DetectEngineCtx *, Signature *, char *); static void DetectGeoipRegisterTests(void); static void DetectGeoipDataFree(void *); @@ -165,9 +165,9 @@ static int CheckGeoMatchIPv4(DetectGeoipData *geoipdata, uint32_t ip) * \retval 1 match */ static int DetectGeoipMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, SigMatchCtx *ctx) { - DetectGeoipData *geoipdata = (DetectGeoipData *)m->ctx; + DetectGeoipData *geoipdata = (DetectGeoipData *)ctx; int matches = 0; if (PKT_IS_PSEUDOPKT(p)) @@ -339,7 +339,7 @@ static int DetectGeoipSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) goto error; sm->type = DETECT_GEOIP; - sm->ctx = (void *)geoipdata; + sm->ctx = (SigMatchCtx *)geoipdata; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 112e11efef53..e6c902aab155 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -1718,10 +1718,10 @@ int DetectHttpClientBodyTest22(void) goto end; } - DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1773,10 +1773,10 @@ int DetectHttpClientBodyTest23(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1827,10 +1827,10 @@ int DetectHttpClientBodyTest24(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1882,10 +1882,10 @@ int DetectHttpClientBodyTest25(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1938,10 +1938,10 @@ int DetectHttpClientBodyTest26(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2021,10 +2021,10 @@ int DetectHttpClientBodyTest28(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2076,8 +2076,8 @@ int DetectHttpClientBodyTest29(void) goto end; } - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_DISTANCE || @@ -2120,8 +2120,8 @@ int DetectHttpClientBodyTest30(void) goto end; } - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_WITHIN || @@ -2244,8 +2244,8 @@ int DetectHttpClientBodyTest34(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hcbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { @@ -2295,8 +2295,8 @@ int DetectHttpClientBodyTest35(void) goto end; } - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "two", hcbd1->content_len) != 0) { @@ -2346,8 +2346,8 @@ int DetectHttpClientBodyTest36(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hcbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 8f902cc9ae3e..6c9fea9a340a 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -1237,8 +1237,8 @@ int DetectHttpHeaderTest20(void) goto end; } - DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "one", hhd1->content_len) != 0 || hhd2->flags != DETECT_CONTENT_DISTANCE || @@ -1281,8 +1281,8 @@ int DetectHttpHeaderTest21(void) goto end; } - DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "one", hhd1->content_len) != 0 || hhd2->flags != DETECT_CONTENT_WITHIN || @@ -1405,8 +1405,8 @@ int DetectHttpHeaderTest25(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_WITHIN || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { @@ -1456,8 +1456,8 @@ int DetectHttpHeaderTest26(void) goto end; } - DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "two", hhd1->content_len) != 0) { @@ -1507,8 +1507,8 @@ int DetectHttpHeaderTest27(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 4df0fe329a80..19e87e162431 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -1418,10 +1418,10 @@ int DetectHttpHHTest22(void) goto end; } - DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1473,10 +1473,10 @@ int DetectHttpHHTest23(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1527,10 +1527,10 @@ int DetectHttpHHTest24(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1582,10 +1582,10 @@ int DetectHttpHHTest25(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1638,10 +1638,10 @@ int DetectHttpHHTest26(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1721,10 +1721,10 @@ int DetectHttpHHTest28(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1776,8 +1776,8 @@ int DetectHttpHHTest29(void) goto end; } - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || @@ -1820,8 +1820,8 @@ int DetectHttpHHTest30(void) goto end; } - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_WITHIN) || @@ -1944,8 +1944,8 @@ int DetectHttpHHTest34(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhhd2->flags != (DETECT_CONTENT_WITHIN) || memcmp(hhhd2->content, "two", hhhd2->content_len) != 0) { @@ -1995,8 +1995,8 @@ int DetectHttpHHTest35(void) goto end; } - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "two", hhhd1->content_len) != 0) { @@ -2046,8 +2046,8 @@ int DetectHttpHHTest36(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hhhd2->content, "two", hhhd2->content_len) != 0) { diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index fd15544c374d..a6a56b1080ca 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -1414,10 +1414,10 @@ int DetectHttpHRHTest22(void) goto end; } - DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1469,10 +1469,10 @@ int DetectHttpHRHTest23(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1523,10 +1523,10 @@ int DetectHttpHRHTest24(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1578,10 +1578,10 @@ int DetectHttpHRHTest25(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1634,10 +1634,10 @@ int DetectHttpHRHTest26(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1717,10 +1717,10 @@ int DetectHttpHRHTest28(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1772,8 +1772,8 @@ int DetectHttpHRHTest29(void) goto end; } - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || @@ -1816,8 +1816,8 @@ int DetectHttpHRHTest30(void) goto end; } - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_WITHIN) || @@ -1940,8 +1940,8 @@ int DetectHttpHRHTest34(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_CASELESS) || hrhhd2->flags != (DETECT_CONTENT_WITHIN) || memcmp(hrhhd2->content, "two", hrhhd2->content_len) != 0) { @@ -1991,8 +1991,8 @@ int DetectHttpHRHTest35(void) goto end; } - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_CASELESS) || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "two", hrhhd1->content_len) != 0) { @@ -2042,8 +2042,8 @@ int DetectHttpHRHTest36(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_CASELESS) || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hrhhd2->content, "two", hrhhd2->content_len) != 0) { diff --git a/src/detect-http-method.c b/src/detect-http-method.c index f398de44837a..4cc8a7873f7f 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -292,8 +292,8 @@ static int DetectHttpMethodTest12(void) goto end; } - DetectContentData *hmd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; - DetectContentData *hmd2 = de_ctx->sig_list->next->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *hmd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *hmd2 = (DetectContentData *)de_ctx->sig_list->next->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (!(hmd1->flags & DETECT_CONTENT_NOCASE)) { printf("nocase flag not set on sig 1: "); diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index 61e2f153c16e..1a5f0eb27571 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -1236,8 +1236,8 @@ int DetectHttpRawHeaderTest20(void) goto end; } - DetectContentData *hrhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hrhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *hrhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *hrhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (hrhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hrhd1->content, "one", hrhd1->content_len) != 0 || hrhd2->flags != DETECT_CONTENT_DISTANCE || @@ -1280,8 +1280,8 @@ int DetectHttpRawHeaderTest21(void) goto end; } - DetectContentData *hrhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hrhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *hrhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *hrhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (hrhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hrhd1->content, "one", hrhd1->content_len) != 0 || hrhd2->flags != DETECT_CONTENT_WITHIN || @@ -1404,8 +1404,8 @@ int DetectHttpRawHeaderTest25(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_WITHIN || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { @@ -1455,8 +1455,8 @@ int DetectHttpRawHeaderTest26(void) goto end; } - DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "two", hhd1->content_len) != 0) { @@ -1506,8 +1506,8 @@ int DetectHttpRawHeaderTest27(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 7cedd8927122..e269686e5deb 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -304,9 +304,9 @@ int DetectHttpRawUriTest12(void) } DetectContentData *ud1 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; DetectContentData *ud2 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -351,9 +351,9 @@ int DetectHttpRawUriTest13(void) } DetectContentData *ud1 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; DetectContentData *ud2 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || @@ -470,9 +470,9 @@ int DetectHttpRawUriTest17(void) } DetectContentData *ud1 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; DetectContentData *ud2 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -518,9 +518,9 @@ int DetectHttpRawUriTest18(void) } DetectContentData *ud1 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; DetectContentData *ud2 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index 01a9def8f2fd..9406aa12f25d 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -1758,10 +1758,10 @@ int DetectHttpServerBodyTest22(void) goto end; } - DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1813,10 +1813,10 @@ int DetectHttpServerBodyTest23(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1867,10 +1867,10 @@ int DetectHttpServerBodyTest24(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1922,10 +1922,10 @@ int DetectHttpServerBodyTest25(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1978,10 +1978,10 @@ int DetectHttpServerBodyTest26(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2061,10 +2061,10 @@ int DetectHttpServerBodyTest28(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2116,8 +2116,8 @@ int DetectHttpServerBodyTest29(void) goto end; } - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_DISTANCE || @@ -2160,8 +2160,8 @@ int DetectHttpServerBodyTest30(void) goto end; } - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_WITHIN || @@ -2284,8 +2284,8 @@ int DetectHttpServerBodyTest34(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hsbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { @@ -2335,8 +2335,8 @@ int DetectHttpServerBodyTest35(void) goto end; } - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "two", hsbd1->content_len) != 0) { @@ -2386,8 +2386,8 @@ int DetectHttpServerBodyTest36(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hsbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index e335aeb101c4..cae5e9faee00 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -1422,10 +1422,10 @@ int DetectHttpUATest22(void) goto end; } - DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1477,10 +1477,10 @@ int DetectHttpUATest23(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1531,10 +1531,10 @@ int DetectHttpUATest24(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1586,10 +1586,10 @@ int DetectHttpUATest25(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1642,10 +1642,10 @@ int DetectHttpUATest26(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1725,10 +1725,10 @@ int DetectHttpUATest28(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1780,8 +1780,8 @@ int DetectHttpUATest29(void) goto end; } - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_DISTANCE || @@ -1824,8 +1824,8 @@ int DetectHttpUATest30(void) goto end; } - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_WITHIN || @@ -1948,8 +1948,8 @@ int DetectHttpUATest34(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || huad2->flags != DETECT_CONTENT_WITHIN || memcmp(huad2->content, "two", huad2->content_len) != 0) { @@ -1999,8 +1999,8 @@ int DetectHttpUATest35(void) goto end; } - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "two", huad1->content_len) != 0) { @@ -2050,8 +2050,8 @@ int DetectHttpUATest36(void) goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || huad2->flags != DETECT_CONTENT_DISTANCE || memcmp(huad2->content, "two", huad2->content_len) != 0) { diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index a4a4782d7924..92c4803e18ba 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -296,8 +296,8 @@ int DetectHttpUriTest12(void) goto end; } - DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -340,8 +340,8 @@ int DetectHttpUriTest13(void) goto end; } - DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || @@ -402,7 +402,7 @@ int DetectHttpUriTest15(void) goto end; } - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (memcmp(cd->content, "one", cd->content_len) != 0 || cd->flags != DETECT_CONTENT_WITHIN) { goto end; @@ -467,8 +467,8 @@ int DetectHttpUriTest17(void) goto end; } - DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -511,8 +511,8 @@ int DetectHttpUriTest18(void) goto end; } - DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index fefcd025f627..5d6f7f263985 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -42,7 +42,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIcmpIdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectIcmpIdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectIcmpIdSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpIdRegisterTests(void); void DetectIcmpIdFree(void *); @@ -92,10 +92,10 @@ void DetectIcmpIdRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { uint16_t pid; - DetectIcmpIdData *iid = (DetectIcmpIdData *)m->ctx; + const DetectIcmpIdData *iid = (const DetectIcmpIdData *)ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; @@ -240,7 +240,7 @@ static int DetectIcmpIdSetup (DetectEngineCtx *de_ctx, Signature *s, char *icmpi if (sm == NULL) goto error; sm->type = DETECT_ICMP_ID; - sm->ctx = (void *)iid; + sm->ctx = (SigMatchCtx *)iid; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index b5bccc0c1cef..4e3fe1ac1961 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -42,7 +42,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIcmpSeqMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectIcmpSeqMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectIcmpSeqSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpSeqRegisterTests(void); void DetectIcmpSeqFree(void *); @@ -92,10 +92,10 @@ void DetectIcmpSeqRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { uint16_t seqn; - DetectIcmpSeqData *iseq = (DetectIcmpSeqData *)m->ctx; + const DetectIcmpSeqData *iseq = (const DetectIcmpSeqData *)ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; @@ -242,7 +242,7 @@ static int DetectIcmpSeqSetup (DetectEngineCtx *de_ctx, Signature *s, char *icmp if (sm == NULL) goto error; sm->type = DETECT_ICMP_SEQ; - sm->ctx = (void *)iseq; + sm->ctx = (SigMatchCtx *)iseq; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); diff --git a/src/detect-icode.c b/src/detect-icode.c index ff82274e341c..05c35a722169 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -45,7 +45,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectICodeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectICodeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectICodeSetup(DetectEngineCtx *, Signature *, char *); void DetectICodeRegisterTests(void); void DetectICodeFree(void *); @@ -98,11 +98,11 @@ void DetectICodeRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectICodeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectICodeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { int ret = 0; uint8_t picode; - DetectICodeData *icd = (DetectICodeData *)m->ctx; + const DetectICodeData *icd = (const DetectICodeData *)ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; @@ -259,7 +259,7 @@ static int DetectICodeSetup(DetectEngineCtx *de_ctx, Signature *s, char *icodest if (sm == NULL) goto error; sm->type = DETECT_ICODE; - sm->ctx = (void *)icd; + sm->ctx = (SigMatchCtx *)icd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-id.c b/src/detect-id.c index d9b861c80014..bb084d2c7671 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -49,7 +49,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectIdMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectIdSetup (DetectEngineCtx *, Signature *, char *); void DetectIdRegisterTests(void); void DetectIdFree(void *); @@ -103,9 +103,9 @@ void DetectIdRegister (void) * \retval 1 match */ int DetectIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s, SigMatch *m) + Signature *s, const SigMatchCtx *ctx) { - DetectIdData *id_d = (DetectIdData *)m->ctx; + const DetectIdData *id_d = (const DetectIdData *)ctx; /** * To match a ipv4 packet with a "id" rule @@ -233,7 +233,7 @@ int DetectIdSetup (DetectEngineCtx *de_ctx, Signature *s, char *idstr) goto error; sm->type = DETECT_ID; - sm->ctx = (void *)id_d; + sm->ctx = (SigMatchCtx *)id_d; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index a8bfc065b604..159578ee0e89 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -46,7 +46,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIpOptsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectIpOptsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectIpOptsSetup (DetectEngineCtx *, Signature *, char *); void IpOptsRegisterTests(void); void DetectIpOptsFree(void *); @@ -101,11 +101,11 @@ void DetectIpOptsRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectIpOptsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectIpOptsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { int ret = 0; int ipopt = 0; - DetectIpOptsData *de = (DetectIpOptsData *)m->ctx; + const DetectIpOptsData *de = (const DetectIpOptsData *)ctx; if (!de || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) return ret; @@ -201,7 +201,7 @@ static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst goto error; sm->type = DETECT_IPOPTS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -303,9 +303,9 @@ int IpOptsTestParse03 (void) goto error; sm->type = DETECT_IPOPTS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectIpOptsMatch(&tv,NULL,p,NULL,sm); + ret = DetectIpOptsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { SCFree(p); @@ -355,9 +355,9 @@ int IpOptsTestParse04 (void) goto error; sm->type = DETECT_IPOPTS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectIpOptsMatch(&tv,NULL,p,NULL,sm); + ret = DetectIpOptsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { SCFree(p); diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index a40403681888..d8ffc44b7910 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -294,7 +294,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst temp_sm = temp_sm->next; } if (temp_sm != NULL) { - DetectIPProtoData *data_temp = temp_sm->ctx; + DetectIPProtoData *data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto <= data->proto) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have " "both gt and lt ipprotos, with the lt being " @@ -337,7 +337,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst temp_sm = temp_sm->next; } if (temp_sm != NULL) { - data_temp = temp_sm->ctx; + data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto <= data->proto) { /* Updated by AS. Please do not remove this unused code. * Need it as we redo this code once we solve ipproto @@ -413,7 +413,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst temp_sm = temp_sm->next; } if (temp_sm != NULL) { - DetectIPProtoData *data_temp = temp_sm->ctx; + DetectIPProtoData *data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto >= data->proto) { /* Updated by AS. Please do not remove this unused code. * Need it as we redo this code once we solve ipproto @@ -457,7 +457,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst temp_sm = temp_sm->next; } if (temp_sm != NULL) { - data_temp = temp_sm->ctx; + data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto >= data->proto) { /* Updated by AS. Please do not remove this unused code. * Need it as we redo this code once we solve ipproto diff --git a/src/detect-iprep.c b/src/detect-iprep.c index 89b297a5f19c..4e47acdcb6a0 100644 --- a/src/detect-iprep.c +++ b/src/detect-iprep.c @@ -52,7 +52,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIPRepMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectIPRepMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectIPRepSetup (DetectEngineCtx *, Signature *, char *); void DetectIPRepFree (void *); void IPRepRegisterTests(void); @@ -187,9 +187,9 @@ static inline int RepMatch(uint8_t op, uint8_t val1, uint8_t val2) * 1: match * -1: error */ -int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectIPRepData *rd = (DetectIPRepData *)m->ctx; + const DetectIPRepData *rd = (const DetectIPRepData *)ctx; if (rd == NULL) return 0; @@ -368,7 +368,7 @@ int DetectIPRepSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) goto error; sm->type = DETECT_IPREP; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index e8e11df1c17c..f2c3895392fa 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -55,7 +55,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIsdataatMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectIsdataatMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); int DetectIsdataatSetup (DetectEngineCtx *, Signature *, char *); void DetectIsdataatRegisterTests(void); void DetectIsdataatFree(void *); @@ -109,9 +109,9 @@ void DetectIsdataatRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectIsdataatMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectIsdataatMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectIsdataatData *idad = (DetectIsdataatData *)m->ctx; + const DetectIsdataatData *idad = (const DetectIsdataatData *)ctx; SCLogDebug("payload_len: %u , dataat? %u ; relative? %u...", p->payload_len,idad->dataat,idad->flags &ISDATAAT_RELATIVE); @@ -390,7 +390,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst if (sm == NULL) goto end; sm->type = DETECT_ISDATAAT; - sm->ctx = (void *)idad; + sm->ctx = (SigMatchCtx *)idad; SigMatchAppendSMToList(s, sm, sm_list); if (!(idad->flags & ISDATAAT_RELATIVE)) { diff --git a/src/detect-itype.c b/src/detect-itype.c index 1828dbc02522..1be076478460 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -45,7 +45,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectITypeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectITypeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectITypeSetup(DetectEngineCtx *, Signature *, char *); void DetectITypeRegisterTests(void); void DetectITypeFree(void *); @@ -98,11 +98,11 @@ void DetectITypeRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectITypeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectITypeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { int ret = 0; uint8_t pitype; - DetectITypeData *itd = (DetectITypeData *)m->ctx; + const DetectITypeData *itd = (const DetectITypeData *)ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; @@ -259,7 +259,7 @@ static int DetectITypeSetup(DetectEngineCtx *de_ctx, Signature *s, char *itypest if (sm == NULL) goto error; sm->type = DETECT_ITYPE; - sm->ctx = (void *)itd; + sm->ctx = (SigMatchCtx *)itd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-lua.c b/src/detect-lua.c index d711cb6eb1bf..def801859324 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* 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 @@ -108,7 +108,7 @@ static pthread_mutex_t luajit_states_lock = SCMUTEX_INITIALIZER; #include "util-lua.h" static int DetectLuaMatch (ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, SigMatch *); + Packet *, Signature *, const SigMatchCtx *); static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m); static int DetectLuaSetup (DetectEngineCtx *, Signature *, char *); @@ -382,11 +382,11 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch * \retval 1 match */ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; - DetectLuaData *luajit = (DetectLuaData *)m->ctx; + DetectLuaData *luajit = (DetectLuaData *)ctx; if (luajit == NULL) SCReturnInt(0); @@ -1015,7 +1015,7 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) goto error; sm->type = DETECT_LUA; - sm->ctx = (void *)luajit; + sm->ctx = (SigMatchCtx *)luajit; if (luajit->alproto == ALPROTO_UNKNOWN) { if (luajit->flags & DATATYPE_STREAM) @@ -1075,7 +1075,7 @@ void DetectLuaPostSetup(Signature *s) if (sm->type != DETECT_LUA) continue; - DetectLuaData *ld = sm->ctx; + DetectLuaData *ld = (DetectLuaData *)sm->ctx; ld->sid = s->id; ld->rev = s->rev; ld->gid = s->gid; diff --git a/src/detect-mark.c b/src/detect-mark.c index d641df6fd2f2..695a7b412cc9 100644 --- a/src/detect-mark.c +++ b/src/detect-mark.c @@ -43,7 +43,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectMarkSetup (DetectEngineCtx *, Signature *, char *); -int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m); +int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx); void DetectMarkDataFree(void *ptr); /** @@ -219,7 +219,7 @@ static int DetectMarkSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) } sm->type = DETECT_MARK; - sm->ctx = (void *)data; + sm->ctx = (SigMatchCtx *)data; /* Append it to the list of tags */ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TMATCH); @@ -237,10 +237,10 @@ void DetectMarkDataFree(void *ptr) } -int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { #ifdef NFQ - DetectMarkData *nf_data = (DetectMarkData *) m->ctx; + const DetectMarkData *nf_data = (const DetectMarkData *)ctx; if (nf_data->mask) { p->nfq_v.mark = (nf_data->mark & nf_data->mask) | (p->nfq_v.mark & ~(nf_data->mask)); diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 1c649f21ff18..61c98b118c29 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -3716,7 +3716,7 @@ static int DetectPcreFlowvarCapture01(void) s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + DetectPcreData *pd = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -3842,7 +3842,7 @@ static int DetectPcreFlowvarCapture02(void) s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:3; sid:2;)"); if (s == NULL) { @@ -3855,7 +3855,7 @@ static int DetectPcreFlowvarCapture02(void) s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd2 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; if (pd1->capidx != pd2->capidx) { printf("capidx mismatch, %u != %u: ", pd1->capidx, pd2->capidx); @@ -3988,7 +3988,7 @@ static int DetectPcreFlowvarCapture03(void) s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:3; sid:2;)"); if (s == NULL) { @@ -4001,7 +4001,7 @@ static int DetectPcreFlowvarCapture03(void) s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd2 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; if (pd1->capidx != pd2->capidx) { printf("capidx mismatch, %u != %u: ", pd1->capidx, pd2->capidx); diff --git a/src/detect-pktvar.c b/src/detect-pktvar.c index 813c20ed3005..c841f69d359c 100644 --- a/src/detect-pktvar.c +++ b/src/detect-pktvar.c @@ -39,7 +39,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectPktvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectPktvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectPktvarSetup (DetectEngineCtx *, Signature *, char *); void DetectPktvarRegister (void) @@ -82,10 +82,10 @@ void DetectPktvarRegister (void) * -1: error */ -int DetectPktvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectPktvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { int ret = 0; - DetectPktvarData *pd = (DetectPktvarData *)m->ctx; + const DetectPktvarData *pd = (const DetectPktvarData *)ctx; PktVar *pv = PktVarGet(p, pd->name); if (pv != NULL) { @@ -236,7 +236,7 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst goto error; sm->type = DETECT_PKTVAR; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); diff --git a/src/detect-rpc.c b/src/detect-rpc.c index ba7b426c1730..86fc03c645af 100644 --- a/src/detect-rpc.c +++ b/src/detect-rpc.c @@ -48,7 +48,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectRpcMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectRpcMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); int DetectRpcSetup (DetectEngineCtx *, Signature *, char *); void DetectRpcRegisterTests(void); void DetectRpcFree(void *); @@ -107,10 +107,10 @@ void DetectRpcRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectRpcMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectRpcMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { /* PrintRawDataFp(stdout, p->payload, p->payload_len); */ - DetectRpcData *rd = (DetectRpcData *)m->ctx; + const DetectRpcData *rd = (const DetectRpcData *)ctx; char *rpcmsg = (char *)p->payload; if (PKT_IS_TCP(p)) { @@ -286,7 +286,7 @@ int DetectRpcSetup (DetectEngineCtx *de_ctx, Signature *s, char *rpcstr) goto error; sm->type = DETECT_RPC; - sm->ctx = (void *)rd; + sm->ctx = (SigMatchCtx *)rd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-sameip.c b/src/detect-sameip.c index db17e21599e4..a8e02908b9ed 100644 --- a/src/detect-sameip.c +++ b/src/detect-sameip.c @@ -38,7 +38,7 @@ #include "util-unittest-helper.h" static int DetectSameipMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static int DetectSameipSetup(DetectEngineCtx *, Signature *, char *); static void DetectSameipRegisterTests(void); @@ -71,7 +71,7 @@ void DetectSameipRegister(void) * \retval 1 match */ static int DetectSameipMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { return CMP_ADDR(&p->src, &p->dst) ? 1 : 0; } diff --git a/src/detect-seq.c b/src/detect-seq.c index b78fa567de0c..4d285ca344a1 100644 --- a/src/detect-seq.c +++ b/src/detect-seq.c @@ -41,7 +41,7 @@ static int DetectSeqSetup(DetectEngineCtx *, Signature *, char *); static int DetectSeqMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, SigMatch *); + Packet *, Signature *, const SigMatchCtx *); static void DetectSeqRegisterTests(void); static void DetectSeqFree(void *); @@ -70,9 +70,9 @@ void DetectSeqRegister(void) * \retval 1 match */ static int DetectSeqMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectSeqData *data = (DetectSeqData *)m->ctx; + const DetectSeqData *data = (const DetectSeqData *)ctx; /* This is only needed on TCP packets */ if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { @@ -111,7 +111,7 @@ static int DetectSeqSetup (DetectEngineCtx *de_ctx, Signature *s, char *optstr) if (-1 == ByteExtractStringUint32(&data->seq, 10, 0, optstr)) { goto error; } - sm->ctx = data; + sm->ctx = (SigMatchCtx*)data; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index ade64358784f..fa296631acf2 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -300,7 +300,7 @@ int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) goto error; sm->type = DETECT_AL_SSL_STATE; - sm->ctx = ssd; + sm->ctx = (SigMatchCtx*)ssd; if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c index 200ce76b5a91..bec2edce6ef9 100644 --- a/src/detect-stream_size.c +++ b/src/detect-stream_size.c @@ -44,7 +44,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; /*prototypes*/ -int DetectStreamSizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectStreamSizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectStreamSizeSetup (DetectEngineCtx *, Signature *, char *); void DetectStreamSizeFree(void *); void DetectStreamSizeRegisterTests(void); @@ -141,11 +141,11 @@ static int DetectStreamSizeCompare (uint32_t diff, uint32_t stream_size, uint8_t * \retval 0 no match * \retval 1 match */ -int DetectStreamSizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectStreamSizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { int ret = 0; - DetectStreamSizeData *sd = (DetectStreamSizeData *) m->ctx; + const DetectStreamSizeData *sd = (const DetectStreamSizeData *)ctx; if (!(PKT_IS_TCP(p))) return ret; @@ -320,7 +320,7 @@ static int DetectStreamSizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *s goto error; sm->type = DETECT_STREAM_SIZE; - sm->ctx = (void *)sd; + sm->ctx = (SigMatchCtx *)sd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -447,9 +447,9 @@ static int DetectStreamSizeParseTest03 (void) f.protoctx = &ssn; p->flow = &f; p->tcph = &tcph; - sm.ctx = sd; + sm.ctx = (SigMatchCtx*)sd; - result = DetectStreamSizeMatch(&tv, &dtx, p, &s, &sm); + result = DetectStreamSizeMatch(&tv, &dtx, p, &s, sm.ctx); if (result == 0) { printf("result 0 != 1: "); } @@ -507,9 +507,9 @@ static int DetectStreamSizeParseTest04 (void) f.protoctx = &ssn; p->flow = &f; p->ip4h = &ip4h; - sm.ctx = sd; + sm.ctx = (SigMatchCtx*)sd; - if (!DetectStreamSizeMatch(&tv, &dtx, p, &s, &sm)) + if (!DetectStreamSizeMatch(&tv, &dtx, p, &s, sm.ctx)) result = 1; SCFree(p); diff --git a/src/detect-tag.c b/src/detect-tag.c index 5e0f85ffe81a..d011a0bea4d3 100644 --- a/src/detect-tag.c +++ b/src/detect-tag.c @@ -57,7 +57,7 @@ SC_ATOMIC_EXTERN(unsigned int, num_tags); static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectTagMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectTagMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectTagSetup(DetectEngineCtx *, Signature *, char *); void DetectTagRegisterTests(void); void DetectTagDataFree(void *); @@ -109,9 +109,9 @@ void DetectTagRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectTagMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectTagMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectTagData *td = (DetectTagData *) m->ctx; + const DetectTagData *td = (const DetectTagData *)ctx; DetectTagDataEntry tde; memset(&tde, 0, sizeof(DetectTagDataEntry)); @@ -313,7 +313,7 @@ int DetectTagSetup(DetectEngineCtx *de_ctx, Signature *s, char *tagstr) goto error; sm->type = DETECT_TAG; - sm->ctx = (void *)td; + sm->ctx = (SigMatchCtx *)td; /* Append it to the list of tags */ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TMATCH); diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 08eadbebda47..4f47756718ed 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -65,7 +65,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectThresholdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectThresholdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectThresholdSetup(DetectEngineCtx *, Signature *, char *); static void DetectThresholdFree(void *); @@ -108,7 +108,7 @@ void DetectThresholdRegister(void) } -static int DetectThresholdMatch(ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) +static int DetectThresholdMatch(ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { return 1; } @@ -261,7 +261,7 @@ static int DetectThresholdSetup(DetectEngineCtx *de_ctx, Signature *s, char *raw goto error; sm->type = DETECT_THRESHOLD; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); @@ -1484,7 +1484,7 @@ static int DetectThresholdTestSig12(void) SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void*)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); diff --git a/src/detect-tos.c b/src/detect-tos.c index 942dd28b5e58..40928261d782 100644 --- a/src/detect-tos.c +++ b/src/detect-tos.c @@ -50,7 +50,7 @@ static pcre_extra *parse_regex_study; static int DetectTosSetup(DetectEngineCtx *, Signature *, char *); static int DetectTosMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + Signature *, const SigMatchCtx *); static void DetectTosRegisterTests(void); static void DetectTosFree(void *); @@ -103,9 +103,9 @@ void DetectTosRegister(void) * \retval 1 match */ int DetectTosMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s, SigMatch *sm) + Signature *s, const SigMatchCtx *ctx) { - DetectTosData *tosd = (DetectTosData *)sm->ctx; + const DetectTosData *tosd = (const DetectTosData *)ctx; int result = 0; if (!PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) { @@ -215,7 +215,7 @@ int DetectTosSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) goto error; sm->type = DETECT_TOS; - sm->ctx = (void *)tosd; + sm->ctx = (SigMatchCtx *)tosd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-ttl.c b/src/detect-ttl.c index f348ea2b02d8..80f3966726af 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -42,7 +42,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; /*prototypes*/ -int DetectTtlMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectTtlMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectTtlSetup (DetectEngineCtx *, Signature *, char *); void DetectTtlFree (void *); void DetectTtlRegisterTests (void); @@ -95,12 +95,12 @@ void DetectTtlRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectTtlMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectTtlMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { int ret = 0; uint8_t pttl; - DetectTtlData *ttld = (DetectTtlData *) m->ctx; + const DetectTtlData *ttld = (const DetectTtlData *)ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; @@ -288,7 +288,7 @@ static int DetectTtlSetup (DetectEngineCtx *de_ctx, Signature *s, char *ttlstr) goto error; sm->type = DETECT_TTL; - sm->ctx = (void *)ttld; + sm->ctx = (SigMatchCtx *)ttld; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect-window.c b/src/detect-window.c index f98e0258ebf0..e770f71b1be2 100644 --- a/src/detect-window.c +++ b/src/detect-window.c @@ -47,7 +47,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectWindowMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectWindowMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); int DetectWindowSetup(DetectEngineCtx *, Signature *, char *); void DetectWindowRegisterTests(void); void DetectWindowFree(void *); @@ -104,9 +104,9 @@ void DetectWindowRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectWindowData *wd = (DetectWindowData *)m->ctx; + const DetectWindowData *wd = (const DetectWindowData *)ctx; if ( !(PKT_IS_TCP(p)) || wd == NULL || PKT_IS_PSEUDOPKT(p)) { return 0; @@ -219,7 +219,7 @@ int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, char *windowstr) goto error; sm->type = DETECT_WINDOW; - sm->ctx = (void *)wd; + sm->ctx = (SigMatchCtx *)wd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; diff --git a/src/detect.c b/src/detect.c index ae5c7b0e7ac3..bbaa0bb04f63 100644 --- a/src/detect.c +++ b/src/detect.c @@ -612,7 +612,7 @@ int SigMatchSignaturesRunPostMatch(ThreadVars *tv, for ( ; sm != NULL; sm = sm->next) { KEYWORD_PROFILING_START; - (void)sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm); + (void)sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm->ctx); KEYWORD_PROFILING_END(det_ctx, sm->type, 1); } } @@ -1647,7 +1647,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SCLogDebug("running match functions, sm %p", sm); for ( ; sm != NULL; sm = sm->next) { KEYWORD_PROFILING_START; - if (sigmatch_table[sm->type].Match(th_v, det_ctx, p, s, sm) <= 0) { + if (sigmatch_table[sm->type].Match(th_v, det_ctx, p, s, sm->ctx) <= 0) { KEYWORD_PROFILING_END(det_ctx, sm->type, 0); goto next; } diff --git a/src/detect.h b/src/detect.h index b03a4929493c..65a10ee0ec82 100644 --- a/src/detect.h +++ b/src/detect.h @@ -364,15 +364,23 @@ typedef struct SignatureHeader_ { struct Signature_ *full_sig; } SignatureHeader; +/** \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_ { uint8_t type; /**< match type */ uint16_t idx; /**< position in the signature */ - void *ctx; /**< plugin specific data */ + SigMatchCtx *ctx; /**< plugin specific data */ struct SigMatch_ *next; struct SigMatch_ *prev; } SigMatch; + /** \brief Signature container */ typedef struct Signature_ { union { @@ -881,7 +889,7 @@ typedef struct DetectionEngineThreadCtx_ { */ typedef struct SigTableElmt_ { /** Packet match function pointer */ - int (*Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); + int (*Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); /** AppLayer match function pointer */ int (*AppLayerMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, Signature *, SigMatch *); From 1874784c1075ce6bfcb9ecd235396dd8f874b91f Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Tue, 14 Oct 2014 17:24:14 -0400 Subject: [PATCH 0177/2553] Create optimized sig_arrays from sig_lists Create a copy of the SigMatch data in the sig_lists linked-lists and store it in an array for faster access and not next and previous pointers. The array is then used when calling the Match() functions. Gives a 7.7% speed up on one test. --- src/detect-engine-iponly.c | 23 ++++++---- src/detect.c | 94 ++++++++++++++++++++++++++++++-------- src/detect.h | 10 ++++ 3 files changed, 99 insertions(+), 28 deletions(-) diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index fd8dedaec9d2..d279295d485a 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -1062,16 +1062,21 @@ void IPOnlyMatchPacket(ThreadVars *tv, SCLogDebug("Signum %"PRIu16" match (sid: %"PRIu16", msg: %s)", u * 8 + i, s->id, s->msg); - if (s->sm_lists[DETECT_SM_LIST_POSTMATCH] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_POSTMATCH] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_POSTMATCH); - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_POSTMATCH]; - - SCLogDebug("running match functions, sm %p", sm); - - for ( ; sm != NULL; sm = sm->next) { - KEYWORD_PROFILING_START; - (void)sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm->ctx); - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_POSTMATCH]; + + SCLogDebug("running match functions, sm %p", smd); + + if (smd != NULL) { + while (1) { + KEYWORD_PROFILING_START; + (void)sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) + break; + smd++; + } } } if (!(s->flags & SIG_FLAG_NOALERT)) { diff --git a/src/detect.c b/src/detect.c index bbaa0bb04f63..3eea3268bad4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -604,16 +604,21 @@ int SigMatchSignaturesRunPostMatch(ThreadVars *tv, Signature *s) { /* run the packet match functions */ - if (s->sm_lists[DETECT_SM_LIST_POSTMATCH] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_POSTMATCH] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_POSTMATCH); - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_POSTMATCH]; - SCLogDebug("running match functions, sm %p", sm); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_POSTMATCH]; + SCLogDebug("running match functions, sm %p", smd); - for ( ; sm != NULL; sm = sm->next) { - KEYWORD_PROFILING_START; - (void)sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm->ctx); - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + if (smd != NULL) { + while (1) { + KEYWORD_PROFILING_START; + (void)sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) + break; + smd++; + } } } @@ -1194,7 +1199,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh StreamMsg *smsg = NULL; Signature *s = NULL; Signature *next_s = NULL; - SigMatch *sm = NULL; uint16_t alversion = 0; int reset_de_state = 0; int state_alert = 0; @@ -1563,7 +1567,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* Check the payload keywords. If we are a MPM sig and we've made * to here, we've had at least one of the patterns match */ - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_PMATCH] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_PMATCH); /* if we have stream msgs, inspect against those first, * but not for a "dsize" signature */ @@ -1640,18 +1644,23 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } /* run the packet match functions */ - if (s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_MATCH] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH); - sm = s->sm_lists[DETECT_SM_LIST_MATCH]; - - SCLogDebug("running match functions, sm %p", sm); - for ( ; sm != NULL; sm = sm->next) { - KEYWORD_PROFILING_START; - if (sigmatch_table[sm->type].Match(th_v, det_ctx, p, s, sm->ctx) <= 0) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); - goto next; + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH]; + + SCLogDebug("running match functions, sm %p", smd); + if (smd != NULL) { + while (1) { + KEYWORD_PROFILING_START; + if (sigmatch_table[smd->type].Match(th_v, det_ctx, p, s, smd->ctx) <= 0) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); + goto next; + } + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) + break; + smd++; } - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); } } @@ -4475,6 +4484,47 @@ int SigAddressPrepareStage5(DetectEngineCtx *de_ctx) return 0; } +static int SigMatchListLen(SigMatch *sm) +{ + int len = 0; + for (; sm != NULL; sm = sm->next) + len++; + + return len; +} + +static int SigMatchPrepare(DetectEngineCtx *de_ctx) +{ + SCEnter(); + + Signature *s = de_ctx->sig_list; + for (; s != NULL; s = s->next) { + int type; + for (type = 0; type < DETECT_SM_LIST_MAX; type++) { + SigMatch *sm = s->sm_lists[type]; + int len = SigMatchListLen(sm); + if (len == 0) + s->sm_arrays[type] = NULL; + else { + SigMatchData *smd = (SigMatchData*)SCMalloc(len * sizeof(SigMatchData)); + if (smd == NULL) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + exit(EXIT_FAILURE); + } + /* Copy sm type and Context into array */ + s->sm_arrays[type] = smd; + for (; sm != NULL; sm = sm->next, smd++) { + smd->type = sm->type; + smd->ctx = sm->ctx; + smd->is_last = (sm->next == NULL); + } + } + } + } + + SCReturnInt(0); +} + /** * \brief Convert the signature list into the runtime match structure. * @@ -4743,6 +4793,12 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) // DetectAddressPrintMemory(); // DetectSigGroupPrintMemory(); // DetectPortPrintMemory(); + + if (SigMatchPrepare(de_ctx) != 0) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + exit(EXIT_FAILURE); + } + #ifdef PROFILING SCProfilingRuleInitCounters(de_ctx); #endif diff --git a/src/detect.h b/src/detect.h index 65a10ee0ec82..786297fdab26 100644 --- a/src/detect.h +++ b/src/detect.h @@ -380,6 +380,13 @@ typedef struct SigMatch_ { struct SigMatch_ *prev; } SigMatch; +/** \brief Data needed for Match() */ +typedef struct SigMatchData_ { + uint8_t type; /**< match type */ + uint8_t is_last; /**< Last element of the list */ + SigMatchCtx *ctx; /**< plugin specific data */ +} SigMatchData; + /** \brief Signature container */ typedef struct Signature_ { @@ -446,6 +453,9 @@ typedef struct Signature_ { int prio; + /* Hold copies of the sm lists for Match() */ + SigMatchData *sm_arrays[DETECT_SM_LIST_MAX]; + /* holds all sm lists */ struct SigMatch_ *sm_lists[DETECT_SM_LIST_MAX]; /* holds all sm lists' tails */ From 6717c356e3d23dccbd837c85e37e51566e7a4f54 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 8 Dec 2014 12:11:15 +0100 Subject: [PATCH 0178/2553] Clean up sm_array memory at SigFree --- src/detect-parse.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/detect-parse.c b/src/detect-parse.c index 92501e016ea3..a6e54937bfa9 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -913,6 +913,17 @@ static void SigRefFree (Signature *s) SCReturn; } +static void SigMatchFreeArrays(Signature *s) +{ + if (s != NULL) { + int type; + for (type = 0; type < DETECT_SM_LIST_MAX; type++) { + if (s->sm_arrays[type] != NULL) + SCFree(s->sm_arrays[type]); + } + } +} + void SigFree(Signature *s) { if (s == NULL) @@ -933,6 +944,7 @@ void SigFree(Signature *s) sm = nsm; } } + SigMatchFreeArrays(s); DetectAddressHeadCleanup(&s->src); DetectAddressHeadCleanup(&s->dst); From d01d3324fc2fbf3d3d7050cb12bf8e888dc770eb Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 17 Oct 2014 17:25:30 -0400 Subject: [PATCH 0179/2553] Increase max pattern ID allowed in MPM AC-tile to 28-bits --- src/util-mpm-ac-tile.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index a3e0c7c5b3c4..b1f8cd9257cd 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -1081,8 +1081,8 @@ static inline void SCACTileInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { if (ctx->pattern_list[ctx->output_table[state].patterns[k]].cs != NULL) { /* TODO - Find better way to store this. */ - ctx->output_table[state].patterns[k] &= 0x0000FFFF; - ctx->output_table[state].patterns[k] |= 1 << 16; + ctx->output_table[state].patterns[k] &= 0x0FFFFFFF; + ctx->output_table[state].patterns[k] |= 1 << 31; } } } @@ -1478,7 +1478,7 @@ int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, uint32_t k; for (k = 0; k < no_of_entries; k++) { - MpmPatternIndex pindex = patterns[k] & 0x0000FFFF; + MpmPatternIndex pindex = patterns[k] & 0x0FFFFFFF; if (mpm_bitarray[pindex / 8] & (1 << (pindex % 8))) { /* Pattern already seen by this MPM. */ /* NOTE: This is faster then rechecking if it is a case-sensitive match @@ -1492,7 +1492,7 @@ int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, } uint32_t pid = pattern_list[pindex].pid; /* Double check case-sensitve match now. */ - if (patterns[k] & 0xFFFF0000) { + if (patterns[k] >> 31) { uint16_t patlen = pattern_list[pindex].patlen; if (SCMemcmpNZ(pattern_list[pindex].cs, buf_offset - patlen, patlen) != 0) { /* Case-sensitive match failed. */ From 736ac6a45980c225b69117bd9db7ecfca6536ef9 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Sun, 2 Nov 2014 14:12:16 -0500 Subject: [PATCH 0180/2553] Use SigIntId as the type for storing signature IDs (Internal) Previously using uint32_t, but SigIntId is currently uint16_t, so arrays will take less memory. --- src/detect-engine-siggroup.c | 4 ++-- src/detect.c | 26 +++++++++++++------------- src/detect.h | 2 +- src/util-mpm-ac-bs.c | 22 +++++++++++----------- src/util-mpm-ac-bs.h | 4 ++-- src/util-mpm-ac-gfbs.c | 16 ++++++++-------- src/util-mpm-ac-gfbs.h | 4 ++-- src/util-mpm-ac-tile.c | 14 +++++++------- src/util-mpm-ac-tile.h | 4 ++-- src/util-mpm-ac.c | 14 +++++++------- src/util-mpm-ac.h | 4 ++-- src/util-mpm-b2g.c | 22 ++++++++++++---------- src/util-mpm-b2g.h | 2 +- src/util-mpm-b3g.c | 18 +++++++++--------- src/util-mpm-b3g.h | 2 +- src/util-mpm-wumanber.c | 14 +++++++------- src/util-mpm-wumanber.h | 2 +- src/util-mpm.c | 14 +++++++------- src/util-mpm.h | 20 ++++++++++---------- 19 files changed, 105 insertions(+), 103 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index f5397baa26f9..bd867dc0b702 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -1730,9 +1730,9 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return 0; } - sgh->non_mpm_id_array = SCMalloc(non_mpm * sizeof(uint32_t)); + sgh->non_mpm_id_array = SCMalloc(non_mpm * sizeof(SigIntId)); BUG_ON(sgh->non_mpm_id_array == NULL); - memset(sgh->non_mpm_id_array, 0, non_mpm * sizeof(uint32_t)); + memset(sgh->non_mpm_id_array, 0, non_mpm * sizeof(SigIntId)); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; diff --git a/src/detect.c b/src/detect.c index 3eea3268bad4..e3f458033591 100644 --- a/src/detect.c +++ b/src/detect.c @@ -781,12 +781,12 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, SigGroupHead *sgh) { - uint32_t mpm = -1; - uint32_t nonmpm = -1; + SigIntId mpm = (SigIntId)-1; + SigIntId nonmpm = (SigIntId)-1; det_ctx->match_array_cnt = 0; - uint32_t *mpm_ptr = det_ctx->pmq.rule_id_array; - uint32_t *nonmpm_ptr = sgh->non_mpm_id_array; + SigIntId *mpm_ptr = det_ctx->pmq.rule_id_array; + SigIntId *nonmpm_ptr = sgh->non_mpm_id_array; uint32_t m_cnt = det_ctx->pmq.rule_id_array_cnt; uint32_t n_cnt = sgh->non_mpm_id_cnt; SCLogDebug("PMQ rule id array count %d", det_ctx->pmq.rule_id_array_cnt); @@ -797,21 +797,21 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, mpm = *(mpm_ptr++); m_cnt--; } else - mpm = -1; + mpm = (SigIntId)-1; if (likely(n_cnt)) { nonmpm = *(nonmpm_ptr++); n_cnt--; } else - nonmpm = -1; + nonmpm = (SigIntId)-1; - uint32_t previous_id = (uint32_t)-1; + SigIntId previous_id = (SigIntId)-1; Signature **sig_array = de_ctx->sig_array; Signature **match_array = det_ctx->match_array; Signature *s; while (1) { - uint32_t id = MIN(mpm, nonmpm); + SigIntId id = MIN(mpm, nonmpm); - if (unlikely(id == (uint32_t)-1)) + if (unlikely(id == (SigIntId)-1)) break; else { s = sig_array[id]; @@ -842,10 +842,10 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, BUG_ON((det_ctx->pmq.rule_id_array_cnt + sgh->non_mpm_id_cnt) < det_ctx->match_array_cnt); } -static int DoSort(const void *a, const void *b) +static int DoSortSigIntId(const void *a, const void *b) { - uint32_t x = *(uint32_t *)a; - uint32_t y = *(uint32_t *)b; + SigIntId x = *(SigIntId *)a; + SigIntId y = *(SigIntId *)b; return x - y; } @@ -1100,7 +1100,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ if (det_ctx->pmq.rule_id_array_cnt) { qsort(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt, - sizeof(uint32_t), DoSort); + sizeof(SigIntId), DoSortSigIntId); } } diff --git a/src/detect.h b/src/detect.h index 786297fdab26..3a31af255d1c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -993,7 +993,7 @@ typedef struct SigGroupHead_ { * signatures to be inspected in a cache efficient way. */ SignatureHeader *head_array; - uint32_t *non_mpm_id_array; + SigIntId *non_mpm_id_array; uint32_t non_mpm_id_cnt; // size is cnt * sizeof(uint32_t) /* pattern matcher instances */ diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index c706c0982192..d6c4e78502cd 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -65,9 +65,9 @@ void SCACBSInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void SCACBSDestroyCtx(MpmCtx *); void SCACBSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACBSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACBSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACBSPreparePatterns(MpmCtx *mpm_ctx); uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); @@ -164,8 +164,8 @@ static inline uint32_t SCACBSInitHashRaw(uint8_t *pat, uint16_t patlen) * \retval hash A 32 bit unsigned hash. */ static inline SCACBSPattern *SCACBSInitHashLookup(SCACBSCtx *ctx, uint8_t *pat, - uint16_t patlen, char flags, - uint32_t pid) + uint16_t patlen, char flags, + uint32_t pid) { uint32_t hash = SCACBSInitHashRaw(pat, patlen); @@ -290,8 +290,8 @@ static inline int SCACBSInitHashAdd(SCACBSCtx *ctx, SCACBSPattern *p) * \retval -1 On failure. */ static int SCACBSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; @@ -372,7 +372,7 @@ static int SCACBSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, ctx->max_pat_id = pid; p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); BUG_ON(p->sids == NULL); p->sids[0] = sid; } else { @@ -387,7 +387,7 @@ static int SCACBSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, } } if (!found) { - uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); BUG_ON(sids == NULL); p->sids = sids; p->sids[p->sids_size] = sid; @@ -503,7 +503,7 @@ static void SCACBSSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACBSEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid, - MpmCtx *mpm_ctx) + MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int32_t state = 0; @@ -1635,7 +1635,7 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, */ int SCACBSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return SCACBSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); @@ -1660,7 +1660,7 @@ int SCACBSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, */ int SCACBSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { return SCACBSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } diff --git a/src/util-mpm-ac-bs.h b/src/util-mpm-ac-bs.h index 935bc77c2792..a66757e72a3d 100644 --- a/src/util-mpm-ac-bs.h +++ b/src/util-mpm-ac-bs.h @@ -41,7 +41,7 @@ typedef struct SCACBSPattern_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; struct SCACBSPattern_ *next; } SCACBSPattern; @@ -52,7 +52,7 @@ typedef struct SCACBSPatternList_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; } SCACBSPatternList; typedef struct SCACBSOutputTable_ { diff --git a/src/util-mpm-ac-gfbs.c b/src/util-mpm-ac-gfbs.c index 523aa0ff95ac..e0ace7f3e7f2 100644 --- a/src/util-mpm-ac-gfbs.c +++ b/src/util-mpm-ac-gfbs.c @@ -59,9 +59,9 @@ void SCACGfbsInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void SCACGfbsDestroyCtx(MpmCtx *); void SCACGfbsDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACGfbsAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACGfbsAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACGfbsPreparePatterns(MpmCtx *mpm_ctx); uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); @@ -284,7 +284,7 @@ static inline int SCACGfbsInitHashAdd(SCACGfbsCtx *ctx, SCACGfbsPattern *p) */ static int SCACGfbsAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; @@ -365,7 +365,7 @@ static int SCACGfbsAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, ctx->max_pat_id = pid; p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); BUG_ON(p->sids == NULL); p->sids[0] = sid; } else { @@ -380,7 +380,7 @@ static int SCACGfbsAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, } } if (!found) { - uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); BUG_ON(sids == NULL); p->sids = sids; p->sids[p->sids_size] = sid; @@ -496,7 +496,7 @@ static void SCACGfbsSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACGfbsEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid, - MpmCtx *mpm_ctx) + MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; int32_t state = 0; @@ -1593,7 +1593,7 @@ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, */ int SCACGfbsAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return SCACGfbsAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); @@ -1618,7 +1618,7 @@ int SCACGfbsAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, */ int SCACGfbsAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { return SCACGfbsAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } diff --git a/src/util-mpm-ac-gfbs.h b/src/util-mpm-ac-gfbs.h index 5f1fc7bbad04..4003a5b560a5 100644 --- a/src/util-mpm-ac-gfbs.h +++ b/src/util-mpm-ac-gfbs.h @@ -41,7 +41,7 @@ typedef struct SCACGfbsPattern_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; struct SCACGfbsPattern_ *next; } SCACGfbsPattern; @@ -52,7 +52,7 @@ typedef struct SCACGfbsPatternList_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; } SCACGfbsPatternList; typedef struct SCACGfbsOutputTable_ { diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index b1f8cd9257cd..f3a52d6e56cd 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -94,9 +94,9 @@ void SCACTileInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void SCACTileDestroyCtx(MpmCtx *); void SCACTileDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACTileAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACTileAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACTilePreparePatterns(MpmCtx *mpm_ctx); uint32_t SCACTileSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, @@ -512,7 +512,7 @@ static int SCACTileAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, } p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); BUG_ON(p->sids == NULL); p->sids[0] = sid; //SCLogInfo("MPM added %u:%u", pid, sid); @@ -528,7 +528,7 @@ static int SCACTileAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, } } if (!found) { - uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); BUG_ON(sids == NULL); p->sids = sids; p->sids[p->sids_size] = sid; @@ -1473,7 +1473,7 @@ int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, SCACTilePatternList *pattern_list = ctx->pattern_list; uint8_t *buf_offset = buf + i + 1; // Lift out of loop uint32_t no_of_entries = ctx->output_table[state].no_of_entries; - uint32_t *patterns = ctx->output_table[state].patterns; + MpmPatternIndex *patterns = ctx->output_table[state].patterns; uint8_t *pmq_bitarray = pmq->pattern_id_bitarray; uint32_t k; @@ -1701,7 +1701,7 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct */ int SCACTileAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return SCACTileAddPattern(mpm_ctx, pat, patlen, offset, depth, @@ -1727,7 +1727,7 @@ int SCACTileAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, */ int SCACTileAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { return SCACTileAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); diff --git a/src/util-mpm-ac-tile.h b/src/util-mpm-ac-tile.h index 33a4ceac1714..63d5bc95eff9 100644 --- a/src/util-mpm-ac-tile.h +++ b/src/util-mpm-ac-tile.h @@ -42,7 +42,7 @@ typedef struct SCACTilePattern_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; struct SCACTilePattern_ *next; } SCACTilePattern; @@ -56,7 +56,7 @@ typedef struct SCACTilePatternList_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; } SCACTilePatternList; typedef struct SCACTileOutputTable_ { diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 01263d177f37..6cf05c1ffcdd 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -74,9 +74,9 @@ void SCACInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void SCACDestroyCtx(MpmCtx *); void SCACDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACPreparePatterns(MpmCtx *mpm_ctx); uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); @@ -278,7 +278,7 @@ static inline int SCACInitHashAdd(SCACCtx *ctx, SCACPattern *p) */ static int SCACAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; @@ -359,7 +359,7 @@ static int SCACAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, ctx->max_pat_id = pid; p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); BUG_ON(p->sids == NULL); p->sids[0] = sid; //SCLogInfo("MPM added %u:%u", pid, sid); @@ -375,7 +375,7 @@ static int SCACAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, } } if (!found) { - uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); BUG_ON(sids == NULL); p->sids = sids; p->sids[p->sids_size] = sid; @@ -1421,7 +1421,7 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, */ int SCACAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return SCACAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); @@ -1446,7 +1446,7 @@ int SCACAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, */ int SCACAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { return SCACAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } diff --git a/src/util-mpm-ac.h b/src/util-mpm-ac.h index 7519fffd620f..a837f5f01541 100644 --- a/src/util-mpm-ac.h +++ b/src/util-mpm-ac.h @@ -54,7 +54,7 @@ typedef struct SCACPattern_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; struct SCACPattern_ *next; } SCACPattern; @@ -65,7 +65,7 @@ typedef struct SCACPatternList_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; } SCACPatternList; typedef struct SCACOutputTable_ { diff --git a/src/util-mpm-b2g.c b/src/util-mpm-b2g.c index b4e2fcb77b26..f71728391015 100644 --- a/src/util-mpm-b2g.c +++ b/src/util-mpm-b2g.c @@ -65,8 +65,10 @@ void B2gInitCtx (MpmCtx *); void B2gThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void B2gDestroyCtx(MpmCtx *); void B2gThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); -int B2gAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); +int B2gAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags); +int B2gAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags); int B2gPreparePatterns(MpmCtx *mpm_ctx); uint32_t B2gSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t B2gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); @@ -285,7 +287,7 @@ void B2gFreePattern(MpmCtx *mpm_ctx, B2gPattern *p) if (p && p->sids) { SCFree(p->sids); mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->sids_size * sizeof(uint32_t); + mpm_ctx->memory_size -= p->sids_size * sizeof(SigIntId); } if (p) { @@ -306,7 +308,7 @@ void B2gFreePattern(MpmCtx *mpm_ctx, B2gPattern *p) * * \initonly */ -static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) +static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) { B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; @@ -364,11 +366,11 @@ static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ } p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); BUG_ON(p->sids == NULL); p->sids[0] = sid; mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(uint32_t); + mpm_ctx->memory_size += sizeof(SigIntId); //printf("B2gAddPattern: ci \""); prt(p->ci,p->len); //printf("\" cs \""); prt(p->cs,p->len); @@ -400,12 +402,12 @@ static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ } } if (!found) { - uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); BUG_ON(sids == NULL); p->sids = sids; p->sids[p->sids_size] = sid; p->sids_size++; - mpm_ctx->memory_size += sizeof(uint32_t); + mpm_ctx->memory_size += sizeof(SigIntId); } } @@ -417,14 +419,14 @@ static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ } int B2gAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) + uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return B2gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } int B2gAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) + uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) { return B2gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } diff --git a/src/util-mpm-b2g.h b/src/util-mpm-b2g.h index 8c002b63451e..b3b59b092124 100644 --- a/src/util-mpm-b2g.h +++ b/src/util-mpm-b2g.h @@ -62,7 +62,7 @@ typedef struct B2gPattern_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; struct B2gPattern_ *next; } B2gPattern; diff --git a/src/util-mpm-b3g.c b/src/util-mpm-b3g.c index 03b7fd6927f7..bc74bc205338 100644 --- a/src/util-mpm-b3g.c +++ b/src/util-mpm-b3g.c @@ -60,8 +60,8 @@ void B3gInitCtx (MpmCtx *); void B3gThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void B3gDestroyCtx(MpmCtx *); void B3gThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); -int B3gAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B3gAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); +int B3gAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); +int B3gAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int B3gPreparePatterns(MpmCtx *); uint32_t B3gSearchWrap(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t B3gSearch1(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); @@ -248,7 +248,7 @@ void B3gFreePattern(MpmCtx *mpm_ctx, B3gPattern *p) if (p && p->sids) { SCFree(p->sids); mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->sids_size * sizeof(uint32_t); + mpm_ctx->memory_size -= p->sids_size * sizeof(SigIntId); } if (p) { @@ -317,11 +317,11 @@ static int B3gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ //printf("\" prefix_ci %" PRIu32 ", prefix_cs %" PRIu32 "\n", p->prefix_ci, p->prefix_cs); p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); BUG_ON(p->sids == NULL); p->sids[0] = sid; mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(uint32_t); + mpm_ctx->memory_size += sizeof(SigIntId); /* put in the pattern hash */ B3gInitHashAdd(ctx, p); @@ -349,12 +349,12 @@ static int B3gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ } } if (!found) { - uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); BUG_ON(sids == NULL); p->sids = sids; p->sids[p->sids_size] = sid; p->sids_size++; - mpm_ctx->memory_size += sizeof(uint32_t); + mpm_ctx->memory_size += sizeof(SigIntId); } } @@ -366,14 +366,14 @@ static int B3gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ } int B3gAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) + uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return B3gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } int B3gAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) + uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) { return B3gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } diff --git a/src/util-mpm-b3g.h b/src/util-mpm-b3g.h index 2d75caa335d1..d35aa0334d02 100644 --- a/src/util-mpm-b3g.h +++ b/src/util-mpm-b3g.h @@ -63,7 +63,7 @@ typedef struct B3gPattern_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; struct B3gPattern_ *next; diff --git a/src/util-mpm-wumanber.c b/src/util-mpm-wumanber.c index 4966821f6e5a..dc78cde260ad 100644 --- a/src/util-mpm-wumanber.c +++ b/src/util-mpm-wumanber.c @@ -63,8 +63,8 @@ void WmInitCtx (MpmCtx *mpm_ctx); void WmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t); void WmDestroyCtx(MpmCtx *mpm_ctx); void WmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx); -int WmAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int WmAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); +int WmAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); +int WmAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int WmPreparePatterns(MpmCtx *mpm_ctx); uint32_t WmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); @@ -377,11 +377,11 @@ static int WmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(uint32_t)); + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); BUG_ON(p->sids == NULL); p->sids[0] = sid; mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(uint32_t); + mpm_ctx->memory_size += sizeof(SigIntId); } else { /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ @@ -395,7 +395,7 @@ static int WmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t } } if (!found) { - uint32_t *sids = SCRealloc(p->sids, (sizeof(uint32_t) * (p->sids_size + 1))); + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); BUG_ON(sids == NULL); p->sids = sids; p->sids[p->sids_size] = sid; @@ -412,14 +412,14 @@ static int WmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t } int WmAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) + uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return WmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } int WmAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) + uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) { return WmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } diff --git a/src/util-mpm-wumanber.h b/src/util-mpm-wumanber.h index a8b0bdef5d6d..ef6998145d1b 100644 --- a/src/util-mpm-wumanber.h +++ b/src/util-mpm-wumanber.h @@ -41,7 +41,7 @@ typedef struct WmPattern_ { /* sid(s) for this pattern */ uint32_t sids_size; - uint32_t *sids; + SigIntId *sids; } WmPattern; diff --git a/src/util-mpm.c b/src/util-mpm.c index 157eb58700b3..ac185e301fa3 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -453,8 +453,8 @@ int PmqSetup(PatternMatcherQueue *pmq, uint32_t patmaxid) pmq->rule_id_array_size = 128; /* Initial size, TODO: Make configure option. */ pmq->rule_id_array_cnt = 0; - uint32_t bytes = pmq->rule_id_array_size * sizeof(uint32_t); - pmq->rule_id_array = SCMalloc(bytes); + size_t bytes = pmq->rule_id_array_size * sizeof(SigIntId); + pmq->rule_id_array = (SigIntId*)SCMalloc(bytes); if (pmq->rule_id_array == NULL) { pmq->rule_id_array_size = 0; SCReturnInt(-1); @@ -481,8 +481,8 @@ MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size) * larger than the old size. */ new_size = new_size * 2; - uint32_t *new_array = (uint32_t*)SCRealloc(pmq->rule_id_array, - new_size * sizeof(uint32_t)); + SigIntId *new_array = (SigIntId*)SCRealloc(pmq->rule_id_array, + new_size * sizeof(SigIntId)); if (unlikely(new_array == NULL)) { /* Try again just big enough. */ new_size = new_size / 2; @@ -551,7 +551,7 @@ MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size) */ int MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t patid, - uint8_t *bitarray, uint32_t *sids, uint32_t sids_size) + uint8_t *bitarray, SigIntId *sids, uint32_t sids_size) { SCEnter(); @@ -737,7 +737,7 @@ uint32_t MpmGetBloomSize(const char *conf_val) int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, - uint32_t pid, uint32_t sid, uint8_t flags) + uint32_t pid, SigIntId sid, uint8_t flags) { return mpm_table[mpm_ctx->mpm_type].AddPattern(mpm_ctx, pat, patlen, offset, depth, @@ -746,7 +746,7 @@ int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, - uint32_t pid, uint32_t sid, uint8_t flags) + uint32_t pid, SigIntId sid, uint8_t flags) { return mpm_table[mpm_ctx->mpm_type].AddPatternNocase(mpm_ctx, pat, patlen, offset, depth, diff --git a/src/util-mpm.h b/src/util-mpm.h index ca1fb4348a20..da650884b88f 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -112,7 +112,7 @@ typedef struct PatternMatcherQueue_ { /* used for storing rule id's */ /* Array of rule IDs found. */ - uint32_t *rule_id_array; + SigIntId *rule_id_array; /* Number of rule IDs in the array. */ uint32_t rule_id_array_cnt; /* The number of slots allocated for storing rule IDs */ @@ -189,8 +189,8 @@ typedef struct MpmTableElmt_ { * \param sid signature _internal_ id * \param flags pattern flags */ - int (*AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); - int (*AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); + int (*AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); + int (*AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int (*Prepare)(struct MpmCtx_ *); uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); void (*Cleanup)(struct MpmThreadCtx_ *); @@ -255,8 +255,8 @@ void PmqFree(PatternMatcherQueue *); void MpmTableSetup(void); void MpmRegisterTests(void); -int MpmVerifyMatch(MpmThreadCtx *, PatternMatcherQueue *, uint32_t, - uint8_t *bitarray, uint32_t *sids, uint32_t sid_size); +int MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t patid, + uint8_t *bitarray, SigIntId *sids, uint32_t sids_size); void MpmInitCtx(MpmCtx *mpm_ctx, uint16_t matcher); void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t, uint32_t); uint32_t MpmGetHashSize(const char *); @@ -264,10 +264,10 @@ uint32_t MpmGetBloomSize(const char *); int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, - uint32_t pid, uint32_t sid, uint8_t flags); + uint32_t pid, SigIntId sid, uint8_t flags); int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, - uint32_t pid, uint32_t sid, uint8_t flags); + uint32_t pid, SigIntId sid, uint8_t flags); /* Resize Signature ID array. Only called from MpmAddSids(). */ int MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size); @@ -283,7 +283,7 @@ int MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size); * */ static inline void -MpmAddSids(PatternMatcherQueue *pmq, uint32_t *sids, uint32_t sids_size) +MpmAddSids(PatternMatcherQueue *pmq, SigIntId *sids, uint32_t sids_size) { if (sids_size == 0) return; @@ -298,8 +298,8 @@ MpmAddSids(PatternMatcherQueue *pmq, uint32_t *sids, uint32_t sids_size) } SCLogDebug("Adding %u sids", sids_size); // Add SIDs for this pattern to the end of the array - uint32_t *ptr = pmq->rule_id_array + pmq->rule_id_array_cnt; - uint32_t *end = ptr + sids_size; + SigIntId *ptr = pmq->rule_id_array + pmq->rule_id_array_cnt; + SigIntId *end = ptr + sids_size; do { *ptr++ = *sids++; } while (ptr != end); From 86f4c6c47b73618ee1980e05113a3eac76300b3e Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Sun, 2 Nov 2014 18:49:54 -0500 Subject: [PATCH 0181/2553] Custom Quick Sort for Signature IDs Use an in place Quick Sort instead of qsort(), which does merge sort and calls memcpy(). Improves performance on my tests. --- src/detect.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/detect.c b/src/detect.c index e3f458033591..5c37099e051a 100644 --- a/src/detect.c +++ b/src/detect.c @@ -842,11 +842,29 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, BUG_ON((det_ctx->pmq.rule_id_array_cnt + sgh->non_mpm_id_cnt) < det_ctx->match_array_cnt); } -static int DoSortSigIntId(const void *a, const void *b) +/* Return true is the list is sorted smallest to largest */ +static void QuickSortSigIntId(SigIntId *sids, uint32_t n) { - SigIntId x = *(SigIntId *)a; - SigIntId y = *(SigIntId *)b; - return x - y; + if (n < 2) + return; + SigIntId p = sids[n / 2]; + SigIntId *l = sids; + SigIntId *r = sids + n - 1; + while (l <= r) { + if (*l < p) + l++; + else if (*r > p) + r--; + else { + SigIntId t = *l; + *l = *r; + *r = t; + l++; + r--; + } + } + QuickSortSigIntId(sids, r - sids + 1); + QuickSortSigIntId(l, sids + n - l); } #define SMS_USE_FLOW_SGH 0x01 @@ -1098,9 +1116,8 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, /* Sort the rule list to lets look at pmq. * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ - if (det_ctx->pmq.rule_id_array_cnt) { - qsort(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt, - sizeof(SigIntId), DoSortSigIntId); + if (det_ctx->pmq.rule_id_array_cnt > 1) { + QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt); } } From 403b5a46457f5f5e92ab5635ac245ff816c9c72e Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Sun, 2 Nov 2014 22:27:07 -0500 Subject: [PATCH 0182/2553] Further optimize merging mpm and non-mpm rule ID lists. When reaching the end of either list, merging is no longer required, simply walk down the other list. If the non-MPM list can't have duplicates, it would be worth removing the duplicate check for the non-MPM list when it is the only non-empty list remaining. --- src/detect.c | 104 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/src/detect.c b/src/detect.c index 5c37099e051a..48747df31403 100644 --- a/src/detect.c +++ b/src/detect.c @@ -781,9 +781,7 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, SigGroupHead *sgh) { - SigIntId mpm = (SigIntId)-1; - SigIntId nonmpm = (SigIntId)-1; - + SigIntId mpm, nonmpm; det_ctx->match_array_cnt = 0; SigIntId *mpm_ptr = det_ctx->pmq.rule_id_array; SigIntId *nonmpm_ptr = sgh->non_mpm_id_array; @@ -791,45 +789,74 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, uint32_t n_cnt = sgh->non_mpm_id_cnt; SCLogDebug("PMQ rule id array count %d", det_ctx->pmq.rule_id_array_cnt); SCLogDebug("SGH non-MPM id count %d", sgh->non_mpm_id_cnt); + SigIntId *final_ptr; + uint32_t final_cnt; + SigIntId id; + SigIntId previous_id = (SigIntId)-1; + Signature **sig_array = de_ctx->sig_array; + Signature **match_array = det_ctx->match_array; + Signature *s; /* Load first values. */ if (likely(m_cnt)) { - mpm = *(mpm_ptr++); - m_cnt--; - } else - mpm = (SigIntId)-1; + mpm = *mpm_ptr; + } else { + /* mpm list is empty */ + final_ptr = nonmpm_ptr; + final_cnt = n_cnt; + goto final; + } if (likely(n_cnt)) { - nonmpm = *(nonmpm_ptr++); - n_cnt--; - } else - nonmpm = (SigIntId)-1; - - SigIntId previous_id = (SigIntId)-1; - Signature **sig_array = de_ctx->sig_array; - Signature **match_array = det_ctx->match_array; - Signature *s; - while (1) { - SigIntId id = MIN(mpm, nonmpm); - - if (unlikely(id == (SigIntId)-1)) - break; - else { - s = sig_array[id]; - - if (id == mpm) { - if (likely(m_cnt)) { - mpm = *(mpm_ptr++); - m_cnt--; - } else - mpm = -1; // TODO - at this point, just copy of remaining array onto the end of the list. - } else { // (id == nonmpm) - if (likely(n_cnt)) { - nonmpm = *(nonmpm_ptr++); - n_cnt--; - } else - nonmpm = -1; - } - } + nonmpm = *nonmpm_ptr; + } else { + /* non-mpm list is empty. */ + final_ptr = mpm_ptr; + final_cnt = m_cnt; + goto final; + } + while (1) { + if (mpm <= nonmpm) { + /* Take from mpm list */ + id = mpm; + + s = sig_array[id]; + /* As the mpm list can contain duplicates, check for that here. */ + if (likely(id != previous_id)) { + *match_array++ = s; + previous_id = id; + } + if (unlikely(--m_cnt == 0)) { + /* mpm list is now empty */ + final_ptr = nonmpm_ptr; + final_cnt = n_cnt; + goto final; + } + mpm_ptr++; + mpm = *mpm_ptr; + } else { + id = nonmpm; + + s = sig_array[id]; + /* As the mpm list can contain duplicates, check for that here. */ + if (likely(id != previous_id)) { + *match_array++ = s; + previous_id = id; + } + if (unlikely(--n_cnt == 0)) { + final_ptr = mpm_ptr; + final_cnt = m_cnt; + goto final; + } + nonmpm_ptr++; + nonmpm = *nonmpm_ptr; + } + } + + final: /* Only one list remaining. Just walk that list. */ + + while (final_cnt-- > 0) { + id = *final_ptr++; + s = sig_array[id]; /* As the mpm list can contain duplicates, check for that here. */ if (likely(id != previous_id)) { @@ -837,6 +864,7 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, previous_id = id; } } + det_ctx->match_array_cnt = match_array - det_ctx->match_array; BUG_ON((det_ctx->pmq.rule_id_array_cnt + sgh->non_mpm_id_cnt) < det_ctx->match_array_cnt); From 4bd280f1963000497cf76c27212cefea791305f5 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Mon, 3 Nov 2014 11:50:35 -0500 Subject: [PATCH 0183/2553] Indentation clean up --- src/detect.c | 65 ++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/detect.c b/src/detect.c index 48747df31403..28d4082501ee 100644 --- a/src/detect.c +++ b/src/detect.c @@ -779,7 +779,8 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) } static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, SigGroupHead *sgh) + DetectEngineThreadCtx *det_ctx, + SigGroupHead *sgh) { SigIntId mpm, nonmpm; det_ctx->match_array_cnt = 0; @@ -815,19 +816,19 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, goto final; } while (1) { - if (mpm <= nonmpm) { - /* Take from mpm list */ - id = mpm; - - s = sig_array[id]; - /* As the mpm list can contain duplicates, check for that here. */ - if (likely(id != previous_id)) { - *match_array++ = s; - previous_id = id; - } - if (unlikely(--m_cnt == 0)) { - /* mpm list is now empty */ - final_ptr = nonmpm_ptr; + if (mpm <= nonmpm) { + /* Take from mpm list */ + id = mpm; + + s = sig_array[id]; + /* As the mpm list can contain duplicates, check for that here. */ + if (likely(id != previous_id)) { + *match_array++ = s; + previous_id = id; + } + if (unlikely(--m_cnt == 0)) { + /* mpm list is now empty */ + final_ptr = nonmpm_ptr; final_cnt = n_cnt; goto final; } @@ -849,7 +850,7 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, } nonmpm_ptr++; nonmpm = *nonmpm_ptr; - } + } } final: /* Only one list remaining. Just walk that list. */ @@ -1462,8 +1463,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh uint32_t sflags, next_sflags = 0; if (match_cnt) { - next_s = *match_array++; - next_sflags = next_s->flags; + next_s = *match_array++; + next_sflags = next_s->flags; } while (match_cnt--) { @@ -1476,8 +1477,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh s = next_s; sflags = next_sflags; if (match_cnt) { - next_s = *match_array++; - next_sflags = next_s->flags; + next_s = *match_array++; + next_sflags = next_s->flags; } uint8_t s_proto_flags = s->proto.flags; @@ -1501,14 +1502,13 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh if (unlikely(sflags & SIG_FLAG_DSIZE)) { if (likely(p->payload_len < s->dsize_low || p->payload_len > s->dsize_high)) { SCLogDebug("kicked out as p->payload_len %u, dsize low %u, hi %u", - p->payload_len, s->dsize_low, s->dsize_high); + p->payload_len, s->dsize_low, s->dsize_high); goto next; } } /* check for a pattern match of the one pattern in this sig. */ - if (likely(sflags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_APPLAYER))) - { + if (likely(sflags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_APPLAYER))) { /* filter out sigs that want pattern matches, but * have no matches */ if (!(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { @@ -1545,7 +1545,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* no flowvars? skip this sig */ if (m == 0) { SCLogDebug("skipping sig as the flow has no flowvars and sig " - "has SIG_FLAG_REQUIRE_FLOWVAR flag set."); + "has SIG_FLAG_REQUIRE_FLOWVAR flag set."); goto next; } } @@ -1637,7 +1637,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* Tell the engine that this reassembled stream can drop the * rest of the pkts with no further inspection */ if (s->action & ACTION_DROP) - alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW; + alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW; alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH; break; @@ -1680,7 +1680,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { goto next; } - } else { if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) goto next; @@ -1710,13 +1709,13 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } SCLogDebug("s->sm_lists[DETECT_SM_LIST_AMATCH] %p, " - "s->sm_lists[DETECT_SM_LIST_UMATCH] %p, " - "s->sm_lists[DETECT_SM_LIST_DMATCH] %p, " - "s->sm_lists[DETECT_SM_LIST_HCDMATCH] %p", - s->sm_lists[DETECT_SM_LIST_AMATCH], - s->sm_lists[DETECT_SM_LIST_UMATCH], - s->sm_lists[DETECT_SM_LIST_DMATCH], - s->sm_lists[DETECT_SM_LIST_HCDMATCH]); + "s->sm_lists[DETECT_SM_LIST_UMATCH] %p, " + "s->sm_lists[DETECT_SM_LIST_DMATCH] %p, " + "s->sm_lists[DETECT_SM_LIST_HCDMATCH] %p", + s->sm_lists[DETECT_SM_LIST_AMATCH], + s->sm_lists[DETECT_SM_LIST_UMATCH], + s->sm_lists[DETECT_SM_LIST_DMATCH], + s->sm_lists[DETECT_SM_LIST_HCDMATCH]); /* consider stateful sig matches */ if (sflags & SIG_FLAG_STATE_MATCH) { @@ -1733,7 +1732,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh * can store the tx_id with the alert */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); state_alert = DeStateDetectStartDetection(th_v, de_ctx, det_ctx, s, - p, pflow, flags, alproto, alversion); + p, pflow, flags, alproto, alversion); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); if (state_alert == 0) goto next; From 65af1f1c5e99c4219a7bba410d433346da0028e3 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 10 Oct 2014 17:13:08 -0400 Subject: [PATCH 0184/2553] Remove sgh->mask_array Not needed by new MPM opt. --- src/detect-engine-siggroup.c | 33 ------ src/detect-simd.c | 210 ----------------------------------- 2 files changed, 243 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index bd867dc0b702..ff7fcb2d4a57 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -185,14 +185,6 @@ void SigGroupHeadFree(SigGroupHead *sgh) PatternMatchDestroyGroup(sgh); -#if defined(__SSE3__) || defined(__tile__) - if (sgh->mask_array != NULL) { - /* mask is aligned */ - SCFreeAligned(sgh->mask_array); - sgh->mask_array = NULL; - } -#endif - if (sgh->head_array != NULL) { SCFree(sgh->head_array); sgh->head_array = NULL; @@ -1760,28 +1752,6 @@ int SigGroupHeadBuildHeadArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return 0; BUG_ON(sgh->head_array != NULL); -#if defined(__SSE3__) || defined(__tile__) - BUG_ON(sgh->mask_array != NULL); - - /* mask array is 16 byte aligned for SIMD checking, also we always - * alloc a multiple of 32/64 bytes */ - int cnt = sgh->sig_cnt; -#if __WORDSIZE == 32 - if (cnt % 32 != 0) { - cnt += (32 - (cnt % 32)); - } -#elif __WORDSIZE == 64 - if (cnt % 64 != 0) { - cnt += (64 - (cnt % 64)); - } -#endif /* __WORDSIZE */ - - sgh->mask_array = (SignatureMask *)SCMallocAligned((cnt * sizeof(SignatureMask)), 16); - if (sgh->mask_array == NULL) - return -1; - - memset(sgh->mask_array, 0, (cnt * sizeof(SignatureMask))); -#endif sgh->head_array = SCMalloc(sgh->sig_cnt * sizeof(SignatureHeader)); if (sgh->head_array == NULL) @@ -1802,9 +1772,6 @@ int SigGroupHeadBuildHeadArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) sgh->head_array[idx].hdr_copy3 = s->hdr_copy3; sgh->head_array[idx].full_sig = s; -#if defined(__SSE3__) || defined(__tile__) - sgh->mask_array[idx] = s->mask; -#endif idx++; } diff --git a/src/detect-simd.c b/src/detect-simd.c index 0773bc964ca5..114ee589a1f5 100644 --- a/src/detect-simd.c +++ b/src/detect-simd.c @@ -32,216 +32,6 @@ /* Included into detect.c */ -#if defined(__SSE3__) - -/** - * \brief SIMD implementation of mask prefiltering. - * - * Mass mask matching is done creating a bitmap of signatures that need - * futher inspection. - * - * On 32 bit systems we inspect in 32 sig batches, creating a u32 with flags. - * On 64 bit systems we inspect in 64 sig batches, creating a u64 with flags. - * The size of a register is leading here. - */ -void SigMatchSignaturesBuildMatchArray(DetectEngineThreadCtx *det_ctx, - Packet *p, SignatureMask mask, AppProto alproto) -{ - uint32_t u; - SigIntId x; - int bitno = 0; -#if __WORDSIZE == 32 - register uint32_t bm; /* bit mask, 32 bits used */ - - Vector pm, sm, r1, r2; - /* load the packet mask into each byte of the vector */ - pm.v = _mm_set1_epi8(mask); - - /* reset previous run */ - det_ctx->match_array_cnt = 0; - - for (u = 0; u < det_ctx->sgh->sig_cnt; u += 32) { - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm = ((uint32_t) _mm_movemask_epi8(r2.v)); - - SCLogDebug("bm1 %08x", bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+16]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm |= ((uint32_t) _mm_movemask_epi8(r2.v) << 16); - - SCLogDebug("bm2 %08x", bm); - - if (bm == 0) { - continue; - } - - /* Check each bit in the bit map. Little endian is assumed (SSE is x86), - * so the bits are in memory backwards, 0 is on the right edge, - * 31 on the left edge. This is why above we store the output of the - * _mm_movemask_epi8 in this order as well */ - bitno = 0; - for (x = u; x < det_ctx->sgh->sig_cnt && bitno < 32; x++, bitno++) { - if (bm & (1 << bitno)) { - SignatureHeader *s = &det_ctx->sgh->head_array[x]; - - if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { - /* okay, store it */ - det_ctx->match_array[det_ctx->match_array_cnt] = s->full_sig; - det_ctx->match_array_cnt++; - } - } - } - } -#elif __WORDSIZE == 64 - register uint64_t bm; /* bit mask, 64 bits used */ - - Vector pm, sm, r1, r2; - /* load the packet mask into each byte of the vector */ - pm.v = _mm_set1_epi8(mask); - - /* reset previous run */ - det_ctx->match_array_cnt = 0; - - for (u = 0; u < det_ctx->sgh->sig_cnt; u += 64) { - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm = ((uint64_t) _mm_movemask_epi8(r2.v)); - - SCLogDebug("bm1 %08"PRIx64, bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+16]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 16; - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+32]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 32; - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+48]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 48; - - SCLogDebug("bm2 %08"PRIx64, bm); - - if (bm == 0) { - continue; - } - - /* Check each bit in the bit map. Little endian is assumed (SSE is x86-64), - * so the bits are in memory backwards, 0 is on the right edge, - * 63 on the left edge. This is why above we store the output of the - * _mm_movemask_epi8 in this order as well */ - bitno = 0; - for (x = u; x < det_ctx->sgh->sig_cnt && bitno < 64; x++, bitno++) { - if (bm & ((uint64_t)1 << bitno)) { - SignatureHeader *s = &det_ctx->sgh->head_array[x]; - - if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { - /* okay, store it */ - det_ctx->match_array[det_ctx->match_array_cnt] = s->full_sig; - det_ctx->match_array_cnt++; - } - } - } - } -#else -#error Wordsize (__WORDSIZE) neither 32 or 64. -#endif -} - /* end defined(__SSE3__) */ -#elif defined(__tile__) - -/** - * \brief SIMD implementation of mask prefiltering for TILE-Gx - * - * Mass mask matching is done creating a bitmap of signatures that need - * futher inspection. - */ -void SigMatchSignaturesBuildMatchArray(DetectEngineThreadCtx *det_ctx, - Packet *p, SignatureMask mask, AppProto alproto) -{ - uint32_t u; - register uint64_t bm; /* bit mask, 64 bits used */ - - /* Keep local copies of variables that don't change during this function. */ - uint64_t *mask_vector = (uint64_t*)det_ctx->sgh->mask_array; - uint32_t sig_cnt = det_ctx->sgh->sig_cnt; - SignatureHeader *head_array = det_ctx->sgh->head_array; - - Signature **match_array = det_ctx->match_array; - uint32_t match_count = 0; - - /* Replicate the packet mask into each byte of the vector. */ - uint64_t pm = __insn_shufflebytes(mask, 0, 0); - - /* u is the signature index. */ - for (u = 0; u < sig_cnt; u += 8) { - /* Load 8 masks */ - uint64_t sm = *mask_vector++; - /* Binary AND 8 masks with the packet's mask */ - uint64_t r1 = pm & sm; - /* Compare the result with the original mask - * Result if equal puts a 1 in LSB of bytes that match. - */ - bm = __insn_v1cmpeq(sm, r1); - - /* Check the LSB bit of each byte in the bit map. Little endian is assumed, - * so the LSB byte is index 0. Uses count trailing zeros to find least - * significant bit that is set. */ - while (bm) { - /* Find first bit set starting from LSB. */ - unsigned int first_bit = __insn_ctz(bm); - unsigned int first_byte = first_bit >> 3; - unsigned int x = u + first_byte; - if (x >= sig_cnt) - break; - SignatureHeader *s = &head_array[x]; - - /* Clear the first bit set, so it is not found again. */ - bm -= (1UL << first_bit); - - if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { - /* okay, store it */ - *match_array++ = s->full_sig; - match_count++; - } - } - } - det_ctx->match_array_cnt = match_count; -} -#endif /* defined(__tile__) */ #ifdef UNITTESTS From ef6875d583b1d270997f385d727abffd0242e369 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 8 Dec 2014 14:30:52 +0100 Subject: [PATCH 0185/2553] detect: Disable unused SignatureHeader code --- src/Makefile.am | 1 - src/detect-engine-siggroup.c | 41 ---- src/detect-engine-siggroup.h | 2 - src/detect-simd.c | 365 ----------------------------------- src/detect.c | 121 +----------- src/detect.h | 38 ---- 6 files changed, 2 insertions(+), 566 deletions(-) delete mode 100644 src/detect-simd.c diff --git a/src/Makefile.am b/src/Makefile.am index cc1357e0f8b0..d60f56c4b9b9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,7 +71,6 @@ detect-byte-extract.c detect-byte-extract.h \ detect-bytejump.c detect-bytejump.h \ detect-bytetest.c detect-bytetest.h \ detect.c detect.h \ -detect-simd.c \ detect-classtype.c detect-classtype.h \ detect-content.c detect-content.h \ detect-csum.c detect-csum.h \ diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index ff7fcb2d4a57..3b8a9ed3bf6a 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -185,11 +185,6 @@ void SigGroupHeadFree(SigGroupHead *sgh) PatternMatchDestroyGroup(sgh); - if (sgh->head_array != NULL) { - SCFree(sgh->head_array); - sgh->head_array = NULL; - } - if (sgh->match_array != NULL) { detect_siggroup_matcharray_free_cnt++; detect_siggroup_matcharray_memory -= (sgh->sig_cnt * sizeof(Signature *)); @@ -1742,42 +1737,6 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return 0; } -int SigGroupHeadBuildHeadArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - Signature *s = NULL; - uint32_t idx = 0; - uint32_t sig = 0; - - if (sgh == NULL) - return 0; - - BUG_ON(sgh->head_array != NULL); - - sgh->head_array = SCMalloc(sgh->sig_cnt * sizeof(SignatureHeader)); - if (sgh->head_array == NULL) - return -1; - - memset(sgh->head_array, 0, sgh->sig_cnt * sizeof(SignatureHeader)); - - detect_siggroup_matcharray_init_cnt++; - detect_siggroup_matcharray_memory += (sgh->sig_cnt * sizeof(SignatureHeader *)); - - for (sig = 0; sig < sgh->sig_cnt; sig++) { - s = sgh->match_array[sig]; - if (s == NULL) - continue; - - sgh->head_array[idx].hdr_copy1 = s->hdr_copy1; - sgh->head_array[idx].hdr_copy2 = s->hdr_copy2; - sgh->head_array[idx].hdr_copy3 = s->hdr_copy3; - sgh->head_array[idx].full_sig = s; - - idx++; - } - - return 0; -} - /** * \brief Check if a SigGroupHead contains a Signature, whose sid is sent as an * argument. diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index a9368ee19f89..829b0cefb326 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -84,8 +84,6 @@ void SigGroupHeadRegisterTests(void); void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh); void SigGroupHeadStore(DetectEngineCtx *, SigGroupHead *); - -int SigGroupHeadBuildHeadArray(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilestoreCount(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *, SigGroupHead *); diff --git a/src/detect-simd.c b/src/detect-simd.c deleted file mode 100644 index 114ee589a1f5..000000000000 --- a/src/detect-simd.c +++ /dev/null @@ -1,365 +0,0 @@ -/* Copyright (C) 2013 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 - * - * Basic detection engine - */ - -#include "suricata-common.h" -#include "detect.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-vector.h" - -/* Included into detect.c */ - - - -#ifdef UNITTESTS -#include "flow-util.h" -#include "stream-tcp-reassemble.h" -#include "util-var-name.h" - -/// SCLogInfo("%s %u %u %u %u", #v, (v).dw[0], (v).dw[1], (v).dw[2], (v).dw[3]); -#define VECTOR_SCLogInfo(v) { \ - SCLogInfo("%s %08X %08X %08X %08X", #v, (v).dw[0], (v).dw[1], (v).dw[2], (v).dw[3]); \ -} - -/** - * \test Test 32 bit SIMD code. - */ -static int SigTestSIMDMask01(void) -{ -#if defined (__SSE3__) - Vector pm, sm, r1, r2; - uint32_t bm = 0; - - uint8_t *mask = SCMallocAligned(32, 16); - memset(mask, 0xEF, 32); - mask[31] = 0xFF; - printf("\n"); - pm.v = _mm_set1_epi8(0xEF); - VECTOR_SCLogInfo(pm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[0]); - VECTOR_SCLogInfo(sm); - - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm = ((uint32_t) _mm_movemask_epi8(r2.v)); - - SCLogInfo("bm %08x", bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[16]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint32_t) _mm_movemask_epi8(r2.v)) << 16; - - SCLogInfo("bm %08x", bm); - - int b = 0; - for ( ; b < 32; b++){ - if (bm & (1 << b)) { - SCLogInfo("b %02d, set", b); - } else { - SCLogInfo("b %02d, not set", b); - - } - } - - if (!(bm & (1 << 31))) { - return 1; - } - return 0; -#else - return 1; -#endif -} - -/** - * \test Test 32 bit SIMD code. - */ -static int SigTestSIMDMask02(void) -{ -#if defined (__SSE3__) - Vector pm, sm, r1, r2; - uint32_t bm = 0; - - uint8_t *mask = SCMallocAligned(32, 16); - memset(mask, 0x01, 32); - mask[31] = 0; - pm.v = _mm_set1_epi8(0x02); - VECTOR_SCLogInfo(pm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[0]); - VECTOR_SCLogInfo(sm); - - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm = ((uint32_t) _mm_movemask_epi8(r2.v)); - - SCLogInfo("bm %08x", bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[16]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint32_t) _mm_movemask_epi8(r2.v)) << 16; - - SCLogInfo("bm %08x", bm); - - int b = 0; - for ( ; b < 32; b++){ - if (bm & (1 << b)) { - SCLogInfo("b %02d, set", b); - } else { - SCLogInfo("b %02d, not set", b); - - } - } - - if (bm & (1 << 31)) { - return 1; - } - return 0; -#else - return 1; -#endif -} - -/** - * \test Test 64 bit SIMD code. - */ -static int SigTestSIMDMask03(void) -{ -#if defined (__SSE3__) - Vector pm, sm, r1, r2; - uint64_t bm = 0; - uint8_t *mask = SCMallocAligned(64, 16); - memset(mask, 0xEF, 64); - mask[31] = 0xFF; - mask[62] = 0xFF; - printf("\n"); - pm.v = _mm_set1_epi8(0xEF); - VECTOR_SCLogInfo(pm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[0]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm = ((uint64_t) _mm_movemask_epi8(r2.v)); - - SCLogInfo("bm1 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[16]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 16; - - SCLogInfo("bm2 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[32]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 32; - - SCLogInfo("bm3 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[48]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 48; - - SCLogInfo("bm4 %"PRIxMAX, (uintmax_t)bm); - - int b = 0; - for ( ; b < 64; b++){ - if (bm & ((uint64_t)1 << b)) { - SCLogInfo("b %02d, set", b); - } else { - SCLogInfo("b %02d, not set", b); - - } - } - - if (!(bm & ((uint64_t)1 << 31)) && !(bm & ((uint64_t)1 << 62))) { - return 1; - } - return 0; -#else - return 1; -#endif -} - -/** - * \test Test 64 bit SIMD code. - */ -static int SigTestSIMDMask04(void) -{ -#if defined (__SSE3__) - Vector pm, sm, r1, r2; - uint64_t bm = 0; - - uint8_t *mask = SCMallocAligned(64, 16); - memset(mask, 0x01, 64); - mask[31] = 0; - mask[62] = 0; - pm.v = _mm_set1_epi8(0x02); - VECTOR_SCLogInfo(pm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[0]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm = ((uint64_t) _mm_movemask_epi8(r2.v)); - - SCLogInfo("bm1 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[16]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 16; - - SCLogInfo("bm2 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[32]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 32; - - SCLogInfo("bm3 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[48]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= (((uint64_t) _mm_movemask_epi8(r2.v)) << 48); - - SCLogInfo("bm4-total %"PRIxMAX, (uintmax_t)bm); - - int b = 0; - for ( ; b < 64; b++){ - if (bm & ((uint64_t)1 << b)) { - SCLogInfo("b %02d, set", b); - } else { - SCLogInfo("b %02d, not set", b); - - } - } - - if ((bm & ((uint64_t)1 << 31)) && (bm & ((uint64_t)1 << 62))) { - return 1; - } - return 0; -#else - return 1; -#endif -} -#endif /* UNITTESTS */ - -void DetectSimdRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("SigTestSIMDMask01", SigTestSIMDMask01, 1); - UtRegisterTest("SigTestSIMDMask02", SigTestSIMDMask02, 1); - UtRegisterTest("SigTestSIMDMask03", SigTestSIMDMask03, 1); - UtRegisterTest("SigTestSIMDMask04", SigTestSIMDMask04, 1); -#endif /* UNITTESTS */ -} diff --git a/src/detect.c b/src/detect.c index 28d4082501ee..b2ef96520290 100644 --- a/src/detect.c +++ b/src/detect.c @@ -483,122 +483,6 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl SCReturnInt(ret); } -/** - * \brief See if we can prefilter a signature on inexpensive checks - * - * Order of SignatureHeader access: - * 1. flags - * 2. alproto - * 3. mpm_pattern_id_div8 - * 4. mpm_pattern_id_mod8 - * 5. num - * - * \retval 0 can't match, don't inspect - * \retval 1 might match, further inspection required - */ -int SigMatchSignaturesBuildMatchArrayAddSignature(DetectEngineThreadCtx *det_ctx, - Packet *p, SignatureHeader *s, - AppProto alproto) -{ - /* if the sig has alproto and the session as well they should match */ - if (likely(s->flags & SIG_FLAG_APPLAYER)) { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { - if (s->alproto == ALPROTO_DCERPC) { - if (alproto != ALPROTO_SMB && alproto != ALPROTO_SMB2) { - SCLogDebug("DCERPC sig, alproto not SMB or SMB2"); - return 0; - } - } else { - SCLogDebug("alproto mismatch"); - return 0; - } - } - } - - if (unlikely(s->flags & SIG_FLAG_DSIZE)) { - if (likely(p->payload_len < s->dsize_low || p->payload_len > s->dsize_high)) { - SCLogDebug("kicked out as p->payload_len %u, dsize low %u, hi %u", - p->payload_len, s->dsize_low, s->dsize_high); - return 0; - } - } - - /* check for a pattern match of the one pattern in this sig. */ - if (likely(s->flags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_APPLAYER))) - { - /* filter out sigs that want pattern matches, but - * have no matches */ - if (!(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { - if (s->flags & SIG_FLAG_MPM_PACKET) { - if (!(s->flags & SIG_FLAG_MPM_PACKET_NEG)) { - return 0; - } - } else if (s->flags & SIG_FLAG_MPM_STREAM) { - /* filter out sigs that want pattern matches, but - * have no matches */ - if (!(s->flags & SIG_FLAG_MPM_STREAM_NEG)) { - return 0; - } - } else if (s->flags & SIG_FLAG_MPM_APPLAYER) { - if (!(s->flags & SIG_FLAG_MPM_APPLAYER_NEG)) { - return 0; - } - } - } - } - - /* de_state check, filter out all signatures that already had a match before - * or just partially match */ - if (s->flags & SIG_FLAG_STATE_MATCH) { - /* we run after DeStateDetectContinueDetection, so we might have - * state NEW here. In that case we'd want to continue detection - * for this sig. If we have NOSTATE, stateful detection didn't - * start yet for this sig, so we will inspect it. - */ - if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NO_NEW_STATE) - return 0; - } - - return 1; -} - -#if defined(__SSE3__) || defined(__tile__) -/* SIMD implementations are in detect-simd.c */ -#else -/* Non-SIMD implementation */ -/** - * \brief build an array of signatures that will be inspected - * - * All signatures that can be filtered out on forehand are not added to it. - * - * \param de_ctx detection engine ctx - * \param det_ctx detection engine thread ctx -- array is stored here - * \param p packet - * \param mask Packets mask - * \param alproto application layer protocol - */ -void SigMatchSignaturesBuildMatchArray(DetectEngineThreadCtx *det_ctx, - Packet *p, SignatureMask mask, - AppProto alproto) -{ - uint32_t u; - - /* reset previous run */ - det_ctx->match_array_cnt = 0; - - for (u = 0; u < det_ctx->sgh->sig_cnt; u++) { - SignatureHeader *s = &det_ctx->sgh->head_array[u]; - if ((mask & s->mask) == s->mask) { - if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { - /* okay, store it */ - det_ctx->match_array[det_ctx->match_array_cnt] = s->full_sig; - det_ctx->match_array_cnt++; - } - } - } -} -#endif /* No SIMD implementation */ - int SigMatchSignaturesRunPostMatch(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s) @@ -4192,8 +4076,6 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SigGroupHead *sgh = de_ctx->sgh_array[idx]; if (sgh == NULL) continue; - - SigGroupHeadBuildHeadArray(de_ctx, sgh); SigGroupHeadSetFilemagicFlag(de_ctx, sgh); SigGroupHeadSetFileMd5Flag(de_ctx, sgh); SigGroupHeadSetFilesizeFlag(de_ctx, sgh); @@ -4204,7 +4086,6 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) } if (de_ctx->decoder_event_sgh != NULL) { - SigGroupHeadBuildHeadArray(de_ctx, de_ctx->decoder_event_sgh); /* no need to set filestore count here as that would make a * signature not decode event only. */ } @@ -12274,7 +12155,9 @@ void SigRegisterTests(void) UtRegisterTest("SigTestPorts01", SigTestPorts01, 1); UtRegisterTest("SigTestBug01", SigTestBug01, 1); +#if 0 DetectSimdRegisterTests(); +#endif #endif /* UNITTESTS */ } diff --git a/src/detect.h b/src/detect.h index 3a31af255d1c..8d089be924c1 100644 --- a/src/detect.h +++ b/src/detect.h @@ -333,37 +333,6 @@ typedef struct IPOnlyCIDRItem_ { } 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 Used to start a pointer to SigMatch context * Should never be dereferenced without casting to something else. */ @@ -988,10 +957,6 @@ typedef struct SigGroupHead_ { #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; SigIntId *non_mpm_id_array; uint32_t non_mpm_id_cnt; // size is cnt * sizeof(uint32_t) @@ -1184,9 +1149,6 @@ 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 *); From 30b7fdcb492425a6786dfc025bad0a99515f7686 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Nov 2014 16:05:57 +0100 Subject: [PATCH 0186/2553] Detect perf counters --- src/detect-engine.c | 9 +++++++++ src/detect.c | 3 +++ src/detect.h | 3 +++ 3 files changed, 15 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 11f117addaff..63de6d6a58d5 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1356,6 +1356,12 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) * rules haven't been loaded yet. */ uint16_t counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, SC_PERF_TYPE_UINT64, "NULL"); + uint16_t counter_mpm_list = SCPerfTVRegisterAvgCounter("detect.mpm_list", tv, + SC_PERF_TYPE_UINT64, "NULL"); + uint16_t counter_nonmpm_list = SCPerfTVRegisterAvgCounter("detect.nonmpm_list", tv, + SC_PERF_TYPE_UINT64, "NULL"); + uint16_t counter_match_list = SCPerfTVRegisterAvgCounter("detect.match_list", tv, + SC_PERF_TYPE_UINT64, "NULL"); if (de_ctx->delayed_detect == 1 && de_ctx->delayed_detect_initialized == 0) { *data = NULL; return TM_ECODE_OK; @@ -1374,6 +1380,9 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) /** alert counter setup */ det_ctx->counter_alerts = counter_alerts; + det_ctx->counter_mpm_list = counter_mpm_list; + det_ctx->counter_nonmpm_list = counter_nonmpm_list; + det_ctx->counter_match_list = counter_match_list; /* pass thread data back to caller */ *data = (void *)det_ctx; diff --git a/src/detect.c b/src/detect.c index b2ef96520290..46a66f31f671 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1334,6 +1334,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM); DetectMpmPrefilter(de_ctx, det_ctx, smsg, p, flags, alproto, has_state, &sms_runflags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); + SCPerfCounterAddUI64(det_ctx->counter_mpm_list, th_v->sc_perf_pca, (uint64_t)det_ctx->pmq.rule_id_array_cnt); + SCPerfCounterAddUI64(det_ctx->counter_nonmpm_list, th_v->sc_perf_pca, (uint64_t)det_ctx->sgh->non_mpm_id_cnt); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PREFILTER); DetectPrefilterMergeSort(de_ctx, det_ctx, det_ctx->sgh); @@ -1343,6 +1345,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* inspect the sigs against the packet */ /* Prefetch the next signature. */ SigIntId match_cnt = det_ctx->match_array_cnt; + SCPerfCounterAddUI64(det_ctx->counter_match_list, th_v->sc_perf_pca, (uint64_t)match_cnt); Signature **match_array = det_ctx->match_array; uint32_t sflags, next_sflags = 0; diff --git a/src/detect.h b/src/detect.h index 8d089be924c1..c3485a9f7040 100644 --- a/src/detect.h +++ b/src/detect.h @@ -791,6 +791,9 @@ typedef struct DetectionEngineThreadCtx_ { /** id for alert counter */ uint16_t counter_alerts; + uint16_t counter_mpm_list; + uint16_t counter_nonmpm_list; + uint16_t counter_match_list; /* used to discontinue any more matching */ uint16_t discontinue_matching; From 904441327c93c799a521851f1e3ad62eac74814b Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 7 Nov 2014 12:46:46 -0500 Subject: [PATCH 0187/2553] Conditionalize SigMatch performance counters. Only include the counters when PROFILING. --- src/detect-engine.c | 4 ++++ src/detect.c | 17 ++++++++++++++--- src/detect.h | 2 ++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 63de6d6a58d5..f2247b5d6b86 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1356,12 +1356,14 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) * rules haven't been loaded yet. */ uint16_t counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, SC_PERF_TYPE_UINT64, "NULL"); +#ifdef PROFILING uint16_t counter_mpm_list = SCPerfTVRegisterAvgCounter("detect.mpm_list", tv, SC_PERF_TYPE_UINT64, "NULL"); uint16_t counter_nonmpm_list = SCPerfTVRegisterAvgCounter("detect.nonmpm_list", tv, SC_PERF_TYPE_UINT64, "NULL"); uint16_t counter_match_list = SCPerfTVRegisterAvgCounter("detect.match_list", tv, SC_PERF_TYPE_UINT64, "NULL"); +#endif if (de_ctx->delayed_detect == 1 && de_ctx->delayed_detect_initialized == 0) { *data = NULL; return TM_ECODE_OK; @@ -1380,9 +1382,11 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) /** alert counter setup */ det_ctx->counter_alerts = counter_alerts; +#ifdef PROFILING det_ctx->counter_mpm_list = counter_mpm_list; det_ctx->counter_nonmpm_list = counter_nonmpm_list; det_ctx->counter_match_list = counter_match_list; +#endif /* pass thread data back to caller */ *data = (void *)det_ctx; diff --git a/src/detect.c b/src/detect.c index 46a66f31f671..997790831415 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1334,8 +1334,14 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM); DetectMpmPrefilter(de_ctx, det_ctx, smsg, p, flags, alproto, has_state, &sms_runflags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); - SCPerfCounterAddUI64(det_ctx->counter_mpm_list, th_v->sc_perf_pca, (uint64_t)det_ctx->pmq.rule_id_array_cnt); - SCPerfCounterAddUI64(det_ctx->counter_nonmpm_list, th_v->sc_perf_pca, (uint64_t)det_ctx->sgh->non_mpm_id_cnt); +#ifdef PROFILING + if (th_v) { + SCPerfCounterAddUI64(det_ctx->counter_mpm_list, th_v->sc_perf_pca, + (uint64_t)det_ctx->pmq.rule_id_array_cnt); + SCPerfCounterAddUI64(det_ctx->counter_nonmpm_list, th_v->sc_perf_pca, + (uint64_t)det_ctx->sgh->non_mpm_id_cnt); + } +#endif PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PREFILTER); DetectPrefilterMergeSort(de_ctx, det_ctx, det_ctx->sgh); @@ -1345,7 +1351,12 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* inspect the sigs against the packet */ /* Prefetch the next signature. */ SigIntId match_cnt = det_ctx->match_array_cnt; - SCPerfCounterAddUI64(det_ctx->counter_match_list, th_v->sc_perf_pca, (uint64_t)match_cnt); +#ifdef PROFILING + if (th_v) { + SCPerfCounterAddUI64(det_ctx->counter_match_list, th_v->sc_perf_pca, + (uint64_t)match_cnt); + } +#endif Signature **match_array = det_ctx->match_array; uint32_t sflags, next_sflags = 0; diff --git a/src/detect.h b/src/detect.h index c3485a9f7040..2ed8b5a3c023 100644 --- a/src/detect.h +++ b/src/detect.h @@ -791,9 +791,11 @@ typedef struct DetectionEngineThreadCtx_ { /** id for alert counter */ uint16_t counter_alerts; +#ifdef COLLECT_SIGMATCH_LIST_STATS uint16_t counter_mpm_list; uint16_t counter_nonmpm_list; uint16_t counter_match_list; +#endif /* used to discontinue any more matching */ uint16_t discontinue_matching; From b5a31271512cef7c7fd2ad4b009e46b8f6490d40 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Nov 2014 20:57:14 +0100 Subject: [PATCH 0188/2553] detect: add mask check prefilter for non mpm list Add mask array for non_mpm sigs, so that we can exclude many sigs before we merge sort. Shows 50% less non mpm sigs inspected on average. --- src/detect-engine-siggroup.c | 13 +++++++++++++ src/detect-engine.c | 9 +++++++++ src/detect.c | 30 +++++++++++++++++++++++------- src/detect.h | 11 +++++++++-- 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 3b8a9ed3bf6a..5f3a9f14ab8a 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -198,6 +198,12 @@ void SigGroupHeadFree(SigGroupHead *sgh) sgh->non_mpm_id_cnt = 0; } + if (sgh->non_mpm_mask_array != NULL) { + SCFree(sgh->non_mpm_mask_array); + sgh->non_mpm_mask_array = NULL; + sgh->non_mpm_mask_cnt = 0; + } + sgh->sig_cnt = 0; if (sgh->init != NULL) { @@ -1700,6 +1706,7 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return 0; BUG_ON(sgh->non_mpm_id_array != NULL); + BUG_ON(sgh->non_mpm_mask_array != NULL); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; @@ -1721,6 +1728,10 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) BUG_ON(sgh->non_mpm_id_array == NULL); memset(sgh->non_mpm_id_array, 0, non_mpm * sizeof(SigIntId)); + sgh->non_mpm_mask_array = SCMalloc(non_mpm * sizeof(SignatureMask)); + BUG_ON(sgh->non_mpm_mask_array == NULL); + memset(sgh->non_mpm_mask_array, 0, non_mpm * sizeof(SignatureMask)); + for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) @@ -1729,9 +1740,11 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) if (s->mpm_sm == NULL) { BUG_ON(sgh->non_mpm_id_cnt >= non_mpm); sgh->non_mpm_id_array[sgh->non_mpm_id_cnt++] = s->num; + sgh->non_mpm_mask_array[sgh->non_mpm_mask_cnt++] = s->mask; } else if (s->flags & (SIG_FLAG_MPM_PACKET_NEG|SIG_FLAG_MPM_STREAM_NEG|SIG_FLAG_MPM_APPLAYER_NEG)) { BUG_ON(sgh->non_mpm_id_cnt >= non_mpm); sgh->non_mpm_id_array[sgh->non_mpm_id_cnt++] = s->num; + sgh->non_mpm_mask_array[sgh->non_mpm_mask_cnt++] = s->mask; } } return 0; diff --git a/src/detect-engine.c b/src/detect-engine.c index f2247b5d6b86..8f8cc2095dad 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1361,6 +1361,8 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) SC_PERF_TYPE_UINT64, "NULL"); uint16_t counter_nonmpm_list = SCPerfTVRegisterAvgCounter("detect.nonmpm_list", tv, SC_PERF_TYPE_UINT64, "NULL"); + uint16_t counter_fnonmpm_list = SCPerfTVRegisterAvgCounter("detect.fnonmpm_list", tv, + SC_PERF_TYPE_UINT64, "NULL"); uint16_t counter_match_list = SCPerfTVRegisterAvgCounter("detect.match_list", tv, SC_PERF_TYPE_UINT64, "NULL"); #endif @@ -1377,6 +1379,9 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) det_ctx->tv = tv; det_ctx->de_ctx = de_ctx; + det_ctx->non_mpm_id_array = SCCalloc(32000, sizeof(SigIntId)); // TODO proper size or dynamicly grow + BUG_ON(det_ctx->non_mpm_id_array == NULL); + if (ThreadCtxDoInit(de_ctx, det_ctx) != TM_ECODE_OK) return TM_ECODE_FAILED; @@ -1385,6 +1390,7 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) #ifdef PROFILING det_ctx->counter_mpm_list = counter_mpm_list; det_ctx->counter_nonmpm_list = counter_nonmpm_list; + det_ctx->counter_fnonmpm_list = counter_fnonmpm_list; det_ctx->counter_match_list = counter_match_list; #endif @@ -1458,6 +1464,9 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) PmqFree(&det_ctx->smsg_pmq[i]); } + if (det_ctx->non_mpm_id_array != NULL) + SCFree(det_ctx->non_mpm_id_array); + if (det_ctx->de_state_sig_array != NULL) SCFree(det_ctx->de_state_sig_array); if (det_ctx->match_array != NULL) diff --git a/src/detect.c b/src/detect.c index 997790831415..1b561ff912d6 100644 --- a/src/detect.c +++ b/src/detect.c @@ -663,17 +663,19 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) } static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - SigGroupHead *sgh) + DetectEngineThreadCtx *det_ctx) +// SigGroupHead *sgh) { SigIntId mpm, nonmpm; det_ctx->match_array_cnt = 0; SigIntId *mpm_ptr = det_ctx->pmq.rule_id_array; - SigIntId *nonmpm_ptr = sgh->non_mpm_id_array; + SigIntId *nonmpm_ptr = det_ctx->non_mpm_id_array; + //SigIntId *nonmpm_ptr = sgh->non_mpm_id_array; uint32_t m_cnt = det_ctx->pmq.rule_id_array_cnt; - uint32_t n_cnt = sgh->non_mpm_id_cnt; + //uint32_t n_cnt = sgh->non_mpm_id_cnt; + uint32_t n_cnt = det_ctx->non_mpm_id_cnt; SCLogDebug("PMQ rule id array count %d", det_ctx->pmq.rule_id_array_cnt); - SCLogDebug("SGH non-MPM id count %d", sgh->non_mpm_id_cnt); +// SCLogDebug("SGH non-MPM id count %d", sgh->non_mpm_id_cnt); SigIntId *final_ptr; uint32_t final_cnt; SigIntId id; @@ -752,7 +754,7 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, det_ctx->match_array_cnt = match_array - det_ctx->match_array; - BUG_ON((det_ctx->pmq.rule_id_array_cnt + sgh->non_mpm_id_cnt) < det_ctx->match_array_cnt); + BUG_ON((det_ctx->pmq.rule_id_array_cnt + det_ctx->non_mpm_id_cnt) < det_ctx->match_array_cnt); } /* Return true is the list is sorted smallest to largest */ @@ -1330,6 +1332,17 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SignatureMask mask = 0; PacketCreateMask(p, &mask, alproto, has_state, smsg, app_decoder_events); + /* prefilter non_mpm list against the mask of the packet */ + det_ctx->non_mpm_id_cnt = 0; + uint32_t x = 0; + for (x = 0; x < det_ctx->sgh->non_mpm_id_cnt; x++) { + /* only if the mask matches this rule can possibly match, + * so build the non_mpm array only for match candidates */ + if ((det_ctx->sgh->non_mpm_mask_array[x] & mask) == det_ctx->sgh->non_mpm_mask_array[x]) { + det_ctx->non_mpm_id_array[det_ctx->non_mpm_id_cnt++] = det_ctx->sgh->non_mpm_id_array[x]; + } + } + /* run the mpm for each type */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM); DetectMpmPrefilter(de_ctx, det_ctx, smsg, p, flags, alproto, has_state, &sms_runflags); @@ -1340,11 +1353,14 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh (uint64_t)det_ctx->pmq.rule_id_array_cnt); SCPerfCounterAddUI64(det_ctx->counter_nonmpm_list, th_v->sc_perf_pca, (uint64_t)det_ctx->sgh->non_mpm_id_cnt); + /* non mpm sigs after mask prefilter */ + SCPerfCounterAddUI64(det_ctx->counter_fnonmpm_list, + th_v->sc_perf_pca, (uint64_t)det_ctx->non_mpm_id_cnt); } #endif PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PREFILTER); - DetectPrefilterMergeSort(de_ctx, det_ctx, det_ctx->sgh); + DetectPrefilterMergeSort(de_ctx, det_ctx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PREFILTER); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_RULES); diff --git a/src/detect.h b/src/detect.h index 2ed8b5a3c023..9ded0077e130 100644 --- a/src/detect.h +++ b/src/detect.h @@ -762,6 +762,9 @@ typedef struct DetectionEngineThreadCtx_ { /* the thread to which this detection engine thread belongs */ ThreadVars *tv; + SigIntId *non_mpm_id_array; + uint32_t non_mpm_id_cnt; // size is cnt * sizeof(uint32_t) + /* detection engine variables */ /** offset into the payload of the last match by: @@ -791,9 +794,10 @@ typedef struct DetectionEngineThreadCtx_ { /** id for alert counter */ uint16_t counter_alerts; -#ifdef COLLECT_SIGMATCH_LIST_STATS +#ifdef PROFILING uint16_t counter_mpm_list; uint16_t counter_nonmpm_list; + uint16_t counter_fnonmpm_list; uint16_t counter_match_list; #endif @@ -964,7 +968,10 @@ typedef struct SigGroupHead_ { #endif SigIntId *non_mpm_id_array; - uint32_t non_mpm_id_cnt; // size is cnt * sizeof(uint32_t) + uint32_t non_mpm_id_cnt; // size is cnt * sizeof(SigIntId) + + SignatureMask *non_mpm_mask_array; + uint32_t non_mpm_mask_cnt; // size is cnt * sizeof(SignatureMask) /* pattern matcher instances */ MpmCtx *mpm_proto_other_ctx; From 4c10635dc1f820d37e43f44e06d318decc5cd150 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Nov 2014 12:25:30 +0100 Subject: [PATCH 0189/2553] detect: optimize non-mpm mask checking Store id and mask in a single array of type SignatureNonMpmStore so that both are loaded into the same cache line. --- src/detect-engine-siggroup.c | 43 ++++++++++++++---------------------- src/detect.c | 9 ++++---- src/detect.h | 12 +++++----- 3 files changed, 29 insertions(+), 35 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 5f3a9f14ab8a..08c298159c0a 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -192,16 +192,10 @@ void SigGroupHeadFree(SigGroupHead *sgh) sgh->match_array = NULL; } - if (sgh->non_mpm_id_array != NULL) { - SCFree(sgh->non_mpm_id_array); - sgh->non_mpm_id_array = NULL; - sgh->non_mpm_id_cnt = 0; - } - - if (sgh->non_mpm_mask_array != NULL) { - SCFree(sgh->non_mpm_mask_array); - sgh->non_mpm_mask_array = NULL; - sgh->non_mpm_mask_cnt = 0; + if (sgh->non_mpm_store_array != NULL) { + SCFree(sgh->non_mpm_store_array); + sgh->non_mpm_store_array = NULL; + sgh->non_mpm_store_cnt = 0; } sgh->sig_cnt = 0; @@ -1705,8 +1699,7 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) if (sgh == NULL) return 0; - BUG_ON(sgh->non_mpm_id_array != NULL); - BUG_ON(sgh->non_mpm_mask_array != NULL); + BUG_ON(sgh->non_mpm_store_array != NULL); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; @@ -1720,17 +1713,13 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) } if (non_mpm == 0) { - sgh->non_mpm_id_array = NULL; + sgh->non_mpm_store_array = NULL; return 0; } - sgh->non_mpm_id_array = SCMalloc(non_mpm * sizeof(SigIntId)); - BUG_ON(sgh->non_mpm_id_array == NULL); - memset(sgh->non_mpm_id_array, 0, non_mpm * sizeof(SigIntId)); - - sgh->non_mpm_mask_array = SCMalloc(non_mpm * sizeof(SignatureMask)); - BUG_ON(sgh->non_mpm_mask_array == NULL); - memset(sgh->non_mpm_mask_array, 0, non_mpm * sizeof(SignatureMask)); + sgh->non_mpm_store_array = SCMalloc(non_mpm * sizeof(SignatureNonMpmStore)); + BUG_ON(sgh->non_mpm_store_array == NULL); + memset(sgh->non_mpm_store_array, 0, non_mpm * sizeof(SignatureNonMpmStore)); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; @@ -1738,13 +1727,15 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) continue; if (s->mpm_sm == NULL) { - BUG_ON(sgh->non_mpm_id_cnt >= non_mpm); - sgh->non_mpm_id_array[sgh->non_mpm_id_cnt++] = s->num; - sgh->non_mpm_mask_array[sgh->non_mpm_mask_cnt++] = s->mask; + BUG_ON(sgh->non_mpm_store_cnt >= non_mpm); + sgh->non_mpm_store_array[sgh->non_mpm_store_cnt].id = s->num; + sgh->non_mpm_store_array[sgh->non_mpm_store_cnt].mask = s->mask; + sgh->non_mpm_store_cnt++; } else if (s->flags & (SIG_FLAG_MPM_PACKET_NEG|SIG_FLAG_MPM_STREAM_NEG|SIG_FLAG_MPM_APPLAYER_NEG)) { - BUG_ON(sgh->non_mpm_id_cnt >= non_mpm); - sgh->non_mpm_id_array[sgh->non_mpm_id_cnt++] = s->num; - sgh->non_mpm_mask_array[sgh->non_mpm_mask_cnt++] = s->mask; + BUG_ON(sgh->non_mpm_store_cnt >= non_mpm); + sgh->non_mpm_store_array[sgh->non_mpm_store_cnt].id = s->num; + sgh->non_mpm_store_array[sgh->non_mpm_store_cnt].mask = s->mask; + sgh->non_mpm_store_cnt++; } } return 0; diff --git a/src/detect.c b/src/detect.c index 1b561ff912d6..aba0a2c641f4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1335,11 +1335,12 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* prefilter non_mpm list against the mask of the packet */ det_ctx->non_mpm_id_cnt = 0; uint32_t x = 0; - for (x = 0; x < det_ctx->sgh->non_mpm_id_cnt; x++) { + for (x = 0; x < det_ctx->sgh->non_mpm_store_cnt; x++) { /* only if the mask matches this rule can possibly match, * so build the non_mpm array only for match candidates */ - if ((det_ctx->sgh->non_mpm_mask_array[x] & mask) == det_ctx->sgh->non_mpm_mask_array[x]) { - det_ctx->non_mpm_id_array[det_ctx->non_mpm_id_cnt++] = det_ctx->sgh->non_mpm_id_array[x]; + SignatureMask rule_mask = det_ctx->sgh->non_mpm_store_array[x].mask; + if ((rule_mask & mask) == rule_mask) { + det_ctx->non_mpm_id_array[det_ctx->non_mpm_id_cnt++] = det_ctx->sgh->non_mpm_store_array[x].id; } } @@ -1352,7 +1353,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SCPerfCounterAddUI64(det_ctx->counter_mpm_list, th_v->sc_perf_pca, (uint64_t)det_ctx->pmq.rule_id_array_cnt); SCPerfCounterAddUI64(det_ctx->counter_nonmpm_list, th_v->sc_perf_pca, - (uint64_t)det_ctx->sgh->non_mpm_id_cnt); + (uint64_t)det_ctx->sgh->non_mpm_store_cnt); /* non mpm sigs after mask prefilter */ SCPerfCounterAddUI64(det_ctx->counter_fnonmpm_list, th_v->sc_perf_pca, (uint64_t)det_ctx->non_mpm_id_cnt); diff --git a/src/detect.h b/src/detect.h index 9ded0077e130..2a130bb86991 100644 --- a/src/detect.h +++ b/src/detect.h @@ -953,6 +953,11 @@ typedef struct SigGroupHeadInitData_ { struct DetectPort_ *port; } SigGroupHeadInitData; +typedef struct SignatureNonMpmStore_ { + SigIntId id; + SignatureMask mask; +} SignatureNonMpmStore; + /** \brief Container for matching data for a signature group */ typedef struct SigGroupHead_ { uint32_t flags; @@ -967,11 +972,8 @@ typedef struct SigGroupHead_ { SignatureMask *mask_array; #endif - SigIntId *non_mpm_id_array; - uint32_t non_mpm_id_cnt; // size is cnt * sizeof(SigIntId) - - SignatureMask *non_mpm_mask_array; - uint32_t non_mpm_mask_cnt; // size is cnt * sizeof(SignatureMask) + SignatureNonMpmStore *non_mpm_store_array; + uint32_t non_mpm_store_cnt; // size is cnt * sizeof(SignatureNonMpmStore) /* pattern matcher instances */ MpmCtx *mpm_proto_other_ctx; From cc4f7a4b96ff531095a30a4a0fb35bb69fe0ba00 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Nov 2014 13:23:14 +0100 Subject: [PATCH 0190/2553] detect: add profiling for non-mpm list build & filter --- src/detect.c | 2 ++ src/suricata-common.h | 1 + src/util-profiling.c | 1 + 3 files changed, 4 insertions(+) diff --git a/src/detect.c b/src/detect.c index aba0a2c641f4..eeb11eaeec79 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1333,6 +1333,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PacketCreateMask(p, &mask, alproto, has_state, smsg, app_decoder_events); /* prefilter non_mpm list against the mask of the packet */ + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_NONMPMLIST); det_ctx->non_mpm_id_cnt = 0; uint32_t x = 0; for (x = 0; x < det_ctx->sgh->non_mpm_store_cnt; x++) { @@ -1343,6 +1344,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh det_ctx->non_mpm_id_array[det_ctx->non_mpm_id_cnt++] = det_ctx->sgh->non_mpm_store_array[x].id; } } + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_NONMPMLIST); /* run the mpm for each type */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM); diff --git a/src/suricata-common.h b/src/suricata-common.h index deb0e077cc83..d7126a874f82 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -309,6 +309,7 @@ typedef enum PacketProfileDetectId_ { PROF_DETECT_RULES, PROF_DETECT_STATEFUL, PROF_DETECT_PREFILTER, + PROF_DETECT_NONMPMLIST, PROF_DETECT_ALERT, PROF_DETECT_CLEANUP, PROF_DETECT_GETSGH, diff --git a/src/util-profiling.c b/src/util-profiling.c index 7a1ce2909931..dfe8c7744b96 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1035,6 +1035,7 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id) CASE_CODE (PROF_DETECT_ALERT); CASE_CODE (PROF_DETECT_CLEANUP); CASE_CODE (PROF_DETECT_GETSGH); + CASE_CODE (PROF_DETECT_NONMPMLIST); case PROF_DETECT_MPM_PKT_STREAM: return "PROF_DETECT_MPM_PKT_STR"; default: From ca59eabca3c5b5cbd1a21cf5c187b0a2e6dbb3ce Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Nov 2014 13:33:15 +0100 Subject: [PATCH 0191/2553] detect: introduce DetectPrefilterBuildNonMpmList Move building of non-mpm list into a separate function, that is inlined for performance reasons. --- src/detect.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/detect.c b/src/detect.c index eeb11eaeec79..c68d34963be4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1113,6 +1113,19 @@ static void AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(Packet *p, DetectEn return; } +static inline void DetectPrefilterBuildNonMpmList(DetectEngineThreadCtx *det_ctx, SignatureMask mask) +{ + uint32_t x = 0; + for (x = 0; x < det_ctx->sgh->non_mpm_store_cnt; x++) { + /* only if the mask matches this rule can possibly match, + * so build the non_mpm array only for match candidates */ + SignatureMask rule_mask = det_ctx->sgh->non_mpm_store_array[x].mask; + if ((rule_mask & mask) == rule_mask) { + det_ctx->non_mpm_id_array[det_ctx->non_mpm_id_cnt++] = det_ctx->sgh->non_mpm_store_array[x].id; + } + } +} + /** * \brief Signature match function * @@ -1332,17 +1345,11 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SignatureMask mask = 0; PacketCreateMask(p, &mask, alproto, has_state, smsg, app_decoder_events); - /* prefilter non_mpm list against the mask of the packet */ + /* build and prefilter non_mpm list against the mask of the packet */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_NONMPMLIST); det_ctx->non_mpm_id_cnt = 0; - uint32_t x = 0; - for (x = 0; x < det_ctx->sgh->non_mpm_store_cnt; x++) { - /* only if the mask matches this rule can possibly match, - * so build the non_mpm array only for match candidates */ - SignatureMask rule_mask = det_ctx->sgh->non_mpm_store_array[x].mask; - if ((rule_mask & mask) == rule_mask) { - det_ctx->non_mpm_id_array[det_ctx->non_mpm_id_cnt++] = det_ctx->sgh->non_mpm_store_array[x].id; - } + if (likely(det_ctx->sgh->non_mpm_store_cnt > 0)) { + DetectPrefilterBuildNonMpmList(det_ctx, mask); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_NONMPMLIST); From f1f5428faa1d8cf71256412b703413953ab5533d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Nov 2014 14:02:26 +0100 Subject: [PATCH 0192/2553] detect: expand mask checking Change mask to u16, and add checks for various protocol states that need to be present for a rule to be considered. --- src/detect.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- src/detect.h | 7 ++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index c68d34963be4..afb6b6d0f8e8 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2245,6 +2245,26 @@ PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, int has_state SCLogDebug("packet/flow has dce state"); (*mask) |= SIG_MASK_REQUIRE_DCE_STATE; break; + case ALPROTO_SSH: + SCLogDebug("packet/flow has ssh state"); + (*mask) |= SIG_MASK_REQUIRE_SSH_STATE; + break; + case ALPROTO_TLS: + SCLogDebug("packet/flow has tls state"); + (*mask) |= SIG_MASK_REQUIRE_TLS_STATE; + break; + case ALPROTO_DNS: + SCLogDebug("packet/flow has dns state"); + (*mask) |= SIG_MASK_REQUIRE_DNS_STATE; + break; + case ALPROTO_FTP: + SCLogDebug("packet/flow has ftp state"); + (*mask) |= SIG_MASK_REQUIRE_FTP_STATE; + break; + case ALPROTO_SMTP: + SCLogDebug("packet/flow has smtp state"); + (*mask) |= SIG_MASK_REQUIRE_SMTP_STATE; + break; default: SCLogDebug("packet/flow has other state"); break; @@ -2433,8 +2453,34 @@ static int SignatureCreateMask(Signature *s) } } + if (s->alproto == ALPROTO_SSH) { + s->mask |= SIG_MASK_REQUIRE_SSH_STATE; + SCLogDebug("sig requires ssh state"); + } + if (s->alproto == ALPROTO_TLS) { + s->mask |= SIG_MASK_REQUIRE_TLS_STATE; + SCLogDebug("sig requires tls state"); + } + if (s->alproto == ALPROTO_DNS) { + s->mask |= SIG_MASK_REQUIRE_DNS_STATE; + SCLogDebug("sig requires dns state"); + } + if (s->alproto == ALPROTO_FTP) { + s->mask |= SIG_MASK_REQUIRE_FTP_STATE; + SCLogDebug("sig requires ftp state"); + } + if (s->alproto == ALPROTO_SMTP) { + s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; + SCLogDebug("sig requires smtp state"); + } + if ((s->mask & SIG_MASK_REQUIRE_DCE_STATE) || - (s->mask & SIG_MASK_REQUIRE_HTTP_STATE)) + (s->mask & SIG_MASK_REQUIRE_HTTP_STATE) || + (s->mask & SIG_MASK_REQUIRE_SSH_STATE) || + (s->mask & SIG_MASK_REQUIRE_DNS_STATE) || + (s->mask & SIG_MASK_REQUIRE_FTP_STATE) || + (s->mask & SIG_MASK_REQUIRE_SMTP_STATE) || + (s->mask & SIG_MASK_REQUIRE_TLS_STATE)) { s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow"); diff --git a/src/detect.h b/src/detect.h index 2a130bb86991..5ff05bf95479 100644 --- a/src/detect.h +++ b/src/detect.h @@ -298,9 +298,14 @@ typedef struct DetectPort_ { #define SIG_MASK_REQUIRE_HTTP_STATE (1<<5) #define SIG_MASK_REQUIRE_DCE_STATE (1<<6) #define SIG_MASK_REQUIRE_ENGINE_EVENT (1<<7) +#define SIG_MASK_REQUIRE_SSH_STATE (1<<8) +#define SIG_MASK_REQUIRE_TLS_STATE (1<<9) +#define SIG_MASK_REQUIRE_DNS_STATE (1<<10) +#define SIG_MASK_REQUIRE_FTP_STATE (1<<11) +#define SIG_MASK_REQUIRE_SMTP_STATE (1<<12) /* for now a uint8_t is enough */ -#define SignatureMask uint8_t +#define SignatureMask uint16_t #define DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET 0x0001 #define DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM 0x0002 From f88405c650defda62b26b5b16d8d20fa9ce0906e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 10 Dec 2014 10:29:48 +0100 Subject: [PATCH 0193/2553] geoip: adapt to 'const' pointer passing --- src/detect-geoip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-geoip.c b/src/detect-geoip.c index 9bdbae052064..53c950f88c82 100644 --- a/src/detect-geoip.c +++ b/src/detect-geoip.c @@ -63,7 +63,7 @@ void DetectGeoipRegister(void) static int DetectGeoipMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatchCtx *); + Signature *, const SigMatchCtx *); static int DetectGeoipSetup(DetectEngineCtx *, Signature *, char *); static void DetectGeoipRegisterTests(void); static void DetectGeoipDataFree(void *); @@ -131,7 +131,7 @@ static const char *GeolocateIPv4(GeoIP *geoengine, uint32_t ip) * \retval 0 no match * \retval 1 match */ -static int CheckGeoMatchIPv4(DetectGeoipData *geoipdata, uint32_t ip) +static int CheckGeoMatchIPv4(const DetectGeoipData *geoipdata, uint32_t ip) { const char *country; int i; @@ -165,9 +165,9 @@ static int CheckGeoMatchIPv4(DetectGeoipData *geoipdata, uint32_t ip) * \retval 1 match */ static int DetectGeoipMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatchCtx *ctx) + Packet *p, Signature *s, const SigMatchCtx *ctx) { - DetectGeoipData *geoipdata = (DetectGeoipData *)ctx; + const DetectGeoipData *geoipdata = (const DetectGeoipData *)ctx; int matches = 0; if (PKT_IS_PSEUDOPKT(p)) From 4e98a3e530f701240a050acffe67fd8810400a32 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 10 Dec 2014 10:54:22 +0100 Subject: [PATCH 0194/2553] AC: fix memory leak --- src/util-mpm-ac.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 6cf05c1ffcdd..c8f6be77a205 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -218,6 +218,10 @@ static inline void SCACFreePattern(MpmCtx *mpm_ctx, SCACPattern *p) mpm_ctx->memory_size -= p->len; } + if (p != NULL && p->sids != NULL) { + SCFree(p->sids); + } + if (p != NULL) { SCFree(p); mpm_ctx->memory_cnt--; @@ -1089,6 +1093,9 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) //SCLogInfo("ctx->parray[i]->sids_size %u", ctx->parray[i]->sids_size); ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; + + ctx->parray[i]->sids_size = 0; + ctx->parray[i]->sids = NULL; } /* prepare the state table required by AC */ From 62751c801794ad36ce21824604e98843f68cfe8e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Jan 2015 10:57:02 +0100 Subject: [PATCH 0195/2553] Fix live reload detect thread ctx setup Code failed to setup non_mpm_id_array in case of a live reload. --- src/detect-engine.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 8f8cc2095dad..211d330f56ed 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1290,6 +1290,9 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * PmqSetup(&det_ctx->smsg_pmq[i], de_ctx->max_fp_id); } + det_ctx->non_mpm_id_array = SCCalloc(32000, sizeof(SigIntId)); // TODO proper size or dynamicly grow + BUG_ON(det_ctx->non_mpm_id_array == NULL); + /* IP-ONLY */ DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx); @@ -1379,9 +1382,6 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) det_ctx->tv = tv; det_ctx->de_ctx = de_ctx; - det_ctx->non_mpm_id_array = SCCalloc(32000, sizeof(SigIntId)); // TODO proper size or dynamicly grow - BUG_ON(det_ctx->non_mpm_id_array == NULL); - if (ThreadCtxDoInit(de_ctx, det_ctx) != TM_ECODE_OK) return TM_ECODE_FAILED; From a8c16405fbba9744a3cfdd094617bb29d82d944b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Jan 2015 11:54:38 +0100 Subject: [PATCH 0196/2553] detect: properly size det_ctx::non_mpm_id_array Track which sgh has the higest non-mpm sig count and use that value to size the det_ctx::non_mpm_id_array array. --- src/detect-engine-siggroup.c | 9 ++++++++- src/detect-engine.c | 8 ++++++-- src/detect.h | 8 ++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 08c298159c0a..a7ecbafd9abd 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -1689,7 +1689,9 @@ void SigGroupHeadSetFilestoreCount(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return; } -/* build an array of rule id's for sigs with no mpm */ +/** \brief build an array of rule id's for sigs with no mpm + * Also updated de_ctx::non_mpm_store_cnt_max to track the highest cnt + */ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; @@ -1738,6 +1740,11 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) sgh->non_mpm_store_cnt++; } } + + /* track highest cnt for any sgh in our de_ctx */ + if (sgh->non_mpm_store_cnt > de_ctx->non_mpm_store_cnt_max) + de_ctx->non_mpm_store_cnt_max = sgh->non_mpm_store_cnt; + return 0; } diff --git a/src/detect-engine.c b/src/detect-engine.c index 211d330f56ed..cf43590fc48b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1290,8 +1290,12 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * PmqSetup(&det_ctx->smsg_pmq[i], de_ctx->max_fp_id); } - det_ctx->non_mpm_id_array = SCCalloc(32000, sizeof(SigIntId)); // TODO proper size or dynamicly grow - BUG_ON(det_ctx->non_mpm_id_array == NULL); + /* sized to the max of our sgh settings. A max setting of 0 implies that all + * sgh's have: sgh->non_mpm_store_cnt == 0 */ + if (de_ctx->non_mpm_store_cnt_max > 0) { + det_ctx->non_mpm_id_array = SCCalloc(de_ctx->non_mpm_store_cnt_max, sizeof(SigIntId)); + BUG_ON(det_ctx->non_mpm_id_array == NULL); + } /* IP-ONLY */ DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx); diff --git a/src/detect.h b/src/detect.h index 5ff05bf95479..4a7ce480fc3b 100644 --- a/src/detect.h +++ b/src/detect.h @@ -587,6 +587,10 @@ typedef struct DetectEngineCtx_ { 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_mpm_store_cnt_max; + /* used by the signature ordering module */ struct SCSigOrderFunc_ *sc_sig_order_funcs; @@ -977,8 +981,8 @@ typedef struct SigGroupHead_ { SignatureMask *mask_array; #endif - SignatureNonMpmStore *non_mpm_store_array; - uint32_t non_mpm_store_cnt; // size is cnt * sizeof(SignatureNonMpmStore) + SignatureNonMpmStore *non_mpm_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) + uint32_t non_mpm_store_cnt; /* pattern matcher instances */ MpmCtx *mpm_proto_other_ctx; From a3de4ecd9786430fe61462ec4f8f6cfd64304785 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Jan 2015 13:38:44 +0100 Subject: [PATCH 0197/2553] Suppress debug statements --- src/output-json.c | 2 +- src/util-profiling-keywords.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index 69ea7cf19141..aec2f67c4e73 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -523,7 +523,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) json_out = json_ctx->json_out; } - SCLogInfo("returning output_ctx %p", output_ctx); + SCLogDebug("returning output_ctx %p", output_ctx); return output_ctx; } diff --git a/src/util-profiling-keywords.c b/src/util-profiling-keywords.c index 84073735eab8..9f3019aa5d4f 100644 --- a/src/util-profiling-keywords.c +++ b/src/util-profiling-keywords.c @@ -167,7 +167,7 @@ SCProfilingKeywordDump(DetectEngineCtx *de_ctx) tms = SCLocalTime(tval.tv_sec, &local_tm); if (profiling_keywords_output_to_file == 1) { - SCLogInfo("file %s mode %s", profiling_file_name, profiling_file_mode); + SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode); fp = fopen(profiling_file_name, profiling_file_mode); From ddce14360d15c2978bd875c4cbb4421dc605bbde Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Jan 2015 22:00:28 +0100 Subject: [PATCH 0198/2553] Cosmetic fixes to main() --- src/suricata.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 14bd1a6c93e6..9b46eb022582 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2220,10 +2220,10 @@ int main(int argc, char **argv) } if (MayDaemonize(&suri) != TM_ECODE_OK) - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); if (InitSignalHandler(&suri) != TM_ECODE_OK) - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); #ifdef HAVE_NSS /* init NSS for md5 */ @@ -2266,7 +2266,6 @@ int main(int argc, char **argv) if (MagicInit() != 0) exit(EXIT_FAILURE); - if (de_ctx != NULL) { SetupDelayedDetect(de_ctx, &suri); @@ -2293,7 +2292,7 @@ int main(int argc, char **argv) } if (ParseInterfacesList(suri.run_mode, suri.pcap_dev) != TM_ECODE_OK) { - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } if(suri.run_mode == RUNMODE_CONF_TEST){ From 844065bf5853fff4700042032cd45eae8f1eb003 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 13 Jan 2015 10:46:56 +0100 Subject: [PATCH 0199/2553] conf api: use const pointers where possible Use const pointers where possible in the Conf API. --- src/conf.c | 44 ++++++++++++++++++++++---------------------- src/conf.h | 40 ++++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/conf.c b/src/conf.c index cabde9e36fb9..c42ff4957542 100644 --- a/src/conf.c +++ b/src/conf.c @@ -62,7 +62,7 @@ static ConfNode *root_backup = NULL; * created node for the provided name. On error, NULL will be returned. */ static ConfNode * -ConfGetNodeOrCreate(char *name, int final) +ConfGetNodeOrCreate(const char *name, int final) { ConfNode *parent = root; ConfNode *node = NULL; @@ -178,7 +178,7 @@ ConfNodeFree(ConfNode *node) * node does not exist. */ ConfNode * -ConfGetNode(char *name) +ConfGetNode(const char *name) { ConfNode *node = root; char node_name[NODE_NAME_MAX]; @@ -224,7 +224,7 @@ ConfGetRootNode(void) * \retval 1 if the value was set otherwise 0. */ int -ConfSet(char *name, char *val) +ConfSet(const char *name, char *val) { ConfNode *node = ConfGetNodeOrCreate(name, 0); if (node == NULL || node->final) { @@ -254,7 +254,7 @@ ConfSet(char *name, char *val) * \retval 1 if the value was set otherwise 0. */ int -ConfSetFinal(char *name, char *val) +ConfSetFinal(const char *name, char *val) { ConfNode *node = ConfGetNodeOrCreate(name, 1); if (node == NULL) { @@ -287,7 +287,7 @@ ConfSetFinal(char *name, char *val) * be returned. */ int -ConfGet(char *name, char **vptr) +ConfGet(const char *name, char **vptr) { ConfNode *node = ConfGetNode(name); if (node == NULL) { @@ -300,7 +300,7 @@ ConfGet(char *name, char **vptr) } } -int ConfGetChildValue(ConfNode *base, char *name, char **vptr) +int ConfGetChildValue(const ConfNode *base, const char *name, char **vptr) { ConfNode *node = ConfNodeLookupChild(base, name); @@ -315,7 +315,7 @@ int ConfGetChildValue(ConfNode *base, char *name, char **vptr) } -int ConfGetChildValueWithDefault(ConfNode *base, ConfNode *dflt, char *name, char **vptr) +int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, char **vptr) { int ret = ConfGetChildValue(base, name, vptr); /* Get 'default' value */ @@ -336,7 +336,7 @@ int ConfGetChildValueWithDefault(ConfNode *base, ConfNode *dflt, char *name, cha * converted to an interger, otherwise 0 will be returned. */ int -ConfGetInt(char *name, intmax_t *val) +ConfGetInt(const char *name, intmax_t *val) { char *strval; intmax_t tmpint; @@ -356,7 +356,7 @@ ConfGetInt(char *name, intmax_t *val) return 1; } -int ConfGetChildValueInt(ConfNode *base, char *name, intmax_t *val) +int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val) { char *strval; intmax_t tmpint; @@ -376,7 +376,7 @@ int ConfGetChildValueInt(ConfNode *base, char *name, intmax_t *val) } -int ConfGetChildValueIntWithDefault(ConfNode *base, ConfNode *dflt, char *name, intmax_t *val) +int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val) { int ret = ConfGetChildValueInt(base, name, val); /* Get 'default' value */ @@ -398,7 +398,7 @@ int ConfGetChildValueIntWithDefault(ConfNode *base, ConfNode *dflt, char *name, * converted to a boolean, otherwise 0 will be returned. */ int -ConfGetBool(char *name, int *val) +ConfGetBool(const char *name, int *val) { char *strval; @@ -411,7 +411,7 @@ ConfGetBool(char *name, int *val) return 1; } -int ConfGetChildValueBool(ConfNode *base, char *name, int *val) +int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val) { char *strval; @@ -424,7 +424,7 @@ int ConfGetChildValueBool(ConfNode *base, char *name, int *val) return 1; } -int ConfGetChildValueBoolWithDefault(ConfNode *base, ConfNode *dflt, char *name, int *val) +int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val) { int ret = ConfGetChildValueBool(base, name, val); /* Get 'default' value */ @@ -498,7 +498,7 @@ ConfValIsFalse(const char *val) * converted to a double, otherwise 0 will be returned. */ int -ConfGetDouble(char *name, double *val) +ConfGetDouble(const char *name, double *val) { char *strval; double tmpdo; @@ -529,7 +529,7 @@ ConfGetDouble(char *name, double *val) * converted to a double, otherwise 0 will be returned. */ int -ConfGetFloat(char *name, float *val) +ConfGetFloat(const char *name, float *val) { char *strval; double tmpfl; @@ -569,7 +569,7 @@ ConfNodeRemove(ConfNode *node) * most likely indicating the parameter was not set. */ int -ConfRemove(char *name) +ConfRemove(const char *name) { ConfNode *node; @@ -641,7 +641,7 @@ ConfPrintNameArray(char **name_arr, int level) * \brief Dump a configuration node and all its children. */ void -ConfNodeDump(ConfNode *node, const char *prefix) +ConfNodeDump(const ConfNode *node, const char *prefix) { ConfNode *child; @@ -689,7 +689,7 @@ ConfDump(void) * \retval A pointer the child ConfNode if found otherwise NULL. */ ConfNode * -ConfNodeLookupChild(ConfNode *node, const char *name) +ConfNodeLookupChild(const ConfNode *node, const char *name) { ConfNode *child; @@ -714,7 +714,7 @@ ConfNodeLookupChild(ConfNode *node, const char *name) * \retval A pointer the child ConfNodes value if found otherwise NULL. */ const char * -ConfNodeLookupChildValue(ConfNode *node, const char *name) +ConfNodeLookupChildValue(const ConfNode *node, const char *name) { ConfNode *child; @@ -731,7 +731,7 @@ ConfNodeLookupChildValue(ConfNode *node, const char *name) * \return the ConfNode matching or NULL */ -ConfNode *ConfNodeLookupKeyValue(ConfNode *base, const char *key, const char *value) +ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const char *value) { ConfNode *child; @@ -759,7 +759,7 @@ ConfNode *ConfNodeLookupKeyValue(ConfNode *base, const char *key, const char *va * returned, even if the child node does not exist. */ int -ConfNodeChildValueIsTrue(ConfNode *node, const char *key) +ConfNodeChildValueIsTrue(const ConfNode *node, const char *key) { const char *val; @@ -773,7 +773,7 @@ ConfNodeChildValueIsTrue(ConfNode *node, const char *key) * \param file The name of the file * \retval str Pointer to the string path + sig_file */ -char *ConfLoadCompleteIncludePath(char *file) +char *ConfLoadCompleteIncludePath(const char *file) { char *defaultpath = NULL; char *path = NULL; diff --git a/src/conf.h b/src/conf.h index c819eb049361..6bc7414e6aad 100644 --- a/src/conf.h +++ b/src/conf.h @@ -56,36 +56,36 @@ typedef struct ConfNode_ { void ConfInit(void); void ConfDeInit(void); ConfNode *ConfGetRootNode(void); -int ConfGet(char *name, char **vptr); -int ConfGetInt(char *name, intmax_t *val); -int ConfGetBool(char *name, int *val); -int ConfGetDouble(char *name, double *val); -int ConfGetFloat(char *name, float *val); -int ConfSet(char *name, char *val); -int ConfSetFinal(char *name, char *val); +int ConfGet(const char *name, char **vptr); +int ConfGetInt(const char *name, intmax_t *val); +int ConfGetBool(const char *name, int *val); +int ConfGetDouble(const char *name, double *val); +int ConfGetFloat(const char *name, float *val); +int ConfSet(const char *name, char *val); +int ConfSetFinal(const char *name, char *val); void ConfDump(void); -void ConfNodeDump(ConfNode *node, const char *prefix); +void ConfNodeDump(const ConfNode *node, const char *prefix); ConfNode *ConfNodeNew(void); void ConfNodeFree(ConfNode *); -ConfNode *ConfGetNode(char *key); +ConfNode *ConfGetNode(const char *key); void ConfCreateContextBackup(void); void ConfRestoreContextBackup(void); -ConfNode *ConfNodeLookupChild(ConfNode *node, const char *key); -const char *ConfNodeLookupChildValue(ConfNode *node, const char *key); +ConfNode *ConfNodeLookupChild(const ConfNode *node, const char *key); +const char *ConfNodeLookupChildValue(const ConfNode *node, const char *key); void ConfNodeRemove(ConfNode *); void ConfRegisterTests(); -int ConfNodeChildValueIsTrue(ConfNode *node, const char *key); +int ConfNodeChildValueIsTrue(const ConfNode *node, const char *key); int ConfValIsTrue(const char *val); int ConfValIsFalse(const char *val); void ConfNodePrune(ConfNode *node); -ConfNode *ConfNodeLookupKeyValue(ConfNode *base, const char *key, const char *value); -int ConfGetChildValue(ConfNode *base, char *name, char **vptr); -int ConfGetChildValueInt(ConfNode *base, char *name, intmax_t *val); -int ConfGetChildValueBool(ConfNode *base, char *name, int *val); -int ConfGetChildValueWithDefault(ConfNode *base, ConfNode *dflt, char *name, char **vptr); -int ConfGetChildValueIntWithDefault(ConfNode *base, ConfNode *dflt, char *name, intmax_t *val); -int ConfGetChildValueBoolWithDefault(ConfNode *base, ConfNode *dflt, char *name, int *val); -char *ConfLoadCompleteIncludePath(char *); +ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const char *value); +int ConfGetChildValue(const ConfNode *base, const char *name, char **vptr); +int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val); +int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val); +int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, char **vptr); +int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val); +int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val); +char *ConfLoadCompleteIncludePath(const char *); #endif /* ! __CONF_H__ */ From 04e49cea892c012a1238a17a8f80ed66a17228ba Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 18 Jan 2015 10:54:57 +0100 Subject: [PATCH 0200/2553] Fix live reload detect counter setup When profiling was compiled in the detect counters were not setup properly after a reload. --- src/detect-engine.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index cf43590fc48b..73d5e3e9918a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1433,6 +1433,20 @@ static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *tv, void *in /** alert counter setup */ det_ctx->counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, SC_PERF_TYPE_UINT64, "NULL"); +#ifdef PROFILING + uint16_t counter_mpm_list = SCPerfTVRegisterAvgCounter("detect.mpm_list", tv, + SC_PERF_TYPE_UINT64, "NULL"); + uint16_t counter_nonmpm_list = SCPerfTVRegisterAvgCounter("detect.nonmpm_list", tv, + SC_PERF_TYPE_UINT64, "NULL"); + uint16_t counter_fnonmpm_list = SCPerfTVRegisterAvgCounter("detect.fnonmpm_list", tv, + SC_PERF_TYPE_UINT64, "NULL"); + uint16_t counter_match_list = SCPerfTVRegisterAvgCounter("detect.match_list", tv, + SC_PERF_TYPE_UINT64, "NULL"); + det_ctx->counter_mpm_list = counter_mpm_list; + det_ctx->counter_nonmpm_list = counter_nonmpm_list; + det_ctx->counter_fnonmpm_list = counter_fnonmpm_list; + det_ctx->counter_match_list = counter_match_list; +#endif /* no counter creation here */ /* pass thread data back to caller */ From 5a8094136ce667b66bea7484f306d6423fea96b8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Jan 2015 11:31:15 +0100 Subject: [PATCH 0201/2553] Clean up Conf API memory on shutdown. --- src/suricata.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/suricata.c b/src/suricata.c index 9b46eb022582..b71d540f3e3d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2512,6 +2512,7 @@ int main(int argc, char **argv) MpmCudaBufferDeSetup(); CudaHandlerFreeProfiles(); #endif + ConfDeInit(); exit(engine_retval); } From 5b6f8bda1d86df611ddba3b9180963a1a12e513d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Jan 2015 11:43:58 +0100 Subject: [PATCH 0202/2553] detect: fix small memory leaks Fix small memory leaks in option parsing. Move away from pcre_get_substring in favor of pcre_copy_substring. Related to #1046. --- src/detect-dce-iface.c | 34 ++++++++++++++-------------------- src/detect-engine-event.c | 14 ++++++++------ src/detect-fast-pattern.c | 10 +++++----- src/detect-id.c | 34 +++++++++++++--------------------- src/detect-priority.c | 12 +++++------- src/detect-window.c | 36 +++++++++++++----------------------- 6 files changed, 58 insertions(+), 82 deletions(-) diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 029cebdfb63f..60da43ed05a6 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -113,10 +113,10 @@ static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; uint8_t hex_value; - const char *pcre_sub_str = NULL; + char copy_str[128] = ""; int i = 0, j = 0; int len = 0; - char temp_str[3]; + char temp_str[3] = ""; int version; ret = pcre_exec(parse_regex, parse_regex_study, arg, strlen(arg), 0, 0, ov, @@ -131,24 +131,24 @@ static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) memset(did, 0, sizeof(DetectDceIfaceData)); /* retrieve the iface uuid string. iface uuid is a compulsion in the keyword */ - res = pcre_get_substring(arg, ov, MAX_SUBSTRINGS, 1, &pcre_sub_str); + res = pcre_copy_substring(arg, ov, MAX_SUBSTRINGS, 1, copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } /* parse the iface uuid string */ - len = strlen(pcre_sub_str); + len = strlen(copy_str); j = 0; temp_str[2] = '\0'; for (i = 0; i < len; ) { - if (pcre_sub_str[i] == '-') { + if (copy_str[i] == '-') { i++; continue; } - temp_str[0] = pcre_sub_str[i]; - temp_str[1] = pcre_sub_str[i + 1]; + temp_str[0] = copy_str[i]; + temp_str[1] = copy_str[i + 1]; hex_value = strtol(temp_str, NULL, 16); did->uuid[j] = hex_value; @@ -164,13 +164,13 @@ static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) if (ret == 4 || ret == 5) { /* first handle the version number, so that we can do some additional * validations of the version number, wrt. the operator */ - res = pcre_get_substring(arg, ov, MAX_SUBSTRINGS, 3, &pcre_sub_str); + res = pcre_copy_substring(arg, ov, MAX_SUBSTRINGS, 3, copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - version = atoi(pcre_sub_str); + version = atoi(copy_str); if (version > UINT16_MAX) { SCLogError(SC_ERR_INVALID_SIGNATURE, "DCE_IFACE interface version " "invalid: %d\n", version); @@ -178,17 +178,14 @@ static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) } did->version = version; - /* free the substring */ - pcre_free_substring(pcre_sub_str); - /* now let us handle the operator supplied with the version number */ - res = pcre_get_substring(arg, ov, MAX_SUBSTRINGS, 2, &pcre_sub_str); + res = pcre_copy_substring(arg, ov, MAX_SUBSTRINGS, 2, copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - switch (pcre_sub_str[0]) { + switch (copy_str[0]) { case '<': if (version == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "DCE_IFACE interface " @@ -217,9 +214,6 @@ static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) did->op = DETECT_DCE_IFACE_OP_NE; break; } - - /* free the substring */ - pcre_free_substring(pcre_sub_str); } return did; diff --git a/src/detect-engine-event.c b/src/detect-engine-event.c index 737b5478998d..6b685d70543e 100644 --- a/src/detect-engine-event.c +++ b/src/detect-engine-event.c @@ -151,16 +151,17 @@ DetectEngineEventData *DetectEngineEventParse (char *rawstr) goto error; } - const char *str_ptr; - res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 0, &str_ptr); + char copy_str[128] = ""; + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 0, + copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } for (i = 0; DEvents[i].event_name != NULL; i++) { - if (strcasecmp(DEvents[i].event_name,str_ptr) == 0) { + if (strcasecmp(DEvents[i].event_name,copy_str) == 0) { found = 1; break; } @@ -168,7 +169,7 @@ DetectEngineEventData *DetectEngineEventParse (char *rawstr) if (found == 0) { SCLogError(SC_ERR_UNKNOWN_DECODE_EVENT, "unknown decode event \"%s\"", - str_ptr); + copy_str); goto error; } @@ -184,7 +185,8 @@ DetectEngineEventData *DetectEngineEventParse (char *rawstr) return de; error: - if (de) SCFree(de); + if (de) + SCFree(de); return NULL; } diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index db721562d5f0..90b0316ad23f 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -208,7 +208,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; - const char *arg_substr = NULL; + char arg_substr[128] = ""; DetectContentData *cd = NULL; if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL && @@ -320,8 +320,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a /* fast pattern chop */ } else if (ret == 4) { - res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, - 2, &arg_substr); + res = pcre_copy_substring((char *)arg, ov, MAX_SUBSTRINGS, + 2, arg_substr, sizeof(arg_substr)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for fast_pattern offset"); @@ -334,8 +334,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a goto error; } - res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, - 3, &arg_substr); + res = pcre_copy_substring((char *)arg, ov, MAX_SUBSTRINGS, + 3, arg_substr, sizeof(arg_substr)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for fast_pattern offset"); diff --git a/src/detect-id.c b/src/detect-id.c index bb084d2c7671..5df2a6d1823e 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -139,7 +139,6 @@ DetectIdData *DetectIdParse (char *idstr) int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; - ret = pcre_exec(parse_regex, parse_regex_study, idstr, strlen(idstr), 0, 0, ov, MAX_SUBSTRINGS); @@ -152,26 +151,16 @@ DetectIdData *DetectIdParse (char *idstr) if (ret > 1) { - const char *str_ptr; - char *orig; + char copy_str[128] = ""; char *tmp_str; - res = pcre_get_substring((char *)idstr, ov, MAX_SUBSTRINGS, 1, - &str_ptr); + res = pcre_copy_substring((char *)idstr, ov, MAX_SUBSTRINGS, 1, + copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - /* We have a correct id option */ - id_d = SCMalloc(sizeof(DetectIdData)); - if (unlikely(id_d == NULL)) - goto error; - - orig = SCStrdup((char*)str_ptr); - if (unlikely(orig == NULL)) { - goto error; - } - tmp_str=orig; + tmp_str = copy_str; /* Let's see if we need to scape "'s */ if (tmp_str[0] == '"') @@ -187,13 +176,15 @@ DetectIdData *DetectIdParse (char *idstr) SCLogError(SC_ERR_INVALID_VALUE, "\"id\" option must be in " "the range %u - %u", DETECT_IPID_MIN, DETECT_IPID_MAX); - - SCFree(orig); goto error; } - id_d->id = temp; - SCFree(orig); + /* We have a correct id option */ + id_d = SCMalloc(sizeof(DetectIdData)); + if (unlikely(id_d == NULL)) + goto error; + + id_d->id = temp; SCLogDebug("detect-id: will look for ip_id: %u\n", id_d->id); } @@ -201,7 +192,8 @@ DetectIdData *DetectIdParse (char *idstr) return id_d; error: - if (id_d != NULL) DetectIdFree(id_d); + if (id_d != NULL) + DetectIdFree(id_d); return NULL; } diff --git a/src/detect-priority.c b/src/detect-priority.c index 6db84b28b949..5bb0359f85ca 100644 --- a/src/detect-priority.c +++ b/src/detect-priority.c @@ -77,7 +77,7 @@ void DetectPriorityRegister (void) static int DetectPrioritySetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { - const char *prio_str = NULL; + char copy_str[128] = ""; #define MAX_SUBSTRINGS 30 int ret = 0; @@ -90,26 +90,24 @@ static int DetectPrioritySetup (DetectEngineCtx *de_ctx, Signature *s, char *raw return -1; } - ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &prio_str); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 1, copy_str, sizeof(copy_str)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); return -1; } long prio = 0; char *endptr = NULL; - prio = strtol(rawstr, &endptr, 10); + prio = strtol(copy_str, &endptr, 10); if (endptr == NULL || *endptr != '\0') { SCLogError(SC_ERR_INVALID_SIGNATURE, "Saw an invalid character as arg " "to priority keyword"); - goto error; + return -1; } /* if we have reached here, we have had a valid priority. Assign it */ s->prio = prio; return 0; - error: - return -1; } /*------------------------------Unittests-------------------------------------*/ diff --git a/src/detect-window.c b/src/detect-window.c index e770f71b1be2..0fb1afb86501 100644 --- a/src/detect-window.c +++ b/src/detect-window.c @@ -130,15 +130,11 @@ int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, DetectWindowData *DetectWindowParse(char *windowstr) { DetectWindowData *wd = NULL; - char *args[3] = {NULL,NULL,NULL}; /* PR: Why PCRE MAX_SUBSTRING must be multiple of 3? */ - #define MAX_SUBSTRINGS 30 - +#define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; - ret = pcre_exec(parse_regex, parse_regex_study, windowstr, strlen(windowstr), 0, 0, ov, MAX_SUBSTRINGS); - if (ret < 1 || ret > 3) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, windowstr); goto error; @@ -149,45 +145,39 @@ DetectWindowData *DetectWindowParse(char *windowstr) goto error; if (ret > 1) { - const char *str_ptr; - res = pcre_get_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); + char copy_str[128] = ""; + res = pcre_copy_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 1, + copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - args[0] = (char *)str_ptr; + /* Detect if it's negated */ - if (args[0][0] == '!') + if (copy_str[0] == '!') wd->negated = 1; else wd->negated = 0; if (ret > 2) { - res = pcre_get_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); + res = pcre_copy_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 2, + copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - /* Get the window size if it's a valid value (in packets, we should alert if this doesn't happend from decode) */ - if (-1 == ByteExtractStringUint16(&wd->size, 10, 0, str_ptr)) { + /* Get the window size if it's a valid value (in packets, we + * should alert if this doesn't happend from decode) */ + if (-1 == ByteExtractStringUint16(&wd->size, 10, 0, copy_str)) { goto error; } } } - int i = 0; - for (i = 0; i < (ret -1); i++){ - if (args[i] != NULL) - SCFree(args[i]); - } return wd; error: - for (i = 0; i < (ret -1) && i < 3; i++){ - if (args[i] != NULL) - SCFree(args[i]); - } if (wd != NULL) DetectWindowFree(wd); return NULL; From a5641bc7c225d447d21a65927b4077f095d7dca2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 29 Jan 2015 16:51:54 +0100 Subject: [PATCH 0203/2553] Update changelog for 2.1beta3 --- ChangeLog | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ChangeLog b/ChangeLog index 720e846fdd7d..9e57c6298ca6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2.1beta3 -- 2015-01-29 + +Bug #977: WARNING on empty rules file is fatal (should not be) +Bug #1184: pfring: cppcheck warnings +Bug #1321: Flow memuse bookkeeping error +Bug #1327: pcre pkt/flowvar capture broken for non-relative matches (master) +Bug #1332: cppcheck: ioctl +Bug #1336: modbus: CID 1257762: Logically dead code (DEADCODE) +Bug #1351: output-json: duplicate logging (2.1.x) +Bug #1354: coredumps on quitting on OpenBSD +Bug #1355: Bus error when reading pcap-file on OpenBSD +Bug #1363: Suricata does not compile on OS X/Clang due to redefinition of string functions (2.1.x) +Bug #1365: evasion issues (2.1.x) +Feature #1261: Request for Additional Lua Capabilities +Feature #1309: Lua support for Stats output +Feature #1310: Modbus parsing and matching +Feature #1317: Lua: Indicator for end of flow +Feature #1333: unix-socket: allow (easier) non-root usage +Optimization #1339: flow timeout optimization +Optimization #1339: flow timeout optimization +Optimization #1371: mpm optimization + 2.1beta2 -- 2014-11-06 Feature #549: Extract file attachments from emails From e494336453c16c00f1026da63685ffdc2b9f567f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 12:56:55 +0100 Subject: [PATCH 0204/2553] stream: move reassembly loop into util funcs Move IDS per segment reassembly and gap handling into utility functions. --- src/stream-tcp-reassemble.c | 467 +++++++++++++++++++----------------- 1 file changed, 248 insertions(+), 219 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 2905726cc586..f42f1fa8be20 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2846,6 +2846,237 @@ static void GetSessionSize(TcpSession *ssn, Packet *p) } #endif +typedef struct ReassembleData_ { + uint32_t ra_base_seq; + uint32_t data_len; + uint8_t data[4096]; + int partial; /* last segment was processed only partially */ +} ReassembleData; + +int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, + TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd, + Packet *p, uint8_t flags, uint32_t next_seq) +{ + if (unlikely(SEQ_GT(seg->seq, next_seq))) { + /* we've run into a sequence gap */ + + /* first, pass on data before the gap */ + if (rd->data_len > 0) { + SCLogDebug("pre GAP data"); + + STREAM_SET_FLAGS(ssn, stream, p, flags); + + /* process what we have so far */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + rd->data, rd->data_len, flags); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_len = 0; + } + +#ifdef DEBUG + uint32_t gap_len = seg->seq - next_seq; + SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " + "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", + next_seq, seg->seq, stream->last_ack, gap_len); +#endif + /* We have missed the packet and end host has ack'd it, so + * IDS should advance it's ra_base_seq and should not consider this + * packet any longer, even if it is retransmitted, as end host will + * drop it anyway */ + rd->ra_base_seq = seg->seq - 1; + + /* send gap "signal" */ + STREAM_SET_FLAGS(ssn, stream, p, flags); + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + NULL, 0, flags|STREAM_GAP); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + + /* set a GAP flag and make sure not bothering this stream anymore */ + SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); + stream->flags |= STREAMTCP_STREAM_FLAG_GAP; + + StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); + SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); +#ifdef DEBUG + dbg_app_layer_gap++; +#endif + return 1; + } + return 0; +} + +static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, + TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd, + Packet *p, uint8_t flags) +{ + uint16_t payload_offset = 0; + uint16_t payload_len = 0; + + /* start clean */ + rd->partial = FALSE; + + /* if the segment ends beyond ra_base_seq we need to consider it */ + if (SEQ_GT((seg->seq + seg->payload_len), rd->ra_base_seq+1)) { + SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " + "ra_base_seq %" PRIu32 ", last_ack %"PRIu32, seg->seq, + seg->payload_len, rd->ra_base_seq, stream->last_ack); + + /* handle segments partly before ra_base_seq */ + if (SEQ_GT(rd->ra_base_seq, seg->seq)) { + payload_offset = (rd->ra_base_seq + 1) - seg->seq; + SCLogDebug("payload_offset %u", payload_offset); + + if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { + if (SEQ_LT(stream->last_ack, (rd->ra_base_seq + 1))) { + payload_len = (stream->last_ack - seg->seq); + SCLogDebug("payload_len %u", payload_len); + } else { + payload_len = (stream->last_ack - seg->seq) - payload_offset; + SCLogDebug("payload_len %u", payload_len); + } + rd->partial = TRUE; + } else { + payload_len = seg->payload_len - payload_offset; + SCLogDebug("payload_len %u", payload_len); + } + + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + BUG_ON((payload_len + payload_offset) > seg->payload_len); + } + } else { + payload_offset = 0; + + if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { + payload_len = stream->last_ack - seg->seq; + SCLogDebug("payload_len %u", payload_len); + + rd->partial = TRUE; + } else { + payload_len = seg->payload_len; + SCLogDebug("payload_len %u", payload_len); + } + } + SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" + " and stream->last_ack is %"PRIu32"", payload_offset, + payload_len, stream->last_ack); + + if (payload_len == 0) { + SCLogDebug("no payload_len, so bail out"); + return 0; + } + + /* copy the data into the smsg */ + uint16_t copy_size = sizeof(rd->data) - rd->data_len; + if (copy_size > payload_len) { + copy_size = payload_len; + } + if (SCLogDebugEnabled()) { + BUG_ON(copy_size > sizeof(rd->data)); + } + SCLogDebug("copy_size is %"PRIu16"", copy_size); + memcpy(rd->data + rd->data_len, seg->payload + payload_offset, copy_size); + rd->data_len += copy_size; + rd->ra_base_seq += copy_size; + SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, rd->ra_base_seq, rd->data_len); + + /* queue the smsg if it's full */ + if (rd->data_len == sizeof(rd->data)) { + /* process what we have so far */ + STREAM_SET_FLAGS(ssn, stream, p, flags); +// BUG_ON(rd->data_len > sizeof(rd->data)); + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + rd->data, rd->data_len, flags); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_len = 0; + + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + } + + /* if the payload len is bigger than what we copied, we handle the + * rest of the payload next... */ + if (copy_size < payload_len) { + SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, + payload_len); + + payload_offset += copy_size; + payload_len -= copy_size; + SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " + "%"PRIu16" and stream->last_ack is %"PRIu32"", + payload_offset, seg->payload_len, stream->last_ack); + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + } + + /* we need a while loop here as the packets theoretically can be + * 64k */ + char segment_done = FALSE; + while (segment_done == FALSE) { + SCLogDebug("new msg at offset %" PRIu32 ", payload_len " + "%" PRIu32 "", payload_offset, payload_len); + rd->data_len = 0; + + copy_size = sizeof(rd->data) - rd->data_len; + if (copy_size > (seg->payload_len - payload_offset)) { + copy_size = (seg->payload_len - payload_offset); + } + if (SCLogDebugEnabled()) { + BUG_ON(copy_size > sizeof(rd->data)); + } + + SCLogDebug("copy payload_offset %" PRIu32 ", data_len " + "%" PRIu32 ", copy_size %" PRIu32 "", + payload_offset, rd->data_len, copy_size); + memcpy(rd->data + rd->data_len, seg->payload + + payload_offset, copy_size); + rd->data_len += copy_size; + rd->ra_base_seq += copy_size; + SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq); + SCLogDebug("copied payload_offset %" PRIu32 ", " + "data_len %" PRIu32 ", copy_size %" PRIu32 "", + payload_offset, rd->data_len, copy_size); + + if (rd->data_len == sizeof(rd->data)) { + /* process what we have so far */ + STREAM_SET_FLAGS(ssn, stream, p, flags); +// BUG_ON(rd->data_len > sizeof(rd->data)); + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + rd->data, rd->data_len, flags); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_len = 0; + + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + } + + /* see if we have segment payload left to process */ + if ((copy_size + payload_offset) < seg->payload_len) { + payload_offset += copy_size; + payload_len -= copy_size; + + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + } + } else { + payload_offset = 0; + segment_done = TRUE; + } + } + } + } + + return 1; +} + /** * \brief Update the stream reassembly upon receiving an ACK packet. * @@ -2915,15 +3146,14 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, /* stream->ra_app_base_seq remains at stream->isn until protocol is * detected. */ - uint32_t ra_base_seq = stream->ra_app_base_seq; - uint8_t data[4096]; - uint32_t data_len = 0; - uint16_t payload_offset = 0; - uint16_t payload_len = 0; - uint32_t next_seq = ra_base_seq + 1; + ReassembleData rd; + rd.ra_base_seq = stream->ra_app_base_seq; + rd.data_len = 0; + rd.partial = FALSE; + uint32_t next_seq = rd.ra_base_seq + 1; SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32, - ra_base_seq, stream->last_ack, next_seq); + rd.ra_base_seq, stream->last_ack, next_seq); /* loop through the segments and fill one or more msgs */ TcpSegment *seg = stream->seg_list; @@ -2979,219 +3209,18 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, continue; } - /* we've run into a sequence gap */ - if (SEQ_GT(seg->seq, next_seq)) { - - /* first, pass on data before the gap */ - if (data_len > 0) { - SCLogDebug("pre GAP data"); - - STREAM_SET_FLAGS(ssn, stream, p, flags); - - /* process what we have so far */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_len = 0; - } - - /* see what the length of the gap is, gap length is seg->seq - - * (ra_base_seq +1) */ -#ifdef DEBUG - uint32_t gap_len = seg->seq - next_seq; - SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " - "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", - next_seq, seg->seq, stream->last_ack, gap_len); -#endif - /* We have missed the packet and end host has ack'd it, so - * IDS should advance it's ra_base_seq and should not consider this - * packet any longer, even if it is retransmitted, as end host will - * drop it anyway */ - ra_base_seq = seg->seq - 1; - - /* send gap signal */ - STREAM_SET_FLAGS(ssn, stream, p, flags); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags|STREAM_GAP); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - - /* set a GAP flag and make sure not bothering this stream anymore */ - SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); - stream->flags |= STREAMTCP_STREAM_FLAG_GAP; - - StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); -#ifdef DEBUG - dbg_app_layer_gap++; -#endif + /* check if we have a sequence gap and if so, handle it */ + if (DoHandleGap(tv, ra_ctx, ssn, stream, seg, &rd, p, flags, next_seq) == 1) break; - } - - int partial = FALSE; - - /* if the segment ends beyond ra_base_seq we need to consider it */ - if (SEQ_GT((seg->seq + seg->payload_len), ra_base_seq+1)) { - SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " - "ra_base_seq %" PRIu32 ", last_ack %"PRIu32, seg->seq, - seg->payload_len, ra_base_seq, stream->last_ack); - - /* handle segments partly before ra_base_seq */ - if (SEQ_GT(ra_base_seq, seg->seq)) { - payload_offset = (ra_base_seq + 1) - seg->seq; - SCLogDebug("payload_offset %u", payload_offset); - - if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { - if (SEQ_LT(stream->last_ack, (ra_base_seq + 1))) { - payload_len = (stream->last_ack - seg->seq); - SCLogDebug("payload_len %u", payload_len); - } else { - payload_len = (stream->last_ack - seg->seq) - payload_offset; - SCLogDebug("payload_len %u", payload_len); - } - partial = TRUE; - } else { - payload_len = seg->payload_len - payload_offset; - SCLogDebug("payload_len %u", payload_len); - } - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - BUG_ON((payload_len + payload_offset) > seg->payload_len); - } - } else { - payload_offset = 0; - - if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { - payload_len = stream->last_ack - seg->seq; - SCLogDebug("payload_len %u", payload_len); - - partial = TRUE; - } else { - payload_len = seg->payload_len; - SCLogDebug("payload_len %u", payload_len); - } - } - SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" - " and stream->last_ack is %"PRIu32"", payload_offset, - payload_len, stream->last_ack); - - if (payload_len == 0) { - SCLogDebug("no payload_len, so bail out"); - break; - } - - /* copy the data into the smsg */ - uint16_t copy_size = sizeof(data) - data_len; - if (copy_size > payload_len) { - copy_size = payload_len; - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(data)); - } - SCLogDebug("copy_size is %"PRIu16"", copy_size); - memcpy(data + data_len, seg->payload + payload_offset, copy_size); - data_len += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, ra_base_seq, data_len); - - /* queue the smsg if it's full */ - if (data_len == sizeof(data)) { - /* process what we have so far */ - STREAM_SET_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_len = 0; - - /* if after the first data chunk we have no alproto yet, - * there is no point in continueing here. */ - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - SCLogDebug("no alproto after first data chunk"); - break; - } - } - - /* if the payload len is bigger than what we copied, we handle the - * rest of the payload next... */ - if (copy_size < payload_len) { - SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, - payload_len); - - payload_offset += copy_size; - payload_len -= copy_size; - SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " - "%"PRIu16" and stream->last_ack is %"PRIu32"", - payload_offset, seg->payload_len, stream->last_ack); - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - - /* we need a while loop here as the packets theoretically can be - * 64k */ - char segment_done = FALSE; - while (segment_done == FALSE) { - SCLogDebug("new msg at offset %" PRIu32 ", payload_len " - "%" PRIu32 "", payload_offset, payload_len); - data_len = 0; - - copy_size = sizeof(data) - data_len; - if (copy_size > (seg->payload_len - payload_offset)) { - copy_size = (seg->payload_len - payload_offset); - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(data)); - } - - SCLogDebug("copy payload_offset %" PRIu32 ", data_len " - "%" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, data_len, copy_size); - memcpy(data + data_len, seg->payload + - payload_offset, copy_size); - data_len += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); - SCLogDebug("copied payload_offset %" PRIu32 ", " - "data_len %" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, data_len, copy_size); - - if (data_len == sizeof(data)) { - /* process what we have so far */ - STREAM_SET_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_len = 0; - - /* if after the first data chunk we have no alproto yet, - * there is no point in continueing here. */ - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - SCLogDebug("no alproto after first data chunk"); - break; - } - } - - /* see if we have segment payload left to process */ - if ((copy_size + payload_offset) < seg->payload_len) { - payload_offset += copy_size; - payload_len -= copy_size; - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - } else { - payload_offset = 0; - segment_done = TRUE; - } - } - } - } + /* process this segment */ + if (DoReassemble(tv, ra_ctx, ssn, stream, seg, &rd, p, flags) == 0) + break; /* done with this segment, return it to the pool */ TcpSegment *next_seg = seg->next; next_seq = seg->seq + seg->payload_len; - if (partial == FALSE) { + if (rd.partial == FALSE) { SCLogDebug("fully done with segment in app layer reassembly (seg %p seq %"PRIu32")", seg, seg->seq); seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; @@ -3203,19 +3232,19 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } /* put the partly filled smsg in the queue to the l7 handler */ - if (data_len > 0) { - SCLogDebug("data_len > 0, %u", data_len); + if (rd.data_len > 0) { + SCLogDebug("data_len > 0, %u", rd.data_len); /* process what we have so far */ STREAM_SET_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); + BUG_ON(rd.data_len > sizeof(rd.data)); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); + rd.data, rd.data_len, flags); AppLayerProfilingStore(ra_ctx->app_tctx, p); } /* store ra_base_seq in the stream */ if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - stream->ra_app_base_seq = ra_base_seq; + stream->ra_app_base_seq = rd.ra_base_seq; } else { TcpSegment *tmp_seg = stream->seg_list; while (tmp_seg != NULL) { From ed791a562eddbcd14b31063c6a1519c2453c3a76 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 13:48:00 +0100 Subject: [PATCH 0205/2553] stream: track data sent to app-layer --- src/stream-tcp-reassemble.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index f42f1fa8be20..125ab85211e2 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2851,6 +2851,7 @@ typedef struct ReassembleData_ { uint32_t data_len; uint8_t data[4096]; int partial; /* last segment was processed only partially */ + uint32_t data_sent; /* data passed on this run */ } ReassembleData; int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, @@ -2870,6 +2871,7 @@ int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, rd->data, rd->data_len, flags); AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += rd->data_len; rd->data_len = 0; } @@ -2988,6 +2990,7 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, rd->data, rd->data_len, flags); AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += rd->data_len; rd->data_len = 0; /* if after the first data chunk we have no alproto yet, @@ -3048,6 +3051,7 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, rd->data, rd->data_len, flags); AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += rd->data_len; rd->data_len = 0; /* if after the first data chunk we have no alproto yet, @@ -3149,6 +3153,7 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, ReassembleData rd; rd.ra_base_seq = stream->ra_app_base_seq; rd.data_len = 0; + rd.data_sent = 0; rd.partial = FALSE; uint32_t next_seq = rd.ra_base_seq + 1; From e4cb8715de69b12fbb1605a387b79ff221bf9928 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 14:25:34 +0100 Subject: [PATCH 0206/2553] stream: replace STREAM_SET_INLINE_FLAGS macro Replace it by a generic function StreamGetAppLayerFlags, that can be used both by inline and non-inline. --- src/stream-tcp-reassemble.c | 84 +++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 125ab85211e2..7d2db29b9997 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -1935,25 +1935,40 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre } \ } -#define STREAM_SET_INLINE_FLAGS(ssn, stream, p, flag) { \ - flag = 0; \ - if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {\ - flag |= STREAM_START; \ - } \ - if (ssn->state == TCP_CLOSED) { \ - flag |= STREAM_EOF; \ - } \ - if (p->flags & PKT_PSEUDO_STREAM_END) { \ - flag |= STREAM_EOF; \ - } \ - if ((p)->flowflags & FLOW_PKT_TOSERVER) { \ - flag |= STREAM_TOSERVER; \ - } else { \ - flag |= STREAM_TOCLIENT; \ - } \ - if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { \ - flag |= STREAM_DEPTH; \ - } \ +static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream, + Packet *p) +{ + uint8_t flag = 0; + + if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) { + flag |= STREAM_START; + } + + if (ssn->state == TCP_CLOSED) { + flag |= STREAM_EOF; + } + if (p->flags & PKT_PSEUDO_STREAM_END) { + flag |= STREAM_EOF; + } + + if (StreamTcpInlineMode() == 0) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + flag |= STREAM_TOCLIENT; + } else { + flag |= STREAM_TOSERVER; + } + } else { + if (p->flowflags & FLOW_PKT_TOSERVER) { + flag |= STREAM_TOSERVER; + } else { + flag |= STREAM_TOCLIENT; + } + } + + if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { + flag |= STREAM_DEPTH; + } + return flag; } static void StreamTcpSetupMsg(TcpSession *ssn, TcpStream *stream, Packet *p, @@ -2121,8 +2136,6 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, { SCEnter(); - uint8_t flags = 0; - /* this function can be directly called by app layer protocol * detection. */ if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) { @@ -2145,9 +2158,8 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, if (ssn->state > TCP_ESTABLISHED) { SCLogDebug("sending empty eof message"); /* send EOF to app layer */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags); + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, NULL, 0, + StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); } else { @@ -2182,9 +2194,8 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, if (!(p->flow->flags & FLOW_NO_APPLAYER_INSPECTION)) { if (SEQ_GT(seg->seq, next_seq) && SEQ_LT(seg->seq, stream->last_ack)) { /* send gap signal */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags|STREAM_GAP); + NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); AppLayerProfilingStore(ra_ctx->app_tctx, p); /* set a GAP flag and make sure not bothering this stream anymore */ @@ -2238,11 +2249,9 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, if (data_len > 0) { SCLogDebug("pre GAP data"); - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - /* process what we have so far */ AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); + data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); data_len = 0; } @@ -2262,9 +2271,8 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, ra_base_seq = seg->seq - 1; /* send gap signal */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags|STREAM_GAP); + NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); AppLayerProfilingStore(ra_ctx->app_tctx, p); data_sent += data_len; @@ -2325,10 +2333,8 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, /* queue the smsg if it's full */ if (data_len == sizeof(data)) { /* process what we have so far */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); + data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); data_sent += data_len; data_len = 0; @@ -2379,10 +2385,8 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, if (data_len == sizeof(data)) { /* process what we have so far */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); + data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); data_sent += data_len; data_len = 0; @@ -2415,10 +2419,9 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, if (data_len > 0) { SCLogDebug("data_len > 0, %u", data_len); /* process what we have so far */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); BUG_ON(data_len > sizeof(data)); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); + data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); data_sent += data_len; } @@ -2426,9 +2429,8 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, if (data_sent == 0 && ssn->state > TCP_ESTABLISHED) { SCLogDebug("sending empty eof message"); /* send EOF to app layer */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags); + NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); } From 29d2483efb47108efb26728483e94ea502ac7f8c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 14:26:35 +0100 Subject: [PATCH 0207/2553] stream: update inline tests Make sure inline tests set the stream_inline flag. --- src/stream-tcp-reassemble.c | 10 ++++++++++ src/stream-tcp-util.c | 7 +++++++ src/stream-tcp-util.h | 2 ++ 3 files changed, 19 insertions(+) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 7d2db29b9997..0ab3ce96026e 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -7715,6 +7715,7 @@ static int StreamTcpReassembleInlineTest01(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -7793,6 +7794,7 @@ static int StreamTcpReassembleInlineTest02(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -7904,6 +7906,7 @@ static int StreamTcpReassembleInlineTest03(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8020,6 +8023,7 @@ static int StreamTcpReassembleInlineTest04(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8133,6 +8137,7 @@ static int StreamTcpReassembleInlineTest05(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8227,6 +8232,7 @@ static int StreamTcpReassembleInlineTest06(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8356,6 +8362,7 @@ static int StreamTcpReassembleInlineTest07(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8491,6 +8498,7 @@ static int StreamTcpReassembleInlineTest08(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8624,6 +8632,7 @@ static int StreamTcpReassembleInlineTest09(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8771,6 +8780,7 @@ static int StreamTcpReassembleInlineTest10(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.server, 1); diff --git a/src/stream-tcp-util.c b/src/stream-tcp-util.c index 83cccf4ae2cb..405684fd9451 100644 --- a/src/stream-tcp-util.c +++ b/src/stream-tcp-util.c @@ -40,6 +40,8 @@ /* unittest helper functions */ +extern int stream_inline; + void StreamTcpUTInit(TcpReassemblyThreadCtx **ra_ctx) { StreamTcpInitConfig(TRUE); @@ -50,6 +52,11 @@ void StreamTcpUTDeinit(TcpReassemblyThreadCtx *ra_ctx) { StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); + stream_inline = 0; +} + +void StreamTcpUTInitInline(void) { + stream_inline = 1; } void StreamTcpUTSetupSession(TcpSession *ssn) diff --git a/src/stream-tcp-util.h b/src/stream-tcp-util.h index 32dec5c79d24..72f2b4fcb97f 100644 --- a/src/stream-tcp-util.h +++ b/src/stream-tcp-util.h @@ -29,6 +29,8 @@ void StreamTcpUTInit(TcpReassemblyThreadCtx **); void StreamTcpUTDeinit(TcpReassemblyThreadCtx *); +void StreamTcpUTInitInline(void); + void StreamTcpUTSetupSession(TcpSession *); void StreamTcpUTClearSession(TcpSession *); From e1d134b0275a1fef073cee55b75b43107164a851 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 14:36:05 +0100 Subject: [PATCH 0208/2553] stream: remove STREAM_SET_FLAGS Use the unified StreamGetAppLayerFlags instead. --- src/stream-tcp-reassemble.c | 61 +++++++++++-------------------------- 1 file changed, 17 insertions(+), 44 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 0ab3ce96026e..46855e244273 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -1914,27 +1914,6 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre SCReturnInt(0); } -#define STREAM_SET_FLAGS(ssn, stream, p, flag) { \ - flag = 0; \ - if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {\ - flag |= STREAM_START; \ - } \ - if (ssn->state == TCP_CLOSED) { \ - flag |= STREAM_EOF; \ - } \ - if (p->flags & PKT_PSEUDO_STREAM_END) { \ - flag |= STREAM_EOF; \ - } \ - if ((p)->flowflags & FLOW_PKT_TOSERVER) { \ - flag |= STREAM_TOCLIENT; \ - } else { \ - flag |= STREAM_TOSERVER; \ - } \ - if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { \ - flag |= STREAM_DEPTH; \ - } \ -} - static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream, Packet *p) { @@ -2858,7 +2837,7 @@ typedef struct ReassembleData_ { int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd, - Packet *p, uint8_t flags, uint32_t next_seq) + Packet *p, uint32_t next_seq) { if (unlikely(SEQ_GT(seg->seq, next_seq))) { /* we've run into a sequence gap */ @@ -2867,11 +2846,10 @@ int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (rd->data_len > 0) { SCLogDebug("pre GAP data"); - STREAM_SET_FLAGS(ssn, stream, p, flags); - /* process what we have so far */ AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - rd->data, rd->data_len, flags); + rd->data, rd->data_len, + StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); rd->data_sent += rd->data_len; rd->data_len = 0; @@ -2890,9 +2868,8 @@ int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, rd->ra_base_seq = seg->seq - 1; /* send gap "signal" */ - STREAM_SET_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags|STREAM_GAP); + NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); AppLayerProfilingStore(ra_ctx->app_tctx, p); /* set a GAP flag and make sure not bothering this stream anymore */ @@ -2911,7 +2888,7 @@ int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd, - Packet *p, uint8_t flags) + Packet *p) { uint16_t payload_offset = 0; uint16_t payload_len = 0; @@ -2987,10 +2964,9 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, /* queue the smsg if it's full */ if (rd->data_len == sizeof(rd->data)) { /* process what we have so far */ - STREAM_SET_FLAGS(ssn, stream, p, flags); -// BUG_ON(rd->data_len > sizeof(rd->data)); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - rd->data, rd->data_len, flags); + rd->data, rd->data_len, + StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); rd->data_sent += rd->data_len; rd->data_len = 0; @@ -3048,10 +3024,9 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (rd->data_len == sizeof(rd->data)) { /* process what we have so far */ - STREAM_SET_FLAGS(ssn, stream, p, flags); -// BUG_ON(rd->data_len > sizeof(rd->data)); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - rd->data, rd->data_len, flags); + rd->data, rd->data_len, + StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); rd->data_sent += rd->data_len; rd->data_len = 0; @@ -3111,8 +3086,6 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, SCReturnInt(0); } - uint8_t flags = 0; - SCLogDebug("stream->seg_list %p", stream->seg_list); #ifdef DEBUG PrintList(stream->seg_list); @@ -3130,9 +3103,9 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) { SCLogDebug("sending empty eof message"); /* send EOF to app layer */ - STREAM_SET_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags); + NULL, 0, + StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); SCReturnInt(0); @@ -3174,9 +3147,9 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (!(p->flow->flags & FLOW_NO_APPLAYER_INSPECTION)) { if (SEQ_GT(seg->seq, next_seq) && SEQ_LT(seg->seq, stream->last_ack)) { /* send gap signal */ - STREAM_SET_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags|STREAM_GAP); + NULL, 0, + StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); AppLayerProfilingStore(ra_ctx->app_tctx, p); /* set a GAP flag and make sure not bothering this stream anymore */ @@ -3217,11 +3190,11 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } /* check if we have a sequence gap and if so, handle it */ - if (DoHandleGap(tv, ra_ctx, ssn, stream, seg, &rd, p, flags, next_seq) == 1) + if (DoHandleGap(tv, ra_ctx, ssn, stream, seg, &rd, p, next_seq) == 1) break; /* process this segment */ - if (DoReassemble(tv, ra_ctx, ssn, stream, seg, &rd, p, flags) == 0) + if (DoReassemble(tv, ra_ctx, ssn, stream, seg, &rd, p) == 0) break; /* done with this segment, return it to the pool */ @@ -3242,10 +3215,10 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (rd.data_len > 0) { SCLogDebug("data_len > 0, %u", rd.data_len); /* process what we have so far */ - STREAM_SET_FLAGS(ssn, stream, p, flags); BUG_ON(rd.data_len > sizeof(rd.data)); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - rd.data, rd.data_len, flags); + rd.data, rd.data_len, + StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); } From 97908bcd2d4157536ba03fd724ed0ee6351ab73f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 15:27:58 +0100 Subject: [PATCH 0209/2553] stream: unify inline and non-inline applayer assembly Unifiy inline and non-inline app layer stream reassembly to aid maintainability of the code. --- src/app-layer.c | 8 +-- src/stream-tcp-reassemble.c | 106 ++++++++++++++++++++++++++---------- 2 files changed, 78 insertions(+), 36 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 77c2d4f95ae2..857a0b49955f 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -201,14 +201,8 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, p->flowflags |= FLOW_PKT_TOCLIENT; } } - int ret; - if (StreamTcpInlineMode()) { - ret = StreamTcpReassembleInlineAppLayer(tv, ra_ctx, ssn, - opposing_stream, p); - } else { - ret = StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, + int ret = StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, opposing_stream, p); - } if (stream == &ssn->client) { if (StreamTcpInlineMode()) { p->flowflags &= ~FLOW_PKT_TOCLIENT; diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 46855e244273..8159c613dfba 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2835,6 +2835,14 @@ typedef struct ReassembleData_ { uint32_t data_sent; /* data passed on this run */ } ReassembleData; +/** \internal + * \brief test if segment follows a gap. If so, handle the gap + * + * If in inline mode, segment may be un-ack'd. In this case we + * consider it a gap, but it's not 'final' yet. + * + * \retval bool 1 gap 0 no gap + */ int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd, Packet *p, uint32_t next_seq) @@ -2842,6 +2850,13 @@ int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (unlikely(SEQ_GT(seg->seq, next_seq))) { /* we've run into a sequence gap */ + if (StreamTcpInlineMode()) { + /* don't conclude it's a gap until we see that the data + * that is missing was acked. */ + if (SEQ_GT(seg->seq,stream->last_ack) && ssn->state != TCP_CLOSED) + return 1; + } + /* first, pass on data before the gap */ if (rd->data_len > 0) { SCLogDebug("pre GAP data"); @@ -2902,40 +2917,57 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, "ra_base_seq %" PRIu32 ", last_ack %"PRIu32, seg->seq, seg->payload_len, rd->ra_base_seq, stream->last_ack); - /* handle segments partly before ra_base_seq */ - if (SEQ_GT(rd->ra_base_seq, seg->seq)) { - payload_offset = (rd->ra_base_seq + 1) - seg->seq; - SCLogDebug("payload_offset %u", payload_offset); + if (StreamTcpInlineMode() == 0) { + /* handle segments partly before ra_base_seq */ + if (SEQ_GT(rd->ra_base_seq, seg->seq)) { + payload_offset = (rd->ra_base_seq + 1) - seg->seq; + SCLogDebug("payload_offset %u", payload_offset); - if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { - if (SEQ_LT(stream->last_ack, (rd->ra_base_seq + 1))) { - payload_len = (stream->last_ack - seg->seq); - SCLogDebug("payload_len %u", payload_len); + if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { + if (SEQ_LT(stream->last_ack, (rd->ra_base_seq + 1))) { + payload_len = (stream->last_ack - seg->seq); + SCLogDebug("payload_len %u", payload_len); + } else { + payload_len = (stream->last_ack - seg->seq) - payload_offset; + SCLogDebug("payload_len %u", payload_len); + } + rd->partial = TRUE; } else { - payload_len = (stream->last_ack - seg->seq) - payload_offset; + payload_len = seg->payload_len - payload_offset; SCLogDebug("payload_len %u", payload_len); } - rd->partial = TRUE; + + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + BUG_ON((payload_len + payload_offset) > seg->payload_len); + } } else { - payload_len = seg->payload_len - payload_offset; - SCLogDebug("payload_len %u", payload_len); - } + payload_offset = 0; - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - BUG_ON((payload_len + payload_offset) > seg->payload_len); + if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { + payload_len = stream->last_ack - seg->seq; + SCLogDebug("payload_len %u", payload_len); + + rd->partial = TRUE; + } else { + payload_len = seg->payload_len; + SCLogDebug("payload_len %u", payload_len); + } } + /* inline mode, don't consider last_ack as we process un-ACK'd segments */ } else { - payload_offset = 0; - - if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { - payload_len = stream->last_ack - seg->seq; - SCLogDebug("payload_len %u", payload_len); + /* handle segments partly before ra_base_seq */ + if (SEQ_GT(rd->ra_base_seq, seg->seq)) { + payload_offset = rd->ra_base_seq - seg->seq - 1; + payload_len = seg->payload_len - payload_offset; - rd->partial = TRUE; + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + BUG_ON((payload_len + payload_offset) > seg->payload_len); + } } else { + payload_offset = 0; payload_len = seg->payload_len; - SCLogDebug("payload_len %u", payload_len); } } SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" @@ -3165,8 +3197,14 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } } - for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) + for (; seg != NULL; ) { + /* if in inline mode, we process all segments regardless of whether + * they are ack'd or not. In non-inline, we process only those that + * are at least partly ack'd. */ + if (StreamTcpInlineMode() == 0 && SEQ_GEQ(seg->seq, stream->last_ack)) + break; + SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32, seg, seg->seq, seg->payload_len, (uint32_t)(seg->seq + seg->payload_len)); @@ -3222,6 +3260,16 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, AppLayerProfilingStore(ra_ctx->app_tctx, p); } + /* if no data was sent to the applayer, we send it a empty 'nudge' + * when in inline mode */ + if (StreamTcpInlineMode() && rd.data_sent == 0 && ssn->state > TCP_ESTABLISHED) { + SCLogDebug("sending empty eof message"); + /* send EOF to app layer */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + } + /* store ra_base_seq in the stream */ if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { stream->ra_app_base_seq = rd.ra_base_seq; @@ -3580,7 +3628,7 @@ int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ * functions to handle EOF */ if (StreamTcpInlineMode()) { int r = 0; - if (StreamTcpReassembleInlineAppLayer(tv, ra_ctx, ssn, stream, p) < 0) + if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0) r = -1; if (StreamTcpReassembleInlineRaw(ra_ctx, ssn, stream, p) < 0) r = -1; @@ -8783,9 +8831,9 @@ static int StreamTcpReassembleInlineTest10(void) } ssn.server.next_seq = 4; - int r = StreamTcpReassembleInlineAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); + int r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); if (r < 0) { - printf("StreamTcpReassembleInlineAppLayer failed: "); + printf("StreamTcpReassembleAppLayer failed: "); goto end; } @@ -8805,9 +8853,9 @@ static int StreamTcpReassembleInlineTest10(void) } ssn.server.next_seq = 19; - r = StreamTcpReassembleInlineAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); + r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); if (r < 0) { - printf("StreamTcpReassembleInlineAppLayer failed: "); + printf("StreamTcpReassembleAppLayer failed: "); goto end; } From ff2fecf59099f3d1808d7d89ee2c459bdf59ab63 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 15:39:49 +0100 Subject: [PATCH 0210/2553] stream: remove StreamTcpReassembleInlineAppLayer Function is now unused. --- src/stream-tcp-reassemble.c | 333 ------------------------------------ src/stream-tcp-reassemble.h | 4 - 2 files changed, 337 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 8159c613dfba..1e901b3b0e47 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2095,339 +2095,6 @@ static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg) stream->seg_list_tail = seg->prev; } -/** - * \brief Update the stream reassembly upon receiving a data segment - * - * Reassembly is in the same direction of the packet. - * - * One of the utilities called by this function AppLayerHandleTCPData(), - * has a feature where it will call this very same function for the - * stream opposing the stream it is called with. This shouldn't cause - * any issues, since processing of each stream is independent of the - * other stream. - * - * \todo this function is too long, we need to break it up. It needs it BAD - */ -int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, - TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, - Packet *p) -{ - SCEnter(); - - /* this function can be directly called by app layer protocol - * detection. */ - if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) { - SCLogDebug("stream no reassembly flag set. Mostly called via " - "app proto detection."); - SCReturnInt(0); - } - - SCLogDebug("pcap_cnt %"PRIu64", len %u", p->pcap_cnt, p->payload_len); - - SCLogDebug("stream->seg_list %p", stream->seg_list); -#ifdef DEBUG - PrintList(stream->seg_list); - //PrintRawDataFp(stdout, p->payload, p->payload_len); -#endif - - if (stream->seg_list == NULL) { - /* send an empty EOF msg if we have no segments but TCP state - * is beyond ESTABLISHED */ - if (ssn->state > TCP_ESTABLISHED) { - SCLogDebug("sending empty eof message"); - /* send EOF to app layer */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, NULL, 0, - StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - - } else { - SCLogDebug("no segments in the list to reassemble"); - } - - SCReturnInt(0); - } - - if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) { - SCReturnInt(0); - } - - /* stream->ra_app_base_seq remains at stream->isn until protocol is - * detected. */ - uint32_t ra_base_seq = stream->ra_app_base_seq; - uint8_t data[4096]; - uint32_t data_len = 0; - uint16_t payload_offset = 0; - uint16_t payload_len = 0; - uint32_t next_seq = ra_base_seq + 1; - uint32_t data_sent = 0; - TcpSegment *seg = stream->seg_list; - - SCLogDebug("ra_base_seq %u", ra_base_seq); - - /* Check if we have a gap at the start of the list. If last_ack is - * bigger than the list start and the list start is bigger than - * next_seq, we know we are missing data that has been ack'd. That - * won't get retransmitted, so it's a data gap. - */ - if (!(p->flow->flags & FLOW_NO_APPLAYER_INSPECTION)) { - if (SEQ_GT(seg->seq, next_seq) && SEQ_LT(seg->seq, stream->last_ack)) { - /* send gap signal */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - - /* set a GAP flag and make sure not bothering this stream anymore */ - SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); - stream->flags |= STREAMTCP_STREAM_FLAG_GAP; - - StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); -#ifdef DEBUG - dbg_app_layer_gap++; -#endif - SCReturnInt(0); - } - } - - /* loop through the segments and fill one or more msgs */ - SCLogDebug("pre-loop seg %p", seg); - for (; seg != NULL;) { - SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32, - seg, seg->seq, seg->payload_len, - (uint32_t)(seg->seq + seg->payload_len)); - - if (p->flow->flags & FLOW_NO_APPLAYER_INSPECTION) { - SCLogDebug("FLOW_NO_APPLAYER_INSPECTION set, breaking out"); - break; - } - - if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) { - SCLogDebug("removing segment"); - TcpSegment *next_seg = seg->next; - StreamTcpRemoveSegmentFromStream(stream, seg); - StreamTcpSegmentReturntoPool(seg); - seg = next_seg; - continue; - } else if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { - TcpSegment *next_seg = seg->next; - seg = next_seg; - continue; - } - - /* we've run into a sequence gap */ - if (SEQ_GT(seg->seq, next_seq)) { - SCLogDebug("GAP: we expected %u, got %u. Diff %u", next_seq, seg->seq, seg->seq - next_seq); - - /* don't conclude it's a gap until we see that the data - * that is missing was acked. */ - if (SEQ_GT(seg->seq,stream->last_ack) && ssn->state != TCP_CLOSED) - break; - - /* first, pass on data before the gap */ - if (data_len > 0) { - SCLogDebug("pre GAP data"); - - /* process what we have so far */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_len = 0; - } - - /* see what the length of the gap is, gap length is seg->seq - - * (ra_base_seq +1) */ -#ifdef DEBUG - uint32_t gap_len = seg->seq - next_seq; - SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " - "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", - next_seq, seg->seq, stream->last_ack, gap_len); -#endif - /* We have missed the packet and end host has ack'd it, so - * IDS should advance it's ra_base_seq and should not consider this - * packet any longer, even if it is retransmitted, as end host will - * drop it anyway */ - ra_base_seq = seg->seq - 1; - - /* send gap signal */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - - /* set a GAP flag and make sure not bothering this stream anymore */ - SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); - stream->flags |= STREAMTCP_STREAM_FLAG_GAP; - - StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); -#ifdef DEBUG - dbg_app_layer_gap++; -#endif - break; - } - - /* if the segment ends beyond ra_base_seq we need to consider it */ - if (SEQ_GT((seg->seq + seg->payload_len), (ra_base_seq + 1))) { - SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " - "ra_base_seq %" PRIu32 "", seg->seq, - seg->payload_len, ra_base_seq); - - /* handle segments partly before ra_base_seq */ - if (SEQ_GT(ra_base_seq, seg->seq)) { - payload_offset = ra_base_seq - seg->seq - 1; - payload_len = seg->payload_len - payload_offset; - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - BUG_ON((payload_len + payload_offset) > seg->payload_len); - } - } else { - payload_offset = 0; - payload_len = seg->payload_len; - } - SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" - " and stream->next_win is %"PRIu32"", payload_offset, - payload_len, stream->next_win); - - if (payload_len == 0) { - SCLogDebug("no payload_len, so bail out"); - break; - } - - /* copy the data into the smsg */ - uint16_t copy_size = sizeof(data) - data_len; - if (copy_size > payload_len) { - copy_size = payload_len; - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(data)); - } - SCLogDebug("copy_size is %"PRIu16"", copy_size); - memcpy(data + data_len, seg->payload + payload_offset, copy_size); - data_len += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, ra_base_seq, data_len); - - /* queue the smsg if it's full */ - if (data_len == sizeof(data)) { - /* process what we have so far */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - data_len = 0; - } - - /* if the payload len is bigger than what we copied, we handle the - * rest of the payload next... */ - if (copy_size < payload_len) { - SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, - payload_len); - - payload_offset += copy_size; - payload_len -= copy_size; - SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " - "%"PRIu16" and stream->last_ack is %"PRIu32"", - payload_offset, seg->payload_len, stream->last_ack); - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - - /* we need a while loop here as the packets theoretically can be - * 64k */ - char segment_done = FALSE; - while (segment_done == FALSE) { - SCLogDebug("new msg at offset %" PRIu32 ", payload_len " - "%" PRIu32 "", payload_offset, payload_len); - data_len = 0; - - copy_size = sizeof(data) - data_len; - if (copy_size > (seg->payload_len - payload_offset)) { - copy_size = (seg->payload_len - payload_offset); - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(data)); - } - - SCLogDebug("copy payload_offset %" PRIu32 ", data_len " - "%" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, data_len, copy_size); - memcpy(data + data_len, seg->payload + - payload_offset, copy_size); - data_len += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); - SCLogDebug("copied payload_offset %" PRIu32 ", " - "data_len %" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, data_len, copy_size); - - if (data_len == sizeof(data)) { - /* process what we have so far */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - data_len = 0; - } - - /* see if we have segment payload left to process */ - if ((copy_size + payload_offset) < seg->payload_len) { - payload_offset += copy_size; - payload_len -= copy_size; - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - } else { - payload_offset = 0; - segment_done = TRUE; - } - } - } - } - - /* done with this segment, return it to the pool */ - TcpSegment *next_seg = seg->next; - next_seq = seg->seq + seg->payload_len; - seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; - seg = next_seg; - } - - /* put the partly filled smsg in the queue to the l7 handler */ - if (data_len > 0) { - SCLogDebug("data_len > 0, %u", data_len); - /* process what we have so far */ - BUG_ON(data_len > sizeof(data)); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - } - - if (data_sent == 0 && ssn->state > TCP_ESTABLISHED) { - SCLogDebug("sending empty eof message"); - /* send EOF to app layer */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - } - - /* store ra_base_seq in the stream */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - stream->ra_app_base_seq = ra_base_seq; - } else { - TcpSegment *tmp_seg = stream->seg_list; - while (tmp_seg != NULL) { - tmp_seg->flags &= ~SEGMENTTCP_FLAG_APPLAYER_PROCESSED; - tmp_seg = tmp_seg->next; - } - } - - SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq); - SCReturnInt(0); -} - /** * \brief Update the stream reassembly upon receiving a data segment * diff --git a/src/stream-tcp-reassemble.h b/src/stream-tcp-reassemble.h index 7eca5cf68389..b66334a9999b 100644 --- a/src/stream-tcp-reassemble.h +++ b/src/stream-tcp-reassemble.h @@ -79,10 +79,6 @@ void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *); int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p); -int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, - TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, - Packet *p); void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t); From 6ca9c8eb32c5a44d52ae4b3d6ad0d61848025739 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 19:01:03 +0100 Subject: [PATCH 0211/2553] stream: move raw reassembly into util func --- src/stream-tcp-reassemble.c | 374 +++++++++++++++++++----------------- 1 file changed, 196 insertions(+), 178 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 1e901b3b0e47..7f6fccafb871 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2951,6 +2951,183 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, SCReturnInt(0); } +typedef struct ReassembleRawData_ { + uint32_t ra_base_seq; + int partial; /* last segment was processed only partially */ + StreamMsg *smsg; + uint16_t smsg_offset; // TODO diff with smsg->data_len? +} ReassembleRawData; + +static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, Packet *p, + ReassembleRawData *rd) +{ + uint16_t payload_offset = 0; + uint16_t payload_len = 0; + + /* start clean */ + rd->partial = FALSE; + + /* if the segment ends beyond ra_base_seq we need to consider it */ + if (SEQ_GT((seg->seq + seg->payload_len), rd->ra_base_seq+1)) { + SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " + "ra_base_seq %" PRIu32 "", seg->seq, + seg->payload_len, rd->ra_base_seq); + + /* handle segments partly before ra_base_seq */ + if (SEQ_GT(rd->ra_base_seq, seg->seq)) { + payload_offset = rd->ra_base_seq - seg->seq; + + if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { + + if (SEQ_LT(stream->last_ack, rd->ra_base_seq)) { + payload_len = (stream->last_ack - seg->seq); + } else { + payload_len = (stream->last_ack - seg->seq) - payload_offset; + } + rd->partial = TRUE; + } else { + payload_len = seg->payload_len - payload_offset; + } + + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + BUG_ON((payload_len + payload_offset) > seg->payload_len); + } + } else { + payload_offset = 0; + + if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { + payload_len = stream->last_ack - seg->seq; + rd->partial = TRUE; + } else { + payload_len = seg->payload_len; + } + } + SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" + " and stream->last_ack is %"PRIu32"", payload_offset, + payload_len, stream->last_ack); + + if (payload_len == 0) { + SCLogDebug("no payload_len, so bail out"); + return 1; // TODO + } + + if (rd->smsg == NULL) { + rd->smsg = StreamMsgGetFromPool(); + if (rd->smsg == NULL) { + SCLogDebug("stream_msg_pool is empty"); + return -1; + } + + rd->smsg_offset = 0; + + StreamTcpSetupMsg(ssn, stream, p, rd->smsg); + rd->smsg->seq = rd->ra_base_seq + 1; + SCLogDebug("smsg->seq %u", rd->smsg->seq); + } + + /* copy the data into the smsg */ + uint16_t copy_size = sizeof (rd->smsg->data) - rd->smsg_offset; + if (copy_size > payload_len) { + copy_size = payload_len; + } + if (SCLogDebugEnabled()) { + BUG_ON(copy_size > sizeof(rd->smsg->data)); + } + SCLogDebug("copy_size is %"PRIu16"", copy_size); + memcpy(rd->smsg->data + rd->smsg_offset, seg->payload + payload_offset, + copy_size); + rd->smsg_offset += copy_size; + rd->ra_base_seq += copy_size; + SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq); + + rd->smsg->data_len += copy_size; + + /* queue the smsg if it's full */ + if (rd->smsg->data_len == sizeof (rd->smsg->data)) { + StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0); + stream->ra_raw_base_seq = rd->ra_base_seq; + rd->smsg = NULL; + } + + /* if the payload len is bigger than what we copied, we handle the + * rest of the payload next... */ + if (copy_size < payload_len) { + SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, + payload_len); + + payload_offset += copy_size; + payload_len -= copy_size; + SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " + "%"PRIu16" and stream->last_ack is %"PRIu32"", + payload_offset, seg->payload_len, stream->last_ack); + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + } + + /* we need a while loop here as the packets theoretically can be + * 64k */ + char segment_done = FALSE; + while (segment_done == FALSE) { + SCLogDebug("new msg at offset %" PRIu32 ", payload_len " + "%" PRIu32 "", payload_offset, payload_len); + + /* get a new message + XXX we need a setup function */ + rd->smsg = StreamMsgGetFromPool(); + if (rd->smsg == NULL) { + SCLogDebug("stream_msg_pool is empty"); + SCReturnInt(-1); + } + rd->smsg_offset = 0; + + StreamTcpSetupMsg(ssn, stream, p, rd->smsg); + rd->smsg->seq = rd->ra_base_seq + 1; + + copy_size = sizeof(rd->smsg->data) - rd->smsg_offset; + if (copy_size > payload_len) { + copy_size = payload_len; + } + if (SCLogDebugEnabled()) { + BUG_ON(copy_size > sizeof(rd->smsg->data)); + } + + SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset " + "%" PRIu32 ", copy_size %" PRIu32 "", + payload_offset, rd->smsg_offset, copy_size); + memcpy(rd->smsg->data + rd->smsg_offset, seg->payload + + payload_offset, copy_size); + rd->smsg_offset += copy_size; + rd->ra_base_seq += copy_size; + SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq); + rd->smsg->data_len += copy_size; + SCLogDebug("copied payload_offset %" PRIu32 ", " + "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "", + payload_offset, rd->smsg_offset, copy_size); + if (rd->smsg->data_len == sizeof(rd->smsg->data)) { + StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0); + stream->ra_raw_base_seq = rd->ra_base_seq; + rd->smsg = NULL; + } + + /* see if we have segment payload left to process */ + if (copy_size < payload_len) { + payload_offset += copy_size; + payload_len -= copy_size; + + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + } + } else { + payload_offset = 0; + segment_done = TRUE; + } + } + } + } + return 1; +} + /** * \brief Update the stream reassembly upon receiving an ACK packet. * \todo this function is too long, we need to break it up. It needs it BAD @@ -2983,16 +3160,15 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, SCReturnInt(0); } - uint32_t ra_base_seq = stream->ra_raw_base_seq; - StreamMsg *smsg = NULL; - uint16_t smsg_offset = 0; - uint16_t payload_offset = 0; - uint16_t payload_len = 0; TcpSegment *seg = stream->seg_list; - uint32_t next_seq = ra_base_seq + 1; + ReassembleRawData rd; + rd.smsg = NULL; + rd.ra_base_seq = stream->ra_raw_base_seq; + rd.smsg_offset = 0; + uint32_t next_seq = rd.ra_base_seq + 1; SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32, - ra_base_seq, stream->last_ack, next_seq); + rd.ra_base_seq, stream->last_ack, next_seq); /* loop through the segments and fill one or more msgs */ for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) @@ -3018,15 +3194,15 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, if (SEQ_GT(seg->seq, next_seq)) { /* pass on pre existing smsg (if any) */ - if (smsg != NULL && smsg->data_len > 0) { + if (rd.smsg != NULL && rd.smsg->data_len > 0) { /* if app layer protocol has not been detected till yet, then check did we have sent message to app layer already or not. If not then sent the message and set flag that first message has been sent. No more data till proto has not been detected */ - StreamTcpStoreStreamChunk(ssn, smsg, p, 0); - stream->ra_raw_base_seq = ra_base_seq; - smsg = NULL; + StreamTcpStoreStreamChunk(ssn, rd.smsg, p, 0); + stream->ra_raw_base_seq = rd.ra_base_seq; + rd.smsg = NULL; } /* see what the length of the gap is, gap length is seg->seq - @@ -3037,180 +3213,22 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", next_seq, seg->seq, stream->last_ack, gap_len); #endif - stream->ra_raw_base_seq = ra_base_seq; + stream->ra_raw_base_seq = rd.ra_base_seq; /* We have missed the packet and end host has ack'd it, so * IDS should advance it's ra_base_seq and should not consider this * packet any longer, even if it is retransmitted, as end host will * drop it anyway */ - ra_base_seq = seg->seq - 1; + rd.ra_base_seq = seg->seq - 1; } - int partial = FALSE; - - /* if the segment ends beyond ra_base_seq we need to consider it */ - if (SEQ_GT((seg->seq + seg->payload_len), ra_base_seq+1)) { - SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " - "ra_base_seq %" PRIu32 "", seg->seq, - seg->payload_len, ra_base_seq); - - /* handle segments partly before ra_base_seq */ - if (SEQ_GT(ra_base_seq, seg->seq)) { - payload_offset = ra_base_seq - seg->seq; - - if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { - - if (SEQ_LT(stream->last_ack, ra_base_seq)) { - payload_len = (stream->last_ack - seg->seq); - } else { - payload_len = (stream->last_ack - seg->seq) - payload_offset; - } - partial = TRUE; - } else { - payload_len = seg->payload_len - payload_offset; - } - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - BUG_ON((payload_len + payload_offset) > seg->payload_len); - } - } else { - payload_offset = 0; - - if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { - payload_len = stream->last_ack - seg->seq; - partial = TRUE; - } else { - payload_len = seg->payload_len; - } - } - SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" - " and stream->last_ack is %"PRIu32"", payload_offset, - payload_len, stream->last_ack); - - if (payload_len == 0) { - SCLogDebug("no payload_len, so bail out"); - break; - } - - if (smsg == NULL) { - smsg = StreamMsgGetFromPool(); - if (smsg == NULL) { - SCLogDebug("stream_msg_pool is empty"); - return -1; - } - - smsg_offset = 0; - - StreamTcpSetupMsg(ssn, stream, p, smsg); - smsg->seq = ra_base_seq + 1; - SCLogDebug("smsg->seq %u", smsg->seq); - } - - /* copy the data into the smsg */ - uint16_t copy_size = sizeof (smsg->data) - smsg_offset; - if (copy_size > payload_len) { - copy_size = payload_len; - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(smsg->data)); - } - SCLogDebug("copy_size is %"PRIu16"", copy_size); - memcpy(smsg->data + smsg_offset, seg->payload + payload_offset, - copy_size); - smsg_offset += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); - - smsg->data_len += copy_size; - - /* queue the smsg if it's full */ - if (smsg->data_len == sizeof (smsg->data)) { - StreamTcpStoreStreamChunk(ssn, smsg, p, 0); - stream->ra_raw_base_seq = ra_base_seq; - smsg = NULL; - } - - /* if the payload len is bigger than what we copied, we handle the - * rest of the payload next... */ - if (copy_size < payload_len) { - SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, - payload_len); - - payload_offset += copy_size; - payload_len -= copy_size; - SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " - "%"PRIu16" and stream->last_ack is %"PRIu32"", - payload_offset, seg->payload_len, stream->last_ack); - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - - /* we need a while loop here as the packets theoretically can be - * 64k */ - char segment_done = FALSE; - while (segment_done == FALSE) { - SCLogDebug("new msg at offset %" PRIu32 ", payload_len " - "%" PRIu32 "", payload_offset, payload_len); - - /* get a new message - XXX we need a setup function */ - smsg = StreamMsgGetFromPool(); - if (smsg == NULL) { - SCLogDebug("stream_msg_pool is empty"); - SCReturnInt(-1); - } - smsg_offset = 0; - - StreamTcpSetupMsg(ssn, stream,p,smsg); - smsg->seq = ra_base_seq + 1; - - copy_size = sizeof(smsg->data) - smsg_offset; - if (copy_size > payload_len) { - copy_size = payload_len; - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(smsg->data)); - } - - SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset " - "%" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, smsg_offset, copy_size); - memcpy(smsg->data + smsg_offset, seg->payload + - payload_offset, copy_size); - smsg_offset += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); - smsg->data_len += copy_size; - SCLogDebug("copied payload_offset %" PRIu32 ", " - "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, smsg_offset, copy_size); - if (smsg->data_len == sizeof (smsg->data)) { - StreamTcpStoreStreamChunk(ssn, smsg, p, 0); - stream->ra_raw_base_seq = ra_base_seq; - smsg = NULL; - } - - /* see if we have segment payload left to process */ - if (copy_size < payload_len) { - payload_offset += copy_size; - payload_len -= copy_size; - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - } else { - payload_offset = 0; - segment_done = TRUE; - } - } - } - } + if (DoRawReassemble(ssn, stream, seg, p, &rd) == 0) + break; /* done with this segment, return it to the pool */ TcpSegment *next_seg = seg->next; next_seq = seg->seq + seg->payload_len; - if (partial == FALSE) { + if (rd.partial == FALSE) { SCLogDebug("fully done with segment in raw reassembly (seg %p seq %"PRIu32")", seg, seg->seq); seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED; @@ -3222,10 +3240,10 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, } /* put the partly filled smsg in the queue to the l7 handler */ - if (smsg != NULL) { - StreamTcpStoreStreamChunk(ssn, smsg, p, 0); - smsg = NULL; - stream->ra_raw_base_seq = ra_base_seq; + if (rd.smsg != NULL) { + StreamTcpStoreStreamChunk(ssn, rd.smsg, p, 0); + rd.smsg = NULL; + stream->ra_raw_base_seq = rd.ra_base_seq; } SCReturnInt(0); From 8c1bc7cfb6adddfbfcbad6ee087b5fd45383cd66 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Dec 2014 19:08:14 +0100 Subject: [PATCH 0212/2553] stream: move raw stream gap handling into util func --- src/stream-tcp-reassemble.c | 67 ++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 7f6fccafb871..bd5c9029fc94 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2958,6 +2958,41 @@ typedef struct ReassembleRawData_ { uint16_t smsg_offset; // TODO diff with smsg->data_len? } ReassembleRawData; +static void DoHandleRawGap(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, Packet *p, + ReassembleRawData *rd, uint32_t next_seq) +{ + /* we've run into a sequence gap */ + if (SEQ_GT(seg->seq, next_seq)) { + /* pass on pre existing smsg (if any) */ + if (rd->smsg != NULL && rd->smsg->data_len > 0) { + /* if app layer protocol has not been detected till yet, + then check did we have sent message to app layer already + or not. If not then sent the message and set flag that first + message has been sent. No more data till proto has not + been detected */ + StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0); + stream->ra_raw_base_seq = rd->ra_base_seq; + rd->smsg = NULL; + } + + /* see what the length of the gap is, gap length is seg->seq - + * (ra_base_seq +1) */ +#ifdef DEBUG + uint32_t gap_len = seg->seq - next_seq; + SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " + "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", + next_seq, seg->seq, stream->last_ack, gap_len); +#endif + stream->ra_raw_base_seq = rd->ra_base_seq; + + /* We have missed the packet and end host has ack'd it, so + * IDS should advance it's ra_base_seq and should not consider this + * packet any longer, even if it is retransmitted, as end host will + * drop it anyway */ + rd->ra_base_seq = seg->seq - 1; + } +} + static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, Packet *p, ReassembleRawData *rd) { @@ -3190,37 +3225,7 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, continue; } - /* we've run into a sequence gap */ - if (SEQ_GT(seg->seq, next_seq)) { - - /* pass on pre existing smsg (if any) */ - if (rd.smsg != NULL && rd.smsg->data_len > 0) { - /* if app layer protocol has not been detected till yet, - then check did we have sent message to app layer already - or not. If not then sent the message and set flag that first - message has been sent. No more data till proto has not - been detected */ - StreamTcpStoreStreamChunk(ssn, rd.smsg, p, 0); - stream->ra_raw_base_seq = rd.ra_base_seq; - rd.smsg = NULL; - } - - /* see what the length of the gap is, gap length is seg->seq - - * (ra_base_seq +1) */ -#ifdef DEBUG - uint32_t gap_len = seg->seq - next_seq; - SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " - "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", - next_seq, seg->seq, stream->last_ack, gap_len); -#endif - stream->ra_raw_base_seq = rd.ra_base_seq; - - /* We have missed the packet and end host has ack'd it, so - * IDS should advance it's ra_base_seq and should not consider this - * packet any longer, even if it is retransmitted, as end host will - * drop it anyway */ - rd.ra_base_seq = seg->seq - 1; - } + DoHandleRawGap(ssn, stream, seg, p, &rd, next_seq); if (DoRawReassemble(ssn, stream, seg, p, &rd) == 0) break; From 2bba5eb7044504044b9a0e913e95fa4f542e49e4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Jan 2015 11:53:29 +0100 Subject: [PATCH 0213/2553] tcp: zero copy fast path in app-layer reassembly Create 2 'fast paths' for app layer reassembly. Both are about reducing copying. In the cases described below, we pass the segment's data directly to the app layer API, instead of first copying it into a buffer than we then pass. This safes a copy. The first is for the case when we have just one single segment that was just ack'd. As we know that we won't use any other segment this round, we can just use the segment data. The second case is more aggressive. When the segment meets a certain size limit (currently hardcoded at 128 bytes), we pass it to the app-layer API directly. Thus invoking the app-layer somewhat more often to safe some copies. --- src/stream-tcp-reassemble.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index bd5c9029fc94..b61748dd1059 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2572,6 +2572,42 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd, Packet *p) { + /* fast path 1: segment is exactly what we need */ + if (likely(rd->data_len == 0 && SEQ_EQ(seg->seq, rd->ra_base_seq+1) && SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len)))) { + /* process single segment directly */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + seg->payload, seg->payload_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += seg->payload_len; + rd->ra_base_seq += seg->payload_len; + + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + return 1; + /* fast path 2: segment acked completely, meets minimal size req for 0copy processing */ + } else if (rd->data_len == 0 && SEQ_EQ(seg->seq, rd->ra_base_seq+1) && SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) && seg->payload_len >= 128) { + /* process single segment directly */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + seg->payload, seg->payload_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += seg->payload_len; + rd->ra_base_seq += seg->payload_len; + + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + return 1; + } + uint16_t payload_offset = 0; uint16_t payload_len = 0; From 37b56dca5570313a0bee6f19d1955f8baf40b926 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Jan 2015 12:12:38 +0100 Subject: [PATCH 0214/2553] tcp: add debug stats about reassembly fast paths Only shown if --enable-debug is passed to configure. --- src/stream-tcp-reassemble.c | 16 +++++++++++++--- src/stream-tcp-reassemble.h | 5 +++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index b61748dd1059..e3ee0048753e 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -551,6 +551,10 @@ void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx) { SCEnter(); AppLayerDestroyCtxThread(ra_ctx->app_tctx); +#ifdef DEBUG + SCLogDebug("reassembly fast path stats: fp1 %"PRIu64" fp2 %"PRIu64" sp %"PRIu64, + ra_ctx->fp1, ra_ctx->fp2, ra_ctx->sp); +#endif SCFree(ra_ctx); SCReturn; } @@ -2581,7 +2585,9 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, AppLayerProfilingStore(ra_ctx->app_tctx, p); rd->data_sent += seg->payload_len; rd->ra_base_seq += seg->payload_len; - +#ifdef DEBUG + ra_ctx->fp1++; +#endif /* if after the first data chunk we have no alproto yet, * there is no point in continueing here. */ if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { @@ -2598,7 +2604,9 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, AppLayerProfilingStore(ra_ctx->app_tctx, p); rd->data_sent += seg->payload_len; rd->ra_base_seq += seg->payload_len; - +#ifdef DEBUG + ra_ctx->fp2++; +#endif /* if after the first data chunk we have no alproto yet, * there is no point in continueing here. */ if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { @@ -2607,7 +2615,9 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } return 1; } - +#ifdef DEBUG + ra_ctx->sp++; +#endif uint16_t payload_offset = 0; uint16_t payload_len = 0; diff --git a/src/stream-tcp-reassemble.h b/src/stream-tcp-reassemble.h index b66334a9999b..686c2e47d905 100644 --- a/src/stream-tcp-reassemble.h +++ b/src/stream-tcp-reassemble.h @@ -66,6 +66,11 @@ typedef struct TcpReassemblyThreadCtx_ { uint16_t counter_htp_memuse; /* number of allocation failed due to memcap when handling HTTP protocol */ uint16_t counter_htp_memcap; +#ifdef DEBUG + uint64_t fp1; + uint64_t fp2; + uint64_t sp; +#endif } TcpReassemblyThreadCtx; #define OS_POLICY_DEFAULT OS_POLICY_BSD From 9327b08ab16c10807b70a2fb200d5681ed6aea39 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Jan 2015 13:43:31 +0100 Subject: [PATCH 0215/2553] tcp: add stream.reassembly.zero-copy-size option The option sets in bytes the value at which segment data is passed to the app layer API directly. Data sizes equal to and higher than the value set are passed on directly. Default is 128. --- src/stream-tcp-reassemble.c | 24 ++++++++++++++++++++++-- src/stream-tcp.h | 3 +++ suricata.yaml.in | 6 ++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index e3ee0048753e..cebdd53544d5 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -466,6 +466,19 @@ int StreamTcpReassemblyConfig(char quiet) if (!quiet) SCLogInfo("stream.reassembly \"chunk-prealloc\": %u", stream_chunk_prealloc); StreamMsgQueuesInit(stream_chunk_prealloc); + + intmax_t zero_copy_size = 128; + if (ConfGetInt("stream.reassembly.zero-copy-size", &zero_copy_size) == 1) { + if (zero_copy_size < 0 || zero_copy_size > 0xffff) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "stream.reassembly.zero-copy-size of " + "%"PRIiMAX" is invalid: valid values are 0 to 65535", zero_copy_size); + return -1; + } + } + stream_config.zero_copy_size = (uint16_t)zero_copy_size; + if (!quiet) + SCLogInfo("stream.reassembly \"zero-copy-size\": %u", stream_config.zero_copy_size); + return 0; } @@ -2577,7 +2590,10 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet *p) { /* fast path 1: segment is exactly what we need */ - if (likely(rd->data_len == 0 && SEQ_EQ(seg->seq, rd->ra_base_seq+1) && SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len)))) { + if (likely(rd->data_len == 0 && + SEQ_EQ(seg->seq, rd->ra_base_seq+1) && + SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len)))) + { /* process single segment directly */ AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, seg->payload, seg->payload_len, @@ -2596,7 +2612,11 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } return 1; /* fast path 2: segment acked completely, meets minimal size req for 0copy processing */ - } else if (rd->data_len == 0 && SEQ_EQ(seg->seq, rd->ra_base_seq+1) && SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) && seg->payload_len >= 128) { + } else if (rd->data_len == 0 && + SEQ_EQ(seg->seq, rd->ra_base_seq+1) && + SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) && + seg->payload_len >= stream_config.zero_copy_size) + { /* process single segment directly */ AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, seg->payload, seg->payload_len, diff --git a/src/stream-tcp.h b/src/stream-tcp.h index b8a31855afad..113e2e88a135 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -51,6 +51,9 @@ typedef struct TcpStreamCnf_ { uint32_t ssn_init_flags; /**< new ssn flags will be initialized to this */ uint8_t segment_init_flags; /**< new seg flags will be initialized to this */ + uint16_t zero_copy_size; /**< use zero copy for app layer above segments + * of this size */ + uint32_t prealloc_sessions; /**< ssns to prealloc per stream thread */ int midstream; int async_oneside; diff --git a/suricata.yaml.in b/suricata.yaml.in index 04cb3b228571..2bb208381eee 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -785,6 +785,11 @@ flow-timeouts: # - size: 4 # Size of the (data)segment for a pool # prealloc: 256 # Number of segments to prealloc and keep # # in the pool. +# zero-copy-size: 128 # This option sets in bytes the value at +# # which segment data is passed to the app +# # layer API directly. Data sizes equal to +# # and higher than the value set are passed +# # on directly. # stream: memcap: 32mb @@ -816,6 +821,7 @@ stream: # prealloc: 1024 # - size: 65535 # prealloc: 128 + #zero-copy-size: 128 # Host table: # From a0732d3db23538689af9432e012d26241996b99b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2015 13:18:51 +0100 Subject: [PATCH 0216/2553] flow: change flow state logic A flow has 3 states: NEW, ESTABLISHED and CLOSED. For all protocols except TCP, a flow is in state NEW as long as just one side of the conversation has been seen. When both sides have been observed the state is moved to ESTABLISHED. TCP has a different logic, controlled by the stream engine. Here the TCP state is leading. Until now, when parts of the engine needed to know the flow state, it would invoke a per protocol callback 'GetProtoState'. For TCP this would return the state based on the TcpSession. This patch changes this logic. It introduces an atomic variable in the flow 'flow_state'. It defaults to NEW and is set to ESTABLISHED for non- TCP protocols when we've seen both sides of the conversation. For TCP, the state is updated from the TCP engine directly. The goal is to allow for access to the state without holding the Flow's main mutex lock. This will later allow the Flow Manager(s) to evaluate the Flow w/o interupting it. --- src/flow-hash.c | 2 +- src/flow-manager.c | 12 +++++----- src/flow-private.h | 19 ---------------- src/flow-util.h | 3 +++ src/flow.c | 25 ++++----------------- src/flow.h | 11 +++++++-- src/stream-tcp.c | 56 +++++++++++++--------------------------------- 7 files changed, 39 insertions(+), 89 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index 698b5bd7078e..03e1df6b701d 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -666,7 +666,7 @@ static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv) f->fb = NULL; FBLOCK_UNLOCK(fb); - int state = FlowGetFlowState(f); + int state = SC_ATOMIC_GET(f->flow_state); if (state == FLOW_STATE_NEW) f->flow_end_flags |= FLOW_END_FLAG_STATE_NEW; else if (state == FLOW_STATE_ESTABLISHED) diff --git a/src/flow-manager.c b/src/flow-manager.c index 5aa975f7c488..72d6ce535f08 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -280,7 +280,7 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, Flow *next_flow = f->hprev; - int state = FlowGetFlowState(f); + int state = SC_ATOMIC_GET(f->flow_state); /* timeout logic goes here */ if (FlowManagerFlowTimeout(f, state, ts, emergency) == 0) { @@ -413,7 +413,7 @@ static uint32_t FlowManagerHashRowCleanup(Flow *f) Flow *next_flow = f->hprev; - int state = FlowGetFlowState(f); + int state = SC_ATOMIC_GET(f->flow_state); /* remove from the hash */ if (f->hprev != NULL) @@ -1034,7 +1034,7 @@ static int FlowMgrTest01 (void) f.proto = IPPROTO_TCP; - int state = FlowGetFlowState(&f); + int state = SC_ATOMIC_GET(f.flow_state); if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); @@ -1093,7 +1093,7 @@ static int FlowMgrTest02 (void) f.fb = &fb; f.proto = IPPROTO_TCP; - int state = FlowGetFlowState(&f); + int state = SC_ATOMIC_GET(f.flow_state); if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); @@ -1140,7 +1140,7 @@ static int FlowMgrTest03 (void) f.proto = IPPROTO_TCP; f.flags |= FLOW_EMERGENCY; - int state = FlowGetFlowState(&f); + int state = SC_ATOMIC_GET(f.flow_state); if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); @@ -1200,7 +1200,7 @@ static int FlowMgrTest04 (void) f.proto = IPPROTO_TCP; f.flags |= FLOW_EMERGENCY; - int state = FlowGetFlowState(&f); + int state = SC_ATOMIC_GET(f.flow_state); if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); diff --git a/src/flow-private.h b/src/flow-private.h index 2c7b8f6dbdd7..bd25960b2bf0 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -96,24 +96,5 @@ uint32_t flowbits_removed; SCMutex flowbits_mutex; #endif /* FLOWBITS_STATS */ -/** \internal - * \brief Get the flow's state - * - * \param f flow - * - * \retval state either FLOW_STATE_NEW, FLOW_STATE_ESTABLISHED or FLOW_STATE_CLOSED - */ -static inline int FlowGetFlowState(Flow *f) -{ - if (flow_proto[f->protomap].GetProtoState != NULL) { - return flow_proto[f->protomap].GetProtoState(f->protoctx); - } else { - if ((f->flags & FLOW_TO_SRC_SEEN) && (f->flags & FLOW_TO_DST_SEEN)) - return FLOW_STATE_ESTABLISHED; - else - return FLOW_STATE_NEW; - } -} - #endif /* __FLOW_PRIVATE_H__ */ diff --git a/src/flow-util.h b/src/flow-util.h index 8ed6fd88040f..152b409836c8 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -40,6 +40,7 @@ (f)->sp = 0; \ (f)->dp = 0; \ (f)->proto = 0; \ + SC_ATOMIC_INIT((f)->flow_state); \ SC_ATOMIC_INIT((f)->use_cnt); \ (f)->probing_parser_toserver_alproto_masks = 0; \ (f)->probing_parser_toclient_alproto_masks = 0; \ @@ -82,6 +83,7 @@ (f)->sp = 0; \ (f)->dp = 0; \ (f)->proto = 0; \ + SC_ATOMIC_RESET((f)->flow_state); \ SC_ATOMIC_RESET((f)->use_cnt); \ (f)->probing_parser_toserver_alproto_masks = 0; \ (f)->probing_parser_toclient_alproto_masks = 0; \ @@ -116,6 +118,7 @@ #define FLOW_DESTROY(f) do { \ FlowCleanupAppLayer((f)); \ + SC_ATOMIC_DESTROY((f)->flow_state); \ SC_ATOMIC_DESTROY((f)->use_cnt); \ \ FLOWLOCK_DESTROY((f)); \ diff --git a/src/flow.c b/src/flow.c index 516e684e946f..2546e5289e84 100644 --- a/src/flow.c +++ b/src/flow.c @@ -87,7 +87,6 @@ void FlowInitFlowProto(); 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 *)); /* Run mode selected at suricata.c */ extern int run_mode; @@ -270,6 +269,10 @@ void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) if ((f->flags & FLOW_TO_DST_SEEN) && (f->flags & FLOW_TO_SRC_SEEN)) { SCLogDebug("pkt %p FLOW_PKT_ESTABLISHED", p); p->flowflags |= FLOW_PKT_ESTABLISHED; + + if (f->proto != IPPROTO_TCP) { + SC_ATOMIC_SET(f->flow_state, FLOW_STATE_ESTABLISHED); + } } /*set the detection bypass flags*/ @@ -497,7 +500,6 @@ void FlowInitFlowProto(void) flow_proto[FLOW_PROTO_DEFAULT].emerg_closed_timeout = FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_DEFAULT].Freefunc = NULL; - flow_proto[FLOW_PROTO_DEFAULT].GetProtoState = NULL; /*TCP*/ flow_proto[FLOW_PROTO_TCP].new_timeout = FLOW_IPPROTO_TCP_NEW_TIMEOUT; flow_proto[FLOW_PROTO_TCP].est_timeout = FLOW_IPPROTO_TCP_EST_TIMEOUT; @@ -509,7 +511,6 @@ void FlowInitFlowProto(void) flow_proto[FLOW_PROTO_TCP].emerg_closed_timeout = FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_TCP].Freefunc = NULL; - flow_proto[FLOW_PROTO_TCP].GetProtoState = NULL; /*UDP*/ flow_proto[FLOW_PROTO_UDP].new_timeout = FLOW_IPPROTO_UDP_NEW_TIMEOUT; flow_proto[FLOW_PROTO_UDP].est_timeout = FLOW_IPPROTO_UDP_EST_TIMEOUT; @@ -521,7 +522,6 @@ void FlowInitFlowProto(void) flow_proto[FLOW_PROTO_UDP].emerg_closed_timeout = FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_UDP].Freefunc = NULL; - flow_proto[FLOW_PROTO_UDP].GetProtoState = NULL; /*ICMP*/ flow_proto[FLOW_PROTO_ICMP].new_timeout = FLOW_IPPROTO_ICMP_NEW_TIMEOUT; flow_proto[FLOW_PROTO_ICMP].est_timeout = FLOW_IPPROTO_ICMP_EST_TIMEOUT; @@ -533,7 +533,6 @@ void FlowInitFlowProto(void) flow_proto[FLOW_PROTO_ICMP].emerg_closed_timeout = FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_ICMP].Freefunc = NULL; - flow_proto[FLOW_PROTO_ICMP].GetProtoState = NULL; /* Let's see if we have custom timeouts defined from config */ const char *new = NULL; @@ -764,22 +763,6 @@ int FlowSetProtoFreeFunc (uint8_t proto, void (*Free)(void *)) return 1; } -/** - * \brief Function to set the function to get protocol specific flow state. - * - * \param proto protocol of which function is needed to be set. - * \param GetFlowState Function pointer which will be called to get state. - */ - -int FlowSetFlowStateFunc (uint8_t proto, int (*GetProtoState)(void *)) -{ - uint8_t proto_map; - proto_map = FlowGetProtoMapping(proto); - - flow_proto[proto_map].GetProtoState = GetProtoState; - return 1; -} - /** * \brief Function to set the timeout values for the specified protocol. * diff --git a/src/flow.h b/src/flow.h index 12cda835aa9c..6f95401aa048 100644 --- a/src/flow.h +++ b/src/flow.h @@ -272,6 +272,13 @@ typedef unsigned int FlowRefCount; typedef unsigned short FlowRefCount; #endif +#ifdef __tile__ +/* Atomic Ints performance better on Tile. */ +typedef unsigned int FlowStateType; +#else +typedef unsigned short FlowStateType; +#endif + /** Local Thread ID */ typedef uint16_t FlowThreadId; @@ -312,6 +319,8 @@ typedef struct Flow_ /* end of flow "header" */ + SC_ATOMIC_DECLARE(FlowStateType, flow_state); + /** how many pkts and stream msgs are using the flow *right now*. This * variable is atomic so not protected by the Flow mutex "m". * @@ -414,7 +423,6 @@ typedef struct FlowProto_ { uint32_t emerg_est_timeout; uint32_t emerg_closed_timeout; void (*Freefunc)(void *); - int (*GetProtoState)(void *); } FlowProto; void FlowHandlePacket (ThreadVars *, DecodeThreadVars *, Packet *); @@ -428,7 +436,6 @@ 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_; diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 2d075797f8e2..dcad82c9ee8d 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -596,7 +596,6 @@ void StreamTcpInitConfig(char quiet) /* set the default free function and flow state function * values. */ FlowSetProtoFreeFunc(IPPROTO_TCP, StreamTcpSessionClear); - FlowSetFlowStateFunc(IPPROTO_TCP, StreamTcpGetFlowState); #ifdef UNITTESTS if (RunmodeIsUnittests()) { @@ -679,6 +678,22 @@ static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn, return; ssn->state = state; + + /* update the flow state */ + switch(ssn->state) { + case TCP_ESTABLISHED: + case TCP_FIN_WAIT1: + case TCP_FIN_WAIT2: + case TCP_CLOSING: + case TCP_CLOSE_WAIT: + SC_ATOMIC_SET(p->flow->flow_state, FLOW_STATE_ESTABLISHED); + break; + case TCP_LAST_ACK: + case TCP_TIME_WAIT: + case TCP_CLOSED: + SC_ATOMIC_SET(p->flow->flow_state, FLOW_STATE_CLOSED); + break; + } } /** @@ -5038,45 +5053,6 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) return 0; } -/** - * \brief Function to return the FLOW state depending upon the TCP session state. - * - * \param s TCP session of which the state has to be returned - * \retval state The FLOW_STATE_ depends upon the TCP sesison state, default is - * FLOW_STATE_CLOSED - */ - -int StreamTcpGetFlowState(void *s) -{ - SCEnter(); - - TcpSession *ssn = (TcpSession *)s; - if (unlikely(ssn == NULL)) { - SCReturnInt(FLOW_STATE_CLOSED); - } - - /* sorted most likely to least likely */ - switch(ssn->state) { - case TCP_ESTABLISHED: - case TCP_FIN_WAIT1: - case TCP_FIN_WAIT2: - case TCP_CLOSING: - case TCP_CLOSE_WAIT: - SCReturnInt(FLOW_STATE_ESTABLISHED); - case TCP_NONE: - case TCP_SYN_SENT: - case TCP_SYN_RECV: - case TCP_LISTEN: - SCReturnInt(FLOW_STATE_NEW); - case TCP_LAST_ACK: - case TCP_TIME_WAIT: - case TCP_CLOSED: - SCReturnInt(FLOW_STATE_CLOSED); - } - - SCReturnInt(FLOW_STATE_CLOSED); -} - /** * \brief Function to check the validity of the received timestamp based on * the target OS of the given stream. From 5587372ce15cf3ead98867e1daf3dd010529b4ad Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2015 13:46:25 +0100 Subject: [PATCH 0217/2553] flow: modify lastts update logic In the lastts timeval struct field in the flow the timestamp of the last packet to update is recorded. This allows for tracking the timeout of the flow. So far, this value was updated under the flow lock and also read under the flow lock. This patch moves the updating of this field to the FlowGetFlowFromHash function, where it updated at the point where both the Flow and the Flow Hash Row lock are held. This guarantees that the field is only updated when both locks are held. This makes reading the field safe when either lock is held, which is the purpose of this patch. The flow manager, while holding the flow hash row lock, can now safely read the lastts value. This allows it to do the flow timeout check without actually locking the flow. --- src/flow-hash.c | 12 ++++++++++++ src/flow.c | 3 --- src/flow.h | 4 +++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index 03e1df6b701d..a2ce5708c96a 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -529,6 +529,9 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p FlowInit(f, p); f->fb = fb; + /* update the last seen timestamp of this flow */ + COPY_TIMESTAMP(&p->ts,&f->lastts); + FBLOCK_UNLOCK(fb); FlowHashCountUpdate; return f; @@ -564,6 +567,9 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p FlowInit(f, p); f->fb = fb; + /* update the last seen timestamp of this flow */ + COPY_TIMESTAMP(&p->ts,&f->lastts); + FBLOCK_UNLOCK(fb); FlowHashCountUpdate; return f; @@ -589,6 +595,9 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* found our flow, lock & return */ FLOWLOCK_WRLOCK(f); + /* update the last seen timestamp of this flow */ + COPY_TIMESTAMP(&p->ts,&f->lastts); + FBLOCK_UNLOCK(fb); FlowHashCountUpdate; return f; @@ -598,6 +607,9 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* lock & return */ FLOWLOCK_WRLOCK(f); + /* update the last seen timestamp of this flow */ + COPY_TIMESTAMP(&p->ts,&f->lastts); + FBLOCK_UNLOCK(fb); FlowHashCountUpdate; return f; diff --git a/src/flow.c b/src/flow.c index 2546e5289e84..018e1fe64836 100644 --- a/src/flow.c +++ b/src/flow.c @@ -246,9 +246,6 @@ void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) /* Point the Packet at the Flow */ FlowReference(&p->flow, f); - /* update the last seen timestamp of this flow */ - COPY_TIMESTAMP(&p->ts,&f->lastts); - /* update flags and counters */ if (FlowGetPacketDirection(f, p) == TOSERVER) { if (FlowUpdateSeenFlag(p)) { diff --git a/src/flow.h b/src/flow.h index 6f95401aa048..fc1ea3d8ef4a 100644 --- a/src/flow.h +++ b/src/flow.h @@ -337,7 +337,9 @@ typedef struct Flow_ uint32_t flags; - /* time stamp of last update (last packet) */ + /* time stamp of last update (last packet). Set/updated under the + * flow and flow hash row locks, safe to read under either the + * flow lock or flow hash row lock. */ struct timeval lastts; #ifdef FLOWLOCK_RWLOCK From 5251ea9ff5a8b419cb3f642606a036210c6e0bd1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2015 14:10:11 +0100 Subject: [PATCH 0218/2553] flow: lockless flow manager checks Until this point, the flow manager would check for timed out flows by walking the flow hash, locking first the hash row and then each individual flow to get it's state and timestamp. To not be too intrusive trylocks were used so that a busy flow wouldn't cause the flow manager to wait for a long time while holding the hash row lock. Building on the changes in handling of the flow state and lastts fields, this patch changes the flow managers behavior. It can now get a flows state atomically and the lastts can be safely read while holding just the flow hash row lock. This allows the flow manager to do the basic time out check much more cheaply: 1. it doesn't have to wait for getting a lock 2. it doesn't interupt the packet path As a consequence the trylock is now also gone. A flow that returns 'true' on timeout is pretty much certainly not going to be busy so we can safely lock it unconditionally. This also means the flow manager now walks the entire row unconditionally and is guaranteed to inspect each flow in the row. To make sure the functions called before the flow lock don't accidentally change the flow (which would require a lock) the args to these flows are changed to const pointers. --- src/flow-manager.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 72d6ce535f08..217681c609bc 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -163,7 +163,7 @@ void FlowKillFlowManagerThread(void) * * \retval timeout timeout in seconds */ -static inline uint32_t FlowGetFlowTimeout(Flow *f, int state, int emergency) +static inline uint32_t FlowGetFlowTimeout(const Flow *f, int state, int emergency) { uint32_t timeout; @@ -208,7 +208,7 @@ static inline uint32_t FlowGetFlowTimeout(Flow *f, int state, int emergency) * \retval 0 not timed out * \retval 1 timed out */ -static int FlowManagerFlowTimeout(Flow *f, int state, struct timeval *ts, int emergency) +static int FlowManagerFlowTimeout(const Flow *f, int state, struct timeval *ts, int emergency) { /* set the timeout value according to the flow operating mode, * flow's state and protocol.*/ @@ -273,22 +273,23 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, uint32_t cnt = 0; do { - if (FLOWLOCK_TRYWRLOCK(f) != 0) { - f = f->hprev; - continue; - } - - Flow *next_flow = f->hprev; + /* check flow timeout based on lastts and state. Both can be + * accessed w/o Flow lock as we do have the hash row lock (so flow + * can't disappear) and flow_state is atomic. lastts can only + * be modified when we have both the flow and hash row lock */ int state = SC_ATOMIC_GET(f->flow_state); /* timeout logic goes here */ if (FlowManagerFlowTimeout(f, state, ts, emergency) == 0) { - FLOWLOCK_UNLOCK(f); f = f->hprev; continue; } + FLOWLOCK_WRLOCK(f); + + Flow *next_flow = f->hprev; + /* check if the flow is fully timed out and * ready to be discarded. */ if (FlowManagerFlowTimedOut(f, ts) == 1) { From fbe6dac1ae013d4d118cbe3da2fe9351f19dd9d4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Jan 2015 19:24:35 +0100 Subject: [PATCH 0219/2553] file: optimize file pruning FilePrune would clear the files, but not free them and remove them from the list. This lead to ever growing lists in some cases. Especially in HTTP sessions with many transactions, this could slow us down. --- src/util-file.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/util-file.c b/src/util-file.c index 7788413ff32c..908dc19b1b62 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -132,7 +132,7 @@ static int FileAppendFileData(FileContainer *ffc, FileData *ffd) -static void FilePruneFile(File *file) +static int FilePruneFile(File *file) { SCEnter(); @@ -141,7 +141,7 @@ static void FilePruneFile(File *file) if (!(file->flags & FILE_NOMAGIC)) { /* need magic but haven't set it yet, bail out */ if (file->magic == NULL) - SCReturn; + SCReturnInt(0); else SCLogDebug("file->magic %s", file->magic); } else { @@ -168,19 +168,36 @@ static void FilePruneFile(File *file) #endif } else if (fd->stored == 0) { fd = NULL; + SCReturnInt(0); break; } } - SCReturn; + if (file->state >= FILE_STATE_CLOSED) + SCReturnInt(1); + else + SCReturnInt(0); } void FilePrune(FileContainer *ffc) { - File *file; + File *file = ffc->head; + + while (file) { + if (FilePruneFile(file) == 0) + break; + + BUG_ON(file != ffc->head); + + File *file_next = file->next; + + /* update head and tail */ + ffc->head = file_next; + if (file == ffc->tail) + ffc->tail = NULL; - for (file = ffc->head; file != NULL; file = file->next) { - FilePruneFile(file); + FileFree(file); + file = file_next; } } From e58fd3cc6e29312e957f8b78b43a7115883b4eb8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Jan 2015 10:20:37 +0100 Subject: [PATCH 0220/2553] runmodes: add funcs to check if file loggers enabled Add functions to check if file/filedata loggers are enabled. --- src/runmodes.c | 10 ++++++++++ src/runmodes.h | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/src/runmodes.c b/src/runmodes.c index 4f658ce56e00..ce84f78c01e5 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -436,6 +436,16 @@ static TmModule *file_logger_module = NULL; static TmModule *filedata_logger_module = NULL; static TmModule *streaming_logger_module = NULL; +int RunModeOutputFileEnabled(void) +{ + return (file_logger_module != NULL); +} + +int RunModeOutputFiledataEnabled(void) +{ + return (filedata_logger_module != NULL); +} + /** * Cleanup the run mode. */ diff --git a/src/runmodes.h b/src/runmodes.h index caf09a945747..ba155c713477 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -72,6 +72,11 @@ void RunModeInitializeOutputs(void); void SetupOutputs(ThreadVars *); void RunModeShutDown(void); +/* bool indicating if file logger is enabled */ +int RunModeOutputFileEnabled(void); +/* bool indicating if filedata logger is enabled */ +int RunModeOutputFiledataEnabled(void); + #include "runmode-pcap.h" #include "runmode-pcap-file.h" #include "runmode-pfring.h" From c58b2b4b18375781d56384c5c2e123c6a2fa3e31 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Jan 2015 10:22:01 +0100 Subject: [PATCH 0221/2553] file: improve file pruning Check if file has been logged/stored before considering it 'done'. --- src/util-file.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/util-file.c b/src/util-file.c index 908dc19b1b62..ec5e4df4f1bc 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -28,6 +28,7 @@ #include "debug.h" #include "flow.h" #include "stream.h" +#include "runmodes.h" #include "util-hash.h" #include "util-debug.h" #include "util-memcmp.h" @@ -173,10 +174,15 @@ static int FilePruneFile(File *file) } } - if (file->state >= FILE_STATE_CLOSED) + /* file is done when state is closed+, logging/storing is done (if any) */ + if (file->state >= FILE_STATE_CLOSED && + (!RunModeOutputFileEnabled() || (file->flags & FILE_LOGGED)) && + (!RunModeOutputFiledataEnabled() || (file->flags & FILE_STORED))) + { SCReturnInt(1); - else + } else { SCReturnInt(0); + } } void FilePrune(FileContainer *ffc) From cbe934267efa0973b042853cd36a99c2b3c83941 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Jan 2015 10:22:55 +0100 Subject: [PATCH 0222/2553] file: register filedata log before file log This way the file log can log the 'stored' info that the filedata log sets. --- src/runmodes.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/runmodes.c b/src/runmodes.c index ce84f78c01e5..35f4e0739aeb 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -562,47 +562,47 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); SCLogDebug("__tx_logger__ added"); } - } else if (module->FileLogFunc) { - SCLogDebug("%s is a file logger", module->name); - OutputRegisterFileLogger(module->name, module->FileLogFunc, output_ctx); + } else if (module->FiledataLogFunc) { + SCLogDebug("%s is a filedata logger", module->name); + OutputRegisterFiledataLogger(module->name, module->FiledataLogFunc, output_ctx); /* need one instance of the tx logger module */ - if (file_logger_module == NULL) { - file_logger_module = TmModuleGetByName("__file_logger__"); - if (file_logger_module == NULL) { + if (filedata_logger_module == NULL) { + filedata_logger_module = TmModuleGetByName("__filedata_logger__"); + if (filedata_logger_module == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __file_logger__ failed"); + "TmModuleGetByName for __filedata_logger__ failed"); exit(EXIT_FAILURE); } RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); if (unlikely(runmode_output == NULL)) return; - runmode_output->tm_module = file_logger_module; + runmode_output->tm_module = filedata_logger_module; runmode_output->output_ctx = NULL; TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); - SCLogDebug("__file_logger__ added"); + SCLogDebug("__filedata_logger__ added"); } - } else if (module->FiledataLogFunc) { - SCLogDebug("%s is a filedata logger", module->name); - OutputRegisterFiledataLogger(module->name, module->FiledataLogFunc, output_ctx); + } else if (module->FileLogFunc) { + SCLogDebug("%s is a file logger", module->name); + OutputRegisterFileLogger(module->name, module->FileLogFunc, output_ctx); /* need one instance of the tx logger module */ - if (filedata_logger_module == NULL) { - filedata_logger_module = TmModuleGetByName("__filedata_logger__"); - if (filedata_logger_module == NULL) { + if (file_logger_module == NULL) { + file_logger_module = TmModuleGetByName("__file_logger__"); + if (file_logger_module == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __filedata_logger__ failed"); + "TmModuleGetByName for __file_logger__ failed"); exit(EXIT_FAILURE); } RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); if (unlikely(runmode_output == NULL)) return; - runmode_output->tm_module = filedata_logger_module; + runmode_output->tm_module = file_logger_module; runmode_output->output_ctx = NULL; TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); - SCLogDebug("__filedata_logger__ added"); + SCLogDebug("__file_logger__ added"); } } else if (module->StreamingLogFunc) { SCLogDebug("%s is a streaming logger", module->name); From 10104066e17a59769467cc5350eac59ee37404f1 Mon Sep 17 00:00:00 2001 From: gureedo Date: Sat, 13 Dec 2014 16:12:40 +0500 Subject: [PATCH 0223/2553] netmap support --- configure.ac | 17 + src/Makefile.am | 2 + src/decode.h | 4 + src/runmode-netmap.c | 439 ++++++++++++++++++ src/runmode-netmap.h | 33 ++ src/runmodes.c | 10 + src/runmodes.h | 2 + src/source-netmap.c | 999 ++++++++++++++++++++++++++++++++++++++++ src/source-netmap.h | 62 +++ src/suricata.c | 62 +++ src/tm-modules.c | 2 + src/tm-threads-common.h | 2 + src/util-error.c | 3 + src/util-error.h | 3 + suricata.yaml.in | 33 ++ 15 files changed, 1673 insertions(+) create mode 100644 src/runmode-netmap.c create mode 100644 src/runmode-netmap.h create mode 100644 src/source-netmap.c create mode 100644 src/source-netmap.h diff --git a/configure.ac b/configure.ac index fb4dfefe7098..0cbba4477128 100644 --- a/configure.ac +++ b/configure.ac @@ -1055,6 +1055,22 @@ [[#include ]]) ]) + # Netmap support + AC_ARG_ENABLE(netmap, + AS_HELP_STRING([--enable-netmap], [Enable Netmap support]),,[enable_netmap=no]) + AC_ARG_WITH(netmap_includes, + [ --with-netmap-includes=DIR netmap include directory], + [with_netmap_includes="$withval"],[with_netmap_includes=no]) + + AS_IF([test "x$enable_netmap" = "xyes"], [ + CFLAGS="$CFLAGS -DHAVE_NETMAP" + + if test "$with_netmap_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_netmap_includes}" + fi + + AC_CHECK_HEADER(net/netmap_user.h,,[AC_ERROR(net/netmap_user.h not found ...)],) + ]) # libhtp AC_ARG_ENABLE(non-bundled-htp, @@ -1717,6 +1733,7 @@ SURICATA_BUILD_CONF="Suricata Configuration: NFQueue support: ${enable_nfqueue} NFLOG support: ${enable_nflog} IPFW support: ${enable_ipfw} + Netmap support: ${enable_netmap} DAG enabled: ${enable_dag} Napatech enabled: ${enable_napatech} Unix socket enabled: ${enable_unixsocket} diff --git a/src/Makefile.am b/src/Makefile.am index d60f56c4b9b9..582247e7623c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -249,6 +249,7 @@ runmode-erf-dag.c runmode-erf-dag.h \ runmode-erf-file.c runmode-erf-file.h \ runmode-ipfw.c runmode-ipfw.h \ runmode-napatech.c runmode-napatech.h \ +runmode-netmap.c runmode-netmap.h \ runmode-nfq.c runmode-nfq.h \ runmode-nflog.c runmode-nflog.h \ runmode-pcap.c runmode-pcap.h \ @@ -264,6 +265,7 @@ source-erf-file.c source-erf-file.h \ source-ipfw.c source-ipfw.h \ source-mpipe.c source-mpipe.h \ source-napatech.c source-napatech.h \ +source-netmap.c source-netmap.h \ source-nfq.c source-nfq.h \ source-nflog.c source-nflog.h \ source-pcap.c source-pcap.h \ diff --git a/src/decode.h b/src/decode.h index bd9aeef61b99..9b16e036ccc0 100644 --- a/src/decode.h +++ b/src/decode.h @@ -61,6 +61,7 @@ enum PktSrcEnum { #include "source-pcap.h" #include "source-af-packet.h" #include "source-mpipe.h" +#include "source-netmap.h" #include "action-globals.h" @@ -414,6 +415,9 @@ typedef struct Packet_ /* tilegx mpipe stuff */ MpipePacketVars mpipe_v; #endif +#ifdef HAVE_NETMAP + NetmapPacketVars netmap_v; +#endif /** libpcap vars: shared by Pcap Live mode and Pcap File mode */ PcapPacketVars pcap_v; diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c new file mode 100644 index 000000000000..f5172aba1aeb --- /dev/null +++ b/src/runmode-netmap.c @@ -0,0 +1,439 @@ +/* Copyright (C) 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. + */ + +/** +* \ingroup netmap +* +* @{ +*/ + +/** +* \file +* +* \author Aleksey Katargin +* +* Netmap runmode +* +*/ + +#include "suricata-common.h" +#include "config.h" +#include "tm-threads.h" +#include "conf.h" +#include "runmodes.h" +#include "runmode-netmap.h" +#include "log-httplog.h" +#include "output.h" +#include "detect-engine-mpm.h" + +#include "alert-fastlog.h" +#include "alert-prelude.h" +#include "alert-unified2-alert.h" +#include "alert-debuglog.h" + +#include "util-debug.h" +#include "util-time.h" +#include "util-cpu.h" +#include "util-affinity.h" +#include "util-device.h" +#include "util-runmodes.h" +#include "util-ioctl.h" + +#include "source-netmap.h" + +extern int max_pending_packets; + +static const char *default_mode_workers = NULL; + +const char *RunModeNetmapGetDefaultMode(void) +{ + return default_mode_workers; +} + +void RunModeIdsNetmapRegister(void) +{ + RunModeRegisterNewRunMode(RUNMODE_NETMAP, "single", + "Single threaded netmap mode", + RunModeIdsNetmapSingle); + RunModeRegisterNewRunMode(RUNMODE_NETMAP, "workers", + "Workers netmap mode, each thread does all" + " tasks from acquisition to logging", + RunModeIdsNetmapWorkers); + default_mode_workers = "workers"; + RunModeRegisterNewRunMode(RUNMODE_NETMAP, "autofp", + "Multi threaded netmap mode. Packets from " + "each flow are assigned to a single detect " + "thread.", + RunModeIdsNetmapAutoFp); + return; +} + +#ifdef HAVE_NETMAP + +static void NetmapDerefConfig(void *conf) +{ + NetmapIfaceConfig *pfp = (NetmapIfaceConfig *)conf; + /* config is used only once but cost of this low. */ + if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) { + SCFree(pfp); + } +} + +/** +* \brief extract information from config file +* +* The returned structure will be freed by the thread init function. +* This is thus necessary to or copy the structure before giving it +* to thread or to reparse the file for each thread (and thus have +* new structure. +* +* \return a NetmapIfaceConfig corresponding to the interface name +*/ +static void *ParseNetmapConfig(const char *iface) +{ + char *threadsstr = NULL; + ConfNode *if_root; + ConfNode *if_default = NULL; + ConfNode *netmap_node; + NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); + char *tmpctype; + char *copymodestr; + int boolval; + char *bpf_filter = NULL; + char *out_iface = NULL; + + if (unlikely(aconf == NULL)) { + return NULL; + } + + if (iface == NULL) { + SCFree(aconf); + return NULL; + } + + memset(aconf, 0, sizeof(*aconf)); + strlcpy(aconf->iface, iface, sizeof(aconf->iface)); + SC_ATOMIC_INIT(aconf->ref); + (void) SC_ATOMIC_ADD(aconf->ref, 1); + aconf->DerefFunc = NetmapDerefConfig; + aconf->threads = 1; + aconf->promisc = 1; + aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; + aconf->copy_mode = NETMAP_COPY_MODE_NONE; + + if (ConfGet("bpf-filter", &bpf_filter) == 1) { + if (strlen(bpf_filter) > 0) { + aconf->bpf_filter = bpf_filter; + SCLogInfo("Going to use command-line provided bpf filter '%s'", + aconf->bpf_filter); + } + } + + /* Find initial node */ + netmap_node = ConfGetNode("netmap"); + if (netmap_node == NULL) { + SCLogInfo("Unable to find netmap config using default value"); + return aconf; + } + + if_root = ConfNodeLookupKeyValue(netmap_node, "interface", iface); + + if_default = ConfNodeLookupKeyValue(netmap_node, "interface", "default"); + + if (if_root == NULL && if_default == NULL) { + SCLogInfo("Unable to find netmap config for " + "interface \"%s\" or \"default\", using default value", + iface); + return aconf; + } + + /* If there is no setting for current interface use default one as main iface */ + if (if_root == NULL) { + if_root = if_default; + if_default = NULL; + } + + if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { + aconf->threads = 1; + } else { + if (strcmp(threadsstr, "auto") == 0) { + aconf->threads = GetIfaceRSSQueuesNum(iface); + } else { + aconf->threads = (uint8_t)atoi(threadsstr); + } + } + + if (aconf->threads <= 0) { + aconf->threads = 1; + } + if (aconf->threads) { + SCLogInfo("Using %d threads for interface %s", aconf->threads, iface); + } + + if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { + if (strlen(out_iface) > 0) { + aconf->out_iface = out_iface; + } + } + + if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { + if (aconf->out_iface == NULL) { + SCLogInfo("Copy mode activated but no destination" + " iface. Disabling feature"); + } else if (strlen(copymodestr) <= 0) { + aconf->out_iface = NULL; + } else if (strcmp(copymodestr, "ips") == 0) { + SCLogInfo("Netmap IPS mode activated %s->%s", + iface, + aconf->out_iface); + aconf->copy_mode = NETMAP_COPY_MODE_IPS; + } else if (strcmp(copymodestr, "tap") == 0) { + SCLogInfo("Netmap TAP mode activated %s->%s", + iface, + aconf->out_iface); + aconf->copy_mode = NETMAP_COPY_MODE_TAP; + } else { + SCLogInfo("Invalid mode (not in tap, ips)"); + } + } + + SC_ATOMIC_RESET(aconf->ref); + (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); + + /* load netmap bpf filter */ + /* command line value has precedence */ + if (ConfGet("bpf-filter", &bpf_filter) != 1) { + if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { + if (strlen(bpf_filter) > 0) { + aconf->bpf_filter = bpf_filter; + SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter); + } + } + } + + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); + if (boolval) { + SCLogInfo("Disabling promiscuous mode on iface %s", aconf->iface); + aconf->promisc = 0; + } + + if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { + if (strcmp(tmpctype, "auto") == 0) { + aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; + } else if (strcmp(tmpctype, "yes") == 0) { + aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; + } else if (strcmp(tmpctype, "no") == 0) { + aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; + } else { + SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface); + } + } + + return aconf; +} + +static int NetmapConfigGeThreadsCount(void *conf) +{ + NetmapIfaceConfig *aconf = (NetmapIfaceConfig *)conf; + return aconf->threads; +} + +int NetmapRunModeIsIPS() +{ + int nlive = LiveGetDeviceCount(); + int ldev; + ConfNode *if_root; + ConfNode *if_default = NULL; + ConfNode *netmap_node; + int has_ips = 0; + int has_ids = 0; + + /* Find initial node */ + netmap_node = ConfGetNode("netmap"); + if (netmap_node == NULL) { + return 0; + } + + if_default = ConfNodeLookupKeyValue(netmap_node, "interface", "default"); + + for (ldev = 0; ldev < nlive; ldev++) { + char *live_dev = LiveGetDeviceName(ldev); + if (live_dev == NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); + return 0; + } + char *copymodestr = NULL; + if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev); + + if (if_root == NULL) { + if (if_default == NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); + return 0; + } + if_root = if_default; + } + + if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { + if (strcmp(copymodestr, "ips") == 0) { + has_ips = 1; + } else { + has_ids = 1; + } + } else { + has_ids = 1; + } + } + + if (has_ids && has_ips) { + SCLogInfo("Netmap mode using IPS and IDS mode"); + for (ldev = 0; ldev < nlive; ldev++) { + char *live_dev = LiveGetDeviceName(ldev); + if (live_dev == NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); + return 0; + } + if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev); + char *copymodestr = NULL; + + if (if_root == NULL) { + if (if_default == NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); + return 0; + } + if_root = if_default; + } + + if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) && + (strcmp(copymodestr, "ips") == 0))) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Netmap IPS mode used and interface '%s' is in IDS or TAP mode. " + "Sniffing '%s' but expect bad result as stream-inline is activated.", + live_dev, live_dev); + } + } + } + + return has_ips; +} + +#endif // #ifdef HAVE_NETMAP + +int RunModeIdsNetmapAutoFp(DetectEngineCtx *de_ctx) +{ + SCEnter(); + +#ifdef HAVE_NETMAP + int ret; + char *live_dev = NULL; + + RunModeInitialize(); + + TimeModeSetLive(); + + (void)ConfGet("netmap.live-interface", &live_dev); + + SCLogDebug("live_dev %s", live_dev); + + ret = RunModeSetLiveCaptureAutoFp(de_ctx, + ParseNetmapConfig, + NetmapConfigGeThreadsCount, + "ReceiveNetmap", + "DecodeNetmap", "RxNetmap", + live_dev); + if (ret != 0) { + SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); + exit(EXIT_FAILURE); + } + + SCLogInfo("RunModeIdsNetmapAutoFp initialised"); +#endif /* HAVE_NETMAP */ + + SCReturnInt(0); +} + +/** +* \brief Single thread version of the netmap processing. +*/ +int RunModeIdsNetmapSingle(DetectEngineCtx *de_ctx) +{ + SCEnter(); + +#ifdef HAVE_NETMAP + int ret; + char *live_dev = NULL; + + RunModeInitialize(); + TimeModeSetLive(); + + (void)ConfGet("netmap.live-interface", &live_dev); + + ret = RunModeSetLiveCaptureSingle(de_ctx, + ParseNetmapConfig, + NetmapConfigGeThreadsCount, + "ReceiveNetmap", + "DecodeNetmap", "NetmapPkt", + live_dev); + if (ret != 0) { + SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); + exit(EXIT_FAILURE); + } + + SCLogInfo("RunModeIdsNetmapSingle initialised"); + +#endif /* HAVE_NETMAP */ + SCReturnInt(0); +} + +/** +* \brief Workers version of the netmap processing. +* +* Start N threads with each thread doing all the work. +* +*/ +int RunModeIdsNetmapWorkers(DetectEngineCtx *de_ctx) +{ + SCEnter(); + +#ifdef HAVE_NETMAP + int ret; + char *live_dev = NULL; + + RunModeInitialize(); + TimeModeSetLive(); + + (void)ConfGet("netmap.live-interface", &live_dev); + + ret = RunModeSetLiveCaptureWorkers(de_ctx, + ParseNetmapConfig, + NetmapConfigGeThreadsCount, + "ReceiveNetmap", + "DecodeNetmap", "NetmapPkt", + live_dev); + if (ret != 0) { + SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); + exit(EXIT_FAILURE); + } + + SCLogInfo("RunModeIdsNetmapWorkers initialised"); + +#endif /* HAVE_NETMAP */ + SCReturnInt(0); +} + +/** +* @} +*/ diff --git a/src/runmode-netmap.h b/src/runmode-netmap.h new file mode 100644 index 000000000000..392e9781ca07 --- /dev/null +++ b/src/runmode-netmap.h @@ -0,0 +1,33 @@ +/* Copyright (C) 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 Aleksey Katargin +*/ + +#ifndef __RUNMODE_NETMAP_H__ +#define __RUNMODE_NETMAP_H__ + +int RunModeIdsNetmapSingle(DetectEngineCtx *); +int RunModeIdsNetmapAutoFp(DetectEngineCtx *); +int RunModeIdsNetmapWorkers(DetectEngineCtx *); +void RunModeIdsNetmapRegister(void); +const char *RunModeNetmapGetDefaultMode(void); +int NetmapRunModeIsIPS(); + +#endif /* __RUNMODE_NETMAP_H__ */ diff --git a/src/runmodes.c b/src/runmodes.c index 35f4e0739aeb..4ce80d7a937d 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -133,6 +133,12 @@ static const char *RunModeTranslateModeToName(int runmode) return "MPIPE"; case RUNMODE_AFP_DEV: return "AF_PACKET_DEV"; + case RUNMODE_NETMAP: +#ifdef HAVE_NETMAP + return "NETMAP"; +#else + return "NETMAP(DISABLED)"; +#endif case RUNMODE_UNIX_SOCKET: return "UNIX_SOCKET"; default: @@ -205,6 +211,7 @@ void RunModeRegisterRunModes(void) RunModeErfDagRegister(); RunModeNapatechRegister(); RunModeIdsAFPRegister(); + RunModeIdsNetmapRegister(); RunModeIdsNflogRegister(); RunModeTileMpipeRegister(); RunModeUnixSocketRegister(); @@ -306,6 +313,9 @@ void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_c case RUNMODE_AFP_DEV: custom_mode = RunModeAFPGetDefaultMode(); break; + case RUNMODE_NETMAP: + custom_mode = RunModeNetmapGetDefaultMode(); + break; case RUNMODE_UNIX_SOCKET: custom_mode = RunModeUnixSocketGetDefaultMode(); break; diff --git a/src/runmodes.h b/src/runmodes.h index ba155c713477..80ad652b34b4 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -35,6 +35,7 @@ enum { RUNMODE_ERF_FILE, RUNMODE_DAG, RUNMODE_AFP_DEV, + RUNMODE_NETMAP, RUNMODE_TILERA_MPIPE, RUNMODE_UNITTEST, RUNMODE_NAPATECH, @@ -89,6 +90,7 @@ int RunModeOutputFiledataEnabled(void); #include "runmode-af-packet.h" #include "runmode-nflog.h" #include "runmode-unix-socket.h" +#include "runmode-netmap.h" int threading_set_cpu_affinity; extern float threading_detect_ratio; diff --git a/src/source-netmap.c b/src/source-netmap.c new file mode 100644 index 000000000000..8e36d284d280 --- /dev/null +++ b/src/source-netmap.c @@ -0,0 +1,999 @@ +/* Copyright (C) 2011-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. + */ + +/** +* \defgroup netmap Netmap running mode +* +* @{ +*/ + +/** +* \file +* +* \author Aleksey Katargin +* +* Netmap socket acquisition support +* +*/ + +#include "suricata-common.h" +#include "config.h" +#include "suricata.h" +#include "decode.h" +#include "packet-queue.h" +#include "threads.h" +#include "threadvars.h" +#include "tm-queuehandlers.h" +#include "tm-modules.h" +#include "tm-threads.h" +#include "tm-threads-common.h" +#include "conf.h" +#include "util-debug.h" +#include "util-device.h" +#include "util-error.h" +#include "util-privs.h" +#include "util-optimize.h" +#include "util-checksum.h" +#include "util-ioctl.h" +#include "util-host-info.h" +#include "tmqh-packetpool.h" +#include "source-netmap.h" +#include "runmodes.h" + +#ifdef __SC_CUDA_SUPPORT__ + +#include "util-cuda.h" +#include "util-cuda-buffer.h" +#include "util-mpm-ac.h" +#include "util-cuda-handlers.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "util-cuda-vars.h" + +#endif /* __SC_CUDA_SUPPORT__ */ + +#ifdef HAVE_NETMAP + +#if HAVE_SYS_IOCTL_H +#include +#endif + +#if HAVE_SYS_MMAN_H +#include +#endif + +#include + +#endif /* HAVE_NETMAP */ + +extern int max_pending_packets; + +#ifndef HAVE_NETMAP + +TmEcode NoNetmapSupportExit(ThreadVars *, void *, void **); + +void TmModuleReceiveNetmapRegister (void) +{ + tmm_modules[TMM_RECEIVENETMAP].name = "ReceiveNetmap"; + tmm_modules[TMM_RECEIVENETMAP].ThreadInit = NoNetmapSupportExit; + tmm_modules[TMM_RECEIVENETMAP].Func = NULL; + tmm_modules[TMM_RECEIVENETMAP].ThreadExitPrintStats = NULL; + tmm_modules[TMM_RECEIVENETMAP].ThreadDeinit = NULL; + tmm_modules[TMM_RECEIVENETMAP].RegisterTests = NULL; + tmm_modules[TMM_RECEIVENETMAP].cap_flags = 0; + tmm_modules[TMM_RECEIVENETMAP].flags = TM_FLAG_RECEIVE_TM; +} + +/** +* \brief Registration Function for DecodeNetmap. +* \todo Unit tests are needed for this module. +*/ +void TmModuleDecodeNetmapRegister (void) +{ + tmm_modules[TMM_DECODENETMAP].name = "DecodeNetmap"; + tmm_modules[TMM_DECODENETMAP].ThreadInit = NoNetmapSupportExit; + tmm_modules[TMM_DECODENETMAP].Func = NULL; + tmm_modules[TMM_DECODENETMAP].ThreadExitPrintStats = NULL; + tmm_modules[TMM_DECODENETMAP].ThreadDeinit = NULL; + tmm_modules[TMM_DECODENETMAP].RegisterTests = NULL; + tmm_modules[TMM_DECODENETMAP].cap_flags = 0; + tmm_modules[TMM_DECODENETMAP].flags = TM_FLAG_DECODE_TM; +} + +/** +* \brief this function prints an error message and exits. +*/ +TmEcode NoNetmapSupportExit(ThreadVars *tv, void *initdata, void **data) +{ + SCLogError(SC_ERR_NO_NETMAP,"Error creating thread %s: you do not have " + "support for netmap enabled, please recompile " + "with --enable-netmap", tv->name); + exit(EXIT_FAILURE); +} + +#else /* We have NETMAP support */ + +#define POLL_TIMEOUT 100 + +#if defined(__linux__) +#define POLL_EVENTS (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL) +#else +#define POLL_EVENTS (POLLHUP|POLLERR|POLLNVAL) +#endif + +enum { + NETMAP_OK, + NETMAP_FAILURE, +}; + +enum { + NETMAP_FLAG_ZERO_COPY = 1, +}; + +/** + * \brief Netmap ring isntance. + */ +typedef struct NetmapRing +{ + int fd; + struct netmap_ring *rx; + struct netmap_ring *tx; + SCSpinlock tx_lock; +} NetmapRing; + +/** + * \brief Netmap device instance. + */ +typedef struct NetmapDevice_ +{ + char ifname[IFNAMSIZ]; + void *mem; + size_t memsize; + struct netmap_if *nif; + int rings_cnt; + NetmapRing *rings; + unsigned int ref; + SC_ATOMIC_DECLARE(unsigned int, threads_run); + TAILQ_ENTRY(NetmapDevice_) next; +} NetmapDevice; + +/** + * \brief Module thread local variables. + */ +typedef struct NetmapThreadVars_ +{ + /* receive inteface */ + NetmapDevice *ifsrc; + /* dst interface for IPS mode */ + NetmapDevice *ifdst; + + int ring_from; + int ring_to; + int thread_idx; + int flags; + struct bpf_program bpf_prog; + + /* internal shit */ + TmSlot *slot; + ThreadVars *tv; + LiveDevice *livedev; + + /* copy from config */ + int copy_mode; + ChecksumValidationMode checksum_mode; + + /* counters */ + uint64_t pkts; + uint64_t bytes; + uint64_t drops; + uint16_t capture_kernel_packets; + uint16_t capture_kernel_drops; + + +} NetmapThreadVars; + +typedef TAILQ_HEAD(NetmapDeviceList_, NetmapDevice_) NetmapDeviceList; + +static NetmapDeviceList netmap_devlist = TAILQ_HEAD_INITIALIZER(netmap_devlist); +static SCMutex netmap_devlist_lock = SCMUTEX_INITIALIZER; + +/** + * \brief Get interface flags. + * \param fd Network susbystem file descritor. + * \param ifname Inteface name. + * \return Interface flags or -1 on error + */ +static int NetmapGetIfaceFlags(int fd, const char *ifname) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Unable to get flags for iface \"%s\": %s", + ifname, strerror(errno)); + return -1; + } + +#ifdef OS_FREEBSD + int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); + return flags; +#else + return ifr.ifr_flags; +#endif +} + +/** + * \brief Set interface flags. + * \param fd Network susbystem file descritor. + * \param ifname Inteface name. + * \param flags Flags to set. + * \return Zero on success. + */ +static int NetmapSetIfaceFlags(int fd, const char *ifname, int flags) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +#ifdef OS_FREEBSD + ifr.ifr_flags = flags & 0xffff; + ifr.ifr_flagshigh = flags >> 16; +#else + ifr.ifr_flags = flags; +#endif + + if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Unable to set flags for iface \"%s\": %s", + ifname, strerror(errno)); + return -1; + } + + return 0; +} + +/** + * \brief Open interface in netmap mode. + * \param ifname Interface name. + * \param promisc Enable promiscuous mode. + * \param dev Pointer to requested netmap device instance. + * \param verbose Verbose error logging. + * \return Zero on success. + */ +static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int verbose) +{ + NetmapDevice *pdev = NULL; + struct nmreq nm_req; + + *pdevice = NULL; + + SCMutexLock(&netmap_devlist_lock); + + /* search interface in our already opened list */ + TAILQ_FOREACH(pdev, &netmap_devlist, next) { + if (strcmp(ifname, pdev->ifname) == 0) { + *pdevice = pdev; + pdev->ref++; + SCMutexUnlock(&netmap_devlist_lock); + return 0; + } + } + + /* not found, create new record */ + pdev = SCMalloc(sizeof(*pdev)); + if (unlikely(pdev == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + goto error; + } + + memset(pdev, 0, sizeof(*pdev)); + SC_ATOMIC_INIT(pdev->threads_run); + strlcpy(pdev->ifname, ifname, sizeof(pdev->ifname)); + + /* open netmap */ + int fd = open("/dev/netmap", O_RDWR); + if (fd == -1) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't open netmap device, error %s", + strerror(errno)); + goto error_pdev; + } + + /* check interface is up */ + int if_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (if_fd < 0) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't create control socket for '%s' interface", + ifname); + goto error_fd; + } + int if_flags = NetmapGetIfaceFlags(if_fd, ifname); + if (if_flags == -1) { + if (verbose) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Can not access to interface '%s'", + ifname); + } + close(if_fd); + goto error_fd; + } + if ((if_flags & IFF_UP) == 0) { + if (verbose) { + SCLogError(SC_ERR_NETMAP_CREATE, "Interface '%s' is down", ifname); + } + close(if_fd); + goto error_fd; + } + if (promisc) { + if_flags |= IFF_PROMISC; + NetmapSetIfaceFlags(if_fd, ifname, if_flags); + } + close(if_fd); + + /* query netmap info */ + memset(&nm_req, 0, sizeof(nm_req)); + strlcpy(nm_req.nr_name, ifname, sizeof(nm_req.nr_name)); + nm_req.nr_version = NETMAP_API; + + if (ioctl(fd, NIOCGINFO, &nm_req) != 0) { + if (verbose) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't query netmap for %s, error %s", + ifname, strerror(errno)); + } + goto error_fd; + }; + if (nm_req.nr_rx_rings != nm_req.nr_tx_rings) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Interface '%s' have non-equeal Tx/Rx rings (%"PRIu16"/%"PRIu16")", + ifname, nm_req.nr_rx_rings, nm_req.nr_tx_rings); + goto error_fd; + } + + pdev->rings_cnt = nm_req.nr_rx_rings; + pdev->memsize = nm_req.nr_memsize; + + pdev->rings = SCMalloc(sizeof(*pdev->rings) * pdev->rings_cnt); + if (unlikely(pdev->rings == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + goto error_fd; + } + memset(pdev->rings, 0, sizeof(*pdev->rings) * pdev->rings_cnt); + + /* open individual instance for each ring */ + int success_cnt = 0; + for (int i = 0; i < pdev->rings_cnt; i++) { + NetmapRing *pring = &pdev->rings[i]; + pring->fd = open("/dev/netmap", O_RDWR); + if (pring->fd == -1) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't open netmap device: %s", + strerror(errno)); + break; + } + + nm_req.nr_flags = NR_REG_ONE_NIC; + nm_req.nr_ringid = i | NETMAP_NO_TX_POLL; + if (ioctl(pring->fd, NIOCREGIF, &nm_req) != 0) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't register %s with netmap: %s", + ifname, strerror(errno)); + break; + } + + if (pdev->mem == NULL) { + pdev->mem = mmap(0, pdev->memsize, PROT_WRITE | PROT_READ, + MAP_SHARED, pring->fd, 0); + if (pdev->mem == MAP_FAILED) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't mmap netmap device: %s", + strerror(errno)); + goto error_fd; + } + pdev->nif = NETMAP_IF(pdev->mem, nm_req.nr_offset); + } + + pring->rx = NETMAP_RXRING(pdev->nif, i); + pring->tx = NETMAP_TXRING(pdev->nif, i); + SCSpinInit(&pring->tx_lock, 0); + success_cnt++; + } + + if (success_cnt != pdev->rings_cnt) { + for(int i = 0; i < success_cnt; i++) { + close(pdev->rings[i].fd); + } + SCFree(pdev->rings); + goto error_mem; + } + + close(fd); + *pdevice = pdev; + + TAILQ_INSERT_TAIL(&netmap_devlist, pdev, next); + SCMutexUnlock(&netmap_devlist_lock); + + return 0; + +error_mem: + munmap(pdev->mem, pdev->memsize); +error_fd: + close(fd); +error_pdev: + SCFree(pdev); +error: + SCMutexUnlock(&netmap_devlist_lock); + return -1; +} + +/** + * \brief Close or dereference netmap device instance. + * \param pdev Netmap device instance. + * \return Zero on success. + */ +static int NetmapClose(NetmapDevice *dev) +{ + NetmapDevice *pdev, *tmp; + + SCMutexLock(&netmap_devlist_lock); + + TAILQ_FOREACH_SAFE(pdev, &netmap_devlist, next, tmp) { + if (pdev == dev) { + pdev->ref--; + if (!pdev->ref) { + munmap(pdev->mem, pdev->memsize); + for (int i = 0; i < pdev->rings_cnt; i++) { + NetmapRing *pring = &pdev->rings[i]; + close(pring->fd); + SCSpinDestroy(&pring->tx_lock); + } + SCFree(pdev->rings); + TAILQ_REMOVE(&netmap_devlist, pdev, next); + SCFree(pdev); + } + SCMutexUnlock(&netmap_devlist_lock); + return 0; + } + } + + SCMutexUnlock(&netmap_devlist_lock); + return -1; +} + +/** + * \brief PcapDumpCounters + * \param ntv + */ +static inline void NetmapDumpCounters(NetmapThreadVars *ntv) +{ + SCPerfCounterAddUI64(ntv->capture_kernel_packets, ntv->tv->sc_perf_pca, ntv->pkts); + SCPerfCounterAddUI64(ntv->capture_kernel_drops, ntv->tv->sc_perf_pca, ntv->drops); + (void) SC_ATOMIC_ADD(ntv->livedev->drop, ntv->drops); + (void) SC_ATOMIC_ADD(ntv->livedev->pkts, ntv->pkts); + ntv->drops = 0; + ntv->pkts = 0; +} + +/** + * \brief Init function for ReceiveNetmap. + * \param tv pointer to ThreadVars + * \param initdata pointer to the interface passed from the user + * \param data pointer gets populated with NetmapThreadVars + */ +static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **data) +{ + SCEnter(); + NetmapIfaceConfig *aconf = initdata; + + if (initdata == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL"); + SCReturnInt(TM_ECODE_FAILED); + } + + NetmapThreadVars *ntv = SCMalloc(sizeof(*ntv)); + if (unlikely(ntv == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + goto error; + } + memset(ntv, 0, sizeof(*ntv)); + + ntv->tv = tv; + ntv->checksum_mode = aconf->checksum_mode; + ntv->copy_mode = aconf->copy_mode; + + ntv->livedev = LiveGetDevice(aconf->iface); + if (ntv->livedev == NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); + goto error_ntv; + } + + if (NetmapOpen(aconf->iface, aconf->promisc, &ntv->ifsrc, 1) != 0) { + goto error_ntv; + } + + if (aconf->threads > ntv->ifsrc->rings_cnt) { + SCLogError(SC_ERR_INVALID_VALUE, + "Thread count can't be greater than ring count. " + "Configured %d threads for interfaces '%s' with %u rings.", + aconf->threads, aconf->iface, ntv->ifsrc->rings_cnt); + goto error_src; + } + + do { + ntv->thread_idx = SC_ATOMIC_GET(ntv->ifsrc->threads_run); + } while (SC_ATOMIC_CAS(&ntv->ifsrc->threads_run, ntv->thread_idx, ntv->thread_idx + 1) == 0); + + /* calculate rings borders */ + int tmp = ntv->ifsrc->rings_cnt / aconf->threads; + ntv->ring_from = ntv->thread_idx * tmp; + ntv->ring_to = ntv->ring_from + tmp - 1; + if (ntv->ring_to >= ntv->ifsrc->rings_cnt) + ntv->ring_to = ntv->ifsrc->rings_cnt - 1; + + if (aconf->copy_mode != NETMAP_COPY_MODE_NONE) { + if (NetmapOpen(aconf->out_iface, 0, &ntv->ifdst, 1) != 0) { + goto error_src; + } + } + + /* basic counters */ + ntv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", + ntv->tv, + SC_PERF_TYPE_UINT64, + "NULL"); + ntv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", + ntv->tv, + SC_PERF_TYPE_UINT64, + "NULL"); + + char const *active_runmode = RunmodeGetActive(); + if (active_runmode && !strcmp("workers", active_runmode)) { + ntv->flags |= NETMAP_FLAG_ZERO_COPY; + SCLogInfo("Enabling zero copy mode"); + } + + if (aconf->bpf_filter) { + SCLogInfo("Using BPF '%s' on iface '%s'", + aconf->bpf_filter, ntv->ifsrc->ifname); + if (pcap_compile_nopcap(default_packet_size, /* snaplen_arg */ + LINKTYPE_ETHERNET, /* linktype_arg */ + &ntv->bpf_prog, /* program */ + aconf->bpf_filter, /* const char *buf */ + 1, /* optimize */ + PCAP_NETMASK_UNKNOWN /* mask */ + ) == -1) { + SCLogError(SC_ERR_NETMAP_CREATE, "Filter compilation failed."); + goto error_src; + } + } + + if (GetIfaceOffloading(aconf->iface) == 1) { + SCLogWarning(SC_ERR_NETMAP_CREATE, + "Using mmap mode with GRO or LRO activated can lead to capture problems"); + } + + *data = (void *)ntv; + aconf->DerefFunc(aconf); + SCReturnInt(TM_ECODE_OK); + +error_src: + NetmapClose(ntv->ifsrc); +error_ntv: + SCFree(ntv); +error: + aconf->DerefFunc(aconf); + SCReturnInt(TM_ECODE_FAILED); +} + +/** + * \brief Output packet to destination interface or drop. + * \param ntv Thread local variables. + * \param p Source packet. + */ +static TmEcode NetmapWritePacket(NetmapThreadVars *ntv, Packet *p) +{ + if (ntv->copy_mode == NETMAP_COPY_MODE_IPS) { + if (PACKET_TEST_ACTION(p, ACTION_DROP)) { + return TM_ECODE_OK; + } + } + + /* map src ring_id to dst ring_id */ + int dst_ring_id = p->netmap_v.ring_id % ntv->ifdst->rings_cnt; + NetmapRing *txring = &ntv->ifdst->rings[dst_ring_id]; + NetmapRing *rxring = &ntv->ifsrc->rings[p->netmap_v.ring_id]; + + SCSpinLock(&txring->tx_lock); + + if (!nm_ring_space(txring->tx)) { + ntv->drops++; + SCSpinUnlock(&txring->tx_lock); + return TM_ECODE_FAILED; + } + + struct netmap_slot *rs = &rxring->rx->slot[p->netmap_v.slot_id]; + struct netmap_slot *ts = &txring->tx->slot[txring->tx->cur]; + + /* swap slot buffers */ + uint32_t tmp_idx; + tmp_idx = ts->buf_idx; + ts->buf_idx = rs->buf_idx; + rs->buf_idx = tmp_idx; + + ts->len = rs->len; + + ts->flags |= NS_BUF_CHANGED; + rs->flags |= NS_BUF_CHANGED; + + txring->tx->head = txring->tx->cur = nm_ring_next(txring->tx, txring->tx->cur); + + SCSpinUnlock(&txring->tx_lock); + + return TM_ECODE_OK; +} + +/** + * \brief Packet release routine. + * \param p Packet. + */ +static void NetmapReleasePacket(Packet *p) +{ + NetmapThreadVars *ntv = (NetmapThreadVars *)p->netmap_v.ntv; + + /* Need to be in copy mode and need to detect early release + where Ethernet header could not be set (and pseudo packet) */ + if ((ntv->copy_mode != NETMAP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) { + NetmapWritePacket(ntv, p); + } + + PacketFreeOrRelease(p); +} + +/** + * \brief Read packets from ring and pass them further. + * \param ntv Thread local variables. + * \param ring_id Ring id to read. + */ +static int NetmapRingRead(NetmapThreadVars *ntv, int ring_id) +{ + SCEnter(); + + struct netmap_ring *ring = ntv->ifsrc->rings[ring_id].rx; + uint32_t avail = nm_ring_space(ring); + uint32_t cur = ring->cur; + + while (likely(avail-- > 0)) { + struct netmap_slot *slot = &ring->slot[cur]; + unsigned char *slot_data = (unsigned char *)NETMAP_BUF(ring, slot->buf_idx); + + if (ntv->bpf_prog.bf_len) { + struct pcap_pkthdr pkthdr = { {0, 0}, slot->len, slot->len }; + if (pcap_offline_filter(&ntv->bpf_prog, &pkthdr, slot_data) == 0) { + /* rejected by bpf */ + cur = nm_ring_next(ring, cur); + continue; + } + } + + Packet *p = PacketGetFromQueueOrAlloc(); + if (unlikely(p == NULL)) { + SCReturnInt(NETMAP_FAILURE); + } + + PKT_SET_SRC(p, PKT_SRC_WIRE); + p->livedev = ntv->livedev; + p->datalink = LINKTYPE_ETHERNET; + p->ts = ring->ts; + ntv->pkts++; + ntv->bytes += slot->len; + + /* checksum validation */ + if (ntv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { + p->flags |= PKT_IGNORE_CHECKSUM; + } else if (ntv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { + if (ntv->livedev->ignore_checksum) { + p->flags |= PKT_IGNORE_CHECKSUM; + } else if (ChecksumAutoModeCheck(ntv->pkts, + SC_ATOMIC_GET(ntv->livedev->pkts), + SC_ATOMIC_GET(ntv->livedev->invalid_checksums))) { + ntv->livedev->ignore_checksum = 1; + p->flags |= PKT_IGNORE_CHECKSUM; + } + } + + if (ntv->flags & NETMAP_FLAG_ZERO_COPY) { + if (PacketSetData(p, slot_data, slot->len) == -1) { + TmqhOutputPacketpool(ntv->tv, p); + SCReturnInt(NETMAP_FAILURE); + } else { + p->ReleasePacket = NetmapReleasePacket; + p->netmap_v.ring_id = ring_id; + p->netmap_v.slot_id = cur; + p->netmap_v.ntv = ntv; + } + } else { + if (PacketCopyData(p, slot_data, slot->len) == -1) { + TmqhOutputPacketpool(ntv->tv, p); + SCReturnInt(NETMAP_FAILURE); + } + } + + SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", + GET_PKT_LEN(p), p, GET_PKT_DATA(p)); + + if (TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p) != TM_ECODE_OK) { + TmqhOutputPacketpool(ntv->tv, p); + SCReturnInt(NETMAP_FAILURE); + } + + cur = nm_ring_next(ring, cur); + } + ring->head = ring->cur = cur; + + SCReturnInt(NETMAP_OK); +} + +/** + * \brief Main netmap reading loop function + */ +static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) +{ + SCEnter(); + + TmSlot *s = (TmSlot *)slot; + NetmapThreadVars *ntv = (NetmapThreadVars *)data; + struct pollfd *fds; + int rings_count = ntv->ring_to - ntv->ring_from + 1; + + ntv->slot = s->slot_next; + + fds = SCMalloc(sizeof(*fds) * rings_count); + if (unlikely(fds == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + SCReturnInt(TM_ECODE_FAILED); + } + + for (int i = 0; i < rings_count; i++) { + fds[i].fd = ntv->ifsrc->rings[ntv->ring_from + i].fd; + fds[i].events = POLLIN; + } + + for(;;) { + if (suricata_ctl_flags != 0) { + break; + } + + /* make sure we have at least one packet in the packet pool, + * to prevent us from alloc'ing packets at line rate */ + PacketPoolWait(); + + int r = poll(fds, rings_count, POLL_TIMEOUT); + + if (r < 0) { + /* error */ + if(errno != EINTR) + SCLogError(SC_ERR_NETMAP_READ, + "Error polling netmap from iface '%s': (%d" PRIu32 ") %s", + ntv->ifsrc->ifname, errno, strerror(errno)); + continue; + } else if (r == 0) { + /* no events, timeout */ + SCLogDebug("(%s:%d-%d) Poll timeout", ntv->ifsrc->ifname, + ntv->ring_from, ntv->ring_to); + continue; + } + + for (int i = 0; i < rings_count; i++) { + if (fds[i].revents & POLL_EVENTS) { + if (fds[i].revents & POLLERR) { + SCLogError(SC_ERR_NETMAP_READ, + "Error reading data from iface '%s': (%d" PRIu32 ") %s", + ntv->ifsrc->ifname, errno, strerror(errno)); + } else if (fds[i].revents & POLLNVAL) { + SCLogError(SC_ERR_NETMAP_READ, + "Invalid polling request"); + } + continue; + } + + if (likely(fds[i].revents & POLLIN)) { + int src_ring_id = ntv->ring_from + i; + NetmapRingRead(ntv, src_ring_id); + + if (ntv->copy_mode != NETMAP_COPY_MODE_NONE) { + /* sync dst tx rings */ + int dst_ring_id = src_ring_id % ntv->ifdst->rings_cnt; + NetmapRing *dst_ring = &ntv->ifdst->rings[dst_ring_id]; + if (SCSpinTrylock(&dst_ring->tx_lock) == 0) { + ioctl(dst_ring->fd, NIOCTXSYNC, 0); + SCSpinUnlock(&dst_ring->tx_lock); + } + } + } + } + + NetmapDumpCounters(ntv); + SCPerfSyncCountersIfSignalled(tv); + } + + SCFree(fds); + SCPerfSyncCountersIfSignalled(tv); + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief This function prints stats to the screen at exit. + * \param tv pointer to ThreadVars + * \param data pointer that gets cast into NetmapThreadVars for ntv + */ +static void ReceiveNetmapThreadExitStats(ThreadVars *tv, void *data) +{ + SCEnter(); + NetmapThreadVars *ntv = (NetmapThreadVars *)data; + + NetmapDumpCounters(ntv); + SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 ", bytes %" PRIu64 "", + tv->name, + (uint64_t) SCPerfGetLocalCounterValue(ntv->capture_kernel_packets, tv->sc_perf_pca), + (uint64_t) SCPerfGetLocalCounterValue(ntv->capture_kernel_drops, tv->sc_perf_pca), + ntv->bytes); +} + +/** + * \brief + * \param tv + * \param data Pointer to NetmapThreadVars. + */ +static TmEcode ReceiveNetmapThreadDeinit(ThreadVars *tv, void *data) +{ + SCEnter(); + + NetmapThreadVars *ntv = (NetmapThreadVars *)data; + + if (ntv->ifsrc) { + NetmapClose(ntv->ifsrc); + ntv->ifsrc = NULL; + } + if (ntv->ifdst) { + NetmapClose(ntv->ifdst); + ntv->ifdst = NULL; + } + if (ntv->bpf_prog.bf_insns) { + pcap_freecode(&ntv->bpf_prog); + } + + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief Prepare netmap decode thread. + * \param tv Thread local avariables. + * \param initdata Thread config. + * \param data Pointer to DecodeThreadVars placed here. + */ +static TmEcode DecodeNetmapThreadInit(ThreadVars *tv, void *initdata, void **data) +{ + SCEnter(); + DecodeThreadVars *dtv = NULL; + + dtv = DecodeThreadVarsAlloc(tv); + + if (dtv == NULL) + SCReturnInt(TM_ECODE_FAILED); + + DecodeRegisterPerfCounters(dtv, tv); + + *data = (void *)dtv; + +#ifdef __SC_CUDA_SUPPORT__ + if (CudaThreadVarsInit(&dtv->cuda_vars) < 0) + SCReturnInt(TM_ECODE_FAILED); +#endif + + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief This function passes off to link type decoders. + * + * DecodeNetmap reads packets from the PacketQueue and passes + * them off to the proper link type decoder. + * + * \param t pointer to ThreadVars + * \param p pointer to the current packet + * \param data pointer that gets cast into NetmapThreadVars for ntv + * \param pq pointer to the current PacketQueue + * \param postpq + */ +static TmEcode DecodeNetmap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) +{ + SCEnter(); + + DecodeThreadVars *dtv = (DecodeThreadVars *)data; + + /* XXX HACK: flow timeout can call us for injected pseudo packets + * see bug: https://redmine.openinfosecfoundation.org/issues/1107 */ + if (p->flags & PKT_PSEUDO_STREAM_END) + SCReturnInt(TM_ECODE_OK); + + /* update counters */ + SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + + DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); + + PacketDecodeFinalize(tv, dtv, p); + + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief + * \param tv + * \param data Pointer to DecodeThreadVars. + */ +static TmEcode DecodeNetmapThreadDeinit(ThreadVars *tv, void *data) +{ + SCEnter(); + + if (data != NULL) + DecodeThreadVarsFree(tv, data); + + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief Registration Function for RecieveNetmap. + */ +void TmModuleReceiveNetmapRegister(void) +{ + tmm_modules[TMM_RECEIVENETMAP].name = "ReceiveNetmap"; + tmm_modules[TMM_RECEIVENETMAP].ThreadInit = ReceiveNetmapThreadInit; + tmm_modules[TMM_RECEIVENETMAP].Func = NULL; + tmm_modules[TMM_RECEIVENETMAP].PktAcqLoop = ReceiveNetmapLoop; + tmm_modules[TMM_RECEIVENETMAP].ThreadExitPrintStats = ReceiveNetmapThreadExitStats; + tmm_modules[TMM_RECEIVENETMAP].ThreadDeinit = ReceiveNetmapThreadDeinit; + tmm_modules[TMM_RECEIVENETMAP].RegisterTests = NULL; + tmm_modules[TMM_RECEIVENETMAP].cap_flags = SC_CAP_NET_RAW; + tmm_modules[TMM_RECEIVENETMAP].flags = TM_FLAG_RECEIVE_TM; +} + +/** + * \brief Registration Function for DecodeNetmap. + */ +void TmModuleDecodeNetmapRegister(void) +{ + tmm_modules[TMM_DECODENETMAP].name = "DecodeNetmap"; + tmm_modules[TMM_DECODENETMAP].ThreadInit = DecodeNetmapThreadInit; + tmm_modules[TMM_DECODENETMAP].Func = DecodeNetmap; + tmm_modules[TMM_DECODENETMAP].ThreadExitPrintStats = NULL; + tmm_modules[TMM_DECODENETMAP].ThreadDeinit = DecodeNetmapThreadDeinit; + tmm_modules[TMM_DECODENETMAP].RegisterTests = NULL; + tmm_modules[TMM_DECODENETMAP].cap_flags = 0; + tmm_modules[TMM_DECODENETMAP].flags = TM_FLAG_DECODE_TM; +} + +#endif /* HAVE_NETMAP */ +/* eof */ +/** +* @} +*/ diff --git a/src/source-netmap.h b/src/source-netmap.h new file mode 100644 index 000000000000..42ed91feeff5 --- /dev/null +++ b/src/source-netmap.h @@ -0,0 +1,62 @@ +/* Copyright (C) 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 Aleksey Katargin +*/ + +#ifndef __SOURCE_NETMAP_H__ +#define __SOURCE_NETMAP_H__ + +#include "queue.h" + +/* copy modes */ +enum { + NETMAP_COPY_MODE_NONE, + NETMAP_COPY_MODE_TAP, + NETMAP_COPY_MODE_IPS, +}; + +#define NETMAP_IFACE_NAME_LENGTH 48 + +typedef struct NetmapIfaceConfig_ +{ + char iface[NETMAP_IFACE_NAME_LENGTH]; + int threads; + int promisc; + int copy_mode; + ChecksumValidationMode checksum_mode; + char *bpf_filter; + char *out_iface; + SC_ATOMIC_DECLARE(unsigned int, ref); + void (*DerefFunc)(void *); +} NetmapIfaceConfig; + +typedef struct NetmapPacketVars_ +{ + int ring_id; + int slot_id; + /* NetmapThreadVars */ + void *ntv; +} NetmapPacketVars; + +void TmModuleReceiveNetmapRegister (void); +void TmModuleDecodeNetmapRegister (void); + +#endif /* __SOURCE_NETMAP_H__ */ diff --git a/src/suricata.c b/src/suricata.c index b71d540f3e3d..894b927aa618 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -119,6 +119,7 @@ #include "source-napatech.h" #include "source-af-packet.h" +#include "source-netmap.h" #include "source-mpipe.h" #include "respond-reject.h" @@ -605,6 +606,9 @@ void usage(const char *progname) #ifdef HAVE_AF_PACKET printf("\t--af-packet[=] : run in af-packet mode, no value select interfaces from suricata.yaml\n"); #endif +#ifdef HAVE_NETMAP + printf("\t--netmap[=] : run in netmap mode, no value select interfaces from suricata.yaml\n"); +#endif #ifdef HAVE_PFRING printf("\t--pfring[=] : run in pfring mode, use interfaces from suricata.yaml\n"); printf("\t--pfring-int : run in pfring mode, use interface \n"); @@ -683,6 +687,9 @@ void SCPrintBuildInfo(void) #ifdef HAVE_AF_PACKET strlcat(features, "AF_PACKET ", sizeof(features)); #endif +#ifdef HAVE_NETMAP + strlcat(features, "NETMAP ", sizeof(features)); +#endif #ifdef HAVE_PACKET_FANOUT strlcat(features, "HAVE_PACKET_FANOUT ", sizeof(features)); #endif @@ -844,6 +851,9 @@ void RegisterAllModules() /* af-packet */ TmModuleReceiveAFPRegister(); TmModuleDecodeAFPRegister(); + /* netmap */ + TmModuleReceiveNetmapRegister(); + TmModuleDecodeNetmapRegister(); /* pfring */ TmModuleReceivePfringRegister(); TmModuleDecodePfringRegister(); @@ -1015,6 +1025,26 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) EngineModeSetIPS(); } } +#ifdef HAVE_NETMAP + } else if (run_mode == RUNMODE_NETMAP) { + /* iface has been set on command line */ + if (strlen(pcap_dev)) { + if (ConfSetFinal("netmap.live-interface", pcap_dev) != 1) { + SCLogError(SC_ERR_INITIALIZATION, "Failed to set netmap.live-interface"); + SCReturnInt(TM_ECODE_FAILED); + } + } else { + int ret = LiveBuildDeviceList("netmap"); + if (ret == 0) { + SCLogError(SC_ERR_INITIALIZATION, "No interface found in config for netmap"); + SCReturnInt(TM_ECODE_FAILED); + } + if (NetmapRunModeIsIPS()) { + SCLogInfo("Netmap: Setting IPS mode"); + EngineModeSetIPS(); + } + } +#endif #ifdef HAVE_NFLOG } else if (run_mode == RUNMODE_NFLOG) { int ret = LiveBuildDeviceListCustom("nflog", "group"); @@ -1129,6 +1159,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"pfring-cluster-id", required_argument, 0, 0}, {"pfring-cluster-type", required_argument, 0, 0}, {"af-packet", optional_argument, 0, 0}, + {"netmap", optional_argument, 0, 0}, {"pcap", optional_argument, 0, 0}, #ifdef BUILD_UNIX_SOCKET {"unix-socket", optional_argument, 0, 0}, @@ -1248,6 +1279,36 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) "host, make sure to pass --enable-af-packet to " "configure when building."); return TM_ECODE_FAILED; +#endif + } else if (strcmp((long_opts[option_index]).name , "netmap") == 0){ +#ifdef HAVE_NETMAP + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_NETMAP; + if (optarg) { + LiveRegisterDevice(optarg); + memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); + strlcpy(suri->pcap_dev, optarg, + ((strlen(optarg) < sizeof(suri->pcap_dev)) ? + (strlen(optarg) + 1) : sizeof(suri->pcap_dev))); + } + } else if (suri->run_mode == RUNMODE_NETMAP) { + SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " + "multiple devices to get packets is experimental."); + if (optarg) { + LiveRegisterDevice(optarg); + } else { + SCLogInfo("Multiple netmap option without interface on each is useless"); + break; + } + } else { + SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " + "has been specified"); + usage(argv[0]); + return TM_ECODE_FAILED; + } +#else + SCLogError(SC_ERR_NO_NETMAP, "NETMAP not enabled."); + return TM_ECODE_FAILED; #endif } else if (strcmp((long_opts[option_index]).name, "nflog") == 0) { #ifdef HAVE_NFLOG @@ -1956,6 +2017,7 @@ static int ConfigGetCaptureValue(SCInstance *suri) switch (suri->run_mode) { case RUNMODE_PCAP_DEV: case RUNMODE_AFP_DEV: + case RUNMODE_NETMAP: case RUNMODE_PFRING: /* FIXME this don't work effficiently in multiinterface */ /* find payload for interface and use it */ diff --git a/src/tm-modules.c b/src/tm-modules.c index 19caeca72724..bd990b4e119c 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -269,6 +269,8 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_FLOWRECYCLER); CASE_CODE (TMM_LUALOG); CASE_CODE (TMM_LOGSTATSLOG); + CASE_CODE (TMM_RECEIVENETMAP); + CASE_CODE (TMM_DECODENETMAP); CASE_CODE (TMM_SIZE); } diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 059ba7b12d5f..c18e50876521 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -74,6 +74,8 @@ typedef enum { TMM_DECODEERFDAG, TMM_RECEIVEAFP, TMM_DECODEAFP, + TMM_RECEIVENETMAP, + TMM_DECODENETMAP, TMM_ALERTPCAPINFO, TMM_RECEIVEMPIPE, TMM_DECODEMPIPE, diff --git a/src/util-error.c b/src/util-error.c index e8dd99390231..4ae917191eb0 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -302,6 +302,9 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_WARN_LUA_SCRIPT); CASE_CODE (SC_ERR_LUA_SCRIPT); CASE_CODE (SC_WARN_NO_STATS_LOGGERS); + CASE_CODE (SC_ERR_NO_NETMAP); + CASE_CODE (SC_ERR_NETMAP_CREATE); + CASE_CODE (SC_ERR_NETMAP_READ); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 8d5577d8efa3..9e9008a66c49 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -291,6 +291,9 @@ typedef enum { SC_WARN_LUA_SCRIPT, SC_ERR_LUA_SCRIPT, SC_WARN_NO_STATS_LOGGERS, + SC_ERR_NO_NETMAP, + SC_ERR_NETMAP_CREATE, + SC_ERR_NETMAP_READ, } SCError; const char *SCErrorToString(SCError); diff --git a/suricata.yaml.in b/suricata.yaml.in index 2bb208381eee..5caa0031e647 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -453,6 +453,39 @@ af-packet: #threads: auto #use-mmap: yes +# netmap support +netmap: + - interface: eth2 + # Number of receive threads. "auto" uses number of RSS queues on interface. + threads: auto + # You can use the following variables to activate netmap tap or IPS mode. + # If copy-mode is set to ips or tap, the traffic coming to the current + # interface will be copied to the copy-iface interface. If 'tap' is set, the + # copy is complete. If 'ips' is set, the packet matching a 'drop' action + # will not be copied. + #copy-mode: tap + #copy-iface: eth3 + # Set to yes to disable promiscuous mode + # disable-promisc: no + # Choose checksum verification mode for the interface. At the moment + # of the capture, some packets may be with an invalid checksum due to + # offloading to the network card of the checksum computation. + # Possible values are: + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. + # Warning: 'checksum-validation' must be set to yes to have any validation + #checksum-checks: auto + # BPF filter to apply to this interface. The pcap filter syntax apply here. + #bpf-filter: port 80 or udp + #- interface: eth3 + #threads: auto + #copy-mode: tap + #copy-iface: eth2 + # Put default values here + - interface: default + legacy: uricontent: enabled From bc2c7f462e79b5000636d5160301ee27dfff0f16 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 5 Feb 2015 09:36:34 +0100 Subject: [PATCH 0224/2553] stats api: call thread deinit API functions Thread deinit funcs weren't called. This meant the lua scripts 'deinit' functions weren't called either. --- src/counters.c | 6 ++++++ src/util-error.c | 1 + src/util-error.h | 1 + 3 files changed, 8 insertions(+) diff --git a/src/counters.c b/src/counters.c index 01e80b4e17bd..197fe79ec6d8 100644 --- a/src/counters.c +++ b/src/counters.c @@ -320,6 +320,12 @@ static void *SCPerfMgmtThread(void *arg) TmThreadsSetFlag(tv_local, THV_RUNNING_DONE); TmThreadWaitForFlag(tv_local, THV_DEINIT); + r = tm->ThreadDeinit(tv_local, stats_thread_data); + if (r != TM_ECODE_OK) { + SCLogError(SC_ERR_THREAD_DEINIT, "Perf Counter API " + "ThreadDeinit failed"); + } + TmThreadsSetFlag(tv_local, THV_CLOSED); return NULL; } diff --git a/src/util-error.c b/src/util-error.c index 4ae917191eb0..d352a07e5caf 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -114,6 +114,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_THREAD_SPAWN); CASE_CODE (SC_ERR_THREAD_CREATE); CASE_CODE (SC_ERR_THREAD_INIT); + CASE_CODE (SC_ERR_THREAD_DEINIT); CASE_CODE (SC_ERR_THRESHOLD_HASH_ADD); CASE_CODE (SC_ERR_UNDEFINED_VAR); CASE_CODE (SC_ERR_RULE_KEYWORD_UNKNOWN); diff --git a/src/util-error.h b/src/util-error.h index 9e9008a66c49..019d0179e56f 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -294,6 +294,7 @@ typedef enum { SC_ERR_NO_NETMAP, SC_ERR_NETMAP_CREATE, SC_ERR_NETMAP_READ, + SC_ERR_THREAD_DEINIT, /**< thread's deinit function failed */ } SCError; const char *SCErrorToString(SCError); From d834173bb8a7dc6bc73837fe720b3be3867f4194 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 Feb 2015 12:08:20 +0100 Subject: [PATCH 0225/2553] detect-flow: use dedicated flags The flow keyword used flag names that were shared with the Packet::flowflags field. Some of the flags were'nt used by the packet though. This lead to waste of some 'flag space'. This patch defines dedicated flags for the flow keyword and removes the otherwise unused flags from the FLOW_PKT_* space. --- src/detect-engine-analyzer.c | 3 +- src/detect-flow.c | 174 +++++++++++++++++------------------ src/detect-flow.h | 7 ++ src/flow.h | 9 +- 4 files changed, 97 insertions(+), 96 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 3ac8d0802b38..0faf08ec91a5 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -668,7 +668,8 @@ void EngineAnalysisRules(Signature *s, char *line) } DetectFlowData *fd = (DetectFlowData *)sm->ctx; if (fd != NULL) { - if (fd->flags & FLOW_PKT_NOSTREAM) rule_flow_nostream = 1; + if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) + rule_flow_nostream = 1; } } else if (sm->type == DETECT_FLOWBITS) { diff --git a/src/detect-flow.c b/src/detect-flow.c index a7edaed721ca..9c2db944c305 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -121,30 +121,28 @@ int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S if (p->flowflags & FLOW_PKT_ESTABLISHED) { SCLogDebug("FLOW_PKT_ESTABLISHED"); - } else if (p->flowflags & FLOW_PKT_STATELESS) { - SCLogDebug("FLOW_PKT_STATELESS"); } uint8_t cnt = 0; const DetectFlowData *fd = (const DetectFlowData *)ctx; - if ((fd->flags & FLOW_PKT_TOSERVER) && (p->flowflags & FLOW_PKT_TOSERVER)) { + if ((fd->flags & DETECT_FLOW_FLAG_TOSERVER) && (p->flowflags & FLOW_PKT_TOSERVER)) { cnt++; - } else if ((fd->flags & FLOW_PKT_TOCLIENT) && (p->flowflags & FLOW_PKT_TOCLIENT)) { + } else if ((fd->flags & DETECT_FLOW_FLAG_TOCLIENT) && (p->flowflags & FLOW_PKT_TOCLIENT)) { cnt++; } - if ((fd->flags & FLOW_PKT_ESTABLISHED) && (p->flowflags & FLOW_PKT_ESTABLISHED)) { + if ((fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) && (p->flowflags & FLOW_PKT_ESTABLISHED)) { cnt++; - } else if (fd->flags & FLOW_PKT_STATELESS) { + } else if (fd->flags & DETECT_FLOW_FLAG_STATELESS) { cnt++; } if (det_ctx->flags & DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH) { - if (fd->flags & FLOW_PKT_ONLYSTREAM) + if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) cnt++; } else { - if (fd->flags & FLOW_PKT_NOSTREAM) + if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) cnt++; } @@ -214,59 +212,59 @@ DetectFlowData *DetectFlowParse (char *flowstr) if (args[i]) { /* inspect our options and set the flags */ if (strcasecmp(args[i], "established") == 0) { - if (fd->flags & FLOW_PKT_ESTABLISHED) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_ESTABLISHED flag is already set"); + if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_ESTABLISHED flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_STATELESS) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_STATELESS already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_STATELESS) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_STATELESS already set"); goto error; } - fd->flags |= FLOW_PKT_ESTABLISHED; + fd->flags |= DETECT_FLOW_FLAG_ESTABLISHED; } else if (strcasecmp(args[i], "stateless") == 0) { - if (fd->flags & FLOW_PKT_STATELESS) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_STATELESS flag is already set"); + if (fd->flags & DETECT_FLOW_FLAG_STATELESS) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_STATELESS flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_ESTABLISHED) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_STATELESS, FLOW_PKT_ESTABLISHED already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_STATELESS, DETECT_FLOW_FLAG_ESTABLISHED already set"); goto error; } - fd->flags |= FLOW_PKT_STATELESS; + fd->flags |= DETECT_FLOW_FLAG_STATELESS; } else if (strcasecmp(args[i], "to_client") == 0 || strcasecmp(args[i], "from_server") == 0) { - if (fd->flags & FLOW_PKT_TOCLIENT) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_TOCLIENT flag is already set"); + if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_TOCLIENT flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_TOSERVER) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_client, FLOW_PKT_TOSERVER already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_client, DETECT_FLOW_FLAG_TOSERVER already set"); goto error; } - fd->flags |= FLOW_PKT_TOCLIENT; + fd->flags |= DETECT_FLOW_FLAG_TOCLIENT; } else if (strcasecmp(args[i], "to_server") == 0 || strcasecmp(args[i], "from_client") == 0){ - if (fd->flags & FLOW_PKT_TOSERVER) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_TOSERVER flag is already set"); + if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_TOSERVER flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_TOCLIENT) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_server, FLOW_PKT_TO_CLIENT flag already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_server, DETECT_FLOW_FLAG_TO_CLIENT flag already set"); goto error; } - fd->flags |= FLOW_PKT_TOSERVER; + fd->flags |= DETECT_FLOW_FLAG_TOSERVER; } else if (strcasecmp(args[i], "only_stream") == 0) { - if (fd->flags & FLOW_PKT_ONLYSTREAM) { + if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_NOSTREAM) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag, FLOW_PKT_NOSTREAM already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag, DETECT_FLOW_FLAG_NOSTREAM already set"); goto error; } - fd->flags |= FLOW_PKT_ONLYSTREAM; + fd->flags |= DETECT_FLOW_FLAG_ONLYSTREAM; } else if (strcasecmp(args[i], "no_stream") == 0) { - if (fd->flags & FLOW_PKT_NOSTREAM) { + if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_ONLYSTREAM) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag, FLOW_PKT_ONLYSTREAM already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag, DETECT_FLOW_FLAG_ONLYSTREAM already set"); goto error; } - fd->flags |= FLOW_PKT_NOSTREAM; + fd->flags |= DETECT_FLOW_FLAG_NOSTREAM; } else { SCLogError(SC_ERR_INVALID_VALUE, "invalid flow option \"%s\"", args[i]); goto error; @@ -322,18 +320,18 @@ int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, char *flowstr) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); /* set the signature direction flags */ - if (fd->flags & FLOW_PKT_TOSERVER) { + if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) { s->flags |= SIG_FLAG_TOSERVER; - } else if (fd->flags & FLOW_PKT_TOCLIENT) { + } else if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) { s->flags |= SIG_FLAG_TOCLIENT; } else { s->flags |= SIG_FLAG_TOSERVER; s->flags |= SIG_FLAG_TOCLIENT; } - if (fd->flags & FLOW_PKT_ONLYSTREAM) { + if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) { s->flags |= SIG_FLAG_REQUIRE_STREAM; } - if (fd->flags & FLOW_PKT_NOSTREAM) { + if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) { s->flags |= SIG_FLAG_REQUIRE_PACKET; } else { s->init_flags |= SIG_FLAG_INIT_FLOW; @@ -389,10 +387,10 @@ int DetectFlowTestParse02 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("established"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_ESTABLISHED && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -409,10 +407,10 @@ int DetectFlowTestParse03 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("stateless"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_STATELESS && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -429,10 +427,10 @@ int DetectFlowTestParse04 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOCLIENT, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -449,10 +447,10 @@ int DetectFlowTestParse05 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("to_server"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOSERVER, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -469,10 +467,10 @@ int DetectFlowTestParse06 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOCLIENT, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -489,10 +487,10 @@ int DetectFlowTestParse07 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("from_client"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOSERVER, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -509,10 +507,10 @@ int DetectFlowTestParse08 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("established,to_client"); if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { + if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2) { result = 1; } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); + printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -529,10 +527,10 @@ int DetectFlowTestParse09 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client,stateless"); if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { + if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2) { result = 1; } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); + printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -549,10 +547,10 @@ int DetectFlowTestParse10 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,stateless"); if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ + if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2){ result = 1; } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); + printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -569,10 +567,10 @@ int DetectFlowTestParse11 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse(" from_server , stateless "); if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ + if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2){ result = 1; } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); + printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -606,10 +604,10 @@ int DetectFlowTestParseNocase02 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_ESTABLISHED && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -626,10 +624,10 @@ int DetectFlowTestParseNocase03 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("STATELESS"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_STATELESS && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -646,10 +644,10 @@ int DetectFlowTestParseNocase04 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_CLIENT"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOCLIENT, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -666,10 +664,10 @@ int DetectFlowTestParseNocase05 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_SERVER"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOSERVER, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -686,10 +684,10 @@ int DetectFlowTestParseNocase06 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOCLIENT, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -706,10 +704,10 @@ int DetectFlowTestParseNocase07 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_CLIENT"); if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { + if (fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOSERVER, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -726,10 +724,10 @@ int DetectFlowTestParseNocase08 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED,TO_CLIENT"); if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { + if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2) { result = 1; } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); + printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -746,10 +744,10 @@ int DetectFlowTestParseNocase09 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_CLIENT,STATELESS"); if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { + if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2) { result = 1; } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); + printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -766,10 +764,10 @@ int DetectFlowTestParseNocase10 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,STATELESS"); if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ + if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2){ result = 1; } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); + printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -786,10 +784,10 @@ int DetectFlowTestParseNocase11 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse(" FROM_SERVER , STATELESS "); if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ + if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2){ result = 1; } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); + printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } @@ -909,10 +907,10 @@ int DetectFlowTestParse18 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,only_stream"); if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_ONLYSTREAM && fd->match_cnt == 3) { + if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM && fd->match_cnt == 3) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_ONLYSTREAM, 3, + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT + DETECT_FLOW_FLAG_ONLYSTREAM, 3, fd->flags, fd->match_cnt); } DetectFlowFree(fd); @@ -930,10 +928,10 @@ int DetectFlowTestParseNocase18 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,ESTABLISHED,ONLY_STREAM"); if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_ONLYSTREAM && fd->match_cnt == 3) { + if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM && fd->match_cnt == 3) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_ONLYSTREAM, 3, + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT + DETECT_FLOW_FLAG_ONLYSTREAM, 3, fd->flags, fd->match_cnt); } DetectFlowFree(fd); @@ -969,10 +967,10 @@ int DetectFlowTestParse20 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,no_stream"); if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_NOSTREAM && fd->match_cnt == 3) { + if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->flags & DETECT_FLOW_FLAG_NOSTREAM && fd->match_cnt == 3) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_NOSTREAM, 3, + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT + DETECT_FLOW_FLAG_NOSTREAM, 3, fd->flags, fd->match_cnt); } @@ -991,10 +989,10 @@ int DetectFlowTestParseNocase20 (void) DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,ESTABLISHED,NO_STREAM"); if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_NOSTREAM && fd->match_cnt == 3) { + if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->flags & DETECT_FLOW_FLAG_NOSTREAM && fd->match_cnt == 3) { result = 1; } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_NOSTREAM, 3, + printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT + DETECT_FLOW_FLAG_NOSTREAM, 3, fd->flags, fd->match_cnt); } diff --git a/src/detect-flow.h b/src/detect-flow.h index 37e1f970995b..b3774c292f68 100644 --- a/src/detect-flow.h +++ b/src/detect-flow.h @@ -24,6 +24,13 @@ #ifndef __DETECT_FLOW_H__ #define __DETECT_FLOW_H__ +#define DETECT_FLOW_FLAG_TOSERVER 0x01 +#define DETECT_FLOW_FLAG_TOCLIENT 0x02 +#define DETECT_FLOW_FLAG_ESTABLISHED 0x04 +#define DETECT_FLOW_FLAG_STATELESS 0x08 +#define DETECT_FLOW_FLAG_ONLYSTREAM 0x10 +#define DETECT_FLOW_FLAG_NOSTREAM 0x20 + typedef struct DetectFlowData_ { uint8_t flags; /* flags to match */ uint8_t match_cnt; /* number of matches we need */ diff --git a/src/flow.h b/src/flow.h index fc1ea3d8ef4a..bf38fa554306 100644 --- a/src/flow.h +++ b/src/flow.h @@ -170,13 +170,8 @@ typedef struct AppLayerParserState_ AppLayerParserState; #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 +#define FLOW_PKT_TOSERVER_IPONLY_SET 0x08 +#define FLOW_PKT_TOCLIENT_IPONLY_SET 0x10 #define FLOW_END_FLAG_STATE_NEW 0x01 #define FLOW_END_FLAG_STATE_ESTABLISHED 0x02 From 3b05b735928d8bf2bc35097f6cc77a7f9009496e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 10 Feb 2015 12:03:42 +0100 Subject: [PATCH 0226/2553] tcp midstream: fix window scaling If stream is picked by ACK, we can't know the wscale, so we assume it's set to max. Howver, we didn't apply this to the initial window size we set. --- src/stream-tcp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index dcad82c9ee8d..f0952719f2a7 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -982,11 +982,16 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, ssn->flags = STREAMTCP_FLAG_MIDSTREAM; ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED; + /** window scaling for midstream pickups, we can't do much other + * than assume that it's set to the max value: 14 */ + ssn->client.wscale = TCP_WSCALE_MAX; + ssn->server.wscale = TCP_WSCALE_MAX; + /* set the sequence numbers and window */ ssn->client.isn = TCP_GET_SEQ(p) - 1; STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn); ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; - ssn->client.window = TCP_GET_WINDOW(p); + ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; ssn->client.last_ack = TCP_GET_SEQ(p); ssn->client.next_win = ssn->client.last_ack + ssn->client.window; SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", @@ -1005,11 +1010,6 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, "ssn->server.last_ack %"PRIu32"", ssn, ssn->client.last_ack, ssn->server.last_ack); - /** window scaling for midstream pickups, we can't do much other - * than assume that it's set to the max value: 14 */ - ssn->client.wscale = TCP_WSCALE_MAX; - ssn->server.wscale = TCP_WSCALE_MAX; - /* Set the timestamp value for both streams, if packet has timestamp * option enabled.*/ if (p->tcpvars.ts != NULL) { From fb1b03c471700aa8de45b98210647aa91ec950ac Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 15 Dec 2014 15:06:53 +0100 Subject: [PATCH 0227/2553] flow: handle TCP session reuse in flow engine Until now, TCP session reuse was handled in the TCP stream engine. If the state was TCP_CLOSED, a new SYN packet was received and a few other conditions were met, the flow was 'reset' and reused for the 'new' TCP session. There are a number of problems with this approach: - it breaks the normal flow lifecycle wrt timeout, detection, logging - new TCP sessions could come in on different threads due to mismatches in timeouts between suricata and flow balancing hw/nic/drivers - cleanup code was often causing problems - it complicated locking because of the possible thread mismatch This patch implements a different solution, where a new TCP session also gets a new flow. To do this 2 main things needed to be done: 1. the flow engine needed to be aware of when the TCP reuse case was happening 2. the flow engine needs to be able to 'skip' the old flow once it was replaced by a new one To handle (1), a new function TcpSessionPacketSsnReuse() is introduced to check for the TCP reuse conditions. It's called from 'FlowCompare()' for TCP packets / TCP flows that are candidates for reuse. FlowCompare returns FALSE for the 'old' flow in the case of TCP reuse. This in turn will lead to the flow engine not finding a flow for the TCP SYN packet, resulting in the creation of a new flow. To handle (2), FlowCompare flags the 'old' flow. This flag causes future FlowCompare calls to always return FALSE on it. In other words, the flow can't be found anymore. It can only be accessed by: 1. existing packets with a reference to it 2. flow timeout handling as this logic gets the flows from walking the hash directly 3. flow timeout pseudo packets, as they are set up by (2) The old flow will time out normally, as governed by the "tcp closed" flow timeout setting. At timeout, the normal detection, logging and cleanup code will process it. The flagging of a flow making it 'unfindable' in the flow hash is a bit of a hack. The reason for this approach over for example putting the old flow into a forced timeout queue where it could be timed out, is that such a queue could easily become a contention point. The TCP session reuse case can easily be created by an attacker. In case of multiple packet handlers, this could lead to contention on such a flow timeout queue. --- src/flow-hash.c | 27 +++++++++++++++++++++++++++ src/flow.h | 5 ++--- src/stream-tcp.c | 11 +++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index a2ce5708c96a..1fea10a67d39 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -390,10 +390,37 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p) return 0; } +int TcpSessionPacketSsnReuse(const Packet *p, void *tcp_ssn); + static inline int FlowCompare(Flow *f, const Packet *p) { if (p->proto == IPPROTO_ICMP) { return FlowCompareICMPv4(f, p); + } else if (p->proto == IPPROTO_TCP) { + if (CMP_FLOW(f, p) == 0) + return 0; + + /* if this session is 'reused', we don't return it anymore, + * so return false on the compare */ + if (f->flags & FLOW_TCP_REUSED) + return 0; + + /* lets see if we need to consider the existing session for + * reuse: only considering SYN packets. */ + int syn = (p->tcph && ((p->tcph->th_flags & TH_SYN) == TH_SYN)); + int has_protoctx = ((f->protoctx != NULL)); + + /* syn on existing state, need to see if we need to 'reuse' */ + if (unlikely(syn && has_protoctx && FlowGetPacketDirection(f,p) == TOSERVER)) { + if (unlikely(TcpSessionPacketSsnReuse(p, f->protoctx) == 1)) { + /* okay, we need to setup a new flow for this packet. + * Flag the flow that it's been replaced by a new one */ + f->flags |= FLOW_TCP_REUSED; + SCLogDebug("flow obsolete: TCP reuse will use a new flow"); + return 0; + } + } + return 1; } else { return CMP_FLOW(f, p); } diff --git a/src/flow.h b/src/flow.h index bf38fa554306..0570adbc4d80 100644 --- a/src/flow.h +++ b/src/flow.h @@ -46,9 +46,8 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_TO_SRC_SEEN 0x00000001 /** At least on packet from the destination address was seen */ #define FLOW_TO_DST_SEEN 0x00000002 - -// vacany 1x - +/** Don't return this from the flow hash. It has been replaced. */ +#define FLOW_TCP_REUSED 0x00000004 /** no magic on files in this flow */ #define FLOW_FILE_NO_MAGIC_TS 0x00000008 #define FLOW_FILE_NO_MAGIC_TC 0x00000010 diff --git a/src/stream-tcp.c b/src/stream-tcp.c index f0952719f2a7..f6d79eaf96c0 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4386,6 +4386,17 @@ static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p) return 0; } +int TcpSessionPacketSsnReuse(const Packet *p, void *tcp_ssn) +{ + TcpSession *ssn = tcp_ssn; + if (ssn->state == TCP_CLOSED) { + if(!(SEQ_EQ(ssn->client.isn, TCP_GET_SEQ(p)))) + { + return 1; + } + } + return 0; +} /* flow is and stays locked */ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, From d2eea7fd44b2cfcf7b740a249197dcabd88e8675 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 15 Dec 2014 16:01:28 +0100 Subject: [PATCH 0228/2553] tcp reuse: remove old code --- src/stream-tcp.c | 56 ++---------------------------------------------- 1 file changed, 2 insertions(+), 54 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index f6d79eaf96c0..77d9b09a91b8 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4551,60 +4551,8 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, } break; case TCP_CLOSED: - /* TCP session memory is not returned to pool until timeout. - * If in the mean time we receive any other session from - * the same client reusing same port then we switch back to - * tcp state none, but only on a valid SYN that is not a - * resend from our previous session. - * - * We also check it's not a SYN/ACK, all other SYN pkt - * validation is done at StreamTcpPacketStateNone(); - */ - if (PKT_IS_TOSERVER(p) && (p->tcph->th_flags & TH_SYN) && - !(p->tcph->th_flags & TH_ACK) && - !(SEQ_EQ(ssn->client.isn, TCP_GET_SEQ(p)))) - { - SCLogDebug("reusing closed TCP session"); - - /* return segments */ - StreamTcpReturnStreamSegments(&ssn->client); - StreamTcpReturnStreamSegments(&ssn->server); - /* free SACK list */ - StreamTcpSackFreeList(&ssn->client); - StreamTcpSackFreeList(&ssn->server); - /* reset the app layer state */ - FlowCleanupAppLayer(p->flow); - - ssn->state = 0; - ssn->flags = 0; - ssn->client.flags = 0; - ssn->server.flags = 0; - - /* set state the NONE, also pulls flow out of closed queue */ - StreamTcpPacketSetState(p, ssn, TCP_NONE); - - p->flow->alproto_ts = p->flow->alproto_tc = p->flow->alproto = ALPROTO_UNKNOWN; - p->flow->data_al_so_far[0] = p->flow->data_al_so_far[1] = 0; - ssn->data_first_seen_dir = 0; - p->flow->flags &= (~FLOW_TS_PM_ALPROTO_DETECT_DONE & - ~FLOW_TS_PP_ALPROTO_DETECT_DONE & - ~FLOW_TC_PM_ALPROTO_DETECT_DONE & - ~FLOW_TC_PP_ALPROTO_DETECT_DONE); - p->flow->flags &= ~ FLOW_NO_APPLAYER_INSPECTION; - if (p->flow->de_state != NULL) { - SCMutexLock(&p->flow->de_state_m); - DetectEngineStateReset(p->flow->de_state, (STREAM_TOSERVER | STREAM_TOCLIENT)); - SCMutexUnlock(&p->flow->de_state_m); - } - - if (StreamTcpPacketStateNone(tv,p,stt,ssn, &stt->pseudo_queue)) { - goto error; - } - - SCPerfCounterIncr(stt->counter_tcp_reused_ssn, tv->sc_perf_pca); - } else { - SCLogDebug("packet received on closed state"); - } + /* TCP session memory is not returned to pool until timeout. */ + SCLogDebug("packet received on closed state"); break; default: SCLogDebug("packet received on default state"); From db9f12ee516bcb2c8513f1755bc278979d055813 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 15 Dec 2014 17:42:56 +0100 Subject: [PATCH 0229/2553] flow: add flow.tcp_reuse counter This replaces the tcp.reused_ssn counter. The flow engine now enforces the TCP flow reuse logic. The counter is incremented only when the flow is timed out, so after the "tcp closed" timeout expired for a flow. --- src/flow-manager.c | 12 ++++++++++-- src/stream-tcp.c | 3 --- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 217681c609bc..3bfa477a4a6a 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -93,6 +93,7 @@ typedef struct FlowTimeoutCounters_ { uint32_t new; uint32_t est; uint32_t clo; + uint32_t tcp_reuse; } FlowTimeoutCounters; /** @@ -306,6 +307,9 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, f->hnext = NULL; f->hprev = NULL; + if (f->flags & FLOW_TCP_REUSED) + counters->tcp_reuse++; + if (state == FLOW_STATE_NEW) f->flow_end_flags |= FLOW_END_FLAG_STATE_NEW; else if (state == FLOW_STATE_ESTABLISHED) @@ -491,6 +495,7 @@ typedef struct FlowManagerThreadData_ { uint16_t flow_mgr_spare; uint16_t flow_emerg_mode_enter; uint16_t flow_emerg_mode_over; + uint16_t flow_tcp_reuse; } FlowManagerThreadData; static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) @@ -535,6 +540,8 @@ static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) SC_PERF_TYPE_UINT64, "NULL"); ftd->flow_emerg_mode_over = SCPerfTVRegisterCounter("flow.emerg_mode_over", t, SC_PERF_TYPE_UINT64, "NULL"); + ftd->flow_tcp_reuse = SCPerfTVRegisterCounter("flow.tcp_reuse", t, + SC_PERF_TYPE_UINT64, "NULL"); PacketPoolInit(); return TM_ECODE_OK; @@ -619,7 +626,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) FlowUpdateSpareFlows(); /* try to time out flows */ - FlowTimeoutCounters counters = { 0, 0, 0, }; + FlowTimeoutCounters counters = { 0, 0, 0, 0, }; FlowTimeoutHash(&ts, 0 /* check all */, ftd->min, ftd->max, &counters); @@ -640,6 +647,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) SCPerfCounterAddUI64(ftd->flow_mgr_cnt_est, th_v->sc_perf_pca, (uint64_t)counters.est); long long unsigned int flow_memuse = SC_ATOMIC_GET(flow_memuse); SCPerfCounterSetUI64(ftd->flow_mgr_memuse, th_v->sc_perf_pca, (uint64_t)flow_memuse); + SCPerfCounterAddUI64(ftd->flow_tcp_reuse, th_v->sc_perf_pca, (uint64_t)counters.tcp_reuse); uint32_t len = 0; FQLOCK_LOCK(&flow_spare_q); @@ -1254,7 +1262,7 @@ static int FlowMgrTest05 (void) struct timeval ts; TimeGet(&ts); /* try to time out flows */ - FlowTimeoutCounters counters = { 0, 0, 0, }; + FlowTimeoutCounters counters = { 0, 0, 0, 0, }; FlowTimeoutHash(&ts, 0 /* check all */, 0, flow_config.hash_size, &counters); if (flow_recycle_q.len > 0) { diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 77d9b09a91b8..6f339ae13ef1 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4751,9 +4751,6 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) stt->counter_tcp_no_flow = SCPerfTVRegisterCounter("tcp.no_flow", tv, SC_PERF_TYPE_UINT64, "NULL"); - stt->counter_tcp_reused_ssn = SCPerfTVRegisterCounter("tcp.reused_ssn", tv, - SC_PERF_TYPE_UINT64, - "NULL"); stt->counter_tcp_memuse = SCPerfTVRegisterCounter("tcp.memuse", tv, SC_PERF_TYPE_UINT64, "NULL"); From 34e1de69702749c1523d4c73d70cf45ccdc83740 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 2 Feb 2015 14:40:21 +0100 Subject: [PATCH 0230/2553] flow: move flow/packet updates into util func Move the code responsible for updating the flow and packet after a new packet has come in to a util func "FlowHandlePacketUpdate" --- src/flow.c | 40 +++++++++++++++++++++++++++------------- src/flow.h | 2 +- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/flow.c b/src/flow.c index 018e1fe64836..2e374592045d 100644 --- a/src/flow.c +++ b/src/flow.c @@ -226,22 +226,16 @@ static inline int FlowUpdateSeenFlag(const Packet *p) return 1; } -/** \brief Entry point for packet flow handling +/** \brief Update Packet and Flow * - * This is called for every packet. + * Updates packet and flow based on the new packet. * - * \param tv threadvars - * \param dtv decode thread vars (for flow output api thread data) - * \param p packet to handle flow for + * \param f locked flow + * \param p packet */ -void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) +void FlowHandlePacketUpdate(Flow *f, Packet *p) { - /* Get this packet's flow from the hash. FlowHandlePacket() will setup - * a new flow if nescesary. If we get NULL, we're out of flow memory. - * The returned flow is locked. */ - Flow *f = FlowGetFlowFromHash(tv, dtv, p); - if (f == NULL) - return; + SCLogDebug("packet %"PRIu64" -- flow %p", p->pcap_cnt, f); /* Point the Packet at the Flow */ FlowReference(&p->flow, f); @@ -263,7 +257,7 @@ void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) p->flowflags |= FLOW_PKT_TOCLIENT; } - if ((f->flags & FLOW_TO_DST_SEEN) && (f->flags & FLOW_TO_SRC_SEEN)) { + if ((f->flags & (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) == (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) { SCLogDebug("pkt %p FLOW_PKT_ESTABLISHED", p); p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -281,6 +275,26 @@ void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) SCLogDebug("setting FLOW_NOPAYLOAD_INSPECTION flag on flow %p", f); DecodeSetNoPayloadInspectionFlag(p); } +} + +/** \brief Entry point for packet flow handling + * + * This is called for every packet. + * + * \param tv threadvars + * \param dtv decode thread vars (for flow output api thread data) + * \param p packet to handle flow for + */ +void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) +{ + /* Get this packet's flow from the hash. FlowHandlePacket() will setup + * a new flow if nescesary. If we get NULL, we're out of flow memory. + * The returned flow is locked. */ + Flow *f = FlowGetFlowFromHash(tv, dtv, p); + if (f == NULL) + return; + + FlowHandlePacketUpdate(f, p); FLOWLOCK_UNLOCK(f); diff --git a/src/flow.h b/src/flow.h index 0570adbc4d80..f7fd63e8c83f 100644 --- a/src/flow.h +++ b/src/flow.h @@ -575,7 +575,7 @@ int FlowClearMemory(Flow *,uint8_t ); AppProto FlowGetAppProtocol(Flow *f); void *FlowGetAppState(Flow *f); - +void FlowHandlePacketUpdate(Flow *f, Packet *p); #endif /* __FLOW_H__ */ From cf58ecb084dec06a90a30185f825a38c648fa6d3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 2 Feb 2015 15:46:24 +0100 Subject: [PATCH 0231/2553] flow: overwrite p::flowflags on first set --- src/flow.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/flow.c b/src/flow.c index 2e374592045d..cdeb569226d5 100644 --- a/src/flow.c +++ b/src/flow.c @@ -232,6 +232,8 @@ static inline int FlowUpdateSeenFlag(const Packet *p) * * \param f locked flow * \param p packet + * + * \note overwrites p::flowflags */ void FlowHandlePacketUpdate(Flow *f, Packet *p) { @@ -247,14 +249,14 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p) } f->todstpktcnt++; f->todstbytecnt += GET_PKT_LEN(p); - p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags = FLOW_PKT_TOSERVER; } else { if (FlowUpdateSeenFlag(p)) { f->flags |= FLOW_TO_SRC_SEEN; } f->tosrcpktcnt++; f->tosrcbytecnt += GET_PKT_LEN(p); - p->flowflags |= FLOW_PKT_TOCLIENT; + p->flowflags = FLOW_PKT_TOCLIENT; } if ((f->flags & (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) == (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) { From 2fb9611223824e16ae853a2aaac96183d147cfb0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 2 Feb 2015 17:14:49 +0100 Subject: [PATCH 0232/2553] flow: add util func to remove packet from flow Unsets the p::flowflags that were previously set. --- src/decode.h | 7 +++++++ src/flow.c | 31 +++++++++++++++++++++++++++++++ src/flow.h | 2 ++ 3 files changed, 40 insertions(+) diff --git a/src/decode.h b/src/decode.h index 9b16e036ccc0..921aac3652c2 100644 --- a/src/decode.h +++ b/src/decode.h @@ -872,6 +872,10 @@ void AddressDebugPrint(Address *); (p)->flags |= PKT_NOPAYLOAD_INSPECTION; \ } while (0) +#define DecodeUnsetNoPayloadInspectionFlag(p) do { \ + (p)->flags &= ~PKT_NOPAYLOAD_INSPECTION; \ + } while (0) + /** \brief Set the No packet inspection Flag for the packet. * * \param p Packet to set the flag in @@ -879,6 +883,9 @@ void AddressDebugPrint(Address *); #define DecodeSetNoPacketInspectionFlag(p) do { \ (p)->flags |= PKT_NOPACKET_INSPECTION; \ } while (0) +#define DecodeUnsetNoPacketInspectionFlag(p) do { \ + (p)->flags &= ~PKT_NOPACKET_INSPECTION; \ + } while (0) #define ENGINE_SET_EVENT(p, e) do { \ diff --git a/src/flow.c b/src/flow.c index cdeb569226d5..5ef5abeb79f5 100644 --- a/src/flow.c +++ b/src/flow.c @@ -226,6 +226,37 @@ static inline int FlowUpdateSeenFlag(const Packet *p) return 1; } +/** + * + * Remove packet from flow. This assumes this happens *before* the packet + * is added to the stream engine and other higher state. + * + * \todo we can't restore the lastts + */ +void FlowHandlePacketUpdateRemove(Flow *f, Packet *p) +{ + if (p->flowflags & FLOW_PKT_TOSERVER) { + f->todstpktcnt--; + f->todstbytecnt -= GET_PKT_LEN(p); + p->flowflags &= ~FLOW_PKT_TOSERVER; + } else { + f->tosrcpktcnt--; + f->tosrcbytecnt -= GET_PKT_LEN(p); + p->flowflags &= ~FLOW_PKT_TOCLIENT; + } + p->flowflags &= ~FLOW_PKT_ESTABLISHED; + + /*set the detection bypass flags*/ + if (f->flags & FLOW_NOPACKET_INSPECTION) { + SCLogDebug("unsetting FLOW_NOPACKET_INSPECTION flag on flow %p", f); + DecodeUnsetNoPacketInspectionFlag(p); + } + if (f->flags & FLOW_NOPAYLOAD_INSPECTION) { + SCLogDebug("unsetting FLOW_NOPAYLOAD_INSPECTION flag on flow %p", f); + DecodeUnsetNoPayloadInspectionFlag(p); + } +} + /** \brief Update Packet and Flow * * Updates packet and flow based on the new packet. diff --git a/src/flow.h b/src/flow.h index f7fd63e8c83f..2ef95d724f1d 100644 --- a/src/flow.h +++ b/src/flow.h @@ -575,6 +575,8 @@ int FlowClearMemory(Flow *,uint8_t ); AppProto FlowGetAppProtocol(Flow *f); void *FlowGetAppState(Flow *f); + +void FlowHandlePacketUpdateRemove(Flow *f, Packet *p); void FlowHandlePacketUpdate(Flow *f, Packet *p); #endif /* __FLOW_H__ */ From 29f70bad34dbf1bd55bd149158d23e9143c86ff5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Jan 2015 17:30:10 +0100 Subject: [PATCH 0233/2553] tcp reuse: handle reuse in stream engine For the autofp case, handling TCP reuse in the flow engine didn't work. The problem is the mismatch between the moment the flow engine looks at packets and the stream, and the moment the stream engine runs. Flow engine is invoked in the packet capture thread(s), while the stream engine runs as part of the stream/detect thread(s). Because of the queues between those threads the flow manager may already inspect a new SYN while the stream engine still has to process the previous session. Moving the flow engine to the stream/detect thread(s) wasn't an option as the 'autofp' load balancing depends on the flow already being available in the packet. The solution here is to add a check for this condition to the stream engine. At this point the TCP state is up to date. If a TCP reuse case is encountered, this is the global logic: - detach packet for old flow - get a new flow and attach it to the packet - flag the old flow that it is now obsolete Additional logic makes sure that the packets already in the queue between the flow thread(s) and the stream thread are reassigned the new flow. Some special handling: Apply previous 'reuse' before checking for a new reuse. Otherwise we're tagging the wrong flow in some cases (multiple reuses in the same tuple). When in a flow/ssn reuse condition, properly remove the packet from the flow. Don't 'reuse' if packet is a SYN retransmission. The old flow is timed out normally by the flow manager. --- src/flow-hash.c | 115 +++++++++++++++++++++++++ src/flow.h | 4 +- src/stream-tcp.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 337 insertions(+), 1 deletion(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index 1fea10a67d39..47e7711a2310 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -507,6 +507,121 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) return f; } +Flow *FlowGetFlowFromHashByPacket(const Packet *p) +{ + Flow *f = NULL; + + /* get the key to our bucket */ + uint32_t key = FlowGetKey(p); + /* get our hash bucket and lock it */ + FlowBucket *fb = &flow_hash[key]; + FBLOCK_LOCK(fb); + + SCLogDebug("fb %p fb->head %p", fb, fb->head); + + f = FlowGetNew(NULL, NULL, p); + if (f != NULL) { + /* flow is locked */ + if (fb->head == NULL) { + fb->head = f; + fb->tail = f; + } else { + f->hprev = fb->tail; + fb->tail->hnext = f; + fb->tail = f; + } + + /* got one, now lock, initialize and return */ + FlowInit(f, p); + f->fb = fb; + /* update the last seen timestamp of this flow */ + COPY_TIMESTAMP(&p->ts,&f->lastts); + + } + FBLOCK_UNLOCK(fb); + return f; +} + +/** \brief Lookup flow based on packet + * + * Find the flow belonging to this packet. If not found, no new flow + * is set up. + * + * \param p packet to lookup the flow for + * + * \retval f flow or NULL if not found + */ +Flow *FlowLookupFlowFromHash(const Packet *p) +{ + Flow *f = NULL; + + /* get the key to our bucket */ + uint32_t key = FlowGetKey(p); + /* get our hash bucket and lock it */ + FlowBucket *fb = &flow_hash[key]; + FBLOCK_LOCK(fb); + + SCLogDebug("fb %p fb->head %p", fb, fb->head); + + /* see if the bucket already has a flow */ + if (fb->head == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + + /* ok, we have a flow in the bucket. Let's find out if it is our flow */ + f = fb->head; + + /* see if this is the flow we are looking for */ + if (FlowCompare(f, p) == 0) { + while (f) { + FlowHashCountIncr; + + f = f->hnext; + + if (f == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + + if (FlowCompare(f, p) != 0) { + /* we found our flow, lets put it on top of the + * hash list -- this rewards active flows */ + if (f->hnext) { + f->hnext->hprev = f->hprev; + } + if (f->hprev) { + f->hprev->hnext = f->hnext; + } + if (f == fb->tail) { + fb->tail = f->hprev; + } + + f->hnext = fb->head; + f->hprev = NULL; + fb->head->hprev = f; + fb->head = f; + + /* found our flow, lock & return */ + FLOWLOCK_WRLOCK(f); + /* update the last seen timestamp of this flow */ + COPY_TIMESTAMP(&p->ts,&f->lastts); + + FBLOCK_UNLOCK(fb); + return f; + } + } + } + + /* lock & return */ + FLOWLOCK_WRLOCK(f); + /* update the last seen timestamp of this flow */ + COPY_TIMESTAMP(&p->ts,&f->lastts); + + FBLOCK_UNLOCK(fb); + return f; +} + /** \brief Get Flow for packet * * Hash retrieval function for flows. Looks up the hash bucket containing the diff --git a/src/flow.h b/src/flow.h index 2ef95d724f1d..66df3561f7e3 100644 --- a/src/flow.h +++ b/src/flow.h @@ -575,9 +575,11 @@ int FlowClearMemory(Flow *,uint8_t ); AppProto FlowGetAppProtocol(Flow *f); void *FlowGetAppState(Flow *f); - void FlowHandlePacketUpdateRemove(Flow *f, Packet *p); void FlowHandlePacketUpdate(Flow *f, Packet *p); +Flow *FlowGetFlowFromHashByPacket(const Packet *p); +Flow *FlowLookupFlowFromHash(const Packet *p); + #endif /* __FLOW_H__ */ diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 6f339ae13ef1..a24c86543fb8 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4687,6 +4687,211 @@ static inline int StreamTcpValidateChecksum(Packet *p) return ret; } +/** \internal + * \brief check if a packet is a valid stream started + * \retval bool true/false */ +static int TcpSessionPacketIsStreamStarter(const Packet *p) +{ + uint8_t flag = TH_SYN; + + //SCLogInfo("Want: %02x, have %02x", flag, p->tcph->th_flags); + + if (p->tcph->th_flags == flag) { + SCLogDebug("packet %"PRIu64" is a stream starter: %02x", p->pcap_cnt, p->tcph->th_flags); + return 1; + } + return 0; +} + +/** \internal + * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused + * \retval bool true yes reuse, false no keep tracking old ssn */ +int TcpSessionReuseDoneEnough(Packet *p, const TcpSession *ssn) +{ + if (FlowGetPacketDirection(p->flow, p) == TOSERVER) { + if (ssn == NULL) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn); + return 0; + } + if (SEQ_EQ(ssn->client.isn, TCP_GET_SEQ(p))) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn); + return 0; + } + if (ssn->state >= TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state == TCP_NONE) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state < TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + return 0; + } + + } else { + if (ssn == NULL) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn); + return 1; + } + if (ssn->state >= TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state == TCP_NONE) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state < TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + return 0; + } + } + + + SCLogDebug("default: how did we get here?"); + return 0; +} + +/** \brief Handle TCP reuse of tuple + * + * Logic: + * 1. see if packet could trigger a new session + * 2. see if the flow/ssn is in a state where we want to support the reuse + * 3. disconnect packet from the old flow + * -> at this point new packets can still find the old flow + * -> as the flow's reference count != 0, it can't disappear + * 4. setup a new flow unconditionally + * 5. attach packet to new flow + * 6. tag old flow as FLOW_TCP_REUSED + * -> NEW packets won't find it + * -> existing packets in our queues may still reference it + * 7. dereference the old flow (reference cnt *may* now be 0, + * if no other packets reference it) + * + * The packets that still hold a reference to the old flow are updated + * by HandleFlowReuseApplyToPacket() + */ +static void TcpSessionReuseHandle(Packet *p) { + if (likely(TcpSessionPacketIsStreamStarter(p) == 0)) + return; + + int reuse = 0; + FLOWLOCK_RDLOCK(p->flow); + reuse = TcpSessionReuseDoneEnough(p, p->flow->protoctx); + if (!reuse) { + SCLogDebug("steam starter packet %"PRIu64", but state not " + "ready to be reused", p->pcap_cnt); + FLOWLOCK_UNLOCK(p->flow); + return; + } + + /* ok, this packet needs a new flow */ + + /* first, get a reference to the old flow */ + Flow *old_f = NULL; + FlowReference(&old_f, p->flow); + + /* get some settings that we move over to the new flow */ + FlowThreadId thread_id = old_f->thread_id; + int autofp_tmqh_flow_qid = SC_ATOMIC_GET(old_f->autofp_tmqh_flow_qid); + + /* disconnect the packet from the old flow */ + FlowHandlePacketUpdateRemove(p->flow, p); + FLOWLOCK_UNLOCK(p->flow); + FlowDeReference(&p->flow); // < can't disappear while usecnt >0 + + /* Can't tag flow as reused yet, would be a race condition: + * new packets will not get old flow because of FLOW_TCP_REUSED, + * so new flow may be created. This new flow could be handled in + * a different thread. */ + + /* Get a flow. It will be either a locked flow or NULL */ + Flow *new_f = FlowGetFlowFromHashByPacket(p); + if (new_f == NULL) { + FlowDeReference(&old_f); // < can't disappear while usecnt >0 + return; + } + + /* update flow and packet */ + FlowHandlePacketUpdate(new_f, p); + BUG_ON(new_f != p->flow); + + /* copy flow balancing settings */ + new_f->thread_id = thread_id; + SC_ATOMIC_SET(new_f->autofp_tmqh_flow_qid, autofp_tmqh_flow_qid); + + FLOWLOCK_UNLOCK(new_f); + + /* tag original flow that it's now unused */ + FLOWLOCK_WRLOCK(old_f); + SCLogDebug("old flow %p tagged with FLOW_TCP_REUSED by packet %"PRIu64"!", old_f, p->pcap_cnt); + old_f->flags |= FLOW_TCP_REUSED; + FLOWLOCK_UNLOCK(old_f); + FlowDeReference(&old_f); // < can't disappear while usecnt >0 + + SCLogDebug("new flow %p set up for packet %"PRIu64"!", p->flow, p->pcap_cnt); +} + +/** \brief Handle packets that reference the wrong flow because of TCP reuse + * + * In the case of TCP reuse we can have many packets that were assigned + * a flow by the capture/decode threads before the stream engine decided + * that a new flow was needed for these packets. + * When HandleFlowReuse creates a new flow, the packets already processed + * by the flow engine will still reference the old flow. + * + * This function detects this case and replaces the flow for those packets. + * It's a fairly expensive operation, but it should be rare as it's only + * done for packets that were already in the engine when the TCP reuse + * case was handled. New packets are assigned the correct flow by the + * flow engine. + */ +static void TcpSessionReuseHandleApplyToPacket(Packet *p) +{ + int need_flow_replace = 0; + + FLOWLOCK_WRLOCK(p->flow); + if (p->flow->flags & FLOW_TCP_REUSED) { + SCLogDebug("packet %"PRIu64" attached to outdated flow and ssn", p->pcap_cnt); + need_flow_replace = 1; + } + + if (likely(need_flow_replace == 0)) { + /* Work around a race condition: if HandleFlowReuse has inserted a new flow, + * it will not have seen both sides of the session yet. The packet we have here + * may be the first that got the flow directly from the hash right after the + * flow was added. In this case it won't have FLOW_PKT_ESTABLISHED flag set. */ + if ((p->flow->flags & FLOW_TO_DST_SEEN) && (p->flow->flags & FLOW_TO_SRC_SEEN)) { + p->flowflags |= FLOW_PKT_ESTABLISHED; + SCLogDebug("packet %"PRIu64" / flow %p: p->flowflags |= FLOW_PKT_ESTABLISHED (%u/%u)", p->pcap_cnt, p->flow, p->flow->todstpktcnt, p->flow->tosrcpktcnt); + } else { + SCLogDebug("packet %"PRIu64" / flow %p: p->flowflags NOT FLOW_PKT_ESTABLISHED (%u/%u)", p->pcap_cnt, p->flow, p->flow->todstpktcnt, p->flow->tosrcpktcnt); + } + SCLogDebug("packet %"PRIu64" attached to regular flow %p and ssn", p->pcap_cnt, p->flow); + FLOWLOCK_UNLOCK(p->flow); + return; + } + + /* disconnect packet from old flow */ + FlowHandlePacketUpdateRemove(p->flow, p); + FLOWLOCK_UNLOCK(p->flow); + FlowDeReference(&p->flow); // < can't disappear while usecnt >0 + + /* find the new flow that does belong to this packet */ + Flow *new_f = FlowLookupFlowFromHash(p); + if (new_f == NULL) { + // TODO reset packet flag wrt flow: direction, HAS_FLOW etc + p->flags &= ~PKT_HAS_FLOW; + return; + } + FlowHandlePacketUpdate(new_f, p); + BUG_ON(new_f != p->flow); + FLOWLOCK_UNLOCK(new_f); + SCLogDebug("packet %"PRIu64" switched over to new flow %p!", p->pcap_cnt, p->flow); +} + TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { StreamTcpThread *stt = (StreamTcpThread *)data; @@ -4709,6 +4914,20 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe p->flags |= PKT_IGNORE_CHECKSUM; } +// TODO autofp only somehow + /* "autofp" handling of TCP session/flow reuse */ + if (!(p->flags & PKT_PSEUDO_STREAM_END)) { + /* apply previous reuses to this packet */ + TcpSessionReuseHandleApplyToPacket(p); + if (p->flow == NULL) + return ret; + + /* after that, check for 'new' reuse */ + TcpSessionReuseHandle(p); + if (p->flow == NULL) + return ret; + } + AppLayerProfilingReset(stt->ra_ctx->app_tctx); FLOWLOCK_WRLOCK(p->flow); From 11e3f25de3c910eb2b15b360bdc7594ee214a3fc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 3 Feb 2015 12:06:49 +0100 Subject: [PATCH 0234/2553] tcp reuse: unify autofp and single/workers check --- src/flow-hash.c | 23 ++++++++--------------- src/flow.c | 2 +- src/flow.h | 2 +- src/stream-tcp.c | 31 +++++++++++++++---------------- 4 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index 47e7711a2310..ea3b13408125 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -390,7 +390,7 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p) return 0; } -int TcpSessionPacketSsnReuse(const Packet *p, void *tcp_ssn); +int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, void *tcp_ssn); static inline int FlowCompare(Flow *f, const Packet *p) { @@ -405,20 +405,13 @@ static inline int FlowCompare(Flow *f, const Packet *p) if (f->flags & FLOW_TCP_REUSED) return 0; - /* lets see if we need to consider the existing session for - * reuse: only considering SYN packets. */ - int syn = (p->tcph && ((p->tcph->th_flags & TH_SYN) == TH_SYN)); - int has_protoctx = ((f->protoctx != NULL)); - - /* syn on existing state, need to see if we need to 'reuse' */ - if (unlikely(syn && has_protoctx && FlowGetPacketDirection(f,p) == TOSERVER)) { - if (unlikely(TcpSessionPacketSsnReuse(p, f->protoctx) == 1)) { - /* okay, we need to setup a new flow for this packet. - * Flag the flow that it's been replaced by a new one */ - f->flags |= FLOW_TCP_REUSED; - SCLogDebug("flow obsolete: TCP reuse will use a new flow"); - return 0; - } + /* lets see if we need to consider the existing session reuse */ + if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) { + /* okay, we need to setup a new flow for this packet. + * Flag the flow that it's been replaced by a new one */ + f->flags |= FLOW_TCP_REUSED; + SCLogDebug("flow obsolete: TCP reuse will use a new flow"); + return 0; } return 1; } else { diff --git a/src/flow.c b/src/flow.c index 5ef5abeb79f5..f62879520184 100644 --- a/src/flow.c +++ b/src/flow.c @@ -178,7 +178,7 @@ void FlowSetIPOnlyFlagNoLock(Flow *f, char direction) * \retval 0 to_server * \retval 1 to_client */ -int FlowGetPacketDirection(Flow *f, const Packet *p) +int FlowGetPacketDirection(const Flow *f, const Packet *p) { if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) { if (!(CMP_PORT(p->sp,p->dp))) { diff --git a/src/flow.h b/src/flow.h index 66df3561f7e3..89f0a32b1503 100644 --- a/src/flow.h +++ b/src/flow.h @@ -444,7 +444,7 @@ static inline void FlowLockSetNoPayloadInspectionFlag(Flow *); static inline void FlowSetNoPayloadInspectionFlag(Flow *); static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *); -int FlowGetPacketDirection(Flow *, const Packet *); +int FlowGetPacketDirection(const Flow *, const Packet *); void FlowCleanupAppLayer(Flow *); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index a24c86543fb8..46359a4614f7 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4386,18 +4386,6 @@ static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p) return 0; } -int TcpSessionPacketSsnReuse(const Packet *p, void *tcp_ssn) -{ - TcpSession *ssn = tcp_ssn; - if (ssn->state == TCP_CLOSED) { - if(!(SEQ_EQ(ssn->client.isn, TCP_GET_SEQ(p)))) - { - return 1; - } - } - return 0; -} - /* flow is and stays locked */ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueue *pq) @@ -4706,9 +4694,9 @@ static int TcpSessionPacketIsStreamStarter(const Packet *p) /** \internal * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused * \retval bool true yes reuse, false no keep tracking old ssn */ -int TcpSessionReuseDoneEnough(Packet *p, const TcpSession *ssn) +int TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn) { - if (FlowGetPacketDirection(p->flow, p) == TOSERVER) { + if (FlowGetPacketDirection(f, p) == TOSERVER) { if (ssn == NULL) { SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn); return 0; @@ -4749,11 +4737,22 @@ int TcpSessionReuseDoneEnough(Packet *p, const TcpSession *ssn) } } - SCLogDebug("default: how did we get here?"); return 0; } +int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn) +{ + if (p->proto == IPPROTO_TCP && p->tcph != NULL) { + if (TcpSessionPacketIsStreamStarter(p) == 1) { + if (TcpSessionReuseDoneEnough(p, f, tcp_ssn) == 1) { + return 1; + } + } + } + return 0; +} + /** \brief Handle TCP reuse of tuple * * Logic: @@ -4779,7 +4778,7 @@ static void TcpSessionReuseHandle(Packet *p) { int reuse = 0; FLOWLOCK_RDLOCK(p->flow); - reuse = TcpSessionReuseDoneEnough(p, p->flow->protoctx); + reuse = TcpSessionReuseDoneEnough(p, p->flow, p->flow->protoctx); if (!reuse) { SCLogDebug("steam starter packet %"PRIu64", but state not " "ready to be reused", p->pcap_cnt); From eaae008aeb68ac74468dad0fe473cf7cd04358ed Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 9 Feb 2015 16:44:11 +0100 Subject: [PATCH 0235/2553] tcp reuse: support reuse on syn/ack Support TCP reuse on SYN/ACK. Only effective if midstream and/or async-oneside options are enabled. --- src/stream-tcp.c | 86 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 46359a4614f7..97e717e297f4 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4680,21 +4680,24 @@ static inline int StreamTcpValidateChecksum(Packet *p) * \retval bool true/false */ static int TcpSessionPacketIsStreamStarter(const Packet *p) { - uint8_t flag = TH_SYN; - - //SCLogInfo("Want: %02x, have %02x", flag, p->tcph->th_flags); - - if (p->tcph->th_flags == flag) { + if (p->tcph->th_flags == TH_SYN) { SCLogDebug("packet %"PRIu64" is a stream starter: %02x", p->pcap_cnt, p->tcph->th_flags); return 1; } + + if (stream_config.midstream == TRUE || stream_config.async_oneside == TRUE) { + if (p->tcph->th_flags == (TH_SYN|TH_ACK)) { + SCLogDebug("packet %"PRIu64" is a midstream stream starter: %02x", p->pcap_cnt, p->tcph->th_flags); + return 1; + } + } return 0; } /** \internal * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused * \retval bool true yes reuse, false no keep tracking old ssn */ -int TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn) +static int TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn) { if (FlowGetPacketDirection(f, p) == TOSERVER) { if (ssn == NULL) { @@ -4741,6 +4744,77 @@ int TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession * return 0; } +/** \internal + * \brief check if ssn is done enough for reuse by syn/ack + * \note should only be called if midstream is enabled + */ +static int TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn) +{ + if (FlowGetPacketDirection(f, p) == TOCLIENT) { + if (ssn == NULL) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn); + return 0; + } + if (SEQ_EQ(ssn->server.isn, TCP_GET_SEQ(p))) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn); + return 0; + } + if (ssn->state >= TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state == TCP_NONE) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state < TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + return 0; + } + + } else { + if (ssn == NULL) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn); + return 1; + } + if (ssn->state >= TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state == TCP_NONE) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state < TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + return 0; + } + } + + SCLogDebug("default: how did we get here?"); + return 0; +} + +/** \brief Check if SSN is done enough for reuse + * + * Reuse means a new TCP session reuses the tuple (flow in suri) + * + * \retval bool true if ssn can be reused, false if not */ +int TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn) +{ + if (p->tcph->th_flags == TH_SYN) { + return TcpSessionReuseDoneEnoughSyn(p, f, ssn); + } + + if (stream_config.midstream == TRUE || stream_config.async_oneside == TRUE) { + if (p->tcph->th_flags == (TH_SYN|TH_ACK)) { + return TcpSessionReuseDoneEnoughSynAck(p, f, ssn); + } + } + + return 0; +} + int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn) { if (p->proto == IPPROTO_TCP && p->tcph != NULL) { From c88cbb39fec66faef315c5968d0cacd8e309a780 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 Feb 2015 10:34:53 +0100 Subject: [PATCH 0236/2553] tcp reuse: enable stream handling based on runmode Add a way for runmodes to state that flow and stream run asynchorously. In the stream engine, enable the TCP reuse handling only if that flag is set. --- src/flow-hash.c | 3 ++- src/runmode-erf-file.c | 1 + src/runmode-pcap-file.c | 1 + src/stream-tcp.c | 33 +++++++++++++++++++++------------ src/stream-tcp.h | 4 ++++ src/util-runmodes.c | 18 ++++++++++++++++++ src/util-runmodes.h | 2 ++ 7 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index ea3b13408125..3d609b197754 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -410,7 +410,8 @@ static inline int FlowCompare(Flow *f, const Packet *p) /* okay, we need to setup a new flow for this packet. * Flag the flow that it's been replaced by a new one */ f->flags |= FLOW_TCP_REUSED; - SCLogDebug("flow obsolete: TCP reuse will use a new flow"); + SCLogDebug("flow obsolete: TCP reuse will use a new flow " + "starting with packet %"PRIu64, p->pcap_cnt); return 0; } return 1; diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index dad86caaaa27..50f47669d017 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -137,6 +137,7 @@ int RunModeErfFileAutoFp(DetectEngineCtx *de_ctx) int thread; RunModeInitialize(); + RunmodeSetFlowStreamAsync(); char *file = NULL; if (ConfGet("erf-file.file", &file) == 0) { diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index 9b2c25010067..bd0e68e604b5 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -154,6 +154,7 @@ int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) int thread; RunModeInitialize(); + RunmodeSetFlowStreamAsync(); char *file = NULL; if (ConfGet("pcap-file.file", &file) == 0) { diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 97e717e297f4..54b76dc2add8 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -71,6 +71,7 @@ #include "util-profiling.h" #include "util-misc.h" #include "util-validate.h" +#include "util-runmodes.h" #include "source-pcap-file.h" @@ -4860,6 +4861,9 @@ static void TcpSessionReuseHandle(Packet *p) { return; } + SCLogDebug("steam starter packet %"PRIu64", and state " + "ready to be reused", p->pcap_cnt); + /* ok, this packet needs a new flow */ /* first, get a reference to the old flow */ @@ -4987,20 +4991,20 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe p->flags |= PKT_IGNORE_CHECKSUM; } -// TODO autofp only somehow - /* "autofp" handling of TCP session/flow reuse */ - if (!(p->flags & PKT_PSEUDO_STREAM_END)) { - /* apply previous reuses to this packet */ - TcpSessionReuseHandleApplyToPacket(p); - if (p->flow == NULL) - return ret; + if (stt->runmode_flow_stream_async) { + /* "autofp" handling of TCP session/flow reuse */ + if (!(p->flags & PKT_PSEUDO_STREAM_END)) { + /* apply previous reuses to this packet */ + TcpSessionReuseHandleApplyToPacket(p); + if (p->flow == NULL) + return ret; - /* after that, check for 'new' reuse */ - TcpSessionReuseHandle(p); - if (p->flow == NULL) - return ret; + /* after that, check for 'new' reuse */ + TcpSessionReuseHandle(p); + if (p->flow == NULL) + return ret; + } } - AppLayerProfilingReset(stt->ra_ctx->app_tctx); FLOWLOCK_WRLOCK(p->flow); @@ -5110,6 +5114,11 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) if (stt->ssn_pool_id < 0 || ssn_pool == NULL) SCReturnInt(TM_ECODE_FAILED); + /* see if need to enable the TCP reuse handling in the stream engine */ + stt->runmode_flow_stream_async = RunmodeGetFlowStreamAsync(); + SCLogDebug("Flow and Stream engine run %s", + stt->runmode_flow_stream_async ? "asynchronous" : "synchronous"); + SCReturnInt(TM_ECODE_OK); } diff --git a/src/stream-tcp.h b/src/stream-tcp.h index 113e2e88a135..8dfc992a5fee 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -76,6 +76,10 @@ typedef struct TcpStreamCnf_ { typedef struct StreamTcpThread_ { int ssn_pool_id; + /** if set to true, we activate the TCP tuple reuse code in the + * stream engine. */ + int runmode_flow_stream_async; + uint64_t pkts; /** queue for pseudo packet(s) that were created in the stream diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 293ff43f8485..8f1c85964939 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -47,6 +47,20 @@ #include "util-runmodes.h" +/** set to true if flow engine and stream engine run in different + * threads. */ +static int runmode_flow_stream_async = 0; + +void RunmodeSetFlowStreamAsync(void) +{ + runmode_flow_stream_async = 1; +} + +int RunmodeGetFlowStreamAsync(void) +{ + return runmode_flow_stream_async; +} + /** \brief create a queue string for autofp to pass to * the flow queue handler. * @@ -103,6 +117,8 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, if (thread_max < 1) thread_max = 1; + RunmodeSetFlowStreamAsync(); + queues = RunmodeAutoFpCreatePickupQueuesString(thread_max); if (queues == NULL) { SCLogError(SC_ERR_RUNMODE, "RunmodeAutoFpCreatePickupQueuesString failed"); @@ -493,6 +509,8 @@ int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, if (thread_max < 1) thread_max = 1; + RunmodeSetFlowStreamAsync(); + queues = RunmodeAutoFpCreatePickupQueuesString(thread_max); if (queues == NULL) { SCLogError(SC_ERR_RUNMODE, "RunmodeAutoFpCreatePickupQueuesString failed"); diff --git a/src/util-runmodes.h b/src/util-runmodes.h index 2d562c34727d..c1852ccd8aac 100644 --- a/src/util-runmodes.h +++ b/src/util-runmodes.h @@ -23,6 +23,8 @@ #ifndef __UTIL_RUNMODES_H__ #define __UTIL_RUNMODES_H__ +void RunmodeSetFlowStreamAsync(void); +int RunmodeGetFlowStreamAsync(void); typedef void *(*ConfigIfaceParserFunc) (const char *); typedef void *(*ConfigIPSParserFunc) (int); From 6ad53627de604f7bd8ac9bfa8a20aec03c3b177c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 Feb 2015 12:47:01 +0100 Subject: [PATCH 0237/2553] flow: tag first packet in each direction Set a flowflag for the first packet in each direction: FLOW_PKT_TOSERVER_FIRST and FLOW_PKT_TOCLIENT_FIRST --- src/flow.c | 22 ++++++++++++++-------- src/flow.h | 2 ++ src/stream-tcp.h | 10 ++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/flow.c b/src/flow.c index f62879520184..3255bbf58adf 100644 --- a/src/flow.c +++ b/src/flow.c @@ -238,11 +238,11 @@ void FlowHandlePacketUpdateRemove(Flow *f, Packet *p) if (p->flowflags & FLOW_PKT_TOSERVER) { f->todstpktcnt--; f->todstbytecnt -= GET_PKT_LEN(p); - p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags &= ~(FLOW_PKT_TOSERVER|FLOW_PKT_TOSERVER_FIRST); } else { f->tosrcpktcnt--; f->tosrcbytecnt -= GET_PKT_LEN(p); - p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags &= ~(FLOW_PKT_TOCLIENT|FLOW_PKT_TOCLIENT_FIRST); } p->flowflags &= ~FLOW_PKT_ESTABLISHED; @@ -275,19 +275,25 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p) /* update flags and counters */ if (FlowGetPacketDirection(f, p) == TOSERVER) { - if (FlowUpdateSeenFlag(p)) { - f->flags |= FLOW_TO_DST_SEEN; - } f->todstpktcnt++; f->todstbytecnt += GET_PKT_LEN(p); p->flowflags = FLOW_PKT_TOSERVER; - } else { - if (FlowUpdateSeenFlag(p)) { - f->flags |= FLOW_TO_SRC_SEEN; + if (!(f->flags & FLOW_TO_DST_SEEN)) { + if (FlowUpdateSeenFlag(p)) { + f->flags |= FLOW_TO_DST_SEEN; + p->flowflags |= FLOW_PKT_TOSERVER_FIRST; + } } + } else { f->tosrcpktcnt++; f->tosrcbytecnt += GET_PKT_LEN(p); p->flowflags = FLOW_PKT_TOCLIENT; + if (!(f->flags & FLOW_TO_SRC_SEEN)) { + if (FlowUpdateSeenFlag(p)) { + f->flags |= FLOW_TO_SRC_SEEN; + p->flowflags |= FLOW_PKT_TOCLIENT_FIRST; + } + } } if ((f->flags & (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) == (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) { diff --git a/src/flow.h b/src/flow.h index 89f0a32b1503..8d699fc98d4c 100644 --- a/src/flow.h +++ b/src/flow.h @@ -171,6 +171,8 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_PKT_ESTABLISHED 0x04 #define FLOW_PKT_TOSERVER_IPONLY_SET 0x08 #define FLOW_PKT_TOCLIENT_IPONLY_SET 0x10 +#define FLOW_PKT_TOSERVER_FIRST 0x20 +#define FLOW_PKT_TOCLIENT_FIRST 0x40 #define FLOW_END_FLAG_STATE_NEW 0x01 #define FLOW_END_FLAG_STATE_ESTABLISHED 0x02 diff --git a/src/stream-tcp.h b/src/stream-tcp.h index 8dfc992a5fee..dcafe0e9bcc7 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -171,9 +171,19 @@ static inline void StreamTcpPacketSwitchDir(TcpSession *ssn, Packet *p) if (PKT_IS_TOSERVER(p)) { p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; + + if (p->flowflags & FLOW_PKT_TOSERVER_FIRST) { + p->flowflags &= ~FLOW_PKT_TOSERVER_FIRST; + p->flowflags |= FLOW_PKT_TOCLIENT_FIRST; + } } else { p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; + + if (p->flowflags & FLOW_PKT_TOCLIENT_FIRST) { + p->flowflags &= ~FLOW_PKT_TOCLIENT_FIRST; + p->flowflags |= FLOW_PKT_TOSERVER_FIRST; + } } } From d78be75b9fff92484379d8c031948a3f0cbab986 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 Feb 2015 13:01:52 +0100 Subject: [PATCH 0238/2553] tcp reuse: don't double 'reuse' If the flow engine already reused a flow then the stream engine won't have to do the same. --- src/stream-tcp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 54b76dc2add8..a8c0e37b5b08 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4999,10 +4999,12 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe if (p->flow == NULL) return ret; - /* after that, check for 'new' reuse */ - TcpSessionReuseHandle(p); - if (p->flow == NULL) - return ret; + if (!(p->flowflags & FLOW_PKT_TOSERVER_FIRST)) { + /* after that, check for 'new' reuse */ + TcpSessionReuseHandle(p); + if (p->flow == NULL) + return ret; + } } } AppLayerProfilingReset(stt->ra_ctx->app_tctx); From 7426a9c64504ac2731c36fae23f54a1a3639b9cc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 Feb 2015 08:50:01 +0100 Subject: [PATCH 0239/2553] flow: make TCP reuse handling in flow engine optional In case of autofp (or more general, when flow and stream engine run in different threads) the flow engine should not trigger a flow reuse as this can lead to race conditions between the flow and the stream engine. In such cases, the flow engine can be far ahead of the stream engine as packets are in a queue between the threads. Observed: Flow engine tags packet 10 as start of new flow. Flow is tagged as 'reused'. Stream engine evaluates packet 5 which belongs to the old flow. It rejects the flow as it's tagged 'reused'. Attaches packet 5 to the new flow which is wrong. Solution: This patch connects the flow engines handling of reuse cases to the runmode. It hooks into the RunmodeSetFlowStreamAsync() call to notify the flow engine that it shouldn't handle the reuse. --- src/flow-hash.c | 24 ++++++++++++++++-------- src/flow-hash.h | 2 ++ src/util-runmodes.c | 3 +++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index 3d609b197754..7a151199268a 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -52,6 +52,7 @@ SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx); SC_ATOMIC_EXTERN(unsigned int, flow_flags); static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv); +static int handle_tcp_reuse = 1; #ifdef FLOW_DEBUG_STATS #define FLOW_DEBUG_STATS_PROTO_ALL 0 @@ -148,6 +149,11 @@ void FlowHashDebugDeinit(void) #endif /* FLOW_DEBUG_STATS */ +void FlowDisableTcpReuseHandling(void) +{ + handle_tcp_reuse = 0; +} + /** \brief compare two raw ipv6 addrs * * \note we don't care about the real ipv6 ip's, this is just @@ -405,14 +411,16 @@ static inline int FlowCompare(Flow *f, const Packet *p) if (f->flags & FLOW_TCP_REUSED) return 0; - /* lets see if we need to consider the existing session reuse */ - if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) { - /* okay, we need to setup a new flow for this packet. - * Flag the flow that it's been replaced by a new one */ - f->flags |= FLOW_TCP_REUSED; - SCLogDebug("flow obsolete: TCP reuse will use a new flow " - "starting with packet %"PRIu64, p->pcap_cnt); - return 0; + if (handle_tcp_reuse == 1) { + /* lets see if we need to consider the existing session reuse */ + if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) { + /* okay, we need to setup a new flow for this packet. + * Flag the flow that it's been replaced by a new one */ + f->flags |= FLOW_TCP_REUSED; + SCLogDebug("flow obsolete: TCP reuse will use a new flow " + "starting with packet %"PRIu64, p->pcap_cnt); + return 0; + } } return 1; } else { diff --git a/src/flow-hash.h b/src/flow-hash.h index a5635b06ce19..4272896b5a62 100644 --- a/src/flow-hash.h +++ b/src/flow-hash.h @@ -70,6 +70,8 @@ typedef struct FlowBucket_ { Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *); +void FlowDisableTcpReuseHandling(void); + /** enable to print stats on hash lookups in flow-debug.log */ //#define FLOW_DEBUG_STATS diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 8f1c85964939..26ef2b76c0dc 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -47,6 +47,8 @@ #include "util-runmodes.h" +#include "flow-hash.h" + /** set to true if flow engine and stream engine run in different * threads. */ static int runmode_flow_stream_async = 0; @@ -54,6 +56,7 @@ static int runmode_flow_stream_async = 0; void RunmodeSetFlowStreamAsync(void) { runmode_flow_stream_async = 1; + FlowDisableTcpReuseHandling(); } int RunmodeGetFlowStreamAsync(void) From 5cd7bb2f140d03506b3280aaa71f612701d1a964 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Jan 2015 12:09:29 +0100 Subject: [PATCH 0240/2553] dcerpc: fix error handling for alloc errors Fix error handling of stub parsers. In case of SCRealloc error the function would return a non-error code. This could possibly lead to memory corruption. Reported-By: The Yahoo pentest team --- src/app-layer-dcerpc-udp.c | 5 +++-- src/app-layer-dcerpc.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/app-layer-dcerpc-udp.c b/src/app-layer-dcerpc-udp.c index c44bdbb370a3..9dedeee59e2e 100644 --- a/src/app-layer-dcerpc-udp.c +++ b/src/app-layer-dcerpc-udp.c @@ -45,6 +45,8 @@ enum { DCERPC_FIELD_MAX, }; +/** \internal + * \retval stub_len or 0 in case of error */ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len) @@ -88,7 +90,7 @@ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, SCFree(*stub_data_buffer); *stub_data_buffer = NULL; SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - goto end; + SCReturnUInt(0); } *stub_data_buffer = ptmp; @@ -110,7 +112,6 @@ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, } #endif -end: SCReturnUInt((uint32_t)stub_len); } diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 900c3269894c..3a22ff73162e 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -1189,6 +1189,8 @@ static uint32_t DCERPCParseREQUEST(DCERPC *dcerpc, uint8_t *input, uint32_t inpu SCReturnUInt((uint32_t)(p - input)); } +/** \internal + * \retval stub_len or 0 in case of error */ static uint32_t StubDataParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); @@ -1248,7 +1250,7 @@ static uint32_t StubDataParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_le SCFree(*stub_data_buffer); *stub_data_buffer = NULL; SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - goto end; + SCReturnUInt(0); } *stub_data_buffer = ptmp; @@ -1272,7 +1274,6 @@ static uint32_t StubDataParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_le } #endif -end: SCReturnUInt((uint32_t)stub_len); } From 647985d20d7da4fb1a27c74e3c6767d54826bc8a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Jan 2015 12:12:53 +0100 Subject: [PATCH 0241/2553] dcerpc: don't exit() on malloc failure In 2 places we would exit() if malloc failed. We should never exit in such cases. This patch silently handles it. --- src/app-layer-dcerpc.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 3a22ff73162e..d7198ba586d1 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -692,17 +692,14 @@ static uint32_t DCERPCParseBINDACKCTXItem(DCERPC *dcerpc, uint8_t *input, uint32 dcerpc->dcerpcbindbindack.uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, sizeof(DCERPCUuidEntry)); - if (dcerpc->dcerpcbindbindack.uuid_entry == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, - "Error allocating memory\n"); - exit(EXIT_FAILURE); + if (dcerpc->dcerpcbindbindack.uuid_entry != NULL) { + memcpy(dcerpc->dcerpcbindbindack.uuid_entry, + uuid_entry, + sizeof(DCERPCUuidEntry)); + TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.accepted_uuid_list, + dcerpc->dcerpcbindbindack.uuid_entry, + next); } - memcpy(dcerpc->dcerpcbindbindack.uuid_entry, - uuid_entry, - sizeof(DCERPCUuidEntry)); - TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.accepted_uuid_list, - dcerpc->dcerpcbindbindack.uuid_entry, - next); break; } } @@ -851,17 +848,14 @@ static uint32_t DCERPCParseBINDACKCTXItem(DCERPC *dcerpc, uint8_t *input, uint32 dcerpc->dcerpcbindbindack.uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, sizeof(DCERPCUuidEntry)); - if (dcerpc->dcerpcbindbindack.uuid_entry == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, - "Error allocating memory\n"); - exit(EXIT_FAILURE); + if (dcerpc->dcerpcbindbindack.uuid_entry != NULL) { + memcpy(dcerpc->dcerpcbindbindack.uuid_entry, + uuid_entry, + sizeof(DCERPCUuidEntry)); + TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.accepted_uuid_list, + dcerpc->dcerpcbindbindack.uuid_entry, + next); } - memcpy(dcerpc->dcerpcbindbindack.uuid_entry, - uuid_entry, - sizeof(DCERPCUuidEntry)); - TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.accepted_uuid_list, - dcerpc->dcerpcbindbindack.uuid_entry, - next); break; } } From e90714afd68fad6ed78233182b243437456b2d1e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Jan 2015 13:06:44 +0100 Subject: [PATCH 0242/2553] http: remove unused and broken 'content-len' logic The HTTP tracking code would parse the content lenght and store it in the TX user data. It didn't take the possibility or errors into account though, leading to a possible negative int being cases to unsigned int. Luckily, the result was unused. This patch simply removes the offending code. Reported-by: The Yahoo pentest team --- src/app-layer-htp.c | 9 --------- src/app-layer-htp.h | 2 -- 2 files changed, 11 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 7514b374e3cc..b0038e20d109 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1017,10 +1017,6 @@ static int HTTPParseContentTypeHeader(uint8_t *name, size_t name_len, */ static int HtpRequestBodySetupMultipart(htp_tx_data_t *d, HtpTxUserData *htud) { - htp_header_t *cl = htp_table_get_c(d->tx->request_headers, "content-length"); - if (cl != NULL) - htud->request_body.content_len = SC_htp_parse_content_length(cl->value); - htp_header_t *h = (htp_header_t *)htp_table_get_c(d->tx->request_headers, "Content-Type"); if (h != NULL && bstr_len(h->value) > 0) { @@ -1881,11 +1877,6 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) if (!tx_ud->request_body_init) { tx_ud->request_body_init = 1; tx_ud->operation = HTP_BODY_RESPONSE; - - htp_header_t *cl = htp_table_get_c(d->tx->response_headers, "content-length"); - if (cl != NULL) - tx_ud->response_body.content_len = SC_htp_parse_content_length(cl->value); - } SCLogDebug("tx_ud->response_body.content_len_so_far %"PRIu64, tx_ud->response_body.content_len_so_far); diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index d331dd0e9d84..7fca45e03cbc 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -170,8 +170,6 @@ typedef struct HtpBody_ { HtpBodyChunk *first; /**< Pointer to the first chunk */ HtpBodyChunk *last; /**< Pointer to the last chunk */ - /* Holds the length of the htp request body */ - uint64_t content_len; /* Holds the length of the htp request body seen so far */ uint64_t content_len_so_far; /* parser tracker */ From 67d80c36b465c2f10aba8851ba0992aea6a67ec8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Feb 2015 11:06:41 +0100 Subject: [PATCH 0243/2553] stream: init global config after flow engine Stream depends on flow engine. --- src/suricata.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 894b927aa618..d385b5b381f2 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2296,6 +2296,7 @@ int main(int argc, char **argv) HostInitConfig(HOST_VERBOSE); if (suri.run_mode != RUNMODE_UNIX_SOCKET) { FlowInitConfig(FLOW_VERBOSE); + StreamTcpInitConfig(STREAM_VERBOSE); } DetectEngineCtx *de_ctx = NULL; @@ -2381,8 +2382,6 @@ int main(int argc, char **argv) /* Spawn the flow manager thread */ FlowManagerThreadSpawn(); FlowRecyclerThreadSpawn(); - StreamTcpInitConfig(STREAM_VERBOSE); - SCPerfSpawnThreads(); } From 5ad7198dc0896cd832a5a54158d9ebecb953d77c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 Feb 2015 16:45:20 +0100 Subject: [PATCH 0244/2553] http: add libhtp uri warning event Add event for libhtp warning added 0.5.17 for URI's with suspicious delimeters. --- rules/http-events.rules | 4 +++- src/app-layer-htp.c | 3 +++ src/app-layer-htp.h | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rules/http-events.rules b/rules/http-events.rules index d5bb0f19a7e0..260ce3423937 100644 --- a/rules/http-events.rules +++ b/rules/http-events.rules @@ -41,6 +41,8 @@ alert http any any -> any any (msg:"SURICATA HTTP request server port doesn't ma alert http any any -> any any (msg:"SURICATA HTTP Host part of URI is invalid"; flow:established,to_server; app-layer-event:http.request_uri_host_invalid; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221027; rev:1;) # Host header is invalid alert http any any -> any any (msg:"SURICATA HTTP Host header invalid"; flow:established,to_server; app-layer-event:http.request_header_host_invalid; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221028; rev:1;) +# URI is terminated by non-compliant characters. RFC allows for space (0x20), but many implementations permit others like tab and more. +alert http any any -> any any (msg:"SURICATA HTTP URI terminated by non-compliant character"; flow:established,to_server; app-layer-event:http.uri_delim_non_compliant; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221029; rev:1;) -# next sid 2221029 +# next sid 2221030 diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index b0038e20d109..316a5316d45a 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -144,6 +144,8 @@ SCEnumCharMap http_decoder_event_table[ ] = { HTTP_DECODER_EVENT_URI_HOST_INVALID}, { "REQUEST_HEADER_HOST_INVALID", HTTP_DECODER_EVENT_HEADER_HOST_INVALID}, + { "URI_DELIM_NON_COMPLIANT", + HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT}, /* suricata warnings/errors */ { "MULTIPART_GENERIC_ERROR", @@ -497,6 +499,7 @@ struct { * luckily, "Request server port=" is unique */ /* { "Request server port number differs from the actual TCP port", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, */ { "Request server port=", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, + { "Request line: URI contains non-compliant delimiter", HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT}, }; #define HTP_ERROR_MAX (sizeof(htp_errors) / sizeof(htp_errors[0])) diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 7fca45e03cbc..2526f30bfba0 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -121,6 +121,7 @@ enum { HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH, HTTP_DECODER_EVENT_URI_HOST_INVALID, HTTP_DECODER_EVENT_HEADER_HOST_INVALID, + HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT, /* suricata errors/warnings */ HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR, From e78e33a428865e1317d190a299976ed0253db26e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 Feb 2015 23:46:19 +0100 Subject: [PATCH 0245/2553] http: add event for suspicious method delimeter Add event and rule for suspicious delim(s) between method and uri. Add unittests as well. --- rules/http-events.rules | 4 +- src/app-layer-htp.c | 92 +++++++++++++++++++++++++++++++++++++++++ src/app-layer-htp.h | 1 + 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/rules/http-events.rules b/rules/http-events.rules index 260ce3423937..5f733637537c 100644 --- a/rules/http-events.rules +++ b/rules/http-events.rules @@ -43,6 +43,8 @@ alert http any any -> any any (msg:"SURICATA HTTP Host part of URI is invalid"; alert http any any -> any any (msg:"SURICATA HTTP Host header invalid"; flow:established,to_server; app-layer-event:http.request_header_host_invalid; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221028; rev:1;) # URI is terminated by non-compliant characters. RFC allows for space (0x20), but many implementations permit others like tab and more. alert http any any -> any any (msg:"SURICATA HTTP URI terminated by non-compliant character"; flow:established,to_server; app-layer-event:http.uri_delim_non_compliant; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221029; rev:1;) +# Method is terminated by non-compliant characters. RFC allows for space (0x20), but many implementations permit others like tab and more. +alert http any any -> any any (msg:"SURICATA HTTP METHOD terminated by non-compliant character"; flow:established,to_server; app-layer-event:http.method_delim_non_compliant; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221030; rev:1;) -# next sid 2221030 +# next sid 2221031 diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 316a5316d45a..399dd7a2ae29 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -146,6 +146,8 @@ SCEnumCharMap http_decoder_event_table[ ] = { HTTP_DECODER_EVENT_HEADER_HOST_INVALID}, { "URI_DELIM_NON_COMPLIANT", HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT}, + { "METHOD_DELIM_NON_COMPLIANT", + HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT}, /* suricata warnings/errors */ { "MULTIPART_GENERIC_ERROR", @@ -500,6 +502,7 @@ struct { /* { "Request server port number differs from the actual TCP port", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, */ { "Request server port=", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, { "Request line: URI contains non-compliant delimiter", HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT}, + { "Request line: non-compliant delimiter between Method and URI", HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT}, }; #define HTP_ERROR_MAX (sizeof(htp_errors) / sizeof(htp_errors[0])) @@ -5974,6 +5977,94 @@ libhtp:\n\ HtpConfigRestoreBackup(); return result; } + +/** \test Test unusual delims in request line HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG */ +int HTPParserTest16(void) +{ + int result = 0; + Flow *f = NULL; + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + uint8_t httpbuf[] = "GET\f/blah/\fHTTP/1.1\r\n" + "Host: myhost.lan\r\n" + "Connection: keep-alive\r\n" + "Accept: */*\r\n" + "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n" + "Referer: http://blah.lan/\r\n" + "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n" + "Cookie: blah\r\n\r\n"; + size_t len = sizeof(httpbuf) - 1; + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + uint8_t flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; + + SCMutexLock(&f->m); + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)httpbuf, len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + SCMutexUnlock(&f->m); + goto end; + } + SCMutexUnlock(&f->m); + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_GET and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + SCMutexLock(&f->m); + AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); + if (decoder_events == NULL) { + printf("no app events: "); + SCMutexUnlock(&f->m); + goto end; + } + SCMutexUnlock(&f->m); + + if (decoder_events->events[0] != HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT) { + printf("HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT not set: "); + goto end; + } + + if (decoder_events->events[1] != HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT) { + printf("HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT not set: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + if (htp_state != NULL) + HTPStateFree(htp_state); + UTHFreeFlow(f); + return result; +} + #endif /* UNITTESTS */ /** @@ -6018,6 +6109,7 @@ void HTPParserRegisterTests(void) UtRegisterTest("HTPParserTest14", HTPParserTest14, 1); UtRegisterTest("HTPParserTest15", HTPParserTest15, 1); + UtRegisterTest("HTPParserTest16", HTPParserTest16, 1); HTPFileParserRegisterTests(); #endif /* UNITTESTS */ diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 2526f30bfba0..e3cad8a1e425 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -121,6 +121,7 @@ enum { HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH, HTTP_DECODER_EVENT_URI_HOST_INVALID, HTTP_DECODER_EVENT_HEADER_HOST_INVALID, + HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT, HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT, /* suricata errors/warnings */ From bed5b284121e800b6c5ae245a45085811f4d719a Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 19 Feb 2015 09:37:23 +0100 Subject: [PATCH 0246/2553] util-ioctl: don't build code RX ring on old system If ETHTOOL_GRXRINGS is undefined we will not be able to build the RX rings code. So we can make the build conditional to the definition of ETHTOOL_GRXRINGS. --- src/util-ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 7ea8f22a427f..f08dea719e2d 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -212,7 +212,7 @@ int GetIfaceOffloading(const char *pcap_dev) int GetIfaceRSSQueuesNum(const char *pcap_dev) { -#ifdef HAVE_LINUX_ETHTOOL_H +#if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS struct ifreq ifr; struct ethtool_rxnfc nfccmd; int fd; From 3f44bd504a055e863629e930c72028899f818a3d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 19 Feb 2015 10:29:14 +0100 Subject: [PATCH 0247/2553] CentOS 5.11 pkg-config fix Check for the minimal pkg-config 0.21 version. Without it, CentOS' pkg-config will fail with the warning: configure: error: The pkg-config script could not be found or is too old. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 0cbba4477128..ec2941ce87c1 100644 --- a/configure.ac +++ b/configure.ac @@ -11,6 +11,7 @@ AC_LANG_C AC_PROG_CC_C99 AC_PROG_LIBTOOL + PKG_PROG_PKG_CONFIG(0.21) # 0.21 is the CentOS 5.11 version AC_DEFUN([FAIL_MESSAGE],[ echo From 256388325dbe701f43a6710f725fe8a24a766258 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 19 Feb 2015 10:39:50 +0100 Subject: [PATCH 0248/2553] Fix compiler warning on CentOS 5.11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cc1: warnings being treated as errors app-layer-smtp.c: In function ‘SMTPParseCommandBDAT’: app-layer-smtp.c:908: warning: dereferencing type-punned pointer will break strict-aliasing rules --- src/app-layer-smtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 91dd244c203f..15d507d26169 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -903,10 +903,10 @@ static int SMTPParseCommandBDAT(SMTPState *state) /* decoder event */ return -1; } - uint8_t *endptr = NULL; + char *endptr = NULL; state->bdat_chunk_len = strtoul((const char *)state->current_line + i, (char **)&endptr, 10); - if (endptr == state->current_line + i) { + if ((uint8_t *)endptr == state->current_line + i) { /* decoder event */ return -1; } From 784690b89a863334c7697c40c611661da95ebc54 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 19 Feb 2015 11:45:09 +0100 Subject: [PATCH 0249/2553] Fix make distcheck on CentOS 5.11 datarootdir was undefined. Define it. --- doc/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Makefile.am b/doc/Makefile.am index e507b07b0e25..386debc8fc2c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -30,5 +30,6 @@ Ubuntu_Installation.txt \ Ubuntu_Installation_from_GIT.txt \ Windows.txt +datarootdir=@datarootdir@ docdir = ${datarootdir}/doc/${PACKAGE} dist_doc_DATA = ${EXTRA_DIST} From ae8f2a4e62dc2483266292f7e36b0ebb040e6f90 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 19 Feb 2015 20:58:36 +0100 Subject: [PATCH 0250/2553] stream: fix unittests wrt flow --- src/stream-tcp-reassemble.c | 1 + src/stream-tcp.c | 73 +++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index cebdd53544d5..ae14fd7c7863 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -6143,6 +6143,7 @@ static int StreamTcpReassembleTest39 (void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; diff --git a/src/stream-tcp.c b/src/stream-tcp.c index a8c0e37b5b08..28ef48f7553a 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5958,6 +5958,7 @@ static int StreamTcpTest01 (void) Flow f; memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -5985,6 +5986,7 @@ static int StreamTcpTest01 (void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6015,6 +6017,7 @@ static int StreamTcpTest02 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -6084,6 +6087,7 @@ static int StreamTcpTest02 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6111,6 +6115,7 @@ static int StreamTcpTest03 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -6160,6 +6165,7 @@ static int StreamTcpTest03 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6187,6 +6193,7 @@ static int StreamTcpTest04 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -6229,6 +6236,7 @@ static int StreamTcpTest04 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6257,6 +6265,7 @@ static int StreamTcpTest05 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -6334,6 +6343,7 @@ static int StreamTcpTest05 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6363,6 +6373,7 @@ static int StreamTcpTest06 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -6400,6 +6411,7 @@ static int StreamTcpTest06 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6434,6 +6446,7 @@ static int StreamTcpTest07 (void) memset(&tcpvars, 0, sizeof(TCPVars)); memset(&ts, 0, sizeof(TCPOpt)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -6489,6 +6502,7 @@ static int StreamTcpTest07 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6524,6 +6538,7 @@ static int StreamTcpTest08 (void) memset(&tcpvars, 0, sizeof(TCPVars)); memset(&ts, 0, sizeof(TCPOpt)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -6581,6 +6596,7 @@ static int StreamTcpTest08 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6611,6 +6627,7 @@ static int StreamTcpTest09 (void) memset(&stt, 0, sizeof(StreamTcpThread)); memset(&tcph, 0, sizeof(TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -6660,6 +6677,7 @@ static int StreamTcpTest09 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6687,6 +6705,7 @@ static int StreamTcpTest10 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -6762,6 +6781,7 @@ static int StreamTcpTest10 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6789,6 +6809,7 @@ static int StreamTcpTest11 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -6865,6 +6886,7 @@ static int StreamTcpTest11 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6892,6 +6914,7 @@ static int StreamTcpTest12 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -6960,6 +6983,7 @@ static int StreamTcpTest12 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6988,6 +7012,7 @@ static int StreamTcpTest13 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -7068,6 +7093,7 @@ static int StreamTcpTest13 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7195,6 +7221,7 @@ static int StreamTcpTest14 (void) memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -7333,6 +7360,7 @@ static int StreamTcpTest14 (void) ConfRestoreContextBackup(); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7360,6 +7388,7 @@ static int StreamTcp4WHSTest01 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -7414,6 +7443,7 @@ static int StreamTcp4WHSTest01 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7442,6 +7472,7 @@ static int StreamTcp4WHSTest02 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -7485,6 +7516,7 @@ static int StreamTcp4WHSTest02 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7513,6 +7545,7 @@ static int StreamTcp4WHSTest03 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -7567,6 +7600,7 @@ static int StreamTcp4WHSTest03 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7601,6 +7635,7 @@ static int StreamTcpTest15 (void) memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -7739,6 +7774,7 @@ static int StreamTcpTest15 (void) ConfRestoreContextBackup(); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7773,6 +7809,7 @@ static int StreamTcpTest16 (void) memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -7911,6 +7948,7 @@ static int StreamTcpTest16 (void) ConfRestoreContextBackup(); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7946,6 +7984,7 @@ static int StreamTcpTest17 (void) memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -8084,6 +8123,7 @@ static int StreamTcpTest17 (void) ConfRestoreContextBackup(); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -8374,6 +8414,7 @@ static int StreamTcpTest23(void) StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); + FLOW_INITIALIZE(&f); ssn.client.os_policy = OS_POLICY_BSD; f.protoctx = &ssn; p->src.family = AF_INET; @@ -8431,6 +8472,7 @@ static int StreamTcpTest23(void) printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse)); } SCFree(p); + FLOW_DESTROY(&f); return result; } @@ -8461,6 +8503,7 @@ static int StreamTcpTest24(void) memset(&f, 0, sizeof (Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); ssn.client.os_policy = OS_POLICY_BSD; f.protoctx = &ssn; p->src.family = AF_INET; @@ -8518,6 +8561,7 @@ static int StreamTcpTest24(void) printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse)); } SCFree(p); + FLOW_DESTROY(&f); return result; } @@ -8547,6 +8591,7 @@ static int StreamTcpTest25(void) memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p->flow = &f; tcph.th_win = htons(5480); @@ -8618,6 +8663,7 @@ static int StreamTcpTest25(void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -8647,6 +8693,7 @@ static int StreamTcpTest26(void) memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p->flow = &f; tcph.th_win = htons(5480); @@ -8714,6 +8761,7 @@ static int StreamTcpTest26(void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -8743,6 +8791,7 @@ static int StreamTcpTest27(void) memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p->flow = &f; tcph.th_win = htons(5480); @@ -8810,6 +8859,7 @@ static int StreamTcpTest27(void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -8897,6 +8947,7 @@ static int StreamTcpTest29(void) uint8_t packet[1460] = ""; int result = 1; + FLOW_INITIALIZE(&f); StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ @@ -9038,6 +9089,7 @@ static int StreamTcpTest30(void) 0x49, 0x4c }; int result = 1; + FLOW_INITIALIZE(&f); StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ @@ -9179,6 +9231,7 @@ static int StreamTcpTest31(void) StreamTcpInitConfig(TRUE); + FLOW_INITIALIZE(&f); /* prevent L7 from kicking in */ ssn.client.os_policy = OS_POLICY_LINUX; @@ -9319,6 +9372,7 @@ static int StreamTcpTest32(void) memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p.flow = &f; tcph.th_win = htons(5480); @@ -9409,6 +9463,8 @@ static int StreamTcpTest33 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + + FLOW_INITIALIZE(&f); p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -9511,6 +9567,8 @@ static int StreamTcpTest34 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + + FLOW_INITIALIZE(&f); p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN|TH_PUSH; @@ -9577,6 +9635,8 @@ static int StreamTcpTest35 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + + FLOW_INITIALIZE(&f); p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN|TH_URG; @@ -9642,6 +9702,7 @@ static int StreamTcpTest36(void) memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p.flow = &f; tcph.th_win = htons(5480); @@ -9829,6 +9890,7 @@ static int StreamTcpTest37(void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -9862,6 +9924,7 @@ static int StreamTcpTest38 (void) return 0; memset(p, 0, SIZE_OF_PACKET); + FLOW_INITIALIZE(&f); p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -9946,6 +10009,7 @@ static int StreamTcpTest38 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -9978,6 +10042,7 @@ static int StreamTcpTest39 (void) return 0; memset(p, 0, SIZE_OF_PACKET); + FLOW_INITIALIZE(&f); p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -10064,6 +10129,7 @@ static int StreamTcpTest39 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -10215,6 +10281,7 @@ static int StreamTcpTest42 (void) StreamTcpInitConfig(TRUE); + FLOW_INITIALIZE(&f); p->tcph = &tcph; tcph.th_win = htons(5480); p->flow = &f; @@ -10280,6 +10347,7 @@ static int StreamTcpTest42 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -10307,6 +10375,7 @@ static int StreamTcpTest43 (void) StreamTcpInitConfig(TRUE); + FLOW_INITIALIZE(&f); p->tcph = &tcph; tcph.th_win = htons(5480); p->flow = &f; @@ -10372,6 +10441,7 @@ static int StreamTcpTest43 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -10399,6 +10469,7 @@ static int StreamTcpTest44 (void) StreamTcpInitConfig(TRUE); + FLOW_INITIALIZE(&f); p->tcph = &tcph; tcph.th_win = htons(5480); p->flow = &f; @@ -10459,6 +10530,7 @@ static int StreamTcpTest44 (void) StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -10487,6 +10559,7 @@ static int StreamTcpTest45 (void) StreamTcpInitConfig(TRUE); stream_config.max_synack_queued = 2; + FLOW_INITIALIZE(&f); p->tcph = &tcph; tcph.th_win = htons(5480); p->flow = &f; From ae6ef9acb42bbfd4decd94f6a7f278f3bcab97fe Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 4 Mar 2015 16:47:28 +0100 Subject: [PATCH 0251/2553] flow-manager: init global atomics --- src/flow-manager.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/flow-manager.c b/src/flow-manager.c index 3bfa477a4a6a..338ddc896d6c 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -994,6 +994,8 @@ void TmModuleFlowManagerRegister (void) tmm_modules[TMM_FLOWMANAGER].cap_flags = 0; tmm_modules[TMM_FLOWMANAGER].flags = TM_FLAG_MANAGEMENT_TM; SCLogDebug("%s registered", tmm_modules[TMM_FLOWMANAGER].name); + + SC_ATOMIC_INIT(flowmgr_cnt); } void TmModuleFlowRecyclerRegister (void) @@ -1006,6 +1008,8 @@ void TmModuleFlowRecyclerRegister (void) tmm_modules[TMM_FLOWRECYCLER].cap_flags = 0; tmm_modules[TMM_FLOWRECYCLER].flags = TM_FLAG_MANAGEMENT_TM; SCLogDebug("%s registered", tmm_modules[TMM_FLOWRECYCLER].name); + + SC_ATOMIC_INIT(flowrec_cnt); } #ifdef UNITTESTS From ed147d3b91bf5c2755e1bfbfd2eafbe6e724e968 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 12 Feb 2015 22:18:23 +0100 Subject: [PATCH 0252/2553] runmode-pcap-file: suppress useless include --- src/runmode-pcap-file.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index bd0e68e604b5..4265585644ce 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -22,7 +22,6 @@ #include "runmode-pcap-file.h" #include "log-httplog.h" #include "output.h" -#include "source-pfring.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" From ee7422de0a79054f0271b40fb17dc21d6b12a675 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 12 Feb 2015 22:27:07 +0100 Subject: [PATCH 0253/2553] pcap-file: add missing atomic init It is mandatory to init all atomic to avoid problem on system without atomic support. --- src/runmode-pcap-file.c | 6 ++++++ src/source-pcap-file.c | 5 +++++ src/source-pcap-file.h | 2 ++ 3 files changed, 13 insertions(+) diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index 4265585644ce..f5a3c196b40b 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -24,6 +24,8 @@ #include "output.h" #include "detect-engine-mpm.h" +#include "source-pcap-file.h" + #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" @@ -74,6 +76,8 @@ int RunModeFilePcapSingle(DetectEngineCtx *de_ctx) RunModeInitialize(); TimeModeSetOffline(); + PcapFileGlobalInit(); + /* create the threads */ ThreadVars *tv = TmThreadCreatePacketHandler("PcapFile", "packetpool", "packetpool", @@ -164,6 +168,8 @@ int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) TimeModeSetOffline(); + PcapFileGlobalInit(); + /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 8638bdd8d22a..f7dcb4c06297 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -131,6 +131,11 @@ void TmModuleDecodePcapFileRegister (void) tmm_modules[TMM_DECODEPCAPFILE].flags = TM_FLAG_DECODE_TM; } +void PcapFileGlobalInit() +{ + SC_ATOMIC_INIT(pcap_g.invalid_checksums); +} + void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) { SCEnter(); diff --git a/src/source-pcap-file.h b/src/source-pcap-file.h index 636cbdeb6da3..fa76a1a8f8e7 100644 --- a/src/source-pcap-file.h +++ b/src/source-pcap-file.h @@ -29,5 +29,7 @@ void TmModuleDecodePcapFileRegister (void); void PcapIncreaseInvalidChecksum(); +void PcapFileGlobalInit(); + #endif /* __SOURCE_PCAP_FILE_H__ */ From ec2be2643b0e1e1f92245a56cf8e53cd19d7c6a2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 4 Mar 2015 17:06:59 +0100 Subject: [PATCH 0254/2553] app-layer: init flow in tests --- src/app-layer.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/app-layer.c b/src/app-layer.c index 857a0b49955f..65bf8e8730b8 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -692,6 +692,7 @@ static int AppLayerTest01(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -907,6 +908,7 @@ static int AppLayerTest01(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -930,6 +932,7 @@ static int AppLayerTest02(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -1194,6 +1197,7 @@ static int AppLayerTest02(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -1217,6 +1221,7 @@ static int AppLayerTest03(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -1431,6 +1436,7 @@ static int AppLayerTest03(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -1454,6 +1460,7 @@ static int AppLayerTest04(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -1717,6 +1724,7 @@ static int AppLayerTest04(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -1740,6 +1748,7 @@ static int AppLayerTest05(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -1955,6 +1964,7 @@ static int AppLayerTest05(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -1978,6 +1988,7 @@ static int AppLayerTest06(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -2169,6 +2180,7 @@ static int AppLayerTest06(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -2192,6 +2204,7 @@ static int AppLayerTest07(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -2407,6 +2420,7 @@ static int AppLayerTest07(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -2430,6 +2444,7 @@ static int AppLayerTest08(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -2645,6 +2660,7 @@ static int AppLayerTest08(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -2670,6 +2686,7 @@ static int AppLayerTest09(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -2925,6 +2942,7 @@ static int AppLayerTest09(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -2949,6 +2967,7 @@ static int AppLayerTest10(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -3179,6 +3198,7 @@ static int AppLayerTest10(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -3204,6 +3224,7 @@ static int AppLayerTest11(void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; @@ -3483,6 +3504,7 @@ static int AppLayerTest11(void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } From 20b984999999fa48822fef9763efe492dd6b4de8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Feb 2015 07:37:54 +0100 Subject: [PATCH 0255/2553] util-magic: make unittests less specific So they pass on CentOS 5.11 as well. --- src/util-magic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util-magic.c b/src/util-magic.c index 8b077d31c075..fa05c6d90eb6 100644 --- a/src/util-magic.c +++ b/src/util-magic.c @@ -398,8 +398,8 @@ int MagicDetectTest04(void) } result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); - if (result == NULL || strcmp(result, "OpenOffice.org 1.x Database file") != 0) { - printf("result %p:%s, not \"OpenOffice.org 1.x Database file\": ", result,result?result:"(null)"); + if (result == NULL || strncmp(result, "OpenOffice.org 1.x", 18) != 0) { + printf("result %p:%s, not \"OpenOffice.org 1.x\": ", result,result?result:"(null)"); goto end; } @@ -566,8 +566,8 @@ int MagicDetectTest08(void) } result = MagicGlobalLookup(buffer, buffer_len); - if (result == NULL || strcmp(result, "OpenOffice.org 1.x Database file") != 0) { - printf("result %p:%s, not \"OpenOffice.org 1.x Database file\": ", result,result?result:"(null)"); + if (result == NULL || strncmp(result, "OpenOffice.org 1.x", 18) != 0) { + printf("result %p:%s, not \"OpenOffice.org 1.x\": ", result,result?result:"(null)"); goto end; } From 5f4b745f92cc9cdb29f17202eb477d0ae8c8567e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 18 Feb 2015 11:45:12 +0100 Subject: [PATCH 0256/2553] build: don't link with libnfnetlink Don't link suricata with libnfnetlink when we don't have support for NFQUEUE or NFLOG. Previously, suricata was linked with this library without reason. --- configure.ac | 75 +++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/configure.ac b/configure.ac index ec2941ce87c1..d2b5221e6032 100644 --- a/configure.ac +++ b/configure.ac @@ -657,44 +657,51 @@ AS_IF([test "x$enable_unixsocket" = "xyes"], [AC_DEFINE([BUILD_UNIX_SOCKET], [1], [Unix socket support enabled])]) + AC_ARG_ENABLE(nflog, + AS_HELP_STRING([--enable-nflog],[Enable libnetfilter_log support]), + [ enable_nflog="yes"], + [ enable_nflog="no"]) + AC_ARG_ENABLE(nfqueue, + AS_HELP_STRING([--enable-nfqueue], [Enable NFQUEUE support for inline IDP]),[enable_nfqueue=yes],[enable_nfqueue=no]) + + if test "x$enable_nflog" = "xyes" || test "x$enable_nfqueue" = "xyes"; then # libnfnetlink - case $host in - *-*-mingw32*) - ;; - *) - AC_ARG_WITH(libnfnetlink_includes, - [ --with-libnfnetlink-includes=DIR libnfnetlink include directory], - [with_libnfnetlink_includes="$withval"],[with_libnfnetlink_includes=no]) - AC_ARG_WITH(libnfnetlink_libraries, - [ --with-libnfnetlink-libraries=DIR libnfnetlink library directory], - [with_libnfnetlink_libraries="$withval"],[with_libnfnetlink_libraries="no"]) - - if test "$with_libnfnetlink_includes" != "no"; then - CPPFLAGS="${CPPFLAGS} -I${with_libnfnetlink_includes}" - fi + case $host in + *-*-mingw32*) + ;; + *) + AC_ARG_WITH(libnfnetlink_includes, + [ --with-libnfnetlink-includes=DIR libnfnetlink include directory], + [with_libnfnetlink_includes="$withval"],[with_libnfnetlink_includes=no]) + AC_ARG_WITH(libnfnetlink_libraries, + [ --with-libnfnetlink-libraries=DIR libnfnetlink library directory], + [with_libnfnetlink_libraries="$withval"],[with_libnfnetlink_libraries="no"]) + + if test "$with_libnfnetlink_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_libnfnetlink_includes}" + fi - if test "$with_libnfnetlink_libraries" != "no"; then - LDFLAGS="${LDFLAGS} -L${with_libnfnetlink_libraries}" - fi + if test "$with_libnfnetlink_libraries" != "no"; then + LDFLAGS="${LDFLAGS} -L${with_libnfnetlink_libraries}" + fi - NFNL="" - AC_CHECK_LIB(nfnetlink, nfnl_fd,, NFNL="no") + NFNL="" + AC_CHECK_LIB(nfnetlink, nfnl_fd,, NFNL="no") - if test "$NFNL" = "no"; then - echo - echo " ERROR! nfnetlink library not found, go get it" - echo " from www.netfilter.org." - echo " we automatically append libnetfilter_queue/ when searching" - echo " for headers etc. when the --with-libnfnetlink-includes directive" - echo " is used" - echo - fi - ;; - esac + if test "$NFNL" = "no"; then + echo + echo " ERROR! nfnetlink library not found, go get it" + echo " from www.netfilter.org." + echo " we automatically append libnetfilter_queue/ when searching" + echo " for headers etc. when the --with-libnfnetlink-includes directive" + echo " is used" + echo + fi + ;; + esac + fi #enable support for NFQUEUE - AC_ARG_ENABLE(nfqueue, - AS_HELP_STRING([--enable-nfqueue], [Enable NFQUEUE support for inline IDP]),,[enable_nfqueue=no]) AS_IF([test "x$enable_nfqueue" = "xyes"], [ CFLAGS="$CFLAGS -DNFQ" @@ -781,10 +788,6 @@ ]) # libnetfilter_log - AC_ARG_ENABLE(nflog, - AS_HELP_STRING([--enable-nflog],[Enable libnetfilter_log support]), - [ enable_nflog="yes"], - [ enable_nflog="no"]) AC_ARG_WITH(libnetfilter_log_includes, [ --with-libnetfilter_log-includes=DIR libnetfilter_log include directory], [with_libnetfilter_log_includes="$withval"],[with_libnetfilter_log_includes="no"]) From 972037248d23ce3edaa654e89bc15863db6564f6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 15 Jan 2015 09:44:45 -0600 Subject: [PATCH 0257/2553] Define _DEFAULT_SOURCE. Its the replacement for _BSD_SOURCE which which has been deprecated as of glibc 2.20. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d2b5221e6032..a846ec20e5c2 100644 --- a/configure.ac +++ b/configure.ac @@ -891,7 +891,7 @@ LLIBNET="" AC_CHECK_LIB(net, libnet_write,, LLIBNET="no") if test "$LLIBNET" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_LIBNET11 -D_BSD_SOURCE -D__BSD_SOURCE -D__FAVOR_BSD -DHAVE_NET_ETHERNET_H" + CFLAGS="${CFLAGS} -DHAVE_LIBNET11 -D_DEFAULT_SOURCE -D_BSD_SOURCE -D__BSD_SOURCE -D__FAVOR_BSD -DHAVE_NET_ETHERNET_H" else #if we displayed a warning already no reason to do it again. if test "$LIBNET_DETECT_FAIL" = "no"; then From fb0ecaba05cfde20198975037116ce9b2effa7b1 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Thu, 26 Feb 2015 23:22:35 -0500 Subject: [PATCH 0258/2553] Inject pseudo packet periodically when there is not traffic in mPIPE. To prevent pseudo packets from not being processed when there is no traffic, inject a pseudo packet if no traffic is seen by a thread for ~100ms. --- src/source-mpipe.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/source-mpipe.c b/src/source-mpipe.c index 5bac179ab326..1eb30f01542b 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -317,6 +317,24 @@ static uint16_t XlateStack(MpipeThreadVars *ptv, int stack_idx) } } +static void SendNoOpPacket(ThreadVars *tv, TmSlot *slot) +{ + Packet *p = PacketPoolGetPacket(); + if (p == NULL) { + return; + } + + p->datalink = DLT_RAW; + p->proto = IPPROTO_TCP; + + /* So that DecodeMpipe ignores is. */ + p->flags |= PKT_PSEUDO_STREAM_END; + + p->flow = NULL; + + TmThreadsSlotProcessPkt(tv, slot, p); +} + /** * \brief Receives packets from an interface via gxio mpipe. */ @@ -348,6 +366,7 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) MpipeReceiveOpenIqueue(rank); gxio_mpipe_iqueue_t* iqueue = thread_iqueue; int update_counter = 0; + uint64_t last_packet_time = get_cycle_count(); for (;;) { @@ -392,6 +411,8 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) } /* Move forward M packets in ingress ring. */ gxio_mpipe_iqueue_advance(iqueue, m); + + last_packet_time = get_cycle_count(); } if (update_counter-- <= 0) { /* Only periodically update and check for termination. */ @@ -401,6 +422,14 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) if (suricata_ctl_flags != 0) { break; } + + // If no packet has been received for some period of time, process a NOP packet + // just to make sure that pseudo packets from the Flow manager get processed. + uint64_t now = get_cycle_count(); + if (now - last_packet_time > 100000000) { + SendNoOpPacket(ptv->tv, ptv->slot); + last_packet_time = now; + } } } SCReturnInt(TM_ECODE_OK); From 22182e7a8430626753b4903db9705b8359a08904 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 6 Mar 2015 19:55:28 +0100 Subject: [PATCH 0259/2553] json-tls: refactor to export logging function To be able to add TLS data in alert we need to do the same as what is done with HTTP ie export the logging functions. --- src/output-json-tls.c | 24 +++++++++++++++--------- src/output-json-tls.h | 7 +++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 129b8177bf31..f2843e49fedd 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -72,7 +72,19 @@ typedef struct JsonTlsLogThread_ { #define SSL_VERSION_LENGTH 13 -static void LogTlsLogExtendedJSON(json_t *tjs, SSLState * state) +void JsonTlsLogJSONBasic(json_t *js, SSLState *ssl_state) +{ + /* tls.subject */ + json_object_set_new(js, "subject", + json_string(ssl_state->server_connp.cert0_subject)); + + /* tls.issuerdn */ + json_object_set_new(js, "issuerdn", + json_string(ssl_state->server_connp.cert0_issuerdn)); + +} + +void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) { char ssl_version[SSL_VERSION_LENGTH + 1]; @@ -145,16 +157,10 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) /* reset */ MemBufferReset(buffer); - /* tls.subject */ - json_object_set_new(tjs, "subject", - json_string(ssl_state->server_connp.cert0_subject)); - - /* tls.issuerdn */ - json_object_set_new(tjs, "issuerdn", - json_string(ssl_state->server_connp.cert0_issuerdn)); + JsonTlsLogJSONBasic(tjs, ssl_state); if (tls_ctx->flags & LOG_TLS_EXTENDED) { - LogTlsLogExtendedJSON(tjs, ssl_state); + JsonTlsLogJSONExtended(tjs, ssl_state); } json_object_set_new(js, "tls", tjs); diff --git a/src/output-json-tls.h b/src/output-json-tls.h index 931414f3013b..f330ad898aad 100644 --- a/src/output-json-tls.h +++ b/src/output-json-tls.h @@ -26,4 +26,11 @@ void TmModuleJsonTlsLogRegister (void); +#ifdef HAVE_LIBJANSSON +#include "app-layer-ssl.h" + +void JsonTlsLogJSONBasic(json_t *js, SSLState *ssl_state); +void JsonTlsLogJSONExtended(json_t *js, SSLState *ssl_state); +#endif /* HAVE_LIBJANSSON */ + #endif /* __OUTPUT_JSON_TLS_H__ */ From 180faece7cb5df942bff8f6583e68c45ed7ba19f Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 6 Mar 2015 20:03:13 +0100 Subject: [PATCH 0260/2553] json-alert: log tls info in alert This patch adds the capabilities to log the TLS information the same way it is currently possible to do with HTTP. As it is quite hard to read ASN.1 directly in the stream, this will help people to understand why suricata is firing on alert relative to TLS. --- src/output-json-alert.c | 38 ++++++++++++++++++++++++++++++++++++++ suricata.yaml.in | 1 + 2 files changed, 39 insertions(+) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index cd1168aa2d95..44e418f78a4f 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -52,6 +52,7 @@ #include "output.h" #include "output-json.h" #include "output-json-http.h" +#include "output-json-tls.h" #include "util-byte.h" #include "util-privs.h" @@ -70,6 +71,7 @@ #define LOG_JSON_PACKET 2 #define LOG_JSON_PAYLOAD_BASE64 4 #define LOG_JSON_HTTP 8 +#define LOG_JSON_TLS 16 #define JSON_STREAM_BUFFER_SIZE 4096 @@ -124,6 +126,23 @@ static void AlertJsonHttp(const Flow *f, json_t *js) return; } +static void AlertJsonTls(const Flow *f, json_t *js) +{ + SSLState *ssl_state = (SSLState *)f->alstate; + if (ssl_state) { + json_t *tjs = json_object(); + if (unlikely(tjs == NULL)) + return; + + JsonTlsLogJSONBasic(tjs, ssl_state); + JsonTlsLogJSONExtended(tjs, ssl_state); + + json_object_set_new(js, "tls", tjs); + } + + return; +} + static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) { MemBuffer *payload = aft->payload_buffer; @@ -188,6 +207,19 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } } + if (json_output_ctx->flags & LOG_JSON_TLS) { + if (p->flow != NULL) { + FLOWLOCK_RDLOCK(p->flow); + uint16_t proto = FlowGetAppProtocol(p->flow); + + /* http alert */ + if (proto == ALPROTO_TLS) + AlertJsonTls(p->flow, js); + + FLOWLOCK_UNLOCK(p->flow); + } + } + /* payload */ if (json_output_ctx->flags & (LOG_JSON_PAYLOAD | LOG_JSON_PAYLOAD_BASE64)) { int stream = (p->proto == IPPROTO_TCP) ? @@ -521,7 +553,13 @@ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) const char *packet = ConfNodeLookupChildValue(conf, "packet"); const char *payload_printable = ConfNodeLookupChildValue(conf, "payload-printable"); const char *http = ConfNodeLookupChildValue(conf, "http"); + const char *tls = ConfNodeLookupChildValue(conf, "tls"); + if (tls != NULL) { + if (ConfValIsTrue(tls)) { + json_output_ctx->flags |= LOG_JSON_TLS; + } + } if (http != NULL) { if (ConfValIsTrue(http)) { json_output_ctx->flags |= LOG_JSON_HTTP; diff --git a/suricata.yaml.in b/suricata.yaml.in index 5caa0031e647..be62eeac9092 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -105,6 +105,7 @@ outputs: # payload-printable: yes # enable dumping payload in printable (lossy) format # packet: yes # enable dumping of packet (without stream segments) # http: yes # enable dumping of http fields + # tls: yes # enable dumping of tls fields # HTTP X-Forwarded-For support by adding an extra field or overwriting # the source or destination IP address (depending on flow direction) From c1970a3655360ef603288d50451a6547becdaf3a Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 6 Mar 2015 21:05:51 +0100 Subject: [PATCH 0261/2553] json-ssh: export logging function It will be use in alert logging to display SSH information. --- src/output-json-ssh.c | 45 +++++++++++++++++++++++++------------------ src/output-json-ssh.h | 6 ++++++ 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 0a6ea46230fd..d8494d5e35f4 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -65,6 +65,31 @@ typedef struct JsonSshLogThread_ { MemBuffer *buffer; } JsonSshLogThread; + +void JsonSshLogJSON(json_t *tjs, SshState *ssh_state) +{ + json_t *cjs = json_object(); + if (cjs != NULL) { + json_object_set_new(cjs, "proto_version", + json_string((char *)ssh_state->cli_hdr.proto_version)); + + json_object_set_new(cjs, "software_version", + json_string((char *)ssh_state->cli_hdr.software_version)); + } + json_object_set_new(tjs, "client", cjs); + + json_t *sjs = json_object(); + if (sjs != NULL) { + json_object_set_new(sjs, "proto_version", + json_string((char *)ssh_state->srv_hdr.proto_version)); + + json_object_set_new(sjs, "software_version", + json_string((char *)ssh_state->srv_hdr.software_version)); + } + json_object_set_new(tjs, "server", sjs); + +} + static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) { JsonSshLogThread *aft = (JsonSshLogThread *)thread_data; @@ -102,25 +127,7 @@ static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) /* reset */ MemBufferReset(buffer); - json_t *cjs = json_object(); - if (cjs != NULL) { - json_object_set_new(cjs, "proto_version", - json_string((char *)ssh_state->cli_hdr.proto_version)); - - json_object_set_new(cjs, "software_version", - json_string((char *)ssh_state->cli_hdr.software_version)); - } - json_object_set_new(tjs, "client", cjs); - - json_t *sjs = json_object(); - if (sjs != NULL) { - json_object_set_new(sjs, "proto_version", - json_string((char *)ssh_state->srv_hdr.proto_version)); - - json_object_set_new(sjs, "software_version", - json_string((char *)ssh_state->srv_hdr.software_version)); - } - json_object_set_new(tjs, "server", sjs); + JsonSshLogJSON(tjs, ssh_state); json_object_set_new(js, "ssh", tjs); diff --git a/src/output-json-ssh.h b/src/output-json-ssh.h index af0711c711f0..5d0752bf2a53 100644 --- a/src/output-json-ssh.h +++ b/src/output-json-ssh.h @@ -26,4 +26,10 @@ void TmModuleJsonSshLogRegister (void); +#ifdef HAVE_LIBJANSSON +#include "app-layer-ssh.h" + +void JsonSshLogJSON(json_t *js, SshState *tx); +#endif + #endif /* __OUTPUT_JSON_SSH_H__ */ From 881f32cc02e897fec8cb0c1bec022709f4748083 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 6 Mar 2015 21:16:52 +0100 Subject: [PATCH 0262/2553] json-alert: add SSH fields in alert logging --- src/output-json-alert.c | 37 +++++++++++++++++++++++++++++++++++++ suricata.yaml.in | 1 + 2 files changed, 38 insertions(+) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 44e418f78a4f..22c48963a9d4 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -53,6 +53,7 @@ #include "output-json.h" #include "output-json-http.h" #include "output-json-tls.h" +#include "output-json-ssh.h" #include "util-byte.h" #include "util-privs.h" @@ -72,6 +73,7 @@ #define LOG_JSON_PAYLOAD_BASE64 4 #define LOG_JSON_HTTP 8 #define LOG_JSON_TLS 16 +#define LOG_JSON_SSH 32 #define JSON_STREAM_BUFFER_SIZE 4096 @@ -143,6 +145,22 @@ static void AlertJsonTls(const Flow *f, json_t *js) return; } +static void AlertJsonSsh(const Flow *f, json_t *js) +{ + SshState *ssh_state = (SshState *)f->alstate; + if (ssh_state) { + json_t *tjs = json_object(); + if (unlikely(tjs == NULL)) + return; + + JsonSshLogJSON(tjs, ssh_state); + + json_object_set_new(js, "ssh", tjs); + } + + return; +} + static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) { MemBuffer *payload = aft->payload_buffer; @@ -220,6 +238,19 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } } + if (json_output_ctx->flags & LOG_JSON_SSH) { + if (p->flow != NULL) { + FLOWLOCK_RDLOCK(p->flow); + uint16_t proto = FlowGetAppProtocol(p->flow); + + /* http alert */ + if (proto == ALPROTO_SSH) + AlertJsonSsh(p->flow, js); + + FLOWLOCK_UNLOCK(p->flow); + } + } + /* payload */ if (json_output_ctx->flags & (LOG_JSON_PAYLOAD | LOG_JSON_PAYLOAD_BASE64)) { int stream = (p->proto == IPPROTO_TCP) ? @@ -554,7 +585,13 @@ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) const char *payload_printable = ConfNodeLookupChildValue(conf, "payload-printable"); const char *http = ConfNodeLookupChildValue(conf, "http"); const char *tls = ConfNodeLookupChildValue(conf, "tls"); + const char *ssh = ConfNodeLookupChildValue(conf, "ssh"); + if (ssh != NULL) { + if (ConfValIsTrue(ssh)) { + json_output_ctx->flags |= LOG_JSON_SSH; + } + } if (tls != NULL) { if (ConfValIsTrue(tls)) { json_output_ctx->flags |= LOG_JSON_TLS; diff --git a/suricata.yaml.in b/suricata.yaml.in index be62eeac9092..beb8f7e4a5cf 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -106,6 +106,7 @@ outputs: # packet: yes # enable dumping of packet (without stream segments) # http: yes # enable dumping of http fields # tls: yes # enable dumping of tls fields + # ssh: yes # enable dumping of ssh fields # HTTP X-Forwarded-For support by adding an extra field or overwriting # the source or destination IP address (depending on flow direction) From 54b13851cc390eb1a7963d564a6a1c6d733ccd50 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 6 Mar 2015 22:17:30 +0100 Subject: [PATCH 0263/2553] flow: constify getters param Some potential callers are already using constified values so it is good to do it. --- src/flow.c | 4 ++-- src/flow.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/flow.c b/src/flow.c index 3255bbf58adf..4e9b6848069f 100644 --- a/src/flow.c +++ b/src/flow.c @@ -860,12 +860,12 @@ int FlowSetProtoEmergencyTimeout(uint8_t proto, uint32_t emerg_new_timeout, return 1; } -AppProto FlowGetAppProtocol(Flow *f) +AppProto FlowGetAppProtocol(const Flow *f) { return f->alproto; } -void *FlowGetAppState(Flow *f) +void *FlowGetAppState(const Flow *f) { return f->alstate; } diff --git a/src/flow.h b/src/flow.h index 8d699fc98d4c..48b4b075c0ae 100644 --- a/src/flow.h +++ b/src/flow.h @@ -574,8 +574,8 @@ static inline void FlowDeReference(Flow **d) int FlowClearMemory(Flow *,uint8_t ); -AppProto FlowGetAppProtocol(Flow *f); -void *FlowGetAppState(Flow *f); +AppProto FlowGetAppProtocol(const Flow *f); +void *FlowGetAppState(const Flow *f); void FlowHandlePacketUpdateRemove(Flow *f, Packet *p); void FlowHandlePacketUpdate(Flow *f, Packet *p); From 47d9c7b21170540073d4861c4f2e598bd3bf9c5b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 6 Mar 2015 22:21:12 +0100 Subject: [PATCH 0264/2553] json-alert: use getter for appstate --- src/output-json-alert.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 22c48963a9d4..60dbf1fdb6d9 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -108,7 +108,7 @@ static int AlertJsonPrintStreamSegmentCallback(const Packet *p, void *data, uint */ static void AlertJsonHttp(const Flow *f, json_t *js) { - HtpState *htp_state = (HtpState *)f->alstate; + HtpState *htp_state = (HtpState *)FlowGetAppState(f); if (htp_state) { uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, tx_id); @@ -130,7 +130,7 @@ static void AlertJsonHttp(const Flow *f, json_t *js) static void AlertJsonTls(const Flow *f, json_t *js) { - SSLState *ssl_state = (SSLState *)f->alstate; + SSLState *ssl_state = (SSLState *)FlowGetAppState(f); if (ssl_state) { json_t *tjs = json_object(); if (unlikely(tjs == NULL)) @@ -147,7 +147,7 @@ static void AlertJsonTls(const Flow *f, json_t *js) static void AlertJsonSsh(const Flow *f, json_t *js) { - SshState *ssh_state = (SshState *)f->alstate; + SshState *ssh_state = (SshState *)FlowGetAppState(f); if (ssh_state) { json_t *tjs = json_object(); if (unlikely(tjs == NULL)) From 290b01f95e1864fca8926797a183260146659213 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 24 Feb 2015 17:46:06 +0100 Subject: [PATCH 0265/2553] af-packet: don't unlock twice the bpf mutex --- src/source-af-packet.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 174fcb0e9d4d..813987959a77 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1637,7 +1637,6 @@ TmEcode AFPSetBPFFilter(AFPThreadVars *ptv) return TM_ECODE_FAILED; } - SCMutexUnlock(&afpacket_bpf_set_filter_lock); return TM_ECODE_OK; } From a243a42bdf1bf4bc88deebc2408c51af7e85df5a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 15 Jan 2015 14:43:22 -0600 Subject: [PATCH 0266/2553] New function to test if a configuration node is a sequence or not. --- src/conf.c | 31 +++++++++++++++++++++++++++++++ src/conf.h | 1 + 2 files changed, 32 insertions(+) diff --git a/src/conf.c b/src/conf.c index c42ff4957542..50a9d13ec74e 100644 --- a/src/conf.c +++ b/src/conf.c @@ -840,6 +840,19 @@ ConfNodePrune(ConfNode *node) } } +/** + * \brief Check if a node is a sequence or node. + * + * \param node the node to check. + * + * \return 1 if node is a seuence, otherwise 0. + */ +int +ConfNodeIsSequence(const ConfNode *node) +{ + return node->is_seq == 0 ? 0 : 1; +} + #ifdef UNITTESTS /** @@ -1398,6 +1411,23 @@ ConfNodePruneTest(void) return ret; } +int +ConfNodeIsSequenceTest(void) +{ + ConfNode *node = ConfNodeNew(); + if (node == NULL) { + return 0; + } + if (ConfNodeIsSequence(node)) { + return 0; + } + node->is_seq = 1; + if (!ConfNodeIsSequence(node)) { + return 0; + } + return 1; +} + void ConfRegisterTests(void) { @@ -1416,6 +1446,7 @@ ConfRegisterTests(void) UtRegisterTest("ConfGetChildValueBoolWithDefaultTest", ConfGetChildValueBoolWithDefaultTest, 1); UtRegisterTest("ConfGetNodeOrCreateTest", ConfGetNodeOrCreateTest, 1); UtRegisterTest("ConfNodePruneTest", ConfNodePruneTest, 1); + UtRegisterTest("ConfNodeIsSequenceTest", ConfNodeIsSequenceTest, 1); } #endif /* UNITTESTS */ diff --git a/src/conf.h b/src/conf.h index 6bc7414e6aad..2c01a43ee183 100644 --- a/src/conf.h +++ b/src/conf.h @@ -87,5 +87,6 @@ int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, con int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val); int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val); char *ConfLoadCompleteIncludePath(const char *); +int ConfNodeIsSequence(const ConfNode *node); #endif /* ! __CONF_H__ */ From 6ed246c041b9d08e0616401d011cea4d28378763 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 15 Jan 2015 14:43:45 -0600 Subject: [PATCH 0267/2553] Don't attempt to load the rule files if the rule-files configuration node is not a sequence. Instead log a warning as this is usually a configuration error. --- src/conf.c | 16 ++++++++++++---- src/detect.c | 38 +++++++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/conf.c b/src/conf.c index 50a9d13ec74e..bc8e145880cb 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1414,18 +1414,26 @@ ConfNodePruneTest(void) int ConfNodeIsSequenceTest(void) { + int retval = 0; ConfNode *node = ConfNodeNew(); if (node == NULL) { - return 0; + goto end; } if (ConfNodeIsSequence(node)) { - return 0; + goto end; } node->is_seq = 1; if (!ConfNodeIsSequence(node)) { - return 0; + goto end; } - return 1; + + retval = 1; + +end: + if (node != NULL) { + ConfNodeFree(node); + } + return retval; } void diff --git a/src/detect.c b/src/detect.c index afb6b6d0f8e8..a3f7d3406f0c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -405,22 +405,30 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl if (!(sig_file != NULL && sig_file_exclusive == TRUE)) { rule_files = ConfGetNode("rule-files"); if (rule_files != NULL) { - TAILQ_FOREACH(file, &rule_files->head, next) { - sfile = DetectLoadCompleteSigPath(file->val); - SCLogDebug("Loading rule file: %s", sfile); - - cntf++; - r = DetectLoadSigFile(de_ctx, sfile, &goodsigs, &badsigs); - if (r < 0) { - badfiles++; - } - if (goodsigs == 0) { - SCLogWarning(SC_ERR_NO_RULES, "No rules loaded from %s", sfile); - } - SCFree(sfile); + if (!ConfNodeIsSequence(rule_files)) { + SCLogWarning(SC_ERR_INVALID_ARGUMENT, + "Invalid rule-files configuration section: " + "expected a list of filenames."); + } + else { + TAILQ_FOREACH(file, &rule_files->head, next) { + sfile = DetectLoadCompleteSigPath(file->val); + SCLogDebug("Loading rule file: %s", sfile); + + cntf++; + r = DetectLoadSigFile(de_ctx, sfile, &goodsigs, &badsigs); + if (r < 0) { + badfiles++; + } + if (goodsigs == 0) { + SCLogWarning(SC_ERR_NO_RULES, + "No rules loaded from %s", sfile); + } + SCFree(sfile); - goodtotal += goodsigs; - badtotal += badsigs; + goodtotal += goodsigs; + badtotal += badsigs; + } } } } From ab1d69fc4eb0e4ccd8902c198af0cb94fce1e696 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 Feb 2015 11:30:47 -0600 Subject: [PATCH 0268/2553] When re-opening a log file on HUP, always append. This will prevent log files that have not been rotated by some external tool from being deleted, but log files that were rotated (moved out of the way) will be re-opened. This is a better default behaviour, especially when not all log files are rotated at the same time. Thanks to iro on IRC. --- src/util-logopenfile.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 4e42ceef402f..fcef26d623e2 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -251,9 +251,10 @@ int SCConfLogReopen(LogFileCtx *log_ctx) fclose(log_ctx->fp); - /* Reopen the file. In this case do not append like may have been - * done on the initial opening of the file. */ - log_ctx->fp = SCLogOpenFileFp(log_ctx->filename, "no"); + /* Reopen the file. Append is forced in case the file was not + * moved as part of a rotation process. */ + SCLogDebug("Reopening log file %s.", log_ctx->filename); + log_ctx->fp = SCLogOpenFileFp(log_ctx->filename, "yes"); if (log_ctx->fp == NULL) { return -1; // Already logged by Open..Fp routine. } From e138a2ac1e0e0be8421b21d1c461cbfb0733731e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 12 Feb 2015 21:15:27 +0100 Subject: [PATCH 0269/2553] decode: introduce PacketCallocExtPkt function In flow timeout handling we need a function that allocate and blank a place that will be used to put constructed packet data. This new function has no other goal. --- src/decode.c | 12 ++++++++++++ src/decode.h | 1 + 2 files changed, 13 insertions(+) diff --git a/src/decode.c b/src/decode.c index 87aa831b2448..c2c31cf14abb 100644 --- a/src/decode.c +++ b/src/decode.c @@ -171,6 +171,18 @@ Packet *PacketGetFromQueueOrAlloc(void) return p; } +inline int PacketCallocExtPkt(Packet *p, int datalen) +{ + if (! p->ext_pkt) { + p->ext_pkt = SCCalloc(1, datalen); + if (unlikely(p->ext_pkt == NULL)) { + SET_PKT_LEN(p, 0); + return -1; + } + } + return 0; +} + /** * \brief Copy data to Packet payload at given offset * diff --git a/src/decode.h b/src/decode.h index 921aac3652c2..2af5494e29de 100644 --- a/src/decode.h +++ b/src/decode.h @@ -835,6 +835,7 @@ Packet *PacketGetFromAlloc(void); void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p); void PacketFree(Packet *p); void PacketFreeOrRelease(Packet *p); +int PacketCallocExtPkt(Packet *p, int datalen); int PacketCopyData(Packet *p, uint8_t *pktdata, int pktlen); int PacketSetData(Packet *p, uint8_t *pktdata, int pktlen); int PacketCopyDataOffset(Packet *p, int offset, uint8_t *data, int datalen); From b8e7d3a2593ee5673aabac267ac0f2a5ea4fbe93 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 19 Jan 2015 19:16:49 +0100 Subject: [PATCH 0270/2553] flow-timeout: fix init of pseudo packet The code was not checking if we had enough room in the direct data. In case default_packet_size was set really small, this was resulting in data being written over the data and causing a crash. The patch fixes the issue by forcing an allocation if the direct data size in the Packet is to small. --- src/flow-timeout.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/flow-timeout.c b/src/flow-timeout.c index a3de51da6444..afd1ef71cd67 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -108,6 +108,14 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, p->dp = f->sp; } + /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr. + * Force an allocation if it is not the case. + */ + if (GET_PKT_DIRECT_MAX_SIZE(p) < 40) { + if (PacketCallocExtPkt(p, 40) == -1) { + return NULL; + } + } /* set the ip header */ p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); /* version 4 and length 20 bytes for the tcp header */ @@ -145,6 +153,14 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, p->dp = f->sp; } + /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr. + * Force an allocation if it is not the case. + */ + if (GET_PKT_DIRECT_MAX_SIZE(p) < 60) { + if (PacketCallocExtPkt(p, 60) == -1) { + return NULL; + } + } /* set the ip header */ p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p); /* version 6 */ From c914f7bcdc40d60b6a27354a9c04d79cb89d52ae Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Oct 2014 10:43:56 +0200 Subject: [PATCH 0271/2553] detect: cleanup, remove unused order_id No longer used, so remove. --- src/decode.h | 1 - src/detect-engine-alert.c | 1 - 2 files changed, 2 deletions(-) diff --git a/src/decode.h b/src/decode.h index 2af5494e29de..9a0bfde924c4 100644 --- a/src/decode.h +++ b/src/decode.h @@ -255,7 +255,6 @@ typedef uint16_t Port; * found in this packet */ typedef struct PacketAlert_ { SigIntId num; /* Internal num, used for sorting */ - SigIntId order_id; /* Internal num, used for sorting */ uint8_t action; /* Internal num, used for sorting */ uint8_t flags; struct Signature_ *s; diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index db9becc5cbf7..428ff42195ab 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -46,7 +46,6 @@ void PacketAlertTagInit(void) memset(&g_tag_pa, 0x00, sizeof(g_tag_pa)); - g_tag_pa.order_id = 1000; g_tag_pa.action = ACTION_ALERT; g_tag_pa.s = &g_tag_signature; } From e9857200b3704d4c4a0feedca098a8b6898b9b21 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Oct 2014 10:04:57 +0200 Subject: [PATCH 0272/2553] detect: set action from utility function Set actions that are set directly from Signatures using the new utility function DetectSignatureApplyActions. This will apply the actions and also store info about the 'drop' that first made the rule drop. --- src/decode.h | 4 ++++ src/detect-engine-alert.c | 4 ++-- src/detect-engine-iponly.c | 2 +- src/detect-engine-state.c | 10 +++++----- src/detect.c | 17 ++++++++++++++++- src/detect.h | 1 + 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/decode.h b/src/decode.h index 9a0bfde924c4..0ea4c15f7a9f 100644 --- a/src/decode.h +++ b/src/decode.h @@ -277,6 +277,9 @@ typedef struct PacketAlert_ { typedef struct PacketAlerts_ { uint16_t cnt; PacketAlert alerts[PACKET_ALERT_MAX]; + /* single pa used when we're dropping, + * so we can log it out in the drop log. */ + PacketAlert drop; } PacketAlerts; /** number of decoder events we support per packet. Power of 2 minus 1 @@ -723,6 +726,7 @@ typedef struct DecodeThreadVars_ (p)->payload_len = 0; \ (p)->pktlen = 0; \ (p)->alerts.cnt = 0; \ + (p)->alerts.drop.action = 0; \ (p)->pcap_cnt = 0; \ (p)->tunnel_rtv_cnt = 0; \ (p)->tunnel_tpr_cnt = 0; \ diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index 428ff42195ab..8f91a4b8375d 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -286,8 +286,8 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx } } - /* set verdict on packet */ - PACKET_UPDATE_ACTION(p, p->alerts.alerts[i].action); + /* set actions on packet */ + DetectSignatureApplyActions(p, p->alerts.alerts[i].s); if (PACKET_TEST_ACTION(p, ACTION_PASS)) { /* Ok, reset the alert cnt to end in the previous of pass diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index d279295d485a..d98fa0e50c32 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -1086,7 +1086,7 @@ void IPOnlyMatchPacket(ThreadVars *tv, PacketAlertAppend(det_ctx, s, p, 0, 0); } else { /* apply actions for noalert/rule suppressed as well */ - PACKET_UPDATE_ACTION(p, s->action); + DetectSignatureApplyActions(p, s); } } } diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 2ca789afa7fd..5c84bc7abf08 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -331,7 +331,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, PacketAlertAppend(det_ctx, s, p, tx_id, PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX); } else { - PACKET_UPDATE_ACTION(p, s->action); + DetectSignatureApplyActions(p, s); } alert_cnt = 1; @@ -373,7 +373,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, PacketAlertAppend(det_ctx, s, p, 0, PACKET_ALERT_FLAG_STATE_MATCH); } else { - PACKET_UPDATE_ACTION(p, s->action); + DetectSignatureApplyActions(p, s); } alert_cnt = 1; @@ -387,7 +387,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, PacketAlertAppend(det_ctx, s, p, 0, PACKET_ALERT_FLAG_STATE_MATCH); } else { - PACKET_UPDATE_ACTION(p, s->action); + DetectSignatureApplyActions(p, s); } } @@ -442,7 +442,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, PacketAlertAppend(det_ctx, s, p, 0, PACKET_ALERT_FLAG_STATE_MATCH); } else { - PACKET_UPDATE_ACTION(p, s->action); + DetectSignatureApplyActions(p, s); } alert_cnt = 1; } @@ -736,7 +736,7 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, PacketAlertAppend(det_ctx, s, p, 0, PACKET_ALERT_FLAG_STATE_MATCH); } else { - PACKET_UPDATE_ACTION(p, s->action); + DetectSignatureApplyActions(p, s); } } diff --git a/src/detect.c b/src/detect.c index a3f7d3406f0c..3bc7d3b46f18 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1688,7 +1688,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PacketAlertAppend(det_ctx, s, p, 0, alert_flags); } else { /* apply actions even if not alerting */ - PACKET_UPDATE_ACTION(p, s->action); + DetectSignatureApplyActions(p, s); } alerts++; next: @@ -1826,6 +1826,21 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SCReturnInt((int)(alerts > 0)); } +/** \brief Apply action(s) and Set 'drop' sig info, + * if applicable */ +void DetectSignatureApplyActions(Packet *p, const Signature *s) +{ + PACKET_UPDATE_ACTION(p, s->action); + + if (s->action & ACTION_DROP) { + if (p->alerts.drop.action == 0) { + p->alerts.drop.num = s->num; + p->alerts.drop.action = s->action; + p->alerts.drop.s = (Signature *)s; + } + } +} + /* tm module api functions */ /** \brief Detection engine thread wrapper. diff --git a/src/detect.h b/src/detect.h index 4a7ce480fc3b..13481ae7d5f1 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1207,6 +1207,7 @@ void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *, int); int SigMatchSignaturesRunPostMatch(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s); +void DetectSignatureApplyActions(Packet *p, const Signature *s); #endif /* __DETECT_H__ */ From 8a97bb0d042ea25c445872e142de406aa432ca1e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Oct 2014 13:59:28 +0200 Subject: [PATCH 0273/2553] alert json: move alert info into function Move adding the alert info (sid,rev,gid,etc) into it's own function, so it can be called from other outputs as well. --- src/output-json-alert.c | 60 ++++++++++++++++++++++------------------- src/output-json-alert.h | 3 +++ 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 60dbf1fdb6d9..3d567c0c6e32 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -161,6 +161,38 @@ static void AlertJsonSsh(const Flow *f, json_t *js) return; } +void AlertJsonHeader(const PacketAlert *pa, json_t *js) +{ + char *action = "allowed"; + if (pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) { + action = "blocked"; + } else if ((pa->action & ACTION_DROP) && EngineModeIsIPS()) { + action = "blocked"; + } + + json_t *ajs = json_object(); + if (ajs == NULL) { + json_decref(js); + return; + } + + json_object_set_new(ajs, "action", json_string(action)); + json_object_set_new(ajs, "gid", json_integer(pa->s->gid)); + json_object_set_new(ajs, "signature_id", json_integer(pa->s->id)); + json_object_set_new(ajs, "rev", json_integer(pa->s->rev)); + json_object_set_new(ajs, "signature", + json_string((pa->s->msg) ? pa->s->msg : "")); + json_object_set_new(ajs, "category", + json_string((pa->s->class_msg) ? pa->s->class_msg : "")); + json_object_set_new(ajs, "severity", json_integer(pa->s->prio)); + + if (pa->flags & PACKET_ALERT_FLAG_TX) + json_object_set_new(ajs, "tx_id", json_integer(pa->tx_id)); + + /* alert */ + json_object_set_new(js, "alert", ajs); +} + static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) { MemBuffer *payload = aft->payload_buffer; @@ -181,36 +213,10 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) continue; } - char *action = "allowed"; - if (pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) { - action = "blocked"; - } else if ((pa->action & ACTION_DROP) && EngineModeIsIPS()) { - action = "blocked"; - } - - json_t *ajs = json_object(); - if (ajs == NULL) { - json_decref(js); - return TM_ECODE_OK; - } - MemBufferReset(aft->json_buffer); - json_object_set_new(ajs, "action", json_string(action)); - json_object_set_new(ajs, "gid", json_integer(pa->s->gid)); - json_object_set_new(ajs, "signature_id", json_integer(pa->s->id)); - json_object_set_new(ajs, "rev", json_integer(pa->s->rev)); - json_object_set_new(ajs, "signature", - json_string((pa->s->msg) ? pa->s->msg : "")); - json_object_set_new(ajs, "category", - json_string((pa->s->class_msg) ? pa->s->class_msg : "")); - json_object_set_new(ajs, "severity", json_integer(pa->s->prio)); - - if (pa->flags & PACKET_ALERT_FLAG_TX) - json_object_set_new(ajs, "tx_id", json_integer(pa->tx_id)); - /* alert */ - json_object_set_new(js, "alert", ajs); + AlertJsonHeader(pa, js); if (json_output_ctx->flags & LOG_JSON_HTTP) { if (p->flow != NULL) { diff --git a/src/output-json-alert.h b/src/output-json-alert.h index ec8abb7e4ebf..55313fbb555a 100644 --- a/src/output-json-alert.h +++ b/src/output-json-alert.h @@ -28,6 +28,9 @@ #define __OUTPUT_JSON_ALERT_H__ void TmModuleJsonAlertLogRegister (void); +#ifdef HAVE_LIBJANSSON +void AlertJsonHeader(const PacketAlert *pa, json_t *js); +#endif /* HAVE_LIBJANSSON */ #endif /* __OUTPUT_JSON_ALERT_H__ */ From 6b172bb0103d723574640b53c24f4b00d35a0df3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Oct 2014 14:02:20 +0200 Subject: [PATCH 0274/2553] drop json: add sids (if applicable) If a drop is caused by a SID match, add it to the drop record. --- src/output-json-drop.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 19a4f071199c..1474517b6e03 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -44,6 +44,7 @@ #include "output.h" #include "output-json.h" +#include "output-json-alert.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -133,6 +134,20 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) break; } json_object_set_new(js, "drop", djs); + + int i; + for (i = 0; i < p->alerts.cnt; i++) { + const PacketAlert *pa = &p->alerts.alerts[i]; + if (unlikely(pa->s == NULL)) { + continue; + } + if ((pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) || + ((pa->action & ACTION_DROP) && EngineModeIsIPS())) + { + AlertJsonHeader(pa, js); + } + } + OutputJSONBuffer(js, aft->file_ctx, buffer); json_object_del(js, "drop"); json_object_clear(js); From 2e754ca6fadf9caf94a6d09390a58785feca0843 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Oct 2014 15:43:42 +0200 Subject: [PATCH 0275/2553] drop json: make alerts logging optional Make logging out alerts that caused the drop optional. --- src/output-json-drop.c | 89 ++++++++++++++++++++++++++++++++---------- suricata.yaml.in | 3 +- 2 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 1474517b6e03..fc4b4eb36db5 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -61,9 +61,15 @@ #ifdef HAVE_LIBJANSSON #include +#define LOG_DROP_ALERTS 1 + +typedef struct JsonDropOutputCtx_ { + LogFileCtx *file_ctx; + uint8_t flags; +} JsonDropOutputCtx; + typedef struct JsonDropLogThread_ { - /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ - LogFileCtx* file_ctx; + JsonDropOutputCtx *drop_ctx; MemBuffer *buffer; } JsonDropLogThread; @@ -135,20 +141,22 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) } json_object_set_new(js, "drop", djs); - int i; - for (i = 0; i < p->alerts.cnt; i++) { - const PacketAlert *pa = &p->alerts.alerts[i]; - if (unlikely(pa->s == NULL)) { - continue; - } - if ((pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) || - ((pa->action & ACTION_DROP) && EngineModeIsIPS())) - { - AlertJsonHeader(pa, js); + if (aft->drop_ctx->flags & LOG_DROP_ALERTS) { + int i; + for (i = 0; i < p->alerts.cnt; i++) { + const PacketAlert *pa = &p->alerts.alerts[i]; + if (unlikely(pa->s == NULL)) { + continue; + } + if ((pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) || + ((pa->action & ACTION_DROP) && EngineModeIsIPS())) + { + AlertJsonHeader(pa, js); + } } } - OutputJSONBuffer(js, aft->file_ctx, buffer); + OutputJSONBuffer(js, aft->drop_ctx->file_ctx, buffer); json_object_del(js, "drop"); json_object_clear(js); json_decref(js); @@ -163,6 +171,7 @@ static TmEcode JsonDropLogThreadInit(ThreadVars *t, void *initdata, void **data) if (unlikely(aft == NULL)) return TM_ECODE_FAILED; memset(aft, 0, sizeof(*aft)); + if(initdata == NULL) { SCLogDebug("Error getting context for AlertFastLog. \"initdata\" argument NULL"); @@ -177,7 +186,7 @@ static TmEcode JsonDropLogThreadInit(ThreadVars *t, void *initdata, void **data) } /** Use the Ouptut Context (file pointer and mutex) */ - aft->file_ctx = ((OutputCtx *)initdata)->data; + aft->drop_ctx = ((OutputCtx *)initdata)->data; *data = (void *)aft; return TM_ECODE_OK; @@ -216,6 +225,15 @@ static void JsonDropLogDeInitCtxSub(OutputCtx *output_ctx) SCFree(output_ctx); } +static void JsonDropOutputCtxFree(JsonDropOutputCtx *drop_ctx) +{ + if (drop_ctx != NULL) { + if (drop_ctx->file_ctx != NULL) + LogFileFreeCtx(drop_ctx->file_ctx); + SCFree(drop_ctx); + } +} + #define DEFAULT_LOG_FILENAME "drop.json" static OutputCtx *JsonDropLogInitCtx(ConfNode *conf) { @@ -225,22 +243,37 @@ static OutputCtx *JsonDropLogInitCtx(ConfNode *conf) return NULL; } - LogFileCtx *logfile_ctx = LogFileNewCtx(); - if (logfile_ctx == NULL) { + JsonDropOutputCtx *drop_ctx = SCCalloc(1, sizeof(*drop_ctx)); + if (drop_ctx == NULL) + return NULL; + + drop_ctx->file_ctx = LogFileNewCtx(); + if (drop_ctx->file_ctx == NULL) { + JsonDropOutputCtxFree(drop_ctx); return NULL; } - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { - LogFileFreeCtx(logfile_ctx); + if (SCConfLogOpenGeneric(conf, drop_ctx->file_ctx, DEFAULT_LOG_FILENAME) < 0) { + JsonDropOutputCtxFree(drop_ctx); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { + JsonDropOutputCtxFree(drop_ctx); return NULL; } - output_ctx->data = logfile_ctx; + if (conf) { + const char *extended = ConfNodeLookupChildValue(conf, "alerts"); + if (extended != NULL) { + if (ConfValIsTrue(extended)) { + drop_ctx->flags = LOG_DROP_ALERTS; + } + } + } + + output_ctx->data = drop_ctx; output_ctx->DeInit = JsonDropLogDeInitCtx; return output_ctx; } @@ -255,12 +288,28 @@ static OutputCtx *JsonDropLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) AlertJsonThread *ajt = parent_ctx->data; + JsonDropOutputCtx *drop_ctx = SCCalloc(1, sizeof(*drop_ctx)); + if (drop_ctx == NULL) + return NULL; + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { + JsonDropOutputCtxFree(drop_ctx); return NULL; } - output_ctx->data = ajt->file_ctx; + if (conf) { + const char *extended = ConfNodeLookupChildValue(conf, "alerts"); + if (extended != NULL) { + if (ConfValIsTrue(extended)) { + drop_ctx->flags = LOG_DROP_ALERTS; + } + } + } + + drop_ctx->file_ctx = ajt->file_ctx; + + output_ctx->data = drop_ctx; output_ctx->DeInit = JsonDropLogDeInitCtxSub; return output_ctx; } diff --git a/suricata.yaml.in b/suricata.yaml.in index beb8f7e4a5cf..1681be5559c9 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -136,7 +136,8 @@ outputs: - files: force-magic: no # force logging magic on all logged files force-md5: no # force logging of md5 checksums - #- drop + #- drop: + # alerts: no # log alerts that caused drops - smtp - ssh # bi-directional flows From 2d7f79a62bc1ad75dd5d97b1a43710a5b36552cc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Oct 2014 19:27:34 +0200 Subject: [PATCH 0276/2553] drop json log: log out 'drop' signature If no normal sig was logged as the 'drop' reason, try the stored drop signature instead, this will also log out 'noalert' sigs. --- src/output-json-drop.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/output-json-drop.c b/src/output-json-drop.c index fc4b4eb36db5..9f457ab7df59 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -142,6 +142,7 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) json_object_set_new(js, "drop", djs); if (aft->drop_ctx->flags & LOG_DROP_ALERTS) { + int logged = 0; int i; for (i = 0; i < p->alerts.cnt; i++) { const PacketAlert *pa = &p->alerts.alerts[i]; @@ -152,6 +153,13 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) ((pa->action & ACTION_DROP) && EngineModeIsIPS())) { AlertJsonHeader(pa, js); + logged = 1; + } + } + if (logged == 0) { + if (p->alerts.drop.action != 0) { + const PacketAlert *pa = &p->alerts.drop; + AlertJsonHeader(pa, js); } } } @@ -365,6 +373,8 @@ static int JsonDropLogCondition(ThreadVars *tv, const Packet *p) if (p->flow != NULL) { int ret = FALSE; + + /* for a flow that will be dropped fully, log just once per direction */ FLOWLOCK_RDLOCK(p->flow); if (p->flow->flags & FLOW_ACTION_DROP) { if (PKT_IS_TOSERVER(p) && !(p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) @@ -373,6 +383,11 @@ static int JsonDropLogCondition(ThreadVars *tv, const Packet *p) ret = TRUE; } FLOWLOCK_UNLOCK(p->flow); + + /* if drop is caused by signature, log anyway */ + if (p->alerts.drop.action != 0) + ret = TRUE; + return ret; } else if (PACKET_TEST_ACTION(p, ACTION_DROP)) { return TRUE; From 5b8c94db3026bcfd324eaa6f61a1655358182667 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 21 Feb 2015 14:19:48 +0100 Subject: [PATCH 0277/2553] Remove spinning PacketPoolWait PacketPoolWait in autofp can wait for considerable time. Until now it was essentially spinning, keeping the CPU 100% busy. This patch introduces a condition to wait in such cases. Atomically flag pool that consumer is waiting, so that we can sync the pending pool right away instead of waiting for the MAX_PENDING_RETURN_PACKETS limit. --- src/tmqh-packetpool.c | 17 ++++++++++++++++- src/tmqh-packetpool.h | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index 6ef25c7d326f..5ea5c426d355 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -146,6 +146,13 @@ void PacketPoolWait(void) { PktPool *my_pool = GetThreadPacketPool(); + if (PacketPoolIsEmpty(my_pool)) { + SCMutexLock(&my_pool->return_stack.mutex); + SC_ATOMIC_ADD(my_pool->return_stack.sync_now, 1); + SCCondWait(&my_pool->return_stack.cond, &my_pool->return_stack.mutex); + SCMutexUnlock(&my_pool->return_stack.mutex); + } + while(PacketPoolIsEmpty(my_pool)) cc_barrier(); } @@ -246,12 +253,14 @@ void PacketPoolReturnPacket(Packet *p) p->next = my_pool->pending_head; my_pool->pending_head = p; my_pool->pending_count++; - if (my_pool->pending_count > MAX_PENDING_RETURN_PACKETS) { + if (SC_ATOMIC_GET(pool->return_stack.sync_now) || my_pool->pending_count > MAX_PENDING_RETURN_PACKETS) { /* Return the entire list of pending packets. */ SCMutexLock(&pool->return_stack.mutex); my_pool->pending_tail->next = pool->return_stack.head; pool->return_stack.head = my_pool->pending_head; + SC_ATOMIC_RESET(pool->return_stack.sync_now); SCMutexUnlock(&pool->return_stack.mutex); + SCCondSignal(&pool->return_stack.cond); /* Clear the list of pending packets to return. */ my_pool->pending_pool = NULL; my_pool->pending_head = NULL; @@ -263,7 +272,9 @@ void PacketPoolReturnPacket(Packet *p) SCMutexLock(&pool->return_stack.mutex); p->next = pool->return_stack.head; pool->return_stack.head = p; + SC_ATOMIC_RESET(pool->return_stack.sync_now); SCMutexUnlock(&pool->return_stack.mutex); + SCCondSignal(&pool->return_stack.cond); } } } @@ -279,6 +290,8 @@ void PacketPoolInit(void) PktPool *my_pool = GetThreadPacketPool(); SCMutexInit(&my_pool->return_stack.mutex, NULL); + SCCondInit(&my_pool->return_stack.cond, NULL); + SC_ATOMIC_INIT(my_pool->return_stack.sync_now); /* pre allocate packets */ SCLogDebug("preallocating packets... packet size %" PRIuMAX "", @@ -317,6 +330,8 @@ void PacketPoolDestroy(void) while ((p = PacketPoolGetPacket()) != NULL) { PacketFree(p); } + + SC_ATOMIC_DESTROY(my_pool->return_stack.sync_now); } Packet *TmqhInputPacketpool(ThreadVars *tv) diff --git a/src/tmqh-packetpool.h b/src/tmqh-packetpool.h index 729883cd31fe..f7c8b9fc1e57 100644 --- a/src/tmqh-packetpool.h +++ b/src/tmqh-packetpool.h @@ -26,11 +26,14 @@ #include "decode.h" #include "threads.h" +#include "util-atomic.h" /* Return stack, onto which other threads free packets. */ typedef struct PktPoolLockedStack_{ /* linked list of free packets. */ SCMutex mutex; + SCCondT cond; + SC_ATOMIC_DECLARE(int, sync_now); Packet *head; } __attribute__((aligned(CLS))) PktPoolLockedStack; From c0f265fd82cdf4fccad2eb8c53f37ce325d5d438 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 Feb 2015 00:04:11 +0100 Subject: [PATCH 0278/2553] http: fix stat_msg and stat_code state tracking --- src/detect-engine-hscd.c | 2 +- src/detect-engine-hsmd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index b54c79511d89..aa9f6f7dcce9 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -100,7 +100,7 @@ int DetectEngineInspectHttpStatCode(ThreadVars *tv, { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->response_status == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_RESPONSE_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 8881f3cf06dc..2c5176022a13 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -100,7 +100,7 @@ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->response_message == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_RESPONSE_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; From 6723d03c7e1e2bdafe06249c6c8bd54669d3e0a7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 9 Mar 2015 14:56:24 +0100 Subject: [PATCH 0279/2553] http: add inspection engine for http request line No MPM though. --- src/Makefile.am | 1 + src/detect-engine-content-inspection.h | 1 + src/detect-engine-hrl.c | 4221 ++++++++++++++++++++++++ src/detect-engine-hrl.h | 34 + src/detect-engine-state.h | 1 + src/detect-engine.c | 10 + src/detect-lua.c | 2 +- src/detect-parse.c | 2 + src/detect.h | 2 + 9 files changed, 4273 insertions(+), 1 deletion(-) create mode 100644 src/detect-engine-hrl.c create mode 100644 src/detect-engine-hrl.h diff --git a/src/Makefile.am b/src/Makefile.am index 582247e7623c..d30cce2e5cc5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -103,6 +103,7 @@ detect-engine-hmd.c detect-engine-hmd.h \ detect-engine-hrhd.c detect-engine-hrhd.h \ detect-engine-hrhhd.c detect-engine-hrhhd.h \ detect-engine-hrud.c detect-engine-hrud.h \ +detect-engine-hrl.c detect-engine-hrl.h \ detect-engine-hsbd.c detect-engine-hsbd.h \ detect-engine-hscd.c detect-engine-hscd.h \ detect-engine-hsmd.c detect-engine-hsmd.h \ diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 090e39495dca..ab12c25118d7 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -35,6 +35,7 @@ enum { /* called with flow locked */ DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_URI, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRL, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRUD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHD, diff --git a/src/detect-engine-hrl.c b/src/detect-engine-hrl.c new file mode 100644 index 000000000000..af1b93f316ae --- /dev/null +++ b/src/detect-engine-hrl.c @@ -0,0 +1,4221 @@ +/* Copyright (C) 2015 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 + * + * Based on detect-engine-uri.c + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-engine-content-inspection.h" + +#include "flow-util.h" +#include "util-debug.h" +#include "util-print.h" +#include "flow.h" + +#include "stream-tcp.h" + +#include "app-layer-parser.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer.h" +#include "app-layer-htp.h" +#include "app-layer-protos.h" + +/** + * \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags app layer flags + * \param state App layer state + * + * \retval 0 no match. + * \retval 1 match. + * \retval 2 Sig can't match. + */ +int DetectEngineInspectHttpRequestLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *txv, uint64_t tx_id) +{ + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_line == NULL) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) > HTP_REQUEST_LINE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + else + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } + + det_ctx->discontinue_matching = 0; + det_ctx->buffer_offset = 0; + det_ctx->inspection_recursion_counter = 0; + +#if 0 + PrintRawDataFp(stdout, (uint8_t *)bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); +#endif + + /* Inspect all the uricontents fetched on each + * transaction at the app layer */ + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRLMATCH], + f, + bstr_ptr(tx->request_line), + bstr_len(tx->request_line), + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRL, NULL); + if (r == 1) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } else { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } +} + +/***********************************Unittests**********************************/ + +#ifdef UNITTESTS +/** \test Test a simple uricontent option */ +static int UriTestSig01(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test uricontent option\"; " + "uricontent:\"one\"; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test the pcre /U option */ +static int UriTestSig02(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /on HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /one HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test pcre /U option\"; " + "pcre:/one/U; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted with payload2, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert, but it should: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test the pcre /U option */ +static int UriTestSig03(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test pcre /U option\"; " + "pcre:/blah/U; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test the urilen option */ +static int UriTestSig04(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test urilen option\"; " + "urilen:>20; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test the urilen option */ +static int UriTestSig05(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test urilen option\"; " + "urilen:>4; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert with payload2, but it should: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test the pcre /U option */ +static int UriTestSig06(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test pcre /U option\"; " + "pcre:/(oneself)+/U; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert on payload2, but it should: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test the pcre /U option in combination with urilen */ +static int UriTestSig07(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test pcre /U option with urilen \"; " + "pcre:/(one){2,}(self)?/U; urilen:3<>20; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert, but it should: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert with payload2, but it should: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test the pcre /U option in combination with urilen */ +static int UriTestSig08(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test pcre /U option with urilen\"; " + "pcre:/(blabla){2,}(self)?/U; urilen:3<>20; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test the pcre /U option in combination with urilen */ +static int UriTestSig09(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test pcre /U option with urilen \"; " + "pcre:/(one){2,}(self)?/U; urilen:<2; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test the uricontent option in combination with urilen */ +static int UriTestSig10(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test uricontent with urilen option\"; " + "uricontent:\"one\"; urilen:<2; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test content, uricontent, urilen, pcre /U options */ +static int UriTestSig11(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test content, uricontent, pcre /U and urilen options\"; " + "content:\"one\"; uricontent:\"one\"; pcre:/(one){2,}(self)?/U;" + "urilen:<2; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test uricontent, urilen, pcre /U options */ +static int UriTestSig12(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test pcre /U, uricontent and urilen option\"; " + "uricontent:\"one\"; " + "pcre:/(one)+self/U; urilen:>2; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert with payload2, but it should: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test uricontent, urilen */ +static int UriTestSig13(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test urilen option\"; " + "urilen:>2; uricontent:\"one\"; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert with pkt, but it should: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert with payload2, but it should: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test uricontent, pcre /U */ +static int UriTestSig14(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test uricontent option\"; " + "uricontent:\"one\"; pcre:/one(self)?/U;sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert with pkt, but it should: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert with payload2, but it should: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test pcre /U with anchored regex (bug 155) */ +static int UriTestSig15(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test uricontent option\"; " + "uricontent:\"one\"; pcre:/^\\/one(self)?$/U;sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert with pkt, but it should: "); + goto end; + } + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didnt alert with payload2, but it should: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test Test pcre /U with anchored regex (bug 155) */ +static int UriTestSig16(void) +{ + int result = 0; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /search?q=123&aq=7123abcee HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0/\r\n" + "Host: 1.2.3.4\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /search?q=123&aq=7123abcee HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any (msg:\"ET TROJAN Downadup/Conficker A or B Worm reporting\"; flow:to_server,established; uricontent:\"/search?q=\"; pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; sid:2009024; rev:9;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 2009024)) { + printf("sig 1 didnt alert with pkt, but it should: "); + goto end; + } + p->alerts.cnt = 0; + + DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); + p->payload = http_buf2; + p->payload_len = http_buf2_len; + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 2009024)) { + printf("sig 1 alerted, but it should not (host should not match): "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test multiple relative contents + */ +static int UriTestSig17(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /now_this_is_is_big_big_string_now HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"this\"; uricontent:\"is\"; within:6; " + "uricontent:\"big\"; within:8; " + "uricontent:\"string\"; within:8; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test multiple relative contents + */ +static int UriTestSig18(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /now_this_is_is_is_big_big_big_string_now HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"this\"; uricontent:\"is\"; within:9; " + "uricontent:\"big\"; within:12; " + "uricontent:\"string\"; within:8; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test multiple relative contents + */ +static int UriTestSig19(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /this_this_now_is_is_____big_string_now HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"now\"; uricontent:\"this\"; " + "uricontent:\"is\"; within:12; " + "uricontent:\"big\"; within:8; " + "uricontent:\"string\"; within:8; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test multiple relative contents with offset + */ +static int UriTestSig20(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /_________thus_thus_is_a_big HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"thus\"; offset:8; " + "uricontent:\"is\"; within:6; " + "uricontent:\"big\"; within:8; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test multiple relative contents with a negated content. + */ +static int UriTestSig21(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"fix\"; uricontent:\"this\"; within:6; " + "uricontent:!\"and\"; distance:0; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test relative pcre. + */ +static int UriTestSig22(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /this_is_a_super_duper_" + "nova_in_super_nova_now HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "pcre:/super/U; uricontent:\"nova\"; within:7; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but it should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test multiple relative contents with a negated content. + */ +static int UriTestSig23(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "uricontent:!\"fix_this_now\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test multiple relative contents with a negated content. + */ +static int UriTestSig24(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"we_need_to\"; uricontent:!\"fix_this_now\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test normalized uricontents. + */ +static int UriTestSig25(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "pcre:/normalized/U; uricontent:\"normalized uri\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but it should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test multiple relative contents with a negated content. + */ +static int UriTestSig26(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"fix_this\"; isdataat:4,relative; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but it should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test multiple relative contents with a negated content. + */ +static int UriTestSig27(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"fix_this\"; isdataat:!10,relative; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but it should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +static int UriTestSig28(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"dummy\"; " + "uricontent:\"this\"; " + "byte_extract:1,2,one,string,dec,relative; " + "uricontent:\"ring\"; distance:one; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int UriTestSig29(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"dummy\"; " + "uricontent:\"this\"; " + "byte_extract:1,2,one,string,dec,relative; " + "uricontent:\"ring\"; distance:one; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int UriTestSig30(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"dummy\"; " + "uricontent:\"this\"; " + "byte_extract:1,2,one,string,dec,relative; " + "uricontent:\"_b5ig\"; offset:one; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int UriTestSig31(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"dummy\"; " + "uricontent:\"this\"; " + "byte_extract:1,2,one,string,dec,relative; " + "uricontent:\"his\"; depth:one; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int UriTestSig32(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"dummy\"; " + "uricontent:\"this\"; " + "byte_extract:1,2,one,string,dec,relative; " + "uricontent:\"g_st\"; within:one; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int UriTestSig33(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "urilen:15; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but it should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int UriTestSig34(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "urilen:15, norm; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but it should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int UriTestSig35(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "urilen:16; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int UriTestSig36(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "urilen:16, norm; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int UriTestSig37(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "urilen:17, raw; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sig 1 didn't alert, but it should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int UriTestSig38(void) +{ + int result = 0; + uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + uint32_t http_buf_len = strlen((char *)http_buf); + Flow f; + TcpSession ssn; + HtpState *http_state = NULL; + Packet *p = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "urilen:18, raw; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted, but it shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +#endif /* UNITTESTS */ + +void HttpRequestLineRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("UriTestSig01", UriTestSig01, 1); + UtRegisterTest("UriTestSig02", UriTestSig02, 1); + UtRegisterTest("UriTestSig03", UriTestSig03, 1); + UtRegisterTest("UriTestSig04", UriTestSig04, 1); + UtRegisterTest("UriTestSig05", UriTestSig05, 1); + UtRegisterTest("UriTestSig06", UriTestSig06, 1); + UtRegisterTest("UriTestSig07", UriTestSig07, 1); + UtRegisterTest("UriTestSig08", UriTestSig08, 1); + UtRegisterTest("UriTestSig09", UriTestSig09, 1); + UtRegisterTest("UriTestSig10", UriTestSig10, 1); + UtRegisterTest("UriTestSig11", UriTestSig11, 1); + UtRegisterTest("UriTestSig12", UriTestSig12, 1); + UtRegisterTest("UriTestSig13", UriTestSig13, 1); + UtRegisterTest("UriTestSig14", UriTestSig14, 1); + UtRegisterTest("UriTestSig15", UriTestSig15, 1); + UtRegisterTest("UriTestSig16", UriTestSig16, 1); + UtRegisterTest("UriTestSig17", UriTestSig17, 1); + UtRegisterTest("UriTestSig18", UriTestSig18, 1); + UtRegisterTest("UriTestSig19", UriTestSig19, 1); + UtRegisterTest("UriTestSig20", UriTestSig20, 1); + UtRegisterTest("UriTestSig21", UriTestSig21, 1); + UtRegisterTest("UriTestSig22", UriTestSig22, 1); + UtRegisterTest("UriTestSig23", UriTestSig23, 1); + UtRegisterTest("UriTestSig24", UriTestSig24, 1); + UtRegisterTest("UriTestSig25", UriTestSig25, 1); + UtRegisterTest("UriTestSig26", UriTestSig26, 1); + UtRegisterTest("UriTestSig27", UriTestSig27, 1); + + UtRegisterTest("UriTestSig28", UriTestSig28, 1); + UtRegisterTest("UriTestSig29", UriTestSig29, 1); + UtRegisterTest("UriTestSig30", UriTestSig30, 1); + UtRegisterTest("UriTestSig31", UriTestSig31, 1); + UtRegisterTest("UriTestSig32", UriTestSig32, 1); + UtRegisterTest("UriTestSig33", UriTestSig33, 1); + UtRegisterTest("UriTestSig34", UriTestSig34, 1); + UtRegisterTest("UriTestSig35", UriTestSig35, 1); + UtRegisterTest("UriTestSig36", UriTestSig36, 1); + UtRegisterTest("UriTestSig37", UriTestSig37, 1); + UtRegisterTest("UriTestSig38", UriTestSig38, 1); +#endif /* UNITTESTS */ + + return; +} diff --git a/src/detect-engine-hrl.h b/src/detect-engine-hrl.h new file mode 100644 index 000000000000..cb5360d9a08b --- /dev/null +++ b/src/detect-engine-hrl.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2015 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 + */ + +#ifndef __DETECT_ENGINE_HRL_H__ +#define __DETECT_ENGINE_HRL_H__ + +int DetectEngineInspectHttpRequestLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *tx, uint64_t tx_id); +void HttpRequestLineRegisterTests(void); + +#endif /* __DETECT_ENGINE_HRL_H__ */ diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 9f497551185f..4c8bf9b19eca 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -77,6 +77,7 @@ #define DE_STATE_FLAG_DNSQUERY_INSPECT (1 << 17) #define DE_STATE_FLAG_APP_EVENT_INSPECT (1 << 18) #define DE_STATE_FLAG_MODBUS_INSPECT (1 << 19) +#define DE_STATE_FLAG_HRL_INSPECT (1 << 20) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine.c b/src/detect-engine.c index 73d5e3e9918a..248927822a17 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -52,6 +52,7 @@ #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" +#include "detect-engine-hrl.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" #include "detect-engine-hua.h" @@ -160,6 +161,13 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_URI_INSPECT, 0, DetectEngineInspectPacketUris }, + { IPPROTO_TCP, + ALPROTO_HTTP, + DETECT_SM_LIST_HRLMATCH, + DE_STATE_FLAG_HRL_INSPECT, + DE_STATE_FLAG_HRL_INSPECT, + 0, + DetectEngineInspectHttpRequestLine }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HCBDMATCH, @@ -1637,6 +1645,8 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http cookie"; case DETECT_SM_LIST_HUADMATCH: return "http user-agent"; + case DETECT_SM_LIST_HRLMATCH: + return "http request line"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-lua.c b/src/detect-lua.c index def801859324..8d2b35abe4fb 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1042,7 +1042,7 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) else if (luajit->flags & DATATYPE_HTTP_RESPONSE_COOKIE) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); else - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRLMATCH); } else if (luajit->alproto == ALPROTO_DNS) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSQUERY_MATCH); } else { diff --git a/src/detect-parse.c b/src/detect-parse.c index a6e54937bfa9..9bc0d035c539 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1445,6 +1445,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_AMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_HRLMATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HCBDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HSBDMATCH]) diff --git a/src/detect.h b/src/detect.h index 13481ae7d5f1..03658e42aa47 100644 --- a/src/detect.h +++ b/src/detect.h @@ -109,6 +109,8 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_HCDMATCH, /* list for http_user_agent keyword and the ones relative to it */ DETECT_SM_LIST_HUADMATCH, + /* list for http_request_line keyword and the ones relative to it */ + DETECT_SM_LIST_HRLMATCH, /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, From 9f1b4176608bf71d75b83910a02b82948b35eee4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 Feb 2015 17:10:09 +0100 Subject: [PATCH 0280/2553] file: don't 'close' file if we need to track it --- src/util-file.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util-file.c b/src/util-file.c index ec5e4df4f1bc..56be73eee65f 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -821,8 +821,10 @@ void FileDisableStoringForFile(File *ff) ff->flags |= FILE_NOSTORE; if (ff->state == FILE_STATE_OPENED && ff->size >= (uint64_t)FileMagicSize()) { - (void)FileCloseFilePtr(ff, NULL, 0, - (FILE_TRUNCATED|FILE_NOSTORE)); + if (g_file_force_md5 == 0 && g_file_force_tracking == 0) { + (void)FileCloseFilePtr(ff, NULL, 0, + (FILE_TRUNCATED|FILE_NOSTORE)); + } } } From 97cab030d77cac2ab016953008929adcf9e60235 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 9 Mar 2015 15:49:28 +0100 Subject: [PATCH 0281/2553] modbus: shrink data structure --- src/app-layer-modbus.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-modbus.h b/src/app-layer-modbus.h index fba43db74a0d..99e07e885f84 100644 --- a/src/app-layer-modbus.h +++ b/src/app-layer-modbus.h @@ -88,6 +88,8 @@ typedef struct ModbusTransaction_ { uint8_t function; uint8_t category; uint8_t type; + uint8_t replied; /**< bool indicating request is replied to. */ + union { uint16_t subFunction; uint8_t mei; @@ -107,8 +109,6 @@ typedef struct ModbusTransaction_ { AppLayerDecoderEvents *decoder_events; /**< per tx events */ - uint8_t replied; /**< bool indicating request is replied to. */ - TAILQ_ENTRY(ModbusTransaction_) next; } ModbusTransaction; From 54cb2b68774c5e037777d22703ecf47427f2273a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Feb 2015 15:02:21 +0100 Subject: [PATCH 0282/2553] detect-state: cleanup retvals Use DETECT_ENGINE_INSPECT_SIG_* instead of 0, 1, 2 and 3. --- src/detect-engine-state.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 5c84bc7abf08..61445a6981bb 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -305,15 +305,15 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, match = engine->Callback(tv, de_ctx, det_ctx, s, f, flags, alstate, tx, tx_id); - if (match == 1) { + if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { inspect_flags |= engine->inspect_flags; engine = engine->next; total_matches++; continue; - } else if (match == 2) { + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; inspect_flags |= engine->inspect_flags; - } else if (match == 3) { + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; inspect_flags |= engine->inspect_flags; file_no_match++; @@ -640,15 +640,15 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); match = engine->Callback(tv, de_ctx, det_ctx, s, f, flags, alstate, inspect_tx, inspect_tx_id); - if (match == 1) { + if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { inspect_flags |= engine->inspect_flags; engine = engine->next; total_matches++; continue; - } else if (match == 2) { + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; inspect_flags |= engine->inspect_flags; - } else if (match == 3) { + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; inspect_flags |= engine->inspect_flags; file_no_match++; From b710f2dd59fbfc676ad3b3ee9f444d23bb3a8b13 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Feb 2015 15:23:41 +0100 Subject: [PATCH 0283/2553] detect-state: cleanup ContinueDetection Only lock f->de_state->m when we start to access it. So after declaration and initialization of local vars. --- src/detect-engine-state.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 61445a6981bb..1dd213c3af97 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -486,8 +486,6 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Packet *p, Flow *f, uint8_t flags, AppProto alproto, uint16_t alversion) { - SCMutexLock(&f->de_state_m); - DetectEngineAppInspectionEngine *engine = NULL; SigMatch *sm = NULL; uint16_t file_no_match = 0; @@ -502,8 +500,6 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, int match = 0; uint8_t alert = 0; - DetectEngineStateDirection *dir_state = &f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1]; - DeStateStore *store = dir_state->head; void *inspect_tx = NULL; uint64_t inspect_tx_id = 0; uint64_t total_txs = 0; @@ -514,6 +510,10 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, * assume that we have an alert if engine == NULL */ uint8_t total_matches = 0; + SCMutexLock(&f->de_state_m); + DetectEngineStateDirection *dir_state = &f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1]; + DeStateStore *store = dir_state->head; + DeStateResetFileInspection(f, alproto, alstate, flags); if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { From 072ae12771f516e23ba23aa21b78f32757858566 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Feb 2015 15:58:43 +0100 Subject: [PATCH 0284/2553] detect-state: add helper to indicate last tx Add little helper to indicate current tx is that last we have. --- src/detect-engine-state.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 1dd213c3af97..de64033c08e4 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -244,6 +244,13 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion return r; } +static inline int TxIsLast(uint64_t tx_id, uint64_t total_txs) +{ + if (total_txs - tx_id <= 1) + return 1; + return 0; +} + int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, Flow *f, uint8_t flags, @@ -337,7 +344,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, alert_cnt = 1; } - if (tx_id == (total_txs - 1)) { + if (TxIsLast(tx_id, total_txs)) { void *tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id); if (tx == NULL) continue; @@ -567,8 +574,9 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { if (alproto_supports_txs) { - if ((total_txs - inspect_tx_id) <= 1) + if (TxIsLast(inspect_tx_id, total_txs)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + } } else { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; } @@ -591,8 +599,9 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; } else { if (alproto_supports_txs) { - if ((total_txs - inspect_tx_id) <= 1) + if (TxIsLast(inspect_tx_id, total_txs)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + } } else { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; } @@ -722,8 +731,9 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, item->flags |= inspect_flags; item->nm = sm; - if ((total_txs - inspect_tx_id) <= 1) + if (TxIsLast(inspect_tx_id, total_txs)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + } if (alert) { SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); From e390e24a7cabe9ae8bf7fd39868d8d23d5f9eed6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Feb 2015 16:11:31 +0100 Subject: [PATCH 0285/2553] detect-state: add helper to test state Add little helper function StateIsValid() to test if the state can be inspected safely. Cleans up stateful detection loops. --- src/detect-engine-state.c | 40 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index de64033c08e4..5aed7d876034 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -244,6 +244,21 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion return r; } +static inline int StateIsValid(uint16_t alproto, void *alstate) +{ + if (alstate != NULL) { + if (alproto == ALPROTO_HTTP) { + HtpState *htp_state = (HtpState *)alstate; + if (htp_state->conn != NULL) { + return 1; + } + } else { + return 1; + } + } + return 0; +} + static inline int TxIsLast(uint64_t tx_id, uint64_t total_txs) { if (total_txs - tx_id <= 1) @@ -262,7 +277,6 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, uint32_t inspect_flags = 0; void *alstate = NULL; - HtpState *htp_state = NULL; SMBState *smb_state = NULL; void *tx = NULL; @@ -281,17 +295,11 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { FLOWLOCK_WRLOCK(f); alstate = FlowGetAppState(f); - if (alstate == NULL) { + if (!StateIsValid(alproto, alstate)) { FLOWLOCK_UNLOCK(f); goto end; } - if (alproto == ALPROTO_HTTP) { - htp_state = (HtpState *)alstate; - if (htp_state->conn == NULL) { - FLOWLOCK_UNLOCK(f); - goto end; - } - } + tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); SCLogDebug("tx_id %"PRIu64, tx_id); total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); @@ -499,7 +507,6 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, uint32_t inspect_flags = 0; void *alstate = NULL; - HtpState *htp_state = NULL; SMBState *smb_state = NULL; SigIntId store_cnt = 0; @@ -526,7 +533,7 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { FLOWLOCK_RDLOCK(f); alstate = FlowGetAppState(f); - if (alstate == NULL) { + if (!StateIsValid(alproto, alstate)) { FLOWLOCK_UNLOCK(f); SCMutexUnlock(&f->de_state_m); return; @@ -618,21 +625,12 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (alproto_supports_txs) { FLOWLOCK_WRLOCK(f); alstate = FlowGetAppState(f); - if (alstate == NULL) { + if (!StateIsValid(alproto, alstate)) { FLOWLOCK_UNLOCK(f); RULE_PROFILING_END(det_ctx, s, match, p); goto end; } - if (alproto == ALPROTO_HTTP) { - htp_state = (HtpState *)alstate; - if (htp_state->conn == NULL) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, match, p); - goto end; - } - } - det_ctx->tx_id = inspect_tx_id; det_ctx->tx_id_set = 1; engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; From 206f9d40108d72c687e5444e5c987d525843934c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Feb 2015 17:49:30 +0100 Subject: [PATCH 0286/2553] detect-state: remove redundant code --- src/detect-engine-state.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 5aed7d876034..144ea623e677 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -353,9 +353,6 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } if (TxIsLast(tx_id, total_txs)) { - void *tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id); - if (tx == NULL) - continue; if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) < AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)) { store_de_state = 1; From bf818b8fb244fad460dfd776c83438e29fb01d04 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Feb 2015 17:32:36 +0100 Subject: [PATCH 0287/2553] detect-state: remove DeStateResetFileInspection It was effectively unused. --- src/detect-engine-state.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 144ea623e677..c6c5b08326d1 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -156,33 +156,6 @@ static int DeStateStoreFilestoreSigsCantMatch(SigGroupHead *sgh, DetectEngineSta return 0; } -static void DeStateResetFileInspection(Flow *f, AppProto alproto, void *alstate, uint8_t direction) -{ - if (f == NULL || alproto != ALPROTO_HTTP || alstate == NULL || f->de_state == NULL) - return; - - FLOWLOCK_WRLOCK(f); - HtpState *htp_state = (HtpState *)alstate; - - if (direction & STREAM_TOSERVER) { - if (htp_state->flags & HTP_FLAG_NEW_FILE_TX_TS) { - SCLogDebug("new file in the TS direction"); - htp_state->flags &= ~HTP_FLAG_NEW_FILE_TX_TS; - f->de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW; - } - } else { - if (htp_state->flags & HTP_FLAG_NEW_FILE_TX_TC) { - SCLogDebug("new file in the TC direction"); - htp_state->flags &= ~HTP_FLAG_NEW_FILE_TX_TC; - f->de_state->dir_state[1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW; - } - } - - FLOWLOCK_UNLOCK(f); -} - - - DetectEngineState *DetectEngineStateAlloc(void) { DetectEngineState *d = SCMalloc(sizeof(DetectEngineState)); @@ -525,8 +498,6 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineStateDirection *dir_state = &f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1]; DeStateStore *store = dir_state->head; - DeStateResetFileInspection(f, alproto, alstate, flags); - if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { FLOWLOCK_RDLOCK(f); alstate = FlowGetAppState(f); From eec22ce19b597d56efea8470a2c665374f14794d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Feb 2015 17:23:49 +0100 Subject: [PATCH 0288/2553] detect-state: rip per sig detect out of ContinueDetect --- src/detect-engine-state.c | 424 ++++++++++++++++++++------------------ 1 file changed, 218 insertions(+), 206 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index c6c5b08326d1..3ac87b43080e 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -466,33 +466,226 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, return alert_cnt ? 1:0; } +static int DoInspectItem(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const int alproto_supports_txs, + DeStateStoreItem *item, const uint8_t dir_state_flags, + Packet *p, Flow *f, AppProto alproto, uint8_t flags, + const uint64_t inspect_tx_id, const uint64_t total_txs, + + uint16_t *file_no_match) +{ + Signature *s = de_ctx->sig_array[item->sid]; + + /* check if a sig in state 'full inspect' needs to be reconsidered + * as the result of a new file in the existing tx */ + if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { + if (item->flags & (DE_STATE_FLAG_FILE_TC_INSPECT|DE_STATE_FLAG_FILE_TS_INSPECT)) { + if ((flags & STREAM_TOCLIENT) && + (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW)) + { + item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; + item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; + } + + if ((flags & STREAM_TOSERVER) && + (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW)) + { + item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; + item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; + } + } + + if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { + if (alproto_supports_txs) { + if (TxIsLast(inspect_tx_id, total_txs)) { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + } + } else { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + } + return 0; + } + } + + /* check if a sig in state 'cant match' needs to be reconsidered + * as the result of a new file in the existing tx */ + if (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) { + if ((flags & STREAM_TOSERVER) && + (item->flags & DE_STATE_FLAG_FILE_TS_INSPECT) && + (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW)) + { + item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; + item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; + } else if ((flags & STREAM_TOCLIENT) && + (item->flags & DE_STATE_FLAG_FILE_TC_INSPECT) && + (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW)) + { + item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; + item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; + } else { + if (alproto_supports_txs) { + if (TxIsLast(inspect_tx_id, total_txs)) { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + } + } else { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + } + return 0; + } + } + + uint8_t alert = 0; + uint32_t inspect_flags = 0; + int total_matches = 0; + + RULE_PROFILING_START(p); + + if (alproto_supports_txs) { + FLOWLOCK_WRLOCK(f); + void *alstate = FlowGetAppState(f); + if (!StateIsValid(alproto, alstate)) { + FLOWLOCK_UNLOCK(f); + RULE_PROFILING_END(det_ctx, s, 0, p); + return -1; + } + + det_ctx->tx_id = inspect_tx_id; + det_ctx->tx_id_set = 1; + DetectEngineAppInspectionEngine *engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; + void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); + if (inspect_tx == NULL) { + FLOWLOCK_UNLOCK(f); + RULE_PROFILING_END(det_ctx, s, 0, p); + return -1; + } + + while (engine != NULL) { + if (!(item->flags & engine->inspect_flags) && + s->sm_lists[engine->sm_list] != NULL) + { + KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); + int match = engine->Callback(tv, de_ctx, det_ctx, s, f, + flags, alstate, inspect_tx, inspect_tx_id); + if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { + inspect_flags |= engine->inspect_flags; + engine = engine->next; + total_matches++; + continue; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { + inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; + inspect_flags |= engine->inspect_flags; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { + inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; + inspect_flags |= engine->inspect_flags; + (*file_no_match)++; + } + break; + } + engine = engine->next; + } + if (total_matches > 0 && (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { + if (engine == NULL) + alert = 1; + inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; + } + + FLOWLOCK_UNLOCK(f); + } + + /* count AMATCH matches */ + total_matches = 0; + SigMatch *sm = NULL; + + KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_AMATCH); + if (item->nm != NULL) { + /* RDLOCK would be nicer, but at least tlsstore needs + * write lock currently. */ + FLOWLOCK_WRLOCK(f); + void *alstate = FlowGetAppState(f); + if (alstate == NULL) { + FLOWLOCK_UNLOCK(f); + RULE_PROFILING_END(det_ctx, s, 0 /* no match */, p); + return -1; + } + + for (sm = item->nm; sm != NULL; sm = sm->next) { + if (sigmatch_table[sm->type].AppLayerMatch != NULL) + { + int match = 0; + if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { + SMBState *smb_state = (SMBState *)alstate; + if (smb_state->dcerpc_present) { + KEYWORD_PROFILING_START; + match = sigmatch_table[sm->type]. + AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, sm); + KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + } + } else { + KEYWORD_PROFILING_START; + match = sigmatch_table[sm->type]. + AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); + KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + } + + if (match == 0) + break; + else if (match == 2) + inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; + else if (match == 1) + total_matches++; + } + } + FLOWLOCK_UNLOCK(f); + } + + if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { + if (total_matches > 0 && (sm == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { + if (sm == NULL) + alert = 1; + inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; + } + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + } + RULE_PROFILING_END(det_ctx, s, (alert == 1), p); + + item->flags |= inspect_flags; + item->nm = sm; + if (TxIsLast(inspect_tx_id, total_txs)) { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + } + + if (alert) { + SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); + + if (!(s->flags & SIG_FLAG_NOALERT)) { + if (alproto_supports_txs) + PacketAlertAppend(det_ctx, s, p, inspect_tx_id, + PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX); + else + PacketAlertAppend(det_ctx, s, p, 0, + PACKET_ALERT_FLAG_STATE_MATCH); + } else { + DetectSignatureApplyActions(p, s); + } + } + + DetectFlowvarProcessList(det_ctx, f); + return 1; +} + void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f, uint8_t flags, AppProto alproto, uint16_t alversion) { - DetectEngineAppInspectionEngine *engine = NULL; - SigMatch *sm = NULL; uint16_t file_no_match = 0; - uint32_t inspect_flags = 0; - - void *alstate = NULL; - SMBState *smb_state = NULL; - SigIntId store_cnt = 0; SigIntId state_cnt = 0; - int match = 0; - uint8_t alert = 0; - - void *inspect_tx = NULL; uint64_t inspect_tx_id = 0; uint64_t total_txs = 0; uint8_t alproto_supports_txs = 0; uint8_t reset_de_state = 0; - /* this was introduced later to allow protocols that had both app - * keywords with transaction keywords. Without this we would - * assume that we have an alert if engine == NULL */ - uint8_t total_matches = 0; SCMutexLock(&f->de_state_m); DetectEngineStateDirection *dir_state = &f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1]; @@ -500,7 +693,7 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { FLOWLOCK_RDLOCK(f); - alstate = FlowGetAppState(f); + void *alstate = FlowGetAppState(f); if (!StateIsValid(alproto, alstate)) { FLOWLOCK_UNLOCK(f); SCMutexUnlock(&f->de_state_m); @@ -509,7 +702,7 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, inspect_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); - inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); + void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); if (inspect_tx != NULL) { if (AppLayerParserGetStateProgress(f->proto, alproto, inspect_tx, flags) >= AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)) { @@ -520,203 +713,22 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, alproto_supports_txs = 1; } + /* Loop through stored 'items' (stateful rules) and inspect them */ for (; store != NULL; store = store->next) { for (store_cnt = 0; store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt; store_cnt++, state_cnt++) { - total_matches = 0; DeStateStoreItem *item = &store->store[store_cnt]; - Signature *s = de_ctx->sig_array[item->sid]; - - if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { - if (item->flags & (DE_STATE_FLAG_FILE_TC_INSPECT | - DE_STATE_FLAG_FILE_TS_INSPECT)) { - if ((flags & STREAM_TOCLIENT) && - (dir_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW)) - { - item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; - item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; - } - - if ((flags & STREAM_TOSERVER) && - (dir_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW)) - { - item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; - item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; - } - } - - if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { - if (alproto_supports_txs) { - if (TxIsLast(inspect_tx_id, total_txs)) { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } - } else { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } - continue; - } - } - - if (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) { - if ((flags & STREAM_TOSERVER) && - (item->flags & DE_STATE_FLAG_FILE_TS_INSPECT) && - (dir_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW)) - { - item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; - item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; - } else if ((flags & STREAM_TOCLIENT) && - (item->flags & DE_STATE_FLAG_FILE_TC_INSPECT) && - (dir_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW)) - { - item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; - item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; - } else { - if (alproto_supports_txs) { - if (TxIsLast(inspect_tx_id, total_txs)) { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } - } else { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } - continue; - } - } - - alert = 0; - inspect_flags = 0; - match = 0; - - RULE_PROFILING_START(p); - - if (alproto_supports_txs) { - FLOWLOCK_WRLOCK(f); - alstate = FlowGetAppState(f); - if (!StateIsValid(alproto, alstate)) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, match, p); - goto end; - } - - det_ctx->tx_id = inspect_tx_id; - det_ctx->tx_id_set = 1; - engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; - inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); - if (inspect_tx == NULL) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, match, p); - goto end; - } - while (engine != NULL) { - if (!(item->flags & engine->inspect_flags) && - s->sm_lists[engine->sm_list] != NULL) - { - KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); - match = engine->Callback(tv, de_ctx, det_ctx, s, f, - flags, alstate, inspect_tx, inspect_tx_id); - if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { - inspect_flags |= engine->inspect_flags; - engine = engine->next; - total_matches++; - continue; - } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; - } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; - file_no_match++; - } - break; - } - engine = engine->next; - } - if (total_matches > 0 && (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { - if (engine == NULL) - alert = 1; - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; - } - - FLOWLOCK_UNLOCK(f); - } - - /* count AMATCH matches */ - total_matches = 0; - - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_AMATCH); - if (item->nm != NULL) { - /* RDLOCK would be nicer, but at least tlsstore needs - * write lock currently. */ - FLOWLOCK_WRLOCK(f); - alstate = FlowGetAppState(f); - if (alstate == NULL) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, 0 /* no match */, p); - goto end; - } - - for (sm = item->nm; sm != NULL; sm = sm->next) { - if (sigmatch_table[sm->type].AppLayerMatch != NULL) - { - if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { - smb_state = (SMBState *)alstate; - if (smb_state->dcerpc_present) { - KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); - } - } else { - KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); - } - - if (match == 0) - break; - else if (match == 2) - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - else if (match == 1) - total_matches++; - } - } - FLOWLOCK_UNLOCK(f); - } - RULE_PROFILING_END(det_ctx, s, match, p); - - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - if (total_matches > 0 && (sm == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { - if (sm == NULL) - alert = 1; - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; - } - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } - - item->flags |= inspect_flags; - item->nm = sm; - if (TxIsLast(inspect_tx_id, total_txs)) { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } - - if (alert) { - SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); - if (!(s->flags & SIG_FLAG_NOALERT)) { - if (alproto_supports_txs) - PacketAlertAppend(det_ctx, s, p, inspect_tx_id, - PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX); - else - PacketAlertAppend(det_ctx, s, p, 0, - PACKET_ALERT_FLAG_STATE_MATCH); - } else { - DetectSignatureApplyActions(p, s); - } + int r = DoInspectItem(tv, de_ctx, det_ctx, alproto_supports_txs, + item, dir_state->flags, + p, f, alproto, flags, + inspect_tx_id, total_txs, + &file_no_match); + if (r < 0) { + goto end; } - - DetectFlowvarProcessList(det_ctx, f); } } From 7e752799771b8c4df725dd228ba8cca3b07412be Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Feb 2015 18:38:04 +0100 Subject: [PATCH 0289/2553] detect-state: various cleanups --- src/detect-engine-state.c | 49 ++++++++++++++------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 3ac87b43080e..286b803494c8 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -244,30 +244,19 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Signature *s, Packet *p, Flow *f, uint8_t flags, AppProto alproto, uint16_t alversion) { - DetectEngineAppInspectionEngine *engine = NULL; SigMatch *sm = NULL; uint16_t file_no_match = 0; uint32_t inspect_flags = 0; - - void *alstate = NULL; - SMBState *smb_state = NULL; - - void *tx = NULL; - uint64_t tx_id = 0; - uint64_t total_txs = 0; - int match = 0; int store_de_state = 0; uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; - /* this was introduced later to allow protocols that had both app - * keywords with transaction keywords. Without this we would - * assume that we have an alert if engine == NULL */ - int total_matches = 0; - int alert_cnt = 0; if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { + uint64_t tx_id = 0; + uint64_t total_txs = 0; + FLOWLOCK_WRLOCK(f); - alstate = FlowGetAppState(f); + void *alstate = FlowGetAppState(f); if (!StateIsValid(alproto, alstate)) { FLOWLOCK_UNLOCK(f); goto end; @@ -279,18 +268,18 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SCLogDebug("total_txs %"PRIu64, total_txs); for (; tx_id < total_txs; tx_id++) { - total_matches = 0; - tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id); + int total_matches = 0; + void *tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id); if (tx == NULL) continue; det_ctx->tx_id = tx_id; det_ctx->tx_id_set = 1; - engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][direction]; + DetectEngineAppInspectionEngine *engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][direction]; inspect_flags = 0; while (engine != NULL) { if (s->sm_lists[engine->sm_list] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); - match = engine->Callback(tv, de_ctx, det_ctx, s, f, + int match = engine->Callback(tv, de_ctx, det_ctx, s, f, flags, alstate, tx, tx_id); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { @@ -314,17 +303,17 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, * didn't have a match in one of the engines we would have * broken off and engine wouldn't be NULL. Hence the alert. */ if (engine == NULL && total_matches > 0) { - if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, tx_id, PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX); } else { DetectSignatureApplyActions(p, s); } - alert_cnt = 1; } + /* if this is the last tx in our list, and it's incomplete: then + * we store the state so that ContinueDetection knows about it */ if (TxIsLast(tx_id, total_txs)) { if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) < AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)) { @@ -342,7 +331,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, alproto == ALPROTO_SMB2)) { FLOWLOCK_WRLOCK(f); - alstate = FlowGetAppState(f); + void *alstate = FlowGetAppState(f); if (alstate == NULL) { FLOWLOCK_UNLOCK(f); goto end; @@ -350,7 +339,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_DMATCH); if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { - smb_state = (SMBState *)alstate; + SMBState *smb_state = (SMBState *)alstate; if (smb_state->dcerpc_present && DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, flags, &smb_state->dcerpc) == 1) { @@ -360,21 +349,18 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } else { DetectSignatureApplyActions(p, s); } - alert_cnt = 1; } } else { if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, flags, alstate) == 1) { - alert_cnt = 1; - if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, 0, PACKET_ALERT_FLAG_STATE_MATCH); } else { DetectSignatureApplyActions(p, s); } - + alert_cnt = 1; } } FLOWLOCK_UNLOCK(f); @@ -386,17 +372,18 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, /* RDLOCK would be nicer, but at least tlsstore needs * write lock currently. */ FLOWLOCK_WRLOCK(f); - alstate = FlowGetAppState(f); + void *alstate = FlowGetAppState(f); if (alstate == NULL) { FLOWLOCK_UNLOCK(f); goto end; } - for (match = 0; sm != NULL; sm = sm->next) { - match = 0; + int match = 0; + for ( ; sm != NULL; sm = sm->next) { if (sigmatch_table[sm->type].AppLayerMatch != NULL) { + match = 0; if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { - smb_state = (SMBState *)alstate; + SMBState *smb_state = (SMBState *)alstate; if (smb_state->dcerpc_present) { KEYWORD_PROFILING_START; match = sigmatch_table[sm->type]. From 866d9684eaef61481d9a3bb52ab057e772980d05 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Feb 2015 18:40:31 +0100 Subject: [PATCH 0290/2553] detect-state: fix profiling --- src/detect-engine-state.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 286b803494c8..261bd5fb78ae 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -388,13 +388,13 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, KEYWORD_PROFILING_START; match = sigmatch_table[sm->type]. AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + KEYWORD_PROFILING_END(det_ctx, sm->type, (match == 1)); } } else { KEYWORD_PROFILING_START; match = sigmatch_table[sm->type]. AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + KEYWORD_PROFILING_END(det_ctx, sm->type, (match == 1)); } if (match == 0) @@ -606,13 +606,13 @@ static int DoInspectItem(ThreadVars *tv, KEYWORD_PROFILING_START; match = sigmatch_table[sm->type]. AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + KEYWORD_PROFILING_END(det_ctx, sm->type, (match == 1)); } } else { KEYWORD_PROFILING_START; match = sigmatch_table[sm->type]. AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + KEYWORD_PROFILING_END(det_ctx, sm->type, (match == 1)); } if (match == 0) From 1cf02560c8aa60ec3f009f4efee28ac08dcfb637 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 Mar 2015 19:11:10 +0100 Subject: [PATCH 0291/2553] app-layer: per tx destate Add API calls for storing detection state in the TX. --- src/app-layer-parser.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/app-layer-parser.h | 8 ++++++++ 2 files changed, 48 insertions(+) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index c32f721c1251..42ad4e1eddc6 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -106,6 +106,9 @@ typedef struct AppLayerParserProtoCtx_ int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type); + DetectEngineState *(*GetTxDetectState)(void *tx); + int (*SetTxDetectState)(void *tx, DetectEngineState *); + /* Indicates the direction the parser is ready to see the data * the first time for a flow. Values accepted - * STREAM_TOSERVER, STREAM_TOCLIENT */ @@ -468,6 +471,18 @@ void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, SCReturn; } +void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, + DetectEngineState *(*GetTxDetectState)(void *tx), + int (*SetTxDetectState)(void *tx, DetectEngineState *)) +{ + SCEnter(); + + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState = GetTxDetectState; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState = SetTxDetectState; + + SCReturn; +} + /***** Get and transaction functions *****/ void *AppLayerParserGetProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto) @@ -782,6 +797,31 @@ uint64_t AppLayerParserGetTransactionActive(uint8_t ipproto, AppProto alproto, SCReturnCT(active_id, "uint64_t"); } +int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto) +{ + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState != NULL) + return TRUE; + return FALSE; +} + +DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx) +{ + SCEnter(); + DetectEngineState *s; + s = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState(tx); + SCReturnPtr(s, "DetectEngineState"); +} + +int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx, DetectEngineState *s) +{ + int r; + SCEnter(); + if ((alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState(tx) != NULL)) + SCReturnInt(-EBUSY); + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState(tx, s); + SCReturnInt(r); +} + /***** General *****/ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index a000f0fbb082..44f27b76c8d2 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -26,6 +26,7 @@ #define __APP_LAYER_PARSER_H__ #include "app-layer-events.h" +#include "detect-engine-state.h" #include "util-file.h" #define APP_LAYER_PARSER_EOF 0x01 @@ -141,6 +142,9 @@ void AppLayerParserRegisterGetStateProgressCompletionStatus(uint8_t ipproto, void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type)); +void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, + DetectEngineState *(*GetTxDetectState)(void *tx), + int (*SetTxDetectState)(void *tx, DetectEngineState *)); /***** Get and transaction functions *****/ @@ -175,6 +179,10 @@ uint64_t AppLayerParserGetTransactionActive(uint8_t ipproto, AppProto alproto, A uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto); +int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto); +DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx); +int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx, DetectEngineState *s); + /***** General *****/ int AppLayerParserParse(AppLayerParserThreadCtx *tctx, Flow *f, AppProto alproto, From 6279da0fbd643ea365f338bb5c27246da09f9aaa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 Mar 2015 19:37:55 +0100 Subject: [PATCH 0292/2553] http: support per TX destate storage --- src/app-layer-htp.c | 24 ++++++++++++++++++++++++ src/app-layer-htp.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 399dd7a2ae29..e1a513a8eacf 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2629,6 +2629,28 @@ static void HTPStateTruncate(void *state, uint8_t direction) } } +static DetectEngineState *HTPGetTxDetectState(void *vtx) +{ + htp_tx_t *tx = (htp_tx_t *)vtx; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + return tx_ud ? tx_ud->de_state : NULL; +} + +static int HTPSetTxDetectState(void *vtx, DetectEngineState *s) +{ + htp_tx_t *tx = (htp_tx_t *)vtx; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + if (tx_ud == NULL) { + tx_ud = HTPMalloc(sizeof(*tx_ud)); + if (unlikely(tx_ud == NULL)) + return -ENOMEM; + memset(tx_ud, 0, sizeof(*tx_ud)); + htp_tx_set_user_data(tx, tx_ud); + } + tx_ud->de_state = s; + return 0; +} + static int HTPRegisterPatternsForProtocolDetection(void) { /* toserver */ @@ -2758,6 +2780,8 @@ void RegisterHTPParsers(void) AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetEventInfo); AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateTruncate); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_HTTP, + HTPGetTxDetectState, HTPSetTxDetectState); AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOSERVER, HTPHandleRequestData); diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index e3cad8a1e425..fca9efe37fe2 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -36,6 +36,7 @@ #include "util-radix-tree.h" #include "util-file.h" #include "app-layer-htp-mem.h" +#include "detect-engine-state.h" #include @@ -228,6 +229,7 @@ typedef struct HtpTxUserData_ { uint8_t request_body_type; uint8_t response_body_type; + DetectEngineState *de_state; } HtpTxUserData; typedef struct HtpState_ { From 774bb9035130efb95d32fe349e11483394dc2377 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 9 Mar 2015 11:08:47 +0100 Subject: [PATCH 0293/2553] http: clean up tx destate at tx destroy --- src/app-layer-htp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index e1a513a8eacf..db72614862e4 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -321,6 +321,9 @@ static void HtpTxUserDataFree(HtpTxUserData *htud) AppLayerDecoderEventsFreeEvents(&htud->decoder_events); if (htud->boundary) HTPFree(htud->boundary, htud->boundary_len); + if (htud->de_state != NULL) { + DetectEngineStateFree(htud->de_state); + } HTPFree(htud, sizeof(HtpTxUserData)); } } From 2a23627a82a655b808ca4dd67e8f40194c491333 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 9 Mar 2015 15:32:40 +0100 Subject: [PATCH 0294/2553] dns: implement tx de_state --- src/app-layer-dns-common.c | 16 ++++++++++++++++ src/app-layer-dns-common.h | 4 ++++ src/app-layer-dns-tcp.c | 2 ++ src/app-layer-dns-udp.c | 2 ++ 4 files changed, 24 insertions(+) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 5f8e0be13326..95eaf131520e 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -277,6 +277,9 @@ static void DNSTransactionFree(DNSTransaction *tx, DNSState *state) AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + if (tx->de_state != NULL) + DetectEngineStateFree(tx->de_state); + DNSDecrMemcap(sizeof(DNSTransaction), state); SCFree(tx); SCReturn; @@ -344,6 +347,19 @@ DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16 return NULL; } +DetectEngineState *DNSGetTxDetectState(void *vtx) +{ + DNSTransaction *tx = (DNSTransaction *)vtx; + return tx->de_state; +} + +int DNSSetTxDetectState(void *vtx, DetectEngineState *s) +{ + DNSTransaction *tx = (DNSTransaction *)vtx; + tx->de_state = s; + return 0; +} + void *DNSStateAlloc(void) { void *s = SCMalloc(sizeof(DNSState)); diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index ab2d8ef11835..5977a74df841 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -149,6 +149,7 @@ typedef struct DNSTransaction_ { AppLayerDecoderEvents *decoder_events; /**< per tx events */ TAILQ_ENTRY(DNSTransaction_) next; + DetectEngineState *de_state; } DNSTransaction; /** \brief Per flow DNS state container */ @@ -199,6 +200,9 @@ int DNSGetAlstateProgressCompletionStatus(uint8_t direction); void DNSStateTransactionFree(void *state, uint64_t tx_id); DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16_t tx_id); +DetectEngineState *DNSGetTxDetectState(void *vtx); +int DNSSetTxDetectState(void *vtx, DetectEngineState *s); + void DNSSetEvent(DNSState *s, uint8_t e); void *DNSStateAlloc(void); void DNSStateFree(void *s); diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 6b46a5a1dcb2..8ed1a85dcb67 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -642,6 +642,8 @@ void RegisterDNSTCPParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSHasEvents); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DNS, + DNSGetTxDetectState, DNSSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNS, DNSGetTx); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DNS, DNSGetTxCnt); diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index feeb7de1c7dc..86350d0ce396 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -398,6 +398,8 @@ void RegisterDNSUDPParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSHasEvents); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_DNS, + DNSGetTxDetectState, DNSSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_DNS, DNSGetTx); From e984a57203722e45335e113ee8a5b96f5dfd82b5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 9 Mar 2015 15:45:39 +0100 Subject: [PATCH 0295/2553] smtp: tx de_state --- src/app-layer-smtp.c | 17 +++++++++++++++++ src/app-layer-smtp.h | 1 + 2 files changed, 18 insertions(+) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 15d507d26169..90bc7d89fea9 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1128,6 +1128,8 @@ static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state) if (tx->decoder_events != NULL) { AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + if (tx->de_state != NULL) + DetectEngineStateFree(tx->de_state); #if 0 if (tx->decoder_events->cnt <= smtp_state->events) smtp_state->events -= tx->decoder_events->cnt; @@ -1332,6 +1334,19 @@ static AppLayerDecoderEvents *SMTPGetEvents(void *state, uint64_t tx_id) return NULL; } +static DetectEngineState *SMTPGetTxDetectState(void *vtx) +{ + SMTPTransaction *tx = (SMTPTransaction *)vtx; + return tx->de_state; +} + +static int SMTPSetTxDetectState(void *vtx, DetectEngineState *s) +{ + SMTPTransaction *tx = (SMTPTransaction *)vtx; + tx->de_state = s; + return 0; +} + /** * \brief Register the SMTP Protocol parser. */ @@ -1359,6 +1374,8 @@ void RegisterSMTPParsers(void) AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo); AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, + SMTPGetTxDetectState, SMTPSetTxDetectState); AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc, SMTPLocalStorageFree); diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index d5e936a93849..8bb4a9323902 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -62,6 +62,7 @@ typedef struct SMTPTransaction_ { MimeDecParseState *mime_state; AppLayerDecoderEvents *decoder_events; /**< per tx events */ + DetectEngineState *de_state; TAILQ_ENTRY(SMTPTransaction_) next; } SMTPTransaction; From 840efe17fe00ab10a231648ea17964024eb1d47e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 9 Mar 2015 15:58:07 +0100 Subject: [PATCH 0296/2553] modbus: tx de_state --- src/app-layer-modbus.c | 18 ++++++++++++++++++ src/app-layer-modbus.h | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index d2518b5313d3..873423184ae6 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -332,6 +332,9 @@ static void ModbusTxFree(ModbusTransaction *tx) { AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + if (tx->de_state != NULL) + DetectEngineStateFree(tx->de_state); + SCFree(tx); SCReturn; } @@ -1332,6 +1335,19 @@ static uint16_t ModbusProbingParser(uint8_t *input, return ALPROTO_MODBUS; } +DetectEngineState *ModbusGetTxDetectState(void *vtx) +{ + ModbusTransaction *tx = (ModbusTransaction *)vtx; + return tx->de_state; +} + +int ModbusSetTxDetectState(void *vtx, DetectEngineState *s) +{ + ModbusTransaction *tx = (ModbusTransaction *)vtx; + tx->de_state = s; + return 0; +} + /** * \brief Function to register the Modbus protocol parsers and other functions */ @@ -1392,6 +1408,8 @@ void RegisterModbusParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusHasEvents); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, + ModbusGetTxDetectState, ModbusSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTx); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTxCnt); diff --git a/src/app-layer-modbus.h b/src/app-layer-modbus.h index 99e07e885f84..25ac519afd39 100644 --- a/src/app-layer-modbus.h +++ b/src/app-layer-modbus.h @@ -35,7 +35,7 @@ #define __APP_LAYER_MODBUS_H__ #include "decode.h" - +#include "detect-engine-state.h" #include "queue.h" /* Modbus Application Data Unit (ADU) @@ -108,6 +108,7 @@ typedef struct ModbusTransaction_ { uint16_t *data; /**< to store data to write, bit is converted in 16bits. */ AppLayerDecoderEvents *decoder_events; /**< per tx events */ + DetectEngineState *de_state; TAILQ_ENTRY(ModbusTransaction_) next; } ModbusTransaction; From da3e8ad8f6e77583cc7998057d41959a85758868 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 Feb 2015 15:21:17 +0100 Subject: [PATCH 0297/2553] detect-state: split flow and tx state Use separate data structures for storing TX and FLOW (AMATCH) detect state. - move state storing into util funcs - remove de_state_m - simplify reset state logic on reload --- src/detect-engine-state.c | 659 +++++++++++++++++++++++++------------- src/detect-engine-state.h | 31 +- src/detect.c | 12 +- src/flow-util.h | 12 +- src/flow.h | 7 +- 5 files changed, 471 insertions(+), 250 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 261bd5fb78ae..c19e398f49a2 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -83,6 +83,28 @@ /******** static internal helpers *********/ +static inline int StateIsValid(uint16_t alproto, void *alstate) +{ + if (alstate != NULL) { + if (alproto == ALPROTO_HTTP) { + HtpState *htp_state = (HtpState *)alstate; + if (htp_state->conn != NULL) { + return 1; + } + } else { + return 1; + } + } + return 0; +} + +static inline int TxIsLast(uint64_t tx_id, uint64_t total_txs) +{ + if (total_txs - tx_id <= 1) + return 1; + return 0; +} + static DeStateStore *DeStateStoreAlloc(void) { DeStateStore *d = SCMalloc(sizeof(DeStateStore)); @@ -92,10 +114,17 @@ static DeStateStore *DeStateStoreAlloc(void) return d; } +static DeStateStoreFlowRules *DeStateStoreFlowRulesAlloc(void) +{ + DeStateStoreFlowRules *d = SCMalloc(sizeof(DeStateStoreFlowRules)); + if (unlikely(d == NULL)) + return NULL; + memset(d, 0, sizeof(DeStateStoreFlowRules)); -static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, - SigMatch *sm, uint32_t inspect_flags, - uint8_t direction) + return d; +} + +static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, uint32_t inspect_flags, uint8_t direction) { int jump = 0; int i = 0; @@ -128,19 +157,56 @@ static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, SigIntId idx = dir_state->cnt++ % DE_STATE_CHUNK_SIZE; store->store[idx].sid = s->num; store->store[idx].flags = inspect_flags; - store->store[idx].nm = sm; return; } -static void DeStateStoreStateVersion(DetectEngineState *de_state, - uint16_t alversion, uint8_t direction) +static void DeStateFlowRuleAppend(DetectEngineStateFlow *state, Signature *s, + SigMatch *sm, uint32_t inspect_flags, + uint8_t direction) { - de_state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].alversion = alversion; + int jump = 0; + int i = 0; + DetectEngineStateDirectionFlow *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1]; + DeStateStoreFlowRules *store = dir_state->head; + + if (store == NULL) { + store = DeStateStoreFlowRulesAlloc(); + if (store != NULL) { + dir_state->head = store; + dir_state->tail = store; + } + } else { + jump = dir_state->cnt / DE_STATE_CHUNK_SIZE; + for (i = 0; i < jump; i++) { + store = store->next; + } + if (store == NULL) { + store = DeStateStoreFlowRulesAlloc(); + if (store != NULL) { + dir_state->tail->next = store; + dir_state->tail = store; + } + } + } + + if (store == NULL) + return; + + SigIntId idx = dir_state->cnt++ % DE_STATE_CHUNK_SIZE; + store->store[idx].sid = s->num; + store->store[idx].flags = inspect_flags; + store->store[idx].nm = sm; return; } +static void DeStateStoreStateVersion(Flow *f, + uint16_t alversion, uint8_t direction) +{ + f->detect_alversion[direction & STREAM_TOSERVER ? 0 : 1] = alversion; +} + static void DeStateStoreFileNoMatchCnt(DetectEngineState *de_state, uint16_t file_no_match, uint8_t direction) { de_state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].filestore_cnt += file_no_match; @@ -166,6 +232,16 @@ DetectEngineState *DetectEngineStateAlloc(void) return d; } +DetectEngineStateFlow *DetectEngineStateFlowAlloc(void) +{ + DetectEngineStateFlow *d = SCMalloc(sizeof(DetectEngineStateFlow)); + if (unlikely(d == NULL)) + return NULL; + memset(d, 0, sizeof(DetectEngineStateFlow)); + + return d; +} + void DetectEngineStateFree(DetectEngineState *state) { DeStateStore *store; @@ -185,7 +261,65 @@ void DetectEngineStateFree(DetectEngineState *state) return; } -/** +void DetectEngineStateFlowFree(DetectEngineStateFlow *state) +{ + DeStateStoreFlowRules *store; + DeStateStoreFlowRules *store_next; + int i = 0; + + for (i = 0; i < 2; i++) { + store = state->dir_state[i].head; + while (store != NULL) { + store_next = store->next; + SCFree(store); + store = store_next; + } + } + SCFree(state); + + return; +} + +static int HasStoredSigs(Flow *f, uint8_t flags) +{ + if (f->de_state != NULL && f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1].cnt != 0) { + SCLogDebug("global sigs present"); + return 1; + } + + if (AppLayerParserProtocolSupportsTxs(f->proto, f->alproto)) { + AppProto alproto = f->alproto; + void *alstate = FlowGetAppState(f); + if (!StateIsValid(f->alproto, alstate)) { + return 0; + } + + uint64_t inspect_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); + + for ( ; inspect_tx_id < total_txs; inspect_tx_id++) { + void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); + if (inspect_tx != NULL) { + DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(f->proto, alproto, inspect_tx); + if (tx_de_state == NULL) { + continue; + } + if (tx_de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1].cnt != 0) { + SCLogDebug("tx %u has sigs present", (uint)inspect_tx_id); + return 1; + } + } + } + } + return 0; +} + +/** \brief Check if we need to inspect this state + * + * State needs to be inspected if: + * 1. state has been updated + * 2. we already have de_state in progress + * * \retval 0 no inspectable state * \retval 1 inspectable state * \retval 2 inspectable state, but no update @@ -194,49 +328,97 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion { int r = 0; - SCMutexLock(&f->de_state_m); - if (f->de_state == NULL || f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1].cnt == 0) { - if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { - FLOWLOCK_RDLOCK(f); - if (f->alparser != NULL && f->alstate != NULL) { - if (AppLayerParserGetTransactionInspectId(f->alparser, flags) >= - AppLayerParserGetTxCnt(f->proto, alproto, f->alstate)) { - r = 2; - } - } - FLOWLOCK_UNLOCK(f); - } - } else if (!(flags & STREAM_EOF) && - f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1].alversion == alversion) { + FLOWLOCK_WRLOCK(f); + + if (!(flags & STREAM_EOF) && f->de_state && + f->detect_alversion[flags & STREAM_TOSERVER ? 0 : 1] == alversion) { + SCLogDebug("unchanged state"); r = 2; - } else { + } else if (HasStoredSigs(f, flags)) { r = 1; + } else { + r = 0; } - SCMutexUnlock(&f->de_state_m); + FLOWLOCK_UNLOCK(f); return r; } -static inline int StateIsValid(uint16_t alproto, void *alstate) +static int StoreState(DetectEngineThreadCtx *det_ctx, + Flow *f, const uint8_t flags, const uint16_t alversion, + Signature *s, SigMatch *sm, const uint32_t inspect_flags, + const uint16_t file_no_match) { - if (alstate != NULL) { - if (alproto == ALPROTO_HTTP) { - HtpState *htp_state = (HtpState *)alstate; - if (htp_state->conn != NULL) { - return 1; + if (f->de_state == NULL) { + f->de_state = DetectEngineStateFlowAlloc(); + if (f->de_state == NULL) { + return 0; + } + } + + DeStateFlowRuleAppend(f->de_state, s, sm, inspect_flags, flags); + DeStateStoreStateVersion(f, alversion, flags); + return 1; +} + +static void StoreStateTxHandleFiles(DetectEngineThreadCtx *det_ctx, Flow *f, + DetectEngineState *destate, const uint8_t flags, + const uint64_t tx_id, const uint16_t file_no_match) +{ + DeStateStoreFileNoMatchCnt(destate, file_no_match, flags); + if (DeStateStoreFilestoreSigsCantMatch(det_ctx->sgh, destate, flags) == 1) { + FileDisableStoringForTransaction(f, flags & (STREAM_TOCLIENT | STREAM_TOSERVER), tx_id); + destate->dir_state[flags & STREAM_TOSERVER ? 0 : 1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED; + } +} + +static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx, + Flow *f, const uint8_t flags, const uint64_t tx_id, void *tx, + const uint16_t file_no_match) +{ + if (AppLayerParserSupportsTxDetectState(f->proto, f->alproto)) { + DetectEngineState *destate = AppLayerParserGetTxDetectState(f->proto, f->alproto, tx); + if (destate == NULL) { + destate = DetectEngineStateAlloc(); + if (destate == NULL) + return; + if (AppLayerParserSetTxDetectState(f->proto, f->alproto, tx, destate) < 0) { + DetectEngineStateFree(destate); + BUG_ON(1); + return; } - } else { - return 1; + SCLogDebug("destate created for %"PRIu64, tx_id); } + StoreStateTxHandleFiles(det_ctx, f, destate, flags, tx_id, file_no_match); } - return 0; } -static inline int TxIsLast(uint64_t tx_id, uint64_t total_txs) +static void StoreStateTx(DetectEngineThreadCtx *det_ctx, + Flow *f, const uint8_t flags, const uint16_t alversion, + const uint64_t tx_id, void *tx, + Signature *s, SigMatch *sm, + const uint32_t inspect_flags, const uint16_t file_no_match) { - if (total_txs - tx_id <= 1) - return 1; - return 0; + if (AppLayerParserSupportsTxDetectState(f->proto, f->alproto)) { + DetectEngineState *destate = AppLayerParserGetTxDetectState(f->proto, f->alproto, tx); + if (destate == NULL) { + destate = DetectEngineStateAlloc(); + if (destate == NULL) + return; + if (AppLayerParserSetTxDetectState(f->proto, f->alproto, tx, destate) < 0) { + DetectEngineStateFree(destate); + BUG_ON(1); + return; + } + SCLogDebug("destate created for %"PRIu64, tx_id); + } + + DeStateSignatureAppend(destate, s, inspect_flags, flags); + DeStateStoreStateVersion(f, alversion, flags); + + StoreStateTxHandleFiles(det_ctx, f, destate, flags, tx_id, file_no_match); + } + SCLogDebug("Stored for TX %"PRIu64, tx_id); } int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, @@ -247,23 +429,21 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SigMatch *sm = NULL; uint16_t file_no_match = 0; uint32_t inspect_flags = 0; - int store_de_state = 0; uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; int alert_cnt = 0; + FLOWLOCK_WRLOCK(f); + /* TX based matches (inspect engines) */ if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { uint64_t tx_id = 0; uint64_t total_txs = 0; - FLOWLOCK_WRLOCK(f); void *alstate = FlowGetAppState(f); if (!StateIsValid(alproto, alstate)) { - FLOWLOCK_UNLOCK(f); goto end; } tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); - SCLogDebug("tx_id %"PRIu64, tx_id); total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); SCLogDebug("total_txs %"PRIu64, total_txs); @@ -314,26 +494,31 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, /* if this is the last tx in our list, and it's incomplete: then * we store the state so that ContinueDetection knows about it */ - if (TxIsLast(tx_id, total_txs)) { - if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) < - AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)) { - store_de_state = 1; - if (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) + int tx_is_done = (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) >= + AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)); + + if ((engine == NULL && total_matches > 0) || (inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { + if (!(TxIsLast(tx_id, total_txs)) || !tx_is_done) { + if (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; + } + + /* store */ + StoreStateTx(det_ctx, f, flags, alversion, tx_id, tx, + s, sm, inspect_flags, file_no_match); + } else { + StoreStateTxFileOnly(det_ctx, f, flags, tx_id, tx, file_no_match); } } } /* for */ - FLOWLOCK_UNLOCK(f); - + /* DCERPC matches */ } else if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL && (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2)) { - FLOWLOCK_WRLOCK(f); void *alstate = FlowGetAppState(f); if (alstate == NULL) { - FLOWLOCK_UNLOCK(f); goto end; } @@ -363,18 +548,14 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, alert_cnt = 1; } } - FLOWLOCK_UNLOCK(f); } + /* flow based matches */ KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_AMATCH); sm = s->sm_lists[DETECT_SM_LIST_AMATCH]; if (sm != NULL) { - /* RDLOCK would be nicer, but at least tlsstore needs - * write lock currently. */ - FLOWLOCK_WRLOCK(f); void *alstate = FlowGetAppState(f); if (alstate == NULL) { - FLOWLOCK_UNLOCK(f); goto end; } @@ -405,9 +586,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } } } - FLOWLOCK_UNLOCK(f); - store_de_state = 1; if (sm == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) { if (match == 1) { if (!(s->flags & SIG_FLAG_NOALERT)) { @@ -420,34 +599,14 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; } - } - - if (!store_de_state && file_no_match == 0) - goto end; - SCMutexLock(&f->de_state_m); - if (f->de_state == NULL) { - f->de_state = DetectEngineStateAlloc(); - if (f->de_state == NULL) { - SCMutexUnlock(&f->de_state_m); - goto end; - } + StoreState(det_ctx, f, flags, alversion, + s, sm, inspect_flags, file_no_match); } - if (store_de_state) { - DeStateSignatureAppend(f->de_state, s, sm, inspect_flags, flags); - DeStateStoreStateVersion(f->de_state, alversion, flags); - } - DeStateStoreFileNoMatchCnt(f->de_state, file_no_match, flags); - if (DeStateStoreFilestoreSigsCantMatch(det_ctx->sgh, f->de_state, flags) == 1) { - FLOWLOCK_WRLOCK(f); - FileDisableStoringForTransaction(f, flags & (STREAM_TOCLIENT | STREAM_TOSERVER), - det_ctx->tx_id); - FLOWLOCK_UNLOCK(f); - f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED; - } - SCMutexUnlock(&f->de_state_m); end: + FLOWLOCK_UNLOCK(f); + det_ctx->tx_id = 0; det_ctx->tx_id_set = 0; return alert_cnt ? 1:0; @@ -455,12 +614,12 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, static int DoInspectItem(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const int alproto_supports_txs, DeStateStoreItem *item, const uint8_t dir_state_flags, Packet *p, Flow *f, AppProto alproto, uint8_t flags, const uint64_t inspect_tx_id, const uint64_t total_txs, - uint16_t *file_no_match) + uint16_t *file_no_match, int inprogress, // is current tx in progress? + const int next_tx_no_progress) // tx after current is still dormant { Signature *s = de_ctx->sig_array[item->sid]; @@ -484,11 +643,7 @@ static int DoInspectItem(ThreadVars *tv, } if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { - if (alproto_supports_txs) { - if (TxIsLast(inspect_tx_id, total_txs)) { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } - } else { + if (TxIsLast(inspect_tx_id, total_txs) || inprogress || next_tx_no_progress) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; } return 0; @@ -511,11 +666,7 @@ static int DoInspectItem(ThreadVars *tv, item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; } else { - if (alproto_supports_txs) { - if (TxIsLast(inspect_tx_id, total_txs)) { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } - } else { + if (TxIsLast(inspect_tx_id, total_txs) || inprogress || next_tx_no_progress) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; } return 0; @@ -528,70 +679,105 @@ static int DoInspectItem(ThreadVars *tv, RULE_PROFILING_START(p); - if (alproto_supports_txs) { - FLOWLOCK_WRLOCK(f); - void *alstate = FlowGetAppState(f); - if (!StateIsValid(alproto, alstate)) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, 0, p); - return -1; - } + void *alstate = FlowGetAppState(f); + if (!StateIsValid(alproto, alstate)) { + RULE_PROFILING_END(det_ctx, s, 0, p); + return -1; + } - det_ctx->tx_id = inspect_tx_id; - det_ctx->tx_id_set = 1; - DetectEngineAppInspectionEngine *engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; - void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); - if (inspect_tx == NULL) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, 0, p); - return -1; - } + det_ctx->tx_id = inspect_tx_id; + det_ctx->tx_id_set = 1; + DetectEngineAppInspectionEngine *engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; + void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); + if (inspect_tx == NULL) { + RULE_PROFILING_END(det_ctx, s, 0, p); + return -1; + } - while (engine != NULL) { - if (!(item->flags & engine->inspect_flags) && - s->sm_lists[engine->sm_list] != NULL) - { - KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); - int match = engine->Callback(tv, de_ctx, det_ctx, s, f, - flags, alstate, inspect_tx, inspect_tx_id); - if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { - inspect_flags |= engine->inspect_flags; - engine = engine->next; - total_matches++; - continue; - } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; - } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; - (*file_no_match)++; - } - break; + while (engine != NULL) { + if (!(item->flags & engine->inspect_flags) && + s->sm_lists[engine->sm_list] != NULL) + { + KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); + int match = engine->Callback(tv, de_ctx, det_ctx, s, f, + flags, alstate, inspect_tx, inspect_tx_id); + if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { + inspect_flags |= engine->inspect_flags; + engine = engine->next; + total_matches++; + continue; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { + inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; + inspect_flags |= engine->inspect_flags; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { + inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; + inspect_flags |= engine->inspect_flags; + (*file_no_match)++; } - engine = engine->next; + break; } - if (total_matches > 0 && (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { - if (engine == NULL) - alert = 1; - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; + engine = engine->next; + } + if (total_matches > 0 && (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { + if (engine == NULL) + alert = 1; + inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; + } + + item->flags |= inspect_flags; + if (TxIsLast(inspect_tx_id, total_txs)) { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + } + + if (alert) { + SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); + + if (!(s->flags & SIG_FLAG_NOALERT)) { + PacketAlertAppend(det_ctx, s, p, inspect_tx_id, + PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX); + } else { + PACKET_UPDATE_ACTION(p, s->action); } + } - FLOWLOCK_UNLOCK(f); + DetectFlowvarProcessList(det_ctx, f); + return 1; +} + +/** \internal + * \brief Continue Detection for a single "flow" rule (AMATCH) + */ +static int DoInspectFlowRule(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + DeStateStoreFlowRule *item, const uint8_t dir_state_flags, + Packet *p, Flow *f, AppProto alproto, uint8_t flags) +{ + if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { + if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + return 0; + } + } + + /* check if a sig in state 'cant match' needs to be reconsidered + * as the result of a new file in the existing tx */ + if (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + return 0; } - /* count AMATCH matches */ - total_matches = 0; + uint8_t alert = 0; + uint32_t inspect_flags = 0; + int total_matches = 0; SigMatch *sm = NULL; + Signature *s = de_ctx->sig_array[item->sid]; + + RULE_PROFILING_START(p); KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_AMATCH); if (item->nm != NULL) { - /* RDLOCK would be nicer, but at least tlsstore needs - * write lock currently. */ - FLOWLOCK_WRLOCK(f); void *alstate = FlowGetAppState(f); if (alstate == NULL) { - FLOWLOCK_UNLOCK(f); RULE_PROFILING_END(det_ctx, s, 0 /* no match */, p); return -1; } @@ -623,7 +809,6 @@ static int DoInspectItem(ThreadVars *tv, total_matches++; } } - FLOWLOCK_UNLOCK(f); } if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { @@ -638,20 +823,13 @@ static int DoInspectItem(ThreadVars *tv, item->flags |= inspect_flags; item->nm = sm; - if (TxIsLast(inspect_tx_id, total_txs)) { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } if (alert) { SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); if (!(s->flags & SIG_FLAG_NOALERT)) { - if (alproto_supports_txs) - PacketAlertAppend(det_ctx, s, p, inspect_tx_id, - PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX); - else - PacketAlertAppend(det_ctx, s, p, 0, - PACKET_ALERT_FLAG_STATE_MATCH); + PacketAlertAppend(det_ctx, s, p, 0, + PACKET_ALERT_FLAG_STATE_MATCH); } else { DetectSignatureApplyActions(p, s); } @@ -671,83 +849,111 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SigIntId state_cnt = 0; uint64_t inspect_tx_id = 0; uint64_t total_txs = 0; - uint8_t alproto_supports_txs = 0; - uint8_t reset_de_state = 0; - SCMutexLock(&f->de_state_m); - DetectEngineStateDirection *dir_state = &f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1]; - DeStateStore *store = dir_state->head; + FLOWLOCK_WRLOCK(f); + + SCLogDebug("starting continue detection for packet %"PRIu64, p->pcap_cnt); if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { - FLOWLOCK_RDLOCK(f); void *alstate = FlowGetAppState(f); if (!StateIsValid(alproto, alstate)) { FLOWLOCK_UNLOCK(f); - SCMutexUnlock(&f->de_state_m); return; } inspect_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); - void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); - if (inspect_tx != NULL) { - if (AppLayerParserGetStateProgress(f->proto, alproto, inspect_tx, flags) >= - AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)) { - reset_de_state = 1; - } - } - FLOWLOCK_UNLOCK(f); - alproto_supports_txs = 1; - } - /* Loop through stored 'items' (stateful rules) and inspect them */ - for (; store != NULL; store = store->next) { - for (store_cnt = 0; - store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt; - store_cnt++, state_cnt++) - { - DeStateStoreItem *item = &store->store[store_cnt]; - - int r = DoInspectItem(tv, de_ctx, det_ctx, alproto_supports_txs, - item, dir_state->flags, - p, f, alproto, flags, - inspect_tx_id, total_txs, - &file_no_match); - if (r < 0) { - goto end; + for ( ; inspect_tx_id < total_txs; inspect_tx_id++) { + int inspect_tx_inprogress = 0; + int next_tx_no_progress = 0; + void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); + if (inspect_tx != NULL) { + int a = AppLayerParserGetStateProgress(f->proto, alproto, inspect_tx, flags); + int b = AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags); + if (a < b) { + inspect_tx_inprogress = 1; + } + SCLogDebug("tx %"PRIu64" (%"PRIu64") => %s", inspect_tx_id, total_txs, + inspect_tx_inprogress ? "in progress" : "done"); + + DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(f->proto, alproto, inspect_tx); + if (tx_de_state == NULL) { + SCLogDebug("NO STATE tx %"PRIu64" (%"PRIu64")", inspect_tx_id, total_txs); + continue; + } + DetectEngineStateDirection *tx_dir_state = &tx_de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1]; + DeStateStore *tx_store = tx_dir_state->head; + + /* see if we need to consider the next tx in our decision to add + * a sig to the 'no inspect array'. */ + if (!TxIsLast(inspect_tx_id, total_txs)) { + void *next_inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id+1); + if (next_inspect_tx != NULL) { + int c = AppLayerParserGetStateProgress(f->proto, alproto, next_inspect_tx, flags); + if (c == 0) { + next_tx_no_progress = 1; + } + } + } + + /* Loop through stored 'items' (stateful rules) and inspect them */ + state_cnt = 0; + for (; tx_store != NULL; tx_store = tx_store->next) { + SCLogDebug("tx_store %p", tx_store); + for (store_cnt = 0; + store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < tx_dir_state->cnt; + store_cnt++, state_cnt++) + { + DeStateStoreItem *item = &tx_store->store[store_cnt]; + int r = DoInspectItem(tv, de_ctx, det_ctx, + item, tx_dir_state->flags, + p, f, alproto, flags, + inspect_tx_id, total_txs, + &file_no_match, inspect_tx_inprogress, next_tx_no_progress); + if (r < 0) { + SCLogDebug("failed"); + goto end; + } + } + } + } + if (inspect_tx_inprogress) { + SCLogDebug("break out"); + break; } } } - DeStateStoreStateVersion(f->de_state, alversion, flags); - DeStateStoreFileNoMatchCnt(f->de_state, file_no_match, flags); - - if (!(dir_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED)) { - if (DeStateStoreFilestoreSigsCantMatch(det_ctx->sgh, f->de_state, flags) == 1) { - SCLogDebug("disabling file storage for transaction"); - - FLOWLOCK_WRLOCK(f); - FileDisableStoringForTransaction(f, flags & (STREAM_TOCLIENT|STREAM_TOSERVER), - det_ctx->tx_id); - FLOWLOCK_UNLOCK(f); + /* continue on flow based state rules (AMATCH) */ + if (f->de_state != NULL) { + DetectEngineStateDirectionFlow *dir_state = &f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1]; + DeStateStoreFlowRules *store = dir_state->head; + /* Loop through stored 'items' (stateful rules) and inspect them */ + for (; store != NULL; store = store->next) { + for (store_cnt = 0; + store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt; + store_cnt++, state_cnt++) + { + DeStateStoreFlowRule *rule = &store->store[store_cnt]; - dir_state->flags |= DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED; + int r = DoInspectFlowRule(tv, de_ctx, det_ctx, + rule, dir_state->flags, + p, f, alproto, flags); + if (r < 0) { + goto end; + } + } } + DeStateStoreStateVersion(f, alversion, flags); } end: - if (f->de_state != NULL) - dir_state->flags &= ~DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW; - - if (reset_de_state) - DetectEngineStateReset(f->de_state, flags); - - SCMutexUnlock(&f->de_state_m); + FLOWLOCK_UNLOCK(f); det_ctx->tx_id = 0; det_ctx->tx_id_set = 0; return; } - /** \brief update flow's inspection id's * * \note it is possible that f->alstate, f->alparser are NULL */ @@ -762,18 +968,15 @@ void DeStateUpdateInspectTransactionId(Flow *f, uint8_t direction) return; } - -void DetectEngineStateReset(DetectEngineState *state, uint8_t direction) +void DetectEngineStateReset(DetectEngineStateFlow *state, uint8_t direction) { if (state != NULL) { if (direction & STREAM_TOSERVER) { state->dir_state[0].cnt = 0; - state->dir_state[0].filestore_cnt = 0; state->dir_state[0].flags = 0; } if (direction & STREAM_TOCLIENT) { state->dir_state[1].cnt = 0; - state->dir_state[1].filestore_cnt = 0; state->dir_state[1].flags = 0; } } @@ -825,39 +1028,39 @@ static int DeStateTest02(void) uint8_t direction = STREAM_TOSERVER; s.num = 0; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 11; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 22; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 33; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 44; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 55; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 66; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 77; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 88; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 99; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 100; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 111; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 122; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 133; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 144; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 155; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 166; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL) { goto end; @@ -907,9 +1110,9 @@ static int DeStateTest03(void) uint8_t direction = STREAM_TOSERVER; s.num = 11; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 22; - DeStateSignatureAppend(state, &s, NULL, DE_STATE_FLAG_URI_INSPECT, direction); + DeStateSignatureAppend(state, &s, DE_STATE_FLAG_URI_INSPECT, direction); if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL) { goto end; diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 4c8bf9b19eca..9a5b7ebab16b 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -104,8 +104,9 @@ typedef enum { DE_STATE_MATCH_NO_NEW_STATE, } DeStateMatchResult; +/* TX BASED (inspect engines) */ + typedef struct DeStateStoreItem_ { - SigMatch *nm; uint32_t flags; SigIntId sid; } DeStateStoreItem; @@ -120,7 +121,6 @@ typedef struct DetectEngineStateDirection_ { DeStateStore *tail; SigIntId cnt; uint16_t filestore_cnt; - uint8_t alversion; uint8_t flags; } DetectEngineStateDirection; @@ -128,6 +128,30 @@ typedef struct DetectEngineState_ { DetectEngineStateDirection dir_state[2]; } DetectEngineState; +/* FLOW BASED (AMATCH) */ + +typedef struct DeStateStoreFlowRule_ { + SigMatch *nm; + uint32_t flags; + SigIntId sid; +} DeStateStoreFlowRule; + +typedef struct DeStateStoreFlowRules_ { + DeStateStoreFlowRule store[DE_STATE_CHUNK_SIZE]; + struct DeStateStoreFlowRules_ *next; +} DeStateStoreFlowRules; + +typedef struct DetectEngineStateDirectionFlow_ { + DeStateStoreFlowRules *head; + DeStateStoreFlowRules *tail; + SigIntId cnt; + uint8_t flags; +} DetectEngineStateDirectionFlow; + +typedef struct DetectEngineStateFlow_ { + DetectEngineStateDirectionFlow dir_state[2]; +} DetectEngineStateFlow; + /** * \brief Alloc a DetectEngineState object. * @@ -141,6 +165,7 @@ DetectEngineState *DetectEngineStateAlloc(void); * \param state DetectEngineState instance to free. */ void DetectEngineStateFree(DetectEngineState *state); +void DetectEngineStateFlowFree(DetectEngineStateFlow *state); /** * \brief Check if a flow already contains(newly updated as well) de state. @@ -204,7 +229,7 @@ void DeStateUpdateInspectTransactionId(Flow *f, uint8_t direction); * \param state Pointer to the state(LOCKED). * \param direction Direction flags - STREAM_TOSERVER or STREAM_TOCLIENT. */ -void DetectEngineStateReset(DetectEngineState *state, uint8_t direction); +void DetectEngineStateReset(DetectEngineStateFlow *state, uint8_t direction); void DeStateRegisterTests(void); diff --git a/src/detect.c b/src/detect.c index 3bc7d3b46f18..98e3959ce9fa 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1153,7 +1153,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh Signature *s = NULL; Signature *next_s = NULL; uint16_t alversion = 0; - int reset_de_state = 0; int state_alert = 0; int alerts = 0; int app_decoder_events = 0; @@ -1195,11 +1194,13 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh pflow->flags &= ~FLOW_SGH_TOCLIENT; pflow->sgh_toserver = NULL; pflow->sgh_toclient = NULL; - reset_de_state = 1; pflow->de_ctx_id = de_ctx->id; GenericVarFree(pflow->flowvar); pflow->flowvar = NULL; + + DetectEngineStateReset(pflow->de_state, + (STREAM_TOSERVER|STREAM_TOCLIENT)); } /* set the iponly stuff */ @@ -1264,13 +1265,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } SCLogDebug("p->flowflags 0x%02x", p->flowflags); - /* reset because of ruleswap */ - if (reset_de_state) { - SCMutexLock(&pflow->de_state_m); - DetectEngineStateReset(pflow->de_state, (STREAM_TOSERVER|STREAM_TOCLIENT)); - SCMutexUnlock(&pflow->de_state_m); - } - if (((p->flowflags & FLOW_PKT_TOSERVER) && !(p->flowflags & FLOW_PKT_TOSERVER_IPONLY_SET)) || ((p->flowflags & FLOW_PKT_TOCLIENT) && !(p->flowflags & FLOW_PKT_TOCLIENT_IPONLY_SET))) { diff --git a/src/flow-util.h b/src/flow-util.h index 152b409836c8..38257b1289bb 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -57,13 +57,14 @@ (f)->data_al_so_far[1] = 0; \ (f)->de_ctx_id = 0; \ (f)->thread_id = 0; \ + (f)->detect_alversion[0] = 0; \ + (f)->detect_alversion[1] = 0; \ (f)->alparser = NULL; \ (f)->alstate = NULL; \ (f)->de_state = NULL; \ (f)->sgh_toserver = NULL; \ (f)->sgh_toclient = NULL; \ (f)->flowvar = NULL; \ - SCMutexInit(&(f)->de_state_m, NULL); \ (f)->hnext = NULL; \ (f)->hprev = NULL; \ (f)->lnext = NULL; \ @@ -101,10 +102,10 @@ (f)->data_al_so_far[1] = 0; \ (f)->de_ctx_id = 0; \ (f)->thread_id = 0; \ + (f)->detect_alversion[0] = 0; \ + (f)->detect_alversion[1] = 0; \ if ((f)->de_state != NULL) { \ - SCMutexLock(&(f)->de_state_m); \ DetectEngineStateReset((f)->de_state, (STREAM_TOSERVER | STREAM_TOCLIENT)); \ - SCMutexUnlock(&(f)->de_state_m); \ } \ (f)->sgh_toserver = NULL; \ (f)->sgh_toclient = NULL; \ @@ -123,12 +124,9 @@ \ FLOWLOCK_DESTROY((f)); \ if ((f)->de_state != NULL) { \ - SCMutexLock(&(f)->de_state_m); \ - DetectEngineStateFree((f)->de_state); \ - SCMutexUnlock(&(f)->de_state_m); \ + DetectEngineStateFlowFree((f)->de_state); \ } \ GenericVarFree((f)->flowvar); \ - SCMutexDestroy(&(f)->de_state_m); \ SC_ATOMIC_DESTROY((f)->autofp_tmqh_flow_qid); \ } while(0) diff --git a/src/flow.h b/src/flow.h index 48b4b075c0ae..b772986db6d1 100644 --- a/src/flow.h +++ b/src/flow.h @@ -370,6 +370,9 @@ typedef struct Flow_ /** Thread ID for the stream/detect portion of this flow */ FlowThreadId thread_id; + /** detect state 'alversion' inspected for both directions */ + uint8_t detect_alversion[2]; + /** application level storage ptrs. * */ @@ -377,7 +380,7 @@ typedef struct Flow_ void *alstate; /**< application layer state */ /** detection engine state */ - struct DetectEngineState_ *de_state; + struct DetectEngineStateFlow_ *de_state; /** toclient sgh for this flow. Only use when FLOW_SGH_TOCLIENT flow flag * has been set. */ @@ -389,8 +392,6 @@ typedef struct Flow_ /* 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; From e250040b72169536022efdac017eaddb0a58d37a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 10 Mar 2015 17:41:03 +0100 Subject: [PATCH 0298/2553] detect-state: implement tx state reset for reload In case of Detect Reload, we need to reset active tx' state. --- src/detect-engine-state.c | 39 +++++++++++++++++++++++++++++++++++++++ src/detect-engine-state.h | 2 ++ src/detect.c | 1 + 3 files changed, 42 insertions(+) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index c19e398f49a2..6ff91afccd59 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -984,6 +984,45 @@ void DetectEngineStateReset(DetectEngineStateFlow *state, uint8_t direction) return; } +/** \brief Reset de state for active tx' + * To be used on detect engine reload. + * \param f write LOCKED flow + */ +void DetectEngineStateResetTxs(Flow *f) +{ + if (AppLayerParserProtocolSupportsTxs(f->proto, f->alproto)) { + void *alstate = FlowGetAppState(f); + if (!StateIsValid(f->alproto, alstate)) { + return; + } + + uint64_t inspect_ts = AppLayerParserGetTransactionInspectId(f->alparser, STREAM_TOCLIENT); + uint64_t inspect_tc = AppLayerParserGetTransactionInspectId(f->alparser, STREAM_TOSERVER); + + uint64_t inspect_tx_id = MIN(inspect_ts, inspect_tc); + + uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, f->alproto, alstate); + + for ( ; inspect_tx_id < total_txs; inspect_tx_id++) { + void *inspect_tx = AppLayerParserGetTx(f->proto, f->alproto, alstate, inspect_tx_id); + if (inspect_tx != NULL) { + DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(f->proto, f->alproto, inspect_tx); + if (tx_de_state == NULL) { + continue; + } + + tx_de_state->dir_state[0].cnt = 0; + tx_de_state->dir_state[0].filestore_cnt = 0; + tx_de_state->dir_state[0].flags = 0; + + tx_de_state->dir_state[1].cnt = 0; + tx_de_state->dir_state[1].filestore_cnt = 0; + tx_de_state->dir_state[1].flags = 0; + } + } + } +} + /** \brief get string for match enum */ const char *DeStateMatchResultToString(DeStateMatchResult res) { diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 9a5b7ebab16b..464f7180fd1c 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -231,6 +231,8 @@ void DeStateUpdateInspectTransactionId(Flow *f, uint8_t direction); */ void DetectEngineStateReset(DetectEngineStateFlow *state, uint8_t direction); +void DetectEngineStateResetTxs(Flow *f); + void DeStateRegisterTests(void); #endif /* __DETECT_ENGINE_STATE_H__ */ diff --git a/src/detect.c b/src/detect.c index 98e3959ce9fa..2d5ff9822425 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1201,6 +1201,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh DetectEngineStateReset(pflow->de_state, (STREAM_TOSERVER|STREAM_TOCLIENT)); + DetectEngineStateResetTxs(pflow); } /* set the iponly stuff */ From ee7e81325669d6349f345845eeaff4712fb852f0 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 16 Mar 2015 22:29:22 -0600 Subject: [PATCH 0299/2553] Bug 1417 - Record sequence nodes as sequences. Nodes that are sequences weren't being recorded as such, causing rules to fail to load. Change sequence test name to reflect better what it tests, and test that the sequence node is detected as a sequence. --- src/conf-yaml-loader.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index 8e873079432f..49ee6540d1c7 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -310,6 +310,7 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) SCLogDebug("event.type=YAML_SEQUENCE_START_EVENT; state=%d", state); if (ConfYamlParse(parser, node, 1) != 0) goto fail; + node->is_seq = 1; state = CONF_KEY; } else if (event.type == YAML_SEQUENCE_END_EVENT) { @@ -451,7 +452,7 @@ ConfYamlLoadString(const char *string, size_t len) #ifdef UNITTESTS static int -ConfYamlRuleFileTest(void) +ConfYamlSequenceTest(void) { char input[] = "\ %YAML 1.1\n\ @@ -472,6 +473,8 @@ default-log-dir: /tmp\n\ node = ConfGetNode("rule-files"); if (node == NULL) return 0; + if (!ConfNodeIsSequence(node)) + return 0; if (TAILQ_EMPTY(&node->head)) return 0; int i = 0; @@ -480,10 +483,16 @@ default-log-dir: /tmp\n\ if (i == 0) { if (strcmp(filename->val, "netbios.rules") != 0) return 0; + if (ConfNodeIsSequence(filename)) + return 0; + if (filename->is_seq != 0) + return 0; } else if (i == 1) { if (strcmp(filename->val, "x11.rules") != 0) return 0; + if (ConfNodeIsSequence(filename)) + return 0; } else { return 0; @@ -864,7 +873,7 @@ void ConfYamlRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ConfYamlRuleFileTest", ConfYamlRuleFileTest, 1); + UtRegisterTest("ConfYamlSequenceTest", ConfYamlSequenceTest, 1); UtRegisterTest("ConfYamlLoggingOutputTest", ConfYamlLoggingOutputTest, 1); UtRegisterTest("ConfYamlNonYamlFileTest", ConfYamlNonYamlFileTest, 1); UtRegisterTest("ConfYamlBadYamlVersionTest", ConfYamlBadYamlVersionTest, 1); From 60a49657df10d6d14f087037593fd8ef4daf07d5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 Mar 2015 11:48:17 +0100 Subject: [PATCH 0300/2553] Bug 1401: on midstream pickup, fix packet direction On midstream SYN/ACK pickups, we would flip the direction of packets after the first. This meant the first (pickup) packet's direction was wrong. This patch fixes that. --- src/stream-tcp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 28ef48f7553a..d414186bf87d 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -913,6 +913,9 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, "SACK permitted for both sides", ssn); } + /* packet thinks it is in the wrong direction, flip it */ + StreamTcpPacketSwitchDir(ssn, p); + } else if (p->tcph->th_flags & TH_SYN) { if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); From 69f99245c554f2d4ad028026abf8725967896ad4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 29 Jan 2015 11:45:44 +0100 Subject: [PATCH 0301/2553] unix-command: fix duplicate registration error msg --- src/unix-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index 2026ab011aaf..c3fbfc3d898c 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -770,7 +770,7 @@ TmEcode UnixManagerRegisterCommand(const char * keyword, TAILQ_FOREACH(lcmd, &command.commands, next) { if (!strcmp(keyword, lcmd->name)) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "Null keyword"); + SCLogError(SC_ERR_INVALID_ARGUMENT, "%s already registered", keyword); SCReturnInt(TM_ECODE_FAILED); } } From 49bad2cfba46f8a52d69632f559d6a36e1cca4e2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Jan 2015 19:28:44 +0100 Subject: [PATCH 0302/2553] detect: consolidate more setup into DetectEngineCtxInit Loading of classifications, references and action order was done unconditionally, so can be done in one place. --- src/detect-engine.c | 14 +++++++------- src/suricata.c | 6 ------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 248927822a17..9b2058ddb60a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -551,13 +551,6 @@ static void *DetectEngineLiveRuleSwap(void *arg) goto error; } - SCClassConfLoadClassficationConfigFile(de_ctx); - SCRConfLoadReferenceConfigFile(de_ctx); - - if (ActionInitConfig() < 0) { - exit(EXIT_FAILURE); - } - if (SigLoadSignatures(de_ctx, NULL, FALSE) < 0) { SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); if (de_ctx->failure_fatal) @@ -879,6 +872,13 @@ DetectEngineCtx *DetectEngineCtxInit(void) SCProfilingKeywordInitCounters(de_ctx); #endif + SCClassConfLoadClassficationConfigFile(de_ctx); + SCRConfLoadReferenceConfigFile(de_ctx); + + if (ActionInitConfig() < 0) { + goto error; + } + return de_ctx; error: return NULL; diff --git a/src/suricata.c b/src/suricata.c index d385b5b381f2..12458caf70e8 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2312,12 +2312,6 @@ int main(int argc, char **argv) CudaVarsSetDeCtx(de_ctx); #endif /* __SC_CUDA_SUPPORT__ */ - SCClassConfLoadClassficationConfigFile(de_ctx); - SCRConfLoadReferenceConfigFile(de_ctx); - - if (ActionInitConfig() < 0) { - exit(EXIT_FAILURE); - } } else { /* disable raw reassembly */ (void)ConfSetFinal("stream.reassembly.raw", "false"); From 092ddc1853d4f11baf7d6b64c61e0e3b29044e07 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Jan 2015 16:34:16 +0100 Subject: [PATCH 0303/2553] detect: no exit on reference/classification errors Don't exit on errors during classification and reference parsing. Add some suppression of error messages when in unittest mode. --- src/util-classification-config.c | 24 +++++++++++++++++++----- src/util-reference-config.c | 16 +++++++++++++--- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/util-classification-config.c b/src/util-classification-config.c index 3a0d62a8cb4a..db79b7a21340 100644 --- a/src/util-classification-config.c +++ b/src/util-classification-config.c @@ -97,6 +97,10 @@ int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) if (fd == NULL) { filename = SCClassConfGetConfFilename(); if ( (fd = fopen(filename, "r")) == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests()) + goto error; // silently fail +#endif SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } @@ -206,7 +210,7 @@ static char *SCClassConfStringToLowercase(const char *str) if ( (new_str = SCStrdup(str)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); + return NULL; } temp_str = new_str; @@ -392,13 +396,17 @@ SCClassConfClasstype *SCClassConfAllocClasstype(uint8_t classtype_id, if ( (ct->classtype = SCClassConfStringToLowercase(classtype)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); + + SCClassConfDeAllocClasstype(ct); + return NULL; } if (classtype_desc != NULL && (ct->classtype_desc = SCStrdup(classtype_desc)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); + + SCClassConfDeAllocClasstype(ct); + return NULL; } ct->classtype_id = classtype_id; @@ -519,8 +527,14 @@ void SCClassConfClasstypeHashFree(void *ch) void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx) { if (SCClassConfInitContextAndLocalResources(de_ctx) == -1) { - SCLogInfo("Please check the \"classification-file\" option in your suricata.yaml file"); - exit(EXIT_FAILURE); +#ifdef UNITTESTS + if (RunmodeIsUnittests() && fd == NULL) { + return; + } +#endif + SCLogError(SC_ERR_OPENING_FILE, "please check the \"classification-file\" " + "option in your suricata.yaml file"); + return; } SCClassConfParseFile(de_ctx); diff --git a/src/util-reference-config.c b/src/util-reference-config.c index 1eb8047e055c..aea8562772c6 100644 --- a/src/util-reference-config.c +++ b/src/util-reference-config.c @@ -93,6 +93,10 @@ static int SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) if (fd == NULL) { filename = SCRConfGetConfFilename(); if ((fd = fopen(filename, "r")) == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests()) + goto error; // silently fail +#endif SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; @@ -492,8 +496,14 @@ void SCRConfReferenceHashFree(void *data) int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx) { if (SCRConfInitContextAndLocalResources(de_ctx) == -1) { - SCLogInfo("Please check the \"reference-config-file\" option in your suricata.yaml file"); - exit(EXIT_FAILURE); +#ifdef UNITTESTS + if (RunmodeIsUnittests() && fd == NULL) { + return -1; + } +#endif + SCLogError(SC_ERR_OPENING_FILE, "please check the \"reference-config-file\" " + "option in your suricata.yaml file"); + return -1; } SCRConfParseFile(de_ctx); @@ -518,7 +528,7 @@ SCRConfReference *SCRConfGetReference(const char *rconf_name, { SCRConfReference *ref_conf = SCRConfAllocSCRConfReference(rconf_name, NULL); if (ref_conf == NULL) - exit(EXIT_FAILURE); + return NULL; SCRConfReference *lookup_ref_conf = HashTableLookup(de_ctx->reference_conf_ht, ref_conf, 0); From 664100c0742bd3e9a43b8e2975789111ebf04e25 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Jan 2015 19:25:24 +0100 Subject: [PATCH 0304/2553] suricatasc: allow for much longer response times --- scripts/suricatasc/src/suricatasc.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index c941b4b51ee9..ea4c62ae6136 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -22,6 +22,7 @@ import readline from socket import socket, AF_UNIX, error from time import sleep +import select import sys SURICATASC_VERSION = "0.9" @@ -114,7 +115,12 @@ def send_command(self, command, arguments = None): self.socket.send(json.dumps(cmdmsg)) else: self.socket.send(bytes(json.dumps(cmdmsg), 'iso-8859-1')) - cmdret = self.json_recv() + + ready = select.select([self.socket], [], [], 600) + if ready[0]: + cmdret = self.json_recv() + else: + cmdret = None if cmdret == None: raise SuricataReturnException("Unable to get message from server") From d66fa1add1137791e0d323b55649f2f13aeb52ac Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Jan 2015 18:44:23 +0100 Subject: [PATCH 0305/2553] detect: update detect engine management Update detect engine management to make it easier to reload the detect engine. Core of the new approach is a 'master' ctx, that keeps a list of one or more detect engines. The detect engines will not be passed to any thread directly, but instead will only be accessed through the detect engine thread contexts. As we can replace those atomically, replacing a detect engine becomes easier. Each thread keeps a reference to its detect context. When a detect engine is replaced or removed, it's added to a free list. Once its reference count reaches 0, it is freed. --- src/detect-engine.c | 446 +++++++++++++++++++++++++++++++++++++++----- src/detect-engine.h | 8 +- src/detect.h | 18 ++ src/suricata.c | 16 +- 4 files changed, 433 insertions(+), 55 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 9b2058ddb60a..b81fe74ef785 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -101,6 +101,8 @@ static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *, void *, vo static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *); +static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, NULL, NULL, }; + /* 2 - for each direction */ DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; @@ -443,6 +445,208 @@ void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, return; } +static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) +{ + SCEnter(); + + int i = 0; + int no_of_detect_tvs = 0; + ThreadVars *tv = NULL; + + SCLogNotice("rule reload starting"); + + /* count detect threads in use */ + SCMutexLock(&tv_root_lock); + tv = tv_root[TVT_PPT]; + while (tv) { + /* obtain the slots for this TV */ + TmSlot *slots = tv->tm_slots; + while (slots != NULL) { + TmModule *tm = TmModuleGetById(slots->tm_id); + + if (suricata_ctl_flags != 0) { + SCLogInfo("rule reload interupted by engine shutdown"); + SCMutexUnlock(&tv_root_lock); + return -1; + } + + if (!(tm->flags & TM_FLAG_DETECT_TM)) { + slots = slots->slot_next; + continue; + } + no_of_detect_tvs++; + break; + } + + tv = tv->next; + } + SCMutexUnlock(&tv_root_lock); + + if (no_of_detect_tvs == 0) { + return -1; + } + + /* prepare swap structures */ + DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs]; + DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs]; + ThreadVars *detect_tvs[no_of_detect_tvs]; + memset(old_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *))); + memset(new_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *))); + memset(detect_tvs, 0x00, (no_of_detect_tvs * sizeof(ThreadVars *))); + + /* start the process of swapping detect threads ctxs */ + + /* get reference to tv's and setup new_det_ctx array */ + SCMutexLock(&tv_root_lock); + tv = tv_root[TVT_PPT]; + while (tv) { + /* obtain the slots for this TV */ + TmSlot *slots = tv->tm_slots; + while (slots != NULL) { + TmModule *tm = TmModuleGetById(slots->tm_id); + + if (suricata_ctl_flags != 0) { + SCMutexUnlock(&tv_root_lock); + goto error; + } + + if (!(tm->flags & TM_FLAG_DETECT_TM)) { + slots = slots->slot_next; + continue; + } + + old_det_ctx[i] = SC_ATOMIC_GET(slots->slot_data); + detect_tvs[i] = tv; + TmEcode r = DetectEngineThreadCtxInitForLiveRuleSwap(tv, (void *)new_de_ctx, + (void **)&new_det_ctx[i]); + i++; + if (r == TM_ECODE_FAILED) { + SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init " + "failure in live rule swap. Let's get out of here"); + SCMutexUnlock(&tv_root_lock); + goto error; + } + SCLogDebug("live rule swap created new det_ctx - %p and de_ctx " + "- %p\n", new_det_ctx, new_de_ctx); + break; + } + + tv = tv->next; + } + BUG_ON(i != no_of_detect_tvs); + + /* atomicly replace the det_ctx data */ + i = 0; + tv = tv_root[TVT_PPT]; + while (tv) { + /* find the correct slot */ + TmSlot *slots = tv->tm_slots; + while (slots != NULL) { + if (suricata_ctl_flags != 0) { + return -1; + } + + TmModule *tm = TmModuleGetById(slots->tm_id); + if (!(tm->flags & TM_FLAG_DETECT_TM)) { + slots = slots->slot_next; + continue; + } + SCLogDebug("swapping new det_ctx - %p with older one - %p", + new_det_ctx[i], SC_ATOMIC_GET(slots->slot_data)); + (void)SC_ATOMIC_SET(slots->slot_data, new_det_ctx[i++]); + break; + } + tv = tv->next; + } + SCMutexUnlock(&tv_root_lock); + + /* threads now all have new data, however they may not have started using + * it and may still use the old data */ + + SCLogInfo("Live rule swap has swapped %d old det_ctx's with new ones, " + "along with the new de_ctx", no_of_detect_tvs); + + /* inject a fake packet if the detect thread isn't using the new ctx yet, + * this speeds up the process */ + for (i = 0; i < no_of_detect_tvs; i++) { + int break_out = 0; + int pseudo_pkt_inserted = 0; + usleep(1000); + while (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) { + if (suricata_ctl_flags != 0) { + break_out = 1; + break; + } + + if (pseudo_pkt_inserted == 0) { + pseudo_pkt_inserted = 1; + if (detect_tvs[i]->inq != NULL) { + Packet *p = PacketGetFromAlloc(); + if (p != NULL) { + p->flags |= PKT_PSEUDO_STREAM_END; + PacketQueue *q = &trans_q[detect_tvs[i]->inq->id]; + SCMutexLock(&q->mutex_q); + PacketEnqueue(q, p); + SCCondSignal(&q->cond_q); + SCMutexUnlock(&q->mutex_q); + } + } + } + usleep(1000); + } + if (break_out) + break; + SCLogDebug("new_det_ctx - %p used by detect engine", new_det_ctx[i]); + } + + /* this is to make sure that if someone initiated shutdown during a live + * rule swap, the live rule swap won't clean up the old det_ctx and + * de_ctx, till all detect threads have stopped working and sitting + * silently after setting RUNNING_DONE flag and while waiting for + * THV_DEINIT flag */ + if (i != no_of_detect_tvs) { // not all threads we swapped + ThreadVars *tv = tv_root[TVT_PPT]; + while (tv) { + /* obtain the slots for this TV */ + TmSlot *slots = tv->tm_slots; + while (slots != NULL) { + TmModule *tm = TmModuleGetById(slots->tm_id); + if (!(tm->flags & TM_FLAG_DETECT_TM)) { + slots = slots->slot_next; + continue; + } + + while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + usleep(100); + } + + slots = slots->slot_next; + } + + tv = tv->next; + } + } + + /* free all the ctxs */ + for (i = 0; i < no_of_detect_tvs; i++) { + SCLogDebug("Freeing old_det_ctx - %p used by detect", + old_det_ctx[i]); + DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]); + } + + SRepReloadComplete(); + + SCLogNotice("rule reload complete"); + return 0; + + error: + for (i = 0; i < no_of_detect_tvs; i++) { + if (new_det_ctx[i] != NULL) + DetectEngineThreadCtxDeinit(NULL, new_det_ctx[i]); + } + return -1; +} + static void *DetectEngineLiveRuleSwap(void *arg) { SCEnter(); @@ -762,36 +966,6 @@ void DetectEngineSpawnLiveRuleSwapMgmtThread(void) SCReturn; } -DetectEngineCtx *DetectEngineGetGlobalDeCtx(void) -{ - DetectEngineCtx *de_ctx = NULL; - - SCMutexLock(&tv_root_lock); - - ThreadVars *tv = tv_root[TVT_PPT]; - while (tv) { - /* obtain the slots for this TV */ - TmSlot *slots = tv->tm_slots; - while (slots != NULL) { - TmModule *tm = TmModuleGetById(slots->tm_id); - - if (tm->flags & TM_FLAG_DETECT_TM) { - DetectEngineThreadCtx *det_ctx = SC_ATOMIC_GET(slots->slot_data); - de_ctx = det_ctx->de_ctx; - SCMutexUnlock(&tv_root_lock); - return de_ctx; - } - - slots = slots->slot_next; - } - - tv = tv->next; - } - - SCMutexUnlock(&tv_root_lock); - return NULL; -} - DetectEngineCtx *DetectEngineCtxInit(void) { DetectEngineCtx *de_ctx; @@ -1363,10 +1537,6 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * */ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) { - DetectEngineCtx *de_ctx = (DetectEngineCtx *)initdata; - if (de_ctx == NULL) - return TM_ECODE_FAILED; - /* first register the counter. In delayed detect mode we exit right after if the * rules haven't been loaded yet. */ uint16_t counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, @@ -1381,21 +1551,22 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) uint16_t counter_match_list = SCPerfTVRegisterAvgCounter("detect.match_list", tv, SC_PERF_TYPE_UINT64, "NULL"); #endif - if (de_ctx->delayed_detect == 1 && de_ctx->delayed_detect_initialized == 0) { - *data = NULL; - return TM_ECODE_OK; - } - DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); if (unlikely(det_ctx == NULL)) return TM_ECODE_FAILED; memset(det_ctx, 0, sizeof(DetectEngineThreadCtx)); det_ctx->tv = tv; - det_ctx->de_ctx = de_ctx; + det_ctx->de_ctx = DetectEngineGetCurrent(); + if (det_ctx->de_ctx == NULL) { + DetectEngineThreadCtxDeinit(tv, det_ctx); + return TM_ECODE_FAILED; + } - if (ThreadCtxDoInit(de_ctx, det_ctx) != TM_ECODE_OK) + if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) { + DetectEngineThreadCtxDeinit(tv, det_ctx); return TM_ECODE_FAILED; + } /** alert counter setup */ det_ctx->counter_alerts = counter_alerts; @@ -1423,19 +1594,18 @@ static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *tv, void *in { *data = NULL; - DetectEngineCtx *de_ctx = (DetectEngineCtx *)initdata; - if (de_ctx == NULL) - return TM_ECODE_FAILED; - DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); if (unlikely(det_ctx == NULL)) return TM_ECODE_FAILED; memset(det_ctx, 0, sizeof(DetectEngineThreadCtx)); det_ctx->tv = tv; - det_ctx->de_ctx = de_ctx; + det_ctx->de_ctx = DetectEngineGetCurrent(); + if (det_ctx->de_ctx == NULL) { + return TM_ECODE_FAILED; + } - if (ThreadCtxDoInit(de_ctx, det_ctx) != TM_ECODE_OK) + if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) return TM_ECODE_FAILED; /** alert counter setup */ @@ -1535,6 +1705,7 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) } DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx); + DetectEngineDeReference(&det_ctx->de_ctx); SCFree(det_ctx); return TM_ECODE_OK; @@ -1611,6 +1782,187 @@ void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) return det_ctx->keyword_ctxs_array[id]; } +DetectEngineCtx *DetectEngineGetCurrent(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->list == NULL) { + SCMutexUnlock(&master->lock); + return NULL; + } + + master->list->ref_cnt++; + SCLogDebug("master->list %p ref_cnt %u", master->list, master->list->ref_cnt); + SCMutexUnlock(&master->lock); + return master->list; +} + +void DetectEngineDeReference(DetectEngineCtx **de_ctx) +{ + BUG_ON((*de_ctx)->ref_cnt == 0); + (*de_ctx)->ref_cnt--; + *de_ctx = NULL; +} + +static int DetectEngineAddToList(DetectEngineCtx *instance) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + + if (instance == NULL) + return -1; + + if (master->list == NULL) { + master->list = instance; + } else { + instance->next = master->list; + master->list = instance; + } + + return 0; +} + +int DetectEngineAddToMaster(DetectEngineCtx *de_ctx) +{ + int r; + + if (de_ctx == NULL) + return -1; + + SCLogDebug("adding de_ctx %p to master", de_ctx); + + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + r = DetectEngineAddToList(de_ctx); + SCMutexUnlock(&master->lock); + return r; +} + +int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + + SCMutexLock(&master->lock); + DetectEngineCtx *instance = master->list; + if (instance == NULL) { + SCMutexUnlock(&master->lock); + return -1; + } + + /* remove from active list */ + if (instance == de_ctx) { + master->list = instance->next; + } else { + DetectEngineCtx *prev = instance; + instance = instance->next; /* already checked first element */ + + while (instance) { + DetectEngineCtx *next = instance->next; + + if (instance == de_ctx) { + prev->next = instance->next; + break; + } + + prev = instance; + instance = next; + } + if (instance == NULL) { + SCMutexUnlock(&master->lock); + return -1; + } + } + + /* instance is now detached from list */ + instance->next = NULL; + + /* add to free list */ + if (master->free_list == NULL) { + master->free_list = instance; + } else { + instance->next = master->free_list; + master->free_list = instance; + } + SCLogDebug("detect engine %p moved to free list (%u refs)", de_ctx, de_ctx->ref_cnt); + + SCMutexUnlock(&master->lock); + return 0; +} + +void DetectEnginePruneFreeList(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + DetectEngineCtx *prev = NULL; + DetectEngineCtx *instance = master->free_list; + while (instance) { + DetectEngineCtx *next = instance->next; + + SCLogDebug("detect engine %p has %u ref(s)", instance, instance->ref_cnt); + + if (instance->ref_cnt == 0) { + if (prev == NULL) { + master->free_list = next; + } else { + prev->next = next; + } + + SCLogDebug("freeing detect engine %p", instance); + DetectEngineCtxFree(instance); + instance = NULL; + } + + prev = instance; + instance = next; + } + SCMutexUnlock(&master->lock); +} + +int DetectEngineReload(void) +{ + DetectEngineCtx *new_de_ctx = NULL; + DetectEngineCtx *old_de_ctx = NULL; + + /* get a reference to the current de_ctx */ + old_de_ctx = DetectEngineGetCurrent(); + if (old_de_ctx == NULL) + return -1; + SCLogDebug("get ref to old_de_ctx %p", old_de_ctx); + + /* get new detection engine */ + new_de_ctx = DetectEngineCtxInit(); + if (new_de_ctx == NULL) { + DetectEngineDeReference(&old_de_ctx); + return -1; + } + if (SigLoadSignatures(new_de_ctx, NULL, 0) != 0) { + DetectEngineCtxFree(new_de_ctx); + DetectEngineDeReference(&old_de_ctx); + return -1; + } + SCThresholdConfInitContext(new_de_ctx, NULL); + SCLogDebug("set up new_de_ctx %p", new_de_ctx); + + /* add to master */ + DetectEngineAddToMaster(new_de_ctx); + + /* move to old free list */ + DetectEngineMoveToFreeList(old_de_ctx); + DetectEngineDeReference(&old_de_ctx); + + SCLogDebug("going to reload the threads to use new_de_ctx %p", new_de_ctx); + /* update the threads */ + DetectEngineReloadThreads(new_de_ctx); + SCLogDebug("threads now run new_de_ctx %p", new_de_ctx); + + /* walk free list, freeing the old_de_ctx */ + DetectEnginePruneFreeList(); + + SCLogDebug("old_de_ctx should have been freed"); + return 0; +} + const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) { switch (type) { diff --git a/src/detect-engine.h b/src/detect-engine.h index 73b3554f20ff..14c6e6f18fd7 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -57,7 +57,6 @@ extern DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT void DetectEngineRegisterAppInspectionEngines(void); void DetectEngineSpawnLiveRuleSwapMgmtThread(void); DetectEngineCtx *DetectEngineCtxInit(void); -DetectEngineCtx *DetectEngineGetGlobalDeCtx(void); void DetectEngineCtxFree(DetectEngineCtx *); TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **); @@ -69,6 +68,13 @@ void DetectEngineResetMaxSigId(DetectEngineCtx *); void DetectEngineRegisterTests(void); const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type); +int DetectEngineAddToMaster(DetectEngineCtx *de_ctx); +DetectEngineCtx *DetectEngineGetCurrent(void); +void DetectEnginePruneFreeList(void); +int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx); +void DetectEngineDeReference(DetectEngineCtx **de_ctx); +int DetectEngineReload(void); + /** * \brief Registers an app inspection engine. * diff --git a/src/detect.h b/src/detect.h index 03658e42aa47..a5cd359ddb1b 100644 --- a/src/detect.h +++ b/src/detect.h @@ -736,6 +736,11 @@ typedef struct DetectEngineCtx_ { struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx; struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; #endif + + /** how many de_ctx' are referencing this */ + uint32_t ref_cnt; + /** list in master: either active or freelist */ + struct DetectEngineCtx_ *next; } DetectEngineCtx; /* Engine groups profiles (low, medium, high, custom) */ @@ -1041,6 +1046,19 @@ typedef struct SigGroupHead_ { * deal with both cases */ #define SIGMATCH_OPTIONAL_OPT (1 << 5) +typedef struct DetectEngineMasterCtx_ { + SCMutex lock; + + /** 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; +} DetectEngineMasterCtx; + /** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a signature group */ enum { diff --git a/src/suricata.c b/src/suricata.c index 12458caf70e8..96a61b819038 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2307,6 +2307,7 @@ int main(int argc, char **argv) "context failed."); exit(EXIT_FAILURE); } + #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) CudaVarsSetDeCtx(de_ctx); @@ -2332,6 +2333,7 @@ int main(int argc, char **argv) if (suri.run_mode == RUNMODE_ENGINE_ANALYSIS) { exit(EXIT_SUCCESS); } + DetectEngineAddToMaster(de_ctx); } } @@ -2482,11 +2484,6 @@ int main(int argc, char **argv) } } - DetectEngineCtx *global_de_ctx = DetectEngineGetGlobalDeCtx(); - if (suri.run_mode != RUNMODE_UNIX_SOCKET && de_ctx != NULL) { - BUG_ON(global_de_ctx == NULL); - } - /* before TmThreadKillThreads, as otherwise that kills it * but more slowly */ if (suri.run_mode != RUNMODE_UNIX_SOCKET) { @@ -2517,9 +2514,14 @@ int main(int argc, char **argv) AppLayerHtpPrintStats(); - if (global_de_ctx) { - DetectEngineCtxFree(global_de_ctx); + /** TODO this can do into it's own func */ + de_ctx = DetectEngineGetCurrent(); + if (de_ctx) { + DetectEngineMoveToFreeList(de_ctx); + DetectEngineDeReference(&de_ctx); } + DetectEnginePruneFreeList(); + AppLayerDeSetup(); TagDestroyCtx(); From b038b6a2f87549474503ff80c2e5586ccd02c92d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 20 Jan 2015 11:25:02 +0100 Subject: [PATCH 0306/2553] unittests: add exception to detect engine setup Add code to allow for unittests not following the complete api. Update replace tests as they don't use the unittests runmode that powers the workaround based on RunmodeIsUnittests(). --- src/detect-engine.c | 14 ++++++++++++++ src/detect-replace.c | 15 ++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index b81fe74ef785..7e0f57138aff 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1559,8 +1559,17 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) det_ctx->tv = tv; det_ctx->de_ctx = DetectEngineGetCurrent(); if (det_ctx->de_ctx == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests()) { + det_ctx->de_ctx = (DetectEngineCtx *)initdata; + } else { + DetectEngineThreadCtxDeinit(tv, det_ctx); + return TM_ECODE_FAILED; + } +#else DetectEngineThreadCtxDeinit(tv, det_ctx); return TM_ECODE_FAILED; +#endif } if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) { @@ -1705,7 +1714,12 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) } DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx); +#ifdef UNITTESTS + if (!RunmodeIsUnittests() || det_ctx->de_ctx->ref_cnt > 0) + DetectEngineDeReference(&det_ctx->de_ctx); +#else DetectEngineDeReference(&det_ctx->de_ctx); +#endif SCFree(det_ctx); return TM_ECODE_OK; diff --git a/src/detect-replace.c b/src/detect-replace.c index 6031c31184f6..3bf725a992e1 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -261,9 +261,11 @@ int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, ch } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineAddToMaster(de_ctx); + DetectEngineThreadCtxInit(&th_v, NULL, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + DetectEngineMoveToFreeList(de_ctx); if (PacketAlertCheck(p, sid) != 1) { SCLogDebug("replace: no alert on sig %d", sid); @@ -281,14 +283,9 @@ int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, ch end: if (dtv.app_tctx != NULL) AppLayerDestroyCtxThread(dtv.app_tctx); - if (de_ctx != NULL) - { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEnginePruneFreeList(); PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); From 38b349af1e8c3e1b85dcb5ba2708ceb7f164f402 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Jan 2015 10:27:34 +0100 Subject: [PATCH 0307/2553] runmodes: remove DetectEngineCtx passing from API No longer pass a pointer to the current detection engine to the runmode API calls. Note: breaks delayed detect. Will be fixed in a future commit. --- src/detect-engine.c | 16 ++++++++++++ src/detect-engine.h | 1 + src/runmode-af-packet.c | 23 ++++++------------ src/runmode-af-packet.h | 7 +++--- src/runmode-erf-dag.c | 22 ++++++----------- src/runmode-erf-dag.h | 6 ++--- src/runmode-erf-file.c | 19 ++++++--------- src/runmode-erf-file.h | 4 +-- src/runmode-ipfw.c | 17 +++---------- src/runmode-ipfw.h | 5 ++-- src/runmode-napatech.c | 20 ++++++--------- src/runmode-napatech.h | 5 ++-- src/runmode-netmap.c | 12 ++++----- src/runmode-netmap.h | 6 ++--- src/runmode-nflog.c | 15 +++++------- src/runmode-nflog.h | 6 ++--- src/runmode-nfq.c | 17 +++---------- src/runmode-nfq.h | 5 ++-- src/runmode-pcap-file.c | 22 ++++++----------- src/runmode-pcap-file.h | 5 ++-- src/runmode-pcap.c | 26 ++++++-------------- src/runmode-pcap.h | 5 ++-- src/runmode-pfring.c | 22 +++++------------ src/runmode-pfring.h | 7 +++--- src/runmode-tile.c | 13 +++------- src/runmode-tile.h | 2 +- src/runmode-unix-socket.c | 18 ++++---------- src/runmode-unix-socket.h | 2 +- src/runmodes.c | 10 +++----- src/runmodes.h | 4 +-- src/suricata.c | 4 +-- src/unix-manager.c | 3 +-- src/unix-manager.h | 2 +- src/util-runmodes.c | 51 +++++++++++++++------------------------ src/util-runmodes.h | 24 +++++------------- 35 files changed, 159 insertions(+), 267 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 7e0f57138aff..8abf373de29f 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1796,6 +1796,22 @@ void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) return det_ctx->keyword_ctxs_array[id]; } +/** \brief Check if detection is enabled + * \retval bool true or false */ +int DetectEngineEnabled(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->list == NULL) { + SCMutexUnlock(&master->lock); + return 0; + } + + SCMutexUnlock(&master->lock); + return 1; +} + DetectEngineCtx *DetectEngineGetCurrent(void) { DetectEngineMasterCtx *master = &g_master_de_ctx; diff --git a/src/detect-engine.h b/src/detect-engine.h index 14c6e6f18fd7..1b6d55398415 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -74,6 +74,7 @@ void DetectEnginePruneFreeList(void); int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx); void DetectEngineDeReference(DetectEngineCtx **de_ctx); int DetectEngineReload(void); +int DetectEngineEnabled(void); /** * \brief Registers an app inspection engine. diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 29817d22be30..3a20cd09b3f0 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -433,7 +433,7 @@ int AFPRunModeIsIPS() return has_ips; } -int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) +int RunModeIdsAFPAutoFp(void) { SCEnter(); @@ -455,8 +455,7 @@ int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureAutoFp(de_ctx, - ParseAFPConfig, + ret = RunModeSetLiveCaptureAutoFp(ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", "DecodeAFP", "RxAFP", @@ -481,14 +480,12 @@ int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) /** * \brief Single thread version of the AF_PACKET processing. */ -int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx) +int RunModeIdsAFPSingle(void) { + SCEnter(); #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; -#endif - SCEnter(); -#ifdef HAVE_AF_PACKET RunModeInitialize(); TimeModeSetLive(); @@ -500,8 +497,7 @@ int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureSingle(de_ctx, - ParseAFPConfig, + ret = RunModeSetLiveCaptureSingle(ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", "DecodeAFP", "AFPacket", @@ -529,14 +525,12 @@ int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx) * Start N threads with each thread doing all the work. * */ -int RunModeIdsAFPWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsAFPWorkers(void) { + SCEnter(); #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; -#endif - SCEnter(); -#ifdef HAVE_AF_PACKET RunModeInitialize(); TimeModeSetLive(); @@ -548,8 +542,7 @@ int RunModeIdsAFPWorkers(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureWorkers(de_ctx, - ParseAFPConfig, + ret = RunModeSetLiveCaptureWorkers(ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", "DecodeAFP", "AFPacket", diff --git a/src/runmode-af-packet.h b/src/runmode-af-packet.h index 0e1c764dd764..79fe436a692f 100644 --- a/src/runmode-af-packet.h +++ b/src/runmode-af-packet.h @@ -23,10 +23,9 @@ #ifndef __RUNMODE_AF_PACKET_H__ #define __RUNMODE_AF_PACKET_H__ -int RunModeIdsAFPAuto(DetectEngineCtx *); -int RunModeIdsAFPSingle(DetectEngineCtx *); -int RunModeIdsAFPAutoFp(DetectEngineCtx *); -int RunModeIdsAFPWorkers(DetectEngineCtx *); +int RunModeIdsAFPSingle(void); +int RunModeIdsAFPAutoFp(void); +int RunModeIdsAFPWorkers(void); void RunModeIdsAFPRegister(void); const char *RunModeAFPGetDefaultMode(void); int AFPRunModeIsIPS(); diff --git a/src/runmode-erf-dag.c b/src/runmode-erf-dag.c index 4fa9a6fccb92..5653b9ecfbe0 100644 --- a/src/runmode-erf-dag.c +++ b/src/runmode-erf-dag.c @@ -20,14 +20,9 @@ #include "conf.h" #include "runmodes.h" #include "runmode-erf-dag.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" +#include "detect-engine.h" #include "util-debug.h" #include "util-time.h" @@ -76,7 +71,7 @@ void RunModeErfDagRegister(void) return; } -int RunModeIdsErfDagSingle(DetectEngineCtx *de_ctx) +int RunModeIdsErfDagSingle(void) { int ret; @@ -86,8 +81,7 @@ int RunModeIdsErfDagSingle(DetectEngineCtx *de_ctx) TimeModeSetLive(); - ret = RunModeSetLiveCaptureSingle(de_ctx, - ParseDagConfig, + ret = RunModeSetLiveCaptureSingle(ParseDagConfig, DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", @@ -103,7 +97,7 @@ int RunModeIdsErfDagSingle(DetectEngineCtx *de_ctx) SCReturnInt(0); } -int RunModeIdsErfDagAutoFp(DetectEngineCtx *de_ctx) +int RunModeIdsErfDagAutoFp(void) { int ret; @@ -113,8 +107,7 @@ int RunModeIdsErfDagAutoFp(DetectEngineCtx *de_ctx) TimeModeSetLive(); - ret = RunModeSetLiveCaptureAutoFp(de_ctx, - ParseDagConfig, + ret = RunModeSetLiveCaptureAutoFp(ParseDagConfig, DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", @@ -130,7 +123,7 @@ int RunModeIdsErfDagAutoFp(DetectEngineCtx *de_ctx) SCReturnInt(0); } -int RunModeIdsErfDagWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsErfDagWorkers(void) { int ret; @@ -140,8 +133,7 @@ int RunModeIdsErfDagWorkers(DetectEngineCtx *de_ctx) TimeModeSetLive(); - ret = RunModeSetLiveCaptureWorkers(de_ctx, - ParseDagConfig, + ret = RunModeSetLiveCaptureWorkers(ParseDagConfig, DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", diff --git a/src/runmode-erf-dag.h b/src/runmode-erf-dag.h index 2a4b20ea520c..c4b2a59cee5e 100644 --- a/src/runmode-erf-dag.h +++ b/src/runmode-erf-dag.h @@ -23,9 +23,9 @@ #ifndef __RUNMODE_ERF_DAG_H__ #define __RUNMODE_ERF_DAG_H__ -int RunModeIdsErfDagAutoFp(DetectEngineCtx *); -int RunModeIdsErfDagSingle(DetectEngineCtx *); -int RunModeIdsErfDagWorkers(DetectEngineCtx *); +int RunModeIdsErfDagAutoFp(void); +int RunModeIdsErfDagSingle(void); +int RunModeIdsErfDagWorkers(void); void RunModeErfDagRegister(void); const char *RunModeErfDagGetDefaultMode(void); diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index 50f47669d017..ef7d2e09ec9c 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -20,14 +20,9 @@ #include "conf.h" #include "runmodes.h" #include "runmode-erf-file.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" +#include "detect-engine.h" #include "util-debug.h" #include "util-time.h" @@ -59,7 +54,7 @@ void RunModeErfFileRegister(void) return; } -int RunModeErfFileSingle(DetectEngineCtx *de_ctx) +int RunModeErfFileSingle(void) { char *file; @@ -106,13 +101,13 @@ int RunModeErfFileSingle(DetectEngineCtx *de_ctx) } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (de_ctx != NULL) { + if (DetectEngineEnabled()) { tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName Detect failed\n"); exit(EXIT_FAILURE); } - TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); + TmSlotSetFuncAppend(tv, tm_module, NULL); } SetupOutputs(tv); @@ -127,7 +122,7 @@ int RunModeErfFileSingle(DetectEngineCtx *de_ctx) SCReturnInt(0); } -int RunModeErfFileAutoFp(DetectEngineCtx *de_ctx) +int RunModeErfFileAutoFp(void) { SCEnter(); char tname[TM_THREAD_NAME_MAX]; @@ -235,13 +230,13 @@ int RunModeErfFileAutoFp(DetectEngineCtx *de_ctx) } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (de_ctx != NULL) { + if (DetectEngineEnabled()) { tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName Detect failed\n"); exit(EXIT_FAILURE); } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); + TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); } if (threading_set_cpu_affinity) { diff --git a/src/runmode-erf-file.h b/src/runmode-erf-file.h index 0612e9fa436c..54a8ba8972fa 100644 --- a/src/runmode-erf-file.h +++ b/src/runmode-erf-file.h @@ -23,8 +23,8 @@ #ifndef __RUNMODE_ERF_FILE_H__ #define __RUNMODE_ERF_FILE_H__ -int RunModeErfFileSingle(DetectEngineCtx *); -int RunModeErfFileAutoFp(DetectEngineCtx *); +int RunModeErfFileSingle(void); +int RunModeErfFileAutoFp(void); void RunModeErfFileRegister(void); const char *RunModeErfFileGetDefaultMode(void); diff --git a/src/runmode-ipfw.c b/src/runmode-ipfw.c index 03bb02e55fb8..841692e1166b 100644 --- a/src/runmode-ipfw.c +++ b/src/runmode-ipfw.c @@ -31,14 +31,7 @@ #include "conf.h" #include "runmodes.h" #include "runmode-ipfw.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" - -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" @@ -70,7 +63,7 @@ void RunModeIpsIPFWRegister(void) return; } -int RunModeIpsIPFWAutoFp(DetectEngineCtx *de_ctx) +int RunModeIpsIPFWAutoFp(void) { SCEnter(); int ret = 0; @@ -82,8 +75,7 @@ int RunModeIpsIPFWAutoFp(DetectEngineCtx *de_ctx) LiveDeviceHasNoStats(); - ret = RunModeSetIPSAutoFp(de_ctx, - IPFWGetThread, + ret = RunModeSetIPSAutoFp(IPFWGetThread, "ReceiveIPFW", "VerdictIPFW", "DecodeIPFW"); @@ -91,7 +83,7 @@ int RunModeIpsIPFWAutoFp(DetectEngineCtx *de_ctx) return ret; } -int RunModeIpsIPFWWorker(DetectEngineCtx *de_ctx) +int RunModeIpsIPFWWorker(void) { SCEnter(); int ret = 0; @@ -103,8 +95,7 @@ int RunModeIpsIPFWWorker(DetectEngineCtx *de_ctx) LiveDeviceHasNoStats(); - ret = RunModeSetIPSWorker(de_ctx, - IPFWGetThread, + ret = RunModeSetIPSWorker(IPFWGetThread, "ReceiveIPFW", "VerdictIPFW", "DecodeIPFW"); diff --git a/src/runmode-ipfw.h b/src/runmode-ipfw.h index 92fae6b8ad32..5c8345b17455 100644 --- a/src/runmode-ipfw.h +++ b/src/runmode-ipfw.h @@ -23,9 +23,8 @@ #ifndef __RUNMODE_IPFW_H__ #define __RUNMODE_IPFW_H__ -int RunModeIpsIPFWAuto(DetectEngineCtx *); -int RunModeIpsIPFWAutoFp(DetectEngineCtx *); -int RunModeIpsIPFWWorker(DetectEngineCtx *); +int RunModeIpsIPFWAutoFp(void); +int RunModeIpsIPFWWorker(void); void RunModeIpsIPFWRegister(void); const char *RunModeIpsIPFWGetDefaultMode(void); diff --git a/src/runmode-napatech.c b/src/runmode-napatech.c index 0c9be2a233d3..7c161ad864ae 100644 --- a/src/runmode-napatech.c +++ b/src/runmode-napatech.c @@ -25,14 +25,8 @@ #include "tm-threads.h" #include "conf.h" #include "runmodes.h" -#include "log-httplog.h" #include "output.h" -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" - #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" @@ -185,7 +179,7 @@ int NapatechGetThreadsCount(void *conf __attribute__((unused))) { return 1; } -int NapatechInit(DetectEngineCtx *de_ctx, int runmode) +static int NapatechInit(int runmode) { int ret; char errbuf[100]; @@ -208,12 +202,12 @@ int NapatechInit(DetectEngineCtx *de_ctx, int runmode) switch(runmode) { case NT_RUNMODE_AUTOFP: - ret = RunModeSetLiveCaptureAutoFp(de_ctx, NapatechConfigParser, NapatechGetThreadsCount, + ret = RunModeSetLiveCaptureAutoFp(NapatechConfigParser, NapatechGetThreadsCount, "NapatechStream", "NapatechDecode", "RxNT", NULL); break; case NT_RUNMODE_WORKERS: - ret = RunModeSetLiveCaptureWorkers(de_ctx, NapatechConfigParser, NapatechGetThreadsCount, + ret = RunModeSetLiveCaptureWorkers(NapatechConfigParser, NapatechGetThreadsCount, "NapatechStream", "NapatechDecode", "RxNT", NULL); break; @@ -228,14 +222,14 @@ int NapatechInit(DetectEngineCtx *de_ctx, int runmode) return 0; } -int RunModeNapatechAutoFp(DetectEngineCtx *de_ctx) +int RunModeNapatechAutoFp(void) { - return NapatechInit(de_ctx, NT_RUNMODE_AUTOFP); + return NapatechInit(NT_RUNMODE_AUTOFP); } -int RunModeNapatechWorkers(DetectEngineCtx *de_ctx) +int RunModeNapatechWorkers(void) { - return NapatechInit(de_ctx, NT_RUNMODE_WORKERS); + return NapatechInit(NT_RUNMODE_WORKERS); } #endif diff --git a/src/runmode-napatech.h b/src/runmode-napatech.h index ffb1d42efe09..d10b406376d0 100644 --- a/src/runmode-napatech.h +++ b/src/runmode-napatech.h @@ -29,9 +29,8 @@ #include #endif -int RunModeNapatechAuto(DetectEngineCtx *); -int RunModeNapatechAutoFp(DetectEngineCtx *); -int RunModeNapatechWorkers(DetectEngineCtx *); +int RunModeNapatechAutoFp(void); +int RunModeNapatechWorkers(void); void RunModeNapatechRegister(void); const char *RunModeNapatechGetDefaultMode(void); diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index f5172aba1aeb..3639bef92e39 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -332,7 +332,7 @@ int NetmapRunModeIsIPS() #endif // #ifdef HAVE_NETMAP -int RunModeIdsNetmapAutoFp(DetectEngineCtx *de_ctx) +int RunModeIdsNetmapAutoFp(void) { SCEnter(); @@ -348,7 +348,7 @@ int RunModeIdsNetmapAutoFp(DetectEngineCtx *de_ctx) SCLogDebug("live_dev %s", live_dev); - ret = RunModeSetLiveCaptureAutoFp(de_ctx, + ret = RunModeSetLiveCaptureAutoFp( ParseNetmapConfig, NetmapConfigGeThreadsCount, "ReceiveNetmap", @@ -368,7 +368,7 @@ int RunModeIdsNetmapAutoFp(DetectEngineCtx *de_ctx) /** * \brief Single thread version of the netmap processing. */ -int RunModeIdsNetmapSingle(DetectEngineCtx *de_ctx) +int RunModeIdsNetmapSingle(void) { SCEnter(); @@ -381,7 +381,7 @@ int RunModeIdsNetmapSingle(DetectEngineCtx *de_ctx) (void)ConfGet("netmap.live-interface", &live_dev); - ret = RunModeSetLiveCaptureSingle(de_ctx, + ret = RunModeSetLiveCaptureSingle( ParseNetmapConfig, NetmapConfigGeThreadsCount, "ReceiveNetmap", @@ -404,7 +404,7 @@ int RunModeIdsNetmapSingle(DetectEngineCtx *de_ctx) * Start N threads with each thread doing all the work. * */ -int RunModeIdsNetmapWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsNetmapWorkers(void) { SCEnter(); @@ -417,7 +417,7 @@ int RunModeIdsNetmapWorkers(DetectEngineCtx *de_ctx) (void)ConfGet("netmap.live-interface", &live_dev); - ret = RunModeSetLiveCaptureWorkers(de_ctx, + ret = RunModeSetLiveCaptureWorkers( ParseNetmapConfig, NetmapConfigGeThreadsCount, "ReceiveNetmap", diff --git a/src/runmode-netmap.h b/src/runmode-netmap.h index 392e9781ca07..988c349ab5a2 100644 --- a/src/runmode-netmap.h +++ b/src/runmode-netmap.h @@ -23,9 +23,9 @@ #ifndef __RUNMODE_NETMAP_H__ #define __RUNMODE_NETMAP_H__ -int RunModeIdsNetmapSingle(DetectEngineCtx *); -int RunModeIdsNetmapAutoFp(DetectEngineCtx *); -int RunModeIdsNetmapWorkers(DetectEngineCtx *); +int RunModeIdsNetmapSingle(void); +int RunModeIdsNetmapAutoFp(void); +int RunModeIdsNetmapWorkers(void); void RunModeIdsNetmapRegister(void); const char *RunModeNetmapGetDefaultMode(void); int NetmapRunModeIsIPS(); diff --git a/src/runmode-nflog.c b/src/runmode-nflog.c index 17725622b5e8..9c08f9aef060 100644 --- a/src/runmode-nflog.c +++ b/src/runmode-nflog.c @@ -169,7 +169,7 @@ int NflogConfigGeThreadsCount(void *conf) return 1; } -int RunModeIdsNflogAutoFp(DetectEngineCtx *de_ctx) +int RunModeIdsNflogAutoFp(void) { SCEnter(); @@ -180,8 +180,7 @@ int RunModeIdsNflogAutoFp(DetectEngineCtx *de_ctx) RunModeInitialize(); TimeModeSetLive(); - ret = RunModeSetLiveCaptureAutoFp(de_ctx, - ParseNflogConfig, + ret = RunModeSetLiveCaptureAutoFp(ParseNflogConfig, NflogConfigGeThreadsCount, "ReceiveNFLOG", "DecodeNFLOG", @@ -198,7 +197,7 @@ int RunModeIdsNflogAutoFp(DetectEngineCtx *de_ctx) SCReturnInt(0); } -int RunModeIdsNflogSingle(DetectEngineCtx *de_ctx) +int RunModeIdsNflogSingle(void) { SCEnter(); @@ -209,8 +208,7 @@ int RunModeIdsNflogSingle(DetectEngineCtx *de_ctx) RunModeInitialize(); TimeModeSetLive(); - ret = RunModeSetLiveCaptureSingle(de_ctx, - ParseNflogConfig, + ret = RunModeSetLiveCaptureSingle(ParseNflogConfig, NflogConfigGeThreadsCount, "ReceiveNFLOG", "DecodeNFLOG", @@ -227,7 +225,7 @@ int RunModeIdsNflogSingle(DetectEngineCtx *de_ctx) SCReturnInt(0); } -int RunModeIdsNflogWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsNflogWorkers(void) { SCEnter(); @@ -238,8 +236,7 @@ int RunModeIdsNflogWorkers(DetectEngineCtx *de_ctx) RunModeInitialize(); TimeModeSetLive(); - ret = RunModeSetLiveCaptureWorkers(de_ctx, - ParseNflogConfig, + ret = RunModeSetLiveCaptureWorkers(ParseNflogConfig, NflogConfigGeThreadsCount, "ReceiveNFLOG", "DecodeNFLOG", diff --git a/src/runmode-nflog.h b/src/runmode-nflog.h index 2dd4e7a6358f..9c70c69397de 100644 --- a/src/runmode-nflog.h +++ b/src/runmode-nflog.h @@ -23,9 +23,9 @@ #ifndef __RUNMODE_NFLOG_H__ #define __RUNMODE_NFLOG_H__ -int RunModeIdsNflogAutoFp(DetectEngineCtx *); -int RunModeIdsNflogSingle(DetectEngineCtx *); -int RunModeIdsNflogWorkers(DetectEngineCtx *); +int RunModeIdsNflogAutoFp(void); +int RunModeIdsNflogSingle(void); +int RunModeIdsNflogWorkers(void); void RunModeIdsNflogRegister(void); const char *RunModeIdsNflogGetDefaultMode(void); diff --git a/src/runmode-nfq.c b/src/runmode-nfq.c index edf7bc7e553b..67fa5bcbe969 100644 --- a/src/runmode-nfq.c +++ b/src/runmode-nfq.c @@ -30,14 +30,7 @@ #include "conf.h" #include "runmodes.h" #include "runmode-nfq.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" - -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" @@ -66,7 +59,7 @@ void RunModeIpsNFQRegister(void) return; } -int RunModeIpsNFQAutoFp(DetectEngineCtx *de_ctx) +int RunModeIpsNFQAutoFp(void) { SCEnter(); int ret = 0; @@ -78,8 +71,7 @@ int RunModeIpsNFQAutoFp(DetectEngineCtx *de_ctx) LiveDeviceHasNoStats(); - ret = RunModeSetIPSAutoFp(de_ctx, - NFQGetThread, + ret = RunModeSetIPSAutoFp(NFQGetThread, "ReceiveNFQ", "VerdictNFQ", "DecodeNFQ"); @@ -87,7 +79,7 @@ int RunModeIpsNFQAutoFp(DetectEngineCtx *de_ctx) return ret; } -int RunModeIpsNFQWorker(DetectEngineCtx *de_ctx) +int RunModeIpsNFQWorker(void) { SCEnter(); int ret = 0; @@ -99,8 +91,7 @@ int RunModeIpsNFQWorker(DetectEngineCtx *de_ctx) LiveDeviceHasNoStats(); - ret = RunModeSetIPSWorker(de_ctx, - NFQGetThread, + ret = RunModeSetIPSWorker(NFQGetThread, "ReceiveNFQ", "VerdictNFQ", "DecodeNFQ"); diff --git a/src/runmode-nfq.h b/src/runmode-nfq.h index 677fff682bb4..6ad880146639 100644 --- a/src/runmode-nfq.h +++ b/src/runmode-nfq.h @@ -23,9 +23,8 @@ #ifndef __RUNMODE_NFQ_H__ #define __RUNMODE_NFQ_H__ -int RunModeIpsNFQAuto(DetectEngineCtx *); -int RunModeIpsNFQAutoFp(DetectEngineCtx *); -int RunModeIpsNFQWorker(DetectEngineCtx *); +int RunModeIpsNFQAutoFp(void); +int RunModeIpsNFQWorker(void); void RunModeIpsNFQRegister(void); const char *RunModeIpsNFQGetDefaultMode(void); diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index f5a3c196b40b..d337cb9711a7 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -20,17 +20,11 @@ #include "conf.h" #include "runmodes.h" #include "runmode-pcap-file.h" -#include "log-httplog.h" #include "output.h" -#include "detect-engine-mpm.h" +#include "detect-engine.h" #include "source-pcap-file.h" -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" - #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" @@ -65,7 +59,7 @@ void RunModeFilePcapRegister(void) /** * \brief Single thread version of the Pcap file processing. */ -int RunModeFilePcapSingle(DetectEngineCtx *de_ctx) +int RunModeFilePcapSingle(void) { char *file = NULL; if (ConfGet("pcap-file.file", &file) == 0) { @@ -109,13 +103,13 @@ int RunModeFilePcapSingle(DetectEngineCtx *de_ctx) } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (de_ctx) { + if (DetectEngineEnabled()) { tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } - TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); + TmSlotSetFuncAppend(tv, tm_module, NULL); } SetupOutputs(tv); @@ -142,12 +136,10 @@ int RunModeFilePcapSingle(DetectEngineCtx *de_ctx) * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * - * \param de_ctx Pointer to the Detection Engine - * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ -int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) +int RunModeFilePcapAutoFp(void) { SCEnter(); char tname[TM_THREAD_NAME_MAX]; @@ -253,13 +245,13 @@ int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (de_ctx) { + if (DetectEngineEnabled()) { tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); + TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); } char *thread_group_name = SCStrdup("Detect"); diff --git a/src/runmode-pcap-file.h b/src/runmode-pcap-file.h index 5dbd3a9c2631..52cab02228f0 100644 --- a/src/runmode-pcap-file.h +++ b/src/runmode-pcap-file.h @@ -23,9 +23,8 @@ #ifndef __RUNMODE_PCAP_FILE_H__ #define __RUNMODE_PCAP_FILE_H__ -int RunModeFilePcapSingle(DetectEngineCtx *); -int RunModeFilePcapAuto(DetectEngineCtx *); -int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx); +int RunModeFilePcapSingle(void); +int RunModeFilePcapAutoFp(void); void RunModeFilePcapRegister(void); const char *RunModeFilePcapGetDefaultMode(void); diff --git a/src/runmode-pcap.c b/src/runmode-pcap.c index 17d9e692ee5c..6561c1c8c4c8 100644 --- a/src/runmode-pcap.c +++ b/src/runmode-pcap.c @@ -22,13 +22,6 @@ #include "runmode-pcap.h" #include "log-httplog.h" #include "output.h" -#include "source-pfring.h" -#include "detect-engine-mpm.h" - -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" @@ -46,7 +39,7 @@ const char *RunModeIdsGetDefaultMode(void) return default_mode; } -int RunModeIdsPcapWorkers(DetectEngineCtx *de_ctx); +int RunModeIdsPcapWorkers(void); void RunModeIdsPcapRegister(void) { @@ -234,7 +227,7 @@ int PcapConfigGeThreadsCount(void *conf) /** * \brief Single thread version of the Pcap live processing. */ -int RunModeIdsPcapSingle(DetectEngineCtx *de_ctx) +int RunModeIdsPcapSingle(void) { int ret; char *live_dev = NULL; @@ -246,8 +239,7 @@ int RunModeIdsPcapSingle(DetectEngineCtx *de_ctx) (void)ConfGet("pcap.single-pcap-dev", &live_dev); - ret = RunModeSetLiveCaptureSingle(de_ctx, - ParsePcapConfig, + ret = RunModeSetLiveCaptureSingle(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", "DecodePcap", "PcapLive", @@ -274,12 +266,10 @@ int RunModeIdsPcapSingle(DetectEngineCtx *de_ctx) * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * - * \param de_ctx Pointer to the Detection Engine - * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ -int RunModeIdsPcapAutoFp(DetectEngineCtx *de_ctx) +int RunModeIdsPcapAutoFp(void) { int ret; char *live_dev = NULL; @@ -290,8 +280,7 @@ int RunModeIdsPcapAutoFp(DetectEngineCtx *de_ctx) (void) ConfGet("pcap.single-pcap-dev", &live_dev); - ret = RunModeSetLiveCaptureAutoFp(de_ctx, - ParsePcapConfig, + ret = RunModeSetLiveCaptureAutoFp(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", "DecodePcap", "RxPcap", @@ -312,7 +301,7 @@ int RunModeIdsPcapAutoFp(DetectEngineCtx *de_ctx) * Start N threads with each thread doing all the work. * */ -int RunModeIdsPcapWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsPcapWorkers(void) { int ret; char *live_dev = NULL; @@ -323,8 +312,7 @@ int RunModeIdsPcapWorkers(DetectEngineCtx *de_ctx) (void) ConfGet("pcap.single-pcap-dev", &live_dev); - ret = RunModeSetLiveCaptureWorkers(de_ctx, - ParsePcapConfig, + ret = RunModeSetLiveCaptureWorkers(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", "DecodePcap", "RxPcap", diff --git a/src/runmode-pcap.h b/src/runmode-pcap.h index 9e88c6d90f8b..b68c6ddcfc7f 100644 --- a/src/runmode-pcap.h +++ b/src/runmode-pcap.h @@ -23,9 +23,8 @@ #ifndef __RUNMODE_PCAP_H__ #define __RUNMODE_PCAP_H__ -int RunModeIdsPcapAuto(DetectEngineCtx *); -int RunModeIdsPcapSingle(DetectEngineCtx *); -int RunModeIdsPcapAutoFp(DetectEngineCtx *de_ctx); +int RunModeIdsPcapSingle(void); +int RunModeIdsPcapAutoFp(void); void RunModeIdsPcapRegister(void); const char *RunModeIdsGetDefaultMode(void); diff --git a/src/runmode-pfring.c b/src/runmode-pfring.c index 21c22fc2e6b0..8c9a06fde422 100644 --- a/src/runmode-pfring.c +++ b/src/runmode-pfring.c @@ -21,14 +21,7 @@ #include "runmodes.h" #include "runmode-pfring.h" #include "source-pfring.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" - -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" @@ -418,7 +411,7 @@ static int GetDevAndParser(char **live_dev, ConfigIfaceParserFunc *parser) } #endif -int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx) +int RunModeIdsPfringAutoFp(void) { SCEnter(); @@ -439,8 +432,7 @@ int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureAutoFp(de_ctx, - tparser, + ret = RunModeSetLiveCaptureAutoFp(tparser, PfringConfigGeThreadsCount, "ReceivePfring", "DecodePfring", "RxPFR", @@ -456,7 +448,7 @@ int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx) return 0; } -int RunModeIdsPfringSingle(DetectEngineCtx *de_ctx) +int RunModeIdsPfringSingle(void) { SCEnter(); @@ -477,8 +469,7 @@ int RunModeIdsPfringSingle(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureSingle(de_ctx, - tparser, + ret = RunModeSetLiveCaptureSingle(tparser, PfringConfigGeThreadsCount, "ReceivePfring", "DecodePfring", "RxPFR", @@ -494,7 +485,7 @@ int RunModeIdsPfringSingle(DetectEngineCtx *de_ctx) return 0; } -int RunModeIdsPfringWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsPfringWorkers(void) { SCEnter(); @@ -515,8 +506,7 @@ int RunModeIdsPfringWorkers(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureWorkers(de_ctx, - tparser, + ret = RunModeSetLiveCaptureWorkers(tparser, PfringConfigGeThreadsCount, "ReceivePfring", "DecodePfring", "RxPFR", diff --git a/src/runmode-pfring.h b/src/runmode-pfring.h index 9ba7d5c93f04..316c82f74af6 100644 --- a/src/runmode-pfring.h +++ b/src/runmode-pfring.h @@ -25,10 +25,9 @@ #include "suricata-common.h" -int RunModeIdsPfringAuto(DetectEngineCtx *); -int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx); -int RunModeIdsPfringSingle(DetectEngineCtx *de_ctx); -int RunModeIdsPfringWorkers(DetectEngineCtx *de_ctx); +int RunModeIdsPfringAutoFp(void); +int RunModeIdsPfringSingle(void); +int RunModeIdsPfringWorkers(void); void RunModeIdsPfringRegister(void); const char *RunModeIdsPfringGetDefaultMode(void); diff --git a/src/runmode-tile.c b/src/runmode-tile.c index 1839234dddb9..38f5afecc0fd 100644 --- a/src/runmode-tile.c +++ b/src/runmode-tile.c @@ -29,14 +29,10 @@ #include "conf.h" #include "runmodes.h" #include "runmode-tile.h" -#include "log-httplog.h" #include "output.h" #include "source-mpipe.h" -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" +#include "detect-engine.h" #include "util-debug.h" #include "util-time.h" @@ -140,13 +136,12 @@ void *ParseMpipeConfig(const char *iface) /** * \brief RunModeTileMpipeWorkers set up to process all modules in each thread. * - * \param de_ctx pointer to the Detection Engine * \param iface pointer to the name of the interface from which we will * fetch the packets * \retval 0 if all goes well. (If any problem is detected the engine will * exit()) */ -int RunModeTileMpipeWorkers(DetectEngineCtx *de_ctx) +int RunModeTileMpipeWorkers(void) { SCEnter(); char tname[TM_THREAD_NAME_MAX]; @@ -262,13 +257,13 @@ int RunModeTileMpipeWorkers(DetectEngineCtx *de_ctx) } TmSlotSetFuncAppend(tv_worker, tm_module, NULL); - if (de_ctx != NULL) { + if (DetectEngineEnabled()) { tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName Detect failed\n"); exit(EXIT_FAILURE); } - TmSlotSetFuncAppend(tv_worker, tm_module, (void *)de_ctx); + TmSlotSetFuncAppend(tv_worker, tm_module, NULL); } tm_module = TmModuleGetByName("RespondReject"); diff --git a/src/runmode-tile.h b/src/runmode-tile.h index 8e0af793a99b..ec6c9e5042dd 100644 --- a/src/runmode-tile.h +++ b/src/runmode-tile.h @@ -34,7 +34,7 @@ void RunModeTileMpipeRegister(void); extern int tile_num_pipelines; -int RunModeTileMpipeWorkers(DetectEngineCtx *); +int RunModeTileMpipeWorkers(void); void *ParseMpipeConfig(const char *iface); diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index bff022d6eb22..1ee5ce0815a8 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -20,15 +20,7 @@ #include "conf.h" #include "runmodes.h" #include "runmode-pcap-file.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" -#include "detect-engine-mpm.h" - -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" @@ -36,6 +28,8 @@ #include "util-affinity.h" #include "unix-manager.h" +#include "detect-engine.h" + #include "flow-manager.h" #include "flow-timeout.h" #include "stream-tcp.h" @@ -56,7 +50,6 @@ typedef struct PcapFiles_ { } PcapFiles; typedef struct PcapCommand_ { - DetectEngineCtx *de_ctx; TAILQ_HEAD(, PcapFiles_) files; int running; char *currentfile; @@ -354,7 +347,7 @@ TmEcode UnixSocketPcapFilesCheck(void *data) StreamTcpInitConfig(STREAM_VERBOSE); RunModeInitializeOutputs(); SCPerfInitCounterApi(); - RunModeDispatch(RUNMODE_PCAP_FILE, NULL, this->de_ctx); + RunModeDispatch(RUNMODE_PCAP_FILE, NULL); FlowManagerThreadSpawn(); FlowRecyclerThreadSpawn(); SCPerfSpawnThreads(); @@ -396,7 +389,7 @@ void UnixSocketPcapFile(TmEcode tm) /** * \brief Single thread version of the Pcap file processing. */ -int RunModeUnixSocketSingle(DetectEngineCtx *de_ctx) +int RunModeUnixSocketSingle(void) { #ifdef BUILD_UNIX_SOCKET PcapCommand *pcapcmd = SCMalloc(sizeof(PcapCommand)); @@ -405,12 +398,11 @@ int RunModeUnixSocketSingle(DetectEngineCtx *de_ctx) SCLogError(SC_ERR_MEM_ALLOC, "Can not allocate pcap command"); return 1; } - pcapcmd->de_ctx = de_ctx; TAILQ_INIT(&pcapcmd->files); pcapcmd->running = 0; pcapcmd->currentfile = NULL; - UnixManagerThreadSpawn(de_ctx, 1); + UnixManagerThreadSpawn(1); unix_socket_mode_is_running = 1; diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index c2674f2d4a3d..578469ec242d 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -23,7 +23,7 @@ #ifndef __RUNMODE_UNIX_SOCKET_H__ #define __RUNMODE_UNIX_SOCKET_H__ -int RunModeUnixSocketSingle(DetectEngineCtx *); +int RunModeUnixSocketSingle(void); void RunModeUnixSocketRegister(void); const char *RunModeUnixSocketGetDefaultMode(void); diff --git a/src/runmodes.c b/src/runmodes.c index 4ce80d7a937d..5fd9b9145821 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -60,7 +60,7 @@ typedef struct RunMode_ { const char *name; const char *description; /* runmode function */ - int (*RunModeFunc)(DetectEngineCtx *); + int (*RunModeFunc)(void); } RunMode; typedef struct RunModes_ { @@ -154,7 +154,6 @@ static const char *RunModeTranslateModeToName(int runmode) * * \param runmode The runmode type. * \param runmode_customd_id The runmode custom id. - * \param de_ctx Detection Engine Context. */ static RunMode *RunModeGetCustomMode(int runmode, const char *custom_mode) { @@ -264,9 +263,8 @@ void RunModeListRunmodes(void) } /** - * \param de_ctx Detection engine ctx. Can be NULL is detect is disabled. */ -void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_ctx) +void RunModeDispatch(int runmode, const char *custom_mode) { char *local_custom_mode = NULL; @@ -365,7 +363,7 @@ void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_c exit(EXIT_FAILURE); } - mode->RunModeFunc(de_ctx); + mode->RunModeFunc(); if (local_custom_mode != NULL) SCFree(local_custom_mode); @@ -383,7 +381,7 @@ void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_c */ void RunModeRegisterNewRunMode(int runmode, const char *name, const char *description, - int (*RunModeFunc)(DetectEngineCtx *)) + int (*RunModeFunc)(void)) { void *ptmp; if (RunModeGetCustomMode(runmode, name) != NULL) { diff --git a/src/runmodes.h b/src/runmodes.h index 80ad652b34b4..bd8d03263eb9 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -64,10 +64,10 @@ char *RunmodeGetActive(void); const char *RunModeGetMainMode(void); void RunModeListRunmodes(void); -void RunModeDispatch(int, const char *, DetectEngineCtx *); +void RunModeDispatch(int, const char *); void RunModeRegisterRunModes(void); void RunModeRegisterNewRunMode(int, const char *, const char *, - int (*RunModeFunc)(DetectEngineCtx *)); + int (*RunModeFunc)(void)); void RunModeInitialize(void); void RunModeInitializeOutputs(void); void SetupOutputs(ThreadVars *); diff --git a/src/suricata.c b/src/suricata.c index 96a61b819038..ff9ff74c7a45 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2359,7 +2359,7 @@ int main(int argc, char **argv) exit(EXIT_SUCCESS); } - RunModeDispatch(suri.run_mode, suri.runmode_custom_mode, de_ctx); + RunModeDispatch(suri.run_mode, suri.runmode_custom_mode); /* In Unix socket runmode, Flow manager is started on demand */ if (suri.run_mode != RUNMODE_UNIX_SOCKET) { @@ -2368,7 +2368,7 @@ int main(int argc, char **argv) if (ConfGetBool("unix-command.enabled", &unix_socket) != 1) unix_socket = 0; if (unix_socket == 1) { - UnixManagerThreadSpawn(de_ctx, 0); + UnixManagerThreadSpawn(0); #ifdef BUILD_UNIX_SOCKET UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL, UNIX_CMD_TAKE_ARGS); diff --git a/src/unix-manager.c b/src/unix-manager.c index c3fbfc3d898c..e9538a194b04 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -903,10 +903,9 @@ void *UnixManagerThread(void *td) /** \brief Spawn the unix socket manager thread * - * \param de_ctx context for detection engine * \param mode if set to 1, init failure cause suricata exit * */ -void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode) +void UnixManagerThreadSpawn(int mode) { ThreadVars *tv_unixmgr = NULL; diff --git a/src/unix-manager.h b/src/unix-manager.h index 937737ef110a..2bbdee11ed99 100644 --- a/src/unix-manager.h +++ b/src/unix-manager.h @@ -33,7 +33,7 @@ SCCtrlCondT unix_manager_ctrl_cond; SCCtrlMutex unix_manager_ctrl_mutex; -void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode); +void UnixManagerThreadSpawn(int mode); void UnixSocketKillSocketThread(void); diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 26ef2b76c0dc..5e89f7b28dde 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -32,6 +32,8 @@ #include "runmode-af-packet.h" #include "log-httplog.h" #include "output.h" + +#include "detect-engine.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" @@ -97,10 +99,8 @@ char *RunmodeAutoFpCreatePickupQueuesString(int n) } /** - * \param de_ctx detection engine, can be NULL */ -int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc ConfigParser, +int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, @@ -275,14 +275,13 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (de_ctx != NULL) { + if (DetectEngineEnabled()) { tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } - TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); + TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); } TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); @@ -315,10 +314,8 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, } /** - * \param de_ctx detection engine, can be NULL */ -static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx, - ConfigIfaceThreadsCountFunc ModThreadsCount, +static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev, void *aconf, @@ -382,14 +379,13 @@ static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx, } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (de_ctx != NULL) { + if (DetectEngineEnabled()) { tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } - TmSlotSetFuncAppendDelayed(tv, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); + TmSlotSetFuncAppend(tv, tm_module, NULL); } tm_module = TmModuleGetByName("RespondReject"); @@ -412,8 +408,7 @@ static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx, return 0; } -int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc ConfigParser, +int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, @@ -436,8 +431,7 @@ int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, live_dev_c = LiveGetDeviceName(ldev); aconf = ConfigParser(live_dev_c); } - RunModeSetLiveCaptureWorkersForDevice(de_ctx, - ModThreadsCount, + RunModeSetLiveCaptureWorkersForDevice(ModThreadsCount, recv_mod_name, decode_mod_name, thread_name, @@ -449,8 +443,7 @@ int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, return 0; } -int RunModeSetLiveCaptureSingle(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc ConfigParser, +int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, @@ -473,7 +466,7 @@ int RunModeSetLiveCaptureSingle(DetectEngineCtx *de_ctx, /* \todo Set threads number in config to 1 */ } - return RunModeSetLiveCaptureWorkersForDevice(de_ctx, + return RunModeSetLiveCaptureWorkersForDevice( ModThreadsCount, recv_mod_name, decode_mod_name, @@ -485,10 +478,8 @@ int RunModeSetLiveCaptureSingle(DetectEngineCtx *de_ctx, /** - * \param de_ctx detection engine, can be NULL */ -int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, +int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name) @@ -592,14 +583,13 @@ int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (de_ctx != NULL) { + if (DetectEngineEnabled()) { tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } - TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); + TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); } TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); @@ -665,10 +655,8 @@ int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, } /** - * \param de_ctx detection engine, can be NULL */ -int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, +int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name) @@ -725,14 +713,13 @@ int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (de_ctx != NULL) { + if (DetectEngineEnabled()) { tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } - TmSlotSetFuncAppendDelayed(tv, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); + TmSlotSetFuncAppend(tv, tm_module, NULL); } tm_module = TmModuleGetByName(verdict_mod_name); @@ -741,7 +728,7 @@ int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, exit(EXIT_FAILURE); } - TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); + TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { diff --git a/src/util-runmodes.h b/src/util-runmodes.h index c1852ccd8aac..607895a4ab38 100644 --- a/src/util-runmodes.h +++ b/src/util-runmodes.h @@ -30,48 +30,36 @@ typedef void *(*ConfigIfaceParserFunc) (const char *); typedef void *(*ConfigIPSParserFunc) (int); typedef int (*ConfigIfaceThreadsCountFunc) (void *); -int RunModeSetLiveCaptureAuto(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc configparser, +int RunModeSetLiveCaptureAuto(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev); -int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc configparser, +int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev); -int RunModeSetLiveCaptureSingle(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc configparser, +int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev); -int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc configparser, +int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev); -int RunModeSetIPSAuto(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name); - -int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, +int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name); -int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, +int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name); From b0cb4c17ec3e31f53051b5bf6223aaaf45529c4d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Jan 2015 12:08:55 +0100 Subject: [PATCH 0308/2553] detect: unify delayed detect and reload Instead of threading logic with dummy slots and all, use the regular reload logic for delayed detect. This means we pass a empty detect engine to the threads and then reload (live swap) it as soon as the engine is running. --- src/detect.h | 5 ----- src/suricata.c | 40 +++++++++++++++++----------------------- src/unix-manager.c | 2 +- 3 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/detect.h b/src/detect.h index a5cd359ddb1b..557b03c6052c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -720,11 +720,6 @@ typedef struct DetectEngineCtx_ { 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; diff --git a/src/suricata.c b/src/suricata.c index ff9ff74c7a45..35501129d5e2 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1958,7 +1958,7 @@ static int FinalizeRunMode(SCInstance *suri, char **argv) return TM_ECODE_OK; } -static void SetupDelayedDetect(DetectEngineCtx *de_ctx, SCInstance *suri) +static void SetupDelayedDetect(SCInstance *suri) { /* In offline mode delayed init of detect is a bad idea */ if (suri->offline) { @@ -1974,7 +1974,6 @@ static void SetupDelayedDetect(DetectEngineCtx *de_ctx, SCInstance *suri) } } } - de_ctx->delayed_detect = suri->delayed_detect; SCLogInfo("Delayed detect %s", suri->delayed_detect ? "enabled" : "disabled"); if (suri->delayed_detect) { @@ -2299,6 +2298,9 @@ int main(int argc, char **argv) StreamTcpInitConfig(STREAM_VERBOSE); } + if (MagicInit() != 0) + exit(EXIT_FAILURE); + DetectEngineCtx *de_ctx = NULL; if (!suri.disabled_detect) { de_ctx = DetectEngineCtxInit(); @@ -2313,28 +2315,22 @@ int main(int argc, char **argv) CudaVarsSetDeCtx(de_ctx); #endif /* __SC_CUDA_SUPPORT__ */ - } else { - /* disable raw reassembly */ - (void)ConfSetFinal("stream.reassembly.raw", "false"); - - /* tell the app layer to consider only the log id */ - RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveLogOnly); - } - - if (MagicInit() != 0) - exit(EXIT_FAILURE); - - if (de_ctx != NULL) { - SetupDelayedDetect(de_ctx, &suri); - + SetupDelayedDetect(&suri); if (!suri.delayed_detect) { if (LoadSignatures(de_ctx, &suri) != TM_ECODE_OK) exit(EXIT_FAILURE); if (suri.run_mode == RUNMODE_ENGINE_ANALYSIS) { exit(EXIT_SUCCESS); } - DetectEngineAddToMaster(de_ctx); } + + DetectEngineAddToMaster(de_ctx); + } else { + /* disable raw reassembly */ + (void)ConfSetFinal("stream.reassembly.raw", "false"); + + /* tell the app layer to consider only the log id */ + RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveLogOnly); } SCAsn1LoadConfig(); @@ -2403,15 +2399,13 @@ int main(int argc, char **argv) /* registering singal handlers we use. We register usr2 here, so that one * can't call it during the first sig load phase or while threads are still * starting up. */ - if (de_ctx != NULL && suri.sig_file == NULL && suri.rule_reload == 1 && + if (DetectEngineEnabled() && suri.sig_file == NULL && suri.rule_reload == 1 && suri.delayed_detect == 0) UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - if (de_ctx != NULL && suri.delayed_detect) { - if (LoadSignatures(de_ctx, &suri) != TM_ECODE_OK) - exit(EXIT_FAILURE); - de_ctx->delayed_detect_initialized = 1; - TmThreadActivateDummySlot(); + if (suri.delayed_detect) { + /* force 'reload', this will load the rules and swap engines */ + DetectEngineReload(); if (suri.rule_reload) { if (suri.sig_file != NULL) diff --git a/src/unix-manager.c b/src/unix-manager.c index e9538a194b04..6863db349455 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -975,7 +975,7 @@ void UnixSocketKillSocketThread(void) #else /* BUILD_UNIX_SOCKET */ -void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode) +void UnixManagerThreadSpawn(int mode) { SCLogError(SC_ERR_UNIMPLEMENTED, "Unix socket is not compiled"); return; From f4617d53574637482319d54b81d8de4a50d442a7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Jan 2015 12:11:22 +0100 Subject: [PATCH 0309/2553] threading: remove 'dummy' slot logic Now that delayed detect is not using it anymore, the dummy logic can be removed. --- src/tm-threads.c | 94 ------------------------------------------------ src/tm-threads.h | 3 -- 2 files changed, 97 deletions(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index 1bce7526c9ba..343b252e320b 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -110,16 +110,6 @@ void TmThreadsUnsetFlag(ThreadVars *tv, uint16_t flag) SC_ATOMIC_AND(tv->flags, ~flag); } -/** - * \brief Function to use as dummy stack function - * - * \retval TM_ECODE_OK - */ -TmEcode TmDummyFunc(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) -{ - return TM_ECODE_OK; -} - /** * \brief Separate run function so we can call it recursively. * @@ -780,90 +770,6 @@ void TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data) _TmSlotSetFuncAppend(tv, tm, data); } -typedef struct TmDummySlot_ { - TmSlot *slot; - TmEcode (*SlotFunc)(ThreadVars *, Packet *, void *, PacketQueue *, - PacketQueue *); - TmEcode (*SlotThreadInit)(ThreadVars *, void *, void **); - TAILQ_ENTRY(TmDummySlot_) next; -} TmDummySlot; - -static TAILQ_HEAD(, TmDummySlot_) dummy_slots = - TAILQ_HEAD_INITIALIZER(dummy_slots); - -/** - * \brief Appends a new entry to the slots with a delayed option. - * - * \param tv TV the slot is attached to. - * \param tm TM to append. - * \param data Data to be passed on to the slot init function. - * \param delayed Delayed start of slot if equal to 1 - */ -void TmSlotSetFuncAppendDelayed(ThreadVars *tv, TmModule *tm, void *data, - int delayed) -{ - TmSlot *slot = _TmSlotSetFuncAppend(tv, tm, data); - TmDummySlot *dslot = NULL; - - if ((slot == NULL) || (delayed == 0)) { - return; - } - - dslot = SCMalloc(sizeof(TmDummySlot)); - if (unlikely(dslot == NULL)) { - TmSlotFree(slot); - return; - } - memset(dslot, 0, sizeof(*dslot)); - - dslot->SlotFunc = SC_ATOMIC_GET(slot->SlotFunc); - (void)SC_ATOMIC_SET(slot->SlotFunc, TmDummyFunc); - dslot->SlotThreadInit = slot->SlotThreadInit; - dslot->slot = slot; - - TAILQ_INSERT_TAIL(&dummy_slots, dslot, next); - - return; -} - -/** - * \brief Activate slots that have been started in delayed mode - */ -void TmThreadActivateDummySlot() -{ - TmDummySlot *dslot; - TmSlot *s; - TmEcode r = TM_ECODE_OK; - - TAILQ_FOREACH(dslot, &dummy_slots, next) { - void *slot_data = NULL; - s = dslot->slot; - if (dslot->SlotThreadInit != NULL) { - s->SlotThreadInit = dslot->SlotThreadInit; - r = s->SlotThreadInit(s->tv, s->slot_initdata, &slot_data); - if (r != TM_ECODE_OK) { - EngineKill(); - TmThreadsSetFlag(s->tv, THV_CLOSED | THV_RUNNING_DONE); - } - (void)SC_ATOMIC_SET(s->slot_data, slot_data); - } - (void)SC_ATOMIC_CAS(&s->SlotFunc, TmDummyFunc, dslot->SlotFunc); - } -} - -/** - * \brief Deactivate slots that have been started in delayed mode. - */ -void TmThreadDeActivateDummySlot() -{ - TmDummySlot *dslot; - - TAILQ_FOREACH(dslot, &dummy_slots, next) { - (void)SC_ATOMIC_CAS(&dslot->slot->SlotFunc, dslot->SlotFunc, TmDummyFunc); - dslot->slot->SlotThreadInit = NULL; - } -} - /** * \brief Returns the slot holding a TM with the particular tm_id. * diff --git a/src/tm-threads.h b/src/tm-threads.h index 9ffc9efba810..0c92a4bdb09d 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -119,9 +119,6 @@ void TmThreadCheckThreadState(void); TmEcode TmThreadWaitOnThreadInit(void); ThreadVars *TmThreadsGetCallingThread(void); -void TmThreadActivateDummySlot(void); -void TmThreadDeActivateDummySlot(void); - int TmThreadsCheckFlag(ThreadVars *, uint16_t); void TmThreadsSetFlag(ThreadVars *, uint16_t); void TmThreadsUnsetFlag(ThreadVars *, uint16_t); From e7882da178fcb8d8faf02557602e2d25139f800a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Jan 2015 14:54:11 +0100 Subject: [PATCH 0310/2553] detect: introduce 'minimal' detect engine The minimal detect engine has only the minimal memory use and setup time. It's to be used for 'delayed' detect where the first detection engine is essentially empty. The threads setup are also minimal. --- src/detect-engine-mpm.c | 3 ++- src/detect-engine.c | 30 ++++++++++++++++++++++++------ src/detect-engine.h | 1 + src/detect.h | 3 +++ src/suricata.c | 8 ++++++-- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index bff9ca8de791..6da966a12daf 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -817,7 +817,8 @@ void PatternMatchThreadPrint(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) { SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16"", mpm_thread_ctx, mpm_matcher); - mpm_table[mpm_matcher].DestroyThreadCtx(NULL, mpm_thread_ctx); + if (mpm_table[mpm_matcher].DestroyThreadCtx != NULL) + mpm_table[mpm_matcher].DestroyThreadCtx(NULL, mpm_thread_ctx); } void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher, uint32_t max_id) { diff --git a/src/detect-engine.c b/src/detect-engine.c index 8abf373de29f..8d0b301ab5d0 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -966,7 +966,7 @@ void DetectEngineSpawnLiveRuleSwapMgmtThread(void) SCReturn; } -DetectEngineCtx *DetectEngineCtxInit(void) +static DetectEngineCtx *DetectEngineCtxInitReal(int minimal) { DetectEngineCtx *de_ctx; @@ -981,6 +981,12 @@ DetectEngineCtx *DetectEngineCtxInit(void) memset(de_ctx,0,sizeof(DetectEngineCtx)); + if (minimal) { + de_ctx->minimal = 1; + de_ctx->id = detect_engine_ctx_id++; + return de_ctx; + } + if (ConfGetBool("engine.init-failure-fatal", (int *)&(de_ctx->failure_fatal)) != 1) { SCLogDebug("ConfGetBool could not load the value."); } @@ -1037,8 +1043,6 @@ DetectEngineCtx *DetectEngineCtxInit(void) goto error; } - de_ctx->id = detect_engine_ctx_id++; - /* init iprep... ignore errors for now */ (void)SRepInit(de_ctx); @@ -1053,9 +1057,21 @@ DetectEngineCtx *DetectEngineCtxInit(void) goto error; } + de_ctx->id = detect_engine_ctx_id++; return de_ctx; error: return NULL; + +} + +DetectEngineCtx *DetectEngineCtxInitMinimal(void) +{ + return DetectEngineCtxInitReal(1); +} + +DetectEngineCtx *DetectEngineCtxInit(void) +{ + return DetectEngineCtxInitReal(0); } static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx) @@ -1572,9 +1588,11 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) #endif } - if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) { - DetectEngineThreadCtxDeinit(tv, det_ctx); - return TM_ECODE_FAILED; + if (det_ctx->de_ctx->minimal == 0) { + if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) { + DetectEngineThreadCtxDeinit(tv, det_ctx); + return TM_ECODE_FAILED; + } } /** alert counter setup */ diff --git a/src/detect-engine.h b/src/detect-engine.h index 1b6d55398415..f500aa094fdd 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -57,6 +57,7 @@ extern DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT void DetectEngineRegisterAppInspectionEngines(void); void DetectEngineSpawnLiveRuleSwapMgmtThread(void); DetectEngineCtx *DetectEngineCtxInit(void); +DetectEngineCtx *DetectEngineCtxInitMinimal(void); void DetectEngineCtxFree(DetectEngineCtx *); TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **); diff --git a/src/detect.h b/src/detect.h index 557b03c6052c..5d87616137ec 100644 --- a/src/detect.h +++ b/src/detect.h @@ -732,6 +732,9 @@ typedef struct DetectEngineCtx_ { struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; #endif + /** minimal: essentially a stub */ + int minimal; + /** how many de_ctx' are referencing this */ uint32_t ref_cnt; /** list in master: either active or freelist */ diff --git a/src/suricata.c b/src/suricata.c index 35501129d5e2..839c08adae5e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2303,7 +2303,12 @@ int main(int argc, char **argv) DetectEngineCtx *de_ctx = NULL; if (!suri.disabled_detect) { - de_ctx = DetectEngineCtxInit(); + SetupDelayedDetect(&suri); + if (!suri.delayed_detect) { + de_ctx = DetectEngineCtxInit(); + } else { + de_ctx = DetectEngineCtxInitMinimal(); + } if (de_ctx == NULL) { SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " "context failed."); @@ -2315,7 +2320,6 @@ int main(int argc, char **argv) CudaVarsSetDeCtx(de_ctx); #endif /* __SC_CUDA_SUPPORT__ */ - SetupDelayedDetect(&suri); if (!suri.delayed_detect) { if (LoadSignatures(de_ctx, &suri) != TM_ECODE_OK) exit(EXIT_FAILURE); From 0c263105cd1e8799150df6fbfc4de34b520d9f52 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Jan 2015 22:09:59 +0100 Subject: [PATCH 0311/2553] detect: move reload into main loop Use new DetectEngineReload() function. It's called from the main loop instead of it being spawned into it's own temporary thread. This greatly simplifies the signal handling. An added advantage is that this seems to improve the memory usage. Related to bug #1358 --- src/suricata.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index 839c08adae5e..c35fb20fa3c6 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -195,6 +195,7 @@ volatile sig_atomic_t sigint_count = 0; volatile sig_atomic_t sighup_count = 0; volatile sig_atomic_t sigterm_count = 0; +volatile sig_atomic_t sigusr2_count = 0; /* * Flag to indicate if the engine is at the initialization @@ -316,6 +317,7 @@ void SignalHandlerSigusr2Idle(int sig) void SignalHandlerSigusr2(int sig) { +#if 0 if (run_mode == RUNMODE_UNKNOWN || run_mode == RUNMODE_UNITTEST) { SCLogInfo("Ruleset load signal USR2 triggered for wrong runmode"); return; @@ -331,6 +333,8 @@ void SignalHandlerSigusr2(int sig) DetectEngineSpawnLiveRuleSwapMgmtThread(); return; +#endif + sigusr2_count = 1; } /** @@ -2442,6 +2446,10 @@ int main(int argc, char **argv) OutputNotifyFileRotation(); sighup_count--; } + if (sigusr2_count > 0) { + DetectEngineReload(); + sigusr2_count--; + } usleep(10* 1000); } From b1c54a8673fcc293090ff61eca791a6b45e3d228 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Jan 2015 10:53:54 +0100 Subject: [PATCH 0312/2553] detect: remove old live reload implementation Remove code that ran the reload in it's own thread. Simplify the signal handling. --- src/detect-engine.c | 319 -------------------------------------------- src/detect-engine.h | 1 - src/suricata.c | 54 +------- 3 files changed, 4 insertions(+), 370 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 8d0b301ab5d0..93aab657807c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -647,325 +647,6 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) return -1; } -static void *DetectEngineLiveRuleSwap(void *arg) -{ - SCEnter(); - - int i = 0; - int no_of_detect_tvs = 0; - DetectEngineCtx *old_de_ctx = NULL; - ThreadVars *tv = NULL; - - if (SCSetThreadName("LiveRuleSwap") < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } - - SCLogNotice("rule reload starting"); - - ThreadVars *tv_local = (ThreadVars *)arg; - - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); - - if (tv_local->thread_setup_flags != 0) - TmThreadSetupOptions(tv_local); - - /* release TmThreadSpawn */ - TmThreadsSetFlag(tv_local, THV_INIT_DONE); - - ConfDeInit(); - ConfInit(); - - /* re-load the yaml file */ - if (conf_filename != NULL) { - if (ConfYamlLoadFile(conf_filename) != 0) { - /* Error already displayed. */ - exit(EXIT_FAILURE); - } - - ConfNode *file; - ConfNode *includes = ConfGetNode("include"); - if (includes != NULL) { - TAILQ_FOREACH(file, &includes->head, next) { - char *ifile = ConfLoadCompleteIncludePath(file->val); - SCLogInfo("Live Rule Swap: Including: %s", ifile); - - if (ConfYamlLoadFile(ifile) != 0) { - /* Error already displayed. */ - exit(EXIT_FAILURE); - } - } - } - } /* if (conf_filename != NULL) */ - -#if 0 - ConfDump(); -#endif - - SCMutexLock(&tv_root_lock); - - tv = tv_root[TVT_PPT]; - while (tv) { - /* obtain the slots for this TV */ - TmSlot *slots = tv->tm_slots; - while (slots != NULL) { - TmModule *tm = TmModuleGetById(slots->tm_id); - - if (suricata_ctl_flags != 0) { - TmThreadsSetFlag(tv_local, THV_CLOSED); - - SCLogInfo("rule reload interupted by engine shutdown"); - - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - SCMutexUnlock(&tv_root_lock); - pthread_exit(NULL); - } - - if (!(tm->flags & TM_FLAG_DETECT_TM)) { - slots = slots->slot_next; - continue; - } - no_of_detect_tvs++; - break; - } - - tv = tv->next; - } - - if (no_of_detect_tvs == 0) { - TmThreadsSetFlag(tv_local, THV_CLOSED); - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - SCLogInfo("===== Live rule swap FAILURE ====="); - pthread_exit(NULL); - } - - DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs]; - DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs]; - ThreadVars *detect_tvs[no_of_detect_tvs]; - memset(old_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *))); - memset(new_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *))); - memset(detect_tvs, 0x00, (no_of_detect_tvs * sizeof(ThreadVars *))); - - SCMutexUnlock(&tv_root_lock); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - SCLogError(SC_ERR_LIVE_RULE_SWAP, "Allocation failure in live " - "swap. Let's get out of here."); - goto error; - } - - if (SigLoadSignatures(de_ctx, NULL, FALSE) < 0) { - SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); - if (de_ctx->failure_fatal) - exit(EXIT_FAILURE); - DetectEngineCtxFree(de_ctx); - SCLogError(SC_ERR_LIVE_RULE_SWAP, "Failure encountered while " - "loading new ruleset with live swap."); - SCLogError(SC_ERR_LIVE_RULE_SWAP, "rule reload failed"); - TmThreadsSetFlag(tv_local, THV_CLOSED); - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - pthread_exit(NULL); - } - - SCThresholdConfInitContext(de_ctx, NULL); - - /* start the process of swapping detect threads ctxs */ - - SCMutexLock(&tv_root_lock); - - /* all receive threads are part of packet processing threads */ - tv = tv_root[TVT_PPT]; - while (tv) { - /* obtain the slots for this TV */ - TmSlot *slots = tv->tm_slots; - while (slots != NULL) { - TmModule *tm = TmModuleGetById(slots->tm_id); - - if (suricata_ctl_flags != 0) { - TmThreadsSetFlag(tv_local, THV_CLOSED); - - SCLogInfo("rule reload interupted by engine shutdown"); - - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - SCMutexUnlock(&tv_root_lock); - pthread_exit(NULL); - } - - if (!(tm->flags & TM_FLAG_DETECT_TM)) { - slots = slots->slot_next; - continue; - } - - old_det_ctx[i] = SC_ATOMIC_GET(slots->slot_data); - detect_tvs[i] = tv; - TmEcode r = DetectEngineThreadCtxInitForLiveRuleSwap(tv, (void *)de_ctx, - (void **)&new_det_ctx[i]); - i++; - if (r == TM_ECODE_FAILED) { - SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init " - "failure in live rule swap. Let's get out of here"); - SCMutexUnlock(&tv_root_lock); - goto error; - } - SCLogDebug("live rule swap created new det_ctx - %p and de_ctx " - "- %p\n", new_det_ctx, de_ctx); - break; - } - - tv = tv->next; - } - - i = 0; - tv = tv_root[TVT_PPT]; - while (tv) { - TmSlot *slots = tv->tm_slots; - while (slots != NULL) { - if (suricata_ctl_flags != 0) { - TmThreadsSetFlag(tv_local, THV_CLOSED); - - SCLogInfo("rule reload interupted by engine shutdown"); - - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - SCMutexUnlock(&tv_root_lock); - pthread_exit(NULL); - } - - TmModule *tm = TmModuleGetById(slots->tm_id); - if (!(tm->flags & TM_FLAG_DETECT_TM)) { - slots = slots->slot_next; - continue; - } - SCLogDebug("swapping new det_ctx - %p with older one - %p", - new_det_ctx[i], SC_ATOMIC_GET(slots->slot_data)); - (void)SC_ATOMIC_SET(slots->slot_data, new_det_ctx[i++]); - break; - } - tv = tv->next; - } - - SCMutexUnlock(&tv_root_lock); - - SCLogInfo("Live rule swap has swapped %d old det_ctx's with new ones, " - "along with the new de_ctx", no_of_detect_tvs); - - for (i = 0; i < no_of_detect_tvs; i++) { - int break_out = 0; - int pseudo_pkt_inserted = 0; - usleep(1000); - while (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) { - if (suricata_ctl_flags != 0) { - break_out = 1; - break; - } - - if (pseudo_pkt_inserted == 0) { - pseudo_pkt_inserted = 1; - if (detect_tvs[i]->inq != NULL) { - Packet *p = PacketGetFromAlloc(); - if (p != NULL) { - p->flags |= PKT_PSEUDO_STREAM_END; - PacketQueue *q = &trans_q[detect_tvs[i]->inq->id]; - SCMutexLock(&q->mutex_q); - - PacketEnqueue(q, p); - SCCondSignal(&q->cond_q); - SCMutexUnlock(&q->mutex_q); - } - } - } - usleep(1000); - } - if (break_out) - break; - SCLogDebug("new_det_ctx - %p used by detect engine", new_det_ctx[i]); - } - - /* this is to make sure that if someone initiated shutdown during a live - * rule swap, the live rule swap won't clean up the old det_ctx and - * de_ctx, till all detect threads have stopped working and sitting - * silently after setting RUNNING_DONE flag and while waiting for - * THV_DEINIT flag */ - if (i != no_of_detect_tvs) { - ThreadVars *tv = tv_root[TVT_PPT]; - while (tv) { - /* obtain the slots for this TV */ - TmSlot *slots = tv->tm_slots; - while (slots != NULL) { - TmModule *tm = TmModuleGetById(slots->tm_id); - - if (!(tm->flags & TM_FLAG_DETECT_TM)) { - slots = slots->slot_next; - continue; - } - - while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { - usleep(100); - } - - slots = slots->slot_next; - } - - tv = tv->next; - } - } - - /* free all the ctxs */ - old_de_ctx = old_det_ctx[0]->de_ctx; - for (i = 0; i < no_of_detect_tvs; i++) { - SCLogDebug("Freeing old_det_ctx - %p used by detect", - old_det_ctx[i]); - DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]); - } - DetectEngineCtxFree(old_de_ctx); - - SRepReloadComplete(); - - /* reset the handler */ - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - - TmThreadsSetFlag(tv_local, THV_CLOSED); - - SCLogNotice("rule reload complete"); - - pthread_exit(NULL); - - error: - for (i = 0; i < no_of_detect_tvs; i++) { - if (new_det_ctx[i] != NULL) - DetectEngineThreadCtxDeinit(NULL, new_det_ctx[i]); - } - DetectEngineCtxFree(de_ctx); - TmThreadsSetFlag(tv_local, THV_CLOSED); - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - SCLogInfo("===== Live rule swap FAILURE ====="); - pthread_exit(NULL); -} - -void DetectEngineSpawnLiveRuleSwapMgmtThread(void) -{ - SCEnter(); - - SCLogDebug("Spawning mgmt thread for live rule swap"); - - ThreadVars *tv = TmThreadCreateMgmtThread("DetectEngineLiveRuleSwap", - DetectEngineLiveRuleSwap, 0); - if (tv == NULL) { - SCLogError(SC_ERR_THREAD_CREATE, "Live rule swap thread spawn failed"); - exit(EXIT_FAILURE); - } - - TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); - - if (TmThreadSpawn(tv) != 0) { - SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed for " - "DetectEngineLiveRuleSwap"); - exit(EXIT_FAILURE); - } - - SCReturn; -} - static DetectEngineCtx *DetectEngineCtxInitReal(int minimal) { DetectEngineCtx *de_ctx; diff --git a/src/detect-engine.h b/src/detect-engine.h index f500aa094fdd..af580751341f 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -55,7 +55,6 @@ extern DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT /* prototypes */ void DetectEngineRegisterAppInspectionEngines(void); -void DetectEngineSpawnLiveRuleSwapMgmtThread(void); DetectEngineCtx *DetectEngineCtxInit(void); DetectEngineCtx *DetectEngineCtxInitMinimal(void); void DetectEngineCtxFree(DetectEngineCtx *); diff --git a/src/suricata.c b/src/suricata.c index c35fb20fa3c6..36ceaffbb934 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -279,15 +279,11 @@ static void SignalHandlerSigterm(/*@unused@*/ int sig) void SignalHandlerSigusr2Disabled(int sig) { SCLogInfo("Live rule reload not enabled in config."); - - return; } void SignalHandlerSigusr2StartingUp(int sig) { SCLogInfo("Live rule reload only possible after engine completely started."); - - return; } void SignalHandlerSigusr2DelayedDetect(int sig) @@ -298,42 +294,14 @@ void SignalHandlerSigusr2DelayedDetect(int sig) void SignalHandlerSigusr2SigFileStartup(int sig) { SCLogInfo("Live rule reload not possible if -s or -S option used at runtime."); - - return; -} - -void SignalHandlerSigusr2Idle(int sig) -{ - if (run_mode == RUNMODE_UNKNOWN || run_mode == RUNMODE_UNITTEST) { - SCLogInfo("Ruleset load signal USR2 triggered for wrong runmode"); - return; - } - - SCLogInfo("Ruleset load in progress. New ruleset load " - "allowed after current is done"); - - return; } +/** + * SIGUSR2 handler. Just set sigusr2_count. The main loop will act on + * it. + */ void SignalHandlerSigusr2(int sig) { -#if 0 - if (run_mode == RUNMODE_UNKNOWN || run_mode == RUNMODE_UNITTEST) { - SCLogInfo("Ruleset load signal USR2 triggered for wrong runmode"); - return; - } - - if (suricata_ctl_flags != 0) { - SCLogInfo("Live rule swap no longer possible. Engine in shutdown mode."); - return; - } - - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle); - - DetectEngineSpawnLiveRuleSwapMgmtThread(); - - return; -#endif sigusr2_count = 1; } @@ -2476,20 +2444,6 @@ int main(int argc, char **argv) SCPrintElapsedTime(&suri); - if (suri.rule_reload == 1) { - /* wait if live rule swap is in progress */ - if (UtilSignalIsHandler(SIGUSR2, SignalHandlerSigusr2Idle)) { - SCLogInfo("Live rule swap in progress. Waiting for it to end " - "before we shut the engine/threads down"); - while (UtilSignalIsHandler(SIGUSR2, SignalHandlerSigusr2Idle)) { - /* sleep for 0.5 seconds */ - usleep(500000); - } - SCLogInfo("Received notification that live rule swap is done. " - "Continuing with engine/threads shutdown"); - } - } - /* before TmThreadKillThreads, as otherwise that kills it * but more slowly */ if (suri.run_mode != RUNMODE_UNIX_SOCKET) { From 55e7370fc514258b83a26645633c8ee3c386617c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Jan 2015 11:30:08 +0100 Subject: [PATCH 0313/2553] detect reload: allow master update during reload Add DetectEngineReference, which takes a reference to a detect engine, and make DetectEngineThreadCtxInitForLiveRuleSwap use it. This way reload will not depend on master staying the same. This allows master to be updated in between w/o affecting the reload that is in progress. --- src/detect-engine.c | 10 +++++++++- src/detect-engine.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 93aab657807c..f9785c7c982b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1308,7 +1308,7 @@ static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *tv, void *in memset(det_ctx, 0, sizeof(DetectEngineThreadCtx)); det_ctx->tv = tv; - det_ctx->de_ctx = DetectEngineGetCurrent(); + det_ctx->de_ctx = DetectEngineReference(initdata); if (det_ctx->de_ctx == NULL) { return TM_ECODE_FAILED; } @@ -1527,6 +1527,14 @@ DetectEngineCtx *DetectEngineGetCurrent(void) return master->list; } +DetectEngineCtx *DetectEngineReference(DetectEngineCtx *de_ctx) +{ + if (de_ctx == NULL) + return NULL; + de_ctx->ref_cnt++; + return de_ctx; +} + void DetectEngineDeReference(DetectEngineCtx **de_ctx) { BUG_ON((*de_ctx)->ref_cnt == 0); diff --git a/src/detect-engine.h b/src/detect-engine.h index af580751341f..b95f509ebb25 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -72,6 +72,7 @@ int DetectEngineAddToMaster(DetectEngineCtx *de_ctx); DetectEngineCtx *DetectEngineGetCurrent(void); void DetectEnginePruneFreeList(void); int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx); +DetectEngineCtx *DetectEngineReference(DetectEngineCtx *); void DetectEngineDeReference(DetectEngineCtx **de_ctx); int DetectEngineReload(void); int DetectEngineEnabled(void); From c9a8262ccf877f45a903d2e113a492ce5988dc8f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Jan 2015 12:33:21 +0100 Subject: [PATCH 0314/2553] detect: reload thread init cleanup Rename the thread init function DetectEngineThreadCtxInitForLiveRuleSwap to DetectEngineThreadCtxInitForReload and change it's logic to take the new detection engine as argument and let it return the DetectEngineThreadCtx or NULL on error. The old approach used the thread init API format, but it wasn't used in that way. --- src/detect-engine.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index f9785c7c982b..6b86384e60e1 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -97,7 +97,8 @@ static uint32_t detect_engine_ctx_id = 1; -static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *, void *, void **); +static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( + ThreadVars *tv, DetectEngineCtx *new_de_ctx); static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *); @@ -517,17 +518,16 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) old_det_ctx[i] = SC_ATOMIC_GET(slots->slot_data); detect_tvs[i] = tv; - TmEcode r = DetectEngineThreadCtxInitForLiveRuleSwap(tv, (void *)new_de_ctx, - (void **)&new_det_ctx[i]); - i++; - if (r == TM_ECODE_FAILED) { + new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx); + if (new_det_ctx[i] == NULL) { SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init " "failure in live rule swap. Let's get out of here"); SCMutexUnlock(&tv_root_lock); goto error; } SCLogDebug("live rule swap created new det_ctx - %p and de_ctx " - "- %p\n", new_det_ctx, new_de_ctx); + "- %p\n", new_det_ctx[i], new_de_ctx); + i++; break; } @@ -1293,28 +1293,31 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) /** * \internal - * \brief This thread is an exact duplicate of DetectEngineThreadCtxInit(), - * except that the counters API 2 calls doesn't let us use the same - * init function. Once we have the new counters API it should let - * us use the same init function. + * \brief initialize a det_ctx for reload cases + * \param new_de_ctx the new detection engine + * \retval det_ctx detection engine thread ctx or NULL in case of error */ -static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *tv, void *initdata, void **data) +static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( + ThreadVars *tv, DetectEngineCtx *new_de_ctx) { - *data = NULL; - DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); if (unlikely(det_ctx == NULL)) - return TM_ECODE_FAILED; + return NULL; memset(det_ctx, 0, sizeof(DetectEngineThreadCtx)); det_ctx->tv = tv; - det_ctx->de_ctx = DetectEngineReference(initdata); + det_ctx->de_ctx = DetectEngineReference(new_de_ctx); if (det_ctx->de_ctx == NULL) { - return TM_ECODE_FAILED; + SCFree(det_ctx); + return NULL; } - if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) - return TM_ECODE_FAILED; + /* most of the init happens here */ + if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) { + DetectEngineDeReference(&det_ctx->de_ctx); + SCFree(det_ctx); + return NULL; + } /** alert counter setup */ det_ctx->counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, @@ -1333,12 +1336,8 @@ static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *tv, void *in det_ctx->counter_fnonmpm_list = counter_fnonmpm_list; det_ctx->counter_match_list = counter_match_list; #endif - /* no counter creation here */ - /* pass thread data back to caller */ - *data = (void *)det_ctx; - - return TM_ECODE_OK; + return det_ctx; } TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) From a80cc696d73a9ec71556c2e49f1e7789b57dcdfc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 29 Jan 2015 11:16:49 +0100 Subject: [PATCH 0315/2553] detect: allow det_ctx->de_ctx to be NULL When freeing det_ctx, allow de_ctx to be NULL. --- src/detect-engine.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 6b86384e60e1..e42e89617472 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1357,9 +1357,11 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) DetectEngineIPOnlyThreadDeinit(&det_ctx->io_ctx); /** \todo get rid of this static */ - PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher); - PatternMatchThreadDestroy(&det_ctx->mtcs, det_ctx->de_ctx->mpm_matcher); - PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher); + if (det_ctx->de_ctx != NULL) { + PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher); + PatternMatchThreadDestroy(&det_ctx->mtcs, det_ctx->de_ctx->mpm_matcher); + PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher); + } PmqFree(&det_ctx->pmq); int i; @@ -1411,13 +1413,15 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) SCFree(det_ctx->hcbd); } - DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx); + if (det_ctx->de_ctx != NULL) { + DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx); #ifdef UNITTESTS - if (!RunmodeIsUnittests() || det_ctx->de_ctx->ref_cnt > 0) - DetectEngineDeReference(&det_ctx->de_ctx); + if (!RunmodeIsUnittests() || det_ctx->de_ctx->ref_cnt > 0) + DetectEngineDeReference(&det_ctx->de_ctx); #else - DetectEngineDeReference(&det_ctx->de_ctx); + DetectEngineDeReference(&det_ctx->de_ctx); #endif + } SCFree(det_ctx); return TM_ECODE_OK; From 97d77e3540972e60a3557382cefeb58a8b730191 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 13 Jan 2015 11:59:21 +0100 Subject: [PATCH 0316/2553] conf: add ConfYamlLoadFileWithPrefix Add function to load a yaml file and insert it into the conf tree at a specific prefix. Example YAML: somefile: myfile.txt If loaded using ConfYamlLoadFileWithPrefix with prefix "myprefix", it can be retrieved by the name of "myprefix.somefile". --- src/conf-yaml-loader.c | 65 ++++++++++++++++++++++++++++++++++++++++++ src/conf-yaml-loader.h | 2 ++ 2 files changed, 67 insertions(+) diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index 49ee6540d1c7..d61e495ce192 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -449,6 +449,71 @@ ConfYamlLoadString(const char *string, size_t len) return ret; } +/** + * \brief Load configuration from a YAML file, insert in tree at 'prefix' + * + * This function will load a configuration file and insert it into the + * config tree at 'prefix'. This means that if this is called with prefix + * "abc" and the file contains a parameter "def", it will be loaded as + * "abc.def". + * + * \param filename Filename of configuration file to load. + * \param prefix Name prefix to use. + * + * \retval 0 on success, -1 on failure. + */ +int +ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix) +{ + FILE *infile; + yaml_parser_t parser; + int ret; + ConfNode *root = ConfGetNode(prefix); + + if (yaml_parser_initialize(&parser) != 1) { + SCLogError(SC_ERR_FATAL, "failed to initialize yaml parser."); + return -1; + } + + struct stat stat_buf; + if (stat(filename, &stat_buf) == 0) { + if (stat_buf.st_mode & S_IFDIR) { + SCLogError(SC_ERR_FATAL, "yaml argument is not a file but a directory: %s. " + "Please specify the yaml file in your -c option.", filename); + return -1; + } + } + + infile = fopen(filename, "r"); + if (infile == NULL) { + SCLogError(SC_ERR_FATAL, "failed to open file: %s: %s", filename, + strerror(errno)); + yaml_parser_delete(&parser); + return -1; + } + + if (conf_dirname == NULL) { + ConfYamlSetConfDirname(filename); + } + + if (root == NULL) { + /* if node at 'prefix' doesn't yet exist, add a place holder */ + ConfSet(prefix, ""); + root = ConfGetNode(prefix); + if (root == NULL) { + fclose(infile); + yaml_parser_delete(&parser); + return -1; + } + } + yaml_parser_set_input_file(&parser, infile); + ret = ConfYamlParse(&parser, root, 0); + yaml_parser_delete(&parser); + fclose(infile); + + return ret; +} + #ifdef UNITTESTS static int diff --git a/src/conf-yaml-loader.h b/src/conf-yaml-loader.h index 22dfb8777377..6c599d0ac8ff 100644 --- a/src/conf-yaml-loader.h +++ b/src/conf-yaml-loader.h @@ -26,6 +26,8 @@ int ConfYamlLoadFile(const char *); int ConfYamlLoadString(const char *, size_t); +int ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix); + void ConfYamlRegisterTests(void); #endif /* !__CONF_YAML_LOADER_H__ */ From 7108085d33b2848f0eccd8c82244f671ed10e793 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Jan 2015 17:46:16 +0100 Subject: [PATCH 0317/2553] detect: initialize detection engine by prefix Initalize detection engine by configuration prefix. DetectEngineCtxInitWithPrefix(const char *prefix) Takes the detection engine configuration from: . If prefix is NULL the regular config will be used. Update sure that DetectLoadCompleteSigPath considers the prefix when retrieving the configuration. --- src/detect-engine.c | 15 ++++++++++++--- src/detect-engine.h | 1 + src/detect-filemd5.c | 6 +++--- src/detect-lua.c | 6 +++--- src/detect.c | 21 +++++++++++++++++---- src/detect.h | 4 +++- 6 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index e42e89617472..688c41961584 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -647,7 +647,7 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) return -1; } -static DetectEngineCtx *DetectEngineCtxInitReal(int minimal) +static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) { DetectEngineCtx *de_ctx; @@ -668,6 +668,10 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal) return de_ctx; } + if (prefix != NULL) { + strlcpy(de_ctx->config_prefix, prefix, sizeof(de_ctx->config_prefix)); + } + if (ConfGetBool("engine.init-failure-fatal", (int *)&(de_ctx->failure_fatal)) != 1) { SCLogDebug("ConfGetBool could not load the value."); } @@ -747,12 +751,17 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal) DetectEngineCtx *DetectEngineCtxInitMinimal(void) { - return DetectEngineCtxInitReal(1); + return DetectEngineCtxInitReal(1, NULL); } DetectEngineCtx *DetectEngineCtxInit(void) { - return DetectEngineCtxInitReal(0); + return DetectEngineCtxInitReal(0, NULL); +} + +DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix) +{ + return DetectEngineCtxInitReal(0, prefix); } static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx) diff --git a/src/detect-engine.h b/src/detect-engine.h index b95f509ebb25..c664f50e2638 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -55,6 +55,7 @@ extern DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT /* prototypes */ void DetectEngineRegisterAppInspectionEngines(void); +DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix); DetectEngineCtx *DetectEngineCtxInit(void); DetectEngineCtx *DetectEngineCtxInitMinimal(void); void DetectEngineCtxFree(DetectEngineCtx *); diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index 1bb0cf3ac88b..87f3f35e9b34 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -211,7 +211,7 @@ static int DetectFileMd5Match (ThreadVars *t, DetectEngineThreadCtx *det_ctx, * \retval filemd5 pointer to DetectFileMd5Data on success * \retval NULL on failure */ -static DetectFileMd5Data *DetectFileMd5Parse (char *str) +static DetectFileMd5Data *DetectFileMd5Parse (const DetectEngineCtx *de_ctx, char *str) { DetectFileMd5Data *filemd5 = NULL; FILE *fp = NULL; @@ -235,7 +235,7 @@ static DetectFileMd5Data *DetectFileMd5Parse (char *str) } /* get full filename */ - filename = DetectLoadCompleteSigPath(str); + filename = DetectLoadCompleteSigPath(de_ctx, str); if (filename == NULL) { goto error; } @@ -309,7 +309,7 @@ static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) DetectFileMd5Data *filemd5 = NULL; SigMatch *sm = NULL; - filemd5 = DetectFileMd5Parse(str); + filemd5 = DetectFileMd5Parse(de_ctx, str); if (filemd5 == NULL) goto error; diff --git a/src/detect-lua.c b/src/detect-lua.c index 8d2b35abe4fb..8a957ccac901 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -713,7 +713,7 @@ static void DetectLuaThreadFree(void *ctx) * \retval luajit pointer to DetectLuaData on success * \retval NULL on failure */ -static DetectLuaData *DetectLuaParse (char *str) +static DetectLuaData *DetectLuaParse (const DetectEngineCtx *de_ctx, char *str) { DetectLuaData *luajit = NULL; @@ -730,7 +730,7 @@ static DetectLuaData *DetectLuaParse (char *str) } /* get full filename */ - luajit->filename = DetectLoadCompleteSigPath(str); + luajit->filename = DetectLoadCompleteSigPath(de_ctx, str); if (luajit->filename == NULL) { goto error; } @@ -987,7 +987,7 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) DetectLuaData *luajit = NULL; SigMatch *sm = NULL; - luajit = DetectLuaParse(str); + luajit = DetectLuaParse(de_ctx, str); if (luajit == NULL) goto error; diff --git a/src/detect.c b/src/detect.c index 2d5ff9822425..53953d4f2a9b 100644 --- a/src/detect.c +++ b/src/detect.c @@ -239,14 +239,20 @@ void DetectExitPrintStats(ThreadVars *tv, void *data) * \param sig_file The name of the file * \retval str Pointer to the string path + sig_file */ -char *DetectLoadCompleteSigPath(char *sig_file) +char *DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, char *sig_file) { char *defaultpath = NULL; char *path = NULL; + char varname[128] = "default-rule-path"; + + if (strlen(de_ctx->config_prefix) > 0) { + snprintf(varname, sizeof(varname), "%s.default-rule-path", + de_ctx->config_prefix); + } /* Path not specified */ if (PathIsRelative(sig_file)) { - if (ConfGet("default-rule-path", &defaultpath) == 1) { + if (ConfGet(varname, &defaultpath) == 1) { SCLogDebug("Default path: %s", defaultpath); size_t path_len = sizeof(char) * (strlen(defaultpath) + strlen(sig_file) + 2); @@ -396,6 +402,13 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl int goodtotal = 0; int badtotal = 0; + char varname[128] = "rule-files"; + + if (strlen(de_ctx->config_prefix) > 0) { + snprintf(varname, sizeof(varname), "%s.rule-files", + de_ctx->config_prefix); + } + if (RunmodeGetCurrent() == RUNMODE_ENGINE_ANALYSIS) { fp_engine_analysis_set = SetupFPAnalyzer(); rule_engine_analysis_set = SetupRuleAnalyzer(); @@ -403,7 +416,7 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl /* ok, let's load signature files from the general config */ if (!(sig_file != NULL && sig_file_exclusive == TRUE)) { - rule_files = ConfGetNode("rule-files"); + rule_files = ConfGetNode(varname); if (rule_files != NULL) { if (!ConfNodeIsSequence(rule_files)) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, @@ -412,7 +425,7 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl } else { TAILQ_FOREACH(file, &rule_files->head, next) { - sfile = DetectLoadCompleteSigPath(file->val); + sfile = DetectLoadCompleteSigPath(de_ctx, file->val); SCLogDebug("Loading rule file: %s", sfile); cntf++; diff --git a/src/detect.h b/src/detect.h index 5d87616137ec..973f7f87cf50 100644 --- a/src/detect.h +++ b/src/detect.h @@ -732,6 +732,8 @@ typedef struct DetectEngineCtx_ { struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; #endif + char config_prefix[64]; + /** minimal: essentially a stub */ int minimal; @@ -1202,7 +1204,7 @@ int SigGroupBuild(DetectEngineCtx *); int SigGroupCleanup (DetectEngineCtx *de_ctx); void SigAddressPrepareBidirectionals (DetectEngineCtx *); -char *DetectLoadCompleteSigPath(char *sig_file); +char *DetectLoadCompleteSigPath(const DetectEngineCtx *, char *sig_file); int SigLoadSignatures (DetectEngineCtx *, char *, int); void SigTableList(const char *keyword); void SigTableSetup(void); From 2be9ccfe9c92d7e21ff09b2103a51248bb1f6ecd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 1 Mar 2015 11:02:33 +0100 Subject: [PATCH 0318/2553] detect: pass DetectEngineCtx to address parsing Preparation for prefix handling in address parsing. --- src/detect-engine-address.c | 186 ++++++++++++++++++------------------ src/detect-engine-address.h | 2 +- src/detect-parse.c | 19 ++-- 3 files changed, 106 insertions(+), 101 deletions(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 51385bba5aca..7a04cc761b48 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -909,8 +909,9 @@ int DetectAddressSetup(DetectAddressHead *gh, char *s) * \retval 0 On successfully parsing. * \retval -1 On failure. */ -int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, - int negate) +static int DetectAddressParse2(const DetectEngineCtx *de_ctx, + DetectAddressHead *gh, DetectAddressHead *ghn, + char *s, int negate) { size_t x = 0; size_t u = 0; @@ -951,7 +952,7 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, /* normal block */ SCLogDebug("normal block"); - if (DetectAddressParse2(gh, ghn, address, (negate + n_set) % 2) < 0) + if (DetectAddressParse2(de_ctx, gh, ghn, address, (negate + n_set) % 2) < 0) goto error; } else { /* negated block @@ -964,7 +965,7 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, DetectAddressHead tmp_gh = { NULL, NULL, NULL }; DetectAddressHead tmp_ghn = { NULL, NULL, NULL }; - if (DetectAddressParse2(&tmp_gh, &tmp_ghn, address, 0) < 0) + if (DetectAddressParse2(de_ctx, &tmp_gh, &tmp_ghn, address, 0) < 0) goto error; DetectAddress *tmp_ad; @@ -1048,7 +1049,7 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } - DetectAddressParse2(gh, ghn, temp_rule_var_address, + DetectAddressParse2(de_ctx, gh, ghn, temp_rule_var_address, (negate + n_set) % 2); d_set = 0; n_set = 0; @@ -1100,7 +1101,7 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } - if (DetectAddressParse2(gh, ghn, temp_rule_var_address, + if (DetectAddressParse2(de_ctx, gh, ghn, temp_rule_var_address, (negate + n_set) % 2) < 0) { SCLogDebug("DetectAddressParse2 hates us"); goto error; @@ -1389,7 +1390,7 @@ int DetectAddressTestConfVars(void) goto error; } - int r = DetectAddressParse2(gh, ghn, seq_node->val, /* start with negate no */0); + int r = DetectAddressParse2(NULL, gh, ghn, seq_node->val, /* start with negate no */0); if (r < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "failed to parse address var \"%s\" with value \"%s\". " @@ -1429,7 +1430,8 @@ int DetectAddressTestConfVars(void) * \retval 0 On success. * \retval -1 On failure. */ -int DetectAddressParse(DetectAddressHead *gh, char *str) +int DetectAddressParse(const DetectEngineCtx *de_ctx, + DetectAddressHead *gh, char *str) { int r; DetectAddressHead *ghn = NULL; @@ -1447,7 +1449,7 @@ int DetectAddressParse(DetectAddressHead *gh, char *str) goto error; } - r = DetectAddressParse2(gh, ghn, str, /* start with negate no */0); + r = DetectAddressParse2(de_ctx, gh, ghn, str, /* start with negate no */0); if (r < 0) { SCLogDebug("DetectAddressParse2 returned %d", r); goto error; @@ -3164,7 +3166,7 @@ int AddressTestAddressGroupSetup01(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.4"); + int r = DetectAddressParse(NULL, gh, "1.2.3.4"); if (r == 0) result = 1; @@ -3179,7 +3181,7 @@ int AddressTestAddressGroupSetup02(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.4"); + int r = DetectAddressParse(NULL, gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head != NULL) result = 1; @@ -3194,11 +3196,11 @@ int AddressTestAddressGroupSetup03(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.4"); + int r = DetectAddressParse(NULL, gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.3"); + r = DetectAddressParse(NULL, gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { result = 1; @@ -3216,16 +3218,16 @@ int AddressTestAddressGroupSetup04(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.4"); + int r = DetectAddressParse(NULL, gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.3"); + r = DetectAddressParse(NULL, gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { DetectAddress *prev_head = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.2"); + r = DetectAddressParse(NULL, gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { result = 1; @@ -3244,16 +3246,16 @@ int AddressTestAddressGroupSetup05(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.2"); + int r = DetectAddressParse(NULL, gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.3"); + r = DetectAddressParse(NULL, gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next != prev_head) { DetectAddress *prev_head = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.4"); + r = DetectAddressParse(NULL, gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next != prev_head) { result = 1; @@ -3272,11 +3274,11 @@ int AddressTestAddressGroupSetup06(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.2"); + int r = DetectAddressParse(NULL, gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.2"); + r = DetectAddressParse(NULL, gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == NULL) { result = 1; @@ -3294,9 +3296,9 @@ int AddressTestAddressGroupSetup07(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.0.0.0/8"); + int r = DetectAddressParse(NULL, gh, "10.0.0.0/8"); if (r == 0 && gh->ipv4_head != NULL) { - r = DetectAddressParse(gh, "10.10.10.10"); + r = DetectAddressParse(NULL, gh, "10.10.10.10"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { @@ -3315,9 +3317,9 @@ int AddressTestAddressGroupSetup08(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.10.10.10"); + int r = DetectAddressParse(NULL, gh, "10.10.10.10"); if (r == 0 && gh->ipv4_head != NULL) { - r = DetectAddressParse(gh, "10.0.0.0/8"); + r = DetectAddressParse(NULL, gh, "10.0.0.0/8"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { @@ -3336,9 +3338,9 @@ int AddressTestAddressGroupSetup09(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.10.10.0/24"); + int r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0 && gh->ipv4_head != NULL) { - r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); + r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { @@ -3357,9 +3359,9 @@ int AddressTestAddressGroupSetup10(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); + int r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0 && gh->ipv4_head != NULL) { - r = DetectAddressParse(gh, "10.10.10.0/24"); + r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { @@ -3378,11 +3380,11 @@ int AddressTestAddressGroupSetup11(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); + int r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0) { - r = DetectAddressParse(gh, "10.10.10.0/24"); + r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0) { - r = DetectAddressParse(gh, "0.0.0.0/0"); + r = DetectAddressParse(NULL, gh, "0.0.0.0/0"); if (r == 0) { DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, *four = three->next, @@ -3417,11 +3419,11 @@ int AddressTestAddressGroupSetup12 (void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); + int r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0) { - r = DetectAddressParse(gh, "0.0.0.0/0"); + r = DetectAddressParse(NULL, gh, "0.0.0.0/0"); if (r == 0) { - r = DetectAddressParse(gh, "10.10.10.0/24"); + r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0) { DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, *four = three->next, @@ -3456,11 +3458,11 @@ int AddressTestAddressGroupSetup13(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "0.0.0.0/0"); + int r = DetectAddressParse(NULL, gh, "0.0.0.0/0"); if (r == 0) { - r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); + r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0) { - r = DetectAddressParse(gh, "10.10.10.0/24"); + r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0) { DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, *four = three->next, @@ -3495,7 +3497,7 @@ int AddressTestAddressGroupSetupIPv414(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "!1.2.3.4"); + int r = DetectAddressParse(NULL, gh, "!1.2.3.4"); if (r == 0) { DetectAddress *one = gh->ipv4_head; DetectAddress *two = one ? one->next : NULL; @@ -3529,7 +3531,7 @@ int AddressTestAddressGroupSetupIPv415(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "!0.0.0.0"); + int r = DetectAddressParse(NULL, gh, "!0.0.0.0"); if (r == 0) { DetectAddress *one = gh->ipv4_head; @@ -3553,7 +3555,7 @@ int AddressTestAddressGroupSetupIPv416(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "!255.255.255.255"); + int r = DetectAddressParse(NULL, gh, "!255.255.255.255"); if (r == 0) { DetectAddress *one = gh->ipv4_head; @@ -3577,7 +3579,7 @@ int AddressTestAddressGroupSetup14(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::1"); + int r = DetectAddressParse(NULL, gh, "2001::1"); if (r == 0) result = 1; @@ -3592,7 +3594,7 @@ int AddressTestAddressGroupSetup15(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::1"); + int r = DetectAddressParse(NULL, gh, "2001::1"); if (r == 0 && gh->ipv6_head != NULL) result = 1; @@ -3607,11 +3609,11 @@ int AddressTestAddressGroupSetup16(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4"); + int r = DetectAddressParse(NULL, gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::3"); + r = DetectAddressParse(NULL, gh, "2001::3"); if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { result = 1; @@ -3629,16 +3631,16 @@ int AddressTestAddressGroupSetup17(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4"); + int r = DetectAddressParse(NULL, gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::3"); + r = DetectAddressParse(NULL, gh, "2001::3"); if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { DetectAddress *prev_head = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::2"); + r = DetectAddressParse(NULL, gh, "2001::2"); if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { result = 1; @@ -3657,16 +3659,16 @@ int AddressTestAddressGroupSetup18(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::2"); + int r = DetectAddressParse(NULL, gh, "2001::2"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::3"); + r = DetectAddressParse(NULL, gh, "2001::3"); if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next != prev_head) { DetectAddress *prev_head = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::4"); + r = DetectAddressParse(NULL, gh, "2001::4"); if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next != prev_head) { result = 1; @@ -3685,11 +3687,11 @@ int AddressTestAddressGroupSetup19(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::2"); + int r = DetectAddressParse(NULL, gh, "2001::2"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::2"); + r = DetectAddressParse(NULL, gh, "2001::2"); if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == NULL) { result = 1; @@ -3707,9 +3709,9 @@ int AddressTestAddressGroupSetup20(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2000::/3"); + int r = DetectAddressParse(NULL, gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL) { - r = DetectAddressParse(gh, "2001::4"); + r = DetectAddressParse(NULL, gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { @@ -3728,9 +3730,9 @@ int AddressTestAddressGroupSetup21(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4"); + int r = DetectAddressParse(NULL, gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL) { - r = DetectAddressParse(gh, "2000::/3"); + r = DetectAddressParse(NULL, gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { @@ -3749,9 +3751,9 @@ int AddressTestAddressGroupSetup22(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2000::/3"); + int r = DetectAddressParse(NULL, gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL) { - r = DetectAddressParse(gh, "2001::4-2001::6"); + r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { @@ -3770,9 +3772,9 @@ int AddressTestAddressGroupSetup23(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4-2001::6"); + int r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0 && gh->ipv6_head != NULL) { - r = DetectAddressParse(gh, "2000::/3"); + r = DetectAddressParse(NULL, gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { @@ -3791,11 +3793,11 @@ int AddressTestAddressGroupSetup24(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4-2001::6"); + int r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0) { - r = DetectAddressParse(gh, "2001::/3"); + r = DetectAddressParse(NULL, gh, "2001::/3"); if (r == 0) { - r = DetectAddressParse(gh, "::/0"); + r = DetectAddressParse(NULL, gh, "::/0"); if (r == 0) { DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, *four = three->next, @@ -3861,11 +3863,11 @@ int AddressTestAddressGroupSetup25(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4-2001::6"); + int r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0) { - r = DetectAddressParse(gh, "::/0"); + r = DetectAddressParse(NULL, gh, "::/0"); if (r == 0) { - r = DetectAddressParse(gh, "2001::/3"); + r = DetectAddressParse(NULL, gh, "2001::/3"); if (r == 0) { DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, *four = three->next, @@ -3931,11 +3933,11 @@ int AddressTestAddressGroupSetup26(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "::/0"); + int r = DetectAddressParse(NULL, gh, "::/0"); if (r == 0) { - r = DetectAddressParse(gh, "2001::4-2001::6"); + r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0) { - r = DetectAddressParse(gh, "2001::/3"); + r = DetectAddressParse(NULL, gh, "2001::/3"); if (r == 0) { DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, *four = three->next, @@ -4001,7 +4003,7 @@ int AddressTestAddressGroupSetup27(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.2.3.4]"); + int r = DetectAddressParse(NULL, gh, "[1.2.3.4]"); if (r == 0) result = 1; @@ -4016,7 +4018,7 @@ int AddressTestAddressGroupSetup28(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.2.3.4,4.3.2.1]"); + int r = DetectAddressParse(NULL, gh, "[1.2.3.4,4.3.2.1]"); if (r == 0) result = 1; @@ -4031,7 +4033,7 @@ int AddressTestAddressGroupSetup29(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.2.3.4,4.3.2.1,10.10.10.10]"); + int r = DetectAddressParse(NULL, gh, "[1.2.3.4,4.3.2.1,10.10.10.10]"); if (r == 0) result = 1; @@ -4046,7 +4048,7 @@ int AddressTestAddressGroupSetup30(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[[1.2.3.4,2.3.4.5],4.3.2.1,[10.10.10.10,11.11.11.11]]"); + int r = DetectAddressParse(NULL, gh, "[[1.2.3.4,2.3.4.5],4.3.2.1,[10.10.10.10,11.11.11.11]]"); if (r == 0) result = 1; @@ -4061,7 +4063,7 @@ int AddressTestAddressGroupSetup31(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[[1.2.3.4,[2.3.4.5,3.4.5.6]],4.3.2.1,[10.10.10.10,[11.11.11.11,12.12.12.12]]]"); + int r = DetectAddressParse(NULL, gh, "[[1.2.3.4,[2.3.4.5,3.4.5.6]],4.3.2.1,[10.10.10.10,[11.11.11.11,12.12.12.12]]]"); if (r == 0) result = 1; @@ -4076,7 +4078,7 @@ int AddressTestAddressGroupSetup32(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[[1.2.3.4,[2.3.4.5,[3.4.5.6,4.5.6.7]]],4.3.2.1,[10.10.10.10,[11.11.11.11,[12.12.12.12,13.13.13.13]]]]"); + int r = DetectAddressParse(NULL, gh, "[[1.2.3.4,[2.3.4.5,[3.4.5.6,4.5.6.7]]],4.3.2.1,[10.10.10.10,[11.11.11.11,[12.12.12.12,13.13.13.13]]]]"); if (r == 0) result = 1; @@ -4091,7 +4093,7 @@ int AddressTestAddressGroupSetup33(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "![1.1.1.1,[2.2.2.2,[3.3.3.3,4.4.4.4]]]"); + int r = DetectAddressParse(NULL, gh, "![1.1.1.1,[2.2.2.2,[3.3.3.3,4.4.4.4]]]"); if (r == 0) result = 1; @@ -4106,7 +4108,7 @@ int AddressTestAddressGroupSetup34(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.0.0.0/8,![1.1.1.1,[1.2.1.1,1.3.1.1]]]"); + int r = DetectAddressParse(NULL, gh, "[1.0.0.0/8,![1.1.1.1,[1.2.1.1,1.3.1.1]]]"); if (r == 0) result = 1; @@ -4121,7 +4123,7 @@ int AddressTestAddressGroupSetup35(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.0.0.0/8,[2.0.0.0/8,![1.1.1.1,2.2.2.2]]]"); + int r = DetectAddressParse(NULL, gh, "[1.0.0.0/8,[2.0.0.0/8,![1.1.1.1,2.2.2.2]]]"); if (r == 0) result = 1; @@ -4136,7 +4138,7 @@ int AddressTestAddressGroupSetup36 (void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.0.0.0/8,[2.0.0.0/8,[3.0.0.0/8,!1.1.1.1]]]"); + int r = DetectAddressParse(NULL, gh, "[1.0.0.0/8,[2.0.0.0/8,[3.0.0.0/8,!1.1.1.1]]]"); if (r == 0) result = 1; @@ -4151,7 +4153,7 @@ int AddressTestAddressGroupSetup37(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[0.0.0.0/0,::/0]"); + int r = DetectAddressParse(NULL, gh, "[0.0.0.0/0,::/0]"); if (r == 0) result = 1; @@ -4170,7 +4172,7 @@ static int AddressTestAddressGroupSetup38(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "![192.168.0.0/16,!192.168.14.0/24]"); + int r = DetectAddressParse(NULL, gh, "![192.168.0.0/16,!192.168.14.0/24]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 3, expectations) == TRUE) result = 1; @@ -4191,7 +4193,7 @@ static int AddressTestAddressGroupSetup39(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[![192.168.0.0/16,!192.168.14.0/24]]"); + int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,!192.168.14.0/24]]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 3, expectations) == TRUE) result = 1; @@ -4211,7 +4213,7 @@ static int AddressTestAddressGroupSetup40(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[![192.168.0.0/16,[!192.168.14.0/24]]]"); + int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,[!192.168.14.0/24]]]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 3, expectations) == TRUE) result = 1; @@ -4231,7 +4233,7 @@ static int AddressTestAddressGroupSetup41(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[![192.168.0.0/16,![192.168.14.0/24]]]"); + int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,![192.168.14.0/24]]]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 3, expectations) == TRUE) result = 1; @@ -4249,7 +4251,7 @@ static int AddressTestAddressGroupSetup42(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[2001::/3]"); + int r = DetectAddressParse(NULL, gh, "[2001::/3]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 1, expectations) == TRUE) result = 1; @@ -4268,7 +4270,7 @@ static int AddressTestAddressGroupSetup43(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[2001::/3,!3000::/5]"); + int r = DetectAddressParse(NULL, gh, "[2001::/3,!3000::/5]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 2, expectations) == TRUE) result = 1; @@ -4286,7 +4288,7 @@ static int AddressTestAddressGroupSetup44(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "3ffe:ffff:7654:feda:1245:ba98:3210:4562/96"); + int r = DetectAddressParse(NULL, gh, "3ffe:ffff:7654:feda:1245:ba98:3210:4562/96"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 1, expectations) == TRUE) result = 1; @@ -4302,7 +4304,7 @@ static int AddressTestAddressGroupSetup45(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[192.168.1.3,!192.168.0.0/16]"); + int r = DetectAddressParse(NULL, gh, "[192.168.1.3,!192.168.0.0/16]"); if (r != 0) { result = 1; } @@ -4322,7 +4324,7 @@ static int AddressTestAddressGroupSetup46(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24]]]"); + int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24]]]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 4, expectations) == TRUE) result = 1; @@ -4345,7 +4347,7 @@ static int AddressTestAddressGroupSetup47(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]]"); + int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 5, expectations) == TRUE) result = 1; @@ -4367,7 +4369,7 @@ static int AddressTestAddressGroupSetup48(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]"); + int r = DetectAddressParse(NULL, gh, "[192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 4, expectations) == TRUE) result = 1; diff --git a/src/detect-engine-address.h b/src/detect-engine-address.h index f185b7abde8f..b29cff1b4c92 100644 --- a/src/detect-engine-address.h +++ b/src/detect-engine-address.h @@ -33,7 +33,7 @@ void DetectAddressHeadFree(DetectAddressHead *); void DetectAddressHeadCleanup(DetectAddressHead *); int DetectAddressParseString(DetectAddress *, char *); -int DetectAddressParse(DetectAddressHead *, char *); +int DetectAddressParse(const DetectEngineCtx *, DetectAddressHead *, char *); DetectAddress *DetectAddressInit(void); void DetectAddressFree(DetectAddress *); diff --git a/src/detect-parse.c b/src/detect-parse.c index 9bc0d035c539..15504b21dabb 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -552,10 +552,12 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, return -1; } -/* XXX implement this for real +/** \brief Parse address string and update signature * + * \retval 0 ok, -1 error */ -int SigParseAddress(Signature *s, const char *addrstr, char flag) +int SigParseAddress(const DetectEngineCtx *de_ctx, + Signature *s, const char *addrstr, char flag) { SCLogDebug("Address Group \"%s\" to be parsed now", addrstr); @@ -564,13 +566,13 @@ int SigParseAddress(Signature *s, const char *addrstr, char flag) if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_SRC_ANY; - if (DetectAddressParse(&s->src, (char *)addrstr) < 0) + if (DetectAddressParse(de_ctx, &s->src, (char *)addrstr) < 0) goto error; } else { if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_DST_ANY; - if (DetectAddressParse(&s->dst, (char *)addrstr) < 0) + if (DetectAddressParse(de_ctx, &s->dst, (char *)addrstr) < 0) goto error; } @@ -737,7 +739,8 @@ int SigParseAction(Signature *s, const char *action) * \internal * \brief split a signature string into a few blocks for further parsing */ -static int SigParseBasics(Signature *s, char *sigstr, SignatureParser *parser, uint8_t addrs_direction) +static int SigParseBasics(const DetectEngineCtx *de_ctx, + Signature *s, const char *sigstr, SignatureParser *parser, uint8_t addrs_direction) { #define MAX_SUBSTRINGS 30 int ov[MAX_SUBSTRINGS]; @@ -784,10 +787,10 @@ static int SigParseBasics(Signature *s, char *sigstr, SignatureParser *parser, u s->init_flags |= SIG_FLAG_INIT_BIDIREC; /* Parse Address & Ports */ - if (SigParseAddress(s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) + if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) goto error; - if (SigParseAddress(s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0) + if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0) goto error; /* For IPOnly */ @@ -832,7 +835,7 @@ int SigParse(DetectEngineCtx *de_ctx, Signature *s, char *sigstr, uint8_t addrs_ s->sig_str = sigstr; - int ret = SigParseBasics(s, sigstr, &parser, addrs_direction); + int ret = SigParseBasics(de_ctx, s, sigstr, &parser, addrs_direction); if (ret < 0) { SCLogDebug("SigParseBasics failed"); SCReturnInt(-1); From 3083f51cc6bfe3708f9cfb1050ef8c66dda09769 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 1 Mar 2015 12:34:11 +0100 Subject: [PATCH 0319/2553] detect:pass DetectEngineCtx to port parsing Preparation for prefix handling in port parsing. --- src/app-layer-detect-proto.c | 2 +- src/detect-engine-port.c | 86 ++++++++++++++++++------------------ src/detect-engine-port.h | 2 +- src/detect-parse.c | 13 +++--- 4 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 123b3248816f..c9c406de53ec 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1391,7 +1391,7 @@ void AppLayerProtoDetectPPRegister(uint8_t ipproto, SCEnter(); DetectPort *head = NULL; - DetectPortParse(&head, portstr); + DetectPortParse(NULL,&head, portstr); DetectPort *temp_dp = head; while (temp_dp != NULL) { uint32_t port = temp_dp->port; diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index 2583f018d572..826f7a9d5b9b 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -1023,8 +1023,9 @@ static int DetectPortParseInsertString(DetectPort **head, char *s) * \retval 0 On successfully parsing. * \retval -1 On failure. */ -static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, - int negate) +static int DetectPortParseDo(const DetectEngineCtx *de_ctx, + DetectPort **head, DetectPort **nhead, + char *s, int negate) { size_t u = 0; size_t x = 0; @@ -1064,7 +1065,7 @@ static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, SCLogDebug("Parsed port from DetectPortParseDo - %s", address); x = 0; - r = DetectPortParseDo(head, nhead, address, negate? negate: n_set); + r = DetectPortParseDo(de_ctx, head, nhead, address, negate? negate: n_set); if (r == -1) goto error; @@ -1101,7 +1102,7 @@ static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, "[%s]", rule_var_port); temp_rule_var_port = alloc_rule_var_port; } - r = DetectPortParseDo(head, nhead, temp_rule_var_port, + r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port, (negate + n_set) % 2);//negate? negate: n_set); if (r == -1) goto error; @@ -1161,7 +1162,7 @@ static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, "[%s]", rule_var_port); temp_rule_var_port = alloc_rule_var_port; } - r = DetectPortParseDo(head, nhead, temp_rule_var_port, + r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port, (negate + n_set) % 2); if (r == -1) goto error; @@ -1360,7 +1361,7 @@ int DetectPortTestConfVars(void) goto error; } - int r = DetectPortParseDo(&gh, &ghn, seq_node->val, /* start with negate no */0); + int r = DetectPortParseDo(NULL, &gh, &ghn, seq_node->val, /* start with negate no */0); if (r < 0) { DetectPortCleanupList(gh); goto error; @@ -1398,7 +1399,8 @@ int DetectPortTestConfVars(void) * \retval 0 on success * \retval -1 on error */ -int DetectPortParse(DetectPort **head, char *str) +int DetectPortParse(const DetectEngineCtx *de_ctx, + DetectPort **head, char *str) { int r; @@ -1407,7 +1409,7 @@ int DetectPortParse(DetectPort **head, char *str) /* negate port list */ DetectPort *nhead = NULL; - r = DetectPortParseDo(head, &nhead, str,/* start with negate no */0); + r = DetectPortParseDo(de_ctx, head, &nhead, str,/* start with negate no */0); if (r < 0) goto error; @@ -1719,7 +1721,7 @@ int PortTestParse01 (void) { DetectPort *dd = NULL; - int r = DetectPortParse(&dd,"80"); + int r = DetectPortParse(NULL,&dd,"80"); if (r == 0) { DetectPortFree(dd); return 1; @@ -1736,9 +1738,9 @@ int PortTestParse02 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"80"); + int r = DetectPortParse(NULL,&dd,"80"); if (r == 0) { - r = DetectPortParse(&dd,"22"); + r = DetectPortParse(NULL,&dd,"22"); if (r == 0) { result = 1; } @@ -1758,9 +1760,9 @@ int PortTestParse03 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"80:88"); + int r = DetectPortParse(NULL,&dd,"80:88"); if (r == 0) { - r = DetectPortParse(&dd,"85:100"); + r = DetectPortParse(NULL,&dd,"85:100"); if (r == 0) { result = 1; } @@ -1780,7 +1782,7 @@ int PortTestParse04 (void) { DetectPort *dd = NULL; - int r = DetectPortParse(&dd,"!80:81"); + int r = DetectPortParse(NULL,&dd,"!80:81"); if (r == 0) { DetectPortCleanupList(dd); return 1; @@ -1798,7 +1800,7 @@ int PortTestParse05 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"!80:81"); + int r = DetectPortParse(NULL,&dd,"!80:81"); if (r != 0) goto end; @@ -1825,15 +1827,15 @@ int PortTestParse06 (void) DetectPort *dd = NULL, *copy = NULL; int result = 0; - int r = DetectPortParse(&dd,"22"); + int r = DetectPortParse(NULL,&dd,"22"); if (r != 0) goto end; - r = DetectPortParse(&dd,"80"); + r = DetectPortParse(NULL,&dd,"80"); if (r != 0) goto end; - r = DetectPortParse(&dd,"143"); + r = DetectPortParse(NULL,&dd,"143"); if (r != 0) goto end; @@ -1879,7 +1881,7 @@ int PortTestParse07 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"!21:902"); + int r = DetectPortParse(NULL,&dd,"!21:902"); if (r != 0) goto end; @@ -1906,7 +1908,7 @@ int PortTestParse08 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"[80:!80]"); + int r = DetectPortParse(NULL,&dd,"[80:!80]"); if (r == 0) goto end; @@ -1924,7 +1926,7 @@ int PortTestParse09 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"1024:"); + int r = DetectPortParse(NULL,&dd,"1024:"); if (r != 0) goto end; @@ -1948,7 +1950,7 @@ int PortTestParse10 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"77777777777777777777777777777777777777777777"); + int r = DetectPortParse(NULL,&dd,"77777777777777777777777777777777777777777777"); if (r != 0) { result = 1 ; goto end; @@ -1968,7 +1970,7 @@ int PortTestParse11 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"1024:65536"); + int r = DetectPortParse(NULL,&dd,"1024:65536"); if (r != 0) { result = 1 ; goto end; @@ -1988,7 +1990,7 @@ int PortTestParse12 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"1024:65535"); + int r = DetectPortParse(NULL,&dd,"1024:65535"); if (r != 0) { goto end; } @@ -2008,7 +2010,7 @@ int PortTestParse13 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"65536:65535"); + int r = DetectPortParse(NULL,&dd,"65536:65535"); if (r != 0) { result = 1 ; goto end; @@ -2055,7 +2057,7 @@ int PortTestParse15 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"![0:100,1000:3000]"); + int r = DetectPortParse(NULL,&dd,"![0:100,1000:3000]"); if (r != 0 || dd->next == NULL) goto end; @@ -2079,15 +2081,15 @@ int PortTestParse16 (void) DetectPort *dd = NULL, *copy = NULL; int result = 0; - int r = DetectPortParse(&dd,"22"); + int r = DetectPortParse(NULL,&dd,"22"); if (r != 0) goto end; - r = DetectPortParse(&dd,"80"); + r = DetectPortParse(NULL,&dd,"80"); if (r != 0) goto end; - r = DetectPortParse(&dd,"143"); + r = DetectPortParse(NULL,&dd,"143"); if (r != 0) goto end; @@ -2135,7 +2137,7 @@ int PortTestFunctions01(void) int result = 0; /* Parse */ - int r = DetectPortParse(&head,"![0:100,1000:65535]"); + int r = DetectPortParse(NULL,&head,"![0:100,1000:65535]"); if (r != 0 || head->next != NULL) goto end; @@ -2147,7 +2149,7 @@ int PortTestFunctions01(void) if (!(head->next == NULL)) goto end; - r = DetectPortParse(&dp1,"2000:3000"); + r = DetectPortParse(NULL, &dp1,"2000:3000"); if (r != 0 || dp1->next != NULL) goto end; if (!(dp1->port == 2000)) @@ -2198,11 +2200,11 @@ int PortTestFunctions02(void) int result = 0; /* Parse */ - int r = DetectPortParse(&head, "![0:100,1000:65535]"); + int r = DetectPortParse(NULL,&head, "![0:100,1000:65535]"); if (r != 0 || head->next != NULL) goto end; - r = DetectPortParse(&dp1, "!200:300"); + r = DetectPortParse(NULL, &dp1, "!200:300"); if (r != 0 || dp1->next == NULL) goto end; @@ -2211,7 +2213,7 @@ int PortTestFunctions02(void) if (r != 0 || head->next != NULL) goto end; - r = DetectPortParse(&dp2, "!100:500"); + r = DetectPortParse(NULL, &dp2, "!100:500"); if (r != 0 || dp2->next == NULL) goto end; @@ -2247,11 +2249,11 @@ int PortTestFunctions03(void) DetectPort *dp3= NULL; int result = 0; - int r = DetectPortParse(&dp1, "200:300"); + int r = DetectPortParse(NULL, &dp1, "200:300"); if (r != 0) goto end; - r = DetectPortParse(&dp2, "250:300"); + r = DetectPortParse(NULL, &dp2, "250:300"); if (r != 0) goto end; @@ -2312,7 +2314,7 @@ int PortTestFunctions04(void) DetectPort *dp2= NULL; int result = 0; - int r = DetectPortParse(&dp1, "200:300"); + int r = DetectPortParse(NULL, &dp1, "200:300"); if (r != 0) goto end; @@ -2359,14 +2361,14 @@ static int PortTestFunctions05(void) s[0].num = 0; s[1].num = 1; - r = DetectPortParse(&dp1, "1024:65535"); + r = DetectPortParse(NULL, &dp1, "1024:65535"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; } SigGroupHeadAppendSig(de_ctx, &dp1->sh, &s[0]); - r = DetectPortParse(&dp2, "any"); + r = DetectPortParse(NULL, &dp2, "any"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; @@ -2437,14 +2439,14 @@ static int PortTestFunctions06(void) s[0].num = 0; s[1].num = 1; - r = DetectPortParse(&dp1, "1024:65535"); + r = DetectPortParse(NULL, &dp1, "1024:65535"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; } SigGroupHeadAppendSig(de_ctx, &dp1->sh, &s[0]); - r = DetectPortParse(&dp2, "any"); + r = DetectPortParse(NULL, &dp2, "any"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; @@ -2784,7 +2786,7 @@ static int PortTestMatchDoubleNegation(void) int result = 0; DetectPort *head = NULL, *nhead = NULL; - if (DetectPortParseDo(&head, &nhead, "![!80]", 0) == -1) + if (DetectPortParseDo(NULL, &head, &nhead, "![!80]", 0) == -1) return result; result = (head != NULL); diff --git a/src/detect-engine-port.h b/src/detect-engine-port.h index bfba92d19a61..e23c1e476e63 100644 --- a/src/detect-engine-port.h +++ b/src/detect-engine-port.h @@ -25,7 +25,7 @@ #define __DETECT_PORT_H__ /* prototypes */ -int DetectPortParse(DetectPort **head, char *str); +int DetectPortParse(const DetectEngineCtx *, DetectPort **head, char *str); DetectPort *DetectPortCopy(DetectEngineCtx *, DetectPort *); DetectPort *DetectPortCopySingle(DetectEngineCtx *, DetectPort *); diff --git a/src/detect-parse.c b/src/detect-parse.c index 15504b21dabb..fa1bb35dd480 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -638,7 +638,8 @@ int SigParseProto(Signature *s, const char *protostr) * \retval 0 On success. * \retval -1 On failure. */ -int SigParsePort(Signature *s, const char *portstr, char flag) +static int SigParsePort(const DetectEngineCtx *de_ctx, + Signature *s, const char *portstr, char flag) { int r = 0; @@ -650,12 +651,12 @@ int SigParsePort(Signature *s, const char *portstr, char flag) if (strcasecmp(portstr, "any") == 0) s->flags |= SIG_FLAG_SP_ANY; - r = DetectPortParse(&s->sp, (char *)portstr); + r = DetectPortParse(de_ctx, &s->sp, (char *)portstr); } else if (flag == 1) { if (strcasecmp(portstr, "any") == 0) s->flags |= SIG_FLAG_DP_ANY; - r = DetectPortParse(&s->dp, (char *)portstr); + r = DetectPortParse(de_ctx, &s->dp, (char *)portstr); } if (r < 0) @@ -804,9 +805,9 @@ static int SigParseBasics(const DetectEngineCtx *de_ctx, * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp * changes that we made sees to it that at this point of time we don't * set the ip proto for the sig. We do it a bit later. */ - if (SigParsePort(s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0) + if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0) goto error; - if (SigParsePort(s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0) + if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0) goto error; return 0; @@ -1925,7 +1926,7 @@ int SigParseTest02 (void) goto end; } - int r = DetectPortParse(&port, "0:20"); + int r = DetectPortParse(de_ctx, &port, "0:20"); if (r < 0) goto end; From 0bc27c7dc7f5e4c0e30c1a703f1b1545c91ef3b8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 1 Mar 2015 20:30:01 +0100 Subject: [PATCH 0320/2553] rule-vars: take detect engine as arg --- src/detect-engine-address.c | 4 +-- src/detect-engine-iponly.c | 33 +++++++++++---------- src/detect-engine-iponly.h | 2 +- src/detect-engine-port.c | 4 +-- src/detect-parse.c | 4 +-- src/util-rule-vars.c | 59 +++++++++++++++++++------------------ src/util-rule-vars.h | 2 +- 7 files changed, 56 insertions(+), 52 deletions(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 7a04cc761b48..19b960a79b94 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -1029,7 +1029,7 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, } else if (d_set == 1) { address[x - 1] = '\0'; - rule_var_address = SCRuleVarsGetConfVar(address, + rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; @@ -1081,7 +1081,7 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, x = 0; if (d_set == 1) { - rule_var_address = SCRuleVarsGetConfVar(address, + rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index d98fa0e50c32..bc876a188844 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -581,7 +581,8 @@ static void SigNumArrayFree(void *tmp) * \retval 0 if success * \retval -1 if fails */ -static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) +static IPOnlyCIDRItem *IPOnlyCIDRListParse2(const DetectEngineCtx *de_ctx, + char *s, int negate) { size_t x = 0; size_t u = 0; @@ -615,7 +616,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) address[x - 1] = '\0'; x = 0; - if ( (subhead = IPOnlyCIDRListParse2(address, + if ( (subhead = IPOnlyCIDRListParse2(de_ctx, address, (negate + n_set) % 2)) == NULL) goto error; @@ -629,7 +630,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) } else if (d_set == 1) { address[x - 1] = '\0'; - rule_var_address = SCRuleVarsGetConfVar(address, + rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; @@ -646,7 +647,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) "[%s]", rule_var_address); } - subhead = IPOnlyCIDRListParse2(temp_rule_var_address, + subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address, (negate + n_set) % 2); head = IPOnlyCIDRItemInsert(head, subhead); @@ -689,7 +690,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) x = 0; if (d_set == 1) { - rule_var_address = SCRuleVarsGetConfVar(address, + rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; @@ -703,7 +704,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } - subhead = IPOnlyCIDRListParse2(temp_rule_var_address, + subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address, (negate + n_set) % 2); head = IPOnlyCIDRItemInsert(head, subhead); @@ -751,14 +752,15 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) * \retval 0 On success. * \retval -1 On failure. */ -static int IPOnlyCIDRListParse(IPOnlyCIDRItem **gh, char *str) +static int IPOnlyCIDRListParse(const DetectEngineCtx *de_ctx, + IPOnlyCIDRItem **gh, char *str) { SCLogDebug("gh %p, str %s", gh, str); if (gh == NULL) goto error; - *gh = IPOnlyCIDRListParse2(str, 0); + *gh = IPOnlyCIDRListParse2(de_ctx, str, 0); if (*gh == NULL) { SCLogDebug("DetectAddressParse2 returned null"); goto error; @@ -782,7 +784,8 @@ static int IPOnlyCIDRListParse(IPOnlyCIDRItem **gh, char *str) * \retval 0 On success. * \retval -1 On failure. */ -int IPOnlySigParseAddress(Signature *s, const char *addrstr, char flag) +int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx, + Signature *s, const char *addrstr, char flag) { SCLogDebug("Address Group \"%s\" to be parsed now", addrstr); IPOnlyCIDRItem *tmp = NULL; @@ -792,15 +795,15 @@ int IPOnlySigParseAddress(Signature *s, const char *addrstr, char flag) if (strcasecmp(addrstr, "any") == 0) { s->flags |= SIG_FLAG_SRC_ANY; - if (IPOnlyCIDRListParse(&s->CidrSrc, (char *)"0.0.0.0/0") < 0) + if (IPOnlyCIDRListParse(de_ctx, &s->CidrSrc, (char *)"0.0.0.0/0") < 0) goto error; - if (IPOnlyCIDRListParse(&tmp, (char *)"::/0") < 0) + if (IPOnlyCIDRListParse(de_ctx, &tmp, (char *)"::/0") < 0) goto error; s->CidrSrc = IPOnlyCIDRItemInsert(s->CidrSrc, tmp); - } else if (IPOnlyCIDRListParse(&s->CidrSrc, (char *)addrstr) < 0) { + } else if (IPOnlyCIDRListParse(de_ctx, &s->CidrSrc, (char *)addrstr) < 0) { goto error; } @@ -809,15 +812,15 @@ int IPOnlySigParseAddress(Signature *s, const char *addrstr, char flag) if (strcasecmp(addrstr, "any") == 0) { s->flags |= SIG_FLAG_DST_ANY; - if (IPOnlyCIDRListParse(&tmp, (char *)"0.0.0.0/0") < 0) + if (IPOnlyCIDRListParse(de_ctx, &tmp, (char *)"0.0.0.0/0") < 0) goto error; - if (IPOnlyCIDRListParse(&s->CidrDst, (char *)"::/0") < 0) + if (IPOnlyCIDRListParse(de_ctx, &s->CidrDst, (char *)"::/0") < 0) goto error; s->CidrDst = IPOnlyCIDRItemInsert(s->CidrDst, tmp); - } else if (IPOnlyCIDRListParse(&s->CidrDst, (char *)addrstr) < 0) { + } else if (IPOnlyCIDRListParse(de_ctx, &s->CidrDst, (char *)addrstr) < 0) { goto error; } diff --git a/src/detect-engine-iponly.h b/src/detect-engine-iponly.h index 599a11157e4d..b71a59337dcd 100644 --- a/src/detect-engine-iponly.h +++ b/src/detect-engine-iponly.h @@ -36,7 +36,7 @@ typedef struct SigNumArray_ { } SigNumArray; void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead); -int IPOnlySigParseAddress(Signature *, const char *, char); +int IPOnlySigParseAddress(const DetectEngineCtx *, Signature *, const char *, char); void IPOnlyMatchPacket(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, DetectEngineIPOnlyCtx *, DetectEngineIPOnlyThreadCtx *, Packet *); diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index 826f7a9d5b9b..6d3d5208eb48 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -1082,7 +1082,7 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, address[x - 1] = '\0'; - rule_var_port = SCRuleVarsGetConfVar(address, + rule_var_port = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_PORT_GROUPS); if (rule_var_port == NULL) goto error; @@ -1142,7 +1142,7 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, char *temp_rule_var_port = NULL, *alloc_rule_var_port = NULL; - rule_var_port = SCRuleVarsGetConfVar(address, + rule_var_port = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_PORT_GROUPS); if (rule_var_port == NULL) goto error; diff --git a/src/detect-parse.c b/src/detect-parse.c index fa1bb35dd480..0f65cd466e10 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -795,10 +795,10 @@ static int SigParseBasics(const DetectEngineCtx *de_ctx, goto error; /* For IPOnly */ - if (IPOnlySigParseAddress(s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) + if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) goto error; - if (IPOnlySigParseAddress(s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0) + if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0) goto error; /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp, diff --git a/src/util-rule-vars.c b/src/util-rule-vars.c index bf7515f82e23..32cfa78bb4e2 100644 --- a/src/util-rule-vars.c +++ b/src/util-rule-vars.c @@ -62,7 +62,8 @@ SCEnumCharMap sc_rule_vars_type_map[ ] = { * \retval conf_var_name_value Pointer to the string containing the conf value * on success; NULL on failure. */ -char *SCRuleVarsGetConfVar(const char *conf_var_name, +char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx, + const char *conf_var_name, SCRuleVarsType conf_vars_type) { SCEnter(); @@ -180,44 +181,44 @@ int SCRuleVarsPositiveTest01(void) ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); /* check for address-groups */ - result &= (SCRuleVarsGetConfVar("$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), "[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:13c5:" "5AFE::/64,2001:888:13c5:CAFE::/64]") == 0); - result &= (SCRuleVarsGetConfVar("$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS), "[!192.168.0.0/16,2000::/3]") == 0); - result &= (SCRuleVarsGetConfVar("$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "!192.168.0.0/16") == 0); - result &= (SCRuleVarsGetConfVar("$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "!192.168.0.0/16") == 0); - result &= (SCRuleVarsGetConfVar("$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "!192.168.0.0/16") == 0); - result &= (SCRuleVarsGetConfVar("$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "any") == 0); - result &= (SCRuleVarsGetConfVar("$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "any") == 0); - result &= (SCRuleVarsGetConfVar("$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "any") == 0); /* check for port-groups */ - result &= (SCRuleVarsGetConfVar("$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), "80:81,88") == 0); - result &= (SCRuleVarsGetConfVar("$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS), "80") == 0); - result &= (SCRuleVarsGetConfVar("$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS), "1521") == 0); - result &= (SCRuleVarsGetConfVar("$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS), "22") == 0); ConfDeInit(); @@ -238,11 +239,11 @@ int SCRuleVarsNegativeTest02(void) ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); - result &= (SCRuleVarsGetConfVar("$HOME_NETW", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); - result &= (SCRuleVarsGetConfVar("$home_net", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); + result &= (SCRuleVarsGetConfVar(NULL,"$HOME_NETW", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); + result &= (SCRuleVarsGetConfVar(NULL,"$home_net", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); - result &= (SCRuleVarsGetConfVar("$TOMCAT_PORTSW", SC_RULE_VARS_PORT_GROUPS) == NULL); - result &= (SCRuleVarsGetConfVar("$tomcat_ports", SC_RULE_VARS_PORT_GROUPS) == NULL); + result &= (SCRuleVarsGetConfVar(NULL,"$TOMCAT_PORTSW", SC_RULE_VARS_PORT_GROUPS) == NULL); + result &= (SCRuleVarsGetConfVar(NULL,"$tomcat_ports", SC_RULE_VARS_PORT_GROUPS) == NULL); ConfDeInit(); ConfRestoreContextBackup(); diff --git a/src/util-rule-vars.h b/src/util-rule-vars.h index 35f677ffb6d9..57d161e9f154 100644 --- a/src/util-rule-vars.h +++ b/src/util-rule-vars.h @@ -30,7 +30,7 @@ typedef enum { SC_RULE_VARS_PORT_GROUPS, } SCRuleVarsType; -char *SCRuleVarsGetConfVar(const char *, SCRuleVarsType); +char *SCRuleVarsGetConfVar(const DetectEngineCtx *, const char *, SCRuleVarsType); void SCRuleVarsRegisterTests(void); #endif /* __UTIL_RULE_VARS_H__ */ From 85e12f2bc6b75de14a9f324a879dff547118dcd6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 2 Mar 2015 08:59:44 +0100 Subject: [PATCH 0321/2553] rule vars: support prefix Support the detection engine's prefix when retrieving rule vars. --- src/util-rule-vars.c | 93 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 5 deletions(-) diff --git a/src/util-rule-vars.c b/src/util-rule-vars.c index 32cfa78bb4e2..f060a14af1cb 100644 --- a/src/util-rule-vars.c +++ b/src/util-rule-vars.c @@ -69,7 +69,7 @@ char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx, SCEnter(); const char *conf_var_type_name = NULL; - char conf_var_full_name[1024] = ""; + char conf_var_full_name[2048] = ""; char *conf_var_full_name_value = NULL; if (conf_var_name == NULL) @@ -80,9 +80,16 @@ char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx, if (conf_var_type_name == NULL) goto end; - if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s", - conf_var_type_name, conf_var_name) < 0) { - goto end; + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s.%s", + de_ctx->config_prefix, conf_var_type_name, conf_var_name) < 0) { + goto end; + } + } else { + if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s", + conf_var_type_name, conf_var_name) < 0) { + goto end; + } } if (ConfGet(conf_var_full_name, &conf_var_full_name_value) != 1) { @@ -423,16 +430,92 @@ int SCRuleVarsNegativeTest04(void) return result; } +static const char *dummy_mt_conf_string = + "%YAML 1.1\n" + "---\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"[1.2.3.4]\"\n" + " port-groups:\n" + " HTTP_PORTS: \"12345\"\n" + "multi-detect:\n" + " 0:\n" + " vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"[8.8.8.8]\"\n" + " port-groups:\n" + " HTTP_PORTS: \"54321\"\n" + "\n"; + +/** + * \test Check that valid address and port group vars are correctly retrieved + * from the configuration. + */ +int SCRuleVarsMTest01(void) +{ + int result = 0; + DetectEngineCtx *de_ctx = NULL; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_mt_conf_string, strlen(dummy_mt_conf_string)); + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + return 0; + de_ctx->flags |= DE_QUIET; + snprintf(de_ctx->config_prefix, sizeof(de_ctx->config_prefix), + "multi-detect.0"); + + /* check for address-groups */ + result = (SCRuleVarsGetConfVar(de_ctx,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(de_ctx,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), + "[8.8.8.8]") == 0); + if (result == 0) + goto end; + + result = (SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), + "[1.2.3.4]") == 0); + if (result == 0) + goto end; + + /* check for port-groups */ + result = (SCRuleVarsGetConfVar(de_ctx,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(de_ctx,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), + "54321") == 0); + if (result == 0) + goto end; + + result = (SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), + "12345") == 0); + if (result == 0) + goto end; + +end: + ConfDeInit(); + ConfRestoreContextBackup(); + + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + #endif /* UNITTESTS */ void SCRuleVarsRegisterTests(void) { - #ifdef UNITTESTS UtRegisterTest("SCRuleVarsPositiveTest01", SCRuleVarsPositiveTest01, 1); UtRegisterTest("SCRuleVarsNegativeTest02", SCRuleVarsNegativeTest02, 1); UtRegisterTest("SCRuleVarsPositiveTest03", SCRuleVarsPositiveTest03, 1); UtRegisterTest("SCRuleVarsNegativeTest04", SCRuleVarsNegativeTest04, 1); + + UtRegisterTest("SCRuleVarsMTest01", SCRuleVarsMTest01, 1); #endif return; From b51075e804189a50191581611fa5e21e57ae602f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 5 Mar 2015 13:00:33 +0100 Subject: [PATCH 0322/2553] detect: remove config at prefix Remove config at prefix when freeing a detect engine. --- src/detect-engine.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 688c41961584..df728ed05946 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -761,7 +761,10 @@ DetectEngineCtx *DetectEngineCtxInit(void) DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix) { - return DetectEngineCtxInitReal(0, prefix); + if (prefix == NULL || strlen(prefix) == 0) + return DetectEngineCtxInit(); + else + return DetectEngineCtxInitReal(0, prefix); } static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx) @@ -829,6 +832,19 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) DetectEngineCtxFreeThreadKeywordData(de_ctx); SRepDestroy(de_ctx); + + /* if we have a config prefix, remove the config from the tree */ + if (strlen(de_ctx->config_prefix) > 0) { + /* remove config */ + ConfNode *node = ConfGetNode(de_ctx->config_prefix); + if (node != NULL) { + ConfNodeRemove(node); /* frees node */ + } +#if 0 + ConfDump(); +#endif + } + SCFree(de_ctx); //DetectAddressGroupPrintMemory(); //DetectSigGroupPrintMemory(); From 71d01f06b920a632ca68a7111b550f95eab6b158 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 5 Mar 2015 13:04:33 +0100 Subject: [PATCH 0323/2553] detect reload: load config Load the YAML into a prefix "detect-engine-reloads.N" where N is the reload counter. This way we can load the updated config w/o overwriting the current one. --- src/detect-engine.c | 40 ++++++++++++++++++++++++++++++++++++++-- src/detect-engine.h | 2 +- src/suricata.c | 4 ++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index df728ed05946..4e9757af23a5 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1684,11 +1684,45 @@ void DetectEnginePruneFreeList(void) SCMutexUnlock(&master->lock); } -int DetectEngineReload(void) +static int reloads = 0; + +/** \brief Reload the detection engine + * + * \param filename YAML file to load for the detect config + * + * \retval -1 error + * \retval 0 ok + */ +int DetectEngineReload(const char *filename) { DetectEngineCtx *new_de_ctx = NULL; DetectEngineCtx *old_de_ctx = NULL; + char prefix[128] = ""; + if (filename != NULL) { + snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++); + + ConfNode *node = ConfGetNode(prefix); + if (node != NULL) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "reload %d already loaded", reloads-1); + return -1; + } + + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename); + return -1; + } + + node = ConfGetNode(prefix); + if (node == NULL) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename); + return -1; + } +#if 0 + ConfDump(); +#endif + } + /* get a reference to the current de_ctx */ old_de_ctx = DetectEngineGetCurrent(); if (old_de_ctx == NULL) @@ -1696,8 +1730,10 @@ int DetectEngineReload(void) SCLogDebug("get ref to old_de_ctx %p", old_de_ctx); /* get new detection engine */ - new_de_ctx = DetectEngineCtxInit(); + new_de_ctx = DetectEngineCtxInitWithPrefix(prefix); if (new_de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " + "context failed."); DetectEngineDeReference(&old_de_ctx); return -1; } diff --git a/src/detect-engine.h b/src/detect-engine.h index c664f50e2638..a7a0734d4d82 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -75,7 +75,7 @@ void DetectEnginePruneFreeList(void); int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx); DetectEngineCtx *DetectEngineReference(DetectEngineCtx *); void DetectEngineDeReference(DetectEngineCtx **de_ctx); -int DetectEngineReload(void); +int DetectEngineReload(const char *filename); int DetectEngineEnabled(void); /** diff --git a/src/suricata.c b/src/suricata.c index 36ceaffbb934..0cf908f15a9f 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2381,7 +2381,7 @@ int main(int argc, char **argv) if (suri.delayed_detect) { /* force 'reload', this will load the rules and swap engines */ - DetectEngineReload(); + DetectEngineReload(NULL); if (suri.rule_reload) { if (suri.sig_file != NULL) @@ -2415,7 +2415,7 @@ int main(int argc, char **argv) sighup_count--; } if (sigusr2_count > 0) { - DetectEngineReload(); + DetectEngineReload(conf_filename); sigusr2_count--; } From 7c9e015748db1c5c61505cbd2894507daa9a32c6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 5 Mar 2015 16:25:09 +0100 Subject: [PATCH 0324/2553] unix-socket: implement reload-rules Implement the reload-rules unix socket command. The unix command thread signals the main thread to do the reload and it waits for it to complete. --- src/detect-engine.c | 63 +++++++++++++++++++++++++++++++++++++++++++++ src/detect-engine.h | 6 +++++ src/suricata.c | 4 +++ src/unix-manager.c | 14 ++++++++-- 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 4e9757af23a5..f643594cf154 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -446,6 +446,69 @@ void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, return; } +/* code to control the main thread to do a reload */ + +enum DetectEngineSyncState { + IDLE, /**< ready to start a reload */ + RELOAD, /**< command main thread to do the reload */ + DONE, /**< main thread telling us reload is done */ +}; + + +typedef struct DetectEngineSyncer_ { + SCMutex m; + enum DetectEngineSyncState state; +} DetectEngineSyncer; + +static DetectEngineSyncer detect_sync = { SCMUTEX_INITIALIZER, IDLE }; + +/* tell main to start reloading */ +int DetectEngineReloadStart(void) +{ + int r = 0; + SCMutexLock(&detect_sync.m); + if (detect_sync.state == IDLE) { + detect_sync.state = RELOAD; + } else { + r = -1; + } + SCMutexUnlock(&detect_sync.m); + return r; +} + +/* main thread checks this to see if it should start */ +int DetectEngineReloadIsStart(void) +{ + int r = 0; + SCMutexLock(&detect_sync.m); + if (detect_sync.state == RELOAD) { + r = 1; + } + SCMutexUnlock(&detect_sync.m); + return r; +} + +/* main thread sets done when it's done */ +void DetectEngineReloadSetDone(void) +{ + SCMutexLock(&detect_sync.m); + detect_sync.state = DONE; + SCMutexUnlock(&detect_sync.m); +} + +/* caller loops this until it returns 1 */ +int DetectEngineReloadIsDone(void) +{ + int r = 0; + SCMutexLock(&detect_sync.m); + if (detect_sync.state == DONE) { + r = 1; + detect_sync.state = IDLE; + } + SCMutexUnlock(&detect_sync.m); + return r; +} + static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) { SCEnter(); diff --git a/src/detect-engine.h b/src/detect-engine.h index a7a0734d4d82..dfd7bae93a01 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -78,6 +78,12 @@ void DetectEngineDeReference(DetectEngineCtx **de_ctx); int DetectEngineReload(const char *filename); int DetectEngineEnabled(void); +int DetectEngineReloadStart(void); +int DetectEngineReloadIsStart(void); +void DetectEngineReloadSetDone(void); +int DetectEngineReloadIsDone(void); + + /** * \brief Registers an app inspection engine. * diff --git a/src/suricata.c b/src/suricata.c index 0cf908f15a9f..c999611b2a0b 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2414,9 +2414,13 @@ int main(int argc, char **argv) OutputNotifyFileRotation(); sighup_count--; } + if (sigusr2_count > 0) { DetectEngineReload(conf_filename); sigusr2_count--; + } else if (DetectEngineReloadIsStart()) { + DetectEngineReload(conf_filename); + DetectEngineReloadSetDone(); } usleep(10* 1000); diff --git a/src/unix-manager.c b/src/unix-manager.c index 6863db349455..e86bae81aab9 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -647,6 +647,18 @@ TmEcode UnixManagerCaptureModeCommand(json_t *cmd, SCReturnInt(TM_ECODE_OK); } +TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg, void *data) +{ + SCEnter(); + DetectEngineReloadStart(); + + while (DetectEngineReloadIsDone() == 0) + usleep(100); + + json_object_set_new(server_msg, "message", json_string("done")); + SCReturnInt(TM_ECODE_OK); +} + TmEcode UnixManagerConfGetCommand(json_t *cmd, json_t *server_msg, void *data) { @@ -870,9 +882,7 @@ void *UnixManagerThread(void *td) UnixManagerRegisterCommand("capture-mode", UnixManagerCaptureModeCommand, &command, 0); UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("dump-counters", SCPerfOutputCounterSocket, NULL, 0); -#if 0 UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0); -#endif TmThreadsSetFlag(th_v, THV_INIT_DONE); while (1) { From 724c7044e19e0e1624982720653eaf6b8c95606f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 16 Mar 2015 10:53:56 +0100 Subject: [PATCH 0325/2553] detect-reload: 0 detect threads is no error The reload code would consider 0 detect threads to be an error, but it's not in case of unix socket mode. --- src/detect-engine.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index f643594cf154..4bf33eaefadd 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -509,6 +509,19 @@ int DetectEngineReloadIsDone(void) return r; } +/** \internal + * \brief Update detect threads with new detect engine + * + * Atomically update each detect thread with a new thread context + * that is associated to the new detection engine(s). + * + * If called in unix socket mode, it's possible that we don't have + * detect threads yet. + * + * \retval -1 error + * \retval 0 no detection threads + * \retval 1 successful reload + */ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) { SCEnter(); @@ -517,8 +530,6 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) int no_of_detect_tvs = 0; ThreadVars *tv = NULL; - SCLogNotice("rule reload starting"); - /* count detect threads in use */ SCMutexLock(&tv_root_lock); tv = tv_root[TVT_PPT]; @@ -546,10 +557,13 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) } SCMutexUnlock(&tv_root_lock); + /* can be zero in unix socket mode */ if (no_of_detect_tvs == 0) { - return -1; + return 0; } + SCLogNotice("rule reload starting"); + /* prepare swap structures */ DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs]; DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs]; @@ -700,7 +714,7 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) SRepReloadComplete(); SCLogNotice("rule reload complete"); - return 0; + return 1; error: for (i = 0; i < no_of_detect_tvs; i++) { From 0704ece4d7414dc5ba9427e9a0446dee9f34e13e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 19 Mar 2015 17:20:27 +0100 Subject: [PATCH 0326/2553] detect-reload: enable unconditionally Reloading is available unconditionally now. --- src/detect.c | 4 +--- src/suricata.c | 50 +++++++++--------------------------------------- src/suricata.h | 1 - suricata.yaml.in | 3 --- 4 files changed, 10 insertions(+), 48 deletions(-) diff --git a/src/detect.c b/src/detect.c index 53953d4f2a9b..ed4d132b4b76 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2718,9 +2718,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) #ifdef HAVE_LUAJIT /* run this before the mpm states are initialized */ - if (DetectLuajitSetupStatesPool(de_ctx->detect_luajit_instances, - IsRuleReloadSet(TRUE)) - != 0) { + if (DetectLuajitSetupStatesPool(de_ctx->detect_luajit_instances, TRUE) != 0) { if (de_ctx->failure_fatal) return -1; } diff --git a/src/suricata.c b/src/suricata.c index c999611b2a0b..e4e3cb5ae148 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -276,11 +276,6 @@ static void SignalHandlerSigterm(/*@unused@*/ int sig) suricata_ctl_flags |= SURICATA_KILL; } -void SignalHandlerSigusr2Disabled(int sig) -{ - SCLogInfo("Live rule reload not enabled in config."); -} - void SignalHandlerSigusr2StartingUp(int sig) { SCLogInfo("Live rule reload only possible after engine completely started."); @@ -920,25 +915,6 @@ TmEcode LoadYamlConfig(char *conf_filename) SCReturnInt(TM_ECODE_OK); } -int IsRuleReloadSet(int quiet) -{ - int rule_reload = 0; - - ConfNode *denode = NULL; - ConfNode *decnf = ConfGetNode("detect-engine"); - if (decnf != NULL) { - TAILQ_FOREACH(denode, &decnf->head, next) { - if (strcmp(denode->val, "rule-reload") == 0) { - (void)ConfGetChildValueBool(denode, "rule-reload", &rule_reload); - if (!quiet) - SCLogInfo("Live rule reloads %s", - rule_reload ? "enabled" : "disabled"); - } - } - } - return rule_reload; -} - static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) { SCEnter(); @@ -2026,8 +2002,6 @@ static int PostConfLoadedSetup(SCInstance *suri) MpmCudaEnvironmentSetup(); #endif - suri->rule_reload = IsRuleReloadSet(FALSE); - switch (suri->checksum_validation) { case 0: ConfSet("stream.checksum-validation", "0"); @@ -2140,14 +2114,10 @@ static int PostConfLoadedSetup(SCInstance *suri) DetectEngineRegisterAppInspectionEngines(); - if (suri->rule_reload) { - if (suri->sig_file != NULL) - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2SigFileStartup); - else - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2StartingUp); - } else { - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Disabled); - } + if (suri->sig_file != NULL) + UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2SigFileStartup); + else + UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2StartingUp); StorageFinalize(); @@ -2375,7 +2345,7 @@ int main(int argc, char **argv) /* registering singal handlers we use. We register usr2 here, so that one * can't call it during the first sig load phase or while threads are still * starting up. */ - if (DetectEngineEnabled() && suri.sig_file == NULL && suri.rule_reload == 1 && + if (DetectEngineEnabled() && suri.sig_file == NULL && suri.delayed_detect == 0) UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); @@ -2383,12 +2353,10 @@ int main(int argc, char **argv) /* force 'reload', this will load the rules and swap engines */ DetectEngineReload(NULL); - if (suri.rule_reload) { - if (suri.sig_file != NULL) - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2SigFileStartup); - else - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - } + if (suri.sig_file != NULL) + UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2SigFileStartup); + else + UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); SCLogNotice("Signature(s) loaded, Detect thread(s) activated."); } diff --git a/src/suricata.h b/src/suricata.h index 573be0bb0aa9..12e72697a07d 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -146,7 +146,6 @@ typedef struct SCInstance_ { uint32_t groupid; #endif /* OS_WIN32 */ int delayed_detect; - int rule_reload; int disabled_detect; int daemon; int offline; diff --git a/suricata.yaml.in b/suricata.yaml.in index 1681be5559c9..001d8e61f26b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -528,9 +528,6 @@ detect-engine: toserver-dp-groups: 25 - sgh-mpm-context: auto - inspection-recursion-limit: 3000 - # When rule-reload is enabled, sending a USR2 signal to the Suricata process - # will trigger a live rule reload. Experimental feature, use with care. - #- rule-reload: true # If set to yes, the loading of signatures will be made after the capture # is started. This will limit the downtime in IPS mode. #- delayed-detect: yes From 0b262cbfdac968cb5a05f46f2907bcdbf87f4fec Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 Mar 2015 23:05:07 +0100 Subject: [PATCH 0327/2553] dns: optimize tx list walks The detection engine and log engines can walk the tx list indirectly, by looping AppLayerParserGetTx. This would lead to new list walks in the DNS tx list though. Leading to bad performance. This patch stores the last returned tx and uses that to determine if the next tx is what we need next. If so, we can return that w/o list walk. --- src/app-layer-dns-common.c | 19 +++++++++++++++++++ src/app-layer-dns-common.h | 1 + 2 files changed, 20 insertions(+) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 95eaf131520e..4d724dfaa4d1 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -173,15 +173,31 @@ void *DNSGetTx(void *alstate, uint64_t tx_id) DNSState *dns_state = (DNSState *)alstate; DNSTransaction *tx = NULL; + /* fast track: try the current tx */ if (dns_state->curr && dns_state->curr->tx_num == tx_id + 1) return dns_state->curr; + /* fast track: + * if the prev tx_id is equal to the stored tx ptr, we can + * use this shortcut to get to the next. */ + if (dns_state->iter) { + if (tx_id == dns_state->iter->tx_num) { + tx = TAILQ_NEXT(dns_state->iter, next); + if (tx && tx->tx_num == tx_id + 1) { + dns_state->iter = tx; + return tx; + } + } + } + + /* no luck with the fast tracks, do the full list walk */ TAILQ_FOREACH(tx, &dns_state->tx_list, next) { SCLogDebug("tx->tx_num %u, tx_id %"PRIu64, tx->tx_num, (tx_id+1)); if ((tx_id+1) != tx->tx_num) continue; SCLogDebug("returning tx %p", tx); + dns_state->iter = tx; return tx; } @@ -280,6 +296,9 @@ static void DNSTransactionFree(DNSTransaction *tx, DNSState *state) if (tx->de_state != NULL) DetectEngineStateFree(tx->de_state); + if (state->iter == tx) + state->iter = NULL; + DNSDecrMemcap(sizeof(DNSTransaction), state); SCFree(tx); SCReturn; diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index 5977a74df841..d795f0cba657 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -156,6 +156,7 @@ typedef struct DNSTransaction_ { typedef struct DNSState_ { TAILQ_HEAD(, DNSTransaction_) tx_list; /**< transaction list */ DNSTransaction *curr; /**< ptr to current tx */ + DNSTransaction *iter; uint64_t transaction_max; uint32_t unreplied_cnt; /**< number of unreplied requests in a row */ uint32_t memuse; /**< state memuse, for comparing with From 18f0351d9bcd69dff0839680050fea3bb8d3264b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Mar 2015 14:30:00 +0100 Subject: [PATCH 0328/2553] detect-state: fix profiling --- src/detect-engine-state.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 6ff91afccd59..a78a3b624325 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -728,6 +728,7 @@ static int DoInspectItem(ThreadVars *tv, if (TxIsLast(inspect_tx_id, total_txs)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; } + RULE_PROFILING_END(det_ctx, s, (alert == 1), p); if (alert) { SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); From 9bcb02119f9e3c443f10f48c2d602db45a460a6f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Mar 2015 15:23:18 +0100 Subject: [PATCH 0329/2553] detect-flowint: fix unlocked flow access Some of the access to the flow and to structures retrieved from the flow was unlocked. This patch changes the logic to be wrapped in lock calls. --- src/detect-flowint.c | 54 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 9023d21096f4..e829eaac0612 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -111,6 +111,9 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, FlowVar *fv; FlowVar *fvt; uint32_t targetval; + int ret = 0; + + FLOWLOCK_WRLOCK(p->flow); /** ATM If we are going to compare the current var with another * that doesn't exist, the default value will be zero; @@ -136,9 +139,10 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, SCLogDebug("Our var %s is at idx: %"PRIu16"", sfd->name, sfd->idx); if (sfd->modifier == FLOWINT_MODIFIER_SET) { - FlowVarAddInt(p->flow, sfd->idx, targetval); + FlowVarAddIntNoLock(p->flow, sfd->idx, targetval); SCLogDebug("Setting %s = %u", sfd->name, targetval); - return 1; + ret = 1; + goto end; } fv = FlowVarGet(p->flow, sfd->idx); @@ -146,58 +150,58 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, if (sfd->modifier == FLOWINT_MODIFIER_ISSET) { SCLogDebug(" Isset %s? = %u", sfd->name,(fv) ? 1 : 0); if (fv != NULL) - return 1; - else - return 0; + ret = 1; + goto end; } if (sfd->modifier == FLOWINT_MODIFIER_NOTSET) { SCLogDebug(" Not set %s? = %u", sfd->name,(fv) ? 0 : 1); - if (fv != NULL) - return 0; - else - return 1; + if (fv == NULL) + ret = 1; + goto end; } if (fv != NULL && fv->datatype == FLOWVAR_TYPE_INT) { if (sfd->modifier == FLOWINT_MODIFIER_ADD) { SCLogDebug("Adding %u to %s", targetval, sfd->name); - FlowVarAddInt(p->flow, sfd->idx, fv->data.fv_int.value + + FlowVarAddIntNoLock(p->flow, sfd->idx, fv->data.fv_int.value + targetval); - return 1; + ret = 1; + goto end; } if (sfd->modifier == FLOWINT_MODIFIER_SUB) { SCLogDebug("Substracting %u to %s", targetval, sfd->name); - FlowVarAddInt(p->flow, sfd->idx, fv->data.fv_int.value - + FlowVarAddIntNoLock(p->flow, sfd->idx, fv->data.fv_int.value - targetval); - return 1; + ret = 1; + goto end; } switch(sfd->modifier) { case FLOWINT_MODIFIER_EQ: SCLogDebug("( %u EQ %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value == targetval; + ret = (fv->data.fv_int.value == targetval); break; case FLOWINT_MODIFIER_NE: SCLogDebug("( %u NE %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value != targetval; + ret = (fv->data.fv_int.value != targetval); break; case FLOWINT_MODIFIER_LT: SCLogDebug("( %u LT %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value < targetval; + ret = (fv->data.fv_int.value < targetval); break; case FLOWINT_MODIFIER_LE: SCLogDebug("( %u LE %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value <= targetval; + ret = (fv->data.fv_int.value <= targetval); break; case FLOWINT_MODIFIER_GT: SCLogDebug("( %u GT %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value > targetval; + ret = (fv->data.fv_int.value > targetval); break; case FLOWINT_MODIFIER_GE: SCLogDebug("( %u GE %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value >= targetval; + ret = (fv->data.fv_int.value >= targetval); break; default: SCLogDebug("Unknown Modifier!"); @@ -210,18 +214,20 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, * so implying a 0 set. */ if (sfd->modifier == FLOWINT_MODIFIER_ADD) { SCLogDebug("Adding %u to %s (new var)", targetval, sfd->name); - FlowVarAddInt(p->flow, sfd->idx, targetval); - return 1; + FlowVarAddIntNoLock(p->flow, sfd->idx, targetval); + ret = 1; } else { - SCLogDebug("Var not found!"); /* It doesn't exist because it wasn't set * or it is a string var, that we don't compare here */ - return 0; + ret = 0; } } - return 0; + +end: + FLOWLOCK_UNLOCK(p->flow); + return ret; } /** From 5111aa2ec02089e1cbdd095d311610acd06cf638 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Mar 2015 15:47:39 +0100 Subject: [PATCH 0330/2553] detect-state: handle 'post match' locking The post match list was called with an unlocked flow until now. However, recent de_state handling updates changed this. The stateful detection code can now call the post match functions while keeping the flow locked. The normal detection code still calls it with an unlocked flow. This patch adds a hint to the DetectEngineThreadCtx called 'flow_locked' that is set to true if the caller has already locked the flow. --- src/detect-engine-state.c | 4 ++++ src/detect-filestore.c | 7 +++++-- src/detect-flowvar.c | 13 ++++++++++--- src/detect-flowvar.h | 5 +++-- src/detect.h | 6 +++++- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index a78a3b624325..143551be8624 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -731,7 +731,9 @@ static int DoInspectItem(ThreadVars *tv, RULE_PROFILING_END(det_ctx, s, (alert == 1), p); if (alert) { + det_ctx->flow_locked = 1; SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); + det_ctx->flow_locked = 0; if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, inspect_tx_id, @@ -826,7 +828,9 @@ static int DoInspectFlowRule(ThreadVars *tv, item->nm = sm; if (alert) { + det_ctx->flow_locked = 1; SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); + det_ctx->flow_locked = 0; if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, 0, diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 42bb74faf661..00e8aacc8fd4 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -224,7 +224,8 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack else flags |= STREAM_TOSERVER; - FLOWLOCK_WRLOCK(p->flow); + if (det_ctx->flow_locked == 0) + FLOWLOCK_WRLOCK(p->flow); FileContainer *ffc = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, flags); @@ -245,7 +246,9 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack } } - FLOWLOCK_UNLOCK(p->flow); + if (det_ctx->flow_locked == 0) + FLOWLOCK_UNLOCK(p->flow); + SCReturnInt(0); } diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index 0746393e637c..8e8fddee0be1 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -288,6 +288,7 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx { DetectFlowvarList *fs, *prev; const DetectFlowvarData *fd; + const int flow_locked = det_ctx->flow_locked; if (det_ctx->flowvarlist == NULL || p->flow == NULL) return 1; @@ -301,7 +302,10 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx SCLogDebug("adding to the flow %u:", fs->idx); //PrintRawDataFp(stdout, fs->buffer, fs->len); - FlowVarAddStr(p->flow, fs->idx, fs->buffer, fs->len); + if (flow_locked) + FlowVarAddStrNoLock(p->flow, fs->idx, fs->buffer, fs->len); + else + FlowVarAddStr(p->flow, fs->idx, fs->buffer, fs->len); /* memory at fs->buffer is now the responsibility of * the flowvar code. */ @@ -327,7 +331,7 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx * - enforce storage for type ALWAYS (luajit) * Only called from DetectFlowvarProcessList() when flowvarlist is not NULL . */ -void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f) +void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f, const int flow_locked) { DetectFlowvarList *next; @@ -339,7 +343,10 @@ void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f) SCLogDebug("adding to the flow %u:", fs->idx); //PrintRawDataFp(stdout, fs->buffer, fs->len); - FlowVarAddStr(f, fs->idx, fs->buffer, fs->len); + if (flow_locked) + FlowVarAddStrNoLock(f, fs->idx, fs->buffer, fs->len); + else + FlowVarAddStr(f, fs->idx, fs->buffer, fs->len); /* memory at fs->buffer is now the responsibility of * the flowvar code. */ } else diff --git a/src/detect-flowvar.h b/src/detect-flowvar.h index 7ee12f02ccd7..9e72a5bcb5c4 100644 --- a/src/detect-flowvar.h +++ b/src/detect-flowvar.h @@ -39,16 +39,17 @@ int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx); int DetectFlowvarStoreMatch(DetectEngineThreadCtx *, uint16_t, uint8_t *, uint16_t, int); /* For use only by DetectFlowvarProcessList() */ -void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f); +void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f, const int flow_locked); static inline void DetectFlowvarProcessList(DetectEngineThreadCtx *det_ctx, Flow *f) { DetectFlowvarList *fs = det_ctx->flowvarlist; + const int flow_locked = det_ctx->flow_locked; SCLogDebug("det_ctx->flowvarlist %p", fs); if (fs != NULL) { det_ctx->flowvarlist = NULL; - DetectFlowvarProcessListInternal(fs, f); + DetectFlowvarProcessListInternal(fs, f, flow_locked); } } diff --git a/src/detect.h b/src/detect.h index 973f7f87cf50..80d6d6a97d2c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -774,7 +774,7 @@ typedef struct HttpReassembledBody_ { /** * Detection engine thread data. */ -typedef struct DetectionEngineThreadCtx_ { +typedef struct DetectEngineThreadCtx_ { /* the thread to which this detection engine thread belongs */ ThreadVars *tv; @@ -792,6 +792,10 @@ typedef struct DetectionEngineThreadCtx_ { /* counter for the filestore array below -- up here for cache reasons. */ uint16_t filestore_cnt; + /* bool to hint the POSTMATCH list members about the lock status of the + * flow. If locked this is TRUE, unlocked or no-flow: FALSE */ + uint8_t flow_locked; + HttpReassembledBody *hsbd; uint64_t hsbd_start_tx_id; uint16_t hsbd_buffers_size; From 4609495c607a7c419ef1c9d8607559a96c0362c3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Mar 2015 16:22:19 +0100 Subject: [PATCH 0331/2553] detect-flowint: conditional locking --- src/detect-flowint.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/detect-flowint.c b/src/detect-flowint.c index e829eaac0612..6328b67572a2 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -107,13 +107,15 @@ void DetectFlowintRegister(void) int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { + const int flow_locked = det_ctx->flow_locked; const DetectFlowintData *sfd = (const DetectFlowintData *)ctx; FlowVar *fv; FlowVar *fvt; uint32_t targetval; int ret = 0; - FLOWLOCK_WRLOCK(p->flow); + if (flow_locked == 0) + FLOWLOCK_WRLOCK(p->flow); /** ATM If we are going to compare the current var with another * that doesn't exist, the default value will be zero; @@ -226,7 +228,8 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } end: - FLOWLOCK_UNLOCK(p->flow); + if (flow_locked == 0) + FLOWLOCK_UNLOCK(p->flow); return ret; } From e1efa7a0b54a710097be27c5294134bc9d277a11 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Mar 2015 16:09:10 +0100 Subject: [PATCH 0332/2553] detect-flowbits: locking update Make matches that can be in the POSTMATCH list aware of the lock hint. --- src/detect-flowbits.c | 28 +++++++++++++++++++--------- src/flow-bit.c | 27 ++++++++++++++++++--------- src/flow-bit.h | 3 +++ 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 9960348db955..e1ea8e60ae1e 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -92,30 +92,39 @@ void DetectFlowbitsRegister (void) } -static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd) +static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd, const int flow_locked) { if (p->flow == NULL) return 0; - FlowBitToggle(p->flow,fd->idx); + if (flow_locked) + FlowBitToggleNoLock(p->flow,fd->idx); + else + FlowBitToggle(p->flow,fd->idx); return 1; } -static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd) +static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd, const int flow_locked) { if (p->flow == NULL) return 0; - FlowBitUnset(p->flow,fd->idx); + if (flow_locked) + FlowBitUnsetNoLock(p->flow,fd->idx); + else + FlowBitUnset(p->flow,fd->idx); return 1; } -static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd) +static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd, const int flow_locked) { if (p->flow == NULL) return 0; - FlowBitSet(p->flow,fd->idx); + if (flow_locked) + FlowBitSetNoLock(p->flow,fd->idx); + else + FlowBitSet(p->flow,fd->idx); return 1; } @@ -146,6 +155,7 @@ int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx; if (fd == NULL) return 0; + const int flow_locked = det_ctx->flow_locked; switch (fd->cmd) { case DETECT_FLOWBITS_CMD_ISSET: @@ -153,11 +163,11 @@ int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p case DETECT_FLOWBITS_CMD_ISNOTSET: return DetectFlowbitMatchIsnotset(p,fd); case DETECT_FLOWBITS_CMD_SET: - return DetectFlowbitMatchSet(p,fd); + return DetectFlowbitMatchSet(p,fd,flow_locked); case DETECT_FLOWBITS_CMD_UNSET: - return DetectFlowbitMatchUnset(p,fd); + return DetectFlowbitMatchUnset(p,fd,flow_locked); case DETECT_FLOWBITS_CMD_TOGGLE: - return DetectFlowbitMatchToggle(p,fd); + return DetectFlowbitMatchToggle(p,fd,flow_locked); default: SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd); return 0; diff --git a/src/flow-bit.c b/src/flow-bit.c index 81fe16413a24..2e52b9ef1aa0 100644 --- a/src/flow-bit.c +++ b/src/flow-bit.c @@ -103,41 +103,50 @@ static void FlowBitRemove(Flow *f, uint16_t idx) #endif /* FLOWBITS_STATS */ } -void FlowBitSet(Flow *f, uint16_t idx) +void FlowBitSetNoLock(Flow *f, uint16_t idx) { - FLOWLOCK_WRLOCK(f); - FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) { FlowBitAdd(f, idx); } - - FLOWLOCK_UNLOCK(f); } -void FlowBitUnset(Flow *f, uint16_t idx) +void FlowBitSet(Flow *f, uint16_t idx) { FLOWLOCK_WRLOCK(f); + FlowBitSetNoLock(f, idx); + FLOWLOCK_UNLOCK(f); +} +void FlowBitUnsetNoLock(Flow *f, uint16_t idx) +{ FlowBit *fb = FlowBitGet(f, idx); if (fb != NULL) { FlowBitRemove(f, idx); } - - FLOWLOCK_UNLOCK(f); } -void FlowBitToggle(Flow *f, uint16_t idx) +void FlowBitUnset(Flow *f, uint16_t idx) { FLOWLOCK_WRLOCK(f); + FlowBitUnsetNoLock(f, idx); + FLOWLOCK_UNLOCK(f); +} +void FlowBitToggleNoLock(Flow *f, uint16_t idx) +{ FlowBit *fb = FlowBitGet(f, idx); if (fb != NULL) { FlowBitRemove(f, idx); } else { FlowBitAdd(f, idx); } +} +void FlowBitToggle(Flow *f, uint16_t idx) +{ + FLOWLOCK_WRLOCK(f); + FlowBitToggleNoLock(f, idx); FLOWLOCK_UNLOCK(f); } diff --git a/src/flow-bit.h b/src/flow-bit.h index 633b5ee3d9a9..1b966a007198 100644 --- a/src/flow-bit.h +++ b/src/flow-bit.h @@ -38,8 +38,11 @@ typedef struct FlowBit_ { void FlowBitFree(FlowBit *); void FlowBitRegisterTests(void); +void FlowBitSetNoLock(Flow *, uint16_t); void FlowBitSet(Flow *, uint16_t); +void FlowBitUnsetNoLock(Flow *, uint16_t); void FlowBitUnset(Flow *, uint16_t); +void FlowBitToggleNoLock(Flow *, uint16_t); void FlowBitToggle(Flow *, uint16_t); int FlowBitIsset(Flow *, uint16_t); int FlowBitIsnotset(Flow *, uint16_t); From 304c711a27ddca7413eb6fcd38929e5dc01c0dd2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Mar 2015 19:23:09 +0100 Subject: [PATCH 0333/2553] detect-state: use f->protomap instead of FlowGetProtoMapping(f->proto) --- src/detect-engine-state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 143551be8624..8d17770a9d61 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -454,7 +454,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, continue; det_ctx->tx_id = tx_id; det_ctx->tx_id_set = 1; - DetectEngineAppInspectionEngine *engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][direction]; + DetectEngineAppInspectionEngine *engine = app_inspection_engine[f->protomap][alproto][direction]; inspect_flags = 0; while (engine != NULL) { if (s->sm_lists[engine->sm_list] != NULL) { @@ -687,7 +687,7 @@ static int DoInspectItem(ThreadVars *tv, det_ctx->tx_id = inspect_tx_id; det_ctx->tx_id_set = 1; - DetectEngineAppInspectionEngine *engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; + DetectEngineAppInspectionEngine *engine = app_inspection_engine[f->protomap][alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); if (inspect_tx == NULL) { RULE_PROFILING_END(det_ctx, s, 0, p); From 4e177bc9d623ff83bfcf314989cd238debde5111 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Mar 2015 21:58:50 +0100 Subject: [PATCH 0334/2553] detect-state: cleanups and comments --- src/detect-engine-state.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 8d17770a9d61..5aac3bd9a9ac 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -755,16 +755,9 @@ static int DoInspectFlowRule(ThreadVars *tv, DeStateStoreFlowRule *item, const uint8_t dir_state_flags, Packet *p, Flow *f, AppProto alproto, uint8_t flags) { - if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { - if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - return 0; - } - } - - /* check if a sig in state 'cant match' needs to be reconsidered - * as the result of a new file in the existing tx */ - if (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) { + /* flag rules that are either full inspected or unable to match + * in the de_state_sig_array so that prefilter filters them out */ + if (item->flags & (DE_STATE_FLAG_FULL_INSPECT|DE_STATE_FLAG_SIG_CANT_MATCH)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; return 0; } @@ -820,10 +813,12 @@ static int DoInspectFlowRule(ThreadVars *tv, alert = 1; inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; } + /* prevent the rule loop from reinspecting this rule */ det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; } RULE_PROFILING_END(det_ctx, s, (alert == 1), p); + /* store the progress in the state */ item->flags |= inspect_flags; item->nm = sm; @@ -854,6 +849,7 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SigIntId state_cnt = 0; uint64_t inspect_tx_id = 0; uint64_t total_txs = 0; + uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; FLOWLOCK_WRLOCK(f); @@ -887,7 +883,7 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SCLogDebug("NO STATE tx %"PRIu64" (%"PRIu64")", inspect_tx_id, total_txs); continue; } - DetectEngineStateDirection *tx_dir_state = &tx_de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1]; + DetectEngineStateDirection *tx_dir_state = &tx_de_state->dir_state[direction]; DeStateStore *tx_store = tx_dir_state->head; /* see if we need to consider the next tx in our decision to add @@ -923,6 +919,8 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } } } + /* if the current tx is in progress, we won't advance to any newer + * tx' just yet. */ if (inspect_tx_inprogress) { SCLogDebug("break out"); break; @@ -932,7 +930,7 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, /* continue on flow based state rules (AMATCH) */ if (f->de_state != NULL) { - DetectEngineStateDirectionFlow *dir_state = &f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1]; + DetectEngineStateDirectionFlow *dir_state = &f->de_state->dir_state[direction]; DeStateStoreFlowRules *store = dir_state->head; /* Loop through stored 'items' (stateful rules) and inspect them */ for (; store != NULL; store = store->next) { From 8e83d0073e4655388e8dd13c785875996faa494d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Mar 2015 22:29:10 +0100 Subject: [PATCH 0335/2553] stream: fix bad last_ack update leading to gaps A bad last_ack update where it would be set beyond next_seq could lead to rejection of valid segments and thus stream gaps. Update tests to reflect new last_ack/next_seq behaviour. --- src/stream-tcp.c | 112 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 20 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index d414186bf87d..5cc5513ab54a 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -753,18 +753,25 @@ uint32_t StreamTcpGetStreamSize(TcpStream *stream) } /** - * \brief macro to update last_ack only if the new value is higher + * \brief macro to update last_ack only if the new value is higher and + * the ack value isn't beyond the next_seq * * \param ssn session * \param stream stream to update * \param ack ACK value to test and set */ #define StreamTcpUpdateLastAck(ssn, stream, ack) { \ - if (SEQ_GT((ack), (stream)->last_ack)) { \ + if (SEQ_GT((ack), (stream)->last_ack) && \ + (SEQ_LEQ((ack),(stream)->next_seq) || \ + ((ssn)->state >= TCP_FIN_WAIT1 && SEQ_EQ((ack),((stream)->next_seq + 1))))) \ + { \ (stream)->last_ack = (ack); \ SCLogDebug("ssn %p: last_ack set to %"PRIu32, (ssn), (stream)->last_ack); \ StreamTcpSackPruneList((stream)); \ - } \ + } else { \ + SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \ + (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \ + }\ } /** @@ -2036,6 +2043,7 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack /* Check if the ACK value is sane and inside the window limit */ StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); + SCLogDebug("ack %u last_ack %u next_seq %u", TCP_GET_ACK(p), ssn->server.last_ack, ssn->server.next_seq); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -9910,12 +9918,11 @@ static int StreamTcpTest38 (void) Flow f; ThreadVars tv; StreamTcpThread stt; - uint8_t payload[4]; + uint8_t payload[128]; TCPHdr tcph; - TcpReassemblyThreadCtx ra_ctx; PacketQueue pq; - memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx)); + TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); @@ -9933,7 +9940,7 @@ static int StreamTcpTest38 (void) tcph.th_flags = TH_SYN; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; - stt.ra_ctx = &ra_ctx; + stt.ra_ctx = ra_ctx; StreamTcpInitConfig(TRUE); SCMutexLock(&f.m); @@ -9983,7 +9990,27 @@ static int StreamTcpTest38 (void) goto end; } - p->tcph->th_ack = htonl(2984); + p->tcph->th_ack = htonl(1); + p->tcph->th_seq = htonl(1); + p->tcph->th_flags = TH_PUSH | TH_ACK; + p->flowflags = FLOW_PKT_TOCLIENT; + + StreamTcpCreateTestPacket(payload, 0x41, 127, 128); /*AAA*/ + p->payload = payload; + p->payload_len = 127; + + if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { + printf("failed in processing packet in StreamTcpPacket\n"); + goto end; + } + + if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 128) { + printf("the server.next_seq should be 128, but it is %"PRIu32"\n", + ((TcpSession *)(p->flow->protoctx))->server.next_seq); + goto end; + } + + p->tcph->th_ack = htonl(256); // in window, but beyond next_seq p->tcph->th_seq = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; @@ -9997,10 +10024,32 @@ static int StreamTcpTest38 (void) goto end; } + /* last_ack value should be 1, not 256, as the previous sent ACK value + is inside window, but beyond next_seq */ + if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 1) { + printf("the server.last_ack should be 1, but it is %"PRIu32"\n", + ((TcpSession *)(p->flow->protoctx))->server.last_ack); + goto end; + } + + p->tcph->th_ack = htonl(128); + p->tcph->th_seq = htonl(8); + p->tcph->th_flags = TH_PUSH | TH_ACK; + p->flowflags = FLOW_PKT_TOSERVER; + + StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ + p->payload = payload; + p->payload_len = 3; + + if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { + printf("failed in processing packet in StreamTcpPacket\n"); + goto end; + } + /* last_ack value should be 2984 as the previous sent ACK value is inside window */ - if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 2984) { - printf("the server.last_ack should be 2984, but it is %"PRIu32"\n", + if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 128) { + printf("the server.last_ack should be 128, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.last_ack); goto end; } @@ -10013,6 +10062,8 @@ static int StreamTcpTest38 (void) SCMutexUnlock(&f.m); SCFree(p); FLOW_DESTROY(&f); + if (stt.ra_ctx != NULL) + StreamTcpReassembleFreeThreadCtx(stt.ra_ctx); return ret; } @@ -10030,10 +10081,9 @@ static int StreamTcpTest39 (void) StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; - TcpReassemblyThreadCtx ra_ctx; PacketQueue pq; - memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx)); + TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); @@ -10052,7 +10102,7 @@ static int StreamTcpTest39 (void) p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; int ret = 0; - stt.ra_ctx = &ra_ctx; + stt.ra_ctx = ra_ctx; StreamTcpInitConfig(TRUE); @@ -10081,7 +10131,27 @@ static int StreamTcpTest39 (void) goto end; } - p->tcph->th_ack = htonl(2984); + p->tcph->th_ack = htonl(1); + p->tcph->th_seq = htonl(1); + p->tcph->th_flags = TH_PUSH | TH_ACK; + p->flowflags = FLOW_PKT_TOCLIENT; + + StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ + p->payload = payload; + p->payload_len = 3; + + if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { + printf("failed in processing packet in StreamTcpPacket\n"); + goto end; + } + + if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 4) { + printf("the server.next_seq should be 4, but it is %"PRIu32"\n", + ((TcpSession *)(p->flow->protoctx))->server.next_seq); + goto end; + } + + p->tcph->th_ack = htonl(4); p->tcph->th_seq = htonl(2); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; @@ -10095,15 +10165,15 @@ static int StreamTcpTest39 (void) goto end; } - /* last_ack value should be 2984 as the previous sent ACK value is inside + /* last_ack value should be 4 as the previous sent ACK value is inside window */ - if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 2984) { - printf("the server.last_ack should be 2984, but it is %"PRIu32"\n", + if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 4) { + printf("the server.last_ack should be 4, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.last_ack); goto end; } - p->tcph->th_seq = htonl(2984); + p->tcph->th_seq = htonl(4); p->tcph->th_ack = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; @@ -10119,8 +10189,8 @@ static int StreamTcpTest39 (void) /* next_seq value should be 2987 as the previous sent ACK value is inside window */ - if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 2987) { - printf("the server.next_seq should be 2987, but it is %"PRIu32"\n", + if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 7) { + printf("the server.next_seq should be 7, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.next_seq); goto end; } @@ -10133,6 +10203,8 @@ static int StreamTcpTest39 (void) SCMutexUnlock(&f.m); SCFree(p); FLOW_DESTROY(&f); + if (stt.ra_ctx != NULL) + StreamTcpReassembleFreeThreadCtx(stt.ra_ctx); return ret; } From ef3290bb2e5741f968ee37aa2f4766a23d30c9d0 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 20 Mar 2015 10:24:39 +0100 Subject: [PATCH 0336/2553] flow-manager: don't set cpu affinity twice It is already set in the thread creation function. --- src/flow-manager.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 338ddc896d6c..b52220d153b5 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -738,8 +738,6 @@ void FlowManagerThreadSpawn() "FlowManager", 0); BUG_ON(tv_flowmgr == NULL); - TmThreadSetCPU(tv_flowmgr, MANAGEMENT_CPU_SET); - if (tv_flowmgr == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(1); @@ -900,8 +898,6 @@ void FlowRecyclerThreadSpawn() "FlowRecycler", 0); BUG_ON(tv_flowmgr == NULL); - TmThreadSetCPU(tv_flowmgr, MANAGEMENT_CPU_SET); - if (tv_flowmgr == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(1); From e5ae808b0f656a9da3073e0e162309d39ade599e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 1 Apr 2015 13:58:25 +0200 Subject: [PATCH 0337/2553] runmodes: fix typo in output --- src/runmodes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runmodes.c b/src/runmodes.c index 5fd9b9145821..e38552715321 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -229,7 +229,7 @@ void RunModeListRunmodes(void) "-----------------------\n"); printf("| %-17s | %-17s | %-10s \n", - "RunMode Type", "Custom Mode ", "Descripition"); + "RunMode Type", "Custom Mode ", "Description"); printf("|-----------------------------------------------------------------" "-----------------------\n"); int i = RUNMODE_UNKNOWN + 1; From 9fb82390ab5864cf4cff13746e553f17ca2c2abb Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 5 Mar 2015 11:09:03 +0100 Subject: [PATCH 0338/2553] suricata.yaml: add missing mpm-algo --- suricata.yaml.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 001d8e61f26b..a2a566376ccf 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -620,7 +620,7 @@ cuda: # Select the multi pattern algorithm you want to run for scan/search the # in the engine. The supported algorithms are b2g, b3g, wumanber, -# ac and ac-gfbs. +# ac, ac-bs and ac-gfbs. # # The mpm you choose also decides the distribution of mpm contexts for # signature groups, specified by the conf - "detect-engine.sgh-mpm-context". From 605ef339727e013c9ea6f8917fd1d165408d8ae8 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 1 Apr 2015 17:59:54 +0200 Subject: [PATCH 0339/2553] runmodes: improve listing output This patch removes some multiple line displayed before the information about unix socket mode. --- src/runmodes.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/runmodes.c b/src/runmodes.c index e38552715321..aa2e9bce64fc 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -255,8 +255,10 @@ void RunModeListRunmodes(void) if (mode_displayed == 0) mode_displayed = 1; } - printf("|-----------------------------------------------------------------" - "-----------------------\n"); + if (mode_displayed == 1) { + printf("|-----------------------------------------------------------------" + "-----------------------\n"); + } } return; From bd0041470f7b47fba5920354845ee5aa9035afd9 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 2 Apr 2015 18:21:40 +0200 Subject: [PATCH 0340/2553] rules: add app layer events rules Some application layer events are defined but the corresponding rules were not available in the rules directory. --- rules/Makefile.am | 1 + rules/app-layer-events.rules | 14 ++++++++++++++ suricata.yaml.in | 1 + 3 files changed, 16 insertions(+) create mode 100644 rules/app-layer-events.rules diff --git a/rules/Makefile.am b/rules/Makefile.am index cd3404336817..7ab27bdf1e56 100644 --- a/rules/Makefile.am +++ b/rules/Makefile.am @@ -6,4 +6,5 @@ http-events.rules \ dns-events.rules \ tls-events.rules \ modbus-events.rules \ +app-layer-events.rules \ files.rules diff --git a/rules/app-layer-events.rules b/rules/app-layer-events.rules new file mode 100644 index 000000000000..4d2ac28bbc97 --- /dev/null +++ b/rules/app-layer-events.rules @@ -0,0 +1,14 @@ +# App layer event rules +# +# SID's fall in the 2260000+ range. See http://doc.emergingthreats.net/bin/view/Main/SidAllocation +# +# These sigs fire at most once per connection. +# +# A flowint applayer.anomaly.count is incremented for each match. By default it will be 0. +# +alert ip any any -> any any (msg:"SURICATA Applayer Mismatch protocol both directions"; flow:established; app-layer-event:applayer_mismatch_protocol_both_directions; flowint:applayer.anomaly.count,+,1; classtype:protocol-command-decode; sid:2260000; rev:1;) +alert ip any any -> any any (msg:"SURICATA Applayer Wrong direction first Data"; flow:established; app-layer-event:applayer_wrong_direction_first_data; flowint:applayer.anomaly.count,+,1; classtype:protocol-command-decode; sid:2260001; rev:1;) +alert ip any any -> any any (msg:"SURICATA Applayer Detect protocol only one direction"; flow:established; app-layer-event:applayer_detect_protocol_only_one_direction; flowint:applayer.anomaly.count,+,1; classtype:protocol-command-decode; sid:2260002; rev:1;) +alert ip any any -> any any (msg:"SURICATA Applayer Protocol detection skipped"; flow:established; app-layer-event:applayer_proto_detection_skipped; flowint:applayer.anomaly.count,+,1; classtype:protocol-command-decode; sid:2260003; rev:1;) + +#next sid is 2260004 diff --git a/suricata.yaml.in b/suricata.yaml.in index a2a566376ccf..8189cbede699 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1086,6 +1086,7 @@ rule-files: - dns-events.rules # available in suricata sources under rules dir - tls-events.rules # available in suricata sources under rules dir - modbus-events.rules # available in suricata sources under rules dir + - app-layer-events.rules # available in suricata sources under rules dir classification-file: @e_sysconfdir@classification.config reference-config-file: @e_sysconfdir@reference.config From 754ea3d849a0fbccf1a7197555761ffba5bd61e0 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 16 Mar 2015 22:33:51 -0600 Subject: [PATCH 0341/2553] prscript - fallback to json is simplejson not available. --- qa/prscript.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qa/prscript.py b/qa/prscript.py index 7910ef7b5e17..142ad6802a0a 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -15,7 +15,10 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import urllib, urllib2, cookielib -import simplejson as json +try: + import simplejson as json +except: + import json import time import argparse import sys From 45ba20bcb09e03ca7a69d0d6107e6e4da5f04a60 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Mon, 23 Mar 2015 20:06:47 +0300 Subject: [PATCH 0342/2553] DetectAddressParseString(): fix IPv6 address handling --- src/detect-engine-address.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 19b960a79b94..31e6a7ab81b7 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -709,12 +709,16 @@ int DetectAddressParseString(DetectAddress *dd, char *str) ip[mask - ip] = '\0'; mask++; + int cidr = atoi(mask); + if (cidr < 0 || cidr > 128) + goto error; + r = inet_pton(AF_INET6, ip, &in6); if (r <= 0) goto error; memcpy(&ip6addr, &in6.s6_addr, sizeof(ip6addr)); - DetectAddressParseIPv6CIDR(atoi(mask), &mask6); + DetectAddressParseIPv6CIDR(cidr, &mask6); memcpy(&netmask, &mask6.s6_addr, sizeof(netmask)); dd->ip2.addr_data32[0] = dd->ip.addr_data32[0] = ip6addr[0] & netmask[0]; From 3b827fd649726fe8dad58939143aecbd574ad38a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 6 Apr 2015 17:05:16 -0600 Subject: [PATCH 0343/2553] Duplicate rule ID. --- rules/files.rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/files.rules b/rules/files.rules index 467735ee0461..c747727f3968 100644 --- a/rules/files.rules +++ b/rules/files.rules @@ -26,7 +26,7 @@ # Store all JPG files, don't alert. #alert http any any -> any any (msg:"FILE magic"; filemagic:"JFIF"; filestore; noalert; sid:16; rev:1;) -#alert http any any -> any any (msg:"FILE magic"; filemagic:"GIF"; filestore; noalert; sid:16; rev:1;) +#alert http any any -> any any (msg:"FILE magic"; filemagic:"GIF"; filestore; noalert; sid:23; rev:1;) #alert http any any -> any any (msg:"FILE magic"; filemagic:"PNG"; filestore; noalert; sid:17; rev:1;) # Store all Windows executables From dd6f9a6298e14e655d264467d181bda90844ce5f Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 10 Mar 2015 13:15:15 +0100 Subject: [PATCH 0344/2553] prscript: refactor for docker With the current work in progress on docker we need to update the script to handle this case. This patch adds two options: - -d to run in docker mode. In that case the build is started in the local dockerized buildbot instance - -l to not test the tested branch synchronization with github. The -l option allows user to run a complete test without publishing the code on github and without Internet access. --- qa/prscript.py | 138 ++++++++++++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 58 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index 142ad6802a0a..cc29a2a16f25 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright(C) 2013 Open Information Security Foundation +# Copyright(C) 2013, 2014, 2015 Open Information Security Foundation # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -27,9 +27,6 @@ # - buildbot user and password BASE_URI="https://buildbot.openinfosecfoundation.org/" -BUILDERS_URI=BASE_URI+"builders/" -JSON_BUILDERS_URI=BASE_URI+"json/builders/" - GITHUB_BASE_URI = "https://api.github.com/repos/" GITHUB_MASTER_URI = "https://api.github.com/repos/inliniac/suricata/commits?sha=master" @@ -40,12 +37,24 @@ parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output', default=False) parser.add_argument('--norebase', action='store_const', const=True, help='do not test if branch is in sync with master', default=False) parser.add_argument('-r', '--repository', dest='repository', default='suricata', help='name of suricata repository on github') +parser.add_argument('-d', '--docker', action='store_const', const=True, help='use docker based testing', default=False) +parser.add_argument('-l', '--local', action='store_const', const=True, help='local testing before github push', default=False) parser.add_argument('branch', metavar='branch', help='github branch to build') args = parser.parse_args() username = args.username password = args.password cookie = None +if args.docker: + BASE_URI="http://localhost:8010/" + BUILDERS_LIST = ["build", "clang", "debug", "features", "profiling", "pcaps"] +else: + BUILDERS_LIST = [username, username + "-pcap"] + + +BUILDERS_URI=BASE_URI+"builders/" +JSON_BUILDERS_URI=BASE_URI+"json/builders/" + def TestRepoSync(branch): request = urllib2.Request(GITHUB_MASTER_URI) page = urllib2.urlopen(request) @@ -72,12 +81,15 @@ def OpenBuildbotSession(): return cookie -def SubmitBuild(branch, extension = ""): +def SubmitBuild(branch, extension = "", builder_name = None): raw_params = {'branch':branch,'reason':'Testing ' + branch, 'name':'force_build', 'forcescheduler':'force'} params = urllib.urlencode(raw_params) - opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) - urllib2.install_opener(opener) - request = urllib2.Request(BUILDERS_URI + username + extension + '/force', params) + if not args.docker: + opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) + urllib2.install_opener(opener) + if builder_name == None: + builder_name = username + extension + request = urllib2.Request(BUILDERS_URI + builder_name + '/force', params) page = urllib2.urlopen(request) result = page.read() @@ -85,15 +97,24 @@ def SubmitBuild(branch, extension = ""): print "=== response ===" print result print "=== end of response ===" + if args.docker: + if "

Pending Build Requests:

" in result: + print "Build '" + builder_name + "' submitted" + return 0 + else: + return -1 if "Current Builds" in result: - print "Build submitted" + print "Build '" + builder_name + "' submitted" return 0 else: return -1 # TODO honor the branch argument -def FindBuild(branch, extension = ""): - request = urllib2.Request(JSON_BUILDERS_URI + username + extension + '/') +def FindBuild(branch, extension = "", builder_name = None): + if builder_name == None: + request = urllib2.Request(JSON_BUILDERS_URI + username + extension + '/') + else: + request = urllib2.Request(JSON_BUILDERS_URI + builder_name + '/') page = urllib2.urlopen(request) json_result = json.loads(page.read()) # Pending build is unnumbered @@ -105,9 +126,12 @@ def FindBuild(branch, extension = ""): return json_result["cachedBuilds"][-1] return -2 -def GetBuildStatus(builder, buildid, extension=""): - # https://buildbot.suricata-ids.org/json/builders/build%20deb6/builds/11 - request = urllib2.Request(JSON_BUILDERS_URI + username + extension + '/builds/' + str(buildid)) +def GetBuildStatus(builder, buildid, extension="", builder_name = None): + if builder_name == None: + # https://buildbot.suricata-ids.org/json/builders/build%20deb6/builds/11 + request = urllib2.Request(JSON_BUILDERS_URI + username + extension + '/builds/' + str(buildid)) + else: + request = urllib2.Request(JSON_BUILDERS_URI + builder_name + '/builds/' + str(buildid)) page = urllib2.urlopen(request) result = page.read() if args.verbose: @@ -121,23 +145,25 @@ def GetBuildStatus(builder, buildid, extension=""): return 0 return -1 -def WaitForBuildResult(builder, buildid, extension=""): +def WaitForBuildResult(builder, buildid, extension="", builder_name = None): # fetch result every 10 secs till task is over + if builder_name == None: + builder_name = username + extension res = 1 while res == 1: - res = GetBuildStatus(username,buildid, extension=extension) + res = GetBuildStatus(username,buildid, builder_name = builder_name) if res == 1: time.sleep(10) # return the result if res == 0: - print "Build successful" + print "Build successful for " + builder_name else: - print "Build failure: " + BUILDERS_URI + username + extension + '/builds/' + str(buildid) + print "Build failure for " + builder_name + ": " + BUILDERS_URI + builder_name + '/builds/' + str(buildid) return res # check that github branch and inliniac master branch are sync -if TestRepoSync(args.branch) == -1: +if not args.local and TestRepoSync(args.branch) == -1: if args.norebase: print "Branch " + args.branch + " is not in sync with inliniac's master branch. Continuing due to --norebase option." else: @@ -146,54 +172,50 @@ def WaitForBuildResult(builder, buildid, extension=""): # submit buildbot form to build current branch on the devel builder if not args.check: - cookie = OpenBuildbotSession() - if cookie == None: - print "Unable to connect to buildbot with provided credentials" - sys.exit(-1) - res = SubmitBuild(args.branch) - if res == -1: - print "Unable to start build. Check command line parameters" - sys.exit(-1) - res = SubmitBuild(args.branch, extension="-pcap") - if res == -1: - print "Unable to start pcap build. Check command line parameters" - sys.exit(-1) - -# get build number and exit if we don't have -buildid = FindBuild(args.branch) -if buildid == -1: - print "Pending build tracking is not supported. Follow build by browsing " + BUILDERS_URI + username -elif buildid == -2: - print "No build found for " + BUILDERS_URI + username - sys.exit(0) -else: - print "You can watch build progress at " + BUILDERS_URI + username + "/builds/" + str(buildid) + if not args.docker: + cookie = OpenBuildbotSession() + if cookie == None: + print "Unable to connect to buildbot with provided credentials" + sys.exit(-1) + for build in BUILDERS_LIST: + res = SubmitBuild(args.branch, builder_name = build) + if res == -1: + print "Unable to start build. Check command line parameters" + sys.exit(-1) + +buildids = {} + +if args.docker: + from time import sleep + print "Waiting 2 seconds" + sleep(2) # get build number and exit if we don't have -buildidpcap = FindBuild(args.branch, extension = "-pcap") -if buildidpcap == -1: - print "Pending build tracking is not supported. Follow build by browsing " + BUILDERS_URI + username + "-pcap" -elif buildidpcap == -2: - print "No build found for " + BUILDERS_URI + username + "-pcap" - sys.exit(0) -else: - print "You can watch build progress at " + BUILDERS_URI + username + "-pcap/builds/" + str(buildidpcap) +for build in BUILDERS_LIST: + buildid = FindBuild(args.branch, builder_name = build) + if buildid == -1: + print "Pending build tracking is not supported. Follow build by browsing " + BUILDERS_URI + build + elif buildid == -2: + print "No build found for " + BUILDERS_URI + build + sys.exit(0) + else: + print "You can watch build progress at " + BUILDERS_URI + build + "/builds/" + str(buildid) + buildids[build] = buildid -if buildid != -1 or buildidpcap != -1: +if len(buildids): print "Waiting for build completion" +else: + sys.exit(0) res = 0 -if buildid != -1: - res = WaitForBuildResult(username, buildid) - -if buildidpcap != -1: - res += WaitForBuildResult(username, buildidpcap, extension="-pcap") +for build in buildids: + res = WaitForBuildResult(build, buildids[build], builder_name = build) if res == 0: - if not args.norebase: + if not args.norebase and not args.docker: print "You can copy/paste following lines into github PR" - print "- PR build: " + BUILDERS_URI + username + "/builds/" + str(buildid) - print "- PR pcaps: " + BUILDERS_URI + username + "-pcap/builds/" + str(buildidpcap) + for build in buildids: + print "- PR " + build + ": " + BUILDERS_URI + build + "/builds/" + str(buildids[build]) sys.exit(0) else: sys.exit(-1) From 1180fc1ac732912096766f2ee2c1ca944790ae91 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 10 Mar 2015 16:12:45 +0100 Subject: [PATCH 0345/2553] prscript: add docker handling support You can now create the docker image necessary to run a suricata builbot in docker. To do that you need to have docker and python-docker installed on the system. Then you can go to the qa directory. You need to run once the creattion procedure: sudo ./prscript.py -C -d master -l This will create a container named 'suri-buildbot'. You can start it with: sudo ./prscript.py -s -d master -l And stop it with: sudo ./prscript.py -S -d master -l To start a test, you can do: ./prscript.py -d my_branch -l --- qa/prscript.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index cc29a2a16f25..001c92b34124 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -22,6 +22,13 @@ import time import argparse import sys +import os + +GOT_DOCKER = True +try: + from docker import Client +except: + GOT_DOCKER = False # variables # - github user # - buildbot user and password @@ -39,6 +46,10 @@ parser.add_argument('-r', '--repository', dest='repository', default='suricata', help='name of suricata repository on github') parser.add_argument('-d', '--docker', action='store_const', const=True, help='use docker based testing', default=False) parser.add_argument('-l', '--local', action='store_const', const=True, help='local testing before github push', default=False) +if GOT_DOCKER: + parser.add_argument('-C', '--create', action='store_const', const=True, help='create docker container', default=False) + parser.add_argument('-s', '--start', action='store_const', const=True, help='start docker container', default=False) + parser.add_argument('-S', '--stop', action='store_const', const=True, help='stop docker container', default=False) parser.add_argument('branch', metavar='branch', help='github branch to build') args = parser.parse_args() username = args.username @@ -128,10 +139,9 @@ def FindBuild(branch, extension = "", builder_name = None): def GetBuildStatus(builder, buildid, extension="", builder_name = None): if builder_name == None: - # https://buildbot.suricata-ids.org/json/builders/build%20deb6/builds/11 - request = urllib2.Request(JSON_BUILDERS_URI + username + extension + '/builds/' + str(buildid)) - else: - request = urllib2.Request(JSON_BUILDERS_URI + builder_name + '/builds/' + str(buildid)) + builder_name = username + extension + # https://buildbot.suricata-ids.org/json/builders/build%20deb6/builds/11 + request = urllib2.Request(JSON_BUILDERS_URI + builder_name + '/builds/' + str(buildid)) page = urllib2.urlopen(request) result = page.read() if args.verbose: @@ -170,6 +180,43 @@ def WaitForBuildResult(builder, buildid, extension="", builder_name = None): print "Branch " + args.branch + " is not in sync with inliniac's master branch. Rebase needed." sys.exit(-1) +def CreateContainer(): + if not os.geteuid() == 0: + print "Command must be run as root" + sys.exit(-1) + cli = Client() + # FIXME check if existing + print "Pulling docking image, that will take long" + cli.pull('regit/suri-buildbot') + cli.create_container(name='suri-buildbot', image='regit/suri-buildbot', ports=[8010, 22], volumes=['/data/oisf']) + sys.exit(0) + +def StartContainer(): + if not os.geteuid() == 0: + print "Command must be run as root" + sys.exit(-1) + cli = Client() + suri_src_dir = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] + print "Using base src dir: " + suri_src_dir + cli.start('suri-buildbot', port_bindings={8010:8010, 22:None}, binds={suri_src_dir: { 'bind': '/data/oisf', 'ro': True}} ) + sys.exit(0) + +def StopContainer(): + if not os.geteuid() == 0: + print "Command must be run as root" + sys.exit(-1) + cli = Client() + cli.stop('suri-buildbot') + sys.exit(0) + +if GOT_DOCKER: + if args.create: + CreateContainer() + if args.start: + StartContainer() + if args.stop: + StopContainer() + # submit buildbot form to build current branch on the devel builder if not args.check: if not args.docker: From be473fa71233d53a9742c0c30aa5ce561b300eff Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 10 Mar 2015 19:55:23 +0100 Subject: [PATCH 0346/2553] prscript: add a comment on the SELinux issue --- qa/prscript.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qa/prscript.py b/qa/prscript.py index 001c92b34124..6dcc36fcb751 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -14,6 +14,12 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Note to Docker users: +# If you are running SELinux in enforced mode, you may want to run +# chcon -Rt svirt_sandbox_file_t SURICATA_ROOTSRC_DIR +# or the buildbot will not be able to access to the data in /data/oisf +# and the git step will fail. + import urllib, urllib2, cookielib try: import simplejson as json From f12e6fdcdabf8a3fccb0de27032a058bded2c867 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 11 Mar 2015 15:01:58 +0100 Subject: [PATCH 0347/2553] prscript: read buildbot config from source This patch change the logic of the Docker buildbot system. The buildbot configuration is now the one available in qa/docker directory. This way, developers can test features in docker buildbot that could require some specific flags to be set. They just need to edit the buildbot.cfg for instance to enable a new feature. In the same way, the tested pcap files are the one which are in the qa/docker/pcaps/ directory. So to test some private ones it is enough to put them in that directory. To take into consideration a buildbot.cfg modification or a new pcap, it is enough to stop and restart the container: sudo qa/prscript.py -l -d -S master sudo qa/prscript.py -l -d -s master This patch also fixes the container update issue. A local modification to the buildbot will be kept. It is also fixing the issue when working on old code that could possibly not support the same build flag as the one of buildbot. Here the configuration will remains in sync. --- qa/docker/buildbot.cfg | 235 +++++++++++++++++++++++++++++++++++++++ qa/docker/pcaps/tls.pcap | Bin 0 -> 160944 bytes qa/prscript.py | 6 +- 3 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 qa/docker/buildbot.cfg create mode 100644 qa/docker/pcaps/tls.pcap diff --git a/qa/docker/buildbot.cfg b/qa/docker/buildbot.cfg new file mode 100644 index 000000000000..bce14d22f3a8 --- /dev/null +++ b/qa/docker/buildbot.cfg @@ -0,0 +1,235 @@ +# -*- python -*- +# ex: set syntax=python: + +# This is a sample buildmaster config file. It must be installed as +# 'master.cfg' in your buildmaster's base directory. + +# This is the dictionary that the buildmaster pays attention to. We also use +# a shorter alias to save typing. +c = BuildmasterConfig = {} + +####### BUILDSLAVES + +# The 'slaves' list defines the set of recognized buildslaves. Each element is +# a BuildSlave object, specifying a unique slave name and password. The same +# slave name and password must be configured on the slave. +from buildbot.buildslave import BuildSlave +c['slaves'] = [BuildSlave("buildslave", "Suridocker")] + +# 'slavePortnum' defines the TCP port to listen on for connections from slaves. +# This must match the value configured into the buildslaves (with their +# --master option) +c['slavePortnum'] = 9989 + +####### CHANGESOURCES + +# the 'change_source' setting tells the buildmaster how it should find out +# about source code changes. Here we point to the buildbot clone of pyflakes. + +from buildbot.changes.gitpoller import GitPoller +c['change_source'] = [] +c['change_source'].append(GitPoller( + '/data/oisf/.git/', + workdir='gitpoller-workdir', branches = ['master'], + pollinterval=300, project='suricata')) + +####### SCHEDULERS + +# Configure the Schedulers, which decide how to react to incoming changes. In this +# case, just kick off a 'runtests' build + +from buildbot.schedulers.basic import SingleBranchScheduler +#from buildbot.schedulers.forcesched import ForceScheduler +from buildbot.changes import filter +c['schedulers'] = [] +c['schedulers'].append(SingleBranchScheduler( + name="master", + change_filter=filter.ChangeFilter(branch='master'), + treeStableTimer=None, + builderNames=["features","profiling","clang"])) + +#c['schedulers'].append(ForceScheduler( +# name="force", +# builderNames=["builds","debug"])) + +####### BUILDERS + +# The 'builders' list defines the Builders, which tell Buildbot how to perform a build: +# what steps, and which slaves can execute them. Note that any particular build will +# only take place on one slave. + +from buildbot.process.factory import BuildFactory +#from buildbot.steps.source.git import Git +from buildbot.steps.source import Git +from buildbot.steps.shell import ShellCommand + +def SuriBuildFactory(repo='/data/oisf/'): + factory = BuildFactory() + factory.addStep(Git(repourl=repo, mode='copy')) + factory.addStep(ShellCommand(command=["rm", "-rf", "libhtp"])) + factory.addStep(ShellCommand(command=["git", "clone", "-b", "0.5.x", "/data/oisf/libhtp/.git/", "libhtp"])) + return factory + +factory = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory.addStep(ShellCommand(command=["./autogen.sh"])) +factory.addStep(ShellCommand(command=["./configure"])) +factory.addStep(ShellCommand(command=["make"])) +factory.addStep(ShellCommand(command=["make", "clean"])) +#factory.addStep(ShellCommand(command=["make", "distcheck"])) + +factory_devel = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_devel.addStep(ShellCommand(command=["./autogen.sh"])) +factory_devel.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-unittests"])) +factory_devel.addStep(ShellCommand(command=["make"])) +factory_devel.addStep(ShellCommand(command=["make", "clean"])) +#factory_devel.addStep(ShellCommand(command=["make", "distcheck"], env={'DISTCHECK_CONFIGURE_FLAGS': "--enable-debug --enable-unittests"})) + +factory_profiling = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_profiling.addStep(ShellCommand(command=["./autogen.sh"])) +factory_profiling.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-profiling","--enable-unittests"])) +factory_profiling.addStep(ShellCommand(command=["make"])) +factory_profiling.addStep(ShellCommand(command=["make", "clean"])) +#factory_profiling.addStep(ShellCommand(command=["make", "distcheck"],env={'DISTCHECK_CONFIGURE_FLAGS': "--enable-debug --enable-profiling --enable-unittests"})) + +factory_clang = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_clang.addStep(ShellCommand(command=["./autogen.sh"])) +#factory_clang.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-unittests","CC=clang","CFLAGS=-fsanitize=address"])) +factory_clang.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-unittests","CC=clang","ac_cv_func_malloc_0_nonnull=yes","ac_cv_func_realloc_0_nonnull=yes"])) +factory_clang.addStep(ShellCommand(command=["make"])) +factory_clang.addStep(ShellCommand(command=["make", "clean"])) + +factory_clang_32 = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_clang_32.addStep(ShellCommand(command=["./autogen.sh"])) +factory_clang_32.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-unittests","CC=clang","CFLAGS=-fsanitize=address","ac_cv_func_malloc_0_nonnull=yes","ac_cv_func_realloc_0_nonnull=yes"])) +factory_clang_32.addStep(ShellCommand(command=["make"])) +factory_clang_32.addStep(ShellCommand(command=["make", "clean"])) + +factory_features = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_features.addStep(ShellCommand(command=["./autogen.sh"])) +factory_features.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-unittests","--enable-nfqueue","--enable-nflog", "--enable-lua", "--enable-prelude"])) +factory_features.addStep(ShellCommand(command=["make"])) +factory_features.addStep(ShellCommand(command=["make", "clean"])) +import psutil +factory_features.addStep(ShellCommand(command=["make", "distcheck"],env={'DISTCHECK_CONFIGURE_FLAGS': "--enable-debug --enable-unittests --enable-nfqueue --enable-nflog --enable-lua --enable-prelude", "CONCURRENCY_LEVEL": str(psutil.cpu_count())})) + +import os +PCAP_PATH='/data/oisf/qa/docker/pcaps/' +(_, _, pcaps_list) = os.walk(PCAP_PATH).next() +pcaps_list = [ os.path.join(PCAP_PATH, pcap) for pcap in pcaps_list if pcap.endswith(".pcap") ] + +factory_stress_pcap = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_stress_pcap.addStep(ShellCommand(command=["./autogen.sh"])) +factory_stress_pcap.addStep(ShellCommand(command=["./configure","--enable-debug-validation"])) +factory_stress_pcap.addStep(ShellCommand(command=["make"])) +factory_stress_pcap.addStep(ShellCommand(command=["sudo", "make","install"])) +factory_stress_pcap.addStep(ShellCommand(command=["sudo", "rm", "-f", "/usr/local/etc/suricata/suricata.yaml"])) +factory_stress_pcap.addStep(ShellCommand(command=["sudo", "make","install-conf"])) +factory_stress_pcap.addStep(ShellCommand(command=["make","clean"])) +factory_stress_pcap.addStep(ShellCommand(command=["sudo", "ldconfig"])) +for pfile in pcaps_list: + factory_stress_pcap.addStep(ShellCommand(command=["sudo", "/usr/local/bin/suricata","-r",pfile,"--init-errors-fatal","-S","/data/oisf/rules/http-events.rules"])) +factory_stress_pcap.addStep(ShellCommand(command=["sudo", "rm", "-rf", "/usr/local/var/log/suricata/"])) + +from buildbot.config import BuilderConfig + +def SuriBuilderConfig(*args, **kwargs): + if not kwargs.has_key('category'): + kwargs['category']='default' + return BuilderConfig(*args, **kwargs) + +c['builders'] = [] + +c['builders'].append( + SuriBuilderConfig(name="gcc", + slavename="buildslave", + factory=factory)) +c['schedulers'].append(SingleBranchScheduler( + name="build", + change_filter=filter.ChangeFilter(branch='master'), + treeStableTimer=None, + builderNames=["gcc"])) + +c['builders'].append( + SuriBuilderConfig(name="debug", + slavename="buildslave", + factory=factory_devel)) +c['schedulers'].append(SingleBranchScheduler( + name="debug", + change_filter=filter.ChangeFilter(branch='master'), + treeStableTimer=None, + builderNames=["debug"])) + +c['builders'].append( + SuriBuilderConfig(name="profiling", + slavename="buildslave", + factory=factory_profiling)) +c['builders'].append( + SuriBuilderConfig(name="clang", + slavename="buildslave", + factory=factory_clang_32)) +c['builders'].append( + SuriBuilderConfig(name="features", + slavename="buildslave", + factory=factory_features)) +c['builders'].append( + SuriBuilderConfig(name="pcaps", + slavename="buildslave", + factory=factory_stress_pcap)) + +from buildbot import locks +build_lock = locks.SlaveLock("slave_builds", maxCount = 1) + + +from buildbot.schedulers.forcesched import * +c['schedulers'].append(ForceScheduler(name="force", builderNames = [ builder.getConfigDict()['name'] for builder in c['builders'] ])) + +c['status'] = [] + +from buildbot.status import html +from buildbot.status.web import authz, auth + +authz_cfg=authz.Authz( + # change any of these to True to enable; see the manual for more + # options + #auth=auth.BasicAuth(users), + gracefulShutdown = False, + forceBuild = True, # use this to test your slave once it is set up + forceAllBuilds = True, + pingBuilder = True, + stopBuild = True, + stopAllBuilds = True, + cancelPendingBuild = True, +) +c['status'].append(html.WebStatus(http_port=8010, authz=authz_cfg)) + +####### PROJECT IDENTITY + +# the 'title' string will appear at the top of this buildbot +# installation's html.WebStatus home page (linked to the +# 'titleURL') and is embedded in the title of the waterfall HTML page. + +c['title'] = "Suricata" +c['titleURL'] = "https://redmine.openinfosecfoundation.org/projects/suricata" + +# the 'buildbotURL' string should point to the location where the buildbot's +# internal web server (usually the html.WebStatus page) is visible. This +# typically uses the port number set in the Waterfall 'status' entry, but +# with an externally-visible host name which the buildbot cannot figure out +# without some help. + +c['buildbotURL'] = "http://localhost:8010/" + +####### DB URL + +c['db'] = { + # This specifies what database buildbot uses to store its state. You can leave + # this at its default for all but the largest installations. + 'db_url' : "sqlite:///state.sqlite", +} diff --git a/qa/docker/pcaps/tls.pcap b/qa/docker/pcaps/tls.pcap new file mode 100644 index 0000000000000000000000000000000000000000..8aca21861188067c3bb40ee5498d09c6daccfdd5 GIT binary patch literal 160944 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�~##T>wfVfmNEQ z#v*A{c&=(<%TzCA$AJ^#w$g^>B=WiWSuZ+0Mpe@=x5PAj5JZ^r-YlWnk?IEKEaG2I zS2Q&JeNpGN{ySNF3V_KIZ&CjLE{C!rK16nX63sfUI1?HuQTY9T{)$cQ5an){3w0-h zK}X7lWxjDj0`9H_m80kFx%N29yx8aH)|dV&&VWH_o2YXgds5?m%SW+&pttd{Wdkzw z%GFQq{07+2j^*fXg)v8@YKC zfI$a!$*3-svafe?4GFKn>hIy+i}lJ3_tO!o!dG>bHeS2M2!o5hF!)=AZcw{7)N0e{ z#LiytM`c^g+|dWcN4UVGU~_-u!W|r20hp!G2H^luFvY-r>7KmgD56@@ zG=58%6nq6L2-tm_@-5#s#ufxrX}{SRh94?-RGbL$8R zYd)C4pYyOlr2oRkpg{!Kkh-~(62enMU%WY`FUJ)ERG z-MxxQQCEL1oEN;i_y;MFTD1v;EL8g^WT2E1x_K_}qi0$(cHXgptz4)CVJOk$76C|g zLQpAejGEw-gYYebrVRN2Fum3X+jROf#;0n}jyg2gk9YU=C zBD;3+d=Xefmkv{-fl*$j3T{1N&UR0f{dbJMU|Rj-<0fSr)s>M)?$WMke()V_ z;$hvS@Ie8}k~L7aEP2Xs9ZJ%cL4jBfB8kGze>#RcU8>uP5qjM_2~4MOC$H>$v_)U3 zAi>eEiJIA8;Jh$ibpEB4*q<5Ky0V;=5QT!CY+7?R`wwcQ0~q&ri{o>*aGbsg`D=mP zshBhg?C(f4qmixpp(RRRCCOrHJnDu)ge(=@#b&@g5!J8bhIn%;VoNT&(dRNToV!C# z(J@@`{_~0t&B)y^T>ucj>50{j-_H=o4ST{AF)* z*K}CYFi%%iAh+kC@S9upsn{>h^2d2X7sZ7EK`onN3sG;dbKD}Us~}s2RNYd|kE}6r z3u&X!S02+>y1s0I&V%edDt#Cfh71C89yTz|kfL|#ko?uvAVj;+O;&MOXx1j2hpzY> zgzZO3Z&%_48l0ac;Z&p+;~z;gU=O0vXN1o=D!-!q4E@kRy2I7X`Wv)e8IPlZTsxQf zjf$V4bq(LiA0?4uoDd}&PqIfRI7qA&n98t-Ao|`tL?>!6*#T`a6mB)>fu%aYkT?y^ z$4L_DS4%+!))GFEN8wVXJMl)Vc&ldPww`axJ-M>aF;J4|7Fc-Lf9Xmt3d5TuPK}nx zMZlO+SqX)2ks&5jasVW*b#?*CMe@L0sNuee zZG+Fzden;`z^5N<-7`TW2)yhZ%t4NetTQcPNuBLqd+Wf|0-*pc6e(d(8*@R#SKXMO zy`Qf4HP3j_DDe*2Pv(l!*6F{TaAMyda&sJ1HWgQK1I_TiOrz-wjCIGJhiWH=S`6yr}Mggd5 zR0vIe#NmI3wRQoAK2elvr{VZ05>nW9-0#fv+*!_9GoG{BtyvS)RP0OpX{o%DIm>O_1ETlA}cTbiQ+ zCE7X7eS69yf`A!TWbKafhcJLpE=So{2T86&lhKUGPp7eJEjHa^@*f{q1_u%KZ} zjR$a9MOD6w)YyuoozLakc%ZRpVzdvvYM0-w?fG@;zj9Qw${d|rA%!g7{b&e>sUF18 zbw|?svDmXE3~(3IC8mH2mOO}nNIHjoV1Y&K=+PiIh%0DRa}Xzc&CVmOm#tc%n_ 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

G*ZU>FF>6Ma6bgw~b~*{W*c8+X zvFK8GJ`loAQR_-nW|4`47A$#|QAMbt9K3TlG;UT~PlN>ayCp6M=h7TD#8A{;tBGn#b0?kkS>kfktq9*W%lifE)t^>r!^ zTuFOSjAzR@0Bl>E>P9x^Du<$!CY`fILh;>gDtooivld~`iUPuo^L4s$53g>hyfq8b zH_c1gtzZK0bL*Z{Z9AXE`#S@}-lX?B)DsvmS(L}p1woXV$+r6Wo)NXCIgw?)w$M}Zwy zhr-=RttE65k+~A-O1p-6zu+~FzGo7|&lqa~qP!gN#bZnpol3i&I<{?oD&^0%Ekfsc z6AASq^(0nXL=*K^g~tv~l!es-v#2Y2i06x(HsVGAgV%qV!eClO&qrBhMJ6X>Ii+uv==HgHv0p$ZsRQ! zPHzWs2&=9;{3)%+-S;PDx5(Z-DOI0@BKHY#7|dD15hBx#+vWoYWcKN=P++`rziE@Am3N9-aX{#`MblPZoco5**;Gc-Y7?G=1h4IBMr}_J8g^$UWNW zMG>zOIS3jVT#Zct8d{YZ={$Bigk|}%yC;hyhVo}>f-c)%V<*$oBseaBo?}a<*hbnx z7~)f8j1=mg&bC$sTk6{jr%$pqXhOqLs;cD&>eW@W0jogf5y40=nl2R?LS8Xf%^(B% zC&-}&u$zen#}A)3S=TcbW2bpUHw}9&D-uY==y&PteG7Q~6}taGqriO#hv~u9P)GJ% zl^WsKW@0X0v^&hPR_oRc6QB{NhB?Kl@Wu(a7IfjTq!m4t*(I?t5Ec=@C%S{ZQb|Gk z$n?87Rro#go>!0n1{VPJeDILc^pJtcht7N1MA$m=&E^~{%mY<#P#UG@W?C}YMK^>; zL(l1G+=PmkH3D$97lX-5#})r_k|q16Z|%A@m)=)co&d!Rk4jbKIu1>CldtNyu8BYr zmy4HrurXWAVYJskt$!*EJ<~_fg!6CQ+&0v6o1%-*vy*6{qlx{yX@h+ZnfIi#HCaa| z3OVB}>;zE1BdzsD$*K`36awq>@Z4?QttQ;ch+|oK8D>jhj!pCl(!~JPA|z5>2tJ1K zuWAl%Xk#rldG+Tz(|3ooRA?O{Qg2&*^vv2aqGyyznX~Lj{w!o_ElzVp&87MzW@a_o z^ZAU#Q9wSCxJ(E9m9G=q&gD1jRA^0?F}l>j#yX{Km*_8CxbUqMn!RDvneR`e+42N7 zvXtA?O7RAzVPOkYP2MqkwGR+z6|#_Sq`7WMIb*zqE(l)8JK5ffhR3d4mOb13Tb}%W zA0|y)S%WEAppRhqwfW_i;htAe&bzwJCEra88*F3l1ybM8e5wmf*eB28BlW`ypEg?2T;CiIG;MIQ8HY8w{%4`#UfMIkl5{QK^5}zo`3w zRHws01Fftz&8d0C5NzRYNY$2?Fk}me@4lK(pRQ|fR#m;Se;GNxeWB*9<*8L?l!n?^ z8Jdm*gw0b;+nh#-sf&Lpy9r4XXzgqo0fzE|MgUc*MMyMLNJ+tD>-UAA4@~~WkkLU; zd-YCKox)&{!z*WqXlcV6{41h*GGO-CmUFWp?FO?%23Hyf?9!d>wOkdnwV~EHI5ve~ zOKn#;3(Dl)b$r3cy;zfpc6_sXHU2IBS1mTIOr_b7^orH~HU28vnw!5M z2`pvV+0Ov8mlnipw@=Y=x5lCZ%{6`CJ#m|k#O3Q1uuGXj%AF5IG~&Jd8jV&?WereK zb!}hu2^p@BUQSo(gccH~#L)cg9P7Y@w_>*`uRl`2r9Je1F66~7}MS8PCFPk`n)#D^DqMi)3YJsx%7SW2T1L; zwl^twtyzz6H~rO-(u0=E0#?8kC?s00_Z&5aOXUu=QqL;<#?0_s%1>Q^jw|U6NMdO5 z&i7R+_DQ=9RiAEuy-TSZTLrSse7fN)(2o-h{P!^SEw9v%qf!8mb46?oQkfgXjeH=s zl9BOM-b>T+ItOaUE}7Ca6jnC?P#r{o3|e|&nM$BM!W2J5k7*Kr{g-@gG1Pq#9wMvA zEq)&$-_=qcCEdi^H&#RPNlg(e0wUoKUFQ2F($@P5mTZu0+GmPR$}@E{;~nK#7(H{{ zoMC@eW};E&&ta+V{)G0GZ-9+d*V}9na_zKbR~v0D$=ut#GhVN&)qCYKl$#+yfihNN z9|;fALiKo7MJh;u?Ady@_ofQM)O)?x1DPm`8yUr3VGhz!-9%R=~PhbHy>X3=tprTzODe?+>krjD8y_DMtD%Hf8U!!7C=)i@bfP zGXoU}0-j<+@d4C{wG^4zoy`1)5z7FQ2=$Hwq~&tzB)%E4z~S|Uua}Je5SA@u(Up+r z3rC*tlZqghB6ML}ii={(-f41ja)iG&;<+$!35o24!T4%?j*KrPIOimF%vZ_y8Tjr@ zU>6>27pGx-KXZut$j&iph8pn%MS-n0@cnVj72`WWQw^LDnyrBUey~Jgs?=P~cYD^N zQ&sb5kScOKfFIC_sx{$z!17I-Zso|fAe-MWo%odx|6S4S4KZrjetItl@lv$M?_M&+ z=ql$vewLQ_6z`#y3^g6w!tvX4h0&S2W@e4-kgX0se_^p|+jO4xBrIMlWXVRqhO=^f zJ#(n7lwSQpXO{|C(7z=|sH0R592C@XwOupvO#7{w zMamGrm-)2Bx)OCPZu^S#ju?J9jGsIzi#_yi04WO`j!caK`-^t8vY_{N!Ntzc;nR9@ z?3i3=E&*B3H`caFL+{|xjixD)xr1*SJ|*L7T)gF(;zkE!m}8|Z+^(L08Q(U@ed)3w zh7#Kbf#{Vcit_I9PF+{rfL<#rCpqKh^?Adum2A+lX98VHLR)tBhnaH1MF>cZJjW(c zpHt%dsahGxJJ#nIY$@K>m~^)6wmw<3Ckz6BPx#%h2zu1Kmb8gKC$6DGJ8DX<9IZb* zjCH1lXd{oriu6?>8#J_Ky1et<4Xt?@%I3s{gP@*- zy{Zuv{}iKNMaV(9fh=L79}>0ga#?tVdCO{boN(C!9h4MQG+1!JKurS9zZhyK$bw|H zJscwynB~u#N5Mm<27hR9*G7g-**jxnNBo=B3fX|*JYO*v|F=C*?0~q}Xq@$LNOjJc zAJl{zOx7c&k*E^&qLihA8h;#bLH8_I zW@&&RR9Dy?wPN;*0x*roh&g2k($3mAqt8rZHKGDX6$GdfDL^!DZVw05n%j-|g8zcuVGrw-gkLHMCH8 zK|rvkOn@%@Fw!|7OO!^v`-+t4jfX&jhnm>(?Xhyezn?sT}9d0^SKSc=#kI&>__qKnm8^qWNKam}bVt z|D>jW4963BZFmg;sJzN{%$kH5`cX{+Xh=u9c49$1=p&Qx;dHMW#YR=@McAx6r78O_ z`nd!q;RNe<#F~R~I>c(trV$G<+rwWE&qws+TBwzc4)yih2cx#PA%u_~u4;!Y`)8-` z2CuhWn-wm>_rrlLSgsl5iq3_a2uLsE^+z5%Wnh zz+oMFZBy|Y!wgb2@GcGla+hV5W!e15vMN^M^$AH4ud4-=GgDjwCHCtkf8j`5WsH3c zoS(R~9_?LX3Me?!4%*A@*IHc>&Ydi(5?mlM7j=>?^t7JXBJZTeN(N7tSUU!aEzv%8 zJ&I)#@Pr&^f%R}?$6qsFRJs`xa@N>?s!6c7{Tx@u5_YSvg1RFtp z>$vqQ{=%-2PEPL6b~joQR*K8$HSBa|c6!jEKIp-l0n)Q17U^avft?yBe`g!djiv^lDH z4}ur-c|_ice&d=kA#42Y-ucoq7i_-;oorOM4pmVx|b4OltXhDPOhwubMDD@y3mHI zcq7b7qh%*1?cPyTtgEEc{b_oJ&V~ou7XQ3si|5m$geSO_i|02D6U+*C6yNsXv3?{p zKj-|iy;TtxOf{975K)aNv?bYwmcz%%1OBS4uIU@cy!+a!Ec{nX4_i}4H6$oLcxkNz z=LTkuK{pg-Y-NmPw1ETy@ODnag|7Pn(n`oLJQ0Wkb|ePz;toHnQFI*v*4zjr4!fPV z>qMySG2yS!$YQa%qH<%9&k@!HdRed32@v)1ExyQfzs8~%XhFGJj#a5j!gp>g_!f2LdLaJb~=J{()oWY=mrP8f2X#VyX{vOK{~9FqlkGu(1gstXIQ{Ps>Yx z;3~Kzny!R(aXkt@CfS9#mLG}-qT{R$D2$I2CjuG*e0TGcU+2HGZMsymgQ z<(w#ecRyU?*R)el#)`D)>)kHC($4xIw>+b~WaNa4u=RT|ZWb1spYTb6Kd-R6vw&o9 zM)Y0Wz=O@vu}v3=!|W6SGc*HQZenIO z$0>Y=(P0^y6BOvHd12(X?^2(a++`Q=@7ad^xVNm zd7}J#sE~gs&54_~(D_`cpQT*Sn6?I_GEw(Z&b{Bpc?8wS1+y0&!x!)^>(1w5Wp+Ub z+?CYFU=WU|lrJAq=o66!HPkJl(^WfMp8*#Vjw;(3Nl$-7ysucOaEVh`yR63dw~lEW zbwS|wHW)FKiED-;!0cr#J`ioy->OTIN%;X@AS$Hu>sH@FMO}H!D3UWRh8js6OqG?? z1D8%obi)b4LMzA!H~_jhSFF~5UI)2<5LH5rw-o*S3TEq{J#EKF)!rc^GB`L>!3rXGWvPx7y4VML^JjSl#nwRDHcoGVkE*($4EqeO#98m2!VLMfht`b@O>0vkRv`jt74wM3K zKV(MB>&G0-!cO40b&jxHXV7=@3FW2#6vg0wxwppo^3V4s;2QstBrM4Nvu`1Ck)S>5 z9eQM9P089?Zu~|&ViAe&lnbOX22Wn-ZROz~BmZapYPNmQUrd6ChZ5s!LBo8K}>d~?{_ z^gO0ln1wJOI`5g3y{HLBkfP0^k?D(5Z0dk?d{L8N|EMDPZgw>-P-*ryad8FMKVMTp zF0dtMWkKwFo9@$JN-HK@F4rXx@E7~B?cKNK>+>vG%8vT9H$~U#p+Gozyz(}X$tW9_ zG48#p!!n8+6~uMKYBT}uLnhap%OjkUJ5+jqej)6QRmNeon*@A31pQ$psHmAaH$JU^}I{%aP#)P z$|x@&9x~{h|+_LF%kuyxcU| zzL+k$(hZyt-gO{A8XRmsow?m|DXYwYJ@i5djPSBiSwW zJKuSZ)+ZPOzeJYRNU}WHDZ&*)s5yKWpdIB$?$LR4LPMfmP>VTmoL%PjlHCjRS%Jer zZhk7%=$J%8nS(H!og;+cuv${cbo`)lspu_~ir_K9xX%O+qI(P`a4y^)G4SN=%Co1y znWb5Xb}D!0-!YoA?$v+RsglKnR@~Unfa8+JAlKdneD$t-l=Y9p z0w#a&gci3F7>> z2$(1I4TJ-q2KR1A-uNkQ09ZCA#>P0mpIUkZ^IN6qiMrb9;m=cvpXNnVuUjtud55BQ z>S7JFLdh;K1`!{lP<*pl;SQAFUs~sE9YX*2(eG){v@BC%(9+E095&Xz zRO{>f3OV=Ccgl;&BY35MyXiV1^pJgT=61A4yxz%Q0Z|koZyNvxjedQ+Tmz|3V~~pj z76mnPY(Ty`5yiqIvjCfl>?aEJ?dnVjCZH}5I8i@gAhcfH1pFI4M7nk;#O;p_CUXn{ zpqXU~p`UndYyz|3bhwCH-rLT$-D-V;BnRZ|WB24+tL$VZfGWria3oI-iJXYKQxGdm z&DAO5b;_Z#iPo_qfyRk>Is(@ga!VW}USHR83V(5-XOW>0;mh%F{4tp)aHA1duav() z6pinAauuI|QXP2p!mh)o3vc*-qM_P-hZTAET_-s(35mcce0~eUL#(1~jy2pX|CQip zUx6tXICMz12XaUnBTpvph5i$E>UkO*4#SdYxU9S7F7=J!3_)8RPHgJ+L?Gv(%Nu3r zH7VD|s@_B;{8rE23=WR+1htN$*$D+}{%;E(c(4a|nf}-Jk=i5>Js|6~s(tfdUR86$ zylnw?G5}cNljEGWL7j6kQs0m-px63z5bC{0yN;EkP#8Ggwz!F;(KjTn_1A8XqPI4> z;SFBr9o=Ebk-q=Hk?=S)DzV9%Tk1-Qxt!knn#v1fmLz>T={Watg#mkbH%%||x4}-u z%K{otNzIVhmvqI8u!)tulTT&j$GU%sAcP>|2a*WpjIAA>ZS9Bdc~nHbX#m3WXl$z6 zE}&5|5qG?#9H!5Gw0p`{H1Xt{P^sUTRX5VC zL{u4bNMYFof2DD+NV?g9ZJ{e&XxJFTHbcTs$d+fbmTDfOZ|{_r*B$$kp2=nL{7-x& zEkKb-7!F}ls3AIMFYq@AEi(Kf_9as*##-R~sd&h}t zTWFBZINAb(z4ZD0&r)$#GKy5l5Eh|_^T5`*$I6FQcDp-V!H}Gc~zDoW=X@%<* z(u5rr{RULVjhWxIX>x!Ntm%V`-NaVb!Au9Kt%u!h>Ppd}qSP`jEQ1oGMxRBF2%AAJ zk9C(y8%GE=TBK_vR9Jb-i?5lga96rigvYuiQiB=%g!n2>nu?O43H(|!fr=L-TD=K%HJzVaLIBg%Tc?zzXPV{g5 z-=e2UNPu>d`^;P#jC(|n7~?r}?K|~!sZb^lnLNH|CV;YGojHIkNQ&H3{Sj;-suz?} z^Cph8Jt}&o(`!)qb}Cyop&F>n=Q`QHCA8WwYBkgVQM{-YdKK*!cT#Nfn6qBO0B`(e z0FYa!0=)^g!`WUMrqkBbM+xFafLPR{01!lW?})TB(S6{|12GQ!4T{qWW+RGuyB~Q$ zB*8M2yP)R6ABx2cL%d!Ek3xc4(9Lv!f^QdZXW7_1 zWR|R~>zjJ7+rMEsGg{%(QvGoIc$)lUvI-chUowT+tsN#T>bMV>A_LNFPcESJvi%h3 zw~VAH>HG&=?o5L3`_^yxtme@=R3b@68lQ!4kIX69$olUo7~yjkWZD6f!*x zRrwU!cxESvzyNv<$~x+4mT(V5FY$AMhqj}iHF?}^tWrO6Tf?c~JZ9_4Uep_yoDV0t zn{T+a=IR0J>E<1Xp z6LWb_ypU>>YgwtCBYgdc458B>PE!S}Mv&CPz$O}ylZe5M!-%gWxe%oJ!xOdjE`iw{ zCL%OhpHerS(9@wf^+Kk6oW zj)5S*7sns6xeRkGKbJpsd6+TyBx1S^@F-8lfx4EgJ-@QGo$_OhLXiQwna^ohw#11Y zO>^a3M*#vb+yu!-I*-X$E(zr+Z5RMQ_BIBr=cS=97|orvq*#1i-p1W@7=bQOwD}poE;;A_xK*Z?6$K^MN70 z2tS;C+9BSaMoemwROt`v0<6BK;Tu7qyZyR_EI_CimeX%c1hf8=9oO%6dXIlUv4


(UgFYtu>+ZcULtK+)iW-9fiNF|y(&MyHE8l#4lz!q2_wwZbpt0j^9lMs zW3xL(gM$JSa?_2x)Kt_{;um+!XpVYe|IWqayDhm=Xo_5H?m$kJedZ!6B~RD^zngrC zXXW@W+|3p#-;K!pJ3dpa&*lSGhmK-*@h~{*L3DC2HVrBpE;DxK$~?BMr{7fQNRv#L5r4 ztH+>61eLN@SC{&l6E@^_2Y!AboXOg4x0%`kpqI9R+PUu>h}W!p6{b9EN|5ho)&e z1pQ4GHOXJ7lUm0q=Ee`qr2?dUS3!5IRjW4o9+00t@Ry4)w2|~V>azQm6fq2cWxtwh zPfH~1r_I;0Hp3_mkJU}BL;inK}XPX7^8at$_19{j1^u+y~ z7g4?#?gXN$DhAh>lVX1vgYIRM!BIRf4o!j9q^E|3a1=+Ukz8YUD;FomzwtxC$u^~- z{{hp>I;_m?)3$II)xTc%p}%EBO>$XF!MWw7?JSSTwadOMl090J({$Dm7? zY7O9hYKn-GDk>E^sSMKimlzVjjpy`8Ap$y)2KcxzRrO^{Nvi{a`O4Nf4h1P+GD-t1 z1>(z2(s|vC^)HIP$c<|migNkM!HzHFc`!>NZe0Zp45~O0$Z&YwXZH#L+J^s_aH>QM zJw_`&Mg8Ga9ge5L#T*To3^)*7My~f{v3qLVxF;Ze{psZc?etS_IKlp=aye!@aF$9t z6o|hdr)zmPLE^7E_7p+Ivb6ijjpx)q{;AVpEjZA)=KiK7mkf&nm$=<_Mja^IYZ7B_ z?)`zGE!A3^SG)FaW+kUyaiYzE&zkGtVRm;<~ zFB zADci4{+oX<*q)TjytUJ*kkByl=dRg)KkO;r+*VzXt47m)p(#H)GE;J~oG@PC`-)B`kdbofe>I%tY+q0gn6-Dhjd;f`^nF z9xaO{AwpqzR+sbCtyWA|%BRIt10do3!xV$z9YCVR@#v=y>rPvJ((H9MeS8prKit3m zi{IK5g_{2oo`28o+&_y-73Co`NY^^+%HF)%s*K~v9=WyKldo{4=6djlemprvm3$Iq z&|*Ye^hC@*YgTPAaag)>r}z7Qr8fQJ1IhW}B%`(U!bPl^swriWFNwL9U|YEob7mom zt}hok!73i_M0_zzFk2)~)!k&TSmX;vfaDj@<2w7?;^5(HvwhWf7#O1mDlo|K0Y8~|@UCE516OQaLxLi3n0^_8z`aBY>LZCsEfl5ScO;V|mDp&HM4Owv z=%0q}%?oQ-zP=YSFEGjlDFa^F;lBej@W7+DqeRme@zKd2;rHhx|1b{zmV|C-^+KiY zyk^E3_d#98mxU5-unZXu2|UPHDRW2wdR}n48`plZtL{EnrRDstOuEkdJ0jZL`}$E8 zNWi+g?*PIt2~O9%+T7k6Ij$PiPWqpOmOJrHeNO9F#QhaASw18(9wbIh7AwgR#b`KQ zYl`+1x_eH-0h)TU^3U=Ssz}WWrI;3Se$6G#0$`!?NWW>5@a#KuS}rzxXl*z!CZTmppvZZriDYMuuTZF>69$DjQX? zb%PTbxk%!VsG8rv)myq9n=Hjw9c#R8(%m6U*FnX(UV4?3F`>keYJkH8v4*ivSFTf; zE3_q$XUerxuog&j`ZmgJ%xrb^xdPdr^fR#EaHSq=OZ#JjiZ0h2g7F8UjGm)g7Me?i#ax5zz6W^0vNoB5ec$F#RX1^5GIiq zPFF=g#AvZV1JWmV2(P#d=cliP=77PWv5m|$NOLZr<6+3A4zB=(1{FmpvDXpWazG`n zx>Yj*FPlFbr=S?YVuC3hgzyv$*i7~83q>+r6sq9Sg&_+)ZS!P+ocTtaW~J}px7*6M zr`BiYnnm$oU`2ysW^gYo$K82KwAdVS*c0dJ0)Nq%N`VtiI3Wgv4bNc4opFlJfgM?Pdfm@I&>;+m+F-$0uNY;70HN#BRrOEv5kZ1h zbyUu^B_02EIG!fK*wJj>ij7o&oxv$O%Z4GMP;&g2b%Y-!lTyJiBkVFKof+$<50hM3 zgwCo5lH&M4wWjI?ALj@JU)g%3T3bILGWC)m#=)RGPI}5g>jw~ z=QcK|7hxzXuG{fP&wp3eKR#P#vg*e85z0R2A8s7+g!x+hT_CyuW?^?!f%0qX$5w@O z5rzR?Ls-nQA5PGNOS7@El0gvR-6$@^F-!xG$(BEyjS4(m%Y@fmu1N9LyreG$OIjqm z`3rb}YcDNZse!xdrh~kLkI=zaSW%1CAS!>*?hMF+0IJb&+Lo1x9v=WKE+W0V+hl@S zfRM#AF;)Y^X}oAL8nY~Km!oF3&$iiaKvNv&Oy)>=EbC>M?DZFEj-eO6Rae-IZh7EJYXyX?DCp@^8k0ijK$WTrrM;_aZRE$ZSpZc@KzdBQ4{^wq(-87MY zWQFef@;5d7>zk?af}Hwxs`fZD#i!D89hHrr5l(Ik3uvWD4@k>CEkH$G0QO7=8lyAc zf*Rlzx4JN*#L3(eW>-!n^LxbCG*OnHf&InO)&x{iT=!k)l5(76i_d7th6$uAp$l8L zrG4%#Aar95E=eAY8q#>1jNC-9hx2sBCD}_#!^-jv)AgE{XpEx>EL>w;k! zY2XD3GG`>65x;iXT;g9l3F1rVMoS&4az+?UPUM+M!gp-e!MchE4N`8odj~fAm@ML? zSJZCm^4-@IDjtdqd4)!W)$)cNYWj;e$Z1fVPrs)M{G!gqOY-+^@n~U!=m|#t^}jlz z*`t5Dna&X^HeX31b?+k)i2YWQUeIXwK3R+XVoLzZ75I?LoANqEKBQ}G^$GE`jS8;( z-0zu3IV*8lJ2i~L@-6hxR#-TUlGSx#)*R$x%a%o)9*_gRb}mwG z5H@rNfCdEc+zsy&P2`ezfIjD@ynraBP2)X0r>fp-&5IRzt4XvjdH<=`%oDJArq!q{ z{;tHyNqhPUA9A6%I|NQofmG<; zP}M(|e!;7i&Rk)gh4gzD@P>IW`z%}-r%4GVm`iRdbMI!`WU`eNvWWn>ZCXS2xKDX* z-vi`zjB|8Mm)%1Nh$j|)=OHXe68of0c}+A=VeI3%$oADg(P?pZLXZn1B0tMv%#ok& z@h*fTw8Qn3Dpy|k`j<{MDA0KR;CqYCujKEbThL~7hm17KTQUkIYk_}_Bk0OHNJ5(~ z8&W2>y;O1A=iY=VpzfhxLP$`kt}$0lW0aH(p%~N&CFk~eWY5A$6bis)E`pxNWc0e$ zrt#u7oe=A!19fipS#8`k;MV`o4=6M4#X$^dH2SF8cOz1b#*u+;6NoUWc4}R zJ}#BP{QY^6(!E=zM*uQV#3imU9L-lCEd2)UMaPt-<4Fof?a0vS_j2CzRG@LBqIEqN z+k(2g%ZpHyEAkV!6c#j(^>NNXNE8o*QZF<^)c!L9Y@Rs2_ zPdv}Gai)R&%l1S~}KfzP1T{*1s|LA;4ylc@bk6+2!*fA&$r zECgeXm1FptdL?*zY--%7S}PuZ!sK-#8bZYs{hdC5*V$Il-8L*G6KX~ytInI(z!75< zFfmUgn$5=k2y~w?u&h^n^zcYfvay*qOWl6VDwdIOq_$XR!wYtKCw%=K2|zC)!ltb=5McI zqZcj8c!4&?wotRI9S??YW7ZdHT`4@oW#vAF#l^&n*Y>A;SIRx|=MBXjjb7Ib$=2f~ z%gA10GT3Q!D|Vy_`Ui%~$o07j`+x}n9cFhxaRQ)Xm4Nb=8hjJSK&<7v^ec0jL8pBo zSE_935PCzAN4KX}zglE9xb%1h4k&5V4Q!Sd?|IZo$g4^CF0QgLCzMgf2d^#2Mm%mV z;p6kKvxvK2^?cHT2#>{he8iTRbD@FNvj#rwjoG&GZdeEEDOL#ikT2{;!5{?ecM`CK%(0iy_g|-9kPw3YnXZ;G~Y`kOPNHj!+Vnukw5{^_mn zoaEdT#ctK{M>QlG99h`JIgT%)b$_iUyWWKM7DqQr15dk}$^#hML%b(qP)Gk1-3$D7 zC%26G>$RiD8d6nVyh(|X`Zl-JXm^l=2AlDC3cJLGBWP=;J= zhv^|?GS7hS`OU!ihtVT)U@@V+YGNKwP*d9;G!OyjQA{F}wLNKv z7PrG*OQKW@Pgy|&XK@m8kS@+Xs8pOacv9XpqI(LJ8C?1w`cIhch0R_j&0x@vq zQLQupYh0wB76u}XXoL7~_t5pKg@z4^x^vX8$f=k|$F=~JtbG@^LLVIs$${-kXbZ{v z0i`ACT7y**{o}gb&EK6w7+&nGfY;7#MPe-NNrwc3gfn&zp&{UGyy&Uz4wGzxCo4xh zrpq!7n4YKEN_rk-^?YRa2JM7H+5oKVWX&9TNPw6`^t?99L*-0kQ+&#SYtjrpo(g@U zZIw|oNjVTNwCaeQD9Kvq?R;AmpA)+F_gq&HWkdBX#ueiP-mrG@^v?)WrUdiPws0rAzvLilo> z$G}~s2lMpL4GCn89Gvr*vZp(5gWG@@d@;4xQfjT~K5Gjjo`-+-CTorSbjvV)pzU%! zLYm~J`xm@AL2nO~J3X({fq>bFpDN~EdAvIjrvm`BiL|s$z&!GT2*86I22D0k?2TY< z*Ec~(Z{GtY>q!fuhUnY-+VkJ!S7HnTMGi+4mVp);#yHo08E&$v_iF&JvUjG4bu>&5 ziE{@&`LWPi)?U_`I7Zn#?6=Yt0=n}4sBbWWr*#B= zlkY=h?RVQr-V&S;=StSUqZ8Qk81)^LtQo6AUkD(4TuC~s^1iL^P`4tcwNebvw_uJm zf0kFW9gpY5gI7xTrkQ-b8n0p@hqijF z)Q9Y3EDdwp9IvCZ$T49>iXt>OFFc`38XK;t7C49%D>N$Q2J_@9vL|b0{xApwR_BY( z4qrU{Dq)81wN3stis)?J)-GEPSI3wINSDyYW@;vT+mM%a z=CXY=a@&=}>C1-V!qcH>efTxYx~4huyiY^nFmYaVkHx{M2+STJqBCW8-0=PlZu8Ps zg6VhoDCilAQBTNvUclcUKmHMa&=z)H*5Te$rcqhjM<$kYlGb5e(YgwE*NtdcPAr!O z+6c>L-ng_MxH2bs+Jelu(9hV0do75>5MGx8R)|t;F9Y}5dH&m=vB7w8YZJ)5c@4Ku z*^xNrp>2ED>;SSTZD4p4uUKUsk}!L9%W+A;M~QESF;bJ}nr_V=1$=<0ruS=t!z&K9 z4f7oLJx5mkYJNd&L~+C)lsI~^8Fg3EB1kY{*ME)fE7kH%5Nm|YDc?QpBOxyir+B8= zb+5K#jd#bU*WG3TcpSr(ZIW1+_M!y!(y@%V3iSC+5SB z>31uT)si@0xH&wvvxlx4E&_+4Lx?_;lGe+G1&>h2n**M`CkA7#{U5@NW_H>Kmg-KJ^P;k1N2cS06AKK z|9VgWgJCHNnr<$g7im9 z^2To6FE)MJ*j7-88{s>;99Uk=Y7!J-cp#Sv!u< zh#$X2*G7#9C;))X2q#`5x;U&6xnq-8Z{d=6M6o$Ai=_6v1!Op96$o2T+NaRY2m=-k z1R;hBJJ1EdwUQrwoWU!?VMT?kJFv;uRf@HupB`@Sw@{Z#9N9C{h^aXUNA@aE7CtV0 zCaf}5pp;G}5R)?^b~2>Q&^2()T_TXmf3KWo>&yOh^V1r&1_gGX2w*zLL5M}(`%0?F z%vu%PVBBN3Y2Fh)NUCKmM$T1bnHwV$?jk?j2xp{Zydj3wPt8@cDP%GEHW$v|O+4h# z|9Pl`CK=7)zOBCQDPZ|FdTN)u68LBXl6O*(g3n8jd+!pWOV&!{Ni(O^y#}o7JG=T& zZQFxGl9(2So#}xxfTt+SZMJ(lH*1d>y zxIVOLd_fT7en`qNZ~mIYnybtbZ#71YI-_#Qq@|Hr!qCk<#b^lkEY`n|>b-#XkEviG zPv)^WEl|9tv`BLC^}(609s(yoG=JV^Qc!F@ZPPqLI&^tGlp?iMn(HEgytArj+OLgdE9pzn#GRK;3P0` z>*6j3QMRh5apBUI?c`muriN>$-@}xf!~Z~BI3cmCR{QB?k?3m$0nni#6cKUg*t#B# zRpD2b%FJX5@$UHV&+L_CNv}L$oQm68!aUIpKPELR1_~0nI(5%&WU~f=jv9461ObfX z4RsM9DR!_2hD#980q#_TnJ-NB|FyL)7%DfD~sc z+u!tE#ds4lNBFE|JcpU|2k#cEX=K3M966b^Gs9s1cV>EkoE-4_Qwp>3<^i-KC|;x; zdiWmiy16ig(^_ig45xFEu_SRr|2iCtT!`fs%j)FMhr*bAZ-2)1j4f*cA&gb;Jy~wt z7g-ee=BRG%12d0xX1EvzKi;O`9E$0g`$NTCFcN zo!o*Sq6y1p+==daeBkCGdgZFULz(?iyr54Q^%cKykA8V=(%4v0?l1TWkYn=4#nh9^NGzB;PpuUX-Dzg@{&pNn%cMckLOD;hUGqG$aYY-Eut`Hm=Acv+#gHS^`JI6gb;+}#pn(jhNX83y8X2v z1^u{W%cvF4f$*l9*uB4!Kml5*Ihu;L&IXp=psahq`EPc*W{%X0hxJX&>B43Sre2m&RsDw057vCVM?@db-XY$gkjxC1$q=T?bXFB0{-5Ar?!DGg7 zIHW*Z3_uFhZKGh+Vz$^o&EaEBRzM_1)dn59c6s0uR+doVm#T2iwQNm&qaNzrBeRy? zYgBWjuEi7%j+C0zbFarXLnf0ok_R`?ZV+bC8y6d6@I>0A7bz8F2lN}WIYa~`v5{+q zXjodo0bnlg+=oLFc?vrsx~W9z9&z=}mBX8;3`yNAPK@zyLQ-8T+3SkrEoh~e5{ivw z8%`?TmlkF)QI- z=oJ_44@0K=|H$n@5ITH7@+VabU1QV`3|IxQx;qZJ{h(UD3uAalV~5g}|2FZCS(Tqw zV3hkOQl!aZ=sU!vG&yU%si%bCV?B9{<=^Vb*aU%M(0=64vmgNif9}9wfOzWjmDUVC z2rBB-#@~&~=CdseSNz> z2(4fohd-mE2C9;Ey}TUA1nZ_|^*1DOw6z?nQe6EyK)`smZ$IcKF^8p3Q$k`0Jp3zl$X|T#&vLD<6tLqqFXkLb;LXw)ek@s`j#yG`x)g-}h$2(28^( zx$!Rzlo8+QL1!lU*Y}Yvc;%9t8%375QnhYR-UpRyR4cK&Zq*~Z@bmvJFkonYq^%ow zh3C=O6-GufohF_Z6N=hMiU>&;1-@K2N+#dPX2#~oq)s|Ysq+R`$LE!%)&%Y>~ zEx-pJ!ZF$ike16_|GuFWDeoG(D#lDZXa&JGn-0_&KE)Fdr_w*)7ykPWA&`rvGg_%j z8BSam-kwnBBU5JGW>|t_7%vNeqUHa!dL5lAU&k6_Ss(-B zgjDTC`kfnbS-enN>-jYNgDszo`|*0oKx5&}&%L@-j-JIP>Y-H86gs}0i3pJ2An3vq zTOJ$)Bux}bz?;5F|B2x93{{;GA4iqrmuCDx=6cL>cb>gT^^ zgRxY`Iq4o3Lo0iNRdXX=Xgdg=2&8} z+O}6!m)Ap>4*etIVEtep<4E;Qm}q#Wn4J92BVfg#bx_g8s+rVPD8 zYbm2_HDPJ{JI&twkk?b-L1kmgOTk}g{0+#+8C)2G1FffhywwgobfW)@`f#%@*|A`j zST_L~1Zq7<)ohX(cXDd-m;FPB@aAE!@`CHiz(a42)rX|yU49%|l`8KGPHqAk_IQW0 zgoytcjN;XtLHoOqxb2=N7ZIBAsp+XSDbH5N>P2#a2|j z)twxQs#RZu8?)HgxNT9+7#l0nO{6&E{FZd_RQ>Gwb`Og+hA*Rde>;;z;9*To8PPe1 zsJT`!?r7P#OVpd&{bz;KP>zFCMmN6HvM!s7ZG{@CQW*1wca1M8l%7}ye3?vjkkSVr zg^Sl?u9owUjlTev1a?X;HEK>9A}G5CtX6_I3~oFgVRnm^ZTh3Fcgsj5n8P4-v5ues z@lmlmv80;lEIIr>DzFKdaCvEOM$>16(C%Ojpf5(F%6-K35FJ+8MSGTtMad2ZgtWv(Nt48JhV~#9eq#dE7CV+h6Ope7NQsEoCNe~LCjU&R0JsFGh%^7LF zgjK1f#T8QS*2*Hk!1wC;1nH%m{KUU1iBHLJe>`&$14i2)PK?6{>vL#m1<* zR;AEE)(k<7`=tET78E(l8ugIqST_um{$p$vQ=%hF*oKsuL9{BszO$;Qap_)4{Y`jZ zo$jab1-(0PIbYlPYhPA9lj7}zT_L#XkG|MN_tk`K1;6a;kMte<;#&p;cBhMB z_!T;>xR7beNEM3?`Hwfx@HOHG98tJN=^| zeqXsmEOqN+asi{vf=y2XW&MFVq69$|9X4S%hn_Wuf@^PpHFW7sxm$!}tn8$w`n+h@ zf{u(7NLsWDXBi4fPw&D@IA>-0akJ>;!L7bnDUM&%7d0WhSZaIF@;v^@@)VLCBj6B8 zCjW+oE?o~mzC`g5#+}5UoP%b$O#H*h@qg_U*u1d(^vy)ZRDhNgyNI#O&!0YN4xt;J zZ#I%J^>%h8(*=wmez&H0VAVOSE#VYIj7~>uh6E!YUWfWlp8Rhj*H&FGS##UiQV(S9 zKf-x6X|*eG)D$y`Zm7;L2x`E8nt3fSg^asjnIo(MdVe-p-$I$^x6t?A%1cU_k1 zBXaC_S=Yg6uW3Hpt`t+@_jXiqwv4%$&<|evrlpJBJbLrPdVIrVXE9Nj}HhCBQXpgc8z*2}ziBqyo~Q zqs;kX>J4@Om?ZzWl)>v}34h`=3eVTF-eNLeO4Bd=K_kk(AWO`oXZM8MfWo#PUb5yt zBtYSRug`$VQ|COK6HYS* zuvoiy(qjU!^}Z*q59{8|CBAu;PRfPm9j_{xi&{7u4Penk)Tr!_R})Ap-Y$18qAVNK zr~gr{(ANkUdY!f>2|SX_ie)vF&5 znSt0$5`#bet)|+i#u5|d^4;W!TAq@^90$>v`mWTeqA0q4+r#g)h-!M>5jD?6f}N|J z1Q)*sV1B}$rEauttXY~Mny~)AXnwdbsVnMqonFtct;$}3QCCTfxYSlQ(v#N}*7D{m zwEBfoeDL+S4@-)UN$dnPC$)Tm{jh@7@H40!7%V#&|&QJ zgKAjB(xbVsw;3p~dJO`nv?ow?02WKQK(+R)RZyYp>M*A11iAr&!DekFNx&LLv3WcW zwe;4l_~E*eB%hlWBe^Mp)WB#y9CVhMgH=EMnWs6ikW$FP-Z-VbHd8F+nB5v%2Holz-7*^z|a$KQv_= zFTw0CPwp!L-1!@-;?v_*B~h-|8E~)t-N4;{y?h6B0*jYJ7Bu&gV9DI6t9<^-(_;tZ zuS5WIyy5>)@AndVcOj)nLr~_Zq4)C!NXFo@6PrEsnQY+QgdenMs zya@R*V%_F2&T}M@t0)>gX6V`bAvtlpGg<y^%b`q0?rIysXGYl$Lg3IddB|&`B?lC37sc0bB#{ljpN|@x z9Q_`SaSUw8zc>)9(P3)|L1Ot=v&XIRS?EYlv%hG5hMDRc^C z^bNmx?#Z0A9jOLiWPp=!dXej=P_-h(EtH7U?jy7<6|y4V@e+sHyzzn3R@qHowU;|Kyb|`$_X<|lNCydr-kd3x^ZCdLd3y1JZ&_|ZD8mLW_QvH7Om&ALO|%t+ zX(~64J(+IN?zUQd&!ksBi9E{(pE38eewu#7sZbgNFYtBO|TNp&D@N$qUu`GI-aPl1^16K=Hi;gX!pimr)4Rhbl zjao2DC3K&Aj3^1oE_6kDS^m5NPR^V!ne4(aGn?<_0!)Gh+=bHx2D|{@%dyeH^CXN% zOxLNJoGV>rSk}Av*Od9-BM^!&NC4v&lQ)I1ME9#^+k-t4<}`%MDy;=(vh=ehv@0zI z59LPk_r_t;79TTcj-&{_M4u)Hd%)QO8+0PHR+27iW7a)89$en4b0)-4bTx7mBN^%C zXM{DrHqMyY>C(d)))K!AhJ*R6px}_9!$v4PWOXTp{VUH^vZ=gdwDeH#nmTnq%si;` z8sDbHz1Ck3V$P~e2rRbI-2cU(8tLnnbZ}fj5eDd~cZYnBm@sMzcgWXKdwoiG_+E~X z1tX_F6Zt_AYrS+E{!jr3b|UIZ#=+|%J2&fm$3p>qh7Yw zp5Xjvd>g#2(FV}si;UTDa5)k+SFj&Z%9)D@DX~f8-q-Y|Ed!S|P2kR4)MVed6p3vb zdR$g|AS|MSX+R3&ft7T6Aua-0YaGv|+3?-qmNmX<{Ue5B$za5D)@p62dra*Y>@R<4 zGshloN2zjubXMno<&RdM6siwO1kIVmvX8;`zf3ykVNv#m-jcDmZ zk^Y?lh#V~=4VOs}O+1x(3yGH%wxs!d3oL1u=^P_7g@O_cZo`R*46km6!YOQ?gCdSwH0Xcc` zy(Ul{1_+jKGXJab0?`jOT@lbte+mQpi?Yk zG<``77yO&0YXir+p8j5{?!K;V3Axc2Hj*;HKBV-BC4+rAh@+ z%c?2o9g!YanzKf;P5^v`6Th3GNhoXA!`vR{`k=KUPfXXY_NiD`nV7hhcHV>iMA$kCtjybDz-KHe(`%Eufa zx3HyMEV1S*zb(_O`_07V^EB~Yw|n~wwD*;&R(Ef%ez*7*JS5#Q7%r=)i0@G=-QTGIw}bgj>&!}csQ^+n%q zC1EO&!EcL?G!;q9>Wy9Ni=67csc+Z?X25wdl)Nc^I+x^FZYZZlvj@WFS!IK!Elpn9 zKkk8h!}zgbUwdMlf85)G;8mKM8g5D`Y@q?A712Ci(}#I_ic7~mB2weB-7huR2IBAI zVDH44;bG%5)pEdnZvo0(#x>>ba0M(Hs&T2EH*RefEsuC^qVduSS5~2 z1z0wd`=f-CMLNh`le9F!kDZ&4%kBV(G6SCOGxER$PV4PJ=i>Vxn1mASE=3Q#XYi60 zEKAGf?a=3$>txCMp_#FNmrMGQ3k-_$u*Lu4RtV_2IbIiTuqiG(Rd1K8^{TQ>-ZL~U z4FK(;kBOqCk^@Jxwn_g)OG;y7k;y;zqHMeK@>(c63M#}e$)xQt*fblo=(Yd?(&oW;tR;80q z{oFywN!Az!{14&oxJ9^pMbb!MW_bHR@+;Zjf}2X}0OI5JVX}ju-E+J_Szrazo|n({ z);oG3k(Exu!0oD1sO7_+*a=2Er1{mZ`OQEE+`JS@%q zC@qx@I4|MuDdFuf5ubUME^;M|57*K=dt3QB(Kz-(2C_!56J@MmwX!5R<1|tWDp+71z^>@Ne zKwynm^7b6;2!Y#jhAM)!7=%2CcynLO@?Lny+-?uS`4(9UdAA-o9^+$%{JvtSDV>3A zi$a``19Nc+q>P~5&f-VPPQ~$b32vVcJJHho6>6&%hDIp@f%4SRg}1%VYGX!V!&K}H z^AvwH(-+*jrv+%XYss}nX|#T{vx!icIXw0U(BIKYMoi11m4#ZL^RF$pxFE91c9$tw z5>b1CMUN0qJ|cCgyCvSv6Rj0o#xXf zpx>=ypd2=mu`@bL*4D^bA$X%+1Vby6Rz}8!nD%Wyzlf@4d5pjHgxlsM_oQRJNoE4g zQbV*#QZix%7Lc>A+STIvidR3^$>hc)$`I*YL!;(t52_(X)FM&4jgU+dNh-zx7qa31 zR__ePZN(#*Q*>@`t5?b`1hNhbFU?}3>q0acO0!-51%)DAQS|`Tpm=Q>Arr{MJX0++ z_qtQ6JUjewtUK=m`tF*>q&8W(?IHcbWP*u{Pc%a$45tQbXaFCCWVt^8Y8BrPc*EzP$W)j8 zA_QVaLFl!K#ROig3+l=1YQ=f@6cbs?t1kc)gnO}htn!3`ITI6`;m3g$05|5DVA&x- zta9qc6}UJ=;TI>)=qzIWik(Cr0p*+wV{?rs+KqWZch%FG?}RG=tk=vl-$(W;C$y4h zkcoTrGN4{6`e}(Xkc>PjWI$23PkxZWqJ4E0Z?*f=vY8j95xF5nt4>9d%Tb#J<@MdMl_u4f6*t(}Kq55GwIt@Yf;4*#88fcr zpE?wGx$*d{+Uv50g;|04^xi%8=luWh^^M_`MO(J9Z6_7mPAax-+jhmNsAAi;ZQHhO zJ9(+w-S^$T{a&B%TYtxybDpvH*>mi%){KpE3c;|QavU5v7iQ`&3NqW~|AS69e~i=MXLh_jawevzFtR4HFr@9g61QV1Hyy1H+!G132u>Iu_eO zH$D}ajeh0`@HnN?Xxc&af}lT+j_x`D>_w!FOn>4WM1%(+#%Rs20iz_(4MB3Cj~=J} zPqz}&qj7TWg!2Ye^nJFpmrb%5NWIt|?^7fnPO-X`sD+lSGNK!W2Cr0}92}S;1a+)k6d4QG_Hf*gxhU-whA_t}Ph$~C;a=P&SxJ!{>dllug z{5$3e-E`BhrT#$%vvSy(CJ^BKL4<5~VPpq}-+7aW$@~(3Fs7|djuguP@??~!i(*?N zY{>x15etr9Pewt@=9O}hSsuqrc}(S@X-`~H55+U)YdQt)cQv5OpB$ng0;!gVt-Tfq zav4ehOD9t4Z9yrusV&uK;eS$!AP+xdXCgZISBSoa&wToT%0Wcgk)^n`JR&{Z6oIOq zy`{ez8&G%<*MerVKjreEV9(jOAo=0`$k2A#eJcRSCy!oX$@e99X*Pji(?vIDZqpLa za(IDSA}%yv=mFWfU29!4nai=GHACe_v4~08?nFeO>)+5oA8}4JGlorXq~e-NChJ1& zXs+~l;Qulx*SNJ;ID<70G+tDiF=Q$mKgu%m)@0v$1TB9)h4Wd7o^???s5Hg#4|g8) z$*G`5oujhoE8i{_4{2)H)#j_^)yx&6OW%z(l&N24*{Ro97UpR1A)8<@*|c%ZFQJpn z1(`VQF$s*VHZ7btjt&|QIIj7T!nE!m?L!D~_=7!a6e{1#I!?-vr`g7Fm>4j{6dQ>>;~b$M?O!aXhT1Fw~75|$!wED-+Wq#VWobgKg@ zMteFnr!+ZP)kP2j_Pfh@UR>-ROK1D4-#X{k;tstJeV*5@N21yG61^% zCya6LEiyZNvGfu>gnPDxPBBSx;SG6gPyv;ngV^$KQ%^zisy7Cng#7j!l>AOWo=tXmS`7yYs6E_V;ie+LQSPWn$C#t{-(zH zSc*(;A&e_JbV-JLfIP2uR!}()w1>3!O+9))e0)hg;4BPtrK37sB$(hy6 zdZN7*=~nmh=wsdMNKY{y{iYi--?BJ9fsUB;a}q6UqpU)QQ2&Tl0Gvz>nT za{!&iuodLv>auC>@bF1rnfj?4=7mq?=!kkTerW@N_Rf=msp~(?aE?0;=(6^KKBZ-m z2o#9`WqutHT|xS}L}p{7VjC}*51Qn#tV=_jysWr4w@D168H-c*K~-WR<0q(Cf#BN# zR)!MP{A7wErUVk#*A71yXQCdEf{1}Iay&|g-RbF}Aoz%aj!kd@Lbx=@o!inq|0(HE zsK>=;!?TdZ`U8Ke@((`PT0H#nAJ?O_`pQ%ddZ)I00Z8eEbQD36cR}t!kafAEK_Y!EpINoK-ZL*9_B_cYOF#t{f^Ge)p~)?NVq4vpgGL0p z>zE)dgj4j(T&5;^=9h11wZ?CJfB?2vvZHN-E2s%sKjP4Oo8MwP9t4n3MwJ7Je+tSs zXWqI?2h^8=XwmLhBdd-jHaVGfQ9T@1DTgJo!jwx(sjC9w*16*8&l7Mrc%$O5F@Ob) zD>)g3iyo7!N=Rv)#GH|}u+vRv2C^!EL5o;Os8??UOJQx+oO5hyMTPO5*6qA1Kn6CU zx_*kRw_<;EjFU~yex6K@{QlA{QZsD1<9WTcdohy$Asr|Go}TVaiOpcxVGO*R3ka03zaLx!=XQAibGEkb>R2RVo3*rB6#!m5lqg zd|9=Qa$Q**i_iHAGsC^F8Gr7hXs(O4Kws&Z(r-ySY_URj)KTAL;?H8 zxGi5Ut#|VK3!Ll1mO;S$OXlb%-Dl1+bEqvo&~hq@AB;ZEAuAb$L>Y-g{1j$33JW1`NNJ3q>F#cwZAHZ?38ZoKbrYGUtypD$jhjIK0m+J56tANr%8AL@s&9t@3mOHTKO?{SfMHhi32LIYb1|nPx|r;2YgQ4_dZf|e(^INVev8A;mjVVU zqWYy^0G3XS>wJ$k`L{2Gs&YM`*CFug0mri-8&gR>C+bjl4^+VEi&;Xm1C0|-s=#Ol z(yWJDmoN6xDJ2aUr4dk)ad)`|dSnAs%!~c7Cxf?%27oZDD(50x!tzIFRVhy^*NT@& z&P0)!V&*WeVHB54vZ?V`R3OP8t(n1RH0Fi233V*_U$tG*bRDmHtKGG;g0Ed&nQ>&U zqY23xgidh~7kmSk{S_q*-M917#)!xygdB<`;;yLIu=0QZ#EHY71Qr3bGO_M`xuYj={P4>13boRR8|n>&7{<*a}fDfL=gDpW?@r;cz5=Oi=M1dD@g%=8at5 zB1^qPBNdhSX3r_ON_WBPG&E%cYcpkk*JInc!O#WDX+1a6O%p0p(vwK2&tpaw5JSyW z#igf;)=6GiH4e$AA%Q;I@&N+OQ^+IYnUaZ^E___pZSeOC#n*dbCrUWlYj7dj>lmvF zV*sFRgR^N?jyn~9>-!niY7Z~s?3C@Vq)B+AgIR0ow3GIvq&!Juz8ugIdv;#@P!7!VOc@e=jD*P`i6x?6Z(6?&o4% zzfMrhb?+iQB6!1Qo#|yod(Je5yVN*dc(onb>bD%Y)(n>EbZh%37Jwlh3l)j$x{Tu5 zHZc0z5)%B*)kp?OlD-j6vbcQvg&7v?TEiS2#x-z%$!GKc?E{PJyZy2_7Ah}NTSEOp zsOTR2L%H-~-GiQZPM~kv4dhQDxbq)#um($~GF#SIuLEpewnb7Npd1jlDZeNk25jGZ z7?Ha<0)aEo;{3zG+L$BvN{2}iFq(+H!l*%yvO%!(shlaW3$I;>3!@_ZyUzMg*S1d+ zvt@9Xff6}(vGJJUHjP`KOBWaaZcrTd2+bw0efW!>vvawH4&_wE*7 zhfIO()`U7x*^n|4#Gu7RQQa@f;4+MQ@qN-<|rx@Y|JYsvGROh zB~z`|W)nalE7HlzMnlFrd85k*wioO;a`#RYBbWTW(}U4d!Mfc+>rOJL9rdqYo8;SF z{lECN*Z<+yrvIOQZ3*;mzxK`Xw;dZ05CZD2v--aV&bbal0gQdSwEwPu_iF=m^rZhq z3_AK3zxK+GUJTN4*KYt{41hD4*Z=0%UPl8429O5=0FVX-R(g5IVc|MlU8{NK9IZZ1 zJ#3q``jai$%ylbtlv7y&KrldHGdn!(`qT1!sW8@$qpfgU@3Z5wQ~2%Fw0&yjH)l5; z008J0AOIi$$~P(?;9qR=mBAa$RNfzCH|9>K409>>O{1fr%Z~6Zvt#7=4e8vVEcpb+NE|a)r9rxPZ;oJ6* zj!buDlRcGAMwRk2sQ;$*_8r9kk{0Pdf;jxQAejD<7UFkWk^eo2zlegPPykThzuMpR z?`Z+PKW+R)lr{Y);xb^{U%&o#%r~nrz-}s1{yXBgXCLspcK`T*?7k}D1Q6&>0!o=4 z1E%lv6IFt0G5RV7xgINzTc+STs19!8E@P?YTR{-Sih&*gv8~A!+uv`Z(gQorAkuK2 zqR2IXYPH4KL)F}2NaLE#`Q)E3%1SK-tGRhzkTM!Top`VlRpg6TiWT&)f*_|3Zii*b zx`x$oVb)tZKnh;O&=P6|Om1@qg`KRHJ78nj1gF=%)43`XV@_e%AkVhSErLQ}%9kL= zWMaYGxP{0?Sm;Yfh$8tGlhuw>yE?Eaqr1e1Y}C&ez#4U{5(?|g#iMiiPVWpW#Ec||_MT-sTuwGv@mv<3_jYKE{((DcY zT(Ul5fq?fx9Yf3$`tu+kfS--G3Zh1(uBYFqODY#;n>w3DivyD$`fQDOJ4_VH(ozCb zn)c3|ad0^t(1!5nz0F{W^kQs;{_skx`6zMMuF=oNg>774+;WvYzek3pl?yTRlcq#? z%P^MCZ|QCP^hWCtUOUjT*}hW4r-i}*VtEElm*9P0wD+!Z(pdJfNkA>?+$6- zml4zVC3F@N{U6NuCVRp6J?H5!;_Ls4xB>GQ(F)*S5SRb*OyS!v=8FIbd(Qtq5xIDv z0Tkf@{;~c&MtI>3*uRKcm;X;h3_w_btA8Sv|BdmRz3?#qx#I-xT+Y-6$k_V}mtU>^ ztNBhWzW*GEw=Y(Ga=JZEy)zY3N$X@7tj4S4YvWj;&wX5u^}J5jt?;-moC1V7YtU04 z82I(YMiZo``UV#C0HKgF5@Y#^TZmg7h@FD}Cq^sJA#T9#=P^zt8;$@tk6-n>-yY)Ym z(rt&0Y&nzY;%$@K zVOE%=R|kcckkEgk^8mUw^+ipar(@ERv3&qcL>6q-No4*47_<3kI1bFdA#si@UJMSG z@1?@gln4x&YTO3|Z59VyuB1s#G}2a)PLmRNQO~j7O*MOA*~YSORLTX-pEpfC4mQQk z`+of!a7sgpEWgXj6{SV3`|_k0oK)Tqb<*Lj+1~RI$70^E{R~!4dpgwGMzf?IXP4gQ zZI$yz0QbB>z-@21LEyuCtiBw2*n`BCwdQ-`Ee?#o-8@+kDIEVy>ZbOzTVbo7mI5Q| zlkbyO-vYTyZoNrL!!t*m!#o>+_DR}j@#C&RwsIj(g`;f zpWxRlP@@@GTBf@^zBOrxLIi}Z8=Z+LMIW&FwFP~2;NcNjn_`qWK@ktDtmO82!zUl~ z_wyk6AD?~V;Ue*a(cra4ewOOESjxjQON^KiUCO;mWeh<_>q>rZaLrd(kAk+n!`$Rj z0a9tgjgQ#Rawu_}C6a8K;#wkBBL*aLuroXHiU7_Iw4_o9Nm{Qe)ott287jxn*CHSa zp~GpkvTYcEc#aQ{0?Es!~66CJ}{umdMM{UKdd(*umw z7p7ybm=N^cn%N5P)QM)P*oZL_jU`nDSf__i@n&sf0-_%ei!TPO93YFowD0KJMs7Cx zt!bqMs||`WWhtr~hjeNrnnG?!x4xA15FOFC*b7h-=ogo_ykVW+%MUiD)o+FlnV6MQ zm!qYOWXOlJ0-r08GQ~|iEPY@=qdoDU_w9OE1Jj|NQiq%dprWBGuyc?ikl$eLJTw-P zly9IqdidYSqb5|lYXfG>lLcsJ&9FWBMQo4Zl?t(C9CO@FhT3lgpx&3Fx4tM?#mw&u z`wslEhooM8&gwU{hd*D!`KYvIw^U|_h66HqrfMn9P1YVd?m}Ju2muO=T;EgFj!nk6 z_lOT}e3oOthGIyw*Lv{R@qFa=18_U>nNQsr~5(6MU&#&Y3P9yP;*h8b)JGV zloweIL<%mWCYKaoMC8Dl4&dB;?NKlXTN-blqbd~a7BDQAP&AHL_bFj&HIoy6dcoqHx5xKk^^Ryh0foR%h2P+ z=aZ|Y1drXyB^7$cb}I%Wx~b#0#$gXR&n&0aAF>7Rd_eE0lxn^0WEp-J%27dg=pKE9 zGTUpK5%9T3^zyKeMS4s+jKmcpq?OIqj@6w-g2LLX#f$CS>5s2g46IaiN8i=KtfYDM z;#XRMp_KL`<`1MPUjF04V26#)vd&0D7NwWqxX->hVxmr@ub-Jw! zJjAx-(C%|7MqU+WYR54u^!$+z1z>(X=cD?R zcG#t`if*f3JOwL}io%1IlssEV%C0`+QS%iM3cR))&tW6yEcw35(WvF-2LQ;D3#|oS zyw;a5R$-pMM)zax`B1MW!Zt|XqxKYoqw|!X;_wsUH<~hIsMPra{Z$PITVFfk{9xt}?xhH&Rct^UVZQ`7F zWuhy|N`ZbFwdq*An(UH8wShE(t$uNMYoYn7^XfYrLLu&6J6u|hOsSexG;BD!1%K`I zzS;_4oR^mx2{#Cw=SSQ&qdp+w4ny-Bd1jm$bo| zM>V>XOIyK7U^)c2QHCwhWNT=RWMsCSB@E0KC;C#qr=XWaZm`IQ zaMG(;OY{Ylm&hQWi=GGzY0H_9&)|f9%xxOSAwMvP9wpkKU8x?>B_>@U2wAXRYpU*( zMIt}`NO{H;u~{on9{UQvB;JoWSkMDoi#p(p)j(N!POL@o(b8C_rwW>LSm<|p#{L5q)F_%5v39Y1-ZgKFRF$r&;ZEDa^`twV@(ev*IYpbhkoRoVA1>?b!lr%4lZXI zblHZ6G~o)?!zW3JNq>L3p?R4wsQ8SmDA2EBJPK(D{Sm0KT0*Z*@*7$`q~ zqx6`&-_Bl?Ute$VX?RP+QnTO}tlV0jV;VAuBD7?BaFErNF@5xw2D%2DM(j%;w*nvV z&=~sV@X<-#jk%FoIN2d72MKObV=b&wZ4#KW225ONE1RiQwhu9al||%ktw(L2;iaQ{ zUZa9k;AOF~10pf;JPqIeltR?J2zz-uaD<+X>VYFHEBT+_M=B+CG7@{D(Bw^zqSHk+ z$NZ52LZ%NqrMAwhBQCVjF`oe!H?4Sm0SQ%`Fs-FX>9Tvjz88Hz%< zv1r?=8Ge$43S@jPkg;tsK=!zy+)0`Yzl$lU-64AKicU~n@@ccE>J^fuemTub9LM5L*IBI z2ooaR_ui7ZMD?nX%+#=ZSZCkj`Q!VxvnS3iTUB`TQSaBXMNifzC%JMbyiB48B39aF zj*fiCOg&0-oV;~Si?T3yc=?#N&R(UCp%cM7Dhh!BgFQQbXDB+B)!gxYmh=0$o>Y39 zHeNQS2s>tp$rCvWpQWWL+=>!F^?~BbHgQIGXp?L$t*iTFy z@zQM+csF)d=mHBbJHi#)-Z>~7ynE2Nz?V`Ck_-+SR~q!8tENC)BJR|=gq$Vr_AS=* zpw)K4nqI}0O?I(wkhWoDNpv{+vZ%DcEkwob1*VA1`+DvJ%yxipjv5Wfa9_FL7Uw5# zb$e}TRM*^@&}GwX?v`x$>cO(gTx3dGgjqE2)m<>4jSjvO{;XN^t`bLgE)KNBGN(a% z7#)n*5sPmBBwA6CNfG4#qLPnm~jbN;hoR6$a z%P^rEr5-<+-;dXSmTx|PX;P%cC`dGJ73H6b1_zG9Q9zPmXG+)|&==EQO8n`aC7jGi z(BUcY3Rn_rLgEaxa9!BZx}*lZY1;bP=cdezyR}mD2duM<^-74G@=l3pEeX_&)aHm| zyDZfWJ6SKbjMi0gM692S60P`kH1ubFxc{e?>BMsvNAR!ht#%#$ETz`JO}qAYi~awX zoSruSw%GEteRj@A`K{Ampd5zlgFj|3v)PtTDi8+O_`+5ftQa)_-NO)&G>mKq*6) zn`>n5e5kL84Wq{&Kb4WMnRFaC9|1%$<&JgUJvt`Ld(z2q0N=+xSAa^u&mv$W0T1S7 z;Uyv&zz9B^ZHdPnZfn~8Z7c#p!hB72^z}0p@*Jcc*Q1*$LLSR)N>kj+)w@&oUWZ9aqu*^hRLqjq${K^;@IU|*ON z6H!JU(Ls(zUdb1?`&z^1Rg7zBp=57O*ti}?ePoa#!tmo*v5ndGZ6 zgyHyv60YH2fva(U<@d|z>pE*xu48}C`#R&@H30x zl9r_aC*c>Yck9tAX1j1laz6>>bA=gK*~ohwN-bgLRk<`vne;PjI>0cq!x zvg$~l{vj#l10&U140%qNxS0H(FwntYh_o}BhXipMO%gMg3nGhaG!G+;os2gQ6mwLZZ z4OL@NL}y^0ySU~Eag_Mw*M?0C%o-h^H}=*q0dh$&c->^G+!pf3MwXFGM4@|ppSCKu zwdX5ceupiep2VD_lwUFv*LPob;Z=d?4R{%A&C=y&OscfUW0@;iD-B^RBRe>mYhUtSU#~P(3&Mhu*Mxyw32}G~;nU9f6q0P$V z5UUL(Dy1&`;OY&%DVNznr~UU(OUGUTinx&Jg4#}GZ&z4@;~znq)15Oz#Hl1*AafG> zF$1ZLpD*Y=yEPu$?r1=Pb=q0{O zp4(Lmt9ifZ3(0Rfx7H>`jI>TxwR|i=K8;?9njMVc`-~UACt@rgh5v}r8|CHyBD?90 z+PsGaHsqQzL1Y{zW7`%=V~rWtOQx}fc~m98g_IV|;P0456N%$AHX{|7yZ?5sP0YC_ ztu;r!(4mbyZCsP~8}#I;+jYv23~9I6f$@eO!TgyxF~dFXl!nFruAu!c%tk8Ecp8*D|RH+ z-uCR=EY?JHoajaUbErJ=$X`oD<&lfY>w>XJukblkKXAR!lZnwsy^9i0Df!o4T`fFN zkhMq$a<(vu0j3j;oII<&rxfFVtKZ`Q2KSUX~KXU`_A-832YWwjkLM+MN3;JYEP#c9V0z8?y zKi%LBAqL7$q)k{%#*BRo1%sWIgzbQtn4CG;FP7`oWwC>u*WNFe0_(Q?0;?narJ?Ch zsb5sWH>(UZ6xgt!rueGaUL+FrtseZQ`Ea&}yrZFk1IulbA9z|35ZROgE9C@nY8)G# zy1sN7+8e6#9Vhq@9iI;HEFpTi&xMcm8}X~ zqQWBwKl-Z98q=(!oI%6%A71A|)S(X_sr}DqVt?Z2ubcRgn5idq_6|WGeTYRg3aFM3 zKvJ+E*;`j#2!DO_zwtw)NlhTlu-@K4ne?Y~ZsZLPkUNhgYX^xv$Vx9h&@L3INf{Mt zltd6`;@g{t@hx^JK7o$WYd^KgE>uxUYONvA^ht}SfL-Qd7ZLQ~sRB&7@+_e&q7NkK zb-wmTw3s9;&4)d%@SG?$vR8G{F0^gVTDUfet8vLi_)Sh{hhIWX|F#3^zwK2`D354k zPEoQFuHT)>vQxyR1ef&My9Diks7)t=h>>B59E9H0*-DfiXHs9wFhlj44GV&eO=4^m zb`nWB0CPj~vm>)$j(m5$ZyrDHa5K5sx)9VRhKxLtSxkWuNYNU`Y$L(hWGf;R&I|L! zu~(%SP0LK9*Z=e-#Mm;pXs2h_BeZ`e!V4zJ(0pKL=DaClm?CU%E}+mAq=U#3!pxvb zPcXvmD|;pBF_;iX9+lf}n$@NuJwdw7lR5Su;KkyXW-@+DXmJ4)=iKyM23Pq^ehi}_ z8wa~8VYQkE!&x)>li{?JKH70A-|x!uBT`@p8)S(}-++nWM;avi_n+q;Tg;8N-I!B) zaR4Ht4K@C?-%V*P>kQY2x^k#Pnu6CJ1bx-UC`#T>;S_>Ro1q?PFM;q@l*pr}u&4vG z9|7G}V=%}@sbJO8d_eWS{mFsj1+})hS8ojYHjj?3OVi>3ZBY$7s>ZS&4%TuPXUU7A z#4`LG%F}|rwl6BuKKaIEkaN`pRjTbFK*omB3nYOR_o>ji)d+)z6NK4-o|ZfWF)p%! z@HG!(fPA=jR|Rb!_6UzxCl-c|Q`8sq@0y(+fJ#~wk^&ZsYV`eD5U3gvDYrd+_QCjC zFG(1RbS%7kJypbvF{aj@8IKhY2&J^}p775)4JhlCDuscL!^?m{-YGfC(dwq$zpMu? z(7Wi)cuCYcKXT>r;RAH6It!h~C(4YXK&)}5VBCliIl-&y@wi#6Cp>zqNted#=6+RV z64rzU8u29V?=9i|eoHNV;H;#l-JepI;a@aWYhuMqHO-bW!xe8d7fRWyT?sff6BOhD%K_n^e*7jiCl8UaH;wT`Z{pqE|8+}I>zttoXLv_FDP1& z{vKGHS|b&5WX@7GKYl1-ainmgw&yw|sj=~Sl8v2IPqY>ZsC-N49*Rp^#`Dr2TqWDP zu(I`V(}=d#j6C}}Ur(Y9$hHPCwvhdTAQhIDV6CZY0M1>}`Q=7*BklnVjda3T zbo==Nepik*Rn{NY)}A^>Dh_-l2m0CXZBvYa{!}-6Qa1ZN&~Ye#?Dj^ly5+tYDg(>nHv9q_12wtfb!B^3t_ zvuQ!r-LDVWa1_r(PeS~W%7RzqfQ1RV&w@I@%>0$KW34$C_Ifo*)yT1bq}IM{40Nv~l_5IUnVG{cDCO zjrNQ6WOsV=gqKydT64Y$TVrcgaMrQ*OXu#lg)bTwKr>ofS#HZY z-b*RYH)}{2?MVAKK#18o@pqj#+hHv{(vuw~Q%5{dz_s=jBKZ|g$U6$Ch4Dn7P2Vu{ z&1orOr4EE2A%XIE5MBp4Yu%k7Fao#CQd0`%&9SXhpcuVF_5YuZsrh5KWc5wIzq{*1O-d-;N6D#3i_su4Ixsr=d@tEHkT zDf*$J+FX&bS^(*i@k4<4yUH>+8d~uzN~QjZmVbk0nOcfu{GE zK{k7c)Zn1@{I7nLawM=BnFV4TwL z+@I_+QYV-jl!O_+!C#1CL9=gxUUoeT@EEIIk*A6mW)^b-!^~x`-dwbtV(sNMp|KianP$iJj4hQDF>kmOdG4QXYlKzWSbKualJ`^6#2b_GEfShxI=UB zm2hyyE&&aRCN#ASnV@!^l!768A{7lSaqe|Dgb@NTEuDjOY^a`IE_5O8>yATM!*}b9 zn<~FO1(f5|RVDGv-6iU@O$gCb{rX{u#p$B7zRX{^JEk5HdB;z;$ zUIsZI8y@ySL4`bS-^Tc9N6VU!r6|RhAbYSa&kK@`UyG1rxFdo>cf*SzRF(%l`R!$9 z@O*aU7_9wz7*-IU&IGG|y87cgFZ**GJD^zJ#y?|C`pGaiZocYy7u=(GFNYL~l0FVA zX8pjrdNuPipa2lOh0D~;n&*&c z-6yr;$C^B3h*kTd`rXpJFyd_3_ z(+%Mn0{3Z-A#h`aqYFj6Lsct&1>X7nxk^R=lYM<^Us}YPDTV1&LX#uZBeh8GLt-W% zZ&Ey1DX4gSt$|NzDCvW$-)FjmaX;?x>VAVudwt?#KxFIHJ&9m$+N_>K>I^Y}fBr-w z;b!5HXIuvtBJV0UOlJ!V#lrt&MJ&*#=we>E!(VS(Jawmf;_rt?o(<_DZw&hp1IYEK z-vPnX)5$b>_PpGKtKJo=aw%<14kI!~vb20Vq%d`#AONHA4XOunc2%_J`Fo2)J7?s8#MBJQ+~|FHu0CbH zSH=;M35MBKXu3YuwPs)@pcK6rqc4$3Al`F?1rDs_86!INs{=3G!nHf<`RnzwI}Yb z8T*>qERuPYqr${+M~8J9Qi5B*nc7)psz}fJwVKo0%NBUOK_DHxpZx|OwcV@%@)U`C zqWFg!Q12zr#z(S1g8Ij14gMm8B4L)}RmYvoh<%=%`J@tpHq(LcI1IDVHaQk2Vep%G zyt2(iH%882BMlLe$?4KqLi1KI*j;7fH6aGjA~jW(VICvp@9TUjJn;*oMqSD< zZ42jzuUT1z?ry6+gK!#c!EOG_u)47Rqz_D^NeAs;mz(!$s?c1urL&VQOSc!LZX`Av znO>V@v!w3Lu8@5VBP$f}tI{%;R_yjnCfyBq(BLz0!^fk~PTI#NPZxAdZB|8SO)yR_ zBrUm8nA0=}=@gOxkWJ1Asq0g%6>>Wy^ZKOpHsU6S=!kEzSh6>iKWV(}#2u(5s3t$n z>fz!ll49PL?uq0rB#cGI9ssR#keO=9n&XoZ*67fyOHw?YWRbf0*@c`A47D8(Z|j1< zTi<_no}46F*{QdCwoWX*Rfy%8y$7s_wBqD=PvwLs=g-H3ZciUGQaNH!7M(QcaIrN! zwqd&2go1}-AWN1p5p^a6coq}yV1-z7+@LaPz{(3xLUZoF`{4$EDxn=qbuWOBMF%h& z+kMFrE&?GW$^H>Q6{j053Y)E`{fbq9Ie3r~^S`5m8!4MK+9?et?u+*ZqBOX$V#|YE zS@LZ>Nc&y6(P778E>pubZ27PPv4>lIX{Z{}x-I?loMsl2U?G%fd5)c#8-*^^DZ1)U zwmWkd%9fM&j~Bh5f=_&G-T{8L6YP6$7kTmb z@FncmkKODYy`WCLH3oBpU6@mO$8H&~q1&Rnp0hbyU_wxe4*qKYVb>_H{oo${cMvap zun_l={<|Jkn_1wr`(dd^7_Z%@U$~_MY;*i4THs59=Vt@0KLVcRQ2>xsnC=x+ys|#a zml!m#!m2F|oN=z8A2b4!eu>sI39>8uDPy}gHG)rmcIQn~uGTJ*1_qKj2}EL+cB!Xa zavW4$+A_q~BZ}j|VKNv>a+#Zun#~ZGAZ)})6Pw!O@R~8ym`xSu#|8Uvtm^4jnab7}^<`n@q`q@cW zS7INt8&vm;^*}&AJ(I(pS8V2n4hYn=%ZsbD3_F(UovW5ZWjk2cODSjz7F4PG=@l{M z1F0Rj`pJXFgib9xf(%}# zgaB15wMM>!(q>oq_nGzKQ#L-u>Ou+R9fu%&Fivg3(h|-5x`Ye<=(_qJP^UZ1&?2R7 z5GDl((LCVSUH(342~%xpPnr?$WPd1ceKFsONOn26S)`d?DMh)NJ~H#LlomhTn$g~( z_Vsf7+P^?KA=vgcbtuJNjrhM`1OHBKMQdOgaB~fjn&9_yEOs}w1C}deKVt>Ah5J4W zO$q}=5vEV27+1NK;UPA*S;&hbhG0EVS6(i}c~4%J&Z~LnBbj|-Hc0yz(t)FT635!0 zxA>$HMbT|n?aSTW9*y6Wbb;xxf4We9sNdG7wCA zrDUbm3P`at$H-nxf;MhP6u<&7n;J?Da5=w#yE2?51jW9(R(G?7n&DCgxl13t$x4tI zzM^dVu0zBU!Ss=eIcSPsZanqlu=~hIMboF7q%B19af};RU62jE5c3P5pY%=k=w`So zlcT1!2vZj>WS>)3HPQ!w)V$e3Q2BrZYc`z~Uz(9y%v>?GIz?`uJ!m?DHdY$t31~m+ zVq7fcGu&O=-hq ze*62fUjSPec-xBV_esP`V{bDLhg^B2@>2khw4N6GcznF;!UD-mD!rriMv2Ec8j;NBVshuA{Y}yYMR7HBcS;M}6|zYC;ME>v%x3 zN>7f*-8BMWo1=~Mua_1}Fn@NZ4tTmdcp=GV%}j zGHoxy0DV*Sp~pd}5>6O}j|7gH>UBT`OOylqFoTftB`-oT_Us!LD=|VGCQL`>41zWZ@!%$8(Gd;1+-F5c{aY)V&8$OwLcQsrh9!Yv^Ekn zDZA-Dnala;n<+f4#p?q&UK~!`-W)yd3$Y7V>%=QoH!j)h!7~NVo_S#3EzNICw{Jz{ z5nE@dCXs^DzbG%gJ47#Ll-lO8fm0GnzdL|)s^3K2npt{=pkUWUgghGym`IR;t4^RS z14#ELgZQ@vlxq4vUS-p{J{&s@xs7&E7&lzAZZ}>5 zG1XQ1>=KT3;xFxEqY_^OK={&}y^Q%28L=NsZmDfmC=CNok{^B|=U@Iy7g=1aI*E-! zw%XG>=vSp_wsq0E$5WOlZe<#-fymFdAiNdO(Wn05AiG%mNMabX{rH)Wor))$uC413 z1iV@@v7Z=rh-=)TNfZu4r@%cAsR!5r>pMpJfn#M6a%AUvgb@;QWDXw3b?TjzC8Lu& z1c=c1uFY(0dv}l|!k{HOfSxULq}rV3`fbdi=T z+Kwtj0J)Mm$7~tK&Y}2-R}+n5L8}o`+^Y6}_q}W=$?2sC;BVk zSE#2#WmqOfrMGFw8iM(-EZFzD12zA`6+v(>S7u#Bzd!jmTs#Y#6^j!-cTmPhnV{`W zLOXN3@pkvOuyojIAzFWGhk`c>Ph?Dmgx!K}3BVdEfXY`-7qR+UFW!_SlI>}4EI{U}c|v)!^|uTTZ3u|6 z#X)${Iae^RRO1fLFTNlirj~`6aO59~IJHN;<-`Aw*x6{9%cGD;OBSkXa%2`k0wQH- z+Z?WID^}_3jLnMFOr&YBOr(ap8Xsz#v8ncI^hIL3{RJ;TL489s=;K+^DN=G5@ZI$a z7KT$7QNZm!Z3WDB-G%i{PHiWz_-9Nescio^FaVnR&pYa6z-b+`>BT^9LW5!N59#ut z@SLb^O@CC73a~7x$U(Ak%L?GoX`YznsFnB3cOT|i+N#bzn zWYD*%9383O8l*BefnNFD;HfdBW>9nJtY*W=aX)KAmi-eD7I)f1 zKKJ0bm|M*kJo*sT@Ae~tiHh*xHbjg^QimKC8_-ik_mXp>$5gE!;IF)E;)*#v!g1}m zct>0-%$-girZX`KikmgTAgo|rR`aB|C^WM`CXc~W>WNh-oz6iu3~60^XQJOhkcQ{#EFG@ch2+{| z8b%j?MRNxGl?Qj|tUHP70uDN}DCth*K9m-FAH<%dCWs|dDDY)hoR&iUzPS0ep*(;5 zD|4CSqoRAhA9s>sXmV0TO9@f`W?gB%AJ0X+d5pvELxm-4a_wj7=#JE%@e)sL{|+C> zZ0`B}cVsqmkB=tMf6!P>=>+hz1udEUyoNu*L=N;^_LekD$=MaXQ6nO2hMxnotKJB{ ziO+B|peTz&bB}Sv^~>(9dwqq2tv`>z$}(A=c100xX}9-gC7`heC+`@LNT&vIotF>G z^?Ma~kaCykLL89j!zX5Wjk@IJ;~@H`HK?N?J}vxoI;-l87OzZ*Mvwm!EH zkDVw)af9yhi#Sg7XRY=>;jH-#T`tmR?9=~#W2+xL|NT5Xe%}y37z`+b7?}VjK%0BA zGf7&{ZU!plI#W~`aoJYZgz7_+BI!3?0&TuQB!n}@oNT* zmf5M2wdk3~QX(2@PB@Qw-iH|5Uyi}AE_F!Jh9Vt@#MK?n+#>cnmGZKqqR1nf^hYyxzIY}z z2VL&cf)9uB4!@Te+0$=&$oeCz{XZ`AwUi$;9(f#r>c9%g~a3m4hBHgCSwOq`sj1(Go+}pH298 z#li1(+>G{sT=vzLT#(gDUgxKXBvis_Oe%!#+T4_4qinI_??ZL)FVm857DSKzK;Onr zNL@sjaUzOjECa8!apOT{MxyyJHvA~E%j1&`f%(J%#-rLq?#as(oJd6L=@<=-J<-}6 zq%sNVKHb6?j#9{q&V_cMj^DH3aDdqe`YgQ{Pf(K3{ym=B*I)TzxD0{K!GG{V*FVoG z73EHy>;oA6)u(76Q!}wD@G;|`eB23^IJ8@?Dv=s4ObvPf`s-vhXXe@WcPwK_w+y~H zwte$HguD1D$<;Mfr(YTQz*r~?D~01+{qYJrK5rx};pxCk^R!7s9^LgO3HP!+ zZDiV~M)O=;&0TOR-wWZ4~eUMs{JG)2Sd}EY6hm1T52?EFO&f zxdc}#N~i2-dl!~3zqEwfW#pwj3soQ1Pc=SjC}|6p``{*U$iifek}-Sz&K6<1?J~F^ z=t(?dP09rSqI)GDg_sy|NDRxKR%9ns*RHIqRsooU+-`Yc)bsrzZ6m@cnTi|=*XB=g zH*FoTtxXf+(QoGImanBRq|VJNfutvzGIfg!be&toF+5`mh!?7x&$~#Gm>}FPQ!uC? zEC0R40OnlrBzO^et*;NF21K?M$*}o+$86YkVs}GCj@q?Qf||iS>%CF1Gx3$SAI!)8 zit4-GgWK*K3xG@P{v*iz>$6itz#cgnmVd5;_6i=`542G@A>4o&c9NiD-&h_eXutZw z?!lriTaiVXrb`V)p)uxP*tx-K&U#|6yVq11Y^u254K`_13P8TG z6080yV`81R2re*o$U{DhTXI)nmNyBCJwSwwqCv!JE8I;#+Vk~~XsAAmE@_j~yRbhF z@6kChU>aC%Nh5_4bdxUx&hKs9E?Z0>7D@(RMnm{^;9ZJ;ltQhA>*5$Sq0k_$<7Zxy ztQ|k+34;F<_@=mz+(tURn6V~C1JGw7p)vUjpQXX5M*QY#%al;U=QM*#0Y4M}`-5wb zsKm*e2a!Kn-Q<-^@;jn~pF@+8&NstGP$4tKEY-`On}0sH_NWvJu}DK_345t5xyQ)# z8?j>*1WO%RhToFpVRJh&^OEbOd}X)zGAu7t!GspxG<>NA)J@WZA-XkJ;mqD`5mq&;loOm`Gv1A+mZw(w+b z9iT`qhf&nE#e^g4sS6`iY)iWx-sS`hf!JHyKc-UcE_FNYo)Ffc`IcLYs}erH+?&C|2Ka*fYFSu_v-N~U5mDc#k@QzxcXq;{#o8_ zZT7d>%NB&xNL#_%>|>NpRH0L+5oFDCy8RT>&a67cm|pc$4i|eQWC@QZ5xcA-jW;_O zeTg#OTz+qc z6c(Vh;T|kpc%~!>+B|_V->by0gEuww&uZpPT4_*aq9*{tPyagna!BA&oZ$M{;5A{) zBJp7CuM&YW*I4I`6O8%+DHO#tyhLvS;(|Rutr@kbi>6~yBoVO$c)Gq+7mlF^vUI;g zpcO;9x~_L?vgGf~@i>kvG#LZ^hrL`0H{iw)FWqh!n+Ttq26~G4S1y_w@bqynP0Vl? zGsJ2P*VEz~3+1?PqB6MSeEs|P#R(cj<_(b@w>AUBPU1MsrmQ4}_G~~6vqUKg=1c8- zr!Mj+IIA?`)F5ue404iOdx&J_n;y*a%GojeAn=CET*vD$YJR9Z%&hYR1Ns0(xeUx< z+nrt$1a~rKj*|pZqEtwYhX4uh6pkdoF|=BF@qXIq{;kMigZsTm1S%yAX$2xF4KzH_ zbqe1f|Dd77NVkh6;JB<%&oep?m={kj;K$m}RRZy^HNibDBM(>EQ1r!%R3Z*6_at8l zRj$KN&vD1Xmy6mKs$j>9SWT^B8n4t~YJTPo${~_TU_vU!UL8h) zfD)mS=`{-Iz#0M-?YA`1bEB5hbiIJadxG^c{rhXSH)g%t9^_J#x9P8Hr;@(D#+NV= zr^`;y5QF0CsZfuz*$Us&S8w4RpfZn47_*y2i|Owg0>1*z!;IPbJ%y;cN)!4N(@cG~ zoD6kAt|7jj_{x>O0kxq~YZ&dVcqhLKt-s(!% z`;oYPSAg_!?v-nHe)TFKB9Y2vk%V*k@ar2E%0Ts@dqVufA&qfJRr z?gd(zC|K~7$e9&FHrRk>4zqsoj0C+R=s*8r(8F7$yJ)QwS?bQ>4LxiQ;akb2Dpkwi zJm!yWp9QGW%$i=uZI)+$+DC8AJ^oIZlIMCp6pfR=`ZEhtM9Ow+fsF}w~QyEd;M>${xG%u$xsu3K|%!$;?{<% zG_SC+|D9zlYH-(2~%f|LZElt1lDHi5W3ZrI}XB#3* zWh(hq&trO+We1~dw&Dt{=Ov?TzTi1+)bOZ@Z{`!fQ7;=V*CNIHLHauAU`j#!hdL-1 zb=}lMbBpFI&tNCUqJ5i_?IT}Y$ZVLIp?5PQ-S0(y=(*3Px6LA0)wFkqATgM%sGK-nzrump$nu^#pIP{r`FekGSObi!?K(l9 z!{u`KeRX_=lYqAg=afWynC|ZzQ|MqNxm30~8-va@DZAv|$CDKND9qdPj)x9~8uo50 zSPITi=A2k?UL;(zNEJ(>5i%6jsIeGlbahJoM(E%W(U^eT0WP@k^H&R#@MF5di5;G7 zQ=X|7w5HDz3=3hhP-+5@gkurtV7f-UX!PW0Vn{EiIBh@-94H&BUdNuR*#6STq%1$4 zlmsxcr+iOy)l^c4Akz2+dSMCIm>cp^SmgDg+kqfs@m&J2k{tdc`sd#eHA;=EwUa76 zDa6f~+P;d@z+-J;myEDLmOnjplGZz8rw{F&5Zh^2857CeTDUvly98xHh3X*7ol7mP z@*rxFogAp(9xdmWQ?RxU;YhNEi=_O{#^^7ER{u?7@x8CO*r;Y zI`A<$iK0ENS4MIn!{$q}{o174PO{h{bwLRuVanO&^4&FS^)IK6h+@@!7B=G4g1p9lKi+z(b0(S1y&llTVzH_iK4KVf=ktAcx!-DlNsW|R`^@O&geFd zv>U1dV<|s)uzG95qBOc=AY$bFP|hwIW{^StMZ_)2J@d{SR%S+jzjI4ZPq=WpEKXmm z*n2EdhAqJWs{@Cg*(yMyQTv0wqND%BRX#YP6 zLSkA*=77YZ2fYkgE$+XubBv^+eAm#4C;>YwdFAyMN%pt`5&%zmHI2_yV@z@bFpF%+ z->Qb~l0Gw;F3Wydr>|Fa(`yAEzu3%O@w4u0hx1c@7?yJ6j*-|bKuAYjsAk$rC@4mV z-ttg2EI54}j6~Um?m}zXQhJ|bWNA1tl|k4Xi1GlD^Fo_jsojj1D4O=PP1tC_T(r`H zgbIlHiO?~qq5pyxQ=dBKJ?r869liIdE8yT`7aSabuTa@Hd8LNeo}#Mf9$fYNcw>Pq z(MvQEyb;U%crwolH8;ICp!QR5eY1reoltljDkI1OTRd9ROg+naI&+WcejKrBWV?GG z86M+dSoX6gr7keVI1}{>fL`)Un=#sox(ZL);iP%2(=DH27;i2>8z&2IZts85=kQ6! zLdc#0&TM_322Z#3`C%IMI7(EES`sy5wiEB1gD$mHI ziF90F9<+UKG>yo>EN<|cNZQNd5ARZyrqNkUX_ZOUkQ`x>I+x^yK7^6yd=wV{?sNQh z;#jr2HJw-+YFz_R%BjR#u{{!oqm7o zH_^;N*Ooksix&15qZqr`Z@mn(4F?QW2H&PD@ z^lXw&$rxMvNC9*I1gZ}(hM_8v=C#%^LF9t`6^L3i?K?0Z@%`E#z|O3}ilQ&E>{mik zk9E#3=R|FNyI)ylBjvjxCru=wNA+;jJOp@%juUJS=_s#R1Rsm|5}%#2kt8@mkYo9Nw z5k)FF6kAD!x{{9&VI~RHd&=(K?P$N@rjpFda_G`TU9Opy^UpTn;|fBULp4#u|6rqK zwON2n($POlqYEf9gKgz>sD5@%t1?Cnx4*M_Kx$dr&1clP*_*~O*f?u;x#9Fa$D%EB zLdADAm@P@DLUUiG1N_e&{=M8=ikj;}HgS&Ouk08m^3tmbwm46VX-|05t1q-UY(?M! zqC=0reNwIeFzC6j z>r!8Za{}8Nfpoe|C)U@4z1l$2^X6n9)m`G)M|u2$&<=AJ~3J@ z*}>xPZnkc>aiar1-u?GbnxF5el>V4ECrA@~FE^1rsCGZguK|;>{Q{AIu`{V!&)1=R zRd{{-OgxL&>unkb{6MN|7q&iU>N2f%MwQ}Sbt^h$?CaF}t^gfEH2*3MM|8kzCqI`; z&`|P_w?n4gQ^=Wlp_SVutN(P~Y&_FZht3?*qFoV#jGDVJw#=}skhK7#YN(huNu(h1 z-4;OYHemRN^40MMvZHhm6FE(_g`nYfEPxBREM4v2$JU7kB8l);GSB&d1sL3He=q8o zm8i}Q{Lro4A4g&~@BQN2nLjb`^`%!7-ujvc=MqW6{l=aB`r=_uN$aUs(bT(Wpjb!yn&u_ z!`o`Q&BX;aHP(qR*g$!Sk!c1O?qJSp{PmBg2ejFP_sHpIU%vW8;#}p(TbCvT?BUJL z!$f#5h_g}SP~bv3Nm{V1S*ByeYU9)XwcaB%M)s>!AZ**9?YBjl#$r;bw&xK+kPO3v zGc)*z2k&vzqR3yaoPt48^`CL%zLe8ga_0P6@|?@4qYs{kv4ZZLd8;gfCj^0h!xftz zH*qMv^96KM?X6l*;BA`uZ`G@ne+qb($*nwf&m1{yi zEI;Eex#5VrUi25DfG}I$A*6oWmj{(oJ8HOHs#~k-Zc_`3k^>D zZaq;=u{JVxvHgt_2iK?sGu@NHJ=oFOftnVzPgX>sjMGyi75ycBP{if==YR%2)Sy%T zL!YwBQ*LR^cRFMdv(%THR%_#3)*N%Ug>Hp0{4yx3OcEqOPUCcbmo@C8j=I_n%NS0JL(-b`}4^?m^gwJ^5GcBXV?cvJ4 zgA<4LSM7ITlVL1`qVx(f&%d)c^FS;lB%#PMkjj`1QUW2gl~O$EMbaqX+fD00fn4dU#CpRS!)9No7JY=?!6 z6oeArTDsDI*2L5T=QUAAhL|SP-rZweaN@1P9ONQ+fC1=%L6mIaIdCxblsI~5Cn3H8p zXSusis0aaG#Kh$Uc@#~7k)^cSZGsz5T>P!$q*)GkV0BzEa(sztZ9gwtzFJEVajkF& z%#E$@17x(ZZ!2PLu`U3G_?UbRiFUM3LG~va46wmcFY}`s&sI~RXm^86^+Q3lyC(|^ zAT*>vaK_TztXPtE2}-uDk>ACCY!8XQ@jre+V_^fow^|iWzM;iDx0Ui60#jh=aI>aT z1xP{lRDc16xl!~v<4L9H|9!kDDr3h{8LIv=2np}R>3n->lx~7c-mJ*`LBvK^+o2<%UOP*0*BWHPk6!D}{Q->ZR)mBuhQRMCX}i@nq0HC4hk}RT3n~d} z9N`;*Vg!!u6F_JQ*fk={J1Be5Z)1@3{Dcb+`GlGP1QqLmF%}`kn`Bpc07%&uMrC%W5=^aXUiSh@kXIAi1b@g*n|SSaIL0 zA<&gzkE4#D;GJT!Y{?S-3qP!ghk=f_@f*y~S$Zqrme~M#f*v$D4Zh-X% zH}L zI)qL(l3aRfiX>g4)-_gZaDipQkx2v3DF*>A88TUYe7b@L+7 zfwMb#I=^EYGAfHXrvd=bYDin%I)|jF>+=T8A3s+ch{02r$*f zgHfvNOqL_VFb`6Fl=NzEmSQBrAy{oy+l{%JJbAD`4iFR^xA{;smm)uV<7{h`g=ny` zes@ttm_D5;**HvLBj-|O)gy6IIf;_4l%{2HjPAMY0*BU0MnVBZd8;P&qx37;2DnXZ z`7JehbT*iTeb5!qjw0@`Hy$5{MDk4?#5=vo$-3(?g-EsRtR0I9Po3yoqbW;c`em3s z>xybcL|K51n}iUdQSoEu%jK#u(*;ttul_cniK@<}lb?tQ(csvG zicc9n@r)4{3vre*tUik{Jc#hG}bm3xEDEm?5cGMZ$rSKcee!L6jzxAW1F z&Uf3 zz89!X+11CWN_dWKKQ!Z28q7`Qr@1}|Teq%Ty>3H3qPOgTIf%_zOPr5-#VlbTlry9s zESqRHN@hZudGgZWs`Q+N5S^S>83rZ9%_4oysLh8iNVHFp?JUVCaHRCzGif(f zTsdL=yTveTxShVhI^n~6K6I$Dl_&G}XkSGCunZ&=JppN84(h3V#X`P)m7n`Hyk?L~niy0?Uc)pU(#7|o7!N(lQh8paHg9bwqs?qZv!%BDteVT5v!~mqvu|H4|s2!k)sl?62D~BoD z76d)#5Z5_wc5WGPFB%mMZqrRn^|XZgq^q*Bt`+#euQ(+4&f1R;*vGnaoD5sNO8*==jzNfX_N&+hH7-SuKoZ|$;6jJ{ znieW2LI`ELM~A4Nnu9BQmeY+192ecTMFdsQgXwU#8P)B}I>Jo#+%TX*$VP>>S0Chy zzxFJGeb#P=+h0nk z0-b)JGUjR2@aXNRHSmC)@Qw2hn15$1&zZlXvM^;-z+#r)Mbd^S6C11U*?swX)OyFC ze%`N1T#I}>T5MZy9SB$~^h$1R-Vk@G?r)k1J{IT(3rtg6cD`#eu6)s9y2e6Nq@BmH~-e~V%bs7gzr6V^4&=E-I{wLAY z*{*8>7vBoT!;4Ih)orJ_@gEac8Bpp<`b+W)o67u}~P zY0}T;=LrWw3udEU_tsHag`c-v{q06Q1gakfS>b236#tH1<7tYPOo0Dy(CMj_ZjH(* zNi-#r(l*NqW^3?H&Uai&3eJwCv&{Eu)?|=Q*HZR~cBC0#X@KS`#DfWvk8wNF&aQW& zFgc=8h_w}k;+oyVtJn(5Z37tACs|7&Y(4C4GR((|C2u1^IUz%FZbu*jMZPa-2CBA-Pw=`) z6!k|(=y_9LE2uBh!rFHg4D}QImCFCQ;))p<@fpKtj#!kos~9yn*vt{g!gfff0fc;p zW&g;JbR+9D@@okxwa zB_Z~ep?PIrcp-D)TiG0me?JzTN0Ok#*{y@BA}g+fT3Q$8GyV?riOQ^TK`~n##&jq8 z@t8t_{FHg3KwXrVjMm57GIV=1&8EyfsUb{r@t{yQSKuzFkkD8(HldL;cYy~TYE zk9k-3(;(v-A~89|a$P8pTZw{b)R*|DX`4f|k7uU_soMp+;FJ%bzfXnr-H9$Ztx~9p zh2rUVlIPRjDt;O80%14|RqmzaS)Ob7*7jkT;?E9Fsn1s{@@yNGisU&$%qFGd>F37! zBe zZ+dr;TU1o>G9V>lupG=u%0e}8S=gvA@1=e*YEC4oB2YI|SxvV z)%$cQ1i*o}iinnLQG-`E>3jPJB0p2OH2Nhy_>qsI{JxSab3Nq`;*(qp1r1XGmV9JL zoUm-Tr#3!%lmRBTkWSwD#d7b(7*=O1!ua;SvBpez_szu>I1`NYQB`^+?j&MKNpT#- zm{fXkGqqG4&I9`Uteh<_q6(_1+aV%`4}O~F72uu?zxxy{`aMSf%WvDpWhfI27IBkQ zX!Z1_C22SlV3R+wR$ws40T}vySUtxy)rM&rele;9vj6(NrJpP4 zSvz73p*eHP$;p9cr2?P58yyL)B$$VH%YEX#&>cH1*^7B3&dhXqs5x$@z&CIm1kcF` zk}3>RgB>jsC9$Wmn|4KM(qR(V$vjyN@NK<{)24cEK-|Lg zaYU5X#r_kZs|^DYL^%ZC0+xws1rN^@YYmg34ztQpAMB5FLApbO<4*(1JN#!`hB{H9 zz@L(vQaUw5sK9r?Z#BvMucl8WTgW=nOUAUj^!#gkrhuu9(u4o9CQTZhIU@qdgdTZ5qb!=>yQT1z9{O6})g$Y_$h9v-A{BDO$2Z4*156jY(mlVcrLd#iQ&wW>y>B96Ox$3bn_`!YFkqllmS{< z0U#plJ6I6rlq=qKtd*yBg1BWz0=p>3+5BpUSlVyP+|nBf4(?Ms5LR}>jR-V9h*OaH zI_J@24*IA;QcO(=uL9Lk<#%F*NZ*Cz#LFo7@E?tg*W2(9*PC3khv;69mk;1raH z2q80!*p{HaQC`P3#S`k$2^iRGrqO{u;HZK`78@_bJC5%llWoXUpkl)TVZ+~LL( zJ4Fagm)xsh?B*k;aytzB?nj#vCLZwMm1-C=$e2|+qz-CKX8_a^!f`ZW{{pk{lce)A zu0kvyWT-dXu6)EzU&tPo>JNyi3ke~YTiAMyZD*d53@=;t_+&j3+%H8>Jl3GxXDXGY zq);24>e0ZFX~LZSs^*f|AIpk!zl6ox#fJg%B*5QR^!CIE$S2LaCO#dhHMs+7=17KG z_1<_2uO~x5Xd?E{ay0qmliIg{hk4$GE$Bh91^p%hnb!&|57zBtQxS_gh=iv7t)RpJlD>~ ze-=P{3gVN>02Lo@c2k3cM2O8Np@xuxkT<;9z_kVrVZ{XR?O!HPCy29$?i@3=wXFwD zEMwz9Y|33lb0c_M1XE?P++Qc4TV*_hg+IPAHv|LvhWS(t?SX33%mxdLG8E&)&RRkZ zEHevKRO4U>f!Cp*rJrzC(^<-bQY9IGE8FrB&}aM`(dx09D`~gM$~Qi|Y0Bmg9CfvMWKumgFF1cB3Xm_@ z-%6?8-$e1D5bP-i-Kws5@IIHC-@0CW9G5(u%oH^sLFHk-`dhkKF@usG^*>A*X453O z{lH3{l-)UM8#4N-UHZVr4g?`wya;}Sr>v-DQ4m(u!*&Tgof5$0Vs)A$K^I6qJsy%f zH#P(F`ViPdOt4PzAAZ{#^Tl#u!@BG^F`T|4(Y6JV#1Vkux{jXLlO#*$4uc1_!f8sw z7F}}Jt2tJ#fgH#74o!;Q338Gmit6!nBj&rUO96(u=qI}4Om(v&XSj1?%`xTI?)dCt z=Z^Zs0a3Yd0_?`KOBsa?qU?q|Y7Z>B{KA4&<-%}rB)o_;5{8xKnG|PbqP{(J)ZSbD z-T`FlJz$)Nr+vJlf`4#6ci{xErQEiyyp^4+H#>*}jae&B1hVkF)37=XUbg4fy1`q} z5TdKcXfko~jQY!8@GeVMoIdgL?>_zf6)%mc;?xE4*iEA`G_5M=C+DOKa6lfIhU{NW1z$SK2FZ}m9d7N;PZAeI4>!;+#1gBSN#1LQa%xoOMC2ta*XJsF_Bw6gEEF;5-GNog?w0E1DixipmkpYdL(^8_$q&FgCA)y^_8 zxNe&%@TWAk?!SYS`)PyA?hD!J^TgS|-ktq!f*7plP*GQ=zO2>8qT0b_6|#~SO+9jf zB168Dk*`yAZln$nS`3!i`_H0Boei8x_XFR+-VJ@RX5h!^v(!n~-Gmij zIdzp6x3l(>saqyFl{bR==d(a&1;N?kFW{fP6N&LJHs|H_C(MAORnIQ6ffb20pk)*| z8EnYb79W1G-eWng_~Do``{7g~j_-C&KL7E%3|D?K+&=}tfx25|&(3k~3*0t39lK%$ zD3Ro-B33I`j95uq-NxBYcr>8zNU*Fw3+4hk!!!Z(Q_P^baLmCPj4W7}PDT&>$tK(S zHCIC#cB?q>+i`^m*;PgeFe&z?pn9PS_NQ()Mj$jRv_vUmD)~H!V1&JT`DfaenwJcP z%ka{|ax#&>U?9b+Y}w6YYHiTV6T^bY>h$=yHo^@zPXB#L(k zOMgcU%vwn$RCZ%BpycjqRW660+?%kK3xU;}uzyH{udlU9@dPk*jpff%a8+L##@Rd` zzJw^uFot4?G)q%tPcmP7l_Wu5P7PE;6VBFhm12uT0pW?z?swZZi6g{vs%rApNsEOaq!vU4?9_)bV>?Oxa~{_W9c}IX5gb7GM;y2o1qDE@}7GK z|JV7U&xEOWmGWZK?KRk~@&c|=;2OOa-f^mQ6HOW&jg>d{=5H?f{4f(!Tu9!;H@1;P z@BVg~4r?&6QbY*BEf(5&Rj9{gS2?vd;PCvATZb0@#Z@|%y9@@Cx)QDdGh^E<+JJ4d z02}}MKPNKndzOIgRk(Qnq)O$P{RHS_aMbdezT%h0aYKZ z_0J~OkiJXlyR5Y|blw()!W`jNoDw_`dz0(5FJ>duBSwhQ2n0QojLqPD%>>ozZRVmw zcUIwK;6a1r5wWWw+hP>uMn?u5HjS=r76WTD-^hUUiwY&=<&FkCQ_na398beO5f(Jr zi*Ja!NMPEkMh0o*Z*J@?L^SI`v&2u6-q(T~UTXAf4_{J6?==)ZiMc(*Fe7*gt$j1w zdulV5N1&2n$vjQ>O6dT%+iptlAdmK9Lk{Tf6JT$K$FG?ByfL4Hj@6I zbxmOQd(|Er_ZA9G>rQ;TDUCJ(4@EB=kBu3v{DV}$UIO>r&)-iZ=N)bV3kCgLVv8+b=7=0)q+0eO+^nZNn4DbC;@Y8R0ARNh3u!Xu5~ zXnf@HLE`SuwGMv23iw`v!0#Edm{#G`BDylv;F>{#q}Zv}&J7WGje+;aPH`~EL7DYS z?7Sv&cA&YPx6%%h57lY0!WVdNm9-RG_kaIv82f{`Bp9#A`x6(->7arxVtHxEB9VgfH;r&Fovsj*om990Vco41wp7vTU^H8E!f zuvjhjIa~=daz#av$-U^V`qLOc5Vq)yg=!)+m2=Gn8dMK4ff6TB_$4vHYJ3-cy=89; z`CHfkP9mYOeXc}!zcCsMcIXfy{m1V;U&oKhN9@FQC5%$_+4*V=4`!xfR8!|o9ZXpf z_x+W>P&C8P)lSocDw|+K=AGGee{53Ob>RO3cnBMGpPwh9q=g#wgi=E#eus}V)K>rp0C*B|U&&&RQiJi6ozZtQh@(5}Ezl<>d z5j_8c_jmtqygx)m4Z`etEyUp#SvbEsPmT8o!2oW5E zA-6&|TY|wK*@d{476yXRG?U9P;P0?pCPla{_sr^x6ojdOJplAXD+ z`lgWmm;?8cJU{$93{03y+e;5s9o4ZX!&0g*+lv+U^1626^^$iMuY`keTF_418N}=w zy%;dnLd2sNfPAfR^xb+>RnPW*MbBrR=>&@04`T$>ak}@m#2v?(OG>PTDKf?!$E$ogs zzax36QpHpM<|#FaFwp$Z`N%K(=6~Yz*;@;|SH>Bel61S@C2}GEHa|!3 z1W^~t|LE(yW18@`I9`M@%O+Chj}2w7ij*w^$`V0DK%gK)1T0&oEGY^yDk4y1l_h&` zN*S_bqZOI5WeEOQg3Q;dG0(i@-Q?t+dv9`clW#ufoIh@I+G;T=jKDAkdDZ@3JfvoY+9lS~&-*_~xGS|ep9#O>FG@Df&j+q8;lrTnwTTo!fo$g*#aMNma(*R9%RlL)ED?E^&J+@R&U{XOq) zYOo5x3;f!Z^<|JyLC%3N62+8HCAYjvTIs$q#U;l#lQ&;qX3(?lTa~r*wR&0tOAIRw z9@D7HD64%&(o~ZANw6hK`(^J8r&emeaBy*->T5}Z5W^oImc&ji_Bx{4KvH`dkY?KS z;yb(>i!9|>FtonV24m$`lsdG(Ki_z_NTzmQn}_W~E+y6^_)fuxjF6#0zRwce92cW6 zT?*BHAkTG(Bkz|OK!^Dax){Gm-ixN$ zNM`|}xZH3MfEq{ujA#JDcaPr^Qv$RAWG6HHL~)&X|AwsYt+6^8I{`AG#Iiq-wGtqs zBZy1Z`5Q7OfriNJ2>0bgP76)REFPnJsDB}eINhC>#yt@B2-(g?7;<$$hF$tb2sWt! z-)zRs2+mC#az53{y)T#OmXDx1&U;XJJHmy1bVPQsxh!Sfpi4i^lEVlqZn(6YWU%qsosrKE9?{` zhZsd}1`6pkL2rcG@il^8r$VZ)&EGXK++w&N%#P;?*p0324)_Lp(r-0B&$$gnUg?k9 zkR|unZVD654Z5JZ`MIw`w$Kr!EPik;N4}UjDrr6mpM3Rn5V40iM%q3}0#YY*qev>- zMvrb8x2ke+0R+NFe7=lL#$E5yS{TjgzVw)N&DHIz4a4<%l36BAbBbqDE|0%Ha#sO& z@>xJAFy2Gvw#M9_!bjH6V!g;E9`t=%Zf~L9nmc0Y_(zigf5>UYfoik9yhlB}s{sp7 z)t~T9&SsS)1v~f-3QJ<&D#bgXA;=C2X1qlB?P*+NZO)l=!Y*=&S`8x1HK#>M`=M5S z_`8F_&^RoGXTczjCZ4`r04pG)!0m5sAubUUu~6Ju3H8G}$Qxnhg38;Oiw4y0N_7R| z3SHM4E{@>^VhUfB=J^M->E!G3F_whz>_IF(=h(uV3SB+gbe?UE)to>=PeO|A;lM!F zE{R^>%JaLrxRfNc;AH)mt+JGgPRmb-6bPB+^h#IPY7IK$^LL!+*==N-+d60Bnok78 z>N|XmrYwdPS5rt2&pKf-jg6Z!<+3fJ-WoY0;VUf}@+A{S!ERxUm1)ABq$w3CgMtMs zPPHHQ$3Dze4ruSIQJJD~#_>)zMqzdnXPNW|=5yXs-D*Zx3C&`A-vappLO%Lh4n>s5 z6xYX6#nAf{EO2;Ml4+aiItXe!jqo?)U|E4ITF+M7b#!K#IhvP+TKc8Lz(tlcF}!$a zFD^YY$Ci$%PTF@Pi49zvVgN6=&=BsuX=p5;!gP61PmItL@ztBj_a0Xfx-5dFLp==Q zwH#Dy))UZuXWPgNo7TZy@g6BzD(SUy1zG+75RH!1UMwPEQ*neF*z zUvsg!p&uERUu_4m?&nk@bP2s+=0jgrLy;jPLbAUBZlqyZ$Lz=g(#rCe5n1UnRob!7 z6D}Qwcf!dZoO3ZRDf#2%J(X#u->d0HoH=bDb+kfl&(09eZr7HKK;|86)F%G~Tj8kf z#>1U$ypy=SD7o~>pMQH8?XLD!oh@ z~pB*=Y;Zfz-|3c z+T$Rky;g3*jh+cq0AfK&G&w?A1RVd0xX2keVFA!!JU z#rQ6lea{`}inwR%3IKorBxE+u?(S_&L>EYOy?*)s0e*vf A$^ZZW literal 0 HcmV?d00001 diff --git a/qa/prscript.py b/qa/prscript.py index 6dcc36fcb751..61b67605770d 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -64,7 +64,7 @@ if args.docker: BASE_URI="http://localhost:8010/" - BUILDERS_LIST = ["build", "clang", "debug", "features", "profiling", "pcaps"] + BUILDERS_LIST = ["gcc", "clang", "debug", "features", "profiling", "pcaps"] else: BUILDERS_LIST = [username, username + "-pcap"] @@ -194,7 +194,7 @@ def CreateContainer(): # FIXME check if existing print "Pulling docking image, that will take long" cli.pull('regit/suri-buildbot') - cli.create_container(name='suri-buildbot', image='regit/suri-buildbot', ports=[8010, 22], volumes=['/data/oisf']) + cli.create_container(name='suri-buildbot', image='regit/suri-buildbot', ports=[8010, 22], volumes=['/data/oisf', '/data/buildbot/master/master.cfg']) sys.exit(0) def StartContainer(): @@ -204,7 +204,7 @@ def StartContainer(): cli = Client() suri_src_dir = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] print "Using base src dir: " + suri_src_dir - cli.start('suri-buildbot', port_bindings={8010:8010, 22:None}, binds={suri_src_dir: { 'bind': '/data/oisf', 'ro': True}} ) + cli.start('suri-buildbot', port_bindings={8010:8010, 22:None}, binds={suri_src_dir: { 'bind': '/data/oisf', 'ro': True}, os.path.join(suri_src_dir,'qa','docker','buildbot.cfg'): { 'bind': '/data/buildbot/master/master.cfg', 'ro': True}} ) sys.exit(0) def StopContainer(): From fbe5db500ce9faadfa4cc1feba65492963bd2c4d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 11 Mar 2015 18:07:15 +0100 Subject: [PATCH 0348/2553] prscript: iterate on builds when checking status This patch is changing the logic when using docker mode. We are iterating over each builds so we know when one build is over in the 5 seconds following the event instead of getting the result when the builds that are checked before are others. On OISF's build system, the two builds comes out in order so there is no problem. --- qa/prscript.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index 61b67605770d..45d435a7071a 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -29,6 +29,7 @@ import argparse import sys import os +import copy GOT_DOCKER = True try: @@ -261,8 +262,27 @@ def StopContainer(): sys.exit(0) res = 0 -for build in buildids: - res = WaitForBuildResult(build, buildids[build], builder_name = build) +if args.docker: + while len(buildids): + up_buildids = copy.copy(buildids) + for build in buildids: + ret = GetBuildStatus(build, buildids[build], builder_name = build) + if ret == -1: + res = -1 + up_buildids.pop(build, None) + print "Build failure for " + build + ": " + BUILDERS_URI + build + '/builds/' + str(buildids[build]) + " (" + ', '.join(up_buildids.keys()) + " remaining)" + elif ret == 0: + up_buildids.pop(build, None) + print "Build successful for " + build + " (" + ', '.join(up_buildids.keys()) + " remaining)" + time.sleep(5) + buildids = up_buildids + if res == -1: + sys.exit(-1) + else: + sys.exit(0) +else: + for build in buildids: + res = WaitForBuildResult(build, buildids[build], builder_name = build) if res == 0: if not args.norebase and not args.docker: From a3c921f0a610d0b7e17a42ae88830f1a26285e3e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 11 Mar 2015 19:08:37 +0100 Subject: [PATCH 0349/2553] prscript: suppress useless message No build run faster than 2 seconds. --- qa/prscript.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index 45d435a7071a..cab6849ee134 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -240,9 +240,7 @@ def StopContainer(): buildids = {} if args.docker: - from time import sleep - print "Waiting 2 seconds" - sleep(2) + time.sleep(2) # get build number and exit if we don't have for build in BUILDERS_LIST: From ef627816cc1c7d303b034be9123ba2bf0a7ac32c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 11 Mar 2015 19:15:14 +0100 Subject: [PATCH 0350/2553] prscript: improve wordings --- qa/prscript.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index cab6849ee134..76b8b4f5bf09 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -193,7 +193,7 @@ def CreateContainer(): sys.exit(-1) cli = Client() # FIXME check if existing - print "Pulling docking image, that will take long" + print "Pulling docking image, first run should take long" cli.pull('regit/suri-buildbot') cli.create_container(name='suri-buildbot', image='regit/suri-buildbot', ports=[8010, 22], volumes=['/data/oisf', '/data/buildbot/master/master.cfg']) sys.exit(0) @@ -251,9 +251,13 @@ def StopContainer(): print "No build found for " + BUILDERS_URI + build sys.exit(0) else: - print "You can watch build progress at " + BUILDERS_URI + build + "/builds/" + str(buildid) + if not args.docker: + print "You can watch build progress at " + BUILDERS_URI + build + "/builds/" + str(buildid) buildids[build] = buildid +if args.docker: + print "You can watch build progress at " + BASE_URI + "waterfall" + if len(buildids): print "Waiting for build completion" else: @@ -268,10 +272,10 @@ def StopContainer(): if ret == -1: res = -1 up_buildids.pop(build, None) - print "Build failure for " + build + ": " + BUILDERS_URI + build + '/builds/' + str(buildids[build]) + " (" + ', '.join(up_buildids.keys()) + " remaining)" + print "Build failure for " + build + ": " + BUILDERS_URI + build + '/builds/' + str(buildids[build]) + " (remaining builds: " + ', '.join(up_buildids.keys()) + ")" elif ret == 0: up_buildids.pop(build, None) - print "Build successful for " + build + " (" + ', '.join(up_buildids.keys()) + " remaining)" + print "Build successful for " + build + " (remaining builds: " + ', '.join(up_buildids.keys()) + ")" time.sleep(5) buildids = up_buildids if res == -1: From fe45f2a342a35c4b9684a1e1d76acd4ac96253a5 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 11 Mar 2015 19:56:12 +0100 Subject: [PATCH 0351/2553] prscript: add notification system If Python pynotify is installed, prscript can now send notification via the -n flag. --- qa/prscript.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index 76b8b4f5bf09..e7c5118261c0 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -31,6 +31,12 @@ import os import copy +GOT_NOTIFY = True +try: + import pynotify +except: + GOT_NOTIFY = False + GOT_DOCKER = True try: from docker import Client @@ -53,6 +59,8 @@ parser.add_argument('-r', '--repository', dest='repository', default='suricata', help='name of suricata repository on github') parser.add_argument('-d', '--docker', action='store_const', const=True, help='use docker based testing', default=False) parser.add_argument('-l', '--local', action='store_const', const=True, help='local testing before github push', default=False) +if GOT_NOTIFY: + parser.add_argument('-n', '--notify', action='store_const', const=True, help='send desktop notification', default=False) if GOT_DOCKER: parser.add_argument('-C', '--create', action='store_const', const=True, help='create docker container', default=False) parser.add_argument('-s', '--start', action='store_const', const=True, help='start docker container', default=False) @@ -73,6 +81,18 @@ BUILDERS_URI=BASE_URI+"builders/" JSON_BUILDERS_URI=BASE_URI+"json/builders/" +if GOT_NOTIFY: + if args.notify: + pynotify.init("PRscript") + +def SendNotification(title, text): + if not GOT_NOTIFY: + return + if not args.notify: + return + n = pynotify.Notification(title, text) + n.show() + def TestRepoSync(branch): request = urllib2.Request(GITHUB_MASTER_URI) page = urllib2.urlopen(request) @@ -272,15 +292,26 @@ def StopContainer(): if ret == -1: res = -1 up_buildids.pop(build, None) - print "Build failure for " + build + ": " + BUILDERS_URI + build + '/builds/' + str(buildids[build]) + " (remaining builds: " + ', '.join(up_buildids.keys()) + ")" + if len(up_buildids): + remains = " (remaining builds: " + ', '.join(up_buildids.keys()) + ")" + else: + remains = "" + print "Build failure for " + build + ": " + BUILDERS_URI + build + '/builds/' + str(buildids[build]) + remains elif ret == 0: up_buildids.pop(build, None) - print "Build successful for " + build + " (remaining builds: " + ', '.join(up_buildids.keys()) + ")" + if len(up_buildids): + remains = " (remaining builds: " + ', '.join(up_buildids.keys()) + ")" + else: + remains = "" + print "Build successful for " + build + remains time.sleep(5) buildids = up_buildids if res == -1: + SendNotification("PRscript failure", "Some builds have failed. Check waterfall for results.") sys.exit(-1) else: + print "PRscript completed successfully" + SendNotification("PRscript success", "Congrats! All builds have passed.") sys.exit(0) else: for build in buildids: @@ -291,6 +322,8 @@ def StopContainer(): print "You can copy/paste following lines into github PR" for build in buildids: print "- PR " + build + ": " + BUILDERS_URI + build + "/builds/" + str(buildids[build]) + SendNotification("OISF PRscript success", "Congrats! All builds have passed.") sys.exit(0) else: + SendNotification("OISF PRscript failure", "Some builds have failed. Check waterfall for results.") sys.exit(-1) From 8a0ebc4ade1d67e8290c516ed3e601a72e2ca0e9 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 12 Mar 2015 15:39:32 +0100 Subject: [PATCH 0352/2553] prscript: improve command line You can now directly access to docker related command: qa/prscript.py -C # create container qa/prscript.py -s # start container qa/prscript.py -S # stop container The build option does not change: qa/prscript.pu -l -d MY_BRANCH # build test of branch MY_BRANCH --- qa/prscript.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index e7c5118261c0..626dafdf4a71 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -65,19 +65,23 @@ parser.add_argument('-C', '--create', action='store_const', const=True, help='create docker container', default=False) parser.add_argument('-s', '--start', action='store_const', const=True, help='start docker container', default=False) parser.add_argument('-S', '--stop', action='store_const', const=True, help='stop docker container', default=False) -parser.add_argument('branch', metavar='branch', help='github branch to build') +parser.add_argument('branch', metavar='branch', help='github branch to build', nargs='?') args = parser.parse_args() username = args.username password = args.password cookie = None +if GOT_DOCKER: + if args.create or args.start or args.stop: + args.docker = True + args.local = True + if args.docker: BASE_URI="http://localhost:8010/" BUILDERS_LIST = ["gcc", "clang", "debug", "features", "profiling", "pcaps"] else: BUILDERS_LIST = [username, username + "-pcap"] - BUILDERS_URI=BASE_URI+"builders/" JSON_BUILDERS_URI=BASE_URI+"json/builders/" @@ -244,6 +248,10 @@ def StopContainer(): if args.stop: StopContainer() +if not args.branch: + print "You need to specify a branch for this mode" + sys.exit(-1) + # submit buildbot form to build current branch on the devel builder if not args.check: if not args.docker: From 0b64b992c96cbd8a4c7c35c4a09e7e666dd08895 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 12 Mar 2015 18:01:03 +0100 Subject: [PATCH 0353/2553] prscript: fix error message in non local test Indicate to user that non local test needs a github user. --- qa/prscript.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qa/prscript.py b/qa/prscript.py index 626dafdf4a71..3fd3354d1b9e 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -71,6 +71,11 @@ password = args.password cookie = None +if not args.local: + if not args.username: + print "You need to specify a github username (-u option) for this mode (or use -l to disable)" + sys.exit(-1) + if GOT_DOCKER: if args.create or args.start or args.stop: args.docker = True From f7a25f2b241fa3cc93f3c82654e6891f231a86ba Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 13 Mar 2015 09:55:27 +0100 Subject: [PATCH 0354/2553] prscript: rework option logic Handle cleanly the case where user start docker handling command without having the dependency installed. The help message does now say: ``` -d, --docker use docker based testing -C, --create create docker container (disabled) -s, --start start docker container (disabled) -S, --stop stop docker container (disabled) You need to install Python docker module to enable docker container handling options. ``` And running a disabled options says: ``` $ qa/prscript.py -s You need to install python docker to use docker handling features. ``` --- qa/prscript.py | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index 3fd3354d1b9e..4f401edde44b 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -50,37 +50,47 @@ GITHUB_BASE_URI = "https://api.github.com/repos/" GITHUB_MASTER_URI = "https://api.github.com/repos/inliniac/suricata/commits?sha=master" -parser = argparse.ArgumentParser(prog='prscript', description='Script checking validity of branch before PR') +if GOT_DOCKER: + parser = argparse.ArgumentParser(prog='prscript', description='Script checking validity of branch before PR') +else: + parser = argparse.ArgumentParser(prog='prscript', description='Script checking validity of branch before PR', + epilog='You need to install Python docker module to enable docker container handling options.') parser.add_argument('-u', '--username', dest='username', help='github and buildbot user') parser.add_argument('-p', '--password', dest='password', help='buildbot password') parser.add_argument('-c', '--check', action='store_const', const=True, help='only check last build', default=False) parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output', default=False) parser.add_argument('--norebase', action='store_const', const=True, help='do not test if branch is in sync with master', default=False) parser.add_argument('-r', '--repository', dest='repository', default='suricata', help='name of suricata repository on github') -parser.add_argument('-d', '--docker', action='store_const', const=True, help='use docker based testing', default=False) parser.add_argument('-l', '--local', action='store_const', const=True, help='local testing before github push', default=False) if GOT_NOTIFY: parser.add_argument('-n', '--notify', action='store_const', const=True, help='send desktop notification', default=False) -if GOT_DOCKER: - parser.add_argument('-C', '--create', action='store_const', const=True, help='create docker container', default=False) - parser.add_argument('-s', '--start', action='store_const', const=True, help='start docker container', default=False) - parser.add_argument('-S', '--stop', action='store_const', const=True, help='stop docker container', default=False) + +docker_deps = "" +if not GOT_DOCKER: + docker_deps = " (disabled)" +parser.add_argument('-d', '--docker', action='store_const', const=True, help='use docker based testing', default=False) +parser.add_argument('-C', '--create', action='store_const', const=True, help='create docker container' + docker_deps, default=False) +parser.add_argument('-s', '--start', action='store_const', const=True, help='start docker container' + docker_deps, default=False) +parser.add_argument('-S', '--stop', action='store_const', const=True, help='stop docker container' + docker_deps, default=False) parser.add_argument('branch', metavar='branch', help='github branch to build', nargs='?') args = parser.parse_args() username = args.username password = args.password cookie = None +if args.create or args.start or args.stop: + if GOT_DOCKER: + args.docker = True + args.local = True + else: + print "You need to install python docker to use docker handling features." + sys.exit(-1) + if not args.local: if not args.username: print "You need to specify a github username (-u option) for this mode (or use -l to disable)" sys.exit(-1) -if GOT_DOCKER: - if args.create or args.start or args.stop: - args.docker = True - args.local = True - if args.docker: BASE_URI="http://localhost:8010/" BUILDERS_LIST = ["gcc", "clang", "debug", "features", "profiling", "pcaps"] From 99ae643e4e6142d5dea9c8a82aac4e8ed1d70679 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Dec 2014 23:33:03 +0100 Subject: [PATCH 0355/2553] ippair: track ippairs, enable tests --- src/Makefile.am | 4 + src/ippair-queue.c | 143 ++++++++ src/ippair-queue.h | 83 +++++ src/ippair-storage.c | 299 +++++++++++++++++ src/ippair-storage.h | 45 +++ src/ippair-timeout.c | 148 ++++++++ src/ippair-timeout.h | 32 ++ src/ippair.c | 687 ++++++++++++++++++++++++++++++++++++++ src/ippair.h | 154 +++++++++ src/runmode-unittests.c | 2 + src/runmode-unix-socket.c | 3 + src/suricata.c | 3 + src/util-error.c | 1 + src/util-error.h | 1 + src/util-storage.c | 2 + src/util-storage.h | 1 + 16 files changed, 1608 insertions(+) create mode 100644 src/ippair-queue.c create mode 100644 src/ippair-queue.h create mode 100644 src/ippair-storage.c create mode 100644 src/ippair-storage.h create mode 100644 src/ippair-timeout.c create mode 100644 src/ippair-timeout.h create mode 100644 src/ippair.c create mode 100644 src/ippair.h diff --git a/src/Makefile.am b/src/Makefile.am index d30cce2e5cc5..2d9cb14ec38f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -210,6 +210,10 @@ host.c host.h \ host-queue.c host-queue.h \ host-storage.c host-storage.h \ host-timeout.c host-timeout.h \ +ippair.c ippair.h \ +ippair-queue.c ippair-queue.h \ +ippair-storage.c ippair-storage.h \ +ippair-timeout.c ippair-timeout.h \ log-dnslog.c log-dnslog.h \ log-droplog.c log-droplog.h \ log-file.c log-file.h \ diff --git a/src/ippair-queue.c b/src/ippair-queue.c new file mode 100644 index 000000000000..0f68200dd947 --- /dev/null +++ b/src/ippair-queue.c @@ -0,0 +1,143 @@ +/* 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 + * + * IPPair queue handler functions + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "ippair-queue.h" +#include "util-error.h" +#include "util-debug.h" +#include "util-print.h" + +IPPairQueue *IPPairQueueInit (IPPairQueue *q) +{ + if (q != NULL) { + memset(q, 0, sizeof(IPPairQueue)); + HQLOCK_INIT(q); + } + return q; +} + +IPPairQueue *IPPairQueueNew() +{ + IPPairQueue *q = (IPPairQueue *)SCMalloc(sizeof(IPPairQueue)); + if (q == NULL) { + SCLogError(SC_ERR_FATAL, "Fatal error encountered in IPPairQueueNew. Exiting..."); + exit(EXIT_SUCCESS); + } + q = IPPairQueueInit(q); + return q; +} + +/** + * \brief Destroy a ippair queue + * + * \param q the ippair queue to destroy + */ +void IPPairQueueDestroy (IPPairQueue *q) +{ + HQLOCK_DESTROY(q); +} + +/** + * \brief add a ippair to a queue + * + * \param q queue + * \param h ippair + */ +void IPPairEnqueue (IPPairQueue *q, IPPair *h) +{ +#ifdef DEBUG + BUG_ON(q == NULL || h == NULL); +#endif + + HQLOCK_LOCK(q); + + /* more ippairs in queue */ + if (q->top != NULL) { + h->lnext = q->top; + q->top->lprev = h; + q->top = h; + /* only ippair */ + } else { + q->top = h; + q->bot = h; + } + q->len++; +#ifdef DBG_PERF + if (q->len > q->dbg_maxlen) + q->dbg_maxlen = q->len; +#endif /* DBG_PERF */ + HQLOCK_UNLOCK(q); +} + +/** + * \brief remove a ippair from the queue + * + * \param q queue + * + * \retval h ippair or NULL if empty list. + */ +IPPair *IPPairDequeue (IPPairQueue *q) +{ + HQLOCK_LOCK(q); + + IPPair *h = q->bot; + if (h == NULL) { + HQLOCK_UNLOCK(q); + return NULL; + } + + /* more packets in queue */ + if (q->bot->lprev != NULL) { + q->bot = q->bot->lprev; + q->bot->lnext = NULL; + /* just the one we remove, so now empty */ + } else { + q->top = NULL; + q->bot = NULL; + } + +#ifdef DEBUG + BUG_ON(q->len == 0); +#endif + if (q->len > 0) + q->len--; + + h->lnext = NULL; + h->lprev = NULL; + + HQLOCK_UNLOCK(q); + return h; +} + +uint32_t IPPairQueueLen(IPPairQueue *q) +{ + uint32_t len; + HQLOCK_LOCK(q); + len = q->len; + HQLOCK_UNLOCK(q); + return len; +} diff --git a/src/ippair-queue.h b/src/ippair-queue.h new file mode 100644 index 000000000000..5c80cf3917da --- /dev/null +++ b/src/ippair-queue.h @@ -0,0 +1,83 @@ +/* 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 + */ + +#ifndef __IPPAIR_QUEUE_H__ +#define __IPPAIR_QUEUE_H__ + +#include "suricata-common.h" +#include "ippair.h" + +/** Spinlocks or Mutex for the ippair queues. */ +//#define HQLOCK_SPIN +#define HQLOCK_MUTEX + +#ifdef HQLOCK_SPIN + #ifdef HQLOCK_MUTEX + #error Cannot enable both HQLOCK_SPIN and HQLOCK_MUTEX + #endif +#endif + +/* Define a queue for storing ippairs */ +typedef struct IPPairQueue_ +{ + IPPair *top; + IPPair *bot; + uint32_t len; +#ifdef DBG_PERF + uint32_t dbg_maxlen; +#endif /* DBG_PERF */ +#ifdef HQLOCK_MUTEX + SCMutex m; +#elif defined HQLOCK_SPIN + SCSpinlock s; +#else + #error Enable HQLOCK_SPIN or HQLOCK_MUTEX +#endif +} IPPairQueue; + +#ifdef HQLOCK_SPIN + #define HQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) + #define HQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) + #define HQLOCK_LOCK(q) SCSpinLock(&(q)->s) + #define HQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) + #define HQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) +#elif defined HQLOCK_MUTEX + #define HQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) + #define HQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) + #define HQLOCK_LOCK(q) SCMutexLock(&(q)->m) + #define HQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) + #define HQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) +#else + #error Enable HQLOCK_SPIN or HQLOCK_MUTEX +#endif + +/* prototypes */ +IPPairQueue *IPPairQueueNew(); +IPPairQueue *IPPairQueueInit(IPPairQueue *); +void IPPairQueueDestroy (IPPairQueue *); + +void IPPairEnqueue (IPPairQueue *, IPPair *); +IPPair *IPPairDequeue (IPPairQueue *); +uint32_t IPPairQueueLen(IPPairQueue *); + +#endif /* __IPPAIR_QUEUE_H__ */ diff --git a/src/ippair-storage.c b/src/ippair-storage.c new file mode 100644 index 000000000000..dddc71365811 --- /dev/null +++ b/src/ippair-storage.c @@ -0,0 +1,299 @@ +/* Copyright (C) 2007-2013 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 + * + * IPPair wrapper around storage api + */ + +#include "suricata-common.h" +#include "ippair-storage.h" +#include "util-unittest.h" + +unsigned int IPPairStorageSize(void) +{ + return StorageGetSize(STORAGE_IPPAIR); +} + +void *IPPairGetStorageById(IPPair *h, int id) +{ + return StorageGetById((Storage *)((void *)h + sizeof(IPPair)), STORAGE_IPPAIR, id); +} + +int IPPairSetStorageById(IPPair *h, int id, void *ptr) +{ + return StorageSetById((Storage *)((void *)h + sizeof(IPPair)), STORAGE_IPPAIR, id, ptr); +} + +void *IPPairAllocStorageById(IPPair *h, int id) +{ + return StorageAllocByIdPrealloc((Storage *)((void *)h + sizeof(IPPair)), STORAGE_IPPAIR, id); +} + +void IPPairFreeStorageById(IPPair *h, int id) +{ + StorageFreeById((Storage *)((void *)h + sizeof(IPPair)), STORAGE_IPPAIR, id); +} + +void IPPairFreeStorage(IPPair *h) +{ + if (IPPairStorageSize() > 0) + StorageFreeAll((Storage *)((void *)h + sizeof(IPPair)), STORAGE_IPPAIR); +} + +int IPPairStorageRegister(const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *)) { + return StorageRegister(STORAGE_IPPAIR, name, size, Alloc, Free); +} + +#ifdef UNITTESTS + +static void *StorageTestAlloc(unsigned int size) +{ + void *x = SCMalloc(size); + return x; +} +static void StorageTestFree(void *x) +{ + if (x) + SCFree(x); +} + +static int IPPairStorageTest01(void) +{ + StorageInit(); + + int id1 = IPPairStorageRegister("test", 8, StorageTestAlloc, StorageTestFree); + if (id1 < 0) + goto error; + int id2 = IPPairStorageRegister("variable", 24, StorageTestAlloc, StorageTestFree); + if (id2 < 0) + goto error; + int id3 = IPPairStorageRegister("store", sizeof(void *), StorageTestAlloc, StorageTestFree); + if (id3 < 0) + goto error; + + if (StorageFinalize() < 0) + goto error; + + IPPairInitConfig(1); + + Address a, b; + memset(&a, 0x00, sizeof(a)); + memset(&b, 0x00, sizeof(b)); + a.addr_data32[0] = 0x01020304; + b.addr_data32[0] = 0x04030201; + a.family = AF_INET; + b.family = AF_INET; + IPPair *h = IPPairGetIPPairFromHash(&a, &b); + if (h == NULL) { + printf("failed to get ippair: "); + goto error; + } + + void *ptr = IPPairGetStorageById(h, id1); + if (ptr != NULL) { + goto error; + } + ptr = IPPairGetStorageById(h, id2); + if (ptr != NULL) { + goto error; + } + ptr = IPPairGetStorageById(h, id3); + if (ptr != NULL) { + goto error; + } + + void *ptr1a = IPPairAllocStorageById(h, id1); + if (ptr1a == NULL) { + goto error; + } + void *ptr2a = IPPairAllocStorageById(h, id2); + if (ptr2a == NULL) { + goto error; + } + void *ptr3a = IPPairAllocStorageById(h, id3); + if (ptr3a == NULL) { + goto error; + } + + void *ptr1b = IPPairGetStorageById(h, id1); + if (ptr1a != ptr1b) { + goto error; + } + void *ptr2b = IPPairGetStorageById(h, id2); + if (ptr2a != ptr2b) { + goto error; + } + void *ptr3b = IPPairGetStorageById(h, id3); + if (ptr3a != ptr3b) { + goto error; + } + + IPPairRelease(h); + + IPPairShutdown(); + StorageCleanup(); + return 1; +error: + IPPairShutdown(); + StorageCleanup(); + return 0; +} + +static int IPPairStorageTest02(void) +{ + StorageInit(); + + int id1 = IPPairStorageRegister("test", sizeof(void *), NULL, StorageTestFree); + if (id1 < 0) + goto error; + + if (StorageFinalize() < 0) + goto error; + + IPPairInitConfig(1); + + Address a, b; + memset(&a, 0x00, sizeof(a)); + memset(&b, 0x00, sizeof(b)); + a.addr_data32[0] = 0x01020304; + b.addr_data32[0] = 0x04030201; + a.family = AF_INET; + b.family = AF_INET; + IPPair *h = IPPairGetIPPairFromHash(&a, &b); + if (h == NULL) { + printf("failed to get ippair: "); + goto error; + } + + void *ptr = IPPairGetStorageById(h, id1); + if (ptr != NULL) { + goto error; + } + + void *ptr1a = SCMalloc(128); + if (unlikely(ptr1a == NULL)) { + goto error; + } + IPPairSetStorageById(h, id1, ptr1a); + + void *ptr1b = IPPairGetStorageById(h, id1); + if (ptr1a != ptr1b) { + goto error; + } + + IPPairRelease(h); + + IPPairShutdown(); + StorageCleanup(); + return 1; +error: + IPPairShutdown(); + StorageCleanup(); + return 0; +} + +static int IPPairStorageTest03(void) +{ + StorageInit(); + + int id1 = IPPairStorageRegister("test1", sizeof(void *), NULL, StorageTestFree); + if (id1 < 0) + goto error; + int id2 = IPPairStorageRegister("test2", sizeof(void *), NULL, StorageTestFree); + if (id2 < 0) + goto error; + int id3 = IPPairStorageRegister("test3", 32, StorageTestAlloc, StorageTestFree); + if (id3 < 0) + goto error; + + if (StorageFinalize() < 0) + goto error; + + IPPairInitConfig(1); + + Address a, b; + memset(&a, 0x00, sizeof(a)); + memset(&b, 0x00, sizeof(b)); + a.addr_data32[0] = 0x01020304; + b.addr_data32[0] = 0x04030201; + a.family = AF_INET; + b.family = AF_INET; + IPPair *h = IPPairGetIPPairFromHash(&a, &b); + if (h == NULL) { + printf("failed to get ippair: "); + goto error; + } + + void *ptr = IPPairGetStorageById(h, id1); + if (ptr != NULL) { + goto error; + } + + void *ptr1a = SCMalloc(128); + if (unlikely(ptr1a == NULL)) { + goto error; + } + IPPairSetStorageById(h, id1, ptr1a); + + void *ptr2a = SCMalloc(256); + if (unlikely(ptr2a == NULL)) { + goto error; + } + IPPairSetStorageById(h, id2, ptr2a); + + void *ptr3a = IPPairAllocStorageById(h, id3); + if (ptr3a == NULL) { + goto error; + } + + void *ptr1b = IPPairGetStorageById(h, id1); + if (ptr1a != ptr1b) { + goto error; + } + void *ptr2b = IPPairGetStorageById(h, id2); + if (ptr2a != ptr2b) { + goto error; + } + void *ptr3b = IPPairGetStorageById(h, id3); + if (ptr3a != ptr3b) { + goto error; + } + + IPPairRelease(h); + + IPPairShutdown(); + StorageCleanup(); + return 1; +error: + IPPairShutdown(); + StorageCleanup(); + return 0; +} +#endif + +void RegisterIPPairStorageTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("IPPairStorageTest01", IPPairStorageTest01, 1); + UtRegisterTest("IPPairStorageTest02", IPPairStorageTest02, 1); + UtRegisterTest("IPPairStorageTest03", IPPairStorageTest03, 1); +#endif +} diff --git a/src/ippair-storage.h b/src/ippair-storage.h new file mode 100644 index 000000000000..0671ac9196c9 --- /dev/null +++ b/src/ippair-storage.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2007-2013 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 + * + * IPPair wrapper around storage api + */ + +#ifndef __IPPAIR_STORAGE_H__ +#define __IPPAIR_STORAGE_H__ + +#include "util-storage.h" +#include "ippair.h" + +unsigned int IPPairStorageSize(void); + +void *IPPairGetStorageById(IPPair *h, int id); +int IPPairSetStorageById(IPPair *h, int id, void *ptr); +void *IPPairAllocStorageById(IPPair *h, int id); + +void IPPairFreeStorageById(IPPair *h, int id); +void IPPairFreeStorage(IPPair *h); + +void RegisterIPPairStorageTests(void); + +int IPPairStorageRegister(const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *)); + +#endif /* __IPPAIR_STORAGE_H__ */ diff --git a/src/ippair-timeout.c b/src/ippair-timeout.c new file mode 100644 index 000000000000..d1a6a24e0da4 --- /dev/null +++ b/src/ippair-timeout.c @@ -0,0 +1,148 @@ +/* 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 + */ + +#include "suricata-common.h" +#include "ippair.h" + +uint32_t IPPairGetSpareCount(void) +{ + return IPPairSpareQueueGetSize(); +} + +uint32_t IPPairGetActiveCount(void) +{ + return SC_ATOMIC_GET(ippair_counter); +} + +/** \internal + * \brief See if we can really discard this ippair. Check use_cnt reference. + * + * \param h ippair + * \param ts timestamp + * + * \retval 0 not timed out just yet + * \retval 1 fully timed out, lets kill it + */ +static int IPPairIPPairTimedOut(IPPair *h, struct timeval *ts) +{ + /** never prune a ippair that is used by a packet + * we are currently processing in one of the threads */ + if (SC_ATOMIC_GET(h->use_cnt) > 0) { + return 0; + } + + SCLogDebug("ippair %p timed out", h); + return 1; +} + +/** + * \internal + * + * \brief check all ippairs in a hash row for timing out + * + * \param hb ippair hash row *LOCKED* + * \param h last ippair in the hash row + * \param ts timestamp + * + * \retval cnt timed out ippairs + */ +static uint32_t IPPairHashRowTimeout(IPPairHashRow *hb, IPPair *h, struct timeval *ts) +{ + uint32_t cnt = 0; + + do { + if (SCMutexTrylock(&h->m) != 0) { + h = h->hprev; + continue; + } + + IPPair *next_ippair = h->hprev; + + /* check if the ippair is fully timed out and + * ready to be discarded. */ + if (IPPairIPPairTimedOut(h, ts) == 1) { + /* remove from the hash */ + if (h->hprev != NULL) + h->hprev->hnext = h->hnext; + if (h->hnext != NULL) + h->hnext->hprev = h->hprev; + if (hb->head == h) + hb->head = h->hnext; + if (hb->tail == h) + hb->tail = h->hprev; + + h->hnext = NULL; + h->hprev = NULL; + + IPPairClearMemory (h); + + /* no one is referring to this ippair, use_cnt 0, removed from hash + * so we can unlock it and move it back to the spare queue. */ + SCMutexUnlock(&h->m); + + /* move to spare list */ + IPPairMoveToSpare(h); + + cnt++; + } else { + SCMutexUnlock(&h->m); + } + + h = next_ippair; + } while (h != NULL); + + return cnt; +} + +/** + * \brief time out ippairs from the hash + * + * \param ts timestamp + * + * \retval cnt number of timed out ippair + */ +uint32_t IPPairTimeoutHash(struct timeval *ts) +{ + uint32_t idx = 0; + uint32_t cnt = 0; + + for (idx = 0; idx < ippair_config.hash_size; idx++) { + IPPairHashRow *hb = &ippair_hash[idx]; + + if (HRLOCK_TRYLOCK(hb) != 0) + continue; + + /* ippair hash bucket is now locked */ + + if (hb->tail == NULL) { + HRLOCK_UNLOCK(hb); + continue; + } + + /* we have a ippair, or more than one */ + cnt += IPPairHashRowTimeout(hb, hb->tail, ts); + HRLOCK_UNLOCK(hb); + } + + return cnt; +} diff --git a/src/ippair-timeout.h b/src/ippair-timeout.h new file mode 100644 index 000000000000..15d8e96a9890 --- /dev/null +++ b/src/ippair-timeout.h @@ -0,0 +1,32 @@ +/* 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 + */ + +#ifndef __IPPAIR_TIMEOUT_H__ +#define __IPPAIR_TIMEOUT_H__ + +uint32_t IPPairTimeoutHash(struct timeval *ts); + +uint32_t IPPairGetSpareCount(void); +uint32_t IPPairGetActiveCount(void); + +#endif diff --git a/src/ippair.c b/src/ippair.c new file mode 100644 index 000000000000..780ee6ce168e --- /dev/null +++ b/src/ippair.c @@ -0,0 +1,687 @@ +/* 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 + * + * Information about ippairs. + */ + +#include "suricata-common.h" +#include "conf.h" + +#include "util-debug.h" +#include "ippair.h" +#include "ippair-storage.h" + +#include "util-random.h" +#include "util-misc.h" +#include "util-byte.h" + +#include "ippair-queue.h" + +#include "detect-tag.h" +#include "detect-engine-tag.h" +#include "detect-engine-threshold.h" + +#include "util-hash-lookup3.h" + +static IPPair *IPPairGetUsedIPPair(void); + +/** queue with spare ippairs */ +static IPPairQueue ippair_spare_q; + +uint32_t IPPairSpareQueueGetSize(void) +{ + return IPPairQueueLen(&ippair_spare_q); +} + +void IPPairMoveToSpare(IPPair *h) +{ + IPPairEnqueue(&ippair_spare_q, h); + (void) SC_ATOMIC_SUB(ippair_counter, 1); +} + +IPPair *IPPairAlloc(void) +{ + size_t size = sizeof(IPPair) + IPPairStorageSize(); + + if (!(IPPAIR_CHECK_MEMCAP(size))) { + return NULL; + } + + (void) SC_ATOMIC_ADD(ippair_memuse, size); + + IPPair *h = SCMalloc(size); + if (unlikely(h == NULL)) + goto error; + + memset(h, 0x00, size); + + SCMutexInit(&h->m, NULL); + SC_ATOMIC_INIT(h->use_cnt); + return h; + +error: + return NULL; +} + +void IPPairFree(IPPair *h) +{ + if (h != NULL) { + IPPairClearMemory(h); + + SC_ATOMIC_DESTROY(h->use_cnt); + SCMutexDestroy(&h->m); + SCFree(h); + (void) SC_ATOMIC_SUB(ippair_memuse, (sizeof(IPPair) + IPPairStorageSize())); + } +} + +IPPair *IPPairNew(Address *a, Address *b) +{ + IPPair *p = IPPairAlloc(); + if (p == NULL) + goto error; + + /* copy addresses */ + COPY_ADDRESS(a, &p->a[0]); + COPY_ADDRESS(b, &p->a[1]); + + return p; + +error: + return NULL; +} + +void IPPairClearMemory(IPPair *h) +{ + if (IPPairStorageSize() > 0) + IPPairFreeStorage(h); +} + +#define IPPAIR_DEFAULT_HASHSIZE 4096 +#define IPPAIR_DEFAULT_MEMCAP 16777216 +#define IPPAIR_DEFAULT_PREALLOC 1000 + +/** \brief initialize the configuration + * \warning Not thread safe */ +void IPPairInitConfig(char quiet) +{ + SCLogDebug("initializing ippair engine..."); + + memset(&ippair_config, 0, sizeof(ippair_config)); + //SC_ATOMIC_INIT(flow_flags); + SC_ATOMIC_INIT(ippair_counter); + SC_ATOMIC_INIT(ippair_memuse); + SC_ATOMIC_INIT(ippair_prune_idx); + IPPairQueueInit(&ippair_spare_q); + + unsigned int seed = RandomTimePreseed(); + /* set defaults */ + ippair_config.hash_rand = (int)( IPPAIR_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); + + ippair_config.hash_size = IPPAIR_DEFAULT_HASHSIZE; + ippair_config.memcap = IPPAIR_DEFAULT_MEMCAP; + ippair_config.prealloc = IPPAIR_DEFAULT_PREALLOC; + + /* Check if we have memcap and hash_size defined at config */ + char *conf_val; + uint32_t configval = 0; + + /** set config values for memcap, prealloc and hash_size */ + if ((ConfGet("ippair.memcap", &conf_val)) == 1) + { + if (ParseSizeStringU64(conf_val, &ippair_config.memcap) < 0) { + SCLogError(SC_ERR_SIZE_PARSE, "Error parsing ippair.memcap " + "from conf file - %s. Killing engine", + conf_val); + exit(EXIT_FAILURE); + } + } + if ((ConfGet("ippair.hash-size", &conf_val)) == 1) + { + if (ByteExtractStringUint32(&configval, 10, strlen(conf_val), + conf_val) > 0) { + ippair_config.hash_size = configval; + } + } + + if ((ConfGet("ippair.prealloc", &conf_val)) == 1) + { + if (ByteExtractStringUint32(&configval, 10, strlen(conf_val), + conf_val) > 0) { + ippair_config.prealloc = configval; + } else { + WarnInvalidConfEntry("ippair.prealloc", "%"PRIu32, ippair_config.prealloc); + } + } + SCLogDebug("IPPair config from suricata.yaml: memcap: %"PRIu64", hash-size: " + "%"PRIu32", prealloc: %"PRIu32, ippair_config.memcap, + ippair_config.hash_size, ippair_config.prealloc); + + /* alloc hash memory */ + uint64_t hash_size = ippair_config.hash_size * sizeof(IPPairHashRow); + if (!(IPPAIR_CHECK_MEMCAP(hash_size))) { + SCLogError(SC_ERR_IPPAIR_INIT, "allocating ippair hash failed: " + "max ippair memcap is smaller than projected hash size. " + "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate " + "total hash size by multiplying \"ippair.hash-size\" with %"PRIuMAX", " + "which is the hash bucket size.", ippair_config.memcap, hash_size, + (uintmax_t)sizeof(IPPairHashRow)); + exit(EXIT_FAILURE); + } + ippair_hash = SCCalloc(ippair_config.hash_size, sizeof(IPPairHashRow)); + if (unlikely(ippair_hash == NULL)) { + SCLogError(SC_ERR_FATAL, "Fatal error encountered in IPPairInitConfig. Exiting..."); + exit(EXIT_FAILURE); + } + memset(ippair_hash, 0, ippair_config.hash_size * sizeof(IPPairHashRow)); + + uint32_t i = 0; + for (i = 0; i < ippair_config.hash_size; i++) { + HRLOCK_INIT(&ippair_hash[i]); + } + (void) SC_ATOMIC_ADD(ippair_memuse, (ippair_config.hash_size * sizeof(IPPairHashRow))); + + if (quiet == FALSE) { + SCLogInfo("allocated %llu bytes of memory for the ippair hash... " + "%" PRIu32 " buckets of size %" PRIuMAX "", + SC_ATOMIC_GET(ippair_memuse), ippair_config.hash_size, + (uintmax_t)sizeof(IPPairHashRow)); + } + + /* pre allocate ippairs */ + for (i = 0; i < ippair_config.prealloc; i++) { + if (!(IPPAIR_CHECK_MEMCAP(sizeof(IPPair)))) { + SCLogError(SC_ERR_IPPAIR_INIT, "preallocating ippairs failed: " + "max ippair memcap reached. Memcap %"PRIu64", " + "Memuse %"PRIu64".", ippair_config.memcap, + ((uint64_t)SC_ATOMIC_GET(ippair_memuse) + (uint64_t)sizeof(IPPair))); + exit(EXIT_FAILURE); + } + + IPPair *h = IPPairAlloc(); + if (h == NULL) { + SCLogError(SC_ERR_IPPAIR_INIT, "preallocating ippair failed: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + IPPairEnqueue(&ippair_spare_q,h); + } + + if (quiet == FALSE) { + SCLogInfo("preallocated %" PRIu32 " ippairs of size %" PRIuMAX "", + ippair_spare_q.len, (uintmax_t)sizeof(IPPair)); + SCLogInfo("ippair memory usage: %llu bytes, maximum: %"PRIu64, + SC_ATOMIC_GET(ippair_memuse), ippair_config.memcap); + } + + return; +} + +/** \brief print some ippair stats + * \warning Not thread safe */ +void IPPairPrintStats (void) +{ +#ifdef IPPAIRBITS_STATS + SCLogInfo("ippairbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", + ippairbits_added, ippairbits_removed, ippairbits_memuse_max); +#endif /* IPPAIRBITS_STATS */ + SCLogInfo("ippair memory usage: %llu bytes, maximum: %"PRIu64, + SC_ATOMIC_GET(ippair_memuse), ippair_config.memcap); + return; +} + +/** \brief shutdown the flow engine + * \warning Not thread safe */ +void IPPairShutdown(void) +{ + IPPair *h; + uint32_t u; + + IPPairPrintStats(); + + /* free spare queue */ + while((h = IPPairDequeue(&ippair_spare_q))) { + BUG_ON(SC_ATOMIC_GET(h->use_cnt) > 0); + IPPairFree(h); + } + + /* clear and free the hash */ + if (ippair_hash != NULL) { + for (u = 0; u < ippair_config.hash_size; u++) { + IPPair *h = ippair_hash[u].head; + while (h) { + IPPair *n = h->hnext; + IPPairFree(h); + h = n; + } + + HRLOCK_DESTROY(&ippair_hash[u]); + } + SCFree(ippair_hash); + ippair_hash = NULL; + } + (void) SC_ATOMIC_SUB(ippair_memuse, ippair_config.hash_size * sizeof(IPPairHashRow)); + IPPairQueueDestroy(&ippair_spare_q); + + SC_ATOMIC_DESTROY(ippair_prune_idx); + SC_ATOMIC_DESTROY(ippair_memuse); + SC_ATOMIC_DESTROY(ippair_counter); + //SC_ATOMIC_DESTROY(flow_flags); + return; +} + +/** \brief Cleanup the ippair engine + * + * Cleanup the ippair engine from tag and threshold. + * + */ +void IPPairCleanup(void) +{ + IPPair *h; + uint32_t u; + + if (ippair_hash != NULL) { + for (u = 0; u < ippair_config.hash_size; u++) { + h = ippair_hash[u].head; + IPPairHashRow *hb = &ippair_hash[u]; + HRLOCK_LOCK(hb); + while (h) { + if ((SC_ATOMIC_GET(h->use_cnt) > 0)) { + /* iprep is attached to ippair only clear local storage */ + IPPairFreeStorage(h); + h = h->hnext; + } else { + IPPair *n = h->hnext; + /* remove from the hash */ + if (h->hprev != NULL) + h->hprev->hnext = h->hnext; + if (h->hnext != NULL) + h->hnext->hprev = h->hprev; + if (hb->head == h) + hb->head = h->hnext; + if (hb->tail == h) + hb->tail = h->hprev; + h->hnext = NULL; + h->hprev = NULL; + IPPairClearMemory(h); + IPPairMoveToSpare(h); + h = n; + } + } + HRLOCK_UNLOCK(hb); + } + } + + return; +} + +/* calculate the hash key for this packet + * + * we're using: + * hash_rand -- set at init time + * source address + */ +static uint32_t IPPairGetKey(Address *a, Address *b) +{ + uint32_t key; + + if (a->family == AF_INET) { + uint32_t hash = hashword(&a->addr_data32[0], 1, ippair_config.hash_rand); + key = hash % ippair_config.hash_size; + } else if (a->family == AF_INET6) { + uint32_t hash = hashword(a->addr_data32, 4, ippair_config.hash_rand); + key = hash % ippair_config.hash_size; + } else + key = 0; + + return key; +} + +/* Since two or more ippairs can have the same hash key, we need to compare + * the ippair with the current addresses. */ +static inline int IPPairCompare(IPPair *p, Address *a, Address *b) +{ + /* compare in both directions */ + if ((CMP_ADDR(&p->a[0], a) && CMP_ADDR(&p->a[1], b)) || + (CMP_ADDR(&p->a[0], b) && CMP_ADDR(&p->a[1], a))) + return 1; + return 0; +} + +/** + * \brief Get a new ippair + * + * Get a new ippair. We're checking memcap first and will try to make room + * if the memcap is reached. + * + * \retval h *LOCKED* ippair on succes, NULL on error. + */ +static IPPair *IPPairGetNew(Address *a, Address *b) +{ + IPPair *h = NULL; + + /* get a ippair from the spare queue */ + h = IPPairDequeue(&ippair_spare_q); + if (h == NULL) { + /* If we reached the max memcap, we get a used ippair */ + if (!(IPPAIR_CHECK_MEMCAP(sizeof(IPPair)))) { + /* declare state of emergency */ + //if (!(SC_ATOMIC_GET(ippair_flags) & IPPAIR_EMERGENCY)) { + // SC_ATOMIC_OR(ippair_flags, IPPAIR_EMERGENCY); + + /* under high load, waking up the flow mgr each time leads + * to high cpu usage. Flows are not timed out much faster if + * we check a 1000 times a second. */ + // FlowWakeupFlowManagerThread(); + //} + + h = IPPairGetUsedIPPair(); + if (h == NULL) { + return NULL; + } + + /* freed a ippair, but it's unlocked */ + } else { + /* now see if we can alloc a new ippair */ + h = IPPairNew(a,b); + if (h == NULL) { + return NULL; + } + + /* ippair is initialized but *unlocked* */ + } + } else { + /* ippair has been recycled before it went into the spare queue */ + + /* ippair is initialized (recylced) but *unlocked* */ + } + + (void) SC_ATOMIC_ADD(ippair_counter, 1); + SCMutexLock(&h->m); + return h; +} + +void IPPairInit(IPPair *h, Address *a, Address *b) +{ + COPY_ADDRESS(a, &h->a[0]); + COPY_ADDRESS(b, &h->a[1]); + (void) IPPairIncrUsecnt(h); +} + +void IPPairRelease(IPPair *h) +{ + (void) IPPairDecrUsecnt(h); + SCMutexUnlock(&h->m); +} + +void IPPairLock(IPPair *h) +{ + SCMutexLock(&h->m); +} + +void IPPairUnlock(IPPair *h) +{ + SCMutexUnlock(&h->m); +} + +/* IPPairGetIPPairFromHash + * + * Hash retrieval function for ippairs. Looks up the hash bucket containing the + * ippair pointer. Then compares the packet with the found ippair to see if it is + * the ippair we need. If it isn't, walk the list until the right ippair is found. + * + * returns a *LOCKED* ippair or NULL + */ +IPPair *IPPairGetIPPairFromHash (Address *a, Address *b) +{ + IPPair *h = NULL; + + /* get the key to our bucket */ + uint32_t key = IPPairGetKey(a, b); + /* get our hash bucket and lock it */ + IPPairHashRow *hb = &ippair_hash[key]; + HRLOCK_LOCK(hb); + + /* see if the bucket already has a ippair */ + if (hb->head == NULL) { + h = IPPairGetNew(a,b); + if (h == NULL) { + HRLOCK_UNLOCK(hb); + return NULL; + } + + /* ippair is locked */ + hb->head = h; + hb->tail = h; + + /* got one, now lock, initialize and return */ + IPPairInit(h,a,b); + + HRLOCK_UNLOCK(hb); + return h; + } + + /* ok, we have a ippair in the bucket. Let's find out if it is our ippair */ + h = hb->head; + + /* see if this is the ippair we are looking for */ + if (IPPairCompare(h, a, b) == 0) { + IPPair *ph = NULL; /* previous ippair */ + + while (h) { + ph = h; + h = h->hnext; + + if (h == NULL) { + h = ph->hnext = IPPairGetNew(a,b); + if (h == NULL) { + HRLOCK_UNLOCK(hb); + return NULL; + } + hb->tail = h; + + /* ippair is locked */ + + h->hprev = ph; + + /* initialize and return */ + IPPairInit(h,a,b); + + HRLOCK_UNLOCK(hb); + return h; + } + + if (IPPairCompare(h, a, b) != 0) { + /* we found our ippair, lets put it on top of the + * hash list -- this rewards active ippairs */ + if (h->hnext) { + h->hnext->hprev = h->hprev; + } + if (h->hprev) { + h->hprev->hnext = h->hnext; + } + if (h == hb->tail) { + hb->tail = h->hprev; + } + + h->hnext = hb->head; + h->hprev = NULL; + hb->head->hprev = h; + hb->head = h; + + /* found our ippair, lock & return */ + SCMutexLock(&h->m); + (void) IPPairIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + return h; + } + } + } + + /* lock & return */ + SCMutexLock(&h->m); + (void) IPPairIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + return h; +} + +/** \brief look up a ippair in the hash + * + * \param a address to look up + * + * \retval h *LOCKED* ippair or NULL + */ +IPPair *IPPairLookupIPPairFromHash (Address *a, Address *b) +{ + IPPair *h = NULL; + + /* get the key to our bucket */ + uint32_t key = IPPairGetKey(a, b); + /* get our hash bucket and lock it */ + IPPairHashRow *hb = &ippair_hash[key]; + HRLOCK_LOCK(hb); + + /* see if the bucket already has a ippair */ + if (hb->head == NULL) { + HRLOCK_UNLOCK(hb); + return h; + } + + /* ok, we have a ippair in the bucket. Let's find out if it is our ippair */ + h = hb->head; + + /* see if this is the ippair we are looking for */ + if (IPPairCompare(h, a, b) == 0) { + while (h) { + h = h->hnext; + + if (h == NULL) { + HRLOCK_UNLOCK(hb); + return h; + } + + if (IPPairCompare(h, a, b) != 0) { + /* we found our ippair, lets put it on top of the + * hash list -- this rewards active ippairs */ + if (h->hnext) { + h->hnext->hprev = h->hprev; + } + if (h->hprev) { + h->hprev->hnext = h->hnext; + } + if (h == hb->tail) { + hb->tail = h->hprev; + } + + h->hnext = hb->head; + h->hprev = NULL; + hb->head->hprev = h; + hb->head = h; + + /* found our ippair, lock & return */ + SCMutexLock(&h->m); + (void) IPPairIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + return h; + } + } + } + + /* lock & return */ + SCMutexLock(&h->m); + (void) IPPairIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + return h; +} + +/** \internal + * \brief Get a ippair from the hash directly. + * + * Called in conditions where the spare queue is empty and memcap is reached. + * + * Walks the hash until a ippair can be freed. "ippair_prune_idx" atomic int makes + * sure we don't start at the top each time since that would clear the top of + * the hash leading to longer and longer search times under high pressure (observed). + * + * \retval h ippair or NULL + */ +static IPPair *IPPairGetUsedIPPair(void) +{ + uint32_t idx = SC_ATOMIC_GET(ippair_prune_idx) % ippair_config.hash_size; + uint32_t cnt = ippair_config.hash_size; + + while (cnt--) { + if (++idx >= ippair_config.hash_size) + idx = 0; + + IPPairHashRow *hb = &ippair_hash[idx]; + + if (HRLOCK_TRYLOCK(hb) != 0) + continue; + + IPPair *h = hb->tail; + if (h == NULL) { + HRLOCK_UNLOCK(hb); + continue; + } + + if (SCMutexTrylock(&h->m) != 0) { + HRLOCK_UNLOCK(hb); + continue; + } + + /** never prune a ippair that is used by a packets + * we are currently processing in one of the threads */ + if (SC_ATOMIC_GET(h->use_cnt) > 0) { + HRLOCK_UNLOCK(hb); + SCMutexUnlock(&h->m); + continue; + } + + /* remove from the hash */ + if (h->hprev != NULL) + h->hprev->hnext = h->hnext; + if (h->hnext != NULL) + h->hnext->hprev = h->hprev; + if (hb->head == h) + hb->head = h->hnext; + if (hb->tail == h) + hb->tail = h->hprev; + + h->hnext = NULL; + h->hprev = NULL; + HRLOCK_UNLOCK(hb); + + IPPairClearMemory (h); + + SCMutexUnlock(&h->m); + + (void) SC_ATOMIC_ADD(ippair_prune_idx, (ippair_config.hash_size - cnt)); + return h; + } + + return NULL; +} + +void IPPairRegisterUnittests(void) +{ + RegisterIPPairStorageTests(); +} diff --git a/src/ippair.h b/src/ippair.h new file mode 100644 index 000000000000..79affc624535 --- /dev/null +++ b/src/ippair.h @@ -0,0 +1,154 @@ +/* Copyright (C) 2007-2013 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 + */ + +#ifndef __IPPAIR_H__ +#define __IPPAIR_H__ + +#include "decode.h" +#include "util-storage.h" + +/** Spinlocks or Mutex for the flow buckets. */ +//#define HRLOCK_SPIN +#define HRLOCK_MUTEX + +#ifdef HRLOCK_SPIN + #ifdef HRLOCK_MUTEX + #error Cannot enable both HRLOCK_SPIN and HRLOCK_MUTEX + #endif +#endif + +#ifdef HRLOCK_SPIN + #define HRLOCK_TYPE SCSpinlock + #define HRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) + #define HRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) + #define HRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) + #define HRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) + #define HRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) +#elif defined HRLOCK_MUTEX + #define HRLOCK_TYPE SCMutex + #define HRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) + #define HRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) + #define HRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) + #define HRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) + #define HRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) +#else + #error Enable HRLOCK_SPIN or HRLOCK_MUTEX +#endif + +typedef struct IPPair_ { + /** ippair mutex */ + SCMutex m; + + /** ippair addresses -- ipv4 or ipv6 */ + Address a[2]; + + /** use cnt, reference counter */ + SC_ATOMIC_DECLARE(unsigned int, use_cnt); + + /** storage api handle */ + Storage *storage; + + /** hash pointers, protected by hash row mutex/spin */ + struct IPPair_ *hnext; + struct IPPair_ *hprev; + + /** list pointers, protected by ippair-queue mutex/spin */ + struct IPPair_ *lnext; + struct IPPair_ *lprev; +} IPPair; + +typedef struct IPPairHashRow_ { + HRLOCK_TYPE lock; + IPPair *head; + IPPair *tail; +} __attribute__((aligned(CLS))) IPPairHashRow; + +/** ippair hash table */ +IPPairHashRow *ippair_hash; + +#define IPPAIR_VERBOSE 0 +#define IPPAIR_QUIET 1 + +typedef struct IPPairConfig_ { + uint64_t memcap; + uint32_t hash_rand; + uint32_t hash_size; + uint32_t prealloc; +} IPPairConfig; + +/** \brief check if a memory alloc would fit in the memcap + * + * \param size memory allocation size to check + * + * \retval 1 it fits + * \retval 0 no fit + */ +#define IPPAIR_CHECK_MEMCAP(size) \ + ((((uint64_t)SC_ATOMIC_GET(ippair_memuse) + (uint64_t)(size)) <= ippair_config.memcap)) + +#define IPPairIncrUsecnt(h) \ + (void)SC_ATOMIC_ADD((h)->use_cnt, 1) +#define IPPairDecrUsecnt(h) \ + (void)SC_ATOMIC_SUB((h)->use_cnt, 1) + +#define IPPairReference(dst_h_ptr, h) do { \ + if ((h) != NULL) { \ + IPPairIncrUsecnt((h)); \ + *(dst_h_ptr) = h; \ + } \ + } while (0) + +#define IPPairDeReference(src_h_ptr) do { \ + if (*(src_h_ptr) != NULL) { \ + IPPairDecrUsecnt(*(src_h_ptr)); \ + *(src_h_ptr) = NULL; \ + } \ + } while (0) + +IPPairConfig ippair_config; +SC_ATOMIC_DECLARE(unsigned long long int,ippair_memuse); +SC_ATOMIC_DECLARE(unsigned int,ippair_counter); +SC_ATOMIC_DECLARE(unsigned int,ippair_prune_idx); + +void IPPairInitConfig(char quiet); +void IPPairShutdown(void); +void IPPairCleanup(void); + +IPPair *IPPairLookupIPPairFromHash (Address *, Address *); +IPPair *IPPairGetIPPairFromHash (Address *, Address *); +void IPPairRelease(IPPair *); +void IPPairLock(IPPair *); +void IPPairClearMemory(IPPair *); +void IPPairMoveToSpare(IPPair *); +uint32_t IPPairSpareQueueGetSize(void); +void IPPairPrintStats (void); + +void IPPairRegisterUnittests(void); + +IPPair *IPPairAlloc(void); +void IPPairFree(IPPair *); + +void IPPairLock(IPPair *); +void IPPairUnlock(IPPair *); + +#endif /* __IPPAIR_H__ */ diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 10f540ae0316..d4c55f391e8c 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -60,6 +60,7 @@ #include "pkt-var.h" #include "host.h" +#include "ippair.h" #include "unix-manager.h" #include "app-layer-detect-proto.h" @@ -214,6 +215,7 @@ void RunUnittests(int list_unittests, char *regex_arg) TmqhFlowRegisterTests(); FlowRegisterTests(); HostRegisterUnittests(); + IPPairRegisterUnittests(); SCSigRegisterSignatureOrderingTests(); SCRadixRegisterTests(); DefragRegisterTests(); diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 1ee5ce0815a8..1d6b023feac9 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -36,6 +36,7 @@ #include "output.h" #include "host.h" #include "defrag.h" +#include "ippair.h" #include "util-profiling.h" @@ -303,6 +304,7 @@ TmEcode UnixSocketPcapFilesCheck(void *data) SCPerfReleaseResources(); RunModeShutDown(); FlowShutdown(); + IPPairShutdown(); HostCleanup(); StreamTcpFreeConfig(STREAM_VERBOSE); DefragDestroy(); @@ -344,6 +346,7 @@ TmEcode UnixSocketPcapFilesCheck(void *data) #endif /* PROFILING */ DefragInit(); FlowInitConfig(FLOW_QUIET); + IPPairInitConfig(FLOW_QUIET); StreamTcpInitConfig(STREAM_VERBOSE); RunModeInitializeOutputs(); SCPerfInitCounterApi(); diff --git a/src/suricata.c b/src/suricata.c index e4e3cb5ae148..b766ff54e561 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -131,6 +131,7 @@ #include "flow-bit.h" #include "pkt-var.h" +#include "ippair.h" #include "host.h" #include "unix-manager.h" @@ -2238,6 +2239,7 @@ int main(int argc, char **argv) if (suri.run_mode != RUNMODE_UNIX_SOCKET) { FlowInitConfig(FLOW_VERBOSE); StreamTcpInitConfig(STREAM_VERBOSE); + IPPairInitConfig(IPPAIR_VERBOSE); } if (MagicInit() != 0) @@ -2427,6 +2429,7 @@ int main(int argc, char **argv) if (suri.run_mode != RUNMODE_UNIX_SOCKET) { SCPerfReleaseResources(); + IPPairShutdown(); FlowShutdown(); StreamTcpFreeConfig(STREAM_VERBOSE); } diff --git a/src/util-error.c b/src/util-error.c index d352a07e5caf..354765343f6a 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -306,6 +306,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_NO_NETMAP); CASE_CODE (SC_ERR_NETMAP_CREATE); CASE_CODE (SC_ERR_NETMAP_READ); + CASE_CODE (SC_ERR_IPPAIR_INIT); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 019d0179e56f..db6b462206b0 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -295,6 +295,7 @@ typedef enum { SC_ERR_NETMAP_CREATE, SC_ERR_NETMAP_READ, SC_ERR_THREAD_DEINIT, /**< thread's deinit function failed */ + SC_ERR_IPPAIR_INIT, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-storage.c b/src/util-storage.c index cfba8461a036..ba9aa7168558 100644 --- a/src/util-storage.c +++ b/src/util-storage.c @@ -54,6 +54,8 @@ const char *StoragePrintType(StorageEnum type) return "host"; case STORAGE_FLOW: return "flow"; + case STORAGE_IPPAIR: + return "ippair"; case STORAGE_MAX: return "max"; } diff --git a/src/util-storage.h b/src/util-storage.h index 0165ad5d55d0..d88b030fbd96 100644 --- a/src/util-storage.h +++ b/src/util-storage.h @@ -29,6 +29,7 @@ typedef enum StorageEnum_ { STORAGE_HOST, STORAGE_FLOW, + STORAGE_IPPAIR, STORAGE_MAX, } StorageEnum; From 5c880377ae6dd62f5fbc43224b890aa331c92f4f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 12 Dec 2014 23:40:30 +0100 Subject: [PATCH 0356/2553] detect: hostbits keyword Per host bit similar to 'flowbits'. Initial code that uses just the 'src' ip for the operations. --- src/Makefile.am | 2 + src/detect-hostbits.c | 1091 +++++++++++++++++++++++++++++++++++++++ src/detect-hostbits.h | 43 ++ src/detect.c | 2 + src/detect.h | 1 + src/host-bit.c | 489 ++++++++++++++++++ src/host-bit.h | 49 ++ src/host.c | 7 + src/host.h | 5 + src/runmode-unittests.c | 4 + src/suricata.c | 2 + src/util-var.c | 8 + 12 files changed, 1703 insertions(+) create mode 100644 src/detect-hostbits.c create mode 100644 src/detect-hostbits.h create mode 100644 src/host-bit.c create mode 100644 src/host-bit.h diff --git a/src/Makefile.am b/src/Makefile.am index 2d9cb14ec38f..11d326879919 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -137,6 +137,7 @@ detect-fragoffset.c detect-fragoffset.h \ detect-ftpbounce.c detect-ftpbounce.h \ detect-geoip.c detect-geoip.h \ detect-gid.c detect-gid.h \ +detect-hostbits.c detect-hostbits.h \ detect-http-client-body.c detect-http-client-body.h \ detect-http-cookie.c detect-http-cookie.h \ detect-http-header.c detect-http-header.h \ @@ -207,6 +208,7 @@ flow-timeout.c flow-timeout.h \ flow-util.c flow-util.h \ flow-var.c flow-var.h \ host.c host.h \ +host-bit.c host-bit.h \ host-queue.c host-queue.h \ host-storage.c host-storage.h \ host-timeout.c host-timeout.h \ diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c new file mode 100644 index 000000000000..f52f089befa0 --- /dev/null +++ b/src/detect-hostbits.c @@ -0,0 +1,1091 @@ +/* Copyright (C) 2007-2010 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 + * + * Implements the hostbits keyword + */ + +#include "suricata-common.h" +#include "decode.h" +#include "detect.h" +#include "threads.h" +#include "flow.h" +#include "flow-util.h" +#include "detect-hostbits.h" +#include "util-spm.h" + +#include "app-layer-parser.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow-bit.h" +#include "host-bit.h" +#include "util-var-name.h" +#include "util-unittest.h" +#include "util-debug.h" + +#define PARSE_REGEX "([a-z]+)(?:,(.*))?" +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +int DetectHostbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectHostbitSetup (DetectEngineCtx *, Signature *, char *); +void DetectHostbitFree (void *); +void HostBitsRegisterTests(void); + +void DetectHostbitsRegister (void) +{ + sigmatch_table[DETECT_HOSTBITS].name = "hostbits"; + sigmatch_table[DETECT_HOSTBITS].desc = "operate on flow flag"; +// sigmatch_table[DETECT_HOSTBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flowbits"; + sigmatch_table[DETECT_HOSTBITS].Match = DetectHostbitMatch; + sigmatch_table[DETECT_HOSTBITS].Setup = DetectHostbitSetup; + sigmatch_table[DETECT_HOSTBITS].Free = DetectHostbitFree; + sigmatch_table[DETECT_HOSTBITS].RegisterTests = HostBitsRegisterTests; + /* this is compatible to ip-only signatures */ + sigmatch_table[DETECT_HOSTBITS].flags |= SIGMATCH_IPONLY_COMPAT; + + const char *eb; + int eo; + int opts = 0; + + parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); + if(parse_regex == NULL) + { + SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); + goto error; + } + + parse_regex_study = pcre_study(parse_regex, 0, &eb); + if(eb != NULL) + { + SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + goto error; + } + + return; + +error: + return; +} + + +static int DetectHostbitMatchToggle (Packet *p, const DetectHostbitsData *fd) +{ + if (p->host_src == NULL) { + p->host_src = HostGetHostFromHash(&p->src); + if (p->host_src == NULL) + return 0; + } + else + HostLock(p->host_src); + + HostBitToggle(p->host_src,fd->idx); + HostUnlock(p->host_src); + return 1; +} + +/* return true even if bit not found */ +static int DetectHostbitMatchUnset (Packet *p, const DetectHostbitsData *fd) +{ + if (p->host_src == NULL) + return 1; + + HostLock(p->host_src); + HostBitUnset(p->host_src,fd->idx); + HostUnlock(p->host_src); + return 1; +} + +static int DetectHostbitMatchSet (Packet *p, const DetectHostbitsData *fd) +{ + if (p->host_src == NULL) { + p->host_src = HostGetHostFromHash(&p->src); + if (p->host_src == NULL) + return 0; + //SCLogInfo("host added"); + } else + HostLock(p->host_src); + + HostBitSet(p->host_src,fd->idx); + HostUnlock(p->host_src); + return 1; +} + +static int DetectHostbitMatchIsset (Packet *p, const DetectHostbitsData *fd) +{ + if (p->host_src == NULL) + return 0; + + HostLock(p->host_src); + int r = 0; + r = HostBitIsset(p->host_src,fd->idx); + HostUnlock(p->host_src); + return r; +} + +static int DetectHostbitMatchIsnotset (Packet *p, const DetectHostbitsData *fd) +{ + if (p->host_src == NULL) + return 1; + + HostLock(p->host_src); + int r = 0; + r = HostBitIsnotset(p->host_src,fd->idx); + HostUnlock(p->host_src); + return r; +} + +/* + * returns 0: no match + * 1: match + * -1: error + */ + +int DetectHostbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + const DetectHostbitsData *fd = (const DetectHostbitsData *)ctx; + if (fd == NULL) + return 0; + + switch (fd->cmd) { + case DETECT_HOSTBITS_CMD_ISSET: + return DetectHostbitMatchIsset(p,fd); + case DETECT_HOSTBITS_CMD_ISNOTSET: + return DetectHostbitMatchIsnotset(p,fd); + case DETECT_HOSTBITS_CMD_SET: + return DetectHostbitMatchSet(p,fd); + case DETECT_HOSTBITS_CMD_UNSET: + return DetectHostbitMatchUnset(p,fd); + case DETECT_HOSTBITS_CMD_TOGGLE: + return DetectHostbitMatchToggle(p,fd); + default: + SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd); + return 0; + } + + return 0; +} + +int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +{ + DetectHostbitsData *cd = NULL; + SigMatch *sm = NULL; + uint8_t fb_cmd = 0; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + char fb_cmd_str[16] = "", fb_name[256] = ""; + + ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret != 2 && ret != 3) { + SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for flowbits.", rawstr); + return -1; + } + + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, fb_cmd_str, sizeof(fb_cmd_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return -1; + } + + if (ret == 3) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, fb_name, sizeof(fb_name)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + } + + if (strcmp(fb_cmd_str,"noalert") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_NOALERT; + } else if (strcmp(fb_cmd_str,"isset") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_ISSET; + } else if (strcmp(fb_cmd_str,"isnotset") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_ISNOTSET; + } else if (strcmp(fb_cmd_str,"set") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_SET; + } else if (strcmp(fb_cmd_str,"unset") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_UNSET; + } else if (strcmp(fb_cmd_str,"toggle") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_TOGGLE; + } else { + SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str); + goto error; + } + + switch (fb_cmd) { + case DETECT_HOSTBITS_CMD_NOALERT: + if (strlen(fb_name) != 0) + goto error; + s->flags |= SIG_FLAG_NOALERT; + return 0; + case DETECT_HOSTBITS_CMD_ISNOTSET: + case DETECT_HOSTBITS_CMD_ISSET: + case DETECT_HOSTBITS_CMD_SET: + case DETECT_HOSTBITS_CMD_UNSET: + case DETECT_HOSTBITS_CMD_TOGGLE: + default: + if (strlen(fb_name) == 0) + goto error; + break; + } + + cd = SCMalloc(sizeof(DetectHostbitsData)); + if (unlikely(cd == NULL)) + goto error; + + cd->idx = VariableNameGetIdx(de_ctx, fb_name, DETECT_HOSTBITS); + cd->cmd = fb_cmd; + + SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", + cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_HOSTBITS; + sm->ctx = (void *)cd; + + switch (fb_cmd) { + case DETECT_HOSTBITS_CMD_NOALERT: + /* nothing to do */ + break; + + case DETECT_HOSTBITS_CMD_ISNOTSET: + case DETECT_HOSTBITS_CMD_ISSET: + /* checks, so packet list */ + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); + break; + + case DETECT_HOSTBITS_CMD_SET: + case DETECT_HOSTBITS_CMD_UNSET: + case DETECT_HOSTBITS_CMD_TOGGLE: + /* modifiers, only run when entire sig has matched */ + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); + break; + } + + return 0; + +error: + if (cd != NULL) + SCFree(cd); + if (sm != NULL) + SCFree(sm); + return -1; +} + +void DetectHostbitFree (void *ptr) +{ + DetectHostbitsData *fd = (DetectHostbitsData *)ptr; + + if (fd == NULL) + return; + + SCFree(fd); +} + +#ifdef UNITTESTS +/** + * \test HostBitsTestSig01 is a test for a valid noalert flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig01(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + HostInitConfig(TRUE); + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + printf("bad de_ctx: "); + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (hostbits:set,abc; content:\"GET \"; sid:1;)"); + + if (s == NULL) { + printf("bad sig: "); + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + result = 1; + +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + HostCleanup(); + + SCFree(p); + return result; +} + +#if 0 +/** + * \test HostBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig02(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + int error_count = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)"); + + if (s == NULL) { + error_count++; + } + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)"); + + if (s == NULL) { + error_count++; + } + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)"); + + if (s == NULL) { + error_count++; + } + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)"); + + if (s == NULL) { + error_count++; + } + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)"); + + if (s == NULL) { + error_count++; + } + + if(error_count == 5) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + goto cleanup; + } + if (PacketAlertCheck(p, 2)) { + goto cleanup; + } + if (PacketAlertCheck(p, 3)) { + goto cleanup; + } + if (PacketAlertCheck(p, 4)) { + goto cleanup; + } + if (PacketAlertCheck(p, 5)) { + goto cleanup; + } + + result = 1; + +cleanup: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + SCFree(p); + return result; +} + +/** + * \test HostBitsTestSig03 is a test for a invalid flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig03(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)"); + + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + result = 1; + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + + SCFree(p); + return result; +} +#endif + +/** + * \test HostBitsTestSig04 is a test check idx value + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig04(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + int idx = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; hostbits:isset,fbt; content:\"GET \"; sid:1;)"); + + idx = VariableNameGetIdx(de_ctx, "fbt", DETECT_HOSTBITS); + + if (s == NULL || idx != 1) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + result = 1; + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + SCFree(p); + return result; + +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + SCFree(p); + return result; +} + +#if 0 +/** + * \test HostBitsTestSig05 is a test check noalert flag + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig05(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)"); + + if (s == NULL || ((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT)) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + result = 1; + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + SCFree(p); + return result; +} + +/** + * \test HostBitsTestSig06 is a test set flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig06(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + GenericVar flowvar, *gv = NULL; + int result = 0; + int idx = 0; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + memset(&flowvar, 0, sizeof(GenericVar)); + + FLOW_INITIALIZE(&f); + p->flow = &f; + p->flow->flowvar = &flowvar; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + p->flags |= PKT_HAS_FLOW; + p->flowflags |= FLOW_PKT_TOSERVER; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)"); + + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_HOSTBITS); + + gv = p->flow->flowvar; + + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_HOSTBITS && gv->idx == idx) { + result = 1; + } + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + SCFree(p); + return result; +} + +/** + * \test HostBitsTestSig07 is a test unset flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig07(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + GenericVar flowvar, *gv = NULL; + int result = 0; + int idx = 0; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + memset(&flowvar, 0, sizeof(GenericVar)); + + FLOW_INITIALIZE(&f); + p->flow = &f; + p->flow->flowvar = &flowvar; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); + if (s == NULL) { + goto end; + } + + s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_HOSTBITS); + + gv = p->flow->flowvar; + + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_HOSTBITS && gv->idx == idx) { + result = 1; + } + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + + SCFree(p); + return result; +} +#endif + +/** + * \test HostBitsTestSig08 is a test toogle flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig08(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + int result = 0; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + + HostInitConfig(TRUE); + + FLOW_INITIALIZE(&f); + p->flow = &f; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; hostbits:set,myflow2; sid:10;)"); + + if (s == NULL) { + goto end; + } + + s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit toggle\"; hostbits:isset,myflow2; sid:11;)"); + + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + SCLogInfo("p->host_src %p", p->host_src); + + if (HostHasHostBits(p->host_src) == 1) { + if (PacketAlertCheck(p, 11)) { + result = 1; + } + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + + HostCleanup(); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + FLOW_DESTROY(&f); + + SCFree(p); + return result; +} +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for HostBits + */ +void HostBitsRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("HostBitsTestSig01", HostBitsTestSig01, 1); +#if 0 + UtRegisterTest("HostBitsTestSig02", HostBitsTestSig02, 0); + UtRegisterTest("HostBitsTestSig03", HostBitsTestSig03, 0); +#endif + UtRegisterTest("HostBitsTestSig04", HostBitsTestSig04, 1); +#if 0 + UtRegisterTest("HostBitsTestSig05", HostBitsTestSig05, 1); + UtRegisterTest("HostBitsTestSig06", HostBitsTestSig06, 1); + UtRegisterTest("HostBitsTestSig07", HostBitsTestSig07, 0); +#endif + UtRegisterTest("HostBitsTestSig08", HostBitsTestSig08, 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-hostbits.h b/src/detect-hostbits.h new file mode 100644 index 000000000000..82f5c1fa2913 --- /dev/null +++ b/src/detect-hostbits.h @@ -0,0 +1,43 @@ +/* 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 + */ + +#ifndef __DETECT_HOSTBITS_H__ +#define __DETECT_HOSTBITS_H__ + +#define DETECT_HOSTBITS_CMD_SET 0 +#define DETECT_HOSTBITS_CMD_TOGGLE 1 +#define DETECT_HOSTBITS_CMD_UNSET 2 +#define DETECT_HOSTBITS_CMD_ISNOTSET 3 +#define DETECT_HOSTBITS_CMD_ISSET 4 +#define DETECT_HOSTBITS_CMD_NOALERT 5 +#define DETECT_HOSTBITS_CMD_MAX 6 + +typedef struct DetectHostbitsData_ { + uint16_t idx; + uint8_t cmd; +} DetectHostbitsData; + +/* prototypes */ +void DetectHostbitsRegister (void); + +#endif /* __DETECT_HOSTBITS_H__ */ diff --git a/src/detect.c b/src/detect.c index ed4d132b4b76..0082969a06c2 100644 --- a/src/detect.c +++ b/src/detect.c @@ -108,6 +108,7 @@ #include "detect-pktvar.h" #include "detect-noalert.h" #include "detect-flowbits.h" +#include "detect-hostbits.h" #include "detect-csum.h" #include "detect-stream_size.h" #include "detect-engine-sigorder.h" @@ -5002,6 +5003,7 @@ void SigTableSetup(void) DetectPktvarRegister(); DetectNoalertRegister(); DetectFlowbitsRegister(); + DetectHostbitsRegister(); DetectEngineEventRegister(); DetectIpOptsRegister(); DetectFlagsRegister(); diff --git a/src/detect.h b/src/detect.h index 80d6d6a97d2c..775fe2eeaa2a 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1106,6 +1106,7 @@ enum { DETECT_PKTVAR, DETECT_NOALERT, DETECT_FLOWBITS, + DETECT_HOSTBITS, DETECT_IPV4_CSUM, DETECT_TCPV4_CSUM, DETECT_TCPV6_CSUM, diff --git a/src/host-bit.c b/src/host-bit.c new file mode 100644 index 000000000000..a70d15bf6e88 --- /dev/null +++ b/src/host-bit.c @@ -0,0 +1,489 @@ +/* Copyright (C) 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 + * + * Implements per host bits. Actually, not a bit, + * but called that way because of Snort's flowbits. + * It's a binary storage. + * + * \todo move away from a linked list implementation + * \todo use different datatypes, such as string, int, etc. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "host-bit.h" +#include "host.h" +#include "detect.h" +#include "util-var.h" +#include "util-debug.h" +#include "util-unittest.h" +#include "host-storage.h" + +static int host_bit_id = -1; /**< Host storage id for bits */ + +void HostBitFreeAll(void *store) { + GenericVar *gv = store; + GenericVarFree(gv); +} + +void HostBitInitCtx(void) +{ + host_bit_id = HostStorageRegister("bit", sizeof(void *), NULL, HostBitFreeAll); + if (host_bit_id == -1) { + SCLogError(SC_ERR_HOST_INIT, "Can't initiate host storage for bits"); + exit(EXIT_FAILURE); + } +} + +/* lock before using this */ +int HostHasHostBits(Host *host) +{ + if (host == NULL) + return 0; + return HostGetStorageById(host, host_bit_id) ? 1 : 0; +} + +/* get the bit with idx from the host */ +static HostBit *HostBitGet(Host *h, uint16_t idx) +{ + GenericVar *gv = HostGetStorageById(h, host_bit_id); + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_HOSTBITS && gv->idx == idx) { + return (HostBit *)gv; + } + } + + return NULL; +} + +/* add a flowbit to the flow */ +static void HostBitAdd(Host *h, uint16_t idx) +{ + HostBit *fb = HostBitGet(h, idx); + if (fb == NULL) { + fb = SCMalloc(sizeof(HostBit)); + if (unlikely(fb == NULL)) + return; + + fb->type = DETECT_HOSTBITS; + fb->idx = idx; + fb->next = NULL; + + GenericVar *gv = HostGetStorageById(h, host_bit_id); + GenericVarAppend(&gv, (GenericVar *)fb); + HostSetStorageById(h, host_bit_id, gv); + } +} + +static void HostBitRemove(Host *h, uint16_t idx) +{ + HostBit *fb = HostBitGet(h, idx); + if (fb == NULL) + return; + + GenericVar *gv = HostGetStorageById(h, host_bit_id); + if (gv) { + GenericVarRemove(&gv, (GenericVar *)fb); + HostSetStorageById(h, host_bit_id, gv); + } +} + +void HostBitSet(Host *h, uint16_t idx) +{ + HostBit *fb = HostBitGet(h, idx); + if (fb == NULL) { + HostBitAdd(h, idx); + } +} + +void HostBitUnset(Host *h, uint16_t idx) +{ + HostBit *fb = HostBitGet(h, idx); + if (fb != NULL) { + HostBitRemove(h, idx); + } +} + +void HostBitToggle(Host *h, uint16_t idx) +{ + HostBit *fb = HostBitGet(h, idx); + if (fb != NULL) { + HostBitRemove(h, idx); + } else { + HostBitAdd(h, idx); + } +} + +int HostBitIsset(Host *h, uint16_t idx) +{ + int r = 0; + + HostBit *fb = HostBitGet(h, idx); + if (fb != NULL) { + r = 1; + } + return r; +} + +int HostBitIsnotset(Host *h, uint16_t idx) +{ + int r = 0; + + HostBit *fb = HostBitGet(h, idx); + if (fb == NULL) { + r = 1; + } + + return r; +} + +void HostBitFree(HostBit *fb) +{ + if (fb == NULL) + return; + + SCFree(fb); +} + + +/* TESTS */ +#ifdef UNITTESTS +static int HostBitTest01 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + + HostBit *fb = HostBitGet(h,0); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest02 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBit *fb = HostBitGet(h,0); + if (fb == NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest03 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + + HostBit *fb = HostBitGet(h,0); + if (fb == NULL) { + printf("fb == NULL although it was just added: "); + goto end; + } + + HostBitRemove(h, 0); + + fb = HostBitGet(h,0); + if (fb != NULL) { + printf("fb != NULL although it was just removed: "); + goto end; + } else { + ret = 1; + } + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest04 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,0); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest05 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,1); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest06 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,2); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest07 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,3); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest08 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,0); + if (fb == NULL) + goto end; + + HostBitRemove(h,0); + + fb = HostBitGet(h,0); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest09 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,1); + if (fb == NULL) + goto end; + + HostBitRemove(h,1); + + fb = HostBitGet(h,1); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest10 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,2); + if (fb == NULL) + goto end; + + HostBitRemove(h,2); + + fb = HostBitGet(h,2); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest11 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,3); + if (fb == NULL) + goto end; + + HostBitRemove(h,3); + + fb = HostBitGet(h,3); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + ret = 1; + return ret; +} + +#endif /* UNITTESTS */ + +void HostBitRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("HostBitTest01", HostBitTest01, 1); + UtRegisterTest("HostBitTest02", HostBitTest02, 1); + UtRegisterTest("HostBitTest03", HostBitTest03, 1); + UtRegisterTest("HostBitTest04", HostBitTest04, 1); + UtRegisterTest("HostBitTest05", HostBitTest05, 1); + UtRegisterTest("HostBitTest06", HostBitTest06, 1); + UtRegisterTest("HostBitTest07", HostBitTest07, 1); + UtRegisterTest("HostBitTest08", HostBitTest08, 1); + UtRegisterTest("HostBitTest09", HostBitTest09, 1); + UtRegisterTest("HostBitTest10", HostBitTest10, 1); + UtRegisterTest("HostBitTest11", HostBitTest11, 1); +#endif /* UNITTESTS */ +} diff --git a/src/host-bit.h b/src/host-bit.h new file mode 100644 index 000000000000..c10a4fecf008 --- /dev/null +++ b/src/host-bit.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2007-2010 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 + */ + +#ifndef __HOST_BIT_H__ +#define __HOST_BIT_H__ + +#include "host.h" +#include "util-var.h" + +typedef struct HostBit_ { + uint8_t type; /* type, DETECT_HOSTBITS in this case */ + uint16_t idx; /* name idx */ + GenericVar *next; /* right now just implement this as a list, + * in the long run we have think of something + * faster. */ +} HostBit; + +void HostBitInitCtx(void); +void HostBitFree(HostBit *); +void HostBitRegisterTests(void); + +int HostHasHostBits(Host *host); + +void HostBitSet(Host *, uint16_t); +void HostBitUnset(Host *, uint16_t); +void HostBitToggle(Host *, uint16_t); +int HostBitIsset(Host *, uint16_t); +int HostBitIsnotset(Host *, uint16_t); +#endif /* __FLOW_BIT_H__ */ diff --git a/src/host.c b/src/host.c index c3831c757ef7..7c3c5841720c 100644 --- a/src/host.c +++ b/src/host.c @@ -29,6 +29,7 @@ #include "util-debug.h" #include "host.h" #include "host-storage.h" +#include "host-bit.h" #include "util-random.h" #include "util-misc.h" @@ -439,6 +440,12 @@ void HostLock(Host *h) SCMutexLock(&h->m); } +void HostUnlock(Host *h) +{ + SCMutexUnlock(&h->m); +} + + /* HostGetHostFromHash * * Hash retrieval function for hosts. Looks up the hash bucket containing the diff --git a/src/host.h b/src/host.h index 56a16dc47281..e3dd167a2e31 100644 --- a/src/host.h +++ b/src/host.h @@ -148,5 +148,10 @@ void HostPrintStats (void); void HostRegisterUnittests(void); +Host *HostAlloc(); +void HostFree(); + +void HostUnlock(Host *h); + #endif /* __HOST_H__ */ diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index d4c55f391e8c..1252dd975204 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -60,6 +60,7 @@ #include "pkt-var.h" #include "host.h" +#include "host-bit.h" #include "ippair.h" #include "unix-manager.h" @@ -171,6 +172,8 @@ void RunUnittests(int list_unittests, char *regex_arg) DetectEngineRegisterAppInspectionEngines(); + HostBitInitCtx(); + StorageFinalize(); /* test and initialize the unittesting subsystem */ if(regex_arg == NULL){ @@ -194,6 +197,7 @@ void RunUnittests(int list_unittests, char *regex_arg) ByteRegisterTests(); MpmRegisterTests(); FlowBitRegisterTests(); + HostBitRegisterTests(); SCPerfRegisterTests(); DecodePPPRegisterTests(); DecodeVLANRegisterTests(); diff --git a/src/suricata.c b/src/suricata.c index b766ff54e561..a6e022b5ce92 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -130,6 +130,7 @@ #include "flow-var.h" #include "flow-bit.h" #include "pkt-var.h" +#include "host-bit.h" #include "ippair.h" #include "host.h" @@ -2097,6 +2098,7 @@ static int PostConfLoadedSetup(SCInstance *suri) TagInitCtx(); ThresholdInit(); + HostBitInitCtx(); if (DetectAddressTestConfVars() < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, diff --git a/src/util-var.c b/src/util-var.c index 832a2d31f1c0..b84f19118749 100644 --- a/src/util-var.c +++ b/src/util-var.c @@ -31,6 +31,7 @@ #include "flow-var.h" #include "flow-bit.h" #include "pkt-var.h" +#include "host-bit.h" #include "util-debug.h" @@ -50,6 +51,13 @@ void GenericVarFree(GenericVar *gv) FlowBitFree(fb); break; } + case DETECT_HOSTBITS: + { + HostBit *fb = (HostBit *)gv; + //printf("GenericVarFree: fb %p, removing\n", fb); + HostBitFree(fb); + break; + } case DETECT_FLOWVAR: { FlowVar *fv = (FlowVar *)gv; From d67fd306f855a6d394b9bd8ec494d04723d6dc98 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 14 Dec 2014 00:04:14 +0100 Subject: [PATCH 0357/2553] hostbits: implement sigorder Like with flowbits, make sure that 'set's are evaluated before 'isset's, etc. --- src/detect-engine-sigorder.c | 103 +++++++++++++++++++++++++++++++++++ src/detect-engine-sigorder.h | 1 + 2 files changed, 104 insertions(+) diff --git a/src/detect-engine-sigorder.c b/src/detect-engine-sigorder.c index 4a980ad66da3..edca49c353e4 100644 --- a/src/detect-engine-sigorder.c +++ b/src/detect-engine-sigorder.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "detect.h" +#include "detect-hostbits.h" #include "detect-flowbits.h" #include "detect-flowint.h" #include "detect-parse.h" @@ -58,6 +59,11 @@ #define DETECT_FLOWINT_TYPE_SET_READ 3 #define DETECT_FLOWINT_TYPE_SET 4 +#define DETECT_HOSTBITS_NOT_USED 1 +#define DETECT_HOSTBITS_TYPE_READ 2 +#define DETECT_HOSTBITS_TYPE_SET_READ 3 +#define DETECT_HOSTBITS_TYPE_SET 4 + /** * \brief Registers a keyword-based, signature ordering function @@ -340,6 +346,75 @@ static inline int SCSigGetPktvarType(Signature *sig) return type; } +/** + * \brief Returns the hostbit type set for this signature. If more than one + * hostbit has been set for the same rule, we return the hostbit type of + * the maximum priority/value, where priority/value is maximum for the + * ones that set the value and the lowest for ones that read the value. + * If no hostbit has been set for the rule, we return 0, which indicates + * the least value amongst hostbit types. + * + * \param sig Pointer to the Signature from which the hostbit value has to be + * returned. + * + * \retval hostbits The hostbits type for this signature if it is set; if it is + * not set, return 0 + */ +static inline int SCSigGetHostbitsType(Signature *sig) +{ + DetectHostbitsData *fb = NULL; + int hostbits_user_type = DETECT_HOSTBITS_NOT_USED; + int read = 0; + int write = 0; + SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + + while (sm != NULL) { + if (sm->type == DETECT_HOSTBITS) { + fb = (DetectHostbitsData *)sm->ctx; + if (fb->cmd == DETECT_HOSTBITS_CMD_ISNOTSET || + fb->cmd == DETECT_HOSTBITS_CMD_ISSET) { + read++; + } else { +#ifdef DEBUG + BUG_ON(1); +#endif + } + } + + sm = sm->next; + } + + sm = sig->sm_lists[DETECT_SM_LIST_POSTMATCH]; + while (sm != NULL) { + if (sm->type == DETECT_HOSTBITS) { + fb = (DetectHostbitsData *)sm->ctx; + if (fb->cmd == DETECT_HOSTBITS_CMD_SET || + fb->cmd == DETECT_HOSTBITS_CMD_UNSET || + fb->cmd == DETECT_HOSTBITS_CMD_TOGGLE) { + write++; + } else { +#ifdef DEBUG + BUG_ON(1); +#endif + } + } + + sm = sm->next; + } + + if (read > 0 && write == 0) { + hostbits_user_type = DETECT_HOSTBITS_TYPE_READ; + } else if (read == 0 && write > 0) { + hostbits_user_type = DETECT_HOSTBITS_TYPE_SET; + } else if (read > 0 && write > 0) { + hostbits_user_type = DETECT_HOSTBITS_TYPE_SET_READ; + } + + SCLogDebug("Sig %s typeval %d", sig->msg, hostbits_user_type); + + return hostbits_user_type; +} + /** * \brief Processes the flowbits data for this signature and caches it for * future use. This is needed to optimize the sig_ordering module. @@ -381,6 +456,18 @@ static inline void SCSigProcessUserDataForPktvar(SCSigSignatureWrapper *sw) sw->user[SC_RADIX_USER_DATA_PKTVAR] = SCSigGetPktvarType(sw->sig); } +/** + * \brief Processes the flowbits data for this signature and caches it for + * future use. This is needed to optimize the sig_ordering module. + * + * \param sw The sigwrapper/signature for which the flowbits data has to be + * cached + */ +static inline void SCSigProcessUserDataForHostbits(SCSigSignatureWrapper *sw) +{ + sw->user[SC_RADIX_USER_DATA_HOSTBITS] = SCSigGetHostbitsType(sw->sig); +} + /* Return 1 if sw1 comes before sw2 in the final list. */ static int SCSigLessThan(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2, @@ -528,6 +615,20 @@ static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1, sw2->user[SC_RADIX_USER_DATA_FLOWINT]; } +/** + * \brief Orders an incoming Signature based on its hostbits type + * + * \param de_ctx Pointer to the detection engine context from which the + * signatures have to be ordered. + * \param sw The new signature that has to be ordered based on its hostbits + */ +static int SCSigOrderByHostbitsCompare(SCSigSignatureWrapper *sw1, + SCSigSignatureWrapper *sw2) +{ + return sw1->user[SC_RADIX_USER_DATA_HOSTBITS] - + sw2->user[SC_RADIX_USER_DATA_HOSTBITS]; +} + /** * \brief Orders an incoming Signature based on its priority type * @@ -564,6 +665,7 @@ static inline SCSigSignatureWrapper *SCSigAllocSignatureWrapper(Signature *sig) SCSigProcessUserDataForFlowvar(sw); SCSigProcessUserDataForFlowint(sw); SCSigProcessUserDataForPktvar(sw); + SCSigProcessUserDataForHostbits(sw); return sw; } @@ -643,6 +745,7 @@ void SCSigRegisterSignatureOrderingFuncs(DetectEngineCtx *de_ctx) SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowintCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); + SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByHostbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); } diff --git a/src/detect-engine-sigorder.h b/src/detect-engine-sigorder.h index 1451dfc3fae3..312165a04bf1 100644 --- a/src/detect-engine-sigorder.h +++ b/src/detect-engine-sigorder.h @@ -33,6 +33,7 @@ typedef enum{ SC_RADIX_USER_DATA_FLOWVAR, SC_RADIX_USER_DATA_PKTVAR, SC_RADIX_USER_DATA_FLOWINT, + SC_RADIX_USER_DATA_HOSTBITS, SC_RADIX_USER_DATA_MAX } SCRadixUserDataType; From be725a5ba2b1dba6905bc89667ed57269581f926 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 14 Dec 2014 00:04:47 +0100 Subject: [PATCH 0358/2553] hostbits: add more tests, include sigorder --- src/detect-hostbits.c | 153 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 143 insertions(+), 10 deletions(-) diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index f52f089befa0..9649abb9256b 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -32,6 +32,8 @@ #include "detect-hostbits.h" #include "util-spm.h" +#include "detect-engine-sigorder.h" + #include "app-layer-parser.h" #include "detect-parse.h" @@ -671,7 +673,6 @@ static int HostBitsTestSig04(void) return result; } -#if 0 /** * \test HostBitsTestSig05 is a test check noalert flag * @@ -711,7 +712,8 @@ static int HostBitsTestSig05(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ip any any -> any any (hostbits:noalert; content:\"GET \"; sid:1;)"); if (s == NULL || ((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT)) { goto end; @@ -722,7 +724,9 @@ static int HostBitsTestSig05(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - result = 1; + if (!PacketAlertCheck(p, 1)) { + result = 1; + } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -751,6 +755,7 @@ static int HostBitsTestSig05(void) return result; } +#if 0 /** * \test HostBitsTestSig06 is a test set flowbits option * @@ -964,13 +969,12 @@ static int HostBitsTestSig07(void) #endif /** - * \test HostBitsTestSig08 is a test toogle flowbits option + * \test set / isset * * \retval 1 on succces * \retval 0 on failure */ - -static int HostBitsTestSig08(void) +static int HostBitsTestSig07(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" @@ -1010,17 +1014,136 @@ static int HostBitsTestSig08(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; hostbits:set,myflow2; sid:10;)"); + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ip any any -> any any (hostbits:set,myflow2; sid:10;)"); if (s == NULL) { goto end; } - s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit toggle\"; hostbits:isset,myflow2; sid:11;)"); + s = s->next = SigInit(de_ctx, + "alert ip any any -> any any (hostbits:isset,myflow2; sid:11;)"); + + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + SCLogInfo("p->host_src %p", p->host_src); + + if (HostHasHostBits(p->host_src) == 1) { + if (PacketAlertCheck(p, 11)) { + result = 1; + } + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + + HostCleanup(); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + FLOW_DESTROY(&f); + + SCFree(p); + return result; +} + +/** + * \test set / toggle / toggle / isset + * + * \retval 1 on succces + * \retval 0 on failure + */ +static int HostBitsTestSig08(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + int result = 0; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + + HostInitConfig(TRUE); + + FLOW_INITIALIZE(&f); + p->flow = &f; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:set,myflow2; sid:10;)"); if (s == NULL) { goto end; } + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:toggle,myflow2; sid:11;)"); + if (s == NULL) { + goto end; + } + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:toggle,myflow2; sid:12;)"); + if (s == NULL) { + goto end; + } + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:isset,myflow2; sid:13;)"); + if (s == NULL) { + goto end; + } + + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -1030,7 +1153,17 @@ static int HostBitsTestSig08(void) SCLogInfo("p->host_src %p", p->host_src); if (HostHasHostBits(p->host_src) == 1) { + if (PacketAlertCheck(p, 10)) { + SCLogInfo("sid 10 matched"); + } if (PacketAlertCheck(p, 11)) { + SCLogInfo("sid 11 matched"); + } + if (PacketAlertCheck(p, 12)) { + SCLogInfo("sid 12 matched"); + } + if (PacketAlertCheck(p, 13)) { + SCLogInfo("sid 13 matched"); result = 1; } } @@ -1081,11 +1214,11 @@ void HostBitsRegisterTests(void) UtRegisterTest("HostBitsTestSig03", HostBitsTestSig03, 0); #endif UtRegisterTest("HostBitsTestSig04", HostBitsTestSig04, 1); -#if 0 UtRegisterTest("HostBitsTestSig05", HostBitsTestSig05, 1); +#if 0 UtRegisterTest("HostBitsTestSig06", HostBitsTestSig06, 1); - UtRegisterTest("HostBitsTestSig07", HostBitsTestSig07, 0); #endif + UtRegisterTest("HostBitsTestSig07", HostBitsTestSig07, 1); UtRegisterTest("HostBitsTestSig08", HostBitsTestSig08, 1); #endif /* UNITTESTS */ } From 2cb0df7cf98798865b212a7e7a82237a09698ebe Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Dec 2014 08:41:23 +0100 Subject: [PATCH 0359/2553] hostbits: allow for src/dst parameter By default, the hostbit checks the 'src' host. By adding the dst option the dst host is used instead. --- src/detect-hostbits.c | 299 ++++++++++++++++++++++++++---------------- src/detect-hostbits.h | 5 + 2 files changed, 193 insertions(+), 111 deletions(-) diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 9649abb9256b..49fa8a0aaed0 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -47,7 +47,21 @@ #include "util-unittest.h" #include "util-debug.h" -#define PARSE_REGEX "([a-z]+)(?:,(.*))?" +/* + hostbits:isset,bitname; + hostbits:set,bitname; + + hostbits:set,bitname,src; + hostbits:set,bitname,dst; +TODO: + hostbits:set,bitname,both; + + hostbits:set,bitname,src,3600; + hostbits:set,bitname,dst,60; + hostbits:set,bitname,both,120; + */ + +#define PARSE_REGEX "([a-z]+)(?:,([^,]+))?(?:,([^,]+))?" static pcre *parse_regex; static pcre_extra *parse_regex_study; @@ -59,7 +73,7 @@ void HostBitsRegisterTests(void); void DetectHostbitsRegister (void) { sigmatch_table[DETECT_HOSTBITS].name = "hostbits"; - sigmatch_table[DETECT_HOSTBITS].desc = "operate on flow flag"; + sigmatch_table[DETECT_HOSTBITS].desc = "operate on host flag"; // sigmatch_table[DETECT_HOSTBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flowbits"; sigmatch_table[DETECT_HOSTBITS].Match = DetectHostbitMatch; sigmatch_table[DETECT_HOSTBITS].Setup = DetectHostbitSetup; @@ -92,71 +106,158 @@ void DetectHostbitsRegister (void) return; } - static int DetectHostbitMatchToggle (Packet *p, const DetectHostbitsData *fd) { - if (p->host_src == NULL) { - p->host_src = HostGetHostFromHash(&p->src); - if (p->host_src == NULL) - return 0; + switch (fd->dir) { + case DETECT_HOSTBITS_DIR_SRC: + if (p->host_src == NULL) { + p->host_src = HostGetHostFromHash(&p->src); + if (p->host_src == NULL) + return 0; + } + else + HostLock(p->host_src); + + HostBitToggle(p->host_src,fd->idx); + HostUnlock(p->host_src); + break; + case DETECT_HOSTBITS_DIR_DST: + if (p->host_dst == NULL) { + p->host_dst = HostGetHostFromHash(&p->dst); + if (p->host_dst == NULL) + return 0; + } + else + HostLock(p->host_dst); + + HostBitToggle(p->host_dst,fd->idx); + HostUnlock(p->host_dst); + break; } - else - HostLock(p->host_src); - - HostBitToggle(p->host_src,fd->idx); - HostUnlock(p->host_src); return 1; } /* return true even if bit not found */ static int DetectHostbitMatchUnset (Packet *p, const DetectHostbitsData *fd) { - if (p->host_src == NULL) - return 1; - - HostLock(p->host_src); - HostBitUnset(p->host_src,fd->idx); - HostUnlock(p->host_src); + switch (fd->dir) { + case DETECT_HOSTBITS_DIR_SRC: + if (p->host_src == NULL) { + p->host_src = HostLookupHostFromHash(&p->src); + if (p->host_src == NULL) + return 1; + } else + HostLock(p->host_src); + + HostBitUnset(p->host_src,fd->idx); + HostUnlock(p->host_src); + break; + case DETECT_HOSTBITS_DIR_DST: + if (p->host_dst == NULL) { + p->host_dst = HostLookupHostFromHash(&p->dst); + if (p->host_dst == NULL) + return 1; + } else + HostLock(p->host_dst); + + HostBitUnset(p->host_dst,fd->idx); + HostUnlock(p->host_dst); + break; + } return 1; } static int DetectHostbitMatchSet (Packet *p, const DetectHostbitsData *fd) { - if (p->host_src == NULL) { - p->host_src = HostGetHostFromHash(&p->src); - if (p->host_src == NULL) - return 0; - //SCLogInfo("host added"); - } else - HostLock(p->host_src); - - HostBitSet(p->host_src,fd->idx); - HostUnlock(p->host_src); + switch (fd->dir) { + case DETECT_HOSTBITS_DIR_SRC: + if (p->host_src == NULL) { + p->host_src = HostGetHostFromHash(&p->src); + if (p->host_src == NULL) + return 0; + } else + HostLock(p->host_src); + + HostBitSet(p->host_src,fd->idx); + HostUnlock(p->host_src); + break; + case DETECT_HOSTBITS_DIR_DST: + if (p->host_dst == NULL) { + p->host_dst = HostGetHostFromHash(&p->dst); + if (p->host_dst == NULL) + return 0; + } else + HostLock(p->host_dst); + + HostBitSet(p->host_dst,fd->idx); + HostUnlock(p->host_dst); + break; + } return 1; } static int DetectHostbitMatchIsset (Packet *p, const DetectHostbitsData *fd) { - if (p->host_src == NULL) - return 0; - - HostLock(p->host_src); int r = 0; - r = HostBitIsset(p->host_src,fd->idx); - HostUnlock(p->host_src); - return r; + switch (fd->dir) { + case DETECT_HOSTBITS_DIR_SRC: + if (p->host_src == NULL) { + p->host_src = HostLookupHostFromHash(&p->src); + if (p->host_src == NULL) + return 0; + } else + HostLock(p->host_src); + + HostLock(p->host_src); + r = HostBitIsset(p->host_src,fd->idx); + HostUnlock(p->host_src); + return r; + case DETECT_HOSTBITS_DIR_DST: + if (p->host_dst == NULL) { + p->host_dst = HostLookupHostFromHash(&p->dst); + if (p->host_dst == NULL) + return 0; + } else + HostLock(p->host_dst); + + HostLock(p->host_dst); + r = HostBitIsset(p->host_dst,fd->idx); + HostUnlock(p->host_dst); + return r; + } + return 0; } static int DetectHostbitMatchIsnotset (Packet *p, const DetectHostbitsData *fd) { - if (p->host_src == NULL) - return 1; - - HostLock(p->host_src); int r = 0; - r = HostBitIsnotset(p->host_src,fd->idx); - HostUnlock(p->host_src); - return r; + switch (fd->dir) { + case DETECT_HOSTBITS_DIR_SRC: + if (p->host_src == NULL) { + p->host_src = HostLookupHostFromHash(&p->src); + if (p->host_src == NULL) + return 1; + } else + HostLock(p->host_src); + + HostLock(p->host_src); + r = HostBitIsnotset(p->host_src,fd->idx); + HostUnlock(p->host_src); + return r; + case DETECT_HOSTBITS_DIR_DST: + if (p->host_dst == NULL) { + p->host_dst = HostLookupHostFromHash(&p->dst); + if (p->host_dst == NULL) + return 1; + } else + HostLock(p->host_dst); + + HostLock(p->host_dst); + r = HostBitIsnotset(p->host_dst,fd->idx); + HostUnlock(p->host_dst); + return r; + } + return 0; } /* @@ -195,29 +296,53 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) DetectHostbitsData *cd = NULL; SigMatch *sm = NULL; uint8_t fb_cmd = 0; + uint8_t hb_dir = 0; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; char fb_cmd_str[16] = "", fb_name[256] = ""; + char hb_dir_str[16] = ""; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); - if (ret != 2 && ret != 3) { - SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for flowbits.", rawstr); + if (ret != 2 && ret != 3 && ret != 4) { + SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for hostbits.", rawstr); return -1; } - + SCLogInfo("ret %d, %s", ret, rawstr); res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, fb_cmd_str, sizeof(fb_cmd_str)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); return -1; } - if (ret == 3) { + if (ret >= 3) { res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, fb_name, sizeof(fb_name)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } + if (ret >= 4) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, hb_dir_str, sizeof(hb_dir_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogInfo("hb_dir_str %s", hb_dir_str); + if (strlen(hb_dir_str) > 0) { + if (strcmp(hb_dir_str, "src") == 0) + hb_dir = DETECT_HOSTBITS_DIR_SRC; + else if (strcmp(hb_dir_str, "dst") == 0) + hb_dir = DETECT_HOSTBITS_DIR_DST; + else if (strcmp(hb_dir_str, "both") == 0) { + hb_dir = DETECT_HOSTBITS_DIR_BOTH; + SCLogError(SC_ERR_UNIMPLEMENTED, "'both' not implemented"); + goto error; + } else { + // TODO + goto error; + } + } + } } if (strcmp(fb_cmd_str,"noalert") == 0) { @@ -260,6 +385,7 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) cd->idx = VariableNameGetIdx(de_ctx, fb_name, DETECT_HOSTBITS); cd->cmd = fb_cmd; + cd->dir = hb_dir; SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); @@ -389,9 +515,8 @@ static int HostBitsTestSig01(void) return result; } -#if 0 /** - * \test HostBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options + * \test various options * * \retval 1 on succces * \retval 0 on failure @@ -399,119 +524,71 @@ static int HostBitsTestSig01(void) static int HostBitsTestSig02(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; int error_count = 0; memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)"); - + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:isset,abc,src; content:\"GET \"; sid:1;)"); if (s == NULL) { error_count++; } - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)"); - + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:isnotset,abc,dst; content:\"GET \"; sid:2;)"); if (s == NULL) { error_count++; } - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)"); - + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:set,abc,both; content:\"GET \"; sid:3;)"); if (s == NULL) { error_count++; } - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)"); - + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:unset,abc,src; content:\"GET \"; sid:4;)"); if (s == NULL) { error_count++; } - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)"); - + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:toggle,abc,dst; content:\"GET \"; sid:5;)"); if (s == NULL) { error_count++; } - if(error_count == 5) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - goto cleanup; - } - if (PacketAlertCheck(p, 2)) { - goto cleanup; - } - if (PacketAlertCheck(p, 3)) { - goto cleanup; - } - if (PacketAlertCheck(p, 4)) { - goto cleanup; - } - if (PacketAlertCheck(p, 5)) { - goto cleanup; - } + if (error_count != 0) + goto end; result = 1; -cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - + return result; end: - if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } - SCFree(p); return result; } +#if 0 /** * \test HostBitsTestSig03 is a test for a invalid flowbits option * @@ -1209,8 +1286,8 @@ void HostBitsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("HostBitsTestSig01", HostBitsTestSig01, 1); + UtRegisterTest("HostBitsTestSig02", HostBitsTestSig02, 1); #if 0 - UtRegisterTest("HostBitsTestSig02", HostBitsTestSig02, 0); UtRegisterTest("HostBitsTestSig03", HostBitsTestSig03, 0); #endif UtRegisterTest("HostBitsTestSig04", HostBitsTestSig04, 1); diff --git a/src/detect-hostbits.h b/src/detect-hostbits.h index 82f5c1fa2913..72406cc8eb83 100644 --- a/src/detect-hostbits.h +++ b/src/detect-hostbits.h @@ -32,9 +32,14 @@ #define DETECT_HOSTBITS_CMD_NOALERT 5 #define DETECT_HOSTBITS_CMD_MAX 6 +#define DETECT_HOSTBITS_DIR_SRC 0 +#define DETECT_HOSTBITS_DIR_DST 1 +#define DETECT_HOSTBITS_DIR_BOTH 2 + typedef struct DetectHostbitsData_ { uint16_t idx; uint8_t cmd; + uint8_t dir; } DetectHostbitsData; /* prototypes */ From 4c6d564211f41348d8c28af5c4a0af9893c3d82d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Dec 2014 11:22:24 +0100 Subject: [PATCH 0360/2553] hostbits: unittest cleanups --- src/detect-hostbits.c | 49 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 49fa8a0aaed0..22797af0e050 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -439,6 +439,21 @@ void DetectHostbitFree (void *ptr) } #ifdef UNITTESTS + +static void HostBitsTestSetup(void) +{ + StorageInit(); + HostBitInitCtx(); + StorageFinalize(); + HostInitConfig(TRUE); +} + +static void HostBitsTestShutdown(void) +{ + HostCleanup(); + StorageCleanup(); +} + /** * \test HostBitsTestSig01 is a test for a valid noalert flowbits option * @@ -462,8 +477,6 @@ static int HostBitsTestSig01(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - HostInitConfig(TRUE); - memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->src.family = AF_INET; @@ -472,6 +485,8 @@ static int HostBitsTestSig01(void) p->payload_len = buflen; p->proto = IPPROTO_TCP; + HostBitsTestSetup(); + de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -509,7 +524,7 @@ static int HostBitsTestSig01(void) DetectEngineCtxFree(de_ctx); } - HostCleanup(); + HostBitsTestShutdown(); SCFree(p); return result; @@ -550,13 +565,13 @@ static int HostBitsTestSig02(void) if (s == NULL) { error_count++; } - +/* TODO reenable after both is supported s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:set,abc,both; content:\"GET \"; sid:3;)"); if (s == NULL) { error_count++; } - +*/ s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:unset,abc,src; content:\"GET \"; sid:4;)"); if (s == NULL) { @@ -700,6 +715,8 @@ static int HostBitsTestSig04(void) p->payload_len = buflen; p->proto = IPPROTO_TCP; + HostBitsTestSetup(); + de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -728,6 +745,8 @@ static int HostBitsTestSig04(void) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); + HostBitsTestShutdown(); + SCFree(p); return result; @@ -746,6 +765,8 @@ static int HostBitsTestSig04(void) DetectEngineCtxFree(de_ctx); } + HostBitsTestShutdown(); + SCFree(p); return result; } @@ -781,6 +802,8 @@ static int HostBitsTestSig05(void) p->payload_len = buflen; p->proto = IPPROTO_TCP; + HostBitsTestSetup(); + de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -811,6 +834,8 @@ static int HostBitsTestSig05(void) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); + HostBitsTestShutdown(); + SCFree(p); return result; end: @@ -828,6 +853,8 @@ static int HostBitsTestSig05(void) DetectEngineCtxFree(de_ctx); } + HostBitsTestShutdown(); + SCFree(p); return result; } @@ -1072,7 +1099,7 @@ static int HostBitsTestSig07(void) memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(Flow)); - HostInitConfig(TRUE); + HostBitsTestSetup(); FLOW_INITIALIZE(&f); p->flow = &f; @@ -1126,8 +1153,7 @@ static int HostBitsTestSig07(void) FLOW_DESTROY(&f); - HostCleanup(); - + HostBitsTestShutdown(); SCFree(p); return result; end: @@ -1147,6 +1173,7 @@ static int HostBitsTestSig07(void) FLOW_DESTROY(&f); + HostBitsTestShutdown(); SCFree(p); return result; } @@ -1178,7 +1205,7 @@ static int HostBitsTestSig08(void) memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(Flow)); - HostInitConfig(TRUE); + HostBitsTestSetup(); FLOW_INITIALIZE(&f); p->flow = &f; @@ -1253,7 +1280,7 @@ static int HostBitsTestSig08(void) FLOW_DESTROY(&f); - HostCleanup(); + HostBitsTestShutdown(); SCFree(p); return result; @@ -1274,6 +1301,8 @@ static int HostBitsTestSig08(void) FLOW_DESTROY(&f); + HostBitsTestShutdown(); + SCFree(p); return result; } From 61cb2abc8d3dab3e17663a0db21d2d910bd0bdbe Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Dec 2014 17:40:36 +0100 Subject: [PATCH 0361/2553] ippair: xbit implementation detect xbits for ippair: initial implementation --- src/Makefile.am | 2 + src/detect-xbits.c | 513 ++++++++++++++++++++++++++++++++++++++++ src/detect-xbits.h | 49 ++++ src/detect.c | 2 + src/detect.h | 2 + src/ippair-bit.c | 489 ++++++++++++++++++++++++++++++++++++++ src/ippair-bit.h | 52 ++++ src/runmode-unittests.c | 2 + src/suricata.c | 3 + src/util-var.c | 8 + 10 files changed, 1122 insertions(+) create mode 100644 src/detect-xbits.c create mode 100644 src/detect-xbits.h create mode 100644 src/ippair-bit.c create mode 100644 src/ippair-bit.h diff --git a/src/Makefile.am b/src/Makefile.am index 11d326879919..01c94375b4be 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -198,6 +198,7 @@ detect-urilen.c detect-urilen.h \ detect-window.c detect-window.h \ detect-within.c detect-within.h \ detect-modbus.c detect-modbus.h \ +detect-xbits.c detect-xbits.h \ flow-bit.c flow-bit.h \ flow.c flow.h \ flow-hash.c flow-hash.h \ @@ -213,6 +214,7 @@ host-queue.c host-queue.h \ host-storage.c host-storage.h \ host-timeout.c host-timeout.h \ ippair.c ippair.h \ +ippair-bit.c ippair-bit.h \ ippair-queue.c ippair-queue.h \ ippair-storage.c ippair-storage.h \ ippair-timeout.c ippair-timeout.h \ diff --git a/src/detect-xbits.c b/src/detect-xbits.c new file mode 100644 index 000000000000..28f05c201f83 --- /dev/null +++ b/src/detect-xbits.c @@ -0,0 +1,513 @@ +/* Copyright (C) 2007-2010 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 + * + * Implements the xbits keyword + */ + +#include "suricata-common.h" +#include "decode.h" +#include "detect.h" +#include "threads.h" +#include "flow.h" +#include "flow-util.h" +#include "detect-xbits.h" +#include "util-spm.h" + +#include "detect-engine-sigorder.h" + +#include "app-layer-parser.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow-bit.h" +#include "host-bit.h" +#include "ippair-bit.h" +#include "util-var-name.h" +#include "util-unittest.h" +#include "util-debug.h" + +/* + xbits:set,bitname,track ip_pair + */ + +#define PARSE_REGEX "([a-z]+)(?:,([^,]+))?(?:,(?:track\\s+([^,]+)))" +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +int DetectXbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectXbitSetup (DetectEngineCtx *, Signature *, char *); +void DetectXbitFree (void *); +void XBitsRegisterTests(void); + +void DetectXbitsRegister (void) +{ + sigmatch_table[DETECT_XBITS].name = "xbits"; + sigmatch_table[DETECT_XBITS].desc = "operate on bits"; +// sigmatch_table[DETECT_XBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flowbits"; + sigmatch_table[DETECT_XBITS].Match = DetectXbitMatch; + sigmatch_table[DETECT_XBITS].Setup = DetectXbitSetup; + sigmatch_table[DETECT_XBITS].Free = DetectXbitFree; + sigmatch_table[DETECT_XBITS].RegisterTests = XBitsRegisterTests; + /* this is compatible to ip-only signatures */ + sigmatch_table[DETECT_XBITS].flags |= SIGMATCH_IPONLY_COMPAT; + + const char *eb; + int eo; + int opts = 0; + + parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); + if(parse_regex == NULL) + { + SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); + goto error; + } + + parse_regex_study = pcre_study(parse_regex, 0, &eb); + if(eb != NULL) + { + SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + goto error; + } + + return; + +error: + return; +} + +static int DetectIPPairbitMatchToggle (Packet *p, const DetectXbitsData *fd) +{ + IPPair *pair = IPPairGetIPPairFromHash(&p->src, &p->dst); + if (pair == NULL) + return 0; + + IPPairBitToggle(pair,fd->idx); + IPPairRelease(pair); + return 1; +} + +/* return true even if bit not found */ +static int DetectIPPairbitMatchUnset (Packet *p, const DetectXbitsData *fd) +{ + IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); + if (pair == NULL) + return 1; + + IPPairBitUnset(pair,fd->idx); + IPPairRelease(pair); + return 1; +} + +static int DetectIPPairbitMatchSet (Packet *p, const DetectXbitsData *fd) +{ + IPPair *pair = IPPairGetIPPairFromHash(&p->src, &p->dst); + if (pair == NULL) + return 0; + + IPPairBitSet(pair,fd->idx); + IPPairRelease(pair); + return 1; +} + +static int DetectIPPairbitMatchIsset (Packet *p, const DetectXbitsData *fd) +{ + int r = 0; + IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); + if (pair == NULL) + return 0; + + r = IPPairBitIsset(pair,fd->idx); + IPPairRelease(pair); + return r; +} + +static int DetectIPPairbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) +{ + int r = 0; + IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); + if (pair == NULL) + return 1; + + r = IPPairBitIsnotset(pair,fd->idx); + IPPairRelease(pair); + return r; +} + +/* + * returns 0: no match + * 1: match + * -1: error + */ + +int DetectXbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + const DetectXbitsData *fd = (const DetectXbitsData *)ctx; + if (fd == NULL) + return 0; + + switch (fd->cmd) { + case DETECT_XBITS_CMD_ISSET: + return DetectIPPairbitMatchIsset(p,fd); + case DETECT_XBITS_CMD_ISNOTSET: + return DetectIPPairbitMatchIsnotset(p,fd); + case DETECT_XBITS_CMD_SET: + return DetectIPPairbitMatchSet(p,fd); + case DETECT_XBITS_CMD_UNSET: + return DetectIPPairbitMatchUnset(p,fd); + case DETECT_XBITS_CMD_TOGGLE: + return DetectIPPairbitMatchToggle(p,fd); + default: + SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd); + return 0; + } + + return 0; +} + +int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +{ + DetectXbitsData *cd = NULL; + SigMatch *sm = NULL; + uint8_t fb_cmd = 0; + uint8_t hb_dir = 0; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + char fb_cmd_str[16] = "", fb_name[256] = ""; + char hb_dir_str[16] = ""; + + ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret != 2 && ret != 3 && ret != 4) { + SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for hostbits.", rawstr); + return -1; + } + SCLogDebug("ret %d, %s", ret, rawstr); + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, fb_cmd_str, sizeof(fb_cmd_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return -1; + } + + if (ret >= 3) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, fb_name, sizeof(fb_name)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + if (ret >= 4) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, hb_dir_str, sizeof(hb_dir_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("hb_dir_str %s", hb_dir_str); + if (strlen(hb_dir_str) > 0) { + if (strcmp(hb_dir_str, "ip_src") == 0) + hb_dir = DETECT_XBITS_TRACK_IPSRC; + else if (strcmp(hb_dir_str, "ip_dst") == 0) + hb_dir = DETECT_XBITS_TRACK_IPDST; + else if (strcmp(hb_dir_str, "ip_pair") == 0) { + hb_dir = DETECT_XBITS_TRACK_IPPAIR; + } else { + // TODO + goto error; + } + } + } + } + + if (strcmp(fb_cmd_str,"noalert") == 0) { + fb_cmd = DETECT_XBITS_CMD_NOALERT; + } else if (strcmp(fb_cmd_str,"isset") == 0) { + fb_cmd = DETECT_XBITS_CMD_ISSET; + } else if (strcmp(fb_cmd_str,"isnotset") == 0) { + fb_cmd = DETECT_XBITS_CMD_ISNOTSET; + } else if (strcmp(fb_cmd_str,"set") == 0) { + fb_cmd = DETECT_XBITS_CMD_SET; + } else if (strcmp(fb_cmd_str,"unset") == 0) { + fb_cmd = DETECT_XBITS_CMD_UNSET; + } else if (strcmp(fb_cmd_str,"toggle") == 0) { + fb_cmd = DETECT_XBITS_CMD_TOGGLE; + } else { + SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str); + goto error; + } + + switch (fb_cmd) { + case DETECT_XBITS_CMD_NOALERT: + if (strlen(fb_name) != 0) + goto error; + s->flags |= SIG_FLAG_NOALERT; + return 0; + case DETECT_XBITS_CMD_ISNOTSET: + case DETECT_XBITS_CMD_ISSET: + case DETECT_XBITS_CMD_SET: + case DETECT_XBITS_CMD_UNSET: + case DETECT_XBITS_CMD_TOGGLE: + default: + if (strlen(fb_name) == 0) + goto error; + break; + } + + cd = SCMalloc(sizeof(DetectXbitsData)); + if (unlikely(cd == NULL)) + goto error; + + cd->idx = VariableNameGetIdx(de_ctx, fb_name, DETECT_XBITS); + cd->cmd = fb_cmd; + cd->tracker = hb_dir; + + SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", + cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_XBITS; + sm->ctx = (void *)cd; + + switch (fb_cmd) { + case DETECT_XBITS_CMD_NOALERT: + /* nothing to do */ + break; + + case DETECT_XBITS_CMD_ISNOTSET: + case DETECT_XBITS_CMD_ISSET: + /* checks, so packet list */ + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); + break; + + case DETECT_XBITS_CMD_SET: + case DETECT_XBITS_CMD_UNSET: + case DETECT_XBITS_CMD_TOGGLE: + /* modifiers, only run when entire sig has matched */ + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); + break; + } + + return 0; + +error: + if (cd != NULL) + SCFree(cd); + if (sm != NULL) + SCFree(sm); + return -1; +} + +void DetectXbitFree (void *ptr) +{ + DetectXbitsData *fd = (DetectXbitsData *)ptr; + + if (fd == NULL) + return; + + SCFree(fd); +} + +#ifdef UNITTESTS + +static void XBitsTestSetup(void) +{ + StorageInit(); + HostBitInitCtx(); + IPPairBitInitCtx(); + StorageFinalize(); + HostInitConfig(TRUE); + IPPairInitConfig(TRUE); +} + +static void XBitsTestShutdown(void) +{ + HostCleanup(); + IPPairCleanup(); + StorageCleanup(); +} + +/** + * \test HostBitsTestSig01 is a test for a valid noalert flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int XBitsTestSig01(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + XBitsTestSetup(); + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + printf("bad de_ctx: "); + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:set,abc,track ip_pair; content:\"GET \"; sid:1;)"); + if (s == NULL) { + printf("bad sig: "); + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + result = 1; + +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + XBitsTestShutdown(); + + SCFree(p); + return result; +} + +/** + * \test various options + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int XBitsTestSig02(void) +{ + Signature *s = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + int error_count = 0; + + memset(&th_v, 0, sizeof(th_v)); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:isset,abc,track ip_src; content:\"GET \"; sid:1;)"); + if (s == NULL) { + error_count++; + } + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:isnotset,abc,track ip_dst; content:\"GET \"; sid:2;)"); + if (s == NULL) { + error_count++; + } + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:set,abc,track ip_pair; content:\"GET \"; sid:3;)"); + if (s == NULL) { + error_count++; + } + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:unset,abc,track ip_src; content:\"GET \"; sid:4;)"); + if (s == NULL) { + error_count++; + } + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:toggle,abc,track ip_dst; content:\"GET \"; sid:5;)"); + if (s == NULL) { + error_count++; + } + + if (error_count != 0) + goto end; + + result = 1; + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + + return result; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for XBits + */ +void XBitsRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("XBitsTestSig01", XBitsTestSig01, 1); + UtRegisterTest("XBitsTestSig02", XBitsTestSig02, 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-xbits.h b/src/detect-xbits.h new file mode 100644 index 000000000000..e01d8c330a8e --- /dev/null +++ b/src/detect-xbits.h @@ -0,0 +1,49 @@ +/* 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 + */ + +#ifndef __DETECT_XBITS_H__ +#define __DETECT_XBITS_H__ + +#define DETECT_XBITS_CMD_SET 0 +#define DETECT_XBITS_CMD_TOGGLE 1 +#define DETECT_XBITS_CMD_UNSET 2 +#define DETECT_XBITS_CMD_ISNOTSET 3 +#define DETECT_XBITS_CMD_ISSET 4 +#define DETECT_XBITS_CMD_NOALERT 5 +#define DETECT_XBITS_CMD_MAX 6 + +#define DETECT_XBITS_TRACK_IPSRC 0 +#define DETECT_XBITS_TRACK_IPDST 1 +#define DETECT_XBITS_TRACK_IPPAIR 2 +#define DETECT_XBITS_TRACK_FLOW 3 + +typedef struct DetectXbitsData_ { + uint16_t idx; + uint8_t cmd; + uint8_t tracker; +} DetectXbitsData; + +/* prototypes */ +void DetectXbitsRegister (void); + +#endif /* __DETECT_XBITS_H__ */ diff --git a/src/detect.c b/src/detect.c index 0082969a06c2..e27e57b26dcb 100644 --- a/src/detect.c +++ b/src/detect.c @@ -109,6 +109,7 @@ #include "detect-noalert.h" #include "detect-flowbits.h" #include "detect-hostbits.h" +#include "detect-xbits.h" #include "detect-csum.h" #include "detect-stream_size.h" #include "detect-engine-sigorder.h" @@ -5004,6 +5005,7 @@ void SigTableSetup(void) DetectNoalertRegister(); DetectFlowbitsRegister(); DetectHostbitsRegister(); + DetectXbitsRegister(); DetectEngineEventRegister(); DetectIpOptsRegister(); DetectFlagsRegister(); diff --git a/src/detect.h b/src/detect.h index 775fe2eeaa2a..295950295d02 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1184,6 +1184,8 @@ enum { DETECT_AL_DNS_QUERY, DETECT_AL_MODBUS, + DETECT_XBITS, + /* make sure this stays last */ DETECT_TBLSIZE, }; diff --git a/src/ippair-bit.c b/src/ippair-bit.c new file mode 100644 index 000000000000..0a38568786d5 --- /dev/null +++ b/src/ippair-bit.c @@ -0,0 +1,489 @@ +/* Copyright (C) 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 + * + * Implements per ippair bits. Actually, not a bit, + * but called that way because of Snort's flowbits. + * It's a binary storage. + * + * \todo move away from a linked list implementation + * \todo use different datatypes, such as string, int, etc. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "ippair-bit.h" +#include "ippair.h" +#include "detect.h" +#include "util-var.h" +#include "util-debug.h" +#include "util-unittest.h" +#include "ippair-storage.h" + +static int ippair_bit_id = -1; /**< IPPair storage id for bits */ + +void XBitFreeAll(void *store) { + GenericVar *gv = store; + GenericVarFree(gv); +} + +void IPPairBitInitCtx(void) +{ + ippair_bit_id = IPPairStorageRegister("bit", sizeof(void *), NULL, XBitFreeAll); + if (ippair_bit_id == -1) { + SCLogError(SC_ERR_IPPAIR_INIT, "Can't initiate ippair storage for bits"); + exit(EXIT_FAILURE); + } +} + +/* lock before using this */ +int IPPairHasBits(IPPair *ippair) +{ + if (ippair == NULL) + return 0; + return IPPairGetStorageById(ippair, ippair_bit_id) ? 1 : 0; +} + +/* get the bit with idx from the ippair */ +static XBit *IPPairBitGet(IPPair *h, uint16_t idx) +{ + GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_XBITS && gv->idx == idx) { + return (XBit *)gv; + } + } + + return NULL; +} + +/* add a flowbit to the flow */ +static void IPPairBitAdd(IPPair *h, uint16_t idx) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb == NULL) { + fb = SCMalloc(sizeof(XBit)); + if (unlikely(fb == NULL)) + return; + + fb->type = DETECT_XBITS; + fb->idx = idx; + fb->next = NULL; + + GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); + GenericVarAppend(&gv, (GenericVar *)fb); + IPPairSetStorageById(h, ippair_bit_id, gv); + } +} + +static void IPPairBitRemove(IPPair *h, uint16_t idx) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb == NULL) + return; + + GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); + if (gv) { + GenericVarRemove(&gv, (GenericVar *)fb); + IPPairSetStorageById(h, ippair_bit_id, gv); + } +} + +void IPPairBitSet(IPPair *h, uint16_t idx) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb == NULL) { + IPPairBitAdd(h, idx); + } +} + +void IPPairBitUnset(IPPair *h, uint16_t idx) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb != NULL) { + IPPairBitRemove(h, idx); + } +} + +void IPPairBitToggle(IPPair *h, uint16_t idx) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb != NULL) { + IPPairBitRemove(h, idx); + } else { + IPPairBitAdd(h, idx); + } +} + +int IPPairBitIsset(IPPair *h, uint16_t idx) +{ + int r = 0; + + XBit *fb = IPPairBitGet(h, idx); + if (fb != NULL) { + r = 1; + } + return r; +} + +int IPPairBitIsnotset(IPPair *h, uint16_t idx) +{ + int r = 0; + + XBit *fb = IPPairBitGet(h, idx); + if (fb == NULL) { + r = 1; + } + + return r; +} + +void XBitFree(XBit *fb) +{ + if (fb == NULL) + return; + + SCFree(fb); +} + + +/* TESTS */ +#ifdef UNITTESTS +static int IPPairBitTest01 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0); + + XBit *fb = IPPairBitGet(h,0); + if (fb != NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest02 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + XBit *fb = IPPairBitGet(h,0); + if (fb == NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest03 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0); + + XBit *fb = IPPairBitGet(h,0); + if (fb == NULL) { + printf("fb == NULL although it was just added: "); + goto end; + } + + IPPairBitRemove(h, 0); + + fb = IPPairBitGet(h,0); + if (fb != NULL) { + printf("fb != NULL although it was just removed: "); + goto end; + } else { + ret = 1; + } + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest04 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0); + IPPairBitAdd(h, 1); + IPPairBitAdd(h, 2); + IPPairBitAdd(h, 3); + + XBit *fb = IPPairBitGet(h,0); + if (fb != NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest05 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0); + IPPairBitAdd(h, 1); + IPPairBitAdd(h, 2); + IPPairBitAdd(h, 3); + + XBit *fb = IPPairBitGet(h,1); + if (fb != NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest06 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0); + IPPairBitAdd(h, 1); + IPPairBitAdd(h, 2); + IPPairBitAdd(h, 3); + + XBit *fb = IPPairBitGet(h,2); + if (fb != NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest07 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0); + IPPairBitAdd(h, 1); + IPPairBitAdd(h, 2); + IPPairBitAdd(h, 3); + + XBit *fb = IPPairBitGet(h,3); + if (fb != NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest08 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0); + IPPairBitAdd(h, 1); + IPPairBitAdd(h, 2); + IPPairBitAdd(h, 3); + + XBit *fb = IPPairBitGet(h,0); + if (fb == NULL) + goto end; + + IPPairBitRemove(h,0); + + fb = IPPairBitGet(h,0); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest09 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0); + IPPairBitAdd(h, 1); + IPPairBitAdd(h, 2); + IPPairBitAdd(h, 3); + + XBit *fb = IPPairBitGet(h,1); + if (fb == NULL) + goto end; + + IPPairBitRemove(h,1); + + fb = IPPairBitGet(h,1); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest10 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0); + IPPairBitAdd(h, 1); + IPPairBitAdd(h, 2); + IPPairBitAdd(h, 3); + + XBit *fb = IPPairBitGet(h,2); + if (fb == NULL) + goto end; + + IPPairBitRemove(h,2); + + fb = IPPairBitGet(h,2); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest11 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0); + IPPairBitAdd(h, 1); + IPPairBitAdd(h, 2); + IPPairBitAdd(h, 3); + + XBit *fb = IPPairBitGet(h,3); + if (fb == NULL) + goto end; + + IPPairBitRemove(h,3); + + fb = IPPairBitGet(h,3); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + IPPairFree(h); +end: + IPPairCleanup(); + ret = 1; + return ret; +} + +#endif /* UNITTESTS */ + +void IPPairBitRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("IPPairBitTest01", IPPairBitTest01, 1); + UtRegisterTest("IPPairBitTest02", IPPairBitTest02, 1); + UtRegisterTest("IPPairBitTest03", IPPairBitTest03, 1); + UtRegisterTest("IPPairBitTest04", IPPairBitTest04, 1); + UtRegisterTest("IPPairBitTest05", IPPairBitTest05, 1); + UtRegisterTest("IPPairBitTest06", IPPairBitTest06, 1); + UtRegisterTest("IPPairBitTest07", IPPairBitTest07, 1); + UtRegisterTest("IPPairBitTest08", IPPairBitTest08, 1); + UtRegisterTest("IPPairBitTest09", IPPairBitTest09, 1); + UtRegisterTest("IPPairBitTest10", IPPairBitTest10, 1); + UtRegisterTest("IPPairBitTest11", IPPairBitTest11, 1); +#endif /* UNITTESTS */ +} diff --git a/src/ippair-bit.h b/src/ippair-bit.h new file mode 100644 index 000000000000..43019c920e12 --- /dev/null +++ b/src/ippair-bit.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2007-2010 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 + */ + +#ifndef __IPPAIR_BIT_H__ +#define __IPPAIR_BIT_H__ + +#include "ippair.h" +#include "util-var.h" + +typedef struct XBit_ { + uint8_t type; /* type, DETECT_XBITS in this case */ + uint16_t idx; /* name idx */ + GenericVar *next; /* right now just implement this as a list, + * in the long run we have think of something + * faster. */ +} XBit; + +void XBitFree(XBit *fb); + +void IPPairBitInitCtx(void); +void IPPairBitFree(XBit *); +void IPPairBitRegisterTests(void); + +int IPPairHasIPPairBits(IPPair *host); + +void IPPairBitSet(IPPair *, uint16_t); +void IPPairBitUnset(IPPair *, uint16_t); +void IPPairBitToggle(IPPair *, uint16_t); +int IPPairBitIsset(IPPair *, uint16_t); +int IPPairBitIsnotset(IPPair *, uint16_t); + +#endif /* __IPPAIR_BIT_H__ */ diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 1252dd975204..e7a8b34d2745 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -62,6 +62,7 @@ #include "host.h" #include "host-bit.h" #include "ippair.h" +#include "ippair-bit.h" #include "unix-manager.h" #include "app-layer-detect-proto.h" @@ -198,6 +199,7 @@ void RunUnittests(int list_unittests, char *regex_arg) MpmRegisterTests(); FlowBitRegisterTests(); HostBitRegisterTests(); + IPPairBitRegisterTests(); SCPerfRegisterTests(); DecodePPPRegisterTests(); DecodeVLANRegisterTests(); diff --git a/src/suricata.c b/src/suricata.c index a6e022b5ce92..5918708b8a5e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -133,6 +133,8 @@ #include "host-bit.h" #include "ippair.h" +#include "ippair-bit.h" + #include "host.h" #include "unix-manager.h" @@ -2099,6 +2101,7 @@ static int PostConfLoadedSetup(SCInstance *suri) TagInitCtx(); ThresholdInit(); HostBitInitCtx(); + IPPairBitInitCtx(); if (DetectAddressTestConfVars() < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, diff --git a/src/util-var.c b/src/util-var.c index b84f19118749..fb0b1f4a99f3 100644 --- a/src/util-var.c +++ b/src/util-var.c @@ -32,6 +32,7 @@ #include "flow-bit.h" #include "pkt-var.h" #include "host-bit.h" +#include "ippair-bit.h" #include "util-debug.h" @@ -58,6 +59,13 @@ void GenericVarFree(GenericVar *gv) HostBitFree(fb); break; } + case DETECT_XBITS: + { + XBit *fb = (XBit *)gv; + //printf("GenericVarFree: fb %p, removing\n", fb); + XBitFree(fb); + break; + } case DETECT_FLOWVAR: { FlowVar *fv = (FlowVar *)gv; From a716dded04d493618b47e5d89eb9b4d4a6a4dbc3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 10:00:24 +0100 Subject: [PATCH 0362/2553] xbit: move to util-var We can reuse the type for hostbits and flowbits as well. --- src/ippair-bit.c | 8 -------- src/ippair-bit.h | 11 ----------- src/util-var.c | 8 ++++++++ src/util-var.h | 6 ++++++ 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/ippair-bit.c b/src/ippair-bit.c index 0a38568786d5..5a72288867f1 100644 --- a/src/ippair-bit.c +++ b/src/ippair-bit.c @@ -156,14 +156,6 @@ int IPPairBitIsnotset(IPPair *h, uint16_t idx) return r; } -void XBitFree(XBit *fb) -{ - if (fb == NULL) - return; - - SCFree(fb); -} - /* TESTS */ #ifdef UNITTESTS diff --git a/src/ippair-bit.h b/src/ippair-bit.h index 43019c920e12..e44c0320a90d 100644 --- a/src/ippair-bit.h +++ b/src/ippair-bit.h @@ -27,18 +27,7 @@ #include "ippair.h" #include "util-var.h" -typedef struct XBit_ { - uint8_t type; /* type, DETECT_XBITS in this case */ - uint16_t idx; /* name idx */ - GenericVar *next; /* right now just implement this as a list, - * in the long run we have think of something - * faster. */ -} XBit; - -void XBitFree(XBit *fb); - void IPPairBitInitCtx(void); -void IPPairBitFree(XBit *); void IPPairBitRegisterTests(void); int IPPairHasIPPairBits(IPPair *host); diff --git a/src/util-var.c b/src/util-var.c index fb0b1f4a99f3..0ba93deb4501 100644 --- a/src/util-var.c +++ b/src/util-var.c @@ -36,6 +36,14 @@ #include "util-debug.h" +static void XBitFree(XBit *fb) +{ + if (fb == NULL) + return; + + SCFree(fb); +} + void GenericVarFree(GenericVar *gv) { if (gv == NULL) diff --git a/src/util-var.h b/src/util-var.h index 5d28cc7cc11f..21907227962e 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -30,6 +30,12 @@ typedef struct GenericVar_ { struct GenericVar_ *next; } GenericVar; +typedef struct XBit_ { + uint8_t type; /* type, DETECT_XBITS in this case */ + uint16_t idx; /* name idx */ + GenericVar *next; +} XBit; + void GenericVarFree(GenericVar *); void GenericVarAppend(GenericVar **, GenericVar *); void GenericVarRemove(GenericVar **, GenericVar *); From f77c3d9a2c5602a088ebf5fb92659ee480bf42b6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 10:06:30 +0100 Subject: [PATCH 0363/2553] xbits: hostbits use xbits type Make hostbits use xbits type. --- src/host-bit.c | 55 +++++++++++++++++++++----------------------------- src/host-bit.h | 9 --------- src/util-var.c | 7 ------- 3 files changed, 23 insertions(+), 48 deletions(-) diff --git a/src/host-bit.c b/src/host-bit.c index a70d15bf6e88..ed07e2ffa894 100644 --- a/src/host-bit.c +++ b/src/host-bit.c @@ -63,12 +63,12 @@ int HostHasHostBits(Host *host) } /* get the bit with idx from the host */ -static HostBit *HostBitGet(Host *h, uint16_t idx) +static XBit *HostBitGet(Host *h, uint16_t idx) { GenericVar *gv = HostGetStorageById(h, host_bit_id); for ( ; gv != NULL; gv = gv->next) { - if (gv->type == DETECT_HOSTBITS && gv->idx == idx) { - return (HostBit *)gv; + if (gv->type == DETECT_XBITS && gv->idx == idx) { + return (XBit *)gv; } } @@ -78,13 +78,13 @@ static HostBit *HostBitGet(Host *h, uint16_t idx) /* add a flowbit to the flow */ static void HostBitAdd(Host *h, uint16_t idx) { - HostBit *fb = HostBitGet(h, idx); + XBit *fb = HostBitGet(h, idx); if (fb == NULL) { - fb = SCMalloc(sizeof(HostBit)); + fb = SCMalloc(sizeof(XBit)); if (unlikely(fb == NULL)) return; - fb->type = DETECT_HOSTBITS; + fb->type = DETECT_XBITS; fb->idx = idx; fb->next = NULL; @@ -96,7 +96,7 @@ static void HostBitAdd(Host *h, uint16_t idx) static void HostBitRemove(Host *h, uint16_t idx) { - HostBit *fb = HostBitGet(h, idx); + XBit *fb = HostBitGet(h, idx); if (fb == NULL) return; @@ -109,7 +109,7 @@ static void HostBitRemove(Host *h, uint16_t idx) void HostBitSet(Host *h, uint16_t idx) { - HostBit *fb = HostBitGet(h, idx); + XBit *fb = HostBitGet(h, idx); if (fb == NULL) { HostBitAdd(h, idx); } @@ -117,7 +117,7 @@ void HostBitSet(Host *h, uint16_t idx) void HostBitUnset(Host *h, uint16_t idx) { - HostBit *fb = HostBitGet(h, idx); + XBit *fb = HostBitGet(h, idx); if (fb != NULL) { HostBitRemove(h, idx); } @@ -125,7 +125,7 @@ void HostBitUnset(Host *h, uint16_t idx) void HostBitToggle(Host *h, uint16_t idx) { - HostBit *fb = HostBitGet(h, idx); + XBit *fb = HostBitGet(h, idx); if (fb != NULL) { HostBitRemove(h, idx); } else { @@ -137,7 +137,7 @@ int HostBitIsset(Host *h, uint16_t idx) { int r = 0; - HostBit *fb = HostBitGet(h, idx); + XBit *fb = HostBitGet(h, idx); if (fb != NULL) { r = 1; } @@ -148,7 +148,7 @@ int HostBitIsnotset(Host *h, uint16_t idx) { int r = 0; - HostBit *fb = HostBitGet(h, idx); + XBit *fb = HostBitGet(h, idx); if (fb == NULL) { r = 1; } @@ -156,15 +156,6 @@ int HostBitIsnotset(Host *h, uint16_t idx) return r; } -void HostBitFree(HostBit *fb) -{ - if (fb == NULL) - return; - - SCFree(fb); -} - - /* TESTS */ #ifdef UNITTESTS static int HostBitTest01 (void) @@ -178,7 +169,7 @@ static int HostBitTest01 (void) HostBitAdd(h, 0); - HostBit *fb = HostBitGet(h,0); + XBit *fb = HostBitGet(h,0); if (fb != NULL) ret = 1; @@ -197,7 +188,7 @@ static int HostBitTest02 (void) if (h == NULL) goto end; - HostBit *fb = HostBitGet(h,0); + XBit *fb = HostBitGet(h,0); if (fb == NULL) ret = 1; @@ -218,7 +209,7 @@ static int HostBitTest03 (void) HostBitAdd(h, 0); - HostBit *fb = HostBitGet(h,0); + XBit *fb = HostBitGet(h,0); if (fb == NULL) { printf("fb == NULL although it was just added: "); goto end; @@ -254,7 +245,7 @@ static int HostBitTest04 (void) HostBitAdd(h, 2); HostBitAdd(h, 3); - HostBit *fb = HostBitGet(h,0); + XBit *fb = HostBitGet(h,0); if (fb != NULL) ret = 1; @@ -278,7 +269,7 @@ static int HostBitTest05 (void) HostBitAdd(h, 2); HostBitAdd(h, 3); - HostBit *fb = HostBitGet(h,1); + XBit *fb = HostBitGet(h,1); if (fb != NULL) ret = 1; @@ -302,7 +293,7 @@ static int HostBitTest06 (void) HostBitAdd(h, 2); HostBitAdd(h, 3); - HostBit *fb = HostBitGet(h,2); + XBit *fb = HostBitGet(h,2); if (fb != NULL) ret = 1; @@ -326,7 +317,7 @@ static int HostBitTest07 (void) HostBitAdd(h, 2); HostBitAdd(h, 3); - HostBit *fb = HostBitGet(h,3); + XBit *fb = HostBitGet(h,3); if (fb != NULL) ret = 1; @@ -350,7 +341,7 @@ static int HostBitTest08 (void) HostBitAdd(h, 2); HostBitAdd(h, 3); - HostBit *fb = HostBitGet(h,0); + XBit *fb = HostBitGet(h,0); if (fb == NULL) goto end; @@ -383,7 +374,7 @@ static int HostBitTest09 (void) HostBitAdd(h, 2); HostBitAdd(h, 3); - HostBit *fb = HostBitGet(h,1); + XBit *fb = HostBitGet(h,1); if (fb == NULL) goto end; @@ -416,7 +407,7 @@ static int HostBitTest10 (void) HostBitAdd(h, 2); HostBitAdd(h, 3); - HostBit *fb = HostBitGet(h,2); + XBit *fb = HostBitGet(h,2); if (fb == NULL) goto end; @@ -449,7 +440,7 @@ static int HostBitTest11 (void) HostBitAdd(h, 2); HostBitAdd(h, 3); - HostBit *fb = HostBitGet(h,3); + XBit *fb = HostBitGet(h,3); if (fb == NULL) goto end; diff --git a/src/host-bit.h b/src/host-bit.h index c10a4fecf008..884ae3b1a580 100644 --- a/src/host-bit.h +++ b/src/host-bit.h @@ -27,16 +27,7 @@ #include "host.h" #include "util-var.h" -typedef struct HostBit_ { - uint8_t type; /* type, DETECT_HOSTBITS in this case */ - uint16_t idx; /* name idx */ - GenericVar *next; /* right now just implement this as a list, - * in the long run we have think of something - * faster. */ -} HostBit; - void HostBitInitCtx(void); -void HostBitFree(HostBit *); void HostBitRegisterTests(void); int HostHasHostBits(Host *host); diff --git a/src/util-var.c b/src/util-var.c index 0ba93deb4501..e4e9689b35d9 100644 --- a/src/util-var.c +++ b/src/util-var.c @@ -60,13 +60,6 @@ void GenericVarFree(GenericVar *gv) FlowBitFree(fb); break; } - case DETECT_HOSTBITS: - { - HostBit *fb = (HostBit *)gv; - //printf("GenericVarFree: fb %p, removing\n", fb); - HostBitFree(fb); - break; - } case DETECT_XBITS: { XBit *fb = (XBit *)gv; From dea8dda3c19773ba51a6bb67d9e365047251c598 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 12:02:59 +0100 Subject: [PATCH 0364/2553] vars: redo var name <-> idx handling Can't use sm type anymore as multiple var carriers (host/flow/etc) will all have xbits. --- src/detect-engine-sigorder.c | 104 ++++++++++++++++++++----------- src/detect-engine-sigorder.h | 1 + src/detect-flowbits.c | 10 +-- src/detect-flowint.c | 4 +- src/detect-flowvar.c | 2 +- src/detect-hostbits.c | 115 +++++++++++++++++------------------ src/detect-hostbits.h | 18 +----- src/detect-lua.c | 4 +- src/detect-pcre.c | 4 +- src/detect-xbits.c | 13 ++-- src/detect-xbits.h | 2 + src/detect.c | 2 +- src/util-var-name.c | 10 +-- src/util-var-name.h | 4 +- src/util-var.h | 20 ++++++ 15 files changed, 177 insertions(+), 136 deletions(-) diff --git a/src/detect-engine-sigorder.c b/src/detect-engine-sigorder.c index edca49c353e4..0baa87a22e0d 100644 --- a/src/detect-engine-sigorder.c +++ b/src/detect-engine-sigorder.c @@ -25,7 +25,7 @@ #include "suricata-common.h" #include "detect.h" -#include "detect-hostbits.h" +#include "detect-xbits.h" #include "detect-flowbits.h" #include "detect-flowint.h" #include "detect-parse.h" @@ -59,10 +59,10 @@ #define DETECT_FLOWINT_TYPE_SET_READ 3 #define DETECT_FLOWINT_TYPE_SET 4 -#define DETECT_HOSTBITS_NOT_USED 1 -#define DETECT_HOSTBITS_TYPE_READ 2 -#define DETECT_HOSTBITS_TYPE_SET_READ 3 -#define DETECT_HOSTBITS_TYPE_SET 4 +#define DETECT_XBITS_NOT_USED 1 +#define DETECT_XBITS_TYPE_READ 2 +#define DETECT_XBITS_TYPE_SET_READ 3 +#define DETECT_XBITS_TYPE_SET 4 /** @@ -347,37 +347,39 @@ static inline int SCSigGetPktvarType(Signature *sig) } /** - * \brief Returns the hostbit type set for this signature. If more than one - * hostbit has been set for the same rule, we return the hostbit type of + * \brief Returns the xbit type set for this signature. If more than one + * xbit has been set for the same rule, we return the xbit type of * the maximum priority/value, where priority/value is maximum for the * ones that set the value and the lowest for ones that read the value. - * If no hostbit has been set for the rule, we return 0, which indicates - * the least value amongst hostbit types. + * If no xbit has been set for the rule, we return 0, which indicates + * the least value amongst xbit types. * - * \param sig Pointer to the Signature from which the hostbit value has to be + * \param sig Pointer to the Signature from which the xbit value has to be * returned. * - * \retval hostbits The hostbits type for this signature if it is set; if it is + * \retval xbits The xbits type for this signature if it is set; if it is * not set, return 0 */ -static inline int SCSigGetHostbitsType(Signature *sig) +static inline int SCSigGetXbitsType(Signature *sig, enum VarTypes type) { - DetectHostbitsData *fb = NULL; - int hostbits_user_type = DETECT_HOSTBITS_NOT_USED; + DetectXbitsData *fb = NULL; + int xbits_user_type = DETECT_XBITS_NOT_USED; int read = 0; int write = 0; SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { - if (sm->type == DETECT_HOSTBITS) { - fb = (DetectHostbitsData *)sm->ctx; - if (fb->cmd == DETECT_HOSTBITS_CMD_ISNOTSET || - fb->cmd == DETECT_HOSTBITS_CMD_ISSET) { - read++; - } else { + if (sm->type == DETECT_XBITS) { + fb = (DetectXbitsData *)sm->ctx; + if (fb->type == type) { + if (fb->cmd == DETECT_XBITS_CMD_ISNOTSET || + fb->cmd == DETECT_XBITS_CMD_ISSET) { + read++; + } else { #ifdef DEBUG - BUG_ON(1); + BUG_ON(1); #endif + } } } @@ -387,15 +389,17 @@ static inline int SCSigGetHostbitsType(Signature *sig) sm = sig->sm_lists[DETECT_SM_LIST_POSTMATCH]; while (sm != NULL) { if (sm->type == DETECT_HOSTBITS) { - fb = (DetectHostbitsData *)sm->ctx; - if (fb->cmd == DETECT_HOSTBITS_CMD_SET || - fb->cmd == DETECT_HOSTBITS_CMD_UNSET || - fb->cmd == DETECT_HOSTBITS_CMD_TOGGLE) { - write++; - } else { + fb = (DetectXbitsData *)sm->ctx; + if (fb->type == type) { + if (fb->cmd == DETECT_XBITS_CMD_SET || + fb->cmd == DETECT_XBITS_CMD_UNSET || + fb->cmd == DETECT_XBITS_CMD_TOGGLE) { + write++; + } else { #ifdef DEBUG - BUG_ON(1); + BUG_ON(1); #endif + } } } @@ -403,16 +407,16 @@ static inline int SCSigGetHostbitsType(Signature *sig) } if (read > 0 && write == 0) { - hostbits_user_type = DETECT_HOSTBITS_TYPE_READ; + xbits_user_type = DETECT_XBITS_TYPE_READ; } else if (read == 0 && write > 0) { - hostbits_user_type = DETECT_HOSTBITS_TYPE_SET; + xbits_user_type = DETECT_XBITS_TYPE_SET; } else if (read > 0 && write > 0) { - hostbits_user_type = DETECT_HOSTBITS_TYPE_SET_READ; + xbits_user_type = DETECT_XBITS_TYPE_SET_READ; } - SCLogDebug("Sig %s typeval %d", sig->msg, hostbits_user_type); + SCLogDebug("Sig %s typeval %d", sig->msg, xbits_user_type); - return hostbits_user_type; + return xbits_user_type; } /** @@ -457,15 +461,27 @@ static inline void SCSigProcessUserDataForPktvar(SCSigSignatureWrapper *sw) } /** - * \brief Processes the flowbits data for this signature and caches it for + * \brief Processes the hostbits data for this signature and caches it for * future use. This is needed to optimize the sig_ordering module. * - * \param sw The sigwrapper/signature for which the flowbits data has to be + * \param sw The sigwrapper/signature for which the hostbits data has to be * cached */ static inline void SCSigProcessUserDataForHostbits(SCSigSignatureWrapper *sw) { - sw->user[SC_RADIX_USER_DATA_HOSTBITS] = SCSigGetHostbitsType(sw->sig); + sw->user[SC_RADIX_USER_DATA_HOSTBITS] = SCSigGetXbitsType(sw->sig, VAR_TYPE_HOST_BIT); +} + +/** + * \brief Processes the hostbits data for this signature and caches it for + * future use. This is needed to optimize the sig_ordering module. + * + * \param sw The sigwrapper/signature for which the hostbits data has to be + * cached + */ +static inline void SCSigProcessUserDataForIPPairbits(SCSigSignatureWrapper *sw) +{ + sw->user[SC_RADIX_USER_DATA_IPPAIRBITS] = SCSigGetXbitsType(sw->sig, VAR_TYPE_IPPAIR_BIT); } /* Return 1 if sw1 comes before sw2 in the final list. */ @@ -629,6 +645,20 @@ static int SCSigOrderByHostbitsCompare(SCSigSignatureWrapper *sw1, sw2->user[SC_RADIX_USER_DATA_HOSTBITS]; } +/** + * \brief Orders an incoming Signature based on its ippairbits (xbits) type + * + * \param de_ctx Pointer to the detection engine context from which the + * signatures have to be ordered. + * \param sw The new signature that has to be ordered based on its bits + */ +static int SCSigOrderByIPPairbitsCompare(SCSigSignatureWrapper *sw1, + SCSigSignatureWrapper *sw2) +{ + return sw1->user[SC_RADIX_USER_DATA_IPPAIRBITS] - + sw2->user[SC_RADIX_USER_DATA_IPPAIRBITS]; +} + /** * \brief Orders an incoming Signature based on its priority type * @@ -666,6 +696,7 @@ static inline SCSigSignatureWrapper *SCSigAllocSignatureWrapper(Signature *sig) SCSigProcessUserDataForFlowint(sw); SCSigProcessUserDataForPktvar(sw); SCSigProcessUserDataForHostbits(sw); + SCSigProcessUserDataForIPPairbits(sw); return sw; } @@ -746,6 +777,7 @@ void SCSigRegisterSignatureOrderingFuncs(DetectEngineCtx *de_ctx) SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByHostbitsCompare); + SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByIPPairbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); } diff --git a/src/detect-engine-sigorder.h b/src/detect-engine-sigorder.h index 312165a04bf1..686ce9280f4d 100644 --- a/src/detect-engine-sigorder.h +++ b/src/detect-engine-sigorder.h @@ -34,6 +34,7 @@ typedef enum{ SC_RADIX_USER_DATA_PKTVAR, SC_RADIX_USER_DATA_FLOWINT, SC_RADIX_USER_DATA_HOSTBITS, + SC_RADIX_USER_DATA_IPPAIRBITS, SC_RADIX_USER_DATA_MAX } SCRadixUserDataType; diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index e1ea8e60ae1e..315cb8cfc9c3 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -244,7 +244,7 @@ int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) if (unlikely(cd == NULL)) goto error; - cd->idx = VariableNameGetIdx(de_ctx, fb_name, DETECT_FLOWBITS); + cd->idx = VariableNameGetIdx(de_ctx, fb_name, VAR_TYPE_FLOW_BIT); cd->cmd = fb_cmd; SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", @@ -616,7 +616,7 @@ static int FlowBitsTestSig04(void) s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)"); - idx = VariableNameGetIdx(de_ctx, "fbt", DETECT_FLOWBITS); + idx = VariableNameGetIdx(de_ctx, "fbt", VAR_TYPE_FLOW_BIT); if (s == NULL || idx != 1) { goto end; @@ -797,7 +797,7 @@ static int FlowBitsTestSig06(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_FLOWBITS); + idx = VariableNameGetIdx(de_ctx, "myflow", VAR_TYPE_FLOW_BIT); gv = p->flow->flowvar; @@ -903,7 +903,7 @@ static int FlowBitsTestSig07(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_FLOWBITS); + idx = VariableNameGetIdx(de_ctx, "myflow", VAR_TYPE_FLOW_BIT); gv = p->flow->flowvar; @@ -1012,7 +1012,7 @@ static int FlowBitsTestSig08(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_FLOWBITS); + idx = VariableNameGetIdx(de_ctx, "myflow", VAR_TYPE_FLOW_BIT); gv = p->flow->flowvar; diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 6328b67572a2..54303cd3ae4c 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -126,7 +126,7 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, * return zero(not match). */ if (sfd->targettype == FLOWINT_TARGET_VAR) { - uint16_t tvar_idx = VariableNameGetIdx(det_ctx->de_ctx, sfd->target.tvar.name, DETECT_FLOWINT); + uint16_t tvar_idx = VariableNameGetIdx(det_ctx->de_ctx, sfd->target.tvar.name, VAR_TYPE_FLOW_INT); fvt = FlowVarGet(p->flow, tvar_idx); /* We don't have that variable initialized yet */ @@ -351,7 +351,7 @@ DetectFlowintData *DetectFlowintParse(DetectEngineCtx *de_ctx, char *rawstr) goto error; } if (de_ctx != NULL) - sfd->idx = VariableNameGetIdx(de_ctx, varname, DETECT_FLOWINT); + sfd->idx = VariableNameGetIdx(de_ctx, varname, VAR_TYPE_FLOW_INT); sfd->modifier = modifier; pcre_free_substring(varname); diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index 8e8fddee0be1..f6ff82d60891 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -188,7 +188,7 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws fd->name = SCStrdup(varname); if (unlikely(fd->name == NULL)) goto error; - fd->idx = VariableNameGetIdx(de_ctx, varname, DETECT_FLOWVAR); + fd->idx = VariableNameGetIdx(de_ctx, varname, VAR_TYPE_FLOW_VAR); /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 22797af0e050..11897bda4130 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -106,10 +106,10 @@ void DetectHostbitsRegister (void) return; } -static int DetectHostbitMatchToggle (Packet *p, const DetectHostbitsData *fd) +static int DetectHostbitMatchToggle (Packet *p, const DetectXbitsData *fd) { - switch (fd->dir) { - case DETECT_HOSTBITS_DIR_SRC: + switch (fd->tracker) { + case DETECT_XBITS_TRACK_IPSRC: if (p->host_src == NULL) { p->host_src = HostGetHostFromHash(&p->src); if (p->host_src == NULL) @@ -121,7 +121,7 @@ static int DetectHostbitMatchToggle (Packet *p, const DetectHostbitsData *fd) HostBitToggle(p->host_src,fd->idx); HostUnlock(p->host_src); break; - case DETECT_HOSTBITS_DIR_DST: + case DETECT_XBITS_TRACK_IPDST: if (p->host_dst == NULL) { p->host_dst = HostGetHostFromHash(&p->dst); if (p->host_dst == NULL) @@ -138,10 +138,10 @@ static int DetectHostbitMatchToggle (Packet *p, const DetectHostbitsData *fd) } /* return true even if bit not found */ -static int DetectHostbitMatchUnset (Packet *p, const DetectHostbitsData *fd) +static int DetectHostbitMatchUnset (Packet *p, const DetectXbitsData *fd) { - switch (fd->dir) { - case DETECT_HOSTBITS_DIR_SRC: + switch (fd->tracker) { + case DETECT_XBITS_TRACK_IPSRC: if (p->host_src == NULL) { p->host_src = HostLookupHostFromHash(&p->src); if (p->host_src == NULL) @@ -152,7 +152,7 @@ static int DetectHostbitMatchUnset (Packet *p, const DetectHostbitsData *fd) HostBitUnset(p->host_src,fd->idx); HostUnlock(p->host_src); break; - case DETECT_HOSTBITS_DIR_DST: + case DETECT_XBITS_TRACK_IPDST: if (p->host_dst == NULL) { p->host_dst = HostLookupHostFromHash(&p->dst); if (p->host_dst == NULL) @@ -167,10 +167,10 @@ static int DetectHostbitMatchUnset (Packet *p, const DetectHostbitsData *fd) return 1; } -static int DetectHostbitMatchSet (Packet *p, const DetectHostbitsData *fd) +static int DetectHostbitMatchSet (Packet *p, const DetectXbitsData *fd) { - switch (fd->dir) { - case DETECT_HOSTBITS_DIR_SRC: + switch (fd->tracker) { + case DETECT_XBITS_TRACK_IPSRC: if (p->host_src == NULL) { p->host_src = HostGetHostFromHash(&p->src); if (p->host_src == NULL) @@ -181,7 +181,7 @@ static int DetectHostbitMatchSet (Packet *p, const DetectHostbitsData *fd) HostBitSet(p->host_src,fd->idx); HostUnlock(p->host_src); break; - case DETECT_HOSTBITS_DIR_DST: + case DETECT_XBITS_TRACK_IPDST: if (p->host_dst == NULL) { p->host_dst = HostGetHostFromHash(&p->dst); if (p->host_dst == NULL) @@ -196,11 +196,11 @@ static int DetectHostbitMatchSet (Packet *p, const DetectHostbitsData *fd) return 1; } -static int DetectHostbitMatchIsset (Packet *p, const DetectHostbitsData *fd) +static int DetectHostbitMatchIsset (Packet *p, const DetectXbitsData *fd) { int r = 0; - switch (fd->dir) { - case DETECT_HOSTBITS_DIR_SRC: + switch (fd->tracker) { + case DETECT_XBITS_TRACK_IPSRC: if (p->host_src == NULL) { p->host_src = HostLookupHostFromHash(&p->src); if (p->host_src == NULL) @@ -208,11 +208,10 @@ static int DetectHostbitMatchIsset (Packet *p, const DetectHostbitsData *fd) } else HostLock(p->host_src); - HostLock(p->host_src); r = HostBitIsset(p->host_src,fd->idx); HostUnlock(p->host_src); return r; - case DETECT_HOSTBITS_DIR_DST: + case DETECT_XBITS_TRACK_IPDST: if (p->host_dst == NULL) { p->host_dst = HostLookupHostFromHash(&p->dst); if (p->host_dst == NULL) @@ -220,7 +219,6 @@ static int DetectHostbitMatchIsset (Packet *p, const DetectHostbitsData *fd) } else HostLock(p->host_dst); - HostLock(p->host_dst); r = HostBitIsset(p->host_dst,fd->idx); HostUnlock(p->host_dst); return r; @@ -228,11 +226,11 @@ static int DetectHostbitMatchIsset (Packet *p, const DetectHostbitsData *fd) return 0; } -static int DetectHostbitMatchIsnotset (Packet *p, const DetectHostbitsData *fd) +static int DetectHostbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) { int r = 0; - switch (fd->dir) { - case DETECT_HOSTBITS_DIR_SRC: + switch (fd->tracker) { + case DETECT_XBITS_TRACK_IPSRC: if (p->host_src == NULL) { p->host_src = HostLookupHostFromHash(&p->src); if (p->host_src == NULL) @@ -240,11 +238,10 @@ static int DetectHostbitMatchIsnotset (Packet *p, const DetectHostbitsData *fd) } else HostLock(p->host_src); - HostLock(p->host_src); r = HostBitIsnotset(p->host_src,fd->idx); HostUnlock(p->host_src); return r; - case DETECT_HOSTBITS_DIR_DST: + case DETECT_XBITS_TRACK_IPDST: if (p->host_dst == NULL) { p->host_dst = HostLookupHostFromHash(&p->dst); if (p->host_dst == NULL) @@ -252,7 +249,6 @@ static int DetectHostbitMatchIsnotset (Packet *p, const DetectHostbitsData *fd) } else HostLock(p->host_dst); - HostLock(p->host_dst); r = HostBitIsnotset(p->host_dst,fd->idx); HostUnlock(p->host_dst); return r; @@ -268,20 +264,20 @@ static int DetectHostbitMatchIsnotset (Packet *p, const DetectHostbitsData *fd) int DetectHostbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - const DetectHostbitsData *fd = (const DetectHostbitsData *)ctx; + const DetectXbitsData *fd = (const DetectXbitsData *)ctx; if (fd == NULL) return 0; switch (fd->cmd) { - case DETECT_HOSTBITS_CMD_ISSET: + case DETECT_XBITS_CMD_ISSET: return DetectHostbitMatchIsset(p,fd); - case DETECT_HOSTBITS_CMD_ISNOTSET: + case DETECT_XBITS_CMD_ISNOTSET: return DetectHostbitMatchIsnotset(p,fd); - case DETECT_HOSTBITS_CMD_SET: + case DETECT_XBITS_CMD_SET: return DetectHostbitMatchSet(p,fd); - case DETECT_HOSTBITS_CMD_UNSET: + case DETECT_XBITS_CMD_UNSET: return DetectHostbitMatchUnset(p,fd); - case DETECT_HOSTBITS_CMD_TOGGLE: + case DETECT_XBITS_CMD_TOGGLE: return DetectHostbitMatchToggle(p,fd); default: SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd); @@ -293,7 +289,7 @@ int DetectHostbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { - DetectHostbitsData *cd = NULL; + DetectXbitsData *cd = NULL; SigMatch *sm = NULL; uint8_t fb_cmd = 0; uint8_t hb_dir = 0; @@ -330,11 +326,11 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) SCLogInfo("hb_dir_str %s", hb_dir_str); if (strlen(hb_dir_str) > 0) { if (strcmp(hb_dir_str, "src") == 0) - hb_dir = DETECT_HOSTBITS_DIR_SRC; + hb_dir = DETECT_XBITS_TRACK_IPSRC; else if (strcmp(hb_dir_str, "dst") == 0) - hb_dir = DETECT_HOSTBITS_DIR_DST; + hb_dir = DETECT_XBITS_TRACK_IPDST; else if (strcmp(hb_dir_str, "both") == 0) { - hb_dir = DETECT_HOSTBITS_DIR_BOTH; + //hb_dir = DETECT_XBITS_TRACK_IPBOTH; SCLogError(SC_ERR_UNIMPLEMENTED, "'both' not implemented"); goto error; } else { @@ -346,46 +342,47 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) } if (strcmp(fb_cmd_str,"noalert") == 0) { - fb_cmd = DETECT_HOSTBITS_CMD_NOALERT; + fb_cmd = DETECT_XBITS_CMD_NOALERT; } else if (strcmp(fb_cmd_str,"isset") == 0) { - fb_cmd = DETECT_HOSTBITS_CMD_ISSET; + fb_cmd = DETECT_XBITS_CMD_ISSET; } else if (strcmp(fb_cmd_str,"isnotset") == 0) { - fb_cmd = DETECT_HOSTBITS_CMD_ISNOTSET; + fb_cmd = DETECT_XBITS_CMD_ISNOTSET; } else if (strcmp(fb_cmd_str,"set") == 0) { - fb_cmd = DETECT_HOSTBITS_CMD_SET; + fb_cmd = DETECT_XBITS_CMD_SET; } else if (strcmp(fb_cmd_str,"unset") == 0) { - fb_cmd = DETECT_HOSTBITS_CMD_UNSET; + fb_cmd = DETECT_XBITS_CMD_UNSET; } else if (strcmp(fb_cmd_str,"toggle") == 0) { - fb_cmd = DETECT_HOSTBITS_CMD_TOGGLE; + fb_cmd = DETECT_XBITS_CMD_TOGGLE; } else { SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str); goto error; } switch (fb_cmd) { - case DETECT_HOSTBITS_CMD_NOALERT: + case DETECT_XBITS_CMD_NOALERT: if (strlen(fb_name) != 0) goto error; s->flags |= SIG_FLAG_NOALERT; return 0; - case DETECT_HOSTBITS_CMD_ISNOTSET: - case DETECT_HOSTBITS_CMD_ISSET: - case DETECT_HOSTBITS_CMD_SET: - case DETECT_HOSTBITS_CMD_UNSET: - case DETECT_HOSTBITS_CMD_TOGGLE: + case DETECT_XBITS_CMD_ISNOTSET: + case DETECT_XBITS_CMD_ISSET: + case DETECT_XBITS_CMD_SET: + case DETECT_XBITS_CMD_UNSET: + case DETECT_XBITS_CMD_TOGGLE: default: if (strlen(fb_name) == 0) goto error; break; } - cd = SCMalloc(sizeof(DetectHostbitsData)); + cd = SCMalloc(sizeof(DetectXbitsData)); if (unlikely(cd == NULL)) goto error; - cd->idx = VariableNameGetIdx(de_ctx, fb_name, DETECT_HOSTBITS); + cd->idx = VariableNameGetIdx(de_ctx, fb_name, VAR_TYPE_HOST_BIT); cd->cmd = fb_cmd; - cd->dir = hb_dir; + cd->tracker = hb_dir; + cd->type = VAR_TYPE_HOST_BIT; SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); @@ -400,19 +397,19 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) sm->ctx = (void *)cd; switch (fb_cmd) { - case DETECT_HOSTBITS_CMD_NOALERT: + case DETECT_XBITS_CMD_NOALERT: /* nothing to do */ break; - case DETECT_HOSTBITS_CMD_ISNOTSET: - case DETECT_HOSTBITS_CMD_ISSET: + case DETECT_XBITS_CMD_ISNOTSET: + case DETECT_XBITS_CMD_ISSET: /* checks, so packet list */ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); break; - case DETECT_HOSTBITS_CMD_SET: - case DETECT_HOSTBITS_CMD_UNSET: - case DETECT_HOSTBITS_CMD_TOGGLE: + case DETECT_XBITS_CMD_SET: + case DETECT_XBITS_CMD_UNSET: + case DETECT_XBITS_CMD_TOGGLE: /* modifiers, only run when entire sig has matched */ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); break; @@ -430,7 +427,7 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) void DetectHostbitFree (void *ptr) { - DetectHostbitsData *fd = (DetectHostbitsData *)ptr; + DetectXbitsData *fd = (DetectXbitsData *)ptr; if (fd == NULL) return; @@ -727,7 +724,7 @@ static int HostBitsTestSig04(void) s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; hostbits:isset,fbt; content:\"GET \"; sid:1;)"); - idx = VariableNameGetIdx(de_ctx, "fbt", DETECT_HOSTBITS); + idx = VariableNameGetIdx(de_ctx, "fbt", VAR_TYPE_HOST_BIT); if (s == NULL || idx != 1) { goto end; @@ -922,7 +919,7 @@ static int HostBitsTestSig06(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_HOSTBITS); + idx = VariableNameGetIdx(de_ctx, "myflow", VAR_TYPE_HOST_BIT); gv = p->flow->flowvar; @@ -1028,7 +1025,7 @@ static int HostBitsTestSig07(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_HOSTBITS); + idx = VariableNameGetIdx(de_ctx, "myflow", VAR_TYPE_HOST_BIT); gv = p->flow->flowvar; diff --git a/src/detect-hostbits.h b/src/detect-hostbits.h index 72406cc8eb83..00880b9eb3a5 100644 --- a/src/detect-hostbits.h +++ b/src/detect-hostbits.h @@ -24,23 +24,7 @@ #ifndef __DETECT_HOSTBITS_H__ #define __DETECT_HOSTBITS_H__ -#define DETECT_HOSTBITS_CMD_SET 0 -#define DETECT_HOSTBITS_CMD_TOGGLE 1 -#define DETECT_HOSTBITS_CMD_UNSET 2 -#define DETECT_HOSTBITS_CMD_ISNOTSET 3 -#define DETECT_HOSTBITS_CMD_ISSET 4 -#define DETECT_HOSTBITS_CMD_NOALERT 5 -#define DETECT_HOSTBITS_CMD_MAX 6 - -#define DETECT_HOSTBITS_DIR_SRC 0 -#define DETECT_HOSTBITS_DIR_DST 1 -#define DETECT_HOSTBITS_DIR_BOTH 2 - -typedef struct DetectHostbitsData_ { - uint16_t idx; - uint8_t cmd; - uint8_t dir; -} DetectHostbitsData; +#include "detect-xbits.h" /* prototypes */ void DetectHostbitsRegister (void); diff --git a/src/detect-lua.c b/src/detect-lua.c index 8a957ccac901..5c0e1f6403af 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -831,7 +831,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) goto error; } - uint16_t idx = VariableNameGetIdx(de_ctx, (char *)value, DETECT_FLOWVAR); + uint16_t idx = VariableNameGetIdx(de_ctx, (char *)value, VAR_TYPE_FLOW_VAR); ld->flowvar[ld->flowvars++] = idx; SCLogDebug("script uses flowvar %u with script id %u", idx, ld->flowvars - 1); } @@ -853,7 +853,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) goto error; } - uint16_t idx = VariableNameGetIdx(de_ctx, (char *)value, DETECT_FLOWINT); + uint16_t idx = VariableNameGetIdx(de_ctx, (char *)value, VAR_TYPE_FLOW_INT); ld->flowint[ld->flowints++] = idx; SCLogDebug("script uses flowint %u with script id %u", idx, ld->flowints - 1); } diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 61c98b118c29..dd359feb23e8 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -620,9 +620,9 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec } if (pd->capname != NULL) { if (pd->flags & DETECT_PCRE_CAPTURE_PKT) - pd->capidx = VariableNameGetIdx(de_ctx, (char *)pd->capname, DETECT_PKTVAR); + pd->capidx = VariableNameGetIdx(de_ctx, (char *)pd->capname, VAR_TYPE_PKT_VAR); else if (pd->flags & DETECT_PCRE_CAPTURE_FLOW) - pd->capidx = VariableNameGetIdx(de_ctx, (char *)pd->capname, DETECT_FLOWVAR); + pd->capidx = VariableNameGetIdx(de_ctx, (char *)pd->capname, VAR_TYPE_FLOW_VAR); } SCLogDebug("pd->capname %s", pd->capname); diff --git a/src/detect-xbits.c b/src/detect-xbits.c index 28f05c201f83..a622dbf3302c 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -197,6 +197,7 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) int ov[MAX_SUBSTRINGS]; char fb_cmd_str[16] = "", fb_name[256] = ""; char hb_dir_str[16] = ""; + enum VarTypes var_type = VAR_TYPE_NOT_SET; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 2 && ret != 3 && ret != 4) { @@ -224,12 +225,15 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) } SCLogDebug("hb_dir_str %s", hb_dir_str); if (strlen(hb_dir_str) > 0) { - if (strcmp(hb_dir_str, "ip_src") == 0) + if (strcmp(hb_dir_str, "ip_src") == 0) { hb_dir = DETECT_XBITS_TRACK_IPSRC; - else if (strcmp(hb_dir_str, "ip_dst") == 0) + var_type = VAR_TYPE_HOST_BIT; + } else if (strcmp(hb_dir_str, "ip_dst") == 0) { hb_dir = DETECT_XBITS_TRACK_IPDST; - else if (strcmp(hb_dir_str, "ip_pair") == 0) { + var_type = VAR_TYPE_HOST_BIT; + } else if (strcmp(hb_dir_str, "ip_pair") == 0) { hb_dir = DETECT_XBITS_TRACK_IPPAIR; + var_type = VAR_TYPE_IPPAIR_BIT; } else { // TODO goto error; @@ -276,9 +280,10 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) if (unlikely(cd == NULL)) goto error; - cd->idx = VariableNameGetIdx(de_ctx, fb_name, DETECT_XBITS); + cd->idx = VariableNameGetIdx(de_ctx, fb_name, var_type); cd->cmd = fb_cmd; cd->tracker = hb_dir; + cd->type = var_type; SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); diff --git a/src/detect-xbits.h b/src/detect-xbits.h index e01d8c330a8e..56ba917b8a95 100644 --- a/src/detect-xbits.h +++ b/src/detect-xbits.h @@ -41,6 +41,8 @@ typedef struct DetectXbitsData_ { uint16_t idx; uint8_t cmd; uint8_t tracker; + /** data type: host/ippair/flow used for sig sorting in sigorder */ + enum VarTypes type; } DetectXbitsData; /* prototypes */ diff --git a/src/detect.c b/src/detect.c index e27e57b26dcb..ad0af28c8ac8 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1104,7 +1104,7 @@ static void AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(Packet *p, DetectEn } FlowBit *fb = (FlowBit *) gv; - char *name = VariableIdxGetName(de_ctx, fb->idx, fb->type); + char *name = VariableIdxGetName(de_ctx, fb->idx, VAR_TYPE_FLOW_BIT); if (name != NULL) { p->debuglog_flowbits_names[i] = SCStrdup(name); if (p->debuglog_flowbits_names[i] == NULL) { diff --git a/src/util-var-name.c b/src/util-var-name.c index b50e35c9c46f..91322189780a 100644 --- a/src/util-var-name.c +++ b/src/util-var-name.c @@ -131,11 +131,11 @@ void VariableNameFreeHash(DetectEngineCtx *de_ctx) /** \brief Get a name idx for a name. If the name is already used reuse the idx. * \param name nul terminated string with the name - * \param type variable type (DETECT_FLOWBITS, DETECT_PKTVAR, etc) + * \param type variable type * \retval 0 in case of error - * \retval _ the idx. + * \retval idx the idx or 0 */ -uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, char *name, uint8_t type) +uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, char *name, enum VarTypes type) { uint16_t idx = 0; @@ -170,11 +170,11 @@ uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, char *name, uint8_t type) /** \brief Get a name from the idx. * \param idx index of the variable whose name is to be fetched - * \param type variable type (DETECT_FLOWBITS, DETECT_PKTVAR, etc) + * \param type variable type * \retval NULL in case of error * \retval name of the variable if successful. */ -char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, uint8_t type) +char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, enum VarTypes type) { VariableName *fn = SCMalloc(sizeof(VariableName)); if (unlikely(fn == NULL)) diff --git a/src/util-var-name.h b/src/util-var-name.h index 10bd4165c314..2be142689ae9 100644 --- a/src/util-var-name.h +++ b/src/util-var-name.h @@ -27,8 +27,8 @@ int VariableNameInitHash(DetectEngineCtx *); void VariableNameFreeHash(DetectEngineCtx *); -uint16_t VariableNameGetIdx(DetectEngineCtx *, char *, uint8_t); -char * VariableIdxGetName(DetectEngineCtx *, uint16_t , uint8_t); +uint16_t VariableNameGetIdx(DetectEngineCtx *, char *, enum VarTypes); +char * VariableIdxGetName(DetectEngineCtx *, uint16_t , enum VarTypes); #endif diff --git a/src/util-var.h b/src/util-var.h index 21907227962e..965b36e012d6 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -24,6 +24,26 @@ #ifndef __UTIL_VAR_H__ #define __UTIL_VAR_H__ +enum VarTypes { + VAR_TYPE_NOT_SET, + + VAR_TYPE_PKT_BIT, + VAR_TYPE_PKT_INT, + VAR_TYPE_PKT_VAR, + + VAR_TYPE_FLOW_BIT, + VAR_TYPE_FLOW_INT, + VAR_TYPE_FLOW_VAR, + + VAR_TYPE_HOST_BIT, + VAR_TYPE_HOST_INT, + VAR_TYPE_HOST_VAR, + + VAR_TYPE_IPPAIR_BIT, + VAR_TYPE_IPPAIR_INT, + VAR_TYPE_IPPAIR_VAR, +}; + typedef struct GenericVar_ { uint8_t type; uint16_t idx; From 8e6453faacbdde56dd456eafebcdb4b76316e7ab Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 12:24:03 +0100 Subject: [PATCH 0365/2553] xbits: prepare for non-ippair support --- src/detect-xbits.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/detect-xbits.c b/src/detect-xbits.c index a622dbf3302c..14c3f06503fc 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -155,6 +155,26 @@ static int DetectIPPairbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) return r; } +static int DetectXbitMatchIPPair(Packet *p, const DetectXbitsData *xd) +{ + switch (xd->cmd) { + case DETECT_XBITS_CMD_ISSET: + return DetectIPPairbitMatchIsset(p,xd); + case DETECT_XBITS_CMD_ISNOTSET: + return DetectIPPairbitMatchIsnotset(p,xd); + case DETECT_XBITS_CMD_SET: + return DetectIPPairbitMatchSet(p,xd); + case DETECT_XBITS_CMD_UNSET: + return DetectIPPairbitMatchUnset(p,xd); + case DETECT_XBITS_CMD_TOGGLE: + return DetectIPPairbitMatchToggle(p,xd); + default: + SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", xd->cmd); + return 0; + } + return 0; +} + /* * returns 0: no match * 1: match @@ -167,22 +187,13 @@ int DetectXbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S if (fd == NULL) return 0; - switch (fd->cmd) { - case DETECT_XBITS_CMD_ISSET: - return DetectIPPairbitMatchIsset(p,fd); - case DETECT_XBITS_CMD_ISNOTSET: - return DetectIPPairbitMatchIsnotset(p,fd); - case DETECT_XBITS_CMD_SET: - return DetectIPPairbitMatchSet(p,fd); - case DETECT_XBITS_CMD_UNSET: - return DetectIPPairbitMatchUnset(p,fd); - case DETECT_XBITS_CMD_TOGGLE: - return DetectIPPairbitMatchToggle(p,fd); + switch (fd->type) { + case VAR_TYPE_IPPAIR_BIT: + return DetectXbitMatchIPPair(p, (const DetectXbitsData *)fd); + break; default: - SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd); - return 0; + break; } - return 0; } From 57d93cbcfec50ade29350cbfd423dbb4bbf832ec Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 12:28:01 +0100 Subject: [PATCH 0366/2553] hostbits: prepare for xbits integration --- src/detect-hostbits.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 11897bda4130..ff280e2a888f 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -256,37 +256,42 @@ static int DetectHostbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) return 0; } -/* - * returns 0: no match - * 1: match - * -1: error - */ - -int DetectHostbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +int DetectXbitMatchHost(Packet *p, const DetectXbitsData *xd) { - const DetectXbitsData *fd = (const DetectXbitsData *)ctx; - if (fd == NULL) - return 0; - - switch (fd->cmd) { + switch (xd->cmd) { case DETECT_XBITS_CMD_ISSET: - return DetectHostbitMatchIsset(p,fd); + return DetectHostbitMatchIsset(p,xd); case DETECT_XBITS_CMD_ISNOTSET: - return DetectHostbitMatchIsnotset(p,fd); + return DetectHostbitMatchIsnotset(p,xd); case DETECT_XBITS_CMD_SET: - return DetectHostbitMatchSet(p,fd); + return DetectHostbitMatchSet(p,xd); case DETECT_XBITS_CMD_UNSET: - return DetectHostbitMatchUnset(p,fd); + return DetectHostbitMatchUnset(p,xd); case DETECT_XBITS_CMD_TOGGLE: - return DetectHostbitMatchToggle(p,fd); + return DetectHostbitMatchToggle(p,xd); default: - SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd); + SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", xd->cmd); return 0; } return 0; } +/* + * returns 0: no match + * 1: match + * -1: error + */ + +int DetectHostbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + const DetectXbitsData *xd = (const DetectXbitsData *)ctx; + if (xd == NULL) + return 0; + + return DetectXbitMatchHost(p, xd); +} + int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectXbitsData *cd = NULL; From 7b79b9458d0b3f5675618d3bbed5c903b05c36d1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 13:39:23 +0100 Subject: [PATCH 0367/2553] xbits: implement ip_src/ip_dst support Just a wrapper for regular 'hostbits'. --- src/detect-hostbits.h | 2 ++ src/detect-xbits.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/detect-hostbits.h b/src/detect-hostbits.h index 00880b9eb3a5..6e9c7f5f0e42 100644 --- a/src/detect-hostbits.h +++ b/src/detect-hostbits.h @@ -26,6 +26,8 @@ #include "detect-xbits.h" +int DetectXbitMatchHost(Packet *p, const DetectXbitsData *xd); + /* prototypes */ void DetectHostbitsRegister (void); diff --git a/src/detect-xbits.c b/src/detect-xbits.c index 14c3f06503fc..488e3454a4c7 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -30,6 +30,7 @@ #include "flow.h" #include "flow-util.h" #include "detect-xbits.h" +#include "detect-hostbits.h" #include "util-spm.h" #include "detect-engine-sigorder.h" @@ -188,6 +189,9 @@ int DetectXbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S return 0; switch (fd->type) { + case VAR_TYPE_HOST_BIT: + return DetectXbitMatchHost(p, (const DetectXbitsData *)fd); + break; case VAR_TYPE_IPPAIR_BIT: return DetectXbitMatchIPPair(p, (const DetectXbitsData *)fd); break; From fbdcffabc2ebe36f663aeacc431407b3e130ed43 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 17:14:53 +0100 Subject: [PATCH 0368/2553] xbits: expire (first steps) --- src/detect-xbits.c | 22 ++++++++++++++++++---- src/detect-xbits.h | 1 + src/util-var.h | 1 + 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/detect-xbits.c b/src/detect-xbits.c index 488e3454a4c7..d630930e1e20 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -50,10 +50,10 @@ #include "util-debug.h" /* - xbits:set,bitname,track ip_pair + xbits:set,bitname,track ip_pair,expire 60 */ -#define PARSE_REGEX "([a-z]+)(?:,([^,]+))?(?:,(?:track\\s+([^,]+)))" +#define PARSE_REGEX "([a-z]+)" "(?:,\\s*([^,]+))?" "(?:,\\s*(?:track\\s+([^,]+)))" "(?:,\\s*(?:expire\\s+([^,]+)))?" static pcre *parse_regex; static pcre_extra *parse_regex_study; @@ -213,10 +213,11 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) char fb_cmd_str[16] = "", fb_name[256] = ""; char hb_dir_str[16] = ""; enum VarTypes var_type = VAR_TYPE_NOT_SET; + int expire = 30; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); - if (ret != 2 && ret != 3 && ret != 4) { - SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for hostbits.", rawstr); + if (ret != 2 && ret != 3 && ret != 4 && ret != 5) { + SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for xbits.", rawstr); return -1; } SCLogDebug("ret %d, %s", ret, rawstr); @@ -254,6 +255,18 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) goto error; } } + + if (ret >= 5) { + char expire_str[16] = ""; + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, expire_str, sizeof(expire_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("expire_str %s", expire_str); + expire = atoi(expire_str); + SCLogDebug("expire %d", expire); + } } } @@ -299,6 +312,7 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) cd->cmd = fb_cmd; cd->tracker = hb_dir; cd->type = var_type; + cd->expire = expire; SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); diff --git a/src/detect-xbits.h b/src/detect-xbits.h index 56ba917b8a95..477aab8c2bda 100644 --- a/src/detect-xbits.h +++ b/src/detect-xbits.h @@ -41,6 +41,7 @@ typedef struct DetectXbitsData_ { uint16_t idx; uint8_t cmd; uint8_t tracker; + uint32_t expire; /** data type: host/ippair/flow used for sig sorting in sigorder */ enum VarTypes type; } DetectXbitsData; diff --git a/src/util-var.h b/src/util-var.h index 965b36e012d6..0cd8c3528b1f 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -54,6 +54,7 @@ typedef struct XBit_ { uint8_t type; /* type, DETECT_XBITS in this case */ uint16_t idx; /* name idx */ GenericVar *next; + uint32_t expire; } XBit; void GenericVarFree(GenericVar *); From ca1f3e68d4b75f88c9b4ef72298c572411bc5051 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 19:07:48 +0100 Subject: [PATCH 0369/2553] ippair: implement xbits expiration --- src/detect-xbits.c | 8 ++-- src/ippair-bit.c | 109 +++++++++++++++++++++++++-------------------- src/ippair-bit.h | 8 ++-- 3 files changed, 68 insertions(+), 57 deletions(-) diff --git a/src/detect-xbits.c b/src/detect-xbits.c index d630930e1e20..09a85a5c73a5 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -104,7 +104,7 @@ static int DetectIPPairbitMatchToggle (Packet *p, const DetectXbitsData *fd) if (pair == NULL) return 0; - IPPairBitToggle(pair,fd->idx); + IPPairBitToggle(pair,fd->idx,p->ts.tv_sec + fd->expire); IPPairRelease(pair); return 1; } @@ -127,7 +127,7 @@ static int DetectIPPairbitMatchSet (Packet *p, const DetectXbitsData *fd) if (pair == NULL) return 0; - IPPairBitSet(pair,fd->idx); + IPPairBitSet(pair, fd->idx, p->ts.tv_sec + fd->expire); IPPairRelease(pair); return 1; } @@ -139,7 +139,7 @@ static int DetectIPPairbitMatchIsset (Packet *p, const DetectXbitsData *fd) if (pair == NULL) return 0; - r = IPPairBitIsset(pair,fd->idx); + r = IPPairBitIsset(pair,fd->idx,p->ts.tv_sec); IPPairRelease(pair); return r; } @@ -151,7 +151,7 @@ static int DetectIPPairbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) if (pair == NULL) return 1; - r = IPPairBitIsnotset(pair,fd->idx); + r = IPPairBitIsnotset(pair,fd->idx,p->ts.tv_sec); IPPairRelease(pair); return r; } diff --git a/src/ippair-bit.c b/src/ippair-bit.c index 5a72288867f1..d24bbf7e7cfe 100644 --- a/src/ippair-bit.c +++ b/src/ippair-bit.c @@ -76,7 +76,7 @@ static XBit *IPPairBitGet(IPPair *h, uint16_t idx) } /* add a flowbit to the flow */ -static void IPPairBitAdd(IPPair *h, uint16_t idx) +static void IPPairBitAdd(IPPair *h, uint16_t idx, uint32_t expire) { XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) { @@ -87,10 +87,15 @@ static void IPPairBitAdd(IPPair *h, uint16_t idx) fb->type = DETECT_XBITS; fb->idx = idx; fb->next = NULL; + fb->expire = expire; GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); GenericVarAppend(&gv, (GenericVar *)fb); IPPairSetStorageById(h, ippair_bit_id, gv); + + // bit already set, lets update it's timer + } else { + fb->expire = expire; } } @@ -107,11 +112,11 @@ static void IPPairBitRemove(IPPair *h, uint16_t idx) } } -void IPPairBitSet(IPPair *h, uint16_t idx) +void IPPairBitSet(IPPair *h, uint16_t idx, uint32_t expire) { XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) { - IPPairBitAdd(h, idx); + IPPairBitAdd(h, idx, expire); } } @@ -123,37 +128,43 @@ void IPPairBitUnset(IPPair *h, uint16_t idx) } } -void IPPairBitToggle(IPPair *h, uint16_t idx) +void IPPairBitToggle(IPPair *h, uint16_t idx, uint32_t expire) { XBit *fb = IPPairBitGet(h, idx); if (fb != NULL) { IPPairBitRemove(h, idx); } else { - IPPairBitAdd(h, idx); + IPPairBitAdd(h, idx, expire); } } -int IPPairBitIsset(IPPair *h, uint16_t idx) +int IPPairBitIsset(IPPair *h, uint16_t idx, uint32_t ts) { - int r = 0; - XBit *fb = IPPairBitGet(h, idx); if (fb != NULL) { - r = 1; + if (fb->expire < ts) { + IPPairBitRemove(h, idx); + return 0; + } + + return 1; } - return r; + return 0; } -int IPPairBitIsnotset(IPPair *h, uint16_t idx) +int IPPairBitIsnotset(IPPair *h, uint16_t idx, uint32_t ts) { - int r = 0; - XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) { - r = 1; + return 1; + } + + if (fb->expire < ts) { + IPPairBitRemove(h, idx); + return 1; } - return r; + return 0; } @@ -168,7 +179,7 @@ static int IPPairBitTest01 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0); + IPPairBitAdd(h, 0, 0); XBit *fb = IPPairBitGet(h,0); if (fb != NULL) @@ -208,7 +219,7 @@ static int IPPairBitTest03 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0); + IPPairBitAdd(h, 0, 30); XBit *fb = IPPairBitGet(h,0); if (fb == NULL) { @@ -241,10 +252,10 @@ static int IPPairBitTest04 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0); - IPPairBitAdd(h, 1); - IPPairBitAdd(h, 2); - IPPairBitAdd(h, 3); + IPPairBitAdd(h, 0,30); + IPPairBitAdd(h, 1,30); + IPPairBitAdd(h, 2,30); + IPPairBitAdd(h, 3,30); XBit *fb = IPPairBitGet(h,0); if (fb != NULL) @@ -265,10 +276,10 @@ static int IPPairBitTest05 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0); - IPPairBitAdd(h, 1); - IPPairBitAdd(h, 2); - IPPairBitAdd(h, 3); + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,1); if (fb != NULL) @@ -289,10 +300,10 @@ static int IPPairBitTest06 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0); - IPPairBitAdd(h, 1); - IPPairBitAdd(h, 2); - IPPairBitAdd(h, 3); + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,2); if (fb != NULL) @@ -313,10 +324,10 @@ static int IPPairBitTest07 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0); - IPPairBitAdd(h, 1); - IPPairBitAdd(h, 2); - IPPairBitAdd(h, 3); + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,3); if (fb != NULL) @@ -337,10 +348,10 @@ static int IPPairBitTest08 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0); - IPPairBitAdd(h, 1); - IPPairBitAdd(h, 2); - IPPairBitAdd(h, 3); + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,0); if (fb == NULL) @@ -370,10 +381,10 @@ static int IPPairBitTest09 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0); - IPPairBitAdd(h, 1); - IPPairBitAdd(h, 2); - IPPairBitAdd(h, 3); + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,1); if (fb == NULL) @@ -403,10 +414,10 @@ static int IPPairBitTest10 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0); - IPPairBitAdd(h, 1); - IPPairBitAdd(h, 2); - IPPairBitAdd(h, 3); + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,2); if (fb == NULL) @@ -436,10 +447,10 @@ static int IPPairBitTest11 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0); - IPPairBitAdd(h, 1); - IPPairBitAdd(h, 2); - IPPairBitAdd(h, 3); + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,3); if (fb == NULL) diff --git a/src/ippair-bit.h b/src/ippair-bit.h index e44c0320a90d..e02f6d42ef6c 100644 --- a/src/ippair-bit.h +++ b/src/ippair-bit.h @@ -32,10 +32,10 @@ void IPPairBitRegisterTests(void); int IPPairHasIPPairBits(IPPair *host); -void IPPairBitSet(IPPair *, uint16_t); +void IPPairBitSet(IPPair *, uint16_t, uint32_t); void IPPairBitUnset(IPPair *, uint16_t); -void IPPairBitToggle(IPPair *, uint16_t); -int IPPairBitIsset(IPPair *, uint16_t); -int IPPairBitIsnotset(IPPair *, uint16_t); +void IPPairBitToggle(IPPair *, uint16_t, uint32_t); +int IPPairBitIsset(IPPair *, uint16_t, uint32_t); +int IPPairBitIsnotset(IPPair *, uint16_t, uint32_t); #endif /* __IPPAIR_BIT_H__ */ From 67dd5c0430dda97c8ba15b9fada525b5eee0acb1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 20:02:19 +0100 Subject: [PATCH 0370/2553] host: implement hostbits/xbits expire --- src/detect-hostbits.c | 16 +++---- src/host-bit.c | 107 +++++++++++++++++++++++------------------- src/host-bit.h | 10 ++-- 3 files changed, 71 insertions(+), 62 deletions(-) diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index ff280e2a888f..3da30a79c799 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -118,7 +118,7 @@ static int DetectHostbitMatchToggle (Packet *p, const DetectXbitsData *fd) else HostLock(p->host_src); - HostBitToggle(p->host_src,fd->idx); + HostBitToggle(p->host_src,fd->idx,p->ts.tv_sec + fd->expire); HostUnlock(p->host_src); break; case DETECT_XBITS_TRACK_IPDST: @@ -130,7 +130,7 @@ static int DetectHostbitMatchToggle (Packet *p, const DetectXbitsData *fd) else HostLock(p->host_dst); - HostBitToggle(p->host_dst,fd->idx); + HostBitToggle(p->host_dst,fd->idx,p->ts.tv_sec + fd->expire); HostUnlock(p->host_dst); break; } @@ -178,7 +178,7 @@ static int DetectHostbitMatchSet (Packet *p, const DetectXbitsData *fd) } else HostLock(p->host_src); - HostBitSet(p->host_src,fd->idx); + HostBitSet(p->host_src,fd->idx,p->ts.tv_sec + fd->expire); HostUnlock(p->host_src); break; case DETECT_XBITS_TRACK_IPDST: @@ -189,7 +189,7 @@ static int DetectHostbitMatchSet (Packet *p, const DetectXbitsData *fd) } else HostLock(p->host_dst); - HostBitSet(p->host_dst,fd->idx); + HostBitSet(p->host_dst,fd->idx, p->ts.tv_sec + fd->expire); HostUnlock(p->host_dst); break; } @@ -208,7 +208,7 @@ static int DetectHostbitMatchIsset (Packet *p, const DetectXbitsData *fd) } else HostLock(p->host_src); - r = HostBitIsset(p->host_src,fd->idx); + r = HostBitIsset(p->host_src,fd->idx, p->ts.tv_sec); HostUnlock(p->host_src); return r; case DETECT_XBITS_TRACK_IPDST: @@ -219,7 +219,7 @@ static int DetectHostbitMatchIsset (Packet *p, const DetectXbitsData *fd) } else HostLock(p->host_dst); - r = HostBitIsset(p->host_dst,fd->idx); + r = HostBitIsset(p->host_dst,fd->idx, p->ts.tv_sec); HostUnlock(p->host_dst); return r; } @@ -238,7 +238,7 @@ static int DetectHostbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) } else HostLock(p->host_src); - r = HostBitIsnotset(p->host_src,fd->idx); + r = HostBitIsnotset(p->host_src,fd->idx, p->ts.tv_sec); HostUnlock(p->host_src); return r; case DETECT_XBITS_TRACK_IPDST: @@ -249,7 +249,7 @@ static int DetectHostbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) } else HostLock(p->host_dst); - r = HostBitIsnotset(p->host_dst,fd->idx); + r = HostBitIsnotset(p->host_dst,fd->idx, p->ts.tv_sec); HostUnlock(p->host_dst); return r; } diff --git a/src/host-bit.c b/src/host-bit.c index ed07e2ffa894..4210c0ca02bb 100644 --- a/src/host-bit.c +++ b/src/host-bit.c @@ -76,7 +76,7 @@ static XBit *HostBitGet(Host *h, uint16_t idx) } /* add a flowbit to the flow */ -static void HostBitAdd(Host *h, uint16_t idx) +static void HostBitAdd(Host *h, uint16_t idx, uint32_t expire) { XBit *fb = HostBitGet(h, idx); if (fb == NULL) { @@ -87,10 +87,15 @@ static void HostBitAdd(Host *h, uint16_t idx) fb->type = DETECT_XBITS; fb->idx = idx; fb->next = NULL; + fb->expire = expire; GenericVar *gv = HostGetStorageById(h, host_bit_id); GenericVarAppend(&gv, (GenericVar *)fb); HostSetStorageById(h, host_bit_id, gv); + + // bit already set, lets update it's time + } else { + fb->expire = expire; } } @@ -107,11 +112,11 @@ static void HostBitRemove(Host *h, uint16_t idx) } } -void HostBitSet(Host *h, uint16_t idx) +void HostBitSet(Host *h, uint16_t idx, uint32_t expire) { XBit *fb = HostBitGet(h, idx); if (fb == NULL) { - HostBitAdd(h, idx); + HostBitAdd(h, idx, expire); } } @@ -123,37 +128,41 @@ void HostBitUnset(Host *h, uint16_t idx) } } -void HostBitToggle(Host *h, uint16_t idx) +void HostBitToggle(Host *h, uint16_t idx, uint32_t expire) { XBit *fb = HostBitGet(h, idx); if (fb != NULL) { HostBitRemove(h, idx); } else { - HostBitAdd(h, idx); + HostBitAdd(h, idx, expire); } } -int HostBitIsset(Host *h, uint16_t idx) +int HostBitIsset(Host *h, uint16_t idx, uint32_t ts) { - int r = 0; - XBit *fb = HostBitGet(h, idx); if (fb != NULL) { - r = 1; + if (fb->expire < ts) { + HostBitRemove(h,idx); + return 0; + } + return 1; } - return r; + return 0; } -int HostBitIsnotset(Host *h, uint16_t idx) +int HostBitIsnotset(Host *h, uint16_t idx, uint32_t ts) { - int r = 0; - XBit *fb = HostBitGet(h, idx); if (fb == NULL) { - r = 1; + return 1; } - return r; + if (fb->expire < ts) { + HostBitRemove(h,idx); + return 1; + } + return 0; } /* TESTS */ @@ -167,7 +176,7 @@ static int HostBitTest01 (void) if (h == NULL) goto end; - HostBitAdd(h, 0); + HostBitAdd(h, 0, 0); XBit *fb = HostBitGet(h,0); if (fb != NULL) @@ -207,7 +216,7 @@ static int HostBitTest03 (void) if (h == NULL) goto end; - HostBitAdd(h, 0); + HostBitAdd(h, 0, 30); XBit *fb = HostBitGet(h,0); if (fb == NULL) { @@ -240,10 +249,10 @@ static int HostBitTest04 (void) if (h == NULL) goto end; - HostBitAdd(h, 0); - HostBitAdd(h, 1); - HostBitAdd(h, 2); - HostBitAdd(h, 3); + HostBitAdd(h, 0, 30); + HostBitAdd(h, 1, 30); + HostBitAdd(h, 2, 30); + HostBitAdd(h, 3, 30); XBit *fb = HostBitGet(h,0); if (fb != NULL) @@ -264,10 +273,10 @@ static int HostBitTest05 (void) if (h == NULL) goto end; - HostBitAdd(h, 0); - HostBitAdd(h, 1); - HostBitAdd(h, 2); - HostBitAdd(h, 3); + HostBitAdd(h, 0, 30); + HostBitAdd(h, 1, 30); + HostBitAdd(h, 2, 30); + HostBitAdd(h, 3, 30); XBit *fb = HostBitGet(h,1); if (fb != NULL) @@ -288,10 +297,10 @@ static int HostBitTest06 (void) if (h == NULL) goto end; - HostBitAdd(h, 0); - HostBitAdd(h, 1); - HostBitAdd(h, 2); - HostBitAdd(h, 3); + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); XBit *fb = HostBitGet(h,2); if (fb != NULL) @@ -312,10 +321,10 @@ static int HostBitTest07 (void) if (h == NULL) goto end; - HostBitAdd(h, 0); - HostBitAdd(h, 1); - HostBitAdd(h, 2); - HostBitAdd(h, 3); + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); XBit *fb = HostBitGet(h,3); if (fb != NULL) @@ -336,10 +345,10 @@ static int HostBitTest08 (void) if (h == NULL) goto end; - HostBitAdd(h, 0); - HostBitAdd(h, 1); - HostBitAdd(h, 2); - HostBitAdd(h, 3); + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); XBit *fb = HostBitGet(h,0); if (fb == NULL) @@ -369,10 +378,10 @@ static int HostBitTest09 (void) if (h == NULL) goto end; - HostBitAdd(h, 0); - HostBitAdd(h, 1); - HostBitAdd(h, 2); - HostBitAdd(h, 3); + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); XBit *fb = HostBitGet(h,1); if (fb == NULL) @@ -402,10 +411,10 @@ static int HostBitTest10 (void) if (h == NULL) goto end; - HostBitAdd(h, 0); - HostBitAdd(h, 1); - HostBitAdd(h, 2); - HostBitAdd(h, 3); + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); XBit *fb = HostBitGet(h,2); if (fb == NULL) @@ -435,10 +444,10 @@ static int HostBitTest11 (void) if (h == NULL) goto end; - HostBitAdd(h, 0); - HostBitAdd(h, 1); - HostBitAdd(h, 2); - HostBitAdd(h, 3); + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); XBit *fb = HostBitGet(h,3); if (fb == NULL) diff --git a/src/host-bit.h b/src/host-bit.h index 884ae3b1a580..574ae9b26946 100644 --- a/src/host-bit.h +++ b/src/host-bit.h @@ -32,9 +32,9 @@ void HostBitRegisterTests(void); int HostHasHostBits(Host *host); -void HostBitSet(Host *, uint16_t); +void HostBitSet(Host *, uint16_t, uint32_t); void HostBitUnset(Host *, uint16_t); -void HostBitToggle(Host *, uint16_t); -int HostBitIsset(Host *, uint16_t); -int HostBitIsnotset(Host *, uint16_t); -#endif /* __FLOW_BIT_H__ */ +void HostBitToggle(Host *, uint16_t, uint32_t); +int HostBitIsset(Host *, uint16_t, uint32_t); +int HostBitIsnotset(Host *, uint16_t, uint32_t); +#endif /* __HOST_BIT_H__ */ From f2349e10ad42591b1781593c180773b0b6fbd274 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 21:12:15 +0100 Subject: [PATCH 0371/2553] hosts: consider hostbits/xbits status in timeout Consider the host's xbits expiry status when checking the host for timeout. If a single active non-expired bit is found, the host won't be timeout just yet. --- src/host-bit.c | 15 +++++++++++++++ src/host-bit.h | 1 + src/host-timeout.c | 9 ++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/host-bit.c b/src/host-bit.c index 4210c0ca02bb..7f33f3bca9ee 100644 --- a/src/host-bit.c +++ b/src/host-bit.c @@ -62,6 +62,21 @@ int HostHasHostBits(Host *host) return HostGetStorageById(host, host_bit_id) ? 1 : 0; } +/** \retval 1 host timed out wrt xbits + * \retval 0 host still has active (non-expired) xbits */ +int HostBitsTimedoutCheck(Host *h, struct timeval *ts) +{ + GenericVar *gv = HostGetStorageById(h, host_bit_id); + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_XBITS) { + XBit *xb = (XBit *)gv; + if (xb->expire > (uint32_t)ts->tv_sec) + return 0; + } + } + return 1; +} + /* get the bit with idx from the host */ static XBit *HostBitGet(Host *h, uint16_t idx) { diff --git a/src/host-bit.h b/src/host-bit.h index 574ae9b26946..d4bba11abf5b 100644 --- a/src/host-bit.h +++ b/src/host-bit.h @@ -31,6 +31,7 @@ void HostBitInitCtx(void); void HostBitRegisterTests(void); int HostHasHostBits(Host *host); +int HostBitsTimedoutCheck(Host *h, struct timeval *ts); void HostBitSet(Host *, uint16_t, uint32_t); void HostBitUnset(Host *, uint16_t); diff --git a/src/host-timeout.c b/src/host-timeout.c index a8b08b8d8591..c8be4e05a75e 100644 --- a/src/host-timeout.c +++ b/src/host-timeout.c @@ -26,6 +26,9 @@ #include "detect-engine-tag.h" #include "detect-engine-threshold.h" + +#include "host-bit.h" + #include "reputation.h" uint32_t HostGetSpareCount(void) @@ -51,6 +54,7 @@ static int HostHostTimedOut(Host *h, struct timeval *ts) { int tags = 0; int thresholds = 0; + int vars = 0; /** never prune a host that is used by a packet * we are currently processing in one of the threads */ @@ -71,8 +75,11 @@ static int HostHostTimedOut(Host *h, struct timeval *ts) if (ThresholdHostHasThreshold(h) && ThresholdTimeoutCheck(h, ts) == 0) { thresholds = 1; } + if (HostHasHostBits(h) && HostBitsTimedoutCheck(h, ts) == 0) { + vars = 1; + } - if (tags || thresholds) + if (tags || thresholds || vars) return 0; SCLogDebug("host %p timed out", h); From e8a59250122008277d759c8c12de258a7ca0ed51 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 21:30:12 +0100 Subject: [PATCH 0372/2553] ippair: implement basic timeout check The only user is the xbits subsys, so it's timeout controls all. --- src/ippair-bit.c | 15 +++++++++++++++ src/ippair-bit.h | 3 ++- src/ippair-timeout.c | 15 +++++++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/ippair-bit.c b/src/ippair-bit.c index d24bbf7e7cfe..014b1d9b26d6 100644 --- a/src/ippair-bit.c +++ b/src/ippair-bit.c @@ -62,6 +62,21 @@ int IPPairHasBits(IPPair *ippair) return IPPairGetStorageById(ippair, ippair_bit_id) ? 1 : 0; } +/** \retval 1 ippair timed out wrt xbits + * \retval 0 ippair still has active (non-expired) xbits */ +int IPPairBitsTimedoutCheck(IPPair *h, struct timeval *ts) +{ + GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_XBITS) { + XBit *xb = (XBit *)gv; + if (xb->expire > (uint32_t)ts->tv_sec) + return 0; + } + } + return 1; +} + /* get the bit with idx from the ippair */ static XBit *IPPairBitGet(IPPair *h, uint16_t idx) { diff --git a/src/ippair-bit.h b/src/ippair-bit.h index e02f6d42ef6c..44a0ac469c7e 100644 --- a/src/ippair-bit.h +++ b/src/ippair-bit.h @@ -30,7 +30,8 @@ void IPPairBitInitCtx(void); void IPPairBitRegisterTests(void); -int IPPairHasIPPairBits(IPPair *host); +int IPPairHasBits(IPPair *host); +int IPPairBitsTimedoutCheck(IPPair *h, struct timeval *ts); void IPPairBitSet(IPPair *, uint16_t, uint32_t); void IPPairBitUnset(IPPair *, uint16_t); diff --git a/src/ippair-timeout.c b/src/ippair-timeout.c index d1a6a24e0da4..1225f82511c5 100644 --- a/src/ippair-timeout.c +++ b/src/ippair-timeout.c @@ -23,6 +23,7 @@ #include "suricata-common.h" #include "ippair.h" +#include "ippair-bit.h" uint32_t IPPairGetSpareCount(void) { @@ -43,14 +44,24 @@ uint32_t IPPairGetActiveCount(void) * \retval 0 not timed out just yet * \retval 1 fully timed out, lets kill it */ -static int IPPairIPPairTimedOut(IPPair *h, struct timeval *ts) +static int IPPairTimedOut(IPPair *h, struct timeval *ts) { + int vars = 0; + /** never prune a ippair that is used by a packet * we are currently processing in one of the threads */ if (SC_ATOMIC_GET(h->use_cnt) > 0) { return 0; } + if (IPPairHasBits(h) && IPPairBitsTimedoutCheck(h, ts) == 0) { + vars = 1; + } + + if (vars) { + return 0; + } + SCLogDebug("ippair %p timed out", h); return 1; } @@ -80,7 +91,7 @@ static uint32_t IPPairHashRowTimeout(IPPairHashRow *hb, IPPair *h, struct timeva /* check if the ippair is fully timed out and * ready to be discarded. */ - if (IPPairIPPairTimedOut(h, ts) == 1) { + if (IPPairTimedOut(h, ts) == 1) { /* remove from the hash */ if (h->hprev != NULL) h->hprev->hnext = h->hnext; From ab7882fbf38a9e0dcf796f8554e1f847072d7b46 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 22:19:11 +0100 Subject: [PATCH 0373/2553] ippair: handle timeouts in the flow manager Like host and defrag, handle timeouts of ippair in the first flow manager thread. --- src/flow-manager.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/flow-manager.c b/src/flow-manager.c index b52220d153b5..70300b95cd04 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -63,6 +63,7 @@ #include "host-timeout.h" #include "defrag-timeout.h" +#include "ippair-timeout.h" #include "output-flow.h" @@ -634,6 +635,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) DefragTimeoutHash(&ts); //uint32_t hosts_pruned = HostTimeoutHash(&ts); + IPPairTimeoutHash(&ts); } /* SCPerfCounterAddUI64(flow_mgr_host_prune, th_v->sc_perf_pca, (uint64_t)hosts_pruned); From 00d62986666a4f78552de6157278b7399b7ca878 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Dec 2014 22:43:21 +0100 Subject: [PATCH 0374/2553] host: handle timeout Set expiration for regular hostbits keyword. --- src/detect-hostbits.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 3da30a79c799..a940897b9afa 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -388,6 +388,7 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) cd->cmd = fb_cmd; cd->tracker = hb_dir; cd->type = VAR_TYPE_HOST_BIT; + cd->expire = 300; SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); From ca60d8c370ca3675d840b07f35a70095b966f0ff Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 16 Apr 2015 11:44:55 -0600 Subject: [PATCH 0375/2553] ParseSizeString - don't abort on unknown unit type. --- src/util-misc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/util-misc.c b/src/util-misc.c index fdb3eaeae8c8..b72aa05e8e6b 100644 --- a/src/util-misc.c +++ b/src/util-misc.c @@ -125,8 +125,9 @@ static int ParseSizeString(const char *size, double *res) } else if (strcasecmp(str2, "gb") == 0) { *res *= 1024 * 1024 * 1024; } else { - /* not possible */ - BUG_ON(1); + /* Bad unit. */ + retval = -1; + goto end; } } @@ -1118,6 +1119,11 @@ int UtilMiscParseSizeStringTest01(void) goto error; } + /* Should fail on unknown units. */ + if (ParseSizeString("32eb", &result) > 0) { + goto error; + } + return 1; error: return 0; From da88b3b787f67d83610b0f9e2fee9580d2a15de1 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 16 Apr 2015 14:46:24 -0600 Subject: [PATCH 0376/2553] DetectSidSetup - safer stripping of quotes. Discovered by AFL when using a rule like: alert tcp any any -> any any (content:"ABC"; sid:";) would result in a negative array index. --- src/detect-sid.c | 96 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 7 deletions(-) diff --git a/src/detect-sid.c b/src/detect-sid.c index 1c7666bb17d2..7e5e1b1f851e 100644 --- a/src/detect-sid.c +++ b/src/detect-sid.c @@ -25,10 +25,14 @@ #include "suricata-common.h" #include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" #include "util-debug.h" #include "util-error.h" +#include "util-unittest.h" static int DetectSidSetup (DetectEngineCtx *, Signature *, char *); +static void DetectSidRegisterTests(void); void DetectSidRegister (void) { @@ -38,7 +42,7 @@ void DetectSidRegister (void) sigmatch_table[DETECT_SID].Match = NULL; sigmatch_table[DETECT_SID].Setup = DetectSidSetup; sigmatch_table[DETECT_SID].Free = NULL; - sigmatch_table[DETECT_SID].RegisterTests = NULL; + sigmatch_table[DETECT_SID].RegisterTests = DetectSidRegisterTests; } static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, char *sidstr) @@ -46,13 +50,15 @@ static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, char *sidstr) char *str = sidstr; char dubbed = 0; - /* strip "'s */ - if (sidstr[0] == '\"' && sidstr[strlen(sidstr)-1] == '\"') { - str = SCStrdup(sidstr+1); - if (unlikely(str == NULL)) + /* Strip leading and trailing "s. */ + if (sidstr[0] == '\"') { + str = SCStrdup(sidstr + 1); + if (unlikely(str == NULL)) { return -1; - - str[strlen(sidstr)-2] = '\0'; + } + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } @@ -81,3 +87,79 @@ static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, char *sidstr) return -1; } +#ifdef UNITTESTS + +static int SidTestParse01(void) +{ + int result = 0; + Signature *s = NULL; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + s = DetectEngineAppendSig(de_ctx, + "alert tcp 1.2.3.4 any -> any any (sid:1; gid:1;)"); + if (s == NULL || s->id != 1) + goto end; + + result = 1; + +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +static int SidTestParse02(void) +{ + int result = 0; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + if (DetectEngineAppendSig(de_ctx, + "alert tcp 1.2.3.4 any -> any any (sid:a; gid:1;)") != NULL) + goto end; + + result = 1; + +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +static int SidTestParse03(void) +{ + int result = 0; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + if (DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"ABC\"; sid:\";)") != NULL) + goto end; + + result = 1; +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +#endif + +/** + * \brief Register DetectSid unit tests. + */ +static void DetectSidRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SidTestParse01", SidTestParse01, 1); + UtRegisterTest("SidTestParse02", SidTestParse02, 1); + UtRegisterTest("SidTestParse03", SidTestParse03, 1); +#endif /* UNITTESTS */ +} From 8911b04077797b11441598b10817e564b8be3479 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 16 Apr 2015 15:33:32 -0600 Subject: [PATCH 0377/2553] DetectGidSet - safer stripping of quotes. Discovered by AFL when using a rule like: alert tcp any any -> any any (content:"ABC"; gid:";) resulting a negative array index. --- src/detect-gid.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/detect-gid.c b/src/detect-gid.c index b25dc0157957..3a36d7bc65b2 100644 --- a/src/detect-gid.c +++ b/src/detect-gid.c @@ -71,13 +71,15 @@ static int DetectGidSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) char *str = rawstr; char dubbed = 0; - /* strip "'s */ - if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') { - str = SCStrdup(rawstr+1); - if (unlikely(str == NULL)) + /* Strip leading and trailing "s. */ + if (rawstr[0] == '\"') { + str = SCStrdup(rawstr + 1); + if (unlikely(str == NULL)) { return -1; - - str[strlen(rawstr)-2] = '\0'; + } + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\"'; + } dubbed = 1; } @@ -160,6 +162,31 @@ static int GidTestParse02 (void) DetectEngineCtxFree(de_ctx); return result; } + +/** + * \test Test a gid consisting of a single quote. + * + * \retval 1 on succces + * \retval 0 on failure + */ +static int GidTestParse03 (void) +{ + int result = 0; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + if (DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"ABC\"; gid:\";)") != NULL) + goto end; + + result = 1; +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} #endif /* UNITTESTS */ /** @@ -170,5 +197,6 @@ void GidRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("GidTestParse01", GidTestParse01, 1); UtRegisterTest("GidTestParse02", GidTestParse02, 1); + UtRegisterTest("GidTestParse03", GidTestParse03, 1); #endif /* UNITTESTS */ } From 1f9d9256e70bec590304c041eda2e258431f0760 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 16 Apr 2015 15:56:51 -0600 Subject: [PATCH 0378/2553] spelling - dubbed -> duped (for duplicate) --- src/detect-gid.c | 8 ++++---- src/detect-sid.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/detect-gid.c b/src/detect-gid.c index 3a36d7bc65b2..f63ea28a7405 100644 --- a/src/detect-gid.c +++ b/src/detect-gid.c @@ -69,7 +69,7 @@ void DetectGidRegister (void) static int DetectGidSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { char *str = rawstr; - char dubbed = 0; + char duped = 0; /* Strip leading and trailing "s. */ if (rawstr[0] == '\"') { @@ -80,7 +80,7 @@ static int DetectGidSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) if (strlen(str) && str[strlen(str) - 1] == '\"') { str[strlen(str) - 1] = '\"'; } - dubbed = 1; + duped = 1; } unsigned long gid = 0; @@ -98,12 +98,12 @@ static int DetectGidSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) s->gid = (uint32_t)gid; - if (dubbed) + if (duped) SCFree(str); return 0; error: - if (dubbed) + if (duped) SCFree(str); return -1; } diff --git a/src/detect-sid.c b/src/detect-sid.c index 7e5e1b1f851e..a3ed34031535 100644 --- a/src/detect-sid.c +++ b/src/detect-sid.c @@ -48,7 +48,7 @@ void DetectSidRegister (void) static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, char *sidstr) { char *str = sidstr; - char dubbed = 0; + char duped = 0; /* Strip leading and trailing "s. */ if (sidstr[0] == '\"') { @@ -59,7 +59,7 @@ static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, char *sidstr) if (strlen(str) && str[strlen(str) - 1] == '\"') { str[strlen(str) - 1] = '\0'; } - dubbed = 1; + duped = 1; } unsigned long id = 0; @@ -77,12 +77,12 @@ static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, char *sidstr) s->id = (uint32_t)id; - if (dubbed) + if (duped) SCFree(str); return 0; error: - if (dubbed) + if (duped) SCFree(str); return -1; } From 568635c2e142004cd6cb7a4a55618e96fc823288 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Tue, 7 Apr 2015 17:04:52 +0300 Subject: [PATCH 0379/2553] Reject ICMP traffic, not only TCP/UDP --- src/respond-reject.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/respond-reject.c b/src/respond-reject.c index 42aabbaa816a..ea756d7e720e 100644 --- a/src/respond-reject.c +++ b/src/respond-reject.c @@ -70,18 +70,14 @@ TmEcode RespondRejectFunc(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq if (PKT_IS_IPV4(p)) { if (PKT_IS_TCP(p)) { ret = RejectSendIPv4TCP(tv, p, data); - } else if(PKT_IS_UDP(p)) { - ret = RejectSendIPv4ICMP(tv, p, data); } else { - return TM_ECODE_OK; + ret = RejectSendIPv4ICMP(tv, p, data); } } else if (PKT_IS_IPV6(p)) { if (PKT_IS_TCP(p)) { ret = RejectSendIPv6TCP(tv, p, data); - } else if(PKT_IS_UDP(p)){ - ret = RejectSendIPv6ICMP(tv, p, data); } else { - return TM_ECODE_OK; + ret = RejectSendIPv6ICMP(tv, p, data); } } else { /* we're only supporting IPv4 and IPv6 */ From d98060410cec5fd1793a6eca056cc53577033630 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 16 Jan 2015 10:12:55 +0100 Subject: [PATCH 0380/2553] list keywords: restore 2.0 similar output Unset was previously displayed if the application layer was not set. Code before this patch was displaying '(null)' which is not user friendly. --- src/detect.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect.c b/src/detect.c index ad0af28c8ac8..648c69ef7e01 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4902,8 +4902,8 @@ static inline void SigMultilinePrint(int i, char *prefix) void SigTableList(const char *keyword) { size_t size = sizeof(sigmatch_table) / sizeof(SigTableElmt); - size_t i; + char *proto_name; if (keyword == NULL) { printf("=====Supported keywords=====\n"); @@ -4928,8 +4928,8 @@ void SigTableList(const char *keyword) printf("%s", sigmatch_table[i].desc); } /* Build feature */ - printf(";%s;", - AppLayerGetProtoName(sigmatch_table[i].alproto)); + proto_name = AppLayerGetProtoName(sigmatch_table[i].alproto); + printf(";%s;", proto_name ? proto_name : "Unset"); PrintFeatureList(sigmatch_table[i].flags, ':'); printf(";"); if (sigmatch_table[i].url) { From 6f5c4c12e1a6e16fbe7d9eece6e8f1504647e952 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 16 Jan 2015 14:37:41 +0100 Subject: [PATCH 0381/2553] list keywords: fix regression on app layer name It was not anymore displayed. --- src/util-running-modes.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util-running-modes.c b/src/util-running-modes.c index 8f30044dc7d2..07aeffef5f5a 100644 --- a/src/util-running-modes.c +++ b/src/util-running-modes.c @@ -24,11 +24,14 @@ #include "config.h" #include "app-layer-detect-proto.h" #include "app-layer.h" +#include "app-layer-parser.h" #include "util-cuda.h" #include "util-unittest.h" int ListKeywords(const char *keyword_info) { + MpmTableSetup(); + AppLayerSetup(); SigTableSetup(); /* load the rule keywords */ SigTableList(keyword_info); exit(EXIT_SUCCESS); From f35001a614c92e90c6bdee82cce5be80178cd237 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 27 Jan 2015 21:22:29 +0100 Subject: [PATCH 0382/2553] util-running-mode: setup config file Without that we get warning message. --- src/util-running-modes.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util-running-modes.c b/src/util-running-modes.c index 07aeffef5f5a..8ad5a1eea862 100644 --- a/src/util-running-modes.c +++ b/src/util-running-modes.c @@ -27,9 +27,13 @@ #include "app-layer-parser.h" #include "util-cuda.h" #include "util-unittest.h" +#include "util-debug.h" +#include "conf-yaml-loader.h" int ListKeywords(const char *keyword_info) { + if (ConfYamlLoadFile(DEFAULT_CONF_FILE) != -1) + SCLogLoadConfig(0, 0); MpmTableSetup(); AppLayerSetup(); SigTableSetup(); /* load the rule keywords */ @@ -39,6 +43,8 @@ int ListKeywords(const char *keyword_info) int ListAppLayerProtocols() { + if (ConfYamlLoadFile(DEFAULT_CONF_FILE) != -1) + SCLogLoadConfig(0, 0); MpmTableSetup(); AppLayerSetup(); AppLayerListSupportedProtocols(); From 48971afdfb8f8400956a9f11867005ef8e0ad470 Mon Sep 17 00:00:00 2001 From: David Maciejak Date: Sun, 8 Feb 2015 10:27:03 +0800 Subject: [PATCH 0383/2553] Fix Unit ID check --- src/app-layer-modbus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 873423184ae6..6442b821e9ce 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -451,8 +451,8 @@ static void ModbusCheckHeader(ModbusState *modbus, ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_LENGTH); /* Check Unit Identifier field that is not in invalid range */ - if ((header->length > MODBUS_MIN_INVALID_UNIT_ID) && - (header->length < MODBUS_MAX_INVALID_UNIT_ID) ) + if ((header->unitId > MODBUS_MIN_INVALID_UNIT_ID) && + (header->unitId < MODBUS_MAX_INVALID_UNIT_ID) ) ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_UNIT_IDENTIFIER); SCReturn; From 915eb992cafa68af04addc039da273603e457255 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 23 Apr 2015 09:53:20 +0200 Subject: [PATCH 0384/2553] app-layer: update protocol detection tests AppLayerTest09, AppLayerTest10 and AppLayerTest11 depended on a max protocol detection pattern size of < 17. Update the tests to pass one extra byte to the app layer. This makes the protocol detection code flag the session as 'proto detection completed' again. --- src/app-layer.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 65bf8e8730b8..806191cc3d66 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -2822,7 +2822,7 @@ static int AppLayerTest09(void) /* full request */ uint8_t request2[] = { - 0x44, 0x44, 0x45, 0x20, 0x2f, 0x69, 0x6e, 0x64 }; + 0x44, 0x44, 0x45, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0xff }; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(9); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2889,7 +2889,7 @@ static int AppLayerTest09(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; @@ -2914,7 +2914,7 @@ static int AppLayerTest09(void) /* response ack */ p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(17); + p->tcph->th_seq = htonl(18); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; @@ -3054,7 +3054,7 @@ static int AppLayerTest10(void) /* full request */ uint8_t request1[] = { 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, - 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64 }; + 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0xff }; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -3079,7 +3079,7 @@ static int AppLayerTest10(void) } /* response - request ack */ - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; @@ -3145,7 +3145,7 @@ static int AppLayerTest10(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; @@ -3170,7 +3170,7 @@ static int AppLayerTest10(void) /* response ack */ p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(17); + p->tcph->th_seq = htonl(18); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; @@ -3311,7 +3311,7 @@ static int AppLayerTest11(void) /* full request */ uint8_t request1[] = { 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, - 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64 }; + 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0xff }; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -3336,7 +3336,7 @@ static int AppLayerTest11(void) } /* response - request ack */ - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; @@ -3362,7 +3362,7 @@ static int AppLayerTest11(void) /* full response - request ack */ uint8_t response1[] = { 0x55, 0x74, 0x54, 0x50, }; - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; @@ -3387,7 +3387,7 @@ static int AppLayerTest11(void) /* response ack from request */ p->tcph->th_ack = htonl(5); - p->tcph->th_seq = htonl(17); + p->tcph->th_seq = htonl(18); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; @@ -3451,7 +3451,7 @@ static int AppLayerTest11(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; @@ -3476,7 +3476,7 @@ static int AppLayerTest11(void) /* response ack from request */ p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(17); + p->tcph->th_seq = htonl(18); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; From a7abaf538cf92fb29d84b828fc8360925da0160a Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 16 Apr 2015 16:15:10 +0200 Subject: [PATCH 0385/2553] Added DELETE and PATCH http methods to app-layer-htp.c Added two new http methods to the http decoding done in app-layer-htp.c so that these messages will be decoded as well. --- src/app-layer-htp.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index db72614862e4..4b25f5f27624 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2657,6 +2657,8 @@ static int HTPSetTxDetectState(void *vtx, DetectEngineState *s) static int HTPRegisterPatternsForProtocolDetection(void) { /* toserver */ + + /* GET */ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "GET|20|", 4, 0, STREAM_TOSERVER) < 0) { @@ -2667,6 +2669,8 @@ static int HTPRegisterPatternsForProtocolDetection(void) { return -1; } + + /* PUT */ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "PUT|20|", 4, 0, STREAM_TOSERVER) < 0) { @@ -2677,6 +2681,8 @@ static int HTPRegisterPatternsForProtocolDetection(void) { return -1; } + + /* POST */ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "POST|20|", 5, 0, STREAM_TOSERVER) < 0) { @@ -2687,6 +2693,8 @@ static int HTPRegisterPatternsForProtocolDetection(void) { return -1; } + + /* HEAD */ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "HEAD|20|", 5, 0, STREAM_TOSERVER) < 0) { @@ -2697,6 +2705,8 @@ static int HTPRegisterPatternsForProtocolDetection(void) { return -1; } + + /* TRACE */ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "TRACE|20|", 6, 0, STREAM_TOSERVER) < 0) { @@ -2707,6 +2717,8 @@ static int HTPRegisterPatternsForProtocolDetection(void) { return -1; } + + /* OPTIONS */ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "OPTIONS|20|", 8, 0, STREAM_TOSERVER) < 0) { @@ -2717,6 +2729,8 @@ static int HTPRegisterPatternsForProtocolDetection(void) { return -1; } + + /* CONNECT */ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "CONNECT|20|", 8, 0, STREAM_TOSERVER) < 0) { @@ -2728,6 +2742,30 @@ static int HTPRegisterPatternsForProtocolDetection(void) return -1; } + /* DELETE */ + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "DELETE|20|", 7, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "DELETE|09|", 7, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + + /* PATCH */ + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "PATCH|20|", 6, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "PATCH|09|", 6, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + /* toclient */ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "HTTP/0.9", 8, 0, STREAM_TOCLIENT) < 0) From 7a9e963619a905b59378b4a5de653216182fff25 Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 16 Apr 2015 22:44:36 +0200 Subject: [PATCH 0386/2553] Added http methods for webdav (rfc4918). Included the following methods to app-layer-htp.c: - PROPFIND - PROPPATCH - MKCOL - COPY - MOVE - LOCK - UNLOCK --- src/app-layer-htp.c | 85 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 4b25f5f27624..73b11ad0e767 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2766,6 +2766,91 @@ static int HTPRegisterPatternsForProtocolDetection(void) return -1; } + /* WEBDAV METHODS (rfc4918) */ + /* PROPFIND */ + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "PROPFIND|20|", 9, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "PROPFIND|09|", 9, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + + /* PROPPATCH */ + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "PROPPATCH|20|", 10, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "PATCH|09|", 10, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + + /* MKCOL */ + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "MKCOL|20|", 6, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "MKCOL|09|", 6, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + + /* COPY */ + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "COPY|20|", 5, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "COPY|09|", 5, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + + /* MOVE */ + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "MOVE|20|", 5, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "MOVE|09|", 5, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + + /* LOCK */ + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "LOCK|20|", 5, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "LOCK|09|", 5, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + + /* UNLOCK */ + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "UNLOCK|20|", 7, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, + "UNLOCK|09|", 7, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + /* toclient */ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "HTTP/0.9", 8, 0, STREAM_TOCLIENT) < 0) From 3b26b07963df9ae8e67a0257fe8c0af1112caffb Mon Sep 17 00:00:00 2001 From: maxtors Date: Fri, 17 Apr 2015 10:03:24 +0200 Subject: [PATCH 0387/2553] Reworked pattern registration structure and feedback issues. 1) Reworked pattern registration for http methods and versions. Instead of being a manual and verbose action of adding one and one http method with N-amount if prefix spacings and the same for HTTP versions (eg. HTTP/1.1) i moved it all to be loop based actions reading values from char arrays. In the future all that is needed is to add new methods to the arrays and they will be added as a pattern. 2) Modified pattern registration after feedback. Changed variable used in snprintf for http method registration Should have been size of dest buffer at not another var (catsize) that i had created. Also removed this variable. Fixed a typo in the comment for registering http versions. TO_CIENT -> TO_CLIENT. --- src/app-layer-htp.c | 246 +++++++------------------------------------- 1 file changed, 37 insertions(+), 209 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 73b11ad0e767..af313587bbfd 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2656,218 +2656,46 @@ static int HTPSetTxDetectState(void *vtx, DetectEngineState *s) static int HTPRegisterPatternsForProtocolDetection(void) { - /* toserver */ - - /* GET */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "GET|20|", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "GET|09|", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* PUT */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "PUT|20|", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "PUT|09|", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* POST */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "POST|20|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "POST|09|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* HEAD */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "HEAD|20|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "HEAD|09|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* TRACE */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "TRACE|20|", 6, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "TRACE|09|", 6, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* OPTIONS */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "OPTIONS|20|", 8, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "OPTIONS|09|", 8, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* CONNECT */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "CONNECT|20|", 8, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "CONNECT|09|", 8, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* DELETE */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "DELETE|20|", 7, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "DELETE|09|", 7, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* PATCH */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "PATCH|20|", 6, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "PATCH|09|", 6, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* WEBDAV METHODS (rfc4918) */ - /* PROPFIND */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "PROPFIND|20|", 9, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "PROPFIND|09|", 9, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* PROPPATCH */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "PROPPATCH|20|", 10, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "PATCH|09|", 10, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* MKCOL */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "MKCOL|20|", 6, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "MKCOL|09|", 6, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* COPY */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "COPY|20|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "COPY|09|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* MOVE */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "MOVE|20|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "MOVE|09|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* LOCK */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "LOCK|20|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "LOCK|09|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /* UNLOCK */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "UNLOCK|20|", 7, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "UNLOCK|09|", 7, 0, STREAM_TOSERVER) < 0) - { - return -1; + char *methods[] = { "GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS", + "CONNECT", "DELETE", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL", + "COPY", "MOVE", "LOCK", "UNLOCK", NULL}; + char *spacings[] = { "|20|", "|09|", NULL }; + char *versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", NULL }; + + uint methods_pos; + uint spacings_pos; + uint versions_pos; + int register_result; + char method_buffer[32] = ""; + + // Loop through all the methods ands spacings and register the patterns + for (methods_pos = 0; methods[methods_pos]; methods_pos++) { + for (spacings_pos = 0; spacings[spacings_pos]; spacings_pos++) { + + // Combine the method name and the spacing + snprintf(method_buffer, sizeof(method_buffer), "%s%s", methods[methods_pos], spacings[spacings_pos]); + + // Register the new method+spacing pattern + // 3 is subtracted from the length since the spacing is hex typed as |xx| + // but the pattern matching should only be one char. + register_result = AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, + ALPROTO_HTTP, method_buffer, strlen(method_buffer)-3, 0, STREAM_TOSERVER); + if (register_result < 0) { + return -1; + } + } } - /* toclient */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "HTTP/0.9", 8, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "HTTP/1.0", 8, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "HTTP/1.1", 8, 0, STREAM_TOCLIENT) < 0) - { - return -1; + // Loop through all the http verions patterns that are TO_CLIENT + for (versions_pos = 0; versions[versions_pos]; versions_pos++) { + register_result = AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, + ALPROTO_HTTP, versions[versions_pos], strlen(versions[versions_pos]), + 0, STREAM_TOCLIENT); + if (register_result < 0) { + return -1; + } } - + return 0; } From e7658fd4f474323df7451cb6dfb516342aa0ae48 Mon Sep 17 00:00:00 2001 From: maxtors Date: Fri, 17 Apr 2015 10:37:21 +0200 Subject: [PATCH 0388/2553] Added new WebDAV http methods. Added more WebDAV functions. A complete list of what http methods libhtp can handle can be found at: https://github.com/OISF/libhtp/blob/0.5.x/htp/htp_core.h#L260. So now the methods array reflects these available functions. The comments have also been changed to reflect the desired style. --- src/app-layer-htp.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index af313587bbfd..1c1380bb1200 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2658,7 +2658,9 @@ static int HTPRegisterPatternsForProtocolDetection(void) { char *methods[] = { "GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS", "CONNECT", "DELETE", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL", - "COPY", "MOVE", "LOCK", "UNLOCK", NULL}; + "COPY", "MOVE", "LOCK", "UNLOCK", "CHECKOUT", "UNCHECKOUT", "CHECKIN", + "UPDATE", "LABEL", "REPORT", "MKWORKSPACE", "MKACTIVITY", "MERGE", + "INVALID", "VERSION-CONTROL", "BASELINE-CONTROL", NULL}; char *spacings[] = { "|20|", "|09|", NULL }; char *versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", NULL }; @@ -2668,16 +2670,17 @@ static int HTPRegisterPatternsForProtocolDetection(void) int register_result; char method_buffer[32] = ""; - // Loop through all the methods ands spacings and register the patterns + /* Loop through all the methods ands spacings and register the patterns */ for (methods_pos = 0; methods[methods_pos]; methods_pos++) { for (spacings_pos = 0; spacings[spacings_pos]; spacings_pos++) { - // Combine the method name and the spacing + /* Combine the method name and the spacing */ snprintf(method_buffer, sizeof(method_buffer), "%s%s", methods[methods_pos], spacings[spacings_pos]); - // Register the new method+spacing pattern - // 3 is subtracted from the length since the spacing is hex typed as |xx| - // but the pattern matching should only be one char. + /* Register the new method+spacing pattern + * 3 is subtracted from the length since the spacing is hex typed as |xx| + * but the pattern matching should only be one char + */ register_result = AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, method_buffer, strlen(method_buffer)-3, 0, STREAM_TOSERVER); if (register_result < 0) { @@ -2686,7 +2689,7 @@ static int HTPRegisterPatternsForProtocolDetection(void) } } - // Loop through all the http verions patterns that are TO_CLIENT + /* Loop through all the http verions patterns that are TO_CLIENT */ for (versions_pos = 0; versions[versions_pos]; versions_pos++) { register_result = AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, versions[versions_pos], strlen(versions[versions_pos]), From 643c30f67f887c80868b817d021c01446b219c8e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 23 Apr 2015 09:32:01 +0200 Subject: [PATCH 0389/2553] threading: add missing locks to threading storage Lock threading root lock when walking or updating the threading storage for 'ThreadVars' objects. --- src/tm-threads.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index 343b252e320b..f7f2f2382e2e 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1420,6 +1420,7 @@ void TmThreadDisableReceiveThreads(void) ThreadVars *tv = NULL; +again: SCMutexLock(&tv_root_lock); /* all receive threads are part of packet processing threads */ @@ -1453,8 +1454,11 @@ void TmThreadDisableReceiveThreads(void) if (!(strlen(tv->inq->name) == strlen("packetpool") && strcasecmp(tv->inq->name, "packetpool") == 0)) { PacketQueue *q = &trans_q[tv->inq->id]; - while (q->len != 0) { + if (q->len != 0) { + SCMutexUnlock(&tv_root_lock); + /* don't sleep while holding a lock */ usleep(1000); + goto again; } } } @@ -1508,6 +1512,7 @@ void TmThreadDisablePacketThreads(void) ThreadVars *tv = NULL; +again: SCMutexLock(&tv_root_lock); /* all receive threads are part of packet processing threads */ @@ -1525,8 +1530,11 @@ void TmThreadDisablePacketThreads(void) if (!(strlen(tv->inq->name) == strlen("packetpool") && strcasecmp(tv->inq->name, "packetpool") == 0)) { PacketQueue *q = &trans_q[tv->inq->id]; - while (q->len != 0) { + if (q->len != 0) { + SCMutexUnlock(&tv_root_lock); + /* don't sleep while holding a lock */ usleep(1000); + goto again; } } } @@ -1655,6 +1663,7 @@ void TmThreadClearThreadsFamily(int family) if ((family < 0) || (family >= TVT_MAX)) return; + SCMutexLock(&tv_root_lock); tv = tv_root[family]; while (tv) { @@ -1663,6 +1672,7 @@ void TmThreadClearThreadsFamily(int family) TmThreadFree(ptv); } tv_root[family] = NULL; + SCMutexUnlock(&tv_root_lock); } /** @@ -1812,6 +1822,7 @@ void TmThreadContinueThreads() ThreadVars *tv = NULL; int i = 0; + SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { @@ -1819,6 +1830,7 @@ void TmThreadContinueThreads() tv = tv->next; } } + SCMutexUnlock(&tv_root_lock); return; } @@ -1845,6 +1857,7 @@ void TmThreadPauseThreads() TmThreadsListThreads(); + SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { @@ -1852,6 +1865,7 @@ void TmThreadPauseThreads() tv = tv->next; } } + SCMutexUnlock(&tv_root_lock); return; } @@ -1895,6 +1909,7 @@ void TmThreadCheckThreadState(void) ThreadVars *tv = NULL; int i = 0; + SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; @@ -1904,13 +1919,13 @@ void TmThreadCheckThreadState(void) pthread_join(tv->t, NULL); if ((tv_aof & THV_ENGINE_EXIT) || (tv->aof & THV_ENGINE_EXIT)) { EngineKill(); - return; + goto end; } else { /* if the engine kill-stop has been received by now, chuck * restarting and return to kill the engine */ if ((suricata_ctl_flags & SURICATA_KILL) || (suricata_ctl_flags & SURICATA_STOP)) { - return; + goto end; } TmThreadRestartThread(tv); } @@ -1918,7 +1933,8 @@ void TmThreadCheckThreadState(void) tv = tv->next; } } - +end: + SCMutexUnlock(&tv_root_lock); return; } @@ -1937,6 +1953,7 @@ TmEcode TmThreadWaitOnThreadInit(void) uint16_t mgt_num = 0; uint16_t ppt_num = 0; + SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { @@ -1951,11 +1968,13 @@ TmEcode TmThreadWaitOnThreadInit(void) } if (TmThreadsCheckFlag(tv, THV_FAILED)) { + SCMutexUnlock(&tv_root_lock); SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" failed to " "initialize.", tv->name); return TM_ECODE_FAILED; } if (TmThreadsCheckFlag(tv, THV_CLOSED)) { + SCMutexUnlock(&tv_root_lock); SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" closed on " "initialization.", tv->name); return TM_ECODE_FAILED; @@ -1968,6 +1987,7 @@ TmEcode TmThreadWaitOnThreadInit(void) tv = tv->next; } } + SCMutexUnlock(&tv_root_lock); SCLogNotice("all %"PRIu16" packet processing threads, %"PRIu16" management " "threads initialized, engine started.", ppt_num, mgt_num); From 1884227019183241b538587cb81c668f94a6c834 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Apr 2015 11:21:54 +0200 Subject: [PATCH 0390/2553] autofp: reduce flow storage space requirement Use int16_t instead of a regular int to safe 2 bytes per flow. --- src/flow.h | 2 +- src/tmqh-flow.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/flow.h b/src/flow.h index b772986db6d1..79147112b009 100644 --- a/src/flow.h +++ b/src/flow.h @@ -326,7 +326,7 @@ typedef struct Flow_ SC_ATOMIC_DECLARE(FlowRefCount, use_cnt); /** flow queue id, used with autofp */ - SC_ATOMIC_DECLARE(int, autofp_tmqh_flow_qid); + SC_ATOMIC_DECLARE(int16_t, autofp_tmqh_flow_qid); uint32_t probing_parser_toserver_alproto_masks; uint32_t probing_parser_toclient_alproto_masks; diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index cebd34429f4c..1ec4bec526b9 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -229,7 +229,7 @@ void TmqhOutputFlowFreeCtx(void *ctx) */ void TmqhOutputFlowRoundRobin(ThreadVars *tv, Packet *p) { - int32_t qid = 0; + int16_t qid = 0; TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; @@ -271,7 +271,7 @@ void TmqhOutputFlowRoundRobin(ThreadVars *tv, Packet *p) */ void TmqhOutputFlowActivePackets(ThreadVars *tv, Packet *p) { - int32_t qid = 0; + int16_t qid = 0; TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; @@ -319,7 +319,7 @@ void TmqhOutputFlowActivePackets(ThreadVars *tv, Packet *p) */ void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) { - int32_t qid = 0; + int16_t qid = 0; TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; From deb98fab0c792e4c14a575e3ea86bdc1c9c3e701 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 22 Apr 2015 12:38:52 +0200 Subject: [PATCH 0391/2553] packet pool: init pool for autofp workers as well Introduce a new 'PacketPoolInitEmpty' as these pools will not often need packets. Also, don't double 'destroy' in the main thread. --- src/suricata.c | 1 - src/tm-threads.c | 4 ++++ src/tmqh-packetpool.c | 13 +++++++++++++ src/tmqh-packetpool.h | 1 + 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/suricata.c b/src/suricata.c index 5918708b8a5e..08f84cdc5e21 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2474,7 +2474,6 @@ int main(int argc, char **argv) if (suri.run_mode != RUNMODE_UNIX_SOCKET) { DefragDestroy(); } - PacketPoolDestroy(); MagicDeinit(); TmqhCleanup(); TmModuleRunDeInit(); diff --git a/src/tm-threads.c b/src/tm-threads.c index f7f2f2382e2e..181d04a0b62e 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -402,6 +402,8 @@ void *TmThreadsSlotVar(void *td) char run = 1; TmEcode r = TM_ECODE_OK; + PacketPoolInitEmpty(); + /* Set the thread name */ if (SCSetThreadName(tv->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); @@ -524,6 +526,8 @@ void *TmThreadsSlotVar(void *td) TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); + PacketPoolDestroy(); + s = (TmSlot *)tv->tm_slots; for ( ; s != NULL; s = s->slot_next) { diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index 5ea5c426d355..79103a4a01d9 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -279,6 +279,19 @@ void PacketPoolReturnPacket(Packet *p) } } +void PacketPoolInitEmpty(void) +{ +#ifndef TLS + TmqhPacketPoolInit(); +#endif + + PktPool *my_pool = GetThreadPacketPool(); + + SCMutexInit(&my_pool->return_stack.mutex, NULL); + SCCondInit(&my_pool->return_stack.cond, NULL); + SC_ATOMIC_INIT(my_pool->return_stack.sync_now); +} + void PacketPoolInit(void) { extern intmax_t max_pending_packets; diff --git a/src/tmqh-packetpool.h b/src/tmqh-packetpool.h index f7c8b9fc1e57..6da6fc6aa855 100644 --- a/src/tmqh-packetpool.h +++ b/src/tmqh-packetpool.h @@ -71,6 +71,7 @@ Packet *PacketPoolGetPacket(void); void PacketPoolWait(void); void PacketPoolReturnPacket(Packet *p); void PacketPoolInit(void); +void PacketPoolInitEmpty(void); void PacketPoolDestroy(void); #endif /* __TMQH_PACKETPOOL_H__ */ From 3fbc6ede6b918667ff36d5607dbd8ae372a164da Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Apr 2015 15:47:19 +0200 Subject: [PATCH 0392/2553] suricatasc: allow for longer response times after connect --- scripts/suricatasc/src/suricatasc.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index ea4c62ae6136..f5a7aa7f0b7a 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -146,8 +146,11 @@ def connect(self): else: self.socket.send(bytes(json.dumps({"version": VERSION}), 'iso-8859-1')) - # get return - cmdret = self.json_recv() + ready = select.select([self.socket], [], [], 600) + if ready[0]: + cmdret = self.json_recv() + else: + cmdret = None if cmdret == None: raise SuricataReturnException("Unable to get message from server") From cc38df80747d4789282ce2c5d10168df4b403712 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Apr 2015 15:15:29 +0200 Subject: [PATCH 0393/2553] classification: cleanups Reduce hash table size as regular classification files are usually below 100 in size. It's not performance critical anyway. Convert pcre_get_substring calls to pcre_copy_substring. --- src/util-classification-config.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/util-classification-config.c b/src/util-classification-config.c index db79b7a21340..51d18fdb2e77 100644 --- a/src/util-classification-config.c +++ b/src/util-classification-config.c @@ -81,7 +81,7 @@ int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) int opts = 0; /* init the hash table to be used by the classification config Classtypes */ - de_ctx->class_conf_ht = HashTableInit(4096, SCClassConfClasstypeHashFunc, + de_ctx->class_conf_ht = HashTableInit(128, SCClassConfClasstypeHashFunc, SCClassConfClasstypeHashCompareFunc, SCClassConfClasstypeHashFree); if (de_ctx->class_conf_ht == NULL) { @@ -235,9 +235,9 @@ static char *SCClassConfStringToLowercase(const char *str) */ int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx) { - const char *ct_name = NULL; - const char *ct_desc = NULL; - const char *ct_priority_str = NULL; + char ct_name[64]; + char ct_desc[512]; + char ct_priority_str[16]; int ct_priority = 0; uint8_t ct_id = index; @@ -256,23 +256,23 @@ int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx } /* retrieve the classtype name */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &ct_name); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 1, ct_name, sizeof(ct_name)); if (ret < 0) { - SCLogInfo("pcre_get_substring() failed"); + SCLogInfo("pcre_copy_substring() failed"); goto error; } /* retrieve the classtype description */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &ct_desc); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 2, ct_desc, sizeof(ct_desc)); if (ret < 0) { - SCLogInfo("pcre_get_substring() failed"); + SCLogInfo("pcre_copy_substring() failed"); goto error; } /* retrieve the classtype priority */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &ct_priority_str); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 3, ct_priority_str, sizeof(ct_priority_str)); if (ret < 0) { - SCLogInfo("pcre_get_substring() failed"); + SCLogInfo("pcre_copy_substring() failed"); goto error; } if (ct_priority_str == NULL) { @@ -299,16 +299,9 @@ int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx SCFree(ct_new); } - if (ct_name) SCFree((char *)ct_name); - if (ct_desc) SCFree((char *)ct_desc); - if (ct_priority_str) SCFree((char *)ct_priority_str); return 0; error: - if (ct_name) SCFree((char *)ct_name); - if (ct_desc) SCFree((char *)ct_desc); - if (ct_priority_str) SCFree((char *)ct_priority_str); - return -1; } From e86e1e0282e100e4f476cf46ad9fd367afeb69bf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Apr 2015 15:34:58 +0200 Subject: [PATCH 0394/2553] reference: use pcre_copy_substring --- src/util-reference-config.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/util-reference-config.c b/src/util-reference-config.c index aea8562772c6..30b1a366d1df 100644 --- a/src/util-reference-config.c +++ b/src/util-reference-config.c @@ -229,8 +229,8 @@ static char *SCRConfStringToLowercase(const char *str) */ static int SCRConfAddReference(char *rawstr, DetectEngineCtx *de_ctx) { - const char *system = NULL; - const char *url = NULL; + char system[64]; + char url[1024]; SCRConfReference *ref_new = NULL; SCRConfReference *ref_lookup = NULL; @@ -247,21 +247,23 @@ static int SCRConfAddReference(char *rawstr, DetectEngineCtx *de_ctx) } /* retrieve the reference system */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &system); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 1, system, sizeof(system)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring() failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring() failed"); goto error; } /* retrieve the reference url */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &url); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 2, url, sizeof(url)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring() failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring() failed"); goto error; } /* Create a new instance of the parsed Reference string */ ref_new = SCRConfAllocSCRConfReference(system, url); + if (ref_new == NULL) + goto error; /* Check if the Reference is present in the HashTable. In case it's present * ignore it, as it's a duplicate. If not present, add it to the table */ @@ -275,17 +277,9 @@ static int SCRConfAddReference(char *rawstr, DetectEngineCtx *de_ctx) SCRConfDeAllocSCRConfReference(ref_new); } - /* free the substrings */ - pcre_free_substring(system); - pcre_free_substring(url); return 0; error: - if (system) - pcre_free_substring(system); - if (url) - pcre_free_substring(url); - return -1; } From 22142d9b8b19a83402d3bfc681b1c5f3af017b68 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Apr 2015 16:22:07 +0200 Subject: [PATCH 0395/2553] threshold: cleanups Use pcre_copy_substring in the most common part of threshold rule parsing. Minor other cleanups. --- src/util-threshold-config.c | 40 +++++++++++++++---------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index 92ddce6a3296..25be3d79316b 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -689,9 +689,10 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, uint8_t *ret_parsed_new_action, const char **ret_th_ip) { - const char *th_rule_type = NULL; - const char *th_gid = NULL; - const char *th_sid = NULL; + char th_rule_type[32]; + char th_gid[16]; + char th_sid[16]; + char rule_extend[1024]; const char *th_type = NULL; const char *th_track = NULL; const char *th_count = NULL; @@ -699,7 +700,6 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, const char *th_new_action= NULL; const char *th_timeout = NULL; const char *th_ip = NULL; - const char *rule_extend = NULL; uint8_t parsed_type = 0; uint8_t parsed_track = 0; @@ -724,39 +724,39 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, } /* retrieve the classtype name */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &th_rule_type); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 1, th_rule_type, sizeof(th_rule_type)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } /* retrieve the classtype name */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &th_gid); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 2, th_gid, sizeof(th_gid)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &th_sid); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 3, th_sid, sizeof(th_sid)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - ret = pcre_get_substring((char *)rawstr, ov, 30, 4, &rule_extend); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 4, rule_extend, sizeof(rule_extend)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } /* get type of rule */ - if (strncasecmp(th_rule_type,"event_filter",strlen("event_filter")) == 0) { + if (strcasecmp(th_rule_type,"event_filter") == 0) { rule_type = THRESHOLD_TYPE_EVENT_FILTER; - } else if (strncasecmp(th_rule_type,"threshold",strlen("threshold")) == 0) { + } else if (strcasecmp(th_rule_type,"threshold") == 0) { rule_type = THRESHOLD_TYPE_THRESHOLD; - } else if (strncasecmp(th_rule_type,"rate",strlen("rate")) == 0) { + } else if (strcasecmp(th_rule_type,"rate_filter") == 0) { rule_type = THRESHOLD_TYPE_RATE; - } else if (strncasecmp(th_rule_type,"suppress",strlen("suppress")) == 0) { + } else if (strcasecmp(th_rule_type,"suppress") == 0) { rule_type = THRESHOLD_TYPE_SUPPRESS; } else { SCLogError(SC_ERR_INVALID_VALUE, "rule type %s is unknown", th_rule_type); @@ -984,12 +984,6 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, *ret_th_ip = th_ip; return 0; error: - if (th_rule_type != NULL) - SCFree((char *)th_rule_type); - if (th_sid != NULL) - SCFree((char *)th_sid); - if (th_gid != NULL) - SCFree((char *)th_gid); if (th_track != NULL) SCFree((char *)th_track); if (th_count != NULL) @@ -1000,8 +994,6 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, SCFree((char *)th_type); if (th_ip != NULL) SCFree((char *)th_ip); - if (rule_extend != NULL) - SCFree((char *)rule_extend); return -1; } From 94321b8a2f797002b65846d7810b32974a06845e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Apr 2015 17:29:24 +0200 Subject: [PATCH 0396/2553] packet pool: fix memleaks Don't kill flow manager and recyclers before the rest of the threads. The packet threads may still have packets from their pools. As the flow threads would destroy their pools the packets would be lost. This patch doesn't kill the threads, it just pulls them out of their run loop and into a wait loop. The packet pools won't be cleared until all threads are killed. Wait for flow management threads to close before moving on to the next steps in the shutdown process. Don't destroy flow force reassembly packet pool too early. Worker threads may still want to return packets to it. --- src/flow-manager.c | 80 +++++++++++++++++++-------------------- src/flow-manager.h | 4 +- src/flow-timeout.c | 3 -- src/runmode-unix-socket.c | 9 ++++- src/suricata.c | 15 ++++++-- src/tm-threads.c | 4 +- 6 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 70300b95cd04..56ccce3b24d1 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -98,12 +98,12 @@ typedef struct FlowTimeoutCounters_ { } FlowTimeoutCounters; /** - * \brief Used to kill flow manager thread(s). + * \brief Used to disable flow manager thread(s). * * \todo Kinda hackish since it uses the tv name to identify flow manager * thread. We need an all weather identification scheme. */ -void FlowKillFlowManagerThread(void) +void FlowDisableFlowManagerThread(void) { ThreadVars *tv = NULL; int cnt = 0; @@ -121,8 +121,24 @@ void FlowKillFlowManagerThread(void) while (tv != NULL) { if (strcasecmp(tv->name, "FlowManagerThread") == 0) { TmThreadsSetFlag(tv, THV_KILL); - TmThreadsSetFlag(tv, THV_DEINIT); cnt++; + + /* value in seconds */ +#define THREAD_KILL_MAX_WAIT_TIME 60 + /* value in microseconds */ +#define WAIT_TIME 100 + + double total_wait_time = 0; + while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + usleep(WAIT_TIME); + total_wait_time += WAIT_TIME / 1000000.0; + if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { + SCLogError(SC_ERR_FATAL, "Engine unable to " + "disable detect thread - \"%s\". " + "Killing engine", tv->name); + exit(EXIT_FAILURE); + } + } } tv = tv->next; } @@ -131,24 +147,6 @@ void FlowKillFlowManagerThread(void) for (u = 0; u < flowmgr_number; u++) SCCtrlCondSignal(&flow_manager_ctrl_cond); - tv = tv_root[TVT_MGMT]; - while (tv != NULL) { - if (strcasecmp(tv->name, "FlowManagerThread") == 0) { - /* be sure it has shut down */ - while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { - usleep(100); - } - } - tv = tv->next; - } - - - /* not possible, unless someone decides to rename FlowManagerThread */ - if (cnt == 0) { - SCMutexUnlock(&tv_root_lock); - abort(); - } - SCMutexUnlock(&tv_root_lock); /* reset count, so we can kill and respawn (unix socket) */ @@ -913,14 +911,14 @@ void FlowRecyclerThreadSpawn() } /** - * \brief Used to kill flow recycler thread(s). + * \brief Used to disable flow recycler thread(s). * * \note this should only be called when the flow manager is already gone * * \todo Kinda hackish since it uses the tv name to identify flow recycler * thread. We need an all weather identification scheme. */ -void FlowKillFlowRecyclerThread(void) +void FlowDisableFlowRecyclerThread(void) { ThreadVars *tv = NULL; int cnt = 0; @@ -947,8 +945,24 @@ void FlowKillFlowRecyclerThread(void) while (tv != NULL) { if (strcasecmp(tv->name, "FlowRecyclerThread") == 0) { TmThreadsSetFlag(tv, THV_KILL); - TmThreadsSetFlag(tv, THV_DEINIT); cnt++; + + /* value in seconds */ +#define THREAD_KILL_MAX_WAIT_TIME 60 + /* value in microseconds */ +#define WAIT_TIME 100 + + double total_wait_time = 0; + while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + usleep(WAIT_TIME); + total_wait_time += WAIT_TIME / 1000000.0; + if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { + SCLogError(SC_ERR_FATAL, "Engine unable to " + "disable detect thread - \"%s\". " + "Killing engine", tv->name); + exit(EXIT_FAILURE); + } + } } tv = tv->next; } @@ -957,24 +971,6 @@ void FlowKillFlowRecyclerThread(void) for (u = 0; u < flowrec_number; u++) SCCtrlCondSignal(&flow_recycler_ctrl_cond); - tv = tv_root[TVT_MGMT]; - while (tv != NULL) { - if (strcasecmp(tv->name, "FlowRecyclerThread") == 0) { - /* be sure it has shut down */ - while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { - usleep(100); - } - } - tv = tv->next; - } - - - /* not possible, unless someone decides to rename FlowManagerThread */ - if (cnt == 0) { - SCMutexUnlock(&tv_root_lock); - abort(); - } - SCMutexUnlock(&tv_root_lock); /* reset count, so we can kill and respawn (unix socket) */ diff --git a/src/flow-manager.h b/src/flow-manager.h index a2e6f6dc068d..32ae2b2641dd 100644 --- a/src/flow-manager.h +++ b/src/flow-manager.h @@ -30,7 +30,7 @@ SCCtrlMutex flow_manager_ctrl_mutex; #define FlowWakeupFlowManagerThread() SCCtrlCondSignal(&flow_manager_ctrl_cond) void FlowManagerThreadSpawn(void); -void FlowKillFlowManagerThread(void); +void FlowDisableFlowManagerThread(void); void FlowMgrRegisterTests (void); /** flow recycler scheduling condition */ @@ -40,7 +40,7 @@ SCCtrlMutex flow_recycler_ctrl_mutex; SCCtrlCondSignal(&flow_recycler_ctrl_cond) void FlowRecyclerThreadSpawn(void); -void FlowKillFlowRecyclerThread(void); +void FlowDisableFlowRecyclerThread(void); void TmModuleFlowManagerRegister (void); void TmModuleFlowRecyclerRegister (void); diff --git a/src/flow-timeout.c b/src/flow-timeout.c index afd1ef71cd67..f2eb0899289c 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -553,11 +553,8 @@ static inline void FlowForceReassemblyForHash(void) */ void FlowForceReassembly(void) { - /* called by 'main()' which has no packet pool */ - PacketPoolInit(); /* Carry out flow reassembly for unattended flows */ FlowForceReassemblyForHash(); - PacketPoolDestroy(); return; } diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 1d6b023feac9..42f836cf22ab 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -283,13 +283,16 @@ TmEcode UnixSocketPcapFilesCheck(void *data) } this->currentfile = NULL; + /* needed by FlowForceReassembly */ + PacketPoolInit(); + /* handle graceful shutdown of the flow engine, it's helper * threads and the packet threads */ - FlowKillFlowManagerThread(); + FlowDisableFlowManagerThread(); TmThreadDisableReceiveThreads(); FlowForceReassembly(); TmThreadDisablePacketThreads(); - FlowKillFlowRecyclerThread(); + FlowDisableFlowRecyclerThread(); /* kill the stats threads */ TmThreadKillThreadsFamily(TVT_MGMT); @@ -299,6 +302,8 @@ TmEcode UnixSocketPcapFilesCheck(void *data) TmThreadKillThreadsFamily(TVT_PPT); TmThreadClearThreadsFamily(TVT_PPT); + PacketPoolDestroy(); + /* mgt and ppt threads killed, we can run non thread-safe * shutdown functions */ SCPerfReleaseResources(); diff --git a/src/suricata.c b/src/suricata.c index 08f84cdc5e21..60bf9ed02570 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2407,14 +2407,18 @@ int main(int argc, char **argv) UnixSocketKillSocketThread(); if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - /* First we need to kill the flow manager thread */ - FlowKillFlowManagerThread(); + /* First we need to disable the flow manager thread */ + FlowDisableFlowManagerThread(); } + /* Disable packet acquisition first */ TmThreadDisableReceiveThreads(); if (suri.run_mode != RUNMODE_UNIX_SOCKET) { + /* we need a packet pool for FlowForceReassembly */ + PacketPoolInit(); + FlowForceReassembly(); /* kill receive threads when they have processed all * flow timeout packets */ @@ -2426,13 +2430,18 @@ int main(int argc, char **argv) /* before TmThreadKillThreads, as otherwise that kills it * but more slowly */ if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - FlowKillFlowRecyclerThread(); + FlowDisableFlowRecyclerThread(); } /* kill remaining threads */ TmThreadKillThreads(); + if (suri.run_mode != RUNMODE_UNIX_SOCKET) { + /* destroy the packet pool for flow reassembly after all + * the other threads are gone. */ + PacketPoolDestroy(); + SCPerfReleaseResources(); IPPairShutdown(); FlowShutdown(); diff --git a/src/tm-threads.c b/src/tm-threads.c index 181d04a0b62e..b7fb3a695797 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -352,11 +352,11 @@ void *TmThreadsSlotPktAcqLoop(void *td) /* process all pseudo packets the flow timeout may throw at us */ TmThreadTimeoutLoop(tv, s); - PacketPoolDestroy(); - TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); + PacketPoolDestroy(); + for (slot = s; slot != NULL; slot = slot->slot_next) { if (slot->SlotThreadExitPrintStats != NULL) { slot->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(slot->slot_data)); From b9aaf5a9ab5f38c9a77b9482b08876c1a35b25fb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 29 Apr 2015 15:03:23 +0200 Subject: [PATCH 0397/2553] Fix potential deadlock in output Coverity: ** CID 1296115: Program hangs (ORDER_REVERSAL) /src/tm-threads.c: 1670 in TmThreadClearThreadsFamily() The problem is with the by default unused '%m' output parameter. To get the thread vars it takes the tv_root_lock. This may already be locked by the calling thread. Also, it could lead to a case of wrong lock order between the tv_root_lock and the thread_store_lock. Very unlikely to happen though. As the %m param isn't really used (by default) this patch just disables it. --- src/util-debug.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/util-debug.c b/src/util-debug.c index 8283c99c5f37..7a78987dda5d 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -358,12 +358,19 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, substr = temp_fmt; substr++; break; - case SC_LOG_FMT_TM: temp_fmt[0] = '\0'; +/* disabled to prevent dead lock: + * log or alloc (which calls log on error) can call TmThreadsGetCallingThread + * which will lock tv_root_lock. This can happen while we already hold this + * lock. */ +#if 0 ThreadVars *tv = TmThreadsGetCallingThread(); cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%s", substr, ((tv != NULL)? tv->name: "UNKNOWN TM")); +#endif + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + "%s%s", substr, "N/A"); if (cw < 0) goto error; temp += cw; @@ -371,7 +378,6 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, substr = temp_fmt; substr++; break; - case SC_LOG_FMT_LOG_LEVEL: temp_fmt[0] = '\0'; s = SCMapEnumValueToName(log_level, sc_log_level_map); From 54d5e2eed5921f42fe44b8c414a440593dd9a47a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 29 Apr 2015 15:38:39 +0200 Subject: [PATCH 0398/2553] coverity fix: don't do pointer check on static array --- src/util-classification-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-classification-config.c b/src/util-classification-config.c index 51d18fdb2e77..ea696d7b7fb5 100644 --- a/src/util-classification-config.c +++ b/src/util-classification-config.c @@ -275,7 +275,7 @@ int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx SCLogInfo("pcre_copy_substring() failed"); goto error; } - if (ct_priority_str == NULL) { + if (strlen(ct_priority_str) == 0) { goto error; } From 1a83fee5f561d0f32f00e3bf59da2f655b96b526 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 29 Apr 2015 15:51:19 +0200 Subject: [PATCH 0399/2553] xbits: fix coverity warnings Switch statement would contain NOALERT even though this was unreachable. --- src/detect-flowbits.c | 4 +--- src/detect-hostbits.c | 4 +--- src/detect-xbits.c | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 315cb8cfc9c3..bb95c95cd659 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -260,9 +260,7 @@ int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) sm->ctx = (SigMatchCtx *)cd; switch (fb_cmd) { - case DETECT_FLOWBITS_CMD_NOALERT: - /* nothing to do */ - break; + /* case DETECT_FLOWBITS_CMD_NOALERT can't happen here */ case DETECT_FLOWBITS_CMD_ISNOTSET: case DETECT_FLOWBITS_CMD_ISSET: diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index a940897b9afa..a69c292f1260 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -403,9 +403,7 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) sm->ctx = (void *)cd; switch (fb_cmd) { - case DETECT_XBITS_CMD_NOALERT: - /* nothing to do */ - break; + /* case DETECT_XBITS_CMD_NOALERT can't happen here */ case DETECT_XBITS_CMD_ISNOTSET: case DETECT_XBITS_CMD_ISSET: diff --git a/src/detect-xbits.c b/src/detect-xbits.c index 09a85a5c73a5..876ddc36dfdc 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -327,9 +327,7 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) sm->ctx = (void *)cd; switch (fb_cmd) { - case DETECT_XBITS_CMD_NOALERT: - /* nothing to do */ - break; + /* case DETECT_XBITS_CMD_NOALERT can't happen here */ case DETECT_XBITS_CMD_ISNOTSET: case DETECT_XBITS_CMD_ISSET: From 91ddf85323f66fa62ae8277ba2826a413139479c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 29 Apr 2015 23:34:44 +0200 Subject: [PATCH 0400/2553] profiling: fix sorting on very long runs Fix poor int handling breaking sorts of profiling on long runs where the numbers could get really big. --- src/util-profiling-rules.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index a6a4189da5e5..2f4ec5c75e7e 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -194,7 +194,10 @@ SCProfileSummarySortByTicks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->ticks - s0->ticks; + if (s1->ticks == s0->ticks) + return 0; + else + return s0->ticks > s1->ticks ? -1 : 1; } /** @@ -205,7 +208,10 @@ SCProfileSummarySortByAvgTicksMatch(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->avgticks_match - s0->avgticks_match; + if (s1->avgticks_match == s0->avgticks_match) + return 0; + else + return s0->avgticks_match > s1->avgticks_match ? -1 : 1; } /** @@ -216,7 +222,10 @@ SCProfileSummarySortByAvgTicksNoMatch(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->avgticks_no_match - s0->avgticks_no_match; + if (s1->avgticks_no_match == s0->avgticks_no_match) + return 0; + else + return s0->avgticks_no_match > s1->avgticks_no_match ? -1 : 1; } /** @@ -227,7 +236,10 @@ SCProfileSummarySortByAvgTicks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->avgticks - s0->avgticks; + if (s1->avgticks == s0->avgticks) + return 0; + else + return s0->avgticks > s1->avgticks ? -1 : 1; } /** @@ -238,7 +250,10 @@ SCProfileSummarySortByChecks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->checks - s0->checks; + if (s1->checks == s0->checks) + return 0; + else + return s0->checks > s1->checks ? -1 : 1; } /** @@ -249,7 +264,10 @@ SCProfileSummarySortByMatches(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->matches - s0->matches; + if (s1->matches == s0->matches) + return 0; + else + return s0->matches > s1->matches ? -1 : 1; } /** @@ -260,7 +278,10 @@ SCProfileSummarySortByMaxTicks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->max - s0->max; + if (s1->max == s0->max) + return 0; + else + return s0->max > s1->max ? -1 : 1; } /** From 7b8184947ac6a32a2a23ff29042e716febf90829 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 29 Apr 2015 15:43:47 +0200 Subject: [PATCH 0401/2553] app-layer-smtp: fix SMTPTransactionFree function A typo was causing some freeing tasks not to be executed. --- src/app-layer-smtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 90bc7d89fea9..bc6459ab8330 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1126,8 +1126,9 @@ static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state) /* Free list of MIME message recursively */ MimeDecFreeEntity(tx->msg_head); - if (tx->decoder_events != NULL) { + if (tx->decoder_events != NULL) AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + if (tx->de_state != NULL) DetectEngineStateFree(tx->de_state); #if 0 @@ -1136,7 +1137,6 @@ static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state) else smtp_state->events = 0; #endif - } SCFree(tx); } From bd67000b6980555d2232569f986127e4ec7d08cf Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 29 Apr 2015 14:57:07 +0200 Subject: [PATCH 0402/2553] email-json: free temporary 'to' string --- src/output-json-email-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index f12a0e181227..bb5bf38235c4 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -126,6 +126,7 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packe //printf("got another addr: \"%s\"\n", p); json_array_append_new(js_to, json_string(&p[strspn(p, " ")])); } + SCFree(to_line); json_object_set_new(sjs, "to", js_to); } } From 0376b60da91230e5dcb9aafa014a1476e30b2ec4 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 29 Apr 2015 14:57:53 +0200 Subject: [PATCH 0403/2553] email-json: free temporary 'cc' string --- src/output-json-email-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index bb5bf38235c4..4c427d4467b1 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -149,6 +149,7 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packe //printf("got another addr: \"%s\"\n", p); json_array_append_new(js_cc, json_string(&p[strspn(p, " ")])); } + SCFree(cc_line); json_object_set_new(sjs, "cc", js_cc); } } From 75d21851cf9492ccca56432e3774bf274b3bf270 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 20 Apr 2015 11:47:18 -0600 Subject: [PATCH 0404/2553] afl - Don't fail if app-layer proto enabled value is NULL. Found by using AFL on suricata.yaml. --- src/app-layer-detect-proto.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index c9c406de53ec..9545dffac7d5 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1630,17 +1630,20 @@ int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, } } - if (strcasecmp(node->val, "yes") == 0) { - goto enabled; - } else if (strcasecmp(node->val, "no") == 0) { - goto disabled; - } else if (strcasecmp(node->val, "detection-only") == 0) { - goto enabled; - } else { - SCLogError(SC_ERR_FATAL, "Invalid value found for %s.", param); - exit(EXIT_FAILURE); + if (node->val) { + if (ConfValIsTrue(node->val)) { + goto enabled; + } else if (ConfValIsFalse(node->val)) { + goto disabled; + } else if (strcasecmp(node->val, "detection-only") == 0) { + goto enabled; + } } + /* Invalid or null value. */ + SCLogError(SC_ERR_FATAL, "Invalid value found for %s.", param); + exit(EXIT_FAILURE); + disabled: enabled = 0; enabled: From 11d6770ae4814a7b61fd53bdf9ec02a20c1b482d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 20 Apr 2015 12:12:55 -0600 Subject: [PATCH 0405/2553] afl - SCHINfoLoadFromConfig - check for NULL before parsing. Found by AFL on suricata.yaml. --- src/util-host-os-info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-host-os-info.c b/src/util-host-os-info.c index 8438d198971b..ad0de7e25ad3 100644 --- a/src/util-host-os-info.c +++ b/src/util-host-os-info.c @@ -342,7 +342,7 @@ void SCHInfoLoadFromConfig(void) ConfNode *host; TAILQ_FOREACH(host, &policy->head, next) { int is_ipv4 = 1; - if (index(host->val, ':') != NULL) + if (host->val != NULL && index(host->val, ':') != NULL) is_ipv4 = 0; if (SCHInfoAddHostOSInfo(policy->name, host->val, is_ipv4) == -1) { SCLogError(SC_ERR_INVALID_ARGUMENT, From 97a2d1ac267a13b6c623bf57ad1b8ad8d95290a1 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Thu, 16 Apr 2015 21:28:03 -0700 Subject: [PATCH 0406/2553] fix reputation parser so that it accepts ipv6 addresses in configuration file. --- src/reputation.c | 69 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/src/reputation.c b/src/reputation.c index 23484f08b05c..d1aef713c926 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -267,7 +267,7 @@ static int SRepCatSplitLine(char *line, uint8_t *cat, char *shortname, size_t sh * \retval 1 header * \retval -1 boo */ -static int SRepSplitLine(SRepCIDRTree *cidr_ctx, char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) +static int SRepSplitLine(SRepCIDRTree *cidr_ctx, char *line, Address *ip, uint8_t *cat, uint8_t *value) { size_t line_len = strlen(line); char *ptrs[3] = {NULL,NULL,NULL}; @@ -319,12 +319,14 @@ static int SRepSplitLine(SRepCIDRTree *cidr_ctx, char *line, uint32_t *ip, uint8 SRepCIDRAddNetblock(cidr_ctx, ptrs[0], c, v); return 1; } else { - uint32_t addr; - if (inet_pton(AF_INET, ptrs[0], &addr) <= 0) { + if (inet_pton(AF_INET, ptrs[0], &ip->address) == 1) { + ip->family = AF_INET; + } else if (inet_pton(AF_INET6, ptrs[0], &ip->address) == 1) { + ip->family = AF_INET6; + } else { return -1; } - *ip = addr; *cat = c; *value = v; } @@ -468,17 +470,21 @@ int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp) line[len - 1] = '\0'; } - uint32_t ip = 0; uint8_t cat = 0, value = 0; - int r = SRepSplitLine(cidr_ctx, line, &ip, &cat, &value); + int r = SRepSplitLine(cidr_ctx, line, &a, &cat, &value); if (r < 0) { SCLogError(SC_ERR_NO_REPUTATION, "bad line \"%s\"", line); } else if (r == 0) { - char ipstr[16]; - PrintInet(AF_INET, (const void *)&ip, ipstr, sizeof(ipstr)); - SCLogDebug("%s %u %u", ipstr, cat, value); + if (a.family == AF_INET) { + char ipstr[16]; + PrintInet(AF_INET, (const void *)&a.address, ipstr, sizeof(ipstr)); + SCLogDebug("%s %u %u", ipstr, cat, value); + } else { + char ipstr[128]; + PrintInet(AF_INET6, (const void *)&a.address, ipstr, sizeof(ipstr)); + SCLogDebug("%s %u %u", ipstr, cat, value); + } - a.addr_data32[0] = ip; Host *h = HostGetHostFromHash(&a); if (h == NULL) { SCLogError(SC_ERR_NO_REPUTATION, "failed to get a host, increase host.memcap"); @@ -704,14 +710,14 @@ static int SRepTest01(void) } SRepInit(de_ctx); - uint32_t ip = 0; + Address a; uint8_t cat = 0, value = 0; - if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &ip, &cat, &value) != 0) { + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) != 0) { goto end; } char ipstr[16]; - PrintInet(AF_INET, (const void *)&ip, ipstr, sizeof(ipstr)); + PrintInet(AF_INET, (const void *)&a.address, ipstr, sizeof(ipstr)); if (strcmp(ipstr, "1.2.3.4") != 0) goto end; @@ -739,9 +745,9 @@ static int SRepTest02(void) } SRepInit(de_ctx); - uint32_t ip = 0; + Address a; uint8_t cat = 0, value = 0; - if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &ip, &cat, &value) == 0) { + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) == 0) { goto end; } result = 1; @@ -789,9 +795,9 @@ static int SRepTest04(void) char str[] = "10.0.0.0/16,1,2"; - uint32_t ip = 0; + Address a; uint8_t cat = 0, value = 0; - if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &ip, &cat, &value) != 1) { + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) != 1) { goto end; } @@ -825,9 +831,9 @@ static int SRepTest05(void) char str[] = "10.0.0.0/16,1,20"; - uint32_t ip = 0; + Address a; uint8_t cat = 0, value = 0; - if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &ip, &cat, &value) != 1) { + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) != 1) { goto end; } cat = 1; @@ -868,9 +874,9 @@ static int SRepTest06(void) "0.0.0.0/0,1,10\n" "192.168.0.0/16,2,127"; - uint32_t ip = 0; + Address a; uint8_t cat = 0, value = 0; - if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &ip, &cat, &value) != 1) { + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) != 1) { goto end; } cat = 1; @@ -885,6 +891,26 @@ static int SRepTest06(void) DetectEngineCtxFree(de_ctx); return result; } + +static int SRepTest07(void) { + char str[] = "2000:0000:0000:0000:0000:0000:0000:0001,"; + int result = 0; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return 0; + } + + SRepInit(de_ctx); + Address a; + uint8_t cat = 0, value = 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) == 0) { + goto end; + } + result = 1; +end: + DetectEngineCtxFree(de_ctx); + return result; +} #endif /** Global trees that hold host reputation for IPV4 and IPV6 hosts */ @@ -2322,6 +2348,7 @@ void SCReputationRegisterTests(void) UtRegisterTest("SRepTest04", SRepTest04, 1); UtRegisterTest("SRepTest05", SRepTest05, 1); UtRegisterTest("SRepTest06", SRepTest06, 1); + UtRegisterTest("SRepTest07", SRepTest07, 1); #endif /* UNITTESTS */ } From 04ccfda6398820ccc570497ea76aea5966dc368c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Apr 2015 12:12:46 +0200 Subject: [PATCH 0407/2553] pcap: implement LINKTYPE_NULL Implement LINKTYPE_NULL for pcap live and pcap file. From: http://www.tcpdump.org/linktypes.html "BSD loopback encapsulation; the link layer header is a 4-byte field, in host byte order, containing a PF_ value from socket.h for the network-layer protocol of the packet. Note that ``host byte order'' is the byte order of the machine on which the packets are captured, and the PF_ values are for the OS of the machine on which the packets are captured; if a live capture is being done, ``host byte order'' is the byte order of the machine capturing the packets, and the PF_ values are those of the OS of the machine capturing the packets, but if a ``savefile'' is being read, the byte order and PF_ values are not necessarily those of the machine reading the capture file." Feature ticket #1445 --- rules/decoder-events.rules | 7 ++- src/Makefile.am | 1 + src/decode-events.h | 4 ++ src/decode-null.c | 89 ++++++++++++++++++++++++++++++++++++++ src/decode-null.h | 27 ++++++++++++ src/decode.c | 2 + src/decode.h | 8 ++++ src/detect-engine-event.h | 4 ++ src/source-pcap-file.c | 3 ++ src/source-pcap.c | 3 ++ 10 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 src/decode-null.c create mode 100644 src/decode-null.h diff --git a/rules/decoder-events.rules b/rules/decoder-events.rules index d731dc8ddd9a..dc74a8160bf1 100644 --- a/rules/decoder-events.rules +++ b/rules/decoder-events.rules @@ -123,5 +123,10 @@ alert pkthdr any any -> any any (msg:"SURICATA MPLS bad implicit null label"; de alert pkthdr any any -> any any (msg:"SURICATA MPLS reserved label"; decode-event:mpls.bad_label_reserved; sid: 2200100; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA MPLS unknown payload type"; decode-event:mpls.unknown_payload_type; sid: 2200101; rev:1;) -# next sid is 2200103 +# linktype null +alert pkthdr any any -> any any (msg:"SURICATA NULL pkt too small"; decode-event:ltnull.pkt_too_small; sid: 2200103; rev:1;) +# packet has type not supported by Suricata's decoders +alert pkthdr any any -> any any (msg:"SURICATA NULL unsupported type"; decode-event:ltnull.unsupported_type; sid: 2200104; rev:1;) + +# next sid is 2200105 diff --git a/src/Makefile.am b/src/Makefile.am index 01c94375b4be..d802d21174ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -48,6 +48,7 @@ decode-icmpv4.c decode-icmpv4.h \ decode-icmpv6.c decode-icmpv6.h \ decode-ipv4.c decode-ipv4.h \ decode-ipv6.c decode-ipv6.h \ +decode-null.c decode-null.h \ decode-ppp.c decode-ppp.h \ decode-pppoe.c decode-pppoe.h \ decode-raw.c decode-raw.h \ diff --git a/src/decode-events.h b/src/decode-events.h index d9cceb1648ea..7ad23d9f7259 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -146,6 +146,10 @@ enum { /* RAW EVENTS */ IPRAW_INVALID_IPV, /**< invalid ip version in ip raw */ + /* LINKTYPE NULL EVENTS */ + LTNULL_PKT_TOO_SMALL, /**< pkt too small for lt:null */ + LTNULL_UNSUPPORTED_TYPE, /**< pkt has a type that the decoder doesn't support */ + /* STREAM EVENTS */ STREAM_3WHS_ACK_IN_WRONG_DIR, STREAM_3WHS_ASYNC_WRONG_SEQ, diff --git a/src/decode-null.c b/src/decode-null.c new file mode 100644 index 000000000000..8bb76ca79bda --- /dev/null +++ b/src/decode-null.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2015 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. + */ + +/** + * \ingroup decode + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Decode linkype null: + * http://www.tcpdump.org/linktypes.html + */ + +#include "suricata-common.h" +#include "decode.h" +#include "decode-raw.h" +#include "decode-events.h" + +#include "util-unittest.h" +#include "util-debug.h" + +#include "pkt-var.h" +#include "util-profiling.h" +#include "host.h" + +#define HDR_SIZE 4 + +int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) +{ + SCPerfCounterIncr(dtv->counter_null, tv->sc_perf_pca); + + if (unlikely(len < HDR_SIZE)) { + ENGINE_SET_INVALID_EVENT(p, LTNULL_PKT_TOO_SMALL); + return TM_ECODE_FAILED; + } + + uint32_t type = *((uint32_t *)pkt); + switch(type) { + case AF_INET: + SCLogDebug("IPV4 Packet"); + DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p)+HDR_SIZE, GET_PKT_LEN(p)-HDR_SIZE, pq); + break; + case AF_INET6: + SCLogDebug("IPV6 Packet"); + DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p)+HDR_SIZE, GET_PKT_LEN(p)-HDR_SIZE, pq); + break; + default: + SCLogDebug("Unknown Null packet type version %" PRIu32 "", type); + ENGINE_SET_EVENT(p, LTNULL_UNSUPPORTED_TYPE); + break; + } + return TM_ECODE_OK; +} + +#ifdef UNITTESTS + +#endif /* UNITTESTS */ + +/** + * \brief Registers Null unit tests + */ +void DecodeNullRegisterTests(void) +{ +#ifdef UNITTESTS +#endif /* UNITTESTS */ +} +/** + * @} + */ diff --git a/src/decode-null.h b/src/decode-null.h new file mode 100644 index 000000000000..22d988c72481 --- /dev/null +++ b/src/decode-null.h @@ -0,0 +1,27 @@ +/* Copyright (C) 2007-2010 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 + */ + +#ifndef __DECODE_NULL_H__ +#define __DECODE_NULL_H__ +void DecodeNullRegisterTests(void); +#endif /* __DECODE_NULL_H__ */ diff --git a/src/decode.c b/src/decode.c index c2c31cf14abb..4d656691c5da 100644 --- a/src/decode.c +++ b/src/decode.c @@ -384,6 +384,8 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_raw = SCPerfTVRegisterCounter("decoder.raw", tv, SC_PERF_TYPE_UINT64, "NULL"); + dtv->counter_null = SCPerfTVRegisterCounter("decoder.null", tv, + SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_sll = SCPerfTVRegisterCounter("decoder.sll", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_tcp = SCPerfTVRegisterCounter("decoder.tcp", tv, diff --git a/src/decode.h b/src/decode.h index 0ea4c15f7a9f..11501cdffcc1 100644 --- a/src/decode.h +++ b/src/decode.h @@ -78,6 +78,7 @@ enum PktSrcEnum { #include "decode-udp.h" #include "decode-sctp.h" #include "decode-raw.h" +#include "decode-null.h" #include "decode-vlan.h" #include "decode-mpls.h" @@ -591,6 +592,7 @@ typedef struct DecodeThreadVars_ uint16_t counter_eth; uint16_t counter_sll; uint16_t counter_raw; + uint16_t counter_null; uint16_t counter_tcp; uint16_t counter_udp; uint16_t counter_sctp; @@ -854,6 +856,7 @@ int DecodePPP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, P int DecodePPPOESession(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodePPPOEDiscovery(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *, uint8_t) __attribute__ ((warn_unused_result)); +int DecodeNull(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeRaw(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeIPV4(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeIPV6(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); @@ -962,8 +965,13 @@ void AddressDebugPrint(Address *); #endif #endif +#ifndef DLT_NULL +#define DLT_NULL 0 +#endif + /** libpcap shows us the way to linktype codes * \todo we need more & maybe put them in a separate file? */ +#define LINKTYPE_NULL DLT_NULL #define LINKTYPE_ETHERNET DLT_EN10MB #define LINKTYPE_LINUX_SLL 113 #define LINKTYPE_PPP 9 diff --git a/src/detect-engine-event.h b/src/detect-engine-event.h index 6270ca094be2..5d51d6834d4b 100644 --- a/src/detect-engine-event.h +++ b/src/detect-engine-event.h @@ -155,6 +155,10 @@ struct DetectEngineEvents_ { /* RAW EVENTS */ { "ipraw.invalid_ip_version",IPRAW_INVALID_IPV, }, + /* LINKTYPE NULL EVENTS */ + { "ltnull.pkt_too_small", LTNULL_PKT_TOO_SMALL, }, + { "ltnull.unsupported_type", LTNULL_UNSUPPORTED_TYPE, }, + /* STREAM EVENTS */ { "stream.3whs_ack_in_wrong_dir", STREAM_3WHS_ACK_IN_WRONG_DIR, }, { "stream.3whs_async_wrong_seq", STREAM_3WHS_ASYNC_WRONG_SEQ, }, diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index f7dcb4c06297..a9d55659e257 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -318,6 +318,9 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) case LINKTYPE_RAW: pcap_g.Decoder = DecodeRaw; break; + case LINKTYPE_NULL: + pcap_g.Decoder = DecodeNull; + break; default: SCLogError(SC_ERR_UNIMPLEMENTED, "datalink type %" PRId32 " not " diff --git a/src/source-pcap.c b/src/source-pcap.c index bf51ff91ea88..634cc8117cbc 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -743,6 +743,9 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe case LINKTYPE_RAW: DecodeRaw(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; + case LINKTYPE_NULL: + DecodeNull(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); + break; default: SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodePcap", p->datalink); break; From a2d0441380b16669c9d5baa45c3317906c236caa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 1 May 2015 17:58:34 +0200 Subject: [PATCH 0408/2553] Bug 1340: fix missing flow cleanup Fix missing flow output cleanup function leading to a crash in the unix socket mode. --- src/runmodes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runmodes.c b/src/runmodes.c index aa2e9bce64fc..a769b9b6ee7d 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -469,6 +469,7 @@ void RunModeShutDown(void) OutputFiledataShutdown(); OutputStreamingShutdown(); OutputStatsShutdown(); + OutputFlowShutdown(); /* Close any log files. */ RunModeOutput *output; From fa73a0bb8f312fd0a95cc70f6b3ee4e4997bdba7 Mon Sep 17 00:00:00 2001 From: Pierre Chifflier Date: Sat, 18 Apr 2015 14:24:45 +0200 Subject: [PATCH 0409/2553] Fix possible wrap in uint32_t addition in DER parser Signed-off-by: Pierre Chifflier --- src/util-decode-der.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/util-decode-der.c b/src/util-decode-der.c index 3e7324be9cdb..1687668bd5fd 100644 --- a/src/util-decode-der.c +++ b/src/util-decode-der.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 ANSSI + * Copyright (C) 2011-2015 ANSSI * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -466,8 +466,11 @@ static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_ return NULL; } } - if (length > max_size) + if (length == UINT32_MAX || length > max_size) { + if (errcode) + *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; return NULL; + } a = Asn1GenericNew(); if (a == NULL) @@ -508,8 +511,11 @@ static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint3 return NULL; } } - if (length > max_size) + if (length == UINT32_MAX || length > max_size) { + if (errcode) + *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; return NULL; + } a = Asn1GenericNew(); if (a == NULL) @@ -561,8 +567,11 @@ static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, u return NULL; } } - if (length > max_size) + if (length == UINT32_MAX || length > max_size) { + if (errcode) + *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; return NULL; + } a = Asn1GenericNew(); if (a == NULL) @@ -612,7 +621,9 @@ static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t } } node->length = d_length + (d_ptr - buffer); - if (node->length > max_size) { + if (node->length > max_size || node->length < d_length /* wrap */) { + if (errcode) + *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; SCFree(node); return NULL; } @@ -626,6 +637,10 @@ static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t Asn1Generic *child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, seq_index, errcode); if (child == NULL) { + if (errcode && *errcode != 0) { + DerFree(node); + return NULL; + } break; } @@ -676,7 +691,7 @@ static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_ } node->length = d_length + (d_ptr - buffer); - if (node->length > max_size) { + if (node->length > max_size || node->length < d_length /* wrap */) { if (errcode) *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; SCFree(node); @@ -687,6 +702,10 @@ static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_ el_max_size = max_size - (d_ptr-buffer); child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, seq_index, errcode); + if (child == NULL) { + DerFree(node); + return NULL; + } node->data = child; From a4a1c396e1595ebf5b86a2dd1bedbe604584e7ea Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Apr 2015 19:29:12 +0200 Subject: [PATCH 0410/2553] pcap-file: fix malformed timestamp crash A bad timestamp would lead to SCLocalTime returning NULL. This case wasn't checked, leading to a NULL deref. Reported-by: Kostya Kortchinsky of the Google Security Team --- src/util-time.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/util-time.c b/src/util-time.c index e8f6fe107dbf..1e4237335d52 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -129,9 +129,13 @@ void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size) struct tm local_tm; struct tm *t = (struct tm*)SCLocalTime(time, &local_tm); - snprintf(str, size, "%04d-%02d-%02dT%02d:%02d:%02d.%06u", - t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, - t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); + if (likely(t != NULL)) { + snprintf(str, size, "%04d-%02d-%02dT%02d:%02d:%02d.%06u", + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, + t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); + } else { + snprintf(str, size, "ts-error"); + } } /* @@ -152,9 +156,13 @@ void CreateTimeString (const struct timeval *ts, char *str, size_t size) struct tm local_tm; struct tm *t = (struct tm*)SCLocalTime(time, &local_tm); - snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", - t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, - t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); + if (likely(t != NULL)) { + snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", + t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, + t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); + } else { + snprintf(str, size, "ts-error"); + } } #else From 6d170cadd77bcf0e1d05f2db89ff7dc77ab74ce1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Apr 2015 17:05:52 +0200 Subject: [PATCH 0411/2553] smtp: fix mime boundary parsing issue If a boundary was longer than 254 bytes a stack overflow would result in mime decoding. Ticket #1449 Reported-by: Kostya Kortchinsky of the Google Security Team --- rules/smtp-events.rules | 3 +++ src/app-layer-smtp.c | 5 +++++ src/app-layer-smtp.h | 1 + src/util-decode-mime.c | 11 +++++++++++ src/util-decode-mime.h | 1 + 5 files changed, 21 insertions(+) diff --git a/rules/smtp-events.rules b/rules/smtp-events.rules index 52b4647f9618..c1ade81ad3df 100644 --- a/rules/smtp-events.rules +++ b/rules/smtp-events.rules @@ -25,3 +25,6 @@ alert smtp any any -> any any (msg:"SURICATA SMTP data command rejected"; flow:e #alert smtp any any -> any any (msg:"SURICATA SMTP Mime quoted-printable-decoding failed"; flow:established; app-layer-event:smtp.mime_invalid_qp; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220014; rev:1;) #alert smtp any any -> any any (msg:"SURICATA SMTP Mime line len exceeded"; flow:established; app-layer-event:smtp.mime_long_line; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220015; rev:1;) #alert smtp any any -> any any (msg:"SURICATA SMTP Mime encoded line len exceeded"; flow:established; app-layer-event:smtp.mime_long_enc_line; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220016; rev:1;) +alert smtp any any -> any any (msg:"SURICATA SMTP Mime boundary length exceeded"; flow:established,to_server; app-layer-event:smtp.mime_long_boundary; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220017; rev:1;) + +# next sid 2220018 diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index bc6459ab8330..1a0894f0f98c 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -133,6 +133,8 @@ SCEnumCharMap smtp_decoder_event_table[ ] = { SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME }, { "MIME_LONG_HEADER_VALUE", SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE }, + { "MIME_LONG_BOUNDARY", + SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG }, { NULL, -1 }, }; @@ -753,6 +755,9 @@ static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, if (msg->anomaly_flags & ANOM_MALFORMED_MSG) { SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG); } + if (msg->anomaly_flags & ANOM_LONG_BOUNDARY) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG); + } } state->curr_tx->done = 1; SCLogDebug("marked tx as done"); diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 8bb4a9323902..eca2003180fa 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -48,6 +48,7 @@ enum { SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE, + SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG, }; typedef struct SMTPTransaction_ { diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 187740ea874b..3f4affcccf6c 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -1889,6 +1889,11 @@ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, state->found_child = 1; entity->ctnt_flags |= CTNT_IS_MULTIPART; + if (blen > (BOUNDARY_BUF - 2)) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_BOUNDARY; + return MIME_DEC_ERR_PARSE; + } + /* Store boundary in parent node */ state->stack->top->bdef = SCMalloc(blen); if (unlikely(state->stack->top->bdef == NULL)) { @@ -2207,6 +2212,12 @@ static int ProcessMimeBody(const uint8_t *buf, uint32_t len, if (len > 1 && buf[0] == '-' && buf[1] == '-') { tlen = node->bdef_len + 2; + if (tlen > BOUNDARY_BUF) { + if (state->stack->top->data) + state->stack->top->data->anomaly_flags |= ANOM_LONG_BOUNDARY; + return MIME_DEC_ERR_PARSE; + } + memcpy(temp, "--", 2); memcpy(temp + 2, node->bdef, node->bdef_len); diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h index 0b3b2d22b115..792fbcc199c7 100644 --- a/src/util-decode-mime.h +++ b/src/util-decode-mime.h @@ -62,6 +62,7 @@ #define ANOM_LONG_LINE 16 /* Lines that exceed 998 octets */ #define ANOM_LONG_ENC_LINE 32 /* Lines that exceed 76 octets */ #define ANOM_MALFORMED_MSG 64 /* Misc msg format errors found */ +#define ANOM_LONG_BOUNDARY 128 /* Boundary too long */ /* Pubicly exposed size constants */ #define DATA_CHUNK_SIZE 3072 /* Should be divisible by 3 */ From 04f3f5066d0ed7ef50b8413f7026d260c9009a75 Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Thu, 30 Apr 2015 19:02:56 +0200 Subject: [PATCH 0412/2553] app-layer-modbus: fix deadlock in parsers --- src/app-layer-modbus.c | 112 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 6 deletions(-) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 6442b821e9ce..31982eadfe8c 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1175,18 +1175,19 @@ static int ModbusParseRequest(Flow *f, ModbusHeader header; while (input_len > 0) { - uint16_t adu_len, offset = 0; + uint32_t adu_len; + uint16_t offset = 0; uint8_t *ptr = input; /* Modbus header is 7 bytes long */ - if (input_len < sizeof(ModbusHeader)) + if (input_len < (uint32_t) sizeof(ModbusHeader)) SCReturnInt(0); /* Extract MODBUS Header */ ModbusParseHeader(&header, ptr, &offset); /* Compute ADU length. */ - adu_len = sizeof(ModbusHeader) + header.length - 1; + adu_len = (uint32_t) sizeof(ModbusHeader) + (uint32_t) header.length - 1; if (adu_len > input_len) SCReturnInt(0); @@ -1235,18 +1236,19 @@ static int ModbusParseResponse(Flow *f, ModbusTransaction *tx; while (input_len > 0) { - uint16_t adu_len, offset = 0; + uint32_t adu_len; + uint16_t offset = 0; uint8_t *ptr = input; /* Modbus header is 7 bytes long */ - if (input_len < sizeof(ModbusHeader)) + if (input_len < (uint32_t) sizeof(ModbusHeader)) SCReturnInt(0); /* Extract MODBUS Header */ ModbusParseHeader(&header, ptr, &offset); /* Compute ADU length */ - adu_len = sizeof(ModbusHeader) + header.length - 1; + adu_len = (uint32_t) sizeof(ModbusHeader) + (uint32_t) header.length - 1; if (adu_len > input_len) SCReturnInt(0); @@ -1553,6 +1555,16 @@ static uint8_t invalidLengthWriteMultipleRegistersReq[] = { /* Registers Value */ 0x00, 0x0A, 0x01, 0x02}; +static uint8_t exceededLengthWriteMultipleRegistersReq[] = { + /* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0xff, 0xfa, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x7f, 0xf9, + /* Byte count */ 0xff}; + /** \test Send Modbus Read Coils request/response. */ static int ModbusParserTest01(void) { AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2401,6 +2413,93 @@ static int ModbusParserTest10(void) { FLOW_DESTROY(&f); return result; } + +/** \test Send Modbus exceed Length request. */ +static int ModbusParserTest11(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + exceededLengthWriteMultipleRegistersReq, + sizeof(exceededLengthWriteMultipleRegistersReq) + 65523 /* header.length - 7 */ * sizeof(uint8_t)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} #endif /* UNITTESTS */ void ModbusParserRegisterTests(void) { @@ -2415,5 +2514,6 @@ void ModbusParserRegisterTests(void) { UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid", ModbusParserTest08, 1); UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets", ModbusParserTest09, 1); UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet", ModbusParserTest10, 1); + UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request", ModbusParserTest11, 1); #endif /* UNITTESTS */ } From cf839c931f90253afcc27f00ee159fe880f1a92a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 1 May 2015 15:12:47 +0200 Subject: [PATCH 0413/2553] tls: force 'raw' reassembly after each record Trigger raw reassembly after each record and after the handshake. --- src/app-layer-ssl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index fc7583b1d0c4..d980b00abd67 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -897,6 +897,9 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, if (ssl_state->curr_connp->bytes_processed == ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { SSLParserReset(ssl_state); } + + SCLogDebug("trigger RAW! (post HS)"); + AppLayerParserTriggerRawStreamReassembly(ssl_state->f); return parsed; } @@ -920,6 +923,10 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } + + SCLogDebug("record complete, trigger RAW"); + AppLayerParserTriggerRawStreamReassembly(ssl_state->f); + /* looks like we have another record */ uint32_t diff = ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN - ssl_state->curr_connp->bytes_processed; parsed += diff; From 2918a75da1f3f74f1c57e5848e4e7a860854b945 Mon Sep 17 00:00:00 2001 From: David Cannings Date: Thu, 16 Apr 2015 19:40:46 +0100 Subject: [PATCH 0414/2553] Added support for full parsing of the rcode header in DNS answer packets. Where rcode isn't "no error" this is displayed in both DNS and JSON logs. Note that this changes the current "No such domain" to "NXDOMAIN" in DNS logs. This could be fixed if desired to maintain compatibility with anybody crazy enough to parse the DNS log. When the rcode is not "no error" (for example NXDOMAIN or SERVFAIL) it is unlikely that there will be answer RRs. Therefore the rname from the query is used. Because the rcode applies to a whole answer packet (not individual queries) it is impossible to determine which query RR caused the error. Because of this most DNS servers currently reject multiple queries per packet. Therefore each query RR is output instead with the relevant error code, likely to be FORMERR if queries > 1. --- src/app-layer-dns-common.c | 171 ++++++++++++++++++++++--------------- src/app-layer-dns-common.h | 23 ++++- src/app-layer-dns-tcp.c | 28 +++--- src/app-layer-dns-udp.c | 26 +++--- src/log-dnslog.c | 13 +-- src/output-json-dns.c | 55 +++++++++++- 6 files changed, 216 insertions(+), 100 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 4d724dfaa4d1..852afa7c85dd 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -794,22 +794,22 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ } const DNSAnswerHeader *head = (DNSAnswerHeader *)data; - switch (ntohs(head->type)) { - case DNS_RECORD_TYPE_A: - case DNS_RECORD_TYPE_AAAA: - case DNS_RECORD_TYPE_CNAME: - { - data += sizeof(DNSAnswerHeader); - SCLogDebug("head->len %u", ntohs(head->len)); + data += sizeof(DNSAnswerHeader); - if (input + input_len < data + ntohs(head->len)) { - SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); - goto insufficient_data; - } - SCLogDebug("TTL %u", ntohl(head->ttl)); + SCLogDebug("head->len %u", ntohs(head->len)); + + if (input + input_len < data + ntohs(head->len)) { + SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); + goto insufficient_data; + } - if (ntohs(head->type) == DNS_RECORD_TYPE_A && ntohs(head->len) == 4) { + SCLogDebug("TTL %u", ntohl(head->ttl)); + + switch (ntohs(head->type)) { + case DNS_RECORD_TYPE_A: + { + if (ntohs(head->len) == 4) { //PrintRawDataFp(stdout, data, ntohs(head->len)); //char a[16]; //PrintInet(AF_INET, (const void *)data, a, sizeof(a)); @@ -818,7 +818,17 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), data, 4, ntohs(dns_header->tx_id)); - } else if (ntohs(head->type) == DNS_RECORD_TYPE_AAAA && ntohs(head->len) == 16) { + } else { + SCLogDebug("invalid length for A response data: %u", ntohs(head->len)); + goto bad_data; + } + + data += ntohs(head->len); + break; + } + case DNS_RECORD_TYPE_AAAA: + { + if (ntohs(head->len) == 16) { //char a[46]; //PrintInet(AF_INET6, (const void *)data, a, sizeof(a)); //SCLogInfo("AAAA %s TTL %u", a, ntohl(head->ttl)); @@ -826,46 +836,29 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), data, 16, ntohs(dns_header->tx_id)); - } else if (ntohs(head->type) == DNS_RECORD_TYPE_CNAME) { - uint8_t cname[DNS_MAX_SIZE]; - uint16_t cname_len = 0; - - if ((cname_len = DNSResponseGetNameByOffset(input, input_len, - data - input, cname, sizeof(cname))) == 0) - { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif - goto insufficient_data; - } - - DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, - ntohs(head->type), ntohs(head->class), ntohl(head->ttl), - cname, cname_len, ntohs(dns_header->tx_id)); + } else { + SCLogDebug("invalid length for AAAA response data: %u", ntohs(head->len)); + goto bad_data; } data += ntohs(head->len); break; } case DNS_RECORD_TYPE_MX: + case DNS_RECORD_TYPE_CNAME: + case DNS_RECORD_TYPE_PTR: { - data += sizeof(DNSAnswerHeader); + uint8_t name[DNS_MAX_SIZE]; + uint16_t name_len = 0; + uint8_t skip = 0; - SCLogDebug("head->len %u", ntohs(head->len)); - - if (input + input_len < data + ntohs(head->len)) { - SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); - goto insufficient_data; + if (ntohs(head->type) == DNS_RECORD_TYPE_MX) { + // Skip the preference header + skip = 2; } - SCLogDebug("TTL %u", ntohl(head->ttl)); - - uint8_t mxname[DNS_MAX_SIZE]; - uint16_t mxname_len = 0; - - if ((mxname_len = DNSResponseGetNameByOffset(input, input_len, - data - input + 2, mxname, sizeof(mxname))) == 0) { + if ((name_len = DNSResponseGetNameByOffset(input, input_len, + data - input + skip, name, sizeof(name))) == 0) { #if DEBUG PrintRawDataFp(stdout, (uint8_t *)input, input_len); BUG_ON(1); @@ -875,7 +868,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), - mxname, mxname_len, ntohs(dns_header->tx_id)); + name, name_len, ntohs(dns_header->tx_id)); data += ntohs(head->len); break; @@ -883,15 +876,6 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ case DNS_RECORD_TYPE_NS: case DNS_RECORD_TYPE_SOA: { - data += sizeof(DNSAnswerHeader); - - if (input + input_len < data + ntohs(head->len)) { - SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); - goto insufficient_data; - } - - SCLogDebug("TTL %u", ntohl(head->ttl)); - uint8_t pname[DNS_MAX_SIZE]; uint16_t pname_len = 0; @@ -960,13 +944,6 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ } case DNS_RECORD_TYPE_TXT: { - data += sizeof(DNSAnswerHeader); - - if (input + input_len < data + ntohs(head->len)) { - SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); - goto insufficient_data; - } - uint16_t datalen = ntohs(head->len); uint8_t txtlen = *data; const uint8_t *tdata = data + 1; @@ -996,13 +973,6 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ } default: /* unsupported record */ { - data += sizeof(DNSAnswerHeader); - - if (input + input_len < data + ntohs(head->len)) { - SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); - goto insufficient_data; - } - DNSStoreAnswerInState(dns_state, list, NULL, 0, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), NULL, 0, ntohs(dns_header->tx_id)); @@ -1076,3 +1046,68 @@ void DNSCreateTypeString(uint16_t type, char *str, size_t str_size) snprintf(str, str_size, "%04x/%u", type, type); } } + +void DNSCreateRcodeString(uint8_t rcode, char *str, size_t str_size) +{ + switch (rcode) { + case DNS_RCODE_NOERROR: + snprintf(str, str_size, "NOERROR"); + break; + case DNS_RCODE_FORMERR: + snprintf(str, str_size, "FORMERR"); + break; + case DNS_RCODE_SERVFAIL: + snprintf(str, str_size, "SERVFAIL"); + break; + case DNS_RCODE_NXDOMAIN: + snprintf(str, str_size, "NXDOMAIN"); + break; + case DNS_RCODE_NOTIMP: + snprintf(str, str_size, "NOTIMP"); + break; + case DNS_RCODE_REFUSED: + snprintf(str, str_size, "REFUSED"); + break; + case DNS_RCODE_YXDOMAIN: + snprintf(str, str_size, "YXDOMAIN"); + break; + case DNS_RCODE_YXRRSET: + snprintf(str, str_size, "YXRRSET"); + break; + case DNS_RCODE_NXRRSET: + snprintf(str, str_size, "NXRRSET"); + break; + case DNS_RCODE_NOTAUTH: + snprintf(str, str_size, "NOTAUTH"); + break; + case DNS_RCODE_NOTZONE: + snprintf(str, str_size, "NOTZONE"); + break; + /* these are the same, need more logic */ + case DNS_RCODE_BADVERS: + //case DNS_RCODE_BADSIG: + snprintf(str, str_size, "BADVERS/BADSIG"); + break; + case DNS_RCODE_BADKEY: + snprintf(str, str_size, "BADKEY"); + break; + case DNS_RCODE_BADTIME: + snprintf(str, str_size, "BADTIME"); + break; + case DNS_RCODE_BADMODE: + snprintf(str, str_size, "BADMODE"); + break; + case DNS_RCODE_BADNAME: + snprintf(str, str_size, "BADNAME"); + break; + case DNS_RCODE_BADALG: + snprintf(str, str_size, "BADALG"); + break; + case DNS_RCODE_BADTRUNC: + snprintf(str, str_size, "BADTRUNC"); + break; + default: + SCLogDebug("could not map DNS rcode to name, bug!"); + snprintf(str, str_size, "%04x/%u", rcode, rcode); + } +} diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index d795f0cba657..1564fec98683 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -60,6 +60,26 @@ #define DNS_RECORD_TYPE_ANY 255 +#define DNS_RCODE_NOERROR 0 +#define DNS_RCODE_FORMERR 1 +#define DNS_RCODE_SERVFAIL 2 +#define DNS_RCODE_NXDOMAIN 3 +#define DNS_RCODE_NOTIMP 4 +#define DNS_RCODE_REFUSED 5 +#define DNS_RCODE_YXDOMAIN 6 +#define DNS_RCODE_YXRRSET 7 +#define DNS_RCODE_NXRRSET 8 +#define DNS_RCODE_NOTAUTH 9 +#define DNS_RCODE_NOTZONE 10 +#define DNS_RCODE_BADVERS 16 +#define DNS_RCODE_BADSIG 16 +#define DNS_RCODE_BADKEY 17 +#define DNS_RCODE_BADTIME 18 +#define DNS_RCODE_BADMODE 19 +#define DNS_RCODE_BADNAME 20 +#define DNS_RCODE_BADALG 21 +#define DNS_RCODE_BADTRUNC 22 + enum { DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE, DNS_DECODER_EVENT_MALFORMED_DATA, @@ -139,7 +159,7 @@ typedef struct DNSTransaction_ { uint8_t replied; /**< bool indicating request is replied to. */ uint8_t reply_lost; - uint8_t no_such_name; /**< server said "no such name" */ + uint8_t rcode; /**< response code (e.g. "no error" / "no such name") */ uint8_t recursion_desired; /**< server said "recursion desired" */ TAILQ_HEAD(, DNSQueryEntry_) query_list; /**< list for query/queries */ @@ -228,5 +248,6 @@ uint16_t DNSUdpResponseGetNameByOffset(const uint8_t * const input, const uint32 const uint16_t offset, uint8_t *fqdn, const size_t fqdn_size); void DNSCreateTypeString(uint16_t type, char *str, size_t str_size); +void DNSCreateRcodeString(uint8_t rcode, char *str, size_t str_size); #endif /* __APP_LAYER_DNS_COMMON_H__ */ diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 8ed1a85dcb67..36b8848aeb63 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -141,7 +141,7 @@ static int DNSTCPRequestParseProbe(uint8_t *input, uint32_t input_len) data += sizeof(DNSQueryTrailer); } - SCReturnInt(1); + SCReturnInt(1); insufficient_data: SCReturnInt(0); bad_data: @@ -262,7 +262,7 @@ static int DNSRequestParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu } } - SCReturnInt(1); + SCReturnInt(1); bad_data: insufficient_data: SCReturnInt(-1); @@ -277,7 +277,7 @@ static int DNSTCPRequestParse(Flow *f, void *dstate, uint8_t *input, uint32_t input_len, void *local_data) { - DNSState *dns_state = (DNSState *)dstate; + DNSState *dns_state = (DNSState *)dstate; SCLogDebug("starting %u", input_len); /** \todo remove this when PP is fixed to enforce ipproto */ @@ -351,7 +351,7 @@ static int DNSTCPRequestParse(Flow *f, void *dstate, goto bad_data; } - SCReturnInt(1); + SCReturnInt(1); insufficient_data: SCReturnInt(-1); bad_data: @@ -447,11 +447,15 @@ static int DNSReponseParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu } } - /* see if this is a "no such name" error */ - if (ntohs(dns_header->flags) & 0x0003) { - SCLogDebug("no such name"); + /* parse rcode, e.g. "noerror" or "nxdomain" */ + uint8_t rcode = ntohs(dns_header->flags) & 0x0F; + if (rcode <= DNS_RCODE_NOTZONE || (rcode >= DNS_RCODE_BADSIG && rcode <= DNS_RCODE_BADTRUNC)) { + SCLogDebug("rcode %u", rcode); if (tx != NULL) - tx->no_such_name = 1; + tx->rcode = rcode; + } else { + /* this is not invalid, rcodes can be user defined */ + SCLogDebug("unexpected DNS rcode %u", rcode); } if (ntohs(dns_header->flags) & 0x0080) { @@ -464,7 +468,7 @@ static int DNSReponseParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu tx->replied = 1; } - SCReturnInt(1); + SCReturnInt(1); bad_data: insufficient_data: SCReturnInt(-1); @@ -484,7 +488,7 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, uint8_t *input, uint32_t input_len, void *local_data) { - DNSState *dns_state = (DNSState *)dstate; + DNSState *dns_state = (DNSState *)dstate; /** \todo remove this when PP is fixed to enforce ipproto */ if (f != NULL && f->proto != IPPROTO_TCP) @@ -553,7 +557,7 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, if (r < 0) goto bad_data; } - SCReturnInt(1); + SCReturnInt(1); insufficient_data: SCReturnInt(-1); bad_data: @@ -664,6 +668,6 @@ void RegisterDNSTCPParsers(void) #ifdef UNITTESTS void DNSTCPParserRegisterTests(void) { -// UtRegisterTest("DNSTCPParserTest01", DNSTCPParserTest01, 1); +// UtRegisterTest("DNSTCPParserTest01", DNSTCPParserTest01, 1); } #endif diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index 86350d0ce396..1917914b1b11 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -147,7 +147,7 @@ static int DNSUDPRequestParse(Flow *f, void *dstate, } } - SCReturnInt(1); + SCReturnInt(1); bad_data: insufficient_data: SCReturnInt(-1); @@ -164,7 +164,7 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, uint8_t *input, uint32_t input_len, void *local_data) { - DNSState *dns_state = (DNSState *)dstate; + DNSState *dns_state = (DNSState *)dstate; SCLogDebug("starting %u", input_len); @@ -269,11 +269,15 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, } } - /* see if this is a "no such name" error */ - if (ntohs(dns_header->flags) & 0x0003) { - SCLogDebug("no such name"); + /* parse rcode, e.g. "noerror" or "nxdomain" */ + uint8_t rcode = ntohs(dns_header->flags) & 0x0F; + if (rcode <= DNS_RCODE_NOTZONE || (rcode >= DNS_RCODE_BADSIG && rcode <= DNS_RCODE_BADTRUNC)) { + SCLogDebug("rcode %u", rcode); if (tx != NULL) - tx->no_such_name = 1; + tx->rcode = rcode; + } else { + /* this is not invalid, rcodes can be user defined */ + SCLogDebug("unexpected DNS rcode %u", rcode); } if (ntohs(dns_header->flags) & 0x0080) { @@ -613,10 +617,10 @@ static int DNSUDPParserTest05 (void) void DNSUDPParserRegisterTests(void) { - UtRegisterTest("DNSUDPParserTest01", DNSUDPParserTest01, 1); - UtRegisterTest("DNSUDPParserTest02", DNSUDPParserTest02, 1); - UtRegisterTest("DNSUDPParserTest03", DNSUDPParserTest03, 1); - UtRegisterTest("DNSUDPParserTest04", DNSUDPParserTest04, 1); - UtRegisterTest("DNSUDPParserTest05", DNSUDPParserTest05, 1); + UtRegisterTest("DNSUDPParserTest01", DNSUDPParserTest01, 1); + UtRegisterTest("DNSUDPParserTest02", DNSUDPParserTest02, 1); + UtRegisterTest("DNSUDPParserTest03", DNSUDPParserTest03, 1); + UtRegisterTest("DNSUDPParserTest04", DNSUDPParserTest04, 1); + UtRegisterTest("DNSUDPParserTest05", DNSUDPParserTest05, 1); } #endif diff --git a/src/log-dnslog.c b/src/log-dnslog.c index 7d226e8b8a20..f0f381b521aa 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -40,6 +40,7 @@ #include "output.h" #include "log-dnslog.h" +#include "app-layer-dns-common.h" #include "app-layer-dns-udp.h" #include "app-layer.h" #include "util-privs.h" @@ -109,16 +110,18 @@ static void LogAnswer(LogDnsLogThread *aft, char *timebuf, char *srcip, char *ds /* reset */ MemBufferReset(aft->buffer); - /* time & tx*/ MemBufferWriteString(aft->buffer, "%s [**] Response TX %04x [**] ", timebuf, tx->tx_id); if (entry == NULL) { - if (tx->no_such_name) - MemBufferWriteString(aft->buffer, "No Such Name"); - else if (tx->recursion_desired) + if (tx->rcode) { + char rcode[16] = ""; + DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode)); + MemBufferWriteString(aft->buffer, "%s", rcode); + } else if (tx->recursion_desired) { MemBufferWriteString(aft->buffer, "Recursion Desired"); + } } else { /* query */ if (entry->fqdn_len > 0) { @@ -216,7 +219,7 @@ static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, Flow *f, LogQuery(aft, timebuf, dstip, srcip, dp, sp, dns_tx, query); } - if (dns_tx->no_such_name) + if (dns_tx->rcode) LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, NULL); if (dns_tx->recursion_desired) LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, NULL); diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 44494dbc0925..d0be0e6aa8f1 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -126,6 +126,12 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, /* id */ json_object_set_new(js, "id", json_integer(tx->tx_id)); + /* rcode */ + char rcode[16] = ""; + DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode)); + json_object_set_new(js, "rcode", json_string(rcode)); + + /* we are logging an answer RR */ if (entry != NULL) { /* query */ if (entry->fqdn_len > 0) { @@ -157,7 +163,8 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, json_object_set_new(js, "rdata", json_string(a)); } else if (entry->data_len == 0) { json_object_set_new(js, "rdata", json_string("")); - } else if (entry->type == DNS_RECORD_TYPE_TXT) { + } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME || + entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR) { if (entry->data_len != 0) { char buffer[256] = ""; uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ? @@ -180,13 +187,55 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, return; } +static void OutputFailure(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, DNSQueryEntry *entry) +{ + MemBuffer *buffer = (MemBuffer *)aft->buffer; + json_t *js = json_object(); + if (js == NULL) + return; + + /* type */ + json_object_set_new(js, "type", json_string("answer")); + + /* id */ + json_object_set_new(js, "id", json_integer(tx->tx_id)); + + /* rcode */ + char rcode[16] = ""; + DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode)); + json_object_set_new(js, "rcode", json_string(rcode)); + + /* no answer RRs, use query for rname */ + char *c; + c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSQueryEntry)), entry->len); + if (c != NULL) { + json_object_set_new(js, "rrname", json_string(c)); + SCFree(c); + } + + /* reset */ + MemBufferReset(buffer); + json_object_set_new(djs, "dns", js); + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, buffer); + json_object_del(djs, "dns"); + + return; +} + static void LogAnswers(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uint64_t tx_id) { SCLogDebug("got a DNS response and now logging !!"); - if (tx->no_such_name) { - OutputAnswer(aft, js, tx, NULL); + /* rcode != noerror */ + if (tx->rcode) { + /* Most DNS servers do not support multiple queries because + * the rcode in response is not per-query. Multiple queries + * are likely to lead to FORMERR, so log this. */ + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &tx->query_list, next) { + OutputFailure(aft, js, tx, query); + } } DNSAnswerEntry *entry = NULL; From b12c53cd51ca1b24039c248f1eab6808d9686e4b Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Thu, 7 May 2015 12:40:28 +0300 Subject: [PATCH 0415/2553] Add timezone to timestamp in JSON logs --- src/util-time.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util-time.c b/src/util-time.c index 1e4237335d52..7c7a362458bb 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -128,11 +128,11 @@ void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size) time_t time = ts->tv_sec; struct tm local_tm; struct tm *t = (struct tm*)SCLocalTime(time, &local_tm); + char time_fmt[64] = { 0 }; if (likely(t != NULL)) { - snprintf(str, size, "%04d-%02d-%02dT%02d:%02d:%02d.%06u", - t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, - t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); + strftime(time_fmt, sizeof(time_fmt), "%Y-%m-%dT%H:%M:%S.%%06u%z", t); + snprintf(str, size, time_fmt, ts->tv_usec); } else { snprintf(str, size, "ts-error"); } From 208d27abc76a8ab9280a91d9cfbdc16abe43b196 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Apr 2015 08:42:23 +0200 Subject: [PATCH 0416/2553] stream: next_seq handling improvements Allow next_seq updating to recover from cases where last_ack has been moved beyond it. This can happen if ACK's have been accepted for missing data that is later retransmitted. This undoes some of the previous last_ack update changes --- src/stream-tcp.c | 76 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 5cc5513ab54a..9c51f3351216 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -753,17 +753,14 @@ uint32_t StreamTcpGetStreamSize(TcpStream *stream) } /** - * \brief macro to update last_ack only if the new value is higher and - * the ack value isn't beyond the next_seq + * \brief macro to update last_ack only if the new value is higher * * \param ssn session * \param stream stream to update * \param ack ACK value to test and set */ #define StreamTcpUpdateLastAck(ssn, stream, ack) { \ - if (SEQ_GT((ack), (stream)->last_ack) && \ - (SEQ_LEQ((ack),(stream)->next_seq) || \ - ((ssn)->state >= TCP_FIN_WAIT1 && SEQ_EQ((ack),((stream)->next_seq + 1))))) \ + if (SEQ_GT((ack), (stream)->last_ack)) \ { \ (stream)->last_ack = (ack); \ SCLogDebug("ssn %p: last_ack set to %"PRIu32, (ssn), (stream)->last_ack); \ @@ -1882,6 +1879,7 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; + SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; ssn->server.next_win = ssn->server.last_ack + ssn->server.window; @@ -1999,6 +1997,19 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p)); ssn->flags |= STREAMTCP_FLAG_ASYNC; + /* if last ack is beyond next_seq, we have accepted ack's for missing data. + * In this case we do accept the data before last_ack if it is (partly) + * beyond next seq */ + } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) && + SEQ_GT((TCP_GET_SEQ(p)+p->payload_len),ssn->client.next_seq)) + { + SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16 + " before last_ack %"PRIu32", after next_seq %"PRIu32":" + " acked data that we haven't seen before", + ssn, TCP_GET_SEQ(p), p->payload_len, ssn->client.last_ack, ssn->client.next_seq); + if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq)) { + ssn->client.next_seq += p->payload_len; + } } else { SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ" " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " @@ -2025,6 +2036,14 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack ssn->client.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn, ssn->client.next_seq); + /* not completely as expected, but valid */ + } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->client.next_seq) && + SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->client.next_seq)) + { + ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; + SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32 + " (started before next_seq, ended after)", + ssn, ssn->client.next_seq); } /* in window check */ @@ -2049,11 +2068,6 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack StreamTcpHandleTimestamp(ssn, p); } - /* Update the next_seq, in case if we have missed the server packet - and client has already received and acked it */ - if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) - ssn->server.next_seq = TCP_GET_ACK(p); - StreamTcpSackUpdatePacket(&ssn->server, p); /* update next_win */ @@ -2134,10 +2148,23 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack ssn->server.last_ack = TCP_GET_SEQ(p); + /* if last ack is beyond next_seq, we have accepted ack's for missing data. + * In this case we do accept the data before last_ack if it is (partly) + * beyond next seq */ + } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) && + SEQ_GT((TCP_GET_SEQ(p)+p->payload_len),ssn->server.next_seq)) + { + SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16 + " before last_ack %"PRIu32", after next_seq %"PRIu32":" + " acked data that we haven't seen before", + ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq); + if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq)) { + ssn->server.next_seq += p->payload_len; + } } else { SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16 - " before last_ack %"PRIu32, - ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack); + " before last_ack %"PRIu32". next_seq %"PRIu32, + ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK); return -1; } @@ -2154,6 +2181,14 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack ssn->server.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); + /* not completely as expected, but valid */ + } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->server.next_seq) && + SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->server.next_seq)) + { + ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len; + SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 + " (started before next_seq, ended after)", + ssn, ssn->server.next_seq); } if (zerowindowprobe) { @@ -2173,11 +2208,6 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack StreamTcpHandleTimestamp(ssn, p); } - /* Update the next_seq, in case if we have missed the client packet - and server has already received and acked it */ - if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) - ssn->client.next_seq = TCP_GET_ACK(p); - StreamTcpSackUpdatePacket(&ssn->client, p); StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window)); @@ -10024,9 +10054,9 @@ static int StreamTcpTest38 (void) goto end; } - /* last_ack value should be 1, not 256, as the previous sent ACK value - is inside window, but beyond next_seq */ - if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 1) { + /* last_ack value should be 256, as the previous sent ACK value + is inside window */ + if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 256) { printf("the server.last_ack should be 1, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.last_ack); goto end; @@ -10046,10 +10076,10 @@ static int StreamTcpTest38 (void) goto end; } - /* last_ack value should be 2984 as the previous sent ACK value is inside + /* last_ack value should be 256 as the previous sent ACK value is inside window */ - if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 128) { - printf("the server.last_ack should be 128, but it is %"PRIu32"\n", + if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 256) { + printf("the server.last_ack should be 256, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.last_ack); goto end; } From f0c659f82f675a090fa08dacc008061a70db2550 Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Fri, 24 Apr 2015 14:28:32 -0400 Subject: [PATCH 0417/2553] Fix Bug #1204 Fix typo that causes eve syslog settings code to be unreachable. --- src/output-json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output-json.c b/src/output-json.c index aec2f67c4e73..78a915d42267 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -479,7 +479,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) exit(EXIT_FAILURE); } } - } else if (json_out == ALERT_SYSLOG) { + } else if (json_ctx->json_out == ALERT_SYSLOG) { const char *facility_s = ConfNodeLookupChildValue(conf, "facility"); if (facility_s == NULL) { facility_s = DEFAULT_ALERT_SYSLOG_FACILITY_STR; From d44eab82c1a015e3797a7aa4583072a121f8a2b7 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Thu, 16 Apr 2015 12:40:17 +0300 Subject: [PATCH 0418/2553] Fix bug #1435 (data loss when dumping payloads to JSON) --- src/output-json-alert.c | 39 ++++++++++++++++++++------------------- src/util-buffer.h | 2 -- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 3d567c0c6e32..f9783b28af29 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -93,12 +93,10 @@ typedef struct JsonAlertLogThread_ { /* Callback function to pack payload contents from a stream into a buffer * so we can report them in JSON output. */ -static int AlertJsonPrintStreamSegmentCallback(const Packet *p, void *data, uint8_t *buf, uint32_t buflen) +static int AlertJsonDumpStreamSegmentCallback(const Packet *p, void *data, uint8_t *buf, uint32_t buflen) { MemBuffer *payload = (MemBuffer *)data; - - PrintStringsToBuffer(payload->buffer, &payload->offset, payload->size, - buf, buflen); + MemBufferWriteRaw(payload, buf, buflen); return 1; } @@ -276,38 +274,41 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } StreamSegmentForEach((const Packet *)p, flag, - AlertJsonPrintStreamSegmentCallback, + AlertJsonDumpStreamSegmentCallback, (void *)payload); if (json_output_ctx->flags & LOG_JSON_PAYLOAD_BASE64) { unsigned long len = JSON_STREAM_BUFFER_SIZE * 2; - unsigned char encoded[len]; + uint8_t encoded[len]; Base64Encode((unsigned char *)payload, payload->offset, encoded, &len); json_object_set_new(js, "payload", json_string((char *)encoded)); } if (json_output_ctx->flags & LOG_JSON_PAYLOAD) { + uint8_t printable_buf[payload->offset + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + (unsigned char *)payload, payload->offset); json_object_set_new(js, "payload_printable", - json_string((char *)payload->buffer)); + json_string((char *)printable_buf)); } } else { /* This is a single packet and not a stream */ - unsigned char packet_buf[p->payload_len + 1]; - uint32_t offset = 0; - - PrintStringsToBuffer(packet_buf, &offset, - p->payload_len + 1, - p->payload, p->payload_len); - if (json_output_ctx->flags & LOG_JSON_PAYLOAD_BASE64) { - unsigned long len = sizeof(packet_buf) * 2; - unsigned char encoded[len]; - Base64Encode(packet_buf, offset, encoded, &len); + unsigned long len = p->payload_len * 2 + 1; + uint8_t encoded[len]; + Base64Encode(p->payload, p->payload_len, encoded, &len); json_object_set_new(js, "payload", json_string((char *)encoded)); } if (json_output_ctx->flags & LOG_JSON_PAYLOAD) { - json_object_set_new(js, "payload_printable", json_string((char *)packet_buf)); + uint8_t printable_buf[p->payload_len + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + p->payload_len + 1, + p->payload, p->payload_len); + json_object_set_new(js, "payload_printable", json_string((char *)printable_buf)); } } @@ -317,7 +318,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) /* base64-encoded full packet */ if (json_output_ctx->flags & LOG_JSON_PACKET) { unsigned long len = GET_PKT_LEN(p) * 2; - unsigned char encoded_packet[len]; + uint8_t encoded_packet[len]; Base64Encode((unsigned char*) GET_PKT_DATA(p), GET_PKT_LEN(p), encoded_packet, &len); json_object_set_new(js, "packet", json_string((char *)encoded_packet)); } diff --git a/src/util-buffer.h b/src/util-buffer.h index 602b4df06864..58d5098a2820 100644 --- a/src/util-buffer.h +++ b/src/util-buffer.h @@ -144,8 +144,6 @@ void MemBufferFree(MemBuffer *buffer); memcpy((dst)->buffer + (dst)->offset, (raw_buffer), write_len); \ (dst)->offset += write_len; \ dst->buffer[dst->offset] = '\0'; \ - \ - return; \ } while (0) /** From cf9da2be15e7042c20f96b6a573305f8d35268d4 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 20 Dec 2013 16:36:58 -0500 Subject: [PATCH 0419/2553] Fix DetectReplaceAddToList I see two problems: 1) If allocating a newlist fails, the function returns NULL, which then leaks any existing list elements. 2) The code to add the new value to the list works for the first two, but for not the third. For example, replist=A, A->next=B, B->next=NULL, then adding C results in replist=A, A->next=C, C->next=NULL, B is lost. The fix pushes new values onto the head of the list, which might not be what is needed, but there are no comments on what the function does, so I made an assumption. --- src/detect-replace.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/detect-replace.c b/src/detect-replace.c index 3bf725a992e1..0d1b2725765d 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -161,16 +161,13 @@ DetectReplaceList * DetectReplaceAddToList(DetectReplaceList *replist, uint8_t * newlist = SCMalloc(sizeof(DetectReplaceList)); if (unlikely(newlist == NULL)) - return NULL; + return replist; newlist->found = found; newlist->cd = cd; - newlist->next = NULL; + /* Push new value onto the front of the list. */ + newlist->next = replist; - if (replist) { - replist->next = newlist; - return replist; - } else - return newlist; + return newlist; } @@ -195,7 +192,7 @@ void DetectReplaceFreeInternal(DetectReplaceList *replist) { DetectReplaceList *tlist = NULL; while(replist) { - SCLogDebug("replace: Freing match"); + SCLogDebug("replace: Freeing match"); tlist = replist; replist = replist->next; SCFree(tlist); From ddec92676d27ed68c9e767a178e7bd4685a083bf Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Thu, 6 Feb 2014 10:12:24 -0500 Subject: [PATCH 0420/2553] Add a comment for DetectReplaceList Reworded a quote in PR 742 by Regit from Inliniac to explain why adding the head of the list (really a FIFO) is the correct behavior. --- src/detect-replace.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/detect-replace.c b/src/detect-replace.c index 0d1b2725765d..8e39004c630b 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2013 Open Information Security Foundation +/* Copyright (C) 2011-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 @@ -151,6 +151,14 @@ int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *replacestr) return -1; } +/* Add to the head of the replace-list. + * + * The first to add to the replace-list has the highest priority. So, + * adding the the head of the list results in the newest modifications + * of content being applied first, so later changes can over ride + * earlier changes. Thus the highest priority modifications should be + * applied last. + */ DetectReplaceList * DetectReplaceAddToList(DetectReplaceList *replist, uint8_t *found, DetectContentData *cd) { DetectReplaceList *newlist; From eac83be1216a554f99b668b053e8dd4f6cea6953 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Thu, 6 Feb 2014 10:22:17 -0500 Subject: [PATCH 0421/2553] Formatting cleanup in detect-replace.c Wrap lines longer than 80 characters Add "static" for unit tests. Use (void) for () for function arguments. Add space after "while(" -> "while (" Remove space after function names. Put open bracket of function on a new line. --- src/detect-replace.c | 60 +++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/detect-replace.c b/src/detect-replace.c index 8e39004c630b..57e06e7aeb4f 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -59,7 +59,7 @@ extern int run_mode; #include "host.h" #include "util-profiling.h" -static int DetectReplaceSetup (DetectEngineCtx *, Signature *, char *); +static int DetectReplaceSetup(DetectEngineCtx *, Signature *, char *); void DetectReplaceRegisterTests(void); void DetectReplaceRegister (void) @@ -159,7 +159,9 @@ int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *replacestr) * earlier changes. Thus the highest priority modifications should be * applied last. */ -DetectReplaceList * DetectReplaceAddToList(DetectReplaceList *replist, uint8_t *found, DetectContentData *cd) +DetectReplaceList *DetectReplaceAddToList(DetectReplaceList *replist, + uint8_t *found, + DetectContentData *cd) { DetectReplaceList *newlist; @@ -184,7 +186,7 @@ void DetectReplaceExecuteInternal(Packet *p, DetectReplaceList *replist) DetectReplaceList *tlist = NULL; SCLogDebug("replace: Executing match"); - while(replist) { + while (replist) { memcpy(replist->found, replist->cd->replace, replist->cd->replace_len); SCLogDebug("replace: injecting '%s'", replist->cd->replace); p->flags |= PKT_STREAM_MODIFIED; @@ -199,7 +201,7 @@ void DetectReplaceExecuteInternal(Packet *p, DetectReplaceList *replist) void DetectReplaceFreeInternal(DetectReplaceList *replist) { DetectReplaceList *tlist = NULL; - while(replist) { + while (replist) { SCLogDebug("replace: Freeing match"); tlist = replist; replist = replist->next; @@ -218,8 +220,10 @@ void DetectReplaceFreeInternal(DetectReplaceList *replist) * \retval return 1 if match * \retval return 0 if not */ -int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, char *sig, - uint32_t sid, uint8_t *pp, uint16_t *len) +static +int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, + char *sig, uint32_t sid, uint8_t *pp, + uint16_t *len) { int result = 0; @@ -385,7 +389,7 @@ int DetectReplaceLongPatternMatchTestUDPWrp(char *sig, uint32_t sid, char *sig_r /** * \test Check if replace is working */ -int DetectReplaceMatchTest01() +static int DetectReplaceMatchTest01(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; sid:1;)"; @@ -397,7 +401,7 @@ int DetectReplaceMatchTest01() /** * \test Check if replace is working with offset */ -int DetectReplaceMatchTest02() +static int DetectReplaceMatchTest02(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; offset: 4; replace:\"TH\"; sid:1;)"; @@ -409,7 +413,7 @@ int DetectReplaceMatchTest02() /** * \test Check if replace is working with offset and keyword inversion */ -int DetectReplaceMatchTest03() +static int DetectReplaceMatchTest03(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; replace:\"TH\"; offset: 4; sid:1;)"; @@ -421,7 +425,7 @@ int DetectReplaceMatchTest03() /** * \test Check if replace is working with second content */ -int DetectReplaceMatchTest04() +static int DetectReplaceMatchTest04(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; replace:\"TH\"; content:\"patter\"; replace:\"matter\"; sid:1;)"; @@ -433,7 +437,7 @@ int DetectReplaceMatchTest04() /** * \test Check if replace is not done when second content don't match */ -int DetectReplaceMatchTest05() +static int DetectReplaceMatchTest05(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; replace:\"TH\"; content:\"nutella\"; sid:1;)"; @@ -446,7 +450,7 @@ int DetectReplaceMatchTest05() * \test Check if replace is not done when second content match and not * first */ -int DetectReplaceMatchTest06() +static int DetectReplaceMatchTest06(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"nutella\"; replace:\"commode\"; content:\"this is\"; sid:1;)"; @@ -458,7 +462,7 @@ int DetectReplaceMatchTest06() /** * \test Check if replace is working when nocase used */ -int DetectReplaceMatchTest07() +static int DetectReplaceMatchTest07(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"BiG\"; nocase; replace:\"pig\"; sid:1;)"; @@ -470,7 +474,7 @@ int DetectReplaceMatchTest07() /** * \test Check if replace is working when depth is used */ -int DetectReplaceMatchTest08() +static int DetectReplaceMatchTest08(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; depth:17; replace:\"pig\"; sid:1;)"; @@ -482,7 +486,7 @@ int DetectReplaceMatchTest08() /** * \test Check if replace is working when depth block match used */ -int DetectReplaceMatchTest09() +static int DetectReplaceMatchTest09(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; depth:16; replace:\"pig\"; sid:1;)"; @@ -494,7 +498,7 @@ int DetectReplaceMatchTest09() /** * \test Check if replace is working when depth block match used */ -int DetectReplaceMatchTest10() +static int DetectReplaceMatchTest10(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; depth:17; replace:\"pig\"; offset: 14; sid:1;)"; @@ -506,7 +510,7 @@ int DetectReplaceMatchTest10() /** * \test Check if replace is working with within */ -int DetectReplaceMatchTest11() +static int DetectReplaceMatchTest11(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 11; sid:1;)"; @@ -518,7 +522,7 @@ int DetectReplaceMatchTest11() /** * \test Check if replace is working with within */ -int DetectReplaceMatchTest12() +static int DetectReplaceMatchTest12(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 4; sid:1;)"; @@ -530,7 +534,7 @@ int DetectReplaceMatchTest12() /** * \test Check if replace is working with within */ -int DetectReplaceMatchTest13() +static int DetectReplaceMatchTest13(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 1; sid:1;)"; @@ -542,7 +546,7 @@ int DetectReplaceMatchTest13() /** * \test Check if replace is working with within */ -int DetectReplaceMatchTest14() +static int DetectReplaceMatchTest14(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 2; sid:1;)"; @@ -554,7 +558,7 @@ int DetectReplaceMatchTest14() /** * \test Check if replace is working with within */ -int DetectReplaceMatchTest15() +static int DetectReplaceMatchTest15(void) { char *sig = "alert udp any any -> any any (msg:\"Nothing..\";" " content:\"com\"; replace:\"org\"; sid:1;)"; @@ -567,7 +571,7 @@ int DetectReplaceMatchTest15() /** * \test Parsing test */ -int DetectReplaceParseTest01(void) +static int DetectReplaceParseTest01(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -601,7 +605,7 @@ int DetectReplaceParseTest01(void) /** * \test Parsing test: non valid because of http protocol */ -int DetectReplaceParseTest02(void) +static int DetectReplaceParseTest02(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -636,7 +640,7 @@ int DetectReplaceParseTest02(void) * \test Parsing test: non valid because of http_header on same content * as replace keyword */ -int DetectReplaceParseTest03(void) +static int DetectReplaceParseTest03(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -670,7 +674,7 @@ int DetectReplaceParseTest03(void) /** * \test Parsing test no content */ -int DetectReplaceParseTest04(void) +static int DetectReplaceParseTest04(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -704,7 +708,7 @@ int DetectReplaceParseTest04(void) /** * \test Parsing test content after replace */ -int DetectReplaceParseTest05(void) +static int DetectReplaceParseTest05(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -738,7 +742,7 @@ int DetectReplaceParseTest05(void) /** * \test Parsing test content and replace length differ */ -int DetectReplaceParseTest06(void) +static int DetectReplaceParseTest06(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -772,7 +776,7 @@ int DetectReplaceParseTest06(void) /** * \test Parsing test content and replace length differ */ -int DetectReplaceParseTest07(void) +static int DetectReplaceParseTest07(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; From 41a1a9f4aff442bcad4d38ab9222c410fdaa5355 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Tue, 20 Jan 2015 10:28:38 +0100 Subject: [PATCH 0422/2553] find and replace HSBDMATCH by FILEDATA This commit do a find and replace of the following: - DETECT_SM_LIST_HSBDMATCH by DETECT_SM_LIST_FILEDATA sed -i 's/DETECT_SM_LIST_HSBDMATCH/DETECT_SM_LIST_FILEDATA/g' src/* - HSBD by FILEDATA: sed -i 's/HSBDMATCH/FILEDATA/g' src/* --- src/detect-byte-extract.c | 18 ++--- src/detect-bytejump.c | 20 +++--- src/detect-bytetest.c | 20 +++--- src/detect-content.c | 22 +++--- src/detect-depth.c | 2 +- src/detect-distance.c | 2 +- src/detect-engine-analyzer.c | 8 +-- src/detect-engine-hsbd.c | 2 +- src/detect-engine-mpm.c | 6 +- src/detect-engine.c | 6 +- src/detect-fast-pattern.c | 122 +++++++++++++++++++++------------- src/detect-file-data.c | 2 +- src/detect-http-server-body.c | 116 ++++++++++++++++---------------- src/detect-isdataat.c | 26 ++++---- src/detect-lua.c | 2 +- src/detect-nocase.c | 2 +- src/detect-offset.c | 2 +- src/detect-parse.c | 10 +-- src/detect-pcre.c | 26 ++++---- src/detect-pkt-data.c | 4 +- src/detect-within.c | 2 +- src/detect.c | 6 +- src/detect.h | 2 +- 23 files changed, 230 insertions(+), 198 deletions(-) diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 8dda193aa00f..bc8bdf2d6f92 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -553,7 +553,7 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) int sm_list; if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { + if (s->list == DETECT_SM_LIST_FILEDATA) { if (data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "dce byte_extract specified " "with file_data option set."); @@ -596,7 +596,7 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -611,7 +611,7 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -626,7 +626,7 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -641,7 +641,7 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -656,7 +656,7 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -671,7 +671,7 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -4758,11 +4758,11 @@ static int DetectByteExtractTest62(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { goto end; } - sm = s->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = s->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 2c9bd67b8840..46a2a3e49a41 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -536,7 +536,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) int sm_list; if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { + if (s->list == DETECT_SM_LIST_FILEDATA) { if (data->flags & DETECT_BYTEJUMP_DCE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "dce bytejump specified " "with file_data option set."); @@ -580,7 +580,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -595,7 +595,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -610,7 +610,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -625,7 +625,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -640,7 +640,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -655,7 +655,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -1179,15 +1179,15 @@ static int DetectBytejumpTestParse12(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_BYTEJUMP) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_BYTEJUMP) { goto end; } - bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if ((bd->flags & DETECT_BYTEJUMP_DCE) && (bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index d001fe900b0f..365ad55c8a69 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -462,7 +462,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) int sm_list; if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { + if (s->list == DETECT_SM_LIST_FILEDATA) { if (data->flags & DETECT_BYTETEST_DCE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "dce bytetest specified " "with file_data option set."); @@ -506,7 +506,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -521,7 +521,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -536,7 +536,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -551,7 +551,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -566,7 +566,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -581,7 +581,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -1355,17 +1355,17 @@ static int DetectBytetestTestParse22(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { printf("empty server body list: "); goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_BYTETEST) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_BYTETEST) { printf("bytetest not last sm in server body list: "); goto end; } - bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (bd->flags & DETECT_BYTETEST_DCE && bd->flags & DETECT_BYTETEST_RELATIVE && (bd->flags & DETECT_BYTETEST_STRING) && diff --git a/src/detect-content.c b/src/detect-content.c index f965bcbc244b..48eb2f64faf3 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -390,7 +390,7 @@ int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentstr) int sm_list; if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { + if (s->list == DETECT_SM_LIST_FILEDATA) { AppLayerHtpEnableResponseBodyCallback(); s->alproto = ALPROTO_HTTP; } @@ -1874,8 +1874,8 @@ static int DetectContentParseTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("content not in HSBDMATCH list: "); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("content not in FILEDATA list: "); goto end; } @@ -1914,8 +1914,8 @@ static int DetectContentParseTest37(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("content not in HSBDMATCH list: "); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("content not in FILEDATA list: "); goto end; } @@ -1954,8 +1954,8 @@ static int DetectContentParseTest38(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("content not in HSBDMATCH list: "); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("content not in FILEDATA list: "); goto end; } @@ -2038,8 +2038,8 @@ static int DetectContentParseTest39(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("content not in HSBDMATCH list: "); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("content not in FILEDATA list: "); goto end; } @@ -2078,8 +2078,8 @@ static int DetectContentParseTest40(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("content not in HSBDMATCH list: "); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("content not in FILEDATA list: "); goto end; } diff --git a/src/detect-depth.c b/src/detect-depth.c index 4aa33dee12c0..f58438dae473 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -80,7 +80,7 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], diff --git a/src/detect-distance.c b/src/detect-distance.c index 14af5c27ee0d..a8284dbeb339 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -88,7 +88,7 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 0faf08ec91a5..024c3c866d9f 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -90,7 +90,7 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "http cookie content\n"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(fp_engine_analysis_FD, "http client body content\n"); - else if (list_type == DETECT_SM_LIST_HSBDMATCH) + else if (list_type == DETECT_SM_LIST_FILEDATA) fprintf(fp_engine_analysis_FD, "http server body content\n"); else if (list_type == DETECT_SM_LIST_HSCDMATCH) fprintf(fp_engine_analysis_FD, "http stat code content\n"); @@ -421,7 +421,7 @@ static void EngineAnalysisRulesPrintFP(Signature *s) fprintf(rule_engine_analysis_FD, "http cookie content"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(rule_engine_analysis_FD, "http client body content"); - else if (list_type == DETECT_SM_LIST_HSBDMATCH) + else if (list_type == DETECT_SM_LIST_FILEDATA) fprintf(rule_engine_analysis_FD, "http server body content"); else if (list_type == DETECT_SM_LIST_HSCDMATCH) fprintf(rule_engine_analysis_FD, "http stat code content"); @@ -553,7 +553,7 @@ void EngineAnalysisRules(Signature *s, char *line) norm_http_buf += 1; http_cookie_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSBDMATCH) { + else if (list_id == DETECT_SM_LIST_FILEDATA) { rule_pcre_http += 1; http_server_body_buf += 1; raw_http_buf += 1; @@ -619,7 +619,7 @@ void EngineAnalysisRules(Signature *s, char *line) raw_http_buf += 1; http_client_body_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSBDMATCH) { + else if (list_id == DETECT_SM_LIST_FILEDATA) { rule_content_http += 1; raw_http_buf += 1; http_server_body_buf += 1; diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 05583727c9c7..cb798277187b 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -266,7 +266,7 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HSBDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_FILEDATA], f, buffer, buffer_len, diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 6da966a12daf..78f7f8a0c35a 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1446,7 +1446,7 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, case DETECT_SM_LIST_UMATCH: case DETECT_SM_LIST_HRUDMATCH: case DETECT_SM_LIST_HCBDMATCH: - case DETECT_SM_LIST_HSBDMATCH: + case DETECT_SM_LIST_FILEDATA: case DETECT_SM_LIST_HHDMATCH: case DETECT_SM_LIST_HRHDMATCH: case DETECT_SM_LIST_HMDMATCH: @@ -1477,7 +1477,7 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, s->flags |= SIG_FLAG_MPM_APPLAYER; if (cd->flags & DETECT_CONTENT_NEGATED) s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HSBDMATCH) { + } else if (sm_list == DETECT_SM_LIST_FILEDATA) { if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hsbd_ctx_tc; sgh->flags |= SIG_GROUP_HEAD_MPM_HSBD; @@ -1980,7 +1980,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) has_co_hcbd = 1; } - if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { + if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) { has_co_hsbd = 1; } diff --git a/src/detect-engine.c b/src/detect-engine.c index 4bf33eaefadd..02c317ea01d2 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -279,7 +279,7 @@ void DetectEngineRegisterAppInspectionEngines(void) struct tmp_t data_toclient[] = { { IPPROTO_TCP, ALPROTO_HTTP, - DETECT_SM_LIST_HSBDMATCH, + DETECT_SM_LIST_FILEDATA, DE_STATE_FLAG_HSBD_INSPECT, DE_STATE_FLAG_HSBD_INSPECT, 1, @@ -1855,7 +1855,7 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http raw uri"; case DETECT_SM_LIST_HCBDMATCH: return "http client body"; - case DETECT_SM_LIST_HSBDMATCH: + case DETECT_SM_LIST_FILEDATA: return "http server body"; case DETECT_SM_LIST_HHDMATCH: return "http headers"; @@ -2287,7 +2287,7 @@ int DetectEngineTest07(void) DE_STATE_FLAG_HCBD_INSPECT, 0, DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_HSBDMATCH, + { DETECT_SM_LIST_FILEDATA, DE_STATE_FLAG_HSBD_INSPECT, DE_STATE_FLAG_HSBD_INSPECT, 1, diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 90b0316ad23f..6d76cde97c89 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -115,7 +115,7 @@ static void SupportFastPatternForSigMatchList(int list_id, int priority) void SupportFastPatternForSigMatchTypes(void) { SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCBDMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSBDMATCH, 2); + SupportFastPatternForSigMatchList(DETECT_SM_LIST_FILEDATA, 2); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHDMATCH, 2); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHDMATCH, 2); @@ -214,7 +214,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL && + s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] == NULL && @@ -241,7 +241,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -13440,7 +13440,8 @@ int DetectFastPatternTest466(void) "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -13478,7 +13479,7 @@ int DetectFastPatternTest467(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -13515,7 +13516,7 @@ int DetectFastPatternTest468(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -13546,7 +13547,7 @@ int DetectFastPatternTest469(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm == NULL) { goto end; } @@ -13582,7 +13583,7 @@ int DetectFastPatternTest470(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm == NULL) { goto end; } @@ -13827,7 +13828,7 @@ int DetectFastPatternTest480(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13859,7 +13860,8 @@ int DetectFastPatternTest481(void) "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13891,7 +13893,8 @@ int DetectFastPatternTest482(void) "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13923,7 +13926,8 @@ int DetectFastPatternTest483(void) "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13954,7 +13958,8 @@ int DetectFastPatternTest484(void) "content:\"two\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14079,7 +14084,8 @@ int DetectFastPatternTest489(void) "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14111,7 +14117,8 @@ int DetectFastPatternTest490(void) "content:\"three\"; http_server_body; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14143,7 +14150,8 @@ int DetectFastPatternTest491(void) "content:\"three\"; http_server_body; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14175,7 +14183,8 @@ int DetectFastPatternTest492(void) "content:\"three\"; http_server_body; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14207,7 +14216,8 @@ int DetectFastPatternTest493(void) "content:\"three\"; http_server_body; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14239,7 +14249,8 @@ int DetectFastPatternTest494(void) "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14271,7 +14282,8 @@ int DetectFastPatternTest495(void) "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14303,7 +14315,8 @@ int DetectFastPatternTest496(void) "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14335,7 +14348,8 @@ int DetectFastPatternTest497(void) "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14442,7 +14456,8 @@ int DetectFastPatternTest501(void) "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14571,7 +14586,8 @@ int DetectFastPatternTest506(void) "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14609,7 +14625,8 @@ int DetectFastPatternTest507(void) "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14647,7 +14664,7 @@ int DetectFastPatternTest508(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -14684,7 +14701,7 @@ int DetectFastPatternTest509(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -14715,7 +14732,7 @@ int DetectFastPatternTest510(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm == NULL) { goto end; } @@ -14751,7 +14768,7 @@ int DetectFastPatternTest511(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm == NULL) { goto end; } @@ -14996,7 +15013,7 @@ int DetectFastPatternTest521(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15028,7 +15045,8 @@ int DetectFastPatternTest522(void) "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15060,7 +15078,8 @@ int DetectFastPatternTest523(void) "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15092,7 +15111,8 @@ int DetectFastPatternTest524(void) "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15123,7 +15143,8 @@ int DetectFastPatternTest525(void) "content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15248,7 +15269,8 @@ int DetectFastPatternTest530(void) "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15280,7 +15302,8 @@ int DetectFastPatternTest531(void) "content:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15312,7 +15335,8 @@ int DetectFastPatternTest532(void) "content:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15344,7 +15368,8 @@ int DetectFastPatternTest533(void) "content:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15376,7 +15401,8 @@ int DetectFastPatternTest534(void) "content:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15408,7 +15434,8 @@ int DetectFastPatternTest535(void) "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15440,7 +15467,8 @@ int DetectFastPatternTest536(void) "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15472,7 +15500,8 @@ int DetectFastPatternTest537(void) "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15504,7 +15533,8 @@ int DetectFastPatternTest538(void) "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15611,7 +15641,8 @@ int DetectFastPatternTest542(void) "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15740,7 +15771,8 @@ int DetectFastPatternTest547(void) "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && diff --git a/src/detect-file-data.c b/src/detect-file-data.c index 694f4d297d1d..3c18b4d6a218 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -81,7 +81,7 @@ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str return -1; } - s->list = DETECT_SM_LIST_HSBDMATCH; + s->list = DETECT_SM_LIST_FILEDATA; return 0; } diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index 9406aa12f25d..a5463b66b356 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -107,7 +107,7 @@ int DetectHttpServerBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_SERVER_BODY, - DETECT_SM_LIST_HSBDMATCH, + DETECT_SM_LIST_FILEDATA, ALPROTO_HTTP, DetectHttpServerBodySetupCallback); } @@ -167,7 +167,7 @@ static int DetectHttpServerBodyTest01(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm == NULL) { goto end; } @@ -1753,15 +1753,15 @@ int DetectHttpServerBodyTest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1808,15 +1808,15 @@ int DetectHttpServerBodyTest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1862,15 +1862,15 @@ int DetectHttpServerBodyTest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1917,15 +1917,15 @@ int DetectHttpServerBodyTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1973,15 +1973,15 @@ int DetectHttpServerBodyTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2056,15 +2056,15 @@ int DetectHttpServerBodyTest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2111,13 +2111,13 @@ int DetectHttpServerBodyTest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_DISTANCE || @@ -2155,13 +2155,13 @@ int DetectHttpServerBodyTest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_WITHIN || @@ -2271,21 +2271,21 @@ int DetectHttpServerBodyTest34(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hsbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { @@ -2322,21 +2322,21 @@ int DetectHttpServerBodyTest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "two", hsbd1->content_len) != 0) { @@ -2373,21 +2373,21 @@ int DetectHttpServerBodyTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hsbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index f2c3895392fa..2cac2bd794b1 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -261,7 +261,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst int sm_list; if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { + if (s->list == DETECT_SM_LIST_FILEDATA) { AppLayerHtpEnableResponseBodyCallback(); s->alproto = ALPROTO_HTTP; } @@ -277,7 +277,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -292,7 +292,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -307,7 +307,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -322,7 +322,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -337,7 +337,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -352,7 +352,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -987,17 +987,17 @@ static int DetectIsdataatTestParse14(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { printf("server body list empty: "); goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_ISDATAAT) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_ISDATAAT) { printf("last server body sm not isdataat: "); goto end; } - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { @@ -1037,17 +1037,17 @@ static int DetectIsdataatTestParse15(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { printf("server body list empty: "); goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_ISDATAAT) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_ISDATAAT) { printf("last server body sm not isdataat: "); goto end; } - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { diff --git a/src/detect-lua.c b/src/detect-lua.c index 5c0e1f6403af..660850184170 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1024,7 +1024,7 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); } else if (luajit->alproto == ALPROTO_HTTP) { if (luajit->flags & DATATYPE_HTTP_RESPONSE_BODY) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEDATA); else if (luajit->flags & DATATYPE_HTTP_REQUEST_BODY) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCBDMATCH); else if (luajit->flags & DATATYPE_HTTP_URI) diff --git a/src/detect-nocase.c b/src/detect-nocase.c index 694613512714..9968e3c45738 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -88,7 +88,7 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], diff --git a/src/detect-offset.c b/src/detect-offset.c index 6797267d0523..65372ec0af5d 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -79,7 +79,7 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], diff --git a/src/detect-parse.c b/src/detect-parse.c index 0f65cd466e10..d2c09af98793 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1131,7 +1131,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } else if (fd->flags & FLOW_PKT_TOSERVER) { /* check for uricontent + from_server/to_client */ - if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL || + if (/*s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL ||*/ s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use http_" @@ -1152,7 +1152,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) s->flags |= SIG_FLAG_TOSERVER; s->flags &= ~SIG_FLAG_TOCLIENT; } - if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL || + if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL || s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { sig_flags |= SIG_FLAG_TOCLIENT; @@ -1248,7 +1248,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -1269,7 +1269,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] || + s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] || s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] || @@ -1453,7 +1453,7 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HCBDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HSBDMATCH]) + if (sig->sm_lists[DETECT_SM_LIST_FILEDATA]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index dd359feb23e8..5b84afaf2b08 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -446,7 +446,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, break; case 'Q': /* suricata extension (http response body inspection) */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HSBDMATCH); + *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_FILEDATA); break; case 'Y': /* snort's option */ @@ -653,7 +653,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst if (parsed_sm_list == DETECT_SM_LIST_UMATCH || parsed_sm_list == DETECT_SM_LIST_HRUDMATCH || parsed_sm_list == DETECT_SM_LIST_HCBDMATCH || - parsed_sm_list == DETECT_SM_LIST_HSBDMATCH || + parsed_sm_list == DETECT_SM_LIST_FILEDATA || parsed_sm_list == DETECT_SM_LIST_HHDMATCH || parsed_sm_list == DETECT_SM_LIST_HRHDMATCH || parsed_sm_list == DETECT_SM_LIST_HSMDMATCH || @@ -681,7 +681,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst int sm_list = -1; if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { + if (s->list == DETECT_SM_LIST_FILEDATA) { SCLogDebug("adding to http server body list because of file data"); AppLayerHtpEnableResponseBodyCallback(); } else if (s->list == DETECT_SM_LIST_DMATCH) { @@ -700,7 +700,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst sm_list = parsed_sm_list; break; - case DETECT_SM_LIST_HSBDMATCH: + case DETECT_SM_LIST_FILEDATA: AppLayerHtpEnableResponseBodyCallback(); s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; @@ -1167,17 +1167,17 @@ static int DetectPcreParseTest12(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { printf("empty server body list: "); goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE) { printf("last sm not pcre: "); goto end; } - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE)) { printf("flags not right: "); @@ -1216,17 +1216,17 @@ static int DetectPcreParseTest13(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { printf("empty server body list: "); goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE) { printf("last sm not pcre: "); goto end; } - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE)) { printf("flags not right: "); @@ -1265,17 +1265,17 @@ static int DetectPcreParseTest14(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { printf("empty server body list: "); goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) { + if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE) { printf("last sm not pcre: "); goto end; } - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; if (data->flags & DETECT_PCRE_RAWBYTES || data->flags & DETECT_PCRE_RELATIVE) { printf("flags not right: "); diff --git a/src/detect-pkt-data.c b/src/detect-pkt-data.c index 332ac4ccdce6..df65444a5d70 100644 --- a/src/detect-pkt-data.c +++ b/src/detect-pkt-data.c @@ -106,9 +106,9 @@ static int DetectPktDataTest01(void) } /* sm should be in the MATCH list */ - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; if (sm == NULL) { - printf("sm not in DETECT_SM_LIST_HSBDMATCH: "); + printf("sm not in DETECT_SM_LIST_FILEDATA: "); goto end; } diff --git a/src/detect-within.c b/src/detect-within.c index 0aefdffc8162..25c97238676b 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -92,7 +92,7 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, char *within DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], diff --git a/src/detect.c b/src/detect.c index 648c69ef7e01..ec665944e1c7 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2055,7 +2055,7 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) + if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) @@ -2182,7 +2182,7 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, Signature *s) s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL || + s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || @@ -2332,7 +2332,7 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { + if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } diff --git a/src/detect.h b/src/detect.h index 295950295d02..5cec5aa58e86 100644 --- a/src/detect.h +++ b/src/detect.h @@ -90,7 +90,7 @@ enum DetectSigmatchListEnum { /* 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, + DETECT_SM_LIST_FILEDATA, /* 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 */ From 04561f13d375989b25b4c17e71415ca711d0ac8f Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Thu, 5 Feb 2015 15:04:13 +0100 Subject: [PATCH 0423/2553] signature: set flags and test the protocol This checks if the signature's protocol is http when setup the content keyword. Also sets the proper flags based by protocol since the flag SIG_FLAG_TOSERVER has to be set if the proto is smtp, otherwise SIG_FLAG_TOCLIENT is it's http. --- src/detect-content.c | 2 +- src/detect-parse.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/detect-content.c b/src/detect-content.c index 48eb2f64faf3..cd0722eae84f 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -390,7 +390,7 @@ int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentstr) int sm_list; if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_FILEDATA) { + if (s->list == DETECT_SM_LIST_FILEDATA && s->alproto == ALPROTO_HTTP) { AppLayerHtpEnableResponseBodyCallback(); s->alproto = ALPROTO_HTTP; } diff --git a/src/detect-parse.c b/src/detect-parse.c index d2c09af98793..4b084d0e2519 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1143,7 +1143,8 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || + if ((s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_SMTP) || + s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || @@ -1152,7 +1153,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) s->flags |= SIG_FLAG_TOSERVER; s->flags &= ~SIG_FLAG_TOCLIENT; } - if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL || + if ((s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_HTTP) || s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { sig_flags |= SIG_FLAG_TOCLIENT; From 68cf3dd621fff203e976d40a9a48fe03f29930e9 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Tue, 20 Jan 2015 12:02:16 +0100 Subject: [PATCH 0424/2553] file_data: register keyword for smtp and tcp protocol Permits to use file_data keyword with smtp or tcp proto. Also adds some unit tests --- src/detect-file-data.c | 101 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/src/detect-file-data.c b/src/detect-file-data.c index 3c18b4d6a218..e0186e5ec44c 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -44,7 +44,7 @@ #include "util-unittest-helper.h" static int DetectFiledataSetup (DetectEngineCtx *, Signature *, char *); - +static void DetectFiledataRegisterTests(void); /** * \brief Registration function for keyword: file_data */ @@ -58,7 +58,7 @@ void DetectFiledataRegister(void) sigmatch_table[DETECT_FILE_DATA].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILE_DATA].Setup = DetectFiledataSetup; sigmatch_table[DETECT_FILE_DATA].Free = NULL; - sigmatch_table[DETECT_FILE_DATA].RegisterTests = NULL; + sigmatch_table[DETECT_FILE_DATA].RegisterTests = DetectFiledataRegisterTests; sigmatch_table[DETECT_FILE_DATA].flags = SIGMATCH_NOOPT; } @@ -76,12 +76,105 @@ void DetectFiledataRegister(void) static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); - if ((s->init_flags & SIG_FLAG_INIT_FLOW) && (s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with flow:to_server or from_client with http."); + + if (!DetectProtoContainsProto(&s->proto, IPPROTO_TCP) && + s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP && + s->alproto != ALPROTO_SMTP) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); return -1; } + if ((s->init_flags & SIG_FLAG_INIT_FLOW) && + (s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with flow:to_server or from_client with http or smtp."); + return -1; + } + s->list = DETECT_SM_LIST_FILEDATA; return 0; } + +#ifdef UNITTESTS +static int DetectFiledataParseTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert smtp any any -> any any " + "(msg:\"test\"; file_data; content:\"abc\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("sig parse failed: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("content is still in FILEDATA list: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("content not in FILEDATA list: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +static int DetectFiledataParseTest02(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"test\"; file_data; content:\"abc\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("sig parse failed: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("content is still in PMATCH list: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("content not in FILEDATA list: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} +#endif + +void DetectFiledataRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectFiledataParseTest01", DetectFiledataParseTest01, 1); + UtRegisterTest("DetectFiledataParseTest02", DetectFiledataParseTest02, 1); +#endif +} From b9468aba7cbc03481165939cbe62de5f5ff2154a Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Tue, 20 Jan 2015 17:20:57 +0100 Subject: [PATCH 0425/2553] FileData: add stream_offset field This is required to store the offset for reassembling chunks. --- src/util-file.c | 5 +++++ src/util-file.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/util-file.c b/src/util-file.c index 56be73eee65f..de24261dad75 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -492,6 +492,11 @@ int FileAppendData(FileContainer *ffc, uint8_t *data, uint32_t data_len) SCReturnInt(-1); } + if (ffc->tail->chunks_head == NULL) + ffd->stream_offset = 0; + else + ffd->stream_offset = ffc->tail->size; + /* append the data */ if (FileAppendFileData(ffc, ffd) < 0) { ffc->tail->state = FILE_STATE_ERROR; diff --git a/src/util-file.h b/src/util-file.h index 36419ffbf3f6..18c137843456 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -53,6 +53,7 @@ typedef enum FileState_ { typedef struct FileData_ { uint8_t *data; uint32_t len; + uint64_t stream_offset; int stored; /* true if this chunk has been stored already * false otherwise */ struct FileData_ *next; From f0c54d47648bd7e973bd315fc0c2d1351af50d02 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Tue, 20 Jan 2015 17:38:06 +0100 Subject: [PATCH 0426/2553] Detect engine for smtp file_data file_data: inspecting smtp attachments Create a buffer to store reassembled file chunks, and inspect the content. --- src/Makefile.am | 1 + src/detect-engine-content-inspection.h | 1 + src/detect-engine-filedata-smtp.c | 217 +++++++++++++++++++++++++ src/detect-engine-filedata-smtp.h | 34 ++++ src/detect-engine-state.h | 1 + src/detect-engine.c | 9 + src/detect.h | 12 ++ 7 files changed, 275 insertions(+) create mode 100644 src/detect-engine-filedata-smtp.c create mode 100644 src/detect-engine-filedata-smtp.h diff --git a/src/Makefile.am b/src/Makefile.am index d802d21174ed..aacf9eccd0a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -96,6 +96,7 @@ detect-engine-dns.c detect-engine-dns.h \ detect-engine-modbus.c detect-engine-modbus.h \ detect-engine-event.c detect-engine-event.h \ detect-engine-file.c detect-engine-file.h \ +detect-engine-filedata-smtp.c detect-engine-filedata-smtp.h \ detect-engine-hcbd.c detect-engine-hcbd.h \ detect-engine-hcd.c detect-engine-hcd.h \ detect-engine-hhd.c detect-engine-hhd.h \ diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index ab12c25118d7..6d3accaaa324 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -49,6 +49,7 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, }; int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c new file mode 100644 index 000000000000..6cd1adb8684a --- /dev/null +++ b/src/detect-engine-filedata-smtp.c @@ -0,0 +1,217 @@ +/* Copyright (C) 2015 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 Giuseppe Longo + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-engine-content-inspection.h" + +#include "flow-util.h" +#include "util-debug.h" +#include "util-print.h" +#include "flow.h" + +#include "stream-tcp.h" + +#include "app-layer-parser.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer.h" +#include "app-layer-smtp.h" +#include "app-layer-protos.h" + +#include "conf.h" +#include "conf-yaml-loader.h" + +#define BUFFER_STEP 50 + +static inline int SMTPCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) +{ + void *ptmp; + if (size > det_ctx->smtp_buffers_size) { + ptmp = SCRealloc(det_ctx->smtp, + (det_ctx->smtp_buffers_size + BUFFER_STEP) * sizeof(FiledataReassembledBody)); + if (ptmp == NULL) { + SCFree(det_ctx->hsbd); + det_ctx->smtp = NULL; + det_ctx->smtp_buffers_size = 0; + det_ctx->smtp_buffers_list_len = 0; + return -1; + } + det_ctx->smtp = ptmp; + + memset(det_ctx->smtp + det_ctx->smtp_buffers_size, 0, BUFFER_STEP * sizeof(FiledataReassembledBody)); + det_ctx->smtp_buffers_size += BUFFER_STEP; + } + for (int i = det_ctx->smtp_buffers_list_len; i < (size); i++) { + det_ctx->smtp[i].buffer_len = 0; + det_ctx->smtp[i].offset = 0; + } + + return 0; +} + +static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Flow *f, File *curr_file, + uint8_t flags, + uint32_t *buffer_len, + uint32_t *stream_start_offset) +{ + int index = 0; + uint8_t *buffer = NULL; + *buffer_len = 0; + *stream_start_offset = 0; + FileData *curr_chunk = NULL; + + if (det_ctx->smtp_buffers_list_len == 0) { + if (SMTPCreateSpace(det_ctx, 1) < 0) + goto end; + index = 0; + + if (det_ctx->smtp_buffers_list_len == 0) { + det_ctx->smtp_start_tx_id = tx_id; + } + det_ctx->smtp_buffers_list_len++; + } else { + if ((tx_id - det_ctx->smtp_start_tx_id) < det_ctx->smtp_buffers_list_len) { + if (det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len != 0) { + *buffer_len = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len; + *stream_start_offset = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].offset; + return det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer; + } + } else { + if (SMTPCreateSpace(det_ctx, (tx_id - det_ctx->smtp_start_tx_id) + 1) < 0) + goto end; + + if (det_ctx->smtp_buffers_list_len == 0) { + det_ctx->smtp_start_tx_id = tx_id; + } + det_ctx->smtp_buffers_list_len++; + } + index = (tx_id - det_ctx->smtp_start_tx_id); + } + + if (curr_file != NULL) { + curr_chunk = curr_file->chunks_head; + while (curr_chunk != NULL) { + /* see if we can filter out chunks */ + + /* see if we need to grow the buffer */ + if (det_ctx->smtp[index].buffer == NULL || (det_ctx->smtp[index].buffer_len + curr_chunk->len) > det_ctx->smtp[index].buffer_size) { + void *ptmp; + det_ctx->smtp[index].buffer_size += curr_chunk->len * 2; + + if ((ptmp = SCRealloc(det_ctx->smtp[index].buffer, det_ctx->smtp[index].buffer_size)) == NULL) { + SCFree(det_ctx->smtp[index].buffer); + det_ctx->smtp[index].buffer = NULL; + det_ctx->smtp[index].buffer_size = 0; + det_ctx->smtp[index].buffer_len = 0; + goto end; + } + det_ctx->smtp[index].buffer = ptmp; + } + memcpy(det_ctx->smtp[index].buffer + det_ctx->smtp[index].buffer_len, curr_chunk->data, curr_chunk->len); + det_ctx->smtp[index].buffer_len += curr_chunk->len; + + curr_chunk = curr_chunk->next; + } + } + + buffer = det_ctx->smtp[index].buffer; + *buffer_len = det_ctx->smtp[index].buffer_len; + *stream_start_offset = det_ctx->smtp[index].offset; +end: + return buffer; +} + +int DetectEngineInspectSMTPFiledata(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *tx, uint64_t tx_id) +{ + SMTPState *smtp_state = (SMTPState *)alstate; + FileContainer *ffc = smtp_state->files_ts; + int r = 0; + int match = 0; + uint32_t buffer_len = 0; + uint32_t stream_start_offset = 0; + uint8_t *buffer = 0; + + if (ffc != NULL) { + File *file = ffc->head; + for (; file != NULL; file = file->next) { + buffer = DetectEngineSMTPGetBufferForTX(tx_id, + de_ctx, det_ctx, + f, file, + flags, + &buffer_len, + &stream_start_offset); + if (buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + match = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_FILEDATA], + f, + buffer, + buffer_len, + stream_start_offset, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, NULL); + if (match == 1) + r = 1; + } + } + +end: + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + else + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx->smtp_buffers_list_len > 0) { + for (int i = 0; i < det_ctx->smtp_buffers_list_len; i++) { + det_ctx->smtp[i].buffer_len = 0; + det_ctx->smtp[i].offset = 0; + } + } + det_ctx->smtp_buffers_list_len = 0; + det_ctx->smtp_start_tx_id = 0; + + return; +} diff --git a/src/detect-engine-filedata-smtp.h b/src/detect-engine-filedata-smtp.h new file mode 100644 index 000000000000..b574b974c2a0 --- /dev/null +++ b/src/detect-engine-filedata-smtp.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2015 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 Giuseppe Longo + */ + +#ifndef __DETECT_ENGINE_FILEDATA_SMTP_H__ +#define __DETECT_ENGINE_FILEDATA_SMTP_H__ + +int DetectEngineInspectSMTPFiledata(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *tx, uint64_t tx_id); +void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx); + +#endif /* __DETECT_ENGINE_FILEDATA_SMTP_H__ */ diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 464f7180fd1c..ab30ccffed72 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -78,6 +78,7 @@ #define DE_STATE_FLAG_APP_EVENT_INSPECT (1 << 18) #define DE_STATE_FLAG_MODBUS_INSPECT (1 << 19) #define DE_STATE_FLAG_HRL_INSPECT (1 << 20) +#define DE_STATE_FLAG_FD_SMTP_INSPECT (1 << 21) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine.c b/src/detect-engine.c index 02c317ea01d2..742a2560c9e4 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -61,6 +61,7 @@ #include "detect-engine-file.h" #include "detect-engine-dns.h" #include "detect-engine-modbus.h" +#include "detect-engine-filedata-smtp.h" #include "detect-engine.h" #include "detect-engine-state.h" @@ -274,6 +275,14 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_MODBUS_INSPECT, 0, DetectEngineInspectModbus }, + /* file_data smtp */ + { IPPROTO_TCP, + ALPROTO_SMTP, + DETECT_SM_LIST_FILEDATA, + DE_STATE_FLAG_FD_SMTP_INSPECT, + DE_STATE_FLAG_FD_SMTP_INSPECT, + 0, + DetectEngineInspectSMTPFiledata }, }; struct tmp_t data_toclient[] = { diff --git a/src/detect.h b/src/detect.h index 5cec5aa58e86..f34b46c7d0fb 100644 --- a/src/detect.h +++ b/src/detect.h @@ -767,6 +767,13 @@ typedef struct HttpReassembledBody_ { uint64_t offset; /**< data offset */ } HttpReassembledBody; +typedef struct FiledataReassembledBody_ { + 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 */ +} FiledataReassembledBody; + #define DETECT_FILESTORE_MAX 15 /** \todo review how many we actually need here */ #define DETECT_SMSG_PMQ_NUM 256 @@ -812,6 +819,11 @@ typedef struct DetectEngineThreadCtx_ { uint16_t hhd_buffers_list_len; uint64_t hhd_start_tx_id; + FiledataReassembledBody *smtp; + uint64_t smtp_start_tx_id; + uint16_t smtp_buffers_size; + uint16_t smtp_buffers_list_len; + /** id for alert counter */ uint16_t counter_alerts; #ifdef PROFILING From 84dc73d9dee4ddc7f5d33aea861541e2d0450d30 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Wed, 21 Jan 2015 20:39:34 +0100 Subject: [PATCH 0427/2553] mpm: implement prefiltering for smtp --- src/detect-engine-filedata-smtp.c | 31 +++++++++++ src/detect-engine-filedata-smtp.h | 7 +++ src/detect-engine-mpm.c | 90 +++++++++++++++++++++++++++++-- src/detect-engine-mpm.h | 1 + src/detect.c | 50 ++++++++++++++++- src/detect.h | 3 ++ src/suricata-common.h | 1 + 7 files changed, 178 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 6cd1adb8684a..7f0ff13e7f32 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -215,3 +215,34 @@ void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx) return; } + +int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Flow *f, + SMTPState *smtp_state, uint8_t flags, + void *tx, uint64_t idx) +{ + FileContainer *ffc = smtp_state->files_ts; + uint32_t cnt = 0; + uint32_t buffer_len = 0; + uint32_t stream_start_offset = 0; + uint8_t *buffer = 0; + + if (ffc != NULL) { + File *file = ffc->head; + for (; file != NULL; file = file->next) { + buffer = DetectEngineSMTPGetBufferForTX(idx, + de_ctx, det_ctx, + f, file, + flags, + &buffer_len, + &stream_start_offset); + + if (buffer_len == 0) + goto end; + + cnt = SMTPFiledataPatternSearch(det_ctx, buffer, buffer_len, flags); + } + } +end: + return cnt; +} diff --git a/src/detect-engine-filedata-smtp.h b/src/detect-engine-filedata-smtp.h index b574b974c2a0..666c9e56b471 100644 --- a/src/detect-engine-filedata-smtp.h +++ b/src/detect-engine-filedata-smtp.h @@ -23,6 +23,8 @@ #ifndef __DETECT_ENGINE_FILEDATA_SMTP_H__ #define __DETECT_ENGINE_FILEDATA_SMTP_H__ +#include "app-layer-smtp.h" + int DetectEngineInspectSMTPFiledata(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -31,4 +33,9 @@ int DetectEngineInspectSMTPFiledata(ThreadVars *tv, void *tx, uint64_t tx_id); void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx); +int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Flow *f, + SMTPState *smtp_state, uint8_t flags, + void *tx, uint64_t idx); + #endif /* __DETECT_ENGINE_FILEDATA_SMTP_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 78f7f8a0c35a..1cbf2770975a 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -737,6 +737,36 @@ uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p, SCReturnInt(ret); } +/** + * \brief SMTP Filedata match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param buffer Buffer to inspect. + * \param buffer_len buffer length. + * \param flags Flags + * + * \retval ret Number of matches. + */ +uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *buffer, uint32_t buffer_len, + uint8_t flags) +{ + SCEnter(); + + uint32_t ret = 0; + + if (flags & STREAM_TOSERVER) { + if (det_ctx->sgh->mpm_smtp_filedata_ctx_ts == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_smtp_filedata_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_smtp_filedata_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); + } + + SCReturnUInt(ret); +} + /** \brief cleans up the mpm instance after a match */ void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) { @@ -944,6 +974,16 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) } } + if (sh->mpm_smtp_filedata_ctx_ts != NULL) { + if (sh->mpm_smtp_filedata_ctx_ts != NULL) { + if (!sh->mpm_smtp_filedata_ctx_ts->global) { + mpm_table[sh->mpm_smtp_filedata_ctx_ts->mpm_type].DestroyCtx(sh->mpm_smtp_filedata_ctx_ts); + SCFree(sh->mpm_smtp_filedata_ctx_ts); + } + sh->mpm_smtp_filedata_ctx_ts = NULL; + } + } + if (sh->mpm_hhd_ctx_ts != NULL || sh->mpm_hhd_ctx_tc != NULL) { if (sh->mpm_hhd_ctx_ts != NULL) { if (!sh->mpm_hhd_ctx_ts->global) { @@ -1478,9 +1518,14 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, if (cd->flags & DETECT_CONTENT_NEGATED) s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; } else if (sm_list == DETECT_SM_LIST_FILEDATA) { - if (s->flags & SIG_FLAG_TOCLIENT) + if (s->flags & SIG_FLAG_TOCLIENT) { mpm_ctx_tc = sgh->mpm_hsbd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HSBD; + sgh->flags |= SIG_GROUP_HEAD_MPM_HSBD; + } + if (s->flags & SIG_FLAG_TOSERVER) { + mpm_ctx_ts = sgh->mpm_smtp_filedata_ctx_ts; + sgh->flags |= SIG_GROUP_HEAD_MPM_FD_SMTP; + } s->flags |= SIG_FLAG_MPM_APPLAYER; if (cd->flags & DETECT_CONTENT_NEGATED) s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; @@ -1934,6 +1979,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) uint32_t has_co_hcbd = 0; /* used to indicate if sgh has atleast one sig with http_server_body */ uint32_t has_co_hsbd = 0; + /* used to indicate if sgh has smtp file_data inspecting content */ + uint32_t has_co_smtp = 0; /* used to indicate if sgh has atleast one sig with http_header */ uint32_t has_co_hhd = 0; /* used to indicate if sgh has atleast one sig with http_raw_header */ @@ -1981,7 +2028,14 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) } if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) { - has_co_hsbd = 1; + if (s->alproto == ALPROTO_SMTP) + has_co_smtp = 1; + else if (s->alproto == ALPROTO_HTTP) + has_co_hsbd = 1; + else if (s->alproto == ALPROTO_UNKNOWN) { + has_co_smtp = 1; + has_co_hsbd = 1; + } } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { @@ -2131,6 +2185,20 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) MpmInitCtx(sh->mpm_hsbd_ctx_tc, de_ctx->mpm_matcher); } + if (has_co_smtp) { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { + sh->mpm_smtp_filedata_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_smtp, 0); + } else { + sh->mpm_smtp_filedata_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); + } + if (sh->mpm_smtp_filedata_ctx_ts == NULL) { + SCLogDebug("sh->mpm_smtp_filedata_ctx_ts == NULL. This should never happen"); + exit(EXIT_FAILURE); + } + + MpmInitCtx(sh->mpm_smtp_filedata_ctx_ts, de_ctx->mpm_matcher); + } + if (has_co_hhd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 0); @@ -2299,6 +2367,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) has_co_uri || has_co_hcbd || has_co_hsbd || + has_co_smtp || has_co_hhd || has_co_hrhd || has_co_hmd || @@ -2442,6 +2511,19 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) } } + if (sh->mpm_smtp_filedata_ctx_ts != NULL) { + if (sh->mpm_smtp_filedata_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_smtp_filedata_ctx_ts); + sh->mpm_smtp_filedata_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_smtp_filedata_ctx_ts->mpm_type].Prepare != NULL) { + mpm_table[sh->mpm_smtp_filedata_ctx_ts->mpm_type].Prepare(sh->mpm_smtp_filedata_ctx_ts); + } + } + } + } + if (sh->mpm_hhd_ctx_ts != NULL) { if (sh->mpm_hhd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_ts); @@ -2639,6 +2721,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_hrhhd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_dnsquery_ctx_ts); sh->mpm_dnsquery_ctx_ts = NULL; + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_smtp_filedata_ctx_ts); + sh->mpm_smtp_filedata_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_tc); sh->mpm_proto_tcp_ctx_tc = NULL; diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 05178e46fc19..02df56f47bdc 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -52,6 +52,7 @@ uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8 uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *buffer, uint32_t buffer_len, uint8_t flags); +uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *buffer, uint32_t buffer_len, uint8_t flags); void PacketPatternCleanup(ThreadVars *, DetectEngineThreadCtx *); void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg); diff --git a/src/detect.c b/src/detect.c index ec665944e1c7..9b08e8852a0e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -49,6 +49,7 @@ #include "detect-dns-query.h" #include "detect-engine-state.h" #include "detect-engine-analyzer.h" +#include "detect-engine-filedata-smtp.h" #include "detect-http-cookie.h" #include "detect-http-method.h" @@ -160,6 +161,7 @@ #include "app-layer.h" #include "app-layer-protos.h" #include "app-layer-htp.h" +#include "app-layer-smtp.h" #include "detect-tls.h" #include "detect-tls-version.h" #include "detect-ssh-proto-version.h" @@ -988,6 +990,32 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, FLOWLOCK_UNLOCK(p->flow); } } + } else if (alproto == ALPROTO_SMTP && has_state) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_FD_SMTP) { + FLOWLOCK_RDLOCK(p->flow); + void *alstate = FlowGetAppState(p->flow); + if (alstate == NULL) { + SCLogDebug("no alstate"); + FLOWLOCK_UNLOCK(p->flow); + return; + } + + SMTPState *smtp_state = (SMTPState *)alstate; + uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); + uint64_t total_txs = AppLayerParserGetTxCnt(p->flow->proto, alproto, alstate); + for (; idx < total_txs; idx++) { + void *tx = AppLayerParserGetTx(p->flow->proto, alproto, alstate, idx); + if (tx == NULL) + continue; + + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_FD_SMTP); + DetectEngineRunSMTPMpm(de_ctx, det_ctx, p->flow, smtp_state, flags, tx, idx); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_FD_SMTP); + } + FLOWLOCK_UNLOCK(p->flow); + } + } } if (smsg != NULL && (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_STREAM)) { @@ -2333,8 +2361,13 @@ static int SignatureCreateMask(Signature *s) } if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); + /* set the state depending from the protocol */ + if (s->alproto == ALPROTO_HTTP) + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; + else if (s->alproto == ALPROTO_SMTP) + s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; + + SCLogDebug("sig requires http or smtp app state"); } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { @@ -2561,6 +2594,9 @@ static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) de_ctx->sgh_mpm_context_hsbd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hsbd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); + de_ctx->sgh_mpm_context_smtp = + MpmFactoryRegisterMpmCtxProfile(de_ctx, "smtp", + MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hhd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hhd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); @@ -4698,6 +4734,16 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) } //printf("hsbd- %d\n", mpm_ctx->pattern_cnt); + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_smtp, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_smtp, 1); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + //printf("smtp- %d\n"; mpm_ctx->pattern_cnt); + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); diff --git a/src/detect.h b/src/detect.h index f34b46c7d0fb..3b5ff6005cfb 100644 --- a/src/detect.h +++ b/src/detect.h @@ -705,6 +705,7 @@ typedef struct DetectEngineCtx_ { int32_t sgh_mpm_context_hrhhd; int32_t sgh_mpm_context_app_proto_detect; int32_t sgh_mpm_context_dnsquery; + int32_t sgh_mpm_context_smtp; /* the max local id used amongst all sigs */ int32_t byte_extract_max_local_id; @@ -962,6 +963,7 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_HAVEFILEMD5 (1 << 21) #define SIG_GROUP_HEAD_HAVEFILESIZE (1 << 22) #define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 23) +#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 24) typedef struct SigGroupHeadInitData_ { /* list of content containers @@ -1024,6 +1026,7 @@ typedef struct SigGroupHead_ { MpmCtx *mpm_hhhd_ctx_ts; MpmCtx *mpm_hrhhd_ctx_ts; MpmCtx *mpm_dnsquery_ctx_ts; + MpmCtx *mpm_smtp_filedata_ctx_ts; MpmCtx *mpm_proto_tcp_ctx_tc; MpmCtx *mpm_proto_udp_ctx_tc; diff --git a/src/suricata-common.h b/src/suricata-common.h index d7126a874f82..98545fd80397 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -313,6 +313,7 @@ typedef enum PacketProfileDetectId_ { PROF_DETECT_ALERT, PROF_DETECT_CLEANUP, PROF_DETECT_GETSGH, + PROF_DETECT_MPM_FD_SMTP, PROF_DETECT_SIZE, } PacketProfileDetectId; From d2657becc9bc5e9fea6c0dd2fdc874eaa7e89924 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Tue, 10 Feb 2015 15:21:35 +0100 Subject: [PATCH 0428/2553] app-layer-smtp: make functions as public --- src/app-layer-smtp.c | 60 ++++++++++++++++++++++---------------------- src/app-layer-smtp.h | 5 ++++ 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 1a0894f0f98c..4bf3e4607edd 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -291,7 +291,7 @@ static SMTPTransaction *SMTPTransactionCreate(void) return tx; } -static int ProcessDataChunk(const uint8_t *chunk, uint32_t len, +int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state) { int ret = MIME_DEC_OK; @@ -965,7 +965,7 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, SCMemcmpLowercase("data", state->current_line, 4) == 0) { state->current_command = SMTP_COMMAND_DATA; if (smtp_config.decode_mime) { - tx->mime_state = MimeDecInitParser(f, ProcessDataChunk); + tx->mime_state = MimeDecInitParser(f, SMTPProcessDataChunk); if (tx->mime_state == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to " "allocate data"); @@ -1080,7 +1080,7 @@ static int SMTPParseServerRecord(Flow *f, void *alstate, * \internal * \brief Function to allocate SMTP state memory. */ -static void *SMTPStateAlloc(void) +void *SMTPStateAlloc(void) { SMTPState *smtp_state = SCMalloc(sizeof(SMTPState)); if (unlikely(smtp_state == NULL)) @@ -4603,7 +4603,7 @@ int SMTPProcessDataChunkTest01(void){ f.flags = FLOW_FILE_NO_STORE_TS; MimeDecParseState *state = MimeDecInitParser(&f, NULL); int ret; - ret = ProcessDataChunk(NULL, 0, state); + ret = SMTPProcessDataChunk(NULL, 0, state); return ret; } @@ -4660,7 +4660,7 @@ int SMTPProcessDataChunkTest02(void){ ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; state->body_begin = 1; int ret; - ret = ProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); return ret; @@ -4690,31 +4690,31 @@ int SMTPProcessDataChunkTest03(void){ int ret; state->body_begin = 1; - ret = ProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); if(ret) goto end; state->body_begin = 0; - ret = ProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state); if(ret) goto end; - ret = ProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state); if(ret) goto end; - ret = ProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state); if(ret) goto end; - ret = ProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state); if(ret) goto end; - ret = ProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state); if(ret) goto end; - ret = ProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state); if(ret) goto end; - ret = ProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state); if(ret) goto end; - ret = ProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state); if(ret) goto end; - ret = ProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state); if(ret) goto end; - ret = ProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state); if(ret) goto end; state->body_end = 1; - ret = ProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state); if(ret) goto end; end: @@ -4743,20 +4743,20 @@ int SMTPProcessDataChunkTest04(void){ int ret = MIME_DEC_OK; state->body_begin = 1; - if(ProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end; - if(ProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end; - if(ProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end; - if(ProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end; - if(ProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end; - if(ProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end; - if(ProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end; state->body_begin = 0; state->body_end = 1; - if(ProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end; state->body_end = 0; - if(ProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end; - if(ProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end; - if(ProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end; end: return ret; @@ -4779,7 +4779,7 @@ int SMTPProcessDataChunkTest05(void){ state->body_begin = 1; int ret; uint64_t file_size = 0; - ret = ProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); state->body_begin = 0; if(ret){goto end;} SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate; @@ -4790,7 +4790,7 @@ int SMTPProcessDataChunkTest05(void){ FileDisableStoring(&f, STREAM_TOSERVER); FileDisableMagic(&f, STREAM_TOSERVER); FileDisableMd5(&f, STREAM_TOSERVER); - ret = ProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); if(ret){goto end;} printf("%u\t%u\n", (uint32_t) file->size, (uint32_t) file_size); if(file->size == file_size){ diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index eca2003180fa..b11e335b1c9b 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -129,6 +129,11 @@ typedef struct SMTPState_ { } SMTPState; +/* Create SMTP config structure */ +extern SMTPConfig smtp_config; + +int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state); +void *SMTPStateAlloc(void); void RegisterSMTPParsers(void); void SMTPParserRegisterTests(void); From 1f52410d0fdac1e2eb95256cee40b7e2aeb46d39 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Fri, 30 Jan 2015 10:36:55 +0100 Subject: [PATCH 0429/2553] UT: implement tests for inspection code --- src/detect-engine-filedata-smtp.c | 274 ++++++++++++++++++++++++++++++ src/detect-engine-filedata-smtp.h | 2 + src/runmode-unittests.c | 2 + 3 files changed, 278 insertions(+) diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 7f0ff13e7f32..c9eedd4df532 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -47,6 +47,7 @@ #include "app-layer.h" #include "app-layer-smtp.h" #include "app-layer-protos.h" +#include "app-layer-parser.h" #include "conf.h" #include "conf-yaml-loader.h" @@ -246,3 +247,276 @@ int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, end: return cnt; } + +#ifdef UNITTESTS + +static int DetectEngineSMTPFiledataTest01(void) +{ + uint8_t mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, + 0x20, 0x74, 0x65, 0x78, 0x74, 0x2F, 0x70, 0x6C, + 0x61, 0x69, 0x6E, 0x3B, 0x20, 0x63, 0x68, 0x61, + 0x72, 0x73, 0x65, 0x74, 0x3D, 0x55, 0x54, 0x46, + 0x2D, 0x38, 0x3B, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, + 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, + 0x6E, 0x73, 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, + 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, + 0x37, 0x62, 0x69, 0x74, 0x0D, 0x0A, 0x43, 0x6F, + 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69, + 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, + 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66, + 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D, + 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x74, 0x78, + 0x74, 0x22, 0x0D, 0x0A, 0x0D, 0x0A, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65,}; + uint32_t mimemsg_len = sizeof(mimemsg) - 1; + TcpSession ssn; + Packet *p; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + SMTPState *smtp_state = NULL; + Flow f; + int result = 0; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + f.alstate = SMTPStateAlloc(); + + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + state->body_begin = 1; + + if (SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) + goto end; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert smtp any any -> any any " + "(msg:\"file_data smtp test\"; " + "file_data; content:\"message\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, mimemsg, mimemsg_len); + if (r != 0) { + printf("AppLayerParse for smtp failed. Returned %d", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have\n"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +static int DetectEngineSMTPFiledataTest02(void) +{ + Signature *s = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert smtp any any -> any any " + "(msg:\"file_data smtp test\"; " + "file_data; content:\"message\"; sid:1;)"); + if (s == NULL) + goto end; + + if (s->flags & SIG_FLAG_TOSERVER) + result = 1; + else if (s->flags & SIG_FLAG_TOCLIENT) + printf("s->flags & SIG_FLAG_TOCLIENT"); + +end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; + +} + +static int DetectEngineSMTPFiledataTest03(void) +{ + uint8_t mimemsg1[] = {0x65, 0x76,}; + uint8_t mimemsg2[] = {0x69, 0x6C,}; + uint32_t mimemsg1_len = sizeof(mimemsg1) - 1; + uint32_t mimemsg2_len = sizeof(mimemsg2) - 1; + TcpSession ssn; + Packet *p; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + SMTPState *smtp_state = NULL; + Flow f; + int result = 1; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + f.alstate = SMTPStateAlloc(); + + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + state->body_begin = 1; + + if (SMTPProcessDataChunk((uint8_t *)mimemsg1, sizeof(mimemsg1), state) != 0) + goto end; + + if (SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) + goto end; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert smtp any any -> any any " + "(msg:\"file_data smtp test\"; " + "file_data; content:\"evil\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = 0; + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, mimemsg1, mimemsg1_len); + if (r != 0) { + printf("AppLayerParse for smtp failed. Returned %d", r); + SCMutexUnlock(&f.m); + goto end; + } + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, mimemsg2, mimemsg2_len); + if (r != 0) { + printf("AppLayerParse for smtp failed. Returned %d", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + result = 0; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +#endif /* UNITTESTS */ + +void DetectEngineSMTPFiledataRegisterTests(void) +{ + #ifdef UNITTESTS + UtRegisterTest("DetectEngineSMTPFiledataTest01", + DetectEngineSMTPFiledataTest01, 1); + UtRegisterTest("DetectEngineSMTPFiledataTest02", + DetectEngineSMTPFiledataTest02, 1); + UtRegisterTest("DetectEngineSMTPFiledataTest03", + DetectEngineSMTPFiledataTest03, 0); + #endif /* UNITTESTS */ + + return; +} diff --git a/src/detect-engine-filedata-smtp.h b/src/detect-engine-filedata-smtp.h index 666c9e56b471..e04832b77b0e 100644 --- a/src/detect-engine-filedata-smtp.h +++ b/src/detect-engine-filedata-smtp.h @@ -38,4 +38,6 @@ int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, SMTPState *smtp_state, uint8_t flags, void *tx, uint64_t idx); +void DetectEngineSMTPFiledataRegisterTests(void); + #endif /* __DETECT_ENGINE_FILEDATA_SMTP_H__ */ diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index e7a8b34d2745..378d3c801e52 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -51,6 +51,7 @@ #include "detect-engine-state.h" #include "detect-engine-tag.h" #include "detect-engine-modbus.h" +#include "detect-engine-filedata-smtp.h" #include "detect-fast-pattern.h" #include "flow.h" #include "flow-timeout.h" @@ -261,6 +262,7 @@ void RunUnittests(int list_unittests, char *regex_arg) DetectEngineHttpHRHRegisterTests(); DetectEngineInspectModbusRegisterTests(); DetectEngineRegisterTests(); + DetectEngineSMTPFiledataRegisterTests(); SCLogRegisterTests(); MagicRegisterTests(); UtilMiscRegisterTests(); From 4b5848616f903997674f57e1ed3e1af561d0ba95 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Tue, 10 Mar 2015 16:21:14 +0100 Subject: [PATCH 0430/2553] filedata: implement inspected tracker --- src/detect-engine-filedata-smtp.c | 46 +++++++++++++++++++++++++++++++ src/util-file.c | 2 ++ src/util-file.h | 2 ++ 3 files changed, 50 insertions(+) diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index c9eedd4df532..6f2bbbad62b7 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -53,6 +53,9 @@ #include "conf-yaml-loader.h" #define BUFFER_STEP 50 +#define FILECONTENT_CONTENT_LIMIT 1000 +#define FILECONTENT_INSPECT_MIN_SIZE 1000 +#define FILECONTENT_INSPECT_WINDOW 1000 static inline int SMTPCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) { @@ -122,10 +125,50 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, index = (tx_id - det_ctx->smtp_start_tx_id); } + /* no new data */ + if (curr_file->content_inspected == curr_file->content_len_so_far) { + SCLogDebug("no new data"); + goto end; + } + + curr_chunk = curr_file->chunks_head; + if (curr_chunk == NULL) { + SCLogDebug("no data chunks to inspect for this transaction"); + goto end; + } + + if ((FILECONTENT_CONTENT_LIMIT == 0 || + curr_file->content_len_so_far < FILECONTENT_CONTENT_LIMIT) && + curr_file->content_len_so_far < FILECONTENT_INSPECT_MIN_SIZE && + !(flags & STREAM_EOF)) { + SCLogDebug("we still haven't seen the entire content. " + "Let's defer content inspection till we see the " + "entire content."); + goto end; + } + if (curr_file != NULL) { + int first = 1; curr_chunk = curr_file->chunks_head; while (curr_chunk != NULL) { /* see if we can filter out chunks */ + if (curr_file->content_inspected > 0) { + if (curr_chunk->stream_offset < curr_file->content_inspected) { + if ((curr_file->content_inspected - curr_chunk->stream_offset) > FILECONTENT_INSPECT_WINDOW) { + curr_chunk = curr_chunk->next; + continue; + } else { + /* include this one */ + } + } else { + /* include this one */ + } + } + + if (first) { + det_ctx->smtp[index].offset = curr_chunk->stream_offset; + first = 0; + } /* see if we need to grow the buffer */ if (det_ctx->smtp[index].buffer == NULL || (det_ctx->smtp[index].buffer_len + curr_chunk->len) > det_ctx->smtp[index].buffer_size) { @@ -146,6 +189,9 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, curr_chunk = curr_chunk->next; } + + /* updat inspected tracker */ + curr_file->content_inspected = curr_file->chunks_tail->stream_offset + curr_file->chunks_tail->len; } buffer = det_ctx->smtp[index].buffer; diff --git a/src/util-file.c b/src/util-file.c index de24261dad75..bfb68e1e0363 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -97,9 +97,11 @@ static int FileAppendFileDataFilePtr(File *ff, FileData *ffd) if (ff->chunks_tail == NULL) { ff->chunks_head = ffd; ff->chunks_tail = ffd; + ff->content_len_so_far = ffd->len; } else { ff->chunks_tail->next = ffd; ff->chunks_tail = ffd; + ff->content_len_so_far += ffd->len; } #ifdef DEBUG diff --git a/src/util-file.h b/src/util-file.h index 18c137843456..9cfc3a85936e 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -79,6 +79,8 @@ typedef struct File_ { uint64_t chunks_cnt; uint64_t chunks_cnt_max; #endif + uint64_t content_len_so_far; + uint64_t content_inspected; } File; typedef struct FileContainer_ { From 26ba647d58c01efce2e38ac31194b884046c2084 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Thu, 7 May 2015 23:34:15 +0200 Subject: [PATCH 0431/2553] filedata: read inspected tracker settings from suricata.yaml --- src/app-layer-smtp.c | 52 ++++++++++++++++++++++++++----- src/app-layer-smtp.h | 9 ++++++ src/detect-engine-filedata-smtp.c | 11 +++---- suricata.yaml.in | 6 +++- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 4bf3e4607edd..e03cad89470c 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -55,6 +55,14 @@ #include "conf.h" #include "util-mem.h" +#include "util-misc.h" + +/* content-limit default value */ +#define FILEDATA_CONTENT_LIMIT 1000 +/* content-inspect-min-size default value */ +#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 1000 +/* content-inspect-window default value */ +#define FILEDATA_CONTENT_INSPECT_WINDOW 1000 #define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510 @@ -211,15 +219,8 @@ SCEnumCharMap smtp_reply_map[ ] = { { NULL, -1 }, }; -typedef struct SMTPConfig { - - int decode_mime; - MimeDecConfig mime_config; - -} SMTPConfig; - /* Create SMTP config structure */ -static SMTPConfig smtp_config = { 0, { 0, 0, 0, 0 } }; +SMTPConfig smtp_config = { 0, { 0, 0, 0, 0 }, 0, 0, 0}; /** * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML @@ -232,6 +233,9 @@ static void SMTPConfigure(void) { SCEnter(); int ret = 0, val; intmax_t imval; + uint32_t content_limit = 0; + uint32_t content_inspect_min_size = 0; + uint32_t content_inspect_window = 0; ConfNode *config = ConfGetNode("app-layer.protocols.smtp.mime"); if (config != NULL) { @@ -265,6 +269,38 @@ static void SMTPConfigure(void) { /* Pass mime config data to MimeDec API */ MimeDecSetConfig(&smtp_config.mime_config); + ConfNode *t = ConfGetNode("app-layer.protocols.smtp.inspected-tracker"); + ConfNode *p = NULL; + + if (t == NULL) + return; + + TAILQ_FOREACH(p, &t->head, next) { + if (strcasecmp("content-limit", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_limit) < 0) { + SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-limit " + "from conf file - %s. Killing engine", p->val); + content_limit = FILEDATA_CONTENT_LIMIT; + } + } + + if (strcasecmp("content-inspect-min-size", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) { + SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-inspect-min-size-limit " + "from conf file - %s. Killing engine", p->val); + content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; + } + } + + if (strcasecmp("content-inspect-window", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) { + SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-inspect-window " + "from conf file - %s. Killing engine", p->val); + content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; + } + } + } + SCReturn; } diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index b11e335b1c9b..02090c61c07e 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -68,6 +68,15 @@ typedef struct SMTPTransaction_ { TAILQ_ENTRY(SMTPTransaction_) next; } SMTPTransaction; +typedef struct SMTPConfig { + + int decode_mime; + MimeDecConfig mime_config; + uint32_t content_limit; + uint32_t content_inspect_min_size; + uint32_t content_inspect_window; +} SMTPConfig; + typedef struct SMTPState_ { SMTPTransaction *curr_tx; TAILQ_HEAD(, SMTPTransaction_) tx_list; /**< transaction list */ diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 6f2bbbad62b7..f3687607f7e3 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -53,9 +53,6 @@ #include "conf-yaml-loader.h" #define BUFFER_STEP 50 -#define FILECONTENT_CONTENT_LIMIT 1000 -#define FILECONTENT_INSPECT_MIN_SIZE 1000 -#define FILECONTENT_INSPECT_WINDOW 1000 static inline int SMTPCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) { @@ -137,9 +134,9 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, goto end; } - if ((FILECONTENT_CONTENT_LIMIT == 0 || - curr_file->content_len_so_far < FILECONTENT_CONTENT_LIMIT) && - curr_file->content_len_so_far < FILECONTENT_INSPECT_MIN_SIZE && + if ((smtp_config.content_limit == 0 || + curr_file->content_len_so_far < smtp_config.content_limit) && + curr_file->content_len_so_far < smtp_config.content_inspect_min_size && !(flags & STREAM_EOF)) { SCLogDebug("we still haven't seen the entire content. " "Let's defer content inspection till we see the " @@ -154,7 +151,7 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, /* see if we can filter out chunks */ if (curr_file->content_inspected > 0) { if (curr_chunk->stream_offset < curr_file->content_inspected) { - if ((curr_file->content_inspected - curr_chunk->stream_offset) > FILECONTENT_INSPECT_WINDOW) { + if ((curr_file->content_inspected - curr_chunk->stream_offset) > smtp_config.content_inspect_window) { curr_chunk = curr_chunk->next; continue; } else { diff --git a/suricata.yaml.in b/suricata.yaml.in index 8189cbede699..8d16815bee46 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1238,7 +1238,11 @@ app-layer: # Extract URLs and save in state data structure extract-urls: yes - + # Configure inspected-tracker for file_data keyword + inspected-tracker: + content-limit: 1000 + content-inspect-min-size: 1000 + content-inspect-window: 1000 imap: enabled: detection-only msn: From 58582df1c6644c1ca9cf2dfcde237b32476ab60e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 1 Oct 2014 16:15:06 +0200 Subject: [PATCH 0432/2553] decode-der: decode DC keyword 'DC' is used by some certificates and it was not currently translated to a string. --- src/util-decode-der-get.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util-decode-der-get.c b/src/util-decode-der-get.c index f2ac3f74be9e..4323eb39d4ec 100644 --- a/src/util-decode-der-get.c +++ b/src/util-decode-der-get.c @@ -66,6 +66,9 @@ static const char *Oid2ShortStr(const char *oid) if (strcmp(oid, "2.5.4.11")==0) return "OU"; + if (strcmp(oid, "0.9.2342.19200300.100.1.25")==0) + return "DC"; + return "unknown"; } From da98b0b84f4c36a77e6c141404cccf22d47501c7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 10 Jun 2014 09:43:56 +0200 Subject: [PATCH 0433/2553] coccinelle: update struct flags test --- qa/coccinelle/struct-flags.cocci | 54 ++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/qa/coccinelle/struct-flags.cocci b/qa/coccinelle/struct-flags.cocci index d7204aada4b8..45fab73415da 100644 --- a/qa/coccinelle/struct-flags.cocci +++ b/qa/coccinelle/struct-flags.cocci @@ -1,18 +1,20 @@ @flags@ -TcpSegment *struct0; -identifier struct_flags0 =~ "^(?!SEGMENTTCP_FLAG).+"; -TcpStream *struct1; -identifier struct_flags1 =~ "^(?!STREAMTCP_STREAM_FLAG_).+"; -TcpSession *struct2; -identifier struct_flags2 =~ "^(?!STREAMTCP_FLAG).+"; -Packet *struct3; -identifier struct_flags3 =~ "^(?!FLOW_PKT_).+"; -SignatureHeader *struct4; -identifier struct_flags4 =~ "^(?!SIG_FLAG).+"; -Signature *struct5; -identifier struct_flags5 =~ "^(?!SIG_FLAG).+"; -Signature *struct6; -identifier struct_flags6 =~ "^(?!SIG_FLAG_INIT_).+"; +SignatureHeader *struct0; +identifier struct_flags0 =~ "^(?!SIG_FLAG).+"; +Signature *struct1; +identifier struct_flags1 =~ "^(?!SIG_FLAG).+"; +Signature *struct2; +identifier struct_flags2 =~ "^(?!SIG_FLAG_INIT_).+"; +Flow *struct3; +identifier struct_flags3 =~ "^(?!FLOW_).+"; +TcpSegment *struct4; +identifier struct_flags4 =~ "^(?!SEGMENTTCP_FLAG).+"; +TcpStream *struct5; +identifier struct_flags5 =~ "^(?!STREAMTCP_STREAM_FLAG_).+"; +TcpSession *struct6; +identifier struct_flags6 =~ "^(?!STREAMTCP_FLAG).+"; +Packet *struct7; +identifier struct_flags7 =~ "^(?!FLOW_PKT_).+"; position p1; @@ @@ -29,17 +31,17 @@ struct1->flags@p1 & struct_flags1 | struct1->flags@p1 &= ~struct_flags1 | -struct2->flags@p1 |= struct_flags2 +struct2->init_flags@p1 |= struct_flags2 | -struct2->flags@p1 & struct_flags2 +struct2->init_flags@p1 & struct_flags2 | -struct2->flags@p1 &= ~struct_flags2 +struct2->init_flags@p1 &= ~struct_flags2 | -struct3->flowflags@p1 |= struct_flags3 +struct3->flags@p1 |= struct_flags3 | -struct3->flowflags@p1 & struct_flags3 +struct3->flags@p1 & struct_flags3 | -struct3->flowflags@p1 &= ~struct_flags3 +struct3->flags@p1 &= ~struct_flags3 | struct4->flags@p1 |= struct_flags4 | @@ -53,11 +55,17 @@ struct5->flags@p1 & struct_flags5 | struct5->flags@p1 &= ~struct_flags5 | -struct6->init_flags@p1 |= struct_flags6 +struct6->flags@p1 |= struct_flags6 | -struct6->init_flags@p1 & struct_flags6 +struct6->flags@p1 & struct_flags6 | -struct6->init_flags@p1 &= ~struct_flags6 +struct6->flags@p1 &= ~struct_flags6 +| +struct7->flowflags@p1 |= struct_flags7 +| +struct7->flowflags@p1 & struct_flags7 +| +struct7->flowflags@p1 &= ~struct_flags7 ) @script:python@ From 268285c49f2ab2141c9217cc21aeffbf366cb555 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 18 Nov 2014 11:07:59 +0100 Subject: [PATCH 0434/2553] output-json-http: output status as an integer HTTP status is an integer and it should be written as such in the JSON events. This will allow to have improved matching in log analysis tools. --- src/output-json-http.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/output-json-http.c b/src/output-json-http.c index b5a63bf294d0..bef5335f2d60 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -327,7 +327,8 @@ void JsonHttpLogJSONExtended(json_t *js, htp_tx_t *tx) if (tx->response_status != NULL) { c = bstr_util_strdup_to_c(tx->response_status); if (c != NULL) { - json_object_set_new(js, "status", json_string(c)); + unsigned int val = strtoul(c, NULL, 10); + json_object_set_new(js, "status", json_integer(val)); SCFree(c); } From 43f691fef8d003edf6a6c849edb91d9be6f6082b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 25 Jan 2015 19:31:45 +0100 Subject: [PATCH 0435/2553] util-device: fix LiveBuildDeviceListCustom The code was assuming that the dictionnary containing the parameter of a interface was ordered. But for YAML, the order is not assumed so in case the configuration is generated we may not be able to parse correctly the configuration file. By iterating on child on main node and then iterating on subchild and doing a match on the name, we are able to find the interface list. In term of code, this algorithm was obtained by simply removing the test on the name of the first child. --- src/util-device.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/util-device.c b/src/util-device.c index a98b45759743..c08e30f0b89d 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -151,17 +151,15 @@ int LiveBuildDeviceListCustom(char * runmode, char * itemname) return 0; TAILQ_FOREACH(child, &base->head, next) { - if (!strcmp(child->val, itemname)) { - ConfNode *subchild; - TAILQ_FOREACH(subchild, &child->head, next) { - if ((!strcmp(subchild->name, itemname))) { - if (!strcmp(subchild->val, "default")) - break; - SCLogInfo("Adding %s %s from config file", - itemname, subchild->val); - LiveRegisterDevice(subchild->val); - i++; - } + ConfNode *subchild; + TAILQ_FOREACH(subchild, &child->head, next) { + if ((!strcmp(subchild->name, itemname))) { + if (!strcmp(subchild->val, "default")) + break; + SCLogInfo("Adding %s %s from config file", + itemname, subchild->val); + LiveRegisterDevice(subchild->val); + i++; } } } From 0303245761942d5bd5dd455042003e12d68394da Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 25 Jan 2015 20:49:28 +0100 Subject: [PATCH 0436/2553] af-packet: use max packet size as snaplen If default_packet_size is set to 0, then we use the maximum packet size as snaplen. --- src/source-af-packet.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 813987959a77..718cdbf65456 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1340,6 +1340,15 @@ frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + siz int tp_hdrlen = sizeof(struct tpacket_hdr); int snaplen = default_packet_size; + if (snaplen == 0) { + snaplen = GetIfaceMaxPacketSize(ptv->iface); + if (snaplen <= 0) { + SCLogWarning(SC_ERR_INVALID_VALUE, + "Unable to get MTU, setting snaplen to sane default of 1514"); + snaplen = 1514; + } + } + ptv->req.tp_frame_size = TPACKET_ALIGN(snaplen +TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); ptv->req.tp_block_size = getpagesize() << order; int frames_per_block = ptv->req.tp_block_size / ptv->req.tp_frame_size; From 0e2a4c01bacf71ac7b11ab34f0511a30e182a5b2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 May 2015 16:09:24 +0200 Subject: [PATCH 0437/2553] Update changelog for 2.1beta4 release --- ChangeLog | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/ChangeLog b/ChangeLog index 9e57c6298ca6..a265dd7657b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,40 @@ +2.1beta4 -- 2015-05-08 + +Bug #1314: http-events performance issues +Bug #1340: null ptr dereference in Suricata v2.1beta2 (output-json.c:347) +Bug #1352: file list is not cleaned up +Bug #1358: Gradual memory leak using reload (kill -USR2 $pid) +Bug #1366: Crash if default_packet_size is below 32 bytes +Bug #1378: stats api doesn't call thread deinit funcs +Bug #1384: tcp midstream window issue (master) +Bug #1388: pcap-file hangs on systems w/o atomics support (master) +Bug #1392: http uri parsing issue (master) +Bug #1393: CentOS 5.11 build failures +Bug #1398: DCERPC traffic parsing issue (master) +Bug #1401: inverted matching on incomplete session +Bug #1402: When re-opening files on HUP (rotation) always use the append flag. +Bug #1417: no rules loaded - latest git - rev e250040 +Bug #1425: dead lock in de_state vs flowints/flowvars +Bug #1426: Files prematurely truncated by detection engine even though force-md5 is enabled +Bug #1429: stream: last_ack update issue leading to stream gaps +Bug #1435: EVE-Log alert payload option loses data +Bug #1441: Local timestamps in json events +Bug #1446: Unit ID check in Modbus packet error +Bug #1449: smtp parsing issue +Bug #1451: Fix list-keywords regressions +Bug #1463: modbus parsing issue +Feature #336: Add support for NETMAP to Suricata. +Feature #885: smtp file_data support +Feature #1394: Improve TCP reuse support +Feature #1410: add alerts to EVE's drop logs +Feature #1445: Suricata does not work on pfSense/FreeBSD interfaces using PPPoE +Feature #1447: Ability to reject ICMP traffic +Feature #1448: xbits +Optimization #1014: app layer reassembly fast-path +Optimization #1377: flow manager: reduce (try)locking +Optimization #1403: autofp packet pool performance problems +Optimization #1409: http pipeline support for stateful detection + 2.1beta3 -- 2015-01-29 Bug #977: WARNING on empty rules file is fatal (should not be) From 2f85308afe216e399a164018d375932dca57093b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Jan 2015 11:06:35 +0100 Subject: [PATCH 0438/2553] threads: fix missing unlock in error handling If TmThreadsUnregisterThread was called with out of range 'id', a lock would not be cleared after returning from the function. ** CID 1264421: Missing unlock (LOCK) /src/tm-threads.c: 2186 in TmThreadsUnregisterThread() --- src/tm-threads.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index b7fb3a695797..92f35e5178d8 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -2112,8 +2112,10 @@ int TmThreadsRegisterThread(ThreadVars *tv, const int type) void TmThreadsUnregisterThread(const int id) { SCMutexLock(&thread_store_lock); - if (id <= 0 || id > (int)thread_store.threads_size) + if (id <= 0 || id > (int)thread_store.threads_size) { + SCMutexUnlock(&thread_store_lock); return; + } /* id is one higher than index */ int idx = id - 1; From 52195a419213e49f60a9a46f5abe48be3d8b4f5c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 18 Oct 2014 21:46:59 +0200 Subject: [PATCH 0439/2553] http: add event for leading spaces on request line Libhtp will issue a warning in this case, so we can match on this. This patch adds event, rule and unittest. --- rules/http-events.rules | 4 +- src/app-layer-htp.c | 83 +++++++++++++++++++++++++++++++++++++++++ src/app-layer-htp.h | 1 + 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/rules/http-events.rules b/rules/http-events.rules index 5f733637537c..3c83a68411f8 100644 --- a/rules/http-events.rules +++ b/rules/http-events.rules @@ -45,6 +45,8 @@ alert http any any -> any any (msg:"SURICATA HTTP Host header invalid"; flow:est alert http any any -> any any (msg:"SURICATA HTTP URI terminated by non-compliant character"; flow:established,to_server; app-layer-event:http.uri_delim_non_compliant; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221029; rev:1;) # Method is terminated by non-compliant characters. RFC allows for space (0x20), but many implementations permit others like tab and more. alert http any any -> any any (msg:"SURICATA HTTP METHOD terminated by non-compliant character"; flow:established,to_server; app-layer-event:http.method_delim_non_compliant; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221030; rev:1;) +# Request line started with whitespace +alert http any any -> any any (msg:"SURICATA HTTP Request line with leading whitespace"; flow:established,to_server; app-layer-event:http.request_line_leading_whitespace; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221031; rev:1;) -# next sid 2221031 +# next sid 2221032 diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 1c1380bb1200..8ae86fe1b42b 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -148,6 +148,8 @@ SCEnumCharMap http_decoder_event_table[ ] = { HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT}, { "METHOD_DELIM_NON_COMPLIANT", HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT}, + { "REQUEST_LINE_LEADING_WHITESPACE", + HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE}, /* suricata warnings/errors */ { "MULTIPART_GENERIC_ERROR", @@ -506,6 +508,7 @@ struct { { "Request server port=", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, { "Request line: URI contains non-compliant delimiter", HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT}, { "Request line: non-compliant delimiter between Method and URI", HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT}, + { "Request line: leading whitespace", HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE}, }; #define HTP_ERROR_MAX (sizeof(htp_errors) / sizeof(htp_errors[0])) @@ -2854,6 +2857,85 @@ int HTPParserTest01(void) return result; } +/** \test Test case where chunks are sent in smaller chunks and check the + * response of the parser from HTP library. */ +static int HTPParserTest01a(void) +{ + int result = 1; + Flow *f = NULL; + uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" + " Data is c0oL!"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER|STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER|STREAM_EOF; + else + flags = STREAM_TOSERVER; + + SCMutexLock(&f->m); + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", u, r); + result = 0; + SCMutexUnlock(&f->m); + goto end; + } + SCMutexUnlock(&f->m); + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0") + || tx->request_method_number != HTP_M_POST || + tx->request_protocol_number != HTP_PROTOCOL_1_0) + { + printf("expected header value: Victor/1.0 and got %s: and expected" + " method: POST and got %s, expected protocol number HTTP/1.0" + " and got: %s \n", bstr_util_strdup_to_c(h->value), + bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + result = 0; + goto end; + } + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + if (htp_state != NULL) + HTPStateFree(htp_state); + UTHFreeFlow(f); + return result; +} + /** \test See how it deals with an incomplete request. */ int HTPParserTest02(void) { @@ -6055,6 +6137,7 @@ void HTPParserRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("HTPParserTest01", HTPParserTest01, 1); + UtRegisterTest("HTPParserTest01a", HTPParserTest01a, 1); UtRegisterTest("HTPParserTest02", HTPParserTest02, 1); UtRegisterTest("HTPParserTest03", HTPParserTest03, 1); UtRegisterTest("HTPParserTest04", HTPParserTest04, 1); diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index fca9efe37fe2..869d2bfc221c 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -124,6 +124,7 @@ enum { HTTP_DECODER_EVENT_HEADER_HOST_INVALID, HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT, HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT, + HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE, /* suricata errors/warnings */ HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR, From 21f932898963f98af9ae7d6b18413951736e8ba9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 2 Jul 2014 13:16:28 +0200 Subject: [PATCH 0440/2553] lua: fix error handling --- src/detect-lua.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-lua.c b/src/detect-lua.c index 660850184170..55bb0aec57b7 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -749,7 +749,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) lua_State *luastate = luaL_newstate(); if (luastate == NULL) - goto error; + return -1; luaL_openlibs(luastate); /* hackish, needed to allow unittests to pass buffers as scripts instead of files */ From 8d0b09015053e37898ffd8f56d4783035728c483 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 21 Jul 2014 21:09:06 +0200 Subject: [PATCH 0441/2553] engine-analysis: print fast_pattern summary When using engine analysis for print fast_pattern stats, print a short summary at the end containing per buffer: - smallest fp - biggest fp - number of patterns - avg fp len --- src/detect-engine-analyzer.c | 44 ++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 024c3c866d9f..291e560beeb4 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -27,6 +27,7 @@ #include "suricata.h" #include "detect.h" #include "detect-parse.h" +#include "detect-engine.h" #include "detect-engine-analyzer.h" #include "detect-engine-mpm.h" #include "conf.h" @@ -42,6 +43,31 @@ static pcre *percent_re = NULL; static pcre_extra *percent_re_study = NULL; static char log_path[PATH_MAX]; +typedef struct FpPatternStats_ { + uint16_t min; + uint16_t max; + uint32_t cnt; + uint64_t tot; +} FpPatternStats; + +static FpPatternStats fp_pattern_stats[DETECT_SM_LIST_MAX]; + +static void FpPatternStatsAdd(int list, uint16_t patlen) +{ + FpPatternStats *f = &fp_pattern_stats[list]; + + if (f->min == 0) + f->min = patlen; + else if (patlen < f->min) + f->min = patlen; + + if (patlen > f->max) + f->max = patlen; + + f->cnt++; + f->tot += patlen; +} + void EngineAnalysisFP(Signature *s, char *line) { int fast_pattern_set = 0; @@ -162,10 +188,14 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, " Final content: "); PrintRawUriFp(fp_engine_analysis_FD, pat, patlen); fprintf(fp_engine_analysis_FD, "\n"); + + FpPatternStatsAdd(list_type, patlen); } else { fprintf(fp_engine_analysis_FD, " Final content: "); PrintRawUriFp(fp_engine_analysis_FD, pat, patlen); fprintf(fp_engine_analysis_FD, "\n"); + + FpPatternStatsAdd(list_type, patlen); } SCFree(pat); @@ -220,6 +250,7 @@ int SetupFPAnalyzer(void) fprintf(fp_engine_analysis_FD, "----------------------------------------------" "---------------------\n"); + memset(&fp_pattern_stats, 0, sizeof(fp_pattern_stats)); return 1; } @@ -286,6 +317,19 @@ int SetupRuleAnalyzer(void) void CleanupFPAnalyzer(void) { + fprintf(fp_engine_analysis_FD, "============\n" + "Summary:\n============\n"); + int i; + for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + FpPatternStats *f = &fp_pattern_stats[i]; + if (f->cnt == 0) + continue; + + fprintf(fp_engine_analysis_FD, + "%s, smallest pattern %u byte(s), longest pattern %u byte(s), number of patterns %u, avg pattern len %.2f byte(s)\n", + DetectSigmatchListEnumToString(i), f->min, f->max, f->cnt, (float)((double)f->tot/(float)f->cnt)); + } + if (fp_engine_analysis_FD != NULL) { fclose(fp_engine_analysis_FD); fp_engine_analysis_FD = NULL; From 62e937672df0f1b038bffdf97945620c699520e6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 12 Nov 2014 13:41:50 +0100 Subject: [PATCH 0442/2553] detect-events: set SIG_MASK_REQUIRE_*_STATE for events Set SIG_MASK_REQUIRE_*_STATE for event rules to earlier discard them. --- src/detect.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/detect.c b/src/detect.c index 9b08e8852a0e..e446d37459c3 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2434,6 +2434,30 @@ static int SignatureCreateMask(Signature *s) } } + for (sm = s->sm_lists[DETECT_SM_LIST_APP_EVENT] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_AL_APP_LAYER_EVENT: + { + DetectAppLayerEventData *aed = (DetectAppLayerEventData *)sm->ctx; + switch (aed->alproto) { + case ALPROTO_HTTP: + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; + SCLogDebug("sig %u requires http app state (http event)", s->id); + break; + case ALPROTO_SMTP: + s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; + SCLogDebug("sig %u requires smtp app state (smtp event)", s->id); + break; + case ALPROTO_DNS: + s->mask |= SIG_MASK_REQUIRE_DNS_STATE; + SCLogDebug("sig %u requires dns app state (dns event)", s->id); + break; + } + break; + } + } + } + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { case DETECT_FLOWBITS: From 359e2d68f5739fceccb6f7a27b04c626196f442d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 24 Mar 2015 17:25:04 +0100 Subject: [PATCH 0443/2553] detect-http-header: improve buffer handling Previously we could never be calling DetectEngineHHDGetBufferForTX for TX N and then afterwards for TX N - 1. Due to changes in the stateful detection code this is now possible. This patch changes the buffer logic to take the 'inspect_id' as it's base, instead of the first transaction that we are called with. --- src/detect-engine-hcbd.c | 28 +++++++++++++++------------- src/detect-engine-hhd.c | 28 +++++++++++++++++----------- src/detect-engine-hsbd.c | 25 +++++++++++++------------ 3 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index fccafada5f1d..2eb16acae95d 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -105,14 +105,18 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, *stream_start_offset = 0; if (det_ctx->hcbd_buffers_list_len == 0) { - if (HCBDCreateSpace(det_ctx, 1) < 0) - goto end; /* let's consider it as stage not done for now */ - index = 0; - - if (det_ctx->hcbd_buffers_list_len == 0) { - det_ctx->hcbd_start_tx_id = tx_id; - } - det_ctx->hcbd_buffers_list_len++; + /* get the inspect id to use as a 'base id' */ + uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + BUG_ON(base_inspect_id > tx_id); + /* see how many space we need for the current tx_id */ + uint16_t txs = (tx_id - base_inspect_id) + 1; + + if (HCBDCreateSpace(det_ctx, txs) < 0) + goto end; + + index = (tx_id - base_inspect_id); + det_ctx->hcbd_start_tx_id = base_inspect_id; + det_ctx->hcbd_buffers_list_len = txs; } else { if ((tx_id - det_ctx->hcbd_start_tx_id) < det_ctx->hcbd_buffers_list_len) { if (det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer_len != 0) { @@ -121,13 +125,11 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer; } } else { - if (HCBDCreateSpace(det_ctx, (tx_id - det_ctx->hcbd_start_tx_id) + 1) < 0) + uint16_t txs = (tx_id - det_ctx->hcbd_start_tx_id) + 1; + if (HCBDCreateSpace(det_ctx, txs) < 0) goto end; /* let's consider it as stage not done for now */ - if (det_ctx->hcbd_buffers_list_len == 0) { - det_ctx->hcbd_start_tx_id = tx_id; - } - det_ctx->hcbd_buffers_list_len++; + det_ctx->hcbd_buffers_list_len = txs; } index = (tx_id - det_ctx->hcbd_start_tx_id); } diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 6672895b4829..dce39d3dccbc 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -107,28 +107,34 @@ static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, *buffer_len = 0; if (det_ctx->hhd_buffers_list_len == 0) { - if (HHDCreateSpace(det_ctx, 1) < 0) + /* get the inspect id to use as a 'base id' */ + uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + BUG_ON(base_inspect_id > tx_id); + /* see how many space we need for the current tx_id */ + uint16_t txs = (tx_id - base_inspect_id) + 1; + + if (HHDCreateSpace(det_ctx, txs) < 0) goto end; - index = 0; - if (det_ctx->hhd_buffers_list_len == 0) { - det_ctx->hhd_start_tx_id = tx_id; - } - det_ctx->hhd_buffers_list_len++; + index = (tx_id - base_inspect_id); + det_ctx->hhd_start_tx_id = base_inspect_id; + det_ctx->hhd_buffers_list_len = txs; } else { + /* tx fits in our current buffers */ if ((tx_id - det_ctx->hhd_start_tx_id) < det_ctx->hhd_buffers_list_len) { + /* if we previously reassembled, return that buffer */ if (det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)] != 0) { *buffer_len = det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)]; return det_ctx->hhd_buffers[(tx_id - det_ctx->hhd_start_tx_id)]; } + /* otherwise fall through */ } else { - if (HHDCreateSpace(det_ctx, (tx_id - det_ctx->hhd_start_tx_id) + 1) < 0) + /* not enough space, lets expand */ + uint16_t txs = (tx_id - det_ctx->hhd_start_tx_id) + 1; + if (HHDCreateSpace(det_ctx, txs) < 0) goto end; - if (det_ctx->hhd_buffers_list_len == 0) { - det_ctx->hhd_start_tx_id = tx_id; - } - det_ctx->hhd_buffers_list_len++; + det_ctx->hhd_buffers_list_len = txs; } index = (tx_id - det_ctx->hhd_start_tx_id); } diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index cb798277187b..e7ef0bbd4a35 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -104,14 +104,17 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, *stream_start_offset = 0; if (det_ctx->hsbd_buffers_list_len == 0) { - if (HSBDCreateSpace(det_ctx, 1) < 0) - goto end; - index = 0; + /* get the inspect id to use as a 'base id' */ + uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + BUG_ON(base_inspect_id > tx_id); + /* see how many space we need for the current tx_id */ + uint16_t txs = (tx_id - base_inspect_id) + 1; - if (det_ctx->hsbd_buffers_list_len == 0) { - det_ctx->hsbd_start_tx_id = tx_id; - } - det_ctx->hsbd_buffers_list_len++; + if (HSBDCreateSpace(det_ctx, txs) < 0) + goto end; + index = (tx_id - base_inspect_id); + det_ctx->hsbd_start_tx_id = base_inspect_id; + det_ctx->hsbd_buffers_list_len = txs; } else { if ((tx_id - det_ctx->hsbd_start_tx_id) < det_ctx->hsbd_buffers_list_len) { if (det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer_len != 0) { @@ -120,13 +123,11 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer; } } else { - if (HSBDCreateSpace(det_ctx, (tx_id - det_ctx->hsbd_start_tx_id) + 1) < 0) + uint16_t txs = (tx_id - det_ctx->hsbd_start_tx_id) + 1; + if (HSBDCreateSpace(det_ctx, txs) < 0) goto end; - if (det_ctx->hsbd_buffers_list_len == 0) { - det_ctx->hsbd_start_tx_id = tx_id; - } - det_ctx->hsbd_buffers_list_len++; + det_ctx->hsbd_buffers_list_len = txs; } index = (tx_id - det_ctx->hsbd_start_tx_id); } From 9d198e66627a6a8a33f7d0e96ff1bab025d7142a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 24 Mar 2015 12:40:27 +0100 Subject: [PATCH 0444/2553] detect-state: fix state storing Fix storing state and bypassing detection. Previously we'd store on a match only, meaning that StartDetection would rerun often. Make sure StartDetection only stores if there is something to store. --- src/detect-engine-state.c | 41 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 5aac3bd9a9ac..9e5f4d5173e0 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -447,6 +447,8 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); SCLogDebug("total_txs %"PRIu64, total_txs); + SCLogDebug("starting: start tx %u, packet %u", (uint)tx_id, (uint)p->pcap_cnt); + for (; tx_id < total_txs; tx_id++) { int total_matches = 0; void *tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id); @@ -490,14 +492,33 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectSignatureApplyActions(p, s); } alert_cnt = 1; + SCLogDebug("MATCH: tx %u packet %u", (uint)tx_id, (uint)p->pcap_cnt); } /* if this is the last tx in our list, and it's incomplete: then * we store the state so that ContinueDetection knows about it */ int tx_is_done = (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) >= AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)); + /* see if we need to consider the next tx in our decision to add + * a sig to the 'no inspect array'. */ + int next_tx_no_progress = 0; + if (!TxIsLast(tx_id, total_txs)) { + void *next_tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id+1); + if (next_tx != NULL) { + int c = AppLayerParserGetStateProgress(f->proto, alproto, next_tx, flags); + if (c == 0) { + next_tx_no_progress = 1; + } + } + } + + SCLogDebug("tx %u, packet %u, rule %u, alert_cnt %u, last tx %d, tx_is_done %d, next_tx_no_progress %d", + (uint)tx_id, (uint)p->pcap_cnt, s->num, alert_cnt, + TxIsLast(tx_id, total_txs), tx_is_done, next_tx_no_progress); - if ((engine == NULL && total_matches > 0) || (inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { + /* if we have something to store (partial match or file store info), + * then we do it now. */ + if (inspect_flags != 0) { if (!(TxIsLast(tx_id, total_txs)) || !tx_is_done) { if (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; @@ -509,7 +530,11 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } else { StoreStateTxFileOnly(det_ctx, f, flags, tx_id, tx, file_no_match); } + } else { + SCLogDebug("no state to store"); } + if (next_tx_no_progress) + break; } /* for */ /* DCERPC matches */ @@ -645,6 +670,9 @@ static int DoInspectItem(ThreadVars *tv, if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { if (TxIsLast(inspect_tx_id, total_txs) || inprogress || next_tx_no_progress) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + SCLogDebug("skip and bypass: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + } else { + SCLogDebug("just skip: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); } return 0; } @@ -668,6 +696,9 @@ static int DoInspectItem(ThreadVars *tv, } else { if (TxIsLast(inspect_tx_id, total_txs) || inprogress || next_tx_no_progress) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + SCLogDebug("skip and bypass: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + } else { + SCLogDebug("just skip: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); } return 0; } @@ -687,6 +718,8 @@ static int DoInspectItem(ThreadVars *tv, det_ctx->tx_id = inspect_tx_id; det_ctx->tx_id_set = 1; + SCLogDebug("inspecting: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + DetectEngineAppInspectionEngine *engine = app_inspection_engine[f->protomap][alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); if (inspect_tx == NULL) { @@ -725,8 +758,11 @@ static int DoInspectItem(ThreadVars *tv, } item->flags |= inspect_flags; - if (TxIsLast(inspect_tx_id, total_txs)) { + /* flag this sig to don't inspect again from the detection loop it if + * there is no need for it */ + if (TxIsLast(inspect_tx_id, total_txs) || inprogress || next_tx_no_progress) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + SCLogDebug("inspected, now bypass: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); } RULE_PROFILING_END(det_ctx, s, (alert == 1), p); @@ -741,6 +777,7 @@ static int DoInspectItem(ThreadVars *tv, } else { PACKET_UPDATE_ACTION(p, s->action); } + SCLogDebug("MATCH: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); } DetectFlowvarProcessList(det_ctx, f); From bc6e4140befa80080777c41040eb47f9b6e05129 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Mar 2015 09:19:49 +0100 Subject: [PATCH 0445/2553] detect: add de_state duplication check Add test to check if no duplicate destate is created. Only enabled with DEBUG_VALIDATION. --- src/detect-engine-state.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 9e5f4d5173e0..8cbc5b85404d 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -124,11 +124,42 @@ static DeStateStoreFlowRules *DeStateStoreFlowRulesAlloc(void) return d; } +#ifdef DEBUG_VALIDATION +static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIntId num) +{ + DetectEngineStateDirection *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1]; + DeStateStore *tx_store = dir_state->head; + SigIntId store_cnt; + SigIntId state_cnt = 0; + + for (; tx_store != NULL; tx_store = tx_store->next) { + SCLogDebug("tx_store %p", tx_store); + for (store_cnt = 0; + store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt; + store_cnt++, state_cnt++) + { + DeStateStoreItem *item = &tx_store->store[store_cnt]; + if (item->sid == num) { + SCLogDebug("BUG! sid %u already in state: %p %p %p %u %u, direction %s", + num, state, dir_state, tx_store, state_cnt, + store_cnt, direction & STREAM_TOSERVER ? "toserver" : "toclient"); + return 1; + } + } + } + return 0; +} +#endif + static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, uint32_t inspect_flags, uint8_t direction) { int jump = 0; int i = 0; DetectEngineStateDirection *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1]; + +#ifdef DEBUG_VALIDATION + BUG_ON(DeStateSearchState(state, direction, s->num)); +#endif DeStateStore *store = dir_state->head; if (store == NULL) { From 37f0bd57b68f888689e1fb664d6dd05054cc7d9f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 24 Mar 2015 15:36:39 +0100 Subject: [PATCH 0446/2553] detect-state: handle duplicate inspect/match If for a packet we have a TX N that has detect state and a TX N+1 that has no detect state, but does have 'progress', we have a corner case in stateful detection. ContinueDetection inspects TX N, but cannot flag the rule in the de_state_sig_array as the next (TX N+1) has already started and needs to be inspected. 'StartDetection' however, is then unaware of the fact that ContinueDetection already inspected the rule. It uses the per session 'inspect_id' that is only moved forward at the end of the detection run. This patch adds a workaround. It uses the DetectEngineThreadCtx:: de_state_sig_array to store an offset between the 'base' inspect_id and the inspect_id that StartDetection should use. The data type is limited, so if the offset would be too big, a search based fall back is implemented as well. --- src/detect-engine-state.c | 80 ++++++++++++++++++++++++++++++--------- src/detect-engine-state.h | 6 +-- src/detect.c | 4 +- 3 files changed, 67 insertions(+), 23 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 8cbc5b85404d..110d236f8406 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -81,6 +81,18 @@ /** convert enum to string */ #define CASE_CODE(E) case E: return #E +/** The DetectEngineThreadCtx::de_state_sig_array contains 2 separate values: + * 1. the first bit tells the prefilter engine to bypass the rule (or not) + * 2. the other bits allow 'ContinueDetect' to specify an offset again the + * base tx id. This offset will then be used by 'StartDetect' to not + * inspect transactions again for the same signature. + * + * The offset in (2) has a max value due to the limited data type. If it is + * set to max the code will fall back to a slower path that validates that + * we're not adding duplicate rules to the detection state. + */ +#define MAX_STORED_TXID_OFFSET 127 + /******** static internal helpers *********/ static inline int StateIsValid(uint16_t alproto, void *alstate) @@ -124,7 +136,6 @@ static DeStateStoreFlowRules *DeStateStoreFlowRulesAlloc(void) return d; } -#ifdef DEBUG_VALIDATION static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIntId num) { DetectEngineStateDirection *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1]; @@ -140,7 +151,7 @@ static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIn { DeStateStoreItem *item = &tx_store->store[store_cnt]; if (item->sid == num) { - SCLogDebug("BUG! sid %u already in state: %p %p %p %u %u, direction %s", + SCLogDebug("sid %u already in state: %p %p %p %u %u, direction %s", num, state, dir_state, tx_store, state_cnt, store_cnt, direction & STREAM_TOSERVER ? "toserver" : "toclient"); return 1; @@ -149,7 +160,6 @@ static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIn } return 0; } -#endif static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, uint32_t inspect_flags, uint8_t direction) { @@ -424,11 +434,14 @@ static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx, } } +/** + * \param check_before_add check for duplicates before adding the sig + */ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, Flow *f, const uint8_t flags, const uint16_t alversion, const uint64_t tx_id, void *tx, Signature *s, SigMatch *sm, - const uint32_t inspect_flags, const uint16_t file_no_match) + const uint32_t inspect_flags, const uint16_t file_no_match, int check_before_add) { if (AppLayerParserSupportsTxDetectState(f->proto, f->alproto)) { DetectEngineState *destate = AppLayerParserGetTxDetectState(f->proto, f->alproto, tx); @@ -444,7 +457,8 @@ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, SCLogDebug("destate created for %"PRIu64, tx_id); } - DeStateSignatureAppend(destate, s, inspect_flags, flags); + if (check_before_add == 0 || DeStateSearchState(destate, flags, s->num) == 0) + DeStateSignatureAppend(destate, s, inspect_flags, flags); DeStateStoreStateVersion(f, alversion, flags); StoreStateTxHandleFiles(det_ctx, f, destate, flags, tx_id, file_no_match); @@ -462,6 +476,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, uint32_t inspect_flags = 0; uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; int alert_cnt = 0; + int check_before_add = 0; FLOWLOCK_WRLOCK(f); /* TX based matches (inspect engines) */ @@ -474,7 +489,18 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, goto end; } + /* if continue detection already inspected this rule for this tx, + * continue with the first not-inspected tx */ + uint8_t offset = det_ctx->de_state_sig_array[s->num] & 0xef; tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + if (offset > 0) { + SCLogDebug("using stored_tx_id %u instead of %u", (uint)tx_id+offset, (uint)tx_id); + tx_id += offset; + } + if (offset == MAX_STORED_TXID_OFFSET) { + check_before_add = 1; + } + total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); SCLogDebug("total_txs %"PRIu64, total_txs); @@ -557,7 +583,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, /* store */ StoreStateTx(det_ctx, f, flags, alversion, tx_id, tx, - s, sm, inspect_flags, file_no_match); + s, sm, inspect_flags, file_no_match, check_before_add); } else { StoreStateTxFileOnly(det_ctx, f, flags, tx_id, tx, file_no_match); } @@ -704,6 +730,16 @@ static int DoInspectItem(ThreadVars *tv, SCLogDebug("skip and bypass: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); } else { SCLogDebug("just skip: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + + /* make sure that if we reinspect this right now from + * start detection, we skip this tx we just matched on */ + uint64_t base_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + uint64_t offset = (inspect_tx_id + 1) - base_tx_id; + if (offset > MAX_STORED_TXID_OFFSET) + offset = MAX_STORED_TXID_OFFSET; + det_ctx->de_state_sig_array[item->sid] = (uint8_t)offset; + BUG_ON(det_ctx->de_state_sig_array[item->sid] & DE_STATE_MATCH_NO_NEW_STATE); // check that we don't set the bit + SCLogDebug("storing tx_id %u for this sid", (uint)inspect_tx_id + 1); } return 0; } @@ -730,6 +766,16 @@ static int DoInspectItem(ThreadVars *tv, SCLogDebug("skip and bypass: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); } else { SCLogDebug("just skip: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + + /* make sure that if we reinspect this right now from + * start detection, we skip this tx we just matched on */ + uint64_t base_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + uint64_t offset = (inspect_tx_id + 1) - base_tx_id; + if (offset > MAX_STORED_TXID_OFFSET) + offset = MAX_STORED_TXID_OFFSET; + det_ctx->de_state_sig_array[item->sid] = (uint8_t)offset; + BUG_ON(det_ctx->de_state_sig_array[item->sid] & DE_STATE_MATCH_NO_NEW_STATE); // check that we don't set the bit + SCLogDebug("storing tx_id %u for this sid", (uint)inspect_tx_id + 1); } return 0; } @@ -794,6 +840,17 @@ static int DoInspectItem(ThreadVars *tv, if (TxIsLast(inspect_tx_id, total_txs) || inprogress || next_tx_no_progress) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; SCLogDebug("inspected, now bypass: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + } else { + /* make sure that if we reinspect this right now from + * start detection, we skip this tx we just matched on */ + uint64_t base_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + uint64_t offset = (inspect_tx_id + 1) - base_tx_id; + if (offset > MAX_STORED_TXID_OFFSET) + offset = MAX_STORED_TXID_OFFSET; + det_ctx->de_state_sig_array[item->sid] = (uint8_t)offset; + BUG_ON(det_ctx->de_state_sig_array[item->sid] & DE_STATE_MATCH_NO_NEW_STATE); // check that we don't set the bit + + SCLogDebug("storing tx_id %u for this sid", (uint)inspect_tx_id + 1); } RULE_PROFILING_END(det_ctx, s, (alert == 1), p); @@ -1094,17 +1151,6 @@ void DetectEngineStateResetTxs(Flow *f) } } -/** \brief get string for match enum */ -const char *DeStateMatchResultToString(DeStateMatchResult res) -{ - switch (res) { - CASE_CODE (DE_STATE_MATCH_NO_NEW_STATE); - CASE_CODE (DE_STATE_MATCH_HAS_NEW_STATE); - } - - return NULL; -} - /*********Unittests*********/ #ifdef UNITTESTS diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index ab30ccffed72..7ef4df2c45e3 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -100,10 +100,8 @@ * the HAS_NEW_STATE flag, while if we don't have a new tx, we set * NO_NEW_STATE, to avoid getting the sig reinspected for the already * inspected tx. */ -typedef enum { - DE_STATE_MATCH_HAS_NEW_STATE = 0, - DE_STATE_MATCH_NO_NEW_STATE, -} DeStateMatchResult; +#define DE_STATE_MATCH_HAS_NEW_STATE 0x00 +#define DE_STATE_MATCH_NO_NEW_STATE 0x80 /* TX BASED (inspect engines) */ diff --git a/src/detect.c b/src/detect.c index e446d37459c3..8ff406680549 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1374,10 +1374,10 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); /* stateful app layer detection */ if ((p->flags & PKT_HAS_FLOW) && has_state) { - /* initialize to 0(DE_STATE_MATCH_HAS_NEW_STATE) */ memset(det_ctx->de_state_sig_array, 0x00, det_ctx->de_state_sig_array_len); int has_inspectable_state = DeStateFlowHasInspectableState(pflow, alproto, alversion, flags); if (has_inspectable_state == 1) { + /* initialize to 0(DE_STATE_MATCH_HAS_NEW_STATE) */ DeStateDetectContinueDetection(th_v, de_ctx, det_ctx, p, pflow, flags, alproto, alversion); } else if (has_inspectable_state == 2) { @@ -1500,7 +1500,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } } if (sflags & SIG_FLAG_STATE_MATCH) { - if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NO_NEW_STATE) + if (det_ctx->de_state_sig_array[s->num] & DE_STATE_MATCH_NO_NEW_STATE) goto next; } From 5f0678120d40447269917754041bf35db5b11496 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Mar 2015 15:54:35 +0100 Subject: [PATCH 0447/2553] detect-state: update test to check state storing --- src/detect-engine-state.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 110d236f8406..150f49213614 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -1491,7 +1491,7 @@ static int DeStateSigTest02(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"/\"; http_uri; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"body\"; nocase; http_client_body; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; @@ -1547,12 +1547,24 @@ static int DeStateSigTest02(void) SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert: "); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted too early: "); goto end; } p->alerts.cnt = 0; + void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, f.alstate, 0); + if (tx == NULL) { + printf("no http tx: "); + goto end; + } + DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(IPPROTO_TCP, ALPROTO_HTTP, tx); + if (tx_de_state == NULL || tx_de_state->dir_state[0].cnt != 1 || + tx_de_state->dir_state[0].head->store[0].flags != 0x00000001) { + printf("de_state not present or has unexpected content: "); + goto end; + } + SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { @@ -1564,8 +1576,8 @@ static int DeStateSigTest02(void) SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("signature matched, but shouldn't have: "); + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't match: "); goto end; } p->alerts.cnt = 0; From f536099a67b4524c8705627f54708f63a211445e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 7 Apr 2015 16:00:08 +0200 Subject: [PATCH 0448/2553] app-layer: de_state optimization Add API to bypass expensive TX list walks. This API call is optional. Implement it for HTTP and DNS. --- src/app-layer-dns-common.c | 17 ++++++++++++-- src/app-layer-dns-common.h | 5 +++- src/app-layer-dns-tcp.c | 1 + src/app-layer-dns-udp.c | 1 + src/app-layer-htp.c | 47 +++++++++++++++++++++++--------------- src/app-layer-htp.h | 1 + src/app-layer-modbus.c | 4 ++-- src/app-layer-parser.c | 22 ++++++++++++++---- src/app-layer-parser.h | 6 +++-- src/app-layer-smtp.c | 4 ++-- src/detect-engine-state.c | 12 ++++++++-- 11 files changed, 86 insertions(+), 34 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 852afa7c85dd..b7d404254422 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -293,8 +293,11 @@ static void DNSTransactionFree(DNSTransaction *tx, DNSState *state) AppLayerDecoderEventsFreeEvents(&tx->decoder_events); - if (tx->de_state != NULL) + if (tx->de_state != NULL) { DetectEngineStateFree(tx->de_state); + BUG_ON(state->tx_with_detect_state_cnt == 0); + state->tx_with_detect_state_cnt--; + } if (state->iter == tx) state->iter = NULL; @@ -366,15 +369,23 @@ DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16 return NULL; } +int DNSStateHasTxDetectState(void *alstate) +{ + DNSState *state = (DNSState *)alstate; + return (state->tx_with_detect_state_cnt > 0); +} + DetectEngineState *DNSGetTxDetectState(void *vtx) { DNSTransaction *tx = (DNSTransaction *)vtx; return tx->de_state; } -int DNSSetTxDetectState(void *vtx, DetectEngineState *s) +int DNSSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s) { + DNSState *state = (DNSState *)alstate; DNSTransaction *tx = (DNSTransaction *)vtx; + state->tx_with_detect_state_cnt++; tx->de_state = s; return 0; } @@ -413,6 +424,8 @@ void DNSStateFree(void *s) SCFree(dns_state->buffer); } + BUG_ON(dns_state->tx_with_detect_state_cnt > 0); + DNSDecrMemcap(sizeof(DNSState), dns_state); BUG_ON(dns_state->memuse > 0); SCFree(s); diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index 1564fec98683..1a06f8d1dc09 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -181,6 +181,8 @@ typedef struct DNSState_ { uint32_t unreplied_cnt; /**< number of unreplied requests in a row */ uint32_t memuse; /**< state memuse, for comparing with state-memcap settings */ + uint64_t tx_with_detect_state_cnt; + uint16_t events; uint16_t givenup; @@ -221,8 +223,9 @@ int DNSGetAlstateProgressCompletionStatus(uint8_t direction); void DNSStateTransactionFree(void *state, uint64_t tx_id); DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16_t tx_id); +int DNSStateHasTxDetectState(void *alstate); DetectEngineState *DNSGetTxDetectState(void *vtx); -int DNSSetTxDetectState(void *vtx, DetectEngineState *s); +int DNSSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s); void DNSSetEvent(DNSState *s, uint8_t e); void *DNSStateAlloc(void); diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 36b8848aeb63..0842c6686e64 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -647,6 +647,7 @@ void RegisterDNSTCPParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSHasEvents); AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DNS, + DNSStateHasTxDetectState, DNSGetTxDetectState, DNSSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNS, DNSGetTx); diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index 1917914b1b11..bb0c73bf555d 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -403,6 +403,7 @@ void RegisterDNSUDPParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSHasEvents); AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_DNS, + DNSStateHasTxDetectState, DNSGetTxDetectState, DNSSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_DNS, diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 8ae86fe1b42b..2ded474ed99a 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -310,9 +310,9 @@ static void *HTPStateAlloc(void) SCReturnPtr(NULL, "void"); } -static void HtpTxUserDataFree(HtpTxUserData *htud) +static void HtpTxUserDataFree(HtpState *state, HtpTxUserData *htud) { - if (htud) { + if (likely(htud)) { HtpBodyFree(&htud->request_body); HtpBodyFree(&htud->response_body); bstr_free(htud->request_uri_normalized); @@ -324,6 +324,11 @@ static void HtpTxUserDataFree(HtpTxUserData *htud) if (htud->boundary) HTPFree(htud->boundary, htud->boundary_len); if (htud->de_state != NULL) { + if (likely(state != NULL)) { // should be impossible that it's null + BUG_ON(state->tx_with_detect_state_cnt == 0); + state->tx_with_detect_state_cnt--; + } + DetectEngineStateFree(htud->de_state); } HTPFree(htud, sizeof(HtpTxUserData)); @@ -357,15 +362,14 @@ void HTPStateFree(void *state) htp_tx_t *tx = HTPStateGetTx(s, tx_id); if (tx != NULL) { HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud != NULL) { - HtpTxUserDataFree(htud); - htp_tx_set_user_data(tx, NULL); - } + HtpTxUserDataFree(s, htud); + htp_tx_set_user_data(tx, NULL); } } } htp_connp_destroy_all(s->connp); } + BUG_ON(s->tx_with_detect_state_cnt > 0); FileContainerFree(s->files_ts); FileContainerFree(s->files_tc); @@ -400,10 +404,8 @@ static void HTPStateTransactionFree(void *state, uint64_t id) if (tx != NULL) { /* This will remove obsolete body chunks */ HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud != NULL) { - HtpTxUserDataFree(htud); - htp_tx_set_user_data(tx, NULL); - } + HtpTxUserDataFree(s, htud); + htp_tx_set_user_data(tx, NULL); htp_tx_destroy(tx); } @@ -2109,10 +2111,9 @@ static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data) tx_ud->request_headers_raw_len, tx_ud->request_headers_raw_len + tx_data->len); if (ptmp == NULL) { - HTPFree(tx_ud->request_headers_raw, tx_ud->request_headers_raw_len); - tx_ud->request_headers_raw = NULL; - tx_ud->request_headers_raw_len = 0; - HtpTxUserDataFree(tx_ud); + /* error: we're freeing the entire user data */ + HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp); + HtpTxUserDataFree(hstate, tx_ud); htp_tx_set_user_data(tx_data->tx, NULL); return HTP_OK; } @@ -2147,10 +2148,9 @@ static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data) tx_ud->response_headers_raw_len, tx_ud->response_headers_raw_len + tx_data->len); if (ptmp == NULL) { - HTPFree(tx_ud->response_headers_raw, tx_ud->response_headers_raw_len); - tx_ud->response_headers_raw = NULL; - tx_ud->response_headers_raw_len = 0; - HtpTxUserDataFree(tx_ud); + /* error: we're freeing the entire user data */ + HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp); + HtpTxUserDataFree(hstate, tx_ud); htp_tx_set_user_data(tx_data->tx, NULL); return HTP_OK; } @@ -2635,6 +2635,12 @@ static void HTPStateTruncate(void *state, uint8_t direction) } } +static int HTPStateHasTxDetectState(void *alstate) +{ + HtpState *htp_state = (HtpState *)alstate; + return (htp_state->tx_with_detect_state_cnt > 0); +} + static DetectEngineState *HTPGetTxDetectState(void *vtx) { htp_tx_t *tx = (htp_tx_t *)vtx; @@ -2642,8 +2648,9 @@ static DetectEngineState *HTPGetTxDetectState(void *vtx) return tx_ud ? tx_ud->de_state : NULL; } -static int HTPSetTxDetectState(void *vtx, DetectEngineState *s) +static int HTPSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s) { + HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = (htp_tx_t *)vtx; HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); if (tx_ud == NULL) { @@ -2653,6 +2660,7 @@ static int HTPSetTxDetectState(void *vtx, DetectEngineState *s) memset(tx_ud, 0, sizeof(*tx_ud)); htp_tx_set_user_data(tx, tx_ud); } + htp_state->tx_with_detect_state_cnt++; tx_ud->de_state = s; return 0; } @@ -2741,6 +2749,7 @@ void RegisterHTPParsers(void) AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateTruncate); AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_HTTP, + HTPStateHasTxDetectState, HTPGetTxDetectState, HTPSetTxDetectState); AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOSERVER, diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 869d2bfc221c..50b95d66d1a0 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -248,6 +248,7 @@ typedef struct HtpState_ { uint16_t flags; uint16_t events; uint16_t htp_messages_offset; /**< offset into conn->messages list */ + uint64_t tx_with_detect_state_cnt; } HtpState; /** part of the engine needs the request body (e.g. http_client_body keyword) */ diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 31982eadfe8c..93b834b4b3d2 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1343,7 +1343,7 @@ DetectEngineState *ModbusGetTxDetectState(void *vtx) return tx->de_state; } -int ModbusSetTxDetectState(void *vtx, DetectEngineState *s) +int ModbusSetTxDetectState(void *state, void *vtx, DetectEngineState *s) { ModbusTransaction *tx = (ModbusTransaction *)vtx; tx->de_state = s; @@ -1410,7 +1410,7 @@ void RegisterModbusParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusHasEvents); - AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, NULL, ModbusGetTxDetectState, ModbusSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTx); diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 42ad4e1eddc6..289a59d7cd44 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -106,8 +106,9 @@ typedef struct AppLayerParserProtoCtx_ int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type); + int (*StateHasTxDetectState)(void *alstate); DetectEngineState *(*GetTxDetectState)(void *tx); - int (*SetTxDetectState)(void *tx, DetectEngineState *); + int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *); /* Indicates the direction the parser is ready to see the data * the first time for a flow. Values accepted - @@ -472,11 +473,13 @@ void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, } void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, + int (*StateHasTxDetectState)(void *alstate), DetectEngineState *(*GetTxDetectState)(void *tx), - int (*SetTxDetectState)(void *tx, DetectEngineState *)) + int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *)) { SCEnter(); + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState = StateHasTxDetectState; alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState = GetTxDetectState; alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState = SetTxDetectState; @@ -804,6 +807,16 @@ int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto) return FALSE; } +int AppLayerParserHasTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate) +{ + int r; + SCEnter(); + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState == NULL) + return -ENOSYS; + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState(alstate); + SCReturnInt(r); +} + DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx) { SCEnter(); @@ -812,13 +825,14 @@ DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alpr SCReturnPtr(s, "DetectEngineState"); } -int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx, DetectEngineState *s) +int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, + void *alstate, void *tx, DetectEngineState *s) { int r; SCEnter(); if ((alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState(tx) != NULL)) SCReturnInt(-EBUSY); - r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState(tx, s); + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState(alstate, tx, s); SCReturnInt(r); } diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index 44f27b76c8d2..b81459b7666a 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -143,8 +143,9 @@ void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type)); void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, + int (*StateHasTxDetectState)(void *alstate), DetectEngineState *(*GetTxDetectState)(void *tx), - int (*SetTxDetectState)(void *tx, DetectEngineState *)); + int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *)); /***** Get and transaction functions *****/ @@ -180,8 +181,9 @@ uint64_t AppLayerParserGetTransactionActive(uint8_t ipproto, AppProto alproto, A uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto); int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto); +int AppLayerParserHasTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate); DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx); -int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx, DetectEngineState *s); +int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate, void *tx, DetectEngineState *s); /***** General *****/ diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index e03cad89470c..c0772ec75ae4 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1381,7 +1381,7 @@ static DetectEngineState *SMTPGetTxDetectState(void *vtx) return tx->de_state; } -static int SMTPSetTxDetectState(void *vtx, DetectEngineState *s) +static int SMTPSetTxDetectState(void *state, void *vtx, DetectEngineState *s) { SMTPTransaction *tx = (SMTPTransaction *)vtx; tx->de_state = s; @@ -1415,7 +1415,7 @@ void RegisterSMTPParsers(void) AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo); AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents); - AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, NULL, SMTPGetTxDetectState, SMTPSetTxDetectState); AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc, diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 150f49213614..37a63f5c7fad 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -335,6 +335,14 @@ static int HasStoredSigs(Flow *f, uint8_t flags) return 0; } + int state = AppLayerParserHasTxDetectState(f->proto, alproto, f->alstate); + if (state == -ENOSYS) { /* proto doesn't support this API call */ + /* fall through */ + } else if (state == 0) { + return 0; + } + /* if state == 1 we also fall through */ + uint64_t inspect_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); @@ -423,7 +431,7 @@ static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx, destate = DetectEngineStateAlloc(); if (destate == NULL) return; - if (AppLayerParserSetTxDetectState(f->proto, f->alproto, tx, destate) < 0) { + if (AppLayerParserSetTxDetectState(f->proto, f->alproto, f->alstate, tx, destate) < 0) { DetectEngineStateFree(destate); BUG_ON(1); return; @@ -449,7 +457,7 @@ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, destate = DetectEngineStateAlloc(); if (destate == NULL) return; - if (AppLayerParserSetTxDetectState(f->proto, f->alproto, tx, destate) < 0) { + if (AppLayerParserSetTxDetectState(f->proto, f->alproto, f->alstate, tx, destate) < 0) { DetectEngineStateFree(destate); BUG_ON(1); return; From 22a810813c8c9a33371dc65acf222de1cfff881d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Jan 2015 11:12:37 +0100 Subject: [PATCH 0449/2553] app-layer: add DisableAppLayer Move various app layer related flag setting calls into a utility function "DisableAppLayer" --- src/app-layer.c | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 806191cc3d66..0beecbe2948f 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -88,6 +88,15 @@ static void DNSUpdateCounters(ThreadVars *tv, AppLayerThreadCtx *app_tctx) /***** L7 layer dispatchers *****/ +static void DisableAppLayer(Flow *f, TcpSession *ssn) +{ + SCLogInfo("disable app layer for flow %p, ssn %p", f, ssn); + FlowSetSessionNoApplayerInspectionFlag(f); + StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); + StreamTcpDisableAppLayerReassembly(ssn); +} + int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet *p, Flow *f, TcpSession *ssn, TcpStream *stream, @@ -221,9 +230,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } } if (ret < 0) { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); + DisableAppLayer(f, ssn); goto failure; } } @@ -250,9 +257,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) { AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_WRONG_DIRECTION_FIRST_DATA); - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + DisableAppLayer(f, ssn); /* Set a value that is neither STREAM_TOSERVER, nor STREAM_TOCLIENT */ ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; goto failure; @@ -301,9 +306,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { SCLogDebug("midstream end pd %p", ssn); /* midstream and toserver detection failed: give up */ - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + DisableAppLayer(f, ssn); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; goto end; } @@ -330,9 +333,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if ((ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) && (first_data_dir) && !(first_data_dir & flags)) { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + DisableAppLayer(f, ssn); goto failure; } @@ -374,26 +375,20 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + DisableAppLayer(f, ssn); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; } else if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && size_ts > 100000 && size_tc == 0) { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + DisableAppLayer(f, ssn); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); } else if (FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && size_tc > 100000 && size_ts == 0) { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + DisableAppLayer(f, ssn); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); @@ -404,9 +399,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + DisableAppLayer(f, ssn); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); @@ -417,9 +410,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && !(FLOW_IS_PM_DONE(f, STREAM_TOCLIENT)) && FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + DisableAppLayer(f, ssn); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); From b2e1854e2a7a19a44026b27f0a8e63b89dd37009 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 5 May 2015 17:48:18 +0200 Subject: [PATCH 0450/2553] stream: improve 'no app layer' handling When the session/flow was flagged as 'no applayer inspect', which could happen as a result various reasons, packets would still be considered by the app layer reassembly. When ACK'd, they would be removed again. Depending also on the raw reassembly. In very long sessions however, this meganism could fail leading to virtually endlessly growing segment lists. This patch makes sure that segments that come in on a 'no app layer' session are tagged properly or even not added at all. Use a new ssn flag instead of flow flag for no app tracking. --- src/stream-tcp-private.h | 5 +++++ src/stream-tcp-reassemble.c | 35 +++++++++++++++++++---------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 50c6421a872b..51ced8882824 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -142,6 +142,8 @@ enum * normal packet we assume 3whs to be completed. Only used for SYN/ACK resend * event. */ #define STREAMTCP_FLAG_3WHS_CONFIRMED 0x1000 +/** App Layer tracking/reassembly is disabled */ +#define STREAMTCP_FLAG_APP_LAYER_DISABLED 0x2000 /* * Per STREAM flags @@ -237,5 +239,8 @@ typedef struct TcpSession_ { ((stream)->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) #define StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream) \ ((stream)->flags &= ~STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED); +#define StreamTcpDisableAppLayerReassembly(ssn) do { \ + ((ssn)->flags |= STREAMTCP_FLAG_APP_LAYER_DISABLED); \ + } while (0); #endif /* __STREAM_TCP_PRIVATE_H__ */ diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index ae14fd7c7863..c319c468f768 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -1870,6 +1870,12 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre } } + if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) && + (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)) { + SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn); + SCReturnInt(0); + } + /* If we have reached the defined depth for either of the stream, then stop reassembling the TCP session */ uint32_t size = StreamTcpReassembleCheckDepth(stream, TCP_GET_SEQ(p), p->payload_len); @@ -1907,6 +1913,9 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre seg->payload_len = size; seg->seq = TCP_GET_SEQ(p); + if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) + seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; + /* if raw reassembly is disabled for new segments, flag each * segment as complete for raw before insert */ if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) { @@ -2049,8 +2058,9 @@ static int StreamTcpReassembleRawCheckLimit(TcpSession *ssn, TcpStream *stream, * \retval 1 app layer is done with this segment * \retval 0 not done yet */ -#define StreamTcpAppLayerSegmentProcessed(stream, segment) \ - (( ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \ +#define StreamTcpAppLayerSegmentProcessed(ssn, stream, segment) \ + (( ( (ssn)->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || \ + ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \ ( (segment)->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED ) ? 1 :0 )) /** \internal @@ -2082,10 +2092,8 @@ static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, Tc } /* check app layer conditions */ - if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) { - if (!(StreamTcpAppLayerSegmentProcessed(stream, seg))) { - SCReturnInt(0); - } + if (!(StreamTcpAppLayerSegmentProcessed(ssn, stream, seg))) { + SCReturnInt(0); } /* check raw reassembly conditions */ @@ -2188,7 +2196,7 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, seg->payload_len); /* only remove if app layer reassembly is ready too */ - if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { + if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) { TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); @@ -2207,7 +2215,7 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, * If the stream is in GAP state the app layer flag won't be set */ if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) && (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && - StreamTcpAppLayerSegmentProcessed(stream, seg)) + StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) { SCLogDebug("segment(%p) of length %"PRIu16" has been processed," " so return it to pool", seg, seg->payload_len); @@ -2421,7 +2429,7 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, SCLogDebug("seg %p seq %"PRIu32", len %"PRIu16", sum %"PRIu32, seg, seg->seq, seg->payload_len, seg->seq+seg->payload_len); /* only remove if app layer reassembly is ready too */ - if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { + if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) { TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); @@ -2909,7 +2917,7 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, * next_seq, we know we are missing data that has been ack'd. That * won't get retransmitted, so it's a data gap. */ - if (!(p->flow->flags & FLOW_NO_APPLAYER_INSPECTION)) { + if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) { if (SEQ_GT(seg->seq, next_seq) && SEQ_LT(seg->seq, stream->last_ack)) { /* send gap signal */ AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, @@ -2942,11 +2950,6 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, seg, seg->seq, seg->payload_len, (uint32_t)(seg->seq + seg->payload_len)); - if (p->flow->flags & FLOW_NO_APPLAYER_INSPECTION) { - SCLogDebug("FLOW_NO_APPLAYER_INSPECTION set, breaking out"); - break; - } - if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) { SCLogDebug("removing segment"); TcpSegment *next_seg = seg->next; @@ -2954,7 +2957,7 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; - } else if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { + } else if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) { TcpSegment *next_seg = seg->next; seg = next_seg; continue; From b6798495c5ba89ed45eaa31cfd4ca94a1078eb2d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Jan 2015 12:16:32 +0100 Subject: [PATCH 0451/2553] stream: remove FLOW_NO_APPLAYER_INSPECTION use from tests --- src/app-layer.c | 152 ++++++++++++++++++------------------ src/stream-tcp-private.h | 1 + src/stream-tcp-reassemble.c | 34 ++++---- 3 files changed, 94 insertions(+), 93 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 0beecbe2948f..b1ccc3d082f8 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -711,7 +711,7 @@ static int AppLayerTest01(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -735,7 +735,7 @@ static int AppLayerTest01(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -759,7 +759,7 @@ static int AppLayerTest01(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -795,7 +795,7 @@ static int AppLayerTest01(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -861,7 +861,7 @@ static int AppLayerTest01(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -885,7 +885,7 @@ static int AppLayerTest01(void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -951,7 +951,7 @@ static int AppLayerTest02(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -975,7 +975,7 @@ static int AppLayerTest02(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -999,7 +999,7 @@ static int AppLayerTest02(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -1024,7 +1024,7 @@ static int AppLayerTest02(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -1048,7 +1048,7 @@ static int AppLayerTest02(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -1084,7 +1084,7 @@ static int AppLayerTest02(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -1150,7 +1150,7 @@ static int AppLayerTest02(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -1174,7 +1174,7 @@ static int AppLayerTest02(void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -1240,7 +1240,7 @@ static int AppLayerTest03(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -1263,7 +1263,7 @@ static int AppLayerTest03(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -1287,7 +1287,7 @@ static int AppLayerTest03(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -1323,7 +1323,7 @@ static int AppLayerTest03(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -1389,7 +1389,7 @@ static int AppLayerTest03(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -1413,7 +1413,7 @@ static int AppLayerTest03(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -1479,7 +1479,7 @@ static int AppLayerTest04(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -1502,7 +1502,7 @@ static int AppLayerTest04(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -1526,7 +1526,7 @@ static int AppLayerTest04(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -1562,7 +1562,7 @@ static int AppLayerTest04(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -1587,7 +1587,7 @@ static int AppLayerTest04(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -1611,7 +1611,7 @@ static int AppLayerTest04(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 4 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -1677,7 +1677,7 @@ static int AppLayerTest04(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 4 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -1701,7 +1701,7 @@ static int AppLayerTest04(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -1767,7 +1767,7 @@ static int AppLayerTest05(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -1791,7 +1791,7 @@ static int AppLayerTest05(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -1815,7 +1815,7 @@ static int AppLayerTest05(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -1851,7 +1851,7 @@ static int AppLayerTest05(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -1917,7 +1917,7 @@ static int AppLayerTest05(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -1941,7 +1941,7 @@ static int AppLayerTest05(void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -2007,7 +2007,7 @@ static int AppLayerTest06(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2031,7 +2031,7 @@ static int AppLayerTest06(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2055,7 +2055,7 @@ static int AppLayerTest06(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2121,7 +2121,7 @@ static int AppLayerTest06(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOCLIENT) { @@ -2157,7 +2157,7 @@ static int AppLayerTest06(void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || + !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -2223,7 +2223,7 @@ static int AppLayerTest07(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2247,7 +2247,7 @@ static int AppLayerTest07(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2271,7 +2271,7 @@ static int AppLayerTest07(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2307,7 +2307,7 @@ static int AppLayerTest07(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -2373,7 +2373,7 @@ static int AppLayerTest07(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -2397,7 +2397,7 @@ static int AppLayerTest07(void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - (f.flags & FLOW_NO_APPLAYER_INSPECTION) || + (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -2463,7 +2463,7 @@ static int AppLayerTest08(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2487,7 +2487,7 @@ static int AppLayerTest08(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2511,7 +2511,7 @@ static int AppLayerTest08(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2547,7 +2547,7 @@ static int AppLayerTest08(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -2613,7 +2613,7 @@ static int AppLayerTest08(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -2637,11 +2637,11 @@ static int AppLayerTest08(void) f.alproto_tc != ALPROTO_DCERPC || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || + !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); + printf("failure 6 %04x\n", ssn->flags); goto end; } @@ -2705,7 +2705,7 @@ static int AppLayerTest09(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2729,7 +2729,7 @@ static int AppLayerTest09(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2753,7 +2753,7 @@ static int AppLayerTest09(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -2779,7 +2779,7 @@ static int AppLayerTest09(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -2803,7 +2803,7 @@ static int AppLayerTest09(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -2829,7 +2829,7 @@ static int AppLayerTest09(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -2895,7 +2895,7 @@ static int AppLayerTest09(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -2919,7 +2919,7 @@ static int AppLayerTest09(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || + !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -2986,7 +2986,7 @@ static int AppLayerTest10(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -3010,7 +3010,7 @@ static int AppLayerTest10(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -3034,7 +3034,7 @@ static int AppLayerTest10(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -3061,7 +3061,7 @@ static int AppLayerTest10(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -3085,7 +3085,7 @@ static int AppLayerTest10(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -3151,7 +3151,7 @@ static int AppLayerTest10(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -3175,7 +3175,7 @@ static int AppLayerTest10(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || + !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { @@ -3243,7 +3243,7 @@ static int AppLayerTest11(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -3267,7 +3267,7 @@ static int AppLayerTest11(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -3291,7 +3291,7 @@ static int AppLayerTest11(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != 0) { @@ -3318,7 +3318,7 @@ static int AppLayerTest11(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -3342,7 +3342,7 @@ static int AppLayerTest11(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -3368,7 +3368,7 @@ static int AppLayerTest11(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -3392,7 +3392,7 @@ static int AppLayerTest11(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -3457,7 +3457,7 @@ static int AppLayerTest11(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != STREAM_TOSERVER) { @@ -3481,7 +3481,7 @@ static int AppLayerTest11(void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || + !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 51ced8882824..4e64da6e8192 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -240,6 +240,7 @@ typedef struct TcpSession_ { #define StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream) \ ((stream)->flags &= ~STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED); #define StreamTcpDisableAppLayerReassembly(ssn) do { \ + SCLogDebug("setting STREAMTCP_FLAG_APP_LAYER_DISABLED on ssn %p", ssn); \ ((ssn)->flags |= STREAMTCP_FLAG_APP_LAYER_DISABLED); \ } while (0); diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index c319c468f768..8d9bd133d539 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -6175,7 +6175,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list != NULL || @@ -6202,7 +6202,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list != NULL || @@ -6230,7 +6230,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list != NULL || @@ -6259,7 +6259,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6289,7 +6289,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6330,7 +6330,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6402,7 +6402,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_UNKNOWN || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6431,7 +6431,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6460,7 +6460,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6488,7 +6488,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6516,7 +6516,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6546,7 +6546,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6576,7 +6576,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6605,7 +6605,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6635,7 +6635,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list->next == NULL || @@ -6678,7 +6678,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list != NULL || @@ -6705,7 +6705,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto_tc != ALPROTO_HTTP || f.data_al_so_far[0] != 0 || f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list != NULL || From c1558f5ac49a8be0e0946fe09688e7236154cf52 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Jan 2015 13:07:19 +0100 Subject: [PATCH 0452/2553] stream: remove FLOW_NO_APPLAYER_INSPECTION flag Instead, intruduce StreamTcpDisableAppLayer to disable app layer tracking and reassembly. StreamTcpAppLayerIsDisabled can be used to check it. Replace all uses of FlowSetSessionNoApplayerInspectionFlag and the FLOW_NO_APPLAYER_INSPECTION. --- src/alert-debuglog.c | 6 +++++- src/app-layer-parser.c | 29 +++++++++++++++++------------ src/app-layer-smtp.c | 4 ++-- src/app-layer.c | 31 ++++++++++++++----------------- src/detect.c | 4 ++-- src/flow.h | 13 ++----------- src/stream-tcp-reassemble.c | 22 ++++++++++++++++++++++ src/stream-tcp-reassemble.h | 4 ++++ src/stream-tcp.c | 2 +- 9 files changed, 69 insertions(+), 46 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 0a7402047256..27710a9d5903 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -54,6 +54,8 @@ #include "util-logopenfile.h" #include "util-time.h" +#include "stream-tcp-reassemble.h" + #define DEFAULT_LOG_FILENAME "alert-debug.log" #define MODULE_NAME "AlertDebugLog" @@ -213,7 +215,9 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da p->flowflags & FLOW_PKT_TOCLIENT ? "TRUE" : "FALSE"); if (p->flow != NULL) { + int applayer = 0; FLOWLOCK_RDLOCK(p->flow); + applayer = StreamTcpAppLayerIsDisabled(p->flow); CreateTimeString(&p->flow->startts, timebuf, sizeof(timebuf)); MemBufferWriteString(aft->buffer, "FLOW Start TS: %s\n", timebuf); MemBufferWriteString(aft->buffer, "FLOW PKTS TODST: %"PRIu32"\n" @@ -231,7 +235,7 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da p->flow->flags & FLOW_ACTION_DROP ? "TRUE" : "FALSE", p->flow->flags & FLOW_NOPACKET_INSPECTION ? "TRUE" : "FALSE", p->flow->flags & FLOW_NOPAYLOAD_INSPECTION ? "TRUE" : "FALSE", - p->flow->flags & FLOW_NO_APPLAYER_INSPECTION ? "TRUE" : "FALSE", + applayer ? "TRUE" : "FALSE", (p->flow->alproto != ALPROTO_UNKNOWN) ? "TRUE" : "FALSE", p->flow->alproto); AlertDebugLogFlowVars(aft, p); AlertDebugLogFlowBits(aft, (Packet *)p); /* < no const */ diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 289a59d7cd44..655da90213b1 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -904,17 +904,20 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp if (pstate->flags & APP_LAYER_PARSER_NO_INSPECTION) { AppLayerParserSetEOF(pstate); FlowSetNoPayloadInspectionFlag(f); - FlowSetSessionNoApplayerInspectionFlag(f); - /* Set the no reassembly flag for both the stream in this TcpSession */ - if (f->proto == IPPROTO_TCP && pstate->flags & APP_LAYER_PARSER_NO_REASSEMBLY) { - /* Used only if it's TCP */ - TcpSession *ssn = f->protoctx; - if (ssn != NULL) { - StreamTcpSetSessionNoReassemblyFlag(ssn, - flags & STREAM_TOCLIENT ? 1 : 0); - StreamTcpSetSessionNoReassemblyFlag(ssn, - flags & STREAM_TOSERVER ? 1 : 0); + if (f->proto == IPPROTO_TCP) { + StreamTcpDisableAppLayer(f); + + /* Set the no reassembly flag for both the stream in this TcpSession */ + if (pstate->flags & APP_LAYER_PARSER_NO_REASSEMBLY) { + /* Used only if it's TCP */ + TcpSession *ssn = f->protoctx; + if (ssn != NULL) { + StreamTcpSetSessionNoReassemblyFlag(ssn, + flags & STREAM_TOCLIENT ? 1 : 0); + StreamTcpSetSessionNoReassemblyFlag(ssn, + flags & STREAM_TOSERVER ? 1 : 0); + } } } } @@ -945,7 +948,9 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp error: /* Set the no app layer inspection flag for both * the stream in this Flow */ - FlowSetSessionNoApplayerInspectionFlag(f); + if (f->proto == IPPROTO_TCP) { + StreamTcpDisableAppLayer(f); + } AppLayerParserSetEOF(pstate); SCReturnInt(-1); } @@ -1280,7 +1285,7 @@ static int AppLayerParserTest01(void) } SCMutexUnlock(&f->m); - if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) { + if (!(ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) { printf("flag should have been set, but is not: "); goto end; } diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index c0772ec75ae4..bbfa7ae93202 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1622,7 +1622,7 @@ int SMTPParserTest01(void) } if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION) || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || + !(ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !(((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || !(((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { goto end; @@ -2907,7 +2907,7 @@ int SMTPParserTest05(void) } if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) || - (f.flags & FLOW_NO_APPLAYER_INSPECTION) || + (ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { goto end; diff --git a/src/app-layer.c b/src/app-layer.c index b1ccc3d082f8..f8bdf7738549 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -88,13 +88,10 @@ static void DNSUpdateCounters(ThreadVars *tv, AppLayerThreadCtx *app_tctx) /***** L7 layer dispatchers *****/ -static void DisableAppLayer(Flow *f, TcpSession *ssn) +static void DisableAppLayer(Flow *f) { - SCLogInfo("disable app layer for flow %p, ssn %p", f, ssn); - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpDisableAppLayerReassembly(ssn); + SCLogDebug("disable app layer for flow %p", f); + StreamTcpDisableAppLayer(f); } int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, @@ -116,8 +113,8 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, uint8_t first_data_dir; SCLogDebug("data_len %u flags %02X", data_len, flags); - if (f->flags & FLOW_NO_APPLAYER_INSPECTION) { - SCLogDebug("FLOW_AL_NO_APPLAYER_INSPECTION is set"); + if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) { + SCLogDebug("STREAMTCP_FLAG_APP_LAYER_DISABLED is set"); goto end; } @@ -230,7 +227,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } } if (ret < 0) { - DisableAppLayer(f, ssn); + DisableAppLayer(f); goto failure; } } @@ -257,7 +254,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) { AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_WRONG_DIRECTION_FIRST_DATA); - DisableAppLayer(f, ssn); + DisableAppLayer(f); /* Set a value that is neither STREAM_TOSERVER, nor STREAM_TOCLIENT */ ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; goto failure; @@ -306,7 +303,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { SCLogDebug("midstream end pd %p", ssn); /* midstream and toserver detection failed: give up */ - DisableAppLayer(f, ssn); + DisableAppLayer(f); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; goto end; } @@ -333,7 +330,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if ((ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) && (first_data_dir) && !(first_data_dir & flags)) { - DisableAppLayer(f, ssn); + DisableAppLayer(f); goto failure; } @@ -375,20 +372,20 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) { - DisableAppLayer(f, ssn); + DisableAppLayer(f); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; } else if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && size_ts > 100000 && size_tc == 0) { - DisableAppLayer(f, ssn); + DisableAppLayer(f); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); } else if (FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && size_tc > 100000 && size_ts == 0) { - DisableAppLayer(f, ssn); + DisableAppLayer(f); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); @@ -399,7 +396,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) { - DisableAppLayer(f, ssn); + DisableAppLayer(f); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); @@ -410,7 +407,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && !(FLOW_IS_PM_DONE(f, STREAM_TOCLIENT)) && FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { - DisableAppLayer(f, ssn); + DisableAppLayer(f); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); diff --git a/src/detect.c b/src/detect.c index 8ff406680549..2a2b2828d721 100644 --- a/src/detect.c +++ b/src/detect.c @@ -11583,7 +11583,7 @@ static int SigTestDropFlow03(void) SCLogDebug("This flow/stream triggered a drop rule"); FlowSetNoPacketInspectionFlag(p2->flow); DecodeSetNoPacketInspectionFlag(p2); - FlowSetSessionNoApplayerInspectionFlag(p2->flow); + StreamTcpDisableAppLayer(p2->flow); p2->action |= ACTION_DROP; /* return the segments to the pool */ StreamTcpSessionPktFree(p2); @@ -11766,7 +11766,7 @@ static int SigTestDropFlow04(void) if (StreamTcpCheckFlowDrops(p2) == 1) { FlowSetNoPacketInspectionFlag(p2->flow); DecodeSetNoPacketInspectionFlag(p2); - FlowSetSessionNoApplayerInspectionFlag(p2->flow); + StreamTcpDisableAppLayer(p2->flow); p2->action |= ACTION_DROP; /* return the segments to the pool */ StreamTcpSessionPktFree(p2); diff --git a/src/flow.h b/src/flow.h index 79147112b009..bc1f65ac882d 100644 --- a/src/flow.h +++ b/src/flow.h @@ -76,7 +76,8 @@ typedef struct AppLayerParserState_ AppLayerParserState; #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 + +// vacany 1x /** Pattern matcher alproto detection done */ #define FLOW_TS_PM_ALPROTO_DETECT_DONE 0x00020000 @@ -445,7 +446,6 @@ 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(const Flow *, const Packet *); @@ -513,15 +513,6 @@ static inline void FlowSetNoPayloadInspectionFlag(Flow *f) 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; -} - /** * \brief increase the use count of a flow * diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 8d9bd133d539..b53be3a4f5e0 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -279,6 +279,28 @@ void StreamTcpReturnStreamSegments (TcpStream *stream) stream->seg_list_tail = NULL; } +/** \param f locked flow */ +void StreamTcpDisableAppLayer(Flow *f) +{ + if (f->protoctx == NULL) + return; + + TcpSession *ssn = (TcpSession *)f->protoctx; + StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); + StreamTcpDisableAppLayerReassembly(ssn); +} + +/** \param f locked flow */ +int StreamTcpAppLayerIsDisabled(Flow *f) +{ + if (f->protoctx == NULL || f->proto != IPPROTO_TCP) + return 0; + + TcpSession *ssn = (TcpSession *)f->protoctx; + return (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); +} + typedef struct SegmentSizes_ { uint16_t pktsize; diff --git a/src/stream-tcp-reassemble.h b/src/stream-tcp-reassemble.h index 686c2e47d905..c934f4fabd83 100644 --- a/src/stream-tcp-reassemble.h +++ b/src/stream-tcp-reassemble.h @@ -109,5 +109,9 @@ int StreamTcpReassembleDepthReached(Packet *p); void StreamTcpReassembleIncrMemuse(uint64_t size); void StreamTcpReassembleDecrMemuse(uint64_t size); int StreamTcpReassembleCheckMemcap(uint32_t size); + +void StreamTcpDisableAppLayer(Flow *f); +int StreamTcpAppLayerIsDisabled(Flow *f); + #endif /* __STREAM_TCP_REASSEMBLE_H__ */ diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 9c51f3351216..ec427bd5e31c 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4481,7 +4481,7 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, SCLogDebug("This flow/stream triggered a drop rule"); FlowSetNoPacketInspectionFlag(p->flow); DecodeSetNoPacketInspectionFlag(p); - FlowSetSessionNoApplayerInspectionFlag(p->flow); + StreamTcpDisableAppLayer(p->flow); PACKET_DROP(p); /* return the segments to the pool */ StreamTcpSessionPktFree(p); From 9764a356047a191f0f5f0171371f560d316cf444 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 5 May 2015 19:43:33 +0200 Subject: [PATCH 0453/2553] stream: fix --disable-detection reassembly issue Due to an error at initialization, the stream engine would not disable 'raw' reassembly automatically when --disable-detection was used. This lead to segments not getting cleared from the segment lists. --- src/suricata.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 60bf9ed02570..d87f4d52ca4d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2240,6 +2240,11 @@ int main(int argc, char **argv) NSS_NoDB_Init(NULL); #endif + if (suri.disabled_detect) { + /* disable raw reassembly */ + (void)ConfSetFinal("stream.reassembly.raw", "false"); + } + HostInitConfig(HOST_VERBOSE); if (suri.run_mode != RUNMODE_UNIX_SOCKET) { FlowInitConfig(FLOW_VERBOSE); @@ -2279,9 +2284,6 @@ int main(int argc, char **argv) DetectEngineAddToMaster(de_ctx); } else { - /* disable raw reassembly */ - (void)ConfSetFinal("stream.reassembly.raw", "false"); - /* tell the app layer to consider only the log id */ RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveLogOnly); } From 393689ce44f4879952f011bb74ccd236d07acb76 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 12 May 2015 16:20:27 +0200 Subject: [PATCH 0454/2553] classification: remove global from parsing Parsing code used a 'fd' global. Remove this. --- src/alert-fastlog.c | 10 ++-- src/detect-classtype.c | 15 +++--- src/detect-engine.c | 2 +- src/detect-msg.c | 5 +- src/detect-parse.c | 5 +- src/log-droplog.c | 10 ++-- src/util-classification-config.c | 92 +++++++++++++------------------- src/util-classification-config.h | 9 ++-- 8 files changed, 59 insertions(+), 89 deletions(-) diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 27fdbe44592c..ce198658e630 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -298,9 +298,8 @@ static int AlertFastLogTest01() de_ctx->flags |= DE_QUIET; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"FastLog test\"; content:\"GET\"; " @@ -346,9 +345,8 @@ static int AlertFastLogTest02() de_ctx->flags |= DE_QUIET; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"FastLog test\"; content:\"GET\"; " diff --git a/src/detect-classtype.c b/src/detect-classtype.c index fd0aebeb88f1..bc77371006ca 100644 --- a/src/detect-classtype.c +++ b/src/detect-classtype.c @@ -182,9 +182,8 @@ int DetectClasstypeTest01() goto end; } - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; " @@ -214,9 +213,8 @@ int DetectClasstypeTest02() goto end; } - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:bad-unknown; sid:1;)"); @@ -281,9 +279,8 @@ int DetectClasstypeTest03() goto end; } - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:bad-unknown; priority:1; sid:1;)"); diff --git a/src/detect-engine.c b/src/detect-engine.c index 742a2560c9e4..6489069dfe41 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -821,7 +821,7 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) SCProfilingKeywordInitCounters(de_ctx); #endif - SCClassConfLoadClassficationConfigFile(de_ctx); + SCClassConfLoadClassficationConfigFile(de_ctx, NULL); SCRConfLoadReferenceConfigFile(de_ctx); if (ActionInitConfig() < 0) { diff --git a/src/detect-msg.c b/src/detect-msg.c index abd861001da0..e8b87529673a 100644 --- a/src/detect-msg.c +++ b/src/detect-msg.c @@ -148,9 +148,8 @@ static int DetectMsgParseTest01(void) if (de_ctx == NULL) goto end; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"flow stateless to_server\"; flow:stateless,to_server; content:\"flowstatelesscheck\"; classtype:bad-unknown; sid: 40000002; rev: 1;)"); if(sig == NULL) diff --git a/src/detect-parse.c b/src/detect-parse.c index 4b084d0e2519..87745c15d5bd 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1918,9 +1918,8 @@ int SigParseTest02 (void) if (de_ctx == NULL) goto end; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); if (sig == NULL) { diff --git a/src/log-droplog.c b/src/log-droplog.c index 34447ae2171e..877d243754f3 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -384,9 +384,8 @@ int LogDropLogTest01() de_ctx->flags |= DE_QUIET; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any " "(msg:\"LogDropLog test\"; content:\"GET\"; Classtype:unknown; sid:1;)"); @@ -453,9 +452,8 @@ int LogDropLogTest02() de_ctx->flags |= DE_QUIET; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"LogDropLog test\"; content:\"GET\"; Classtype:unknown; sid:1;)"); diff --git a/src/util-classification-config.c b/src/util-classification-config.c index ea696d7b7fb5..af952e67593e 100644 --- a/src/util-classification-config.c +++ b/src/util-classification-config.c @@ -49,7 +49,6 @@ /* Holds a pointer to the default path for the classification.config file */ static const char *default_file_path = SC_CLASS_CONF_DEF_CONF_FILEPATH; -static FILE *fd = NULL; static pcre *regex = NULL; static pcre_extra *regex_study = NULL; @@ -70,10 +69,9 @@ static char *SCClassConfGetConfFilename(void); * * \param de_ctx Pointer to the Detection Engine Context. * - * \retval 0 On success. - * \retval -1 On failure. + * \retval fp NULL on error */ -int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) +FILE *SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) { char *filename = NULL; const char *eb = NULL; @@ -119,7 +117,7 @@ int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) goto error; } - return 0; + return fd; error: if (de_ctx->class_conf_ht != NULL) { @@ -140,7 +138,7 @@ int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) regex_study = NULL; } - return -1; + return NULL; } @@ -167,12 +165,14 @@ static char *SCClassConfGetConfFilename(void) /** * \brief Releases resources used by the Classification Config API. */ -static void SCClassConfDeInitLocalResources(DetectEngineCtx *de_ctx) +static void SCClassConfDeInitLocalResources(DetectEngineCtx *de_ctx, FILE *fd) { + if (fd != NULL) { + fclose(fd); + fd = NULL; + } - fclose(fd); default_file_path = SC_CLASS_CONF_DEF_CONF_FILEPATH; - fd = NULL; if (regex != NULL) { pcre_free(regex); regex = NULL; @@ -341,7 +341,7 @@ static int SCClassConfIsLineBlankOrComment(char *line) * * \param de_ctx Pointer to the Detection Engine Context. */ -void SCClassConfParseFile(DetectEngineCtx *de_ctx) +void SCClassConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) { char line[1024]; uint8_t i = 1; @@ -517,9 +517,10 @@ void SCClassConfClasstypeHashFree(void *ch) * \param de_ctx Pointer to the Detection Engine Context that should be updated * with Classtype information. */ -void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx) +void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx, FILE *fd) { - if (SCClassConfInitContextAndLocalResources(de_ctx) == -1) { + fd = SCClassConfInitContextAndLocalResources(de_ctx, fd); + if (fd == NULL) { #ifdef UNITTESTS if (RunmodeIsUnittests() && fd == NULL) { return; @@ -530,8 +531,8 @@ void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx) return; } - SCClassConfParseFile(de_ctx); - SCClassConfDeInitLocalResources(de_ctx); + SCClassConfParseFile(de_ctx, fd); + SCClassConfDeInitLocalResources(de_ctx, fd); return; } @@ -573,18 +574,18 @@ SCClassConfClasstype *SCClassConfGetClasstype(const char *ct_name, * * \file_path Pointer to the file_path for the dummy classification file. */ -void SCClassConfGenerateValidDummyClassConfigFD01(void) +FILE *SCClassConfGenerateValidDummyClassConfigFD01(void) { const char *buffer = "config classification: nothing-wrong,Nothing Wrong With Us,3\n" "config classification: unknown,Unknown are we,3\n" "config classification: bad-unknown,We think it's bad, 2\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Classifiation Config test code"); - return; + return fd; } /** @@ -593,7 +594,7 @@ void SCClassConfGenerateValidDummyClassConfigFD01(void) * * \file_path Pointer to the file_path for the dummy classification file. */ -void SCClassConfGenerateInValidDummyClassConfigFD02(void) +FILE *SCClassConfGenerateInValidDummyClassConfigFD02(void) { const char *buffer = "config classification: not-suspicious,Not Suspicious Traffic,3\n" @@ -604,11 +605,11 @@ void SCClassConfGenerateInValidDummyClassConfigFD02(void) "config classification: policy-violation,Potential Corporate " "config classification: bamboola,Unknown Traffic,3\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Classifiation Config test code"); - return; + return fd; } /** @@ -617,7 +618,7 @@ void SCClassConfGenerateInValidDummyClassConfigFD02(void) * * \file_path Pointer to the file_path for the dummy classification file. */ -void SCClassConfGenerateInValidDummyClassConfigFD03(void) +FILE *SCClassConfGenerateInValidDummyClassConfigFD03(void) { const char *buffer = "conig classification: not-suspicious,Not Suspicious Traffic,3\n" @@ -625,26 +626,11 @@ void SCClassConfGenerateInValidDummyClassConfigFD03(void) "config classification: _badunknown,Potentially Bad Traffic, 2\n" "config classification: misc-activity,Misc activity,-1\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Classifiation Config test code"); - return; -} - -/** - * \brief Deletes a file, whose path is specified as the argument. - * - * \file_path Pointer to the file_path that has to be deleted. - */ -void SCClassConfDeleteDummyClassificationConfigFD(void) -{ - if (fd != NULL) { - fclose(fd); - fd = NULL; - } - - return; + return fd; } /** @@ -659,9 +645,8 @@ int SCClassConfTest01(void) if (de_ctx == NULL) return result; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return result; @@ -686,9 +671,8 @@ int SCClassConfTest02(void) if (de_ctx == NULL) return result; - SCClassConfGenerateInValidDummyClassConfigFD03(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateInValidDummyClassConfigFD03(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return result; @@ -712,9 +696,8 @@ int SCClassConfTest03(void) if (de_ctx == NULL) return result; - SCClassConfGenerateInValidDummyClassConfigFD02(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateInValidDummyClassConfigFD02(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return result; @@ -738,9 +721,8 @@ int SCClassConfTest04(void) if (de_ctx == NULL) return 0; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return 0; @@ -772,9 +754,8 @@ int SCClassConfTest05(void) if (de_ctx == NULL) return 0; - SCClassConfGenerateInValidDummyClassConfigFD03(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateInValidDummyClassConfigFD03(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return 0; @@ -805,9 +786,8 @@ int SCClassConfTest06(void) if (de_ctx == NULL) return 0; - SCClassConfGenerateInValidDummyClassConfigFD02(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateInValidDummyClassConfigFD02(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return 0; diff --git a/src/util-classification-config.h b/src/util-classification-config.h index 4d0c80a2675c..7d9748ed5997 100644 --- a/src/util-classification-config.h +++ b/src/util-classification-config.h @@ -45,16 +45,15 @@ typedef struct SCClassConfClasstype_ { SCClassConfClasstype *SCClassConfAllocClasstype(uint8_t, const char *, const char *, int); void SCClassConfDeAllocClasstype(SCClassConfClasstype *); -void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *); +void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *, FILE *fd); SCClassConfClasstype *SCClassConfGetClasstype(const char *, DetectEngineCtx *); void SCClassConfDeInitContext(DetectEngineCtx *); void SCClassConfRegisterTests(void); /* for unittests */ -void SCClassConfGenerateValidDummyClassConfigFD01(void); -void SCClassConfGenerateInValidDummyClassConfigFD02(void); -void SCClassConfGenerateInValidDummyClassConfigFD03(void); -void SCClassConfDeleteDummyClassificationConfigFD(void); +FILE *SCClassConfGenerateValidDummyClassConfigFD01(void); +FILE *SCClassConfGenerateInValidDummyClassConfigFD02(void); +FILE *SCClassConfGenerateInValidDummyClassConfigFD03(void); #endif /* __UTIL_CLASSIFICATION_CONFIG_H__ */ From b2da57c82713847747ca4fae452f10d902e3e2ef Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 12 May 2015 16:53:02 +0200 Subject: [PATCH 0455/2553] reference: remove global --- src/detect-engine.c | 2 +- src/detect-reference.c | 15 +++---- src/util-reference-config.c | 86 +++++++++++++++---------------------- src/util-reference-config.h | 9 ++-- 4 files changed, 45 insertions(+), 67 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 6489069dfe41..ba02dfa228f1 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -822,7 +822,7 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) #endif SCClassConfLoadClassficationConfigFile(de_ctx, NULL); - SCRConfLoadReferenceConfigFile(de_ctx); + SCRConfLoadReferenceConfigFile(de_ctx, NULL); if (ActionInitConfig() < 0) { goto error; diff --git a/src/detect-reference.c b/src/detect-reference.c index 55d33d2f6d5c..a672f5c2fcdc 100644 --- a/src/detect-reference.c +++ b/src/detect-reference.c @@ -242,9 +242,8 @@ static int DetectReferenceParseTest01(void) } de_ctx->flags |= DE_QUIET; - SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"One reference\"; reference:one,001-2010; sid:2;)"); @@ -289,9 +288,8 @@ static int DetectReferenceParseTest02(void) } de_ctx->flags |= DE_QUIET; - SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"Two references\"; " @@ -344,9 +342,8 @@ static int DetectReferenceParseTest03(void) } de_ctx->flags |= DE_QUIET; - SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd =SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"invalid ref\"; " diff --git a/src/util-reference-config.c b/src/util-reference-config.c index 30b1a366d1df..59aaf0a9fcbf 100644 --- a/src/util-reference-config.c +++ b/src/util-reference-config.c @@ -43,7 +43,6 @@ /* Holds a pointer to the default path for the reference.config file */ static const char *file_path = SC_RCONF_DEFAULT_FILE_PATH; -static FILE *fd = NULL; static pcre *regex = NULL; static pcre_extra *regex_study = NULL; @@ -69,7 +68,7 @@ static char *SCRConfGetConfFilename(void); * \retval 0 On success. * \retval -1 On failure. */ -static int SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) +static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) { char *filename = NULL; const char *eb = NULL; @@ -116,7 +115,7 @@ static int SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) goto error; } - return 0; + return fd; error: if (de_ctx->reference_conf_ht != NULL) { @@ -137,7 +136,7 @@ static int SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) regex_study = NULL; } - return -1; + return NULL; } @@ -162,12 +161,13 @@ static char *SCRConfGetConfFilename(void) /** * \brief Releases local resources used by the Reference Config API. */ -static void SCRConfDeInitLocalResources(DetectEngineCtx *de_ctx) +static void SCRConfDeInitLocalResources(DetectEngineCtx *de_ctx, FILE *fd) { - if (fd != NULL) + if (fd != NULL) { fclose(fd); + fd = NULL; + } file_path = SC_RCONF_DEFAULT_FILE_PATH; - fd = NULL; if (regex != NULL) { pcre_free(regex); @@ -319,7 +319,7 @@ static int SCRConfIsLineBlankOrComment(char *line) * * \param de_ctx Pointer to the Detection Engine Context. */ -static void SCRConfParseFile(DetectEngineCtx *de_ctx) +static void SCRConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) { char line[1024]; uint8_t i = 1; @@ -487,9 +487,10 @@ void SCRConfReferenceHashFree(void *data) * \retval 0 On success. * \retval -1 On failure. */ -int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx) +int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx, FILE *fd) { - if (SCRConfInitContextAndLocalResources(de_ctx) == -1) { + fd = SCRConfInitContextAndLocalResources(de_ctx, fd); + if (fd == NULL) { #ifdef UNITTESTS if (RunmodeIsUnittests() && fd == NULL) { return -1; @@ -500,8 +501,8 @@ int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx) return -1; } - SCRConfParseFile(de_ctx); - SCRConfDeInitLocalResources(de_ctx); + SCRConfParseFile(de_ctx, fd); + SCRConfDeInitLocalResources(de_ctx, fd); return 0; } @@ -539,7 +540,7 @@ SCRConfReference *SCRConfGetReference(const char *rconf_name, * \brief Creates a dummy reference config, with all valid references, for * testing purposes. */ -void SCRConfGenerateValidDummyReferenceConfigFD01(void) +FILE *SCRConfGenerateValidDummyReferenceConfigFD01(void) { const char *buffer = "config reference: one http://www.one.com\n" @@ -548,18 +549,18 @@ void SCRConfGenerateValidDummyReferenceConfigFD01(void) "config reference: one http://www.one.com\n" "config reference: three http://www.three.com\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); - return; + return fd; } /** * \brief Creates a dummy reference config, with some valid references and a * couple of invalid references, for testing purposes. */ -void SCRConfGenerateInValidDummyReferenceConfigFD02(void) +FILE *SCRConfGenerateInValidDummyReferenceConfigFD02(void) { const char *buffer = "config reference: one http://www.one.com\n" @@ -568,18 +569,18 @@ void SCRConfGenerateInValidDummyReferenceConfigFD02(void) "config reference: four\n" "config reference five http://www.five.com\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); - return; + return fd; } /** * \brief Creates a dummy reference config, with all invalid references, for * testing purposes. */ -void SCRConfGenerateInValidDummyReferenceConfigFD03(void) +FILE *SCRConfGenerateInValidDummyReferenceConfigFD03(void) { const char *buffer = "config reference one http://www.one.com\n" @@ -587,24 +588,11 @@ void SCRConfGenerateInValidDummyReferenceConfigFD03(void) "config reference_: three http://www.three.com\n" "config reference: four\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); - return; -} - -/** - * \brief Deletes the FD, if set by the other testing functions. - */ -void SCRConfDeleteDummyReferenceConfigFD(void) -{ - if (fd != NULL) { - fclose(fd); - fd = NULL; - } - - return; + return fd; } /** @@ -619,9 +607,8 @@ int SCRConfTest01(void) if (de_ctx == NULL) return result; - SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -648,9 +635,8 @@ int SCRConfTest02(void) if (de_ctx == NULL) return result; - SCRConfGenerateInValidDummyReferenceConfigFD03(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateInValidDummyReferenceConfigFD03(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -676,9 +662,8 @@ int SCRConfTest03(void) if (de_ctx == NULL) return result; - SCRConfGenerateInValidDummyReferenceConfigFD02(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateInValidDummyReferenceConfigFD02(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -703,9 +688,8 @@ int SCRConfTest04(void) if (de_ctx == NULL) return 0; - SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -736,9 +720,8 @@ int SCRConfTest05(void) if (de_ctx == NULL) return 0; - SCRConfGenerateInValidDummyReferenceConfigFD03(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateInValidDummyReferenceConfigFD03(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -769,9 +752,8 @@ int SCRConfTest06(void) if (de_ctx == NULL) return 0; - SCRConfGenerateInValidDummyReferenceConfigFD02(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateInValidDummyReferenceConfigFD02(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; diff --git a/src/util-reference-config.h b/src/util-reference-config.h index f5b7ddb296b5..98cc51b14975 100644 --- a/src/util-reference-config.h +++ b/src/util-reference-config.h @@ -36,16 +36,15 @@ typedef struct SCRConfReference_ { SCRConfReference *SCRConfAllocSCRConfReference(const char *, const char *); void SCRConfDeAllocSCRConfReference(SCRConfReference *); -int SCRConfLoadReferenceConfigFile(DetectEngineCtx *); +int SCRConfLoadReferenceConfigFile(DetectEngineCtx *, FILE *); void SCRConfDeInitContext(DetectEngineCtx *); SCRConfReference *SCRConfGetReference(const char *, DetectEngineCtx *); void SCRConfRegisterTests(void); /* these below functions are only used by unittests */ -void SCRConfGenerateValidDummyReferenceConfigFD01(void); -void SCRConfGenerateInValidDummyReferenceConfigFD02(void); -void SCRConfGenerateInValidDummyReferenceConfigFD03(void); -void SCRConfDeleteDummyReferenceConfigFD(void); +FILE *SCRConfGenerateValidDummyReferenceConfigFD01(void); +FILE *SCRConfGenerateInValidDummyReferenceConfigFD02(void); +FILE *SCRConfGenerateInValidDummyReferenceConfigFD03(void); #endif /* __UTIL_REFERENCE_CONFIG_H__ */ From 46d401e3bbecc92405665b866be4d0e9a30abc4d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 May 2015 09:37:39 +0200 Subject: [PATCH 0456/2553] classification: update pcre globals use Don't update globals each time we parse, but instead do it once at startup. --- src/suricata.c | 4 ++ src/util-classification-config.c | 77 +++++++++++++++----------------- src/util-classification-config.h | 3 ++ 3 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index d87f4d52ca4d..9582b106fb20 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2257,6 +2257,7 @@ int main(int argc, char **argv) DetectEngineCtx *de_ctx = NULL; if (!suri.disabled_detect) { + SCClassConfInit(); SetupDelayedDetect(&suri); if (!suri.delayed_detect) { de_ctx = DetectEngineCtxInit(); @@ -2485,6 +2486,9 @@ int main(int argc, char **argv) if (suri.run_mode != RUNMODE_UNIX_SOCKET) { DefragDestroy(); } + if (!suri.disabled_detect) { + SCClassConfDeinit(); + } MagicDeinit(); TmqhCleanup(); TmModuleRunDeInit(); diff --git a/src/util-classification-config.c b/src/util-classification-config.c index af952e67593e..3711dd32b1b3 100644 --- a/src/util-classification-config.c +++ b/src/util-classification-config.c @@ -47,8 +47,6 @@ #define SC_CLASS_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/classification.config" #endif -/* Holds a pointer to the default path for the classification.config file */ -static const char *default_file_path = SC_CLASS_CONF_DEF_CONF_FILEPATH; static pcre *regex = NULL; static pcre_extra *regex_study = NULL; @@ -58,6 +56,42 @@ char SCClassConfClasstypeHashCompareFunc(void *data1, uint16_t datalen1, void SCClassConfClasstypeHashFree(void *ch); static char *SCClassConfGetConfFilename(void); +void SCClassConfInit(void) +{ + const char *eb = NULL; + int eo; + int opts = 0; + + regex = pcre_compile(DETECT_CLASSCONFIG_REGEX, opts, &eb, &eo, NULL); + if (regex == NULL) { + SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", + DETECT_CLASSCONFIG_REGEX, eo, eb); + return; + } + + regex_study = pcre_study(regex, 0, &eb); + if (eb != NULL) { + pcre_free(regex); + regex = NULL; + SCLogDebug("pcre study failed: %s", eb); + return; + } + return; +} + +void SCClassConfDeinit(void) +{ + if (regex != NULL) { + pcre_free(regex); + regex = NULL; + } + if (regex_study != NULL) { + pcre_free(regex_study); + regex_study = NULL; + } +} + + /** * \brief Inits the context to be used by the Classification Config parsing API. * @@ -74,9 +108,6 @@ static char *SCClassConfGetConfFilename(void); FILE *SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) { char *filename = NULL; - const char *eb = NULL; - int eo; - int opts = 0; /* init the hash table to be used by the classification config Classtypes */ de_ctx->class_conf_ht = HashTableInit(128, SCClassConfClasstypeHashFunc, @@ -104,19 +135,6 @@ FILE *SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) } } - regex = pcre_compile(DETECT_CLASSCONFIG_REGEX, opts, &eb, &eo, NULL); - if (regex == NULL) { - SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", - DETECT_CLASSCONFIG_REGEX, eo, eb); - goto error; - } - - regex_study = pcre_study(regex, 0, &eb); - if (eb != NULL) { - SCLogDebug("pcre study failed: %s", eb); - goto error; - } - return fd; error: @@ -129,15 +147,6 @@ FILE *SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) fd = NULL; } - if (regex != NULL) { - pcre_free(regex); - regex = NULL; - } - if (regex_study != NULL) { - pcre_free(regex_study); - regex_study = NULL; - } - return NULL; } @@ -156,7 +165,7 @@ static char *SCClassConfGetConfFilename(void) char *log_filename = NULL; if (ConfGet("classification-file", &log_filename) != 1) { - log_filename = (char *)default_file_path; + log_filename = (char *)SC_CLASS_CONF_DEF_CONF_FILEPATH; } return log_filename; @@ -171,18 +180,6 @@ static void SCClassConfDeInitLocalResources(DetectEngineCtx *de_ctx, FILE *fd) fclose(fd); fd = NULL; } - - default_file_path = SC_CLASS_CONF_DEF_CONF_FILEPATH; - if (regex != NULL) { - pcre_free(regex); - regex = NULL; - } - if (regex_study != NULL) { - pcre_free(regex_study); - regex_study = NULL; - } - - return; } /** diff --git a/src/util-classification-config.h b/src/util-classification-config.h index 7d9748ed5997..7e916c2cd2ef 100644 --- a/src/util-classification-config.h +++ b/src/util-classification-config.h @@ -56,4 +56,7 @@ FILE *SCClassConfGenerateValidDummyClassConfigFD01(void); FILE *SCClassConfGenerateInValidDummyClassConfigFD02(void); FILE *SCClassConfGenerateInValidDummyClassConfigFD03(void); +void SCClassConfInit(void); +void SCClassConfDeinit(void); + #endif /* __UTIL_CLASSIFICATION_CONFIG_H__ */ From 34f2ff067b1af35cbe9ca3e869db03c3d109e42b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 May 2015 09:53:49 +0200 Subject: [PATCH 0457/2553] reference: update pcre globals use Don't update globals each time we parse, but instead do it once at startup. --- src/suricata.c | 2 + src/util-reference-config.c | 76 ++++++++++++++++++------------------- src/util-reference-config.h | 3 ++ 3 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 9582b106fb20..d0971ab4843f 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2258,6 +2258,7 @@ int main(int argc, char **argv) DetectEngineCtx *de_ctx = NULL; if (!suri.disabled_detect) { SCClassConfInit(); + SCReferenceConfInit(); SetupDelayedDetect(&suri); if (!suri.delayed_detect) { de_ctx = DetectEngineCtxInit(); @@ -2487,6 +2488,7 @@ int main(int argc, char **argv) DefragDestroy(); } if (!suri.disabled_detect) { + SCReferenceConfDeinit(); SCClassConfDeinit(); } MagicDeinit(); diff --git a/src/util-reference-config.c b/src/util-reference-config.c index 59aaf0a9fcbf..a2f09bd36042 100644 --- a/src/util-reference-config.c +++ b/src/util-reference-config.c @@ -41,8 +41,6 @@ /* Default path for the reference.conf file */ #define SC_RCONF_DEFAULT_FILE_PATH CONFIG_DIR "/reference.config" -/* Holds a pointer to the default path for the reference.config file */ -static const char *file_path = SC_RCONF_DEFAULT_FILE_PATH; static pcre *regex = NULL; static pcre_extra *regex_study = NULL; @@ -55,6 +53,43 @@ void SCRConfReferenceHashFree(void *ch); /* used to get the reference.config file path */ static char *SCRConfGetConfFilename(void); +void SCReferenceConfInit(void) +{ + const char *eb = NULL; + int eo; + int opts = 0; + + regex = pcre_compile(SC_RCONF_REGEX, opts, &eb, &eo, NULL); + if (regex == NULL) { + SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", + SC_RCONF_REGEX, eo, eb); + return; + } + + regex_study = pcre_study(regex, 0, &eb); + if (eb != NULL) { + pcre_free(regex); + regex = NULL; + SCLogDebug("pcre study failed: %s", eb); + return; + } + + return; +} + +void SCReferenceConfDeinit(void) +{ + if (regex != NULL) { + pcre_free(regex); + regex = NULL; + } + if (regex_study != NULL) { + pcre_free(regex_study); + regex_study = NULL; + } +} + + /** * \brief Inits the context to be used by the Reference Config parsing API. * @@ -71,9 +106,6 @@ static char *SCRConfGetConfFilename(void); static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) { char *filename = NULL; - const char *eb = NULL; - int eo; - int opts = 0; /* init the hash table to be used by the reference config references */ de_ctx->reference_conf_ht = HashTableInit(128, SCRConfReferenceHashFunc, @@ -102,19 +134,6 @@ static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE * } } - regex = pcre_compile(SC_RCONF_REGEX, opts, &eb, &eo, NULL); - if (regex == NULL) { - SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", - SC_RCONF_REGEX, eo, eb); - goto error; - } - - regex_study = pcre_study(regex, 0, &eb); - if (eb != NULL) { - SCLogDebug("pcre study failed: %s", eb); - goto error; - } - return fd; error: @@ -127,15 +146,6 @@ static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE * fd = NULL; } - if (regex != NULL) { - pcre_free(regex); - regex = NULL; - } - if (regex_study != NULL) { - pcre_free(regex_study); - regex_study = NULL; - } - return NULL; } @@ -153,7 +163,7 @@ static char *SCRConfGetConfFilename(void) { char *path = NULL; if (ConfGet("reference-config-file", &path) != 1) { - return (char *)file_path; + return (char *)SC_RCONF_DEFAULT_FILE_PATH; } return path; } @@ -167,16 +177,6 @@ static void SCRConfDeInitLocalResources(DetectEngineCtx *de_ctx, FILE *fd) fclose(fd); fd = NULL; } - file_path = SC_RCONF_DEFAULT_FILE_PATH; - - if (regex != NULL) { - pcre_free(regex); - regex = NULL; - } - if (regex_study != NULL) { - pcre_free(regex_study); - regex_study = NULL; - } return; } diff --git a/src/util-reference-config.h b/src/util-reference-config.h index 98cc51b14975..f7fe4cc1ebdb 100644 --- a/src/util-reference-config.h +++ b/src/util-reference-config.h @@ -47,4 +47,7 @@ FILE *SCRConfGenerateValidDummyReferenceConfigFD01(void); FILE *SCRConfGenerateInValidDummyReferenceConfigFD02(void); FILE *SCRConfGenerateInValidDummyReferenceConfigFD03(void); +void SCReferenceConfInit(void); +void SCReferenceConfDeinit(void); + #endif /* __UTIL_REFERENCE_CONFIG_H__ */ From cc01b5f6b6c2e01968565dc15efd04040d31b1ea Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 May 2015 10:21:20 +0200 Subject: [PATCH 0458/2553] reference/classification: call global init for unittests --- src/runmode-unittests.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 378d3c801e52..2d3ad232525c 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -169,6 +169,8 @@ void RunUnittests(int list_unittests, char *regex_arg) SCProtoNameInit(); TagInitCtx(); + SCReferenceConfInit(); + SCClassConfInit(); RegisterAllModules(); From df5e9d44ca0904a20ed198f22d21dc4bba8a188b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 May 2015 16:52:11 +0200 Subject: [PATCH 0459/2553] unix-manager: convert to thread module Sync command thread for unix manager with other managers and make it a full thread module. --- src/suricata.c | 2 ++ src/tm-modules.c | 1 + src/tm-modules.h | 1 + src/tm-threads-common.h | 2 ++ src/tm-threads.c | 35 ++++++++++++++++++++++++++++++ src/tm-threads.h | 2 ++ src/unix-manager.c | 48 +++++++++++++++++++++++++++++++---------- src/unix-manager.h | 2 ++ 8 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index d0971ab4843f..6a8f0679508d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -797,6 +797,8 @@ int g_ut_covered; void RegisterAllModules() { + /* commanders */ + TmModuleUnixManagerRegister(); /* managers */ TmModuleFlowManagerRegister(); TmModuleFlowRecyclerRegister(); diff --git a/src/tm-modules.c b/src/tm-modules.c index bd990b4e119c..3c6d6d229271 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -267,6 +267,7 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_OUTPUTJSON); CASE_CODE (TMM_FLOWMANAGER); CASE_CODE (TMM_FLOWRECYCLER); + CASE_CODE (TMM_UNIXMANAGER); CASE_CODE (TMM_LUALOG); CASE_CODE (TMM_LOGSTATSLOG); CASE_CODE (TMM_RECEIVENETMAP); diff --git a/src/tm-modules.h b/src/tm-modules.h index a606306c5590..6502b21c1080 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -34,6 +34,7 @@ #define TM_FLAG_DETECT_TM 0x08 #define TM_FLAG_LOGAPI_TM 0x10 /**< TM is run by Log API */ #define TM_FLAG_MANAGEMENT_TM 0x20 +#define TM_FLAG_COMMAND_TM 0x40 typedef struct TmModule_ { char *name; diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index c18e50876521..5affa40c1866 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -104,6 +104,8 @@ typedef enum { TMM_FLOWMANAGER, TMM_FLOWRECYCLER, + TMM_UNIXMANAGER, + TMM_LUALOG, TMM_SIZE, } TmmId; diff --git a/src/tm-threads.c b/src/tm-threads.c index 92f35e5178d8..b77f52af4dbd 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -662,6 +662,8 @@ TmEcode TmThreadSetSlots(ThreadVars *tv, char *name, void *(*fn_p)(void *)) tv->tm_func = TmThreadsSlotPktAcqLoop; } else if (strcmp(name, "management") == 0) { tv->tm_func = TmThreadsManagement; + } else if (strcmp(name, "command") == 0) { + tv->tm_func = TmThreadsManagement; } else if (strcmp(name, "custom") == 0) { if (fn_p == NULL) goto error; @@ -1227,6 +1229,39 @@ ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, return tv; } +/** + * \brief Creates and returns the TV instance for a Command thread (CMD). + * This function supports only custom slot functions and hence a + * function pointer should be sent as an argument. + * + * \param name Name of this TV instance + * \param module Name of TmModule with COMMAND flag set. + * \param mucond Flag to indicate whether to initialize the condition + * and the mutex variables for this newly created TV. + * + * \retval the newly created TV instance, or NULL on error + */ +ThreadVars *TmThreadCreateCmdThreadByName(char *name, char *module, + int mucond) +{ + ThreadVars *tv = NULL; + + tv = TmThreadCreate(name, NULL, NULL, NULL, NULL, "command", NULL, mucond); + + if (tv != NULL) { + tv->type = TVT_CMD; + tv->id = TmThreadsRegisterThread(tv, tv->type); + TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); + + TmModule *m = TmModuleGetByName(module); + if (m) { + TmSlotSetFuncAppend(tv, m, NULL); + } + } + + return tv; +} + /** * \brief Creates and returns the TV instance for a CMD thread. * This function supports only custom slot functions and hence a diff --git a/src/tm-threads.h b/src/tm-threads.h index 0c92a4bdb09d..363a30b8b3d2 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -92,6 +92,8 @@ ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), int); ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, int mucond); ThreadVars *TmThreadCreateCmdThread(char *name, void *(fn_p)(void *), int); +ThreadVars *TmThreadCreateCmdThreadByName(char *name, char *module, + int mucond); TmEcode TmThreadSpawn(ThreadVars *); void TmThreadSetFlags(ThreadVars *, uint8_t); void TmThreadSetAOF(ThreadVars *, uint8_t); diff --git a/src/unix-manager.c b/src/unix-manager.c index e86bae81aab9..b8eb0045ca44 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -841,13 +841,31 @@ TmEcode UnixManagerRegisterBackgroundTask(TmEcode (*Func)(void *), SCReturnInt(TM_ECODE_OK); } -void *UnixManagerThread(void *td) +typedef struct UnixManagerThreadData_ { + int padding; +} UnixManagerThreadData; + +static TmEcode UnixManagerThreadInit(ThreadVars *t, void *initdata, void **data) +{ + UnixManagerThreadData *utd = SCCalloc(1, sizeof(*utd)); + if (utd == NULL) + return TM_ECODE_FAILED; + + *data = utd; + return TM_ECODE_OK; +} + +static TmEcode UnixManagerThreadDeinit(ThreadVars *t, void *data) +{ + SCFree(data); + return TM_ECODE_OK; +} + +static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) { - ThreadVars *th_v = (ThreadVars *)td; int ret; /* set the thread name */ - (void) SCSetThreadName(th_v->name); SCLogDebug("%s started...", th_v->name); th_v->sc_perf_pca = SCPerfGetAllCountersArray(&th_v->sc_perf_pctx); @@ -863,8 +881,7 @@ void *UnixManagerThread(void *td) if (failure_fatal) { exit(EXIT_FAILURE); } else { - TmThreadsSetFlag(th_v, THV_INIT_DONE|THV_RUNNING_DONE); - pthread_exit((void *) 0); + return TM_ECODE_FAILED; } } @@ -904,10 +921,7 @@ void *UnixManagerThread(void *td) UnixCommandBackgroundTasks(&command); } - TmThreadWaitForFlag(th_v, THV_DEINIT); - - TmThreadsSetFlag(th_v, THV_CLOSED); - pthread_exit((void *) 0); + return TM_ECODE_OK; } @@ -922,8 +936,8 @@ void UnixManagerThreadSpawn(int mode) SCCtrlCondInit(&unix_manager_ctrl_cond, NULL); SCCtrlMutexInit(&unix_manager_ctrl_mutex, NULL); - tv_unixmgr = TmThreadCreateCmdThread("UnixManagerThread", - UnixManagerThread, 0); + tv_unixmgr = TmThreadCreateCmdThreadByName("UnixManagerThread", + "UnixManager", 0); if (tv_unixmgr == NULL) { SCLogError(SC_ERR_INITIALIZATION, "TmThreadsCreate failed"); @@ -997,3 +1011,15 @@ void UnixSocketKillSocketThread(void) } #endif /* BUILD_UNIX_SOCKET */ + +void TmModuleUnixManagerRegister (void) +{ +#ifdef BUILD_UNIX_SOCKET + tmm_modules[TMM_UNIXMANAGER].name = "UnixManager"; + tmm_modules[TMM_UNIXMANAGER].ThreadInit = UnixManagerThreadInit; + tmm_modules[TMM_UNIXMANAGER].ThreadDeinit = UnixManagerThreadDeinit; + tmm_modules[TMM_UNIXMANAGER].Management = UnixManager; + tmm_modules[TMM_UNIXMANAGER].cap_flags = 0; + tmm_modules[TMM_UNIXMANAGER].flags = TM_FLAG_COMMAND_TM; +#endif /* BUILD_UNIX_SOCKET */ +} diff --git a/src/unix-manager.h b/src/unix-manager.h index 2bbdee11ed99..848da76137d6 100644 --- a/src/unix-manager.h +++ b/src/unix-manager.h @@ -46,4 +46,6 @@ TmEcode UnixManagerRegisterBackgroundTask( void *data); #endif +void TmModuleUnixManagerRegister(void); + #endif /* UNIX_MANAGER_H */ From c96805e83955b3ef878adbae8564da8d096ff0b4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 May 2015 10:17:16 +0200 Subject: [PATCH 0460/2553] threading: remove unused cmd thread create func --- src/tm-threads.c | 28 ---------------------------- src/tm-threads.h | 1 - 2 files changed, 29 deletions(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index b77f52af4dbd..171aca2e4811 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1262,34 +1262,6 @@ ThreadVars *TmThreadCreateCmdThreadByName(char *name, char *module, return tv; } -/** - * \brief Creates and returns the TV instance for a CMD thread. - * This function supports only custom slot functions and hence a - * function pointer should be sent as an argument. - * - * \param name Name of this TV instance - * \param fn_p Pointer to function when \"slots\" is of type \"custom\" - * \param mucond Flag to indicate whether to initialize the condition - * and the mutex variables for this newly created TV. - * - * \retval the newly created TV instance, or NULL on error - */ -ThreadVars *TmThreadCreateCmdThread(char *name, void *(fn_p)(void *), - int mucond) -{ - ThreadVars *tv = NULL; - - tv = TmThreadCreate(name, NULL, NULL, NULL, NULL, "custom", fn_p, mucond); - - if (tv != NULL) { - tv->type = TVT_CMD; - tv->id = TmThreadsRegisterThread(tv, tv->type); - TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); - } - - return tv; -} - /** * \brief Appends this TV to tv_root based on its type * diff --git a/src/tm-threads.h b/src/tm-threads.h index 363a30b8b3d2..9b9fd620dfd4 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -91,7 +91,6 @@ ThreadVars *TmThreadCreatePacketHandler(char *, char *, char *, char *, char *, ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), int); ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, int mucond); -ThreadVars *TmThreadCreateCmdThread(char *name, void *(fn_p)(void *), int); ThreadVars *TmThreadCreateCmdThreadByName(char *name, char *module, int mucond); TmEcode TmThreadSpawn(ThreadVars *); From 478719ee9d5be6f083268175b6afc5c2a643cb90 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 May 2015 10:38:10 +0200 Subject: [PATCH 0461/2553] flow: don't hold tv_root_lock longer than needed Don't hold it longer than needed in shutting down. --- src/flow-manager.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 56ccce3b24d1..8283a43e2ed7 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -142,13 +142,12 @@ void FlowDisableFlowManagerThread(void) } tv = tv->next; } + SCMutexUnlock(&tv_root_lock); /* wake up threads, another try */ for (u = 0; u < flowmgr_number; u++) SCCtrlCondSignal(&flow_manager_ctrl_cond); - SCMutexUnlock(&tv_root_lock); - /* reset count, so we can kill and respawn (unix socket) */ SC_ATOMIC_SET(flowmgr_cnt, 0); return; From fb479902e487d780149824fafc3fbbe1a5402762 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 May 2015 10:38:58 +0200 Subject: [PATCH 0462/2553] threading: explain purpose of threadvars mucond --- src/counters.c | 7 +++++++ src/tm-threads.c | 9 ++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/counters.c b/src/counters.c index 197fe79ec6d8..6840fa9ea80b 100644 --- a/src/counters.c +++ b/src/counters.c @@ -306,6 +306,8 @@ static void *SCPerfMgmtThread(void *arg) cond_time.tv_sec = time(NULL) + sc_counter_tts; cond_time.tv_nsec = 0; + /* wait for the set time, or until we are woken up by + * the shutdown procedure */ SCCtrlMutexLock(tv_local->ctrl_mutex); SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time); SCCtrlMutexUnlock(tv_local->ctrl_mutex); @@ -380,6 +382,8 @@ static void *SCPerfWakeupThread(void *arg) cond_time.tv_sec = time(NULL) + SC_PERF_WUT_TTS; cond_time.tv_nsec = 0; + /* wait for the set time, or until we are woken up by + * the shutdown procedure */ SCCtrlMutexLock(tv_local->ctrl_mutex); SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time); SCCtrlMutexUnlock(tv_local->ctrl_mutex); @@ -828,6 +832,9 @@ void SCPerfInitCounterApi(void) /** * \brief Spawns the wakeup, and the management thread used by the perf * counter api + * + * The threads use the condition variable in the thread vars to control + * their wait loops to make sure the main thread can quickly kill them. */ void SCPerfSpawnThreads(void) { diff --git a/src/tm-threads.c b/src/tm-threads.c index 171aca2e4811..6ad8b6fedf09 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1748,6 +1748,9 @@ void TmThreadSetAOF(ThreadVars *tv, uint8_t aof) /** * \brief Initializes the mutex and condition variables for this TV * + * It can be used by a thread to control a wait loop that can also be + * influenced by other threads. + * * \param tv Pointer to a TV instance */ void TmThreadInitMC(ThreadVars *tv) @@ -1760,19 +1763,19 @@ void TmThreadInitMC(ThreadVars *tv) if (SCCtrlMutexInit(tv->ctrl_mutex, NULL) != 0) { printf("Error initializing the tv->m mutex\n"); - exit(0); + exit(EXIT_FAILURE); } if ( (tv->ctrl_cond = SCMalloc(sizeof(*tv->ctrl_cond))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in TmThreadInitMC. " "Exiting..."); - exit(0); + exit(EXIT_FAILURE); } if (SCCtrlCondInit(tv->ctrl_cond, NULL) != 0) { SCLogError(SC_ERR_FATAL, "Error initializing the tv->cond condition " "variable"); - exit(0); + exit(EXIT_FAILURE); } return; From bc2b53f10bb681f5a7ed501ca316aeedb3c30527 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 May 2015 14:25:49 +0200 Subject: [PATCH 0463/2553] parsing: s/strtok/strtok_r/g Remove all strtok uses and replace them by strtok_r. Do the same for Windows builds. Cygwin builds fine with strtok_r. Add strtok to banned function list. --- qa/coccinelle/banned-functions.cocci | 2 +- src/detect-asn1.c | 11 ++++++----- src/detect-detection-filter.c | 7 +++++-- src/detect-threshold.c | 7 +++++-- src/util-proto-name.c | 14 -------------- 5 files changed, 17 insertions(+), 24 deletions(-) diff --git a/qa/coccinelle/banned-functions.cocci b/qa/coccinelle/banned-functions.cocci index bc2c60e6cbae..5913521cb38f 100644 --- a/qa/coccinelle/banned-functions.cocci +++ b/qa/coccinelle/banned-functions.cocci @@ -3,7 +3,7 @@ identifier i; position p1; @@ -\(sprintf@i\|strcat@i\|strcpy@i\|strncpy@i\|strncat@i\|strndup@i\|strchrdup@i\)(...)@p1 +\(strtok@i\|sprintf@i\|strcat@i\|strcpy@i\|strncpy@i\|strncat@i\|strndup@i\|strchrdup@i\)(...)@p1 @script:python@ p1 << banned.p1; diff --git a/src/detect-asn1.c b/src/detect-asn1.c index 8b7ff06f393b..69d90829e27c 100644 --- a/src/detect-asn1.c +++ b/src/detect-asn1.c @@ -205,8 +205,9 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) uint32_t abs_off = 0; int32_t rel_off = 0; uint8_t flags = 0; + char *saveptr = NULL; - tok = strtok(asn1str, ASN_DELIM); + tok = strtok_r(asn1str, ASN_DELIM, &saveptr); if (tok == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed asn1 argument: %s", asn1str); @@ -223,7 +224,7 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) } else if (strcasecmp("oversize_length", tok) == 0) { flags |= ASN1_OVERSIZE_LEN; /* get the param */ - tok = strtok(NULL, ASN_DELIM); + tok = strtok_r(NULL, ASN_DELIM, &saveptr); if ( tok == NULL || ByteExtractStringUint32(&ov_len, 10, 0, tok) <= 0) { @@ -234,7 +235,7 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) } else if (strcasecmp("absolute_offset", tok) == 0) { flags |= ASN1_ABSOLUTE_OFFSET; /* get the param */ - tok = strtok(NULL, ASN_DELIM); + tok = strtok_r(NULL, ASN_DELIM, &saveptr); if (tok == NULL || ByteExtractStringUint32(&abs_off, 10, 0, tok) <= 0) { @@ -245,7 +246,7 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) } else if (strcasecmp("relative_offset",tok) == 0) { flags |= ASN1_RELATIVE_OFFSET; /* get the param */ - tok = strtok(NULL, ASN_DELIM); + tok = strtok_r(NULL, ASN_DELIM, &saveptr); if (tok == NULL || ByteExtractStringInt32(&rel_off, 10, 0, tok) <= 0) { @@ -258,7 +259,7 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) asn1str); return NULL; } - tok = strtok(NULL, ASN_DELIM); + tok = strtok_r(NULL, ASN_DELIM, &saveptr); } fd = SCMalloc(sizeof(DetectAsn1Data)); diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index b16178cb6498..7e1ee8bc9b8e 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -121,14 +121,17 @@ DetectThresholdData *DetectDetectionFilterParse (char *rawstr) int seconds_pos = 0, count_pos = 0; uint16_t pos = 0; int i = 0; + char *saveptr = NULL; copy_str = SCStrdup(rawstr); if (unlikely(copy_str == NULL)) { goto error; } - for(pos = 0, df_opt = strtok(copy_str,","); pos < strlen(copy_str) && df_opt != NULL; pos++, df_opt = strtok(NULL,",")) { - + for (pos = 0, df_opt = strtok_r(copy_str,",", &saveptr); + pos < strlen(copy_str) && df_opt != NULL; + pos++, df_opt = strtok_r(NULL,",", &saveptr)) + { if(strstr(df_opt,"count")) count_found++; if(strstr(df_opt,"second")) diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 4f47756718ed..5c83ee4d4730 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -142,8 +142,11 @@ static DetectThresholdData *DetectThresholdParse(char *rawstr) goto error; } - for(pos = 0, threshold_opt = strtok(copy_str,","); pos < strlen(copy_str) && threshold_opt != NULL; pos++, threshold_opt = strtok(NULL,",")) { - + char *saveptr = NULL; + for (pos = 0, threshold_opt = strtok_r(copy_str,",", &saveptr); + pos < strlen(copy_str) && threshold_opt != NULL; + pos++, threshold_opt = strtok_r(NULL,"," , &saveptr)) + { if(strstr(threshold_opt,"count")) count_found++; if(strstr(threshold_opt,"second")) diff --git a/src/util-proto-name.c b/src/util-proto-name.c index 82ec8e64ba6f..0b958884ca4e 100644 --- a/src/util-proto-name.c +++ b/src/util-proto-name.c @@ -43,27 +43,17 @@ void SCProtoNameInit() FILE *fp = fopen(PROTO_FILE,"r"); if (fp != NULL) { char line[200]; -#if !defined(__WIN32) && !defined(_WIN32) char *ptr = NULL; -#endif /* __WIN32 */ while(fgets(line, sizeof(line), fp) != NULL) { if (line[0] == '#') continue; -#if defined(__WIN32) || defined(_WIN32) - char *name = strtok(line," \t"); -#else char *name = strtok_r(line," \t", &ptr); -#endif /* __WIN32 */ if (name == NULL) continue; -#if defined(__WIN32) || defined(_WIN32) - char *proto_ch = strtok(NULL," \t"); -#else char *proto_ch = strtok_r(NULL," \t", &ptr); -#endif /* __WIN32 */ if (proto_ch == NULL) continue; @@ -71,11 +61,7 @@ void SCProtoNameInit() if (proto >= 255) continue; -#if defined(__WIN32) || defined(_WIN32) - char *cname = strtok(NULL, " \t"); -#else char *cname = strtok_r(NULL, " \t", &ptr); -#endif /* __WIN32 */ if (known_proto[proto] != NULL) { SCFree(known_proto[proto]); From c7bc9ae6a80796bc4fedc52e2613371b3aab4afb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 May 2015 14:26:13 +0200 Subject: [PATCH 0464/2553] detect: minor cleanups --- src/detect.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/detect.c b/src/detect.c index 2a2b2828d721..b3bdbe16f5c1 100644 --- a/src/detect.c +++ b/src/detect.c @@ -199,8 +199,6 @@ #include "runmodes.h" -extern int rule_reload; - extern int engine_analysis; static int fp_engine_analysis_set = 0; static int rule_engine_analysis_set = 0; @@ -265,10 +263,10 @@ char *DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, char *sig_file) return NULL; strlcpy(path, defaultpath, path_len); #if defined OS_WIN32 || defined __CYGWIN__ - if (path[strlen(path) - 1] != '\\') + if (path[strlen(path) - 1] != '\\') strlcat(path, "\\\\", path_len); #else - if (path[strlen(path) - 1] != '/') + if (path[strlen(path) - 1] != '/') strlcat(path, "/", path_len); #endif strlcat(path, sig_file, path_len); From 5037ea93f3727a8689acb0df4d067f9a6d9aab1d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 18 May 2015 18:05:11 +0200 Subject: [PATCH 0465/2553] threads: add untimed control cond call The control conditions so far could only do timed waits, not normal waits. --- src/threads-arch-tile.h | 1 + src/threads-debug.h | 1 + src/threads-profile.h | 1 + src/threads.h | 1 + 4 files changed, 4 insertions(+) diff --git a/src/threads-arch-tile.h b/src/threads-arch-tile.h index a0e2fc501d0b..d022d90e339f 100644 --- a/src/threads-arch-tile.h +++ b/src/threads-arch-tile.h @@ -47,6 +47,7 @@ #define SCCtrlCondInit pthread_cond_init #define SCCtrlCondSignal pthread_cond_signal #define SCCtrlCondTimedwait pthread_cond_timedwait +#define SCCtrlCondWait pthread_cond_wait #define SCCtrlCondDestroy pthread_cond_destroy /* mutex */ diff --git a/src/threads-debug.h b/src/threads-debug.h index 5a8b30fa6317..050e305643eb 100644 --- a/src/threads-debug.h +++ b/src/threads-debug.h @@ -383,6 +383,7 @@ #define SCCtrlCondInit pthread_cond_init #define SCCtrlCondSignal pthread_cond_signal #define SCCtrlCondTimedwait pthread_cond_timedwait +#define SCCtrlCondWait pthread_cond_wait #define SCCtrlCondDestroy pthread_cond_destroy #endif diff --git a/src/threads-profile.h b/src/threads-profile.h index 4adde85889b8..6e19673b1048 100644 --- a/src/threads-profile.h +++ b/src/threads-profile.h @@ -212,6 +212,7 @@ extern __thread uint64_t rwr_lock_cnt; #define SCCtrlCondInit pthread_cond_init #define SCCtrlCondSignal pthread_cond_signal #define SCCtrlCondTimedwait pthread_cond_timedwait +#define SCCtrlCondWait pthread_cond_wait #define SCCtrlCondDestroy pthread_cond_destroy #endif diff --git a/src/threads.h b/src/threads.h index 18f1eaae9e97..0a843b7ff034 100644 --- a/src/threads.h +++ b/src/threads.h @@ -153,6 +153,7 @@ enum { #define SCCtrlCondInit pthread_cond_init #define SCCtrlCondSignal pthread_cond_signal #define SCCtrlCondTimedwait pthread_cond_timedwait +#define SCCtrlCondWait pthread_cond_wait #define SCCtrlCondDestroy pthread_cond_destroy /* spinlocks */ From 0e22e95e4766e25f7bbff5b852d5c96b1d4a09f0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 19 May 2015 15:54:41 +0200 Subject: [PATCH 0466/2553] alert-json: fix stream logging for IPS mode Switch direction in IPS mode. --- src/output-json-alert.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index f9783b28af29..973c657f038f 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -267,10 +267,18 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) MemBufferReset(payload); - if (p->flowflags & FLOW_PKT_TOSERVER) { - flag = FLOW_PKT_TOCLIENT; + if (!EngineModeIsIPS()) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + flag = FLOW_PKT_TOCLIENT; + } else { + flag = FLOW_PKT_TOSERVER; + } } else { - flag = FLOW_PKT_TOSERVER; + if (p->flowflags & FLOW_PKT_TOSERVER) { + flag = FLOW_PKT_TOSERVER; + } else { + flag = FLOW_PKT_TOCLIENT; + } } StreamSegmentForEach((const Packet *)p, flag, From e2b04635a7a5d9d3a912cf878328799223a1444e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 27 Oct 2014 11:36:26 -0600 Subject: [PATCH 0467/2553] Bug 1281 - Accept rule content with lengths greater than 255. --- src/detect-content.c | 21 ++++++++++----------- src/detect-content.h | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/detect-content.c b/src/detect-content.c index cd0722eae84f..3d24b00be676 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -235,13 +235,6 @@ DetectContentData *DetectContentParse (char *contentstr) if (ret == -1) { return NULL; } - if (len > 255) { - SCLogError(SC_ERR_NOT_SUPPORTED, "Currently we don't support content " - "length greater than 255. Please split the pattern, if " - "length > 255. The length of the content after " - "normalization is \"%"PRIu16"\".", len); - return NULL; - } cd = SCMalloc(sizeof(DetectContentData) + len); if (unlikely(cd == NULL)) { @@ -2119,6 +2112,9 @@ int DetectContentParseTest41(void) return result; } +/** + * Tests that content lengths > 255 are supported. + */ int DetectContentParseTest42(void) { int result = 1; @@ -2136,8 +2132,8 @@ int DetectContentParseTest42(void) teststring[idx++] = '\0'; cd = DetectContentParse(teststring); - if (cd != NULL) { - SCLogDebug("expected NULL got %p: ", cd); + if (cd == NULL) { + SCLogDebug("expected not NULL"); result = 0; } @@ -2177,6 +2173,9 @@ int DetectContentParseTest43(void) return result; } +/** + * Tests that content lengths > 255 are supported. + */ int DetectContentParseTest44(void) { int result = 1; @@ -2198,8 +2197,8 @@ int DetectContentParseTest44(void) teststring[idx++] = '\0'; cd = DetectContentParse(teststring); - if (cd != NULL) { - SCLogDebug("expected NULL got %p: ", cd); + if (cd == NULL) { + SCLogDebug("expected not NULL"); result = 0; } diff --git a/src/detect-content.h b/src/detect-content.h index c5c47263d6e3..b2e0f9694f57 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -65,8 +65,8 @@ typedef struct DetectContentData_ { uint8_t *content; - uint8_t content_len; - uint8_t replace_len; + uint16_t content_len; + uint16_t replace_len; /* for chopped fast pattern, the length */ uint16_t fp_chop_len; /* would want to move PatIntId here and flags down to remove the padding From 3e5b8f48b191205b5337f77be4f410661b6982c7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 2 Jan 2015 15:30:30 -0600 Subject: [PATCH 0468/2553] Bug 1281 - Add tests for rule content of lengths > 255. --- src/detect-content.c | 131 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/src/detect-content.c b/src/detect-content.c index 3d24b00be676..5f315cc5befc 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -2583,6 +2583,134 @@ static int SigTest77TestBug139(void) UTHFreePacket(p); return result; } + +static int DetectLongContentTestCommon(char *sig, uint32_t sid) +{ + /* Packet with 512 A's in it for testing long content. */ + static uint8_t pkt[739] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00, + 0x02, 0xd5, 0x4a, 0x18, 0x40, 0x00, 0x40, 0x06, + 0xd7, 0xd6, 0x0a, 0x10, 0x01, 0x0b, 0x0a, 0x10, + 0x01, 0x0a, 0xdb, 0x36, 0x00, 0x50, 0xca, 0xc5, + 0xcc, 0xd1, 0x95, 0x77, 0x0f, 0x7d, 0x80, 0x18, + 0x00, 0xe5, 0x77, 0x9d, 0x00, 0x00, 0x01, 0x01, + 0x08, 0x0a, 0x1d, 0xe0, 0x86, 0xc6, 0xfc, 0x73, + 0x49, 0xf3, 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f, + 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, + 0x31, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x63, + 0x75, 0x72, 0x6c, 0x2f, 0x37, 0x2e, 0x33, 0x37, + 0x2e, 0x30, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, + 0x3a, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x36, 0x2e, + 0x31, 0x2e, 0x31, 0x30, 0x0d, 0x0a, 0x41, 0x63, + 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, + 0x2a, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x3a, 0x20, 0x35, 0x32, 0x38, 0x0d, 0x0a, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x78, 0x2d, 0x77, 0x77, 0x77, 0x2d, + 0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x75, 0x72, 0x6c, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x0d, + 0x0a, 0x0d, 0x0a, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58 + }; + + return DetectContentLongPatternMatchTest(pkt, (uint16_t)sizeof(pkt), sig, + sid); +} + +static int DetectLongContentTest1(void) +{ + /* Signature with 256 A's. */ + char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; + + return DetectLongContentTestCommon(sig, 1); +} + +static int DetectLongContentTest2(void) +{ + /* Signature with 512 A's. */ + char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; + + return DetectLongContentTestCommon(sig, 1); +} + +static int DetectLongContentTest3(void) +{ + /* Signature with 513 A's. */ + char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; + + return !DetectLongContentTestCommon(sig, 1); +} + #endif /* UNITTESTS */ /** @@ -2689,5 +2817,8 @@ void DetectContentRegisterTests(void) UtRegisterTest("SigTest76TestBug134", SigTest76TestBug134, 1); UtRegisterTest("SigTest77TestBug139", SigTest77TestBug139, 1); + UtRegisterTest("DetectLongContentTest1", DetectLongContentTest1, 1); + UtRegisterTest("DetectLongContentTest2", DetectLongContentTest2, 1); + UtRegisterTest("DetectLongContentTest3", DetectLongContentTest3, 1); #endif /* UNITTESTS */ } From 56f6e373049b037567313ea2c8c6748fb5321f89 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 11 May 2015 10:20:25 -0600 Subject: [PATCH 0469/2553] radix-tree - prevent out of bounds array access An IPv6 entry specified before an IPv4 entry on the host-os-policy table can cause the stream byte array to be access one byte after the end of the allocated memory at util-radix-tree.c:578. --- src/util-radix-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-radix-tree.c b/src/util-radix-tree.c index 39f8304ef907..cbf49c7de7cb 100644 --- a/src/util-radix-tree.c +++ b/src/util-radix-tree.c @@ -570,7 +570,7 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, * down along one of the paths, since either paths should end up with a * node that has a common prefix whose differ bit is greater than the * bitlen of the incoming prefix */ - if (bitlen < node->bit) { + if (bitlen <= node->bit) { if (node->right == NULL) break; node = node->right; From 9fdae82815802ccd6f84e4873de30f053736be09 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 11 May 2015 16:50:19 -0600 Subject: [PATCH 0470/2553] conf - process includes even if not at root node. --- src/conf-yaml-loader.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index d61e495ce192..13ec04884571 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -244,9 +244,7 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) } else if (state == CONF_KEY) { - /* Top level include statements. */ - if ((strcmp(value, "include") == 0) && - (parent == ConfGetRootNode())) { + if (strcmp(value, "include") == 0) { state = CONF_INCLUDE; goto next; } From 4f8f53d080c6807f959a772279fdee5982384a9e Mon Sep 17 00:00:00 2001 From: David Cannings Date: Mon, 11 May 2015 21:51:38 +0100 Subject: [PATCH 0471/2553] Fix rcode parsing, as noticed by Coverity. Without support for OPT RR from RFC6891 (Extension mechanisms for DNS) values of RCODE above 15 are not possible. Remove dead code which will never match. --- src/app-layer-dns-common.h | 2 ++ src/app-layer-dns-tcp.c | 2 +- src/app-layer-dns-udp.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index 1a06f8d1dc09..203b2908e6d5 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -71,6 +71,8 @@ #define DNS_RCODE_NXRRSET 8 #define DNS_RCODE_NOTAUTH 9 #define DNS_RCODE_NOTZONE 10 +// Support for OPT RR from RFC6891 will be needed to +// parse RCODE values over 15 #define DNS_RCODE_BADVERS 16 #define DNS_RCODE_BADSIG 16 #define DNS_RCODE_BADKEY 17 diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 0842c6686e64..840a0f8086e5 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -449,7 +449,7 @@ static int DNSReponseParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu /* parse rcode, e.g. "noerror" or "nxdomain" */ uint8_t rcode = ntohs(dns_header->flags) & 0x0F; - if (rcode <= DNS_RCODE_NOTZONE || (rcode >= DNS_RCODE_BADSIG && rcode <= DNS_RCODE_BADTRUNC)) { + if (rcode <= DNS_RCODE_NOTZONE) { SCLogDebug("rcode %u", rcode); if (tx != NULL) tx->rcode = rcode; diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index bb0c73bf555d..eb87849c5211 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -271,7 +271,7 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, /* parse rcode, e.g. "noerror" or "nxdomain" */ uint8_t rcode = ntohs(dns_header->flags) & 0x0F; - if (rcode <= DNS_RCODE_NOTZONE || (rcode >= DNS_RCODE_BADSIG && rcode <= DNS_RCODE_BADTRUNC)) { + if (rcode <= DNS_RCODE_NOTZONE) { SCLogDebug("rcode %u", rcode); if (tx != NULL) tx->rcode = rcode; From f11e237d7791c5fe6d49ae68a39e525291e9b5da Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Wed, 13 May 2015 21:18:43 +0300 Subject: [PATCH 0472/2553] Feature #1440: support wildcards in rule filenames --- configure.ac | 1 + src/detect.c | 128 ++++++++++++++++++++++++++++++++------------------- src/detect.h | 8 ++++ 3 files changed, 90 insertions(+), 47 deletions(-) diff --git a/configure.ac b/configure.ac index a846ec20e5c2..93720520981a 100644 --- a/configure.ac +++ b/configure.ac @@ -128,6 +128,7 @@ AC_CHECK_HEADERS([sys/time.h time.h unistd.h]) AC_CHECK_HEADERS([sys/ioctl.h linux/if_ether.h linux/if_packet.h linux/filter.h]) AC_CHECK_HEADERS([linux/ethtool.h linux/sockios.h]) + AC_CHECK_HEADER(glob.h,,[AC_ERROR(glob.h not found ...)]) AC_CHECK_HEADERS([sys/socket.h net/if.h sys/mman.h linux/if_arp.h], [], [], [[#ifdef HAVE_SYS_SOCKET_H diff --git a/src/detect.c b/src/detect.c index b3bdbe16f5c1..4069a5d5b9a1 100644 --- a/src/detect.c +++ b/src/detect.c @@ -199,6 +199,10 @@ #include "runmodes.h" +#include + +extern int rule_reload; + extern int engine_analysis; static int fp_engine_analysis_set = 0; static int rule_engine_analysis_set = 0; @@ -287,8 +291,9 @@ char *DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, char *sig_file) * \brief Load a file with signatures * \param de_ctx Pointer to the detection engine context * \param sig_file Filename to load signatures from - * \param sigs_tot Will store number of signatures processed in the file - * \retval Number of rules loaded successfully, -1 on error + * \param goodsigs_tot Will store number of valid signatures in the file + * \param badsigs_tot Will store number of invalid signatures in the file + * \retval 0 on success, -1 on error */ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *goodsigs, int *badsigs) @@ -302,11 +307,6 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, (*goodsigs) = 0; (*badsigs) = 0; - if (sig_file == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "opening rule file null"); - return -1; - } - FILE *fp = fopen(sig_file, "r"); if (fp == NULL) { SCLogError(SC_ERR_OPENING_RULE_FILE, "opening rule file %s:" @@ -373,15 +373,65 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, } fclose(fp); - (*goodsigs) = good; - (*badsigs) = bad; + *goodsigs = good; + *badsigs = bad; return 0; } +/** + * \brief Expands wildcards and reads signatures from each matching file + * \param de_ctx Pointer to the detection engine context + * \param sig_file Filename (or pattern) holding signatures + * \retval -1 on error + */ +static int ProcessSigFiles(DetectEngineCtx *de_ctx, char *pattern, + SigFileLoaderStat *st, int *good_sigs, int *bad_sigs) +{ + if (pattern == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "opening rule file null"); + return -1; + } + + glob_t files; + int r = glob(pattern, 0, NULL, &files); + + if (r == GLOB_NOMATCH) { + SCLogWarning(SC_ERR_NO_RULES, "No rule files match the pattern %s", pattern); + ++(st->bad_files); + return -1; + } else if (r != 0) { + SCLogError(SC_ERR_OPENING_RULE_FILE, "error expanding template %s: %s", + pattern, strerror(errno)); + return -1; + } + + for (size_t i = 0; i < (size_t)files.gl_pathc; i++) { + char *fname = files.gl_pathv[i]; + SCLogInfo("Loading rule file: %s", fname); + r = DetectLoadSigFile(de_ctx, fname, good_sigs, bad_sigs); + if (r < 0) { + ++(st->bad_files); + } + + ++(st->total_files); + + if (*good_sigs == 0) { + SCLogWarning(SC_ERR_NO_RULES, + "No rules loaded from %s", fname); + } + + st->good_sigs_total += *good_sigs; + st->bad_sigs_total += *bad_sigs; + } + + globfree(&files); + return r; +} + /** * \brief Load signatures * \param de_ctx Pointer to the detection engine context - * \param sig_file Filename holding signatures + * \param sig_file Filename (or pattern) holding signatures * \param sig_file_exclusive File passed in 'sig_file' should be loaded exclusively. * \retval -1 on error */ @@ -391,20 +441,14 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl ConfNode *rule_files; ConfNode *file = NULL; + SigFileLoaderStat sig_stat; int ret = 0; - int r = 0; - int cntf = 0; char *sfile = NULL; - - int goodsigs = 0; - int badsigs = 0; - - int badfiles = 0; - - int goodtotal = 0; - int badtotal = 0; - char varname[128] = "rule-files"; + int good_sigs = 0; + int bad_sigs = 0; + + memset(&sig_stat, 0, sizeof(SigFileLoaderStat)); if (strlen(de_ctx->config_prefix) > 0) { snprintf(varname, sizeof(varname), "%s.rule-files", @@ -428,21 +472,9 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl else { TAILQ_FOREACH(file, &rule_files->head, next) { sfile = DetectLoadCompleteSigPath(de_ctx, file->val); - SCLogDebug("Loading rule file: %s", sfile); - - cntf++; - r = DetectLoadSigFile(de_ctx, sfile, &goodsigs, &badsigs); - if (r < 0) { - badfiles++; - } - if (goodsigs == 0) { - SCLogWarning(SC_ERR_NO_RULES, - "No rules loaded from %s", sfile); - } + good_sigs = bad_sigs = 0; + ProcessSigFiles(de_ctx, sfile, &sig_stat, &good_sigs, &bad_sigs); SCFree(sfile); - - goodtotal += goodsigs; - badtotal += badsigs; } } } @@ -451,33 +483,35 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl /* If a Signature file is specified from commandline, parse it too */ if (sig_file != NULL) { SCLogInfo("Loading rule file: %s", sig_file); - cntf++; - r = DetectLoadSigFile(de_ctx, sig_file, &goodsigs, &badsigs); - if (r < 0) { - badfiles++; + ++sig_stat.total_files; + + if (ProcessSigFiles(de_ctx, sig_file, &sig_stat, &good_sigs, &bad_sigs) != 0) { + ++sig_stat.bad_files; } - if (goodsigs == 0) { + + if (good_sigs == 0) { SCLogWarning(SC_ERR_NO_RULES, "No rules loaded from %s", sig_file); } - goodtotal += goodsigs; - badtotal += badsigs; + sig_stat.good_sigs_total += good_sigs; + sig_stat.bad_sigs_total += bad_sigs; } /* now we should have signatures to work with */ - if (goodsigs <= 0) { - if (cntf > 0) { - SCLogWarning(SC_ERR_NO_RULES_LOADED, "%d rule files specified, but no rule was loaded at all!", cntf); + if (sig_stat.good_sigs_total <= 0) { + if (sig_stat.total_files > 0) { + SCLogWarning(SC_ERR_NO_RULES_LOADED, "%d rule files specified, but no rule was loaded at all!", sig_stat.total_files); } else { SCLogInfo("No signatures supplied."); goto end; } } else { /* we report the total of files and rules successfully loaded and failed */ - SCLogInfo("%" PRId32 " rule files processed. %" PRId32 " rules successfully loaded, %" PRId32 " rules failed", cntf, goodtotal, badtotal); + SCLogInfo("%" PRId32 " rule files processed. %" PRId32 " rules successfully loaded, %" PRId32 " rules failed", + sig_stat.total_files, sig_stat.good_sigs_total, sig_stat.bad_sigs_total); } - if ((badtotal || badfiles) && de_ctx->failure_fatal) { + if ((sig_stat.bad_sigs_total || sig_stat.bad_files) && de_ctx->failure_fatal) { ret = -1; goto end; } diff --git a/src/detect.h b/src/detect.h index 3b5ff6005cfb..fbed549fe119 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1078,6 +1078,14 @@ typedef struct DetectEngineMasterCtx_ { DetectEngineCtx *free_list; } DetectEngineMasterCtx; +/** \brief Signature loader statistics */ +typedef struct SigFileLoaderStat_ { + int bad_files; + int total_files; + int good_sigs_total; + int bad_sigs_total; +} SigFileLoaderStat; + /** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a signature group */ enum { From 39d667ff56899fcbacd4452230d98d13494e52b3 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 7 Feb 2015 01:58:28 +0100 Subject: [PATCH 0473/2553] output-json: fix type of data parameter The cast of data to AlertJsonThread was not correct as the real type of the void pointer is a OutputJsonCtx. This was working by luck because they both have a file_ctx as first element. --- src/output-json-alert.c | 2 +- src/output-json-file.c | 4 ++-- src/output-json-flow.c | 4 ++-- src/output-json-http.c | 4 ++-- src/output-json-netflow.c | 4 ++-- src/output-json-smtp.c | 4 ++-- src/output-json-ssh.c | 4 ++-- src/output-json-tls.c | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 973c657f038f..cbb2ed475880 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -571,7 +571,7 @@ static OutputCtx *JsonAlertLogInitCtx(ConfNode *conf) */ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ajt = parent_ctx->data; AlertJsonOutputCtx *json_output_ctx = NULL; HttpXFFCfg *xff_cfg = NULL; diff --git a/src/output-json-file.c b/src/output-json-file.c index 93250fb4f636..22b9f98cadc6 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -324,7 +324,7 @@ static void OutputFileLogDeinitSub(OutputCtx *output_ctx) * */ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; OutputFileCtx *output_file_ctx = SCMalloc(sizeof(OutputFileCtx)); if (unlikely(output_file_ctx == NULL)) @@ -336,7 +336,7 @@ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - output_file_ctx->file_ctx = ajt->file_ctx; + output_file_ctx->file_ctx = ojc->file_ctx; if (conf) { const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 760234d4b162..aefa5cf95227 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -386,7 +386,7 @@ static void OutputFlowLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputFlowLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; LogJsonFileCtx *flow_ctx = SCMalloc(sizeof(LogJsonFileCtx)); if (unlikely(flow_ctx == NULL)) @@ -398,7 +398,7 @@ OutputCtx *OutputFlowLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - flow_ctx->file_ctx = ajt->file_ctx; + flow_ctx->file_ctx = ojc->file_ctx; flow_ctx->flags = LOG_HTTP_DEFAULT; output_ctx->data = flow_ctx; diff --git a/src/output-json-http.c b/src/output-json-http.c index bef5335f2d60..f5152be547d1 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -462,7 +462,7 @@ static void OutputHttpLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputHttpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; LogHttpFileCtx *http_ctx = SCMalloc(sizeof(LogHttpFileCtx)); if (unlikely(http_ctx == NULL)) @@ -475,7 +475,7 @@ OutputCtx *OutputHttpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - http_ctx->file_ctx = ajt->file_ctx; + http_ctx->file_ctx = ojc->file_ctx; http_ctx->flags = LOG_HTTP_DEFAULT; if (conf) { diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 3a1b57d0f7b0..198dd58fc0a8 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -369,7 +369,7 @@ static void OutputNetFlowLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputNetFlowLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; LogJsonFileCtx *flow_ctx = SCMalloc(sizeof(LogJsonFileCtx)); if (unlikely(flow_ctx == NULL)) @@ -381,7 +381,7 @@ OutputCtx *OutputNetFlowLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - flow_ctx->file_ctx = ajt->file_ctx; + flow_ctx->file_ctx = ojc->file_ctx; output_ctx->data = flow_ctx; output_ctx->DeInit = OutputNetFlowLogDeinitSub; diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index f541ff891f0a..83e9d12c0f2c 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -121,7 +121,7 @@ OutputCtx *OutputSmtpLogInit(ConfNode *conf) static OutputCtx *OutputSmtpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; OutputJsonEmailCtx *email_ctx = SCMalloc(sizeof(OutputJsonEmailCtx)); if (unlikely(email_ctx == NULL)) @@ -133,7 +133,7 @@ static OutputCtx *OutputSmtpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - email_ctx->file_ctx = ajt->file_ctx; + email_ctx->file_ctx = ojc->file_ctx; output_ctx->data = email_ctx; output_ctx->DeInit = OutputSmtpLogDeInitCtxSub; diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index d8494d5e35f4..dd68020c60e0 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -248,7 +248,7 @@ static void OutputSshLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; if (OutputSshLoggerEnable() != 0) { SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'ssh' logger " @@ -266,7 +266,7 @@ OutputCtx *OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - ssh_ctx->file_ctx = ajt->file_ctx; + ssh_ctx->file_ctx = ojc->file_ctx; output_ctx->data = ssh_ctx; output_ctx->DeInit = OutputSshLogDeinitSub; diff --git a/src/output-json-tls.c b/src/output-json-tls.c index f2843e49fedd..ef28b55ddea4 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -292,7 +292,7 @@ static void OutputTlsLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; if (OutputTlsLoggerEnable() != 0) { SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'tls' logger " @@ -310,7 +310,7 @@ OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - tls_ctx->file_ctx = ajt->file_ctx; + tls_ctx->file_ctx = ojc->file_ctx; tls_ctx->flags = LOG_TLS_DEFAULT; if (conf) { From 7d73db9b80a89d462ddb72c48b40273a93a02558 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 7 Feb 2015 11:36:37 +0100 Subject: [PATCH 0474/2553] suricata.yaml: fix the name of EVE module It is netflow and not newflow. --- suricata.yaml.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 8d16815bee46..be7ac5573e34 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -143,7 +143,7 @@ outputs: # bi-directional flows #- flow # uni-directional flows - #- newflow + #- netflow # alert output for use with Barnyard2 - unified2-alert: From 636e3d93c03ce8050e37e3d7015f538303498b66 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 20 May 2015 13:38:10 +0200 Subject: [PATCH 0475/2553] log file: add type flag It will be used to store if the file is syslog or a real file. --- src/output-json.h | 8 ++------ src/util-logopenfile.h | 8 ++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/output-json.h b/src/output-json.h index e35b81be4581..1acde3e67792 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -39,10 +39,7 @@ TmEcode OutputJSON(json_t *js, void *data, uint64_t *count); int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer); OutputCtx *OutputJsonInitCtx(ConfNode *); -enum JsonOutput { ALERT_FILE, - ALERT_SYSLOG, - ALERT_UNIX_DGRAM, - ALERT_UNIX_STREAM }; + enum JsonFormat { COMPACT, INDENT }; /* @@ -50,11 +47,10 @@ enum JsonFormat { COMPACT, INDENT }; */ typedef struct OutputJsonCtx_ { LogFileCtx *file_ctx; - enum JsonOutput json_out; + enum LogFileType json_out; enum JsonFormat format; } OutputJsonCtx; - typedef struct AlertJsonThread_ { /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ LogFileCtx *file_ctx; diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 65d179a6f775..49e770a504e2 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -31,6 +31,11 @@ typedef struct { uint16_t fileno; } PcieFile; +enum LogFileType { ALERT_FILE, + ALERT_SYSLOG, + ALERT_UNIX_DGRAM, + ALERT_UNIX_STREAM }; + /** Global structure for Output Context */ typedef struct LogFileCtx_ { union { @@ -45,6 +50,9 @@ typedef struct LogFileCtx_ { * record cannot be written to the file in one call */ SCMutex fp_mutex; + /** the type of file */ + enum LogFileType type; + /** The name of the file */ char *filename; From 4c6a7bea30eb87aa3017dd0be21dc0d72c810100 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 20 May 2015 13:40:01 +0200 Subject: [PATCH 0476/2553] output-json: suppress global variable It uses the new type field in the LogFileCtx instead. This fixes the problem of not being able to use two eve-json instance with different logging methods. --- src/output-json.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index 78a915d42267..c984247094c2 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -146,10 +146,6 @@ void TmModuleOutputJsonRegister (void) /* Default Sensor ID value */ static int64_t sensor_id = -1; /* -1 = not defined */ -static enum JsonOutput json_out = ALERT_FILE; - -static enum JsonFormat format = COMPACT; - /** \brief jsonify tcp flags field * Only add 'true' fields in an attempt to keep things reasonably compact. */ @@ -345,9 +341,9 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) return TM_ECODE_OK; SCMutexLock(&file_ctx->fp_mutex); - if (json_out == ALERT_SYSLOG) { + if (file_ctx->type == ALERT_SYSLOG) { syslog(alert_syslog_level, "%s", js_s); - } else if (json_out == ALERT_FILE || json_out == ALERT_UNIX_DGRAM || json_out == ALERT_UNIX_STREAM) { + } else if (file_ctx->type == ALERT_FILE || file_ctx->type == ALERT_UNIX_DGRAM || file_ctx->type == ALERT_UNIX_STREAM) { MemBufferWriteString(buffer, "%s\n", js_s); file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), MEMBUFFER_OFFSET(buffer), file_ctx); @@ -519,8 +515,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) } } - format = json_ctx->format; - json_out = json_ctx->json_out; + json_ctx->file_ctx->type = json_ctx->json_out; } SCLogDebug("returning output_ctx %p", output_ctx); From 1e8142c6994cbffe69dee917f2705a7c71905bc2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 22 May 2015 14:23:18 +0200 Subject: [PATCH 0477/2553] logfile: rename ALERT_ types to LOGFILE_TYPE_ --- src/output-json.c | 23 ++++++++++++++--------- src/util-logopenfile.h | 8 ++++---- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index c984247094c2..e77dd6846a71 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -341,9 +341,12 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) return TM_ECODE_OK; SCMutexLock(&file_ctx->fp_mutex); - if (file_ctx->type == ALERT_SYSLOG) { + if (file_ctx->type == LOGFILE_TYPE_SYSLOG) { syslog(alert_syslog_level, "%s", js_s); - } else if (file_ctx->type == ALERT_FILE || file_ctx->type == ALERT_UNIX_DGRAM || file_ctx->type == ALERT_UNIX_STREAM) { + } else if (file_ctx->type == LOGFILE_TYPE_FILE || + file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || + file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) + { MemBufferWriteString(buffer, "%s\n", js_s); file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), MEMBUFFER_OFFSET(buffer), file_ctx); @@ -439,13 +442,13 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) if (output_s != NULL) { if (strcmp(output_s, "file") == 0 || strcmp(output_s, "regular") == 0) { - json_ctx->json_out = ALERT_FILE; + json_ctx->json_out = LOGFILE_TYPE_FILE; } else if (strcmp(output_s, "syslog") == 0) { - json_ctx->json_out = ALERT_SYSLOG; + json_ctx->json_out = LOGFILE_TYPE_SYSLOG; } else if (strcmp(output_s, "unix_dgram") == 0) { - json_ctx->json_out = ALERT_UNIX_DGRAM; + json_ctx->json_out = LOGFILE_TYPE_UNIX_DGRAM; } else if (strcmp(output_s, "unix_stream") == 0) { - json_ctx->json_out = ALERT_UNIX_STREAM; + json_ctx->json_out = LOGFILE_TYPE_UNIX_STREAM; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid JSON output option: %s", output_s); @@ -453,8 +456,10 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) } } - if (json_ctx->json_out == ALERT_FILE || json_ctx->json_out == ALERT_UNIX_DGRAM || json_ctx->json_out == ALERT_UNIX_STREAM) { - + if (json_ctx->json_out == LOGFILE_TYPE_FILE || + json_ctx->json_out == LOGFILE_TYPE_UNIX_DGRAM || + json_ctx->json_out == LOGFILE_TYPE_UNIX_STREAM) + { if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME) < 0) { LogFileFreeCtx(json_ctx->file_ctx); SCFree(json_ctx); @@ -475,7 +480,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) exit(EXIT_FAILURE); } } - } else if (json_ctx->json_out == ALERT_SYSLOG) { + } else if (json_ctx->json_out == LOGFILE_TYPE_SYSLOG) { const char *facility_s = ConfNodeLookupChildValue(conf, "facility"); if (facility_s == NULL) { facility_s = DEFAULT_ALERT_SYSLOG_FACILITY_STR; diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 49e770a504e2..5d144f95d43e 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -31,10 +31,10 @@ typedef struct { uint16_t fileno; } PcieFile; -enum LogFileType { ALERT_FILE, - ALERT_SYSLOG, - ALERT_UNIX_DGRAM, - ALERT_UNIX_STREAM }; +enum LogFileType { LOGFILE_TYPE_FILE, + LOGFILE_TYPE_SYSLOG, + LOGFILE_TYPE_UNIX_DGRAM, + LOGFILE_TYPE_UNIX_STREAM }; /** Global structure for Output Context */ typedef struct LogFileCtx_ { From e2c557cfdb48ac13ed535ee672d49d58b5a772c5 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 17 May 2015 18:57:48 +0200 Subject: [PATCH 0478/2553] suri-graphite: fix port option If port is specified on command line we need to convert it as an integer before using it as argument to connect. --- contrib/suri-graphite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/suri-graphite b/contrib/suri-graphite index 7a71ecf2dd5f..83422e89d58f 100755 --- a/contrib/suri-graphite +++ b/contrib/suri-graphite @@ -35,7 +35,7 @@ sc = suricatasc.SuricataSC(args.socket) sc.connect() sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -sck.connect((args.host, args.port)) +sck.connect((args.host, int(args.port))) while 1: res = sc.send_command("dump-counters") From a54cef31ea81f4fdc41adf657e83a96e32cd4e5f Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 17 May 2015 19:02:37 +0200 Subject: [PATCH 0479/2553] suri-graphite: add daemonization capability You can now use -d or --daemon to daemonize the process. --- contrib/suri-graphite | 57 ++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/contrib/suri-graphite b/contrib/suri-graphite index 83422e89d58f..8506ceb7773b 100755 --- a/contrib/suri-graphite +++ b/contrib/suri-graphite @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (C) 2013 Eric Leblond +# Copyright (C) 2013, 2015 Eric Leblond # # You can copy, redistribute or modify this Program under the terms of # the GNU General Public License version 3 as published by the Free @@ -20,6 +20,13 @@ import socket import time import argparse +have_daemon = True +try: + import daemon +except: + logging.warning("No daemon support available, install python-daemon if feature is needed") + have_daemon = False + parser = argparse.ArgumentParser(prog='suri-graphite', description='Export suricata stats to Graphite') parser.add_argument('-H', '--host', default='localhost', help='Host running Graphite') parser.add_argument('-P', '--port', default=2003, help='Port of Graphite data socket') @@ -29,23 +36,35 @@ parser.add_argument('-r', '--root', default='suricata.perf', help='Prefix of dat parser.add_argument('socket', help='suricata socket file to connect to', default="/usr/local/var/run/suricata/suricata-command.socket", nargs='?') parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output', default=False) +if have_daemon: + parser.add_argument('-d', '--daemon', default=False, action="store_true", help="Run as unix daemon") + args = parser.parse_args() -sc = suricatasc.SuricataSC(args.socket) -sc.connect() - -sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -sck.connect((args.host, int(args.port))) - -while 1: - res = sc.send_command("dump-counters") - res = res['message'] - tnow = int(time.time()) - for thread in res: - for counter in res[thread]: - sck.send("%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow)) - if args.verbose: - print "%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow) - if args.oneshot: - break - time.sleep(float(args.delay)) + + +def main_task(args): + sc = suricatasc.SuricataSC(args.socket) + sc.connect() + + sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sck.connect((args.host, int(args.port))) + + while 1: + res = sc.send_command("dump-counters") + res = res['message'] + tnow = int(time.time()) + for thread in res: + for counter in res[thread]: + sck.send("%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow)) + if args.verbose: + print "%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow) + if args.oneshot: + break + time.sleep(float(args.delay)) + +if have_daemon and args.daemon: + with daemon.DaemonContext(): + main_task(args) +else: + main_task(args) From 0e955ccf3a8d46790dff241148515d707fc0359b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 20 May 2015 21:45:25 +0200 Subject: [PATCH 0480/2553] suri-graphite: add ouput to file option The --ooutput option allows to write the stats to a file given as argument the format used is JSON for easy parsing. --- contrib/suri-graphite | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/contrib/suri-graphite b/contrib/suri-graphite index 8506ceb7773b..beac0792b090 100755 --- a/contrib/suri-graphite +++ b/contrib/suri-graphite @@ -33,6 +33,7 @@ parser.add_argument('-P', '--port', default=2003, help='Port of Graphite data so parser.add_argument('-O', '--oneshot', action='store_const', const=True, help='Send one update and exit', default=False) parser.add_argument('-D', '--delay', default=10, help='Delay between data dump') parser.add_argument('-r', '--root', default='suricata.perf', help='Prefix of data name in Graphite') +parser.add_argument('-o', '--output', default=None, help='Output stats to a file instead of using Graphite') parser.add_argument('socket', help='suricata socket file to connect to', default="/usr/local/var/run/suricata/suricata-command.socket", nargs='?') parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output', default=False) @@ -42,13 +43,18 @@ if have_daemon: args = parser.parse_args() +if args.output: + import json def main_task(args): sc = suricatasc.SuricataSC(args.socket) sc.connect() - sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sck.connect((args.host, int(args.port))) + if args.output: + logfile = open(args.output, 'a') + else: + sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sck.connect((args.host, int(args.port))) while 1: res = sc.send_command("dump-counters") @@ -56,7 +62,11 @@ def main_task(args): tnow = int(time.time()) for thread in res: for counter in res[thread]: - sck.send("%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow)) + if args.output: + data = {"key": "%s.%s" % (thread , counter), "value": res[thread][counter], "time": tnow} + logfile.write(json.dumps(data) + '\n') + else: + sck.send("%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow)) if args.verbose: print "%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow) if args.oneshot: From 9f584483becf86cf91e7ee1ab6846d63210630d4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 22 May 2015 14:16:10 +0200 Subject: [PATCH 0481/2553] counters: minor cleanups --- src/counters.c | 3 +-- src/threadvars.h | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/counters.c b/src/counters.c index 6840fa9ea80b..cb9f3032ed78 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1219,14 +1219,13 @@ SCPerfCounterArray *SCPerfGetAllCountersArray(SCPerfContext *pctx) * * \param pca Pointer to the SCPerfCounterArray * \param pctx Pointer the the tv's SCPerfContext - * \param reset_lc Indicates whether the local counter has to be reset or not * * \retval 0 on success * \retval -1 on error */ int SCPerfUpdateCounterArray(SCPerfCounterArray *pca, SCPerfContext *pctx) { - SCPerfCounter *pc = NULL; + SCPerfCounter *pc = NULL; SCPCAElem *pcae = NULL; uint32_t i = 0; diff --git a/src/threadvars.h b/src/threadvars.h index 64c215bcca80..6ecdda25db4a 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -101,8 +101,12 @@ typedef struct ThreadVars_ { uint16_t rank; int thread_priority; /** priority (real time) for this thread. Look at threads.h */ - /* the perf counter context and the perf counter array */ + /* counters */ + + /** public counter store: counter syncs update this */ SCPerfContext sc_perf_pctx; + + /** private counter store: counter updates modify this */ SCPerfCounterArray *sc_perf_pca; SCCtrlMutex *ctrl_mutex; From 0a5ae1b403fb8f8a32e2da5b5c021981213bda46 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 22 May 2015 16:59:07 +0200 Subject: [PATCH 0482/2553] counters: s/SCPerfCounterArray/SCPerfPrivateContext/g Goal is to make it's purpose clear. --- src/counters.c | 50 ++++++++++++++++++++++++------------------------ src/counters.h | 25 ++++++++++++------------ src/threadvars.h | 2 +- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/counters.c b/src/counters.c index cb9f3032ed78..bf4447fd9844 100644 --- a/src/counters.c +++ b/src/counters.c @@ -79,7 +79,7 @@ void SCPerfOutputCounters(ThreadVars *tv) * \param pca Counter array that holds the local counter for this TM * \param x Value to add to this local counter */ -void SCPerfCounterAddUI64(uint16_t id, SCPerfCounterArray *pca, uint64_t x) +void SCPerfCounterAddUI64(uint16_t id, SCPerfPrivateContext *pca, uint64_t x) { if (!pca) { SCLogDebug("counterarray is NULL"); @@ -99,7 +99,7 @@ void SCPerfCounterAddUI64(uint16_t id, SCPerfCounterArray *pca, uint64_t x) * \param id Index of the counter in the counter array * \param pca Counter array that holds the local counters for this TM */ -void SCPerfCounterIncr(uint16_t id, SCPerfCounterArray *pca) +void SCPerfCounterIncr(uint16_t id, SCPerfPrivateContext *pca) { if (pca == NULL) { SCLogDebug("counterarray is NULL"); @@ -119,10 +119,10 @@ void SCPerfCounterIncr(uint16_t id, SCPerfCounterArray *pca) * \brief Sets a value of type double to the local counter * * \param id Index of the local counter in the counter array - * \param pca Pointer to the SCPerfCounterArray + * \param pca Pointer to the SCPerfPrivateContext * \param x The value to set for the counter */ -void SCPerfCounterSetUI64(uint16_t id, SCPerfCounterArray *pca, +void SCPerfCounterSetUI64(uint16_t id, SCPerfPrivateContext *pca, uint64_t x) { if (!pca) { @@ -545,10 +545,10 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, /** * \brief Copies the SCPerfCounter value from the local counter present in the - * SCPerfCounterArray to its corresponding global counterpart. Used + * SCPerfPrivateContext to its corresponding global counterpart. Used * internally by SCPerfUpdateCounterArray() * - * \param pcae Pointer to the SCPerfCounterArray which holds the local + * \param pcae Pointer to the SCPerfPrivateContext which holds the local * versions of the counters */ static void SCPerfCopyCounterValue(SCPCAElem *pcae) @@ -1148,11 +1148,11 @@ int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfContext *pctx) * * \retval a counter-array in this(s_id-e_id) range for this TM instance */ -SCPerfCounterArray *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, +SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, SCPerfContext *pctx) { SCPerfCounter *pc = NULL; - SCPerfCounterArray *pca = NULL; + SCPerfPrivateContext *pca = NULL; uint32_t i = 0; if (pctx == NULL) { @@ -1170,9 +1170,9 @@ SCPerfCounterArray *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, return NULL; } - if ( (pca = SCMalloc(sizeof(SCPerfCounterArray))) == NULL) + if ( (pca = SCMalloc(sizeof(SCPerfPrivateContext))) == NULL) return NULL; - memset(pca, 0, sizeof(SCPerfCounterArray)); + memset(pca, 0, sizeof(SCPerfPrivateContext)); if ( (pca->head = SCMalloc(sizeof(SCPCAElem) * (e_id - s_id + 2))) == NULL) { SCFree(pca); @@ -1205,9 +1205,9 @@ SCPerfCounterArray *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, * \retval pca Pointer to a counter-array for all counter of this tm instance * on success; NULL on failure */ -SCPerfCounterArray *SCPerfGetAllCountersArray(SCPerfContext *pctx) +SCPerfPrivateContext *SCPerfGetAllCountersArray(SCPerfContext *pctx) { - SCPerfCounterArray *pca = ((pctx)? + SCPerfPrivateContext *pca = ((pctx)? SCPerfGetCounterArrayRange(1, pctx->curr_id, pctx): NULL); @@ -1217,13 +1217,13 @@ SCPerfCounterArray *SCPerfGetAllCountersArray(SCPerfContext *pctx) /** * \brief Syncs the counter array with the global counter variables * - * \param pca Pointer to the SCPerfCounterArray + * \param pca Pointer to the SCPerfPrivateContext * \param pctx Pointer the the tv's SCPerfContext * * \retval 0 on success * \retval -1 on error */ -int SCPerfUpdateCounterArray(SCPerfCounterArray *pca, SCPerfContext *pctx) +int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, SCPerfContext *pctx) { SCPerfCounter *pc = NULL; SCPCAElem *pcae = NULL; @@ -1264,12 +1264,12 @@ int SCPerfUpdateCounterArray(SCPerfCounterArray *pca, SCPerfContext *pctx) * \brief Get the value of the local copy of the counter that hold this id. * * \param id The counter id. - * \param pca Pointer to the SCPerfCounterArray. + * \param pca Pointer to the SCPerfPrivateContext. * * \retval 0 on success. * \retval -1 on error. */ -double SCPerfGetLocalCounterValue(uint16_t id, SCPerfCounterArray *pca) +double SCPerfGetLocalCounterValue(uint16_t id, SCPerfPrivateContext *pca) { #ifdef DEBUG BUG_ON (pca == NULL); @@ -1308,12 +1308,12 @@ void SCPerfReleasePerfCounterS(SCPerfCounter *head) } /** - * \brief Releases the SCPerfCounterArray allocated by the user, for storing and + * \brief Releases the SCPerfPrivateContext allocated by the user, for storing and * updating local counter values * - * \param pca Pointer to the SCPerfCounterArray + * \param pca Pointer to the SCPerfPrivateContext */ -void SCPerfReleasePCA(SCPerfCounterArray *pca) +void SCPerfReleasePCA(SCPerfPrivateContext *pca) { if (pca != NULL) { if (pca->head != NULL) @@ -1423,12 +1423,12 @@ static int SCPerfTestGetCntArray06() static int SCPerfTestCntArraySize07() { ThreadVars tv; - SCPerfCounterArray *pca = NULL; + SCPerfPrivateContext *pca = NULL; int result; memset(&tv, 0, sizeof(ThreadVars)); - //pca = (SCPerfCounterArray *)&tv.sc_perf_pca; + //pca = (SCPerfPrivateContext *)&tv.sc_perf_pca; SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); @@ -1451,7 +1451,7 @@ static int SCPerfTestCntArraySize07() static int SCPerfTestUpdateCounter08() { ThreadVars tv; - SCPerfCounterArray *pca = NULL; + SCPerfPrivateContext *pca = NULL; int id; int result; @@ -1476,7 +1476,7 @@ static int SCPerfTestUpdateCounter08() static int SCPerfTestUpdateCounter09() { ThreadVars tv; - SCPerfCounterArray *pca = NULL; + SCPerfPrivateContext *pca = NULL; uint16_t id1, id2; int result; @@ -1509,7 +1509,7 @@ static int SCPerfTestUpdateCounter09() static int SCPerfTestUpdateGlobalCounter10() { ThreadVars tv; - SCPerfCounterArray *pca = NULL; + SCPerfPrivateContext *pca = NULL; int result = 1; uint16_t id1, id2, id3; @@ -1545,7 +1545,7 @@ static int SCPerfTestUpdateGlobalCounter10() static int SCPerfTestCounterValues11() { ThreadVars tv; - SCPerfCounterArray *pca = NULL; + SCPerfPrivateContext *pca = NULL; int result = 1; uint16_t id1, id2, id3, id4; diff --git a/src/counters.h b/src/counters.h index a1617d403757..3cc0dad08301 100644 --- a/src/counters.h +++ b/src/counters.h @@ -97,7 +97,7 @@ typedef struct SCPerfContext_ { } SCPerfContext; /** - * \brief Node elements used by the SCPerfCounterArray(PCA) Node + * \brief Node elements used by the SCPerfPrivateContext(PCA) Node */ typedef struct SCPCAElem_ { /* pointer to the PerfCounter that corresponds to this PCAElem */ @@ -113,16 +113,15 @@ typedef struct SCPCAElem_ { } SCPCAElem; /** - * \brief The SCPerfCounterArray used to hold the local version of the counters - * registered + * \brief used to hold the private version of the counters registered */ -typedef struct SCPerfCounterArray_ { +typedef struct SCPerfPrivateContext_ { /* points to the array holding PCAElems */ SCPCAElem *head; /* no of PCAElems in head */ uint32_t size; -} SCPerfCounterArray; +} SCPerfPrivateContext; /** * \brief Holds multiple instances of the same TM together, used when the stats @@ -161,24 +160,24 @@ uint16_t SCPerfRegisterMaxCounter(char *, char *, int, char *, SCPerfContext *); /* utility functions */ int SCPerfAddToClubbedTMTable(char *, SCPerfContext *); -SCPerfCounterArray *SCPerfGetCounterArrayRange(uint16_t, uint16_t, SCPerfContext *); -SCPerfCounterArray * SCPerfGetAllCountersArray(SCPerfContext *); +SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t, uint16_t, SCPerfContext *); +SCPerfPrivateContext * SCPerfGetAllCountersArray(SCPerfContext *); -int SCPerfUpdateCounterArray(SCPerfCounterArray *, SCPerfContext *); -double SCPerfGetLocalCounterValue(uint16_t, SCPerfCounterArray *); +int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfContext *); +double SCPerfGetLocalCounterValue(uint16_t, SCPerfPrivateContext *); /* functions used to free the resources alloted by the Perf counter API */ void SCPerfReleaseResources(void); void SCPerfReleasePerfCounterS(SCPerfCounter *); -void SCPerfReleasePCA(SCPerfCounterArray *); +void SCPerfReleasePCA(SCPerfPrivateContext *); -void SCPerfCounterSetUI64(uint16_t, SCPerfCounterArray *, uint64_t); -void SCPerfCounterIncr(uint16_t, SCPerfCounterArray *); +void SCPerfCounterSetUI64(uint16_t, SCPerfPrivateContext *, uint64_t); +void SCPerfCounterIncr(uint16_t, SCPerfPrivateContext *); void SCPerfRegisterTests(void); /* functions used to update local counter values */ -void SCPerfCounterAddUI64(uint16_t, SCPerfCounterArray *, uint64_t); +void SCPerfCounterAddUI64(uint16_t, SCPerfPrivateContext *, uint64_t); #define SCPerfSyncCounters(tv) \ SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->sc_perf_pctx); \ diff --git a/src/threadvars.h b/src/threadvars.h index 6ecdda25db4a..896f786ef784 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -107,7 +107,7 @@ typedef struct ThreadVars_ { SCPerfContext sc_perf_pctx; /** private counter store: counter updates modify this */ - SCPerfCounterArray *sc_perf_pca; + SCPerfPrivateContext *sc_perf_pca; SCCtrlMutex *ctrl_mutex; SCCtrlCondT *ctrl_cond; From 6ffbc3a36216f6dcf0c94c915fc743ddbbef6f97 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 22 May 2015 17:04:17 +0200 Subject: [PATCH 0483/2553] counters: s/SCPerfContext/SCPerfPublicContext/g --- src/counters.c | 58 ++++++++++++++++++++++++------------------------ src/counters.h | 20 ++++++++--------- src/threadvars.h | 2 +- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/counters.c b/src/counters.c index bf4447fd9844..c214b123d2d9 100644 --- a/src/counters.c +++ b/src/counters.c @@ -334,7 +334,7 @@ static void *SCPerfMgmtThread(void *arg) /** * \brief Wake up thread. This thread wakes up every TTS(time to sleep) seconds - * and sets the flag for every ThreadVars' SCPerfContext + * and sets the flag for every ThreadVars' SCPerfPublicContext * * \param arg is NULL always * @@ -465,7 +465,7 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) * \param tm_name Thread module to which this counter belongs * \param type Datatype of this counter variable * \param desc Description of this counter - * \param pctx SCPerfContext for this tm-tv instance + * \param pctx SCPerfPublicContext for this tm-tv instance * \param type_q Qualifier describing the type of counter to be registered * * \retval the counter id for the newly registered counter, or the already @@ -474,7 +474,7 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) */ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, int type, char *desc, - SCPerfContext *pctx, int type_q) + SCPerfPublicContext *pctx, int type_q) { SCPerfCounter **head = &pctx->head; SCPerfCounter *temp = NULL; @@ -482,7 +482,7 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, SCPerfCounter *pc = NULL; if (cname == NULL || tm_name == NULL || pctx == NULL) { - SCLogDebug("Counter name, tm name null or SCPerfContext NULL"); + SCLogDebug("Counter name, tm name null or SCPerfPublicContext NULL"); return 0; } @@ -962,14 +962,14 @@ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, * registered * \param type Datatype of this counter variable * \param desc Description of this counter - * \param pctx SCPerfContext corresponding to the tm_name key under which the + * \param pctx SCPerfPublicContext corresponding to the tm_name key under which the * key has to be registered * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, char *desc, - SCPerfContext *pctx) + SCPerfPublicContext *pctx) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, pctx, SC_PERF_TYPE_Q_NORMAL); @@ -986,14 +986,14 @@ uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, char *desc, * registered * \param type Datatype of this counter variable * \param desc Description of this counter - * \param pctx SCPerfContext corresponding to the tm_name key under which the + * \param pctx SCPerfPublicContext corresponding to the tm_name key under which the * key has to be registered * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfRegisterAvgCounter(char *cname, char *tm_name, int type, - char *desc, SCPerfContext *pctx) + char *desc, SCPerfPublicContext *pctx) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, pctx, SC_PERF_TYPE_Q_AVERAGE); @@ -1010,14 +1010,14 @@ uint16_t SCPerfRegisterAvgCounter(char *cname, char *tm_name, int type, * registered * \param type Datatype of this counter variable * \param desc Description of this counter - * \param pctx SCPerfContext corresponding to the tm_name key under which the + * \param pctx SCPerfPublicContext corresponding to the tm_name key under which the * key has to be registered * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfRegisterMaxCounter(char *cname, char *tm_name, int type, - char *desc, SCPerfContext *pctx) + char *desc, SCPerfPublicContext *pctx) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, pctx, SC_PERF_TYPE_Q_MAXIMUM); @@ -1030,11 +1030,11 @@ uint16_t SCPerfRegisterMaxCounter(char *cname, char *tm_name, int type, * are stacked together in a PCTMI container. * * \param tm_name Name of the tm to be added to the table - * \param pctx SCPerfContext associated with the TM tm_name + * \param pctx SCPerfPublicContext associated with the TM tm_name * * \retval 1 on success, 0 on failure */ -int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfContext *pctx) +int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfPublicContext *pctx) { void *ptmp; if (sc_perf_op_ctx == NULL) { @@ -1045,7 +1045,7 @@ int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfContext *pctx) SCPerfClubTMInst *pctmi = NULL; SCPerfClubTMInst *prev = NULL; SCPerfClubTMInst *temp = NULL; - SCPerfContext **hpctx = NULL; + SCPerfPublicContext **hpctx = NULL; uint32_t u = 0; if (tm_name == NULL || pctx == NULL) { @@ -1077,7 +1077,7 @@ int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfContext *pctx) memset(temp, 0, sizeof(SCPerfClubTMInst)); temp->size = 1; - temp->head = SCMalloc(sizeof(SCPerfContext **)); + temp->head = SCMalloc(sizeof(SCPerfPublicContext **)); if (temp->head == NULL) { SCFree(temp); SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); @@ -1112,7 +1112,7 @@ int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfContext *pctx) } ptmp = SCRealloc(pctmi->head, - (pctmi->size + 1) * sizeof(SCPerfContext **)); + (pctmi->size + 1) * sizeof(SCPerfPublicContext **)); if (ptmp == NULL) { SCFree(pctmi->head); pctmi->head = NULL; @@ -1144,12 +1144,12 @@ int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfContext *pctx) * * \param s_id Counter id of the first counter to be added to the array * \param e_id Counter id of the last counter to be added to the array - * \param pctx Pointer to the tv's SCPerfContext + * \param pctx Pointer to the tv's SCPerfPublicContext * * \retval a counter-array in this(s_id-e_id) range for this TM instance */ SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, - SCPerfContext *pctx) + SCPerfPublicContext *pctx) { SCPerfCounter *pc = NULL; SCPerfPrivateContext *pca = NULL; @@ -1200,12 +1200,12 @@ SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, * \brief Returns a counter array for all counters registered for this tm * instance * - * \param pctx Pointer to the tv's SCPerfContext + * \param pctx Pointer to the tv's SCPerfPublicContext * * \retval pca Pointer to a counter-array for all counter of this tm instance * on success; NULL on failure */ -SCPerfPrivateContext *SCPerfGetAllCountersArray(SCPerfContext *pctx) +SCPerfPrivateContext *SCPerfGetAllCountersArray(SCPerfPublicContext *pctx) { SCPerfPrivateContext *pca = ((pctx)? SCPerfGetCounterArrayRange(1, pctx->curr_id, pctx): @@ -1218,12 +1218,12 @@ SCPerfPrivateContext *SCPerfGetAllCountersArray(SCPerfContext *pctx) * \brief Syncs the counter array with the global counter variables * * \param pca Pointer to the SCPerfPrivateContext - * \param pctx Pointer the the tv's SCPerfContext + * \param pctx Pointer the the tv's SCPerfPublicContext * * \retval 0 on success * \retval -1 on error */ -int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, SCPerfContext *pctx) +int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, SCPerfPublicContext *pctx) { SCPerfCounter *pc = NULL; SCPCAElem *pcae = NULL; @@ -1330,28 +1330,28 @@ void SCPerfReleasePCA(SCPerfPrivateContext *pca) #ifdef UNITTESTS static int SCPerfTestCounterReg01() { - SCPerfContext pctx; + SCPerfPublicContext pctx; - memset(&pctx, 0, sizeof(SCPerfContext)); + memset(&pctx, 0, sizeof(SCPerfPublicContext)); return SCPerfRegisterCounter("t1", "c1", 5, NULL, &pctx); } static int SCPerfTestCounterReg02() { - SCPerfContext pctx; + SCPerfPublicContext pctx; - memset(&pctx, 0, sizeof(SCPerfContext)); + memset(&pctx, 0, sizeof(SCPerfPublicContext)); return SCPerfRegisterCounter(NULL, NULL, SC_PERF_TYPE_UINT64, NULL, &pctx); } static int SCPerfTestCounterReg03() { - SCPerfContext pctx; + SCPerfPublicContext pctx; int result; - memset(&pctx, 0, sizeof(SCPerfContext)); + memset(&pctx, 0, sizeof(SCPerfPublicContext)); result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); @@ -1362,10 +1362,10 @@ static int SCPerfTestCounterReg03() static int SCPerfTestCounterReg04() { - SCPerfContext pctx; + SCPerfPublicContext pctx; int result; - memset(&pctx, 0, sizeof(SCPerfContext)); + memset(&pctx, 0, sizeof(SCPerfPublicContext)); SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &pctx); diff --git a/src/counters.h b/src/counters.h index 3cc0dad08301..c3bdca24422c 100644 --- a/src/counters.h +++ b/src/counters.h @@ -82,7 +82,7 @@ typedef struct SCPerfCounter_ { /** * \brief Holds the Perf Context for a ThreadVars instance */ -typedef struct SCPerfContext_ { +typedef struct SCPerfPublicContext_ { /* flag set by the wakeup thread, to inform the client threads to sync */ uint32_t perf_flag; @@ -94,7 +94,7 @@ typedef struct SCPerfContext_ { /* mutex to prevent simultaneous access during update_counter/output_stat */ SCMutex m; -} SCPerfContext; +} SCPerfPublicContext; /** * \brief Node elements used by the SCPerfPrivateContext(PCA) Node @@ -130,7 +130,7 @@ typedef struct SCPerfPrivateContext_ { typedef struct SCPerfClubTMInst_ { char *tm_name; - SCPerfContext **head; + SCPerfPublicContext **head; uint32_t size; struct SCPerfClubTMInst_ *next; @@ -154,16 +154,16 @@ uint16_t SCPerfTVRegisterAvgCounter(char *, struct ThreadVars_ *, int, char *); uint16_t SCPerfTVRegisterMaxCounter(char *, struct ThreadVars_ *, int, char *); /* the non-ThreadVars counter registration functions */ -uint16_t SCPerfRegisterCounter(char *, char *, int, char *, SCPerfContext *); -uint16_t SCPerfRegisterAvgCounter(char *, char *, int, char *, SCPerfContext *); -uint16_t SCPerfRegisterMaxCounter(char *, char *, int, char *, SCPerfContext *); +uint16_t SCPerfRegisterCounter(char *, char *, int, char *, SCPerfPublicContext *); +uint16_t SCPerfRegisterAvgCounter(char *, char *, int, char *, SCPerfPublicContext *); +uint16_t SCPerfRegisterMaxCounter(char *, char *, int, char *, SCPerfPublicContext *); /* utility functions */ -int SCPerfAddToClubbedTMTable(char *, SCPerfContext *); -SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t, uint16_t, SCPerfContext *); -SCPerfPrivateContext * SCPerfGetAllCountersArray(SCPerfContext *); +int SCPerfAddToClubbedTMTable(char *, SCPerfPublicContext *); +SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t, uint16_t, SCPerfPublicContext *); +SCPerfPrivateContext * SCPerfGetAllCountersArray(SCPerfPublicContext *); -int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfContext *); +int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfPublicContext *); double SCPerfGetLocalCounterValue(uint16_t, SCPerfPrivateContext *); /* functions used to free the resources alloted by the Perf counter API */ diff --git a/src/threadvars.h b/src/threadvars.h index 896f786ef784..25045f197919 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -104,7 +104,7 @@ typedef struct ThreadVars_ { /* counters */ /** public counter store: counter syncs update this */ - SCPerfContext sc_perf_pctx; + SCPerfPublicContext sc_perf_pctx; /** private counter store: counter updates modify this */ SCPerfPrivateContext *sc_perf_pca; From 50bb995458d49d01c0a13c0947edeb6b9d82c818 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 22 May 2015 19:59:35 +0200 Subject: [PATCH 0484/2553] counters: rename threadvars public counters --- src/counters.c | 90 +++++++++++++++++++++++----------------------- src/counters.h | 6 ++-- src/detect.c | 4 +-- src/threadvars.h | 2 +- src/tm-threads.c | 16 ++++----- src/unix-manager.c | 4 +-- 6 files changed, 61 insertions(+), 61 deletions(-) diff --git a/src/counters.c b/src/counters.c index c214b123d2d9..d07666f784fa 100644 --- a/src/counters.c +++ b/src/counters.c @@ -390,14 +390,14 @@ static void *SCPerfWakeupThread(void *arg) tv = tv_root[TVT_PPT]; while (tv != NULL) { - if (tv->sc_perf_pctx.head == NULL) { + if (tv->perf_public_ctx.head == NULL) { tv = tv->next; continue; } /* assuming the assignment of an int to be atomic, and even if it's * not, it should be okay */ - tv->sc_perf_pctx.perf_flag = 1; + tv->perf_public_ctx.perf_flag = 1; if (tv->inq != NULL) { q = &trans_q[tv->inq->id]; @@ -410,14 +410,14 @@ static void *SCPerfWakeupThread(void *arg) /* mgt threads for flow manager */ tv = tv_root[TVT_MGMT]; while (tv != NULL) { - if (tv->sc_perf_pctx.head == NULL) { + if (tv->perf_public_ctx.head == NULL) { tv = tv->next; continue; } /* assuming the assignment of an int to be atomic, and even if it's * not, it should be okay */ - tv->sc_perf_pctx.perf_flag = 1; + tv->perf_public_ctx.perf_flag = 1; tv = tv->next; } @@ -898,7 +898,7 @@ uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type, uint16_t id = SCPerfRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, desc, - &tv->sc_perf_pctx, + &tv->perf_public_ctx, SC_PERF_TYPE_Q_NORMAL); return id; @@ -923,7 +923,7 @@ uint16_t SCPerfTVRegisterAvgCounter(char *cname, struct ThreadVars_ *tv, uint16_t id = SCPerfRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, desc, - &tv->sc_perf_pctx, + &tv->perf_public_ctx, SC_PERF_TYPE_Q_AVERAGE); return id; @@ -948,7 +948,7 @@ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, uint16_t id = SCPerfRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, desc, - &tv->sc_perf_pctx, + &tv->perf_public_ctx, SC_PERF_TYPE_Q_MAXIMUM); return id; @@ -1386,7 +1386,7 @@ static int SCPerfTestGetCntArray05() memset(&tv, 0, sizeof(ThreadVars)); id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); if (id != 1) { printf("id %d: ", id); return 0; @@ -1406,15 +1406,15 @@ static int SCPerfTestGetCntArray06() memset(&tv, 0, sizeof(ThreadVars)); id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); if (id != 1) return 0; - tv.sc_perf_pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + tv.sc_perf_pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); result = (tv.sc_perf_pca)?1:0; - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); + SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); SCPerfReleasePCA(tv.sc_perf_pca); return result; @@ -1431,18 +1431,18 @@ static int SCPerfTestCntArraySize07() //pca = (SCPerfPrivateContext *)&tv.sc_perf_pca; SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); SCPerfCounterIncr(1, pca); SCPerfCounterIncr(2, pca); result = pca->size; - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); + SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); SCPerfReleasePCA(pca); return result; @@ -1458,16 +1458,16 @@ static int SCPerfTestUpdateCounter08() memset(&tv, 0, sizeof(ThreadVars)); id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); SCPerfCounterIncr(id, pca); SCPerfCounterAddUI64(id, pca, 100); result = pca->head[id].ui64_cnt; - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); + SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); SCPerfReleasePCA(pca); return result; @@ -1483,24 +1483,24 @@ static int SCPerfTestUpdateCounter09() memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); id2 = SCPerfRegisterCounter("t5", "c5", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); SCPerfCounterIncr(id2, pca); SCPerfCounterAddUI64(id2, pca, 100); result = (pca->head[id1].ui64_cnt == 0) && (pca->head[id2].ui64_cnt == 101); - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); + SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); SCPerfReleasePCA(pca); return result; @@ -1517,26 +1517,26 @@ static int SCPerfTestUpdateGlobalCounter10() memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); SCPerfCounterIncr(id1, pca); SCPerfCounterAddUI64(id2, pca, 100); SCPerfCounterIncr(id3, pca); SCPerfCounterAddUI64(id3, pca, 100); - SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx); + SCPerfUpdateCounterArray(pca, &tv.perf_public_ctx); - result = (1 == tv.sc_perf_pctx.head->value); - result &= (100 == tv.sc_perf_pctx.head->next->value); - result &= (101 == tv.sc_perf_pctx.head->next->next->value); + result = (1 == tv.perf_public_ctx.head->value); + result &= (100 == tv.perf_public_ctx.head->next->value); + result &= (101 == tv.perf_public_ctx.head->next->next->value); - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); + SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); SCPerfReleasePCA(pca); return result; @@ -1553,32 +1553,32 @@ static int SCPerfTestCounterValues11() memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); id4 = SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); SCPerfCounterIncr(id1, pca); SCPerfCounterAddUI64(id2, pca, 256); SCPerfCounterAddUI64(id3, pca, 257); SCPerfCounterAddUI64(id4, pca, 16843024); - SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx); + SCPerfUpdateCounterArray(pca, &tv.perf_public_ctx); - result &= (1 == tv.sc_perf_pctx.head->value); + result &= (1 == tv.perf_public_ctx.head->value); - result &= (256 == tv.sc_perf_pctx.head->next->value); + result &= (256 == tv.perf_public_ctx.head->next->value); - result &= (257 == tv.sc_perf_pctx.head->next->next->value); + result &= (257 == tv.perf_public_ctx.head->next->next->value); - result &= (16843024 == tv.sc_perf_pctx.head->next->next->next->value); + result &= (16843024 == tv.perf_public_ctx.head->next->next->next->value); - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); + SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); SCPerfReleasePCA(pca); return result; diff --git a/src/counters.h b/src/counters.h index c3bdca24422c..c10eb4e50c1f 100644 --- a/src/counters.h +++ b/src/counters.h @@ -180,12 +180,12 @@ void SCPerfRegisterTests(void); void SCPerfCounterAddUI64(uint16_t, SCPerfPrivateContext *, uint64_t); #define SCPerfSyncCounters(tv) \ - SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->sc_perf_pctx); \ + SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->perf_public_ctx); \ #define SCPerfSyncCountersIfSignalled(tv) \ do { \ - if ((tv)->sc_perf_pctx.perf_flag == 1) { \ - SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->sc_perf_pctx); \ + if ((tv)->perf_public_ctx.perf_flag == 1) { \ + SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->perf_public_ctx); \ } \ } while (0) diff --git a/src/detect.c b/src/detect.c index 4069a5d5b9a1..6ca2b30bdd71 100644 --- a/src/detect.c +++ b/src/detect.c @@ -11263,9 +11263,9 @@ static int SigTestDetectAlertCounter(void) DetectEngineThreadCtxInit(&tv, de_ctx, (void *)&det_ctx); /* init counters */ - tv.sc_perf_pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + tv.sc_perf_pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); SCPerfAddToClubbedTMTable((tv.thread_group_name != NULL) ? - tv.thread_group_name : tv.name, &tv.sc_perf_pctx); + tv.thread_group_name : tv.name, &tv.perf_public_ctx); p = UTHBuildPacket((uint8_t *)"boo", strlen("boo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); diff --git a/src/threadvars.h b/src/threadvars.h index 25045f197919..d6d8265dc877 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -104,7 +104,7 @@ typedef struct ThreadVars_ { /* counters */ /** public counter store: counter syncs update this */ - SCPerfPublicContext sc_perf_pctx; + SCPerfPublicContext perf_public_ctx; /** private counter store: counter updates modify this */ SCPerfPrivateContext *sc_perf_pca; diff --git a/src/tm-threads.c b/src/tm-threads.c index 6ad8b6fedf09..dfe0bcc59b5f 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -322,9 +322,9 @@ void *TmThreadsSlotPktAcqLoop(void *td) } } - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); + tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->perf_public_ctx); SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); + tv->thread_group_name : tv->name, &tv->perf_public_ctx); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -455,9 +455,9 @@ void *TmThreadsSlotVar(void *td) } } - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); + tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->perf_public_ctx); SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); + tv->thread_group_name : tv->name, &tv->perf_public_ctx); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -597,9 +597,9 @@ static void *TmThreadsManagement(void *td) memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); + tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->perf_public_ctx); SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); + tv->thread_group_name : tv->name, &tv->perf_public_ctx); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -1045,7 +1045,7 @@ ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name, memset(tv, 0, sizeof(ThreadVars)); SC_ATOMIC_INIT(tv->flags); - SCMutexInit(&tv->sc_perf_pctx.m, NULL); + SCMutexInit(&tv->perf_public_ctx.m, NULL); tv->name = name; /* default state for every newly created thread */ @@ -1653,7 +1653,7 @@ void TmThreadFree(ThreadVars *tv) SCLogDebug("Freeing thread '%s'.", tv->name); - SCMutexDestroy(&tv->sc_perf_pctx.m); + SCMutexDestroy(&tv->perf_public_ctx.m); s = (TmSlot *)tv->tm_slots; while (s) { diff --git a/src/unix-manager.c b/src/unix-manager.c index b8eb0045ca44..dd2d2d91d294 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -868,8 +868,8 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) /* set the thread name */ SCLogDebug("%s started...", th_v->name); - th_v->sc_perf_pca = SCPerfGetAllCountersArray(&th_v->sc_perf_pctx); - SCPerfAddToClubbedTMTable(th_v->name, &th_v->sc_perf_pctx); + th_v->sc_perf_pca = SCPerfGetAllCountersArray(&th_v->perf_public_ctx); + SCPerfAddToClubbedTMTable(th_v->name, &th_v->perf_public_ctx); if (UnixNew(&command) == 0) { int failure_fatal = 0; From 9a8bff7d96038177f745315003113fd498c22299 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 22 May 2015 20:56:09 +0200 Subject: [PATCH 0485/2553] counters: threadvars s/sc_perf_pca/perf_private_ctx/g --- src/app-layer-htp-mem.c | 4 ++-- src/app-layer.c | 6 +++--- src/counters.c | 12 ++++++------ src/counters.h | 4 ++-- src/decode-ethernet.c | 2 +- src/decode-gre.c | 2 +- src/decode-icmpv4.c | 2 +- src/decode-icmpv6.c | 2 +- src/decode-ipv4.c | 2 +- src/decode-ipv6.c | 6 +++--- src/decode-mpls.c | 2 +- src/decode-null.c | 2 +- src/decode-ppp.c | 2 +- src/decode-pppoe.c | 4 ++-- src/decode-raw.c | 2 +- src/decode-sctp.c | 2 +- src/decode-sll.c | 2 +- src/decode-tcp.c | 2 +- src/decode-teredo.c | 2 +- src/decode-udp.c | 2 +- src/decode-vlan.c | 4 ++-- src/decode.c | 2 +- src/defrag.c | 8 ++++---- src/detect.c | 20 ++++++++++---------- src/flow-manager.c | 22 +++++++++++----------- src/source-af-packet.c | 24 ++++++++++++------------ src/source-erf-dag.c | 26 +++++++++++++------------- src/source-erf-file.c | 14 +++++++------- src/source-ipfw.c | 8 ++++---- src/source-mpipe.c | 16 ++++++++-------- src/source-napatech.c | 10 +++++----- src/source-netmap.c | 16 ++++++++-------- src/source-nflog.c | 8 ++++---- src/source-nfq.c | 12 ++++++------ src/source-pcap-file.c | 14 +++++++------- src/source-pcap.c | 20 ++++++++++---------- src/source-pfring.c | 28 ++++++++++++++-------------- src/stream-tcp-reassemble.c | 10 +++++----- src/stream-tcp.c | 28 ++++++++++++++-------------- src/threadvars.h | 2 +- src/tm-threads.c | 6 +++--- src/unix-manager.c | 2 +- 42 files changed, 182 insertions(+), 182 deletions(-) diff --git a/src/app-layer-htp-mem.c b/src/app-layer-htp-mem.c index 8d5e9f0e8b17..f676af0617bd 100644 --- a/src/app-layer-htp-mem.c +++ b/src/app-layer-htp-mem.c @@ -81,9 +81,9 @@ void HTPDecrMemuse(uint64_t size) void HTPMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *trt) { uint64_t tmpval = SC_ATOMIC_GET(htp_memuse); - SCPerfCounterSetUI64(trt->counter_htp_memuse, tv->sc_perf_pca, tmpval); + SCPerfCounterSetUI64(trt->counter_htp_memuse, tv->perf_private_ctx, tmpval); tmpval = SC_ATOMIC_GET(htp_memcap); - SCPerfCounterSetUI64(trt->counter_htp_memcap, tv->sc_perf_pca, tmpval); + SCPerfCounterSetUI64(trt->counter_htp_memcap, tv->perf_private_ctx, tmpval); return; } /** diff --git a/src/app-layer.c b/src/app-layer.c index f8bdf7738549..711bec3a0587 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -79,11 +79,11 @@ static void DNSUpdateCounters(ThreadVars *tv, AppLayerThreadCtx *app_tctx) DNSMemcapGetCounters(&memuse, &memcap_state, &memcap_global); SCPerfCounterSetUI64(app_tctx->counter_dns_memuse, - tv->sc_perf_pca, memuse); + tv->perf_private_ctx, memuse); SCPerfCounterSetUI64(app_tctx->counter_dns_memcap_state, - tv->sc_perf_pca, memcap_state); + tv->perf_private_ctx, memcap_state); SCPerfCounterSetUI64(app_tctx->counter_dns_memcap_global, - tv->sc_perf_pca, memcap_global); + tv->perf_private_ctx, memcap_global); } /***** L7 layer dispatchers *****/ diff --git a/src/counters.c b/src/counters.c index d07666f784fa..3ccbccae9615 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1392,9 +1392,9 @@ static int SCPerfTestGetCntArray05() return 0; } - tv.sc_perf_pca = SCPerfGetAllCountersArray(NULL); + tv.perf_private_ctx = SCPerfGetAllCountersArray(NULL); - return (!tv.sc_perf_pca)?1:0; + return (!tv.perf_private_ctx)?1:0; } static int SCPerfTestGetCntArray06() @@ -1410,12 +1410,12 @@ static int SCPerfTestGetCntArray06() if (id != 1) return 0; - tv.sc_perf_pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); - result = (tv.sc_perf_pca)?1:0; + result = (tv.perf_private_ctx)?1:0; SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); - SCPerfReleasePCA(tv.sc_perf_pca); + SCPerfReleasePCA(tv.perf_private_ctx); return result; } @@ -1428,7 +1428,7 @@ static int SCPerfTestCntArraySize07() memset(&tv, 0, sizeof(ThreadVars)); - //pca = (SCPerfPrivateContext *)&tv.sc_perf_pca; + //pca = (SCPerfPrivateContext *)&tv.perf_private_ctx; SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); diff --git a/src/counters.h b/src/counters.h index c10eb4e50c1f..3eff9ef6e632 100644 --- a/src/counters.h +++ b/src/counters.h @@ -180,12 +180,12 @@ void SCPerfRegisterTests(void); void SCPerfCounterAddUI64(uint16_t, SCPerfPrivateContext *, uint64_t); #define SCPerfSyncCounters(tv) \ - SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->perf_public_ctx); \ + SCPerfUpdateCounterArray((tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ #define SCPerfSyncCountersIfSignalled(tv) \ do { \ if ((tv)->perf_public_ctx.perf_flag == 1) { \ - SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->perf_public_ctx); \ + SCPerfUpdateCounterArray((tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ } \ } while (0) diff --git a/src/decode-ethernet.c b/src/decode-ethernet.c index e5a920d16932..32f737a7ddc5 100644 --- a/src/decode-ethernet.c +++ b/src/decode-ethernet.c @@ -41,7 +41,7 @@ int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_eth, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_eth, tv->perf_private_ctx); if (unlikely(len < ETHERNET_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, ETHERNET_PKT_TOO_SMALL); diff --git a/src/decode-gre.c b/src/decode-gre.c index cd9f47191b8f..b686663d34cb 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -48,7 +48,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui uint16_t header_len = GRE_HDR_LEN; GRESreHdr *gsre = NULL; - SCPerfCounterIncr(dtv->counter_gre, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_gre, tv->perf_private_ctx); if(len < GRE_HDR_LEN) { ENGINE_SET_INVALID_EVENT(p, GRE_PKT_TOO_SMALL); diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index 99ab99f231c6..a1926ec210cb 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -153,7 +153,7 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) */ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_icmpv4, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_icmpv4, tv->perf_private_ctx); if (len < ICMPV4_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, ICMPV4_PKT_TOO_SMALL); diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index 4cd62ef96434..a56a0db6602a 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -168,7 +168,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { int full_hdr = 0; - SCPerfCounterIncr(dtv->counter_icmpv6, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_icmpv6, tv->perf_private_ctx); if (len < ICMPV6_HEADER_LEN) { SCLogDebug("ICMPV6_PKT_TOO_SMALL"); diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 5bfb228c8367..03fd4782ab99 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -519,7 +519,7 @@ static int DecodeIPV4Packet(Packet *p, uint8_t *pkt, uint16_t len) int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_ipv4, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_ipv4, tv->perf_private_ctx); SCLogDebug("pkt %p len %"PRIu16"", pkt, len); diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index 111810bd9766..bb2b40269c60 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -65,7 +65,7 @@ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, u PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); - SCPerfCounterIncr(dtv->counter_ipv4inipv6, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_ipv4inipv6, tv->perf_private_ctx); return; } } @@ -92,7 +92,7 @@ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); PacketEnqueue(pq,tp); - SCPerfCounterIncr(dtv->counter_ipv6inipv6, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_ipv6inipv6, tv->perf_private_ctx); } } } else { @@ -601,7 +601,7 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u { int ret; - SCPerfCounterIncr(dtv->counter_ipv6, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_ipv6, tv->perf_private_ctx); /* do the actual decoding */ ret = DecodeIPV6Packet (tv, dtv, p, pkt, len); diff --git a/src/decode-mpls.c b/src/decode-mpls.c index 86188502031b..e8ff0371e2d6 100644 --- a/src/decode-mpls.c +++ b/src/decode-mpls.c @@ -51,7 +51,7 @@ int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, int label; int event = 0; - SCPerfCounterIncr(dtv->counter_mpls, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_mpls, tv->perf_private_ctx); do { if (len < MPLS_HEADER_LEN) { diff --git a/src/decode-null.c b/src/decode-null.c index 8bb76ca79bda..fa1738436aa9 100644 --- a/src/decode-null.c +++ b/src/decode-null.c @@ -47,7 +47,7 @@ int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_null, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_null, tv->perf_private_ctx); if (unlikely(len < HDR_SIZE)) { ENGINE_SET_INVALID_EVENT(p, LTNULL_PKT_TOO_SMALL); diff --git a/src/decode-ppp.c b/src/decode-ppp.c index 0d15c0c450ed..1f2c395924fc 100644 --- a/src/decode-ppp.c +++ b/src/decode-ppp.c @@ -42,7 +42,7 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_ppp, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_ppp, tv->perf_private_ctx); if (unlikely(len < PPP_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, PPP_PKT_TOO_SMALL); diff --git a/src/decode-pppoe.c b/src/decode-pppoe.c index 57df28f5e54b..1cec70076c37 100644 --- a/src/decode-pppoe.c +++ b/src/decode-pppoe.c @@ -49,7 +49,7 @@ */ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_pppoe, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_pppoe, tv->perf_private_ctx); if (len < PPPOE_DISCOVERY_HEADER_MIN_LEN) { ENGINE_SET_INVALID_EVENT(p, PPPOE_PKT_TOO_SMALL); @@ -128,7 +128,7 @@ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8 */ int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_pppoe, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_pppoe, tv->perf_private_ctx); if (len < PPPOE_SESSION_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, PPPOE_PKT_TOO_SMALL); diff --git a/src/decode-raw.c b/src/decode-raw.c index caa806873842..06eaec39c78f 100644 --- a/src/decode-raw.c +++ b/src/decode-raw.c @@ -45,7 +45,7 @@ int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_raw, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_raw, tv->perf_private_ctx); /* If it is ipv4 or ipv6 it should at least be the size of ipv4 */ if (unlikely(len < IPV4_HEADER_LEN)) { diff --git a/src/decode-sctp.c b/src/decode-sctp.c index 6fd8be8d616d..cc287e0d48dd 100644 --- a/src/decode-sctp.c +++ b/src/decode-sctp.c @@ -61,7 +61,7 @@ static int DecodeSCTPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t le int DecodeSCTP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_sctp, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_sctp, tv->perf_private_ctx); if (unlikely(DecodeSCTPPacket(tv, p,pkt,len) < 0)) { p->sctph = NULL; diff --git a/src/decode-sll.c b/src/decode-sll.c index 5bfc63cf56fd..65c1c57db42a 100644 --- a/src/decode-sll.c +++ b/src/decode-sll.c @@ -38,7 +38,7 @@ int DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_sll, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_sll, tv->perf_private_ctx); if (unlikely(len < SLL_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, SLL_PKT_TOO_SMALL); diff --git a/src/decode-tcp.c b/src/decode-tcp.c index 47c066160d0b..206669e4dc4c 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -186,7 +186,7 @@ static int DecodeTCPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t len int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_tcp, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_tcp, tv->perf_private_ctx); if (unlikely(DecodeTCPPacket(tv, p,pkt,len) < 0)) { SCLogDebug("invalid TCP packet"); diff --git a/src/decode-teredo.c b/src/decode-teredo.c index bea132e3b652..6c557a3d2d4e 100644 --- a/src/decode-teredo.c +++ b/src/decode-teredo.c @@ -96,7 +96,7 @@ int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, PKT_SET_SRC(tp, PKT_SRC_DECODER_TEREDO); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); - SCPerfCounterIncr(dtv->counter_teredo, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_teredo, tv->perf_private_ctx); return TM_ECODE_OK; } } diff --git a/src/decode-udp.c b/src/decode-udp.c index 5b83768f9e6f..dbbe8cae86d7 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -72,7 +72,7 @@ static int DecodeUDPPacket(ThreadVars *t, Packet *p, uint8_t *pkt, uint16_t len) int DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_udp, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_udp, tv->perf_private_ctx); if (unlikely(DecodeUDPPacket(tv, p,pkt,len) < 0)) { p->udph = NULL; diff --git a/src/decode-vlan.c b/src/decode-vlan.c index d84262e606c8..60b463c24d72 100644 --- a/src/decode-vlan.c +++ b/src/decode-vlan.c @@ -61,9 +61,9 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u uint32_t proto; if (p->vlan_idx == 0) - SCPerfCounterIncr(dtv->counter_vlan, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_vlan, tv->perf_private_ctx); else if (p->vlan_idx == 1) - SCPerfCounterIncr(dtv->counter_vlan_qinq, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_vlan_qinq, tv->perf_private_ctx); if(len < VLAN_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL); diff --git a/src/decode.c b/src/decode.c index 4d656691c5da..b4b48281422a 100644 --- a/src/decode.c +++ b/src/decode.c @@ -106,7 +106,7 @@ void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { if (p->flags & PKT_IS_INVALID) - SCPerfCounterIncr(dtv->counter_invalid, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_invalid, tv->perf_private_ctx); #ifdef __SC_CUDA_SUPPORT__ if (dtv->cuda_vars.mpm_is_cuda) diff --git a/src/defrag.c b/src/defrag.c index f005ade7de37..b170afcfc924 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -772,7 +772,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, r = Defrag4Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { SCPerfCounterIncr(dtv->counter_defrag_ipv4_reassembled, - tv->sc_perf_pca); + tv->perf_private_ctx); if (pq && DecodeIPV4(tv, dtv, r, (void *)r->ip4h, IPV4_GET_IPLEN(r), pq) != TM_ECODE_OK) { TmqhOutputPacketpool(tv, r); @@ -785,7 +785,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, r = Defrag6Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { SCPerfCounterIncr(dtv->counter_defrag_ipv6_reassembled, - tv->sc_perf_pca); + tv->perf_private_ctx); if (pq && DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h, IPV6_GET_PLEN(r) + IPV6_HEADER_LEN, pq) != TM_ECODE_OK) { @@ -926,11 +926,11 @@ Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, PacketQueue *pq) if (tv != NULL && dtv != NULL) { if (af == AF_INET) { SCPerfCounterIncr(dtv->counter_defrag_ipv4_fragments, - tv->sc_perf_pca); + tv->perf_private_ctx); } else if (af == AF_INET6) { SCPerfCounterIncr(dtv->counter_defrag_ipv6_fragments, - tv->sc_perf_pca); + tv->perf_private_ctx); } } diff --git a/src/detect.c b/src/detect.c index 6ca2b30bdd71..b55d4456dcb5 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1437,13 +1437,13 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); #ifdef PROFILING if (th_v) { - SCPerfCounterAddUI64(det_ctx->counter_mpm_list, th_v->sc_perf_pca, + SCPerfCounterAddUI64(det_ctx->counter_mpm_list, th_v->perf_private_ctx, (uint64_t)det_ctx->pmq.rule_id_array_cnt); - SCPerfCounterAddUI64(det_ctx->counter_nonmpm_list, th_v->sc_perf_pca, + SCPerfCounterAddUI64(det_ctx->counter_nonmpm_list, th_v->perf_private_ctx, (uint64_t)det_ctx->sgh->non_mpm_store_cnt); /* non mpm sigs after mask prefilter */ SCPerfCounterAddUI64(det_ctx->counter_fnonmpm_list, - th_v->sc_perf_pca, (uint64_t)det_ctx->non_mpm_id_cnt); + th_v->perf_private_ctx, (uint64_t)det_ctx->non_mpm_id_cnt); } #endif @@ -1457,7 +1457,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SigIntId match_cnt = det_ctx->match_array_cnt; #ifdef PROFILING if (th_v) { - SCPerfCounterAddUI64(det_ctx->counter_match_list, th_v->sc_perf_pca, + SCPerfCounterAddUI64(det_ctx->counter_match_list, th_v->perf_private_ctx, (uint64_t)match_cnt); } #endif @@ -1790,7 +1790,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_START(p, PROF_DETECT_ALERT); PacketAlertFinalize(de_ctx, det_ctx, p); if (p->alerts.cnt > 0) { - SCPerfCounterAddUI64(det_ctx->counter_alerts, det_ctx->tv->sc_perf_pca, (uint64_t)p->alerts.cnt); + SCPerfCounterAddUI64(det_ctx->counter_alerts, det_ctx->tv->perf_private_ctx, (uint64_t)p->alerts.cnt); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_ALERT); @@ -11263,26 +11263,26 @@ static int SigTestDetectAlertCounter(void) DetectEngineThreadCtxInit(&tv, de_ctx, (void *)&det_ctx); /* init counters */ - tv.sc_perf_pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); SCPerfAddToClubbedTMTable((tv.thread_group_name != NULL) ? tv.thread_group_name : tv.name, &tv.perf_public_ctx); p = UTHBuildPacket((uint8_t *)"boo", strlen("boo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result = (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 1); + result = (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.perf_private_ctx) == 1); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 2); + result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.perf_private_ctx) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"roo", strlen("roo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 2); + result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.perf_private_ctx) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"laboosa", strlen("laboosa"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 3); + result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.perf_private_ctx) == 3); UTHFreePackets(&p, 1); end: diff --git a/src/flow-manager.c b/src/flow-manager.c index 8283a43e2ed7..2587c9fd2e79 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -605,7 +605,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) SCLogDebug("Flow emergency mode entered..."); - SCPerfCounterIncr(ftd->flow_emerg_mode_enter, th_v->sc_perf_pca); + SCPerfCounterIncr(ftd->flow_emerg_mode_enter, th_v->perf_private_ctx); } } @@ -635,24 +635,24 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) IPPairTimeoutHash(&ts); } /* - SCPerfCounterAddUI64(flow_mgr_host_prune, th_v->sc_perf_pca, (uint64_t)hosts_pruned); + SCPerfCounterAddUI64(flow_mgr_host_prune, th_v->perf_private_ctx, (uint64_t)hosts_pruned); uint32_t hosts_active = HostGetActiveCount(); - SCPerfCounterSetUI64(flow_mgr_host_active, th_v->sc_perf_pca, (uint64_t)hosts_active); + SCPerfCounterSetUI64(flow_mgr_host_active, th_v->perf_private_ctx, (uint64_t)hosts_active); uint32_t hosts_spare = HostGetSpareCount(); - SCPerfCounterSetUI64(flow_mgr_host_spare, th_v->sc_perf_pca, (uint64_t)hosts_spare); + SCPerfCounterSetUI64(flow_mgr_host_spare, th_v->perf_private_ctx, (uint64_t)hosts_spare); */ - SCPerfCounterAddUI64(ftd->flow_mgr_cnt_clo, th_v->sc_perf_pca, (uint64_t)counters.clo); - SCPerfCounterAddUI64(ftd->flow_mgr_cnt_new, th_v->sc_perf_pca, (uint64_t)counters.new); - SCPerfCounterAddUI64(ftd->flow_mgr_cnt_est, th_v->sc_perf_pca, (uint64_t)counters.est); + SCPerfCounterAddUI64(ftd->flow_mgr_cnt_clo, th_v->perf_private_ctx, (uint64_t)counters.clo); + SCPerfCounterAddUI64(ftd->flow_mgr_cnt_new, th_v->perf_private_ctx, (uint64_t)counters.new); + SCPerfCounterAddUI64(ftd->flow_mgr_cnt_est, th_v->perf_private_ctx, (uint64_t)counters.est); long long unsigned int flow_memuse = SC_ATOMIC_GET(flow_memuse); - SCPerfCounterSetUI64(ftd->flow_mgr_memuse, th_v->sc_perf_pca, (uint64_t)flow_memuse); - SCPerfCounterAddUI64(ftd->flow_tcp_reuse, th_v->sc_perf_pca, (uint64_t)counters.tcp_reuse); + SCPerfCounterSetUI64(ftd->flow_mgr_memuse, th_v->perf_private_ctx, (uint64_t)flow_memuse); + SCPerfCounterAddUI64(ftd->flow_tcp_reuse, th_v->perf_private_ctx, (uint64_t)counters.tcp_reuse); uint32_t len = 0; FQLOCK_LOCK(&flow_spare_q); len = flow_spare_q.len; FQLOCK_UNLOCK(&flow_spare_q); - SCPerfCounterSetUI64(ftd->flow_mgr_spare, th_v->sc_perf_pca, (uint64_t)len); + SCPerfCounterSetUI64(ftd->flow_mgr_spare, th_v->perf_private_ctx, (uint64_t)len); /* Don't fear, FlowManagerThread is here... * clear emergency bit if we have at least xx flows pruned. */ @@ -676,7 +676,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) "%% flows at the queue", (uintmax_t)ts.tv_sec, (uintmax_t)ts.tv_usec, len * 100 / flow_config.prealloc); - SCPerfCounterIncr(ftd->flow_emerg_mode_over, th_v->sc_perf_pca); + SCPerfCounterIncr(ftd->flow_emerg_mode_over, th_v->perf_private_ctx); } else { flow_update_delay_sec = FLOW_EMERG_MODE_UPDATE_DELAY_SEC; flow_update_delay_nsec = FLOW_EMERG_MODE_UPDATE_DELAY_NSEC; diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 718cdbf65456..29d20df20598 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -511,8 +511,8 @@ static inline void AFPDumpCounters(AFPThreadVars *ptv) SCLogDebug("(%s) Kernel: Packets %" PRIu32 ", dropped %" PRIu32 "", ptv->tv->name, kstats.tp_packets, kstats.tp_drops); - SCPerfCounterAddUI64(ptv->capture_kernel_packets, ptv->tv->sc_perf_pca, kstats.tp_packets); - SCPerfCounterAddUI64(ptv->capture_kernel_drops, ptv->tv->sc_perf_pca, kstats.tp_drops); + SCPerfCounterAddUI64(ptv->capture_kernel_packets, ptv->tv->perf_private_ctx, kstats.tp_packets); + SCPerfCounterAddUI64(ptv->capture_kernel_drops, ptv->tv->perf_private_ctx, kstats.tp_drops); (void) SC_ATOMIC_ADD(ptv->livedev->drop, (uint64_t) kstats.tp_drops); (void) SC_ATOMIC_ADD(ptv->livedev->pkts, (uint64_t) kstats.tp_packets); } @@ -1805,8 +1805,8 @@ void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) AFPDumpCounters(ptv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, tv->sc_perf_pca), - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, tv->sc_perf_pca)); + (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, tv->perf_private_ctx), + (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, tv->perf_private_ctx)); #endif SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); @@ -1856,22 +1856,22 @@ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); +// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); #if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, + SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { - SCPerfCounterIncr(dtv->counter_vlan, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_vlan, tv->perf_private_ctx); } /* call the decoder */ diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index a68910c35505..dbf6a79a5076 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -444,7 +444,7 @@ ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) break; case TYPE_ETH: if (dr->lctr) { - SCPerfCounterAddUI64(ewtn->drops, ewtn->tv->sc_perf_pca, + SCPerfCounterAddUI64(ewtn->drops, ewtn->tv->perf_private_ctx, ntohs(dr->lctr)); } break; @@ -538,7 +538,7 @@ ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) p->ts.tv_sec++; } - SCPerfCounterIncr(ewtn->packets, ewtn->tv->sc_perf_pca); + SCPerfCounterIncr(ewtn->packets, ewtn->tv->perf_private_ctx); ewtn->bytes += wlen; if (TmThreadsSlotProcessPkt(ewtn->tv, ewtn->slot, p) != TM_ECODE_OK) { @@ -561,16 +561,16 @@ ReceiveErfDagThreadExitStats(ThreadVars *tv, void *data) ErfDagThreadVars *ewtn = (ErfDagThreadVars *)data; (void)SC_ATOMIC_SET(ewtn->livedev->pkts, - (uint64_t)SCPerfGetLocalCounterValue(ewtn->packets, tv->sc_perf_pca)); + (uint64_t)SCPerfGetLocalCounterValue(ewtn->packets, tv->perf_private_ctx)); (void)SC_ATOMIC_SET(ewtn->livedev->drop, - (uint64_t)SCPerfGetLocalCounterValue(ewtn->drops, tv->sc_perf_pca)); + (uint64_t)SCPerfGetLocalCounterValue(ewtn->drops, tv->perf_private_ctx)); SCLogInfo("Stream: %d; Bytes: %"PRIu64"; Packets: %"PRIu64 "; Drops: %"PRIu64, ewtn->dagstream, ewtn->bytes, - (uint64_t)SCPerfGetLocalCounterValue(ewtn->packets, tv->sc_perf_pca), - (uint64_t)SCPerfGetLocalCounterValue(ewtn->drops, tv->sc_perf_pca)); + (uint64_t)SCPerfGetLocalCounterValue(ewtn->packets, tv->perf_private_ctx), + (uint64_t)SCPerfGetLocalCounterValue(ewtn->drops, tv->perf_private_ctx)); } /** @@ -624,19 +624,19 @@ DecodeErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); +// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); #if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, + SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); /* call the decoder */ diff --git a/src/source-erf-file.c b/src/source-erf-file.c index 6825e3fc3f5c..3bd23cd8ab0b 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -284,18 +284,18 @@ DecodeErfFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueu return TM_ECODE_OK; /* Update counters. */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); +// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); #if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, + SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-ipfw.c b/src/source-ipfw.c index 53bb03f2891e..e1cc7aaff2b9 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -452,10 +452,10 @@ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); /* Process IP packets */ if (IPV4_GET_RAW_VER(ip4h) == 4) { diff --git a/src/source-mpipe.c b/src/source-mpipe.c index 1eb30f01542b..3444d2cdec6a 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -383,7 +383,7 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) } if (unlikely(n > max_queued)) { SCPerfCounterSetUI64(ptv->max_mpipe_depth, - tv->sc_perf_pca, + tv->perf_private_ctx, (uint64_t)n); max_queued = n; } @@ -400,10 +400,10 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) /* Buffer Error - No buffer available, so mPipe * dropped the packet. */ SCPerfCounterIncr(XlateStack(ptv, idesc->stack_idx), - tv->sc_perf_pca); + tv->perf_private_ctx); } else { /* Bad packet. CRC error */ - SCPerfCounterIncr(ptv->mpipe_drop, tv->sc_perf_pca); + SCPerfCounterIncr(ptv->mpipe_drop, tv->perf_private_ctx); gxio_mpipe_iqueue_drop(iqueue, idesc); } gxio_mpipe_iqueue_release(iqueue, idesc); @@ -1063,13 +1063,13 @@ TmEcode DecodeMpipe(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); +// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); /* call the decoder */ DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-napatech.c b/src/source-napatech.c index 6c577fecc2a1..eda65a5fa801 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -357,11 +357,11 @@ TmEcode NapatechDecode(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); +// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); switch (p->datalink) { case LINKTYPE_ETHERNET: diff --git a/src/source-netmap.c b/src/source-netmap.c index 8e36d284d280..3c41f2a2cb84 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -483,8 +483,8 @@ static int NetmapClose(NetmapDevice *dev) */ static inline void NetmapDumpCounters(NetmapThreadVars *ntv) { - SCPerfCounterAddUI64(ntv->capture_kernel_packets, ntv->tv->sc_perf_pca, ntv->pkts); - SCPerfCounterAddUI64(ntv->capture_kernel_drops, ntv->tv->sc_perf_pca, ntv->drops); + SCPerfCounterAddUI64(ntv->capture_kernel_packets, ntv->tv->perf_private_ctx, ntv->pkts); + SCPerfCounterAddUI64(ntv->capture_kernel_drops, ntv->tv->perf_private_ctx, ntv->drops); (void) SC_ATOMIC_ADD(ntv->livedev->drop, ntv->drops); (void) SC_ATOMIC_ADD(ntv->livedev->pkts, ntv->pkts); ntv->drops = 0; @@ -851,8 +851,8 @@ static void ReceiveNetmapThreadExitStats(ThreadVars *tv, void *data) NetmapDumpCounters(ntv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 ", bytes %" PRIu64 "", tv->name, - (uint64_t) SCPerfGetLocalCounterValue(ntv->capture_kernel_packets, tv->sc_perf_pca), - (uint64_t) SCPerfGetLocalCounterValue(ntv->capture_kernel_drops, tv->sc_perf_pca), + (uint64_t) SCPerfGetLocalCounterValue(ntv->capture_kernel_packets, tv->perf_private_ctx), + (uint64_t) SCPerfGetLocalCounterValue(ntv->capture_kernel_drops, tv->perf_private_ctx), ntv->bytes); } @@ -934,10 +934,10 @@ static TmEcode DecodeNetmap(ThreadVars *tv, Packet *p, void *data, PacketQueue * SCReturnInt(TM_ECODE_OK); /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-nflog.c b/src/source-nflog.c index f7a36fa16af0..f04fb5abadd7 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -503,10 +503,10 @@ TmEcode DecodeNFLOG(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); diff --git a/src/source-nfq.c b/src/source-nfq.c index 5014d343d7d7..b1c6852de1f2 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -1223,13 +1223,13 @@ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet if (p->flags & PKT_PSEUDO_STREAM_END) return TM_ECODE_OK; - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); #if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, + SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0); #endif diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index a9d55659e257..453d9cc07cb9 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -401,17 +401,17 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); +// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); #if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, + SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); double curr_ts = p->ts.tv_sec + p->ts.tv_usec / 1000.0; if (curr_ts < prev_signaled_ts || (curr_ts - prev_signaled_ts) > 60.0) { diff --git a/src/source-pcap.c b/src/source-pcap.c index 634cc8117cbc..6e53b1b45d4a 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -155,10 +155,10 @@ static inline void PcapDumpCounters(PcapThreadVars *ptv) { struct pcap_stat pcap_s; if (likely((pcap_stats(ptv->pcap_handle, &pcap_s) >= 0))) { - SCPerfCounterSetUI64(ptv->capture_kernel_packets, ptv->tv->sc_perf_pca, pcap_s.ps_recv); - SCPerfCounterSetUI64(ptv->capture_kernel_drops, ptv->tv->sc_perf_pca, pcap_s.ps_drop); + SCPerfCounterSetUI64(ptv->capture_kernel_packets, ptv->tv->perf_private_ctx, pcap_s.ps_recv); + SCPerfCounterSetUI64(ptv->capture_kernel_drops, ptv->tv->perf_private_ctx, pcap_s.ps_drop); (void) SC_ATOMIC_SET(ptv->livedev->drop, pcap_s.ps_drop); - SCPerfCounterSetUI64(ptv->capture_kernel_ifdrops, ptv->tv->sc_perf_pca, pcap_s.ps_ifdrop); + SCPerfCounterSetUI64(ptv->capture_kernel_ifdrops, ptv->tv->perf_private_ctx, pcap_s.ps_ifdrop); } } @@ -716,18 +716,18 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); +// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); #if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, + SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); /* call the decoder */ switch(p->datalink) { diff --git a/src/source-pfring.c b/src/source-pfring.c index 6f483ff741d4..eb4df877abe0 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -199,13 +199,13 @@ static inline void PfringDumpCounters(PfringThreadVars *ptv) * the newly seen packets and drops for this thread and add it * to the interface counter */ uint64_t th_pkts = SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, - ptv->tv->sc_perf_pca); + ptv->tv->perf_private_ctx); uint64_t th_drops = SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, - ptv->tv->sc_perf_pca); + ptv->tv->perf_private_ctx); SC_ATOMIC_ADD(ptv->livedev->pkts, pfring_s.recv - th_pkts); SC_ATOMIC_ADD(ptv->livedev->drop, pfring_s.drop - th_drops); - SCPerfCounterSetUI64(ptv->capture_kernel_packets, ptv->tv->sc_perf_pca, pfring_s.recv); - SCPerfCounterSetUI64(ptv->capture_kernel_drops, ptv->tv->sc_perf_pca, pfring_s.drop); + SCPerfCounterSetUI64(ptv->capture_kernel_packets, ptv->tv->perf_private_ctx, pfring_s.recv); + SCPerfCounterSetUI64(ptv->capture_kernel_drops, ptv->tv->perf_private_ctx, pfring_s.drop); } } @@ -554,8 +554,8 @@ void ReceivePfringThreadExitStats(ThreadVars *tv, void *data) PfringDumpCounters(ptv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, tv->sc_perf_pca), - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, tv->sc_perf_pca)); + (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, tv->perf_private_ctx), + (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, tv->perf_private_ctx)); SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); } @@ -608,22 +608,22 @@ TmEcode DecodePfring(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pac return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); +// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); #if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, + SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { - SCPerfCounterIncr(dtv->counter_vlan, tv->sc_perf_pca); + SCPerfCounterIncr(dtv->counter_vlan, tv->perf_private_ctx); } DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index b53be3a4f5e0..9bbf331abe56 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -139,7 +139,7 @@ void StreamTcpReassembleMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *rt { uint64_t smemuse = SC_ATOMIC_GET(ra_memuse); if (tv != NULL && rtv != NULL) - SCPerfCounterSetUI64(rtv->counter_tcp_reass_memuse, tv->sc_perf_pca, smemuse); + SCPerfCounterSetUI64(rtv->counter_tcp_reass_memuse, tv->perf_private_ctx, smemuse); return; } @@ -1905,7 +1905,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { /* increment stream depth counter */ - SCPerfCounterIncr(ra_ctx->counter_tcp_stream_depth, tv->sc_perf_pca); + SCPerfCounterIncr(ra_ctx->counter_tcp_stream_depth, tv->perf_private_ctx); stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY; SCLogDebug("ssn %p: reassembly depth reached, " @@ -2606,7 +2606,7 @@ int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, stream->flags |= STREAMTCP_STREAM_FLAG_GAP; StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); + SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->perf_private_ctx); #ifdef DEBUG dbg_app_layer_gap++; #endif @@ -2952,7 +2952,7 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, stream->flags |= STREAMTCP_STREAM_FLAG_GAP; StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); + SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->perf_private_ctx); #ifdef DEBUG dbg_app_layer_gap++; #endif @@ -3596,7 +3596,7 @@ TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, segment_pool[idx]->allocated); /* Increment the counter to show that we are not able to serve the segment request due to memcap limit */ - SCPerfCounterIncr(ra_ctx->counter_tcp_segment_memcap, tv->sc_perf_pca); + SCPerfCounterIncr(ra_ctx->counter_tcp_segment_memcap, tv->perf_private_ctx); } else { seg->flags = stream_config.segment_init_flags; seg->next = NULL; diff --git a/src/stream-tcp.c b/src/stream-tcp.c index ec427bd5e31c..c48d856da7e1 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -147,7 +147,7 @@ void StreamTcpDecrMemuse(uint64_t size) void StreamTcpMemuseCounter(ThreadVars *tv, StreamTcpThread *stt) { uint64_t memusecopy = SC_ATOMIC_GET(st_memuse); - SCPerfCounterSetUI64(stt->counter_tcp_memuse, tv->sc_perf_pca, memusecopy); + SCPerfCounterSetUI64(stt->counter_tcp_memuse, tv->perf_private_ctx, memusecopy); return; } @@ -843,10 +843,10 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->perf_private_ctx); return -1; } - SCPerfCounterIncr(stt->counter_tcp_sessions, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_sessions, tv->perf_private_ctx); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV); @@ -924,11 +924,11 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->perf_private_ctx); return -1; } - SCPerfCounterIncr(stt->counter_tcp_sessions, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_sessions, tv->perf_private_ctx); } /* set the state */ @@ -977,10 +977,10 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->perf_private_ctx); return -1; } - SCPerfCounterIncr(stt->counter_tcp_sessions, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_sessions, tv->perf_private_ctx); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); @@ -4460,12 +4460,12 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, /* update counters */ if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { - SCPerfCounterIncr(stt->counter_tcp_synack, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_synack, tv->perf_private_ctx); } else if (p->tcph->th_flags & (TH_SYN)) { - SCPerfCounterIncr(stt->counter_tcp_syn, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_syn, tv->perf_private_ctx); } if (p->tcph->th_flags & (TH_RST)) { - SCPerfCounterIncr(stt->counter_tcp_rst, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_rst, tv->perf_private_ctx); } /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */ @@ -5019,13 +5019,13 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; if (p->flow == NULL) { - SCPerfCounterIncr(stt->counter_tcp_no_flow, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_no_flow, tv->perf_private_ctx); return TM_ECODE_OK; } if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) { if (StreamTcpValidateChecksum(p) == 0) { - SCPerfCounterIncr(stt->counter_tcp_invalid_checksum, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_invalid_checksum, tv->perf_private_ctx); return TM_ECODE_OK; } } else { @@ -5896,7 +5896,7 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread Packet *np = StreamTcpPseudoSetup(p, GET_PKT_DATA(p), GET_PKT_LEN(p)); if (np == NULL) { SCLogDebug("The packet received from packet allocation is NULL"); - SCPerfCounterIncr(stt->counter_tcp_pseudo_failed, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_pseudo_failed, tv->perf_private_ctx); SCReturn; } PKT_SET_SRC(np, PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO); @@ -5931,7 +5931,7 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread PacketEnqueue(pq, np); - SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); + SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->perf_private_ctx); SCReturn; } diff --git a/src/threadvars.h b/src/threadvars.h index d6d8265dc877..0148359133af 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -107,7 +107,7 @@ typedef struct ThreadVars_ { SCPerfPublicContext perf_public_ctx; /** private counter store: counter updates modify this */ - SCPerfPrivateContext *sc_perf_pca; + SCPerfPrivateContext *perf_private_ctx; SCCtrlMutex *ctrl_mutex; SCCtrlCondT *ctrl_cond; diff --git a/src/tm-threads.c b/src/tm-threads.c index dfe0bcc59b5f..50ec19fbf06d 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -322,7 +322,7 @@ void *TmThreadsSlotPktAcqLoop(void *td) } } - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->perf_public_ctx); + tv->perf_private_ctx = SCPerfGetAllCountersArray(&tv->perf_public_ctx); SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->perf_public_ctx); @@ -455,7 +455,7 @@ void *TmThreadsSlotVar(void *td) } } - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->perf_public_ctx); + tv->perf_private_ctx = SCPerfGetAllCountersArray(&tv->perf_public_ctx); SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->perf_public_ctx); @@ -597,7 +597,7 @@ static void *TmThreadsManagement(void *td) memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->perf_public_ctx); + tv->perf_private_ctx = SCPerfGetAllCountersArray(&tv->perf_public_ctx); SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->perf_public_ctx); diff --git a/src/unix-manager.c b/src/unix-manager.c index dd2d2d91d294..ce6ae64fe053 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -868,7 +868,7 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) /* set the thread name */ SCLogDebug("%s started...", th_v->name); - th_v->sc_perf_pca = SCPerfGetAllCountersArray(&th_v->perf_public_ctx); + th_v->perf_private_ctx = SCPerfGetAllCountersArray(&th_v->perf_public_ctx); SCPerfAddToClubbedTMTable(th_v->name, &th_v->perf_public_ctx); if (UnixNew(&command) == 0) { From e9b067c1ebec3e30efbe99d1fcacb2c669b93ccd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 23 May 2015 00:44:45 +0200 Subject: [PATCH 0486/2553] counters: make increment call take threadvars This hides the implementation from the caller. --- src/app-layer-htp-mem.c | 4 +-- src/app-layer.c | 9 +++---- src/counters.c | 51 ++++++++++++++++++++----------------- src/counters.h | 6 ++--- src/decode-ethernet.c | 2 +- src/decode-gre.c | 2 +- src/decode-icmpv4.c | 2 +- src/decode-icmpv6.c | 2 +- src/decode-ipv4.c | 2 +- src/decode-ipv6.c | 6 ++--- src/decode-mpls.c | 2 +- src/decode-null.c | 2 +- src/decode-ppp.c | 2 +- src/decode-pppoe.c | 4 +-- src/decode-raw.c | 2 +- src/decode-sctp.c | 2 +- src/decode-sll.c | 2 +- src/decode-tcp.c | 2 +- src/decode-teredo.c | 2 +- src/decode-udp.c | 2 +- src/decode-vlan.c | 4 +-- src/decode.c | 2 +- src/defrag.c | 12 +++------ src/detect.c | 12 ++++----- src/flow-manager.c | 22 ++++++++-------- src/source-af-packet.c | 16 ++++++------ src/source-erf-dag.c | 17 +++++-------- src/source-erf-file.c | 10 ++++---- src/source-ipfw.c | 8 +++--- src/source-mpipe.c | 18 ++++++------- src/source-napatech.c | 10 ++++---- src/source-netmap.c | 12 ++++----- src/source-nflog.c | 8 +++--- src/source-nfq.c | 8 +++--- src/source-pcap-file.c | 10 ++++---- src/source-pcap.c | 16 ++++++------ src/source-pfring.c | 16 ++++++------ src/stream-tcp-reassemble.c | 10 ++++---- src/stream-tcp.c | 28 ++++++++++---------- 39 files changed, 170 insertions(+), 177 deletions(-) diff --git a/src/app-layer-htp-mem.c b/src/app-layer-htp-mem.c index f676af0617bd..18aa223a6bf8 100644 --- a/src/app-layer-htp-mem.c +++ b/src/app-layer-htp-mem.c @@ -81,9 +81,9 @@ void HTPDecrMemuse(uint64_t size) void HTPMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *trt) { uint64_t tmpval = SC_ATOMIC_GET(htp_memuse); - SCPerfCounterSetUI64(trt->counter_htp_memuse, tv->perf_private_ctx, tmpval); + SCPerfCounterSetUI64(tv, trt->counter_htp_memuse, tmpval); tmpval = SC_ATOMIC_GET(htp_memcap); - SCPerfCounterSetUI64(trt->counter_htp_memcap, tv->perf_private_ctx, tmpval); + SCPerfCounterSetUI64(tv, trt->counter_htp_memcap, tmpval); return; } /** diff --git a/src/app-layer.c b/src/app-layer.c index 711bec3a0587..c14e5f4a508a 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -78,12 +78,9 @@ static void DNSUpdateCounters(ThreadVars *tv, AppLayerThreadCtx *app_tctx) DNSMemcapGetCounters(&memuse, &memcap_state, &memcap_global); - SCPerfCounterSetUI64(app_tctx->counter_dns_memuse, - tv->perf_private_ctx, memuse); - SCPerfCounterSetUI64(app_tctx->counter_dns_memcap_state, - tv->perf_private_ctx, memcap_state); - SCPerfCounterSetUI64(app_tctx->counter_dns_memcap_global, - tv->perf_private_ctx, memcap_global); + SCPerfCounterSetUI64(tv, app_tctx->counter_dns_memuse, memuse); + SCPerfCounterSetUI64(tv, app_tctx->counter_dns_memcap_state, memcap_state); + SCPerfCounterSetUI64(tv, app_tctx->counter_dns_memcap_global, memcap_global); } /***** L7 layer dispatchers *****/ diff --git a/src/counters.c b/src/counters.c index 3ccbccae9615..184852f78b80 100644 --- a/src/counters.c +++ b/src/counters.c @@ -79,8 +79,10 @@ void SCPerfOutputCounters(ThreadVars *tv) * \param pca Counter array that holds the local counter for this TM * \param x Value to add to this local counter */ -void SCPerfCounterAddUI64(uint16_t id, SCPerfPrivateContext *pca, uint64_t x) +void SCPerfCounterAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) { + SCPerfPrivateContext *pca = tv->perf_private_ctx; + if (!pca) { SCLogDebug("counterarray is NULL"); return; @@ -99,8 +101,10 @@ void SCPerfCounterAddUI64(uint16_t id, SCPerfPrivateContext *pca, uint64_t x) * \param id Index of the counter in the counter array * \param pca Counter array that holds the local counters for this TM */ -void SCPerfCounterIncr(uint16_t id, SCPerfPrivateContext *pca) +void SCPerfCounterIncr(ThreadVars *tv, uint16_t id) { + SCPerfPrivateContext *pca = tv->perf_private_ctx; + if (pca == NULL) { SCLogDebug("counterarray is NULL"); return; @@ -122,9 +126,10 @@ void SCPerfCounterIncr(uint16_t id, SCPerfPrivateContext *pca) * \param pca Pointer to the SCPerfPrivateContext * \param x The value to set for the counter */ -void SCPerfCounterSetUI64(uint16_t id, SCPerfPrivateContext *pca, - uint64_t x) +void SCPerfCounterSetUI64(ThreadVars *tv, uint16_t id, uint64_t x) { + SCPerfPrivateContext *pca = tv->perf_private_ctx; + if (!pca) { SCLogDebug("counterarray is NULL"); return; @@ -1435,10 +1440,10 @@ static int SCPerfTestCntArraySize07() SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + pca = tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); - SCPerfCounterIncr(1, pca); - SCPerfCounterIncr(2, pca); + SCPerfCounterIncr(&tv, 1); + SCPerfCounterIncr(&tv, 2); result = pca->size; @@ -1460,10 +1465,10 @@ static int SCPerfTestUpdateCounter08() id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + pca = tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); - SCPerfCounterIncr(id, pca); - SCPerfCounterAddUI64(id, pca, 100); + SCPerfCounterIncr(&tv, id); + SCPerfCounterAddUI64(&tv, id, 100); result = pca->head[id].ui64_cnt; @@ -1493,10 +1498,10 @@ static int SCPerfTestUpdateCounter09() id2 = SCPerfRegisterCounter("t5", "c5", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + pca = tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); - SCPerfCounterIncr(id2, pca); - SCPerfCounterAddUI64(id2, pca, 100); + SCPerfCounterIncr(&tv, id2); + SCPerfCounterAddUI64(&tv, id2, 100); result = (pca->head[id1].ui64_cnt == 0) && (pca->head[id2].ui64_cnt == 101); @@ -1523,12 +1528,12 @@ static int SCPerfTestUpdateGlobalCounter10() id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + pca = tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); - SCPerfCounterIncr(id1, pca); - SCPerfCounterAddUI64(id2, pca, 100); - SCPerfCounterIncr(id3, pca); - SCPerfCounterAddUI64(id3, pca, 100); + SCPerfCounterIncr(&tv, id1); + SCPerfCounterAddUI64(&tv, id2, 100); + SCPerfCounterIncr(&tv, id3); + SCPerfCounterAddUI64(&tv, id3, 100); SCPerfUpdateCounterArray(pca, &tv.perf_public_ctx); @@ -1561,12 +1566,12 @@ static int SCPerfTestCounterValues11() id4 = SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + pca = tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); - SCPerfCounterIncr(id1, pca); - SCPerfCounterAddUI64(id2, pca, 256); - SCPerfCounterAddUI64(id3, pca, 257); - SCPerfCounterAddUI64(id4, pca, 16843024); + SCPerfCounterIncr(&tv, id1); + SCPerfCounterAddUI64(&tv, id2, 256); + SCPerfCounterAddUI64(&tv, id3, 257); + SCPerfCounterAddUI64(&tv, id4, 16843024); SCPerfUpdateCounterArray(pca, &tv.perf_public_ctx); diff --git a/src/counters.h b/src/counters.h index 3eff9ef6e632..8c0f62868495 100644 --- a/src/counters.h +++ b/src/counters.h @@ -171,13 +171,13 @@ void SCPerfReleaseResources(void); void SCPerfReleasePerfCounterS(SCPerfCounter *); void SCPerfReleasePCA(SCPerfPrivateContext *); -void SCPerfCounterSetUI64(uint16_t, SCPerfPrivateContext *, uint64_t); -void SCPerfCounterIncr(uint16_t, SCPerfPrivateContext *); +void SCPerfCounterSetUI64(struct ThreadVars_ *, uint16_t, uint64_t); +void SCPerfCounterIncr(struct ThreadVars_ *, uint16_t); void SCPerfRegisterTests(void); /* functions used to update local counter values */ -void SCPerfCounterAddUI64(uint16_t, SCPerfPrivateContext *, uint64_t); +void SCPerfCounterAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); #define SCPerfSyncCounters(tv) \ SCPerfUpdateCounterArray((tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ diff --git a/src/decode-ethernet.c b/src/decode-ethernet.c index 32f737a7ddc5..d77b7ac3b32f 100644 --- a/src/decode-ethernet.c +++ b/src/decode-ethernet.c @@ -41,7 +41,7 @@ int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_eth, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_eth); if (unlikely(len < ETHERNET_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, ETHERNET_PKT_TOO_SMALL); diff --git a/src/decode-gre.c b/src/decode-gre.c index b686663d34cb..42459446bd14 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -48,7 +48,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui uint16_t header_len = GRE_HDR_LEN; GRESreHdr *gsre = NULL; - SCPerfCounterIncr(dtv->counter_gre, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_gre); if(len < GRE_HDR_LEN) { ENGINE_SET_INVALID_EVENT(p, GRE_PKT_TOO_SMALL); diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index a1926ec210cb..af094e4259fe 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -153,7 +153,7 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) */ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_icmpv4, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_icmpv4); if (len < ICMPV4_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, ICMPV4_PKT_TOO_SMALL); diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index a56a0db6602a..d9bc41db6569 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -168,7 +168,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { int full_hdr = 0; - SCPerfCounterIncr(dtv->counter_icmpv6, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_icmpv6); if (len < ICMPV6_HEADER_LEN) { SCLogDebug("ICMPV6_PKT_TOO_SMALL"); diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 03fd4782ab99..a0ca8c173ced 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -519,7 +519,7 @@ static int DecodeIPV4Packet(Packet *p, uint8_t *pkt, uint16_t len) int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_ipv4, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_ipv4); SCLogDebug("pkt %p len %"PRIu16"", pkt, len); diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index bb2b40269c60..12ba7705d904 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -65,7 +65,7 @@ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, u PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); - SCPerfCounterIncr(dtv->counter_ipv4inipv6, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_ipv4inipv6); return; } } @@ -92,7 +92,7 @@ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); PacketEnqueue(pq,tp); - SCPerfCounterIncr(dtv->counter_ipv6inipv6, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_ipv6inipv6); } } } else { @@ -601,7 +601,7 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u { int ret; - SCPerfCounterIncr(dtv->counter_ipv6, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_ipv6); /* do the actual decoding */ ret = DecodeIPV6Packet (tv, dtv, p, pkt, len); diff --git a/src/decode-mpls.c b/src/decode-mpls.c index e8ff0371e2d6..f8a77b5831b8 100644 --- a/src/decode-mpls.c +++ b/src/decode-mpls.c @@ -51,7 +51,7 @@ int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, int label; int event = 0; - SCPerfCounterIncr(dtv->counter_mpls, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_mpls); do { if (len < MPLS_HEADER_LEN) { diff --git a/src/decode-null.c b/src/decode-null.c index fa1738436aa9..445a33331c2e 100644 --- a/src/decode-null.c +++ b/src/decode-null.c @@ -47,7 +47,7 @@ int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_null, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_null); if (unlikely(len < HDR_SIZE)) { ENGINE_SET_INVALID_EVENT(p, LTNULL_PKT_TOO_SMALL); diff --git a/src/decode-ppp.c b/src/decode-ppp.c index 1f2c395924fc..d6ec902512c9 100644 --- a/src/decode-ppp.c +++ b/src/decode-ppp.c @@ -42,7 +42,7 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_ppp, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_ppp); if (unlikely(len < PPP_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, PPP_PKT_TOO_SMALL); diff --git a/src/decode-pppoe.c b/src/decode-pppoe.c index 1cec70076c37..565a9f5894cd 100644 --- a/src/decode-pppoe.c +++ b/src/decode-pppoe.c @@ -49,7 +49,7 @@ */ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_pppoe, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_pppoe); if (len < PPPOE_DISCOVERY_HEADER_MIN_LEN) { ENGINE_SET_INVALID_EVENT(p, PPPOE_PKT_TOO_SMALL); @@ -128,7 +128,7 @@ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8 */ int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_pppoe, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_pppoe); if (len < PPPOE_SESSION_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, PPPOE_PKT_TOO_SMALL); diff --git a/src/decode-raw.c b/src/decode-raw.c index 06eaec39c78f..dc31c944cac5 100644 --- a/src/decode-raw.c +++ b/src/decode-raw.c @@ -45,7 +45,7 @@ int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_raw, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_raw); /* If it is ipv4 or ipv6 it should at least be the size of ipv4 */ if (unlikely(len < IPV4_HEADER_LEN)) { diff --git a/src/decode-sctp.c b/src/decode-sctp.c index cc287e0d48dd..25607421256b 100644 --- a/src/decode-sctp.c +++ b/src/decode-sctp.c @@ -61,7 +61,7 @@ static int DecodeSCTPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t le int DecodeSCTP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_sctp, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_sctp); if (unlikely(DecodeSCTPPacket(tv, p,pkt,len) < 0)) { p->sctph = NULL; diff --git a/src/decode-sll.c b/src/decode-sll.c index 65c1c57db42a..0da071da9351 100644 --- a/src/decode-sll.c +++ b/src/decode-sll.c @@ -38,7 +38,7 @@ int DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_sll, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_sll); if (unlikely(len < SLL_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, SLL_PKT_TOO_SMALL); diff --git a/src/decode-tcp.c b/src/decode-tcp.c index 206669e4dc4c..ae85df48d382 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -186,7 +186,7 @@ static int DecodeTCPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t len int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_tcp, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_tcp); if (unlikely(DecodeTCPPacket(tv, p,pkt,len) < 0)) { SCLogDebug("invalid TCP packet"); diff --git a/src/decode-teredo.c b/src/decode-teredo.c index 6c557a3d2d4e..ba8cd311b37b 100644 --- a/src/decode-teredo.c +++ b/src/decode-teredo.c @@ -96,7 +96,7 @@ int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, PKT_SET_SRC(tp, PKT_SRC_DECODER_TEREDO); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); - SCPerfCounterIncr(dtv->counter_teredo, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_teredo); return TM_ECODE_OK; } } diff --git a/src/decode-udp.c b/src/decode-udp.c index dbbe8cae86d7..a5be2a43125d 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -72,7 +72,7 @@ static int DecodeUDPPacket(ThreadVars *t, Packet *p, uint8_t *pkt, uint16_t len) int DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_udp, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_udp); if (unlikely(DecodeUDPPacket(tv, p,pkt,len) < 0)) { p->udph = NULL; diff --git a/src/decode-vlan.c b/src/decode-vlan.c index 60b463c24d72..95eb3e6845d4 100644 --- a/src/decode-vlan.c +++ b/src/decode-vlan.c @@ -61,9 +61,9 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u uint32_t proto; if (p->vlan_idx == 0) - SCPerfCounterIncr(dtv->counter_vlan, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_vlan); else if (p->vlan_idx == 1) - SCPerfCounterIncr(dtv->counter_vlan_qinq, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_vlan_qinq); if(len < VLAN_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL); diff --git a/src/decode.c b/src/decode.c index b4b48281422a..f578994cdeee 100644 --- a/src/decode.c +++ b/src/decode.c @@ -106,7 +106,7 @@ void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { if (p->flags & PKT_IS_INVALID) - SCPerfCounterIncr(dtv->counter_invalid, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_invalid); #ifdef __SC_CUDA_SUPPORT__ if (dtv->cuda_vars.mpm_is_cuda) diff --git a/src/defrag.c b/src/defrag.c index b170afcfc924..0d1ab333dc7c 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -771,8 +771,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, if (tracker->af == AF_INET) { r = Defrag4Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { - SCPerfCounterIncr(dtv->counter_defrag_ipv4_reassembled, - tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_defrag_ipv4_reassembled); if (pq && DecodeIPV4(tv, dtv, r, (void *)r->ip4h, IPV4_GET_IPLEN(r), pq) != TM_ECODE_OK) { TmqhOutputPacketpool(tv, r); @@ -784,8 +783,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, else if (tracker->af == AF_INET6) { r = Defrag6Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { - SCPerfCounterIncr(dtv->counter_defrag_ipv6_reassembled, - tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_defrag_ipv6_reassembled); if (pq && DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h, IPV6_GET_PLEN(r) + IPV6_HEADER_LEN, pq) != TM_ECODE_OK) { @@ -925,12 +923,10 @@ Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, PacketQueue *pq) if (tv != NULL && dtv != NULL) { if (af == AF_INET) { - SCPerfCounterIncr(dtv->counter_defrag_ipv4_fragments, - tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_defrag_ipv4_fragments); } else if (af == AF_INET6) { - SCPerfCounterIncr(dtv->counter_defrag_ipv6_fragments, - tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_defrag_ipv6_fragments); } } diff --git a/src/detect.c b/src/detect.c index b55d4456dcb5..bca51a25c92f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1437,13 +1437,13 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); #ifdef PROFILING if (th_v) { - SCPerfCounterAddUI64(det_ctx->counter_mpm_list, th_v->perf_private_ctx, + SCPerfCounterAddUI64(th_v, det_ctx->counter_mpm_list, (uint64_t)det_ctx->pmq.rule_id_array_cnt); - SCPerfCounterAddUI64(det_ctx->counter_nonmpm_list, th_v->perf_private_ctx, + SCPerfCounterAddUI64(th_v, det_ctx->counter_nonmpm_list, (uint64_t)det_ctx->sgh->non_mpm_store_cnt); /* non mpm sigs after mask prefilter */ - SCPerfCounterAddUI64(det_ctx->counter_fnonmpm_list, - th_v->perf_private_ctx, (uint64_t)det_ctx->non_mpm_id_cnt); + SCPerfCounterAddUI64(th_v, det_ctx->counter_fnonmpm_list, + (uint64_t)det_ctx->non_mpm_id_cnt); } #endif @@ -1457,7 +1457,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SigIntId match_cnt = det_ctx->match_array_cnt; #ifdef PROFILING if (th_v) { - SCPerfCounterAddUI64(det_ctx->counter_match_list, th_v->perf_private_ctx, + SCPerfCounterAddUI64(th_v, det_ctx->counter_match_list, (uint64_t)match_cnt); } #endif @@ -1790,7 +1790,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_START(p, PROF_DETECT_ALERT); PacketAlertFinalize(de_ctx, det_ctx, p); if (p->alerts.cnt > 0) { - SCPerfCounterAddUI64(det_ctx->counter_alerts, det_ctx->tv->perf_private_ctx, (uint64_t)p->alerts.cnt); + SCPerfCounterAddUI64(th_v, det_ctx->counter_alerts, (uint64_t)p->alerts.cnt); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_ALERT); diff --git a/src/flow-manager.c b/src/flow-manager.c index 2587c9fd2e79..48dba4efbaec 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -605,7 +605,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) SCLogDebug("Flow emergency mode entered..."); - SCPerfCounterIncr(ftd->flow_emerg_mode_enter, th_v->perf_private_ctx); + SCPerfCounterIncr(th_v, ftd->flow_emerg_mode_enter); } } @@ -635,24 +635,24 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) IPPairTimeoutHash(&ts); } /* - SCPerfCounterAddUI64(flow_mgr_host_prune, th_v->perf_private_ctx, (uint64_t)hosts_pruned); + SCPerfCounterAddUI64(th_v, flow_mgr_host_prune, (uint64_t)hosts_pruned); uint32_t hosts_active = HostGetActiveCount(); - SCPerfCounterSetUI64(flow_mgr_host_active, th_v->perf_private_ctx, (uint64_t)hosts_active); + SCPerfCounterSetUI64(th_v, flow_mgr_host_active, (uint64_t)hosts_active); uint32_t hosts_spare = HostGetSpareCount(); - SCPerfCounterSetUI64(flow_mgr_host_spare, th_v->perf_private_ctx, (uint64_t)hosts_spare); + SCPerfCounterSetUI64(th_v, flow_mgr_host_spare, (uint64_t)hosts_spare); */ - SCPerfCounterAddUI64(ftd->flow_mgr_cnt_clo, th_v->perf_private_ctx, (uint64_t)counters.clo); - SCPerfCounterAddUI64(ftd->flow_mgr_cnt_new, th_v->perf_private_ctx, (uint64_t)counters.new); - SCPerfCounterAddUI64(ftd->flow_mgr_cnt_est, th_v->perf_private_ctx, (uint64_t)counters.est); + SCPerfCounterAddUI64(th_v, ftd->flow_mgr_cnt_clo, (uint64_t)counters.clo); + SCPerfCounterAddUI64(th_v, ftd->flow_mgr_cnt_new, (uint64_t)counters.new); + SCPerfCounterAddUI64(th_v, ftd->flow_mgr_cnt_est, (uint64_t)counters.est); long long unsigned int flow_memuse = SC_ATOMIC_GET(flow_memuse); - SCPerfCounterSetUI64(ftd->flow_mgr_memuse, th_v->perf_private_ctx, (uint64_t)flow_memuse); - SCPerfCounterAddUI64(ftd->flow_tcp_reuse, th_v->perf_private_ctx, (uint64_t)counters.tcp_reuse); + SCPerfCounterSetUI64(th_v, ftd->flow_mgr_memuse, (uint64_t)flow_memuse); + SCPerfCounterAddUI64(th_v, ftd->flow_tcp_reuse, (uint64_t)counters.tcp_reuse); uint32_t len = 0; FQLOCK_LOCK(&flow_spare_q); len = flow_spare_q.len; FQLOCK_UNLOCK(&flow_spare_q); - SCPerfCounterSetUI64(ftd->flow_mgr_spare, th_v->perf_private_ctx, (uint64_t)len); + SCPerfCounterSetUI64(th_v, ftd->flow_mgr_spare, (uint64_t)len); /* Don't fear, FlowManagerThread is here... * clear emergency bit if we have at least xx flows pruned. */ @@ -676,7 +676,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) "%% flows at the queue", (uintmax_t)ts.tv_sec, (uintmax_t)ts.tv_usec, len * 100 / flow_config.prealloc); - SCPerfCounterIncr(ftd->flow_emerg_mode_over, th_v->perf_private_ctx); + SCPerfCounterIncr(th_v, ftd->flow_emerg_mode_over); } else { flow_update_delay_sec = FLOW_EMERG_MODE_UPDATE_DELAY_SEC; flow_update_delay_nsec = FLOW_EMERG_MODE_UPDATE_DELAY_NSEC; diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 29d20df20598..fa384fc345c6 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -511,8 +511,8 @@ static inline void AFPDumpCounters(AFPThreadVars *ptv) SCLogDebug("(%s) Kernel: Packets %" PRIu32 ", dropped %" PRIu32 "", ptv->tv->name, kstats.tp_packets, kstats.tp_drops); - SCPerfCounterAddUI64(ptv->capture_kernel_packets, ptv->tv->perf_private_ctx, kstats.tp_packets); - SCPerfCounterAddUI64(ptv->capture_kernel_drops, ptv->tv->perf_private_ctx, kstats.tp_drops); + SCPerfCounterAddUI64(ptv->tv, ptv->capture_kernel_packets, kstats.tp_packets); + SCPerfCounterAddUI64(ptv->tv, ptv->capture_kernel_drops, kstats.tp_drops); (void) SC_ATOMIC_ADD(ptv->livedev->drop, (uint64_t) kstats.tp_drops); (void) SC_ATOMIC_ADD(ptv->livedev->pkts, (uint64_t) kstats.tp_packets); } @@ -1856,22 +1856,22 @@ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_pkts); +// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { - SCPerfCounterIncr(dtv->counter_vlan, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_vlan); } /* call the decoder */ diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index dbf6a79a5076..b73f2fd6fa9d 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -444,8 +444,7 @@ ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) break; case TYPE_ETH: if (dr->lctr) { - SCPerfCounterAddUI64(ewtn->drops, ewtn->tv->perf_private_ctx, - ntohs(dr->lctr)); + SCPerfCounterAddUI64(tv, ewtn->drops, ntohs(dr->lctr)); } break; default: @@ -538,7 +537,7 @@ ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) p->ts.tv_sec++; } - SCPerfCounterIncr(ewtn->packets, ewtn->tv->perf_private_ctx); + SCPerfCounterIncr(tv, ewtn->packets); ewtn->bytes += wlen; if (TmThreadsSlotProcessPkt(ewtn->tv, ewtn->slot, p) != TM_ECODE_OK) { @@ -624,20 +623,18 @@ DecodeErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_pkts); +// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, - GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, - GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* call the decoder */ switch(p->datalink) { diff --git a/src/source-erf-file.c b/src/source-erf-file.c index 3bd23cd8ab0b..ff39bedc2d2f 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -284,18 +284,18 @@ DecodeErfFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueu return TM_ECODE_OK; /* Update counters. */ - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_pkts); +// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-ipfw.c b/src/source-ipfw.c index e1cc7aaff2b9..8163d8387d8b 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -452,10 +452,10 @@ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterIncr(tv, dtv->counter_pkts); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* Process IP packets */ if (IPV4_GET_RAW_VER(ip4h) == 4) { diff --git a/src/source-mpipe.c b/src/source-mpipe.c index 3444d2cdec6a..f55f42184659 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -382,8 +382,7 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) __insn_prefetch(&idesc[i]); } if (unlikely(n > max_queued)) { - SCPerfCounterSetUI64(ptv->max_mpipe_depth, - tv->perf_private_ctx, + SCPerfCounterSetUI64(tv, ptv->max_mpipe_depth, (uint64_t)n); max_queued = n; } @@ -399,11 +398,10 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) if (idesc->be) { /* Buffer Error - No buffer available, so mPipe * dropped the packet. */ - SCPerfCounterIncr(XlateStack(ptv, idesc->stack_idx), - tv->perf_private_ctx); + SCPerfCounterIncr(tv, XlateStack(ptv, idesc->stack_idx)); } else { /* Bad packet. CRC error */ - SCPerfCounterIncr(ptv->mpipe_drop, tv->perf_private_ctx); + SCPerfCounterIncr(tv, ptv->mpipe_drop); gxio_mpipe_iqueue_drop(iqueue, idesc); } gxio_mpipe_iqueue_release(iqueue, idesc); @@ -1063,13 +1061,13 @@ TmEcode DecodeMpipe(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_pkts); +// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* call the decoder */ DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-napatech.c b/src/source-napatech.c index eda65a5fa801..f3430d079209 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -357,11 +357,11 @@ TmEcode NapatechDecode(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterIncr(tv, dtv->counter_pkts); +// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); switch (p->datalink) { case LINKTYPE_ETHERNET: diff --git a/src/source-netmap.c b/src/source-netmap.c index 3c41f2a2cb84..1b6b3329888a 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -483,8 +483,8 @@ static int NetmapClose(NetmapDevice *dev) */ static inline void NetmapDumpCounters(NetmapThreadVars *ntv) { - SCPerfCounterAddUI64(ntv->capture_kernel_packets, ntv->tv->perf_private_ctx, ntv->pkts); - SCPerfCounterAddUI64(ntv->capture_kernel_drops, ntv->tv->perf_private_ctx, ntv->drops); + SCPerfCounterAddUI64(ntv->tv, ntv->capture_kernel_packets, ntv->pkts); + SCPerfCounterAddUI64(ntv->tv, ntv->capture_kernel_drops, ntv->drops); (void) SC_ATOMIC_ADD(ntv->livedev->drop, ntv->drops); (void) SC_ATOMIC_ADD(ntv->livedev->pkts, ntv->pkts); ntv->drops = 0; @@ -934,10 +934,10 @@ static TmEcode DecodeNetmap(ThreadVars *tv, Packet *p, void *data, PacketQueue * SCReturnInt(TM_ECODE_OK); /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterIncr(tv, dtv->counter_pkts); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-nflog.c b/src/source-nflog.c index f04fb5abadd7..d068acbb9dff 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -503,10 +503,10 @@ TmEcode DecodeNFLOG(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterIncr(tv, dtv->counter_pkts); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); diff --git a/src/source-nfq.c b/src/source-nfq.c index b1c6852de1f2..12123b7752a7 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -1223,10 +1223,10 @@ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet if (p->flags & PKT_PSEUDO_STREAM_END) return TM_ECODE_OK; - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterIncr(tv, dtv->counter_pkts); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 453d9cc07cb9..a1b1d04d4433 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -401,17 +401,17 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_pkts); +// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); double curr_ts = p->ts.tv_sec + p->ts.tv_usec / 1000.0; if (curr_ts < prev_signaled_ts || (curr_ts - prev_signaled_ts) > 60.0) { diff --git a/src/source-pcap.c b/src/source-pcap.c index 6e53b1b45d4a..138db8496fbc 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -155,10 +155,10 @@ static inline void PcapDumpCounters(PcapThreadVars *ptv) { struct pcap_stat pcap_s; if (likely((pcap_stats(ptv->pcap_handle, &pcap_s) >= 0))) { - SCPerfCounterSetUI64(ptv->capture_kernel_packets, ptv->tv->perf_private_ctx, pcap_s.ps_recv); - SCPerfCounterSetUI64(ptv->capture_kernel_drops, ptv->tv->perf_private_ctx, pcap_s.ps_drop); + SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_packets, pcap_s.ps_recv); + SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_drops, pcap_s.ps_drop); (void) SC_ATOMIC_SET(ptv->livedev->drop, pcap_s.ps_drop); - SCPerfCounterSetUI64(ptv->capture_kernel_ifdrops, ptv->tv->perf_private_ctx, pcap_s.ps_ifdrop); + SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_ifdrops, pcap_s.ps_ifdrop); } } @@ -716,18 +716,18 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_pkts); +// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* call the decoder */ switch(p->datalink) { diff --git a/src/source-pfring.c b/src/source-pfring.c index eb4df877abe0..5708ddd8dad7 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -204,8 +204,8 @@ static inline void PfringDumpCounters(PfringThreadVars *ptv) ptv->tv->perf_private_ctx); SC_ATOMIC_ADD(ptv->livedev->pkts, pfring_s.recv - th_pkts); SC_ATOMIC_ADD(ptv->livedev->drop, pfring_s.drop - th_drops); - SCPerfCounterSetUI64(ptv->capture_kernel_packets, ptv->tv->perf_private_ctx, pfring_s.recv); - SCPerfCounterSetUI64(ptv->capture_kernel_drops, ptv->tv->perf_private_ctx, pfring_s.drop); + SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_packets, pfring_s.recv); + SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_drops, pfring_s.drop); } } @@ -608,22 +608,22 @@ TmEcode DecodePfring(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pac return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->perf_private_ctx); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_pkts); +// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->perf_private_ctx, GET_PKT_LEN(p)); + SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { - SCPerfCounterIncr(dtv->counter_vlan, tv->perf_private_ctx); + SCPerfCounterIncr(tv, dtv->counter_vlan); } DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 9bbf331abe56..20074e6807c7 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -139,7 +139,7 @@ void StreamTcpReassembleMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *rt { uint64_t smemuse = SC_ATOMIC_GET(ra_memuse); if (tv != NULL && rtv != NULL) - SCPerfCounterSetUI64(rtv->counter_tcp_reass_memuse, tv->perf_private_ctx, smemuse); + SCPerfCounterSetUI64(tv, rtv->counter_tcp_reass_memuse, smemuse); return; } @@ -1905,7 +1905,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { /* increment stream depth counter */ - SCPerfCounterIncr(ra_ctx->counter_tcp_stream_depth, tv->perf_private_ctx); + SCPerfCounterIncr(tv, ra_ctx->counter_tcp_stream_depth); stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY; SCLogDebug("ssn %p: reassembly depth reached, " @@ -2606,7 +2606,7 @@ int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, stream->flags |= STREAMTCP_STREAM_FLAG_GAP; StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->perf_private_ctx); + SCPerfCounterIncr(tv, ra_ctx->counter_tcp_reass_gap); #ifdef DEBUG dbg_app_layer_gap++; #endif @@ -2952,7 +2952,7 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, stream->flags |= STREAMTCP_STREAM_FLAG_GAP; StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->perf_private_ctx); + SCPerfCounterIncr(tv, ra_ctx->counter_tcp_reass_gap); #ifdef DEBUG dbg_app_layer_gap++; #endif @@ -3596,7 +3596,7 @@ TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, segment_pool[idx]->allocated); /* Increment the counter to show that we are not able to serve the segment request due to memcap limit */ - SCPerfCounterIncr(ra_ctx->counter_tcp_segment_memcap, tv->perf_private_ctx); + SCPerfCounterIncr(tv, ra_ctx->counter_tcp_segment_memcap); } else { seg->flags = stream_config.segment_init_flags; seg->next = NULL; diff --git a/src/stream-tcp.c b/src/stream-tcp.c index c48d856da7e1..c7d1098ed12c 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -147,7 +147,7 @@ void StreamTcpDecrMemuse(uint64_t size) void StreamTcpMemuseCounter(ThreadVars *tv, StreamTcpThread *stt) { uint64_t memusecopy = SC_ATOMIC_GET(st_memuse); - SCPerfCounterSetUI64(stt->counter_tcp_memuse, tv->perf_private_ctx, memusecopy); + SCPerfCounterSetUI64(tv, stt->counter_tcp_memuse, memusecopy); return; } @@ -843,10 +843,10 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_ssn_memcap); return -1; } - SCPerfCounterIncr(stt->counter_tcp_sessions, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_sessions); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV); @@ -924,11 +924,11 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_ssn_memcap); return -1; } - SCPerfCounterIncr(stt->counter_tcp_sessions, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_sessions); } /* set the state */ @@ -977,10 +977,10 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_ssn_memcap); return -1; } - SCPerfCounterIncr(stt->counter_tcp_sessions, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_sessions); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); @@ -4460,12 +4460,12 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, /* update counters */ if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { - SCPerfCounterIncr(stt->counter_tcp_synack, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_synack); } else if (p->tcph->th_flags & (TH_SYN)) { - SCPerfCounterIncr(stt->counter_tcp_syn, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_syn); } if (p->tcph->th_flags & (TH_RST)) { - SCPerfCounterIncr(stt->counter_tcp_rst, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_rst); } /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */ @@ -5019,13 +5019,13 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; if (p->flow == NULL) { - SCPerfCounterIncr(stt->counter_tcp_no_flow, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_no_flow); return TM_ECODE_OK; } if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) { if (StreamTcpValidateChecksum(p) == 0) { - SCPerfCounterIncr(stt->counter_tcp_invalid_checksum, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_invalid_checksum); return TM_ECODE_OK; } } else { @@ -5896,7 +5896,7 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread Packet *np = StreamTcpPseudoSetup(p, GET_PKT_DATA(p), GET_PKT_LEN(p)); if (np == NULL) { SCLogDebug("The packet received from packet allocation is NULL"); - SCPerfCounterIncr(stt->counter_tcp_pseudo_failed, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_pseudo_failed); SCReturn; } PKT_SET_SRC(np, PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO); @@ -5931,7 +5931,7 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread PacketEnqueue(pq, np); - SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->perf_private_ctx); + SCPerfCounterIncr(tv, stt->counter_tcp_pseudo); SCReturn; } From b34c6dc93aa5d280cd6fb611c24b61a7ed43a650 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 23 May 2015 12:15:10 +0200 Subject: [PATCH 0487/2553] counters: remove references to SCPerfCounterAddDouble They were all in comments anyway. --- src/source-af-packet.c | 9 +-------- src/source-erf-dag.c | 9 +-------- src/source-erf-file.c | 9 +-------- src/source-nfq.c | 5 ----- src/source-pcap-file.c | 8 +------- src/source-pcap.c | 9 +-------- src/source-pfring.c | 9 +-------- 7 files changed, 6 insertions(+), 52 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index fa384fc345c6..6482ee759f4d 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1857,15 +1857,8 @@ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); -// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - + //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, - (GET_PKT_LEN(p) * 8)/1000000.0); -#endif - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index b73f2fd6fa9d..910729b9365a 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -624,15 +624,8 @@ DecodeErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); -// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - + //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, - (GET_PKT_LEN(p) * 8)/1000000.0); -#endif - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-erf-file.c b/src/source-erf-file.c index ff39bedc2d2f..38fa57ca9f7a 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -285,15 +285,8 @@ DecodeErfFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueu /* Update counters. */ SCPerfCounterIncr(tv, dtv->counter_pkts); -// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - + //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, - (GET_PKT_LEN(p) * 8)/1000000.0 ); -#endif - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-nfq.c b/src/source-nfq.c index 12123b7752a7..a4a6ab73b677 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -1227,11 +1227,6 @@ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, - (GET_PKT_LEN(p) * 8)/1000000.0); -#endif if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index a1b1d04d4433..8e7e0bfd0909 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -402,14 +402,8 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); -// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - + //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, - (GET_PKT_LEN(p) * 8)/1000000.0 ); -#endif SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-pcap.c b/src/source-pcap.c index 138db8496fbc..7a551d16ac22 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -717,15 +717,8 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); -// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - + //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, - (GET_PKT_LEN(p) * 8)/1000000.0); -#endif - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-pfring.c b/src/source-pfring.c index 5708ddd8dad7..a6149e2af4bf 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -609,15 +609,8 @@ TmEcode DecodePfring(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pac /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); -// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - + //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->perf_private_ctx, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->perf_private_ctx, - (GET_PKT_LEN(p) * 8)/1000000.0 ); -#endif - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); From 55cfab89e4d55ea21b940736e4bf2f51beacb1be Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 23 May 2015 12:28:54 +0200 Subject: [PATCH 0488/2553] counters: SCPerfGetLocalCounterValue cleanup Return u64, update arguments. --- src/counters.c | 9 +++++---- src/counters.h | 2 +- src/detect.c | 8 ++++---- src/source-af-packet.c | 4 ++-- src/source-erf-dag.c | 8 ++++---- src/source-netmap.c | 4 ++-- src/source-pfring.c | 10 ++++------ 7 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/counters.c b/src/counters.c index 184852f78b80..adf5660a69d0 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1265,17 +1265,18 @@ int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, SCPerfPublicContext *pct return 1; } -/* +/** * \brief Get the value of the local copy of the counter that hold this id. * - * \param id The counter id. - * \param pca Pointer to the SCPerfPrivateContext. + * \param tv threadvars + * \param id The counter id. * * \retval 0 on success. * \retval -1 on error. */ -double SCPerfGetLocalCounterValue(uint16_t id, SCPerfPrivateContext *pca) +uint64_t SCPerfGetLocalCounterValue(ThreadVars *tv, uint16_t id) { + SCPerfPrivateContext *pca = tv->perf_private_ctx; #ifdef DEBUG BUG_ON (pca == NULL); BUG_ON ((id < 1) || (id > pca->size)); diff --git a/src/counters.h b/src/counters.h index 8c0f62868495..de8780b4d7a2 100644 --- a/src/counters.h +++ b/src/counters.h @@ -164,7 +164,7 @@ SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t, uint16_t, SCPerfPubli SCPerfPrivateContext * SCPerfGetAllCountersArray(SCPerfPublicContext *); int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfPublicContext *); -double SCPerfGetLocalCounterValue(uint16_t, SCPerfPrivateContext *); +uint64_t SCPerfGetLocalCounterValue(struct ThreadVars_ *, uint16_t); /* functions used to free the resources alloted by the Perf counter API */ void SCPerfReleaseResources(void); diff --git a/src/detect.c b/src/detect.c index bca51a25c92f..3d51866e07b6 100644 --- a/src/detect.c +++ b/src/detect.c @@ -11269,20 +11269,20 @@ static int SigTestDetectAlertCounter(void) p = UTHBuildPacket((uint8_t *)"boo", strlen("boo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result = (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.perf_private_ctx) == 1); + result = (SCPerfGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 1); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.perf_private_ctx) == 2); + result &= (SCPerfGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"roo", strlen("roo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.perf_private_ctx) == 2); + result &= (SCPerfGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"laboosa", strlen("laboosa"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.perf_private_ctx) == 3); + result &= (SCPerfGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 3); UTHFreePackets(&p, 1); end: diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 6482ee759f4d..d49898dfcff3 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1805,8 +1805,8 @@ void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) AFPDumpCounters(ptv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, tv->perf_private_ctx), - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, tv->perf_private_ctx)); + SCPerfGetLocalCounterValue(tv, ptv->capture_kernel_packets), + SCPerfGetLocalCounterValue(tv, ptv->capture_kernel_drops)); #endif SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index 910729b9365a..fbe21fe855f5 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -560,16 +560,16 @@ ReceiveErfDagThreadExitStats(ThreadVars *tv, void *data) ErfDagThreadVars *ewtn = (ErfDagThreadVars *)data; (void)SC_ATOMIC_SET(ewtn->livedev->pkts, - (uint64_t)SCPerfGetLocalCounterValue(ewtn->packets, tv->perf_private_ctx)); + SCPerfGetLocalCounterValue(tv, ewtn->packets)); (void)SC_ATOMIC_SET(ewtn->livedev->drop, - (uint64_t)SCPerfGetLocalCounterValue(ewtn->drops, tv->perf_private_ctx)); + SCPerfGetLocalCounterValue(tv, ewtn->drops)); SCLogInfo("Stream: %d; Bytes: %"PRIu64"; Packets: %"PRIu64 "; Drops: %"PRIu64, ewtn->dagstream, ewtn->bytes, - (uint64_t)SCPerfGetLocalCounterValue(ewtn->packets, tv->perf_private_ctx), - (uint64_t)SCPerfGetLocalCounterValue(ewtn->drops, tv->perf_private_ctx)); + SCPerfGetLocalCounterValue(tv, ewtn->packets), + SCPerfGetLocalCounterValue(tv, ewtn->drops)); } /** diff --git a/src/source-netmap.c b/src/source-netmap.c index 1b6b3329888a..db853e19194d 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -851,8 +851,8 @@ static void ReceiveNetmapThreadExitStats(ThreadVars *tv, void *data) NetmapDumpCounters(ntv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 ", bytes %" PRIu64 "", tv->name, - (uint64_t) SCPerfGetLocalCounterValue(ntv->capture_kernel_packets, tv->perf_private_ctx), - (uint64_t) SCPerfGetLocalCounterValue(ntv->capture_kernel_drops, tv->perf_private_ctx), + SCPerfGetLocalCounterValue(tv, ntv->capture_kernel_packets), + SCPerfGetLocalCounterValue(tv, ntv->capture_kernel_drops), ntv->bytes); } diff --git a/src/source-pfring.c b/src/source-pfring.c index a6149e2af4bf..e0e9001960b6 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -198,10 +198,8 @@ static inline void PfringDumpCounters(PfringThreadVars *ptv) * So to get the number of packet on the interface we can add * the newly seen packets and drops for this thread and add it * to the interface counter */ - uint64_t th_pkts = SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, - ptv->tv->perf_private_ctx); - uint64_t th_drops = SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, - ptv->tv->perf_private_ctx); + uint64_t th_pkts = SCPerfGetLocalCounterValue(ptv->tv, ptv->capture_kernel_packets); + uint64_t th_drops = SCPerfGetLocalCounterValue(ptv->tv, ptv->capture_kernel_drops); SC_ATOMIC_ADD(ptv->livedev->pkts, pfring_s.recv - th_pkts); SC_ATOMIC_ADD(ptv->livedev->drop, pfring_s.drop - th_drops); SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_packets, pfring_s.recv); @@ -554,8 +552,8 @@ void ReceivePfringThreadExitStats(ThreadVars *tv, void *data) PfringDumpCounters(ptv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, tv->perf_private_ctx), - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, tv->perf_private_ctx)); + SCPerfGetLocalCounterValue(tv, ptv->capture_kernel_packets), + SCPerfGetLocalCounterValue(tv, ptv->capture_kernel_drops)); SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); } From 799640f9066f14e806e36abff078053ab8b18172 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 23 May 2015 12:56:16 +0200 Subject: [PATCH 0489/2553] counters: make threadvars::perf_private_ctx static Update SCPerfGetAllCountersArray and add a UT workaround. --- src/counters.c | 101 +++++++++++++++++++++------------------------ src/counters.h | 12 +++--- src/detect.c | 2 +- src/threadvars.h | 2 +- src/tm-threads.c | 6 +-- src/unix-manager.c | 2 +- 6 files changed, 60 insertions(+), 65 deletions(-) diff --git a/src/counters.c b/src/counters.c index adf5660a69d0..c9e307585550 100644 --- a/src/counters.c +++ b/src/counters.c @@ -81,12 +81,11 @@ void SCPerfOutputCounters(ThreadVars *tv) */ void SCPerfCounterAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) { - SCPerfPrivateContext *pca = tv->perf_private_ctx; - - if (!pca) { - SCLogDebug("counterarray is NULL"); + SCPerfPrivateContext *pca = &tv->perf_private_ctx; +#ifdef UNITTESTS + if (pca->initialized == 0) return; - } +#endif #ifdef DEBUG BUG_ON ((id < 1) || (id > pca->size)); #endif @@ -103,17 +102,14 @@ void SCPerfCounterAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) */ void SCPerfCounterIncr(ThreadVars *tv, uint16_t id) { - SCPerfPrivateContext *pca = tv->perf_private_ctx; - - if (pca == NULL) { - SCLogDebug("counterarray is NULL"); + SCPerfPrivateContext *pca = &tv->perf_private_ctx; +#ifdef UNITTESTS + if (pca->initialized == 0) return; - } - +#endif #ifdef DEBUG BUG_ON ((id < 1) || (id > pca->size)); #endif - pca->head[id].ui64_cnt++; pca->head[id].syncs++; return; @@ -128,13 +124,11 @@ void SCPerfCounterIncr(ThreadVars *tv, uint16_t id) */ void SCPerfCounterSetUI64(ThreadVars *tv, uint16_t id, uint64_t x) { - SCPerfPrivateContext *pca = tv->perf_private_ctx; - - if (!pca) { - SCLogDebug("counterarray is NULL"); + SCPerfPrivateContext *pca = &tv->perf_private_ctx; +#ifdef UNITTESTS + if (pca->initialized == 0) return; - } - +#endif #ifdef DEBUG BUG_ON ((id < 1) || (id > pca->size)); #endif @@ -1153,35 +1147,30 @@ int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfPublicContext *pctx) * * \retval a counter-array in this(s_id-e_id) range for this TM instance */ -SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, - SCPerfPublicContext *pctx) +static int SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, + SCPerfPublicContext *pctx, + SCPerfPrivateContext *pca) { SCPerfCounter *pc = NULL; - SCPerfPrivateContext *pca = NULL; uint32_t i = 0; - if (pctx == NULL) { - SCLogDebug("pctx is NULL"); - return NULL; + if (pctx == NULL || pca == NULL) { + SCLogDebug("pctx/pca is NULL"); + return -1; } if (s_id < 1 || e_id < 1 || s_id > e_id) { SCLogDebug("error with the counter ids"); - return NULL; + return -1; } if (e_id > pctx->curr_id) { SCLogDebug("end id is greater than the max id for this tv"); - return NULL; + return -1; } - if ( (pca = SCMalloc(sizeof(SCPerfPrivateContext))) == NULL) - return NULL; - memset(pca, 0, sizeof(SCPerfPrivateContext)); - if ( (pca->head = SCMalloc(sizeof(SCPCAElem) * (e_id - s_id + 2))) == NULL) { - SCFree(pca); - return NULL; + return -1; } memset(pca->head, 0, sizeof(SCPCAElem) * (e_id - s_id + 2)); @@ -1198,7 +1187,8 @@ SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, } pca->size = i - 1; - return pca; + pca->initialized = 1; + return 0; } /** @@ -1210,13 +1200,12 @@ SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, * \retval pca Pointer to a counter-array for all counter of this tm instance * on success; NULL on failure */ -SCPerfPrivateContext *SCPerfGetAllCountersArray(SCPerfPublicContext *pctx) +int SCPerfGetAllCountersArray(SCPerfPublicContext *pctx, SCPerfPrivateContext *private) { - SCPerfPrivateContext *pca = ((pctx)? - SCPerfGetCounterArrayRange(1, pctx->curr_id, pctx): - NULL); + if (pctx == NULL || private == NULL) + return -1; - return pca; + return SCPerfGetCounterArrayRange(1, pctx->curr_id, pctx, private); } /** @@ -1276,9 +1265,8 @@ int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, SCPerfPublicContext *pct */ uint64_t SCPerfGetLocalCounterValue(ThreadVars *tv, uint16_t id) { - SCPerfPrivateContext *pca = tv->perf_private_ctx; + SCPerfPrivateContext *pca = &tv->perf_private_ctx; #ifdef DEBUG - BUG_ON (pca == NULL); BUG_ON ((id < 1) || (id > pca->size)); #endif return pca->head[id].ui64_cnt; @@ -1322,10 +1310,11 @@ void SCPerfReleasePerfCounterS(SCPerfCounter *head) void SCPerfReleasePCA(SCPerfPrivateContext *pca) { if (pca != NULL) { - if (pca->head != NULL) + if (pca->head != NULL) { SCFree(pca->head); - - SCFree(pca); + pca->head = NULL; + } + pca->initialized = 0; } return; @@ -1398,9 +1387,8 @@ static int SCPerfTestGetCntArray05() return 0; } - tv.perf_private_ctx = SCPerfGetAllCountersArray(NULL); - - return (!tv.perf_private_ctx)?1:0; + int r = SCPerfGetAllCountersArray(NULL, &tv.perf_private_ctx); + return (r == -1) ? 1 : 0; } static int SCPerfTestGetCntArray06() @@ -1416,12 +1404,12 @@ static int SCPerfTestGetCntArray06() if (id != 1) return 0; - tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + int r = SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); - result = (tv.perf_private_ctx)?1:0; + result = (r == 0) ? 1 : 0; SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); - SCPerfReleasePCA(tv.perf_private_ctx); + SCPerfReleasePCA(&tv.perf_private_ctx); return result; } @@ -1441,7 +1429,8 @@ static int SCPerfTestCntArraySize07() SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); - pca = tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + pca = &tv.perf_private_ctx; SCPerfCounterIncr(&tv, 1); SCPerfCounterIncr(&tv, 2); @@ -1466,7 +1455,8 @@ static int SCPerfTestUpdateCounter08() id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); - pca = tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + pca = &tv.perf_private_ctx; SCPerfCounterIncr(&tv, id); SCPerfCounterAddUI64(&tv, id, 100); @@ -1499,7 +1489,8 @@ static int SCPerfTestUpdateCounter09() id2 = SCPerfRegisterCounter("t5", "c5", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); - pca = tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + pca = &tv.perf_private_ctx; SCPerfCounterIncr(&tv, id2); SCPerfCounterAddUI64(&tv, id2, 100); @@ -1529,7 +1520,8 @@ static int SCPerfTestUpdateGlobalCounter10() id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); - pca = tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + pca = &tv.perf_private_ctx; SCPerfCounterIncr(&tv, id1); SCPerfCounterAddUI64(&tv, id2, 100); @@ -1567,7 +1559,8 @@ static int SCPerfTestCounterValues11() id4 = SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, NULL, &tv.perf_public_ctx); - pca = tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + pca = &tv.perf_private_ctx; SCPerfCounterIncr(&tv, id1); SCPerfCounterAddUI64(&tv, id2, 256); diff --git a/src/counters.h b/src/counters.h index de8780b4d7a2..e930019a0581 100644 --- a/src/counters.h +++ b/src/counters.h @@ -121,6 +121,8 @@ typedef struct SCPerfPrivateContext_ { /* no of PCAElems in head */ uint32_t size; + + int initialized; } SCPerfPrivateContext; /** @@ -160,8 +162,7 @@ uint16_t SCPerfRegisterMaxCounter(char *, char *, int, char *, SCPerfPublicConte /* utility functions */ int SCPerfAddToClubbedTMTable(char *, SCPerfPublicContext *); -SCPerfPrivateContext *SCPerfGetCounterArrayRange(uint16_t, uint16_t, SCPerfPublicContext *); -SCPerfPrivateContext * SCPerfGetAllCountersArray(SCPerfPublicContext *); +int SCPerfGetAllCountersArray(SCPerfPublicContext *, SCPerfPrivateContext *); int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfPublicContext *); uint64_t SCPerfGetLocalCounterValue(struct ThreadVars_ *, uint16_t); @@ -180,12 +181,13 @@ void SCPerfRegisterTests(void); void SCPerfCounterAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); #define SCPerfSyncCounters(tv) \ - SCPerfUpdateCounterArray((tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ + SCPerfUpdateCounterArray(&(tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ #define SCPerfSyncCountersIfSignalled(tv) \ do { \ - if ((tv)->perf_public_ctx.perf_flag == 1) { \ - SCPerfUpdateCounterArray((tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ + if ((tv)->perf_public_ctx.perf_flag == 1) { \ + SCPerfUpdateCounterArray(&(tv)->perf_private_ctx, \ + &(tv)->perf_public_ctx); \ } \ } while (0) diff --git a/src/detect.c b/src/detect.c index 3d51866e07b6..6823ed912538 100644 --- a/src/detect.c +++ b/src/detect.c @@ -11263,7 +11263,7 @@ static int SigTestDetectAlertCounter(void) DetectEngineThreadCtxInit(&tv, de_ctx, (void *)&det_ctx); /* init counters */ - tv.perf_private_ctx = SCPerfGetAllCountersArray(&tv.perf_public_ctx); + SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); SCPerfAddToClubbedTMTable((tv.thread_group_name != NULL) ? tv.thread_group_name : tv.name, &tv.perf_public_ctx); diff --git a/src/threadvars.h b/src/threadvars.h index 0148359133af..b5702cfc70a3 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -107,7 +107,7 @@ typedef struct ThreadVars_ { SCPerfPublicContext perf_public_ctx; /** private counter store: counter updates modify this */ - SCPerfPrivateContext *perf_private_ctx; + SCPerfPrivateContext perf_private_ctx; SCCtrlMutex *ctrl_mutex; SCCtrlCondT *ctrl_cond; diff --git a/src/tm-threads.c b/src/tm-threads.c index 50ec19fbf06d..32076874e312 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -322,7 +322,7 @@ void *TmThreadsSlotPktAcqLoop(void *td) } } - tv->perf_private_ctx = SCPerfGetAllCountersArray(&tv->perf_public_ctx); + SCPerfGetAllCountersArray(&tv->perf_public_ctx, &tv->perf_private_ctx); SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->perf_public_ctx); @@ -455,7 +455,7 @@ void *TmThreadsSlotVar(void *td) } } - tv->perf_private_ctx = SCPerfGetAllCountersArray(&tv->perf_public_ctx); + SCPerfGetAllCountersArray(&tv->perf_public_ctx, &tv->perf_private_ctx); SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->perf_public_ctx); @@ -597,7 +597,7 @@ static void *TmThreadsManagement(void *td) memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - tv->perf_private_ctx = SCPerfGetAllCountersArray(&tv->perf_public_ctx); + SCPerfGetAllCountersArray(&tv->perf_public_ctx, &tv->perf_private_ctx); SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->perf_public_ctx); diff --git a/src/unix-manager.c b/src/unix-manager.c index ce6ae64fe053..266f78a305f3 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -868,7 +868,7 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) /* set the thread name */ SCLogDebug("%s started...", th_v->name); - th_v->perf_private_ctx = SCPerfGetAllCountersArray(&th_v->perf_public_ctx); + SCPerfGetAllCountersArray(&th_v->perf_public_ctx, &th_v->perf_private_ctx); SCPerfAddToClubbedTMTable(th_v->name, &th_v->perf_public_ctx); if (UnixNew(&command) == 0) { From 74ab84c194a915bddf36fe1d51f416c1ee830c8b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 23 May 2015 13:24:08 +0200 Subject: [PATCH 0490/2553] counters: introduce SCPerfSetupPrivate for thread setup --- src/counters.h | 10 ++++++++++ src/detect.c | 4 +--- src/tm-threads.c | 12 +++--------- src/unix-manager.c | 3 +-- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/counters.h b/src/counters.h index e930019a0581..72e62f5b197d 100644 --- a/src/counters.h +++ b/src/counters.h @@ -191,6 +191,16 @@ void SCPerfCounterAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); } \ } while (0) +#define SCPerfSetupPrivate(tv) \ + do { \ + SCPerfGetAllCountersArray(&(tv)->perf_public_ctx, \ + &(tv)->perf_private_ctx); \ + \ + SCPerfAddToClubbedTMTable(((tv)->thread_group_name != NULL) ? \ + (tv)->thread_group_name : (tv)->name, \ + &(tv)->perf_public_ctx); \ + } while (0) + #ifdef BUILD_UNIX_SOCKET #include TmEcode SCPerfOutputCounterSocket(json_t *cmd, diff --git a/src/detect.c b/src/detect.c index 6823ed912538..b95d5859cb9c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -11263,9 +11263,7 @@ static int SigTestDetectAlertCounter(void) DetectEngineThreadCtxInit(&tv, de_ctx, (void *)&det_ctx); /* init counters */ - SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); - SCPerfAddToClubbedTMTable((tv.thread_group_name != NULL) ? - tv.thread_group_name : tv.name, &tv.perf_public_ctx); + SCPerfSetupPrivate(&tv); p = UTHBuildPacket((uint8_t *)"boo", strlen("boo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); diff --git a/src/tm-threads.c b/src/tm-threads.c index 32076874e312..f6c2802c821b 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -322,9 +322,7 @@ void *TmThreadsSlotPktAcqLoop(void *td) } } - SCPerfGetAllCountersArray(&tv->perf_public_ctx, &tv->perf_private_ctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->perf_public_ctx); + SCPerfSetupPrivate(tv); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -455,9 +453,7 @@ void *TmThreadsSlotVar(void *td) } } - SCPerfGetAllCountersArray(&tv->perf_public_ctx, &tv->perf_private_ctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->perf_public_ctx); + SCPerfSetupPrivate(tv); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -597,9 +593,7 @@ static void *TmThreadsManagement(void *td) memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - SCPerfGetAllCountersArray(&tv->perf_public_ctx, &tv->perf_private_ctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->perf_public_ctx); + SCPerfSetupPrivate(tv); TmThreadsSetFlag(tv, THV_INIT_DONE); diff --git a/src/unix-manager.c b/src/unix-manager.c index 266f78a305f3..094c2d1f8565 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -868,8 +868,7 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) /* set the thread name */ SCLogDebug("%s started...", th_v->name); - SCPerfGetAllCountersArray(&th_v->perf_public_ctx, &th_v->perf_private_ctx); - SCPerfAddToClubbedTMTable(th_v->name, &th_v->perf_public_ctx); + SCPerfSetupPrivate(th_v); if (UnixNew(&command) == 0) { int failure_fatal = 0; From 66635f0741befe295d0c76b26035475dfaf29263 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 23 May 2015 13:27:41 +0200 Subject: [PATCH 0491/2553] counters: minor cleanups --- src/counters.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/counters.h b/src/counters.h index 72e62f5b197d..ff00e0d89a54 100644 --- a/src/counters.h +++ b/src/counters.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2015 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 @@ -19,6 +19,7 @@ * \file * * \author Anoop Saldanha + * \author Victor Julien */ #ifndef __COUNTERS_H__ @@ -149,6 +150,7 @@ typedef struct SCPerfOPIfaceContext_ { /* the initialization functions */ void SCPerfInitCounterApi(void); void SCPerfSpawnThreads(void); +void SCPerfRegisterTests(void); /* the ThreadVars counter registration functions */ uint16_t SCPerfTVRegisterCounter(char *, struct ThreadVars_ *, int, char *); @@ -163,7 +165,6 @@ uint16_t SCPerfRegisterMaxCounter(char *, char *, int, char *, SCPerfPublicConte /* utility functions */ int SCPerfAddToClubbedTMTable(char *, SCPerfPublicContext *); int SCPerfGetAllCountersArray(SCPerfPublicContext *, SCPerfPrivateContext *); - int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfPublicContext *); uint64_t SCPerfGetLocalCounterValue(struct ThreadVars_ *, uint16_t); @@ -172,13 +173,10 @@ void SCPerfReleaseResources(void); void SCPerfReleasePerfCounterS(SCPerfCounter *); void SCPerfReleasePCA(SCPerfPrivateContext *); -void SCPerfCounterSetUI64(struct ThreadVars_ *, uint16_t, uint64_t); -void SCPerfCounterIncr(struct ThreadVars_ *, uint16_t); - -void SCPerfRegisterTests(void); - /* functions used to update local counter values */ void SCPerfCounterAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); +void SCPerfCounterSetUI64(struct ThreadVars_ *, uint16_t, uint64_t); +void SCPerfCounterIncr(struct ThreadVars_ *, uint16_t); #define SCPerfSyncCounters(tv) \ SCPerfUpdateCounterArray(&(tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ From ac6e24c06a3110dd682ebfb925dbf8a0871a1fcb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 23 May 2015 13:41:49 +0200 Subject: [PATCH 0492/2553] counters: make SCPerfSetupPrivate a function --- src/counters.c | 51 ++++++++++++++++++++++++++++++-------------------- src/counters.h | 13 +------------ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/counters.c b/src/counters.c index c9e307585550..2e4546a2001f 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1024,16 +1024,16 @@ uint16_t SCPerfRegisterMaxCounter(char *cname, char *tm_name, int type, return id; } -/** - * \brief Adds a TM to the clubbed TM table. Multiple instances of the same TM - * are stacked together in a PCTMI container. +/** \internal + * \brief Adds a TM to the clubbed TM table. Multiple instances of the same TM + * are stacked together in a PCTMI container. * - * \param tm_name Name of the tm to be added to the table - * \param pctx SCPerfPublicContext associated with the TM tm_name + * \param tm_name Name of the tm to be added to the table + * \param pctx SCPerfPublicContext associated with the TM tm_name * - * \retval 1 on success, 0 on failure + * \retval 1 on success, 0 on failure */ -int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfPublicContext *pctx) +static int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfPublicContext *pctx) { void *ptmp; if (sc_perf_op_ctx == NULL) { @@ -1138,14 +1138,14 @@ int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfPublicContext *pctx) return 1; } -/** - * \brief Returns a counter array for counters in this id range(s_id - e_id) +/** \internal + * \brief Returns a counter array for counters in this id range(s_id - e_id) * - * \param s_id Counter id of the first counter to be added to the array - * \param e_id Counter id of the last counter to be added to the array - * \param pctx Pointer to the tv's SCPerfPublicContext + * \param s_id Counter id of the first counter to be added to the array + * \param e_id Counter id of the last counter to be added to the array + * \param pctx Pointer to the tv's SCPerfPublicContext * - * \retval a counter-array in this(s_id-e_id) range for this TM instance + * \retval a counter-array in this(s_id-e_id) range for this TM instance */ static int SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, SCPerfPublicContext *pctx, @@ -1191,16 +1191,16 @@ static int SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, return 0; } -/** - * \brief Returns a counter array for all counters registered for this tm - * instance +/** \internal + * \brief Returns a counter array for all counters registered for this tm + * instance * - * \param pctx Pointer to the tv's SCPerfPublicContext + * \param pctx Pointer to the tv's SCPerfPublicContext * - * \retval pca Pointer to a counter-array for all counter of this tm instance - * on success; NULL on failure + * \retval pca Pointer to a counter-array for all counter of this tm instance + * on success; NULL on failure */ -int SCPerfGetAllCountersArray(SCPerfPublicContext *pctx, SCPerfPrivateContext *private) +static int SCPerfGetAllCountersArray(SCPerfPublicContext *pctx, SCPerfPrivateContext *private) { if (pctx == NULL || private == NULL) return -1; @@ -1208,6 +1208,17 @@ int SCPerfGetAllCountersArray(SCPerfPublicContext *pctx, SCPerfPrivateContext *p return SCPerfGetCounterArrayRange(1, pctx->curr_id, pctx, private); } + +int SCPerfSetupPrivate(ThreadVars *tv) +{ + SCPerfGetAllCountersArray(&(tv)->perf_public_ctx, &(tv)->perf_private_ctx); + + SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? + tv->thread_group_name : tv->name, + &(tv)->perf_public_ctx); + return 0; +} + /** * \brief Syncs the counter array with the global counter variables * diff --git a/src/counters.h b/src/counters.h index ff00e0d89a54..a63cc5bb4a4e 100644 --- a/src/counters.h +++ b/src/counters.h @@ -163,10 +163,9 @@ uint16_t SCPerfRegisterAvgCounter(char *, char *, int, char *, SCPerfPublicConte uint16_t SCPerfRegisterMaxCounter(char *, char *, int, char *, SCPerfPublicContext *); /* utility functions */ -int SCPerfAddToClubbedTMTable(char *, SCPerfPublicContext *); -int SCPerfGetAllCountersArray(SCPerfPublicContext *, SCPerfPrivateContext *); int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfPublicContext *); uint64_t SCPerfGetLocalCounterValue(struct ThreadVars_ *, uint16_t); +int SCPerfSetupPrivate(struct ThreadVars_ *); /* functions used to free the resources alloted by the Perf counter API */ void SCPerfReleaseResources(void); @@ -189,16 +188,6 @@ void SCPerfCounterIncr(struct ThreadVars_ *, uint16_t); } \ } while (0) -#define SCPerfSetupPrivate(tv) \ - do { \ - SCPerfGetAllCountersArray(&(tv)->perf_public_ctx, \ - &(tv)->perf_private_ctx); \ - \ - SCPerfAddToClubbedTMTable(((tv)->thread_group_name != NULL) ? \ - (tv)->thread_group_name : (tv)->name, \ - &(tv)->perf_public_ctx); \ - } while (0) - #ifdef BUILD_UNIX_SOCKET #include TmEcode SCPerfOutputCounterSocket(json_t *cmd, From 7da657dc3dd449ff00f3cb35841df84ff3f00871 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 23 May 2015 14:16:21 +0200 Subject: [PATCH 0493/2553] counters: remove unused public API calls and make them private --- src/counters.c | 92 +++++++++++++++++++++++--------------------------- src/counters.h | 50 +-------------------------- 2 files changed, 44 insertions(+), 98 deletions(-) diff --git a/src/counters.c b/src/counters.c index 2e4546a2001f..66caf64fb058 100644 --- a/src/counters.c +++ b/src/counters.c @@ -50,6 +50,48 @@ /* Time interval at which the mgmt thread o/p the stats */ #define SC_PERF_MGMTT_TTS 8 +/** + * \brief Different kinds of qualifier that can be used to modify the behaviour + * of the Perf counter to be registered + */ +enum { + SC_PERF_TYPE_Q_NORMAL = 1, + SC_PERF_TYPE_Q_AVERAGE = 2, + SC_PERF_TYPE_Q_MAXIMUM = 3, + SC_PERF_TYPE_Q_MAX = 4, +}; + +/** + * \brief Different output interfaces made available by the Perf counter API + */ +enum { + SC_PERF_IFACE_FILE, + SC_PERF_IFACE_CONSOLE, + SC_PERF_IFACE_SYSLOG, + SC_PERF_IFACE_MAX, +}; + +/** + * \brief Holds multiple instances of the same TM together, used when the stats + * have to be clubbed based on TM, before being sent out + */ +typedef struct SCPerfClubTMInst_ { + char *tm_name; + + SCPerfPublicContext **head; + uint32_t size; + + struct SCPerfClubTMInst_ *next; +} SCPerfClubTMInst; + +/** + * \brief Holds the output interface context for the counter api + */ +typedef struct SCPerfOPIfaceContext_ { + SCPerfClubTMInst *pctmi; + SCMutex pctmi_lock; +} SCPerfOPIfaceContext; + static void *stats_thread_data = NULL; static SCPerfOPIfaceContext *sc_perf_op_ctx = NULL; static time_t sc_start_time; @@ -967,7 +1009,7 @@ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, char *desc, +static uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, char *desc, SCPerfPublicContext *pctx) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, @@ -976,54 +1018,6 @@ uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, char *desc, return id; } -/** - * \brief Registers a counter, whose value holds the average of all the values - * assigned to it. - * - * \param cname Name of the counter, to be registered - * \param tm_name Name of the engine module under which the counter has to be - * registered - * \param type Datatype of this counter variable - * \param desc Description of this counter - * \param pctx SCPerfPublicContext corresponding to the tm_name key under which the - * key has to be registered - * - * \retval id Counter id for the newly registered counter, or the already - * present counter - */ -uint16_t SCPerfRegisterAvgCounter(char *cname, char *tm_name, int type, - char *desc, SCPerfPublicContext *pctx) -{ - uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, - pctx, SC_PERF_TYPE_Q_AVERAGE); - - return id; -} - -/** - * \brief Registers a counter, whose value holds the maximum of all the values - * assigned to it. - * - * \param cname Name of the counter, to be registered - * \param tm_name Name of the engine module under which the counter has to be - * registered - * \param type Datatype of this counter variable - * \param desc Description of this counter - * \param pctx SCPerfPublicContext corresponding to the tm_name key under which the - * key has to be registered - * - * \retval id Counter id for the newly registered counter, or the already - * present counter - */ -uint16_t SCPerfRegisterMaxCounter(char *cname, char *tm_name, int type, - char *desc, SCPerfPublicContext *pctx) -{ - uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, - pctx, SC_PERF_TYPE_Q_MAXIMUM); - - return id; -} - /** \internal * \brief Adds a TM to the clubbed TM table. Multiple instances of the same TM * are stacked together in a PCTMI container. diff --git a/src/counters.h b/src/counters.h index a63cc5bb4a4e..75fac388961d 100644 --- a/src/counters.h +++ b/src/counters.h @@ -36,27 +36,6 @@ enum { SC_PERF_TYPE_MAX, }; -/** - * \brief Different kinds of qualifier that can be used to modify the behaviour - * of the Perf counter to be registered - */ -enum { - SC_PERF_TYPE_Q_NORMAL = 1, - SC_PERF_TYPE_Q_AVERAGE = 2, - SC_PERF_TYPE_Q_MAXIMUM = 3, - SC_PERF_TYPE_Q_MAX = 4, -}; - -/** - * \brief Different output interfaces made available by the Perf counter API - */ -enum { - SC_PERF_IFACE_FILE, - SC_PERF_IFACE_CONSOLE, - SC_PERF_IFACE_SYSLOG, - SC_PERF_IFACE_MAX, -}; - /** * \brief Container to hold the counter variable */ @@ -126,42 +105,16 @@ typedef struct SCPerfPrivateContext_ { int initialized; } SCPerfPrivateContext; -/** - * \brief Holds multiple instances of the same TM together, used when the stats - * have to be clubbed based on TM, before being sent out - */ -typedef struct SCPerfClubTMInst_ { - char *tm_name; - - SCPerfPublicContext **head; - uint32_t size; - - struct SCPerfClubTMInst_ *next; -} SCPerfClubTMInst; - -/** - * \brief Holds the output interface context for the counter api - */ -typedef struct SCPerfOPIfaceContext_ { - SCPerfClubTMInst *pctmi; - SCMutex pctmi_lock; -} SCPerfOPIfaceContext; - /* the initialization functions */ void SCPerfInitCounterApi(void); void SCPerfSpawnThreads(void); void SCPerfRegisterTests(void); -/* the ThreadVars counter registration functions */ +/* counter registration functions */ uint16_t SCPerfTVRegisterCounter(char *, struct ThreadVars_ *, int, char *); uint16_t SCPerfTVRegisterAvgCounter(char *, struct ThreadVars_ *, int, char *); uint16_t SCPerfTVRegisterMaxCounter(char *, struct ThreadVars_ *, int, char *); -/* the non-ThreadVars counter registration functions */ -uint16_t SCPerfRegisterCounter(char *, char *, int, char *, SCPerfPublicContext *); -uint16_t SCPerfRegisterAvgCounter(char *, char *, int, char *, SCPerfPublicContext *); -uint16_t SCPerfRegisterMaxCounter(char *, char *, int, char *, SCPerfPublicContext *); - /* utility functions */ int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfPublicContext *); uint64_t SCPerfGetLocalCounterValue(struct ThreadVars_ *, uint16_t); @@ -169,7 +122,6 @@ int SCPerfSetupPrivate(struct ThreadVars_ *); /* functions used to free the resources alloted by the Perf counter API */ void SCPerfReleaseResources(void); -void SCPerfReleasePerfCounterS(SCPerfCounter *); void SCPerfReleasePCA(SCPerfPrivateContext *); /* functions used to update local counter values */ From 711cd7b59bfc2e4b5913ac7dad5a7c5d0c637acb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 24 May 2015 09:04:04 +0200 Subject: [PATCH 0494/2553] counters: merge counters from threads for output Merge counters so the table contains combined values from counters from each thread. Use global counter id's, track them in a hash. Rename SCPCAElem members Fix and improve average counters --- src/counters.c | 363 +++++++++++++++++++++++-------------------------- src/counters.h | 12 +- 2 files changed, 177 insertions(+), 198 deletions(-) diff --git a/src/counters.c b/src/counters.c index 66caf64fb058..f61da6abedde 100644 --- a/src/counters.c +++ b/src/counters.c @@ -76,8 +76,12 @@ enum { * have to be clubbed based on TM, before being sent out */ typedef struct SCPerfClubTMInst_ { + char *name; + char *tm_name; + SCPerfPublicContext *ctx; + SCPerfPublicContext **head; uint32_t size; @@ -90,6 +94,7 @@ typedef struct SCPerfClubTMInst_ { typedef struct SCPerfOPIfaceContext_ { SCPerfClubTMInst *pctmi; SCMutex pctmi_lock; + HashTable *counters_id_hash; } SCPerfOPIfaceContext; static void *stats_thread_data = NULL; @@ -106,6 +111,8 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv); * loggers. Initialized at first use. */ static StatsTable stats_table = { NULL, 0, 0, {0 , 0}}; +static uint16_t counters_global_id = 0; + /** * \brief The output interface dispatcher for the counter api */ @@ -131,8 +138,8 @@ void SCPerfCounterAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) #ifdef DEBUG BUG_ON ((id < 1) || (id > pca->size)); #endif - pca->head[id].ui64_cnt += x; - pca->head[id].syncs++; + pca->head[id].value += x; + pca->head[id].updates++; return; } @@ -152,8 +159,8 @@ void SCPerfCounterIncr(ThreadVars *tv, uint16_t id) #ifdef DEBUG BUG_ON ((id < 1) || (id > pca->size)); #endif - pca->head[id].ui64_cnt++; - pca->head[id].syncs++; + pca->head[id].value++; + pca->head[id].updates++; return; } @@ -176,13 +183,13 @@ void SCPerfCounterSetUI64(ThreadVars *tv, uint16_t id, uint64_t x) #endif if ((pca->head[id].pc->type == SC_PERF_TYPE_Q_MAXIMUM) && - (x > pca->head[id].ui64_cnt)) { - pca->head[id].ui64_cnt = x; + (x > pca->head[id].value)) { + pca->head[id].value = x; } else if (pca->head[id].pc->type == SC_PERF_TYPE_Q_NORMAL) { - pca->head[id].ui64_cnt = x; + pca->head[id].value = x; } - pca->head[id].syncs++; + pca->head[id].updates++; return; } @@ -594,20 +601,10 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, */ static void SCPerfCopyCounterValue(SCPCAElem *pcae) { - SCPerfCounter *pc = NULL; - uint64_t ui64_temp = 0; - - pc = pcae->pc; - ui64_temp = pcae->ui64_cnt; - - if (pc->type == SC_PERF_TYPE_Q_AVERAGE) { - if (pcae->syncs != 0) - ui64_temp /= pcae->syncs; - pc->value = ui64_temp; - } else { - pc->value = ui64_temp; - } + SCPerfCounter *pc = pcae->pc; + pc->value = pcae->value; + pc->updates = pcae->updates; return; } @@ -629,7 +626,6 @@ static uint64_t SCPerfOutputCalculateCounterValue(SCPerfCounter *pc) return pc->value; } - /** * \brief The file output interface for the Perf Counter api */ @@ -637,61 +633,10 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) { const SCPerfClubTMInst *pctmi = NULL; const SCPerfCounter *pc = NULL; - SCPerfCounter **pc_heads = NULL; - - uint64_t ui64_temp = 0; - uint64_t ui64_result = 0; - - uint32_t u = 0; - int flag = 0; void *td = stats_thread_data; if (stats_table.nstats == 0) { - uint32_t nstats = 0; - - pctmi = sc_perf_op_ctx->pctmi; - while (pctmi != NULL) { - if (pctmi->size == 0) { - pctmi = pctmi->next; - continue; - } - - if ((pc_heads = SCMalloc(pctmi->size * sizeof(SCPerfCounter *))) == NULL) - return 0; - memset(pc_heads, 0, pctmi->size * sizeof(SCPerfCounter *)); - - for (u = 0; u < pctmi->size; u++) { - pc_heads[u] = pctmi->head[u]->head; - SCMutexLock(&pctmi->head[u]->m); - } - - flag = 1; - while (flag) { - if (pc_heads[0] == NULL) - break; - - for (u = 0; u < pctmi->size; u++) { - if (pc_heads[u] != NULL) - pc_heads[u] = pc_heads[u]->next; - if (pc_heads[u] == NULL) - flag = 0; - } - - /* count */ - nstats++; - } - - for (u = 0; u < pctmi->size; u++) - SCMutexUnlock(&pctmi->head[u]->m); - - pctmi = pctmi->next; - SCFree(pc_heads); - - } - if (nstats == 0) { - SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "no counters registered"); - return -1; - } + uint32_t nstats = counters_global_id; stats_table.nstats = nstats; stats_table.stats = SCCalloc(stats_table.nstats, sizeof(StatsRecord)); @@ -703,58 +648,72 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) stats_table.start_time = sc_start_time; } - StatsRecord *table = stats_table.stats; - int table_i = 0; + /** temporary local table to merge the per thread counters, + * especially needed for the average counters */ + struct CountersMergeTable { + int type; + uint64_t value; + uint64_t updates; + } merge_table[counters_global_id]; + memset(&merge_table, 0x00, + counters_global_id * sizeof(struct CountersMergeTable)); + StatsRecord *table = stats_table.stats; pctmi = sc_perf_op_ctx->pctmi; + SCLogDebug("pctmi %p", pctmi); while (pctmi != NULL) { - if (pctmi->size == 0) { - pctmi = pctmi->next; - continue; - } - - if ((pc_heads = SCMalloc(pctmi->size * sizeof(SCPerfCounter *))) == NULL) - return 0; - memset(pc_heads, 0, pctmi->size * sizeof(SCPerfCounter *)); - - for (u = 0; u < pctmi->size; u++) { - pc_heads[u] = pctmi->head[u]->head; - SCMutexLock(&pctmi->head[u]->m); - } - - flag = 1; - while (flag) { - ui64_result = 0; - if (pc_heads[0] == NULL) - break; - /* keep ptr to first pc to we can use it to print the cname */ - pc = pc_heads[0]; - - for (u = 0; u < pctmi->size; u++) { - ui64_temp = SCPerfOutputCalculateCounterValue(pc_heads[u]); - ui64_result += ui64_temp; + SCLogDebug("Thread %s (%s) ctx %p", pctmi->name, + pctmi->tm_name ? pctmi->tm_name : "none", pctmi->ctx); - if (pc_heads[u] != NULL) - pc_heads[u] = pc_heads[u]->next; - if (pc_heads[u] == NULL) - flag = 0; + SCMutexLock(&pctmi->ctx->m); + pc = pctmi->ctx->head; + while (pc != NULL) { + SCLogDebug("Counter %s (%u:%u) value %"PRIu64, + pc->cname, pc->id, pc->gid, pc->value); + + merge_table[pc->gid].type = pc->type; + switch (pc->type) { + case SC_PERF_TYPE_Q_MAXIMUM: + if (pc->value > merge_table[pc->gid].value) + merge_table[pc->gid].value = pc->value; + break; + default: + merge_table[pc->gid].value += pc->value; + break; } + merge_table[pc->gid].updates += pc->updates; - /* store in the table */ - table[table_i].name = pc->cname; - table[table_i].tm_name = pctmi->tm_name; - table[table_i].pvalue = table[table_i].value; - table[table_i].value = ui64_result; - table_i++; - } - - for (u = 0; u < pctmi->size; u++) - SCMutexUnlock(&pctmi->head[u]->m); + table[pc->gid].name = pc->cname; + table[pc->gid].tm_name = pctmi->tm_name; + pc = pc->next; + } + SCMutexUnlock(&pctmi->ctx->m); pctmi = pctmi->next; - SCFree(pc_heads); + } + uint16_t x; + for (x = 0; x < counters_global_id; x++) { + /* xfer previous value to pvalue and reset value */ + table[x].pvalue = table[x].value; + table[x].value = 0; + + struct CountersMergeTable *m = &merge_table[x]; + switch (m->type) { + case SC_PERF_TYPE_Q_MAXIMUM: + if (m->value > table[x].value) + table[x].value = m->value; + break; + case SC_PERF_TYPE_Q_AVERAGE: + if (m->value > 0 && m->updates > 0) { + table[x].value = (uint64_t)(m->value / m->updates); + } + break; + default: + table[x].value += m->value; + break; + } } /* invoke logger(s) */ @@ -1018,6 +977,57 @@ static uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, char return id; } +typedef struct CountersIdType_ { + uint16_t id; + const char *string; +} CountersIdType; + +uint32_t CountersIdHashFunc(HashTable *ht, void *data, uint16_t datalen) +{ + CountersIdType *t = (CountersIdType *)data; + uint32_t hash = 0; + int i = 0; + + int len = strlen(t->string); + + for (i = 0; i < len; i++) + hash += tolower((unsigned char)t->string[i]); + + hash = hash % ht->array_size; + + return hash; +} + +char CountersIdHashCompareFunc(void *data1, uint16_t datalen1, + void *data2, uint16_t datalen2) +{ + CountersIdType *t1 = (CountersIdType *)data1; + CountersIdType *t2 = (CountersIdType *)data2; + int len1 = 0; + int len2 = 0; + + if (t1 == NULL || t2 == NULL) + return 0; + + if (t1->string == NULL || t2->string == NULL) + return 0; + + len1 = strlen(t1->string); + len2 = strlen(t2->string); + + if (len1 == len2 && memcmp(t1->string, t2->string, len1) == 0) { + return 1; + } + + return 0; +} + +void CountersIdHashFreeFunc(void *data) +{ + SCFree(data); +} + + /** \internal * \brief Adds a TM to the clubbed TM table. Multiple instances of the same TM * are stacked together in a PCTMI container. @@ -1027,108 +1037,73 @@ static uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, char * * \retval 1 on success, 0 on failure */ -static int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfPublicContext *pctx) +static int SCPerfAddToClubbedTMTable(ThreadVars *tv, SCPerfPublicContext *pctx) { - void *ptmp; if (sc_perf_op_ctx == NULL) { SCLogDebug("Counter module has been disabled"); return 0; } - SCPerfClubTMInst *pctmi = NULL; - SCPerfClubTMInst *prev = NULL; SCPerfClubTMInst *temp = NULL; - SCPerfPublicContext **hpctx = NULL; - uint32_t u = 0; - if (tm_name == NULL || pctx == NULL) { + if (tv == NULL || pctx == NULL) { SCLogDebug("supplied argument(s) to SCPerfAddToClubbedTMTable NULL"); return 0; } SCMutexLock(&sc_perf_op_ctx->pctmi_lock); - - pctmi = sc_perf_op_ctx->pctmi; - SCLogDebug("pctmi %p", pctmi); - prev = pctmi; - - while (pctmi != NULL) { - prev = pctmi; - if (strcmp(tm_name, pctmi->tm_name) != 0) { - pctmi = pctmi->next; - continue; - } - break; + if (sc_perf_op_ctx->counters_id_hash == NULL) { + sc_perf_op_ctx->counters_id_hash = HashTableInit(256, CountersIdHashFunc, + CountersIdHashCompareFunc, + CountersIdHashFreeFunc); + BUG_ON(sc_perf_op_ctx->counters_id_hash == NULL); } - - /* get me the bugger who wrote this junk of a code :P */ - if (pctmi == NULL) { - if ( (temp = SCMalloc(sizeof(SCPerfClubTMInst))) == NULL) { - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 0; - } - memset(temp, 0, sizeof(SCPerfClubTMInst)); - - temp->size = 1; - temp->head = SCMalloc(sizeof(SCPerfPublicContext **)); - if (temp->head == NULL) { - SCFree(temp); - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 0; - } - temp->head[0] = pctx; - temp->tm_name = SCStrdup(tm_name); - if (unlikely(temp->tm_name == NULL)) { - SCFree(temp->head); - SCFree(temp); - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 0; + SCPerfCounter *pc = pctx->head; + while (pc != NULL) { + CountersIdType t = { 0, pc->cname }, *id = NULL; + id = HashTableLookup(sc_perf_op_ctx->counters_id_hash, &t, sizeof(t)); + if (id == NULL) { + id = SCCalloc(1, sizeof(*id)); + BUG_ON(id == NULL); + id->id = counters_global_id++; + id->string = pc->cname; + BUG_ON(HashTableAdd(sc_perf_op_ctx->counters_id_hash, id, sizeof(*id)) < 0); } - - if (prev == NULL) - sc_perf_op_ctx->pctmi = temp; - else - prev->next = temp; - - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 1; + pc->gid = id->id; + pc = pc->next; } - /* see if the pctx is already part of this pctmi */ - hpctx = pctmi->head; - for (u = 0; u < pctmi->size; u++) { - if (hpctx[u] != pctx) - continue; + if ( (temp = SCMalloc(sizeof(SCPerfClubTMInst))) == NULL) { SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 1; + return 0; } + memset(temp, 0, sizeof(SCPerfClubTMInst)); - ptmp = SCRealloc(pctmi->head, - (pctmi->size + 1) * sizeof(SCPerfPublicContext **)); - if (ptmp == NULL) { - SCFree(pctmi->head); - pctmi->head = NULL; + temp->ctx = pctx; + + temp->name = SCStrdup(tv->name); + if (unlikely(temp->name == NULL)) { + SCFree(temp); SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); return 0; } - pctmi->head = ptmp; - - hpctx = pctmi->head; - hpctx[pctmi->size] = pctx; - for (u = pctmi->size - 1; u > 0; u--) { - if (pctx->curr_id <= hpctx[u]->curr_id) { - hpctx[u + 1] = hpctx[u]; - hpctx[u] = pctx; - continue; + if (tv->thread_group_name != NULL) { + temp->tm_name = SCStrdup(tv->thread_group_name); + if (unlikely(temp->tm_name == NULL)) { + SCFree(temp->name); + SCFree(temp); + SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); + return 0; } - break; } - pctmi->size++; - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); + temp->next = sc_perf_op_ctx->pctmi; + sc_perf_op_ctx->pctmi = temp; + SCLogInfo("sc_perf_op_ctx->pctmi %p", sc_perf_op_ctx->pctmi); + SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); return 1; } @@ -1207,9 +1182,7 @@ int SCPerfSetupPrivate(ThreadVars *tv) { SCPerfGetAllCountersArray(&(tv)->perf_public_ctx, &(tv)->perf_private_ctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, - &(tv)->perf_public_ctx); + SCPerfAddToClubbedTMTable(tv, &(tv)->perf_public_ctx); return 0; } @@ -1274,7 +1247,7 @@ uint64_t SCPerfGetLocalCounterValue(ThreadVars *tv, uint16_t id) #ifdef DEBUG BUG_ON ((id < 1) || (id > pca->size)); #endif - return pca->head[id].ui64_cnt; + return pca->head[id].value; } /** @@ -1466,7 +1439,7 @@ static int SCPerfTestUpdateCounter08() SCPerfCounterIncr(&tv, id); SCPerfCounterAddUI64(&tv, id, 100); - result = pca->head[id].ui64_cnt; + result = pca->head[id].value; SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); SCPerfReleasePCA(pca); @@ -1500,7 +1473,7 @@ static int SCPerfTestUpdateCounter09() SCPerfCounterIncr(&tv, id2); SCPerfCounterAddUI64(&tv, id2, 100); - result = (pca->head[id1].ui64_cnt == 0) && (pca->head[id2].ui64_cnt == 101); + result = (pca->head[id1].value == 0) && (pca->head[id2].value == 101); SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); SCPerfReleasePCA(pca); diff --git a/src/counters.h b/src/counters.h index 75fac388961d..877a65798803 100644 --- a/src/counters.h +++ b/src/counters.h @@ -45,7 +45,12 @@ typedef struct SCPerfCounter_ { /* local id for this counter in this tm */ uint16_t id; - uint64_t value; + /* global id */ + uint16_t gid; + + /* counter value(s): copies from the 'private' counter */ + uint64_t value; /**< sum of updates/increments, or 'set' value */ + uint64_t updates; /**< number of updates (for avg) */ /* name of the counter */ char *cname; @@ -86,10 +91,11 @@ typedef struct SCPCAElem_ { /* counter id of the above counter(pc) */ uint16_t id; - uint64_t ui64_cnt; + /* total value of the adds/increments, or exact value in case of 'set' */ + uint64_t value; /* no of times the local counter has been updated */ - uint64_t syncs; + uint64_t updates; } SCPCAElem; /** From b293a4b7d0ce06aeafdd41e0b3687a3e1357c655 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 24 May 2015 14:04:45 +0200 Subject: [PATCH 0495/2553] counters: remove unused description --- src/app-layer.c | 6 ++-- src/counters.c | 82 ++++++++++++++++++------------------------ src/counters.h | 9 ++--- src/decode.c | 64 ++++++++++++++++----------------- src/detect-engine.c | 20 +++++------ src/flow-manager.c | 25 ++++++------- src/source-af-packet.c | 8 ++--- src/source-erf-dag.c | 4 +-- src/source-mpipe.c | 30 ++++++---------- src/source-netmap.c | 8 ++--- src/source-nflog.c | 6 ++-- src/source-pcap.c | 24 ++++--------- src/source-pfring.c | 8 ++--- src/stream-tcp.c | 48 +++++++++---------------- 14 files changed, 135 insertions(+), 207 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index c14e5f4a508a..1f8590f5132b 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -604,11 +604,11 @@ AppLayerThreadCtx *AppLayerGetCtxThread(ThreadVars *tv) /* tv is allowed to be NULL in unittests */ if (tv != NULL) { app_tctx->counter_dns_memuse = SCPerfTVRegisterCounter("dns.memuse", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); app_tctx->counter_dns_memcap_state = SCPerfTVRegisterCounter("dns.memcap_state", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); app_tctx->counter_dns_memcap_global = SCPerfTVRegisterCounter("dns.memcap_global", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); } goto done; diff --git a/src/counters.c b/src/counters.c index f61da6abedde..468263720ef9 100644 --- a/src/counters.c +++ b/src/counters.c @@ -497,9 +497,6 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) if (pc->tm_name != NULL) SCFree(pc->tm_name); - if (pc->desc != NULL) - SCFree(pc->desc); - SCFree(pc); } @@ -512,7 +509,6 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) * \param cname Name of the counter, to be registered * \param tm_name Thread module to which this counter belongs * \param type Datatype of this counter variable - * \param desc Description of this counter * \param pctx SCPerfPublicContext for this tm-tv instance * \param type_q Qualifier describing the type of counter to be registered * @@ -521,8 +517,8 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) * \retval 0 on failure */ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, - int type, char *desc, - SCPerfPublicContext *pctx, int type_q) + int type, SCPerfPublicContext *pctx, + int type_q) { SCPerfCounter **head = &pctx->head; SCPerfCounter *temp = NULL; @@ -575,11 +571,6 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, * PerfContext. Please note that the id start from 1, and not 0 */ pc->id = ++(pctx->curr_id); - if (desc != NULL && (pc->desc = SCStrdup(desc)) == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - pc->type = type_q; /* we now add the counter to the list */ @@ -887,17 +878,15 @@ void SCPerfSpawnThreads(void) * \param tv Pointer to the ThreadVars instance for which the counter would * be registered * \param type Datatype of this counter variable - * \param desc Description of this counter * * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type, - char *desc) +uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, - type, desc, + type, &tv->perf_public_ctx, SC_PERF_TYPE_Q_NORMAL); @@ -912,17 +901,16 @@ uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type, * \param tv Pointer to the ThreadVars instance for which the counter would * be registered * \param type Datatype of this counter variable - * \param desc Description of this counter * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfTVRegisterAvgCounter(char *cname, struct ThreadVars_ *tv, - int type, char *desc) + int type) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, - type, desc, + type, &tv->perf_public_ctx, SC_PERF_TYPE_Q_AVERAGE); @@ -937,17 +925,16 @@ uint16_t SCPerfTVRegisterAvgCounter(char *cname, struct ThreadVars_ *tv, * \param tv Pointer to the ThreadVars instance for which the counter would * be registered * \param type Datatype of this counter variable - * \param desc Description of this counter * * \retval the counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, - int type, char *desc) + int type) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, - type, desc, + type, &tv->perf_public_ctx, SC_PERF_TYPE_Q_MAXIMUM); @@ -961,17 +948,16 @@ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, * \param tm_name Name of the engine module under which the counter has to be * registered * \param type Datatype of this counter variable - * \param desc Description of this counter * \param pctx SCPerfPublicContext corresponding to the tm_name key under which the * key has to be registered * * \retval id Counter id for the newly registered counter, or the already * present counter */ -static uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, char *desc, +static uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, SCPerfPublicContext *pctx) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, + uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, pctx, SC_PERF_TYPE_Q_NORMAL); return id; @@ -1307,7 +1293,7 @@ static int SCPerfTestCounterReg01() memset(&pctx, 0, sizeof(SCPerfPublicContext)); - return SCPerfRegisterCounter("t1", "c1", 5, NULL, &pctx); + return SCPerfRegisterCounter("t1", "c1", 5, &pctx); } static int SCPerfTestCounterReg02() @@ -1316,7 +1302,7 @@ static int SCPerfTestCounterReg02() memset(&pctx, 0, sizeof(SCPerfPublicContext)); - return SCPerfRegisterCounter(NULL, NULL, SC_PERF_TYPE_UINT64, NULL, &pctx); + return SCPerfRegisterCounter(NULL, NULL, SC_PERF_TYPE_UINT64, &pctx); } static int SCPerfTestCounterReg03() @@ -1326,7 +1312,7 @@ static int SCPerfTestCounterReg03() memset(&pctx, 0, sizeof(SCPerfPublicContext)); - result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); + result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &pctx); SCPerfReleasePerfCounterS(pctx.head); @@ -1340,11 +1326,11 @@ static int SCPerfTestCounterReg04() memset(&pctx, 0, sizeof(SCPerfPublicContext)); - SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); - SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &pctx); - SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, &pctx); + SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &pctx); + SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, &pctx); + SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, &pctx); - result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); + result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &pctx); SCPerfReleasePerfCounterS(pctx.head); @@ -1358,7 +1344,7 @@ static int SCPerfTestGetCntArray05() memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, + id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); if (id != 1) { printf("id %d: ", id); @@ -1377,7 +1363,7 @@ static int SCPerfTestGetCntArray06() memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, + id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); if (id != 1) return 0; @@ -1402,9 +1388,9 @@ static int SCPerfTestCntArraySize07() //pca = (SCPerfPrivateContext *)&tv.perf_private_ctx; - SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, + SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); - SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, + SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); @@ -1430,7 +1416,7 @@ static int SCPerfTestUpdateCounter08() memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, + id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); @@ -1456,15 +1442,15 @@ static int SCPerfTestUpdateCounter09() memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, + id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); - SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, + SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); - SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, + SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); - SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, NULL, + SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); - id2 = SCPerfRegisterCounter("t5", "c5", SC_PERF_TYPE_UINT64, NULL, + id2 = SCPerfRegisterCounter("t5", "c5", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); @@ -1491,11 +1477,11 @@ static int SCPerfTestUpdateGlobalCounter10() memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, + id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); - id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, + id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); - id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, + id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); @@ -1528,13 +1514,13 @@ static int SCPerfTestCounterValues11() memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, + id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); - id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, + id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); - id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, + id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); - id4 = SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, NULL, + id4 = SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); diff --git a/src/counters.h b/src/counters.h index 877a65798803..9a6cc8a29015 100644 --- a/src/counters.h +++ b/src/counters.h @@ -59,9 +59,6 @@ typedef struct SCPerfCounter_ { /* the next perfcounter for this tv's tm instance */ struct SCPerfCounter_ *next; - - /* description of this counter */ - char *desc; } SCPerfCounter; /** @@ -117,9 +114,9 @@ void SCPerfSpawnThreads(void); void SCPerfRegisterTests(void); /* counter registration functions */ -uint16_t SCPerfTVRegisterCounter(char *, struct ThreadVars_ *, int, char *); -uint16_t SCPerfTVRegisterAvgCounter(char *, struct ThreadVars_ *, int, char *); -uint16_t SCPerfTVRegisterMaxCounter(char *, struct ThreadVars_ *, int, char *); +uint16_t SCPerfTVRegisterCounter(char *, struct ThreadVars_ *, int); +uint16_t SCPerfTVRegisterAvgCounter(char *, struct ThreadVars_ *, int); +uint16_t SCPerfTVRegisterMaxCounter(char *, struct ThreadVars_ *, int); /* utility functions */ int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfPublicContext *); diff --git a/src/decode.c b/src/decode.c index f578994cdeee..4e2613e79fd0 100644 --- a/src/decode.c +++ b/src/decode.c @@ -371,77 +371,77 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) { /* register counters */ dtv->counter_pkts = SCPerfTVRegisterCounter("decoder.pkts", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_bytes = SCPerfTVRegisterCounter("decoder.bytes", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_invalid = SCPerfTVRegisterCounter("decoder.invalid", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_ipv4 = SCPerfTVRegisterCounter("decoder.ipv4", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_ipv6 = SCPerfTVRegisterCounter("decoder.ipv6", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_eth = SCPerfTVRegisterCounter("decoder.ethernet", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_raw = SCPerfTVRegisterCounter("decoder.raw", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_null = SCPerfTVRegisterCounter("decoder.null", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_sll = SCPerfTVRegisterCounter("decoder.sll", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_tcp = SCPerfTVRegisterCounter("decoder.tcp", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_udp = SCPerfTVRegisterCounter("decoder.udp", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_sctp = SCPerfTVRegisterCounter("decoder.sctp", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_icmpv4 = SCPerfTVRegisterCounter("decoder.icmpv4", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_icmpv6 = SCPerfTVRegisterCounter("decoder.icmpv6", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_ppp = SCPerfTVRegisterCounter("decoder.ppp", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_pppoe = SCPerfTVRegisterCounter("decoder.pppoe", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_gre = SCPerfTVRegisterCounter("decoder.gre", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_vlan = SCPerfTVRegisterCounter("decoder.vlan", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_vlan_qinq = SCPerfTVRegisterCounter("decoder.vlan_qinq", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_teredo = SCPerfTVRegisterCounter("decoder.teredo", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_ipv4inipv6 = SCPerfTVRegisterCounter("decoder.ipv4_in_ipv6", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_ipv6inipv6 = SCPerfTVRegisterCounter("decoder.ipv6_in_ipv6", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_mpls = SCPerfTVRegisterCounter("decoder.mpls", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_avg_pkt_size = SCPerfTVRegisterAvgCounter("decoder.avg_pkt_size", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_max_pkt_size = SCPerfTVRegisterMaxCounter("decoder.max_pkt_size", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_defrag_ipv4_fragments = SCPerfTVRegisterCounter("defrag.ipv4.fragments", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_defrag_ipv4_reassembled = SCPerfTVRegisterCounter("defrag.ipv4.reassembled", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_defrag_ipv4_timeouts = SCPerfTVRegisterCounter("defrag.ipv4.timeouts", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_defrag_ipv6_fragments = SCPerfTVRegisterCounter("defrag.ipv6.fragments", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_defrag_ipv6_reassembled = SCPerfTVRegisterCounter("defrag.ipv6.reassembled", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_defrag_ipv6_timeouts = SCPerfTVRegisterCounter("defrag.ipv6.timeouts", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); dtv->counter_defrag_max_hit = SCPerfTVRegisterCounter("defrag.max_frag_hits", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); return; } diff --git a/src/detect-engine.c b/src/detect-engine.c index ba02dfa228f1..355cdef9d141 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1348,16 +1348,16 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) /* first register the counter. In delayed detect mode we exit right after if the * rules haven't been loaded yet. */ uint16_t counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); #ifdef PROFILING uint16_t counter_mpm_list = SCPerfTVRegisterAvgCounter("detect.mpm_list", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); uint16_t counter_nonmpm_list = SCPerfTVRegisterAvgCounter("detect.nonmpm_list", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); uint16_t counter_fnonmpm_list = SCPerfTVRegisterAvgCounter("detect.fnonmpm_list", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); uint16_t counter_match_list = SCPerfTVRegisterAvgCounter("detect.match_list", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); #endif DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); if (unlikely(det_ctx == NULL)) @@ -1432,16 +1432,16 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( /** alert counter setup */ det_ctx->counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); #ifdef PROFILING uint16_t counter_mpm_list = SCPerfTVRegisterAvgCounter("detect.mpm_list", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); uint16_t counter_nonmpm_list = SCPerfTVRegisterAvgCounter("detect.nonmpm_list", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); uint16_t counter_fnonmpm_list = SCPerfTVRegisterAvgCounter("detect.fnonmpm_list", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); uint16_t counter_match_list = SCPerfTVRegisterAvgCounter("detect.match_list", tv, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); det_ctx->counter_mpm_list = counter_mpm_list; det_ctx->counter_nonmpm_list = counter_nonmpm_list; det_ctx->counter_fnonmpm_list = counter_fnonmpm_list; diff --git a/src/flow-manager.c b/src/flow-manager.c index 48dba4efbaec..71bdef657237 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -525,21 +525,21 @@ static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) *data = ftd; ftd->flow_mgr_cnt_clo = SCPerfTVRegisterCounter("flow_mgr.closed_pruned", t, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); ftd->flow_mgr_cnt_new = SCPerfTVRegisterCounter("flow_mgr.new_pruned", t, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); ftd->flow_mgr_cnt_est = SCPerfTVRegisterCounter("flow_mgr.est_pruned", t, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); ftd->flow_mgr_memuse = SCPerfTVRegisterCounter("flow.memuse", t, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); ftd->flow_mgr_spare = SCPerfTVRegisterCounter("flow.spare", t, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); ftd->flow_emerg_mode_enter = SCPerfTVRegisterCounter("flow.emerg_mode_entered", t, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); ftd->flow_emerg_mode_over = SCPerfTVRegisterCounter("flow.emerg_mode_over", t, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); ftd->flow_tcp_reuse = SCPerfTVRegisterCounter("flow.tcp_reuse", t, - SC_PERF_TYPE_UINT64, "NULL"); + SC_PERF_TYPE_UINT64); PacketPoolInit(); return TM_ECODE_OK; @@ -576,14 +576,11 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) /* VJ leaving disabled for now, as hosts are only used by tags and the numbers * are really low. Might confuse ppl uint16_t flow_mgr_host_prune = SCPerfTVRegisterCounter("hosts.pruned", th_v, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); uint16_t flow_mgr_host_active = SCPerfTVRegisterCounter("hosts.active", th_v, - SC_PERF_TYPE_Q_NORMAL, - "NULL"); + SC_PERF_TYPE_UINT64); uint16_t flow_mgr_host_spare = SCPerfTVRegisterCounter("hosts.spare", th_v, - SC_PERF_TYPE_Q_NORMAL, - "NULL"); + SC_PERF_TYPE_UINT64); */ memset(&ts, 0, sizeof(ts)); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index d49898dfcff3..3b50ba8f3167 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1715,13 +1715,9 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) #ifdef PACKET_STATISTICS ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->tv, SC_PERF_TYPE_UINT64); ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->tv, SC_PERF_TYPE_UINT64); #endif char *active_runmode = RunmodeGetActive(); diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index fbe21fe855f5..55b273e0aa9b 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -305,9 +305,9 @@ ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) } ewtn->packets = SCPerfTVRegisterCounter("capture.dag_packets", - tv, SC_PERF_TYPE_UINT64, "NULL"); + tv, SC_PERF_TYPE_UINT64); ewtn->drops = SCPerfTVRegisterCounter("capture.dag_drops", - tv, SC_PERF_TYPE_UINT64, "NULL"); + tv, SC_PERF_TYPE_UINT64); ewtn->tv = tv; *data = (void *)ewtn; diff --git a/src/source-mpipe.c b/src/source-mpipe.c index f55f42184659..665282605e9f 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -438,36 +438,26 @@ static void MpipeRegisterPerfCounters(MpipeThreadVars *ptv, ThreadVars *tv) /* register counters */ ptv->max_mpipe_depth = SCPerfTVRegisterCounter("mpipe.max_mpipe_depth", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); ptv->mpipe_drop = SCPerfTVRegisterCounter("mpipe.drop", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); ptv->counter_no_buffers_0 = SCPerfTVRegisterCounter("mpipe.no_buf0", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); ptv->counter_no_buffers_1 = SCPerfTVRegisterCounter("mpipe.no_buf1", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); ptv->counter_no_buffers_2 = SCPerfTVRegisterCounter("mpipe.no_buf2", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); ptv->counter_no_buffers_3 = SCPerfTVRegisterCounter("mpipe.no_buf3", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); ptv->counter_no_buffers_4 = SCPerfTVRegisterCounter("mpipe.no_buf4", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); ptv->counter_no_buffers_5 = SCPerfTVRegisterCounter("mpipe.no_buf5", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); ptv->counter_no_buffers_6 = SCPerfTVRegisterCounter("mpipe.no_buf6", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); ptv->counter_no_buffers_7 = SCPerfTVRegisterCounter("mpipe.no_buf7", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); } static const gxio_mpipe_buffer_size_enum_t gxio_buffer_sizes[] = { diff --git a/src/source-netmap.c b/src/source-netmap.c index db853e19194d..adf330fc67f7 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -555,13 +555,9 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da /* basic counters */ ntv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ntv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ntv->tv, SC_PERF_TYPE_UINT64); ntv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ntv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ntv->tv, SC_PERF_TYPE_UINT64); char const *active_runmode = RunmodeGetActive(); if (active_runmode && !strcmp("workers", active_runmode)) { diff --git a/src/source-nflog.c b/src/source-nflog.c index d068acbb9dff..98406ed504be 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -309,12 +309,10 @@ TmEcode ReceiveNFLOGThreadInit(ThreadVars *tv, void *initdata, void **data) #ifdef PACKET_STATISTICS ntv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", ntv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); ntv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", ntv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); #endif char *active_runmode = RunmodeGetActive(); diff --git a/src/source-pcap.c b/src/source-pcap.c index 7a551d16ac22..57237fed1440 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -522,17 +522,11 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) pcapconfig->DerefFunc(pcapconfig); ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->tv, SC_PERF_TYPE_UINT64); ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->tv, SC_PERF_TYPE_UINT64); ptv->capture_kernel_ifdrops = SCPerfTVRegisterCounter("capture.kernel_ifdrops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->tv, SC_PERF_TYPE_UINT64); *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); @@ -627,17 +621,11 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->datalink = pcap_datalink(ptv->pcap_handle); ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->tv, SC_PERF_TYPE_UINT64); ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->tv, SC_PERF_TYPE_UINT64); ptv->capture_kernel_ifdrops = SCPerfTVRegisterCounter("capture.kernel_ifdrops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->tv, SC_PERF_TYPE_UINT64); *data = (void *)ptv; diff --git a/src/source-pfring.c b/src/source-pfring.c index e0e9001960b6..a7f1342a5c71 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -498,13 +498,9 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) } ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->tv, SC_PERF_TYPE_UINT64); ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->tv, SC_PERF_TYPE_UINT64); /* A bit strange to have this here but we only have vlan information * during reading so we need to know if we want to keep vlan during diff --git a/src/stream-tcp.c b/src/stream-tcp.c index c7d1098ed12c..5586c7a52c85 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5073,35 +5073,25 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) *data = (void *)stt; stt->counter_tcp_sessions = SCPerfTVRegisterCounter("tcp.sessions", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->counter_tcp_ssn_memcap = SCPerfTVRegisterCounter("tcp.ssn_memcap_drop", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->counter_tcp_pseudo = SCPerfTVRegisterCounter("tcp.pseudo", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->counter_tcp_pseudo_failed = SCPerfTVRegisterCounter("tcp.pseudo_failed", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->counter_tcp_invalid_checksum = SCPerfTVRegisterCounter("tcp.invalid_checksum", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->counter_tcp_no_flow = SCPerfTVRegisterCounter("tcp.no_flow", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->counter_tcp_memuse = SCPerfTVRegisterCounter("tcp.memuse", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->counter_tcp_syn = SCPerfTVRegisterCounter("tcp.syn", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->counter_tcp_synack = SCPerfTVRegisterCounter("tcp.synack", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->counter_tcp_rst = SCPerfTVRegisterCounter("tcp.rst", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); /* init reassembly ctx */ stt->ra_ctx = StreamTcpReassembleInitThreadCtx(tv); @@ -5109,24 +5099,18 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_FAILED); stt->ra_ctx->counter_tcp_segment_memcap = SCPerfTVRegisterCounter("tcp.segment_memcap_drop", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->ra_ctx->counter_tcp_stream_depth = SCPerfTVRegisterCounter("tcp.stream_depth_reached", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->ra_ctx->counter_tcp_reass_memuse = SCPerfTVRegisterCounter("tcp.reassembly_memuse", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->ra_ctx->counter_tcp_reass_gap = SCPerfTVRegisterCounter("tcp.reassembly_gap", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); /** \fixme Find a better place in 2.1 as it is linked with app layer */ stt->ra_ctx->counter_htp_memuse = SCPerfTVRegisterCounter("http.memuse", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); stt->ra_ctx->counter_htp_memcap = SCPerfTVRegisterCounter("http.memcap", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + SC_PERF_TYPE_UINT64); SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p", stt, stt->ra_ctx); From 9bbef55c4d0c5e8204c3b58a532cbb826afea5b7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 7 Jan 2015 19:57:18 +0100 Subject: [PATCH 0496/2553] Fix harmless typo in IPOnlyCIDRItemNew's SCReturnPtr use --- src/detect-engine-iponly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index bc876a188844..bfbbb0f4b33a 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -73,7 +73,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRItemNew() item = SCMalloc(sizeof(IPOnlyCIDRItem)); if (unlikely(item == NULL)) - SCReturnPtr(NULL, "NULL"); + SCReturnPtr(NULL, "IPOnlyCIDRItem"); memset(item, 0, sizeof(IPOnlyCIDRItem)); SCReturnPtr(item, "IPOnlyCIDRItem"); From 06461e37dada97c72718cafdff1ff689b94fc7dc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 24 May 2015 17:23:48 +0200 Subject: [PATCH 0497/2553] counters: global counters registration --- src/counters.c | 38 +++++++++++++++++++++++++++++++------- src/counters.h | 5 +++++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/counters.c b/src/counters.c index 468263720ef9..a0e13f93e670 100644 --- a/src/counters.c +++ b/src/counters.c @@ -58,7 +58,9 @@ enum { SC_PERF_TYPE_Q_NORMAL = 1, SC_PERF_TYPE_Q_AVERAGE = 2, SC_PERF_TYPE_Q_MAXIMUM = 3, - SC_PERF_TYPE_Q_MAX = 4, + SC_PERF_TYPE_Q_FUNC = 4, + + SC_PERF_TYPE_Q_MAX = 5, }; /** @@ -95,6 +97,9 @@ typedef struct SCPerfOPIfaceContext_ { SCPerfClubTMInst *pctmi; SCMutex pctmi_lock; HashTable *counters_id_hash; + + //SCPerfCounter *global_counters; + SCPerfPublicContext global_counter_ctx; } SCPerfOPIfaceContext; static void *stats_thread_data = NULL; @@ -518,7 +523,7 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) */ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, int type, SCPerfPublicContext *pctx, - int type_q) + int type_q, uint64_t (*Func)(void)) { SCPerfCounter **head = &pctx->head; SCPerfCounter *temp = NULL; @@ -888,7 +893,7 @@ uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type) (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, &tv->perf_public_ctx, - SC_PERF_TYPE_Q_NORMAL); + SC_PERF_TYPE_Q_NORMAL, NULL); return id; } @@ -912,7 +917,7 @@ uint16_t SCPerfTVRegisterAvgCounter(char *cname, struct ThreadVars_ *tv, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, &tv->perf_public_ctx, - SC_PERF_TYPE_Q_AVERAGE); + SC_PERF_TYPE_Q_AVERAGE, NULL); return id; } @@ -936,11 +941,30 @@ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, &tv->perf_public_ctx, - SC_PERF_TYPE_Q_MAXIMUM); + SC_PERF_TYPE_Q_MAXIMUM, NULL); return id; } +/** + * \brief Registers a counter, which represents a global value + * + * \param cname Name of the counter, to be registered + * \param Func Function Pointer returning a uint64_t + * + * \retval id Counter id for the newly registered counter, or the already + * present counter + */ +uint16_t SCPerfTVRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)) +{ + uint16_t id = SCPerfRegisterQualifiedCounter(cname, NULL, + SC_PERF_TYPE_UINT64, + &(sc_perf_op_ctx->global_counter_ctx), + SC_PERF_TYPE_Q_FUNC, + Func); + return id; +} + /** * \brief Registers a normal, unqualified counter * @@ -957,8 +981,8 @@ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, static uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, SCPerfPublicContext *pctx) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, - pctx, SC_PERF_TYPE_Q_NORMAL); + uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, pctx, + SC_PERF_TYPE_Q_NORMAL, NULL); return id; } diff --git a/src/counters.h b/src/counters.h index 9a6cc8a29015..30f44d4cfea7 100644 --- a/src/counters.h +++ b/src/counters.h @@ -52,6 +52,10 @@ typedef struct SCPerfCounter_ { uint64_t value; /**< sum of updates/increments, or 'set' value */ uint64_t updates; /**< number of updates (for avg) */ + /* when using type SC_PERF_TYPE_Q_FUNC this function is called once + * to get the counter value, regardless of how many threads there are. */ + uint64_t (*Func)(void); + /* name of the counter */ char *cname; /* name of the thread module this counter is registered to */ @@ -117,6 +121,7 @@ void SCPerfRegisterTests(void); uint16_t SCPerfTVRegisterCounter(char *, struct ThreadVars_ *, int); uint16_t SCPerfTVRegisterAvgCounter(char *, struct ThreadVars_ *, int); uint16_t SCPerfTVRegisterMaxCounter(char *, struct ThreadVars_ *, int); +uint16_t SCPerfTVRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)); /* utility functions */ int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfPublicContext *); From b5bd3dee1385e30b2c5cf2c39b2e4675fc808672 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 7 Jan 2015 23:00:52 +0100 Subject: [PATCH 0498/2553] stream: make tcp.reassembly_memuse counter global Fixes bugs #632 and #1178 --- src/stream-tcp-reassemble.c | 10 +++++----- src/stream-tcp-reassemble.h | 2 -- src/stream-tcp.c | 3 +-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 20074e6807c7..7331db1bd3b7 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -135,12 +135,10 @@ void StreamTcpReassembleDecrMemuse(uint64_t size) return; } -void StreamTcpReassembleMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *rtv) +uint64_t StreamTcpReassembleMemuseGlobalCounter(void) { uint64_t smemuse = SC_ATOMIC_GET(ra_memuse); - if (tv != NULL && rtv != NULL) - SCPerfCounterSetUI64(tv, rtv->counter_tcp_reass_memuse, smemuse); - return; + return smemuse; } /** @@ -515,6 +513,9 @@ int StreamTcpReassembleInit(char quiet) SCMutexInit(&segment_pool_memuse_mutex, NULL); SCMutexInit(&segment_pool_cnt_mutex, NULL); #endif + + SCPerfTVRegisterGlobalCounter("tcp.reassembly_memuse", + StreamTcpReassembleMemuseGlobalCounter); return 0; } @@ -3419,7 +3420,6 @@ int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ } } - StreamTcpReassembleMemuseCounter(tv, ra_ctx); SCReturnInt(0); } diff --git a/src/stream-tcp-reassemble.h b/src/stream-tcp-reassemble.h index c934f4fabd83..c5e926fc9c91 100644 --- a/src/stream-tcp-reassemble.h +++ b/src/stream-tcp-reassemble.h @@ -57,8 +57,6 @@ typedef struct TcpReassemblyThreadCtx_ { uint16_t counter_tcp_segment_memcap; /** number of streams that stop reassembly because their depth is reached */ uint16_t counter_tcp_stream_depth; - /** account memory usage for the reassembly portion of the stream engine */ - uint16_t counter_tcp_reass_memuse; /** count number of streams with a unrecoverable stream gap (missing pkts) */ uint16_t counter_tcp_reass_gap; /** account memory usage by suricata to handle HTTP protocol (not counting diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 5586c7a52c85..2136a8f5d525 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -115,6 +115,7 @@ static SCMutex ssn_pool_mutex = SCMUTEX_INITIALIZER; /**< init only, protect ini static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */ #endif +uint64_t StreamTcpReassembleMemuseGlobalCounter(void); SC_ATOMIC_DECLARE(uint64_t, st_memuse); /* stream engine running in "inline" mode. */ @@ -5102,8 +5103,6 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) SC_PERF_TYPE_UINT64); stt->ra_ctx->counter_tcp_stream_depth = SCPerfTVRegisterCounter("tcp.stream_depth_reached", tv, SC_PERF_TYPE_UINT64); - stt->ra_ctx->counter_tcp_reass_memuse = SCPerfTVRegisterCounter("tcp.reassembly_memuse", tv, - SC_PERF_TYPE_UINT64); stt->ra_ctx->counter_tcp_reass_gap = SCPerfTVRegisterCounter("tcp.reassembly_gap", tv, SC_PERF_TYPE_UINT64); /** \fixme Find a better place in 2.1 as it is linked with app layer */ From 2346a88db7c659c9033e121df041d415de8b4c15 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 24 May 2015 17:58:13 +0200 Subject: [PATCH 0499/2553] counters: remove thread module name from counters API --- src/counters.c | 21 +-------------------- src/counters.h | 2 -- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/counters.c b/src/counters.c index a0e13f93e670..a74f99efb80d 100644 --- a/src/counters.c +++ b/src/counters.c @@ -499,9 +499,6 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) if (pc->cname != NULL) SCFree(pc->cname); - if (pc->tm_name != NULL) - SCFree(pc->tm_name); - SCFree(pc); } @@ -545,8 +542,7 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, while (temp != NULL) { prev = temp; - if (strcmp(cname, temp->cname) == 0 && - strcmp(tm_name, temp->tm_name) == 0) { + if (strcmp(cname, temp->cname) == 0) { break; } @@ -567,11 +563,6 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, exit(EXIT_FAILURE); } - if ( (pc->tm_name = SCStrdup(tm_name)) == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - /* assign a unique id to this SCPerfCounter. The id is local to this * PerfContext. Please note that the id start from 1, and not 0 */ pc->id = ++(pctx->curr_id); @@ -1099,16 +1090,6 @@ static int SCPerfAddToClubbedTMTable(ThreadVars *tv, SCPerfPublicContext *pctx) return 0; } - if (tv->thread_group_name != NULL) { - temp->tm_name = SCStrdup(tv->thread_group_name); - if (unlikely(temp->tm_name == NULL)) { - SCFree(temp->name); - SCFree(temp); - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 0; - } - } - temp->next = sc_perf_op_ctx->pctmi; sc_perf_op_ctx->pctmi = temp; SCLogInfo("sc_perf_op_ctx->pctmi %p", sc_perf_op_ctx->pctmi); diff --git a/src/counters.h b/src/counters.h index 30f44d4cfea7..527c011be9dc 100644 --- a/src/counters.h +++ b/src/counters.h @@ -58,8 +58,6 @@ typedef struct SCPerfCounter_ { /* name of the counter */ char *cname; - /* name of the thread module this counter is registered to */ - char *tm_name; /* the next perfcounter for this tv's tm instance */ struct SCPerfCounter_ *next; From 0478407833fe1328fa2014804c89fec87c44da1b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 24 May 2015 18:32:58 +0200 Subject: [PATCH 0500/2553] counters: remove threadvars arg from SCPerfAddToClubbedTMTable --- src/counters.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/counters.c b/src/counters.c index a74f99efb80d..309a290da1ce 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1038,7 +1038,7 @@ void CountersIdHashFreeFunc(void *data) * * \retval 1 on success, 0 on failure */ -static int SCPerfAddToClubbedTMTable(ThreadVars *tv, SCPerfPublicContext *pctx) +static int SCPerfAddToClubbedTMTable(const char *thread_name, SCPerfPublicContext *pctx) { if (sc_perf_op_ctx == NULL) { SCLogDebug("Counter module has been disabled"); @@ -1047,7 +1047,7 @@ static int SCPerfAddToClubbedTMTable(ThreadVars *tv, SCPerfPublicContext *pctx) SCPerfClubTMInst *temp = NULL; - if (tv == NULL || pctx == NULL) { + if (thread_name == NULL || pctx == NULL) { SCLogDebug("supplied argument(s) to SCPerfAddToClubbedTMTable NULL"); return 0; } @@ -1083,7 +1083,7 @@ static int SCPerfAddToClubbedTMTable(ThreadVars *tv, SCPerfPublicContext *pctx) temp->ctx = pctx; - temp->name = SCStrdup(tv->name); + temp->name = SCStrdup(thread_name); if (unlikely(temp->name == NULL)) { SCFree(temp); SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); @@ -1173,7 +1173,7 @@ int SCPerfSetupPrivate(ThreadVars *tv) { SCPerfGetAllCountersArray(&(tv)->perf_public_ctx, &(tv)->perf_private_ctx); - SCPerfAddToClubbedTMTable(tv, &(tv)->perf_public_ctx); + SCPerfAddToClubbedTMTable(tv->name, &(tv)->perf_public_ctx); return 0; } From f300ad253ee88337d3e388540f1375a109fb6e38 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 24 May 2015 18:38:39 +0200 Subject: [PATCH 0501/2553] counters: simplify and speedup counters sync --- src/counters.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/counters.c b/src/counters.c index 309a290da1ce..27056b6fd33c 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1188,7 +1188,6 @@ int SCPerfSetupPrivate(ThreadVars *tv) */ int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, SCPerfPublicContext *pctx) { - SCPerfCounter *pc = NULL; SCPCAElem *pcae = NULL; uint32_t i = 0; @@ -1200,22 +1199,9 @@ int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, SCPerfPublicContext *pct pcae = pca->head; SCMutexLock(&pctx->m); - pc = pctx->head; - for (i = 1; i <= pca->size; i++) { - while (pc != NULL) { - if (pc->id != pcae[i].id) { - pc = pc->next; - continue; - } - - SCPerfCopyCounterValue(&pcae[i]); - - pc = pc->next; - break; - } + SCPerfCopyCounterValue(&pcae[i]); } - SCMutexUnlock(&pctx->m); pctx->perf_flag = 0; From d05eed3735886d7df28299fac3f3d77285a6725c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 24 May 2015 20:18:02 +0200 Subject: [PATCH 0502/2553] counters: start using Stats prefix --- src/counters.c | 86 ++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 49 deletions(-) diff --git a/src/counters.c b/src/counters.c index 27056b6fd33c..b0b565a1ba34 100644 --- a/src/counters.c +++ b/src/counters.c @@ -21,7 +21,7 @@ * \author Anoop Saldanha * \author Victor Julien * - * Performance counters + * Engine stats API */ #include "suricata-common.h" @@ -55,29 +55,18 @@ * of the Perf counter to be registered */ enum { - SC_PERF_TYPE_Q_NORMAL = 1, - SC_PERF_TYPE_Q_AVERAGE = 2, - SC_PERF_TYPE_Q_MAXIMUM = 3, - SC_PERF_TYPE_Q_FUNC = 4, + STATS_TYPE_NORMAL = 1, + STATS_TYPE_AVERAGE = 2, + STATS_TYPE_MAXIMUM = 3, + STATS_TYPE_FUNC = 4, - SC_PERF_TYPE_Q_MAX = 5, + STATS_TYPE_MAX = 5, }; /** - * \brief Different output interfaces made available by the Perf counter API + * \brief per thread store of counters */ -enum { - SC_PERF_IFACE_FILE, - SC_PERF_IFACE_CONSOLE, - SC_PERF_IFACE_SYSLOG, - SC_PERF_IFACE_MAX, -}; - -/** - * \brief Holds multiple instances of the same TM together, used when the stats - * have to be clubbed based on TM, before being sent out - */ -typedef struct SCPerfClubTMInst_ { +typedef struct StatsThreadStore_ { char *name; char *tm_name; @@ -87,23 +76,22 @@ typedef struct SCPerfClubTMInst_ { SCPerfPublicContext **head; uint32_t size; - struct SCPerfClubTMInst_ *next; -} SCPerfClubTMInst; + struct StatsThreadStore_ *next; +} StatsThreadStore; /** * \brief Holds the output interface context for the counter api */ -typedef struct SCPerfOPIfaceContext_ { - SCPerfClubTMInst *pctmi; +typedef struct StatsGlobalContext_ { + StatsThreadStore *pctmi; SCMutex pctmi_lock; HashTable *counters_id_hash; - //SCPerfCounter *global_counters; SCPerfPublicContext global_counter_ctx; -} SCPerfOPIfaceContext; +} StatsGlobalContext; static void *stats_thread_data = NULL; -static SCPerfOPIfaceContext *sc_perf_op_ctx = NULL; +static StatsGlobalContext *sc_perf_op_ctx = NULL; static time_t sc_start_time; /** refresh interval in seconds */ static uint32_t sc_counter_tts = SC_PERF_MGMTT_TTS; @@ -187,10 +175,10 @@ void SCPerfCounterSetUI64(ThreadVars *tv, uint16_t id, uint64_t x) BUG_ON ((id < 1) || (id > pca->size)); #endif - if ((pca->head[id].pc->type == SC_PERF_TYPE_Q_MAXIMUM) && + if ((pca->head[id].pc->type == STATS_TYPE_MAXIMUM) && (x > pca->head[id].value)) { pca->head[id].value = x; - } else if (pca->head[id].pc->type == SC_PERF_TYPE_Q_NORMAL) { + } else if (pca->head[id].pc->type == STATS_TYPE_NORMAL) { pca->head[id].value = x; } @@ -224,11 +212,11 @@ static ConfNode *GetConfig(void) { static void SCPerfInitOPCtx(void) { SCEnter(); - if ( (sc_perf_op_ctx = SCMalloc(sizeof(SCPerfOPIfaceContext))) == NULL) { + if ( (sc_perf_op_ctx = SCMalloc(sizeof(StatsGlobalContext))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCPerfInitOPCtx. Exiting..."); exit(EXIT_FAILURE); } - memset(sc_perf_op_ctx, 0, sizeof(SCPerfOPIfaceContext)); + memset(sc_perf_op_ctx, 0, sizeof(StatsGlobalContext)); ConfNode *stats = GetConfig(); if (stats != NULL) { @@ -252,7 +240,7 @@ static void SCPerfInitOPCtx(void) /* Store the engine start time */ time(&sc_start_time); - /* init the lock used by SCPerfClubTMInst */ + /* init the lock used by StatsThreadStore */ if (SCMutexInit(&sc_perf_op_ctx->pctmi_lock, NULL) != 0) { SCLogError(SC_ERR_INITIALIZATION, "error initializing pctmi mutex"); exit(EXIT_FAILURE); @@ -272,8 +260,8 @@ static void SCPerfReleaseOPCtx() return; } - SCPerfClubTMInst *pctmi = NULL; - SCPerfClubTMInst *temp = NULL; + StatsThreadStore *pctmi = NULL; + StatsThreadStore *temp = NULL; pctmi = sc_perf_op_ctx->pctmi; while (pctmi != NULL) { @@ -618,7 +606,7 @@ static uint64_t SCPerfOutputCalculateCounterValue(SCPerfCounter *pc) */ static int SCPerfOutputCounterFileIface(ThreadVars *tv) { - const SCPerfClubTMInst *pctmi = NULL; + const StatsThreadStore *pctmi = NULL; const SCPerfCounter *pc = NULL; void *td = stats_thread_data; @@ -661,7 +649,7 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) merge_table[pc->gid].type = pc->type; switch (pc->type) { - case SC_PERF_TYPE_Q_MAXIMUM: + case STATS_TYPE_MAXIMUM: if (pc->value > merge_table[pc->gid].value) merge_table[pc->gid].value = pc->value; break; @@ -688,11 +676,11 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) struct CountersMergeTable *m = &merge_table[x]; switch (m->type) { - case SC_PERF_TYPE_Q_MAXIMUM: + case STATS_TYPE_MAXIMUM: if (m->value > table[x].value) table[x].value = m->value; break; - case SC_PERF_TYPE_Q_AVERAGE: + case STATS_TYPE_AVERAGE: if (m->value > 0 && m->updates > 0) { table[x].value = (uint64_t)(m->value / m->updates); } @@ -715,7 +703,7 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) TmEcode SCPerfOutputCounterSocket(json_t *cmd, json_t *answer, void *data) { - SCPerfClubTMInst *pctmi = NULL; + StatsThreadStore *pctmi = NULL; SCPerfCounter *pc = NULL; SCPerfCounter **pc_heads = NULL; @@ -884,7 +872,7 @@ uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type) (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, &tv->perf_public_ctx, - SC_PERF_TYPE_Q_NORMAL, NULL); + STATS_TYPE_NORMAL, NULL); return id; } @@ -908,7 +896,7 @@ uint16_t SCPerfTVRegisterAvgCounter(char *cname, struct ThreadVars_ *tv, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, &tv->perf_public_ctx, - SC_PERF_TYPE_Q_AVERAGE, NULL); + STATS_TYPE_AVERAGE, NULL); return id; } @@ -932,7 +920,7 @@ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, &tv->perf_public_ctx, - SC_PERF_TYPE_Q_MAXIMUM, NULL); + STATS_TYPE_MAXIMUM, NULL); return id; } @@ -951,7 +939,7 @@ uint16_t SCPerfTVRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)) uint16_t id = SCPerfRegisterQualifiedCounter(cname, NULL, SC_PERF_TYPE_UINT64, &(sc_perf_op_ctx->global_counter_ctx), - SC_PERF_TYPE_Q_FUNC, + STATS_TYPE_FUNC, Func); return id; } @@ -973,7 +961,7 @@ static uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, SCPerfPublicContext *pctx) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, pctx, - SC_PERF_TYPE_Q_NORMAL, NULL); + STATS_TYPE_NORMAL, NULL); return id; } @@ -1038,17 +1026,17 @@ void CountersIdHashFreeFunc(void *data) * * \retval 1 on success, 0 on failure */ -static int SCPerfAddToClubbedTMTable(const char *thread_name, SCPerfPublicContext *pctx) +static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pctx) { if (sc_perf_op_ctx == NULL) { SCLogDebug("Counter module has been disabled"); return 0; } - SCPerfClubTMInst *temp = NULL; + StatsThreadStore *temp = NULL; if (thread_name == NULL || pctx == NULL) { - SCLogDebug("supplied argument(s) to SCPerfAddToClubbedTMTable NULL"); + SCLogDebug("supplied argument(s) to StatsThreadRegister NULL"); return 0; } @@ -1075,11 +1063,11 @@ static int SCPerfAddToClubbedTMTable(const char *thread_name, SCPerfPublicContex } - if ( (temp = SCMalloc(sizeof(SCPerfClubTMInst))) == NULL) { + if ( (temp = SCMalloc(sizeof(StatsThreadStore))) == NULL) { SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); return 0; } - memset(temp, 0, sizeof(SCPerfClubTMInst)); + memset(temp, 0, sizeof(StatsThreadStore)); temp->ctx = pctx; @@ -1173,7 +1161,7 @@ int SCPerfSetupPrivate(ThreadVars *tv) { SCPerfGetAllCountersArray(&(tv)->perf_public_ctx, &(tv)->perf_private_ctx); - SCPerfAddToClubbedTMTable(tv->name, &(tv)->perf_public_ctx); + StatsThreadRegister(tv->name, &(tv)->perf_public_ctx); return 0; } From 33756abd87856fb95e06c1a41909cfd77943ca44 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 25 May 2015 11:40:42 +0200 Subject: [PATCH 0503/2553] counters: split API init Split into early ctx initialization and post-config setup. --- src/counters.c | 20 +++++++++++--------- src/counters.h | 3 ++- src/runmode-unix-socket.c | 3 ++- src/suricata.c | 3 ++- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/counters.c b/src/counters.c index b0b565a1ba34..ad11c3c7af12 100644 --- a/src/counters.c +++ b/src/counters.c @@ -212,12 +212,6 @@ static ConfNode *GetConfig(void) { static void SCPerfInitOPCtx(void) { SCEnter(); - if ( (sc_perf_op_ctx = SCMalloc(sizeof(StatsGlobalContext))) == NULL) { - SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCPerfInitOPCtx. Exiting..."); - exit(EXIT_FAILURE); - } - memset(sc_perf_op_ctx, 0, sizeof(StatsGlobalContext)); - ConfNode *stats = GetConfig(); if (stats != NULL) { const char *enabled = ConfNodeLookupChildValue(stats, "enabled"); @@ -797,11 +791,19 @@ TmEcode SCPerfOutputCounterSocket(json_t *cmd, * \brief Initializes the perf counter api. Things are hard coded currently. * More work to be done when we implement multiple interfaces */ -void SCPerfInitCounterApi(void) +void StatsInit(void) { - SCPerfInitOPCtx(); + BUG_ON(sc_perf_op_ctx != NULL); + if ( (sc_perf_op_ctx = SCMalloc(sizeof(StatsGlobalContext))) == NULL) { + SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCPerfInitOPCtx. Exiting..."); + exit(EXIT_FAILURE); + } + memset(sc_perf_op_ctx, 0, sizeof(StatsGlobalContext)); +} - return; +void StatsSetupPostConfig(void) +{ + SCPerfInitOPCtx(); } /** diff --git a/src/counters.h b/src/counters.h index 527c011be9dc..8d9113f68490 100644 --- a/src/counters.h +++ b/src/counters.h @@ -111,7 +111,8 @@ typedef struct SCPerfPrivateContext_ { } SCPerfPrivateContext; /* the initialization functions */ -void SCPerfInitCounterApi(void); +void StatsInit(void); +void StatsSetupPostConfig(void); void SCPerfSpawnThreads(void); void SCPerfRegisterTests(void); diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 42f836cf22ab..a7331bb9c69c 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -344,6 +344,7 @@ TmEcode UnixSocketPcapFilesCheck(void *data) return TM_ECODE_FAILED; } PcapFilesFree(cfile); + StatsInit(); #ifdef PROFILING SCProfilingRulesGlobalInit(); SCProfilingKeywordsGlobalInit(); @@ -354,7 +355,7 @@ TmEcode UnixSocketPcapFilesCheck(void *data) IPPairInitConfig(FLOW_QUIET); StreamTcpInitConfig(STREAM_VERBOSE); RunModeInitializeOutputs(); - SCPerfInitCounterApi(); + StatsSetupPostConfig(); RunModeDispatch(RUNMODE_PCAP_FILE, NULL); FlowManagerThreadSpawn(); FlowRecyclerThreadSpawn(); diff --git a/src/suricata.c b/src/suricata.c index 6a8f0679508d..4e55c3185785 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2203,6 +2203,7 @@ int main(int argc, char **argv) GlobalInits(); TimeInit(); SupportFastPatternForSigMatchTypes(); + StatsInit(); if (conf_filename == NULL) conf_filename = DEFAULT_CONF_FILE; @@ -2302,7 +2303,7 @@ int main(int argc, char **argv) if (suri.run_mode != RUNMODE_UNIX_SOCKET) { RunModeInitializeOutputs(); - SCPerfInitCounterApi(); + StatsSetupPostConfig(); } if (ParseInterfacesList(suri.run_mode, suri.pcap_dev) != TM_ECODE_OK) { From 60c5ad464964126bf309b77560b10c2fcb2d8d0d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 25 May 2015 11:42:41 +0200 Subject: [PATCH 0504/2553] counters: call global counters funcs --- src/counters.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/counters.c b/src/counters.c index ad11c3c7af12..8304eb4034f4 100644 --- a/src/counters.c +++ b/src/counters.c @@ -99,6 +99,7 @@ static uint32_t sc_counter_tts = SC_PERF_MGMTT_TTS; static char sc_counter_enabled = TRUE; static int SCPerfOutputCounterFileIface(ThreadVars *tv); +static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *); /** stats table is filled each interval and passed to the * loggers. Initialized at first use. */ @@ -509,8 +510,8 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, SCPerfCounter *prev = NULL; SCPerfCounter *pc = NULL; - if (cname == NULL || tm_name == NULL || pctx == NULL) { - SCLogDebug("Counter name, tm name null or SCPerfPublicContext NULL"); + if (cname == NULL || pctx == NULL) { + SCLogDebug("Counter name, SCPerfPublicContext NULL"); return 0; } @@ -550,6 +551,7 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, pc->id = ++(pctx->curr_id); pc->type = type_q; + pc->Func = Func; /* we now add the counter to the list */ if (prev == NULL) @@ -605,6 +607,8 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) void *td = stats_thread_data; if (stats_table.nstats == 0) { + StatsThreadRegister("Globals", &sc_perf_op_ctx->global_counter_ctx); + uint32_t nstats = counters_global_id; stats_table.nstats = nstats; @@ -629,6 +633,9 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) counters_global_id * sizeof(struct CountersMergeTable)); StatsRecord *table = stats_table.stats; + + /* Loop through the thread counter stores. The global counters + * are in a separate store inside this list. */ pctmi = sc_perf_op_ctx->pctmi; SCLogDebug("pctmi %p", pctmi); while (pctmi != NULL) { @@ -646,15 +653,21 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) case STATS_TYPE_MAXIMUM: if (pc->value > merge_table[pc->gid].value) merge_table[pc->gid].value = pc->value; + table[pc->gid].tm_name = "Total"; + break; + case STATS_TYPE_FUNC: + if (pc->Func != NULL) + merge_table[pc->gid].value = pc->Func(); + table[pc->gid].tm_name = "Global"; break; default: merge_table[pc->gid].value += pc->value; + table[pc->gid].tm_name = "Total"; break; } merge_table[pc->gid].updates += pc->updates; table[pc->gid].name = pc->cname; - table[pc->gid].tm_name = pctmi->tm_name; pc = pc->next; } @@ -938,6 +951,12 @@ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, */ uint16_t SCPerfTVRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)) { +#ifdef UNITTESTS + if (sc_perf_op_ctx == NULL) + return 0; +#else + BUG_ON(sc_perf_op_ctx == NULL); +#endif uint16_t id = SCPerfRegisterQualifiedCounter(cname, NULL, SC_PERF_TYPE_UINT64, &(sc_perf_op_ctx->global_counter_ctx), @@ -1082,7 +1101,7 @@ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pct temp->next = sc_perf_op_ctx->pctmi; sc_perf_op_ctx->pctmi = temp; - SCLogInfo("sc_perf_op_ctx->pctmi %p", sc_perf_op_ctx->pctmi); + SCLogDebug("sc_perf_op_ctx->pctmi %p", sc_perf_op_ctx->pctmi); SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); return 1; From de82b6d31eb4aebf4e8c01778826ec13eef3a53a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 25 May 2015 13:46:19 +0200 Subject: [PATCH 0505/2553] counters: rename widely used pctmi var to sts (stats thread store) --- src/counters.c | 91 +++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/src/counters.c b/src/counters.c index 8304eb4034f4..827b1e3aaa2a 100644 --- a/src/counters.c +++ b/src/counters.c @@ -83,8 +83,9 @@ typedef struct StatsThreadStore_ { * \brief Holds the output interface context for the counter api */ typedef struct StatsGlobalContext_ { - StatsThreadStore *pctmi; - SCMutex pctmi_lock; + /** list of thread stores: one per thread plus one global */ + StatsThreadStore *sts; + SCMutex sts_lock; HashTable *counters_id_hash; SCPerfPublicContext global_counter_ctx; @@ -236,8 +237,8 @@ static void SCPerfInitOPCtx(void) time(&sc_start_time); /* init the lock used by StatsThreadStore */ - if (SCMutexInit(&sc_perf_op_ctx->pctmi_lock, NULL) != 0) { - SCLogError(SC_ERR_INITIALIZATION, "error initializing pctmi mutex"); + if (SCMutexInit(&sc_perf_op_ctx->sts_lock, NULL) != 0) { + SCLogError(SC_ERR_INITIALIZATION, "error initializing sts mutex"); exit(EXIT_FAILURE); } @@ -255,20 +256,20 @@ static void SCPerfReleaseOPCtx() return; } - StatsThreadStore *pctmi = NULL; + StatsThreadStore *sts = NULL; StatsThreadStore *temp = NULL; - pctmi = sc_perf_op_ctx->pctmi; + sts = sc_perf_op_ctx->sts; - while (pctmi != NULL) { - if (pctmi->tm_name != NULL) - SCFree(pctmi->tm_name); + while (sts != NULL) { + if (sts->tm_name != NULL) + SCFree(sts->tm_name); - if (pctmi->head != NULL) - SCFree(pctmi->head); + if (sts->head != NULL) + SCFree(sts->head); - temp = pctmi->next; - SCFree(pctmi); - pctmi = temp; + temp = sts->next; + SCFree(sts); + sts = temp; } SCFree(sc_perf_op_ctx); @@ -602,7 +603,7 @@ static uint64_t SCPerfOutputCalculateCounterValue(SCPerfCounter *pc) */ static int SCPerfOutputCounterFileIface(ThreadVars *tv) { - const StatsThreadStore *pctmi = NULL; + const StatsThreadStore *sts = NULL; const SCPerfCounter *pc = NULL; void *td = stats_thread_data; @@ -636,14 +637,14 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) /* Loop through the thread counter stores. The global counters * are in a separate store inside this list. */ - pctmi = sc_perf_op_ctx->pctmi; - SCLogDebug("pctmi %p", pctmi); - while (pctmi != NULL) { - SCLogDebug("Thread %s (%s) ctx %p", pctmi->name, - pctmi->tm_name ? pctmi->tm_name : "none", pctmi->ctx); - - SCMutexLock(&pctmi->ctx->m); - pc = pctmi->ctx->head; + sts = sc_perf_op_ctx->sts; + SCLogDebug("sts %p", sts); + while (sts != NULL) { + SCLogDebug("Thread %s (%s) ctx %p", sts->name, + sts->tm_name ? sts->tm_name : "none", sts->ctx); + + SCMutexLock(&sts->ctx->m); + pc = sts->ctx->head; while (pc != NULL) { SCLogDebug("Counter %s (%u:%u) value %"PRIu64, pc->cname, pc->id, pc->gid, pc->value); @@ -671,8 +672,8 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) pc = pc->next; } - SCMutexUnlock(&pctmi->ctx->m); - pctmi = pctmi->next; + SCMutexUnlock(&sts->ctx->m); + sts = sts->next; } uint16_t x; @@ -710,7 +711,7 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) TmEcode SCPerfOutputCounterSocket(json_t *cmd, json_t *answer, void *data) { - StatsThreadStore *pctmi = NULL; + StatsThreadStore *sts = NULL; SCPerfCounter *pc = NULL; SCPerfCounter **pc_heads = NULL; @@ -735,8 +736,8 @@ TmEcode SCPerfOutputCounterSocket(json_t *cmd, return TM_ECODE_FAILED; } - pctmi = sc_perf_op_ctx->pctmi; - while (pctmi != NULL) { + sts = sc_perf_op_ctx->sts; + while (sts != NULL) { json_t *jdata; int filled = 0; jdata = json_object(); @@ -746,18 +747,18 @@ TmEcode SCPerfOutputCounterSocket(json_t *cmd, json_string("internal error at json object creation")); return TM_ECODE_FAILED; } - if ((pc_heads = SCMalloc(pctmi->size * sizeof(SCPerfCounter *))) == NULL) { + if ((pc_heads = SCMalloc(sts->size * sizeof(SCPerfCounter *))) == NULL) { json_decref(tm_array); json_object_set_new(answer, "message", json_string("internal memory error")); return TM_ECODE_FAILED; } - memset(pc_heads, 0, pctmi->size * sizeof(SCPerfCounter *)); + memset(pc_heads, 0, sts->size * sizeof(SCPerfCounter *)); - for (u = 0; u < pctmi->size; u++) { - pc_heads[u] = pctmi->head[u]->head; + for (u = 0; u < sts->size; u++) { + pc_heads[u] = sts->head[u]->head; - SCMutexLock(&pctmi->head[u]->m); + SCMutexLock(&sts->head[u]->m); } flag = 1; @@ -767,7 +768,7 @@ TmEcode SCPerfOutputCounterSocket(json_t *cmd, break; pc = pc_heads[0]; - for (u = 0; u < pctmi->size; u++) { + for (u = 0; u < sts->size; u++) { ui64_temp = SCPerfOutputCalculateCounterValue(pc_heads[u]); ui64_result += ui64_temp; @@ -781,13 +782,13 @@ TmEcode SCPerfOutputCounterSocket(json_t *cmd, json_object_set_new(jdata, pc->cname, json_integer(ui64_result)); } - for (u = 0; u < pctmi->size; u++) - SCMutexUnlock(&pctmi->head[u]->m); + for (u = 0; u < sts->size; u++) + SCMutexUnlock(&sts->head[u]->m); if (filled == 1) { - json_object_set_new(tm_array, pctmi->tm_name, jdata); + json_object_set_new(tm_array, sts->tm_name, jdata); } - pctmi = pctmi->next; + sts = sts->next; SCFree(pc_heads); @@ -1061,7 +1062,7 @@ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pct return 0; } - SCMutexLock(&sc_perf_op_ctx->pctmi_lock); + SCMutexLock(&sc_perf_op_ctx->sts_lock); if (sc_perf_op_ctx->counters_id_hash == NULL) { sc_perf_op_ctx->counters_id_hash = HashTableInit(256, CountersIdHashFunc, CountersIdHashCompareFunc, @@ -1085,7 +1086,7 @@ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pct if ( (temp = SCMalloc(sizeof(StatsThreadStore))) == NULL) { - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); + SCMutexUnlock(&sc_perf_op_ctx->sts_lock); return 0; } memset(temp, 0, sizeof(StatsThreadStore)); @@ -1095,15 +1096,15 @@ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pct temp->name = SCStrdup(thread_name); if (unlikely(temp->name == NULL)) { SCFree(temp); - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); + SCMutexUnlock(&sc_perf_op_ctx->sts_lock); return 0; } - temp->next = sc_perf_op_ctx->pctmi; - sc_perf_op_ctx->pctmi = temp; - SCLogDebug("sc_perf_op_ctx->pctmi %p", sc_perf_op_ctx->pctmi); + temp->next = sc_perf_op_ctx->sts; + sc_perf_op_ctx->sts = temp; + SCLogDebug("sc_perf_op_ctx->sts %p", sc_perf_op_ctx->sts); - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); + SCMutexUnlock(&sc_perf_op_ctx->sts_lock); return 1; } From 23f17950bca598b0b972aca3ece31db3124a5723 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 25 May 2015 20:53:17 +0200 Subject: [PATCH 0506/2553] counters: pass per thread stats to output api As well as the global (merged) stats. --- src/counters.c | 100 ++++++++++++++++++++++++++++++++++++++------- src/log-stats.c | 30 +++++++++++++- src/output-stats.h | 6 ++- 3 files changed, 118 insertions(+), 18 deletions(-) diff --git a/src/counters.c b/src/counters.c index 827b1e3aaa2a..acf2a1c9baae 100644 --- a/src/counters.c +++ b/src/counters.c @@ -86,6 +86,8 @@ typedef struct StatsGlobalContext_ { /** list of thread stores: one per thread plus one global */ StatsThreadStore *sts; SCMutex sts_lock; + int sts_cnt; + HashTable *counters_id_hash; SCPerfPublicContext global_counter_ctx; @@ -104,7 +106,7 @@ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *); /** stats table is filled each interval and passed to the * loggers. Initialized at first use. */ -static StatsTable stats_table = { NULL, 0, 0, {0 , 0}}; +static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}}; static uint16_t counters_global_id = 0; @@ -608,7 +610,7 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) void *td = stats_thread_data; if (stats_table.nstats == 0) { - StatsThreadRegister("Globals", &sc_perf_op_ctx->global_counter_ctx); + StatsThreadRegister("Global", &sc_perf_op_ctx->global_counter_ctx); uint32_t nstats = counters_global_id; @@ -620,6 +622,15 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) return -1; } + stats_table.ntstats = sc_perf_op_ctx->sts_cnt; + uint32_t array_size = stats_table.nstats * sizeof(StatsRecord); + stats_table.tstats = SCCalloc(stats_table.ntstats, array_size); + if (stats_table.tstats == NULL) { + stats_table.ntstats = 0; + SCLogError(SC_ERR_MEM_ALLOC, "could not alloc memory for stats"); + return -1; + } + stats_table.start_time = sc_start_time; } @@ -633,6 +644,7 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) memset(&merge_table, 0x00, counters_global_id * sizeof(struct CountersMergeTable)); + int thread = sc_perf_op_ctx->sts_cnt - 1; StatsRecord *table = stats_table.stats; /* Loop through the thread counter stores. The global counters @@ -640,47 +652,104 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) sts = sc_perf_op_ctx->sts; SCLogDebug("sts %p", sts); while (sts != NULL) { - SCLogDebug("Thread %s (%s) ctx %p", sts->name, + BUG_ON(thread < 0); + + SCLogDebug("Thread %d %s (%s) ctx %p", thread, sts->name, sts->tm_name ? sts->tm_name : "none", sts->ctx); + /* temporay table for quickly storing the counters for this + * thread store, so that we can post process them outside + * of the thread store lock */ + struct CountersMergeTable thread_table[counters_global_id]; + memset(&thread_table, 0x00, + counters_global_id * sizeof(struct CountersMergeTable)); + SCMutexLock(&sts->ctx->m); pc = sts->ctx->head; while (pc != NULL) { SCLogDebug("Counter %s (%u:%u) value %"PRIu64, pc->cname, pc->id, pc->gid, pc->value); - merge_table[pc->gid].type = pc->type; + thread_table[pc->gid].type = pc->type; switch (pc->type) { - case STATS_TYPE_MAXIMUM: - if (pc->value > merge_table[pc->gid].value) - merge_table[pc->gid].value = pc->value; - table[pc->gid].tm_name = "Total"; - break; case STATS_TYPE_FUNC: if (pc->Func != NULL) - merge_table[pc->gid].value = pc->Func(); - table[pc->gid].tm_name = "Global"; + thread_table[pc->gid].value = pc->Func(); break; + case STATS_TYPE_AVERAGE: default: - merge_table[pc->gid].value += pc->value; - table[pc->gid].tm_name = "Total"; + thread_table[pc->gid].value = pc->value; break; } - merge_table[pc->gid].updates += pc->updates; - + thread_table[pc->gid].updates = pc->updates; table[pc->gid].name = pc->cname; pc = pc->next; } SCMutexUnlock(&sts->ctx->m); + + /* update merge table */ + uint16_t c; + for (c = 0; c < counters_global_id; c++) { + struct CountersMergeTable *e = &thread_table[c]; + /* thread only sets type if it has a counter + * of this type. */ + if (e->type == 0) + continue; + + switch (e->type) { + case STATS_TYPE_MAXIMUM: + if (e->value > merge_table[c].value) + merge_table[c].value = e->value; + break; + case STATS_TYPE_FUNC: + merge_table[c].value = e->value; + break; + case STATS_TYPE_AVERAGE: + default: + merge_table[c].value += e->value; + break; + } + merge_table[c].updates += e->updates; + merge_table[c].type = e->type; + } + + /* update per thread stats table */ + for (c = 0; c < counters_global_id; c++) { + struct CountersMergeTable *e = &thread_table[c]; + /* thread only sets type if it has a counter + * of this type. */ + if (e->type == 0) + continue; + + uint32_t offset = (thread * stats_table.nstats) + c; + StatsRecord *r = &stats_table.tstats[offset]; + r->name = table[c].name; + r->tm_name = sts->name; + + switch (e->type) { + case STATS_TYPE_AVERAGE: + if (e->value > 0 && e->updates > 0) { + r->value = (uint64_t)(e->value / e->updates); + } + break; + default: + r->value = e->value; + break; + } + } + sts = sts->next; + thread--; } + /* transfer 'merge table' to final stats table */ uint16_t x; for (x = 0; x < counters_global_id; x++) { /* xfer previous value to pvalue and reset value */ table[x].pvalue = table[x].value; table[x].value = 0; + table[x].tm_name = "Total"; struct CountersMergeTable *m = &merge_table[x]; switch (m->type) { @@ -1102,6 +1171,7 @@ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pct temp->next = sc_perf_op_ctx->sts; sc_perf_op_ctx->sts = temp; + sc_perf_op_ctx->sts_cnt++; SCLogDebug("sc_perf_op_ctx->sts %p", sc_perf_op_ctx->sts); SCMutexUnlock(&sc_perf_op_ctx->sts_lock); diff --git a/src/log-stats.c b/src/log-stats.c index 1ae4246208e9..cd35d57800e3 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -98,10 +98,11 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) MemBufferWriteString(aft->buffer, "----------------------------------------------" "---------------------\n"); + /* global stats */ uint32_t u = 0; for (u = 0; u < st->nstats; u++) { if (st->stats[u].name == NULL) - break; + continue; char line[1024]; size_t len = snprintf(line, sizeof(line), "%-25s | %-25s | %-" PRIu64 "\n", @@ -116,6 +117,33 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) MemBufferWriteString(aft->buffer, "%s", line); } + /* per thread stats */ + if (st->tstats != NULL) { + /* for each thread (store) */ + uint32_t x; + for (x = 0; x < st->ntstats; x++) { + uint32_t offset = x * st->nstats; + + /* for each counter */ + for (u = offset; u < (offset + st->nstats); u++) { + if (st->tstats[u].name == NULL) + continue; + + char line[1024]; + size_t len = snprintf(line, sizeof(line), "%-25s | %-25s | %-" PRIu64 "\n", + st->tstats[u].name, st->tstats[u].tm_name, st->tstats[u].value); + + /* since we can have many threads, the buffer might not be big enough. + * Expand if necessary. */ + if (MEMBUFFER_OFFSET(aft->buffer) + len > MEMBUFFER_SIZE(aft->buffer)) { + MemBufferExpand(&aft->buffer, OUTPUT_BUFFER_SIZE); + } + + MemBufferWriteString(aft->buffer, "%s", line); + } + } + } + SCMutexLock(&aft->statslog_ctx->file_ctx->fp_mutex); aft->statslog_ctx->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), aft->statslog_ctx->file_ctx); diff --git a/src/output-stats.h b/src/output-stats.h index 6ca89f931bed..75017ca20c4e 100644 --- a/src/output-stats.h +++ b/src/output-stats.h @@ -34,8 +34,10 @@ typedef struct StatsRecord_ { } StatsRecord; typedef struct StatsTable_ { - StatsRecord *stats; - uint32_t nstats; + StatsRecord *stats; /**< array of global stats, indexed by counters gid */ + StatsRecord *tstats; /**< array of arrays with per thread stats */ + uint32_t nstats; /**< size in records of 'stats' */ + uint32_t ntstats; /**< number of threads for which tstats stores stats */ time_t start_time; struct timeval ts; } StatsTable; From 117eed0385431a85c91916b1c2c55d2b19ab4f97 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Mon, 3 Nov 2014 17:01:59 -0800 Subject: [PATCH 0507/2553] eve-log: add JSON stats logging Support for counters in stats.log in eve output JSON stream. --- src/Makefile.am | 1 + src/output-json-stats.c | 336 ++++++++++++++++++++++++++++++++++++++++ src/output-json-stats.h | 29 ++++ src/suricata.c | 3 + src/tm-modules.c | 1 + src/tm-threads-common.h | 1 + suricata.yaml.in | 1 + 7 files changed, 372 insertions(+) create mode 100644 src/output-json-stats.c create mode 100644 src/output-json-stats.h diff --git a/src/Makefile.am b/src/Makefile.am index aacf9eccd0a8..d682b62cc4f4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -243,6 +243,7 @@ output-json-netflow.c output-json-netflow.h \ output-json-http.c output-json-http.h \ output-json-smtp.c output-json-smtp.h \ output-json-ssh.c output-json-ssh.h \ +output-json-stats.c output-json-stats.h \ output-json-tls.c output-json-tls.h \ output-lua.c output-lua.h \ output-packet.c output-packet.h \ diff --git a/src/output-json-stats.c b/src/output-json-stats.c new file mode 100644 index 000000000000..3aab8110f744 --- /dev/null +++ b/src/output-json-stats.c @@ -0,0 +1,336 @@ +/* Copyright (C) 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 Tom DeCanio + * + * Implements JSON stats counters logging portion of the engine. + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" +#include "output.h" +#include "util-privs.h" +#include "util-buffer.h" + +#include "util-logopenfile.h" +#include "util-crypt.h" + +#include "output-json.h" + +#ifdef HAVE_LIBJANSSON +#include + +#define MODULE_NAME "LogStatsLog" + +typedef struct OutputStatsCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; /** Store mode */ +} OutputStatsCtx; + + +typedef struct JsonStatsLogThread_ { + OutputStatsCtx *statslog_ctx; + //MemBuffer *buffer; +} JsonStatsLogThread; + +static void *eve_file_ctx = NULL; +static void *eve_buffer = NULL; + +static +json_t *SCPerfLookupJson(json_t *js, char *key) +{ + void *iter; + char *s = strndup(key, index(key, '.') - key); + + iter = json_object_iter_at(js, s); + char *s1 = index(key, '.'); + char *s2 = index(s1+1, '.'); + + json_t *value = json_object_iter_value(iter); + if (value == NULL) { + value = json_object(); + json_object_set(js, s, value); + } + if (s2 != NULL) { + return SCPerfLookupJson(value, &key[index(key,'.')-key+1]); + } + return value; +} + +static int JsonStatsLogger(ThreadVars *tv, void *thread_data, StatsTable *st) +{ + SCEnter(); + /*JsonStatsLogThread *aft = (JsonStatsLogThread *)thread_data; */ + + struct timeval tval; + struct tm *tms; + + gettimeofday(&tval, NULL); + struct tm local_tm; + tms = SCLocalTime(tval.tv_sec, &local_tm); + + /* Calculate the Engine uptime */ + int up_time = (int)difftime(tval.tv_sec, st->start_time); + int sec = up_time % 60; // Seconds in a minute + int in_min = up_time / 60; + int min = in_min % 60; // Minutes in a hour + int in_hours = in_min / 60; + int hours = in_hours % 24; // Hours in a day + int days = in_hours / 24; + + json_t *js = json_object(); + if (unlikely(js == NULL)) + return 0; + + json_object_set_new(js, "event_type", json_string("stats")); + json_t *js_stats = json_object(); + if (unlikely(js_stats == NULL)) { + json_decref(js); + return 0; + } + char date[128]; + snprintf(date, sizeof(date), + "%" PRId32 "/%" PRId32 "/%04d -- %02d:%02d:%02d", + tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, + tms->tm_min, tms->tm_sec); + + json_object_set_new(js_stats, "date", json_string(date)); + + char uptime[128]; + snprintf(uptime, sizeof(uptime), + "%"PRId32"d, %02dh %02dm %02ds", days, hours, min, sec); + + json_object_set_new(js_stats, "uptime", json_string(uptime)); + + uint32_t u = 0; + for (u = 0; u < st->nstats; u++) { + if (st->stats[u].name == NULL) + break; + char str[256]; + snprintf(str, sizeof(str), "%s.%s", st->stats[u].tm_name, st->stats[u].name); + json_t *js_type = SCPerfLookupJson(js_stats, str); + + if (js_type != NULL) { + json_object_set_new(js_type, &str[rindex(str, '.')-str+1], json_integer(st->stats[u].value)); + } + } + json_object_set_new(js, "stats", js_stats); + + if (eve_file_ctx != NULL && eve_buffer != NULL) { + OutputJSONBuffer(js, eve_file_ctx, eve_buffer); + } + json_object_clear(js); + json_decref(js); + + SCReturnInt(0); +} + +void SCPerfRegisterEveFile(void *file_ctx, void *buffer) +{ + eve_file_ctx = file_ctx; + eve_buffer = buffer; +} + +#define OUTPUT_BUFFER_SIZE 65535 +static TmEcode JsonStatsLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + JsonStatsLogThread *aft = SCMalloc(sizeof(JsonStatsLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(JsonStatsLogThread)); + + if(initdata == NULL) + { + SCLogDebug("Error getting context for json stats. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + /* Use the Ouptut Context (file pointer and mutex) */ + aft->statslog_ctx = ((OutputCtx *)initdata)->data; + + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode JsonStatsLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonStatsLogThread *aft = (JsonStatsLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + /* clear memory */ + memset(aft, 0, sizeof(JsonStatsLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static void OutputStatsLogDeinit(OutputCtx *output_ctx) +{ + + OutputStatsCtx *stats_ctx = output_ctx->data; + LogFileCtx *logfile_ctx = stats_ctx->file_ctx; + LogFileFreeCtx(logfile_ctx); + SCFree(stats_ctx); + SCFree(output_ctx); +} + +#define DEFAULT_LOG_FILENAME "stats.json" +OutputCtx *OutputStatsLogInit(ConfNode *conf) +{ + LogFileCtx *file_ctx = LogFileNewCtx(); + if(file_ctx == NULL) { + SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + LogFileFreeCtx(file_ctx); + return NULL; + } + + OutputStatsCtx *stats_ctx = SCMalloc(sizeof(OutputStatsCtx)); + if (unlikely(stats_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + return NULL; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + SCFree(stats_ctx); + return NULL; + } + + stats_ctx->file_ctx = file_ctx; + + output_ctx->data = stats_ctx; + output_ctx->DeInit = OutputStatsLogDeinit; + + return output_ctx; +} + +static void OutputStatsLogDeinitSub(OutputCtx *output_ctx) +{ + + OutputStatsCtx *stats_ctx = output_ctx->data; + SCFree(stats_ctx); + SCFree(output_ctx); +} + +OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AlertJsonThread *ajt = parent_ctx->data; + MemBuffer *buffer; + + OutputStatsCtx *stats_ctx = SCMalloc(sizeof(OutputStatsCtx)); + if (unlikely(stats_ctx == NULL)) + return NULL; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(stats_ctx); + return NULL; + } + + stats_ctx->file_ctx = ajt->file_ctx; + + output_ctx->data = stats_ctx; + output_ctx->DeInit = OutputStatsLogDeinitSub; + + buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (buffer == NULL) { + SCFree(stats_ctx); + SCFree(output_ctx); + return NULL; + } + +#if 0 + if (conf) { + const char *interval_s = ConfNodeLookupChildValue(conf, "interval"); + if (interval_s != NULL) + interval = (uint32_t) atoi(interval_s); + } +#endif + +#ifdef NOTYET + SCPerfRegisterEveFile(stats_ctx->file_ctx, buffer, interval); +#endif + SCPerfRegisterEveFile(stats_ctx->file_ctx, buffer); + + return output_ctx; +} + +#if 0 +/** \internal + * \brief Condition function for Stats logger + * \retval bool true or false -- log now? + */ +static int JsonStatsCondition(ThreadVars *tv, const Packet *p) { + return FALSE; +} +#endif + +void TmModuleJsonStatsLogRegister (void) { + tmm_modules[TMM_JSONSTATSLOG].name = "JsonStatsLog"; + tmm_modules[TMM_JSONSTATSLOG].ThreadInit = JsonStatsLogThreadInit; + tmm_modules[TMM_JSONSTATSLOG].ThreadDeinit = JsonStatsLogThreadDeinit; + tmm_modules[TMM_JSONSTATSLOG].RegisterTests = NULL; + tmm_modules[TMM_JSONSTATSLOG].cap_flags = 0; + tmm_modules[TMM_JSONSTATSLOG].flags = TM_FLAG_LOGAPI_TM; + + /* register as separate module */ + OutputRegisterStatsModule("JsonStatsLog", "stats", OutputStatsLogInit, + JsonStatsLogger); + + /* also register as child of eve-log */ + OutputRegisterStatsSubModule("eve-log", "JsonStatsLog", "eve-log.stats", + OutputStatsLogInitSub, JsonStatsLogger); +} + +#else + +static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) +{ + SCLogInfo("Can't init JSON output - JSON support was disabled during build."); + return TM_ECODE_FAILED; +} + +void TmModuleJsonStatsLogRegister (void) +{ + tmm_modules[TMM_JSONSTATSLOG].name = "JsonStatsLog"; + tmm_modules[TMM_JSONSTATSLOG].ThreadInit = OutputJsonThreadInit; +} + +#endif diff --git a/src/output-json-stats.h b/src/output-json-stats.h new file mode 100644 index 000000000000..9ad1d9b8164a --- /dev/null +++ b/src/output-json-stats.h @@ -0,0 +1,29 @@ +/* Copyright (C) 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 Tom DeCanio + */ + +#ifndef __OUTPUT_JSON_COUNTERS_H__ +#define __OUTPUT_JSON_COUNTERS_H__ + +void TmModuleJsonStatsLogRegister (void); + +#endif /* __OUTPUT_JSON_COUNTERS_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 4e55c3185785..8b2a82ced281 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -94,6 +94,7 @@ #include "log-file.h" #include "output-json-file.h" #include "output-json-smtp.h" +#include "output-json-stats.h" #include "log-filestore.h" #include "log-tcp-data.h" #include "log-stats.h" @@ -891,6 +892,8 @@ void RegisterAllModules() /* flow/netflow */ TmModuleJsonFlowLogRegister(); TmModuleJsonNetFlowLogRegister(); + /* json stats */ + TmModuleJsonStatsLogRegister(); /* log api */ TmModulePacketLoggerRegister(); diff --git a/src/tm-modules.c b/src/tm-modules.c index 3c6d6d229271..7d29551fd930 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -263,6 +263,7 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_JSONNETFLOWLOG); CASE_CODE (TMM_JSONSMTPLOG); CASE_CODE (TMM_JSONSSHLOG); + CASE_CODE (TMM_JSONSTATSLOG); CASE_CODE (TMM_JSONTLSLOG); CASE_CODE (TMM_OUTPUTJSON); CASE_CODE (TMM_FLOWMANAGER); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 5affa40c1866..17ea053d15de 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -93,6 +93,7 @@ typedef enum { TMM_JSONDNSLOG, TMM_JSONSMTPLOG, TMM_JSONSSHLOG, + TMM_JSONSTATSLOG, TMM_JSONTLSLOG, TMM_JSONFILELOG, TMM_RECEIVENFLOG, diff --git a/suricata.yaml.in b/suricata.yaml.in index be7ac5573e34..147e002d65dd 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -140,6 +140,7 @@ outputs: # alerts: no # log alerts that caused drops - smtp - ssh + - stats # bi-directional flows #- flow # uni-directional flows From e4e07d0c3b3a87327fa35faa5f93b1aa77cc9950 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Mon, 3 Nov 2014 17:16:46 -0800 Subject: [PATCH 0508/2553] eve-log: stats logging code cleanup. --- src/output-json-stats.c | 43 ++++++++--------------------------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 3aab8110f744..8b5183a33c41 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -46,11 +46,11 @@ #include "output-json.h" +#define MODULE_NAME "JsonStatsLog" + #ifdef HAVE_LIBJANSSON #include -#define MODULE_NAME "LogStatsLog" - typedef struct OutputStatsCtx_ { LogFileCtx *file_ctx; uint32_t flags; /** Store mode */ @@ -59,7 +59,6 @@ typedef struct OutputStatsCtx_ { typedef struct JsonStatsLogThread_ { OutputStatsCtx *statslog_ctx; - //MemBuffer *buffer; } JsonStatsLogThread; static void *eve_file_ctx = NULL; @@ -154,12 +153,6 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, StatsTable *st) SCReturnInt(0); } -void SCPerfRegisterEveFile(void *file_ctx, void *buffer) -{ - eve_file_ctx = file_ctx; - eve_buffer = buffer; -} - #define OUTPUT_BUFFER_SIZE 65535 static TmEcode JsonStatsLogThreadInit(ThreadVars *t, void *initdata, void **data) { @@ -276,34 +269,14 @@ OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } -#if 0 - if (conf) { - const char *interval_s = ConfNodeLookupChildValue(conf, "interval"); - if (interval_s != NULL) - interval = (uint32_t) atoi(interval_s); - } -#endif - -#ifdef NOTYET - SCPerfRegisterEveFile(stats_ctx->file_ctx, buffer, interval); -#endif - SCPerfRegisterEveFile(stats_ctx->file_ctx, buffer); + eve_file_ctx = stats_ctx->file_ctx; + eve_buffer = buffer; return output_ctx; } -#if 0 -/** \internal - * \brief Condition function for Stats logger - * \retval bool true or false -- log now? - */ -static int JsonStatsCondition(ThreadVars *tv, const Packet *p) { - return FALSE; -} -#endif - void TmModuleJsonStatsLogRegister (void) { - tmm_modules[TMM_JSONSTATSLOG].name = "JsonStatsLog"; + tmm_modules[TMM_JSONSTATSLOG].name = MODULE_NAME; tmm_modules[TMM_JSONSTATSLOG].ThreadInit = JsonStatsLogThreadInit; tmm_modules[TMM_JSONSTATSLOG].ThreadDeinit = JsonStatsLogThreadDeinit; tmm_modules[TMM_JSONSTATSLOG].RegisterTests = NULL; @@ -311,11 +284,11 @@ void TmModuleJsonStatsLogRegister (void) { tmm_modules[TMM_JSONSTATSLOG].flags = TM_FLAG_LOGAPI_TM; /* register as separate module */ - OutputRegisterStatsModule("JsonStatsLog", "stats", OutputStatsLogInit, + OutputRegisterStatsModule(MODULE_NAME, "stats", OutputStatsLogInit, JsonStatsLogger); /* also register as child of eve-log */ - OutputRegisterStatsSubModule("eve-log", "JsonStatsLog", "eve-log.stats", + OutputRegisterStatsSubModule("eve-log", MODULE_NAME, "eve-log.stats", OutputStatsLogInitSub, JsonStatsLogger); } @@ -329,7 +302,7 @@ static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) void TmModuleJsonStatsLogRegister (void) { - tmm_modules[TMM_JSONSTATSLOG].name = "JsonStatsLog"; + tmm_modules[TMM_JSONSTATSLOG].name = MODULE_NAME; tmm_modules[TMM_JSONSTATSLOG].ThreadInit = OutputJsonThreadInit; } From 6565c86f96b1abb43415f050d916e153afb7b9e8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 4 Nov 2014 09:50:29 +0100 Subject: [PATCH 0509/2553] stats-json: fixes and improvements Use proper LogFileCtx and MemBuffer handling so we can have multiple loggers active at the same time. Change 'date' field to timestamp, and use ISO notation to make it the same as the other JSON outputs. --- src/output-json-stats.c | 53 ++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 8b5183a33c41..e6d3e33b5501 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -56,14 +56,11 @@ typedef struct OutputStatsCtx_ { uint32_t flags; /** Store mode */ } OutputStatsCtx; - typedef struct JsonStatsLogThread_ { OutputStatsCtx *statslog_ctx; + MemBuffer *buffer; } JsonStatsLogThread; -static void *eve_file_ctx = NULL; -static void *eve_buffer = NULL; - static json_t *SCPerfLookupJson(json_t *js, char *key) { @@ -85,17 +82,14 @@ json_t *SCPerfLookupJson(json_t *js, char *key) return value; } -static int JsonStatsLogger(ThreadVars *tv, void *thread_data, StatsTable *st) +static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) { SCEnter(); - /*JsonStatsLogThread *aft = (JsonStatsLogThread *)thread_data; */ + JsonStatsLogThread *aft = (JsonStatsLogThread *)thread_data; + MemBuffer *buffer = (MemBuffer *)aft->buffer; struct timeval tval; - struct tm *tms; - gettimeofday(&tval, NULL); - struct tm local_tm; - tms = SCLocalTime(tval.tv_sec, &local_tm); /* Calculate the Engine uptime */ int up_time = (int)difftime(tval.tv_sec, st->start_time); @@ -110,19 +104,16 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, StatsTable *st) if (unlikely(js == NULL)) return 0; + char timebuf[64]; + CreateIsoTimeString(&tval, timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); + json_object_set_new(js, "event_type", json_string("stats")); json_t *js_stats = json_object(); if (unlikely(js_stats == NULL)) { json_decref(js); return 0; } - char date[128]; - snprintf(date, sizeof(date), - "%" PRId32 "/%" PRId32 "/%04d -- %02d:%02d:%02d", - tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, - tms->tm_min, tms->tm_sec); - - json_object_set_new(js_stats, "date", json_string(date)); char uptime[128]; snprintf(uptime, sizeof(uptime), @@ -144,9 +135,9 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, StatsTable *st) } json_object_set_new(js, "stats", js_stats); - if (eve_file_ctx != NULL && eve_buffer != NULL) { - OutputJSONBuffer(js, eve_file_ctx, eve_buffer); - } + OutputJSONBuffer(js, aft->statslog_ctx->file_ctx, buffer); + MemBufferReset(buffer); + json_object_clear(js); json_decref(js); @@ -171,6 +162,12 @@ static TmEcode JsonStatsLogThreadInit(ThreadVars *t, void *initdata, void **data /* Use the Ouptut Context (file pointer and mutex) */ aft->statslog_ctx = ((OutputCtx *)initdata)->data; + aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + *data = (void *)aft; return TM_ECODE_OK; } @@ -182,6 +179,8 @@ static TmEcode JsonStatsLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } + MemBufferFree(aft->buffer); + /* clear memory */ memset(aft, 0, sizeof(JsonStatsLogThread)); @@ -236,7 +235,6 @@ OutputCtx *OutputStatsLogInit(ConfNode *conf) static void OutputStatsLogDeinitSub(OutputCtx *output_ctx) { - OutputStatsCtx *stats_ctx = output_ctx->data; SCFree(stats_ctx); SCFree(output_ctx); @@ -245,7 +243,6 @@ static void OutputStatsLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { AlertJsonThread *ajt = parent_ctx->data; - MemBuffer *buffer; OutputStatsCtx *stats_ctx = SCMalloc(sizeof(OutputStatsCtx)); if (unlikely(stats_ctx == NULL)) @@ -262,16 +259,6 @@ OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) output_ctx->data = stats_ctx; output_ctx->DeInit = OutputStatsLogDeinitSub; - buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); - if (buffer == NULL) { - SCFree(stats_ctx); - SCFree(output_ctx); - return NULL; - } - - eve_file_ctx = stats_ctx->file_ctx; - eve_buffer = buffer; - return output_ctx; } @@ -284,7 +271,7 @@ void TmModuleJsonStatsLogRegister (void) { tmm_modules[TMM_JSONSTATSLOG].flags = TM_FLAG_LOGAPI_TM; /* register as separate module */ - OutputRegisterStatsModule(MODULE_NAME, "stats", OutputStatsLogInit, + OutputRegisterStatsModule(MODULE_NAME, "stats-json", OutputStatsLogInit, JsonStatsLogger); /* also register as child of eve-log */ From 175831331c82b24e0feea7be0aa9f8c11fdad5cc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 4 Nov 2014 10:07:25 +0100 Subject: [PATCH 0510/2553] stats json: replace strndup strndup is a banned function. --- src/output-json-stats.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/output-json-stats.c b/src/output-json-stats.c index e6d3e33b5501..63e11a7784fe 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -61,23 +61,28 @@ typedef struct JsonStatsLogThread_ { MemBuffer *buffer; } JsonStatsLogThread; -static -json_t *SCPerfLookupJson(json_t *js, char *key) +static json_t *OutputStats2Json(json_t *js, const char *key) { void *iter; - char *s = strndup(key, index(key, '.') - key); + + const char *dot = index(key, '.'); + if (dot == NULL) + return NULL; + + size_t predot_len = (dot - key) + 1; + char s[predot_len]; + strlcpy(s, key, predot_len); iter = json_object_iter_at(js, s); - char *s1 = index(key, '.'); - char *s2 = index(s1+1, '.'); + const char *s2 = index(dot+1, '.'); json_t *value = json_object_iter_value(iter); if (value == NULL) { value = json_object(); - json_object_set(js, s, value); + json_object_set_new(js, s, value); } if (s2 != NULL) { - return SCPerfLookupJson(value, &key[index(key,'.')-key+1]); + return OutputStats2Json(value, &key[dot-key+1]); } return value; } @@ -127,7 +132,7 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * break; char str[256]; snprintf(str, sizeof(str), "%s.%s", st->stats[u].tm_name, st->stats[u].name); - json_t *js_type = SCPerfLookupJson(js_stats, str); + json_t *js_type = OutputStats2Json(js_stats, str); if (js_type != NULL) { json_object_set_new(js_type, &str[rindex(str, '.')-str+1], json_integer(st->stats[u].value)); @@ -138,6 +143,8 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * OutputJSONBuffer(js, aft->statslog_ctx->file_ctx, buffer); MemBufferReset(buffer); + json_object_clear(js_stats); + json_object_del(js, "stats"); json_object_clear(js); json_decref(js); From 2c9a2c83275facab15d9fab38d50e90ea7a4e46e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 12:00:36 +0200 Subject: [PATCH 0511/2553] stats: support per thread stats in json output Default is only to output totals. Optionally per thread can be added. Both can be enabled together. --- src/output-json-stats.c | 78 ++++++++++++++++++++++++++++++++++++----- suricata.yaml.in | 4 ++- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 63e11a7784fe..1b684c99b923 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -51,6 +51,9 @@ #ifdef HAVE_LIBJANSSON #include +#define JSON_STATS_TOTALS (1<<0) +#define JSON_STATS_THREADS (1<<1) + typedef struct OutputStatsCtx_ { LogFileCtx *file_ctx; uint32_t flags; /** Store mode */ @@ -127,17 +130,43 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * json_object_set_new(js_stats, "uptime", json_string(uptime)); uint32_t u = 0; - for (u = 0; u < st->nstats; u++) { - if (st->stats[u].name == NULL) - break; - char str[256]; - snprintf(str, sizeof(str), "%s.%s", st->stats[u].tm_name, st->stats[u].name); - json_t *js_type = OutputStats2Json(js_stats, str); - - if (js_type != NULL) { - json_object_set_new(js_type, &str[rindex(str, '.')-str+1], json_integer(st->stats[u].value)); + if (aft->statslog_ctx->flags & JSON_STATS_TOTALS) { + for (u = 0; u < st->nstats; u++) { + if (st->stats[u].name == NULL) + continue; + char str[256]; + snprintf(str, sizeof(str), "%s.%s", st->stats[u].tm_name, st->stats[u].name); + json_t *js_type = OutputStats2Json(js_stats, str); + if (js_type != NULL) { + json_object_set_new(js_type, &str[rindex(str, '.')-str+1], + json_integer(st->stats[u].value)); + } + } + } + + /* per thread stats */ + if (st->tstats != NULL && (aft->statslog_ctx->flags & JSON_STATS_THREADS)) { + /* for each thread (store) */ + uint32_t x; + for (x = 0; x < st->ntstats; x++) { + uint32_t offset = x * st->nstats; + + /* for each counter */ + for (u = offset; u < (offset + st->nstats); u++) { + if (st->tstats[u].name == NULL) + continue; + + char str[256]; + snprintf(str, sizeof(str), "%s.%s", st->tstats[u].tm_name, st->tstats[u].name); + json_t *js_type = OutputStats2Json(js_stats, str); + + if (js_type != NULL) { + json_object_set_new(js_type, &str[rindex(str, '.')-str+1], json_integer(st->tstats[u].value)); + } + } } } + json_object_set_new(js, "stats", js_stats); OutputJSONBuffer(js, aft->statslog_ctx->file_ctx, buffer); @@ -224,6 +253,21 @@ OutputCtx *OutputStatsLogInit(ConfNode *conf) LogFileFreeCtx(file_ctx); return NULL; } + stats_ctx->flags = JSON_STATS_TOTALS; + + if (conf != NULL) { + const char *totals = ConfNodeLookupChildValue(conf, "totals"); + const char *threads = ConfNodeLookupChildValue(conf, "threads"); + SCLogDebug("totals %s threads %s", totals, threads); + + if (totals != NULL && ConfValIsFalse(totals)) { + stats_ctx->flags &= ~JSON_STATS_TOTALS; + } + if (threads != NULL && ConfValIsTrue(threads)) { + stats_ctx->flags |= JSON_STATS_THREADS; + } + SCLogDebug("stats_ctx->flags %08x", stats_ctx->flags); + } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { @@ -255,6 +299,22 @@ OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) if (unlikely(stats_ctx == NULL)) return NULL; + stats_ctx->flags = JSON_STATS_TOTALS; + + if (conf != NULL) { + const char *totals = ConfNodeLookupChildValue(conf, "totals"); + const char *threads = ConfNodeLookupChildValue(conf, "threads"); + SCLogDebug("totals %s threads %s", totals, threads); + + if (totals != NULL && ConfValIsFalse(totals)) { + stats_ctx->flags &= ~JSON_STATS_TOTALS; + } + if (threads != NULL && ConfValIsTrue(threads)) { + stats_ctx->flags |= JSON_STATS_THREADS; + } + SCLogDebug("stats_ctx->flags %08x", stats_ctx->flags); + } + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { SCFree(stats_ctx); diff --git a/suricata.yaml.in b/suricata.yaml.in index 147e002d65dd..f2e9a1853356 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -140,7 +140,9 @@ outputs: # alerts: no # log alerts that caused drops - smtp - ssh - - stats + - stats: + totals: yes # stats for all threads merged together + threads: no # per thread stats # bi-directional flows #- flow # uni-directional flows From 3fab736539be109d5b6426061e1f75daebe52265 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 13:51:38 +0200 Subject: [PATCH 0512/2553] log-stats: make global/threads logging configurable --- src/log-stats.c | 51 ++++++++++++++++++++++++++++++++++-------------- suricata.yaml.in | 2 ++ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/log-stats.c b/src/log-stats.c index cd35d57800e3..d7c050b2c5e5 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -49,6 +49,9 @@ #define MODULE_NAME "LogStatsLog" #define OUTPUT_BUFFER_SIZE 16384 +#define LOG_STATS_TOTALS (1<<0) +#define LOG_STATS_THREADS (1<<1) + TmEcode LogStatsLogThreadInit(ThreadVars *, void *, void **); TmEcode LogStatsLogThreadDeinit(ThreadVars *, void *); void LogStatsLogExitPrintStats(ThreadVars *, void *); @@ -100,25 +103,27 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) /* global stats */ uint32_t u = 0; - for (u = 0; u < st->nstats; u++) { - if (st->stats[u].name == NULL) - continue; - - char line[1024]; - size_t len = snprintf(line, sizeof(line), "%-25s | %-25s | %-" PRIu64 "\n", - st->stats[u].name, st->stats[u].tm_name, st->stats[u].value); - - /* since we can have many threads, the buffer might not be big enough. - * Expand if necessary. */ - if (MEMBUFFER_OFFSET(aft->buffer) + len > MEMBUFFER_SIZE(aft->buffer)) { - MemBufferExpand(&aft->buffer, OUTPUT_BUFFER_SIZE); - } + if (aft->statslog_ctx->flags & LOG_STATS_TOTALS) { + for (u = 0; u < st->nstats; u++) { + if (st->stats[u].name == NULL) + continue; + + char line[1024]; + size_t len = snprintf(line, sizeof(line), "%-25s | %-25s | %-" PRIu64 "\n", + st->stats[u].name, st->stats[u].tm_name, st->stats[u].value); + + /* since we can have many threads, the buffer might not be big enough. + * Expand if necessary. */ + if (MEMBUFFER_OFFSET(aft->buffer) + len > MEMBUFFER_SIZE(aft->buffer)) { + MemBufferExpand(&aft->buffer, OUTPUT_BUFFER_SIZE); + } - MemBufferWriteString(aft->buffer, "%s", line); + MemBufferWriteString(aft->buffer, "%s", line); + } } /* per thread stats */ - if (st->tstats != NULL) { + if (st->tstats != NULL && aft->statslog_ctx->flags & LOG_STATS_THREADS) { /* for each thread (store) */ uint32_t x; for (x = 0; x < st->ntstats; x++) { @@ -228,6 +233,22 @@ OutputCtx *LogStatsLogInitCtx(ConfNode *conf) } memset(statslog_ctx, 0x00, sizeof(LogStatsFileCtx)); + statslog_ctx->flags = LOG_STATS_TOTALS; + + if (conf != NULL) { + const char *totals = ConfNodeLookupChildValue(conf, "totals"); + const char *threads = ConfNodeLookupChildValue(conf, "threads"); + SCLogDebug("totals %s threads %s", totals, threads); + + if (totals != NULL && ConfValIsFalse(totals)) { + statslog_ctx->flags &= ~LOG_STATS_TOTALS; + } + if (threads != NULL && ConfValIsTrue(threads)) { + statslog_ctx->flags |= LOG_STATS_THREADS; + } + SCLogDebug("statslog_ctx->flags %08x", statslog_ctx->flags); + } + statslog_ctx->file_ctx = file_ctx; OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); diff --git a/suricata.yaml.in b/suricata.yaml.in index f2e9a1853356..5942494b7ea4 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -274,6 +274,8 @@ outputs: - stats: enabled: yes filename: stats.log + totals: yes # stats for all threads merged together + threads: no # per thread stats # a line based alerts log similar to fast.log into syslog - syslog: From 1ef786e7cba546780ecd8e8e48f13b4af26b9963 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 14:33:21 +0200 Subject: [PATCH 0513/2553] counters: rename register API calls Also remove 'type' parameter which was always the same. --- src/app-layer.c | 9 +-- src/counters.c | 117 ++++++++++++------------------------ src/counters.h | 16 ++--- src/decode.c | 96 ++++++++++------------------- src/detect-engine.c | 30 +++------ src/flow-manager.c | 33 ++++------ src/source-af-packet.c | 8 +-- src/source-erf-dag.c | 6 +- src/source-mpipe.c | 32 +++------- src/source-netmap.c | 8 +-- src/source-nflog.c | 10 ++- src/source-pcap.c | 24 ++++---- src/source-pfring.c | 8 +-- src/stream-tcp-reassemble.c | 2 +- src/stream-tcp.c | 45 +++++--------- 15 files changed, 153 insertions(+), 291 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 1f8590f5132b..5dfd433c61ac 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -603,12 +603,9 @@ AppLayerThreadCtx *AppLayerGetCtxThread(ThreadVars *tv) /* tv is allowed to be NULL in unittests */ if (tv != NULL) { - app_tctx->counter_dns_memuse = SCPerfTVRegisterCounter("dns.memuse", tv, - SC_PERF_TYPE_UINT64); - app_tctx->counter_dns_memcap_state = SCPerfTVRegisterCounter("dns.memcap_state", tv, - SC_PERF_TYPE_UINT64); - app_tctx->counter_dns_memcap_global = SCPerfTVRegisterCounter("dns.memcap_global", tv, - SC_PERF_TYPE_UINT64); + app_tctx->counter_dns_memuse = StatsRegisterCounter("dns.memuse", tv); + app_tctx->counter_dns_memcap_state = StatsRegisterCounter("dns.memcap_state", tv); + app_tctx->counter_dns_memcap_global = StatsRegisterCounter("dns.memcap_global", tv); } goto done; diff --git a/src/counters.c b/src/counters.c index acf2a1c9baae..0e686191cf2f 100644 --- a/src/counters.c +++ b/src/counters.c @@ -496,7 +496,6 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) * * \param cname Name of the counter, to be registered * \param tm_name Thread module to which this counter belongs - * \param type Datatype of this counter variable * \param pctx SCPerfPublicContext for this tm-tv instance * \param type_q Qualifier describing the type of counter to be registered * @@ -504,9 +503,9 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) * present counter on success * \retval 0 on failure */ -static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, - int type, SCPerfPublicContext *pctx, - int type_q, uint64_t (*Func)(void)) +static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, + SCPerfPublicContext *pctx, + int type_q, uint64_t (*Func)(void)) { SCPerfCounter **head = &pctx->head; SCPerfCounter *temp = NULL; @@ -518,12 +517,6 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, return 0; } - if ((type >= SC_PERF_TYPE_MAX) || (type < 0)) { - SCLogError(SC_ERR_INVALID_ARGUMENTS, "Counters of type %" PRId32 " can't " - "be registered", type); - return 0; - } - temp = prev = *head; while (temp != NULL) { prev = temp; @@ -946,16 +939,14 @@ void SCPerfSpawnThreads(void) * \param cname Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered - * \param type Datatype of this counter variable * * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type) +uint16_t StatsRegisterCounter(char *cname, struct ThreadVars_ *tv) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, + uint16_t id = StatsRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, - type, &tv->perf_public_ctx, STATS_TYPE_NORMAL, NULL); @@ -969,17 +960,14 @@ uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type) * \param cname Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered - * \param type Datatype of this counter variable * * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t SCPerfTVRegisterAvgCounter(char *cname, struct ThreadVars_ *tv, - int type) +uint16_t StatsRegisterAvgCounter(char *cname, struct ThreadVars_ *tv) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, + uint16_t id = StatsRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, - type, &tv->perf_public_ctx, STATS_TYPE_AVERAGE, NULL); @@ -993,17 +981,14 @@ uint16_t SCPerfTVRegisterAvgCounter(char *cname, struct ThreadVars_ *tv, * \param cname Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered - * \param type Datatype of this counter variable * * \retval the counter id for the newly registered counter, or the already * present counter */ -uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, - int type) +uint16_t StatsRegisterMaxCounter(char *cname, struct ThreadVars_ *tv) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, + uint16_t id = StatsRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, - type, &tv->perf_public_ctx, STATS_TYPE_MAXIMUM, NULL); @@ -1019,7 +1004,7 @@ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t SCPerfTVRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)) +uint16_t StatsRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)) { #ifdef UNITTESTS if (sc_perf_op_ctx == NULL) @@ -1027,8 +1012,7 @@ uint16_t SCPerfTVRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)) #else BUG_ON(sc_perf_op_ctx == NULL); #endif - uint16_t id = SCPerfRegisterQualifiedCounter(cname, NULL, - SC_PERF_TYPE_UINT64, + uint16_t id = StatsRegisterQualifiedCounter(cname, NULL, &(sc_perf_op_ctx->global_counter_ctx), STATS_TYPE_FUNC, Func); @@ -1048,11 +1032,11 @@ uint16_t SCPerfTVRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)) * \retval id Counter id for the newly registered counter, or the already * present counter */ -static uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, +static uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, SCPerfPublicContext *pctx) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, pctx, - STATS_TYPE_NORMAL, NULL); + uint16_t id = StatsRegisterQualifiedCounter(cname, tm_name, pctx, + STATS_TYPE_NORMAL, NULL); return id; } @@ -1358,22 +1342,13 @@ void SCPerfReleasePCA(SCPerfPrivateContext *pca) /*----------------------------------Unit_Tests--------------------------------*/ #ifdef UNITTESTS -static int SCPerfTestCounterReg01() -{ - SCPerfPublicContext pctx; - - memset(&pctx, 0, sizeof(SCPerfPublicContext)); - - return SCPerfRegisterCounter("t1", "c1", 5, &pctx); -} - static int SCPerfTestCounterReg02() { SCPerfPublicContext pctx; memset(&pctx, 0, sizeof(SCPerfPublicContext)); - return SCPerfRegisterCounter(NULL, NULL, SC_PERF_TYPE_UINT64, &pctx); + return SCPerfRegisterCounter(NULL, NULL, &pctx); } static int SCPerfTestCounterReg03() @@ -1383,7 +1358,7 @@ static int SCPerfTestCounterReg03() memset(&pctx, 0, sizeof(SCPerfPublicContext)); - result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &pctx); + result = SCPerfRegisterCounter("t1", "c1", &pctx); SCPerfReleasePerfCounterS(pctx.head); @@ -1397,11 +1372,11 @@ static int SCPerfTestCounterReg04() memset(&pctx, 0, sizeof(SCPerfPublicContext)); - SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &pctx); - SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, &pctx); - SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, &pctx); + SCPerfRegisterCounter("t1", "c1", &pctx); + SCPerfRegisterCounter("t2", "c2", &pctx); + SCPerfRegisterCounter("t3", "c3", &pctx); - result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, &pctx); + result = SCPerfRegisterCounter("t1", "c1", &pctx); SCPerfReleasePerfCounterS(pctx.head); @@ -1415,8 +1390,7 @@ static int SCPerfTestGetCntArray05() memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); + id = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); if (id != 1) { printf("id %d: ", id); return 0; @@ -1434,8 +1408,7 @@ static int SCPerfTestGetCntArray06() memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); + id = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); if (id != 1) return 0; @@ -1459,10 +1432,8 @@ static int SCPerfTestCntArraySize07() //pca = (SCPerfPrivateContext *)&tv.perf_private_ctx; - SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); - SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); + SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); + SCPerfRegisterCounter("t2", "c2", &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; @@ -1487,8 +1458,7 @@ static int SCPerfTestUpdateCounter08() memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); + id = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; @@ -1513,16 +1483,11 @@ static int SCPerfTestUpdateCounter09() memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); - SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); - SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); - SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); - id2 = SCPerfRegisterCounter("t5", "c5", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); + id1 = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); + SCPerfRegisterCounter("t2", "c2", &tv.perf_public_ctx); + SCPerfRegisterCounter("t3", "c3", &tv.perf_public_ctx); + SCPerfRegisterCounter("t4", "c4", &tv.perf_public_ctx); + id2 = SCPerfRegisterCounter("t5", "c5", &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; @@ -1548,12 +1513,9 @@ static int SCPerfTestUpdateGlobalCounter10() memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); - id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); - id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); + id1 = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); + id2 = SCPerfRegisterCounter("t2", "c2", &tv.perf_public_ctx); + id3 = SCPerfRegisterCounter("t3", "c3", &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; @@ -1585,14 +1547,10 @@ static int SCPerfTestCounterValues11() memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); - id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); - id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); - id4 = SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, - &tv.perf_public_ctx); + id1 = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); + id2 = SCPerfRegisterCounter("t2", "c2", &tv.perf_public_ctx); + id3 = SCPerfRegisterCounter("t3", "c3", &tv.perf_public_ctx); + id4 = SCPerfRegisterCounter("t4", "c4", &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; @@ -1623,7 +1581,6 @@ static int SCPerfTestCounterValues11() void SCPerfRegisterTests() { #ifdef UNITTESTS - UtRegisterTest("SCPerfTestCounterReg01", SCPerfTestCounterReg01, 0); UtRegisterTest("SCPerfTestCounterReg02", SCPerfTestCounterReg02, 0); UtRegisterTest("SCPerfTestCounterReg03", SCPerfTestCounterReg03, 1); UtRegisterTest("SCPerfTestCounterReg04", SCPerfTestCounterReg04, 1); diff --git a/src/counters.h b/src/counters.h index 8d9113f68490..82378c02fec0 100644 --- a/src/counters.h +++ b/src/counters.h @@ -28,14 +28,6 @@ /* forward declaration of the ThreadVars structure */ struct ThreadVars_; -/** - * \brief Data type for different kind of Perf counters that can be registered - */ -enum { - SC_PERF_TYPE_UINT64, - SC_PERF_TYPE_MAX, -}; - /** * \brief Container to hold the counter variable */ @@ -117,10 +109,10 @@ void SCPerfSpawnThreads(void); void SCPerfRegisterTests(void); /* counter registration functions */ -uint16_t SCPerfTVRegisterCounter(char *, struct ThreadVars_ *, int); -uint16_t SCPerfTVRegisterAvgCounter(char *, struct ThreadVars_ *, int); -uint16_t SCPerfTVRegisterMaxCounter(char *, struct ThreadVars_ *, int); -uint16_t SCPerfTVRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)); +uint16_t StatsRegisterCounter(char *, struct ThreadVars_ *); +uint16_t StatsRegisterAvgCounter(char *, struct ThreadVars_ *); +uint16_t StatsRegisterMaxCounter(char *, struct ThreadVars_ *); +uint16_t StatsRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)); /* utility functions */ int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfPublicContext *); diff --git a/src/decode.c b/src/decode.c index 4e2613e79fd0..b096bf5753ee 100644 --- a/src/decode.c +++ b/src/decode.c @@ -370,78 +370,46 @@ void PacketDefragPktSetupParent(Packet *parent) void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) { /* register counters */ - dtv->counter_pkts = SCPerfTVRegisterCounter("decoder.pkts", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_bytes = SCPerfTVRegisterCounter("decoder.bytes", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_invalid = SCPerfTVRegisterCounter("decoder.invalid", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_ipv4 = SCPerfTVRegisterCounter("decoder.ipv4", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_ipv6 = SCPerfTVRegisterCounter("decoder.ipv6", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_eth = SCPerfTVRegisterCounter("decoder.ethernet", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_raw = SCPerfTVRegisterCounter("decoder.raw", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_null = SCPerfTVRegisterCounter("decoder.null", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_sll = SCPerfTVRegisterCounter("decoder.sll", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_tcp = SCPerfTVRegisterCounter("decoder.tcp", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_udp = SCPerfTVRegisterCounter("decoder.udp", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_sctp = SCPerfTVRegisterCounter("decoder.sctp", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_icmpv4 = SCPerfTVRegisterCounter("decoder.icmpv4", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_icmpv6 = SCPerfTVRegisterCounter("decoder.icmpv6", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_ppp = SCPerfTVRegisterCounter("decoder.ppp", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_pppoe = SCPerfTVRegisterCounter("decoder.pppoe", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_gre = SCPerfTVRegisterCounter("decoder.gre", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_vlan = SCPerfTVRegisterCounter("decoder.vlan", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_vlan_qinq = SCPerfTVRegisterCounter("decoder.vlan_qinq", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_teredo = SCPerfTVRegisterCounter("decoder.teredo", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_ipv4inipv6 = SCPerfTVRegisterCounter("decoder.ipv4_in_ipv6", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_ipv6inipv6 = SCPerfTVRegisterCounter("decoder.ipv6_in_ipv6", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_mpls = SCPerfTVRegisterCounter("decoder.mpls", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_avg_pkt_size = SCPerfTVRegisterAvgCounter("decoder.avg_pkt_size", tv, - SC_PERF_TYPE_UINT64); - dtv->counter_max_pkt_size = SCPerfTVRegisterMaxCounter("decoder.max_pkt_size", tv, - SC_PERF_TYPE_UINT64); + dtv->counter_pkts = StatsRegisterCounter("decoder.pkts", tv); + dtv->counter_bytes = StatsRegisterCounter("decoder.bytes", tv); + dtv->counter_invalid = StatsRegisterCounter("decoder.invalid", tv); + dtv->counter_ipv4 = StatsRegisterCounter("decoder.ipv4", tv); + dtv->counter_ipv6 = StatsRegisterCounter("decoder.ipv6", tv); + dtv->counter_eth = StatsRegisterCounter("decoder.ethernet", tv); + dtv->counter_raw = StatsRegisterCounter("decoder.raw", tv); + dtv->counter_null = StatsRegisterCounter("decoder.null", tv); + dtv->counter_sll = StatsRegisterCounter("decoder.sll", tv); + dtv->counter_tcp = StatsRegisterCounter("decoder.tcp", tv); + dtv->counter_udp = StatsRegisterCounter("decoder.udp", tv); + dtv->counter_sctp = StatsRegisterCounter("decoder.sctp", tv); + dtv->counter_icmpv4 = StatsRegisterCounter("decoder.icmpv4", tv); + dtv->counter_icmpv6 = StatsRegisterCounter("decoder.icmpv6", tv); + dtv->counter_ppp = StatsRegisterCounter("decoder.ppp", tv); + dtv->counter_pppoe = StatsRegisterCounter("decoder.pppoe", tv); + dtv->counter_gre = StatsRegisterCounter("decoder.gre", tv); + dtv->counter_vlan = StatsRegisterCounter("decoder.vlan", tv); + dtv->counter_vlan_qinq = StatsRegisterCounter("decoder.vlan_qinq", tv); + dtv->counter_teredo = StatsRegisterCounter("decoder.teredo", tv); + dtv->counter_ipv4inipv6 = StatsRegisterCounter("decoder.ipv4_in_ipv6", tv); + dtv->counter_ipv6inipv6 = StatsRegisterCounter("decoder.ipv6_in_ipv6", tv); + dtv->counter_mpls = StatsRegisterCounter("decoder.mpls", tv); + dtv->counter_avg_pkt_size = StatsRegisterAvgCounter("decoder.avg_pkt_size", tv); + dtv->counter_max_pkt_size = StatsRegisterMaxCounter("decoder.max_pkt_size", tv); dtv->counter_defrag_ipv4_fragments = - SCPerfTVRegisterCounter("defrag.ipv4.fragments", tv, - SC_PERF_TYPE_UINT64); + StatsRegisterCounter("defrag.ipv4.fragments", tv); dtv->counter_defrag_ipv4_reassembled = - SCPerfTVRegisterCounter("defrag.ipv4.reassembled", tv, - SC_PERF_TYPE_UINT64); + StatsRegisterCounter("defrag.ipv4.reassembled", tv); dtv->counter_defrag_ipv4_timeouts = - SCPerfTVRegisterCounter("defrag.ipv4.timeouts", tv, - SC_PERF_TYPE_UINT64); + StatsRegisterCounter("defrag.ipv4.timeouts", tv); dtv->counter_defrag_ipv6_fragments = - SCPerfTVRegisterCounter("defrag.ipv6.fragments", tv, - SC_PERF_TYPE_UINT64); + StatsRegisterCounter("defrag.ipv6.fragments", tv); dtv->counter_defrag_ipv6_reassembled = - SCPerfTVRegisterCounter("defrag.ipv6.reassembled", tv, - SC_PERF_TYPE_UINT64); + StatsRegisterCounter("defrag.ipv6.reassembled", tv); dtv->counter_defrag_ipv6_timeouts = - SCPerfTVRegisterCounter("defrag.ipv6.timeouts", tv, - SC_PERF_TYPE_UINT64); + StatsRegisterCounter("defrag.ipv6.timeouts", tv); dtv->counter_defrag_max_hit = - SCPerfTVRegisterCounter("defrag.max_frag_hits", tv, - SC_PERF_TYPE_UINT64); + StatsRegisterCounter("defrag.max_frag_hits", tv); return; } diff --git a/src/detect-engine.c b/src/detect-engine.c index 355cdef9d141..6c27b76da0a7 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1347,17 +1347,12 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) { /* first register the counter. In delayed detect mode we exit right after if the * rules haven't been loaded yet. */ - uint16_t counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, - SC_PERF_TYPE_UINT64); + uint16_t counter_alerts = StatsRegisterCounter("detect.alert", tv); #ifdef PROFILING - uint16_t counter_mpm_list = SCPerfTVRegisterAvgCounter("detect.mpm_list", tv, - SC_PERF_TYPE_UINT64); - uint16_t counter_nonmpm_list = SCPerfTVRegisterAvgCounter("detect.nonmpm_list", tv, - SC_PERF_TYPE_UINT64); - uint16_t counter_fnonmpm_list = SCPerfTVRegisterAvgCounter("detect.fnonmpm_list", tv, - SC_PERF_TYPE_UINT64); - uint16_t counter_match_list = SCPerfTVRegisterAvgCounter("detect.match_list", tv, - SC_PERF_TYPE_UINT64); + uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv); + uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv); + uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv); + uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv); #endif DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); if (unlikely(det_ctx == NULL)) @@ -1431,17 +1426,12 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( } /** alert counter setup */ - det_ctx->counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, - SC_PERF_TYPE_UINT64); + det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv); #ifdef PROFILING - uint16_t counter_mpm_list = SCPerfTVRegisterAvgCounter("detect.mpm_list", tv, - SC_PERF_TYPE_UINT64); - uint16_t counter_nonmpm_list = SCPerfTVRegisterAvgCounter("detect.nonmpm_list", tv, - SC_PERF_TYPE_UINT64); - uint16_t counter_fnonmpm_list = SCPerfTVRegisterAvgCounter("detect.fnonmpm_list", tv, - SC_PERF_TYPE_UINT64); - uint16_t counter_match_list = SCPerfTVRegisterAvgCounter("detect.match_list", tv, - SC_PERF_TYPE_UINT64); + uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv); + uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv); + uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv); + uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv); det_ctx->counter_mpm_list = counter_mpm_list; det_ctx->counter_nonmpm_list = counter_nonmpm_list; det_ctx->counter_fnonmpm_list = counter_fnonmpm_list; diff --git a/src/flow-manager.c b/src/flow-manager.c index 71bdef657237..1b5b24c4965e 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -524,22 +524,14 @@ static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) /* pass thread data back to caller */ *data = ftd; - ftd->flow_mgr_cnt_clo = SCPerfTVRegisterCounter("flow_mgr.closed_pruned", t, - SC_PERF_TYPE_UINT64); - ftd->flow_mgr_cnt_new = SCPerfTVRegisterCounter("flow_mgr.new_pruned", t, - SC_PERF_TYPE_UINT64); - ftd->flow_mgr_cnt_est = SCPerfTVRegisterCounter("flow_mgr.est_pruned", t, - SC_PERF_TYPE_UINT64); - ftd->flow_mgr_memuse = SCPerfTVRegisterCounter("flow.memuse", t, - SC_PERF_TYPE_UINT64); - ftd->flow_mgr_spare = SCPerfTVRegisterCounter("flow.spare", t, - SC_PERF_TYPE_UINT64); - ftd->flow_emerg_mode_enter = SCPerfTVRegisterCounter("flow.emerg_mode_entered", t, - SC_PERF_TYPE_UINT64); - ftd->flow_emerg_mode_over = SCPerfTVRegisterCounter("flow.emerg_mode_over", t, - SC_PERF_TYPE_UINT64); - ftd->flow_tcp_reuse = SCPerfTVRegisterCounter("flow.tcp_reuse", t, - SC_PERF_TYPE_UINT64); + ftd->flow_mgr_cnt_clo = StatsRegisterCounter("flow_mgr.closed_pruned", t); + ftd->flow_mgr_cnt_new = StatsRegisterCounter("flow_mgr.new_pruned", t); + ftd->flow_mgr_cnt_est = StatsRegisterCounter("flow_mgr.est_pruned", t); + ftd->flow_mgr_memuse = StatsRegisterCounter("flow.memuse", t); + ftd->flow_mgr_spare = StatsRegisterCounter("flow.spare", t); + ftd->flow_emerg_mode_enter = StatsRegisterCounter("flow.emerg_mode_entered", t); + ftd->flow_emerg_mode_over = StatsRegisterCounter("flow.emerg_mode_over", t); + ftd->flow_tcp_reuse = StatsRegisterCounter("flow.tcp_reuse", t); PacketPoolInit(); return TM_ECODE_OK; @@ -575,12 +567,9 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) int flow_update_delay_nsec = FLOW_NORMAL_MODE_UPDATE_DELAY_NSEC; /* VJ leaving disabled for now, as hosts are only used by tags and the numbers * are really low. Might confuse ppl - uint16_t flow_mgr_host_prune = SCPerfTVRegisterCounter("hosts.pruned", th_v, - SC_PERF_TYPE_UINT64); - uint16_t flow_mgr_host_active = SCPerfTVRegisterCounter("hosts.active", th_v, - SC_PERF_TYPE_UINT64); - uint16_t flow_mgr_host_spare = SCPerfTVRegisterCounter("hosts.spare", th_v, - SC_PERF_TYPE_UINT64); + uint16_t flow_mgr_host_prune = StatsRegisterCounter("hosts.pruned", th_v); + uint16_t flow_mgr_host_active = StatsRegisterCounter("hosts.active", th_v); + uint16_t flow_mgr_host_spare = StatsRegisterCounter("hosts.spare", th_v); */ memset(&ts, 0, sizeof(ts)); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 3b50ba8f3167..5fdaa8031762 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1714,10 +1714,10 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) } #ifdef PACKET_STATISTICS - ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, SC_PERF_TYPE_UINT64); - ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, SC_PERF_TYPE_UINT64); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ptv->tv); #endif char *active_runmode = RunmodeGetActive(); diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index 55b273e0aa9b..0854a87c5798 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -304,10 +304,8 @@ ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_FAILED); } - ewtn->packets = SCPerfTVRegisterCounter("capture.dag_packets", - tv, SC_PERF_TYPE_UINT64); - ewtn->drops = SCPerfTVRegisterCounter("capture.dag_drops", - tv, SC_PERF_TYPE_UINT64); + ewtn->packets = StatsRegisterCounter("capture.dag_packets", tv); + ewtn->drops = StatsRegisterCounter("capture.dag_drops", tv); ewtn->tv = tv; *data = (void *)ewtn; diff --git a/src/source-mpipe.c b/src/source-mpipe.c index 665282605e9f..bb3655afdb39 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -436,28 +436,16 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) static void MpipeRegisterPerfCounters(MpipeThreadVars *ptv, ThreadVars *tv) { /* register counters */ - ptv->max_mpipe_depth = SCPerfTVRegisterCounter("mpipe.max_mpipe_depth", - tv, - SC_PERF_TYPE_UINT64); - ptv->mpipe_drop = SCPerfTVRegisterCounter("mpipe.drop", - tv, - SC_PERF_TYPE_UINT64); - ptv->counter_no_buffers_0 = SCPerfTVRegisterCounter("mpipe.no_buf0", tv, - SC_PERF_TYPE_UINT64); - ptv->counter_no_buffers_1 = SCPerfTVRegisterCounter("mpipe.no_buf1", tv, - SC_PERF_TYPE_UINT64); - ptv->counter_no_buffers_2 = SCPerfTVRegisterCounter("mpipe.no_buf2", tv, - SC_PERF_TYPE_UINT64); - ptv->counter_no_buffers_3 = SCPerfTVRegisterCounter("mpipe.no_buf3", tv, - SC_PERF_TYPE_UINT64); - ptv->counter_no_buffers_4 = SCPerfTVRegisterCounter("mpipe.no_buf4", tv, - SC_PERF_TYPE_UINT64); - ptv->counter_no_buffers_5 = SCPerfTVRegisterCounter("mpipe.no_buf5", tv, - SC_PERF_TYPE_UINT64); - ptv->counter_no_buffers_6 = SCPerfTVRegisterCounter("mpipe.no_buf6", tv, - SC_PERF_TYPE_UINT64); - ptv->counter_no_buffers_7 = SCPerfTVRegisterCounter("mpipe.no_buf7", tv, - SC_PERF_TYPE_UINT64); + ptv->max_mpipe_depth = StatsRegisterCounter("mpipe.max_mpipe_depth", tv); + ptv->mpipe_drop = StatsRegisterCounter("mpipe.drop", tv); + ptv->counter_no_buffers_0 = StatsRegisterCounter("mpipe.no_buf0", tv); + ptv->counter_no_buffers_1 = StatsRegisterCounter("mpipe.no_buf1", tv); + ptv->counter_no_buffers_2 = StatsRegisterCounter("mpipe.no_buf2", tv); + ptv->counter_no_buffers_3 = StatsRegisterCounter("mpipe.no_buf3", tv); + ptv->counter_no_buffers_4 = StatsRegisterCounter("mpipe.no_buf4", tv); + ptv->counter_no_buffers_5 = StatsRegisterCounter("mpipe.no_buf5", tv); + ptv->counter_no_buffers_6 = StatsRegisterCounter("mpipe.no_buf6", tv); + ptv->counter_no_buffers_7 = StatsRegisterCounter("mpipe.no_buf7", tv); } static const gxio_mpipe_buffer_size_enum_t gxio_buffer_sizes[] = { diff --git a/src/source-netmap.c b/src/source-netmap.c index adf330fc67f7..0b70c6a6c6d6 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -554,10 +554,10 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da } /* basic counters */ - ntv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ntv->tv, SC_PERF_TYPE_UINT64); - ntv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ntv->tv, SC_PERF_TYPE_UINT64); + ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ntv->tv); + ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ntv->tv); char const *active_runmode = RunmodeGetActive(); if (active_runmode && !strcmp("workers", active_runmode)) { diff --git a/src/source-nflog.c b/src/source-nflog.c index 98406ed504be..cb462af57e82 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -307,12 +307,10 @@ TmEcode ReceiveNFLOGThreadInit(ThreadVars *tv, void *initdata, void **data) } #ifdef PACKET_STATISTICS - ntv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ntv->tv, - SC_PERF_TYPE_UINT64); - ntv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ntv->tv, - SC_PERF_TYPE_UINT64); + ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ntv->tv); + ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ntv->tv); #endif char *active_runmode = RunmodeGetActive(); diff --git a/src/source-pcap.c b/src/source-pcap.c index 57237fed1440..a092a7599e2f 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -521,12 +521,12 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) pcapconfig->DerefFunc(pcapconfig); - ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, SC_PERF_TYPE_UINT64); - ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, SC_PERF_TYPE_UINT64); - ptv->capture_kernel_ifdrops = SCPerfTVRegisterCounter("capture.kernel_ifdrops", - ptv->tv, SC_PERF_TYPE_UINT64); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ptv->tv); + ptv->capture_kernel_ifdrops = StatsRegisterCounter("capture.kernel_ifdrops", + ptv->tv); *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); @@ -620,12 +620,12 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->datalink = pcap_datalink(ptv->pcap_handle); - ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, SC_PERF_TYPE_UINT64); - ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, SC_PERF_TYPE_UINT64); - ptv->capture_kernel_ifdrops = SCPerfTVRegisterCounter("capture.kernel_ifdrops", - ptv->tv, SC_PERF_TYPE_UINT64); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ptv->tv); + ptv->capture_kernel_ifdrops = StatsRegisterCounter("capture.kernel_ifdrops", + ptv->tv); *data = (void *)ptv; diff --git a/src/source-pfring.c b/src/source-pfring.c index a7f1342a5c71..a9fff4cbe22e 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -497,10 +497,10 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) } } - ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, SC_PERF_TYPE_UINT64); - ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, SC_PERF_TYPE_UINT64); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ptv->tv); /* A bit strange to have this here but we only have vlan information * during reading so we need to know if we want to keep vlan during diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 7331db1bd3b7..839a9ccd55f4 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -514,7 +514,7 @@ int StreamTcpReassembleInit(char quiet) SCMutexInit(&segment_pool_cnt_mutex, NULL); #endif - SCPerfTVRegisterGlobalCounter("tcp.reassembly_memuse", + StatsRegisterGlobalCounter("tcp.reassembly_memuse", StreamTcpReassembleMemuseGlobalCounter); return 0; } diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 2136a8f5d525..00e1e423a53f 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5073,43 +5073,28 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) *data = (void *)stt; - stt->counter_tcp_sessions = SCPerfTVRegisterCounter("tcp.sessions", tv, - SC_PERF_TYPE_UINT64); - stt->counter_tcp_ssn_memcap = SCPerfTVRegisterCounter("tcp.ssn_memcap_drop", tv, - SC_PERF_TYPE_UINT64); - stt->counter_tcp_pseudo = SCPerfTVRegisterCounter("tcp.pseudo", tv, - SC_PERF_TYPE_UINT64); - stt->counter_tcp_pseudo_failed = SCPerfTVRegisterCounter("tcp.pseudo_failed", tv, - SC_PERF_TYPE_UINT64); - stt->counter_tcp_invalid_checksum = SCPerfTVRegisterCounter("tcp.invalid_checksum", tv, - SC_PERF_TYPE_UINT64); - stt->counter_tcp_no_flow = SCPerfTVRegisterCounter("tcp.no_flow", tv, - SC_PERF_TYPE_UINT64); - stt->counter_tcp_memuse = SCPerfTVRegisterCounter("tcp.memuse", tv, - SC_PERF_TYPE_UINT64); - stt->counter_tcp_syn = SCPerfTVRegisterCounter("tcp.syn", tv, - SC_PERF_TYPE_UINT64); - stt->counter_tcp_synack = SCPerfTVRegisterCounter("tcp.synack", tv, - SC_PERF_TYPE_UINT64); - stt->counter_tcp_rst = SCPerfTVRegisterCounter("tcp.rst", tv, - SC_PERF_TYPE_UINT64); + stt->counter_tcp_sessions = StatsRegisterCounter("tcp.sessions", tv); + stt->counter_tcp_ssn_memcap = StatsRegisterCounter("tcp.ssn_memcap_drop", tv); + stt->counter_tcp_pseudo = StatsRegisterCounter("tcp.pseudo", tv); + stt->counter_tcp_pseudo_failed = StatsRegisterCounter("tcp.pseudo_failed", tv); + stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", tv); + stt->counter_tcp_no_flow = StatsRegisterCounter("tcp.no_flow", tv); + stt->counter_tcp_memuse = StatsRegisterCounter("tcp.memuse", tv); + stt->counter_tcp_syn = StatsRegisterCounter("tcp.syn", tv); + stt->counter_tcp_synack = StatsRegisterCounter("tcp.synack", tv); + stt->counter_tcp_rst = StatsRegisterCounter("tcp.rst", tv); /* init reassembly ctx */ stt->ra_ctx = StreamTcpReassembleInitThreadCtx(tv); if (stt->ra_ctx == NULL) SCReturnInt(TM_ECODE_FAILED); - stt->ra_ctx->counter_tcp_segment_memcap = SCPerfTVRegisterCounter("tcp.segment_memcap_drop", tv, - SC_PERF_TYPE_UINT64); - stt->ra_ctx->counter_tcp_stream_depth = SCPerfTVRegisterCounter("tcp.stream_depth_reached", tv, - SC_PERF_TYPE_UINT64); - stt->ra_ctx->counter_tcp_reass_gap = SCPerfTVRegisterCounter("tcp.reassembly_gap", tv, - SC_PERF_TYPE_UINT64); + stt->ra_ctx->counter_tcp_segment_memcap = StatsRegisterCounter("tcp.segment_memcap_drop", tv); + stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv); + stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv); /** \fixme Find a better place in 2.1 as it is linked with app layer */ - stt->ra_ctx->counter_htp_memuse = SCPerfTVRegisterCounter("http.memuse", tv, - SC_PERF_TYPE_UINT64); - stt->ra_ctx->counter_htp_memcap = SCPerfTVRegisterCounter("http.memcap", tv, - SC_PERF_TYPE_UINT64); + stt->ra_ctx->counter_htp_memuse = StatsRegisterCounter("http.memuse", tv); + stt->ra_ctx->counter_htp_memcap = StatsRegisterCounter("http.memcap", tv); SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p", stt, stt->ra_ctx); From 60d9eb6790d8f7d9fd2faf3d5b415d818a84591c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 14:38:02 +0200 Subject: [PATCH 0514/2553] counters: clean up defines --- src/counters.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/counters.c b/src/counters.c index 0e686191cf2f..8c2852fd8398 100644 --- a/src/counters.c +++ b/src/counters.c @@ -38,17 +38,11 @@ #include "unix-manager.h" #include "output.h" -/** \todo Get the default log directory from some global resource. */ -#define SC_PERF_DEFAULT_LOG_FILENAME "stats.log" - -/* Used to parse the interval for Timebased counters */ -#define SC_PERF_PCRE_TIMEBASED_INTERVAL "^(?:(\\d+)([shm]))(?:(\\d+)([shm]))?(?:(\\d+)([shm]))?$" - /* Time interval for syncing the local counters with the global ones */ -#define SC_PERF_WUT_TTS 3 +#define STATS_WUT_TTS 3 /* Time interval at which the mgmt thread o/p the stats */ -#define SC_PERF_MGMTT_TTS 8 +#define STATS_MGMTT_TTS 8 /** * \brief Different kinds of qualifier that can be used to modify the behaviour @@ -97,7 +91,7 @@ static void *stats_thread_data = NULL; static StatsGlobalContext *sc_perf_op_ctx = NULL; static time_t sc_start_time; /** refresh interval in seconds */ -static uint32_t sc_counter_tts = SC_PERF_MGMTT_TTS; +static uint32_t sc_counter_tts = STATS_MGMTT_TTS; /** is the stats counter enabled? */ static char sc_counter_enabled = TRUE; @@ -418,7 +412,7 @@ static void *SCPerfWakeupThread(void *arg) TmThreadsUnsetFlag(tv_local, THV_PAUSED); } - cond_time.tv_sec = time(NULL) + SC_PERF_WUT_TTS; + cond_time.tv_sec = time(NULL) + STATS_WUT_TTS; cond_time.tv_nsec = 0; /* wait for the set time, or until we are woken up by From 8992275b0c27aa3185696304b0526a2971231e63 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 14:45:43 +0200 Subject: [PATCH 0515/2553] counters: s/SCPerfCounterAddUI64/StatsAddUI64/g --- src/counters.c | 16 ++++++++-------- src/counters.h | 2 +- src/detect.c | 10 +++++----- src/flow-manager.c | 10 +++++----- src/source-af-packet.c | 8 ++++---- src/source-erf-dag.c | 6 +++--- src/source-erf-file.c | 4 ++-- src/source-ipfw.c | 4 ++-- src/source-mpipe.c | 4 ++-- src/source-napatech.c | 4 ++-- src/source-netmap.c | 8 ++++---- src/source-nflog.c | 4 ++-- src/source-nfq.c | 4 ++-- src/source-pcap-file.c | 4 ++-- src/source-pcap.c | 4 ++-- src/source-pfring.c | 4 ++-- 16 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/counters.c b/src/counters.c index 8c2852fd8398..5473b01b4a3c 100644 --- a/src/counters.c +++ b/src/counters.c @@ -119,7 +119,7 @@ void SCPerfOutputCounters(ThreadVars *tv) * \param pca Counter array that holds the local counter for this TM * \param x Value to add to this local counter */ -void SCPerfCounterAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) +void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) { SCPerfPrivateContext *pca = &tv->perf_private_ctx; #ifdef UNITTESTS @@ -1458,7 +1458,7 @@ static int SCPerfTestUpdateCounter08() pca = &tv.perf_private_ctx; SCPerfCounterIncr(&tv, id); - SCPerfCounterAddUI64(&tv, id, 100); + StatsAddUI64(&tv, id, 100); result = pca->head[id].value; @@ -1487,7 +1487,7 @@ static int SCPerfTestUpdateCounter09() pca = &tv.perf_private_ctx; SCPerfCounterIncr(&tv, id2); - SCPerfCounterAddUI64(&tv, id2, 100); + StatsAddUI64(&tv, id2, 100); result = (pca->head[id1].value == 0) && (pca->head[id2].value == 101); @@ -1515,9 +1515,9 @@ static int SCPerfTestUpdateGlobalCounter10() pca = &tv.perf_private_ctx; SCPerfCounterIncr(&tv, id1); - SCPerfCounterAddUI64(&tv, id2, 100); + StatsAddUI64(&tv, id2, 100); SCPerfCounterIncr(&tv, id3); - SCPerfCounterAddUI64(&tv, id3, 100); + StatsAddUI64(&tv, id3, 100); SCPerfUpdateCounterArray(pca, &tv.perf_public_ctx); @@ -1550,9 +1550,9 @@ static int SCPerfTestCounterValues11() pca = &tv.perf_private_ctx; SCPerfCounterIncr(&tv, id1); - SCPerfCounterAddUI64(&tv, id2, 256); - SCPerfCounterAddUI64(&tv, id3, 257); - SCPerfCounterAddUI64(&tv, id4, 16843024); + StatsAddUI64(&tv, id2, 256); + StatsAddUI64(&tv, id3, 257); + StatsAddUI64(&tv, id4, 16843024); SCPerfUpdateCounterArray(pca, &tv.perf_public_ctx); diff --git a/src/counters.h b/src/counters.h index 82378c02fec0..7f463d91c668 100644 --- a/src/counters.h +++ b/src/counters.h @@ -124,7 +124,7 @@ void SCPerfReleaseResources(void); void SCPerfReleasePCA(SCPerfPrivateContext *); /* functions used to update local counter values */ -void SCPerfCounterAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); +void StatsAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); void SCPerfCounterSetUI64(struct ThreadVars_ *, uint16_t, uint64_t); void SCPerfCounterIncr(struct ThreadVars_ *, uint16_t); diff --git a/src/detect.c b/src/detect.c index b95d5859cb9c..2156187c3af9 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1437,12 +1437,12 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); #ifdef PROFILING if (th_v) { - SCPerfCounterAddUI64(th_v, det_ctx->counter_mpm_list, + StatsAddUI64(th_v, det_ctx->counter_mpm_list, (uint64_t)det_ctx->pmq.rule_id_array_cnt); - SCPerfCounterAddUI64(th_v, det_ctx->counter_nonmpm_list, + StatsAddUI64(th_v, det_ctx->counter_nonmpm_list, (uint64_t)det_ctx->sgh->non_mpm_store_cnt); /* non mpm sigs after mask prefilter */ - SCPerfCounterAddUI64(th_v, det_ctx->counter_fnonmpm_list, + StatsAddUI64(th_v, det_ctx->counter_fnonmpm_list, (uint64_t)det_ctx->non_mpm_id_cnt); } #endif @@ -1457,7 +1457,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SigIntId match_cnt = det_ctx->match_array_cnt; #ifdef PROFILING if (th_v) { - SCPerfCounterAddUI64(th_v, det_ctx->counter_match_list, + StatsAddUI64(th_v, det_ctx->counter_match_list, (uint64_t)match_cnt); } #endif @@ -1790,7 +1790,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_START(p, PROF_DETECT_ALERT); PacketAlertFinalize(de_ctx, det_ctx, p); if (p->alerts.cnt > 0) { - SCPerfCounterAddUI64(th_v, det_ctx->counter_alerts, (uint64_t)p->alerts.cnt); + StatsAddUI64(th_v, det_ctx->counter_alerts, (uint64_t)p->alerts.cnt); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_ALERT); diff --git a/src/flow-manager.c b/src/flow-manager.c index 1b5b24c4965e..eca211f09c1b 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -621,18 +621,18 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) IPPairTimeoutHash(&ts); } /* - SCPerfCounterAddUI64(th_v, flow_mgr_host_prune, (uint64_t)hosts_pruned); + StatsAddUI64(th_v, flow_mgr_host_prune, (uint64_t)hosts_pruned); uint32_t hosts_active = HostGetActiveCount(); SCPerfCounterSetUI64(th_v, flow_mgr_host_active, (uint64_t)hosts_active); uint32_t hosts_spare = HostGetSpareCount(); SCPerfCounterSetUI64(th_v, flow_mgr_host_spare, (uint64_t)hosts_spare); */ - SCPerfCounterAddUI64(th_v, ftd->flow_mgr_cnt_clo, (uint64_t)counters.clo); - SCPerfCounterAddUI64(th_v, ftd->flow_mgr_cnt_new, (uint64_t)counters.new); - SCPerfCounterAddUI64(th_v, ftd->flow_mgr_cnt_est, (uint64_t)counters.est); + StatsAddUI64(th_v, ftd->flow_mgr_cnt_clo, (uint64_t)counters.clo); + StatsAddUI64(th_v, ftd->flow_mgr_cnt_new, (uint64_t)counters.new); + StatsAddUI64(th_v, ftd->flow_mgr_cnt_est, (uint64_t)counters.est); long long unsigned int flow_memuse = SC_ATOMIC_GET(flow_memuse); SCPerfCounterSetUI64(th_v, ftd->flow_mgr_memuse, (uint64_t)flow_memuse); - SCPerfCounterAddUI64(th_v, ftd->flow_tcp_reuse, (uint64_t)counters.tcp_reuse); + StatsAddUI64(th_v, ftd->flow_tcp_reuse, (uint64_t)counters.tcp_reuse); uint32_t len = 0; FQLOCK_LOCK(&flow_spare_q); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 5fdaa8031762..1fffe2ba0f62 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -511,8 +511,8 @@ static inline void AFPDumpCounters(AFPThreadVars *ptv) SCLogDebug("(%s) Kernel: Packets %" PRIu32 ", dropped %" PRIu32 "", ptv->tv->name, kstats.tp_packets, kstats.tp_drops); - SCPerfCounterAddUI64(ptv->tv, ptv->capture_kernel_packets, kstats.tp_packets); - SCPerfCounterAddUI64(ptv->tv, ptv->capture_kernel_drops, kstats.tp_drops); + StatsAddUI64(ptv->tv, ptv->capture_kernel_packets, kstats.tp_packets); + StatsAddUI64(ptv->tv, ptv->capture_kernel_drops, kstats.tp_drops); (void) SC_ATOMIC_ADD(ptv->livedev->drop, (uint64_t) kstats.tp_drops); (void) SC_ATOMIC_ADD(ptv->livedev->pkts, (uint64_t) kstats.tp_packets); } @@ -1854,8 +1854,8 @@ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* If suri has set vlan during reading, we increase vlan counter */ diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index 0854a87c5798..7394ddd04354 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -442,7 +442,7 @@ ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) break; case TYPE_ETH: if (dr->lctr) { - SCPerfCounterAddUI64(tv, ewtn->drops, ntohs(dr->lctr)); + StatsAddUI64(tv, ewtn->drops, ntohs(dr->lctr)); } break; default: @@ -623,8 +623,8 @@ DecodeErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* call the decoder */ diff --git a/src/source-erf-file.c b/src/source-erf-file.c index 38fa57ca9f7a..5bc4c38f5c6a 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -286,8 +286,8 @@ DecodeErfFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueu /* Update counters. */ SCPerfCounterIncr(tv, dtv->counter_pkts); //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-ipfw.c b/src/source-ipfw.c index 8163d8387d8b..75965465076c 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -453,8 +453,8 @@ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* Process IP packets */ diff --git a/src/source-mpipe.c b/src/source-mpipe.c index bb3655afdb39..5a9d60eeebb7 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -1042,9 +1042,9 @@ TmEcode DecodeMpipe(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, SCPerfCounterIncr(tv, dtv->counter_pkts); // SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* call the decoder */ diff --git a/src/source-napatech.c b/src/source-napatech.c index f3430d079209..ed32ded4948b 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -359,8 +359,8 @@ TmEcode NapatechDecode(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); // SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); switch (p->datalink) { diff --git a/src/source-netmap.c b/src/source-netmap.c index 0b70c6a6c6d6..e0e52977134d 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -483,8 +483,8 @@ static int NetmapClose(NetmapDevice *dev) */ static inline void NetmapDumpCounters(NetmapThreadVars *ntv) { - SCPerfCounterAddUI64(ntv->tv, ntv->capture_kernel_packets, ntv->pkts); - SCPerfCounterAddUI64(ntv->tv, ntv->capture_kernel_drops, ntv->drops); + StatsAddUI64(ntv->tv, ntv->capture_kernel_packets, ntv->pkts); + StatsAddUI64(ntv->tv, ntv->capture_kernel_drops, ntv->drops); (void) SC_ATOMIC_ADD(ntv->livedev->drop, ntv->drops); (void) SC_ATOMIC_ADD(ntv->livedev->pkts, ntv->pkts); ntv->drops = 0; @@ -931,8 +931,8 @@ static TmEcode DecodeNetmap(ThreadVars *tv, Packet *p, void *data, PacketQueue * /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-nflog.c b/src/source-nflog.c index cb462af57e82..f8dc318ce928 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -500,8 +500,8 @@ TmEcode DecodeNFLOG(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack DecodeThreadVars *dtv = (DecodeThreadVars *)data; SCPerfCounterIncr(tv, dtv->counter_pkts); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); if (IPV4_GET_RAW_VER(ip4h) == 4) { diff --git a/src/source-nfq.c b/src/source-nfq.c index a4a6ab73b677..ea2bdf83d39d 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -1224,8 +1224,8 @@ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet return TM_ECODE_OK; SCPerfCounterIncr(tv, dtv->counter_pkts); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); if (IPV4_GET_RAW_VER(ip4h) == 4) { diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 8e7e0bfd0909..7e7b8ba79b42 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -403,8 +403,8 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); double curr_ts = p->ts.tv_sec + p->ts.tv_usec / 1000.0; diff --git a/src/source-pcap.c b/src/source-pcap.c index a092a7599e2f..b92831899514 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -706,8 +706,8 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* call the decoder */ diff --git a/src/source-pfring.c b/src/source-pfring.c index a9fff4cbe22e..6e997be920ed 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -604,8 +604,8 @@ TmEcode DecodePfring(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pac /* update counters */ SCPerfCounterIncr(tv, dtv->counter_pkts); //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); - SCPerfCounterAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* If suri has set vlan during reading, we increase vlan counter */ From 1c0b4ee0aef1be39352481c5222646f55b766e1d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 14:53:24 +0200 Subject: [PATCH 0516/2553] counters: s/SCPerfCounterIncr/StatsIncr/g --- src/counters.c | 16 ++++++++-------- src/counters.h | 2 +- src/decode-ethernet.c | 2 +- src/decode-gre.c | 2 +- src/decode-icmpv4.c | 2 +- src/decode-icmpv6.c | 2 +- src/decode-ipv4.c | 2 +- src/decode-ipv6.c | 6 +++--- src/decode-mpls.c | 2 +- src/decode-null.c | 2 +- src/decode-ppp.c | 2 +- src/decode-pppoe.c | 4 ++-- src/decode-raw.c | 2 +- src/decode-sctp.c | 2 +- src/decode-sll.c | 2 +- src/decode-tcp.c | 2 +- src/decode-teredo.c | 2 +- src/decode-udp.c | 2 +- src/decode-vlan.c | 4 ++-- src/decode.c | 2 +- src/defrag.c | 8 ++++---- src/flow-manager.c | 4 ++-- src/source-af-packet.c | 6 +++--- src/source-erf-dag.c | 6 +++--- src/source-erf-file.c | 4 ++-- src/source-ipfw.c | 2 +- src/source-mpipe.c | 8 ++++---- src/source-napatech.c | 4 ++-- src/source-netmap.c | 2 +- src/source-nflog.c | 2 +- src/source-nfq.c | 2 +- src/source-pcap-file.c | 4 ++-- src/source-pcap.c | 4 ++-- src/source-pfring.c | 6 +++--- src/stream-tcp-reassemble.c | 8 ++++---- src/stream-tcp.c | 26 +++++++++++++------------- 36 files changed, 79 insertions(+), 79 deletions(-) diff --git a/src/counters.c b/src/counters.c index 5473b01b4a3c..6fcd66e23b7a 100644 --- a/src/counters.c +++ b/src/counters.c @@ -140,7 +140,7 @@ void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) * \param id Index of the counter in the counter array * \param pca Counter array that holds the local counters for this TM */ -void SCPerfCounterIncr(ThreadVars *tv, uint16_t id) +void StatsIncr(ThreadVars *tv, uint16_t id) { SCPerfPrivateContext *pca = &tv->perf_private_ctx; #ifdef UNITTESTS @@ -1432,8 +1432,8 @@ static int SCPerfTestCntArraySize07() SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; - SCPerfCounterIncr(&tv, 1); - SCPerfCounterIncr(&tv, 2); + StatsIncr(&tv, 1); + StatsIncr(&tv, 2); result = pca->size; @@ -1457,7 +1457,7 @@ static int SCPerfTestUpdateCounter08() SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; - SCPerfCounterIncr(&tv, id); + StatsIncr(&tv, id); StatsAddUI64(&tv, id, 100); result = pca->head[id].value; @@ -1486,7 +1486,7 @@ static int SCPerfTestUpdateCounter09() SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; - SCPerfCounterIncr(&tv, id2); + StatsIncr(&tv, id2); StatsAddUI64(&tv, id2, 100); result = (pca->head[id1].value == 0) && (pca->head[id2].value == 101); @@ -1514,9 +1514,9 @@ static int SCPerfTestUpdateGlobalCounter10() SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; - SCPerfCounterIncr(&tv, id1); + StatsIncr(&tv, id1); StatsAddUI64(&tv, id2, 100); - SCPerfCounterIncr(&tv, id3); + StatsIncr(&tv, id3); StatsAddUI64(&tv, id3, 100); SCPerfUpdateCounterArray(pca, &tv.perf_public_ctx); @@ -1549,7 +1549,7 @@ static int SCPerfTestCounterValues11() SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; - SCPerfCounterIncr(&tv, id1); + StatsIncr(&tv, id1); StatsAddUI64(&tv, id2, 256); StatsAddUI64(&tv, id3, 257); StatsAddUI64(&tv, id4, 16843024); diff --git a/src/counters.h b/src/counters.h index 7f463d91c668..693141fd5d9f 100644 --- a/src/counters.h +++ b/src/counters.h @@ -126,7 +126,7 @@ void SCPerfReleasePCA(SCPerfPrivateContext *); /* functions used to update local counter values */ void StatsAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); void SCPerfCounterSetUI64(struct ThreadVars_ *, uint16_t, uint64_t); -void SCPerfCounterIncr(struct ThreadVars_ *, uint16_t); +void StatsIncr(struct ThreadVars_ *, uint16_t); #define SCPerfSyncCounters(tv) \ SCPerfUpdateCounterArray(&(tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ diff --git a/src/decode-ethernet.c b/src/decode-ethernet.c index d77b7ac3b32f..ee4157236cb8 100644 --- a/src/decode-ethernet.c +++ b/src/decode-ethernet.c @@ -41,7 +41,7 @@ int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_eth); + StatsIncr(tv, dtv->counter_eth); if (unlikely(len < ETHERNET_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, ETHERNET_PKT_TOO_SMALL); diff --git a/src/decode-gre.c b/src/decode-gre.c index 42459446bd14..af4c1af55b08 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -48,7 +48,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui uint16_t header_len = GRE_HDR_LEN; GRESreHdr *gsre = NULL; - SCPerfCounterIncr(tv, dtv->counter_gre); + StatsIncr(tv, dtv->counter_gre); if(len < GRE_HDR_LEN) { ENGINE_SET_INVALID_EVENT(p, GRE_PKT_TOO_SMALL); diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index af094e4259fe..5af012ce9ac8 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -153,7 +153,7 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) */ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_icmpv4); + StatsIncr(tv, dtv->counter_icmpv4); if (len < ICMPV4_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, ICMPV4_PKT_TOO_SMALL); diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index d9bc41db6569..7972ea797c98 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -168,7 +168,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { int full_hdr = 0; - SCPerfCounterIncr(tv, dtv->counter_icmpv6); + StatsIncr(tv, dtv->counter_icmpv6); if (len < ICMPV6_HEADER_LEN) { SCLogDebug("ICMPV6_PKT_TOO_SMALL"); diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index a0ca8c173ced..856ae5b6d647 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -519,7 +519,7 @@ static int DecodeIPV4Packet(Packet *p, uint8_t *pkt, uint16_t len) int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_ipv4); + StatsIncr(tv, dtv->counter_ipv4); SCLogDebug("pkt %p len %"PRIu16"", pkt, len); diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index 12ba7705d904..efd6f10f5033 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -65,7 +65,7 @@ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, u PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); - SCPerfCounterIncr(tv, dtv->counter_ipv4inipv6); + StatsIncr(tv, dtv->counter_ipv4inipv6); return; } } @@ -92,7 +92,7 @@ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); PacketEnqueue(pq,tp); - SCPerfCounterIncr(tv, dtv->counter_ipv6inipv6); + StatsIncr(tv, dtv->counter_ipv6inipv6); } } } else { @@ -601,7 +601,7 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u { int ret; - SCPerfCounterIncr(tv, dtv->counter_ipv6); + StatsIncr(tv, dtv->counter_ipv6); /* do the actual decoding */ ret = DecodeIPV6Packet (tv, dtv, p, pkt, len); diff --git a/src/decode-mpls.c b/src/decode-mpls.c index f8a77b5831b8..1569ebfbf6b7 100644 --- a/src/decode-mpls.c +++ b/src/decode-mpls.c @@ -51,7 +51,7 @@ int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, int label; int event = 0; - SCPerfCounterIncr(tv, dtv->counter_mpls); + StatsIncr(tv, dtv->counter_mpls); do { if (len < MPLS_HEADER_LEN) { diff --git a/src/decode-null.c b/src/decode-null.c index 445a33331c2e..b3bcb0667c21 100644 --- a/src/decode-null.c +++ b/src/decode-null.c @@ -47,7 +47,7 @@ int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_null); + StatsIncr(tv, dtv->counter_null); if (unlikely(len < HDR_SIZE)) { ENGINE_SET_INVALID_EVENT(p, LTNULL_PKT_TOO_SMALL); diff --git a/src/decode-ppp.c b/src/decode-ppp.c index d6ec902512c9..f4ea670cfe49 100644 --- a/src/decode-ppp.c +++ b/src/decode-ppp.c @@ -42,7 +42,7 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_ppp); + StatsIncr(tv, dtv->counter_ppp); if (unlikely(len < PPP_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, PPP_PKT_TOO_SMALL); diff --git a/src/decode-pppoe.c b/src/decode-pppoe.c index 565a9f5894cd..b6f5031fa7db 100644 --- a/src/decode-pppoe.c +++ b/src/decode-pppoe.c @@ -49,7 +49,7 @@ */ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_pppoe); + StatsIncr(tv, dtv->counter_pppoe); if (len < PPPOE_DISCOVERY_HEADER_MIN_LEN) { ENGINE_SET_INVALID_EVENT(p, PPPOE_PKT_TOO_SMALL); @@ -128,7 +128,7 @@ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8 */ int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_pppoe); + StatsIncr(tv, dtv->counter_pppoe); if (len < PPPOE_SESSION_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, PPPOE_PKT_TOO_SMALL); diff --git a/src/decode-raw.c b/src/decode-raw.c index dc31c944cac5..22e1b9e1e908 100644 --- a/src/decode-raw.c +++ b/src/decode-raw.c @@ -45,7 +45,7 @@ int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_raw); + StatsIncr(tv, dtv->counter_raw); /* If it is ipv4 or ipv6 it should at least be the size of ipv4 */ if (unlikely(len < IPV4_HEADER_LEN)) { diff --git a/src/decode-sctp.c b/src/decode-sctp.c index 25607421256b..2d493c6690fe 100644 --- a/src/decode-sctp.c +++ b/src/decode-sctp.c @@ -61,7 +61,7 @@ static int DecodeSCTPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t le int DecodeSCTP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_sctp); + StatsIncr(tv, dtv->counter_sctp); if (unlikely(DecodeSCTPPacket(tv, p,pkt,len) < 0)) { p->sctph = NULL; diff --git a/src/decode-sll.c b/src/decode-sll.c index 0da071da9351..eed61a4c39fe 100644 --- a/src/decode-sll.c +++ b/src/decode-sll.c @@ -38,7 +38,7 @@ int DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_sll); + StatsIncr(tv, dtv->counter_sll); if (unlikely(len < SLL_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, SLL_PKT_TOO_SMALL); diff --git a/src/decode-tcp.c b/src/decode-tcp.c index ae85df48d382..428e7ae4e390 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -186,7 +186,7 @@ static int DecodeTCPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t len int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_tcp); + StatsIncr(tv, dtv->counter_tcp); if (unlikely(DecodeTCPPacket(tv, p,pkt,len) < 0)) { SCLogDebug("invalid TCP packet"); diff --git a/src/decode-teredo.c b/src/decode-teredo.c index ba8cd311b37b..b4199a052d64 100644 --- a/src/decode-teredo.c +++ b/src/decode-teredo.c @@ -96,7 +96,7 @@ int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, PKT_SET_SRC(tp, PKT_SRC_DECODER_TEREDO); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); - SCPerfCounterIncr(tv, dtv->counter_teredo); + StatsIncr(tv, dtv->counter_teredo); return TM_ECODE_OK; } } diff --git a/src/decode-udp.c b/src/decode-udp.c index a5be2a43125d..14ba7887d3aa 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -72,7 +72,7 @@ static int DecodeUDPPacket(ThreadVars *t, Packet *p, uint8_t *pkt, uint16_t len) int DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(tv, dtv->counter_udp); + StatsIncr(tv, dtv->counter_udp); if (unlikely(DecodeUDPPacket(tv, p,pkt,len) < 0)) { p->udph = NULL; diff --git a/src/decode-vlan.c b/src/decode-vlan.c index 95eb3e6845d4..59495594e7e6 100644 --- a/src/decode-vlan.c +++ b/src/decode-vlan.c @@ -61,9 +61,9 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u uint32_t proto; if (p->vlan_idx == 0) - SCPerfCounterIncr(tv, dtv->counter_vlan); + StatsIncr(tv, dtv->counter_vlan); else if (p->vlan_idx == 1) - SCPerfCounterIncr(tv, dtv->counter_vlan_qinq); + StatsIncr(tv, dtv->counter_vlan_qinq); if(len < VLAN_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL); diff --git a/src/decode.c b/src/decode.c index b096bf5753ee..16f5476b411a 100644 --- a/src/decode.c +++ b/src/decode.c @@ -106,7 +106,7 @@ void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { if (p->flags & PKT_IS_INVALID) - SCPerfCounterIncr(tv, dtv->counter_invalid); + StatsIncr(tv, dtv->counter_invalid); #ifdef __SC_CUDA_SUPPORT__ if (dtv->cuda_vars.mpm_is_cuda) diff --git a/src/defrag.c b/src/defrag.c index 0d1ab333dc7c..7418b93c665f 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -771,7 +771,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, if (tracker->af == AF_INET) { r = Defrag4Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { - SCPerfCounterIncr(tv, dtv->counter_defrag_ipv4_reassembled); + StatsIncr(tv, dtv->counter_defrag_ipv4_reassembled); if (pq && DecodeIPV4(tv, dtv, r, (void *)r->ip4h, IPV4_GET_IPLEN(r), pq) != TM_ECODE_OK) { TmqhOutputPacketpool(tv, r); @@ -783,7 +783,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, else if (tracker->af == AF_INET6) { r = Defrag6Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { - SCPerfCounterIncr(tv, dtv->counter_defrag_ipv6_reassembled); + StatsIncr(tv, dtv->counter_defrag_ipv6_reassembled); if (pq && DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h, IPV6_GET_PLEN(r) + IPV6_HEADER_LEN, pq) != TM_ECODE_OK) { @@ -923,10 +923,10 @@ Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, PacketQueue *pq) if (tv != NULL && dtv != NULL) { if (af == AF_INET) { - SCPerfCounterIncr(tv, dtv->counter_defrag_ipv4_fragments); + StatsIncr(tv, dtv->counter_defrag_ipv4_fragments); } else if (af == AF_INET6) { - SCPerfCounterIncr(tv, dtv->counter_defrag_ipv6_fragments); + StatsIncr(tv, dtv->counter_defrag_ipv6_fragments); } } diff --git a/src/flow-manager.c b/src/flow-manager.c index eca211f09c1b..4076abdca168 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -591,7 +591,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) SCLogDebug("Flow emergency mode entered..."); - SCPerfCounterIncr(th_v, ftd->flow_emerg_mode_enter); + StatsIncr(th_v, ftd->flow_emerg_mode_enter); } } @@ -662,7 +662,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) "%% flows at the queue", (uintmax_t)ts.tv_sec, (uintmax_t)ts.tv_usec, len * 100 / flow_config.prealloc); - SCPerfCounterIncr(th_v, ftd->flow_emerg_mode_over); + StatsIncr(th_v, ftd->flow_emerg_mode_over); } else { flow_update_delay_sec = FLOW_EMERG_MODE_UPDATE_DELAY_SEC; flow_update_delay_nsec = FLOW_EMERG_MODE_UPDATE_DELAY_NSEC; diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 1fffe2ba0f62..be06b4e95ef2 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1852,15 +1852,15 @@ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(tv, dtv->counter_pkts); - //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); + StatsIncr(tv, dtv->counter_pkts); + //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { - SCPerfCounterIncr(tv, dtv->counter_vlan); + StatsIncr(tv, dtv->counter_vlan); } /* call the decoder */ diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index 7394ddd04354..f8b6b16b286b 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -535,7 +535,7 @@ ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) p->ts.tv_sec++; } - SCPerfCounterIncr(tv, ewtn->packets); + StatsIncr(tv, ewtn->packets); ewtn->bytes += wlen; if (TmThreadsSlotProcessPkt(ewtn->tv, ewtn->slot, p) != TM_ECODE_OK) { @@ -621,8 +621,8 @@ DecodeErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(tv, dtv->counter_pkts); - //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); + StatsIncr(tv, dtv->counter_pkts); + //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-erf-file.c b/src/source-erf-file.c index 5bc4c38f5c6a..b1ab61938d93 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -284,8 +284,8 @@ DecodeErfFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueu return TM_ECODE_OK; /* Update counters. */ - SCPerfCounterIncr(tv, dtv->counter_pkts); - //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); + StatsIncr(tv, dtv->counter_pkts); + //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-ipfw.c b/src/source-ipfw.c index 75965465076c..3fb8ef3361ed 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -452,7 +452,7 @@ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(tv, dtv->counter_pkts); + StatsIncr(tv, dtv->counter_pkts); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-mpipe.c b/src/source-mpipe.c index 5a9d60eeebb7..511e298f1ce3 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -398,10 +398,10 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) if (idesc->be) { /* Buffer Error - No buffer available, so mPipe * dropped the packet. */ - SCPerfCounterIncr(tv, XlateStack(ptv, idesc->stack_idx)); + StatsIncr(tv, XlateStack(ptv, idesc->stack_idx)); } else { /* Bad packet. CRC error */ - SCPerfCounterIncr(tv, ptv->mpipe_drop); + StatsIncr(tv, ptv->mpipe_drop); gxio_mpipe_iqueue_drop(iqueue, idesc); } gxio_mpipe_iqueue_release(iqueue, idesc); @@ -1039,8 +1039,8 @@ TmEcode DecodeMpipe(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(tv, dtv->counter_pkts); -// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); + StatsIncr(tv, dtv->counter_pkts); +// StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); diff --git a/src/source-napatech.c b/src/source-napatech.c index ed32ded4948b..b508e03ac61f 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -357,8 +357,8 @@ TmEcode NapatechDecode(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(tv, dtv->counter_pkts); -// SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); + StatsIncr(tv, dtv->counter_pkts); +// StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-netmap.c b/src/source-netmap.c index e0e52977134d..0a96a148f02d 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -930,7 +930,7 @@ static TmEcode DecodeNetmap(ThreadVars *tv, Packet *p, void *data, PacketQueue * SCReturnInt(TM_ECODE_OK); /* update counters */ - SCPerfCounterIncr(tv, dtv->counter_pkts); + StatsIncr(tv, dtv->counter_pkts); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-nflog.c b/src/source-nflog.c index f8dc318ce928..d37959807c05 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -499,7 +499,7 @@ TmEcode DecodeNFLOG(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; - SCPerfCounterIncr(tv, dtv->counter_pkts); + StatsIncr(tv, dtv->counter_pkts); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-nfq.c b/src/source-nfq.c index ea2bdf83d39d..9596ed45382a 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -1223,7 +1223,7 @@ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet if (p->flags & PKT_PSEUDO_STREAM_END) return TM_ECODE_OK; - SCPerfCounterIncr(tv, dtv->counter_pkts); + StatsIncr(tv, dtv->counter_pkts); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 7e7b8ba79b42..c46c8a6bd73b 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -401,8 +401,8 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(tv, dtv->counter_pkts); - //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); + StatsIncr(tv, dtv->counter_pkts); + //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-pcap.c b/src/source-pcap.c index b92831899514..aa67b60adada 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -704,8 +704,8 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(tv, dtv->counter_pkts); - //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); + StatsIncr(tv, dtv->counter_pkts); + //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); diff --git a/src/source-pfring.c b/src/source-pfring.c index 6e997be920ed..6b60df9adda4 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -602,15 +602,15 @@ TmEcode DecodePfring(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pac return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(tv, dtv->counter_pkts); - //SCPerfCounterIncr(tv, dtv->counter_pkts_per_sec); + StatsIncr(tv, dtv->counter_pkts); + //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { - SCPerfCounterIncr(tv, dtv->counter_vlan); + StatsIncr(tv, dtv->counter_vlan); } DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 839a9ccd55f4..c0979b9459ad 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -1906,7 +1906,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { /* increment stream depth counter */ - SCPerfCounterIncr(tv, ra_ctx->counter_tcp_stream_depth); + StatsIncr(tv, ra_ctx->counter_tcp_stream_depth); stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY; SCLogDebug("ssn %p: reassembly depth reached, " @@ -2607,7 +2607,7 @@ int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, stream->flags |= STREAMTCP_STREAM_FLAG_GAP; StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(tv, ra_ctx->counter_tcp_reass_gap); + StatsIncr(tv, ra_ctx->counter_tcp_reass_gap); #ifdef DEBUG dbg_app_layer_gap++; #endif @@ -2953,7 +2953,7 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, stream->flags |= STREAMTCP_STREAM_FLAG_GAP; StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(tv, ra_ctx->counter_tcp_reass_gap); + StatsIncr(tv, ra_ctx->counter_tcp_reass_gap); #ifdef DEBUG dbg_app_layer_gap++; #endif @@ -3596,7 +3596,7 @@ TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, segment_pool[idx]->allocated); /* Increment the counter to show that we are not able to serve the segment request due to memcap limit */ - SCPerfCounterIncr(tv, ra_ctx->counter_tcp_segment_memcap); + StatsIncr(tv, ra_ctx->counter_tcp_segment_memcap); } else { seg->flags = stream_config.segment_init_flags; seg->next = NULL; diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 00e1e423a53f..afc19fc05451 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -844,10 +844,10 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(tv, stt->counter_tcp_ssn_memcap); + StatsIncr(tv, stt->counter_tcp_ssn_memcap); return -1; } - SCPerfCounterIncr(tv, stt->counter_tcp_sessions); + StatsIncr(tv, stt->counter_tcp_sessions); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV); @@ -925,11 +925,11 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(tv, stt->counter_tcp_ssn_memcap); + StatsIncr(tv, stt->counter_tcp_ssn_memcap); return -1; } - SCPerfCounterIncr(tv, stt->counter_tcp_sessions); + StatsIncr(tv, stt->counter_tcp_sessions); } /* set the state */ @@ -978,10 +978,10 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(tv, stt->counter_tcp_ssn_memcap); + StatsIncr(tv, stt->counter_tcp_ssn_memcap); return -1; } - SCPerfCounterIncr(tv, stt->counter_tcp_sessions); + StatsIncr(tv, stt->counter_tcp_sessions); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); @@ -4461,12 +4461,12 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, /* update counters */ if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { - SCPerfCounterIncr(tv, stt->counter_tcp_synack); + StatsIncr(tv, stt->counter_tcp_synack); } else if (p->tcph->th_flags & (TH_SYN)) { - SCPerfCounterIncr(tv, stt->counter_tcp_syn); + StatsIncr(tv, stt->counter_tcp_syn); } if (p->tcph->th_flags & (TH_RST)) { - SCPerfCounterIncr(tv, stt->counter_tcp_rst); + StatsIncr(tv, stt->counter_tcp_rst); } /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */ @@ -5020,13 +5020,13 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; if (p->flow == NULL) { - SCPerfCounterIncr(tv, stt->counter_tcp_no_flow); + StatsIncr(tv, stt->counter_tcp_no_flow); return TM_ECODE_OK; } if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) { if (StreamTcpValidateChecksum(p) == 0) { - SCPerfCounterIncr(tv, stt->counter_tcp_invalid_checksum); + StatsIncr(tv, stt->counter_tcp_invalid_checksum); return TM_ECODE_OK; } } else { @@ -5864,7 +5864,7 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread Packet *np = StreamTcpPseudoSetup(p, GET_PKT_DATA(p), GET_PKT_LEN(p)); if (np == NULL) { SCLogDebug("The packet received from packet allocation is NULL"); - SCPerfCounterIncr(tv, stt->counter_tcp_pseudo_failed); + StatsIncr(tv, stt->counter_tcp_pseudo_failed); SCReturn; } PKT_SET_SRC(np, PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO); @@ -5899,7 +5899,7 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread PacketEnqueue(pq, np); - SCPerfCounterIncr(tv, stt->counter_tcp_pseudo); + StatsIncr(tv, stt->counter_tcp_pseudo); SCReturn; } From 30cce2bd297ff2c770a3e7b97155c696ced01a11 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 15:08:35 +0200 Subject: [PATCH 0517/2553] counters: s/SCPerfCounterSetUI64/StatsSetUI64/g --- src/app-layer-htp-mem.c | 4 ++-- src/app-layer.c | 6 +++--- src/counters.c | 2 +- src/counters.h | 2 +- src/flow-manager.c | 8 ++++---- src/source-af-packet.c | 2 +- src/source-erf-dag.c | 2 +- src/source-erf-file.c | 2 +- src/source-ipfw.c | 2 +- src/source-mpipe.c | 4 ++-- src/source-napatech.c | 2 +- src/source-netmap.c | 2 +- src/source-nflog.c | 2 +- src/source-nfq.c | 2 +- src/source-pcap-file.c | 2 +- src/source-pcap.c | 8 ++++---- src/source-pfring.c | 6 +++--- src/stream-tcp.c | 2 +- 18 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/app-layer-htp-mem.c b/src/app-layer-htp-mem.c index 18aa223a6bf8..f024ef9aa496 100644 --- a/src/app-layer-htp-mem.c +++ b/src/app-layer-htp-mem.c @@ -81,9 +81,9 @@ void HTPDecrMemuse(uint64_t size) void HTPMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *trt) { uint64_t tmpval = SC_ATOMIC_GET(htp_memuse); - SCPerfCounterSetUI64(tv, trt->counter_htp_memuse, tmpval); + StatsSetUI64(tv, trt->counter_htp_memuse, tmpval); tmpval = SC_ATOMIC_GET(htp_memcap); - SCPerfCounterSetUI64(tv, trt->counter_htp_memcap, tmpval); + StatsSetUI64(tv, trt->counter_htp_memcap, tmpval); return; } /** diff --git a/src/app-layer.c b/src/app-layer.c index 5dfd433c61ac..bc6e986adb44 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -78,9 +78,9 @@ static void DNSUpdateCounters(ThreadVars *tv, AppLayerThreadCtx *app_tctx) DNSMemcapGetCounters(&memuse, &memcap_state, &memcap_global); - SCPerfCounterSetUI64(tv, app_tctx->counter_dns_memuse, memuse); - SCPerfCounterSetUI64(tv, app_tctx->counter_dns_memcap_state, memcap_state); - SCPerfCounterSetUI64(tv, app_tctx->counter_dns_memcap_global, memcap_global); + StatsSetUI64(tv, app_tctx->counter_dns_memuse, memuse); + StatsSetUI64(tv, app_tctx->counter_dns_memcap_state, memcap_state); + StatsSetUI64(tv, app_tctx->counter_dns_memcap_global, memcap_global); } /***** L7 layer dispatchers *****/ diff --git a/src/counters.c b/src/counters.c index 6fcd66e23b7a..3638f2c47f65 100644 --- a/src/counters.c +++ b/src/counters.c @@ -162,7 +162,7 @@ void StatsIncr(ThreadVars *tv, uint16_t id) * \param pca Pointer to the SCPerfPrivateContext * \param x The value to set for the counter */ -void SCPerfCounterSetUI64(ThreadVars *tv, uint16_t id, uint64_t x) +void StatsSetUI64(ThreadVars *tv, uint16_t id, uint64_t x) { SCPerfPrivateContext *pca = &tv->perf_private_ctx; #ifdef UNITTESTS diff --git a/src/counters.h b/src/counters.h index 693141fd5d9f..0a6e830fbf5f 100644 --- a/src/counters.h +++ b/src/counters.h @@ -125,7 +125,7 @@ void SCPerfReleasePCA(SCPerfPrivateContext *); /* functions used to update local counter values */ void StatsAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); -void SCPerfCounterSetUI64(struct ThreadVars_ *, uint16_t, uint64_t); +void StatsSetUI64(struct ThreadVars_ *, uint16_t, uint64_t); void StatsIncr(struct ThreadVars_ *, uint16_t); #define SCPerfSyncCounters(tv) \ diff --git a/src/flow-manager.c b/src/flow-manager.c index 4076abdca168..c938573ad310 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -623,22 +623,22 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) /* StatsAddUI64(th_v, flow_mgr_host_prune, (uint64_t)hosts_pruned); uint32_t hosts_active = HostGetActiveCount(); - SCPerfCounterSetUI64(th_v, flow_mgr_host_active, (uint64_t)hosts_active); + StatsSetUI64(th_v, flow_mgr_host_active, (uint64_t)hosts_active); uint32_t hosts_spare = HostGetSpareCount(); - SCPerfCounterSetUI64(th_v, flow_mgr_host_spare, (uint64_t)hosts_spare); + StatsSetUI64(th_v, flow_mgr_host_spare, (uint64_t)hosts_spare); */ StatsAddUI64(th_v, ftd->flow_mgr_cnt_clo, (uint64_t)counters.clo); StatsAddUI64(th_v, ftd->flow_mgr_cnt_new, (uint64_t)counters.new); StatsAddUI64(th_v, ftd->flow_mgr_cnt_est, (uint64_t)counters.est); long long unsigned int flow_memuse = SC_ATOMIC_GET(flow_memuse); - SCPerfCounterSetUI64(th_v, ftd->flow_mgr_memuse, (uint64_t)flow_memuse); + StatsSetUI64(th_v, ftd->flow_mgr_memuse, (uint64_t)flow_memuse); StatsAddUI64(th_v, ftd->flow_tcp_reuse, (uint64_t)counters.tcp_reuse); uint32_t len = 0; FQLOCK_LOCK(&flow_spare_q); len = flow_spare_q.len; FQLOCK_UNLOCK(&flow_spare_q); - SCPerfCounterSetUI64(th_v, ftd->flow_mgr_spare, (uint64_t)len); + StatsSetUI64(th_v, ftd->flow_mgr_spare, (uint64_t)len); /* Don't fear, FlowManagerThread is here... * clear emergency bit if we have at least xx flows pruned. */ diff --git a/src/source-af-packet.c b/src/source-af-packet.c index be06b4e95ef2..aed38baba113 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1856,7 +1856,7 @@ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index f8b6b16b286b..9758b7216215 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -625,7 +625,7 @@ DecodeErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* call the decoder */ switch(p->datalink) { diff --git a/src/source-erf-file.c b/src/source-erf-file.c index b1ab61938d93..fd6973f57ff1 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -288,7 +288,7 @@ DecodeErfFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueu //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-ipfw.c b/src/source-ipfw.c index 3fb8ef3361ed..9e4fd62a5e69 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -455,7 +455,7 @@ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe StatsIncr(tv, dtv->counter_pkts); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* Process IP packets */ if (IPV4_GET_RAW_VER(ip4h) == 4) { diff --git a/src/source-mpipe.c b/src/source-mpipe.c index 511e298f1ce3..90fc7a0ba695 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -382,7 +382,7 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) __insn_prefetch(&idesc[i]); } if (unlikely(n > max_queued)) { - SCPerfCounterSetUI64(tv, ptv->max_mpipe_depth, + StatsSetUI64(tv, ptv->max_mpipe_depth, (uint64_t)n); max_queued = n; } @@ -1045,7 +1045,7 @@ TmEcode DecodeMpipe(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* call the decoder */ DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-napatech.c b/src/source-napatech.c index b508e03ac61f..27e4f1cdda4e 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -361,7 +361,7 @@ TmEcode NapatechDecode(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, // StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); switch (p->datalink) { case LINKTYPE_ETHERNET: diff --git a/src/source-netmap.c b/src/source-netmap.c index 0a96a148f02d..04508e6c12fb 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -933,7 +933,7 @@ static TmEcode DecodeNetmap(ThreadVars *tv, Packet *p, void *data, PacketQueue * StatsIncr(tv, dtv->counter_pkts); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-nflog.c b/src/source-nflog.c index d37959807c05..583af8545a56 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -502,7 +502,7 @@ TmEcode DecodeNFLOG(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack StatsIncr(tv, dtv->counter_pkts); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); diff --git a/src/source-nfq.c b/src/source-nfq.c index 9596ed45382a..18259afc8e9c 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -1226,7 +1226,7 @@ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet StatsIncr(tv, dtv->counter_pkts); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index c46c8a6bd73b..007f89a29993 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -405,7 +405,7 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); double curr_ts = p->ts.tv_sec + p->ts.tv_usec / 1000.0; if (curr_ts < prev_signaled_ts || (curr_ts - prev_signaled_ts) > 60.0) { diff --git a/src/source-pcap.c b/src/source-pcap.c index aa67b60adada..0a1bcaf0ed63 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -155,10 +155,10 @@ static inline void PcapDumpCounters(PcapThreadVars *ptv) { struct pcap_stat pcap_s; if (likely((pcap_stats(ptv->pcap_handle, &pcap_s) >= 0))) { - SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_packets, pcap_s.ps_recv); - SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_drops, pcap_s.ps_drop); + StatsSetUI64(ptv->tv, ptv->capture_kernel_packets, pcap_s.ps_recv); + StatsSetUI64(ptv->tv, ptv->capture_kernel_drops, pcap_s.ps_drop); (void) SC_ATOMIC_SET(ptv->livedev->drop, pcap_s.ps_drop); - SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_ifdrops, pcap_s.ps_ifdrop); + StatsSetUI64(ptv->tv, ptv->capture_kernel_ifdrops, pcap_s.ps_ifdrop); } } @@ -708,7 +708,7 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* call the decoder */ switch(p->datalink) { diff --git a/src/source-pfring.c b/src/source-pfring.c index 6b60df9adda4..2b430200b1a1 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -202,8 +202,8 @@ static inline void PfringDumpCounters(PfringThreadVars *ptv) uint64_t th_drops = SCPerfGetLocalCounterValue(ptv->tv, ptv->capture_kernel_drops); SC_ATOMIC_ADD(ptv->livedev->pkts, pfring_s.recv - th_pkts); SC_ATOMIC_ADD(ptv->livedev->drop, pfring_s.drop - th_drops); - SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_packets, pfring_s.recv); - SCPerfCounterSetUI64(ptv->tv, ptv->capture_kernel_drops, pfring_s.drop); + StatsSetUI64(ptv->tv, ptv->capture_kernel_packets, pfring_s.recv); + StatsSetUI64(ptv->tv, ptv->capture_kernel_drops, pfring_s.drop); } } @@ -606,7 +606,7 @@ TmEcode DecodePfring(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pac //StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { diff --git a/src/stream-tcp.c b/src/stream-tcp.c index afc19fc05451..6e08f8195872 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -148,7 +148,7 @@ void StreamTcpDecrMemuse(uint64_t size) void StreamTcpMemuseCounter(ThreadVars *tv, StreamTcpThread *stt) { uint64_t memusecopy = SC_ATOMIC_GET(st_memuse); - SCPerfCounterSetUI64(tv, stt->counter_tcp_memuse, memusecopy); + StatsSetUI64(tv, stt->counter_tcp_memuse, memusecopy); return; } From 7e70f136ec41042c1f323be4d31eec91f39f5006 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 15:41:35 +0200 Subject: [PATCH 0518/2553] counters: various renames and cleanups --- src/counters.c | 195 +++++++++++++++++++++++-------------------------- 1 file changed, 93 insertions(+), 102 deletions(-) diff --git a/src/counters.c b/src/counters.c index 3638f2c47f65..9a333a7eb761 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2015 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 @@ -88,14 +88,14 @@ typedef struct StatsGlobalContext_ { } StatsGlobalContext; static void *stats_thread_data = NULL; -static StatsGlobalContext *sc_perf_op_ctx = NULL; -static time_t sc_start_time; +static StatsGlobalContext *stats_ctx = NULL; +static time_t stats_start_time; /** refresh interval in seconds */ -static uint32_t sc_counter_tts = STATS_MGMTT_TTS; +static uint32_t stats_tts = STATS_MGMTT_TTS; /** is the stats counter enabled? */ -static char sc_counter_enabled = TRUE; +static char stats_enabled = TRUE; -static int SCPerfOutputCounterFileIface(ThreadVars *tv); +static int StatsOutput(ThreadVars *tv); static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *); /** stats table is filled each interval and passed to the @@ -104,14 +104,6 @@ static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}}; static uint16_t counters_global_id = 0; -/** - * \brief The output interface dispatcher for the counter api - */ -void SCPerfOutputCounters(ThreadVars *tv) -{ - SCPerfOutputCounterFileIface(tv); -} - /** * \brief Adds a value of type uint64_t to the local counter. * @@ -214,26 +206,26 @@ static void SCPerfInitOPCtx(void) if (stats != NULL) { const char *enabled = ConfNodeLookupChildValue(stats, "enabled"); if (enabled != NULL && ConfValIsFalse(enabled)) { - sc_counter_enabled = FALSE; + stats_enabled = FALSE; SCLogDebug("Stats module has been disabled"); SCReturn; } const char *interval = ConfNodeLookupChildValue(stats, "interval"); if (interval != NULL) - sc_counter_tts = (uint32_t) atoi(interval); + stats_tts = (uint32_t) atoi(interval); } if (!OutputStatsLoggersRegistered()) { SCLogWarning(SC_WARN_NO_STATS_LOGGERS, "stats are enabled but no loggers are active"); - sc_counter_enabled = FALSE; + stats_enabled = FALSE; SCReturn; } /* Store the engine start time */ - time(&sc_start_time); + time(&stats_start_time); /* init the lock used by StatsThreadStore */ - if (SCMutexInit(&sc_perf_op_ctx->sts_lock, NULL) != 0) { + if (SCMutexInit(&stats_ctx->sts_lock, NULL) != 0) { SCLogError(SC_ERR_INITIALIZATION, "error initializing sts mutex"); exit(EXIT_FAILURE); } @@ -247,14 +239,14 @@ static void SCPerfInitOPCtx(void) */ static void SCPerfReleaseOPCtx() { - if (sc_perf_op_ctx == NULL) { + if (stats_ctx == NULL) { SCLogDebug("Counter module has been disabled"); return; } StatsThreadStore *sts = NULL; StatsThreadStore *temp = NULL; - sts = sc_perf_op_ctx->sts; + sts = stats_ctx->sts; while (sts != NULL) { if (sts->tm_name != NULL) @@ -268,8 +260,8 @@ static void SCPerfReleaseOPCtx() sts = temp; } - SCFree(sc_perf_op_ctx); - sc_perf_op_ctx = NULL; + SCFree(stats_ctx); + stats_ctx = NULL; /* free stats table */ if (stats_table.stats != NULL) { @@ -310,7 +302,7 @@ static void *SCPerfMgmtThread(void *arg) SCDropCaps(tv_local); - if (sc_perf_op_ctx == NULL) { + if (stats_ctx == NULL) { SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" "SCPerfInitCounterApi() has to be called first"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); @@ -336,7 +328,7 @@ static void *SCPerfMgmtThread(void *arg) TmThreadsUnsetFlag(tv_local, THV_PAUSED); } - cond_time.tv_sec = time(NULL) + sc_counter_tts; + cond_time.tv_sec = time(NULL) + stats_tts; cond_time.tv_nsec = 0; /* wait for the set time, or until we are woken up by @@ -345,7 +337,7 @@ static void *SCPerfMgmtThread(void *arg) SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time); SCCtrlMutexUnlock(tv_local->ctrl_mutex); - SCPerfOutputCounters(tv_local); + StatsOutput(tv_local); if (TmThreadsCheckFlag(tv_local, THV_KILL)) { run = 0; @@ -397,7 +389,7 @@ static void *SCPerfWakeupThread(void *arg) SCDropCaps(tv_local); - if (sc_perf_op_ctx == NULL) { + if (stats_ctx == NULL) { SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" "SCPerfInitCounterApi() has to be called first"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); @@ -588,16 +580,16 @@ static uint64_t SCPerfOutputCalculateCounterValue(SCPerfCounter *pc) } /** - * \brief The file output interface for the Perf Counter api + * \brief The output interface for the Stats API */ -static int SCPerfOutputCounterFileIface(ThreadVars *tv) +static int StatsOutput(ThreadVars *tv) { const StatsThreadStore *sts = NULL; const SCPerfCounter *pc = NULL; void *td = stats_thread_data; if (stats_table.nstats == 0) { - StatsThreadRegister("Global", &sc_perf_op_ctx->global_counter_ctx); + StatsThreadRegister("Global", &stats_ctx->global_counter_ctx); uint32_t nstats = counters_global_id; @@ -609,7 +601,7 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) return -1; } - stats_table.ntstats = sc_perf_op_ctx->sts_cnt; + stats_table.ntstats = stats_ctx->sts_cnt; uint32_t array_size = stats_table.nstats * sizeof(StatsRecord); stats_table.tstats = SCCalloc(stats_table.ntstats, array_size); if (stats_table.tstats == NULL) { @@ -618,7 +610,7 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) return -1; } - stats_table.start_time = sc_start_time; + stats_table.start_time = stats_start_time; } /** temporary local table to merge the per thread counters, @@ -631,12 +623,12 @@ static int SCPerfOutputCounterFileIface(ThreadVars *tv) memset(&merge_table, 0x00, counters_global_id * sizeof(struct CountersMergeTable)); - int thread = sc_perf_op_ctx->sts_cnt - 1; + int thread = stats_ctx->sts_cnt - 1; StatsRecord *table = stats_table.stats; /* Loop through the thread counter stores. The global counters * are in a separate store inside this list. */ - sts = sc_perf_op_ctx->sts; + sts = stats_ctx->sts; SCLogDebug("sts %p", sts); while (sts != NULL) { BUG_ON(thread < 0); @@ -777,7 +769,7 @@ TmEcode SCPerfOutputCounterSocket(json_t *cmd, uint32_t u = 0; int flag = 0; - if (sc_perf_op_ctx == NULL) { + if (stats_ctx == NULL) { json_object_set_new(answer, "message", json_string("No performance counter context")); return TM_ECODE_FAILED; @@ -792,7 +784,7 @@ TmEcode SCPerfOutputCounterSocket(json_t *cmd, return TM_ECODE_FAILED; } - sts = sc_perf_op_ctx->sts; + sts = stats_ctx->sts; while (sts != NULL) { json_t *jdata; int filled = 0; @@ -863,12 +855,12 @@ TmEcode SCPerfOutputCounterSocket(json_t *cmd, */ void StatsInit(void) { - BUG_ON(sc_perf_op_ctx != NULL); - if ( (sc_perf_op_ctx = SCMalloc(sizeof(StatsGlobalContext))) == NULL) { + BUG_ON(stats_ctx != NULL); + if ( (stats_ctx = SCMalloc(sizeof(StatsGlobalContext))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCPerfInitOPCtx. Exiting..."); exit(EXIT_FAILURE); } - memset(sc_perf_op_ctx, 0, sizeof(StatsGlobalContext)); + memset(stats_ctx, 0, sizeof(StatsGlobalContext)); } void StatsSetupPostConfig(void) @@ -887,7 +879,7 @@ void SCPerfSpawnThreads(void) { SCEnter(); - if (!sc_counter_enabled) { + if (!stats_enabled) { SCReturn; } @@ -1001,40 +993,18 @@ uint16_t StatsRegisterMaxCounter(char *cname, struct ThreadVars_ *tv) uint16_t StatsRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)) { #ifdef UNITTESTS - if (sc_perf_op_ctx == NULL) + if (stats_ctx == NULL) return 0; #else - BUG_ON(sc_perf_op_ctx == NULL); + BUG_ON(stats_ctx == NULL); #endif uint16_t id = StatsRegisterQualifiedCounter(cname, NULL, - &(sc_perf_op_ctx->global_counter_ctx), + &(stats_ctx->global_counter_ctx), STATS_TYPE_FUNC, Func); return id; } -/** - * \brief Registers a normal, unqualified counter - * - * \param cname Name of the counter, to be registered - * \param tm_name Name of the engine module under which the counter has to be - * registered - * \param type Datatype of this counter variable - * \param pctx SCPerfPublicContext corresponding to the tm_name key under which the - * key has to be registered - * - * \retval id Counter id for the newly registered counter, or the already - * present counter - */ -static uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, - SCPerfPublicContext *pctx) -{ - uint16_t id = StatsRegisterQualifiedCounter(cname, tm_name, pctx, - STATS_TYPE_NORMAL, NULL); - - return id; -} - typedef struct CountersIdType_ { uint16_t id; const char *string; @@ -1097,7 +1067,7 @@ void CountersIdHashFreeFunc(void *data) */ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pctx) { - if (sc_perf_op_ctx == NULL) { + if (stats_ctx == NULL) { SCLogDebug("Counter module has been disabled"); return 0; } @@ -1109,23 +1079,23 @@ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pct return 0; } - SCMutexLock(&sc_perf_op_ctx->sts_lock); - if (sc_perf_op_ctx->counters_id_hash == NULL) { - sc_perf_op_ctx->counters_id_hash = HashTableInit(256, CountersIdHashFunc, + SCMutexLock(&stats_ctx->sts_lock); + if (stats_ctx->counters_id_hash == NULL) { + stats_ctx->counters_id_hash = HashTableInit(256, CountersIdHashFunc, CountersIdHashCompareFunc, CountersIdHashFreeFunc); - BUG_ON(sc_perf_op_ctx->counters_id_hash == NULL); + BUG_ON(stats_ctx->counters_id_hash == NULL); } SCPerfCounter *pc = pctx->head; while (pc != NULL) { CountersIdType t = { 0, pc->cname }, *id = NULL; - id = HashTableLookup(sc_perf_op_ctx->counters_id_hash, &t, sizeof(t)); + id = HashTableLookup(stats_ctx->counters_id_hash, &t, sizeof(t)); if (id == NULL) { id = SCCalloc(1, sizeof(*id)); BUG_ON(id == NULL); id->id = counters_global_id++; id->string = pc->cname; - BUG_ON(HashTableAdd(sc_perf_op_ctx->counters_id_hash, id, sizeof(*id)) < 0); + BUG_ON(HashTableAdd(stats_ctx->counters_id_hash, id, sizeof(*id)) < 0); } pc->gid = id->id; pc = pc->next; @@ -1133,7 +1103,7 @@ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pct if ( (temp = SCMalloc(sizeof(StatsThreadStore))) == NULL) { - SCMutexUnlock(&sc_perf_op_ctx->sts_lock); + SCMutexUnlock(&stats_ctx->sts_lock); return 0; } memset(temp, 0, sizeof(StatsThreadStore)); @@ -1143,16 +1113,16 @@ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pct temp->name = SCStrdup(thread_name); if (unlikely(temp->name == NULL)) { SCFree(temp); - SCMutexUnlock(&sc_perf_op_ctx->sts_lock); + SCMutexUnlock(&stats_ctx->sts_lock); return 0; } - temp->next = sc_perf_op_ctx->sts; - sc_perf_op_ctx->sts = temp; - sc_perf_op_ctx->sts_cnt++; - SCLogDebug("sc_perf_op_ctx->sts %p", sc_perf_op_ctx->sts); + temp->next = stats_ctx->sts; + stats_ctx->sts = temp; + stats_ctx->sts_cnt++; + SCLogDebug("stats_ctx->sts %p", stats_ctx->sts); - SCMutexUnlock(&sc_perf_op_ctx->sts_lock); + SCMutexUnlock(&stats_ctx->sts_lock); return 1; } @@ -1336,13 +1306,34 @@ void SCPerfReleasePCA(SCPerfPrivateContext *pca) /*----------------------------------Unit_Tests--------------------------------*/ #ifdef UNITTESTS +/** \internal + * \brief Registers a normal, unqualified counter + * + * \param cname Name of the counter, to be registered + * \param tm_name Name of the engine module under which the counter has to be + * registered + * \param type Datatype of this counter variable + * \param pctx SCPerfPublicContext corresponding to the tm_name key under which the + * key has to be registered + * + * \retval id Counter id for the newly registered counter, or the already + * present counter + */ +static uint16_t RegisterCounter(char *cname, char *tm_name, + SCPerfPublicContext *pctx) +{ + uint16_t id = StatsRegisterQualifiedCounter(cname, tm_name, pctx, + STATS_TYPE_NORMAL, NULL); + return id; +} + static int SCPerfTestCounterReg02() { SCPerfPublicContext pctx; memset(&pctx, 0, sizeof(SCPerfPublicContext)); - return SCPerfRegisterCounter(NULL, NULL, &pctx); + return RegisterCounter(NULL, NULL, &pctx); } static int SCPerfTestCounterReg03() @@ -1352,7 +1343,7 @@ static int SCPerfTestCounterReg03() memset(&pctx, 0, sizeof(SCPerfPublicContext)); - result = SCPerfRegisterCounter("t1", "c1", &pctx); + result = RegisterCounter("t1", "c1", &pctx); SCPerfReleasePerfCounterS(pctx.head); @@ -1366,11 +1357,11 @@ static int SCPerfTestCounterReg04() memset(&pctx, 0, sizeof(SCPerfPublicContext)); - SCPerfRegisterCounter("t1", "c1", &pctx); - SCPerfRegisterCounter("t2", "c2", &pctx); - SCPerfRegisterCounter("t3", "c3", &pctx); + RegisterCounter("t1", "c1", &pctx); + RegisterCounter("t2", "c2", &pctx); + RegisterCounter("t3", "c3", &pctx); - result = SCPerfRegisterCounter("t1", "c1", &pctx); + result = RegisterCounter("t1", "c1", &pctx); SCPerfReleasePerfCounterS(pctx.head); @@ -1384,7 +1375,7 @@ static int SCPerfTestGetCntArray05() memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); + id = RegisterCounter("t1", "c1", &tv.perf_public_ctx); if (id != 1) { printf("id %d: ", id); return 0; @@ -1402,7 +1393,7 @@ static int SCPerfTestGetCntArray06() memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); + id = RegisterCounter("t1", "c1", &tv.perf_public_ctx); if (id != 1) return 0; @@ -1426,8 +1417,8 @@ static int SCPerfTestCntArraySize07() //pca = (SCPerfPrivateContext *)&tv.perf_private_ctx; - SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); - SCPerfRegisterCounter("t2", "c2", &tv.perf_public_ctx); + RegisterCounter("t1", "c1", &tv.perf_public_ctx); + RegisterCounter("t2", "c2", &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; @@ -1452,7 +1443,7 @@ static int SCPerfTestUpdateCounter08() memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); + id = RegisterCounter("t1", "c1", &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; @@ -1477,11 +1468,11 @@ static int SCPerfTestUpdateCounter09() memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); - SCPerfRegisterCounter("t2", "c2", &tv.perf_public_ctx); - SCPerfRegisterCounter("t3", "c3", &tv.perf_public_ctx); - SCPerfRegisterCounter("t4", "c4", &tv.perf_public_ctx); - id2 = SCPerfRegisterCounter("t5", "c5", &tv.perf_public_ctx); + id1 = RegisterCounter("t1", "c1", &tv.perf_public_ctx); + RegisterCounter("t2", "c2", &tv.perf_public_ctx); + RegisterCounter("t3", "c3", &tv.perf_public_ctx); + RegisterCounter("t4", "c4", &tv.perf_public_ctx); + id2 = RegisterCounter("t5", "c5", &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; @@ -1507,9 +1498,9 @@ static int SCPerfTestUpdateGlobalCounter10() memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); - id2 = SCPerfRegisterCounter("t2", "c2", &tv.perf_public_ctx); - id3 = SCPerfRegisterCounter("t3", "c3", &tv.perf_public_ctx); + id1 = RegisterCounter("t1", "c1", &tv.perf_public_ctx); + id2 = RegisterCounter("t2", "c2", &tv.perf_public_ctx); + id3 = RegisterCounter("t3", "c3", &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; @@ -1541,10 +1532,10 @@ static int SCPerfTestCounterValues11() memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", &tv.perf_public_ctx); - id2 = SCPerfRegisterCounter("t2", "c2", &tv.perf_public_ctx); - id3 = SCPerfRegisterCounter("t3", "c3", &tv.perf_public_ctx); - id4 = SCPerfRegisterCounter("t4", "c4", &tv.perf_public_ctx); + id1 = RegisterCounter("t1", "c1", &tv.perf_public_ctx); + id2 = RegisterCounter("t2", "c2", &tv.perf_public_ctx); + id3 = RegisterCounter("t3", "c3", &tv.perf_public_ctx); + id4 = RegisterCounter("t4", "c4", &tv.perf_public_ctx); SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; From 628c3b1bc7b0dbb80a2932dbdc4d37fb8e954b7a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 16:01:09 +0200 Subject: [PATCH 0519/2553] counters: s/SCPerfPublicContext/StatsPublicThreadContext/g --- src/counters.c | 48 ++++++++++++++++++++++++------------------------ src/counters.h | 6 +++--- src/threadvars.h | 2 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/counters.c b/src/counters.c index 9a333a7eb761..15d8b85ae186 100644 --- a/src/counters.c +++ b/src/counters.c @@ -65,9 +65,9 @@ typedef struct StatsThreadStore_ { char *tm_name; - SCPerfPublicContext *ctx; + StatsPublicThreadContext *ctx; - SCPerfPublicContext **head; + StatsPublicThreadContext **head; uint32_t size; struct StatsThreadStore_ *next; @@ -84,7 +84,7 @@ typedef struct StatsGlobalContext_ { HashTable *counters_id_hash; - SCPerfPublicContext global_counter_ctx; + StatsPublicThreadContext global_counter_ctx; } StatsGlobalContext; static void *stats_thread_data = NULL; @@ -96,7 +96,7 @@ static uint32_t stats_tts = STATS_MGMTT_TTS; static char stats_enabled = TRUE; static int StatsOutput(ThreadVars *tv); -static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *); +static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext *); /** stats table is filled each interval and passed to the * loggers. Initialized at first use. */ @@ -359,7 +359,7 @@ static void *SCPerfMgmtThread(void *arg) /** * \brief Wake up thread. This thread wakes up every TTS(time to sleep) seconds - * and sets the flag for every ThreadVars' SCPerfPublicContext + * and sets the flag for every ThreadVars' StatsPublicThreadContext * * \param arg is NULL always * @@ -482,7 +482,7 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) * * \param cname Name of the counter, to be registered * \param tm_name Thread module to which this counter belongs - * \param pctx SCPerfPublicContext for this tm-tv instance + * \param pctx StatsPublicThreadContext for this tm-tv instance * \param type_q Qualifier describing the type of counter to be registered * * \retval the counter id for the newly registered counter, or the already @@ -490,7 +490,7 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) * \retval 0 on failure */ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, - SCPerfPublicContext *pctx, + StatsPublicThreadContext *pctx, int type_q, uint64_t (*Func)(void)) { SCPerfCounter **head = &pctx->head; @@ -499,7 +499,7 @@ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, SCPerfCounter *pc = NULL; if (cname == NULL || pctx == NULL) { - SCLogDebug("Counter name, SCPerfPublicContext NULL"); + SCLogDebug("Counter name, StatsPublicThreadContext NULL"); return 0; } @@ -1061,11 +1061,11 @@ void CountersIdHashFreeFunc(void *data) * are stacked together in a PCTMI container. * * \param tm_name Name of the tm to be added to the table - * \param pctx SCPerfPublicContext associated with the TM tm_name + * \param pctx StatsPublicThreadContext associated with the TM tm_name * * \retval 1 on success, 0 on failure */ -static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pctx) +static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext *pctx) { if (stats_ctx == NULL) { SCLogDebug("Counter module has been disabled"); @@ -1131,12 +1131,12 @@ static int StatsThreadRegister(const char *thread_name, SCPerfPublicContext *pct * * \param s_id Counter id of the first counter to be added to the array * \param e_id Counter id of the last counter to be added to the array - * \param pctx Pointer to the tv's SCPerfPublicContext + * \param pctx Pointer to the tv's StatsPublicThreadContext * * \retval a counter-array in this(s_id-e_id) range for this TM instance */ static int SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, - SCPerfPublicContext *pctx, + StatsPublicThreadContext *pctx, SCPerfPrivateContext *pca) { SCPerfCounter *pc = NULL; @@ -1183,12 +1183,12 @@ static int SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, * \brief Returns a counter array for all counters registered for this tm * instance * - * \param pctx Pointer to the tv's SCPerfPublicContext + * \param pctx Pointer to the tv's StatsPublicThreadContext * * \retval pca Pointer to a counter-array for all counter of this tm instance * on success; NULL on failure */ -static int SCPerfGetAllCountersArray(SCPerfPublicContext *pctx, SCPerfPrivateContext *private) +static int SCPerfGetAllCountersArray(StatsPublicThreadContext *pctx, SCPerfPrivateContext *private) { if (pctx == NULL || private == NULL) return -1; @@ -1209,12 +1209,12 @@ int SCPerfSetupPrivate(ThreadVars *tv) * \brief Syncs the counter array with the global counter variables * * \param pca Pointer to the SCPerfPrivateContext - * \param pctx Pointer the the tv's SCPerfPublicContext + * \param pctx Pointer the the tv's StatsPublicThreadContext * * \retval 0 on success * \retval -1 on error */ -int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, SCPerfPublicContext *pctx) +int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, StatsPublicThreadContext *pctx) { SCPCAElem *pcae = NULL; uint32_t i = 0; @@ -1313,14 +1313,14 @@ void SCPerfReleasePCA(SCPerfPrivateContext *pca) * \param tm_name Name of the engine module under which the counter has to be * registered * \param type Datatype of this counter variable - * \param pctx SCPerfPublicContext corresponding to the tm_name key under which the + * \param pctx StatsPublicThreadContext corresponding to the tm_name key under which the * key has to be registered * * \retval id Counter id for the newly registered counter, or the already * present counter */ static uint16_t RegisterCounter(char *cname, char *tm_name, - SCPerfPublicContext *pctx) + StatsPublicThreadContext *pctx) { uint16_t id = StatsRegisterQualifiedCounter(cname, tm_name, pctx, STATS_TYPE_NORMAL, NULL); @@ -1329,19 +1329,19 @@ static uint16_t RegisterCounter(char *cname, char *tm_name, static int SCPerfTestCounterReg02() { - SCPerfPublicContext pctx; + StatsPublicThreadContext pctx; - memset(&pctx, 0, sizeof(SCPerfPublicContext)); + memset(&pctx, 0, sizeof(StatsPublicThreadContext)); return RegisterCounter(NULL, NULL, &pctx); } static int SCPerfTestCounterReg03() { - SCPerfPublicContext pctx; + StatsPublicThreadContext pctx; int result; - memset(&pctx, 0, sizeof(SCPerfPublicContext)); + memset(&pctx, 0, sizeof(StatsPublicThreadContext)); result = RegisterCounter("t1", "c1", &pctx); @@ -1352,10 +1352,10 @@ static int SCPerfTestCounterReg03() static int SCPerfTestCounterReg04() { - SCPerfPublicContext pctx; + StatsPublicThreadContext pctx; int result; - memset(&pctx, 0, sizeof(SCPerfPublicContext)); + memset(&pctx, 0, sizeof(StatsPublicThreadContext)); RegisterCounter("t1", "c1", &pctx); RegisterCounter("t2", "c2", &pctx); diff --git a/src/counters.h b/src/counters.h index 0a6e830fbf5f..7d91afa83bf5 100644 --- a/src/counters.h +++ b/src/counters.h @@ -58,7 +58,7 @@ typedef struct SCPerfCounter_ { /** * \brief Holds the Perf Context for a ThreadVars instance */ -typedef struct SCPerfPublicContext_ { +typedef struct StatsPublicThreadContext_ { /* flag set by the wakeup thread, to inform the client threads to sync */ uint32_t perf_flag; @@ -70,7 +70,7 @@ typedef struct SCPerfPublicContext_ { /* mutex to prevent simultaneous access during update_counter/output_stat */ SCMutex m; -} SCPerfPublicContext; +} StatsPublicThreadContext; /** * \brief Node elements used by the SCPerfPrivateContext(PCA) Node @@ -115,7 +115,7 @@ uint16_t StatsRegisterMaxCounter(char *, struct ThreadVars_ *); uint16_t StatsRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)); /* utility functions */ -int SCPerfUpdateCounterArray(SCPerfPrivateContext *, SCPerfPublicContext *); +int SCPerfUpdateCounterArray(SCPerfPrivateContext *, StatsPublicThreadContext *); uint64_t SCPerfGetLocalCounterValue(struct ThreadVars_ *, uint16_t); int SCPerfSetupPrivate(struct ThreadVars_ *); diff --git a/src/threadvars.h b/src/threadvars.h index b5702cfc70a3..7f915e1b82d2 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -104,7 +104,7 @@ typedef struct ThreadVars_ { /* counters */ /** public counter store: counter syncs update this */ - SCPerfPublicContext perf_public_ctx; + StatsPublicThreadContext perf_public_ctx; /** private counter store: counter updates modify this */ SCPerfPrivateContext perf_private_ctx; From 4362d0a6e9b0b48bf7f41b05ad8e1c6a26c0eef4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 16:04:30 +0200 Subject: [PATCH 0520/2553] counters: s/SCPerfPrivateContext/StatsPrivateThreadContext/g --- src/counters.c | 40 ++++++++++++++++++++-------------------- src/counters.h | 10 +++++----- src/threadvars.h | 2 +- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/counters.c b/src/counters.c index 15d8b85ae186..cd2e2934eac6 100644 --- a/src/counters.c +++ b/src/counters.c @@ -113,7 +113,7 @@ static uint16_t counters_global_id = 0; */ void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) { - SCPerfPrivateContext *pca = &tv->perf_private_ctx; + StatsPrivateThreadContext *pca = &tv->perf_private_ctx; #ifdef UNITTESTS if (pca->initialized == 0) return; @@ -134,7 +134,7 @@ void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) */ void StatsIncr(ThreadVars *tv, uint16_t id) { - SCPerfPrivateContext *pca = &tv->perf_private_ctx; + StatsPrivateThreadContext *pca = &tv->perf_private_ctx; #ifdef UNITTESTS if (pca->initialized == 0) return; @@ -151,12 +151,12 @@ void StatsIncr(ThreadVars *tv, uint16_t id) * \brief Sets a value of type double to the local counter * * \param id Index of the local counter in the counter array - * \param pca Pointer to the SCPerfPrivateContext + * \param pca Pointer to the StatsPrivateThreadContext * \param x The value to set for the counter */ void StatsSetUI64(ThreadVars *tv, uint16_t id, uint64_t x) { - SCPerfPrivateContext *pca = &tv->perf_private_ctx; + StatsPrivateThreadContext *pca = &tv->perf_private_ctx; #ifdef UNITTESTS if (pca->initialized == 0) return; @@ -546,10 +546,10 @@ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, /** * \brief Copies the SCPerfCounter value from the local counter present in the - * SCPerfPrivateContext to its corresponding global counterpart. Used + * StatsPrivateThreadContext to its corresponding global counterpart. Used * internally by SCPerfUpdateCounterArray() * - * \param pcae Pointer to the SCPerfPrivateContext which holds the local + * \param pcae Pointer to the StatsPrivateThreadContext which holds the local * versions of the counters */ static void SCPerfCopyCounterValue(SCPCAElem *pcae) @@ -1137,7 +1137,7 @@ static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext */ static int SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, StatsPublicThreadContext *pctx, - SCPerfPrivateContext *pca) + StatsPrivateThreadContext *pca) { SCPerfCounter *pc = NULL; uint32_t i = 0; @@ -1188,7 +1188,7 @@ static int SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, * \retval pca Pointer to a counter-array for all counter of this tm instance * on success; NULL on failure */ -static int SCPerfGetAllCountersArray(StatsPublicThreadContext *pctx, SCPerfPrivateContext *private) +static int SCPerfGetAllCountersArray(StatsPublicThreadContext *pctx, StatsPrivateThreadContext *private) { if (pctx == NULL || private == NULL) return -1; @@ -1208,13 +1208,13 @@ int SCPerfSetupPrivate(ThreadVars *tv) /** * \brief Syncs the counter array with the global counter variables * - * \param pca Pointer to the SCPerfPrivateContext + * \param pca Pointer to the StatsPrivateThreadContext * \param pctx Pointer the the tv's StatsPublicThreadContext * * \retval 0 on success * \retval -1 on error */ -int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, StatsPublicThreadContext *pctx) +int SCPerfUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadContext *pctx) { SCPCAElem *pcae = NULL; uint32_t i = 0; @@ -1248,7 +1248,7 @@ int SCPerfUpdateCounterArray(SCPerfPrivateContext *pca, StatsPublicThreadContext */ uint64_t SCPerfGetLocalCounterValue(ThreadVars *tv, uint16_t id) { - SCPerfPrivateContext *pca = &tv->perf_private_ctx; + StatsPrivateThreadContext *pca = &tv->perf_private_ctx; #ifdef DEBUG BUG_ON ((id < 1) || (id > pca->size)); #endif @@ -1285,12 +1285,12 @@ void SCPerfReleasePerfCounterS(SCPerfCounter *head) } /** - * \brief Releases the SCPerfPrivateContext allocated by the user, for storing and + * \brief Releases the StatsPrivateThreadContext allocated by the user, for storing and * updating local counter values * - * \param pca Pointer to the SCPerfPrivateContext + * \param pca Pointer to the StatsPrivateThreadContext */ -void SCPerfReleasePCA(SCPerfPrivateContext *pca) +void SCPerfReleasePCA(StatsPrivateThreadContext *pca) { if (pca != NULL) { if (pca->head != NULL) { @@ -1410,12 +1410,12 @@ static int SCPerfTestGetCntArray06() static int SCPerfTestCntArraySize07() { ThreadVars tv; - SCPerfPrivateContext *pca = NULL; + StatsPrivateThreadContext *pca = NULL; int result; memset(&tv, 0, sizeof(ThreadVars)); - //pca = (SCPerfPrivateContext *)&tv.perf_private_ctx; + //pca = (StatsPrivateThreadContext *)&tv.perf_private_ctx; RegisterCounter("t1", "c1", &tv.perf_public_ctx); RegisterCounter("t2", "c2", &tv.perf_public_ctx); @@ -1437,7 +1437,7 @@ static int SCPerfTestCntArraySize07() static int SCPerfTestUpdateCounter08() { ThreadVars tv; - SCPerfPrivateContext *pca = NULL; + StatsPrivateThreadContext *pca = NULL; int id; int result; @@ -1462,7 +1462,7 @@ static int SCPerfTestUpdateCounter08() static int SCPerfTestUpdateCounter09() { ThreadVars tv; - SCPerfPrivateContext *pca = NULL; + StatsPrivateThreadContext *pca = NULL; uint16_t id1, id2; int result; @@ -1491,7 +1491,7 @@ static int SCPerfTestUpdateCounter09() static int SCPerfTestUpdateGlobalCounter10() { ThreadVars tv; - SCPerfPrivateContext *pca = NULL; + StatsPrivateThreadContext *pca = NULL; int result = 1; uint16_t id1, id2, id3; @@ -1525,7 +1525,7 @@ static int SCPerfTestUpdateGlobalCounter10() static int SCPerfTestCounterValues11() { ThreadVars tv; - SCPerfPrivateContext *pca = NULL; + StatsPrivateThreadContext *pca = NULL; int result = 1; uint16_t id1, id2, id3, id4; diff --git a/src/counters.h b/src/counters.h index 7d91afa83bf5..d6d89a8dd407 100644 --- a/src/counters.h +++ b/src/counters.h @@ -73,7 +73,7 @@ typedef struct StatsPublicThreadContext_ { } StatsPublicThreadContext; /** - * \brief Node elements used by the SCPerfPrivateContext(PCA) Node + * \brief Node elements used by the StatsPrivateThreadContext(PCA) Node */ typedef struct SCPCAElem_ { /* pointer to the PerfCounter that corresponds to this PCAElem */ @@ -92,7 +92,7 @@ typedef struct SCPCAElem_ { /** * \brief used to hold the private version of the counters registered */ -typedef struct SCPerfPrivateContext_ { +typedef struct StatsPrivateThreadContext_ { /* points to the array holding PCAElems */ SCPCAElem *head; @@ -100,7 +100,7 @@ typedef struct SCPerfPrivateContext_ { uint32_t size; int initialized; -} SCPerfPrivateContext; +} StatsPrivateThreadContext; /* the initialization functions */ void StatsInit(void); @@ -115,13 +115,13 @@ uint16_t StatsRegisterMaxCounter(char *, struct ThreadVars_ *); uint16_t StatsRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)); /* utility functions */ -int SCPerfUpdateCounterArray(SCPerfPrivateContext *, StatsPublicThreadContext *); +int SCPerfUpdateCounterArray(StatsPrivateThreadContext *, StatsPublicThreadContext *); uint64_t SCPerfGetLocalCounterValue(struct ThreadVars_ *, uint16_t); int SCPerfSetupPrivate(struct ThreadVars_ *); /* functions used to free the resources alloted by the Perf counter API */ void SCPerfReleaseResources(void); -void SCPerfReleasePCA(SCPerfPrivateContext *); +void SCPerfReleasePCA(StatsPrivateThreadContext *); /* functions used to update local counter values */ void StatsAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); diff --git a/src/threadvars.h b/src/threadvars.h index 7f915e1b82d2..a632a23b4f27 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -107,7 +107,7 @@ typedef struct ThreadVars_ { StatsPublicThreadContext perf_public_ctx; /** private counter store: counter updates modify this */ - SCPerfPrivateContext perf_private_ctx; + StatsPrivateThreadContext perf_private_ctx; SCCtrlMutex *ctrl_mutex; SCCtrlCondT *ctrl_cond; From 752f03e7a40225b05d9d0dbd56fe7b5cb4b23b9b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 16:10:17 +0200 Subject: [PATCH 0521/2553] counters: remaining s/SCPerf/Stats/g --- src/counters.c | 198 +++++++++++++++++++------------------- src/counters.h | 34 +++---- src/detect.c | 10 +- src/flow-manager.c | 8 +- src/runmode-unittests.c | 2 +- src/runmode-unix-socket.c | 4 +- src/source-af-packet.c | 8 +- src/source-erf-dag.c | 10 +- src/source-ipfw.c | 2 +- src/source-mpipe.c | 2 +- src/source-napatech.c | 2 +- src/source-netmap.c | 8 +- src/source-nflog.c | 2 +- src/source-nfq.c | 2 +- src/source-pcap-file.c | 2 +- src/source-pcap.c | 4 +- src/source-pfring.c | 10 +- src/suricata.c | 4 +- src/tm-threads.c | 12 +-- src/tmqh-flow.c | 2 +- src/tmqh-ringbuffer.c | 6 +- src/tmqh-simple.c | 2 +- src/unix-manager.c | 6 +- 23 files changed, 170 insertions(+), 170 deletions(-) diff --git a/src/counters.c b/src/counters.c index cd2e2934eac6..10521363c5b8 100644 --- a/src/counters.c +++ b/src/counters.c @@ -199,7 +199,7 @@ static ConfNode *GetConfig(void) { * * \todo Support multiple interfaces */ -static void SCPerfInitOPCtx(void) +static void StatsInitOPCtx(void) { SCEnter(); ConfNode *stats = GetConfig(); @@ -237,7 +237,7 @@ static void SCPerfInitOPCtx(void) * \brief Releases the resources alloted to the output context of the Perf * Counter API */ -static void SCPerfReleaseOPCtx() +static void StatsReleaseOPCtx() { if (stats_ctx == NULL) { SCLogDebug("Counter module has been disabled"); @@ -280,7 +280,7 @@ static void SCPerfReleaseOPCtx() * * \retval NULL This is the value that is always returned */ -static void *SCPerfMgmtThread(void *arg) +static void *StatsMgmtThread(void *arg) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); @@ -304,7 +304,7 @@ static void *SCPerfMgmtThread(void *arg) if (stats_ctx == NULL) { SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" - "SCPerfInitCounterApi() has to be called first"); + "StatsInitCounterApi() has to be called first"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); return NULL; } @@ -365,7 +365,7 @@ static void *SCPerfMgmtThread(void *arg) * * \retval NULL This is the value that is always returned */ -static void *SCPerfWakeupThread(void *arg) +static void *StatsWakeupThread(void *arg) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); @@ -391,7 +391,7 @@ static void *SCPerfWakeupThread(void *arg) if (stats_ctx == NULL) { SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" - "SCPerfInitCounterApi() has to be called first"); + "StatsInitCounterApi() has to be called first"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); return NULL; } @@ -461,11 +461,11 @@ static void *SCPerfWakeupThread(void *arg) /** * \brief Releases a perf counter. Used internally by - * SCPerfReleasePerfCounterS() + * StatsReleasePerfCounterS() * - * \param pc Pointer to the SCPerfCounter to be freed + * \param pc Pointer to the StatsCounter to be freed */ -static void SCPerfReleaseCounter(SCPerfCounter *pc) +static void StatsReleaseCounter(StatsCounter *pc) { if (pc != NULL) { if (pc->cname != NULL) @@ -493,10 +493,10 @@ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, StatsPublicThreadContext *pctx, int type_q, uint64_t (*Func)(void)) { - SCPerfCounter **head = &pctx->head; - SCPerfCounter *temp = NULL; - SCPerfCounter *prev = NULL; - SCPerfCounter *pc = NULL; + StatsCounter **head = &pctx->head; + StatsCounter *temp = NULL; + StatsCounter *prev = NULL; + StatsCounter *pc = NULL; if (cname == NULL || pctx == NULL) { SCLogDebug("Counter name, StatsPublicThreadContext NULL"); @@ -519,16 +519,16 @@ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, return(temp->id); /* if we reach this point we don't have a counter registered by this cname */ - if ( (pc = SCMalloc(sizeof(SCPerfCounter))) == NULL) + if ( (pc = SCMalloc(sizeof(StatsCounter))) == NULL) return 0; - memset(pc, 0, sizeof(SCPerfCounter)); + memset(pc, 0, sizeof(StatsCounter)); if ( (pc->cname = SCStrdup(cname)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - /* assign a unique id to this SCPerfCounter. The id is local to this + /* assign a unique id to this StatsCounter. The id is local to this * PerfContext. Please note that the id start from 1, and not 0 */ pc->id = ++(pctx->curr_id); @@ -545,16 +545,16 @@ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, } /** - * \brief Copies the SCPerfCounter value from the local counter present in the + * \brief Copies the StatsCounter value from the local counter present in the * StatsPrivateThreadContext to its corresponding global counterpart. Used - * internally by SCPerfUpdateCounterArray() + * internally by StatsUpdateCounterArray() * * \param pcae Pointer to the StatsPrivateThreadContext which holds the local * versions of the counters */ -static void SCPerfCopyCounterValue(SCPCAElem *pcae) +static void StatsCopyCounterValue(SCPCAElem *pcae) { - SCPerfCounter *pc = pcae->pc; + StatsCounter *pc = pcae->pc; pc->value = pcae->value; pc->updates = pcae->updates; @@ -574,7 +574,7 @@ static void SCPerfCopyCounterValue(SCPCAElem *pcae) * \param pc Pointer to the PerfCounter for which the timebased counter has to * be calculated */ -static uint64_t SCPerfOutputCalculateCounterValue(SCPerfCounter *pc) +static uint64_t StatsOutputCalculateCounterValue(StatsCounter *pc) { return pc->value; } @@ -585,7 +585,7 @@ static uint64_t SCPerfOutputCalculateCounterValue(SCPerfCounter *pc) static int StatsOutput(ThreadVars *tv) { const StatsThreadStore *sts = NULL; - const SCPerfCounter *pc = NULL; + const StatsCounter *pc = NULL; void *td = stats_thread_data; if (stats_table.nstats == 0) { @@ -756,12 +756,12 @@ static int StatsOutput(ThreadVars *tv) /** * \brief The file output interface for the Perf Counter api */ -TmEcode SCPerfOutputCounterSocket(json_t *cmd, +TmEcode StatsOutputCounterSocket(json_t *cmd, json_t *answer, void *data) { StatsThreadStore *sts = NULL; - SCPerfCounter *pc = NULL; - SCPerfCounter **pc_heads = NULL; + StatsCounter *pc = NULL; + StatsCounter **pc_heads = NULL; uint64_t ui64_temp = 0; uint64_t ui64_result = 0; @@ -795,13 +795,13 @@ TmEcode SCPerfOutputCounterSocket(json_t *cmd, json_string("internal error at json object creation")); return TM_ECODE_FAILED; } - if ((pc_heads = SCMalloc(sts->size * sizeof(SCPerfCounter *))) == NULL) { + if ((pc_heads = SCMalloc(sts->size * sizeof(StatsCounter *))) == NULL) { json_decref(tm_array); json_object_set_new(answer, "message", json_string("internal memory error")); return TM_ECODE_FAILED; } - memset(pc_heads, 0, sts->size * sizeof(SCPerfCounter *)); + memset(pc_heads, 0, sts->size * sizeof(StatsCounter *)); for (u = 0; u < sts->size; u++) { pc_heads[u] = sts->head[u]->head; @@ -817,7 +817,7 @@ TmEcode SCPerfOutputCounterSocket(json_t *cmd, pc = pc_heads[0]; for (u = 0; u < sts->size; u++) { - ui64_temp = SCPerfOutputCalculateCounterValue(pc_heads[u]); + ui64_temp = StatsOutputCalculateCounterValue(pc_heads[u]); ui64_result += ui64_temp; if (pc_heads[u] != NULL) @@ -857,7 +857,7 @@ void StatsInit(void) { BUG_ON(stats_ctx != NULL); if ( (stats_ctx = SCMalloc(sizeof(StatsGlobalContext))) == NULL) { - SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCPerfInitOPCtx. Exiting..."); + SCLogError(SC_ERR_FATAL, "Fatal error encountered in StatsInitOPCtx. Exiting..."); exit(EXIT_FAILURE); } memset(stats_ctx, 0, sizeof(StatsGlobalContext)); @@ -865,7 +865,7 @@ void StatsInit(void) void StatsSetupPostConfig(void) { - SCPerfInitOPCtx(); + StatsInitOPCtx(); } /** @@ -875,7 +875,7 @@ void StatsSetupPostConfig(void) * The threads use the condition variable in the thread vars to control * their wait loops to make sure the main thread can quickly kill them. */ -void SCPerfSpawnThreads(void) +void StatsSpawnThreads(void) { SCEnter(); @@ -887,8 +887,8 @@ void SCPerfSpawnThreads(void) ThreadVars *tv_mgmt = NULL; /* spawn the stats wakeup thread */ - tv_wakeup = TmThreadCreateMgmtThread("SCPerfWakeupThread", - SCPerfWakeupThread, 1); + tv_wakeup = TmThreadCreateMgmtThread("StatsWakeupThread", + StatsWakeupThread, 1); if (tv_wakeup == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadCreateMgmtThread " "failed"); @@ -897,13 +897,13 @@ void SCPerfSpawnThreads(void) if (TmThreadSpawn(tv_wakeup) != 0) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed for " - "SCPerfWakeupThread"); + "StatsWakeupThread"); exit(EXIT_FAILURE); } /* spawn the stats mgmt thread */ - tv_mgmt = TmThreadCreateMgmtThread("SCPerfMgmtThread", - SCPerfMgmtThread, 1); + tv_mgmt = TmThreadCreateMgmtThread("StatsMgmtThread", + StatsMgmtThread, 1); if (tv_mgmt == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadCreateMgmtThread failed"); @@ -912,7 +912,7 @@ void SCPerfSpawnThreads(void) if (TmThreadSpawn(tv_mgmt) != 0) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed for " - "SCPerfWakeupThread"); + "StatsWakeupThread"); exit(EXIT_FAILURE); } @@ -1086,7 +1086,7 @@ static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext CountersIdHashFreeFunc); BUG_ON(stats_ctx->counters_id_hash == NULL); } - SCPerfCounter *pc = pctx->head; + StatsCounter *pc = pctx->head; while (pc != NULL) { CountersIdType t = { 0, pc->cname }, *id = NULL; id = HashTableLookup(stats_ctx->counters_id_hash, &t, sizeof(t)); @@ -1135,11 +1135,11 @@ static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext * * \retval a counter-array in this(s_id-e_id) range for this TM instance */ -static int SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, +static int StatsGetCounterArrayRange(uint16_t s_id, uint16_t e_id, StatsPublicThreadContext *pctx, StatsPrivateThreadContext *pca) { - SCPerfCounter *pc = NULL; + StatsCounter *pc = NULL; uint32_t i = 0; if (pctx == NULL || pca == NULL) { @@ -1188,18 +1188,18 @@ static int SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, * \retval pca Pointer to a counter-array for all counter of this tm instance * on success; NULL on failure */ -static int SCPerfGetAllCountersArray(StatsPublicThreadContext *pctx, StatsPrivateThreadContext *private) +static int StatsGetAllCountersArray(StatsPublicThreadContext *pctx, StatsPrivateThreadContext *private) { if (pctx == NULL || private == NULL) return -1; - return SCPerfGetCounterArrayRange(1, pctx->curr_id, pctx, private); + return StatsGetCounterArrayRange(1, pctx->curr_id, pctx, private); } -int SCPerfSetupPrivate(ThreadVars *tv) +int StatsSetupPrivate(ThreadVars *tv) { - SCPerfGetAllCountersArray(&(tv)->perf_public_ctx, &(tv)->perf_private_ctx); + StatsGetAllCountersArray(&(tv)->perf_public_ctx, &(tv)->perf_private_ctx); StatsThreadRegister(tv->name, &(tv)->perf_public_ctx); return 0; @@ -1214,13 +1214,13 @@ int SCPerfSetupPrivate(ThreadVars *tv) * \retval 0 on success * \retval -1 on error */ -int SCPerfUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadContext *pctx) +int StatsUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadContext *pctx) { SCPCAElem *pcae = NULL; uint32_t i = 0; if (pca == NULL || pctx == NULL) { - SCLogDebug("pca or pctx is NULL inside SCPerfUpdateCounterArray"); + SCLogDebug("pca or pctx is NULL inside StatsUpdateCounterArray"); return -1; } @@ -1228,7 +1228,7 @@ int SCPerfUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadCo SCMutexLock(&pctx->m); for (i = 1; i <= pca->size; i++) { - SCPerfCopyCounterValue(&pcae[i]); + StatsCopyCounterValue(&pcae[i]); } SCMutexUnlock(&pctx->m); @@ -1246,7 +1246,7 @@ int SCPerfUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadCo * \retval 0 on success. * \retval -1 on error. */ -uint64_t SCPerfGetLocalCounterValue(ThreadVars *tv, uint16_t id) +uint64_t StatsGetLocalCounterValue(ThreadVars *tv, uint16_t id) { StatsPrivateThreadContext *pca = &tv->perf_private_ctx; #ifdef DEBUG @@ -1258,9 +1258,9 @@ uint64_t SCPerfGetLocalCounterValue(ThreadVars *tv, uint16_t id) /** * \brief Releases the resources alloted by the Perf Counter API */ -void SCPerfReleaseResources() +void StatsReleaseResources() { - SCPerfReleaseOPCtx(); + StatsReleaseOPCtx(); return; } @@ -1271,14 +1271,14 @@ void SCPerfReleaseResources() * \param head Pointer to the head of the list of perf counters that have to * be freed */ -void SCPerfReleasePerfCounterS(SCPerfCounter *head) +void StatsReleasePerfCounterS(StatsCounter *head) { - SCPerfCounter *pc = NULL; + StatsCounter *pc = NULL; while (head != NULL) { pc = head; head = head->next; - SCPerfReleaseCounter(pc); + StatsReleaseCounter(pc); } return; @@ -1290,7 +1290,7 @@ void SCPerfReleasePerfCounterS(SCPerfCounter *head) * * \param pca Pointer to the StatsPrivateThreadContext */ -void SCPerfReleasePCA(StatsPrivateThreadContext *pca) +void StatsReleasePCA(StatsPrivateThreadContext *pca) { if (pca != NULL) { if (pca->head != NULL) { @@ -1327,7 +1327,7 @@ static uint16_t RegisterCounter(char *cname, char *tm_name, return id; } -static int SCPerfTestCounterReg02() +static int StatsTestCounterReg02() { StatsPublicThreadContext pctx; @@ -1336,7 +1336,7 @@ static int SCPerfTestCounterReg02() return RegisterCounter(NULL, NULL, &pctx); } -static int SCPerfTestCounterReg03() +static int StatsTestCounterReg03() { StatsPublicThreadContext pctx; int result; @@ -1345,12 +1345,12 @@ static int SCPerfTestCounterReg03() result = RegisterCounter("t1", "c1", &pctx); - SCPerfReleasePerfCounterS(pctx.head); + StatsReleasePerfCounterS(pctx.head); return result; } -static int SCPerfTestCounterReg04() +static int StatsTestCounterReg04() { StatsPublicThreadContext pctx; int result; @@ -1363,12 +1363,12 @@ static int SCPerfTestCounterReg04() result = RegisterCounter("t1", "c1", &pctx); - SCPerfReleasePerfCounterS(pctx.head); + StatsReleasePerfCounterS(pctx.head); return result; } -static int SCPerfTestGetCntArray05() +static int StatsTestGetCntArray05() { ThreadVars tv; int id; @@ -1381,11 +1381,11 @@ static int SCPerfTestGetCntArray05() return 0; } - int r = SCPerfGetAllCountersArray(NULL, &tv.perf_private_ctx); + int r = StatsGetAllCountersArray(NULL, &tv.perf_private_ctx); return (r == -1) ? 1 : 0; } -static int SCPerfTestGetCntArray06() +static int StatsTestGetCntArray06() { ThreadVars tv; int id; @@ -1397,17 +1397,17 @@ static int SCPerfTestGetCntArray06() if (id != 1) return 0; - int r = SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + int r = StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); result = (r == 0) ? 1 : 0; - SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); - SCPerfReleasePCA(&tv.perf_private_ctx); + StatsReleasePerfCounterS(tv.perf_public_ctx.head); + StatsReleasePCA(&tv.perf_private_ctx); return result; } -static int SCPerfTestCntArraySize07() +static int StatsTestCntArraySize07() { ThreadVars tv; StatsPrivateThreadContext *pca = NULL; @@ -1420,7 +1420,7 @@ static int SCPerfTestCntArraySize07() RegisterCounter("t1", "c1", &tv.perf_public_ctx); RegisterCounter("t2", "c2", &tv.perf_public_ctx); - SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; StatsIncr(&tv, 1); @@ -1428,13 +1428,13 @@ static int SCPerfTestCntArraySize07() result = pca->size; - SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); - SCPerfReleasePCA(pca); + StatsReleasePerfCounterS(tv.perf_public_ctx.head); + StatsReleasePCA(pca); return result; } -static int SCPerfTestUpdateCounter08() +static int StatsTestUpdateCounter08() { ThreadVars tv; StatsPrivateThreadContext *pca = NULL; @@ -1445,7 +1445,7 @@ static int SCPerfTestUpdateCounter08() id = RegisterCounter("t1", "c1", &tv.perf_public_ctx); - SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; StatsIncr(&tv, id); @@ -1453,13 +1453,13 @@ static int SCPerfTestUpdateCounter08() result = pca->head[id].value; - SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); - SCPerfReleasePCA(pca); + StatsReleasePerfCounterS(tv.perf_public_ctx.head); + StatsReleasePCA(pca); return result; } -static int SCPerfTestUpdateCounter09() +static int StatsTestUpdateCounter09() { ThreadVars tv; StatsPrivateThreadContext *pca = NULL; @@ -1474,7 +1474,7 @@ static int SCPerfTestUpdateCounter09() RegisterCounter("t4", "c4", &tv.perf_public_ctx); id2 = RegisterCounter("t5", "c5", &tv.perf_public_ctx); - SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; StatsIncr(&tv, id2); @@ -1482,13 +1482,13 @@ static int SCPerfTestUpdateCounter09() result = (pca->head[id1].value == 0) && (pca->head[id2].value == 101); - SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); - SCPerfReleasePCA(pca); + StatsReleasePerfCounterS(tv.perf_public_ctx.head); + StatsReleasePCA(pca); return result; } -static int SCPerfTestUpdateGlobalCounter10() +static int StatsTestUpdateGlobalCounter10() { ThreadVars tv; StatsPrivateThreadContext *pca = NULL; @@ -1502,7 +1502,7 @@ static int SCPerfTestUpdateGlobalCounter10() id2 = RegisterCounter("t2", "c2", &tv.perf_public_ctx); id3 = RegisterCounter("t3", "c3", &tv.perf_public_ctx); - SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; StatsIncr(&tv, id1); @@ -1510,19 +1510,19 @@ static int SCPerfTestUpdateGlobalCounter10() StatsIncr(&tv, id3); StatsAddUI64(&tv, id3, 100); - SCPerfUpdateCounterArray(pca, &tv.perf_public_ctx); + StatsUpdateCounterArray(pca, &tv.perf_public_ctx); result = (1 == tv.perf_public_ctx.head->value); result &= (100 == tv.perf_public_ctx.head->next->value); result &= (101 == tv.perf_public_ctx.head->next->next->value); - SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); - SCPerfReleasePCA(pca); + StatsReleasePerfCounterS(tv.perf_public_ctx.head); + StatsReleasePCA(pca); return result; } -static int SCPerfTestCounterValues11() +static int StatsTestCounterValues11() { ThreadVars tv; StatsPrivateThreadContext *pca = NULL; @@ -1537,7 +1537,7 @@ static int SCPerfTestCounterValues11() id3 = RegisterCounter("t3", "c3", &tv.perf_public_ctx); id4 = RegisterCounter("t4", "c4", &tv.perf_public_ctx); - SCPerfGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); pca = &tv.perf_private_ctx; StatsIncr(&tv, id1); @@ -1545,7 +1545,7 @@ static int SCPerfTestCounterValues11() StatsAddUI64(&tv, id3, 257); StatsAddUI64(&tv, id4, 16843024); - SCPerfUpdateCounterArray(pca, &tv.perf_public_ctx); + StatsUpdateCounterArray(pca, &tv.perf_public_ctx); result &= (1 == tv.perf_public_ctx.head->value); @@ -1555,27 +1555,27 @@ static int SCPerfTestCounterValues11() result &= (16843024 == tv.perf_public_ctx.head->next->next->next->value); - SCPerfReleasePerfCounterS(tv.perf_public_ctx.head); - SCPerfReleasePCA(pca); + StatsReleasePerfCounterS(tv.perf_public_ctx.head); + StatsReleasePCA(pca); return result; } #endif -void SCPerfRegisterTests() +void StatsRegisterTests() { #ifdef UNITTESTS - UtRegisterTest("SCPerfTestCounterReg02", SCPerfTestCounterReg02, 0); - UtRegisterTest("SCPerfTestCounterReg03", SCPerfTestCounterReg03, 1); - UtRegisterTest("SCPerfTestCounterReg04", SCPerfTestCounterReg04, 1); - UtRegisterTest("SCPerfTestGetCntArray05", SCPerfTestGetCntArray05, 1); - UtRegisterTest("SCPerfTestGetCntArray06", SCPerfTestGetCntArray06, 1); - UtRegisterTest("SCPerfTestCntArraySize07", SCPerfTestCntArraySize07, 2); - UtRegisterTest("SCPerfTestUpdateCounter08", SCPerfTestUpdateCounter08, 101); - UtRegisterTest("SCPerfTestUpdateCounter09", SCPerfTestUpdateCounter09, 1); - UtRegisterTest("SCPerfTestUpdateGlobalCounter10", - SCPerfTestUpdateGlobalCounter10, 1); - UtRegisterTest("SCPerfTestCounterValues11", SCPerfTestCounterValues11, 1); + UtRegisterTest("StatsTestCounterReg02", StatsTestCounterReg02, 0); + UtRegisterTest("StatsTestCounterReg03", StatsTestCounterReg03, 1); + UtRegisterTest("StatsTestCounterReg04", StatsTestCounterReg04, 1); + UtRegisterTest("StatsTestGetCntArray05", StatsTestGetCntArray05, 1); + UtRegisterTest("StatsTestGetCntArray06", StatsTestGetCntArray06, 1); + UtRegisterTest("StatsTestCntArraySize07", StatsTestCntArraySize07, 2); + UtRegisterTest("StatsTestUpdateCounter08", StatsTestUpdateCounter08, 101); + UtRegisterTest("StatsTestUpdateCounter09", StatsTestUpdateCounter09, 1); + UtRegisterTest("StatsTestUpdateGlobalCounter10", + StatsTestUpdateGlobalCounter10, 1); + UtRegisterTest("StatsTestCounterValues11", StatsTestCounterValues11, 1); #endif } diff --git a/src/counters.h b/src/counters.h index d6d89a8dd407..95dfd6a670af 100644 --- a/src/counters.h +++ b/src/counters.h @@ -31,7 +31,7 @@ struct ThreadVars_; /** * \brief Container to hold the counter variable */ -typedef struct SCPerfCounter_ { +typedef struct StatsCounter_ { int type; /* local id for this counter in this tm */ @@ -52,8 +52,8 @@ typedef struct SCPerfCounter_ { char *cname; /* the next perfcounter for this tv's tm instance */ - struct SCPerfCounter_ *next; -} SCPerfCounter; + struct StatsCounter_ *next; +} StatsCounter; /** * \brief Holds the Perf Context for a ThreadVars instance @@ -63,7 +63,7 @@ typedef struct StatsPublicThreadContext_ { uint32_t perf_flag; /* pointer to the head of a list of counters assigned under this context */ - SCPerfCounter *head; + StatsCounter *head; /* holds the total no of counters already assigned for this perf context */ uint16_t curr_id; @@ -77,7 +77,7 @@ typedef struct StatsPublicThreadContext_ { */ typedef struct SCPCAElem_ { /* pointer to the PerfCounter that corresponds to this PCAElem */ - SCPerfCounter *pc; + StatsCounter *pc; /* counter id of the above counter(pc) */ uint16_t id; @@ -105,8 +105,8 @@ typedef struct StatsPrivateThreadContext_ { /* the initialization functions */ void StatsInit(void); void StatsSetupPostConfig(void); -void SCPerfSpawnThreads(void); -void SCPerfRegisterTests(void); +void StatsSpawnThreads(void); +void StatsRegisterTests(void); /* counter registration functions */ uint16_t StatsRegisterCounter(char *, struct ThreadVars_ *); @@ -115,33 +115,33 @@ uint16_t StatsRegisterMaxCounter(char *, struct ThreadVars_ *); uint16_t StatsRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)); /* utility functions */ -int SCPerfUpdateCounterArray(StatsPrivateThreadContext *, StatsPublicThreadContext *); -uint64_t SCPerfGetLocalCounterValue(struct ThreadVars_ *, uint16_t); -int SCPerfSetupPrivate(struct ThreadVars_ *); +int StatsUpdateCounterArray(StatsPrivateThreadContext *, StatsPublicThreadContext *); +uint64_t StatsGetLocalCounterValue(struct ThreadVars_ *, uint16_t); +int StatsSetupPrivate(struct ThreadVars_ *); /* functions used to free the resources alloted by the Perf counter API */ -void SCPerfReleaseResources(void); -void SCPerfReleasePCA(StatsPrivateThreadContext *); +void StatsReleaseResources(void); +void StatsReleasePCA(StatsPrivateThreadContext *); /* functions used to update local counter values */ void StatsAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); void StatsSetUI64(struct ThreadVars_ *, uint16_t, uint64_t); void StatsIncr(struct ThreadVars_ *, uint16_t); -#define SCPerfSyncCounters(tv) \ - SCPerfUpdateCounterArray(&(tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ +#define StatsSyncCounters(tv) \ + StatsUpdateCounterArray(&(tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ -#define SCPerfSyncCountersIfSignalled(tv) \ +#define StatsSyncCountersIfSignalled(tv) \ do { \ if ((tv)->perf_public_ctx.perf_flag == 1) { \ - SCPerfUpdateCounterArray(&(tv)->perf_private_ctx, \ + StatsUpdateCounterArray(&(tv)->perf_private_ctx, \ &(tv)->perf_public_ctx); \ } \ } while (0) #ifdef BUILD_UNIX_SOCKET #include -TmEcode SCPerfOutputCounterSocket(json_t *cmd, +TmEcode StatsOutputCounterSocket(json_t *cmd, json_t *answer, void *data); #endif diff --git a/src/detect.c b/src/detect.c index 2156187c3af9..94e25a7d0252 100644 --- a/src/detect.c +++ b/src/detect.c @@ -11263,24 +11263,24 @@ static int SigTestDetectAlertCounter(void) DetectEngineThreadCtxInit(&tv, de_ctx, (void *)&det_ctx); /* init counters */ - SCPerfSetupPrivate(&tv); + StatsSetupPrivate(&tv); p = UTHBuildPacket((uint8_t *)"boo", strlen("boo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result = (SCPerfGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 1); + result = (StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 1); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); + result &= (StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"roo", strlen("roo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); + result &= (StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"laboosa", strlen("laboosa"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 3); + result &= (StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 3); UTHFreePackets(&p, 1); end: diff --git a/src/flow-manager.c b/src/flow-manager.c index c938573ad310..3739a2f87456 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -670,7 +670,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) } if (TmThreadsCheckFlag(th_v, THV_KILL)) { - SCPerfSyncCounters(th_v); + StatsSyncCounters(th_v); break; } @@ -683,7 +683,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) SCLogDebug("woke up... %s", SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY ? "emergency":""); - SCPerfSyncCountersIfSignalled(th_v); + StatsSyncCountersIfSignalled(th_v); } FlowHashDebugDeinit(); @@ -822,7 +822,7 @@ static TmEcode FlowRecycler(ThreadVars *th_v, void *thread_data) SCLogDebug("%u flows to recycle", len); if (TmThreadsCheckFlag(th_v, THV_KILL)) { - SCPerfSyncCounters(th_v); + StatsSyncCounters(th_v); break; } @@ -835,7 +835,7 @@ static TmEcode FlowRecycler(ThreadVars *th_v, void *thread_data) SCLogDebug("woke up..."); - SCPerfSyncCountersIfSignalled(th_v); + StatsSyncCountersIfSignalled(th_v); } SCLogInfo("%"PRIu64" flows processed", recycled_cnt); diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 2d3ad232525c..93fd7f0b0853 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -203,7 +203,7 @@ void RunUnittests(int list_unittests, char *regex_arg) FlowBitRegisterTests(); HostBitRegisterTests(); IPPairBitRegisterTests(); - SCPerfRegisterTests(); + StatsRegisterTests(); DecodePPPRegisterTests(); DecodeVLANRegisterTests(); HTPParserRegisterTests(); diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index a7331bb9c69c..6657d7e91d4f 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -306,7 +306,7 @@ TmEcode UnixSocketPcapFilesCheck(void *data) /* mgt and ppt threads killed, we can run non thread-safe * shutdown functions */ - SCPerfReleaseResources(); + StatsReleaseResources(); RunModeShutDown(); FlowShutdown(); IPPairShutdown(); @@ -359,7 +359,7 @@ TmEcode UnixSocketPcapFilesCheck(void *data) RunModeDispatch(RUNMODE_PCAP_FILE, NULL); FlowManagerThreadSpawn(); FlowRecyclerThreadSpawn(); - SCPerfSpawnThreads(); + StatsSpawnThreads(); /* Un-pause all the paused threads */ TmThreadContinueThreads(); } diff --git a/src/source-af-packet.c b/src/source-af-packet.c index aed38baba113..654ce00c8b6c 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1247,11 +1247,11 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) AFPSwitchState(ptv, AFP_STATE_DOWN); continue; } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } AFPDumpCounters(ptv); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); SCReturnInt(TM_ECODE_OK); } @@ -1801,8 +1801,8 @@ void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) AFPDumpCounters(ptv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, - SCPerfGetLocalCounterValue(tv, ptv->capture_kernel_packets), - SCPerfGetLocalCounterValue(tv, ptv->capture_kernel_drops)); + StatsGetLocalCounterValue(tv, ptv->capture_kernel_packets), + StatsGetLocalCounterValue(tv, ptv->capture_kernel_drops)); #endif SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index 9758b7216215..30baadcd1d74 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -379,7 +379,7 @@ ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) SCReturnInt(TM_ECODE_FAILED); } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); SCLogDebug("Read %d records from stream: %d, DAG: %s", pkts_read, dtv->dagstream, dtv->dagname); @@ -558,16 +558,16 @@ ReceiveErfDagThreadExitStats(ThreadVars *tv, void *data) ErfDagThreadVars *ewtn = (ErfDagThreadVars *)data; (void)SC_ATOMIC_SET(ewtn->livedev->pkts, - SCPerfGetLocalCounterValue(tv, ewtn->packets)); + StatsGetLocalCounterValue(tv, ewtn->packets)); (void)SC_ATOMIC_SET(ewtn->livedev->drop, - SCPerfGetLocalCounterValue(tv, ewtn->drops)); + StatsGetLocalCounterValue(tv, ewtn->drops)); SCLogInfo("Stream: %d; Bytes: %"PRIu64"; Packets: %"PRIu64 "; Drops: %"PRIu64, ewtn->dagstream, ewtn->bytes, - SCPerfGetLocalCounterValue(tv, ewtn->packets), - SCPerfGetLocalCounterValue(tv, ewtn->drops)); + StatsGetLocalCounterValue(tv, ewtn->packets), + StatsGetLocalCounterValue(tv, ewtn->drops)); } /** diff --git a/src/source-ipfw.c b/src/source-ipfw.c index 9e4fd62a5e69..1b4c1c7e9909 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -307,7 +307,7 @@ TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) SCReturnInt(TM_ECODE_FAILED); } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); diff --git a/src/source-mpipe.c b/src/source-mpipe.c index 90fc7a0ba695..54a567bc7545 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -414,7 +414,7 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) } if (update_counter-- <= 0) { /* Only periodically update and check for termination. */ - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); update_counter = 10000; if (suricata_ctl_flags != 0) { diff --git a/src/source-napatech.c b/src/source-napatech.c index 27e4f1cdda4e..e964d4e8bed2 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -294,7 +294,7 @@ TmEcode NapatechStreamLoop(ThreadVars *tv, void *data, void *slot) } NT_NetRxRelease(ntv->rx_stream, packet_buffer); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); diff --git a/src/source-netmap.c b/src/source-netmap.c index 04508e6c12fb..89fd69fea08b 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -826,11 +826,11 @@ static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) } NetmapDumpCounters(ntv); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCFree(fds); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); SCReturnInt(TM_ECODE_OK); } @@ -847,8 +847,8 @@ static void ReceiveNetmapThreadExitStats(ThreadVars *tv, void *data) NetmapDumpCounters(ntv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 ", bytes %" PRIu64 "", tv->name, - SCPerfGetLocalCounterValue(tv, ntv->capture_kernel_packets), - SCPerfGetLocalCounterValue(tv, ntv->capture_kernel_drops), + StatsGetLocalCounterValue(tv, ntv->capture_kernel_packets), + StatsGetLocalCounterValue(tv, ntv->capture_kernel_drops), ntv->bytes); } diff --git a/src/source-nflog.c b/src/source-nflog.c index 583af8545a56..865edd528218 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -461,7 +461,7 @@ TmEcode ReceiveNFLOGLoop(ThreadVars *tv, void *data, void *slot) SCLogWarning(SC_ERR_NFLOG_HANDLE_PKT, "nflog_handle_packet error %" PRId32 "", ret); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); diff --git a/src/source-nfq.c b/src/source-nfq.c index 18259afc8e9c..34a747cb3240 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -1003,7 +1003,7 @@ TmEcode ReceiveNFQLoop(ThreadVars *tv, void *data, void *slot) } NFQRecvPkt(nq, ntv); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); } diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 007f89a29993..7a857fdff468 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -248,7 +248,7 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) SCReturnInt(TM_ECODE_DONE); } } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); diff --git a/src/source-pcap.c b/src/source-pcap.c index 0a1bcaf0ed63..cb38e3f7dc64 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -340,11 +340,11 @@ TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot) SCReturnInt(TM_ECODE_FAILED); } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } PcapDumpCounters(ptv); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); SCReturnInt(TM_ECODE_OK); } diff --git a/src/source-pfring.c b/src/source-pfring.c index 2b430200b1a1..88e128622ef3 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -198,8 +198,8 @@ static inline void PfringDumpCounters(PfringThreadVars *ptv) * So to get the number of packet on the interface we can add * the newly seen packets and drops for this thread and add it * to the interface counter */ - uint64_t th_pkts = SCPerfGetLocalCounterValue(ptv->tv, ptv->capture_kernel_packets); - uint64_t th_drops = SCPerfGetLocalCounterValue(ptv->tv, ptv->capture_kernel_drops); + uint64_t th_pkts = StatsGetLocalCounterValue(ptv->tv, ptv->capture_kernel_packets); + uint64_t th_drops = StatsGetLocalCounterValue(ptv->tv, ptv->capture_kernel_drops); SC_ATOMIC_ADD(ptv->livedev->pkts, pfring_s.recv - th_pkts); SC_ATOMIC_ADD(ptv->livedev->drop, pfring_s.drop - th_drops); StatsSetUI64(ptv->tv, ptv->capture_kernel_packets, pfring_s.recv); @@ -360,7 +360,7 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(TM_ECODE_FAILED); } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } return TM_ECODE_OK; @@ -548,8 +548,8 @@ void ReceivePfringThreadExitStats(ThreadVars *tv, void *data) PfringDumpCounters(ptv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, - SCPerfGetLocalCounterValue(tv, ptv->capture_kernel_packets), - SCPerfGetLocalCounterValue(tv, ptv->capture_kernel_drops)); + StatsGetLocalCounterValue(tv, ptv->capture_kernel_packets), + StatsGetLocalCounterValue(tv, ptv->capture_kernel_drops)); SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); } diff --git a/src/suricata.c b/src/suricata.c index 8b2a82ced281..ab65ed92a30d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2337,7 +2337,7 @@ int main(int argc, char **argv) /* Spawn the flow manager thread */ FlowManagerThreadSpawn(); FlowRecyclerThreadSpawn(); - SCPerfSpawnThreads(); + StatsSpawnThreads(); } #ifdef __SC_CUDA_SUPPORT__ @@ -2452,7 +2452,7 @@ int main(int argc, char **argv) * the other threads are gone. */ PacketPoolDestroy(); - SCPerfReleaseResources(); + StatsReleaseResources(); IPPairShutdown(); FlowShutdown(); StreamTcpFreeConfig(STREAM_VERBOSE); diff --git a/src/tm-threads.c b/src/tm-threads.c index f6c2802c821b..a922a82253f2 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -322,7 +322,7 @@ void *TmThreadsSlotPktAcqLoop(void *td) } } - SCPerfSetupPrivate(tv); + StatsSetupPrivate(tv); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -343,7 +343,7 @@ void *TmThreadsSlotPktAcqLoop(void *td) run = 0; } } - SCPerfSyncCounters(tv); + StatsSyncCounters(tv); TmThreadsSetFlag(tv, THV_FLOW_LOOP); @@ -453,7 +453,7 @@ void *TmThreadsSlotVar(void *td) } } - SCPerfSetupPrivate(tv); + StatsSetupPrivate(tv); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -517,7 +517,7 @@ void *TmThreadsSlotVar(void *td) run = 0; } } /* while (run) */ - SCPerfSyncCounters(tv); + StatsSyncCounters(tv); TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); @@ -593,7 +593,7 @@ static void *TmThreadsManagement(void *td) memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - SCPerfSetupPrivate(tv); + StatsSetupPrivate(tv); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -604,7 +604,7 @@ static void *TmThreadsManagement(void *td) } if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCPerfSyncCounters(tv); + StatsSyncCounters(tv); } TmThreadsSetFlag(tv, THV_RUNNING_DONE); diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index 1ec4bec526b9..c0898ef0afcb 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -85,7 +85,7 @@ Packet *TmqhInputFlow(ThreadVars *tv) { PacketQueue *q = &trans_q[tv->inq->id]; - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); SCMutexLock(&q->mutex_q); if (q->len == 0) { diff --git a/src/tmqh-ringbuffer.c b/src/tmqh-ringbuffer.c index 95c8c08b1edf..29228e1a7430 100644 --- a/src/tmqh-ringbuffer.c +++ b/src/tmqh-ringbuffer.c @@ -104,7 +104,7 @@ Packet *TmqhInputRingBufferMrSw(ThreadVars *t) Packet *p = (Packet *)RingBufferMrSw8Get(rb); - SCPerfSyncCountersIfSignalled(t); + StatsSyncCountersIfSignalled(t); return p; } @@ -121,7 +121,7 @@ Packet *TmqhInputRingBufferSrSw(ThreadVars *t) Packet *p = (Packet *)RingBufferSrSw8Get(rb); - SCPerfSyncCountersIfSignalled(t); + StatsSyncCountersIfSignalled(t); return p; } @@ -138,7 +138,7 @@ Packet *TmqhInputRingBufferSrMw(ThreadVars *t) Packet *p = (Packet *)RingBufferSrMw8Get(rb); - SCPerfSyncCountersIfSignalled(t); + StatsSyncCountersIfSignalled(t); return p; } diff --git a/src/tmqh-simple.c b/src/tmqh-simple.c index 26aea2adc248..bc09dff340bf 100644 --- a/src/tmqh-simple.c +++ b/src/tmqh-simple.c @@ -47,7 +47,7 @@ Packet *TmqhInputSimple(ThreadVars *t) { PacketQueue *q = &trans_q[t->inq->id]; - SCPerfSyncCountersIfSignalled(t); + StatsSyncCountersIfSignalled(t); SCMutexLock(&q->mutex_q); diff --git a/src/unix-manager.c b/src/unix-manager.c index 094c2d1f8565..6228c6a5eb4d 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -868,7 +868,7 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) /* set the thread name */ SCLogDebug("%s started...", th_v->name); - SCPerfSetupPrivate(th_v); + StatsSetupPrivate(th_v); if (UnixNew(&command) == 0) { int failure_fatal = 0; @@ -897,7 +897,7 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) UnixManagerRegisterCommand("running-mode", UnixManagerRunningModeCommand, &command, 0); UnixManagerRegisterCommand("capture-mode", UnixManagerCaptureModeCommand, &command, 0); UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS); - UnixManagerRegisterCommand("dump-counters", SCPerfOutputCounterSocket, NULL, 0); + UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0); UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0); TmThreadsSetFlag(th_v, THV_INIT_DONE); @@ -914,7 +914,7 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) close(item->fd); SCFree(item); } - SCPerfSyncCounters(th_v); + StatsSyncCounters(th_v); break; } From 4c3ccda72efa6a089c733d8d0abcf05f242af1da Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 16:15:03 +0200 Subject: [PATCH 0522/2553] counters: minor header cleanup --- src/counters.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/counters.h b/src/counters.h index 95dfd6a670af..4ba866d5c6a7 100644 --- a/src/counters.h +++ b/src/counters.h @@ -44,7 +44,7 @@ typedef struct StatsCounter_ { uint64_t value; /**< sum of updates/increments, or 'set' value */ uint64_t updates; /**< number of updates (for avg) */ - /* when using type SC_PERF_TYPE_Q_FUNC this function is called once + /* when using type STATS_TYPE_Q_FUNC this function is called once * to get the counter value, regardless of how many threads there are. */ uint64_t (*Func)(void); @@ -108,26 +108,26 @@ void StatsSetupPostConfig(void); void StatsSpawnThreads(void); void StatsRegisterTests(void); +/* functions used to free the resources alloted by the Perf counter API */ +void StatsReleaseResources(void); +void StatsReleasePCA(StatsPrivateThreadContext *); + /* counter registration functions */ uint16_t StatsRegisterCounter(char *, struct ThreadVars_ *); uint16_t StatsRegisterAvgCounter(char *, struct ThreadVars_ *); uint16_t StatsRegisterMaxCounter(char *, struct ThreadVars_ *); uint16_t StatsRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)); -/* utility functions */ -int StatsUpdateCounterArray(StatsPrivateThreadContext *, StatsPublicThreadContext *); -uint64_t StatsGetLocalCounterValue(struct ThreadVars_ *, uint16_t); -int StatsSetupPrivate(struct ThreadVars_ *); - -/* functions used to free the resources alloted by the Perf counter API */ -void StatsReleaseResources(void); -void StatsReleasePCA(StatsPrivateThreadContext *); - /* functions used to update local counter values */ void StatsAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); void StatsSetUI64(struct ThreadVars_ *, uint16_t, uint64_t); void StatsIncr(struct ThreadVars_ *, uint16_t); +/* utility functions */ +int StatsUpdateCounterArray(StatsPrivateThreadContext *, StatsPublicThreadContext *); +uint64_t StatsGetLocalCounterValue(struct ThreadVars_ *, uint16_t); +int StatsSetupPrivate(struct ThreadVars_ *); + #define StatsSyncCounters(tv) \ StatsUpdateCounterArray(&(tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ From d2a9ef2680a3f0db00089594a6be8a645650f4ec Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 16:24:39 +0200 Subject: [PATCH 0523/2553] counters: rename unparsable SCPCAElem to StatsLocalCounter --- src/counters.c | 8 ++++---- src/counters.h | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/counters.c b/src/counters.c index 10521363c5b8..421f5a644002 100644 --- a/src/counters.c +++ b/src/counters.c @@ -552,7 +552,7 @@ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, * \param pcae Pointer to the StatsPrivateThreadContext which holds the local * versions of the counters */ -static void StatsCopyCounterValue(SCPCAElem *pcae) +static void StatsCopyCounterValue(StatsLocalCounter *pcae) { StatsCounter *pc = pcae->pc; @@ -1157,10 +1157,10 @@ static int StatsGetCounterArrayRange(uint16_t s_id, uint16_t e_id, return -1; } - if ( (pca->head = SCMalloc(sizeof(SCPCAElem) * (e_id - s_id + 2))) == NULL) { + if ( (pca->head = SCMalloc(sizeof(StatsLocalCounter) * (e_id - s_id + 2))) == NULL) { return -1; } - memset(pca->head, 0, sizeof(SCPCAElem) * (e_id - s_id + 2)); + memset(pca->head, 0, sizeof(StatsLocalCounter) * (e_id - s_id + 2)); pc = pctx->head; while (pc->id != s_id) @@ -1216,7 +1216,7 @@ int StatsSetupPrivate(ThreadVars *tv) */ int StatsUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadContext *pctx) { - SCPCAElem *pcae = NULL; + StatsLocalCounter *pcae = NULL; uint32_t i = 0; if (pca == NULL || pctx == NULL) { diff --git a/src/counters.h b/src/counters.h index 4ba866d5c6a7..0bf52c003001 100644 --- a/src/counters.h +++ b/src/counters.h @@ -34,10 +34,10 @@ struct ThreadVars_; typedef struct StatsCounter_ { int type; - /* local id for this counter in this tm */ + /* local id for this counter in this thread */ uint16_t id; - /* global id */ + /* global id, used in output */ uint16_t gid; /* counter value(s): copies from the 'private' counter */ @@ -56,7 +56,7 @@ typedef struct StatsCounter_ { } StatsCounter; /** - * \brief Holds the Perf Context for a ThreadVars instance + * \brief Stats Context for a ThreadVars instance */ typedef struct StatsPublicThreadContext_ { /* flag set by the wakeup thread, to inform the client threads to sync */ @@ -73,13 +73,14 @@ typedef struct StatsPublicThreadContext_ { } StatsPublicThreadContext; /** - * \brief Node elements used by the StatsPrivateThreadContext(PCA) Node + * \brief Storage for local counters, with a link to the public counter used + * for syncs */ -typedef struct SCPCAElem_ { - /* pointer to the PerfCounter that corresponds to this PCAElem */ +typedef struct StatsLocalCounter_ { + /* pointer to the counter that corresponds to this local counter */ StatsCounter *pc; - /* counter id of the above counter(pc) */ + /* local counter id of the above counter */ uint16_t id; /* total value of the adds/increments, or exact value in case of 'set' */ @@ -87,16 +88,16 @@ typedef struct SCPCAElem_ { /* no of times the local counter has been updated */ uint64_t updates; -} SCPCAElem; +} StatsLocalCounter; /** * \brief used to hold the private version of the counters registered */ typedef struct StatsPrivateThreadContext_ { - /* points to the array holding PCAElems */ - SCPCAElem *head; + /* points to the array holding local counters */ + StatsLocalCounter *head; - /* no of PCAElems in head */ + /* size of head array in elements */ uint32_t size; int initialized; @@ -110,7 +111,6 @@ void StatsRegisterTests(void); /* functions used to free the resources alloted by the Perf counter API */ void StatsReleaseResources(void); -void StatsReleasePCA(StatsPrivateThreadContext *); /* counter registration functions */ uint16_t StatsRegisterCounter(char *, struct ThreadVars_ *); From 41ead6611a427b3e3537c6efd9eb9f33ad325720 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 16:28:01 +0200 Subject: [PATCH 0524/2553] counters: minor internal API cleanups --- src/counters.c | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/counters.c b/src/counters.c index 421f5a644002..1748ddc7dd67 100644 --- a/src/counters.c +++ b/src/counters.c @@ -195,11 +195,9 @@ static ConfNode *GetConfig(void) { } /** - * \brief Initializes the output interface context - * - * \todo Support multiple interfaces + * \brief Initializes stats context */ -static void StatsInitOPCtx(void) +static void StatsInitCtx(void) { SCEnter(); ConfNode *stats = GetConfig(); @@ -237,7 +235,7 @@ static void StatsInitOPCtx(void) * \brief Releases the resources alloted to the output context of the Perf * Counter API */ -static void StatsReleaseOPCtx() +static void StatsReleaseCtx() { if (stats_ctx == NULL) { SCLogDebug("Counter module has been disabled"); @@ -461,7 +459,7 @@ static void *StatsWakeupThread(void *arg) /** * \brief Releases a perf counter. Used internally by - * StatsReleasePerfCounterS() + * StatsReleasePerfCounters() * * \param pc Pointer to the StatsCounter to be freed */ @@ -857,7 +855,7 @@ void StatsInit(void) { BUG_ON(stats_ctx != NULL); if ( (stats_ctx = SCMalloc(sizeof(StatsGlobalContext))) == NULL) { - SCLogError(SC_ERR_FATAL, "Fatal error encountered in StatsInitOPCtx. Exiting..."); + SCLogError(SC_ERR_FATAL, "Fatal error encountered in StatsInitCtx. Exiting..."); exit(EXIT_FAILURE); } memset(stats_ctx, 0, sizeof(StatsGlobalContext)); @@ -865,7 +863,7 @@ void StatsInit(void) void StatsSetupPostConfig(void) { - StatsInitOPCtx(); + StatsInitCtx(); } /** @@ -1260,7 +1258,7 @@ uint64_t StatsGetLocalCounterValue(ThreadVars *tv, uint16_t id) */ void StatsReleaseResources() { - StatsReleaseOPCtx(); + StatsReleaseCtx(); return; } @@ -1271,7 +1269,7 @@ void StatsReleaseResources() * \param head Pointer to the head of the list of perf counters that have to * be freed */ -void StatsReleasePerfCounterS(StatsCounter *head) +void StatsReleasePerfCounters(StatsCounter *head) { StatsCounter *pc = NULL; @@ -1290,7 +1288,7 @@ void StatsReleasePerfCounterS(StatsCounter *head) * * \param pca Pointer to the StatsPrivateThreadContext */ -void StatsReleasePCA(StatsPrivateThreadContext *pca) +void StatsReleasePrivateThreadContext(StatsPrivateThreadContext *pca) { if (pca != NULL) { if (pca->head != NULL) { @@ -1345,7 +1343,7 @@ static int StatsTestCounterReg03() result = RegisterCounter("t1", "c1", &pctx); - StatsReleasePerfCounterS(pctx.head); + StatsReleasePerfCounters(pctx.head); return result; } @@ -1363,7 +1361,7 @@ static int StatsTestCounterReg04() result = RegisterCounter("t1", "c1", &pctx); - StatsReleasePerfCounterS(pctx.head); + StatsReleasePerfCounters(pctx.head); return result; } @@ -1401,8 +1399,8 @@ static int StatsTestGetCntArray06() result = (r == 0) ? 1 : 0; - StatsReleasePerfCounterS(tv.perf_public_ctx.head); - StatsReleasePCA(&tv.perf_private_ctx); + StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(&tv.perf_private_ctx); return result; } @@ -1428,8 +1426,8 @@ static int StatsTestCntArraySize07() result = pca->size; - StatsReleasePerfCounterS(tv.perf_public_ctx.head); - StatsReleasePCA(pca); + StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(pca); return result; } @@ -1453,8 +1451,8 @@ static int StatsTestUpdateCounter08() result = pca->head[id].value; - StatsReleasePerfCounterS(tv.perf_public_ctx.head); - StatsReleasePCA(pca); + StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(pca); return result; } @@ -1482,8 +1480,8 @@ static int StatsTestUpdateCounter09() result = (pca->head[id1].value == 0) && (pca->head[id2].value == 101); - StatsReleasePerfCounterS(tv.perf_public_ctx.head); - StatsReleasePCA(pca); + StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(pca); return result; } @@ -1516,8 +1514,8 @@ static int StatsTestUpdateGlobalCounter10() result &= (100 == tv.perf_public_ctx.head->next->value); result &= (101 == tv.perf_public_ctx.head->next->next->value); - StatsReleasePerfCounterS(tv.perf_public_ctx.head); - StatsReleasePCA(pca); + StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(pca); return result; } @@ -1555,8 +1553,8 @@ static int StatsTestCounterValues11() result &= (16843024 == tv.perf_public_ctx.head->next->next->next->value); - StatsReleasePerfCounterS(tv.perf_public_ctx.head); - StatsReleasePCA(pca); + StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(pca); return result; } From 83f27ae2a571e5345d5146eda3b8e850d39543fd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 16:29:35 +0200 Subject: [PATCH 0525/2553] counters: remove old unix socket json logic --- src/counters.c | 92 +++----------------------------------------------- 1 file changed, 4 insertions(+), 88 deletions(-) diff --git a/src/counters.c b/src/counters.c index 1748ddc7dd67..539127b013ff 100644 --- a/src/counters.c +++ b/src/counters.c @@ -752,99 +752,15 @@ static int StatsOutput(ThreadVars *tv) #ifdef BUILD_UNIX_SOCKET /** - * \brief The file output interface for the Perf Counter api + * \todo reimplement this, probably based on stats-json */ TmEcode StatsOutputCounterSocket(json_t *cmd, json_t *answer, void *data) { - StatsThreadStore *sts = NULL; - StatsCounter *pc = NULL; - StatsCounter **pc_heads = NULL; - - uint64_t ui64_temp = 0; - uint64_t ui64_result = 0; - - uint32_t u = 0; - int flag = 0; - - if (stats_ctx == NULL) { - json_object_set_new(answer, "message", - json_string("No performance counter context")); - return TM_ECODE_FAILED; - } - - json_t *tm_array; - - tm_array = json_object(); - if (tm_array == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); - return TM_ECODE_FAILED; - } - - sts = stats_ctx->sts; - while (sts != NULL) { - json_t *jdata; - int filled = 0; - jdata = json_object(); - if (jdata == NULL) { - json_decref(tm_array); - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); - return TM_ECODE_FAILED; - } - if ((pc_heads = SCMalloc(sts->size * sizeof(StatsCounter *))) == NULL) { - json_decref(tm_array); - json_object_set_new(answer, "message", - json_string("internal memory error")); - return TM_ECODE_FAILED; - } - memset(pc_heads, 0, sts->size * sizeof(StatsCounter *)); - - for (u = 0; u < sts->size; u++) { - pc_heads[u] = sts->head[u]->head; - - SCMutexLock(&sts->head[u]->m); - } - - flag = 1; - while(flag) { - ui64_result = 0; - if (pc_heads[0] == NULL) - break; - pc = pc_heads[0]; - - for (u = 0; u < sts->size; u++) { - ui64_temp = StatsOutputCalculateCounterValue(pc_heads[u]); - ui64_result += ui64_temp; - - if (pc_heads[u] != NULL) - pc_heads[u] = pc_heads[u]->next; - if (pc_heads[u] == NULL) - flag = 0; - } - - filled = 1; - json_object_set_new(jdata, pc->cname, json_integer(ui64_result)); - } - - for (u = 0; u < sts->size; u++) - SCMutexUnlock(&sts->head[u]->m); - - if (filled == 1) { - json_object_set_new(tm_array, sts->tm_name, jdata); - } - sts = sts->next; - - SCFree(pc_heads); - - } - - json_object_set_new(answer, "message", tm_array); - - return TM_ECODE_OK; + json_object_set_new(answer, "message", + json_string("not implemented")); + return TM_ECODE_FAILED; } - #endif /* BUILD_UNIX_SOCKET */ /** From faef92f8daf09fd5134ea5556f3106b7878c741a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 16:33:51 +0200 Subject: [PATCH 0526/2553] counters: remove last and now unused tm_name reference --- src/counters.c | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/src/counters.c b/src/counters.c index 539127b013ff..cb50a33ebd5a 100644 --- a/src/counters.c +++ b/src/counters.c @@ -61,9 +61,8 @@ enum { * \brief per thread store of counters */ typedef struct StatsThreadStore_ { - char *name; - - char *tm_name; + /** thread name used in output */ + const char *name; StatsPublicThreadContext *ctx; @@ -247,9 +246,6 @@ static void StatsReleaseCtx() sts = stats_ctx->sts; while (sts != NULL) { - if (sts->tm_name != NULL) - SCFree(sts->tm_name); - if (sts->head != NULL) SCFree(sts->head); @@ -559,24 +555,6 @@ static void StatsCopyCounterValue(StatsLocalCounter *pcae) return; } -/** - * \brief Calculates counter value that should be sent as output - * - * If we aren't dealing with timebased counters, we just return the - * the counter value. In case of Timebased counters, if we haven't - * crossed the interval, we display the current value without any - * modifications. If we have crossed the limit, we calculate the counter - * value for the time period and also return 1, to indicate that the - * counter value can be reset after use - * - * \param pc Pointer to the PerfCounter for which the timebased counter has to - * be calculated - */ -static uint64_t StatsOutputCalculateCounterValue(StatsCounter *pc) -{ - return pc->value; -} - /** * \brief The output interface for the Stats API */ @@ -631,8 +609,7 @@ static int StatsOutput(ThreadVars *tv) while (sts != NULL) { BUG_ON(thread < 0); - SCLogDebug("Thread %d %s (%s) ctx %p", thread, sts->name, - sts->tm_name ? sts->tm_name : "none", sts->ctx); + SCLogDebug("Thread %d %s ctx %p", thread, sts->name, sts->ctx); /* temporay table for quickly storing the counters for this * thread store, so that we can post process them outside From f05d0692ef4e9e1ed38e68caad7512894147489e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 16:45:07 +0200 Subject: [PATCH 0527/2553] counters: remove references to 'perf' counters --- src/counters.c | 51 +++++++++++++++++++++++------------------------- src/counters.h | 2 +- src/util-error.c | 2 +- src/util-error.h | 2 +- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/counters.c b/src/counters.c index cb50a33ebd5a..997ad01ca3b2 100644 --- a/src/counters.c +++ b/src/counters.c @@ -46,7 +46,7 @@ /** * \brief Different kinds of qualifier that can be used to modify the behaviour - * of the Perf counter to be registered + * of the counter to be registered */ enum { STATS_TYPE_NORMAL = 1, @@ -231,8 +231,8 @@ static void StatsInitCtx(void) } /** - * \brief Releases the resources alloted to the output context of the Perf - * Counter API + * \brief Releases the resources alloted to the output context of the + * Stats API */ static void StatsReleaseCtx() { @@ -267,10 +267,9 @@ static void StatsReleaseCtx() } /** - * \brief The management thread. This thread is responsible for writing the - * performance stats information. + * \brief management thread. This thread is responsible for writing the stats * - * \param arg is NULL always + * \param arg thread var * * \retval NULL This is the value that is always returned */ @@ -297,7 +296,7 @@ static void *StatsMgmtThread(void *arg) SCDropCaps(tv_local); if (stats_ctx == NULL) { - SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" + SCLogError(SC_ERR_STATS_NOT_INIT, "Stats API not init" "StatsInitCounterApi() has to be called first"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); return NULL; @@ -307,7 +306,7 @@ static void *StatsMgmtThread(void *arg) BUG_ON(tm->ThreadInit == NULL); int r = tm->ThreadInit(tv_local, NULL, &stats_thread_data); if (r != 0 || stats_thread_data == NULL) { - SCLogError(SC_ERR_THREAD_INIT, "Perf Counter API " + SCLogError(SC_ERR_THREAD_INIT, "Stats API " "ThreadInit failed"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); return NULL; @@ -343,7 +342,7 @@ static void *StatsMgmtThread(void *arg) r = tm->ThreadDeinit(tv_local, stats_thread_data); if (r != TM_ECODE_OK) { - SCLogError(SC_ERR_THREAD_DEINIT, "Perf Counter API " + SCLogError(SC_ERR_THREAD_DEINIT, "Stats Counter API " "ThreadDeinit failed"); } @@ -384,7 +383,7 @@ static void *StatsWakeupThread(void *arg) SCDropCaps(tv_local); if (stats_ctx == NULL) { - SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" + SCLogError(SC_ERR_STATS_NOT_INIT, "Stats API not init" "StatsInitCounterApi() has to be called first"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); return NULL; @@ -454,8 +453,7 @@ static void *StatsWakeupThread(void *arg) } /** - * \brief Releases a perf counter. Used internally by - * StatsReleasePerfCounters() + * \brief Releases a counter * * \param pc Pointer to the StatsCounter to be freed */ @@ -472,7 +470,7 @@ static void StatsReleaseCounter(StatsCounter *pc) } /** - * \brief Registers a counter. Used internally by the Perf Counter API + * \brief Registers a counter. * * \param cname Name of the counter, to be registered * \param tm_name Thread module to which this counter belongs @@ -523,7 +521,7 @@ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, } /* assign a unique id to this StatsCounter. The id is local to this - * PerfContext. Please note that the id start from 1, and not 0 */ + * thread context. Please note that the id start from 1, and not 0 */ pc->id = ++(pctx->curr_id); pc->type = type_q; @@ -760,8 +758,7 @@ void StatsSetupPostConfig(void) } /** - * \brief Spawns the wakeup, and the management thread used by the perf - * counter api + * \brief Spawns the wakeup, and the management thread used by the stats api * * The threads use the condition variable in the thread vars to control * their wait loops to make sure the main thread can quickly kill them. @@ -1147,7 +1144,7 @@ uint64_t StatsGetLocalCounterValue(ThreadVars *tv, uint16_t id) } /** - * \brief Releases the resources alloted by the Perf Counter API + * \brief Releases the resources alloted by the Stats API */ void StatsReleaseResources() { @@ -1157,12 +1154,12 @@ void StatsReleaseResources() } /** - * \brief Releases a list of perf counters + * \brief Releases counters * * \param head Pointer to the head of the list of perf counters that have to * be freed */ -void StatsReleasePerfCounters(StatsCounter *head) +void StatsReleaseCounters(StatsCounter *head) { StatsCounter *pc = NULL; @@ -1236,7 +1233,7 @@ static int StatsTestCounterReg03() result = RegisterCounter("t1", "c1", &pctx); - StatsReleasePerfCounters(pctx.head); + StatsReleaseCounters(pctx.head); return result; } @@ -1254,7 +1251,7 @@ static int StatsTestCounterReg04() result = RegisterCounter("t1", "c1", &pctx); - StatsReleasePerfCounters(pctx.head); + StatsReleaseCounters(pctx.head); return result; } @@ -1292,7 +1289,7 @@ static int StatsTestGetCntArray06() result = (r == 0) ? 1 : 0; - StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleaseCounters(tv.perf_public_ctx.head); StatsReleasePrivateThreadContext(&tv.perf_private_ctx); return result; @@ -1319,7 +1316,7 @@ static int StatsTestCntArraySize07() result = pca->size; - StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleaseCounters(tv.perf_public_ctx.head); StatsReleasePrivateThreadContext(pca); return result; @@ -1344,7 +1341,7 @@ static int StatsTestUpdateCounter08() result = pca->head[id].value; - StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleaseCounters(tv.perf_public_ctx.head); StatsReleasePrivateThreadContext(pca); return result; @@ -1373,7 +1370,7 @@ static int StatsTestUpdateCounter09() result = (pca->head[id1].value == 0) && (pca->head[id2].value == 101); - StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleaseCounters(tv.perf_public_ctx.head); StatsReleasePrivateThreadContext(pca); return result; @@ -1407,7 +1404,7 @@ static int StatsTestUpdateGlobalCounter10() result &= (100 == tv.perf_public_ctx.head->next->value); result &= (101 == tv.perf_public_ctx.head->next->next->value); - StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleaseCounters(tv.perf_public_ctx.head); StatsReleasePrivateThreadContext(pca); return result; @@ -1446,7 +1443,7 @@ static int StatsTestCounterValues11() result &= (16843024 == tv.perf_public_ctx.head->next->next->next->value); - StatsReleasePerfCounters(tv.perf_public_ctx.head); + StatsReleaseCounters(tv.perf_public_ctx.head); StatsReleasePrivateThreadContext(pca); return result; diff --git a/src/counters.h b/src/counters.h index 0bf52c003001..01e65e3b72f2 100644 --- a/src/counters.h +++ b/src/counters.h @@ -109,7 +109,7 @@ void StatsSetupPostConfig(void); void StatsSpawnThreads(void); void StatsRegisterTests(void); -/* functions used to free the resources alloted by the Perf counter API */ +/* functions used to free the resources alloted by the Stats API */ void StatsReleaseResources(void); /* counter registration functions */ diff --git a/src/util-error.c b/src/util-error.c index 354765343f6a..fd52a4d264f0 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -264,7 +264,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_SYSCALL); CASE_CODE (SC_ERR_SYSCONF); CASE_CODE (SC_ERR_INVALID_ARGUMENTS); - CASE_CODE (SC_ERR_PERF_STATS_NOT_INIT); + CASE_CODE (SC_ERR_STATS_NOT_INIT); CASE_CODE (SC_ERR_NFQ_OPEN); CASE_CODE (SC_ERR_NFQ_MAXLEN); CASE_CODE (SC_ERR_NFQ_CREATE_QUEUE); diff --git a/src/util-error.h b/src/util-error.h index db6b462206b0..83529d0cdf10 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -80,7 +80,7 @@ typedef enum { SC_ERR_SYSCALL, SC_ERR_SYSCONF, SC_ERR_INVALID_ARGUMENTS, - SC_ERR_PERF_STATS_NOT_INIT, + SC_ERR_STATS_NOT_INIT, SC_ERR_COMPLETE_PORT_SPACE_NEGATED, SC_ERR_NO_PORTS_LEFT_AFTER_MERGE, SC_ERR_NEGATED_VALUE_IN_PORT_RANGE, From cddbb0f606a0e20eb5ca5e8bef6540f8deedd6e1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 8 Jan 2015 01:44:18 +0100 Subject: [PATCH 0528/2553] http: make http.memuse a global counter http.memcap as well. --- src/app-layer-htp-mem.c | 14 +++++++++----- src/app-layer-htp-mem.h | 4 ++-- src/app-layer-htp.c | 4 ++++ src/app-layer.c | 4 +--- src/stream-tcp-reassemble.h | 5 ----- src/stream-tcp.c | 4 +--- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/app-layer-htp-mem.c b/src/app-layer-htp-mem.c index f024ef9aa496..c4f94e826ee7 100644 --- a/src/app-layer-htp-mem.c +++ b/src/app-layer-htp-mem.c @@ -78,14 +78,18 @@ void HTPDecrMemuse(uint64_t size) return; } -void HTPMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *trt) +uint64_t HTPMemuseGlobalCounter(void) { uint64_t tmpval = SC_ATOMIC_GET(htp_memuse); - StatsSetUI64(tv, trt->counter_htp_memuse, tmpval); - tmpval = SC_ATOMIC_GET(htp_memcap); - StatsSetUI64(tv, trt->counter_htp_memcap, tmpval); - return; + return tmpval; } + +uint64_t HTPMemcapGlobalCounter(void) +{ + uint64_t tmpval = SC_ATOMIC_GET(htp_memcap); + return tmpval; +} + /** * \brief Check if alloc'ing "size" would mean we're over memcap * diff --git a/src/app-layer-htp-mem.h b/src/app-layer-htp-mem.h index 54b21f5d27d5..44b50f5c0848 100644 --- a/src/app-layer-htp-mem.h +++ b/src/app-layer-htp-mem.h @@ -22,5 +22,5 @@ void *HTPMalloc(size_t size); void *HTPRealloc(void *ptr, size_t orig_size, size_t size); void HTPFree(void *ptr, size_t size); - -void HTPMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *trt); +uint64_t HTPMemuseGlobalCounter(void); +uint64_t HTPMemcapGlobalCounter(void); diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 2ded474ed99a..fc8c564ced80 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -38,6 +38,7 @@ #include "debug.h" #include "decode.h" #include "threads.h" +#include "counters.h" #include "util-print.h" #include "util-pool.h" @@ -2546,6 +2547,9 @@ void HTPConfigure(void) HTPConfigSetDefaultsPhase2(s->name, htprec); } + StatsRegisterGlobalCounter("http.memuse", HTPMemuseGlobalCounter); + StatsRegisterGlobalCounter("http.memcap", HTPMemcapGlobalCounter); + SCReturn; } diff --git a/src/app-layer.c b/src/app-layer.c index bc6e986adb44..5cb18e1c38ae 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -435,9 +435,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } /** \fixme a bit hacky but will be improved in 2.1 */ - if (*alproto == ALPROTO_HTTP) - HTPMemuseCounter(tv, ra_ctx); - else if (*alproto == ALPROTO_DNS) + if (*alproto == ALPROTO_DNS) DNSUpdateCounters(tv, app_tctx); goto end; failure: diff --git a/src/stream-tcp-reassemble.h b/src/stream-tcp-reassemble.h index c5e926fc9c91..b6e798ce0be6 100644 --- a/src/stream-tcp-reassemble.h +++ b/src/stream-tcp-reassemble.h @@ -59,11 +59,6 @@ typedef struct TcpReassemblyThreadCtx_ { uint16_t counter_tcp_stream_depth; /** count number of streams with a unrecoverable stream gap (missing pkts) */ uint16_t counter_tcp_reass_gap; - /** account memory usage by suricata to handle HTTP protocol (not counting - * libhtp memory usage)*/ - uint16_t counter_htp_memuse; - /* number of allocation failed due to memcap when handling HTTP protocol */ - uint16_t counter_htp_memcap; #ifdef DEBUG uint64_t fp1; uint64_t fp2; diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 6e08f8195872..d5f90c8fbb60 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -65,6 +65,7 @@ #include "app-layer.h" #include "app-layer-parser.h" #include "app-layer-protos.h" +#include "app-layer-htp-mem.h" #include "util-host-os-info.h" #include "util-privs.h" @@ -5092,9 +5093,6 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) stt->ra_ctx->counter_tcp_segment_memcap = StatsRegisterCounter("tcp.segment_memcap_drop", tv); stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv); stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv); - /** \fixme Find a better place in 2.1 as it is linked with app layer */ - stt->ra_ctx->counter_htp_memuse = StatsRegisterCounter("http.memuse", tv); - stt->ra_ctx->counter_htp_memcap = StatsRegisterCounter("http.memcap", tv); SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p", stt, stt->ra_ctx); From ac069c579ade91f9380c7bbe2c626f5aa0f4e169 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 19:16:23 +0200 Subject: [PATCH 0529/2553] counters: make tcp.memuse a global counter --- src/stream-tcp.c | 8 +++----- src/stream-tcp.h | 2 -- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index d5f90c8fbb60..9f2fbefd620b 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -146,11 +146,10 @@ void StreamTcpDecrMemuse(uint64_t size) return; } -void StreamTcpMemuseCounter(ThreadVars *tv, StreamTcpThread *stt) +uint64_t StreamTcpMemuseCounter(void) { uint64_t memusecopy = SC_ATOMIC_GET(st_memuse); - StatsSetUI64(tv, stt->counter_tcp_memuse, memusecopy); - return; + return memusecopy; } /** @@ -593,6 +592,7 @@ void StreamTcpInitConfig(char quiet) /* init the memcap/use tracking */ SC_ATOMIC_INIT(st_memuse); + StatsRegisterGlobalCounter("tcp.memuse", StreamTcpMemuseCounter); StreamTcpReassembleInit(quiet); @@ -4654,7 +4654,6 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, } } - StreamTcpMemuseCounter(tv, stt); SCReturnInt(0); error: @@ -5080,7 +5079,6 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) stt->counter_tcp_pseudo_failed = StatsRegisterCounter("tcp.pseudo_failed", tv); stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", tv); stt->counter_tcp_no_flow = StatsRegisterCounter("tcp.no_flow", tv); - stt->counter_tcp_memuse = StatsRegisterCounter("tcp.memuse", tv); stt->counter_tcp_syn = StatsRegisterCounter("tcp.syn", tv); stt->counter_tcp_synack = StatsRegisterCounter("tcp.synack", tv); stt->counter_tcp_rst = StatsRegisterCounter("tcp.rst", tv); diff --git a/src/stream-tcp.h b/src/stream-tcp.h index dcafe0e9bcc7..f7c3ab108b2c 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -100,8 +100,6 @@ typedef struct StreamTcpThread_ { uint16_t counter_tcp_no_flow; /** sessions reused */ uint16_t counter_tcp_reused_ssn; - /** sessions reused */ - uint16_t counter_tcp_memuse; /** syn pkts */ uint16_t counter_tcp_syn; /** syn/ack pkts */ From 0a262acdfb00af0e8e1fa877c17dfa899b637b5d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 19:36:59 +0200 Subject: [PATCH 0530/2553] counters: make DNS counters globals --- src/app-layer-dns-common.c | 20 +++++++++++++++----- src/app-layer-dns-common.h | 5 +++-- src/app-layer-dns-udp.c | 4 ++++ src/app-layer.c | 31 ------------------------------- 4 files changed, 22 insertions(+), 38 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index b7d404254422..a11daa1eb026 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -103,12 +103,22 @@ int DNSCheckMemcap(uint32_t want, DNSState *state) return 0; } -void DNSMemcapGetCounters(uint64_t *memuse, uint64_t *memcap_state, - uint64_t *memcap_global) +uint64_t DNSMemcapGetMemuseCounter(void) { - *memuse = SC_ATOMIC_GET(dns_memuse); - *memcap_state = SC_ATOMIC_GET(dns_memcap_state); - *memcap_global = SC_ATOMIC_GET(dns_memcap_global); + uint64_t x = SC_ATOMIC_GET(dns_memuse); + return x; +} + +uint64_t DNSMemcapGetMemcapStateCounter(void) +{ + uint64_t x = SC_ATOMIC_GET(dns_memcap_state); + return x; +} + +uint64_t DNSMemcapGetMemcapGlobalCounter(void) +{ + uint64_t x = SC_ATOMIC_GET(dns_memcap_global); + return x; } SCEnumCharMap dns_decoder_event_table[ ] = { diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index 203b2908e6d5..c19795268a4b 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -206,8 +206,9 @@ void DNSConfigSetGlobalMemcap(uint64_t value); void DNSIncrMemcap(uint32_t size, DNSState *state); void DNSDecrMemcap(uint32_t size, DNSState *state); int DNSCheckMemcap(uint32_t want, DNSState *state); -void DNSMemcapGetCounters(uint64_t *memuse, uint64_t *memcap_state, - uint64_t *memcap_global); +uint64_t DNSMemcapGetMemuseCounter(void); +uint64_t DNSMemcapGetMemcapStateCounter(void); +uint64_t DNSMemcapGetMemcapGlobalCounter(void); void RegisterDNSParsers(void); void DNSParserTests(void); diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index eb87849c5211..3e533ba75ff2 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -358,6 +358,10 @@ void RegisterDNSUDPParsers(void) { char *proto_name = "dns"; + StatsRegisterGlobalCounter("dns.memuse", DNSMemcapGetMemuseCounter); + StatsRegisterGlobalCounter("dns.memcap_state", DNSMemcapGetMemcapStateCounter); + StatsRegisterGlobalCounter("dns.memcap_global", DNSMemcapGetMemcapGlobalCounter); + /** DNS */ if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) { AppLayerProtoDetectRegisterProtocol(ALPROTO_DNS, proto_name); diff --git a/src/app-layer.c b/src/app-layer.c index 5cb18e1c38ae..0e6818fd0006 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -55,10 +55,6 @@ struct AppLayerThreadCtx_ { /* App layer parser thread context, from AppLayerParserThreadCtxAlloc(). */ AppLayerParserThreadCtx *alp_tctx; - uint16_t counter_dns_memuse; - uint16_t counter_dns_memcap_state; - uint16_t counter_dns_memcap_global; - #ifdef PROFILING uint64_t ticks_start; uint64_t ticks_end; @@ -70,19 +66,6 @@ struct AppLayerThreadCtx_ { #endif }; -/** \todo move this into the DNS code. Problem is that there we can't - * access AppLayerThreadCtx internals. */ -static void DNSUpdateCounters(ThreadVars *tv, AppLayerThreadCtx *app_tctx) -{ - uint64_t memuse = 0, memcap_state = 0, memcap_global = 0; - - DNSMemcapGetCounters(&memuse, &memcap_state, &memcap_global); - - StatsSetUI64(tv, app_tctx->counter_dns_memuse, memuse); - StatsSetUI64(tv, app_tctx->counter_dns_memcap_state, memcap_state); - StatsSetUI64(tv, app_tctx->counter_dns_memcap_global, memcap_global); -} - /***** L7 layer dispatchers *****/ static void DisableAppLayer(Flow *f) @@ -434,9 +417,6 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } } - /** \fixme a bit hacky but will be improved in 2.1 */ - if (*alproto == ALPROTO_DNS) - DNSUpdateCounters(tv, app_tctx); goto end; failure: r = -1; @@ -461,7 +441,6 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * SCEnter(); int r = 0; - AppProto alproto; FLOWLOCK_WRLOCK(f); @@ -516,13 +495,10 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * "for l7"); } } - alproto = f->alproto; FLOWLOCK_UNLOCK(f); PACKET_PROFILING_APP_STORE(tctx, p); - if (alproto == ALPROTO_DNS) - DNSUpdateCounters(tv, tctx); SCReturnInt(r); } @@ -599,13 +575,6 @@ AppLayerThreadCtx *AppLayerGetCtxThread(ThreadVars *tv) if ((app_tctx->alp_tctx = AppLayerParserThreadCtxAlloc()) == NULL) goto error; - /* tv is allowed to be NULL in unittests */ - if (tv != NULL) { - app_tctx->counter_dns_memuse = StatsRegisterCounter("dns.memuse", tv); - app_tctx->counter_dns_memcap_state = StatsRegisterCounter("dns.memcap_state", tv); - app_tctx->counter_dns_memcap_global = StatsRegisterCounter("dns.memcap_global", tv); - } - goto done; error: AppLayerDestroyCtxThread(app_tctx); From 84b8829cb4073a1c202501b5abc7840f395e64cc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 26 May 2015 19:44:01 +0200 Subject: [PATCH 0531/2553] counters: turn flow.memuse into a global counter --- src/flow-manager.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 3739a2f87456..2d86b81c6a36 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -489,7 +489,6 @@ typedef struct FlowManagerThreadData_ { uint16_t flow_mgr_cnt_clo; uint16_t flow_mgr_cnt_new; uint16_t flow_mgr_cnt_est; - uint16_t flow_mgr_memuse; uint16_t flow_mgr_spare; uint16_t flow_emerg_mode_enter; uint16_t flow_emerg_mode_over; @@ -527,7 +526,6 @@ static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) ftd->flow_mgr_cnt_clo = StatsRegisterCounter("flow_mgr.closed_pruned", t); ftd->flow_mgr_cnt_new = StatsRegisterCounter("flow_mgr.new_pruned", t); ftd->flow_mgr_cnt_est = StatsRegisterCounter("flow_mgr.est_pruned", t); - ftd->flow_mgr_memuse = StatsRegisterCounter("flow.memuse", t); ftd->flow_mgr_spare = StatsRegisterCounter("flow.spare", t); ftd->flow_emerg_mode_enter = StatsRegisterCounter("flow.emerg_mode_entered", t); ftd->flow_emerg_mode_over = StatsRegisterCounter("flow.emerg_mode_over", t); @@ -630,8 +628,6 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) StatsAddUI64(th_v, ftd->flow_mgr_cnt_clo, (uint64_t)counters.clo); StatsAddUI64(th_v, ftd->flow_mgr_cnt_new, (uint64_t)counters.new); StatsAddUI64(th_v, ftd->flow_mgr_cnt_est, (uint64_t)counters.est); - long long unsigned int flow_memuse = SC_ATOMIC_GET(flow_memuse); - StatsSetUI64(th_v, ftd->flow_mgr_memuse, (uint64_t)flow_memuse); StatsAddUI64(th_v, ftd->flow_tcp_reuse, (uint64_t)counters.tcp_reuse); uint32_t len = 0; @@ -695,6 +691,12 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) return TM_ECODE_OK; } +static uint64_t FlowGetMemuse(void) +{ + uint64_t flow_memuse = SC_ATOMIC_GET(flow_memuse); + return flow_memuse; +} + /** \brief spawn the flow manager thread */ void FlowManagerThreadSpawn() { @@ -712,6 +714,8 @@ void FlowManagerThreadSpawn() SCCtrlCondInit(&flow_manager_ctrl_cond, NULL); SCCtrlMutexInit(&flow_manager_ctrl_mutex, NULL); + StatsRegisterGlobalCounter("flow.memuse", FlowGetMemuse); + uint32_t u; for (u = 0; u < flowmgr_number; u++) { ThreadVars *tv_flowmgr = NULL; From 81548ae3e804347f1c39b6f7e56738906ac53f64 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 27 May 2015 09:28:24 +0200 Subject: [PATCH 0532/2553] counters: clean up global context --- src/counters.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/counters.c b/src/counters.c index 997ad01ca3b2..a50160e2b88d 100644 --- a/src/counters.c +++ b/src/counters.c @@ -96,6 +96,7 @@ static char stats_enabled = TRUE; static int StatsOutput(ThreadVars *tv); static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext *); +void StatsReleaseCounters(StatsCounter *head); /** stats table is filled each interval and passed to the * loggers. Initialized at first use. */ @@ -103,6 +104,20 @@ static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}}; static uint16_t counters_global_id = 0; +void StatsPublicThreadContextInit(StatsPublicThreadContext *t) +{ + SCMutexInit(&t->m, NULL); +} + +void StatsPublicThreadContextCleanup(StatsPublicThreadContext *t) +{ + SCMutexLock(&t->m); + StatsReleaseCounters(t->head); + SCMutexUnlock(&t->m); + + SCMutexDestroy(&t->m); +} + /** * \brief Adds a value of type uint64_t to the local counter. * @@ -254,14 +269,26 @@ static void StatsReleaseCtx() sts = temp; } + if (stats_ctx->counters_id_hash != NULL) { + HashTableFree(stats_ctx->counters_id_hash); + stats_ctx->counters_id_hash = NULL; + } + + StatsPublicThreadContextCleanup(&stats_ctx->global_counter_ctx); SCFree(stats_ctx); stats_ctx = NULL; /* free stats table */ + if (stats_table.tstats != NULL) { + SCFree(stats_table.tstats); + stats_table.tstats = NULL; + } + if (stats_table.stats != NULL) { SCFree(stats_table.stats); - memset(&stats_table, 0, sizeof(stats_table)); + stats_table.stats = NULL; } + memset(&stats_table, 0, sizeof(stats_table)); return; } @@ -750,6 +777,8 @@ void StatsInit(void) exit(EXIT_FAILURE); } memset(stats_ctx, 0, sizeof(StatsGlobalContext)); + + StatsPublicThreadContextInit(&stats_ctx->global_counter_ctx); } void StatsSetupPostConfig(void) From e48153c6b0fb95e6cab8ff652a8211d54418c326 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 27 May 2015 11:23:19 +0200 Subject: [PATCH 0533/2553] counters: make threads cleanup all memory --- src/counters.c | 23 +++++++++++++---------- src/counters.h | 1 + src/tm-threads.c | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/counters.c b/src/counters.c index a50160e2b88d..08f6329a2910 100644 --- a/src/counters.c +++ b/src/counters.c @@ -104,17 +104,19 @@ static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}}; static uint16_t counters_global_id = 0; -void StatsPublicThreadContextInit(StatsPublicThreadContext *t) +static void StatsPublicThreadContextInit(StatsPublicThreadContext *t) { SCMutexInit(&t->m, NULL); } -void StatsPublicThreadContextCleanup(StatsPublicThreadContext *t) +static void StatsPublicThreadContextCleanup(StatsPublicThreadContext *t) { SCMutexLock(&t->m); StatsReleaseCounters(t->head); + t->head = NULL; + t->perf_flag = 0; + t->curr_id = 0; SCMutexUnlock(&t->m); - SCMutexDestroy(&t->m); } @@ -1026,13 +1028,7 @@ static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext memset(temp, 0, sizeof(StatsThreadStore)); temp->ctx = pctx; - - temp->name = SCStrdup(thread_name); - if (unlikely(temp->name == NULL)) { - SCFree(temp); - SCMutexUnlock(&stats_ctx->sts_lock); - return 0; - } + temp->name = thread_name; temp->next = stats_ctx->sts; stats_ctx->sts = temp; @@ -1213,6 +1209,7 @@ void StatsReleasePrivateThreadContext(StatsPrivateThreadContext *pca) if (pca->head != NULL) { SCFree(pca->head); pca->head = NULL; + pca->size = 0; } pca->initialized = 0; } @@ -1220,6 +1217,12 @@ void StatsReleasePrivateThreadContext(StatsPrivateThreadContext *pca) return; } +void StatsThreadCleanup(ThreadVars *tv) +{ + StatsPublicThreadContextCleanup(&tv->perf_public_ctx); + StatsReleasePrivateThreadContext(&tv->perf_private_ctx); +} + /*----------------------------------Unit_Tests--------------------------------*/ #ifdef UNITTESTS diff --git a/src/counters.h b/src/counters.h index 01e65e3b72f2..229e6c9f24c2 100644 --- a/src/counters.h +++ b/src/counters.h @@ -127,6 +127,7 @@ void StatsIncr(struct ThreadVars_ *, uint16_t); int StatsUpdateCounterArray(StatsPrivateThreadContext *, StatsPublicThreadContext *); uint64_t StatsGetLocalCounterValue(struct ThreadVars_ *, uint16_t); int StatsSetupPrivate(struct ThreadVars_ *); +void StatsThreadCleanup(struct ThreadVars_ *); #define StatsSyncCounters(tv) \ StatsUpdateCounterArray(&(tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ diff --git a/src/tm-threads.c b/src/tm-threads.c index a922a82253f2..f0f8a3cf0a92 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1647,7 +1647,7 @@ void TmThreadFree(ThreadVars *tv) SCLogDebug("Freeing thread '%s'.", tv->name); - SCMutexDestroy(&tv->perf_public_ctx.m); + StatsThreadCleanup(tv); s = (TmSlot *)tv->tm_slots; while (s) { From cb5aa8f8d5e2c348687c4756218f98b3400a76b6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 27 May 2015 11:33:41 +0200 Subject: [PATCH 0534/2553] counters: work around unix-socket init issues --- src/app-layer-dns-udp.c | 4 ---- src/app-layer-htp.c | 3 --- src/app-layer.c | 11 +++++++++++ src/app-layer.h | 1 + src/runmode-unix-socket.c | 2 ++ src/suricata.c | 5 ++++- 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index 3e533ba75ff2..eb87849c5211 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -358,10 +358,6 @@ void RegisterDNSUDPParsers(void) { char *proto_name = "dns"; - StatsRegisterGlobalCounter("dns.memuse", DNSMemcapGetMemuseCounter); - StatsRegisterGlobalCounter("dns.memcap_state", DNSMemcapGetMemcapStateCounter); - StatsRegisterGlobalCounter("dns.memcap_global", DNSMemcapGetMemcapGlobalCounter); - /** DNS */ if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) { AppLayerProtoDetectRegisterProtocol(ALPROTO_DNS, proto_name); diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index fc8c564ced80..dd4797572e9f 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2547,9 +2547,6 @@ void HTPConfigure(void) HTPConfigSetDefaultsPhase2(s->name, htprec); } - StatsRegisterGlobalCounter("http.memuse", HTPMemuseGlobalCounter); - StatsRegisterGlobalCounter("http.memcap", HTPMemcapGlobalCounter); - SCReturn; } diff --git a/src/app-layer.c b/src/app-layer.c index 0e6818fd0006..c47c2dd6624a 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -609,6 +609,17 @@ void AppLayerProfilingStoreInternal(AppLayerThreadCtx *app_tctx, Packet *p) PACKET_PROFILING_APP_STORE(app_tctx, p); } +/** \brief HACK to work around our broken unix manager (re)init loop + */ +void AppLayerRegisterGlobalCounters(void) +{ + StatsRegisterGlobalCounter("dns.memuse", DNSMemcapGetMemuseCounter); + StatsRegisterGlobalCounter("dns.memcap_state", DNSMemcapGetMemcapStateCounter); + StatsRegisterGlobalCounter("dns.memcap_global", DNSMemcapGetMemcapGlobalCounter); + StatsRegisterGlobalCounter("http.memuse", HTPMemuseGlobalCounter); + StatsRegisterGlobalCounter("http.memcap", HTPMemcapGlobalCounter); +} + /***** Unittests *****/ #ifdef UNITTESTS diff --git a/src/app-layer.h b/src/app-layer.h index ca221d2dc1d8..f45afe6798c7 100644 --- a/src/app-layer.h +++ b/src/app-layer.h @@ -130,6 +130,7 @@ static inline void AppLayerProfilingStore(AppLayerThreadCtx *app_tctx, Packet *p #endif } +void AppLayerRegisterGlobalCounters(void); /***** Unittests *****/ diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 6657d7e91d4f..bc7f24cc70dc 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -37,6 +37,7 @@ #include "host.h" #include "defrag.h" #include "ippair.h" +#include "app-layer.h" #include "util-profiling.h" @@ -354,6 +355,7 @@ TmEcode UnixSocketPcapFilesCheck(void *data) FlowInitConfig(FLOW_QUIET); IPPairInitConfig(FLOW_QUIET); StreamTcpInitConfig(STREAM_VERBOSE); + AppLayerRegisterGlobalCounters(); RunModeInitializeOutputs(); StatsSetupPostConfig(); RunModeDispatch(RUNMODE_PCAP_FILE, NULL); diff --git a/src/suricata.c b/src/suricata.c index ab65ed92a30d..4b88b7b12ab0 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2206,7 +2206,9 @@ int main(int argc, char **argv) GlobalInits(); TimeInit(); SupportFastPatternForSigMatchTypes(); - StatsInit(); + if (suri.run_mode != RUNMODE_UNIX_SOCKET) { + StatsInit(); + } if (conf_filename == NULL) conf_filename = DEFAULT_CONF_FILE; @@ -2256,6 +2258,7 @@ int main(int argc, char **argv) FlowInitConfig(FLOW_VERBOSE); StreamTcpInitConfig(STREAM_VERBOSE); IPPairInitConfig(IPPAIR_VERBOSE); + AppLayerRegisterGlobalCounters(); } if (MagicInit() != 0) From 7e66c7050711f0fe423b3ef7399a3526e9ae99fb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 27 May 2015 14:11:57 +0200 Subject: [PATCH 0535/2553] counters: don't run if no counters have been registered --- src/counters.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/counters.c b/src/counters.c index 08f6329a2910..7fa1045d2284 100644 --- a/src/counters.c +++ b/src/counters.c @@ -591,6 +591,9 @@ static int StatsOutput(ThreadVars *tv) const StatsCounter *pc = NULL; void *td = stats_thread_data; + if (counters_global_id == 0) + return -1; + if (stats_table.nstats == 0) { StatsThreadRegister("Global", &stats_ctx->global_counter_ctx); From 07efec550dd249f3c4a1a1fb926cbbe4298245cc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 27 May 2015 14:29:54 +0200 Subject: [PATCH 0536/2553] counters: use ptr to name instead of copy All counters have hardcoded names, so copies are not needed. --- src/counters.c | 58 ++++++++++++++++++++++---------------------------- src/counters.h | 2 +- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/src/counters.c b/src/counters.c index 7fa1045d2284..e863337d9c11 100644 --- a/src/counters.c +++ b/src/counters.c @@ -489,9 +489,6 @@ static void *StatsWakeupThread(void *arg) static void StatsReleaseCounter(StatsCounter *pc) { if (pc != NULL) { - if (pc->cname != NULL) - SCFree(pc->cname); - SCFree(pc); } @@ -501,7 +498,7 @@ static void StatsReleaseCounter(StatsCounter *pc) /** * \brief Registers a counter. * - * \param cname Name of the counter, to be registered + * \param name Name of the counter, to be registered * \param tm_name Thread module to which this counter belongs * \param pctx StatsPublicThreadContext for this tm-tv instance * \param type_q Qualifier describing the type of counter to be registered @@ -510,7 +507,7 @@ static void StatsReleaseCounter(StatsCounter *pc) * present counter on success * \retval 0 on failure */ -static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, +static uint16_t StatsRegisterQualifiedCounter(char *name, char *tm_name, StatsPublicThreadContext *pctx, int type_q, uint64_t (*Func)(void)) { @@ -519,7 +516,7 @@ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, StatsCounter *prev = NULL; StatsCounter *pc = NULL; - if (cname == NULL || pctx == NULL) { + if (name == NULL || pctx == NULL) { SCLogDebug("Counter name, StatsPublicThreadContext NULL"); return 0; } @@ -528,7 +525,7 @@ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, while (temp != NULL) { prev = temp; - if (strcmp(cname, temp->cname) == 0) { + if (strcmp(name, temp->name) == 0) { break; } @@ -539,20 +536,15 @@ static uint16_t StatsRegisterQualifiedCounter(char *cname, char *tm_name, if (temp != NULL) return(temp->id); - /* if we reach this point we don't have a counter registered by this cname */ + /* if we reach this point we don't have a counter registered by this name */ if ( (pc = SCMalloc(sizeof(StatsCounter))) == NULL) return 0; memset(pc, 0, sizeof(StatsCounter)); - if ( (pc->cname = SCStrdup(cname)) == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - /* assign a unique id to this StatsCounter. The id is local to this * thread context. Please note that the id start from 1, and not 0 */ pc->id = ++(pctx->curr_id); - + pc->name = name; pc->type = type_q; pc->Func = Func; @@ -652,7 +644,7 @@ static int StatsOutput(ThreadVars *tv) pc = sts->ctx->head; while (pc != NULL) { SCLogDebug("Counter %s (%u:%u) value %"PRIu64, - pc->cname, pc->id, pc->gid, pc->value); + pc->name, pc->id, pc->gid, pc->value); thread_table[pc->gid].type = pc->type; switch (pc->type) { @@ -666,7 +658,7 @@ static int StatsOutput(ThreadVars *tv) break; } thread_table[pc->gid].updates = pc->updates; - table[pc->gid].name = pc->cname; + table[pc->gid].name = pc->name; pc = pc->next; } @@ -844,16 +836,16 @@ void StatsSpawnThreads(void) /** * \brief Registers a normal, unqualified counter * - * \param cname Name of the counter, to be registered + * \param name Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered * * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t StatsRegisterCounter(char *cname, struct ThreadVars_ *tv) +uint16_t StatsRegisterCounter(char *name, struct ThreadVars_ *tv) { - uint16_t id = StatsRegisterQualifiedCounter(cname, + uint16_t id = StatsRegisterQualifiedCounter(name, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->perf_public_ctx, STATS_TYPE_NORMAL, NULL); @@ -865,16 +857,16 @@ uint16_t StatsRegisterCounter(char *cname, struct ThreadVars_ *tv) * \brief Registers a counter, whose value holds the average of all the values * assigned to it. * - * \param cname Name of the counter, to be registered + * \param name Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered * * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t StatsRegisterAvgCounter(char *cname, struct ThreadVars_ *tv) +uint16_t StatsRegisterAvgCounter(char *name, struct ThreadVars_ *tv) { - uint16_t id = StatsRegisterQualifiedCounter(cname, + uint16_t id = StatsRegisterQualifiedCounter(name, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->perf_public_ctx, STATS_TYPE_AVERAGE, NULL); @@ -886,16 +878,16 @@ uint16_t StatsRegisterAvgCounter(char *cname, struct ThreadVars_ *tv) * \brief Registers a counter, whose value holds the maximum of all the values * assigned to it. * - * \param cname Name of the counter, to be registered + * \param name Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered * * \retval the counter id for the newly registered counter, or the already * present counter */ -uint16_t StatsRegisterMaxCounter(char *cname, struct ThreadVars_ *tv) +uint16_t StatsRegisterMaxCounter(char *name, struct ThreadVars_ *tv) { - uint16_t id = StatsRegisterQualifiedCounter(cname, + uint16_t id = StatsRegisterQualifiedCounter(name, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->perf_public_ctx, STATS_TYPE_MAXIMUM, NULL); @@ -906,13 +898,13 @@ uint16_t StatsRegisterMaxCounter(char *cname, struct ThreadVars_ *tv) /** * \brief Registers a counter, which represents a global value * - * \param cname Name of the counter, to be registered + * \param name Name of the counter, to be registered * \param Func Function Pointer returning a uint64_t * * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t StatsRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)) +uint16_t StatsRegisterGlobalCounter(char *name, uint64_t (*Func)(void)) { #ifdef UNITTESTS if (stats_ctx == NULL) @@ -920,7 +912,7 @@ uint16_t StatsRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)) #else BUG_ON(stats_ctx == NULL); #endif - uint16_t id = StatsRegisterQualifiedCounter(cname, NULL, + uint16_t id = StatsRegisterQualifiedCounter(name, NULL, &(stats_ctx->global_counter_ctx), STATS_TYPE_FUNC, Func); @@ -1010,13 +1002,13 @@ static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext } StatsCounter *pc = pctx->head; while (pc != NULL) { - CountersIdType t = { 0, pc->cname }, *id = NULL; + CountersIdType t = { 0, pc->name }, *id = NULL; id = HashTableLookup(stats_ctx->counters_id_hash, &t, sizeof(t)); if (id == NULL) { id = SCCalloc(1, sizeof(*id)); BUG_ON(id == NULL); id->id = counters_global_id++; - id->string = pc->cname; + id->string = pc->name; BUG_ON(HashTableAdd(stats_ctx->counters_id_hash, id, sizeof(*id)) < 0); } pc->gid = id->id; @@ -1232,7 +1224,7 @@ void StatsThreadCleanup(ThreadVars *tv) /** \internal * \brief Registers a normal, unqualified counter * - * \param cname Name of the counter, to be registered + * \param name Name of the counter, to be registered * \param tm_name Name of the engine module under which the counter has to be * registered * \param type Datatype of this counter variable @@ -1242,10 +1234,10 @@ void StatsThreadCleanup(ThreadVars *tv) * \retval id Counter id for the newly registered counter, or the already * present counter */ -static uint16_t RegisterCounter(char *cname, char *tm_name, +static uint16_t RegisterCounter(char *name, char *tm_name, StatsPublicThreadContext *pctx) { - uint16_t id = StatsRegisterQualifiedCounter(cname, tm_name, pctx, + uint16_t id = StatsRegisterQualifiedCounter(name, tm_name, pctx, STATS_TYPE_NORMAL, NULL); return id; } diff --git a/src/counters.h b/src/counters.h index 229e6c9f24c2..023d15aac738 100644 --- a/src/counters.h +++ b/src/counters.h @@ -49,7 +49,7 @@ typedef struct StatsCounter_ { uint64_t (*Func)(void); /* name of the counter */ - char *cname; + const char *name; /* the next perfcounter for this tv's tm instance */ struct StatsCounter_ *next; From 0a4fd39f9c95588a4e9fe9d05dba2d1349bcc71a Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Wed, 27 May 2015 17:00:35 +0200 Subject: [PATCH 0537/2553] modbus: fix heap-buffer-overflow in Modbus parser Modbus parser does not check length to extract/read data (read or write address, quantity of data, etc.) that should be present. In case of malformated data (invalid length in header), Modbus parser reads data over the input data length. Add check before extracting/reading data from input buffer to avoid head buffer overflow. --- src/app-layer-modbus.c | 356 ++++++++++++++++++++++++++----------- src/detect-engine-modbus.c | 2 +- 2 files changed, 249 insertions(+), 109 deletions(-) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 93b834b4b3d2..16ab40d0b0dc 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -383,33 +383,49 @@ void ModbusStateTxFree(void *state, uint64_t tx_id) { /** \internal * \brief Extract 8bits data from pointer the received input data * - * \param res Pointer to the result - * \param input Pointer the received input data - * \param offset Offset of the received input data pointer + * \param res Pointer to the result + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer */ -static void ModbusExtractUint8(uint8_t *res, - uint8_t *input, - uint16_t *offset) { +static int ModbusExtractUint8(ModbusState *modbus, + uint8_t *res, + uint8_t *input, + uint32_t input_len, + uint16_t *offset) { SCEnter(); + if (input_len < (uint32_t) (*offset + sizeof(uint8_t))) { + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_LENGTH); + SCReturnInt(-1); + } + *res = *(input + *offset); *offset += sizeof(uint8_t); - SCReturn; + SCReturnInt(0); } /** \internal * \brief Extract 16bits data from pointer the received input data * - * \param res Pointer to the result - * \param input Pointer the received input data - * \param offset Offset of the received input data pointer + * \param res Pointer to the result + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer */ -static void ModbusExtractUint16(uint16_t *res, - uint8_t *input, - uint16_t *offset) { +static int ModbusExtractUint16(ModbusState *modbus, + uint16_t *res, + uint8_t *input, + uint32_t input_len, + uint16_t *offset) { SCEnter(); + if (input_len < (uint32_t) (*offset + sizeof(uint16_t))) { + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_LENGTH); + SCReturnInt(-1); + } + ByteExtractUint16(res, BYTE_BIG_ENDIAN, sizeof(uint16_t), (const uint8_t *) (input + *offset)); *offset += sizeof(uint16_t); - SCReturn; + SCReturnInt(0); } /** \internal @@ -461,21 +477,24 @@ static void ModbusCheckHeader(ModbusState *modbus, /** \internal * \brief Parse Exception Response and verify protocol compliance. * - * \param tx Pointer to Modbus Transaction structure - * \param modbus Pointer to Modbus state structure - * \param input Pointer the received input data - * \param offset Offset of the received input data pointer + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer */ static void ModbusExceptionResponse(ModbusTransaction *tx, ModbusState *modbus, uint8_t *input, + uint32_t input_len, uint16_t *offset) { SCEnter(); uint8_t exception; /* Exception code (1 byte) */ - ModbusExtractUint8(&exception, input, offset); + if (ModbusExtractUint8(modbus, &exception, input, input_len, offset)) + SCReturn; switch (exception) { case MODBUS_ERROR_CODE_ILLEGAL_FUNCTION: @@ -511,14 +530,16 @@ static void ModbusExceptionResponse(ModbusTransaction *tx, * \brief Parse Read data Request, complete Transaction structure * and verify protocol compliance. * - * \param tx Pointer to Modbus Transaction structure - * \param modbus Pointer to Modbus state structure - * \param input Pointer the received input data - * \param offset Offset of the received input data pointer + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer */ static void ModbusParseReadRequest(ModbusTransaction *tx, ModbusState *modbus, uint8_t *input, + uint32_t input_len, uint16_t *offset) { SCEnter(); @@ -526,10 +547,12 @@ static void ModbusParseReadRequest(ModbusTransaction *tx, uint8_t type = tx->type; /* Starting Address (2 bytes) */ - ModbusExtractUint16(&(tx->read.address), input, offset); + if (ModbusExtractUint16(modbus, &(tx->read.address), input, input_len, offset)) + goto end; /* Quantity (2 bytes) */ - ModbusExtractUint16(&(tx->read.quantity), input, offset); + if (ModbusExtractUint16(modbus, &(tx->read.quantity), input, input_len, offset)) + goto end; quantity = tx->read.quantity; /* Check Quantity range */ @@ -560,21 +583,24 @@ static void ModbusParseReadRequest(ModbusTransaction *tx, /** \internal * \brief Parse Read data Response and verify protocol compliance * - * \param tx Pointer to Modbus Transaction structure - * \param modbus Pointer to Modbus state structure - * \param input Pointer the received input data - * \param offset Offset of the received input data pointer + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer */ static void ModbusParseReadResponse(ModbusTransaction *tx, ModbusState *modbus, uint8_t *input, + uint32_t input_len, uint16_t *offset) { SCEnter(); uint8_t count; /* Count (1 bytes) */ - ModbusExtractUint8(&count, input, offset); + if (ModbusExtractUint8(modbus, &count, input, input_len, offset)) + goto end; /* Check Count range and value according to the request */ if ((tx->type) & MODBUS_TYP_BIT_ACCESS_MASK) { @@ -605,16 +631,18 @@ static void ModbusParseReadResponse(ModbusTransaction *tx, * \brief Parse Write data Request, complete Transaction structure * and verify protocol compliance. * - * \param tx Pointer to Modbus Transaction structure - * \param modbus Pointer to Modbus state structure - * \param input Pointer the received input data - * \param offset Offset of the received input data pointer + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer * * \retval On success returns 0 or on failure returns -1. */ static int ModbusParseWriteRequest(ModbusTransaction *tx, ModbusState *modbus, uint8_t *input, + uint32_t input_len, uint16_t *offset) { SCEnter(); @@ -624,7 +652,8 @@ static int ModbusParseWriteRequest(ModbusTransaction *tx, int i = 0; /* Starting/Output/Register Address (2 bytes) */ - ModbusExtractUint16(&(tx->write.address), input, offset); + if (ModbusExtractUint16(modbus, &(tx->write.address), input, input_len, offset)) + goto end; if (type & MODBUS_TYP_SINGLE) { /* The length of Write Single Coil (code 5) and */ @@ -634,11 +663,13 @@ static int ModbusParseWriteRequest(ModbusTransaction *tx, goto end; } else if (type & MODBUS_TYP_MULTIPLE) { /* Quantity (2 bytes) */ - ModbusExtractUint16(&quantity, input, offset); + if (ModbusExtractUint16(modbus, &quantity, input, input_len, offset)) + goto end; tx->write.quantity = quantity; /* Count (1 bytes) */ - ModbusExtractUint8(&count, input, offset); + if (ModbusExtractUint8(modbus, &count, input, input_len, offset)) + goto end; tx->write.count = count; if (type & MODBUS_TYP_BIT_ACCESS_MASK) { @@ -691,7 +722,8 @@ static int ModbusParseWriteRequest(ModbusTransaction *tx, if (type & MODBUS_TYP_SINGLE) { /* Outputs value (2 bytes) */ - ModbusExtractUint16(&word, input, offset); + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; tx->data[i] = word; if ((word != 0x00) && (word != 0xFF00)) @@ -699,7 +731,8 @@ static int ModbusParseWriteRequest(ModbusTransaction *tx, } else { for (i = 0; i < count; i++) { /* Outputs value (1 byte) */ - ModbusExtractUint8(&byte, input, offset); + if (ModbusExtractUint8(modbus, &byte, input, input_len, offset)) + goto end; tx->data[i] = (uint16_t) byte; } } @@ -711,7 +744,8 @@ static int ModbusParseWriteRequest(ModbusTransaction *tx, for (i = 0; i < quantity; i++) { /* Outputs/Registers value (2 bytes) */ - ModbusExtractUint16(&word, input, offset); + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; tx->data[i] = word; } } @@ -726,14 +760,16 @@ static int ModbusParseWriteRequest(ModbusTransaction *tx, /** \internal * \brief Parse Write data Response and verify protocol compliance * - * \param tx Pointer to Modbus Transaction structure - * \param modbus Pointer to Modbus state structure - * \param input Pointer the received input data - * \param offset Offset of the received input data pointer + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer */ static void ModbusParseWriteResponse(ModbusTransaction *tx, ModbusState *modbus, uint8_t *input, + uint32_t input_len, uint16_t *offset) { SCEnter(); @@ -741,21 +777,24 @@ static void ModbusParseWriteResponse(ModbusTransaction *tx, uint8_t type = tx->type; /* Starting Address (2 bytes) */ - ModbusExtractUint16(&address, input, offset); + if (ModbusExtractUint16(modbus, &address, input, input_len, offset)) + goto end; if (address != tx->write.address) goto error; if (type & MODBUS_TYP_SINGLE) { /* Outputs/Registers value (2 bytes) */ - ModbusExtractUint16(&word, input, offset); + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; /* Check with Outputs/Registers from request */ if (word != tx->data[0]) goto error; } else if (type & MODBUS_TYP_MULTIPLE) { /* Quantity (2 bytes) */ - ModbusExtractUint16(&quantity, input, offset); + if (ModbusExtractUint16(modbus, &quantity, input, input_len, offset)) + goto end; /* Check Quantity range */ if (type & MODBUS_TYP_BIT_ACCESS_MASK) { @@ -773,14 +812,15 @@ static void ModbusParseWriteResponse(ModbusTransaction *tx, goto error; } else { /* And_Mask value (2 bytes) */ - ModbusExtractUint16(&word, input, offset); + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; /* Check And_Mask value according to the request */ if (word != tx->data[0]) goto error; /* And_Or_Mask value (2 bytes) */ - ModbusExtractUint16(&word, input, offset); + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) /* Check Or_Mask value according to the request */ if (word != tx->data[1]) @@ -808,26 +848,30 @@ static void ModbusParseWriteResponse(ModbusTransaction *tx, * \brief Parse Diagnostic Request, complete Transaction * structure (Category) and verify protocol compliance. * - * \param tx Pointer to Modbus Transaction structure - * \param modbus Pointer to Modbus state structure - * \param input Pointer the received input data - * \param offset Offset of the received input data pointer + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer * * \retval Reserved category function returns 1 otherwise returns 0. */ static int ModbusParseDiagnosticRequest(ModbusTransaction *tx, ModbusState *modbus, uint8_t *input, + uint32_t input_len, uint16_t *offset) { SCEnter(); uint16_t data; /* Sub-function (2 bytes) */ - ModbusExtractUint16(&(tx->subFunction), input, offset); + if (ModbusExtractUint16(modbus, &(tx->subFunction), input, input_len, offset)) + goto end; /* Data (2 bytes) */ - ModbusExtractUint16(&data, input, offset); + if (ModbusExtractUint16(modbus, &data, input, input_len, offset)) + goto end; if (tx->subFunction != MODBUS_SUBFUNC_QUERY_DATA) { switch (tx->subFunction) { @@ -908,20 +952,22 @@ static ModbusFunctionCodeRange modbusFunctionCodeRanges[] = { * \param tx Pointer to Modbus Transaction structure * \param ModbusPdu Pointer the Modbus PDU state in which the value to be stored * \param input Pointer the received input data - * \param offset Offset of the received input data pointer + * \param input_len Length of the received input data */ static void ModbusParseRequestPDU(ModbusTransaction *tx, ModbusState *modbus, uint8_t *input, - uint16_t *offset) + uint32_t input_len) { SCEnter(); - uint8_t count; + uint16_t offset = (uint16_t) sizeof(ModbusHeader); + uint8_t count; int i = 0; /* Standard function codes used on MODBUS application layer protocol (1 byte) */ - ModbusExtractUint8(&(tx->function), input, offset); + if (ModbusExtractUint8(modbus, &(tx->function), input, input_len, &offset)) + goto end; /* Set default function code category */ tx->category = MODBUS_CAT_NONE; @@ -987,14 +1033,15 @@ static void ModbusParseRequestPDU(ModbusTransaction *tx, case MODBUS_FUNC_READFILERECORD: case MODBUS_FUNC_WRITEFILERECORD: /* Count/length (1 bytes) */ - ModbusExtractUint8(&count, input, offset); + if (ModbusExtractUint8(modbus, &count, input, input_len, &offset)) + goto end; /* Modbus Application Protocol Specification V1.1b3 6.14 and 6.15 */ ModbusCheckHeaderLength(modbus, tx->length, 2 + count); break; case MODBUS_FUNC_DIAGNOSTIC: - if(ModbusParseDiagnosticRequest(tx, modbus, input, offset)) + if(ModbusParseDiagnosticRequest(tx, modbus, input, input_len, &offset)) goto end; break; @@ -1013,7 +1060,8 @@ static void ModbusParseRequestPDU(ModbusTransaction *tx, case MODBUS_FUNC_ENCAPINTTRANS: /* MEI type (1 byte) */ - ModbusExtractUint8(&(tx->mei), input, offset); + if (ModbusExtractUint8(modbus, &(tx->mei), input, input_len, &offset)) + goto end; if (tx->mei == MODBUS_MEI_ENCAPINTTRANS_READ) { /* Modbus Application Protocol Specification V1.1b3 6.21 */ @@ -1045,10 +1093,10 @@ static void ModbusParseRequestPDU(ModbusTransaction *tx, tx->category = MODBUS_CAT_PUBLIC_ASSIGNED; if (tx->type & MODBUS_TYP_READ) - ModbusParseReadRequest(tx, modbus, input, offset); + ModbusParseReadRequest(tx, modbus, input, input_len, &offset); if (tx->type & MODBUS_TYP_WRITE) - ModbusParseWriteRequest(tx, modbus, input, offset); + ModbusParseWriteRequest(tx, modbus, input, input_len, &offset); end: SCReturn; @@ -1057,21 +1105,24 @@ static void ModbusParseRequestPDU(ModbusTransaction *tx, /** \internal * \brief Parse the Modbus Protocol Data Unit (PDU) Response * - * \param tx Pointer to Modbus Transaction structure - * \param modbus Pointer the Modbus PDU state in which the value to be stored - * \param input Pointer the received input data - * \param offset Offset of the received input data pointer + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer the Modbus PDU state in which the value to be stored + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer */ static void ModbusParseResponsePDU(ModbusTransaction *tx, ModbusState *modbus, uint8_t *input, - uint16_t *offset) + uint32_t input_len) { SCEnter(); - uint8_t count, error = FALSE, function, mei; + uint16_t offset = (uint16_t) sizeof(ModbusHeader); + uint8_t count, error = FALSE, function, mei; /* Standard function codes used on MODBUS application layer protocol (1 byte) */ - ModbusExtractUint8(&function, input, offset); + if (ModbusExtractUint8(modbus, &function, input, input_len, &offset)) + goto end; /* Check if response is error */ if(function & MODBUS_FUNC_ERRORMASK) { @@ -1082,7 +1133,7 @@ static void ModbusParseResponsePDU(ModbusTransaction *tx, if (tx->category == MODBUS_CAT_PUBLIC_ASSIGNED) { /* Check if response is error. */ if (error) { - ModbusExceptionResponse(tx, modbus, input, offset); + ModbusExceptionResponse(tx, modbus, input, input_len, &offset); } else { switch(function) { case MODBUS_FUNC_READEXCSTATUS: @@ -1098,7 +1149,8 @@ static void ModbusParseResponsePDU(ModbusTransaction *tx, case MODBUS_FUNC_READFILERECORD: case MODBUS_FUNC_WRITEFILERECORD: /* Count/length (1 bytes) */ - ModbusExtractUint8(&count, input, offset); + if (ModbusExtractUint8(modbus, &count, input, input_len, &offset)) + goto end; /* Modbus Application Protocol Specification V1.1b3 6.14 and 6.15 */ ModbusCheckHeaderLength(modbus, tx->length, 2 + count); @@ -1106,7 +1158,8 @@ static void ModbusParseResponsePDU(ModbusTransaction *tx, case MODBUS_FUNC_ENCAPINTTRANS: /* MEI type (1 byte) */ - ModbusExtractUint8(&mei, input, offset); + if (ModbusExtractUint8(modbus, &mei, input, input_len, &offset)) + goto end; if (mei != tx->mei) ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_VALUE_MISMATCH); @@ -1114,10 +1167,10 @@ static void ModbusParseResponsePDU(ModbusTransaction *tx, } if (tx->type & MODBUS_TYP_READ) - ModbusParseReadResponse(tx, modbus, input, offset); + ModbusParseReadResponse(tx, modbus, input, input_len, &offset); /* Read/Write response contents none write response part */ else if (tx->type & MODBUS_TYP_WRITE) - ModbusParseWriteResponse(tx, modbus, input, offset); + ModbusParseWriteResponse(tx, modbus, input, input_len, &offset); } } @@ -1130,26 +1183,26 @@ static void ModbusParseResponsePDU(ModbusTransaction *tx, * * \param header Pointer the Modbus header state in which the value to be stored * \param input Pointer the received input data - * \param offset Offset of the received input data pointer */ -static void ModbusParseHeader(ModbusHeader *header, - uint8_t *input, - uint16_t *offset) +static int ModbusParseHeader(ModbusState *modbus, + ModbusHeader *header, + uint8_t *input, + uint32_t input_len) { SCEnter(); - /* Transaction Identifier (2 bytes) */ - ModbusExtractUint16(&(header->transactionId), input, offset); + uint16_t offset = 0; + /* Transaction Identifier (2 bytes) */ + if (ModbusExtractUint16(modbus, &(header->transactionId), input, input_len, &offset) || /* Protocol Identifier (2 bytes) */ - ModbusExtractUint16(&(header->protocolId), input, offset); - + ModbusExtractUint16(modbus, &(header->protocolId), input, input_len, &offset) || /* Length (2 bytes) */ - ModbusExtractUint16(&(header->length), input, offset); - + ModbusExtractUint16(modbus, &(header->length), input, input_len, &offset) || /* Unit Identifier (1 byte) */ - ModbusExtractUint8(&(header->unitId), input, offset); + ModbusExtractUint8(modbus, &(header->unitId), input, input_len, &offset)) + SCReturnInt(-1); - SCReturn; + SCReturnInt(0); } /** \internal @@ -1175,18 +1228,14 @@ static int ModbusParseRequest(Flow *f, ModbusHeader header; while (input_len > 0) { - uint32_t adu_len; - uint16_t offset = 0; - uint8_t *ptr = input; - - /* Modbus header is 7 bytes long */ - if (input_len < (uint32_t) sizeof(ModbusHeader)) - SCReturnInt(0); + uint32_t adu_len = input_len; + uint8_t *adu = input; /* Extract MODBUS Header */ - ModbusParseHeader(&header, ptr, &offset); + if (ModbusParseHeader(modbus, &header, adu, adu_len)) + SCReturnInt(0); - /* Compute ADU length. */ + /* Update ADU length with length in Modbus header. */ adu_len = (uint32_t) sizeof(ModbusHeader) + (uint32_t) header.length - 1; if (adu_len > input_len) SCReturnInt(0); @@ -1204,7 +1253,7 @@ static int ModbusParseRequest(Flow *f, tx->length = header.length; /* Extract MODBUS PDU and fill Transaction Context */ - ModbusParseRequestPDU(tx, modbus, ptr, &offset); + ModbusParseRequestPDU(tx, modbus, adu, adu_len); /* Update input line and remaining input length of the command */ input += adu_len; @@ -1236,18 +1285,14 @@ static int ModbusParseResponse(Flow *f, ModbusTransaction *tx; while (input_len > 0) { - uint32_t adu_len; - uint16_t offset = 0; - uint8_t *ptr = input; - - /* Modbus header is 7 bytes long */ - if (input_len < (uint32_t) sizeof(ModbusHeader)) - SCReturnInt(0); + uint32_t adu_len = input_len; + uint8_t *adu = input; /* Extract MODBUS Header */ - ModbusParseHeader(&header, ptr, &offset); + if (ModbusParseHeader(modbus, &header, adu, adu_len)) + SCReturnInt(0); - /* Compute ADU length */ + /* Update ADU length with length in Modbus header. */ adu_len = (uint32_t) sizeof(ModbusHeader) + (uint32_t) header.length - 1; if (adu_len > input_len) SCReturnInt(0); @@ -1268,7 +1313,7 @@ static int ModbusParseResponse(Flow *f, tx->length = header.length; /* Extract MODBUS PDU and fill Transaction Context */ - ModbusParseResponsePDU(tx, modbus, ptr, &offset); + ModbusParseResponsePDU(tx, modbus, adu, adu_len); } /* Check and store MODBUS Header */ @@ -1565,6 +1610,13 @@ static uint8_t exceededLengthWriteMultipleRegistersReq[] = { /* Quantity of Registers */ 0x7f, 0xf9, /* Byte count */ 0xff}; +static uint8_t invalidLengthPDUWriteMultipleRegistersReq[] = { + /* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x02, + /* Unit ID */ 0x00, + /* Function code */ 0x10}; + /** \test Send Modbus Read Coils request/response. */ static int ModbusParserTest01(void) { AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2500,6 +2552,93 @@ static int ModbusParserTest11(void) { UTHFreePackets(&p, 1); return result; } + +/** \test Send Modbus invalid PDU Length. */ +static int ModbusParserTest12(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidLengthPDUWriteMultipleRegistersReq, + sizeof(invalidLengthPDUWriteMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} #endif /* UNITTESTS */ void ModbusParserRegisterTests(void) { @@ -2515,5 +2654,6 @@ void ModbusParserRegisterTests(void) { UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets", ModbusParserTest09, 1); UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet", ModbusParserTest10, 1); UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request", ModbusParserTest11, 1); + UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length", ModbusParserTest12, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-modbus.c b/src/detect-engine-modbus.c index cced4966341a..8bbe58286f4f 100644 --- a/src/detect-engine-modbus.c +++ b/src/detect-engine-modbus.c @@ -283,7 +283,7 @@ static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00, /* Example of a request to read input register 9 */ static uint8_t readInputsRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A, /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x05, + /* Length */ 0x00, 0x06, /* Unit ID */ 0x00, /* Function code */ 0x04, /* Starting Address */ 0x00, 0x08, From d9fe95bc8a0b4809b77d12973b8b3ca0cfce029b Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 20 May 2015 14:19:20 -0600 Subject: [PATCH 0538/2553] conf - function declaration style Use consistent style - function return type and declaration on same line. --- src/conf.c | 138 +++++++++++++++++++---------------------------------- 1 file changed, 50 insertions(+), 88 deletions(-) diff --git a/src/conf.c b/src/conf.c index bc8e145880cb..a5c7741b1e27 100644 --- a/src/conf.c +++ b/src/conf.c @@ -61,8 +61,7 @@ static ConfNode *root_backup = NULL; * \retval The existing configuration node if it exists, or a newly * created node for the provided name. On error, NULL will be returned. */ -static ConfNode * -ConfGetNodeOrCreate(const char *name, int final) +static ConfNode *ConfGetNodeOrCreate(const char *name, int final) { ConfNode *parent = root; ConfNode *node = NULL; @@ -111,8 +110,7 @@ ConfGetNodeOrCreate(const char *name, int final) /** * \brief Initialize the configuration system. */ -void -ConfInit(void) +void ConfInit(void) { if (root != NULL) { SCLogDebug("already initialized"); @@ -133,8 +131,7 @@ ConfInit(void) * * \retval An allocated configuration node on success, NULL on failure. */ -ConfNode * -ConfNodeNew(void) +ConfNode *ConfNodeNew(void) { ConfNode *new; @@ -152,8 +149,7 @@ ConfNodeNew(void) * * \param node The configuration node to SCFree. */ -void -ConfNodeFree(ConfNode *node) +void ConfNodeFree(ConfNode *node) { ConfNode *tmp; @@ -177,8 +173,7 @@ ConfNodeFree(ConfNode *node) * \retval A pointer to ConfNode is found or NULL if the configuration * node does not exist. */ -ConfNode * -ConfGetNode(const char *name) +ConfNode *ConfGetNode(const char *name) { ConfNode *node = root; char node_name[NODE_NAME_MAX]; @@ -205,8 +200,7 @@ ConfGetNode(const char *name) /** * \brief Get the root configuration node. */ -ConfNode * -ConfGetRootNode(void) +ConfNode *ConfGetRootNode(void) { return root; } @@ -223,8 +217,7 @@ ConfGetRootNode(void) * * \retval 1 if the value was set otherwise 0. */ -int -ConfSet(const char *name, char *val) +int ConfSet(const char *name, char *val) { ConfNode *node = ConfGetNodeOrCreate(name, 0); if (node == NULL || node->final) { @@ -253,8 +246,7 @@ ConfSet(const char *name, char *val) * * \retval 1 if the value was set otherwise 0. */ -int -ConfSetFinal(const char *name, char *val) +int ConfSetFinal(const char *name, char *val) { ConfNode *node = ConfGetNodeOrCreate(name, 1); if (node == NULL) { @@ -286,8 +278,7 @@ ConfSetFinal(const char *name, char *val) * \retval 1 will be returned if the name is found, otherwise 0 will * be returned. */ -int -ConfGet(const char *name, char **vptr) +int ConfGet(const char *name, char **vptr) { ConfNode *node = ConfGetNode(name); if (node == NULL) { @@ -315,7 +306,8 @@ int ConfGetChildValue(const ConfNode *base, const char *name, char **vptr) } -int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, char **vptr) +int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, + const char *name, char **vptr) { int ret = ConfGetChildValue(base, name, vptr); /* Get 'default' value */ @@ -335,8 +327,7 @@ int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, con * \retval 1 will be returned if the name is found and was properly * converted to an interger, otherwise 0 will be returned. */ -int -ConfGetInt(const char *name, intmax_t *val) +int ConfGetInt(const char *name, intmax_t *val) { char *strval; intmax_t tmpint; @@ -376,7 +367,8 @@ int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val) } -int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val) +int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, + const char *name, intmax_t *val) { int ret = ConfGetChildValueInt(base, name, val); /* Get 'default' value */ @@ -397,8 +389,7 @@ int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, * \retval 1 will be returned if the name is found and was properly * converted to a boolean, otherwise 0 will be returned. */ -int -ConfGetBool(const char *name, int *val) +int ConfGetBool(const char *name, int *val) { char *strval; @@ -424,7 +415,8 @@ int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val) return 1; } -int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val) +int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, + const char *name, int *val) { int ret = ConfGetChildValueBool(base, name, val); /* Get 'default' value */ @@ -446,8 +438,7 @@ int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, * * \retval 1 If the value is true, 0 if not. */ -int -ConfValIsTrue(const char *val) +int ConfValIsTrue(const char *val) { char *trues[] = {"1", "yes", "true", "on"}; size_t u; @@ -472,8 +463,7 @@ ConfValIsTrue(const char *val) * * \retval 1 If the value is false, 0 if not. */ -int -ConfValIsFalse(const char *val) +int ConfValIsFalse(const char *val) { char *falses[] = {"0", "no", "false", "off"}; size_t u; @@ -497,8 +487,7 @@ ConfValIsFalse(const char *val) * \retval 1 will be returned if the name is found and was properly * converted to a double, otherwise 0 will be returned. */ -int -ConfGetDouble(const char *name, double *val) +int ConfGetDouble(const char *name, double *val) { char *strval; double tmpdo; @@ -528,8 +517,7 @@ ConfGetDouble(const char *name, double *val) * \retval 1 will be returned if the name is found and was properly * converted to a double, otherwise 0 will be returned. */ -int -ConfGetFloat(const char *name, float *val) +int ConfGetFloat(const char *name, float *val) { char *strval; double tmpfl; @@ -552,8 +540,7 @@ ConfGetFloat(const char *name, float *val) /** * \brief Remove (and SCFree) the provided configuration node. */ -void -ConfNodeRemove(ConfNode *node) +void ConfNodeRemove(ConfNode *node) { if (node->parent != NULL) TAILQ_REMOVE(&node->parent->head, node, next); @@ -568,8 +555,7 @@ ConfNodeRemove(ConfNode *node) * \retval Returns 1 if the parameter was removed, otherwise 0 is returned * most likely indicating the parameter was not set. */ -int -ConfRemove(const char *name) +int ConfRemove(const char *name) { ConfNode *node; @@ -585,8 +571,7 @@ ConfRemove(const char *name) /** * \brief Creates a backup of the conf_hash hash_table used by the conf API. */ -void -ConfCreateContextBackup(void) +void ConfCreateContextBackup(void) { root_backup = root; root = NULL; @@ -598,8 +583,7 @@ ConfCreateContextBackup(void) * \brief Restores the backup of the hash_table present in backup_conf_hash * back to conf_hash. */ -void -ConfRestoreContextBackup(void) +void ConfRestoreContextBackup(void) { root = root_backup; root_backup = NULL; @@ -610,8 +594,7 @@ ConfRestoreContextBackup(void) /** * \brief De-initializes the configuration system. */ -void -ConfDeInit(void) +void ConfDeInit(void) { if (root != NULL) { ConfNodeFree(root); @@ -621,8 +604,7 @@ ConfDeInit(void) SCLogDebug("configuration module de-initialized"); } -static char * -ConfPrintNameArray(char **name_arr, int level) +static char *ConfPrintNameArray(char **name_arr, int level) { static char name[128*128]; int i; @@ -640,8 +622,7 @@ ConfPrintNameArray(char **name_arr, int level) /** * \brief Dump a configuration node and all its children. */ -void -ConfNodeDump(const ConfNode *node, const char *prefix) +void ConfNodeDump(const ConfNode *node, const char *prefix) { ConfNode *child; @@ -671,8 +652,7 @@ ConfNodeDump(const ConfNode *node, const char *prefix) /** * \brief Dump configuration to stdout. */ -void -ConfDump(void) +void ConfDump(void) { ConfNodeDump(root, NULL); } @@ -688,8 +668,7 @@ ConfDump(void) * * \retval A pointer the child ConfNode if found otherwise NULL. */ -ConfNode * -ConfNodeLookupChild(const ConfNode *node, const char *name) +ConfNode *ConfNodeLookupChild(const ConfNode *node, const char *name) { ConfNode *child; @@ -713,8 +692,7 @@ ConfNodeLookupChild(const ConfNode *node, const char *name) * * \retval A pointer the child ConfNodes value if found otherwise NULL. */ -const char * -ConfNodeLookupChildValue(const ConfNode *node, const char *name) +const char *ConfNodeLookupChildValue(const ConfNode *node, const char *name) { ConfNode *child; @@ -731,7 +709,8 @@ ConfNodeLookupChildValue(const ConfNode *node, const char *name) * \return the ConfNode matching or NULL */ -ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const char *value) +ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, + const char *value) { ConfNode *child; @@ -758,8 +737,7 @@ ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const ch * \retval 1 if the child node has a true value, otherwise 0 is * returned, even if the child node does not exist. */ -int -ConfNodeChildValueIsTrue(const ConfNode *node, const char *key) +int ConfNodeChildValueIsTrue(const ConfNode *node, const char *key) { const char *val; @@ -814,8 +792,7 @@ char *ConfLoadCompleteIncludePath(const char *file) * * \param node The configuration node to prune. */ -void -ConfNodePrune(ConfNode *node) +void ConfNodePrune(ConfNode *node) { ConfNode *item, *it; @@ -847,8 +824,7 @@ ConfNodePrune(ConfNode *node) * * \return 1 if node is a seuence, otherwise 0. */ -int -ConfNodeIsSequence(const ConfNode *node) +int ConfNodeIsSequence(const ConfNode *node) { return node->is_seq == 0 ? 0 : 1; } @@ -858,8 +834,7 @@ ConfNodeIsSequence(const ConfNode *node) /** * Lookup a non-existant value. */ -static int -ConfTestGetNonExistant(void) +static int ConfTestGetNonExistant(void) { char name[] = "non-existant-value"; char *value; @@ -870,8 +845,7 @@ ConfTestGetNonExistant(void) /** * Set then lookup a value. */ -static int -ConfTestSetAndGet(void) +static int ConfTestSetAndGet(void) { char name[] = "some-name"; char value[] = "some-value"; @@ -894,8 +868,7 @@ ConfTestSetAndGet(void) * Test that overriding a value is allowed provided allow_override is * true and that the config parameter gets the new value. */ -static int -ConfTestOverrideValue1(void) +static int ConfTestOverrideValue1(void) { char name[] = "some-name"; char value0[] = "some-value"; @@ -921,8 +894,7 @@ ConfTestOverrideValue1(void) /** * Test that a final value will not be overrided by a ConfSet. */ -static int -ConfTestOverrideValue2(void) +static int ConfTestOverrideValue2(void) { char name[] = "some-name"; char value0[] = "some-value"; @@ -948,8 +920,7 @@ ConfTestOverrideValue2(void) /** * Test retrieving an integer value from the configuration db. */ -static int -ConfTestGetInt(void) +static int ConfTestGetInt(void) { char name[] = "some-int.x"; intmax_t val; @@ -987,8 +958,7 @@ ConfTestGetInt(void) /** * Test retrieving a boolean value from the configuration db. */ -static int -ConfTestGetBool(void) +static int ConfTestGetBool(void) { char name[] = "some-bool"; char *trues[] = { @@ -1028,8 +998,7 @@ ConfTestGetBool(void) return 1; } -static int -ConfNodeLookupChildTest(void) +static int ConfNodeLookupChildTest(void) { char *test_vals[] = { "one", "two", "three" }; size_t u; @@ -1077,8 +1046,7 @@ ConfNodeLookupChildTest(void) return 1; } -static int -ConfNodeLookupChildValueTest(void) +static int ConfNodeLookupChildValueTest(void) { char *test_vals[] = { "one", "two", "three" }; size_t u; @@ -1212,8 +1180,7 @@ static int ConfGetChildValueBoolWithDefaultTest(void) /** * Test the removal of a configuration node. */ -static int -ConfNodeRemoveTest(void) +static int ConfNodeRemoveTest(void) { ConfCreateContextBackup(); ConfInit(); @@ -1236,8 +1203,7 @@ ConfNodeRemoveTest(void) return 1; } -static int -ConfSetTest(void) +static int ConfSetTest(void) { ConfCreateContextBackup(); ConfInit(); @@ -1270,8 +1236,7 @@ ConfSetTest(void) return 1; } -static int -ConfGetNodeOrCreateTest(void) +static int ConfGetNodeOrCreateTest(void) { ConfNode *node; int ret = 0; @@ -1363,8 +1328,7 @@ ConfGetNodeOrCreateTest(void) return ret; } -static int -ConfNodePruneTest(void) +static int ConfNodePruneTest(void) { int ret = 0; ConfNode *node; @@ -1411,8 +1375,7 @@ ConfNodePruneTest(void) return ret; } -int -ConfNodeIsSequenceTest(void) +int ConfNodeIsSequenceTest(void) { int retval = 0; ConfNode *node = ConfNodeNew(); @@ -1436,8 +1399,7 @@ ConfNodeIsSequenceTest(void) return retval; } -void -ConfRegisterTests(void) +void ConfRegisterTests(void) { UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant, 1); UtRegisterTest("ConfSetTest", ConfSetTest, 1); From ae23144b67e62636b8955d28cc0b8f9c761a3334 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 20 May 2015 15:14:59 -0600 Subject: [PATCH 0539/2553] --set - handle spaces on either side of '=' Discard spaces when provided as part of --set around the '='. For example, "val=key", "val = key", "val= key" and "val =key" are all equivalent now. --- src/conf.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++ src/conf.h | 1 + src/suricata.c | 4 +- 3 files changed, 113 insertions(+), 2 deletions(-) diff --git a/src/conf.c b/src/conf.c index a5c7741b1e27..88b9389c58e9 100644 --- a/src/conf.c +++ b/src/conf.c @@ -232,6 +232,56 @@ int ConfSet(const char *name, char *val) return 1; } +/** + * \brief Set a configuration parameter from a string. + * + * Where the input string is something like: + * stream.midstream=true + * + * \param input the input string to be parsed. + * + * \retval 1 if the value of set, otherwise 0. + */ +int ConfSetFromString(const char *input, int final) +{ + int retval = 0; + char *name = SCStrdup(input), *val = NULL; + if (unlikely(name == NULL)) { + goto done; + } + val = strchr(name, '='); + if (val == NULL) { + goto done; + } + *val++ = '\0'; + + while (isspace((int)name[strlen(name) - 1])) { + name[strlen(name) - 1] = '\0'; + } + + while (isspace((int)*val)) { + val++; + } + + if (final) { + if (!ConfSetFinal(name, val)) { + goto done; + } + } + else { + if (!ConfSet(name, val)) { + goto done; + } + } + + retval = 1; +done: + if (name != NULL) { + SCFree(name); + } + return retval; +} + /** * \brief Set a final configuration value. * @@ -1399,6 +1449,65 @@ int ConfNodeIsSequenceTest(void) return retval; } +static int ConfSetFromStringTest(void) +{ + int retval = 0; + ConfNode *n; + + ConfCreateContextBackup(); + ConfInit(); + + if (!ConfSetFromString("stream.midstream=true", 0)) { + goto end; + } + n = ConfGetNode("stream.midstream"); + if (n == NULL) { + goto end; + } + if (n->val == NULL || strcmp("true", n->val)) { + goto end; + } + + if (!ConfSetFromString("stream.midstream =false", 0)) { + goto end; + } + n = ConfGetNode("stream.midstream"); + if (n == NULL) { + goto end; + } + if (n->val == NULL || strcmp("false", n->val)) { + goto end; + } + + if (!ConfSetFromString("stream.midstream= true", 0)) { + goto end; + } + n = ConfGetNode("stream.midstream"); + if (n == NULL) { + goto end; + } + if (n->val == NULL || strcmp("true", n->val)) { + goto end; + } + + if (!ConfSetFromString("stream.midstream = false", 0)) { + goto end; + } + n = ConfGetNode("stream.midstream"); + if (n == NULL) { + goto end; + } + if (n->val == NULL || strcmp("false", n->val)) { + goto end; + } + + retval = 1; +end: + ConfDeInit(); + ConfRestoreContextBackup(); + return retval; +} + void ConfRegisterTests(void) { UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant, 1); @@ -1417,6 +1526,7 @@ void ConfRegisterTests(void) UtRegisterTest("ConfGetNodeOrCreateTest", ConfGetNodeOrCreateTest, 1); UtRegisterTest("ConfNodePruneTest", ConfNodePruneTest, 1); UtRegisterTest("ConfNodeIsSequenceTest", ConfNodeIsSequenceTest, 1); + UtRegisterTest("ConfSetFromStringTest", ConfSetFromStringTest, 1); } #endif /* UNITTESTS */ diff --git a/src/conf.h b/src/conf.h index 2c01a43ee183..2318580a6504 100644 --- a/src/conf.h +++ b/src/conf.h @@ -62,6 +62,7 @@ int ConfGetBool(const char *name, int *val); int ConfGetDouble(const char *name, double *val); int ConfGetFloat(const char *name, float *val); int ConfSet(const char *name, char *val); +int ConfSetFromString(const char *input, int final); int ConfSetFinal(const char *name, char *val); void ConfDump(void); void ConfNodeDump(const ConfNode *node, const char *prefix); diff --git a/src/suricata.c b/src/suricata.c index 4b88b7b12ab0..b26924f307c5 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1479,14 +1479,14 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) #endif else if (strcmp((long_opts[option_index]).name, "set") == 0) { if (optarg != NULL) { + /* Quick validation. */ char *val = strchr(optarg, '='); if (val == NULL) { SCLogError(SC_ERR_CMD_LINE, "Invalid argument for --set, must be key=val."); exit(EXIT_FAILURE); } - *val++ = '\0'; - if (ConfSetFinal(optarg, val) != 1) { + if (!ConfSetFromString(optarg, 1)) { fprintf(stderr, "Failed to set configuration value %s.", optarg); exit(EXIT_FAILURE); From be07620a6021b7bd448bca02a68961516ab4ef9a Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 28 May 2015 07:02:12 +0200 Subject: [PATCH 0540/2553] output-lua: sync variable name with yaml 'script-dir' was used in the code but we had 'scripts-dir' in the configuration file. This patch fixes it to 'scripts-dir'. --- src/output-lua.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output-lua.c b/src/output-lua.c index 7f7514eef460..fc075cd3149a 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -692,7 +692,7 @@ static void LogLuaMasterFree(OutputCtx *oc) { */ static OutputCtx *OutputLuaLogInit(ConfNode *conf) { - const char *dir = ConfNodeLookupChildValue(conf, "script-dir"); + const char *dir = ConfNodeLookupChildValue(conf, "scripts-dir"); if (dir == NULL) dir = ""; From d837562441fae6f5b3a246f26b73654d687b71d3 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 27 May 2015 22:05:19 +0200 Subject: [PATCH 0541/2553] logging: fix modules ordering during logging With the previous code the order of the logging modules in the YAML were determining which module was run first. This was not wished and a consequences was that the EVE fileinfo module was not correctly displaying the key 'stored' because it was depending on a flag set alter by the filestore module. This patch adds a priority file to the TmModule structure. The higher the priority is set, the sooner the module is run in the logging process. The RunModeOutput structure has also been updated to contain the name of the original TmModule. Thus allowing to define a priority for a RunModeOutput. Currently only the filestore has a priority set. The rest of them is set to the default value of zero. --- src/log-filestore.c | 1 + src/runmodes.c | 45 +++++++++++++++++++++++++++++++++++++++------ src/tm-modules.h | 2 ++ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/log-filestore.c b/src/log-filestore.c index 51ad673b9e05..3caee3b7ff45 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -485,6 +485,7 @@ void TmModuleLogFilestoreRegister (void) tmm_modules[TMM_FILESTORE].RegisterTests = NULL; tmm_modules[TMM_FILESTORE].cap_flags = 0; tmm_modules[TMM_FILESTORE].flags = TM_FLAG_LOGAPI_TM; + tmm_modules[TMM_FILESTORE].priority = 10; OutputRegisterFiledataModule(MODULE_NAME, "file", LogFilestoreLogInitCtx, LogFilestoreLogger); diff --git a/src/runmodes.c b/src/runmodes.c index a769b9b6ee7d..5f9b201d5178 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -72,6 +72,7 @@ typedef struct RunModes_ { * A list of output modules that will be active for the run mode. */ typedef struct RunModeOutput_ { + const char *name; TmModule *tm_module; OutputCtx *output_ctx; @@ -506,6 +507,32 @@ static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx) TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries); } + +static int GetRunModeOutputPriority(RunModeOutput *module) +{ + TmModule *tm = TmModuleGetByName(module->name); + if (tm == NULL) + return 0; + + return tm->priority; +} + +static void InsertInRunModeOutputs(RunModeOutput *runmode_output) +{ + RunModeOutput *r_output = NULL; + int output_priority = GetRunModeOutputPriority(runmode_output); + + TAILQ_FOREACH(r_output, &RunModeOutputs, entries) { + if (GetRunModeOutputPriority(r_output) < output_priority) + break; + } + if (r_output) { + TAILQ_INSERT_BEFORE(r_output, runmode_output, entries); + } else { + TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); + } +} + /** \brief Turn output into thread module */ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *output_ctx) { @@ -546,9 +573,10 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); if (unlikely(runmode_output == NULL)) return; + runmode_output->name = module->name; runmode_output->tm_module = pkt_logger_module; runmode_output->output_ctx = NULL; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); + InsertInRunModeOutputs(runmode_output); SCLogDebug("__packet_logger__ added"); } } else if (module->TxLogFunc) { @@ -568,9 +596,10 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); if (unlikely(runmode_output == NULL)) return; + runmode_output->name = module->name; runmode_output->tm_module = tx_logger_module; runmode_output->output_ctx = NULL; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); + InsertInRunModeOutputs(runmode_output); SCLogDebug("__tx_logger__ added"); } } else if (module->FiledataLogFunc) { @@ -589,9 +618,10 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); if (unlikely(runmode_output == NULL)) return; + runmode_output->name = module->name; runmode_output->tm_module = filedata_logger_module; runmode_output->output_ctx = NULL; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); + InsertInRunModeOutputs(runmode_output); SCLogDebug("__filedata_logger__ added"); } } else if (module->FileLogFunc) { @@ -610,9 +640,10 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); if (unlikely(runmode_output == NULL)) return; + runmode_output->name = module->name; runmode_output->tm_module = file_logger_module; runmode_output->output_ctx = NULL; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); + InsertInRunModeOutputs(runmode_output); SCLogDebug("__file_logger__ added"); } } else if (module->StreamingLogFunc) { @@ -632,9 +663,10 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); if (unlikely(runmode_output == NULL)) return; + runmode_output->name = module->name; runmode_output->tm_module = streaming_logger_module; runmode_output->output_ctx = NULL; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); + InsertInRunModeOutputs(runmode_output); SCLogDebug("__streaming_logger__ added"); } } else { @@ -643,9 +675,10 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); if (unlikely(runmode_output == NULL)) return; + runmode_output->name = module->name; runmode_output->tm_module = tm_module; runmode_output->output_ctx = output_ctx; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); + InsertInRunModeOutputs(runmode_output); } } diff --git a/src/tm-modules.h b/src/tm-modules.h index 6502b21c1080..c9d4e1f56e3f 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -61,6 +61,8 @@ typedef struct TmModule_ { the given TmModule */ /* Other flags used by the module */ uint8_t flags; + /* priority in the logging order, higher priority is runned first */ + uint8_t priority; } TmModule; TmModule tmm_modules[TMM_SIZE]; From 320355570863dfa6376c9d2af875495ccc8a199f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 29 May 2015 12:15:18 +0200 Subject: [PATCH 0542/2553] http-client-body: create unittest util func --- src/detect-engine-hcbd.c | 4241 ++++++-------------------------------- 1 file changed, 632 insertions(+), 3609 deletions(-) diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 2eb16acae95d..2de2a54ebdbd 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -295,52 +295,35 @@ void DetectEngineCleanHCBDBuffers(DetectEngineThreadCtx *det_ctx) #ifdef UNITTESTS -static int DetectEngineHttpClientBodyTest01(void) +struct TestSteps { + const uint8_t *input; + size_t input_size; /**< if 0 strlen will be used */ + int direction; /**< STREAM_TOSERVER, STREAM_TOCLIENT */ + int expect; +}; + +static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml) { TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; + Flow f; + Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; + if (yaml) { + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; + ConfYamlLoadString(yaml, strlen(yaml)); + HTPConfigure(); + } StreamTcpInitConfig(TRUE); @@ -348,64 +331,64 @@ static int DetectEngineHttpClientBodyTest01(void) if (de_ctx == NULL) goto end; + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + f.alproto = ALPROTO_HTTP; + + SCLogDebug("sig %s", sig); + DetectEngineAppendSig(de_ctx, (char *)sig); + de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1This\"; http_client_body; " - "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; + struct TestSteps *b = steps; + int i = 0; + while (b->input != NULL) { + SCLogDebug("chunk %p %d", b, i); + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + if (p == NULL) + goto end; + p->flow = &f; + p->flowflags = (b->direction == STREAM_TOSERVER) ? FLOW_PKT_TOSERVER : FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, b->direction, + (uint8_t *)b->input, + b->input_size ? b->input_size : strlen((const char *)b->input)); + if (r != 0) { + printf("toserver chunk %d returned %" PRId32 ", expected 0: ", i+1, r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if ((PacketAlertCheck(p1, 1))) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + int match = PacketAlertCheck(p, 1); + if (b->expect != match) { + printf("rule matching mismatch: "); + goto end; + } - if (!(PacketAlertCheck(p2, 1))) { - printf("sid 1 didn't match but should have"); - goto end; + UTHFreePackets(&p, 1); + p = NULL; + b++; + i++; } - result = 1; -end: + end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -417,3452 +400,609 @@ static int DetectEngineHttpClientBodyTest01(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); + UTHFreePackets(&p, 1); + + if (yaml) { + HtpConfigRestoreBackup(); + ConfRestoreContextBackup(); + } return result; } -static int DetectEngineHttpClientBodyTest02(void) +static int DetectEngineHttpClientBodyTest01(void) { - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 19\r\n" - "\r\n" - "This is dummy body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1This\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; +static int DetectEngineHttpClientBodyTest02(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; offset:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - StreamTcpInitConfig(TRUE); +static int DetectEngineHttpClientBodyTest03(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; offset:16; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; +static int DetectEngineHttpClientBodyTest04(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; offset:16; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx->flags |= DE_QUIET; +static int DetectEngineHttpClientBodyTest05(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; depth:25; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; offset:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; +static int DetectEngineHttpClientBodyTest06(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; depth:25; sid:1;)"; + return RunTest(steps, sig, NULL); +} - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); +static int DetectEngineHttpClientBodyTest07(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; depth:15; sid:1;)"; + return RunTest(steps, sig, NULL); +} - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); +static int DetectEngineHttpClientBodyTest08(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"This is dummy body1This is dummy message body2\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } +static int DetectEngineHttpClientBodyTest09(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"This\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); +static int DetectEngineHttpClientBodyTest10(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"boom\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match but should have\n"); - goto end; - } +static int DetectEngineHttpClientBodyTest11(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"boom\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - result = 1; +static int DetectEngineHttpClientBodyTest12(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"This\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); +static int DetectEngineHttpClientBodyTest13(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"dummy\"; http_client_body; distance:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; +static int DetectEngineHttpClientBodyTest14(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"dummy\"; http_client_body; distance:10; sid:1;)"; + return RunTest(steps, sig, NULL); } -static int DetectEngineHttpClientBodyTest03(void) +static int DetectEngineHttpClientBodyTest15(void) { - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"dummy\"; http_client_body; distance:10; sid:1;)"; + return RunTest(steps, sig, NULL); +} - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); +static int DetectEngineHttpClientBodyTest16(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"dummy\"; http_client_body; distance:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); +static int DetectEngineHttpClientBodyTest17(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"bambu\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; +static int DetectEngineHttpClientBodyTest18(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"bambu\"; http_client_body; fast_pattern; sid:1;)"; + return RunTest(steps, sig, NULL); +} - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; +static int DetectEngineHttpClientBodyTest19(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"bambu\"; http_client_body; content:\"is\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - StreamTcpInitConfig(TRUE); +static int DetectEngineHttpClientBodyTest20(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"is\"; http_client_body; fast_pattern; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; +static int DetectEngineHttpClientBodyTest21(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; http_client_body; within:7; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx->flags |= DE_QUIET; +static int DetectEngineHttpClientBodyTest22(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; within:7; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; offset:16; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; +static int DetectEngineHttpClientBodyTest23(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; distance:3; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); +static int DetectEngineHttpClientBodyTest24(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; distance:13; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); +static int DetectEngineHttpClientBodyTest25(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; within:15; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } +static int DetectEngineHttpClientBodyTest26(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; within:10; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); +static int DetectEngineHttpClientBodyTest27(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; distance:8; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } +static int DetectEngineHttpClientBodyTest28(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; distance:14; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; +static int DetectEngineHttpClientBodyTest29(void) +{ + const char *request_buffer = "GET /one HTTP/1.0\r\n" + "Host: localhost\r\n\r\n"; +#define TOTAL_REQUESTS 45 + uint8_t *http_buf = SCMalloc(TOTAL_REQUESTS * strlen(request_buffer)); + if (unlikely(http_buf == NULL)) + return 0; + for (int i = 0; i < TOTAL_REQUESTS; i++) { + memcpy(http_buf + i * strlen(request_buffer), request_buffer, + strlen(request_buffer)); } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + uint32_t http_buf_len = TOTAL_REQUESTS * strlen(request_buffer); +#undef TOTAL_REQUESTS - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } + struct TestSteps steps[] = { + { (const uint8_t *)http_buf, + (size_t)http_buf_len, STREAM_TOSERVER, 0 }, - result = 1; + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "dummy", + 0, STREAM_TOCLIENT, 0 }, -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + { NULL, 0, 0, 0 }, + }; - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); + const char *sig = "alert http any any -> any any (content:\"dummyone\"; fast_pattern:0,3; http_server_body; sid:1;)"; + int result = RunTest(steps, sig, NULL); + SCFree(http_buf); return result; } -static int DetectEngineHttpClientBodyTest04(void) +static int DetectEngineHttpClientBodyTest30(void) { - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:!\"body1\"; http_client_body; offset:16; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest05(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; depth:25; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest06(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:!\"body1\"; http_client_body; depth:25; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest07(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:!\"body1\"; http_client_body; depth:15; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest08(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:!\"body1\"; http_client_body; depth:25; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest09(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"This\"; http_client_body; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest10(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:!\"boom\"; http_client_body; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest11(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"boom\"; http_client_body; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest12(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:!\"This\"; http_client_body; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest13(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"dummy\"; http_client_body; distance:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest14(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:!\"dummy\"; http_client_body; distance:10; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest15(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"dummy\"; http_client_body; distance:10; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest16(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:!\"dummy\"; http_client_body; distance:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest17(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This is dummy body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"bambu\"; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 1) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest18(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This is dummy body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"bambu\"; http_client_body; fast_pattern; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 0) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest19(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This is dummy body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"bambu\"; http_client_body; " - "content:\"is\"; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 0) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest20(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This is dummy body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"bambu\"; http_client_body; " - "content:\"is\"; http_client_body; fast_pattern; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 2) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest21(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:!\"dummy\"; http_client_body; within:7; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest22(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:!\"dummy\"; within:7; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest23(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:!\"dummy\"; distance:3; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest24(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:!\"dummy\"; distance:13; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest25(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:\"dummy\"; within:15; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest26(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:\"dummy\"; within:10; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest27(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:\"dummy\"; distance:8; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest28(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:\"dummy\"; distance:14; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest29(void) -{ - int result = 0; - Packet *p = NULL; - TcpSession ssn; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - void *alp_tctx = NULL; - const char *request_buffer = "GET /one HTTP/1.0\r\n" - "Host: localhost\r\n" - "\r\n"; - -#define TOTAL_REQUESTS 45 - uint8_t *http_buf = SCMalloc(TOTAL_REQUESTS * strlen(request_buffer)); - if (unlikely(http_buf == NULL)) - goto end; - for (int i = 0; i < TOTAL_REQUESTS; i++) { - memcpy(http_buf + i * strlen(request_buffer), request_buffer, - strlen(request_buffer)); - } - uint32_t http_buf_len = TOTAL_REQUESTS * strlen(request_buffer); - alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"dummyone\"; fast_pattern:0,3; http_server_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - uint8_t response_buf[] = "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 5\r\n" - "\r\n" - "dummy"; - uint32_t response_buf_len = strlen((char *)response_buf); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, - response_buf, response_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p->flow = &f; - p->flowflags |= FLOW_PKT_TOCLIENT; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest30(void) -{ - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - request-body-limit: 0\n\ - response-body-limit: 0\n\ -\n\ - request-body-inspect-window: 0\n\ - response-body-inspect-window: 0\n\ - request-body-minimal-inspect-size: 0\n\ - response-body-minimal-inspect-size: 0\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "bags is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"bags\"; within:4; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HtpConfigRestoreBackup(); - ConfRestoreContextBackup(); - - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + request-body-limit: 0\n\ + response-body-limit: 0\n\ +\n\ + request-body-inspect-window: 0\n\ + response-body-inspect-window: 0\n\ + request-body-minimal-inspect-size: 0\n\ + response-body-minimal-inspect-size: 0\n\ +"; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"bags\"; within:4; http_client_body; sid:1;)"; + return RunTest(steps, sig, yaml); +} static int DetectEngineHttpClientBodyTest31(void) { - char input[] = "\ + const char yaml[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ @@ -3878,138 +1018,21 @@ libhtp:\n\ response-body-minimal-inspect-size: 0\n\ "; - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "bags is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"bags\"; depth:4; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HtpConfigRestoreBackup(); - ConfRestoreContextBackup(); - - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"bags\"; depth:4; http_client_body; sid:1;)"; + return RunTest(steps, sig, yaml); } #endif /* UNITTESTS */ From 0bbc818b2d26d3c042f2af8fc43afd186b067dce Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 31 May 2015 10:52:05 +0200 Subject: [PATCH 0543/2553] http: fix body tracking In HTTP body tracking for response bodies, pruning body chunks was broken as the body parsing code wouldn't update HtpBody::body_parsed. --- src/app-layer-htp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index dd4797572e9f..ac97d408b66c 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1730,6 +1730,7 @@ int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud, } } + htud->response_body.body_parsed += data_len; return 0; end: return -1; From 9fa2f85cc7f951b144c35b01d39b8bbb42348a1d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 1 Jun 2015 11:00:36 +0200 Subject: [PATCH 0544/2553] http: improve body pruning Take inspect window into account. --- src/app-layer-htp-body.c | 13 +++++++++++-- src/app-layer-htp-body.h | 2 +- src/app-layer-htp.c | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index 393336a40de3..0ee1f72bf459 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -199,7 +199,7 @@ void HtpBodyFree(HtpBody *body) * * \retval none */ -void HtpBodyPrune(HtpBody *body) +void HtpBodyPrune(HtpState *state, HtpBody *body) { SCEnter(); @@ -211,6 +211,10 @@ void HtpBodyPrune(HtpBody *body) SCReturn; } + if (body->body_inspected < state->cfg->response_inspect_min_size) { + SCReturn; + } + SCLogDebug("Pruning chunks of Body %p; data %p, len %"PRIu32, body, body->last->data, (uint32_t)body->last->len); @@ -222,7 +226,12 @@ void HtpBodyPrune(HtpBody *body) "body->body_parsed %"PRIu64, cur->stream_offset, cur->len, cur->stream_offset + cur->len, body->body_parsed); - if (cur->stream_offset >= body->body_inspected) { + uint64_t left_edge = 0; + if (state->cfg->response_inspect_window < body->body_inspected) { + left_edge = body->body_inspected - state->cfg->response_inspect_window; + } + + if (cur->stream_offset >= left_edge) { break; } diff --git a/src/app-layer-htp-body.h b/src/app-layer-htp-body.h index 82d92a486042..950b520e5f21 100644 --- a/src/app-layer-htp-body.h +++ b/src/app-layer-htp-body.h @@ -31,6 +31,6 @@ int HtpBodyAppendChunk(HtpTxUserData *, HtpBody *, uint8_t *, uint32_t); void HtpBodyPrint(HtpBody *); void HtpBodyFree(HtpBody *); -void HtpBodyPrune(HtpBody *); +void HtpBodyPrune(HtpState *, HtpBody *); #endif /* __APP_LAYER_HTP_BODY_H__ */ diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index ac97d408b66c..281733255132 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1848,7 +1848,7 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) end: /* see if we can get rid of htp body chunks */ - HtpBodyPrune(&tx_ud->request_body); + HtpBodyPrune(hstate, &tx_ud->request_body); /* set the new chunk flag */ hstate->flags |= HTP_FLAG_NEW_BODY_SET; @@ -1917,7 +1917,7 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) } /* see if we can get rid of htp body chunks */ - HtpBodyPrune(&tx_ud->response_body); + HtpBodyPrune(hstate, &tx_ud->response_body); /* set the new chunk flag */ hstate->flags |= HTP_FLAG_NEW_BODY_SET; From 8949054212ca3403de5f9aecef93eb780235d8df Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Jun 2015 10:43:06 +0200 Subject: [PATCH 0545/2553] detect: remove unused match_flags from inspect engines --- src/detect-engine.c | 61 +++------------------------------------------ src/detect-engine.h | 2 -- src/detect-parse.c | 4 --- 3 files changed, 4 insertions(+), 63 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 6c27b76da0a7..74bcb2a329c7 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -146,7 +146,6 @@ void DetectEngineRegisterAppInspectionEngines(void) AppProto alproto; int32_t sm_list; uint32_t inspect_flags; - uint32_t match_flags; uint16_t dir; int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, @@ -162,84 +161,72 @@ void DetectEngineRegisterAppInspectionEngines(void) ALPROTO_HTTP, DETECT_SM_LIST_UMATCH, DE_STATE_FLAG_URI_INSPECT, - DE_STATE_FLAG_URI_INSPECT, 0, DetectEngineInspectPacketUris }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HRLMATCH, DE_STATE_FLAG_HRL_INSPECT, - DE_STATE_FLAG_HRL_INSPECT, 0, DetectEngineInspectHttpRequestLine }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HCBDMATCH, DE_STATE_FLAG_HCBD_INSPECT, - DE_STATE_FLAG_HCBD_INSPECT, 0, DetectEngineInspectHttpClientBody }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HHDMATCH, DE_STATE_FLAG_HHD_INSPECT, - DE_STATE_FLAG_HHD_INSPECT, 0, DetectEngineInspectHttpHeader }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HRHDMATCH, DE_STATE_FLAG_HRHD_INSPECT, - DE_STATE_FLAG_HRHD_INSPECT, 0, DetectEngineInspectHttpRawHeader }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HMDMATCH, DE_STATE_FLAG_HMD_INSPECT, - DE_STATE_FLAG_HMD_INSPECT, 0, DetectEngineInspectHttpMethod }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HCDMATCH, DE_STATE_FLAG_HCD_INSPECT, - DE_STATE_FLAG_HCD_INSPECT, 0, DetectEngineInspectHttpCookie }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HRUDMATCH, DE_STATE_FLAG_HRUD_INSPECT, - DE_STATE_FLAG_HRUD_INSPECT, 0, DetectEngineInspectHttpRawUri }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DE_STATE_FLAG_FILE_TS_INSPECT, - DE_STATE_FLAG_FILE_TS_INSPECT, 0, DetectFileInspectHttp }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HUADMATCH, DE_STATE_FLAG_HUAD_INSPECT, - DE_STATE_FLAG_HUAD_INSPECT, 0, DetectEngineInspectHttpUA }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HHHDMATCH, DE_STATE_FLAG_HHHD_INSPECT, - DE_STATE_FLAG_HHHD_INSPECT, 0, DetectEngineInspectHttpHH }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HRHHDMATCH, DE_STATE_FLAG_HRHHD_INSPECT, - DE_STATE_FLAG_HRHHD_INSPECT, 0, DetectEngineInspectHttpHRH }, /* DNS */ @@ -247,7 +234,6 @@ void DetectEngineRegisterAppInspectionEngines(void) ALPROTO_DNS, DETECT_SM_LIST_DNSQUERY_MATCH, DE_STATE_FLAG_DNSQUERY_INSPECT, - DE_STATE_FLAG_DNSQUERY_INSPECT, 0, DetectEngineInspectDnsQueryName }, /* specifically for UDP, register again @@ -257,14 +243,12 @@ void DetectEngineRegisterAppInspectionEngines(void) ALPROTO_DNS, DETECT_SM_LIST_DNSQUERY_MATCH, DE_STATE_FLAG_DNSQUERY_INSPECT, - DE_STATE_FLAG_DNSQUERY_INSPECT, 0, DetectEngineInspectDnsQueryName }, { IPPROTO_TCP, ALPROTO_SMTP, DETECT_SM_LIST_FILEMATCH, DE_STATE_FLAG_FILE_TS_INSPECT, - DE_STATE_FLAG_FILE_TS_INSPECT, 0, DetectFileInspectSmtp }, /* Modbus */ @@ -272,7 +256,6 @@ void DetectEngineRegisterAppInspectionEngines(void) ALPROTO_MODBUS, DETECT_SM_LIST_MODBUS_MATCH, DE_STATE_FLAG_MODBUS_INSPECT, - DE_STATE_FLAG_MODBUS_INSPECT, 0, DetectEngineInspectModbus }, /* file_data smtp */ @@ -280,7 +263,6 @@ void DetectEngineRegisterAppInspectionEngines(void) ALPROTO_SMTP, DETECT_SM_LIST_FILEDATA, DE_STATE_FLAG_FD_SMTP_INSPECT, - DE_STATE_FLAG_FD_SMTP_INSPECT, 0, DetectEngineInspectSMTPFiledata }, }; @@ -290,49 +272,42 @@ void DetectEngineRegisterAppInspectionEngines(void) ALPROTO_HTTP, DETECT_SM_LIST_FILEDATA, DE_STATE_FLAG_HSBD_INSPECT, - DE_STATE_FLAG_HSBD_INSPECT, 1, DetectEngineInspectHttpServerBody }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HHDMATCH, DE_STATE_FLAG_HHD_INSPECT, - DE_STATE_FLAG_HHD_INSPECT, 1, DetectEngineInspectHttpHeader }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HRHDMATCH, DE_STATE_FLAG_HRHD_INSPECT, - DE_STATE_FLAG_HRHD_INSPECT, 1, DetectEngineInspectHttpRawHeader }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HCDMATCH, DE_STATE_FLAG_HCD_INSPECT, - DE_STATE_FLAG_HCD_INSPECT, 1, DetectEngineInspectHttpCookie }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DE_STATE_FLAG_FILE_TC_INSPECT, - DE_STATE_FLAG_FILE_TC_INSPECT, 1, DetectFileInspectHttp }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HSMDMATCH, DE_STATE_FLAG_HSMD_INSPECT, - DE_STATE_FLAG_HSMD_INSPECT, 1, DetectEngineInspectHttpStatMsg }, { IPPROTO_TCP, ALPROTO_HTTP, DETECT_SM_LIST_HSCDMATCH, DE_STATE_FLAG_HSCD_INSPECT, - DE_STATE_FLAG_HSCD_INSPECT, 1, DetectEngineInspectHttpStatCode }, /* Modbus */ @@ -340,7 +315,6 @@ void DetectEngineRegisterAppInspectionEngines(void) ALPROTO_MODBUS, DETECT_SM_LIST_MODBUS_MATCH, DE_STATE_FLAG_MODBUS_INSPECT, - DE_STATE_FLAG_MODBUS_INSPECT, 0, DetectEngineInspectModbus } }; @@ -352,7 +326,6 @@ void DetectEngineRegisterAppInspectionEngines(void) data_toserver[i].dir, data_toserver[i].sm_list, data_toserver[i].inspect_flags, - data_toserver[i].match_flags, data_toserver[i].Callback, app_inspection_engine); } @@ -363,7 +336,6 @@ void DetectEngineRegisterAppInspectionEngines(void) data_toclient[i].dir, data_toclient[i].sm_list, data_toclient[i].inspect_flags, - data_toclient[i].match_flags, data_toclient[i].Callback, app_inspection_engine); } @@ -384,14 +356,13 @@ static void AppendAppInspectionEngine(DetectEngineAppInspectionEngine *engine, while (tmp != NULL) { if (tmp->dir == engine->dir && (tmp->sm_list == engine->sm_list || - tmp->inspect_flags == engine->inspect_flags || - tmp->match_flags == engine->match_flags)) { + tmp->inspect_flags == engine->inspect_flags + )) { SCLogError(SC_ERR_DETECT_PREPARE, "App Inspection Engine already " "registered for this direction(%"PRIu16") ||" "sm_list(%d) || " - "[match(%"PRIu32")|inspect(%"PRIu32")]_flags", - tmp->dir, tmp->sm_list, tmp->inspect_flags, - tmp->match_flags); + "[inspect(%"PRIu32")]_flags", + tmp->dir, tmp->sm_list, tmp->inspect_flags); exit(EXIT_FAILURE); } insert = tmp; @@ -410,7 +381,6 @@ void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, uint16_t dir, int32_t sm_list, uint32_t inspect_flags, - uint32_t match_flags, int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -447,7 +417,6 @@ void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, new_engine->dir = dir; new_engine->sm_list = sm_list; new_engine->inspect_flags = inspect_flags; - new_engine->match_flags = match_flags; new_engine->Callback = Callback; AppendAppInspectionEngine(new_engine, list); @@ -2120,7 +2089,6 @@ int DetectEngineTest05(void) 0 /* STREAM_TOSERVER */, DETECT_SM_LIST_UMATCH, DE_STATE_FLAG_URI_INSPECT, - DE_STATE_FLAG_URI_INSPECT, DummyTestAppInspectionEngine01, engine_list); @@ -2141,7 +2109,6 @@ int DetectEngineTest05(void) engine->dir != dir || engine->sm_list != DETECT_SM_LIST_UMATCH || engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || - engine->match_flags != DE_STATE_FLAG_URI_INSPECT || engine->Callback != DummyTestAppInspectionEngine01) { printf("failed for http and dir(0-toserver)\n"); goto end; @@ -2183,7 +2150,6 @@ int DetectEngineTest06(void) 0 /* STREAM_TOSERVER */, DETECT_SM_LIST_UMATCH, DE_STATE_FLAG_URI_INSPECT, - DE_STATE_FLAG_URI_INSPECT, DummyTestAppInspectionEngine01, engine_list); DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, @@ -2191,7 +2157,6 @@ int DetectEngineTest06(void) 1 /* STREAM_TOCLIENT */, DETECT_SM_LIST_UMATCH, DE_STATE_FLAG_URI_INSPECT, - DE_STATE_FLAG_URI_INSPECT, DummyTestAppInspectionEngine02, engine_list); @@ -2212,7 +2177,6 @@ int DetectEngineTest06(void) engine->dir != dir || engine->sm_list != DETECT_SM_LIST_UMATCH || engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || - engine->match_flags != DE_STATE_FLAG_URI_INSPECT || engine->Callback != DummyTestAppInspectionEngine01) { printf("failed for http and dir(0-toserver)\n"); goto end; @@ -2231,7 +2195,6 @@ int DetectEngineTest06(void) engine->dir != dir || engine->sm_list != DETECT_SM_LIST_UMATCH || engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || - engine->match_flags != DE_STATE_FLAG_URI_INSPECT || engine->Callback != DummyTestAppInspectionEngine02) { printf("failed for http and dir(0-toclient)\n"); goto end; @@ -2264,7 +2227,6 @@ int DetectEngineTest07(void) struct test_data_t { int32_t sm_list; uint32_t inspect_flags; - uint32_t match_flags; uint16_t dir; int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, @@ -2277,67 +2239,54 @@ int DetectEngineTest07(void) struct test_data_t data[] = { { DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, DE_STATE_FLAG_URI_INSPECT, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HCBDMATCH, - DE_STATE_FLAG_HCBD_INSPECT, DE_STATE_FLAG_HCBD_INSPECT, 0, DummyTestAppInspectionEngine02 }, { DETECT_SM_LIST_FILEDATA, - DE_STATE_FLAG_HSBD_INSPECT, DE_STATE_FLAG_HSBD_INSPECT, 1, DummyTestAppInspectionEngine02 }, { DETECT_SM_LIST_HHDMATCH, - DE_STATE_FLAG_HHD_INSPECT, DE_STATE_FLAG_HHD_INSPECT, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HRHDMATCH, - DE_STATE_FLAG_HRHD_INSPECT, DE_STATE_FLAG_HRHD_INSPECT, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HMDMATCH, - DE_STATE_FLAG_HMD_INSPECT, DE_STATE_FLAG_HMD_INSPECT, 0, DummyTestAppInspectionEngine02 }, { DETECT_SM_LIST_HCDMATCH, - DE_STATE_FLAG_HCD_INSPECT, DE_STATE_FLAG_HCD_INSPECT, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HRUDMATCH, - DE_STATE_FLAG_HRUD_INSPECT, DE_STATE_FLAG_HRUD_INSPECT, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TS_INSPECT, DE_STATE_FLAG_FILE_TS_INSPECT, 0, DummyTestAppInspectionEngine02 }, { DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TC_INSPECT, DE_STATE_FLAG_FILE_TC_INSPECT, 1, DummyTestAppInspectionEngine02 }, { DETECT_SM_LIST_HSMDMATCH, - DE_STATE_FLAG_HSMD_INSPECT, DE_STATE_FLAG_HSMD_INSPECT, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HSCDMATCH, - DE_STATE_FLAG_HSCD_INSPECT, DE_STATE_FLAG_HSCD_INSPECT, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HUADMATCH, - DE_STATE_FLAG_HUAD_INSPECT, DE_STATE_FLAG_HUAD_INSPECT, 0, DummyTestAppInspectionEngine02 }, @@ -2350,7 +2299,6 @@ int DetectEngineTest07(void) data[i].dir /* STREAM_TOCLIENT */, data[i].sm_list, data[i].inspect_flags, - data[i].match_flags, data[i].Callback, engine_list); } @@ -2376,7 +2324,6 @@ int DetectEngineTest07(void) engine->dir != data[i].dir || engine->sm_list != data[i].sm_list || engine->inspect_flags != data[i].inspect_flags || - engine->match_flags != data[i].match_flags || engine->Callback != data[i].Callback) { printf("failed for http\n"); goto end; diff --git a/src/detect-engine.h b/src/detect-engine.h index dfd7bae93a01..b89260d613e5 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -35,7 +35,6 @@ typedef struct DetectEngineAppInspectionEngine_ { int32_t sm_list; uint32_t inspect_flags; - uint32_t match_flags; /* \retval 0 No match. Don't discontinue matching yet. We need more data. * 1 Match. @@ -101,7 +100,6 @@ void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, uint16_t direction, int32_t sm_list, uint32_t inspect_flags, - uint32_t match_flags, int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-parse.c b/src/detect-parse.c index 87745c15d5bd..4713502ebbe2 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1504,7 +1504,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, 0, DETECT_SM_LIST_APP_EVENT, DE_STATE_FLAG_APP_EVENT_INSPECT, - DE_STATE_FLAG_APP_EVENT_INSPECT, DetectEngineAptEventInspect, app_inspection_engine); } @@ -1514,7 +1513,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, 1, DETECT_SM_LIST_APP_EVENT, DE_STATE_FLAG_APP_EVENT_INSPECT, - DE_STATE_FLAG_APP_EVENT_INSPECT, DetectEngineAptEventInspect, app_inspection_engine); } @@ -1526,7 +1524,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, 0, DETECT_SM_LIST_APP_EVENT, DE_STATE_FLAG_APP_EVENT_INSPECT, - DE_STATE_FLAG_APP_EVENT_INSPECT, DetectEngineAptEventInspect, app_inspection_engine); } @@ -1536,7 +1533,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, 1, DETECT_SM_LIST_APP_EVENT, DE_STATE_FLAG_APP_EVENT_INSPECT, - DE_STATE_FLAG_APP_EVENT_INSPECT, DetectEngineAptEventInspect, app_inspection_engine); } From 5483b800c5961d30f9e5a5cde88e8765d4405a14 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Jun 2015 11:43:26 +0200 Subject: [PATCH 0546/2553] detect: remove struct/union tricks from Signature --- src/detect.h | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/detect.h b/src/detect.h index fbed549fe119..75a0a3436bce 100644 --- a/src/detect.h +++ b/src/detect.h @@ -366,30 +366,19 @@ typedef struct SigMatchData_ { /** \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; - }; + /* coccinelle: Signature:flags:SIG_FLAG */ + uint32_t flags; + + AppProto alproto; + + uint16_t dsize_low; + uint16_t dsize_high; + + uint16_t mpm_pattern_id_div_8; + uint8_t mpm_pattern_id_mod_8; + + SignatureMask mask; + SigIntId num; /**< signature number, internal id */ /** inline -- action */ uint8_t action; From ef7cd043cc285d31df7942f74aa7e4ca330db6b8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Jun 2015 11:50:04 +0200 Subject: [PATCH 0547/2553] detect: various header cleanups --- src/detect.h | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/src/detect.h b/src/detect.h index 75a0a3436bce..0765b4acf5b1 100644 --- a/src/detect.h +++ b/src/detect.h @@ -165,9 +165,6 @@ 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 { @@ -344,7 +341,7 @@ typedef struct IPOnlyCIDRItem_ { * Should never be dereferenced without casting to something else. */ typedef struct SigMatchCtx_ { - int foo; + int foo; } SigMatchCtx; /** \brief a single match condition for a signature */ @@ -489,8 +486,7 @@ typedef struct DetectEngineIPOnlyThreadCtx_ { 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 */ +/** \brief IP only rules matching ctx. */ typedef struct DetectEngineIPOnlyCtx_ { /* lookup hashes */ HashListTable *ht16_src, *ht16_dst; @@ -639,17 +635,6 @@ typedef struct DetectEngineCtx_ { 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; @@ -955,11 +940,7 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 24) 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 - */ + /* list of content containers */ uint8_t *content_array; uint32_t content_size; uint8_t *uri_content_array; @@ -967,8 +948,6 @@ typedef struct SigGroupHeadInitData_ { 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 */ From aa6b24f81443be7e4c4184694aea2924d2fea30a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 20 May 2015 21:42:19 +0200 Subject: [PATCH 0548/2553] decode: clean up tunnel decode logic Don't use mix of existing and custom types to indicate the next layer. --- src/decode-gre.c | 8 ++++---- src/decode-ipv4.c | 2 +- src/decode-ipv6.c | 4 ++-- src/decode-teredo.c | 2 +- src/decode.c | 15 +++++++++------ src/decode.h | 13 ++++++++++--- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/decode-gre.c b/src/decode-gre.c index af4c1af55b08..f827cabe8815 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -201,7 +201,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, IPPROTO_IP, pq); + len - header_len, DECODE_TUNNEL_IPV4, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); @@ -214,7 +214,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, PPP_OVER_GRE, pq); + len - header_len, DECODE_TUNNEL_PPP, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); @@ -227,7 +227,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, IPPROTO_IPV6, pq); + len - header_len, DECODE_TUNNEL_IPV6, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); @@ -240,7 +240,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, VLAN_OVER_GRE, pq); + len - header_len, DECODE_TUNNEL_VLAN, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 856ae5b6d647..63aae4ede45b 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -583,7 +583,7 @@ int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u /* spawn off tunnel packet */ Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), - IPV4_GET_IPPROTO(p), pq); + DECODE_TUNNEL_IPV6, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV4); PacketEnqueue(pq,tp); diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index efd6f10f5033..21ae5226e2ce 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -60,7 +60,7 @@ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, u } if (IP_GET_RAW_VER(pkt) == 4) { if (pq != NULL) { - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, IPPROTO_IP, pq); + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, DECODE_TUNNEL_IPV4, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); /* add the tp to the packet queue. */ @@ -88,7 +88,7 @@ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint } if (IP_GET_RAW_VER(pkt) == 6) { if (unlikely(pq != NULL)) { - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, IPPROTO_IPV6, pq); + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, DECODE_TUNNEL_IPV6, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); PacketEnqueue(pq,tp); diff --git a/src/decode-teredo.c b/src/decode-teredo.c index b4199a052d64..208760277d0e 100644 --- a/src/decode-teredo.c +++ b/src/decode-teredo.c @@ -91,7 +91,7 @@ int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, int blen = len - (start - pkt); /* spawn off tunnel packet */ Packet *tp = PacketTunnelPktSetup(tv, dtv, p, start, blen, - IPPROTO_IPV6, pq); + DECODE_TUNNEL_IPV6, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_TEREDO); /* add the tp to the packet queue. */ diff --git a/src/decode.c b/src/decode.c index 16f5476b411a..ca96ee0adf88 100644 --- a/src/decode.c +++ b/src/decode.c @@ -67,17 +67,19 @@ #include "output-flow.h" int DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - uint8_t *pkt, uint16_t len, PacketQueue *pq, uint8_t proto) + uint8_t *pkt, uint16_t len, PacketQueue *pq, enum DecodeTunnelProto proto) { switch (proto) { - case PPP_OVER_GRE: + case DECODE_TUNNEL_PPP: return DecodePPP(tv, dtv, p, pkt, len, pq); - case IPPROTO_IP: + case DECODE_TUNNEL_IPV4: return DecodeIPV4(tv, dtv, p, pkt, len, pq); - case IPPROTO_IPV6: + case DECODE_TUNNEL_IPV6: return DecodeIPV6(tv, dtv, p, pkt, len, pq); - case VLAN_OVER_GRE: + case DECODE_TUNNEL_VLAN: return DecodeVLAN(tv, dtv, p, pkt, len, pq); + case DECODE_TUNNEL_ETHERNET: + return DecodeEthernet(tv, dtv, p, pkt, len, pq); default: SCLogInfo("FIXME: DecodeTunnel: protocol %" PRIu32 " not supported.", proto); break; @@ -251,7 +253,8 @@ inline int PacketCopyData(Packet *p, uint8_t *pktdata, int pktlen) * \retval p the pseudo packet or NULL if out of memory */ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *parent, - uint8_t *pkt, uint16_t len, uint8_t proto, PacketQueue *pq) + uint8_t *pkt, uint16_t len, enum DecodeTunnelProto proto, + PacketQueue *pq) { int ret; diff --git a/src/decode.h b/src/decode.h index 11501cdffcc1..830b3b360a1c 100644 --- a/src/decode.h +++ b/src/decode.h @@ -829,12 +829,19 @@ typedef struct DecodeThreadVars_ #define IS_TUNNEL_PKT_VERDICTED(p) (((p)->flags & PKT_TUNNEL_VERDICTED)) #define SET_TUNNEL_PKT_VERDICTED(p) ((p)->flags |= PKT_TUNNEL_VERDICTED) +enum DecodeTunnelProto { + DECODE_TUNNEL_ETHERNET, + DECODE_TUNNEL_VLAN, + DECODE_TUNNEL_IPV4, + DECODE_TUNNEL_IPV6, + DECODE_TUNNEL_PPP, +}; -void DecodeRegisterPerfCounters(DecodeThreadVars *, ThreadVars *); Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *parent, - uint8_t *pkt, uint16_t len, uint8_t proto, PacketQueue *pq); + uint8_t *pkt, uint16_t len, enum DecodeTunnelProto proto, PacketQueue *pq); Packet *PacketDefragPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto); void PacketDefragPktSetupParent(Packet *parent); +void DecodeRegisterPerfCounters(DecodeThreadVars *, ThreadVars *); Packet *PacketGetFromQueueOrAlloc(void); Packet *PacketGetFromAlloc(void); void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p); @@ -855,7 +862,7 @@ int DecodeSll(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, P int DecodePPP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodePPPOESession(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodePPPOEDiscovery(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); -int DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *, uint8_t) __attribute__ ((warn_unused_result)); +int DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *, enum DecodeTunnelProto) __attribute__ ((warn_unused_result)); int DecodeNull(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeRaw(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeIPV4(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); From 928957f0a39a8ead06935b2b37e6f593659a1f09 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 20 May 2015 23:01:22 +0200 Subject: [PATCH 0549/2553] decode: add ERSPANv1 decoder Only allow v1 to be parsed as thats what is tested. Take vlan_id from the ERSPAN layer. --- rules/decoder-events.rules | 8 +++- src/Makefile.am | 1 + src/decode-erspan.c | 78 ++++++++++++++++++++++++++++++++++++++ src/decode-erspan.h | 37 ++++++++++++++++++ src/decode-ethernet.h | 1 + src/decode-events.h | 5 +++ src/decode-gre.c | 13 +++++++ src/decode.c | 2 + src/decode.h | 3 ++ src/detect-engine-event.h | 5 +++ 10 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 src/decode-erspan.c create mode 100644 src/decode-erspan.h diff --git a/rules/decoder-events.rules b/rules/decoder-events.rules index dc74a8160bf1..314c0f9268e7 100644 --- a/rules/decoder-events.rules +++ b/rules/decoder-events.rules @@ -128,5 +128,11 @@ alert pkthdr any any -> any any (msg:"SURICATA NULL pkt too small"; decode-event # packet has type not supported by Suricata's decoders alert pkthdr any any -> any any (msg:"SURICATA NULL unsupported type"; decode-event:ltnull.unsupported_type; sid: 2200104; rev:1;) -# next sid is 2200105 +# ERSPAN +alert pkthdr any any -> any any (msg:"SURICATA ERSPAN pkt too small"; decode-event:erspan.header_too_small; sid: 2200105; rev:1;) +# packet has type not supported by Suricata's decoders +alert pkthdr any any -> any any (msg:"SURICATA ERSPAN unsupported version"; decode-event:erspan.unsupported_version; sid: 2200106; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA ERSPAN too many vlan layers"; decode-event:erspan.too_many_vlan_layers; sid: 2200107; rev:1;) + +# next sid is 2200108 diff --git a/src/Makefile.am b/src/Makefile.am index d682b62cc4f4..819338427761 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,7 @@ conf-yaml-loader.c conf-yaml-loader.h \ counters.c counters.h \ data-queue.c data-queue.h \ decode.c decode.h \ +decode-erspan.c decode-erspan.h \ decode-ethernet.c decode-ethernet.h \ decode-events.c decode-events.h \ decode-gre.c decode-gre.h \ diff --git a/src/decode-erspan.c b/src/decode-erspan.c new file mode 100644 index 000000000000..9325f6b81f10 --- /dev/null +++ b/src/decode-erspan.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2015 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. + */ + +/** + * \ingroup decode + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Decodes ERSPAN + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" +#include "decode-events.h" +#include "decode-erspan.h" + +#include "util-unittest.h" +#include "util-debug.h" + +/** + * \brief Function to decode ERSPAN packets + */ + +int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) +{ + if (len < sizeof(ErspanHdr)) { + ENGINE_SET_EVENT(p,ERSPAN_HEADER_TOO_SMALL); + return TM_ECODE_FAILED; + } + + const ErspanHdr *ehdr = (const ErspanHdr *)pkt; + uint16_t version = ntohs(ehdr->ver_vlan) >> 12; + uint16_t vlan_id = ntohs(ehdr->ver_vlan) & 0x0fff; + + SCLogDebug("ERSPAN: version %u vlan %u", version, vlan_id); + + /* only v1 is tested at this time */ + if (version != 1) { + ENGINE_SET_EVENT(p,ERSPAN_UNSUPPORTED_VERSION); + return TM_ECODE_FAILED; + } + + if (vlan_id > 0) { + if (p->vlan_idx >= 2) { + ENGINE_SET_EVENT(p,ERSPAN_TOO_MANY_VLAN_LAYERS); + return TM_ECODE_FAILED; + } + p->vlan_id[p->vlan_idx++] = vlan_id; + } + + return DecodeEthernet(tv, dtv, p, pkt + sizeof(ErspanHdr), len - sizeof(ErspanHdr), pq); +} + +/** + * @} + */ diff --git a/src/decode-erspan.h b/src/decode-erspan.h new file mode 100644 index 000000000000..2f81d1e4a384 --- /dev/null +++ b/src/decode-erspan.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2007-2010 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 + * + */ + +#ifndef __DECODE_ERSPAN_H__ +#define __DECODE_ERSPAN_H__ + +#include "decode.h" +#include "threadvars.h" + +typedef struct ErspanHdr_ { + uint16_t ver_vlan; + uint16_t flags_spanid; + uint32_t padding; +} __attribute__((__packed__)) ErspanHdr; + +#endif /* __DECODE_ERSPAN_H__ */ diff --git a/src/decode-ethernet.h b/src/decode-ethernet.h index 2a6f86e936a4..f8ede8803ffc 100644 --- a/src/decode-ethernet.h +++ b/src/decode-ethernet.h @@ -40,6 +40,7 @@ #define ETHERNET_TYPE_8021Q 0x8100 #define ETHERNET_TYPE_LOOP 0x9000 #define ETHERNET_TYPE_8021QINQ 0x9100 +#define ETHERNET_TYPE_ERSPAN 0x88BE typedef struct EthernetHdr_ { uint8_t eth_dst[6]; diff --git a/src/decode-events.h b/src/decode-events.h index 7ad23d9f7259..c16d0d92d6a1 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -240,6 +240,11 @@ enum { MPLS_BAD_LABEL_RESERVED, MPLS_UNKNOWN_PAYLOAD_TYPE, + /* ERSPAN events */ + ERSPAN_HEADER_TOO_SMALL, + ERSPAN_UNSUPPORTED_VERSION, + ERSPAN_TOO_MANY_VLAN_LAYERS, + /* should always be last! */ DECODE_EVENT_MAX, }; diff --git a/src/decode-gre.c b/src/decode-gre.c index f827cabe8815..6ad9e39758d8 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -249,6 +249,19 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui break; } + case ETHERNET_TYPE_ERSPAN: + { + if (pq != NULL) { + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, + len - header_len, DECODE_TUNNEL_ERSPAN, pq); + if (tp != NULL) { + PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); + PacketEnqueue(pq,tp); + } + } + break; + } + default: return TM_ECODE_OK; } diff --git a/src/decode.c b/src/decode.c index ca96ee0adf88..49896d8efcd2 100644 --- a/src/decode.c +++ b/src/decode.c @@ -80,6 +80,8 @@ int DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, return DecodeVLAN(tv, dtv, p, pkt, len, pq); case DECODE_TUNNEL_ETHERNET: return DecodeEthernet(tv, dtv, p, pkt, len, pq); + case DECODE_TUNNEL_ERSPAN: + return DecodeERSPAN(tv, dtv, p, pkt, len, pq); default: SCLogInfo("FIXME: DecodeTunnel: protocol %" PRIu32 " not supported.", proto); break; diff --git a/src/decode.h b/src/decode.h index 830b3b360a1c..1c02a3ede90e 100644 --- a/src/decode.h +++ b/src/decode.h @@ -65,6 +65,7 @@ enum PktSrcEnum { #include "action-globals.h" +#include "decode-erspan.h" #include "decode-ethernet.h" #include "decode-gre.h" #include "decode-ppp.h" @@ -831,6 +832,7 @@ typedef struct DecodeThreadVars_ enum DecodeTunnelProto { DECODE_TUNNEL_ETHERNET, + DECODE_TUNNEL_ERSPAN, DECODE_TUNNEL_VLAN, DECODE_TUNNEL_IPV4, DECODE_TUNNEL_IPV6, @@ -875,6 +877,7 @@ int DecodeSCTP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, int DecodeGRE(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeVLAN(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeMPLS(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); +int DecodeERSPAN(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void AddressDebugPrint(Address *); diff --git a/src/detect-engine-event.h b/src/detect-engine-event.h index 5d51d6834d4b..9d6424fbdb48 100644 --- a/src/detect-engine-event.h +++ b/src/detect-engine-event.h @@ -243,6 +243,11 @@ struct DetectEngineEvents_ { { "mpls.bad_label_reserved", MPLS_BAD_LABEL_RESERVED, }, { "mpls.unknown_payload_type", MPLS_UNKNOWN_PAYLOAD_TYPE, }, + /* ERSPAN events */ + { "erspan.header_too_small", ERSPAN_HEADER_TOO_SMALL, }, + { "erspan.unsupported_version", ERSPAN_UNSUPPORTED_VERSION, }, + { "erspan.too_many_vlan_layers", ERSPAN_TOO_MANY_VLAN_LAYERS, }, + { NULL, 0 }, }; #endif /* DETECT_EVENTS */ From fe5a85aea0fa56c99b2f334fa7a71f8bd9c69ead Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 30 May 2015 11:31:30 +0200 Subject: [PATCH 0550/2553] decode: add erspan counter --- src/decode-erspan.c | 2 ++ src/decode.c | 1 + src/decode.h | 1 + 3 files changed, 4 insertions(+) diff --git a/src/decode-erspan.c b/src/decode-erspan.c index 9325f6b81f10..ff6390b52387 100644 --- a/src/decode-erspan.c +++ b/src/decode-erspan.c @@ -45,6 +45,8 @@ int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { + StatsIncr(tv, dtv->counter_erspan); + if (len < sizeof(ErspanHdr)) { ENGINE_SET_EVENT(p,ERSPAN_HEADER_TOO_SMALL); return TM_ECODE_FAILED; diff --git a/src/decode.c b/src/decode.c index 49896d8efcd2..682e0b3c9a01 100644 --- a/src/decode.c +++ b/src/decode.c @@ -400,6 +400,7 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) dtv->counter_mpls = StatsRegisterCounter("decoder.mpls", tv); dtv->counter_avg_pkt_size = StatsRegisterAvgCounter("decoder.avg_pkt_size", tv); dtv->counter_max_pkt_size = StatsRegisterMaxCounter("decoder.max_pkt_size", tv); + dtv->counter_erspan = StatsRegisterMaxCounter("decoder.erspan", tv); dtv->counter_defrag_ipv4_fragments = StatsRegisterCounter("defrag.ipv4.fragments", tv); diff --git a/src/decode.h b/src/decode.h index 1c02a3ede90e..a07b24bd8ba9 100644 --- a/src/decode.h +++ b/src/decode.h @@ -610,6 +610,7 @@ typedef struct DecodeThreadVars_ uint16_t counter_ipv6inipv6; uint16_t counter_avg_pkt_size; uint16_t counter_max_pkt_size; + uint16_t counter_erspan; /** frag stats - defrag runs in the context of the decoder. */ uint16_t counter_defrag_ipv4_fragments; From a083513c49753242addca4d61f3896dfa43ee55b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 30 May 2015 11:48:34 +0200 Subject: [PATCH 0551/2553] decode: optimize DecodeThreadVars layout Put common counters on the first cache line. Please the flow output pointer last as it's use depends on the flow logging being enabled and even then it's only called very rarely. --- src/decode.h | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/decode.h b/src/decode.h index a07b24bd8ba9..1c1bba5f54dd 100644 --- a/src/decode.h +++ b/src/decode.h @@ -581,24 +581,26 @@ typedef struct DecodeThreadVars_ int vlan_disabled; - /* thread data for flow logging api */ - void *output_flow_thread_data; - /** stats/counters */ uint16_t counter_pkts; uint16_t counter_bytes; + uint16_t counter_avg_pkt_size; + uint16_t counter_max_pkt_size; + uint16_t counter_invalid; + + uint16_t counter_eth; uint16_t counter_ipv4; uint16_t counter_ipv6; - uint16_t counter_eth; - uint16_t counter_sll; - uint16_t counter_raw; - uint16_t counter_null; uint16_t counter_tcp; uint16_t counter_udp; - uint16_t counter_sctp; uint16_t counter_icmpv4; uint16_t counter_icmpv6; + + uint16_t counter_sll; + uint16_t counter_raw; + uint16_t counter_null; + uint16_t counter_sctp; uint16_t counter_ppp; uint16_t counter_gre; uint16_t counter_vlan; @@ -608,8 +610,6 @@ typedef struct DecodeThreadVars_ uint16_t counter_mpls; uint16_t counter_ipv4inipv6; uint16_t counter_ipv6inipv6; - uint16_t counter_avg_pkt_size; - uint16_t counter_max_pkt_size; uint16_t counter_erspan; /** frag stats - defrag runs in the context of the decoder. */ @@ -621,6 +621,10 @@ typedef struct DecodeThreadVars_ uint16_t counter_defrag_ipv6_timeouts; uint16_t counter_defrag_max_hit; + /* thread data for flow logging api: only used at forced + * flow recycle during lookups */ + void *output_flow_thread_data; + #ifdef __SC_CUDA_SUPPORT__ CudaThreadVars cuda_vars; #endif From 0edf28a4f80b47c53dd09a4c1344dcf2311c40ae Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Wed, 3 Jun 2015 11:59:06 -0400 Subject: [PATCH 0552/2553] Add Feature #1454. Generic eve-log prefix support. --- src/output-json.c | 36 ++++++++++++++++++++++++++++++++---- suricata.yaml.in | 1 + 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index e77dd6846a71..4dea72c8618f 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -341,13 +341,29 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) return TM_ECODE_OK; SCMutexLock(&file_ctx->fp_mutex); - if (file_ctx->type == LOGFILE_TYPE_SYSLOG) { - syslog(alert_syslog_level, "%s", js_s); - } else if (file_ctx->type == LOGFILE_TYPE_FILE || + if (file_ctx->type == LOGFILE_TYPE_SYSLOG) + { + if (file_ctx->prefix != NULL) + { + syslog(alert_syslog_level, "%s%s", file_ctx->prefix, js_s); + } + else + { + syslog(alert_syslog_level, "%s", js_s); + } + } + else if (file_ctx->type == LOGFILE_TYPE_FILE || file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) { - MemBufferWriteString(buffer, "%s\n", js_s); + if (file_ctx->prefix != NULL) + { + MemBufferWriteString(buffer, "%s%s\n", file_ctx->prefix, js_s); + } + else + { + MemBufferWriteString(buffer, "%s\n", js_s); + } file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), MEMBUFFER_OFFSET(buffer), file_ctx); } @@ -456,6 +472,18 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) } } + const char *prefix = ConfNodeLookupChildValue(conf, "prefix"); + if (prefix != NULL) + { + json_ctx->file_ctx->prefix = SCStrdup(prefix); + if (json_ctx->file_ctx->prefix == NULL) + { + SCLogError(SC_ERR_MEM_ALLOC, + "Failed to allocate memory for eve-log.prefix setting."); + exit(EXIT_FAILURE); + } + } + if (json_ctx->json_out == LOGFILE_TYPE_FILE || json_ctx->json_out == LOGFILE_TYPE_UNIX_DGRAM || json_ctx->json_out == LOGFILE_TYPE_UNIX_STREAM) diff --git a/suricata.yaml.in b/suricata.yaml.in index 5942494b7ea4..ce8defb9abdb 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -94,6 +94,7 @@ outputs: enabled: yes filetype: regular #regular|syslog|unix_dgram|unix_stream filename: eve.json + #prefix: "@cee: " # prefix to prepend to each log entry # the following are valid when type: syslog above #identity: "suricata" #facility: local5 From 0f1dd0d7ea46fb9a3b8d46d0da31c4af77774040 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 9 Jun 2015 14:26:57 -0600 Subject: [PATCH 0553/2553] flowbits: strip leading and trailing spaces in name Redmine bug 1481. Strip leading and trailing white space. Factor out parsing from setup while in here. --- src/detect-flowbits.c | 126 +++++++++++++++++++++++++++++++++++------- 1 file changed, 105 insertions(+), 21 deletions(-) diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index bb95c95cd659..2c10f4995528 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -46,7 +46,7 @@ #include "util-unittest.h" #include "util-debug.h" -#define PARSE_REGEX "([a-z]+)(?:,(.*))?" +#define PARSE_REGEX "([a-z]+)(?:,\\s*([^\\s]*))?" static pcre *parse_regex; static pcre_extra *parse_regex_study; @@ -176,36 +176,51 @@ int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p return 0; } -int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +static int DetectFlowbitParse(char *str, char *cmd, int cmd_len, char *name, + int name_len) { - DetectFlowbitsData *cd = NULL; - SigMatch *sm = NULL; - uint8_t fb_cmd = 0; -#define MAX_SUBSTRINGS 30 - int ret = 0, res = 0; - int ov[MAX_SUBSTRINGS]; - char fb_cmd_str[16] = "", fb_name[256] = ""; - - ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); - if (ret != 2 && ret != 3) { - SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for flowbits.", rawstr); - return -1; + const int max_substrings = 30; + int count, rc; + int ov[max_substrings]; + + count = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, + ov, max_substrings); + if (count != 2 && count != 3) { + SCLogError(SC_ERR_PCRE_MATCH, + "\"%s\" is not a valid setting for flowbits.", str); + return 0; } - res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, fb_cmd_str, sizeof(fb_cmd_str)); - if (res < 0) { + rc = pcre_copy_substring((char *)str, ov, max_substrings, 1, cmd, cmd_len); + if (rc < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - return -1; + return 0; } - if (ret == 3) { - res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, fb_name, sizeof(fb_name)); - if (res < 0) { + if (count == 3) { + rc = pcre_copy_substring((char *)str, ov, max_substrings, 2, name, + name_len); + if (rc < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - goto error; + return 0; } } + return 1; +} + +int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +{ + DetectFlowbitsData *cd = NULL; + SigMatch *sm = NULL; + uint8_t fb_cmd = 0; + char fb_cmd_str[16] = "", fb_name[256] = ""; + + if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name, + sizeof(fb_name))) { + return -1; + } + if (strcmp(fb_cmd_str,"noalert") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_NOALERT; } else if (strcmp(fb_cmd_str,"isset") == 0) { @@ -297,6 +312,74 @@ void DetectFlowbitFree (void *ptr) } #ifdef UNITTESTS + +static int FlowBitsTestParse01(void) +{ + int ret = 0; + char command[16] = "", name[16] = ""; + + /* Single argument version. */ + if (!DetectFlowbitParse("noalert", command, sizeof(command), name, + sizeof(name))) { + goto end; + } + if (strcmp(command, "noalert") != 0) { + goto end; + } + + /* No leading or trailing spaces. */ + if (!DetectFlowbitParse("set,flowbit", command, sizeof(command), name, + sizeof(name))) { + goto end; + } + if (strcmp(command, "set") != 0) { + goto end; + } + if (strcmp(name, "flowbit") != 0) { + goto end; + } + + /* Leading space. */ + if (!DetectFlowbitParse("set, flowbit", command, sizeof(command), name, + sizeof(name))) { + goto end; + } + if (strcmp(command, "set") != 0) { + goto end; + } + if (strcmp(name, "flowbit") != 0) { + goto end; + } + + /* Trailing space. */ + if (!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name, + sizeof(name))) { + goto end; + } + if (strcmp(command, "set") != 0) { + goto end; + } + if (strcmp(name, "flowbit") != 0) { + goto end; + } + + /* Leading and trailing space. */ + if (!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name, + sizeof(name))) { + goto end; + } + if (strcmp(command, "set") != 0) { + goto end; + } + if (strcmp(name, "flowbit") != 0) { + goto end; + } + + ret = 1; +end: + return ret; +} + /** * \test FlowBitsTestSig01 is a test for a valid noalert flowbits option * @@ -1060,6 +1143,7 @@ static int FlowBitsTestSig08(void) void FlowBitsRegisterTests(void) { #ifdef UNITTESTS + UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01, 1); UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01, 0); UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02, 0); UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03, 0); From 1f2caf78c38525d2d58325991c11e264cdf6a278 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 10 Jun 2015 14:39:38 -0600 Subject: [PATCH 0554/2553] json-stats: log uptime in seconds, instead of a string --- src/output-json-stats.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 1b684c99b923..8db88d7c97f3 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -99,15 +99,6 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * struct timeval tval; gettimeofday(&tval, NULL); - /* Calculate the Engine uptime */ - int up_time = (int)difftime(tval.tv_sec, st->start_time); - int sec = up_time % 60; // Seconds in a minute - int in_min = up_time / 60; - int min = in_min % 60; // Minutes in a hour - int in_hours = in_min / 60; - int hours = in_hours % 24; // Hours in a day - int days = in_hours / 24; - json_t *js = json_object(); if (unlikely(js == NULL)) return 0; @@ -123,11 +114,9 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * return 0; } - char uptime[128]; - snprintf(uptime, sizeof(uptime), - "%"PRId32"d, %02dh %02dm %02ds", days, hours, min, sec); - - json_object_set_new(js_stats, "uptime", json_string(uptime)); + /* Uptime, in seconds. */ + json_object_set_new(js_stats, "uptime", + json_integer((int)difftime(tval.tv_sec, st->start_time))); uint32_t u = 0; if (aft->statslog_ctx->flags & JSON_STATS_TOTALS) { From 7c40c7348288d79cc97140cd63e4c9562ae12d8f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 10 Jun 2015 15:15:19 -0600 Subject: [PATCH 0555/2553] json-stats: reorg threads and totals Totals are now placed at the top level instead of under a "Total" object. Threads are placed under a "threads" object. --- src/output-json-stats.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 8db88d7c97f3..3e1d45e28bae 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -123,19 +123,27 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * for (u = 0; u < st->nstats; u++) { if (st->stats[u].name == NULL) continue; - char str[256]; - snprintf(str, sizeof(str), "%s.%s", st->stats[u].tm_name, st->stats[u].name); - json_t *js_type = OutputStats2Json(js_stats, str); + const char *name = st->stats[u].name; + const char *shortname = name; + if (rindex(name, '.') != NULL) { + shortname = &name[rindex(name, '.') - name + 1]; + } + json_t *js_type = OutputStats2Json(js_stats, name); if (js_type != NULL) { - json_object_set_new(js_type, &str[rindex(str, '.')-str+1], - json_integer(st->stats[u].value)); + json_object_set_new(js_type, shortname, + json_integer(st->stats[u].value)); } } } - /* per thread stats */ + /* per thread stats - stored in a "threads" object. */ if (st->tstats != NULL && (aft->statslog_ctx->flags & JSON_STATS_THREADS)) { /* for each thread (store) */ + json_t *threads = json_object(); + if (unlikely(threads == NULL)) { + json_decref(js); + return 0; + } uint32_t x; for (x = 0; x < st->ntstats; x++) { uint32_t offset = x * st->nstats; @@ -147,13 +155,14 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * char str[256]; snprintf(str, sizeof(str), "%s.%s", st->tstats[u].tm_name, st->tstats[u].name); - json_t *js_type = OutputStats2Json(js_stats, str); + json_t *js_type = OutputStats2Json(threads, str); if (js_type != NULL) { json_object_set_new(js_type, &str[rindex(str, '.')-str+1], json_integer(st->tstats[u].value)); } } } + json_object_set_new(js_stats, "threads", threads); } json_object_set_new(js, "stats", js_stats); From 26fc5682ad7b2f48d5db1d6c561ed1f228ed7cbc Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 11 Jun 2015 16:45:34 -0600 Subject: [PATCH 0556/2553] hostbits: ignore leading and trailing white space Ignore leading and trailing space around the name and direction tokens. --- src/detect-hostbits.c | 220 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 181 insertions(+), 39 deletions(-) diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index a69c292f1260..ad1fce57b5c0 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -61,7 +61,7 @@ hostbits:set,bitname,both,120; */ -#define PARSE_REGEX "([a-z]+)(?:,([^,]+))?(?:,([^,]+))?" +#define PARSE_REGEX "([a-z]+)(?:\\s*,\\s*([^\\s,]+))?(?:\\s*,\\s*([^,\\s]+))?" static pcre *parse_regex; static pcre_extra *parse_regex_study; @@ -292,57 +292,74 @@ int DetectHostbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p return DetectXbitMatchHost(p, xd); } +static int DetectHostbitParse(const char *str, char *cmd, int cmd_len, + char *name, int name_len, char *dir, int dir_len) +{ + const int max_substrings = 30; + int count, rc; + int ov[max_substrings]; + + count = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, + ov, max_substrings); + if (count != 2 && count != 3 && count != 4) { + SCLogError(SC_ERR_PCRE_MATCH, + "\"%s\" is not a valid setting for hostbits.", str); + return 0; + } + + rc = pcre_copy_substring((char *)str, ov, max_substrings, 1, cmd, cmd_len); + if (rc < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return 0; + } + + if (count >= 3) { + rc = pcre_copy_substring((char *)str, ov, max_substrings, 2, name, + name_len); + if (rc < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return 0; + } + if (count >= 4) { + rc = pcre_copy_substring((char *)str, ov, max_substrings, 3, dir, + dir_len); + if (rc < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, + "pcre_copy_substring failed"); + return 0; + } + } + } + + return 1; +} + int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectXbitsData *cd = NULL; SigMatch *sm = NULL; uint8_t fb_cmd = 0; uint8_t hb_dir = 0; -#define MAX_SUBSTRINGS 30 - int ret = 0, res = 0; - int ov[MAX_SUBSTRINGS]; char fb_cmd_str[16] = "", fb_name[256] = ""; char hb_dir_str[16] = ""; - ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); - if (ret != 2 && ret != 3 && ret != 4) { - SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for hostbits.", rawstr); - return -1; - } - SCLogInfo("ret %d, %s", ret, rawstr); - res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, fb_cmd_str, sizeof(fb_cmd_str)); - if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + if (!DetectHostbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), + fb_name, sizeof(fb_name), hb_dir_str, sizeof(hb_dir_str))) { return -1; } - if (ret >= 3) { - res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, fb_name, sizeof(fb_name)); - if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + if (strlen(hb_dir_str) > 0) { + if (strcmp(hb_dir_str, "src") == 0) + hb_dir = DETECT_XBITS_TRACK_IPSRC; + else if (strcmp(hb_dir_str, "dst") == 0) + hb_dir = DETECT_XBITS_TRACK_IPDST; + else if (strcmp(hb_dir_str, "both") == 0) { + //hb_dir = DETECT_XBITS_TRACK_IPBOTH; + SCLogError(SC_ERR_UNIMPLEMENTED, "'both' not implemented"); + goto error; + } else { + // TODO goto error; - } - if (ret >= 4) { - res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, hb_dir_str, sizeof(hb_dir_str)); - if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - goto error; - } - SCLogInfo("hb_dir_str %s", hb_dir_str); - if (strlen(hb_dir_str) > 0) { - if (strcmp(hb_dir_str, "src") == 0) - hb_dir = DETECT_XBITS_TRACK_IPSRC; - else if (strcmp(hb_dir_str, "dst") == 0) - hb_dir = DETECT_XBITS_TRACK_IPDST; - else if (strcmp(hb_dir_str, "both") == 0) { - //hb_dir = DETECT_XBITS_TRACK_IPBOTH; - SCLogError(SC_ERR_UNIMPLEMENTED, "'both' not implemented"); - goto error; - } else { - // TODO - goto error; - } - } } } @@ -455,6 +472,130 @@ static void HostBitsTestShutdown(void) StorageCleanup(); } +static int HostBitsTestParse01(void) +{ + int ret = 0; + char cmd[16] = "", name[256] = "", dir[16] = ""; + + /* No direction. */ + if (!DetectHostbitParse("isset,name", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))) { + goto end; + } + if (strcmp(cmd, "isset") != 0) { + goto end; + } + if (strcmp(name, "name") != 0) { + goto end; + } + if (strlen(dir)) { + goto end; + } + + /* No direction, leading space. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + if (!DetectHostbitParse("isset, name", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))) { + goto end; + } + if (strcmp(cmd, "isset") != 0) { + goto end; + } + if (strcmp(name, "name") != 0) { + goto end; + } + + /* No direction, trailing space. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + if (!DetectHostbitParse("isset,name ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))) { + goto end; + } + if (strcmp(cmd, "isset") != 0) { + goto end; + } + if (strcmp(name, "name") != 0) { + goto end; + } + + /* No direction, leading and trailing space. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + if (!DetectHostbitParse("isset, name ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))) { + goto end; + } + if (strcmp(cmd, "isset") != 0) { + goto end; + } + if (strcmp(name, "name") != 0) { + goto end; + } + + /* With direction. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + if (!DetectHostbitParse("isset,name,src", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))) { + goto end; + } + if (strcmp(cmd, "isset") != 0) { + goto end; + } + if (strcmp(name, "name") != 0) { + goto end; + } + if (strcmp(dir, "src") != 0) { + goto end; + } + + /* With direction - leading and trailing spaces on name. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + if (!DetectHostbitParse("isset, name ,src", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))) { + goto end; + } + if (strcmp(cmd, "isset") != 0) { + goto end; + } + if (strcmp(name, "name") != 0) { + goto end; + } + if (strcmp(dir, "src") != 0) { + goto end; + } + + /* With direction - space around direction. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + if (!DetectHostbitParse("isset, name , src ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))) { + goto end; + } + if (strcmp(cmd, "isset") != 0) { + goto end; + } + if (strcmp(name, "name") != 0) { + goto end; + } + if (strcmp(dir, "src") != 0) { + goto end; + } + + ret = 1; +end: + return ret; +} + /** * \test HostBitsTestSig01 is a test for a valid noalert flowbits option * @@ -1315,6 +1456,7 @@ static int HostBitsTestSig08(void) void HostBitsRegisterTests(void) { #ifdef UNITTESTS + UtRegisterTest("HostBitsTestParse01", HostBitsTestParse01, 1); UtRegisterTest("HostBitsTestSig01", HostBitsTestSig01, 1); UtRegisterTest("HostBitsTestSig02", HostBitsTestSig02, 1); #if 0 From e85a44c383d6790e96b84c4420cc477ef4cecd98 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 10 Jun 2015 14:20:21 +0200 Subject: [PATCH 0557/2553] suppress: support ip-lists Ticket: 1137 Support supplying a list of IP's to the suppress keyword. Variables from the address-groups and negation is supported. The same logic (and code) is used that is also used in parting the IP portions of regular detection rules. --- src/detect-engine-threshold.c | 8 +++---- src/detect-threshold.c | 2 +- src/detect-threshold.h | 2 +- src/util-threshold-config.c | 40 ++++++++--------------------------- 4 files changed, 15 insertions(+), 37 deletions(-) diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index 1ebc3e404384..900e6b0a0000 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -465,13 +465,13 @@ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint3 } case TYPE_SUPPRESS: { - int res = 0; + DetectAddress *m = NULL; switch (td->track) { case TRACK_DST: - res = DetectAddressMatch(td->addr, &p->dst); + m = DetectAddressLookupInHead(&td->addrs, &p->dst); break; case TRACK_SRC: - res = DetectAddressMatch(td->addr, &p->src); + m = DetectAddressLookupInHead(&td->addrs, &p->src); break; case TRACK_RULE: default: @@ -479,7 +479,7 @@ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint3 "track mode %d is not supported", td->track); break; } - if (res == 0) + if (m == NULL) ret = 1; else ret = 2; /* suppressed but still need actions */ diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 5c83ee4d4730..236b6bf627ac 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -286,7 +286,7 @@ static void DetectThresholdFree(void *de_ptr) { DetectThresholdData *de = (DetectThresholdData *)de_ptr; if (de) { - DetectAddressFree(de->addr); + DetectAddressHeadCleanup(&de->addrs); SCFree(de); } } diff --git a/src/detect-threshold.h b/src/detect-threshold.h index 3306094bee74..fd8c93117f51 100644 --- a/src/detect-threshold.h +++ b/src/detect-threshold.h @@ -60,7 +60,7 @@ typedef struct DetectThresholdData_ { uint8_t new_action; /**< new_action alert|drop|pass|log|sdrop|reject */ uint32_t timeout; /**< timeout */ uint32_t flags; /**< flags used to set option */ - DetectAddress* addr; /**< address group used by suppress keyword */ + DetectAddressHead addrs; } DetectThresholdData; typedef struct DetectThresholdEntry_ { diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index 25be3d79316b..5ee84c55a32f 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -73,7 +73,7 @@ typedef enum ThresholdRuleType { * suppress gen_id 1, sig_id 2000328 * suppress gen_id 1, sig_id 2000328, track by_src, ip fe80::/10 */ -#define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src)\\s*,\\s*ip\\s*([\\da-fA-F.:/]+)*\\s*$" +#define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src)\\s*,\\s*ip\\s*([\\[\\],\\$\\da-zA-Z.:/_]+)*\\s*$" /* Default path for the threshold.config file */ #if defined OS_WIN32 || defined __CYGWIN__ @@ -296,16 +296,10 @@ static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = NULL; if (parsed_track != TRACK_RULE) { - de->addr = DetectAddressInit(); - if (de->addr == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); - goto error; - } - if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { - SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); + if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &de->addrs, (char *)th_ip) != 0) { + SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "failed to parse %s", th_ip); goto error; } } @@ -347,16 +341,10 @@ static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = NULL; if (parsed_track != TRACK_RULE) { - de->addr = DetectAddressInit(); - if (de->addr == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); - goto error; - } - if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { - SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); + if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &de->addrs, (char *)th_ip) != 0) { + SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "failed to parse %s", th_ip); goto error; } } @@ -400,13 +388,8 @@ static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = DetectAddressInit(); - if (de->addr == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); - goto error; - } - if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { - SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); + if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &de->addrs, (char *)th_ip) != 0) { + SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "failed to parse %s", th_ip); goto error; } @@ -427,8 +410,7 @@ static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, return 0; error: if (de != NULL) { - if (de->addr != NULL) - DetectAddressFree(de->addr); + DetectAddressHeadCleanup(&de->addrs); SCFree(de); } return -1; @@ -485,7 +467,6 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = NULL; sm = SigMatchAlloc(); if (sm == NULL) { @@ -549,7 +530,6 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = NULL; sm = SigMatchAlloc(); if (sm == NULL) { @@ -640,7 +620,6 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = NULL; sm = SigMatchAlloc(); if (sm == NULL) { @@ -675,8 +654,7 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid return 0; error: if (de != NULL) { - if (de->addr != NULL) - DetectAddressFree(de->addr); + DetectAddressHeadCleanup(&de->addrs); SCFree(de); } return -1; From ebb42f831c98e2368a7d4fd03c788f718ba899e9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 10 Jun 2015 15:22:12 +0200 Subject: [PATCH 0558/2553] suppress: add track by_either mode So far suppress rules would apply to src or dst addresses of a packet. This meant that if a ip would need to suppressed both as src and as dst, 2 suppress rules would be needed. This patch introduces track by_either, which means that the ip(s) in the suppress rule are tested against both the packets source and dest ip's. If either of them is on the suppress list, the alert is suppressed. --- src/detect-engine-threshold.c | 64 ++++++++++++++++++++++------------- src/detect-threshold.h | 1 + src/util-threshold-config.c | 5 ++- 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index 900e6b0a0000..6c6d1371a8d6 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2015 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 @@ -209,6 +209,41 @@ static DetectThresholdEntry *ThresholdHostLookupEntry(Host *h, uint32_t sid, uin return e; } +int ThresholdHandlePacketSuppress(Packet *p, DetectThresholdData *td, uint32_t sid, uint32_t gid) +{ + int ret = 0; + DetectAddress *m = NULL; + switch (td->track) { + case TRACK_DST: + m = DetectAddressLookupInHead(&td->addrs, &p->dst); + SCLogInfo("TRACK_DST"); + break; + case TRACK_SRC: + m = DetectAddressLookupInHead(&td->addrs, &p->src); + SCLogInfo("TRACK_SRC"); + break; + /* suppress if either src or dst is a match on the suppress + * address list */ + case TRACK_EITHER: + m = DetectAddressLookupInHead(&td->addrs, &p->src); + if (m == NULL) { + m = DetectAddressLookupInHead(&td->addrs, &p->dst); + } + break; + case TRACK_RULE: + default: + SCLogError(SC_ERR_INVALID_VALUE, + "track mode %d is not supported", td->track); + break; + } + if (m == NULL) + ret = 1; + else + ret = 2; /* suppressed but still need actions */ + + return ret; +} + /** * \retval 2 silent match (no alert but apply actions) * \retval 1 normal match @@ -463,28 +498,7 @@ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint3 } break; } - case TYPE_SUPPRESS: - { - DetectAddress *m = NULL; - switch (td->track) { - case TRACK_DST: - m = DetectAddressLookupInHead(&td->addrs, &p->dst); - break; - case TRACK_SRC: - m = DetectAddressLookupInHead(&td->addrs, &p->src); - break; - case TRACK_RULE: - default: - SCLogError(SC_ERR_INVALID_VALUE, - "track mode %d is not supported", td->track); - break; - } - if (m == NULL) - ret = 1; - else - ret = 2; /* suppressed but still need actions */ - break; - } + /* case TYPE_SUPPRESS: is not handled here */ default: SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type); } @@ -600,7 +614,9 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx SCReturnInt(0); } - if (td->track == TRACK_SRC) { + if (td->type == TYPE_SUPPRESS) { + ret = ThresholdHandlePacketSuppress(p,td,s->id,s->gid); + } else if (td->track == TRACK_SRC) { Host *src = HostGetHostFromHash(&p->src); if (src) { ret = ThresholdHandlePacketHost(src,p,td,s->id,s->gid); diff --git a/src/detect-threshold.h b/src/detect-threshold.h index fd8c93117f51..50e1d2704857 100644 --- a/src/detect-threshold.h +++ b/src/detect-threshold.h @@ -38,6 +38,7 @@ #define TRACK_DST 1 #define TRACK_SRC 2 #define TRACK_RULE 3 +#define TRACK_EITHER 4 /**< either src or dst: only used by suppress */ /* Get the new action to take */ #define TH_ACTION_ALERT 0x01 diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index 5ee84c55a32f..9f107a1e0f89 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -73,7 +73,7 @@ typedef enum ThresholdRuleType { * suppress gen_id 1, sig_id 2000328 * suppress gen_id 1, sig_id 2000328, track by_src, ip fe80::/10 */ -#define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src)\\s*,\\s*ip\\s*([\\[\\],\\$\\da-zA-Z.:/_]+)*\\s*$" +#define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src|by_either)\\s*,\\s*ip\\s*([\\[\\],\\$\\da-zA-Z.:/_]+)*\\s*$" /* Default path for the threshold.config file */ #if defined OS_WIN32 || defined __CYGWIN__ @@ -935,6 +935,9 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, parsed_track = TRACK_DST; else if (strcasecmp(th_track,"by_src") == 0) parsed_track = TRACK_SRC; + else if (strcasecmp(th_track,"by_either") == 0) { + parsed_track = TRACK_EITHER; + } else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid track parameter %s in %s", th_track, rule_extend); goto error; From 0bafc71689b8510e9724ee565f008f16b824fe35 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 9 Jun 2015 15:50:31 +0200 Subject: [PATCH 0559/2553] app-layer: add modbus to AppProtoToString It was missing causing protocol identified as modbus not to be displayed in netflow events. --- src/app-layer-protos.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index fd874125711d..1abf295e18f9 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -71,6 +71,9 @@ const char *AppProtoToString(AppProto alproto) case ALPROTO_DNS: proto_name = "dns"; break; + case ALPROTO_MODBUS: + proto_name = "modbus"; + break; case ALPROTO_FAILED: #ifdef UNITTESTS case ALPROTO_TEST: From 925aac854e687683d3b3c88cb6f5243a0fad8c50 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 15 Jun 2015 11:44:24 +0200 Subject: [PATCH 0560/2553] alproto: improve AppProtoToString Make AppProtoToString compilation fail on missing 'case's. --- src/app-layer-protos.c | 3 ++- src/app-layer-protos.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index 1abf295e18f9..0b8ed17bee7d 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -30,8 +30,9 @@ const char *AppProtoToString(AppProto alproto) { const char *proto_name = NULL; + enum AppProtoEnum proto = alproto; - switch (alproto) { + switch (proto) { case ALPROTO_HTTP: proto_name = "http"; break; diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index ecfc4569e84b..79973661efc9 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -25,7 +25,7 @@ #ifndef __APP_LAYER_PROTOS_H__ #define __APP_LAYER_PROTOS_H__ -enum { +enum AppProtoEnum { ALPROTO_UNKNOWN = 0, ALPROTO_HTTP, ALPROTO_FTP, @@ -53,6 +53,7 @@ enum { ALPROTO_MAX, }; +/* not using the enum as that is a unsigned int, so 4 bytes */ typedef uint16_t AppProto; /** From b7f1e9e370230023b55dd1d082513683db87647f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Jun 2015 12:34:58 +0200 Subject: [PATCH 0561/2553] file extract: add app_proto to logging --- src/log-filestore.c | 3 +++ src/output-json-file.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/log-filestore.c b/src/log-filestore.c index 3caee3b7ff45..8686a0a49f0a 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -207,6 +207,9 @@ static void LogFilestoreLogCreateMetaFile(const Packet *p, const File *ff, char fprintf(fp, "DST PORT: %" PRIu16 "\n", dp); } + fprintf(fp, "APP PROTO: %s\n", + AppProtoToString(p->flow->alproto)); + /* Only applicable to HTTP traffic */ if (p->flow->alproto == ALPROTO_HTTP) { fprintf(fp, "HTTP URI: "); diff --git a/src/output-json-file.c b/src/output-json-file.c index 22b9f98cadc6..5464088f1650 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -187,6 +187,7 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F return; } + json_object_set_new(hjs, "app_proto", json_string(AppProtoToString(p->flow->alproto))); switch (p->flow->alproto) { case ALPROTO_HTTP: json_object_set_new(hjs, "url", LogFileMetaGetUri(p, ff)); From 3e14aa729ae83616e4724ff626a346bd75713ee8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Jun 2015 14:36:54 +0200 Subject: [PATCH 0562/2553] detect-state: remove/hide BUG_ON statements --- src/detect-engine-state.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 37a63f5c7fad..ca6cf3abec17 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -433,7 +433,6 @@ static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx, return; if (AppLayerParserSetTxDetectState(f->proto, f->alproto, f->alstate, tx, destate) < 0) { DetectEngineStateFree(destate); - BUG_ON(1); return; } SCLogDebug("destate created for %"PRIu64, tx_id); @@ -459,7 +458,6 @@ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, return; if (AppLayerParserSetTxDetectState(f->proto, f->alproto, f->alstate, tx, destate) < 0) { DetectEngineStateFree(destate); - BUG_ON(1); return; } SCLogDebug("destate created for %"PRIu64, tx_id); @@ -746,7 +744,9 @@ static int DoInspectItem(ThreadVars *tv, if (offset > MAX_STORED_TXID_OFFSET) offset = MAX_STORED_TXID_OFFSET; det_ctx->de_state_sig_array[item->sid] = (uint8_t)offset; +#ifdef DEBUG_VALIDATION BUG_ON(det_ctx->de_state_sig_array[item->sid] & DE_STATE_MATCH_NO_NEW_STATE); // check that we don't set the bit +#endif SCLogDebug("storing tx_id %u for this sid", (uint)inspect_tx_id + 1); } return 0; @@ -782,7 +782,9 @@ static int DoInspectItem(ThreadVars *tv, if (offset > MAX_STORED_TXID_OFFSET) offset = MAX_STORED_TXID_OFFSET; det_ctx->de_state_sig_array[item->sid] = (uint8_t)offset; +#ifdef DEBUG_VALIDATION BUG_ON(det_ctx->de_state_sig_array[item->sid] & DE_STATE_MATCH_NO_NEW_STATE); // check that we don't set the bit +#endif SCLogDebug("storing tx_id %u for this sid", (uint)inspect_tx_id + 1); } return 0; @@ -856,8 +858,9 @@ static int DoInspectItem(ThreadVars *tv, if (offset > MAX_STORED_TXID_OFFSET) offset = MAX_STORED_TXID_OFFSET; det_ctx->de_state_sig_array[item->sid] = (uint8_t)offset; +#ifdef DEBUG_VALIDATION BUG_ON(det_ctx->de_state_sig_array[item->sid] & DE_STATE_MATCH_NO_NEW_STATE); // check that we don't set the bit - +#endif SCLogDebug("storing tx_id %u for this sid", (uint)inspect_tx_id + 1); } RULE_PROFILING_END(det_ctx, s, (alert == 1), p); From e3ce29f694217ee5880db609cd49228166d1c8fa Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 10 Jun 2015 16:09:58 -0600 Subject: [PATCH 0563/2553] json-stats: log deltas If "deltas" is yes, log delta values as the name of the value suffixed with _delta. --- src/output-json-stats.c | 32 +++++++++++++++++++++++++++++--- suricata.yaml.in | 1 + 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 3e1d45e28bae..0778bfe6d3ea 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -53,6 +53,7 @@ #define JSON_STATS_TOTALS (1<<0) #define JSON_STATS_THREADS (1<<1) +#define JSON_STATS_DELTAS (1<<2) typedef struct OutputStatsCtx_ { LogFileCtx *file_ctx; @@ -95,6 +96,7 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * SCEnter(); JsonStatsLogThread *aft = (JsonStatsLogThread *)thread_data; MemBuffer *buffer = (MemBuffer *)aft->buffer; + const char delta_suffix[] = "_delta"; struct timeval tval; gettimeofday(&tval, NULL); @@ -132,6 +134,13 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * if (js_type != NULL) { json_object_set_new(js_type, shortname, json_integer(st->stats[u].value)); + if (aft->statslog_ctx->flags & JSON_STATS_DELTAS) { + char deltaname[strlen(shortname) + strlen(delta_suffix) + 1]; + snprintf(deltaname, sizeof(deltaname), "%s%s", shortname, + delta_suffix); + json_object_set_new(js_type, deltaname, + json_integer(st->stats[u].value - st->stats[u].pvalue)); + } } } } @@ -155,10 +164,19 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * char str[256]; snprintf(str, sizeof(str), "%s.%s", st->tstats[u].tm_name, st->tstats[u].name); + char *shortname = &str[rindex(str, '.') - str + 1]; json_t *js_type = OutputStats2Json(threads, str); if (js_type != NULL) { - json_object_set_new(js_type, &str[rindex(str, '.')-str+1], json_integer(st->tstats[u].value)); + json_object_set_new(js_type, shortname, json_integer(st->tstats[u].value)); + + if (aft->statslog_ctx->flags & JSON_STATS_DELTAS) { + char deltaname[strlen(shortname) + strlen(delta_suffix) + 1]; + snprintf(deltaname, sizeof(deltaname), "%s%s", + shortname, delta_suffix); + json_object_set_new(js_type, deltaname, + json_integer(st->tstats[u].value - st->tstats[u].pvalue)); + } } } } @@ -256,7 +274,8 @@ OutputCtx *OutputStatsLogInit(ConfNode *conf) if (conf != NULL) { const char *totals = ConfNodeLookupChildValue(conf, "totals"); const char *threads = ConfNodeLookupChildValue(conf, "threads"); - SCLogDebug("totals %s threads %s", totals, threads); + const char *deltas = ConfNodeLookupChildValue(conf, "deltas"); + SCLogDebug("totals %s threads %s deltas %s", totals, threads, deltas); if (totals != NULL && ConfValIsFalse(totals)) { stats_ctx->flags &= ~JSON_STATS_TOTALS; @@ -264,6 +283,9 @@ OutputCtx *OutputStatsLogInit(ConfNode *conf) if (threads != NULL && ConfValIsTrue(threads)) { stats_ctx->flags |= JSON_STATS_THREADS; } + if (deltas != NULL && ConfValIsTrue(deltas)) { + stats_ctx->flags |= JSON_STATS_DELTAS; + } SCLogDebug("stats_ctx->flags %08x", stats_ctx->flags); } @@ -302,7 +324,8 @@ OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) if (conf != NULL) { const char *totals = ConfNodeLookupChildValue(conf, "totals"); const char *threads = ConfNodeLookupChildValue(conf, "threads"); - SCLogDebug("totals %s threads %s", totals, threads); + const char *deltas = ConfNodeLookupChildValue(conf, "deltas"); + SCLogDebug("totals %s threads %s deltas %s", totals, threads, deltas); if (totals != NULL && ConfValIsFalse(totals)) { stats_ctx->flags &= ~JSON_STATS_TOTALS; @@ -310,6 +333,9 @@ OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) if (threads != NULL && ConfValIsTrue(threads)) { stats_ctx->flags |= JSON_STATS_THREADS; } + if (deltas != NULL && ConfValIsTrue(deltas)) { + stats_ctx->flags |= JSON_STATS_DELTAS; + } SCLogDebug("stats_ctx->flags %08x", stats_ctx->flags); } diff --git a/suricata.yaml.in b/suricata.yaml.in index ce8defb9abdb..d4883c4236da 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -144,6 +144,7 @@ outputs: - stats: totals: yes # stats for all threads merged together threads: no # per thread stats + deltas: no # include delta values # bi-directional flows #- flow # uni-directional flows From 14466a803dc1782bea978f3f428465ad08e64d5d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 27 May 2015 17:17:50 +0200 Subject: [PATCH 0564/2553] decode: create util function for basic counter updates --- src/decode.c | 10 ++++++++++ src/decode.h | 2 ++ src/source-af-packet.c | 6 +----- src/source-erf-dag.c | 6 +----- src/source-erf-file.c | 6 +----- src/source-ipfw.c | 5 +---- src/source-mpipe.c | 8 +------- src/source-napatech.c | 6 +----- src/source-netmap.c | 5 +---- src/source-nflog.c | 5 +---- src/source-nfq.c | 5 +---- src/source-pcap-file.c | 6 +----- src/source-pcap.c | 6 +----- src/source-pfring.c | 6 +----- 14 files changed, 24 insertions(+), 58 deletions(-) diff --git a/src/decode.c b/src/decode.c index 682e0b3c9a01..b80703884169 100644 --- a/src/decode.c +++ b/src/decode.c @@ -420,6 +420,16 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) return; } +void DecodeUpdatePacketCounters(ThreadVars *tv, + const DecodeThreadVars *dtv, const Packet *p) +{ + StatsIncr(tv, dtv->counter_pkts); + //StatsIncr(tv, dtv->counter_pkts_per_sec); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); +} + /** * \brief Debug print function for printing addresses * diff --git a/src/decode.h b/src/decode.h index 1c1bba5f54dd..3f77cd06da39 100644 --- a/src/decode.h +++ b/src/decode.h @@ -862,6 +862,8 @@ const char *PktSrcToString(enum PktSrcEnum pkt_src); DecodeThreadVars *DecodeThreadVarsAlloc(ThreadVars *); void DecodeThreadVarsFree(ThreadVars *, DecodeThreadVars *); +void DecodeUpdatePacketCounters(ThreadVars *tv, + const DecodeThreadVars *dtv, const Packet *p); /* decoder functions */ int DecodeEthernet(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 654ce00c8b6c..3f1f44e19ddd 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1852,11 +1852,7 @@ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet return TM_ECODE_OK; /* update counters */ - StatsIncr(tv, dtv->counter_pkts); - //StatsIncr(tv, dtv->counter_pkts_per_sec); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index 30baadcd1d74..2614dd05b3df 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -621,11 +621,7 @@ DecodeErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - StatsIncr(tv, dtv->counter_pkts); - //StatsIncr(tv, dtv->counter_pkts_per_sec); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* call the decoder */ switch(p->datalink) { diff --git a/src/source-erf-file.c b/src/source-erf-file.c index fd6973f57ff1..938621c40a31 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -284,11 +284,7 @@ DecodeErfFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueu return TM_ECODE_OK; /* Update counters. */ - StatsIncr(tv, dtv->counter_pkts); - //StatsIncr(tv, dtv->counter_pkts_per_sec); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-ipfw.c b/src/source-ipfw.c index 1b4c1c7e9909..4c68958bed94 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -452,10 +452,7 @@ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; /* update counters */ - StatsIncr(tv, dtv->counter_pkts); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* Process IP packets */ if (IPV4_GET_RAW_VER(ip4h) == 4) { diff --git a/src/source-mpipe.c b/src/source-mpipe.c index 54a567bc7545..9fdebf65a0eb 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -1039,13 +1039,7 @@ TmEcode DecodeMpipe(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - StatsIncr(tv, dtv->counter_pkts); -// StatsIncr(tv, dtv->counter_pkts_per_sec); - - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* call the decoder */ DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-napatech.c b/src/source-napatech.c index e964d4e8bed2..27432314e893 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -357,11 +357,7 @@ TmEcode NapatechDecode(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - StatsIncr(tv, dtv->counter_pkts); -// StatsIncr(tv, dtv->counter_pkts_per_sec); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); switch (p->datalink) { case LINKTYPE_ETHERNET: diff --git a/src/source-netmap.c b/src/source-netmap.c index 89fd69fea08b..570ecfc4da47 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -930,10 +930,7 @@ static TmEcode DecodeNetmap(ThreadVars *tv, Packet *p, void *data, PacketQueue * SCReturnInt(TM_ECODE_OK); /* update counters */ - StatsIncr(tv, dtv->counter_pkts); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-nflog.c b/src/source-nflog.c index 865edd528218..7722244ffee1 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -499,10 +499,7 @@ TmEcode DecodeNFLOG(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; - StatsIncr(tv, dtv->counter_pkts); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); diff --git a/src/source-nfq.c b/src/source-nfq.c index 34a747cb3240..b8b38bc3e621 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -1223,10 +1223,7 @@ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet if (p->flags & PKT_PSEUDO_STREAM_END) return TM_ECODE_OK; - StatsIncr(tv, dtv->counter_pkts); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 7a857fdff468..5d60b9871340 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -401,11 +401,7 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P return TM_ECODE_OK; /* update counters */ - StatsIncr(tv, dtv->counter_pkts); - //StatsIncr(tv, dtv->counter_pkts_per_sec); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); double curr_ts = p->ts.tv_sec + p->ts.tv_usec / 1000.0; if (curr_ts < prev_signaled_ts || (curr_ts - prev_signaled_ts) > 60.0) { diff --git a/src/source-pcap.c b/src/source-pcap.c index cb38e3f7dc64..0656f9589069 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -704,11 +704,7 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; /* update counters */ - StatsIncr(tv, dtv->counter_pkts); - //StatsIncr(tv, dtv->counter_pkts_per_sec); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* call the decoder */ switch(p->datalink) { diff --git a/src/source-pfring.c b/src/source-pfring.c index 88e128622ef3..84fe0df61568 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -602,11 +602,7 @@ TmEcode DecodePfring(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pac return TM_ECODE_OK; /* update counters */ - StatsIncr(tv, dtv->counter_pkts); - //StatsIncr(tv, dtv->counter_pkts_per_sec); - StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); - StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); - StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { From 813930f0271ef2e8716fef9eab01dd616301bc8a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 27 May 2015 17:53:23 +0200 Subject: [PATCH 0565/2553] nfq: add ips stats --- src/source-nfq.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/source-nfq.c b/src/source-nfq.c index b8b38bc3e621..f2bfd7f0cbd7 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -131,6 +131,10 @@ typedef struct NFQThreadVars_ char *data; /** Per function and thread data */ int datalen; /** Length of per function and thread data */ + uint16_t counter_ips_accepted; + uint16_t counter_ips_blocked; + uint16_t counter_ips_rejected; + } NFQThreadVars; /* shared vars for all for nfq queues and threads */ static NFQGlobalVars nfq_g; @@ -755,9 +759,13 @@ TmEcode ReceiveNFQThreadDeinit(ThreadVars *t, void *data) TmEcode VerdictNFQThreadInit(ThreadVars *tv, void *initdata, void **data) { + NFQThreadVars *ntv = (NFQThreadVars *) initdata; - *data = (void *)initdata; + ntv->counter_ips_accepted = StatsRegisterCounter("ips.accepted", tv); + ntv->counter_ips_blocked = StatsRegisterCounter("ips.blocked", tv); + ntv->counter_ips_rejected = StatsRegisterCounter("ips.rejected", tv); + *data = (void *)ntv; return TM_ECODE_OK; } @@ -1169,6 +1177,16 @@ TmEcode NFQSetVerdict(Packet *p) */ TmEcode VerdictNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { + NFQThreadVars *ntv = (NFQThreadVars *)data; + /* update counters */ + if (unlikely(PACKET_TEST_ACTION(p, (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)))) { + StatsIncr(tv, ntv->counter_ips_rejected); + } else if (unlikely(PACKET_TEST_ACTION(p, ACTION_DROP))) { + StatsIncr(tv, ntv->counter_ips_blocked); + } else { + StatsIncr(tv, ntv->counter_ips_accepted); + } + int ret; /* if this is a tunnel packet we check if we are ready to verdict * already. */ From 80615f7d43f500b6ca64324dcfd0b43cecea164f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 28 May 2015 20:44:36 +0200 Subject: [PATCH 0566/2553] ips: move counters in common struct and funcs --- src/decode.c | 21 +++++++++++++++++++++ src/decode.h | 12 ++++++++++++ src/source-nfq.c | 16 +++------------- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/decode.c b/src/decode.c index b80703884169..aa6068bbc09c 100644 --- a/src/decode.c +++ b/src/decode.c @@ -544,6 +544,27 @@ const char *PktSrcToString(enum PktSrcEnum pkt_src) return pkt_src_str; } +void CaptureStatsUpdate(ThreadVars *tv, CaptureStats *s, const Packet *p) +{ + if (unlikely(PACKET_TEST_ACTION(p, (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)))) { + StatsIncr(tv, s->counter_ips_rejected); + } else if (unlikely(PACKET_TEST_ACTION(p, ACTION_DROP))) { + StatsIncr(tv, s->counter_ips_blocked); + } else if (unlikely(p->flags & PKT_STREAM_MODIFIED)) { + StatsIncr(tv, s->counter_ips_replaced); + } else { + StatsIncr(tv, s->counter_ips_accepted); + } +} + +void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s) +{ + s->counter_ips_accepted = StatsRegisterCounter("ips.accepted", tv); + s->counter_ips_blocked = StatsRegisterCounter("ips.blocked", tv); + s->counter_ips_rejected = StatsRegisterCounter("ips.rejected", tv); + s->counter_ips_replaced = StatsRegisterCounter("ips.replaced", tv); +} + /** * @} */ diff --git a/src/decode.h b/src/decode.h index 3f77cd06da39..1a510eec46f2 100644 --- a/src/decode.h +++ b/src/decode.h @@ -630,6 +630,18 @@ typedef struct DecodeThreadVars_ #endif } DecodeThreadVars; +typedef struct CaptureStats_ { + + uint16_t counter_ips_accepted; + uint16_t counter_ips_blocked; + uint16_t counter_ips_rejected; + uint16_t counter_ips_replaced; + +} CaptureStats; + +void CaptureStatsUpdate(ThreadVars *tv, CaptureStats *s, const Packet *p); +void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s); + /** * \brief reset these to -1(indicates that the packet is fresh from the queue) */ diff --git a/src/source-nfq.c b/src/source-nfq.c index f2bfd7f0cbd7..38770cb9708e 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -131,9 +131,7 @@ typedef struct NFQThreadVars_ char *data; /** Per function and thread data */ int datalen; /** Length of per function and thread data */ - uint16_t counter_ips_accepted; - uint16_t counter_ips_blocked; - uint16_t counter_ips_rejected; + CaptureStats stats; } NFQThreadVars; /* shared vars for all for nfq queues and threads */ @@ -761,9 +759,7 @@ TmEcode VerdictNFQThreadInit(ThreadVars *tv, void *initdata, void **data) { NFQThreadVars *ntv = (NFQThreadVars *) initdata; - ntv->counter_ips_accepted = StatsRegisterCounter("ips.accepted", tv); - ntv->counter_ips_blocked = StatsRegisterCounter("ips.blocked", tv); - ntv->counter_ips_rejected = StatsRegisterCounter("ips.rejected", tv); + CaptureStatsSetup(tv, &ntv->stats); *data = (void *)ntv; return TM_ECODE_OK; @@ -1179,13 +1175,7 @@ TmEcode VerdictNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe { NFQThreadVars *ntv = (NFQThreadVars *)data; /* update counters */ - if (unlikely(PACKET_TEST_ACTION(p, (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)))) { - StatsIncr(tv, ntv->counter_ips_rejected); - } else if (unlikely(PACKET_TEST_ACTION(p, ACTION_DROP))) { - StatsIncr(tv, ntv->counter_ips_blocked); - } else { - StatsIncr(tv, ntv->counter_ips_accepted); - } + CaptureStatsUpdate(tv, &ntv->stats, p); int ret; /* if this is a tunnel packet we check if we are ready to verdict From a459376d2e0e04937cdf603b5d8d8c86549ce2bf Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Thu, 28 May 2015 13:42:28 +0200 Subject: [PATCH 0567/2553] app-layer-htp: add http_body_inline setting --- src/app-layer-htp.c | 15 +++++++++++++++ src/app-layer-htp.h | 1 + suricata.yaml.in | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 281733255132..3fd009f57302 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2468,6 +2468,21 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, exit(EXIT_FAILURE); } cfg_prec->randomize_range = range; + } else if (strcasecmp("http-body-inline", p->name) == 0) { + if (ConfValIsTrue(p->val)) { + cfg_prec->http_body_inline = 1; + } else if (ConfValIsFalse(p->val)) { + cfg_prec->http_body_inline = 0; + } else { + if (strcmp("auto", p->val) != 0) { + WarnInvalidConfEntry("http_body_inline", "%s", "auto"); + } + if (EngineModeIsIPS()) { + cfg_prec->http_body_inline = 1; + } else { + cfg_prec->http_body_inline = 0; + } + } } else { SCLogWarning(SC_ERR_UNKNOWN_VALUE, "LIBHTP Ignoring unknown " "default config: %s", p->name); diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 50b95d66d1a0..275bc4b7efbd 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -157,6 +157,7 @@ typedef struct HTPCfgRec_ { uint32_t response_inspect_window; int randomize; int randomize_range; + int http_body_inline; } HTPCfgRec; /** Struct used to hold chunks of a body on a request */ diff --git a/suricata.yaml.in b/suricata.yaml.in index d4883c4236da..a4c7ab5aab32 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1366,6 +1366,10 @@ app-layer: request-body-inspect-window: 4kb response-body-minimal-inspect-size: 32kb response-body-inspect-window: 4kb + + # auto will use http-body-inline mode in IPS mode, yes or no set it statically + http-body-inline: auto + # Take a random value for inspection sizes around the specified value. # This lower the risk of some evasion technics but could lead # detection change between runs. It is set to 'yes' by default. From 8f1998e35fc5e58b701f3973f68d9cf0804b1a73 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 11 May 2015 19:48:32 +0200 Subject: [PATCH 0568/2553] hsbd: inspect buffer depending on the engine mode Currently, data is buffered up to response-body-minimal size and response-body-inspect-window before being inspected. With this, in IPS mode, inspect data as it comes in up. The sliding window concept is used here, some data chunks are copied into the window (buffer) then it's inspected. --- src/detect-engine-hsbd.c | 1419 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 1365 insertions(+), 54 deletions(-) diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index e7ef0bbd4a35..77e33b958a12 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -89,6 +89,123 @@ static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) return 0; } +static void HSBDGetBufferForTXInIDSMode(DetectEngineThreadCtx *det_ctx, + HtpState *htp_state, HtpBodyChunk *cur, + HtpTxUserData *htud, int index) +{ + int first = 1; + while (cur != NULL) { + /* see if we can filter out chunks */ + if (htud->response_body.body_inspected > 0) { + if (cur->stream_offset < htud->response_body.body_inspected) { + if ((htud->response_body.body_inspected - cur->stream_offset) > htp_state->cfg->response_inspect_window) { + cur = cur->next; + continue; + } else { + /* include this one */ + } + } else { + /* include this one */ + } + } + + if (first) { + det_ctx->hsbd[index].offset = cur->stream_offset; + first = 0; + } + + /* see if we need to grow the buffer */ + if (det_ctx->hsbd[index].buffer == NULL || (det_ctx->hsbd[index].buffer_len + cur->len) > det_ctx->hsbd[index].buffer_size) { + void *ptmp; + det_ctx->hsbd[index].buffer_size += cur->len * 2; + + if ((ptmp = SCRealloc(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size)) == NULL) { + SCFree(det_ctx->hsbd[index].buffer); + det_ctx->hsbd[index].buffer = NULL; + det_ctx->hsbd[index].buffer_size = 0; + det_ctx->hsbd[index].buffer_len = 0; + return; + } + det_ctx->hsbd[index].buffer = ptmp; + } + memcpy(det_ctx->hsbd[index].buffer + det_ctx->hsbd[index].buffer_len, cur->data, cur->len); + det_ctx->hsbd[index].buffer_len += cur->len; + + cur = cur->next; + } + + /* update inspected tracker */ + htud->response_body.body_inspected = htud->response_body.last->stream_offset + htud->response_body.last->len; +} + +static void HSBDGetBufferForTXInIPSMode(DetectEngineThreadCtx *det_ctx, + HtpState *htp_state, HtpBodyChunk *cur, + HtpTxUserData *htud, int index) +{ + uint32_t window_size = 0; + uint32_t extra_size = 0; + int resize = 0; + + if (htud->response_body.content_len_so_far <= htp_state->cfg->response_inspect_min_size) { + resize = 1; + window_size = htp_state->cfg->response_inspect_min_size; + } else { + resize = 1; + window_size = htp_state->cfg->response_inspect_window; + } + + int first = 1; + while (cur != NULL) { + /* see if we need to grow the buffer */ + if (cur->len > window_size) { + extra_size = window_size * 0.25; + window_size = cur->len; + resize = 1; + } else if (cur->len == window_size) { + window_size = window_size * 1.25; + resize = 1; + } + + if (det_ctx->hsbd[index].buffer == NULL || resize) { + void *ptmp; + + if ((ptmp = SCRealloc(det_ctx->hsbd[index].buffer, window_size + extra_size)) == NULL) { + SCFree(det_ctx->hsbd[index].buffer); + det_ctx->hsbd[index].buffer = NULL; + det_ctx->hsbd[index].buffer_size = 0; + det_ctx->hsbd[index].buffer_len = 0; + return; + } + det_ctx->hsbd[index].buffer = ptmp; + resize = 0; + } + + if (first) { + det_ctx->hsbd[index].offset = cur->stream_offset; + first = 0; + } + + /* + * Copy a part of the previous buffer before the current chunk on. + * For example, let's have the chunks [123], [456]. + * When the current chunk is [456], this copy [3] before. + */ + if (det_ctx->hsbd[index].buffer_len + cur->len > window_size + extra_size) { + uint32_t offset = (det_ctx->hsbd[index].buffer_len + cur->len) - (window_size + extra_size); + /* we use memmove to avoid memory overlap */ + memmove(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer + offset, det_ctx->hsbd[index].buffer_len - offset); + det_ctx->hsbd[index].buffer_len -= offset; + det_ctx->hsbd[index].offset += offset; + } + memcpy(det_ctx->hsbd[index].buffer + det_ctx->hsbd[index].buffer_len, cur->data, cur->len); + det_ctx->hsbd[index].buffer_len += cur->len; + + cur = cur->next; + } + + /* update inspected tracker */ + htud->response_body.body_inspected = htud->response_body.last->stream_offset + htud->response_body.last->len; +} static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, DetectEngineCtx *de_ctx, @@ -158,63 +275,24 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, flags & STREAM_EOF ? "true" : "false", (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) ? "true" : "false"); - /* inspect the body if the transfer is complete or we have hit - * our body size limit */ - if ((htp_state->cfg->response_body_limit == 0 || - htud->response_body.content_len_so_far < htp_state->cfg->response_body_limit) && - htud->response_body.content_len_so_far < htp_state->cfg->response_inspect_min_size && - !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) && - !(flags & STREAM_EOF)) { - SCLogDebug("we still haven't seen the entire response body. " - "Let's defer body inspection till we see the " - "entire body."); - goto end; - } - - int first = 1; - while (cur != NULL) { - /* see if we can filter out chunks */ - if (htud->response_body.body_inspected > 0) { - if (cur->stream_offset < htud->response_body.body_inspected) { - if ((htud->response_body.body_inspected - cur->stream_offset) > htp_state->cfg->response_inspect_window) { - cur = cur->next; - continue; - } else { - /* include this one */ - } - } else { - /* include this one */ - } - } - - if (first) { - det_ctx->hsbd[index].offset = cur->stream_offset; - first = 0; - } - - /* see if we need to grow the buffer */ - if (det_ctx->hsbd[index].buffer == NULL || (det_ctx->hsbd[index].buffer_len + cur->len) > det_ctx->hsbd[index].buffer_size) { - void *ptmp; - det_ctx->hsbd[index].buffer_size += cur->len * 2; - - if ((ptmp = SCRealloc(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size)) == NULL) { - SCFree(det_ctx->hsbd[index].buffer); - det_ctx->hsbd[index].buffer = NULL; - det_ctx->hsbd[index].buffer_size = 0; - det_ctx->hsbd[index].buffer_len = 0; - goto end; - } - det_ctx->hsbd[index].buffer = ptmp; + if (!htp_state->cfg->http_body_inline) { + /* inspect the body if the transfer is complete or we have hit + * our body size limit */ + if ((htp_state->cfg->response_body_limit == 0 || + htud->response_body.content_len_so_far < htp_state->cfg->response_body_limit) && + htud->response_body.content_len_so_far < htp_state->cfg->response_inspect_min_size && + !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) && + !(flags & STREAM_EOF)) { + SCLogDebug("we still haven't seen the entire response body. " + "Let's defer body inspection till we see the " + "entire body."); + goto end; } - memcpy(det_ctx->hsbd[index].buffer + det_ctx->hsbd[index].buffer_len, cur->data, cur->len); - det_ctx->hsbd[index].buffer_len += cur->len; - - cur = cur->next; + HSBDGetBufferForTXInIDSMode(det_ctx, htp_state, cur, htud, index); + } else { + HSBDGetBufferForTXInIPSMode(det_ctx, htp_state, cur, htud, index); } - /* update inspected tracker */ - htud->response_body.body_inspected = htud->response_body.last->stream_offset + htud->response_body.last->len; - buffer = det_ctx->hsbd[index].buffer; *buffer_len = det_ctx->hsbd[index].buffer_len; *stream_start_offset = det_ctx->hsbd[index].offset; @@ -3631,6 +3709,1227 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) return result; } +/* + * Tests buffer inspection like in ips mode, + * here all chunks size are smaller than the window_size. + + * in: buffer: + * [ab] [ab] + * [cd] [abcd] + * [ef] [cdef] +*/ +static int DetectEngineHttpServerBodyFileDataTest04(void) +{ + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 1\n\ + response-body-inspect-window: 4\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + EngineModeSetIPS(); + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "ab"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = "cd"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + uint8_t http_buf4[] = "ef"; + uint32_t http_len4 = sizeof(http_buf4) - 1; + + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"ab\"; sid:1;)"))) + goto end; + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"bc\"; sid:2;)"))) + goto end; + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"cdef\"; sid:3;)"))) + goto end; + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"ef\"; sid:4;)"))) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 did not match but should have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 2)) { + printf("sid 2 did not match but should have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf4, http_len4); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 3)) { + printf("sid 3 did not match but should have: "); + goto end; + } + + if (!PacketAlertCheck(p2, 4)) { + printf("sid 4 did not match but should have: "); + goto end; + } + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + EngineModeSetIDS(); + ConfDeInit(); + ConfRestoreContextBackup(); + return result; +} + +/* + * Tests buffer inspection like in ips mode, + * here the last chunk size is greater than the window size. + + * in: buffer: + * [ab] [ab] + * [cd] [abcd] + * [12345678] [d12345678] +*/ +static int DetectEngineHttpServerBodyFileDataTest05(void) +{ + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 1\n\ + response-body-inspect-window: 4\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + EngineModeSetIPS(); + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 12\r\n" + "\r\n" + "ab"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = "cd"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + uint8_t http_buf4[] = "12345678"; + uint32_t http_len4 = sizeof(http_buf4) - 1; + + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"ab\"; sid:1;)"))) + goto end; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"abcd\"; sid:2;)"))) + goto end; + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"d12345678\"; sid:3;)"))) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 did not match but should have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 2)) { + printf("sid 2 did not match but should have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf4, http_len4); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 3)) { + printf("sid 3 did not match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + EngineModeSetIDS(); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + return result; +} + +/** + * in: buffer: + * [123] [123] + * [456] [3456] + */ +static int DetectEngineHttpServerBodyFileDataTest06(void) +{ + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 1\n\ + response-body-inspect-window: 4\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + EngineModeSetIPS(); + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "123"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = "456"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"123\"; sid:1;)"))) + goto end; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"3456\"; sid:2;)"))) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 did not match but should have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 2)) { + printf("sid 2 did not match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + EngineModeSetIDS(); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + return result; +} + +/** + * in: buffer: + * [ab] [ab] + * [c] [abc] + * [de] [bcde] + */ +static int DetectEngineHttpServerBodyFileDataTest07(void) +{ + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 1\n\ + response-body-inspect-window: 4\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + EngineModeSetIPS(); + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "ab"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = "c"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + uint8_t http_buf4[] = "de"; + uint32_t http_len4 = sizeof(http_buf4) - 1; + + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"ab\"; sid:1;)"))) + goto end; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"abc\"; sid:2;)"))) + goto end; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"bcde\"; sid:3;)"))) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 did not match but should have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 2)) { + printf("sid 2 did not match but should have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf4, http_len4); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 3)) { + printf("sid 2 did not match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + EngineModeSetIDS(); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + return result; +} + +/** + * in: buffer: + * [abcd] [abcd] + * [efgh] [defgh] + */ +static int DetectEngineHttpServerBodyFileDataTest08(void) +{ + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 1\n\ + response-body-inspect-window: 4\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + EngineModeSetIPS(); + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 8\r\n" + "\r\n" + "abcd"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = "efgh"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"abcd\"; sid:1;)"))) + goto end; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"defgh\"; sid:2;)"))) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 did not match but should have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 2)) { + printf("sid 2 did not match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + EngineModeSetIDS(); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + return result; +} + +/** + * in: buffer: + * [a] [a] + * [b] [ab] + * [c] [abc] + * [d] [abcd] + * [efghijklm] [defghijklm] + */ +static int DetectEngineHttpServerBodyFileDataTest09(void) +{ + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 1\n\ + response-body-inspect-window: 4\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + EngineModeSetIPS(); + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "a"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = "b"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + uint8_t http_buf4[] = "c"; + uint32_t http_len4 = sizeof(http_buf4) - 1; + uint8_t http_buf5[] = "d"; + uint32_t http_len5 = sizeof(http_buf5) - 1; + uint8_t http_buf6[] = "efghijklm"; + uint32_t http_len6 = sizeof(http_buf6) - 1; + + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"abcd\"; sid:1;)"))) + goto end; + + if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"defghijklm\"; sid:2;)"))) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf4, http_len4); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf5, http_len5); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 did not match but should have: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf6, http_len6); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 2)) { + printf("sid 1 did not match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + EngineModeSetIDS(); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + return result; +} #endif /* UNITTESTS */ void DetectEngineHttpServerBodyRegisterTests(void) @@ -3688,6 +4987,18 @@ void DetectEngineHttpServerBodyRegisterTests(void) DetectEngineHttpServerBodyFileDataTest02, 1); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest03", DetectEngineHttpServerBodyFileDataTest03, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest04", + DetectEngineHttpServerBodyFileDataTest04, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest05", + DetectEngineHttpServerBodyFileDataTest05, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest06", + DetectEngineHttpServerBodyFileDataTest06, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest07", + DetectEngineHttpServerBodyFileDataTest07, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest08", + DetectEngineHttpServerBodyFileDataTest08, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest09", + DetectEngineHttpServerBodyFileDataTest09, 1); #endif /* UNITTESTS */ return; From 79d34f4575d55f793ee2cfaf176f458550d243dd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 2 Jun 2015 13:31:47 +0200 Subject: [PATCH 0569/2553] http: body pruning update Take inspect limits into account. Consider per direction inspect settings. --- src/app-layer-htp-body.c | 28 ++++++++++++++++++++-------- src/app-layer-htp-body.h | 2 +- src/app-layer-htp.c | 4 ++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index 0ee1f72bf459..6454fe1c8c3e 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -195,11 +195,13 @@ void HtpBodyFree(HtpBody *body) /** * \brief Free request body chunks that are already fully parsed. * - * \param htud pointer to the HtpTxUserData holding the body + * \param state htp_state, with reference to our config + * \param body the body to prune + * \param direction STREAM_TOSERVER (request), STREAM_TOCLIENT (response) * * \retval none */ -void HtpBodyPrune(HtpState *state, HtpBody *body) +void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) { SCEnter(); @@ -211,7 +213,16 @@ void HtpBodyPrune(HtpState *state, HtpBody *body) SCReturn; } - if (body->body_inspected < state->cfg->response_inspect_min_size) { + /* get the configured inspect sizes. Default to response values */ + uint32_t min_size = state->cfg->response_inspect_min_size; + uint32_t window = state->cfg->response_inspect_window; + + if (direction == STREAM_TOSERVER) { + min_size = state->cfg->request_inspect_min_size; + window = state->cfg->request_inspect_window; + } + + if (body->body_inspected < (min_size > window) ? min_size : window) { SCReturn; } @@ -226,12 +237,13 @@ void HtpBodyPrune(HtpState *state, HtpBody *body) "body->body_parsed %"PRIu64, cur->stream_offset, cur->len, cur->stream_offset + cur->len, body->body_parsed); - uint64_t left_edge = 0; - if (state->cfg->response_inspect_window < body->body_inspected) { - left_edge = body->body_inspected - state->cfg->response_inspect_window; - } + uint64_t left_edge = body->body_inspected; + if (left_edge <= min_size || left_edge <= window) + left_edge = 0; + if (left_edge) + left_edge -= window; - if (cur->stream_offset >= left_edge) { + if (cur->stream_offset + cur->len > left_edge) { break; } diff --git a/src/app-layer-htp-body.h b/src/app-layer-htp-body.h index 950b520e5f21..6d54f0d5f8b2 100644 --- a/src/app-layer-htp-body.h +++ b/src/app-layer-htp-body.h @@ -31,6 +31,6 @@ int HtpBodyAppendChunk(HtpTxUserData *, HtpBody *, uint8_t *, uint32_t); void HtpBodyPrint(HtpBody *); void HtpBodyFree(HtpBody *); -void HtpBodyPrune(HtpState *, HtpBody *); +void HtpBodyPrune(HtpState *, HtpBody *, int); #endif /* __APP_LAYER_HTP_BODY_H__ */ diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 3fd009f57302..c6a6e412beac 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1848,7 +1848,7 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) end: /* see if we can get rid of htp body chunks */ - HtpBodyPrune(hstate, &tx_ud->request_body); + HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER); /* set the new chunk flag */ hstate->flags |= HTP_FLAG_NEW_BODY_SET; @@ -1917,7 +1917,7 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) } /* see if we can get rid of htp body chunks */ - HtpBodyPrune(hstate, &tx_ud->response_body); + HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT); /* set the new chunk flag */ hstate->flags |= HTP_FLAG_NEW_BODY_SET; From 423d5fd0de58c793985d03f052b175791e889a7a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 31 May 2015 10:53:42 +0200 Subject: [PATCH 0570/2553] http: improve inline body tracking Rewrite the sliding window handling for IPS mode for the server body. The buffer used will have the following properties: left edge: inspected data - window_size right edge: the most recent data Due to handling of compressed bodies, the data can be much bigger than the configured window size. --- src/detect-engine-hsbd.c | 100 +++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 77e33b958a12..23898414ba89 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -143,68 +143,78 @@ static void HSBDGetBufferForTXInIPSMode(DetectEngineThreadCtx *det_ctx, HtpTxUserData *htud, int index) { uint32_t window_size = 0; - uint32_t extra_size = 0; int resize = 0; - if (htud->response_body.content_len_so_far <= htp_state->cfg->response_inspect_min_size) { - resize = 1; - window_size = htp_state->cfg->response_inspect_min_size; - } else { + /* how much from before body_inspected will we consider? */ + uint32_t cfg_win = + htud->response_body.body_inspected >= htp_state->cfg->response_inspect_min_size ? + htp_state->cfg->response_inspect_window : + htp_state->cfg->response_inspect_min_size; + + /* but less if we don't have that much before body_inspected */ + if ((htud->response_body.body_inspected - htud->response_body.first->stream_offset) < cfg_win) { + cfg_win = htud->response_body.body_inspected - htud->response_body.first->stream_offset; + } + window_size = (htud->response_body.content_len_so_far - htud->response_body.body_inspected) + cfg_win; + if (window_size > 100*1024) { + SCLogInfo("WEIRD: body size is %uk", window_size/1024); + } + if (window_size > det_ctx->hsbd[index].buffer_size) resize = 1; - window_size = htp_state->cfg->response_inspect_window; + + if (det_ctx->hsbd[index].buffer == NULL || resize) { + void *ptmp; + + if ((ptmp = SCRealloc(det_ctx->hsbd[index].buffer, window_size)) == NULL) { + SCFree(det_ctx->hsbd[index].buffer); + det_ctx->hsbd[index].buffer = NULL; + det_ctx->hsbd[index].buffer_size = 0; + det_ctx->hsbd[index].buffer_len = 0; + return; + } + det_ctx->hsbd[index].buffer = ptmp; + det_ctx->hsbd[index].buffer_size = window_size; + resize = 0; } + uint32_t left_edge = htud->response_body.body_inspected - cfg_win; + int first = 1; while (cur != NULL) { - /* see if we need to grow the buffer */ - if (cur->len > window_size) { - extra_size = window_size * 0.25; - window_size = cur->len; - resize = 1; - } else if (cur->len == window_size) { - window_size = window_size * 1.25; - resize = 1; + if (first) { + det_ctx->hsbd[index].offset = cur->stream_offset; + first = 0; } - if (det_ctx->hsbd[index].buffer == NULL || resize) { - void *ptmp; + /* entirely before our window */ + if ((cur->stream_offset + cur->len) <= left_edge) { + cur = cur->next; + continue; + } else { + uint32_t offset = 0; + if (cur->stream_offset < left_edge && (cur->stream_offset + cur->len) > left_edge) { + offset = left_edge - cur->stream_offset; + BUG_ON(offset > cur->len); + } - if ((ptmp = SCRealloc(det_ctx->hsbd[index].buffer, window_size + extra_size)) == NULL) { - SCFree(det_ctx->hsbd[index].buffer); - det_ctx->hsbd[index].buffer = NULL; - det_ctx->hsbd[index].buffer_size = 0; - det_ctx->hsbd[index].buffer_len = 0; - return; + /* unusual: if window isn't big enough, we just give up */ + if (det_ctx->hsbd[index].buffer_len + (cur->len - offset) > window_size) { + htud->response_body.body_inspected = cur->stream_offset; + SCReturn; } - det_ctx->hsbd[index].buffer = ptmp; - resize = 0; - } - if (first) { - det_ctx->hsbd[index].offset = cur->stream_offset; - first = 0; - } + BUG_ON(det_ctx->hsbd[index].buffer_len + (cur->len - offset) > window_size); - /* - * Copy a part of the previous buffer before the current chunk on. - * For example, let's have the chunks [123], [456]. - * When the current chunk is [456], this copy [3] before. - */ - if (det_ctx->hsbd[index].buffer_len + cur->len > window_size + extra_size) { - uint32_t offset = (det_ctx->hsbd[index].buffer_len + cur->len) - (window_size + extra_size); - /* we use memmove to avoid memory overlap */ - memmove(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer + offset, det_ctx->hsbd[index].buffer_len - offset); - det_ctx->hsbd[index].buffer_len -= offset; - det_ctx->hsbd[index].offset += offset; + memcpy(det_ctx->hsbd[index].buffer + det_ctx->hsbd[index].buffer_len, cur->data + offset, cur->len - offset); + det_ctx->hsbd[index].buffer_len += (cur->len - offset); + det_ctx->hsbd[index].offset -= offset; } - memcpy(det_ctx->hsbd[index].buffer + det_ctx->hsbd[index].buffer_len, cur->data, cur->len); - det_ctx->hsbd[index].buffer_len += cur->len; cur = cur->next; } - /* update inspected tracker */ - htud->response_body.body_inspected = htud->response_body.last->stream_offset + htud->response_body.last->len; + /* update inspected tracker to point before the current window */ + htud->response_body.body_inspected = htud->response_body.content_len_so_far; } static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, @@ -3729,7 +3739,7 @@ libhtp:\n\ default-config:\n\ \n\ http-body-inline: yes\n\ - response-body-minimal-inspect-size: 1\n\ + response-body-minimal-inspect-size: 4\n\ response-body-inspect-window: 4\n\ "; From 9f52bdd1e5541e8a1c3be406422fd5b555d7f9d4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 3 Jun 2015 12:11:22 +0200 Subject: [PATCH 0571/2553] flow timeout: prevent dead locks The flow timeout mechanism called both from the flow manager at run time and at shutdown creates pseudo packets. For this it has it's own packet pool, which can be depleted if the timeout logic is faster than the packet processing threads. In this case the flow timeout would enter a wait loop. The problem however, is that this wait loop would happen while keeping a flow locked. This could lead to a race condition when the packet thread(s) are waiting for the lock that the flow manager has. This patch introduces a new packet pool call 'PacketPoolWaitForN', meant to make sure that the thread's packet pool has at least N available packets. The flow timeout paths use this to make sure enough packets are available *before* grabbing the flow lock. If there aren't enough packets available yet, the wait happens before the lock as well. This still means the wait can happen while the flow hash row is locked, so we do make sure some more packets are available when entering that. But perhaps in the future we need a more precise logic there as well. --- src/flow-manager.c | 13 ++++++++++- src/flow-timeout.c | 3 +++ src/tmqh-packetpool.c | 51 +++++++++++++++++++++++++++++++++++++++++++ src/tmqh-packetpool.h | 1 + 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 2d86b81c6a36..411dcbc88cee 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -285,6 +285,10 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, continue; } + /* before grabbing the flow lock, make sure we have at least + * 3 packets in the pool */ + PacketPoolWaitForN(3); + FLOWLOCK_WRLOCK(f); Flow *next_flow = f->hprev; @@ -377,6 +381,10 @@ static uint32_t FlowTimeoutHash(struct timeval *ts, uint32_t try_cnt, for (idx = hash_min; idx < hash_max; idx++) { FlowBucket *fb = &flow_hash[idx]; + /* before grabbing the row lock, make sure we have at least + * 9 packets in the pool */ + PacketPoolWaitForN(9); + if (FBLOCK_TRYLOCK(fb) != 0) continue; @@ -1220,7 +1228,10 @@ static int FlowMgrTest04 (void) static int FlowMgrTest05 (void) { int result = 0; + extern intmax_t max_pending_packets; + max_pending_packets = 128; + PacketPoolInit(); FlowInitConfig(FLOW_QUIET); FlowConfig backup; memcpy(&backup, &flow_config, sizeof(FlowConfig)); @@ -1258,7 +1269,7 @@ static int FlowMgrTest05 (void) memcpy(&flow_config, &backup, sizeof(FlowConfig)); FlowShutdown(); - + PacketPoolDestroy(); return result; } #endif /* UNITTESTS */ diff --git a/src/flow-timeout.c b/src/flow-timeout.c index f2eb0899289c..b18007939e3b 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -515,6 +515,7 @@ static inline void FlowForceReassemblyForHash(void) for (idx = 0; idx < flow_config.hash_size; idx++) { FlowBucket *fb = &flow_hash[idx]; + PacketPoolWaitForN(9); FBLOCK_LOCK(fb); /* get the topmost flow from the QUEUE */ @@ -522,6 +523,8 @@ static inline void FlowForceReassemblyForHash(void) /* we need to loop through all the flows in the queue */ while (f != NULL) { + PacketPoolWaitForN(3); + FLOWLOCK_WRLOCK(f); /* Get the tcp session for the flow */ diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index 79103a4a01d9..4c4bf40691af 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -157,6 +157,57 @@ void PacketPoolWait(void) cc_barrier(); } +/** \brief Wait until we have the requested ammount of packets in the pool + * + * In some cases waiting for packets is undesirable. Especially when + * a wait would happen under a lock of some kind, other parts of the + * engine could have to wait. + * + * This function only returns when at least N packets are in our pool. + * + * \param n number of packets needed + */ +void PacketPoolWaitForN(int n) +{ + PktPool *my_pool = GetThreadPacketPool(); + Packet *p = NULL; + + while (1) { + int i = 0; + PacketPoolWait(); + + /* count packets in our stack */ + p = my_pool->head; + while (p != NULL) { + if (++i == n) + return; + + p = p->next; + } + + /* continue counting in the return stack */ + if (my_pool->return_stack.head != NULL) { + SCMutexLock(&my_pool->return_stack.mutex); + p = my_pool->return_stack.head; + while (p != NULL) { + if (++i == n) { + SCMutexUnlock(&my_pool->return_stack.mutex); + return; + } + p = p->next; + } + SCMutexUnlock(&my_pool->return_stack.mutex); + + /* or signal that we need packets and wait */ + } else { + SCMutexLock(&my_pool->return_stack.mutex); + SC_ATOMIC_ADD(my_pool->return_stack.sync_now, 1); + SCCondWait(&my_pool->return_stack.cond, &my_pool->return_stack.mutex); + SCMutexUnlock(&my_pool->return_stack.mutex); + } + } +} + /** \brief a initialized packet * * \warning Use *only* at init, not at packet runtime diff --git a/src/tmqh-packetpool.h b/src/tmqh-packetpool.h index 6da6fc6aa855..12a3f5cabdd4 100644 --- a/src/tmqh-packetpool.h +++ b/src/tmqh-packetpool.h @@ -69,6 +69,7 @@ void TmqhReleasePacketsToPacketPool(PacketQueue *); void TmqhPacketpoolRegister(void); Packet *PacketPoolGetPacket(void); void PacketPoolWait(void); +void PacketPoolWaitForN(int n); void PacketPoolReturnPacket(Packet *p); void PacketPoolInit(void); void PacketPoolInitEmpty(void); From 3163a5757726c41a52acee014398a683eee9ea70 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 3 Jun 2015 18:15:55 +0200 Subject: [PATCH 0572/2553] smtp file_data: fix wrong free --- src/detect-engine-filedata-smtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index f3687607f7e3..423db75d2bf4 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -61,7 +61,7 @@ static inline int SMTPCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) ptmp = SCRealloc(det_ctx->smtp, (det_ctx->smtp_buffers_size + BUFFER_STEP) * sizeof(FiledataReassembledBody)); if (ptmp == NULL) { - SCFree(det_ctx->hsbd); + SCFree(det_ctx->smtp); det_ctx->smtp = NULL; det_ctx->smtp_buffers_size = 0; det_ctx->smtp_buffers_list_len = 0; From 573d082219482b985d80defc38886fdde0645d18 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 3 Jun 2015 18:16:33 +0200 Subject: [PATCH 0573/2553] http: memcap HTTP server inspect body code --- src/detect-engine-hsbd.c | 18 +++++++++++------- src/detect-engine.c | 5 +++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 23898414ba89..de37099f2123 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -56,6 +56,7 @@ #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" +#include "app-layer-htp-mem.h" #include "app-layer-protos.h" #include "conf.h" @@ -117,16 +118,17 @@ static void HSBDGetBufferForTXInIDSMode(DetectEngineThreadCtx *det_ctx, /* see if we need to grow the buffer */ if (det_ctx->hsbd[index].buffer == NULL || (det_ctx->hsbd[index].buffer_len + cur->len) > det_ctx->hsbd[index].buffer_size) { void *ptmp; - det_ctx->hsbd[index].buffer_size += cur->len * 2; + uint32_t newsize = det_ctx->hsbd[index].buffer_size + (cur->len * 2); - if ((ptmp = SCRealloc(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size)) == NULL) { - SCFree(det_ctx->hsbd[index].buffer); + if ((ptmp = HTPRealloc(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size, newsize)) == NULL) { + HTPFree(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size); det_ctx->hsbd[index].buffer = NULL; det_ctx->hsbd[index].buffer_size = 0; det_ctx->hsbd[index].buffer_len = 0; return; } det_ctx->hsbd[index].buffer = ptmp; + det_ctx->hsbd[index].buffer_size = newsize; } memcpy(det_ctx->hsbd[index].buffer + det_ctx->hsbd[index].buffer_len, cur->data, cur->len); det_ctx->hsbd[index].buffer_len += cur->len; @@ -138,6 +140,7 @@ static void HSBDGetBufferForTXInIDSMode(DetectEngineThreadCtx *det_ctx, htud->response_body.body_inspected = htud->response_body.last->stream_offset + htud->response_body.last->len; } +#define MAX_WINDOW 10*1024*1024 static void HSBDGetBufferForTXInIPSMode(DetectEngineThreadCtx *det_ctx, HtpState *htp_state, HtpBodyChunk *cur, HtpTxUserData *htud, int index) @@ -156,8 +159,9 @@ static void HSBDGetBufferForTXInIPSMode(DetectEngineThreadCtx *det_ctx, cfg_win = htud->response_body.body_inspected - htud->response_body.first->stream_offset; } window_size = (htud->response_body.content_len_so_far - htud->response_body.body_inspected) + cfg_win; - if (window_size > 100*1024) { - SCLogInfo("WEIRD: body size is %uk", window_size/1024); + if (window_size > MAX_WINDOW) { + SCLogDebug("weird: body size is %uk", window_size/1024); + window_size = MAX_WINDOW; } if (window_size > det_ctx->hsbd[index].buffer_size) resize = 1; @@ -165,8 +169,8 @@ static void HSBDGetBufferForTXInIPSMode(DetectEngineThreadCtx *det_ctx, if (det_ctx->hsbd[index].buffer == NULL || resize) { void *ptmp; - if ((ptmp = SCRealloc(det_ctx->hsbd[index].buffer, window_size)) == NULL) { - SCFree(det_ctx->hsbd[index].buffer); + if ((ptmp = HTPRealloc(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size, window_size)) == NULL) { + HTPFree(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size); det_ctx->hsbd[index].buffer = NULL; det_ctx->hsbd[index].buffer_size = 0; det_ctx->hsbd[index].buffer_len = 0; diff --git a/src/detect-engine.c b/src/detect-engine.c index 74bcb2a329c7..3017f2b32e2e 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1466,8 +1466,9 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) if (det_ctx->hsbd != NULL) { SCLogDebug("det_ctx hsbd %u", det_ctx->hsbd_buffers_size); for (i = 0; i < det_ctx->hsbd_buffers_size; i++) { - if (det_ctx->hsbd[i].buffer != NULL) - SCFree(det_ctx->hsbd[i].buffer); + if (det_ctx->hsbd[i].buffer != NULL) { + HTPFree(det_ctx->hsbd[i].buffer, det_ctx->hsbd[i].buffer_size); + } } SCFree(det_ctx->hsbd); } From 32563d51d155decb77fea6af8f3616feb7f01e7d Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 8 Jun 2015 14:06:24 +0200 Subject: [PATCH 0574/2553] http: rework UT This reworks UT based on commit 320355570863dfa6376c9d2af875495ccc8a199f --- src/detect-engine-hsbd.c | 1768 ++++++++++++++------------------------ 1 file changed, 631 insertions(+), 1137 deletions(-) diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index de37099f2123..beba23966bbb 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -393,6 +393,123 @@ void DetectEngineCleanHSBDBuffers(DetectEngineThreadCtx *det_ctx) #ifdef UNITTESTS +struct TestSteps { + const uint8_t *input; + size_t input_size; /**< if 0 strlen will be used */ + int direction; /**< STREAM_TOSERVER, STREAM_TOCLIENT */ + int expect; +}; + +static int RunTest(struct TestSteps *steps, const char *sig, const char *yaml) +{ + TcpSession ssn; + Flow f; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; + int i = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + if (yaml) { + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(yaml, strlen(yaml)); + HTPConfigure(); + EngineModeSetIPS(); + } + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + f.alproto = ALPROTO_HTTP; + + SCLogDebug("sig %s", sig); + DetectEngineAppendSig(de_ctx, (char *)sig); + + de_ctx->flags |= DE_QUIET; + + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + struct TestSteps *b = steps; + i = 0; + while (b->input != NULL) { + SCLogDebug("chunk %p %d", b, i); + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + if (p == NULL) + goto end; + p->flow = &f; + p->flowflags = (b->direction == STREAM_TOSERVER) ? FLOW_PKT_TOSERVER : FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, b->direction, + (uint8_t *)b->input, + b->input_size ? b->input_size : strlen((const char *)b->input)); + if (r != 0) { + printf("toserver chunk %d returned %" PRId32 ", expected 0: ", i+1, r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + int match = PacketAlertCheck(p, 1); + if (b->expect != match) { + printf("rule matching mismatch: "); + goto end; + } + + UTHFreePackets(&p, 1); + p = NULL; + b++; + i++; + } + result = 1; + + end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + + if (yaml) { + HtpConfigRestoreBackup(); + ConfRestoreContextBackup(); + EngineModeSetIDS(); + } + return result; +} + static int DetectEngineHttpServerBodyTest01(void) { TcpSession ssn; @@ -3723,19 +3840,10 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) return result; } -/* - * Tests buffer inspection like in ips mode, - * here all chunks size are smaller than the window_size. - - * in: buffer: - * [ab] [ab] - * [cd] [abcd] - * [ef] [cdef] -*/ static int DetectEngineHttpServerBodyFileDataTest04(void) { - char input[] = "\ + const char yaml[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ @@ -3743,999 +3851,265 @@ libhtp:\n\ default-config:\n\ \n\ http-body-inline: yes\n\ - response-body-minimal-inspect-size: 4\n\ - response-body-inspect-window: 4\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ "; - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - EngineModeSetIPS(); - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "ab"; - uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = "cd"; - uint32_t http_len3 = sizeof(http_buf3) - 1; - uint8_t http_buf4[] = "ef"; - uint32_t http_len4 = sizeof(http_buf4) - 1; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"ef", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + const char *sig = "alert http any any -> any any (file_data; content:\"abcd\"; sid:1;)"; + return RunTest(steps, sig, yaml); +} - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); +static int DetectEngineHttpServerBodyFileDataTest05(void) +{ - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ef", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; + const char *sig = "alert http any any -> any any (file_data; content:\"abcdef\"; sid:1;)"; + return RunTest(steps, sig, yaml); +} - StreamTcpInitConfig(TRUE); +static int DetectEngineHttpServerBodyFileDataTest06(void) +{ - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - de_ctx->flags |= DE_QUIET; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ef", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"ab\"; sid:1;)"))) - goto end; - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"bc\"; sid:2;)"))) - goto end; - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"cdef\"; sid:3;)"))) - goto end; - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"ef\"; sid:4;)"))) - goto end; + const char *sig = "alert http any any -> any any (file_data; content:\"bcdef\"; offset:1; sid:1;)"; + return RunTest(steps, sig, yaml); +} - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); +static int DetectEngineHttpServerBodyFileDataTest07(void) +{ - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"123456789", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + const char *sig = "alert http any any -> any any (file_data; content:\"bc\"; offset:1; depth:2; sid:1;)"; + return RunTest(steps, sig, yaml); +} - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } +static int DetectEngineHttpServerBodyFileDataTest08(void) +{ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"1234567890", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 did not match but should have: "); - goto end; - } + const char *sig = "alert http any any -> any any (file_data; content:\"d123456789\"; offset:3; sid:1;)"; + return RunTest(steps, sig, yaml); +} - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); +static int DetectEngineHttpServerBodyFileDataTest09(void) +{ - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - if (!PacketAlertCheck(p2, 2)) { - printf("sid 2 did not match but should have: "); - goto end; - } + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"123456789", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf4, http_len4); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + const char *sig = "alert http any any -> any any (file_data; content:\"abcd12\"; depth:6; sid:1;)"; + return RunTest(steps, sig, yaml); +} - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); +static int DetectEngineHttpServerBodyFileDataTest10(void) +{ - if (!PacketAlertCheck(p2, 3)) { - printf("sid 3 did not match but should have: "); - goto end; - } - - if (!PacketAlertCheck(p2, 4)) { - printf("sid 4 did not match but should have: "); - goto end; - } - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - EngineModeSetIDS(); - ConfDeInit(); - ConfRestoreContextBackup(); - return result; -} - -/* - * Tests buffer inspection like in ips mode, - * here the last chunk size is greater than the window size. - - * in: buffer: - * [ab] [ab] - * [cd] [abcd] - * [12345678] [d12345678] -*/ -static int DetectEngineHttpServerBodyFileDataTest05(void) -{ - - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ -\n\ - http-body-inline: yes\n\ - response-body-minimal-inspect-size: 1\n\ - response-body-inspect-window: 4\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - EngineModeSetIPS(); - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 12\r\n" - "\r\n" - "ab"; - uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = "cd"; - uint32_t http_len3 = sizeof(http_buf3) - 1; - uint8_t http_buf4[] = "12345678"; - uint32_t http_len4 = sizeof(http_buf4) - 1; - - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"ab\"; sid:1;)"))) - goto end; - - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"abcd\"; sid:2;)"))) - goto end; - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"d12345678\"; sid:3;)"))) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 did not match but should have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 2)) { - printf("sid 2 did not match but should have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf4, http_len4); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 3)) { - printf("sid 3 did not match but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - EngineModeSetIDS(); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - return result; -} - -/** - * in: buffer: - * [123] [123] - * [456] [3456] - */ -static int DetectEngineHttpServerBodyFileDataTest06(void) -{ - - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ -\n\ - http-body-inline: yes\n\ - response-body-minimal-inspect-size: 1\n\ - response-body-inspect-window: 4\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - EngineModeSetIPS(); - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "123"; - uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = "456"; - uint32_t http_len3 = sizeof(http_buf3) - 1; - - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"123\"; sid:1;)"))) - goto end; - - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"3456\"; sid:2;)"))) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 did not match but should have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 2)) { - printf("sid 2 did not match but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - EngineModeSetIDS(); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - return result; -} - -/** - * in: buffer: - * [ab] [ab] - * [c] [abc] - * [de] [bcde] - */ -static int DetectEngineHttpServerBodyFileDataTest07(void) -{ - - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ -\n\ - http-body-inline: yes\n\ - response-body-minimal-inspect-size: 1\n\ - response-body-inspect-window: 4\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - EngineModeSetIPS(); - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 5\r\n" - "\r\n" - "ab"; - uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = "c"; - uint32_t http_len3 = sizeof(http_buf3) - 1; - uint8_t http_buf4[] = "de"; - uint32_t http_len4 = sizeof(http_buf4) - 1; - - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"ab\"; sid:1;)"))) - goto end; - - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"abc\"; sid:2;)"))) - goto end; - - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"bcde\"; sid:3;)"))) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 did not match but should have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 2)) { - printf("sid 2 did not match but should have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf4, http_len4); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 3)) { - printf("sid 2 did not match but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - EngineModeSetIDS(); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - return result; -} - -/** - * in: buffer: - * [abcd] [abcd] - * [efgh] [defgh] - */ -static int DetectEngineHttpServerBodyFileDataTest08(void) -{ - - char input[] = "\ + const char yaml[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ -\n\ - http-body-inline: yes\n\ - response-body-minimal-inspect-size: 1\n\ - response-body-inspect-window: 4\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - EngineModeSetIPS(); - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 8\r\n" - "\r\n" - "abcd"; - uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = "efgh"; - uint32_t http_len3 = sizeof(http_buf3) - 1; - - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"abcd\"; sid:1;)"))) - goto end; - - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"defgh\"; sid:2;)"))) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 did not match but should have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 2)) { - printf("sid 2 did not match but should have: "); - goto end; - } - - result = 1; +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", + 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"de", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - EngineModeSetIDS(); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - return result; + const char *sig = "alert http any any -> any any (file_data; content:\"abc\"; depth:3; sid:1;)"; + return RunTest(steps, sig, yaml); } -/** - * in: buffer: - * [a] [a] - * [b] [ab] - * [c] [abc] - * [d] [abcd] - * [efghijklm] [defghijklm] - */ -static int DetectEngineHttpServerBodyFileDataTest09(void) +static int DetectEngineHttpServerBodyFileDataTest11(void) { - char input[] = "\ + const char yaml[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ @@ -4743,206 +4117,307 @@ libhtp:\n\ default-config:\n\ \n\ http-body-inline: yes\n\ - response-body-minimal-inspect-size: 1\n\ - response-body-inspect-window: 4\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ "; - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"de", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - EngineModeSetIPS(); - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 13\r\n" - "\r\n" - "a"; - uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = "b"; - uint32_t http_len3 = sizeof(http_buf3) - 1; - uint8_t http_buf4[] = "c"; - uint32_t http_len4 = sizeof(http_buf4) - 1; - uint8_t http_buf5[] = "d"; - uint32_t http_len5 = sizeof(http_buf5) - 1; - uint8_t http_buf6[] = "efghijklm"; - uint32_t http_len6 = sizeof(http_buf6) - 1; + const char *sig = "alert http any any -> any any (file_data; content:\"bcde\"; offset:1; depth:4; sid:1;)"; + return RunTest(steps, sig, yaml); +} - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); +static int DetectEngineHttpServerBodyFileDataTest12(void) +{ - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "a", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"b", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"d", + 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"efghijklm", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; + const char *sig = "alert http any any -> any any (file_data; content:\"abcd\"; sid:1;)"; + return RunTest(steps, sig, yaml); +} - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; +static int DetectEngineHttpServerBodyFileDataTest13(void) +{ - StreamTcpInitConfig(TRUE); + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "a", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"b", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"d", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"efghijklm", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; - de_ctx->flags |= DE_QUIET; + const char *sig = "alert http any any -> any any (file_data; content:\"abcdefghijklm\"; sid:1;)"; + return RunTest(steps, sig, yaml); +} - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"abcd\"; sid:1;)"))) - goto end; +static int DetectEngineHttpServerBodyFileDataTest14(void) +{ - if (!(DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"defghijklm\"; sid:2;)"))) - goto end; + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "1234567890", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"abcdefghi", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + const char *sig = "alert http any any -> any any (file_data; content:\"890abcdefghi\"; sid:1;)"; + return RunTest(steps, sig, yaml); +} - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } +static int DetectEngineHttpServerBodyFileDataTest15(void) +{ - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "1234567890", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"abcdefghi", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + const char *sig = "alert http any any -> any any (file_data; content:\"7890ab\"; depth:6; sid:1;)"; + return RunTest(steps, sig, yaml); +} - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); +static int DetectEngineHttpServerBodyFileDataTest16(void) +{ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf4, http_len4); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf5, http_len5); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "aaaab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"bbbbc", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ccccd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"dddde", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + const char *sig = "alert http any any -> any any (file_data; content:\"aabb\"; depth:4; sid:1;)"; + return RunTest(steps, sig, yaml); +} - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 did not match but should have: "); - goto end; - } +static int DetectEngineHttpServerBodyFileDataTest17(void) +{ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf6, http_len6); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "aaaab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"bbbbc", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ccccd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"dddde", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; - if (!PacketAlertCheck(p2, 2)) { - printf("sid 1 did not match but should have: "); - goto end; - } + const char *sig = "alert http any any -> any any (file_data; content:\"bbbc\"; depth:4; sid:1;)"; + return RunTest(steps, sig, yaml); +} - result = 1; +static int DetectEngineHttpServerBodyFileDataTest18(void) +{ -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - EngineModeSetIDS(); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - return result; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "aaaab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"bbbbc", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ccccd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"dddde", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"bccd\"; depth:4; sid:1;)"; + return RunTest(steps, sig, yaml); } #endif /* UNITTESTS */ @@ -5013,6 +4488,25 @@ void DetectEngineHttpServerBodyRegisterTests(void) DetectEngineHttpServerBodyFileDataTest08, 1); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest09", DetectEngineHttpServerBodyFileDataTest09, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest10", + DetectEngineHttpServerBodyFileDataTest10, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest11", + DetectEngineHttpServerBodyFileDataTest11, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest12", + DetectEngineHttpServerBodyFileDataTest12, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest13", + DetectEngineHttpServerBodyFileDataTest13, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest14", + DetectEngineHttpServerBodyFileDataTest14, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest15", + DetectEngineHttpServerBodyFileDataTest15, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest16", + DetectEngineHttpServerBodyFileDataTest16, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest17", + DetectEngineHttpServerBodyFileDataTest17, 1); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest18", + DetectEngineHttpServerBodyFileDataTest18, 1); + #endif /* UNITTESTS */ return; From 3ffa01d15098f236e2679c4a094fabce4a4c0b9e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 5 Jun 2015 09:54:44 +0200 Subject: [PATCH 0575/2553] stream: remove STREAMTCP_STREAM_FLAG_CLOSE_INITIATED logic --- src/stream-tcp-private.h | 3 +-- src/stream-tcp.c | 39 --------------------------------------- 2 files changed, 1 insertion(+), 41 deletions(-) diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 4e64da6e8192..5c03c4bcd7a0 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -157,8 +157,7 @@ enum #define STREAMTCP_STREAM_FLAG_KEEPALIVE 0x0004 /** Stream has reached it's reassembly depth, all further packets are ignored */ #define STREAMTCP_STREAM_FLAG_DEPTH_REACHED 0x0008 -/** Stream has sent a FIN/RST */ -#define STREAMTCP_STREAM_FLAG_CLOSE_INITIATED 0x0010 +// vacancy /** Stream supports TIMESTAMP -- used to set ssn STREAMTCP_FLAG_TIMESTAMP * flag. */ #define STREAMTCP_STREAM_FLAG_TIMESTAMP 0x0020 diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 9f2fbefd620b..c810ea75c0a1 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -1288,15 +1288,11 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1))) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); } } else { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); } @@ -1615,8 +1611,6 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, if (reset == TRUE) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); @@ -2281,8 +2275,6 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, if (PKT_IS_TOSERVER(p)) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); @@ -2313,8 +2305,6 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, * cleanup. */ } else { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); @@ -2512,7 +2502,6 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, } StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT); - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn); if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) @@ -2560,7 +2549,6 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, } StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn); if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) @@ -2617,8 +2605,6 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -2684,7 +2670,6 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; @@ -2741,7 +2726,6 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -2806,7 +2790,6 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_CLOSING); - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; @@ -2864,7 +2847,6 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_CLOSING); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -3077,8 +3059,6 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -3148,7 +3128,6 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; @@ -3203,7 +3182,6 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -3387,8 +3365,6 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -3569,8 +3545,6 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -3689,7 +3663,6 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -3863,8 +3836,6 @@ static int StreamTcpPacketStateLastAck(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -3990,8 +3961,6 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -4595,14 +4564,6 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, if (ssn->state >= TCP_ESTABLISHED) { p->flags |= PKT_STREAM_EST; } - - if (PKT_IS_TOSERVER(p)) { - if (ssn->client.flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) - p->flags |= PKT_STREAM_EOF; - } else { - if (ssn->server.flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) - p->flags |= PKT_STREAM_EOF; - } } /* deal with a pseudo packet that is created upon receiving a RST From 7451d3339689d6705fbaed307f44dbc3452a629e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 5 Jun 2015 12:30:05 +0200 Subject: [PATCH 0576/2553] stream: update StreamMsg to don't have fixed size StreamMsg would have a fixed size buffer. This patch replaces the buffer by a dynamically allocated buffer. Preparation of allowing bigger and customizable buffer sizes. --- src/stream-tcp-reassemble.c | 305 +++++++----------------------------- src/stream.c | 26 +-- src/stream.h | 17 +- 3 files changed, 77 insertions(+), 271 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index c0979b9459ad..caf955afa1a5 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2176,14 +2176,14 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, uint32_t ra_base_seq = stream->ra_raw_base_seq; StreamMsg *smsg = NULL; - uint16_t smsg_offset = 0; + uint32_t smsg_offset = 0; uint16_t payload_offset = 0; uint16_t payload_len = 0; TcpSegment *seg = stream->seg_list; uint32_t next_seq = ra_base_seq + 1; int gap = 0; - uint16_t chunk_size = PKT_IS_TOSERVER(p) ? + uint32_t chunk_size = PKT_IS_TOSERVER(p) ? stream_config.reassembly_toserver_chunk_size : stream_config.reassembly_toclient_chunk_size; @@ -2314,12 +2314,12 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, } /* copy the data into the smsg */ - uint16_t copy_size = sizeof (smsg->data) - smsg_offset; + uint32_t copy_size = smsg->data_size - smsg_offset; if (copy_size > payload_len) { copy_size = payload_len; } if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(smsg->data)); + BUG_ON(copy_size > smsg->data_size); } SCLogDebug("copy_size is %"PRIu16"", copy_size); memcpy(smsg->data + smsg_offset, seg->payload + payload_offset, @@ -2337,7 +2337,7 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, smsg->data_len += copy_size; /* queue the smsg if it's full */ - if (smsg->data_len == sizeof (smsg->data)) { + if (smsg->data_len == smsg->data_size) { StreamTcpStoreStreamChunk(ssn, smsg, p, 1); stream->ra_raw_base_seq = ra_base_seq; smsg = NULL; @@ -2376,12 +2376,12 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, StreamTcpSetupMsg(ssn, stream,p,smsg); smsg->seq = ra_base_seq + 1; - copy_size = sizeof(smsg->data) - smsg_offset; - if (copy_size > (seg->payload_len - payload_offset)) { + copy_size = smsg->data_size - smsg_offset; + if ((int32_t)copy_size > (seg->payload_len - payload_offset)) { copy_size = (seg->payload_len - payload_offset); } if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(smsg->data)); + BUG_ON(copy_size > smsg->data_size); } SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset " @@ -2398,7 +2398,7 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, SCLogDebug("copied payload_offset %" PRIu32 ", " "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "", payload_offset, smsg_offset, copy_size); - if (smsg->data_len == sizeof (smsg->data)) { + if (smsg->data_len == smsg->data_size) { StreamTcpStoreStreamChunk(ssn, smsg, p, 1); stream->ra_raw_base_seq = ra_base_seq; smsg = NULL; @@ -2743,7 +2743,7 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, return 0; } - /* copy the data into the smsg */ + /* copy the data into the buffer */ uint16_t copy_size = sizeof(rd->data) - rd->data_len; if (copy_size > payload_len) { copy_size = payload_len; @@ -3047,7 +3047,7 @@ typedef struct ReassembleRawData_ { uint32_t ra_base_seq; int partial; /* last segment was processed only partially */ StreamMsg *smsg; - uint16_t smsg_offset; // TODO diff with smsg->data_len? + uint32_t smsg_offset; // TODO diff with smsg->data_len? } ReassembleRawData; static void DoHandleRawGap(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, Packet *p, @@ -3154,12 +3154,12 @@ static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, } /* copy the data into the smsg */ - uint16_t copy_size = sizeof (rd->smsg->data) - rd->smsg_offset; + uint32_t copy_size = rd->smsg->data_size - rd->smsg_offset; if (copy_size > payload_len) { copy_size = payload_len; } if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(rd->smsg->data)); + BUG_ON(copy_size > rd->smsg->data_size); } SCLogDebug("copy_size is %"PRIu16"", copy_size); memcpy(rd->smsg->data + rd->smsg_offset, seg->payload + payload_offset, @@ -3171,7 +3171,7 @@ static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, rd->smsg->data_len += copy_size; /* queue the smsg if it's full */ - if (rd->smsg->data_len == sizeof (rd->smsg->data)) { + if (rd->smsg->data_len == rd->smsg->data_size) { StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0); stream->ra_raw_base_seq = rd->ra_base_seq; rd->smsg = NULL; @@ -3211,12 +3211,12 @@ static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, StreamTcpSetupMsg(ssn, stream, p, rd->smsg); rd->smsg->seq = rd->ra_base_seq + 1; - copy_size = sizeof(rd->smsg->data) - rd->smsg_offset; + copy_size = rd->smsg->data_size - rd->smsg_offset; if (copy_size > payload_len) { copy_size = payload_len; } if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(rd->smsg->data)); + BUG_ON(copy_size > rd->smsg->data_size); } SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset " @@ -3231,7 +3231,7 @@ static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, SCLogDebug("copied payload_offset %" PRIu32 ", " "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "", payload_offset, rd->smsg_offset, copy_size); - if (rd->smsg->data_len == sizeof(rd->smsg->data)) { + if (rd->smsg->data_len == rd->smsg->data_size) { StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0); stream->ra_raw_base_seq = rd->ra_base_seq; rd->smsg = NULL; @@ -3640,6 +3640,25 @@ void StreamTcpReassembleTriggerRawReassembly(TcpSession *ssn) #ifdef UNITTESTS /** unit tests and it's support functions below */ +static int UtTestSmsg(StreamMsg *smsg, const uint8_t *buf, uint32_t buf_len) +{ + if (smsg == NULL) + return 0; + + if (smsg->data_len != buf_len) { + return 0; + } + + if (!(memcmp(buf, smsg->data, buf_len) == 0)) { + printf("data is not what we expected:\nExpected:\n"); + PrintRawDataFp(stdout, (uint8_t *)buf, buf_len); + printf("Got:\n"); + PrintRawDataFp(stdout, smsg->data, smsg->data_len); + return 0; + } + return 1; +} + static uint32_t UtSsnSmsgCnt(TcpSession *ssn, uint8_t direction) { uint32_t cnt = 0; @@ -7560,18 +7579,8 @@ static int StreamTcpReassembleInlineTest01(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); + if (UtTestSmsg(smsg, stream_payload, 15) == 0) goto end; - } - - if (!(memcmp(stream_payload, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); - goto end; - } ret = 1; end: @@ -7640,18 +7649,8 @@ static int StreamTcpReassembleInlineTest02(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 15) == 0) goto end; - } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); @@ -7671,18 +7670,8 @@ static int StreamTcpReassembleInlineTest02(void) } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 20) { - printf("expected data length to be 20, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 20) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 20); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 20) == 0) goto end; - } ret = 1; end: @@ -7755,18 +7744,8 @@ static int StreamTcpReassembleInlineTest03(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 15) == 0) goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); - goto end; - } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); @@ -7788,18 +7767,8 @@ static int StreamTcpReassembleInlineTest03(void) } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 15) == 0) goto end; - } ret = 1; end: @@ -7872,18 +7841,8 @@ static int StreamTcpReassembleInlineTest04(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 15) == 0) goto end; - } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); @@ -7905,18 +7864,8 @@ static int StreamTcpReassembleInlineTest04(void) } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 16) { - printf("expected data length to be 16, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 16) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 16); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 16) == 0) goto end; - } ret = 1; end: @@ -7986,32 +7935,12 @@ static int StreamTcpReassembleInlineTest05(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 10) { - printf("expected data length to be 10, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 10) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 10); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 10) == 0) goto end; - } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 5) { - printf("expected data length to be 5, got %u: ", smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 5) == 0) goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 5) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 5); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); - goto end; - } ret = 1; end: @@ -8082,32 +8011,12 @@ static int StreamTcpReassembleInlineTest06(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 10) { - printf("expected data length to be 10, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 10) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 10); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 10) == 0) goto end; - } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 5) { - printf("expected data length to be 5, got %u: ", smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 5) == 0) goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 5) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 5); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); - goto end; - } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); @@ -8129,18 +8038,8 @@ static int StreamTcpReassembleInlineTest06(void) } smsg = ssn.toserver_smsg_head->next->next; - if (smsg->data_len != 20) { - printf("expected data length to be 20, got %u: ", smsg->data_len); + if (UtTestSmsg(smsg, stream_payload3, 20) == 0) goto end; - } - - if (!(memcmp(stream_payload3, smsg->data, 20) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload3, 20); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); - goto end; - } ret = 1; end: @@ -8215,32 +8114,12 @@ static int StreamTcpReassembleInlineTest07(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 6) { - printf("expected data length to be 6, got %u: ", smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 6) == 0) goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 6) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 6); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); - goto end; - } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 5) { - printf("expected data length to be 5, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 5) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 5); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 5) == 0) goto end; - } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); @@ -8262,18 +8141,8 @@ static int StreamTcpReassembleInlineTest07(void) } smsg = ssn.toserver_smsg_head->next->next; - if (smsg->data_len != 16) { - printf("expected data length to be 16, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload3, smsg->data, 16) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload3, 16); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload3, 16) == 0) goto end; - } ret = 1; end: @@ -8348,18 +8217,8 @@ static int StreamTcpReassembleInlineTest08(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 15) == 0) goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); - goto end; - } if (ssn.client.ra_raw_base_seq != 16) { printf("ra_raw_base_seq %"PRIu32", expected 16: ", ssn.client.ra_raw_base_seq); @@ -8386,18 +8245,8 @@ static int StreamTcpReassembleInlineTest08(void) } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 15) == 0) goto end; - } if (ssn.client.ra_raw_base_seq != 21) { printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq); @@ -8483,32 +8332,12 @@ static int StreamTcpReassembleInlineTest09(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 10) { - printf("expected data length to be 10, got %u (bot): ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 10) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 10); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 10) == 0) goto end; - } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 5) { - printf("expected data length to be 5, got %u (top): ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 5) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 5); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 5) == 0) goto end; - } if (ssn.client.ra_raw_base_seq != 11) { printf("ra_raw_base_seq %"PRIu32", expected 11: ", ssn.client.ra_raw_base_seq); @@ -8536,18 +8365,8 @@ static int StreamTcpReassembleInlineTest09(void) } smsg = ssn.toserver_smsg_head->next->next; - if (smsg->data_len != 20) { - printf("expected data length to be 20, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload3, smsg->data, 20) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload3, 20); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload3, 20) == 0) goto end; - } if (ssn.client.ra_raw_base_seq != 21) { printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq); @@ -8718,18 +8537,8 @@ static int StreamTcpReassembleInsertTest01(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 20) { - printf("expected data length to be 20, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 20) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 20); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 20) == 0) goto end; - } if (ssn.client.ra_raw_base_seq != 21) { printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq); diff --git a/src/stream.c b/src/stream.c index 6d77890bbbde..8aabd6dcaea6 100644 --- a/src/stream.c +++ b/src/stream.c @@ -133,25 +133,31 @@ void StreamMsgPutInQueue(StreamMsgQueue *q, StreamMsg *s) SCLogDebug("q->len %" PRIu32 "", q->len); } +#define SIZE 4072 void *StreamMsgPoolAlloc(void) { - if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(StreamMsg)) == 0) + if (StreamTcpReassembleCheckMemcap((uint32_t)(sizeof(StreamMsg)+SIZE)) == 0) return NULL; - StreamMsg *m = SCMalloc(sizeof(StreamMsg)); - if (m != NULL) - StreamTcpReassembleIncrMemuse((uint32_t)sizeof(StreamMsg)); + StreamMsg *m = SCCalloc(1, (sizeof(StreamMsg) + SIZE)); + if (m != NULL) { + m->data = (uint8_t *)m + sizeof(StreamMsg); + m->data_size = SIZE; + + StreamTcpReassembleIncrMemuse((uint32_t)(sizeof(StreamMsg)+SIZE)); + } return m; } int StreamMsgInit(void *data, void *initdata) { - memset(data, 0, sizeof(StreamMsg)); + StreamMsg *s = data; + memset(s->data, 0, s->data_size); #ifdef DEBUG SCMutexLock(&stream_pool_memuse_mutex); - stream_pool_memuse += sizeof(StreamMsg); + stream_pool_memuse += (sizeof(StreamMsg) + SIZE); stream_pool_memcnt ++; SCMutexUnlock(&stream_pool_memuse_mutex); #endif @@ -162,7 +168,7 @@ void StreamMsgPoolFree(void *ptr) { if (ptr) { SCFree(ptr); - StreamTcpReassembleDecrMemuse((uint32_t)sizeof(StreamMsg)); + StreamTcpReassembleDecrMemuse((uint32_t)(sizeof(StreamMsg)+SIZE)); } } @@ -228,12 +234,6 @@ void StreamMsgQueueFree(StreamMsgQueue *q) StreamTcpReassembleDecrMemuse((uint32_t)sizeof(StreamMsgQueue)); } -StreamMsgQueue *StreamMsgQueueGetByPort(uint16_t port) -{ - /* XXX implement this */ - return NULL;//&stream_q; -} - void StreamMsgQueueSetMinChunkLen(uint8_t dir, uint16_t len) { if (dir == FLOW_PKT_TOSERVER) { diff --git a/src/stream.h b/src/stream.h index 6a5b75427543..dfe5c342e88c 100644 --- a/src/stream.h +++ b/src/stream.h @@ -30,11 +30,8 @@ #define STREAM_EOF 0x02 #define STREAM_TOSERVER 0x04 #define STREAM_TOCLIENT 0x08 -#define STREAM_GAP 0x10 /* data gap encountered */ -#define STREAM_DEPTH 0x20 /* depth reached */ - -/** size of the data chunks sent to the app layer parser. */ -#define MSG_DATA_SIZE 4072 /* 4096 - 24 (size of rest of the struct) */ +#define STREAM_GAP 0x10 /**< data gap encountered */ +#define STREAM_DEPTH 0x20 /**< depth reached */ typedef struct StreamMsg_ { struct StreamMsg_ *next; @@ -42,14 +39,15 @@ typedef struct StreamMsg_ { uint32_t seq; /**< sequence number */ uint32_t data_len; /**< length of the data */ - uint8_t data[MSG_DATA_SIZE]; /**< reassembled data */ + uint32_t data_size; + uint8_t *data; /**< reassembled data: ptr to after this + * struct */ } StreamMsg; typedef struct StreamMsgQueue_ { StreamMsg *top; StreamMsg *bot; uint16_t len; - //uint8_t flags; #ifdef DBG_PERF uint16_t dbg_maxlen; #endif /* DBG_PERF */ @@ -66,7 +64,6 @@ void StreamMsgPutInQueue(StreamMsgQueue *, StreamMsg *); StreamMsgQueue *StreamMsgQueueGetNew(void); void StreamMsgQueueFree(StreamMsgQueue *); -StreamMsgQueue *StreamMsgQueueGetByPort(uint16_t); void StreamMsgQueueSetMinChunkLen(uint8_t dir, uint16_t len); uint16_t StreamMsgQueueGetMinChunkLen(uint8_t); @@ -75,8 +72,8 @@ void StreamMsgReturnListToPool(void *); typedef int (*StreamSegmentCallback)(const Packet *, void *, uint8_t *, uint32_t); int StreamSegmentForEach(const Packet *p, uint8_t flag, - StreamSegmentCallback CallbackFunc, - void *data); + StreamSegmentCallback CallbackFunc, + void *data); #endif /* __STREAM_H__ */ From df79c1019f6315154b1527fb190d57f9a865598f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 5 Jun 2015 12:47:28 +0200 Subject: [PATCH 0577/2553] print: make PrintRawDataFp take a const arg --- src/util-print.c | 2 +- src/util-print.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-print.c b/src/util-print.c index 8cdf0c47e9ec..3e34756c7a0d 100644 --- a/src/util-print.c +++ b/src/util-print.c @@ -133,7 +133,7 @@ void PrintRawUriBuf(char *retbuf, uint32_t *offset, uint32_t retbuflen, return; } -void PrintRawDataFp(FILE *fp, uint8_t *buf, uint32_t buflen) +void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen) { int ch = 0; uint32_t u = 0; diff --git a/src/util-print.h b/src/util-print.h index bbd1e719f91b..a696a98aa3c3 100644 --- a/src/util-print.h +++ b/src/util-print.h @@ -46,7 +46,7 @@ void PrintRawUriFp(FILE *, uint8_t *, uint32_t); void PrintRawUriBuf(char *, uint32_t *, uint32_t, uint8_t *, uint32_t); void PrintRawJsonFp(FILE *, uint8_t *, uint32_t); -void PrintRawDataFp(FILE *, uint8_t *, uint32_t); +void PrintRawDataFp(FILE *, const uint8_t *, uint32_t); void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, uint8_t *src_buf, uint32_t src_buf_len); void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, From cf9ff6adbd4842010be805ac27f3d09ed7767643 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 11 Jun 2015 12:39:53 +0200 Subject: [PATCH 0578/2553] app-layer: improve EOF handling On receiving TCP end of stream packets (e.g. RST, but also sometimes FIN packets), in some cases the AppLayer parser would not be notified. This could happen in IDS mode, but would especially be an issue in IPS mode. This patch changes the logic of the AppLayer API to handle this. When no new data is available, and the stream ends, the AppLayer API now gets called with a NULL/0 input, but with the EOF flag set. This allows the AppLayer parser to call it's final routines still in the context of a real packet. --- src/app-layer-htp.c | 78 ++++++++++++++++++++++-------------------- src/app-layer-parser.c | 2 +- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index c6a6e412beac..aed1ddeb4783 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -739,28 +739,30 @@ static int HTPHandleRequestData(Flow *f, void *htp_state, htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec }; /* pass the new data to the htp parser */ - r = htp_connp_req_data(hstate->connp, &ts, input, input_len); + if (input_len > 0) { + r = htp_connp_req_data(hstate->connp, &ts, input, input_len); - switch(r) { - case HTP_STREAM_ERROR: + switch(r) { + case HTP_STREAM_ERROR: - hstate->flags |= HTP_FLAG_STATE_ERROR; - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; - ret = -1; - break; - case HTP_STREAM_DATA: - case HTP_STREAM_DATA_OTHER: + hstate->flags |= HTP_FLAG_STATE_ERROR; + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + ret = -1; + break; + case HTP_STREAM_DATA: + case HTP_STREAM_DATA_OTHER: - hstate->flags |= HTP_FLAG_STATE_DATA; - break; - case HTP_STREAM_TUNNEL: - break; - default: - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + hstate->flags |= HTP_FLAG_STATE_DATA; + break; + case HTP_STREAM_TUNNEL: + break; + default: + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + } + HTPHandleError(hstate); } - HTPHandleError(hstate); /* if the TCP connection is closed, then close the HTTP connection */ if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) && @@ -815,25 +817,27 @@ static int HTPHandleResponseData(Flow *f, void *htp_state, hstate->flags &=~ HTP_FLAG_NEW_BODY_SET; htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec }; - r = htp_connp_res_data(hstate->connp, &ts, input, input_len); - switch(r) { - case HTP_STREAM_ERROR: - hstate->flags = HTP_FLAG_STATE_ERROR; - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; - ret = -1; - break; - case HTP_STREAM_DATA: - case HTP_STREAM_DATA_OTHER: - hstate->flags |= HTP_FLAG_STATE_DATA; - break; - case HTP_STREAM_TUNNEL: - break; - default: - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; - } - HTPHandleError(hstate); + if (input_len > 0) { + r = htp_connp_res_data(hstate->connp, &ts, input, input_len); + switch(r) { + case HTP_STREAM_ERROR: + hstate->flags = HTP_FLAG_STATE_ERROR; + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + ret = -1; + break; + case HTP_STREAM_DATA: + case HTP_STREAM_DATA_OTHER: + hstate->flags |= HTP_FLAG_STATE_DATA; + break; + case HTP_STREAM_TUNNEL: + break; + default: + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + } + HTPHandleError(hstate); + } /* if we the TCP connection is closed, then close the HTTP connection */ if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) && diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 655da90213b1..2c4d2f8b2c67 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -890,7 +890,7 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp } /* invoke the recursive parser, but only on data. We may get empty msgs on EOF */ - if (input_len > 0) { + if (input_len > 0 || (flags & STREAM_EOF)) { /* invoke the parser */ if (p->Parser[(flags & STREAM_TOSERVER) ? 0 : 1](f, alstate, pstate, input, input_len, From 4e7cb7b8630258d1715742ea30145ef9568319ec Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 11 Jun 2015 16:54:52 +0200 Subject: [PATCH 0579/2553] app-layer: update all protocols to accept NULL+EOF Update all non-HTTP protocol parsers to accept a NULL+EOF input. --- src/app-layer-dcerpc-udp.c | 4 ++++ src/app-layer-dcerpc.c | 4 ++++ src/app-layer-dns-tcp.c | 10 +++++++++- src/app-layer-dns-udp.c | 12 ++++++++++-- src/app-layer-ftp.c | 4 ++++ src/app-layer-modbus.c | 8 ++++++++ src/app-layer-smb.c | 4 ++++ src/app-layer-smb2.c | 4 ++++ src/app-layer-smtp.c | 4 ++++ src/app-layer-ssh.c | 8 ++++++++ src/app-layer-ssl.c | 4 ++++ 11 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/app-layer-dcerpc-udp.c b/src/app-layer-dcerpc-udp.c index 9dedeee59e2e..e42c96804e4e 100644 --- a/src/app-layer-dcerpc-udp.c +++ b/src/app-layer-dcerpc-udp.c @@ -714,6 +714,10 @@ static int DCERPCUDPParse(Flow *f, void *dcerpc_state, int hdrretval = 0; SCEnter(); + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpc_state; while (sstate->bytesprocessed < DCERPC_UDP_HDR_LEN && input_len) { hdrretval = DCERPCUDPParseHeader(f, dcerpc_state, pstate, input, diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index d7198ba586d1..bbfb33006790 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -1911,6 +1911,10 @@ static int DCERPCParse(Flow *f, void *dcerpc_state, int32_t retval = 0; DCERPCState *sstate = (DCERPCState *) dcerpc_state; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + if (sstate->dcerpc.bytesprocessed != 0 && sstate->data_needed_for_dir != dir) { SCReturnInt(-1); } diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 840a0f8086e5..80a48507ee4d 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -280,12 +280,16 @@ static int DNSTCPRequestParse(Flow *f, void *dstate, DNSState *dns_state = (DNSState *)dstate; SCLogDebug("starting %u", input_len); + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + /** \todo remove this when PP is fixed to enforce ipproto */ if (f != NULL && f->proto != IPPROTO_TCP) SCReturnInt(-1); /* probably a rst/fin sending an eof */ - if (input_len == 0) { + if (input == NULL || input_len == 0) { goto insufficient_data; } @@ -490,6 +494,10 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, { DNSState *dns_state = (DNSState *)dstate; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + /** \todo remove this when PP is fixed to enforce ipproto */ if (f != NULL && f->proto != IPPROTO_TCP) SCReturnInt(-1); diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index eb87849c5211..e3ee01ffab43 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -62,11 +62,15 @@ static int DNSUDPRequestParse(Flow *f, void *dstate, SCLogDebug("starting %u", input_len); + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + /** \todo remove this when PP is fixed to enforce ipproto */ if (f != NULL && f->proto != IPPROTO_UDP) SCReturnInt(-1); - if (input_len == 0 || input_len < sizeof(DNSHeader)) { + if (input == NULL || input_len == 0 || input_len < sizeof(DNSHeader)) { SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSHeader)); goto insufficient_data; } @@ -168,11 +172,15 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, SCLogDebug("starting %u", input_len); + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + /** \todo remove this when PP is fixed to enforce ipproto */ if (f != NULL && f->proto != IPPROTO_UDP) SCReturnInt(-1); - if (input_len == 0 || input_len < sizeof(DNSHeader)) { + if (input == NULL || input_len == 0 || input_len < sizeof(DNSHeader)) { SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSHeader)); goto insufficient_data; } diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index b4a4d6f8e8bd..1ba184461537 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -219,6 +219,10 @@ static int FTPParseRequest(Flow *f, void *ftp_state, FtpState *state = (FtpState *)ftp_state; void *ptmp; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + state->input = input; state->input_len = input_len; /* toserver stream */ diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 16ab40d0b0dc..9e9ba03741be 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1227,6 +1227,10 @@ static int ModbusParseRequest(Flow *f, ModbusTransaction *tx; ModbusHeader header; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + while (input_len > 0) { uint32_t adu_len = input_len; uint8_t *adu = input; @@ -1284,6 +1288,10 @@ static int ModbusParseResponse(Flow *f, ModbusState *modbus = (ModbusState *) state; ModbusTransaction *tx; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + while (input_len > 0) { uint32_t adu_len = input_len; uint8_t *adu = input; diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index b7ae55d3d196..c5021031525c 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -1172,6 +1172,10 @@ static int SMBParse(Flow *f, void *smb_state, AppLayerParserState *pstate, SCReturnInt(0); } + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + if (sstate->bytesprocessed != 0 && sstate->data_needed_for_dir != dir) { SCReturnInt(-1); } diff --git a/src/app-layer-smb2.c b/src/app-layer-smb2.c index 6a49bd751c1d..3c591e913a2c 100644 --- a/src/app-layer-smb2.c +++ b/src/app-layer-smb2.c @@ -532,6 +532,10 @@ static int SMB2Parse(Flow *f, void *smb2_state, AppLayerParserState *pstate, if (pstate == NULL) return -1; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + while (sstate->bytesprocessed < NBSS_HDR_LEN && input_len) { retval = NBSSParseHeader(smb2_state, pstate, input, input_len); if (retval <= input_len) { diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index bbfa7ae93202..7f398a6e7d65 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1065,6 +1065,10 @@ static int SMTPParse(int direction, Flow *f, SMTPState *state, { SCEnter(); + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + state->input = input; state->input_len = input_len; state->direction = direction; diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index 9d610b8c6b8e..fda60c1cf50b 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -422,6 +422,10 @@ static int SSHParseRequest(Flow *f, void *state, AppLayerParserState *pstate, SshState *ssh_state = (SshState *)state; SshHeader *ssh_header = &ssh_state->cli_hdr; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + int r = SSHParseData(ssh_state, ssh_header, input, input_len); if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE && @@ -440,6 +444,10 @@ static int SSHParseResponse(Flow *f, void *state, AppLayerParserState *pstate, SshState *ssh_state = (SshState *)state; SshHeader *ssh_header = &ssh_state->srv_hdr; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + int r = SSHParseData(ssh_state, ssh_header, input, input_len); if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE && diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index d980b00abd67..0800c1db3d80 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -974,6 +974,10 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt ssl_state->f = f; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + if (direction == 0) ssl_state->curr_connp = &ssl_state->client_connp; else From 29fbcce50dc1cb1628398c3c60fb78adbb1607db Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Jun 2015 12:04:44 +0200 Subject: [PATCH 0580/2553] detect hsbd: simplify resize logic --- src/detect-engine-hsbd.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index beba23966bbb..93440a198d72 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -146,7 +146,6 @@ static void HSBDGetBufferForTXInIPSMode(DetectEngineThreadCtx *det_ctx, HtpTxUserData *htud, int index) { uint32_t window_size = 0; - int resize = 0; /* how much from before body_inspected will we consider? */ uint32_t cfg_win = @@ -163,10 +162,8 @@ static void HSBDGetBufferForTXInIPSMode(DetectEngineThreadCtx *det_ctx, SCLogDebug("weird: body size is %uk", window_size/1024); window_size = MAX_WINDOW; } - if (window_size > det_ctx->hsbd[index].buffer_size) - resize = 1; - if (det_ctx->hsbd[index].buffer == NULL || resize) { + if (det_ctx->hsbd[index].buffer == NULL || window_size > det_ctx->hsbd[index].buffer_size) { void *ptmp; if ((ptmp = HTPRealloc(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size, window_size)) == NULL) { @@ -178,7 +175,6 @@ static void HSBDGetBufferForTXInIPSMode(DetectEngineThreadCtx *det_ctx, } det_ctx->hsbd[index].buffer = ptmp; det_ctx->hsbd[index].buffer_size = window_size; - resize = 0; } uint32_t left_edge = htud->response_body.body_inspected - cfg_win; From c0807c3df5b3655e80c741df7f23ff5784f2803d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Jun 2015 15:27:04 +0200 Subject: [PATCH 0581/2553] fast log: clean up tests --- src/alert-fastlog.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index ce198658e630..9e47c73dd4fc 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -304,16 +304,14 @@ static int AlertFastLogTest01() de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"FastLog test\"; content:\"GET\"; " "Classtype:unknown; sid:1;)"); - result = (de_ctx->sig_list != NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt == 1) + if (p->alerts.cnt == 1) { result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); - else - result = 0; + } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -351,25 +349,16 @@ static int AlertFastLogTest02() de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"FastLog test\"; content:\"GET\"; " "Classtype:unknown; sid:1;)"); - result = (de_ctx->sig_list != NULL); - if (result == 0) - printf("sig parse failed: "); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt == 1) { - result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown Traffic") != 0); - if (result == 0) - printf("p->alerts.alerts[0].class_msg %s: ", p->alerts.alerts[0].s->class_msg); - result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); if (result == 0) printf("p->alerts.alerts[0].class_msg %s: ", p->alerts.alerts[0].s->class_msg); - } else { - result = 0; } SigGroupCleanup(de_ctx); From b3b7625be52dfedcbb759a951f69d409409d6d66 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Jun 2015 15:34:46 +0200 Subject: [PATCH 0582/2553] htp: fix test --- src/app-layer-htp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index aed1ddeb4783..d561f0868f98 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -6123,8 +6123,8 @@ int HTPParserTest16(void) if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1) { printf("expected method M_GET and got %s: , expected protocol " - "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), - bstr_util_strdup_to_c(tx->request_protocol)); + "HTTP/1.1 and got %s \n", tx ? bstr_util_strdup_to_c(tx->request_method) : "tx null", + tx ? bstr_util_strdup_to_c(tx->request_protocol) : "tx null"); goto end; } From a5168d59770ea990a3276af83b69caad5faadeeb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Jun 2015 15:46:28 +0200 Subject: [PATCH 0583/2553] dce_opnum: improve memory handling on parsing error --- src/detect-dce-opnum.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 3c6e6aad67f0..0885666374eb 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -182,6 +182,13 @@ static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) dor = DetectDceOpnumAllocDetectDceOpnumRange(); if (dor == NULL) goto error; + if (prev_dor == NULL) { + prev_dor = dor; + dod->range = dor; + } else { + prev_dor->next = dor; + prev_dor = dor; + } if ((hyphen_token = index(dup_str_temp, '-')) != NULL) { hyphen_token[0] = '\0'; @@ -199,20 +206,17 @@ static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) if (dor->range1 > DCE_OPNUM_RANGE_MAX) goto error; - if (prev_dor == NULL) { - prev_dor = dor; - dod->range = dor; - } else { - prev_dor->next = dor; - prev_dor = dor; - } - dup_str_temp = dup_str; } dor = DetectDceOpnumAllocDetectDceOpnumRange(); if (dor == NULL) goto error; + if (prev_dor == NULL) { + dod->range = dor; + } else { + prev_dor->next = dor; + } if ( (hyphen_token = index(dup_str, '-')) != NULL) { hyphen_token[0] = '\0'; @@ -230,12 +234,6 @@ static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) if (dor->range1 > DCE_OPNUM_RANGE_MAX) goto error; - if (prev_dor == NULL) { - dod->range = dor; - } else { - prev_dor->next = dor; - } - if (dup_str_head != NULL) SCFree(dup_str_head); From 21db5ee691b349d3da1925b703ea5200d736e40a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Jun 2015 15:47:02 +0200 Subject: [PATCH 0584/2553] counters: reduce global usage --- src/counters.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/counters.c b/src/counters.c index e863337d9c11..887fd7ca99d6 100644 --- a/src/counters.c +++ b/src/counters.c @@ -611,15 +611,19 @@ static int StatsOutput(ThreadVars *tv) stats_table.start_time = stats_start_time; } + const uint16_t max_id = counters_global_id; + if (max_id == 0) + return -1; + /** temporary local table to merge the per thread counters, * especially needed for the average counters */ struct CountersMergeTable { int type; uint64_t value; uint64_t updates; - } merge_table[counters_global_id]; + } merge_table[max_id]; memset(&merge_table, 0x00, - counters_global_id * sizeof(struct CountersMergeTable)); + max_id * sizeof(struct CountersMergeTable)); int thread = stats_ctx->sts_cnt - 1; StatsRecord *table = stats_table.stats; @@ -636,9 +640,9 @@ static int StatsOutput(ThreadVars *tv) /* temporay table for quickly storing the counters for this * thread store, so that we can post process them outside * of the thread store lock */ - struct CountersMergeTable thread_table[counters_global_id]; + struct CountersMergeTable thread_table[max_id]; memset(&thread_table, 0x00, - counters_global_id * sizeof(struct CountersMergeTable)); + max_id * sizeof(struct CountersMergeTable)); SCMutexLock(&sts->ctx->m); pc = sts->ctx->head; @@ -666,7 +670,7 @@ static int StatsOutput(ThreadVars *tv) /* update merge table */ uint16_t c; - for (c = 0; c < counters_global_id; c++) { + for (c = 0; c < max_id; c++) { struct CountersMergeTable *e = &thread_table[c]; /* thread only sets type if it has a counter * of this type. */ @@ -691,7 +695,7 @@ static int StatsOutput(ThreadVars *tv) } /* update per thread stats table */ - for (c = 0; c < counters_global_id; c++) { + for (c = 0; c < max_id; c++) { struct CountersMergeTable *e = &thread_table[c]; /* thread only sets type if it has a counter * of this type. */ @@ -721,7 +725,7 @@ static int StatsOutput(ThreadVars *tv) /* transfer 'merge table' to final stats table */ uint16_t x; - for (x = 0; x < counters_global_id; x++) { + for (x = 0; x < max_id; x++) { /* xfer previous value to pvalue and reset value */ table[x].pvalue = table[x].value; table[x].value = 0; From aa095864d3a8bae4364a8a50a5793fe7e02d1e0a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Jun 2015 16:07:21 +0200 Subject: [PATCH 0585/2553] pfring runmode: remove set that is never read --- src/runmode-pfring.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/runmode-pfring.c b/src/runmode-pfring.c index 8c9a06fde422..fbbd8c917234 100644 --- a/src/runmode-pfring.c +++ b/src/runmode-pfring.c @@ -233,8 +233,6 @@ void *ParsePfringConfig(const char *iface) if_default = ConfNodeLookupKeyValue(pf_ring_node, "interface", "default"); if (if_root == NULL && if_default == NULL) { - /* Switch to old mode */ - if_root = pf_ring_node; SCLogInfo("Unable to find pfring config for " "interface %s, using default value or 1.0 " "configuration system. ", From bcff35fd9f86da0f863e4b43fa81b56fc89e602d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Jun 2015 12:38:37 +0200 Subject: [PATCH 0586/2553] smb: fix coverity warning ** CID 1298892: Incorrect expression (UNUSED_VALUE) /src/app-layer-smb.c: 1486 in SMBProbingParser() --- src/app-layer-smb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index c5021031525c..4d7aa845b7d3 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -1488,7 +1488,7 @@ static uint16_t SMBProbingParser(uint8_t *input, uint32_t ilen, uint32_t *offset case NBSS_RETARGET_SESSION_RESPONSE: case NBSS_SESSION_KEEP_ALIVE: len = (input[1] & 0x01) << 16; - len = input[2] << 8; + len |= input[2] << 8; len |= input[3]; break; default: From dd2afd51f7cabc11a6303f14d7ef99c125ea0b05 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Jun 2015 12:42:57 +0200 Subject: [PATCH 0587/2553] file_data smtp: fix minor coverity warning CID 1298891: Null pointer dereferences (REVERSE_INULL) Null-checking "curr_file" suggests that it may be null, but it has already been dereferenced on all paths leading to the check. --- src/detect-engine-filedata-smtp.c | 70 +++++++++++++++---------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 423db75d2bf4..dc50d8c7d708 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -144,53 +144,51 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, goto end; } - if (curr_file != NULL) { - int first = 1; - curr_chunk = curr_file->chunks_head; - while (curr_chunk != NULL) { - /* see if we can filter out chunks */ - if (curr_file->content_inspected > 0) { - if (curr_chunk->stream_offset < curr_file->content_inspected) { - if ((curr_file->content_inspected - curr_chunk->stream_offset) > smtp_config.content_inspect_window) { - curr_chunk = curr_chunk->next; - continue; - } else { - /* include this one */ - } + int first = 1; + curr_chunk = curr_file->chunks_head; + while (curr_chunk != NULL) { + /* see if we can filter out chunks */ + if (curr_file->content_inspected > 0) { + if (curr_chunk->stream_offset < curr_file->content_inspected) { + if ((curr_file->content_inspected - curr_chunk->stream_offset) > smtp_config.content_inspect_window) { + curr_chunk = curr_chunk->next; + continue; } else { /* include this one */ } + } else { + /* include this one */ } + } - if (first) { - det_ctx->smtp[index].offset = curr_chunk->stream_offset; - first = 0; - } + if (first) { + det_ctx->smtp[index].offset = curr_chunk->stream_offset; + first = 0; + } - /* see if we need to grow the buffer */ - if (det_ctx->smtp[index].buffer == NULL || (det_ctx->smtp[index].buffer_len + curr_chunk->len) > det_ctx->smtp[index].buffer_size) { - void *ptmp; - det_ctx->smtp[index].buffer_size += curr_chunk->len * 2; - - if ((ptmp = SCRealloc(det_ctx->smtp[index].buffer, det_ctx->smtp[index].buffer_size)) == NULL) { - SCFree(det_ctx->smtp[index].buffer); - det_ctx->smtp[index].buffer = NULL; - det_ctx->smtp[index].buffer_size = 0; - det_ctx->smtp[index].buffer_len = 0; - goto end; - } - det_ctx->smtp[index].buffer = ptmp; - } - memcpy(det_ctx->smtp[index].buffer + det_ctx->smtp[index].buffer_len, curr_chunk->data, curr_chunk->len); - det_ctx->smtp[index].buffer_len += curr_chunk->len; + /* see if we need to grow the buffer */ + if (det_ctx->smtp[index].buffer == NULL || (det_ctx->smtp[index].buffer_len + curr_chunk->len) > det_ctx->smtp[index].buffer_size) { + void *ptmp; + det_ctx->smtp[index].buffer_size += curr_chunk->len * 2; - curr_chunk = curr_chunk->next; + if ((ptmp = SCRealloc(det_ctx->smtp[index].buffer, det_ctx->smtp[index].buffer_size)) == NULL) { + SCFree(det_ctx->smtp[index].buffer); + det_ctx->smtp[index].buffer = NULL; + det_ctx->smtp[index].buffer_size = 0; + det_ctx->smtp[index].buffer_len = 0; + goto end; + } + det_ctx->smtp[index].buffer = ptmp; } + memcpy(det_ctx->smtp[index].buffer + det_ctx->smtp[index].buffer_len, curr_chunk->data, curr_chunk->len); + det_ctx->smtp[index].buffer_len += curr_chunk->len; - /* updat inspected tracker */ - curr_file->content_inspected = curr_file->chunks_tail->stream_offset + curr_file->chunks_tail->len; + curr_chunk = curr_chunk->next; } + /* updat inspected tracker */ + curr_file->content_inspected = curr_file->chunks_tail->stream_offset + curr_file->chunks_tail->len; + buffer = det_ctx->smtp[index].buffer; *buffer_len = det_ctx->smtp[index].buffer_len; *stream_start_offset = det_ctx->smtp[index].offset; From 1ed8d7b53842d825ada15dd3f295c6f9e76fc402 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Jun 2015 12:50:05 +0200 Subject: [PATCH 0588/2553] detect analizer: fix minor coverity warning ** CID 1298889: Integer handling issues (NEGATIVE_RETURNS) /src/detect-engine-analyzer.c: 102 in EngineAnalysisFP() --- src/detect-engine-analyzer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 291e560beeb4..e6c69b086b0a 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -54,6 +54,9 @@ static FpPatternStats fp_pattern_stats[DETECT_SM_LIST_MAX]; static void FpPatternStatsAdd(int list, uint16_t patlen) { + if (list < 0 || list >= DETECT_SM_LIST_MAX) + return; + FpPatternStats *f = &fp_pattern_stats[list]; if (f->min == 0) From bd73553027a3a77815d09457a899791bbe8a76ff Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Jun 2015 13:02:29 +0200 Subject: [PATCH 0589/2553] smtp json: fix potential crash on malloc failure ** CID 1298888: (FORWARD_NULL) /src/output-json-email-common.c: 117 in JsonEmailLogJson() /src/output-json-email-common.c: 140 in JsonEmailLogJson() --- src/output-json-email-common.c | 40 +++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 4c427d4467b1..1efa9ce80fac 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -114,19 +114,21 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packe if (field != NULL) { json_t *js_to = json_array(); if (likely(js_to != NULL)) { - char *savep = NULL; - char *p; to_line = BytesToString((uint8_t *)field->value, (size_t)field->value_len); - //printf("to_line:: TO: \"%s\" (%d)\n", to_line, strlen(to_line)); - p = strtok_r(to_line, ",", &savep); - //printf("got another addr: \"%s\"\n", p); - json_array_append_new(js_to, json_string(p)); - while ((p = strtok_r(NULL, ",", &savep)) != NULL) { + if (likely(to_line != NULL)) { + char *savep = NULL; + char *p; + //printf("to_line:: TO: \"%s\" (%d)\n", to_line, strlen(to_line)); + p = strtok_r(to_line, ",", &savep); //printf("got another addr: \"%s\"\n", p); - json_array_append_new(js_to, json_string(&p[strspn(p, " ")])); + json_array_append_new(js_to, json_string(p)); + while ((p = strtok_r(NULL, ",", &savep)) != NULL) { + //printf("got another addr: \"%s\"\n", p); + json_array_append_new(js_to, json_string(&p[strspn(p, " ")])); + } + SCFree(to_line); } - SCFree(to_line); json_object_set_new(sjs, "to", js_to); } } @@ -137,19 +139,21 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packe if (field != NULL) { json_t *js_cc = json_array(); if (likely(js_cc != NULL)) { - char *savep = NULL; - char *p; cc_line = BytesToString((uint8_t *)field->value, (size_t)field->value_len); - //printf("cc_line:: CC: \"%s\" (%d)\n", to_line, strlen(to_line)); - p = strtok_r(cc_line, ",", &savep); - //printf("got another addr: \"%s\"\n", p); - json_array_append_new(js_cc, json_string(p)); - while ((p = strtok_r(NULL, ",", &savep)) != NULL) { + if (likely(cc_line != NULL)) { + char *savep = NULL; + char *p; + //printf("cc_line:: CC: \"%s\" (%d)\n", to_line, strlen(to_line)); + p = strtok_r(cc_line, ",", &savep); //printf("got another addr: \"%s\"\n", p); - json_array_append_new(js_cc, json_string(&p[strspn(p, " ")])); + json_array_append_new(js_cc, json_string(p)); + while ((p = strtok_r(NULL, ",", &savep)) != NULL) { + //printf("got another addr: \"%s\"\n", p); + json_array_append_new(js_cc, json_string(&p[strspn(p, " ")])); + } + SCFree(cc_line); } - SCFree(cc_line); json_object_set_new(sjs, "cc", js_cc); } } From b8211e8c04f25947ee3bbb1473e8ff75920c9c46 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Jun 2015 13:05:49 +0200 Subject: [PATCH 0590/2553] htp: hide BUG_ON's behind DEBUG_VALIDATION --- src/app-layer-htp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index d561f0868f98..8444afe651ed 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -702,7 +702,9 @@ static int HTPHandleRequestData(Flow *f, void *htp_state, } if (NULL == htp) { +#ifdef DEBUG_VALIDATION BUG_ON(htp == NULL); +#endif /* should never happen if HTPConfigure is properly invoked */ goto error; } @@ -721,7 +723,9 @@ static int HTPHandleRequestData(Flow *f, void *htp_state, } /* the code block above should make sure connp is never NULL here */ +#ifdef DEBUG_VALIDATION BUG_ON(hstate->connp == NULL); +#endif /* Unset the body inspection (the callback should * reactivate it if necessary) */ From 6c792cb4cc7309a9e925e30322bda9c4d6facab7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Jun 2015 13:09:36 +0200 Subject: [PATCH 0591/2553] erspan: respect vlan.use-for-tracking setting --- src/decode-erspan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/decode-erspan.c b/src/decode-erspan.c index ff6390b52387..f2fb0eb124fc 100644 --- a/src/decode-erspan.c +++ b/src/decode-erspan.c @@ -64,12 +64,13 @@ int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, return TM_ECODE_FAILED; } - if (vlan_id > 0) { + if (vlan_id > 0 && dtv->vlan_disabled == 0) { if (p->vlan_idx >= 2) { ENGINE_SET_EVENT(p,ERSPAN_TOO_MANY_VLAN_LAYERS); return TM_ECODE_FAILED; } - p->vlan_id[p->vlan_idx++] = vlan_id; + p->vlan_id[p->vlan_idx] = vlan_id; + p->vlan_idx++; } return DecodeEthernet(tv, dtv, p, pkt + sizeof(ErspanHdr), len - sizeof(ErspanHdr), pq); From f4f53924bbe702649ffd21764cf26e118a65e016 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Jun 2015 13:39:30 +0200 Subject: [PATCH 0592/2553] app-layer: fix coverity warnings --- src/app-layer-dcerpc-udp.c | 2 ++ src/app-layer-dcerpc.c | 2 ++ src/app-layer-dns-tcp.c | 2 +- src/app-layer-ftp.c | 2 ++ src/app-layer-modbus.c | 4 ++++ src/app-layer-smb2.c | 2 ++ src/app-layer-smtp.c | 2 ++ src/app-layer-ssh.c | 4 ++++ src/app-layer-ssl.c | 2 ++ 9 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/app-layer-dcerpc-udp.c b/src/app-layer-dcerpc-udp.c index e42c96804e4e..58d714d040f4 100644 --- a/src/app-layer-dcerpc-udp.c +++ b/src/app-layer-dcerpc-udp.c @@ -716,6 +716,8 @@ static int DCERPCUDPParse(Flow *f, void *dcerpc_state, if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); } DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpc_state; diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index bbfb33006790..44705ea970a2 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -1913,6 +1913,8 @@ static int DCERPCParse(Flow *f, void *dcerpc_state, if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); } if (sstate->dcerpc.bytesprocessed != 0 && sstate->data_needed_for_dir != dir) { diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 80a48507ee4d..f1cb597d2aef 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -503,7 +503,7 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, SCReturnInt(-1); /* probably a rst/fin sending an eof */ - if (input_len == 0) { + if (input == NULL || input_len == 0) { goto insufficient_data; } diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index 1ba184461537..b5d4a03d98ec 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -221,6 +221,8 @@ static int FTPParseRequest(Flow *f, void *ftp_state, if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); } state->input = input; diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 9e9ba03741be..fa965135d394 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1229,6 +1229,8 @@ static int ModbusParseRequest(Flow *f, if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); } while (input_len > 0) { @@ -1290,6 +1292,8 @@ static int ModbusParseResponse(Flow *f, if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); } while (input_len > 0) { diff --git a/src/app-layer-smb2.c b/src/app-layer-smb2.c index 3c591e913a2c..f412e1dfeebb 100644 --- a/src/app-layer-smb2.c +++ b/src/app-layer-smb2.c @@ -534,6 +534,8 @@ static int SMB2Parse(Flow *f, void *smb2_state, AppLayerParserState *pstate, if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); } while (sstate->bytesprocessed < NBSS_HDR_LEN && input_len) { diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 7f398a6e7d65..1951613d1f3a 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1067,6 +1067,8 @@ static int SMTPParse(int direction, Flow *f, SMTPState *state, if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); } state->input = input; diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index fda60c1cf50b..879c77466557 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -424,6 +424,8 @@ static int SSHParseRequest(Flow *f, void *state, AppLayerParserState *pstate, if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); } int r = SSHParseData(ssh_state, ssh_header, input, input_len); @@ -446,6 +448,8 @@ static int SSHParseResponse(Flow *f, void *state, AppLayerParserState *pstate, if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); } int r = SSHParseData(ssh_state, ssh_header, input, input_len); diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 0800c1db3d80..5fb41ba15a21 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -976,6 +976,8 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); } if (direction == 0) From e583de05823c51694cb443d326e7b0ed13cb457e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Jun 2015 14:39:44 +0200 Subject: [PATCH 0593/2553] Minor unittest cleanups --- src/host-bit.c | 1 - src/ippair-bit.c | 1 - src/log-droplog.c | 8 -------- 3 files changed, 10 deletions(-) diff --git a/src/host-bit.c b/src/host-bit.c index 7f33f3bca9ee..6225673f5daf 100644 --- a/src/host-bit.c +++ b/src/host-bit.c @@ -480,7 +480,6 @@ static int HostBitTest11 (void) HostFree(h); end: HostCleanup(); - ret = 1; return ret; } diff --git a/src/ippair-bit.c b/src/ippair-bit.c index 014b1d9b26d6..0cf5c60c67c2 100644 --- a/src/ippair-bit.c +++ b/src/ippair-bit.c @@ -483,7 +483,6 @@ static int IPPairBitTest11 (void) IPPairFree(h); end: IPPairCleanup(); - ret = 1; return ret; } diff --git a/src/log-droplog.c b/src/log-droplog.c index 877d243754f3..69b8539fbdb5 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -390,16 +390,12 @@ int LogDropLogTest01() de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any " "(msg:\"LogDropLog test\"; content:\"GET\"; Classtype:unknown; sid:1;)"); - result = (de_ctx->sig_list != NULL); - SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt == 1 && (PACKET_TEST_ACTION(p, ACTION_DROP))) result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); - else - result = 0; if (LogDropCondition(NULL, p) == TRUE) LogDropLogger(NULL, &dlt, p); @@ -458,16 +454,12 @@ int LogDropLogTest02() de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"LogDropLog test\"; content:\"GET\"; Classtype:unknown; sid:1;)"); - result = (de_ctx->sig_list != NULL); - SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt == 1 && p->alerts.alerts[0].action != ACTION_DROP) result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); - else - result = 0; if (LogDropCondition(NULL, p) == TRUE) LogDropLogger(NULL, &dlt, p); From d592d570396c19681d57e7bcb85ca13020424dbd Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Fri, 15 May 2015 11:05:29 +0200 Subject: [PATCH 0594/2553] file_data: check for signature alproto and flow Currently the following rule can't be loaded: alert tcp any any -> any 25 (msg:"SMTP file_data test"; flow:to_server,established; file_data; content:"abc";sid:1;) and produces the error output: "Can't use file_data with flow:to_server or from_client with http or smtp." This checks if the alproto is not http in a signature, so permits to use flow keyword also. Issue reported by rmkml. --- src/detect-file-data.c | 104 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/src/detect-file-data.c b/src/detect-file-data.c index e0186e5ec44c..258a135cf0a4 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -84,9 +84,15 @@ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str return -1; } - if ((s->init_flags & SIG_FLAG_INIT_FLOW) && + if (s->alproto == ALPROTO_HTTP && (s->init_flags & SIG_FLAG_INIT_FLOW) && (s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with flow:to_server or from_client with http or smtp."); + SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with flow:to_server or from_client with http."); + return -1; + } + + if (s->alproto == ALPROTO_SMTP && (s->init_flags & SIG_FLAG_INIT_FLOW) && + !(s->flags & SIG_FLAG_TOSERVER) && (s->flags & SIG_FLAG_TOCLIENT)) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with flow:to_client or from_server with smtp."); return -1; } @@ -169,6 +175,97 @@ static int DetectFiledataParseTest02(void) return result; } + +static int DetectFiledataParseTest03(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any 25 " + "(msg:\"test\"; flow:to_server,established; file_data; content:\"abc\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("sig parse failed: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("content is still in PMATCH list: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + printf("content not in FILEDATA list: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +static int DetectFiledataParseTest04(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert smtp any any -> any any " + "(msg:\"test\"; flow:to_client,established; file_data; content:\"abc\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("sig parse failed: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +static int DetectFiledataParseTest05(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"test\"; flow:to_server,established; file_data; content:\"abc\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("sig parse failed: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} #endif void DetectFiledataRegisterTests(void) @@ -176,5 +273,8 @@ void DetectFiledataRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectFiledataParseTest01", DetectFiledataParseTest01, 1); UtRegisterTest("DetectFiledataParseTest02", DetectFiledataParseTest02, 1); + UtRegisterTest("DetectFiledataParseTest03", DetectFiledataParseTest03, 1); + UtRegisterTest("DetectFiledataParseTest04", DetectFiledataParseTest04, 0); + UtRegisterTest("DetectFiledataParseTest05", DetectFiledataParseTest05, 0); #endif } From d36eba4e5e378e5ea8dc3f1a760781f00502f6bb Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Mon, 29 Jun 2015 20:46:15 +0300 Subject: [PATCH 0595/2553] Fix issues #1493 and #1494 --- src/detect.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/detect.c b/src/detect.c index 94e25a7d0252..04fb11f17d3a 100644 --- a/src/detect.c +++ b/src/detect.c @@ -398,6 +398,7 @@ static int ProcessSigFiles(DetectEngineCtx *de_ctx, char *pattern, if (r == GLOB_NOMATCH) { SCLogWarning(SC_ERR_NO_RULES, "No rule files match the pattern %s", pattern); ++(st->bad_files); + ++(st->total_files); return -1; } else if (r != 0) { SCLogError(SC_ERR_OPENING_RULE_FILE, "error expanding template %s: %s", @@ -473,8 +474,14 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl TAILQ_FOREACH(file, &rule_files->head, next) { sfile = DetectLoadCompleteSigPath(de_ctx, file->val); good_sigs = bad_sigs = 0; - ProcessSigFiles(de_ctx, sfile, &sig_stat, &good_sigs, &bad_sigs); + ret = ProcessSigFiles(de_ctx, sfile, &sig_stat, &good_sigs, &bad_sigs); SCFree(sfile); + + if (ret != 0 || good_sigs == 0) { + if (de_ctx->failure_fatal == 1) { + exit(EXIT_FAILURE); + } + } } } } @@ -482,19 +489,21 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl /* If a Signature file is specified from commandline, parse it too */ if (sig_file != NULL) { - SCLogInfo("Loading rule file: %s", sig_file); - ++sig_stat.total_files; + ret = ProcessSigFiles(de_ctx, sig_file, &sig_stat, &good_sigs, &bad_sigs); - if (ProcessSigFiles(de_ctx, sig_file, &sig_stat, &good_sigs, &bad_sigs) != 0) { - ++sig_stat.bad_files; + if (ret != 0) { + if (de_ctx->failure_fatal == 1) { + exit(EXIT_FAILURE); + } } if (good_sigs == 0) { - SCLogWarning(SC_ERR_NO_RULES, "No rules loaded from %s", sig_file); - } + SCLogError(SC_ERR_NO_RULES, "No rules loaded from %s", sig_file); - sig_stat.good_sigs_total += good_sigs; - sig_stat.bad_sigs_total += bad_sigs; + if (de_ctx->failure_fatal == 1) { + exit(EXIT_FAILURE); + } + } } /* now we should have signatures to work with */ From cd9cc2559e33590033debdc09b45c83f433052ce Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Fri, 26 Jun 2015 11:38:59 +0300 Subject: [PATCH 0596/2553] Issue 1491: fix capabilities for pf_ring mode when running under non-root account --- src/util-privs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-privs.c b/src/util-privs.c index 2048d12ac6fa..635247c3e590 100644 --- a/src/util-privs.c +++ b/src/util-privs.c @@ -80,7 +80,7 @@ void SCDropMainThreadCaps(uint32_t userid, uint32_t groupid) break; case RUNMODE_PFRING: capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, - CAP_NET_ADMIN, + CAP_NET_ADMIN, CAP_NET_RAW, -1); break; case RUNMODE_NFQ: From 91efdadf8e871662a6bc4cfad0a21d707a31eded Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 29 Jun 2015 16:04:14 +0200 Subject: [PATCH 0597/2553] Disable pcap-config use during cross compilation This allows cross compilation where the host system has pcap-config installed and would create an invalid entry in the cross-CFLAGS. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 93720520981a..fb3c363a3cce 100644 --- a/configure.ac +++ b/configure.ac @@ -961,7 +961,7 @@ AC_CHECK_LIB(pcap, pcap_activate,, LPCAPVTEST="no") if test "$LPCAPVTEST" != "no"; then AC_PATH_PROG(HAVE_PCAP_CONFIG, pcap-config, "no") - if test "$HAVE_PCAP_CONFIG" = "no"; then + if test "$HAVE_PCAP_CONFIG" = "no" -o "$cross_compiling" = "yes"; then CFLAGS="${CFLAGS} -DLIBPCAP_VERSION_MAJOR=1" else CFLAGS="${CFLAGS} `pcap-config --defines` `pcap-config --cflags` -DLIBPCAP_VERSION_MAJOR=1" From c2f4031a8cfdd24f20085fb1a29a1c628b34eb86 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 6 Jul 2015 13:33:36 +0200 Subject: [PATCH 0598/2553] detect: fix settings override for reloads --- src/detect-engine.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 3017f2b32e2e..6ac78654db63 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1747,19 +1747,12 @@ int DetectEngineReload(const char *filename) char prefix[128] = ""; if (filename != NULL) { snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++); - - ConfNode *node = ConfGetNode(prefix); - if (node != NULL) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "reload %d already loaded", reloads-1); - return -1; - } - if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename); return -1; } - node = ConfGetNode(prefix); + ConfNode *node = ConfGetNode(prefix); if (node == NULL) { SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename); return -1; From d6fc6e874f2271b1a28e81d35944a22c8cb95879 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Jun 2015 17:32:16 +0200 Subject: [PATCH 0599/2553] log: reorganize SCLogOPIfaceCtx to make it more efficient --- src/util-debug.c | 4 ++++ src/util-debug.h | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/util-debug.c b/src/util-debug.c index 7a78987dda5d..7e9726bbb5d8 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -652,6 +652,10 @@ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, } iface_ctx->log_level = tmp_log_level; + if (isatty(fileno(stdout))) { + + } + return iface_ctx; } diff --git a/src/util-debug.h b/src/util-debug.h index e5b4d7055025..5b0dd008ea9c 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -120,12 +120,12 @@ typedef struct SCLogOPIfaceCtx_ { /* the facility code if the interface is SC_LOG_IFACE_SYSLOG */ int facility; - /* override for the global_log_format(currently not used) */ - const char *log_format; - /* override for the global_log_level */ SCLogLevel log_level; + /* override for the global_log_format(currently not used) */ + const char *log_format; + struct SCLogOPIfaceCtx_ *next; } SCLogOPIfaceCtx; From b30bdc21b594545c2e9ad0ac90df43b07e5ff3d7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 26 Jun 2015 16:10:16 +0200 Subject: [PATCH 0600/2553] logging: cleanup output API Make SCLogMessage master of the logging. Reduces complexity of the SCLog macro's. --- src/util-debug.c | 83 ++++++++++++++++++----------------- src/util-debug.h | 111 ++++++++++++++++++----------------------------- 2 files changed, 85 insertions(+), 109 deletions(-) diff --git a/src/util-debug.c b/src/util-debug.c index 7e9726bbb5d8..e6c22cb58556 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -194,7 +194,7 @@ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) * \param msg Pointer to the message that has to be logged * \param log_level The log_level of the message that has to be logged */ -void SCLogOutputBuffer(SCLogLevel log_level, char *msg) +static void SCLogOutputBuffer(SCLogLevel log_level, char *msg) { char *temp = msg; int len = strlen(msg); @@ -264,10 +264,12 @@ void SCLogOutputBuffer(SCLogLevel log_level, char *msg) * * \retval SC_OK on success; else an error code */ -SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, - unsigned line, const char *function) +SCError SCLogMessage(SCLogLevel log_level, const char *file, + unsigned line, const char *function, + SCError error_code, const char *message) { - char *temp = *msg; + char buffer[SC_LOG_MAX_LOG_MSG_LEN] = ""; + char *temp = buffer; const char *s = NULL; struct timeval tval; @@ -284,20 +286,6 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, return SC_ERR_LOG_MODULE_NOT_INIT; } - if (sc_log_fg_filters_present == 1) { - if (SCLogMatchFGFilterWL(file, function, line) != 1) { - return SC_ERR_LOG_FG_FILTER_MATCH; - } - - if (SCLogMatchFGFilterBL(file, function, line) != 1) { - return SC_ERR_LOG_FG_FILTER_MATCH; - } - } - - if (sc_log_fd_filters_present == 1 && SCLogMatchFDFilter(function) != 1) { - return SC_ERR_LOG_FG_FILTER_MATCH; - } - char *temp_fmt = strdup(sc_log_config->log_format); if (unlikely(temp_fmt == NULL)) { return SC_ERR_MEM_ALLOC; @@ -306,10 +294,7 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, char *substr = temp_fmt; while ( (temp_fmt = index(temp_fmt, SC_LOG_FMT_PREFIX)) ) { - if ((temp - *msg) > SC_LOG_MAX_LOG_MSG_LEN) { - printf("Warning: Log message exceeded message length limit of %d\n", - SC_LOG_MAX_LOG_MSG_LEN); - *msg = *msg + SC_LOG_MAX_LOG_MSG_LEN; + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { if (temp_fmt_h != NULL) SCFree(temp_fmt_h); return SC_OK; @@ -322,7 +307,7 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, struct tm local_tm; tms = SCLocalTime(tval.tv_sec, &local_tm); - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%d/%d/%04d -- %02d:%02d:%02d", substr, tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, @@ -337,7 +322,7 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_PID: temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%u", substr, getpid()); if (cw < 0) goto error; @@ -349,7 +334,7 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_TID: temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%lu", substr, SCGetThreadIdLong()); if (cw < 0) goto error; @@ -369,7 +354,7 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%s", substr, ((tv != NULL)? tv->name: "UNKNOWN TM")); #endif - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, "N/A"); if (cw < 0) goto error; @@ -382,10 +367,10 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, temp_fmt[0] = '\0'; s = SCMapEnumValueToName(log_level, sc_log_level_map); if (s != NULL) - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, s); else - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, "INVALID"); if (cw < 0) goto error; @@ -397,7 +382,7 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_FILE_NAME: temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, file); if (cw < 0) goto error; @@ -409,7 +394,7 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_LINE: temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%u", substr, line); if (cw < 0) goto error; @@ -421,7 +406,7 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_FUNCTION: temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, function); if (cw < 0) goto error; @@ -434,31 +419,47 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, } temp_fmt++; } - if ((temp - *msg) > SC_LOG_MAX_LOG_MSG_LEN) { - printf("Warning: Log message exceeded message length limit of %d\n", - SC_LOG_MAX_LOG_MSG_LEN); - *msg = *msg + SC_LOG_MAX_LOG_MSG_LEN; + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { if (temp_fmt_h != NULL) SCFree(temp_fmt_h); return SC_OK; } - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s", substr); + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr); if (cw < 0) goto error; temp += cw; - if ((temp - *msg) > SC_LOG_MAX_LOG_MSG_LEN) { - printf("Warning: Log message exceeded message length limit of %d\n", - SC_LOG_MAX_LOG_MSG_LEN); - *msg = *msg + SC_LOG_MAX_LOG_MSG_LEN; + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { if (temp_fmt_h != NULL) SCFree(temp_fmt_h); return SC_OK; } - *msg = temp; + if (error_code != SC_OK) { + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "[ERRCODE: %s(%d)] - ", SCErrorToString(error_code), error_code); + if (cw < 0) + goto error; + temp += cw; + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { + if (temp_fmt_h != NULL) + SCFree(temp_fmt_h); + return SC_OK; + } + } + + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", message); + if (cw < 0) + goto error; + temp += cw; + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { + if (temp_fmt_h != NULL) + SCFree(temp_fmt_h); + return SC_OK; + } SCFree(temp_fmt_h); + SCLogOutputBuffer(log_level, buffer); return SC_OK; error: diff --git a/src/util-debug.h b/src/util-debug.h index 5b0dd008ea9c..b73c390481e8 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -191,59 +191,45 @@ extern int sc_log_module_initialized; extern int sc_log_module_cleaned; -#define SCLog(x, ...) do { \ - char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN] = ""; \ - char *_sc_log_temp = _sc_log_msg; \ - if ( !( \ - (sc_log_global_log_level >= x) && \ - SCLogMessage(x, &_sc_log_temp, \ - __FILE__, \ - __LINE__, \ - __FUNCTION__) \ - == SC_OK) ) \ - { } else { \ - snprintf(_sc_log_temp, \ - (SC_LOG_MAX_LOG_MSG_LEN - \ - (_sc_log_temp - _sc_log_msg)), \ - __VA_ARGS__); \ - SCLogOutputBuffer(x, _sc_log_msg); \ - } \ - } while(0) - -#define SCLogErr(x, err, ...) do { \ - char _sc_log_err_msg[SC_LOG_MAX_LOG_MSG_LEN] = ""; \ - char *_sc_log_err_temp = _sc_log_err_msg; \ - if ( !( \ - (sc_log_global_log_level >= x) && \ - SCLogMessage(x, &_sc_log_err_temp,\ - __FILE__, \ - __LINE__, \ - __FUNCTION__) \ - == SC_OK) ) \ - { } else { \ - _sc_log_err_temp = \ - _sc_log_err_temp + \ - snprintf(_sc_log_err_temp, \ - (SC_LOG_MAX_LOG_MSG_LEN - \ - (_sc_log_err_temp - _sc_log_err_msg)), \ - "[ERRCODE: %s(%d)] - ", \ - SCErrorToString(err), \ - err); \ - if ((_sc_log_err_temp - _sc_log_err_msg) > \ - SC_LOG_MAX_LOG_MSG_LEN) { \ - printf("Warning: Log message exceeded message length limit of %d\n",\ - SC_LOG_MAX_LOG_MSG_LEN); \ - _sc_log_err_temp = _sc_log_err_msg + \ - SC_LOG_MAX_LOG_MSG_LEN; \ - } else { \ - snprintf(_sc_log_err_temp, \ - (SC_LOG_MAX_LOG_MSG_LEN - \ - (_sc_log_err_temp - _sc_log_err_msg)), \ - __VA_ARGS__); \ - } \ - SCLogOutputBuffer(x, _sc_log_err_msg); \ - } \ - } while(0) +#define SCLog(x, ...) \ + do { \ + if (sc_log_global_log_level >= x && \ + (sc_log_fg_filters_present == 0 || \ + SCLogMatchFGFilterWL(__FILE__, __FUNCTION__, __LINE__) == 1 || \ + SCLogMatchFGFilterBL(__FILE__, __FUNCTION__, __LINE__) == 1) && \ + (sc_log_fd_filters_present == 0 || \ + SCLogMatchFDFilter(__FUNCTION__) == 1)) \ + { \ + char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN] = ""; \ + \ + snprintf(_sc_log_msg, SC_LOG_MAX_LOG_MSG_LEN, __VA_ARGS__); \ + \ + SCLogMessage(x, \ + __FILE__, \ + __LINE__, \ + __FUNCTION__, SC_OK, _sc_log_msg); \ + } \ + } while(0) + +#define SCLogErr(x, err, ...) \ + do { \ + if (sc_log_global_log_level >= x && \ + (sc_log_fg_filters_present == 0 || \ + SCLogMatchFGFilterWL(__FILE__, __FUNCTION__, __LINE__) == 1 || \ + SCLogMatchFGFilterBL(__FILE__, __FUNCTION__, __LINE__) == 1) && \ + (sc_log_fd_filters_present == 0 || \ + SCLogMatchFDFilter(__FUNCTION__) == 1)) \ + { \ + char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN] = ""; \ + \ + snprintf(_sc_log_msg, SC_LOG_MAX_LOG_MSG_LEN, __VA_ARGS__); \ + \ + SCLogMessage(x, \ + __FILE__, \ + __LINE__, \ + __FUNCTION__, err, _sc_log_msg); \ + } \ + } while(0) /** * \brief Macro used to log INFORMATIONAL messages. @@ -350,19 +336,10 @@ extern int sc_log_module_cleaned; * \retval f An argument can be supplied, although it is not used */ #define SCEnter(f) do { \ - char _sc_enter_msg[SC_LOG_MAX_LOG_MSG_LEN]; \ - char *_sc_enter_temp = _sc_enter_msg; \ if (sc_log_global_log_level >= SC_LOG_DEBUG &&\ - SCLogCheckFDFilterEntry(__FUNCTION__) && \ - SCLogMessage(SC_LOG_DEBUG, &_sc_enter_temp, \ - __FILE__, \ - __LINE__, \ - __FUNCTION__) == SC_OK) { \ - snprintf(_sc_enter_temp, (SC_LOG_MAX_LOG_MSG_LEN - \ - (_sc_enter_msg - _sc_enter_temp)), \ - "Entering ... >>"); \ - SCLogOutputBuffer(SC_LOG_DEBUG, \ - _sc_enter_msg); \ + SCLogCheckFDFilterEntry(__FUNCTION__)) \ + { \ + SCLogDebug("Entering ... >>"); \ } \ } while(0) @@ -536,9 +513,7 @@ void SCLogInitLogModuleIfEnvSet(void); void SCLogDeInitLogModule(void); -SCError SCLogMessage(SCLogLevel, char **, const char *, unsigned, const char *); - -void SCLogOutputBuffer(SCLogLevel, char *); +SCError SCLogMessage(SCLogLevel, const char *, unsigned, const char *, SCError, const char *message); SCLogOPBuffer *SCLogAllocLogOPBuffer(void); From 1927b3000c5dfc663042c90cf321e65afc0e34ce Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 29 Jun 2015 18:38:23 +0200 Subject: [PATCH 0601/2553] output: cleanup --- src/util-debug.c | 6 +++--- src/util-debug.h | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/util-debug.c b/src/util-debug.c index e6c22cb58556..529e502a9177 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -264,9 +264,9 @@ static void SCLogOutputBuffer(SCLogLevel log_level, char *msg) * * \retval SC_OK on success; else an error code */ -SCError SCLogMessage(SCLogLevel log_level, const char *file, - unsigned line, const char *function, - SCError error_code, const char *message) +SCError SCLogMessage(const SCLogLevel log_level, const char *file, + const unsigned int line, const char *function, + const SCError error_code, const char *message) { char buffer[SC_LOG_MAX_LOG_MSG_LEN] = ""; char *temp = buffer; diff --git a/src/util-debug.h b/src/util-debug.h index b73c390481e8..191d8287890f 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -513,7 +513,8 @@ void SCLogInitLogModuleIfEnvSet(void); void SCLogDeInitLogModule(void); -SCError SCLogMessage(SCLogLevel, const char *, unsigned, const char *, SCError, const char *message); +SCError SCLogMessage(const SCLogLevel, const char *, const unsigned int, + const char *, const SCError, const char *message); SCLogOPBuffer *SCLogAllocLogOPBuffer(void); From b13de5bf082a0f38424fc73740c8467969716616 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 30 Jun 2015 09:09:17 +0200 Subject: [PATCH 0602/2553] logging: change newline handling --- src/util-debug.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/util-debug.c b/src/util-debug.c index 529e502a9177..17d6ee41f8ad 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -156,7 +156,7 @@ static inline void SCLogPrintToStream(FILE *fd, char *msg) SCMutexLock(&sc_log_stream_lock); #endif /* OS_WIN32 */ - if (fprintf(fd, "%s", msg) < 0) + if (fprintf(fd, "%s\n", msg) < 0) printf("Error writing to stream using fprintf\n"); fflush(fd); @@ -196,8 +196,6 @@ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) */ static void SCLogOutputBuffer(SCLogLevel log_level, char *msg) { - char *temp = msg; - int len = strlen(msg); SCLogOPIfaceCtx *op_iface_ctx = NULL; #define MAX_SUBSTRINGS 30 @@ -209,15 +207,6 @@ static void SCLogOutputBuffer(SCLogLevel log_level, char *msg) return; } - /* We need to add a \n for our messages, before logging them. If the - * messages have hit the 1023 length limit, strip the message to - * accomodate the \n */ - if (len == SC_LOG_MAX_LOG_MSG_LEN - 1) - len = SC_LOG_MAX_LOG_MSG_LEN - 2; - - temp[len] = '\n'; - temp[len + 1] = '\0'; - if (sc_log_config->op_filter_regex != NULL) { if (pcre_exec(sc_log_config->op_filter_regex, sc_log_config->op_filter_regex_study, From b51c4e608f8b188eb65b9fd8ef28805cdeb86678 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 26 Jun 2015 11:32:50 +0200 Subject: [PATCH 0603/2553] logging: optional colors output Construct message per output method. --- src/suricata.c | 2 +- src/util-debug.c | 205 +++++++++++++++++++++++++++++------------------ src/util-debug.h | 2 + 3 files changed, 132 insertions(+), 77 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index b26924f307c5..c7f2ffe9491c 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2317,7 +2317,7 @@ int main(int argc, char **argv) } if(suri.run_mode == RUNMODE_CONF_TEST){ - SCLogInfo("Configuration provided was successfully loaded. Exiting."); + SCLogNotice("Configuration provided was successfully loaded. Exiting."); exit(EXIT_SUCCESS); } diff --git a/src/util-debug.c b/src/util-debug.c index 17d6ee41f8ad..067152ca3fec 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -188,60 +188,6 @@ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) return; } -/** - * \brief Outputs the message sent as the argument - * - * \param msg Pointer to the message that has to be logged - * \param log_level The log_level of the message that has to be logged - */ -static void SCLogOutputBuffer(SCLogLevel log_level, char *msg) -{ - SCLogOPIfaceCtx *op_iface_ctx = NULL; - -#define MAX_SUBSTRINGS 30 - int ov[MAX_SUBSTRINGS]; - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return; - } - - if (sc_log_config->op_filter_regex != NULL) { - if (pcre_exec(sc_log_config->op_filter_regex, - sc_log_config->op_filter_regex_study, - msg, strlen(msg), 0, 0, ov, MAX_SUBSTRINGS) < 0) - return; - } - - op_iface_ctx = sc_log_config->op_ifaces; - while (op_iface_ctx != NULL) { - if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) { - op_iface_ctx = op_iface_ctx->next; - continue; - } - - switch (op_iface_ctx->iface) { - case SC_LOG_OP_IFACE_CONSOLE: - SCLogPrintToStream((log_level == SC_LOG_ERROR)? stderr: stdout, - msg); - break; - case SC_LOG_OP_IFACE_FILE: - SCLogPrintToStream(op_iface_ctx->file_d, msg); - break; - case SC_LOG_OP_IFACE_SYSLOG: - SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), - msg); - break; - default: - break; - } - op_iface_ctx = op_iface_ctx->next; - } - - return; -} - /** * \brief Adds the global log_format to the outgoing buffer * @@ -253,17 +199,33 @@ static void SCLogOutputBuffer(SCLogLevel log_level, char *msg) * * \retval SC_OK on success; else an error code */ -SCError SCLogMessage(const SCLogLevel log_level, const char *file, +static SCError SCLogMessageGetBuffer(struct timeval *tval, int color, char *buffer, size_t buffer_size, + + const SCLogLevel log_level, const char *file, const unsigned int line, const char *function, const SCError error_code, const char *message) { - char buffer[SC_LOG_MAX_LOG_MSG_LEN] = ""; char *temp = buffer; const char *s = NULL; - - struct timeval tval; struct tm *tms = NULL; + char *redb = ""; + char *red = ""; + char *yellowb = ""; + char *yellow = ""; + char *green = ""; + char *blue = ""; + char *reset = ""; + if (color) { + redb = "\x1b[1;31m"; + red = "\x1b[31m"; + yellowb = "\x1b[1;33m"; + yellow = "\x1b[33m"; + green = "\x1b[32m"; + blue = "\x1b[34m"; + reset = "\x1b[0m"; + } + /* no of characters_written(cw) by snprintf */ int cw = 0; @@ -292,15 +254,14 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, case SC_LOG_FMT_TIME: temp_fmt[0] = '\0'; - gettimeofday(&tval, NULL); struct tm local_tm; - tms = SCLocalTime(tval.tv_sec, &local_tm); + tms = SCLocalTime(tval->tv_sec, &local_tm); cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%d/%d/%04d -- %02d:%02d:%02d", - substr, tms->tm_mday, tms->tm_mon + 1, + "%s%s%d/%d/%04d -- %02d:%02d:%02d%s", + substr, green, tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, - tms->tm_sec); + tms->tm_sec, reset); if (cw < 0) goto error; temp += cw; @@ -312,7 +273,7 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, case SC_LOG_FMT_PID: temp_fmt[0] = '\0'; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%u", substr, getpid()); + "%s%s%u%s", substr, yellow, getpid(), reset); if (cw < 0) goto error; temp += cw; @@ -324,7 +285,7 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, case SC_LOG_FMT_TID: temp_fmt[0] = '\0'; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%lu", substr, SCGetThreadIdLong()); + "%s%s%lu%s", substr, yellow, SCGetThreadIdLong(), reset); if (cw < 0) goto error; temp += cw; @@ -355,12 +316,23 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, case SC_LOG_FMT_LOG_LEVEL: temp_fmt[0] = '\0'; s = SCMapEnumValueToName(log_level, sc_log_level_map); - if (s != NULL) - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s", substr, s); - else + if (s != NULL) { + if (log_level <= SC_LOG_ERROR) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%s%s", substr, redb, s, reset); + else if (log_level == SC_LOG_WARNING) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%s%s", substr, red, s, reset); + else if (log_level == SC_LOG_NOTICE) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%s%s", substr, yellowb, s, reset); + else + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%s%s", substr, yellow, s, reset); + } else { cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, "INVALID"); + } if (cw < 0) goto error; temp += cw; @@ -372,7 +344,7 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, case SC_LOG_FMT_FILE_NAME: temp_fmt[0] = '\0'; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s", substr, file); + "%s%s%s%s", substr, blue, file, reset); if (cw < 0) goto error; temp += cw; @@ -384,7 +356,7 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, case SC_LOG_FMT_LINE: temp_fmt[0] = '\0'; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%u", substr, line); + "%s%s%u%s", substr, green, line, reset); if (cw < 0) goto error; temp += cw; @@ -396,7 +368,7 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, case SC_LOG_FMT_FUNCTION: temp_fmt[0] = '\0'; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s", substr, function); + "%s%s%s%s", substr, green, function, reset); if (cw < 0) goto error; temp += cw; @@ -425,7 +397,7 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, if (error_code != SC_OK) { cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "[ERRCODE: %s(%d)] - ", SCErrorToString(error_code), error_code); + "[%sERRCODE%s: %s%s%s(%s%d%s)] - ", yellow, reset, red, SCErrorToString(error_code), reset, yellow, error_code, reset); if (cw < 0) goto error; temp += cw; @@ -436,7 +408,8 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, } } - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", message); + char *xyellow = error_code > SC_OK ? yellow : ""; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", xyellow, message, reset); if (cw < 0) goto error; temp += cw; @@ -448,7 +421,19 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, SCFree(temp_fmt_h); - SCLogOutputBuffer(log_level, buffer); + if (sc_log_config->op_filter_regex != NULL) { +#define MAX_SUBSTRINGS 30 + int ov[MAX_SUBSTRINGS]; + + if (pcre_exec(sc_log_config->op_filter_regex, + sc_log_config->op_filter_regex_study, + buffer, strlen(buffer), 0, 0, ov, MAX_SUBSTRINGS) < 0) + { + return SC_ERR_LOG_FG_FILTER_MATCH; // bit hacky, but just return !0 + } +#undef MAX_SUBSTRINGS + } + return SC_OK; error: @@ -457,6 +442,74 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, return SC_ERR_SPRINTF; } +/** + * \brief Adds the global log_format to the outgoing buffer + * + * \param log_level log_level of the message that has to be logged + * \param msg Buffer containing the outgoing message + * \param file File_name from where the message originated + * \param function Function_name from where the message originated + * \param line Line_no from where the messaged originated + * + * \retval SC_OK on success; else an error code + */ +SCError SCLogMessage(const SCLogLevel log_level, const char *file, + const unsigned int line, const char *function, + const SCError error_code, const char *message) +{ + char buffer[SC_LOG_MAX_LOG_MSG_LEN] = ""; + SCLogOPIfaceCtx *op_iface_ctx = NULL; + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return SC_OK; + } + + /* get ts here so we log the same ts to each output */ + struct timeval tval; + gettimeofday(&tval, NULL); + + op_iface_ctx = sc_log_config->op_ifaces; + while (op_iface_ctx != NULL) { + if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) { + op_iface_ctx = op_iface_ctx->next; + continue; + } + + switch (op_iface_ctx->iface) { + case SC_LOG_OP_IFACE_CONSOLE: + if (SCLogMessageGetBuffer(&tval, op_iface_ctx->use_color, buffer, sizeof(buffer), + log_level, file, line, function, + error_code, message) == 0) + { + SCLogPrintToStream((log_level == SC_LOG_ERROR)? stderr: stdout, buffer); + } + break; + case SC_LOG_OP_IFACE_FILE: + if (SCLogMessageGetBuffer(&tval, 0, buffer, sizeof(buffer), + log_level, file, line, function, + error_code, message) == 0) + { + SCLogPrintToStream(op_iface_ctx->file_d, buffer); + } + break; + case SC_LOG_OP_IFACE_SYSLOG: + if (SCLogMessageGetBuffer(&tval, 0, buffer, sizeof(buffer), + log_level, file, line, function, + error_code, message) == 0) + { + SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), buffer); + } + break; + default: + break; + } + op_iface_ctx = op_iface_ctx->next; + } + return SC_OK; +} + /** * \brief Returns whether debug messages are enabled to be logged or not * @@ -643,7 +696,7 @@ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, iface_ctx->log_level = tmp_log_level; if (isatty(fileno(stdout))) { - + iface_ctx->use_color = TRUE; } return iface_ctx; diff --git a/src/util-debug.h b/src/util-debug.h index 191d8287890f..9356e9a89a38 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -112,6 +112,8 @@ typedef struct SCLogOPBuffer_ { typedef struct SCLogOPIfaceCtx_ { SCLogOPIface iface; + int use_color; + /* the output file to be used if the interface is SC_LOG_IFACE_FILE */ const char *file; /* the output file descriptor for the above file */ From 126ecb3ebf94cf0cb73a472e21f1a827a476c397 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 30 Jun 2015 11:21:39 +0200 Subject: [PATCH 0604/2553] logging: fix per output log formats --- src/util-debug.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/util-debug.c b/src/util-debug.c index 067152ca3fec..ba8f97b40e46 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -200,6 +200,7 @@ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) * \retval SC_OK on success; else an error code */ static SCError SCLogMessageGetBuffer(struct timeval *tval, int color, char *buffer, size_t buffer_size, + const char *log_format, const SCLogLevel log_level, const char *file, const unsigned int line, const char *function, @@ -237,7 +238,7 @@ static SCError SCLogMessageGetBuffer(struct timeval *tval, int color, char *buff return SC_ERR_LOG_MODULE_NOT_INIT; } - char *temp_fmt = strdup(sc_log_config->log_format); + char *temp_fmt = strdup(log_format); if (unlikely(temp_fmt == NULL)) { return SC_ERR_MEM_ALLOC; } @@ -480,6 +481,8 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, switch (op_iface_ctx->iface) { case SC_LOG_OP_IFACE_CONSOLE: if (SCLogMessageGetBuffer(&tval, op_iface_ctx->use_color, buffer, sizeof(buffer), + op_iface_ctx->log_format ? + op_iface_ctx->log_format : sc_log_config->log_format, log_level, file, line, function, error_code, message) == 0) { @@ -488,6 +491,8 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, break; case SC_LOG_OP_IFACE_FILE: if (SCLogMessageGetBuffer(&tval, 0, buffer, sizeof(buffer), + op_iface_ctx->log_format ? + op_iface_ctx->log_format : sc_log_config->log_format, log_level, file, line, function, error_code, message) == 0) { @@ -496,6 +501,8 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, break; case SC_LOG_OP_IFACE_SYSLOG: if (SCLogMessageGetBuffer(&tval, 0, buffer, sizeof(buffer), + op_iface_ctx->log_format ? + op_iface_ctx->log_format : sc_log_config->log_format, log_level, file, line, function, error_code, message) == 0) { From 45fc619f79cd4a0398a23fbd78d9ce4719174bd3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 21 May 2015 17:33:53 +0200 Subject: [PATCH 0605/2553] logging: json output Make JSON output optional. Cleanups. --- src/util-debug.c | 262 ++++++++++++++++++++--------------------------- src/util-debug.h | 10 +- 2 files changed, 117 insertions(+), 155 deletions(-) diff --git a/src/util-debug.c b/src/util-debug.c index ba8f97b40e46..f1ac0463e505 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -188,6 +188,69 @@ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) return; } +#ifdef HAVE_LIBJANSSON +/** + */ +int SCLogMessageJSON(struct timeval *tval, char *buffer, size_t buffer_size, + SCLogLevel log_level, const char *file, + unsigned line, const char *function, SCError error_code, + const char *message) +{ + json_t *js = json_object(); + if (unlikely(js == NULL)) + goto error; + json_t *ejs = json_object(); + if (unlikely(ejs == NULL)) + goto error; + + char timebuf[64]; + CreateIsoTimeString(tval, timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); + + json_object_set_new(js, "event_type", json_string("engine")); + + if (error_code > 0) { + json_object_set_new(ejs, "error_code", json_integer(error_code)); + json_object_set_new(ejs, "error", json_string(SCErrorToString(error_code))); + } + + if (message) + json_object_set_new(ejs, "message", json_string(message)); + + if (log_level >= SC_LOG_DEBUG) { + if (function) + json_object_set_new(ejs, "function", json_string(function)); + + if (file) + json_object_set_new(ejs, "file", json_string(file)); + + if (line > 0) + json_object_set_new(ejs, "line", json_integer(line)); + } + + json_object_set_new(js, "engine", ejs); + + char *js_s = json_dumps(js, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| +#ifdef JSON_ESCAPE_SLASH + JSON_ESCAPE_SLASH +#else + 0 +#endif + ); + snprintf(buffer, buffer_size, "%s", js_s); + free(js_s); + + json_object_del(js, "engine"); + json_object_clear(js); + json_decref(js); + + return 0; +error: + return -1; +} +#endif /* HAVE_LIBJANSSON */ + /** * \brief Adds the global log_format to the outgoing buffer * @@ -199,13 +262,20 @@ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) * * \retval SC_OK on success; else an error code */ -static SCError SCLogMessageGetBuffer(struct timeval *tval, int color, char *buffer, size_t buffer_size, +static SCError SCLogMessageGetBuffer( + struct timeval *tval, int color, SCLogOPType type, + char *buffer, size_t buffer_size, const char *log_format, const SCLogLevel log_level, const char *file, const unsigned int line, const char *function, const SCError error_code, const char *message) { +#ifdef HAVE_LIBJANSSON + if (type == SC_LOG_OP_TYPE_JSON) + return SCLogMessageJSON(tval, buffer, buffer_size, log_level, file, line, function, error_code, message); +#endif + char *temp = buffer; const char *s = NULL; struct tm *tms = NULL; @@ -480,7 +550,8 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, switch (op_iface_ctx->iface) { case SC_LOG_OP_IFACE_CONSOLE: - if (SCLogMessageGetBuffer(&tval, op_iface_ctx->use_color, buffer, sizeof(buffer), + if (SCLogMessageGetBuffer(&tval, op_iface_ctx->use_color, op_iface_ctx->type, + buffer, sizeof(buffer), op_iface_ctx->log_format ? op_iface_ctx->log_format : sc_log_config->log_format, log_level, file, line, function, @@ -490,7 +561,7 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, } break; case SC_LOG_OP_IFACE_FILE: - if (SCLogMessageGetBuffer(&tval, 0, buffer, sizeof(buffer), + if (SCLogMessageGetBuffer(&tval, 0, op_iface_ctx->type, buffer, sizeof(buffer), op_iface_ctx->log_format ? op_iface_ctx->log_format : sc_log_config->log_format, log_level, file, line, function, @@ -500,7 +571,7 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, } break; case SC_LOG_OP_IFACE_SYSLOG: - if (SCLogMessageGetBuffer(&tval, 0, buffer, sizeof(buffer), + if (SCLogMessageGetBuffer(&tval, 0, op_iface_ctx->type, buffer, sizeof(buffer), op_iface_ctx->log_format ? op_iface_ctx->log_format : sc_log_config->log_format, log_level, file, line, function, @@ -599,7 +670,8 @@ static inline SCLogOPIfaceCtx *SCLogAllocLogOPIfaceCtx() */ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, const char *log_format, - int log_level) + int log_level, + SCLogOPType type) { SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); @@ -613,6 +685,7 @@ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, } iface_ctx->iface = SC_LOG_OP_IFACE_FILE; + iface_ctx->type = type; if ( (iface_ctx->file_d = fopen(file, "w+")) == NULL) { printf("Error opening file %s\n", file); @@ -659,7 +732,7 @@ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, * \initonly */ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, - SCLogLevel log_level) + SCLogLevel log_level, SCLogOPType type) { SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); @@ -669,6 +742,7 @@ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, } iface_ctx->iface = SC_LOG_OP_IFACE_CONSOLE; + iface_ctx->type = type; /* console log format is overridden by envvars */ const char *tmp_log_format = log_format; @@ -721,7 +795,8 @@ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, */ static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility, const char *log_format, - SCLogLevel log_level) + SCLogLevel log_level, + SCLogOPType type) { SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); @@ -731,6 +806,7 @@ static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility, } iface_ctx->iface = SC_LOG_OP_IFACE_SYSLOG; + iface_ctx->type = type; if (facility == -1) facility = SC_LOG_DEF_SYSLOG_FACILITY; @@ -906,18 +982,18 @@ static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc) switch (op_iface) { case SC_LOG_OP_IFACE_CONSOLE: - op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX); + op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX,0); break; case SC_LOG_OP_IFACE_FILE: s = getenv(SC_LOG_ENV_LOG_FILE); if (s == NULL) { char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE); if (str != NULL) { - op_ifaces_ctx = SCLogInitFileOPIface(str, NULL, SC_LOG_LEVEL_MAX); + op_ifaces_ctx = SCLogInitFileOPIface(str, NULL, SC_LOG_LEVEL_MAX,0); SCFree(str); } } else { - op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, SC_LOG_LEVEL_MAX); + op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, SC_LOG_LEVEL_MAX,0); } break; case SC_LOG_OP_IFACE_SYSLOG: @@ -925,13 +1001,12 @@ static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc) if (s == NULL) s = SC_LOG_DEF_SYSLOG_FACILITY_STR; - op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1); + op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1,0); break; } sc_lc->op_ifaces = op_ifaces_ctx; sc_lc->op_ifaces_cnt++; } - return; } @@ -1113,11 +1188,12 @@ SCLogOPIfaceCtx *SCLogInitOPIfaceCtx(const char *iface_name, switch (iface) { case SC_LOG_OP_IFACE_CONSOLE: - return SCLogInitConsoleOPIface(log_format, log_level); + return SCLogInitConsoleOPIface(log_format, log_level, SC_LOG_OP_TYPE_REGULAR); case SC_LOG_OP_IFACE_FILE: - return SCLogInitFileOPIface(arg, log_format, log_level); + return SCLogInitFileOPIface(arg, log_format, log_level, SC_LOG_OP_TYPE_REGULAR); case SC_LOG_OP_IFACE_SYSLOG: - return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()), log_format, log_level); + return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()), + log_format, log_level, SC_LOG_OP_TYPE_REGULAR); default: #ifdef DEBUG printf("Output Interface \"%s\" not supported by the logging module", @@ -1230,6 +1306,22 @@ void SCLogLoadConfig(int daemon, int verbose) if (enabled != NULL && ConfValIsFalse(enabled)) continue; + SCLogOPType type = SC_LOG_OP_TYPE_REGULAR; + const char *type_s = ConfNodeLookupChildValue(output, "type"); + if (type_s != NULL) { + if (strcmp(type_s, "regular") == 0) + type = SC_LOG_OP_TYPE_REGULAR; + else if (strcmp(type_s, "json") == 0) { +#ifdef HAVE_LIBJANSSON + type = SC_LOG_OP_TYPE_JSON; +#else + SCLogError(SC_ERR_INVALID_ARGUMENT, "libjansson support not " + "compiled in, can't use 'json' logging"); + exit(EXIT_FAILURE); +#endif /* HAVE_LIBJANSSON */ + } + } + /* if available use the log format setting for this output, * otherwise fall back to the global setting. */ format = ConfNodeLookupChildValue(output, "format"); @@ -1247,7 +1339,7 @@ void SCLogLoadConfig(int daemon, int verbose) } if (strcmp(output->name, "console") == 0) { - op_iface_ctx = SCLogInitConsoleOPIface(format, level); + op_iface_ctx = SCLogInitConsoleOPIface(format, level, type); } else if (strcmp(output->name, "file") == 0) { const char *filename = ConfNodeLookupChildValue(output, "filename"); @@ -1257,7 +1349,7 @@ void SCLogLoadConfig(int daemon, int verbose) exit(EXIT_FAILURE); } have_logging = 1; - op_iface_ctx = SCLogInitFileOPIface(filename, format, level); + op_iface_ctx = SCLogInitFileOPIface(filename, format, level, type); } else if (strcmp(output->name, "syslog") == 0) { int facility = SC_LOG_DEF_SYSLOG_FACILITY; @@ -1275,7 +1367,7 @@ void SCLogLoadConfig(int daemon, int verbose) printf("Initialization syslog logging with format \"%s\".\n", format); have_logging = 1; - op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level); + op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level, type); } else { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid logging method: %s, " @@ -1299,144 +1391,10 @@ void SCLogLoadConfig(int daemon, int verbose) SCLogDebug("sc_lc->log_format: %s", sc_log_config->log_format); SCLogDebug("SCLogSetOPFilter: filter: %s", sc_log_config->op_filter); - //exit(1); - /* \todo Can we free sc_lid now? */ if (sc_lid != NULL) SCFree(sc_lid); } -/** - * \brief Initializes the logging module if the environment variables are set. - * Used at the start of the engine, for cases, where there is an error - * in the yaml parsing code, and we want to enable the logging module. - */ -void SCLogInitLogModuleIfEnvSet(void) -{ - SCLogConfig *sc_lc = NULL; - const char *s = NULL; - const char *filter = NULL; - int opts = 0; - const char *ep; - int eo = 0; - SCLogOPIfaceCtx *op_ifaces_ctx = NULL; - int op_iface = 0; - char *format = NULL; - SCLogLevel log_level = SC_LOG_NOTSET; - - /* sc_log_config is a global variable */ - if ( (sc_log_config = SCMalloc(sizeof(SCLogConfig))) == NULL) - return; - memset(sc_log_config, 0, sizeof(SCLogConfig)); - sc_lc = sc_log_config; - - /* Check if the user has set the op_iface env var. Only if it is set, - * we proceed with the initialization */ - s = getenv(SC_LOG_ENV_LOG_OP_IFACE); - if (s != NULL) { - op_iface = SCMapEnumNameToValue(s, sc_log_op_iface_map); - - if(op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) { - op_iface = SC_LOG_DEF_LOG_OP_IFACE; -#ifndef UNITTESTS - printf("Warning: Invalid output interface supplied by user. " - "Falling back on default_output_interface \"%s\"\n", - SCMapEnumValueToName(op_iface, sc_log_op_iface_map)); -#endif - } - } else { - SCLogFreeLogConfig(sc_lc); - sc_log_config = NULL; - return; - } - - switch (op_iface) { - case SC_LOG_OP_IFACE_CONSOLE: - op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, -1); - break; - case SC_LOG_OP_IFACE_FILE: - s = getenv(SC_LOG_ENV_LOG_FILE); - if (s == NULL) { - char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE); - if (str != NULL) { - op_ifaces_ctx = SCLogInitFileOPIface(str, NULL, SC_LOG_LEVEL_MAX); - SCFree(str); - } - } else { - op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, -1); - } - break; - case SC_LOG_OP_IFACE_SYSLOG: - s = getenv(SC_LOG_ENV_LOG_FACILITY); - if (s == NULL) - s = SC_LOG_DEF_SYSLOG_FACILITY_STR; - - op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1); - break; - } - sc_lc->op_ifaces = op_ifaces_ctx; - - - /* Set the filter */ - filter = getenv(SC_LOG_ENV_LOG_OP_FILTER); - if (filter != NULL && strcmp(filter, "") != 0) { - sc_lc->op_filter_regex = pcre_compile(filter, opts, &ep, &eo, NULL); - if (sc_lc->op_filter_regex == NULL) { - printf("pcre compile of \"%s\" failed at offset %d : %s\n", filter, - eo, ep); - return; - } - - sc_lc->op_filter_regex_study = pcre_study(sc_lc->op_filter_regex, 0, - &ep); - if (ep != NULL) { - printf("pcre study failed: %s\n", ep); - return; - } - } - - /* Set the log_format */ - format = getenv(SC_LOG_ENV_LOG_FORMAT); - if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) { - format = SC_LOG_DEF_LOG_FORMAT; -#ifndef UNITTESTS - printf("Warning: Invalid global_log_format supplied by user or format " - "length exceeded limit of \"%d\" characters. Falling back on " - "default log_format \"%s\"\n", SC_LOG_MAX_LOG_FORMAT_LEN, - format); -#endif - } - - if (format != NULL && - (sc_lc->log_format = SCStrdup(format)) == NULL) { - printf("Error allocating memory\n"); - exit(EXIT_FAILURE); - } - - /* Set the log_level */ - s = getenv(SC_LOG_ENV_LOG_LEVEL); - if (s != NULL) - log_level = SCMapEnumNameToValue(s, sc_log_level_map); - - if (log_level >= 0 && log_level < SC_LOG_LEVEL_MAX) - sc_lc->log_level = log_level; - else { - sc_lc->log_level = SC_LOG_DEF_LOG_LEVEL; -#ifndef UNITTESTS - printf("Warning: Invalid global_log_level assigned by user. Falling " - "back on default_log_level \"%s\"\n", - SCMapEnumValueToName(sc_lc->log_level, sc_log_level_map)); -#endif - } - - /* we also set it to a global var, as it is easier to access it */ - sc_log_global_log_level = sc_lc->log_level; - - sc_log_module_initialized = 1; - sc_log_module_cleaned = 0; - - return; -} - /** * \brief Returns a full file path given a filename uses log dir specified in * conf or DEFAULT_LOG_DIR diff --git a/src/util-debug.h b/src/util-debug.h index 9356e9a89a38..02ea30e2b08b 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -70,6 +70,11 @@ typedef enum { SC_LOG_OP_IFACE_MAX, } SCLogOPIface; +typedef enum { + SC_LOG_OP_TYPE_REGULAR = 0, + SC_LOG_OP_TYPE_JSON, +} SCLogOPType; + /* The default log_format, if it is not supplied by the user */ #ifdef RELEASE #define SC_LOG_DEF_LOG_FORMAT "%t - <%d> - " @@ -112,7 +117,8 @@ typedef struct SCLogOPBuffer_ { typedef struct SCLogOPIfaceCtx_ { SCLogOPIface iface; - int use_color; + int16_t use_color; + int16_t type; /* the output file to be used if the interface is SC_LOG_IFACE_FILE */ const char *file; @@ -511,8 +517,6 @@ void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *, SCLogInitData *); void SCLogInitLogModule(SCLogInitData *); -void SCLogInitLogModuleIfEnvSet(void); - void SCLogDeInitLogModule(void); SCError SCLogMessage(const SCLogLevel, const char *, const unsigned int, From cd038419fdea04542c57a38c55f7147ca1839fca Mon Sep 17 00:00:00 2001 From: Zopieux Date: Thu, 18 Jun 2015 11:26:53 +0200 Subject: [PATCH 0606/2553] stream_size operator comparison (fix issue #1488) `DetectStreamSizeParse` was first checking if mode[0] is '<', which is true for both '<' and '<=', thus '<=' (and resp. '>=') is never matched. This patch does the `strcmp` to '<=' (resp. '>=') within the if block of '<' (resp. '>') to fix #1488. --- src/detect-stream_size.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c index bec2edce6ef9..c3eaad90f014 100644 --- a/src/detect-stream_size.c +++ b/src/detect-stream_size.c @@ -244,19 +244,19 @@ DetectStreamSizeData *DetectStreamSizeParse (char *streamstr) if (strlen(mode) == 0) goto error; - if (mode[0] == '<') + if (mode[0] == '=') { + sd->mode = DETECTSSIZE_EQ; + } else if (mode[0] == '<') { sd->mode = DETECTSSIZE_LT; - else if (strcmp("<=", mode) == 0) - sd->mode = DETECTSSIZE_LEQ; - else if (mode[0] == '>') + if (strcmp("<=", mode) == 0) + sd->mode = DETECTSSIZE_LEQ; + } else if (mode[0] == '>') { sd->mode = DETECTSSIZE_GT; - else if (strcmp(">=", mode) == 0) - sd->mode = DETECTSSIZE_GEQ; - else if (strcmp("!=", mode) == 0) + if (strcmp(">=", mode) == 0) + sd->mode = DETECTSSIZE_GEQ; + } else if (strcmp("!=", mode) == 0) { sd->mode = DETECTSSIZE_NEQ; - else if (mode[0] == '=') - sd->mode = DETECTSSIZE_EQ; - else { + } else { SCLogError(SC_ERR_INVALID_OPERATOR, "Invalid operator"); goto error; } From a9176cf1269e96125505fdffe03d07b368143bca Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Tue, 16 Jun 2015 18:12:01 +0300 Subject: [PATCH 0607/2553] suricatasc: remove "u" prefix when printing JSON output. If we want to parse suricatasc's output, python's unicode prefix should be removed to make JSON parsers happy. --- scripts/suricatasc/suricatasc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/suricatasc/suricatasc.in b/scripts/suricatasc/suricatasc.in index 4b44204bcf50..6c33ba3237d9 100755 --- a/scripts/suricatasc/suricatasc.in +++ b/scripts/suricatasc/suricatasc.in @@ -42,7 +42,7 @@ except SuricataReturnException as err: if args.command: (command, arguments) = sc.parse_command(args.command) res = sc.send_command(command, arguments) - print(res) + print(json.dumps(res)) sc.close() if res['return'] == 'OK': sys.exit(0) From e0289179557117897245510e4b119a66f97db2fb Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Thu, 18 Jun 2015 20:44:26 +0300 Subject: [PATCH 0608/2553] In non interactive mode, print errors to stderr --- scripts/suricatasc/suricatasc.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/suricatasc/suricatasc.in b/scripts/suricatasc/suricatasc.in index 6c33ba3237d9..63b4ebfaf5ab 100755 --- a/scripts/suricatasc/suricatasc.in +++ b/scripts/suricatasc/suricatasc.in @@ -15,6 +15,8 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +from __future__ import print_function +import sys import argparse from suricatasc import * @@ -33,10 +35,10 @@ sc = SuricataSC(SOCKET_PATH, verbose=args.verbose) try: sc.connect() except SuricataNetException as err: - print("Unable to connect to socket %s: %s" % (SOCKET_PATH, err)) + print("Unable to connect to socket %s: %s" % (SOCKET_PATH, err), file=sys.stderr) sys.exit(1) except SuricataReturnException as err: - print("Unable to negotiate version with server: %s" % (err)) + print("Unable to negotiate version with server: %s" % (err), file=sys.stderr) sys.exit(1) if args.command: From e58cfb6a05b2938a3b79f924fc79de81560dbc30 Mon Sep 17 00:00:00 2001 From: sfd Date: Fri, 3 Jul 2015 16:43:02 +1200 Subject: [PATCH 0609/2553] Fix compile bad dereferences The src/source-erf-dag.c code was not compiling. It looks like some stats counters were added but not tested as the dereferences are incorrect. --- src/source-erf-dag.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index 2614dd05b3df..f66407122fcf 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -442,7 +442,7 @@ ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) break; case TYPE_ETH: if (dr->lctr) { - StatsAddUI64(tv, ewtn->drops, ntohs(dr->lctr)); + StatsAddUI64(ewtn->tv, ewtn->drops, ntohs(dr->lctr)); } break; default: @@ -535,7 +535,7 @@ ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) p->ts.tv_sec++; } - StatsIncr(tv, ewtn->packets); + StatsIncr(ewtn->tv, ewtn->packets); ewtn->bytes += wlen; if (TmThreadsSlotProcessPkt(ewtn->tv, ewtn->slot, p) != TM_ECODE_OK) { From f43767ba445b9536e797b432ca5e9848846d9d36 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Jul 2015 16:12:29 +0200 Subject: [PATCH 0610/2553] config: update yaml to show json logging option --- suricata.yaml.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/suricata.yaml.in b/suricata.yaml.in index a4c7ab5aab32..64a8182a298b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -901,13 +901,16 @@ logging: outputs: - console: enabled: yes + # type: json - file: enabled: no filename: /var/log/suricata.log + # type: json - syslog: enabled: no facility: local5 format: "[%i] <%d> -- " + # type: json # Tilera mpipe configuration. for use on Tilera TILE-Gx. mpipe: From 14981cb2a84951ff1ce4e8d911ebc7cdd9b22755 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 17 Jul 2015 16:22:59 -0600 Subject: [PATCH 0611/2553] rule vars: strip leading white space before looking up var. --- src/util-rule-vars.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/util-rule-vars.c b/src/util-rule-vars.c index f060a14af1cb..f3b5604fbed2 100644 --- a/src/util-rule-vars.c +++ b/src/util-rule-vars.c @@ -74,6 +74,11 @@ char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx, if (conf_var_name == NULL) goto end; + + while (conf_var_name[0] != '\0' && isspace(conf_var_name[0])) { + conf_var_name++; + } + (conf_var_name[0] == '$') ? conf_var_name++ : conf_var_name; conf_var_type_name = SCMapEnumValueToName(conf_vars_type, sc_rule_vars_type_map); @@ -214,6 +219,11 @@ int SCRuleVarsPositiveTest01(void) strcmp(SCRuleVarsGetConfVar(NULL,"$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "any") == 0); + /* Test that a leading space is stripped. */ + result &= (SCRuleVarsGetConfVar(NULL," $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL," $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + "any") == 0); + /* check for port-groups */ result &= (SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), From b512580bbe28cb1109fd876a653abf486aa02ad9 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 8 Jul 2015 09:49:41 -0600 Subject: [PATCH 0612/2553] logging: integrate rotation into SCConfLogOpenGeneric. Addresses issue 1492, and will make it harder to omit rotation on new outputs. --- src/alert-debuglog.c | 4 +--- src/alert-fastlog.c | 4 +--- src/log-dnslog.c | 4 +--- src/log-droplog.c | 4 +--- src/log-file.c | 4 +--- src/log-httplog.c | 4 +--- src/log-stats.c | 4 +--- src/log-tcp-data.c | 2 +- src/log-tlslog.c | 4 +--- src/output-json-alert.c | 2 +- src/output-json-dns.c | 2 +- src/output-json-drop.c | 2 +- src/output-json-flow.c | 2 +- src/output-json-http.c | 2 +- src/output-json-netflow.c | 2 +- src/output-json-smtp.c | 2 +- src/output-json-ssh.c | 2 +- src/output-json-stats.c | 2 +- src/output-json-tls.c | 2 +- src/output-json.c | 3 +-- src/util-logopenfile.c | 9 ++++++++- src/util-logopenfile.h | 2 +- 22 files changed, 29 insertions(+), 39 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 27710a9d5903..5df1f4c1e9f5 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -448,7 +448,6 @@ static void AlertDebugLogDeInitCtx(OutputCtx *output_ctx) { if (output_ctx != NULL) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; - OutputUnregisterFileRotationFlag(&logfile_ctx->rotation_flag); if (logfile_ctx != NULL) { LogFileFreeCtx(logfile_ctx); } @@ -473,10 +472,9 @@ static OutputCtx *AlertDebugLogInitCtx(ConfNode *conf) goto error; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { goto error; } - OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); OutputCtx *output_ctx = SCMalloc(sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 9e47c73dd4fc..41630f8a3ac0 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -250,11 +250,10 @@ OutputCtx *AlertFastLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } - OutputRegisterFileRotationFlag(&logfile_ctx->rotation_flag); OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) @@ -268,7 +267,6 @@ OutputCtx *AlertFastLogInitCtx(ConfNode *conf) static void AlertFastLogDeInitCtx(OutputCtx *output_ctx) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; - OutputUnregisterFileRotationFlag(&logfile_ctx->rotation_flag); LogFileFreeCtx(logfile_ctx); SCFree(output_ctx); } diff --git a/src/log-dnslog.c b/src/log-dnslog.c index f0f381b521aa..e30c3d3e0c1a 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -294,7 +294,6 @@ static void LogDnsLogExitPrintStats(ThreadVars *tv, void *data) static void LogDnsLogDeInitCtx(OutputCtx *output_ctx) { LogDnsFileCtx *dnslog_ctx = (LogDnsFileCtx *)output_ctx->data; - OutputUnregisterFileRotationFlag(&dnslog_ctx->file_ctx->rotation_flag); LogFileFreeCtx(dnslog_ctx->file_ctx); SCFree(dnslog_ctx); SCFree(output_ctx); @@ -313,11 +312,10 @@ static OutputCtx *LogDnsLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } - OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); LogDnsFileCtx *dnslog_ctx = SCMalloc(sizeof(LogDnsFileCtx)); if (unlikely(dnslog_ctx == NULL)) { diff --git a/src/log-droplog.c b/src/log-droplog.c index 69b8539fbdb5..1ee2d999f7ba 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -125,7 +125,6 @@ static void LogDropLogDeInitCtx(OutputCtx *output_ctx) if (output_ctx != NULL) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; if (logfile_ctx != NULL) { - OutputUnregisterFileRotationFlag(&logfile_ctx->rotation_flag); LogFileFreeCtx(logfile_ctx); } SCFree(output_ctx); @@ -151,11 +150,10 @@ static OutputCtx *LogDropLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } - OutputRegisterFileRotationFlag(&logfile_ctx->rotation_flag); OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { diff --git a/src/log-file.c b/src/log-file.c index 439ca3227fe1..0c41e38d298c 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -388,7 +388,6 @@ void LogFileLogExitPrintStats(ThreadVars *tv, void *data) static void LogFileLogDeInitCtx(OutputCtx *output_ctx) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; - OutputUnregisterFileRotationFlag(&logfile_ctx->rotation_flag); LogFileFreeCtx(logfile_ctx); free(output_ctx); } @@ -405,11 +404,10 @@ static OutputCtx *LogFileLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } - OutputRegisterFileRotationFlag(&logfile_ctx->rotation_flag); OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) diff --git a/src/log-httplog.c b/src/log-httplog.c index 609157808bc9..b9723d8c15ae 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -599,11 +599,10 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } - OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); LogHttpFileCtx *httplog_ctx = SCMalloc(sizeof(LogHttpFileCtx)); if (unlikely(httplog_ctx == NULL)) { @@ -733,7 +732,6 @@ static void LogHttpLogDeInitCtx(OutputCtx *output_ctx) for (i = 0; i < httplog_ctx->cf_n; i++) { SCFree(httplog_ctx->cf_nodes[i]); } - OutputUnregisterFileRotationFlag(&httplog_ctx->file_ctx->rotation_flag); LogFileFreeCtx(httplog_ctx->file_ctx); SCFree(httplog_ctx); SCFree(output_ctx); diff --git a/src/log-stats.c b/src/log-stats.c index d7c050b2c5e5..5fcb1c9f62df 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -221,7 +221,7 @@ OutputCtx *LogStatsLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } @@ -263,14 +263,12 @@ OutputCtx *LogStatsLogInitCtx(ConfNode *conf) SCLogDebug("STATS log output initialized"); - OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); return output_ctx; } static void LogStatsLogDeInitCtx(OutputCtx *output_ctx) { LogStatsFileCtx *statslog_ctx = (LogStatsFileCtx *)output_ctx->data; - OutputUnregisterFileRotationFlag(&statslog_ctx->file_ctx->rotation_flag); LogFileFreeCtx(statslog_ctx->file_ctx); SCFree(statslog_ctx); SCFree(output_ctx); diff --git a/src/log-tcp-data.c b/src/log-tcp-data.c index 2133f9de4a01..c41dd4c238c3 100644 --- a/src/log-tcp-data.c +++ b/src/log-tcp-data.c @@ -293,7 +293,7 @@ OutputCtx *LogTcpDataLogInitCtx(ConfNode *conf) if (tcpdatalog_ctx->file == 1) { SCLogInfo("opening logfile"); - if (SCConfLogOpenGeneric(conf, file_ctx, filename) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, filename, 1) < 0) { LogFileFreeCtx(file_ctx); SCFree(tcpdatalog_ctx); return NULL; diff --git a/src/log-tlslog.c b/src/log-tlslog.c index 580b0a20226c..c2b17e7f1bf0 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -382,7 +382,6 @@ static void LogTlsLogDeInitCtx(OutputCtx *output_ctx) OutputTlsLoggerDisable(); LogTlsFileCtx *tlslog_ctx = (LogTlsFileCtx *) output_ctx->data; - OutputUnregisterFileRotationFlag(&tlslog_ctx->file_ctx->rotation_flag); LogFileFreeCtx(tlslog_ctx->file_ctx); SCFree(tlslog_ctx); SCFree(output_ctx); @@ -436,10 +435,9 @@ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf) } } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { goto filectx_error; } - OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); LogTlsFileCtx *tlslog_ctx = SCCalloc(1, sizeof(LogTlsFileCtx)); if (unlikely(tlslog_ctx == NULL)) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index cbb2ed475880..887c23e7776b 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -550,7 +550,7 @@ static OutputCtx *JsonAlertLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } diff --git a/src/output-json-dns.c b/src/output-json-dns.c index d0be0e6aa8f1..89c11b3eefaa 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -382,7 +382,7 @@ static OutputCtx *JsonDnsLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 9f457ab7df59..d0a4275fd59b 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -261,7 +261,7 @@ static OutputCtx *JsonDropLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, drop_ctx->file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, drop_ctx->file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { JsonDropOutputCtxFree(drop_ctx); return NULL; } diff --git a/src/output-json-flow.c b/src/output-json-flow.c index aefa5cf95227..7ff0d3d22ebc 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -352,7 +352,7 @@ OutputCtx *OutputFlowLogInit(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } diff --git a/src/output-json-http.c b/src/output-json-http.c index f5152be547d1..316419855aa1 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -414,7 +414,7 @@ OutputCtx *OutputHttpLogInit(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 198dd58fc0a8..153beb3ded39 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -335,7 +335,7 @@ OutputCtx *OutputNetFlowLogInit(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 83e9d12c0f2c..f722c383e0b2 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -90,7 +90,7 @@ OutputCtx *OutputSmtpLogInit(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index dd68020c60e0..3dc4d10f843f 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -211,7 +211,7 @@ OutputCtx *OutputSshLogInit(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 0778bfe6d3ea..fea7177aa8fb 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -259,7 +259,7 @@ OutputCtx *OutputStatsLogInit(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } diff --git a/src/output-json-tls.c b/src/output-json-tls.c index ef28b55ddea4..4cbd21aec6d6 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -245,7 +245,7 @@ OutputCtx *OutputTlsLogInit(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } diff --git a/src/output-json.c b/src/output-json.c index 4dea72c8618f..74289f1b5854 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -488,7 +488,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) json_ctx->json_out == LOGFILE_TYPE_UNIX_DGRAM || json_ctx->json_out == LOGFILE_TYPE_UNIX_STREAM) { - if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(json_ctx->file_ctx); SCFree(json_ctx); SCFree(output_ctx); @@ -559,7 +559,6 @@ static void OutputJsonDeInitCtx(OutputCtx *output_ctx) { OutputJsonCtx *json_ctx = (OutputJsonCtx *)output_ctx->data; LogFileCtx *logfile_ctx = json_ctx->file_ctx; - OutputUnregisterFileRotationFlag(&logfile_ctx->rotation_flag); LogFileFreeCtx(logfile_ctx); SCFree(json_ctx); SCFree(output_ctx); diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index fcef26d623e2..0e548d1ce130 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -142,13 +142,15 @@ static PcieFile *SCLogOpenPcieFp(LogFileCtx *log_ctx, const char *path, * \param conf ConfNode structure for the output section in question * \param log_ctx Log file context allocated by caller * \param default_filename Default name of file to open, if not specified in ConfNode + * \param rotate Register the file for rotation in HUP. * \retval 0 on success * \retval -1 on error */ int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *log_ctx, - const char *default_filename) + const char *default_filename, + int rotate) { char log_path[PATH_MAX]; char *log_dir; @@ -211,6 +213,9 @@ SCConfLogOpenGeneric(ConfNode *conf, "filename"); return -1; } + if (rotate) { + OutputRegisterFileRotationFlag(&log_ctx->rotation_flag); + } } else if (strcasecmp(filetype, "pcie") == 0) { log_ctx->pcie_fp = SCLogOpenPcieFp(log_ctx, log_path, append); if (log_ctx->pcie_fp == NULL) @@ -307,6 +312,8 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) if(lf_ctx->filename != NULL) SCFree(lf_ctx->filename); + OutputUnregisterFileRotationFlag(&lf_ctx->rotation_flag); + SCFree(lf_ctx); SCReturnInt(1); diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 5d144f95d43e..1f10e3491bbf 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -85,7 +85,7 @@ typedef struct LogFileCtx_ { LogFileCtx *LogFileNewCtx(void); int LogFileFreeCtx(LogFileCtx *); -int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *, const char *); +int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *, const char *, int); int SCConfLogReopen(LogFileCtx *); #endif /* __UTIL_LOGOPENFILE_H__ */ From 893fc9660dcaf613162140c442d71b338047ea3e Mon Sep 17 00:00:00 2001 From: Jeff Barber Date: Thu, 16 Jul 2015 09:39:15 -0400 Subject: [PATCH 0613/2553] Support for reconnecting unix domain socket log files Issue #1423 --- src/util-logopenfile.c | 93 +++++++++++++++++++++++++++++++++++------- src/util-logopenfile.h | 8 ++++ 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 0e548d1ce130..b25c4a82705f 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -36,11 +36,12 @@ /** \brief connect to the indicated local stream socket, logging any errors * \param path filesystem path to connect to + * \param log_err, non-zero if connect failure should be logged. * \retval FILE* on success (fdopen'd wrapper of underlying socket) * \retval NULL on error */ static FILE * -SCLogOpenUnixSocketFp(const char *path, int sock_type) +SCLogOpenUnixSocketFp(const char *path, int sock_type, int log_err) { struct sockaddr_un sun; int s = -1; @@ -64,8 +65,10 @@ SCLogOpenUnixSocketFp(const char *path, int sock_type) return ret; err: - SCLogError(SC_ERR_SOCKET, "Error connecting to socket \"%s\": %s", - path, strerror(errno)); + if (log_err) + SCLogWarning(SC_ERR_SOCKET, + "Error connecting to socket \"%s\": %s (will keep trying)", + path, strerror(errno)); if (s >= 0) close(s); @@ -73,6 +76,52 @@ SCLogOpenUnixSocketFp(const char *path, int sock_type) return NULL; } +/** + * \brief Attempt to reconnect a disconnected (or never-connected) Unix domain socket. + * \retval 1 if it is now connected; otherwise 0 + */ +static int SCLogUnixSocketReconnect(LogFileCtx *log_ctx) +{ + int disconnected = 0; + if (log_ctx->fp) { + SCLogWarning(SC_ERR_SOCKET, + "Write error on Unix socket \"%s\": %s; reconnecting...", + log_ctx->filename, strerror(errno)); + fclose(log_ctx->fp); + log_ctx->fp = NULL; + log_ctx->reconn_timer = 0; + disconnected = 1; + } + + struct timeval tv; + uint64_t now; + gettimeofday(&tv, NULL); + now = (uint64_t)tv.tv_sec * 1000; + now += tv.tv_usec / 1000; /* msec resolution */ + if (log_ctx->reconn_timer != 0 && + (now - log_ctx->reconn_timer) < LOGFILE_RECONN_MIN_TIME) { + /* Don't bother to try reconnecting too often. */ + return 0; + } + log_ctx->reconn_timer = now; + + log_ctx->fp = SCLogOpenUnixSocketFp(log_ctx->filename, log_ctx->sock_type, 0); + if (log_ctx->fp) { + /* Connected at last (or reconnected) */ + SCLogNotice("Reconnected socket \"%s\"", log_ctx->filename); + } else if (disconnected) { + SCLogWarning(SC_ERR_SOCKET, "Reconnect failed: %s (will keep trying)", + strerror(errno)); + } + + return log_ctx->fp ? 1 : 0; +} + +/** + * \brief Write buffer to log file. + * \retval 0 on failure; otherwise, the return value of fwrite (number of + * characters successfully written). + */ static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx) { /* Check for rotation. */ @@ -83,9 +132,21 @@ static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ct int ret = 0; + if (log_ctx->fp == NULL && log_ctx->is_sock) + SCLogUnixSocketReconnect(log_ctx); + if (log_ctx->fp) { + clearerr(log_ctx->fp); ret = fwrite(buffer, buffer_len, 1, log_ctx->fp); fflush(log_ctx->fp); + + if (ferror(log_ctx->fp) && log_ctx->is_sock) { + /* Error on Unix socket, maybe needs reconnect */ + if (SCLogUnixSocketReconnect(log_ctx)) { + ret = fwrite(buffer, buffer_len, 1, log_ctx->fp); + fflush(log_ctx->fp); + } + } } return ret; @@ -194,25 +255,21 @@ SCConfLogOpenGeneric(ConfNode *conf, // Now, what have we been asked to open? if (strcasecmp(filetype, "unix_stream") == 0) { - log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM); - if (log_ctx->fp == NULL) - return -1; // Error already logged by Open...Fp routine + /* Don't bail. May be able to connect later. */ + log_ctx->is_sock = 1; + log_ctx->sock_type = SOCK_STREAM; + log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1); } else if (strcasecmp(filetype, "unix_dgram") == 0) { - log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM); - if (log_ctx->fp == NULL) - return -1; // Error already logged by Open...Fp routine + /* Don't bail. May be able to connect later. */ + log_ctx->is_sock = 1; + log_ctx->sock_type = SOCK_DGRAM; + log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1); } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 || strcasecmp(filetype, "file") == 0) { log_ctx->fp = SCLogOpenFileFp(log_path, append); if (log_ctx->fp == NULL) return -1; // Error already logged by Open...Fp routine log_ctx->is_regular = 1; - log_ctx->filename = SCStrdup(log_path); - if (unlikely(log_ctx->filename == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for " - "filename"); - return -1; - } if (rotate) { OutputRegisterFileRotationFlag(&log_ctx->rotation_flag); } @@ -227,6 +284,12 @@ SCConfLogOpenGeneric(ConfNode *conf, "or \"unix_dgram\"", conf->name); } + log_ctx->filename = SCStrdup(log_path); + if (unlikely(log_ctx->filename == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, + "Failed to allocate memory for filename"); + return -1; + } SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, filename); diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 1f10e3491bbf..d345475d220c 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -56,6 +56,11 @@ typedef struct LogFileCtx_ { /** The name of the file */ char *filename; + /** Handle auto-connecting / reconnecting sockets */ + int is_sock; + int sock_type; + uint64_t reconn_timer; + /**< Used by some alert loggers like the unified ones that append * the date onto the end of files. */ char *prefix; @@ -78,6 +83,9 @@ typedef struct LogFileCtx_ { int rotation_flag; } LogFileCtx; +/* Min time (msecs) before trying to reconnect a Unix domain socket */ +#define LOGFILE_RECONN_MIN_TIME 500 + /* flags for LogFileCtx */ #define LOGFILE_HEADER_WRITTEN 0x01 #define LOGFILE_ALERTS_PRINTED 0x02 From 4db0a35f25cd2cd6079cdff28be55c6996c11f2d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 14 Jul 2015 21:22:31 +0200 Subject: [PATCH 0614/2553] tls-store: now a separate module An design error was made when doing the TLS storage module which has been made dependant of the TLS logging. At the time there was only one TLS logging module but there is now two different ones. By putting the TLS store module in a separate module, we can now use EVE output and TLS store at the same time. --- src/Makefile.am | 1 + src/app-layer-ssl.h | 5 +- src/log-tlslog.c | 218 +-------------------- src/log-tlslog.h | 4 + src/log-tlsstore.c | 421 ++++++++++++++++++++++++++++++++++++++++ src/log-tlsstore.h | 29 +++ src/suricata.c | 2 + src/tm-modules.c | 1 + src/tm-threads-common.h | 1 + suricata.yaml.in | 6 +- 10 files changed, 471 insertions(+), 217 deletions(-) create mode 100644 src/log-tlsstore.c create mode 100644 src/log-tlsstore.h diff --git a/src/Makefile.am b/src/Makefile.am index 819338427761..64ade1591240 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -230,6 +230,7 @@ log-pcap.c log-pcap.h \ log-stats.c log-stats.h \ log-tcp-data.c log-tcp-data.h \ log-tlslog.c log-tlslog.h \ +log-tlsstore.c log-tlsstore.h \ output.c output.h \ output-file.c output-file.h \ output-filedata.c output-filedata.h \ diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 1e5bbebddb8d..5c6fe5b153b5 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -76,7 +76,10 @@ enum { /* flags specific to HeartBeat state */ #define SSL_AL_FLAG_HB_INFLIGHT 0x8000 #define SSL_AL_FLAG_HB_CLIENT_INIT 0x10000 -#define SSL_AL_FLAG_HB_SERVER_INIT 0x20000 +#define SSL_AL_FLAG_HB_SERVER_INIT 0x20000 + +/* flags for file storage */ +#define SSL_AL_FLAG_STATE_STORED 0x40000 /* config flags */ #define SSL_TLS_LOG_PEM (1 << 0) diff --git a/src/log-tlslog.c b/src/log-tlslog.c index c2b17e7f1bf0..edb0ded2d0fe 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -56,9 +56,6 @@ #define DEFAULT_LOG_FILENAME "tls.log" -static char tls_logfile_base_dir[PATH_MAX] = "/tmp"; -SC_ATOMIC_DECLARE(unsigned int, cert_id); - #define MODULE_NAME "LogTlsLog" #define OUTPUT_BUFFER_SIZE 65535 @@ -79,8 +76,6 @@ typedef struct LogTlsLogThread_ { uint32_t tls_cnt; MemBuffer *buffer; - uint8_t* enc_buf; - size_t enc_buf_len; } LogTlsLogThread; static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state) @@ -115,7 +110,7 @@ static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state) MemBufferWriteString(aft->buffer, "\n"); } -static int GetIPInformations(const Packet *p, char* srcip, size_t srcip_len, +int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len, Port* sp, char* dstip, size_t dstip_len, Port* dp, int ipproto) { @@ -153,162 +148,6 @@ static int GetIPInformations(const Packet *p, char* srcip, size_t srcip_len, return 1; } -static int CreateFileName(LogTlsFileCtx *log, const Packet *p, SSLState *state, char *filename) -{ -#define FILELEN 64 //filename len + extention + ending path / + some space - - int filenamelen = FILELEN + strlen(tls_logfile_base_dir); - int file_id = SC_ATOMIC_ADD(cert_id, 1); - - if (filenamelen + 1 > PATH_MAX) { - return 0; - } - - /* Use format : packet time + incremental ID - * When running on same pcap it will overwrite - * On a live device, we will not be able to overwrite */ - snprintf(filename, filenamelen, "%s/%ld.%ld-%d.pem", - tls_logfile_base_dir, - (long int)p->ts.tv_sec, - (long int)p->ts.tv_usec, - file_id); - return 1; -} - -static void LogTlsLogPem(LogTlsLogThread *aft, const Packet *p, SSLState *state, LogTlsFileCtx *log, int ipproto) -{ -#define PEMHEADER "-----BEGIN CERTIFICATE-----\n" -#define PEMFOOTER "-----END CERTIFICATE-----\n" - //Logging pem certificate - char filename[PATH_MAX] = ""; - FILE* fp = NULL; - FILE* fpmeta = NULL; - unsigned long pemlen; - unsigned char* pembase64ptr = NULL; - int ret; - uint8_t *ptmp; - SSLCertsChain *cert; - - if ((state->server_connp.cert_input == NULL) || (state->server_connp.cert_input_len == 0)) - SCReturn; - - CreateFileName(log, p, state, filename); - if (strlen(filename) == 0) { - SCLogWarning(SC_ERR_FOPEN, "Can't create PEM filename"); - SCReturn; - } - - fp = fopen(filename, "w"); - if (fp == NULL) { - SCLogWarning(SC_ERR_FOPEN, "Can't create PEM file: %s", filename); - SCReturn; - } - - TAILQ_FOREACH(cert, &state->server_connp.certs, next) { - pemlen = (4 * (cert->cert_len + 2) / 3) +1; - if (pemlen > aft->enc_buf_len) { - ptmp = (uint8_t*) SCRealloc(aft->enc_buf, sizeof(uint8_t) * pemlen); - if (ptmp == NULL) { - SCFree(aft->enc_buf); - aft->enc_buf = NULL; - SCLogWarning(SC_ERR_MEM_ALLOC, "Can't allocate data for base64 encoding"); - goto end_fp; - } - aft->enc_buf = ptmp; - aft->enc_buf_len = pemlen; - } - - memset(aft->enc_buf, 0, aft->enc_buf_len); - - ret = Base64Encode((unsigned char*) cert->cert_data, cert->cert_len, aft->enc_buf, &pemlen); - if (ret != SC_BASE64_OK) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "Invalid return of Base64Encode function"); - goto end_fwrite_fp; - } - - if (fprintf(fp, PEMHEADER) < 0) - goto end_fwrite_fp; - - pembase64ptr = aft->enc_buf; - while (pemlen > 0) { - size_t loffset = pemlen >= 64 ? 64 : pemlen; - if (fwrite(pembase64ptr, 1, loffset, fp) != loffset) - goto end_fwrite_fp; - if (fwrite("\n", 1, 1, fp) != 1) - goto end_fwrite_fp; - pembase64ptr += 64; - if (pemlen < 64) - break; - pemlen -= 64; - } - - if (fprintf(fp, PEMFOOTER) < 0) - goto end_fwrite_fp; - } - fclose(fp); - - //Logging certificate informations - memcpy(filename + (strlen(filename) - 3), "meta", 4); - fpmeta = fopen(filename, "w"); - if (fpmeta != NULL) { - #define PRINT_BUF_LEN 46 - char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; - char timebuf[64]; - Port sp, dp; - CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); - if (!GetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) - goto end_fwrite_fpmeta; - if (fprintf(fpmeta, "TIME: %s\n", timebuf) < 0) - goto end_fwrite_fpmeta; - if (p->pcap_cnt > 0) { - if (fprintf(fpmeta, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt) < 0) - goto end_fwrite_fpmeta; - } - if (fprintf(fpmeta, "SRC IP: %s\n", srcip) < 0) - goto end_fwrite_fpmeta; - if (fprintf(fpmeta, "DST IP: %s\n", dstip) < 0) - goto end_fwrite_fpmeta; - if (fprintf(fpmeta, "PROTO: %" PRIu32 "\n", p->proto) < 0) - goto end_fwrite_fpmeta; - if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) { - if (fprintf(fpmeta, "SRC PORT: %" PRIu16 "\n", sp) < 0) - goto end_fwrite_fpmeta; - if (fprintf(fpmeta, "DST PORT: %" PRIu16 "\n", dp) < 0) - goto end_fwrite_fpmeta; - } - - if (fprintf(fpmeta, "TLS SUBJECT: %s\n" - "TLS ISSUERDN: %s\n" - "TLS FINGERPRINT: %s\n", - state->server_connp.cert0_subject, - state->server_connp.cert0_issuerdn, - state->server_connp.cert0_fingerprint) < 0) - goto end_fwrite_fpmeta; - - fclose(fpmeta); - } else { - SCLogWarning(SC_ERR_FOPEN, "Can't open meta file: %s", - filename); - SCReturn; - } - - /* Reset the store flag */ - state->server_connp.cert_log_flag &= ~SSL_TLS_LOG_PEM; - SCReturn; - -end_fwrite_fp: - fclose(fp); - SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate"); -end_fwrite_fpmeta: - if (fpmeta) { - fclose(fpmeta); - SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate metafile"); - } - SCReturn; -end_fp: - fclose(fp); -} - static TmEcode LogTlsLogThreadInit(ThreadVars *t, void *initdata, void **data) { LogTlsLogThread *aft = SCMalloc(sizeof(LogTlsLogThread)); @@ -322,39 +161,12 @@ static TmEcode LogTlsLogThreadInit(ThreadVars *t, void *initdata, void **data) return TM_ECODE_FAILED; } - struct stat stat_buf; - if (stat(tls_logfile_base_dir, &stat_buf) != 0) { - int ret; - ret = mkdir(tls_logfile_base_dir, S_IRWXU|S_IXGRP|S_IRGRP); - if (ret != 0) { - int err = errno; - if (err != EEXIST) { - SCLogError(SC_ERR_LOGDIR_CONFIG, - "Cannot create certs drop directory %s: %s", - tls_logfile_base_dir, strerror(err)); - exit(EXIT_FAILURE); - } - } else { - SCLogInfo("Created certs drop directory %s", - tls_logfile_base_dir); - } - - } - aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); if (aft->buffer == NULL) { SCFree(aft); return TM_ECODE_FAILED; } - aft->enc_buf = SCMalloc(CERT_ENC_BUFFER_SIZE); - if (aft->enc_buf == NULL) { - SCFree(aft); - return TM_ECODE_FAILED; - } - aft->enc_buf_len = CERT_ENC_BUFFER_SIZE; - memset(aft->enc_buf, 0, aft->enc_buf_len); - /* Use the Ouptut Context (file pointer and mutex) */ aft->tlslog_ctx = ((OutputCtx *) initdata)->data; @@ -417,24 +229,6 @@ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf) return NULL; } - char *s_default_log_dir = NULL; - s_default_log_dir = ConfigGetLogDirectory(); - - const char *s_base_dir = NULL; - s_base_dir = ConfNodeLookupChildValue(conf, "certs-log-dir"); - if (s_base_dir == NULL || strlen(s_base_dir) == 0) { - strlcpy(tls_logfile_base_dir, - s_default_log_dir, sizeof(tls_logfile_base_dir)); - } else { - if (PathIsAbsolute(s_base_dir)) { - strlcpy(tls_logfile_base_dir, - s_base_dir, sizeof(tls_logfile_base_dir)); - } else { - snprintf(tls_logfile_base_dir, sizeof(tls_logfile_base_dir), - "%s/%s", s_default_log_dir, s_base_dir); - } - } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { goto filectx_error; } @@ -542,10 +336,6 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) if (ssl_state->server_connp.cert0_issuerdn == NULL || ssl_state->server_connp.cert0_subject == NULL) goto end; - if (ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) { - LogTlsLogPem(aft, p, ssl_state, hlog, ipproto); - } - /* Don't log again the state. If we are here it was because we had * to store the cert. */ if (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED) @@ -555,8 +345,8 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) #define PRINT_BUF_LEN 46 char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; Port sp, dp; - if (!GetIPInformations(p, srcip, PRINT_BUF_LEN, - &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) { + if (!TLSGetIPInformations(p, srcip, PRINT_BUF_LEN, + &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) { goto end; } @@ -600,6 +390,4 @@ void TmModuleLogTlsLogRegister(void) OutputRegisterPacketModule(MODULE_NAME, "tls-log", LogTlsLogInitCtx, LogTlsLogger, LogTlsCondition); - - SC_ATOMIC_INIT(cert_id); } diff --git a/src/log-tlslog.h b/src/log-tlslog.h index f339d5d81fb2..d3c9ce516b86 100644 --- a/src/log-tlslog.h +++ b/src/log-tlslog.h @@ -27,5 +27,9 @@ void TmModuleLogTlsLogRegister (void); +int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len, + Port* sp, char* dstip, size_t dstip_len, + Port* dp, int ipproto); + #endif /* __LOG_TLSLOG_H__ */ diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c new file mode 100644 index 000000000000..ddd4b800c9be --- /dev/null +++ b/src/log-tlsstore.c @@ -0,0 +1,421 @@ +/* Copyright (C) 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 Roliers Jean-Paul + * \author Eric Leblond + * \author Victor Julien + * + * Implements TLS store portion of the engine. + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "log-tlslog.h" +#include "app-layer-ssl.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util-privs.h" +#include "util-buffer.h" + +#include "util-logopenfile.h" +#include "util-crypt.h" +#include "util-time.h" + +#define MODULE_NAME "LogTlsStoreLog" + +static char tls_logfile_base_dir[PATH_MAX] = "/tmp"; +SC_ATOMIC_DECLARE(unsigned int, cert_id); + +typedef struct LogTlsStoreLogThread_ { + uint32_t tls_cnt; + + uint8_t* enc_buf; + size_t enc_buf_len; +} LogTlsStoreLogThread; + +static int CreateFileName(const Packet *p, SSLState *state, char *filename) +{ +#define FILELEN 64 //filename len + extention + ending path / + some space + + int filenamelen = FILELEN + strlen(tls_logfile_base_dir); + int file_id = SC_ATOMIC_ADD(cert_id, 1); + + if (filenamelen + 1 > PATH_MAX) { + return 0; + } + + /* Use format : packet time + incremental ID + * When running on same pcap it will overwrite + * On a live device, we will not be able to overwrite */ + snprintf(filename, filenamelen, "%s/%ld.%ld-%d.pem", + tls_logfile_base_dir, + (long int)p->ts.tv_sec, + (long int)p->ts.tv_usec, + file_id); + return 1; +} + +static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *state, int ipproto) +{ +#define PEMHEADER "-----BEGIN CERTIFICATE-----\n" +#define PEMFOOTER "-----END CERTIFICATE-----\n" + //Logging pem certificate + char filename[PATH_MAX] = ""; + FILE* fp = NULL; + FILE* fpmeta = NULL; + unsigned long pemlen; + unsigned char* pembase64ptr = NULL; + int ret; + uint8_t *ptmp; + SSLCertsChain *cert; + + if ((state->server_connp.cert_input == NULL) || (state->server_connp.cert_input_len == 0)) + SCReturn; + + CreateFileName(p, state, filename); + if (strlen(filename) == 0) { + SCLogWarning(SC_ERR_FOPEN, "Can't create PEM filename"); + SCReturn; + } + + fp = fopen(filename, "w"); + if (fp == NULL) { + SCLogWarning(SC_ERR_FOPEN, "Can't create PEM file: %s", filename); + SCReturn; + } + + TAILQ_FOREACH(cert, &state->server_connp.certs, next) { + pemlen = (4 * (cert->cert_len + 2) / 3) +1; + if (pemlen > aft->enc_buf_len) { + ptmp = (uint8_t*) SCRealloc(aft->enc_buf, sizeof(uint8_t) * pemlen); + if (ptmp == NULL) { + SCFree(aft->enc_buf); + aft->enc_buf = NULL; + SCLogWarning(SC_ERR_MEM_ALLOC, "Can't allocate data for base64 encoding"); + goto end_fp; + } + aft->enc_buf = ptmp; + aft->enc_buf_len = pemlen; + } + + memset(aft->enc_buf, 0, aft->enc_buf_len); + + ret = Base64Encode((unsigned char*) cert->cert_data, cert->cert_len, aft->enc_buf, &pemlen); + if (ret != SC_BASE64_OK) { + SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "Invalid return of Base64Encode function"); + goto end_fwrite_fp; + } + + if (fprintf(fp, PEMHEADER) < 0) + goto end_fwrite_fp; + + pembase64ptr = aft->enc_buf; + while (pemlen > 0) { + size_t loffset = pemlen >= 64 ? 64 : pemlen; + if (fwrite(pembase64ptr, 1, loffset, fp) != loffset) + goto end_fwrite_fp; + if (fwrite("\n", 1, 1, fp) != 1) + goto end_fwrite_fp; + pembase64ptr += 64; + if (pemlen < 64) + break; + pemlen -= 64; + } + + if (fprintf(fp, PEMFOOTER) < 0) + goto end_fwrite_fp; + } + fclose(fp); + + //Logging certificate informations + memcpy(filename + (strlen(filename) - 3), "meta", 4); + fpmeta = fopen(filename, "w"); + if (fpmeta != NULL) { + #define PRINT_BUF_LEN 46 + char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; + char timebuf[64]; + Port sp, dp; + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + if (!TLSGetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) + goto end_fwrite_fpmeta; + if (fprintf(fpmeta, "TIME: %s\n", timebuf) < 0) + goto end_fwrite_fpmeta; + if (p->pcap_cnt > 0) { + if (fprintf(fpmeta, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt) < 0) + goto end_fwrite_fpmeta; + } + if (fprintf(fpmeta, "SRC IP: %s\n", srcip) < 0) + goto end_fwrite_fpmeta; + if (fprintf(fpmeta, "DST IP: %s\n", dstip) < 0) + goto end_fwrite_fpmeta; + if (fprintf(fpmeta, "PROTO: %" PRIu32 "\n", p->proto) < 0) + goto end_fwrite_fpmeta; + if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) { + if (fprintf(fpmeta, "SRC PORT: %" PRIu16 "\n", sp) < 0) + goto end_fwrite_fpmeta; + if (fprintf(fpmeta, "DST PORT: %" PRIu16 "\n", dp) < 0) + goto end_fwrite_fpmeta; + } + + if (fprintf(fpmeta, "TLS SUBJECT: %s\n" + "TLS ISSUERDN: %s\n" + "TLS FINGERPRINT: %s\n", + state->server_connp.cert0_subject, + state->server_connp.cert0_issuerdn, + state->server_connp.cert0_fingerprint) < 0) + goto end_fwrite_fpmeta; + + fclose(fpmeta); + } else { + SCLogWarning(SC_ERR_FOPEN, "Can't open meta file: %s", + filename); + SCReturn; + } + + /* Reset the store flag */ + state->server_connp.cert_log_flag &= ~SSL_TLS_LOG_PEM; + SCReturn; + +end_fwrite_fp: + fclose(fp); + SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate"); +end_fwrite_fpmeta: + if (fpmeta) { + fclose(fpmeta); + SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate metafile"); + } + SCReturn; +end_fp: + fclose(fp); + SCReturn; +} + +/** \internal + * \brief Condition function for TLS logger + * \retval bool true or false -- log now? + */ +static int LogTlsStoreCondition(ThreadVars *tv, const Packet *p) +{ + if (p->flow == NULL) { + return FALSE; + } + + if (!(PKT_IS_TCP(p))) { + return FALSE; + } + + FLOWLOCK_RDLOCK(p->flow); + uint16_t proto = FlowGetAppProtocol(p->flow); + if (proto != ALPROTO_TLS) + goto dontlog; + + SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + if (ssl_state == NULL) { + SCLogDebug("no tls state, so no request logging"); + goto dontlog; + } + + /* we only log the state once if we don't have to write + * the cert due to tls.store keyword. */ + if (!(ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) && + (ssl_state->flags & SSL_AL_FLAG_STATE_STORED)) + goto dontlog; + + if (ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) + goto dontlog; + + FLOWLOCK_UNLOCK(p->flow); + return TRUE; +dontlog: + FLOWLOCK_UNLOCK(p->flow); + return FALSE; +} + +static int LogTlsStoreLogger(ThreadVars *tv, void *thread_data, const Packet *p) +{ + LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)thread_data; + int ipproto = (PKT_IS_IPV4(p)) ? AF_INET : AF_INET6; + /* check if we have TLS state or not */ + FLOWLOCK_WRLOCK(p->flow); + uint16_t proto = FlowGetAppProtocol(p->flow); + if (proto != ALPROTO_TLS) + goto end; + + SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + if (unlikely(ssl_state == NULL)) { + goto end; + } + + if (ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) { + LogTlsLogPem(aft, p, ssl_state, ipproto); + } + + /* we only store the state once */ + ssl_state->flags |= SSL_AL_FLAG_STATE_STORED; +end: + FLOWLOCK_UNLOCK(p->flow); + return 0; +} + +static TmEcode LogTlsStoreLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + LogTlsStoreLogThread *aft = SCMalloc(sizeof(LogTlsStoreLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(LogTlsStoreLogThread)); + + if (initdata == NULL) { + SCLogDebug("Error getting context for LogTlsStore. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + struct stat stat_buf; + if (stat(tls_logfile_base_dir, &stat_buf) != 0) { + int ret; + ret = mkdir(tls_logfile_base_dir, S_IRWXU|S_IXGRP|S_IRGRP); + if (ret != 0) { + int err = errno; + if (err != EEXIST) { + SCLogError(SC_ERR_LOGDIR_CONFIG, + "Cannot create certs drop directory %s: %s", + tls_logfile_base_dir, strerror(err)); + exit(EXIT_FAILURE); + } + } else { + SCLogInfo("Created certs drop directory %s", + tls_logfile_base_dir); + } + + } + + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode LogTlsStoreLogThreadDeinit(ThreadVars *t, void *data) +{ + LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + /* clear memory */ + memset(aft, 0, sizeof(LogTlsStoreLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static void LogTlsStoreLogExitPrintStats(ThreadVars *tv, void *data) +{ + LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)data; + if (aft == NULL) { + return; + } + + SCLogInfo("(%s) certificates extracted %" PRIu32 "", tv->name, aft->tls_cnt); +} + +/** + * \internal + * + * \brief deinit the log ctx and write out the waldo + * + * \param output_ctx output context to deinit + */ +static void LogTlsStoreLogDeInitCtx(OutputCtx *output_ctx) +{ + SCFree(output_ctx); +} + +/** \brief Create a new http log LogFilestoreCtx. + * \param conf Pointer to ConfNode containing this loggers configuration. + * \return NULL if failure, LogFilestoreCtx* to the file_ctx if succesful + * */ +static OutputCtx *LogTlsStoreLogInitCtx(ConfNode *conf) +{ + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) + return NULL; + + output_ctx->data = NULL; + output_ctx->DeInit = LogTlsStoreLogDeInitCtx; + + /* FIXME we need to implement backward compability here */ + char *s_default_log_dir = NULL; + s_default_log_dir = ConfigGetLogDirectory(); + + const char *s_base_dir = NULL; + s_base_dir = ConfNodeLookupChildValue(conf, "certs-log-dir"); + if (s_base_dir == NULL || strlen(s_base_dir) == 0) { + strlcpy(tls_logfile_base_dir, + s_default_log_dir, sizeof(tls_logfile_base_dir)); + } else { + if (PathIsAbsolute(s_base_dir)) { + strlcpy(tls_logfile_base_dir, + s_base_dir, sizeof(tls_logfile_base_dir)); + } else { + snprintf(tls_logfile_base_dir, sizeof(tls_logfile_base_dir), + "%s/%s", s_default_log_dir, s_base_dir); + } + } + + SCLogInfo("storing certs in %s", tls_logfile_base_dir); + + SCReturnPtr(output_ctx, "OutputCtx"); +} + +void TmModuleLogTlsStoreRegister (void) +{ + tmm_modules[TMM_TLSSTORE].name = MODULE_NAME; + tmm_modules[TMM_TLSSTORE].ThreadInit = LogTlsStoreLogThreadInit; + tmm_modules[TMM_TLSSTORE].Func = NULL; + tmm_modules[TMM_TLSSTORE].ThreadExitPrintStats = LogTlsStoreLogExitPrintStats; + tmm_modules[TMM_TLSSTORE].ThreadDeinit = LogTlsStoreLogThreadDeinit; + tmm_modules[TMM_TLSSTORE].RegisterTests = NULL; + tmm_modules[TMM_TLSSTORE].cap_flags = 0; + tmm_modules[TMM_TLSSTORE].flags = TM_FLAG_LOGAPI_TM; + tmm_modules[TMM_TLSSTORE].priority = 10; + + OutputRegisterPacketModule(MODULE_NAME, "tls-store", LogTlsStoreLogInitCtx, + LogTlsStoreLogger, LogTlsStoreCondition); + + SC_ATOMIC_INIT(cert_id); + + SCLogDebug("registered"); +} diff --git a/src/log-tlsstore.h b/src/log-tlsstore.h new file mode 100644 index 000000000000..6cbacab64760 --- /dev/null +++ b/src/log-tlsstore.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2015 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 + */ + +#ifndef __LOG_TLSSTORE_H__ +#define __LOG_TLSSTORE_H__ + +void TmModuleLogTlsStoreRegister (void); + +#endif /* __LOG_TLSSTORE_H__ */ diff --git a/src/suricata.c b/src/suricata.c index c7f2ffe9491c..e571c796bc15 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -88,6 +88,7 @@ #include "log-dnslog.h" #include "output-json-dns.h" #include "log-tlslog.h" +#include "log-tlsstore.h" #include "output-json-tls.h" #include "output-json-ssh.h" #include "log-pcap.h" @@ -872,6 +873,7 @@ void RegisterAllModules() /* tls log */ TmModuleLogTlsLogRegister(); TmModuleJsonTlsLogRegister(); + TmModuleLogTlsStoreRegister(); /* ssh */ TmModuleJsonSshLogRegister(); /* pcap log */ diff --git a/src/tm-modules.c b/src/tm-modules.c index 7d29551fd930..c6f8c9ac76d6 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -273,6 +273,7 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_LOGSTATSLOG); CASE_CODE (TMM_RECEIVENETMAP); CASE_CODE (TMM_DECODENETMAP); + CASE_CODE (TMM_TLSSTORE); CASE_CODE (TMM_SIZE); } diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 17ea053d15de..e59c2a8764f7 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -108,6 +108,7 @@ typedef enum { TMM_UNIXMANAGER, TMM_LUALOG, + TMM_TLSSTORE, TMM_SIZE, } TmmId; diff --git a/suricata.yaml.in b/suricata.yaml.in index 64a8182a298b..415afacc11d6 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -200,7 +200,11 @@ outputs: append: yes #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' #extended: yes # Log extended information like fingerprint - certs-log-dir: certs # directory to store the certificates files + + # output module to store certificates chain to disk + - tls-store: + enabled: no + #certs-log-dir: certs # directory to store the certificates files # a line based log of DNS requests and/or replies (no alerts) - dns-log: From b77cd22b9818f71ce5d276a44166bc0c56effbb3 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 14 Jul 2015 22:35:32 +0200 Subject: [PATCH 0615/2553] tls-store: backward compatibility This patch implements backward compatibility in suricata.yaml file. In case the new 'tls-store' output is not present in the YAML we have to use the value defined in 'tls-log'. --- src/runmodes.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/runmodes.c b/src/runmodes.c index 5f9b201d5178..e6ff72872b33 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -695,6 +695,8 @@ void RunModeInitializeOutputs(void) ConfNode *output, *output_config; const char *enabled; + char tls_log_enabled = 0; + char tls_store_present = 0; TAILQ_FOREACH(output, &outputs->head, next) { @@ -706,6 +708,10 @@ void RunModeInitializeOutputs(void) exit(1); } + if (strcmp(output->val, "tls-store") == 0) { + tls_store_present = 1; + } + enabled = ConfNodeLookupChildValue(output_config, "enabled"); if (enabled == NULL || !ConfValIsTrue(enabled)) { continue; @@ -742,6 +748,8 @@ void RunModeInitializeOutputs(void) "files installed to add lua support."); continue; #endif + } else if (strcmp(output->val, "tls-log") == 0) { + tls_log_enabled = 1; } OutputModule *module = OutputGetModuleByConfName(output->val); @@ -847,6 +855,40 @@ void RunModeInitializeOutputs(void) SetupOutput(module->name, module, output_ctx); } } + + /* Backward compatibility code */ + if (!tls_store_present && tls_log_enabled) { + /* old YAML with no "tls-store" in outputs. "tls-log" value needs + * to be started using 'tls-log' config as own config */ + SCLogWarning(SC_ERR_CONF_YAML_ERROR, + "Please use 'tls-store' in YAML to configure TLS storage"); + + TAILQ_FOREACH(output, &outputs->head, next) { + output_config = ConfNodeLookupChild(output, output->val); + + if (strcmp(output->val, "tls-log") == 0) { + + OutputModule *module = OutputGetModuleByConfName("tls-store"); + if (module == NULL) { + SCLogWarning(SC_ERR_INVALID_ARGUMENT, + "No output module named %s, ignoring", "tls-store"); + continue; + } + + OutputCtx *output_ctx = NULL; + if (module->InitFunc != NULL) { + output_ctx = module->InitFunc(output_config); + if (output_ctx == NULL) { + continue; + } + } + + AddOutputToFreeList(module, output_ctx); + SetupOutput(module->name, module, output_ctx); + } + } + } + } /** From cbf5d8844706cd7f83ba4ed06a2f2ce0028c2d79 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 15 Jul 2015 13:50:22 +0200 Subject: [PATCH 0616/2553] filestore: use SCFree instead of free --- src/log-filestore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/log-filestore.c b/src/log-filestore.c index 8686a0a49f0a..4244b9a44fa5 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -417,7 +417,7 @@ static void LogFilestoreLogDeInitCtx(OutputCtx *output_ctx) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; LogFileFreeCtx(logfile_ctx); - free(output_ctx); + SCFree(output_ctx); } From 159a6d1cb4054ee7a93b87f823fbe6c464d30698 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 15 Jul 2015 22:21:07 +0200 Subject: [PATCH 0617/2553] tls-store: avoid log flooding In case we can't write in the certs directory, this is possible we flood the log for each TLS session or even worse each TLS packet. So this patch puts a limit in the number of logged messages related to file creation. --- src/log-tlsstore.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c index ddd4b800c9be..da23908e7cf2 100644 --- a/src/log-tlsstore.c +++ b/src/log-tlsstore.c @@ -57,6 +57,9 @@ static char tls_logfile_base_dir[PATH_MAX] = "/tmp"; SC_ATOMIC_DECLARE(unsigned int, cert_id); +static char logging_dir_not_writable; + +#define LOGGING_WRITE_ISSUE_LIMIT 6 typedef struct LogTlsStoreLogThread_ { uint32_t tls_cnt; @@ -112,7 +115,12 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s fp = fopen(filename, "w"); if (fp == NULL) { - SCLogWarning(SC_ERR_FOPEN, "Can't create PEM file: %s", filename); + if (logging_dir_not_writable < LOGGING_WRITE_ISSUE_LIMIT) { + SCLogWarning(SC_ERR_FOPEN, + "Can't create PEM file '%s' in '%s' directory", + filename, tls_logfile_base_dir); + logging_dir_not_writable++; + } SCReturn; } @@ -199,8 +207,12 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s fclose(fpmeta); } else { - SCLogWarning(SC_ERR_FOPEN, "Can't open meta file: %s", - filename); + if (logging_dir_not_writable < LOGGING_WRITE_ISSUE_LIMIT) { + SCLogWarning(SC_ERR_FOPEN, + "Can't create meta file '%s' in '%s' directory", + filename, tls_logfile_base_dir); + logging_dir_not_writable++; + } SCReturn; } @@ -210,11 +222,17 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s end_fwrite_fp: fclose(fp); - SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate"); + if (logging_dir_not_writable < LOGGING_WRITE_ISSUE_LIMIT) { + SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate"); + logging_dir_not_writable++; + } end_fwrite_fpmeta: if (fpmeta) { fclose(fpmeta); - SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate metafile"); + if (logging_dir_not_writable < LOGGING_WRITE_ISSUE_LIMIT) { + SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate metafile"); + logging_dir_not_writable++; + } } SCReturn; end_fp: From c46d472921aed5c5aab03ca8dc3e0277dd467568 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 4 Jun 2015 10:46:26 +0200 Subject: [PATCH 0618/2553] lua: initial DNS logging support --- src/output-lua.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/output-lua.c b/src/output-lua.c index fc075cd3149a..0f06450e9b6c 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -56,6 +56,7 @@ #include "util-lua.h" #include "util-lua-common.h" #include "util-lua-http.h" +#include "util-lua-dns.h" #define MODULE_NAME "LuaLog" @@ -514,6 +515,8 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { if (strcmp(k,"protocol") == 0 && strcmp(v, "http") == 0) options->alproto = ALPROTO_HTTP; + else if (strcmp(k,"protocol") == 0 && strcmp(v, "dns") == 0) + options->alproto = ALPROTO_DNS; else if (strcmp(k, "type") == 0 && strcmp(v, "packet") == 0) options->packet = 1; else if (strcmp(k, "filter") == 0 && strcmp(v, "alerts") == 0) @@ -532,7 +535,7 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { SCLogInfo("unknown key and/or value: k='%s', v='%s'", k, v); } - if (options->alproto + options->packet + options->file > 1) { + if (((options->alproto != ALPROTO_UNKNOWN)) + options->packet + options->file > 1) { SCLogError(SC_ERR_LUA_ERROR, "invalid combination of 'needs' in the script"); goto error; } @@ -613,6 +616,7 @@ static lua_State *LuaScriptSetup(const char *filename) /* unconditionally register http function. They will only work * if the tx is registered in the state at runtime though. */ LuaRegisterHttpFunctions(luastate); + LuaRegisterDnsFunctions(luastate); if (lua_pcall(luastate, 0, 0, 0) != 0) { SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'setup' function: %s", lua_tostring(luastate, -1)); @@ -756,6 +760,11 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_HTTP; AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP); + } else if (opts.alproto == ALPROTO_DNS) { + om->TxLogFunc = LuaTxLogger; + om->alproto = ALPROTO_DNS; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNS); + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); } else if (opts.packet && opts.alerts) { om->PacketLogFunc = LuaPacketLoggerAlerts; om->PacketConditionFunc = LuaPacketConditionAlerts; From a1e50b3138b59c667120b19997c5a7e40499b0e1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 5 Jun 2015 08:53:47 +0200 Subject: [PATCH 0619/2553] lua: dns extensions Add DNS lua calls for getting queries, answers, authorities. Also rcode and recusion desired flags. --- src/util-lua-dns.c | 221 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) diff --git a/src/util-lua-dns.c b/src/util-lua-dns.c index 8ac0688d0136..dcebc6a13204 100644 --- a/src/util-lua-dns.c +++ b/src/util-lua-dns.c @@ -88,12 +88,233 @@ static int DnsGetDnsRrname(lua_State *luastate) return LuaCallbackError(luastate, "no query"); } +static int DnsGetTxid(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + lua_pushinteger(luastate, tx->tx_id); + return 1; +} + +static int DnsGetRcode(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + if (tx->rcode) { + char rcode[16] = ""; + DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode)); + return LuaPushStringBuffer(luastate, (const uint8_t *)rcode, strlen(rcode)); + } else { + return 0; + } +} + +static int DnsGetRecursionDesired(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + lua_pushboolean(luastate, tx->recursion_desired); + return 1; +} + +static int DnsGetQueryTable(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + uint32_t u = 0; + lua_newtable(luastate); + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &tx->query_list, next) { + lua_pushinteger(luastate, u++); + + lua_newtable(luastate); + char record[16] = ""; + DNSCreateTypeString(query->type, record, sizeof(record)); + lua_pushstring(luastate, "type"); + lua_pushstring(luastate, record); + lua_settable(luastate, -3); + + { + char *c; + size_t input_len; + c = BytesToString((uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)), query->len); + if (c != NULL) { + input_len = strlen(c); + /* sanity check */ + if (input_len > (size_t)(2 * query->len)) { + SCFree(c); + return LuaCallbackError(luastate, "invalid length"); + } + lua_pushstring(luastate, "rrname"); + LuaPushStringBuffer(luastate, (uint8_t *)c, input_len); + lua_settable(luastate, -3); + SCFree(c); + } + } + + + lua_settable(luastate, -3); + } + + return 1; +} + +static int DnsGetAnswerTable(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + uint32_t u = 0; + lua_newtable(luastate); + DNSAnswerEntry *answer = NULL; + TAILQ_FOREACH(answer, &tx->answer_list, next) { + lua_pushinteger(luastate, u++); + + lua_newtable(luastate); + char record[16] = ""; + DNSCreateTypeString(answer->type, record, sizeof(record)); + lua_pushstring(luastate, "type"); + lua_pushstring(luastate, record); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "ttl"); + lua_pushinteger(luastate, answer->ttl); + lua_settable(luastate, -3); + + { + uint8_t *ptr = (uint8_t *)((uint8_t *)answer + sizeof(DNSAnswerEntry)); + lua_pushstring(luastate, "rrname"); + LuaPushStringBuffer(luastate, ptr, answer->fqdn_len); + lua_settable(luastate, -3); + + ptr = (uint8_t *)((uint8_t *)answer + sizeof(DNSAnswerEntry) + answer->fqdn_len); + if (answer->type == DNS_RECORD_TYPE_A) { + char a[16] = ""; + PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); + lua_pushstring(luastate, "addr"); + LuaPushStringBuffer(luastate, (uint8_t *)a, strlen(a)); + lua_settable(luastate, -3); + } else if (answer->type == DNS_RECORD_TYPE_AAAA) { + char a[46]; + PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); + lua_pushstring(luastate, "addr"); + LuaPushStringBuffer(luastate, (uint8_t *)a, strlen(a)); + lua_settable(luastate, -3); + } else if (answer->data_len == 0) { + /* not setting 'addr' */ + } else { + lua_pushstring(luastate, "addr"); + LuaPushStringBuffer(luastate, (uint8_t *)ptr, answer->data_len); + lua_settable(luastate, -3); + } + } + + lua_settable(luastate, -3); + } + + return 1; +} + +static int DnsGetAuthorityTable(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + uint32_t u = 0; + lua_newtable(luastate); + DNSAnswerEntry *answer = NULL; + TAILQ_FOREACH(answer, &tx->authority_list, next) { + lua_pushinteger(luastate, u++); + + lua_newtable(luastate); + char record[16] = ""; + DNSCreateTypeString(answer->type, record, sizeof(record)); + lua_pushstring(luastate, "type"); + lua_pushstring(luastate, record); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "ttl"); + lua_pushinteger(luastate, answer->ttl); + lua_settable(luastate, -3); + + { + char *c; + size_t input_len; + c = BytesToString((uint8_t *)((uint8_t *)answer + sizeof(DNSAnswerEntry)), answer->fqdn_len); + if (c != NULL) { + input_len = strlen(c); + /* sanity check */ + if (input_len > (size_t)(2 * answer->fqdn_len)) { + SCFree(c); + return LuaCallbackError(luastate, "invalid length"); + } + lua_pushstring(luastate, "rrname"); + LuaPushStringBuffer(luastate, (uint8_t *)c, input_len); + lua_settable(luastate, -3); + SCFree(c); + } + } + + + lua_settable(luastate, -3); + } + + return 1; +} + + /** \brief register http lua extensions in a luastate */ int LuaRegisterDnsFunctions(lua_State *luastate) { /* registration of the callbacks */ lua_pushcfunction(luastate, DnsGetDnsRrname); lua_setglobal(luastate, "DnsGetDnsRrname"); + + lua_pushcfunction(luastate, DnsGetQueryTable); + lua_setglobal(luastate, "DnsGetQueries"); + + lua_pushcfunction(luastate, DnsGetAnswerTable); + lua_setglobal(luastate, "DnsGetAnswers"); + + lua_pushcfunction(luastate, DnsGetAuthorityTable); + lua_setglobal(luastate, "DnsGetAuthorities"); + + lua_pushcfunction(luastate, DnsGetTxid); + lua_setglobal(luastate, "DnsGetTxid"); + + lua_pushcfunction(luastate, DnsGetRcode); + lua_setglobal(luastate, "DnsGetRcode"); + + lua_pushcfunction(luastate, DnsGetRecursionDesired); + lua_setglobal(luastate, "DnsGetRecursionDesired"); return 0; } From 2c8e8c2516742a100875a4b9392bd889e4506a00 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Jun 2015 14:49:22 +0200 Subject: [PATCH 0620/2553] dns: rename type so it's purpose is more clear --- src/detect-dns-query.c | 2 +- src/detect-engine-analyzer.c | 2 +- src/detect-engine-dns.c | 2 +- src/detect-engine-mpm.c | 6 +++--- src/detect-engine-state.h | 2 +- src/detect-engine.c | 12 ++++++------ src/detect-fast-pattern.c | 6 +++--- src/detect-isdataat.c | 6 +++--- src/detect-lua.c | 2 +- src/detect-parse.c | 2 +- src/detect-pcre.c | 4 ++-- src/detect.h | 2 +- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 84333cb4df5b..55742f8982fc 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -93,7 +93,7 @@ void DetectDnsQueryRegister (void) static int DetectDnsQuerySetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->list = DETECT_SM_LIST_DNSQUERY_MATCH; + s->list = DETECT_SM_LIST_DNSQUERYNAME_MATCH; s->alproto = ALPROTO_DNS; return 0; } diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index e6c69b086b0a..066d41c6edfa 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -476,7 +476,7 @@ static void EngineAnalysisRulesPrintFP(Signature *s) fprintf(rule_engine_analysis_FD, "http stat msg content"); else if (list_type == DETECT_SM_LIST_HUADMATCH) fprintf(rule_engine_analysis_FD, "http user agent content"); - else if (list_type == DETECT_SM_LIST_DNSQUERY_MATCH) + else if (list_type == DETECT_SM_LIST_DNSQUERYNAME_MATCH) fprintf(rule_engine_analysis_FD, "dns query name content"); fprintf(rule_engine_analysis_FD, "\" buffer.\n"); diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index 946f7412fea9..a1e064083cdc 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -84,7 +84,7 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, //PrintRawDataFp(stdout, buffer, buffer_len); r = DetectEngineContentInspection(de_ctx, det_ctx, - s, s->sm_lists[DETECT_SM_LIST_DNSQUERY_MATCH], + s, s->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH], f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, NULL); if (r == 1) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 1cbf2770975a..c34ef252468e 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1496,7 +1496,7 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, case DETECT_SM_LIST_HUADMATCH: case DETECT_SM_LIST_HHHDMATCH: case DETECT_SM_LIST_HRHHDMATCH: - case DETECT_SM_LIST_DNSQUERY_MATCH: + case DETECT_SM_LIST_DNSQUERYNAME_MATCH: { MpmCtx *mpm_ctx_ts = NULL; MpmCtx *mpm_ctx_tc = NULL; @@ -1605,7 +1605,7 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, s->flags |= SIG_FLAG_MPM_APPLAYER; if (cd->flags & DETECT_CONTENT_NEGATED) s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_DNSQUERY_MATCH) { + } else if (sm_list == DETECT_SM_LIST_DNSQUERYNAME_MATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_dnsquery_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) @@ -2078,7 +2078,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) has_co_hrhhd = 1; } - if (s->sm_lists[DETECT_SM_LIST_DNSQUERY_MATCH] != NULL) { + if (s->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH] != NULL) { has_co_dnsquery = 1; } } diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 7ef4df2c45e3..a04b1231737e 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -74,7 +74,7 @@ #define DE_STATE_FLAG_FILE_TS_INSPECT (1 << 14) #define DE_STATE_FLAG_FULL_INSPECT (1 << 15) #define DE_STATE_FLAG_SIG_CANT_MATCH (1 << 16) -#define DE_STATE_FLAG_DNSQUERY_INSPECT (1 << 17) +#define DE_STATE_FLAG_DNSQUERYNAME_INSPECT (1 << 17) #define DE_STATE_FLAG_APP_EVENT_INSPECT (1 << 18) #define DE_STATE_FLAG_MODBUS_INSPECT (1 << 19) #define DE_STATE_FLAG_HRL_INSPECT (1 << 20) diff --git a/src/detect-engine.c b/src/detect-engine.c index 6ac78654db63..81fdfb8750f5 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -232,8 +232,8 @@ void DetectEngineRegisterAppInspectionEngines(void) /* DNS */ { IPPROTO_TCP, ALPROTO_DNS, - DETECT_SM_LIST_DNSQUERY_MATCH, - DE_STATE_FLAG_DNSQUERY_INSPECT, + DETECT_SM_LIST_DNSQUERYNAME_MATCH, + DE_STATE_FLAG_DNSQUERYNAME_INSPECT, 0, DetectEngineInspectDnsQueryName }, /* specifically for UDP, register again @@ -241,8 +241,8 @@ void DetectEngineRegisterAppInspectionEngines(void) * in the detection engine */ { IPPROTO_UDP, ALPROTO_DNS, - DETECT_SM_LIST_DNSQUERY_MATCH, - DE_STATE_FLAG_DNSQUERY_INSPECT, + DETECT_SM_LIST_DNSQUERYNAME_MATCH, + DE_STATE_FLAG_DNSQUERYNAME_INSPECT, 0, DetectEngineInspectDnsQueryName }, { IPPROTO_TCP, @@ -1852,8 +1852,8 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_FILEMATCH: return "file"; - case DETECT_SM_LIST_DNSQUERY_MATCH: - return "dns query"; + case DETECT_SM_LIST_DNSQUERYNAME_MATCH: + return "dns query name"; case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 6d76cde97c89..01b8f398e8d5 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -134,7 +134,7 @@ void SupportFastPatternForSigMatchTypes(void) SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSCDMATCH, 3); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSMDMATCH, 3); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_DNSQUERY_MATCH, 2); + SupportFastPatternForSigMatchList(DETECT_SM_LIST_DNSQUERYNAME_MATCH, 2); #if 0 SCFPSupportSMList *tmp = sm_fp_support_smlist_list; @@ -225,7 +225,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH] == NULL) { + s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL) { SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " "rule, without a preceding content based keyword. " "Currently we provide fast_pattern support for content, " @@ -252,7 +252,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " "the rule, without a content context. Please use a " diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 2cac2bd794b1..e6a16f40d087 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -1087,17 +1087,17 @@ static int DetectIsdataatTestParse16(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH] == NULL) { + if (s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL) { printf("dns_query list empty: "); goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH]->type != DETECT_ISDATAAT) { + if (s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH]->type != DETECT_ISDATAAT) { printf("last dns_query body sm not isdataat: "); goto end; } - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH]->ctx; + data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { diff --git a/src/detect-lua.c b/src/detect-lua.c index 55bb0aec57b7..81de2f95eb3a 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1044,7 +1044,7 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) else SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRLMATCH); } else if (luajit->alproto == ALPROTO_DNS) { - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSQUERY_MATCH); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSQUERYNAME_MATCH); } else { SCLogError(SC_ERR_LUA_ERROR, "luajit can't be used with protocol %s", AppLayerGetProtoName(luajit->alproto)); diff --git a/src/detect-parse.c b/src/detect-parse.c index 4713502ebbe2..2517036643dc 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1478,7 +1478,7 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HRHHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_DNSQUERY_MATCH]) + if (sig->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_MODBUS_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 5b84afaf2b08..86f3d169950a 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -686,8 +686,8 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst AppLayerHtpEnableResponseBodyCallback(); } else if (s->list == DETECT_SM_LIST_DMATCH) { SCLogDebug("adding to dmatch list because of dce_stub_data"); - } else if (s->list == DETECT_SM_LIST_DNSQUERY_MATCH) { - SCLogDebug("adding to DETECT_SM_LIST_DNSQUERY_MATCH list because of dns_query"); + } else if (s->list == DETECT_SM_LIST_DNSQUERYNAME_MATCH) { + SCLogDebug("adding to DETECT_SM_LIST_DNSQUERYNAME_MATCH list because of dns_query"); } s->flags |= SIG_FLAG_APPLAYER; sm_list = s->list; diff --git a/src/detect.h b/src/detect.h index 0765b4acf5b1..32a729370432 100644 --- a/src/detect.h +++ b/src/detect.h @@ -120,7 +120,7 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_FILEMATCH, - DETECT_SM_LIST_DNSQUERY_MATCH, + DETECT_SM_LIST_DNSQUERYNAME_MATCH, DETECT_SM_LIST_MODBUS_MATCH, /* list for post match actions: flowbit set, flowint increment, etc */ From e6129f7b47cfbf886254bf283bf4844f6493ac40 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 9 Jun 2015 15:31:32 +0200 Subject: [PATCH 0621/2553] dns: generic request/response detect lists --- src/detect-engine.c | 4 ++++ src/detect.h | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 81fdfb8750f5..913aa8ab2650 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1854,6 +1854,10 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_DNSQUERYNAME_MATCH: return "dns query name"; + case DETECT_SM_LIST_DNSREQUEST_MATCH: + return "dns request"; + case DETECT_SM_LIST_DNSRESPONSE_MATCH: + return "dns response"; case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; diff --git a/src/detect.h b/src/detect.h index 32a729370432..24b6ff3a323a 100644 --- a/src/detect.h +++ b/src/detect.h @@ -120,7 +120,10 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_FILEMATCH, - DETECT_SM_LIST_DNSQUERYNAME_MATCH, + DETECT_SM_LIST_DNSREQUEST_MATCH, /**< per DNS query tx match list */ + DETECT_SM_LIST_DNSRESPONSE_MATCH, /**< per DNS response tx match list */ + DETECT_SM_LIST_DNSQUERYNAME_MATCH, /**< per query in a tx list */ + DETECT_SM_LIST_MODBUS_MATCH, /* list for post match actions: flowbit set, flowint increment, etc */ From 110e23964e99cf7c7f43a9a24eb740f3e335b002 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 10 Jun 2015 11:50:51 +0200 Subject: [PATCH 0622/2553] detect: add AppLayerTxMatch call --- src/detect.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/detect.h b/src/detect.h index 24b6ff3a323a..d8d884751a93 100644 --- a/src/detect.h +++ b/src/detect.h @@ -892,6 +892,11 @@ typedef struct SigTableElmt_ { /** AppLayer match function pointer */ int (*AppLayerMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, Signature *, SigMatch *); + /** AppLayer TX match function pointer */ + int (*AppLayerTxMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t flags, void *alstate, void *txv, + const Signature *, const SigMatchCtx *); + /** File match function pointer */ int (*FileMatch)(ThreadVars *, /**< thread local vars */ DetectEngineThreadCtx *, From 433e511b636d09dfa71bd45095499210aa68bee5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 10 Jun 2015 11:57:59 +0200 Subject: [PATCH 0623/2553] dns: generic inspect engines for DNS --- src/detect-engine-dns.c | 69 +++++++++++++++++++++++++++++++++++++++ src/detect-engine-dns.h | 10 ++++++ src/detect-engine-state.h | 2 ++ src/detect-engine.c | 33 ++++++++++++++++++- src/detect-parse.c | 9 +++++ 5 files changed, 122 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index a1e064083cdc..b08681c01e95 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -92,3 +92,72 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, } return r; } + + +/** \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags app layer flags + * \param state App layer state + * + * \retval 0 no match + * \retval 1 match + */ +int DetectEngineInspectGenericList(ThreadVars *tv, + const DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + const Signature *s, Flow *f, const uint8_t flags, + void *alstate, void *txv, uint64_t tx_id, const int list) +{ + KEYWORD_PROFILING_SET_LIST(det_ctx, list); + + SigMatchData *smd = s->sm_arrays[list]; + SCLogDebug("running match functions, sm %p", smd); + if (smd != NULL) { + while (1) { + int match = 0; + KEYWORD_PROFILING_START; + match = sigmatch_table[smd->type]. + AppLayerTxMatch(tv, det_ctx, f, flags, alstate, txv, s, smd->ctx); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); + + if (match == 0) + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + if (match == 2) { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + + if (smd->is_last) + break; + smd++; + } + } + + return DETECT_ENGINE_INSPECT_SIG_MATCH; +} + +int DetectEngineInspectDnsRequest(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, + alstate, txv, tx_id, + DETECT_SM_LIST_DNSREQUEST_MATCH); +} + +int DetectEngineInspectDnsResponse(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, + alstate, txv, tx_id, + DETECT_SM_LIST_DNSRESPONSE_MATCH); +} diff --git a/src/detect-engine-dns.h b/src/detect-engine-dns.h index 419f0fed0339..801a22d42155 100644 --- a/src/detect-engine-dns.h +++ b/src/detect-engine-dns.h @@ -26,5 +26,15 @@ int DetectEngineInspectDnsQueryName(ThreadVars *, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, void *, uint64_t); +int DetectEngineInspectDnsRequest(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); +int DetectEngineInspectDnsResponse(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); #endif /* __DETECT_ENGINE_DNS_H__ */ diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index a04b1231737e..4c88ae794a04 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -79,6 +79,8 @@ #define DE_STATE_FLAG_MODBUS_INSPECT (1 << 19) #define DE_STATE_FLAG_HRL_INSPECT (1 << 20) #define DE_STATE_FLAG_FD_SMTP_INSPECT (1 << 21) +#define DE_STATE_FLAG_DNSREQUEST_INSPECT (1 << 22) +#define DE_STATE_FLAG_DNSRESPONSE_INSPECT (1 << 23) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine.c b/src/detect-engine.c index 913aa8ab2650..adb3d5908e9e 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -245,6 +245,22 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_DNSQUERYNAME_INSPECT, 0, DetectEngineInspectDnsQueryName }, + { IPPROTO_TCP, + ALPROTO_DNS, + DETECT_SM_LIST_DNSREQUEST_MATCH, + DE_STATE_FLAG_DNSREQUEST_INSPECT, + 0, + DetectEngineInspectDnsRequest }, + /* specifically for UDP, register again + * allows us to use the alproto w/o translation + * in the detection engine */ + { IPPROTO_UDP, + ALPROTO_DNS, + DETECT_SM_LIST_DNSREQUEST_MATCH, + DE_STATE_FLAG_DNSREQUEST_INSPECT, + 0, + DetectEngineInspectDnsRequest }, + /* SMTP */ { IPPROTO_TCP, ALPROTO_SMTP, DETECT_SM_LIST_FILEMATCH, @@ -316,7 +332,22 @@ void DetectEngineRegisterAppInspectionEngines(void) DETECT_SM_LIST_MODBUS_MATCH, DE_STATE_FLAG_MODBUS_INSPECT, 0, - DetectEngineInspectModbus } + DetectEngineInspectModbus }, + { IPPROTO_TCP, + ALPROTO_DNS, + DETECT_SM_LIST_DNSRESPONSE_MATCH, + DE_STATE_FLAG_DNSRESPONSE_INSPECT, + 1, + DetectEngineInspectDnsResponse }, + /* specifically for UDP, register again + * allows us to use the alproto w/o translation + * in the detection engine */ + { IPPROTO_UDP, + ALPROTO_DNS, + DETECT_SM_LIST_DNSRESPONSE_MATCH, + DE_STATE_FLAG_DNSRESPONSE_INSPECT, + 1, + DetectEngineInspectDnsResponse }, }; size_t i; diff --git a/src/detect-parse.c b/src/detect-parse.c index 2517036643dc..d077791e345a 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1478,8 +1478,17 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HRHHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + + /* DNS */ if (sig->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_DNSREQUEST_MATCH]) { + sig->flags |= SIG_FLAG_STATE_MATCH; + } + if (sig->sm_lists[DETECT_SM_LIST_DNSRESPONSE_MATCH]) { + sig->flags |= SIG_FLAG_STATE_MATCH; + } + if (sig->sm_lists[DETECT_SM_LIST_MODBUS_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_APP_EVENT]) From 4dd53c8f03111da4c6b857f6e7486697b8be246f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 10 Jun 2015 12:15:10 +0200 Subject: [PATCH 0624/2553] lua: dns support --- src/detect-lua.c | 73 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/src/detect-lua.c b/src/detect-lua.c index 81de2f95eb3a..76626a017622 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -111,6 +111,10 @@ static int DetectLuaMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m); +static int DetectLuaAppTxMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, + const SigMatchCtx *ctx); static int DetectLuaSetup (DetectEngineCtx *, Signature *, char *); static void DetectLuaRegisterTests(void); static void DetectLuaFree(void *); @@ -126,6 +130,7 @@ void DetectLuaRegister(void) sigmatch_table[DETECT_LUA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Lua_scripting"; sigmatch_table[DETECT_LUA].Match = DetectLuaMatch; sigmatch_table[DETECT_LUA].AppLayerMatch = DetectLuaAppMatch; + sigmatch_table[DETECT_LUA].AppLayerTxMatch = DetectLuaAppTxMatch; sigmatch_table[DETECT_LUA].Setup = DetectLuaSetup; sigmatch_table[DETECT_LUA].Free = DetectLuaFree; sigmatch_table[DETECT_LUA].RegisterTests = DetectLuaRegisterTests; @@ -156,6 +161,8 @@ void DetectLuaRegister(void) #define DATATYPE_HTTP_RESPONSE_HEADERS_RAW (1<<14) #define DATATYPE_DNS_RRNAME (1<<15) +#define DATATYPE_DNS_REQUEST (1<<16) +#define DATATYPE_DNS_RESPONSE (1<<17) #ifdef HAVE_LUAJIT static void *LuaStatePoolAlloc(void) @@ -510,23 +517,13 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, SCReturnInt(ret); } -/** - * \brief match the specified lua script in AMATCH - * - * \param t thread local vars - * \param det_ctx pattern matcher thread local data - * \param s signature being inspected - * \param m sigmatch that we will cast into DetectLuaData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectLuaAppMatchCommon (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; - DetectLuaData *luajit = (DetectLuaData *)m->ctx; + DetectLuaData *luajit = (DetectLuaData *)ctx; if (luajit == NULL) SCReturnInt(0); @@ -622,6 +619,42 @@ static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, SCReturnInt(ret); } +/** + * \brief match the specified lua script in AMATCH + * + * \param t thread local vars + * \param det_ctx pattern matcher thread local data + * \param s signature being inspected + * \param m sigmatch that we will cast into DetectLuaData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +{ + return DetectLuaAppMatchCommon(t, det_ctx, f, flags, state, s, m->ctx); +} + +/** + * \brief match the specified lua script in a list with a tx + * + * \param t thread local vars + * \param det_ctx pattern matcher thread local data + * \param s signature being inspected + * \param m sigmatch that we will cast into DetectLuaData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectLuaAppTxMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, + const SigMatchCtx *ctx) +{ + return DetectLuaAppMatchCommon(t, det_ctx, f, flags, state, s, ctx); +} + #ifdef UNITTESTS /* if this ptr is set the luajit setup functions will use this buffer as the * lua script instead of calling luaL_loadfile on the filename supplied. */ @@ -946,6 +979,10 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) if (strcmp(k, "dns.rrname") == 0) ld->flags |= DATATYPE_DNS_RRNAME; + else if (strcmp(k, "dns.request") == 0) + ld->flags |= DATATYPE_DNS_REQUEST; + else if (strcmp(k, "dns.response") == 0) + ld->flags |= DATATYPE_DNS_RESPONSE; else { SCLogError(SC_ERR_LUA_ERROR, "unsupported dns data type %s", k); @@ -1044,7 +1081,13 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) else SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRLMATCH); } else if (luajit->alproto == ALPROTO_DNS) { - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSQUERYNAME_MATCH); + if (luajit->flags & DATATYPE_DNS_RRNAME) { + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSQUERYNAME_MATCH); + } else if (luajit->flags & DATATYPE_DNS_REQUEST) { + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSREQUEST_MATCH); + } else if (luajit->flags & DATATYPE_DNS_RESPONSE) { + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSRESPONSE_MATCH); + } } else { SCLogError(SC_ERR_LUA_ERROR, "luajit can't be used with protocol %s", AppLayerGetProtoName(luajit->alproto)); From 334e8656bf7cc08e24048a1d8c7865ec45ccb478 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 10 Jul 2015 12:19:57 +0200 Subject: [PATCH 0625/2553] introduce fatal error macro's Add 'FatalError' and 'FatalErrorConditonal' that will take the same args as SCLogError. FatalError logs the error using SCLogError and then exits with return code EXIT_FAILURE. FatalErrorOnInit does the same only during init and with --init-errors-fatal enabled, otherwise it just calls SCLogWarning. So then the macro returns to the caller. Implement this for output setup. --- src/output-lua.c | 15 ++++++++++++--- src/runmodes.c | 26 +++++++++++--------------- src/util-debug.h | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/output-lua.c b/src/output-lua.c index 0f06450e9b6c..fc5a562164fe 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -736,7 +736,7 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) int r = LuaScriptInit(path, &opts); if (r != 0) { SCLogError(SC_ERR_LUA_ERROR, "couldn't initialize scipt"); - continue; + goto error; } /* create an OutputModule for this script, based @@ -744,7 +744,7 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) OutputModule *om = SCCalloc(1, sizeof(*om)); if (om == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "calloc() failed"); - continue; + goto error; } om->name = MODULE_NAME; @@ -783,13 +783,22 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) } else { SCLogError(SC_ERR_LUA_ERROR, "failed to setup thread module"); SCFree(om); - continue; + goto error; } TAILQ_INSERT_TAIL(&output_ctx->submodules, om, entries); } return output_ctx; + +error: + + if (output_ctx != NULL) { + if (output_ctx->DeInit && output_ctx->data) + output_ctx->DeInit(output_ctx->data); + SCFree(output_ctx); + } + return NULL; } /** \internal diff --git a/src/runmodes.c b/src/runmodes.c index e6ff72872b33..5a9f9762259d 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -703,9 +703,8 @@ void RunModeInitializeOutputs(void) output_config = ConfNodeLookupChild(output, output->val); if (output_config == NULL) { /* Shouldn't happen. */ - SCLogError(SC_ERR_INVALID_ARGUMENT, - "Failed to lookup configuration child node: fast"); - exit(1); + FatalError(SC_ERR_INVALID_ARGUMENT, + "Failed to lookup configuration child node: %s", output->val); } if (strcmp(output->val, "tls-store") == 0) { @@ -754,8 +753,8 @@ void RunModeInitializeOutputs(void) OutputModule *module = OutputGetModuleByConfName(output->val); if (module == NULL) { - SCLogWarning(SC_ERR_INVALID_ARGUMENT, - "No output module named %s, ignoring", output->val); + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + "No output module named %s", output->val); continue; } @@ -763,8 +762,7 @@ void RunModeInitializeOutputs(void) if (module->InitFunc != NULL) { output_ctx = module->InitFunc(output_config); if (output_ctx == NULL) { - /* In most cases the init function will have logged the - * error. Maybe we should exit on init errors? */ + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, "output module setup failed"); continue; } } else if (module->InitSubFunc != NULL) { @@ -786,20 +784,18 @@ void RunModeInitializeOutputs(void) OutputModule *sub_module = OutputGetModuleByConfName(subname); if (sub_module == NULL) { - SCLogWarning(SC_ERR_INVALID_ARGUMENT, - "No output module named %s, ignoring", subname); + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + "No output module named %s", subname); continue; } if (sub_module->parent_name == NULL || strcmp(sub_module->parent_name,output->val) != 0) { - SCLogWarning(SC_ERR_INVALID_ARGUMENT, - "bad parent for %s, ignoring", subname); - continue; + FatalError(SC_ERR_INVALID_ARGUMENT, + "bad parent for %s", subname); } if (sub_module->InitSubFunc == NULL) { - SCLogWarning(SC_ERR_INVALID_ARGUMENT, - "bad sub-module for %s, ignoring", subname); - continue; + FatalError(SC_ERR_INVALID_ARGUMENT, + "bad sub-module for %s", subname); } ConfNode *sub_output_config = ConfNodeLookupChild(type, type->val); // sub_output_config may be NULL if no config diff --git a/src/util-debug.h b/src/util-debug.h index 02ea30e2b08b..9c9d2e23eed3 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -507,6 +507,24 @@ extern int sc_log_module_cleaned; #endif /* DEBUG */ +#define FatalError(x, ...) do { \ + SCLogError(x, __VA_ARGS__); \ + exit(EXIT_FAILURE); \ +} while(0) + +/** \brief Fatal error IF we're starting up, and configured to consider + * errors to be fatal errors */ +#define FatalErrorOnInit(x, ...) do { \ + int init_errors_fatal = 0; \ + ConfGetBool("engine.init-failure-fatal", &init_errors_fatal); \ + if (init_errors_fatal && (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT))\ + { \ + SCLogError(x, __VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } \ + SCLogWarning(x, __VA_ARGS__); \ +} while(0) + SCLogInitData *SCLogAllocLogInitData(void); From 6484299701699a3934f145ababeaae5b9f01bf75 Mon Sep 17 00:00:00 2001 From: Schnaffon Date: Tue, 28 Apr 2015 12:23:12 +0200 Subject: [PATCH 0626/2553] Use unlikely for error treatment in alert-prelude.c When handling error cases on creation of a new idmef field, we are in an unlikely case. This patch adds the unlikely() expression to indicate this to gcc. --- src/alert-prelude.c | 108 ++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index a8e41ac339d2..a053e38b833a 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -131,22 +131,22 @@ static int SetupAnalyzer(idmef_analyzer_t *analyzer) SCEnter(); ret = idmef_analyzer_new_model(analyzer, &string); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); prelude_string_set_constant(string, ANALYZER_MODEL); ret = idmef_analyzer_new_class(analyzer, &string); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); prelude_string_set_constant(string, ANALYZER_CLASS); ret = idmef_analyzer_new_manufacturer(analyzer, &string); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); prelude_string_set_constant(string, ANALYZER_MANUFACTURER); ret = idmef_analyzer_new_version(analyzer, &string); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); prelude_string_set_constant(string, VERSION); @@ -174,11 +174,11 @@ static int EventToImpact(const PacketAlert *pa, const Packet *p, idmef_alert_t * SCEnter(); ret = idmef_alert_new_assessment(alert, &assessment); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_assessment_new_impact(assessment, &impact); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); if ( (unsigned int)pa->s->prio < mid_priority ) @@ -199,7 +199,7 @@ static int EventToImpact(const PacketAlert *pa, const Packet *p, idmef_alert_t * idmef_action_t *action; ret = idmef_action_new(&action); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); idmef_action_set_category(action, IDMEF_ACTION_CATEGORY_BLOCK_INSTALLED); @@ -208,7 +208,7 @@ static int EventToImpact(const PacketAlert *pa, const Packet *p, idmef_alert_t * if (pa->s->class_msg) { ret = idmef_impact_new_description(impact, &str); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); prelude_string_set_ref(str, pa->s->class_msg); @@ -259,11 +259,11 @@ static int EventToSourceTarget(const Packet *p, idmef_alert_t *alert) SCReturnInt(0); ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_source_new_service(source, &service); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); if ( p->tcph || p->udph ) @@ -273,25 +273,25 @@ static int EventToSourceTarget(const Packet *p, idmef_alert_t *alert) idmef_service_set_iana_protocol_number(service, ip_proto); ret = idmef_source_new_node(source, &node); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_address_new_address(address, &string); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); prelude_string_set_ref(string, saddr); ret = idmef_alert_new_target(alert, &target, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_target_new_service(target, &service); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); if ( p->tcph || p->udph ) @@ -301,15 +301,15 @@ static int EventToSourceTarget(const Packet *p, idmef_alert_t *alert) idmef_service_set_iana_protocol_number(service, ip_proto); ret = idmef_target_new_node(target, &node); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_address_new_address(address, &string); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); prelude_string_set_ref(string, daddr); @@ -335,25 +335,25 @@ static int AddByteData(idmef_alert_t *alert, const char *meaning, const unsigned SCReturnInt(0); ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(0); ret = idmef_additional_data_set_byte_string_ref(ad, data, size); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("%s: error setting byte string data: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } ret = idmef_additional_data_new_meaning(ad, &str); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("%s: error creating additional-data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } ret = prelude_string_set_ref(str, meaning); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("%s: error setting byte string data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); @@ -377,20 +377,20 @@ static int AddIntData(idmef_alert_t *alert, const char *meaning, uint32_t data) SCEnter(); ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); idmef_additional_data_set_integer(ad, data); ret = idmef_additional_data_new_meaning(ad, &str); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("%s: error creating additional-data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } ret = prelude_string_set_ref(str, meaning); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("%s: error setting integer data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); @@ -449,7 +449,7 @@ static int PacketToData(const Packet *p, const PacketAlert *pa, idmef_alert_t *a { SCEnter(); - if ( ! p ) + if (unlikely(p == NULL)) SCReturnInt(0); AddIntData(alert, "snort_rule_sid", pa->s->id); @@ -513,11 +513,11 @@ static int AddSnortReference(idmef_classification_t *class, int gen_id, int sig_ SCReturnInt(0); ret = idmef_classification_new_reference(class, &ref, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_reference_new_name(ref, &str); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); idmef_reference_set_origin(ref, IDMEF_REFERENCE_ORIGIN_VENDOR_SPECIFIC); @@ -527,19 +527,19 @@ static int AddSnortReference(idmef_classification_t *class, int gen_id, int sig_ else ret = prelude_string_sprintf(str, "%u:%u", gen_id, sig_id); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_reference_new_meaning(ref, &str); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = prelude_string_sprintf(str, "Snort Signature ID"); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_reference_new_url(ref, &str); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); if ( gen_id == 0 ) @@ -566,18 +566,18 @@ static int EventToReference(const PacketAlert *pa, const Packet *p, idmef_classi SCEnter(); ret = idmef_classification_new_ident(class, &str); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); if ( pa->s->gid == 0 ) ret = prelude_string_sprintf(str, "%u", pa->s->id); else ret = prelude_string_sprintf(str, "%u:%u", pa->s->gid, pa->s->id); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = AddSnortReference(class, pa->s->gid, pa->s->id); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); SCReturnInt(0); @@ -606,7 +606,7 @@ static TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data SCEnter(); - if(initdata == NULL) + if(unlikely(initdata == NULL)) { SCLogDebug("Error getting context for Prelude. \"initdata\" argument NULL"); SCReturnInt(TM_ECODE_FAILED); @@ -635,7 +635,7 @@ static TmEcode AlertPreludeThreadDeinit(ThreadVars *t, void *data) SCEnter(); - if (aun == NULL) { + if (unlikely(aun == NULL)) { SCLogDebug("AlertPreludeThreadDeinit done (error)"); SCReturnInt(TM_ECODE_FAILED); } @@ -677,7 +677,7 @@ static OutputCtx *AlertPreludeInitCtx(ConfNode *conf) SCEnter(); ret = prelude_init(0, NULL); - if (ret < 0) { + if (unlikely(ret < 0)) { prelude_perror(ret, "unable to initialize the prelude library"); SCReturnPtr(NULL, "AlertPreludeCtx"); } @@ -690,14 +690,14 @@ static OutputCtx *AlertPreludeInitCtx(ConfNode *conf) log_packet_header = ConfNodeLookupChildValue(conf, "log-packet-header"); ret = prelude_client_new(&client, prelude_profile_name); - if ( ret < 0 || ! client ) { + if ( unlikely(ret < 0 || client == NULL )) { prelude_perror(ret, "Unable to create a prelude client object"); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); } ret = prelude_client_set_flags(client, prelude_client_get_flags(client) | PRELUDE_CLIENT_FLAGS_ASYNC_TIMER|PRELUDE_CLIENT_FLAGS_ASYNC_SEND); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("Unable to set asynchronous send and timer."); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); @@ -706,7 +706,7 @@ static OutputCtx *AlertPreludeInitCtx(ConfNode *conf) SetupAnalyzer(prelude_client_get_analyzer(client)); ret = prelude_client_start(client); - if (ret < 0) { + if (unlikely(ret < 0)) { prelude_perror(ret, "Unable to start prelude client"); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); @@ -779,7 +779,7 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p SCEnter(); - if (apn == NULL || apn->ctx == NULL) { + if (unlikely(apn == NULL || apn->ctx == NULL)) { SCReturnInt(TM_ECODE_FAILED); } @@ -792,43 +792,43 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p /* XXX which one to add to this alert? Lets see how Snort solves this. * For now just take last alert. */ pa = &p->alerts.alerts[p->alerts.cnt-1]; - if (pa->s == NULL) + if (unlikely(pa->s == NULL)) goto err; ret = idmef_message_new(&idmef); - if ( ret < 0 ) + if (unlikely(ret < 0)) SCReturnInt(TM_ECODE_FAILED); ret = idmef_message_new_alert(idmef, &alert); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; ret = idmef_alert_new_classification(alert, &class); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; if (pa->s->msg) { ret = idmef_classification_new_text(class, &str); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; prelude_string_set_ref(str, pa->s->msg); } ret = EventToImpact(pa, p, alert); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; ret = EventToReference(pa, p, class); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; ret = EventToSourceTarget(p, alert); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; ret = PacketToData(p, pa, alert, apn->ctx); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; if (PKT_IS_TCP(p) && (pa->flags & PACKET_ALERT_FLAG_STATE_MATCH)) { @@ -842,16 +842,16 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p PreludePrintStreamSegmentCallback, (void *)alert); } - if (ret < 0) + if (unlikely(ret < 0)) goto err; ret = idmef_alert_new_detect_time(alert, &time); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; idmef_time_set_from_timeval(time, &p->ts); ret = idmef_time_new_from_gettimeofday(&time); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; idmef_alert_set_create_time(alert, time); From 491fca468d73eab0ef554f32fa4ee7444259dd3f Mon Sep 17 00:00:00 2001 From: Aleksey Katargin Date: Thu, 16 Jul 2015 17:43:28 +0500 Subject: [PATCH 0627/2553] netmap: support non-equal count of Rx and Tx rings on interface. Netmap does not guarantees that NIC will have equal number of transmit and receive rings. --- src/source-netmap.c | 59 ++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index 570ecfc4da47..2b42fc29fa61 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -127,6 +127,8 @@ TmEcode NoNetmapSupportExit(ThreadVars *tv, void *initdata, void **data) #else /* We have NETMAP support */ +#define max(a, b) (((a) > (b)) ? (a) : (b)) + #define POLL_TIMEOUT 100 #if defined(__linux__) @@ -165,6 +167,8 @@ typedef struct NetmapDevice_ size_t memsize; struct netmap_if *nif; int rings_cnt; + int rx_rings_cnt; + int tx_rings_cnt; NetmapRing *rings; unsigned int ref; SC_ATOMIC_DECLARE(unsigned int, threads_run); @@ -360,15 +364,11 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver } goto error_fd; }; - if (nm_req.nr_rx_rings != nm_req.nr_tx_rings) { - SCLogError(SC_ERR_NETMAP_CREATE, - "Interface '%s' have non-equeal Tx/Rx rings (%"PRIu16"/%"PRIu16")", - ifname, nm_req.nr_rx_rings, nm_req.nr_tx_rings); - goto error_fd; - } - pdev->rings_cnt = nm_req.nr_rx_rings; pdev->memsize = nm_req.nr_memsize; + pdev->rx_rings_cnt = nm_req.nr_rx_rings; + pdev->tx_rings_cnt = nm_req.nr_tx_rings; + pdev->rings_cnt = max(pdev->rx_rings_cnt, pdev->tx_rings_cnt); pdev->rings = SCMalloc(sizeof(*pdev->rings) * pdev->rings_cnt); if (unlikely(pdev->rings == NULL)) { @@ -410,8 +410,12 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver pdev->nif = NETMAP_IF(pdev->mem, nm_req.nr_offset); } - pring->rx = NETMAP_RXRING(pdev->nif, i); - pring->tx = NETMAP_TXRING(pdev->nif, i); + if (i < pdev->rx_rings_cnt) { + pring->rx = NETMAP_RXRING(pdev->nif, i); + } + if (i < pdev->tx_rings_cnt) { + pring->tx = NETMAP_TXRING(pdev->nif, i); + } SCSpinInit(&pring->tx_lock, 0); success_cnt++; } @@ -528,11 +532,18 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da goto error_ntv; } - if (aconf->threads > ntv->ifsrc->rings_cnt) { + if (unlikely(!ntv->ifsrc->rx_rings_cnt)) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Input interface '%s' does not have Rx rings", + aconf->iface); + goto error_src; + } + + if (unlikely(aconf->threads > ntv->ifsrc->rx_rings_cnt)) { SCLogError(SC_ERR_INVALID_VALUE, - "Thread count can't be greater than ring count. " - "Configured %d threads for interfaces '%s' with %u rings.", - aconf->threads, aconf->iface, ntv->ifsrc->rings_cnt); + "Thread count can't be greater than Rx ring count. " + "Configured %d threads for interface '%s' with %u Rx rings.", + aconf->threads, aconf->iface, ntv->ifsrc->rx_rings_cnt); goto error_src; } @@ -541,16 +552,22 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da } while (SC_ATOMIC_CAS(&ntv->ifsrc->threads_run, ntv->thread_idx, ntv->thread_idx + 1) == 0); /* calculate rings borders */ - int tmp = ntv->ifsrc->rings_cnt / aconf->threads; + int tmp = ntv->ifsrc->rx_rings_cnt / aconf->threads; ntv->ring_from = ntv->thread_idx * tmp; ntv->ring_to = ntv->ring_from + tmp - 1; - if (ntv->ring_to >= ntv->ifsrc->rings_cnt) - ntv->ring_to = ntv->ifsrc->rings_cnt - 1; + if (ntv->ring_to >= ntv->ifsrc->rx_rings_cnt) + ntv->ring_to = ntv->ifsrc->rx_rings_cnt - 1; if (aconf->copy_mode != NETMAP_COPY_MODE_NONE) { if (NetmapOpen(aconf->out_iface, 0, &ntv->ifdst, 1) != 0) { goto error_src; } + if (unlikely(!ntv->ifdst->tx_rings_cnt)) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Output interface '%s' does not have Tx rings", + aconf->out_iface); + goto error_dst; + } } /* basic counters */ @@ -576,7 +593,7 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da PCAP_NETMASK_UNKNOWN /* mask */ ) == -1) { SCLogError(SC_ERR_NETMAP_CREATE, "Filter compilation failed."); - goto error_src; + goto error_dst; } } @@ -589,6 +606,10 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da aconf->DerefFunc(aconf); SCReturnInt(TM_ECODE_OK); +error_dst: + if (aconf->copy_mode != NETMAP_COPY_MODE_NONE) { + NetmapClose(ntv->ifdst); + } error_src: NetmapClose(ntv->ifsrc); error_ntv: @@ -612,7 +633,7 @@ static TmEcode NetmapWritePacket(NetmapThreadVars *ntv, Packet *p) } /* map src ring_id to dst ring_id */ - int dst_ring_id = p->netmap_v.ring_id % ntv->ifdst->rings_cnt; + int dst_ring_id = p->netmap_v.ring_id % ntv->ifdst->tx_rings_cnt; NetmapRing *txring = &ntv->ifdst->rings[dst_ring_id]; NetmapRing *rxring = &ntv->ifsrc->rings[p->netmap_v.ring_id]; @@ -815,7 +836,7 @@ static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) if (ntv->copy_mode != NETMAP_COPY_MODE_NONE) { /* sync dst tx rings */ - int dst_ring_id = src_ring_id % ntv->ifdst->rings_cnt; + int dst_ring_id = src_ring_id % ntv->ifdst->tx_rings_cnt; NetmapRing *dst_ring = &ntv->ifdst->rings[dst_ring_id]; if (SCSpinTrylock(&dst_ring->tx_lock) == 0) { ioctl(dst_ring->fd, NIOCTXSYNC, 0); From 5104b02f322017d9ccb1a9a4f9c713779335ad7a Mon Sep 17 00:00:00 2001 From: Aleksey Katargin Date: Thu, 16 Jul 2015 18:35:23 +0500 Subject: [PATCH 0628/2553] netmap: fixed autofp mode. Previous implementation does not work with this mode. --- src/source-netmap.c | 50 +++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index 2b42fc29fa61..7d56e623b97d 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -635,7 +635,6 @@ static TmEcode NetmapWritePacket(NetmapThreadVars *ntv, Packet *p) /* map src ring_id to dst ring_id */ int dst_ring_id = p->netmap_v.ring_id % ntv->ifdst->tx_rings_cnt; NetmapRing *txring = &ntv->ifdst->rings[dst_ring_id]; - NetmapRing *rxring = &ntv->ifsrc->rings[p->netmap_v.ring_id]; SCSpinLock(&txring->tx_lock); @@ -645,21 +644,33 @@ static TmEcode NetmapWritePacket(NetmapThreadVars *ntv, Packet *p) return TM_ECODE_FAILED; } - struct netmap_slot *rs = &rxring->rx->slot[p->netmap_v.slot_id]; struct netmap_slot *ts = &txring->tx->slot[txring->tx->cur]; - /* swap slot buffers */ - uint32_t tmp_idx; - tmp_idx = ts->buf_idx; - ts->buf_idx = rs->buf_idx; - rs->buf_idx = tmp_idx; - - ts->len = rs->len; - - ts->flags |= NS_BUF_CHANGED; - rs->flags |= NS_BUF_CHANGED; + if (ntv->flags & NETMAP_FLAG_ZERO_COPY) { + NetmapRing *rxring = &ntv->ifsrc->rings[p->netmap_v.ring_id]; + struct netmap_slot *rs = &rxring->rx->slot[p->netmap_v.slot_id]; + + /* swap slot buffers */ + uint32_t tmp_idx; + tmp_idx = ts->buf_idx; + ts->buf_idx = rs->buf_idx; + rs->buf_idx = tmp_idx; + + ts->len = rs->len; + + ts->flags |= NS_BUF_CHANGED; + rs->flags |= NS_BUF_CHANGED; + } else { + unsigned char *slot_data = (unsigned char *)NETMAP_BUF(txring->tx, ts->buf_idx); + memcpy(slot_data, GET_PKT_DATA(p), GET_PKT_LEN(p)); + ts->len = GET_PKT_LEN(p); + ts->flags |= NS_BUF_CHANGED; + } txring->tx->head = txring->tx->cur = nm_ring_next(txring->tx, txring->tx->cur); + if ((ntv->flags & NETMAP_FLAG_ZERO_COPY) == 0) { + ioctl(txring->fd, NIOCTXSYNC, 0); + } SCSpinUnlock(&txring->tx_lock); @@ -739,11 +750,6 @@ static int NetmapRingRead(NetmapThreadVars *ntv, int ring_id) if (PacketSetData(p, slot_data, slot->len) == -1) { TmqhOutputPacketpool(ntv->tv, p); SCReturnInt(NETMAP_FAILURE); - } else { - p->ReleasePacket = NetmapReleasePacket; - p->netmap_v.ring_id = ring_id; - p->netmap_v.slot_id = cur; - p->netmap_v.ntv = ntv; } } else { if (PacketCopyData(p, slot_data, slot->len) == -1) { @@ -752,6 +758,11 @@ static int NetmapRingRead(NetmapThreadVars *ntv, int ring_id) } } + p->ReleasePacket = NetmapReleasePacket; + p->netmap_v.ring_id = ring_id; + p->netmap_v.slot_id = cur; + p->netmap_v.ntv = ntv; + SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", GET_PKT_LEN(p), p, GET_PKT_DATA(p)); @@ -834,10 +845,13 @@ static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) int src_ring_id = ntv->ring_from + i; NetmapRingRead(ntv, src_ring_id); - if (ntv->copy_mode != NETMAP_COPY_MODE_NONE) { + if ((ntv->copy_mode != NETMAP_COPY_MODE_NONE) && + (ntv->flags & NETMAP_FLAG_ZERO_COPY)) { + /* sync dst tx rings */ int dst_ring_id = src_ring_id % ntv->ifdst->tx_rings_cnt; NetmapRing *dst_ring = &ntv->ifdst->rings[dst_ring_id]; + /* if locked, another loop already do sync */ if (SCSpinTrylock(&dst_ring->tx_lock) == 0) { ioctl(dst_ring->fd, NIOCTXSYNC, 0); SCSpinUnlock(&dst_ring->tx_lock); From 823167bde2d805b7a089c3ea0c69ee0bc2ff4d64 Mon Sep 17 00:00:00 2001 From: Aleksey Katargin Date: Thu, 16 Jul 2015 18:51:03 +0500 Subject: [PATCH 0629/2553] netmap: strict check for zero copy mode Netmap does not guarantees that mmap'ed regions for different interfaces would be the same. --- src/source-netmap.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index 7d56e623b97d..b00dd43b7546 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -578,8 +578,15 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da char const *active_runmode = RunmodeGetActive(); if (active_runmode && !strcmp("workers", active_runmode)) { - ntv->flags |= NETMAP_FLAG_ZERO_COPY; - SCLogInfo("Enabling zero copy mode"); + if (likely(ntv->ifsrc->mem == ntv->ifdst->mem)) { + ntv->flags |= NETMAP_FLAG_ZERO_COPY; + SCLogInfo("Enabling zero copy mode for %s->%s", + aconf->iface, aconf->out_iface); + } else { + SCLogInfo("Unable to set zero copy mode for %s->%s", + aconf->iface, aconf->out_iface); + } + } if (aconf->bpf_filter) { From caa2438b98f7f48fc0f6e6a30e9522b68d368f81 Mon Sep 17 00:00:00 2001 From: Aleksey Katargin Date: Thu, 16 Jul 2015 21:17:49 +0500 Subject: [PATCH 0630/2553] netmap: support SW rings Netmap uses SW rings to send and receive packets from OS. --- src/runmode-netmap.c | 54 ++++++++----- src/source-netmap.c | 175 +++++++++++++++++++++++++++++-------------- src/source-netmap.h | 13 +++- suricata.yaml.in | 13 +++- 4 files changed, 180 insertions(+), 75 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 3639bef92e39..3289275ed37e 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -103,7 +103,7 @@ static void NetmapDerefConfig(void *conf) * * \return a NetmapIfaceConfig corresponding to the interface name */ -static void *ParseNetmapConfig(const char *iface) +static void *ParseNetmapConfig(const char *iface_name) { char *threadsstr = NULL; ConfNode *if_root; @@ -120,20 +120,29 @@ static void *ParseNetmapConfig(const char *iface) return NULL; } - if (iface == NULL) { + if (iface_name == NULL) { SCFree(aconf); return NULL; } memset(aconf, 0, sizeof(*aconf)); - strlcpy(aconf->iface, iface, sizeof(aconf->iface)); - SC_ATOMIC_INIT(aconf->ref); - (void) SC_ATOMIC_ADD(aconf->ref, 1); aconf->DerefFunc = NetmapDerefConfig; aconf->threads = 1; aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; aconf->copy_mode = NETMAP_COPY_MODE_NONE; + strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name)); + SC_ATOMIC_INIT(aconf->ref); + (void) SC_ATOMIC_ADD(aconf->ref, 1); + + strlcpy(aconf->iface, aconf->iface_name, sizeof(aconf->iface)); + if (aconf->iface[0]) { + size_t len = strlen(aconf->iface); + if (aconf->iface[len-1] == '+') { + aconf->iface[len-1] = '\0'; + aconf->iface_sw = 1; + } + } if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { @@ -150,14 +159,14 @@ static void *ParseNetmapConfig(const char *iface) return aconf; } - if_root = ConfNodeLookupKeyValue(netmap_node, "interface", iface); + if_root = ConfNodeLookupKeyValue(netmap_node, "interface", aconf->iface_name); if_default = ConfNodeLookupKeyValue(netmap_node, "interface", "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find netmap config for " "interface \"%s\" or \"default\", using default value", - iface); + aconf->iface_name); return aconf; } @@ -171,7 +180,7 @@ static void *ParseNetmapConfig(const char *iface) aconf->threads = 1; } else { if (strcmp(threadsstr, "auto") == 0) { - aconf->threads = GetIfaceRSSQueuesNum(iface); + aconf->threads = GetIfaceRSSQueuesNum(aconf->iface); } else { aconf->threads = (uint8_t)atoi(threadsstr); } @@ -181,36 +190,47 @@ static void *ParseNetmapConfig(const char *iface) aconf->threads = 1; } if (aconf->threads) { - SCLogInfo("Using %d threads for interface %s", aconf->threads, iface); + SCLogInfo("Using %d threads for interface %s", aconf->threads, + aconf->iface_name); } if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { if (strlen(out_iface) > 0) { - aconf->out_iface = out_iface; + aconf->out_iface_name = out_iface; } } if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { - if (aconf->out_iface == NULL) { + if (aconf->out_iface_name == NULL) { SCLogInfo("Copy mode activated but no destination" " iface. Disabling feature"); } else if (strlen(copymodestr) <= 0) { - aconf->out_iface = NULL; + aconf->out_iface_name = NULL; } else if (strcmp(copymodestr, "ips") == 0) { SCLogInfo("Netmap IPS mode activated %s->%s", - iface, - aconf->out_iface); + aconf->iface_name, + aconf->out_iface_name); aconf->copy_mode = NETMAP_COPY_MODE_IPS; } else if (strcmp(copymodestr, "tap") == 0) { SCLogInfo("Netmap TAP mode activated %s->%s", - iface, - aconf->out_iface); + aconf->iface_name, + aconf->out_iface_name); aconf->copy_mode = NETMAP_COPY_MODE_TAP; } else { SCLogInfo("Invalid mode (not in tap, ips)"); } } + if (aconf->out_iface_name && aconf->out_iface_name[0]) { + strlcpy(aconf->out_iface, aconf->out_iface_name, + sizeof(aconf->out_iface)); + size_t len = strlen(aconf->out_iface); + if (aconf->out_iface[len-1] == '+') { + aconf->out_iface[len-1] = '\0'; + aconf->out_iface_sw = 1; + } + } + SC_ATOMIC_RESET(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); @@ -239,7 +259,7 @@ static void *ParseNetmapConfig(const char *iface) } else if (strcmp(tmpctype, "no") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { - SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface); + SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface_name); } } diff --git a/src/source-netmap.c b/src/source-netmap.c index b00dd43b7546..79bd161b8cdd 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -154,6 +154,9 @@ typedef struct NetmapRing int fd; struct netmap_ring *rx; struct netmap_ring *tx; + int dst_ring_from; + int dst_ring_to; + int dst_next_ring; SCSpinlock tx_lock; } NetmapRing; @@ -169,6 +172,7 @@ typedef struct NetmapDevice_ int rings_cnt; int rx_rings_cnt; int tx_rings_cnt; + /* hw rings + sw ring */ NetmapRing *rings; unsigned int ref; SC_ATOMIC_DECLARE(unsigned int, threads_run); @@ -185,8 +189,8 @@ typedef struct NetmapThreadVars_ /* dst interface for IPS mode */ NetmapDevice *ifdst; - int ring_from; - int ring_to; + int src_ring_from; + int src_ring_to; int thread_idx; int flags; struct bpf_program bpf_prog; @@ -370,16 +374,17 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver pdev->tx_rings_cnt = nm_req.nr_tx_rings; pdev->rings_cnt = max(pdev->rx_rings_cnt, pdev->tx_rings_cnt); - pdev->rings = SCMalloc(sizeof(*pdev->rings) * pdev->rings_cnt); + /* hw rings + sw ring */ + pdev->rings = SCMalloc(sizeof(*pdev->rings) * (pdev->rings_cnt + 1)); if (unlikely(pdev->rings == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); goto error_fd; } - memset(pdev->rings, 0, sizeof(*pdev->rings) * pdev->rings_cnt); + memset(pdev->rings, 0, sizeof(*pdev->rings) * (pdev->rings_cnt + 1)); /* open individual instance for each ring */ int success_cnt = 0; - for (int i = 0; i < pdev->rings_cnt; i++) { + for (int i = 0; i <= pdev->rings_cnt; i++) { NetmapRing *pring = &pdev->rings[i]; pring->fd = open("/dev/netmap", O_RDWR); if (pring->fd == -1) { @@ -389,8 +394,13 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver break; } - nm_req.nr_flags = NR_REG_ONE_NIC; - nm_req.nr_ringid = i | NETMAP_NO_TX_POLL; + if (i < pdev->rings_cnt) { + nm_req.nr_flags = NR_REG_ONE_NIC; + nm_req.nr_ringid = i | NETMAP_NO_TX_POLL; + } else { + nm_req.nr_flags = NR_REG_SW; + nm_req.nr_ringid = NETMAP_NO_TX_POLL; + } if (ioctl(pring->fd, NIOCREGIF, &nm_req) != 0) { SCLogError(SC_ERR_NETMAP_CREATE, "Couldn't register %s with netmap: %s", @@ -405,27 +415,30 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver SCLogError(SC_ERR_NETMAP_CREATE, "Couldn't mmap netmap device: %s", strerror(errno)); - goto error_fd; + break; } pdev->nif = NETMAP_IF(pdev->mem, nm_req.nr_offset); } - if (i < pdev->rx_rings_cnt) { + if ((i < pdev->rx_rings_cnt) || (i == pdev->rings_cnt)) { pring->rx = NETMAP_RXRING(pdev->nif, i); } - if (i < pdev->tx_rings_cnt) { + if ((i < pdev->tx_rings_cnt) || (i == pdev->rings_cnt)) { pring->tx = NETMAP_TXRING(pdev->nif, i); } SCSpinInit(&pring->tx_lock, 0); success_cnt++; } - if (success_cnt != pdev->rings_cnt) { + if (success_cnt != (pdev->rings_cnt + 1)) { for(int i = 0; i < success_cnt; i++) { close(pdev->rings[i].fd); } + if (pdev->mem) { + munmap(pdev->mem, pdev->memsize); + } SCFree(pdev->rings); - goto error_mem; + goto error_fd; } close(fd); @@ -436,8 +449,6 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver return 0; -error_mem: - munmap(pdev->mem, pdev->memsize); error_fd: close(fd); error_pdev: @@ -463,7 +474,7 @@ static int NetmapClose(NetmapDevice *dev) pdev->ref--; if (!pdev->ref) { munmap(pdev->mem, pdev->memsize); - for (int i = 0; i < pdev->rings_cnt; i++) { + for (int i = 0; i <= pdev->rings_cnt; i++) { NetmapRing *pring = &pdev->rings[i]; close(pring->fd); SCSpinDestroy(&pring->tx_lock); @@ -522,7 +533,7 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da ntv->checksum_mode = aconf->checksum_mode; ntv->copy_mode = aconf->copy_mode; - ntv->livedev = LiveGetDevice(aconf->iface); + ntv->livedev = LiveGetDevice(aconf->iface_name); if (ntv->livedev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); goto error_ntv; @@ -532,42 +543,83 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da goto error_ntv; } - if (unlikely(!ntv->ifsrc->rx_rings_cnt)) { + if (unlikely(!aconf->iface_sw && !ntv->ifsrc->rx_rings_cnt)) { SCLogError(SC_ERR_NETMAP_CREATE, "Input interface '%s' does not have Rx rings", - aconf->iface); + aconf->iface_name); goto error_src; } - if (unlikely(aconf->threads > ntv->ifsrc->rx_rings_cnt)) { + if (unlikely(aconf->iface_sw && aconf->threads > 1)) { + SCLogError(SC_ERR_INVALID_VALUE, + "Interface '%s+'. " + "Thread count can't be greater than 1 for SW ring.", + aconf->iface_name); + goto error_src; + } else if (unlikely(aconf->threads > ntv->ifsrc->rx_rings_cnt)) { SCLogError(SC_ERR_INVALID_VALUE, "Thread count can't be greater than Rx ring count. " - "Configured %d threads for interface '%s' with %u Rx rings.", - aconf->threads, aconf->iface, ntv->ifsrc->rx_rings_cnt); + "Configured %d threads for interface '%s' with %d Rx rings.", + aconf->threads, aconf->iface_name, ntv->ifsrc->rx_rings_cnt); goto error_src; } - do { - ntv->thread_idx = SC_ATOMIC_GET(ntv->ifsrc->threads_run); - } while (SC_ATOMIC_CAS(&ntv->ifsrc->threads_run, ntv->thread_idx, ntv->thread_idx + 1) == 0); + if (aconf->iface_sw) { + ntv->thread_idx = 0; + } else { + do { + ntv->thread_idx = SC_ATOMIC_GET(ntv->ifsrc->threads_run); + } while (SC_ATOMIC_CAS(&ntv->ifsrc->threads_run, ntv->thread_idx, ntv->thread_idx + 1) == 0); + } - /* calculate rings borders */ - int tmp = ntv->ifsrc->rx_rings_cnt / aconf->threads; - ntv->ring_from = ntv->thread_idx * tmp; - ntv->ring_to = ntv->ring_from + tmp - 1; - if (ntv->ring_to >= ntv->ifsrc->rx_rings_cnt) - ntv->ring_to = ntv->ifsrc->rx_rings_cnt - 1; + /* calculate thread rings binding */ + if (aconf->iface_sw) { + ntv->src_ring_from = ntv->src_ring_to = ntv->ifsrc->rings_cnt; + } else { + int tmp = (ntv->ifsrc->rx_rings_cnt + 1) / aconf->threads; + ntv->src_ring_from = ntv->thread_idx * tmp; + ntv->src_ring_to = ntv->src_ring_from + tmp - 1; + if (ntv->thread_idx == (aconf->threads - 1)) { + ntv->src_ring_to = ntv->ifsrc->rx_rings_cnt - 1; + } + } + SCLogDebug("netmap: %s thread:%d rings:%d-%d", aconf->iface_name, + ntv->thread_idx, ntv->src_ring_from, ntv->src_ring_to); if (aconf->copy_mode != NETMAP_COPY_MODE_NONE) { if (NetmapOpen(aconf->out_iface, 0, &ntv->ifdst, 1) != 0) { goto error_src; } - if (unlikely(!ntv->ifdst->tx_rings_cnt)) { + + if (unlikely(!aconf->out_iface_sw && !ntv->ifdst->tx_rings_cnt)) { SCLogError(SC_ERR_NETMAP_CREATE, "Output interface '%s' does not have Tx rings", - aconf->out_iface); + aconf->out_iface_name); goto error_dst; } + + /* calculate dst rings bindings */ + for (int i = ntv->src_ring_from; i <= ntv->src_ring_to; i++) { + NetmapRing *ring = &ntv->ifsrc->rings[i]; + if (aconf->out_iface_sw) { + ring->dst_ring_from = ring->dst_ring_to = ntv->ifdst->rings_cnt; + } else if (ntv->ifdst->tx_rings_cnt > ntv->ifsrc->rx_rings_cnt) { + int tmp = (ntv->ifdst->tx_rings_cnt + 1) / ntv->ifsrc->rx_rings_cnt; + ring->dst_ring_from = i * tmp; + ring->dst_ring_to = ring->dst_ring_from + tmp - 1; + if (i == (ntv->src_ring_to - 1)) { + ring->dst_ring_to = ntv->ifdst->tx_rings_cnt - 1; + } + } else { + ring->dst_ring_from = ring->dst_ring_to = + i % ntv->ifdst->tx_rings_cnt; + } + ring->dst_next_ring = ring->dst_ring_from; + + SCLogDebug("netmap: %s(%d)->%s(%d-%d)", + aconf->iface_name, i, aconf->out_iface_name, + ring->dst_ring_from, ring->dst_ring_to); + } } /* basic counters */ @@ -581,10 +633,10 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da if (likely(ntv->ifsrc->mem == ntv->ifdst->mem)) { ntv->flags |= NETMAP_FLAG_ZERO_COPY; SCLogInfo("Enabling zero copy mode for %s->%s", - aconf->iface, aconf->out_iface); + aconf->iface_name, aconf->out_iface_name); } else { SCLogInfo("Unable to set zero copy mode for %s->%s", - aconf->iface, aconf->out_iface); + aconf->iface_name, aconf->out_iface_name); } } @@ -640,8 +692,8 @@ static TmEcode NetmapWritePacket(NetmapThreadVars *ntv, Packet *p) } /* map src ring_id to dst ring_id */ - int dst_ring_id = p->netmap_v.ring_id % ntv->ifdst->tx_rings_cnt; - NetmapRing *txring = &ntv->ifdst->rings[dst_ring_id]; + NetmapRing *rxring = &ntv->ifsrc->rings[p->netmap_v.ring_id]; + NetmapRing *txring = &ntv->ifdst->rings[p->netmap_v.dst_ring_id]; SCSpinLock(&txring->tx_lock); @@ -654,7 +706,6 @@ static TmEcode NetmapWritePacket(NetmapThreadVars *ntv, Packet *p) struct netmap_slot *ts = &txring->tx->slot[txring->tx->cur]; if (ntv->flags & NETMAP_FLAG_ZERO_COPY) { - NetmapRing *rxring = &ntv->ifsrc->rings[p->netmap_v.ring_id]; struct netmap_slot *rs = &rxring->rx->slot[p->netmap_v.slot_id]; /* swap slot buffers */ @@ -710,19 +761,20 @@ static int NetmapRingRead(NetmapThreadVars *ntv, int ring_id) { SCEnter(); - struct netmap_ring *ring = ntv->ifsrc->rings[ring_id].rx; - uint32_t avail = nm_ring_space(ring); - uint32_t cur = ring->cur; + NetmapRing *ring = &ntv->ifsrc->rings[ring_id]; + struct netmap_ring *rx = ring->rx; + uint32_t avail = nm_ring_space(rx); + uint32_t cur = rx->cur; while (likely(avail-- > 0)) { - struct netmap_slot *slot = &ring->slot[cur]; - unsigned char *slot_data = (unsigned char *)NETMAP_BUF(ring, slot->buf_idx); + struct netmap_slot *slot = &rx->slot[cur]; + unsigned char *slot_data = (unsigned char *)NETMAP_BUF(rx, slot->buf_idx); if (ntv->bpf_prog.bf_len) { struct pcap_pkthdr pkthdr = { {0, 0}, slot->len, slot->len }; if (pcap_offline_filter(&ntv->bpf_prog, &pkthdr, slot_data) == 0) { /* rejected by bpf */ - cur = nm_ring_next(ring, cur); + cur = nm_ring_next(rx, cur); continue; } } @@ -735,7 +787,7 @@ static int NetmapRingRead(NetmapThreadVars *ntv, int ring_id) PKT_SET_SRC(p, PKT_SRC_WIRE); p->livedev = ntv->livedev; p->datalink = LINKTYPE_ETHERNET; - p->ts = ring->ts; + p->ts = rx->ts; ntv->pkts++; ntv->bytes += slot->len; @@ -768,8 +820,16 @@ static int NetmapRingRead(NetmapThreadVars *ntv, int ring_id) p->ReleasePacket = NetmapReleasePacket; p->netmap_v.ring_id = ring_id; p->netmap_v.slot_id = cur; + p->netmap_v.dst_ring_id = ring->dst_next_ring; p->netmap_v.ntv = ntv; + if (ring->dst_ring_from != ring->dst_ring_to) { + ring->dst_next_ring++; + if (ring->dst_next_ring == ring->dst_ring_to) { + ring->dst_next_ring = ring->dst_ring_from; + } + } + SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", GET_PKT_LEN(p), p, GET_PKT_DATA(p)); @@ -778,9 +838,9 @@ static int NetmapRingRead(NetmapThreadVars *ntv, int ring_id) SCReturnInt(NETMAP_FAILURE); } - cur = nm_ring_next(ring, cur); + cur = nm_ring_next(rx, cur); } - ring->head = ring->cur = cur; + rx->head = rx->cur = cur; SCReturnInt(NETMAP_OK); } @@ -795,7 +855,7 @@ static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) TmSlot *s = (TmSlot *)slot; NetmapThreadVars *ntv = (NetmapThreadVars *)data; struct pollfd *fds; - int rings_count = ntv->ring_to - ntv->ring_from + 1; + int rings_count = ntv->src_ring_to - ntv->src_ring_from + 1; ntv->slot = s->slot_next; @@ -806,7 +866,7 @@ static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) } for (int i = 0; i < rings_count; i++) { - fds[i].fd = ntv->ifsrc->rings[ntv->ring_from + i].fd; + fds[i].fd = ntv->ifsrc->rings[ntv->src_ring_from + i].fd; fds[i].events = POLLIN; } @@ -831,7 +891,7 @@ static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) } else if (r == 0) { /* no events, timeout */ SCLogDebug("(%s:%d-%d) Poll timeout", ntv->ifsrc->ifname, - ntv->ring_from, ntv->ring_to); + ntv->src_ring_from, ntv->src_ring_to); continue; } @@ -849,19 +909,22 @@ static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) } if (likely(fds[i].revents & POLLIN)) { - int src_ring_id = ntv->ring_from + i; + int src_ring_id = ntv->src_ring_from + i; NetmapRingRead(ntv, src_ring_id); if ((ntv->copy_mode != NETMAP_COPY_MODE_NONE) && (ntv->flags & NETMAP_FLAG_ZERO_COPY)) { + NetmapRing *src_ring = &ntv->ifsrc->rings[src_ring_id]; + /* sync dst tx rings */ - int dst_ring_id = src_ring_id % ntv->ifdst->tx_rings_cnt; - NetmapRing *dst_ring = &ntv->ifdst->rings[dst_ring_id]; - /* if locked, another loop already do sync */ - if (SCSpinTrylock(&dst_ring->tx_lock) == 0) { - ioctl(dst_ring->fd, NIOCTXSYNC, 0); - SCSpinUnlock(&dst_ring->tx_lock); + for (int j = src_ring->dst_ring_from; j <= src_ring->dst_ring_to; j++) { + NetmapRing *dst_ring = &ntv->ifdst->rings[j]; + /* if locked, another loop already do sync */ + if (SCSpinTrylock(&dst_ring->tx_lock) == 0) { + ioctl(dst_ring->fd, NIOCTXSYNC, 0); + SCSpinUnlock(&dst_ring->tx_lock); + } } } } diff --git a/src/source-netmap.h b/src/source-netmap.h index 42ed91feeff5..c52b50507929 100644 --- a/src/source-netmap.h +++ b/src/source-netmap.h @@ -37,13 +37,23 @@ enum { typedef struct NetmapIfaceConfig_ { + /* semantic interface name */ + char iface_name[NETMAP_IFACE_NAME_LENGTH]; + /* real inner interface name */ char iface[NETMAP_IFACE_NAME_LENGTH]; + /* sw ring flag for iface */ + int iface_sw; int threads; int promisc; int copy_mode; ChecksumValidationMode checksum_mode; char *bpf_filter; - char *out_iface; + /* semantic interface name */ + char *out_iface_name; + /* real inner interface name */ + char out_iface[NETMAP_IFACE_NAME_LENGTH]; + /* sw ring flag for out_iface */ + int out_iface_sw; SC_ATOMIC_DECLARE(unsigned int, ref); void (*DerefFunc)(void *); } NetmapIfaceConfig; @@ -52,6 +62,7 @@ typedef struct NetmapPacketVars_ { int ring_id; int slot_id; + int dst_ring_id; /* NetmapThreadVars */ void *ntv; } NetmapPacketVars; diff --git a/suricata.yaml.in b/suricata.yaml.in index 415afacc11d6..ecf7bcccc7e1 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -467,8 +467,19 @@ af-packet: #threads: auto #use-mmap: yes -# netmap support +# Netmap support +# +# Netmap operates with NIC directly in driver, so you need FreeBSD wich have +# built-in netmap support or compile and install netmap module and appropriate +# NIC driver on your Linux system. +# To reach maximum throughput disable all receive-, segmentation-, +# checksum- offloadings on NIC. +# Disabling Tx checksum offloading is *required* for connecting OS endpoint +# with NIC endpoint. +# You can find more information at https://github.com/luigirizzo/netmap +# netmap: + # To specify OS endpoint add plus sign at the end (e.g. "eth0+") - interface: eth2 # Number of receive threads. "auto" uses number of RSS queues on interface. threads: auto From 851fcef9627e11f62b9cd0fe78a1ec7775204093 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 19 Jun 2015 12:05:05 +0200 Subject: [PATCH 0631/2553] af-packet: sync header with latest features Sync the replacement define with the latest Linux code. This patch also updates the detection part in configure.ac to do a declaration of all fields if the newest features are not present. --- configure.ac | 4 ++-- src/source-af-packet.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index fb3c363a3cce..f796b06a281a 100644 --- a/configure.ac +++ b/configure.ac @@ -1054,8 +1054,8 @@ [enable_af_packet="no"], [[#include #include ]]) - AC_CHECK_DECL([PACKET_FANOUT], - AC_DEFINE([HAVE_PACKET_FANOUT],[1],[Packet fanout support is available]), + AC_CHECK_DECL([PACKET_FANOUT_QM], + AC_DEFINE([HAVE_PACKET_FANOUT],[1],[Recent packet fanout support is available]), [], [[#include ]]) ]) diff --git a/src/source-af-packet.h b/src/source-af-packet.h index e65a1f2a7a96..61f4e69ea0bc 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -32,6 +32,11 @@ #define PACKET_FANOUT_HASH 0 #define PACKET_FANOUT_LB 1 #define PACKET_FANOUT_CPU 2 +#define PACKET_FANOUT_ROLLOVER 3 +#define PACKET_FANOUT_RND 4 +#define PACKET_FANOUT_QM 5 + +#define PACKET_FANOUT_FLAG_ROLLOVER 0x1000 #define PACKET_FANOUT_FLAG_DEFRAG 0x8000 #else /* HAVE_PACKET_FANOUT */ #include From dc306f3bad0446d8fecca1f950b32a018a8e4903 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 19 Jun 2015 12:08:53 +0200 Subject: [PATCH 0632/2553] af-packet: implement new load balancing modes This patch implements the fanout load balancing modes available in kernel 4.0. The more interesting is cluster_qm that does the load balancing based on the RSS queues. So if the network card is doing a flow based load balancing then a given socket will receive all packets of a flow indepently of the CPU affinity. --- src/runmode-af-packet.c | 13 +++++++++++++ suricata.yaml.in | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 3a20cd09b3f0..cd2b5266b7ea 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -282,6 +282,19 @@ void *ParseAFPConfig(const char *iface) SCLogInfo("Using cpu cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_CPU; + } else if (strcmp(tmpctype, "cluster_qm") == 0) { + SCLogInfo("Using queue based cluster mode for AF_PACKET (iface %s)", + aconf->iface); + aconf->cluster_type = PACKET_FANOUT_QM; + } else if (strcmp(tmpctype, "cluster_random") == 0) { + SCLogInfo("Using random based cluster mode for AF_PACKET (iface %s)", + aconf->iface); + aconf->cluster_type = PACKET_FANOUT_RND; + } else if (strcmp(tmpctype, "cluster_rollover") == 0) { + SCLogInfo("Using rollover based cluster mode for AF_PACKET (iface %s)", + aconf->iface); + aconf->cluster_type = PACKET_FANOUT_ROLLOVER; + } else { SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); SCFree(aconf); diff --git a/suricata.yaml.in b/suricata.yaml.in index ecf7bcccc7e1..480521a42b69 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -416,6 +416,14 @@ af-packet: # * cluster_round_robin: round robin load balancing # * cluster_flow: all packets of a given flow are send to the same socket # * cluster_cpu: all packets treated in kernel by a CPU are send to the same socket + # * cluster_qm: all packets linked by network card to a RSS queue are sent to the same + # socket. Requires at least Linux 3.14. + # * cluster_random: packets are sent randomly to sockets but with an equipartition. + # Requires at least Linux 3.14. + # * cluster_rollover: kernel rotates between sockets filling each socket before moving + # to the next. Requires at least Linux 3.10. + # Recommended modes are cluster_flow on most boxes and cluster_cpu or cluster_qm on system + # with capture card using RSS (require cpu affinity tuning and system irq tuning) cluster-type: cluster_flow # In some fragmentation case, the hash can not be computed. If "defrag" is set # to yes, the kernel will do the needed defragmentation before sending the packets. From 8fde842f97161fe69013944800ebd68cb805384a Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 19 Jun 2015 12:13:31 +0200 Subject: [PATCH 0633/2553] af-packet: implement rollover option This patch implements the rollover option in af_packet capture. This should heavily minimize the packet drops as well as the maximum bandwidth treated for a single flow. The option has been deactivated by default but it is activated in the af_packet default section. This ensure there is no change for old users using an existing YAML. And new users will benefit from the change. This option is available since Linux 3.10. An analysis of af_packet kernel code shows that setting the flag in all cases should not cause any trouble for older kernel. --- src/runmode-af-packet.c | 8 ++++++++ suricata.yaml.in | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index cd2b5266b7ea..fc17a4bd6669 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -301,6 +301,14 @@ void *ParseAFPConfig(const char *iface) return NULL; } + int conf_val = 0; + ConfGetChildValueBoolWithDefault(if_root, if_default, "rollover", &conf_val); + if (conf_val) { + SCLogInfo("Using rollover kernel functionality for AF_PACKET (iface %s)", + aconf->iface); + aconf->cluster_type |= PACKET_FANOUT_FLAG_ROLLOVER; + } + /*load af_packet bpf filter*/ /* command line value has precedence */ if (ConfGet("bpf-filter", &bpf_filter) != 1) { diff --git a/suricata.yaml.in b/suricata.yaml.in index 480521a42b69..da1ee3a9cc1b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -428,6 +428,10 @@ af-packet: # In some fragmentation case, the hash can not be computed. If "defrag" is set # to yes, the kernel will do the needed defragmentation before sending the packets. defrag: yes + # After Linux kernel 3.10 it is possible to activate the rollover option: if a socket is + # full then kernel will send the packet on the next socket with room available. This option + # can minimize packet drop and increase the treated bandwith on single intensive flow. + #rollover: yes # To use the ring feature of AF_PACKET, set 'use-mmap' to yes use-mmap: yes # Ring size will be computed with respect to max_pending_packets and number @@ -474,6 +478,7 @@ af-packet: - interface: default #threads: auto #use-mmap: yes + rollover: yes # Netmap support # From 1cd97713c2945a1e55ea6e3b8df804ab3f06fca4 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 27 May 2015 14:01:36 +0200 Subject: [PATCH 0634/2553] file-json: add file_id to message This will allow to get the filename and by consequence the file after a parsing of the EVEV log file. --- src/output-json-file.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/output-json-file.c b/src/output-json-file.c index 5464088f1650..cbfa0c4d0b6c 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -242,6 +242,9 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F } json_object_set_new(fjs, "stored", (ff->flags & FILE_STORED) ? json_true() : json_false()); + if (ff->flags & FILE_STORED) { + json_object_set_new(fjs, "file_id", json_integer(ff->file_id)); + } json_object_set_new(fjs, "size", json_integer(ff->size)); json_object_set_new(fjs, "tx_id", json_integer(ff->txid)); From baadcab1b8b5c11528b78355fa8960e13af743e3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Jul 2015 11:21:44 +0200 Subject: [PATCH 0635/2553] detect: default to u32 for SigIntId --- src/suricata-common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/suricata-common.h b/src/suricata-common.h index 98545fd80397..388f1a429cd3 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -226,8 +226,8 @@ * extensively keeping this as small as possible reduces the overall memory * footprint of the engine. Set to uint32_t if the engine needs to support * more than 64k sigs. */ -#define SigIntId uint16_t -//#define SigIntId uint32_t +//#define SigIntId uint16_t +#define SigIntId uint32_t /** same for pattern id's */ #define PatIntId uint16_t From a0899cbe85a5aa33863891f345feebcf7e37b0ac Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Jul 2015 11:22:04 +0200 Subject: [PATCH 0636/2553] detect: optimize Signature layout --- src/detect.h | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/detect.h b/src/detect.h index d8d884751a93..223b6d31a47f 100644 --- a/src/detect.h +++ b/src/detect.h @@ -384,40 +384,44 @@ typedef struct Signature_ { uint8_t action; uint8_t file_flags; + /** addresses, ports and proto this sig matches on */ + DetectProto proto; + + /** classification id **/ + uint8_t class; + /** 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; - uint16_t addr_dst_match6_cnt; - uint16_t addr_src_match6_cnt; 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; - /** addresses, ports and proto this sig matches on */ - DetectProto proto; - - /** classification id **/ - uint8_t class; - #ifdef PROFILING uint16_t profiling_id; #endif + /** number of sigmatches in the match and pmatch list */ + uint16_t sm_cnt; - uint32_t gid; /**< generator id */ + /* used to hold flags that are predominantly used during init */ + uint32_t init_flags; + /* coccinelle: Signature:init_flags:SIG_FLAG_INIT_ */ /** netblocks and hosts specified at the sid, in CIDR format */ IPOnlyCIDRItem *CidrSrc, *CidrDst; - uint32_t rev; - - int prio; - /* Hold copies of the sm lists for Match() */ SigMatchData *sm_arrays[DETECT_SM_LIST_MAX]; @@ -438,12 +442,6 @@ typedef struct Signature_ { /** 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 */ @@ -452,12 +450,12 @@ typedef struct Signature_ { uint16_t mpm_content_maxlen; uint16_t mpm_uricontent_maxlen; + int list; + /* 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; From be2849044b164d49a6f009a3b39d1370916c1bbc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Jul 2015 12:49:38 +0200 Subject: [PATCH 0637/2553] flow/stream: xfer noinspect flags to pseudo pkts Set noinspection flags for payloads and packets on flow and stream pseudo packets. Without these, the pseudo packets could trigger inspection even though this was disabled for a flow. --- src/flow-timeout.c | 8 ++++++++ src/stream-tcp.c | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/flow-timeout.c b/src/flow-timeout.c index b18007939e3b..534875c68b28 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -87,6 +87,14 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, p->flags |= PKT_STREAM_EOF; p->flags |= PKT_HAS_FLOW; p->flags |= PKT_PSEUDO_STREAM_END; + + if (f->flags & FLOW_NOPACKET_INSPECTION) { + DecodeSetNoPacketInspectionFlag(p); + } + if (f->flags & FLOW_NOPAYLOAD_INSPECTION) { + DecodeSetNoPayloadInspectionFlag(p); + } + if (direction == 0) p->flowflags |= FLOW_PKT_TOSERVER; else diff --git a/src/stream-tcp.c b/src/stream-tcp.c index c810ea75c0a1..88fe40d4bed5 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5836,6 +5836,13 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread np->flags |= PKT_HAS_FLOW; np->flags |= PKT_PSEUDO_STREAM_END; + if (p->flags & PKT_NOPACKET_INSPECTION) { + DecodeSetNoPacketInspectionFlag(np); + } + if (p->flags & PKT_NOPAYLOAD_INSPECTION) { + DecodeSetNoPayloadInspectionFlag(np); + } + if (PKT_IS_TOSERVER(p)) { SCLogDebug("original is to_server, so pseudo is to_client"); np->flowflags &= ~FLOW_PKT_TOSERVER; From 11d3f5f67aa9c4c70d71c8cc035f716d05dc0248 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 14 Jul 2015 20:09:36 +0200 Subject: [PATCH 0638/2553] http: harden tx inspection code --- src/detect-engine-hcbd.c | 13 ++++++++----- src/detect-engine-hhd.c | 10 ++++++---- src/detect-engine-hsbd.c | 13 ++++++++----- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 2de2a54ebdbd..aed137985ef0 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -62,8 +62,11 @@ #define BUFFER_STEP 50 -static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) +static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) { + if (size >= USHRT_MAX) + return -1; + void *ptmp; if (size > det_ctx->hcbd_buffers_size) { ptmp = SCRealloc(det_ctx->hcbd, @@ -80,7 +83,8 @@ static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) memset(det_ctx->hcbd + det_ctx->hcbd_buffers_size, 0, BUFFER_STEP * sizeof(HttpReassembledBody)); det_ctx->hcbd_buffers_size += BUFFER_STEP; - for (int i = det_ctx->hcbd_buffers_list_len; i < (size); i++) { + uint16_t i; + for (i = det_ctx->hcbd_buffers_list_len; i < ((uint16_t)size); i++) { det_ctx->hcbd[i].buffer_len = 0; det_ctx->hcbd[i].offset = 0; } @@ -109,8 +113,7 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); BUG_ON(base_inspect_id > tx_id); /* see how many space we need for the current tx_id */ - uint16_t txs = (tx_id - base_inspect_id) + 1; - + uint64_t txs = (tx_id - base_inspect_id) + 1; if (HCBDCreateSpace(det_ctx, txs) < 0) goto end; @@ -125,7 +128,7 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer; } } else { - uint16_t txs = (tx_id - det_ctx->hcbd_start_tx_id) + 1; + uint64_t txs = (tx_id - det_ctx->hcbd_start_tx_id) + 1; if (HCBDCreateSpace(det_ctx, txs) < 0) goto end; /* let's consider it as stage not done for now */ diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index dce39d3dccbc..82c5b9ce35d6 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -60,8 +60,11 @@ #define BUFFER_STEP 50 -static inline int HHDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) +static inline int HHDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) { + if (size >= USHRT_MAX) + return -1; + void *ptmp; if (size > det_ctx->hhd_buffers_size) { ptmp = SCRealloc(det_ctx->hhd_buffers, @@ -111,8 +114,7 @@ static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); BUG_ON(base_inspect_id > tx_id); /* see how many space we need for the current tx_id */ - uint16_t txs = (tx_id - base_inspect_id) + 1; - + uint64_t txs = (tx_id - base_inspect_id) + 1; if (HHDCreateSpace(det_ctx, txs) < 0) goto end; @@ -130,7 +132,7 @@ static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, /* otherwise fall through */ } else { /* not enough space, lets expand */ - uint16_t txs = (tx_id - det_ctx->hhd_start_tx_id) + 1; + uint64_t txs = (tx_id - det_ctx->hhd_start_tx_id) + 1; if (HHDCreateSpace(det_ctx, txs) < 0) goto end; diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 93440a198d72..9fad1a3af1b7 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -64,8 +64,11 @@ #define BUFFER_STEP 50 -static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) +static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) { + if (size >= USHRT_MAX) + return -1; + void *ptmp; if (size > det_ctx->hsbd_buffers_size) { ptmp = SCRealloc(det_ctx->hsbd, @@ -82,7 +85,8 @@ static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) memset(det_ctx->hsbd + det_ctx->hsbd_buffers_size, 0, BUFFER_STEP * sizeof(HttpReassembledBody)); det_ctx->hsbd_buffers_size += BUFFER_STEP; } - for (int i = det_ctx->hsbd_buffers_list_len; i < (size); i++) { + uint16_t i; + for (i = det_ctx->hsbd_buffers_list_len; i < ((uint16_t)size); i++) { det_ctx->hsbd[i].buffer_len = 0; det_ctx->hsbd[i].offset = 0; } @@ -235,8 +239,7 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); BUG_ON(base_inspect_id > tx_id); /* see how many space we need for the current tx_id */ - uint16_t txs = (tx_id - base_inspect_id) + 1; - + uint64_t txs = (tx_id - base_inspect_id) + 1; if (HSBDCreateSpace(det_ctx, txs) < 0) goto end; index = (tx_id - base_inspect_id); @@ -250,7 +253,7 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer; } } else { - uint16_t txs = (tx_id - det_ctx->hsbd_start_tx_id) + 1; + uint64_t txs = (tx_id - det_ctx->hsbd_start_tx_id) + 1; if (HSBDCreateSpace(det_ctx, txs) < 0) goto end; From 62fa9f09d4fe021cdd6b437ac8f3f26e7620043c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 15 Jul 2015 09:53:39 +0200 Subject: [PATCH 0639/2553] Sync alversion/appversion types The app layer state 'version' field is incremented with each update to the state. It is used by the detection engine to see if the current version of the state has already been inspected. Since app layer and detect always run closely together there is no need for a big number here. The detect code really only checks for equal/not-equal, so wrap arounds are not an issue. --- src/app-layer-parser.c | 8 ++++---- src/detect-engine-state.c | 13 +++++++------ src/detect-engine-state.h | 6 +++--- src/detect.c | 2 +- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 2c4d2f8b2c67..c79e6142bb8c 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -128,7 +128,7 @@ struct AppLayerParserState_ { uint8_t flags; /* State version, incremented for each update. Can wrap around. */ - uint16_t version; + uint8_t version; /* Indicates the current transaction that is being inspected. * We have a var per direction. */ uint64_t inspect_id[2]; @@ -606,7 +606,7 @@ AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alp uint16_t AppLayerParserGetStateVersion(AppLayerParserState *pstate) { SCEnter(); - SCReturnCT((pstate == NULL) ? 0 : pstate->version, "uint16_t"); + SCReturnCT((pstate == NULL) ? 0 : pstate->version, "uint8_t"); } FileContainer *AppLayerParserGetFiles(uint8_t ipproto, AppProto alproto, @@ -871,7 +871,7 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp goto error; } pstate->version++; - SCLogDebug("app layer parser state version incremented to %"PRIu16, + SCLogDebug("app layer parser state version incremented to %"PRIu8, pstate->version); if (flags & STREAM_EOF) @@ -1166,7 +1166,7 @@ void AppLayerParserStatePrintDetails(AppLayerParserState *pstate) "p->inspect_id[0](%"PRIu64"), " "p->inspect_id[1](%"PRIu64"), " "p->log_id(%"PRIu64"), " - "p->version(%"PRIu16"), " + "p->version(%"PRIu8"), " "p->decoder_events(%p).", pstate, p->inspect_id[0], p->inspect_id[1], p->log_id, p->version, p->decoder_events); diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index ca6cf3abec17..8d5baca8bd31 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -243,7 +243,7 @@ static void DeStateFlowRuleAppend(DetectEngineStateFlow *state, Signature *s, } static void DeStateStoreStateVersion(Flow *f, - uint16_t alversion, uint8_t direction) + const uint8_t alversion, uint8_t direction) { f->detect_alversion[direction & STREAM_TOSERVER ? 0 : 1] = alversion; } @@ -373,7 +373,8 @@ static int HasStoredSigs(Flow *f, uint8_t flags) * \retval 1 inspectable state * \retval 2 inspectable state, but no update */ -int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion, uint8_t flags) +int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, + const uint8_t alversion, uint8_t flags) { int r = 0; @@ -394,7 +395,7 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion } static int StoreState(DetectEngineThreadCtx *det_ctx, - Flow *f, const uint8_t flags, const uint16_t alversion, + Flow *f, const uint8_t flags, const uint8_t alversion, Signature *s, SigMatch *sm, const uint32_t inspect_flags, const uint16_t file_no_match) { @@ -445,7 +446,7 @@ static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx, * \param check_before_add check for duplicates before adding the sig */ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, - Flow *f, const uint8_t flags, const uint16_t alversion, + Flow *f, const uint8_t flags, const uint8_t alversion, const uint64_t tx_id, void *tx, Signature *s, SigMatch *sm, const uint32_t inspect_flags, const uint16_t file_no_match, int check_before_add) @@ -475,7 +476,7 @@ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, uint16_t alversion) + AppProto alproto, const uint8_t alversion) { SigMatch *sm = NULL; uint16_t file_no_match = 0; @@ -978,7 +979,7 @@ static int DoInspectFlowRule(ThreadVars *tv, void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, uint16_t alversion) + AppProto alproto, const uint8_t alversion) { uint16_t file_no_match = 0; SigIntId store_cnt = 0; diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 4c88ae794a04..8efb9445a0df 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -178,7 +178,7 @@ void DetectEngineStateFlowFree(DetectEngineStateFlow *state); * \retval 1 Has state. * \retval 0 Has no state. */ -int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion, uint8_t flags); +int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint8_t alversion, uint8_t flags); /** * \brief Match app layer sig list against app state and store relevant match @@ -198,7 +198,7 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, uint16_t alversion); + AppProto alproto, uint8_t alversion); /** * \brief Continue DeState detection of the signatures stored in the state. @@ -214,7 +214,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, uint16_t alversion); + AppProto alproto, uint8_t alversion); /** * \brief Update the inspect id. diff --git a/src/detect.c b/src/detect.c index 04fb11f17d3a..2b8c0da3d979 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1236,7 +1236,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh StreamMsg *smsg = NULL; Signature *s = NULL; Signature *next_s = NULL; - uint16_t alversion = 0; + uint8_t alversion = 0; int state_alert = 0; int alerts = 0; int app_decoder_events = 0; From b0f5f7ee97d1d14923bb62c68e81172f56d0dc5b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 15 Jul 2015 13:08:22 +0200 Subject: [PATCH 0640/2553] app-layer: fix args to state progress calls --- src/output-streaming.c | 12 ++++++++---- src/output-tx.c | 16 ++++++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/output-streaming.c b/src/output-streaming.c index 35e40d0c6244..bc2a7d4be03d 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -147,9 +147,11 @@ int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) HtpState *s = f->alstate; if (s != NULL && s->conn != NULL) { int tx_progress_done_value_ts = - AppLayerParserGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_HTTP, 0); + AppLayerParserGetStateProgressCompletionStatus(IPPROTO_TCP, + ALPROTO_HTTP, STREAM_TOSERVER); int tx_progress_done_value_tc = - AppLayerParserGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_HTTP, 1); + AppLayerParserGetStateProgressCompletionStatus(IPPROTO_TCP, + ALPROTO_HTTP, STREAM_TOCLIENT); // for each tx uint64_t tx_id = 0; @@ -161,9 +163,11 @@ int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) int tx_done = 0; int tx_logged = 0; - int tx_progress_ts = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, 0); + int tx_progress_ts = AppLayerParserGetStateProgress( + IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER); if (tx_progress_ts >= tx_progress_done_value_ts) { - int tx_progress_tc = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, 1); + int tx_progress_tc = AppLayerParserGetStateProgress( + IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT); if (tx_progress_tc >= tx_progress_done_value_tc) { tx_done = 1; } diff --git a/src/output-tx.c b/src/output-tx.c index 9bb7c277db6b..aa48d9e121c6 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -104,14 +104,14 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ Flow * const f = p->flow; FLOWLOCK_WRLOCK(f); /* WRITE lock before we updated flow logged id */ - AppProto alproto = f->alproto;//AppLayerGetProtoFromPacket(p); + AppProto alproto = f->alproto; if (AppLayerParserProtocolIsTxAware(p->proto, alproto) == 0) goto end; if (AppLayerParserProtocolHasLogger(p->proto, alproto) == 0) goto end; - void *alstate = f->alstate;//AppLayerGetProtoStateFromPacket((const Packet *)p); + void *alstate = f->alstate; if (alstate == NULL) { SCLogDebug("no alstate"); goto end; @@ -120,9 +120,11 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ uint64_t total_txs = AppLayerParserGetTxCnt(p->proto, alproto, alstate); uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); int tx_progress_done_value_ts = - AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto, 0); + AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto, + STREAM_TOSERVER); int tx_progress_done_value_tc = - AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto, 1); + AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto, + STREAM_TOCLIENT); int proto_logged = 0; for (; tx_id < total_txs; tx_id++) @@ -135,13 +137,15 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ if (!(AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_EOF))) { - int tx_progress = AppLayerParserGetStateProgress(p->proto, alproto, tx, 0); + int tx_progress = AppLayerParserGetStateProgress(p->proto, alproto, + tx, STREAM_TOSERVER); if (tx_progress < tx_progress_done_value_ts) { SCLogDebug("progress not far enough, not logging"); break; } - tx_progress = AppLayerParserGetStateProgress(p->proto, alproto, tx, 1); + tx_progress = AppLayerParserGetStateProgress(p->proto, alproto, + tx, STREAM_TOCLIENT); if (tx_progress < tx_progress_done_value_tc) { SCLogDebug("progress not far enough, not logging"); break; From c419f33f441882ba5c080337667db5591df9eb2c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 15 Jul 2015 13:58:12 +0200 Subject: [PATCH 0641/2553] dns: fix state progress handling --- src/app-layer-dns-common.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index a11daa1eb026..852353f55b0b 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -223,8 +223,8 @@ uint64_t DNSGetTxCnt(void *alstate) int DNSGetAlstateProgress(void *tx, uint8_t direction) { DNSTransaction *dns_tx = (DNSTransaction *)tx; - if (direction == 1) - return dns_tx->replied|dns_tx->reply_lost; + if (direction & STREAM_TOCLIENT) + return (dns_tx->replied|dns_tx->reply_lost) ? 2 : 1; else { /* toserver/query is complete if we have stored a query */ return (TAILQ_FIRST(&dns_tx->query_list) != NULL); @@ -237,7 +237,10 @@ int DNSGetAlstateProgress(void *tx, uint8_t direction) */ int DNSGetAlstateProgressCompletionStatus(uint8_t direction) { - return 1; + if (direction & STREAM_TOCLIENT) + return 2; + else + return 1; } void DNSSetEvent(DNSState *s, uint8_t e) From 6e2c90a83b745d3b61c581be87fc1bb445330301 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Jul 2015 15:35:01 +0200 Subject: [PATCH 0642/2553] detect: constify some DetectMpmPrefilter args --- src/detect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/detect.c b/src/detect.c index 2b8c0da3d979..b793b42a3565 100644 --- a/src/detect.c +++ b/src/detect.c @@ -868,7 +868,8 @@ static void QuickSortSigIntId(SigIntId *sids, uint32_t n) */ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg, Packet *p, - uint8_t flags, AppProto alproto, int has_state, uint8_t *sms_runflags) + const uint8_t flags, const AppProto alproto, + const int has_state, uint8_t *sms_runflags) { /* have a look at the reassembled stream (if any) */ if (p->flowflags & FLOW_PKT_ESTABLISHED) { From 8125e04b39243ca75dd2a7ac8f51f5c7e0c8bd8d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Jul 2015 15:35:19 +0200 Subject: [PATCH 0643/2553] detect: clean up flag usage --- src/detect.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/detect.c b/src/detect.c index b793b42a3565..77de1714adad 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1233,7 +1233,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh #ifdef PROFILING int smatch = 0; /* signature match: 1, no match: 0 */ #endif - uint8_t flags = 0; /* flow/state flags */ + uint8_t flow_flags = 0; /* flow/state flags */ StreamMsg *smsg = NULL; Signature *s = NULL; Signature *next_s = NULL; @@ -1262,8 +1262,17 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* grab the protocol state we will detect on */ if (p->flags & PKT_HAS_FLOW) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + flow_flags = STREAM_TOSERVER; + SCLogDebug("flag STREAM_TOSERVER set"); + } else if (p->flowflags & FLOW_PKT_TOCLIENT) { + flow_flags = STREAM_TOCLIENT; + SCLogDebug("flag STREAM_TOCLIENT set"); + } + SCLogDebug("p->flowflags 0x%02x", p->flowflags); + if (p->flags & PKT_STREAM_EOF) { - flags |= STREAM_EOF; + flow_flags |= STREAM_EOF; SCLogDebug("STREAM_EOF set"); } @@ -1308,7 +1317,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_GETSGH); - smsg = SigMatchSignaturesGetSmsg(pflow, p, flags); + smsg = SigMatchSignaturesGetSmsg(pflow, p, flow_flags); #if 0 StreamMsg *tmpsmsg = smsg; while (tmpsmsg) { @@ -1338,19 +1347,10 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh pflow->alproto, pflow->alstate, pflow->alparser, - flags); + flow_flags); } FLOWLOCK_UNLOCK(pflow); - if (p->flowflags & FLOW_PKT_TOSERVER) { - flags |= STREAM_TOSERVER; - SCLogDebug("flag STREAM_TOSERVER set"); - } else if (p->flowflags & FLOW_PKT_TOCLIENT) { - flags |= STREAM_TOCLIENT; - SCLogDebug("flag STREAM_TOCLIENT set"); - } - SCLogDebug("p->flowflags 0x%02x", p->flowflags); - if (((p->flowflags & FLOW_PKT_TOSERVER) && !(p->flowflags & FLOW_PKT_TOSERVER_IPONLY_SET)) || ((p->flowflags & FLOW_PKT_TOCLIENT) && !(p->flowflags & FLOW_PKT_TOCLIENT_IPONLY_SET))) { @@ -1417,11 +1417,11 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* stateful app layer detection */ if ((p->flags & PKT_HAS_FLOW) && has_state) { memset(det_ctx->de_state_sig_array, 0x00, det_ctx->de_state_sig_array_len); - int has_inspectable_state = DeStateFlowHasInspectableState(pflow, alproto, alversion, flags); + int has_inspectable_state = DeStateFlowHasInspectableState(pflow, alproto, alversion, flow_flags); if (has_inspectable_state == 1) { /* initialize to 0(DE_STATE_MATCH_HAS_NEW_STATE) */ DeStateDetectContinueDetection(th_v, de_ctx, det_ctx, p, pflow, - flags, alproto, alversion); + flow_flags, alproto, alversion); } else if (has_inspectable_state == 2) { /* no inspectable state, so pretend we don't have a state at all */ has_state = 0; @@ -1443,7 +1443,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* run the mpm for each type */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM); - DetectMpmPrefilter(de_ctx, det_ctx, smsg, p, flags, alproto, has_state, &sms_runflags); + DetectMpmPrefilter(de_ctx, det_ctx, smsg, p, flow_flags, alproto, has_state, &sms_runflags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); #ifdef PROFILING if (th_v) { @@ -1744,7 +1744,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh * can store the tx_id with the alert */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); state_alert = DeStateDetectStartDetection(th_v, de_ctx, det_ctx, s, - p, pflow, flags, alproto, alversion); + p, pflow, flow_flags, alproto, alversion); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); if (state_alert == 0) goto next; @@ -1789,7 +1789,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* see if we need to increment the inspect_id and reset the de_state */ if (has_state && AppLayerParserProtocolSupportsTxs(p->proto, alproto)) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); - DeStateUpdateInspectTransactionId(pflow, flags); + DeStateUpdateInspectTransactionId(pflow, flow_flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); } From ea571add738d73e1e8bbe6c4206c7d24813ad237 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Jul 2015 16:43:19 +0200 Subject: [PATCH 0644/2553] app-layer: disruption flags Stream GAPs and stream reassembly depth are tracked per direction. In many cases they will happen in one direction, but not in the other. Example: HTTP requests a generally smaller than responses. So on the response side we may hit the depth limit, but not on the request side. The asynchronious 'disruption' has a side effect in the transaction engine. The 'progress' tracking would never mark such transactions as complete, and thus some inspection and logging wouldn't happen until the very last moment: when EOF's are passed around. Especially in proxy environments with _very_ many transactions in a single TCP connection, this could lead to serious resource issues. The EOF handling would suddenly have to handle thousands or more transactions. These transactions would have been stored for a long time. This patch introduces the concept of disruption flags. Flags passed to the tx progress logic that are and indication of disruptions in the traffic or the traffic handling. The idea is that the progress is marked as complete on disruption, even if a tx is not complete. This allows the detection and logging engines to process the tx after which it can be cleaned up. --- src/app-layer-parser.c | 19 ++++++++++++++++--- src/detect-engine-hcbd.c | 4 ++-- src/detect-engine-hcd.c | 4 ++-- src/detect-engine-hhd.c | 8 ++++---- src/detect-engine-hhhd.c | 2 +- src/detect-engine-hmd.c | 2 +- src/detect-engine-hrhd.c | 12 ++++++------ src/detect-engine-hrhhd.c | 2 +- src/detect-engine-hrl.c | 2 +- src/detect-engine-hrud.c | 2 +- src/detect-engine-hsbd.c | 6 +++--- src/detect-engine-hscd.c | 2 +- src/detect-engine-hsmd.c | 2 +- src/detect-engine-hua.c | 2 +- src/detect-engine-uri.c | 2 +- src/detect.c | 2 ++ src/flow.c | 31 +++++++++++++++++++++++++++++++ src/flow.h | 1 + 18 files changed, 76 insertions(+), 29 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index c79e6142bb8c..c97929f70004 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -725,13 +725,26 @@ static void AppLayerParserTransactionsCleanup(Flow *f) } } +#define IS_DISRUPTED(flags) \ + ((flags) & (STREAM_DEPTH|STREAM_GAP)) + +/** + * \brief get the progress value for a tx/protocol + * + * If the stream is disrupted, we return the 'completion' value. + */ int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, - void *alstate, uint8_t direction) + void *alstate, uint8_t flags) { SCEnter(); int r = 0; - r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetProgress(alstate, direction); + if (unlikely(IS_DISRUPTED(flags))) { + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateGetProgressCompletionStatus(flags); + } else { + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateGetProgress(alstate, flags); + } SCReturnInt(r); } diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index aed137985ef0..a1e47e6be439 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -160,7 +160,7 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, if ((htp_state->cfg->request_body_limit == 0 || htud->request_body.content_len_so_far < htp_state->cfg->request_body_limit) && htud->request_body.content_len_so_far < htp_state->cfg->request_inspect_min_size && - !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_BODY) && + !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY) && !(flags & STREAM_EOF)) { SCLogDebug("we still haven't seen the entire request body. " "Let's defer body inspection till we see the " @@ -274,7 +274,7 @@ int DetectEngineInspectHttpClientBody(ThreadVars *tv, end: - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_BODY) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index 513507e4e111..5fcfa51fd368 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -142,10 +142,10 @@ int DetectEngineInspectHttpCookie(ThreadVars *tv, end: if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 82c5b9ce35d6..baf5cf667201 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -143,11 +143,11 @@ static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, htp_table_t *headers; if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) <= HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_REQUEST_HEADERS) goto end; headers = tx->request_headers; } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) <= HTP_RESPONSE_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_RESPONSE_HEADERS) goto end; headers = tx->response_headers; } @@ -263,10 +263,10 @@ int DetectEngineInspectHttpHeader(ThreadVars *tv, end: if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 77a9791d8314..65aebd070acd 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -118,7 +118,7 @@ int DetectEngineInspectHttpHH(ThreadVars *tv, return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index c33cfd967d55..5a4b7d8ad149 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -96,7 +96,7 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv, { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->request_method == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index b6b86a3772f9..90cf1d5e907d 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -71,7 +71,7 @@ int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, SCReturnInt(cnt); if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) <= HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_REQUEST_HEADERS) SCReturnInt(cnt); if (tx_ud->request_headers_raw != NULL) { @@ -81,7 +81,7 @@ int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, flags); } } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOCLIENT) <= HTP_RESPONSE_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_RESPONSE_HEADERS) SCReturnInt(cnt); if (tx_ud->response_headers_raw != NULL) { @@ -120,10 +120,10 @@ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, uint32_t headers_raw_len = 0; if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) <= HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOCLIENT) <= HTP_RESPONSE_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_RESPONSE_HEADERS) return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } @@ -154,10 +154,10 @@ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, end: if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOCLIENT) > HTP_RESPONSE_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_RESPONSE_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index 273c8b6d6a8b..f1acf100189b 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -145,7 +145,7 @@ int DetectEngineInspectHttpHRH(ThreadVars *tv, return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hrl.c b/src/detect-engine-hrl.c index af1b93f316ae..5e5c0cb6214a 100644 --- a/src/detect-engine-hrl.c +++ b/src/detect-engine-hrl.c @@ -72,7 +72,7 @@ int DetectEngineInspectHttpRequestLine(ThreadVars *tv, htp_tx_t *tx = (htp_tx_t *)txv; if (tx->request_line == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) > HTP_REQUEST_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 343054b9ad8e..c715c0292683 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -102,7 +102,7 @@ int DetectEngineInspectHttpRawUri(ThreadVars *tv, { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->request_uri == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 9fad1a3af1b7..a6319db67f98 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -286,7 +286,7 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, htud->response_body.content_len_so_far, htp_state->cfg->response_inspect_min_size, flags & STREAM_EOF ? "true" : "false", - (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) ? "true" : "false"); + (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY) ? "true" : "false"); if (!htp_state->cfg->http_body_inline) { /* inspect the body if the transfer is complete or we have hit @@ -294,7 +294,7 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, if ((htp_state->cfg->response_body_limit == 0 || htud->response_body.content_len_so_far < htp_state->cfg->response_body_limit) && htud->response_body.content_len_so_far < htp_state->cfg->response_inspect_min_size && - !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) && + !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY) && !(flags & STREAM_EOF)) { SCLogDebug("we still haven't seen the entire response body. " "Let's defer body inspection till we see the " @@ -368,7 +368,7 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv, return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index aa9f6f7dcce9..a38562b1932b 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -100,7 +100,7 @@ int DetectEngineInspectHttpStatCode(ThreadVars *tv, { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->response_status == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 2c5176022a13..61c8e2e9b5f3 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -100,7 +100,7 @@ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->response_message == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index d1bd0c2ff1ee..8cafa423af3a 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -122,7 +122,7 @@ int DetectEngineInspectHttpUA(ThreadVars *tv, return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index e0df1e0b9e9d..cd737157843f 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -73,7 +73,7 @@ int DetectEngineInspectPacketUris(ThreadVars *tv, HtpTxUserData *tx_ud = htp_tx_get_user_data(txv); if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) > HTP_REQUEST_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect.c b/src/detect.c index 77de1714adad..868e3ed736d9 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1335,6 +1335,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh (p->proto == IPPROTO_UDP) || (p->proto == IPPROTO_SCTP && (p->flowflags & FLOW_PKT_ESTABLISHED))) { + /* update flow flags with knowledge on disruptions */ + flow_flags = FlowGetDisruptionFlags(pflow, flow_flags); has_state = (FlowGetAppState(pflow) != NULL); alproto = FlowGetAppProtocol(pflow); alversion = AppLayerParserGetStateVersion(pflow->alparser); diff --git a/src/flow.c b/src/flow.c index 4e9b6848069f..42099c3ad5e9 100644 --- a/src/flow.c +++ b/src/flow.c @@ -870,6 +870,37 @@ void *FlowGetAppState(const Flow *f) return f->alstate; } +/** + * \brief get 'disruption' flags: GAP/DEPTH/PASS + * \param f locked flow + * \param flags existing flags to be ammended + * \retval flags original flags + disrupt flags (if any) + * \TODO handle UDP + */ +uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags) +{ + if (f->proto != IPPROTO_TCP) { + return flags; + } + if (f->protoctx == NULL) { + return flags; + } + + uint8_t newflags = flags; + TcpSession *ssn = f->protoctx; + TcpStream *stream = flags & STREAM_TOSERVER ? &ssn->client : &ssn->server; + + if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { + newflags |= STREAM_DEPTH; + } + if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) { + newflags |= STREAM_GAP; + } + /* todo: handle pass case (also for UDP!) */ + + return newflags; +} + /************************************Unittests*******************************/ #ifdef UNITTESTS diff --git a/src/flow.h b/src/flow.h index bc1f65ac882d..caa34c6fc811 100644 --- a/src/flow.h +++ b/src/flow.h @@ -568,6 +568,7 @@ int FlowClearMemory(Flow *,uint8_t ); AppProto FlowGetAppProtocol(const Flow *f); void *FlowGetAppState(const Flow *f); +uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags); void FlowHandlePacketUpdateRemove(Flow *f, Packet *p); void FlowHandlePacketUpdate(Flow *f, Packet *p); From 00ef789ffcae70ac2f6ff199ede53340385eeafb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Jul 2015 13:09:37 +0200 Subject: [PATCH 0645/2553] app-layer: pass full flags around in tx handling --- src/app-layer-parser.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index c97929f70004..0e2fdfb474ef 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -660,10 +660,9 @@ uint64_t AppLayerTransactionGetActiveLogOnly(Flow *f, uint8_t flags) } /* logger is disabled, return highest 'complete' tx id */ - uint8_t direction = flags & (STREAM_TOSERVER|STREAM_TOCLIENT); uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, f->alproto, f->alstate); - uint64_t idx = AppLayerParserGetTransactionInspectId(f->alparser, direction); - int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(f->proto, f->alproto, direction); + uint64_t idx = AppLayerParserGetTransactionInspectId(f->alparser, flags); + int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(f->proto, f->alproto, flags); void *tx; int state_progress; @@ -671,7 +670,7 @@ uint64_t AppLayerTransactionGetActiveLogOnly(Flow *f, uint8_t flags) tx = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, idx); if (tx == NULL) continue; - state_progress = AppLayerParserGetStateProgress(f->proto, f->alproto, tx, direction); + state_progress = AppLayerParserGetStateProgress(f->proto, f->alproto, tx, flags); if (state_progress >= state_done_progress) continue; else From c087708fa999c18ffbf486366db6386996fed438 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Jul 2015 13:10:15 +0200 Subject: [PATCH 0646/2553] output-tx: use disrupt flags --- src/output-streaming.c | 4 ++-- src/output-tx.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/output-streaming.c b/src/output-streaming.c index bc2a7d4be03d..d416cbc3c6c4 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -164,10 +164,10 @@ int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) int tx_logged = 0; int tx_progress_ts = AppLayerParserGetStateProgress( - IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER); + IPPROTO_TCP, ALPROTO_HTTP, tx, FlowGetDisruptionFlags(f, STREAM_TOSERVER)); if (tx_progress_ts >= tx_progress_done_value_ts) { int tx_progress_tc = AppLayerParserGetStateProgress( - IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT); + IPPROTO_TCP, ALPROTO_HTTP, tx, FlowGetDisruptionFlags(f, STREAM_TOCLIENT)); if (tx_progress_tc >= tx_progress_done_value_tc) { tx_done = 1; } diff --git a/src/output-tx.c b/src/output-tx.c index aa48d9e121c6..93ba9956042b 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -138,14 +138,14 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ if (!(AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_EOF))) { int tx_progress = AppLayerParserGetStateProgress(p->proto, alproto, - tx, STREAM_TOSERVER); + tx, FlowGetDisruptionFlags(f, STREAM_TOSERVER)); if (tx_progress < tx_progress_done_value_ts) { SCLogDebug("progress not far enough, not logging"); break; } tx_progress = AppLayerParserGetStateProgress(p->proto, alproto, - tx, STREAM_TOCLIENT); + tx, FlowGetDisruptionFlags(f, STREAM_TOCLIENT)); if (tx_progress < tx_progress_done_value_tc) { SCLogDebug("progress not far enough, not logging"); break; From 6946e0be55e89f546f842bca3b2f64b479cb4277 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Jul 2015 13:32:31 +0200 Subject: [PATCH 0647/2553] detect: pass flags to inspect_id update logic --- src/app-layer-parser.c | 14 +++++++------- src/app-layer-parser.h | 4 ++-- src/detect-engine-state.c | 8 ++++++-- src/detect-engine-state.h | 6 +++--- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 0e2fdfb474ef..134f99095c1c 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -546,15 +546,15 @@ uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint } void AppLayerParserSetTransactionInspectId(AppLayerParserState *pstate, - uint8_t ipproto, AppProto alproto, void *alstate, - uint8_t direction) + const uint8_t ipproto, const AppProto alproto, + void *alstate, const uint8_t flags) { SCEnter(); - uint8_t dir = (direction & STREAM_TOSERVER) ? 0 : 1; + int direction = (flags & STREAM_TOSERVER) ? 0 : 1; uint64_t total_txs = AppLayerParserGetTxCnt(ipproto, alproto, alstate); - uint64_t idx = AppLayerParserGetTransactionInspectId(pstate, direction); - int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(ipproto, alproto, direction); + uint64_t idx = AppLayerParserGetTransactionInspectId(pstate, flags); + int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(ipproto, alproto, flags); void *tx; int state_progress; @@ -562,13 +562,13 @@ void AppLayerParserSetTransactionInspectId(AppLayerParserState *pstate, tx = AppLayerParserGetTx(ipproto, alproto, alstate, idx); if (tx == NULL) continue; - state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, direction); + state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags); if (state_progress >= state_done_progress) continue; else break; } - pstate->inspect_id[dir] = idx; + pstate->inspect_id[direction] = idx; SCReturn; } diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index b81459b7666a..62cb8f68691f 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -158,8 +158,8 @@ uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate); void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate); uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction); void AppLayerParserSetTransactionInspectId(AppLayerParserState *pstate, - uint8_t ipproto, AppProto alproto, void *alstate, - uint8_t direction); + const uint8_t ipproto, const AppProto alproto, void *alstate, + const uint8_t flags); AppLayerDecoderEvents *AppLayerParserGetDecoderEvents(AppLayerParserState *pstate); void AppLayerParserSetDecoderEvents(AppLayerParserState *pstate, AppLayerDecoderEvents *devents); AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *alstate, diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 8d5baca8bd31..05ca25d57fc7 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -1095,13 +1095,17 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, return; } /** \brief update flow's inspection id's + * + * \param f unlocked flow + * \param flags direction and disruption flags * * \note it is possible that f->alstate, f->alparser are NULL */ -void DeStateUpdateInspectTransactionId(Flow *f, uint8_t direction) +void DeStateUpdateInspectTransactionId(Flow *f, const uint8_t flags) { FLOWLOCK_WRLOCK(f); if (f->alparser && f->alstate) { - AppLayerParserSetTransactionInspectId(f->alparser, f->proto, f->alproto, f->alstate, direction); + AppLayerParserSetTransactionInspectId(f->alparser, f->proto, + f->alproto, f->alstate, flags); } FLOWLOCK_UNLOCK(f); diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 8efb9445a0df..51f67448e778 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -219,10 +219,10 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, /** * \brief Update the inspect id. * - * \param f Flow(unlocked). - * \param direction 0 for to server, 1 for toclient. + * \param f unlocked flow + * \param flags direction and disruption flags */ -void DeStateUpdateInspectTransactionId(Flow *f, uint8_t direction); +void DeStateUpdateInspectTransactionId(Flow *f, const uint8_t flags); /** * \brief Reset a DetectEngineState state. From b592f98727ec584b6fd249fc2b6fc2da730f5f34 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Jul 2015 13:37:46 +0200 Subject: [PATCH 0648/2553] detect: optimize http prefilter handing --- src/detect.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/detect.c b/src/detect.c index 868e3ed736d9..de40ccd8ff18 100644 --- a/src/detect.c +++ b/src/detect.c @@ -894,14 +894,15 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, int tx_progress = 0; uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); - uint64_t total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, alstate); + uint64_t total_txs = AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, alstate); for (; idx < total_txs; idx++) { - htp_tx_t *tx = AppLayerParserGetTx(p->flow->proto, ALPROTO_HTTP, htp_state, idx); + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, idx); if (tx == NULL) continue; - tx_progress = AppLayerParserGetStateProgress(p->flow->proto, ALPROTO_HTTP, tx, STREAM_TOSERVER); if (p->flowflags & FLOW_PKT_TOSERVER) { + tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER); + if (tx_progress > HTP_REQUEST_LINE) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_URI) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_URI); @@ -961,7 +962,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } } } else { /* implied FLOW_PKT_TOCLIENT */ - tx_progress = AppLayerParserGetStateProgress(p->flow->proto, ALPROTO_HTTP, tx, STREAM_TOCLIENT); + tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT); if (tx_progress > HTP_RESPONSE_LINE) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSMD) { From 814f0b40945f238b7168809136ebc02ef3c8b92e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Jul 2015 13:38:36 +0200 Subject: [PATCH 0649/2553] detect: make http prefilter use disrupt flags --- src/detect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index de40ccd8ff18..d40b91bb1a2a 100644 --- a/src/detect.c +++ b/src/detect.c @@ -901,7 +901,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, continue; if (p->flowflags & FLOW_PKT_TOSERVER) { - tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER); + tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); if (tx_progress > HTP_REQUEST_LINE) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_URI) { @@ -962,7 +962,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } } } else { /* implied FLOW_PKT_TOCLIENT */ - tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT); + tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); if (tx_progress > HTP_RESPONSE_LINE) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSMD) { From bbc9874b817fcdfda4fac71e806bc4c077ba001e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Jul 2015 15:31:56 +0200 Subject: [PATCH 0650/2553] http: destroy htp_tx_t even if incomplete --- src/app-layer-htp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 8444afe651ed..1a9c41a5c0ab 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -408,6 +408,17 @@ static void HTPStateTransactionFree(void *state, uint64_t id) HtpTxUserDataFree(s, htud); htp_tx_set_user_data(tx, NULL); + /* hack: even if libhtp considers the tx incomplete, we want to + * free it here. htp_tx_destroy however, will refuse to do this. + * As htp_tx_destroy_incomplete isn't available in the public API, + * we hack around it here. */ + if (unlikely(!( + tx->request_progress == HTP_REQUEST_COMPLETE && + tx->response_progress == HTP_RESPONSE_COMPLETE))) + { + tx->request_progress = HTP_REQUEST_COMPLETE; + tx->response_progress = HTP_RESPONSE_COMPLETE; + } htp_tx_destroy(tx); } } From 06ee2bc87e77bcb981a56ffbe74e7e55757146bf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Jul 2015 17:49:01 +0200 Subject: [PATCH 0651/2553] detect: set flow noinspect on pass in applayer/stream If a pass rule matches in the reassembled stream and/or in the app-layer state, it means the rest of the flow should not be inspected. --- src/detect-engine-alert.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index 8f91a4b8375d..c2d7e4206524 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -293,7 +293,16 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx /* Ok, reset the alert cnt to end in the previous of pass * so we ignore the rest with less prio */ p->alerts.cnt = i; + + /* if an stream/app-layer match we enforce the pass for the flow */ + if ((p->flow != NULL) && + (p->alerts.alerts[i].flags & + (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH))) + { + FlowLockSetNoPacketInspectionFlag(p->flow); + } break; + /* if the signature wants to drop, check if the * PACKET_ALERT_FLAG_DROP_FLOW flag is set. */ } else if ((PACKET_TEST_ACTION(p, ACTION_DROP)) && From 2ef0ebb24b2a8f762e1545eddab47c2c1778490e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Jul 2015 21:05:14 +0200 Subject: [PATCH 0652/2553] detect: fix pass transaction handling If a flow was 'pass'd, it means that no packet of it will flow be handled by the detection engine. A side effect of this was that the per flow inspect_id would never be moved forward. This in turn lead to a situation where transactions wouldn't be freed. This patch addresses this case by incrementing the inspect_id anyway for the pass case. --- src/detect.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index d40b91bb1a2a..e98fd311db28 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1939,9 +1939,30 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue DEBUG_VALIDATE_PACKET(p); /* No need to perform any detection on this packet, if the the given flag is set.*/ - if ((p->flags & PKT_NOPACKET_INSPECTION) || (PACKET_TEST_ACTION(p, - ACTION_DROP))) + if ((p->flags & PKT_NOPACKET_INSPECTION) || + (PACKET_TEST_ACTION(p, ACTION_DROP))) + { + /* hack: if we are in pass the entire flow mode, we need to still + * update the inspect_id forward. So test for the condition here, + * and call the update code if necessary. */ + if (p->flow) { + uint8_t flags = 0; + FLOWLOCK_RDLOCK(p->flow); + int pass = ((p->flow->flags & FLOW_NOPACKET_INSPECTION)); + flags = FlowGetDisruptionFlags(p->flow, flags); + AppProto alproto = FlowGetAppProtocol(p->flow); + FLOWLOCK_UNLOCK(p->flow); + if (pass && AppLayerParserProtocolSupportsTxs(p->proto, alproto)) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + flags |= STREAM_TOSERVER; + } else { + flags |= STREAM_TOCLIENT; + } + DeStateUpdateInspectTransactionId(p->flow, flags); + } + } return 0; + } DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; if (det_ctx == NULL) { From 3aa58f25ad51a68b57946f06a2423a26e41400c8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 22 Jul 2015 16:33:56 +0200 Subject: [PATCH 0653/2553] eve alert: fix stream payload printing --- src/output-json-alert.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 887c23e7776b..a8f7f41f0f24 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -288,7 +288,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (json_output_ctx->flags & LOG_JSON_PAYLOAD_BASE64) { unsigned long len = JSON_STREAM_BUFFER_SIZE * 2; uint8_t encoded[len]; - Base64Encode((unsigned char *)payload, payload->offset, encoded, &len); + Base64Encode(payload->buffer, payload->offset, encoded, &len); json_object_set_new(js, "payload", json_string((char *)encoded)); } @@ -297,7 +297,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) uint32_t offset = 0; PrintStringsToBuffer(printable_buf, &offset, sizeof(printable_buf), - (unsigned char *)payload, payload->offset); + payload->buffer, payload->offset); json_object_set_new(js, "payload_printable", json_string((char *)printable_buf)); } From 147a6d2bfd899d16a68d01874bbc8dda71ff791f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Jan 2015 19:00:16 +0100 Subject: [PATCH 0654/2553] multi-detect: (un)register-tenant unix socket commands Make available to live mode and unix socket mode. register-tenant: Loads a new YAML, does basic validation. Loads a new detection engine Loads rules Add new de_ctx to master store and stores tenant id in the de_ctx so we can look it up by tenant id later. unregister-tenant: Gets the de_ctx, moves it to the freelist Removes config Introduce DetectEngineGetByTenantId, which gets a reference to the detect engine by tenant id. --- scripts/suricatasc/src/suricatasc.py | 23 ++++- src/detect-engine.c | 24 +++++ src/detect-engine.h | 1 + src/detect.h | 2 + src/runmode-unix-socket.c | 132 +++++++++++++++++++++++++++ src/runmode-unix-socket.h | 5 + src/unix-manager.c | 3 + 7 files changed, 189 insertions(+), 1 deletion(-) diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index f5a7aa7f0b7a..3ab97b99cc63 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -80,7 +80,7 @@ def __call__(self, text, state): class SuricataSC: def __init__(self, sck_path, verbose=False): - self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat'] + self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat','register-tenant','unregister-tenant'] self.sck_path = sck_path self.verbose = verbose @@ -206,6 +206,27 @@ def parse_command(self, command): else: arguments = {} arguments["variable"] = variable + elif "unregister-tenant" in command: + try: + [cmd, tenantid] = command.split(' ', 1) + except: + raise SuricataCommandException("Unable to split command '%s'" % (command)) + if cmd != "unregister-tenant": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + elif "register-tenant" in command: + try: + [cmd, tenantid, filename] = command.split(' ', 2) + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "register-tenant": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["filename"] = filename else: cmd = command else: diff --git a/src/detect-engine.c b/src/detect-engine.c index adb3d5908e9e..48afc52b6a70 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1640,6 +1640,30 @@ DetectEngineCtx *DetectEngineReference(DetectEngineCtx *de_ctx) return de_ctx; } +DetectEngineCtx *DetectEngineGetByTenantId(int tenant_id) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->list == NULL) { + SCMutexUnlock(&master->lock); + return NULL; + } + + DetectEngineCtx *de_ctx = master->list; + while (de_ctx) { + if (de_ctx->tenant_id == tenant_id) { + de_ctx->ref_cnt++; + break; + } + + de_ctx = de_ctx->next; + } + + SCMutexUnlock(&master->lock); + return de_ctx; +} + void DetectEngineDeReference(DetectEngineCtx **de_ctx) { BUG_ON((*de_ctx)->ref_cnt == 0); diff --git a/src/detect-engine.h b/src/detect-engine.h index b89260d613e5..928f7887669e 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -70,6 +70,7 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type); int DetectEngineAddToMaster(DetectEngineCtx *de_ctx); DetectEngineCtx *DetectEngineGetCurrent(void); +DetectEngineCtx *DetectEngineGetByTenantId(int tenant_id); void DetectEnginePruneFreeList(void); int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx); DetectEngineCtx *DetectEngineReference(DetectEngineCtx *); diff --git a/src/detect.h b/src/detect.h index 223b6d31a47f..05c31d65d6c2 100644 --- a/src/detect.h +++ b/src/detect.h @@ -560,6 +560,8 @@ typedef struct DetectEngineCtx_ { uint8_t flags; int failure_fatal; + int tenant_id; + Signature *sig_list; uint32_t sig_cnt; diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index bc7f24cc70dc..2e9a6c0f4174 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -41,6 +41,10 @@ #include "util-profiling.h" +#include "conf-yaml-loader.h" + +#include "detect-engine.h" + static const char *default_mode = NULL; int unix_socket_mode_is_running = 0; @@ -397,6 +401,134 @@ void UnixSocketPcapFile(TmEcode tm) #endif } +#ifdef BUILD_UNIX_SOCKET +/** + * \brief Command to add a tenant + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * \param data pointer to data defining the context here a PcapCommand:: + */ +TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data) +{ + const char *filename; +#ifdef OS_WIN32 + struct _stat st; +#else + struct stat st; +#endif /* OS_WIN32 */ + + /* 1 get tenant id */ + json_t *jarg = json_object_get(cmd, "id"); + if (!json_is_integer(jarg)) { + json_object_set_new(answer, "message", json_string("id is not an integer")); + return TM_ECODE_FAILED; + } + int tenant_id = json_integer_value(jarg); + + /* 2 get tenant yaml */ + jarg = json_object_get(cmd, "filename"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("command is not a string")); + return TM_ECODE_FAILED; + } + filename = json_string_value(jarg); +#ifdef OS_WIN32 + if(_stat(filename, &st) != 0) { +#else + if(stat(filename, &st) != 0) { +#endif /* OS_WIN32 */ + json_object_set_new(answer, "message", json_string("file does not exist")); + return TM_ECODE_FAILED; + } + + SCLogDebug("add-tenant: %d %s", tenant_id, filename); + + /* 3 register it in the system */ + + /* 3A yaml parsing */ + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); + + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { + json_object_set_new(answer, "message", json_string("YAML loading failed, ConfYamlLoadFileWithPrefix failed")); + return TM_ECODE_FAILED; + } + + ConfNode *node = ConfGetNode(prefix); + if (node == NULL) { + json_object_set_new(answer, "message", json_string("YAML loading failed, node == NULL")); + return TM_ECODE_FAILED; + } +#if 0 + ConfDump(); +#endif + + /* 3B setup the de_ctx */ + DetectEngineCtx *de_ctx = DetectEngineCtxInitWithPrefix(prefix); + if (de_ctx == NULL) { + json_object_set_new(answer, "message", json_string("detect engine failed to load")); + return TM_ECODE_FAILED; + } + SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix); + + de_ctx->tenant_id = tenant_id; + + SigLoadSignatures(de_ctx, NULL, 0); + + DetectEngineAddToMaster(de_ctx); + + /* 3C for each thread, replace det_ctx */ + + json_object_set_new(answer, "message", json_string("work in progress")); + return TM_ECODE_OK; +} + +/** + * \brief Command to remove a tenant + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * \param data pointer to data defining the context here a PcapCommand:: + */ +TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data) +{ + /* 1 get tenant id */ + json_t *jarg = json_object_get(cmd, "id"); + if (!json_is_integer(jarg)) { + SCLogInfo("error: command is not a string"); + json_object_set_new(answer, "message", json_string("id is not an integer")); + return TM_ECODE_FAILED; + } + int tenant_id = json_integer_value(jarg); + + SCLogInfo("remove-tenant: %d TODO", tenant_id); + + /* 2 remove it from the system */ + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); + + DetectEngineCtx *de_ctx = DetectEngineGetByTenantId(tenant_id); + if (de_ctx == NULL) { + json_object_set_new(answer, "message", json_string("tenant detect engine not found")); + return TM_ECODE_FAILED; + } + + /* move to free list */ + DetectEngineMoveToFreeList(de_ctx); + DetectEngineDeReference(&de_ctx); + + /* update the threads */ + /** TODO */ + + /* walk free list, freeing the removed de_ctx */ + DetectEnginePruneFreeList(); + + json_object_set_new(answer, "message", json_string("work in progress")); + return TM_ECODE_OK; +} +#endif /* BUILD_UNIX_SOCKET */ + /** * \brief Single thread version of the Pcap file processing. */ diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index 578469ec242d..b844c890a60a 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -31,4 +31,9 @@ int RunModeUnixSocketIsActive(void); void UnixSocketPcapFile(TmEcode tm); +#ifdef BUILD_UNIX_SOCKET +TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data); +#endif + #endif /* __RUNMODE_UNIX_SOCKET_H__ */ diff --git a/src/unix-manager.c b/src/unix-manager.c index 6228c6a5eb4d..8bea8c48348b 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -899,6 +899,9 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0); UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0); + UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS); + TmThreadsSetFlag(th_v, THV_INIT_DONE); while (1) { From def2b58725e6876abecceccecb096ba005eb34bc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 29 Jan 2015 11:20:09 +0100 Subject: [PATCH 0655/2553] detect: initial MT lookup logic In the DetectEngineThreadCtx, store another DetectEngineThreadCtx per tenant. Currently it's just a simple array indexed by the tenant id. --- src/detect-engine.c | 95 ++++++++++++++++++++++++++++++++++++++++++++- src/detect-engine.h | 1 + src/detect.c | 25 ++++++++---- src/detect.h | 3 ++ 4 files changed, 116 insertions(+), 8 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 48afc52b6a70..b83e5e64759a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -105,6 +105,8 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *); static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, NULL, NULL, }; +static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv); + /* 2 - for each direction */ DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; @@ -604,7 +606,10 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) old_det_ctx[i] = SC_ATOMIC_GET(slots->slot_data); detect_tvs[i] = tv; - new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx); + if (new_de_ctx != NULL) + new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx); + else + new_det_ctx[i] = DetectEngineThreadCtxInitForMT(tv); if (new_det_ctx[i] == NULL) { SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init " "failure in live rule swap. Let's get out of here"); @@ -1450,6 +1455,19 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) return TM_ECODE_OK; } + if (det_ctx->mt_det_ctxs != NULL) { + uint32_t x; + for (x = 0; x < det_ctx->mt_det_ctxs_cnt; x++) { + if (det_ctx->mt_det_ctxs[x] == NULL) + continue; + + DetectEngineThreadCtxDeinit(tv, det_ctx->mt_det_ctxs[x]); + det_ctx->mt_det_ctxs[x] = NULL; + } + SCFree(det_ctx->mt_det_ctxs); + det_ctx->mt_det_ctxs = NULL; + } + #ifdef PROFILING SCProfilingRuleThreadCleanup(det_ctx); SCProfilingKeywordThreadCleanup(det_ctx); @@ -1858,6 +1876,81 @@ int DetectEngineReload(const char *filename) return 0; } +/** NOTE: master MUST be locked before calling this */ +static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + int max_tenant_id = 0; + DetectEngineCtx *list = master->list; + while (list) { + if (list->tenant_id > max_tenant_id) + max_tenant_id = list->tenant_id; + + list = list->next; + } + + if (max_tenant_id == 0) { + SCLogInfo("no tenants left"); + return NULL; + } + + max_tenant_id++; + + DetectEngineThreadCtx **tenant_det_ctxs = SCCalloc(max_tenant_id, sizeof(DetectEngineThreadCtx *)); + BUG_ON(tenant_det_ctxs == NULL); + + list = master->list; + while (list) { + if (list->tenant_id != 0) { + tenant_det_ctxs[list->tenant_id] = DetectEngineThreadCtxInitForReload(tv, list); + if (tenant_det_ctxs[list->tenant_id] == NULL) + goto error; + } + list = list->next; + } + + DetectEngineThreadCtx *det_ctx = SCCalloc(1, sizeof(DetectEngineThreadCtx)); + if (det_ctx == NULL) { + goto error; + } + + det_ctx->mt_det_ctxs = tenant_det_ctxs; + det_ctx->mt_det_ctxs_cnt = max_tenant_id; + + return det_ctx; +error: + return NULL; +} + +int DetectEngineMTApply(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + DetectEngineCtx *minimal_de_ctx = NULL; + /* if we have no tenants, we need a minimal on */ + if (master->list == NULL) { + minimal_de_ctx = master->list = DetectEngineCtxInitMinimal(); + SCLogDebug("no tenants, using minimal %p", minimal_de_ctx); + } else if (master->list->next == NULL && master->list->tenant_id == 0) { + minimal_de_ctx = master->list; + SCLogDebug("no tenants, using original %p", minimal_de_ctx); + } + + /* update the threads */ + SCLogDebug("MT reload starting"); + DetectEngineReloadThreads(minimal_de_ctx); + SCLogDebug("MT reload done"); + + SCMutexUnlock(&master->lock); + + /* walk free list, freeing the old_de_ctx */ + DetectEnginePruneFreeList(); + + SCLogDebug("old_de_ctx should have been freed"); + return 0; +} + const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) { switch (type) { diff --git a/src/detect-engine.h b/src/detect-engine.h index 928f7887669e..01c0b858769b 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -77,6 +77,7 @@ DetectEngineCtx *DetectEngineReference(DetectEngineCtx *); void DetectEngineDeReference(DetectEngineCtx **de_ctx); int DetectEngineReload(const char *filename); int DetectEngineEnabled(void); +int DetectEngineMTApply(void); int DetectEngineReloadStart(void); int DetectEngineReloadIsStart(void); diff --git a/src/detect.c b/src/detect.c index e98fd311db28..66de27ac6c0f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1970,16 +1970,27 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue goto error; } + if (SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0) { + (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); + SCLogDebug("Detect Engine using new det_ctx - %p", + det_ctx); + } + DetectEngineCtx *de_ctx = det_ctx->de_ctx; if (de_ctx == NULL) { - printf("ERROR: Detect has no detection engine ctx\n"); - goto error; - } + if (det_ctx->mt_det_ctxs == 0) { + printf("ERROR: Detect has no detection engine ctx\n"); + goto error; + } - if (SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0) { - (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); - SCLogDebug("Detect Engine using new det_ctx - %p and de_ctx - %p", - det_ctx, de_ctx); + det_ctx = det_ctx->mt_det_ctxs[1]; + BUG_ON(det_ctx == NULL); + de_ctx = det_ctx->de_ctx; + BUG_ON(de_ctx == NULL); + if (SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0) { + (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); + SCLogDebug("MT de_ctx %p det_ctx %p", de_ctx, det_ctx); + } } /* see if the packet matches one or more of the sigs */ diff --git a/src/detect.h b/src/detect.h index 05c31d65d6c2..7cca9ffe2650 100644 --- a/src/detect.h +++ b/src/detect.h @@ -766,6 +766,9 @@ typedef struct DetectEngineThreadCtx_ { SigIntId *non_mpm_id_array; uint32_t non_mpm_id_cnt; // size is cnt * sizeof(uint32_t) + uint32_t mt_det_ctxs_cnt; + struct DetectEngineThreadCtx_ **mt_det_ctxs; + /* detection engine variables */ /** offset into the payload of the last match by: From 3f12bdd4f8d78d40b7bf21974fdcdf9eb2b8ebeb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 29 Jan 2015 11:33:11 +0100 Subject: [PATCH 0656/2553] tenants: apply added/removed tenant Apply to the engine. --- src/runmode-unix-socket.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 2e9a6c0f4174..2a0d651a2d85 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -479,6 +479,11 @@ TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data) DetectEngineAddToMaster(de_ctx); /* 3C for each thread, replace det_ctx */ + if (DetectEngineMTApply() < 0) { + json_object_set_new(answer, "message", json_string("couldn't apply settings")); + // TODO cleanup + return TM_ECODE_FAILED; + } json_object_set_new(answer, "message", json_string("work in progress")); return TM_ECODE_OK; @@ -519,7 +524,11 @@ TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data) DetectEngineDeReference(&de_ctx); /* update the threads */ - /** TODO */ + if (DetectEngineMTApply() < 0) { + json_object_set_new(answer, "message", json_string("couldn't apply settings")); + // TODO cleanup + return TM_ECODE_FAILED; + } /* walk free list, freeing the removed de_ctx */ DetectEnginePruneFreeList(); From b653479815175aa12377b4293f37b5476a437ff7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 29 Jan 2015 14:39:01 +0100 Subject: [PATCH 0657/2553] detect: make multi tenancy a global switch At start up we will set this flag based on "multi-detect.enabled". --- src/detect-engine.c | 21 ++++++++++++++++++++- src/detect-engine.h | 2 ++ src/detect.h | 3 +++ src/runmode-unix-socket.c | 12 ++++++++++++ src/suricata.c | 1 + 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index b83e5e64759a..61c740922856 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -103,7 +103,7 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *); -static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, NULL, NULL, }; +static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, 0, NULL, NULL, }; static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv); @@ -1658,6 +1658,25 @@ DetectEngineCtx *DetectEngineReference(DetectEngineCtx *de_ctx) return de_ctx; } +/** TODO locking? Not needed if this is a one time setting at startup */ +int DetectEngineMultiTenantEnabled(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + return (master->multi_tenant_enabled); +} + +void DetectEngineMultiTenantSetup(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + int enabled = 0; + (void)ConfGetBool("multi-detect.enabled", &enabled); + if (enabled == 1) { + master->multi_tenant_enabled = 1; + } + SCLogInfo("multi-detect is %s (multi tenancy)", + master->multi_tenant_enabled ? "enabled" : "disabled"); +} + DetectEngineCtx *DetectEngineGetByTenantId(int tenant_id) { DetectEngineMasterCtx *master = &g_master_de_ctx; diff --git a/src/detect-engine.h b/src/detect-engine.h index 01c0b858769b..70f5f1f758cb 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -78,6 +78,8 @@ void DetectEngineDeReference(DetectEngineCtx **de_ctx); int DetectEngineReload(const char *filename); int DetectEngineEnabled(void); int DetectEngineMTApply(void); +int DetectEngineMultiTenantEnabled(void); +void DetectEngineMultiTenantSetup(void); int DetectEngineReloadStart(void); int DetectEngineReloadIsStart(void); diff --git a/src/detect.h b/src/detect.h index 7cca9ffe2650..7095eec82ca7 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1047,6 +1047,9 @@ typedef struct SigGroupHead_ { typedef struct DetectEngineMasterCtx_ { SCMutex lock; + /** enable multi tenant mode */ + int multi_tenant_enabled; + /** list of active detection engines. This list is used to generate the * threads det_ctx's */ DetectEngineCtx *list; diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 2a0d651a2d85..75ab1eed3674 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -418,6 +418,12 @@ TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data) struct stat st; #endif /* OS_WIN32 */ + if (!(DetectEngineMultiTenantEnabled())) { + SCLogInfo("error: multi-tenant support not enabled"); + json_object_set_new(answer, "message", json_string("multi-tenant support not enabled")); + return TM_ECODE_FAILED; + } + /* 1 get tenant id */ json_t *jarg = json_object_get(cmd, "id"); if (!json_is_integer(jarg)) { @@ -498,6 +504,12 @@ TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data) */ TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data) { + if (!(DetectEngineMultiTenantEnabled())) { + SCLogInfo("error: multi-tenant support not enabled"); + json_object_set_new(answer, "message", json_string("multi-tenant support not enabled")); + return TM_ECODE_FAILED; + } + /* 1 get tenant id */ json_t *jarg = json_object_get(cmd, "id"); if (!json_is_integer(jarg)) { diff --git a/src/suricata.c b/src/suricata.c index e571c796bc15..7c661e1938ac 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2270,6 +2270,7 @@ int main(int argc, char **argv) if (!suri.disabled_detect) { SCClassConfInit(); SCReferenceConfInit(); + DetectEngineMultiTenantSetup(); SetupDelayedDetect(&suri); if (!suri.delayed_detect) { de_ctx = DetectEngineCtxInit(); From 98d265f40b63538ca2c15996d0fda1f1e6cb8644 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 29 Jan 2015 16:40:23 +0100 Subject: [PATCH 0658/2553] detect: use multi tenant thread init if MT enabled --- src/detect-engine.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 61c740922856..4e167f061378 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1350,6 +1350,12 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * */ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) { + if (DetectEngineMultiTenantEnabled()) { + DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForMT(tv); + *data = (void *)mt_det_ctx; + return (mt_det_ctx == NULL) ? TM_ECODE_FAILED : TM_ECODE_OK; + } + /* first register the counter. In delayed detect mode we exit right after if the * rules haven't been loaded yet. */ uint16_t counter_alerts = StatsRegisterCounter("detect.alert", tv); From 127d8183d78c9e9f6d75dcdc139c1eb79bca1e4c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Jan 2015 13:03:13 +0100 Subject: [PATCH 0659/2553] suricatasc: allow for tenant id in pcap-file Allow for an optional 'tenant id' argument to pcap-file. This will allow us to force the pcap to be inspected by this tenant. If ommited it's 0, which means it's disabled. --- scripts/suricatasc/src/suricatasc.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index 3ab97b99cc63..9507b6ba5f97 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -177,15 +177,21 @@ def parse_command(self, command): if command.split(' ', 2)[0] in self.cmd_list: if "pcap-file " in command: try: - [cmd, filename, output] = command.split(' ', 2) + parts = command.split(' '); except: raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + cmd, filename, output = parts[0], parts[1], parts[2] + tenant = None + if len(parts) > 3: + tenant = parts[3] if cmd != "pcap-file": raise SuricataCommandException("Invalid command '%s'" % (command)) else: arguments = {} arguments["filename"] = filename arguments["output-dir"] = output + if tenant != None: + arguments["tenant"] = int(tenant) elif "iface-stat" in command: try: [cmd, iface] = command.split(' ', 1) From bea66156b9b3255032a29dd1f3f5e73bdf506390 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Jan 2015 13:20:12 +0100 Subject: [PATCH 0660/2553] pcap-file: set tenant-id if available Set the id to each packet's 'pcap_v' structure. --- src/source-pcap-file.c | 13 +++++++++++++ src/source-pcap.h | 1 + 2 files changed, 14 insertions(+) diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 5d60b9871340..0b982fd3ab13 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -78,6 +78,8 @@ typedef struct PcapFileGlobalVars_ { typedef struct PcapFileThreadVars_ { + uint32_t tenant_id; + /* counters */ uint32_t pkts; uint64_t bytes; @@ -155,6 +157,7 @@ void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) p->datalink = pcap_g.datalink; p->pcap_cnt = ++pcap_g.cnt; + p->pcap_v.tenant_id = ptv->tenant_id; ptv->pkts++; ptv->bytes += h->caplen; @@ -271,6 +274,16 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_FAILED); memset(ptv, 0, sizeof(PcapFileThreadVars)); + intmax_t tenant = 0; + if (ConfGetInt("pcap-file.tenant-id", &tenant) == 1) { + if (tenant > 0 && tenant < UINT_MAX) { + ptv->tenant_id = (uint32_t)tenant; + SCLogInfo("tenant %u", ptv->tenant_id); + } else { + SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant out of range"); + } + } + char errbuf[PCAP_ERRBUF_SIZE] = ""; pcap_g.pcap_handle = pcap_open_offline((char *)initdata, errbuf); if (pcap_g.pcap_handle == NULL) { diff --git a/src/source-pcap.h b/src/source-pcap.h index 335986954dc5..ac6d331ddbc3 100644 --- a/src/source-pcap.h +++ b/src/source-pcap.h @@ -39,6 +39,7 @@ char *PcapLiveGetDevice(int); /* per packet Pcap vars */ typedef struct PcapPacketVars_ { + uint32_t tenant_id; } PcapPacketVars; /** needs to be able to contain Windows adapter id's, so From bc7e9be5c64b191521bdbe9f198392a59a5b84d5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Jan 2015 14:27:05 +0100 Subject: [PATCH 0661/2553] unix-socket: allow tenant id with pcap-file Register the tenant id that the pcap-file optionally got. --- src/runmode-unix-socket.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 75ab1eed3674..e4c848ca1e12 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -52,6 +52,7 @@ int unix_socket_mode_is_running = 0; typedef struct PcapFiles_ { char *filename; char *output_dir; + int tenant_id; TAILQ_ENTRY(PcapFiles_) next; } PcapFiles; @@ -154,7 +155,8 @@ static void PcapFilesFree(PcapFiles *cfile) * * \retval 0 in case of error, 1 in case of success */ -TmEcode UnixListAddFile(PcapCommand *this, const char *filename, const char *output_dir) +static TmEcode UnixListAddFile(PcapCommand *this, + const char *filename, const char *output_dir, int tenant_id) { PcapFiles *cfile = NULL; if (filename == NULL || this == NULL) @@ -183,6 +185,8 @@ TmEcode UnixListAddFile(PcapCommand *this, const char *filename, const char *out } } + cfile->tenant_id = tenant_id; + TAILQ_INSERT_TAIL(&this->files, cfile, next); return TM_ECODE_OK; } @@ -200,6 +204,7 @@ TmEcode UnixSocketAddPcapFile(json_t *cmd, json_t* answer, void *data) int ret; const char *filename; const char *output_dir; + int tenant_id = 0; #ifdef OS_WIN32 struct _stat st; #else @@ -245,7 +250,16 @@ TmEcode UnixSocketAddPcapFile(json_t *cmd, json_t* answer, void *data) return TM_ECODE_FAILED; } - ret = UnixListAddFile(this, filename, output_dir); + json_t *targ = json_object_get(cmd, "tenant"); + if (targ != NULL) { + if(!json_is_number(targ)) { + json_object_set_new(answer, "message", json_string("tenant is not a number")); + return TM_ECODE_FAILED; + } + tenant_id = json_number_value(targ); + } + + ret = UnixListAddFile(this, filename, output_dir, tenant_id); switch(ret) { case TM_ECODE_FAILED: json_object_set_new(answer, "message", json_string("Unable to add file to list")); @@ -343,6 +357,15 @@ TmEcode UnixSocketPcapFilesCheck(void *data) return TM_ECODE_FAILED; } } + if (cfile->tenant_id > 0) { + char tstr[16] = ""; + snprintf(tstr, sizeof(tstr), "%d", cfile->tenant_id); + if (ConfSet("pcap-file.tenant-id", tstr) != 1) { + SCLogInfo("Can not set working tenant-id to '%s'", tstr); + PcapFilesFree(cfile); + return TM_ECODE_FAILED; + } + } this->currentfile = SCStrdup(cfile->filename); if (unlikely(this->currentfile == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed file name allocation"); From 0ff6d3dcfd9c61e320fd83d3cdbec371de286722 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Jan 2015 15:04:38 +0100 Subject: [PATCH 0662/2553] detect: select detect engine at Detect entry Limited to Pcap only currently. --- src/detect-engine.c | 5 +++++ src/detect-engine.h | 2 ++ src/detect.c | 19 ++++++++++++------- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 4e167f061378..3d5adde9fec2 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1683,6 +1683,11 @@ void DetectEngineMultiTenantSetup(void) master->multi_tenant_enabled ? "enabled" : "disabled"); } +uint32_t DetectEngineTentantGetIdFromPcap(DetectEngineThreadCtx *det_ctx, const Packet *p) +{ + return p->pcap_v.tenant_id; +} + DetectEngineCtx *DetectEngineGetByTenantId(int tenant_id) { DetectEngineMasterCtx *master = &g_master_de_ctx; diff --git a/src/detect-engine.h b/src/detect-engine.h index 70f5f1f758cb..42c4bef58911 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -86,6 +86,8 @@ int DetectEngineReloadIsStart(void); void DetectEngineReloadSetDone(void); int DetectEngineReloadIsDone(void); +/* TODO move elsewhere? */ +uint32_t DetectEngineTentantGetIdFromPcap(DetectEngineThreadCtx *, const Packet *p); /** * \brief Registers an app inspection engine. diff --git a/src/detect.c b/src/detect.c index 66de27ac6c0f..906f79bc87c6 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1983,13 +1983,18 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue goto error; } - det_ctx = det_ctx->mt_det_ctxs[1]; - BUG_ON(det_ctx == NULL); - de_ctx = det_ctx->de_ctx; - BUG_ON(de_ctx == NULL); - if (SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0) { - (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); - SCLogDebug("MT de_ctx %p det_ctx %p", de_ctx, det_ctx); + uint32_t tenant_id = DetectEngineTentantGetIdFromPcap(det_ctx, p); + if (tenant_id > 0 && tenant_id < det_ctx->mt_det_ctxs_cnt) { + det_ctx = det_ctx->mt_det_ctxs[tenant_id]; + BUG_ON(det_ctx == NULL); + de_ctx = det_ctx->de_ctx; + BUG_ON(de_ctx == NULL); + if (SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0) { + (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); + SCLogDebug("MT de_ctx %p det_ctx %p (tenant %u)", de_ctx, det_ctx, tenant_id); + } + } else { + return TM_ECODE_OK; } } From 1893c5edb1f239985ecaad8afafac08647034485 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 5 Feb 2015 18:58:26 +0100 Subject: [PATCH 0663/2553] multi-detect: initial selectors for tenants The Detection Thread has the TenantGetId pointer which allows it to select a tenant id based on the packet. --- src/detect-engine.c | 121 +++++++++++++++++++++++++++++++++++++++++++- src/detect-engine.h | 3 -- src/detect.c | 5 +- src/detect.h | 28 ++++++++++ 4 files changed, 150 insertions(+), 7 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 3d5adde9fec2..823bab5b224d 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -103,7 +103,7 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *); -static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, 0, NULL, NULL, }; +static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, 0, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL,}; static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv); @@ -1474,6 +1474,11 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) det_ctx->mt_det_ctxs = NULL; } + if (det_ctx->tenant_array != NULL) { + SCFree(det_ctx->tenant_array); + det_ctx->tenant_array = NULL; + } + #ifdef PROFILING SCProfilingRuleThreadCleanup(det_ctx); SCProfilingKeywordThreadCleanup(det_ctx); @@ -1683,7 +1688,66 @@ void DetectEngineMultiTenantSetup(void) master->multi_tenant_enabled ? "enabled" : "disabled"); } -uint32_t DetectEngineTentantGetIdFromPcap(DetectEngineThreadCtx *det_ctx, const Packet *p) +uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p) +{ + const DetectEngineThreadCtx *det_ctx = ctx; + uint32_t x = 0; + uint32_t vlan_id = 0; + + if (p->vlan_idx == 0) + return 0; + + vlan_id = p->vlan_id[0]; + + if (det_ctx == NULL || det_ctx->tenant_array == NULL || det_ctx->tenant_array_size == 0) + return 0; + + /* not very efficient, but for now we're targeting only limited amounts. + * Can use hash/tree approach later. */ + for (x = 0; x < det_ctx->tenant_array_size; x++) { + if (det_ctx->tenant_array[x].traffic_id == vlan_id) + return det_ctx->tenant_array[x].tenant_id; + } + + return 0; +} + +static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors selector, + uint32_t tenant_id, uint32_t traffic_id) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (!(master->tenant_selector == TENANT_SELECTOR_UNKNOWN || master->tenant_selector == selector)) { + SCLogInfo("conflicting selector already set"); + SCMutexUnlock(&master->lock); + return -1; + } + + DetectEngineTenantMapping *map = SCCalloc(1, sizeof(*map)); + if (map == NULL) { + SCLogInfo("memory fail"); + SCMutexUnlock(&master->lock); + return -1; + } + map->traffic_id = traffic_id; + map->tenant_id = tenant_id; + + map->next = master->tenant_mapping_list; + master->tenant_mapping_list = map; + + master->tenant_selector = selector; + + SCMutexUnlock(&master->lock); + return 0; +} + +int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id) +{ + return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id); +} + +uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p) { return p->pcap_v.tenant_id; } @@ -1910,8 +1974,12 @@ int DetectEngineReload(const char *filename) static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) { DetectEngineMasterCtx *master = &g_master_de_ctx; + DetectEngineTenantMapping *map_array = NULL; + uint32_t map_array_size = 0; + uint32_t map_cnt = 0; int max_tenant_id = 0; DetectEngineCtx *list = master->list; + while (list) { if (list->tenant_id > max_tenant_id) max_tenant_id = list->tenant_id; @@ -1926,6 +1994,32 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) max_tenant_id++; + DetectEngineTenantMapping *map = master->tenant_mapping_list; + while (map) { + map_cnt++; + map = map->next; + } + + if (map_cnt > 0) { + map_array_size = map_cnt + 1; + + map_array = SCCalloc(map_array_size, sizeof(*map_array)); + if (map_array == NULL) + goto error; + + /* fill the array */ + map_cnt = 0; + map = master->tenant_mapping_list; + while (map) { + BUG_ON(map_cnt > map_array_size); + map_array[map_cnt].traffic_id = map->traffic_id; + map_array[map_cnt].tenant_id = map->tenant_id; + map_cnt++; + map = map->next; + } + + } + DetectEngineThreadCtx **tenant_det_ctxs = SCCalloc(max_tenant_id, sizeof(DetectEngineThreadCtx *)); BUG_ON(tenant_det_ctxs == NULL); @@ -1947,6 +2041,23 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) det_ctx->mt_det_ctxs = tenant_det_ctxs; det_ctx->mt_det_ctxs_cnt = max_tenant_id; + det_ctx->tenant_array = map_array; + det_ctx->tenant_array_size = map_array_size; + + switch (master->tenant_selector) { + case TENANT_SELECTOR_UNKNOWN: + SCLogDebug("TENANT_SELECTOR_UNKNOWN"); + break; + case TENANT_SELECTOR_VLAN: + det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId; + SCLogDebug("TENANT_SELECTOR_VLAN"); + break; + case TENANT_SELECTOR_DIRECT: + det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap; + SCLogDebug("TENANT_SELECTOR_DIRECT"); + break; + } + return det_ctx; error: return NULL; @@ -1957,6 +2068,12 @@ int DetectEngineMTApply(void) DetectEngineMasterCtx *master = &g_master_de_ctx; SCMutexLock(&master->lock); + if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) { + SCLogInfo("error, no tenant selector"); + SCMutexUnlock(&master->lock); + return -1; + } + DetectEngineCtx *minimal_de_ctx = NULL; /* if we have no tenants, we need a minimal on */ if (master->list == NULL) { diff --git a/src/detect-engine.h b/src/detect-engine.h index 42c4bef58911..76253ab3272c 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -86,9 +86,6 @@ int DetectEngineReloadIsStart(void); void DetectEngineReloadSetDone(void); int DetectEngineReloadIsDone(void); -/* TODO move elsewhere? */ -uint32_t DetectEngineTentantGetIdFromPcap(DetectEngineThreadCtx *, const Packet *p); - /** * \brief Registers an app inspection engine. * diff --git a/src/detect.c b/src/detect.c index 906f79bc87c6..56dab7907bfe 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1977,13 +1977,14 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue } DetectEngineCtx *de_ctx = det_ctx->de_ctx; - if (de_ctx == NULL) { + + if (det_ctx->TenantGetId != NULL) { if (det_ctx->mt_det_ctxs == 0) { printf("ERROR: Detect has no detection engine ctx\n"); goto error; } - uint32_t tenant_id = DetectEngineTentantGetIdFromPcap(det_ctx, p); + uint32_t tenant_id = det_ctx->TenantGetId(det_ctx, p); if (tenant_id > 0 && tenant_id < det_ctx->mt_det_ctxs_cnt) { det_ctx = det_ctx->mt_det_ctxs[tenant_id]; BUG_ON(det_ctx == NULL); diff --git a/src/detect.h b/src/detect.h index 7095eec82ca7..985a8cf59a3f 100644 --- a/src/detect.h +++ b/src/detect.h @@ -769,6 +769,11 @@ typedef struct DetectEngineThreadCtx_ { uint32_t mt_det_ctxs_cnt; struct DetectEngineThreadCtx_ **mt_det_ctxs; + struct DetectEngineTenantMapping_ *tenant_array; + uint32_t tenant_array_size; + + uint32_t (*TenantGetId)(const void *, const Packet *p); + /* detection engine variables */ /** offset into the payload of the last match by: @@ -1044,6 +1049,22 @@ typedef struct SigGroupHead_ { * deal with both cases */ #define SIGMATCH_OPTIONAL_OPT (1 << 5) +enum DetectEngineTenantSelectors +{ + TENANT_SELECTOR_UNKNOWN = 0, /**< not set */ + TENANT_SELECTOR_DIRECT, /**< method provides direct tenant id */ + TENANT_SELECTOR_VLAN, /**< map vlan 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; @@ -1058,6 +1079,13 @@ typedef struct DetectEngineMasterCtx_ { * 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; + } DetectEngineMasterCtx; /** \brief Signature loader statistics */ From 6d92e8d220d4e3924c92e202e6ed608e23ca5db9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 Feb 2015 16:01:09 +0100 Subject: [PATCH 0664/2553] unix-socket: implement register-tenant-handler Register tenant handlers/selectors based on what the unix command "register-tenant-handler" tells. Check traffic id before adding it. No duplicated registrations for a traffic id are allowed. --- src/detect-engine.c | 17 ++++++++ src/detect-engine.h | 3 ++ src/runmode-unix-socket.c | 83 +++++++++++++++++++++++++++++++++++++++ src/runmode-unix-socket.h | 1 + src/unix-manager.c | 1 + 5 files changed, 105 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 823bab5b224d..1eaa3465c3ce 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1724,6 +1724,16 @@ static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors return -1; } + DetectEngineTenantMapping *m = master->tenant_mapping_list; + while (m) { + if (m->traffic_id == traffic_id) { + SCLogInfo("traffic id already registered"); + SCMutexUnlock(&master->lock); + return -1; + } + m = m->next; + } + DetectEngineTenantMapping *map = SCCalloc(1, sizeof(*map)); if (map == NULL) { SCLogInfo("memory fail"); @@ -1738,6 +1748,7 @@ static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors master->tenant_selector = selector; + SCLogInfo("tenant handler %u %u %u registered", selector, tenant_id, traffic_id); SCMutexUnlock(&master->lock); return 0; } @@ -1747,6 +1758,12 @@ int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id) return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id); } +int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id) +{ + SCLogInfo("registering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id); + return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0); +} + uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p) { return p->pcap_v.tenant_id; diff --git a/src/detect-engine.h b/src/detect-engine.h index 76253ab3272c..e67bc1c7ae3c 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -86,6 +86,9 @@ int DetectEngineReloadIsStart(void); void DetectEngineReloadSetDone(void); int DetectEngineReloadIsDone(void); +int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id); +int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id); + /** * \brief Registers an app inspection engine. * diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index e4c848ca1e12..81b5839b076c 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -365,6 +365,8 @@ TmEcode UnixSocketPcapFilesCheck(void *data) PcapFilesFree(cfile); return TM_ECODE_FAILED; } + } else { + SCLogInfo("pcap-file.tenant-id not set"); } this->currentfile = SCStrdup(cfile->filename); if (unlikely(this->currentfile == NULL)) { @@ -425,6 +427,87 @@ void UnixSocketPcapFile(TmEcode tm) } #ifdef BUILD_UNIX_SOCKET +/** + * \brief Command to add a tenant handler + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * \param data pointer to data defining the context here a PcapCommand:: + */ +TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data) +{ + const char *htype; + json_int_t traffic_id = -1; + + if (!(DetectEngineMultiTenantEnabled())) { + SCLogInfo("error: multi-tenant support not enabled"); + json_object_set_new(answer, "message", json_string("multi-tenant support not enabled")); + return TM_ECODE_FAILED; + } + + /* 1 get tenant id */ + json_t *jarg = json_object_get(cmd, "id"); + if (!json_is_integer(jarg)) { + SCLogInfo("error: command is not a string"); + json_object_set_new(answer, "message", json_string("id is not an integer")); + return TM_ECODE_FAILED; + } + int tenant_id = json_integer_value(jarg); + + /* 2 get tenant handler type */ + jarg = json_object_get(cmd, "htype"); + if (!json_is_string(jarg)) { + SCLogInfo("error: command is not a string"); + json_object_set_new(answer, "message", json_string("command is not a string")); + return TM_ECODE_FAILED; + } + htype = json_string_value(jarg); + + SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype); + + /* 3 get optional hargs */ + json_t *hargs = json_object_get(cmd, "hargs"); + if (hargs != NULL) { + if (!json_is_integer(hargs)) { + SCLogInfo("error: hargs not a number"); + json_object_set_new(answer, "message", json_string("hargs not a number")); + return TM_ECODE_FAILED; + } + traffic_id = json_integer_value(hargs); + } + + /* 4 add to system */ + int r = -1; + if (strcmp(htype, "pcap") == 0) { + r = DetectEngineTentantRegisterPcapFile(tenant_id); + } else if (strcmp(htype, "vlan") == 0) { + if (traffic_id < 0) { + json_object_set_new(answer, "message", json_string("vlan requires argument")); + return TM_ECODE_FAILED; + } + if (traffic_id > USHRT_MAX) { + json_object_set_new(answer, "message", json_string("vlan argument out of range")); + return TM_ECODE_FAILED; + } + + SCLogInfo("VLAN handler: id %u maps to tenant %u", (uint32_t)traffic_id, tenant_id); + r = DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)traffic_id); + } + if (r != 0) { + json_object_set_new(answer, "message", json_string("handler setup failure")); + return TM_ECODE_FAILED; + } + + if (DetectEngineMTApply() < 0) { + json_object_set_new(answer, "message", json_string("couldn't apply settings")); + // TODO cleanup + return TM_ECODE_FAILED; + } + + json_object_set_new(answer, "message", json_string("handler added")); + return TM_ECODE_OK; +} + /** * \brief Command to add a tenant * diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index b844c890a60a..68e324337c19 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -32,6 +32,7 @@ int RunModeUnixSocketIsActive(void); void UnixSocketPcapFile(TmEcode tm); #ifdef BUILD_UNIX_SOCKET +TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data); #endif diff --git a/src/unix-manager.c b/src/unix-manager.c index 8bea8c48348b..384e59078507 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -899,6 +899,7 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0); UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0); + UnixManagerRegisterCommand("register-tenant-handler", UnixSocketRegisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS); From 7c581c0ffcaa66b6ebd62b8f3918ad1a9d73072e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 12 Feb 2015 11:04:35 +0100 Subject: [PATCH 0665/2553] multi-detect: allow start up with 0 tenants --- src/detect-engine.c | 68 ++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 1eaa3465c3ce..4ed25c094aee 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1996,6 +1996,7 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) uint32_t map_cnt = 0; int max_tenant_id = 0; DetectEngineCtx *list = master->list; + DetectEngineThreadCtx **tenant_det_ctxs = NULL; while (list) { if (list->tenant_id > max_tenant_id) @@ -2005,49 +2006,48 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) } if (max_tenant_id == 0) { - SCLogInfo("no tenants left"); - return NULL; - } - - max_tenant_id++; - - DetectEngineTenantMapping *map = master->tenant_mapping_list; - while (map) { - map_cnt++; - map = map->next; - } - - if (map_cnt > 0) { - map_array_size = map_cnt + 1; - - map_array = SCCalloc(map_array_size, sizeof(*map_array)); - if (map_array == NULL) - goto error; + SCLogInfo("no tenants left, or none registered yet"); + } else { + max_tenant_id++; - /* fill the array */ - map_cnt = 0; - map = master->tenant_mapping_list; + DetectEngineTenantMapping *map = master->tenant_mapping_list; while (map) { - BUG_ON(map_cnt > map_array_size); - map_array[map_cnt].traffic_id = map->traffic_id; - map_array[map_cnt].tenant_id = map->tenant_id; map_cnt++; map = map->next; } - } - - DetectEngineThreadCtx **tenant_det_ctxs = SCCalloc(max_tenant_id, sizeof(DetectEngineThreadCtx *)); - BUG_ON(tenant_det_ctxs == NULL); + if (map_cnt > 0) { + map_array_size = map_cnt + 1; - list = master->list; - while (list) { - if (list->tenant_id != 0) { - tenant_det_ctxs[list->tenant_id] = DetectEngineThreadCtxInitForReload(tv, list); - if (tenant_det_ctxs[list->tenant_id] == NULL) + map_array = SCCalloc(map_array_size, sizeof(*map_array)); + if (map_array == NULL) goto error; + + /* fill the array */ + map_cnt = 0; + map = master->tenant_mapping_list; + while (map) { + BUG_ON(map_cnt > map_array_size); + map_array[map_cnt].traffic_id = map->traffic_id; + map_array[map_cnt].tenant_id = map->tenant_id; + map_cnt++; + map = map->next; + } + + } + + tenant_det_ctxs = SCCalloc(max_tenant_id, sizeof(DetectEngineThreadCtx *)); + BUG_ON(tenant_det_ctxs == NULL); + + list = master->list; + while (list) { + if (list->tenant_id != 0) { + tenant_det_ctxs[list->tenant_id] = DetectEngineThreadCtxInitForReload(tv, list); + if (tenant_det_ctxs[list->tenant_id] == NULL) + goto error; + } + list = list->next; } - list = list->next; } DetectEngineThreadCtx *det_ctx = SCCalloc(1, sizeof(DetectEngineThreadCtx)); From 1127ad66b46a8322438a99b602974faaf60ff770 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 12 Feb 2015 14:14:35 +0100 Subject: [PATCH 0666/2553] multi-detect: register counters on 'master' det_ctx Otherwise counters are only registered after the stats api is already fixed. --- src/detect-engine.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 4ed25c094aee..3c6256de0a1b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2055,6 +2055,23 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) goto error; } + /* first register the counter. In delayed detect mode we exit right after if the + * rules haven't been loaded yet. */ + uint16_t counter_alerts = StatsRegisterCounter("detect.alert", tv); +#ifdef PROFILING + uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv); + uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv); + uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv); + uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv); +#endif + /** alert counter setup */ + det_ctx->counter_alerts = counter_alerts; +#ifdef PROFILING + det_ctx->counter_mpm_list = counter_mpm_list; + det_ctx->counter_nonmpm_list = counter_nonmpm_list; + det_ctx->counter_fnonmpm_list = counter_fnonmpm_list; + det_ctx->counter_match_list = counter_match_list; +#endif det_ctx->mt_det_ctxs = tenant_det_ctxs; det_ctx->mt_det_ctxs_cnt = max_tenant_id; From c72b7f83b87982b7b03600b08e8fd6d75da9bfa0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 12 Feb 2015 12:08:33 +0100 Subject: [PATCH 0667/2553] multi-detect: error on start if no selector registered Force user to select the method at startup. --- src/detect-engine.c | 6 ++++++ src/util-error.c | 1 + src/util-error.h | 1 + 3 files changed, 8 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 3c6256de0a1b..5e0ce3f78c58 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1998,6 +1998,12 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) DetectEngineCtx *list = master->list; DetectEngineThreadCtx **tenant_det_ctxs = NULL; + if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) { + SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: " + "set using multi-detect.selector"); + return NULL; + } + while (list) { if (list->tenant_id > max_tenant_id) max_tenant_id = list->tenant_id; diff --git a/src/util-error.c b/src/util-error.c index fd52a4d264f0..cb59c0f56404 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -307,6 +307,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_NETMAP_CREATE); CASE_CODE (SC_ERR_NETMAP_READ); CASE_CODE (SC_ERR_IPPAIR_INIT); + CASE_CODE (SC_ERR_MT_NO_SELECTOR); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 83529d0cdf10..97c1cd23d2a5 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -296,6 +296,7 @@ typedef enum { SC_ERR_NETMAP_READ, SC_ERR_THREAD_DEINIT, /**< thread's deinit function failed */ SC_ERR_IPPAIR_INIT, + SC_ERR_MT_NO_SELECTOR, } SCError; const char *SCErrorToString(SCError); From b6f290fac74c51384fb6a89feb94f25bd740d5a8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 12 Feb 2015 12:39:27 +0100 Subject: [PATCH 0668/2553] multi-detect: set selector from yaml Yaml setting is: multi-detect.selector Implement 'vlan' and 'direct'. --- src/detect-engine.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 5e0ce3f78c58..bec2c8baedfa 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1679,13 +1679,31 @@ int DetectEngineMultiTenantEnabled(void) void DetectEngineMultiTenantSetup(void) { DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); int enabled = 0; (void)ConfGetBool("multi-detect.enabled", &enabled); if (enabled == 1) { master->multi_tenant_enabled = 1; + + char *handler = NULL; + if (ConfGet("multi-detect.selector", &handler) == 1) { + SCLogInfo("selector %s", handler); + + if (strcmp(handler, "vlan") == 0) { + master->tenant_selector = TENANT_SELECTOR_VLAN; + } else if (strcmp(handler, "direct") == 0) { + master->tenant_selector = TENANT_SELECTOR_DIRECT; + } else { + SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s " + "multi-detect.selector", handler); + goto end; + } + } + SCLogInfo("multi-detect is enabled (multi tenancy). Selector: %s", handler); } - SCLogInfo("multi-detect is %s (multi tenancy)", - master->multi_tenant_enabled ? "enabled" : "disabled"); + SCLogDebug("multi-detect not enabled (multi tenancy)"); +end: + SCMutexUnlock(&master->lock); } uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p) From 93f856a1b309f84796f182ae95483a383c3edacc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 12 Feb 2015 14:13:46 +0100 Subject: [PATCH 0669/2553] detect: don't error out on no de_ctx This can happen on a multi-detect setup with no registered engines yet. --- src/detect.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/detect.c b/src/detect.c index 56dab7907bfe..19f0da699a46 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1964,6 +1964,7 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue return 0; } + DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; if (det_ctx == NULL) { printf("ERROR: Detect has no thread ctx\n"); @@ -1976,20 +1977,21 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue det_ctx); } - DetectEngineCtx *de_ctx = det_ctx->de_ctx; - if (det_ctx->TenantGetId != NULL) { + /* in MT mode, but no tenants registered yet */ if (det_ctx->mt_det_ctxs == 0) { - printf("ERROR: Detect has no detection engine ctx\n"); - goto error; + return TM_ECODE_OK; } uint32_t tenant_id = det_ctx->TenantGetId(det_ctx, p); if (tenant_id > 0 && tenant_id < det_ctx->mt_det_ctxs_cnt) { det_ctx = det_ctx->mt_det_ctxs[tenant_id]; - BUG_ON(det_ctx == NULL); + if (det_ctx == NULL) + return TM_ECODE_OK; de_ctx = det_ctx->de_ctx; - BUG_ON(de_ctx == NULL); + if (de_ctx == NULL) + return TM_ECODE_OK; + if (SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0) { (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); SCLogDebug("MT de_ctx %p det_ctx %p (tenant %u)", de_ctx, det_ctx, tenant_id); @@ -1997,6 +1999,8 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue } else { return TM_ECODE_OK; } + } else { + de_ctx = det_ctx->de_ctx; } /* see if the packet matches one or more of the sigs */ From 216638c3428819dd7b4254027d5cd48ea8af0191 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 12 Feb 2015 15:56:38 +0100 Subject: [PATCH 0670/2553] multi-detect: implement unregister-tenant-handler Remove a tenant handler from the list and apply it. --- src/detect-engine.c | 47 ++++++++++++++++++++++ src/detect-engine.h | 2 + src/runmode-unix-socket.c | 82 +++++++++++++++++++++++++++++++++++++++ src/runmode-unix-socket.h | 1 + src/unix-manager.c | 1 + 5 files changed, 133 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index bec2c8baedfa..1634f15cd201 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1771,17 +1771,64 @@ static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors return 0; } +static int DetectEngineTentantUnregisterSelector(enum DetectEngineTenantSelectors selector, + uint32_t tenant_id, uint32_t traffic_id) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->tenant_mapping_list == NULL) { + SCMutexUnlock(&master->lock); + return -1; + } + + DetectEngineTenantMapping *prev = NULL; + DetectEngineTenantMapping *map = master->tenant_mapping_list; + while (map) { + if (map->traffic_id == traffic_id && + map->tenant_id == tenant_id) + { + if (prev != NULL) + prev->next = map->next; + else + master->tenant_mapping_list = map->next; + + map->next = NULL; + SCFree(map); + SCLogInfo("tenant handler %u %u %u unregistered", selector, tenant_id, traffic_id); + SCMutexUnlock(&master->lock); + return 0; + } + prev = map; + map = map->next; + } + + SCMutexUnlock(&master->lock); + return -1; +} + int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id) { return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id); } +int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id) +{ + return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id); +} + int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id) { SCLogInfo("registering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id); return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0); } +int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id) +{ + SCLogInfo("unregistering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id); + return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0); +} + uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p) { return p->pcap_v.tenant_id; diff --git a/src/detect-engine.h b/src/detect-engine.h index e67bc1c7ae3c..b263e83bb305 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -87,7 +87,9 @@ void DetectEngineReloadSetDone(void); int DetectEngineReloadIsDone(void); int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id); +int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id); int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id); +int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id); /** * \brief Registers an app inspection engine. diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 81b5839b076c..6b4490d784cf 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -508,6 +508,88 @@ TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data) return TM_ECODE_OK; } +/** + * \brief Command to remove a tenant handler + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * \param data pointer to data defining the context here a PcapCommand:: + */ +TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data) +{ + const char *htype; + json_int_t traffic_id = -1; + + if (!(DetectEngineMultiTenantEnabled())) { + SCLogInfo("error: multi-tenant support not enabled"); + json_object_set_new(answer, "message", json_string("multi-tenant support not enabled")); + return TM_ECODE_FAILED; + } + + /* 1 get tenant id */ + json_t *jarg = json_object_get(cmd, "id"); + if (!json_is_integer(jarg)) { + SCLogInfo("error: command is not a string"); + json_object_set_new(answer, "message", json_string("id is not an integer")); + return TM_ECODE_FAILED; + } + int tenant_id = json_integer_value(jarg); + + /* 2 get tenant handler type */ + jarg = json_object_get(cmd, "htype"); + if (!json_is_string(jarg)) { + SCLogInfo("error: command is not a string"); + json_object_set_new(answer, "message", json_string("command is not a string")); + return TM_ECODE_FAILED; + } + htype = json_string_value(jarg); + + SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype); + + /* 3 get optional hargs */ + json_t *hargs = json_object_get(cmd, "hargs"); + if (hargs != NULL) { + if (!json_is_integer(hargs)) { + SCLogInfo("error: hargs not a number"); + json_object_set_new(answer, "message", json_string("hargs not a number")); + return TM_ECODE_FAILED; + } + traffic_id = json_integer_value(hargs); + } + + /* 4 add to system */ + int r = -1; + if (strcmp(htype, "pcap") == 0) { + r = DetectEngineTentantUnregisterPcapFile(tenant_id); + } else if (strcmp(htype, "vlan") == 0) { + if (traffic_id < 0) { + json_object_set_new(answer, "message", json_string("vlan requires argument")); + return TM_ECODE_FAILED; + } + if (traffic_id > USHRT_MAX) { + json_object_set_new(answer, "message", json_string("vlan argument out of range")); + return TM_ECODE_FAILED; + } + + SCLogInfo("VLAN handler: id %u maps to tenant %u", (uint32_t)traffic_id, tenant_id); + r = DetectEngineTentantUnregisterVlanId(tenant_id, (uint32_t)traffic_id); + } + if (r != 0) { + json_object_set_new(answer, "message", json_string("handler unregister failure")); + return TM_ECODE_FAILED; + } + + /* 5 apply it */ + if (DetectEngineMTApply() < 0) { + json_object_set_new(answer, "message", json_string("couldn't apply settings")); + // TODO cleanup + return TM_ECODE_FAILED; + } + + json_object_set_new(answer, "message", json_string("handler added")); + return TM_ECODE_OK; +} + /** * \brief Command to add a tenant * diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index 68e324337c19..af74e515331f 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -33,6 +33,7 @@ void UnixSocketPcapFile(TmEcode tm); #ifdef BUILD_UNIX_SOCKET TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data); #endif diff --git a/src/unix-manager.c b/src/unix-manager.c index 384e59078507..43a7949ec0bc 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -900,6 +900,7 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0); UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0); UnixManagerRegisterCommand("register-tenant-handler", UnixSocketRegisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS); From a21e88d95534df8dc70b0500b02fd7c45337625e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 Feb 2015 15:08:44 +0100 Subject: [PATCH 0671/2553] suricatasc: add register-tenant-handler command Arguments: - tenant id (int) - name of handler (string) - traffic id related to handler (int, optional) Examples: - register-tenant-handler 1 vlan 1111 - register-tenant-handler 8 pcap --- scripts/suricatasc/src/suricatasc.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index 9507b6ba5f97..97f1c24d7038 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -80,7 +80,7 @@ def __call__(self, text, state): class SuricataSC: def __init__(self, sck_path, verbose=False): - self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat','register-tenant','unregister-tenant'] + self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat','register-tenant','unregister-tenant','register-tenant-handler'] self.sck_path = sck_path self.verbose = verbose @@ -212,6 +212,23 @@ def parse_command(self, command): else: arguments = {} arguments["variable"] = variable + elif "register-tenant-handler" in command: + try: + parts = command.split(' ') + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + cmd, tenantid, htype = parts[0], parts[1], parts[2] + hargs = None + if len(parts) > 3: + hargs = parts[3] + if cmd != "register-tenant-handler": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["htype"] = htype + if hargs != None: + arguments["hargs"] = int(hargs) elif "unregister-tenant" in command: try: [cmd, tenantid] = command.split(' ', 1) From a20e43f97c0d91e642c1c02ca18293d15361000f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 12 Feb 2015 15:30:20 +0100 Subject: [PATCH 0672/2553] suricatasc: add unregister-tenant-handler --- scripts/suricatasc/src/suricatasc.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index 97f1c24d7038..12d9287fa44b 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -80,7 +80,7 @@ def __call__(self, text, state): class SuricataSC: def __init__(self, sck_path, verbose=False): - self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat','register-tenant','unregister-tenant','register-tenant-handler'] + self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat','register-tenant','unregister-tenant','register-tenant-handler','unregister-tenant-handler'] self.sck_path = sck_path self.verbose = verbose @@ -212,6 +212,23 @@ def parse_command(self, command): else: arguments = {} arguments["variable"] = variable + elif "unregister-tenant-handler" in command: + try: + parts = command.split(' ') + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + cmd, tenantid, htype = parts[0], parts[1], parts[2] + hargs = None + if len(parts) > 3: + hargs = parts[3] + if cmd != "unregister-tenant-handler": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["htype"] = htype + if hargs != None: + arguments["hargs"] = int(hargs) elif "register-tenant-handler" in command: try: parts = command.split(' ') From 646eb4c2a8387c642f979c78032e064ed88bc1eb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 19 Feb 2015 18:45:10 +0100 Subject: [PATCH 0673/2553] multi-detect: load tenants from yaml file Load tenants and mappings from the suricata.yaml when available. --- src/detect-engine.c | 177 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 172 insertions(+), 5 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 1634f15cd201..163874c9d9ba 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1676,13 +1676,84 @@ int DetectEngineMultiTenantEnabled(void) return (master->multi_tenant_enabled); } +/** \brief load a tenant from a yaml file + * + * \param tenant_id the tenant id by which the config is known + * \param filename full path of a yaml file + * + * \retval 0 ok + * \retval -1 failed + */ +int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename) +{ + DetectEngineCtx *de_ctx = NULL; + char prefix[64]; + + snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); + +#ifdef OS_WIN32 + struct _stat st; + if(_stat(filename, &st) != 0) { +#else + struct stat st; + if(stat(filename, &st) != 0) { +#endif /* OS_WIN32 */ + SCLogError(SC_ERR_FOPEN, "failed to stat file %s", filename); + goto error; + } + + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename); + goto error; + } + + ConfNode *node = ConfGetNode(prefix); + if (node == NULL) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename); + goto error; + } + + de_ctx = DetectEngineCtxInitWithPrefix(prefix); + if (de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " + "context failed."); + goto error; + } + SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix); + + de_ctx->tenant_id = tenant_id; + + if (SigLoadSignatures(de_ctx, NULL, 0) < 0) { + SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); + goto error; + } + + DetectEngineAddToMaster(de_ctx); + + return 0; + +error: + return -1; +} + +/** + * \brief setup multi-detect / multi-tenancy + * + * See if MT is enabled. If so, setup the selector, tenants and mappings. + * Tenants and mappings are optional, and can also dynamically be added + * and removed from the unix socket. + */ void DetectEngineMultiTenantSetup(void) { DetectEngineMasterCtx *master = &g_master_de_ctx; - SCMutexLock(&master->lock); + + int failure_fatal = 0; + (void)ConfGetBool("engine.init-failure-fatal", &failure_fatal); + int enabled = 0; (void)ConfGetBool("multi-detect.enabled", &enabled); if (enabled == 1) { + SCMutexLock(&master->lock); master->multi_tenant_enabled = 1; char *handler = NULL; @@ -1696,14 +1767,110 @@ void DetectEngineMultiTenantSetup(void) } else { SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s " "multi-detect.selector", handler); - goto end; + SCMutexUnlock(&master->lock); + goto error; } } + SCMutexUnlock(&master->lock); SCLogInfo("multi-detect is enabled (multi tenancy). Selector: %s", handler); + + /* traffic -- tenant mappings */ + ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings"); + ConfNode *mapping_node = NULL; + + if (mappings_root_node != NULL) { + TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) { + if (strcmp(mapping_node->val, "vlan") == 0) { + ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id"); + if (tenant_id_node == NULL) + goto bad_mapping; + ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id"); + if (vlan_id_node == NULL) + goto bad_mapping; + + SCLogInfo("vlan %s %s", tenant_id_node->val, vlan_id_node->val); + + uint32_t tenant_id = 0; + if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val), + tenant_id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id " + "of %s is invalid", tenant_id_node->val); + goto bad_mapping; + } + + uint16_t vlan_id = 0; + if (ByteExtractStringUint16(&vlan_id, 10, strlen(vlan_id_node->val), + vlan_id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id " + "of %s is invalid", vlan_id_node->val); + goto bad_mapping; + } + + if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) { + goto error; + } + } else { + SCLogWarning(SC_ERR_INVALID_VALUE, "multi-detect.mappings expects a list of 'vlan's. Not %s", mapping_node->val); + goto bad_mapping; + } + continue; + + bad_mapping: + if (failure_fatal) + goto error; + } + } + + /* tenants */ + ConfNode *tenants_root_node = ConfGetNode("multi-detect.tenants"); + ConfNode *tenant_node = NULL; + + if (tenants_root_node != NULL) { + TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) { + if (strcmp(tenant_node->val, "tenant") != 0) { + SCLogWarning(SC_ERR_INVALID_VALUE, "multi-detect.tenants expects a list of 'tenant's. Not %s", tenant_node->val); + goto bad_tenant; + } + ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id"); + if (id_node == NULL) + goto bad_tenant; + ConfNode *yaml_node = ConfNodeLookupChild(tenant_node, "yaml"); + if (yaml_node == NULL) + goto bad_tenant; + + uint32_t tenant_id = 0; + if (ByteExtractStringUint32(&tenant_id, 10, strlen(id_node->val), + id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant_id " + "of %s is invalid", id_node->val); + goto bad_tenant; + } + SCLogInfo("tenant id: %u, %s", tenant_id, yaml_node->val); + + if (DetectEngineMultiTenantLoadTenant(tenant_id, yaml_node->val) != 0) { + /* error logged already */ + goto bad_tenant; + } + continue; + + bad_tenant: + if (failure_fatal) + goto error; + } + } + if (DetectEngineMTApply() < 0) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + goto error; + } + + } else { + SCLogDebug("multi-detect not enabled (multi tenancy)"); } - SCLogDebug("multi-detect not enabled (multi tenancy)"); -end: - SCMutexUnlock(&master->lock); +error: + return; } uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p) From 4e0683c3f520ff73cef7d33779f269b54aaa8e0f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Feb 2015 09:33:53 +0100 Subject: [PATCH 0674/2553] multi-detect: cleanup, reuse tenant loading code Reuse tenant loading from YAML code for Unix Socket. --- src/detect-engine.h | 2 ++ src/runmode-unix-socket.c | 38 +++++--------------------------------- 2 files changed, 7 insertions(+), 33 deletions(-) diff --git a/src/detect-engine.h b/src/detect-engine.h index b263e83bb305..ee2d89de0af5 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -86,6 +86,8 @@ int DetectEngineReloadIsStart(void); void DetectEngineReloadSetDone(void); int DetectEngineReloadIsDone(void); +int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename); + int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id); int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id); int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id); diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 6b4490d784cf..a08a335c29f7 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -638,48 +638,20 @@ TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data) SCLogDebug("add-tenant: %d %s", tenant_id, filename); - /* 3 register it in the system */ - - /* 3A yaml parsing */ - char prefix[64]; - snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); - - if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { - json_object_set_new(answer, "message", json_string("YAML loading failed, ConfYamlLoadFileWithPrefix failed")); - return TM_ECODE_FAILED; - } - - ConfNode *node = ConfGetNode(prefix); - if (node == NULL) { - json_object_set_new(answer, "message", json_string("YAML loading failed, node == NULL")); - return TM_ECODE_FAILED; - } -#if 0 - ConfDump(); -#endif - - /* 3B setup the de_ctx */ - DetectEngineCtx *de_ctx = DetectEngineCtxInitWithPrefix(prefix); - if (de_ctx == NULL) { - json_object_set_new(answer, "message", json_string("detect engine failed to load")); + /* 3 load into the system */ + if (DetectEngineMultiTenantLoadTenant(tenant_id, filename) != 0) { + json_object_set_new(answer, "message", json_string("adding tenant failed")); return TM_ECODE_FAILED; } - SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix); - de_ctx->tenant_id = tenant_id; - - SigLoadSignatures(de_ctx, NULL, 0); - - DetectEngineAddToMaster(de_ctx); - - /* 3C for each thread, replace det_ctx */ + /* 4 apply to the running system */ if (DetectEngineMTApply() < 0) { json_object_set_new(answer, "message", json_string("couldn't apply settings")); // TODO cleanup return TM_ECODE_FAILED; } - json_object_set_new(answer, "message", json_string("work in progress")); + json_object_set_new(answer, "message", json_string("adding tenant succeeded")); return TM_ECODE_OK; } From 642c267dc4aa8af62fbdc95ddb61c52055093d8e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Feb 2015 10:40:32 +0100 Subject: [PATCH 0675/2553] multi-detect: refuse to add duplicate tenant Generate error if tentant to be added is already loaded. --- src/detect-engine.c | 11 +++++++++++ src/util-error.c | 1 + src/util-error.h | 1 + 3 files changed, 13 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 163874c9d9ba..87ef62ea63f4 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1702,6 +1702,14 @@ int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename) goto error; } + de_ctx = DetectEngineGetByTenantId(tenant_id); + if (de_ctx != NULL) { + SCLogError(SC_ERR_MT_DUPLICATE_TENANT, "tenant %u already registered", + tenant_id); + DetectEngineDeReference(&de_ctx); + goto error; + } + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename); goto error; @@ -1733,6 +1741,9 @@ int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename) return 0; error: + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } return -1; } diff --git a/src/util-error.c b/src/util-error.c index cb59c0f56404..6e783f42e4cf 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -308,6 +308,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_NETMAP_READ); CASE_CODE (SC_ERR_IPPAIR_INIT); CASE_CODE (SC_ERR_MT_NO_SELECTOR); + CASE_CODE (SC_ERR_MT_DUPLICATE_TENANT); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 97c1cd23d2a5..d1e42a8cdd4e 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -297,6 +297,7 @@ typedef enum { SC_ERR_THREAD_DEINIT, /**< thread's deinit function failed */ SC_ERR_IPPAIR_INIT, SC_ERR_MT_NO_SELECTOR, + SC_ERR_MT_DUPLICATE_TENANT, } SCError; const char *SCErrorToString(SCError); From f4c9915066402852e647346ed8c9d797ba6781f3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 1 Mar 2015 10:09:21 +0100 Subject: [PATCH 0676/2553] multi-detect: store tenant id in packet Store tenant id in the packet so that the output API's can log it. --- src/decode.h | 4 ++++ src/detect.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/decode.h b/src/decode.h index 1a510eec46f2..2f322a02fec3 100644 --- a/src/decode.h +++ b/src/decode.h @@ -538,6 +538,9 @@ typedef struct Packet_ /* tunnel packet ref count */ uint16_t tunnel_tpr_cnt; + /** tenant id for this packet, if any. If 0 then no tenant was assigned. */ + uint32_t tenant_id; + /* The Packet pool from which this packet was allocated. Used when returning * the packet to its owner's stack. If NULL, then allocated with malloc. */ @@ -758,6 +761,7 @@ void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s); (p)->livedev = NULL; \ PACKET_RESET_CHECKSUMS((p)); \ PACKET_PROFILING_RESET((p)); \ + p->tenant_id = 0; \ } while (0) #define PACKET_RECYCLE(p) do { \ diff --git a/src/detect.c b/src/detect.c index 19f0da699a46..b3f9339ffec4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1985,6 +1985,8 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue uint32_t tenant_id = det_ctx->TenantGetId(det_ctx, p); if (tenant_id > 0 && tenant_id < det_ctx->mt_det_ctxs_cnt) { + p->tenant_id = tenant_id; + det_ctx = det_ctx->mt_det_ctxs[tenant_id]; if (det_ctx == NULL) return TM_ECODE_OK; From 8673801ea3b7b5bba0c40fb916f33f53898b6069 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 1 Mar 2015 10:34:53 +0100 Subject: [PATCH 0677/2553] multi-detect: add tenant id to alert json output Add a integer field "tenant_id" to the JSON alert output. --- src/output-json-alert.c | 10 ++++++++-- src/output-json-alert.h | 2 +- src/output-json-drop.c | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index a8f7f41f0f24..3c4219b42876 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -159,7 +159,7 @@ static void AlertJsonSsh(const Flow *f, json_t *js) return; } -void AlertJsonHeader(const PacketAlert *pa, json_t *js) +void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js) { char *action = "allowed"; if (pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) { @@ -187,6 +187,9 @@ void AlertJsonHeader(const PacketAlert *pa, json_t *js) if (pa->flags & PACKET_ALERT_FLAG_TX) json_object_set_new(ajs, "tx_id", json_integer(pa->tx_id)); + if (p->tenant_id > 0) + json_object_set_new(ajs, "tenant_id", json_integer(p->tenant_id)); + /* alert */ json_object_set_new(js, "alert", ajs); } @@ -214,7 +217,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) MemBufferReset(aft->json_buffer); /* alert */ - AlertJsonHeader(pa, js); + AlertJsonHeader(p, pa, js); if (json_output_ctx->flags & LOG_JSON_HTTP) { if (p->flow != NULL) { @@ -431,6 +434,9 @@ static int AlertJsonDecoderEvent(ThreadVars *tv, JsonAlertLogThread *aft, const json_string((pa->s->class_msg) ? pa->s->class_msg : "")); json_object_set_new(ajs, "severity", json_integer(pa->s->prio)); + if (p->tenant_id > 0) + json_object_set_new(ajs, "tenant_id", json_integer(p->tenant_id)); + /* alert */ json_object_set_new(js, "alert", ajs); OutputJSONBuffer(js, aft->file_ctx, buffer); diff --git a/src/output-json-alert.h b/src/output-json-alert.h index 55313fbb555a..a10a316d20b3 100644 --- a/src/output-json-alert.h +++ b/src/output-json-alert.h @@ -29,7 +29,7 @@ void TmModuleJsonAlertLogRegister (void); #ifdef HAVE_LIBJANSSON -void AlertJsonHeader(const PacketAlert *pa, json_t *js); +void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js); #endif /* HAVE_LIBJANSSON */ #endif /* __OUTPUT_JSON_ALERT_H__ */ diff --git a/src/output-json-drop.c b/src/output-json-drop.c index d0a4275fd59b..c9b01df83495 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -152,14 +152,14 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) if ((pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) || ((pa->action & ACTION_DROP) && EngineModeIsIPS())) { - AlertJsonHeader(pa, js); + AlertJsonHeader(p, pa, js); logged = 1; } } if (logged == 0) { if (p->alerts.drop.action != 0) { const PacketAlert *pa = &p->alerts.drop; - AlertJsonHeader(pa, js); + AlertJsonHeader(p, pa, js); } } } From d8181802d375e50dff5f15a6532a20861c5b0b23 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 14 Mar 2015 20:23:13 +0100 Subject: [PATCH 0678/2553] multi-detect: add reload-tenant command Allow for a tenant to be reloaded. The command is the same as the register-tenant command, so with a yaml and tenant-id as argument. However this replaces an existing tenant. --- src/runmode-unix-socket.c | 102 ++++++++++++++++++++++++++++++++++++++ src/runmode-unix-socket.h | 1 + src/unix-manager.c | 1 + 3 files changed, 104 insertions(+) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index a08a335c29f7..bc3e2955c371 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -655,6 +655,108 @@ TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data) return TM_ECODE_OK; } +static int reload_cnt = 1; +/** + * \brief Command to reload a tenant + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * \param data pointer to data defining the context here a PcapCommand:: + */ +TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data) +{ + const char *filename; +#ifdef OS_WIN32 + struct _stat st; +#else + struct stat st; +#endif /* OS_WIN32 */ + + if (!(DetectEngineMultiTenantEnabled())) { + SCLogInfo("error: multi-tenant support not enabled"); + json_object_set_new(answer, "message", json_string("multi-tenant support not enabled")); + return TM_ECODE_FAILED; + } + + /* 1 get tenant id */ + json_t *jarg = json_object_get(cmd, "id"); + if (!json_is_integer(jarg)) { + json_object_set_new(answer, "message", json_string("id is not an integer")); + return TM_ECODE_FAILED; + } + int tenant_id = json_integer_value(jarg); + + /* 2 get tenant yaml */ + jarg = json_object_get(cmd, "filename"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("command is not a string")); + return TM_ECODE_FAILED; + } + filename = json_string_value(jarg); +#ifdef OS_WIN32 + if(_stat(filename, &st) != 0) { +#else + if(stat(filename, &st) != 0) { +#endif /* OS_WIN32 */ + json_object_set_new(answer, "message", json_string("file does not exist")); + return TM_ECODE_FAILED; + } + + SCLogDebug("reload-tenant: %d %s", tenant_id, filename); + + DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id); + if (old_de_ctx == NULL) { + json_object_set_new(answer, "message", json_string("tenant detect engine not found")); + return TM_ECODE_FAILED; + } + + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt); + reload_cnt++; + SCLogInfo("prefix %s", prefix); + + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { + json_object_set_new(answer, "message", json_string("failed to load yaml")); + return TM_ECODE_FAILED; + } + + ConfNode *node = ConfGetNode(prefix); + if (node == NULL) { + json_object_set_new(answer, "message", json_string("failed to properly setup yaml")); + return TM_ECODE_FAILED; + } + + DetectEngineCtx *new_de_ctx = DetectEngineCtxInitWithPrefix(prefix); + if (new_de_ctx == NULL) { + json_object_set_new(answer, "message", json_string("initializing detection engine failed")); + return TM_ECODE_FAILED; + } + SCLogDebug("de_ctx %p with prefix %s", new_de_ctx, new_de_ctx->config_prefix); + + new_de_ctx->tenant_id = tenant_id; + + if (SigLoadSignatures(new_de_ctx, NULL, 0) < 0) { + json_object_set_new(answer, "message", json_string("loading rules failed")); + return TM_ECODE_FAILED; + } + + DetectEngineAddToMaster(new_de_ctx); + + /* move to free list */ + DetectEngineMoveToFreeList(old_de_ctx); + DetectEngineDeReference(&old_de_ctx); + + /* apply to the running system */ + if (DetectEngineMTApply() < 0) { + json_object_set_new(answer, "message", json_string("couldn't apply settings")); + // TODO cleanup + return TM_ECODE_FAILED; + } + + json_object_set_new(answer, "message", json_string("reloading tenant succeeded")); + return TM_ECODE_OK; +} + /** * \brief Command to remove a tenant * diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index af74e515331f..20b0fea496d0 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -35,6 +35,7 @@ void UnixSocketPcapFile(TmEcode tm); TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data); #endif diff --git a/src/unix-manager.c b/src/unix-manager.c index 43a7949ec0bc..1960df569943 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -902,6 +902,7 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) UnixManagerRegisterCommand("register-tenant-handler", UnixSocketRegisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS); From 4d0975eeac28956720df86c1e836e5fa474ee135 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 14 Mar 2015 20:27:30 +0100 Subject: [PATCH 0679/2553] multi-detect: implement reload tenant in suricatasc --- scripts/suricatasc/src/suricatasc.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index 12d9287fa44b..1a776a29a0e5 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -267,6 +267,17 @@ def parse_command(self, command): arguments = {} arguments["id"] = int(tenantid) arguments["filename"] = filename + elif "reload-tenant" in command: + try: + [cmd, tenantid, filename] = command.split(' ', 2) + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "reload-tenant": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["filename"] = filename else: cmd = command else: From 5fff2507497cc0d442a9e9670a145ea42a240e78 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Apr 2015 14:55:16 +0200 Subject: [PATCH 0680/2553] multi-detect: make classification prefix aware Make classification loading prefix aware, so it can be part of tenant configuration. If the setting is missing from the tenant, the global setting is tried and if that too is missing, the global default is used. --- src/util-classification-config.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/util-classification-config.c b/src/util-classification-config.c index 3711dd32b1b3..e88d4f20c58f 100644 --- a/src/util-classification-config.c +++ b/src/util-classification-config.c @@ -54,7 +54,7 @@ uint32_t SCClassConfClasstypeHashFunc(HashTable *ht, void *data, uint16_t datale char SCClassConfClasstypeHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2); void SCClassConfClasstypeHashFree(void *ch); -static char *SCClassConfGetConfFilename(void); +static char *SCClassConfGetConfFilename(const DetectEngineCtx *de_ctx); void SCClassConfInit(void) { @@ -124,7 +124,7 @@ FILE *SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) * instead use an input stream against a buffer containing the * classification strings */ if (fd == NULL) { - filename = SCClassConfGetConfFilename(); + filename = SCClassConfGetConfFilename(de_ctx); if ( (fd = fopen(filename, "r")) == NULL) { #ifdef UNITTESTS if (RunmodeIsUnittests()) @@ -160,12 +160,26 @@ FILE *SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) * \retval log_filename Pointer to a string containing the path for the * Classification Config file. */ -static char *SCClassConfGetConfFilename(void) +static char *SCClassConfGetConfFilename(const DetectEngineCtx *de_ctx) { char *log_filename = NULL; - - if (ConfGet("classification-file", &log_filename) != 1) { - log_filename = (char *)SC_CLASS_CONF_DEF_CONF_FILEPATH; + char config_value[256] = ""; + + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + snprintf(config_value, sizeof(config_value), + "%s.classification-file", de_ctx->config_prefix); + + /* try loading prefix setting, fall back to global if that + * fails. */ + if (ConfGet(config_value, &log_filename) != 1) { + if (ConfGet("classification-file", &log_filename) != 1) { + log_filename = (char *)SC_CLASS_CONF_DEF_CONF_FILEPATH; + } + } + } else { + if (ConfGet("classification-file", &log_filename) != 1) { + log_filename = (char *)SC_CLASS_CONF_DEF_CONF_FILEPATH; + } } return log_filename; From a6e3cec9e560f0fe8c9e297e557d9f2f9a939192 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Apr 2015 15:31:52 +0200 Subject: [PATCH 0681/2553] multi-detect: make reference prefix aware Make reference loading prefix aware, so it can be part of tenant configuration. If the setting is missing from the tenant, the global setting is tried and if that too is missing, the global default is used. --- src/util-reference-config.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/util-reference-config.c b/src/util-reference-config.c index a2f09bd36042..299897ab35a2 100644 --- a/src/util-reference-config.c +++ b/src/util-reference-config.c @@ -51,7 +51,7 @@ char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1, void SCRConfReferenceHashFree(void *ch); /* used to get the reference.config file path */ -static char *SCRConfGetConfFilename(void); +static char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx); void SCReferenceConfInit(void) { @@ -122,7 +122,7 @@ static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE * * instead use an input stream against a buffer containing the * reference strings */ if (fd == NULL) { - filename = SCRConfGetConfFilename(); + filename = SCRConfGetConfFilename(de_ctx); if ((fd = fopen(filename, "r")) == NULL) { #ifdef UNITTESTS if (RunmodeIsUnittests()) @@ -159,11 +159,26 @@ static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE * * \retval log_filename Pointer to a string containing the path for the * reference.config file. */ -static char *SCRConfGetConfFilename(void) +static char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx) { char *path = NULL; - if (ConfGet("reference-config-file", &path) != 1) { - return (char *)SC_RCONF_DEFAULT_FILE_PATH; + char config_value[256] = ""; + + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + snprintf(config_value, sizeof(config_value), + "%s.reference-config-file", de_ctx->config_prefix); + + /* try loading prefix setting, fall back to global if that + * fails. */ + if (ConfGet(config_value, &path) != 1) { + if (ConfGet("reference-config-file", &path) != 1) { + return (char *)SC_RCONF_DEFAULT_FILE_PATH; + } + } + } else { + if (ConfGet("reference-config-file", &path) != 1) { + return (char *)SC_RCONF_DEFAULT_FILE_PATH; + } } return path; } From 4f77e8967bb0baab3b8791b8d3a977cf20c5dac1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Apr 2015 15:59:46 +0200 Subject: [PATCH 0682/2553] multi-detect: make threshold prefix aware Make threshold loading prefix aware, so it can be part of tenant configuration. If the setting is missing from the tenant, the global setting is tried and if that too is missing, the global default is used. Note: currently per host thresholds are tracked globally and NOT per tenant. --- src/util-threshold-config.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index 9f107a1e0f89..6698b16fa6db 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -103,14 +103,27 @@ static pcre_extra *regex_suppress_study = NULL; * \retval log_filename Pointer to a string containing the path for the * Threshold Config file. */ -char *SCThresholdConfGetConfFilename(void) +static char *SCThresholdConfGetConfFilename(const DetectEngineCtx *de_ctx) { char *log_filename = NULL; + char config_value[256] = ""; - if (ConfGet("threshold-file", &log_filename) != 1) { - log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; - } + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + snprintf(config_value, sizeof(config_value), + "%s.threshold-file", de_ctx->config_prefix); + /* try loading prefix setting, fall back to global if that + * fails. */ + if (ConfGet(config_value, &log_filename) != 1) { + if (ConfGet("threshold-file", &log_filename) != 1) { + log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; + } + } + } else { + if (ConfGet("threshold-file", &log_filename) != 1) { + log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; + } + } return log_filename; } @@ -138,7 +151,7 @@ int SCThresholdConfInitContext(DetectEngineCtx *de_ctx, FILE *utfd) int opts = 0; if (fd == NULL) { - filename = SCThresholdConfGetConfFilename(); + filename = SCThresholdConfGetConfFilename(de_ctx); if ( (fd = fopen(filename, "r")) == NULL) { SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; @@ -212,7 +225,6 @@ int SCThresholdConfInitContext(DetectEngineCtx *de_ctx, FILE *utfd) */ void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd) { - if (fd != NULL) fclose(fd); From 722c56dbf33035576e205ca739078be2f2337171 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 10 Apr 2015 09:59:33 +0200 Subject: [PATCH 0683/2553] detect: clean up thread free code Introduce DetectEngineThreadCtxFree that doesn't need a 'ThreadVars' pointer. --- src/detect-engine.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 87ef62ea63f4..d7d13d0cfd30 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1452,22 +1452,15 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( return det_ctx; } -TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) +void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) { - DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; - - if (det_ctx == NULL) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "argument \"data\" NULL"); - return TM_ECODE_OK; - } - if (det_ctx->mt_det_ctxs != NULL) { uint32_t x; for (x = 0; x < det_ctx->mt_det_ctxs_cnt; x++) { if (det_ctx->mt_det_ctxs[x] == NULL) continue; - DetectEngineThreadCtxDeinit(tv, det_ctx->mt_det_ctxs[x]); + DetectEngineThreadCtxFree(det_ctx->mt_det_ctxs[x]); det_ctx->mt_det_ctxs[x] = NULL; } SCFree(det_ctx->mt_det_ctxs); @@ -1554,6 +1547,18 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) #endif } SCFree(det_ctx); +} + +TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) +{ + DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; + + if (det_ctx == NULL) { + SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "argument \"data\" NULL"); + return TM_ECODE_OK; + } + + DetectEngineThreadCtxFree(det_ctx); return TM_ECODE_OK; } From e19c41a80726f27672f9ba889ab9b0444cc09399 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Apr 2015 18:20:28 +0200 Subject: [PATCH 0684/2553] multi-detect: hash lookup for tenants Use hash for storing and looking up det_ctxs. --- src/detect-engine.c | 53 ++++++++++++++++++++++++++++----------------- src/detect.c | 13 ++++++++--- src/detect.h | 5 +++++ 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index d7d13d0cfd30..db2c71bff3f7 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1422,6 +1422,7 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( return NULL; memset(det_ctx, 0, sizeof(DetectEngineThreadCtx)); + det_ctx->tenant_id = new_de_ctx->tenant_id; det_ctx->tv = tv; det_ctx->de_ctx = DetectEngineReference(new_de_ctx); if (det_ctx->de_ctx == NULL) { @@ -1454,19 +1455,6 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) { - if (det_ctx->mt_det_ctxs != NULL) { - uint32_t x; - for (x = 0; x < det_ctx->mt_det_ctxs_cnt; x++) { - if (det_ctx->mt_det_ctxs[x] == NULL) - continue; - - DetectEngineThreadCtxFree(det_ctx->mt_det_ctxs[x]); - det_ctx->mt_det_ctxs[x] = NULL; - } - SCFree(det_ctx->mt_det_ctxs); - det_ctx->mt_det_ctxs = NULL; - } - if (det_ctx->tenant_array != NULL) { SCFree(det_ctx->tenant_array); det_ctx->tenant_array = NULL; @@ -1558,6 +1546,10 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) return TM_ECODE_OK; } + if (det_ctx->mt_det_ctxs_hash != NULL) { + HashTableFree(det_ctx->mt_det_ctxs_hash); + det_ctx->mt_det_ctxs_hash = NULL; + } DetectEngineThreadCtxFree(det_ctx); return TM_ECODE_OK; @@ -2235,6 +2227,24 @@ int DetectEngineReload(const char *filename) return 0; } +static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len) +{ + DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; + return det_ctx->tenant_id % h->array_size; +} + +static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len) +{ + DetectEngineThreadCtx *det1 = (DetectEngineThreadCtx *)d1; + DetectEngineThreadCtx *det2 = (DetectEngineThreadCtx *)d2; + return (det1->tenant_id == det2->tenant_id); +} + +static void TenantIdFree(void *d) +{ + DetectEngineThreadCtxFree(d); +} + /** NOTE: master MUST be locked before calling this */ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) { @@ -2244,7 +2254,6 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) uint32_t map_cnt = 0; int max_tenant_id = 0; DetectEngineCtx *list = master->list; - DetectEngineThreadCtx **tenant_det_ctxs = NULL; if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) { SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: " @@ -2252,13 +2261,18 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) return NULL; } + uint32_t tcnt = 0; while (list) { if (list->tenant_id > max_tenant_id) max_tenant_id = list->tenant_id; list = list->next; + tcnt++; } + HashTable *mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree); + BUG_ON(mt_det_ctxs_hash == NULL); + if (max_tenant_id == 0) { SCLogInfo("no tenants left, or none registered yet"); } else { @@ -2290,15 +2304,14 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) } - tenant_det_ctxs = SCCalloc(max_tenant_id, sizeof(DetectEngineThreadCtx *)); - BUG_ON(tenant_det_ctxs == NULL); - + /* set up hash for tenant lookup */ list = master->list; while (list) { if (list->tenant_id != 0) { - tenant_det_ctxs[list->tenant_id] = DetectEngineThreadCtxInitForReload(tv, list); - if (tenant_det_ctxs[list->tenant_id] == NULL) + DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list); + if (mt_det_ctx == NULL) goto error; + BUG_ON(HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0); } list = list->next; } @@ -2308,6 +2321,7 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) if (det_ctx == NULL) { goto error; } + det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash; /* first register the counter. In delayed detect mode we exit right after if the * rules haven't been loaded yet. */ @@ -2326,7 +2340,6 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) det_ctx->counter_fnonmpm_list = counter_fnonmpm_list; det_ctx->counter_match_list = counter_match_list; #endif - det_ctx->mt_det_ctxs = tenant_det_ctxs; det_ctx->mt_det_ctxs_cnt = max_tenant_id; det_ctx->tenant_array = map_array; diff --git a/src/detect.c b/src/detect.c index b3f9339ffec4..7d608a0a2416 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1926,6 +1926,14 @@ void DetectSignatureApplyActions(Packet *p, const Signature *s) /* tm module api functions */ +static DetectEngineThreadCtx *GetTenantById(HashTable *h, uint32_t id) +{ + /* technically we need to pass a DetectEngineThreadCtx struct with the + * tentant_id member. But as that member is the first in the struct, we + * can use the id directly. */ + return HashTableLookup(h, &id, 0); +} + /** \brief Detection engine thread wrapper. * \param tv thread vars * \param p packet to inspect @@ -1979,15 +1987,14 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue if (det_ctx->TenantGetId != NULL) { /* in MT mode, but no tenants registered yet */ - if (det_ctx->mt_det_ctxs == 0) { + if (det_ctx->mt_det_ctxs_cnt == 0) { return TM_ECODE_OK; } uint32_t tenant_id = det_ctx->TenantGetId(det_ctx, p); if (tenant_id > 0 && tenant_id < det_ctx->mt_det_ctxs_cnt) { p->tenant_id = tenant_id; - - det_ctx = det_ctx->mt_det_ctxs[tenant_id]; + det_ctx = GetTenantById(det_ctx->mt_det_ctxs_hash, tenant_id); if (det_ctx == NULL) return TM_ECODE_OK; de_ctx = det_ctx->de_ctx; diff --git a/src/detect.h b/src/detect.h index 985a8cf59a3f..2ebfb43f96d4 100644 --- a/src/detect.h +++ b/src/detect.h @@ -760,6 +760,10 @@ typedef struct FiledataReassembledBody_ { * Detection engine thread data. */ typedef struct DetectEngineThreadCtx_ { + /** \note multi-tenant hash lookup code from Detect() *depends* + * on this beeing the first member */ + uint32_t tenant_id; + /* the thread to which this detection engine thread belongs */ ThreadVars *tv; @@ -768,6 +772,7 @@ typedef struct DetectEngineThreadCtx_ { 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; From 82aa419431509bb9c54c22e989b6402d43a3b357 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Apr 2015 10:33:11 +0200 Subject: [PATCH 0685/2553] multi-detect: set tenant id on pseudo packets Store the tenant id in the flow and use the stored id when setting up pesudo packets. For tunnel and defrag packets, get tenant from parent. This will only pass tenant_id's set at capture time. For defrag packets, the tenant selector based on vlan id will still work as the vlan id(s) are stored in the defrag tracker before being passed on. --- src/decode.c | 2 ++ src/detect.c | 10 +++++++++- src/flow-timeout.c | 1 + src/flow-util.h | 2 ++ src/flow.h | 4 ++++ src/stream-tcp.c | 2 ++ 6 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/decode.c b/src/decode.c index aa6068bbc09c..0dd9fa86fa04 100644 --- a/src/decode.c +++ b/src/decode.c @@ -274,6 +274,7 @@ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *pare p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; p->datalink = DLT_RAW; + p->tenant_id = parent->tenant_id; /* set the root ptr to the lowest layer */ if (parent->root != NULL) @@ -345,6 +346,7 @@ Packet *PacketDefragPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; p->datalink = DLT_RAW; + p->tenant_id = parent->tenant_id; /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); p->vlan_id[0] = parent->vlan_id[0]; diff --git a/src/detect.c b/src/detect.c index 7d608a0a2416..e420f5e392cd 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1279,6 +1279,12 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh FLOWLOCK_WRLOCK(pflow); { + /* store tenant_id in the flow so that we can use it + * for creating pseudo packets */ + if (p->tenant_id > 0 && pflow->tenant_id == 0) { + pflow->tenant_id = p->tenant_id; + } + /* live ruleswap check for flow updates */ if (pflow->de_ctx_id == 0) { /* first time this flow is inspected, set id */ @@ -1991,7 +1997,9 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue return TM_ECODE_OK; } - uint32_t tenant_id = det_ctx->TenantGetId(det_ctx, p); + uint32_t tenant_id = p->tenant_id; + if (tenant_id == 0) + tenant_id = det_ctx->TenantGetId(det_ctx, p); if (tenant_id > 0 && tenant_id < det_ctx->mt_det_ctxs_cnt) { p->tenant_id = tenant_id; det_ctx = GetTenantById(det_ctx->mt_det_ctxs_hash, tenant_id); diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 534875c68b28..8df85cddcd99 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -80,6 +80,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, TcpSession *ssn, int dummy) { + p->tenant_id = f->tenant_id; p->datalink = DLT_RAW; p->proto = IPPROTO_TCP; FlowReference(&p->flow, f); diff --git a/src/flow-util.h b/src/flow-util.h index 38257b1289bb..ca6a49cccb29 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -42,6 +42,7 @@ (f)->proto = 0; \ SC_ATOMIC_INIT((f)->flow_state); \ SC_ATOMIC_INIT((f)->use_cnt); \ + (f)->tenant_id = 0; \ (f)->probing_parser_toserver_alproto_masks = 0; \ (f)->probing_parser_toclient_alproto_masks = 0; \ (f)->flags = 0; \ @@ -86,6 +87,7 @@ (f)->proto = 0; \ SC_ATOMIC_RESET((f)->flow_state); \ SC_ATOMIC_RESET((f)->use_cnt); \ + (f)->tenant_id = 0; \ (f)->probing_parser_toserver_alproto_masks = 0; \ (f)->probing_parser_toclient_alproto_masks = 0; \ (f)->flags = 0; \ diff --git a/src/flow.h b/src/flow.h index caa34c6fc811..eab737760943 100644 --- a/src/flow.h +++ b/src/flow.h @@ -329,6 +329,10 @@ typedef struct Flow_ /** flow queue id, used with autofp */ SC_ATOMIC_DECLARE(int16_t, autofp_tmqh_flow_qid); + /** flow tenant id, used to setup flow timeout and stream pseudo + * packets with the correct tenant id set */ + uint32_t tenant_id; + uint32_t probing_parser_toserver_alproto_masks; uint32_t probing_parser_toclient_alproto_masks; diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 88fe40d4bed5..6cde8651384b 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5829,6 +5829,8 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread /* Setup the IP and TCP headers */ StreamTcpPseudoPacketSetupHeader(np,p); + np->tenant_id = p->flow->tenant_id; + np->flowflags = p->flowflags; np->flags |= PKT_STREAM_EST; From eb09118d64003b06edaf455bd2bee0cab1fa467b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 12 May 2015 11:35:47 +0200 Subject: [PATCH 0686/2553] detect: create loader threads To speed up startup with many tenants, tenant loading will be parallelized. As no tempary threads should be used for these memory allocation heavy tasks, this patch adds new type of 'command' thread that can be used to load and reload tenants. This patch hardcodes the number of loaders to 4. Future work will make it dynamic. The loader thread essentially sleeps constantly. When a tasks is sent to it, it will wake up and execute it. --- src/detect-engine.c | 309 +++++++++++++++++++++++++++++++++++++- src/detect-engine.h | 2 +- src/detect.h | 4 + src/runmode-unix-socket.c | 2 +- src/tm-modules.c | 1 + src/tm-threads-common.h | 1 + 6 files changed, 315 insertions(+), 4 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index db2c71bff3f7..305f939f9f07 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1677,11 +1677,12 @@ int DetectEngineMultiTenantEnabled(void) * * \param tenant_id the tenant id by which the config is known * \param filename full path of a yaml file + * \param loader_id id of loader thread or -1 * * \retval 0 ok * \retval -1 failed */ -int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename) +int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id) { DetectEngineCtx *de_ctx = NULL; char prefix[64]; @@ -1744,6 +1745,300 @@ int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename) return -1; } +/** + * \param ctx function specific data + * \param loader_id id of the loader that executed the task + */ +typedef int (*LoaderFunc)(void *ctx, int loader_id); + +typedef struct DetectLoaderTask_ { + LoaderFunc Func; + void *ctx; + TAILQ_ENTRY(DetectLoaderTask_) next; +} DetectLoaderTask; + +typedef struct DetectLoaderControl_ { + int id; + int result; /* 0 for ok, error otherwise */ + SCMutex m; + TAILQ_HEAD(, DetectLoaderTask_) task_list; +} DetectLoaderControl; + +#define NLOADERS 4 +static DetectLoaderControl loaders[NLOADERS]; +static int cur_loader = 0; +void TmThreadWakeupDetectLoaderThreads(void); + +/** \param loader -1 for auto select + * \retval loader_id or negative in case of error */ +int DetectLoaderQueueTask(int loader_id, LoaderFunc Func, void *func_ctx) +{ + if (loader_id == -1) { + loader_id = cur_loader; + cur_loader++; + if (cur_loader >= NLOADERS) + cur_loader = 0; + } + if (loader_id >= NLOADERS || loader_id < 0) { + return -ERANGE; + } + + DetectLoaderControl *loader = &loaders[loader_id]; + + DetectLoaderTask *t = SCCalloc(1, sizeof(*t)); + if (t == NULL) + return -ENOMEM; + + t->Func = Func; + t->ctx = func_ctx; + + SCMutexLock(&loader->m); + TAILQ_INSERT_TAIL(&loader->task_list, t, next); + SCMutexUnlock(&loader->m); + + TmThreadWakeupDetectLoaderThreads(); + + SCLogDebug("%d %p %p", loader_id, Func, func_ctx); + return loader_id; +} + +/** \brief wait for loader tasks to complete + * \retval result 0 for ok, -1 for errors */ +int DetectLoadersSync(void) +{ + SCLogDebug("waiting"); + int errors = 0; + int i; + for (i = 0; i < NLOADERS; i++) { + int done = 0; + DetectLoaderControl *loader = &loaders[i]; + while (!done) { + SCMutexLock(&loader->m); + if (TAILQ_EMPTY(&loader->task_list)) { + done = 1; + } + SCMutexUnlock(&loader->m); + } + SCMutexLock(&loader->m); + if (loader->result != 0) { + errors++; + loader->result = 0; + } + SCMutexUnlock(&loader->m); + + } + if (errors) { + SCLogError(SC_ERR_INITIALIZATION, "%d loaders reported errors", errors); + return -1; + } + SCLogDebug("done"); + return 0; +} + +void DetectLoaderInit(DetectLoaderControl *loader) +{ + memset(loader, 0x00, sizeof(*loader)); + SCMutexInit(&loader->m, NULL); + TAILQ_INIT(&loader->task_list); +} + +void DetectLoadersInit(void) +{ + int i; + for (i = 0; i < NLOADERS; i++) { + DetectLoaderInit(&loaders[i]); + } +} + +typedef struct TenantLoaderCtx_ { + uint32_t tenant_id; + const char *yaml; +} TenantLoaderCtx; + +static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id) +{ + TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx; + +/* TODO we need to somehow store the loader id for when we free */ + if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) { + return -1; + } + return 0; +} + +int DetectLoaderSetupLoadTenant(uint32_t tenant_id, const char *yaml) +{ + TenantLoaderCtx *t = SCCalloc(1, sizeof(*t)); + if (t == NULL) + return -ENOMEM; + + t->tenant_id = tenant_id; + t->yaml = yaml; + + return DetectLoaderQueueTask(-1, DetectLoaderFuncLoadTenant, t); +} + +/** + * \brief Unpauses all threads present in tv_root + */ +void TmThreadWakeupDetectLoaderThreads() +{ + ThreadVars *tv = NULL; + int i = 0; + + SCMutexLock(&tv_root_lock); + for (i = 0; i < TVT_MAX; i++) { + tv = tv_root[i]; + while (tv != NULL) { + if (strcmp(tv->name,"DetectLoader") == 0) { + BUG_ON(tv->ctrl_cond == NULL); + pthread_cond_broadcast(tv->ctrl_cond); + } + tv = tv->next; + } + } + SCMutexUnlock(&tv_root_lock); + + return; +} + +/** + * \brief Unpauses all threads present in tv_root + */ +void TmThreadContinueDetectLoaderThreads() +{ + ThreadVars *tv = NULL; + int i = 0; + + SCMutexLock(&tv_root_lock); + for (i = 0; i < TVT_MAX; i++) { + tv = tv_root[i]; + while (tv != NULL) { + if (strcmp(tv->name,"DetectLoader") == 0) + TmThreadContinue(tv); + + tv = tv->next; + } + } + SCMutexUnlock(&tv_root_lock); + + return; +} + + +SC_ATOMIC_DECLARE(int, detect_loader_cnt); + +typedef struct DetectLoaderThreadData_ { + uint32_t instance; +} DetectLoaderThreadData; + +static TmEcode DetectLoaderThreadInit(ThreadVars *t, void *initdata, void **data) +{ + DetectLoaderThreadData *ftd = SCCalloc(1, sizeof(DetectLoaderThreadData)); + if (ftd == NULL) + return TM_ECODE_FAILED; + + ftd->instance = SC_ATOMIC_ADD(detect_loader_cnt, 1) - 1; /* id's start at 0 */ + SCLogDebug("detect loader instance %u", ftd->instance); + + /* pass thread data back to caller */ + *data = ftd; + + return TM_ECODE_OK; +} + +static TmEcode DetectLoaderThreadDeinit(ThreadVars *t, void *data) +{ + SCFree(data); + return TM_ECODE_OK; +} + + +static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data) +{ + /* block usr2. usr2 to be handled by the main thread only */ + UtilSignalBlock(SIGUSR2); + + DetectLoaderThreadData *ftd = (DetectLoaderThreadData *)thread_data; + BUG_ON(ftd == NULL); + + SCLogDebug("loader thread started"); + while (1) + { + if (TmThreadsCheckFlag(th_v, THV_PAUSE)) { + TmThreadsSetFlag(th_v, THV_PAUSED); + TmThreadTestThreadUnPaused(th_v); + TmThreadsUnsetFlag(th_v, THV_PAUSED); + } + + /* see if we have tasks */ + + DetectLoaderControl *loader = &loaders[ftd->instance]; + SCMutexLock(&loader->m); + + DetectLoaderTask *task = NULL, *tmptask = NULL; + TAILQ_FOREACH_SAFE(task, &loader->task_list, next, tmptask) { + int r = task->Func(task->ctx, ftd->instance); + loader->result |= r; + TAILQ_REMOVE(&loader->task_list, task, next); + SCFree(task); + } + + SCMutexUnlock(&loader->m); + + if (TmThreadsCheckFlag(th_v, THV_KILL)) { + break; + } + + /* just wait until someone wakes us up */ + SCCtrlMutexLock(th_v->ctrl_mutex); + SCCtrlCondWait(th_v->ctrl_cond, th_v->ctrl_mutex); + SCCtrlMutexUnlock(th_v->ctrl_mutex); + + SCLogDebug("woke up..."); + } + return TM_ECODE_OK; +} + +/** \brief spawn the detect loader manager thread */ +void DetectLoaderThreadSpawn() +{ + uint32_t u; + for (u = 0; u < NLOADERS; u++) { + ThreadVars *tv_loader = NULL; + + char name[32] = ""; + snprintf(name, sizeof(name), "DetectLoader%02u", u+1); + + tv_loader = TmThreadCreateCmdThreadByName("DetectLoader", + "DetectLoader", 1); + BUG_ON(tv_loader == NULL); + + if (tv_loader == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(1); + } + if (TmThreadSpawn(tv_loader) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(1); + } + } + return; +} + +void TmModuleDetectLoaderRegister (void) +{ + tmm_modules[TMM_DETECTLOADER].name = "DetectLoader"; + tmm_modules[TMM_DETECTLOADER].ThreadInit = DetectLoaderThreadInit; + tmm_modules[TMM_DETECTLOADER].ThreadDeinit = DetectLoaderThreadDeinit; + tmm_modules[TMM_DETECTLOADER].Management = DetectLoader; + tmm_modules[TMM_DETECTLOADER].cap_flags = 0; + tmm_modules[TMM_DETECTLOADER].flags = TM_FLAG_MANAGEMENT_TM; + SCLogDebug("%s registered", tmm_modules[TMM_DETECTLOADER].name); + + SC_ATOMIC_INIT(detect_loader_cnt); +} + /** * \brief setup multi-detect / multi-tenancy * @@ -1761,6 +2056,11 @@ void DetectEngineMultiTenantSetup(void) int enabled = 0; (void)ConfGetBool("multi-detect.enabled", &enabled); if (enabled == 1) { + DetectLoadersInit(); + TmModuleDetectLoaderRegister(); + DetectLoaderThreadSpawn(); + TmThreadContinueDetectLoaderThreads(); + SCMutexLock(&master->lock); master->multi_tenant_enabled = 1; @@ -1858,7 +2158,7 @@ void DetectEngineMultiTenantSetup(void) } SCLogInfo("tenant id: %u, %s", tenant_id, yaml_node->val); - if (DetectEngineMultiTenantLoadTenant(tenant_id, yaml_node->val) != 0) { + if (DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val) != 0) { /* error logged already */ goto bad_tenant; } @@ -1869,6 +2169,11 @@ void DetectEngineMultiTenantSetup(void) goto error; } } + + /* wait for our loaders to complete their tasks */ + if (DetectLoadersSync() != 0) + goto error; + if (DetectEngineMTApply() < 0) { SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); goto error; diff --git a/src/detect-engine.h b/src/detect-engine.h index ee2d89de0af5..c9ee62e82ef8 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -86,7 +86,7 @@ int DetectEngineReloadIsStart(void); void DetectEngineReloadSetDone(void); int DetectEngineReloadIsDone(void); -int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename); +int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id); int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id); int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id); diff --git a/src/detect.h b/src/detect.h index 2ebfb43f96d4..590ce24c6b41 100644 --- a/src/detect.h +++ b/src/detect.h @@ -719,6 +719,10 @@ typedef struct DetectEngineCtx_ { 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; + } DetectEngineCtx; /* Engine groups profiles (low, medium, high, custom) */ diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index bc3e2955c371..1fdd49dfb224 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -639,7 +639,7 @@ TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data) SCLogDebug("add-tenant: %d %s", tenant_id, filename); /* 3 load into the system */ - if (DetectEngineMultiTenantLoadTenant(tenant_id, filename) != 0) { + if (DetectEngineMultiTenantLoadTenant(tenant_id, filename, -1) != 0) { json_object_set_new(answer, "message", json_string("adding tenant failed")); return TM_ECODE_FAILED; } diff --git a/src/tm-modules.c b/src/tm-modules.c index c6f8c9ac76d6..73e9f235fd9d 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -269,6 +269,7 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_FLOWMANAGER); CASE_CODE (TMM_FLOWRECYCLER); CASE_CODE (TMM_UNIXMANAGER); + CASE_CODE (TMM_DETECTLOADER); CASE_CODE (TMM_LUALOG); CASE_CODE (TMM_LOGSTATSLOG); CASE_CODE (TMM_RECEIVENETMAP); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index e59c2a8764f7..f6629eaa82e5 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -104,6 +104,7 @@ typedef enum { TMM_FLOWMANAGER, TMM_FLOWRECYCLER, + TMM_DETECTLOADER, TMM_UNIXMANAGER, From b7b27684c2e093c0f67adbfa9af0400f7104ac3b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 May 2015 15:35:47 +0200 Subject: [PATCH 0687/2553] multi-detect: detect loader for unix socket Move the tenant load and reload commands to be executed by the detect loader thread(s). Limitation: no yaml parsing in parallel. The Conf API is currently not thread safe, so don't load the tenant config (yaml) in parallel. --- src/detect-engine.c | 138 +++++++++++++++++++++++++++++++++++--- src/detect-engine.h | 3 +- src/runmode-unix-socket.c | 45 +++++-------- 3 files changed, 147 insertions(+), 39 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 305f939f9f07..d97e6eaa81f5 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1673,7 +1673,8 @@ int DetectEngineMultiTenantEnabled(void) return (master->multi_tenant_enabled); } -/** \brief load a tenant from a yaml file +/** \internal + * \brief load a tenant from a yaml file * * \param tenant_id the tenant id by which the config is known * \param filename full path of a yaml file @@ -1682,7 +1683,7 @@ int DetectEngineMultiTenantEnabled(void) * \retval 0 ok * \retval -1 failed */ -int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id) +static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id) { DetectEngineCtx *de_ctx = NULL; char prefix[64]; @@ -1708,11 +1709,6 @@ int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, goto error; } - if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename); - goto error; - } - ConfNode *node = ConfGetNode(prefix); if (node == NULL) { SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename); @@ -1728,6 +1724,7 @@ int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix); de_ctx->tenant_id = tenant_id; + de_ctx->loader_id = loader_id; if (SigLoadSignatures(de_ctx, NULL, 0) < 0) { SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); @@ -1745,6 +1742,59 @@ int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, return -1; } +static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *filename, int reload_cnt) +{ + DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id); + if (old_de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "tenant detect engine not found"); + return -1; + } + + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt); + reload_cnt++; + SCLogInfo("prefix %s", prefix); + + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { + SCLogError(SC_ERR_INITIALIZATION,"failed to load yaml"); + goto error; + } + + ConfNode *node = ConfGetNode(prefix); + if (node == NULL) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename); + goto error; + } + + DetectEngineCtx *new_de_ctx = DetectEngineCtxInitWithPrefix(prefix); + if (new_de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " + "context failed."); + goto error; + } + SCLogDebug("de_ctx %p with prefix %s", new_de_ctx, new_de_ctx->config_prefix); + + new_de_ctx->tenant_id = tenant_id; + new_de_ctx->loader_id = old_de_ctx->loader_id; + + if (SigLoadSignatures(new_de_ctx, NULL, 0) < 0) { + SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); + goto error; + } + + DetectEngineAddToMaster(new_de_ctx); + + /* move to free list */ + DetectEngineMoveToFreeList(old_de_ctx); + DetectEngineDeReference(&old_de_ctx); + return 0; + +error: + DetectEngineDeReference(&old_de_ctx); + return -1; +} + + /** * \param ctx function specific data * \param loader_id id of the loader that executed the task @@ -1852,6 +1902,7 @@ void DetectLoadersInit(void) typedef struct TenantLoaderCtx_ { uint32_t tenant_id; + int reload_cnt; /**< used by reload */ const char *yaml; } TenantLoaderCtx; @@ -1859,7 +1910,7 @@ static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id) { TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx; -/* TODO we need to somehow store the loader id for when we free */ + SCLogInfo("loader %d", loader_id); if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) { return -1; } @@ -1878,6 +1929,67 @@ int DetectLoaderSetupLoadTenant(uint32_t tenant_id, const char *yaml) return DetectLoaderQueueTask(-1, DetectLoaderFuncLoadTenant, t); } +static int DetectLoaderFuncReloadTenant(void *vctx, int loader_id) +{ + TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx; + + SCLogDebug("loader_id %d", loader_id); + + if (DetectEngineMultiTenantReloadTenant(ctx->tenant_id, ctx->yaml, ctx->reload_cnt) != 0) { + return -1; + } + return 0; +} + +int DetectLoaderSetupReloadTenant(uint32_t tenant_id, const char *yaml, int reload_cnt) +{ + DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id); + if (old_de_ctx == NULL) + return -ENOENT; + int loader_id = old_de_ctx->loader_id; + DetectEngineDeReference(&old_de_ctx); + + TenantLoaderCtx *t = SCCalloc(1, sizeof(*t)); + if (t == NULL) + return -ENOMEM; + + t->tenant_id = tenant_id; + t->yaml = yaml; + t->reload_cnt = reload_cnt; + + SCLogDebug("loader_id %d", loader_id); + + return DetectLoaderQueueTask(loader_id, DetectLoaderFuncReloadTenant, t); +} + +/** \brief Load a tenant and wait for loading to complete + */ +int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml) +{ + int r = DetectLoaderSetupLoadTenant(tenant_id, yaml); + if (r < 0) + return r; + + if (DetectLoadersSync() != 0) + return -1; + + return 0; +} + +/** \brief Reload a tenant and wait for loading to complete + */ +int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt) +{ + int r = DetectLoaderSetupReloadTenant(tenant_id, yaml, reload_cnt); + if (r < 0) + return r; + + if (DetectLoadersSync() != 0) + return -1; + + return 0; +} + /** * \brief Unpauses all threads present in tv_root */ @@ -1997,6 +2109,7 @@ static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data) SCLogDebug("woke up..."); } + return TM_ECODE_OK; } @@ -2158,6 +2271,15 @@ void DetectEngineMultiTenantSetup(void) } SCLogInfo("tenant id: %u, %s", tenant_id, yaml_node->val); + /* setup the yaml in this loop so that it's not done by the loader + * threads. ConfYamlLoadFileWithPrefix is not thread safe. */ + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); + if (ConfYamlLoadFileWithPrefix(yaml_node->val, prefix) != 0) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", yaml_node->val); + goto bad_tenant; + } + if (DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val) != 0) { /* error logged already */ goto bad_tenant; diff --git a/src/detect-engine.h b/src/detect-engine.h index c9ee62e82ef8..ce4862134d01 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -86,7 +86,8 @@ int DetectEngineReloadIsStart(void); void DetectEngineReloadSetDone(void); int DetectEngineReloadIsDone(void); -int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id); +int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml); +int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt); int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id); int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id); diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 1fdd49dfb224..06a71869d495 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -638,8 +638,18 @@ TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data) SCLogDebug("add-tenant: %d %s", tenant_id, filename); + /* setup the yaml in this loop so that it's not done by the loader + * threads. ConfYamlLoadFileWithPrefix is not thread safe. */ + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename); + json_object_set_new(answer, "message", json_string("failed to load yaml")); + return TM_ECODE_FAILED; + } + /* 3 load into the system */ - if (DetectEngineMultiTenantLoadTenant(tenant_id, filename, -1) != 0) { + if (DetectEngineLoadTenantBlocking(tenant_id, filename) != 0) { json_object_set_new(answer, "message", json_string("adding tenant failed")); return TM_ECODE_FAILED; } @@ -704,15 +714,8 @@ TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data) SCLogDebug("reload-tenant: %d %s", tenant_id, filename); - DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id); - if (old_de_ctx == NULL) { - json_object_set_new(answer, "message", json_string("tenant detect engine not found")); - return TM_ECODE_FAILED; - } - char prefix[64]; snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt); - reload_cnt++; SCLogInfo("prefix %s", prefix); if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { @@ -720,31 +723,13 @@ TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data) return TM_ECODE_FAILED; } - ConfNode *node = ConfGetNode(prefix); - if (node == NULL) { - json_object_set_new(answer, "message", json_string("failed to properly setup yaml")); - return TM_ECODE_FAILED; - } - - DetectEngineCtx *new_de_ctx = DetectEngineCtxInitWithPrefix(prefix); - if (new_de_ctx == NULL) { - json_object_set_new(answer, "message", json_string("initializing detection engine failed")); - return TM_ECODE_FAILED; - } - SCLogDebug("de_ctx %p with prefix %s", new_de_ctx, new_de_ctx->config_prefix); - - new_de_ctx->tenant_id = tenant_id; - - if (SigLoadSignatures(new_de_ctx, NULL, 0) < 0) { - json_object_set_new(answer, "message", json_string("loading rules failed")); + /* 3 load into the system */ + if (DetectEngineReloadTenantBlocking(tenant_id, filename, reload_cnt) != 0) { + json_object_set_new(answer, "message", json_string("reload tenant failed")); return TM_ECODE_FAILED; } - DetectEngineAddToMaster(new_de_ctx); - - /* move to free list */ - DetectEngineMoveToFreeList(old_de_ctx); - DetectEngineDeReference(&old_de_ctx); + reload_cnt++; /* apply to the running system */ if (DetectEngineMTApply() < 0) { From 99c0a7ad72fbe9ca3ffe7905eebafd8bb418bc5a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 19 May 2015 15:14:49 +0200 Subject: [PATCH 0688/2553] multi-detect: improve memory handling of setup code --- src/detect-engine.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index d97e6eaa81f5..02b1f70beb20 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2681,6 +2681,8 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) uint32_t map_cnt = 0; int max_tenant_id = 0; DetectEngineCtx *list = master->list; + HashTable *mt_det_ctxs_hash = NULL; + DetectEngineThreadCtx *det_ctx = NULL; if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) { SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: " @@ -2697,8 +2699,10 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) tcnt++; } - HashTable *mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree); - BUG_ON(mt_det_ctxs_hash == NULL); + mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree); + if (mt_det_ctxs_hash == NULL) { + goto error; + } if (max_tenant_id == 0) { SCLogInfo("no tenants left, or none registered yet"); @@ -2744,11 +2748,12 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) } } - DetectEngineThreadCtx *det_ctx = SCCalloc(1, sizeof(DetectEngineThreadCtx)); + det_ctx = SCCalloc(1, sizeof(DetectEngineThreadCtx)); if (det_ctx == NULL) { goto error; } det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash; + mt_det_ctxs_hash = NULL; /* first register the counter. In delayed detect mode we exit right after if the * rules haven't been loaded yet. */ @@ -2788,6 +2793,11 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) return det_ctx; error: + if (map_array != NULL) + SCFree(map_array); + if (mt_det_ctxs_hash != NULL) + HashTableFree(mt_det_ctxs_hash); + return NULL; } From e44fd97d720801d2d1796bad3ad392831a76c4ed Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Jul 2015 15:57:26 +0200 Subject: [PATCH 0689/2553] unittests: use a global packetpool --- src/alert-unified2-alert.c | 1 - src/flow-manager.c | 4 ---- src/runmode-unittests.c | 6 ++++++ 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 26bacb28cc31..ede624c4f3bf 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -1949,7 +1949,6 @@ static int Unified2TestRotate01(void) */ void Unified2RegisterTests(void) { - PacketPoolInit(); #ifdef UNITTESTS UtRegisterTest("Unified2Test01 -- Ipv4 test", Unified2Test01, 1); UtRegisterTest("Unified2Test02 -- Ipv6 test", Unified2Test02, 1); diff --git a/src/flow-manager.c b/src/flow-manager.c index 411dcbc88cee..15ad6162a0f1 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -1228,10 +1228,7 @@ static int FlowMgrTest04 (void) static int FlowMgrTest05 (void) { int result = 0; - extern intmax_t max_pending_packets; - max_pending_packets = 128; - PacketPoolInit(); FlowInitConfig(FLOW_QUIET); FlowConfig backup; memcpy(&backup, &flow_config, sizeof(FlowConfig)); @@ -1269,7 +1266,6 @@ static int FlowMgrTest05 (void) memcpy(&flow_config, &backup, sizeof(FlowConfig)); FlowShutdown(); - PacketPoolDestroy(); return result; } #endif /* UNITTESTS */ diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 93fd7f0b0853..4f3fc8bf7dc1 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -280,7 +280,13 @@ void RunUnittests(int list_unittests, char *regex_arg) if (list_unittests) { UtListTests(regex_arg); } else { + /* global packet pool */ + extern intmax_t max_pending_packets; + max_pending_packets = 128; + PacketPoolInit(); + uint32_t failed = UtRunTests(regex_arg); + PacketPoolDestroy(); UtCleanup(); #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) From f871c0e1b80e0712bf5dd43cc1799561c5ad42c2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 22 Apr 2015 12:41:57 +0200 Subject: [PATCH 0690/2553] debug: packet pool init/destroy validation Validate packet pool handling: - pools are initialized before use - pools are not used after destroy - pools are not double initialized/destroyed --- src/tmqh-packetpool.c | 36 +++++++++++++++++++++++++++++++++++- src/tmqh-packetpool.h | 12 ++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index 4c4bf40691af..a1f19dca467c 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -241,7 +241,10 @@ static void PacketPoolGetReturnedPackets(PktPool *pool) Packet *PacketPoolGetPacket(void) { PktPool *pool = GetThreadPacketPool(); - +#ifdef DEBUG_VALIDATION + BUG_ON(pool->initialized == 0); + BUG_ON(pool->destroyed == 1); +#endif /* DEBUG_VALIDATION */ if (pool->head) { /* Stack is not empty. */ Packet *p = pool->head; @@ -286,6 +289,12 @@ void PacketPoolReturnPacket(Packet *p) PacketFree(p); return; } +#ifdef DEBUG_VALIDATION + BUG_ON(pool->initialized == 0); + BUG_ON(pool->destroyed == 1); + BUG_ON(my_pool->initialized == 0); + BUG_ON(my_pool->destroyed == 1); +#endif /* DEBUG_VALIDATION */ if (pool == my_pool) { /* Push back onto this thread's own stack, so no locking. */ @@ -338,6 +347,12 @@ void PacketPoolInitEmpty(void) PktPool *my_pool = GetThreadPacketPool(); +#ifdef DEBUG_VALIDATION + BUG_ON(my_pool->initialized); + my_pool->initialized = 1; + my_pool->destroyed = 0; +#endif /* DEBUG_VALIDATION */ + SCMutexInit(&my_pool->return_stack.mutex, NULL); SCCondInit(&my_pool->return_stack.cond, NULL); SC_ATOMIC_INIT(my_pool->return_stack.sync_now); @@ -353,6 +368,12 @@ void PacketPoolInit(void) PktPool *my_pool = GetThreadPacketPool(); +#ifdef DEBUG_VALIDATION + BUG_ON(my_pool->initialized); + my_pool->initialized = 1; + my_pool->destroyed = 0; +#endif /* DEBUG_VALIDATION */ + SCMutexInit(&my_pool->return_stack.mutex, NULL); SCCondInit(&my_pool->return_stack.cond, NULL); SC_ATOMIC_INIT(my_pool->return_stack.sync_now); @@ -371,12 +392,18 @@ void PacketPoolInit(void) } SCLogInfo("preallocated %"PRIiMAX" packets. Total memory %"PRIuMAX"", max_pending_packets, (uintmax_t)(max_pending_packets*SIZE_OF_PACKET)); + } void PacketPoolDestroy(void) { Packet *p = NULL; PktPool *my_pool = GetThreadPacketPool(); + +#ifdef DEBUG_VALIDATION + BUG_ON(my_pool->destroyed); +#endif /* DEBUG_VALIDATION */ + if (my_pool && my_pool->pending_pool != NULL) { p = my_pool->pending_head; while (p) { @@ -385,7 +412,9 @@ void PacketPoolDestroy(void) p = next_p; my_pool->pending_count--; } +#ifdef DEBUG_VALIDATION BUG_ON(my_pool->pending_count); +#endif /* DEBUG_VALIDATION */ my_pool->pending_pool = NULL; my_pool->pending_head = NULL; my_pool->pending_tail = NULL; @@ -396,6 +425,11 @@ void PacketPoolDestroy(void) } SC_ATOMIC_DESTROY(my_pool->return_stack.sync_now); + +#ifdef DEBUG_VALIDATION + my_pool->initialized = 0; + my_pool->destroyed = 1; +#endif /* DEBUG_VALIDATION */ } Packet *TmqhInputPacketpool(ThreadVars *tv) diff --git a/src/tmqh-packetpool.h b/src/tmqh-packetpool.h index 12a3f5cabdd4..ab45184c654f 100644 --- a/src/tmqh-packetpool.h +++ b/src/tmqh-packetpool.h @@ -38,7 +38,7 @@ typedef struct PktPoolLockedStack_{ } __attribute__((aligned(CLS))) PktPoolLockedStack; typedef struct PktPool_ { - /* link listed of free packets local to this thread. + /* link listed of free packets local to this thread. * No mutex is needed. */ Packet *head; @@ -51,8 +51,13 @@ typedef struct PktPool_ { Packet *pending_head; Packet *pending_tail; uint32_t pending_count; - - /* All members above this point are accessed locally by only one thread, so + +#ifdef DEBUG_VALIDATION + int initialized; + int destroyed; +#endif /* DEBUG_VALIDATION */ + + /* All members above this point are accessed locally by only one thread, so * these should live on their own cache line. */ @@ -60,7 +65,6 @@ typedef struct PktPool_ { * to this thread. */ PktPoolLockedStack return_stack; - } PktPool; Packet *TmqhInputPacketpool(ThreadVars *); From cfeaf42caba71f8f34a506758866146f95ff9f5b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Jul 2015 18:08:37 +0200 Subject: [PATCH 0691/2553] detect-loaders: configurable amount of loaders --- src/detect-engine.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 02b1f70beb20..7761bebefdf8 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1815,9 +1815,10 @@ typedef struct DetectLoaderControl_ { } DetectLoaderControl; #define NLOADERS 4 -static DetectLoaderControl loaders[NLOADERS]; +static DetectLoaderControl *loaders = NULL; static int cur_loader = 0; void TmThreadWakeupDetectLoaderThreads(void); +static int num_loaders = NLOADERS; /** \param loader -1 for auto select * \retval loader_id or negative in case of error */ @@ -1826,10 +1827,10 @@ int DetectLoaderQueueTask(int loader_id, LoaderFunc Func, void *func_ctx) if (loader_id == -1) { loader_id = cur_loader; cur_loader++; - if (cur_loader >= NLOADERS) + if (cur_loader >= num_loaders) cur_loader = 0; } - if (loader_id >= NLOADERS || loader_id < 0) { + if (loader_id >= num_loaders || loader_id < 0) { return -ERANGE; } @@ -1859,7 +1860,7 @@ int DetectLoadersSync(void) SCLogDebug("waiting"); int errors = 0; int i; - for (i = 0; i < NLOADERS; i++) { + for (i = 0; i < num_loaders; i++) { int done = 0; DetectLoaderControl *loader = &loaders[i]; while (!done) { @@ -1894,8 +1895,24 @@ void DetectLoaderInit(DetectLoaderControl *loader) void DetectLoadersInit(void) { + intmax_t setting = NLOADERS; + (void)ConfGetInt("multi-detect.loaders", &setting); + + if (setting < 1 || setting > 1024) { + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "invalid multi-detect.loaders setting %"PRIdMAX, setting); + exit(EXIT_FAILURE); + } + num_loaders = (int32_t)setting; + + SCLogInfo("using %d detect loader threads", num_loaders); + + BUG_ON(loaders != NULL); + loaders = SCCalloc(num_loaders, sizeof(DetectLoaderControl)); + BUG_ON(loaders == NULL); + int i; - for (i = 0; i < NLOADERS; i++) { + for (i = 0; i < num_loaders; i++) { DetectLoaderInit(&loaders[i]); } } @@ -2116,12 +2133,12 @@ static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data) /** \brief spawn the detect loader manager thread */ void DetectLoaderThreadSpawn() { - uint32_t u; - for (u = 0; u < NLOADERS; u++) { + int i; + for (i = 0; i < num_loaders; i++) { ThreadVars *tv_loader = NULL; char name[32] = ""; - snprintf(name, sizeof(name), "DetectLoader%02u", u+1); + snprintf(name, sizeof(name), "DetectLoader%02d", i+1); tv_loader = TmThreadCreateCmdThreadByName("DetectLoader", "DetectLoader", 1); From 979bd3527799e657ce6084297e7a78999bc7f9e1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Jul 2015 19:55:38 +0200 Subject: [PATCH 0692/2553] detect loader: move to own file --- src/Makefile.am | 1 + src/detect-engine-loader.c | 300 +++++++++++++++++++++++++++++++++++++ src/detect-engine-loader.h | 57 +++++++ src/detect-engine.c | 286 +---------------------------------- 4 files changed, 360 insertions(+), 284 deletions(-) create mode 100644 src/detect-engine-loader.c create mode 100644 src/detect-engine-loader.h diff --git a/src/Makefile.am b/src/Makefile.am index 64ade1591240..e61e2ffa00c2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -112,6 +112,7 @@ detect-engine-hscd.c detect-engine-hscd.h \ detect-engine-hsmd.c detect-engine-hsmd.h \ detect-engine-hua.c detect-engine-hua.h \ detect-engine-iponly.c detect-engine-iponly.h \ +detect-engine-loader.c detect-engine-loader.h \ detect-engine-mpm.c detect-engine-mpm.h \ detect-engine-payload.c detect-engine-payload.h \ detect-engine-port.c detect-engine-port.h \ diff --git a/src/detect-engine-loader.c b/src/detect-engine-loader.c new file mode 100644 index 000000000000..b360cd0406b3 --- /dev/null +++ b/src/detect-engine-loader.c @@ -0,0 +1,300 @@ +/* Copyright (C) 2015 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 + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "conf.h" +#include "debug.h" +#include "detect.h" +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "queue.h" +#include "util-signal.h" + +#include "detect-engine-loader.h" + +#define NLOADERS 4 +static DetectLoaderControl *loaders = NULL; +static int cur_loader = 0; +void TmThreadWakeupDetectLoaderThreads(void); +static int num_loaders = NLOADERS; + +/** \param loader -1 for auto select + * \retval loader_id or negative in case of error */ +int DetectLoaderQueueTask(int loader_id, LoaderFunc Func, void *func_ctx) +{ + if (loader_id == -1) { + loader_id = cur_loader; + cur_loader++; + if (cur_loader >= num_loaders) + cur_loader = 0; + } + if (loader_id >= num_loaders || loader_id < 0) { + return -ERANGE; + } + + DetectLoaderControl *loader = &loaders[loader_id]; + + DetectLoaderTask *t = SCCalloc(1, sizeof(*t)); + if (t == NULL) + return -ENOMEM; + + t->Func = Func; + t->ctx = func_ctx; + + SCMutexLock(&loader->m); + TAILQ_INSERT_TAIL(&loader->task_list, t, next); + SCMutexUnlock(&loader->m); + + TmThreadWakeupDetectLoaderThreads(); + + SCLogDebug("%d %p %p", loader_id, Func, func_ctx); + return loader_id; +} + +/** \brief wait for loader tasks to complete + * \retval result 0 for ok, -1 for errors */ +int DetectLoadersSync(void) +{ + SCLogDebug("waiting"); + int errors = 0; + int i; + for (i = 0; i < num_loaders; i++) { + int done = 0; + DetectLoaderControl *loader = &loaders[i]; + while (!done) { + SCMutexLock(&loader->m); + if (TAILQ_EMPTY(&loader->task_list)) { + done = 1; + } + SCMutexUnlock(&loader->m); + } + SCMutexLock(&loader->m); + if (loader->result != 0) { + errors++; + loader->result = 0; + } + SCMutexUnlock(&loader->m); + + } + if (errors) { + SCLogError(SC_ERR_INITIALIZATION, "%d loaders reported errors", errors); + return -1; + } + SCLogDebug("done"); + return 0; +} + +static void DetectLoaderInit(DetectLoaderControl *loader) +{ + memset(loader, 0x00, sizeof(*loader)); + SCMutexInit(&loader->m, NULL); + TAILQ_INIT(&loader->task_list); +} + +void DetectLoadersInit(void) +{ + intmax_t setting = NLOADERS; + (void)ConfGetInt("multi-detect.loaders", &setting); + + if (setting < 1 || setting > 1024) { + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "invalid multi-detect.loaders setting %"PRIdMAX, setting); + exit(EXIT_FAILURE); + } + num_loaders = (int32_t)setting; + + SCLogInfo("using %d detect loader threads", num_loaders); + + BUG_ON(loaders != NULL); + loaders = SCCalloc(num_loaders, sizeof(DetectLoaderControl)); + BUG_ON(loaders == NULL); + + int i; + for (i = 0; i < num_loaders; i++) { + DetectLoaderInit(&loaders[i]); + } +} + +/** + * \brief Unpauses all threads present in tv_root + */ +void TmThreadWakeupDetectLoaderThreads() +{ + ThreadVars *tv = NULL; + int i = 0; + + SCMutexLock(&tv_root_lock); + for (i = 0; i < TVT_MAX; i++) { + tv = tv_root[i]; + while (tv != NULL) { + if (strcmp(tv->name,"DetectLoader") == 0) { + BUG_ON(tv->ctrl_cond == NULL); + pthread_cond_broadcast(tv->ctrl_cond); + } + tv = tv->next; + } + } + SCMutexUnlock(&tv_root_lock); + + return; +} + +/** + * \brief Unpauses all threads present in tv_root + */ +void TmThreadContinueDetectLoaderThreads() +{ + ThreadVars *tv = NULL; + int i = 0; + + SCMutexLock(&tv_root_lock); + for (i = 0; i < TVT_MAX; i++) { + tv = tv_root[i]; + while (tv != NULL) { + if (strcmp(tv->name,"DetectLoader") == 0) + TmThreadContinue(tv); + + tv = tv->next; + } + } + SCMutexUnlock(&tv_root_lock); + + return; +} + + +SC_ATOMIC_DECLARE(int, detect_loader_cnt); + +typedef struct DetectLoaderThreadData_ { + uint32_t instance; +} DetectLoaderThreadData; + +static TmEcode DetectLoaderThreadInit(ThreadVars *t, void *initdata, void **data) +{ + DetectLoaderThreadData *ftd = SCCalloc(1, sizeof(DetectLoaderThreadData)); + if (ftd == NULL) + return TM_ECODE_FAILED; + + ftd->instance = SC_ATOMIC_ADD(detect_loader_cnt, 1) - 1; /* id's start at 0 */ + SCLogDebug("detect loader instance %u", ftd->instance); + + /* pass thread data back to caller */ + *data = ftd; + + return TM_ECODE_OK; +} + +static TmEcode DetectLoaderThreadDeinit(ThreadVars *t, void *data) +{ + SCFree(data); + return TM_ECODE_OK; +} + + +static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data) +{ + /* block usr2. usr2 to be handled by the main thread only */ + UtilSignalBlock(SIGUSR2); + + DetectLoaderThreadData *ftd = (DetectLoaderThreadData *)thread_data; + BUG_ON(ftd == NULL); + + SCLogDebug("loader thread started"); + while (1) + { + if (TmThreadsCheckFlag(th_v, THV_PAUSE)) { + TmThreadsSetFlag(th_v, THV_PAUSED); + TmThreadTestThreadUnPaused(th_v); + TmThreadsUnsetFlag(th_v, THV_PAUSED); + } + + /* see if we have tasks */ + + DetectLoaderControl *loader = &loaders[ftd->instance]; + SCMutexLock(&loader->m); + + DetectLoaderTask *task = NULL, *tmptask = NULL; + TAILQ_FOREACH_SAFE(task, &loader->task_list, next, tmptask) { + int r = task->Func(task->ctx, ftd->instance); + loader->result |= r; + TAILQ_REMOVE(&loader->task_list, task, next); + SCFree(task); + } + + SCMutexUnlock(&loader->m); + + if (TmThreadsCheckFlag(th_v, THV_KILL)) { + break; + } + + /* just wait until someone wakes us up */ + SCCtrlMutexLock(th_v->ctrl_mutex); + SCCtrlCondWait(th_v->ctrl_cond, th_v->ctrl_mutex); + SCCtrlMutexUnlock(th_v->ctrl_mutex); + + SCLogDebug("woke up..."); + } + + return TM_ECODE_OK; +} + +/** \brief spawn the detect loader manager thread */ +void DetectLoaderThreadSpawn() +{ + int i; + for (i = 0; i < num_loaders; i++) { + ThreadVars *tv_loader = NULL; + + char name[32] = ""; + snprintf(name, sizeof(name), "DetectLoader%02d", i+1); + + tv_loader = TmThreadCreateCmdThreadByName("DetectLoader", + "DetectLoader", 1); + BUG_ON(tv_loader == NULL); + + if (tv_loader == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(1); + } + if (TmThreadSpawn(tv_loader) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(1); + } + } + return; +} + +void TmModuleDetectLoaderRegister (void) +{ + tmm_modules[TMM_DETECTLOADER].name = "DetectLoader"; + tmm_modules[TMM_DETECTLOADER].ThreadInit = DetectLoaderThreadInit; + tmm_modules[TMM_DETECTLOADER].ThreadDeinit = DetectLoaderThreadDeinit; + tmm_modules[TMM_DETECTLOADER].Management = DetectLoader; + tmm_modules[TMM_DETECTLOADER].cap_flags = 0; + tmm_modules[TMM_DETECTLOADER].flags = TM_FLAG_MANAGEMENT_TM; + SCLogDebug("%s registered", tmm_modules[TMM_DETECTLOADER].name); + + SC_ATOMIC_INIT(detect_loader_cnt); +} diff --git a/src/detect-engine-loader.h b/src/detect-engine-loader.h new file mode 100644 index 000000000000..de28bdaf7751 --- /dev/null +++ b/src/detect-engine-loader.h @@ -0,0 +1,57 @@ +/* Copyright (C) 2015 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 + * + * Detect loader API, for using multiple 'loader' threads + * that can load multiple detection engines in parallel. + */ + +#ifndef __DETECT_ENGINE_LOADER_H__ +#define __DETECT_ENGINE_LOADER_H__ + +/** + * \param ctx function specific data + * \param loader_id id of the loader that executed the task + */ +typedef int (*LoaderFunc)(void *ctx, int loader_id); + +typedef struct DetectLoaderTask_ { + LoaderFunc Func; + void *ctx; + TAILQ_ENTRY(DetectLoaderTask_) next; +} DetectLoaderTask; + +typedef struct DetectLoaderControl_ { + int id; + int result; /* 0 for ok, error otherwise */ + SCMutex m; + TAILQ_HEAD(, DetectLoaderTask_) task_list; +} DetectLoaderControl; + +int DetectLoaderQueueTask(int loader_id, LoaderFunc Func, void *func_ctx); +int DetectLoadersSync(void); +void DetectLoadersInit(void); + +void TmThreadContinueDetectLoaderThreads(); +void DetectLoaderThreadSpawn(); +void TmModuleDetectLoaderRegister (void); + +#endif /* __DETECT_ENGINE_LOADER_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 7761bebefdf8..7de049693f97 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -71,6 +71,8 @@ #include "detect-uricontent.h" #include "detect-engine-threshold.h" +#include "detect-engine-loader.h" + #include "util-classification-config.h" #include "util-reference-config.h" #include "util-threshold-config.h" @@ -1795,128 +1797,6 @@ static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *f } -/** - * \param ctx function specific data - * \param loader_id id of the loader that executed the task - */ -typedef int (*LoaderFunc)(void *ctx, int loader_id); - -typedef struct DetectLoaderTask_ { - LoaderFunc Func; - void *ctx; - TAILQ_ENTRY(DetectLoaderTask_) next; -} DetectLoaderTask; - -typedef struct DetectLoaderControl_ { - int id; - int result; /* 0 for ok, error otherwise */ - SCMutex m; - TAILQ_HEAD(, DetectLoaderTask_) task_list; -} DetectLoaderControl; - -#define NLOADERS 4 -static DetectLoaderControl *loaders = NULL; -static int cur_loader = 0; -void TmThreadWakeupDetectLoaderThreads(void); -static int num_loaders = NLOADERS; - -/** \param loader -1 for auto select - * \retval loader_id or negative in case of error */ -int DetectLoaderQueueTask(int loader_id, LoaderFunc Func, void *func_ctx) -{ - if (loader_id == -1) { - loader_id = cur_loader; - cur_loader++; - if (cur_loader >= num_loaders) - cur_loader = 0; - } - if (loader_id >= num_loaders || loader_id < 0) { - return -ERANGE; - } - - DetectLoaderControl *loader = &loaders[loader_id]; - - DetectLoaderTask *t = SCCalloc(1, sizeof(*t)); - if (t == NULL) - return -ENOMEM; - - t->Func = Func; - t->ctx = func_ctx; - - SCMutexLock(&loader->m); - TAILQ_INSERT_TAIL(&loader->task_list, t, next); - SCMutexUnlock(&loader->m); - - TmThreadWakeupDetectLoaderThreads(); - - SCLogDebug("%d %p %p", loader_id, Func, func_ctx); - return loader_id; -} - -/** \brief wait for loader tasks to complete - * \retval result 0 for ok, -1 for errors */ -int DetectLoadersSync(void) -{ - SCLogDebug("waiting"); - int errors = 0; - int i; - for (i = 0; i < num_loaders; i++) { - int done = 0; - DetectLoaderControl *loader = &loaders[i]; - while (!done) { - SCMutexLock(&loader->m); - if (TAILQ_EMPTY(&loader->task_list)) { - done = 1; - } - SCMutexUnlock(&loader->m); - } - SCMutexLock(&loader->m); - if (loader->result != 0) { - errors++; - loader->result = 0; - } - SCMutexUnlock(&loader->m); - - } - if (errors) { - SCLogError(SC_ERR_INITIALIZATION, "%d loaders reported errors", errors); - return -1; - } - SCLogDebug("done"); - return 0; -} - -void DetectLoaderInit(DetectLoaderControl *loader) -{ - memset(loader, 0x00, sizeof(*loader)); - SCMutexInit(&loader->m, NULL); - TAILQ_INIT(&loader->task_list); -} - -void DetectLoadersInit(void) -{ - intmax_t setting = NLOADERS; - (void)ConfGetInt("multi-detect.loaders", &setting); - - if (setting < 1 || setting > 1024) { - SCLogError(SC_ERR_INVALID_ARGUMENTS, - "invalid multi-detect.loaders setting %"PRIdMAX, setting); - exit(EXIT_FAILURE); - } - num_loaders = (int32_t)setting; - - SCLogInfo("using %d detect loader threads", num_loaders); - - BUG_ON(loaders != NULL); - loaders = SCCalloc(num_loaders, sizeof(DetectLoaderControl)); - BUG_ON(loaders == NULL); - - int i; - for (i = 0; i < num_loaders; i++) { - DetectLoaderInit(&loaders[i]); - } -} - typedef struct TenantLoaderCtx_ { uint32_t tenant_id; int reload_cnt; /**< used by reload */ @@ -2007,168 +1887,6 @@ int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int r return 0; } -/** - * \brief Unpauses all threads present in tv_root - */ -void TmThreadWakeupDetectLoaderThreads() -{ - ThreadVars *tv = NULL; - int i = 0; - - SCMutexLock(&tv_root_lock); - for (i = 0; i < TVT_MAX; i++) { - tv = tv_root[i]; - while (tv != NULL) { - if (strcmp(tv->name,"DetectLoader") == 0) { - BUG_ON(tv->ctrl_cond == NULL); - pthread_cond_broadcast(tv->ctrl_cond); - } - tv = tv->next; - } - } - SCMutexUnlock(&tv_root_lock); - - return; -} - -/** - * \brief Unpauses all threads present in tv_root - */ -void TmThreadContinueDetectLoaderThreads() -{ - ThreadVars *tv = NULL; - int i = 0; - - SCMutexLock(&tv_root_lock); - for (i = 0; i < TVT_MAX; i++) { - tv = tv_root[i]; - while (tv != NULL) { - if (strcmp(tv->name,"DetectLoader") == 0) - TmThreadContinue(tv); - - tv = tv->next; - } - } - SCMutexUnlock(&tv_root_lock); - - return; -} - - -SC_ATOMIC_DECLARE(int, detect_loader_cnt); - -typedef struct DetectLoaderThreadData_ { - uint32_t instance; -} DetectLoaderThreadData; - -static TmEcode DetectLoaderThreadInit(ThreadVars *t, void *initdata, void **data) -{ - DetectLoaderThreadData *ftd = SCCalloc(1, sizeof(DetectLoaderThreadData)); - if (ftd == NULL) - return TM_ECODE_FAILED; - - ftd->instance = SC_ATOMIC_ADD(detect_loader_cnt, 1) - 1; /* id's start at 0 */ - SCLogDebug("detect loader instance %u", ftd->instance); - - /* pass thread data back to caller */ - *data = ftd; - - return TM_ECODE_OK; -} - -static TmEcode DetectLoaderThreadDeinit(ThreadVars *t, void *data) -{ - SCFree(data); - return TM_ECODE_OK; -} - - -static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data) -{ - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); - - DetectLoaderThreadData *ftd = (DetectLoaderThreadData *)thread_data; - BUG_ON(ftd == NULL); - - SCLogDebug("loader thread started"); - while (1) - { - if (TmThreadsCheckFlag(th_v, THV_PAUSE)) { - TmThreadsSetFlag(th_v, THV_PAUSED); - TmThreadTestThreadUnPaused(th_v); - TmThreadsUnsetFlag(th_v, THV_PAUSED); - } - - /* see if we have tasks */ - - DetectLoaderControl *loader = &loaders[ftd->instance]; - SCMutexLock(&loader->m); - - DetectLoaderTask *task = NULL, *tmptask = NULL; - TAILQ_FOREACH_SAFE(task, &loader->task_list, next, tmptask) { - int r = task->Func(task->ctx, ftd->instance); - loader->result |= r; - TAILQ_REMOVE(&loader->task_list, task, next); - SCFree(task); - } - - SCMutexUnlock(&loader->m); - - if (TmThreadsCheckFlag(th_v, THV_KILL)) { - break; - } - - /* just wait until someone wakes us up */ - SCCtrlMutexLock(th_v->ctrl_mutex); - SCCtrlCondWait(th_v->ctrl_cond, th_v->ctrl_mutex); - SCCtrlMutexUnlock(th_v->ctrl_mutex); - - SCLogDebug("woke up..."); - } - - return TM_ECODE_OK; -} - -/** \brief spawn the detect loader manager thread */ -void DetectLoaderThreadSpawn() -{ - int i; - for (i = 0; i < num_loaders; i++) { - ThreadVars *tv_loader = NULL; - - char name[32] = ""; - snprintf(name, sizeof(name), "DetectLoader%02d", i+1); - - tv_loader = TmThreadCreateCmdThreadByName("DetectLoader", - "DetectLoader", 1); - BUG_ON(tv_loader == NULL); - - if (tv_loader == NULL) { - printf("ERROR: TmThreadsCreate failed\n"); - exit(1); - } - if (TmThreadSpawn(tv_loader) != TM_ECODE_OK) { - printf("ERROR: TmThreadSpawn failed\n"); - exit(1); - } - } - return; -} - -void TmModuleDetectLoaderRegister (void) -{ - tmm_modules[TMM_DETECTLOADER].name = "DetectLoader"; - tmm_modules[TMM_DETECTLOADER].ThreadInit = DetectLoaderThreadInit; - tmm_modules[TMM_DETECTLOADER].ThreadDeinit = DetectLoaderThreadDeinit; - tmm_modules[TMM_DETECTLOADER].Management = DetectLoader; - tmm_modules[TMM_DETECTLOADER].cap_flags = 0; - tmm_modules[TMM_DETECTLOADER].flags = TM_FLAG_MANAGEMENT_TM; - SCLogDebug("%s registered", tmm_modules[TMM_DETECTLOADER].name); - - SC_ATOMIC_INIT(detect_loader_cnt); -} - /** * \brief setup multi-detect / multi-tenancy * From 1235c578b25e2e4ca0eb442dfbe962a7a2f22551 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Jul 2015 17:27:26 +0200 Subject: [PATCH 0693/2553] xff: support ports and more ipv6 notations It's not uncommon to see an header like: X-Forwarded-For: 1.2.3.4:56789 This patch recognizes this case and ignores the port. It also supports this for IPv6 if the address has the following notation: X-Forwarded-For: [12::34]:1234 This patch also adds unittests. --- src/app-layer-htp-xff.c | 182 ++++++++++++++++++++++++++++++++++++++-- src/app-layer-htp-xff.h | 2 + src/app-layer-htp.c | 4 +- 3 files changed, 180 insertions(+), 8 deletions(-) diff --git a/src/app-layer-htp-xff.c b/src/app-layer-htp-xff.c index 5be84bbdb75f..96c6de487f75 100644 --- a/src/app-layer-htp-xff.c +++ b/src/app-layer-htp-xff.c @@ -31,6 +31,7 @@ #include "util-misc.h" #include "util-memrchr.h" +#include "util-unittest.h" /** XFF header value minimal length */ #define XFF_CHAIN_MINLEN 7 @@ -39,6 +40,70 @@ /** Default XFF header name */ #define XFF_DEFAULT "X-Forwarded-For" +/** \internal + * \brief parse XFF string + * \param input input string, might be modified + * \param output output buffer + * \param output_size size of output buffer + * \retval bool 1 ok, 0 fail + */ +static int ParseXFFString(char *input, char *output, int output_size) +{ + size_t len = strlen(input); + if (len == 0) + return 0; + + if (input[0] == '[') { + char *end = strchr(input, ']'); + if (end == NULL) // malformed, not closed + return 0; + + if (end != input+(len - 1)) { + SCLogDebug("data after closing bracket"); + // if we ever want to parse the port, we can do it here + } + + /* done, lets wrap up */ + input++; // skip past [ + *end = '\0'; // overwrite ], ignore anything after + + } else { + /* lets see if the xff string ends in a port */ + int c = 0; + int d = 0; + char *p = input; + while (*p != '\0') { + if (*p == ':') + c++; + if (*p == '.') + d++; + p++; + } + /* 3 dots: ipv4, one ':' port */ + if (d == 3 && c == 1) { + SCLogDebug("XFF w port %s", input); + char *x = strchr(input, ':'); + if (x) { + *x = '\0'; + SCLogDebug("XFF w/o port %s", input); + // if we ever want to parse the port, we can do it here + } + } + } + + SCLogDebug("XFF %s", input); + + /** Sanity check on extracted IP for IPv4 and IPv6 */ + uint32_t ip[4]; + if (inet_pton(AF_INET, input, ip) == 1 || + inet_pton(AF_INET6, input, ip) == 1) + { + strlcpy(output, input, output_size); + return 1; // OK + } + return 0; +} + /** * \brief Function to return XFF IP if any in the selected transaction. The * caller needs to lock the flow. @@ -99,13 +164,7 @@ int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, HttpXFFCfg *xff_cfg, } p_xff = xff_chain; } - /** Sanity check on extracted IP for IPv4 and IPv6 */ - uint32_t ip[4]; - if ( inet_pton(AF_INET, (char *)p_xff, ip ) == 1 || - inet_pton(AF_INET6, (char *)p_xff, ip ) == 1 ) { - strlcpy(dstbuf, (char *)p_xff, dstbuflen); - return 1; // OK - } + return ParseXFFString((char *)p_xff, dstbuf, dstbuflen); } return 0; } @@ -194,3 +253,112 @@ void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result) result->flags = XFF_DISABLED; } } + + +#ifdef UNITTESTS +static int XFFTest01(void) { + char input[] = "1.2.3.4:5678"; + char output[16]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "1.2.3.4") == 0) { + return 1; + } + return 0; +} + +static int XFFTest02(void) { + char input[] = "[12::34]:1234"; // thanks chort! + char output[16]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "12::34") == 0) { + return 1; + } + return 0; +} + +static int XFFTest03(void) { + char input[] = "[2a03:2880:1010:3f02:face:b00c:0:2]:80"; // thanks chort! + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "2a03:2880:1010:3f02:face:b00c:0:2") == 0) { + return 1; + } + return 0; +} + +static int XFFTest04(void) { + char input[] = "[2a03:2880:1010:3f02:face:b00c:0:2]"; // thanks chort! + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "2a03:2880:1010:3f02:face:b00c:0:2") == 0) { + return 1; + } + return 0; +} + +static int XFFTest05(void) { + char input[] = "[::ffff:1.2.3.4]:1234"; // thanks double-p + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "::ffff:1.2.3.4") == 0) { + return 1; + } + return 0; +} + +static int XFFTest06(void) { + char input[] = "12::34"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "12::34") == 0) { + return 1; + } + return 0; +} + +static int XFFTest07(void) { + char input[] = "1.2.3.4"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "1.2.3.4") == 0) { + return 1; + } + return 0; +} + +static int XFFTest08(void) { + char input[] = "[1.2.3.4:1234"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 0) { + return 1; + } + return 0; +} + +static int XFFTest09(void) { + char input[] = "999.999.999.999:1234"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 0) { + return 1; + } + return 0; +} + +#endif + +void HTPXFFParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("XFFTest01", XFFTest01, 1); + UtRegisterTest("XFFTest02", XFFTest02, 1); + UtRegisterTest("XFFTest03", XFFTest03, 1); + UtRegisterTest("XFFTest04", XFFTest04, 1); + UtRegisterTest("XFFTest05", XFFTest05, 1); + UtRegisterTest("XFFTest06", XFFTest06, 1); + UtRegisterTest("XFFTest07", XFFTest07, 1); + UtRegisterTest("XFFTest08", XFFTest08, 1); + UtRegisterTest("XFFTest09", XFFTest09, 1); +#endif +} diff --git a/src/app-layer-htp-xff.h b/src/app-layer-htp-xff.h index ad4eb8acda65..1a3b67e16b9d 100644 --- a/src/app-layer-htp-xff.h +++ b/src/app-layer-htp-xff.h @@ -49,4 +49,6 @@ int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, HttpXFFCfg *xff_cfg, cha int HttpXFFGetIP(const Packet *p, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen); +void HTPXFFParserRegisterTests(void); + #endif /* __APP_LAYER_HTP_XFF_H__ */ diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 1a9c41a5c0ab..452a607e9c2b 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -35,6 +35,7 @@ #include "suricata.h" #include "suricata-common.h" +#include "conf.h" #include "debug.h" #include "decode.h" #include "threads.h" @@ -58,6 +59,7 @@ #include "app-layer-htp-body.h" #include "app-layer-htp-file.h" #include "app-layer-htp-libhtp.h" +#include "app-layer-htp-xff.h" #include "util-spm.h" #include "util-debug.h" @@ -73,7 +75,6 @@ #include "detect-parse.h" #include "decode-events.h" -#include "conf.h" #include "util-memcmp.h" @@ -6221,6 +6222,7 @@ void HTPParserRegisterTests(void) UtRegisterTest("HTPParserTest16", HTPParserTest16, 1); HTPFileParserRegisterTests(); + HTPXFFParserRegisterTests(); #endif /* UNITTESTS */ } From 834c36659e881aa9b140683151309e4229600b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20T=C3=B6nkyr=C3=A4?= Date: Tue, 19 May 2015 20:07:21 +0000 Subject: [PATCH 0694/2553] Allow colon in SSH version, at least some trojaned PuTTY clients have version like Putty-Local: Timestamp HH:MM:SS --- src/detect-ssh-software-version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index f2df5a538350..4197bfffffdf 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -61,7 +61,7 @@ /** * \brief Regex for parsing the softwareversion string */ -#define PARSE_REGEX "^\\s*\"?\\s*?([0-9a-zA-Z\\.\\-\\_\\+\\s+]+)\\s*\"?\\s*$" +#define PARSE_REGEX "^\\s*\"?\\s*?([0-9a-zA-Z\\:\\.\\-\\_\\+\\s+]+)\\s*\"?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; From cbf46c44ecec4e59375abdc5b409200b49d47ab9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 20 Aug 2015 19:31:23 +0200 Subject: [PATCH 0695/2553] transaction inspection: fix limit enforcement Make sure we're never wrapping around the size value. --- src/detect-engine-hcbd.c | 2 +- src/detect-engine-hhd.c | 2 +- src/detect-engine-hsbd.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index a1e47e6be439..09b7980a1c37 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -64,7 +64,7 @@ static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) { - if (size >= USHRT_MAX) + if (size >= (USHRT_MAX - BUFFER_STEP)) return -1; void *ptmp; diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index baf5cf667201..3bec4fd2f2ea 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -62,7 +62,7 @@ static inline int HHDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) { - if (size >= USHRT_MAX) + if (size >= (USHRT_MAX - BUFFER_STEP)) return -1; void *ptmp; diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index a6319db67f98..7d52c7d8f683 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -66,7 +66,7 @@ static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) { - if (size >= USHRT_MAX) + if (size >= (USHRT_MAX - BUFFER_STEP)) return -1; void *ptmp; From a7a902a071b91430268a43cdb8eedb3e914ffecb Mon Sep 17 00:00:00 2001 From: gureedo Date: Tue, 28 Jul 2015 09:35:53 +0500 Subject: [PATCH 0696/2553] netmap: extended comments for options in configuration file. Added extended description of the use of OS endpoint with copy mode. --- suricata.yaml.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/suricata.yaml.in b/suricata.yaml.in index da1ee3a9cc1b..ec1dfb2180a7 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -501,6 +501,12 @@ netmap: # interface will be copied to the copy-iface interface. If 'tap' is set, the # copy is complete. If 'ips' is set, the packet matching a 'drop' action # will not be copied. + # To specify the OS as the copy-iface (so the OS can route packets, or forward + # to a service running on the same machine) add a plus sign at the end + # (e.g. "copy-iface: eth0+"). Don't forget to set up a symmetrical eth0+ -> eth0 + # for return packets. Hardware checksumming must be *off* on the interface if + # using an OS endpoint (e.g. 'ifconfig eth0 -rxcsum -txcsum -rxcsum6 -txcsum6' for FreeBSD + # or 'ethtool -K eth0 tx off rx off' for Linux). #copy-mode: tap #copy-iface: eth3 # Set to yes to disable promiscuous mode From c31660e5fdc3e78cace3c7e4aa02cc1f4c24deae Mon Sep 17 00:00:00 2001 From: gureedo Date: Tue, 28 Jul 2015 09:40:13 +0500 Subject: [PATCH 0697/2553] netmap: enable zero-copy mode only when copy-mode is specified. Perform zero-copy checks only when copy-mode is specified. --- src/source-netmap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index 79bd161b8cdd..73930118c1f0 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -628,8 +628,10 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", ntv->tv); + /* enable zero-copy mode for workers runmode */ char const *active_runmode = RunmodeGetActive(); - if (active_runmode && !strcmp("workers", active_runmode)) { + if ((aconf->copy_mode != NETMAP_COPY_MODE_NONE) && active_runmode + && !strcmp("workers", active_runmode)) { if (likely(ntv->ifsrc->mem == ntv->ifdst->mem)) { ntv->flags |= NETMAP_FLAG_ZERO_COPY; SCLogInfo("Enabling zero copy mode for %s->%s", @@ -638,7 +640,6 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da SCLogInfo("Unable to set zero copy mode for %s->%s", aconf->iface_name, aconf->out_iface_name); } - } if (aconf->bpf_filter) { From 63a47967d70c39179cf7cad67ffc1eb0c912adb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20T=C3=B6nkyr=C3=A4?= Date: Sat, 15 Aug 2015 20:58:56 +0000 Subject: [PATCH 0698/2553] source-pfring: don't set cluster mode when using ZC and VLAN tracking is disabled --- src/source-pfring.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index 84fe0df61568..3b2b52df23e0 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -517,8 +517,10 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->vlan_disabled = 1; } - /* Since VLAN is disabled we force the cluster type to CLUSTER_FLOW_5_TUPLE */ - if (ptv->vlan_disabled == 1 && ptv->ctype == CLUSTER_FLOW) { + /* If VLAN tracking is disabled, set cluster type to 5-tuple or in case of a + * ZC interface, do nothing */ + if (ptv->vlan_disabled && ptv->ctype == CLUSTER_FLOW && + strncmp(ptv->interface, "zc", 2) != 0) { SCLogInfo("VLAN disabled, setting cluster type to CLUSTER_FLOW_5_TUPLE"); rc = pfring_set_cluster(ptv->pd, ptv->cluster_id, CLUSTER_FLOW_5_TUPLE); From ba81c4d290d21b7a86e0c3ba921d28cbecdf6d09 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 20 Aug 2015 13:37:09 +0200 Subject: [PATCH 0699/2553] autotools: cleanup Remove most of the CFLAGS updates from configure. Flags are now (mostly) set in AM_CLFLAGS. Update all -DBLAH additions to CFLAGS to use AC_DEFINE([BLAH], ...) Improve Lua vs LuaJIT checking. Improve the configure output a bit. Lots of smaller cleanups. --- configure.ac | 272 +++++++++++++++++++++++++++++------------------- src/Makefile.am | 9 +- 2 files changed, 170 insertions(+), 111 deletions(-) diff --git a/configure.ac b/configure.ac index f796b06a281a..ea819f4a8032 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,3 @@ -#TODO A better place for default CFLAGS? - - AC_INIT(suricata, 2.1dev) m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS([config.h]) @@ -39,10 +36,30 @@ echo ]) - if test `basename $CC` = "clang"; then - CFLAGS="$CFLAGS -Wextra -Werror-implicit-function-declaration" - AC_MSG_CHECKING([clang __sync_bool_compare_and_swap]) - AC_TRY_COMPILE([#include ], + dnl Taken from https://llvm.org/svn/llvm-project/llvm/trunk/autoconf/configure.ac + dnl check if we compile using clang or gcc. On some systems the gcc binary is + dnl is actually clang, so do a compile test. + AC_MSG_CHECKING([whether GCC or Clang is our compiler]) + AC_LANG_PUSH([C]) + compiler=unknown + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#if ! __clang__ + #error + #endif + ]])], + compiler=clang, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#if ! __GNUC__ + #error + #endif + ]])], + compiler=gcc, [])]) + AC_LANG_POP([C]) + AC_MSG_RESULT([${compiler}]) + + case "$compiler" in + clang) + CLANG_CFLAGS="-Wextra -Werror-implicit-function-declaration" + AC_MSG_CHECKING([clang __sync_bool_compare_and_swap support]) + AC_TRY_COMPILE([#include ], [ unsigned int i = 0; (void)__sync_bool_compare_and_swap(&i, 1, 1);], [ AC_DEFINE([__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1], [1], [Fake GCC atomic support]) @@ -51,29 +68,32 @@ AC_DEFINE([__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8], [1], [Fake GCC atomic support]) AC_MSG_RESULT([yes]) ], [AC_MSG_RESULT([no])]) - fi - if test `basename $CC` = "gcc"; then - dnl get gcc version - AC_MSG_CHECKING([gcc version]) - gccver=$($CC -dumpversion) - gccvermajor=$(echo $gccver | cut -d . -f1) - gccverminor=$(echo $gccver | cut -d . -f2) - gccvernum=$(expr $gccvermajor "*" 100 + $gccverminor) - AC_MSG_RESULT($gccver) - - if test "$gccvernum" -ge "400"; then + AC_SUBST(CLANG_CFLAGS) + ;; + gcc) + dnl get gcc version + AC_MSG_CHECKING([gcc version]) + gccver=$($CC -dumpversion) + gccvermajor=$(echo $gccver | cut -d . -f1) + gccverminor=$(echo $gccver | cut -d . -f2) + gccvernum=$(expr $gccvermajor "*" 100 + $gccverminor) + AC_MSG_RESULT($gccver) + + if test "$gccvernum" -ge "400"; then dnl gcc 4.0 or later - CFLAGS="$CFLAGS -Wextra -Werror-implicit-function-declaration" + GCC_CFLAGS="-Wextra -Werror-implicit-function-declaration" # remove optimization options that break our code # VJ 2010/06/27: no-tree-pre added. It breaks ringbuffers code. - CFLAGS="$CFLAGS -fno-tree-pre" - else - CFLAGS="$CFLAGS -W" - fi - fi - CFLAGS="$CFLAGS -Wall" - CFLAGS="$CFLAGS -Wno-unused-parameter" - CFLAGS="$CFLAGS -std=gnu99" + GCC_CFLAGS="$GCC_CFLAGS -fno-tree-pre" + else + GCC_CFLAGS="-W" + fi + AC_SUBST(GCC_CFLAGS) + ;; + *) + AC_MSG_WARN([unsupported/untested compiler, this may or may not work]) + ;; + esac # Checks for programs. AC_PROG_AWK @@ -166,7 +186,11 @@ AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([gettimeofday memset strcasecmp strchr strdup strerror strncasecmp strtol strtoul memchr memrchr]) + + OCFLAGS=$CFLAGS + CFLAGS="" AC_CHECK_FUNCS([strlcpy strlcat]) + CFLAGS=$OCFLAGS # Add large file support AC_SYS_LARGEFILE @@ -252,9 +276,9 @@ AC_MSG_CHECKING(for -fstack-protector) TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -fstack-protector" - AC_TRY_LINK(,,SECCFLAGS="${SECCFLAGS} -fstack-protector" - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) + AC_TRY_LINK(,,SECCFLAGS="-fstack-protector" + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) CFLAGS="${TMPCFLAGS}" #compile-time best-practices errors for certain libc functions, provides checks of buffer lengths and memory regions @@ -262,8 +286,8 @@ TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -D_FORTIFY_SOURCE=2" AC_TRY_COMPILE(,,SECCFLAGS="${SECCFLAGS} -D_FORTIFY_SOURCE=2" - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) CFLAGS="${TMPCFLAGS}" #compile-time warnings about misuse of format strings @@ -271,8 +295,8 @@ TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Wformat -Wformat-security" AC_TRY_COMPILE(,,SECCFLAGS="${SECCFLAGS} -Wformat -Wformat-security" - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) CFLAGS="${TMPCFLAGS}" #provides a read-only relocation table area in the final ELF @@ -280,8 +304,8 @@ TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z relro" AC_TRY_LINK(,,SECLDFLAGS="${SECLDFLAGS} -z relro" - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) LDFLAGS="${TMPLDFLAGS}" #forces all relocations to be resolved at run-time @@ -289,12 +313,12 @@ TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z now" AC_TRY_LINK(,,SECLDFLAGS="${SECLDFLAGS} -z now" - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) LDFLAGS="${TMPLDFLAGS}" - CFLAGS="${CFLAGS} ${SECCFLAGS}" - LDFLAGS="${LDFLAGS} ${SECLDFLAGS}" + AC_SUBST(SECCFLAGS) + AC_SUBST(SECLDFLAGS) ]) #enable profile generation @@ -314,7 +338,8 @@ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]])], [ AC_MSG_RESULT([yes]) - CFLAGS="$OFLAGS -march=native" + OPTIMIZATION_CFLAGS="-march=native" + AC_SUBST(OPTIMIZATION_CFLAGS) ], [ AC_MSG_RESULT([no]) @@ -330,60 +355,59 @@ AC_ARG_ENABLE(unittests, AS_HELP_STRING([--enable-unittests], [Enable compilation of the unit tests]),,[enable_unittests=no]) AS_IF([test "x$enable_unittests" = "xyes"], [ - UT_ENABLED="yes" - CFLAGS="${CFLAGS} -DUNITTESTS" + AC_DEFINE([UNITTESTS],[1],[Enable built-in unittests]) ]) - AM_CONDITIONAL([BUILD_UNITTESTS], [test "x$enable_unittests" = "xyes"]) # enable workaround for old barnyard2 for unified alert output AC_ARG_ENABLE(old-barnyard2, AS_HELP_STRING([--enable-old-barnyard2], [Use workaround for old barnyard2 in unified2 output]),,[enable_old_barnyard2=no]) AS_IF([test "x$enable_old_barnyard2" = "xyes"], [ - CFLAGS="${CFLAGS} -DHAVE_OLD_BARNYARD2" + AC_DEFINE([HAVE_OLD_BARNYARD2],[1],[Use workaround for old barnyard2 in unified2 output]) ]) # enable debug output AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [Enable debug output]),,[enable_debug=no]) AS_IF([test "x$enable_debug" = "xyes"], [ - CFLAGS="${CFLAGS} -DDEBUG" + AC_DEFINE([DEBUG],[1],[Enable debug output]) ]) + AM_CONDITIONAL([DEBUG], [test "x$enable_debug" = "xyes"]) # enable debug validation functions & macro's output AC_ARG_ENABLE(debug-validation, AS_HELP_STRING([--enable-debug-validation], [Enable (debug) validation code output]),,[enable_debug_validation=no]) AS_IF([test "x$enable_debug_validation" = "xyes"], [ - CFLAGS="${CFLAGS} -DDEBUG_VALIDATION" + AC_DEFINE([DEBUG_VALIDATION],[1],[Enable (debug) validation code output]) ]) # profiling support AC_ARG_ENABLE(profiling, AS_HELP_STRING([--enable-profiling], [Enable performance profiling]),,[enable_profiling=no]) AS_IF([test "x$enable_profiling" = "xyes"], [ - - case "$host" in - *-*-openbsd*) - AC_MSG_ERROR([profiling is not supported on OpenBSD]) - ;; - *) - CFLAGS="${CFLAGS} -DPROFILING" - ;; - esac + case "$host" in + *-*-openbsd*) + AC_MSG_ERROR([profiling is not supported on OpenBSD]) + ;; + *) + AC_DEFINE([PROFILING],[1],[Enable performance profiling]) + ;; + esac ]) # profiling support, locking AC_ARG_ENABLE(profiling-locks, AS_HELP_STRING([--enable-profiling-locks], [Enable performance profiling for locks]),,[enable_profiling_locks=no]) AS_IF([test "x$enable_profiling_locks" = "xyes"], [ - CFLAGS="${CFLAGS} -DPROFILING -DPROFILE_LOCKING" + AC_DEFINE([PROFILING],[1],[Enable performance profiling]) + AC_DEFINE([PROFILE_LOCKING],[1],[Enable performance profiling for locks]) ]) # enable support for IPFW AC_ARG_ENABLE(ipfw, AS_HELP_STRING([--enable-ipfw], [Enable FreeBSD IPFW support for inline IDP]),,[enable_ipfw=no]) AS_IF([test "x$enable_ipfw" = "xyes"], [ - CFLAGS="$CFLAGS -DIPFW" + AC_DEFINE([IPFW],[1],[Enable FreeBSD IPFW support for inline IDP]) ]) AC_ARG_ENABLE(coccinelle, @@ -407,6 +431,7 @@ AC_DEFINE([HAVE_DETECT_DISABLED], [1], [Detection is disabled]) ]) + # Tilera PCIE logging AM_CONDITIONAL([BUILD_PCIE_LOGGING], [test ! -z "$TILERA_ROOT"]) # libraries @@ -435,7 +460,7 @@ AC_CHECK_HEADER(pcre.h,,[AC_ERROR(pcre.h not found ...)]) if test "$with_libpcre_libraries" != "no"; then - LDFLAGS="${LDFLAGS} -L${with_libpcre_libraries}" + LDFLAGS="${LDFLAGS} -L${with_libpcre_libraries}" fi PCRE="" AC_CHECK_LIB(pcre, pcre_get_substring,, PCRE="no",-lpthread) @@ -467,13 +492,13 @@ [ pcre_match_limit_recursion_available=yes ], [:] ) if test "$pcre_match_limit_recursion_available" != "yes"; then - CFLAGS="${CFLAGS} -DNO_PCRE_MATCH_RLIMIT" echo echo " Warning! pcre extra opt PCRE_EXTRA_MATCH_LIMIT_RECURSION not found" echo " This could lead to potential DoS please upgrade to pcre >= 6.5" - echo " Continuing for now...." echo " from www.pcre.org." + echo " Continuing for now...." echo + AC_DEFINE([NO_PCRE_MATCH_RLIMIT],[1],[Pcre PCRE_EXTRA_MATCH_LIMIT_RECURSION not available]) fi TMPCFLAGS="${CFLAGS}" @@ -547,7 +572,7 @@ AC_CHECK_HEADER(yaml.h,,LIBYAML="no") if test "$with_libyaml_libraries" != "no"; then - LDFLAGS="${LDFLAGS} -L${with_libyaml_libraries}" + LDFLAGS="${LDFLAGS} -L${with_libyaml_libraries}" fi LIBYAML="" @@ -626,7 +651,7 @@ echo " Go get it from your distribution or from:" echo " http://www.digip.org/jansson/" echo - if test "x$enable_unixsocket" = "xyes"; then + if test "x$enable_unixsocket" = "xyes"; then exit 1 fi enable_unixsocket="no" @@ -634,14 +659,14 @@ else case $host in *-*-mingw32*) - ;; + ;; *-*-cygwin) - ;; + ;; *) - if test "x$enable_unixsocket" = "xtest"; then - enable_unixsocket="yes" - fi - ;; + if test "x$enable_unixsocket" = "xtest"; then + enable_unixsocket="yes" + fi + ;; esac fi else @@ -702,9 +727,9 @@ esac fi - #enable support for NFQUEUE + # enable support for NFQUEUE AS_IF([test "x$enable_nfqueue" = "xyes"], [ - CFLAGS="$CFLAGS -DNFQ" + AC_DEFINE_UNQUOTED([NFQ],[1],[Enable Linux Netfilter NFQUEUE support for inline IDP]) #libnetfilter_queue AC_ARG_WITH(libnetfilter_queue_includes, @@ -892,7 +917,12 @@ LLIBNET="" AC_CHECK_LIB(net, libnet_write,, LLIBNET="no") if test "$LLIBNET" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_LIBNET11 -D_DEFAULT_SOURCE -D_BSD_SOURCE -D__BSD_SOURCE -D__FAVOR_BSD -DHAVE_NET_ETHERNET_H" + AC_DEFINE([HAVE_LIBNET11],[1],(libnet 1.1 available)) + AC_DEFINE([_DEFAULT_SOURCE],[1],(default source)) + AC_DEFINE([_BSD_SOURCE],[1],(bsd source)) + AC_DEFINE([__BSD_SOURCE],[1],(bsd source)) + AC_DEFINE([__FAVOR_BSD],[1],(favor bsd)) + AC_DEFINE([HAVE_NET_ETHERNET_H],[1],(ethernet.h)) else #if we displayed a warning already no reason to do it again. if test "$LIBNET_DETECT_FAIL" = "no"; then @@ -911,7 +941,7 @@ TMPLIBS="${LIBS}" AC_CHECK_LIB(net, libnet_build_icmpv6_unreach,, LLIBNET="no") if test "$LLIBNET" != "no"; then - CFLAGS="$CFLAGS -DHAVE_LIBNET_ICMPV6_UNREACH" + AC_DEFINE([HAVE_LIBNET_ICMPV6_UNREACH],[1],(libnet_build_icmpv6_unreach available)) fi LIBS="${TMPLIBS}" fi @@ -962,12 +992,14 @@ if test "$LPCAPVTEST" != "no"; then AC_PATH_PROG(HAVE_PCAP_CONFIG, pcap-config, "no") if test "$HAVE_PCAP_CONFIG" = "no" -o "$cross_compiling" = "yes"; then - CFLAGS="${CFLAGS} -DLIBPCAP_VERSION_MAJOR=1" + AC_DEFINE([LIBPCAP_VERSION_MAJOR],[1],(libpcap version 1.0+)) else - CFLAGS="${CFLAGS} `pcap-config --defines` `pcap-config --cflags` -DLIBPCAP_VERSION_MAJOR=1" + PCAP_CFLAGS="$(pcap-config --defines) $(pcap-config --cflags)" + AC_SUBST(PCAP_CFLAGS) + AC_DEFINE([LIBPCAP_VERSION_MAJOR],[1],(libpcap version 1.0+)) fi else - CFLAGS="${CFLAGS} -DLIBPCAP_VERSION_MAJOR=0" + AC_DEFINE([LIBPCAP_VERSION_MAJOR],[0],(libpcap version 0.x)) fi LIBS="${TMPLIBS}" @@ -978,7 +1010,7 @@ TMPLIBS="${LIBS}" AC_CHECK_LIB(pcap, pcap_set_buffer_size,, LPCAPSBUFF="no") if test "$LPCAPSBUFF" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_PCAP_SET_BUFF" + AC_DEFINE([HAVE_PCAP_SET_BUFF],[1],(libpcap has pcap_set_buffer_size function)) fi LIBS="${TMPLIBS}" @@ -988,7 +1020,7 @@ AC_ARG_ENABLE(pfring, AS_HELP_STRING([--enable-pfring], [Enable Native PF_RING support]),,[enable_pfring=no]) AS_IF([test "x$enable_pfring" = "xyes"], [ - CFLAGS="$CFLAGS -DHAVE_PFRING" + AC_DEFINE([HAVE_PFRING],[1],(PF_RING support enabled)) #We have to set CFLAGS for AC_TRY_COMPILE as it doesn't pay attention to CPPFLAGS AC_ARG_WITH(libpfring_includes, @@ -1068,7 +1100,7 @@ [with_netmap_includes="$withval"],[with_netmap_includes=no]) AS_IF([test "x$enable_netmap" = "xyes"], [ - CFLAGS="$CFLAGS -DHAVE_NETMAP" + AC_DEFINE([HAVE_NETMAP],[1],(NETMAP support enabled)) if test "$with_netmap_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_netmap_includes}" @@ -1169,7 +1201,7 @@ [ --with-cuda-nvcc=DIR cuda nvcc compiler directory], [with_cuda_nvcc="$withval"],[with_cuda_nvcc=no]) - CFLAGS="${CFLAGS} -D__SC_CUDA_SUPPORT__" + AC_DEFINE([SC_CUDA_SUPPORT__],[1],(CUDA support enabled)) if test "$with_cuda_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_cuda_includes}" @@ -1253,7 +1285,7 @@ fi if test "$LIBCAP_NG" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_LIBCAP_NG" + AC_DEFINE([HAVE_LIBCAP_NG],[1],[Libpcap-ng support]) fi if test "$LIBCAP_NG" = "no"; then @@ -1296,11 +1328,7 @@ AC_CHECK_HEADER(dagapi.h,DAG="yes",DAG="no") if test "$DAG" != "no"; then DAG="" - AC_CHECK_LIB(dag,dag_open,,DAG="no",) - fi - - if test "$DAG" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_DAG" + AC_CHECK_LIB(dag,dag_open,,DAG="no",) fi if test "$DAG" = "no"; then @@ -1309,6 +1337,8 @@ echo exit 1 fi + + AC_DEFINE([HAVE_DAG],[1],(Endace DAG card support enabled)) fi # libnspr @@ -1450,16 +1480,14 @@ AC_CHECK_LIB(ntapi, NT_Init,NAPATECH="yes",NAPATECH="no") fi - if test "$NAPATECH" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_NAPATECH" - fi - if test "$NAPATECH" = "no"; then echo echo " ERROR! libntapi library not found" echo exit 1 fi + + AC_DEFINE([HAVE_NAPATECH],[1],(Napatech capture card support)) fi # liblua @@ -1467,6 +1495,22 @@ AS_HELP_STRING([--enable-lua],[Enable Lua support]), [ enable_lua="yes"], [ enable_lua="no"]) + AC_ARG_ENABLE(luajit, + AS_HELP_STRING([--enable-luajit],[Enable Luajit support]), + [ enable_luajit="yes"], + [ enable_luajit="no"]) + if test "$enable_lua" = "yes"; then + if test "$enable_luajit" = "yes"; then + echo "ERROR: can't enable liblua and luajit at the same time." + echo "For LuaJIT, just use --enable-luajit. For liblua (no jit)" + echo "support, use just --enable-lua." + echo "Both options will enable the Lua scripting capabilities" + echo "in Suricata". + echo + exit 1 + fi + fi + AC_ARG_WITH(liblua_includes, [ --with-liblua-includes=DIR liblua include directory], [with_liblua_includes="$withval"],[with_liblua_includes="no"]) @@ -1544,10 +1588,6 @@ fi # libluajit - AC_ARG_ENABLE(luajit, - AS_HELP_STRING([--enable-luajit],[Enable Luajit support]), - [ enable_luajit="yes"], - [ enable_luajit="no"]) AC_ARG_WITH(libluajit_includes, [ --with-libluajit-includes=DIR libluajit include directory], [with_libluajit_includes="$withval"],[with_libluajit_includes="no"]) @@ -1590,7 +1630,7 @@ AC_DEFINE([HAVE_LUA],[1],[lua support available]) AC_DEFINE([HAVE_LUAJIT],[1],[libluajit available]) - enable_lua="yes" + enable_lua="yes, through luajit" enable_luajit="yes" else echo @@ -1628,7 +1668,7 @@ AC_CHECK_HEADER(GeoIP.h,GEOIP="yes",GEOIP="no") if test "$GEOIP" = "yes"; then if test "$with_libgeoip_libraries" != "no"; then - LDFLAGS="${LDFLAGS} -L${with_libgeoip_libraries}" + LDFLAGS="${LDFLAGS} -L${with_libgeoip_libraries}" fi AC_CHECK_LIB(GeoIP, GeoIP_country_code_by_ipnum,, GEOIP="no") fi @@ -1642,10 +1682,9 @@ echo exit 1 fi - if test "$GEOIP" = "yes"; then - AC_DEFINE([HAVE_GEOIP],[1],[libgeoip available]) - enable_geoip="yes" - fi + + AC_DEFINE([HAVE_GEOIP],[1],[libgeoip available]) + enable_geoip="yes" fi # get cache line size @@ -1655,22 +1694,22 @@ if [test "$CLS" != "" && test "$CLS" != "0"]; then AC_DEFINE_UNQUOTED([CLS],[${CLS}],[L1 cache line size]) else - AC_DEFINE_UNQUOTED([CLS],[64],[L1 cache line size]) + AC_DEFINE([CLS],[64],[L1 cache line size]) fi else - AC_DEFINE_UNQUOTED([CLS],[64],[L1 cache line size]) + AC_DEFINE([CLS],[64],[L1 cache line size]) fi # get revision if test -f ./revision; then REVISION=`cat ./revision` - CFLAGS="${CFLAGS} -DREVISION=\"${REVISION}\"" + AC_DEFINE_UNQUOTED([REVISION],[${REVISION}],[Git revision]) else AC_PATH_PROG(HAVE_GIT_CMD, git, "no") if test "$HAVE_GIT_CMD" != "no"; then if [ test -d .git ]; then REVISION=`git rev-parse --short HEAD` - CFLAGS="${CFLAGS} -DREVISION=\"${REVISION}\"" + AC_DEFINE_UNQUOTED([REVISION],[${REVISION}],[Git revision]) fi fi fi @@ -1730,6 +1769,13 @@ AC_SUBST(e_localstatedir) AC_DEFINE_UNQUOTED([CONFIG_DIR],["$e_sysconfdir"],[Our CONFIG_DIR]) AC_SUBST(e_magic_file) +EXPAND_VARIABLE(prefix, CONFIGURE_PREFIX) +EXPAND_VARIABLE(sysconfdir, CONFIGURE_SYSCONDIR) +EXPAND_VARIABLE(localstatedir, CONFIGURE_LOCALSTATEDIR) +AC_SUBST(CONFIGURE_PREFIX) +AC_SUBST(CONFIGURE_SYSCONDIR) +AC_SUBST(CONFIGURE_LOCALSTATEDIR) + AC_OUTPUT(Makefile src/Makefile qa/Makefile qa/coccinelle/Makefile rules/Makefile doc/Makefile contrib/Makefile contrib/file_processor/Makefile contrib/file_processor/Action/Makefile contrib/file_processor/Processor/Makefile contrib/tile_pcie_logd/Makefile suricata.yaml scripts/Makefile scripts/suricatasc/Makefile scripts/suricatasc/suricatasc) SURICATA_BUILD_CONF="Suricata Configuration: @@ -1741,6 +1787,7 @@ SURICATA_BUILD_CONF="Suricata Configuration: Netmap support: ${enable_netmap} DAG enabled: ${enable_dag} Napatech enabled: ${enable_napatech} + Unix socket enabled: ${enable_unixsocket} Detection enabled: ${enable_detection} @@ -1766,15 +1813,22 @@ SURICATA_BUILD_CONF="Suricata Configuration: Coccinelle / spatch: ${enable_coccinelle} Generic build parameters: - Installation prefix (--prefix): ${prefix} - Configuration directory (--sysconfdir): ${e_sysconfdir} - Log directory (--localstatedir) : ${e_logdir} + Installation prefix: ${prefix} + Configuration directory: ${e_sysconfdir} + Log directory: ${e_logdir} + + --prefix ${CONFIGURE_PREFIX} + --sysconfdir ${CONFIGURE_SYSCONDIR} + --localstatedir ${CONFIGURE_LOCALSTATEDIR} Host: ${host} - GCC binary: ${CC} + Compiler: ${CC} (exec name) / ${compiler} (real) GCC Protect enabled: ${enable_gccprotect} GCC march native enabled: ${enable_gccmarch_native} - GCC Profile enabled: ${enable_gccprofile}" + GCC Profile enabled: ${enable_gccprofile} + CFLAGS ${CFLAGS} + PCAP_CFLAGS ${PCAP_CFLAGS} + SECCFLAGS ${SECCFLAGS}" echo echo "$SURICATA_BUILD_CONF" diff --git a/src/Makefile.am b/src/Makefile.am index e61e2ffa00c2..1d59a5082fca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -472,9 +472,14 @@ cuda-ptxdump.h: $(PTXS) CLEANFILES = $(PTXS) cuda-ptxdump.h endif +# default CFLAGS +AM_CFLAGS = ${OPTIMIZATION_CFLAGS} ${GCC_CFLAGS} ${CLANG_CFLAGS} ${SECCFLAGS} ${PCAP_CFLAGS} -Wall -Wno-unused-parameter -std=gnu99 -DLOCAL_STATE_DIR=\"$(localstatedir)\" +# different flags for different cases +if DEBUG +AM_CFLAGS += -ggdb -O0 +endif -#suricata_CFLAGS = -Wall -fno-strict-aliasing -AM_CFLAGS = -DLOCAL_STATE_DIR=\"$(localstatedir)\" +AM_LDFLAGS = ${SECLDFLAGS} if BUILD_UNITTESTS check-am: From 6b2fb3fd5da11641b3c607184c3d538a9d833d8c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 21 Aug 2015 09:48:42 +0200 Subject: [PATCH 0700/2553] Fix minor format string issues --- src/app-layer-detect-proto.c | 4 ++-- src/decode-tcp.h | 2 +- src/detect-engine-iponly.c | 2 +- src/detect-engine-siggroup.c | 2 +- src/log-droplog.c | 4 ++-- src/runmode-erf-file.c | 4 ++-- src/runmode-pcap-file.c | 4 ++-- src/tm-threads.c | 2 +- src/util-byte.c | 12 ++++++------ src/util-decode-asn1.c | 2 +- src/util-runmodes.c | 18 +++++++++--------- 11 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 9545dffac7d5..ed029e5e6b8b 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -645,7 +645,7 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp else if (pp->ipproto == IPPROTO_UDP) printf("IPProto: UDP\n"); else - printf("IPProto: %"PRIu16"\n", pp->ipproto); + printf("IPProto: %"PRIu8"\n", pp->ipproto); pp_port = pp->port; for ( ; pp_port != NULL; pp_port = pp_port->next) { @@ -934,7 +934,7 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing while (curr_pe != NULL) { if (curr_pe->alproto == alproto) { SCLogError(SC_ERR_ALPARSER, "Duplicate pp registered - " - "ipproto - %"PRIu16" Port - %"PRIu16" " + "ipproto - %"PRIu8" Port - %"PRIu16" " "App Protocol - NULL, App Protocol(ID) - " "%"PRIu16" min_depth - %"PRIu16" " "max_dept - %"PRIu16".", diff --git a/src/decode-tcp.h b/src/decode-tcp.h index 152d5103f42f..29c02dfb2fea 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -66,7 +66,7 @@ #define TCP_OPTS_CNT tcpvars.tcp_opt_cnt #define TCP_GET_RAW_OFFSET(tcph) (((tcph)->th_offx2 & 0xf0) >> 4) -#define TCP_GET_RAW_X2(tcph) ((tcph)->th_offx2 & 0x0f) +#define TCP_GET_RAW_X2(tcph) (unsigned char)((tcph)->th_offx2 & 0x0f) #define TCP_GET_RAW_SRC_PORT(tcph) ntohs((tcph)->th_sport) #define TCP_GET_RAW_DST_PORT(tcph) ntohs((tcph)->th_dport) diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index bfbbb0f4b33a..06983fc0153b 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -484,7 +484,7 @@ static void SigNumArrayPrint(void *tmp) for (; i < 8; i++) { if (bitarray & 0x01) - printf(", %"PRIu16"", u * 8 + i); + printf(", %"PRIu32"", u * 8 + i); else printf(", "); diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index a7ecbafd9abd..02602d908e39 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -1225,7 +1225,7 @@ void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) for (u = 0; u < (sgh->init->sig_size * 8); u++) { if (sgh->init->sig_array[u / 8] & (1 << (u % 8))) { SCLogDebug("%" PRIu32, u); - printf("s->num %"PRIu16" ", u); + printf("s->num %"PRIu32" ", u); } } diff --git a/src/log-droplog.c b/src/log-droplog.c index 1ee2d999f7ba..6eafd9d5ef93 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -244,11 +244,11 @@ static int LogDropLogNetFilter (ThreadVars *tv, const Packet *p, void *data) break; case IPPROTO_ICMP: if (PKT_IS_ICMPV4(p)) { - fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu16" CODE=%"PRIu16"" + fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu8" CODE=%"PRIu8"" " ID=%"PRIu16" SEQ=%"PRIu16"", ICMPV4_GET_TYPE(p), ICMPV4_GET_CODE(p), ICMPV4_GET_ID(p), ICMPV4_GET_SEQ(p)); } else if(PKT_IS_ICMPV6(p)) { - fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu16" CODE=%"PRIu16"" + fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu8" CODE=%"PRIu8"" " ID=%"PRIu16" SEQ=%"PRIu16"", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); } diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index ef7d2e09ec9c..19dbb683dfe0 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -202,8 +202,8 @@ int RunModeErfFileAutoFp(void) } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + snprintf(tname, sizeof(tname), "Detect%d", thread+1); + snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index d337cb9711a7..fab14639b342 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -217,8 +217,8 @@ int RunModeFilePcapAutoFp(void) } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + snprintf(tname, sizeof(tname), "Detect%d", thread+1); + snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); diff --git a/src/tm-threads.c b/src/tm-threads.c index f0f8a3cf0a92..c6828b4071ad 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -991,7 +991,7 @@ TmEcode TmThreadSetupOptions(ThreadVars *tv) tv->thread_priority = taf->prio; } SCLogInfo("Setting prio %d for \"%s\" Module to cpu/core " - "%"PRIu16", thread id %lu", tv->thread_priority, + "%d, thread id %lu", tv->thread_priority, tv->name, cpu, SCGetThreadIdLong()); } else { SetCPUAffinitySet(&taf->cpu_set); diff --git a/src/util-byte.c b/src/util-byte.c index 6f0cd132314c..1d8e088a6a99 100644 --- a/src/util-byte.c +++ b/src/util-byte.c @@ -207,7 +207,7 @@ int ByteExtractStringUint32(uint32_t *res, int base, uint16_t len, const char *s if ((uint64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIu64 " > %" PRIu32 ")", i64, UINT_MAX); + "(%" PRIu64 " > %" PRIuMAX ")", i64, (uintmax_t)UINT_MAX); return -1; } @@ -228,7 +228,7 @@ int ByteExtractStringUint16(uint16_t *res, int base, uint16_t len, const char *s if ((uint64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIu64 " > %" PRIu16 ")", i64, USHRT_MAX); + "(%" PRIu64 " > %" PRIuMAX ")", i64, (uintmax_t)USHRT_MAX); return -1; } @@ -249,7 +249,7 @@ int ByteExtractStringUint8(uint8_t *res, int base, uint16_t len, const char *str if ((uint64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIu64 " > %" PRIu8 ")", i64, UCHAR_MAX); + "(%" PRIu64 " > %" PRIuMAX ")", i64, (uintmax_t)UCHAR_MAX); return -1; } @@ -326,7 +326,7 @@ int ByteExtractStringInt32(int32_t *res, int base, uint16_t len, const char *str if ((int64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIi64 " > %" PRIi32 ")\n", i64, INT_MAX); + "(%" PRIi64 " > %" PRIiMAX ")\n", i64, (intmax_t)INT_MAX); return -1; } @@ -347,7 +347,7 @@ int ByteExtractStringInt16(int16_t *res, int base, uint16_t len, const char *str if ((int64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIi64 " > %" PRIi16 ")\n", i64, SHRT_MAX); + "(%" PRIi64 " > %" PRIiMAX ")\n", i64, (intmax_t)SHRT_MAX); return -1; } @@ -368,7 +368,7 @@ int ByteExtractStringInt8(int8_t *res, int base, uint16_t len, const char *str) if ((int64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIi64 " > %" PRIi8 ")\n", i64, CHAR_MAX); + "(%" PRIi64 " > %" PRIiMAX ")\n", i64, (intmax_t)CHAR_MAX); return -1; } diff --git a/src/util-decode-asn1.c b/src/util-decode-asn1.c index 6766af66c572..3372b517cec4 100644 --- a/src/util-decode-asn1.c +++ b/src/util-decode-asn1.c @@ -319,7 +319,7 @@ void SCPrintByteBin(uint8_t byte) { uint8_t i = 0; for (i = 8; i > 0; i--) { - printf("%"PRIu8, ((byte >> (i - 1)) & 0x01)); + printf("%"PRIu8, (uint8_t)((byte >> (i - 1)) & 0x01)); if (i == 5) printf(" "); } diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 5e89f7b28dde..c9b61e6a2e55 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -90,7 +90,7 @@ char *RunmodeAutoFpCreatePickupQueuesString(int n) if (strlen(queues) > 0) strlcat(queues, ",", queues_size); - snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + snprintf(qname, sizeof(qname), "pickup%d", thread+1); strlcat(queues, qname, queues_size); } @@ -147,7 +147,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, /* create the threads */ for (thread = 0; thread < threads_count; thread++) { - snprintf(tname, sizeof(tname), "%s%"PRIu16, thread_name, thread+1); + snprintf(tname, sizeof(tname), "%s%d", thread_name, thread+1); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); @@ -209,7 +209,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, threads_count = ModThreadsCount(aconf); for (thread = 0; thread < threads_count; thread++) { - snprintf(tname, sizeof(tname), "%s%s%"PRIu16, thread_name, + snprintf(tname, sizeof(tname), "%s%s%d", thread_name, live_dev, thread+1); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { @@ -249,8 +249,8 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + snprintf(tname, sizeof(tname), "Detect%d", thread+1); + snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); @@ -341,7 +341,7 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod if (single_mode) { snprintf(tname, sizeof(tname), "%s", thread_name); } else { - snprintf(tname, sizeof(tname), "%s%s%"PRIu16, + snprintf(tname, sizeof(tname), "%s%s%d", thread_name, live_dev, thread+1); } n_thread_name = SCStrdup(tname); @@ -557,8 +557,8 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + snprintf(tname, sizeof(tname), "Detect%d", thread+1); + snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); @@ -612,7 +612,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, /* create the threads */ for (int i = 0; i < nqueue; i++) { memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Verdict%"PRIu16, i); + snprintf(tname, sizeof(tname), "Verdict%d", i); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { From 3054af7900788324d37fed9ee496ba1e15db2558 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 29 Aug 2015 10:49:26 +0200 Subject: [PATCH 0701/2553] af-packet: don't activate rollover by default Rollover option is causing issue with TCP streaming code because packets from the same flow to be treated out of order. As long as the situation is not fixed in the streaming engine, it is a bad idea to enable it by default. --- suricata.yaml.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index ec1dfb2180a7..fa0fb9a00f09 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -478,7 +478,7 @@ af-packet: - interface: default #threads: auto #use-mmap: yes - rollover: yes + #rollover: yes # Netmap support # From 7281ae6e8014b50ab4e37b0b39c4dd739b5434b3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 31 Aug 2015 18:05:17 +0200 Subject: [PATCH 0702/2553] yaml: add missing ippair section --- suricata.yaml.in | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/suricata.yaml.in b/suricata.yaml.in index fa0fb9a00f09..56d4d3628f37 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -906,6 +906,15 @@ host: prealloc: 1000 memcap: 16777216 +# IP Pair table: +# +# Used by xbits 'ippair' tracking. +# +#ippair: +# hash-size: 4096 +# prealloc: 1000 +# memcap: 16777216 + # Logging configuration. This is not about logging IDS alerts, but # IDS output about what its doing, errors, etc. logging: From a798cf9518192bb78432cddb43c848f31c22ba3f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 2 Sep 2015 13:07:59 +0200 Subject: [PATCH 0703/2553] DNS: refactor tx completion logic Use simple bool values to track the transaction state in both directions. A tx is only created in two cases: 1. full request parsed 2. response parsed (request missing) This is true even for multi-packet TCP requests. This leads to the following tx completion logic for the request side: the presence of a tx implies the request is complete On the response side, we consider the tx complete when we have seen the response. If the DNS parser thinks the response was lost, we also flag the response side as complete. --- src/app-layer-dns-common.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 852353f55b0b..4a3f9ccd0539 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -223,24 +223,26 @@ uint64_t DNSGetTxCnt(void *alstate) int DNSGetAlstateProgress(void *tx, uint8_t direction) { DNSTransaction *dns_tx = (DNSTransaction *)tx; - if (direction & STREAM_TOCLIENT) - return (dns_tx->replied|dns_tx->reply_lost) ? 2 : 1; + if (direction & STREAM_TOCLIENT) { + /* response side of the tx is done if we parsed a reply + * or if we tagged this tx as 'reply lost'. */ + return (dns_tx->replied|dns_tx->reply_lost) ? 1 : 0; + } else { - /* toserver/query is complete if we have stored a query */ - return (TAILQ_FIRST(&dns_tx->query_list) != NULL); + /* tx is only created if we have a complete request, + * or if we lost the request. Either way, if we have + * a tx it we consider the request complete. */ + return 1; } } /** \brief get value for 'complete' status in DNS * - * For DNS we use a simple bool. + * For DNS we use a simple bool. 1 means done. */ int DNSGetAlstateProgressCompletionStatus(uint8_t direction) { - if (direction & STREAM_TOCLIENT) - return 2; - else - return 1; + return 1; } void DNSSetEvent(DNSState *s, uint8_t e) From 8b3afb69862751f19c70fb82abeec07687e110ab Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Jul 2015 21:42:38 +0200 Subject: [PATCH 0704/2553] lua: add direction support --- src/util-lua.c | 18 ++++++++++++++++++ src/util-lua.h | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/src/util-lua.c b/src/util-lua.c index a93dcb5d80b0..32d206c35b8b 100644 --- a/src/util-lua.c +++ b/src/util-lua.c @@ -66,6 +66,8 @@ const char lua_ext_key_p[] = "suricata:lua:pkt:ptr"; const char lua_ext_key_flow[] = "suricata:lua:flow:ptr"; /* key for flow lock hint bool */ const char lua_ext_key_flow_lock_hint[] = "suricata:lua:flow:lock_hint"; +/* key for direction */ +const char lua_ext_key_direction[] = "suricata:lua:direction"; /* key for pa (packet alert) pointer */ const char lua_ext_key_pa[] = "suricata:lua:pkt:alert:ptr"; @@ -200,6 +202,22 @@ void LuaStateSetStreamingBuffer(lua_State *luastate, LuaStreamingBuffer *b) lua_settable(luastate, LUA_REGISTRYINDEX); } +/** \brief get packet pointer from the lua state */ +int LuaStateGetDirection(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_direction); + lua_gettable(luastate, LUA_REGISTRYINDEX); + int dir = lua_toboolean(luastate, -1); + return dir; +} + +void LuaStateSetDirection(lua_State *luastate, int direction) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_direction); + lua_pushboolean(luastate, direction); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + /** \brief dump stack from lua state to screen */ void LuaPrintStack(lua_State *state) { int size = lua_gettop(state); diff --git a/src/util-lua.h b/src/util-lua.h index 7ea69915b9e0..4ea4c60513f4 100644 --- a/src/util-lua.h +++ b/src/util-lua.h @@ -60,6 +60,8 @@ File *LuaStateGetFile(lua_State *luastate); LuaStreamingBuffer *LuaStateGetStreamingBuffer(lua_State *luastate); +int LuaStateGetDirection(lua_State *luastate); + /* sets */ void LuaStateSetPacket(lua_State *luastate, Packet *p); @@ -82,6 +84,8 @@ void LuaStateSetThreadVars(lua_State *luastate, ThreadVars *tv); void LuaStateSetStreamingBuffer(lua_State *luastate, LuaStreamingBuffer *b); +void LuaStateSetDirection(lua_State *luastate, int direction); + void LuaPrintStack(lua_State *state); int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len); From 1e84950017e8e74b9449c23ab7a2b35f48aef0d9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Jul 2015 21:44:38 +0200 Subject: [PATCH 0705/2553] detect-lua: set direction --- src/detect-lua-extensions.c | 4 +++- src/detect-lua-extensions.h | 2 +- src/detect-lua.c | 13 ++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index c58ffa2843e9..7a2657f9d354 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -560,7 +560,7 @@ static int LuaDecrFlowint(lua_State *luastate) } void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld, DetectEngineThreadCtx *det_ctx, - Flow *f, int flow_locked, Packet *p) + Flow *f, int flow_locked, Packet *p, uint8_t flags) { SCLogDebug("det_ctx %p, f %p", det_ctx, f); @@ -587,6 +587,8 @@ void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld, DetectEngi if (p != NULL) LuaStateSetPacket(lua_state, p); + + LuaStateSetDirection(lua_state, (flags & STREAM_TOSERVER)); } /** diff --git a/src/detect-lua-extensions.h b/src/detect-lua-extensions.h index e2edf9c6f9f3..b8aa27366ee9 100644 --- a/src/detect-lua-extensions.h +++ b/src/detect-lua-extensions.h @@ -29,7 +29,7 @@ int LuaRegisterExtensions(lua_State *); void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *, DetectEngineThreadCtx *det_ctx, - Flow *f, int flow_locked, Packet *p); + Flow *f, int flow_locked, Packet *p, uint8_t flags); #endif /* HAVE_LUA */ #endif diff --git a/src/detect-lua.c b/src/detect-lua.c index 76626a017622..8fd5ff61b31e 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -301,7 +301,7 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch /* setup extension data for use in lua c functions */ LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, - f, flow_lock, /* no packet in the ctx */NULL); + f, flow_lock, /* no packet in the ctx */NULL, 0); /* prepare data to pass to script */ lua_getglobal(tluajit->luastate, "match"); @@ -402,8 +402,14 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, SCReturnInt(0); /* setup extension data for use in lua c functions */ + uint8_t flags = 0; + if (p->flowflags & FLOW_PKT_TOSERVER) + flags = STREAM_TOSERVER; + else if (p->flowflags & FLOW_PKT_TOCLIENT) + flags = STREAM_TOCLIENT; + LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, - p->flow, /* flow not locked */LUA_FLOW_NOT_LOCKED_BY_PARENT, p); + p->flow, /* flow not locked */LUA_FLOW_NOT_LOCKED_BY_PARENT, p, flags); if ((tluajit->flags & DATATYPE_PAYLOAD) && p->payload_len == 0) SCReturnInt(0); @@ -533,7 +539,8 @@ static int DetectLuaAppMatchCommon (ThreadVars *t, DetectEngineThreadCtx *det_ct /* setup extension data for use in lua c functions */ LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, - f, /* flow is locked */LUA_FLOW_LOCKED_BY_PARENT, NULL); + f, /* flow is locked */LUA_FLOW_LOCKED_BY_PARENT, + NULL, flags); if (tluajit->alproto != ALPROTO_UNKNOWN) { int alproto = f->alproto; From 371648a8c61e93b42f74263bcedb9d1b8b1af354 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Jul 2015 21:45:15 +0200 Subject: [PATCH 0706/2553] lua: TLS support Support TLS in Lua detection scripts. function init (args) local needs = {} needs["tls"] = tostring(true) return needs end function match(args) version, subject, issuer, fingerprint = TlsGetCertInfo(); if version == nil then return 0 end str = string.format("Version %s\nIssuer %s\nSubject %s\nFingerprint %s", version, issuer, subject, fingerprint) SCLogInfo(str); return 1 end --- src/Makefile.am | 1 + src/detect-lua-extensions.c | 2 + src/detect-lua.c | 10 +++ src/util-lua-tls.c | 145 ++++++++++++++++++++++++++++++++++++ src/util-lua-tls.h | 33 ++++++++ 5 files changed, 191 insertions(+) create mode 100644 src/util-lua-tls.c create mode 100644 src/util-lua-tls.h diff --git a/src/Makefile.am b/src/Makefile.am index 1d59a5082fca..e74672f42573 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -349,6 +349,7 @@ util-lua.c util-lua.h \ util-lua-common.c util-lua-common.h \ util-lua-dns.c util-lua-dns.h \ util-lua-http.c util-lua-http.h \ +util-lua-tls.c util-lua-tls.h \ util-magic.c util-magic.h \ util-memcmp.c util-memcmp.h \ util-memcpy.h \ diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index 7a2657f9d354..020c886d9b00 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -66,6 +66,7 @@ #include "util-lua-common.h" #include "util-lua-http.h" #include "util-lua-dns.h" +#include "util-lua-tls.h" static const char luaext_key_ld[] = "suricata:luajitdata"; static const char luaext_key_det_ctx[] = "suricata:det_ctx"; @@ -617,6 +618,7 @@ int LuaRegisterExtensions(lua_State *lua_state) LuaRegisterFunctions(lua_state); LuaRegisterHttpFunctions(lua_state); LuaRegisterDnsFunctions(lua_state); + LuaRegisterTlsFunctions(lua_state); return 0; } diff --git a/src/detect-lua.c b/src/detect-lua.c index 8fd5ff61b31e..d1f2cd00c2e9 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -164,6 +164,8 @@ void DetectLuaRegister(void) #define DATATYPE_DNS_REQUEST (1<<16) #define DATATYPE_DNS_RESPONSE (1<<17) +#define DATATYPE_TLS (1<<18) + #ifdef HAVE_LUAJIT static void *LuaStatePoolAlloc(void) { @@ -1000,6 +1002,12 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) SCLogError(SC_ERR_LUA_ERROR, "alloc error"); goto error; } + } else if (strncmp(k, "tls", 3) == 0 && strcmp(v, "true") == 0) { + + ld->alproto = ALPROTO_TLS; + + ld->flags |= DATATYPE_TLS; + } else { SCLogError(SC_ERR_LUA_ERROR, "unsupported data type %s", k); goto error; @@ -1095,6 +1103,8 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) } else if (luajit->flags & DATATYPE_DNS_RESPONSE) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSRESPONSE_MATCH); } + } else if (luajit->alproto == ALPROTO_TLS) { + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); } else { SCLogError(SC_ERR_LUA_ERROR, "luajit can't be used with protocol %s", AppLayerGetProtoName(luajit->alproto)); diff --git a/src/util-lua-tls.c b/src/util-lua-tls.c new file mode 100644 index 000000000000..8816d5d5499a --- /dev/null +++ b/src/util-lua-tls.c @@ -0,0 +1,145 @@ +/* Copyright (C) 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 Eric Leblond + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-ssl.h" +#include "util-privs.h" +#include "util-buffer.h" +#include "util-proto-name.h" +#include "util-logopenfile.h" +#include "util-time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" +#include "util-lua-common.h" + +static int GetCertInfo(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_subject == NULL) + return LuaCallbackError(luastate, "error: no cert"); + + /* tls.version */ + char ssl_version[32] = ""; + switch (ssl_state->server_connp.version) { + case TLS_VERSION_UNKNOWN: + snprintf(ssl_version, sizeof(ssl_version), "UNDETERMINED"); + break; + case SSL_VERSION_2: + snprintf(ssl_version, sizeof(ssl_version), "SSLv2"); + break; + case SSL_VERSION_3: + snprintf(ssl_version, sizeof(ssl_version), "SSLv3"); + break; + case TLS_VERSION_10: + snprintf(ssl_version, sizeof(ssl_version), "TLSv1"); + break; + case TLS_VERSION_11: + snprintf(ssl_version, sizeof(ssl_version), "TLS 1.1"); + break; + case TLS_VERSION_12: + snprintf(ssl_version, sizeof(ssl_version), "TLS 1.2"); + break; + default: + snprintf(ssl_version, sizeof(ssl_version), "0x%04x", + ssl_state->server_connp.version); + break; + } + + int r = LuaPushStringBuffer(luastate, (uint8_t *)ssl_version, strlen(ssl_version)); + r += LuaPushStringBuffer(luastate, (uint8_t *)connp->cert0_subject, strlen(connp->cert0_subject)); + r += LuaPushStringBuffer(luastate, (uint8_t *)connp->cert0_issuerdn, strlen(connp->cert0_issuerdn)); + r += LuaPushStringBuffer(luastate, (uint8_t *)connp->cert0_fingerprint, strlen(connp->cert0_fingerprint)); + return r; +} + +static int TlsGetCertInfo(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + int lock_hint = 0; + Flow *f = LuaStateGetFlow(luastate, &lock_hint); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + FLOWLOCK_RDLOCK(f); + r = GetCertInfo(luastate, f, direction); + FLOWLOCK_UNLOCK(f); + } else { + r = GetCertInfo(luastate, f, direction); + } + return r; +} + +/** \brief register tls lua extensions in a luastate */ +int LuaRegisterTlsFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, TlsGetCertInfo); + lua_setglobal(luastate, "TlsGetCertInfo"); + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-tls.h b/src/util-lua-tls.h new file mode 100644 index 000000000000..57a27b5500be --- /dev/null +++ b/src/util-lua-tls.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2015 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 + */ + +#ifndef __UTIL_LUA_TLS_H__ +#define __UTIL_LUA_TLS_H__ + +#ifdef HAVE_LUA + +int LuaRegisterTlsFunctions(lua_State *luastate); + +#endif /* HAVE_LUA */ + +#endif /* __UTIL_LUA_TLS_H__ */ From 830dd324173c19186c6d600a9356ced61d8eb4fc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Aug 2015 18:08:55 +0200 Subject: [PATCH 0707/2553] decoder: add template/example Add fictional example / template for a packet decoder. It's not invoked anywhere. --- src/Makefile.am | 1 + src/decode-template.c | 97 +++++++++++++++++++++++++++++++++++++++++++ src/decode-template.h | 37 +++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 src/decode-template.c create mode 100644 src/decode-template.h diff --git a/src/Makefile.am b/src/Makefile.am index e74672f42573..e2ce97f1e7bb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,6 +60,7 @@ decode-teredo.c decode-teredo.h \ decode-udp.c decode-udp.h \ decode-vlan.c decode-vlan.h \ decode-mpls.c decode-mpls.h \ +decode-template.c decode-template.h \ defrag-config.c defrag-config.h \ defrag.c defrag.h \ defrag-hash.c defrag-hash.h \ diff --git a/src/decode-template.c b/src/decode-template.c new file mode 100644 index 000000000000..2673a2cdff56 --- /dev/null +++ b/src/decode-template.c @@ -0,0 +1,97 @@ +/* Copyright (C) 2015 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. + */ + +/** + * \ingroup decode + * + * @{ + */ + + +/** + * \file + * + * \author XXX Your Name + * + * Decodes XXX describe the protocol + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" +#include "decode-events.h" +#include "decode-template.h" + +#include "util-unittest.h" +#include "util-debug.h" + +/** + * \brief Function to decode XXX packets + * \param tv thread vars + * \param dtv decoder thread vars + * \param p packet + * \param pkt raw packet data + * \param len length in bytes of pkt array + * \retval TM_ECODE_OK or TM_ECODE_FAILED on serious error + */ + +int DecodeTEMPLATE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, + const uint8_t *pkt, uint16_t len, PacketQueue *pq) +{ + /* TODO add counter for your type of packet to DecodeThreadVars, + * and register it in DecodeRegisterPerfCounters */ + //StatsIncr(tv, dtv->counter_template); + + /* Validation: make sure that the input data is big enough to hold + * the header */ + if (len < sizeof(TemplateHdr)) { + /* in case of errors, we set events. Events are defined in + * decode-events.h, and are then exposed to the detection + * engine through detect-engine-events.h */ + //ENGINE_SET_EVENT(p,TEMPLATE_HEADER_TOO_SMALL); + return TM_ECODE_FAILED; + } + + /* Now we can access the header */ + const TemplateHdr *hdr = (const TemplateHdr *)pkt; + + /* lets assume we have UDP encapsulated */ + if (hdr->proto == 17) { + /* we need to pass on the pkt and it's length minus the current + * header */ + size_t hdr_len = sizeof(TemplateHdr); + + /* in this example it's clear that hdr_len can't be bigger than + * 'len', but in more complex cases checking that we can't underflow + * len is very important + if (hdr_len < len) { + */ + + /* invoke the next decoder on the remainder of the data */ + return DecodeUDP(tv, dtv, p, (uint8_t *)pkt + hdr_len, len - hdr_len, pq); + //} + } else { + //ENGINE_SET_EVENT(p,TEMPLATE_UNSUPPORTED_PROTOCOL); + return TM_ECODE_FAILED; + } + + return TM_ECODE_OK; +} + +/** + * @} + */ diff --git a/src/decode-template.h b/src/decode-template.h new file mode 100644 index 000000000000..b6a976e0e4f1 --- /dev/null +++ b/src/decode-template.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2015 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 XXX + * + */ + +#ifndef __DECODE_TEMPLATE_H__ +#define __DECODE_TEMPLATE_H__ + +#include "decode.h" +#include "threadvars.h" + +typedef struct TemplateHdr_ { + uint8_t proto; + uint8_t pad0; + uint16_t pad1; +} __attribute__((__packed__)) TemplateHdr; + +#endif /* __DECODE_TEMPLATE_H__ */ From 85b00dcfa06f558d7246d13851e4f61013bbba6a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 27 Aug 2015 17:37:52 +0200 Subject: [PATCH 0708/2553] development tools: add script to setup new decoder Simplify creation of a new decoder. --- scripts/setup_decoder.sh | 85 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 scripts/setup_decoder.sh diff --git a/scripts/setup_decoder.sh b/scripts/setup_decoder.sh new file mode 100644 index 000000000000..9af4104eb2fc --- /dev/null +++ b/scripts/setup_decoder.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# +# Script to setup a new decoder. +# Written by Victor Julien +# + +set -e +#set -x + +function Usage { + echo + echo "$(basename $0) -- script to provision a decoder. The script" + echo "makes a copy of the decode-template, sets the name and updates" + echo " the build system." + echo + echo "Call from the 'src' directory, with one argument: the decoder name." + echo + echo "E.g. inside 'src': ../scripts/$(basename $0) ipv7" + echo +} + +function Done { + echo + echo "Decoder $NR has been set up in $FILE_C and $FILE_H and the" + echo "build system has been updated." + echo + echo "The decoder should now compile cleanly. Try running 'make'." + echo + echo "Next steps are to edit the files to implement the actual" + echo "decoding of $NR." + echo +} + +if [ $# -ne "1" ]; then + Usage + echo "ERROR: call with one argument" + exit 1 +fi + +INPUT=$1 +# lowercase +LC=${INPUT,,} +#echo $LC +# UPPERCASE +UC=${LC^^} +#echo $UC +# Normal +NR=${LC^} +#echo $NR + +FILE_C="decode-${LC}.c" +FILE_H="decode-${LC}.h" +#echo $FILE_C +#echo $FILE_H + +if [ ! -e ../configure.ac ] || [ ! -e Makefile.am ]; then + Usage + echo "ERROR: call from src/ directory" + exit 1 +fi +if [ ! -e decode-template.c ] || [ ! -e decode-template.h ]; then + Usage + echo "ERROR: input files decode-template.c and/or decode-template.h are missing" + exit 1 +fi +if [ -e $FILE_C ] || [ -e $FILE_H ]; then + Usage + echo "ERROR: file(s) $FILE_C and/or $FILE_H already exist, won't overwrite" + exit 1 +fi + +cp decode-template.c $FILE_C +cp decode-template.h $FILE_H + +# search and replaces +sed -i "s/TEMPLATE/${UC}/g" $FILE_C +sed -i "s/TEMPLATE/${UC}/g" $FILE_H +sed -i "s/Template/${NR}/g" $FILE_C +sed -i "s/Template/${NR}/g" $FILE_H +sed -i "s/template/${LC}/g" $FILE_C +sed -i "s/template/${LC}/g" $FILE_H +sed -i "s/decode-template.c decode-template.h \\\/decode-template.c decode-template.h \\\\\n${FILE_C} ${FILE_H} \\\/g" Makefile.am + +Done +exit 0 From cb060f16fd4e6fea549fac98e752290cee84a8ba Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Nov 2012 16:57:53 +0100 Subject: [PATCH 0709/2553] detect plugin: add template --- src/Makefile.am | 1 + src/detect-template.c | 303 ++++++++++++++++++++++++++++++++++++++++++ src/detect-template.h | 41 ++++++ src/detect.c | 2 + src/detect.h | 2 + 5 files changed, 349 insertions(+) create mode 100644 src/detect-template.c create mode 100644 src/detect-template.h diff --git a/src/Makefile.am b/src/Makefile.am index e2ce97f1e7bb..de99d312f929 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -193,6 +193,7 @@ detect-ssl-state.c detect-ssl-state.h \ detect-ssl-version.c detect-ssl-version.h \ detect-stream_size.c detect-stream_size.h \ detect-tag.c detect-tag.h \ +detect-template.c detect-template.h \ detect-threshold.c detect-threshold.h \ detect-tls.c detect-tls.h \ detect-tls-version.c detect-tls-version.h \ diff --git a/src/detect-template.c b/src/detect-template.c new file mode 100644 index 000000000000..ecad7880b55b --- /dev/null +++ b/src/detect-template.c @@ -0,0 +1,303 @@ +/* Copyright (C) 2015 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 XXX Yourname + * + * XXX Short description of the purpose of this keyword + */ + +#include "suricata-common.h" +#include "util-unittest.h" + +#include "detect-parse.h" +#include "detect-engine.h" + +#include "detect-template.h" + +/** + * \brief Regex for parsing our keyword options + */ +#define PARSE_REGEX "^\\s*([0-9]+)?\\s*,s*([0-9]+)?\\s*$" +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +/* Prototypes of functions registered in DetectTemplateRegister below */ +static int DetectTemplateMatch (ThreadVars *, DetectEngineThreadCtx *, + Packet *, Signature *, const SigMatchCtx *); +static int DetectTemplateSetup (DetectEngineCtx *, Signature *, char *); +static void DetectTemplateFree (void *); +static void DetectTemplateRegisterTests (void); + +/** + * \brief Registration function for template: keyword + * + * This function is called once in the 'lifetime' of the engine. + */ +void DetectTemplateRegister(void) { + /* keyword name: this is how the keyword is used in a rule */ + sigmatch_table[DETECT_TEMPLATE].name = "template"; + /* description: listed in "suricata --list-keywords=all" */ + sigmatch_table[DETECT_TEMPLATE].desc = "give an introduction into how a detection module works"; + /* link to further documentation of the keyword. Normally on the Suricata redmine/wiki */ + sigmatch_table[DETECT_TEMPLATE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Developers_Guide"; + /* match function is called when the signature is inspected on a packet */ + sigmatch_table[DETECT_TEMPLATE].Match = DetectTemplateMatch; + /* setup function is called during signature parsing, when the template + * keyword is encountered in the rule */ + sigmatch_table[DETECT_TEMPLATE].Setup = DetectTemplateSetup; + /* free function is called when the detect engine is freed. Normally at + * shutdown, but also during rule reloads. */ + sigmatch_table[DETECT_TEMPLATE].Free = DetectTemplateFree; + /* registers unittests into the system */ + sigmatch_table[DETECT_TEMPLATE].RegisterTests = DetectTemplateRegisterTests; + + /* set up the PCRE for keyword parsing */ + const char *eb; + int eo; + int opts = 0; + + parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); + if (parse_regex == NULL) { + SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " + "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); + goto error; + } + + parse_regex_study = pcre_study(parse_regex, 0, &eb); + if (eb != NULL) { + SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + goto error; + } + return; + +error: + if (parse_regex != NULL) + SCFree(parse_regex); + if (parse_regex_study != NULL) + SCFree(parse_regex_study); + return; +} + +/** + * \brief This function is used to match TEMPLATE rule option on a packet + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch with context that we will cast into DetectTemplateData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectTemplateMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + Signature *s, const SigMatchCtx *ctx) +{ + int ret = 0; + const DetectTemplateData *templated = (const DetectTemplateData *) ctx; +#if 0 + if (PKT_IS_PSEUDOPKT(p)) { + /* fake pkt */ + } + + if (PKT_IS_IPV4(p)) { + /* ipv4 pkt */ + } else if (PKT_IS_IPV6(p)) { + /* ipv6 pkt */ + } else { + SCLogDebug("packet is of not IPv4 or IPv6"); + return ret; + } +#endif + /* packet payload access */ + if (p->payload != NULL && p->payload_len > 0) { + if (templated->arg1 == p->payload[0] && + templated->arg2 == p->payload[p->payload_len - 1]) + { + ret = 1; + } + } + + return ret; +} + +/** + * \brief This function is used to parse template options passed via template: keyword + * + * \param templatestr Pointer to the user provided template options + * + * \retval templated pointer to DetectTemplateData on success + * \retval NULL on failure + */ +static DetectTemplateData *DetectTemplateParse (const char *templatestr) +{ + DetectTemplateData *templated = NULL; + char arg1[4] = ""; + char arg2[4] = ""; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + + ret = pcre_exec(parse_regex, parse_regex_study, + templatestr, strlen(templatestr), + 0, 0, ov, MAX_SUBSTRINGS); + if (ret != 3) { + SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret); + goto error; + } + + res = pcre_copy_substring((char *) templatestr, ov, MAX_SUBSTRINGS, 1, arg1, sizeof(arg1)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("Arg1 \"%s\"", arg1); + + if (ret >= 3) { + res = pcre_copy_substring((char *) templatestr, ov, MAX_SUBSTRINGS, 2, arg2, sizeof(arg2)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("Arg2 \"%s\"", arg2); + + } + + templated = SCMalloc(sizeof (DetectTemplateData)); + if (unlikely(templated == NULL)) + goto error; + templated->arg1 = (uint8_t)atoi(arg1); + templated->arg2 = (uint8_t)atoi(arg2); + + return templated; + +error: + if (templated) + SCFree(templated); + return NULL; +} + +/** + * \brief parse the options from the 'template' keyword in the rule into + * the Signature data structure. + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param templatestr pointer to the user provided template options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectTemplateSetup (DetectEngineCtx *de_ctx, Signature *s, char *templatestr) +{ + DetectTemplateData *templated = NULL; + SigMatch *sm = NULL; + + templated = DetectTemplateParse(templatestr); + if (templated == NULL) + goto error; + + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_TEMPLATE; + sm->ctx = (void *)templated; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); + s->flags |= SIG_FLAG_REQUIRE_PACKET; + + return 0; + +error: + if (templated != NULL) + DetectTemplateFree(templated); + if (sm != NULL) + SCFree(sm); + return -1; +} + +/** + * \brief this function will free memory associated with DetectTemplateData + * + * \param ptr pointer to DetectTemplateData + */ +static void DetectTemplateFree(void *ptr) { + DetectTemplateData *templated = (DetectTemplateData *)ptr; + + /* do more specific cleanup here, if needed */ + + SCFree(templated); +} + +#ifdef UNITTESTS + +/** + * \test description of the test + */ + +static int DetectTemplateParseTest01 (void) { + DetectTemplateData *templated = NULL; + uint8_t res = 0; + + templated = DetectTemplateParse("1,10"); + if (templated != NULL) { + if (templated->arg1 == 1 && templated->arg2 == 10) + res = 1; + + DetectTemplateFree(templated); + } + + return res; +} + +static int DetectTemplateSignatureTest01 (void) { + uint8_t res = 0; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + Signature *sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (template:1,10; sid:1; rev:1;)"); + if (sig == NULL) { + printf("parsing signature failed: "); + goto end; + } + + /* if we get here, all conditions pass */ + res = 1; +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return res; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for DetectTemplate + */ +void DetectTemplateRegisterTests(void) { +#ifdef UNITTESTS + UtRegisterTest("DetectTemplateParseTest01", + DetectTemplateParseTest01, 1); + UtRegisterTest("DetectTemplateSignatureTest01", + DetectTemplateSignatureTest01, 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-template.h b/src/detect-template.h new file mode 100644 index 000000000000..d86c0083bb6e --- /dev/null +++ b/src/detect-template.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2015 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 XXX Yourname + */ + +#ifndef __DETECT_TEMPLATE_H__ +#define __DETECT_TEMPLATE_H__ + +/** Per keyword data. This is set up by the DetectTemplateSetup() function. + * Each signature will have an instance of DetectTemplateData per occurence + * of the keyword. + * The structure should be considered static/readonly after initialization. + */ +typedef struct DetectTemplateData_ { + uint8_t arg1; + uint8_t arg2; +} DetectTemplateData; + +/** \brief registers the keyword into the engine. Called from + * detect.c::SigTableSetup() */ +void DetectTemplateRegister(void); + +#endif /* __DETECT_TEMPLATE_H__ */ diff --git a/src/detect.c b/src/detect.c index e420f5e392cd..a1516200d010 100644 --- a/src/detect.c +++ b/src/detect.c @@ -155,6 +155,7 @@ #include "detect-geoip.h" #include "detect-dns-query.h" #include "detect-app-layer-protocol.h" +#include "detect-template.h" #include "util-rule-vars.h" @@ -5236,6 +5237,7 @@ void SigTableSetup(void) DetectDnsQueryRegister(); DetectModbusRegister(); DetectAppLayerProtocolRegister(); + DetectTemplateRegister(); } void SigTableRegisterTests(void) diff --git a/src/detect.h b/src/detect.h index 590ce24c6b41..236f69aa243b 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1228,6 +1228,8 @@ enum { DETECT_XBITS, + DETECT_TEMPLATE, + /* make sure this stays last */ DETECT_TBLSIZE, }; From a4bce14770beee46a537eda3c3f6e8e8565d5d0a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 28 Aug 2015 15:03:07 +0200 Subject: [PATCH 0710/2553] development tools: add script to setup detect module Simplify creation of a new detect module by creating a copy of the detect template. It sets the name and registers it in the build system. Finally it's registration function is called. --- scripts/setup_simple_detect.sh | 93 ++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 scripts/setup_simple_detect.sh diff --git a/scripts/setup_simple_detect.sh b/scripts/setup_simple_detect.sh new file mode 100644 index 000000000000..309b47cc2966 --- /dev/null +++ b/scripts/setup_simple_detect.sh @@ -0,0 +1,93 @@ +#!/bin/bash +# +# Script to setup a new 'simple' detect module. +# Written by Victor Julien +# + +set -e +#set -x + +function Usage { + echo + echo "$(basename $0) -- script to provision a detect module. The script" + echo "makes a copy of detect-template, sets the name and updates" + echo "the build system." + echo + echo "Call from the 'src' directory, with one argument: the detect module" + echo "name." + echo + echo "E.g. inside 'src': ../scripts/$(basename $0) helloworld" + echo +} + +function Done { + echo + echo "Detect module $NR has been set up in $FILE_C and $FILE_H" + echo "and the build system has been updated." + echo + echo "The detect module should now compile cleanly. Try running 'make'." + echo + echo "Next steps are to edit the files to implement the actual" + echo "detection logic of $NR." + echo +} + +if [ $# -ne "1" ]; then + Usage + echo "ERROR: call with one argument" + exit 1 +fi + +INPUT=$1 +# lowercase +LC=${INPUT,,} +#echo $LC +# UPPERCASE +UC=${LC^^} +#echo $UC +# Normal +NR=${LC^} +#echo $NR + +FILE_C="detect-${LC}.c" +FILE_H="detect-${LC}.h" +#echo $FILE_C +#echo $FILE_H + +if [ ! -e ../configure.ac ] || [ ! -e Makefile.am ]; then + Usage + echo "ERROR: call from src/ directory" + exit 1 +fi +if [ ! -e detect-template.c ] || [ ! -e detect-template.h ]; then + Usage + echo "ERROR: input files detect-template.c and/or detect-template.h are missing" + exit 1 +fi +if [ -e $FILE_C ] || [ -e $FILE_H ]; then + Usage + echo "ERROR: file(s) $FILE_C and/or $FILE_H already exist, won't overwrite" + exit 1 +fi + +cp detect-template.c $FILE_C +cp detect-template.h $FILE_H + +# search and replaces +sed -i "s/TEMPLATE/${UC}/g" $FILE_C +sed -i "s/TEMPLATE/${UC}/g" $FILE_H +sed -i "s/Template/${NR}/g" $FILE_C +sed -i "s/Template/${NR}/g" $FILE_H +sed -i "s/template/${LC}/g" $FILE_C +sed -i "s/template/${LC}/g" $FILE_H +# add to Makefile.am +sed -i "s/detect-template.c detect-template.h \\\/detect-template.c detect-template.h \\\\\n${FILE_C} ${FILE_H} \\\/g" Makefile.am +# update enum +sed -i "s/DETECT_TEMPLATE,/DETECT_TEMPLATE,\\n DETECT_${UC},/g" detect.h +# add include to detect.c +sed -i "s/#include \"detect-template.h\"/#include \"detect-template.h\"\\n#include \"${FILE_H}\"/g" detect.c +# add reg func to detect.c +sed -i "s/DetectTemplateRegister();/DetectTemplateRegister();\\n Detect${NR}Register();/g" detect.c + +Done +exit 0 From bcfb3fd5d59e602c2f620ce854c5d9b428c829c3 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 9 Sep 2015 22:40:37 +0200 Subject: [PATCH 0711/2553] docker: add ASAN to pcaps build --- qa/docker/buildbot.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/docker/buildbot.cfg b/qa/docker/buildbot.cfg index bce14d22f3a8..b2063ac9ca3b 100644 --- a/qa/docker/buildbot.cfg +++ b/qa/docker/buildbot.cfg @@ -126,7 +126,7 @@ pcaps_list = [ os.path.join(PCAP_PATH, pcap) for pcap in pcaps_list if pcap.ends factory_stress_pcap = SuriBuildFactory() # run the tests (note that this will require that 'trial' is installed) factory_stress_pcap.addStep(ShellCommand(command=["./autogen.sh"])) -factory_stress_pcap.addStep(ShellCommand(command=["./configure","--enable-debug-validation"])) +factory_stress_pcap.addStep(ShellCommand(command=["./configure","--enable-debug-validation"],env={"CFLAGS" : "-fsanitize=address -fno-omit-frame-pointer"})) factory_stress_pcap.addStep(ShellCommand(command=["make"])) factory_stress_pcap.addStep(ShellCommand(command=["sudo", "make","install"])) factory_stress_pcap.addStep(ShellCommand(command=["sudo", "rm", "-f", "/usr/local/etc/suricata/suricata.yaml"])) From c1b921265f4d1dc7b843e53b703eaf538c1f7c81 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 1 Sep 2015 12:04:34 -0600 Subject: [PATCH 0712/2553] app-layer: template for application layer parser --- src/Makefile.am | 1 + src/app-layer-detect-proto.c | 4 + src/app-layer-parser.c | 2 + src/app-layer-protos.c | 3 + src/app-layer-protos.h | 1 + src/app-layer-template.c | 533 +++++++++++++++++++++++++++++++++++ src/app-layer-template.h | 69 +++++ 7 files changed, 613 insertions(+) create mode 100644 src/app-layer-template.c create mode 100644 src/app-layer-template.h diff --git a/src/Makefile.am b/src/Makefile.am index de99d312f929..97a3a993633f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,6 +33,7 @@ app-layer-protos.c app-layer-protos.h \ app-layer-smb2.c app-layer-smb2.h \ app-layer-smb.c app-layer-smb.h \ app-layer-smtp.c app-layer-smtp.h \ +app-layer-template.c app-layer-template.h \ app-layer-ssh.c app-layer-ssh.h \ app-layer-ssl.c app-layer-ssl.h \ app-layer-tls-handshake.c app-layer-tls-handshake.h \ diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index ed029e5e6b8b..221b50ffc801 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -687,6 +687,8 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp printf(" alproto: ALPROTO_DNS\n"); else if (pp_pe->alproto == ALPROTO_MODBUS) printf(" alproto: ALPROTO_MODBUS\n"); + else if (pp_pe->alproto == ALPROTO_TEMPLATE) + printf(" alproto: ALPROTO_TEMPLATE\n"); else printf("impossible\n"); @@ -738,6 +740,8 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp printf(" alproto: ALPROTO_DNS\n"); else if (pp_pe->alproto == ALPROTO_MODBUS) printf(" alproto: ALPROTO_MODBUS\n"); + else if (pp_pe->alproto == ALPROTO_TEMPLATE) + printf(" alproto: ALPROTO_TEMPLATE\n"); else printf("impossible\n"); diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 134f99095c1c..2650863e2082 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -58,6 +58,7 @@ #include "app-layer-dns-udp.h" #include "app-layer-dns-tcp.h" #include "app-layer-modbus.h" +#include "app-layer-template.h" #include "conf.h" #include "util-spm.h" @@ -1106,6 +1107,7 @@ void AppLayerParserRegisterProtocolParsers(void) RegisterDNSUDPParsers(); RegisterDNSTCPParsers(); RegisterModbusParsers(); + RegisterTemplateParsers(); /** IMAP */ AppLayerProtoDetectRegisterProtocol(ALPROTO_IMAP, "imap"); diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index 0b8ed17bee7d..e8875643f879 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -75,6 +75,9 @@ const char *AppProtoToString(AppProto alproto) case ALPROTO_MODBUS: proto_name = "modbus"; break; + case ALPROTO_TEMPLATE: + proto_name = "template"; + break; case ALPROTO_FAILED: #ifdef UNITTESTS case ALPROTO_TEST: diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index 79973661efc9..aff90e9bbaf7 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -42,6 +42,7 @@ enum AppProtoEnum { ALPROTO_DNS, ALPROTO_MODBUS, + ALPROTO_TEMPLATE, /* used by the probing parser when alproto detection fails * permanently for that particular stream */ diff --git a/src/app-layer-template.c b/src/app-layer-template.c new file mode 100644 index 000000000000..87b64b732f76 --- /dev/null +++ b/src/app-layer-template.c @@ -0,0 +1,533 @@ +/* Copyright (C) 2015 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 Template application layer detector and parser for learning and + * template pruposes. + * + * This template implements a simple application layer for something + * like the echo protocol running on port 7. + */ + +#include "suricata-common.h" +#include "stream.h" + +#include "util-unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer-template.h" + +/* The default port to probe for echo traffic if not provided in the + * configuration file. */ +#define TEMPLATE_DEFAULT_PORT "7" + +/* The minimum size for an echo message. For some protocols this might + * be the size of a header. */ +#define TEMPLATE_MIN_FRAME_LEN 1 + +/* Enum of app-layer events for an echo protocol. Normally you might + * have events for errors in parsing data, like unexpected data being + * received. For echo we'll make something up, and log an app-layer + * level alert if an empty message is received. + * + * Example rule: + * + * alert template any any -> any any (msg:"SURCATA Template empty message"; \ + * app-layer-event:template.empty_message; sid:X; rev:Y;) + */ +enum { + TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE, +}; + +SCEnumCharMap template_decoder_event_table[] = { + {"EMPTY_MESSAGE", TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE}, +}; + +static TemplateTransaction *TemplateTxAlloc(TemplateState *echo) +{ + TemplateTransaction *tx = SCCalloc(1, sizeof(TemplateTransaction)); + if (unlikely(tx == NULL)) { + return NULL; + } + + /* Increment the transaction ID on the state each time one is + * allocated. */ + tx->tx_id = echo->transaction_max++; + + TAILQ_INSERT_TAIL(&echo->tx_list, tx, next); + + return tx; +} + +static void TemplateTxFree(void *tx) +{ + TemplateTransaction *templatetx = tx; + + if (templatetx->request_buffer != NULL) { + SCFree(templatetx->request_buffer); + } + + if (templatetx->response_buffer != NULL) { + SCFree(templatetx->response_buffer); + } + + AppLayerDecoderEventsFreeEvents(&templatetx->decoder_events); + + SCFree(tx); +} + +static void *TemplateStateAlloc(void) +{ + SCLogNotice("Allocating template state."); + TemplateState *state = SCCalloc(1, sizeof(TemplateState)); + if (unlikely(state == NULL)) { + return NULL; + } + TAILQ_INIT(&state->tx_list); + return state; +} + +static void TemplateStateFree(void *state) +{ + TemplateState *template_state = state; + TemplateTransaction *tx; + SCLogNotice("Freeing template state."); + while ((tx = TAILQ_FIRST(&template_state->tx_list)) != NULL) { + TAILQ_REMOVE(&template_state->tx_list, tx, next); + TemplateTxFree(tx); + } + SCFree(template_state); +} + +/** + * \brief Callback from the application layer to have a transaction freed. + * + * \param state a void pointer to the TemplateState object. + * \param tx_id the transaction ID to free. + */ +static void TemplateStateTxFree(void *state, uint64_t tx_id) +{ + TemplateState *echo = state; + TemplateTransaction *tx = NULL, *ttx; + + SCLogNotice("Freeing transaction %"PRIu64, tx_id); + + TAILQ_FOREACH_SAFE(tx, &echo->tx_list, next, ttx) { + + /* Continue if this is not the transaction we are looking + * for. */ + if (tx->tx_id != tx_id) { + continue; + } + + /* Remove and free the transaction. */ + TAILQ_REMOVE(&echo->tx_list, tx, next); + TemplateTxFree(tx); + return; + } + + SCLogNotice("Transaction %"PRIu64" not found.", tx_id); +} + +static int TemplateStateGetEventInfo(const char *event_name, int *event_id, + AppLayerEventType *event_type) +{ + *event_id = SCMapEnumNameToValue(event_name, template_decoder_event_table); + if (*event_id == -1) { + SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in " + "template enum map table.", event_name); + /* This should be treated as fatal. */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static AppLayerDecoderEvents *TemplateGetEvents(void *state, uint64_t tx_id) +{ + TemplateState *template_state = state; + TemplateTransaction *tx; + + TAILQ_FOREACH(tx, &template_state->tx_list, next) { + if (tx->tx_id == tx_id) { + return tx->decoder_events; + } + } + + return NULL; +} + +static int TemplateHasEvents(void *state) +{ + TemplateState *echo = state; + return echo->events; +} + +/** + * \brief Probe the input to see if it looks like echo. + * + * \retval ALPROTO_TEMPLATE if it looks like echo, otherwise + * ALPROTO_UNKNOWN. + */ +static AppProto TemplateProbingParser(uint8_t *input, uint32_t input_len, + uint32_t *offset) +{ + /* Very simple test - if there is input, this is echo. */ + if (input_len >= TEMPLATE_MIN_FRAME_LEN) { + SCLogNotice("Detected as ALPROTO_TEMPLATE."); + return ALPROTO_TEMPLATE; + } + + SCLogNotice("Protocol not detected as ALPROTO_TEMPLATE."); + return ALPROTO_UNKNOWN; +} + +static int TemplateParseRequest(Flow *f, void *state, + AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, + void *local_data) +{ + TemplateState *echo = state; + + SCLogNotice("Parsing echo request: len=%"PRIu32, input_len); + + /* Likely connection closed, we can just return here. */ + if ((input == NULL || input_len == 0) && + AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + return 0; + } + + /* Probably don't want to create a transaction in this case + * either. */ + if (input == NULL || input_len == 0) { + return 0; + } + + /* Normally you would parse out data here and store it in the + * transaction object, but as this is echo, we'll just record the + * request data. */ + + /* Also, if this protocol may have a "protocol data unit" span + * multiple chunks of data, which is always a possibility with + * TCP, you may need to do some buffering here. + * + * For the sake of simplicity, buffering is left out here, but + * even for an echo protocol we may want to buffer until a new + * line is seen, assuming its text based. + */ + + /* Allocate a transaction. + * + * But note that if a "protocol data unit" is not received in one + * chunk of data, and the buffering is done on the transaction, we + * may need to look for the transaction that this newly recieved + * data belongs to. + */ + TemplateTransaction *tx = TemplateTxAlloc(echo); + if (unlikely(tx == NULL)) { + SCLogNotice("Failed to allocate new Template tx."); + goto end; + } + SCLogNotice("Allocated Template tx %"PRIu64".", tx->tx_id); + + /* Make a copy of the request. */ + tx->request_buffer = SCCalloc(1, input_len); + if (unlikely(tx->request_buffer == NULL)) { + goto end; + } + memcpy(tx->request_buffer, input, input_len); + tx->request_buffer_len = input_len; + + /* Here we check for an empty message and create an app-layer + * event. */ + if ((input_len == 1 && tx->request_buffer[0] == '\n') || + (input_len == 2 && tx->request_buffer[0] == '\r')) { + SCLogNotice("Creating event for empty message."); + AppLayerDecoderEventsSetEventRaw(&tx->decoder_events, + TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE); + echo->events++; + } + +end: + return 0; +} + +static int TemplateParseResponse(Flow *f, void *state, AppLayerParserState *pstate, + uint8_t *input, uint32_t input_len, void *local_data) +{ + TemplateState *echo = state; + TemplateTransaction *tx = NULL, *ttx;; + + SCLogNotice("Parsing Template response."); + + /* Likely connection closed, we can just return here. */ + if ((input == NULL || input_len == 0) && + AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + return 0; + } + + /* Probably don't want to create a transaction in this case + * either. */ + if (input == NULL || input_len == 0) { + return 0; + } + + /* Look up the existing transaction for this response. In the case + * of echo, it will be the most recent transaction on the + * TemplateState object. */ + + /* We should just grab the last transaction, but this is to + * illustrate how you might traverse the transaction list to find + * the transaction associated with this response. */ + TAILQ_FOREACH(ttx, &echo->tx_list, next) { + tx = ttx; + } + + if (tx == NULL) { + SCLogNotice("Failed to find transaction for response on echo state %p.", + echo); + goto end; + } + + SCLogNotice("Found transaction %"PRIu64" for response on echo state %p.", + tx->tx_id, echo); + + /* If the protocol requires multiple chunks of data to complete, you may + * run into the case where you have existing response data. + * + * In this case, we just log that there is existing data and free it. But + * you might want to realloc the buffer and append the data. + */ + if (tx->response_buffer != NULL) { + SCLogNotice("WARNING: Transaction already has response data, " + "existing data will be overwritten."); + SCFree(tx->response_buffer); + } + + /* Make a copy of the response. */ + tx->response_buffer = SCCalloc(1, input_len); + if (unlikely(tx->response_buffer == NULL)) { + goto end; + } + memcpy(tx->response_buffer, input, input_len); + tx->response_buffer_len = input_len; + + /* Set the response_done flag for transaction state checking in + * TemplateGetStateProgress(). */ + tx->response_done = 1; + +end: + return 0; +} + +static uint64_t TemplateGetTxCnt(void *state) +{ + TemplateState *echo = state; + SCLogNotice("Current tx count is %"PRIu64".", echo->transaction_max); + return echo->transaction_max; +} + +static void *TemplateGetTx(void *state, uint64_t tx_id) +{ + TemplateState *echo = state; + TemplateTransaction *tx; + + SCLogNotice("Requested tx ID %"PRIu64".", tx_id); + + TAILQ_FOREACH(tx, &echo->tx_list, next) { + if (tx->tx_id == tx_id) { + SCLogNotice("Transaction %"PRIu64" found, returning tx object %p.", + tx_id, tx); + return tx; + } + } + + SCLogNotice("Transaction ID %"PRIu64" not found.", tx_id); + return NULL; +} + +/** + * \brief Called by the application layer. + * + * In most cases 1 can be returned here. + */ +static int TemplateGetAlstateProgressCompletionStatus(uint8_t direction) { + return 1; +} + +/** + * \brief Return the state of a transaction in a given direction. + * + * In the case of the echo protocol, the existence of a transaction + * means that the request is done. However, some protocols that may + * need multiple chunks of data to complete the request may need more + * than just the existence of a transaction for the request to be + * considered complete. + * + * For the response to be considered done, the response for a request + * needs to be seen. The response_done flag is set on response for + * checking here. + */ +static int TemplateGetStateProgress(void *tx, uint8_t direction) +{ + TemplateTransaction *echotx = tx; + + SCLogNotice("Transaction progress requested for tx ID %"PRIu64 + ", direction=0x%02x", echotx->tx_id, direction); + + if (direction & STREAM_TOCLIENT && echotx->response_done) { + return 1; + } + else if (direction & STREAM_TOSERVER) { + /* For echo, just the existence of the transaction means the + * request is done. */ + return 1; + } + + return 0; +} + +/** + * \brief ??? + */ +static DetectEngineState *TemplateGetTxDetectState(void *vtx) +{ + TemplateTransaction *tx = vtx; + return tx->de_state; +} + +/** + * \brief ??? + */ +static int TemplateSetTxDetectState(void *state, void *vtx, + DetectEngineState *s) +{ + TemplateTransaction *tx = vtx; + tx->de_state = s; + return 0; +} + +void RegisterTemplateParsers(void) +{ + char *proto_name = "template"; + + /* Check if Template TCP detection is enabled. If it does not exist in + * the configuration file then it will be enabled by default. */ + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + + SCLogNotice("Template TCP protocol detection enabled."); + + AppLayerProtoDetectRegisterProtocol(ALPROTO_TEMPLATE, proto_name); + + if (RunmodeIsUnittests()) { + + SCLogNotice("Unittest mode, registeringd default configuration."); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, TEMPLATE_DEFAULT_PORT, + ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER, + TemplateProbingParser); + + } + else { + + if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, + proto_name, ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, + TemplateProbingParser)) { + SCLogNotice("No echo app-layer configuration, enabling echo" + " detection TCP detection on port %s.", + TEMPLATE_DEFAULT_PORT); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + TEMPLATE_DEFAULT_PORT, ALPROTO_TEMPLATE, 0, + TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER, + TemplateProbingParser); + } + + } + + } + + else { + SCLogNotice("Protocol detecter and parser disabled for Template."); + return; + } + + if (AppLayerParserConfParserEnabled("udp", proto_name)) { + + SCLogNotice("Registering Template protocol parser."); + + /* Register functions for state allocation and freeing. A + * state is allocated for every new Template flow. */ + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateStateAlloc, TemplateStateFree); + + /* Register request parser for parsing frame from server to client. */ + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE, + STREAM_TOSERVER, TemplateParseRequest); + + /* Register response parser for parsing frames from server to client. */ + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE, STREAM_TOCLIENT, + TemplateParseResponse); + + /* Register a function to be called by the application layer + * when a transaction is to be freed. */ + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateStateTxFree); + + /* Register a function to return the current transaction count. */ + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEMPLATE, TemplateGetTxCnt); + + /* Transaction handling. */ + AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, + ALPROTO_TEMPLATE, TemplateGetAlstateProgressCompletionStatus); + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, + ALPROTO_TEMPLATE, TemplateGetStateProgress); + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateGetTx); + + /* Application layer event handling. */ + AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateHasEvents); + + /* What is this being registered for? */ + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE, + NULL, TemplateGetTxDetectState, TemplateSetTxDetectState); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateStateGetEventInfo); + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateGetEvents); + } + else { + SCLogNotice("Template protocol parsing disabled."); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateParserRegisterTests); +#endif +} + +#ifdef UNITTESTS +#endif + +void TemplateParserRegisterTests(void) +{ +#ifdef UNITTESTS +#endif +} diff --git a/src/app-layer-template.h b/src/app-layer-template.h new file mode 100644 index 000000000000..4e58fa89b52a --- /dev/null +++ b/src/app-layer-template.h @@ -0,0 +1,69 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __APP_LAYER_TEMPLATE_H__ +#define __APP_LAYER_TEMPLATE_H__ + +#include "detect-engine-state.h" + +#include "queue.h" + +void RegisterTemplateParsers(void); +void TemplateParserRegisterTests(void); + +typedef struct TemplateTransaction_ { + + uint64_t tx_id; /*<< Internal transaction ID. */ + + AppLayerDecoderEvents *decoder_events; /*<< Application layer + * events that occurred + * while parsing this + * transaction. */ + + uint8_t *request_buffer; + uint32_t request_buffer_len; + + uint8_t *response_buffer; + uint32_t response_buffer_len; + + uint8_t response_done; /*<< Flag to be set when the response is + * seen. */ + + DetectEngineState *de_state; + + TAILQ_ENTRY(TemplateTransaction_) next; + +} TemplateTransaction; + +typedef struct TemplateState_ { + + TAILQ_HEAD(, TemplateTransaction_) tx_list; /**< List of Template transactions + * associated with this + * state. */ + + uint64_t transaction_max; /**< A count of the number of + * transactions created. The + * transaction ID for each transaction + * is allocted by incrementing this + * value. */ + + uint16_t events; /**< Number of application layer events created + * for this state. */ + +} TemplateState; + +#endif /* __APP_LAYER_TEMPLATE_H__ */ From bcda92134d01b5c8c7b3cf114858ebf67e99f0c2 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 1 Sep 2015 12:12:28 -0600 Subject: [PATCH 0713/2553] app-layer: template for application layer tx logger --- src/Makefile.am | 1 + src/output-json-template.c | 213 +++++++++++++++++++++++++++++++++++++ src/output-json-template.h | 23 ++++ src/suricata.c | 5 + src/tm-modules.c | 1 + src/tm-threads-common.h | 1 + 6 files changed, 244 insertions(+) create mode 100644 src/output-json-template.c create mode 100644 src/output-json-template.h diff --git a/src/Makefile.am b/src/Makefile.am index 97a3a993633f..9d3809c2f403 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -251,6 +251,7 @@ output-json-smtp.c output-json-smtp.h \ output-json-ssh.c output-json-ssh.h \ output-json-stats.c output-json-stats.h \ output-json-tls.c output-json-tls.h \ +output-json-template.c output-json-template.h \ output-lua.c output-lua.h \ output-packet.c output-packet.h \ output-stats.c output-stats.h \ diff --git a/src/output-json-template.c b/src/output-json-template.c new file mode 100644 index 000000000000..ca4a937837ba --- /dev/null +++ b/src/output-json-template.c @@ -0,0 +1,213 @@ +/* Copyright (C) 2015 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. + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-unittest.h" +#include "util-buffer.h" +#include "util-debug.h" +#include "util-byte.h" + +#include "output.h" +#include "output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-template.h" + +#ifdef HAVE_LIBJANSSON +#include + +typedef struct LogTemplateFileCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; +} LogTemplateFileCtx; + +typedef struct LogTemplateLogThread_ { + LogTemplateFileCtx *templatelog_ctx; + uint32_t count; + MemBuffer *buffer; +} LogTemplateLogThread; + +static int JsonTemplateLogger(ThreadVars *tv, void *thread_data, + const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) +{ + TemplateTransaction *templatetx = tx; + LogTemplateLogThread *thread = thread_data; + MemBuffer *buffer = thread->buffer; + json_t *js, *templatejs; + + SCLogNotice("Logging template transaction %"PRIu64".", templatetx->tx_id); + + js = CreateJSONHeader((Packet *)p, 0, "template"); + if (unlikely(js == NULL)) { + return TM_ECODE_FAILED; + } + + templatejs = json_object(); + if (unlikely(templatejs == NULL)) { + goto error; + } + + /* Convert the request buffer to a string then log. */ + char *request_buffer = BytesToString(templatetx->request_buffer, + templatetx->request_buffer_len); + if (request_buffer != NULL) { + json_object_set_new(templatejs, "request", json_string(request_buffer)); + SCFree(request_buffer); + } + + /* Convert the response buffer to a string then log. */ + char *response_buffer = BytesToString(templatetx->response_buffer, + templatetx->response_buffer_len); + if (response_buffer != NULL) { + json_object_set_new(templatejs, "response", + json_string(response_buffer)); + SCFree(response_buffer); + } + + json_object_set_new(js, "template", templatejs); + + MemBufferReset(buffer); + OutputJSONBuffer(js, thread->templatelog_ctx->file_ctx, buffer); + + json_decref(js); + return TM_ECODE_OK; + +error: + if (templatejs != NULL) { + json_decref(templatejs); + } + json_decref(js); + return TM_ECODE_FAILED; +} + +static void OutputTemplateLogDeInitCtxSub(OutputCtx *output_ctx) +{ + LogTemplateFileCtx *templatelog_ctx = (LogTemplateFileCtx *)output_ctx->data; + SCFree(templatelog_ctx); + SCFree(output_ctx); +} + +static OutputCtx *OutputTemplateLogInitSub(ConfNode *conf, + OutputCtx *parent_ctx) +{ + AlertJsonThread *ajt = parent_ctx->data; + + LogTemplateFileCtx *templatelog_ctx = SCCalloc(1, sizeof(*templatelog_ctx)); + if (unlikely(templatelog_ctx == NULL)) { + return NULL; + } + templatelog_ctx->file_ctx = ajt->file_ctx; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(templatelog_ctx); + return NULL; + } + output_ctx->data = templatelog_ctx; + output_ctx->DeInit = OutputTemplateLogDeInitCtxSub; + + SCLogNotice("Template log sub-module initialized."); + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TEMPLATE); + + return output_ctx; +} + +#define OUTPUT_BUFFER_SIZE 65535 + +static TmEcode JsonTemplateLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + LogTemplateLogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for Template. \"initdata\" is NULL."); + SCFree(thread); + return TM_ECODE_FAILED; + } + + thread->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (unlikely(thread->buffer == NULL)) { + SCFree(thread); + return TM_ECODE_FAILED; + } + + thread->templatelog_ctx = ((OutputCtx *)initdata)->data; + *data = (void *)thread; + + return TM_ECODE_OK; +} + +static TmEcode JsonTemplateLogThreadDeinit(ThreadVars *t, void *data) +{ + LogTemplateLogThread *thread = (LogTemplateLogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + if (thread->buffer != NULL) { + MemBufferFree(thread->buffer); + } + SCFree(thread); + return TM_ECODE_OK; +} + +void TmModuleJsonTemplateLogRegister(void) +{ + tmm_modules[TMM_JSONTEMPLATELOG].name = "JsonTemplateLog"; + tmm_modules[TMM_JSONTEMPLATELOG].ThreadInit = JsonTemplateLogThreadInit; + tmm_modules[TMM_JSONTEMPLATELOG].ThreadDeinit = JsonTemplateLogThreadDeinit; + tmm_modules[TMM_JSONTEMPLATELOG].RegisterTests = NULL; + tmm_modules[TMM_JSONTEMPLATELOG].cap_flags = 0; + tmm_modules[TMM_JSONTEMPLATELOG].flags = TM_FLAG_LOGAPI_TM; + + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule("eve-log", "JsonTemplateLog", "eve-log.template", + OutputTemplateLogInitSub, ALPROTO_TEMPLATE, JsonTemplateLogger); + + SCLogNotice("Template JSON logger registered."); +} + +#else /* No JSON support. */ + +static TmEcode JsonTemplateLogThreadInit(ThreadVars *t, void *initdata, + void **data) +{ + SCLogInfo("Cannot initialize JSON output for template. " + "JSON support was disabled during build."); + return TM_ECODE_FAILED; +} + +void TmModuleJsonTemplateLogRegister(void) +{ + tmm_modules[TMM_JSONTEMPLATELOG].name = "JsonTemplateLog"; + tmm_modules[TMM_JSONTEMPLATELOG].ThreadInit = JsonTemplateLogThreadInit; +} + +#endif /* HAVE_LIBJANSSON */ diff --git a/src/output-json-template.h b/src/output-json-template.h new file mode 100644 index 000000000000..d071e1828b59 --- /dev/null +++ b/src/output-json-template.h @@ -0,0 +1,23 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __OUTPUT_JSON_TEMPLATE_H__ +#define __OUTPUT_JSON_TEMPLATE_H__ + +void TmModuleJsonTemplateLogRegister(void); + +#endif /* __OUTPUT_JSON_TEMPLATE_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 7c661e1938ac..6c45c57e9931 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -102,6 +102,8 @@ #include "output-json.h" +#include "output-json-template.h" + #include "stream-tcp.h" #include "source-nfq.h" @@ -897,6 +899,9 @@ void RegisterAllModules() /* json stats */ TmModuleJsonStatsLogRegister(); + /* Template JSON logger. */ + TmModuleJsonTemplateLogRegister(); + /* log api */ TmModulePacketLoggerRegister(); TmModuleTxLoggerRegister(); diff --git a/src/tm-modules.c b/src/tm-modules.c index 73e9f235fd9d..06190b654905 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -272,6 +272,7 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_DETECTLOADER); CASE_CODE (TMM_LUALOG); CASE_CODE (TMM_LOGSTATSLOG); + CASE_CODE (TMM_JSONTEMPLATELOG); CASE_CODE (TMM_RECEIVENETMAP); CASE_CODE (TMM_DECODENETMAP); CASE_CODE (TMM_TLSSTORE); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index f6629eaa82e5..6a66b41795f9 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -101,6 +101,7 @@ typedef enum { TMM_JSONFLOWLOG, TMM_JSONNETFLOWLOG, TMM_LOGSTATSLOG, + TMM_JSONTEMPLATELOG, TMM_FLOWMANAGER, TMM_FLOWRECYCLER, From 06beca62f58621a05c6027021d093d836ce02323 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 1 Sep 2015 12:36:00 -0600 Subject: [PATCH 0714/2553] app-layer: template for application layer content inspection --- src/Makefile.am | 2 + src/detect-engine-content-inspection.h | 1 + src/detect-engine-state.h | 1 + src/detect-engine-template.c | 46 +++++++ src/detect-engine-template.h | 25 ++++ src/detect-engine.c | 18 +++ src/detect-parse.c | 5 + src/detect-template-buffer.c | 165 +++++++++++++++++++++++++ src/detect-template-buffer.h | 25 ++++ src/detect.c | 12 ++ src/detect.h | 4 + 11 files changed, 304 insertions(+) create mode 100644 src/detect-engine-template.c create mode 100644 src/detect-engine-template.h create mode 100644 src/detect-template-buffer.c create mode 100644 src/detect-template-buffer.h diff --git a/src/Makefile.am b/src/Makefile.am index 9d3809c2f403..674043f5db72 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -123,6 +123,7 @@ detect-engine-siggroup.c detect-engine-siggroup.h \ detect-engine-sigorder.c detect-engine-sigorder.h \ detect-engine-state.c detect-engine-state.h \ detect-engine-tag.c detect-engine-tag.h \ +detect-engine-template.c detect-engine-template.h \ detect-engine-threshold.c detect-engine-threshold.h \ detect-engine-uri.c detect-engine-uri.h \ detect-fast-pattern.c detect-fast-pattern.h \ @@ -195,6 +196,7 @@ detect-ssl-version.c detect-ssl-version.h \ detect-stream_size.c detect-stream_size.h \ detect-tag.c detect-tag.h \ detect-template.c detect-template.h \ +detect-template-buffer.c detect-template-buffer.h \ detect-threshold.c detect-threshold.h \ detect-tls.c detect-tls.h \ detect-tls-version.c detect-tls-version.h \ diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 6d3accaaa324..dc0b5026bee7 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -50,6 +50,7 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, }; int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 51f67448e778..c8944cffd17c 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -81,6 +81,7 @@ #define DE_STATE_FLAG_FD_SMTP_INSPECT (1 << 21) #define DE_STATE_FLAG_DNSREQUEST_INSPECT (1 << 22) #define DE_STATE_FLAG_DNSRESPONSE_INSPECT (1 << 23) +#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT (1 << 24) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine-template.c b/src/detect-engine-template.c new file mode 100644 index 000000000000..49c29c6a6ae0 --- /dev/null +++ b/src/detect-engine-template.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2015 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. + */ + +#include "suricata-common.h" +#include "stream.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer-template.h" + +int DetectEngineInspectTemplateBuffer(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + TemplateTransaction *tx = (TemplateTransaction *)txv; + int ret = 0; + + if (flags & STREAM_TOSERVER && tx->request_buffer != NULL) { + ret = DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH], f, + tx->request_buffer, tx->request_buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, NULL); + } + else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { + ret = DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH], f, + tx->response_buffer, tx->response_buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, NULL); + } + + SCLogNotice("Returning %d.", ret); + return ret; +} diff --git a/src/detect-engine-template.h b/src/detect-engine-template.h new file mode 100644 index 000000000000..61eb8d01035b --- /dev/null +++ b/src/detect-engine-template.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __DETECT_TEMPLATE_ENGINE_H__ +#define __DETECT_TEMPLATE_ENGINE_H__ + +int DetectEngineInspectTemplateBuffer(ThreadVars *, DetectEngineCtx *, + DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, void *, + uint64_t); + +#endif /* __DETECT_TEMPLATE_ENGINE_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 7de049693f97..c6e1a83f4c5f 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -62,6 +62,7 @@ #include "detect-engine-dns.h" #include "detect-engine-modbus.h" #include "detect-engine-filedata-smtp.h" +#include "detect-engine-template.h" #include "detect-engine.h" #include "detect-engine-state.h" @@ -285,6 +286,13 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_FD_SMTP_INSPECT, 0, DetectEngineInspectSMTPFiledata }, + /* Template. */ + { IPPROTO_TCP, + ALPROTO_TEMPLATE, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT, + 0, + DetectEngineInspectTemplateBuffer }, }; struct tmp_t data_toclient[] = { @@ -352,6 +360,13 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_DNSRESPONSE_INSPECT, 1, DetectEngineInspectDnsResponse }, + /* Template. */ + { IPPROTO_TCP, + ALPROTO_TEMPLATE, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT, + 1, + DetectEngineInspectTemplateBuffer }, }; size_t i; @@ -2630,6 +2645,9 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; + case DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH: + return "template_buffer"; + case DETECT_SM_LIST_POSTMATCH: return "post-match"; diff --git a/src/detect-parse.c b/src/detect-parse.c index d077791e345a..fedfebe8648d 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1479,6 +1479,11 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (sig->sm_lists[DETECT_SM_LIST_HRHHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + /* Template. */ + if (sig->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH]) { + sig->flags |= SIG_FLAG_STATE_MATCH; + } + /* DNS */ if (sig->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c new file mode 100644 index 000000000000..64f948c2b45b --- /dev/null +++ b/src/detect-template-buffer.c @@ -0,0 +1,165 @@ +/* Copyright (C) 2015 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 Set up of the "template_buffer" keyword to allow content inspections + * on the decoded template application layer buffers. + */ + +#include "suricata-common.h" +#include "detect.h" +#include "app-layer-template.h" + +static int DetectTemplateBufferSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTemplateBufferRegisterTests(void); + +void DetectTemplateBufferRegister(void) +{ + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].name = "template_buffer"; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].desc = + "Template content modififier to match on the template buffers"; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].alproto = ALPROTO_TEMPLATE; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].Setup = DetectTemplateBufferSetup; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].RegisterTests = + DetectTemplateBufferRegisterTests; + + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_PAYLOAD; + + SCLogNotice("Template application layer detect registered."); +} + +static int DetectTemplateBufferSetup(DetectEngineCtx *de_ctx, Signature *s, + char *str) +{ + s->list = DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH; + s->alproto = ALPROTO_TEMPLATE; + return 0; +} + +#ifdef UNITTESTS + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer-parser.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "flow-util.h" +#include "stream-tcp.h" + +static int DetectTemplateBufferTest(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p; + TcpSession tcp; + ThreadVars tv; + Signature *s; + + int result = 0; + + uint8_t request[] = "Hello World!"; + + /* Setup flow. */ + memset(&f, 0, sizeof(Flow)); + memset(&tcp, 0, sizeof(TcpSession)); + memset(&tv, 0, sizeof(ThreadVars)); + p = UTHBuildPacket(request, sizeof(request), IPPROTO_TCP); + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_TEMPLATE; + f.protoctx = (void *)&tcp; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + /* This rule should match. */ + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "msg:\"TEMPLATE Test Rule\"; " + "template_buffer; content:\"World!\"; " + "sid:1; rev:1;)"); + if (s == NULL) { + goto end; + } + + /* This rule should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "msg:\"TEMPLATE Test Rule\"; " + "template_buffer; content:\"W0rld!\"; " + "sid:2; rev:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + AppLayerParserParse(alp_tctx, &f, ALPROTO_TEMPLATE, STREAM_TOSERVER, + request, sizeof(request)); + SCMutexUnlock(&f.m); + + /* Check that we have app-layer state. */ + if (f.alstate == NULL) { + goto end; + } + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + if (!PacketAlertCheck(p, 1)) { + goto end; + } + if (PacketAlertCheck(p, 2)) { + goto end; + } + + result = 1; +end: + /* Cleanup. */ + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + + return result; +} + +#endif + +static void DetectTemplateBufferRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectTemplateBufferTest", DetectTemplateBufferTest, 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-template-buffer.h b/src/detect-template-buffer.h new file mode 100644 index 000000000000..8a2ab8bad176 --- /dev/null +++ b/src/detect-template-buffer.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __DETECT_TEMPLATE_BUFFER_H__ +#define __DETECT_TEMPLATE_BUFFER_H__ + +#include "app-layer-template.h" + +void DetectTemplateBufferRegister(void); + +#endif /* __DETECT_TEMPLATE_BUFFER_H__ */ diff --git a/src/detect.c b/src/detect.c index a1516200d010..e0b5bfd3f0cb 100644 --- a/src/detect.c +++ b/src/detect.c @@ -156,6 +156,7 @@ #include "detect-dns-query.h" #include "detect-app-layer-protocol.h" #include "detect-template.h" +#include "detect-template-buffer.h" #include "util-rule-vars.h" @@ -163,6 +164,7 @@ #include "app-layer-protos.h" #include "app-layer-htp.h" #include "app-layer-smtp.h" +#include "app-layer-template.h" #include "detect-tls.h" #include "detect-tls-version.h" #include "detect-ssh-proto-version.h" @@ -2431,6 +2433,10 @@ PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, int has_state SCLogDebug("packet/flow has smtp state"); (*mask) |= SIG_MASK_REQUIRE_SMTP_STATE; break; + case ALPROTO_TEMPLATE: + SCLogDebug("packet/flow has template state"); + (*mask) |= SIG_MASK_REQUIRE_TEMPLATE_STATE; + break; default: SCLogDebug("packet/flow has other state"); break; @@ -2668,6 +2674,10 @@ static int SignatureCreateMask(Signature *s) s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; SCLogDebug("sig requires smtp state"); } + if (s->alproto == ALPROTO_TEMPLATE) { + s->mask |= SIG_MASK_REQUIRE_TEMPLATE_STATE; + SCLogDebug("sig requires template state"); + } if ((s->mask & SIG_MASK_REQUIRE_DCE_STATE) || (s->mask & SIG_MASK_REQUIRE_HTTP_STATE) || @@ -2675,6 +2685,7 @@ static int SignatureCreateMask(Signature *s) (s->mask & SIG_MASK_REQUIRE_DNS_STATE) || (s->mask & SIG_MASK_REQUIRE_FTP_STATE) || (s->mask & SIG_MASK_REQUIRE_SMTP_STATE) || + (s->mask & SIG_MASK_REQUIRE_TEMPLATE_STATE) || (s->mask & SIG_MASK_REQUIRE_TLS_STATE)) { s->mask |= SIG_MASK_REQUIRE_FLOW; @@ -5238,6 +5249,7 @@ void SigTableSetup(void) DetectModbusRegister(); DetectAppLayerProtocolRegister(); DetectTemplateRegister(); + DetectTemplateBufferRegister(); } void SigTableRegisterTests(void) diff --git a/src/detect.h b/src/detect.h index 236f69aa243b..30adc9c4f81c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -126,6 +126,8 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_MODBUS_MATCH, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + /* list for post match actions: flowbit set, flowint increment, etc */ DETECT_SM_LIST_POSTMATCH, @@ -305,6 +307,7 @@ typedef struct DetectPort_ { #define SIG_MASK_REQUIRE_DNS_STATE (1<<10) #define SIG_MASK_REQUIRE_FTP_STATE (1<<11) #define SIG_MASK_REQUIRE_SMTP_STATE (1<<12) +#define SIG_MASK_REQUIRE_TEMPLATE_STATE (1<<13) /* for now a uint8_t is enough */ #define SignatureMask uint16_t @@ -1229,6 +1232,7 @@ enum { DETECT_XBITS, DETECT_TEMPLATE, + DETECT_AL_TEMPLATE_BUFFER, /* make sure this stays last */ DETECT_TBLSIZE, From 4a738023d5ac945f0109ceb13fcc43e3f3095453 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 1 Sep 2015 15:20:13 -0600 Subject: [PATCH 0715/2553] app-layer: scripts to setup app-layer templates setup-app-layer.sh sets up an application layer detector and parser template. setup-app-layer-logger.sh sets up a JSON application layer transaction logger for an application parser that has already been provisioned. setup-app-layer-detect.sh sets up a keyword for performing content inspections on buffers created by the application layer. --- scripts/setup-app-layer-detect.sh | 233 ++++++++++++++++++++++++++++++ scripts/setup-app-layer-logger.sh | 154 ++++++++++++++++++++ scripts/setup-app-layer.sh | 166 +++++++++++++++++++++ 3 files changed, 553 insertions(+) create mode 100755 scripts/setup-app-layer-detect.sh create mode 100755 scripts/setup-app-layer-logger.sh create mode 100755 scripts/setup-app-layer.sh diff --git a/scripts/setup-app-layer-detect.sh b/scripts/setup-app-layer-detect.sh new file mode 100755 index 000000000000..ef3b741e7f4b --- /dev/null +++ b/scripts/setup-app-layer-detect.sh @@ -0,0 +1,233 @@ +#! /bin/sh +# +# Script to provision a new application layer detector and parser. + +set -e + +function usage() { + cat < + +This script will provision content inspection for app-layer decoded +buffers. + +Examples: + + $0 DNP3 + $0 Gopher + +EOF +} + +fail_if_exists() { + path="$1" + if test -e "${path}"; then + echo "error: ${path} already exists." + exit 1 + fi +} + +function copy_template_file() { + src="$1" + dst="$2" + + echo "Creating ${dst}." + + sed -e "s/TEMPLATE/${protoname_upper}/g" \ + -e "s/template/${protoname_lower}/g" \ + -e "s/Template/${protoname}/g" > ${dst} < ${src} +} + +function copy_templates() { + detect_h_dst="src/detect-${protoname_lower}-buffer.h" + detect_c_dst="src/detect-${protoname_lower}-buffer.c" + detect_engine_h_dst="src/detect-engine-${protoname_lower}.h" + detect_engine_c_dst="src/detect-engine-${protoname_lower}.c" + + fail_if_exists ${detect_h_dst} + fail_if_exists ${detect_c_dst} + fail_if_exists ${detect_engine_h_dst} + fail_if_exists ${detect_engine_c_dst} + + copy_template_file "src/detect-template-buffer.h" ${detect_h_dst} + copy_template_file "src/detect-template-buffer.c" ${detect_c_dst} + copy_template_file "src/detect-engine-template.h" ${detect_engine_h_dst} + copy_template_file "src/detect-engine-template.c" ${detect_engine_c_dst} +} + +function patch_makefile_am() { + filename="src/Makefile.am" + echo "Patching ${filename}." + ed -s ${filename} > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < + +This script will provision a new JSON application layer transaction +logger for the protocol name specified on the command line. This is +done by copying and patching src/output-json-template.h and +src/output-json-template.c then link the new files into the build +system. + +It is required that the application layer parser has already been +provisioned by the setup-app-layer.sh script. + +Examples: + + $0 DNP3 + $0 Gopher + +EOF +} + +fail_if_exists() { + path="$1" + if test -e "${path}"; then + echo "error: ${path} already exists." + exit 1 + fi +} + +function copy_template_file() { + src="$1" + dst="$2" + + echo "Creating ${dst}." + + sed -e "s/TEMPLATE/${protoname_upper}/g" \ + -e "s/template/${protoname_lower}/g" \ + -e "s/Template/${protoname}/g" > ${dst} < ${src} +} + +function copy_templates() { + src_h="src/output-json-template.h" + dst_h="src/output-json-${protoname_lower}.h" + src_c="src/output-json-template.c" + dst_c="src/output-json-${protoname_lower}.c" + + fail_if_exists ${dst_h} + fail_if_exists ${dst_c} + + copy_template_file ${src_h} ${dst_h} + copy_template_file ${src_c} ${dst_c} +} + +function patch_makefile_am() { + filename="src/Makefile.am" + echo "Patching ${filename}." + ed -s ${filename} > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < + +This script will provision a new app-layer parser for the protocol +name specified on the command line. This is done by copying and +patching src/app-layer-template.[ch] then linking the new files into +the build system. + +Examples: + + $0 DNP3 + $0 Gopher + +EOF +} + +fail_if_exists() { + path="$1" + if test -e "${path}"; then + echo "error: ${path} already exists." + exit 1 + fi +} + +function copy_template_file() { + src="$1" + dst="$2" + + echo "Creating ${dst}." + + sed -e "s/TEMPLATE/${protoname_upper}/g" \ + -e "s/template/${protoname_lower}/g" \ + -e "s/Template/${protoname}/g" > ${dst} < ${src} +} + +function copy_app_layer_templates { + src_h="src/app-layer-template.h" + dst_h="src/app-layer-${protoname_lower}.h" + src_c="src/app-layer-template.c" + dst_c="src/app-layer-${protoname_lower}.c" + + fail_if_exists ${dst_h} + fail_if_exists ${dst_c} + + copy_template_file ${src_h} ${dst_h} + copy_template_file ${src_c} ${dst_c} +} + +function patch_makefile_am { + filename="src/Makefile.am" + echo "Patching ${filename}." + ed -s ${filename} > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < Date: Mon, 14 Sep 2015 10:55:04 +0200 Subject: [PATCH 0716/2553] configure: use pkg_config for libhtp It was not possible to simply specify PKG_CONFIG_PATH to build with an non bundled libhtp. With this patch we don't need anymore the htp lib and include configure options. --- configure.ac | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure.ac b/configure.ac index ea819f4a8032..ab2df12bc642 100644 --- a/configure.ac +++ b/configure.ac @@ -1113,6 +1113,12 @@ AC_ARG_ENABLE(non-bundled-htp, AS_HELP_STRING([--enable-non-bundled-htp], [Enable the use of an already installed version of htp]),,[enable_non_bundled_htp=no]) AS_IF([test "x$enable_non_bundled_htp" = "xyes"], [ + PKG_CHECK_MODULES([libhtp], htp,, [with_pkgconfig_htp=no]) + if test "$with_pkgconfig_htp" != "no"; then + CPPFLAGS="${CPPFLAGS} ${libhtp_CFLAGS}" + LIBS="${LIBS} ${libhtp_LIBS}" + fi + AC_ARG_WITH(libhtp_includes, [ --with-libhtp-includes=DIR libhtp include directory], [with_libhtp_includes="$withval"],[with_libhtp_includes=no]) From a2867153670f776a338fc698bca08b33ae36d3b6 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 13 Sep 2015 23:34:16 +0200 Subject: [PATCH 0717/2553] host-storage: document host storage API --- src/host-storage.c | 59 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/host-storage.c b/src/host-storage.c index 6748089cd7ae..fe157692725c 100644 --- a/src/host-storage.c +++ b/src/host-storage.c @@ -32,16 +32,66 @@ unsigned int HostStorageSize(void) return StorageGetSize(STORAGE_HOST); } -void *HostGetStorageById(Host *h, int id) -{ - return StorageGetById((Storage *)((void *)h + sizeof(Host)), STORAGE_HOST, id); +/** \defgroup hoststorage Host storage API + * + * The Host storage API is a per-host storage. It is a mean to extend + * the Host structure with arbitrary data. + * + * You have first to register the storage via HostStorageRegister() during + * the init of your module. Then you can attach data via HostSetStorageById() + * and access them via HostGetStorageById(). + * @{ + */ + +/** + * \brief Register a Host storage + * + * \param name the name of the storage + * \param size integer coding the size of the stored value (sizeof(void *) is best choice here) + * \param Alloc allocation function for the storage (can be null) + * \param Free free function for the new storage + * + * \retval The ID of the newly register storage that will be used to access data + * + * It has to be called once during the init of the sub system + */ + +int HostStorageRegister(const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *)) { + return StorageRegister(STORAGE_HOST, name, size, Alloc, Free); } +/** + * \brief Store a pointer in a given Host storage + * + * \param h a pointer to the Host + * \param id the id of the storage (return of HostStorageRegister() call) + * \param ptr pointer to the data to store + */ + int HostSetStorageById(Host *h, int id, void *ptr) { return StorageSetById((Storage *)((void *)h + sizeof(Host)), STORAGE_HOST, id, ptr); } +/** + * \brief Get a value from a given Host storage + * + * \param h a pointer to the Host + * \param id the id of the storage (return of HostStorageRegister() call) + * + */ + +void *HostGetStorageById(Host *h, int id) +{ + return StorageGetById((Storage *)((void *)h + sizeof(Host)), STORAGE_HOST, id); +} + +/** + * @} + */ + +/* Start of "private" function */ + void *HostAllocStorageById(Host *h, int id) { return StorageAllocByIdPrealloc((Storage *)((void *)h + sizeof(Host)), STORAGE_HOST, id); @@ -58,9 +108,6 @@ void HostFreeStorage(Host *h) StorageFreeAll((Storage *)((void *)h + sizeof(Host)), STORAGE_HOST); } -int HostStorageRegister(const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *)) { - return StorageRegister(STORAGE_HOST, name, size, Alloc, Free); -} #ifdef UNITTESTS From 84fd28eaed25c61ad2bea87800bfae756cc0c03f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 16 Sep 2015 11:23:34 -0600 Subject: [PATCH 0718/2553] app-layer setup scripts: fix header substitution. Fixes make distcheck. --- scripts/setup-app-layer-logger.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setup-app-layer-logger.sh b/scripts/setup-app-layer-logger.sh index be32c3931479..8b53ae545384 100755 --- a/scripts/setup-app-layer-logger.sh +++ b/scripts/setup-app-layer-logger.sh @@ -62,7 +62,7 @@ function patch_makefile_am() { ed -s ${filename} > /dev/null < Date: Wed, 26 Aug 2015 14:25:16 +0200 Subject: [PATCH 0719/2553] stream: optimize proto detect segment handling In case of protocol detection not yet being complete, the segment list was walked unconditionally to unset the app layer processed flag. Optimize this to bail on the first segment that doesn't have the flag set. --- src/stream-tcp-reassemble.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index caf955afa1a5..912a446d3cb7 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -3035,6 +3035,8 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } else { TcpSegment *tmp_seg = stream->seg_list; while (tmp_seg != NULL) { + if (!(tmp_seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) + break; tmp_seg->flags &= ~SEGMENTTCP_FLAG_APPLAYER_PROCESSED; tmp_seg = tmp_seg->next; } From 34ed15e1823dd85f89bef7944aac130bd0b7e44f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 26 Aug 2015 16:15:07 +0200 Subject: [PATCH 0720/2553] stream: fix protocol detection issue for GAPs If the protocol required TOSERVER data first, but the SSN started with a GAP, then the TOCLIENT side would get stuck in an expensive path: 1. it would run detection on TOCLIENT 2. it would try to force reassembly for TOSERVER 3. it would reset the detected protocol as TOSERVER failed 4. it would not evict any segment This had 2 consequences: 1. on long running sessions this could lead to using lots of memory on segments, denying other sessions resources 2. wasted cycles on protocol detection and segment list management This patch introduces a fix. It checks in the (2) stage above, whether the opposing stream (that we depend on) it is a NOREASSEMBLY state. If so, it gives up on this side of the session as well. --- src/app-layer.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app-layer.c b/src/app-layer.c index c47c2dd6624a..aeb69a3d94ba 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -187,7 +187,14 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, p->flowflags |= FLOW_PKT_TOCLIENT; } } - int ret = StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, + + int ret = 0; + /* if the opposing side is not going to work, then + * we just have to give up. */ + if (opposing_stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) + ret = -1; + else + ret = StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, opposing_stream, p); if (stream == &ssn->client) { if (StreamTcpInlineMode()) { From 596465b76d9bd89102cc4d18e38f991185b6666a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 31 Aug 2015 18:50:06 +0200 Subject: [PATCH 0721/2553] stream: use reassembly fast path after proto detect Use the reassembly fast paths only after protocol detection has completed. In some corner cases the sending of smaller segments lead to protocol detection failing. --- src/stream-tcp-reassemble.c | 87 ++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 912a446d3cb7..632b966fc0f9 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2620,51 +2620,58 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd, Packet *p) { - /* fast path 1: segment is exactly what we need */ - if (likely(rd->data_len == 0 && - SEQ_EQ(seg->seq, rd->ra_base_seq+1) && - SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len)))) - { - /* process single segment directly */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - seg->payload, seg->payload_len, - StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - rd->data_sent += seg->payload_len; - rd->ra_base_seq += seg->payload_len; + /* fast paths: send data directly into the app layer, w/o first doing + * a copy step. However, don't use the fast path until protocol detection + * has been completed + * TODO if initial data is big enough for proto detect, we could do the + * fast path anyway. */ + if (stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) { + /* fast path 1: segment is exactly what we need */ + if (likely(rd->data_len == 0 && + SEQ_EQ(seg->seq, rd->ra_base_seq+1) && + SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len)))) + { + /* process single segment directly */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + seg->payload, seg->payload_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += seg->payload_len; + rd->ra_base_seq += seg->payload_len; #ifdef DEBUG - ra_ctx->fp1++; + ra_ctx->fp1++; #endif - /* if after the first data chunk we have no alproto yet, - * there is no point in continueing here. */ - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - SCLogDebug("no alproto after first data chunk"); - return 0; - } - return 1; - /* fast path 2: segment acked completely, meets minimal size req for 0copy processing */ - } else if (rd->data_len == 0 && - SEQ_EQ(seg->seq, rd->ra_base_seq+1) && - SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) && - seg->payload_len >= stream_config.zero_copy_size) - { - /* process single segment directly */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - seg->payload, seg->payload_len, - StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - rd->data_sent += seg->payload_len; - rd->ra_base_seq += seg->payload_len; + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + return 1; + /* fast path 2: segment acked completely, meets minimal size req for 0copy processing */ + } else if (rd->data_len == 0 && + SEQ_EQ(seg->seq, rd->ra_base_seq+1) && + SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) && + seg->payload_len >= stream_config.zero_copy_size) + { + /* process single segment directly */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + seg->payload, seg->payload_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += seg->payload_len; + rd->ra_base_seq += seg->payload_len; #ifdef DEBUG - ra_ctx->fp2++; + ra_ctx->fp2++; #endif - /* if after the first data chunk we have no alproto yet, - * there is no point in continueing here. */ - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - SCLogDebug("no alproto after first data chunk"); - return 0; + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + return 1; } - return 1; } #ifdef DEBUG ra_ctx->sp++; From 8ac49d9129603efd5698c9851f769c6d8cc9aee9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 1 Sep 2015 22:46:14 +0200 Subject: [PATCH 0722/2553] stream: allow next_seq catch up after pkt loss If next_seq falls behind last_ack, force update it. --- src/stream-tcp.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 6cde8651384b..94b9e07fec42 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -764,8 +764,13 @@ uint32_t StreamTcpGetStreamSize(TcpStream *stream) #define StreamTcpUpdateLastAck(ssn, stream, ack) { \ if (SEQ_GT((ack), (stream)->last_ack)) \ { \ + SCLogDebug("ssn %p: last_ack set to %"PRIu32", moved %u forward", (ssn), (ack), (ack) - (stream)->last_ack); \ + if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && SEQ_GT((ack),(stream)->next_seq))) { \ + SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), (stream)->last_ack, (stream)->next_seq); \ + } else { \ + SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, (int)(stream)->next_seq - (ack)); \ + }\ (stream)->last_ack = (ack); \ - SCLogDebug("ssn %p: last_ack set to %"PRIu32, (ssn), (stream)->last_ack); \ StreamTcpSackPruneList((stream)); \ } else { \ SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \ @@ -2040,6 +2045,17 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32 " (started before next_seq, ended after)", ssn, ssn->client.next_seq); + /* if next_seq has fallen behind last_ack, we got some catching up to do */ + } else if (SEQ_LT(ssn->client.next_seq, ssn->client.last_ack)) { + ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; + SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32 + " (next_seq had fallen behind last_ack)", + ssn, ssn->client.next_seq); + } else { + SCLogDebug("ssn %p: no update to ssn->client.next_seq %"PRIu32 + " SEQ %u SEQ+ %u last_ack %u", + ssn, ssn->client.next_seq, + TCP_GET_SEQ(p), TCP_GET_SEQ(p)+p->payload_len, ssn->client.last_ack); } /* in window check */ @@ -2185,6 +2201,17 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 " (started before next_seq, ended after)", ssn, ssn->server.next_seq); + /* if next_seq has fallen behind last_ack, we got some catching up to do */ + } else if (SEQ_LT(ssn->server.next_seq, ssn->server.last_ack)) { + ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len; + SCLogDebug("ssn %p: ssn->server.next_seq %"PRIu32 + " (next_seq had fallen behind last_ack)", + ssn, ssn->server.next_seq); + } else { + SCLogDebug("ssn %p: no update to ssn->server.next_seq %"PRIu32 + " SEQ %u SEQ+ %u last_ack %u", + ssn, ssn->server.next_seq, + TCP_GET_SEQ(p), TCP_GET_SEQ(p)+p->payload_len, ssn->server.last_ack); } if (zerowindowprobe) { From e67188e437b39f21cb2f7452cd300c522ce97252 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 27 Aug 2015 18:57:48 +0200 Subject: [PATCH 0723/2553] detect: fix issue with smsg and seq wraps Due to a broken sequence number check, detect could fail to process smsgs in case of a sequence wrap. This could lead to excessive use of smsg's but also of segments, since these aren't cleared until the smsg containing them is. --- src/detect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index e0b5bfd3f0cb..36f19cac07cd 100644 --- a/src/detect.c +++ b/src/detect.c @@ -692,7 +692,7 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) /* if the smsg is bigger than the current packet, we will * process the smsg in a later run */ - if ((head->seq + head->data_len) > (TCP_GET_SEQ(p) + p->payload_len)) { + if (SEQ_GT((head->seq + head->data_len), (TCP_GET_SEQ(p) + p->payload_len))) { SCLogDebug("smsg ends beyond current packet, skipping for now %"PRIu32">%"PRIu32, (head->seq + head->data_len), (TCP_GET_SEQ(p) + p->payload_len)); goto end; @@ -711,7 +711,7 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) /* if the smsg is bigger than the current packet, we will * process the smsg in a later run */ - if ((head->seq + head->data_len) > (TCP_GET_SEQ(p) + p->payload_len)) { + if (SEQ_GT((head->seq + head->data_len), (TCP_GET_SEQ(p) + p->payload_len))) { SCLogDebug("smsg ends beyond current packet, skipping for now %"PRIu32">%"PRIu32, (head->seq + head->data_len), (TCP_GET_SEQ(p) + p->payload_len)); goto end; From fa8dc77dcc73e3e4b9c0374b6eec8b3e5f379fd8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 26 Aug 2015 16:52:09 +0200 Subject: [PATCH 0724/2553] debug validation: add segment list sanity check --- src/stream-tcp-reassemble.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 632b966fc0f9..dbf9c71eb74e 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2967,9 +2967,14 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, SCReturnInt(0); } } - +#ifdef DEBUG_VALIDATION + uint64_t bytes = 0; +#endif for (; seg != NULL; ) { +#ifdef DEBUG_VALIDATION + bytes += seg->payload_len; +#endif /* if in inline mode, we process all segments regardless of whether * they are ack'd or not. In non-inline, we process only those that * are at least partly ack'd. */ @@ -3014,6 +3019,9 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } seg = next_seg; } +#ifdef DEBUG_VALIDATION /* we should never have this much data queued */ + BUG_ON(bytes > 1000000ULL && bytes > (stream->window * 1.5)); +#endif /* put the partly filled smsg in the queue to the l7 handler */ if (rd.data_len > 0) { From 3ca44219dc65e17461db5bae96cef1818a7eec43 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 27 Aug 2015 22:58:32 +0200 Subject: [PATCH 0725/2553] proto detect: more bypass conditions More exceptional cases for protocol detection. In very unbalanced flows, where just a few bytes are sent toserver and many toclient, proto detect might not complete in time on the toserver direction. This can lead to queuing up many segments in the toclient direction. Another case is that in come cases the stream is flagged as proto detect done, but the flows proto detect flags are not set. This is now handled by the ProtoDetectDone() check. --- src/app-layer.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index aeb69a3d94ba..96fa252c9c7e 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -74,6 +74,12 @@ static void DisableAppLayer(Flow *f) StreamTcpDisableAppLayer(f); } +static inline int ProtoDetectDone(const Flow *f, const TcpSession *ssn, uint8_t direction) { + const TcpStream *stream = (direction & STREAM_TOSERVER) ? &ssn->client : &ssn->server; + return ((stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) || + (FLOW_IS_PM_DONE(f, direction) && FLOW_IS_PP_DONE(f, direction))); +} + int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet *p, Flow *f, TcpSession *ssn, TcpStream *stream, @@ -336,7 +342,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } else { f->data_al_so_far[dir] = data_len; } - } else { + } else { /* See if we're going to have to give up: * * If we're getting a lot of data in one direction and the @@ -356,9 +362,16 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, uint32_t size_ts = ssn->client.last_ack - ssn->client.isn - 1; uint32_t size_tc = ssn->server.last_ack - ssn->server.isn - 1; SCLogDebug("size_ts %u, size_tc %u", size_ts, size_tc); - - if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && - FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) { +#ifdef DEBUG_VALIDATION + if (!(ssn->client.flags & STREAMTCP_STREAM_FLAG_GAP)) + BUG_ON(size_ts > 1000000UL); + if (!(ssn->server.flags & STREAMTCP_STREAM_FLAG_GAP)) + BUG_ON(size_tc > 1000000UL); +#endif /* DEBUG_VALIDATION */ + + if (ProtoDetectDone(f, ssn, STREAM_TOSERVER) && + ProtoDetectDone(f, ssn, STREAM_TOCLIENT)) + { DisableAppLayer(f); ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; @@ -398,8 +411,19 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + /* in case of really low TS data (e.g. 4 bytes) we can have + * the PP complete, PM not complete (depth not reached) and + * the TC side also not recognized (proto unknown) */ + } else if (size_tc > 100000 && + FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && + (!FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && !FLOW_IS_PP_DONE(f, STREAM_TOCLIENT))) + { + DisableAppLayer(f); + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); } - } + } } } else { SCLogDebug("stream data (len %" PRIu32 " alproto " From 574ef0ad2a47a2ee0b59bd23fea58c8f02499d1a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 27 Aug 2015 23:49:15 +0200 Subject: [PATCH 0726/2553] stream: RST last_ack update fix Only use ACK if ACK flag was set and ACK value is valid. --- src/stream-tcp.c | 70 +++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 94b9e07fec42..a4dcf41443ee 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -2311,8 +2311,9 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, ssn->server.next_seq); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -2342,8 +2343,9 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, ssn->server.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -2636,8 +2638,9 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -2649,8 +2652,9 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -3090,8 +3094,9 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -3103,8 +3108,9 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -3396,8 +3402,9 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -3409,8 +3416,9 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -3576,8 +3584,9 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -3589,8 +3598,9 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -3867,8 +3877,9 @@ static int StreamTcpPacketStateLastAck(ThreadVars *tv, Packet *p, ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -3880,8 +3891,9 @@ static int StreamTcpPacketStateLastAck(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -3992,8 +4004,9 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -4005,8 +4018,9 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); From cacf425bd38aeee48c6cb77189d9412dbbe3d4e2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 31 Aug 2015 19:00:35 +0200 Subject: [PATCH 0727/2553] stream: improve handling of GAPs at stream start Detect and handle gaps at the start of the stream, when there may be no segments in the list (yet). --- src/stream-tcp-reassemble.c | 81 ++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index dbf9c71eb74e..a947fab35140 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2895,6 +2895,49 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, GetSessionSize(ssn, p); #endif + /* Check if we have a gap at the start of the stream. 2 conditions: + * 1. no segments, but last_ack moved fwd + * 2. segments, but clearly some missing: if last_ack is + * bigger than the list start and the list start is bigger than + * next_seq, we know we are missing data that has been ack'd. That + * won't get retransmitted, so it's a data gap. + */ + if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) { + int ackadd = (ssn->state >= TCP_FIN_WAIT2) ? 2 : 1; + if ((stream->seg_list == NULL && /*1*/ + stream->ra_app_base_seq == stream->isn && + SEQ_GT(stream->last_ack, stream->isn + ackadd)) + || + (stream->seg_list != NULL && /*2*/ + SEQ_GT(stream->seg_list->seq, stream->ra_app_base_seq+1) && + SEQ_LT(stream->seg_list->seq, stream->last_ack))) + { + if (stream->seg_list == NULL) { + SCLogDebug("no segs, last_ack moved fwd so GAP " + "(base %u, isn %u, last_ack %u => diff %u) p %"PRIu64, + stream->ra_app_base_seq, stream->isn, stream->last_ack, + stream->last_ack - (stream->isn + ackadd), p->pcap_cnt); + } + + /* send gap signal */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + NULL, 0, + StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + + /* set a GAP flag and make sure not bothering this stream anymore */ + SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); + stream->flags |= STREAMTCP_STREAM_FLAG_GAP; + + StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); + StatsIncr(tv, ra_ctx->counter_tcp_reass_gap); +#ifdef DEBUG + dbg_app_layer_gap++; +#endif + SCReturnInt(0); + } + } + /* if no segments are in the list or all are already processed, * and state is beyond established, we send an empty msg */ TcpSegment *seg_tail = stream->seg_list_tail; @@ -2941,32 +2984,6 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, /* loop through the segments and fill one or more msgs */ TcpSegment *seg = stream->seg_list; SCLogDebug("pre-loop seg %p", seg); - - /* Check if we have a gap at the start of the list. If last_ack is - * bigger than the list start and the list start is bigger than - * next_seq, we know we are missing data that has been ack'd. That - * won't get retransmitted, so it's a data gap. - */ - if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) { - if (SEQ_GT(seg->seq, next_seq) && SEQ_LT(seg->seq, stream->last_ack)) { - /* send gap signal */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, - StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - - /* set a GAP flag and make sure not bothering this stream anymore */ - SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); - stream->flags |= STREAMTCP_STREAM_FLAG_GAP; - - StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - StatsIncr(tv, ra_ctx->counter_tcp_reass_gap); -#ifdef DEBUG - dbg_app_layer_gap++; -#endif - SCReturnInt(0); - } - } #ifdef DEBUG_VALIDATION uint64_t bytes = 0; #endif @@ -5434,6 +5451,9 @@ static int StreamTcpReassembleTest30 (void) th_flag = TH_ACK|TH_PUSH; th_flags = TH_ACK; + ssn.client.last_ack = 2; + ssn.client.isn = 1; + ssn.server.last_ack = 22; ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9; ssn.server.isn = 9; @@ -6117,7 +6137,7 @@ static int StreamTcpReassembleTest38 (void) ssn.server.last_ack = 60; ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9; ssn.client.isn = 9; - ssn.client.last_ack = 60; + ssn.client.last_ack = 9; f.alproto = ALPROTO_UNKNOWN; f.flags |= FLOW_IPV4; @@ -7235,7 +7255,7 @@ static int StreamTcpReassembleTest45 (void) ssn.server.last_ack = 60; STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9); ssn.client.isn = 9; - ssn.client.last_ack = 60; + ssn.client.last_ack = 9; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); if (f == NULL) @@ -7354,7 +7374,7 @@ static int StreamTcpReassembleTest46 (void) ssn.server.next_seq = ssn.server.isn; STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9); ssn.client.isn = 9; - ssn.client.last_ack = 60; + ssn.client.last_ack = 9; ssn.client.next_seq = ssn.client.isn; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); @@ -8422,6 +8442,9 @@ static int StreamTcpReassembleInlineTest10(void) StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.server, 1); + ssn.server.last_ack = 2; + StreamTcpUTSetupStream(&ssn.client, 1); + ssn.client.last_ack = 2; f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80); if (f == NULL) From e755913b4b6ca3d8f184932841c2f9e8f18fa479 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 13:11:35 +0200 Subject: [PATCH 0728/2553] mpm: minor fixes and cleanups --- src/detect-engine-filedata-smtp.c | 5 ++--- src/detect-engine-mpm.c | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index dc50d8c7d708..829832f9dc70 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -267,7 +267,7 @@ int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, uint32_t cnt = 0; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = 0; + uint8_t *buffer = NULL; if (ffc != NULL) { File *file = ffc->head; @@ -278,11 +278,10 @@ int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, flags, &buffer_len, &stream_start_offset); - if (buffer_len == 0) goto end; - cnt = SMTPFiledataPatternSearch(det_ctx, buffer, buffer_len, flags); + cnt += SMTPFiledataPatternSearch(det_ctx, buffer, buffer_len, flags); } } end: diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index c34ef252468e..e9cf93fbe809 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -2383,7 +2383,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) PatternMatchPreparePopulateMpm(de_ctx, sh); - //if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (sh->mpm_proto_tcp_ctx_ts != NULL) { if (sh->mpm_proto_tcp_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_ts); @@ -2688,7 +2687,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) } } } - //} /* if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) */ } else { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx); sh->mpm_proto_other_ctx = NULL; From 804f8619671a0f3847b911cfd6e183c26ff9dd86 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 13:11:56 +0200 Subject: [PATCH 0729/2553] debug validation: introduce DEBUG_VALIDATE_BUG_ON DEBUG_VALIDATE_BUG_ON(exp) will call BUG_ON(exp) if debug validation is compiled in. Otherwise it's a no-op. --- src/util-validate.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util-validate.h b/src/util-validate.h index b5c3da26b2c3..b7647a7d4da8 100644 --- a/src/util-validate.h +++ b/src/util-validate.h @@ -96,11 +96,14 @@ } \ } while(0) +#define DEBUG_VALIDATE_BUG_ON(exp) BUG_ON((exp)) + #else /* DEBUG_VALIDATE */ #define DEBUG_ASSERT_FLOW_LOCKED(f) #define DEBUG_VALIDATE_FLOW(f) #define DEBUG_VALIDATE_PACKET(p) +#define DEBUG_VALIDATE_BUG_ON(exp) #endif /* DEBUG_VALIDATE */ From a00d83f1f53ab9ec39f3144181bd33e4103de863 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 13:13:55 +0200 Subject: [PATCH 0730/2553] mpm: change direction checking in mpm wrappers Instead of having reachable assertions, use DEBUG_VALIDATE_BUG_ON --- src/detect-engine-mpm.c | 199 +++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 104 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index e9cf93fbe809..bcd277437b29 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -58,6 +58,7 @@ #ifdef __SC_CUDA_SUPPORT__ #include "util-mpm-ac.h" #endif +#include "util-validate.h" /** \todo make it possible to use multiple pattern matcher algorithms next to each other. */ @@ -269,16 +270,15 @@ uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_uri_ctx_ts == NULL) - SCReturnUInt(0U); - ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_uri_ctx_ts, - &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); - } else { - BUG_ON(1); - } + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + + if (det_ctx->sgh->mpm_uri_ctx_ts == NULL) + SCReturnUInt(0U); + + ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_uri_ctx_ts, + &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); //PrintRawDataFp(stdout, uri, uri_len); @@ -300,16 +300,15 @@ uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hcbd_ctx_ts == NULL) - SCReturnUInt(0); - ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hcbd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, body, body_len); - } else { - BUG_ON(1); - } + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + + if (det_ctx->sgh->mpm_hcbd_ctx_ts == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hcbd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, body, body_len); SCReturnUInt(ret); } @@ -329,16 +328,15 @@ uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret; - if (flags & STREAM_TOSERVER) { - BUG_ON(1); - } else { - if (det_ctx->sgh->mpm_hsbd_ctx_tc == NULL) - SCReturnUInt(0); - ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hsbd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, body, body_len); - } + DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); + + if (det_ctx->sgh->mpm_hsbd_ctx_tc == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hsbd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, body, body_len); SCReturnUInt(ret); } @@ -426,16 +424,15 @@ uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hmd_ctx_ts == NULL) - SCReturnUInt(0); - ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hmd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, raw_method, raw_method_len); - } else { - BUG_ON(1); - } + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + + if (det_ctx->sgh->mpm_hmd_ctx_ts == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hmd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, raw_method, raw_method_len); SCReturnUInt(ret); } @@ -489,16 +486,15 @@ uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hrud_ctx_ts == NULL) - SCReturnUInt(0); - ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrud_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, uri, uri_len); - } else { - BUG_ON(1); - } + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + + if (det_ctx->sgh->mpm_hrud_ctx_ts == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hrud_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, uri, uri_len); SCReturnUInt(ret); } @@ -518,16 +514,15 @@ uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret; - if (flags & STREAM_TOSERVER) { - BUG_ON(1); - } else { - if (det_ctx->sgh->mpm_hsmd_ctx_tc == NULL) - SCReturnUInt(0); - ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hsmd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, stat_msg, stat_msg_len); - } + DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); + + if (det_ctx->sgh->mpm_hsmd_ctx_tc == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hsmd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, stat_msg, stat_msg_len); SCReturnUInt(ret); } @@ -547,16 +542,15 @@ uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret; - if (flags & STREAM_TOSERVER) { - BUG_ON(1); - } else { - if (det_ctx->sgh->mpm_hscd_ctx_tc == NULL) - SCReturnUInt(0); - ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hscd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, stat_code, stat_code_len); - } + DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); + + if (det_ctx->sgh->mpm_hscd_ctx_tc == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hscd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, stat_code, stat_code_len); SCReturnUInt(ret); } @@ -576,16 +570,15 @@ uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_huad_ctx_ts == NULL) - SCReturnUInt(0); - ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, ua, ua_len); - } else { - BUG_ON(1); - } + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + + if (det_ctx->sgh->mpm_huad_ctx_ts == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, ua, ua_len); SCReturnUInt(ret); } @@ -606,16 +599,15 @@ uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hhhd_ctx_ts == NULL) - SCReturnUInt(0); - ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hhhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, hh, hh_len); - } else { - BUG_ON(1); - } + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + + if (det_ctx->sgh->mpm_hhhd_ctx_ts == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hhhd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, hh, hh_len); SCReturnUInt(ret); } @@ -636,16 +628,15 @@ uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL) - SCReturnUInt(0); - ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrhhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, hrh, hrh_len); - } else { - BUG_ON(1); - } + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + + if (det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hrhhd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, hrh, hrh_len); SCReturnUInt(ret); } @@ -668,14 +659,14 @@ uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret = 0; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - ret = mpm_table[det_ctx->sgh->mpm_dnsquery_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_dnsquery_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); - } + if (det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_dnsquery_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_dnsquery_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); SCReturnUInt(ret); } @@ -755,14 +746,14 @@ uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret = 0; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_smtp_filedata_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - ret = mpm_table[det_ctx->sgh->mpm_smtp_filedata_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_smtp_filedata_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); - } + if (det_ctx->sgh->mpm_smtp_filedata_ctx_ts == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_smtp_filedata_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_smtp_filedata_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); SCReturnUInt(ret); } From 7c336f4190c7b78720312a0dae5c3430df3b8955 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 13:24:47 +0200 Subject: [PATCH 0731/2553] mpm: indent fix, no functional change --- src/detect-engine-mpm.c | 611 ++++++++++++++++++++-------------------- 1 file changed, 305 insertions(+), 306 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index bcd277437b29..bc092cdfecdc 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -171,7 +171,7 @@ uint16_t PatternMatchDefaultMatcher(void) done: #ifdef __tile__ if (mpm_algo_val == MPM_AC) - mpm_algo_val = MPM_AC_TILE; + mpm_algo_val = MPM_AC_TILE; #endif return mpm_algo_val; @@ -2371,313 +2371,312 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) has_co_hrhhd || has_co_dnsquery) { - PatternMatchPreparePopulateMpm(de_ctx, sh); - if (sh->mpm_proto_tcp_ctx_ts != NULL) { - if (sh->mpm_proto_tcp_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_ts); - sh->mpm_proto_tcp_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type]. - Prepare(sh->mpm_proto_tcp_ctx_ts); - } - } - } - } - if (sh->mpm_proto_tcp_ctx_tc != NULL) { - if (sh->mpm_proto_tcp_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_tc); - sh->mpm_proto_tcp_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type]. - Prepare(sh->mpm_proto_tcp_ctx_tc); - } - } - } - } - - if (sh->mpm_proto_udp_ctx_ts != NULL) { - if (sh->mpm_proto_udp_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_ts); - sh->mpm_proto_udp_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type]. - Prepare(sh->mpm_proto_udp_ctx_ts); - } - } - } - } - if (sh->mpm_proto_udp_ctx_tc != NULL) { - if (sh->mpm_proto_udp_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_tc); - sh->mpm_proto_udp_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type]. - Prepare(sh->mpm_proto_udp_ctx_tc); - } - } - } - } - - if (sh->mpm_proto_other_ctx != NULL) { - if (sh->mpm_proto_other_ctx->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx); - sh->mpm_proto_other_ctx = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_other_ctx->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_other_ctx->mpm_type]. - Prepare(sh->mpm_proto_other_ctx); - } - } - } - } - - if (sh->mpm_stream_ctx_ts != NULL) { - if (sh->mpm_stream_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_ts); - sh->mpm_stream_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_stream_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_stream_ctx_ts->mpm_type].Prepare(sh->mpm_stream_ctx_ts); - } - } - } - if (sh->mpm_stream_ctx_tc != NULL) { - if (sh->mpm_stream_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_tc); - sh->mpm_stream_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_stream_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_stream_ctx_tc->mpm_type].Prepare(sh->mpm_stream_ctx_tc); - } - } - } - - if (sh->mpm_uri_ctx_ts != NULL) { - if (sh->mpm_uri_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_ts); - sh->mpm_uri_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_uri_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_uri_ctx_ts->mpm_type].Prepare(sh->mpm_uri_ctx_ts); - } - } - } - - if (sh->mpm_hcbd_ctx_ts != NULL) { - if (sh->mpm_hcbd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_ts); - sh->mpm_hcbd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].Prepare(sh->mpm_hcbd_ctx_ts); - } - } - } - - if (sh->mpm_hsbd_ctx_tc != NULL) { - if (sh->mpm_hsbd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsbd_ctx_tc); - sh->mpm_hsbd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].Prepare(sh->mpm_hsbd_ctx_tc); - } - } - } - - if (sh->mpm_smtp_filedata_ctx_ts != NULL) { - if (sh->mpm_smtp_filedata_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_smtp_filedata_ctx_ts); - sh->mpm_smtp_filedata_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_smtp_filedata_ctx_ts->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_smtp_filedata_ctx_ts->mpm_type].Prepare(sh->mpm_smtp_filedata_ctx_ts); - } - } - } - } - - if (sh->mpm_hhd_ctx_ts != NULL) { - if (sh->mpm_hhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_ts); - sh->mpm_hhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].Prepare(sh->mpm_hhd_ctx_ts); - } - } - } - if (sh->mpm_hhd_ctx_tc != NULL) { - if (sh->mpm_hhd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_tc); - sh->mpm_hhd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].Prepare(sh->mpm_hhd_ctx_tc); - } - } - } - - if (sh->mpm_hrhd_ctx_ts != NULL) { - if (sh->mpm_hrhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_ts); - sh->mpm_hrhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].Prepare(sh->mpm_hrhd_ctx_ts); - } - } - } - if (sh->mpm_hrhd_ctx_tc != NULL) { - if (sh->mpm_hrhd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_tc); - sh->mpm_hrhd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].Prepare(sh->mpm_hrhd_ctx_tc); - } - } - } - - if (sh->mpm_hmd_ctx_ts != NULL) { - if (sh->mpm_hmd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hmd_ctx_ts); - sh->mpm_hmd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].Prepare(sh->mpm_hmd_ctx_ts); - } - } - } - - if (sh->mpm_hcd_ctx_ts != NULL) { - if (sh->mpm_hcd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_ts); - sh->mpm_hcd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].Prepare(sh->mpm_hcd_ctx_ts); - } - } - } - if (sh->mpm_hcd_ctx_tc != NULL) { - if (sh->mpm_hcd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_tc); - sh->mpm_hcd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].Prepare(sh->mpm_hcd_ctx_tc); - } - } - } - - if (sh->mpm_hrud_ctx_ts != NULL) { - if (sh->mpm_hrud_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrud_ctx_ts); - sh->mpm_hrud_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].Prepare(sh->mpm_hrud_ctx_ts); - } - } - } - - if (sh->mpm_hsmd_ctx_tc != NULL) { - if (sh->mpm_hsmd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsmd_ctx_tc); - sh->mpm_hsmd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].Prepare(sh->mpm_hsmd_ctx_tc); - } - } - } - - if (sh->mpm_hscd_ctx_tc != NULL) { - if (sh->mpm_hscd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hscd_ctx_tc); - sh->mpm_hscd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].Prepare(sh->mpm_hscd_ctx_tc); - } - } - } - - if (sh->mpm_huad_ctx_ts != NULL) { - if (sh->mpm_huad_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_huad_ctx_ts); - sh->mpm_huad_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare(sh->mpm_huad_ctx_ts); - } - } - } - - if (sh->mpm_hhhd_ctx_ts != NULL) { - if (sh->mpm_hhhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhhd_ctx_ts); - sh->mpm_hhhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hhhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hhhd_ctx_ts->mpm_type].Prepare(sh->mpm_hhhd_ctx_ts); - } - } - } - - if (sh->mpm_hrhhd_ctx_ts != NULL) { - if (sh->mpm_hrhhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_ts); - sh->mpm_hrhhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrhhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrhhd_ctx_ts->mpm_type].Prepare(sh->mpm_hrhhd_ctx_ts); - } - } - } - - if (sh->mpm_dnsquery_ctx_ts != NULL) { - if (sh->mpm_dnsquery_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_dnsquery_ctx_ts); - sh->mpm_dnsquery_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].Prepare(sh->mpm_dnsquery_ctx_ts); - } - } - } + if (sh->mpm_proto_tcp_ctx_ts != NULL) { + if (sh->mpm_proto_tcp_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_ts); + sh->mpm_proto_tcp_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type].Prepare != NULL) { + mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type]. + Prepare(sh->mpm_proto_tcp_ctx_ts); + } + } + } + } + if (sh->mpm_proto_tcp_ctx_tc != NULL) { + if (sh->mpm_proto_tcp_ctx_tc->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_tc); + sh->mpm_proto_tcp_ctx_tc = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type].Prepare != NULL) { + mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type]. + Prepare(sh->mpm_proto_tcp_ctx_tc); + } + } + } + } + + if (sh->mpm_proto_udp_ctx_ts != NULL) { + if (sh->mpm_proto_udp_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_ts); + sh->mpm_proto_udp_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type].Prepare != NULL) { + mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type]. + Prepare(sh->mpm_proto_udp_ctx_ts); + } + } + } + } + if (sh->mpm_proto_udp_ctx_tc != NULL) { + if (sh->mpm_proto_udp_ctx_tc->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_tc); + sh->mpm_proto_udp_ctx_tc = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type].Prepare != NULL) { + mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type]. + Prepare(sh->mpm_proto_udp_ctx_tc); + } + } + } + } + + if (sh->mpm_proto_other_ctx != NULL) { + if (sh->mpm_proto_other_ctx->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx); + sh->mpm_proto_other_ctx = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_proto_other_ctx->mpm_type].Prepare != NULL) { + mpm_table[sh->mpm_proto_other_ctx->mpm_type]. + Prepare(sh->mpm_proto_other_ctx); + } + } + } + } + + if (sh->mpm_stream_ctx_ts != NULL) { + if (sh->mpm_stream_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_ts); + sh->mpm_stream_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_stream_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_stream_ctx_ts->mpm_type].Prepare(sh->mpm_stream_ctx_ts); + } + } + } + if (sh->mpm_stream_ctx_tc != NULL) { + if (sh->mpm_stream_ctx_tc->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_tc); + sh->mpm_stream_ctx_tc = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_stream_ctx_tc->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_stream_ctx_tc->mpm_type].Prepare(sh->mpm_stream_ctx_tc); + } + } + } + + if (sh->mpm_uri_ctx_ts != NULL) { + if (sh->mpm_uri_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_ts); + sh->mpm_uri_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_uri_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_uri_ctx_ts->mpm_type].Prepare(sh->mpm_uri_ctx_ts); + } + } + } + + if (sh->mpm_hcbd_ctx_ts != NULL) { + if (sh->mpm_hcbd_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_ts); + sh->mpm_hcbd_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].Prepare(sh->mpm_hcbd_ctx_ts); + } + } + } + + if (sh->mpm_hsbd_ctx_tc != NULL) { + if (sh->mpm_hsbd_ctx_tc->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsbd_ctx_tc); + sh->mpm_hsbd_ctx_tc = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].Prepare(sh->mpm_hsbd_ctx_tc); + } + } + } + + if (sh->mpm_smtp_filedata_ctx_ts != NULL) { + if (sh->mpm_smtp_filedata_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_smtp_filedata_ctx_ts); + sh->mpm_smtp_filedata_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_smtp_filedata_ctx_ts->mpm_type].Prepare != NULL) { + mpm_table[sh->mpm_smtp_filedata_ctx_ts->mpm_type].Prepare(sh->mpm_smtp_filedata_ctx_ts); + } + } + } + } + + if (sh->mpm_hhd_ctx_ts != NULL) { + if (sh->mpm_hhd_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_ts); + sh->mpm_hhd_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].Prepare(sh->mpm_hhd_ctx_ts); + } + } + } + if (sh->mpm_hhd_ctx_tc != NULL) { + if (sh->mpm_hhd_ctx_tc->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_tc); + sh->mpm_hhd_ctx_tc = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].Prepare(sh->mpm_hhd_ctx_tc); + } + } + } + + if (sh->mpm_hrhd_ctx_ts != NULL) { + if (sh->mpm_hrhd_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_ts); + sh->mpm_hrhd_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].Prepare(sh->mpm_hrhd_ctx_ts); + } + } + } + if (sh->mpm_hrhd_ctx_tc != NULL) { + if (sh->mpm_hrhd_ctx_tc->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_tc); + sh->mpm_hrhd_ctx_tc = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].Prepare(sh->mpm_hrhd_ctx_tc); + } + } + } + + if (sh->mpm_hmd_ctx_ts != NULL) { + if (sh->mpm_hmd_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hmd_ctx_ts); + sh->mpm_hmd_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].Prepare(sh->mpm_hmd_ctx_ts); + } + } + } + + if (sh->mpm_hcd_ctx_ts != NULL) { + if (sh->mpm_hcd_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_ts); + sh->mpm_hcd_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].Prepare(sh->mpm_hcd_ctx_ts); + } + } + } + if (sh->mpm_hcd_ctx_tc != NULL) { + if (sh->mpm_hcd_ctx_tc->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_tc); + sh->mpm_hcd_ctx_tc = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].Prepare(sh->mpm_hcd_ctx_tc); + } + } + } + + if (sh->mpm_hrud_ctx_ts != NULL) { + if (sh->mpm_hrud_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrud_ctx_ts); + sh->mpm_hrud_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].Prepare(sh->mpm_hrud_ctx_ts); + } + } + } + + if (sh->mpm_hsmd_ctx_tc != NULL) { + if (sh->mpm_hsmd_ctx_tc->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsmd_ctx_tc); + sh->mpm_hsmd_ctx_tc = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].Prepare(sh->mpm_hsmd_ctx_tc); + } + } + } + + if (sh->mpm_hscd_ctx_tc != NULL) { + if (sh->mpm_hscd_ctx_tc->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hscd_ctx_tc); + sh->mpm_hscd_ctx_tc = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].Prepare(sh->mpm_hscd_ctx_tc); + } + } + } + + if (sh->mpm_huad_ctx_ts != NULL) { + if (sh->mpm_huad_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_huad_ctx_ts); + sh->mpm_huad_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare(sh->mpm_huad_ctx_ts); + } + } + } + + if (sh->mpm_hhhd_ctx_ts != NULL) { + if (sh->mpm_hhhd_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhhd_ctx_ts); + sh->mpm_hhhd_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hhhd_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hhhd_ctx_ts->mpm_type].Prepare(sh->mpm_hhhd_ctx_ts); + } + } + } + + if (sh->mpm_hrhhd_ctx_ts != NULL) { + if (sh->mpm_hrhhd_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_ts); + sh->mpm_hrhhd_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_hrhhd_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hrhhd_ctx_ts->mpm_type].Prepare(sh->mpm_hrhhd_ctx_ts); + } + } + } + + if (sh->mpm_dnsquery_ctx_ts != NULL) { + if (sh->mpm_dnsquery_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_dnsquery_ctx_ts); + sh->mpm_dnsquery_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].Prepare(sh->mpm_dnsquery_ctx_ts); + } + } + } } else { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx); sh->mpm_proto_other_ctx = NULL; From 0dd3b73db2d0264cbabcd402c76a171306f2ac72 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 13:57:57 +0200 Subject: [PATCH 0732/2553] mpm: assume we'll likely have a mpm_ctx --- src/detect-engine-mpm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index bc092cdfecdc..adf462675124 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -232,8 +232,7 @@ uint32_t PacketPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p) } else { mpm_ctx = det_ctx->sgh->mpm_proto_other_ctx; } - - if (mpm_ctx == NULL) + if (unlikely(mpm_ctx == NULL)) SCReturnInt(0); #ifdef __SC_CUDA_SUPPORT__ From a559c41295e395e8db01a18a543423a623837afa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 13:58:03 +0200 Subject: [PATCH 0733/2553] mpm: optimize & debug validate Wrappers are called only if a mpm_ctx is available. So remove the test for a null ctx and replace it by a debug validation BUG_ON. --- src/detect-engine-mpm.c | 72 ++++++++++++----------------------------- 1 file changed, 20 insertions(+), 52 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index adf462675124..b8a997ff6b30 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -185,15 +185,13 @@ uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, uint32_t ret = 0; if (p->flowflags & FLOW_PKT_TOSERVER) { - if (det_ctx->sgh->mpm_stream_ctx_ts == NULL) - SCReturnInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtc, &det_ctx->pmq, p->payload, p->payload_len); } else { - if (det_ctx->sgh->mpm_stream_ctx_tc == NULL) - SCReturnInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_tc == NULL); ret = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtc, &det_ctx->pmq, @@ -271,9 +269,7 @@ uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - - if (det_ctx->sgh->mpm_uri_ctx_ts == NULL) - SCReturnUInt(0U); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_uri_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_uri_ctx_ts, @@ -301,9 +297,7 @@ uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - - if (det_ctx->sgh->mpm_hcbd_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcbd_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hcbd_ctx_ts, &det_ctx->mtcu, @@ -329,9 +323,7 @@ uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); - - if (det_ctx->sgh->mpm_hsbd_ctx_tc == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsbd_ctx_tc == NULL); ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hsbd_ctx_tc, &det_ctx->mtcu, @@ -356,15 +348,13 @@ uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hhd_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhd_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hhd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, headers, headers_len); } else { - if (det_ctx->sgh->mpm_hhd_ctx_tc == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhd_ctx_tc == NULL); ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hhd_ctx_tc, &det_ctx->mtcu, @@ -390,15 +380,13 @@ uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hrhd_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhd_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hrhd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, raw_headers, raw_headers_len); } else { - if (det_ctx->sgh->mpm_hrhd_ctx_tc == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhd_ctx_tc == NULL); ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hrhd_ctx_tc, &det_ctx->mtcu, @@ -425,9 +413,7 @@ uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - - if (det_ctx->sgh->mpm_hmd_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hmd_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hmd_ctx_ts, &det_ctx->mtcu, @@ -452,15 +438,13 @@ uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hcd_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcd_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hcd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, cookie, cookie_len); } else { - if (det_ctx->sgh->mpm_hcd_ctx_tc == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcd_ctx_tc == NULL); ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hcd_ctx_tc, &det_ctx->mtcu, @@ -487,9 +471,7 @@ uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - - if (det_ctx->sgh->mpm_hrud_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrud_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hrud_ctx_ts, &det_ctx->mtcu, @@ -515,9 +497,7 @@ uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); - - if (det_ctx->sgh->mpm_hsmd_ctx_tc == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsmd_ctx_tc == NULL); ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hsmd_ctx_tc, &det_ctx->mtcu, @@ -543,9 +523,7 @@ uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); - - if (det_ctx->sgh->mpm_hscd_ctx_tc == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hscd_ctx_tc == NULL); ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hscd_ctx_tc, &det_ctx->mtcu, @@ -571,9 +549,7 @@ uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - - if (det_ctx->sgh->mpm_huad_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_huad_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, @@ -600,9 +576,7 @@ uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - - if (det_ctx->sgh->mpm_hhhd_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhhd_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hhhd_ctx_ts, &det_ctx->mtcu, @@ -629,9 +603,7 @@ uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - - if (det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hrhhd_ctx_ts, &det_ctx->mtcu, @@ -659,9 +631,7 @@ uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - - if (det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_dnsquery_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_dnsquery_ctx_ts, &det_ctx->mtcu, @@ -746,9 +716,7 @@ uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - - if (det_ctx->sgh->mpm_smtp_filedata_ctx_ts == NULL) - SCReturnUInt(0); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_smtp_filedata_ctx_ts == NULL); ret = mpm_table[det_ctx->sgh->mpm_smtp_filedata_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_smtp_filedata_ctx_ts, &det_ctx->mtcu, From 977074930ba9b88a5ad328ba61534a1241694052 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 18:41:36 +0200 Subject: [PATCH 0734/2553] mpm: use IPPROTO_TCP for readability --- src/detect-engine-mpm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index b8a997ff6b30..62d6c1517a6d 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -84,7 +84,7 @@ int SignatureHasPacketContent(Signature *s) SCReturnInt(0); } - if (!(s->proto.proto[6 / 8] & 1 << (6 % 8))) { + if (!(s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) { SCReturnInt(1); } @@ -118,7 +118,7 @@ int SignatureHasStreamContent(Signature *s) SCReturnInt(0); } - if (!(s->proto.proto[6 / 8] & 1 << (6 % 8))) { + if (!(s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) { SCReturnInt(0); } From da7bad7c1b5d95c5997b94c1368aa1837dc234ad Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 18:41:51 +0200 Subject: [PATCH 0735/2553] mpm: improve debug output --- src/detect-engine-mpm.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 62d6c1517a6d..7fd532e5cc0e 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -820,10 +820,11 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) { /* content */ if (!(sh->flags & SIG_GROUP_HEAD_MPM_COPY)) { - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_tcp_ctx_ts, sh); if (sh->mpm_proto_tcp_ctx_ts != NULL && - !sh->mpm_proto_tcp_ctx_ts->global) { + !sh->mpm_proto_tcp_ctx_ts->global) + { + SCLogDebug("destroying mpm_ctx %p (sh %p)", + sh->mpm_proto_tcp_ctx_ts, sh); mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type]. DestroyCtx(sh->mpm_proto_tcp_ctx_ts); SCFree(sh->mpm_proto_tcp_ctx_ts); @@ -831,10 +832,11 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) /* ready for reuse */ sh->mpm_proto_tcp_ctx_ts = NULL; - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_tcp_ctx_tc, sh); if (sh->mpm_proto_tcp_ctx_tc != NULL && - !sh->mpm_proto_tcp_ctx_tc->global) { + !sh->mpm_proto_tcp_ctx_tc->global) + { + SCLogDebug("destroying mpm_ctx %p (sh %p)", + sh->mpm_proto_tcp_ctx_tc, sh); mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type]. DestroyCtx(sh->mpm_proto_tcp_ctx_tc); SCFree(sh->mpm_proto_tcp_ctx_tc); @@ -842,10 +844,11 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) /* ready for reuse */ sh->mpm_proto_tcp_ctx_tc = NULL; - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_udp_ctx_ts, sh); if (sh->mpm_proto_udp_ctx_ts != NULL && - !sh->mpm_proto_udp_ctx_ts->global) { + !sh->mpm_proto_udp_ctx_ts->global) + { + SCLogDebug("destroying mpm_ctx %p (sh %p)", + sh->mpm_proto_udp_ctx_ts, sh); mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type]. DestroyCtx(sh->mpm_proto_udp_ctx_ts); SCFree(sh->mpm_proto_udp_ctx_ts); @@ -853,10 +856,11 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) /* ready for reuse */ sh->mpm_proto_udp_ctx_ts = NULL; - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_udp_ctx_tc, sh); if (sh->mpm_proto_udp_ctx_tc != NULL && - !sh->mpm_proto_udp_ctx_tc->global) { + !sh->mpm_proto_udp_ctx_tc->global) + { + SCLogDebug("destroying mpm_ctx %p (sh %p)", + sh->mpm_proto_udp_ctx_tc, sh); mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type]. DestroyCtx(sh->mpm_proto_udp_ctx_tc); SCFree(sh->mpm_proto_udp_ctx_tc); @@ -864,10 +868,11 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) /* ready for reuse */ sh->mpm_proto_udp_ctx_tc = NULL; - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_other_ctx, sh); if (sh->mpm_proto_other_ctx != NULL && - !sh->mpm_proto_other_ctx->global) { + !sh->mpm_proto_other_ctx->global) + { + SCLogDebug("destroying mpm_ctx %p (sh %p)", + sh->mpm_proto_other_ctx, sh); mpm_table[sh->mpm_proto_other_ctx->mpm_type]. DestroyCtx(sh->mpm_proto_other_ctx); SCFree(sh->mpm_proto_other_ctx); @@ -879,8 +884,8 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) /* uricontent */ if ((sh->mpm_uri_ctx_ts != NULL) && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) { if (sh->mpm_uri_ctx_ts != NULL) { - SCLogDebug("destroying mpm_uri_ctx %p (sh %p)", sh->mpm_uri_ctx_ts, sh); if (!sh->mpm_uri_ctx_ts->global) { + SCLogDebug("destroying mpm_uri_ctx %p (sh %p)", sh->mpm_uri_ctx_ts, sh); mpm_table[sh->mpm_uri_ctx_ts->mpm_type].DestroyCtx(sh->mpm_uri_ctx_ts); SCFree(sh->mpm_uri_ctx_ts); } @@ -893,8 +898,8 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) if ((sh->mpm_stream_ctx_ts != NULL || sh->mpm_stream_ctx_tc != NULL) && !(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)) { if (sh->mpm_stream_ctx_ts != NULL) { - SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx_ts, sh); if (!sh->mpm_stream_ctx_ts->global) { + SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx_ts, sh); mpm_table[sh->mpm_stream_ctx_ts->mpm_type].DestroyCtx(sh->mpm_stream_ctx_ts); SCFree(sh->mpm_stream_ctx_ts); } @@ -902,8 +907,8 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) sh->mpm_stream_ctx_ts = NULL; } if (sh->mpm_stream_ctx_tc != NULL) { - SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx_tc, sh); if (!sh->mpm_stream_ctx_tc->global) { + SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx_tc, sh); mpm_table[sh->mpm_stream_ctx_tc->mpm_type].DestroyCtx(sh->mpm_stream_ctx_tc); SCFree(sh->mpm_stream_ctx_tc); } From c53c9b4b2009f769f2ab6e6c670f6e68ad147213 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 18:56:43 +0200 Subject: [PATCH 0736/2553] mpm: remove bloated counting logic Counters were only used to print debug info. --- src/detect.c | 124 --------------------------------------------------- src/detect.h | 5 --- 2 files changed, 129 deletions(-) diff --git a/src/detect.c b/src/detect.c index 36f19cac07cd..2b7200949e4a 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3722,62 +3722,6 @@ int BuildDestinationAddressHeads(DetectEngineCtx *de_ctx, DetectAddressHead *hea printf("PatternMatchPrepareGroup failed\n"); goto error; } - if (sgr->sh->mpm_proto_tcp_ctx_ts != NULL) { - if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_tcp_ctx_ts->pattern_cnt) - de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; - - de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; - } - if (sgr->sh->mpm_proto_tcp_ctx_tc != NULL) { - if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_tcp_ctx_tc->pattern_cnt) - de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; - - de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; - } - if (sgr->sh->mpm_proto_udp_ctx_ts != NULL) { - if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_udp_ctx_ts->pattern_cnt) - de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_udp_ctx_ts->pattern_cnt; - - de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_udp_ctx_ts->pattern_cnt; - } - if (sgr->sh->mpm_proto_udp_ctx_tc != NULL) { - if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_udp_ctx_tc->pattern_cnt) - de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_udp_ctx_tc->pattern_cnt; - - de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_udp_ctx_tc->pattern_cnt; - } - if (sgr->sh->mpm_proto_other_ctx != NULL) { - if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_other_ctx->pattern_cnt) - de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_other_ctx->pattern_cnt; - - de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_other_ctx->pattern_cnt; - } - if (sgr->sh->mpm_uri_ctx_ts != NULL) { - if (de_ctx->mpm_uri_max_patcnt < sgr->sh->mpm_uri_ctx_ts->pattern_cnt) - de_ctx->mpm_uri_max_patcnt = sgr->sh->mpm_uri_ctx_ts->pattern_cnt; - - de_ctx->mpm_uri_tot_patcnt += sgr->sh->mpm_uri_ctx_ts->pattern_cnt; - } - /* dbg */ - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_tcp_ctx_ts) { - de_ctx->mpm_memory_size += sgr->sh->mpm_proto_tcp_ctx_ts->memory_size; - } - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_tcp_ctx_tc) { - de_ctx->mpm_memory_size += sgr->sh->mpm_proto_tcp_ctx_tc->memory_size; - } - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_udp_ctx_ts) { - de_ctx->mpm_memory_size += sgr->sh->mpm_proto_udp_ctx_ts->memory_size; - } - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_udp_ctx_tc) { - de_ctx->mpm_memory_size += sgr->sh->mpm_proto_udp_ctx_tc->memory_size; - } - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_other_ctx) { - de_ctx->mpm_memory_size += sgr->sh->mpm_proto_other_ctx->memory_size; - } - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY) && sgr->sh->mpm_uri_ctx_ts) { - de_ctx->mpm_memory_size += sgr->sh->mpm_uri_ctx_ts->memory_size; - } - SigGroupHeadHashAdd(de_ctx, sgr->sh); SigGroupHeadStore(de_ctx, sgr->sh); de_ctx->gh_unique++; @@ -4010,62 +3954,6 @@ int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, DetectAdd printf("PatternMatchPrepareGroup failed\n"); goto error; } - if (dp->sh->mpm_proto_tcp_ctx_ts != NULL) { - if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_tcp_ctx_ts->pattern_cnt) - de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; - - de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; - } - if (dp->sh->mpm_proto_tcp_ctx_tc != NULL) { - if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_tcp_ctx_tc->pattern_cnt) - de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; - - de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; - } - if (dp->sh->mpm_proto_udp_ctx_ts != NULL) { - if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_udp_ctx_ts->pattern_cnt) - de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_udp_ctx_ts->pattern_cnt; - - de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_udp_ctx_ts->pattern_cnt; - } - if (dp->sh->mpm_proto_udp_ctx_tc != NULL) { - if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_udp_ctx_tc->pattern_cnt) - de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_udp_ctx_tc->pattern_cnt; - - de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_udp_ctx_tc->pattern_cnt; - } - if (dp->sh->mpm_proto_other_ctx != NULL) { - if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_other_ctx->pattern_cnt) - de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_other_ctx->pattern_cnt; - - de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_other_ctx->pattern_cnt; - } - if (dp->sh->mpm_uri_ctx_ts != NULL) { - if (de_ctx->mpm_uri_max_patcnt < dp->sh->mpm_uri_ctx_ts->pattern_cnt) - de_ctx->mpm_uri_max_patcnt = dp->sh->mpm_uri_ctx_ts->pattern_cnt; - - de_ctx->mpm_uri_tot_patcnt += dp->sh->mpm_uri_ctx_ts->pattern_cnt; - } - /* dbg */ - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_tcp_ctx_ts) { - de_ctx->mpm_memory_size += dp->sh->mpm_proto_tcp_ctx_ts->memory_size; - } - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_tcp_ctx_tc) { - de_ctx->mpm_memory_size += dp->sh->mpm_proto_tcp_ctx_tc->memory_size; - } - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_udp_ctx_ts) { - de_ctx->mpm_memory_size += dp->sh->mpm_proto_udp_ctx_ts->memory_size; - } - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_udp_ctx_tc) { - de_ctx->mpm_memory_size += dp->sh->mpm_proto_udp_ctx_tc->memory_size; - } - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_other_ctx) { - de_ctx->mpm_memory_size += dp->sh->mpm_proto_other_ctx->memory_size; - } - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY) && dp->sh->mpm_uri_ctx_ts) { - de_ctx->mpm_memory_size += dp->sh->mpm_uri_ctx_ts->memory_size; - } - SigGroupHeadDPortHashAdd(de_ctx, dp->sh); SigGroupHeadStore(de_ctx, dp->sh); de_ctx->gh_unique++; @@ -4250,20 +4138,8 @@ int SigAddressPrepareStage3(DetectEngineCtx *de_ctx) DetectPortSpHashFree(de_ctx); if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("MPM memory %" PRIuMAX " (dynamic %" PRIu32 ", ctxs %" PRIuMAX ", avg per ctx %" PRIu32 ")", - de_ctx->mpm_memory_size + ((de_ctx->mpm_unique + de_ctx->mpm_uri_unique) * (uintmax_t)sizeof(MpmCtx)), - de_ctx->mpm_memory_size, ((de_ctx->mpm_unique + de_ctx->mpm_uri_unique) * (uintmax_t)sizeof(MpmCtx)), - de_ctx->mpm_unique ? de_ctx->mpm_memory_size / de_ctx->mpm_unique: 0); - SCLogDebug("max sig id %" PRIu32 ", array size %" PRIu32 "", DetectEngineGetMaxSigId(de_ctx), DetectEngineGetMaxSigId(de_ctx) / 8 + 1); SCLogDebug("signature group heads: unique %" PRIu32 ", copies %" PRIu32 ".", de_ctx->gh_unique, de_ctx->gh_reuse); - SCLogDebug("MPM instances: %" PRIu32 " unique, copies %" PRIu32 " (none %" PRIu32 ").", - de_ctx->mpm_unique, de_ctx->mpm_reuse, de_ctx->mpm_none); - SCLogDebug("MPM (URI) instances: %" PRIu32 " unique, copies %" PRIu32 " (none %" PRIu32 ").", - de_ctx->mpm_uri_unique, de_ctx->mpm_uri_reuse, de_ctx->mpm_uri_none); - SCLogDebug("MPM max patcnt %" PRIu32 ", avg %" PRIu32 "", de_ctx->mpm_max_patcnt, de_ctx->mpm_unique?de_ctx->mpm_tot_patcnt/de_ctx->mpm_unique:0); - if (de_ctx->mpm_uri_tot_patcnt && de_ctx->mpm_uri_unique) - SCLogDebug("MPM (URI) max patcnt %" PRIu32 ", avg %" PRIu32 " (%" PRIu32 "/%" PRIu32 ")", de_ctx->mpm_uri_max_patcnt, de_ctx->mpm_uri_tot_patcnt/de_ctx->mpm_uri_unique, de_ctx->mpm_uri_tot_patcnt, de_ctx->mpm_uri_unique); SCLogDebug("port maxgroups: %" PRIu32 ", avg %" PRIu32 ", tot %" PRIu32 "", g_groupportlist_maxgroups, g_groupportlist_groupscnt ? g_groupportlist_totgroups/g_groupportlist_groupscnt : 0, g_groupportlist_totgroups); SCLogInfo("building signature grouping structure, stage 3: building destination address lists... complete"); diff --git a/src/detect.h b/src/detect.h index 30adc9c4f81c..886b1ade1522 100644 --- a/src/detect.h +++ b/src/detect.h @@ -595,13 +595,8 @@ typedef struct DetectEngineCtx_ { /* 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; From 496f9800ac8c35d833cd75b7959caf2103728f61 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 19:28:52 +0200 Subject: [PATCH 0737/2553] mpm: remove used counter --- src/detect.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/detect.h b/src/detect.h index 886b1ade1522..4b7b89c7d02e 100644 --- a/src/detect.h +++ b/src/detect.h @@ -617,9 +617,6 @@ typedef struct DetectEngineCtx_ { /* 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; From df95d375bbe5c7ddfb1316baf8f2f025d22beb3d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 19:33:14 +0200 Subject: [PATCH 0738/2553] detect: improve comments on mpm --- src/detect.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/detect.h b/src/detect.h index 4b7b89c7d02e..e35a07761c74 100644 --- a/src/detect.h +++ b/src/detect.h @@ -449,10 +449,13 @@ typedef struct Signature_ { SigMatch *dsize_sm; /* the fast pattern added from this signature */ SigMatch *mpm_sm; - /* helper for init phase */ + + /* track max length for content. Indirectly used in grouping: + * used to set SigGroupHead::mpm_content_maxlen */ uint16_t mpm_content_maxlen; uint16_t mpm_uricontent_maxlen; + /* SigMatch list used for adding content and friends. E.g. file_data; */ int list; /* Be careful, this pointer is only valid while parsing the sig, @@ -986,6 +989,7 @@ typedef struct SigGroupHead_ { /* number of sigs in this head */ SigIntId sig_cnt; + /* track max length for content. Used in grouping */ uint16_t mpm_content_maxlen; /** array of masks, used to check multiple masks against From e529ebb50edbed9fe6aa6d1a5ad66bbf6bc17948 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 20:53:26 +0200 Subject: [PATCH 0739/2553] mpm: redo uri maxlen logic The mpm_uricontent_maxlen logic was meant to track the shortest possible pattern in the MPM of a SGH. So a minlen more than a maxlen. This patch replaces the complicated tracking logic by a simpler scheme. When the SGH's are finalize, the minlen is calculated. It also fixes a small corner case where the calculated "maxlen" could be wrong. This would require a smaller pattern in a rule to be forced as fast pattern. --- src/detect-engine-siggroup.c | 57 ++++++++++++++++++++++++------------ src/detect-engine-siggroup.h | 2 ++ src/detect-parse.c | 28 ------------------ src/detect-uricontent.c | 12 ++++---- src/detect.c | 3 ++ src/detect.h | 3 +- 6 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 02602d908e39..eaf915520c99 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -1038,17 +1038,6 @@ int SigGroupHeadAppendSig(DetectEngineCtx *de_ctx, SigGroupHead **sgh, SCLogDebug("(%p)->mpm_content_maxlen %u", *sgh, (*sgh)->mpm_content_maxlen); } } - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { - if (s->mpm_uricontent_maxlen > 0) { - if ((*sgh)->mpm_uricontent_maxlen == 0) - (*sgh)->mpm_uricontent_maxlen = s->mpm_uricontent_maxlen; - - if ((*sgh)->mpm_uricontent_maxlen > s->mpm_uricontent_maxlen) - (*sgh)->mpm_uricontent_maxlen = s->mpm_uricontent_maxlen; - - SCLogDebug("(%p)->mpm_uricontent_maxlen %u", *sgh, (*sgh)->mpm_uricontent_maxlen); - } - } return 0; error: @@ -1114,13 +1103,6 @@ int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHea SCLogDebug("dst (%p)->mpm_content_maxlen %u", (*dst), (*dst)->mpm_content_maxlen); BUG_ON((*dst)->mpm_content_maxlen == 0); } - if (src->mpm_uricontent_maxlen != 0) { - if ((*dst)->mpm_uricontent_maxlen == 0) - (*dst)->mpm_uricontent_maxlen = src->mpm_uricontent_maxlen; - - if ((*dst)->mpm_uricontent_maxlen > src->mpm_uricontent_maxlen) - (*dst)->mpm_uricontent_maxlen = src->mpm_uricontent_maxlen; - } return 0; error: @@ -1605,6 +1587,45 @@ void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return; } +/** + * \brief Get size of the shortest mpm pattern. + * + * \param de_ctx detection engine ctx for the signatures + * \param sgh sig group head to set the flag in + * \param list sm_list to consider + */ +uint16_t SigGroupHeadGetMinMpmSize(DetectEngineCtx *de_ctx, + SigGroupHead *sgh, int list) +{ + Signature *s = NULL; + uint32_t sig = 0; + uint16_t min = USHRT_MAX; + + if (sgh == NULL) + return 0; + + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; + if (s->sm_lists[list] == NULL) + continue; + + if (s->mpm_sm != NULL && SigMatchListSMBelongsTo(s, s->mpm_sm) == list) + { + DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; + if (cd->content_len < min) + min = cd->content_len; + SCLogDebug("cd->content_len %u", cd->content_len); + } + } + + if (min == USHRT_MAX) + min = 0; + SCLogDebug("min mpm size %u", min); + return min; +} + /** * \brief Set the need size flag in the sgh. * diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index 829b0cefb326..cd6810a1bf22 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -88,6 +88,8 @@ void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilestoreCount(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *, SigGroupHead *); +uint16_t SigGroupHeadGetMinMpmSize(DetectEngineCtx *de_ctx, + SigGroupHead *sgh, int list); int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh); diff --git a/src/detect-parse.c b/src/detect-parse.c index fedfebe8648d..7e723e8d1327 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1390,8 +1390,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (DetectAppLayerEventPrepare(sig) < 0) goto error; - /* set mpm_content_len */ - /* determine the length of the longest pattern in the sig */ if (sig->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { sig->mpm_content_maxlen = 0; @@ -1409,22 +1407,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, } } } - if (sig->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { - sig->mpm_uricontent_maxlen = 0; - - for (sm = sig->sm_lists[DETECT_SM_LIST_UMATCH]; sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - DetectContentData *ud = (DetectContentData *)sm->ctx; - if (ud == NULL) - continue; - - if (sig->mpm_uricontent_maxlen == 0) - sig->mpm_uricontent_maxlen = ud->content_len; - if (sig->mpm_uricontent_maxlen < ud->content_len) - sig->mpm_uricontent_maxlen = ud->content_len; - } - } - } /* set the packet and app layer flags, but only if the * app layer flag wasn't already set in which case we @@ -3273,11 +3255,6 @@ int SigParseTestMpm01 (void) goto end; } - if (sig->mpm_uricontent_maxlen != 0) { - printf("mpm uricontent max len %"PRIu16", expected 0: ", sig->mpm_uricontent_maxlen); - goto end; - } - result = 1; end: if (sig != NULL) @@ -3314,11 +3291,6 @@ int SigParseTestMpm02 (void) goto end; } - if (sig->mpm_uricontent_maxlen != 0) { - printf("mpm uricontent max len %"PRIu16", expected 0: ", sig->mpm_uricontent_maxlen); - goto end; - } - result = 1; end: if (sig != NULL) diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index a22479b07958..65d2ef9443fb 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -216,13 +216,13 @@ static inline int DoDetectAppLayerUricontentMatch (DetectEngineThreadCtx *det_ct { int ret = 0; /* run the pattern matcher against the uri */ - if (det_ctx->sgh->mpm_uricontent_maxlen > uri_len) { - SCLogDebug("not searching as pkt payload is smaller than the " - "largest uricontent length we need to match"); + if (det_ctx->sgh->mpm_uricontent_minlen > uri_len) { + SCLogDebug("not searching as uri len is smaller than the " + "shortest uricontent length we need to match"); } else { - SCLogDebug("search: (%p, maxlen %" PRIu32 ", sgh->sig_cnt " - "%" PRIu32 ")", det_ctx->sgh, det_ctx->sgh-> - mpm_uricontent_maxlen, det_ctx->sgh->sig_cnt); + SCLogDebug("search: (%p, minlen %" PRIu32 ", sgh->sig_cnt " + "%" PRIu32 ")", det_ctx->sgh, + det_ctx->sgh->mpm_uricontent_minlen, det_ctx->sgh->sig_cnt); ret += UriPatternSearch(det_ctx, uri, uri_len, flags); diff --git a/src/detect.c b/src/detect.c index 2b7200949e4a..0f940a98dbb1 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4252,6 +4252,9 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SCLogDebug("filestore count %u", sgh->filestore_cnt); SigGroupHeadBuildNonMpmArray(de_ctx, sgh); + + sgh->mpm_uricontent_minlen = SigGroupHeadGetMinMpmSize(de_ctx, sgh, DETECT_SM_LIST_UMATCH); + SCLogDebug("http_uri content min mpm len: %u", sgh->mpm_uricontent_minlen); } if (de_ctx->decoder_event_sgh != NULL) { diff --git a/src/detect.h b/src/detect.h index e35a07761c74..17adb8e4dd80 100644 --- a/src/detect.h +++ b/src/detect.h @@ -453,7 +453,6 @@ typedef struct Signature_ { /* track max length for content. Indirectly used in grouping: * used to set SigGroupHead::mpm_content_maxlen */ uint16_t mpm_content_maxlen; - uint16_t mpm_uricontent_maxlen; /* SigMatch list used for adding content and friends. E.g. file_data; */ int list; @@ -1030,7 +1029,7 @@ typedef struct SigGroupHead_ { MpmCtx *mpm_hsmd_ctx_tc; MpmCtx *mpm_hscd_ctx_tc; - uint16_t mpm_uricontent_maxlen; + uint16_t mpm_uricontent_minlen; /**< len of shortest mpm pattern in sgh */ /** the number of signatures in this sgh that have the filestore keyword * set. */ From 2716c786283799745436637cc6534bd0059a29e5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 21:46:34 +0200 Subject: [PATCH 0740/2553] mpm: improve SGH content len tracking SGH's track content length for rule grouping. This patch changes the logic to only consider the pattern that is used in the mpm for a sig. --- src/detect-engine-siggroup.c | 33 +++++++++++++++++++++------------ src/detect-parse.c | 29 ----------------------------- src/detect.c | 12 ------------ src/detect.h | 4 ---- 4 files changed, 21 insertions(+), 57 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index eaf915520c99..a63a8152aa78 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -998,6 +998,17 @@ void SigGroupHeadFreeMpmArrays(DetectEngineCtx *de_ctx) return; } +static uint16_t SignatureGetMpmPatternLen(Signature *s, int list) +{ + if (s->sm_lists[list] != NULL && s->mpm_sm != NULL && + SigMatchListSMBelongsTo(s, s->mpm_sm) == list) + { + DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; + return cd->content_len; + } + return 0; +} + /** * \brief Add a Signature to a SigGroupHead. * @@ -1028,12 +1039,13 @@ int SigGroupHeadAppendSig(DetectEngineCtx *de_ctx, SigGroupHead **sgh, /* update maxlen for mpm */ if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { /* check with the precalculated values from the sig */ - if (s->mpm_content_maxlen > 0) { + uint16_t mpm_content_minlen = SignatureGetMpmPatternLen(s, DETECT_SM_LIST_PMATCH); + if (mpm_content_minlen > 0) { if ((*sgh)->mpm_content_maxlen == 0) - (*sgh)->mpm_content_maxlen = s->mpm_content_maxlen; + (*sgh)->mpm_content_maxlen = mpm_content_minlen; - if ((*sgh)->mpm_content_maxlen > s->mpm_content_maxlen) - (*sgh)->mpm_content_maxlen = s->mpm_content_maxlen; + if ((*sgh)->mpm_content_maxlen > mpm_content_minlen) + (*sgh)->mpm_content_maxlen = mpm_content_minlen; SCLogDebug("(%p)->mpm_content_maxlen %u", *sgh, (*sgh)->mpm_content_maxlen); } @@ -1608,15 +1620,12 @@ uint16_t SigGroupHeadGetMinMpmSize(DetectEngineCtx *de_ctx, s = sgh->match_array[sig]; if (s == NULL) continue; - if (s->sm_lists[list] == NULL) - continue; - if (s->mpm_sm != NULL && SigMatchListSMBelongsTo(s, s->mpm_sm) == list) - { - DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; - if (cd->content_len < min) - min = cd->content_len; - SCLogDebug("cd->content_len %u", cd->content_len); + uint16_t mpm_content_minlen = SignatureGetMpmPatternLen(s, DETECT_SM_LIST_PMATCH); + if (mpm_content_minlen > 0) { + if (mpm_content_minlen < min) + min = mpm_content_minlen; + SCLogDebug("mpm_content_minlen %u", mpm_content_minlen); } } diff --git a/src/detect-parse.c b/src/detect-parse.c index 7e723e8d1327..9ac53e03c2d5 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1345,7 +1345,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, uint8_t dir) { - SigMatch *sm; Signature *sig = SigAlloc(); if (sig == NULL) goto error; @@ -1390,24 +1389,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (DetectAppLayerEventPrepare(sig) < 0) goto error; - /* determine the length of the longest pattern in the sig */ - if (sig->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { - sig->mpm_content_maxlen = 0; - - for (sm = sig->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)sm->ctx; - if (cd == NULL) - continue; - - if (sig->mpm_content_maxlen == 0) - sig->mpm_content_maxlen = cd->content_len; - if (sig->mpm_content_maxlen < cd->content_len) - sig->mpm_content_maxlen = cd->content_len; - } - } - } - /* set the packet and app layer flags, but only if the * app layer flag wasn't already set in which case we * only consider the app layer */ @@ -3250,11 +3231,6 @@ int SigParseTestMpm01 (void) goto end; } - if (sig->mpm_content_maxlen != 4) { - printf("mpm content max len %"PRIu16", expected 4: ", sig->mpm_content_maxlen); - goto end; - } - result = 1; end: if (sig != NULL) @@ -3286,11 +3262,6 @@ int SigParseTestMpm02 (void) goto end; } - if (sig->mpm_content_maxlen != 6) { - printf("mpm content max len %"PRIu16", expected 6: ", sig->mpm_content_maxlen); - goto end; - } - result = 1; end: if (sig != NULL) diff --git a/src/detect.c b/src/detect.c index 0f940a98dbb1..06319aa7bfc2 100644 --- a/src/detect.c +++ b/src/detect.c @@ -9792,10 +9792,6 @@ static int SigTestSgh01 (void) printf("internal id != 0: "); goto end; } - if (de_ctx->sig_list->mpm_content_maxlen != 3) { - printf("de_ctx->sig_list->mpm_content_maxlen %u, expected 3: ", de_ctx->sig_list->mpm_content_maxlen); - goto end; - } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 81 (msg:\"2\"; content:\"two\"; content:\"abcd\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { @@ -9806,10 +9802,6 @@ static int SigTestSgh01 (void) printf("internal id != 1: "); goto end; } - if (de_ctx->sig_list->next->mpm_content_maxlen != 4) { - printf("de_ctx->sig_list->mpm_content_maxlen %u, expected 4: ", de_ctx->sig_list->next->mpm_content_maxlen); - goto end; - } de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"3\"; content:\"three\"; sid:3;)"); if (de_ctx->sig_list->next->next == NULL) { @@ -9820,10 +9812,6 @@ static int SigTestSgh01 (void) printf("internal id != 2: "); goto end; } - if (de_ctx->sig_list->next->next->mpm_content_maxlen != 5) { - printf("de_ctx->sig_list->next->next->mpm_content_maxlen %u, expected 5: ", de_ctx->sig_list->next->next->mpm_content_maxlen); - goto end; - } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); diff --git a/src/detect.h b/src/detect.h index 17adb8e4dd80..480e7c4fbdc8 100644 --- a/src/detect.h +++ b/src/detect.h @@ -450,10 +450,6 @@ typedef struct Signature_ { /* the fast pattern added from this signature */ SigMatch *mpm_sm; - /* track max length for content. Indirectly used in grouping: - * used to set SigGroupHead::mpm_content_maxlen */ - uint16_t mpm_content_maxlen; - /* SigMatch list used for adding content and friends. E.g. file_data; */ int list; From 6b2f831a709382c78a71a03249b2ec412fda849f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 21:56:29 +0200 Subject: [PATCH 0741/2553] mpm: SGH maxlen was actually minlen, so rename --- src/detect-engine-siggroup.c | 30 ++++---- src/detect.c | 139 ++++++++++++++++++----------------- src/detect.h | 4 +- 3 files changed, 88 insertions(+), 85 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index a63a8152aa78..89e0eb797093 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -608,7 +608,7 @@ uint32_t SigGroupHeadHashFunc(HashListTable *ht, void *data, uint16_t datalen) uint32_t hash = 0; uint32_t b = 0; - SCLogDebug("hashing sgh %p (mpm_content_maxlen %u)", sgh, sgh->mpm_content_maxlen); + SCLogDebug("hashing sgh %p (mpm_content_minlen %u)", sgh, sgh->mpm_content_minlen); for (b = 0; b < sgh->init->sig_size; b++) hash += sgh->init->sig_array[b]; @@ -1036,18 +1036,18 @@ int SigGroupHeadAppendSig(DetectEngineCtx *de_ctx, SigGroupHead **sgh, /* enable the sig in the bitarray */ (*sgh)->init->sig_array[s->num / 8] |= 1 << (s->num % 8); - /* update maxlen for mpm */ + /* update minlen for mpm */ if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { /* check with the precalculated values from the sig */ uint16_t mpm_content_minlen = SignatureGetMpmPatternLen(s, DETECT_SM_LIST_PMATCH); if (mpm_content_minlen > 0) { - if ((*sgh)->mpm_content_maxlen == 0) - (*sgh)->mpm_content_maxlen = mpm_content_minlen; + if ((*sgh)->mpm_content_minlen == 0) + (*sgh)->mpm_content_minlen = mpm_content_minlen; - if ((*sgh)->mpm_content_maxlen > mpm_content_minlen) - (*sgh)->mpm_content_maxlen = mpm_content_minlen; + if ((*sgh)->mpm_content_minlen > mpm_content_minlen) + (*sgh)->mpm_content_minlen = mpm_content_minlen; - SCLogDebug("(%p)->mpm_content_maxlen %u", *sgh, (*sgh)->mpm_content_maxlen); + SCLogDebug("(%p)->mpm_content_minlen %u", *sgh, (*sgh)->mpm_content_minlen); } } return 0; @@ -1104,16 +1104,16 @@ int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHea for (idx = 0; idx < src->init->sig_size; idx++) (*dst)->init->sig_array[idx] = (*dst)->init->sig_array[idx] | src->init->sig_array[idx]; - if (src->mpm_content_maxlen != 0) { - if ((*dst)->mpm_content_maxlen == 0) - (*dst)->mpm_content_maxlen = src->mpm_content_maxlen; + if (src->mpm_content_minlen != 0) { + if ((*dst)->mpm_content_minlen == 0) + (*dst)->mpm_content_minlen = src->mpm_content_minlen; - if ((*dst)->mpm_content_maxlen > src->mpm_content_maxlen) - (*dst)->mpm_content_maxlen = src->mpm_content_maxlen; + if ((*dst)->mpm_content_minlen > src->mpm_content_minlen) + (*dst)->mpm_content_minlen = src->mpm_content_minlen; - SCLogDebug("src (%p)->mpm_content_maxlen %u", src, src->mpm_content_maxlen); - SCLogDebug("dst (%p)->mpm_content_maxlen %u", (*dst), (*dst)->mpm_content_maxlen); - BUG_ON((*dst)->mpm_content_maxlen == 0); + SCLogDebug("src (%p)->mpm_content_minlen %u", src, src->mpm_content_minlen); + SCLogDebug("dst (%p)->mpm_content_minlen %u", (*dst), (*dst)->mpm_content_minlen); + BUG_ON((*dst)->mpm_content_minlen == 0); } return 0; diff --git a/src/detect.c b/src/detect.c index 06319aa7bfc2..c9a16ead5c90 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1086,8 +1086,8 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_PACKET) { /* run the multi packet matcher against the payload of the packet */ - SCLogDebug("search: (%p, maxlen %" PRIu32 ", sgh->sig_cnt %" PRIu32 ")", - det_ctx->sgh, det_ctx->sgh->mpm_content_maxlen, det_ctx->sgh->sig_cnt); + SCLogDebug("search: (%p, minlen %" PRIu32 ", sgh->sig_cnt %" PRIu32 ")", + det_ctx->sgh, det_ctx->sgh->mpm_content_minlen, det_ctx->sgh->sig_cnt); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_PACKET); PacketPatternSearch(det_ctx, p); @@ -3105,15 +3105,15 @@ int CreateGroupedAddrListCmpCnt(DetectAddress *a, DetectAddress *b) return 0; } -int CreateGroupedAddrListCmpMpmMaxlen(DetectAddress *a, DetectAddress *b) +int CreateGroupedAddrListCmpMpmMinlen(DetectAddress *a, DetectAddress *b) { if (a->sh == NULL || b->sh == NULL) return 0; - if (SMALL_MPM(a->sh->mpm_content_maxlen)) + if (SMALL_MPM(a->sh->mpm_content_minlen)) return 1; - if (a->sh->mpm_content_maxlen < b->sh->mpm_content_maxlen) + if (a->sh->mpm_content_minlen < b->sh->mpm_content_minlen) return 1; return 0; } @@ -3139,7 +3139,7 @@ int CreateGroupedAddrList(DetectEngineCtx *de_ctx, DetectAddress *srchead, for (gr = srchead; gr != NULL; gr = gr->next) { BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); - if (SMALL_MPM(gr->sh->mpm_content_maxlen) && unique_groups > 0) + if (SMALL_MPM(gr->sh->mpm_content_minlen) && unique_groups > 0) unique_groups++; groups++; @@ -3280,15 +3280,15 @@ int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b) return 0; } -int CreateGroupedPortListCmpMpmMaxlen(DetectPort *a, DetectPort *b) +int CreateGroupedPortListCmpMpmMinlen(DetectPort *a, DetectPort *b) { if (a->sh == NULL || b->sh == NULL) return 0; - if (SMALL_MPM(a->sh->mpm_content_maxlen)) + if (SMALL_MPM(a->sh->mpm_content_minlen)) return 1; - if (a->sh->mpm_content_maxlen < b->sh->mpm_content_maxlen) + if (a->sh->mpm_content_minlen < b->sh->mpm_content_minlen) return 1; return 0; @@ -3315,7 +3315,7 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx,HashListTable *port_hash, Dete SCLogDebug("hash list gr %p", gr); DetectPortPrint(gr); - if (SMALL_MPM(gr->sh->mpm_content_maxlen) && unique_groups > 0) + if (SMALL_MPM(gr->sh->mpm_content_minlen) && unique_groups > 0) unique_groups++; groups++; @@ -3505,16 +3505,16 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) CreateGroupedAddrList(de_ctx, de_ctx->flow_gh[f].tmp_gh[proto]->ipv4_head, AF_INET, de_ctx->flow_gh[f].src_gh[proto], groups, - CreateGroupedAddrListCmpMpmMaxlen, DetectEngineGetMaxSigId(de_ctx)); + CreateGroupedAddrListCmpMpmMinlen, DetectEngineGetMaxSigId(de_ctx)); CreateGroupedAddrList(de_ctx, de_ctx->flow_gh[f].tmp_gh[proto]->ipv6_head, AF_INET6, de_ctx->flow_gh[f].src_gh[proto], groups, - CreateGroupedAddrListCmpMpmMaxlen, DetectEngineGetMaxSigId(de_ctx)); + CreateGroupedAddrListCmpMpmMinlen, DetectEngineGetMaxSigId(de_ctx)); CreateGroupedAddrList(de_ctx, de_ctx->flow_gh[f].tmp_gh[proto]->any_head, AF_UNSPEC, de_ctx->flow_gh[f].src_gh[proto], groups, - CreateGroupedAddrListCmpMpmMaxlen, DetectEngineGetMaxSigId(de_ctx)); + CreateGroupedAddrListCmpMpmMinlen, DetectEngineGetMaxSigId(de_ctx)); DetectAddressHeadFree(de_ctx->flow_gh[f].tmp_gh[proto]); de_ctx->flow_gh[f].tmp_gh[proto] = NULL; @@ -3697,7 +3697,8 @@ int BuildDestinationAddressHeads(DetectEngineCtx *de_ctx, DetectAddressHead *hea * mind the limits we use. */ int groups = (flow ? de_ctx->max_uniq_toserver_dst_groups : de_ctx->max_uniq_toclient_dst_groups); - CreateGroupedAddrList(de_ctx, tmp_gr_list, family, gr->dst_gh, groups, CreateGroupedAddrListCmpMpmMaxlen, max_idx); + CreateGroupedAddrList(de_ctx, tmp_gr_list, family, gr->dst_gh, groups, + CreateGroupedAddrListCmpMpmMinlen, max_idx); /* see if the sig group head of each address group is the * same as an earlier one. If it is, free our head and use @@ -3815,7 +3816,8 @@ int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, DetectAdd * mind the limits we use. */ int groups = (flow ? de_ctx->max_uniq_toserver_dst_groups : de_ctx->max_uniq_toclient_dst_groups); - CreateGroupedAddrList(de_ctx, tmp_gr_list, family, src_gr->dst_gh, groups, CreateGroupedAddrListCmpMpmMaxlen, max_idx); + CreateGroupedAddrList(de_ctx, tmp_gr_list, family, src_gr->dst_gh, groups, + CreateGroupedAddrListCmpMpmMinlen, max_idx); /* add the ports to the dst address groups and the sigs * to the ports */ @@ -3866,7 +3868,8 @@ int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, DetectAdd int spgroups = (flow ? de_ctx->max_uniq_toserver_sp_groups : de_ctx->max_uniq_toclient_sp_groups); - CreateGroupedPortList(de_ctx, de_ctx->sport_hash_table, &dst_gr->port, spgroups, CreateGroupedPortListCmpMpmMaxlen, max_idx); + CreateGroupedPortList(de_ctx, de_ctx->sport_hash_table, &dst_gr->port, spgroups, + CreateGroupedPortListCmpMpmMinlen, max_idx); SCLogDebug("adding sgh %p to the hash", dst_gr->sh); SigGroupHeadHashAdd(de_ctx, dst_gr->sh); @@ -3922,7 +3925,7 @@ int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, DetectAdd CreateGroupedPortList(de_ctx, de_ctx->dport_hash_table, &sp->dst_ph, dpgroups, - CreateGroupedPortListCmpMpmMaxlen, max_idx); + CreateGroupedPortListCmpMpmMinlen, max_idx); SigGroupHeadSPortHashAdd(de_ctx, sp->sh); @@ -4350,7 +4353,7 @@ int SigAddressPrepareStage5(DetectEngineCtx *de_ctx) DetectPort *dp = sp->dst_ph; for ( ; dp != NULL; dp = dp->next) { printf(" 4 Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ", sgh %p, maxlen %" PRIu32 ")", dp->sh->sig_cnt, dp->sh, dp->sh->mpm_content_maxlen); + printf(" (sigs %" PRIu32 ", sgh %p, minlen %" PRIu32 ")", dp->sh->sig_cnt, dp->sh, dp->sh->mpm_content_minlen); #ifdef PRINTSIGS printf(" - "); for (u = 0; u < dp->sh->sig_cnt; u++) { @@ -9828,8 +9831,8 @@ static int SigTestSgh01 (void) printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); #endif - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } @@ -9873,13 +9876,13 @@ static int SigTestSgh01 (void) #if 0 printf("-\n"); - printf("sgh2->mpm_content_maxlen %u\n", sgh2->mpm_content_maxlen); - printf("sgh2->mpm_uricontent_maxlen %u\n", sgh2->mpm_uricontent_maxlen); + printf("sgh2->mpm_content_minlen %u\n", sgh2->mpm_content_minlen); + printf("sgh2->mpm_uricontent_minlen %u\n", sgh2->mpm_uricontent_minlen); printf("sgh2->sig_cnt %u\n", sgh2->sig_cnt); printf("sgh2->sig_size %u\n", sgh2->sig_size); #endif - if (sgh2->mpm_content_maxlen != 4) { - printf("sgh2->mpm_content_maxlen %u, expected 4: ", sgh2->mpm_content_maxlen); + if (sgh2->mpm_content_minlen != 4) { + printf("sgh2->mpm_content_minlen %u, expected 4: ", sgh2->mpm_content_minlen); goto end; } @@ -9951,8 +9954,8 @@ static int SigTestSgh02 (void) goto end; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } @@ -9975,8 +9978,8 @@ static int SigTestSgh02 (void) goto end; } #if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); @@ -9989,8 +9992,8 @@ static int SigTestSgh02 (void) goto end; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } @@ -10011,8 +10014,8 @@ static int SigTestSgh02 (void) goto end; } #if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); @@ -10025,8 +10028,8 @@ static int SigTestSgh02 (void) goto end; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } @@ -10040,8 +10043,8 @@ static int SigTestSgh02 (void) goto end; } #if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); @@ -10055,8 +10058,8 @@ static int SigTestSgh02 (void) goto end; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } @@ -10070,8 +10073,8 @@ static int SigTestSgh02 (void) goto end; } #if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); @@ -10148,14 +10151,14 @@ static int SigTestSgh03 (void) } #if 0 printf("-\n"); - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } @@ -10188,8 +10191,8 @@ static int SigTestSgh03 (void) #if 0 printf("-\n"); printf("sgh %p\n", sgh); - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); @@ -10211,8 +10214,8 @@ static int SigTestSgh03 (void) goto end; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3 (%x): ", sgh->mpm_content_maxlen, p->dst.addr_data32[0]); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3 (%x): ", sgh->mpm_content_minlen, p->dst.addr_data32[0]); goto end; } @@ -10226,14 +10229,14 @@ static int SigTestSgh03 (void) } #if 0 printf("-\n"); - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } @@ -10319,8 +10322,8 @@ static int SigTestSgh04 (void) goto end; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } @@ -10343,8 +10346,8 @@ static int SigTestSgh04 (void) goto end; } #if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); @@ -10357,8 +10360,8 @@ static int SigTestSgh04 (void) goto end; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } @@ -10379,8 +10382,8 @@ static int SigTestSgh04 (void) goto end; } #if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); @@ -10393,8 +10396,8 @@ static int SigTestSgh04 (void) goto end; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } @@ -10408,8 +10411,8 @@ static int SigTestSgh04 (void) goto end; } #if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); @@ -10423,14 +10426,14 @@ static int SigTestSgh04 (void) } #if 0 printf("-\n"); - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); + printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); + printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (sgh->mpm_content_minlen != 3) { + printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); goto end; } diff --git a/src/detect.h b/src/detect.h index 480e7c4fbdc8..8d131b92a378 100644 --- a/src/detect.h +++ b/src/detect.h @@ -984,8 +984,8 @@ typedef struct SigGroupHead_ { /* number of sigs in this head */ SigIntId sig_cnt; - /* track max length for content. Used in grouping */ - uint16_t mpm_content_maxlen; + /* track min pattern length for content. Used in grouping */ + uint16_t mpm_content_minlen; /** array of masks, used to check multiple masks against * a packet using SIMD. */ From ff769b73a77bcaaa234a9b32f1977045af51cc2b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 21 Sep 2015 15:01:56 +0200 Subject: [PATCH 0742/2553] stream: improve retransmission detection Consider packets starting before last_ack and ending after it also to be retransmissions. This way we can see if they are having different data. --- src/stream-tcp.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index a4dcf41443ee..9dce70709ee3 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -798,6 +798,13 @@ static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p) if (p->payload_len == 0) SCReturnInt(0); + /* retransmission of already partially ack'd data */ + if (SEQ_LT(TCP_GET_SEQ(p), stream->last_ack) && SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) + { + StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION); + SCReturnInt(1); + } + /* retransmission of already ack'd data */ if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) { StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION); @@ -810,8 +817,8 @@ static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p) SCReturnInt(2); } - SCLogDebug("seq %u payload_len %u => %u, last_ack %u", TCP_GET_SEQ(p), - p->payload_len, (TCP_GET_SEQ(p) + p->payload_len), stream->last_ack); + SCLogDebug("seq %u payload_len %u => %u, last_ack %u, next_seq %u", TCP_GET_SEQ(p), + p->payload_len, (TCP_GET_SEQ(p) + p->payload_len), stream->last_ack, stream->next_seq); SCReturnInt(0); } From 480e91edac2d071f37b76d278e0b76a5f684a2fd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 20 Sep 2015 22:39:17 +0200 Subject: [PATCH 0743/2553] ippair: update ippair size logic Instead of using (sizeof(IPPair)+IPPairStorageSize()) in many places, create a simple size variable that is set during setup. --- src/ippair.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/ippair.c b/src/ippair.c index 780ee6ce168e..79ecb76ca806 100644 --- a/src/ippair.c +++ b/src/ippair.c @@ -47,6 +47,10 @@ static IPPair *IPPairGetUsedIPPair(void); /** queue with spare ippairs */ static IPPairQueue ippair_spare_q; +/** size of the ippair object. Maybe updated in IPPairInitConfig to include + * the storage APIs additions. */ +static uint16_t g_ippair_size = sizeof(IPPair); + uint32_t IPPairSpareQueueGetSize(void) { return IPPairQueueLen(&ippair_spare_q); @@ -60,19 +64,17 @@ void IPPairMoveToSpare(IPPair *h) IPPair *IPPairAlloc(void) { - size_t size = sizeof(IPPair) + IPPairStorageSize(); - - if (!(IPPAIR_CHECK_MEMCAP(size))) { + if (!(IPPAIR_CHECK_MEMCAP(g_ippair_size))) { return NULL; } - (void) SC_ATOMIC_ADD(ippair_memuse, size); + (void) SC_ATOMIC_ADD(ippair_memuse, g_ippair_size); - IPPair *h = SCMalloc(size); + IPPair *h = SCMalloc(g_ippair_size); if (unlikely(h == NULL)) goto error; - memset(h, 0x00, size); + memset(h, 0x00, g_ippair_size); SCMutexInit(&h->m, NULL); SC_ATOMIC_INIT(h->use_cnt); @@ -90,7 +92,7 @@ void IPPairFree(IPPair *h) SC_ATOMIC_DESTROY(h->use_cnt); SCMutexDestroy(&h->m); SCFree(h); - (void) SC_ATOMIC_SUB(ippair_memuse, (sizeof(IPPair) + IPPairStorageSize())); + (void) SC_ATOMIC_SUB(ippair_memuse, g_ippair_size); } } @@ -125,6 +127,8 @@ void IPPairClearMemory(IPPair *h) void IPPairInitConfig(char quiet) { SCLogDebug("initializing ippair engine..."); + if (IPPairStorageSize() > 0) + g_ippair_size = sizeof(IPPair) + IPPairStorageSize(); memset(&ippair_config, 0, sizeof(ippair_config)); //SC_ATOMIC_INIT(flow_flags); @@ -209,11 +213,11 @@ void IPPairInitConfig(char quiet) /* pre allocate ippairs */ for (i = 0; i < ippair_config.prealloc; i++) { - if (!(IPPAIR_CHECK_MEMCAP(sizeof(IPPair)))) { + if (!(IPPAIR_CHECK_MEMCAP(g_ippair_size))) { SCLogError(SC_ERR_IPPAIR_INIT, "preallocating ippairs failed: " "max ippair memcap reached. Memcap %"PRIu64", " "Memuse %"PRIu64".", ippair_config.memcap, - ((uint64_t)SC_ATOMIC_GET(ippair_memuse) + (uint64_t)sizeof(IPPair))); + ((uint64_t)SC_ATOMIC_GET(ippair_memuse) + g_ippair_size)); exit(EXIT_FAILURE); } @@ -226,8 +230,8 @@ void IPPairInitConfig(char quiet) } if (quiet == FALSE) { - SCLogInfo("preallocated %" PRIu32 " ippairs of size %" PRIuMAX "", - ippair_spare_q.len, (uintmax_t)sizeof(IPPair)); + SCLogInfo("preallocated %" PRIu32 " ippairs of size %" PRIu16 "", + ippair_spare_q.len, g_ippair_size); SCLogInfo("ippair memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(ippair_memuse), ippair_config.memcap); } @@ -382,7 +386,7 @@ static IPPair *IPPairGetNew(Address *a, Address *b) h = IPPairDequeue(&ippair_spare_q); if (h == NULL) { /* If we reached the max memcap, we get a used ippair */ - if (!(IPPAIR_CHECK_MEMCAP(sizeof(IPPair)))) { + if (!(IPPAIR_CHECK_MEMCAP(g_ippair_size))) { /* declare state of emergency */ //if (!(SC_ATOMIC_GET(ippair_flags) & IPPAIR_EMERGENCY)) { // SC_ATOMIC_OR(ippair_flags, IPPAIR_EMERGENCY); From 37fa4a48762dda0a8ed5c4f6bc68b383138afb63 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 20 Sep 2015 22:54:32 +0200 Subject: [PATCH 0744/2553] host: update host size logic Instead of using (sizeof(Host)+HostStorageSize()) in many places, create a simple size variable that is set during setup. --- src/host.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/host.c b/src/host.c index 7c3c5841720c..a28639cce454 100644 --- a/src/host.c +++ b/src/host.c @@ -48,6 +48,10 @@ static Host *HostGetUsedHost(void); /** queue with spare hosts */ static HostQueue host_spare_q; +/** size of the host object. Maybe updated in HostInitConfig to include + * the storage APIs additions. */ +static uint16_t g_host_size = sizeof(Host); + uint32_t HostSpareQueueGetSize(void) { return HostQueueLen(&host_spare_q); @@ -61,19 +65,16 @@ void HostMoveToSpare(Host *h) Host *HostAlloc(void) { - size_t size = sizeof(Host) + HostStorageSize(); - - if (!(HOST_CHECK_MEMCAP(size))) { + if (!(HOST_CHECK_MEMCAP(g_host_size))) { return NULL; } + (void) SC_ATOMIC_ADD(host_memuse, g_host_size); - (void) SC_ATOMIC_ADD(host_memuse, size); - - Host *h = SCMalloc(size); + Host *h = SCMalloc(g_host_size); if (unlikely(h == NULL)) goto error; - memset(h, 0x00, size); + memset(h, 0x00, g_host_size); SCMutexInit(&h->m, NULL); SC_ATOMIC_INIT(h->use_cnt); @@ -91,7 +92,7 @@ void HostFree(Host *h) SC_ATOMIC_DESTROY(h->use_cnt); SCMutexDestroy(&h->m); SCFree(h); - (void) SC_ATOMIC_SUB(host_memuse, (sizeof(Host) + HostStorageSize())); + (void) SC_ATOMIC_SUB(host_memuse, g_host_size); } } @@ -130,6 +131,8 @@ void HostClearMemory(Host *h) void HostInitConfig(char quiet) { SCLogDebug("initializing host engine..."); + if (HostStorageSize() > 0) + g_host_size = sizeof(Host) + HostStorageSize(); memset(&host_config, 0, sizeof(host_config)); //SC_ATOMIC_INIT(flow_flags); @@ -214,11 +217,11 @@ void HostInitConfig(char quiet) /* pre allocate hosts */ for (i = 0; i < host_config.prealloc; i++) { - if (!(HOST_CHECK_MEMCAP(sizeof(Host)))) { + if (!(HOST_CHECK_MEMCAP(g_host_size))) { SCLogError(SC_ERR_HOST_INIT, "preallocating hosts failed: " "max host memcap reached. Memcap %"PRIu64", " "Memuse %"PRIu64".", host_config.memcap, - ((uint64_t)SC_ATOMIC_GET(host_memuse) + (uint64_t)sizeof(Host))); + ((uint64_t)SC_ATOMIC_GET(host_memuse) + g_host_size)); exit(EXIT_FAILURE); } @@ -231,8 +234,8 @@ void HostInitConfig(char quiet) } if (quiet == FALSE) { - SCLogInfo("preallocated %" PRIu32 " hosts of size %" PRIuMAX "", - host_spare_q.len, (uintmax_t)sizeof(Host)); + SCLogInfo("preallocated %" PRIu32 " hosts of size %" PRIu16 "", + host_spare_q.len, g_host_size); SCLogInfo("host memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(host_memuse), host_config.memcap); } @@ -386,7 +389,7 @@ static Host *HostGetNew(Address *a) h = HostDequeue(&host_spare_q); if (h == NULL) { /* If we reached the max memcap, we get a used host */ - if (!(HOST_CHECK_MEMCAP(sizeof(Host)))) { + if (!(HOST_CHECK_MEMCAP(g_host_size))) { /* declare state of emergency */ //if (!(SC_ATOMIC_GET(host_flags) & HOST_EMERGENCY)) { // SC_ATOMIC_OR(host_flags, HOST_EMERGENCY); From fc7f090cd3268a3a624177cef32a9576b74975e3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 21 Sep 2015 08:34:19 +0200 Subject: [PATCH 0745/2553] flow: add missing storage size to checks, output --- src/flow-hash.c | 3 ++- src/flow.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index 7a151199268a..b8de40e77fd6 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -35,6 +35,7 @@ #include "flow-util.h" #include "flow-private.h" #include "flow-manager.h" +#include "flow-storage.h" #include "app-layer-parser.h" #include "util-time.h" @@ -472,7 +473,7 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) f = FlowDequeue(&flow_spare_q); if (f == NULL) { /* If we reached the max memcap, we get a used flow */ - if (!(FLOW_CHECK_MEMCAP(sizeof(Flow)))) { + if (!(FLOW_CHECK_MEMCAP(sizeof(Flow) + FlowStorageSize()))) { /* declare state of emergency */ if (!(SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)) { SC_ATOMIC_OR(flow_flags, FLOW_EMERGENCY); diff --git a/src/flow.c b/src/flow.c index 42099c3ad5e9..abd9e7e5fb77 100644 --- a/src/flow.c +++ b/src/flow.c @@ -443,7 +443,7 @@ void FlowInitConfig(char quiet) /* pre allocate flows */ for (i = 0; i < flow_config.prealloc; i++) { - if (!(FLOW_CHECK_MEMCAP(sizeof(Flow)))) { + if (!(FLOW_CHECK_MEMCAP(sizeof(Flow) + FlowStorageSize()))) { SCLogError(SC_ERR_FLOW_INIT, "preallocating flows failed: " "max flow memcap reached. Memcap %"PRIu64", " "Memuse %"PRIu64".", flow_config.memcap, @@ -462,7 +462,7 @@ void FlowInitConfig(char quiet) if (quiet == FALSE) { SCLogInfo("preallocated %" PRIu32 " flows of size %" PRIuMAX "", - flow_spare_q.len, (uintmax_t)sizeof(Flow)); + flow_spare_q.len, (uintmax_t)(sizeof(Flow) + + FlowStorageSize())); SCLogInfo("flow memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(flow_memuse), flow_config.memcap); } From 77302e5d51f8a0f8c4486a39a7b5c8bd243aa3d8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Sep 2015 22:07:57 +0200 Subject: [PATCH 0746/2553] threshold: remove debug message from info loglevel --- src/detect-engine-threshold.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index 6c6d1371a8d6..2d37e55e7c38 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -216,11 +216,11 @@ int ThresholdHandlePacketSuppress(Packet *p, DetectThresholdData *td, uint32_t s switch (td->track) { case TRACK_DST: m = DetectAddressLookupInHead(&td->addrs, &p->dst); - SCLogInfo("TRACK_DST"); + SCLogDebug("TRACK_DST"); break; case TRACK_SRC: m = DetectAddressLookupInHead(&td->addrs, &p->src); - SCLogInfo("TRACK_SRC"); + SCLogDebug("TRACK_SRC"); break; /* suppress if either src or dst is a match on the suppress * address list */ From 5c26a2f2c8f52a4612f6c185dfd5af912f418589 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 17 Apr 2015 16:13:23 +0200 Subject: [PATCH 0747/2553] email-json: move email fields to email section This patch changes the way smtp message are written. It is using the "email" key to store the email related fields. This will allow to do the same search through SMTP and IMAP if we implement this last one. --- src/output-json-email-common.c | 29 ++--------------------------- src/output-json-email-common.h | 4 +++- src/output-json-smtp.c | 22 ++++++++++++++++++++-- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 1efa9ce80fac..de8e2568b17c 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -56,12 +56,11 @@ #include /* JSON format logging */ -static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) +TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) { SMTPState *smtp_state; MimeDecParseState *mime_state; MimeDecEntity *entity; - char *protos = NULL; json_t *sjs = json_object(); if (sjs == NULL) { @@ -80,7 +79,6 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packe SMTPTransaction *tx = vtx; mime_state = tx->mime_state; entity = tx->msg_tail; - protos = "smtp"; SCLogDebug("lets go mime_state %p, entity %p, state_flag %u", mime_state, entity, mime_state ? mime_state->state_flag : 0); break; default: @@ -229,7 +227,7 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packe } else { json_decref(js_url); } - json_object_set_new(js, protos, sjs); + json_object_set_new(js, "email", sjs); // FLOWLOCK_UNLOCK(p->flow); SCReturnInt(TM_ECODE_OK); @@ -240,27 +238,4 @@ static TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packe SCReturnInt(TM_ECODE_DONE); } -int JsonEmailLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) { - SCEnter(); - JsonEmailLogThread *jhl = (JsonEmailLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)jhl->buffer; - - json_t *js = CreateJSONHeader((Packet *)p, 1, "smtp"); - if (unlikely(js == NULL)) - return TM_ECODE_OK; - - /* reset */ - MemBufferReset(buffer); - - if (JsonEmailLogJson(jhl, js, p, f, state, tx, tx_id) == TM_ECODE_OK) { - OutputJSONBuffer(js, jhl->emaillog_ctx->file_ctx, buffer); - } - json_object_del(js, "smtp"); - - json_object_clear(js); - json_decref(js); - - SCReturnInt(TM_ECODE_OK); -} - #endif diff --git a/src/output-json-email-common.h b/src/output-json-email-common.h index 7a95954c77bd..618ba828ccb8 100644 --- a/src/output-json-email-common.h +++ b/src/output-json-email-common.h @@ -35,6 +35,8 @@ typedef struct JsonEmailLogThread_ { MemBuffer *buffer; } JsonEmailLogThread; -int JsonEmailLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id); +#ifdef HAVE_LIBJANSSON +TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id); +#endif #endif /* __OUTPUT_JSON_EMAIL_COMMON_H__ */ diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index f722c383e0b2..bb835f07c3a1 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -57,8 +57,26 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) { SCEnter(); - int r = JsonEmailLogger(tv, thread_data, p, f, state, tx, tx_id); - SCReturnInt(r); + JsonEmailLogThread *jhl = (JsonEmailLogThread *)thread_data; + MemBuffer *buffer = (MemBuffer *)jhl->buffer; + + json_t *js = CreateJSONHeader((Packet *)p, 1, "smtp"); + if (unlikely(js == NULL)) + return TM_ECODE_OK; + + /* reset */ + MemBufferReset(buffer); + + if (JsonEmailLogJson(jhl, js, p, f, state, tx, tx_id) == TM_ECODE_OK) { + OutputJSONBuffer(js, jhl->emaillog_ctx->file_ctx, buffer); + } + json_object_del(js, "smtp"); + + json_object_clear(js); + json_decref(js); + + SCReturnInt(TM_ECODE_OK); + } static void OutputSmtpLogDeInitCtx(OutputCtx *output_ctx) From 7bca8268bcae54db5a2e7ac0914f63f78a39d49b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 17 Apr 2015 10:46:15 +0200 Subject: [PATCH 0748/2553] app-layer-smtp: extract and store HELO and MAIL FROM This patch updates the SMTP transaction and SMTP state to be able to contain the HELO and MAIL FROM fields. --- src/app-layer-smtp.c | 69 ++++++++++++++++++++++++++++++++++++++++++++ src/app-layer-smtp.h | 7 +++++ 2 files changed, 76 insertions(+) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 1951613d1f3a..d0c6589eea8f 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -955,6 +955,52 @@ static int SMTPParseCommandBDAT(SMTPState *state) return 0; } +static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8_t **target, uint16_t *target_len) +{ + int i = prefix_len + 1; + int spc_i = 0; + + while (i < state->current_line_len) { + if (state->current_line[i] != ' ') { + break; + } + i++; + } + + /* rfc1870: with the size extension the mail from can be followed by an option. + We use the space separator to detect it. */ + spc_i = i; + while (spc_i < state->current_line_len) { + if (state->current_line[spc_i] == ' ') { + break; + } + spc_i++; + } + + /* FIXME check arithmetic */ + *target = SCMalloc(spc_i - i + 1); + if (*target == NULL) + return -1; + memcpy(*target, state->current_line + i, spc_i - i); + (*target)[spc_i - i] = '\0'; + *target_len = spc_i - i; + + return 0; + +} + +static int SMTPParseCommandHELO(SMTPState *state) +{ + return SMTPParseCommandWithParam(state, 4, &state->helo, &state->helo_len); +} + +static int SMTPParseCommandMAILFROM(SMTPState *state) +{ + return SMTPParseCommandWithParam(state, 9, + &state->curr_tx->mail_from, + &state->curr_tx->mail_from_len); +} + /* consider 'rset' and 'quit' to be part of the existing state */ static int NoNewTx(SMTPState *state) { @@ -1027,6 +1073,21 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, } state->current_command = SMTP_COMMAND_BDAT; state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; + } else if (state->current_line_len >= 4 && + ((SCMemcmpLowercase("helo", state->current_line, 4) == 0) || + SCMemcmpLowercase("ehlo", state->current_line, 4) == 0)) { + r = SMTPParseCommandHELO(state); + if (r == -1) { + SCReturnInt(-1); + } + state->current_command = SMTP_COMMAND_OTHER_CMD; + } else if (state->current_line_len >= 9 && + SCMemcmpLowercase("mail from", state->current_line, 9) == 0) { + r = SMTPParseCommandMAILFROM(state); + if (r == -1) { + SCReturnInt(-1); + } + state->current_command = SMTP_COMMAND_OTHER_CMD; } else { state->current_command = SMTP_COMMAND_OTHER_CMD; } @@ -1178,6 +1239,10 @@ static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state) if (tx->de_state != NULL) DetectEngineStateFree(tx->de_state); + + if (tx->mail_from) + SCFree(tx->mail_from); + #if 0 if (tx->decoder_events->cnt <= smtp_state->events) smtp_state->events -= tx->decoder_events->cnt; @@ -1205,6 +1270,10 @@ static void SMTPStateFree(void *p) SCFree(smtp_state->tc_db); } + if (smtp_state->helo) { + SCFree(smtp_state->helo); + } + FileContainerFree(smtp_state->files_ts); SMTPTransaction *tx = NULL; diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 02090c61c07e..a63061638ea6 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -65,6 +65,10 @@ typedef struct SMTPTransaction_ { AppLayerDecoderEvents *decoder_events; /**< per tx events */ DetectEngineState *de_state; + /* MAIL FROM parameters */ + uint8_t *mail_from; + uint16_t mail_from_len; + TAILQ_ENTRY(SMTPTransaction_) next; } SMTPTransaction; @@ -136,6 +140,9 @@ typedef struct SMTPState_ { /** the list of files sent to the server */ FileContainer *files_ts; + /* HELO of HELO message content */ + uint8_t *helo; + uint16_t helo_len; } SMTPState; /* Create SMTP config structure */ From 2abae3f0a13237a3a945b058b03147b59acdc8e0 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 17 Apr 2015 16:34:56 +0200 Subject: [PATCH 0749/2553] smtp-json: update SMTP EVE messages This patch updates SMTP message to have them feature a 'smtp' section which will contain all fields coming from the smtp protocol. --- src/output-json-smtp.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index bb835f07c3a1..43ac93d54254 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -54,12 +54,32 @@ #ifdef HAVE_LIBJANSSON #include +static json_t *JsonSmtpDataLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) +{ + json_t *sjs = json_object(); + SMTPTransaction *tx = vtx; + if (sjs == NULL) { + return NULL; + } + if (((SMTPState *)state)->helo) { + json_object_set_new(sjs, "helo", + json_string((const char *)((SMTPState *)state)->helo)); + } + if (tx->mail_from) { + json_object_set_new(sjs, "mail_from", + json_string((const char *)tx->mail_from)); + } + + return sjs; +} + static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) { SCEnter(); JsonEmailLogThread *jhl = (JsonEmailLogThread *)thread_data; MemBuffer *buffer = (MemBuffer *)jhl->buffer; + json_t *sjs; json_t *js = CreateJSONHeader((Packet *)p, 1, "smtp"); if (unlikely(js == NULL)) return TM_ECODE_OK; @@ -67,10 +87,18 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl /* reset */ MemBufferReset(buffer); + sjs = JsonSmtpDataLogger(tv, thread_data, p, f, state, tx, tx_id); + if (sjs) { + json_object_set_new(js, "smtp", sjs); + } + if (JsonEmailLogJson(jhl, js, p, f, state, tx, tx_id) == TM_ECODE_OK) { OutputJSONBuffer(js, jhl->emaillog_ctx->file_ctx, buffer); } - json_object_del(js, "smtp"); + json_object_del(js, "email"); + if (sjs) { + json_object_del(js, "smtp"); + } json_object_clear(js); json_decref(js); From 752fdba95725a94cf1cb31145009fd90448397b3 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 22 Apr 2015 14:40:30 +0200 Subject: [PATCH 0750/2553] app-layer-smtp: parse and extract RCPT TO fields Add the RCPT TO fields to a linked list stored in the transaction. --- src/app-layer-smtp.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ src/app-layer-smtp.h | 9 ++++++++ 2 files changed, 64 insertions(+) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index d0c6589eea8f..db2dd651ca36 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -222,6 +222,8 @@ SCEnumCharMap smtp_reply_map[ ] = { /* Create SMTP config structure */ SMTPConfig smtp_config = { 0, { 0, 0, 0, 0 }, 0, 0, 0}; +static SMTPString *SMTPStringAlloc(void); + /** * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML * config file @@ -323,6 +325,7 @@ static SMTPTransaction *SMTPTransactionCreate(void) return NULL; } + TAILQ_INIT(&tx->rcpt_to_list); tx->mime_state = NULL; return tx; } @@ -1001,6 +1004,27 @@ static int SMTPParseCommandMAILFROM(SMTPState *state) &state->curr_tx->mail_from_len); } +static int SMTPParseCommandRCPTTO(SMTPState *state) +{ + uint8_t *rcptto; + uint16_t rcptto_len; + + if (SMTPParseCommandWithParam(state, 7, &rcptto, &rcptto_len) == 0) { + SMTPString *rcptto_str = SMTPStringAlloc(); + if (rcptto_str) { + rcptto_str->str = rcptto; + rcptto_str->len = rcptto_len; + TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next); + } else { + SCFree(rcptto); + return -1; + } + } else { + return -1; + } + return 0; +} + /* consider 'rset' and 'quit' to be part of the existing state */ static int NoNewTx(SMTPState *state) { @@ -1088,6 +1112,13 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, SCReturnInt(-1); } state->current_command = SMTP_COMMAND_OTHER_CMD; + } else if (state->current_line_len >= 7 && + SCMemcmpLowercase("rcpt to", state->current_line, 7) == 0) { + r = SMTPParseCommandRCPTTO(state); + if (r == -1) { + SCReturnInt(-1); + } + state->current_command = SMTP_COMMAND_OTHER_CMD; } else { state->current_command = SMTP_COMMAND_OTHER_CMD; } @@ -1203,6 +1234,25 @@ void *SMTPStateAlloc(void) return smtp_state; } +static SMTPString *SMTPStringAlloc(void) +{ + SMTPString *smtp_string = SCMalloc(sizeof(SMTPString)); + if (unlikely(smtp_string == NULL)) + return NULL; + memset(smtp_string, 0, sizeof(SMTPString)); + + return smtp_string; +} + + +static void SMTPStringFree(SMTPString *str) +{ + if (str->str) { + SCFree(str->str); + } + SCFree(str); +} + static void *SMTPLocalStorageAlloc(void) { /* needed by the mpm */ @@ -1243,6 +1293,11 @@ static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state) if (tx->mail_from) SCFree(tx->mail_from); + SMTPString *str = NULL; + while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) { + TAILQ_REMOVE(&tx->rcpt_to_list, str, next); + SMTPStringFree(str); + } #if 0 if (tx->decoder_events->cnt <= smtp_state->events) smtp_state->events -= tx->decoder_events->cnt; diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index a63061638ea6..c58684143ab0 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -51,6 +51,13 @@ enum { SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG, }; +typedef struct SMTPString_ { + uint8_t *str; + uint16_t len; + + TAILQ_ENTRY(SMTPString_) next; +} SMTPString; + typedef struct SMTPTransaction_ { /** id of this tx, starting at 0 */ uint64_t tx_id; @@ -69,6 +76,8 @@ typedef struct SMTPTransaction_ { uint8_t *mail_from; uint16_t mail_from_len; + TAILQ_HEAD(, SMTPString_) rcpt_to_list; /**< rcpt to string list */ + TAILQ_ENTRY(SMTPTransaction_) next; } SMTPTransaction; From 0f3979cc814a35a63ba7aca8582551439bd5ab59 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 22 Apr 2015 14:41:20 +0200 Subject: [PATCH 0751/2553] output-json-smtp: output RCPT TO fields This patch uses an array to output the RCPT TO fields to the JSON message. --- src/output-json-smtp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 43ac93d54254..9ebebca7e4a8 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -58,6 +58,7 @@ static json_t *JsonSmtpDataLogger(ThreadVars *tv, void *thread_data, const Packe { json_t *sjs = json_object(); SMTPTransaction *tx = vtx; + SMTPString *rcptto_str; if (sjs == NULL) { return NULL; } @@ -69,6 +70,15 @@ static json_t *JsonSmtpDataLogger(ThreadVars *tv, void *thread_data, const Packe json_object_set_new(sjs, "mail_from", json_string((const char *)tx->mail_from)); } + if (!TAILQ_EMPTY(&tx->rcpt_to_list)) { + json_t *js_rcptto = json_array(); + if (likely(js_rcptto != NULL)) { + TAILQ_FOREACH(rcptto_str, &tx->rcpt_to_list, next) { + json_array_append_new(js_rcptto, json_string((char *)rcptto_str->str)); + } + json_object_set_new(sjs, "rcpt_to", js_rcptto); + } + } return sjs; } From e43eb76abd043c5eb14240d808b66a6d07d4f1d2 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 24 Apr 2015 13:25:41 +0200 Subject: [PATCH 0752/2553] app-layer-stmp: simplify code Delete a only used once goto to a point where we only do a return. --- src/app-layer-smtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index db2dd651ca36..ed034d4ed683 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -369,7 +369,7 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, if (smtp_state->files_ts == NULL) { ret = MIME_DEC_ERR_MEM; SCLogError(SC_ERR_MEM_ALLOC, "Could not create file container"); - goto end; + SCReturnInt(ret); } } files = smtp_state->files_ts; @@ -451,7 +451,7 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, if (files != NULL) { FilePrune(files); } -end: + SCReturnInt(ret); } From d39009ca582af30a1478934be7259294a7247d09 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 24 Apr 2015 16:17:19 +0200 Subject: [PATCH 0753/2553] decode-mime: compute body md5 This patch is computing the md5 sum of the body of the MIME message. This will allow to detect messages with same content and sent to different people. --- src/util-decode-mime.c | 27 +++++++++++++++++++++++++++ src/util-decode-mime.h | 4 ++++ 2 files changed, 31 insertions(+) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 3f4affcccf6c..3b33c548de36 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -1992,6 +1992,7 @@ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ + static int ProcessBodyComplete(MimeDecParseState *state) { int ret = MIME_DEC_OK; @@ -2180,6 +2181,16 @@ static int ProcessMimeBody(const uint8_t *buf, uint32_t len, int body_found = 0; uint32_t tlen; +#ifdef HAVE_NSS + if (state->body_begin == 1 && (state->md5_ctx == NULL)) { + state->md5_ctx = HASH_Create(HASH_AlgMD5); + if (state->md5_ctx != NULL) { + HASH_Begin(state->md5_ctx); + HASH_Update(state->md5_ctx, buf, len + 2); /* plus 2 to add CRLF */ + } + } +#endif + /* Ignore empty lines */ if (len == 0) { return ret; @@ -2394,6 +2405,10 @@ void MimeDecDeInitParser(MimeDecParseState *state) SCFree(state->hname); FreeDataValue(state->hvalue); FreeMimeDecStack(state->stack); +#ifdef HAVE_NSS + if (state->md5_ctx) + HASH_Destroy(state->md5_ctx); +#endif SCFree(state); } @@ -2427,6 +2442,13 @@ int MimeDecParseComplete(MimeDecParseState *state) return ret; } +#ifdef HAVE_NSS + if (state->md5_ctx) { + unsigned int len = 0; + HASH_End(state->md5_ctx, state->md5, &len, sizeof(state->md5)); + } +#endif + if (state->stack->top == NULL) { state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; SCLogDebug("Error: Message is malformed"); @@ -2475,6 +2497,11 @@ int MimeDecParseLine(const uint8_t *line, const uint32_t len, SCLogDebug("SMTP LINE - EMPTY"); } +#ifdef HAVE_NSS + if (state->md5_ctx) { + HASH_Update(state->md5_ctx, line, len + 2); + } +#endif /* Process the entity */ ret = ProcessMimeEntity(line, len, state); if (ret != MIME_DEC_OK) { diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h index 792fbcc199c7..69f328e3c693 100644 --- a/src/util-decode-mime.h +++ b/src/util-decode-mime.h @@ -197,6 +197,10 @@ typedef struct MimeDecParseState { uint8_t bvremain[B64_BLOCK]; /**< Remainder from base64-decoded line */ uint8_t bvr_len; /**< Length of remainder from base64-decoded line */ uint8_t data_chunk[DATA_CHUNK_SIZE]; /**< Buffer holding data chunk */ +#ifdef HAVE_NSS + HASHContext *md5_ctx; + uint8_t md5[MD5_LENGTH]; +#endif uint8_t state_flag; /**< Flag representing current state of parser */ uint32_t data_chunk_len; /**< Length of data chunk */ int found_child; /**< Flag indicating a child entity was found */ From ea311c159424a8a76e2b76875f65e38737e1bc6c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 28 Apr 2015 13:23:23 +0200 Subject: [PATCH 0754/2553] email-json: export md5sum of body The body_md5 has been added and contain the value of the md5sum of the body. This patch is using the state PARSE_DONE on the MIME state to detect when a message has been completely parsed. --- src/output-json-email-common.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index de8e2568b17c..17d4b0ec00e5 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -90,6 +90,20 @@ TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, F SCReturnInt(TM_ECODE_FAILED); } +#ifdef HAVE_NSS + if (mime_state->md5_ctx && (mime_state->state_flag == PARSE_DONE)) { + size_t x; + int i; + char s[256]; + if (likely(s != NULL)) { + for (i = 0, x = 0; x < sizeof(mime_state->md5); x++) { + i += snprintf(s + i, 255-i, "%02x", mime_state->md5[x]); + } + json_object_set_new(sjs, "body_md5", json_string(s)); + } + } +#endif + if ((entity->header_flags & HDR_IS_LOGGED) == 0) { MimeDecField *field; //printf("email LOG\n"); From 990055842830a65cb31ea51c52a06412c3d6c191 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 5 May 2015 15:00:58 +0200 Subject: [PATCH 0755/2553] smtp: add 'body-md5' mime option This option will allow the user to select weither or not he wants to journalize the md5 of the mail body. --- src/app-layer-smtp.c | 7 ++++++- src/util-decode-mime.c | 4 ++-- src/util-decode-mime.h | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index ed034d4ed683..139533468f9c 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -220,7 +220,7 @@ SCEnumCharMap smtp_reply_map[ ] = { }; /* Create SMTP config structure */ -SMTPConfig smtp_config = { 0, { 0, 0, 0, 0 }, 0, 0, 0}; +SMTPConfig smtp_config = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 0}; static SMTPString *SMTPStringAlloc(void); @@ -266,6 +266,11 @@ static void SMTPConfigure(void) { if (ret) { smtp_config.mime_config.extract_urls = val; } + + ret = ConfGetChildValueBool(config, "body-md5", &val); + if (ret) { + smtp_config.mime_config.body_md5 = val; + } } /* Pass mime config data to MimeDec API */ diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 3b33c548de36..312a9af493ae 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -79,7 +79,7 @@ #define MAX_IP6_CHARS 39 /* Globally hold configuration data */ -static MimeDecConfig mime_dec_config = { 1, 1, 1, MAX_HEADER_VALUE }; +static MimeDecConfig mime_dec_config = { 1, 1, 1, 0, MAX_HEADER_VALUE }; #ifdef DEBUG /* Mime Parser String translation */ @@ -2182,7 +2182,7 @@ static int ProcessMimeBody(const uint8_t *buf, uint32_t len, uint32_t tlen; #ifdef HAVE_NSS - if (state->body_begin == 1 && (state->md5_ctx == NULL)) { + if (MimeDecGetConfig()->body_md5 && state->body_begin == 1 && (state->md5_ctx == NULL)) { state->md5_ctx = HASH_Create(HASH_AlgMD5); if (state->md5_ctx != NULL) { HASH_Begin(state->md5_ctx); diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h index 69f328e3c693..020a1f16657b 100644 --- a/src/util-decode-mime.h +++ b/src/util-decode-mime.h @@ -97,6 +97,7 @@ typedef struct MimeDecConfig { int decode_base64; /**< Decode base64 bodies */ int decode_quoted_printable; /**< Decode quoted-printable bodies */ int extract_urls; /**< Extract and store URLs in data structure */ + int body_md5; /**< Compute md5 sum of body */ uint32_t header_value_depth; /**< Depth of which to store header values (Default is 2000) */ } MimeDecConfig; From a233a982ea1495b0d473c8affecac5dbb4f66b20 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 29 Apr 2015 18:24:09 +0200 Subject: [PATCH 0756/2553] decode-mime: add function to get status This new function return the textual status of MIME parsing. --- src/util-decode-mime.c | 7 +++++-- src/util-decode-mime.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 312a9af493ae..718cdeb64b05 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -81,7 +81,6 @@ /* Globally hold configuration data */ static MimeDecConfig mime_dec_config = { 1, 1, 1, 0, MAX_HEADER_VALUE }; -#ifdef DEBUG /* Mime Parser String translation */ static const char *StateFlags[] = { "NONE", "HEADER_READY", @@ -93,7 +92,6 @@ static const char *StateFlags[] = { "NONE", "PARSE_DONE", "PARSE_ERROR", NULL }; -#endif /* URL executable file extensions */ static const char *UrlExeExts[] = { ".exe", @@ -2265,6 +2263,11 @@ static int ProcessMimeBody(const uint8_t *buf, uint32_t len, return ret; } +const char *MimeDecParseStateGetStatus(MimeDecParseState *state) +{ + return StateFlags[state->state_flag]; +} + /** * \brief Processes the MIME Entity based on the input line and current state of * the parser diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h index 020a1f16657b..50d67a92a35e 100644 --- a/src/util-decode-mime.h +++ b/src/util-decode-mime.h @@ -238,6 +238,7 @@ int MimeDecParseComplete(MimeDecParseState *state); int MimeDecParseLine(const uint8_t *line, const uint32_t len, MimeDecParseState *state); MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); +const char *MimeDecParseStateGetStatus(MimeDecParseState *state); /* Test functions */ void MimeDecRegisterTests(void); From d7e13c2c039901fdc4042431d693be31fe1c7ef1 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 29 Apr 2015 18:25:05 +0200 Subject: [PATCH 0757/2553] email-json: output MIME parsing status If the status is not PARSE_DONE then in that case we may have imcomplete information. Increasing the stream reassemly depth in that case would be a good idea. --- src/output-json-email-common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 17d4b0ec00e5..f5366efb9746 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -104,6 +104,9 @@ TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, F } #endif + json_object_set_new(sjs, "status", + json_string(MimeDecParseStateGetStatus(mime_state))); + if ((entity->header_flags & HDR_IS_LOGGED) == 0) { MimeDecField *field; //printf("email LOG\n"); From bccabe3813627abfe4f7a77272d1b195a8115753 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 30 Apr 2015 11:08:47 +0200 Subject: [PATCH 0758/2553] http-json: introduce JsonHttpAddMetadata function This function will be usable in other logging components to add the http data to their messages. --- src/output-json-http.c | 22 ++++++++++++++++++++++ src/output-json-http.h | 1 + 2 files changed, 23 insertions(+) diff --git a/src/output-json-http.c b/src/output-json-http.c index 316419855aa1..bf926b2adf94 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -396,6 +396,28 @@ static int JsonHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl SCReturnInt(TM_ECODE_OK); } +json_t *JsonHttpAddMetadata(const Flow *f) +{ + HtpState *htp_state = (HtpState *)FlowGetAppState(f); + if (htp_state) { + uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, tx_id); + + if (tx) { + json_t *hjs = json_object(); + if (unlikely(hjs == NULL)) + return NULL; + + JsonHttpLogJSONBasic(hjs, tx); + JsonHttpLogJSONExtended(hjs, tx); + + return hjs; + } + } + + return NULL; +} + static void OutputHttpLogDeinit(OutputCtx *output_ctx) { LogHttpFileCtx *http_ctx = output_ctx->data; diff --git a/src/output-json-http.h b/src/output-json-http.h index ab412d227c94..b8fcea15be0e 100644 --- a/src/output-json-http.h +++ b/src/output-json-http.h @@ -29,6 +29,7 @@ void TmModuleJsonHttpLogRegister (void); #ifdef HAVE_LIBJANSSON void JsonHttpLogJSONBasic(json_t *js, htp_tx_t *tx); void JsonHttpLogJSONExtended(json_t *js, htp_tx_t *tx); +json_t *JsonHttpAddMetadata(const Flow *f); #endif /* HAVE_LIBJANSSON */ #endif /* __OUTPUT_JSON_HTTP_H__ */ From 4ef12dcf5d0d7e47f25a5a1cb78b9c2b73f8deef Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 30 Apr 2015 12:52:22 +0200 Subject: [PATCH 0759/2553] alert-json: use new JsonHttpAddMetadata function This patch uses the newly introduced function to handle the logging of HTTP data. --- src/output-json-alert.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 3c4219b42876..e357d2c9d9ee 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -101,31 +101,6 @@ static int AlertJsonDumpStreamSegmentCallback(const Packet *p, void *data, uint8 return 1; } -/** Handle the case where no JSON support is compiled in. - * - */ -static void AlertJsonHttp(const Flow *f, json_t *js) -{ - HtpState *htp_state = (HtpState *)FlowGetAppState(f); - if (htp_state) { - uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, tx_id); - - if (tx) { - json_t *hjs = json_object(); - if (unlikely(hjs == NULL)) - return; - - JsonHttpLogJSONBasic(hjs, tx); - JsonHttpLogJSONExtended(hjs, tx); - - json_object_set_new(js, "http", hjs); - } - } - - return; -} - static void AlertJsonTls(const Flow *f, json_t *js) { SSLState *ssl_state = (SSLState *)FlowGetAppState(f); @@ -198,6 +173,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) { MemBuffer *payload = aft->payload_buffer; AlertJsonOutputCtx *json_output_ctx = aft->json_output_ctx; + json_t *hjs = NULL; int i; @@ -225,8 +201,11 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) uint16_t proto = FlowGetAppProtocol(p->flow); /* http alert */ - if (proto == ALPROTO_HTTP) - AlertJsonHttp(p->flow, js); + if (proto == ALPROTO_HTTP) { + hjs = JsonHttpAddMetadata(p->flow); + if (hjs) + json_object_set_new(js, "http", hjs); + } FLOWLOCK_UNLOCK(p->flow); } From 94dbd303e4744a40f3761265be7c73a7a4754764 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 30 Apr 2015 12:53:09 +0200 Subject: [PATCH 0760/2553] file-json: log http data using common function --- src/output-json-file.c | 111 ++--------------------------------------- 1 file changed, 5 insertions(+), 106 deletions(-) diff --git a/src/output-json-file.c b/src/output-json-file.c index cbfa0c4d0b6c..556d7e2d2b6b 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -53,6 +53,7 @@ #include "output.h" #include "output-json.h" +#include "output-json-http.h" #include "log-file.h" #include "util-logopenfile.h" @@ -74,99 +75,6 @@ typedef struct JsonFileLogThread_ { MemBuffer *buffer; } JsonFileLogThread; -static json_t *LogFileMetaGetUri(const Packet *p, const File *ff) -{ - HtpState *htp_state = (HtpState *)p->flow->alstate; - json_t *js = NULL; - if (htp_state != NULL) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid); - if (tx != NULL) { - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - char *s = bstr_util_strdup_to_c(tx_ud->request_uri_normalized); - if (s != NULL) { - js = json_string(s); - SCFree(s); - if (js != NULL) - return js; - } - } - } - } - - return NULL; -} - -static json_t *LogFileMetaGetHost(const Packet *p, const File *ff) -{ - HtpState *htp_state = (HtpState *)p->flow->alstate; - json_t *js = NULL; - if (htp_state != NULL) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid); - if (tx != NULL && tx->request_hostname != NULL) { - char *s = bstr_util_strdup_to_c(tx->request_hostname); - if (s != NULL) { - js = json_string(s); - SCFree(s); - if (js != NULL) - return js; - } - } - } - - return NULL; -} - -static json_t *LogFileMetaGetReferer(const Packet *p, const File *ff) -{ - HtpState *htp_state = (HtpState *)p->flow->alstate; - json_t *js = NULL; - if (htp_state != NULL) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid); - if (tx != NULL) { - htp_header_t *h = NULL; - h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "Referer"); - if (h != NULL) { - char *s = bstr_util_strdup_to_c(h->value); - if (s != NULL) { - js = json_string(s); - SCFree(s); - if (js != NULL) - return js; - } - } - } - } - - return NULL; -} - -static json_t *LogFileMetaGetUserAgent(const Packet *p, const File *ff) -{ - HtpState *htp_state = (HtpState *)p->flow->alstate; - json_t *js = NULL; - if (htp_state != NULL) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid); - if (tx != NULL) { - htp_header_t *h = NULL; - h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "User-Agent"); - if (h != NULL) { - char *s = bstr_util_strdup_to_c(h->value); - if (s != NULL) { - js = json_string(s); - SCFree(s); - if (js != NULL) - return js; - } - } - } - } - - return NULL; -} - /** * \internal * \brief Write meta data on a single line json record @@ -175,33 +83,24 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F { MemBuffer *buffer = (MemBuffer *)aft->buffer; json_t *js = CreateJSONHeader((Packet *)p, 0, "fileinfo"); //TODO const + json_t *hjs = NULL; if (unlikely(js == NULL)) return; /* reset */ MemBufferReset(buffer); - json_t *hjs = json_object(); - if (unlikely(hjs == NULL)) { - json_decref(js); - return; - } - - json_object_set_new(hjs, "app_proto", json_string(AppProtoToString(p->flow->alproto))); switch (p->flow->alproto) { case ALPROTO_HTTP: - json_object_set_new(hjs, "url", LogFileMetaGetUri(p, ff)); - json_object_set_new(hjs, "hostname", LogFileMetaGetHost(p, ff)); - json_object_set_new(hjs, "http_refer", LogFileMetaGetReferer(p, ff)); - json_object_set_new(hjs, "http_user_agent", LogFileMetaGetUserAgent(p, ff)); - json_object_set_new(js, "http", hjs); + hjs = JsonHttpAddMetadata(p->flow); + if (hjs) + json_object_set_new(js, "http", hjs); break; } json_t *fjs = json_object(); if (unlikely(fjs == NULL)) { - json_decref(hjs); json_decref(js); return; } From 47a199ee978608ba4351c40f48c00833bdc3b6c6 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 30 Apr 2015 13:28:49 +0200 Subject: [PATCH 0761/2553] smtp-json: introduce function to output smtp data --- src/output-json-smtp.c | 19 +++++++++++++++++-- src/output-json-smtp.h | 3 +++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 9ebebca7e4a8..255209571c4a 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -54,7 +54,7 @@ #ifdef HAVE_LIBJANSSON #include -static json_t *JsonSmtpDataLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) +static json_t *JsonSmtpDataLogger(const Flow *f, void *state, void *vtx, uint64_t tx_id) { json_t *sjs = json_object(); SMTPTransaction *tx = vtx; @@ -97,7 +97,7 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl /* reset */ MemBufferReset(buffer); - sjs = JsonSmtpDataLogger(tv, thread_data, p, f, state, tx, tx_id); + sjs = JsonSmtpDataLogger(f, state, tx, tx_id); if (sjs) { json_object_set_new(js, "smtp", sjs); } @@ -117,6 +117,21 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl } +json_t *JsonSMTPAddMetadata(const Flow *f) +{ + SMTPState *smtp_state = (SMTPState *)FlowGetAppState(f); + if (smtp_state) { + uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); + SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, smtp_state, tx_id); + + if (tx) { + return JsonSmtpDataLogger(f, smtp_state, tx, tx_id); + } + } + + return NULL; +} + static void OutputSmtpLogDeInitCtx(OutputCtx *output_ctx) { OutputJsonEmailCtx *email_ctx = output_ctx->data; diff --git a/src/output-json-smtp.h b/src/output-json-smtp.h index d38187c706b8..5b3233abca9f 100644 --- a/src/output-json-smtp.h +++ b/src/output-json-smtp.h @@ -25,5 +25,8 @@ #define __OUTPUT_JSON_SMTP_H__ void TmModuleJsonSmtpLogRegister (void); +#ifdef HAVE_LIBJANSSON +json_t *JsonSMTPAddMetadata(const Flow *f); +#endif #endif /* __OUTPUT_JSON_SMTP_H__ */ From 77119a31863ee9cc3bedcd8abf007914ba7942cc Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 30 Apr 2015 13:44:58 +0200 Subject: [PATCH 0762/2553] file-json: output smtp proto info --- src/output-json-file.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/output-json-file.c b/src/output-json-file.c index 556d7e2d2b6b..8e1ea7796a78 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -54,6 +54,7 @@ #include "output.h" #include "output-json.h" #include "output-json-http.h" +#include "output-json-smtp.h" #include "log-file.h" #include "util-logopenfile.h" @@ -96,6 +97,11 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F if (hjs) json_object_set_new(js, "http", hjs); break; + case ALPROTO_SMTP: + hjs = JsonSMTPAddMetadata(p->flow); + if (hjs) + json_object_set_new(js, "smtp", hjs); + break; } @@ -151,7 +157,15 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F json_object_set_new(js, "fileinfo", fjs); OutputJSONBuffer(js, aft->filelog_ctx->file_ctx, buffer); json_object_del(js, "fileinfo"); - json_object_del(js, "http"); + + switch (p->flow->alproto) { + case ALPROTO_HTTP: + json_object_del(js, "http"); + break; + case ALPROTO_SMTP: + json_object_del(js, "smtp"); + break; + } json_object_clear(js); json_decref(js); From ab941305d53cacd20697403b4ced1b26e44dacc0 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 30 Apr 2015 14:45:52 +0200 Subject: [PATCH 0763/2553] email-json: add function to export data --- src/output-json-email-common.c | 49 ++++++++++++++++++++++++++-------- src/output-json-email-common.h | 3 ++- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index f5366efb9746..f7553460e348 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -56,7 +56,7 @@ #include /* JSON format logging */ -TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) +json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_id) { SMTPState *smtp_state; MimeDecParseState *mime_state; @@ -64,17 +64,17 @@ TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, F json_t *sjs = json_object(); if (sjs == NULL) { - SCReturnInt(TM_ECODE_FAILED); + SCReturnPtr(NULL, "json_t"); } /* check if we have SMTP state or not */ - AppProto proto = FlowGetAppProtocol(p->flow); + AppProto proto = FlowGetAppProtocol(f); switch (proto) { case ALPROTO_SMTP: smtp_state = (SMTPState *)state; if (smtp_state == NULL) { SCLogDebug("no smtp state, so no request logging"); - SCReturnInt(TM_ECODE_FAILED); + SCReturnPtr(NULL, "json_t"); } SMTPTransaction *tx = vtx; mime_state = tx->mime_state; @@ -83,11 +83,11 @@ TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, F break; default: /* don't know how we got here */ - SCReturnInt(TM_ECODE_FAILED); + SCReturnPtr(NULL, "json_t"); } if ((mime_state != NULL)) { if (entity == NULL) { - SCReturnInt(TM_ECODE_FAILED); + SCReturnPtr(NULL, "json_t"); } #ifdef HAVE_NSS @@ -187,7 +187,7 @@ TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, F entity->header_flags |= HDR_IS_LOGGED; if (mime_state->stack == NULL || mime_state->stack->top == NULL || mime_state->stack->top->data == NULL) - SCReturnInt(TM_ECODE_OK); + SCReturnPtr(NULL, "json_t"); entity = (MimeDecEntity *)mime_state->stack->top->data; int attch_cnt = 0; @@ -244,15 +244,42 @@ TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, F } else { json_decref(js_url); } - json_object_set_new(js, "email", sjs); - // FLOWLOCK_UNLOCK(p->flow); - SCReturnInt(TM_ECODE_OK); + SCReturnPtr(sjs, "json_t"); } } + json_decref(sjs); // FLOWLOCK_UNLOCK(p->flow); - SCReturnInt(TM_ECODE_DONE); + SCReturnPtr(NULL, "json_t"); +} + +/* JSON format logging */ +TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) +{ + json_t *sjs = JsonEmailLogJsonData(f, state, vtx, tx_id); + + if (sjs) { + json_object_set_new(js, "email", sjs); + SCReturnInt(TM_ECODE_OK); + } else + SCReturnInt(TM_ECODE_FAILED); } +json_t *JsonEmailAddMetadata(const Flow *f) +{ + SMTPState *smtp_state = (SMTPState *)FlowGetAppState(f); + if (smtp_state) { + uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); + SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, smtp_state, tx_id); + + if (tx) { + return JsonEmailLogJsonData(f, smtp_state, tx, tx_id); + } + } + + return NULL; +} + + #endif diff --git a/src/output-json-email-common.h b/src/output-json-email-common.h index 618ba828ccb8..4553e8572ce4 100644 --- a/src/output-json-email-common.h +++ b/src/output-json-email-common.h @@ -30,13 +30,14 @@ typedef struct OutputJsonEmailCtx_ { } OutputJsonEmailCtx; +#ifdef HAVE_LIBJANSSON typedef struct JsonEmailLogThread_ { OutputJsonEmailCtx *emaillog_ctx; MemBuffer *buffer; } JsonEmailLogThread; -#ifdef HAVE_LIBJANSSON TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id); +json_t *JsonEmailAddMetadata(const Flow *f); #endif #endif /* __OUTPUT_JSON_EMAIL_COMMON_H__ */ From 54038f5691c0e3367651a1fa0b8ff3346ad5f07b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 30 Apr 2015 15:24:52 +0200 Subject: [PATCH 0764/2553] file-json: log 'email' information Log information coming from email/MIME decoding in the message. --- src/output-json-file.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/output-json-file.c b/src/output-json-file.c index 8e1ea7796a78..615ae596e86c 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -51,13 +51,14 @@ #include "util-buffer.h" #include "util-byte.h" +#include "log-file.h" +#include "util-logopenfile.h" + #include "output.h" #include "output-json.h" #include "output-json-http.h" #include "output-json-smtp.h" - -#include "log-file.h" -#include "util-logopenfile.h" +#include "output-json-email-common.h" #include "app-layer-htp.h" #include "util-memcmp.h" @@ -101,6 +102,9 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F hjs = JsonSMTPAddMetadata(p->flow); if (hjs) json_object_set_new(js, "smtp", hjs); + hjs = JsonEmailAddMetadata(p->flow); + if (hjs) + json_object_set_new(js, "email", hjs); break; } @@ -164,6 +168,7 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F break; case ALPROTO_SMTP: json_object_del(js, "smtp"); + json_object_del(js, "email"); break; } From 714c30a127828bfff8e8c44e19c3ffc7316744df Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 5 May 2015 14:31:55 +0200 Subject: [PATCH 0765/2553] decode-mime: introduce MimeDecFindFieldsForEach This patch introduces a new function that can be used to handle multivalued MIME fields. A callback function can be called for each corresponding field value. --- src/util-decode-mime.c | 29 +++++++++++++++++++++++++++++ src/util-decode-mime.h | 1 + 2 files changed, 30 insertions(+) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 718cdeb64b05..8a36b26aaa25 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -297,6 +297,35 @@ MimeDecField * MimeDecAddField(MimeDecEntity *entity) return node; } + +/** + * \brief Searches for header fields with the specified name + * + * \param entity The entity to search + * \param name The header name (lowercase) + * + * \return number of items found + * + */ +int MimeDecFindFieldsForEach(const MimeDecEntity *entity, const char *name, int (*DataCallback)(const uint8_t *val, const size_t, void *data), void *data) +{ + MimeDecField *curr = entity->field_list; + int found = 0; + + while (curr != NULL) { + /* name is stored lowercase */ + if (strlen(name) == curr->name_len) { + if (SCMemcmp(curr->name, name, curr->name_len) == 0) { + if (DataCallback(curr->value, curr->value_len, data)) + found++; + } + } + curr = curr->next; + } + + return found; +} + /** * \brief Searches for a header field with the specified name * diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h index 50d67a92a35e..5fb4cdb75d3e 100644 --- a/src/util-decode-mime.h +++ b/src/util-decode-mime.h @@ -224,6 +224,7 @@ void MimeDecFreeUrl(MimeDecUrl *url); /* List functions */ MimeDecField * MimeDecAddField(MimeDecEntity *entity); MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name); +int MimeDecFindFieldsForEach(const MimeDecEntity *entity, const char *name, int (*DataCallback)(const uint8_t *val, const size_t, void *data), void *data); MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent); /* Helper functions */ From 3456ec467f7c36f5cd5f324f75c7a8f43e9afc71 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 5 May 2015 14:33:50 +0200 Subject: [PATCH 0766/2553] email-json: add custom fields support This patch adds a way to specify which MIME fields to log via the custom keyword in the EVE configuration. it also adds an extended logging where some fields are added. The logging support mono value fields as well as multivalue fields via the use of JSON array. --- src/output-json-email-common.c | 114 +++++++++++++++++++++++++++++++++ src/output-json-email-common.h | 3 + src/output-json-smtp.c | 2 + 3 files changed, 119 insertions(+) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index f7553460e348..acbf78d08fe7 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -55,6 +55,79 @@ #ifdef HAVE_LIBJANSSON #include +#define LOG_EMAIL_DEFAULT 0 +#define LOG_EMAIL_EXTENDED 1 +#define LOG_EMAIL_ARRAY 2 /* require array handling */ + +struct { + char *config_field; + char *email_field; + uint32_t flags; +} email_fields[] = { + { "reply_to", "reply-to", LOG_EMAIL_DEFAULT }, + { "bcc", "bcc", LOG_EMAIL_DEFAULT }, + { "message_id", "message-id", LOG_EMAIL_EXTENDED }, + { "x_mailer", "x-mailer", LOG_EMAIL_EXTENDED }, + { "user_agent", "user-agent", LOG_EMAIL_EXTENDED }, + { "received", "received", LOG_EMAIL_ARRAY }, + { "x_originating_ip", "x-originating-ip", LOG_EMAIL_DEFAULT }, + { "relays", "relays", LOG_EMAIL_ARRAY }, + { NULL, NULL, LOG_EMAIL_DEFAULT}, +}; + +static int JsonEmailAddToJsonArray(const uint8_t *val, size_t len, void *data) +{ + json_t *ajs = data; + + if (ajs == NULL) + return 0; + char *value = BytesToString((uint8_t *)val, len); + json_array_append_new(ajs, json_string(value)); + SCFree(value); + return 1; +} + +static void JsonEmailLogJSONCustom(OutputJsonEmailCtx *email_ctx, json_t *js, SMTPTransaction *tx) +{ + int f = 0; + MimeDecField *field; + MimeDecEntity *entity = tx->msg_tail; + if (entity == NULL) { + return; + } + + while(email_fields[f].config_field) { + if (((email_ctx->fields & (1ULL<flags & LOG_EMAIL_EXTENDED) && (email_fields[f].flags & LOG_EMAIL_EXTENDED)) + ) { + if (email_fields[f].flags & LOG_EMAIL_ARRAY) { + json_t *ajs = json_array(); + if (ajs) { + int found = MimeDecFindFieldsForEach(entity, email_fields[f].email_field, JsonEmailAddToJsonArray, ajs); + if (found > 0) { + json_object_set_new(js, email_fields[f].config_field, ajs); + } else { + json_decref(ajs); + } + } + } else { + field = MimeDecFindField(entity, email_fields[f].email_field); + if (field != NULL) { + char *s = BytesToString((uint8_t *)field->value, + (size_t)field->value_len); + if (likely(s != NULL)) { + json_object_set_new(js, email_fields[f].config_field, json_string(s)); + SCFree(s); + } + } + } + + } + f++; + } +} + /* JSON format logging */ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_id) { @@ -258,6 +331,11 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) { json_t *sjs = JsonEmailLogJsonData(f, state, vtx, tx_id); + OutputJsonEmailCtx *email_ctx = aft->emaillog_ctx; + SMTPTransaction *tx = (SMTPTransaction *) vtx; + + if ((email_ctx->flags & LOG_EMAIL_EXTENDED) || (email_ctx->fields != 0)) + JsonEmailLogJSONCustom(email_ctx, sjs, tx); if (sjs) { json_object_set_new(js, "email", sjs); @@ -282,4 +360,40 @@ json_t *JsonEmailAddMetadata(const Flow *f) } +void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx) +{ + if (conf) { + const char *extended = ConfNodeLookupChildValue(conf, "extended"); + + if (extended != NULL) { + if (ConfValIsTrue(extended)) { + email_ctx->flags = LOG_EMAIL_EXTENDED; + } + } + + ConfNode *custom; + if ((custom = ConfNodeLookupChild(conf, "custom")) != NULL) { + ConfNode *field; + TAILQ_FOREACH(field, &custom->head, next) { + if (field != NULL) { + int f = 0; + while(email_fields[f].config_field) { + if ((strcmp(email_fields[f].config_field, + field->val) == 0) || + (strcasecmp(email_fields[f].email_field, + field->val) == 0)) + { + email_ctx->fields |= (1ULL<file_ctx = ojc->file_ctx; + OutputEmailInitConf(conf, email_ctx); + output_ctx->data = email_ctx; output_ctx->DeInit = OutputSmtpLogDeInitCtxSub; From a7ef0c05ba28f8d41776ebc1411d9a9e4cc7faf7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 4 May 2015 17:35:27 +0200 Subject: [PATCH 0767/2553] email-json: add LOG_EMAIL_COMMA type extract these data types by treating them as a comma separated list. --- src/output-json-email-common.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index acbf78d08fe7..bf3214463d25 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -56,8 +56,9 @@ #include #define LOG_EMAIL_DEFAULT 0 -#define LOG_EMAIL_EXTENDED 1 -#define LOG_EMAIL_ARRAY 2 /* require array handling */ +#define LOG_EMAIL_EXTENDED (1<<0) +#define LOG_EMAIL_ARRAY (1<<1) /* require array handling */ +#define LOG_EMAIL_COMMA (1<<2) /* require array handling */ struct { char *config_field; @@ -65,7 +66,7 @@ struct { uint32_t flags; } email_fields[] = { { "reply_to", "reply-to", LOG_EMAIL_DEFAULT }, - { "bcc", "bcc", LOG_EMAIL_DEFAULT }, + { "bcc", "bcc", LOG_EMAIL_COMMA }, { "message_id", "message-id", LOG_EMAIL_EXTENDED }, { "x_mailer", "x-mailer", LOG_EMAIL_EXTENDED }, { "user_agent", "user-agent", LOG_EMAIL_EXTENDED }, @@ -75,6 +76,24 @@ struct { { NULL, NULL, LOG_EMAIL_DEFAULT}, }; +static json_t* JsonEmailJsonArrayFromCommaList(const uint8_t *val, size_t len) +{ + json_t *ajs = json_array(); + if (likely(ajs != NULL)) { + char *savep = NULL; + char *p; + char *to_line = BytesToString((uint8_t *)val, len); + p = strtok_r(to_line, ",", &savep); + json_array_append_new(ajs, json_string(p)); + while ((p = strtok_r(NULL, ",", &savep)) != NULL) { + json_array_append_new(ajs, json_string(&p[strspn(p, " ")])); + } + SCFree(to_line); + } + + return ajs; +} + static int JsonEmailAddToJsonArray(const uint8_t *val, size_t len, void *data) { json_t *ajs = data; @@ -111,6 +130,14 @@ static void JsonEmailLogJSONCustom(OutputJsonEmailCtx *email_ctx, json_t *js, SM json_decref(ajs); } } + } else if (email_fields[f].flags & LOG_EMAIL_COMMA) { + field = MimeDecFindField(entity, email_fields[f].email_field); + if (field) { + json_t *ajs = JsonEmailJsonArrayFromCommaList(field->value, field->value_len); + if (ajs) { + json_object_set_new(js, email_fields[f].config_field, ajs); + } + } } else { field = MimeDecFindField(entity, email_fields[f].email_field); if (field != NULL) { From 4c0f8803e7e4b9848af1c2e2a976ca4dbf66909f Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 4 May 2015 17:42:33 +0200 Subject: [PATCH 0768/2553] email-json: factorize the code --- src/output-json-email-common.c | 56 ++++++++-------------------------- 1 file changed, 13 insertions(+), 43 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index bf3214463d25..d539308a9846 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -83,12 +83,14 @@ static json_t* JsonEmailJsonArrayFromCommaList(const uint8_t *val, size_t len) char *savep = NULL; char *p; char *to_line = BytesToString((uint8_t *)val, len); - p = strtok_r(to_line, ",", &savep); - json_array_append_new(ajs, json_string(p)); - while ((p = strtok_r(NULL, ",", &savep)) != NULL) { - json_array_append_new(ajs, json_string(&p[strspn(p, " ")])); + if (likely(to_line != NULL)) { + p = strtok_r(to_line, ",", &savep); + json_array_append_new(ajs, json_string(p)); + while ((p = strtok_r(NULL, ",", &savep)) != NULL) { + json_array_append_new(ajs, json_string(&p[strspn(p, " ")])); + } + SCFree(to_line); } - SCFree(to_line); } return ajs; @@ -224,52 +226,20 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ } /* To: */ - char *to_line = NULL; field = MimeDecFindField(entity, "to"); if (field != NULL) { - json_t *js_to = json_array(); - if (likely(js_to != NULL)) { - to_line = BytesToString((uint8_t *)field->value, - (size_t)field->value_len); - if (likely(to_line != NULL)) { - char *savep = NULL; - char *p; - //printf("to_line:: TO: \"%s\" (%d)\n", to_line, strlen(to_line)); - p = strtok_r(to_line, ",", &savep); - //printf("got another addr: \"%s\"\n", p); - json_array_append_new(js_to, json_string(p)); - while ((p = strtok_r(NULL, ",", &savep)) != NULL) { - //printf("got another addr: \"%s\"\n", p); - json_array_append_new(js_to, json_string(&p[strspn(p, " ")])); - } - SCFree(to_line); - } - json_object_set_new(sjs, "to", js_to); + json_t *ajs = JsonEmailJsonArrayFromCommaList(field->value, field->value_len); + if (ajs) { + json_object_set_new(sjs, "to", ajs); } } /* Cc: */ - char *cc_line = NULL; field = MimeDecFindField(entity, "cc"); if (field != NULL) { - json_t *js_cc = json_array(); - if (likely(js_cc != NULL)) { - cc_line = BytesToString((uint8_t *)field->value, - (size_t)field->value_len); - if (likely(cc_line != NULL)) { - char *savep = NULL; - char *p; - //printf("cc_line:: CC: \"%s\" (%d)\n", to_line, strlen(to_line)); - p = strtok_r(cc_line, ",", &savep); - //printf("got another addr: \"%s\"\n", p); - json_array_append_new(js_cc, json_string(p)); - while ((p = strtok_r(NULL, ",", &savep)) != NULL) { - //printf("got another addr: \"%s\"\n", p); - json_array_append_new(js_cc, json_string(&p[strspn(p, " ")])); - } - SCFree(cc_line); - } - json_object_set_new(sjs, "cc", js_cc); + json_t *ajs = JsonEmailJsonArrayFromCommaList(field->value, field->value_len); + if (ajs) { + json_object_set_new(sjs, "cc", ajs); } } From abcaf46193474dc4a1acc6984da1318570c16d58 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 4 May 2015 18:11:37 +0200 Subject: [PATCH 0769/2553] email-json: delete leading white spaces Some mail clients are using tabulation and/or space for comma separated list. This patch removes them so the event will contain only significative characters. --- src/output-json-email-common.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index d539308a9846..533ce17ade4c 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -76,21 +76,41 @@ struct { { NULL, NULL, LOG_EMAIL_DEFAULT}, }; +static inline char *SkipWhiteSpaceTill(char *p, char *savep) +{ + char *sp = p; + if (unlikely(p == NULL)) { + return NULL; + } + while (((*sp == '\t') || (*sp == ' ')) && (sp < savep)) { + sp++; + } + return sp; +} + static json_t* JsonEmailJsonArrayFromCommaList(const uint8_t *val, size_t len) { json_t *ajs = json_array(); if (likely(ajs != NULL)) { char *savep = NULL; char *p; + char *sp; char *to_line = BytesToString((uint8_t *)val, len); if (likely(to_line != NULL)) { p = strtok_r(to_line, ",", &savep); - json_array_append_new(ajs, json_string(p)); + if (p == NULL) { + json_decref(ajs); + SCFree(to_line); + return NULL; + } + sp = SkipWhiteSpaceTill(p, savep); + json_array_append_new(ajs, json_string(sp)); while ((p = strtok_r(NULL, ",", &savep)) != NULL) { - json_array_append_new(ajs, json_string(&p[strspn(p, " ")])); + sp = SkipWhiteSpaceTill(p, savep); + json_array_append_new(ajs, json_string(sp)); } - SCFree(to_line); } + SCFree(to_line); } return ajs; From 431dc155aa8cfec8df96b7caa5140e26ab27fa25 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 4 May 2015 18:14:03 +0200 Subject: [PATCH 0770/2553] email-json: delete white space from "from" The From field is handled separatly and it could also starts by white spaces. --- src/output-json-email-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 533ce17ade4c..ecbd273a2f8e 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -240,7 +240,8 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ (size_t)field->value_len); if (likely(s != NULL)) { //printf("From: \"%s\"\n", s); - json_object_set_new(sjs, "from", json_string(s)); + char * sp = SkipWhiteSpaceTill(s, s + strlen(s)); + json_object_set_new(sjs, "from", json_string(sp)); SCFree(s); } } From 7bb38f7c301741deedd4945c04500e4707746951 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 5 May 2015 10:16:10 +0200 Subject: [PATCH 0771/2553] decode-mime: fix typo in comment --- src/util-decode-mime.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h index 5fb4cdb75d3e..c5a2892e5244 100644 --- a/src/util-decode-mime.h +++ b/src/util-decode-mime.h @@ -64,7 +64,7 @@ #define ANOM_MALFORMED_MSG 64 /* Misc msg format errors found */ #define ANOM_LONG_BOUNDARY 128 /* Boundary too long */ -/* Pubicly exposed size constants */ +/* Publicly exposed size constants */ #define DATA_CHUNK_SIZE 3072 /* Should be divisible by 3 */ #define LINEREM_SIZE 256 From 881aa3efce7e12530d606057ba2d99b35a8ddeab Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 5 May 2015 10:32:16 +0200 Subject: [PATCH 0772/2553] email-json: don't log subject by default It seems to be a bit too intrusive for the privacy so this patch adds this field to the extended logging only. --- src/output-json-email-common.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index ecbd273a2f8e..84294c45b03e 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -68,6 +68,7 @@ struct { { "reply_to", "reply-to", LOG_EMAIL_DEFAULT }, { "bcc", "bcc", LOG_EMAIL_COMMA }, { "message_id", "message-id", LOG_EMAIL_EXTENDED }, + { "subject", "subject", LOG_EMAIL_EXTENDED }, { "x_mailer", "x-mailer", LOG_EMAIL_EXTENDED }, { "user_agent", "user-agent", LOG_EMAIL_EXTENDED }, { "received", "received", LOG_EMAIL_ARRAY }, @@ -264,17 +265,6 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ } } - /* Subject: */ - field = MimeDecFindField(entity, "subject"); - if (field != NULL) { - char *s = BytesToString((uint8_t *)field->value, (size_t) field->value_len); - if (likely(s != NULL)) { - //printf("Subject: \"%s\"\n", s); - json_object_set_new(sjs, "subject", json_string(s)); - SCFree(s); - } - } - entity->header_flags |= HDR_IS_LOGGED; if (mime_state->stack == NULL || mime_state->stack->top == NULL || mime_state->stack->top->data == NULL) From a719ea3c928e0e4c961713c8b6dca72b0abd99a7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 5 May 2015 11:55:46 +0200 Subject: [PATCH 0773/2553] email-json: add capa to display subject md5 To be able to identify mails with identical subjects without using the subject itself as a key, it is possible to use the md5 hash of the subjet string. This allows to limit the privacy impact. --- src/output-json-email-common.c | 60 +++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 84294c45b03e..fae43a2e9aa5 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -55,10 +55,12 @@ #ifdef HAVE_LIBJANSSON #include -#define LOG_EMAIL_DEFAULT 0 -#define LOG_EMAIL_EXTENDED (1<<0) -#define LOG_EMAIL_ARRAY (1<<1) /* require array handling */ -#define LOG_EMAIL_COMMA (1<<2) /* require array handling */ +#define LOG_EMAIL_DEFAULT 0 +#define LOG_EMAIL_EXTENDED (1<<0) +#define LOG_EMAIL_ARRAY (1<<1) /* require array handling */ +#define LOG_EMAIL_COMMA (1<<2) /* require array handling */ +#define LOG_EMAIL_BODY_MD5 (1<<3) +#define LOG_EMAIL_SUBJECT_MD5 (1<<4) struct { char *config_field; @@ -117,6 +119,35 @@ static json_t* JsonEmailJsonArrayFromCommaList(const uint8_t *val, size_t len) return ajs; } + +#ifdef HAVE_NSS +static void JsonEmailLogJSONMd5(OutputJsonEmailCtx *email_ctx, json_t *js, SMTPTransaction *tx) +{ + if (email_ctx->flags & LOG_EMAIL_SUBJECT_MD5) { + MimeDecField *field; + MimeDecEntity *entity = tx->msg_tail; + if (entity == NULL) { + return; + } + field = MimeDecFindField(entity, "subject"); + if (field != NULL) { + unsigned char md5[MD5_LENGTH]; + char smd5[2 * MD5_LENGTH + 1]; + char *value = BytesToString((uint8_t *)field->value , field->value_len); + if (value) { + size_t i,x; + HASH_HashBuf(HASH_AlgMD5, md5, (unsigned char *)value, strlen(value)); + for (i = 0, x = 0; x < sizeof(md5); x++) { + i += snprintf(smd5 + i, 255-i, "%02x", md5[x]); + } + json_object_set_new(js, "subject_md5", json_string(smd5)); + SCFree(value); + } + } + } +} +#endif + static int JsonEmailAddToJsonArray(const uint8_t *val, size_t len, void *data) { json_t *ajs = data; @@ -345,6 +376,10 @@ TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, F if ((email_ctx->flags & LOG_EMAIL_EXTENDED) || (email_ctx->fields != 0)) JsonEmailLogJSONCustom(email_ctx, sjs, tx); +#ifdef HAVE_NSS + JsonEmailLogJSONMd5(email_ctx, sjs, tx); +#endif + if (sjs) { json_object_set_new(js, "email", sjs); SCReturnInt(TM_ECODE_OK); @@ -399,6 +434,23 @@ void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx) } } } + + ConfNode *md5_conf; + if ((md5_conf = ConfNodeLookupChild(conf, "md5")) != NULL) { + ConfNode *field; + TAILQ_FOREACH(field, &md5_conf->head, next) { + if (field != NULL) { + if (strcmp("body", field->val) == 0) { + SCLogInfo("Going to log email body md5"); + email_ctx->flags |= LOG_EMAIL_BODY_MD5; + } + if (strcmp("subject", field->val) == 0) { + SCLogInfo("Going to log email subject md5"); + email_ctx->flags |= LOG_EMAIL_SUBJECT_MD5; + } + } + } + } } return; } From ca52fa91dd7e03a23dd417c19480db079182ad67 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 5 May 2015 15:16:35 +0200 Subject: [PATCH 0774/2553] email-json: body md5 logging is optional --- src/output-json-email-common.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index fae43a2e9aa5..080151589c14 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -145,6 +145,21 @@ static void JsonEmailLogJSONMd5(OutputJsonEmailCtx *email_ctx, json_t *js, SMTPT } } } + + if (email_ctx->flags & LOG_EMAIL_BODY_MD5) { + MimeDecParseState *mime_state = tx->mime_state; + if (mime_state && mime_state->md5_ctx && (mime_state->state_flag == PARSE_DONE)) { + size_t x; + int i; + char s[256]; + if (likely(s != NULL)) { + for (i = 0, x = 0; x < sizeof(mime_state->md5); x++) { + i += snprintf(s + i, 255-i, "%02x", mime_state->md5[x]); + } + json_object_set_new(js, "body_md5", json_string(s)); + } + } + } } #endif @@ -244,20 +259,6 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ SCReturnPtr(NULL, "json_t"); } -#ifdef HAVE_NSS - if (mime_state->md5_ctx && (mime_state->state_flag == PARSE_DONE)) { - size_t x; - int i; - char s[256]; - if (likely(s != NULL)) { - for (i = 0, x = 0; x < sizeof(mime_state->md5); x++) { - i += snprintf(s + i, 255-i, "%02x", mime_state->md5[x]); - } - json_object_set_new(sjs, "body_md5", json_string(s)); - } - } -#endif - json_object_set_new(sjs, "status", json_string(MimeDecParseStateGetStatus(mime_state))); From caa8982b4324c7e63cd7f72afb4208257bdec1d1 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 7 May 2015 11:38:15 +0200 Subject: [PATCH 0775/2553] email-json: add some fields This patch adds some fields to the list of extracted fields. --- src/output-json-email-common.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 080151589c14..d05ecea14169 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -75,7 +75,13 @@ struct { { "user_agent", "user-agent", LOG_EMAIL_EXTENDED }, { "received", "received", LOG_EMAIL_ARRAY }, { "x_originating_ip", "x-originating-ip", LOG_EMAIL_DEFAULT }, - { "relays", "relays", LOG_EMAIL_ARRAY }, + { "in_reply_to", "in-reply-to", LOG_EMAIL_DEFAULT }, + { "references", "references", LOG_EMAIL_DEFAULT }, + { "importance", "importance", LOG_EMAIL_DEFAULT }, + { "priority", "priority", LOG_EMAIL_DEFAULT }, + { "sensitivity", "sensitivity", LOG_EMAIL_DEFAULT }, + { "organization", "organization", LOG_EMAIL_DEFAULT }, + { "content_md5", "content-md5", LOG_EMAIL_DEFAULT }, { NULL, NULL, LOG_EMAIL_DEFAULT}, }; From d1b0a5aa6d6368c40c347b2fde8ddfacded1cc53 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 5 May 2015 14:20:13 +0200 Subject: [PATCH 0776/2553] yaml: document new MIME features --- suricata.yaml.in | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 56d4d3628f37..3833a973f2a4 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -139,7 +139,18 @@ outputs: force-md5: no # force logging of md5 checksums #- drop: # alerts: no # log alerts that caused drops - - smtp + - smtp: + #extended: yes + # custom fields logging from the list: + # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, + # x-originating-ip, in-reply-to, references, importance, priority, + # sensitivity, organization, content-md5 + #custom: [received, x-mailer, x-originating-ip, relays, reply-to, bcc] + # output md5 of fields: body, subject + # for the body you need to set app-layer.protocols.smtp.mime.body-md5 + # to yes + #md5: [body, subject] + - ssh - stats: totals: yes # stats for all threads merged together @@ -1291,6 +1302,9 @@ app-layer: # Extract URLs and save in state data structure extract-urls: yes + # Set to yes to compute the md5 of the mail body. You will then + # be able to journalize it. + body-md5: no # Configure inspected-tracker for file_data keyword inspected-tracker: content-limit: 1000 From dad1f85edb59406a00164e6533c31ca12253b790 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 7 May 2015 14:44:14 +0200 Subject: [PATCH 0777/2553] email-json: add author Add myself as author and change the copyright date. --- src/output-json-email-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index d05ecea14169..12e91f3ef396 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation +/* Copyright (C) 2007-2015 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 @@ -19,6 +19,7 @@ * \file * * \author Tom DeCanio + * \author Eric Leblond * * Implements json common email logging portion of the engine. */ From 6e0668125c16b729106ee5b5e4bda69135c5cf7d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 7 May 2015 14:52:12 +0200 Subject: [PATCH 0778/2553] email-json: improve log message --- src/output-json-email-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 12e91f3ef396..7af0b70bbd04 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -449,11 +449,11 @@ void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx) TAILQ_FOREACH(field, &md5_conf->head, next) { if (field != NULL) { if (strcmp("body", field->val) == 0) { - SCLogInfo("Going to log email body md5"); + SCLogInfo("Going to log the md5 sum of email body"); email_ctx->flags |= LOG_EMAIL_BODY_MD5; } if (strcmp("subject", field->val) == 0) { - SCLogInfo("Going to log email subject md5"); + SCLogInfo("Going to log the md5 sum of email subject"); email_ctx->flags |= LOG_EMAIL_SUBJECT_MD5; } } From 17edff6c5e7cb4f5d41da8d17737681a3879ba71 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 12 May 2015 16:50:16 +0200 Subject: [PATCH 0779/2553] unittests: finally register MIME tests --- src/runmode-unittests.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 4f3fc8bf7dc1..3701d29af785 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -277,6 +277,7 @@ void RunUnittests(int list_unittests, char *regex_arg) CudaBufferRegisterUnittests(); #endif AppLayerUnittestsRegister(); + MimeDecRegisterTests(); if (list_unittests) { UtListTests(regex_arg); } else { From 6f033747ec7853d048683acb743ba124ad9d15d6 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 12 May 2015 16:52:12 +0200 Subject: [PATCH 0780/2553] util-decode-mime: add unittests for field fetching --- src/util-decode-mime.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 8a36b26aaa25..292da4a0958b 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -2821,6 +2821,54 @@ static int MimeDecParseFullMsgTest01(void) return ret; } +/* Test full message with linebreaks */ +static int MimeDecParseFullMsgTest02(void) +{ + int ret = MIME_DEC_OK; + + uint32_t expected_count = 3; + uint32_t line_count = 0; + + char msg[] = "From: Sender2\r\n" + "To: Recipient2\r\n" + "Subject: subject2\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Line 1\r\n" + "Line 2\r\n" + "Line 3\r\n"; + + MimeDecEntity *entity = MimeDecParseFullMsg((uint8_t *)msg, strlen(msg), &line_count, + TestDataChunkCallback); + + if (entity == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return -1; + } + + MimeDecField *field = MimeDecFindField(entity, "subject"); + if (field == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return -1; + } + + if (memcmp(field->value, "subject2", sizeof("subject2")) != 0) { + SCLogInfo("Warning: failed to get subject"); + return -1; + } + + + MimeDecFreeEntity(entity); + + if (expected_count != line_count) { + SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", + expected_count, line_count); + return -1; + } + + return ret; +} + static int MimeBase64DecodeTest01(void) { int ret = -1; @@ -2938,6 +2986,7 @@ void MimeDecRegisterTests(void) UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01, 0); UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02, 0); UtRegisterTest("MimeDecParseFullMsgTest01", MimeDecParseFullMsgTest01, 0); + UtRegisterTest("MimeDecParseFullMsgTest02", MimeDecParseFullMsgTest02, 0); UtRegisterTest("MimeBase64DecodeTest01", MimeBase64DecodeTest01, 0); UtRegisterTest("MimeIsExeURLTest01", MimeIsExeURLTest01, 0); UtRegisterTest("MimeIsIpv4HostTest01", MimeIsIpv4HostTest01, 0); From f81f353d1f75a790dc84a200aa25a2fe38e142bc Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 12 May 2015 16:53:20 +0200 Subject: [PATCH 0781/2553] email-json: add 'date' field extraction --- src/output-json-email-common.c | 1 + suricata.yaml.in | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 7af0b70bbd04..30b8c62fa756 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -83,6 +83,7 @@ struct { { "sensitivity", "sensitivity", LOG_EMAIL_DEFAULT }, { "organization", "organization", LOG_EMAIL_DEFAULT }, { "content_md5", "content-md5", LOG_EMAIL_DEFAULT }, + { "date", "date", LOG_EMAIL_DEFAULT }, { NULL, NULL, LOG_EMAIL_DEFAULT}, }; diff --git a/suricata.yaml.in b/suricata.yaml.in index 3833a973f2a4..07a7d7947bb1 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -144,7 +144,7 @@ outputs: # custom fields logging from the list: # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, # x-originating-ip, in-reply-to, references, importance, priority, - # sensitivity, organization, content-md5 + # sensitivity, organization, content-md5, date #custom: [received, x-mailer, x-originating-ip, relays, reply-to, bcc] # output md5 of fields: body, subject # for the body you need to set app-layer.protocols.smtp.mime.body-md5 From 8fd88f543d43ad0f291fc02bf04c40b6676ed03e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 12 May 2015 16:55:49 +0200 Subject: [PATCH 0782/2553] yaml: add comment describing smtp extended --- suricata.yaml.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 07a7d7947bb1..bdc54279cdb2 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -140,7 +140,8 @@ outputs: #- drop: # alerts: no # log alerts that caused drops - smtp: - #extended: yes + #extended: yes # enable this for extended logging information + # this includes: message-id, subject, x_mailer, user-agent # custom fields logging from the list: # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, # x-originating-ip, in-reply-to, references, importance, priority, From 534360fc0202c66d8877c5c8b55dbee5ead320b8 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 12 May 2015 17:31:56 +0200 Subject: [PATCH 0783/2553] smtp-layer: add HELO parsing test in unittest --- src/app-layer-smtp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 139533468f9c..d95bc73896c5 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -4494,6 +4494,13 @@ int SMTPParserTest14(void) SCMutexUnlock(&f.m); goto end; } + + if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) { + printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || From fbd6428f1bb082b35b24c9b1e4715c2a2ce8128f Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 12 May 2015 17:56:59 +0200 Subject: [PATCH 0784/2553] smtp-layer: add MAIL FROM parsing test in unittest --- src/app-layer-smtp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index d95bc73896c5..0731442ac458 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -4538,6 +4538,16 @@ int SMTPParserTest14(void) SCMutexUnlock(&f.m); goto end; } + + if ((smtp_state->curr_tx->mail_from_len != 14) || + strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) { + printf("incorrect parsing of MAIL FROM field '%s' (%d)\n", + smtp_state->curr_tx->mail_from, + smtp_state->curr_tx->mail_from_len); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || From 946f2a6acc4541e92584d2db628d940f2e1a2e39 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 20 May 2015 10:23:36 +0200 Subject: [PATCH 0785/2553] email-json: add bcc to extended fields --- src/output-json-email-common.c | 2 +- suricata.yaml.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 30b8c62fa756..b255a8e4933b 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -69,7 +69,7 @@ struct { uint32_t flags; } email_fields[] = { { "reply_to", "reply-to", LOG_EMAIL_DEFAULT }, - { "bcc", "bcc", LOG_EMAIL_COMMA }, + { "bcc", "bcc", LOG_EMAIL_COMMA|LOG_EMAIL_EXTENDED }, { "message_id", "message-id", LOG_EMAIL_EXTENDED }, { "subject", "subject", LOG_EMAIL_EXTENDED }, { "x_mailer", "x-mailer", LOG_EMAIL_EXTENDED }, diff --git a/suricata.yaml.in b/suricata.yaml.in index bdc54279cdb2..7767620cda92 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -141,7 +141,7 @@ outputs: # alerts: no # log alerts that caused drops - smtp: #extended: yes # enable this for extended logging information - # this includes: message-id, subject, x_mailer, user-agent + # this includes: bcc, message-id, subject, x_mailer, user-agent # custom fields logging from the list: # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, # x-originating-ip, in-reply-to, references, importance, priority, From 77a5273cdef1bf067fddacd8ba5f34e21a2ed333 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 13 Sep 2015 19:07:34 +0200 Subject: [PATCH 0786/2553] json-smtp: fix a debug message --- src/output-json-smtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 2d5860da97cd..9d1f8599e8a9 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -227,7 +227,7 @@ static TmEcode JsonSmtpLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for SMTPLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } From f03a7a032f09d6d4e822319ff73ed3b5e708549f Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 13 Sep 2015 19:08:52 +0200 Subject: [PATCH 0787/2553] json-alert: add smtp elements in alert --- src/output-json-alert.c | 24 ++++++++++++++++++++++++ suricata.yaml.in | 1 + 2 files changed, 25 insertions(+) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index e357d2c9d9ee..61780075f529 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -54,6 +54,7 @@ #include "output-json-http.h" #include "output-json-tls.h" #include "output-json-ssh.h" +#include "output-json-smtp.h" #include "util-byte.h" #include "util-privs.h" @@ -74,6 +75,7 @@ #define LOG_JSON_HTTP 8 #define LOG_JSON_TLS 16 #define LOG_JSON_SSH 32 +#define LOG_JSON_SMTP 64 #define JSON_STREAM_BUFFER_SIZE 4096 @@ -237,6 +239,22 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } } + if (json_output_ctx->flags & LOG_JSON_SMTP) { + if (p->flow != NULL) { + FLOWLOCK_RDLOCK(p->flow); + uint16_t proto = FlowGetAppProtocol(p->flow); + + /* http alert */ + if (proto == ALPROTO_SMTP) { + hjs = JsonSMTPAddMetadata(p->flow); + if (hjs) + json_object_set_new(js, "smtp", hjs); + } + + FLOWLOCK_UNLOCK(p->flow); + } + } + /* payload */ if (json_output_ctx->flags & (LOG_JSON_PAYLOAD | LOG_JSON_PAYLOAD_BASE64)) { int stream = (p->proto == IPPROTO_TCP) ? @@ -586,6 +604,7 @@ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) const char *http = ConfNodeLookupChildValue(conf, "http"); const char *tls = ConfNodeLookupChildValue(conf, "tls"); const char *ssh = ConfNodeLookupChildValue(conf, "ssh"); + const char *smtp = ConfNodeLookupChildValue(conf, "smtp"); if (ssh != NULL) { if (ConfValIsTrue(ssh)) { @@ -602,6 +621,11 @@ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) json_output_ctx->flags |= LOG_JSON_HTTP; } } + if (smtp != NULL) { + if (ConfValIsTrue(smtp)) { + json_output_ctx->flags |= LOG_JSON_SMTP; + } + } if (payload_printable != NULL) { if (ConfValIsTrue(payload_printable)) { json_output_ctx->flags |= LOG_JSON_PAYLOAD; diff --git a/suricata.yaml.in b/suricata.yaml.in index 7767620cda92..e0b5538c4e86 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -108,6 +108,7 @@ outputs: # http: yes # enable dumping of http fields # tls: yes # enable dumping of tls fields # ssh: yes # enable dumping of ssh fields + # smtp: yes # enable dumping of smtp fields # HTTP X-Forwarded-For support by adding an extra field or overwriting # the source or destination IP address (depending on flow direction) From 0ef0f1d526386d3aa85cd5dd5683d326c2aef1b1 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 14 Sep 2015 11:38:39 +0200 Subject: [PATCH 0788/2553] json-smtp: change copyright date --- src/output-json-smtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 9d1f8599e8a9..dd9d60d90a27 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2015 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 From d9b602fc0f243b4ed42e70aa2cf7f8a0060613d8 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 14 Sep 2015 11:39:19 +0200 Subject: [PATCH 0789/2553] json-smtp: add tx_id param to metadata generation In all metadata generation contexts we know the tx_id so we better used it to log the correct transaction and not an other one. --- src/output-json-alert.c | 2 +- src/output-json-file.c | 2 +- src/output-json-smtp.c | 3 +-- src/output-json-smtp.h | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 61780075f529..b5c624e2b25b 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -246,7 +246,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) /* http alert */ if (proto == ALPROTO_SMTP) { - hjs = JsonSMTPAddMetadata(p->flow); + hjs = JsonSMTPAddMetadata(p->flow, pa->tx_id); if (hjs) json_object_set_new(js, "smtp", hjs); } diff --git a/src/output-json-file.c b/src/output-json-file.c index 615ae596e86c..09ee96790734 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -99,7 +99,7 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F json_object_set_new(js, "http", hjs); break; case ALPROTO_SMTP: - hjs = JsonSMTPAddMetadata(p->flow); + hjs = JsonSMTPAddMetadata(p->flow, ff->txid); if (hjs) json_object_set_new(js, "smtp", hjs); hjs = JsonEmailAddMetadata(p->flow); diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index dd9d60d90a27..be5275de1769 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -117,11 +117,10 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl } -json_t *JsonSMTPAddMetadata(const Flow *f) +json_t *JsonSMTPAddMetadata(const Flow *f, uint64_t tx_id) { SMTPState *smtp_state = (SMTPState *)FlowGetAppState(f); if (smtp_state) { - uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, smtp_state, tx_id); if (tx) { diff --git a/src/output-json-smtp.h b/src/output-json-smtp.h index 5b3233abca9f..2f79d992011a 100644 --- a/src/output-json-smtp.h +++ b/src/output-json-smtp.h @@ -26,7 +26,7 @@ void TmModuleJsonSmtpLogRegister (void); #ifdef HAVE_LIBJANSSON -json_t *JsonSMTPAddMetadata(const Flow *f); +json_t *JsonSMTPAddMetadata(const Flow *f, uint64_t tx_id); #endif #endif /* __OUTPUT_JSON_SMTP_H__ */ From bf6b0145e2758784643576312bff8d33bf730ceb Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 15 Sep 2015 09:36:00 +0200 Subject: [PATCH 0790/2553] json-http: gen metadata function with tx_id param --- src/output-json-alert.c | 2 +- src/output-json-file.c | 2 +- src/output-json-http.c | 3 +-- src/output-json-http.h | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index b5c624e2b25b..ce216ddaadc4 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -204,7 +204,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) /* http alert */ if (proto == ALPROTO_HTTP) { - hjs = JsonHttpAddMetadata(p->flow); + hjs = JsonHttpAddMetadata(p->flow, pa->tx_id); if (hjs) json_object_set_new(js, "http", hjs); } diff --git a/src/output-json-file.c b/src/output-json-file.c index 09ee96790734..b13852bd1621 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -94,7 +94,7 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F switch (p->flow->alproto) { case ALPROTO_HTTP: - hjs = JsonHttpAddMetadata(p->flow); + hjs = JsonHttpAddMetadata(p->flow, ff->txid); if (hjs) json_object_set_new(js, "http", hjs); break; diff --git a/src/output-json-http.c b/src/output-json-http.c index bf926b2adf94..6cfed78ca324 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -396,11 +396,10 @@ static int JsonHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl SCReturnInt(TM_ECODE_OK); } -json_t *JsonHttpAddMetadata(const Flow *f) +json_t *JsonHttpAddMetadata(const Flow *f, uint64_t tx_id) { HtpState *htp_state = (HtpState *)FlowGetAppState(f); if (htp_state) { - uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, tx_id); if (tx) { diff --git a/src/output-json-http.h b/src/output-json-http.h index b8fcea15be0e..0c886f3dd56d 100644 --- a/src/output-json-http.h +++ b/src/output-json-http.h @@ -29,7 +29,7 @@ void TmModuleJsonHttpLogRegister (void); #ifdef HAVE_LIBJANSSON void JsonHttpLogJSONBasic(json_t *js, htp_tx_t *tx); void JsonHttpLogJSONExtended(json_t *js, htp_tx_t *tx); -json_t *JsonHttpAddMetadata(const Flow *f); +json_t *JsonHttpAddMetadata(const Flow *f, uint64_t tx_id); #endif /* HAVE_LIBJANSSON */ #endif /* __OUTPUT_JSON_HTTP_H__ */ From 96412e8921b6c145ddc8bf06551a6e8abfb4d79d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 15 Sep 2015 15:48:19 +0200 Subject: [PATCH 0791/2553] json-email: JsonEmailAddMetadata update Add tx_id to the list of params to be in sync with recent changes. --- src/output-json-alert.c | 7 ++++++- src/output-json-email-common.c | 3 +-- src/output-json-email-common.h | 2 +- src/output-json-file.c | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index ce216ddaadc4..6be573054e50 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -48,6 +48,7 @@ #include "app-layer-htp-xff.h" #include "util-classification-config.h" #include "util-syslog.h" +#include "util-logopenfile.h" #include "output.h" #include "output-json.h" @@ -55,6 +56,7 @@ #include "output-json-tls.h" #include "output-json-ssh.h" #include "output-json-smtp.h" +#include "output-json-email-common.h" #include "util-byte.h" #include "util-privs.h" @@ -62,7 +64,6 @@ #include "util-proto-name.h" #include "util-optimize.h" #include "util-buffer.h" -#include "util-logopenfile.h" #include "util-crypt.h" #define MODULE_NAME "JsonAlertLog" @@ -249,6 +250,10 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) hjs = JsonSMTPAddMetadata(p->flow, pa->tx_id); if (hjs) json_object_set_new(js, "smtp", hjs); + + hjs = JsonEmailAddMetadata(p->flow, pa->tx_id); + if (hjs) + json_object_set_new(js, "email", hjs); } FLOWLOCK_UNLOCK(p->flow); diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index b255a8e4933b..d54b7b4d028e 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -396,11 +396,10 @@ TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, F SCReturnInt(TM_ECODE_FAILED); } -json_t *JsonEmailAddMetadata(const Flow *f) +json_t *JsonEmailAddMetadata(const Flow *f, uint32_t tx_id) { SMTPState *smtp_state = (SMTPState *)FlowGetAppState(f); if (smtp_state) { - uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, smtp_state, tx_id); if (tx) { diff --git a/src/output-json-email-common.h b/src/output-json-email-common.h index afb3b91bfc16..88cfa5576b03 100644 --- a/src/output-json-email-common.h +++ b/src/output-json-email-common.h @@ -38,7 +38,7 @@ typedef struct JsonEmailLogThread_ { } JsonEmailLogThread; TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id); -json_t *JsonEmailAddMetadata(const Flow *f); +json_t *JsonEmailAddMetadata(const Flow *f, uint32_t tx_id); #endif void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx); diff --git a/src/output-json-file.c b/src/output-json-file.c index b13852bd1621..f2f21df34bde 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -102,7 +102,7 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F hjs = JsonSMTPAddMetadata(p->flow, ff->txid); if (hjs) json_object_set_new(js, "smtp", hjs); - hjs = JsonEmailAddMetadata(p->flow); + hjs = JsonEmailAddMetadata(p->flow, ff->txid); if (hjs) json_object_set_new(js, "email", hjs); break; From 113d6a395020396d9d29e0ff7cb796caa85f9bc9 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 15 Sep 2015 16:34:44 +0200 Subject: [PATCH 0792/2553] output-json: add create header with tx function To be able to correlate between events, it is better to have the tx_id information in the root object. This function adds a new function to automate the addition of the field. --- src/output-json.c | 12 ++++++++++++ src/output-json.h | 1 + 2 files changed, 13 insertions(+) diff --git a/src/output-json.c b/src/output-json.c index 74289f1b5854..a8e5456351d1 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -327,6 +327,18 @@ json_t *CreateJSONHeader(Packet *p, int direction_sensitive, char *event_type) return js; } +json_t *CreateJSONHeaderWithTxId(Packet *p, int direction_sensitive, char *event_type, uint32_t tx_id) +{ + json_t *js = CreateJSONHeader(p, direction_sensitive, event_type); + if (unlikely(js == NULL)) + return NULL; + + /* tx id for correlation with other events */ + json_object_set_new(js, "tx_id", json_integer(tx_id)); + + return js; +} + int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) { char *js_s = json_dumps(js, diff --git a/src/output-json.h b/src/output-json.h index 1acde3e67792..15c2829555c2 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -35,6 +35,7 @@ void TmModuleOutputJsonRegister (void); void CreateJSONFlowId(json_t *js, const Flow *f); void JsonTcpFlags(uint8_t flags, json_t *js); json_t *CreateJSONHeader(Packet *p, int direction_sensative, char *event_type); +json_t *CreateJSONHeaderWithTxId(Packet *p, int direction_sensitive, char *event_type, uint32_t tx_id); TmEcode OutputJSON(json_t *js, void *data, uint64_t *count); int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer); OutputCtx *OutputJsonInitCtx(ConfNode *); From 6f04988ba125ab6885340f1baa1eda0c06299104 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 15 Sep 2015 16:36:37 +0200 Subject: [PATCH 0793/2553] output-json: add tx_id to events This patch updates alert, stmp and http JSON logging to have a tx_id in the root of the JSON log message. --- src/output-json-alert.c | 8 +++++--- src/output-json-http.c | 5 +---- src/output-json-smtp.c | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 6be573054e50..2c0d01714c7f 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -146,6 +146,11 @@ void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js) action = "blocked"; } + /* Add tx_id to root element for correlation with other events. */ + json_object_del(js, "tx_id"); + if (pa->flags & PACKET_ALERT_FLAG_TX) + json_object_set_new(js, "tx_id", json_integer(pa->tx_id)); + json_t *ajs = json_object(); if (ajs == NULL) { json_decref(js); @@ -162,9 +167,6 @@ void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js) json_string((pa->s->class_msg) ? pa->s->class_msg : "")); json_object_set_new(ajs, "severity", json_integer(pa->s->prio)); - if (pa->flags & PACKET_ALERT_FLAG_TX) - json_object_set_new(ajs, "tx_id", json_integer(pa->tx_id)); - if (p->tenant_id > 0) json_object_set_new(ajs, "tenant_id", json_integer(p->tenant_id)); diff --git a/src/output-json-http.c b/src/output-json-http.c index 6cfed78ca324..6873987305ce 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -362,9 +362,6 @@ static void JsonHttpLogJSON(JsonHttpLogThread *aft, json_t *js, htp_tx_t *tx, ui if (http_ctx->flags & LOG_HTTP_EXTENDED) JsonHttpLogJSONExtended(hjs, tx); - /* tx id for correlation with alerts */ - json_object_set_new(hjs, "tx_id", json_integer(tx_id)); - json_object_set_new(js, "http", hjs); } @@ -376,7 +373,7 @@ static int JsonHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl JsonHttpLogThread *jhl = (JsonHttpLogThread *)thread_data; MemBuffer *buffer = (MemBuffer *)jhl->buffer; - json_t *js = CreateJSONHeader((Packet *)p, 1, "http"); //TODO const + json_t *js = CreateJSONHeaderWithTxId((Packet *)p, 1, "http", tx_id); //TODO const if (unlikely(js == NULL)) return TM_ECODE_OK; diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index be5275de1769..617b7247f379 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -90,7 +90,7 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl MemBuffer *buffer = (MemBuffer *)jhl->buffer; json_t *sjs; - json_t *js = CreateJSONHeader((Packet *)p, 1, "smtp"); + json_t *js = CreateJSONHeaderWithTxId((Packet *)p, 1, "smtp", tx_id); if (unlikely(js == NULL)) return TM_ECODE_OK; From 38750f1313ba4cbda20fb84adf99fe618ecab2fc Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 23 Sep 2015 13:54:38 +0200 Subject: [PATCH 0794/2553] smtp-layer: remove FIXME and del excessive newline --- src/app-layer-smtp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 0731442ac458..a7f54d6f095f 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -985,7 +985,6 @@ static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8 spc_i++; } - /* FIXME check arithmetic */ *target = SCMalloc(spc_i - i + 1); if (*target == NULL) return -1; @@ -994,7 +993,6 @@ static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8 *target_len = spc_i - i; return 0; - } static int SMTPParseCommandHELO(SMTPState *state) From dbb3e1976e417c3b1346e17b747f2ebd41328328 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 23 Sep 2015 14:47:40 +0200 Subject: [PATCH 0795/2553] util-decode-mime: fix IsIpv6Host function Using in6_addr is better when calling inet_pton. This fixes an issue reported by ASAN. --- src/util-decode-mime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 292da4a0958b..38850c78af1e 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -942,7 +942,7 @@ static int IsIpv4Host(const uint8_t *urlhost, uint32_t len) */ static int IsIpv6Host(const uint8_t *urlhost, uint32_t len) { - struct sockaddr_in sa; + struct in6_addr in6; char tempIp[MAX_IP6_CHARS + 1]; /* Cut off at '/' */ @@ -963,7 +963,7 @@ static int IsIpv6Host(const uint8_t *urlhost, uint32_t len) memcpy(tempIp, urlhost, i); tempIp[i] = '\0'; - return inet_pton(AF_INET6, tempIp, &(sa.sin_addr)); + return inet_pton(AF_INET6, tempIp, &in6); } /** From 53419b93c861b948890bb2ac12e13982e72ae726 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 23 Sep 2015 14:49:03 +0200 Subject: [PATCH 0796/2553] util-decode-mime: fix some unittests Unittests were failling when ASAN is activated because it was finding some read outside of bounds. This patch fixes the different reported issues. --- src/util-decode-mime.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 38850c78af1e..6eee1a6a09b3 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -2852,7 +2852,12 @@ static int MimeDecParseFullMsgTest02(void) return -1; } - if (memcmp(field->value, "subject2", sizeof("subject2")) != 0) { + if (field->value_len != sizeof("subject2") - 1) { + SCLogInfo("Warning: failed to get subject"); + return -1; + } + + if (memcmp(field->value, "subject2", field->value_len) != 0) { SCLogInfo("Warning: failed to get subject"); return -1; } @@ -2878,7 +2883,7 @@ static int MimeBase64DecodeTest01(void) char *base64msg = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QU" "VJTVFVWV1hZWjEyMzQ1Njc4OTBAIyQlXiYqKCktPV8rLC4vOydbXTw+Pzo="; - uint8_t *dst = SCMalloc(strlen(msg)-1); + uint8_t *dst = SCMalloc(strlen(msg) + 1); if (dst == NULL) return 0; @@ -2888,6 +2893,8 @@ static int MimeBase64DecodeTest01(void) ret = 0; } + SCFree(dst); + return ret; } From 2ecab3f76523e9078afe1fc425b5972520680dda Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 2 Oct 2015 23:40:54 +0200 Subject: [PATCH 0797/2553] decode-mime: fix body md5 computation Previous code was wrongly supposing the lines are ending with CRLF. But this is not the case so we must propagate the length of end of line delimiter to be able to compute the md5 of the mail body. --- src/app-layer-smtp.c | 3 +- src/util-decode-mime.c | 65 +++++++++++++++++++++--------------------- src/util-decode-mime.h | 3 +- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index a7f54d6f095f..0c161edb591b 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -813,7 +813,8 @@ static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, if (smtp_config.decode_mime && state->curr_tx->mime_state) { int ret = MimeDecParseLine((const uint8_t *) state->current_line, - state->current_line_len, state->curr_tx->mime_state); + state->current_line_len, state->current_line_delimiter_len, + state->curr_tx->mime_state); if (ret != MIME_DEC_OK) { SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret); } diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 6eee1a6a09b3..51d1468e5538 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -2040,6 +2040,13 @@ static int ProcessBodyComplete(MimeDecParseState *state) } } +#ifdef HAVE_NSS + if (state->md5_ctx) { + unsigned int len = 0; + HASH_End(state->md5_ctx, state->md5, &len, sizeof(state->md5)); + } +#endif + /* Invoke pre-processor and callback with remaining data */ ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); if (ret != MIME_DEC_OK) { @@ -2209,12 +2216,14 @@ static int ProcessMimeBody(const uint8_t *buf, uint32_t len, uint32_t tlen; #ifdef HAVE_NSS - if (MimeDecGetConfig()->body_md5 && state->body_begin == 1 && (state->md5_ctx == NULL)) { - state->md5_ctx = HASH_Create(HASH_AlgMD5); - if (state->md5_ctx != NULL) { - HASH_Begin(state->md5_ctx); - HASH_Update(state->md5_ctx, buf, len + 2); /* plus 2 to add CRLF */ + if (MimeDecGetConfig()->body_md5) { + if (state->body_begin == 1) { + if (state->md5_ctx == NULL) { + state->md5_ctx = HASH_Create(HASH_AlgMD5); + HASH_Begin(state->md5_ctx); + } } + HASH_Update(state->md5_ctx, buf, len + state->current_line_delimiter_len); } #endif @@ -2474,13 +2483,6 @@ int MimeDecParseComplete(MimeDecParseState *state) return ret; } -#ifdef HAVE_NSS - if (state->md5_ctx) { - unsigned int len = 0; - HASH_End(state->md5_ctx, state->md5, &len, sizeof(state->md5)); - } -#endif - if (state->stack->top == NULL) { state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; SCLogDebug("Error: Message is malformed"); @@ -2513,12 +2515,13 @@ int MimeDecParseComplete(MimeDecParseState *state) * * \param line A string representing the line (w/out CRLF) * \param len The length of the line + * \param delim_len The length of the line end delimiter * \param state The parser state * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ int MimeDecParseLine(const uint8_t *line, const uint32_t len, - MimeDecParseState *state) + const uint8_t delim_len, MimeDecParseState *state) { int ret = MIME_DEC_OK; @@ -2529,11 +2532,7 @@ int MimeDecParseLine(const uint8_t *line, const uint32_t len, SCLogDebug("SMTP LINE - EMPTY"); } -#ifdef HAVE_NSS - if (state->md5_ctx) { - HASH_Update(state->md5_ctx, line, len + 2); - } -#endif + state->current_line_delimiter_len = delim_len; /* Process the entity */ ret = ProcessMimeEntity(line, len, state); if (ret != MIME_DEC_OK) { @@ -2581,8 +2580,10 @@ MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *dat line = tok; + state->current_line_delimiter_len = (remainPtr - tok) - tokLen; /* Parse the line */ - ret = MimeDecParseLine(line, tokLen, state); + ret = MimeDecParseLine(line, tokLen, + (remainPtr - tok) - tokLen, state); if (ret != MIME_DEC_OK) { SCLogDebug("Error: MimeDecParseLine() function failed: %d", ret); @@ -2669,25 +2670,25 @@ static int MimeDecParseLineTest01(void) TestDataChunkCallback); char *str = "From: Sender1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "To: Recipient1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "Content-Type: text/plain"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = ""; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "A simple message line 1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "A simple message line 2"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "A simple message line 3"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); if (ret != MIME_DEC_OK) { return ret; @@ -2737,23 +2738,23 @@ static int MimeDecParseLineTest02(void) TestDataChunkCallback); char *str = "From: Sender1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "To: Recipient1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "Content-Type: text/plain"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = ""; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "A simple message line 1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "A simple message line 2 click on http://www.test.com/malware.exe?" "hahah hopefully you click this link"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); if (ret != MIME_DEC_OK) { return ret; diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h index c5a2892e5244..536c3a0a246a 100644 --- a/src/util-decode-mime.h +++ b/src/util-decode-mime.h @@ -207,6 +207,7 @@ typedef struct MimeDecParseState { int found_child; /**< Flag indicating a child entity was found */ int body_begin; /**< Currently at beginning of body */ int body_end; /**< Currently at end of body */ + uint8_t current_line_delimiter_len; /**< Length of line delimiter */ void *data; /**< Pointer to data specific to the caller */ int (*DataChunkProcessorFunc) (const uint8_t *chunk, uint32_t len, struct MimeDecParseState *state); /**< Data chunk processing function callback */ @@ -236,7 +237,7 @@ MimeDecParseState * MimeDecInitParser(void *data, int (*dcpfunc)(const uint8_t * uint32_t len, MimeDecParseState *state)); void MimeDecDeInitParser(MimeDecParseState *state); int MimeDecParseComplete(MimeDecParseState *state); -int MimeDecParseLine(const uint8_t *line, const uint32_t len, MimeDecParseState *state); +int MimeDecParseLine(const uint8_t *line, const uint32_t len, const uint8_t delim_len, MimeDecParseState *state); MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); const char *MimeDecParseStateGetStatus(MimeDecParseState *state); From e634fcee60d0c67394743e1f00720b7dc7217a20 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 30 Sep 2015 10:42:26 +0200 Subject: [PATCH 0798/2553] lua: TLS lua output support Support TLS in lua output scripts (Feature #1568). function init (args) local needs = {} needs["protocol"] = "tls" return needs end function setup (args) filename = SCLogPath() .. "/" .. "lua_tls.log" file = assert(io.open(filename, "a")) end function log (args) ts = SCPacketTimeString() ipver, srcip, dstip, proto, sp, dp = SCFlowTuple() version, subject, issuer, fingerprint = TlsGetCertInfo(); if version == nil then return 0 end file:write(ts .. " " .. srcip .. ":" .. sp .. " -> " .. dstip .. ":" .. dp .. " TLS: " .. "Subject='" .. subject .. "' " .. "Issuerdn='" .. issuer .. "\n") file:flush() end function deinit (args) file:close(file) end --- src/app-layer-ssl.h | 2 ++ src/output-lua.c | 88 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 5c6fe5b153b5..2fc1a9699bde 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -81,6 +81,8 @@ enum { /* flags for file storage */ #define SSL_AL_FLAG_STATE_STORED 0x40000 +#define SSL_AL_FLAG_STATE_LOGGED_LUA 0x80000 + /* config flags */ #define SSL_TLS_LOG_PEM (1 << 0) diff --git a/src/output-lua.c b/src/output-lua.c index fc5a562164fe..0d6e4e8add50 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -40,6 +40,7 @@ #include "output.h" #include "app-layer-htp.h" #include "app-layer.h" +#include "app-layer-ssl.h" #include "app-layer-parser.h" #include "util-privs.h" #include "util-buffer.h" @@ -57,6 +58,7 @@ #include "util-lua-common.h" #include "util-lua-http.h" #include "util-lua-dns.h" +#include "util-lua-tls.h" #define MODULE_NAME "LuaLog" @@ -228,6 +230,86 @@ static int LuaPacketConditionAlerts(ThreadVars *tv, const Packet *p) return FALSE; } +/** \internal + * \brief Packet Logger for lua scripts, for tls + * + * A single call to this function will run one script for a single + * packet. If it is called, it means that the registered condition + * function has returned TRUE. + * + * The script is called once for each packet. + */ +static int LuaPacketLoggerTls(ThreadVars *tv, void *thread_data, const Packet *p) +{ + LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data; + + char timebuf[64]; + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + + SCMutexLock(&td->lua_ctx->m); + + lua_getglobal(td->lua_ctx->luastate, "log"); + + LuaStateSetThreadVars(td->lua_ctx->luastate, tv); + LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); + LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* unlocked */LUA_FLOW_NOT_LOCKED_BY_PARENT); + + int retval = lua_pcall(td->lua_ctx->luastate, 0, 0, 0); + if (retval != 0) { + SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1)); + } + + SCMutexUnlock(&td->lua_ctx->m); + FLOWLOCK_WRLOCK(p->flow); + + SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + if (ssl_state != NULL) + ssl_state->flags |= SSL_AL_FLAG_STATE_LOGGED_LUA; + + FLOWLOCK_UNLOCK(p->flow); + SCReturnInt(0); +} + +static int LuaPacketConditionTls(ThreadVars *tv, const Packet *p) +{ + if (p->flow == NULL) { + return FALSE; + } + + if (!(PKT_IS_IPV4(p)) && !(PKT_IS_IPV6(p))) { + return FALSE; + } + + if (!(PKT_IS_TCP(p))) { + return FALSE; + } + + FLOWLOCK_RDLOCK(p->flow); + uint16_t proto = FlowGetAppProtocol(p->flow); + if (proto != ALPROTO_TLS) + goto dontlog; + + SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + if (ssl_state == NULL) { + SCLogDebug("no tls state, so no request logging"); + goto dontlog; + } + + if (ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) + goto dontlog; + + /* We only log the state once */ + if (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED_LUA) + goto dontlog; + + FLOWLOCK_UNLOCK(p->flow); + return TRUE; +dontlog: + FLOWLOCK_UNLOCK(p->flow); + return FALSE; +} + /** \internal * \brief Packet Logger for lua scripts, for packets * @@ -517,6 +599,8 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { options->alproto = ALPROTO_HTTP; else if (strcmp(k,"protocol") == 0 && strcmp(v, "dns") == 0) options->alproto = ALPROTO_DNS; + else if (strcmp(k,"protocol") == 0 && strcmp(v, "tls") == 0) + options->alproto = ALPROTO_TLS; else if (strcmp(k, "type") == 0 && strcmp(v, "packet") == 0) options->packet = 1; else if (strcmp(k, "filter") == 0 && strcmp(v, "alerts") == 0) @@ -617,6 +701,7 @@ static lua_State *LuaScriptSetup(const char *filename) * if the tx is registered in the state at runtime though. */ LuaRegisterHttpFunctions(luastate); LuaRegisterDnsFunctions(luastate); + LuaRegisterTlsFunctions(luastate); if (lua_pcall(luastate, 0, 0, 0) != 0) { SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'setup' function: %s", lua_tostring(luastate, -1)); @@ -760,6 +845,9 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_HTTP; AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP); + } else if (opts.alproto == ALPROTO_TLS) { + om->PacketLogFunc = LuaPacketLoggerTls; + om->PacketConditionFunc = LuaPacketConditionTls; } else if (opts.alproto == ALPROTO_DNS) { om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_DNS; From 437fe40660d97f7507fdf4e6ad9e33b2d9a13cd2 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Tue, 29 Sep 2015 00:08:55 +0300 Subject: [PATCH 0799/2553] Feature 1527: ability to compile as a position independent executable Adds corresponding configure option which enables proper CPPFLAGS and LDFLAGS. --- configure.ac | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/configure.ac b/configure.ac index ab2df12bc642..97ce3ab1742f 100644 --- a/configure.ac +++ b/configure.ac @@ -1693,6 +1693,16 @@ enable_geoip="yes" fi + # Position Independent Executable + AC_ARG_ENABLE(pie, + AS_HELP_STRING([--enable-pie],[Enable compiling as a position independent executable]), + [ enable_pie="yes"], + [ enable_pie="no"]) + if test "$enable_pie" = "yes"; then + CPPFLAGS="${CPPFLAGS} -fPIC" + LDFLAGS="${LDFLAGS} -pie" + fi + # get cache line size AC_PATH_PROG(HAVE_GETCONF_CMD, getconf, "no") if test "$HAVE_GETCONF_CMD" != "no"; then @@ -1832,6 +1842,7 @@ Generic build parameters: GCC Protect enabled: ${enable_gccprotect} GCC march native enabled: ${enable_gccmarch_native} GCC Profile enabled: ${enable_gccprofile} + Position Independent Executable enabled: ${enable_pie} CFLAGS ${CFLAGS} PCAP_CFLAGS ${PCAP_CFLAGS} SECCFLAGS ${SECCFLAGS}" From 3e29a232087ddac825d1779eae23accbafbade10 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Sun, 27 Sep 2015 22:03:12 +0300 Subject: [PATCH 0800/2553] unix-manager: log client (dis)connection with DEBUG level. Also select/receive errors are logged as ERROR. --- src/unix-manager.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index 1960df569943..9357f4c50453 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -356,7 +356,7 @@ int UnixCommandAccept(UnixCommand *this) json_decref(server_msg); /* client connected */ - SCLogInfo("Unix socket: client connected"); + SCLogDebug("Unix socket: client connected"); uclient = SCMalloc(sizeof(UnixClient)); if (unlikely(uclient == NULL)) { @@ -478,9 +478,9 @@ void UnixCommandRun(UnixCommand * this, UnixClient *client) ret = recv(client->fd, buffer, sizeof(buffer) - 1, 0); if (ret <= 0) { if (ret == 0) { - SCLogInfo("Unix socket: lost connection with client"); + SCLogDebug("Unix socket: lost connection with client"); } else { - SCLogInfo("Unix socket: error on recv() from client: %s", + SCLogError(SC_ERR_SOCKET, "Unix socket: error on recv() from client: %s", strerror(errno)); } UnixCommandClose(this, client->fd); @@ -525,7 +525,7 @@ int UnixMain(UnixCommand * this) if (errno == EINTR) { return 1; } - SCLogInfo("Command server: select() fatal error: %s", strerror(errno)); + SCLogError(SC_ERR_SOCKET, "Command server: select() fatal error: %s", strerror(errno)); return 0; } From ed400acf8e946404bbc0634df153bf155dcae345 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 18 Jun 2015 14:18:49 -0600 Subject: [PATCH 0801/2553] defrag: unit test for tracker reuse (current fails) Will be fixed in subsequent commits as tracker reuse is fixed. --- src/defrag.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/defrag.c b/src/defrag.c index 7418b93c665f..6f0260e3ef0b 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -2328,6 +2328,70 @@ DefragVlanQinQTest(void) return ret; } +static int DefragTrackerReuseTest(void) +{ + int ret = 0; + int id = 1; + Packet *p1 = NULL; + DefragTracker *tracker1 = NULL, *tracker2 = NULL; + + DefragInit(); + + /* Build a packet, its not a fragment but shouldn't matter for + * this test. */ + p1 = BuildTestPacket(id, 0, 0, 'A', 8); + if (p1 == NULL) { + goto end; + } + + /* Get a tracker. It shouldn't look like its already in use. */ + tracker1 = DefragGetTracker(NULL, NULL, p1); + if (tracker1 == NULL) { + goto end; + } + if (tracker1->seen_last) { + goto end; + } + if (tracker1->remove) { + goto end; + } + DefragTrackerRelease(tracker1); + + /* Get a tracker again, it should be the same one. */ + tracker2 = DefragGetTracker(NULL, NULL, p1); + if (tracker2 == NULL) { + goto end; + } + if (tracker2 != tracker1) { + goto end; + } + DefragTrackerRelease(tracker1); + + /* Now mark the tracker for removal. It should not be returned + * when we get a tracker for a packet that may have the same + * attributes. */ + tracker1->remove = 1; + + tracker2 = DefragGetTracker(NULL, NULL, p1); + if (tracker2 == NULL) { + goto end; + } + if (tracker2 == tracker1) { + goto end; + } + if (tracker2->remove) { + goto end; + } + + ret = 1; +end: + if (p1 != NULL) { + SCFree(p1); + } + DefragDestroy(); + return ret; +} + #endif /* UNITTESTS */ void @@ -2374,6 +2438,8 @@ DefragRegisterTests(void) UtRegisterTest("DefragVlanTest", DefragVlanTest, 1); UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest, 1); + UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest, 1); + UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest, 1); #endif /* UNITTESTS */ From 69b4218afc9bf1888d3ab34ff305e05f7b6eb7bb Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 15 Jun 2015 11:06:50 -0600 Subject: [PATCH 0802/2553] defrag: don't use trackers marked for removal These trackers are likely for completed fragments, but have not been cleaned up. If a packet on the same flow with an already seen IP ID is seen, it could be reused prior to being properly reinitialized. --- src/defrag-hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defrag-hash.c b/src/defrag-hash.c index 9cb377e5b3f2..be2fd456ac84 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -526,7 +526,7 @@ DefragTracker *DefragGetTrackerFromHash (Packet *p) dt = hb->head; /* see if this is the tracker we are looking for */ - if (DefragTrackerCompare(dt, p) == 0) { + if (dt->remove || DefragTrackerCompare(dt, p) == 0) { DefragTracker *pdt = NULL; /* previous tracker */ while (dt) { From 3aa7e38c14b0c0d04913f4c68bfa013f6567367c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 15 Jun 2015 11:14:16 -0600 Subject: [PATCH 0803/2553] defrag: tracker initialization cleanup Remove the old tracker reset macro which is no longer being used. Clear last_seen and remove flags on initialization. Remove extra call to DefragTrackerInit as it was being called 2x for each new tracker. Now that DefragTrackerNew is just a wrapper for DefragTrackerAlloc, remove it and just call DefragTrackerAlloc directly. --- src/defrag-hash.c | 17 +++-------------- src/defrag.h | 14 -------------- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/src/defrag-hash.c b/src/defrag-hash.c index be2fd456ac84..e37a08738d85 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -96,24 +96,13 @@ static void DefragTrackerInit(DefragTracker *dt, Packet *p) dt->vlan_id[1] = p->vlan_id[1]; dt->policy = DefragGetOsPolicy(p); dt->host_timeout = DefragPolicyGetHostTimeout(p); + dt->remove = 0; + dt->seen_last = 0; TAILQ_INIT(&dt->frags); (void) DefragTrackerIncrUsecnt(dt); } -static DefragTracker *DefragTrackerNew(Packet *p) -{ - DefragTracker *dt = DefragTrackerAlloc(); - if (dt == NULL) - goto error; - - DefragTrackerInit(dt, p); - return dt; - -error: - return NULL; -} - void DefragTrackerRelease(DefragTracker *t) { (void) DefragTrackerDecrUsecnt(t); @@ -467,7 +456,7 @@ static DefragTracker *DefragTrackerGetNew(Packet *p) /* freed a tracker, but it's unlocked */ } else { /* now see if we can alloc a new tracker */ - dt = DefragTrackerNew(p); + dt = DefragTrackerAlloc(); if (dt == NULL) { return NULL; } diff --git a/src/defrag.h b/src/defrag.h index 8bd0325a341f..2dfaec60cf30 100644 --- a/src/defrag.h +++ b/src/defrag.h @@ -71,20 +71,6 @@ typedef struct Frag_ { TAILQ_ENTRY(Frag_) next; /**< Pointer to next fragment for tailq. */ } Frag; -/** \brief Reset tracker fields except "lock" */ -#define DEFRAG_TRACKER_RESET(t) { \ - (t)->timeout = 0; \ - (t)->id = 0; \ - (t)->policy = 0; \ - (t)->af = 0; \ - (t)->seen_last = 0; \ - (t)->remove = 0; \ - CLEAR_ADDR(&(t)->src_addr); \ - CLEAR_ADDR(&(t)->dst_addr); \ - (t)->frags.tqh_first = NULL; \ - (t)->frags.tqh_last = NULL; \ -} - /** * A defragmentation tracker. Used to track fragments that make up a * single packet. From 6f223c6dba2f62550ad6bece750d4dded2041858 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 27 Aug 2015 13:59:30 -0600 Subject: [PATCH 0804/2553] defrag: stop reassembly at the first packet with more flags not set --- src/defrag.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) diff --git a/src/defrag.c b/src/defrag.c index 6f0260e3ef0b..956fe7ded4da 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -337,6 +337,10 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (frag->offset + frag->data_len > fragmentable_len) fragmentable_len = frag->offset + frag->data_len; } + + if (!frag->more_frags) { + break; + } } SCLogDebug("ip_hdr_offset %u, hlen %u, fragmentable_len %u", @@ -460,6 +464,10 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (frag->offset + frag->data_len > fragmentable_len) fragmentable_len = frag->offset + frag->data_len; } + + if (!frag->more_frags) { + break; + } } rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset); @@ -747,6 +755,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, new->data_len = data_len - ltrim; new->ip_hdr_offset = ip_hdr_offset; new->frag_hdr_offset = frag_hdr_offset; + new->more_frags = more_frags; #ifdef DEBUG new->pcap_cnt = pcap_cnt; #endif @@ -2392,6 +2401,132 @@ static int DefragTrackerReuseTest(void) return ret; } +/** + * IPV4: Test the case where you have a packet fragmented in 3 parts + * and send like: + * - Offset: 2; MF: 1 + * - Offset: 0; MF: 1 + * - Offset: 1; MF: 0 + * + * Only the fragments with offset 0 and 1 should be reassembled. + */ +static int DefragMfIpv4Test(void) +{ + int retval = 0; + int ip_id = 9; + + DefragInit(); + + Packet *p1 = BuildTestPacket(ip_id, 2, 1, 'C', 8); + Packet *p2 = BuildTestPacket(ip_id, 0, 1, 'A', 8); + Packet *p3 = BuildTestPacket(ip_id, 1, 0, 'B', 8); + if (p1 == NULL || p2 == NULL || p3 == NULL) { + goto end; + } + + Packet *p = Defrag(NULL, NULL, p1, NULL); + if (p != NULL) { + goto end; + } + + p = Defrag(NULL, NULL, p2, NULL); + if (p != NULL) { + goto end; + } + + /* This should return a packet as MF=0. */ + p = Defrag(NULL, NULL, p3, NULL); + if (p == NULL) { + goto end; + } + + /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the + * fragments should be in the re-assembled packet. */ + if (IPV4_GET_IPLEN(p) != 36) { + goto end; + } + + retval = 1; +end: + if (p1 != NULL) { + SCFree(p1); + } + if (p2 != NULL) { + SCFree(p2); + } + if (p3 != NULL) { + SCFree(p3); + } + if (p != NULL) { + SCFree(p); + } + DefragDestroy(); + return retval; +} + +/** + * IPV6: Test the case where you have a packet fragmented in 3 parts + * and send like: + * - Offset: 2; MF: 1 + * - Offset: 0; MF: 1 + * - Offset: 1; MF: 0 + * + * Only the fragments with offset 0 and 1 should be reassembled. + */ +static int DefragMfIpv6Test(void) +{ + int retval = 0; + int ip_id = 9; + + DefragInit(); + + Packet *p1 = IPV6BuildTestPacket(ip_id, 2, 1, 'C', 8); + Packet *p2 = IPV6BuildTestPacket(ip_id, 0, 1, 'A', 8); + Packet *p3 = IPV6BuildTestPacket(ip_id, 1, 0, 'B', 8); + if (p1 == NULL || p2 == NULL || p3 == NULL) { + goto end; + } + + Packet *p = Defrag(NULL, NULL, p1, NULL); + if (p != NULL) { + goto end; + } + + p = Defrag(NULL, NULL, p2, NULL); + if (p != NULL) { + goto end; + } + + /* This should return a packet as MF=0. */ + p = Defrag(NULL, NULL, p3, NULL); + if (p == NULL) { + goto end; + } + + /* For IPv6 the expected length is just the length of the payload + * of 2 fragments, so 16. */ + if (IPV6_GET_PLEN(p) != 16) { + goto end; + } + + retval = 1; +end: + if (p1 != NULL) { + SCFree(p1); + } + if (p2 != NULL) { + SCFree(p2); + } + if (p3 != NULL) { + SCFree(p3); + } + if (p != NULL) { + SCFree(p); + } + DefragDestroy(); + return retval; +} + #endif /* UNITTESTS */ void @@ -2437,11 +2572,11 @@ DefragRegisterTests(void) UtRegisterTest("DefragVlanTest", DefragVlanTest, 1); UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest, 1); - UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest, 1); - UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest, 1); + UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test, 1); + UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test, 1); #endif /* UNITTESTS */ } From 4d83318b464143b29e1e2632d94b3c1c2b5cc487 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 24 Sep 2015 12:24:15 +0200 Subject: [PATCH 0805/2553] defrag tests: fix compiler warnings defrag.c:2423:9: error: variable 'p' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:5: note: remove the 'if' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2423:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2423:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~ defrag.c:2427:5: note: variable 'p' is declared here Packet *p = Defrag(NULL, NULL, p1, NULL); ^ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:5: note: remove the 'if' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~ defrag.c:2490:5: note: variable 'p' is declared here Packet *p = Defrag(NULL, NULL, p1, NULL); ^ 6 errors generated. make[3]: *** [defrag.o] Error 1 --- src/defrag.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/defrag.c b/src/defrag.c index 956fe7ded4da..1d86c44868bf 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -2414,6 +2414,7 @@ static int DefragMfIpv4Test(void) { int retval = 0; int ip_id = 9; + Packet *p = NULL; DefragInit(); @@ -2424,7 +2425,7 @@ static int DefragMfIpv4Test(void) goto end; } - Packet *p = Defrag(NULL, NULL, p1, NULL); + p = Defrag(NULL, NULL, p1, NULL); if (p != NULL) { goto end; } @@ -2477,6 +2478,7 @@ static int DefragMfIpv6Test(void) { int retval = 0; int ip_id = 9; + Packet *p = NULL; DefragInit(); @@ -2487,7 +2489,7 @@ static int DefragMfIpv6Test(void) goto end; } - Packet *p = Defrag(NULL, NULL, p1, NULL); + p = Defrag(NULL, NULL, p1, NULL); if (p != NULL) { goto end; } From 6572725a7ada11a33906af4e8243781bac556d43 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 24 Sep 2015 14:20:42 +0200 Subject: [PATCH 0806/2553] util-debug: don't colorize if a redirect is used It is better to disable the color mode when a redirect of stderr is done to avoid getting colorized output in the generated file. --- src/util-debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-debug.c b/src/util-debug.c index f1ac0463e505..d9af08c4381a 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -776,7 +776,7 @@ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, } iface_ctx->log_level = tmp_log_level; - if (isatty(fileno(stdout))) { + if (isatty(fileno(stdout)) && isatty(fileno(stderr))) { iface_ctx->use_color = TRUE; } From 4185f3ee9270b51f2e7b0d0a7227029933b79e40 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 22 Sep 2015 13:58:41 -0600 Subject: [PATCH 0807/2553] detect-pcre: allow upper cases metachars for host (/W). Redmine issue 1490. --- src/detect-pcre.c | 95 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 14 deletions(-) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 86f3d169950a..d69f1da6f9de 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -274,6 +274,26 @@ static int DetectPcreSetList(int list, int set) return set; } +static int DetectPcreHasUpperCase(const char *re) +{ + size_t len = strlen(re); + int is_meta = 0; + + for (size_t i = 0; i < len; i++) { + if (is_meta) { + is_meta = 0; + } + else if (re[i] == '\\') { + is_meta = 1; + } + else if (isupper((unsigned char)re[i])) { + return 1; + } + } + + return 0; +} + static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, int *sm_list) { int ec; @@ -290,8 +310,6 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, char re[slen], op_str[64] = ""; uint16_t pos = 0; uint8_t negate = 0; - uint16_t re_len = 0; - uint32_t u = 0; while (pos < slen && isspace((unsigned char)regexstr[pos])) { pos++; @@ -476,18 +494,14 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, "Since the hostname buffer we match against " "is actually lowercase, having a " "nocase is redundant."); - } else { - re_len = strlen(re); - for (u = 0; u < re_len; u++) { - if (isupper((unsigned char)re[u])) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre host(\"W\") " - "specified has an uppercase char. " - "Since the hostname buffer we match against " - "is actually lowercase, please specify an " - "all lowercase based pcre."); - goto error; - } - } + } + else if (DetectPcreHasUpperCase(re)) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre host(\"W\") " + "specified has an uppercase char. " + "Since the hostname buffer we match against " + "is actually lowercase, please specify an " + "all lowercase based pcre."); + goto error; } } @@ -4053,6 +4067,57 @@ static int DetectPcreFlowvarCapture03(void) return result; } +/** + * \brief Test parsing of pcre's with the W modifier set. + */ +static int DetectPcreParseHttpHost(void) +{ + int result = 0; + DetectPcreData *pd = NULL; + int list = DETECT_SM_LIST_NOTSET; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + return 0; + } + + pd = DetectPcreParse(de_ctx, "/domain\\.com/W", &list); + if (pd == NULL) { + goto end; + } + DetectPcreFree(pd); + + list = DETECT_SM_LIST_NOTSET; + pd = DetectPcreParse(de_ctx, "/dOmain\\.com/W", &list); + if (pd != NULL) { + DetectPcreFree(pd); + goto end; + } + + /* Uppercase meta characters are valid. */ + list = DETECT_SM_LIST_NOTSET; + pd = DetectPcreParse(de_ctx, "/domain\\D+\\.com/W", &list); + if (pd == NULL) { + goto end; + } + DetectPcreFree(pd); + + /* This should not parse as the first \ escapes the second \, then + * we have a D. */ + list = DETECT_SM_LIST_NOTSET; + pd = DetectPcreParse(de_ctx, "/\\\\Ddomain\\.com/W", &list); + if (pd != NULL) { + DetectPcreFree(pd); + goto end; + } + + result = 1; + +end: + DetectEngineCtxFree(de_ctx); + return result; +} + #endif /* UNITTESTS */ /** @@ -4121,6 +4186,8 @@ void DetectPcreRegisterTests(void) UtRegisterTest("DetectPcreFlowvarCapture02 -- capture for http_header", DetectPcreFlowvarCapture02, 1); UtRegisterTest("DetectPcreFlowvarCapture03 -- capture for http_header", DetectPcreFlowvarCapture03, 1); + UtRegisterTest("DetectPcreParseHttpHost", DetectPcreParseHttpHost, 1); + #endif /* UNITTESTS */ } From 580728087cd6f3be4a80177b5d1d8624ac1c9ae8 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 20 Apr 2015 15:54:11 -0600 Subject: [PATCH 0808/2553] fix util-host-os-info unit tests. - Some tests always passed due to the result value being initialized to 1. - Fix tests that now fail. Looks like just the test were wrong and that the code does the right thing. --- src/util-host-os-info.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/util-host-os-info.c b/src/util-host-os-info.c index ad0de7e25ad3..f04d6326c76a 100644 --- a/src/util-host-os-info.c +++ b/src/util-host-os-info.c @@ -450,12 +450,12 @@ int SCHInfoTestInvalidIPV4Address02(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "192.168.1.566", SC_HINFO_IS_IPV4) != -1) { goto end; } - if (SCHInfoAddHostOSInfo("linux", "192.168.1", SC_HINFO_IS_IPV4 != -1)) { + if (SCHInfoAddHostOSInfo("linux", "192.168.1", SC_HINFO_IS_IPV4) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "192.", SC_HINFO_IS_IPV4) != -1) { @@ -488,7 +488,7 @@ int SCHInfoTestInvalidIPV6Address03(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "2362:7322", SC_HINFO_IS_IPV6) != -1) { goto end; @@ -530,7 +530,7 @@ int SCHInfoTestValidIPV4Address04(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == -1) { goto end; @@ -643,7 +643,7 @@ int SCHInfoTestValidIPV4Address05(void) SCHInfoCreateContextBackup(); struct in_addr in; - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == -1) { goto end; @@ -783,7 +783,7 @@ int SCHInfoTestValidIPV6Address06(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "2351:2512:6211:6246:235A:6242:2352:62AD", @@ -919,7 +919,7 @@ int SCHInfoTestValidIPV6Address07(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "2351:2512:6211:6246:235A:6242:2352:62AD", @@ -1076,7 +1076,7 @@ int SCHInfoTestValidIPV6Address08(void) SCHInfoCreateContextBackup(); struct in6_addr in6; - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "2351:2512:6211:6246:235A:6242:2352:62AD", @@ -1248,10 +1248,10 @@ int SCHInfoTestValidIPV4Address09(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "192.168.1.0", SC_HINFO_IS_IPV4) == -1) { - goto end; + goto end; } if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { goto end; @@ -1319,22 +1319,26 @@ int SCHInfoTestValidIPV4Address09(void) goto end; } - if (SCHInfoGetHostOSFlavour("192.168.1.100") == + /* 192.168.1.100 should match "macos" as its more specific than + * "solaris". */ + if (SCHInfoGetHostOSFlavour("192.168.1.100") != SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { goto end; } + /* Remove the 192.168.1.0/20 -> macos entry. */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { goto end; } SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 20); - if (SCHInfoGetHostOSFlavour("192.168.1.100") == + if (SCHInfoGetHostOSFlavour("192.168.1.100") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } + /* Remove the 192.168.1.0/16 -> solaris entry. */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { goto end; @@ -1481,7 +1485,7 @@ host-os-policy:\n\ vista: [0.0.0.5]\n\ \n"; - int result = 1; + int result = 0; SCHInfoCreateContextBackup(); @@ -1527,7 +1531,7 @@ host-os-policy:\n\ vista: [0.0.0.5]\n\ \n"; - int result = 1; + int result = 0; SCHInfoCreateContextBackup(); From 413082afc0bedecc0bc0b6e49e12ee3571d59503 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 21 Sep 2015 15:39:37 -0600 Subject: [PATCH 0809/2553] GPL license sync with official gpl-2.0.txt Synced up with: http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt --- COPYING | 39 +++++++++++++++++++-------------------- LICENSE | 14 +++++++------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/COPYING b/COPYING index 5b6e7c66c276..d159169d1050 100644 --- a/COPYING +++ b/COPYING @@ -1,12 +1,12 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -303,10 +303,9 @@ the "copyright" line and a pointer to where the full notice is found. 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 - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. @@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names: This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General +library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. diff --git a/LICENSE b/LICENSE index d511905c1647..d159169d1050 100644 --- a/LICENSE +++ b/LICENSE @@ -1,12 +1,12 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -56,7 +56,7 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - GNU GENERAL PUBLIC LICENSE + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS + END OF TERMS AND CONDITIONS - How to Apply These Terms to Your New Programs + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it From 53bfcf64b7020993dd4d1cb2c2260fb5757e5e8e Mon Sep 17 00:00:00 2001 From: Alessandro Guido Date: Fri, 19 Jun 2015 16:57:48 +0200 Subject: [PATCH 0810/2553] Add option to omit payload in unified2 output Add a boolean option named "payload" to the unified2-alert output type. Such options makes suricata omit the payload in the resulting unified2 file. The default value is true in order to preserve the current behaviour. --- src/alert-unified2-alert.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index ede624c4f3bf..facc66b231a1 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -186,8 +186,11 @@ typedef struct AlertUnified2Packet_ { typedef struct Unified2AlertFileCtx_ { LogFileCtx *file_ctx; HttpXFFCfg *xff_cfg; + uint32_t flags; /**< flags for all alerts */ } Unified2AlertFileCtx; +#define UNIFIED2_ALERT_FLAGS_EMIT_PACKET (1 << 0) + /** * Unified2 thread vars * @@ -698,6 +701,9 @@ static int Unified2PacketTypeAlert(Unified2AlertThread *aun, const Packet *p, ui { int ret = 0; + if (!(aun->unified2alert_ctx->flags & UNIFIED2_ALERT_FLAGS_EMIT_PACKET)) + return 1; + /* try stream logging first */ if (stream) { SCLogDebug("logging the state"); @@ -1299,6 +1305,20 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) } } + uint32_t flags = UNIFIED2_ALERT_FLAGS_EMIT_PACKET; + if (conf != NULL) { + const char *payload = NULL; + payload = ConfNodeLookupChildValue(conf, "payload"); + if (payload) { + if (ConfValIsFalse(payload)) { + flags &= ~UNIFIED2_ALERT_FLAGS_EMIT_PACKET; + } else if (!ConfValIsTrue(payload)) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, invalid payload: %s", payload); + exit(EXIT_FAILURE); + } + } + } + ret = Unified2AlertOpenFileCtx(file_ctx, filename); if (ret < 0) goto error; @@ -1325,6 +1345,7 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) unified2alert_ctx->file_ctx = file_ctx; unified2alert_ctx->xff_cfg = xff_cfg; + unified2alert_ctx->flags = flags; output_ctx->data = unified2alert_ctx; output_ctx->DeInit = Unified2AlertDeInitCtx; From dcbbda505f1abb55739333de0c6c347e30cb5797 Mon Sep 17 00:00:00 2001 From: Alessandro Guido Date: Tue, 8 Sep 2015 11:39:20 +0200 Subject: [PATCH 0811/2553] Describe new unified2-alert "payload" option --- suricata.yaml.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/suricata.yaml.in b/suricata.yaml.in index e0b5538c4e86..9ab40098fdba 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -175,6 +175,10 @@ outputs: # Sensor ID field of unified2 alerts. #sensor-id: 0 + # Include payload of packets related to alerts. Defaults to true, set to + # false if payload is not required. + #payload: yes + # HTTP X-Forwarded-For support by adding the unified2 extra header or # overwriting the source or destination IP address (depending on flow # direction) with the one reported in the X-Forwarded-For HTTP header. From 7eab16c47809f79464ea15d9c349648fc25c5b44 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 2 Oct 2015 09:00:51 +0200 Subject: [PATCH 0812/2553] lua: SSH support Support SSH in lua detection scripts (Feature #1569). --- src/Makefile.am | 1 + src/detect-lua-extensions.c | 2 + src/detect-lua.c | 10 ++ src/util-lua-ssh.c | 227 ++++++++++++++++++++++++++++++++++++ src/util-lua-ssh.h | 33 ++++++ 5 files changed, 273 insertions(+) create mode 100644 src/util-lua-ssh.c create mode 100644 src/util-lua-ssh.h diff --git a/src/Makefile.am b/src/Makefile.am index 674043f5db72..98e094c19afb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -356,6 +356,7 @@ util-lua-common.c util-lua-common.h \ util-lua-dns.c util-lua-dns.h \ util-lua-http.c util-lua-http.h \ util-lua-tls.c util-lua-tls.h \ +util-lua-ssh.c util-lua-ssh.h \ util-magic.c util-magic.h \ util-memcmp.c util-memcmp.h \ util-memcpy.h \ diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index 020c886d9b00..ae9b4e141272 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -67,6 +67,7 @@ #include "util-lua-http.h" #include "util-lua-dns.h" #include "util-lua-tls.h" +#include "util-lua-ssh.h" static const char luaext_key_ld[] = "suricata:luajitdata"; static const char luaext_key_det_ctx[] = "suricata:det_ctx"; @@ -619,6 +620,7 @@ int LuaRegisterExtensions(lua_State *lua_state) LuaRegisterHttpFunctions(lua_state); LuaRegisterDnsFunctions(lua_state); LuaRegisterTlsFunctions(lua_state); + LuaRegisterSshFunctions(lua_state); return 0; } diff --git a/src/detect-lua.c b/src/detect-lua.c index d1f2cd00c2e9..d5da19d81eec 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -166,6 +166,8 @@ void DetectLuaRegister(void) #define DATATYPE_TLS (1<<18) +#define DATATYPE_SSH (1<<19) + #ifdef HAVE_LUAJIT static void *LuaStatePoolAlloc(void) { @@ -1008,6 +1010,12 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) ld->flags |= DATATYPE_TLS; + } else if (strncmp(k, "ssh", 3) == 0 && strcmp(v, "true") == 0) { + + ld->alproto = ALPROTO_SSH; + + ld->flags |= DATATYPE_SSH; + } else { SCLogError(SC_ERR_LUA_ERROR, "unsupported data type %s", k); goto error; @@ -1105,6 +1113,8 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) } } else if (luajit->alproto == ALPROTO_TLS) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + } else if (luajit->alproto == ALPROTO_SSH) { + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); } else { SCLogError(SC_ERR_LUA_ERROR, "luajit can't be used with protocol %s", AppLayerGetProtoName(luajit->alproto)); diff --git a/src/util-lua-ssh.c b/src/util-lua-ssh.c new file mode 100644 index 000000000000..df232c811855 --- /dev/null +++ b/src/util-lua-ssh.c @@ -0,0 +1,227 @@ +/* Copyright (C) 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 Mats Klepsland + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-ssh.h" +#include "util-privs.h" +#include "util-buffer.h" +#include "util-proto-name.h" +#include "util-logopenfile.h" +#include "util-time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" +#include "util-lua-common.h" + +static int GetServerProtoVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SshState *ssh_state = (SshState *)state; + + if (ssh_state->srv_hdr.proto_version == NULL) + return LuaCallbackError(luastate, "error: no server proto version"); + + return LuaPushStringBuffer(luastate, ssh_state->srv_hdr.proto_version, + strlen((char *)ssh_state->srv_hdr.proto_version)); +} + +static int SshGetServerProtoVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + int lock_hint = 0; + Flow *f = LuaStateGetFlow(luastate, &lock_hint); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + FLOWLOCK_RDLOCK(f); + r = GetServerProtoVersion(luastate, f); + FLOWLOCK_UNLOCK(f); + } else { + r = GetServerProtoVersion(luastate, f); + } + return r; +} + +static int GetServerSoftwareVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SshState *ssh_state = (SshState *)state; + + if (ssh_state->srv_hdr.software_version == NULL) + return LuaCallbackError(luastate, "error: no server software version"); + + return LuaPushStringBuffer(luastate, ssh_state->srv_hdr.software_version, + strlen((char *)ssh_state->srv_hdr.software_version)); +} + +static int SshGetServerSoftwareVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + int lock_hint = 0; + Flow *f = LuaStateGetFlow(luastate, &lock_hint); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + FLOWLOCK_RDLOCK(f); + r = GetServerSoftwareVersion(luastate, f); + FLOWLOCK_UNLOCK(f); + } else { + r = GetServerSoftwareVersion(luastate, f); + } + return r; +} + +static int GetClientProtoVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SshState *ssh_state = (SshState *)state; + + if (ssh_state->cli_hdr.proto_version == NULL) + return LuaCallbackError(luastate, "error: no client proto version"); + + return LuaPushStringBuffer(luastate, ssh_state->cli_hdr.proto_version, + strlen((char *)ssh_state->cli_hdr.proto_version)); +} + +static int SshGetClientProtoVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + int lock_hint = 0; + Flow *f = LuaStateGetFlow(luastate, &lock_hint); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + FLOWLOCK_RDLOCK(f); + r = GetClientProtoVersion(luastate, f); + FLOWLOCK_UNLOCK(f); + } else { + r = GetClientProtoVersion(luastate, f); + } + return r; +} + +static int GetClientSoftwareVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SshState *ssh_state = (SshState *)state; + + if (ssh_state->cli_hdr.software_version == NULL) + return LuaCallbackError(luastate, "error: no client software version"); + + return LuaPushStringBuffer(luastate, ssh_state->cli_hdr.software_version, + strlen((char *)ssh_state->cli_hdr.software_version)); +} + +static int SshGetClientSoftwareVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + int lock_hint = 0; + Flow *f = LuaStateGetFlow(luastate, &lock_hint); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + FLOWLOCK_RDLOCK(f); + r = GetClientSoftwareVersion(luastate, f); + FLOWLOCK_UNLOCK(f); + } else { + r = GetClientSoftwareVersion(luastate, f); + } + return r; +} + +/** \brief register ssh lua extensions in a luastate */ +int LuaRegisterSshFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, SshGetServerProtoVersion); + lua_setglobal(luastate, "SshGetServerProtoVersion"); + + lua_pushcfunction(luastate, SshGetServerSoftwareVersion); + lua_setglobal(luastate, "SshGetServerSoftwareVersion"); + + lua_pushcfunction(luastate, SshGetClientProtoVersion); + lua_setglobal(luastate, "SshGetClientProtoVersion"); + + lua_pushcfunction(luastate, SshGetClientSoftwareVersion); + lua_setglobal(luastate, "SshGetClientSoftwareVersion"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-ssh.h b/src/util-lua-ssh.h new file mode 100644 index 000000000000..aa6b6d704253 --- /dev/null +++ b/src/util-lua-ssh.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2015 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 Mats Klepsland + */ + +#ifndef __UTIL_LUA_SSH_H__ +#define __UTIL_LUA_SSH_H__ + +#ifdef HAVE_LUA + +int LuaRegisterSshFunctions(lua_State *luastate); + +#endif /* HAVE_LUA */ + +#endif /* __UTIL_LUA_SSH_H__ */ From 70cc1ddbcd60fdb9373350e34aa276a98a9727e1 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 2 Oct 2015 09:23:13 +0200 Subject: [PATCH 0813/2553] lua: SSH output support Support SSH in lua output scripts (Feature #1569). --- src/app-layer-ssh.h | 2 ++ src/output-lua.c | 88 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/app-layer-ssh.h b/src/app-layer-ssh.h index 7a6a9b723427..4fd59aa9e1d7 100644 --- a/src/app-layer-ssh.h +++ b/src/app-layer-ssh.h @@ -34,6 +34,8 @@ #define SSH_FLAG_STATE_LOGGED 0x04 +#define SSH_FLAG_STATE_LOGGED_LUA 0x08 + /* MSG_CODE */ #define SSH_MSG_NEWKEYS 21 diff --git a/src/output-lua.c b/src/output-lua.c index 0d6e4e8add50..a8fcb246f7f8 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -41,6 +41,7 @@ #include "app-layer-htp.h" #include "app-layer.h" #include "app-layer-ssl.h" +#include "app-layer-ssh.h" #include "app-layer-parser.h" #include "util-privs.h" #include "util-buffer.h" @@ -59,6 +60,7 @@ #include "util-lua-http.h" #include "util-lua-dns.h" #include "util-lua-tls.h" +#include "util-lua-ssh.h" #define MODULE_NAME "LuaLog" @@ -310,6 +312,86 @@ static int LuaPacketConditionTls(ThreadVars *tv, const Packet *p) return FALSE; } +/** \internal + * \brief Packet Logger for lua scripts, for ssh + * + * A single call to this function will run one script for a single + * packet. If it is called, it means that the registered condition + * function has returned TRUE. + * + * The script is called once for each packet. + */ +static int LuaPacketLoggerSsh(ThreadVars *tv, void *thread_data, const Packet *p) +{ + LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data; + + char timebuf[64]; + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + + SCMutexLock(&td->lua_ctx->m); + + lua_getglobal(td->lua_ctx->luastate, "log"); + + LuaStateSetThreadVars(td->lua_ctx->luastate, tv); + LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); + LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* unlocked */LUA_FLOW_NOT_LOCKED_BY_PARENT); + + int retval = lua_pcall(td->lua_ctx->luastate, 0, 0, 0); + if (retval != 0) { + SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1)); + } + + SCMutexUnlock(&td->lua_ctx->m); + FLOWLOCK_WRLOCK(p->flow); + + SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); + if (ssh_state != NULL) + ssh_state->cli_hdr.flags |= SSH_FLAG_STATE_LOGGED_LUA; + + FLOWLOCK_UNLOCK(p->flow); + SCReturnInt(0); +} + +static int LuaPacketConditionSsh(ThreadVars *tv, const Packet *p) +{ + if (p->flow == NULL) { + return FALSE; + } + + if (!(PKT_IS_IPV4(p)) && !(PKT_IS_IPV6(p))) { + return FALSE; + } + + if (!(PKT_IS_TCP(p))) { + return FALSE; + } + + FLOWLOCK_RDLOCK(p->flow); + uint16_t proto = FlowGetAppProtocol(p->flow); + if (proto != ALPROTO_SSH) + goto dontlog; + + SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); + if (ssh_state == NULL) { + SCLogDebug("no ssh state, so no request logging"); + goto dontlog; + } + + if (ssh_state->cli_hdr.software_version == NULL || + ssh_state->srv_hdr.software_version == NULL) + goto dontlog; + + /* We only log the state once */ + if (ssh_state->cli_hdr.flags & SSH_FLAG_STATE_LOGGED_LUA) + goto dontlog; + + FLOWLOCK_UNLOCK(p->flow); + return TRUE; +dontlog: + FLOWLOCK_UNLOCK(p->flow); + return FALSE; +} + /** \internal * \brief Packet Logger for lua scripts, for packets * @@ -601,6 +683,8 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { options->alproto = ALPROTO_DNS; else if (strcmp(k,"protocol") == 0 && strcmp(v, "tls") == 0) options->alproto = ALPROTO_TLS; + else if (strcmp(k,"protocol") == 0 && strcmp(v, "ssh") == 0) + options->alproto = ALPROTO_SSH; else if (strcmp(k, "type") == 0 && strcmp(v, "packet") == 0) options->packet = 1; else if (strcmp(k, "filter") == 0 && strcmp(v, "alerts") == 0) @@ -702,6 +786,7 @@ static lua_State *LuaScriptSetup(const char *filename) LuaRegisterHttpFunctions(luastate); LuaRegisterDnsFunctions(luastate); LuaRegisterTlsFunctions(luastate); + LuaRegisterSshFunctions(luastate); if (lua_pcall(luastate, 0, 0, 0) != 0) { SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'setup' function: %s", lua_tostring(luastate, -1)); @@ -853,6 +938,9 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) om->alproto = ALPROTO_DNS; AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNS); AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); + } else if (opts.alproto == ALPROTO_SSH) { + om->PacketLogFunc = LuaPacketLoggerSsh; + om->PacketConditionFunc = LuaPacketConditionSsh; } else if (opts.packet && opts.alerts) { om->PacketLogFunc = LuaPacketLoggerAlerts; om->PacketConditionFunc = LuaPacketConditionAlerts; From af6d1dddfa0da9b0f6db8655e3c3dc0b66f01d31 Mon Sep 17 00:00:00 2001 From: Torgeir Natvig Date: Sat, 17 Oct 2015 00:44:49 +0200 Subject: [PATCH 0814/2553] Bugfix for detect-engine.luajit-states detect-engine is a list, and luajit-states was looked up as a map. --- src/detect-lua.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/detect-lua.c b/src/detect-lua.c index d5da19d81eec..a3eead4a9e12 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -192,12 +192,18 @@ int DetectLuajitSetupStatesPool(int num, int reloads) pthread_mutex_lock(&luajit_states_lock); if (luajit_states == NULL) { - int cnt = 0; - char *conf_val = NULL; + intmax_t cnt = 0; + ConfNode *denode = NULL; + ConfNode *decnf = ConfGetNode("detect-engine"); + if (decnf != NULL) { + TAILQ_FOREACH(denode, &decnf->head, next) { + if (strcmp(denode->val, "luajit-states") == 0) { + ConfGetChildValueInt(denode, "luajit-states", &cnt); + } + } + } - if ((ConfGet("detect-engine.luajit-states", &conf_val)) == 1) { - cnt = (int)atoi(conf_val); - } else { + if (cnt == 0) { int cpus = UtilCpuGetNumProcessorsOnline(); if (cpus == 0) { cpus = 10; From 484885b70fe0ee380489f63545c49bd898afbc6d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 14 Oct 2015 12:13:06 +0200 Subject: [PATCH 0815/2553] json-email-common: can now log same header twice Multiple events can be applied on a transaction so we may need to log the same header twice. The HDR_IS_LOGGED flag was making it impossible. And this system is usless as email application layer is transaction based. --- src/output-json-email-common.c | 148 ++++++++++++++++----------------- src/util-decode-mime.h | 3 - 2 files changed, 72 insertions(+), 79 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index d54b7b4d028e..dc628328650f 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -270,51 +270,73 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ json_object_set_new(sjs, "status", json_string(MimeDecParseStateGetStatus(mime_state))); - if ((entity->header_flags & HDR_IS_LOGGED) == 0) { - MimeDecField *field; - //printf("email LOG\n"); - - /* From: */ - field = MimeDecFindField(entity, "from"); - if (field != NULL) { - char *s = BytesToString((uint8_t *)field->value, - (size_t)field->value_len); - if (likely(s != NULL)) { - //printf("From: \"%s\"\n", s); - char * sp = SkipWhiteSpaceTill(s, s + strlen(s)); - json_object_set_new(sjs, "from", json_string(sp)); - SCFree(s); - } - } + MimeDecField *field; + //printf("email LOG\n"); - /* To: */ - field = MimeDecFindField(entity, "to"); - if (field != NULL) { - json_t *ajs = JsonEmailJsonArrayFromCommaList(field->value, field->value_len); - if (ajs) { - json_object_set_new(sjs, "to", ajs); - } + /* From: */ + field = MimeDecFindField(entity, "from"); + if (field != NULL) { + char *s = BytesToString((uint8_t *)field->value, + (size_t)field->value_len); + if (likely(s != NULL)) { + //printf("From: \"%s\"\n", s); + char * sp = SkipWhiteSpaceTill(s, s + strlen(s)); + json_object_set_new(sjs, "from", json_string(sp)); + SCFree(s); } + } - /* Cc: */ - field = MimeDecFindField(entity, "cc"); - if (field != NULL) { - json_t *ajs = JsonEmailJsonArrayFromCommaList(field->value, field->value_len); - if (ajs) { - json_object_set_new(sjs, "cc", ajs); - } + /* To: */ + field = MimeDecFindField(entity, "to"); + if (field != NULL) { + json_t *ajs = JsonEmailJsonArrayFromCommaList(field->value, field->value_len); + if (ajs) { + json_object_set_new(sjs, "to", ajs); } + } - entity->header_flags |= HDR_IS_LOGGED; + /* Cc: */ + field = MimeDecFindField(entity, "cc"); + if (field != NULL) { + json_t *ajs = JsonEmailJsonArrayFromCommaList(field->value, field->value_len); + if (ajs) { + json_object_set_new(sjs, "cc", ajs); + } + } - if (mime_state->stack == NULL || mime_state->stack->top == NULL || mime_state->stack->top->data == NULL) - SCReturnPtr(NULL, "json_t"); + if (mime_state->stack == NULL || mime_state->stack->top == NULL || mime_state->stack->top->data == NULL) + SCReturnPtr(NULL, "json_t"); - entity = (MimeDecEntity *)mime_state->stack->top->data; - int attch_cnt = 0; - int url_cnt = 0; - json_t *js_attch = json_array(); - json_t *js_url = json_array(); + entity = (MimeDecEntity *)mime_state->stack->top->data; + int attch_cnt = 0; + int url_cnt = 0; + json_t *js_attch = json_array(); + json_t *js_url = json_array(); + if (entity->url_list != NULL) { + MimeDecUrl *url; + for (url = entity->url_list; url != NULL; url = url->next) { + char *s = BytesToString((uint8_t *)url->url, + (size_t)url->url_len); + if (s != NULL) { + //printf("URL: \"%s\"\n", s); + json_array_append_new(js_url, + json_string(s)); + SCFree(s); + url_cnt += 1; + } + } + } + for (entity = entity->child; entity != NULL; entity = entity->next) { + if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { + + char *s = BytesToString((uint8_t *)entity->filename, + (size_t)entity->filename_len); + //printf("found attachment \"%s\"\n", s); + json_array_append_new(js_attch, + json_string(s)); + SCFree(s); + attch_cnt += 1; + } if (entity->url_list != NULL) { MimeDecUrl *url; for (url = entity->url_list; url != NULL; url = url->next) { @@ -329,45 +351,19 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ } } } - for (entity = entity->child; entity != NULL; entity = entity->next) { - if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { - - char *s = BytesToString((uint8_t *)entity->filename, - (size_t)entity->filename_len); - //printf("found attachment \"%s\"\n", s); - json_array_append_new(js_attch, - json_string(s)); - SCFree(s); - attch_cnt += 1; - } - if (entity->url_list != NULL) { - MimeDecUrl *url; - for (url = entity->url_list; url != NULL; url = url->next) { - char *s = BytesToString((uint8_t *)url->url, - (size_t)url->url_len); - if (s != NULL) { - //printf("URL: \"%s\"\n", s); - json_array_append_new(js_url, - json_string(s)); - SCFree(s); - url_cnt += 1; - } - } - } - } - if (attch_cnt > 0) { - json_object_set_new(sjs, "attachment", js_attch); - } else { - json_decref(js_attch); - } - if (url_cnt > 0) { - json_object_set_new(sjs, "url", js_url); - } else { - json_decref(js_url); - } -// FLOWLOCK_UNLOCK(p->flow); - SCReturnPtr(sjs, "json_t"); } + if (attch_cnt > 0) { + json_object_set_new(sjs, "attachment", js_attch); + } else { + json_decref(js_attch); + } + if (url_cnt > 0) { + json_object_set_new(sjs, "url", js_url); + } else { + json_decref(js_url); + } +// FLOWLOCK_UNLOCK(p->flow); + SCReturnPtr(sjs, "json_t"); } json_decref(sjs); diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h index 536c3a0a246a..02b3bb13dd95 100644 --- a/src/util-decode-mime.h +++ b/src/util-decode-mime.h @@ -33,9 +33,6 @@ #include "util-base64.h" #include "util-debug.h" -/* Header Flags */ -#define HDR_IS_LOGGED 1 - /* Content Flags */ #define CTNT_IS_MSG 1 #define CTNT_IS_ENV 2 From 3676bd667d494ac93c29e1092715435c052eef31 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 14 Oct 2015 13:48:29 +0200 Subject: [PATCH 0816/2553] json-email-common: suppress commented code --- src/output-json-email-common.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index dc628328650f..05755069690c 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -271,7 +271,6 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ json_string(MimeDecParseStateGetStatus(mime_state))); MimeDecField *field; - //printf("email LOG\n"); /* From: */ field = MimeDecFindField(entity, "from"); @@ -318,7 +317,6 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ char *s = BytesToString((uint8_t *)url->url, (size_t)url->url_len); if (s != NULL) { - //printf("URL: \"%s\"\n", s); json_array_append_new(js_url, json_string(s)); SCFree(s); @@ -331,7 +329,6 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ char *s = BytesToString((uint8_t *)entity->filename, (size_t)entity->filename_len); - //printf("found attachment \"%s\"\n", s); json_array_append_new(js_attch, json_string(s)); SCFree(s); @@ -343,7 +340,6 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ char *s = BytesToString((uint8_t *)url->url, (size_t)url->url_len); if (s != NULL) { - //printf("URL: \"%s\"\n", s); json_array_append_new(js_url, json_string(s)); SCFree(s); @@ -362,12 +358,10 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ } else { json_decref(js_url); } -// FLOWLOCK_UNLOCK(p->flow); SCReturnPtr(sjs, "json_t"); } json_decref(sjs); -// FLOWLOCK_UNLOCK(p->flow); SCReturnPtr(NULL, "json_t"); } From 38c21077e63e0212ed0e95936a9843fbcdeb7a70 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 14 Oct 2015 14:17:19 +0200 Subject: [PATCH 0817/2553] json-email-common: fix email extended logging Two structure fields were uninitialized and used has a bit field. Weird behavior were seen in list of logged fields due to that with some build options. --- src/output-json-email-common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 05755069690c..33264d471d61 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -412,6 +412,7 @@ void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx) } } + email_ctx->fields = 0; ConfNode *custom; if ((custom = ConfNodeLookupChild(conf, "custom")) != NULL) { ConfNode *field; @@ -433,6 +434,7 @@ void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx) } } + email_ctx->flags = 0; ConfNode *md5_conf; if ((md5_conf = ConfNodeLookupChild(conf, "md5")) != NULL) { ConfNode *field; From 9697a09d219ca8abe9bb948df9120338646f23ca Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 8 Oct 2015 14:54:57 -0600 Subject: [PATCH 0818/2553] template app-layer: disable if not in config file (default) Unlike other app-layer protocols which are enabled by default, disable this one by default as it likely shouldn't be enabled in production use of Suricata. --- src/app-layer-template.c | 14 +++++++++++--- src/detect-template-buffer.c | 5 +++++ src/output-json-template.c | 4 ++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/app-layer-template.c b/src/app-layer-template.c index 87b64b732f76..5eafa67e1ae5 100644 --- a/src/app-layer-template.c +++ b/src/app-layer-template.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "stream.h" +#include "conf.h" #include "util-unittest.h" @@ -428,6 +429,12 @@ void RegisterTemplateParsers(void) { char *proto_name = "template"; + /* TEMPLATE_START_REMOVE */ + if (ConfGetNode("app-layer.protocols.template") == NULL) { + return; + } + /* TEMPLATE_END_REMOVE */ + /* Check if Template TCP detection is enabled. If it does not exist in * the configuration file then it will be enabled by default. */ if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { @@ -481,8 +488,8 @@ void RegisterTemplateParsers(void) STREAM_TOSERVER, TemplateParseRequest); /* Register response parser for parsing frames from server to client. */ - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE, STREAM_TOCLIENT, - TemplateParseResponse); + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE, + STREAM_TOCLIENT, TemplateParseResponse); /* Register a function to be called by the application layer * when a transaction is to be freed. */ @@ -490,7 +497,8 @@ void RegisterTemplateParsers(void) TemplateStateTxFree); /* Register a function to return the current transaction count. */ - AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEMPLATE, TemplateGetTxCnt); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateGetTxCnt); /* Transaction handling. */ AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index 64f948c2b45b..d9f9aa67ce55 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -21,6 +21,7 @@ */ #include "suricata-common.h" +#include "conf.h" #include "detect.h" #include "app-layer-template.h" @@ -29,6 +30,10 @@ static void DetectTemplateBufferRegisterTests(void); void DetectTemplateBufferRegister(void) { + if (ConfGetNode("app-layer.protocols.template") == NULL) { + return; + } + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].name = "template_buffer"; sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].desc = "Template content modififier to match on the template buffers"; diff --git a/src/output-json-template.c b/src/output-json-template.c index ca4a937837ba..d360e6746c77 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -180,6 +180,10 @@ static TmEcode JsonTemplateLogThreadDeinit(ThreadVars *t, void *data) void TmModuleJsonTemplateLogRegister(void) { + if (ConfGetNode("app-layer.protocols.template") == NULL) { + return; + } + tmm_modules[TMM_JSONTEMPLATELOG].name = "JsonTemplateLog"; tmm_modules[TMM_JSONTEMPLATELOG].ThreadInit = JsonTemplateLogThreadInit; tmm_modules[TMM_JSONTEMPLATELOG].ThreadDeinit = JsonTemplateLogThreadDeinit; From dc2c8967819fc1e60cbc992c85893e166617f8fc Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 8 Oct 2015 15:20:25 -0600 Subject: [PATCH 0819/2553] app-layer setup scripts: enable new modules on copy The templates are disabled by default, enable the copy of the template so the new app-layer modules are enabled by by default. --- scripts/setup-app-layer-detect.sh | 6 ++++-- scripts/setup-app-layer-logger.sh | 6 ++++-- scripts/setup-app-layer.sh | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/scripts/setup-app-layer-detect.sh b/scripts/setup-app-layer-detect.sh index ef3b741e7f4b..ef4bccaa8e9f 100755 --- a/scripts/setup-app-layer-detect.sh +++ b/scripts/setup-app-layer-detect.sh @@ -34,9 +34,11 @@ function copy_template_file() { echo "Creating ${dst}." - sed -e "s/TEMPLATE/${protoname_upper}/g" \ + sed -e '/TEMPLATE_START_REMOVE/,/TEMPLATE_END_REMOVE/d' \ + -e "s/TEMPLATE/${protoname_upper}/g" \ -e "s/template/${protoname_lower}/g" \ - -e "s/Template/${protoname}/g" > ${dst} < ${src} + -e "s/Template/${protoname}/g" \ + > ${dst} < ${src} } function copy_templates() { diff --git a/scripts/setup-app-layer-logger.sh b/scripts/setup-app-layer-logger.sh index 8b53ae545384..13342412ed94 100755 --- a/scripts/setup-app-layer-logger.sh +++ b/scripts/setup-app-layer-logger.sh @@ -38,9 +38,11 @@ function copy_template_file() { echo "Creating ${dst}." - sed -e "s/TEMPLATE/${protoname_upper}/g" \ + sed -e '/TEMPLATE_START_REMOVE/,/TEMPLATE_END_REMOVE/d' \ + -e "s/TEMPLATE/${protoname_upper}/g" \ -e "s/template/${protoname_lower}/g" \ - -e "s/Template/${protoname}/g" > ${dst} < ${src} + -e "s/Template/${protoname}/g" \ + > ${dst} < ${src} } function copy_templates() { diff --git a/scripts/setup-app-layer.sh b/scripts/setup-app-layer.sh index b24b5e6195d8..2789f20dd7cd 100755 --- a/scripts/setup-app-layer.sh +++ b/scripts/setup-app-layer.sh @@ -37,9 +37,11 @@ function copy_template_file() { echo "Creating ${dst}." - sed -e "s/TEMPLATE/${protoname_upper}/g" \ + sed -e '/TEMPLATE_START_REMOVE/,/TEMPLATE_END_REMOVE/d' \ + -e "s/TEMPLATE/${protoname_upper}/g" \ -e "s/template/${protoname_lower}/g" \ - -e "s/Template/${protoname}/g" > ${dst} < ${src} + -e "s/Template/${protoname}/g" \ + > ${dst} < ${src} } function copy_app_layer_templates { From f8b6768d050573aff955df3a2661340a040af345 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 21 Oct 2015 14:50:25 +0200 Subject: [PATCH 0820/2553] json-email: fix coverity alert The code was not correct and coverity did detect a potential overflow problem that should not happen because of the structure of md5 string and of format. --- src/output-json-email-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 33264d471d61..88cd3acf4b2c 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -140,13 +140,13 @@ static void JsonEmailLogJSONMd5(OutputJsonEmailCtx *email_ctx, json_t *js, SMTPT field = MimeDecFindField(entity, "subject"); if (field != NULL) { unsigned char md5[MD5_LENGTH]; - char smd5[2 * MD5_LENGTH + 1]; + char smd5[256]; char *value = BytesToString((uint8_t *)field->value , field->value_len); if (value) { size_t i,x; HASH_HashBuf(HASH_AlgMD5, md5, (unsigned char *)value, strlen(value)); for (i = 0, x = 0; x < sizeof(md5); x++) { - i += snprintf(smd5 + i, 255-i, "%02x", md5[x]); + i += snprintf(smd5 + i, 255 - i, "%02x", md5[x]); } json_object_set_new(js, "subject_md5", json_string(smd5)); SCFree(value); From 16b210f1ea500193d942955eec2572fe6e2df46a Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 21 Oct 2015 14:56:38 +0200 Subject: [PATCH 0821/2553] json-file: avoid allocation --- src/output-json-file.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/output-json-file.c b/src/output-json-file.c index f2f21df34bde..9506a74670dc 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -128,14 +128,11 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F if (ff->flags & FILE_MD5) { size_t x; int i; - char *s = SCMalloc(256); - if (likely(s != NULL)) { - for (i = 0, x = 0; x < sizeof(ff->md5); x++) { - i += snprintf(&s[i], 255-i, "%02x", ff->md5[x]); - } - json_object_set_new(fjs, "md5", json_string(s)); - SCFree(s); + char s[256]; + for (i = 0, x = 0; x < sizeof(ff->md5); x++) { + i += snprintf(&s[i], 255-i, "%02x", ff->md5[x]); } + json_object_set_new(fjs, "md5", json_string(s)); } #endif break; From c2704c39333c2866d62020e1aa4e749968fb3a01 Mon Sep 17 00:00:00 2001 From: cardigliano Date: Wed, 21 Oct 2015 01:23:32 +0200 Subject: [PATCH 0822/2553] workers runmode: allow multiple input devices This fix allows multiple input devices when running in 'workers' mode. --- src/util-runmodes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-runmodes.c b/src/util-runmodes.c index c9b61e6a2e55..a327a5129ff9 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -420,7 +420,7 @@ int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, for (ldev = 0; ldev < nlive; ldev++) { char *live_dev_c = NULL; - if (live_dev != NULL) { + if ((nlive <= 1) && (live_dev != NULL)) { aconf = ConfigParser(live_dev); live_dev_c = SCStrdup(live_dev); if (unlikely(live_dev_c == NULL)) { From 769722101e91cf59cd0a166870b0220bb6dbc98d Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 12 Oct 2015 11:39:36 +0200 Subject: [PATCH 0823/2553] decode: add flow memcap counter This adds a counter indicating how many times the flow max memcap has been reached Since there is no always a reference to FlowManagerThreadData, the counter is put in DecodeThreadVars. Currently when there is no counter increase in one call of FlowGetNew because we don't have tv or dtv at the time of the call. The following is a snippet of the generated EVE entry: "flow":{"memcap":0,"spare":10000,"emerg_mode_entered":0,"emerg_mode_over":0,"tcp_reuse":0,"memuse":7085248} --- src/decode.c | 1 + src/decode.h | 2 ++ src/flow-hash.c | 8 ++++++++ 3 files changed, 11 insertions(+) diff --git a/src/decode.c b/src/decode.c index 0dd9fa86fa04..4be4b9e70289 100644 --- a/src/decode.c +++ b/src/decode.c @@ -403,6 +403,7 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) dtv->counter_avg_pkt_size = StatsRegisterAvgCounter("decoder.avg_pkt_size", tv); dtv->counter_max_pkt_size = StatsRegisterMaxCounter("decoder.max_pkt_size", tv); dtv->counter_erspan = StatsRegisterMaxCounter("decoder.erspan", tv); + dtv->counter_flow_memcap = StatsRegisterCounter("flow.memcap", tv); dtv->counter_defrag_ipv4_fragments = StatsRegisterCounter("defrag.ipv4.fragments", tv); diff --git a/src/decode.h b/src/decode.h index 2f322a02fec3..f57dcea997fb 100644 --- a/src/decode.h +++ b/src/decode.h @@ -624,6 +624,8 @@ typedef struct DecodeThreadVars_ uint16_t counter_defrag_ipv6_timeouts; uint16_t counter_defrag_max_hit; + uint16_t counter_flow_memcap; + /* thread data for flow logging api: only used at forced * flow recycle during lookups */ void *output_flow_thread_data; diff --git a/src/flow-hash.c b/src/flow-hash.c index b8de40e77fd6..9ddb3713c47c 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -486,6 +486,11 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) f = FlowGetUsedFlow(tv, dtv); if (f == NULL) { + /* max memcap reached, so increments the counter */ + if (tv != NULL && dtv != NULL) { + StatsIncr(tv, dtv->counter_flow_memcap); + } + /* very rare, but we can fail. Just giving up */ return NULL; } @@ -495,6 +500,9 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) /* now see if we can alloc a new flow */ f = FlowAlloc(); if (f == NULL) { + if (tv != NULL && dtv != NULL) { + StatsIncr(tv, dtv->counter_flow_memcap); + } return NULL; } From eef5678e5e4ae210e3a0137cad7650ccd798369b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 7 Feb 2015 13:10:23 +0100 Subject: [PATCH 0824/2553] output-json: add redis support This patch adds redis support to JSON output. --- configure.ac | 41 ++++++++++++++++++++ src/output-json.c | 85 ++++++++++++++++++++++++++++++++++++++++++ src/output-json.h | 1 - src/util-logopenfile.c | 6 +++ src/util-logopenfile.h | 20 +++++++++- suricata.yaml.in | 7 +++- 6 files changed, 157 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 97ce3ab1742f..9e13938304c7 100644 --- a/configure.ac +++ b/configure.ac @@ -1703,6 +1703,46 @@ LDFLAGS="${LDFLAGS} -pie" fi +# libhiredis + AC_ARG_ENABLE(hiredis, + AS_HELP_STRING([--enable-hiredis],[Enable Redis support]), + [ enable_hiredis="yes"], + [ enable_hiredis="no"]) + AC_ARG_WITH(libhiredis_includes, + [ --with-libhiredis-includes=DIR libhiredis include directory], + [with_libhiredis_includes="$withval"],[with_libhiredis_includes="no"]) + AC_ARG_WITH(libhiredis_libraries, + [ --with-libhiredis-libraries=DIR libhiredis library directory], + [with_libhiredis_libraries="$withval"],[with_libhiredis_libraries="no"]) + + if test "$enable_hiredis" = "yes"; then + if test "$with_libhiredis_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_libhiredis_includes}" + fi + + AC_CHECK_HEADER("hiredis/hiredis.h",HIREDIS="yes",HIREDIS="no") + if test "$HIREDIS" = "yes"; then + if test "$with_libhiredis_libraries" != "no"; then + LDFLAGS="${LDFLAGS} -L${with_libhiredis_libraries}" + fi + AC_CHECK_LIB(hiredis, redisConnect,, HIREDIS="no") + fi + if test "$HIREDIS" = "no"; then + echo + echo " ERROR! libhiredis library not found, go get it" + echo " from https://github.com/redis/hiredis or your distribution:" + echo + echo " Ubuntu: apt-get install libhiredis-dev" + echo " Fedora: yum install libhiredis-devel" + echo + exit 1 + fi + if test "$HIREDIS" = "yes"; then + AC_DEFINE([HAVE_LIBHIREDIS],[1],[libhiredis available]) + enable_hiredis="yes" + fi + fi + # get cache line size AC_PATH_PROG(HAVE_GETCONF_CMD, getconf, "no") if test "$HAVE_GETCONF_CMD" != "no"; then @@ -1810,6 +1850,7 @@ SURICATA_BUILD_CONF="Suricata Configuration: libnss support: ${enable_nss} libnspr support: ${enable_nspr} libjansson support: ${enable_jansson} + hiredis support: ${enable_hiredis} Prelude support: ${enable_prelude} PCRE jit: ${pcre_jit_available} LUA support: ${enable_lua} diff --git a/src/output-json.c b/src/output-json.c index a8e5456351d1..eb937c4ef561 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -110,6 +110,9 @@ void OutputJsonRegisterTests (void) #else /* implied we do have JSON support */ #include +#if HAVE_LIBHIREDIS +#include +#endif #define DEFAULT_LOG_FILENAME "eve.json" #define DEFAULT_ALERT_SYSLOG_FACILITY_STR "local0" @@ -379,6 +382,28 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), MEMBUFFER_OFFSET(buffer), file_ctx); } +#if HAVE_LIBHIREDIS + else if (file_ctx->type == LOGFILE_TYPE_REDIS) { + /* FIXME go async here */ + redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s", + file_ctx->redis_setup.command, + file_ctx->redis_setup.key, + js_s); + switch (reply->type) { + case REDIS_REPLY_ERROR: + SCLogWarning(SC_WARN_NO_UNITTESTS, "Redis error: %s", reply->str); + break; + case REDIS_REPLY_INTEGER: + SCLogDebug("Redis integer %lld", reply->integer); + break; + default: + SCLogError(SC_ERR_INVALID_VALUE, + "Redis default triggered with %d", reply->type); + break; + } + freeReplyObject(reply); + } +#endif SCMutexUnlock(&file_ctx->fp_mutex); free(js_s); return 0; @@ -477,6 +502,14 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) json_ctx->json_out = LOGFILE_TYPE_UNIX_DGRAM; } else if (strcmp(output_s, "unix_stream") == 0) { json_ctx->json_out = LOGFILE_TYPE_UNIX_STREAM; + } else if (strcmp(output_s, "redis") == 0) { +#if HAVE_LIBHIREDIS + json_ctx->json_out = LOGFILE_TYPE_REDIS; +#else + SCLogError(SC_ERR_INVALID_ARGUMENT, + "redis JSON output option is not compiled"); + exit(EXIT_FAILURE); +#endif } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid JSON output option: %s", output_s); @@ -549,6 +582,58 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) openlog(ident, LOG_PID|LOG_NDELAY, facility); } +#if HAVE_LIBHIREDIS + else if (json_ctx->json_out == LOGFILE_TYPE_REDIS) { + ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); + const char *redis_server = NULL; + const char *redis_port = NULL; + const char *redis_mode = NULL; + const char *redis_key = NULL; + + if (redis_node) { + redis_server = ConfNodeLookupChildValue(redis_node, "server"); + redis_port = ConfNodeLookupChildValue(redis_node, "port"); + redis_mode = ConfNodeLookupChildValue(redis_node, "mode"); + redis_key = ConfNodeLookupChildValue(redis_node, "key"); + } + if (!redis_server) { + redis_server = "127.0.0.1"; + SCLogInfo("Using default redis server (127.0.0.1)"); + } + if (!redis_port) + redis_port = "6379"; + if (!redis_mode) + redis_mode = "list"; + if (!redis_key) + redis_key = "suricata"; + json_ctx->file_ctx->redis_setup.key = SCStrdup(redis_key); + + if (!json_ctx->file_ctx->redis_setup.key) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key name"); + exit(EXIT_FAILURE); + } + + if (!strcmp(redis_mode, "list")) { + json_ctx->file_ctx->redis_setup.command = SCStrdup("LPUSH"); + if (!json_ctx->file_ctx->redis_setup.command) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); + exit(EXIT_FAILURE); + } + } else { + json_ctx->file_ctx->redis_setup.command = SCStrdup("PUBLISH"); + if (!json_ctx->file_ctx->redis_setup.command) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); + exit(EXIT_FAILURE); + } + } + redisContext *c = redisConnect(redis_server, atoi(redis_port)); + if (c != NULL && c->err) { + SCLogError(SC_ERR_SOCKET, "Error connecting to redis server: %s\n", c->errstr); + exit(EXIT_FAILURE); + } + json_ctx->file_ctx->redis = c; + } +#endif const char *sensor_id_s = ConfNodeLookupChildValue(conf, "sensor-id"); if (sensor_id_s != NULL) { diff --git a/src/output-json.h b/src/output-json.h index 15c2829555c2..89e11d86ce01 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -40,7 +40,6 @@ TmEcode OutputJSON(json_t *js, void *data, uint64_t *count); int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer); OutputCtx *OutputJsonInitCtx(ConfNode *); - enum JsonFormat { COMPACT, INDENT }; /* diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index b25c4a82705f..b22988ae84d1 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -367,6 +367,12 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) SCMutexUnlock(&lf_ctx->fp_mutex); } +#ifdef HAVE_LIBHIREDIS + if (lf_ctx->type == LOGFILE_TYPE_REDIS && lf_ctx->redis) { + redisFree(lf_ctx->redis); + } +#endif + SCMutexDestroy(&lf_ctx->fp_mutex); if (lf_ctx->prefix != NULL) diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index d345475d220c..b5ac9823deac 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -27,6 +27,8 @@ #include "conf.h" /* ConfNode */ #include "tm-modules.h" /* LogFileCtx */ +#include "hiredis/hiredis.h" + typedef struct { uint16_t fileno; } PcieFile; @@ -34,15 +36,31 @@ typedef struct { enum LogFileType { LOGFILE_TYPE_FILE, LOGFILE_TYPE_SYSLOG, LOGFILE_TYPE_UNIX_DGRAM, - LOGFILE_TYPE_UNIX_STREAM }; + LOGFILE_TYPE_UNIX_STREAM, + LOGFILE_TYPE_REDIS }; + +enum RedisMode { REDIS_LIST, REDIS_CHANNEL }; + +typedef struct RedisSetup_ { + enum RedisMode mode; + char *command; + char *key; +} RedisSetup; /** Global structure for Output Context */ typedef struct LogFileCtx_ { union { FILE *fp; PcieFile *pcie_fp; +#ifdef HAVE_LIBHIREDIS + redisContext *redis; +#endif }; +#ifdef HAVE_LIBHIREDIS + RedisSetup redis_setup; +#endif + int (*Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp); void (*Close)(struct LogFileCtx_ *fp); diff --git a/suricata.yaml.in b/suricata.yaml.in index 9ab40098fdba..30921751a929 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -92,7 +92,7 @@ outputs: # Extensible Event Format (nicknamed EVE) event log in JSON format - eve-log: enabled: yes - filetype: regular #regular|syslog|unix_dgram|unix_stream + filetype: regular #regular|syslog|unix_dgram|unix_stream|redis filename: eve.json #prefix: "@cee: " # prefix to prepend to each log entry # the following are valid when type: syslog above @@ -100,6 +100,11 @@ outputs: #facility: local5 #level: Info ## possible levels: Emergency, Alert, Critical, ## Error, Warning, Notice, Info, Debug + #redis: + # server: 127.0.0.1 + # port: 6379 + # mode: list ## possible values: list (default), channel + # key: suricata ## key or channel to use (default to suricata) types: - alert: # payload: yes # enable dumping payload in Base64 From 31c91d53bb0e784fa46fd4c67af75eb453c1d01e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 26 May 2015 22:49:07 +0200 Subject: [PATCH 0825/2553] output-json: improve hiredis define Use #ifdef instead of #if and don't include the header which is not needed anymore. --- src/output-json.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index eb937c4ef561..aa803d12fb5d 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -110,9 +110,6 @@ void OutputJsonRegisterTests (void) #else /* implied we do have JSON support */ #include -#if HAVE_LIBHIREDIS -#include -#endif #define DEFAULT_LOG_FILENAME "eve.json" #define DEFAULT_ALERT_SYSLOG_FACILITY_STR "local0" @@ -503,7 +500,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) } else if (strcmp(output_s, "unix_stream") == 0) { json_ctx->json_out = LOGFILE_TYPE_UNIX_STREAM; } else if (strcmp(output_s, "redis") == 0) { -#if HAVE_LIBHIREDIS +#ifdef HAVE_LIBHIREDIS json_ctx->json_out = LOGFILE_TYPE_REDIS; #else SCLogError(SC_ERR_INVALID_ARGUMENT, @@ -582,7 +579,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) openlog(ident, LOG_PID|LOG_NDELAY, facility); } -#if HAVE_LIBHIREDIS +#ifdef HAVE_LIBHIREDIS else if (json_ctx->json_out == LOGFILE_TYPE_REDIS) { ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); const char *redis_server = NULL; From 9286360f866b723c214d415e3314c76422b15bd9 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 8 Feb 2015 12:20:59 +0100 Subject: [PATCH 0826/2553] travis: add libjansson and hiredis Install the libs and force usage of hiredis. We will have a more complete build with this two libs. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 297b6133b026..8ae46e34c4d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,10 @@ compiler: - gcc - clang # Change this to your needs -script: sh autogen.sh && ./configure --enable-nfqueue --enable-unittests && make && make check +script: sh autogen.sh && ./configure --enable-nfqueue --enable-unittests --enable-hiredis && make && make check before_install: - sudo add-apt-repository -y ppa:npalix/coccinelle - sudo apt-get update -qq - - sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 coccinelle + - sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 coccinelle libjansson-dev libhiredis-dev - ./qa/travis-libhtp.sh From 60ea49c777ad839fc6306f5731fd12aa98b0f011 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 23 May 2015 16:59:16 +0200 Subject: [PATCH 0827/2553] output-json: add sensor-name config variable When using redis output, we are loosing the host key (added by logstash or logstash-forwarder) and we can't find anymore what Suricata did cause the alert. This patch is adding this key during message generation using the 'sensor-name' variable or the hostname is 'sensor-name' is not defined. --- src/output-json.c | 22 ++++++++++++++++++++-- src/util-logopenfile.h | 5 +++++ suricata.yaml.in | 4 ++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index aa803d12fb5d..d45bbb12337b 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -341,8 +341,17 @@ json_t *CreateJSONHeaderWithTxId(Packet *p, int direction_sensitive, char *event int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) { - char *js_s = json_dumps(js, - JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| + char *js_s = NULL; + +#ifdef HAVE_LIBHIREDIS + if (file_ctx->type == LOGFILE_TYPE_REDIS) { + json_object_set_new(js, "host", + json_string(file_ctx->redis_setup.sensor_name)); + } +#endif + + js_s = json_dumps(js, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| #ifdef JSON_ESCAPE_SLASH JSON_ESCAPE_SLASH #else @@ -582,11 +591,20 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) #ifdef HAVE_LIBHIREDIS else if (json_ctx->json_out == LOGFILE_TYPE_REDIS) { ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); + const char *sensor_name = ConfNodeLookupChildValue(conf, "sensor-name"); const char *redis_server = NULL; const char *redis_port = NULL; const char *redis_mode = NULL; const char *redis_key = NULL; + if (!sensor_name) { + char hostname[1024]; + gethostname(hostname, 1023); + sensor_name = hostname; + } + json_ctx->file_ctx->redis_setup.sensor_name = SCStrdup(sensor_name); + + if (redis_node) { redis_server = ConfNodeLookupChildValue(redis_node, "server"); redis_port = ConfNodeLookupChildValue(redis_node, "port"); diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index b5ac9823deac..775647a6b389 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -27,7 +27,9 @@ #include "conf.h" /* ConfNode */ #include "tm-modules.h" /* LogFileCtx */ +#ifdef HAVE_LIBHIREDIS #include "hiredis/hiredis.h" +#endif typedef struct { uint16_t fileno; @@ -39,13 +41,16 @@ enum LogFileType { LOGFILE_TYPE_FILE, LOGFILE_TYPE_UNIX_STREAM, LOGFILE_TYPE_REDIS }; +#ifdef HAVE_LIBHIREDIS enum RedisMode { REDIS_LIST, REDIS_CHANNEL }; typedef struct RedisSetup_ { enum RedisMode mode; char *command; char *key; + char *sensor_name; } RedisSetup; +#endif /** Global structure for Output Context */ typedef struct LogFileCtx_ { diff --git a/suricata.yaml.in b/suricata.yaml.in index 30921751a929..43d5e17a4c55 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -44,6 +44,10 @@ host-mode: auto # user: suri # group: suri +# Some logging module will use that name in event as identifier. The default +# value is the hostname +#sensor-name: suricata + # Default pid file. # Will use this file if no --pidfile in command options. #pid-file: /var/run/suricata.pid From a13be67b5e6c26c53149b88f9565c58f7fbe3381 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 24 May 2015 17:43:51 +0200 Subject: [PATCH 0828/2553] util-logopenfile: add write function Introduce a function LogFileWrite that will handle the writing with respect of the type defined in the configuration. This is used in this patch to remove the write complexity from output-json. --- src/output-json.c | 58 +++--------------------------------------- src/util-logopenfile.c | 40 +++++++++++++++++++++++++++++ src/util-logopenfile.h | 11 +++++++- 3 files changed, 53 insertions(+), 56 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index d45bbb12337b..4ac09b30098c 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -119,10 +119,6 @@ void OutputJsonRegisterTests (void) #define OUTPUT_BUFFER_SIZE 65535 -#ifndef OS_WIN32 -static int alert_syslog_level = DEFAULT_ALERT_SYSLOG_LEVEL; -#endif /* OS_WIN32 */ - TmEcode OutputJson (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode OutputJsonThreadInit(ThreadVars *, void *, void **); TmEcode OutputJsonThreadDeinit(ThreadVars *, void *); @@ -361,56 +357,8 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) if (unlikely(js_s == NULL)) return TM_ECODE_OK; - SCMutexLock(&file_ctx->fp_mutex); - if (file_ctx->type == LOGFILE_TYPE_SYSLOG) - { - if (file_ctx->prefix != NULL) - { - syslog(alert_syslog_level, "%s%s", file_ctx->prefix, js_s); - } - else - { - syslog(alert_syslog_level, "%s", js_s); - } - } - else if (file_ctx->type == LOGFILE_TYPE_FILE || - file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || - file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) - { - if (file_ctx->prefix != NULL) - { - MemBufferWriteString(buffer, "%s%s\n", file_ctx->prefix, js_s); - } - else - { - MemBufferWriteString(buffer, "%s\n", js_s); - } - file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), - MEMBUFFER_OFFSET(buffer), file_ctx); - } -#if HAVE_LIBHIREDIS - else if (file_ctx->type == LOGFILE_TYPE_REDIS) { - /* FIXME go async here */ - redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s", - file_ctx->redis_setup.command, - file_ctx->redis_setup.key, - js_s); - switch (reply->type) { - case REDIS_REPLY_ERROR: - SCLogWarning(SC_WARN_NO_UNITTESTS, "Redis error: %s", reply->str); - break; - case REDIS_REPLY_INTEGER: - SCLogDebug("Redis integer %lld", reply->integer); - break; - default: - SCLogError(SC_ERR_INVALID_VALUE, - "Redis default triggered with %d", reply->type); - break; - } - freeReplyObject(reply); - } -#endif - SCMutexUnlock(&file_ctx->fp_mutex); + LogFileWrite(file_ctx, buffer, js_s, strlen(js_s)); + free(js_s); return 0; } @@ -577,7 +525,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) if (level_s != NULL) { int level = SCMapEnumNameToValue(level_s, SCSyslogGetLogLevelMap()); if (level != -1) { - alert_syslog_level = level; + json_ctx->file_ctx->syslog_setup.alert_syslog_level = level; } } diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index b22988ae84d1..05dad32b0873 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -387,3 +387,43 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) SCReturnInt(1); } + +int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t string_len) +{ + SCMutexLock(&file_ctx->fp_mutex); + if (file_ctx->type == LOGFILE_TYPE_SYSLOG) { + syslog(file_ctx->syslog_setup.alert_syslog_level, "%s", string); + } else if (file_ctx->type == LOGFILE_TYPE_FILE || + file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || + file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) + { + MemBufferWriteString(buffer, "%s\n", string); + file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), + MEMBUFFER_OFFSET(buffer), file_ctx); + } +#if HAVE_LIBHIREDIS + else if (file_ctx->type == LOGFILE_TYPE_REDIS) { + /* FIXME go async here */ + redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s", + file_ctx->redis_setup.command, + file_ctx->redis_setup.key, + string); + switch (reply->type) { + case REDIS_REPLY_ERROR: + SCLogWarning(SC_WARN_NO_UNITTESTS, "Redis error: %s", reply->str); + break; + case REDIS_REPLY_INTEGER: + SCLogDebug("Redis integer %lld", reply->integer); + break; + default: + SCLogError(SC_ERR_INVALID_VALUE, + "Redis default triggered with %d", reply->type); + break; + } + freeReplyObject(reply); + } +#endif + SCMutexUnlock(&file_ctx->fp_mutex); + + return 0; +} diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 775647a6b389..0c6c392bf223 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -26,6 +26,7 @@ #include "conf.h" /* ConfNode */ #include "tm-modules.h" /* LogFileCtx */ +#include "util-buffer.h" #ifdef HAVE_LIBHIREDIS #include "hiredis/hiredis.h" @@ -41,6 +42,10 @@ enum LogFileType { LOGFILE_TYPE_FILE, LOGFILE_TYPE_UNIX_STREAM, LOGFILE_TYPE_REDIS }; +typedef struct SyslogSetup_ { + int alert_syslog_level; +} SyslogSetup; + #ifdef HAVE_LIBHIREDIS enum RedisMode { REDIS_LIST, REDIS_CHANNEL }; @@ -62,9 +67,12 @@ typedef struct LogFileCtx_ { #endif }; + union { + SyslogSetup syslog_setup; #ifdef HAVE_LIBHIREDIS - RedisSetup redis_setup; + RedisSetup redis_setup; #endif + }; int (*Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp); void (*Close)(struct LogFileCtx_ *fp); @@ -115,6 +123,7 @@ typedef struct LogFileCtx_ { LogFileCtx *LogFileNewCtx(void); int LogFileFreeCtx(LogFileCtx *); +int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t string_len); int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *, const char *, int); int SCConfLogReopen(LogFileCtx *); From f953fdfbace8c5dbdc0f190147be3ef7ed309bf7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 24 May 2015 18:07:20 +0200 Subject: [PATCH 0829/2553] util-logopenfile: introduce SCConfLogOpenRedis Introduce a function to realize the parsing and config file and opening of connection to the database. Only used by output-json for now it will be usable by other logging modules. --- src/output-json.c | 52 ++++----------------------------------- src/util-logopenfile.c | 56 ++++++++++++++++++++++++++++++++++++++++++ src/util-logopenfile.h | 1 + 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index 4ac09b30098c..99032a5481cb 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -540,11 +540,6 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) else if (json_ctx->json_out == LOGFILE_TYPE_REDIS) { ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); const char *sensor_name = ConfNodeLookupChildValue(conf, "sensor-name"); - const char *redis_server = NULL; - const char *redis_port = NULL; - const char *redis_mode = NULL; - const char *redis_key = NULL; - if (!sensor_name) { char hostname[1024]; gethostname(hostname, 1023); @@ -552,49 +547,12 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) } json_ctx->file_ctx->redis_setup.sensor_name = SCStrdup(sensor_name); - - if (redis_node) { - redis_server = ConfNodeLookupChildValue(redis_node, "server"); - redis_port = ConfNodeLookupChildValue(redis_node, "port"); - redis_mode = ConfNodeLookupChildValue(redis_node, "mode"); - redis_key = ConfNodeLookupChildValue(redis_node, "key"); - } - if (!redis_server) { - redis_server = "127.0.0.1"; - SCLogInfo("Using default redis server (127.0.0.1)"); - } - if (!redis_port) - redis_port = "6379"; - if (!redis_mode) - redis_mode = "list"; - if (!redis_key) - redis_key = "suricata"; - json_ctx->file_ctx->redis_setup.key = SCStrdup(redis_key); - - if (!json_ctx->file_ctx->redis_setup.key) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key name"); - exit(EXIT_FAILURE); - } - - if (!strcmp(redis_mode, "list")) { - json_ctx->file_ctx->redis_setup.command = SCStrdup("LPUSH"); - if (!json_ctx->file_ctx->redis_setup.command) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); - exit(EXIT_FAILURE); - } - } else { - json_ctx->file_ctx->redis_setup.command = SCStrdup("PUBLISH"); - if (!json_ctx->file_ctx->redis_setup.command) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); - exit(EXIT_FAILURE); - } - } - redisContext *c = redisConnect(redis_server, atoi(redis_port)); - if (c != NULL && c->err) { - SCLogError(SC_ERR_SOCKET, "Error connecting to redis server: %s\n", c->errstr); - exit(EXIT_FAILURE); + if (SCConfLogOpenRedis(redis_node, json_ctx->file_ctx) < 0) { + LogFileFreeCtx(json_ctx->file_ctx); + SCFree(json_ctx); + SCFree(output_ctx); + return NULL; } - json_ctx->file_ctx->redis = c; } #endif diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 05dad32b0873..519e4f7735fb 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -330,6 +330,62 @@ int SCConfLogReopen(LogFileCtx *log_ctx) return 0; } + +#if HAVE_LIBHIREDIS +int SCConfLogOpenRedis(ConfNode *redis_node, LogFileCtx *log_ctx) +{ + const char *redis_server = NULL; + const char *redis_port = NULL; + const char *redis_mode = NULL; + const char *redis_key = NULL; + + if (redis_node) { + redis_server = ConfNodeLookupChildValue(redis_node, "server"); + redis_port = ConfNodeLookupChildValue(redis_node, "port"); + redis_mode = ConfNodeLookupChildValue(redis_node, "mode"); + redis_key = ConfNodeLookupChildValue(redis_node, "key"); + } + if (!redis_server) { + redis_server = "127.0.0.1"; + SCLogInfo("Using default redis server (127.0.0.1)"); + } + if (!redis_port) + redis_port = "6379"; + if (!redis_mode) + redis_mode = "list"; + if (!redis_key) + redis_key = "suricata"; + log_ctx->redis_setup.key = SCStrdup(redis_key); + + if (!log_ctx->redis_setup.key) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key name"); + exit(EXIT_FAILURE); + } + + if (!strcmp(redis_mode, "list")) { + log_ctx->redis_setup.command = SCStrdup("LPUSH"); + if (!log_ctx->redis_setup.command) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); + exit(EXIT_FAILURE); + } + } else { + log_ctx->redis_setup.command = SCStrdup("PUBLISH"); + if (!log_ctx->redis_setup.command) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); + exit(EXIT_FAILURE); + } + } + redisContext *c = redisConnect(redis_server, atoi(redis_port)); + if (c != NULL && c->err) { + SCLogError(SC_ERR_SOCKET, "Error connecting to redis server: %s", c->errstr); + exit(EXIT_FAILURE); + } + log_ctx->redis = c; + + return 0; +} +#endif + /** \brief LogFileNewCtx() Get a new LogFileCtx * \retval LogFileCtx * pointer if succesful, NULL if error * */ diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 0c6c392bf223..82ea4eefdd35 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -126,6 +126,7 @@ int LogFileFreeCtx(LogFileCtx *); int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t string_len); int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *, const char *, int); +int SCConfLogOpenRedis(ConfNode *conf, LogFileCtx *log_ctx); int SCConfLogReopen(LogFileCtx *); #endif /* __UTIL_LOGOPENFILE_H__ */ From b834e2d19ae66b0ea0798e26818f5b100c2dc7d5 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 24 May 2015 21:52:56 +0200 Subject: [PATCH 0830/2553] util-logopenfile: implement redis pipelining This patch implements redis pipelining. This consist in contacting the redis server every N events to minimize the number of TCP exchange. This is optional and setup via the configuration file. --- src/util-logopenfile.c | 78 +++++++++++++++++++++++++++++++++--------- src/util-logopenfile.h | 2 ++ suricata.yaml.in | 7 ++++ 3 files changed, 70 insertions(+), 17 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 519e4f7735fb..08a8f74be05f 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -362,6 +362,24 @@ int SCConfLogOpenRedis(ConfNode *redis_node, LogFileCtx *log_ctx) exit(EXIT_FAILURE); } + log_ctx->redis_setup.batch_size = 0; + + ConfNode *pipelining = ConfNodeLookupChild(redis_node, "pipelining"); + if (pipelining) { + int enabled = 0; + int ret; + intmax_t val; + ret = ConfGetChildValueBool(pipelining, "enabled", &enabled); + if (ret && enabled) { + ret = ConfGetChildValueInt(pipelining, "batch-size", &val); + if (ret) { + log_ctx->redis_setup.batch_size = val; + } else { + log_ctx->redis_setup.batch_size = 10; + } + } + } + if (!strcmp(redis_mode, "list")) { log_ctx->redis_setup.command = SCStrdup("LPUSH"); if (!log_ctx->redis_setup.command) { @@ -404,6 +422,10 @@ LogFileCtx *LogFileNewCtx(void) lf_ctx->Write = SCLogFileWrite; lf_ctx->Close = SCLogFileClose; +#ifdef HAVE_LIBHIREDIS + SC_ATOMIC_INIT(lf_ctx->redis_setup.batch_count); +#endif + return lf_ctx; } @@ -459,24 +481,46 @@ int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t s } #if HAVE_LIBHIREDIS else if (file_ctx->type == LOGFILE_TYPE_REDIS) { - /* FIXME go async here */ - redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s", - file_ctx->redis_setup.command, - file_ctx->redis_setup.key, - string); - switch (reply->type) { - case REDIS_REPLY_ERROR: - SCLogWarning(SC_WARN_NO_UNITTESTS, "Redis error: %s", reply->str); - break; - case REDIS_REPLY_INTEGER: - SCLogDebug("Redis integer %lld", reply->integer); - break; - default: - SCLogError(SC_ERR_INVALID_VALUE, - "Redis default triggered with %d", reply->type); - break; + /* FIXME go async here ? */ + if (file_ctx->redis_setup.batch_size) { + redisAppendCommand(file_ctx->redis, "%s %s %s", + file_ctx->redis_setup.command, + file_ctx->redis_setup.key, + string); + if (SC_ATOMIC_CAS(&file_ctx->redis_setup.batch_count, file_ctx->redis_setup.batch_size, 0)) { + redisReply *reply; + int i; + for(i = 0; i <= file_ctx->redis_setup.batch_size; i++) { + if (redisGetReply(file_ctx->redis, (void **)&reply) == REDIS_OK) { + freeReplyObject(reply); + } else { + /* FIXME treat error */ + SCLogInfo("Error when fetching reply"); + } + } + } else { + SC_ATOMIC_ADD(file_ctx->redis_setup.batch_count, 1); + } + } else { + redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s", + file_ctx->redis_setup.command, + file_ctx->redis_setup.key, + string); + + switch (reply->type) { + case REDIS_REPLY_ERROR: + SCLogWarning(SC_WARN_NO_UNITTESTS, "Redis error: %s", reply->str); + break; + case REDIS_REPLY_INTEGER: + SCLogDebug("Redis integer %lld", reply->integer); + break; + default: + SCLogError(SC_ERR_INVALID_VALUE, + "Redis default triggered with %d", reply->type); + break; + } + freeReplyObject(reply); } - freeReplyObject(reply); } #endif SCMutexUnlock(&file_ctx->fp_mutex); diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 82ea4eefdd35..966fc7545c21 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -54,6 +54,8 @@ typedef struct RedisSetup_ { char *command; char *key; char *sensor_name; + int batch_size; + SC_ATOMIC_DECLARE(int, batch_count); } RedisSetup; #endif diff --git a/suricata.yaml.in b/suricata.yaml.in index 43d5e17a4c55..e19b855b065c 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -109,6 +109,13 @@ outputs: # port: 6379 # mode: list ## possible values: list (default), channel # key: suricata ## key or channel to use (default to suricata) + # Redis pipelining set up. This will enable to only do a query every + # 'batch-size' events. This should lower the latency induced by network + # connection at the cost of some memory. There is no flushing implemented + # so this setting as to be reserved to high traffic suricata. + # pipelining: + # enabled: yes ## set enable to yes to enable query pipelining + # batch-size: 10 ## number of entry to keep in buffer types: - alert: # payload: yes # enable dumping payload in Base64 From 594f62b52305258b6a39be76b7bdf049c74298d3 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 25 May 2015 19:38:28 +0200 Subject: [PATCH 0831/2553] util-logopenfile: reconnect handling This patch implements reconnection handling for the redis output. A reconnect limitation has been implemented with a limitation of one connection per second. --- src/util-logopenfile.c | 91 +++++++++++++++++++++++++++++++++++++++++- src/util-logopenfile.h | 3 ++ 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 08a8f74be05f..c8b335b263e8 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -331,7 +331,16 @@ int SCConfLogReopen(LogFileCtx *log_ctx) } -#if HAVE_LIBHIREDIS +#ifdef HAVE_LIBHIREDIS + +static void SCLogFileCloseRedis(LogFileCtx *log_ctx) +{ + if (log_ctx->redis) + redisFree(log_ctx->redis); + log_ctx->redis_setup.tried = 0; + SC_ATOMIC_SET(log_ctx->redis_setup.batch_count, 0); +} + int SCConfLogOpenRedis(ConfNode *redis_node, LogFileCtx *log_ctx) { const char *redis_server = NULL; @@ -398,10 +407,50 @@ int SCConfLogOpenRedis(ConfNode *redis_node, LogFileCtx *log_ctx) SCLogError(SC_ERR_SOCKET, "Error connecting to redis server: %s", c->errstr); exit(EXIT_FAILURE); } + + /* store server params for reconnection */ + log_ctx->redis_setup.server = SCStrdup(redis_server); + if (!log_ctx->redis_setup.server) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating redis server string"); + exit(EXIT_FAILURE); + } + log_ctx->redis_setup.port = atoi(redis_port); + log_ctx->redis_setup.tried = 0; + log_ctx->redis = c; + log_ctx->Close = SCLogFileCloseRedis; + return 0; } + +int SCConfLogReopenRedis(LogFileCtx *log_ctx) +{ + if (log_ctx->redis != NULL) { + redisFree(log_ctx->redis); + log_ctx->redis = NULL; + } + + /* only try to reconnect once per second */ + if (log_ctx->redis_setup.tried >= time(NULL)) { + return -1; + } + + redisContext *c = redisConnect(log_ctx->redis_setup.server, log_ctx->redis_setup.port); + if (c != NULL && c->err) { + if (log_ctx->redis_setup.tried == 0) { + SCLogError(SC_ERR_SOCKET, "Error connecting to redis server: %s\n", c->errstr); + } + redisFree(c); + log_ctx->redis_setup.tried = time(NULL); + return -1; + } + log_ctx->redis = c; + log_ctx->redis_setup.tried = 0; + SC_ATOMIC_SET(log_ctx->redis_setup.batch_count, 0); + return 0; +} + #endif /** \brief LogFileNewCtx() Get a new LogFileCtx @@ -448,6 +497,9 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) #ifdef HAVE_LIBHIREDIS if (lf_ctx->type == LOGFILE_TYPE_REDIS && lf_ctx->redis) { redisFree(lf_ctx->redis); + SCFree(lf_ctx->redis_setup.server); + SCFree(lf_ctx->redis_setup.command); + SCFree(lf_ctx->redis_setup.key); } #endif @@ -481,6 +533,16 @@ int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t s } #if HAVE_LIBHIREDIS else if (file_ctx->type == LOGFILE_TYPE_REDIS) { + if (file_ctx->redis == NULL) { + /* FIXME temporisation */ + SCConfLogReopenRedis(file_ctx); + if (file_ctx->redis == NULL) { + SCMutexUnlock(&file_ctx->fp_mutex); + return -1; + } else { + SCLogInfo("Reconnected to redis server"); + } + } /* FIXME go async here ? */ if (file_ctx->redis_setup.batch_size) { redisAppendCommand(file_ctx->redis, "%s %s %s", @@ -495,7 +557,30 @@ int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t s freeReplyObject(reply); } else { /* FIXME treat error */ - SCLogInfo("Error when fetching reply"); + if (file_ctx->redis->err) { + SCLogInfo("Error when fetching reply: %s (%d)", + file_ctx->redis->errstr, + file_ctx->redis->err); + } + switch (file_ctx->redis->err) { + case REDIS_ERR_EOF: + case REDIS_ERR_IO: + SCLogInfo("Reopening connection to redis server"); + SCConfLogReopenRedis(file_ctx); + if (file_ctx->redis) { + SCLogInfo("Reconnected to redis server"); + SCMutexUnlock(&file_ctx->fp_mutex); + return 0; + } else { + SCLogInfo("Unable to reconnect to redis server"); + SCMutexUnlock(&file_ctx->fp_mutex); + return 0; + } + break; + default: + SCLogInfo("Unsupported error code %d", + file_ctx->redis->err); + } } } } else { @@ -510,6 +595,7 @@ int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t s switch (reply->type) { case REDIS_REPLY_ERROR: SCLogWarning(SC_WARN_NO_UNITTESTS, "Redis error: %s", reply->str); + SCConfLogReopenRedis(file_ctx); break; case REDIS_REPLY_INTEGER: SCLogDebug("Redis integer %lld", reply->integer); @@ -517,6 +603,7 @@ int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t s default: SCLogError(SC_ERR_INVALID_VALUE, "Redis default triggered with %d", reply->type); + SCConfLogReopenRedis(file_ctx); break; } freeReplyObject(reply); diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 966fc7545c21..d1efee9f6776 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -56,6 +56,9 @@ typedef struct RedisSetup_ { char *sensor_name; int batch_size; SC_ATOMIC_DECLARE(int, batch_count); + char *server; + int port; + time_t tried; } RedisSetup; #endif From f11b269ef134d1822caa0eb9249fcf9b1a0a66b9 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 26 May 2015 11:31:41 +0200 Subject: [PATCH 0832/2553] redis-output: fix sensor-name code The sensor-name was not freed at exist and the result of SCStrdup was not checked. --- src/output-json.c | 6 ++++++ src/util-logopenfile.c | 1 + 2 files changed, 7 insertions(+) diff --git a/src/output-json.c b/src/output-json.c index 99032a5481cb..a4364d2d9d9c 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -546,6 +546,12 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) sensor_name = hostname; } json_ctx->file_ctx->redis_setup.sensor_name = SCStrdup(sensor_name); + if (json_ctx->file_ctx->redis_setup.sensor_name == NULL) { + LogFileFreeCtx(json_ctx->file_ctx); + SCFree(json_ctx); + SCFree(output_ctx); + return NULL; + } if (SCConfLogOpenRedis(redis_node, json_ctx->file_ctx) < 0) { LogFileFreeCtx(json_ctx->file_ctx); diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index c8b335b263e8..89f59d8dac93 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -500,6 +500,7 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) SCFree(lf_ctx->redis_setup.server); SCFree(lf_ctx->redis_setup.command); SCFree(lf_ctx->redis_setup.key); + SCFree(lf_ctx->redis_setup.sensor_name); } #endif From e9d26dd510ebdd3c02727861e05e3ba1de5c76ae Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 26 May 2015 11:53:06 +0200 Subject: [PATCH 0833/2553] util-logopenfile: use a function for redis write --- src/util-logopenfile.c | 157 +++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 76 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 89f59d8dac93..33f7877720b4 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -519,6 +519,85 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) SCReturnInt(1); } +#ifdef HAVE_LIBHIREDIS +static int LogFileWriteRedis(LogFileCtx *file_ctx, char *string, size_t string_len) +{ + if (file_ctx->redis == NULL) { + SCConfLogReopenRedis(file_ctx); + if (file_ctx->redis == NULL) { + return -1; + } else { + SCLogInfo("Reconnected to redis server"); + } + } + /* TODO go async here ? */ + if (file_ctx->redis_setup.batch_size) { + redisAppendCommand(file_ctx->redis, "%s %s %s", + file_ctx->redis_setup.command, + file_ctx->redis_setup.key, + string); + if (SC_ATOMIC_CAS(&file_ctx->redis_setup.batch_count, file_ctx->redis_setup.batch_size, 0)) { + redisReply *reply; + int i; + for (i = 0; i <= file_ctx->redis_setup.batch_size; i++) { + if (redisGetReply(file_ctx->redis, (void **)&reply) == REDIS_OK) { + freeReplyObject(reply); + } else { + if (file_ctx->redis->err) { + SCLogInfo("Error when fetching reply: %s (%d)", + file_ctx->redis->errstr, + file_ctx->redis->err); + } + switch (file_ctx->redis->err) { + case REDIS_ERR_EOF: + case REDIS_ERR_IO: + SCLogInfo("Reopening connection to redis server"); + SCConfLogReopenRedis(file_ctx); + if (file_ctx->redis) { + SCLogInfo("Reconnected to redis server"); + return 0; + } else { + SCLogInfo("Unable to reconnect to redis server"); + return 0; + } + break; + default: + SCLogWarning(SC_ERR_INVALID_VALUE, + "Unsupported error code %d", + file_ctx->redis->err); + return 0; + } + } + } + } else { + SC_ATOMIC_ADD(file_ctx->redis_setup.batch_count, 1); + } + } else { + redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s", + file_ctx->redis_setup.command, + file_ctx->redis_setup.key, + string); + + switch (reply->type) { + case REDIS_REPLY_ERROR: + SCLogWarning(SC_ERR_SOCKET, "Redis error: %s", reply->str); + SCConfLogReopenRedis(file_ctx); + break; + case REDIS_REPLY_INTEGER: + SCLogDebug("Redis integer %lld", reply->integer); + break; + default: + SCLogError(SC_ERR_INVALID_VALUE, + "Redis default triggered with %d", reply->type); + SCConfLogReopenRedis(file_ctx); + break; + } + freeReplyObject(reply); + } + return 0; +} +#endif + int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t string_len) { SCMutexLock(&file_ctx->fp_mutex); @@ -532,83 +611,9 @@ int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t s file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), MEMBUFFER_OFFSET(buffer), file_ctx); } -#if HAVE_LIBHIREDIS +#ifdef HAVE_LIBHIREDIS else if (file_ctx->type == LOGFILE_TYPE_REDIS) { - if (file_ctx->redis == NULL) { - /* FIXME temporisation */ - SCConfLogReopenRedis(file_ctx); - if (file_ctx->redis == NULL) { - SCMutexUnlock(&file_ctx->fp_mutex); - return -1; - } else { - SCLogInfo("Reconnected to redis server"); - } - } - /* FIXME go async here ? */ - if (file_ctx->redis_setup.batch_size) { - redisAppendCommand(file_ctx->redis, "%s %s %s", - file_ctx->redis_setup.command, - file_ctx->redis_setup.key, - string); - if (SC_ATOMIC_CAS(&file_ctx->redis_setup.batch_count, file_ctx->redis_setup.batch_size, 0)) { - redisReply *reply; - int i; - for(i = 0; i <= file_ctx->redis_setup.batch_size; i++) { - if (redisGetReply(file_ctx->redis, (void **)&reply) == REDIS_OK) { - freeReplyObject(reply); - } else { - /* FIXME treat error */ - if (file_ctx->redis->err) { - SCLogInfo("Error when fetching reply: %s (%d)", - file_ctx->redis->errstr, - file_ctx->redis->err); - } - switch (file_ctx->redis->err) { - case REDIS_ERR_EOF: - case REDIS_ERR_IO: - SCLogInfo("Reopening connection to redis server"); - SCConfLogReopenRedis(file_ctx); - if (file_ctx->redis) { - SCLogInfo("Reconnected to redis server"); - SCMutexUnlock(&file_ctx->fp_mutex); - return 0; - } else { - SCLogInfo("Unable to reconnect to redis server"); - SCMutexUnlock(&file_ctx->fp_mutex); - return 0; - } - break; - default: - SCLogInfo("Unsupported error code %d", - file_ctx->redis->err); - } - } - } - } else { - SC_ATOMIC_ADD(file_ctx->redis_setup.batch_count, 1); - } - } else { - redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s", - file_ctx->redis_setup.command, - file_ctx->redis_setup.key, - string); - - switch (reply->type) { - case REDIS_REPLY_ERROR: - SCLogWarning(SC_WARN_NO_UNITTESTS, "Redis error: %s", reply->str); - SCConfLogReopenRedis(file_ctx); - break; - case REDIS_REPLY_INTEGER: - SCLogDebug("Redis integer %lld", reply->integer); - break; - default: - SCLogError(SC_ERR_INVALID_VALUE, - "Redis default triggered with %d", reply->type); - SCConfLogReopenRedis(file_ctx); - break; - } - freeReplyObject(reply); - } + LogFileWriteRedis(file_ctx, string, string_len); } #endif SCMutexUnlock(&file_ctx->fp_mutex); From 1b0f2774f2c5d5df0cd0beeb0133ff9c1729bc51 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 1 Jun 2015 23:14:41 +0200 Subject: [PATCH 0834/2553] util-logopenfile: don't use atomic for batch_count --- src/util-logopenfile.c | 11 ++++++----- src/util-logopenfile.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 33f7877720b4..fe22ed538db1 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -338,7 +338,7 @@ static void SCLogFileCloseRedis(LogFileCtx *log_ctx) if (log_ctx->redis) redisFree(log_ctx->redis); log_ctx->redis_setup.tried = 0; - SC_ATOMIC_SET(log_ctx->redis_setup.batch_count, 0); + log_ctx->redis_setup.batch_count = 0; } int SCConfLogOpenRedis(ConfNode *redis_node, LogFileCtx *log_ctx) @@ -447,7 +447,7 @@ int SCConfLogReopenRedis(LogFileCtx *log_ctx) } log_ctx->redis = c; log_ctx->redis_setup.tried = 0; - SC_ATOMIC_SET(log_ctx->redis_setup.batch_count, 0); + log_ctx->redis_setup.batch_count = 0; return 0; } @@ -472,7 +472,7 @@ LogFileCtx *LogFileNewCtx(void) lf_ctx->Close = SCLogFileClose; #ifdef HAVE_LIBHIREDIS - SC_ATOMIC_INIT(lf_ctx->redis_setup.batch_count); + lf_ctx->redis_setup.batch_count = 0; #endif return lf_ctx; @@ -536,9 +536,10 @@ static int LogFileWriteRedis(LogFileCtx *file_ctx, char *string, size_t string_ file_ctx->redis_setup.command, file_ctx->redis_setup.key, string); - if (SC_ATOMIC_CAS(&file_ctx->redis_setup.batch_count, file_ctx->redis_setup.batch_size, 0)) { + if (file_ctx->redis_setup.batch_count == file_ctx->redis_setup.batch_size) { redisReply *reply; int i; + file_ctx->redis_setup.batch_count = 0; for (i = 0; i <= file_ctx->redis_setup.batch_size; i++) { if (redisGetReply(file_ctx->redis, (void **)&reply) == REDIS_OK) { freeReplyObject(reply); @@ -570,7 +571,7 @@ static int LogFileWriteRedis(LogFileCtx *file_ctx, char *string, size_t string_ } } } else { - SC_ATOMIC_ADD(file_ctx->redis_setup.batch_count, 1); + file_ctx->redis_setup.batch_count++; } } else { redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s", diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index d1efee9f6776..167286d4bfab 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -55,7 +55,7 @@ typedef struct RedisSetup_ { char *key; char *sensor_name; int batch_size; - SC_ATOMIC_DECLARE(int, batch_count); + int batch_count; char *server; int port; time_t tried; From c5d939834ffbecc9cc7cefbed1657b4412ccd95d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 26 May 2015 12:02:49 +0200 Subject: [PATCH 0835/2553] util-logopenfile: cleaner free function --- src/util-logopenfile.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index fe22ed538db1..91a1400ee550 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -495,12 +495,17 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) } #ifdef HAVE_LIBHIREDIS - if (lf_ctx->type == LOGFILE_TYPE_REDIS && lf_ctx->redis) { - redisFree(lf_ctx->redis); - SCFree(lf_ctx->redis_setup.server); - SCFree(lf_ctx->redis_setup.command); - SCFree(lf_ctx->redis_setup.key); - SCFree(lf_ctx->redis_setup.sensor_name); + if (lf_ctx->type == LOGFILE_TYPE_REDIS) { + if (lf_ctx->redis) + redisFree(lf_ctx->redis); + if (lf_ctx->redis_setup.server) + SCFree(lf_ctx->redis_setup.server); + if (lf_ctx->redis_setup.command) + SCFree(lf_ctx->redis_setup.command); + if (lf_ctx->redis_setup.key) + SCFree(lf_ctx->redis_setup.key); + if (lf_ctx->redis_setup.sensor_name) + SCFree(lf_ctx->redis_setup.sensor_name); } #endif From 404e66041091008dc67b5fa4ea4f814384d63af4 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 26 May 2015 12:06:26 +0200 Subject: [PATCH 0836/2553] util-logopenfile: don't lock syslog write --- src/util-logopenfile.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 91a1400ee550..431414fa5bd7 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -606,23 +606,25 @@ static int LogFileWriteRedis(LogFileCtx *file_ctx, char *string, size_t string_ int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t string_len) { - SCMutexLock(&file_ctx->fp_mutex); if (file_ctx->type == LOGFILE_TYPE_SYSLOG) { syslog(file_ctx->syslog_setup.alert_syslog_level, "%s", string); } else if (file_ctx->type == LOGFILE_TYPE_FILE || file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) { + SCMutexLock(&file_ctx->fp_mutex); MemBufferWriteString(buffer, "%s\n", string); file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), MEMBUFFER_OFFSET(buffer), file_ctx); + SCMutexUnlock(&file_ctx->fp_mutex); } #ifdef HAVE_LIBHIREDIS else if (file_ctx->type == LOGFILE_TYPE_REDIS) { + SCMutexLock(&file_ctx->fp_mutex); LogFileWriteRedis(file_ctx, string, string_len); + SCMutexUnlock(&file_ctx->fp_mutex); } #endif - SCMutexUnlock(&file_ctx->fp_mutex); return 0; } From 7e3a5a0db28bebd5ce0deb4a4a54461cac270c86 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 29 May 2015 22:14:22 +0200 Subject: [PATCH 0837/2553] util-logopenfile: log queued events at exit Do a redis query at exit to log possibly existing events. --- src/util-logopenfile.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 431414fa5bd7..159c57eb52fe 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -335,8 +335,17 @@ int SCConfLogReopen(LogFileCtx *log_ctx) static void SCLogFileCloseRedis(LogFileCtx *log_ctx) { - if (log_ctx->redis) + if (log_ctx->redis) { + redisReply *reply; + int i; + for (i = 0; i < log_ctx->redis_setup.batch_count; i++) { + redisGetReply(log_ctx->redis, (void **)&reply); + if (reply) + freeReplyObject(reply); + } redisFree(log_ctx->redis); + log_ctx->redis = NULL; + } log_ctx->redis_setup.tried = 0; log_ctx->redis_setup.batch_count = 0; } From 2ea4bbc4921cd6a34824e8ee54d56370577a5160 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 17 Sep 2015 10:28:08 +0200 Subject: [PATCH 0838/2553] util-logopenfile: move sensor_name to filectx We will now output the sensor name independantly of the output method if it is set in the YAML file. In the case of redis we are using the hostname value if unset. --- src/output-json.c | 28 +++++++++++++++++++--------- src/util-logopenfile.c | 5 +++-- src/util-logopenfile.h | 4 +++- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index a4364d2d9d9c..f80120d47e68 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -339,12 +339,10 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) { char *js_s = NULL; -#ifdef HAVE_LIBHIREDIS - if (file_ctx->type == LOGFILE_TYPE_REDIS) { + if (file_ctx->sensor_name) { json_object_set_new(js, "host", - json_string(file_ctx->redis_setup.sensor_name)); + json_string(file_ctx->sensor_name)); } -#endif js_s = json_dumps(js, JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| @@ -416,6 +414,9 @@ void OutputJsonExitPrintStats(ThreadVars *tv, void *data) OutputCtx *OutputJsonInitCtx(ConfNode *conf) { OutputJsonCtx *json_ctx = SCCalloc(1, sizeof(OutputJsonCtx));; + + const char *sensor_name = ConfNodeLookupChildValue(conf, "sensor-name"); + if (unlikely(json_ctx == NULL)) { SCLogDebug("AlertJsonInitCtx: Could not create new LogFileCtx"); return NULL; @@ -428,6 +429,17 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) return NULL; } + if (sensor_name) { + json_ctx->file_ctx->sensor_name = SCStrdup(sensor_name); + if (json_ctx->file_ctx->sensor_name == NULL) { + LogFileFreeCtx(json_ctx->file_ctx); + SCFree(json_ctx); + return NULL; + } + } else { + json_ctx->file_ctx->sensor_name = NULL; + } + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { LogFileFreeCtx(json_ctx->file_ctx); @@ -539,14 +551,12 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) #ifdef HAVE_LIBHIREDIS else if (json_ctx->json_out == LOGFILE_TYPE_REDIS) { ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); - const char *sensor_name = ConfNodeLookupChildValue(conf, "sensor-name"); - if (!sensor_name) { + if (!json_ctx->file_ctx->sensor_name) { char hostname[1024]; gethostname(hostname, 1023); - sensor_name = hostname; + json_ctx->file_ctx->sensor_name = SCStrdup(hostname); } - json_ctx->file_ctx->redis_setup.sensor_name = SCStrdup(sensor_name); - if (json_ctx->file_ctx->redis_setup.sensor_name == NULL) { + if (json_ctx->file_ctx->sensor_name == NULL) { LogFileFreeCtx(json_ctx->file_ctx); SCFree(json_ctx); SCFree(output_ctx); diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 159c57eb52fe..cce748e84a30 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -513,8 +513,6 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) SCFree(lf_ctx->redis_setup.command); if (lf_ctx->redis_setup.key) SCFree(lf_ctx->redis_setup.key); - if (lf_ctx->redis_setup.sensor_name) - SCFree(lf_ctx->redis_setup.sensor_name); } #endif @@ -526,6 +524,9 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) if(lf_ctx->filename != NULL) SCFree(lf_ctx->filename); + if (lf_ctx->sensor_name) + SCFree(lf_ctx->sensor_name); + OutputUnregisterFileRotationFlag(&lf_ctx->rotation_flag); SCFree(lf_ctx); diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 167286d4bfab..06175b2b090f 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -53,7 +53,6 @@ typedef struct RedisSetup_ { enum RedisMode mode; char *command; char *key; - char *sensor_name; int batch_size; int batch_count; char *server; @@ -92,6 +91,9 @@ typedef struct LogFileCtx_ { /** The name of the file */ char *filename; + /** Suricata sensor name */ + char *sensor_name; + /** Handle auto-connecting / reconnecting sockets */ int is_sock; int sock_type; From d88e1334283b37ee2c3d409d38632062d261c67e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 14 Oct 2015 16:40:44 +0200 Subject: [PATCH 0839/2553] util-logopenfile: don't allocate redis command As we only have two different commands we don't need to allocate it and can use pointer to global variables. --- src/util-logopenfile.c | 9 +++++---- src/util-logopenfile.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index cce748e84a30..c91e039c32dd 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -34,6 +34,9 @@ #include "util-logopenfile.h" #include "util-logopenfile-tile.h" +const char * redis_push_cmd = "LPUSH"; +const char * redis_publish_cmd = "PUBLISH"; + /** \brief connect to the indicated local stream socket, logging any errors * \param path filesystem path to connect to * \param log_err, non-zero if connect failure should be logged. @@ -399,13 +402,13 @@ int SCConfLogOpenRedis(ConfNode *redis_node, LogFileCtx *log_ctx) } if (!strcmp(redis_mode, "list")) { - log_ctx->redis_setup.command = SCStrdup("LPUSH"); + log_ctx->redis_setup.command = redis_push_cmd; if (!log_ctx->redis_setup.command) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); exit(EXIT_FAILURE); } } else { - log_ctx->redis_setup.command = SCStrdup("PUBLISH"); + log_ctx->redis_setup.command = redis_publish_cmd; if (!log_ctx->redis_setup.command) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); exit(EXIT_FAILURE); @@ -509,8 +512,6 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) redisFree(lf_ctx->redis); if (lf_ctx->redis_setup.server) SCFree(lf_ctx->redis_setup.server); - if (lf_ctx->redis_setup.command) - SCFree(lf_ctx->redis_setup.command); if (lf_ctx->redis_setup.key) SCFree(lf_ctx->redis_setup.key); } diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 06175b2b090f..d2924503d78f 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -51,7 +51,7 @@ enum RedisMode { REDIS_LIST, REDIS_CHANNEL }; typedef struct RedisSetup_ { enum RedisMode mode; - char *command; + const char *command; char *key; int batch_size; int batch_count; From c4850c1d8fa8e1902141b92766d2f41e35ebbb0c Mon Sep 17 00:00:00 2001 From: cardigliano Date: Thu, 22 Oct 2015 01:26:54 +0200 Subject: [PATCH 0840/2553] pfring pkt acq: use zero-copy recv in workers runmode This patch removes packet copy when suricata is running in workers runmode, packet copy is not needed in this case since packets are processed in sequence. --- src/source-pfring.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index 3b2b52df23e0..bac91939abcb 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -125,6 +125,10 @@ static SCMutex pfring_bpf_set_filter_lock = SCMUTEX_INITIALIZER; #define LIBPFRING_REENTRANT 0 #define LIBPFRING_WAIT_FOR_INCOMING 1 +typedef enum { + PFRING_FLAGS_ZERO_COPY = 0x1 +} PfringThreadVarsFlags; + /** * \brief Structure to hold thread specific variables. */ @@ -140,6 +144,8 @@ typedef struct PfringThreadVars_ uint16_t capture_kernel_packets; uint16_t capture_kernel_drops; + uint32_t flags; + ThreadVars *tv; TmSlot *slot; @@ -296,6 +302,8 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) TmSlot *s = (TmSlot *)slot; time_t last_dump = 0; struct timeval current_time; + u_int buffer_size; + u_char *pkt_buffer; ptv->slot = s->slot_next; @@ -325,16 +333,23 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) /* Some flavours of PF_RING may fail to set timestamp - see PF-RING-enabled libpcap code*/ hdr.ts.tv_sec = hdr.ts.tv_usec = 0; + /* Check for Zero-copy mode */ + if (ptv->flags & PFRING_FLAGS_ZERO_COPY) { + buffer_size = 0; + pkt_buffer = NULL; + } else { + buffer_size = GET_PKT_DIRECT_MAX_SIZE(p); + pkt_buffer = GET_PKT_DIRECT_DATA(p); + } + /* Depending on what compile time options are used for pfring we either return 0 or -1 on error and always 1 for success */ - u_char *pkt_buffer = GET_PKT_DIRECT_DATA(p); - u_int buffer_size = GET_PKT_DIRECT_MAX_SIZE(p); int r = pfring_recv(ptv->pd, &pkt_buffer, buffer_size, &hdr, LIBPFRING_WAIT_FOR_INCOMING); - /* Check for Zero-copy if buffer size is zero */ - if (buffer_size == 0) { + /* Check for Zero-copy mode */ + if (ptv->flags & PFRING_FLAGS_ZERO_COPY) { PacketSetData(p, pkt_buffer, hdr.caplen); } @@ -386,7 +401,7 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) u_int32_t version = 0; PfringIfaceConfig *pfconf = (PfringIfaceConfig *) initdata; unsigned int opflag; - + char const *active_runmode = RunmodeGetActive(); if (pfconf == NULL) return TM_ECODE_FAILED; @@ -415,6 +430,12 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_FAILED); } + /* enable zero-copy mode for workers runmode */ + if (active_runmode && strcmp("workers", active_runmode) == 0) { + ptv->flags |= PFRING_FLAGS_ZERO_COPY; + SCLogInfo("Enabling zero-copy for %s", ptv->interface); + } + ptv->checksum_mode = pfconf->checksum_mode; opflag = PF_RING_REENTRANT | PF_RING_PROMISC; From 70c98c1ff25a143eb156144d3e517d6d5251c7b1 Mon Sep 17 00:00:00 2001 From: cardigliano Date: Thu, 22 Oct 2015 01:35:04 +0200 Subject: [PATCH 0841/2553] pfring pkt acq: removed reentrant flag PF_RING_REENTRANT is not needed as each pfring socket is used by a single thread. --- src/source-pfring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index bac91939abcb..3e9db24b1104 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -438,7 +438,7 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->checksum_mode = pfconf->checksum_mode; - opflag = PF_RING_REENTRANT | PF_RING_PROMISC; + opflag = PF_RING_PROMISC; /* if suri uses VLAN and if we have a recent kernel, we need * to use parsed_pkt to get VLAN info */ From 86711a1332f7082a688ff68ad38f2641bd20ee26 Mon Sep 17 00:00:00 2001 From: cardigliano Date: Thu, 22 Oct 2015 01:43:41 +0200 Subject: [PATCH 0842/2553] pfring pkt acq: capture loop optimisation For each packet the capture module checks whether it is time to dump stats calling TimeGet(). TimeGet() is an expensive function using gettimeofday() or SCSpinLock() which affect performance. Since gettimeofday() is already called for setting packet timestamp, it is more efficient to use the packet timestamp directly. --- src/source-pfring.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index 3e9db24b1104..3e2ba6a8563c 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -301,7 +301,6 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) struct pfring_pkthdr hdr; TmSlot *s = (TmSlot *)slot; time_t last_dump = 0; - struct timeval current_time; u_int buffer_size; u_char *pkt_buffer; @@ -365,10 +364,9 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) } /* Trigger one dump of stats every second */ - TimeGet(¤t_time); - if (current_time.tv_sec != last_dump) { + if (p->ts.tv_sec != last_dump) { PfringDumpCounters(ptv); - last_dump = current_time.tv_sec; + last_dump = p->ts.tv_sec; } } else { SCLogError(SC_ERR_PF_RING_RECV,"pfring_recv error %" PRId32 "", r); From 77624701e73aade1706836591a750e4aec13520e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Oct 2015 09:53:48 +0200 Subject: [PATCH 0843/2553] htp: cleanup, remove unused declaration --- src/app-layer-htp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 452a607e9c2b..0abcda3bb4c5 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -78,10 +78,6 @@ #include "util-memcmp.h" -#ifndef HAVE_HTP_SET_PATH_DECODE_U_ENCODING -void htp_config_set_path_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding); -#endif - //#define PRINT /** Fast lookup tree (radix) for the various HTP configurations */ From ca3916881fe598b2b9b10f7f90d3636f938a1db5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Oct 2015 18:01:55 +0200 Subject: [PATCH 0844/2553] threading: store thread module flags in threadvars --- src/threadvars.h | 3 +++ src/tm-threads.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/threadvars.h b/src/threadvars.h index a632a23b4f27..79a2b34dc4fd 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -71,6 +71,9 @@ typedef struct ThreadVars_ { /** no of times the thread has been restarted on failure */ uint8_t restarted; + /** TmModule::flags for each module part of this thread */ + uint8_t tmm_flags; + /** local id */ int id; diff --git a/src/tm-threads.c b/src/tm-threads.c index c6828b4071ad..b47d4b050dd9 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -730,6 +730,7 @@ static inline TmSlot * _TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void * * received a TM as arg, if it didn't exist */ slot->tm_id = TmModuleGetIDForTM(tm); + tv->tmm_flags |= tm->flags; tv->cap_flags |= tm->cap_flags; if (tv->tm_slots == NULL) { From 8d06d7bccc431fda671bacca482fd98264b660fb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Oct 2015 18:09:24 +0200 Subject: [PATCH 0845/2553] threads: add func to count running threads of types --- src/tm-threads.c | 23 +++++++++++++++++++++++ src/tm-threads.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/src/tm-threads.c b/src/tm-threads.c index b47d4b050dd9..2b26404fbaaf 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -2034,6 +2034,29 @@ ThreadVars *TmThreadsGetCallingThread(void) return NULL; } +/** + * \brief returns a count of all the threads that match the flag + */ +uint32_t TmThreadCountThreadsByTmmFlags(uint8_t flags) +{ + ThreadVars *tv = NULL; + int i = 0; + uint32_t cnt = 0; + + SCMutexLock(&tv_root_lock); + for (i = 0; i < TVT_MAX; i++) { + tv = tv_root[i]; + while (tv != NULL) { + if ((tv->tmm_flags & flags) == flags) + cnt++; + + tv = tv->next; + } + } + SCMutexUnlock(&tv_root_lock); + return cnt; +} + typedef struct Thread_ { ThreadVars *tv; /**< threadvars structure */ const char *name; diff --git a/src/tm-threads.h b/src/tm-threads.h index 9b9fd620dfd4..397fbd2e86b0 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -132,6 +132,8 @@ void TmThreadDisablePacketThreads(void); void TmThreadDisableReceiveThreads(void); TmSlot *TmThreadGetFirstTmSlotForPartialPattern(const char *); +uint32_t TmThreadCountThreadsByTmmFlags(uint8_t flags); + /** * \brief Process the rest of the functions (if any) and queue. */ From 7f8795c7563827f090d8679cb35847af0085fc56 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Oct 2015 18:29:10 +0200 Subject: [PATCH 0846/2553] threading: avoid autofp deadlock When there are many threads and/or the packet pool (max-pending-packets) is small, a potential dead lock exists between the packet pool return pool logic and the capture threads. The autofp workers together can have all the packets in their return pools, while the capture thread(s) are waiting at an empty pool. A race between the worker threads and the capture thread, where the latter signals the former, is lost by the capture thread. Now everyone is waiting. To avoid this scenario, this patch makes the previously hardcoded 'return pool' threshold dynamic based on the number of threads and the packet pool size. It sets the threshold to the max pending packets value, divided by the number of lister threads. The max value hasn't changed. Normally, in the autofp runmode these are the stream/detect/log worker threads. The max_pending_return_packets value needs to stay below the packet pool size of the 'producers' (normally pkt capture threads but also flow timeout injection) to avoid the deadlock. As it's quite impossible at this time to learn how many threads will be created before starting the runmodes, and thus spawning the threads and already initializing the packet pools, this code sets a global variable after runmode setup, but before the threads are 'unpaused'. --- src/suricata.c | 1 + src/tmqh-packetpool.c | 36 +++++++++++++++++++++++++++++++++++- src/tmqh-packetpool.h | 1 + 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/suricata.c b/src/suricata.c index 6c45c57e9931..8ddd79fd7a60 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2367,6 +2367,7 @@ int main(int argc, char **argv) } (void) SC_ATOMIC_CAS(&engine_stage, SURICATA_INIT, SURICATA_RUNTIME); + PacketPoolPostRunmodes(); /* Un-pause all the paused threads */ TmThreadContinueThreads(); diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index a1f19dca467c..75139254ee67 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -38,6 +38,8 @@ #include "stream-tcp-reassemble.h" #include "tm-queuehandlers.h" +#include "tm-threads.h" +#include "tm-modules.h" #include "pkt-var.h" @@ -50,6 +52,7 @@ /* Number of freed packet to save for one pool before freeing them. */ #define MAX_PENDING_RETURN_PACKETS 32 +static uint32_t max_pending_return_packets = MAX_PENDING_RETURN_PACKETS; #ifdef TLS __thread PktPool thread_pkt_pool; @@ -313,7 +316,7 @@ void PacketPoolReturnPacket(Packet *p) p->next = my_pool->pending_head; my_pool->pending_head = p; my_pool->pending_count++; - if (SC_ATOMIC_GET(pool->return_stack.sync_now) || my_pool->pending_count > MAX_PENDING_RETURN_PACKETS) { + if (SC_ATOMIC_GET(pool->return_stack.sync_now) || my_pool->pending_count > max_pending_return_packets) { /* Return the entire list of pending packets. */ SCMutexLock(&pool->return_stack.mutex); my_pool->pending_tail->next = pool->return_stack.head; @@ -563,3 +566,34 @@ void TmqhReleasePacketsToPacketPool(PacketQueue *pq) return; } + +/** + * \brief Set the max_pending_return_packets value + * + * Set it to the max pending packets value, devided by the number + * of lister threads. Normally, in autofp these are the stream/detect/log + * worker threads. + * + * The max_pending_return_packets value needs to stay below the packet + * pool size of the 'producers' (normally pkt capture threads but also + * flow timeout injection ) to avoid a deadlock where all the 'workers' + * keep packets in their return pools, while the capture thread can't + * continue because its pool is empty. + */ +void PacketPoolPostRunmodes(void) +{ + extern intmax_t max_pending_packets; + + uint32_t threads = TmThreadCountThreadsByTmmFlags(TM_FLAG_DETECT_TM); + if (threads == 0) + return; + if (threads > max_pending_packets) + return; + + uint32_t packets = (max_pending_packets / threads) - 1; + if (packets < max_pending_return_packets) + max_pending_return_packets = packets; + + SCLogDebug("detect threads %u, max packets %u, max_pending_return_packets %u", + threads, (uint)threads, max_pending_return_packets); +} diff --git a/src/tmqh-packetpool.h b/src/tmqh-packetpool.h index ab45184c654f..2b6b90b04e95 100644 --- a/src/tmqh-packetpool.h +++ b/src/tmqh-packetpool.h @@ -78,5 +78,6 @@ void PacketPoolReturnPacket(Packet *p); void PacketPoolInit(void); void PacketPoolInitEmpty(void); void PacketPoolDestroy(void); +void PacketPoolPostRunmodes(void); #endif /* __TMQH_PACKETPOOL_H__ */ From c06dfe6e26e16b0c8e3d4965b5a0ddafc2553174 Mon Sep 17 00:00:00 2001 From: cardigliano Date: Thu, 22 Oct 2015 11:55:57 +0200 Subject: [PATCH 0847/2553] pfring pkt acq: keep running on 'pfring_set_cluster' failure when cluster is not required Suricata creates a pfring cluster with a default ID = 1 when not explicitly configured, unless the device has prefix 'dna' or 'zc'. Since pf_ring also supports other cards implementing kernel-bypass (cluster not supported), this is preventing those cards from running on top of this module. This patch stops suricata on 'pfring_set_cluster' failure only when error code != PF_RING_ERROR_NOT_SUPPORTED or cluster ID has not been explicitly configured. --- src/runmode-pfring.c | 4 ++++ src/source-pfring.c | 7 +++++-- src/source-pfring.h | 6 ++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/runmode-pfring.c b/src/runmode-pfring.c index fbbd8c917234..f08bdad80296 100644 --- a/src/runmode-pfring.c +++ b/src/runmode-pfring.c @@ -109,6 +109,7 @@ void *OldParsePfringConfig(const char *iface) } strlcpy(pfconf->iface, iface, sizeof(pfconf->iface)); + pfconf->flags = 0; pfconf->threads = 1; pfconf->cluster_id = 1; #ifdef HAVE_PFRING @@ -143,6 +144,7 @@ void *OldParsePfringConfig(const char *iface) SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); } else { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); + pfconf->flags |= PFRING_CONF_FLAGS_CLUSTER; SCLogDebug("Going to use cluster-id %" PRId32, pfconf->cluster_id); } @@ -263,6 +265,7 @@ void *ParsePfringConfig(const char *iface) /* command line value has precedence */ if (ConfGet("pfring.cluster-id", &tmpclusterid) == 1) { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); + pfconf->flags |= PFRING_CONF_FLAGS_CLUSTER; SCLogDebug("Going to use command-line provided cluster-id %" PRId32, pfconf->cluster_id); } else { @@ -278,6 +281,7 @@ void *ParsePfringConfig(const char *iface) "Could not get cluster-id from config"); } else { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); + pfconf->flags |= PFRING_CONF_FLAGS_CLUSTER; SCLogDebug("Going to use cluster-id %" PRId32, pfconf->cluster_id); } } diff --git a/src/source-pfring.c b/src/source-pfring.c index 3e2ba6a8563c..527086f564c7 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -485,8 +485,11 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) if (rc != 0) { SCLogError(SC_ERR_PF_RING_SET_CLUSTER_FAILED, "pfring_set_cluster " "returned %d for cluster-id: %d", rc, ptv->cluster_id); - pfconf->DerefFunc(pfconf); - return TM_ECODE_FAILED; + if (rc != PF_RING_ERROR_NOT_SUPPORTED || (pfconf->flags & PFRING_CONF_FLAGS_CLUSTER)) { + /* cluster is mandatory as explicitly specified in the configuration */ + pfconf->DerefFunc(pfconf); + return TM_ECODE_FAILED; + } } } diff --git a/src/source-pfring.h b/src/source-pfring.h index e0878454e12d..9871f458f6ee 100644 --- a/src/source-pfring.h +++ b/src/source-pfring.h @@ -31,8 +31,14 @@ #include #endif +typedef enum { + PFRING_CONF_FLAGS_CLUSTER = 0x1 +} PfringIfaceConfigFlags; + typedef struct PfringIfaceConfig_ { + uint32_t flags; + /* cluster param */ int cluster_id; #ifdef HAVE_PFRING From 9672e16323bd46ee366d922b856deabca9dfd232 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 16 Nov 2015 17:53:04 +0100 Subject: [PATCH 0848/2553] suricata: clean dump-config output When user asks for a configuration dump, it is useless to display the version and CPU info. Also initializing the log system conduct to overwrite the some log files and in particular suricata.log and this is annoying as a command should not interfere with a running daemon. --- src/suricata.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 8ddd79fd7a60..afda5c922a02 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2226,6 +2226,11 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + if (suri.run_mode == RUNMODE_DUMP_CONFIG) { + ConfDump(); + exit(EXIT_SUCCESS); + } + /* Since our config is now loaded we can finish configurating the * logging module. */ SCLogLoadConfig(suri.daemon, suri.verbose); @@ -2234,11 +2239,6 @@ int main(int argc, char **argv) UtilCpuPrintSummary(); - if (suri.run_mode == RUNMODE_DUMP_CONFIG) { - ConfDump(); - exit(EXIT_SUCCESS); - } - if (PostConfLoadedSetup(&suri) != TM_ECODE_OK) { exit(EXIT_FAILURE); } From affb399cd9b09771b59b8eddea1de04719babfc8 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 17 Nov 2015 09:56:55 +0100 Subject: [PATCH 0849/2553] config: don't use hardcoded path It is better to use a transformation to define the default directory of output message instead of using an hardcoded value. Same apply to the directory for the pid file. --- suricata.yaml.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index e19b855b065c..d67b77f91028 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -50,7 +50,7 @@ host-mode: auto # Default pid file. # Will use this file if no --pidfile in command options. -#pid-file: /var/run/suricata.pid +#pid-file: @e_rundir@suricata.pid # Daemon working directory # Suricata will change directory to this one if provided @@ -980,7 +980,7 @@ logging: # type: json - file: enabled: no - filename: /var/log/suricata.log + filename: @e_logdir@suricata.log # type: json - syslog: enabled: no From c199fdcbb9197d13e2cc85d162051139d511494c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 3 Nov 2015 09:45:53 +0100 Subject: [PATCH 0850/2553] handle MTU discovery in multi iface case This patch adds handling of multiple interface by using as default-packet-size the maximum MTU + header length among the live iface. --- src/suricata.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index afda5c922a02..0b8363e58e05 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1977,14 +1977,20 @@ static int ConfigGetCaptureValue(SCInstance *suri) * back on a sane default. */ char *temp_default_packet_size; if ((ConfGet("default-packet-size", &temp_default_packet_size)) != 1) { + int lthread; + int nlive; switch (suri->run_mode) { case RUNMODE_PCAP_DEV: case RUNMODE_AFP_DEV: case RUNMODE_NETMAP: case RUNMODE_PFRING: - /* FIXME this don't work effficiently in multiinterface */ - /* find payload for interface and use it */ - default_packet_size = GetIfaceMaxPacketSize(suri->pcap_dev); + nlive = LiveGetDeviceCount(); + for (lthread = 0; lthread < nlive; lthread++) { + char *live_dev = LiveGetDeviceName(lthread); + unsigned int iface_max_packet_size = GetIfaceMaxPacketSize(live_dev); + if (iface_max_packet_size > default_packet_size) + default_packet_size = iface_max_packet_size; + } if (default_packet_size) break; /* fall through */ @@ -2239,6 +2245,10 @@ int main(int argc, char **argv) UtilCpuPrintSummary(); + if (ParseInterfacesList(suri.run_mode, suri.pcap_dev) != TM_ECODE_OK) { + exit(EXIT_FAILURE); + } + if (PostConfLoadedSetup(&suri) != TM_ECODE_OK) { exit(EXIT_FAILURE); } @@ -2320,10 +2330,6 @@ int main(int argc, char **argv) StatsSetupPostConfig(); } - if (ParseInterfacesList(suri.run_mode, suri.pcap_dev) != TM_ECODE_OK) { - exit(EXIT_FAILURE); - } - if(suri.run_mode == RUNMODE_CONF_TEST){ SCLogNotice("Configuration provided was successfully loaded. Exiting."); exit(EXIT_SUCCESS); From 35c1b681eea62918e07c35e3d8c8df23f1f26d49 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 22 Oct 2015 21:06:44 +0200 Subject: [PATCH 0851/2553] prscript: docker do not need sudo Usage is not to run docker command as root but to have the user in the docker group to be able to run docker commands. --- qa/prscript.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index 4f401edde44b..f67d94cc44a2 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -227,9 +227,6 @@ def WaitForBuildResult(builder, buildid, extension="", builder_name = None): sys.exit(-1) def CreateContainer(): - if not os.geteuid() == 0: - print "Command must be run as root" - sys.exit(-1) cli = Client() # FIXME check if existing print "Pulling docking image, first run should take long" @@ -238,9 +235,6 @@ def CreateContainer(): sys.exit(0) def StartContainer(): - if not os.geteuid() == 0: - print "Command must be run as root" - sys.exit(-1) cli = Client() suri_src_dir = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] print "Using base src dir: " + suri_src_dir @@ -248,9 +242,6 @@ def StartContainer(): sys.exit(0) def StopContainer(): - if not os.geteuid() == 0: - print "Command must be run as root" - sys.exit(-1) cli = Client() cli.stop('suri-buildbot') sys.exit(0) From b85901a6b494ec608b31ab6267f0e9989afa61e4 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 22 Oct 2015 21:20:54 +0200 Subject: [PATCH 0852/2553] prscript: add rm command This command removes the container and the image allowing to free the disk space allocated during the creation. --- qa/prscript.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/qa/prscript.py b/qa/prscript.py index f67d94cc44a2..02dd0ad948c0 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -72,6 +72,7 @@ parser.add_argument('-C', '--create', action='store_const', const=True, help='create docker container' + docker_deps, default=False) parser.add_argument('-s', '--start', action='store_const', const=True, help='start docker container' + docker_deps, default=False) parser.add_argument('-S', '--stop', action='store_const', const=True, help='stop docker container' + docker_deps, default=False) +parser.add_argument('-R', '--rm', action='store_const', const=True, help='remove docker container and image' + docker_deps, default=False) parser.add_argument('branch', metavar='branch', help='github branch to build', nargs='?') args = parser.parse_args() username = args.username @@ -246,6 +247,20 @@ def StopContainer(): cli.stop('suri-buildbot') sys.exit(0) +def RmContainer(): + cli = Client() + try: + cli.remove_container('suri-buildbot') + except: + print "Unable to remove suri-buildbot container" + pass + try: + cli.remove_image('regit/suri-buildbot:latest') + except: + print "Unable to remove suri-buildbot images" + pass + sys.exit(0) + if GOT_DOCKER: if args.create: CreateContainer() @@ -253,6 +268,8 @@ def StopContainer(): StartContainer() if args.stop: StopContainer() + if args.rm: + RmContainer() if not args.branch: print "You need to specify a branch for this mode" From a4089873c70b621a84ca4be75d3a669de7ff45cc Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 22 Oct 2015 20:31:13 +0200 Subject: [PATCH 0853/2553] rules-reload: fix reload with -s or -S When using the -S or -s option, the reload was causing the specified rules file to be forgotten and the default rules to be loaded at reload time. --- src/detect-engine.c | 5 +++-- src/detect-engine.h | 2 +- src/suricata.c | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index c6e1a83f4c5f..431f4b2aa732 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2340,7 +2340,7 @@ static int reloads = 0; * \retval -1 error * \retval 0 ok */ -int DetectEngineReload(const char *filename) +int DetectEngineReload(const char *filename, SCInstance *suri) { DetectEngineCtx *new_de_ctx = NULL; DetectEngineCtx *old_de_ctx = NULL; @@ -2377,7 +2377,8 @@ int DetectEngineReload(const char *filename) DetectEngineDeReference(&old_de_ctx); return -1; } - if (SigLoadSignatures(new_de_ctx, NULL, 0) != 0) { + if (SigLoadSignatures(new_de_ctx, + suri->sig_file, suri->sig_file_exclusive) != 0) { DetectEngineCtxFree(new_de_ctx); DetectEngineDeReference(&old_de_ctx); return -1; diff --git a/src/detect-engine.h b/src/detect-engine.h index ce4862134d01..7b62171007b2 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -75,7 +75,7 @@ void DetectEnginePruneFreeList(void); int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx); DetectEngineCtx *DetectEngineReference(DetectEngineCtx *); void DetectEngineDeReference(DetectEngineCtx **de_ctx); -int DetectEngineReload(const char *filename); +int DetectEngineReload(const char *filename, SCInstance *suri); int DetectEngineEnabled(void); int DetectEngineMTApply(void); int DetectEngineMultiTenantEnabled(void); diff --git a/src/suricata.c b/src/suricata.c index 0b8363e58e05..173ef75fb46e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2386,7 +2386,7 @@ int main(int argc, char **argv) if (suri.delayed_detect) { /* force 'reload', this will load the rules and swap engines */ - DetectEngineReload(NULL); + DetectEngineReload(NULL, &suri); if (suri.sig_file != NULL) UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2SigFileStartup); @@ -2419,10 +2419,10 @@ int main(int argc, char **argv) } if (sigusr2_count > 0) { - DetectEngineReload(conf_filename); + DetectEngineReload(conf_filename, &suri); sigusr2_count--; } else if (DetectEngineReloadIsStart()) { - DetectEngineReload(conf_filename); + DetectEngineReload(conf_filename, &suri); DetectEngineReloadSetDone(); } From b03c288d9a3776aee4e20667f5b7757b18fedea6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 2 Nov 2015 23:00:42 +0100 Subject: [PATCH 0854/2553] profiling: cleanup, remove MIN declaration --- src/util-profiling-rules.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index 2f4ec5c75e7e..6ba77e514234 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -38,10 +38,6 @@ #ifdef PROFILING -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - /** * Extra data for rule profiling. */ From c1bf0e1b079e4c63e9dda6d5c66527cff0eec721 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 3 Nov 2015 10:58:36 +0100 Subject: [PATCH 0855/2553] rule profiling: json output --- src/util-error.c | 1 + src/util-error.h | 1 + src/util-profiling-rules.c | 196 +++++++++++++++++++++++++++---------- suricata.yaml.in | 5 +- 4 files changed, 149 insertions(+), 54 deletions(-) diff --git a/src/util-error.c b/src/util-error.c index 6e783f42e4cf..461e18702e76 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -309,6 +309,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_IPPAIR_INIT); CASE_CODE (SC_ERR_MT_NO_SELECTOR); CASE_CODE (SC_ERR_MT_DUPLICATE_TENANT); + CASE_CODE (SC_ERR_NO_JSON_SUPPORT); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index d1e42a8cdd4e..b7df4766f185 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -298,6 +298,7 @@ typedef enum { SC_ERR_IPPAIR_INIT, SC_ERR_MT_NO_SELECTOR, SC_ERR_MT_DUPLICATE_TENANT, + SC_ERR_NO_JSON_SUPPORT, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index 6ba77e514234..945bc8b3c283 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -81,6 +81,7 @@ extern int profiling_output_to_file; int profiling_rules_enabled = 0; static char *profiling_file_name = ""; static const char *profiling_file_mode = "a"; +static int profiling_rule_json = 0; /** * Sort orders for dumping profiled rules. @@ -178,6 +179,13 @@ void SCProfilingRulesGlobalInit(void) profiling_output_to_file = 1; } + if (ConfNodeChildValueIsTrue(conf, "json")) { +#ifdef HAVE_LIBJANSSON + profiling_rule_json = 1; +#else + SCLogWarning(SC_ERR_NO_JSON_SUPPORT, "no json support compiled in, using plain output"); +#endif + } } } } @@ -280,6 +288,134 @@ SCProfileSummarySortByMaxTicks(const void *a, const void *b) return s0->max > s1->max ? -1 : 1; } +#ifdef HAVE_LIBJANSSON + +static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks) +{ + char timebuf[64]; + uint32_t i; + struct timeval tval; + + json_t *js = json_object(); + if (js == NULL) + return; + json_t *jsa = json_array(); + if (jsa == NULL) { + json_decref(js); + return; + } + + gettimeofday(&tval, NULL); + CreateIsoTimeString(&tval, timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); + + for (i = 0; i < count; i++) { + /* Stop dumping when we hit our first rule with 0 checks. Due + * to sorting this will be the beginning of all the rules with + * 0 checks. */ + if (summary[i].checks == 0) + break; + + json_t *jsm = json_object(); + if (jsm) { + json_object_set_new(jsm, "signature_id", json_integer(summary[i].sid)); + json_object_set_new(jsm, "gid", json_integer(summary[i].gid)); + json_object_set_new(jsm, "rev", json_integer(summary[i].rev)); + + json_object_set_new(jsm, "checks", json_integer(summary[i].checks)); + json_object_set_new(jsm, "matches", json_integer(summary[i].matches)); + + json_object_set_new(jsm, "ticks_total", json_integer(summary[i].ticks)); + json_object_set_new(jsm, "ticks_max", json_integer(summary[i].max)); + json_object_set_new(jsm, "ticks_avg", json_integer(summary[i].avgticks)); + json_object_set_new(jsm, "ticks_avg_match", json_integer(summary[i].avgticks_match)); + json_object_set_new(jsm, "ticks_avg_nomatch", json_integer(summary[i].avgticks_no_match)); + + double percent = (long double)summary[i].ticks / + (long double)total_ticks * 100; + json_object_set_new(jsm, "percent", json_integer(percent)); + json_array_append(jsa, jsm); + } + } + json_object_set_new(js, "rules", jsa); + + char *js_s = json_dumps(js, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| +#ifdef JSON_ESCAPE_SLASH + JSON_ESCAPE_SLASH +#else + 0 +#endif + ); + + if (unlikely(js_s == NULL)) + return; + fprintf(fp, "%s", js_s); + free(js_s); + json_decref(js); +} + +#endif /* HAVE_LIBJANSSON */ + +static void DumpText(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks) +{ + uint32_t i; + struct timeval tval; + struct tm *tms; + gettimeofday(&tval, NULL); + struct tm local_tm; + tms = SCLocalTime(tval.tv_sec, &local_tm); + + fprintf(fp, " ----------------------------------------------" + "----------------------------\n"); + fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, + tms->tm_hour,tms->tm_min, tms->tm_sec); + fprintf(fp, " ----------------------------------------------" + "----------------------------\n"); + fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", "Avg Match", "Avg No Match"); + fprintf(fp, " -------- " + "------------ " + "-------- " + "-------- " + "------------ " + "------ " + "-------- " + "-------- " + "----------- " + "----------- " + "----------- " + "-------------- " + "\n"); + for (i = 0; i < MIN(count, profiling_rules_limit); i++) { + + /* Stop dumping when we hit our first rule with 0 checks. Due + * to sorting this will be the beginning of all the rules with + * 0 checks. */ + if (summary[i].checks == 0) + break; + + double percent = (long double)summary[i].ticks / + (long double)total_ticks * 100; + fprintf(fp, + " %-8"PRIu32" %-12u %-8"PRIu32" %-8"PRIu32" %-12"PRIu64" %-6.2f %-8"PRIu64" %-8"PRIu64" %-11"PRIu64" %-11.2f %-11.2f %-11.2f\n", + i + 1, + summary[i].sid, + summary[i].gid, + summary[i].rev, + summary[i].ticks, + percent, + summary[i].checks, + summary[i].matches, + summary[i].max, + summary[i].avgticks, + summary[i].avgticks_match, + summary[i].avgticks_no_match); + } + + fprintf(fp,"\n"); +} + /** * \brief Dump rule profiling information to file * @@ -294,8 +430,6 @@ SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx) if (rules_ctx == NULL) return; - struct timeval tval; - struct tm *tms; if (profiling_output_to_file == 1) { fp = fopen(profiling_file_name, profiling_file_mode); @@ -379,59 +513,15 @@ SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx) SCProfileSummarySortByAvgTicksNoMatch); break; } - - gettimeofday(&tval, NULL); - struct tm local_tm; - tms = SCLocalTime(tval.tv_sec, &local_tm); - - fprintf(fp, " ----------------------------------------------" - "----------------------------\n"); - fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " - "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, - tms->tm_hour,tms->tm_min, tms->tm_sec); - fprintf(fp, " ----------------------------------------------" - "----------------------------\n"); - fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", "Avg Match", "Avg No Match"); - fprintf(fp, " -------- " - "------------ " - "-------- " - "-------- " - "------------ " - "------ " - "-------- " - "-------- " - "----------- " - "----------- " - "----------- " - "-------------- " - "\n"); - for (i = 0; i < MIN(count, profiling_rules_limit); i++) { - - /* Stop dumping when we hit our first rule with 0 checks. Due - * to sorting this will be the beginning of all the rules with - * 0 checks. */ - if (summary[i].checks == 0) - break; - - double percent = (long double)summary[i].ticks / - (long double)total_ticks * 100; - fprintf(fp, - " %-8"PRIu32" %-12u %-8"PRIu32" %-8"PRIu32" %-12"PRIu64" %-6.2f %-8"PRIu64" %-8"PRIu64" %-11"PRIu64" %-11.2f %-11.2f %-11.2f\n", - i + 1, - summary[i].sid, - summary[i].gid, - summary[i].rev, - summary[i].ticks, - percent, - summary[i].checks, - summary[i].matches, - summary[i].max, - summary[i].avgticks, - summary[i].avgticks_match, - summary[i].avgticks_no_match); +#ifdef HAVE_LIBJANSSON + if (profiling_rule_json) { + DumpJson(fp, summary, count, total_ticks); + } else +#endif + { + DumpText(fp, summary, count, total_ticks); } - fprintf(fp,"\n"); if (fp != stdout) fclose(fp); SCFree(summary); diff --git a/suricata.yaml.in b/suricata.yaml.in index d67b77f91028..af54b5274dd5 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1511,9 +1511,12 @@ profiling: # Sort options: ticks, avgticks, checks, matches, maxticks sort: avgticks - # Limit the number of items printed at exit. + # Limit the number of items printed at exit (ignored for json). limit: 100 + # output to json + json: true + # per keyword profiling keywords: enabled: yes From ad5a753dde70ac0db2a3cfa9f0b549b5798e3aa8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 1 Nov 2015 23:43:59 +0100 Subject: [PATCH 0856/2553] output-json: don't alloc for JSON to string --- src/output-json.c | 26 +++++++++++++++++++------- src/util-logopenfile.c | 5 +++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index f80120d47e68..ed54d0df313d 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -335,16 +335,28 @@ json_t *CreateJSONHeaderWithTxId(Packet *p, int direction_sensitive, char *event return js; } -int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) +static int MemBufferCallback(const char *str, size_t size, void *data) { - char *js_s = NULL; + MemBuffer *memb = data; +#if 0 // can't expand, need a MemBuffer ** + /* since we can have many threads, the buffer might not be big enough. + * * Expand if necessary. */ + if (MEMBUFFER_OFFSET(memb) + size > MEMBUFFER_SIZE(memb)) { + MemBufferExpand(&memb, OUTPUT_BUFFER_SIZE); + } +#endif + MemBufferWriteString(memb, "%s", str); + return 0; +} +int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) +{ if (file_ctx->sensor_name) { json_object_set_new(js, "host", json_string(file_ctx->sensor_name)); } - js_s = json_dumps(js, + int r = json_dump_callback(js, MemBufferCallback, buffer, JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| #ifdef JSON_ESCAPE_SLASH JSON_ESCAPE_SLASH @@ -352,12 +364,12 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) 0 #endif ); - if (unlikely(js_s == NULL)) + if (r != 0) return TM_ECODE_OK; - LogFileWrite(file_ctx, buffer, js_s, strlen(js_s)); - - free(js_s); + LogFileWrite(file_ctx, buffer, + (char *)MEMBUFFER_BUFFER(buffer), + MEMBUFFER_OFFSET(buffer)); return 0; } diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index c91e039c32dd..d2bc61b4e88e 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -623,10 +623,11 @@ int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t s file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) { + /* append \n for files only */ + MemBufferWriteString(buffer, "\n"); SCMutexLock(&file_ctx->fp_mutex); - MemBufferWriteString(buffer, "%s\n", string); file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), - MEMBUFFER_OFFSET(buffer), file_ctx); + MEMBUFFER_OFFSET(buffer), file_ctx); SCMutexUnlock(&file_ctx->fp_mutex); } #ifdef HAVE_LIBHIREDIS From c80990fe1046876753cd7536db32236a77173f23 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 2 Nov 2015 09:54:46 +0100 Subject: [PATCH 0857/2553] output: cleanup JSON logging --- src/output-json.c | 4 +--- src/util-logopenfile.c | 8 +++++--- src/util-logopenfile.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index ed54d0df313d..9cc9bd94b4e0 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -367,9 +367,7 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) if (r != 0) return TM_ECODE_OK; - LogFileWrite(file_ctx, buffer, - (char *)MEMBUFFER_BUFFER(buffer), - MEMBUFFER_OFFSET(buffer)); + LogFileWrite(file_ctx, buffer); return 0; } diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index d2bc61b4e88e..65b80facccb0 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -615,10 +615,11 @@ static int LogFileWriteRedis(LogFileCtx *file_ctx, char *string, size_t string_ } #endif -int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t string_len) +int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer) { if (file_ctx->type == LOGFILE_TYPE_SYSLOG) { - syslog(file_ctx->syslog_setup.alert_syslog_level, "%s", string); + syslog(file_ctx->syslog_setup.alert_syslog_level, "%s", + (const char *)MEMBUFFER_BUFFER(buffer)); } else if (file_ctx->type == LOGFILE_TYPE_FILE || file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) @@ -633,7 +634,8 @@ int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t s #ifdef HAVE_LIBHIREDIS else if (file_ctx->type == LOGFILE_TYPE_REDIS) { SCMutexLock(&file_ctx->fp_mutex); - LogFileWriteRedis(file_ctx, string, string_len); + LogFileWriteRedis(file_ctx, (const char *)MEMBUFFER_BUFFER(buffer), + MEMBUFFER_OFFSET(buffer)); SCMutexUnlock(&file_ctx->fp_mutex); } #endif diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index d2924503d78f..f0a123accbcc 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -130,7 +130,7 @@ typedef struct LogFileCtx_ { LogFileCtx *LogFileNewCtx(void); int LogFileFreeCtx(LogFileCtx *); -int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer, char *string, size_t string_len); +int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer); int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *, const char *, int); int SCConfLogOpenRedis(ConfNode *conf, LogFileCtx *log_ctx); From bec913b40cf9153fd6a021b33cecda97ff76be47 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 23 Nov 2015 09:56:51 +0100 Subject: [PATCH 0858/2553] json: fix malformed output Even though the json output callback is called with a null terminated string, it's not useable directly. The size parameter to the callback might be a lot smaller than the string size. Libjansson gives the size up to the first point that needs escaping. --- src/output-json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output-json.c b/src/output-json.c index 9cc9bd94b4e0..fcc3a9559e70 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -345,7 +345,7 @@ static int MemBufferCallback(const char *str, size_t size, void *data) MemBufferExpand(&memb, OUTPUT_BUFFER_SIZE); } #endif - MemBufferWriteString(memb, "%s", str); + MemBufferWriteRaw(memb, str, size); return 0; } From 3ac1a3d9fe5d955d8351c6f942dafc5df3ae0304 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 13 Oct 2015 14:06:37 +0200 Subject: [PATCH 0859/2553] app-layer-ssl: get server name from SNI extension Decode client hello handshake to get server name from SNI extension. --- src/app-layer-ssl.c | 101 +++++++++++++++++++++++++++++++++++++++++++- src/app-layer-ssl.h | 6 ++- 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 5fb41ba15a21..2c20a0544808 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -119,10 +119,15 @@ SslConfig ssl_config; #define SSLV3_RECORD_HDR_LEN 5 #define SSLV3_MESSAGE_HDR_LEN 4 +#define SSLV3_CLIENT_HELLO_VERSION_LEN 2 +#define SSLV3_CLIENT_HELLO_RANDOM_LEN 32 + /* TLS heartbeat protocol types */ #define TLS_HB_REQUEST 1 #define TLS_HB_RESPONSE 2 +#define HAS_SPACE(n) (((input) + (n) - (initial_input)) > (input_len)) ? 0 : 1 + static void SSLParserReset(SSLState *ssl_state) { ssl_state->curr_connp->bytes_processed = 0; @@ -143,11 +148,101 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, switch (ssl_state->curr_connp->handshake_type) { case SSLV3_HS_CLIENT_HELLO: ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_HELLO; + + /* skip version */ + input += SSLV3_CLIENT_HELLO_VERSION_LEN; + + /* skip random */ + input += SSLV3_CLIENT_HELLO_RANDOM_LEN; + + if (!(HAS_SPACE(1))) + goto end; + + /* skip session id */ + uint8_t session_id_length = *(input++); + + input += session_id_length; + + if (!(HAS_SPACE(2))) + goto end; + + /* skip cipher suites */ + uint16_t cipher_suites_length = ntohs(*(uint16_t *)input); + input += 2; + + input += cipher_suites_length; + + if (!(HAS_SPACE(1))) + goto end; + + /* skip compression methods */ + uint8_t compression_methods_length = *(input++); + + input += compression_methods_length; + + if (!(HAS_SPACE(2))) + goto end; + + uint16_t extensions_len = ntohs(*(uint16_t *)input); + input += 2; + + uint16_t processed_len = 0; + while (processed_len < extensions_len) + { + if (!(HAS_SPACE(2))) + goto end; + + uint16_t ext_type = ntohs(*(uint16_t *)input); + input += 2; + + if (!(HAS_SPACE(2))) + goto end; + + uint16_t ext_len = ntohs(*(uint16_t *)input); + input += 2; + + + switch (ext_type) { + case SSL_EXTENSION_SNI: + { + /* skip sni_list_length and sni_type */ + input += 3; + + if (!(HAS_SPACE(2))) + goto end; + + uint16_t sni_len = ntohs(*(uint16_t *)input); + input += 2; + + size_t sni_strlen = sni_len + 1; + ssl_state->curr_connp->sni = SCMalloc(sni_strlen); + + if (unlikely(ssl_state->curr_connp->sni == NULL)) + goto end; + + if (!(HAS_SPACE(sni_len))) + goto end; + + memcpy(ssl_state->curr_connp->sni, input, + sni_strlen - 1); + ssl_state->curr_connp->sni[sni_strlen-1] = 0; + + input += sni_len; + break; + } + default: + { + input += ext_len; + break; + } + } + processed_len += ext_len + 4; + } +end: break; case SSLV3_HS_SERVER_HELLO: ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_HELLO; - break; case SSLV3_HS_SERVER_KEY_EXCHANGE: @@ -1141,6 +1236,8 @@ void SSLStateFree(void *p) SCFree(ssl_state->client_connp.cert0_issuerdn); if (ssl_state->client_connp.cert0_fingerprint) SCFree(ssl_state->client_connp.cert0_fingerprint); + if (ssl_state->client_connp.sni) + SCFree(ssl_state->client_connp.sni); if (ssl_state->server_connp.trec) SCFree(ssl_state->server_connp.trec); @@ -1150,6 +1247,8 @@ void SSLStateFree(void *p) SCFree(ssl_state->server_connp.cert0_issuerdn); if (ssl_state->server_connp.cert0_fingerprint) SCFree(ssl_state->server_connp.cert0_fingerprint); + if (ssl_state->server_connp.sni) + SCFree(ssl_state->server_connp.sni); /* Free certificate chain */ while ((item = TAILQ_FIRST(&ssl_state->server_connp.certs))) { diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 2fc1a9699bde..e6274249b9e4 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -86,7 +86,8 @@ enum { /* config flags */ #define SSL_TLS_LOG_PEM (1 << 0) - +/* extensions */ +#define SSL_EXTENSION_SNI 0x0000 /* SSL versions. We'll use a unified format for all, with the top byte * holding the major version and the lower byte the minor version */ @@ -134,6 +135,9 @@ typedef struct SSLStateConnp_ { char *cert0_issuerdn; char *cert0_fingerprint; + /* ssl server name indication extension */ + char *sni; + uint8_t *cert_input; uint32_t cert_input_len; From 285022fde970fa8fca1db1ff4c19c09e5b29a670 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 13 Oct 2015 14:44:06 +0200 Subject: [PATCH 0860/2553] output-json-tls: added SNI field to extended output Added SNI field to extended JSON output. --- src/output-json-tls.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 4cbd21aec6d6..d8b8078f976b 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -92,6 +92,12 @@ void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) json_object_set_new(tjs, "fingerprint", json_string(state->server_connp.cert0_fingerprint)); + /* tls.sni */ + if (state->client_connp.sni) { + json_object_set_new(tjs, "sni", + json_string(state->client_connp.sni)); + } + /* tls.version */ switch (state->server_connp.version) { case TLS_VERSION_UNKNOWN: From f363d11afe1e91b9db3f8361a591051fff3c4ef3 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 13 Oct 2015 15:35:33 +0200 Subject: [PATCH 0861/2553] log-tls: added SNI field to extended output Added SNI field to extended tls log output. --- src/log-tlslog.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/log-tlslog.c b/src/log-tlslog.c index edb0ded2d0fe..53ebad8bfc56 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -83,6 +83,9 @@ static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state) if (state->server_connp.cert0_fingerprint != NULL) { MemBufferWriteString(aft->buffer, " SHA1='%s'", state->server_connp.cert0_fingerprint); } + if (state->client_connp.sni != NULL) { + MemBufferWriteString(aft->buffer, " SNI='%s'", state->client_connp.sni); + } switch (state->server_connp.version) { case TLS_VERSION_UNKNOWN: MemBufferWriteString(aft->buffer, " VERSION='UNDETERMINED'"); From 7281f6aaf300a449b3fc6d1322d8b8070612d149 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 13 Oct 2015 15:59:22 +0200 Subject: [PATCH 0862/2553] lua: added function TlsGetSNI() Added function to get server name from TLS SNI extension. --- src/util-lua-tls.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/util-lua-tls.c b/src/util-lua-tls.c index 8816d5d5499a..5963ac246cd8 100644 --- a/src/util-lua-tls.c +++ b/src/util-lua-tls.c @@ -133,12 +133,53 @@ static int TlsGetCertInfo(lua_State *luastate) return r; } +static int GetSNI(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + if (ssl_state->client_connp.sni == NULL) + return LuaCallbackError(luastate, "error: no server name indication"); + + return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->client_connp.sni, + strlen(ssl_state->client_connp.sni)); +} + +static int TlsGetSNI(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int lock_hint = 0; + Flow *f = LuaStateGetFlow(luastate, &lock_hint); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + FLOWLOCK_RDLOCK(f); + r = GetSNI(luastate, f); + FLOWLOCK_UNLOCK(f); + } else { + r = GetSNI(luastate, f); + } + return r; +} + /** \brief register tls lua extensions in a luastate */ int LuaRegisterTlsFunctions(lua_State *luastate) { /* registration of the callbacks */ lua_pushcfunction(luastate, TlsGetCertInfo); lua_setglobal(luastate, "TlsGetCertInfo"); + + lua_pushcfunction(luastate, TlsGetSNI); + lua_setglobal(luastate, "TlsGetSNI"); + return 0; } From 9375e8fb3c5430d43f6f50d128ec24f1b48bc03e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 14 Oct 2015 13:37:45 -0600 Subject: [PATCH 0863/2553] util-base64: strict mode - all characters must be valid Introduce a strict mode to base64 decode. If strict, the function will fail when invalid input data is seen. If not strict, what has been decoded will be returned. This is in support of adding a Snort compatible base64_decode rule option that uses whatever data can be decoded as a length of data to decode is optional. --- src/util-base64.c | 9 +++++++-- src/util-base64.h | 3 ++- src/util-decode-mime.c | 6 +++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/util-base64.c b/src/util-base64.c index f4b508a0199b..45fdc01ab4a0 100644 --- a/src/util-base64.c +++ b/src/util-base64.c @@ -83,10 +83,13 @@ static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64 * \param dest The destination byte buffer * \param src The source string * \param len The length of the source string + * \param strict If set file on invalid byte, otherwise return what has been + * decoded. * * \return Number of bytes decoded, or 0 if no data is decoded or it fails */ -uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len) { +uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len, + int strict) { int val; uint32_t padding = 0, numDecoded = 0, bbidx = 0, valid = 1, i; @@ -103,7 +106,9 @@ uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len) { /* Invalid character found, so decoding fails */ if (src[i] != '=') { valid = 0; - numDecoded = 0; + if (strict) { + numDecoded = 0; + } break; } padding++; diff --git a/src/util-base64.h b/src/util-base64.h index fb1a90a3b577..7c8bed626261 100644 --- a/src/util-base64.h +++ b/src/util-base64.h @@ -49,6 +49,7 @@ #define B64_BLOCK 4 /* Function prototypes */ -uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len); +uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len, + int strict); #endif diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 51d1468e5538..ded4cd6044d4 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -1227,7 +1227,7 @@ static uint8_t ProcessBase64Remainder(const uint8_t *buf, uint32_t len, /* Only decode if divisible by 4 */ if (state->bvr_len == B64_BLOCK || force) { remdec = DecodeBase64(state->data_chunk + state->data_chunk_len, - state->bvremain, state->bvr_len); + state->bvremain, state->bvr_len, 1); if (remdec > 0) { /* Track decoded length */ @@ -1329,7 +1329,7 @@ static int ProcessBase64BodyLine(const uint8_t *buf, uint32_t len, SCLogDebug("Decoding: %u", len - rem1 - rem2); numDecoded = DecodeBase64(state->data_chunk + state->data_chunk_len, - buf + offset, tobuf); + buf + offset, tobuf, 1); if (numDecoded > 0) { /* Track decoded length */ @@ -2888,7 +2888,7 @@ static int MimeBase64DecodeTest01(void) if (dst == NULL) return 0; - ret = DecodeBase64(dst, (const uint8_t *)base64msg, strlen(base64msg)); + ret = DecodeBase64(dst, (const uint8_t *)base64msg, strlen(base64msg), 1); if (memcmp(dst, msg, strlen(msg)) == 0) { ret = 0; From 6b15686fd1ed86dd3b5095fbd5f50e7cddb7822d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 30 Sep 2015 09:49:47 -0600 Subject: [PATCH 0864/2553] base64_decode, base64_data: decode and match base64 --- src/Makefile.am | 2 + src/detect-base64-data.c | 236 ++++++++ src/detect-base64-data.h | 25 + src/detect-base64-decode.c | 778 +++++++++++++++++++++++++ src/detect-base64-decode.h | 33 ++ src/detect-engine-content-inspection.c | 18 +- src/detect-engine-content-inspection.h | 1 + src/detect-engine.c | 18 + src/detect-parse.c | 14 + src/detect.c | 6 + src/detect.h | 11 + src/util-error.c | 1 + src/util-error.h | 2 + 13 files changed, 1142 insertions(+), 3 deletions(-) create mode 100644 src/detect-base64-data.c create mode 100644 src/detect-base64-data.h create mode 100644 src/detect-base64-decode.c create mode 100644 src/detect-base64-decode.h diff --git a/src/Makefile.am b/src/Makefile.am index 98e094c19afb..4af253a8965d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,6 +71,8 @@ detect-ack.c detect-ack.h \ detect-app-layer-event.c detect-app-layer-event.h \ detect-app-layer-protocol.c detect-app-layer-protocol.h \ detect-asn1.c detect-asn1.h \ +detect-base64-data.c detect-base64-data.h \ +detect-base64-decode.c detect-base64-decode.h \ detect-byte-extract.c detect-byte-extract.h \ detect-bytejump.c detect-bytejump.h \ detect-bytetest.c detect-bytetest.h \ diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c new file mode 100644 index 000000000000..b056b97a1e4c --- /dev/null +++ b/src/detect-base64-data.c @@ -0,0 +1,236 @@ +/* Copyright (C) 2015 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. + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-engine-content-inspection.h" +#include "detect-parse.h" + +#include "util-unittest.h" + +static int DetectBase64DataSetup(DetectEngineCtx *, Signature *, char *); +static void DetectBase64DataRegisterTests(void); + +void DetectBase64DataRegister(void) +{ + sigmatch_table[DETECT_BASE64_DATA].name = "base64_data"; + sigmatch_table[DETECT_BASE64_DATA].desc = + "Content match base64 decoded data."; + sigmatch_table[DETECT_BASE64_DATA].url = + "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#base64_data"; + sigmatch_table[DETECT_BASE64_DATA].Setup = DetectBase64DataSetup; + sigmatch_table[DETECT_BASE64_DATA].RegisterTests = + DetectBase64DataRegisterTests; + + sigmatch_table[DETECT_BASE64_DATA].flags |= SIGMATCH_NOOPT; +} + +static int DetectBase64DataSetup(DetectEngineCtx *de_ctx, Signature *s, + char *str) +{ + SigMatch *pm = NULL; + + /* Check for a preceding base64_decode. */ + pm = SigMatchGetLastSMFromLists(s, 28, + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + if (pm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "\"base64_data\" keyword seen without preceding base64_decode."); + return -1; + } + + s->list = DETECT_SM_LIST_BASE64_DATA; + return 0; +} + +int DetectBase64DataDoMatch(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f) +{ + if (det_ctx->base64_decoded_len) { + return DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_BASE64_DATA], f, det_ctx->base64_decoded, + det_ctx->base64_decoded_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_BASE64, NULL); + } + + return 0; +} + +#ifdef UNITTESTS + +#include "detect-engine.h" + +static int DetectBase64DataSetupTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + SigMatch *sm; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert smtp any any -> any any (msg:\"DetectBase64DataSetupTest\"; " + "base64_decode; base64_data; content:\"content\"; sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + printf("SigInit failed: "); + goto end; + } + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; + if (sm == NULL) { + printf("DETECT_SM_LIST_PMATCH should not be NULL: "); + goto end; + } + if (sm->type != DETECT_BASE64_DECODE) { + printf("sm->type should be DETECT_BASE64_DECODE: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_BASE64_DATA] == NULL) { + printf("DETECT_SM_LIST_BASE64_DATA should not be NULL: "); + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +static int DetectBase64DataSetupTest02(void) +{ + DetectEngineCtx *de_ctx = NULL; + SigMatch *sm; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert smtp any any -> any any ( " + "msg:\"DetectBase64DataSetupTest\"; " + "file_data; " + "content:\"SGV\"; " + "base64_decode: bytes 16; " + "base64_data; " + "content:\"content\"; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + printf("SigInit failed: "); + goto end; + } + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; + if (sm != NULL) { + printf("DETECT_SM_LIST_PMATCH is not NULL: "); + goto end; + } + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + if (sm == NULL) { + printf("DETECT_SM_LIST_FILEDATA is NULL: "); + goto end; + } + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_BASE64_DATA]; + if (sm == NULL) { + printf("DETECT_SM_LIST_BASE64_DATA is NULL: "); + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +static int DetectBase64DataSetupTest03(void) +{ + DetectEngineCtx *de_ctx = NULL; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert smtp any any -> any any ( " + "msg:\"DetectBase64DataSetupTest\"; " + "base64_decode: bytes 16; " + "base64_data; " + "content:\"content\"; " + "file_data; " + "content:\"SGV\"; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list != NULL) { + printf("SigInit should have failed: "); + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +#endif + +static void DetectBase64DataRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectBase64DataSetupTest01", DetectBase64DataSetupTest01, + 1); + UtRegisterTest("DetectBase64DataSetupTest02", DetectBase64DataSetupTest02, + 1); + UtRegisterTest("DetectBase64DataSetupTest03", DetectBase64DataSetupTest03, + 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-base64-data.h b/src/detect-base64-data.h new file mode 100644 index 000000000000..12fa60de56e0 --- /dev/null +++ b/src/detect-base64-data.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __DETECT_BASE64_DATA_H__ +#define __DETECT_BASE64_DATA_H__ + +void DetectBase64DataRegister(void); +int DetectBase64DataDoMatch(DetectEngineCtx *, DetectEngineThreadCtx *, + Signature *, Flow *); + +#endif /* __DETECT_BASE64_DATA_H__ */ diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c new file mode 100644 index 000000000000..bd9baea583ba --- /dev/null +++ b/src/detect-base64-decode.c @@ -0,0 +1,778 @@ +/* Copyright (C) 2015 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. + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-base64-decode.h" +#include "util-base64.h" +#include "util-byte.h" +#include "util-print.h" + +/* Arbitrary maximum buffer size for decoded base64 data. */ +#define BASE64_DECODE_MAX 65535 + +static const char decode_pattern[] = "\\s*(bytes\\s+(\\d+),?)?" + "\\s*(offset\\s+(\\d+),?)?" + "\\s*(\\w+)?"; +static pcre *decode_pcre = NULL; +static pcre_extra *decode_pcre_study = NULL; + +static int DetectBase64DecodeSetup(DetectEngineCtx *, Signature *, char *); +static void DetectBase64DecodeFree(void *); +static void DetectBase64DecodeRegisterTests(void); + +void DetectBase64DecodeRegister(void) +{ + const char *pcre_errptr; + int pcre_erroffset; + + sigmatch_table[DETECT_BASE64_DECODE].name = "base64_decode"; + sigmatch_table[DETECT_BASE64_DECODE].desc = + "Decodes base64 encoded data."; + sigmatch_table[DETECT_BASE64_DECODE].url = + "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#base64_decode"; + sigmatch_table[DETECT_BASE64_DECODE].Setup = DetectBase64DecodeSetup; + sigmatch_table[DETECT_BASE64_DECODE].Free = DetectBase64DecodeFree; + sigmatch_table[DETECT_BASE64_DECODE].RegisterTests = + DetectBase64DecodeRegisterTests; + + sigmatch_table[DETECT_BASE64_DECODE].flags |= SIGMATCH_PAYLOAD; + sigmatch_table[DETECT_BASE64_DECODE].flags |= SIGMATCH_OPTIONAL_OPT; + + decode_pcre = pcre_compile(decode_pattern, 0, &pcre_errptr, &pcre_erroffset, + NULL); + if (decode_pcre == NULL) { + SCLogError(SC_ERR_PCRE_COMPILE, "Failed to compile pattern \"%s\" at" + " offset %d: %s", decode_pattern, pcre_erroffset, pcre_errptr); + exit(EXIT_FAILURE); + } + + decode_pcre_study = pcre_study(decode_pcre, 0, &pcre_errptr); + if (pcre_errptr != NULL) { + SCLogError(SC_ERR_PCRE_STUDY, "Failed to study pattern \"%s\": %s", + decode_pattern, pcre_errptr); + exit(EXIT_FAILURE); + } +} + +int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, + const SigMatch *sm, uint8_t *payload, uint32_t payload_len) +{ + DetectBase64Decode *data = (DetectBase64Decode *)sm->ctx; + int decode_len; + +#if 0 + printf("Input data:\n"); + PrintRawDataFp(stdout, payload, payload_len); +#endif + + if (data->relative) { + payload += det_ctx->buffer_offset; + payload_len -= det_ctx->buffer_offset; + } + + if (data->offset) { + if (data->offset >= payload_len) { + return 0; + } + payload = payload + data->offset; + payload_len -= data->offset; + } + + decode_len = MIN(payload_len, data->bytes); + +#if 0 + printf("Decoding:\n"); + PrintRawDataFp(stdout, payload, decode_len); +#endif + + det_ctx->base64_decoded_len = DecodeBase64(det_ctx->base64_decoded, + payload, decode_len, 0); + SCLogDebug("Decoded %d bytes from base64 data.", + det_ctx->base64_decoded_len); +#if 0 + if (det_ctx->base64_decoded_len) { + printf("Decoded data:\n"); + PrintRawDataFp(stdout, det_ctx->base64_decoded, + det_ctx->base64_decoded_len); + } +#endif + + return det_ctx->base64_decoded_len > 0; +} + +static int DetectBase64DecodeParse(const char *str, uint32_t *bytes, + uint32_t *offset, uint8_t *relative) +{ + static const int max = 30; + int ov[max]; + int pcre_rc; + const char *bytes_str = NULL; + const char *offset_str = NULL; + const char *relative_str = NULL; + int retval = 0; + + *bytes = 0; + *offset = 0; + *relative = 0; + + pcre_rc = pcre_exec(decode_pcre, decode_pcre_study, str, strlen(str), 0, 0, + ov, max); + if (pcre_rc < 3) { + goto error; + } + + if (pcre_rc >= 3) { + if (pcre_get_substring((char *)str, ov, max, 2, &bytes_str) > 0) { + if (ByteExtractStringUint32(bytes, 10, 0, bytes_str) <= 0) { + SCLogError(SC_ERR_INVALID_RULE_ARGUMENT, + "Bad value for bytes: \"%s\"", bytes_str); + goto error; + } + } + } + + if (pcre_rc >= 5) { + if (pcre_get_substring((char *)str, ov, max, 4, &offset_str)) { + if (ByteExtractStringUint32(offset, 10, 0, offset_str) <= 0) { + SCLogError(SC_ERR_INVALID_RULE_ARGUMENT, + "Bad value for offset: \"%s\"", offset_str); + goto error; + } + } + } + + if (pcre_rc >= 6) { + if (pcre_get_substring((char *)str, ov, max, 5, &relative_str)) { + if (strcmp(relative_str, "relative") == 0) { + *relative = 1; + } + else { + SCLogError(SC_ERR_INVALID_RULE_ARGUMENT, + "Invalid argument: \"%s\"", relative_str); + goto error; + } + } + } + + retval = 1; +error: + if (bytes_str != NULL) { + pcre_free_substring(bytes_str); + } + if (offset_str != NULL) { + pcre_free_substring(offset_str); + } + if (relative_str != NULL) { + pcre_free_substring(relative_str); + } + return retval; +} + +static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s, + char *str) +{ + uint32_t bytes = 0; + uint32_t offset = 0; + uint8_t relative = 0; + DetectBase64Decode *data = NULL; + int sm_list; + SigMatch *sm = NULL; + SigMatch *pm = NULL; + + if (str != NULL) { + if (!DetectBase64DecodeParse(str, &bytes, &offset, &relative)) { + goto error; + } + } + data = SCCalloc(1, sizeof(DetectBase64Decode)); + if (unlikely(data == NULL)) { + goto error; + } + data->bytes = bytes; + data->offset = offset; + data->relative = relative; + + if (s->list != DETECT_SM_LIST_NOTSET) { + sm_list = s->list; +#if 0 + if (data->relative) { + pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_CONTENT, s->sm_lists_tail[sm_list], + DETECT_PCRE, s->sm_lists_tail[sm_list]); + } +#endif + } + else { + /* Copied from detect-isdataat.c. */ + pm = SigMatchGetLastSMFromLists(s, 168, + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + if (pm == NULL) { + sm_list = DETECT_SM_LIST_PMATCH; + } + else { + sm_list = SigMatchListSMBelongsTo(s, pm); + } + } + + sm = SigMatchAlloc(); + if (sm == NULL) { + goto error; + } + sm->type = DETECT_BASE64_DECODE; + sm->ctx = (SigMatchCtx *)data; + SigMatchAppendSMToList(s, sm, sm_list); + + if (!data->bytes) { + data->bytes = BASE64_DECODE_MAX; + } + if (data->bytes > de_ctx->base64_decode_max_len) { + de_ctx->base64_decode_max_len = data->bytes; + } + + return 0; +error: + if (data != NULL) { + SCFree(data); + } + return -1; +} + +static void DetectBase64DecodeFree(void *ptr) +{ + DetectBase64Decode *data = ptr; + SCFree(data); +} + + +#ifdef UNITTESTS + +#include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer-parser.h" +#include "flow-util.h" +#include "stream-tcp.h" + +static int DetectBase64TestDecodeParse(void) +{ + int retval = 0; + uint32_t bytes = 0; + uint32_t offset = 0; + uint8_t relative = 0; + + if (!DetectBase64DecodeParse("bytes 1", &bytes, &offset, &relative)) { + goto end; + } + if (bytes != 1 || offset != 0 || relative != 0) { + goto end; + } + + if (!DetectBase64DecodeParse("offset 9", &bytes, &offset, &relative)) { + goto end; + } + if (bytes != 0 || offset != 9 || relative != 0) { + goto end; + } + + if (!DetectBase64DecodeParse("relative", &bytes, &offset, &relative)) { + goto end; + } + if (bytes != 0 || offset != 0 || relative != 1) { + goto end; + } + + if (!DetectBase64DecodeParse("bytes 1, offset 2", &bytes, &offset, + &relative)) { + goto end; + } + if (bytes != 1 || offset != 2 || relative != 0) { + goto end; + } + + if (!DetectBase64DecodeParse("bytes 1, offset 2, relative", &bytes, &offset, + &relative)) { + goto end; + } + if (bytes != 1 || offset != 2 || relative != 1) { + goto end; + } + + if (!DetectBase64DecodeParse("offset 2, relative", &bytes, &offset, + &relative)) { + goto end; + } + if (bytes != 0 || offset != 2 || relative != 1) { + goto end; + } + + /* Misspelled relative. */ + if (DetectBase64DecodeParse("bytes 1, offset 2, relatve", &bytes, &offset, + &relative)) { + goto end; + } + + /* Misspelled bytes. */ + if (DetectBase64DecodeParse("byts 1, offset 2, relatve", &bytes, &offset, + &relative)) { + goto end; + } + + /* Misspelled offset. */ + if (DetectBase64DecodeParse("bytes 1, offst 2, relatve", &bytes, &offset, + &relative)) { + goto end; + } + + /* Misspelled empty string. */ + if (DetectBase64DecodeParse("", &bytes, &offset, &relative)) { + goto end; + } + + retval = 1; +end: + return retval; +} + +/** + * Test keyword setup on basic content. + */ +static int DetectBase64DecodeTestSetup(void) +{ + DetectEngineCtx *de_ctx = NULL; + Signature *s; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (" + "msg:\"DetectBase64DecodeTestSetup\"; " + "base64_decode; content:\"content\"; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + s = de_ctx->sig_list; + if (s == NULL) { + goto end; + } + if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +/** + * Test keyword setup when the prior rule has a content modifier on + * it. + */ +static int DetectBase64DecodeHttpHeaderTestSetup(void) +{ + DetectEngineCtx *de_ctx = NULL; + Signature *s; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (" + "msg:\"DetectBase64DecodeTestSetup\"; " + "content:\"Authorization: basic \"; http_header; " + "base64_decode; content:\"content\"; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + s = de_ctx->sig_list; + if (s == NULL) { + goto end; + } + + /* I'm not complete sure if this list should not be NULL. */ + if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + goto end; + } + + /* Test that the http header list is not NULL. */ + if (s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL) { + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +static int DetectBase64DecodeTestDecode(void) +{ + ThreadVars tv; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + Packet *p = NULL; + int retval = 0; + + uint8_t payload[] = { + 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', + 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', + }; + + memset(&tv, 0, sizeof(tv)); + + if ((de_ctx = DetectEngineCtxInit()) == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"base64 test\"; " + "base64_decode; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + if (p == NULL) { + goto end; + } + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + if (det_ctx->base64_decoded_len == 0) { + goto end; + } + + retval = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&tv, det_ctx); + } + if (de_ctx != NULL) { + SigCleanSignatures(de_ctx); + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + if (p != NULL) { + UTHFreePacket(p); + } + return retval; +} + +static int DetectBase64DecodeTestDecodeWithOffset(void) +{ + ThreadVars tv; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + Packet *p = NULL; + int retval = 0; + + uint8_t payload[] = { + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', + 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', + }; + char decoded[] = "Hello World"; + + memset(&tv, 0, sizeof(tv)); + + if ((de_ctx = DetectEngineCtxInit()) == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"base64 test\"; " + "base64_decode: offset 8; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + if (p == NULL) { + goto end; + } + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + if (det_ctx->base64_decoded_len != (int)strlen(decoded)) { + goto end; + } + if (memcmp(det_ctx->base64_decoded, decoded, strlen(decoded))) { + goto end; + } + + retval = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&tv, det_ctx); + } + if (de_ctx != NULL) { + SigCleanSignatures(de_ctx); + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + if (p != NULL) { + UTHFreePacket(p); + } + return retval; +} + +static int DetectBase64DecodeTestDecodeLargeOffset(void) +{ + ThreadVars tv; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + Packet *p = NULL; + int retval = 0; + + uint8_t payload[] = { + 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', + 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', + }; + + memset(&tv, 0, sizeof(tv)); + + if ((de_ctx = DetectEngineCtxInit()) == NULL) { + goto end; + } + + /* Offset is out of range. */ + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"base64 test\"; " + "base64_decode: bytes 16, offset 32; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + if (p == NULL) { + goto end; + } + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + if (det_ctx->base64_decoded_len != 0) { + goto end; + } + + retval = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&tv, det_ctx); + } + if (de_ctx != NULL) { + SigCleanSignatures(de_ctx); + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + if (p != NULL) { + UTHFreePacket(p); + } + return retval; +} + +static int DetectBase64DecodeTestDecodeRelative(void) +{ + ThreadVars tv; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + Packet *p = NULL; + int retval = 0; + + uint8_t payload[] = { + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', + 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', + }; + char decoded[] = "Hello World"; + + memset(&tv, 0, sizeof(tv)); + + if ((de_ctx = DetectEngineCtxInit()) == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"base64 test\"; " + "content:\"aaaaaaaa\"; " + "base64_decode: relative; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + if (p == NULL) { + goto end; + } + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + if (det_ctx->base64_decoded_len != (int)strlen(decoded)) { + goto end; + } + if (memcmp(det_ctx->base64_decoded, decoded, strlen(decoded))) { + goto end; + } + + retval = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&tv, det_ctx); + } + if (de_ctx != NULL) { + SigCleanSignatures(de_ctx); + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + if (p != NULL) { + UTHFreePacket(p); + } + return retval; +} + +#endif + +static void DetectBase64DecodeRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectBase64TestDecodeParse", DetectBase64TestDecodeParse, + 1); + UtRegisterTest("DetectBase64DecodeTestSetup", DetectBase64DecodeTestSetup, + 1); + UtRegisterTest("DetectBase64DecodeHttpHeaderTestSetup", + DetectBase64DecodeHttpHeaderTestSetup, 1); + UtRegisterTest("DetectBase64DecodeTestDecode", DetectBase64DecodeTestDecode, + 1); + UtRegisterTest("DetectBase64DecodeTestDecodeWithOffset", + DetectBase64DecodeTestDecodeWithOffset, 1); + UtRegisterTest("DetectBase64DecodeTestDecodeLargeOffset", + DetectBase64DecodeTestDecodeLargeOffset, 1); + UtRegisterTest("DetectBase64DecodeTestDecodeRelative", + DetectBase64DecodeTestDecodeRelative, 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-base64-decode.h b/src/detect-base64-decode.h new file mode 100644 index 000000000000..a1ce388f188f --- /dev/null +++ b/src/detect-base64-decode.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __DETECT_BASE64_DECODE_H__ +#define __DETECT_BASE64_DECODE_H__ + +#include "app-layer-template.h" + +typedef struct DetectBase64Decode_ { + uint32_t bytes; + uint32_t offset; + uint8_t relative; +} DetectBase64Decode; + +void DetectBase64DecodeRegister(void); +int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *, Signature *, + const SigMatch *, uint8_t *, uint32_t); + +#endif /* __DETECT_BASE64_DECODE_H__ */ diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index a434ca5ad8c8..17df02ce9a1a 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -42,6 +42,8 @@ #include "detect-uricontent.h" #include "detect-urilen.h" #include "detect-lua.h" +#include "detect-base64-decode.h" +#include "detect-base64-data.h" #include "app-layer-dcerpc.h" @@ -551,6 +553,16 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx SCLogDebug("lua match"); goto match; #endif /* HAVE_LUA */ + } else if (sm->type == DETECT_BASE64_DECODE) { + if (DetectBase64DecodeDoMatch(det_ctx, s, sm, buffer, buffer_len)) { + if (s->sm_arrays[DETECT_SM_LIST_BASE64_DATA] != NULL) { + KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + if (DetectBase64DataDoMatch(de_ctx, det_ctx, s, f)) { + /* Base64 is a terminal list. */ + goto final_match; + } + } + } } else { SCLogDebug("sm->type %u", sm->type); #ifdef DEBUG @@ -569,8 +581,8 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx KEYWORD_PROFILING_END(det_ctx, sm->type, 1); int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); SCReturnInt(r); - } else { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - SCReturnInt(1); } +final_match: + KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + SCReturnInt(1); } diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index dc0b5026bee7..5e80b9b8ccd5 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -50,6 +50,7 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_BASE64, DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, }; diff --git a/src/detect-engine.c b/src/detect-engine.c index 431f4b2aa732..63542dc83b72 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1338,6 +1338,16 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * return TM_ECODE_FAILED; } + /* Allocate space for base64 decoded data. */ + if (de_ctx->base64_decode_max_len) { + det_ctx->base64_decoded = SCMalloc(de_ctx->base64_decode_max_len); + if (det_ctx->base64_decoded == NULL) { + return TM_ECODE_FAILED; + } + det_ctx->base64_decoded_len_max = de_ctx->base64_decode_max_len; + det_ctx->base64_decoded_len = 0; + } + DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx); #ifdef PROFILING SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx); @@ -1542,6 +1552,11 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) SCFree(det_ctx->hcbd); } + /* Decoded base64 data. */ + if (det_ctx->base64_decoded != NULL) { + SCFree(det_ctx->base64_decoded); + } + if (det_ctx->de_ctx != NULL) { DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx); #ifdef UNITTESTS @@ -2646,6 +2661,9 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; + case DETECT_SM_LIST_BASE64_DATA: + return "base64_data"; + case DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH: return "template_buffer"; diff --git a/src/detect-parse.c b/src/detect-parse.c index 9ac53e03c2d5..d0f46714ec66 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1319,6 +1319,20 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } + if (s->sm_lists[DETECT_SM_LIST_BASE64_DATA] != NULL) { + uint16_t idx = s->sm_lists[DETECT_SM_LIST_BASE64_DATA]->idx; + for (int list = 0; list < DETECT_SM_LIST_MAX; list++) { + if (list != DETECT_SM_LIST_BASE64_DATA && + s->sm_lists[list] != NULL) { + if (s->sm_lists[list]->idx > idx) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Rule buffer " + "cannot be reset after base64_data."); + SCReturnInt(0); + } + } + } + } + #ifdef HAVE_LUA DetectLuaPostSetup(s); #endif diff --git a/src/detect.c b/src/detect.c index c9a16ead5c90..65f18dc67a80 100644 --- a/src/detect.c +++ b/src/detect.c @@ -60,6 +60,8 @@ #include "detect-engine-event.h" #include "decode.h" +#include "detect-base64-decode.h" +#include "detect-base64-data.h" #include "detect-ipopts.h" #include "detect-flags.h" #include "detect-fragbits.h" @@ -1254,6 +1256,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh p->alerts.cnt = 0; det_ctx->filestore_cnt = 0; + det_ctx->base64_decoded_len = 0; + /* No need to perform any detection on this packet, if the the given flag is set.*/ if (p->flags & PKT_NOPACKET_INSPECTION) { SCReturnInt(0); @@ -5130,6 +5134,8 @@ void SigTableSetup(void) DetectDnsQueryRegister(); DetectModbusRegister(); DetectAppLayerProtocolRegister(); + DetectBase64DecodeRegister(); + DetectBase64DataRegister(); DetectTemplateRegister(); DetectTemplateBufferRegister(); } diff --git a/src/detect.h b/src/detect.h index 8d131b92a378..89ce35ab1ca2 100644 --- a/src/detect.h +++ b/src/detect.h @@ -126,6 +126,8 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_MODBUS_MATCH, + DETECT_SM_LIST_BASE64_DATA, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, /* list for post match actions: flowbit set, flowint increment, etc */ @@ -687,6 +689,9 @@ typedef struct DetectEngineCtx_ { * 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. */ char *rule_file; int rule_line; @@ -883,6 +888,10 @@ typedef struct DetectEngineThreadCtx_ { void **keyword_ctxs_array; int keyword_ctxs_size; + uint8_t *base64_decoded; + int base64_decoded_len; + int base64_decoded_len_max; + #ifdef PROFILING struct SCProfileData_ *rule_perf_data; int rule_perf_data_size; @@ -1221,6 +1230,8 @@ enum { DETECT_AL_MODBUS, DETECT_XBITS, + DETECT_BASE64_DECODE, + DETECT_BASE64_DATA, DETECT_TEMPLATE, DETECT_AL_TEMPLATE_BUFFER, diff --git a/src/util-error.c b/src/util-error.c index 461e18702e76..af266d334fea 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -310,6 +310,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_MT_NO_SELECTOR); CASE_CODE (SC_ERR_MT_DUPLICATE_TENANT); CASE_CODE (SC_ERR_NO_JSON_SUPPORT); + CASE_CODE (SC_ERR_INVALID_RULE_ARGUMENT); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index b7df4766f185..d0b247156790 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -299,6 +299,8 @@ typedef enum { SC_ERR_MT_NO_SELECTOR, SC_ERR_MT_DUPLICATE_TENANT, SC_ERR_NO_JSON_SUPPORT, + SC_ERR_INVALID_RULE_ARGUMENT, /**< Generic error code for invalid + * rule argument. */ } SCError; const char *SCErrorToString(SCError); From adecf41720bae7a3f0552d710ec19a3d2fc7708b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 19 Nov 2015 13:37:23 +0100 Subject: [PATCH 0865/2553] base64: code style fixups --- src/detect-parse.c | 3 ++- src/util-base64.c | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/detect-parse.c b/src/detect-parse.c index d0f46714ec66..f91e759171b6 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1320,8 +1320,9 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } if (s->sm_lists[DETECT_SM_LIST_BASE64_DATA] != NULL) { + int list; uint16_t idx = s->sm_lists[DETECT_SM_LIST_BASE64_DATA]->idx; - for (int list = 0; list < DETECT_SM_LIST_MAX; list++) { + for (list = 0; list < DETECT_SM_LIST_MAX; list++) { if (list != DETECT_SM_LIST_BASE64_DATA && s->sm_lists[list] != NULL) { if (s->sm_lists[list]->idx > idx) { diff --git a/src/util-base64.c b/src/util-base64.c index 45fdc01ab4a0..bea92d52bb4b 100644 --- a/src/util-base64.c +++ b/src/util-base64.c @@ -50,8 +50,8 @@ static const int b64table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, * * \return The decoded value (0 or above), or -1 if the parameter is invalid */ -static inline int GetBase64Value(uint8_t c) { - +static inline int GetBase64Value(uint8_t c) +{ int val = -1; /* Pull from conversion table */ @@ -70,8 +70,8 @@ static inline int GetBase64Value(uint8_t c) { * * \return none */ -static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK]) { - +static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK]) +{ ascii[0] = (uint8_t) (b64[0] << 2) | (b64[1] >> 4); ascii[1] = (uint8_t) (b64[1] << 4) | (b64[2] >> 2); ascii[2] = (uint8_t) (b64[2] << 6) | (b64[3]); @@ -89,8 +89,8 @@ static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64 * \return Number of bytes decoded, or 0 if no data is decoded or it fails */ uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len, - int strict) { - + int strict) +{ int val; uint32_t padding = 0, numDecoded = 0, bbidx = 0, valid = 1, i; uint8_t *dptr = dest; From dc3c1ef01eabb86285636ba9de5a9e50e467fbb4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Nov 2015 12:05:02 +0100 Subject: [PATCH 0866/2553] multi-detect: clean up output --- src/detect-engine.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 63542dc83b72..40d59df3a34a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1837,7 +1837,7 @@ static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id) { TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx; - SCLogInfo("loader %d", loader_id); + SCLogDebug("loader %d", loader_id); if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) { return -1; } @@ -1944,7 +1944,7 @@ void DetectEngineMultiTenantSetup(void) char *handler = NULL; if (ConfGet("multi-detect.selector", &handler) == 1) { - SCLogInfo("selector %s", handler); + SCLogInfo("multi-tenant selector type %s", handler); if (strcmp(handler, "vlan") == 0) { master->tenant_selector = TENANT_SELECTOR_VLAN; @@ -1974,8 +1974,6 @@ void DetectEngineMultiTenantSetup(void) if (vlan_id_node == NULL) goto bad_mapping; - SCLogInfo("vlan %s %s", tenant_id_node->val, vlan_id_node->val); - uint32_t tenant_id = 0; if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val), tenant_id_node->val) == -1) @@ -1997,6 +1995,7 @@ void DetectEngineMultiTenantSetup(void) if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) { goto error; } + SCLogInfo("vlan %u connected to tenant-id %u", vlan_id, tenant_id); } else { SCLogWarning(SC_ERR_INVALID_VALUE, "multi-detect.mappings expects a list of 'vlan's. Not %s", mapping_node->val); goto bad_mapping; @@ -2133,7 +2132,7 @@ static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors master->tenant_selector = selector; - SCLogInfo("tenant handler %u %u %u registered", selector, tenant_id, traffic_id); + SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id); SCMutexUnlock(&master->lock); return 0; } From d7d76e7b273c23c144a32ba54151bb75502ba68a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 Nov 2015 15:52:50 +0100 Subject: [PATCH 0867/2553] multi-detect: use default tenant The default detect engine can be used as 'default tenant'. --- src/detect-engine.c | 300 ++++++++++++++++++++++---------------------- src/detect.c | 13 +- src/suricata.c | 15 ++- 3 files changed, 164 insertions(+), 164 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 40d59df3a34a..82d651994ed5 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -102,13 +102,17 @@ static uint32_t detect_engine_ctx_id = 1; static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( - ThreadVars *tv, DetectEngineCtx *new_de_ctx); + ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt); static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *); static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, 0, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL,}; -static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv); +static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len); +static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len); +static void TenantIdFree(void *d); +static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p); +static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p); /* 2 - for each direction */ DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; @@ -553,7 +557,6 @@ int DetectEngineReloadIsDone(void) static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) { SCEnter(); - int i = 0; int no_of_detect_tvs = 0; ThreadVars *tv = NULL; @@ -623,10 +626,8 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) old_det_ctx[i] = SC_ATOMIC_GET(slots->slot_data); detect_tvs[i] = tv; - if (new_de_ctx != NULL) - new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx); - else - new_det_ctx[i] = DetectEngineThreadCtxInitForMT(tv); + + new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx, 1); if (new_det_ctx[i] == NULL) { SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init " "failure in live rule swap. Let's get out of here"); @@ -1280,6 +1281,114 @@ static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectE } } +/** NOTE: master MUST be locked before calling this */ +static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThreadCtx *det_ctx) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + DetectEngineTenantMapping *map_array = NULL; + uint32_t map_array_size = 0; + uint32_t map_cnt = 0; + int max_tenant_id = 0; + DetectEngineCtx *list = master->list; + HashTable *mt_det_ctxs_hash = NULL; + + if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) { + SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: " + "set using multi-detect.selector"); + return TM_ECODE_FAILED; + } + + uint32_t tcnt = 0; + while (list) { + if (list->tenant_id > max_tenant_id) + max_tenant_id = list->tenant_id; + + list = list->next; + tcnt++; + } + + mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree); + if (mt_det_ctxs_hash == NULL) { + goto error; + } + + if (max_tenant_id == 0) { + SCLogInfo("no tenants left, or none registered yet"); + } else { + max_tenant_id++; + + DetectEngineTenantMapping *map = master->tenant_mapping_list; + while (map) { + map_cnt++; + map = map->next; + } + + if (map_cnt > 0) { + map_array_size = map_cnt + 1; + + map_array = SCCalloc(map_array_size, sizeof(*map_array)); + if (map_array == NULL) + goto error; + + /* fill the array */ + map_cnt = 0; + map = master->tenant_mapping_list; + while (map) { + BUG_ON(map_cnt > map_array_size); + map_array[map_cnt].traffic_id = map->traffic_id; + map_array[map_cnt].tenant_id = map->tenant_id; + map_cnt++; + map = map->next; + } + + } + + /* set up hash for tenant lookup */ + list = master->list; + while (list) { + SCLogInfo("tenant-id %u", list->tenant_id); + if (list->tenant_id != 0) { + DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0); + if (mt_det_ctx == NULL) + goto error; + BUG_ON(HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0); + } + list = list->next; + } + } + + det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash; + mt_det_ctxs_hash = NULL; + + det_ctx->mt_det_ctxs_cnt = max_tenant_id; + + det_ctx->tenant_array = map_array; + det_ctx->tenant_array_size = map_array_size; + + switch (master->tenant_selector) { + case TENANT_SELECTOR_UNKNOWN: + SCLogDebug("TENANT_SELECTOR_UNKNOWN"); + break; + case TENANT_SELECTOR_VLAN: + det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId; + SCLogDebug("TENANT_SELECTOR_VLAN"); + break; + case TENANT_SELECTOR_DIRECT: + det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap; + SCLogDebug("TENANT_SELECTOR_DIRECT"); + break; + } + + return TM_ECODE_OK; +error: + if (map_array != NULL) + SCFree(map_array); + if (mt_det_ctxs_hash != NULL) + HashTableFree(mt_det_ctxs_hash); + + return TM_ECODE_FAILED; +} + /** \internal * \brief Helper for DetectThread setup functions */ @@ -1377,12 +1486,6 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * */ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) { - if (DetectEngineMultiTenantEnabled()) { - DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForMT(tv); - *data = (void *)mt_det_ctx; - return (mt_det_ctx == NULL) ? TM_ECODE_FAILED : TM_ECODE_OK; - } - /* first register the counter. In delayed detect mode we exit right after if the * rules haven't been loaded yet. */ uint16_t counter_alerts = StatsRegisterCounter("detect.alert", tv); @@ -1432,6 +1535,11 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) /* pass thread data back to caller */ *data = (void *)det_ctx; + if (DetectEngineMultiTenantEnabled()) { + if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) + return TM_ECODE_FAILED; + } + return TM_ECODE_OK; } @@ -1439,10 +1547,13 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) * \internal * \brief initialize a det_ctx for reload cases * \param new_de_ctx the new detection engine + * \param mt flag to indicate if MT should be set up for this det_ctx + * this should only be done for the 'root' det_ctx + * * \retval det_ctx detection engine thread ctx or NULL in case of error */ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( - ThreadVars *tv, DetectEngineCtx *new_de_ctx) + ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt) { DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); if (unlikely(det_ctx == NULL)) @@ -1477,6 +1588,14 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( det_ctx->counter_match_list = counter_match_list; #endif + if (mt && DetectEngineMultiTenantEnabled()) { + if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) { + DetectEngineDeReference(&det_ctx->de_ctx); + SCFree(det_ctx); + return NULL; + } + } + return det_ctx; } @@ -2059,12 +2178,6 @@ void DetectEngineMultiTenantSetup(void) /* wait for our loaders to complete their tasks */ if (DetectLoadersSync() != 0) goto error; - - if (DetectEngineMTApply() < 0) { - SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); - goto error; - } - } else { SCLogDebug("multi-detect not enabled (multi tenancy)"); } @@ -2072,7 +2185,7 @@ void DetectEngineMultiTenantSetup(void) return; } -uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p) +static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p) { const DetectEngineThreadCtx *det_ctx = ctx; uint32_t x = 0; @@ -2195,7 +2308,7 @@ int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id) return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0); } -uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p) +static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p) { return p->pcap_v.tenant_id; } @@ -2437,135 +2550,6 @@ static void TenantIdFree(void *d) DetectEngineThreadCtxFree(d); } -/** NOTE: master MUST be locked before calling this */ -static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv) -{ - DetectEngineMasterCtx *master = &g_master_de_ctx; - DetectEngineTenantMapping *map_array = NULL; - uint32_t map_array_size = 0; - uint32_t map_cnt = 0; - int max_tenant_id = 0; - DetectEngineCtx *list = master->list; - HashTable *mt_det_ctxs_hash = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - - if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) { - SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: " - "set using multi-detect.selector"); - return NULL; - } - - uint32_t tcnt = 0; - while (list) { - if (list->tenant_id > max_tenant_id) - max_tenant_id = list->tenant_id; - - list = list->next; - tcnt++; - } - - mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree); - if (mt_det_ctxs_hash == NULL) { - goto error; - } - - if (max_tenant_id == 0) { - SCLogInfo("no tenants left, or none registered yet"); - } else { - max_tenant_id++; - - DetectEngineTenantMapping *map = master->tenant_mapping_list; - while (map) { - map_cnt++; - map = map->next; - } - - if (map_cnt > 0) { - map_array_size = map_cnt + 1; - - map_array = SCCalloc(map_array_size, sizeof(*map_array)); - if (map_array == NULL) - goto error; - - /* fill the array */ - map_cnt = 0; - map = master->tenant_mapping_list; - while (map) { - BUG_ON(map_cnt > map_array_size); - map_array[map_cnt].traffic_id = map->traffic_id; - map_array[map_cnt].tenant_id = map->tenant_id; - map_cnt++; - map = map->next; - } - - } - - /* set up hash for tenant lookup */ - list = master->list; - while (list) { - if (list->tenant_id != 0) { - DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list); - if (mt_det_ctx == NULL) - goto error; - BUG_ON(HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0); - } - list = list->next; - } - } - - det_ctx = SCCalloc(1, sizeof(DetectEngineThreadCtx)); - if (det_ctx == NULL) { - goto error; - } - det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash; - mt_det_ctxs_hash = NULL; - - /* first register the counter. In delayed detect mode we exit right after if the - * rules haven't been loaded yet. */ - uint16_t counter_alerts = StatsRegisterCounter("detect.alert", tv); -#ifdef PROFILING - uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv); - uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv); - uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv); - uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv); -#endif - /** alert counter setup */ - det_ctx->counter_alerts = counter_alerts; -#ifdef PROFILING - det_ctx->counter_mpm_list = counter_mpm_list; - det_ctx->counter_nonmpm_list = counter_nonmpm_list; - det_ctx->counter_fnonmpm_list = counter_fnonmpm_list; - det_ctx->counter_match_list = counter_match_list; -#endif - det_ctx->mt_det_ctxs_cnt = max_tenant_id; - - det_ctx->tenant_array = map_array; - det_ctx->tenant_array_size = map_array_size; - - switch (master->tenant_selector) { - case TENANT_SELECTOR_UNKNOWN: - SCLogDebug("TENANT_SELECTOR_UNKNOWN"); - break; - case TENANT_SELECTOR_VLAN: - det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId; - SCLogDebug("TENANT_SELECTOR_VLAN"); - break; - case TENANT_SELECTOR_DIRECT: - det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap; - SCLogDebug("TENANT_SELECTOR_DIRECT"); - break; - } - - return det_ctx; -error: - if (map_array != NULL) - SCFree(map_array); - if (mt_det_ctxs_hash != NULL) - HashTableFree(mt_det_ctxs_hash); - - return NULL; -} - int DetectEngineMTApply(void) { DetectEngineMasterCtx *master = &g_master_de_ctx; @@ -2578,13 +2562,25 @@ int DetectEngineMTApply(void) } DetectEngineCtx *minimal_de_ctx = NULL; - /* if we have no tenants, we need a minimal on */ + /* if we have no tenants, we need a minimal one */ if (master->list == NULL) { minimal_de_ctx = master->list = DetectEngineCtxInitMinimal(); SCLogDebug("no tenants, using minimal %p", minimal_de_ctx); } else if (master->list->next == NULL && master->list->tenant_id == 0) { minimal_de_ctx = master->list; SCLogDebug("no tenants, using original %p", minimal_de_ctx); + + /* the default de_ctx should be in the list with tenant_id 0 */ + } else { + DetectEngineCtx *list = master->list; + for ( ; list != NULL; list = list->next) { + SCLogInfo("list %p tenant %u", list, list->tenant_id); + + if (list->tenant_id == 0) { + minimal_de_ctx = list; + break; + } + } } /* update the threads */ diff --git a/src/detect.c b/src/detect.c index 65f18dc67a80..401d2b008d32 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1998,12 +1998,10 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue det_ctx); } - if (det_ctx->TenantGetId != NULL) { - /* in MT mode, but no tenants registered yet */ - if (det_ctx->mt_det_ctxs_cnt == 0) { - return TM_ECODE_OK; - } - + /* if in MT mode _and_ we have tenants registered, use + * MT logic. */ + if (det_ctx->mt_det_ctxs_cnt > 0 && det_ctx->TenantGetId != NULL) + { uint32_t tenant_id = p->tenant_id; if (tenant_id == 0) tenant_id = det_ctx->TenantGetId(det_ctx, p); @@ -2021,7 +2019,8 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue SCLogDebug("MT de_ctx %p det_ctx %p (tenant %u)", de_ctx, det_ctx, tenant_id); } } else { - return TM_ECODE_OK; + /* use default if no tenants are registered for this packet */ + de_ctx = det_ctx->de_ctx; } } else { de_ctx = det_ctx->de_ctx; diff --git a/src/suricata.c b/src/suricata.c index 173ef75fb46e..876418e90baf 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2285,12 +2285,17 @@ int main(int argc, char **argv) if (!suri.disabled_detect) { SCClassConfInit(); SCReferenceConfInit(); - DetectEngineMultiTenantSetup(); SetupDelayedDetect(&suri); - if (!suri.delayed_detect) { - de_ctx = DetectEngineCtxInit(); - } else { + int mt_enabled = 0; + (void)ConfGetBool("multi-detect.enabled", &mt_enabled); + int default_tenant = 0; + if (mt_enabled) + (void)ConfGetBool("multi-detect.default", &default_tenant); + DetectEngineMultiTenantSetup(); + if (suri.delayed_detect || (mt_enabled && !default_tenant)) { de_ctx = DetectEngineCtxInitMinimal(); + } else { + de_ctx = DetectEngineCtxInit(); } if (de_ctx == NULL) { SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " @@ -2303,7 +2308,7 @@ int main(int argc, char **argv) CudaVarsSetDeCtx(de_ctx); #endif /* __SC_CUDA_SUPPORT__ */ - if (!suri.delayed_detect) { + if (!de_ctx->minimal) { if (LoadSignatures(de_ctx, &suri) != TM_ECODE_OK) exit(EXIT_FAILURE); if (suri.run_mode == RUNMODE_ENGINE_ANALYSIS) { From 04889f154d64e70d2b3e2e7bfc4977ecd53dacfd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 23 Nov 2015 13:30:03 +0100 Subject: [PATCH 0868/2553] multi-detect: validate vlan_id --- src/detect-engine.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 82d651994ed5..585e3f7c9f5b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2110,6 +2110,11 @@ void DetectEngineMultiTenantSetup(void) "of %s is invalid", vlan_id_node->val); goto bad_mapping; } + if (vlan_id == 0 || vlan_id >= 4095) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id " + "of %s is invalid. Valid range 1-4094.", vlan_id_node->val); + goto bad_mapping; + } if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) { goto error; From 27783f4c667262a7bbb6e962678ebaf0146e30d6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 23 Nov 2015 13:38:59 +0100 Subject: [PATCH 0869/2553] multi-detect: consider vlan tracking Refuse to use vlan selector if vlan tracking is disabled. --- src/detect-engine.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 585e3f7c9f5b..04aad76745db 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2067,6 +2067,15 @@ void DetectEngineMultiTenantSetup(void) if (strcmp(handler, "vlan") == 0) { master->tenant_selector = TENANT_SELECTOR_VLAN; + + int vlanbool = 0; + if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) { + SCLogError(SC_ERR_INVALID_VALUE, "vlan tracking is disabled, " + "can't use multi-detect selector 'vlan'"); + SCMutexUnlock(&master->lock); + goto error; + } + } else if (strcmp(handler, "direct") == 0) { master->tenant_selector = TENANT_SELECTOR_DIRECT; } else { From 906b95eed3cafcae4ebef1cbbc012e441948ce70 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 23 Nov 2015 14:05:21 +0100 Subject: [PATCH 0870/2553] multi-detect: handle missing mappings Notify/warn user about missing mappings depending on other settings like unix socket and init errors fatal. --- src/detect-engine.c | 28 ++++++++++++++++++++++++++-- src/util-error.c | 1 + src/util-error.h | 1 + 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 04aad76745db..63c1dafb4561 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2045,8 +2045,12 @@ int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int r */ void DetectEngineMultiTenantSetup(void) { + enum DetectEngineTenantSelectors tenant_selector = TENANT_SELECTOR_UNKNOWN; DetectEngineMasterCtx *master = &g_master_de_ctx; + int unix_socket = 0; + (void)ConfGetBool("unix-command.enabled", &unix_socket); + int failure_fatal = 0; (void)ConfGetBool("engine.init-failure-fatal", &failure_fatal); @@ -2066,7 +2070,7 @@ void DetectEngineMultiTenantSetup(void) SCLogInfo("multi-tenant selector type %s", handler); if (strcmp(handler, "vlan") == 0) { - master->tenant_selector = TENANT_SELECTOR_VLAN; + tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN; int vlanbool = 0; if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) { @@ -2077,7 +2081,7 @@ void DetectEngineMultiTenantSetup(void) } } else if (strcmp(handler, "direct") == 0) { - master->tenant_selector = TENANT_SELECTOR_DIRECT; + tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT; } else { SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s " "multi-detect.selector", handler); @@ -2092,6 +2096,7 @@ void DetectEngineMultiTenantSetup(void) ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings"); ConfNode *mapping_node = NULL; + int mapping_cnt = 0; if (mappings_root_node != NULL) { TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) { if (strcmp(mapping_node->val, "vlan") == 0) { @@ -2129,6 +2134,7 @@ void DetectEngineMultiTenantSetup(void) goto error; } SCLogInfo("vlan %u connected to tenant-id %u", vlan_id, tenant_id); + mapping_cnt++; } else { SCLogWarning(SC_ERR_INVALID_VALUE, "multi-detect.mappings expects a list of 'vlan's. Not %s", mapping_node->val); goto bad_mapping; @@ -2141,6 +2147,24 @@ void DetectEngineMultiTenantSetup(void) } } + if (tenant_selector == TENANT_SELECTOR_VLAN && mapping_cnt == 0) { + /* no mappings are valid when we're in unix socket mode, + * they can be added on the fly. Otherwise warn/error + * depending on failure_fatal */ + + if (unix_socket) { + SCLogNotice("no tenant traffic mappings defined, " + "tenants won't be used until mappings are added"); + } else { + if (failure_fatal) + SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined"); + else { + SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined"); + goto error; + } + } + } + /* tenants */ ConfNode *tenants_root_node = ConfGetNode("multi-detect.tenants"); ConfNode *tenant_node = NULL; diff --git a/src/util-error.c b/src/util-error.c index af266d334fea..7f2caf00d259 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -309,6 +309,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_IPPAIR_INIT); CASE_CODE (SC_ERR_MT_NO_SELECTOR); CASE_CODE (SC_ERR_MT_DUPLICATE_TENANT); + CASE_CODE (SC_ERR_MT_NO_MAPPING); CASE_CODE (SC_ERR_NO_JSON_SUPPORT); CASE_CODE (SC_ERR_INVALID_RULE_ARGUMENT); } diff --git a/src/util-error.h b/src/util-error.h index d0b247156790..cd2ce24927c6 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -301,6 +301,7 @@ typedef enum { SC_ERR_NO_JSON_SUPPORT, SC_ERR_INVALID_RULE_ARGUMENT, /**< Generic error code for invalid * rule argument. */ + SC_ERR_MT_NO_MAPPING, } SCError; const char *SCErrorToString(SCError); From 07d8617b3e0aab69d4fa6a3c4baee24480607bab Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 23 Nov 2015 14:58:34 +0100 Subject: [PATCH 0871/2553] multi-detect: improve error handling --- src/detect-engine.c | 23 ++++++++++++++--------- src/detect-engine.h | 2 +- src/suricata.c | 6 +++++- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 63c1dafb4561..f5b2edf0da6f 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2043,7 +2043,7 @@ int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int r * Tenants and mappings are optional, and can also dynamically be added * and removed from the unix socket. */ -void DetectEngineMultiTenantSetup(void) +int DetectEngineMultiTenantSetup(void) { enum DetectEngineTenantSelectors tenant_selector = TENANT_SELECTOR_UNKNOWN; DetectEngineMasterCtx *master = &g_master_de_ctx; @@ -2156,11 +2156,11 @@ void DetectEngineMultiTenantSetup(void) SCLogNotice("no tenant traffic mappings defined, " "tenants won't be used until mappings are added"); } else { - if (failure_fatal) - SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined"); - else { + if (failure_fatal) { SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined"); goto error; + } else { + SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined"); } } } @@ -2176,11 +2176,13 @@ void DetectEngineMultiTenantSetup(void) goto bad_tenant; } ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id"); - if (id_node == NULL) + if (id_node == NULL) { goto bad_tenant; + } ConfNode *yaml_node = ConfNodeLookupChild(tenant_node, "yaml"); - if (yaml_node == NULL) + if (yaml_node == NULL) { goto bad_tenant; + } uint32_t tenant_id = 0; if (ByteExtractStringUint32(&tenant_id, 10, strlen(id_node->val), @@ -2201,7 +2203,8 @@ void DetectEngineMultiTenantSetup(void) goto bad_tenant; } - if (DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val) != 0) { + int r = DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val); + if (r < 0) { /* error logged already */ goto bad_tenant; } @@ -2214,13 +2217,15 @@ void DetectEngineMultiTenantSetup(void) } /* wait for our loaders to complete their tasks */ - if (DetectLoadersSync() != 0) + if (DetectLoadersSync() != 0) { goto error; + } } else { SCLogDebug("multi-detect not enabled (multi tenancy)"); } + return 0; error: - return; + return -1; } static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p) diff --git a/src/detect-engine.h b/src/detect-engine.h index 7b62171007b2..70b18133fcb3 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -79,7 +79,7 @@ int DetectEngineReload(const char *filename, SCInstance *suri); int DetectEngineEnabled(void); int DetectEngineMTApply(void); int DetectEngineMultiTenantEnabled(void); -void DetectEngineMultiTenantSetup(void); +int DetectEngineMultiTenantSetup(void); int DetectEngineReloadStart(void); int DetectEngineReloadIsStart(void); diff --git a/src/suricata.c b/src/suricata.c index 876418e90baf..b368f21d07f5 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2291,7 +2291,11 @@ int main(int argc, char **argv) int default_tenant = 0; if (mt_enabled) (void)ConfGetBool("multi-detect.default", &default_tenant); - DetectEngineMultiTenantSetup(); + if (DetectEngineMultiTenantSetup() == -1) { + SCLogError(SC_ERR_INITIALIZATION, "initializing multi-detect " + "detection engine contexts failed."); + exit(EXIT_FAILURE); + } if (suri.delayed_detect || (mt_enabled && !default_tenant)) { de_ctx = DetectEngineCtxInitMinimal(); } else { From 4dfbc0effa668745a5535ce81b32f2e0cebcaca8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 23 Nov 2015 17:18:57 +0100 Subject: [PATCH 0872/2553] multi-detect: fix and simplify config instead mappings: - vlan: vlan-id: 1 tenant-id: 2 we'll now use: mappings: - vlan-id: 1 tenant-id: 2 For YAML it pretty much means the same thing. Ticket: 1517 --- src/detect-engine.c | 71 ++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index f5b2edf0da6f..cba76ca3698d 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2099,46 +2099,41 @@ int DetectEngineMultiTenantSetup(void) int mapping_cnt = 0; if (mappings_root_node != NULL) { TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) { - if (strcmp(mapping_node->val, "vlan") == 0) { - ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id"); - if (tenant_id_node == NULL) - goto bad_mapping; - ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id"); - if (vlan_id_node == NULL) - goto bad_mapping; - - uint32_t tenant_id = 0; - if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val), - tenant_id_node->val) == -1) - { - SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id " - "of %s is invalid", tenant_id_node->val); - goto bad_mapping; - } + ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id"); + if (tenant_id_node == NULL) + goto bad_mapping; + ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id"); + if (vlan_id_node == NULL) + goto bad_mapping; - uint16_t vlan_id = 0; - if (ByteExtractStringUint16(&vlan_id, 10, strlen(vlan_id_node->val), - vlan_id_node->val) == -1) - { - SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id " - "of %s is invalid", vlan_id_node->val); - goto bad_mapping; - } - if (vlan_id == 0 || vlan_id >= 4095) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id " - "of %s is invalid. Valid range 1-4094.", vlan_id_node->val); - goto bad_mapping; - } + uint32_t tenant_id = 0; + if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val), + tenant_id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id " + "of %s is invalid", tenant_id_node->val); + goto bad_mapping; + } - if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) { - goto error; - } - SCLogInfo("vlan %u connected to tenant-id %u", vlan_id, tenant_id); - mapping_cnt++; - } else { - SCLogWarning(SC_ERR_INVALID_VALUE, "multi-detect.mappings expects a list of 'vlan's. Not %s", mapping_node->val); + uint16_t vlan_id = 0; + if (ByteExtractStringUint16(&vlan_id, 10, strlen(vlan_id_node->val), + vlan_id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id " + "of %s is invalid", vlan_id_node->val); goto bad_mapping; } + if (vlan_id == 0 || vlan_id >= 4095) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id " + "of %s is invalid. Valid range 1-4094.", vlan_id_node->val); + goto bad_mapping; + } + + if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) { + goto error; + } + SCLogInfo("vlan %u connected to tenant-id %u", vlan_id, tenant_id); + mapping_cnt++; continue; bad_mapping: @@ -2171,10 +2166,6 @@ int DetectEngineMultiTenantSetup(void) if (tenants_root_node != NULL) { TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) { - if (strcmp(tenant_node->val, "tenant") != 0) { - SCLogWarning(SC_ERR_INVALID_VALUE, "multi-detect.tenants expects a list of 'tenant's. Not %s", tenant_node->val); - goto bad_tenant; - } ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id"); if (id_node == NULL) { goto bad_tenant; From 50f4fb2a7259a4b76c5c7fc5ee63e3be3ccdb10e Mon Sep 17 00:00:00 2001 From: Aaron Campbell Date: Mon, 2 Nov 2015 15:19:12 -0400 Subject: [PATCH 0873/2553] Fix out-of-bounds memory access in DNS TXT record parser. The datalen variable is declared unsigned. If txtlen and datalen are equal, datalen will first be reduced to 0, and then the datalen-- line will cause its value to wrap to 65535. This will cause the loop to continue much longer than intended, and eventually may crash on an out-of-bounds *tdata dereference. Signed-off-by: Aaron Campbell --- src/app-layer-dns-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 4a3f9ccd0539..3c67fe44d2cf 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -979,7 +979,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ do { //PrintRawDataFp(stdout, (uint8_t*)tdata, txtlen); - if (txtlen > datalen) + if (txtlen >= datalen) goto bad_data; DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, From e86e27bab74e1063bfa84f50719b1bb6f26b1353 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 11 Jul 2015 22:52:23 +0200 Subject: [PATCH 0874/2553] http: test cleanups --- src/app-layer-htp.c | 81 ++++++++------------------------------------- 1 file changed, 14 insertions(+), 67 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 0abcda3bb4c5..4deef34759ec 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2824,7 +2824,7 @@ void HtpConfigRestoreBackup(void) * response of the parser from HTP library. */ int HTPParserTest01(void) { - int result = 1; + int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" " Data is c0oL!"; @@ -2860,7 +2860,6 @@ int HTPParserTest01(void) if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -2870,7 +2869,6 @@ int HTPParserTest01(void) htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -2885,10 +2883,10 @@ int HTPParserTest01(void) " and got: %s \n", bstr_util_strdup_to_c(h->value), bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -2903,7 +2901,7 @@ int HTPParserTest01(void) * response of the parser from HTP library. */ static int HTPParserTest01a(void) { - int result = 1; + int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" " Data is c0oL!"; @@ -2939,7 +2937,6 @@ static int HTPParserTest01a(void) if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -2949,7 +2946,6 @@ static int HTPParserTest01a(void) htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -2964,10 +2960,9 @@ static int HTPParserTest01a(void) " and got: %s \n", bstr_util_strdup_to_c(h->value), bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } - + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -2981,7 +2976,7 @@ static int HTPParserTest01a(void) /** \test See how it deals with an incomplete request. */ int HTPParserTest02(void) { - int result = 1; + int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ @@ -3004,7 +2999,6 @@ int HTPParserTest02(void) STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3013,7 +3007,6 @@ int HTPParserTest02(void) http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -3022,10 +3015,9 @@ int HTPParserTest02(void) if ((tx->request_method) != NULL || h != NULL) { printf("expected method NULL, got %s \n", bstr_util_strdup_to_c(tx->request_method)); - result = 0; goto end; } - + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -3040,12 +3032,11 @@ int HTPParserTest02(void) * and check the response of the parser from HTP library. */ int HTPParserTest03(void) { - int result = 1; + int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; - HtpState *htp_state = NULL; int r = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3073,7 +3064,6 @@ int HTPParserTest03(void) if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3082,7 +3072,6 @@ int HTPParserTest03(void) htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -3095,10 +3084,9 @@ int HTPParserTest03(void) printf("expected method M_UNKNOWN and got %s: , expected protocol " "HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } - + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -3113,7 +3101,7 @@ int HTPParserTest03(void) * parser from HTP library. */ int HTPParserTest04(void) { - int result = 1; + int result = 0; Flow *f = NULL; HtpState *htp_state = NULL; uint8_t httpbuf1[] = "World!\r\n"; @@ -3144,7 +3132,6 @@ int HTPParserTest04(void) htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -3156,10 +3143,9 @@ int HTPParserTest04(void) printf("expected method M_UNKNOWN and got %s: , expected protocol " "NULL and got %s \n", bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } - + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -3174,7 +3160,7 @@ int HTPParserTest04(void) * properly parsed them and also keeps them separated. */ int HTPParserTest05(void) { - int result = 1; + int result = 0; Flow *f = NULL; HtpState *http_state = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\n"; @@ -3208,7 +3194,6 @@ int HTPParserTest05(void) httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3217,7 +3202,6 @@ int HTPParserTest05(void) httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3225,7 +3209,6 @@ int HTPParserTest05(void) r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3233,7 +3216,6 @@ int HTPParserTest05(void) r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3242,7 +3224,6 @@ int HTPParserTest05(void) httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3251,7 +3232,6 @@ int HTPParserTest05(void) httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3260,7 +3240,6 @@ int HTPParserTest05(void) http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -3272,7 +3251,6 @@ int HTPParserTest05(void) printf("expected method M_POST and got %s: , expected protocol " "HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } @@ -3281,9 +3259,9 @@ int HTPParserTest05(void) "HTTP/1.0 and got %s \n", tx->response_status_number, bstr_util_strdup_to_c(tx->response_message), bstr_util_strdup_to_c(tx->response_protocol)); - result = 0; goto end; } + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -3298,7 +3276,7 @@ int HTPParserTest05(void) */ int HTPParserTest06(void) { - int result = 1; + int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " @@ -3361,7 +3339,6 @@ int HTPParserTest06(void) httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3370,7 +3347,6 @@ int HTPParserTest06(void) httplen2); if (r != 0) { printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3379,7 +3355,6 @@ int HTPParserTest06(void) http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -3391,7 +3366,6 @@ int HTPParserTest06(void) printf("expected method M_GET and got %s: , expected protocol " "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } @@ -3402,9 +3376,9 @@ int HTPParserTest06(void) "col HTTP/1.1 and got %s \n", tx->response_status_number, bstr_util_strdup_to_c(tx->response_message), bstr_util_strdup_to_c(tx->response_protocol)); - result = 0; goto end; } + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -3640,7 +3614,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk returned %" PRId32 ", expected" " 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -3649,7 +3622,6 @@ libhtp:\n\ htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -4577,7 +4549,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -4587,7 +4558,6 @@ libhtp:\n\ htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -4748,7 +4718,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -4758,7 +4727,6 @@ libhtp:\n\ htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -4917,7 +4885,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -4927,7 +4894,6 @@ libhtp:\n\ htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5056,7 +5022,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -5066,7 +5031,6 @@ libhtp:\n\ htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5168,7 +5132,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -5178,7 +5141,6 @@ libhtp:\n\ htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5280,7 +5242,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -5290,7 +5251,6 @@ libhtp:\n\ htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5393,7 +5353,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -5403,7 +5362,6 @@ libhtp:\n\ htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5503,7 +5461,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -5513,7 +5470,6 @@ libhtp:\n\ htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5614,7 +5570,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -5624,7 +5579,6 @@ libhtp:\n\ htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5770,7 +5724,6 @@ libhtp:\n\ int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -5780,7 +5733,6 @@ libhtp:\n\ r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -5789,7 +5741,6 @@ libhtp:\n\ http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5893,7 +5844,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -5901,7 +5851,6 @@ libhtp:\n\ if (r != -1) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " -1: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -6036,7 +5985,6 @@ libhtp:\n\ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; SCMutexUnlock(&f->m); goto end; } @@ -6119,7 +6067,6 @@ int HTPParserTest16(void) r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)httpbuf, len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; SCMutexUnlock(&f->m); goto end; } From cd81af0bc989a20a005cc5d0f7949d7369fb70b5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Jul 2015 11:26:41 +0200 Subject: [PATCH 0875/2553] http: don't run unittests twice --- src/runmode-unittests.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 3701d29af785..332202095800 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -206,7 +206,6 @@ void RunUnittests(int list_unittests, char *regex_arg) StatsRegisterTests(); DecodePPPRegisterTests(); DecodeVLANRegisterTests(); - HTPParserRegisterTests(); DecodeRawRegisterTests(); DecodePPPOERegisterTests(); DecodeICMPV4RegisterTests(); From a1075ee2f29f523676b7a24ef1628e991931784c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 11 Jul 2015 11:43:34 +0200 Subject: [PATCH 0876/2553] http: add test for plain http over connect --- src/app-layer-htp.c | 351 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 4deef34759ec..e8da88eb8cd3 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -6117,6 +6117,354 @@ int HTPParserTest16(void) return result; } +/** \test CONNECT with plain text HTTP being tunneled */ +int HTPParserTest17(void) +{ + int result = 0; + Flow *f = NULL; + HtpState *http_state = NULL; + /* CONNECT setup */ + uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + /* plain text HTTP */ + uint8_t httpbuf3[] = "GET / HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + uint8_t httpbuf4[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&f->m); + int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, + httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2, + httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf4, + httplen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + + SCMutexUnlock(&f->m); + + http_state = f->alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + if (tx == NULL) + goto end; + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_CONNECT || + h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_POST and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + if (tx->response_status_number != 200) { + printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx->response_status_number, + bstr_util_strdup_to_c(tx->response_message), + bstr_util_strdup_to_c(tx->response_protocol)); + goto end; + } + + tx = HTPStateGetTx(http_state, 1); + if (tx == NULL) + goto end; + h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_GET || + h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_GET and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + if (tx->response_status_number != 200) { + printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx->response_status_number, + bstr_util_strdup_to_c(tx->response_message), + bstr_util_strdup_to_c(tx->response_protocol)); + goto end; + } + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + if (http_state != NULL) + HTPStateFree(http_state); + UTHFreeFlow(f); + return result; +} + +/** \test CONNECT with plain text HTTP being tunneled */ +int HTPParserTest18(void) +{ + int result = 0; + Flow *f = NULL; + HtpState *http_state = NULL; + /* CONNECT setup */ + uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + /* plain text HTTP */ + uint8_t httpbuf3[] = "GE"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + uint8_t httpbuf4[] = "T / HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + uint8_t httpbuf5[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&f->m); + int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, + httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2, + httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf4, httplen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + + + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5, + httplen5); + if (r != 0) { + printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + + SCMutexUnlock(&f->m); + + http_state = f->alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + if (tx == NULL) + goto end; + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_CONNECT || + h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_POST and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + if (tx->response_status_number != 200) { + printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx->response_status_number, + bstr_util_strdup_to_c(tx->response_message), + bstr_util_strdup_to_c(tx->response_protocol)); + goto end; + } + + tx = HTPStateGetTx(http_state, 1); + if (tx == NULL) + goto end; + h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_GET || + h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_GET and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + if (tx->response_status_number != 200) { + printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx->response_status_number, + bstr_util_strdup_to_c(tx->response_message), + bstr_util_strdup_to_c(tx->response_protocol)); + goto end; + } + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + if (http_state != NULL) + HTPStateFree(http_state); + UTHFreeFlow(f); + return result; +} + +/** \test CONNECT with TLS content (start of it at least) */ +int HTPParserTest19(void) +{ + int result = 0; + Flow *f = NULL; + HtpState *http_state = NULL; + /* CONNECT setup */ + uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + /* start of TLS/SSL */ + uint8_t httpbuf3[] = "\x16\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&f->m); + int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, + httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2, + httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + + SCMutexUnlock(&f->m); + + http_state = f->alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + if (tx == NULL) + goto end; + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_CONNECT || + h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_POST and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + if (tx->response_status_number != 200) { + printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx->response_status_number, + bstr_util_strdup_to_c(tx->response_message), + bstr_util_strdup_to_c(tx->response_protocol)); + goto end; + } + + /* no new tx should have been set up for the tunneled data */ + tx = HTPStateGetTx(http_state, 1); + if (tx != NULL) + goto end; + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + if (http_state != NULL) + HTPStateFree(http_state); + UTHFreeFlow(f); + return result; +} + #endif /* UNITTESTS */ /** @@ -6163,6 +6511,9 @@ void HTPParserRegisterTests(void) UtRegisterTest("HTPParserTest14", HTPParserTest14, 1); UtRegisterTest("HTPParserTest15", HTPParserTest15, 1); UtRegisterTest("HTPParserTest16", HTPParserTest16, 1); + UtRegisterTest("HTPParserTest17", HTPParserTest17, 1); + UtRegisterTest("HTPParserTest18", HTPParserTest18, 1); + UtRegisterTest("HTPParserTest19", HTPParserTest19, 1); HTPFileParserRegisterTests(); HTPXFFParserRegisterTests(); From a7f54d63b73877984d240791a84765462a0db561 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 24 Nov 2015 12:06:04 +0100 Subject: [PATCH 0877/2553] tls: fix compiler warnings --- src/app-layer-ssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 2c20a0544808..3d4605aff7d5 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -126,7 +126,7 @@ SslConfig ssl_config; #define TLS_HB_REQUEST 1 #define TLS_HB_RESPONSE 2 -#define HAS_SPACE(n) (((input) + (n) - (initial_input)) > (input_len)) ? 0 : 1 +#define HAS_SPACE(n) ((uint32_t)((input) + (n) - (initial_input)) > (uint32_t)(input_len)) ? 0 : 1 static void SSLParserReset(SSLState *ssl_state) { From d77e4030249598bb1b6bb39aca46780bdc474817 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Nov 2015 12:17:51 +0100 Subject: [PATCH 0878/2553] rule vars: fix compiler warning --- src/util-rule-vars.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-rule-vars.c b/src/util-rule-vars.c index f3b5604fbed2..57347f4ff849 100644 --- a/src/util-rule-vars.c +++ b/src/util-rule-vars.c @@ -75,7 +75,7 @@ char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx, if (conf_var_name == NULL) goto end; - while (conf_var_name[0] != '\0' && isspace(conf_var_name[0])) { + while (conf_var_name[0] != '\0' && isspace((unsigned char)conf_var_name[0])) { conf_var_name++; } From 84c4566a14a2f5aad5e8f10cf70a826c2aa22404 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Nov 2015 13:02:48 +0100 Subject: [PATCH 0879/2553] Update dev version to reflect we're doing 3.0 now --- configure.ac | 2 +- src/suricata.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 9e13938304c7..f3d20a1f5f0a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ - AC_INIT(suricata, 2.1dev) + AC_INIT(suricata, 3.0dev) m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([src/suricata.c]) diff --git a/src/suricata.h b/src/suricata.h index 12e72697a07d..b11239ac2e9c 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -71,7 +71,7 @@ /* the name of our binary */ #define PROG_NAME "Suricata" -#define PROG_VER "2.1dev" +#define PROG_VER "3.0dev" /* workaround SPlint error (don't know __gnuc_va_list) */ #ifdef S_SPLINT_S From 737c99dd308d437765fc7d74b64b437884febe0a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Nov 2015 13:03:40 +0100 Subject: [PATCH 0880/2553] Update changelog for 3.0RC1 --- ChangeLog | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/ChangeLog b/ChangeLog index a265dd7657b2..a7e645986cc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,56 @@ +3.0RC1 -- 2015-11-25 + +Bug #1150: TLS store disabled by TLS EVE logging +Bug #1210: global counters in stats.log +Bug #1423: Unix domain log file writer should automatically reconnect if receiving program is restarted. +Bug #1466: Rule reload - Rules won't reload if rule files are listed in an included file. +Bug #1467: Specifying an IPv6 entry before an IPv4 entry in host-os-policy causes ASAN heap-buffer-overflow. +Bug #1472: Should 'goodsigs' be 'goodtotal' when checking if signatures were loaded in detect.c? +Bug #1475: app-layer-modbus: AddressSanitizer error (heap-buffer-overflow) +Bug #1481: Leading whitespace in flowbits variable names +Bug #1482: suricata 2.1 beta4: StoreStateTxFileOnly crashes +Bug #1485: hostbits - leading and trailing spaces are treated as part of the name and direction. +Bug #1488: stream_size <= and >= modifiers function as < and > (equality is not functional) +Bug #1491: pf_ring is not able to capture packets when running under non-root account +Bug #1493: config test (-T) doesn't fail on missing files +Bug #1494: off by one on rulefile count +Bug #1500: suricata.log +Bug #1508: address var parsing issue +Bug #1517: Order dependent, ambiguous YAML in multi-detect. +Bug #1518: multitenancy - selector vlan - vlan id range +Bug #1521: multitenancy - global vlan tracking relation to selector +Bug #1523: Decoded base64 payload short by 16 characters +Bug #1530: multitenant mapping relation +Bug #1531: multitenancy - confusing tenant id and vlan id output +Bug #1556: MTU setting on NIC interface not considered by af-packet +Bug #1557: stream: retransmission not detected +Bug #1565: defrag: evasion issue +Bug #1597: dns parser issue (master) +Bug #1601: tls: server name logging +Feature #1116: ips packet stats in stats.log +Feature #1137: Support IP lists in threshold.config +Feature #1228: Suricata stats.log in JSON format +Feature #1265: Replace response on Suricata dns decoder when dns error please +Feature #1281: long snort ruleset support for "SC_ERR_NOT_SUPPORTED(225): content length greater than 255 unsupported" +Feature #1282: support for base64_decode from snort's ruleset +Feature #1342: Support Cisco erspan traffic +Feature #1374: Write pre-aggregated counters for all threads +Feature #1408: multi tenancy for detection +Feature #1440: Load rules file from a folder or with a star pattern rather then adding them manually to suricata.yaml +Feature #1454: Proposal to add Lumberjack/CEE formatting option to EVE JSON syslog output for compatibility with rsyslog parsing +Feature #1492: Add HUP coverage to output json-log +Feature #1498: color output +Feature #1499: json output for engine messages +Feature #1502: Expose tls fields to lua +Feature #1514: SSH softwareversion regex should allow colon +Feature #1527: Add ability to compile as a Position-Independent Executable (PIE) +Feature #1568: TLS lua output support +Feature #1569: SSH lua support +Feature #1582: Redis output support +Feature #1586: Add flow memcap counter +Feature #1599: rule profiling: json output +Optimization #1269: Convert SM List from linked list to array + 2.1beta4 -- 2015-05-08 Bug #1314: http-events performance issues From 1291250c0f715cdb22a8c17383370ae14306afa0 Mon Sep 17 00:00:00 2001 From: Maurizio Abba Date: Mon, 16 Nov 2015 12:14:24 +0000 Subject: [PATCH 0881/2553] app-layer-smtp: support for multiline response Multiline response support is provided but not enforced. This patch allow parsing multiline response when a reply is processed --- src/app-layer-smtp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 0c161edb591b..cd0a732e1eb7 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -879,7 +879,12 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, if (state->cmds_idx == state->cmds_cnt) { if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN; + /* the first server reply can be a multiline message. Let's + * flag the fact that we have seen the first reply only at the end + * of a multiline reply + */ + if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) + state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN; if (reply_code == SMTP_REPLY_220) SCReturnInt(0); else From 9930f447d24ac613f3747aa4e61896312109a698 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 23 Nov 2015 13:46:18 +0100 Subject: [PATCH 0882/2553] output-json: fix regression on log prefix handling The log prefix option was not anymore honored due to a regression caused by some recent code. --- src/output-json.c | 5 +++++ src/util-logopenfile.c | 4 +++- src/util-logopenfile.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/output-json.c b/src/output-json.c index fcc3a9559e70..5cd4263df06a 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -356,6 +356,9 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) json_string(file_ctx->sensor_name)); } + if (file_ctx->prefix) + MemBufferWriteRaw(buffer, file_ctx->prefix, file_ctx->prefix_len); + int r = json_dump_callback(js, MemBufferCallback, buffer, JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| #ifdef JSON_ESCAPE_SLASH @@ -496,6 +499,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) const char *prefix = ConfNodeLookupChildValue(conf, "prefix"); if (prefix != NULL) { + SCLogInfo("Using prefix '%s' for JSON message", prefix); json_ctx->file_ctx->prefix = SCStrdup(prefix); if (json_ctx->file_ctx->prefix == NULL) { @@ -503,6 +507,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) "Failed to allocate memory for eve-log.prefix setting."); exit(EXIT_FAILURE); } + json_ctx->file_ctx->prefix_len = strlen(prefix); } if (json_ctx->json_out == LOGFILE_TYPE_FILE || diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 65b80facccb0..84e5d2fe631b 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -519,8 +519,10 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) SCMutexDestroy(&lf_ctx->fp_mutex); - if (lf_ctx->prefix != NULL) + if (lf_ctx->prefix != NULL) { SCFree(lf_ctx->prefix); + lf_ctx->prefix_len = 0; + } if(lf_ctx->filename != NULL) SCFree(lf_ctx->filename); diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index f0a123accbcc..cccbba47d054 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -102,6 +102,7 @@ typedef struct LogFileCtx_ { /**< Used by some alert loggers like the unified ones that append * the date onto the end of files. */ char *prefix; + size_t prefix_len; /** Generic size_limit and size_current * They must be common to the threads accesing the same file */ From ac476de5ed9561bcef5833151891d1d534537bf8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Nov 2015 13:03:11 +0100 Subject: [PATCH 0883/2553] json: small improvement to log message wording --- src/output-json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output-json.c b/src/output-json.c index 5cd4263df06a..b9c2b886e637 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -499,7 +499,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) const char *prefix = ConfNodeLookupChildValue(conf, "prefix"); if (prefix != NULL) { - SCLogInfo("Using prefix '%s' for JSON message", prefix); + SCLogInfo("Using prefix '%s' for JSON messages", prefix); json_ctx->file_ctx->prefix = SCStrdup(prefix); if (json_ctx->file_ctx->prefix == NULL) { From 019f85644251fc56ae12122ec0fc6279017d96b9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 Nov 2015 09:50:50 +0100 Subject: [PATCH 0884/2553] profiling: fix lock profile compilation --- src/util-profiling-locks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util-profiling-locks.c b/src/util-profiling-locks.c index 97cc3e0d8a30..7719e6d5b732 100644 --- a/src/util-profiling-locks.c +++ b/src/util-profiling-locks.c @@ -24,13 +24,13 @@ * */ -#ifdef PROFILING -#ifdef PROFILE_LOCKING - #include "suricata-common.h" #include "util-profiling-locks.h" #include "util-hashlist.h" +#ifdef PROFILING +#ifdef PROFILE_LOCKING + __thread ProfilingLock locks[PROFILING_MAX_LOCKS]; __thread int locks_idx = 0; __thread int record_locks = 0; From 8ac48872a5a005bf97bb90cdc0ecf1fe620448a2 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Mon, 30 Nov 2015 11:21:05 +0300 Subject: [PATCH 0885/2553] Feature 1605: more descriptive error messages when checking MTU, etc --- src/util-ioctl.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index f08dea719e2d..59e2bf282728 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -90,8 +90,8 @@ int GetIfaceMTU(const char *pcap_dev) if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { SCLogWarning(SC_ERR_SYSCALL, - "Failure when trying to get MTU via ioctl: %d", - errno); + "Failure when trying to get MTU via ioctl for '%s': %s (%d)", + pcap_dev, strerror(errno), errno); close(fd); return -1; } @@ -169,8 +169,8 @@ int GetIfaceOffloading(const char *pcap_dev) ifr.ifr_data = (void *) ðv; if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { SCLogWarning(SC_ERR_SYSCALL, - "Failure when trying to get feature via ioctl: %s (%d)", - strerror(errno), errno); + "Failure when trying to get feature via ioctl for '%s': %s (%d)", + pcap_dev, strerror(errno), errno); close(fd); return -1; } else { @@ -188,8 +188,8 @@ int GetIfaceOffloading(const char *pcap_dev) ifr.ifr_data = (void *) ðv; if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { SCLogWarning(SC_ERR_SYSCALL, - "Failure when trying to get feature via ioctl: %s (%d)", - strerror(errno), errno); + "Failure when trying to get feature via ioctl for '%s': %s (%d)", + pcap_dev, strerror(errno), errno); close(fd); return -1; } else { @@ -221,8 +221,8 @@ int GetIfaceRSSQueuesNum(const char *pcap_dev) fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { SCLogWarning(SC_ERR_SYSCALL, - "Failure when opening socket for ioctl: %d", - errno); + "Failure when opening socket for ioctl: %s (%d)", + strerror(errno), errno); return -1; } @@ -232,8 +232,8 @@ int GetIfaceRSSQueuesNum(const char *pcap_dev) if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { if (errno != ENOTSUP) { SCLogWarning(SC_ERR_SYSCALL, - "Failure when trying to get number of RSS queue ioctl: %d", - errno); + "Failure when trying to get number of RSS queue ioctl for '%s': %s (%d)", + pcap_dev, strerror(errno), errno); } close(fd); return 0; From 538f37bd384846d53e5bb70ce04164eff6c673f6 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 3 Dec 2015 12:07:03 +0100 Subject: [PATCH 0886/2553] output-json: add app_proto key in root By adding the key in the root of *flow and fileinfo events it will be possible to get all events for one application layer by using a 'event_type:proto OR app_proto:proto' filter. This will permit to the analyst to get a good view of events related to one protocol. This patch also fixes a regression in file logging where app_proto was available before 94dbd303e4744a40f3761265be7c73a7a4754764 create the regression. --- src/output-json-file.c | 2 ++ src/output-json-flow.c | 2 +- src/output-json-netflow.c | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/output-json-file.c b/src/output-json-file.c index 9506a74670dc..32f3a9435c7f 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -108,6 +108,8 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F break; } + json_object_set_new(js, "app_proto", + json_string(AppProtoToString(p->flow->alproto))); json_t *fjs = json_object(); if (unlikely(fjs == NULL)) { diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 7ff0d3d22ebc..f89c32df7097 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -188,7 +188,7 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) return; } - json_object_set_new(hjs, "app_proto", json_string(AppProtoToString(f->alproto))); + json_object_set_new(js, "app_proto", json_string(AppProtoToString(f->alproto))); json_object_set_new(hjs, "pkts_toserver", json_integer(f->todstpktcnt)); diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 153beb3ded39..1b1fa8c0bdeb 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -194,7 +194,7 @@ static void JsonNetFlowLogJSONToServer(JsonNetFlowLogThread *aft, json_t *js, Fl return; } - json_object_set_new(hjs, "app_proto", + json_object_set_new(js, "app_proto", json_string(AppProtoToString(f->alproto_ts ? f->alproto_ts : f->alproto))); json_object_set_new(hjs, "pkts", @@ -243,7 +243,7 @@ static void JsonNetFlowLogJSONToClient(JsonNetFlowLogThread *aft, json_t *js, Fl return; } - json_object_set_new(hjs, "app_proto", + json_object_set_new(js, "app_proto", json_string(AppProtoToString(f->alproto_tc ? f->alproto_tc : f->alproto))); json_object_set_new(hjs, "pkts", From d87a60f3cc87d346a9b1e04ff133dfed6e9f7cbe Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 3 Dec 2015 15:40:08 -0600 Subject: [PATCH 0887/2553] modbus: disable by default --- src/app-layer-modbus.c | 14 +++----------- suricata.yaml.in | 4 ++-- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index fa965135d394..2d2cdc3d2e2d 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1427,21 +1427,13 @@ void RegisterModbusParsers(void) STREAM_TOSERVER, ModbusProbingParser); } else { - /* if we have no config, we enable the default port 502 */ + /* If there is no app-layer section for Modbus, silently + * leave it disabled. */ if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_MODBUS, 0, sizeof(ModbusHeader), ModbusProbingParser)) { - SCLogWarning(SC_ERR_MODBUS_CONFIG, "no Modbus TCP config found, " - "enabling Modbus detection on " - "port 502."); - - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "502", - ALPROTO_MODBUS, - 0, sizeof(ModbusHeader), - STREAM_TOSERVER, - ModbusProbingParser); + return; } } diff --git a/suricata.yaml.in b/suricata.yaml.in index af54b5274dd5..a612fb25dedd 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1171,7 +1171,7 @@ rule-files: - smtp-events.rules # available in suricata sources under rules dir - dns-events.rules # available in suricata sources under rules dir - tls-events.rules # available in suricata sources under rules dir - - modbus-events.rules # available in suricata sources under rules dir +# - modbus-events.rules # available in suricata sources under rules dir - app-layer-events.rules # available in suricata sources under rules dir classification-file: @e_sysconfdir@classification.config @@ -1350,7 +1350,7 @@ app-layer: # If the limit is reached, app-layer-event:modbus.flooded; will match. #request-flood: 500 - enabled: yes + enabled: no detection-ports: dp: 502 # According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it From 7b45a8a2a9cad49331654ee450e2c51b0cc26537 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 7 Nov 2015 19:28:25 +0100 Subject: [PATCH 0888/2553] device: constify string args --- src/util-device.c | 8 ++++---- src/util-device.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/util-device.c b/src/util-device.c index c08e30f0b89d..fb2c04f649eb 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -42,7 +42,7 @@ static int live_devices_stats = 1; * \retval 0 on success. * \retval -1 on failure. */ -int LiveRegisterDevice(char *dev) +int LiveRegisterDevice(const char *dev) { LiveDevice *pd = SCMalloc(sizeof(LiveDevice)); if (unlikely(pd == NULL)) { @@ -113,7 +113,7 @@ char *LiveGetDeviceName(int number) * \retval ptr pointer to the string containing the device * \retval NULL on error */ -LiveDevice *LiveGetDevice(char *name) +LiveDevice *LiveGetDevice(const char *name) { int i = 0; LiveDevice *pd; @@ -136,12 +136,12 @@ LiveDevice *LiveGetDevice(char *name) -int LiveBuildDeviceList(char * runmode) +int LiveBuildDeviceList(const char *runmode) { return LiveBuildDeviceListCustom(runmode, "interface"); } -int LiveBuildDeviceListCustom(char * runmode, char * itemname) +int LiveBuildDeviceListCustom(const char *runmode, const char *itemname) { ConfNode *base = ConfGetNode(runmode); ConfNode *child; diff --git a/src/util-device.h b/src/util-device.h index fd6a82131333..1fabdbe59665 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -32,14 +32,14 @@ typedef struct LiveDevice_ { } LiveDevice; -int LiveRegisterDevice(char *dev); +int LiveRegisterDevice(const char *dev); int LiveGetDeviceCount(void); char *LiveGetDeviceName(int number); -LiveDevice *LiveGetDevice(char *dev); -int LiveBuildDeviceList(char * base); +LiveDevice *LiveGetDevice(const char *dev); +int LiveBuildDeviceList(const char *base); void LiveDeviceHasNoStats(void); int LiveDeviceListClean(void); -int LiveBuildDeviceListCustom(char * base, char * itemname); +int LiveBuildDeviceListCustom(const char *base, const char *itemname); #ifdef BUILD_UNIX_SOCKET TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *server_msg, void *data); From 49dbb455b5c3cd22941011a01763eaf1f04ba5d8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 7 Nov 2015 21:24:07 +0100 Subject: [PATCH 0889/2553] afpacket: add null decoder, put ethernet first --- src/source-af-packet.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 3f1f44e19ddd..aba1b7d5d479 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1860,19 +1860,22 @@ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet } /* call the decoder */ - switch(p->datalink) { - case LINKTYPE_LINUX_SLL: - DecodeSll(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); - break; + switch (p->datalink) { case LINKTYPE_ETHERNET: DecodeEthernet(tv, dtv, p,GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; + case LINKTYPE_LINUX_SLL: + DecodeSll(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); + break; case LINKTYPE_PPP: DecodePPP(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; case LINKTYPE_RAW: DecodeRaw(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; + case LINKTYPE_NULL: + DecodeNull(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); + break; default: SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodeAFP", p->datalink); break; From f89a4219906fe40cf2fb3092e6eaf1abd732faf8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 8 Nov 2015 08:48:24 +0100 Subject: [PATCH 0890/2553] afpacket: on missing cluster settings, set defaults --- src/runmode-af-packet.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index fc17a4bd6669..16d9113cb8d8 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -92,6 +92,10 @@ void AFPDerefConfig(void *conf) } } +/* if cluster id is not set, assign it automagically, uniq value per + * interface. */ +static int cluster_id_auto = 1; + /** * \brief extract information from config file * @@ -192,7 +196,7 @@ void *ParseAFPConfig(const char *iface) if (rss_queues > 0) { if (rss_queues < aconf->threads) { aconf->threads = rss_queues; - SCLogInfo("More core than RSS queues, using %d threads for interface %s", + SCLogInfo("More cores than RSS queues, using %d threads for interface %s", aconf->threads, iface); } } @@ -252,14 +256,15 @@ void *ParseAFPConfig(const char *iface) (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) { - SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); + aconf->cluster_id = (uint16_t)(cluster_id_auto++); } else { aconf->cluster_id = (uint16_t)atoi(tmpclusterid); SCLogDebug("Going to use cluster-id %" PRId32, aconf->cluster_id); } if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) { - SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED,"Could not get cluster-type from config"); + /* default to our safest choice: flow hashing + defrag enabled */ + aconf->cluster_type = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { SCLogInfo("Using round-robin cluster mode for AF_PACKET (iface %s)", aconf->iface); From cf2588acc40823849d90ad4db12b64a507701ef2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 8 Nov 2015 08:58:26 +0100 Subject: [PATCH 0891/2553] offloading: compress printing of iface offloading --- src/util-ioctl.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 59e2bf282728..99a84a7e62c8 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -157,6 +157,7 @@ int GetIfaceOffloading(const char *pcap_dev) int fd; struct ethtool_value ethv; int ret = 0; + char *lro = "unset", *gro = "unset"; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { @@ -175,10 +176,8 @@ int GetIfaceOffloading(const char *pcap_dev) return -1; } else { if (ethv.data) { - SCLogInfo("Generic Receive Offload is set on %s", pcap_dev); + gro = "SET"; ret = 1; - } else { - SCLogInfo("Generic Receive Offload is unset on %s", pcap_dev); } } @@ -194,15 +193,13 @@ int GetIfaceOffloading(const char *pcap_dev) return -1; } else { if (ethv.data & ETH_FLAG_LRO) { - SCLogInfo("Large Receive Offload is set on %s", pcap_dev); + lro = "SET"; ret = 1; - } else { - SCLogInfo("Large Receive Offload is unset on %s", pcap_dev); } } close(fd); - + SCLogInfo("NIC offloading on %s: GRO: %s, LRO: %s", pcap_dev, gro, lro); return ret; #else /* ioctl is not defined, let's pretend returning 0 is ok */ From 9d882116e271e696fd30e6264f4af4976198b07d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 8 Nov 2015 09:01:52 +0100 Subject: [PATCH 0892/2553] afpacket: indent fixup --- src/source-af-packet.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index aba1b7d5d479..66fe18db6a83 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1702,9 +1702,9 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->cluster_id = 1; /* We only set cluster info if the number of reader threads is greater than 1 */ if (afpconfig->threads > 1) { - ptv->cluster_id = afpconfig->cluster_id; - ptv->cluster_type = afpconfig->cluster_type; - ptv->threads = afpconfig->threads; + ptv->cluster_id = afpconfig->cluster_id; + ptv->cluster_type = afpconfig->cluster_type; + ptv->threads = afpconfig->threads; } #endif ptv->flags = afpconfig->flags; From bed18678308c18be47797cd1beeb3743eaeb5cc7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 8 Nov 2015 09:06:03 +0100 Subject: [PATCH 0893/2553] afpacket: move zero copy setup to config parsing This way it's run and logged per device, instead of per thread. --- src/runmode-af-packet.c | 16 ++++++++++++++++ src/source-af-packet.c | 17 ----------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 16d9113cb8d8..e151806b8e18 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -372,6 +372,22 @@ void *ParseAFPConfig(const char *iface) "Using AF_PACKET with GRO or LRO activated can lead to capture problems"); } + char *active_runmode = RunmodeGetActive(); + if (active_runmode && !strcmp("workers", active_runmode)) { + aconf->flags |= AFP_ZERO_COPY; + SCLogInfo("%s: enabling zero copy mode", iface); + } else { + /* If we are using copy mode we need a lock */ + aconf->flags |= AFP_SOCK_PROTECT; + } + + /* If we are in RING mode, then we can use ZERO copy + * by using the data release mechanism */ + if (aconf->flags & AFP_RING_MODE) { + aconf->flags |= AFP_ZERO_COPY; + SCLogInfo("%s: enabling zero copy mode by using data release call", iface); + } + return aconf; } diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 66fe18db6a83..12c9324ee93f 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1720,23 +1720,6 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->tv); #endif - char *active_runmode = RunmodeGetActive(); - - if (active_runmode && !strcmp("workers", active_runmode)) { - ptv->flags |= AFP_ZERO_COPY; - SCLogInfo("Enabling zero copy mode"); - } else { - /* If we are using copy mode we need a lock */ - ptv->flags |= AFP_SOCK_PROTECT; - } - - /* If we are in RING mode, then we can use ZERO copy - * by using the data release mechanism */ - if (ptv->flags & AFP_RING_MODE) { - ptv->flags |= AFP_ZERO_COPY; - SCLogInfo("Enabling zero copy mode by using data release call"); - } - ptv->copy_mode = afpconfig->copy_mode; if (ptv->copy_mode != AFP_COPY_MODE_NONE) { strlcpy(ptv->out_iface, afpconfig->out_iface, AFP_IFACE_NAME_LENGTH); From 86a3f064104ae4a74588ecb1c9380bc0a79d2f5c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 8 Nov 2015 09:18:17 +0100 Subject: [PATCH 0894/2553] afpacket: suppress output --- src/runmode-af-packet.c | 6 +++--- src/source-af-packet.c | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index e151806b8e18..cd98b229505c 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -513,7 +513,7 @@ int RunModeIdsAFPAutoFp(void) exit(EXIT_FAILURE); } - SCLogInfo("RunModeIdsAFPAutoFp initialised"); + SCLogDebug("RunModeIdsAFPAutoFp initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); @@ -555,7 +555,7 @@ int RunModeIdsAFPSingle(void) exit(EXIT_FAILURE); } - SCLogInfo("RunModeIdsAFPSingle initialised"); + SCLogDebug("RunModeIdsAFPSingle initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); @@ -600,7 +600,7 @@ int RunModeIdsAFPWorkers(void) exit(EXIT_FAILURE); } - SCLogInfo("RunModeIdsAFPWorkers initialised"); + SCLogDebug("RunModeIdsAFPWorkers initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 12c9324ee93f..f9eb865820d5 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1073,7 +1073,7 @@ static int AFPSynchronizeStart(AFPThreadVars *ptv) } /* no packets */ } else if (r == 0 && AFPPeersListStarted()) { - SCLogInfo("Starting to read on %s", ptv->tv->name); + SCLogDebug("Starting to read on %s", ptv->tv->name); return 1; } else if (r < 0) { /* only exit on error */ SCLogWarning(SC_ERR_AFP_READ, "poll failed with retval %d", r); @@ -1154,7 +1154,7 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) AFPPeersListReachedInc(); } if (ptv->afp_state == AFP_STATE_UP) { - SCLogInfo("Thread %s using socket %d", tv->name, ptv->socket); + SCLogDebug("Thread %s using socket %d", tv->name, ptv->socket); AFPSynchronizeStart(ptv); } @@ -1570,8 +1570,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) ptv->frame_offset = 0; } - SCLogInfo("Using interface '%s' via socket %d", (char *)devname, ptv->socket); - + SCLogDebug("Using interface '%s' via socket %d", (char *)devname, ptv->socket); ptv->datalink = AFPGetDevLinktype(ptv->socket, ptv->iface); switch (ptv->datalink) { From 36fde7df428aeaab7f089c744753778fd7685a91 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 8 Nov 2015 09:55:00 +0100 Subject: [PATCH 0895/2553] stats log: suppress 0 counters by default --- src/log-stats.c | 8 ++++++++ suricata.yaml.in | 1 + 2 files changed, 9 insertions(+) diff --git a/src/log-stats.c b/src/log-stats.c index 5fcb1c9f62df..385dec2bb4fc 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -51,6 +51,7 @@ #define LOG_STATS_TOTALS (1<<0) #define LOG_STATS_THREADS (1<<1) +#define LOG_STATS_NULLS (1<<2) TmEcode LogStatsLogThreadInit(ThreadVars *, void *, void **); TmEcode LogStatsLogThreadDeinit(ThreadVars *, void *); @@ -108,6 +109,9 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) if (st->stats[u].name == NULL) continue; + if (!(aft->statslog_ctx->flags & LOG_STATS_NULLS) && st->stats[u].value == 0) + continue; + char line[1024]; size_t len = snprintf(line, sizeof(line), "%-25s | %-25s | %-" PRIu64 "\n", st->stats[u].name, st->stats[u].tm_name, st->stats[u].value); @@ -238,6 +242,7 @@ OutputCtx *LogStatsLogInitCtx(ConfNode *conf) if (conf != NULL) { const char *totals = ConfNodeLookupChildValue(conf, "totals"); const char *threads = ConfNodeLookupChildValue(conf, "threads"); + const char *nulls = ConfNodeLookupChildValue(conf, "null-values"); SCLogDebug("totals %s threads %s", totals, threads); if (totals != NULL && ConfValIsFalse(totals)) { @@ -246,6 +251,9 @@ OutputCtx *LogStatsLogInitCtx(ConfNode *conf) if (threads != NULL && ConfValIsTrue(threads)) { statslog_ctx->flags |= LOG_STATS_THREADS; } + if (nulls != NULL && ConfValIsTrue(nulls)) { + statslog_ctx->flags |= LOG_STATS_NULLS; + } SCLogDebug("statslog_ctx->flags %08x", statslog_ctx->flags); } diff --git a/suricata.yaml.in b/suricata.yaml.in index a612fb25dedd..67abc18a6a3f 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -315,6 +315,7 @@ outputs: filename: stats.log totals: yes # stats for all threads merged together threads: no # per thread stats + #null-values: yes # print counters that have value 0 # a line based alerts log similar to fast.log into syslog - syslog: From b4dad91e269bacd5c2323b65203e9be6384140da Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 6 Dec 2015 10:53:42 +0100 Subject: [PATCH 0896/2553] unified2: disable by default --- suricata.yaml.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 67abc18a6a3f..a2e4dbe6eb6b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -181,7 +181,7 @@ outputs: # alert output for use with Barnyard2 - unified2-alert: - enabled: yes + enabled: no filename: unified2.alert # File size limit. Can be specified in kb, mb, gb. Just a number From 8cdd96d7a4a93ec8e77b837a0347f9db99a369e1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 7 Dec 2015 17:10:40 +0100 Subject: [PATCH 0897/2553] tls: suppress warnings on alloc failure --- src/app-layer-tls-handshake.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-tls-handshake.c b/src/app-layer-tls-handshake.c index ca2e7f491c84..530a7c1fb04d 100644 --- a/src/app-layer-tls-handshake.c +++ b/src/app-layer-tls-handshake.c @@ -174,7 +174,7 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin int j = 0; if (hash == NULL) { - SCLogWarning(SC_ERR_MEM_ALLOC, "Can not allocate fingerprint string"); + // TODO maybe an event here? } else { for (j = 0; j < hash_len; j++, p += 3) { snprintf(p, 4, j == hash_len - 1 ? "%02x" : "%02x:", hash[j]); @@ -182,7 +182,7 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin SCFree(hash); ssl_state->server_connp.cert0_fingerprint = SCStrdup(out); if (ssl_state->server_connp.cert0_fingerprint == NULL) { - SCLogWarning(SC_ERR_MEM_ALLOC, "Can not allocate fingerprint string"); + // TODO do we need an event here? } } From 4b69e1aec12f2ba0ca235e63dee96c57c59002bc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 Nov 2015 17:12:52 +0100 Subject: [PATCH 0898/2553] stream-tcp: bail early on segments before base_seq In cases where base_seq has moved beyond last_ack, bail early. --- src/stream-tcp-reassemble.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index a947fab35140..94deab4311a8 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2696,8 +2696,7 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { if (SEQ_LT(stream->last_ack, (rd->ra_base_seq + 1))) { - payload_len = (stream->last_ack - seg->seq); - SCLogDebug("payload_len %u", payload_len); + return 1; } else { payload_len = (stream->last_ack - seg->seq) - payload_offset; SCLogDebug("payload_len %u", payload_len); @@ -2752,12 +2751,18 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, /* copy the data into the buffer */ uint16_t copy_size = sizeof(rd->data) - rd->data_len; + if (copy_size + payload_offset > seg->payload_len) { + copy_size = seg->payload_len - payload_offset; + } if (copy_size > payload_len) { copy_size = payload_len; } if (SCLogDebugEnabled()) { BUG_ON(copy_size > sizeof(rd->data)); + BUG_ON(copy_size+payload_offset > seg->payload_len); + BUG_ON(copy_size+payload_offset > seg->pool_size); } + SCLogDebug("copy_size is %"PRIu16"", copy_size); memcpy(rd->data + rd->data_len, seg->payload + payload_offset, copy_size); rd->data_len += copy_size; @@ -3141,7 +3146,7 @@ static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { if (SEQ_LT(stream->last_ack, rd->ra_base_seq)) { - payload_len = (stream->last_ack - seg->seq); + return 1; } else { payload_len = (stream->last_ack - seg->seq) - payload_offset; } @@ -3189,6 +3194,9 @@ static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, /* copy the data into the smsg */ uint32_t copy_size = rd->smsg->data_size - rd->smsg_offset; + if (copy_size + payload_offset > seg->payload_len) { + copy_size = seg->payload_len - payload_offset; + } if (copy_size > payload_len) { copy_size = payload_len; } From 260841827f5a7404365be17fdf7e064a05dc2c83 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 Nov 2015 15:46:15 +0100 Subject: [PATCH 0899/2553] smtp: improve handling of bad traffic No longer fail tracking the SMTP stream when a unexpected reply is encountered. Do not store the unexpected reply. --- src/app-layer-smtp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index cd0a732e1eb7..61ac4ec645e6 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -887,12 +887,14 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN; if (reply_code == SMTP_REPLY_220) SCReturnInt(0); - else + else { SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); + SCReturnInt(0); + } } else { /* decoder event - unable to match reply with request */ SCLogDebug("unable to match reply with request"); - SCReturnInt(-1); + SCReturnInt(0); } } From b333e5feae1f0c14d7620490a543fc41bccaea85 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 2 Dec 2015 11:37:57 +0100 Subject: [PATCH 0900/2553] dns: reject bad response data --- src/app-layer-dns-tcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index f1cb597d2aef..9e85ca298119 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -521,7 +521,9 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, DNSTcpHeader *dns_tcp_header = (DNSTcpHeader *)input; SCLogDebug("DNS %p", dns_tcp_header); - if (ntohs(dns_tcp_header->len) == (input_len-2)) { + if (ntohs(dns_tcp_header->len) == 0) { + goto bad_data; + } else if (ntohs(dns_tcp_header->len) == (input_len-2)) { /* we have all data, so process w/o buffering */ if (DNSReponseParseData(f, dns_state, input+2, input_len-2) < 0) goto bad_data; From e94bf9726db3b0d9d7448160f5f92a0c3f5328fd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 8 Dec 2015 14:08:18 +0100 Subject: [PATCH 0901/2553] Update Changelog for 3.0RC2 --- ChangeLog | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ChangeLog b/ChangeLog index a7e645986cc2..5f5cbeb3a477 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +3.0RC2 -- 2015-12-08 + +Bug #1551: --enable-profiling-locks broken +Bug #1602: eve-log prefix field feature broken +Bug #1614: app_proto key missing from EVE file events +Bug #1615: disable modbus by default +Bug #1616: TCP reassembly bug +Bug #1617: DNS over TCP parsing issue +Bug #1618: SMTP parsing issue +Feature #1635: unified2 output: disable by default + 3.0RC1 -- 2015-11-25 Bug #1150: TLS store disabled by TLS EVE logging From 2582e61af74793b3a773c3823a5972e2af710c78 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 Nov 2015 14:06:32 +0100 Subject: [PATCH 0902/2553] http: fix body prune check --- src/app-layer-htp-body.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index 6454fe1c8c3e..af9609b2189b 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -222,7 +222,7 @@ void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) window = state->cfg->request_inspect_window; } - if (body->body_inspected < (min_size > window) ? min_size : window) { + if (body->body_inspected < ((min_size > window) ? min_size : window)) { SCReturn; } From a74a8c874f81fc805223fdc84cf70d23c64a8570 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 1 Dec 2015 15:20:19 +0100 Subject: [PATCH 0903/2553] smtp: reset inspection buffers --- src/detect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect.c b/src/detect.c index 401d2b008d32..74a1b8a927c4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1827,6 +1827,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh DetectEngineCleanHCBDBuffers(det_ctx); DetectEngineCleanHSBDBuffers(det_ctx); DetectEngineCleanHHDBuffers(det_ctx); + DetectEngineCleanSMTPBuffers(det_ctx); /* store the found sgh (or NULL) in the flow to save us from looking it * up again for the next packet. Also return any stream chunk we processed From 006cd5ae3681c6d4bd6718e113e070dcb2f4b825 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 Nov 2015 10:38:21 +0100 Subject: [PATCH 0904/2553] file: sync file and tx id types --- src/util-file.c | 4 ++-- src/util-file.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/util-file.c b/src/util-file.c index bfb68e1e0363..66d4080e66ba 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -873,7 +873,7 @@ void FileDisableStoringForTransaction(Flow *f, uint8_t direction, uint64_t tx_id * \param fc file store * \param file_id the file's id */ -void FileStoreFileById(FileContainer *fc, uint16_t file_id) +void FileStoreFileById(FileContainer *fc, uint32_t file_id) { File *ptr = NULL; @@ -888,7 +888,7 @@ void FileStoreFileById(FileContainer *fc, uint16_t file_id) } } -void FileStoreAllFilesForTx(FileContainer *fc, uint16_t tx_id) +void FileStoreAllFilesForTx(FileContainer *fc, uint64_t tx_id) { File *ptr = NULL; diff --git a/src/util-file.h b/src/util-file.h index 9cfc3a85936e..8f322a99d7d0 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -62,7 +62,7 @@ typedef struct FileData_ { typedef struct File_ { uint16_t flags; uint64_t txid; /**< tx this file is part of */ - unsigned int file_id; + uint32_t file_id; uint8_t *name; uint16_t name_len; int16_t state; @@ -169,7 +169,7 @@ void FileDisableFilesize(Flow *f, uint8_t direction); */ void FileDisableStoringForTransaction(Flow *f, uint8_t direction, uint64_t tx_id); -void FlowFileDisableStoringForTransaction(struct Flow_ *f, uint16_t tx_id); +void FlowFileDisableStoringForTransaction(struct Flow_ *f, uint64_t tx_id); void FilePrune(FileContainer *ffc); @@ -184,8 +184,8 @@ int FileForceMd5(void); void FileForceTrackingEnable(void); void FileStoreAllFiles(FileContainer *); -void FileStoreAllFilesForTx(FileContainer *, uint16_t); -void FileStoreFileById(FileContainer *fc, uint16_t); +void FileStoreAllFilesForTx(FileContainer *, uint64_t); +void FileStoreFileById(FileContainer *fc, uint32_t); void FileTruncateAllOpenFiles(FileContainer *); From 136c6440c84ae0fe7a88b31c44bc65798c49a8d4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 Nov 2015 10:45:18 +0100 Subject: [PATCH 0905/2553] http file: fix txid type --- src/app-layer-htp-file.c | 2 +- src/app-layer-htp-file.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index d8659f338e04..27371a750d60 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -77,7 +77,7 @@ * \retval -2 not handling files on this flow */ int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len, - uint8_t *data, uint32_t data_len, uint16_t txid, uint8_t direction) + uint8_t *data, uint32_t data_len, uint64_t txid, uint8_t direction) { int retval = 0; uint8_t flags = 0; diff --git a/src/app-layer-htp-file.h b/src/app-layer-htp-file.h index d70794eaa573..70799c320120 100644 --- a/src/app-layer-htp-file.h +++ b/src/app-layer-htp-file.h @@ -25,7 +25,7 @@ #ifndef __APP_LAYER_HTP_FILE_H__ #define __APP_LAYER_HTP_FILE_H__ -int HTPFileOpen(HtpState *, uint8_t *, uint16_t, uint8_t *, uint32_t, uint16_t, uint8_t); +int HTPFileOpen(HtpState *, uint8_t *, uint16_t, uint8_t *, uint32_t, uint64_t, uint8_t); int HTPFileStoreChunk(HtpState *, uint8_t *, uint32_t, uint8_t); int HTPFileClose(HtpState *, uint8_t *, uint32_t, uint8_t, uint8_t); From 64017cd29bf77aefed42bb1010f2e4bb1c9cac6c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 10 Dec 2015 09:58:52 +0100 Subject: [PATCH 0906/2553] ips/drop-log: fix crash on logging drops When logging drops for fragmented UDP packets, triggered by detection in the reassembled packet, a missing check could lead to access of the packets UDP header pointer when it was NULL. --- src/log-droplog.c | 36 ++++++++++++++++++++---------------- src/output-json-drop.c | 28 ++++++++++++++++------------ 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/log-droplog.c b/src/log-droplog.c index 6eafd9d5ef93..67cbd1b1ad4a 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -224,30 +224,34 @@ static int LogDropLogNetFilter (ThreadVars *tv, const Packet *p, void *data) switch (proto) { case IPPROTO_TCP: - fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16" " - "SEQ=%"PRIu32" ACK=%"PRIu32" WINDOW=%"PRIu32"", - GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_SEQ(p), - TCP_GET_ACK(p), TCP_GET_WINDOW(p)); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_SYN(p) ? " SYN" : ""); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_ACK(p) ? " ACK" : ""); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_PUSH(p) ? " PSH" : ""); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_RST(p) ? " RST" : ""); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_URG(p) ? " URG" : ""); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_FIN(p) ? " FIN" : ""); - fprintf(dlt->file_ctx->fp, " RES=0x%02"PRIu8" URGP=%"PRIu16"", - TCP_GET_RAW_X2(p->tcph), TCP_GET_URG_POINTER(p)); + if (PKT_IS_TCP(p)) { + fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16" " + "SEQ=%"PRIu32" ACK=%"PRIu32" WINDOW=%"PRIu32"", + GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_SEQ(p), + TCP_GET_ACK(p), TCP_GET_WINDOW(p)); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_SYN(p) ? " SYN" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_ACK(p) ? " ACK" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_PUSH(p) ? " PSH" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_RST(p) ? " RST" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_URG(p) ? " URG" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_FIN(p) ? " FIN" : ""); + fprintf(dlt->file_ctx->fp, " RES=0x%02"PRIu8" URGP=%"PRIu16"", + TCP_GET_RAW_X2(p->tcph), TCP_GET_URG_POINTER(p)); + } break; case IPPROTO_UDP: - fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16"" - " LEN=%"PRIu16"", UDP_GET_SRC_PORT(p), - UDP_GET_DST_PORT(p), UDP_GET_LEN(p)); + if (PKT_IS_UDP(p)) { + fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16"" + " LEN=%"PRIu16"", UDP_GET_SRC_PORT(p), + UDP_GET_DST_PORT(p), UDP_GET_LEN(p)); + } break; case IPPROTO_ICMP: if (PKT_IS_ICMPV4(p)) { fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu8" CODE=%"PRIu8"" " ID=%"PRIu16" SEQ=%"PRIu16"", ICMPV4_GET_TYPE(p), ICMPV4_GET_CODE(p), ICMPV4_GET_ID(p), ICMPV4_GET_SEQ(p)); - } else if(PKT_IS_ICMPV6(p)) { + } else if (PKT_IS_ICMPV6(p)) { fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu8" CODE=%"PRIu8"" " ID=%"PRIu16" SEQ=%"PRIu16"", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); diff --git a/src/output-json-drop.c b/src/output-json-drop.c index c9b01df83495..68c14d9b5d98 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -114,20 +114,24 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) } switch (proto) { case IPPROTO_TCP: - json_object_set_new(djs, "tcpseq", json_integer(TCP_GET_SEQ(p))); - json_object_set_new(djs, "tcpack", json_integer(TCP_GET_ACK(p))); - json_object_set_new(djs, "tcpwin", json_integer(TCP_GET_WINDOW(p))); - json_object_set_new(djs, "syn", TCP_ISSET_FLAG_SYN(p) ? json_true() : json_false()); - json_object_set_new(djs, "ack", TCP_ISSET_FLAG_ACK(p) ? json_true() : json_false()); - json_object_set_new(djs, "psh", TCP_ISSET_FLAG_PUSH(p) ? json_true() : json_false()); - json_object_set_new(djs, "rst", TCP_ISSET_FLAG_RST(p) ? json_true() : json_false()); - json_object_set_new(djs, "urg", TCP_ISSET_FLAG_URG(p) ? json_true() : json_false()); - json_object_set_new(djs, "fin", TCP_ISSET_FLAG_FIN(p) ? json_true() : json_false()); - json_object_set_new(djs, "tcpres", json_integer(TCP_GET_RAW_X2(p->tcph))); - json_object_set_new(djs, "tcpurgp", json_integer(TCP_GET_URG_POINTER(p))); + if (PKT_IS_TCP(p)) { + json_object_set_new(djs, "tcpseq", json_integer(TCP_GET_SEQ(p))); + json_object_set_new(djs, "tcpack", json_integer(TCP_GET_ACK(p))); + json_object_set_new(djs, "tcpwin", json_integer(TCP_GET_WINDOW(p))); + json_object_set_new(djs, "syn", TCP_ISSET_FLAG_SYN(p) ? json_true() : json_false()); + json_object_set_new(djs, "ack", TCP_ISSET_FLAG_ACK(p) ? json_true() : json_false()); + json_object_set_new(djs, "psh", TCP_ISSET_FLAG_PUSH(p) ? json_true() : json_false()); + json_object_set_new(djs, "rst", TCP_ISSET_FLAG_RST(p) ? json_true() : json_false()); + json_object_set_new(djs, "urg", TCP_ISSET_FLAG_URG(p) ? json_true() : json_false()); + json_object_set_new(djs, "fin", TCP_ISSET_FLAG_FIN(p) ? json_true() : json_false()); + json_object_set_new(djs, "tcpres", json_integer(TCP_GET_RAW_X2(p->tcph))); + json_object_set_new(djs, "tcpurgp", json_integer(TCP_GET_URG_POINTER(p))); + } break; case IPPROTO_UDP: - json_object_set_new(djs, "udplen", json_integer(UDP_GET_LEN(p))); + if (PKT_IS_UDP(p)) { + json_object_set_new(djs, "udplen", json_integer(UDP_GET_LEN(p))); + } break; case IPPROTO_ICMP: if (PKT_IS_ICMPV4(p)) { From efdd9e08f2b5dd1dac6a9ed8355a79b11d84cc12 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 10 Dec 2015 16:12:05 +0100 Subject: [PATCH 0907/2553] http: improve body pruning In case the body wasn't inspected the body_inspected variable wouldn't get updated leading to the body not getting pruned at all. This patch adds support for this case. --- src/app-layer-htp-body.c | 11 ++++++++++- src/app-layer-htp.c | 12 ++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index af9609b2189b..a9a1ba17f08d 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -222,7 +222,16 @@ void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) window = state->cfg->request_inspect_window; } - if (body->body_inspected < ((min_size > window) ? min_size : window)) { + uint64_t max_window = ((min_size > window) ? min_size : window); + uint64_t in_flight = body->content_len_so_far - body->body_inspected; + + /* Special case. If body_inspected is not being updated, we make sure that + * we prune the body. We allow for some extra size/room as we may be called + * multiple times on uninspected body chunk additions if a large block of + * data was ack'd at once. Want to avoid pruning before inspection. */ + if (in_flight > (max_window * 3)) { + body->body_inspected = body->content_len_so_far - max_window; + } else if (body->body_inspected < max_window) { SCReturn; } diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index e8da88eb8cd3..5fd0949296b8 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1812,6 +1812,9 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) } } + /* see if we can get rid of htp body chunks */ + HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER); + SCLogDebug("tx_ud->request_body.content_len_so_far %"PRIu64, tx_ud->request_body.content_len_so_far); SCLogDebug("hstate->cfg->request_body_limit %u", hstate->cfg->request_body_limit); @@ -1863,9 +1866,6 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) } end: - /* see if we can get rid of htp body chunks */ - HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER); - /* set the new chunk flag */ hstate->flags |= HTP_FLAG_NEW_BODY_SET; @@ -1911,6 +1911,9 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) tx_ud->operation = HTP_BODY_RESPONSE; } + /* see if we can get rid of htp body chunks */ + HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT); + SCLogDebug("tx_ud->response_body.content_len_so_far %"PRIu64, tx_ud->response_body.content_len_so_far); SCLogDebug("hstate->cfg->response_body_limit %u", hstate->cfg->response_body_limit); @@ -1932,9 +1935,6 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) HtpResponseBodyHandle(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); } - /* see if we can get rid of htp body chunks */ - HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT); - /* set the new chunk flag */ hstate->flags |= HTP_FLAG_NEW_BODY_SET; From fae2836039ef56daebcc222e41be3b4ad445b27c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Dec 2015 16:05:42 +0100 Subject: [PATCH 0908/2553] http: more sane body inspection/tracking defaults --- suricata.yaml.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index a2e4dbe6eb6b..6614906f13d2 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1441,14 +1441,14 @@ app-layer: # Can be specified in kb, mb, gb. Just a number indicates # it's in bytes. - request-body-limit: 3072 - response-body-limit: 3072 + request-body-limit: 100kb + response-body-limit: 100kb # inspection limits request-body-minimal-inspect-size: 32kb request-body-inspect-window: 4kb - response-body-minimal-inspect-size: 32kb - response-body-inspect-window: 4kb + response-body-minimal-inspect-size: 40kb + response-body-inspect-window: 16kb # auto will use http-body-inline mode in IPS mode, yes or no set it statically http-body-inline: auto From 2fbfd6efcca95469246338d4eeba69f31f4224df Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 17 Dec 2015 13:25:02 +0100 Subject: [PATCH 0909/2553] DER decoder: don't use strlcpy on non-strings --- src/util-decode-der.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/util-decode-der.c b/src/util-decode-der.c index 1687668bd5fd..05c4671ad853 100644 --- a/src/util-decode-der.c +++ b/src/util-decode-der.c @@ -482,7 +482,8 @@ static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_ SCFree(a); return NULL; } - strlcpy(a->str, (const char*)d_ptr, length+1); + memcpy(a->str, (const char*)d_ptr, length); + a->str[length] = 0; d_ptr += length; @@ -583,8 +584,8 @@ static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, u SCFree(a); return NULL; } - strlcpy(a->str, (const char*)d_ptr, length+1); - a->str[length] = '\0'; + memcpy(a->str, (const char*)d_ptr, length); + a->str[length] = 0; d_ptr += length; From fe445367bda6da335eddd6d320b48e01493af94d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 16 Dec 2015 10:45:05 +0100 Subject: [PATCH 0910/2553] icmpv4: improve dest unreachable logic When a ICMPv4 destination unreachable packet contains an embedded packet this packet is parsed. When it's found to be invalid, the whole ICMP packet is tagged as invalid. In some cases the unreachable packet would still be used. This patch fixes this by checking the packet is invalid flag as well in the ICMPV4_DEST_UNREACH_IS_VALID macro. --- src/decode-icmpv4.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/decode-icmpv4.h b/src/decode-icmpv4.h index f8cb97f4f0ab..02184dfd3401 100644 --- a/src/decode-icmpv4.h +++ b/src/decode-icmpv4.h @@ -259,7 +259,9 @@ typedef struct ICMPV4Vars_ * * \warning use only _after_ the decoder has processed the packet */ -#define ICMPV4_DEST_UNREACH_IS_VALID(p) (((p)->icmpv4h != NULL) && \ +#define ICMPV4_DEST_UNREACH_IS_VALID(p) ( \ + (!((p)->flags & PKT_IS_INVALID)) && \ + ((p)->icmpv4h != NULL) && \ (ICMPV4_GET_TYPE((p)) == ICMP_DEST_UNREACH) && \ (ICMPV4_GET_EMB_IPV4((p)) != NULL) && \ ((ICMPV4_GET_EMB_TCP((p)) != NULL) || \ From ed1cc1ee2af993d9be68c91d03b7823644e3273d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 16 Dec 2015 10:50:50 +0100 Subject: [PATCH 0911/2553] icmpv4: harden embedded packet handling --- src/decode-icmpv4.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index 5af012ce9ac8..45b213f6704e 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -47,13 +47,13 @@ /** * Note, this is the IP header, plus a bit of the original packet, not the whole thing! */ -void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) +int DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) { /** Check the sizes, the header must fit at least */ if (len < IPV4_HEADER_LEN) { SCLogDebug("DecodePartialIPV4: ICMPV4_IPV4_TRUNC_PKT"); ENGINE_SET_INVALID_EVENT(p, ICMPV4_IPV4_TRUNC_PKT); - return; + return -1; } IPV4Hdr *icmp4_ip4h = (IPV4Hdr*)partial_packet; @@ -64,7 +64,7 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) SCLogDebug("DecodePartialIPV4: ICMPv4 contains Unknown IPV4 version " "ICMPV4_IPV4_UNKNOWN_VER"); ENGINE_SET_INVALID_EVENT(p, ICMPV4_IPV4_UNKNOWN_VER); - return; + return -1; } /** We need to fill icmpv4vars */ @@ -125,12 +125,14 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) break; case IPPROTO_ICMP: - p->icmpv4vars.emb_icmpv4h = (ICMPV4Hdr*)(partial_packet + IPV4_HEADER_LEN); - p->icmpv4vars.emb_sport = 0; - p->icmpv4vars.emb_dport = 0; - p->icmpv4vars.emb_ip4_proto = IPPROTO_ICMP; + if (len >= IPV4_HEADER_LEN + ICMPV4_HEADER_LEN ) { + p->icmpv4vars.emb_icmpv4h = (ICMPV4Hdr*)(partial_packet + IPV4_HEADER_LEN); + p->icmpv4vars.emb_sport = 0; + p->icmpv4vars.emb_dport = 0; + p->icmpv4vars.emb_ip4_proto = IPPROTO_ICMP; - SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->ICMP header"); + SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->ICMP header"); + } break; } @@ -144,8 +146,7 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) IPV4_GET_RAW_IPPROTO(icmp4_ip4h), IPV4_GET_RAW_IPID(icmp4_ip4h)); #endif - return; - + return 0; } /** DecodeICMPV4 @@ -188,11 +189,13 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, } else { /* parse IP header plus 64 bytes */ if (len > ICMPV4_HEADER_PKT_OFFSET) { - DecodePartialIPV4( p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); - - /* ICMP ICMP_DEST_UNREACH influence TCP/UDP flows */ - if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { - FlowHandlePacket(tv, dtv, p); + if (DecodePartialIPV4(p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), + len - ICMPV4_HEADER_PKT_OFFSET ) == 0) + { + /* ICMP ICMP_DEST_UNREACH influence TCP/UDP flows */ + if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { + FlowHandlePacket(tv, dtv, p); + } } } } From 375092da8505cc353e5a72127b6cab7302d3ee78 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 16 Dec 2015 10:49:50 +0100 Subject: [PATCH 0912/2553] icmpv4: remove unused declarations --- src/decode-icmpv4.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/decode-icmpv4.h b/src/decode-icmpv4.h index 02184dfd3401..da5821d675e0 100644 --- a/src/decode-icmpv4.h +++ b/src/decode-icmpv4.h @@ -236,13 +236,6 @@ typedef struct ICMPV4Vars_ /* If message is Error */ -/** macro for icmpv4 "unused" access */ -#define ICMPV4_GET_UNUSED(p) (p)->icmpv4h->icmpv4b.icmpv4e.unused -/** macro for icmpv4 "error_ptr" access */ -#define ICMPV4_GET_ERROR_PTR(p) (p)->icmpv4h->icmpv4b.icmpv4e.error_ptr -/** macro for icmpv4 "mtu" access */ -#define ICMPV4_GET_MTU(p) (p)->icmpv4h->icmpv4b.icmpv4e.mtu - /** macro for icmpv4 embedded "protocol" access */ #define ICMPV4_GET_EMB_PROTO(p) (p)->icmpv4vars.emb_ip4_proto /** macro for icmpv4 embedded "ipv4h" header access */ @@ -282,9 +275,6 @@ typedef struct ICMPV4Vars_ ICMPV4_GET_TYPE((p)) == ICMP_TIME_EXCEEDED || \ ICMPV4_GET_TYPE((p)) == ICMP_PARAMETERPROB) -typedef struct ICMPV4Cache_ { -} ICMPV4Cache; - void DecodeICMPV4RegisterTests(void); /** ------ Inline functions ------ */ From 083f22f6d6d77aa1cb8d43775e98c0f148cfc481 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 16 Dec 2015 11:02:15 +0100 Subject: [PATCH 0913/2553] icmpv4: remove unused header fields --- src/decode-icmpv4.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/decode-icmpv4.h b/src/decode-icmpv4.h index da5821d675e0..2f5862d38994 100644 --- a/src/decode-icmpv4.h +++ b/src/decode-icmpv4.h @@ -179,8 +179,6 @@ typedef struct ICMPV4Vars_ { uint16_t id; uint16_t seq; - uint32_t mtu; - uint32_t error_ptr; /** Pointers to the embedded packet headers */ IPV4Hdr *emb_ipv4h; @@ -203,8 +201,6 @@ typedef struct ICMPV4Vars_ (p)->level4_comp_csum = -1; \ (p)->icmpv4vars.id = 0; \ (p)->icmpv4vars.seq = 0; \ - (p)->icmpv4vars.mtu = 0; \ - (p)->icmpv4vars.error_ptr = 0; \ (p)->icmpv4vars.emb_ipv4h = NULL; \ (p)->icmpv4vars.emb_tcph = NULL; \ (p)->icmpv4vars.emb_udph = NULL; \ From 6b37985c666db978af42cc095b4719af46cf7a43 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 14 Dec 2015 14:02:20 +0100 Subject: [PATCH 0914/2553] unix-manager: fix race condition Under high load it is possible that the thread is not yet started and that we register a command at the same time. As a consequence, the commands list is not yet initialized and we have a segfault. This patch moves the initialization in the ThreadInit function to be sure the commands list is available when needed. --- src/unix-manager.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index 9357f4c50453..ca92677bab50 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -851,25 +851,6 @@ static TmEcode UnixManagerThreadInit(ThreadVars *t, void *initdata, void **data) if (utd == NULL) return TM_ECODE_FAILED; - *data = utd; - return TM_ECODE_OK; -} - -static TmEcode UnixManagerThreadDeinit(ThreadVars *t, void *data) -{ - SCFree(data); - return TM_ECODE_OK; -} - -static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) -{ - int ret; - - /* set the thread name */ - SCLogDebug("%s started...", th_v->name); - - StatsSetupPrivate(th_v); - if (UnixNew(&command) == 0) { int failure_fatal = 0; SCLogError(SC_ERR_INITIALIZATION, @@ -884,10 +865,6 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) } } - /* Set the threads capability */ - th_v->cap_flags = 0; - SCDropCaps(th_v); - /* Init Unix socket */ UnixManagerRegisterCommand("shutdown", UnixManagerShutdownCommand, NULL, 0); UnixManagerRegisterCommand("command-list", UnixManagerListCommand, &command, 0); @@ -905,6 +882,28 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) UnixManagerRegisterCommand("reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS); + *data = utd; + return TM_ECODE_OK; +} + +static TmEcode UnixManagerThreadDeinit(ThreadVars *t, void *data) +{ + SCFree(data); + return TM_ECODE_OK; +} + +static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) +{ + int ret; + + /* set the thread name */ + SCLogDebug("%s started...", th_v->name); + + StatsSetupPrivate(th_v); + + /* Set the threads capability */ + th_v->cap_flags = 0; + SCDropCaps(th_v); TmThreadsSetFlag(th_v, THV_INIT_DONE); while (1) { From 2002b37e30c12278961ff0369bba5692fb0f4802 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 14 Dec 2015 15:04:47 +0100 Subject: [PATCH 0915/2553] unix-manager: display errors like errors Not being able to setup the output directory or file is an error so it should be printed as such. --- src/runmode-unix-socket.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 06a71869d495..46aa3100a64f 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -346,13 +346,15 @@ TmEcode UnixSocketPcapFilesCheck(void *data) unix_manager_file_task_running = 1; this->running = 1; if (ConfSet("pcap-file.file", cfile->filename) != 1) { - SCLogInfo("Can not set working file to '%s'", cfile->filename); + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "Can not set working file to '%s'", cfile->filename); PcapFilesFree(cfile); return TM_ECODE_FAILED; } if (cfile->output_dir) { if (ConfSet("default-log-dir", cfile->output_dir) != 1) { - SCLogInfo("Can not set output dir to '%s'", cfile->output_dir); + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "Can not set output dir to '%s'", cfile->output_dir); PcapFilesFree(cfile); return TM_ECODE_FAILED; } @@ -361,7 +363,8 @@ TmEcode UnixSocketPcapFilesCheck(void *data) char tstr[16] = ""; snprintf(tstr, sizeof(tstr), "%d", cfile->tenant_id); if (ConfSet("pcap-file.tenant-id", tstr) != 1) { - SCLogInfo("Can not set working tenant-id to '%s'", tstr); + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "Can not set working tenant-id to '%s'", tstr); PcapFilesFree(cfile); return TM_ECODE_FAILED; } From 93642a0d1dd29c96e98824935ef963f6b1ef40eb Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 14 Dec 2015 15:18:07 +0100 Subject: [PATCH 0916/2553] suricata: can't use -l and unix socket runmode It is not possible to use simultaneously -l and unix socket runmode because setting the log directory make it final so not modifable by other call. It is a implementation limitation but it does not make sense to set logging directory to have it overwritten by the first directory specified 'by pcap-file'. So it seems correct to only trigger an error if this both options are used at the same time. --- src/suricata.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index b368f21d07f5..a6ed5736a5be 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1108,6 +1108,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) int build_info = 0; int conf_test = 0; int engine_analysis = 0; + int set_log_directory = 0; int ret = TM_ECODE_OK; #ifdef UNITTESTS @@ -1580,6 +1581,8 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) "exist. Shutting down the engine.", optarg, optarg); return TM_ECODE_FAILED; } + set_log_directory = 1; + break; case 'q': #ifdef NFQ @@ -1714,6 +1717,11 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) return TM_ECODE_FAILED; } + if ((suri->run_mode == RUNMODE_UNIX_SOCKET) && set_log_directory) { + SCLogError(SC_ERR_INITIALIZATION, "can't use -l and unix socket runmode at the same time"); + return TM_ECODE_FAILED; + } + if (list_app_layer_protocols) suri->run_mode = RUNMODE_LIST_APP_LAYERS; if (list_cuda_cards) From 1d9087f79f0cfa7786a352bf7ad339e622f61b3c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 7 Dec 2015 12:08:16 +0100 Subject: [PATCH 0917/2553] prelude: fix thread safeness Prelude analyzer is not thread safe so we need to have one analyzer per thread. --- src/alert-prelude.c | 81 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index a053e38b833a..f3da0192675d 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -115,6 +115,7 @@ typedef struct AlertPreludeCtx_ { typedef struct AlertPreludeThread_ { /** Pointer to the global context */ AlertPreludeCtx *ctx; + idmef_analyzer_t *analyzer; } AlertPreludeThread; @@ -131,24 +132,56 @@ static int SetupAnalyzer(idmef_analyzer_t *analyzer) SCEnter(); ret = idmef_analyzer_new_model(analyzer, &string); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating analyzer model: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); - prelude_string_set_constant(string, ANALYZER_MODEL); + } + ret = prelude_string_set_constant(string, ANALYZER_MODEL); + if (unlikely(ret < 0)) { + SCLogDebug("%s: error setting analyzer model: %s.", + prelude_strsource(ret), prelude_strerror(ret)); + SCReturnInt(ret); + } ret = idmef_analyzer_new_class(analyzer, &string); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating analyzer class: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); - prelude_string_set_constant(string, ANALYZER_CLASS); + } + ret = prelude_string_set_constant(string, ANALYZER_CLASS); + if (unlikely(ret < 0)) { + SCLogDebug("%s: error setting analyzer class: %s.", + prelude_strsource(ret), prelude_strerror(ret)); + SCReturnInt(ret); + } ret = idmef_analyzer_new_manufacturer(analyzer, &string); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating analyzer manufacturer: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); - prelude_string_set_constant(string, ANALYZER_MANUFACTURER); + } + ret = prelude_string_set_constant(string, ANALYZER_MANUFACTURER); + if (unlikely(ret < 0)) { + SCLogDebug("%s: error setting analyzer manufacturer: %s.", + prelude_strsource(ret), prelude_strerror(ret)); + SCReturnInt(ret); + } ret = idmef_analyzer_new_version(analyzer, &string); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating analyzer version: %s.", + prelude_strsource(ret), prelude_strerror(ret)); + SCReturnInt(ret); + } + ret = prelude_string_set_constant(string, VERSION); + if (unlikely(ret < 0)) { + SCLogDebug("%s: error setting analyzer version: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); - prelude_string_set_constant(string, VERSION); + } SCReturnInt(0); } @@ -606,9 +639,9 @@ static TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data SCEnter(); - if(unlikely(initdata == NULL)) - { - SCLogDebug("Error getting context for Prelude. \"initdata\" argument NULL"); + if (unlikely(initdata == NULL)) { + SCLogError(SC_ERR_INITIALIZATION, + "Error getting context for Prelude. \"initdata\" argument NULL"); SCReturnInt(TM_ECODE_FAILED); } @@ -617,9 +650,23 @@ static TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data SCReturnInt(TM_ECODE_FAILED); memset(aun, 0, sizeof(AlertPreludeThread)); - /** Use the Ouput Context */ + /* Use the Ouput Context */ aun->ctx = ((OutputCtx *)initdata)->data; + /* Create a per-thread idmef analyzer */ + if (unlikely(idmef_analyzer_new(&aun->analyzer) < 0)) { + SCLogError(SC_ERR_INITIALIZATION, + "Error creating idmef analyzer for Prelude."); + SCReturnInt(TM_ECODE_FAILED); + } + + /* Setup the per-thread idmef analyzer */ + if (unlikely(SetupAnalyzer(aun->analyzer) < 0)) { + SCLogError(SC_ERR_INITIALIZATION, + "Error configuring idmef analyzer for Prelude."); + SCReturnInt(TM_ECODE_FAILED); + } + *data = (void *)aun; SCReturnInt(TM_ECODE_OK); } @@ -641,6 +688,7 @@ static TmEcode AlertPreludeThreadDeinit(ThreadVars *t, void *data) } /* clear memory */ + idmef_analyzer_destroy(aun->analyzer); memset(aun, 0, sizeof(AlertPreludeThread)); SCFree(aun); @@ -703,7 +751,12 @@ static OutputCtx *AlertPreludeInitCtx(ConfNode *conf) SCReturnPtr(NULL, "AlertPreludeCtx"); } - SetupAnalyzer(prelude_client_get_analyzer(client)); + ret = SetupAnalyzer(prelude_client_get_analyzer(client)); + if(ret < 0) { + SCLogDebug("Unable to setup prelude client analyzer."); + prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); + SCReturnPtr(NULL, "AlertPreludeCtx"); + } ret = prelude_client_start(client); if (unlikely(ret < 0)) { @@ -855,7 +908,7 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p goto err; idmef_alert_set_create_time(alert, time); - idmef_alert_set_analyzer(alert, idmef_analyzer_ref(prelude_client_get_analyzer(apn->ctx->client)), IDMEF_LIST_PREPEND); + idmef_alert_set_analyzer(alert, idmef_analyzer_ref(apn->analyzer), IDMEF_LIST_PREPEND); /* finally, send event */ prelude_client_send_idmef(apn->ctx->client, idmef); From 8719d903143c81f6650829144ba4080134c52c82 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 17 Dec 2015 16:41:05 +0100 Subject: [PATCH 0918/2553] prelude: style fixup --- src/alert-prelude.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index f3da0192675d..b5360d13522c 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -752,8 +752,8 @@ static OutputCtx *AlertPreludeInitCtx(ConfNode *conf) } ret = SetupAnalyzer(prelude_client_get_analyzer(client)); - if(ret < 0) { - SCLogDebug("Unable to setup prelude client analyzer."); + if (ret < 0) { + SCLogDebug("Unable to setup prelude client analyzer."); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); } From 33ce78175966722bfbd1beb6a346980900294158 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 18 Dec 2015 11:03:40 +0100 Subject: [PATCH 0919/2553] pcap: fix setup failure memleak on libpcap < 1.0 --- src/source-pcap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/source-pcap.c b/src/source-pcap.c index 0656f9589069..1f0c59bd618e 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -554,6 +554,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->livedev = LiveGetDevice(pcapconfig->iface); if (ptv->livedev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); + SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } From 5457c8d5b37bf5e6ff5c65a1fa6d142c619e12a7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 18 Dec 2015 11:07:36 +0100 Subject: [PATCH 0920/2553] prelude: clean up memory on setup failure --- src/alert-prelude.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index b5360d13522c..1a7b2681499c 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -657,6 +657,8 @@ static TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data if (unlikely(idmef_analyzer_new(&aun->analyzer) < 0)) { SCLogError(SC_ERR_INITIALIZATION, "Error creating idmef analyzer for Prelude."); + + SCFree(aun); SCReturnInt(TM_ECODE_FAILED); } @@ -664,6 +666,9 @@ static TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data if (unlikely(SetupAnalyzer(aun->analyzer) < 0)) { SCLogError(SC_ERR_INITIALIZATION, "Error configuring idmef analyzer for Prelude."); + + idmef_analyzer_destroy(aun->analyzer); + SCFree(aun); SCReturnInt(TM_ECODE_FAILED); } From 37a64bdd45936875598925f7ccde420e4efdc450 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Dec 2015 16:27:35 +0100 Subject: [PATCH 0921/2553] redis: fix compiler warning --- src/util-logopenfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 84e5d2fe631b..04173d48f1ef 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -538,7 +538,7 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) } #ifdef HAVE_LIBHIREDIS -static int LogFileWriteRedis(LogFileCtx *file_ctx, char *string, size_t string_len) +static int LogFileWriteRedis(LogFileCtx *file_ctx, const char *string, size_t string_len) { if (file_ctx->redis == NULL) { SCConfLogReopenRedis(file_ctx); From 44a444ba78cb2a59712ca0b778254750e151a384 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 21 Dec 2015 14:11:44 +0100 Subject: [PATCH 0922/2553] Update changelog for 3.0RC3 --- ChangeLog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index 5f5cbeb3a477..b121928ad41c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +3.0RC3 -- 2015-12-21 + +Bug #1632: Fail to download large file with browser +Bug #1634: Fix non thread safeness of Prelude analyzer +Bug #1640: drop log crashes +Bug #1645: Race condition in unix manager +Bug #1647: FlowGetKey flow-hash.c:240 segmentation fault (master) +Bug #1650: DER parsing issue (master) + 3.0RC2 -- 2015-12-08 Bug #1551: --enable-profiling-locks broken From 202b11c0f6215bfee120addf651a7dc30a98f0e5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 11 Jan 2016 16:46:35 -0500 Subject: [PATCH 0923/2553] smtp: harden mime parsing --- src/app-layer-smtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 61ac4ec645e6..8afcf2597472 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -767,7 +767,7 @@ static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, * the reply received */ SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f); - if (smtp_config.decode_mime) { + if (smtp_config.decode_mime && state->curr_tx->mime_state != NULL) { /* Complete parsing task */ int ret = MimeDecParseComplete(state->curr_tx->mime_state); if (ret != MIME_DEC_OK) { From f9faf990fb08c1a8df5694d7156300f909422f58 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 22 Jan 2016 16:56:48 +0100 Subject: [PATCH 0924/2553] Update Changelog for 3.0 --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index b121928ad41c..c3ef35c4ce69 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +3.0 -- 2016-01-27 + +Bug #1673: smtp: crash during mime parsing + 3.0RC3 -- 2015-12-21 Bug #1632: Fail to download large file with browser From 384db278008b39157c38a796e7f67f72b91af3b0 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 21 Dec 2015 15:13:09 +0100 Subject: [PATCH 0925/2553] unix-manager: fix ressource leak when init fail --- src/unix-manager.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/unix-manager.c b/src/unix-manager.c index ca92677bab50..ffbff905a498 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -858,6 +858,7 @@ static TmEcode UnixManagerThreadInit(ThreadVars *t, void *initdata, void **data) if (ConfGetBool("engine.init-failure-fatal", &failure_fatal) != 1) { SCLogDebug("ConfGetBool could not load the value."); } + SCFree(utd); if (failure_fatal) { exit(EXIT_FAILURE); } else { From 2aa971240be3727a64ada18cda1bf422e6bf6c44 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Wed, 23 Dec 2015 11:49:11 +0300 Subject: [PATCH 0926/2553] unix manager: log client's version with debug level As (dis)connects are already logged as a debug events, this one should do the same. --- src/unix-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index ffbff905a498..c03c20ae7098 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -334,7 +334,7 @@ int UnixCommandAccept(UnixCommand *this) close(client); return 0; } else { - SCLogInfo("Unix socket: client version: \"%s\"", + SCLogDebug("Unix socket: client version: \"%s\"", json_string_value(version)); } From 4352dd179ccdc7b845ae4498d2aa6d41d8fc5455 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 20 Jan 2016 22:41:22 -0600 Subject: [PATCH 0927/2553] conf: null guard in ConfNodeLookupChild Add NULL guarding to the lookup so callers can process nodes in a loop with less error checking. Addresses issue #1660. --- src/conf.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/conf.c b/src/conf.c index 88b9389c58e9..e279a526d7ee 100644 --- a/src/conf.c +++ b/src/conf.c @@ -722,8 +722,12 @@ ConfNode *ConfNodeLookupChild(const ConfNode *node, const char *name) { ConfNode *child; + if (node == NULL || name == NULL) { + return NULL; + } + TAILQ_FOREACH(child, &node->head, next) { - if (strcmp(child->name, name) == 0) + if (child->name != NULL && strcmp(child->name, name) == 0) return child; } @@ -1050,6 +1054,7 @@ static int ConfTestGetBool(void) static int ConfNodeLookupChildTest(void) { + int retval = 0; char *test_vals[] = { "one", "two", "three" }; size_t u; @@ -1065,35 +1070,44 @@ static int ConfNodeLookupChildTest(void) child = ConfNodeLookupChild(parent, "one"); if (child == NULL) - return 0; + goto end; if (strcmp(child->name, "one") != 0) - return 0; + goto end; if (strcmp(child->val, "one") != 0) - return 0; + goto end; child = ConfNodeLookupChild(parent, "two"); if (child == NULL) - return 0; + goto end; if (strcmp(child->name, "two") != 0) - return 0; + goto end; if (strcmp(child->val, "two") != 0) - return 0; + goto end; child = ConfNodeLookupChild(parent, "three"); if (child == NULL) - return 0; + goto end; if (strcmp(child->name, "three") != 0) - return 0; + goto end; if (strcmp(child->val, "three") != 0) - return 0; + goto end; child = ConfNodeLookupChild(parent, "four"); if (child != NULL) - return 0; + goto end; - ConfNodeFree(parent); + if (ConfNodeLookupChild(NULL, NULL) != NULL) { + goto end; + } - return 1; + retval = 1; + +end: + if (parent != NULL) { + ConfNodeFree(parent); + } + + return retval; } static int ConfNodeLookupChildValueTest(void) From b6de1b6567fc446a41d4176d7edb2b075b9066da Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 19 Jan 2016 21:38:37 +0100 Subject: [PATCH 0928/2553] coccinelle: fix typo for strchrnul --- qa/coccinelle/banned-functions.cocci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/coccinelle/banned-functions.cocci b/qa/coccinelle/banned-functions.cocci index 5913521cb38f..bab5e4ee69ed 100644 --- a/qa/coccinelle/banned-functions.cocci +++ b/qa/coccinelle/banned-functions.cocci @@ -3,7 +3,7 @@ identifier i; position p1; @@ -\(strtok@i\|sprintf@i\|strcat@i\|strcpy@i\|strncpy@i\|strncat@i\|strndup@i\|strchrdup@i\)(...)@p1 +\(strtok@i\|sprintf@i\|strcat@i\|strcpy@i\|strncpy@i\|strncat@i\|strndup@i\|strchrnul@i\)(...)@p1 @script:python@ p1 << banned.p1; From 05fdfcb71ee255ffcd6c3761ee564bd93e504b5e Mon Sep 17 00:00:00 2001 From: Alessandro Guido Date: Wed, 16 Sep 2015 15:14:11 +0200 Subject: [PATCH 0929/2553] Segfault fix --- src/detect-engine-content-inspection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index 17df02ce9a1a..ae86a3574e1e 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -433,7 +433,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* if we have dce enabled we will have to use the endianness * specified by the dce header */ - if (flags & DETECT_BYTETEST_DCE) { + if (data && flags & DETECT_BYTETEST_DCE) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ From 96ed8d90ee6b6ea4b3ddc475dca125a5b33b2898 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 22 Sep 2015 15:20:25 +0200 Subject: [PATCH 0930/2553] Fix two more potential issues like bug 1550 --- src/detect-engine-content-inspection.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index ae86a3574e1e..be6d09f6cd7a 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -433,7 +433,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* if we have dce enabled we will have to use the endianness * specified by the dce header */ - if (data && flags & DETECT_BYTETEST_DCE) { + if (flags & DETECT_BYTETEST_DCE && data != NULL) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ @@ -459,7 +459,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* if we have dce enabled we will have to use the endianness * specified by the dce header */ - if (flags & DETECT_BYTEJUMP_DCE) { + if (flags & DETECT_BYTEJUMP_DCE && data != NULL) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ @@ -482,7 +482,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if ((bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) && - endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { + endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE && data != NULL) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done From 18760e222a607a8b1ab6f4277e568ad0e93ee411 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 3 Feb 2016 14:28:50 -0600 Subject: [PATCH 0931/2553] asn1: fix memory leak As reported in issue #1395, fix 2 memory leaks when destroying asn.1 decode contexts. --- src/util-decode-asn1.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/util-decode-asn1.c b/src/util-decode-asn1.c index 3372b517cec4..4e4115a104ff 100644 --- a/src/util-decode-asn1.c +++ b/src/util-decode-asn1.c @@ -373,13 +373,15 @@ void SCAsn1CtxDestroy(Asn1Ctx *ac) if (ac == NULL) return; - uint16_t i = 0; - for (; i < ac->cur_frame; i++) { + for (uint16_t i = 0; i < asn1_max_frames_config; i++) { Asn1Node *node = ASN1CTX_GET_NODE(ac, i); - if (node != NULL) { - SCFree(node); + if (node == NULL) { + break; } + SCFree(node); } + + SCFree(ac->asn1_stack); SCFree(ac); } From dc1bd5b6bd15e24f57eef0dd6677cc49526a2897 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 31 Jan 2016 23:15:20 +0100 Subject: [PATCH 0932/2553] configure: add --disable-python option --- configure.ac | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index f3d20a1f5f0a..c5d8b8ea1e84 100644 --- a/configure.ac +++ b/configure.ac @@ -113,17 +113,24 @@ exit 1 fi + AC_ARG_ENABLE(python, + AS_HELP_STRING([--enable-python], [Enable python]),,[enable_python=yes]) AC_PATH_PROG(HAVE_PYTHON_CONFIG, python, "no") + if test "x$enable_python" = "xno" ; then + echo + echo " Warning! python disabled, you will not be " + echo " able to install surictasc unix socket client " + echo + enable_python="no" + fi if test "$HAVE_PYTHON_CONFIG" = "no"; then echo echo " Warning! python not found, you will not be " echo " able to install surictasc unix socket client " echo enable_python="no" - else - enable_python="yes" fi - AM_CONDITIONAL([HAVE_PYTHON], [test "$HAVE_PYTHON_CONFIG" != "no"]) + AM_CONDITIONAL([HAVE_PYTHON], [test "x$enable_python" = "xyes"]) AC_PATH_PROG(HAVE_WGET, wget, "no") if test "$HAVE_WGET" = "no"; then From 20dd593981285735f3f1d4272a565c76172c6284 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 31 Jan 2016 22:34:56 +0100 Subject: [PATCH 0933/2553] remove unnecessary braces --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c5d8b8ea1e84..000cc68000eb 100644 --- a/configure.ac +++ b/configure.ac @@ -418,7 +418,7 @@ ]) AC_ARG_ENABLE(coccinelle, - AS_HELP_STRING([--disable-coccinelle], [Disable coccinelle QA steps during make check])],[enable_coccinelle="$enableval"],[enable_coccinelle=yes]) + AS_HELP_STRING([--disable-coccinelle], [Disable coccinelle QA steps during make check]),[enable_coccinelle="$enableval"],[enable_coccinelle=yes]) AS_IF([test "x$enable_coccinelle" = "xyes"], [ AC_PATH_PROG(HAVE_COCCINELLE_CONFIG, spatch, "no") if test "$HAVE_COCCINELLE_CONFIG" = "no"; then @@ -433,7 +433,7 @@ # disable detection AC_ARG_ENABLE(detection, - AS_HELP_STRING([--disable-detection], [Disable Detection Modules])], [enable_detection="$enableval"],[enable_detection=yes]) + AS_HELP_STRING([--disable-detection], [Disable Detection Modules]), [enable_detection="$enableval"],[enable_detection=yes]) AS_IF([test "x$enable_detection" = "xno"], [ AC_DEFINE([HAVE_DETECT_DISABLED], [1], [Detection is disabled]) ]) From 368d7e913a9a71d877befce3e5bbc847b7917b90 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Thu, 4 Feb 2016 15:33:23 +0300 Subject: [PATCH 0934/2553] In configuration test mode, check signatures if 'delayed-detect' is enabled When 'detection-engine.delayed-detect' option was set to 'yes', suricata didn't check signatures validity in configuration test mode. --- src/suricata.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/suricata.c b/src/suricata.c index a6ed5736a5be..4c18f6a5b130 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2304,7 +2304,8 @@ int main(int argc, char **argv) "detection engine contexts failed."); exit(EXIT_FAILURE); } - if (suri.delayed_detect || (mt_enabled && !default_tenant)) { + if ((suri.delayed_detect || (mt_enabled && !default_tenant)) && + (suri.run_mode != RUNMODE_CONF_TEST)) { de_ctx = DetectEngineCtxInitMinimal(); } else { de_ctx = DetectEngineCtxInit(); From 15c98c6085fb4e4d23accc34e660841ef735778a Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Fri, 29 Jan 2016 22:02:22 +0100 Subject: [PATCH 0935/2553] file-magic: improve libmagic handling on *nix systems --- configure.ac | 7 ++++--- src/detect-filemagic.c | 17 ++++++++++++----- src/util-magic.c | 19 ++++++++++++++----- suricata.yaml.in | 2 +- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index 000cc68000eb..6cbea678903b 100644 --- a/configure.ac +++ b/configure.ac @@ -215,7 +215,8 @@ fi echo -n "installation for $host OS... " - e_magic_file="/usr/share/file/magic" + e_magic_file="" + e_magic_file_comment="#" case "$host" in *-*-*freebsd*) LUA_PC_NAME="lua-5.1" @@ -223,14 +224,12 @@ CFLAGS="${CFLAGS} -DOS_FREEBSD" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet11" LDFLAGS="${LDFLAGS} -L/usr/local/lib -L/usr/local/lib/libnet11" - e_magic_file="/usr/share/misc/magic" ;; *-*-openbsd*) LUA_PC_NAME="lua51" CFLAGS="${CFLAGS} -D__OpenBSD__" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet-1.1" LDFLAGS="${LDFLAGS} -L/usr/local/lib -I/usr/local/lib/libnet-1.1" - e_magic_file="/usr/local/share/misc/magic.mgc" ;; *darwin*|*Darwin*) LUA_PC_NAME="lua-5.1" @@ -1810,6 +1809,7 @@ if test "$WINDOWS_PATH" = "yes"; then e_sysconfdir="$e_winbase\\\\" e_sysconfrulesdir="$e_winbase\\\\rules\\\\" e_magic_file="$e_winbase\\\\magic.mgc" + e_magic_file_comment="" e_logdir="$e_winbase\\\\log" e_logfilesdir="$e_logdir\\\\files" e_logcertsdir="$e_logdir\\\\certs" @@ -1831,6 +1831,7 @@ AC_SUBST(e_sysconfrulesdir) AC_SUBST(e_localstatedir) AC_DEFINE_UNQUOTED([CONFIG_DIR],["$e_sysconfdir"],[Our CONFIG_DIR]) AC_SUBST(e_magic_file) +AC_SUBST(e_magic_file_comment) EXPAND_VARIABLE(prefix, CONFIGURE_PREFIX) EXPAND_VARIABLE(sysconfdir, CONFIGURE_SYSCONDIR) diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 5dd28ec8195b..ab85feed3e3b 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -322,13 +322,20 @@ static void *DetectFilemagicThreadInit(void *data) (void)ConfGet("magic-file", &filename); if (filename != NULL) { - SCLogInfo("using magic-file %s", filename); + if (strlen(filename) == 0) { + /* set filename to NULL on *nix systems so magic_load uses system default path (see man libmagic) */ + SCLogInfo("using system default magic-file"); + filename = NULL; + } + else { + SCLogInfo("using magic-file %s", filename); - if ( (fd = fopen(filename, "r")) == NULL) { - SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); - goto error; + if ( (fd = fopen(filename, "r")) == NULL) { + SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); + goto error; + } + fclose(fd); } - fclose(fd); } if (magic_load(t->ctx, filename) != 0) { diff --git a/src/util-magic.c b/src/util-magic.c index fa05c6d90eb6..bad15fbe5e2a 100644 --- a/src/util-magic.c +++ b/src/util-magic.c @@ -58,14 +58,23 @@ int MagicInit(void) } (void)ConfGet("magic-file", &filename); + + if (filename != NULL) { - SCLogInfo("using magic-file %s", filename); + if (strlen(filename) == 0) { + /* set filename to NULL on *nix systems so magic_load uses system default path (see man libmagic) */ + SCLogInfo("using system default magic-file"); + filename = NULL; + } + else { + SCLogInfo("using magic-file %s", filename); - if ( (fd = fopen(filename, "r")) == NULL) { - SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); - goto error; + if ( (fd = fopen(filename, "r")) == NULL) { + SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); + goto error; + } + fclose(fd); } - fclose(fd); } if (magic_load(g_magic_ctx, filename) != 0) { diff --git a/suricata.yaml.in b/suricata.yaml.in index 6614906f13d2..90f590915cab 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -395,7 +395,7 @@ outputs: # Magic file. The extension .mgc is added to the value here. #magic-file: /usr/share/file/magic -magic-file: @e_magic_file@ +@e_magic_file_comment@magic-file: @e_magic_file@ # When running in NFQ inline mode, it is possible to use a simulated # non-terminal NFQUEUE verdict. From adbf8bec747680f4b259b4dc37b2156f2f01d6b8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 8 Feb 2016 11:50:20 +0100 Subject: [PATCH 0936/2553] drmemory: suppress magic leak --- qa/drmemory.suppress | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/qa/drmemory.suppress b/qa/drmemory.suppress index fd79b022455f..a4f61eb9ce83 100644 --- a/qa/drmemory.suppress +++ b/qa/drmemory.suppress @@ -14,3 +14,16 @@ name=useless warning, likely DrMemory bug * libpcre.so.3!pcre_get_substring +LEAK +name=libmagic minor leak 1 +libmagic.so.1!? +libmagic.so.1!? +libmagic.so.1!magic_load +suricata!MagicInit + +LEAK +name=libmagic minor leak 2 +libmagic.so.1!? +libmagic.so.1!magic_load +suricata!MagicInit + From 8bd9f3d07209b0d2225b553d07ee052ab4fe4910 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 7 Feb 2016 23:02:14 +0100 Subject: [PATCH 0937/2553] json: fix missing includes in disable unix socket case --- src/output-json-alert.c | 1 + src/output-json-alert.h | 1 + src/output-json-http.h | 1 + src/output-json-smtp.h | 1 + src/output-json-ssh.h | 1 + src/output-json-tls.h | 1 + src/output-json.h | 1 + src/util-debug.c | 1 + 8 files changed, 8 insertions(+) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 2c0d01714c7f..5bfe562857c6 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -69,6 +69,7 @@ #define MODULE_NAME "JsonAlertLog" #ifdef HAVE_LIBJANSSON +#include #define LOG_JSON_PAYLOAD 1 #define LOG_JSON_PACKET 2 diff --git a/src/output-json-alert.h b/src/output-json-alert.h index a10a316d20b3..c981574f90dd 100644 --- a/src/output-json-alert.h +++ b/src/output-json-alert.h @@ -29,6 +29,7 @@ void TmModuleJsonAlertLogRegister (void); #ifdef HAVE_LIBJANSSON +#include void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js); #endif /* HAVE_LIBJANSSON */ diff --git a/src/output-json-http.h b/src/output-json-http.h index 0c886f3dd56d..bcaa57aa9476 100644 --- a/src/output-json-http.h +++ b/src/output-json-http.h @@ -27,6 +27,7 @@ void TmModuleJsonHttpLogRegister (void); #ifdef HAVE_LIBJANSSON +#include void JsonHttpLogJSONBasic(json_t *js, htp_tx_t *tx); void JsonHttpLogJSONExtended(json_t *js, htp_tx_t *tx); json_t *JsonHttpAddMetadata(const Flow *f, uint64_t tx_id); diff --git a/src/output-json-smtp.h b/src/output-json-smtp.h index 2f79d992011a..0c60f2d4891a 100644 --- a/src/output-json-smtp.h +++ b/src/output-json-smtp.h @@ -26,6 +26,7 @@ void TmModuleJsonSmtpLogRegister (void); #ifdef HAVE_LIBJANSSON +#include json_t *JsonSMTPAddMetadata(const Flow *f, uint64_t tx_id); #endif diff --git a/src/output-json-ssh.h b/src/output-json-ssh.h index 5d0752bf2a53..28667ca70ea8 100644 --- a/src/output-json-ssh.h +++ b/src/output-json-ssh.h @@ -28,6 +28,7 @@ void TmModuleJsonSshLogRegister (void); #ifdef HAVE_LIBJANSSON #include "app-layer-ssh.h" +#include void JsonSshLogJSON(json_t *js, SshState *tx); #endif diff --git a/src/output-json-tls.h b/src/output-json-tls.h index f330ad898aad..d9d1142b93f6 100644 --- a/src/output-json-tls.h +++ b/src/output-json-tls.h @@ -28,6 +28,7 @@ void TmModuleJsonTlsLogRegister (void); #ifdef HAVE_LIBJANSSON #include "app-layer-ssl.h" +#include void JsonTlsLogJSONBasic(json_t *js, SSLState *ssl_state); void JsonTlsLogJSONExtended(json_t *js, SSLState *ssl_state); diff --git a/src/output-json.h b/src/output-json.h index 89e11d86ce01..b6aec6c05fe3 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -28,6 +28,7 @@ void TmModuleOutputJsonRegister (void); #ifdef HAVE_LIBJANSSON +#include #include "suricata-common.h" #include "util-buffer.h" #include "util-logopenfile.h" diff --git a/src/util-debug.c b/src/util-debug.c index d9af08c4381a..c439cd78c041 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -189,6 +189,7 @@ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) } #ifdef HAVE_LIBJANSSON +#include /** */ int SCLogMessageJSON(struct timeval *tval, char *buffer, size_t buffer_size, From 5cee70f9ae60e480b4c4d71d45848a1b15dae024 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 17 Nov 2015 12:25:29 +0100 Subject: [PATCH 0938/2553] Fix the comment and explanation for random-chunk-size --- suricata.yaml.in | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 90f590915cab..3a6841947dee 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -879,9 +879,10 @@ flow-timeouts: # # This lower the risk of some evasion technics but could lead # # detection change between runs. It is set to 'yes' by default. # randomize-chunk-range: 10 # If randomize-chunk-size is active, the value of chunk-size is -# # a random value between (1 - randomize-chunk-range/100)*randomize-chunk-size -# # and (1 + randomize-chunk-range/100)*randomize-chunk-size. Default value -# # of randomize-chunk-range is 10. +# # a random value between (1 - randomize-chunk-range/100)*toserver-chunk-size +# # and (1 + randomize-chunk-range/100)*toserver-chunk-size and the same +# # calculation for toclient-chunk-size. +# # Default value of randomize-chunk-range is 10. # # raw: yes # 'Raw' reassembly enabled or disabled. # # raw is for content inspection by detection From 2a17e3e827a2d90d03b0525ad567d3668681947d Mon Sep 17 00:00:00 2001 From: bladeswords Date: Wed, 3 Feb 2016 22:09:34 +1100 Subject: [PATCH 0939/2553] Fix typo of trailing ] in configure --help It is the small things that count. This is an example of the fix Before --disable-threading-tls Disable TLS (thread local storage)] After --disable-threading-tls Disable TLS (thread local storage) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6cbea678903b..6daa5e6df8bd 100644 --- a/configure.ac +++ b/configure.ac @@ -259,7 +259,7 @@ # disable TLS on user request AC_ARG_ENABLE(threading-tls, - AS_HELP_STRING([--disable-threading-tls], [Disable TLS (thread local storage)])], [enable_tls="$enableval"],[enable_tls=yes]) + AS_HELP_STRING([--disable-threading-tls], [Disable TLS (thread local storage)]), [enable_tls="$enableval"],[enable_tls=yes]) AS_IF([test "x$enable_tls" = "xyes"], [ # check if our target supports thread local storage AC_MSG_CHECKING(for thread local storage __thread support) From 2b263d55a2d0583a2c02e352bfe490fd4f42b39a Mon Sep 17 00:00:00 2001 From: notnyt Date: Fri, 5 Feb 2016 19:11:03 -0500 Subject: [PATCH 0940/2553] fix nfq_get_timestamp Handle case when nfq_get_timestamp returns 0 for success, but timestamp is empty. --- src/source-nfq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-nfq.c b/src/source-nfq.c index 38770cb9708e..9b9e737600a6 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -473,7 +473,7 @@ int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data) } ret = nfq_get_timestamp(tb, &p->ts); - if (ret != 0) { + if (ret != 0 || p->ts.tv_sec == 0) { memset (&p->ts, 0, sizeof(struct timeval)); gettimeofday(&p->ts, NULL); } From c4fb6217ee72969ef59b60ff7f4a0f6bfeaa8c9b Mon Sep 17 00:00:00 2001 From: Maurizio Abba Date: Mon, 16 Nov 2015 12:21:27 +0000 Subject: [PATCH 0941/2553] filestore-call: forcing a call to FileStore instead of manually updating the relative flag in order to have a single point where we actually touch the File structure --- src/util-file.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util-file.c b/src/util-file.c index 66d4080e66ba..16a7bd40fe51 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -535,7 +535,7 @@ File *FileOpenFile(FileContainer *ffc, uint8_t *name, } if (flags & FILE_STORE) { - ff->flags |= FILE_STORE; + FileStore(ff); } else if (flags & FILE_NOSTORE) { SCLogDebug("not storing this file"); ff->flags |= FILE_NOSTORE; @@ -882,7 +882,7 @@ void FileStoreFileById(FileContainer *fc, uint32_t file_id) if (fc != NULL) { for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { if (ptr->file_id == file_id) { - ptr->flags |= FILE_STORE; + FileStore(ptr); } } } @@ -897,7 +897,7 @@ void FileStoreAllFilesForTx(FileContainer *fc, uint64_t tx_id) if (fc != NULL) { for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { if (ptr->txid == tx_id) { - ptr->flags |= FILE_STORE; + FileStore(ptr); } } } @@ -911,7 +911,7 @@ void FileStoreAllFiles(FileContainer *fc) if (fc != NULL) { for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { - ptr->flags |= FILE_STORE; + FileStore(ptr); } } } From 3c9538b783e1f3f0765b75a93e0c8a5949697edb Mon Sep 17 00:00:00 2001 From: Nicolas Thill Date: Fri, 5 Feb 2016 11:11:13 +0100 Subject: [PATCH 0942/2553] lua: set thread vars in DetectLuaMatch Fix internal error when calling SCThreadInfo from Lua detection modules. Signed-off-by: Nicolas Thill --- src/detect-lua.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect-lua.c b/src/detect-lua.c index a3eead4a9e12..c4a49bdda780 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -418,6 +418,7 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, else if (p->flowflags & FLOW_PKT_TOCLIENT) flags = STREAM_TOCLIENT; + LuaStateSetThreadVars(tluajit->luastate, tv); LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, p->flow, /* flow not locked */LUA_FLOW_NOT_LOCKED_BY_PARENT, p, flags); From 559747e325cf89f01e4b8bb659bb6f92a5275139 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Mon, 5 Oct 2015 15:34:55 -0700 Subject: [PATCH 0943/2553] file-store: add force-filestore configuration option to enable writing all extracted files to filesystem. --- src/log-file.c | 6 ++++++ src/log-filestore.c | 6 ++++++ src/output-json-file.c | 6 ++++++ src/util-file.c | 17 ++++++++++++++++- src/util-file.h | 2 ++ suricata.yaml.in | 1 + 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/log-file.c b/src/log-file.c index 0c41e38d298c..d95c4310acb7 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -416,6 +416,12 @@ static OutputCtx *LogFileLogInitCtx(ConfNode *conf) output_ctx->data = logfile_ctx; output_ctx->DeInit = LogFileLogDeInitCtx; + const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore"); + if (force_filestore != NULL && ConfValIsTrue(force_filestore)) { + FileForceFilestoreEnable(); + SCLogInfo("forcing filestore of all files"); + } + const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); diff --git a/src/log-filestore.c b/src/log-filestore.c index 4244b9a44fa5..5069ec857921 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -458,6 +458,12 @@ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) } } + const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore"); + if (force_filestore != NULL && ConfValIsTrue(force_filestore)) { + FileForceFilestoreEnable(); + SCLogInfo("forcing filestore of all files"); + } + const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); diff --git a/src/output-json-file.c b/src/output-json-file.c index 32f3a9435c7f..c3932cac3c6b 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -260,6 +260,12 @@ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) output_file_ctx->file_ctx = ojc->file_ctx; if (conf) { + const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore"); + if (force_filestore != NULL && ConfValIsTrue(force_filestore)) { + FileForceFilestoreEnable(); + SCLogInfo("forcing filestore of all files"); + } + const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); diff --git a/src/util-file.c b/src/util-file.c index 16a7bd40fe51..38ea1b8d4279 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -36,6 +36,11 @@ #include "app-layer-parser.h" #include "util-validate.h" +/** \brief switch to force filestore on all files + * regardless of the rules. + */ +static int g_file_force_filestore = 0; + /** \brief switch to force magic checks on all files * regardless of the rules. */ @@ -55,6 +60,11 @@ static int g_file_force_tracking = 0; static void FileFree(File *); static void FileDataFree(FileData *); +void FileForceFilestoreEnable(void) +{ + g_file_force_filestore = 1; +} + void FileForceMagicEnable(void) { g_file_force_magic = 1; @@ -65,6 +75,11 @@ void FileForceMd5Enable(void) g_file_force_md5 = 1; } +int FileForceFilestore(void) +{ + return g_file_force_filestore; +} + int FileForceMagic(void) { return g_file_force_magic; @@ -534,7 +549,7 @@ File *FileOpenFile(FileContainer *ffc, uint8_t *name, SCReturnPtr(NULL, "File"); } - if (flags & FILE_STORE) { + if (flags & FILE_STORE || g_file_force_filestore) { FileStore(ff); } else if (flags & FILE_NOSTORE) { SCLogDebug("not storing this file"); diff --git a/src/util-file.h b/src/util-file.h index 8f322a99d7d0..6d02d395d1f1 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -172,6 +172,8 @@ void FileDisableStoringForTransaction(Flow *f, uint8_t direction, uint64_t tx_id void FlowFileDisableStoringForTransaction(struct Flow_ *f, uint64_t tx_id); void FilePrune(FileContainer *ffc); +void FileForceFilestoreEnable(void); +int FileForceFilestore(void); void FileDisableMagic(Flow *f, uint8_t); void FileForceMagicEnable(void); diff --git a/suricata.yaml.in b/suricata.yaml.in index 3a6841947dee..1f35e130727c 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -349,6 +349,7 @@ outputs: log-dir: files # directory to store the files force-magic: no # force logging magic on all stored files force-md5: no # force logging of md5 checksums + force-filestore: no # force storing of all files #waldo: file.waldo # waldo file to store the file_id across runs # output module to log files tracked in a easily parsable json format From 6f79137971f50450212d3191a31dfe88e1f21f1d Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 2 Nov 2015 13:21:37 +0100 Subject: [PATCH 0944/2553] lua: expose TLS certificate chain to lua Expose TLS certificate chain to lua through TlsGetCertChain(). --- src/util-lua-tls.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/util-lua-tls.c b/src/util-lua-tls.c index 5963ac246cd8..e17e512e41c8 100644 --- a/src/util-lua-tls.c +++ b/src/util-lua-tls.c @@ -170,6 +170,68 @@ static int TlsGetSNI(lua_State *luastate) return r; } +static int GetCertChain(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + uint32_t u = 0; + lua_newtable(luastate); + SSLCertsChain *cert = NULL; + TAILQ_FOREACH(cert, &connp->certs, next) + { + lua_pushinteger(luastate, u++); + + lua_newtable(luastate); + + lua_pushstring(luastate, "length"); + lua_pushinteger(luastate, cert->cert_len); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "data"); + LuaPushStringBuffer(luastate, cert->cert_data, cert->cert_len); + + lua_settable(luastate, -3); + lua_settable(luastate, -3); + } + + return 1; +} + +static int TlsGetCertChain(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + int lock_hint = 0; + Flow *f = LuaStateGetFlow(luastate, &lock_hint); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + FLOWLOCK_RDLOCK(f); + r = GetCertChain(luastate, f, direction); + FLOWLOCK_UNLOCK(f); + } else { + r = GetCertChain(luastate, f, direction); + } + return r; +} + /** \brief register tls lua extensions in a luastate */ int LuaRegisterTlsFunctions(lua_State *luastate) { @@ -180,6 +242,9 @@ int LuaRegisterTlsFunctions(lua_State *luastate) lua_pushcfunction(luastate, TlsGetSNI); lua_setglobal(luastate, "TlsGetSNI"); + lua_pushcfunction(luastate, TlsGetCertChain); + lua_setglobal(luastate, "TlsGetCertChain"); + return 0; } From 4b8bd9dfc9fb99162233983e7c3c97f3ec7684da Mon Sep 17 00:00:00 2001 From: Maxtors Date: Mon, 1 Feb 2016 14:54:29 +0100 Subject: [PATCH 0945/2553] Added checking of negated "totals" and "threads" config values for stats. --- src/log-stats.c | 9 +++++++++ src/output-json-stats.c | 8 ++++++++ src/util-error.c | 2 ++ src/util-error.h | 2 ++ 4 files changed, 21 insertions(+) diff --git a/src/log-stats.c b/src/log-stats.c index 385dec2bb4fc..8507deb301c6 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -245,6 +245,15 @@ OutputCtx *LogStatsLogInitCtx(ConfNode *conf) const char *nulls = ConfNodeLookupChildValue(conf, "null-values"); SCLogDebug("totals %s threads %s", totals, threads); + if ((totals != NULL && ConfValIsFalse(totals)) && + (threads != NULL && ConfValIsFalse(threads))) { + LogFileFreeCtx(file_ctx); + SCFree(statslog_ctx); + SCLogError(SC_ERR_STATS_LOG_NEGATED, + "Cannot disable both totals and threads in stats logging"); + return NULL; + } + if (totals != NULL && ConfValIsFalse(totals)) { statslog_ctx->flags &= ~LOG_STATS_TOTALS; } diff --git a/src/output-json-stats.c b/src/output-json-stats.c index fea7177aa8fb..a22f9d6b9675 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -327,6 +327,14 @@ OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) const char *deltas = ConfNodeLookupChildValue(conf, "deltas"); SCLogDebug("totals %s threads %s deltas %s", totals, threads, deltas); + if ((totals != NULL && ConfValIsFalse(totals)) && + (threads != NULL && ConfValIsFalse(threads))) { + SCFree(stats_ctx); + SCLogError(SC_ERR_JSON_STATS_LOG_NEGATED, + "Cannot disable both totals and threads in stats logging"); + return NULL; + } + if (totals != NULL && ConfValIsFalse(totals)) { stats_ctx->flags &= ~JSON_STATS_TOTALS; } diff --git a/src/util-error.c b/src/util-error.c index 7f2caf00d259..8ea229b5988d 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -312,6 +312,8 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_MT_NO_MAPPING); CASE_CODE (SC_ERR_NO_JSON_SUPPORT); CASE_CODE (SC_ERR_INVALID_RULE_ARGUMENT); + CASE_CODE (SC_ERR_STATS_LOG_NEGATED); + CASE_CODE (SC_ERR_JSON_STATS_LOG_NEGATED); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index cd2ce24927c6..fec09d04a7bf 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -302,6 +302,8 @@ typedef enum { SC_ERR_INVALID_RULE_ARGUMENT, /**< Generic error code for invalid * rule argument. */ SC_ERR_MT_NO_MAPPING, + SC_ERR_STATS_LOG_NEGATED, /** When totals and threads are both NO in yaml **/ + SC_ERR_JSON_STATS_LOG_NEGATED, /** When totals and threads are both NO in yaml **/ } SCError; const char *SCErrorToString(SCError); From 6152d1abca7af90e01c69873fa38a272456f76b5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 31 Jan 2016 13:40:07 +0100 Subject: [PATCH 0946/2553] eve: fix stream payload logging wrong direction In the EVE stream payload logging the IPS path logged the wrong dir. Both IDS and IPS can take the same path as the detection engine inspects in the same direction in both cases, so the alert is also generated in the same direction. Bug #1684 --- src/output-json-alert.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 5bfe562857c6..32ec6c849850 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -275,18 +275,10 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) MemBufferReset(payload); - if (!EngineModeIsIPS()) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - flag = FLOW_PKT_TOCLIENT; - } else { - flag = FLOW_PKT_TOSERVER; - } + if (p->flowflags & FLOW_PKT_TOSERVER) { + flag = FLOW_PKT_TOCLIENT; } else { - if (p->flowflags & FLOW_PKT_TOSERVER) { - flag = FLOW_PKT_TOSERVER; - } else { - flag = FLOW_PKT_TOCLIENT; - } + flag = FLOW_PKT_TOSERVER; } StreamSegmentForEach((const Packet *)p, flag, From 3a9bcd6a5362346b0e5c55fb4a2eb4117d818af4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 31 Jan 2016 19:27:35 +0100 Subject: [PATCH 0947/2553] qa: add --simulate-ips option This option forces the engine in 'IPS' mode. This is useful for testing some IPS code paths based on pcaps. --- src/suricata.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index 4c18f6a5b130..811a760008c0 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -590,6 +590,7 @@ void usage(const char *progname) printf("\t--pfring-cluster-id : pfring cluster id \n"); printf("\t--pfring-cluster-type : pfring cluster type for PF_RING 4.1.2 and later cluster_round_robin|cluster_flow\n"); #endif /* HAVE_PFRING */ + printf("\t--simulate-ips : force engine into IPS mode. Useful for QA\n"); #ifdef HAVE_LIBCAP_NG printf("\t--user : run suricata as this user after init\n"); printf("\t--group : run suricata as this group after init\n"); @@ -1126,6 +1127,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"af-packet", optional_argument, 0, 0}, {"netmap", optional_argument, 0, 0}, {"pcap", optional_argument, 0, 0}, + {"simulate-ips", 0, 0 , 0}, #ifdef BUILD_UNIX_SOCKET {"unix-socket", optional_argument, 0, 0}, #endif @@ -1311,6 +1313,9 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) usage(argv[0]); return TM_ECODE_FAILED; } + } else if(strcmp((long_opts[option_index]).name, "simulate-ips") == 0) { + SCLogInfo("Setting IPS mode"); + EngineModeSetIPS(); } else if(strcmp((long_opts[option_index]).name, "init-errors-fatal") == 0) { if (ConfSetFinal("engine.init-failure-fatal", "1") != 1) { fprintf(stderr, "ERROR: Failed to set engine init-failure-fatal.\n"); From b93a302a5b3d011bc43118cce5037e89becab2f2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 3 Feb 2016 09:51:33 +0100 Subject: [PATCH 0948/2553] stream: improve StreamTcpSegmentForEach for IPS StreamTcpSegmentForEach would only return ACK'd segments. This lead to missing stream data in alerts when running in IPS mode. This patch changes the behavior for IPS. All segments are iterated now, also the non-ACK'd ones. For IDS mode the behavior is unchanged. --- src/stream-tcp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 9dce70709ee3..4c0a81d7f292 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5920,8 +5920,8 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread /** * \brief Run callback function on each TCP segment * - * This function is used by StreamMsgForEach() which - * should be used directly. + * \note when stream engine is running in inline mode all segments are used, + * in IDS/non-inline mode only ack'd segments are iterated. * * \return -1 in case of error, the number of segment in case of success * @@ -5949,8 +5949,12 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback } else { stream = &(ssn->client); } + + /* for IDS, return ack'd segments. For IPS all. */ TcpSegment *seg = stream->seg_list; - for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) { + for (; seg != NULL && + (stream_inline || SEQ_LT(seg->seq, stream->last_ack));) + { ret = CallbackFunc(p, data, seg->payload, seg->payload_len); if (ret != 1) { SCLogDebug("Callback function has failed"); From 4086938f1e3b8f108230f88dbba0f8834966d8bf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 12 Feb 2016 10:48:26 +0100 Subject: [PATCH 0949/2553] pool: fix memory leak Due to pointer size mishandling, the pool code could consider a block of memory inside the 'preallocated' block. It would then not free the block. --- configure.ac | 1 + src/suricata-common.h | 4 ++++ src/util-pool.c | 4 ++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6daa5e6df8bd..79578fb31058 100644 --- a/configure.ac +++ b/configure.ac @@ -147,6 +147,7 @@ # Checks for libraries. # Checks for header files. + AC_CHECK_HEADERS([stddef.h]) AC_CHECK_HEADERS([arpa/inet.h assert.h ctype.h errno.h fcntl.h inttypes.h]) AC_CHECK_HEADERS([getopt.h]) AC_CHECK_HEADERS([limits.h netdb.h netinet/in.h poll.h sched.h signal.h]) diff --git a/src/suricata-common.h b/src/suricata-common.h index 388f1a429cd3..4d60f7878183 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -49,6 +49,10 @@ #include #endif +#if HAVE_STDDEF_H +#include +#endif + #if HAVE_STDINT_h #include #endif diff --git a/src/util-pool.c b/src/util-pool.c index 6f405252046d..4d4d5e40ea21 100644 --- a/src/util-pool.c +++ b/src/util-pool.c @@ -54,10 +54,10 @@ static int PoolMemset(void *pitem, void *initdata) /** * \brief Check if data is preallocated - * \retval 0 or -1 if not inside */ + * \retval 0 if not inside the prealloc'd block, 1 if inside */ static int PoolDataPreAllocated(Pool *p, void *data) { - int delta = data - p->data_buffer; + ptrdiff_t delta = data - p->data_buffer; if ((delta < 0) || (delta > p->data_buffer_size)) { return 0; } From ee5fd4613bec43c13b65c7bb792ad6ef0f01ffdb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 12 Feb 2016 10:54:02 +0100 Subject: [PATCH 0950/2553] tls-sni: fix uninitialized memory use On bad traffic the parser could allocated memory that was not intialized. This was later used in the JSON output logging as a valid null terminated string. --- src/app-layer-ssl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 3d4605aff7d5..5650509b4a62 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -214,15 +214,15 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, uint16_t sni_len = ntohs(*(uint16_t *)input); input += 2; + if (!(HAS_SPACE(sni_len))) + goto end; + size_t sni_strlen = sni_len + 1; ssl_state->curr_connp->sni = SCMalloc(sni_strlen); if (unlikely(ssl_state->curr_connp->sni == NULL)) goto end; - if (!(HAS_SPACE(sni_len))) - goto end; - memcpy(ssl_state->curr_connp->sni, input, sni_strlen - 1); ssl_state->curr_connp->sni[sni_strlen-1] = 0; From 4ee20f264976e43280cfcc850bbac5b82563d0f4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 11 Feb 2016 18:19:34 +0100 Subject: [PATCH 0951/2553] asan: fix reputation code include --- src/reputation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reputation.c b/src/reputation.c index d1aef713c926..b9e87455cf8f 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -25,12 +25,12 @@ * IP Reputation Module, initial API for IPV4 and IPV6 feed */ +#include "suricata-common.h" #include "util-error.h" #include "util-debug.h" #include "util-ip.h" #include "util-radix-tree.h" #include "util-unittest.h" -#include "suricata-common.h" #include "threads.h" #include "util-print.h" #include "host.h" From 0a22ba7e23deef9ab432d048828169f663dd247b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 12 Feb 2016 16:31:57 +0100 Subject: [PATCH 0952/2553] http: fix multipart body tracking slowdown Optimize HTTP multipart body parsing. Big records that were not files could slow down Suricata. The reason was that the body tracker was not moved forward. This lead to growing body buffers, which were expensive wrt memory and inspection. This patch add logic to move the tracker forward in this case. --- src/app-layer-htp.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 5fd0949296b8..caf2ea53076d 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1552,6 +1552,19 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, (uint8_t *) "\r\n\r\n", 4); } } + + /* if we're parsing the multipart and we're not currently processing a + * file, we move the body pointer forward. */ + if (form_end == NULL && !(htud->tsflags & HTP_FILENAME_SET) && header_start == NULL) { + if (chunks_buffer_len > expected_boundary_end_len) { + uint32_t move = chunks_buffer_len - expected_boundary_end_len + 1; + + htud->request_body.body_parsed += move; + SCLogDebug("form not ready, file not set, parsing non-file " + "record: moved %u", move); + } + } + end: if (expected_boundary != NULL) { HTPFree(expected_boundary, expected_boundary_len); From 0d77c4d5609ca9f2e2ddd0b1afe13d49f50c357d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Nov 2015 13:29:05 +0100 Subject: [PATCH 0953/2553] wirefuzz: add -S option for exclusive rule load --- qa/wirefuzz.pl | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/qa/wirefuzz.pl b/qa/wirefuzz.pl index 63708f0b214b..623e0aa10efa 100755 --- a/qa/wirefuzz.pl +++ b/qa/wirefuzz.pl @@ -2,7 +2,7 @@ #Author:William Metcalf #File:wirefuzz.pl -#Copyright (C) 2010 Open Information Security Foundation +#Copyright (C) 2010-2015 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 @@ -55,7 +55,7 @@ use List::Util 'shuffle'; use Devel::GDB; use File::Find; -use Getopt::Long; +use Getopt::Long qw(:config no_ignore_case); use File::Basename; #globals @@ -65,6 +65,7 @@ my $suricatabin; my $loopnum; my $rules; +my $rules_exclusive = 0; my $logdir; my $configfile; my $editeratio; @@ -80,7 +81,7 @@ my $file_was_fuzzed = 0; Getopt::Long::Configure("prefix_pattern=(-|--)"); -GetOptions( \%config, qw(n=s r=s c=s e=s v=s p=s l=s s=s x=s k y z=s h help) ); +GetOptions( \%config, qw(n=s r=s c=s e=s v=s p=s l=s s=s S=s x=s k y z=s h help) ); &parseopts(); @@ -169,6 +170,16 @@ sub parseopts { print("parseopts: rules file not specified or doesn't exist\n"); } + # exclusive rules file: do we have a path and does it exist + if ( $config{S} && -e $config{S} ) { + $rules = $config{S}; + $rules_exclusive = 1; + print "parseopts: telling suricata to use rules file exclusively " . $rules . "\n"; + } + else { + print("parseopts: rules file not specified or doesn't exist\n"); + } + #log dir does it exist if ( $config{l} && -e $config{l} ) { $logdir = $config{l}; @@ -276,6 +287,7 @@ sub printhelp { -r= -n=<(optional) number of iterations or if not specified will run until error> -s=<(optional) path to ids rules file will be passed as -s to suricata> + -S=<(optional) path to ids rules file will be passed as -S to suricata> -e=<(optional) editcap error ratio to introduce if not specified will not fuzz. Valid range for this is 0.00 - 1.0> -p= -l=<(optional) log dir for output if not specified will use current directory.> @@ -426,7 +438,11 @@ sub printhelp { . $fuzzedfile . " -l " . $logdir; if ( defined $rules ) { - $fullcmd = $fullcmd . " -s " . $rules; + if ($rules_exclusive == 1) { + $fullcmd = $fullcmd . " -S " . $rules; + } else { + $fullcmd = $fullcmd . " -s " . $rules; + } } print "suricata: $fullcmd \n"; my $starttime = time(); From 3d0542405dd10cdc7af38ad80db46fcbc21b691f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Nov 2015 13:42:43 +0100 Subject: [PATCH 0954/2553] wirefuzz: enforce -n option per run --- qa/wirefuzz.pl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/qa/wirefuzz.pl b/qa/wirefuzz.pl index 623e0aa10efa..5b407da4b015 100755 --- a/qa/wirefuzz.pl +++ b/qa/wirefuzz.pl @@ -532,6 +532,13 @@ sub printhelp { &clean_logs($fuzzedfilename,$file_was_fuzzed); print "******************Next Packet or Exit *******************\n"; } + + if ($successcnt >= $loopnum) { + last; + } + } + if ($successcnt >= $loopnum) { + last; } } From 7299388d052c87ce5f61f7e662be9947c349d20e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Nov 2015 14:37:10 +0100 Subject: [PATCH 0955/2553] wirefuzz: improve logfile cleanup --- qa/wirefuzz.pl | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/qa/wirefuzz.pl b/qa/wirefuzz.pl index 5b407da4b015..059e5e671947 100755 --- a/qa/wirefuzz.pl +++ b/qa/wirefuzz.pl @@ -599,15 +599,14 @@ sub clean_logs { #system("$rmcmd"); } - if ( unlink(<$logdir . unified*>) > 0 ) { - print "clean_logs: removed unified logs for next run \n"; - } - else { - print "clean_logs: failed to delete unified logs\n:"; + foreach my $file (glob "$logdir/unified2.* $logdir/*.log $logdir/*.json") { + #print $file . "\n"; + if (unlink($file) <= 0) { + print "clean_logs: failed to delete log file $file\n"; + } } - print "******************Log Cleanup Complete**********************\n"; - return; + return; } sub keep_logs { From 048e538828327ceb2e4059206248f08de8da2288 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Nov 2015 17:32:25 +0100 Subject: [PATCH 0956/2553] wirefuzz: add -N option to count complete passes --- qa/wirefuzz.pl | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/qa/wirefuzz.pl b/qa/wirefuzz.pl index 059e5e671947..c24ec6a0e8fd 100755 --- a/qa/wirefuzz.pl +++ b/qa/wirefuzz.pl @@ -64,6 +64,7 @@ my @files; my $suricatabin; my $loopnum; +my $loopnum_per_file = 0; my $rules; my $rules_exclusive = 0; my $logdir; @@ -81,7 +82,7 @@ my $file_was_fuzzed = 0; Getopt::Long::Configure("prefix_pattern=(-|--)"); -GetOptions( \%config, qw(n=s r=s c=s e=s v=s p=s l=s s=s S=s x=s k y z=s h help) ); +GetOptions( \%config, qw(n=s N=s r=s c=s e=s v=s p=s l=s s=s S=s x=s k y z=s h help) ); &parseopts(); @@ -151,16 +152,33 @@ sub parseopts { &printhelp(); } + if ( $config{n} && $config{N} ) { + print "ERROR: can't mix -n and -N\n"; + exit(1); + } + #number of times to loop if ( $config{n} ) { $loopnum = $config{n}; + $loopnum_per_file = 1; + print "parseopts: looping through the pcaps " . $loopnum . " times or until we have an error\n"; + } + else { + $loopnum = "infinity"; + } + + if ( $config{N} ) { + $loopnum = $config{N}; print "parseopts: looping through the pcaps " . $loopnum . " times or until we have an error\n"; } else { - print "parseopts: looping through the pcaps forever or until we have an error\n"; $loopnum = "infinity"; } + if ( $loopnum == "infinity") { + print "parseopts: looping through the pcaps forever or until we have an error\n"; + } + #rules file do we have a path and does it exist if ( $config{s} && -e $config{s} ) { $rules = $config{s}; @@ -286,6 +304,7 @@ sub printhelp { -h or help -r= -n=<(optional) number of iterations or if not specified will run until error> + -N=<(optional) number of iterations of all files in the test set> -s=<(optional) path to ids rules file will be passed as -s to suricata> -S=<(optional) path to ids rules file will be passed as -S to suricata> -e=<(optional) editcap error ratio to introduce if not specified will not fuzz. Valid range for this is 0.00 - 1.0> @@ -473,7 +492,9 @@ sub printhelp { $knownerr = 1; } if ( $knownerr eq 1 ) { - $successcnt++; + if ($loopnum_per_file == 1) { + $successcnt++; + } print "suricata: we have run with success " . $successcnt . " times\n"; if( $keeplogs eq "yes" ) { &keep_logs($fuzzedfilename); @@ -521,7 +542,10 @@ sub printhelp { print "Stream mem counter could not be found in output\n"; } - $successcnt++; + if ($loopnum_per_file == 1) { + $successcnt++; + } + print "suricata: we have run with success " . $successcnt . " times\n"; print "******************Suricata Complete**********************\n"; if( $keeplogs eq "yes" ) { @@ -537,6 +561,9 @@ sub printhelp { last; } } + if ($loopnum_per_file == 0) { + $successcnt++; + } if ($successcnt >= $loopnum) { last; } From 8626eccf58fad65509b048cf3ce7bbe0b1ba5272 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Nov 2015 18:59:34 +0100 Subject: [PATCH 0957/2553] wirefuzz: remove obsolete stream mem check --- qa/wirefuzz.pl | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/qa/wirefuzz.pl b/qa/wirefuzz.pl index c24ec6a0e8fd..22fb5285c5f8 100755 --- a/qa/wirefuzz.pl +++ b/qa/wirefuzz.pl @@ -531,17 +531,6 @@ sub printhelp { exit; } else { - if ( $out =~ /Max memuse of stream engine \d+ \(in use (\d+)\)/ ) { - if ($1 != 0) { - $report = $logdir . $fuzzedfilename . "-OUT.txt"; - &generate_report($report, $fullcmd, $out, $err, $exit, "none"); - print "Stream leak detected " . $1 . " was still in use at exit see " . $report . " for more details\n"; - exit; - } - } else { - print "Stream mem counter could not be found in output\n"; - } - if ($loopnum_per_file == 1) { $successcnt++; } From 9d49b828a66e15d0068423833f0a2106e5be1ae7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 11 Feb 2016 09:46:44 +0100 Subject: [PATCH 0958/2553] wirefuzz: logdir handling improvement --- qa/wirefuzz.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/wirefuzz.pl b/qa/wirefuzz.pl index 22fb5285c5f8..fb1d76d89c58 100755 --- a/qa/wirefuzz.pl +++ b/qa/wirefuzz.pl @@ -200,7 +200,7 @@ sub parseopts { #log dir does it exist if ( $config{l} && -e $config{l} ) { - $logdir = $config{l}; + $logdir = $config{l} . "/"; print "parseopts: using log dir " . $logdir . "\n"; } else { From 1c3a0434ca0d3025dda1c92e57aa7d1af7beb723 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 11 Feb 2016 18:51:15 +0100 Subject: [PATCH 0959/2553] wirefuzz: exit with error code on more issues --- qa/wirefuzz.pl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/qa/wirefuzz.pl b/qa/wirefuzz.pl index fb1d76d89c58..34f0b7d56c9f 100755 --- a/qa/wirefuzz.pl +++ b/qa/wirefuzz.pl @@ -99,7 +99,7 @@ sub parseopts { @tmpfiles = <$config{r}>; if(@tmpfiles eq 0){ print "parseopts: Pcap filemask was invalid we couldn't find any matching files\n"; - exit; + exit(1); } else { #escapes for filenames foreach my $file (@tmpfiles) { @@ -144,7 +144,7 @@ sub parseopts { } else { print "parseopts: suricata bin file is not a text or a bin exiting.\n"; - exit; + exit(1); } } else { @@ -228,7 +228,7 @@ sub parseopts { } else { print "parseopts: error ratio specified but outside of range. Valid range is 0.00-1.0\n"; - exit; + exit(1); } } else { @@ -383,7 +383,7 @@ sub printhelp { #this could still cause us to loop forever if all pcaps are bad but it's better than nothing. if ( @files < 2 ) { print "editcap: had an error and this was our only pcap:" . $editcaperr . "\n"; - exit; + exit(1); } else { print "editcap: had an error going to the next pcap:" . $editcaperr . "\n"; @@ -392,7 +392,7 @@ sub printhelp { } elsif ( $editcap_sys_signal eq 2 ) { print "editcap: system() got a ctl+c we are bailing as well\n"; - exit; + exit(1); } else { @@ -519,7 +519,7 @@ sub printhelp { }else{ &generate_report($report, $fullcmd, $out, $err, $exit, "none"); } - exit; + exit(1); } } elsif ( $suricata_sys_signal eq 2 ) { From 0138bf560594b629ce0ab809c48800e938cf728b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 12 Feb 2016 09:48:05 +0100 Subject: [PATCH 0960/2553] qa: add leak sanitzer suppression --- qa/lsan.suppress | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 qa/lsan.suppress diff --git a/qa/lsan.suppress b/qa/lsan.suppress new file mode 100644 index 000000000000..01f9e9d270fc --- /dev/null +++ b/qa/lsan.suppress @@ -0,0 +1,2 @@ +# a bit heavy handed, but it seems that llvm-symbolizer can't figure out the symbols w/o compiling our own libmagic? +leak:libmagic.so From 6c30f7bdbb476da74186dad11c40b75930ef71e9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Feb 2016 16:45:01 +0100 Subject: [PATCH 0961/2553] counters: fix thread stats delta logging Just like with the global stats, store prev values. Fixes delta logging. --- src/counters.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/counters.c b/src/counters.c index 887fd7ca99d6..05059ef96bf5 100644 --- a/src/counters.c +++ b/src/counters.c @@ -704,6 +704,9 @@ static int StatsOutput(ThreadVars *tv) uint32_t offset = (thread * stats_table.nstats) + c; StatsRecord *r = &stats_table.tstats[offset]; + /* xfer previous value to pvalue and reset value */ + r->pvalue = r->value; + r->value = 0; r->name = table[c].name; r->tm_name = sts->name; From 8bb1cf08efd8ae54bc7d363f350a523709b71c32 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Feb 2016 16:50:48 +0100 Subject: [PATCH 0962/2553] eve: fix mishandling of big messages When the string representation of a JSON message grew bigger than 64k, the JSON record would just be truncated. This lead to errors in the parser(s) of the JSON stream. This patch changes the buffer logic to grow the buffer on demand. --- src/log-stats.c | 4 ++-- src/output-json-alert.c | 7 +++---- src/output-json-dns.c | 16 ++++++---------- src/output-json-drop.c | 5 ++--- src/output-json-file.c | 5 ++--- src/output-json-flow.c | 5 ++--- src/output-json-http.c | 5 ++--- src/output-json-netflow.c | 9 ++++----- src/output-json-smtp.c | 5 ++--- src/output-json-ssh.c | 5 ++--- src/output-json-stats.c | 5 ++--- src/output-json-template.c | 5 ++--- src/output-json-tls.c | 5 ++--- src/output-json.c | 35 +++++++++++++++++++++-------------- src/output-json.h | 2 +- src/util-buffer.h | 2 +- 16 files changed, 56 insertions(+), 64 deletions(-) diff --git a/src/log-stats.c b/src/log-stats.c index 8507deb301c6..ad6ee547208d 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -118,7 +118,7 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) /* since we can have many threads, the buffer might not be big enough. * Expand if necessary. */ - if (MEMBUFFER_OFFSET(aft->buffer) + len > MEMBUFFER_SIZE(aft->buffer)) { + if (MEMBUFFER_OFFSET(aft->buffer) + len >= MEMBUFFER_SIZE(aft->buffer)) { MemBufferExpand(&aft->buffer, OUTPUT_BUFFER_SIZE); } @@ -144,7 +144,7 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) /* since we can have many threads, the buffer might not be big enough. * Expand if necessary. */ - if (MEMBUFFER_OFFSET(aft->buffer) + len > MEMBUFFER_SIZE(aft->buffer)) { + if (MEMBUFFER_OFFSET(aft->buffer) + len >= MEMBUFFER_SIZE(aft->buffer)) { MemBufferExpand(&aft->buffer, OUTPUT_BUFFER_SIZE); } diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 32ec6c849850..f7281f49a41e 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -362,7 +362,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } } - OutputJSONBuffer(js, aft->file_ctx, aft->json_buffer); + OutputJSONBuffer(js, aft->file_ctx, &aft->json_buffer); json_object_del(js, "alert"); } json_object_clear(js); @@ -373,7 +373,6 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) static int AlertJsonDecoderEvent(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) { - MemBuffer *buffer = (MemBuffer *)aft->json_buffer; int i; char timebuf[64]; json_t *js; @@ -384,7 +383,7 @@ static int AlertJsonDecoderEvent(ThreadVars *tv, JsonAlertLogThread *aft, const CreateIsoTimeString(&p->ts, timebuf, sizeof(timebuf)); for (i = 0; i < p->alerts.cnt; i++) { - MemBufferReset(buffer); + MemBufferReset(aft->json_buffer); const PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { @@ -436,7 +435,7 @@ static int AlertJsonDecoderEvent(ThreadVars *tv, JsonAlertLogThread *aft, const /* alert */ json_object_set_new(js, "alert", ajs); - OutputJSONBuffer(js, aft->file_ctx, buffer); + OutputJSONBuffer(js, aft->file_ctx, &aft->json_buffer); json_object_clear(js); json_decref(js); } diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 89c11b3eefaa..c44be89a43ac 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -73,8 +73,6 @@ typedef struct LogDnsLogThread_ { static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uint64_t tx_id, DNSQueryEntry *entry) { - MemBuffer *buffer = (MemBuffer *)aft->buffer; - SCLogDebug("got a DNS request and now logging !!"); json_t *djs = json_object(); @@ -83,7 +81,7 @@ static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, } /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); /* type */ json_object_set_new(djs, "type", json_string("query")); @@ -109,13 +107,12 @@ static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, /* dns */ json_object_set_new(js, "dns", djs); - OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, &aft->buffer); json_object_del(js, "dns"); } static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, DNSAnswerEntry *entry) { - MemBuffer *buffer = (MemBuffer *)aft->buffer; json_t *js = json_object(); if (js == NULL) return; @@ -179,9 +176,9 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, } /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); json_object_set_new(djs, "dns", js); - OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, buffer); + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); json_object_del(djs, "dns"); return; @@ -189,7 +186,6 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, static void OutputFailure(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, DNSQueryEntry *entry) { - MemBuffer *buffer = (MemBuffer *)aft->buffer; json_t *js = json_object(); if (js == NULL) return; @@ -214,9 +210,9 @@ static void OutputFailure(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, } /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); json_object_set_new(djs, "dns", js); - OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, buffer); + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); json_object_del(djs, "dns"); return; diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 68c14d9b5d98..234332c89838 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -85,7 +85,6 @@ typedef struct JsonDropLogThread_ { static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) { uint16_t proto = 0; - MemBuffer *buffer = (MemBuffer *)aft->buffer; json_t *js = CreateJSONHeader((Packet *)p, 0, "drop");//TODO const if (unlikely(js == NULL)) return TM_ECODE_OK; @@ -97,7 +96,7 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) } /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); if (PKT_IS_IPV4(p)) { json_object_set_new(djs, "len", json_integer(IPV4_GET_IPLEN(p))); @@ -168,7 +167,7 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) } } - OutputJSONBuffer(js, aft->drop_ctx->file_ctx, buffer); + OutputJSONBuffer(js, aft->drop_ctx->file_ctx, &aft->buffer); json_object_del(js, "drop"); json_object_clear(js); json_decref(js); diff --git a/src/output-json-file.c b/src/output-json-file.c index c3932cac3c6b..12e416ac7323 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -83,14 +83,13 @@ typedef struct JsonFileLogThread_ { */ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const File *ff) { - MemBuffer *buffer = (MemBuffer *)aft->buffer; json_t *js = CreateJSONHeader((Packet *)p, 0, "fileinfo"); //TODO const json_t *hjs = NULL; if (unlikely(js == NULL)) return; /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); switch (p->flow->alproto) { case ALPROTO_HTTP: @@ -158,7 +157,7 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F /* originally just 'file', but due to bug 1127 naming it fileinfo */ json_object_set_new(js, "fileinfo", fjs); - OutputJSONBuffer(js, aft->filelog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, aft->filelog_ctx->file_ctx, &aft->buffer); json_object_del(js, "fileinfo"); switch (p->flow->alproto) { diff --git a/src/output-json-flow.c b/src/output-json-flow.c index f89c32df7097..372bafa44cfe 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -313,10 +313,9 @@ static int JsonFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) { SCEnter(); JsonFlowLogThread *jhl = (JsonFlowLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)jhl->buffer; /* reset */ - MemBufferReset(buffer); + MemBufferReset(jhl->buffer); json_t *js = CreateJSONHeaderFromFlow(f, "flow"); //TODO const if (unlikely(js == NULL)) @@ -324,7 +323,7 @@ static int JsonFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) JsonFlowLogJSON(jhl, js, f); - OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, &jhl->buffer); json_object_del(js, "http"); json_object_clear(js); diff --git a/src/output-json-http.c b/src/output-json-http.c index 6873987305ce..ddd5dfd68133 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -371,7 +371,6 @@ static int JsonHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl htp_tx_t *tx = txptr; JsonHttpLogThread *jhl = (JsonHttpLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)jhl->buffer; json_t *js = CreateJSONHeaderWithTxId((Packet *)p, 1, "http", tx_id); //TODO const if (unlikely(js == NULL)) @@ -380,11 +379,11 @@ static int JsonHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl SCLogDebug("got a HTTP request and now logging !!"); /* reset */ - MemBufferReset(buffer); + MemBufferReset(jhl->buffer); JsonHttpLogJSON(jhl, js, tx, tx_id); - OutputJSONBuffer(js, jhl->httplog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, jhl->httplog_ctx->file_ctx, &jhl->buffer); json_object_del(js, "http"); json_object_clear(js); diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 1b1fa8c0bdeb..2adb3688946f 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -289,26 +289,25 @@ static int JsonNetFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) { SCEnter(); JsonNetFlowLogThread *jhl = (JsonNetFlowLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)jhl->buffer; /* reset */ - MemBufferReset(buffer); + MemBufferReset(jhl->buffer); json_t *js = CreateJSONHeaderFromFlow(f, "netflow", 0); //TODO const if (unlikely(js == NULL)) return TM_ECODE_OK; JsonNetFlowLogJSONToServer(jhl, js, f); - OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, &jhl->buffer); json_object_del(js, "netflow"); json_object_clear(js); json_decref(js); /* reset */ - MemBufferReset(buffer); + MemBufferReset(jhl->buffer); js = CreateJSONHeaderFromFlow(f, "netflow", 1); //TODO const if (unlikely(js == NULL)) return TM_ECODE_OK; JsonNetFlowLogJSONToClient(jhl, js, f); - OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, &jhl->buffer); json_object_del(js, "netflow"); json_object_clear(js); json_decref(js); diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 617b7247f379..364d4ff4310f 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -87,7 +87,6 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl { SCEnter(); JsonEmailLogThread *jhl = (JsonEmailLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)jhl->buffer; json_t *sjs; json_t *js = CreateJSONHeaderWithTxId((Packet *)p, 1, "smtp", tx_id); @@ -95,7 +94,7 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl return TM_ECODE_OK; /* reset */ - MemBufferReset(buffer); + MemBufferReset(jhl->buffer); sjs = JsonSmtpDataLogger(f, state, tx, tx_id); if (sjs) { @@ -103,7 +102,7 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl } if (JsonEmailLogJson(jhl, js, p, f, state, tx, tx_id) == TM_ECODE_OK) { - OutputJSONBuffer(js, jhl->emaillog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, jhl->emaillog_ctx->file_ctx, &jhl->buffer); } json_object_del(js, "email"); if (sjs) { diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 3dc4d10f843f..55e77a7ead02 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -93,7 +93,6 @@ void JsonSshLogJSON(json_t *tjs, SshState *ssh_state) static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) { JsonSshLogThread *aft = (JsonSshLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)aft->buffer; OutputSshCtx *ssh_ctx = aft->sshlog_ctx; if (unlikely(p->flow == NULL)) { @@ -125,13 +124,13 @@ static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) } /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); JsonSshLogJSON(tjs, ssh_state); json_object_set_new(js, "ssh", tjs); - OutputJSONBuffer(js, ssh_ctx->file_ctx, buffer); + OutputJSONBuffer(js, ssh_ctx->file_ctx, &aft->buffer); json_object_clear(js); json_decref(js); diff --git a/src/output-json-stats.c b/src/output-json-stats.c index a22f9d6b9675..3fd37ad3d0b4 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -95,7 +95,6 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * { SCEnter(); JsonStatsLogThread *aft = (JsonStatsLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)aft->buffer; const char delta_suffix[] = "_delta"; struct timeval tval; @@ -185,8 +184,8 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * json_object_set_new(js, "stats", js_stats); - OutputJSONBuffer(js, aft->statslog_ctx->file_ctx, buffer); - MemBufferReset(buffer); + OutputJSONBuffer(js, aft->statslog_ctx->file_ctx, &aft->buffer); + MemBufferReset(aft->buffer); json_object_clear(js_stats); json_object_del(js, "stats"); diff --git a/src/output-json-template.c b/src/output-json-template.c index d360e6746c77..8a00d88bebe7 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -57,7 +57,6 @@ static int JsonTemplateLogger(ThreadVars *tv, void *thread_data, { TemplateTransaction *templatetx = tx; LogTemplateLogThread *thread = thread_data; - MemBuffer *buffer = thread->buffer; json_t *js, *templatejs; SCLogNotice("Logging template transaction %"PRIu64".", templatetx->tx_id); @@ -91,8 +90,8 @@ static int JsonTemplateLogger(ThreadVars *tv, void *thread_data, json_object_set_new(js, "template", templatejs); - MemBufferReset(buffer); - OutputJSONBuffer(js, thread->templatelog_ctx->file_ctx, buffer); + MemBufferReset(thread->buffer); + OutputJSONBuffer(js, thread->templatelog_ctx->file_ctx, &thread->buffer); json_decref(js); return TM_ECODE_OK; diff --git a/src/output-json-tls.c b/src/output-json-tls.c index d8b8078f976b..3cedfd203a6f 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -129,7 +129,6 @@ void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) { JsonTlsLogThread *aft = (JsonTlsLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)aft->buffer; OutputTlsCtx *tls_ctx = aft->tlslog_ctx; if (unlikely(p->flow == NULL)) { @@ -161,7 +160,7 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) } /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); JsonTlsLogJSONBasic(tjs, ssl_state); @@ -171,7 +170,7 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) json_object_set_new(js, "tls", tjs); - OutputJSONBuffer(js, tls_ctx->file_ctx, buffer); + OutputJSONBuffer(js, tls_ctx->file_ctx, &aft->buffer); json_object_clear(js); json_decref(js); diff --git a/src/output-json.c b/src/output-json.c index b9c2b886e637..7661725d5232 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -117,7 +117,7 @@ void OutputJsonRegisterTests (void) #define DEFAULT_ALERT_SYSLOG_LEVEL LOG_INFO #define MODULE_NAME "OutputJSON" -#define OUTPUT_BUFFER_SIZE 65535 +#define OUTPUT_BUFFER_SIZE 65536 TmEcode OutputJson (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode OutputJsonThreadInit(ThreadVars *, void *, void **); @@ -335,31 +335,38 @@ json_t *CreateJSONHeaderWithTxId(Packet *p, int direction_sensitive, char *event return js; } +/* helper struct for the callback */ +typedef struct MemBufferWrapper_ { + MemBuffer **buffer; +} MemBufferWrapper; + static int MemBufferCallback(const char *str, size_t size, void *data) { - MemBuffer *memb = data; -#if 0 // can't expand, need a MemBuffer ** - /* since we can have many threads, the buffer might not be big enough. - * * Expand if necessary. */ - if (MEMBUFFER_OFFSET(memb) + size > MEMBUFFER_SIZE(memb)) { - MemBufferExpand(&memb, OUTPUT_BUFFER_SIZE); + MemBufferWrapper *wrapper = data; + MemBuffer **memb = wrapper->buffer; + + if (MEMBUFFER_OFFSET(*memb) + size >= MEMBUFFER_SIZE(*memb)) { + MemBufferExpand(memb, OUTPUT_BUFFER_SIZE); } -#endif - MemBufferWriteRaw(memb, str, size); + + MemBufferWriteRaw((*memb), str, size); return 0; } -int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) +int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer) { if (file_ctx->sensor_name) { json_object_set_new(js, "host", json_string(file_ctx->sensor_name)); } - if (file_ctx->prefix) - MemBufferWriteRaw(buffer, file_ctx->prefix, file_ctx->prefix_len); + if (file_ctx->prefix) { + MemBufferWriteRaw((*buffer), file_ctx->prefix, file_ctx->prefix_len); + } + + MemBufferWrapper wrapper = { .buffer = buffer }; - int r = json_dump_callback(js, MemBufferCallback, buffer, + int r = json_dump_callback(js, MemBufferCallback, &wrapper, JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| #ifdef JSON_ESCAPE_SLASH JSON_ESCAPE_SLASH @@ -370,7 +377,7 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) if (r != 0) return TM_ECODE_OK; - LogFileWrite(file_ctx, buffer); + LogFileWrite(file_ctx, *buffer); return 0; } diff --git a/src/output-json.h b/src/output-json.h index b6aec6c05fe3..752f14992da0 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -38,7 +38,7 @@ void JsonTcpFlags(uint8_t flags, json_t *js); json_t *CreateJSONHeader(Packet *p, int direction_sensative, char *event_type); json_t *CreateJSONHeaderWithTxId(Packet *p, int direction_sensitive, char *event_type, uint32_t tx_id); TmEcode OutputJSON(json_t *js, void *data, uint64_t *count); -int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer); +int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer); OutputCtx *OutputJsonInitCtx(ConfNode *); enum JsonFormat { COMPACT, INDENT }; diff --git a/src/util-buffer.h b/src/util-buffer.h index 58d5098a2820..cc7616ccfb6d 100644 --- a/src/util-buffer.h +++ b/src/util-buffer.h @@ -135,7 +135,7 @@ void MemBufferFree(MemBuffer *buffer); \ if (((raw_buffer_len) >= (dst)->size - (dst)->offset)) { \ SCLogDebug("Truncating data write since it exceeded buffer limit of " \ - "- %"PRIu32"\n", (dst)->size); \ + "- %"PRIu32, (dst)->size); \ write_len = ((dst)->size - (dst)->offset) - 1; \ } else { \ write_len = (raw_buffer_len); \ From 9015fb5a7f8f2bb1981dd5caa70904641c339341 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Feb 2016 17:42:38 +0100 Subject: [PATCH 0963/2553] travis: set CFLAGS to error on cc warnings --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 8ae46e34c4d5..7fbbedd11580 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: c +env: + - CFLAGS="-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function" compiler: - gcc - clang From 5f3972850996873fed821bb53368d57f59ab3812 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Feb 2016 22:23:16 +0100 Subject: [PATCH 0964/2553] ssh: fix string handling in unittest --- src/app-layer-ssh.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index 879c77466557..bbebcf698347 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -2109,13 +2109,13 @@ static int SSHParserTest19(void) goto end; } - char *name = SCMalloc(256); + char *name = SCCalloc(1, 256); if (name == NULL) goto end; - memset(name, 0x00, 256); - strlcpy(name, (char *)sshbuf3, strlen((char *)sshbuf3) - 1); + strlcpy(name, (char *)sshbuf3, 256); + name[strlen(name) - 1] = '\0'; // strip \r - if (strncmp((char*)ssh_state->srv_hdr.software_version, name, strlen(name)) != 0) { + if (strcmp((char*)ssh_state->srv_hdr.software_version, name) != 0) { printf("Client version string not parsed correctly: "); goto end; } From 3d2834a232df34af3edbb2c4e8be3eb23e9ac6f7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 11 Feb 2016 14:45:23 -0600 Subject: [PATCH 0965/2553] json: use top-level sensor-name if provided. Currently the default configuration file contains a "sensor-name" at the root of the configuration file, however, eve-log will only use it if its specified under eve-log. Now we will look for it at the eve-log, if present we'll use it but log a deprecation warning, if its not present we'll look for sensor-name at the root of the configuration. --- src/output-json.c | 10 ++++++++++ src/util-error.c | 1 + src/util-error.h | 1 + 3 files changed, 12 insertions(+) diff --git a/src/output-json.c b/src/output-json.c index 7661725d5232..3a24fcecfb18 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -435,7 +435,17 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) { OutputJsonCtx *json_ctx = SCCalloc(1, sizeof(OutputJsonCtx));; + /* First lookup a sensor-name value in this outputs configuration + * node (deprecated). If that fails, lookup the global one. */ const char *sensor_name = ConfNodeLookupChildValue(conf, "sensor-name"); + if (sensor_name != NULL) { + SCLogWarning(SC_ERR_DEPRECATED_CONF, + "Found deprecated eve-log setting \"sensor-name\". " + "Please set sensor-name globally."); + } + else { + ConfGet("sensor-name", (char **)&sensor_name); + } if (unlikely(json_ctx == NULL)) { SCLogDebug("AlertJsonInitCtx: Could not create new LogFileCtx"); diff --git a/src/util-error.c b/src/util-error.c index 8ea229b5988d..5b03c5ad15f8 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -314,6 +314,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_INVALID_RULE_ARGUMENT); CASE_CODE (SC_ERR_STATS_LOG_NEGATED); CASE_CODE (SC_ERR_JSON_STATS_LOG_NEGATED); + CASE_CODE (SC_ERR_DEPRECATED_CONF); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index fec09d04a7bf..0dcfb674d1fa 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -304,6 +304,7 @@ typedef enum { SC_ERR_MT_NO_MAPPING, SC_ERR_STATS_LOG_NEGATED, /** When totals and threads are both NO in yaml **/ SC_ERR_JSON_STATS_LOG_NEGATED, /** When totals and threads are both NO in yaml **/ + SC_ERR_DEPRECATED_CONF, /**< Deprecated configuration parameter. */ } SCError; const char *SCErrorToString(SCError); From 09fe1c62d8d394dc2d839370c550a9851fe22119 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 16 Feb 2016 22:55:28 +0100 Subject: [PATCH 0966/2553] detect-tls-version: fix small resource leak --- src/detect-tls-version.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index 51547260cc6b..26fb7405408b 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -201,6 +201,7 @@ DetectTlsVersionData *DetectTlsVersionParse (char *str) temp = TLS_VERSION_12; } else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid value"); + SCFree(orig); goto error; } From 8f059b2841770791a12d26d74de2fb9c326bd609 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Thu, 18 Feb 2016 14:24:26 -0800 Subject: [PATCH 0967/2553] output-json-dns: add logging of NS answer record content. --- src/output-json-dns.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/output-json-dns.c b/src/output-json-dns.c index c44be89a43ac..7165d80e136b 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -161,7 +161,8 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, } else if (entry->data_len == 0) { json_object_set_new(js, "rdata", json_string("")); } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME || - entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR) { + entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR || + entry->type == DNS_RECORD_TYPE_NS) { if (entry->data_len != 0) { char buffer[256] = ""; uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ? From 72c9debbd67698d835884de9cb863a5b814c2071 Mon Sep 17 00:00:00 2001 From: Travis Green Date: Wed, 10 Feb 2016 10:18:29 -0700 Subject: [PATCH 0968/2553] yaml: disable rules by default Change to "disable by default" rulefiles --- suricata.yaml.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 1f35e130727c..1f8a359cb99b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1131,7 +1131,7 @@ rule-files: - compromised.rules - drop.rules - dshield.rules - - emerging-activex.rules +# - emerging-activex.rules - emerging-attack_response.rules - emerging-chat.rules - emerging-current_events.rules @@ -1139,11 +1139,11 @@ rule-files: - emerging-dos.rules - emerging-exploit.rules - emerging-ftp.rules - - emerging-games.rules - - emerging-icmp_info.rules +# - emerging-games.rules +# - emerging-icmp_info.rules # - emerging-icmp.rules - emerging-imap.rules - - emerging-inappropriate.rules +# - emerging-inappropriate.rules - emerging-malware.rules - emerging-misc.rules - emerging-mobile_malware.rules @@ -1154,7 +1154,7 @@ rule-files: - emerging-rpc.rules - emerging-scada.rules - emerging-scan.rules - - emerging-shellcode.rules +# - emerging-shellcode.rules - emerging-smtp.rules - emerging-snmp.rules - emerging-sql.rules @@ -1165,7 +1165,7 @@ rule-files: - emerging-voip.rules - emerging-web_client.rules - emerging-web_server.rules - - emerging-web_specific_apps.rules +# - emerging-web_specific_apps.rules - emerging-worm.rules - tor.rules - decoder-events.rules # available in suricata sources under rules dir From 8c0e57506347357258ee53cb195d6aed39882e85 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 21 Feb 2016 21:54:32 +0100 Subject: [PATCH 0969/2553] configure: warn if libpcre 8.35 is used --- configure.ac | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/configure.ac b/configure.ac index 79578fb31058..ae085d87d20a 100644 --- a/configure.ac +++ b/configure.ac @@ -479,6 +479,19 @@ exit 1 fi + # libpcre 8.35 (especially on debian) has a known issue that results in segfaults + # see https://redmine.openinfosecfoundation.org/issues/1693 + PKG_CHECK_MODULES(LIBPCREVERSION, [libpcre = 8.35],[libpcre_buggy_found="yes"],[libprce_buggy_found="no"]) + if test "$libpcre_buggy_found" = "yes"; then + echo + echo " Warning! libpcre version 8.35 found" + echo " This version has a known issue that could result in segfaults" + echo " please upgrade to a newer version of pcre which you can get from" + echo " www.pcre.org." + echo " Continuing for now...." + echo + fi + # To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work # see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful PCRE="" From c446abeb471d8be516bf11f0106797526b7122b3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Feb 2016 11:58:07 +0100 Subject: [PATCH 0970/2553] jansson: include in suricata-common.h --- src/counters.h | 3 +-- src/output-json-alert.c | 1 - src/output-json-alert.h | 1 - src/output-json-dns.c | 1 - src/output-json-drop.c | 1 - src/output-json-email-common.c | 1 - src/output-json-file.c | 1 - src/output-json-flow.c | 1 - src/output-json-http.c | 1 - src/output-json-http.h | 1 - src/output-json-netflow.c | 1 - src/output-json-smtp.c | 1 - src/output-json-smtp.h | 1 - src/output-json-ssh.c | 1 - src/output-json-ssh.h | 1 - src/output-json-stats.c | 1 - src/output-json-template.c | 1 - src/output-json-tls.c | 1 - src/output-json-tls.h | 1 - src/output-json.c | 2 -- src/output-json.h | 9 ++++----- src/suricata-common.h | 4 ++++ 22 files changed, 9 insertions(+), 27 deletions(-) diff --git a/src/counters.h b/src/counters.h index 023d15aac738..39fa0bc7f03f 100644 --- a/src/counters.h +++ b/src/counters.h @@ -141,9 +141,8 @@ void StatsThreadCleanup(struct ThreadVars_ *); } while (0) #ifdef BUILD_UNIX_SOCKET -#include TmEcode StatsOutputCounterSocket(json_t *cmd, - json_t *answer, void *data); + json_t *answer, void *data); #endif #endif /* __COUNTERS_H__ */ diff --git a/src/output-json-alert.c b/src/output-json-alert.c index f7281f49a41e..8d09ed759b52 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -69,7 +69,6 @@ #define MODULE_NAME "JsonAlertLog" #ifdef HAVE_LIBJANSSON -#include #define LOG_JSON_PAYLOAD 1 #define LOG_JSON_PACKET 2 diff --git a/src/output-json-alert.h b/src/output-json-alert.h index c981574f90dd..a10a316d20b3 100644 --- a/src/output-json-alert.h +++ b/src/output-json-alert.h @@ -29,7 +29,6 @@ void TmModuleJsonAlertLogRegister (void); #ifdef HAVE_LIBJANSSON -#include void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js); #endif /* HAVE_LIBJANSSON */ diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 7165d80e136b..288142cd1191 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -51,7 +51,6 @@ #include "output-json.h" #ifdef HAVE_LIBJANSSON -#include /* we can do query logging as well, but it's disabled for now as the * TX id handling doesn't expect it */ diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 234332c89838..f82c9c00db3d 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -59,7 +59,6 @@ #define MODULE_NAME "JsonDropLog" #ifdef HAVE_LIBJANSSON -#include #define LOG_DROP_ALERTS 1 diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 88cd3acf4b2c..f91f7f307388 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -54,7 +54,6 @@ #include "output-json-email-common.h" #ifdef HAVE_LIBJANSSON -#include #define LOG_EMAIL_DEFAULT 0 #define LOG_EMAIL_EXTENDED (1<<0) diff --git a/src/output-json-file.c b/src/output-json-file.c index 12e416ac7323..0e1db3746505 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -65,7 +65,6 @@ #include "stream-tcp-reassemble.h" #ifdef HAVE_LIBJANSSON -#include typedef struct OutputFileCtx_ { LogFileCtx *file_ctx; diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 372bafa44cfe..b59cf4f63b46 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -49,7 +49,6 @@ #include "stream-tcp-private.h" #ifdef HAVE_LIBJANSSON -#include typedef struct LogJsonFileCtx_ { LogFileCtx *file_ctx; diff --git a/src/output-json-http.c b/src/output-json-http.c index ddd5dfd68133..7e17b4dd600e 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -50,7 +50,6 @@ #include "output-json.h" #ifdef HAVE_LIBJANSSON -#include typedef struct LogHttpFileCtx_ { LogFileCtx *file_ctx; diff --git a/src/output-json-http.h b/src/output-json-http.h index bcaa57aa9476..0c886f3dd56d 100644 --- a/src/output-json-http.h +++ b/src/output-json-http.h @@ -27,7 +27,6 @@ void TmModuleJsonHttpLogRegister (void); #ifdef HAVE_LIBJANSSON -#include void JsonHttpLogJSONBasic(json_t *js, htp_tx_t *tx); void JsonHttpLogJSONExtended(json_t *js, htp_tx_t *tx); json_t *JsonHttpAddMetadata(const Flow *f, uint64_t tx_id); diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 2adb3688946f..a55bc8cf4eaf 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -49,7 +49,6 @@ #include "stream-tcp-private.h" #ifdef HAVE_LIBJANSSON -#include typedef struct LogJsonFileCtx_ { LogFileCtx *file_ctx; diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 364d4ff4310f..b4b0bfdda01b 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -52,7 +52,6 @@ #include "output-json-email-common.h" #ifdef HAVE_LIBJANSSON -#include static json_t *JsonSmtpDataLogger(const Flow *f, void *state, void *vtx, uint64_t tx_id) { diff --git a/src/output-json-smtp.h b/src/output-json-smtp.h index 0c60f2d4891a..2f79d992011a 100644 --- a/src/output-json-smtp.h +++ b/src/output-json-smtp.h @@ -26,7 +26,6 @@ void TmModuleJsonSmtpLogRegister (void); #ifdef HAVE_LIBJANSSON -#include json_t *JsonSMTPAddMetadata(const Flow *f, uint64_t tx_id); #endif diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 55e77a7ead02..4a5542a9a12e 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -50,7 +50,6 @@ #include "output-json.h" #ifdef HAVE_LIBJANSSON -#include #define MODULE_NAME "LogSshLog" diff --git a/src/output-json-ssh.h b/src/output-json-ssh.h index 28667ca70ea8..5d0752bf2a53 100644 --- a/src/output-json-ssh.h +++ b/src/output-json-ssh.h @@ -28,7 +28,6 @@ void TmModuleJsonSshLogRegister (void); #ifdef HAVE_LIBJANSSON #include "app-layer-ssh.h" -#include void JsonSshLogJSON(json_t *js, SshState *tx); #endif diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 3fd37ad3d0b4..f17593235d5e 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -49,7 +49,6 @@ #define MODULE_NAME "JsonStatsLog" #ifdef HAVE_LIBJANSSON -#include #define JSON_STATS_TOTALS (1<<0) #define JSON_STATS_THREADS (1<<1) diff --git a/src/output-json-template.c b/src/output-json-template.c index 8a00d88bebe7..15bea7c51371 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -39,7 +39,6 @@ #include "app-layer-template.h" #ifdef HAVE_LIBJANSSON -#include typedef struct LogTemplateFileCtx_ { LogFileCtx *file_ctx; diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 3cedfd203a6f..cd88f1e58007 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -50,7 +50,6 @@ #include "output-json.h" #ifdef HAVE_LIBJANSSON -#include SC_ATOMIC_DECLARE(unsigned int, cert_id); diff --git a/src/output-json-tls.h b/src/output-json-tls.h index d9d1142b93f6..f330ad898aad 100644 --- a/src/output-json-tls.h +++ b/src/output-json-tls.h @@ -28,7 +28,6 @@ void TmModuleJsonTlsLogRegister (void); #ifdef HAVE_LIBJANSSON #include "app-layer-ssl.h" -#include void JsonTlsLogJSONBasic(json_t *js, SSLState *ssl_state); void JsonTlsLogJSONExtended(json_t *js, SSLState *ssl_state); diff --git a/src/output-json.c b/src/output-json.c index 3a24fcecfb18..5e048fe4e7b9 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -109,8 +109,6 @@ void OutputJsonRegisterTests (void) #else /* implied we do have JSON support */ -#include - #define DEFAULT_LOG_FILENAME "eve.json" #define DEFAULT_ALERT_SYSLOG_FACILITY_STR "local0" #define DEFAULT_ALERT_SYSLOG_FACILITY LOG_LOCAL0 diff --git a/src/output-json.h b/src/output-json.h index 752f14992da0..edfae8920129 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -24,15 +24,14 @@ #ifndef __OUTPUT_JSON_H__ #define __OUTPUT_JSON_H__ -void TmModuleOutputJsonRegister (void); - -#ifdef HAVE_LIBJANSSON - -#include #include "suricata-common.h" #include "util-buffer.h" #include "util-logopenfile.h" +void TmModuleOutputJsonRegister (void); + +#ifdef HAVE_LIBJANSSON + void CreateJSONFlowId(json_t *js, const Flow *f); void JsonTcpFlags(uint8_t flags, json_t *js); json_t *CreateJSONHeader(Packet *p, int direction_sensative, char *event_type); diff --git a/src/suricata-common.h b/src/suricata-common.h index 4d60f7878183..df3ef79bee88 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -210,6 +210,10 @@ #endif #endif /* !__CYGWIN__ */ +#ifdef HAVE_LIBJANSSON +#include +#endif + #if CPPCHECK==1 #define BUG_ON(x) if (((x))) exit(1) #else From ffdfb6a8f0151fb778ccb56a506936bc2ccf69c6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Feb 2016 20:19:20 +0100 Subject: [PATCH 0971/2553] json-stats: split out json generation Split out JSON generation logic so the code becomes reusable. --- src/output-json-stats.c | 57 ++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/src/output-json-stats.c b/src/output-json-stats.c index f17593235d5e..68701dd9d95f 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -90,28 +90,18 @@ static json_t *OutputStats2Json(json_t *js, const char *key) return value; } -static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) +/** \brief turn StatsTable into a json object + * \param flags JSON_STATS_* flags for controlling output + */ +json_t *StatsToJSON(const StatsTable *st, uint8_t flags) { - SCEnter(); - JsonStatsLogThread *aft = (JsonStatsLogThread *)thread_data; const char delta_suffix[] = "_delta"; - struct timeval tval; gettimeofday(&tval, NULL); - json_t *js = json_object(); - if (unlikely(js == NULL)) - return 0; - - char timebuf[64]; - CreateIsoTimeString(&tval, timebuf, sizeof(timebuf)); - json_object_set_new(js, "timestamp", json_string(timebuf)); - - json_object_set_new(js, "event_type", json_string("stats")); json_t *js_stats = json_object(); if (unlikely(js_stats == NULL)) { - json_decref(js); - return 0; + return NULL; } /* Uptime, in seconds. */ @@ -119,7 +109,7 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * json_integer((int)difftime(tval.tv_sec, st->start_time))); uint32_t u = 0; - if (aft->statslog_ctx->flags & JSON_STATS_TOTALS) { + if (flags & JSON_STATS_TOTALS) { for (u = 0; u < st->nstats; u++) { if (st->stats[u].name == NULL) continue; @@ -132,7 +122,8 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * if (js_type != NULL) { json_object_set_new(js_type, shortname, json_integer(st->stats[u].value)); - if (aft->statslog_ctx->flags & JSON_STATS_DELTAS) { + + if (flags & JSON_STATS_DELTAS) { char deltaname[strlen(shortname) + strlen(delta_suffix) + 1]; snprintf(deltaname, sizeof(deltaname), "%s%s", shortname, delta_suffix); @@ -144,12 +135,12 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * } /* per thread stats - stored in a "threads" object. */ - if (st->tstats != NULL && (aft->statslog_ctx->flags & JSON_STATS_THREADS)) { + if (st->tstats != NULL && (flags & JSON_STATS_THREADS)) { /* for each thread (store) */ json_t *threads = json_object(); if (unlikely(threads == NULL)) { - json_decref(js); - return 0; + json_decref(js_stats); + return NULL; } uint32_t x; for (x = 0; x < st->ntstats; x++) { @@ -168,7 +159,7 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * if (js_type != NULL) { json_object_set_new(js_type, shortname, json_integer(st->tstats[u].value)); - if (aft->statslog_ctx->flags & JSON_STATS_DELTAS) { + if (flags & JSON_STATS_DELTAS) { char deltaname[strlen(shortname) + strlen(delta_suffix) + 1]; snprintf(deltaname, sizeof(deltaname), "%s%s", shortname, delta_suffix); @@ -180,6 +171,30 @@ static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable * } json_object_set_new(js_stats, "threads", threads); } + return js_stats; +} + +static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) +{ + SCEnter(); + JsonStatsLogThread *aft = (JsonStatsLogThread *)thread_data; + + struct timeval tval; + gettimeofday(&tval, NULL); + + json_t *js = json_object(); + if (unlikely(js == NULL)) + return 0; + char timebuf[64]; + CreateIsoTimeString(&tval, timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); + json_object_set_new(js, "event_type", json_string("stats")); + + json_t *js_stats = StatsToJSON(st, aft->statslog_ctx->flags); + if (js_stats == NULL) { + json_decref(js); + return 0; + } json_object_set_new(js, "stats", js_stats); From 310e8fcbf8df6a57f159c1c86f70bfa1ecd8e220 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Feb 2016 20:25:47 +0100 Subject: [PATCH 0972/2553] stats: export StatsToJSON --- src/output-json-stats.c | 4 ---- src/output-json-stats.h | 9 +++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 68701dd9d95f..a94a5996ae93 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -50,10 +50,6 @@ #ifdef HAVE_LIBJANSSON -#define JSON_STATS_TOTALS (1<<0) -#define JSON_STATS_THREADS (1<<1) -#define JSON_STATS_DELTAS (1<<2) - typedef struct OutputStatsCtx_ { LogFileCtx *file_ctx; uint32_t flags; /** Store mode */ diff --git a/src/output-json-stats.h b/src/output-json-stats.h index 9ad1d9b8164a..ab1e6b55c014 100644 --- a/src/output-json-stats.h +++ b/src/output-json-stats.h @@ -24,6 +24,15 @@ #ifndef __OUTPUT_JSON_COUNTERS_H__ #define __OUTPUT_JSON_COUNTERS_H__ +#include "output-stats.h" + +#define JSON_STATS_TOTALS (1<<0) +#define JSON_STATS_THREADS (1<<1) +#define JSON_STATS_DELTAS (1<<2) + +#ifdef HAVE_LIBJANSSON +json_t *StatsToJSON(const StatsTable *st, uint8_t flags); +#endif void TmModuleJsonStatsLogRegister (void); #endif /* __OUTPUT_JSON_COUNTERS_H__ */ From 14030239f8907e0da991af1e9558533c5c3d3900 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Feb 2016 20:45:09 +0100 Subject: [PATCH 0973/2553] unix-socket: restore dump-counters functionality Create a eve.stats like output for dump-counters. --- src/counters.c | 28 +++++++++++++++++++++++----- src/output-json-stats.c | 1 + 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/counters.c b/src/counters.c index 05059ef96bf5..e7af0b4b044f 100644 --- a/src/counters.c +++ b/src/counters.c @@ -36,7 +36,10 @@ #include "util-privs.h" #include "util-signal.h" #include "unix-manager.h" + #include "output.h" +#include "output-stats.h" +#include "output-json-stats.h" /* Time interval for syncing the local counters with the global ones */ #define STATS_WUT_TTS 3 @@ -101,6 +104,7 @@ void StatsReleaseCounters(StatsCounter *head); /** stats table is filled each interval and passed to the * loggers. Initialized at first use. */ static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}}; +static SCMutex stats_table_mutex = SCMUTEX_INITIALIZER; static uint16_t counters_global_id = 0; @@ -280,6 +284,7 @@ static void StatsReleaseCtx() SCFree(stats_ctx); stats_ctx = NULL; + SCMutexLock(&stats_table_mutex); /* free stats table */ if (stats_table.tstats != NULL) { SCFree(stats_table.tstats); @@ -291,6 +296,7 @@ static void StatsReleaseCtx() stats_table.stats = NULL; } memset(&stats_table, 0, sizeof(stats_table)); + SCMutexUnlock(&stats_table_mutex); return; } @@ -359,7 +365,9 @@ static void *StatsMgmtThread(void *arg) SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time); SCCtrlMutexUnlock(tv_local->ctrl_mutex); + SCMutexLock(&stats_table_mutex); StatsOutput(tv_local); + SCMutexUnlock(&stats_table_mutex); if (TmThreadsCheckFlag(tv_local, THV_KILL)) { run = 0; @@ -757,15 +765,25 @@ static int StatsOutput(ThreadVars *tv) } #ifdef BUILD_UNIX_SOCKET -/** - * \todo reimplement this, probably based on stats-json +/** \brief callback for getting stats into unix socket */ TmEcode StatsOutputCounterSocket(json_t *cmd, json_t *answer, void *data) { - json_object_set_new(answer, "message", - json_string("not implemented")); - return TM_ECODE_FAILED; + json_t *message = NULL; + TmEcode r = TM_ECODE_OK; + + SCMutexLock(&stats_table_mutex); + if (stats_table.start_time == 0) { + r = TM_ECODE_FAILED; + message = json_string("stats not yet synchronized"); + } else { + message = StatsToJSON(&stats_table, JSON_STATS_TOTALS|JSON_STATS_THREADS); + } + SCMutexUnlock(&stats_table_mutex); + + json_object_set_new(answer, "message", message); + return r; } #endif /* BUILD_UNIX_SOCKET */ diff --git a/src/output-json-stats.c b/src/output-json-stats.c index a94a5996ae93..1cc5521cc361 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -45,6 +45,7 @@ #include "util-crypt.h" #include "output-json.h" +#include "output-json-stats.h" #define MODULE_NAME "JsonStatsLog" From acaf8a84e89293fa9d26d1c68406ab9643abc673 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Feb 2016 22:33:54 +0100 Subject: [PATCH 0974/2553] stats: fix dump-counters when no loggers are active --- src/counters.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/counters.c b/src/counters.c index e7af0b4b044f..18f1093b3939 100644 --- a/src/counters.c +++ b/src/counters.c @@ -105,6 +105,7 @@ void StatsReleaseCounters(StatsCounter *head); * loggers. Initialized at first use. */ static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}}; static SCMutex stats_table_mutex = SCMUTEX_INITIALIZER; +static int stats_loggers_active = 1; static uint16_t counters_global_id = 0; @@ -234,9 +235,18 @@ static void StatsInitCtx(void) } if (!OutputStatsLoggersRegistered()) { - SCLogWarning(SC_WARN_NO_STATS_LOGGERS, "stats are enabled but no loggers are active"); - stats_enabled = FALSE; - SCReturn; + stats_loggers_active = 0; + + /* if the unix command socket is enabled we do the background + * stats sync just in case someone runs 'dump-counters' */ + int unix_socket = 0; + if (ConfGetBool("unix-command.enabled", &unix_socket) != 1) + unix_socket = 0; + if (unix_socket == 0) { + SCLogWarning(SC_WARN_NO_STATS_LOGGERS, "stats are enabled but no loggers are active"); + stats_enabled = FALSE; + SCReturn; + } } /* Store the engine start time */ @@ -760,7 +770,9 @@ static int StatsOutput(ThreadVars *tv) } /* invoke logger(s) */ - OutputStatsLog(tv, td, &stats_table); + if (stats_loggers_active) { + OutputStatsLog(tv, td, &stats_table); + } return 1; } From 40cf1f8ef73cd8688e53a5c44265aaced7dce271 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Feb 2016 10:36:20 +0100 Subject: [PATCH 0975/2553] json: make membuffer helper public Make json_t to MemBuffer helper public so it can reused. --- src/output-json.c | 18 ++++++++---------- src/output-json.h | 7 +++++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index 5e048fe4e7b9..69e5c577e0d4 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -333,18 +333,13 @@ json_t *CreateJSONHeaderWithTxId(Packet *p, int direction_sensitive, char *event return js; } -/* helper struct for the callback */ -typedef struct MemBufferWrapper_ { - MemBuffer **buffer; -} MemBufferWrapper; - -static int MemBufferCallback(const char *str, size_t size, void *data) +int OutputJSONMemBufferCallback(const char *str, size_t size, void *data) { - MemBufferWrapper *wrapper = data; + OutputJSONMemBufferWrapper *wrapper = data; MemBuffer **memb = wrapper->buffer; if (MEMBUFFER_OFFSET(*memb) + size >= MEMBUFFER_SIZE(*memb)) { - MemBufferExpand(memb, OUTPUT_BUFFER_SIZE); + MemBufferExpand(memb, wrapper->expand_by); } MemBufferWriteRaw((*memb), str, size); @@ -362,9 +357,12 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer) MemBufferWriteRaw((*buffer), file_ctx->prefix, file_ctx->prefix_len); } - MemBufferWrapper wrapper = { .buffer = buffer }; + OutputJSONMemBufferWrapper wrapper = { + .buffer = buffer, + .expand_by = OUTPUT_BUFFER_SIZE + }; - int r = json_dump_callback(js, MemBufferCallback, &wrapper, + int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| #ifdef JSON_ESCAPE_SLASH JSON_ESCAPE_SLASH diff --git a/src/output-json.h b/src/output-json.h index edfae8920129..d6b16fd64114 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -31,6 +31,13 @@ void TmModuleOutputJsonRegister (void); #ifdef HAVE_LIBJANSSON +/* helper struct for OutputJSONMemBufferCallback */ +typedef struct OutputJSONMemBufferWrapper_ { + MemBuffer **buffer; /**< buffer to use & expand as needed */ + size_t expand_by; /**< expand by this size */ +} OutputJSONMemBufferWrapper; + +int OutputJSONMemBufferCallback(const char *str, size_t size, void *data); void CreateJSONFlowId(json_t *js, const Flow *f); void JsonTcpFlags(uint8_t flags, json_t *js); From 654829f9697cdf0030b3ffaa25cdce9fd8803f08 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Feb 2016 10:44:14 +0100 Subject: [PATCH 0976/2553] unix-socket: optimize response sends Instead of sending responses to clients in small chunks, send it in one big chunk. For this the JSON message is first serialized into a MemBuffer before sending. --- src/unix-manager.c | 97 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 22 deletions(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index c03c20ae7098..414d99f7f986 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -33,6 +33,8 @@ #include "util-debug.h" #include "util-signal.h" +#include "util-buffer.h" + #include #include #include @@ -40,6 +42,8 @@ #ifdef BUILD_UNIX_SOCKET #include +#include "output-json.h" + // MSG_NOSIGNAL does not exists on OS X #ifdef OS_DARWIN # ifndef MSG_NOSIGNAL @@ -65,8 +69,10 @@ typedef struct Task_ { TAILQ_ENTRY(Task_) next; } Task; +#define CLIENT_BUFFER_SIZE 4096 typedef struct UnixClient_ { int fd; + MemBuffer *mbuf; /**< buffer for response construction */ TAILQ_ENTRY(UnixClient_) next; } UnixClient; @@ -219,6 +225,30 @@ void UnixCommandSetMaxFD(UnixCommand *this) } } +static UnixClient *UnixClientAlloc(void) +{ + UnixClient *uclient = SCMalloc(sizeof(UnixClient)); + if (unlikely(uclient == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client"); + return NULL; + } + uclient->mbuf = MemBufferCreateNew(CLIENT_BUFFER_SIZE); + if (uclient->mbuf == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client send buffer"); + SCFree(uclient); + return NULL; + } + return uclient; +} + +static void UnixClientFree(UnixClient *c) +{ + if (c != NULL) { + MemBufferFree(c->mbuf); + SCFree(c); + } +} + /** * \brief Close the unix socket */ @@ -243,27 +273,48 @@ void UnixCommandClose(UnixCommand *this, int fd) close(item->fd); UnixCommandSetMaxFD(this); - SCFree(item); + UnixClientFree(item); } -/** - * \brief Callback function used to send message to socket - */ -int UnixCommandSendCallback(const char *buffer, size_t size, void *data) +#define UNIX_PROTO_VERSION_LENGTH 200 +#define UNIX_PROTO_VERSION "0.1" + +int UnixCommandSendJSONToClient(UnixClient *client, json_t *js) { - int fd = *(int *) data; + MemBufferReset(client->mbuf); + + OutputJSONMemBufferWrapper wrapper = { + .buffer = &client->mbuf, + .expand_by = CLIENT_BUFFER_SIZE + }; - if (send(fd, buffer, size, MSG_NOSIGNAL) == -1) { - SCLogInfo("Unable to send block: %s", strerror(errno)); + int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| +#ifdef JSON_ESCAPE_SLASH + JSON_ESCAPE_SLASH +#else + 0 +#endif + ); + if (r != 0) { + SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object"); return -1; } + if (send(client->fd, (const char *)MEMBUFFER_BUFFER(client->mbuf), + MEMBUFFER_OFFSET(client->mbuf), MSG_NOSIGNAL) == -1) + { + SCLogWarning(SC_ERR_SOCKET, "unable to send block of size " + "%"PRIuMAX": %s", (uintmax_t)MEMBUFFER_OFFSET(client->mbuf), + strerror(errno)); + return -1; + } + + SCLogDebug("sent message of size %"PRIuMAX" to client socket %d", + (uintmax_t)MEMBUFFER_OFFSET(client->mbuf), client->fd); return 0; } -#define UNIX_PROTO_VERSION_LENGTH 200 -#define UNIX_PROTO_VERSION "0.1" - /** * \brief Accept a new client on unix socket * @@ -347,23 +398,27 @@ int UnixCommandAccept(UnixCommand *this) } json_object_set_new(server_msg, "return", json_string("OK")); - if (json_dump_callback(server_msg, UnixCommandSendCallback, &client, 0) == -1) { + uclient = UnixClientAlloc(); + if (unlikely(uclient == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client"); + return 0; + } + uclient->fd = client; + + if (UnixCommandSendJSONToClient(uclient, server_msg) != 0) { SCLogWarning(SC_ERR_SOCKET, "Unable to send command"); + + UnixClientFree(uclient); json_decref(server_msg); close(client); return 0; } + json_decref(server_msg); /* client connected */ SCLogDebug("Unix socket: client connected"); - uclient = SCMalloc(sizeof(UnixClient)); - if (unlikely(uclient == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new cient"); - return 0; - } - uclient->fd = client; TAILQ_INSERT_TAIL(&this->clients, uclient, next); UnixCommandSetMaxFD(this); return 1; @@ -453,10 +508,8 @@ int UnixCommandExecute(UnixCommand * this, char *command, UnixClient *client) break; } - /* send answer */ - if (json_dump_callback(server_msg, UnixCommandSendCallback, &client->fd, 0) == -1) { - SCLogWarning(SC_ERR_SOCKET, "Unable to send command"); - goto error_cmd; + if (UnixCommandSendJSONToClient(client, server_msg) != 0) { + goto error; } json_decref(jsoncmd); From 3f3ed71fe72cb5a1710be9138e5e4b8106ae810f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Feb 2016 12:42:31 +0100 Subject: [PATCH 0977/2553] jansson: cleanup JSON_ESCAPE_SLASH use --- src/output-json.c | 7 +------ src/suricata-common.h | 3 +++ src/unix-manager.c | 7 +------ src/util-debug.c | 7 +------ src/util-profiling-rules.c | 7 +------ 5 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index 69e5c577e0d4..9106ca2bee97 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -364,12 +364,7 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer) int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| -#ifdef JSON_ESCAPE_SLASH - JSON_ESCAPE_SLASH -#else - 0 -#endif - ); + JSON_ESCAPE_SLASH); if (r != 0) return TM_ECODE_OK; diff --git a/src/suricata-common.h b/src/suricata-common.h index df3ef79bee88..05bfcdf9ec3b 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -212,6 +212,9 @@ #ifdef HAVE_LIBJANSSON #include +#ifndef JSON_ESCAPE_SLASH +#define JSON_ESCAPE_SLASH 0 +#endif #endif #if CPPCHECK==1 diff --git a/src/unix-manager.c b/src/unix-manager.c index 414d99f7f986..29fe4b8a60c2 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -290,12 +290,7 @@ int UnixCommandSendJSONToClient(UnixClient *client, json_t *js) int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| -#ifdef JSON_ESCAPE_SLASH - JSON_ESCAPE_SLASH -#else - 0 -#endif - ); + JSON_ESCAPE_SLASH); if (r != 0) { SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object"); return -1; diff --git a/src/util-debug.c b/src/util-debug.c index c439cd78c041..e1a9af4539d0 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -233,12 +233,7 @@ int SCLogMessageJSON(struct timeval *tval, char *buffer, size_t buffer_size, char *js_s = json_dumps(js, JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| -#ifdef JSON_ESCAPE_SLASH - JSON_ESCAPE_SLASH -#else - 0 -#endif - ); + JSON_ESCAPE_SLASH); snprintf(buffer, buffer_size, "%s", js_s); free(js_s); diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index 945bc8b3c283..3d679384bbed 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -341,12 +341,7 @@ static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64 char *js_s = json_dumps(js, JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| -#ifdef JSON_ESCAPE_SLASH - JSON_ESCAPE_SLASH -#else - 0 -#endif - ); + JSON_ESCAPE_SLASH); if (unlikely(js_s == NULL)) return; From e51707be9062493ff696d54cbe51a275634f9715 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 23 Feb 2016 09:26:56 +0100 Subject: [PATCH 0978/2553] pcre: blacklist 8.35 for JIT use (issue #1693) --- configure.ac | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index ae085d87d20a..662342245f66 100644 --- a/configure.ac +++ b/configure.ac @@ -484,11 +484,12 @@ PKG_CHECK_MODULES(LIBPCREVERSION, [libpcre = 8.35],[libpcre_buggy_found="yes"],[libprce_buggy_found="no"]) if test "$libpcre_buggy_found" = "yes"; then echo - echo " Warning! libpcre version 8.35 found" + echo " Warning! vulnerable libpcre version 8.35 found" echo " This version has a known issue that could result in segfaults" echo " please upgrade to a newer version of pcre which you can get from" - echo " www.pcre.org." - echo " Continuing for now...." + echo " www.pcre.org. For more information, see issue #1693" + echo + echo " Continuing for now with JIT disabled..." echo fi @@ -539,6 +540,11 @@ [ pcre_jit_available=yes ], [ pcre_jit_available=no ] ) + # bug 1693, libpcre 8.35 is broken and debian jessie is still using that + if test "$libpcre_buggy_found" = "yes"; then + pcre_jit_available="no, libpcre 8.35 blacklisted" + fi + if test "x$pcre_jit_available" = "xyes"; then AC_MSG_RESULT(yes) AC_DEFINE([PCRE_HAVE_JIT], [1], [Pcre with JIT compiler support enabled]) From f5ce7549bef764c0d87bbde3de53f85cfaea9336 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 23 Feb 2016 09:50:40 +0100 Subject: [PATCH 0979/2553] unix-manager: fix memleak in error case (CID 1353491) --- src/unix-manager.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unix-manager.c b/src/unix-manager.c index 29fe4b8a60c2..a7f0052e2382 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -396,6 +396,8 @@ int UnixCommandAccept(UnixCommand *this) uclient = UnixClientAlloc(); if (unlikely(uclient == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client"); + json_decref(server_msg); + close(client); return 0; } uclient->fd = client; From fb90358e1796915fa63b671c7fb687cfc17bb53f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 23 Feb 2016 09:52:09 +0100 Subject: [PATCH 0980/2553] conf: explicitly ignore retval (CID 1353490) --- src/output-json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output-json.c b/src/output-json.c index 9106ca2bee97..89311bdd92cf 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -435,7 +435,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) "Please set sensor-name globally."); } else { - ConfGet("sensor-name", (char **)&sensor_name); + (void)ConfGet("sensor-name", (char **)&sensor_name); } if (unlikely(json_ctx == NULL)) { From 0dd81b85d4a46702b1c7fe482fb1eb04ef50d130 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 23 Feb 2016 10:05:48 +0100 Subject: [PATCH 0981/2553] multi-tenants: improve error handling (CID 1312702) --- src/detect-engine.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index cba76ca3698d..9763ae95bd2a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1334,7 +1334,9 @@ static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThread map_cnt = 0; map = master->tenant_mapping_list; while (map) { - BUG_ON(map_cnt > map_array_size); + if (map_cnt >= map_array_size) { + goto error; + } map_array[map_cnt].traffic_id = map->traffic_id; map_array[map_cnt].tenant_id = map->tenant_id; map_cnt++; @@ -1351,7 +1353,9 @@ static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThread DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0); if (mt_det_ctx == NULL) goto error; - BUG_ON(HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0); + if (HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0) { + goto error; + } } list = list->next; } From b9ee86fdb400ec1569fac8c20b22bcad687b009c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 23 Feb 2016 10:09:24 +0100 Subject: [PATCH 0982/2553] detect-engine: free memory in error conditions (CID 1351210) --- src/detect-engine.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 9763ae95bd2a..79fc15d30e3d 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -854,6 +854,9 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) de_ctx->id = detect_engine_ctx_id++; return de_ctx; error: + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } return NULL; } From 45812c32adfb6aa43fd1448dce380faa6d744a98 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 23 Feb 2016 10:20:29 +0100 Subject: [PATCH 0983/2553] runmode: fix memleak on live modes setup (CID 1197760) --- src/util-runmodes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util-runmodes.c b/src/util-runmodes.c index a327a5129ff9..110af4448f40 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -419,10 +419,10 @@ int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, int ldev; for (ldev = 0; ldev < nlive; ldev++) { - char *live_dev_c = NULL; + const char *live_dev_c = NULL; if ((nlive <= 1) && (live_dev != NULL)) { aconf = ConfigParser(live_dev); - live_dev_c = SCStrdup(live_dev); + live_dev_c = live_dev; if (unlikely(live_dev_c == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate interface name"); exit(EXIT_FAILURE); @@ -461,7 +461,7 @@ int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, if (live_dev != NULL) { aconf = ConfigParser(live_dev); } else { - char *live_dev_c = LiveGetDeviceName(0); + const char *live_dev_c = LiveGetDeviceName(0); aconf = ConfigParser(live_dev_c); /* \todo Set threads number in config to 1 */ } From b25bd2e18031761ff2a5b47f5cd6cff5c7d9449e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Feb 2016 20:58:09 +0100 Subject: [PATCH 0984/2553] http: fix NULL deref on certain out of memory conditions --- src/app-layer-htp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index caf2ea53076d..9425525fe73c 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2127,7 +2127,7 @@ static int HTPCallbackDoubleDecodePath(htp_tx_t *tx) static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data) { void *ptmp; - if (tx_data->len == 0) + if (tx_data->len == 0 || tx_data->tx == NULL) return HTP_OK; HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx); @@ -2164,7 +2164,7 @@ static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data) static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data) { void *ptmp; - if (tx_data->len == 0) + if (tx_data->len == 0 || tx_data->tx == NULL) return HTP_OK; HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx); From 9858ae41bed1cbd62a65657b441e233752159595 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Feb 2016 10:25:02 +0100 Subject: [PATCH 0985/2553] configure: OS X fixes Remove unnecessary -lpthread from tests. Make linker warnings non-fatal with -Werror. --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 662342245f66..118486fa2e25 100644 --- a/configure.ac +++ b/configure.ac @@ -57,7 +57,7 @@ case "$compiler" in clang) - CLANG_CFLAGS="-Wextra -Werror-implicit-function-declaration" + CLANG_CFLAGS="-Wextra -Werror-implicit-function-declaration -Wno-error=unused-command-line-argument" AC_MSG_CHECKING([clang __sync_bool_compare_and_swap support]) AC_TRY_COMPILE([#include ], [ unsigned int i = 0; (void)__sync_bool_compare_and_swap(&i, 1, 1);], @@ -470,7 +470,7 @@ LDFLAGS="${LDFLAGS} -L${with_libpcre_libraries}" fi PCRE="" - AC_CHECK_LIB(pcre, pcre_get_substring,, PCRE="no",-lpthread) + AC_CHECK_LIB(pcre, pcre_get_substring,, PCRE="no") if test "$PCRE" = "no"; then echo echo " ERROR! pcre library not found, go get it" @@ -997,7 +997,7 @@ AC_CHECK_HEADERS([pcap.h pcap/pcap.h pcap/bpf.h]) LIBPCAP="" - AC_CHECK_LIB(pcap, pcap_open_live,, LIBPCAP="no", [-lpthread]) + AC_CHECK_LIB(pcap, pcap_open_live,, LIBPCAP="no") if test "$LIBPCAP" = "no"; then echo echo " ERROR! libpcap library not found, go get it" From 6228f5f689d8016784b46cb400a368529de5b3bf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Feb 2016 14:27:10 +0100 Subject: [PATCH 0986/2553] lua: if pkg-config fails, try -llua --- configure.ac | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 118486fa2e25..087fef32f11a 100644 --- a/configure.ac +++ b/configure.ac @@ -1600,8 +1600,14 @@ LDFLAGS="${LDFLAGS} ${LUA_LIBS}" fi - AC_DEFINE([HAVE_LUA],[1],[liblua available]) - enable_lua="yes" + if test "$LUA" = "no"; then + AC_CHECK_LIB(lua, luaL_openlibs,, LUA="no") + fi + + if test "$LUA" = "yes"; then + AC_DEFINE([HAVE_LUA],[1],[liblua available]) + enable_lua="yes" + fi else echo echo " ERROR! liblua headers not found, go get them" From 893b01ed0de9c7da81685d54f9fa2c7cfc22730f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 23 Feb 2016 11:59:00 +0100 Subject: [PATCH 0987/2553] bpf: fix memleak on unusual error (CID 1197757) --- src/suricata.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/suricata.c b/src/suricata.c index 811a760008c0..f8680a9240e0 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -433,6 +433,7 @@ static int SetBpfString(int optind, char *argv[]) if(strlen(bpf_filter) > 0) { if (ConfSetFinal("bpf-filter", bpf_filter) != 1) { SCLogError(SC_ERR_FATAL, "Failed to set bpf filter."); + SCFree(bpf_filter); return TM_ECODE_FAILED; } } From 154891cf2619ed171388ac13747be38b72b216e1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 23 Feb 2016 12:12:24 +0100 Subject: [PATCH 0988/2553] pcre: work around harmless coverity warnings --- src/detect-pcre.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index d69f1da6f9de..c14fe9f51207 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -306,8 +306,12 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; - size_t slen = strlen(regexstr); - char re[slen], op_str[64] = ""; + /* take the size of the whole input as buffer size for the regex we will + * extract below. Add 1 to please Coverity's alloc_strlen test. */ + size_t slen = strlen(regexstr) + 1; + char re[slen]; + + char op_str[64] = ""; uint16_t pos = 0; uint8_t negate = 0; @@ -591,7 +595,10 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; char type_str[16] = ""; - size_t cap_buffer_len = strlen(regexstr); + + /* take the size of the whole input as buffer size for the string we will + * extract below. Add 1 to please Coverity's alloc_strlen test. */ + size_t cap_buffer_len = strlen(regexstr) + 1; char capture_str[cap_buffer_len]; memset(capture_str, 0x00, cap_buffer_len); From c467c39b61c406ab6f61693501b8e3e107f5a4b8 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 23 Feb 2016 23:27:59 +0100 Subject: [PATCH 0989/2553] build-info: workaround special _FORTIFY_SOURCE defines On systems like Gentoo where _FORTIFY_SOURCE is already defined like FORTIFY_SOURCE=((defined __OPTIMIZE && OPTIMIZE > 0) ? 2 : 0) the use within the printf function (%d) won't result in the correct value and we end up with 'defined' undeclared compile error. This workaround makes sure that just the resolved value is checked and then printed. --- src/suricata.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index f8680a9240e0..e454b8b04319 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -780,8 +780,19 @@ void SCPrintBuildInfo(void) #if __SSP_ALL__ == 2 printf("compiled with -fstack-protector-all\n"); #endif -#ifdef _FORTIFY_SOURCE - printf("compiled with _FORTIFY_SOURCE=%d\n", _FORTIFY_SOURCE); +/* + * Workaround for special defines of _FORTIFY_SOURCE like + * FORTIFY_SOURCE=((defined __OPTIMIZE && OPTIMIZE > 0) ? 2 : 0) + * which is used by Gentoo for example and would result in the error + * 'defined' undeclared when _FORTIFY_SOURCE used via %d in printf func + * + */ +#if _FORTIFY_SOURCE == 2 + printf("compiled with _FORTIFY_SOURCE=2\n"); +#elif _FORTIFY_SOURCE == 1 + printf("compiled with _FORTIFY_SOURCE=1\n"); +#elif _FORTIFY_SOURCE == 0 + printf("compiled with _FORTIFY_SOURCE=0\n"); #endif #ifdef CLS printf("L1 cache line size (CLS)=%d\n", CLS); From 0dbbe016d61ed87cabb90887fdc51b340facfa25 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 24 Feb 2016 10:50:06 +0100 Subject: [PATCH 0990/2553] flowbits: optimize set and remove --- src/flow-bit.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/flow-bit.c b/src/flow-bit.c index 2e52b9ef1aa0..934d485996cc 100644 --- a/src/flow-bit.c +++ b/src/flow-bit.c @@ -105,31 +105,25 @@ static void FlowBitRemove(Flow *f, uint16_t idx) void FlowBitSetNoLock(Flow *f, uint16_t idx) { - FlowBit *fb = FlowBitGet(f, idx); - if (fb == NULL) { - FlowBitAdd(f, idx); - } + FlowBitAdd(f, idx); } void FlowBitSet(Flow *f, uint16_t idx) { FLOWLOCK_WRLOCK(f); - FlowBitSetNoLock(f, idx); + FlowBitAdd(f, idx); FLOWLOCK_UNLOCK(f); } void FlowBitUnsetNoLock(Flow *f, uint16_t idx) { - FlowBit *fb = FlowBitGet(f, idx); - if (fb != NULL) { - FlowBitRemove(f, idx); - } + FlowBitRemove(f, idx); } void FlowBitUnset(Flow *f, uint16_t idx) { FLOWLOCK_WRLOCK(f); - FlowBitUnsetNoLock(f, idx); + FlowBitRemove(f, idx); FLOWLOCK_UNLOCK(f); } From 53af48f021ac018aaa2d0d953355110cfd5cb047 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 24 Feb 2016 12:45:47 +0100 Subject: [PATCH 0991/2553] flowbits: fix memory leak Flowbits removed from a flow by 'toggle' or 'unset' were not actually freed, leading a small memory leak. --- src/flow-bit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flow-bit.c b/src/flow-bit.c index 934d485996cc..2b4ef5ccfa04 100644 --- a/src/flow-bit.c +++ b/src/flow-bit.c @@ -88,6 +88,7 @@ static void FlowBitRemove(Flow *f, uint16_t idx) return; GenericVarRemove(&f->flowvar, (GenericVar *)fb); + FlowBitFree(fb); //printf("FlowBitRemove: remove flowbit with idx %" PRIu32 "\n", idx); #ifdef FLOWBITS_STATS From 3c788a8c176fd2980cdb51db7d5c23fc1749280a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 24 Feb 2016 13:39:10 +0100 Subject: [PATCH 0992/2553] flowbits: remove unused debugging code --- src/flow-bit.c | 35 ----------------------------------- src/flow-private.h | 9 --------- src/flow.c | 4 ---- 3 files changed, 48 deletions(-) diff --git a/src/flow-bit.c b/src/flow-bit.c index 2b4ef5ccfa04..188fc6aae36c 100644 --- a/src/flow-bit.c +++ b/src/flow-bit.c @@ -68,16 +68,6 @@ static void FlowBitAdd(Flow *f, uint16_t idx) fb->idx = idx; fb->next = NULL; GenericVarAppend(&f->flowvar, (GenericVar *)fb); - - //printf("FlowBitAdd: adding flowbit with idx %" PRIu32 "\n", idx); -#ifdef FLOWBITS_STATS - SCMutexLock(&flowbits_mutex); - flowbits_added++; - flowbits_memuse += sizeof(FlowBit); - if (flowbits_memuse > flowbits_memuse_max) - flowbits_memuse_max = flowbits_memuse; - SCMutexUnlock(&flowbits_mutex); -#endif /* FLOWBITS_STATS */ } } @@ -89,19 +79,6 @@ static void FlowBitRemove(Flow *f, uint16_t idx) GenericVarRemove(&f->flowvar, (GenericVar *)fb); FlowBitFree(fb); - - //printf("FlowBitRemove: remove flowbit with idx %" PRIu32 "\n", idx); -#ifdef FLOWBITS_STATS - SCMutexLock(&flowbits_mutex); - flowbits_removed++; - if (flowbits_memuse >= sizeof(FlowBit)) - flowbits_memuse -= sizeof(FlowBit); - else { - printf("ERROR: flowbits memory usage going below 0!\n"); - flowbits_memuse = 0; - } - SCMutexUnlock(&flowbits_mutex); -#endif /* FLOWBITS_STATS */ } void FlowBitSetNoLock(Flow *f, uint16_t idx) @@ -179,18 +156,6 @@ void FlowBitFree(FlowBit *fb) return; SCFree(fb); - -#ifdef FLOWBITS_STATS - SCMutexLock(&flowbits_mutex); - flowbits_removed++; - if (flowbits_memuse >= sizeof(FlowBit)) - flowbits_memuse -= sizeof(FlowBit); - else { - printf("ERROR: flowbits memory usage going below 0!\n"); - flowbits_memuse = 0; - } - SCMutexUnlock(&flowbits_mutex); -#endif /* FLOWBITS_STATS */ } diff --git a/src/flow-private.h b/src/flow-private.h index bd25960b2bf0..507b1aad7dd6 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -87,14 +87,5 @@ FlowConfig flow_config; /** flow memuse counter (atomic), for enforcing memcap limit */ SC_ATOMIC_DECLARE(long long unsigned int, flow_memuse); -//#define FLOWBITS_STATS -#ifdef FLOWBITS_STATS -uint64_t flowbits_memuse; -uint64_t flowbits_memuse_max; -uint32_t flowbits_added; -uint32_t flowbits_removed; -SCMutex flowbits_mutex; -#endif /* FLOWBITS_STATS */ - #endif /* __FLOW_PRIVATE_H__ */ diff --git a/src/flow.c b/src/flow.c index abd9e7e5fb77..cae7c4c0442f 100644 --- a/src/flow.c +++ b/src/flow.c @@ -476,10 +476,6 @@ void FlowInitConfig(char quiet) * \warning Not thread safe */ static void FlowPrintStats (void) { -#ifdef FLOWBITS_STATS - SCLogInfo("flowbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", - flowbits_added, flowbits_removed, flowbits_memuse_max); -#endif /* FLOWBITS_STATS */ return; } From 609cdff540c1ebd2a5a87988a4eba81f2802661a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 24 Feb 2016 16:19:13 +0100 Subject: [PATCH 0993/2553] json-drop-log: clean up memory at shutdown --- src/output-json-drop.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/output-json-drop.c b/src/output-json-drop.c index f82c9c00db3d..f93c22f4db2d 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -218,12 +218,21 @@ static TmEcode JsonDropLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } +static void JsonDropOutputCtxFree(JsonDropOutputCtx *drop_ctx) +{ + if (drop_ctx != NULL) { + if (drop_ctx->file_ctx != NULL) + LogFileFreeCtx(drop_ctx->file_ctx); + SCFree(drop_ctx); + } +} + static void JsonDropLogDeInitCtx(OutputCtx *output_ctx) { OutputDropLoggerDisable(); - LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; - LogFileFreeCtx(logfile_ctx); + JsonDropOutputCtx *drop_ctx = output_ctx->data; + JsonDropOutputCtxFree(drop_ctx); SCFree(output_ctx); } @@ -231,19 +240,12 @@ static void JsonDropLogDeInitCtxSub(OutputCtx *output_ctx) { OutputDropLoggerDisable(); + JsonDropOutputCtx *drop_ctx = output_ctx->data; + SCFree(drop_ctx); SCLogDebug("cleaning up sub output_ctx %p", output_ctx); SCFree(output_ctx); } -static void JsonDropOutputCtxFree(JsonDropOutputCtx *drop_ctx) -{ - if (drop_ctx != NULL) { - if (drop_ctx->file_ctx != NULL) - LogFileFreeCtx(drop_ctx->file_ctx); - SCFree(drop_ctx); - } -} - #define DEFAULT_LOG_FILENAME "drop.json" static OutputCtx *JsonDropLogInitCtx(ConfNode *conf) { From 7a29aa116ed47e869fd1f82ad2847f2abaf5ec65 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Wed, 24 Feb 2016 09:28:41 +0100 Subject: [PATCH 0994/2553] http: close file when http body limit is reached In some conditions, if stream.reassembly.depth is greater than request/response-body-limit size, the logging output is wrong if filestore keyword is used with http. For example, we get: {... "app_proto":"http","fileinfo":{"filename":"\/file.pdf","state":"CLOSED","stored":false,"size":1049292,"tx_id":0}} "state":"CLOSED","stored":false should be "state":"TRUNCATED","stored":true. This happens because the file state and file flags, which is the information that determine a correct output, are not set properly since a file is logged before and then closed (HTPFileClose). The logic of this patch is to close a file when we are above the limits, such that the proper state and flags can be set and the file will be logged correctly. --- src/app-layer-htp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 9425525fe73c..457616c4ac4d 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1946,6 +1946,12 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) HtpBodyAppendChunk(tx_ud, &tx_ud->response_body, (uint8_t *)d->data, len); HtpResponseBodyHandle(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); + } else { + if (tx_ud->tcflags & HTP_FILENAME_SET) { + SCLogDebug("closing file that was being stored"); + (void)HTPFileClose(hstate, NULL, 0, FILE_TRUNCATED, STREAM_TOCLIENT); + tx_ud->tcflags &= ~HTP_FILENAME_SET; + } } /* set the new chunk flag */ From 5ccf6f30ea014c296028ea7c5e858453236f946e Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Tue, 1 Sep 2015 16:09:26 -0700 Subject: [PATCH 0995/2553] Add JSON support for X-Authenticated-User. Supported as a custom field. --- src/output-json-http.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output-json-http.c b/src/output-json-http.c index 7e17b4dd600e..8c9ae9dd96f2 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -91,6 +91,7 @@ typedef enum { HTTP_FIELD_X_REQUESTED_WITH, HTTP_FIELD_DNT, HTTP_FIELD_X_FORWARDED_PROTO, + HTTP_FIELD_X_AUTHENTICATED_USER, HTTP_FIELD_ACCEPT_RANGES, HTTP_FIELD_AGE, HTTP_FIELD_ALLOW, @@ -146,6 +147,7 @@ struct { { "x_requested_with", "x-requested-with", LOG_HTTP_REQUEST }, { "dnt", "dnt", LOG_HTTP_REQUEST }, { "x_forwarded_proto", "x-forwarded-proto", LOG_HTTP_REQUEST }, + { "x_authenticated_user", "x-authenticated-user", LOG_HTTP_REQUEST }, { "accept_range", "accept-range", 0 }, { "age", "age", 0 }, { "allow", "allow", 0 }, From f7c568d1b2f4a6e3711fe79e5b5decc6840cff07 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Wed, 24 Feb 2016 17:15:09 -0800 Subject: [PATCH 0996/2553] output-json-http: Add JSON support for X-Flash-Version. Supported as a custom field. --- src/output-json-http.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output-json-http.c b/src/output-json-http.c index 8c9ae9dd96f2..716515fe6381 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -92,6 +92,7 @@ typedef enum { HTTP_FIELD_DNT, HTTP_FIELD_X_FORWARDED_PROTO, HTTP_FIELD_X_AUTHENTICATED_USER, + HTTP_FIELD_X_FLASH_VERSION, HTTP_FIELD_ACCEPT_RANGES, HTTP_FIELD_AGE, HTTP_FIELD_ALLOW, @@ -148,6 +149,7 @@ struct { { "dnt", "dnt", LOG_HTTP_REQUEST }, { "x_forwarded_proto", "x-forwarded-proto", LOG_HTTP_REQUEST }, { "x_authenticated_user", "x-authenticated-user", LOG_HTTP_REQUEST }, + { "x_flash_version", "x-flash-version", LOG_HTTP_REQUEST }, { "accept_range", "accept-range", 0 }, { "age", "age", 0 }, { "allow", "allow", 0 }, From 4db3a0f0b475652c39a7438c70498af31ac0ee4f Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Tue, 12 Jan 2016 11:25:47 -0800 Subject: [PATCH 0997/2553] output-json-alert: fix segfault when alerts separated out from eve-log. --- src/output-json-alert.c | 131 ++++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 51 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 8d09ed759b52..bd8f93e9a637 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -333,7 +333,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) HttpXFFCfg *xff_cfg = json_output_ctx->xff_cfg; /* xff header */ - if (!(xff_cfg->flags & XFF_DISABLED) && p->flow != NULL) { + if ((xff_cfg != NULL) && !(xff_cfg->flags & XFF_DISABLED) && p->flow != NULL) { int have_xff_ip = 0; char buffer[XFF_MAXLEN]; @@ -513,9 +513,15 @@ static TmEcode JsonAlertLogThreadDeinit(ThreadVars *t, void *data) static void JsonAlertLogDeInitCtx(OutputCtx *output_ctx) { - SCLogDebug("cleaning up output_ctx"); - LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; - LogFileFreeCtx(logfile_ctx); + AlertJsonOutputCtx *json_output_ctx = (AlertJsonOutputCtx *) output_ctx->data; + if (json_output_ctx != NULL) { + HttpXFFCfg *xff_cfg = json_output_ctx->xff_cfg; + if (xff_cfg != NULL) { + SCFree(xff_cfg); + } + LogFileFreeCtx(json_output_ctx->file_ctx); + SCFree(json_output_ctx); + } SCFree(output_ctx); } @@ -538,61 +544,16 @@ static void JsonAlertLogDeInitCtxSub(OutputCtx *output_ctx) #define DEFAULT_LOG_FILENAME "alert.json" -/** - * \brief Create a new LogFileCtx for "fast" output style. - * \param conf The configuration node for this output. - * \return A LogFileCtx pointer on success, NULL on failure. - */ -static OutputCtx *JsonAlertLogInitCtx(ConfNode *conf) -{ - LogFileCtx *logfile_ctx = LogFileNewCtx(); - if (logfile_ctx == NULL) { - SCLogDebug("AlertFastLogInitCtx2: Could not create new LogFileCtx"); - return NULL; - } - - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { - LogFileFreeCtx(logfile_ctx); - return NULL; - } - - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) - return NULL; - output_ctx->data = logfile_ctx; - output_ctx->DeInit = JsonAlertLogDeInitCtx; - - return output_ctx; -} - -/** - * \brief Create a new LogFileCtx for "fast" output style. - * \param conf The configuration node for this output. - * \return A LogFileCtx pointer on success, NULL on failure. - */ -static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) +static void XffSetup(AlertJsonOutputCtx *json_output_ctx, ConfNode *conf) { - OutputJsonCtx *ajt = parent_ctx->data; - AlertJsonOutputCtx *json_output_ctx = NULL; HttpXFFCfg *xff_cfg = NULL; - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) - return NULL; - - json_output_ctx = SCMalloc(sizeof(AlertJsonOutputCtx)); - if (unlikely(json_output_ctx == NULL)) { - goto error; - } - memset(json_output_ctx, 0, sizeof(AlertJsonOutputCtx)); - xff_cfg = SCMalloc(sizeof(HttpXFFCfg)); if (unlikely(xff_cfg == NULL)) { - goto error; + return; } memset(xff_cfg, 0, sizeof(HttpXFFCfg)); - json_output_ctx->file_ctx = ajt->file_ctx; json_output_ctx->xff_cfg = xff_cfg; if (conf != NULL) { @@ -642,6 +603,74 @@ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) HttpXFFGetCfg(conf, xff_cfg); } +} + +/** + * \brief Create a new LogFileCtx for "fast" output style. + * \param conf The configuration node for this output. + * \return A LogFileCtx pointer on success, NULL on failure. + */ +static OutputCtx *JsonAlertLogInitCtx(ConfNode *conf) +{ + AlertJsonOutputCtx *json_output_ctx = NULL; + LogFileCtx *logfile_ctx = LogFileNewCtx(); + if (logfile_ctx == NULL) { + SCLogDebug("AlertFastLogInitCtx2: Could not create new LogFileCtx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { + LogFileFreeCtx(logfile_ctx); + return NULL; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + LogFileFreeCtx(logfile_ctx); + return NULL; + } + + json_output_ctx = SCMalloc(sizeof(AlertJsonOutputCtx)); + if (unlikely(json_output_ctx == NULL)) { + LogFileFreeCtx(logfile_ctx); + SCFree(output_ctx); + return NULL; + } + memset(json_output_ctx, 0, sizeof(AlertJsonOutputCtx)); + + json_output_ctx->file_ctx = logfile_ctx; + + XffSetup(json_output_ctx, conf); + + output_ctx->data = json_output_ctx; + output_ctx->DeInit = JsonAlertLogDeInitCtx; + + return output_ctx; +} + +/** + * \brief Create a new LogFileCtx for "fast" output style. + * \param conf The configuration node for this output. + * \return A LogFileCtx pointer on success, NULL on failure. + */ +static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputJsonCtx *ajt = parent_ctx->data; + AlertJsonOutputCtx *json_output_ctx = NULL; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) + return NULL; + + json_output_ctx = SCMalloc(sizeof(AlertJsonOutputCtx)); + if (unlikely(json_output_ctx == NULL)) { + goto error; + } + memset(json_output_ctx, 0, sizeof(AlertJsonOutputCtx)); + + json_output_ctx->file_ctx = ajt->file_ctx; + + XffSetup(json_output_ctx, conf); output_ctx->data = json_output_ctx; output_ctx->DeInit = JsonAlertLogDeInitCtxSub; From cb66db5ef2a843d1ef8817c983fde5e443cef063 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 11 Feb 2016 11:44:12 +0100 Subject: [PATCH 0998/2553] xff: fix address overwrite in forward case --- src/app-layer-htp-xff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-htp-xff.c b/src/app-layer-htp-xff.c index 96c6de487f75..edc5168eea8f 100644 --- a/src/app-layer-htp-xff.c +++ b/src/app-layer-htp-xff.c @@ -160,7 +160,7 @@ int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, HttpXFFCfg *xff_cfg, /** Get the first IP address from the chain */ p_xff = memchr(xff_chain, ',', bstr_len(h_xff->value)); if (p_xff != NULL) { - xff_chain[bstr_len(h_xff->value) - (p_xff - xff_chain)]=0; + *p_xff = 0; } p_xff = xff_chain; } From c12044c6c53b3af388dbc06006b0230991eac38a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 30 Jan 2016 17:28:28 +0100 Subject: [PATCH 0999/2553] cuda: update build system for modern versions Remove support for compute capabilities below 2.0. Add capabilities until 5.3. --- src/Makefile.am | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 4af253a8965d..d2111e602ebe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -433,36 +433,15 @@ util-mpm-ac-cuda-kernel.cu NVCCFLAGS=-O2 -SUFFIXES = \ -.ptx_sm_10 \ -.ptx_sm_11 \ -.ptx_sm_12 \ -.ptx_sm_13 \ -.ptx_sm_20 \ -.ptx_sm_21 \ -.ptx_sm_30 \ -.ptx_sm_35 - -PTXS = $(suricata_CUDA_KERNELS:.cu=.ptx_sm_10) -PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_11) -PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_12) -PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_13) -PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_20) +PTXS = $(suricata_CUDA_KERNELS:.cu=.ptx_sm_20) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_21) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_30) +PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_32) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_35) - -.cu.ptx_sm_10: - $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_10 -ptx $< - -.cu.ptx_sm_11: - $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_11 -ptx $< - -.cu.ptx_sm_12: - $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_12 -ptx $< - -.cu.ptx_sm_13: - $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_13 -ptx $< +PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_37) +PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_50) +PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_52) +PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_53) .cu.ptx_sm_20: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_20 -ptx $< @@ -473,9 +452,24 @@ PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_35) .cu.ptx_sm_30: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_30 -ptx $< +.cu.ptx_sm_32: + $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_32 -ptx $< + .cu.ptx_sm_35: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_35 -ptx $< +.cu.ptx_sm_37: + $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_37 -ptx $< + +.cu.ptx_sm_50: + $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_50 -ptx $< + +.cu.ptx_sm_52: + $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_52 -ptx $< + +.cu.ptx_sm_53: + $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_53 -ptx $< + cuda-ptxdump.h: $(PTXS) $(PYTHON) ptxdump.py cuda-ptxdump $(PTXS) From fde7a2f656dfd8ba4a4f1aa3694ca3fc13acd05b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 30 Jan 2016 17:54:41 +0100 Subject: [PATCH 1000/2553] cuda: fix compilation --- configure.ac | 3 ++- src/util-cuda-buffer.c | 2 +- src/util-cuda-handlers.c | 3 ++- src/util-cuda-vars.c | 2 +- src/util-cuda.c | 4 ++-- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 087fef32f11a..4cf76860ccf1 100644 --- a/configure.ac +++ b/configure.ac @@ -1233,7 +1233,7 @@ [ --with-cuda-nvcc=DIR cuda nvcc compiler directory], [with_cuda_nvcc="$withval"],[with_cuda_nvcc=no]) - AC_DEFINE([SC_CUDA_SUPPORT__],[1],(CUDA support enabled)) + AC_DEFINE([__SC_CUDA_SUPPORT__],[1],(CUDA support enabled)) if test "$with_cuda_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_cuda_includes}" @@ -1290,6 +1290,7 @@ fi ]) AM_CONDITIONAL([BUILD_CUDA], [test "x$enable_cuda" = "xyes"]) + AM_CONDITIONAL([__SC_CUDA_SUPPORT__], [test "x$enable_cuda" = "xyes"]) # Check for libcap-ng diff --git a/src/util-cuda-buffer.c b/src/util-cuda-buffer.c index efaef9ffa964..47b4bc5e2258 100644 --- a/src/util-cuda-buffer.c +++ b/src/util-cuda-buffer.c @@ -45,9 +45,9 @@ * to be reallocated to other writers. */ -#ifdef __SC_CUDA_SUPPORT__ #include "suricata-common.h" +#ifdef __SC_CUDA_SUPPORT__ #include "suricata.h" #include "util-atomic.h" diff --git a/src/util-cuda-handlers.c b/src/util-cuda-handlers.c index a6cbeec9fb52..198c6f73b92d 100644 --- a/src/util-cuda-handlers.c +++ b/src/util-cuda-handlers.c @@ -23,10 +23,11 @@ /* compile in, only if we have a CUDA enabled device on the machine, with the * toolkit and the driver installed */ -#ifdef __SC_CUDA_SUPPORT__ #include "suricata-common.h" +#ifdef __SC_CUDA_SUPPORT__ + #include "util-error.h" #include "util-debug.h" #include "conf.h" diff --git a/src/util-cuda-vars.c b/src/util-cuda-vars.c index 624c09f8511b..596be8582667 100644 --- a/src/util-cuda-vars.c +++ b/src/util-cuda-vars.c @@ -21,8 +21,8 @@ * \author Anoop Saldanha */ +#include "suricata-common.h" #ifdef __SC_CUDA_SUPPORT__ - #include "suricata.h" #include "util-mpm.h" #include "util-cuda-handlers.h" diff --git a/src/util-cuda.c b/src/util-cuda.c index 3ada56b26c6d..1df4a2c3da58 100644 --- a/src/util-cuda.c +++ b/src/util-cuda.c @@ -25,12 +25,12 @@ /* compile in, only if we have a CUDA enabled device on the machine, with the * toolkit and the driver installed */ + +#include "suricata-common.h" #ifdef __SC_CUDA_SUPPORT__ #include #include "util-cuda.h" -#include "suricata-common.h" - #include "util-error.h" #include "util-debug.h" #include "util-unittest.h" From 3a6b7a1cd6301703972a6031728f5474b0bef2d5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Feb 2016 15:01:29 +0100 Subject: [PATCH 1001/2553] make install-rules: update URL to https and 3.0 --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index faeb777d9328..4bcc70f7ec0d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,9 +29,9 @@ install-rules: install -d "$(DESTDIR)$(e_sysconfrulesdir)" if HAVE_FETCH_COMMAND if HAVE_WGET_COMMAND - $(HAVE_WGET) -qO - http://rules.emergingthreats.net/open/suricata-2.0/emerging.rules.tar.gz | tar -x -z -C "$(DESTDIR)$(e_sysconfdir)" -f - + $(HAVE_WGET) -qO - https://rules.emergingthreats.net/open/suricata-3.0/emerging.rules.tar.gz | tar -x -z -C "$(DESTDIR)$(e_sysconfdir)" -f - else - $(HAVE_CURL) -s http://rules.emergingthreats.net/open/suricata-2.0/emerging.rules.tar.gz | tar -x -z -C "$(DESTDIR)$(e_sysconfdir)" -f - + $(HAVE_CURL) -s https://rules.emergingthreats.net/open/suricata-3.0/emerging.rules.tar.gz | tar -x -z -C "$(DESTDIR)$(e_sysconfdir)" -f - endif else @echo "UNABLE to load ruleset wget or curl are not installed on system." From 3a3cc43f6a81eba3175d35b1843c57896f591238 Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Thu, 25 Feb 2016 10:37:52 +0100 Subject: [PATCH 1002/2553] modbus: fix compiler uninitialized warnings with -Wmaybe-uninitialized All variables are initialized thanks to ModbusExtractUint8 or ModbusExtractUint16 function that extracts 8bits or 16bits data from pointer the received input data. In case of extracting error (because of length), ModbusExtractUint8 or ModbusExtractUint16 returns an error that is managed by the caller function. All variables are now initialized to zero when they are declared. It does not change anything functionnally but it removes Modbus warnings. --- src/app-layer-modbus.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 2d2cdc3d2e2d..3d3cda231aed 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -490,7 +490,7 @@ static void ModbusExceptionResponse(ModbusTransaction *tx, uint16_t *offset) { SCEnter(); - uint8_t exception; + uint8_t exception = 0; /* Exception code (1 byte) */ if (ModbusExtractUint8(modbus, &exception, input, input_len, offset)) @@ -596,7 +596,7 @@ static void ModbusParseReadResponse(ModbusTransaction *tx, uint16_t *offset) { SCEnter(); - uint8_t count; + uint8_t count = 0; /* Count (1 bytes) */ if (ModbusExtractUint8(modbus, &count, input, input_len, offset)) @@ -646,8 +646,8 @@ static int ModbusParseWriteRequest(ModbusTransaction *tx, uint16_t *offset) { SCEnter(); - uint16_t quantity = 1, word; - uint8_t byte, count = 1, type = tx->type; + uint16_t quantity = 1, word = 0; + uint8_t byte = 0, count = 1, type = tx->type; int i = 0; @@ -773,7 +773,7 @@ static void ModbusParseWriteResponse(ModbusTransaction *tx, uint16_t *offset) { SCEnter(); - uint16_t address, quantity, word; + uint16_t address = 0, quantity = 0, word = 0; uint8_t type = tx->type; /* Starting Address (2 bytes) */ @@ -863,7 +863,7 @@ static int ModbusParseDiagnosticRequest(ModbusTransaction *tx, uint16_t *offset) { SCEnter(); - uint16_t data; + uint16_t data = 0; /* Sub-function (2 bytes) */ if (ModbusExtractUint16(modbus, &(tx->subFunction), input, input_len, offset)) @@ -961,7 +961,7 @@ static void ModbusParseRequestPDU(ModbusTransaction *tx, { SCEnter(); uint16_t offset = (uint16_t) sizeof(ModbusHeader); - uint8_t count; + uint8_t count = 0; int i = 0; @@ -1118,7 +1118,7 @@ static void ModbusParseResponsePDU(ModbusTransaction *tx, { SCEnter(); uint16_t offset = (uint16_t) sizeof(ModbusHeader); - uint8_t count, error = FALSE, function, mei; + uint8_t count = 0, error = FALSE, function = 0, mei = 0; /* Standard function codes used on MODBUS application layer protocol (1 byte) */ if (ModbusExtractUint8(modbus, &function, input, input_len, &offset)) From e1468107e57e8c54f257175d671f76b9e32d15f2 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Thu, 25 Feb 2016 21:33:36 +0100 Subject: [PATCH 1003/2553] nfqueue: fix wrong return value check in error cases The check for the return value was wrong, we have 0 for success and 1 (and 2) for the error cases like TM_ECODE_FAILED, so we should quit unless TM_ECODE_OK (0) is returned for NFQInitThread. This fixes #1870 --- src/source-nfq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-nfq.c b/src/source-nfq.c index 9b9e737600a6..34c3734f0170 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -709,7 +709,7 @@ TmEcode ReceiveNFQThreadInit(ThreadVars *tv, void *initdata, void **data) ntv->tv = tv; int r = NFQInitThread(ntv, (max_pending_packets * NFQ_BURST_FACTOR)); - if (r < 0) { + if (r != TM_ECODE_OK) { SCLogError(SC_ERR_NFQ_THREAD_INIT, "nfq thread failed to initialize"); SCMutexUnlock(&nfq_init_lock); From 573284b5ed1e78d17d183a9d3727c7788cb57dcb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 28 Feb 2016 14:29:09 +0100 Subject: [PATCH 1004/2553] vlan: fix bad checks in unittests --- src/decode-vlan.c | 2 +- src/stream-tcp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/decode-vlan.c b/src/decode-vlan.c index 59495594e7e6..166be0ff0a16 100644 --- a/src/decode-vlan.c +++ b/src/decode-vlan.c @@ -240,7 +240,7 @@ static int DecodeVLANtest03 (void) DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL); - if(p->vlanh == NULL) { + if(p->vlanh[0] == NULL) { goto error; } diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 4c0a81d7f292..80d1b8dffde4 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -10253,7 +10253,7 @@ static int StreamTcpTest40(void) DecodeVLAN(&tv, &dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), NULL); - if(p->vlanh == NULL) { + if(p->vlanh[0] == NULL) { SCFree(p); return 0; } From 066c4b0b24c71cd3f30d6418da5e87c837b70d17 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 29 Feb 2016 09:37:04 +0100 Subject: [PATCH 1005/2553] detect ports: fix memory leak Fix mem leak on rules that contained ports like "![21,25,119]". --- src/detect-engine-port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index 6d3d5208eb48..1c9c0228f7c1 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -1275,7 +1275,7 @@ int DetectPortParseMergeNotPorts(DetectPort **head, DetectPort **nhead) /** work with a copy of the ad so we can easily clean up * the ghn group later. */ - ad = DetectPortCopy(NULL, ag); + ad = DetectPortCopySingle(NULL, ag); if (ad == NULL) { goto error; } From ecb79391a0b7af9d462b8fc5de6ceb026cbaa5d6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 1 Mar 2016 08:59:07 +0100 Subject: [PATCH 1006/2553] pcre: use pcre_free_study to free the study data --- src/detect-pcre.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index c14fe9f51207..563a6d884471 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -581,7 +581,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, if (pd != NULL && pd->re != NULL) pcre_free(pd->re); if (pd != NULL && pd->sd != NULL) - pcre_free(pd->sd); + pcre_free_study(pd->sd); if (pd) SCFree(pd); return NULL; @@ -807,7 +807,7 @@ void DetectPcreFree(void *ptr) if (pd->re != NULL) pcre_free(pd->re); if (pd->sd != NULL) - pcre_free(pd->sd); + pcre_free_study(pd->sd); SCFree(pd); return; From 881fc5500d4f467b55000c4dbd0384ec66e62847 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 1 Mar 2016 12:53:02 +0100 Subject: [PATCH 1007/2553] lua output: clean up memory at shutdown Lua module and submodules we're completely freed at exit, and nor was the lua_State. This patch does all the cleanup. --- src/output-lua.c | 19 ++++++++++++++++--- src/runmodes.c | 5 +++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/output-lua.c b/src/output-lua.c index a8fcb246f7f8..4bfe49558440 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -800,6 +800,12 @@ static lua_State *LuaScriptSetup(const char *filename) return NULL; } +static void LogLuaSubFree(OutputCtx *oc) { + if (oc->data) + SCFree(oc->data); + SCFree(oc); +} + /** \brief initialize output for a script instance * * Runs script 'setup' function. @@ -841,7 +847,7 @@ static OutputCtx *OutputLuaLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) SCLogDebug("lua_ctx %p", lua_ctx); output_ctx->data = lua_ctx; - output_ctx->DeInit = NULL; + output_ctx->DeInit = LogLuaSubFree; return output_ctx; error: @@ -851,10 +857,16 @@ static OutputCtx *OutputLuaLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } -static void LogLuaMasterFree(OutputCtx *oc) { - BUG_ON(oc == NULL); +static void LogLuaMasterFree(OutputCtx *oc) +{ if (oc->data) SCFree(oc->data); + + OutputModule *om, *tom; + TAILQ_FOREACH_SAFE(om, &oc->submodules, entries, tom) { + SCFree(om); + } + SCFree(oc); } /** \internal @@ -995,6 +1007,7 @@ static void OutputLuaLogDoDeinit(LogLuaCtx *lua_ctx) SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'deinit' function: %s", lua_tostring(luastate, -1)); return; } + lua_close(luastate); } /** \internal diff --git a/src/runmodes.c b/src/runmodes.c index 5a9f9762259d..998780d8b4bb 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -819,6 +819,10 @@ void RunModeInitializeOutputs(void) } else if (strcmp(output->val, "lua") == 0) { SCLogDebug("handle lua"); + OutputModule *lua_module = OutputGetModuleByConfName(output->val); + BUG_ON(lua_module == NULL); + AddOutputToFreeList(lua_module, output_ctx); + ConfNode *scripts = ConfNodeLookupChild(output_config, "scripts"); BUG_ON(scripts == NULL); //TODO @@ -843,6 +847,7 @@ void RunModeInitializeOutputs(void) continue; } + AddOutputToFreeList(m, sub_output_ctx); SetupOutput(m->name, m, sub_output_ctx); } From 27f6620874b418d7cd5ba43b9852ce0b023435b9 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Mon, 29 Feb 2016 22:37:24 +0100 Subject: [PATCH 1008/2553] rule-parsing: quick fix for rules with wrong double quotes The stripping of leading and trailing "s has issues with rules like the ones described in issue 1638 thus resulted in crashing the rule parser. So for now this is a quick fix which approaches this issue directly by stripping those "s correctly and handling error cases. It also adds the skip for leading spaces at the msg keyword and worksaround a possible null pointer dereference (that should never occur though). A more general approach should be done in the future. --- src/detect-depth.c | 8 +++++--- src/detect-distance.c | 8 +++++--- src/detect-l3proto.c | 8 +++++--- src/detect-msg.c | 28 +++++++++++++++++----------- src/detect-offset.c | 8 +++++--- src/detect-rev.c | 9 +++++---- src/detect-within.c | 8 +++++--- 7 files changed, 47 insertions(+), 30 deletions(-) diff --git a/src/detect-depth.c b/src/detect-depth.c index f58438dae473..9e323f6bf829 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -62,12 +62,14 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths SigMatch *pm = NULL; int ret = -1; - /* strip "'s */ - if (depthstr[0] == '\"' && depthstr[strlen(depthstr) - 1] == '\"') { + /* Strip leading and trailing "s. */ + if (depthstr[0] == '\"') { str = SCStrdup(depthstr + 1); if (unlikely(str == NULL)) goto end; - str[strlen(depthstr) - 2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } diff --git a/src/detect-distance.c b/src/detect-distance.c index a8284dbeb339..33b32787f773 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -70,12 +70,14 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *pm = NULL; int ret = -1; - /* strip "'s */ - if (distancestr[0] == '\"' && distancestr[strlen(distancestr) - 1] == '\"') { + /* Strip leading and trailing "s. */ + if (distancestr[0] == '\"') { str = SCStrdup(distancestr + 1); if (unlikely(str == NULL)) goto end; - str[strlen(distancestr) - 2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } diff --git a/src/detect-l3proto.c b/src/detect-l3proto.c index c67b47c8bb82..f7e4995290d0 100644 --- a/src/detect-l3proto.c +++ b/src/detect-l3proto.c @@ -73,12 +73,14 @@ static int DetectL3ProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst char *str = optstr; char dubbed = 0; - /* strip "'s */ - if (optstr[0] == '\"' && optstr[strlen(optstr) - 1] == '\"') { + /* Strip leading and trailing "s. */ + if (optstr[0] == '\"') { str = SCStrdup(optstr + 1); if (unlikely(str == NULL)) goto error; - str[strlen(optstr) - 2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } diff --git a/src/detect-msg.c b/src/detect-msg.c index e8b87529673a..eddf31197256 100644 --- a/src/detect-msg.c +++ b/src/detect-msg.c @@ -51,28 +51,34 @@ static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *msgstr) { char *str = NULL; uint16_t len; + uint16_t pos = 0; + uint16_t slen = 0; - if (strlen(msgstr) == 0) + slen = strlen(msgstr); + if (slen == 0) goto error; - /* strip "'s */ - if (msgstr[0] == '\"' && msgstr[strlen(msgstr)-1] == '\"') { + /* skip the first spaces */ + while (pos < slen && isspace((unsigned char)msgstr[pos])) + pos++; + + /* Strip leading and trailing "s. */ + if (msgstr[pos] == '\"') { str = SCStrdup(msgstr+1); if (unlikely(str == NULL)) goto error; - str[strlen(msgstr)-2] = '\0'; - } else if (msgstr[1] == '\"' && msgstr[strlen(msgstr)-1] == '\"') { - /* XXX do this parsing in a better way */ - str = SCStrdup(msgstr+2); - if (unlikely(str == NULL)) - goto error; - str[strlen(msgstr)-3] = '\0'; - //printf("DetectMsgSetup: format hack applied: \'%s\'\n", str); + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str)-1] = '\0'; + } } else { SCLogError(SC_ERR_INVALID_VALUE, "format error \'%s\'", msgstr); goto error; } + /* make sure that we don't proceed with null pointer */ + if (unlikely(str == NULL)) + goto error; + len = strlen(str); if (len == 0) goto error; diff --git a/src/detect-offset.c b/src/detect-offset.c index 65372ec0af5d..e13de7f602a0 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -61,12 +61,14 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) SigMatch *pm = NULL; int ret = -1; - /* strip "'s */ - if (offsetstr[0] == '\"' && offsetstr[strlen(offsetstr)-1] == '\"') { + /* Strip leading and trailing "s. */ + if (offsetstr[0] == '\"') { str = SCStrdup(offsetstr+1); if (unlikely(str == NULL)) goto end; - str[strlen(offsetstr) - 2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } diff --git a/src/detect-rev.c b/src/detect-rev.c index 6306f6cc7d1e..d540ec6163a0 100644 --- a/src/detect-rev.c +++ b/src/detect-rev.c @@ -46,13 +46,14 @@ static int DetectRevSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) char *str = rawstr; char dubbed = 0; - /* strip "'s */ - if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') { + /* Strip leading and trailing "s. */ + if (rawstr[0] == '\"') { str = SCStrdup(rawstr+1); if (unlikely(str == NULL)) return -1; - - str[strlen(rawstr)-2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(rawstr)-1] = '\0'; + } dubbed = 1; } diff --git a/src/detect-within.c b/src/detect-within.c index 25c97238676b..2845856fe291 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -74,12 +74,14 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, char *within SigMatch *pm = NULL; int ret = -1; - /* strip "'s */ - if (withinstr[0] == '\"' && withinstr[strlen(withinstr)-1] == '\"') { + /* Strip leading and trailing "s. */ + if (withinstr[0] == '\"') { str = SCStrdup(withinstr+1); if (unlikely(str == NULL)) goto end; - str[strlen(withinstr) - 2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } From 1efcaf217904b3b2238684a6437d2afb0dec08bf Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 1 Mar 2016 14:36:17 -0600 Subject: [PATCH 1009/2553] dcerpc: fix memory leak when called from smb When DCERPC was wrapped in SMB it wasn't being initialized or cleaned up properly. To fix, expose DCERPC initialization and cleanup functions for use by the SMB application layer. Redmine ticket: https://redmine.openinfosecfoundation.org/issues/1708 --- src/app-layer-dcerpc.c | 60 +++++++++++++++++++++++------------------- src/app-layer-dcerpc.h | 2 ++ src/app-layer-smb.c | 23 +++------------- 3 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 44705ea970a2..9f9862f043cc 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -891,12 +891,10 @@ static uint32_t DCERPCParseBIND(DCERPC *dcerpc, uint8_t *input, uint32_t input_l TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.accepted_uuid_list, item, next); SCFree(item); } - TAILQ_INIT(&dcerpc->dcerpcbindbindack.accepted_uuid_list); } dcerpc->dcerpcbindbindack.uuid_internal_id = 0; dcerpc->dcerpcbindbindack.numctxitems = *(p + 8); dcerpc->dcerpcbindbindack.numctxitemsleft = dcerpc->dcerpcbindbindack.numctxitems; - TAILQ_INIT(&dcerpc->dcerpcbindbindack.uuid_list); dcerpc->bytesprocessed += 12; SCReturnUInt(12U); } else { @@ -958,12 +956,10 @@ static uint32_t DCERPCParseBIND(DCERPC *dcerpc, uint8_t *input, uint32_t input_l TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.accepted_uuid_list, item, next); SCFree(item); } - TAILQ_INIT(&dcerpc->dcerpcbindbindack.accepted_uuid_list); } dcerpc->dcerpcbindbindack.uuid_internal_id = 0; dcerpc->dcerpcbindbindack.numctxitems = *(p++); dcerpc->dcerpcbindbindack.numctxitemsleft = dcerpc->dcerpcbindbindack.numctxitems; - TAILQ_INIT(&dcerpc->dcerpcbindbindack.uuid_list); if (!(--input_len)) break; /* fall through */ @@ -1952,49 +1948,59 @@ static int DCERPCParseResponse(Flow *f, void *dcerpc_state, local_data, 1); } +void DCERPCInit(DCERPC *dcerpc) +{ + dcerpc->transaction_id = 1; + + TAILQ_INIT(&dcerpc->dcerpcbindbindack.uuid_list); + TAILQ_INIT(&dcerpc->dcerpcbindbindack.accepted_uuid_list); +} + static void *DCERPCStateAlloc(void) { SCEnter(); - DCERPCState *s = SCMalloc(sizeof(DCERPCState)); + DCERPCState *s = SCCalloc(1, sizeof(DCERPCState)); if (unlikely(s == NULL)) { SCReturnPtr(NULL, "void"); } - memset(s, 0, sizeof(DCERPCState)); - s->dcerpc.transaction_id = 1; + DCERPCInit(&s->dcerpc); SCReturnPtr((void *)s, "void"); } -static void DCERPCStateFree(void *s) +void DCERPCCleanup(DCERPC *dcerpc) { - DCERPCState *sstate = (DCERPCState *) s; - - DCERPCUuidEntry *item; + DCERPCUuidEntry *entry; - while ((item = TAILQ_FIRST(&sstate->dcerpc.dcerpcbindbindack.uuid_list))) { - //printUUID("Free", item); - TAILQ_REMOVE(&sstate->dcerpc.dcerpcbindbindack.uuid_list, item, next); - SCFree(item); + while ((entry = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.uuid_list))) { + TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.uuid_list, entry, next); + SCFree(entry); } - while ((item = TAILQ_FIRST(&sstate->dcerpc.dcerpcbindbindack.accepted_uuid_list))) { - //printUUID("Free", item); - TAILQ_REMOVE(&sstate->dcerpc.dcerpcbindbindack.accepted_uuid_list, item, next); - SCFree(item); + while ((entry = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.accepted_uuid_list))) { + TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.accepted_uuid_list, entry, next); + SCFree(entry); } - if (sstate->dcerpc.dcerpcrequest.stub_data_buffer != NULL) { - SCFree(sstate->dcerpc.dcerpcrequest.stub_data_buffer); - sstate->dcerpc.dcerpcrequest.stub_data_buffer = NULL; - sstate->dcerpc.dcerpcrequest.stub_data_buffer_len = 0; + if (dcerpc->dcerpcrequest.stub_data_buffer != NULL) { + SCFree(dcerpc->dcerpcrequest.stub_data_buffer); + dcerpc->dcerpcrequest.stub_data_buffer = NULL; + dcerpc->dcerpcrequest.stub_data_buffer_len = 0; } - if (sstate->dcerpc.dcerpcresponse.stub_data_buffer != NULL) { - SCFree(sstate->dcerpc.dcerpcresponse.stub_data_buffer); - sstate->dcerpc.dcerpcresponse.stub_data_buffer = NULL; - sstate->dcerpc.dcerpcresponse.stub_data_buffer_len = 0; + if (dcerpc->dcerpcresponse.stub_data_buffer != NULL) { + SCFree(dcerpc->dcerpcresponse.stub_data_buffer); + dcerpc->dcerpcresponse.stub_data_buffer = NULL; + dcerpc->dcerpcresponse.stub_data_buffer_len = 0; } +} + +static void DCERPCStateFree(void *s) +{ + DCERPCState *sstate = (DCERPCState *) s; + + DCERPCCleanup(&sstate->dcerpc); SCFree(s); } diff --git a/src/app-layer-dcerpc.h b/src/app-layer-dcerpc.h index 4781f0d1ae07..db90461e044a 100644 --- a/src/app-layer-dcerpc.h +++ b/src/app-layer-dcerpc.h @@ -36,6 +36,8 @@ typedef struct DCERPCState_ { uint8_t data_needed_for_dir; } DCERPCState; +void DCERPCInit(DCERPC *dcerpc); +void DCERPCCleanup(DCERPC *dcerpc); void RegisterDCERPCParsers(void); void DCERPCParserTests(void); void DCERPCParserRegisterTests(void); diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 4d7aa845b7d3..c56422c21434 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -42,6 +42,7 @@ #include "app-layer-detect-proto.h" #include "app-layer-protos.h" #include "app-layer-parser.h" +#include "app-layer-dcerpc.h" #include "util-spm.h" #include "util-unittest.h" @@ -1426,12 +1427,12 @@ static void *SMBStateAlloc(void) { SCEnter(); - void *s = SCMalloc(sizeof(SMBState)); + SMBState *s = (SMBState *)SCCalloc(1, sizeof(SMBState)); if (unlikely(s == NULL)) { SCReturnPtr(NULL, "void"); } - memset(s, 0, sizeof(SMBState)); + DCERPCInit(&s->dcerpc); SCReturnPtr(s, "void"); } @@ -1444,23 +1445,7 @@ static void SMBStateFree(void *s) SCEnter(); SMBState *sstate = (SMBState *) s; - DCERPCUuidEntry *item; - - while ((item = TAILQ_FIRST(&sstate->dcerpc.dcerpcbindbindack.uuid_list))) { - //printUUID("Free", item); - TAILQ_REMOVE(&sstate->dcerpc.dcerpcbindbindack.uuid_list, item, next); - SCFree(item); - } - if (sstate->dcerpc.dcerpcrequest.stub_data_buffer != NULL) { - SCFree(sstate->dcerpc.dcerpcrequest.stub_data_buffer); - sstate->dcerpc.dcerpcrequest.stub_data_buffer = NULL; - sstate->dcerpc.dcerpcrequest.stub_data_buffer_len = 0; - } - if (sstate->dcerpc.dcerpcresponse.stub_data_buffer != NULL) { - SCFree(sstate->dcerpc.dcerpcresponse.stub_data_buffer); - sstate->dcerpc.dcerpcresponse.stub_data_buffer = NULL; - sstate->dcerpc.dcerpcresponse.stub_data_buffer_len = 0; - } + DCERPCCleanup(&sstate->dcerpc); SCFree(s); SCReturn; From dddd2d06f6ada5fd2edd689673ed217c833df516 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 1 Mar 2016 15:08:14 -0600 Subject: [PATCH 1010/2553] dcerpc: cleanup list handling --- src/app-layer-dcerpc-common.h | 6 ++++-- src/app-layer-dcerpc.c | 38 +++++++++++++---------------------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/app-layer-dcerpc-common.h b/src/app-layer-dcerpc-common.h index cdda563009d1..72fe4574fb44 100644 --- a/src/app-layer-dcerpc-common.h +++ b/src/app-layer-dcerpc-common.h @@ -145,6 +145,8 @@ typedef struct DCERPCUuidEntry_ { TAILQ_ENTRY(DCERPCUuidEntry_) next; } DCERPCUuidEntry; +typedef TAILQ_HEAD(DCERPCUuidEntryList_, DCERPCUuidEntry_) DCERPCUuidEntryList; + typedef struct DCERPCBindBindAck_ { uint8_t numctxitems; uint8_t numctxitemsleft; @@ -154,9 +156,9 @@ typedef struct DCERPCBindBindAck_ { uint16_t version; uint16_t versionminor; DCERPCUuidEntry *uuid_entry; - TAILQ_HEAD(, DCERPCUuidEntry_) uuid_list; + DCERPCUuidEntryList uuid_list; /* the interface uuids that the server has accepted */ - TAILQ_HEAD(, DCERPCUuidEntry_) accepted_uuid_list; + DCERPCUuidEntryList accepted_uuid_list; uint16_t uuid_internal_id; uint16_t secondaryaddrlen; uint16_t secondaryaddrlenleft; diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 9f9862f043cc..5e1d5ba784b8 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -77,6 +77,8 @@ enum { DCERPC_FIELD_MAX, }; +void DCERPCUuidListFree(DCERPCUuidEntryList *list); + /* \brief hexdump function from libdnet, used for debugging only */ void hexdump(/*Flow *f,*/ const void *buf, size_t len) { @@ -875,22 +877,15 @@ static uint32_t DCERPCParseBINDACKCTXItem(DCERPC *dcerpc, uint8_t *input, uint32 static uint32_t DCERPCParseBIND(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); - DCERPCUuidEntry *item; uint8_t *p = input; if (input_len) { switch (dcerpc->bytesprocessed) { case 16: dcerpc->dcerpcbindbindack.numctxitems = 0; if (input_len >= 12) { - while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.uuid_list))) { - TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.uuid_list, item, next); - SCFree(item); - } + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.uuid_list); if (dcerpc->dcerpchdr.type == BIND) { - while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.accepted_uuid_list))) { - TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.accepted_uuid_list, item, next); - SCFree(item); - } + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.accepted_uuid_list); } dcerpc->dcerpcbindbindack.uuid_internal_id = 0; dcerpc->dcerpcbindbindack.numctxitems = *(p + 8); @@ -947,15 +942,9 @@ static uint32_t DCERPCParseBIND(DCERPC *dcerpc, uint8_t *input, uint32_t input_l break; /* fall through */ case 24: - while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.uuid_list))) { - TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.uuid_list, item, next); - SCFree(item); - } + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.uuid_list); if (dcerpc->dcerpchdr.type == BIND) { - while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.accepted_uuid_list))) { - TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.accepted_uuid_list, item, next); - SCFree(item); - } + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.accepted_uuid_list); } dcerpc->dcerpcbindbindack.uuid_internal_id = 0; dcerpc->dcerpcbindbindack.numctxitems = *(p++); @@ -1970,19 +1959,20 @@ static void *DCERPCStateAlloc(void) SCReturnPtr((void *)s, "void"); } -void DCERPCCleanup(DCERPC *dcerpc) +void DCERPCUuidListFree(DCERPCUuidEntryList *list) { DCERPCUuidEntry *entry; - while ((entry = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.uuid_list))) { - TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.uuid_list, entry, next); + while ((entry = TAILQ_FIRST(list))) { + TAILQ_REMOVE(list, entry, next); SCFree(entry); } +} - while ((entry = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.accepted_uuid_list))) { - TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.accepted_uuid_list, entry, next); - SCFree(entry); - } +void DCERPCCleanup(DCERPC *dcerpc) +{ + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.uuid_list); + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.accepted_uuid_list); if (dcerpc->dcerpcrequest.stub_data_buffer != NULL) { SCFree(dcerpc->dcerpcrequest.stub_data_buffer); From a1a0acf8a8437cbc8c397cbea871f360ec5e9237 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 Nov 2015 21:20:59 +0100 Subject: [PATCH 1011/2553] magic: make data arg const --- src/util-magic.c | 4 ++-- src/util-magic.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util-magic.c b/src/util-magic.c index bad15fbe5e2a..0fbb6994ae38 100644 --- a/src/util-magic.c +++ b/src/util-magic.c @@ -103,7 +103,7 @@ int MagicInit(void) * * \retval result pointer to null terminated string */ -char *MagicGlobalLookup(uint8_t *buf, uint32_t buflen) +char *MagicGlobalLookup(const uint8_t *buf, uint32_t buflen) { const char *result = NULL; char *magic = NULL; @@ -132,7 +132,7 @@ char *MagicGlobalLookup(uint8_t *buf, uint32_t buflen) * * \retval result pointer to null terminated string */ -char *MagicThreadLookup(magic_t *ctx, uint8_t *buf, uint32_t buflen) +char *MagicThreadLookup(magic_t *ctx, const uint8_t *buf, uint32_t buflen) { const char *result = NULL; char *magic = NULL; diff --git a/src/util-magic.h b/src/util-magic.h index 0efdbd147b48..85b72d1b157f 100644 --- a/src/util-magic.h +++ b/src/util-magic.h @@ -28,8 +28,8 @@ int MagicInit(void); void MagicDeinit(void); -char *MagicGlobalLookup(uint8_t *, uint32_t); -char *MagicThreadLookup(magic_t *, uint8_t *, uint32_t); +char *MagicGlobalLookup(const uint8_t *, uint32_t); +char *MagicThreadLookup(magic_t *, const uint8_t *, uint32_t); void MagicRegisterTests(void); #endif /* __UTIL_MAGIC_H__ */ From 77f67062dedf40b66773a9a9d7d679536c6e1c6c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 Nov 2015 17:11:08 +0100 Subject: [PATCH 1012/2553] htp: add HTPCalloc wrapper --- src/app-layer-htp-mem.c | 17 +++++++++++++++++ src/app-layer-htp-mem.h | 1 + 2 files changed, 18 insertions(+) diff --git a/src/app-layer-htp-mem.c b/src/app-layer-htp-mem.c index c4f94e826ee7..c9caefa2dffe 100644 --- a/src/app-layer-htp-mem.c +++ b/src/app-layer-htp-mem.c @@ -121,6 +121,23 @@ void *HTPMalloc(size_t size) return ptr; } +void *HTPCalloc(size_t n, size_t size) +{ + void *ptr = NULL; + + if (HTPCheckMemcap((uint32_t)(n * size)) == 0) + return NULL; + + ptr = SCCalloc(n, size); + + if (unlikely(ptr == NULL)) + return NULL; + + HTPIncrMemuse((uint64_t)(n * size)); + + return ptr; +} + void *HTPRealloc(void *ptr, size_t orig_size, size_t size) { void *rptr = NULL; diff --git a/src/app-layer-htp-mem.h b/src/app-layer-htp-mem.h index 44b50f5c0848..1039c32ce611 100644 --- a/src/app-layer-htp-mem.h +++ b/src/app-layer-htp-mem.h @@ -19,6 +19,7 @@ void HTPParseMemcap(); void *HTPMalloc(size_t size); +void *HTPCalloc(size_t n, size_t size); void *HTPRealloc(void *ptr, size_t orig_size, size_t size); void HTPFree(void *ptr, size_t size); From 8631b73852b675048ef4b54f7a47d8792610c9e9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 Nov 2015 22:53:55 +0100 Subject: [PATCH 1013/2553] http body: use HTPCalloc --- src/app-layer-htp-body.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index a9a1ba17f08d..3c0dde1f8ebd 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -85,16 +85,14 @@ int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32 if (body->first == NULL) { /* New chunk */ - bd = (HtpBodyChunk *)HTPMalloc(sizeof(HtpBodyChunk)); + bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); if (bd == NULL) goto error; bd->len = len; bd->stream_offset = 0; - bd->next = NULL; - bd->logged = 0; - bd->data = HTPMalloc(len); + bd->data = HTPCalloc(1, len); if (bd->data == NULL) { goto error; } @@ -104,16 +102,14 @@ int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32 body->content_len_so_far = len; } else { - bd = (HtpBodyChunk *)HTPMalloc(sizeof(HtpBodyChunk)); + bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); if (bd == NULL) goto error; bd->len = len; bd->stream_offset = body->content_len_so_far; - bd->next = NULL; - bd->logged = 0; - bd->data = HTPMalloc(len); + bd->data = HTPCalloc(1, len); if (bd->data == NULL) { goto error; } From e3703ee1262f327f2f25afdfb6538095a734c189 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 Nov 2015 07:56:36 +0100 Subject: [PATCH 1014/2553] file: constify data/name args --- src/util-file.c | 14 +++++++------- src/util-file.h | 9 +++++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/util-file.c b/src/util-file.c index 38ea1b8d4279..de31af31dd9b 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -291,7 +291,7 @@ void FileContainerFree(FileContainer *ffc) * * \retval new FileData object */ -static FileData *FileDataAlloc(uint8_t *data, uint32_t data_len) +static FileData *FileDataAlloc(const uint8_t *data, uint32_t data_len) { FileData *new = SCMalloc(sizeof(FileData)); if (unlikely(new == NULL)) { @@ -339,7 +339,7 @@ static void FileDataFree(FileData *ffd) * * \retval new File object or NULL on error */ -static File *FileAlloc(uint8_t *name, uint16_t name_len) +static File *FileAlloc(const uint8_t *name, uint16_t name_len) { File *new = SCMalloc(sizeof(File)); if (unlikely(new == NULL)) { @@ -465,7 +465,7 @@ static int FileStoreNoStoreCheck(File *ff) * \retval -1 error * \retval -2 no store for this file */ -int FileAppendData(FileContainer *ffc, uint8_t *data, uint32_t data_len) +int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) { SCEnter(); @@ -537,8 +537,8 @@ int FileAppendData(FileContainer *ffc, uint8_t *data, uint32_t data_len) * * \note filename is not a string, so it's not nul terminated. */ -File *FileOpenFile(FileContainer *ffc, uint8_t *name, - uint16_t name_len, uint8_t *data, uint32_t data_len, uint8_t flags) +File *FileOpenFile(FileContainer *ffc, const uint8_t *name, uint16_t name_len, + const uint8_t *data, uint32_t data_len, uint8_t flags) { SCEnter(); @@ -600,7 +600,7 @@ File *FileOpenFile(FileContainer *ffc, uint8_t *name, SCReturnPtr(ff, "File"); } -static int FileCloseFilePtr(File *ff, uint8_t *data, +static int FileCloseFilePtr(File *ff, const uint8_t *data, uint32_t data_len, uint8_t flags) { SCEnter(); @@ -676,7 +676,7 @@ static int FileCloseFilePtr(File *ff, uint8_t *data, * \retval 0 ok * \retval -1 error */ -int FileCloseFile(FileContainer *ffc, uint8_t *data, +int FileCloseFile(FileContainer *ffc, const uint8_t *data, uint32_t data_len, uint8_t flags) { SCEnter(); diff --git a/src/util-file.h b/src/util-file.h index 6d02d395d1f1..96f1939f2f08 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -109,8 +109,8 @@ void FileContainerAdd(FileContainer *, File *); * * \note filename is not a string, so it's not nul terminated. */ -File *FileOpenFile(FileContainer *, uint8_t *name, uint16_t name_len, - uint8_t *data, uint32_t data_len, uint8_t flags); +File *FileOpenFile(FileContainer *, const uint8_t *name, uint16_t name_len, + const uint8_t *data, uint32_t data_len, uint8_t flags); /** * \brief Close a File * @@ -122,7 +122,8 @@ File *FileOpenFile(FileContainer *, uint8_t *name, uint16_t name_len, * \retval 0 ok * \retval -1 error */ -int FileCloseFile(FileContainer *, uint8_t *data, uint32_t data_len, uint8_t flags); +int FileCloseFile(FileContainer *, const uint8_t *data, uint32_t data_len, + uint8_t flags); /** * \brief Store a chunk of file data in the flow. The open "flowfile" @@ -135,7 +136,7 @@ int FileCloseFile(FileContainer *, uint8_t *data, uint32_t data_len, uint8_t fla * \retval 0 ok * \retval -1 error */ -int FileAppendData(FileContainer *, uint8_t *data, uint32_t data_len); +int FileAppendData(FileContainer *, const uint8_t *data, uint32_t data_len); /** * \brief Tag a file for storing From 6b942b6734639d249185433541d76c8141779aa7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 Nov 2015 07:58:15 +0100 Subject: [PATCH 1015/2553] htp file: constify name/data args --- src/app-layer-htp-file.c | 9 +++++---- src/app-layer-htp-file.h | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index 27371a750d60..6de9d655720d 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -76,8 +76,9 @@ * \retval -1 error * \retval -2 not handling files on this flow */ -int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len, - uint8_t *data, uint32_t data_len, uint64_t txid, uint8_t direction) +int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, + const uint8_t *data, uint32_t data_len, + uint64_t txid, uint8_t direction) { int retval = 0; uint8_t flags = 0; @@ -201,7 +202,7 @@ int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len, * \retval -1 error * \retval -2 file doesn't need storing */ -int HTPFileStoreChunk(HtpState *s, uint8_t *data, uint32_t data_len, +int HTPFileStoreChunk(HtpState *s, const uint8_t *data, uint32_t data_len, uint8_t direction) { SCEnter(); @@ -255,7 +256,7 @@ int HTPFileStoreChunk(HtpState *s, uint8_t *data, uint32_t data_len, * \retval -1 error * \retval -2 not storing files on this flow/tx */ -int HTPFileClose(HtpState *s, uint8_t *data, uint32_t data_len, +int HTPFileClose(HtpState *s, const uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction) { SCEnter(); diff --git a/src/app-layer-htp-file.h b/src/app-layer-htp-file.h index 70799c320120..1f0bfb60556f 100644 --- a/src/app-layer-htp-file.h +++ b/src/app-layer-htp-file.h @@ -25,9 +25,9 @@ #ifndef __APP_LAYER_HTP_FILE_H__ #define __APP_LAYER_HTP_FILE_H__ -int HTPFileOpen(HtpState *, uint8_t *, uint16_t, uint8_t *, uint32_t, uint64_t, uint8_t); -int HTPFileStoreChunk(HtpState *, uint8_t *, uint32_t, uint8_t); -int HTPFileClose(HtpState *, uint8_t *, uint32_t, uint8_t, uint8_t); +int HTPFileOpen(HtpState *, const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint64_t, uint8_t); +int HTPFileStoreChunk(HtpState *, const uint8_t *, uint32_t, uint8_t); +int HTPFileClose(HtpState *, const uint8_t *, uint32_t, uint8_t, uint8_t); void HTPFileParserRegisterTests(void); From 914f7fa73384f74b0207284052d5bf130724d6f9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 Nov 2015 10:33:21 +0100 Subject: [PATCH 1016/2553] file: shrink data structure --- src/util-file.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-file.h b/src/util-file.h index 96f1939f2f08..ae3732d5c74b 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -61,11 +61,11 @@ typedef struct FileData_ { typedef struct File_ { uint16_t flags; + uint16_t name_len; + int16_t state; uint64_t txid; /**< tx this file is part of */ uint32_t file_id; uint8_t *name; - uint16_t name_len; - int16_t state; uint64_t size; /**< size tracked so far */ char *magic; FileData *chunks_head; From 6e3514a4449f3c274f82aa08b5a4e0e5272fa55e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 Nov 2015 07:55:44 +0100 Subject: [PATCH 1017/2553] spm: constify search args --- src/util-memcpy.h | 2 +- src/util-spm-bm.c | 10 +++++----- src/util-spm-bm.h | 6 +++--- src/util-spm.c | 12 ++++++++---- src/util-spm.h | 8 ++++---- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/util-memcpy.h b/src/util-memcpy.h index bdb80242b726..c2b8cd7997fc 100644 --- a/src/util-memcpy.h +++ b/src/util-memcpy.h @@ -35,7 +35,7 @@ * \param s Pointer to the src string for memcpy. * \param len len of the string sent in s. */ -static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) +static inline void memcpy_tolower(uint8_t *d, const uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) diff --git a/src/util-spm-bm.c b/src/util-spm-bm.c index 7c5b8d2d4d65..dd16bb99dd47 100644 --- a/src/util-spm-bm.c +++ b/src/util-spm-bm.c @@ -73,7 +73,7 @@ void BoyerMooreCtxToNocase(BmCtx *bm_ctx, uint8_t *needle, uint16_t needle_len) * \retval BmCtx pointer to the newly created Context for the pattern * \initonly BoyerMoore contexts should be created at init */ -BmCtx *BoyerMooreCtxInit(uint8_t *needle, uint16_t needle_len) +BmCtx *BoyerMooreCtxInit(const uint8_t *needle, uint16_t needle_len) { BmCtx *new = SCMalloc(sizeof(BmCtx)); if (unlikely(new == NULL)) { @@ -302,7 +302,7 @@ static void PreBmGsNocase(const uint8_t *x, uint16_t m, uint16_t *bmGs) * * \retval ptr to start of the match; NULL if no match */ -uint8_t *BoyerMoore(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx) +uint8_t *BoyerMoore(const uint8_t *x, uint16_t m, const uint8_t *y, int32_t n, BmCtx *bm_ctx) { uint16_t *bmGs = bm_ctx->bmGs; uint16_t *bmBc = bm_ctx->bmBc; @@ -324,7 +324,7 @@ uint8_t *BoyerMoore(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx for (i = m - 1; i >= 0 && x[i] == y[i + j]; --i); if (i < 0) { - return y + j; + return (uint8_t *)(y + j); //j += bmGs[0]; } else { // printf("%c", y[i+j]); @@ -351,7 +351,7 @@ uint8_t *BoyerMoore(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx * * \retval ptr to start of the match; NULL if no match */ -uint8_t *BoyerMooreNocase(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx) +uint8_t *BoyerMooreNocase(const uint8_t *x, uint16_t m, const uint8_t *y, int32_t n, BmCtx *bm_ctx) { uint16_t *bmGs = bm_ctx->bmGs; uint16_t *bmBc = bm_ctx->bmBc; @@ -372,7 +372,7 @@ uint8_t *BoyerMooreNocase(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx * for (i = m - 1; i >= 0 && x[i] == u8_tolower(y[i + j]); --i); if (i < 0) { - return y + j; + return (uint8_t *)(y + j); } else { j += (m1=bmGs[i]) > (m2=bmBc[u8_tolower(y[i + j])] - m + 1 + i)?m1:m2; } diff --git a/src/util-spm-bm.h b/src/util-spm-bm.h index b3b97ced4bf5..051a10243b75 100644 --- a/src/util-spm-bm.h +++ b/src/util-spm-bm.h @@ -37,12 +37,12 @@ typedef struct BmCtx_ { } BmCtx; /** Prepare and return a Boyer Moore context */ -BmCtx *BoyerMooreCtxInit(uint8_t *needle, uint16_t needle_len); +BmCtx *BoyerMooreCtxInit(const uint8_t *needle, uint16_t needle_len); BmCtx *BoyerMooreNocaseCtxInit(uint8_t *needle, uint16_t needle_len); void BoyerMooreCtxToNocase(BmCtx *, uint8_t *, uint16_t); -uint8_t *BoyerMoore(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx); -uint8_t *BoyerMooreNocase(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx); +uint8_t *BoyerMoore(const uint8_t *x, uint16_t m, const uint8_t *y, int32_t n, BmCtx *bm_ctx); +uint8_t *BoyerMooreNocase(const uint8_t *x, uint16_t m, const uint8_t *y, int32_t n, BmCtx *bm_ctx); void BoyerMooreCtxDeInit(BmCtx *); #endif /* __UTIL_SPM_BM__ */ diff --git a/src/util-spm.c b/src/util-spm.c index 2da12e77889e..845795b8d8b3 100644 --- a/src/util-spm.c +++ b/src/util-spm.c @@ -68,7 +68,8 @@ * \param needle pattern to search for * \param needlelen length of the pattern */ -uint8_t *Bs2bmSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) +uint8_t *Bs2bmSearch(const uint8_t *text, uint32_t textlen, + const uint8_t *needle, uint16_t needlelen) { uint8_t badchars[ALPHABET_SIZE]; Bs2BmBadchars(needle, needlelen, badchars); @@ -84,7 +85,8 @@ uint8_t *Bs2bmSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t * \param needle pattern to search for * \param needlelen length of the pattern */ -uint8_t *Bs2bmNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) +uint8_t *Bs2bmNocaseSearch(const uint8_t *text, uint32_t textlen, + const uint8_t *needle, uint16_t needlelen) { uint8_t badchars[ALPHABET_SIZE]; Bs2BmBadchars(needle, needlelen, badchars); @@ -101,7 +103,8 @@ uint8_t *Bs2bmNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uin * \param needle pattern to search for * \param needlelen length of the pattern */ -uint8_t *BoyerMooreSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) +uint8_t *BoyerMooreSearch(const uint8_t *text, uint32_t textlen, + const uint8_t *needle, uint16_t needlelen) { BmCtx *bm_ctx = BoyerMooreCtxInit(needle, needlelen); @@ -120,7 +123,8 @@ uint8_t *BoyerMooreSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint * \param needle pattern to search for * \param needlelen length of the pattern */ -uint8_t *BoyerMooreNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) +uint8_t *BoyerMooreNocaseSearch(const uint8_t *text, uint32_t textlen, + uint8_t *needle, uint16_t needlelen) { BmCtx *bm_ctx = BoyerMooreNocaseCtxInit(needle, needlelen); diff --git a/src/util-spm.h b/src/util-spm.h index 2dea657ee607..bd1826923143 100644 --- a/src/util-spm.h +++ b/src/util-spm.h @@ -29,10 +29,10 @@ #include "util-spm-bm.h" /** Default algorithm to use: Boyer Moore */ -uint8_t *Bs2bmSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); -uint8_t *Bs2bmNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); -uint8_t *BoyerMooreSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); -uint8_t *BoyerMooreNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); +uint8_t *Bs2bmSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); +uint8_t *Bs2bmNocaseSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); +uint8_t *BoyerMooreSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); +uint8_t *BoyerMooreNocaseSearch(const uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); /* Macros for automatic algorithm selection (use them only when you can't store the context) */ #define SpmSearch(text, textlen, needle, needlelen) ({\ From 83f400dd60d7701aabee2336046e845f553f848d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 Nov 2015 23:26:07 +0100 Subject: [PATCH 1018/2553] http: remove unused param from HtpBodyAppendChunk --- src/app-layer-htp-body.c | 2 +- src/app-layer-htp-body.h | 2 +- src/app-layer-htp.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index 3c0dde1f8ebd..863b8ae37451 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -73,7 +73,7 @@ * \retval 0 ok * \retval -1 error */ -int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32_t len) +int HtpBodyAppendChunk(HtpBody *body, const uint8_t *data, uint32_t len) { SCEnter(); diff --git a/src/app-layer-htp-body.h b/src/app-layer-htp-body.h index 6d54f0d5f8b2..e7d051e8545f 100644 --- a/src/app-layer-htp-body.h +++ b/src/app-layer-htp-body.h @@ -28,7 +28,7 @@ #ifndef __APP_LAYER_HTP_BODY_H__ #define __APP_LAYER_HTP_BODY_H__ -int HtpBodyAppendChunk(HtpTxUserData *, HtpBody *, uint8_t *, uint32_t); +int HtpBodyAppendChunk(HtpBody *, const uint8_t *, uint32_t); void HtpBodyPrint(HtpBody *); void HtpBodyFree(HtpBody *); void HtpBodyPrune(HtpState *, HtpBody *, int); diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 457616c4ac4d..9a8c27dad562 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1844,7 +1844,7 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) } SCLogDebug("len %u", len); - HtpBodyAppendChunk(tx_ud, &tx_ud->request_body, (uint8_t *)d->data, len); + HtpBodyAppendChunk(&tx_ud->request_body, d->data, len); uint8_t *chunks_buffer = NULL; uint32_t chunks_buffer_len = 0; @@ -1943,7 +1943,7 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) } SCLogDebug("len %u", len); - HtpBodyAppendChunk(tx_ud, &tx_ud->response_body, (uint8_t *)d->data, len); + HtpBodyAppendChunk(&tx_ud->response_body, d->data, len); HtpResponseBodyHandle(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); } else { @@ -5665,9 +5665,9 @@ static int HTPBodyReassemblyTest01(void) uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; uint8_t chunk2[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; - int r = HtpBodyAppendChunk(&htud, &htud.request_body, (uint8_t *)chunk1, sizeof(chunk1)-1); + int r = HtpBodyAppendChunk(&htud.request_body, chunk1, sizeof(chunk1)-1); BUG_ON(r != 0); - r = HtpBodyAppendChunk(&htud, &htud.request_body, (uint8_t *)chunk2, sizeof(chunk2)-1); + r = HtpBodyAppendChunk(&htud.request_body, chunk2, sizeof(chunk2)-1); BUG_ON(r != 0); uint8_t *chunks_buffer = NULL; From a2ceb98064ad4486334b6bd85a7da9abcfaf0730 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 14 Dec 2015 18:27:09 +0100 Subject: [PATCH 1019/2553] file: fix flags type in API --- src/util-file.c | 6 +++--- src/util-file.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/util-file.c b/src/util-file.c index de31af31dd9b..7e3ba16113c1 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -538,7 +538,7 @@ int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) * \note filename is not a string, so it's not nul terminated. */ File *FileOpenFile(FileContainer *ffc, const uint8_t *name, uint16_t name_len, - const uint8_t *data, uint32_t data_len, uint8_t flags) + const uint8_t *data, uint32_t data_len, uint16_t flags) { SCEnter(); @@ -601,7 +601,7 @@ File *FileOpenFile(FileContainer *ffc, const uint8_t *name, uint16_t name_len, } static int FileCloseFilePtr(File *ff, const uint8_t *data, - uint32_t data_len, uint8_t flags) + uint32_t data_len, uint16_t flags) { SCEnter(); @@ -677,7 +677,7 @@ static int FileCloseFilePtr(File *ff, const uint8_t *data, * \retval -1 error */ int FileCloseFile(FileContainer *ffc, const uint8_t *data, - uint32_t data_len, uint8_t flags) + uint32_t data_len, uint16_t flags) { SCEnter(); diff --git a/src/util-file.h b/src/util-file.h index ae3732d5c74b..4b590c2c389f 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -110,7 +110,7 @@ void FileContainerAdd(FileContainer *, File *); * \note filename is not a string, so it's not nul terminated. */ File *FileOpenFile(FileContainer *, const uint8_t *name, uint16_t name_len, - const uint8_t *data, uint32_t data_len, uint8_t flags); + const uint8_t *data, uint32_t data_len, uint16_t flags); /** * \brief Close a File * @@ -123,7 +123,7 @@ File *FileOpenFile(FileContainer *, const uint8_t *name, uint16_t name_len, * \retval -1 error */ int FileCloseFile(FileContainer *, const uint8_t *data, uint32_t data_len, - uint8_t flags); + uint16_t flags); /** * \brief Store a chunk of file data in the flow. The open "flowfile" From 50ad1ce3071a4bfd428db4992f4f5e5a92ec9424 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 1 Mar 2016 09:12:53 +0100 Subject: [PATCH 1020/2553] build: install app-layer-events.rules --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 4bcc70f7ec0d..55c93e61f0cf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,6 +42,7 @@ endif @test -e "$(DESTDIR)$(e_sysconfrulesdir)http-events.rules" || install -m 600 "$(top_srcdir)/rules/http-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @test -e "$(DESTDIR)$(e_sysconfrulesdir)dns-events.rules" || install -m 600 "$(top_srcdir)/rules/dns-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @test -e "$(DESTDIR)$(e_sysconfrulesdir)modbus-events.rules" || install -m 600 "$(top_srcdir)/rules/modbus-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)app-layer-events.rules" || install -m 600 "$(top_srcdir)/rules/app-layer-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @echo "" @echo "You can now start suricata by running as root something like '$(DESTDIR)$(bindir)/suricata -c $(DESTDIR)$(e_sysconfdir)/suricata.yaml -i eth0'." @echo "" From 10e2e2a8b6e5ffabcbc85708c57627dc0be7e087 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 1 Mar 2016 15:44:27 +0100 Subject: [PATCH 1021/2553] app-layer-smtp: fix mem leak and add new alert If SMTP session is weird then we may reach a state where a field like MAIL FROM is seen as duplicated. Valgrind output is: 30 bytes in 1 blocks are definitely lost in loss record 96 of 399 at 0x4C29C0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x4A5803: SMTPParseCommandWithParam (app-layer-smtp.c:996) by 0x4A4DCE: SMTPParseCommandMAILFROM (app-layer-smtp.c:1016) by 0x4A3F55: SMTPProcessRequest (app-layer-smtp.c:1127) by 0x4A1F8C: SMTPParse (app-layer-smtp.c:1191) by 0x493AD7: SMTPParseClientRecord (app-layer-smtp.c:1214) by 0x4878A6: AppLayerParserParse (app-layer-parser.c:908) by 0x42384E: AppLayerHandleTCPData (app-layer.c:444) by 0x8D7EAD: DoReassemble (stream-tcp-reassemble.c:2635) by 0x8D795F: StreamTcpReassembleAppLayer (stream-tcp-reassemble.c:3028) by 0x8D8BE0: StreamTcpReassembleHandleSegmentUpdateACK (stream-tcp-reassemble.c:3404) by 0x8D8F6E: StreamTcpReassembleHandleSegment (stream-tcp-reassemble.c:3432) --- rules/smtp-events.rules | 3 ++- src/app-layer-smtp.c | 12 ++++++++++++ src/app-layer-smtp.h | 3 +++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/rules/smtp-events.rules b/rules/smtp-events.rules index c1ade81ad3df..2c318665d109 100644 --- a/rules/smtp-events.rules +++ b/rules/smtp-events.rules @@ -27,4 +27,5 @@ alert smtp any any -> any any (msg:"SURICATA SMTP data command rejected"; flow:e #alert smtp any any -> any any (msg:"SURICATA SMTP Mime encoded line len exceeded"; flow:established; app-layer-event:smtp.mime_long_enc_line; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220016; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP Mime boundary length exceeded"; flow:established,to_server; app-layer-event:smtp.mime_long_boundary; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220017; rev:1;) -# next sid 2220018 +alert smtp any any -> any any (msg:"SURICATA SMTP duplicate fields"; flow:established,to_server; app-layer-event:smtp.duplicate_fields; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220018; rev:1;) +# next sid 2220019 diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 8afcf2597472..a753fd8295cd 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -144,6 +144,10 @@ SCEnumCharMap smtp_decoder_event_table[ ] = { { "MIME_LONG_BOUNDARY", SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG }, + /* Invalid behavior or content */ + { "DUPLICATE_FIELDS", + SMTP_DECODER_EVENT_DUPLICATE_FIELDS }, + { NULL, -1 }, }; @@ -1005,11 +1009,19 @@ static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8 static int SMTPParseCommandHELO(SMTPState *state) { + if (state->helo) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS); + return 0; + } return SMTPParseCommandWithParam(state, 4, &state->helo, &state->helo_len); } static int SMTPParseCommandMAILFROM(SMTPState *state) { + if (state->curr_tx->mail_from) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS); + return 0; + } return SMTPParseCommandWithParam(state, 9, &state->curr_tx->mail_from, &state->curr_tx->mail_from_len); diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index c58684143ab0..7bd252b2ede5 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -49,6 +49,9 @@ enum { SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG, + + /* Invalid behavior or content */ + SMTP_DECODER_EVENT_DUPLICATE_FIELDS, }; typedef struct SMTPString_ { From 5dbedbfa5bacf8a02459b2389596b63ec7822aa0 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 1 Mar 2016 14:59:13 +0100 Subject: [PATCH 1022/2553] app-layer-smtp: fix memory leak This patch fixes the following leak: Direct leak of 9982880 byte(s) in 2902 object(s) allocated from: #0 0x4c253b in malloc ??:? #1 0x10c39ac in MimeDecInitParser /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/util-decode-mime.c:2379 #2 0x6a0f91 in SMTPProcessRequest /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/app-layer-smtp.c:1085 #3 0x697658 in SMTPParse /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/app-layer-smtp.c:1185 #4 0x68fa7a in SMTPParseClientRecord /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/app-layer-smtp.c:1208 #5 0x6561c5 in AppLayerParserParse /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/app-layer-parser.c:908 #6 0x53dc2e in AppLayerHandleTCPData /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/app-layer.c:444 #7 0xf8e0af in DoReassemble /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/stream-tcp-reassemble.c:2635 #8 0xf8c3f8 in StreamTcpReassembleAppLayer /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/stream-tcp-reassemble.c:3028 #9 0xf94267 in StreamTcpReassembleHandleSegmentUpdateACK /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/stream-tcp-reassemble.c:3404 #10 0xf9643d in StreamTcpReassembleHandleSegment /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/stream-tcp-reassemble.c:3432 #11 0xf578b4 in HandleEstablishedPacketToClient /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/stream-tcp.c:2245 #12 0xeea3c7 in StreamTcpPacketStateEstablished /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/stream-tcp.c:2489 #13 0xec1d38 in StreamTcpPacket /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/stream-tcp.c:4568 #14 0xeb0e16 in StreamTcp /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/stream-tcp.c:5064 #15 0xff52a4 in TmThreadsSlotVarRun /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/tm-threads.c:130 #16 0xffdad1 in TmThreadsSlotVar /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/tm-threads.c:474 #17 0x7f7cd678d181 in start_thread /build/buildd/eglibc-2.19/nptl/pthread_create.c:312 (discriminator 2) We come to this case when a SMTP session contains at least 2 mails and then the ending of the first is not correctly detected. In that case, switching to a new tx seems a good solution. This way we still have partial logging. --- rules/smtp-events.rules | 3 ++- src/app-layer-smtp.c | 14 ++++++++++++++ src/app-layer-smtp.h | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/rules/smtp-events.rules b/rules/smtp-events.rules index 2c318665d109..89c25acbc735 100644 --- a/rules/smtp-events.rules +++ b/rules/smtp-events.rules @@ -28,4 +28,5 @@ alert smtp any any -> any any (msg:"SURICATA SMTP data command rejected"; flow:e alert smtp any any -> any any (msg:"SURICATA SMTP Mime boundary length exceeded"; flow:established,to_server; app-layer-event:smtp.mime_long_boundary; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220017; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP duplicate fields"; flow:established,to_server; app-layer-event:smtp.duplicate_fields; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220018; rev:1;) -# next sid 2220019 +alert smtp any any -> any any (msg:"SURICATA SMTP unparsable content"; flow:established,to_server; app-layer-event:smtp.unparsable_content; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220019; rev:1;) +# next sid 2220020 diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index a753fd8295cd..c5544de93da5 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -147,6 +147,8 @@ SCEnumCharMap smtp_decoder_event_table[ ] = { /* Invalid behavior or content */ { "DUPLICATE_FIELDS", SMTP_DECODER_EVENT_DUPLICATE_FIELDS }, + { "UNPARSABLE_CONTENT", + SMTP_DECODER_EVENT_UNPARSABLE_CONTENT }, { NULL, -1 }, }; @@ -1094,6 +1096,18 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, SCMemcmpLowercase("data", state->current_line, 4) == 0) { state->current_command = SMTP_COMMAND_DATA; if (smtp_config.decode_mime) { + if (tx->mime_state) { + /* We have 2 chained mails and did not detect the end + * of first one. So we start a new transaction. */ + tx->mime_state->state_flag = PARSE_ERROR; + SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT); + tx = SMTPTransactionCreate(); + if (tx == NULL) + return -1; + state->curr_tx = tx; + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + tx->tx_id = state->tx_cnt++; + } tx->mime_state = MimeDecInitParser(f, SMTPProcessDataChunk); if (tx->mime_state == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to " diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 7bd252b2ede5..06ade068c71b 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -52,6 +52,7 @@ enum { /* Invalid behavior or content */ SMTP_DECODER_EVENT_DUPLICATE_FIELDS, + SMTP_DECODER_EVENT_UNPARSABLE_CONTENT, }; typedef struct SMTPString_ { From 75cd1f0bf59ac057c4afcf94f562bd740a2999a7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 3 Mar 2016 09:57:46 +0100 Subject: [PATCH 1023/2553] gccprotect: fix SECLDFLAGS not getting used --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index d2111e602ebe..9555a28c5019 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -421,7 +421,7 @@ EXTRA_DIST = util-mpm-ac-cuda-kernel.cu ptxdump.py AM_CPPFLAGS = $(all_includes) # the library search path. -suricata_LDFLAGS = $(all_libraries) +suricata_LDFLAGS = $(all_libraries) ${SECLDFLAGS} suricata_LDADD = $(HTP_LDADD) # Rules to build CUDA ptx modules From 160122205638127eddd8673d2bab46d297d62f4e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 2 Mar 2016 09:54:07 -0600 Subject: [PATCH 1024/2553] alert-debuglog: trigger rotation on non-decoder events as well The write handling was missed for non-decoder events that would trigger rotation after a HUP. --- src/alert-debuglog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 5df1f4c1e9f5..43bbbf98bf1e 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -321,8 +321,8 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da } SCMutexLock(&aft->file_ctx->fp_mutex); - (void)MemBufferPrintToFPAsString(aft->buffer, aft->file_ctx->fp); - fflush(aft->file_ctx->fp); + aft->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), + MEMBUFFER_OFFSET(aft->buffer), aft->file_ctx); aft->file_ctx->alerts += p->alerts.cnt; SCMutexUnlock(&aft->file_ctx->fp_mutex); From 53704ea46842d850d6236495b1f448df0f483f58 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 1 Mar 2016 17:31:33 +0100 Subject: [PATCH 1025/2553] output-json: constify API --- src/output-json.c | 6 ++++-- src/output-json.h | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index 89311bdd92cf..658ac473d700 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -175,7 +175,8 @@ void CreateJSONFlowId(json_t *js, const Flow *f) json_object_set_new(js, "flow_id", json_integer(addr)); } -json_t *CreateJSONHeader(Packet *p, int direction_sensitive, char *event_type) +json_t *CreateJSONHeader(const Packet *p, int direction_sensitive, + const char *event_type) { char timebuf[64]; char srcip[46], dstip[46]; @@ -321,7 +322,8 @@ json_t *CreateJSONHeader(Packet *p, int direction_sensitive, char *event_type) return js; } -json_t *CreateJSONHeaderWithTxId(Packet *p, int direction_sensitive, char *event_type, uint32_t tx_id) +json_t *CreateJSONHeaderWithTxId(const Packet *p, int direction_sensitive, + const char *event_type, uint64_t tx_id) { json_t *js = CreateJSONHeader(p, direction_sensitive, event_type); if (unlikely(js == NULL)) diff --git a/src/output-json.h b/src/output-json.h index d6b16fd64114..467062db33db 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -41,8 +41,8 @@ int OutputJSONMemBufferCallback(const char *str, size_t size, void *data); void CreateJSONFlowId(json_t *js, const Flow *f); void JsonTcpFlags(uint8_t flags, json_t *js); -json_t *CreateJSONHeader(Packet *p, int direction_sensative, char *event_type); -json_t *CreateJSONHeaderWithTxId(Packet *p, int direction_sensitive, char *event_type, uint32_t tx_id); +json_t *CreateJSONHeader(const Packet *p, int direction_sensative, const char *event_type); +json_t *CreateJSONHeaderWithTxId(const Packet *p, int direction_sensitive, const char *event_type, uint64_t tx_id); TmEcode OutputJSON(json_t *js, void *data, uint64_t *count); int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer); OutputCtx *OutputJsonInitCtx(ConfNode *); From 69785f186c227c44a958d3684500b5da5e1a6749 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Fri, 4 Mar 2016 16:18:46 +0300 Subject: [PATCH 1026/2553] BUG #1689: fix stack overflow when parsing variables Suricata crashed when variable (either address or port) referred to itself or if one created a looped chain of variables. For instance: HOME_NET: "!$EXTERNAL_NET" EXTERNAL_NET: "!$HOME_NET" Or: Var1: "$Var2" Var2: "$Var3" Var3: "$Var1" --- src/detect-engine-address.c | 40 +++++++++++++++++++++++++++++-------- src/detect-engine-port.c | 29 ++++++++++++++++++++------- src/util-var.c | 40 +++++++++++++++++++++++++++++++++++++ src/util-var.h | 12 +++++++++++ 4 files changed, 106 insertions(+), 15 deletions(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 31e6a7ab81b7..764af6a85f5a 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -45,6 +45,7 @@ #include "util-debug.h" #include "util-print.h" +#include "util-var.h" /* prototypes */ void DetectAddressPrint(DetectAddress *); @@ -915,7 +916,7 @@ int DetectAddressSetup(DetectAddressHead *gh, char *s) */ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, DetectAddressHead *gh, DetectAddressHead *ghn, - char *s, int negate) + char *s, int negate, ResolvedVariablesList *var_list) { size_t x = 0; size_t u = 0; @@ -926,6 +927,12 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, char *rule_var_address = NULL; char *temp_rule_var_address = NULL; + if (AddVariableToResolveList(var_list, s) == -1) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Found a loop in a address " + "groups declaration. This is likely a misconfiguration."); + goto error; + } + SCLogDebug("s %s negate %s", s, negate ? "true" : "false"); for (u = 0, x = 0; u < size && x < sizeof(address); u++) { @@ -956,7 +963,7 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, /* normal block */ SCLogDebug("normal block"); - if (DetectAddressParse2(de_ctx, gh, ghn, address, (negate + n_set) % 2) < 0) + if (DetectAddressParse2(de_ctx, gh, ghn, address, (negate + n_set) % 2, var_list) < 0) goto error; } else { /* negated block @@ -969,7 +976,7 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, DetectAddressHead tmp_gh = { NULL, NULL, NULL }; DetectAddressHead tmp_ghn = { NULL, NULL, NULL }; - if (DetectAddressParse2(de_ctx, &tmp_gh, &tmp_ghn, address, 0) < 0) + if (DetectAddressParse2(de_ctx, &tmp_gh, &tmp_ghn, address, 0, var_list) < 0) goto error; DetectAddress *tmp_ad; @@ -1037,6 +1044,7 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; + if (strlen(rule_var_address) == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "variable %s resolved " "to nothing. This is likely a misconfiguration. " @@ -1044,6 +1052,7 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, "\"!$HOME_NET\" instead of !$HOME_NET. See issue #295.", s); goto error; } + SCLogDebug("rule_var_address %s", rule_var_address); temp_rule_var_address = rule_var_address; if ((negate + n_set) % 2) { @@ -1053,8 +1062,12 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } - DetectAddressParse2(de_ctx, gh, ghn, temp_rule_var_address, - (negate + n_set) % 2); + + + if (DetectAddressParse2(de_ctx, gh, ghn, temp_rule_var_address, + (negate + n_set) % 2, var_list) < 0) + goto error; + d_set = 0; n_set = 0; if (temp_rule_var_address != rule_var_address) @@ -1089,6 +1102,7 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; + if (strlen(rule_var_address) == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "variable %s resolved " "to nothing. This is likely a misconfiguration. " @@ -1096,6 +1110,7 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, "\"!$HOME_NET\" instead of !$HOME_NET. See issue #295.", s); goto error; } + SCLogDebug("rule_var_address %s", rule_var_address); temp_rule_var_address = rule_var_address; if ((negate + n_set) % 2) { @@ -1105,8 +1120,9 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } + if (DetectAddressParse2(de_ctx, gh, ghn, temp_rule_var_address, - (negate + n_set) % 2) < 0) { + (negate + n_set) % 2, var_list) < 0) { SCLogDebug("DetectAddressParse2 hates us"); goto error; } @@ -1146,6 +1162,7 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, return 0; error: + return -1; } @@ -1368,6 +1385,8 @@ int DetectAddressTestConfVars(void) { SCLogDebug("Testing address conf vars for any misconfigured values"); + ResolvedVariablesList var_list = TAILQ_HEAD_INITIALIZER(var_list); + ConfNode *address_vars_node = ConfGetNode("vars.address-groups"); if (address_vars_node == NULL) { return 0; @@ -1394,7 +1413,10 @@ int DetectAddressTestConfVars(void) goto error; } - int r = DetectAddressParse2(NULL, gh, ghn, seq_node->val, /* start with negate no */0); + int r = DetectAddressParse2(NULL, gh, ghn, seq_node->val, /* start with negate no */0, &var_list); + + CleanVariableResolveList(&var_list); + if (r < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "failed to parse address var \"%s\" with value \"%s\". " @@ -1402,6 +1424,8 @@ int DetectAddressTestConfVars(void) goto error; } + CleanVariableResolveList(&var_list); + if (DetectAddressIsCompleteIPSpace(ghn)) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "address var - \"%s\" has the complete IP space negated " @@ -1453,7 +1477,7 @@ int DetectAddressParse(const DetectEngineCtx *de_ctx, goto error; } - r = DetectAddressParse2(de_ctx, gh, ghn, str, /* start with negate no */0); + r = DetectAddressParse2(de_ctx, gh, ghn, str, /* start with negate no */0, NULL); if (r < 0) { SCLogDebug("DetectAddressParse2 returned %d", r); goto error; diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index 1c9c0228f7c1..2585e6bdbef5 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -51,6 +51,7 @@ #include "pkt-var.h" #include "host.h" #include "util-profiling.h" +#include "util-var.h" static int DetectPortCutNot(DetectPort *, DetectPort **); static int DetectPortCut(DetectEngineCtx *, DetectPort *, DetectPort *, @@ -1025,7 +1026,7 @@ static int DetectPortParseInsertString(DetectPort **head, char *s) */ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, DetectPort **head, DetectPort **nhead, - char *s, int negate) + char *s, int negate, ResolvedVariablesList *var_list) { size_t u = 0; size_t x = 0; @@ -1037,6 +1038,12 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, char *rule_var_port = NULL; int r = 0; + if (AddVariableToResolveList(var_list, s) == -1) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Found a loop in a port " + "groups declaration. This is likely a misconfiguration."); + goto error; + } + SCLogDebug("head %p, *head %p, negate %d", head, *head, negate); for (u = 0, x = 0; u < size && x < sizeof(address); u++) { @@ -1065,7 +1072,7 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, SCLogDebug("Parsed port from DetectPortParseDo - %s", address); x = 0; - r = DetectPortParseDo(de_ctx, head, nhead, address, negate? negate: n_set); + r = DetectPortParseDo(de_ctx, head, nhead, address, negate? negate: n_set, var_list); if (r == -1) goto error; @@ -1103,7 +1110,7 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, temp_rule_var_port = alloc_rule_var_port; } r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port, - (negate + n_set) % 2);//negate? negate: n_set); + (negate + n_set) % 2, var_list);//negate? negate: n_set); if (r == -1) goto error; @@ -1163,7 +1170,7 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, temp_rule_var_port = alloc_rule_var_port; } r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port, - (negate + n_set) % 2); + (negate + n_set) % 2, var_list); if (r == -1) goto error; @@ -1337,6 +1344,8 @@ int DetectPortTestConfVars(void) { SCLogDebug("Testing port conf vars for any misconfigured values"); + ResolvedVariablesList var_list = TAILQ_HEAD_INITIALIZER(var_list); + ConfNode *port_vars_node = ConfGetNode("vars.port-groups"); if (port_vars_node == NULL) { return 0; @@ -1361,9 +1370,15 @@ int DetectPortTestConfVars(void) goto error; } - int r = DetectPortParseDo(NULL, &gh, &ghn, seq_node->val, /* start with negate no */0); + int r = DetectPortParseDo(NULL, &gh, &ghn, seq_node->val, /* start with negate no */0, &var_list); + + CleanVariableResolveList(&var_list); + if (r < 0) { DetectPortCleanupList(gh); + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, + "failed to parse port var \"%s\" with value \"%s\". " + "Please check it's syntax", seq_node->name, seq_node->val); goto error; } @@ -1409,7 +1424,7 @@ int DetectPortParse(const DetectEngineCtx *de_ctx, /* negate port list */ DetectPort *nhead = NULL; - r = DetectPortParseDo(de_ctx, head, &nhead, str,/* start with negate no */0); + r = DetectPortParseDo(de_ctx, head, &nhead, str,/* start with negate no */0, NULL); if (r < 0) goto error; @@ -2786,7 +2801,7 @@ static int PortTestMatchDoubleNegation(void) int result = 0; DetectPort *head = NULL, *nhead = NULL; - if (DetectPortParseDo(NULL, &head, &nhead, "![!80]", 0) == -1) + if (DetectPortParseDo(NULL, &head, &nhead, "![!80]", 0, NULL) == -1) return result; result = (head != NULL); diff --git a/src/util-var.c b/src/util-var.c index e4e9689b35d9..40d4f7f31e83 100644 --- a/src/util-var.c +++ b/src/util-var.c @@ -128,3 +128,43 @@ void GenericVarRemove(GenericVar **list, GenericVar *gv) listgv = listgv->next; } } + +// Checks if a variable is already in a resolve list and if it's not, adds it. +int AddVariableToResolveList(ResolvedVariablesList *list, char *var) +{ + ResolvedVariable *p_item; + + if (list == NULL || var == NULL) + return 0; + + TAILQ_FOREACH(p_item, list, next) { + if (!strcmp(p_item->var_name, var)) { + return -1; + } + } + + p_item = SCMalloc(sizeof(ResolvedVariable)); + + if (unlikely(p_item == NULL)) { + return -1; + } + + strlcpy(p_item->var_name, var, sizeof(p_item->var_name) - 1); + TAILQ_INSERT_TAIL(list, p_item, next); + + return 0; +} + +void CleanVariableResolveList(ResolvedVariablesList *var_list) +{ + if (var_list == NULL) { + return; + } + + ResolvedVariable *p_item; + + while ((p_item = TAILQ_FIRST(var_list))) { + TAILQ_REMOVE(var_list, p_item, next); + SCFree(p_item); + } +} diff --git a/src/util-var.h b/src/util-var.h index 0cd8c3528b1f..dc284725ffa2 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -57,9 +57,21 @@ typedef struct XBit_ { uint32_t expire; } XBit; +// A list of variables we try to resolve while parsing configuration file. +// Helps to detect recursive declarations. +typedef struct ResolvedVariable_ { + char var_name[256]; + TAILQ_ENTRY(ResolvedVariable_) next; +} ResolvedVariable; + +typedef TAILQ_HEAD(, ResolvedVariable_) ResolvedVariablesList; + void GenericVarFree(GenericVar *); void GenericVarAppend(GenericVar **, GenericVar *); void GenericVarRemove(GenericVar **, GenericVar *); +int AddVariableToResolveList(ResolvedVariablesList *list, char *var); +void CleanVariableResolveList(ResolvedVariablesList *var_list); + #endif /* __UTIL_VAR_H__ */ From 5d34ac071d049d5b467fe472d7ddf1be6bd6bf9f Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Fri, 4 Mar 2016 22:29:02 +0100 Subject: [PATCH 1027/2553] rule-parsing: remove unnecessary code Those lines were included former to prevent possible null pointer dereference but that won't happen anymore with the rest of the rework done in the code. The code even results in a control flow issue reported by coverity scan, so just remove it. --- src/detect-msg.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/detect-msg.c b/src/detect-msg.c index eddf31197256..5a5f4c5dfd51 100644 --- a/src/detect-msg.c +++ b/src/detect-msg.c @@ -75,10 +75,6 @@ static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *msgstr) goto error; } - /* make sure that we don't proceed with null pointer */ - if (unlikely(str == NULL)) - goto error; - len = strlen(str); if (len == 0) goto error; From 57e0bd39e91f4edb72fb7be78d5c40682a188475 Mon Sep 17 00:00:00 2001 From: cardigliano Date: Tue, 20 Oct 2015 18:24:25 +0200 Subject: [PATCH 1028/2553] pkt acq: introduce break loop API This patch adds a new callback PktAcqBreakLoop() in TmModule to let packet acquisition modules define "break-loop" functions to terminate the capture loop. This is useful in case of blocking functions that need special actions to take place in order to stop the execution. Implement this for PF_RING --- src/source-af-packet.c | 1 + src/source-erf-dag.c | 1 + src/source-erf-file.c | 1 + src/source-ipfw.c | 1 + src/source-mpipe.c | 1 + src/source-napatech.c | 1 + src/source-netmap.c | 1 + src/source-nflog.c | 1 + src/source-nfq.c | 1 + src/source-pcap-file.c | 1 + src/source-pcap.c | 1 + src/source-pfring.c | 27 +++++++++++++++++++++++++++ src/tm-modules.h | 3 +++ src/tm-threads.c | 6 +++++- 14 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index f9eb865820d5..212e118424d1 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -271,6 +271,7 @@ void TmModuleReceiveAFPRegister (void) tmm_modules[TMM_RECEIVEAFP].ThreadInit = ReceiveAFPThreadInit; tmm_modules[TMM_RECEIVEAFP].Func = NULL; tmm_modules[TMM_RECEIVEAFP].PktAcqLoop = ReceiveAFPLoop; + tmm_modules[TMM_RECEIVEAFP].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = ReceiveAFPThreadExitStats; tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL; diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index f66407122fcf..76f5fe3d83e2 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -138,6 +138,7 @@ TmModuleReceiveErfDagRegister(void) tmm_modules[TMM_RECEIVEERFDAG].ThreadInit = ReceiveErfDagThreadInit; tmm_modules[TMM_RECEIVEERFDAG].Func = NULL; tmm_modules[TMM_RECEIVEERFDAG].PktAcqLoop = ReceiveErfDagLoop; + tmm_modules[TMM_RECEIVEERFDAG].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEERFDAG].ThreadExitPrintStats = ReceiveErfDagThreadExitStats; tmm_modules[TMM_RECEIVEERFDAG].ThreadDeinit = NULL; diff --git a/src/source-erf-file.c b/src/source-erf-file.c index 938621c40a31..5d8af87f7563 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -81,6 +81,7 @@ TmModuleReceiveErfFileRegister(void) tmm_modules[TMM_RECEIVEERFFILE].ThreadInit = ReceiveErfFileThreadInit; tmm_modules[TMM_RECEIVEERFFILE].Func = NULL; tmm_modules[TMM_RECEIVEERFFILE].PktAcqLoop = ReceiveErfFileLoop; + tmm_modules[TMM_RECEIVEERFFILE].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEERFFILE].ThreadExitPrintStats = ReceiveErfFileThreadExitStats; tmm_modules[TMM_RECEIVEERFFILE].ThreadDeinit = NULL; diff --git a/src/source-ipfw.c b/src/source-ipfw.c index 4c68958bed94..e3e0e4986e32 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -158,6 +158,7 @@ void TmModuleReceiveIPFWRegister (void) tmm_modules[TMM_RECEIVEIPFW].ThreadInit = ReceiveIPFWThreadInit; tmm_modules[TMM_RECEIVEIPFW].Func = NULL; tmm_modules[TMM_RECEIVEIPFW].PktAcqLoop = ReceiveIPFWLoop; + tmm_modules[TMM_RECEIVEIPFW].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEIPFW].ThreadExitPrintStats = ReceiveIPFWThreadExitStats; tmm_modules[TMM_RECEIVEIPFW].ThreadDeinit = ReceiveIPFWThreadDeinit; tmm_modules[TMM_RECEIVEIPFW].cap_flags = SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | diff --git a/src/source-mpipe.c b/src/source-mpipe.c index 9fdebf65a0eb..fa9d14ce387b 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -173,6 +173,7 @@ void TmModuleReceiveMpipeRegister (void) tmm_modules[TMM_RECEIVEMPIPE].ThreadInit = ReceiveMpipeThreadInit; tmm_modules[TMM_RECEIVEMPIPE].Func = NULL; tmm_modules[TMM_RECEIVEMPIPE].PktAcqLoop = ReceiveMpipeLoop; + tmm_modules[TMM_RECEIVEMPIPE].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEMPIPE].ThreadExitPrintStats = ReceiveMpipeThreadExitStats; tmm_modules[TMM_RECEIVEMPIPE].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEMPIPE].RegisterTests = NULL; diff --git a/src/source-napatech.c b/src/source-napatech.c index 27432314e893..5566e4022794 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -110,6 +110,7 @@ void TmModuleNapatechStreamRegister(void) tmm_modules[TMM_RECEIVENAPATECH].ThreadInit = NapatechStreamThreadInit; tmm_modules[TMM_RECEIVENAPATECH].Func = NULL; tmm_modules[TMM_RECEIVENAPATECH].PktAcqLoop = NapatechStreamLoop; + tmm_modules[TMM_RECEIVENAPATECH].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVENAPATECH].ThreadExitPrintStats = NapatechStreamThreadExitStats; tmm_modules[TMM_RECEIVENAPATECH].ThreadDeinit = NapatechStreamThreadDeinit; tmm_modules[TMM_RECEIVENAPATECH].RegisterTests = NULL; diff --git a/src/source-netmap.c b/src/source-netmap.c index 73930118c1f0..061635b64768 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -1069,6 +1069,7 @@ void TmModuleReceiveNetmapRegister(void) tmm_modules[TMM_RECEIVENETMAP].ThreadInit = ReceiveNetmapThreadInit; tmm_modules[TMM_RECEIVENETMAP].Func = NULL; tmm_modules[TMM_RECEIVENETMAP].PktAcqLoop = ReceiveNetmapLoop; + tmm_modules[TMM_RECEIVENETMAP].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVENETMAP].ThreadExitPrintStats = ReceiveNetmapThreadExitStats; tmm_modules[TMM_RECEIVENETMAP].ThreadDeinit = ReceiveNetmapThreadDeinit; tmm_modules[TMM_RECEIVENETMAP].RegisterTests = NULL; diff --git a/src/source-nflog.c b/src/source-nflog.c index 7722244ffee1..858ad76c7918 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -117,6 +117,7 @@ void TmModuleReceiveNFLOGRegister (void) tmm_modules[TMM_RECEIVENFLOG].ThreadInit = ReceiveNFLOGThreadInit; tmm_modules[TMM_RECEIVENFLOG].Func = NULL; tmm_modules[TMM_RECEIVENFLOG].PktAcqLoop = ReceiveNFLOGLoop; + tmm_modules[TMM_RECEIVENFLOG].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVENFLOG].ThreadExitPrintStats = ReceiveNFLOGThreadExitStats; tmm_modules[TMM_RECEIVENFLOG].ThreadDeinit = ReceiveNFLOGThreadDeinit; tmm_modules[TMM_RECEIVENFLOG].RegisterTests = NULL; diff --git a/src/source-nfq.c b/src/source-nfq.c index 34c3734f0170..c8923f63d6b3 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -186,6 +186,7 @@ void TmModuleReceiveNFQRegister (void) tmm_modules[TMM_RECEIVENFQ].ThreadInit = ReceiveNFQThreadInit; tmm_modules[TMM_RECEIVENFQ].Func = NULL; tmm_modules[TMM_RECEIVENFQ].PktAcqLoop = ReceiveNFQLoop; + tmm_modules[TMM_RECEIVENFQ].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVENFQ].ThreadExitPrintStats = ReceiveNFQThreadExitStats; tmm_modules[TMM_RECEIVENFQ].ThreadDeinit = ReceiveNFQThreadDeinit; tmm_modules[TMM_RECEIVENFQ].RegisterTests = NULL; diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 0b982fd3ab13..5f970d64fb84 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -114,6 +114,7 @@ void TmModuleReceivePcapFileRegister (void) tmm_modules[TMM_RECEIVEPCAPFILE].ThreadInit = ReceivePcapFileThreadInit; tmm_modules[TMM_RECEIVEPCAPFILE].Func = NULL; tmm_modules[TMM_RECEIVEPCAPFILE].PktAcqLoop = ReceivePcapFileLoop; + tmm_modules[TMM_RECEIVEPCAPFILE].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadExitPrintStats = ReceivePcapFileThreadExitStats; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadDeinit = ReceivePcapFileThreadDeinit; tmm_modules[TMM_RECEIVEPCAPFILE].RegisterTests = NULL; diff --git a/src/source-pcap.c b/src/source-pcap.c index 1f0c59bd618e..7c7a53e8c9a5 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -128,6 +128,7 @@ void TmModuleReceivePcapRegister (void) tmm_modules[TMM_RECEIVEPCAP].ThreadInit = ReceivePcapThreadInit; tmm_modules[TMM_RECEIVEPCAP].Func = NULL; tmm_modules[TMM_RECEIVEPCAP].PktAcqLoop = ReceivePcapLoop; + tmm_modules[TMM_RECEIVEPCAP].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEPCAP].ThreadExitPrintStats = ReceivePcapThreadExitStats; tmm_modules[TMM_RECEIVEPCAP].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEPCAP].RegisterTests = NULL; diff --git a/src/source-pfring.c b/src/source-pfring.c index 527086f564c7..e1a811abe1cb 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -62,6 +62,7 @@ #endif /* __SC_CUDA_SUPPORT__ */ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot); +TmEcode PfringBreakLoop(ThreadVars *tv, void *data); TmEcode ReceivePfringThreadInit(ThreadVars *, void *, void **); void ReceivePfringThreadExitStats(ThreadVars *, void *); TmEcode ReceivePfringThreadDeinit(ThreadVars *, void *); @@ -175,6 +176,7 @@ void TmModuleReceivePfringRegister (void) tmm_modules[TMM_RECEIVEPFRING].ThreadInit = ReceivePfringThreadInit; tmm_modules[TMM_RECEIVEPFRING].Func = NULL; tmm_modules[TMM_RECEIVEPFRING].PktAcqLoop = ReceivePfringLoop; + tmm_modules[TMM_RECEIVEPFRING].PktAcqBreakLoop = PfringBreakLoop; tmm_modules[TMM_RECEIVEPFRING].ThreadExitPrintStats = ReceivePfringThreadExitStats; tmm_modules[TMM_RECEIVEPFRING].ThreadDeinit = ReceivePfringThreadDeinit; tmm_modules[TMM_RECEIVEPFRING].RegisterTests = NULL; @@ -379,6 +381,31 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) return TM_ECODE_OK; } +/** + * \brief Stop function for ReceivePfringLoop. + * + * This function forces ReceivePfringLoop to stop the + * execution, exiting the packet capture loop. + * + * \param tv pointer to ThreadVars + * \param data pointer that gets cast into PfringThreadVars for ptv + * \retval TM_ECODE_OK on success + * \retval TM_ECODE_FAILED on failure + */ +TmEcode PfringBreakLoop(ThreadVars *tv, void *data) +{ + PfringThreadVars *ptv = (PfringThreadVars *)data; + + /* Safety check */ + if (ptv->pd == NULL) { + return TM_ECODE_FAILED; + } + + pfring_breakloop(ptv->pd); + + return TM_ECODE_OK; +} + /** * \brief Init function for RecievePfring. * diff --git a/src/tm-modules.h b/src/tm-modules.h index c9d4e1f56e3f..3486ebf04af4 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -49,6 +49,9 @@ typedef struct TmModule_ { TmEcode (*PktAcqLoop)(ThreadVars *, void *, void *); + /** terminates the capture loop in PktAcqLoop */ + TmEcode (*PktAcqBreakLoop)(ThreadVars *, void *); + TmEcode (*Management)(ThreadVars *, void *); /** global Init/DeInit */ diff --git a/src/tm-threads.c b/src/tm-threads.c index 2b26404fbaaf..f0990f13432f 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1438,10 +1438,11 @@ void TmThreadDisableReceiveThreads(void) * with all receive threads */ while (tv) { int disable = 0; + TmModule *tm = NULL; /* obtain the slots for this TV */ TmSlot *slots = tv->tm_slots; while (slots != NULL) { - TmModule *tm = TmModuleGetById(slots->tm_id); + tm = TmModuleGetById(slots->tm_id); if (tm->flags & TM_FLAG_RECEIVE_TM) { disable = 1; @@ -1470,6 +1471,9 @@ void TmThreadDisableReceiveThreads(void) } /* we found a receive TV. Send it a KILL_PKTACQ signal. */ + if (tm && tm->PktAcqBreakLoop != NULL) { + tm->PktAcqBreakLoop(tv, SC_ATOMIC_GET(slots->slot_data)); + } TmThreadsSetFlag(tv, THV_KILL_PKTACQ); if (tv->inq != NULL) { From 219762b7d9e8fbe0ca4b8e339140ffef603996cc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 3 Mar 2016 11:44:42 +0100 Subject: [PATCH 1029/2553] pfring: small cleanup --- src/source-pfring.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index e1a811abe1cb..7f005bce5566 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -491,11 +491,11 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) pfconf->DerefFunc(pfconf); SCFree(ptv); return TM_ECODE_FAILED; - } else { - pfring_set_application_name(ptv->pd, PROG_NAME); - pfring_version(ptv->pd, &version); } + pfring_set_application_name(ptv->pd, PROG_NAME); + pfring_version(ptv->pd, &version); + /* We only set cluster info if the number of pfring threads is greater than 1 */ ptv->threads = pfconf->threads; From 27b02402e70700c46ec6272b70ae6962fb42d867 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Feb 2016 00:33:58 +0100 Subject: [PATCH 1030/2553] gre: support transparent ethernet bridge decoding --- src/decode-ethernet.h | 1 + src/decode-gre.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/decode-ethernet.h b/src/decode-ethernet.h index f8ede8803ffc..094d2548e785 100644 --- a/src/decode-ethernet.h +++ b/src/decode-ethernet.h @@ -30,6 +30,7 @@ #define ETHERNET_TYPE_PUP 0x0200 /* PUP protocol */ #define ETHERNET_TYPE_IP 0x0800 #define ETHERNET_TYPE_ARP 0x0806 +#define ETHERNET_TYPE_BRIDGE 0x6558 /* transparant ethernet bridge (GRE) */ #define ETHERNET_TYPE_REVARP 0x8035 #define ETHERNET_TYPE_EAPOL 0x888e #define ETHERNET_TYPE_IPV6 0x86dd diff --git a/src/decode-gre.c b/src/decode-gre.c index 6ad9e39758d8..4c555ac010fd 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -262,6 +262,19 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui break; } + case ETHERNET_TYPE_BRIDGE: + { + if (pq != NULL) { + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, + len - header_len, DECODE_TUNNEL_ETHERNET, pq); + if (tp != NULL) { + PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); + PacketEnqueue(pq,tp); + } + } + break; + } + default: return TM_ECODE_OK; } From ab3aed7d251f5abec3b11bbf8af61f3815e33409 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 3 Mar 2016 10:35:19 +0100 Subject: [PATCH 1031/2553] decode: update icmpv6 message handling This patch adds two new events relative to icmpv6. One for packets using unassigned icmpv6 type. The second one for packets using private experimentation type. Icmpv6 type table taken from http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-2 --- rules/decoder-events.rules | 7 +++++-- src/decode-events.h | 2 ++ src/decode-icmpv6.c | 23 ++++++++++++++++++++--- src/detect-engine-event.h | 2 ++ 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/rules/decoder-events.rules b/rules/decoder-events.rules index 314c0f9268e7..4a20197fd5c3 100644 --- a/rules/decoder-events.rules +++ b/rules/decoder-events.rules @@ -52,11 +52,14 @@ alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 unknown code"; decode-even alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 truncated packet"; decode-event:icmpv4.ipv4_trunc_pkt; sid:2200026; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 unknown version"; decode-event:icmpv4.ipv4_unknown_ver; sid:2200027; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 packet too small"; decode-event:icmpv6.pkt_too_small; sid:2200028; rev:1;) -alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown type"; decode-event:icmpv6.unknown_type; sid:2200029; rev:1;) +# uncomment the following sginature if you plan to update suricata code to support more ICMPv6 type +#alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown type"; decode-event:icmpv6.unknown_type; sid:2200029; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown code"; decode-event:icmpv6.unknown_code; sid:2200030; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 truncated packet"; decode-event:icmpv6.ipv6_trunc_pkt; sid:2200031; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown version"; decode-event:icmpv6.ipv6_unknown_version; sid:2200032; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 MLD hop limit not 1"; decode-event:icmpv6.mld_message_with_invalid_hl; sid:2200102; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unassigned type"; decode-event:icmpv6.unassigned_type; sid:2200108; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 private experimentation type"; decode-event:icmpv6.experimentation_type; sid:2200109; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP packet too small"; decode-event:tcp.pkt_too_small; sid:2200033; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP header length too small"; decode-event:tcp.hlen_too_small; sid:2200034; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP invalid option length"; decode-event:tcp.invalid_optlen; sid:2200035; rev:1;) @@ -134,5 +137,5 @@ alert pkthdr any any -> any any (msg:"SURICATA ERSPAN pkt too small"; decode-eve alert pkthdr any any -> any any (msg:"SURICATA ERSPAN unsupported version"; decode-event:erspan.unsupported_version; sid: 2200106; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ERSPAN too many vlan layers"; decode-event:erspan.too_many_vlan_layers; sid: 2200107; rev:1;) -# next sid is 2200108 +# next sid is 2200110 diff --git a/src/decode-events.h b/src/decode-events.h index c16d0d92d6a1..51889387a143 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -58,6 +58,8 @@ enum { ICMPV6_IPV6_UNKNOWN_VER, /**< unknown version in icmpv6 packet */ ICMPV6_IPV6_TRUNC_PKT, /**< truncated icmpv6 packet */ ICMPV6_MLD_MESSAGE_WITH_INVALID_HL, /**< invalid MLD that doesn't have HL 1 */ + ICMPV6_UNASSIGNED_TYPE, /**< unsassigned ICMPv6 type */ + ICMPV6_EXPERIMENTATION_TYPE, /**< uprivate experimentation ICMPv6 type */ /* IPV6 EVENTS */ IPV6_PKT_TOO_SMALL, /**< ipv6 packet smaller than minimum size */ diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index 7972ea797c98..a7a77b5a1967 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -321,9 +321,26 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, } break; default: - SCLogDebug("ICMPV6 Message type %" PRIu8 " not " - "implemented yet", ICMPV6_GET_TYPE(p)); - ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_TYPE); + /* Various range taken from: + * http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-2 + */ + if ((ICMPV6_GET_TYPE(p) > 4) && (ICMPV6_GET_TYPE(p) < 100)) { + ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); + } else if ((ICMPV6_GET_TYPE(p) >= 100) && (ICMPV6_GET_TYPE(p) < 102)) { + ENGINE_SET_EVENT(p, ICMPV6_EXPERIMENTATION_TYPE); + } else if ((ICMPV6_GET_TYPE(p) >= 102) && (ICMPV6_GET_TYPE(p) < 127)) { + ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); + } else if ((ICMPV6_GET_TYPE(p) >= 160) && (ICMPV6_GET_TYPE(p) < 200)) { + ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); + } else if ((ICMPV6_GET_TYPE(p) >= 200) && (ICMPV6_GET_TYPE(p) < 202)) { + ENGINE_SET_EVENT(p, ICMPV6_EXPERIMENTATION_TYPE); + } else if (ICMPV6_GET_TYPE(p) >= 202) { + ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); + } else { + SCLogDebug("ICMPV6 Message type %" PRIu8 " not " + "implemented yet", ICMPV6_GET_TYPE(p)); + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_TYPE); + } } /* for a info message the header is just 4 bytes */ diff --git a/src/detect-engine-event.h b/src/detect-engine-event.h index 9d6424fbdb48..9ee152766ee0 100644 --- a/src/detect-engine-event.h +++ b/src/detect-engine-event.h @@ -71,6 +71,8 @@ struct DetectEngineEvents_ { { "icmpv6.ipv6_unknown_version", ICMPV6_IPV6_UNKNOWN_VER,}, { "icmpv6.ipv6_trunc_pkt", ICMPV6_IPV6_TRUNC_PKT,}, { "icmpv6.mld_message_with_invalid_hl", ICMPV6_MLD_MESSAGE_WITH_INVALID_HL,}, + { "icmpv6.unassigned_type", ICMPV6_UNASSIGNED_TYPE,}, + { "icmpv6.experimentation_type", ICMPV6_EXPERIMENTATION_TYPE,}, /* IPV6 EVENTS */ { "ipv6.pkt_too_small", IPV6_PKT_TOO_SMALL, }, From c49145a79aab1cf010a1e1766d6329555881a231 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 13:33:16 +0100 Subject: [PATCH 1032/2553] log-filestore: suppress unused code Code was unused and was leaking memory. This fixes: Direct leak of 614240 byte(s) in 3839 object(s) allocated from: #0 0x4c396b in malloc (/opt/suricata-asan/bin/suricata+0x4c396b) #1 0x11bc12e in LogFileNewCtx /home/pmanev/sandnet-qa/stage/oisf/src/util-logopenfile.c:474:27 #2 0xcf7ef2 in LogFilestoreLogInitCtx /home/pmanev/sandnet-qa/stage/oisf/src/log-filestore.c:430:31 #3 0xec3275 in RunModeInitializeOutputs /home/pmanev/sandnet-qa/stage/oisf/src/runmodes.c:763:26 #4 0xeae17f in UnixSocketPcapFilesCheck /home/pmanev/sandnet-qa/stage/oisf/src/runmode-unix-socket.c:391:9 #5 0x109bc37 in UnixCommandBackgroundTasks /home/pmanev/sandnet-qa/stage/oisf/src/unix-manager.c:430:20 #6 0x10a9be2 in UnixManager /home/pmanev/sandnet-qa/stage/oisf/src/unix-manager.c:977:9 #7 0x1075643 in TmThreadsManagement /home/pmanev/sandnet-qa/stage/oisf/src/tm-threads.c:600:9 #8 0x7fbc9fcb3181 in start_thread /build/eglibc-3GlaMS/eglibc-2.19/nptl/pthread_create.c:312 --- src/log-filestore.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/log-filestore.c b/src/log-filestore.c index 5069ec857921..c2507163fbd2 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -427,12 +427,6 @@ static void LogFilestoreLogDeInitCtx(OutputCtx *output_ctx) * */ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) { - LogFileCtx *logfile_ctx = LogFileNewCtx(); - if (logfile_ctx == NULL) { - SCLogDebug("Could not create new LogFilestoreCtx"); - return NULL; - } - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; From 24e4edd118c697adb6a0839cfecd18868379dfb9 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 13:38:54 +0100 Subject: [PATCH 1033/2553] output-file: fix memleak This fixes: Direct leak of 31856 byte(s) in 3982 object(s) allocated from: #0 0x4c396b in malloc (/opt/suricata-asan/bin/suricata+0x4c396b) #1 0xd7ff39 in OutputFileLogThreadInit /home/pmanev/sandnet-qa/stage/oisf/src/output-file.c:182:34 #2 0x106c255 in TmThreadsSlotPktAcqLoop /home/pmanev/sandnet-qa/stage/oisf/src/tm-threads.c:295:17 #3 0x7fbc9fcb3181 in start_thread /build/eglibc-3GlaMS/eglibc-2.19/nptl/pthread_create.c:312 --- src/output-file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output-file.c b/src/output-file.c index 0f1e85210672..bd266c77ac74 100644 --- a/src/output-file.c +++ b/src/output-file.c @@ -249,6 +249,8 @@ static TmEcode OutputFileLogThreadDeinit(ThreadVars *tv, void *thread_data) store = next_store; logger = logger->next; } + + SCFree(op_thread_data); return TM_ECODE_OK; } From d0ebe04c8b376b1c6ff537023a480a4ea2619ef6 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 13:43:07 +0100 Subject: [PATCH 1034/2553] output-packet: fix memleak This fixes: Direct leak of 31832 byte(s) in 3979 object(s) allocated from: #0 0x4c396b in malloc (/opt/suricata-asan/bin/suricata+0x4c396b) #1 0xe22129 in OutputPacketLogThreadInit /home/pmanev/sandnet-qa/stage/oisf/src/output-packet.c:123:34 #2 0x106c255 in TmThreadsSlotPktAcqLoop /home/pmanev/sandnet-qa/stage/oisf/src/tm-threads.c:295:17 #3 0x7fbc9fcb3181 in start_thread /build/eglibc-3GlaMS/eglibc-2.19/nptl/pthread_create.c:312 --- src/output-packet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output-packet.c b/src/output-packet.c index d2cd901c88bb..7e2b550b1157 100644 --- a/src/output-packet.c +++ b/src/output-packet.c @@ -191,6 +191,8 @@ static TmEcode OutputPacketLogThreadDeinit(ThreadVars *tv, void *thread_data) logger = logger->next; } + + SCFree(op_thread_data); return TM_ECODE_OK; } From 2866f87c6d4569b474ec0eb2a6d2a728782f3f4d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 13:47:50 +0100 Subject: [PATCH 1035/2553] output-filedata: fix memleak This fixes: Direct leak of 31792 byte(s) in 3974 object(s) allocated from: #0 0x4c396b in malloc (/opt/suricata-asan/bin/suricata+0x4c396b) #1 0xd86ce2 in OutputFiledataLogThreadInit /home/pmanev/sandnet-qa/stage/oisf/src/output-filedata.c:308:34 #2 0x106c255 in TmThreadsSlotPktAcqLoop /home/pmanev/sandnet-qa/stage/oisf/src/tm-threads.c:295:17 #3 0x7fbc9fcb3181 in start_thread /build/eglibc-3GlaMS/eglibc-2.19/nptl/pthread_create.c:312 --- src/output-filedata.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output-filedata.c b/src/output-filedata.c index 8f466bafc6a0..9818339dfc37 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -434,6 +434,8 @@ static TmEcode OutputFiledataLogThreadDeinit(ThreadVars *tv, void *thread_data) g_waldo_deinit = 1; } SCMutexUnlock(&g_waldo_mutex); + + SCFree(op_thread_data); return TM_ECODE_OK; } From 2c755b5fc7b2d0148344db2c6d09eb67f537cb9b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 13:50:26 +0100 Subject: [PATCH 1036/2553] output-tx: fix memleak This fixes: Direct leak of 31752 byte(s) in 3969 object(s) allocated from: #0 0x4c396b in malloc (/opt/suricata-asan/bin/suricata+0x4c396b) #1 0xe385b9 in OutputTxLogThreadInit /home/pmanev/sandnet-qa/stage/oisf/src/output-tx.c:193:34 #2 0x106c255 in TmThreadsSlotPktAcqLoop /home/pmanev/sandnet-qa/stage/oisf/src/tm-threads.c:295:17 #3 0x7fbc9fcb3181 in start_thread /build/eglibc-3GlaMS/eglibc-2.19/nptl/pthread_create.c:312 --- src/output-tx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output-tx.c b/src/output-tx.c index 93ba9956042b..e05c540a076d 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -260,6 +260,8 @@ static TmEcode OutputTxLogThreadDeinit(ThreadVars *tv, void *thread_data) store = next_store; logger = logger->next; } + + SCFree(op_thread_data); return TM_ECODE_OK; } From b1f907a58f764931b39818d8c72c7d41970552fd Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 17:59:45 +0100 Subject: [PATCH 1037/2553] unix-manager: fix memleak This fixes: 2,595 (1,824 direct, 771 indirect) bytes in 57 blocks are definitely lost in loss record 328 of 332 at 0x4C29C0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x66D0C7B: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0) by 0x911A27: UnixManagerListCommand (unix-manager.c:766) by 0x9108A9: UnixCommandExecute (unix-manager.c:486) by 0x910D9E: UnixCommandRun (unix-manager.c:545) by 0x9111B3: UnixMain (unix-manager.c:593) by 0x913D27: UnixManager (unix-manager.c:961) by 0x907773: TmThreadsManagement (tm-threads.c:600) by 0x68DE283: start_thread (pthread_create.c:333) by 0x80A6A4C: clone (in /lib/x86_64-linux-gnu/libc-2.21.so) --- src/unix-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index a7f0052e2382..19922cce7edb 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -763,7 +763,7 @@ TmEcode UnixManagerListCommand(json_t *cmd, } TAILQ_FOREACH(lcmd, &gcmd->commands, next) { - json_array_append(jarray, json_string(lcmd->name)); + json_array_append_new(jarray, json_string(lcmd->name)); i++; } From cc942b4fb8bc9feaf8e7772674028147ebd17ea2 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 18:03:54 +0100 Subject: [PATCH 1038/2553] runmodes: fix memleak active_runmode value was leaking in unix socket mode. --- src/runmodes.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/runmodes.c b/src/runmodes.c index 998780d8b4bb..d9e06af78521 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -360,6 +360,9 @@ void RunModeDispatch(int runmode, const char *custom_mode) } /* Export the custom mode */ + if (active_runmode) { + SCFree(active_runmode); + } active_runmode = SCStrdup(custom_mode); if (unlikely(active_runmode == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup active mode"); From 606ac17c5786c98953e8bf1f60d9c3546cd5b6cc Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 18:04:31 +0100 Subject: [PATCH 1039/2553] util: get rid of json_array_append This function is causing a memleak because it is necessary to clean up after usage. This fixes at least: 37 (32 direct, 5 indirect) bytes in 1 blocks are definitely lost in loss record 104 of 394 at 0x4C29C0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x66D0C7B: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0) by 0x943584: LiveDeviceIfaceList (util-device.c:264) by 0x910889: UnixCommandExecute (unix-manager.c:486) by 0x910D7E: UnixCommandRun (unix-manager.c:545) by 0x911193: UnixMain (unix-manager.c:593) by 0x913CC7: UnixManager (unix-manager.c:961) by 0x907753: TmThreadsManagement (tm-threads.c:600) by 0x68DE283: start_thread (pthread_create.c:333) by 0x80A6A4C: clone (in /lib/x86_64-linux-gnu/libc-2.21.so) --- src/util-device.c | 2 +- src/util-profiling-rules.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-device.c b/src/util-device.c index fb2c04f649eb..9332fcec4f5c 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -261,7 +261,7 @@ TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *answer, void *data) return TM_ECODE_FAILED; } TAILQ_FOREACH(pd, &live_devices, next) { - json_array_append(jarray, json_string(pd->dev)); + json_array_append_new(jarray, json_string(pd->dev)); i++; } diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index 3d679384bbed..870f7b9705fe 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -334,7 +334,7 @@ static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64 double percent = (long double)summary[i].ticks / (long double)total_ticks * 100; json_object_set_new(jsm, "percent", json_integer(percent)); - json_array_append(jsa, jsm); + json_array_append_new(jsa, jsm); } } json_object_set_new(js, "rules", jsa); From f1f2f0d4782103b8aaaed656d5185a5d77a0e161 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 18:25:43 +0100 Subject: [PATCH 1040/2553] util-host-info: fix memleaks This fixes pcre related memory leak in SCKernelVersionIsAtLeast function. --- src/util-host-info.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util-host-info.c b/src/util-host-info.c index c7ea8adf6cf7..2e06c636de10 100644 --- a/src/util-host-info.c +++ b/src/util-host-info.c @@ -86,6 +86,8 @@ int SCKernelVersionIsAtLeast(int major, int minor) kminor = atoi(list[2]); pcre_free_substring_list(list); + pcre_free_study(version_regex_study); + pcre_free(version_regex); if (kmajor > major) return 1; From f34fe85cfedc68e5c5c06a0d699d99b1e9616197 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 18:36:00 +0100 Subject: [PATCH 1041/2553] unix-manager: fix memleak at exit Buffer allocated for UnixClient was not correctly freed. --- src/unix-manager.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/unix-manager.c b/src/unix-manager.c index 19922cce7edb..c2b87ad3d9ea 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -580,6 +580,9 @@ int UnixMain(UnixCommand * this) } if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) { + UnixCommandClose(this, uclient->fd); + } return 1; } From de6a37f17bf6be9628564486c1625a7aa55c22ca Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 19:13:43 +0100 Subject: [PATCH 1042/2553] tm-queue: unify queue name handling Queue name was sometimes allocated and sometimes not. This patch updates the behavior of creation function so it is always allocated. This way we can free it at exit and fix memory leak. This fixes: 900 bytes in 110 blocks are definitely lost in loss record 322 of 329 at 0x4C29C0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x803E0A9: strdup (in /lib/x86_64-linux-gnu/libc-2.21.so) by 0x90090E: StoreQueueId (tmqh-flow.c:112) by 0x8FFEA8: TmqhOutputFlowSetupCtx (tmqh-flow.c:180) by 0x908C7F: TmThreadCreate (tm-threads.c:1095) by 0x909982: TmThreadCreatePacketHandler (tm-threads.c:1154) by 0x87906F: RunModeFilePcapAutoFp (runmode-pcap-file.c:188) by 0x88376B: RunModeDispatch (runmodes.c:372) by 0x87F245: UnixSocketPcapFilesCheck (runmode-unix-socket.c:393) by 0x9102B0: UnixCommandBackgroundTasks (unix-manager.c:430) by 0x91405D: UnixManager (unix-manager.c:980) by 0x907773: TmThreadsManagement (tm-threads.c:600) tm-queue: fix logic WIP --- src/tm-queues.c | 11 ++++++++++- src/tmqh-flow.c | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/tm-queues.c b/src/tm-queues.c index e549a975c7b0..b956c714984c 100644 --- a/src/tm-queues.c +++ b/src/tm-queues.c @@ -52,7 +52,10 @@ Tmq* TmqCreateQueue(char *name) goto error; Tmq *q = &tmqs[tmq_id]; - q->name = name; + q->name = SCStrdup(name); + if (q->name == NULL) + goto error; + q->id = tmq_id++; /* for cuda purposes */ q->q_type = 0; @@ -90,6 +93,12 @@ void TmqDebugList(void) void TmqResetQueues(void) { + uint16_t i; + for (i = 0; i < TMQ_MAX_QUEUES; i++) { + if (tmqs[i].name) { + SCFree(tmqs[i].name); + } + } memset(&tmqs, 0x00, sizeof(tmqs)); tmq_id = 0; } diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index c0898ef0afcb..6ea8917bdba2 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -109,7 +109,7 @@ static int StoreQueueId(TmqhFlowCtx *ctx, char *name) void *ptmp; Tmq *tmq = TmqGetQueueByName(name); if (tmq == NULL) { - tmq = TmqCreateQueue(SCStrdup(name)); + tmq = TmqCreateQueue(name); if (tmq == NULL) return -1; } From 41e540f2f19df61c480d8bd30e761a8cff2c242e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 19:22:46 +0100 Subject: [PATCH 1043/2553] tm-threads: fix memleak Fix cleaning of threads where mutex and condition where not freed. This fixes: 352 (192 direct, 160 indirect) bytes in 4 blocks are definitely lost in loss record 301 of 327 at 0x4C29C0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x909404: TmThreadInitMC (tm-threads.c:1764) by 0x908DE7: TmThreadCreate (tm-threads.c:1120) by 0x90A326: TmThreadCreateMgmtThread (tm-threads.c:1183) by 0x4CA0AD: StatsSpawnThreads (counters.c:856) by 0x87F254: UnixSocketPcapFilesCheck (runmode-unix-socket.c:396) by 0x910330: UnixCommandBackgroundTasks (unix-manager.c:430) by 0x9140DD: UnixManager (unix-manager.c:980) by 0x9077F3: TmThreadsManagement (tm-threads.c:600) by 0x68DE283: start_thread (pthread_create.c:333) by 0x80A6A4C: clone (in /lib/x86_64-linux-gnu/libc-2.21.so) --- src/tm-threads.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/tm-threads.c b/src/tm-threads.c index f0990f13432f..d5326e9f2385 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -73,6 +73,8 @@ __thread uint64_t rwr_lock_cnt; /* prototypes */ static int SetCPUAffinity(uint16_t cpu); +static void TmThreadDeinitMC(ThreadVars *tv); + /* root of the threadvars list */ ThreadVars *tv_root[TVT_MAX] = { NULL }; @@ -1654,6 +1656,8 @@ void TmThreadFree(ThreadVars *tv) StatsThreadCleanup(tv); + TmThreadDeinitMC(tv); + s = (TmSlot *)tv->tm_slots; while (s) { ps = s; @@ -1780,6 +1784,19 @@ void TmThreadInitMC(ThreadVars *tv) return; } +static void TmThreadDeinitMC(ThreadVars *tv) +{ + if (tv->ctrl_mutex) { + SCCtrlMutexDestroy(tv->ctrl_mutex); + SCFree(tv->ctrl_mutex); + } + if (tv->ctrl_cond) { + SCCtrlCondDestroy(tv->ctrl_cond); + SCFree(tv->ctrl_cond); + } + return; +} + /** * \brief Tests if the thread represented in the arg has been unpaused or not. * From c2e2174942d562bcf86777576b821381c3ef3bc7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 19:33:25 +0100 Subject: [PATCH 1044/2553] tmqh-flow: fix memleak in TmqhFlowCtx cleaning This fixes: 96 bytes in 4 blocks are definitely lost in loss record 178 of 320 at 0x4C29C0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x8FF88C: TmqhOutputFlowSetupCtx (tmqh-flow.c:163) by 0x908D5F: TmThreadCreate (tm-threads.c:1097) by 0x909A62: TmThreadCreatePacketHandler (tm-threads.c:1156) by 0x8790CF: RunModeFilePcapAutoFp (runmode-pcap-file.c:188) by 0x8837CB: RunModeDispatch (runmodes.c:372) by 0x87F2A5: UnixSocketPcapFilesCheck (runmode-unix-socket.c:393) by 0x910460: UnixCommandBackgroundTasks (unix-manager.c:430) by 0x91420D: UnixManager (unix-manager.c:980) by 0x907853: TmThreadsManagement (tm-threads.c:602) by 0x68DE283: start_thread (pthread_create.c:333) by 0x80A6A4C: clone (in /lib/x86_64-linux-gnu/libc-2.21.so) --- src/tmqh-flow.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index 6ea8917bdba2..a1ec839bcfbe 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -217,6 +217,7 @@ void TmqhOutputFlowFreeCtx(void *ctx) } SCFree(fctx->queues); + SCFree(fctx); return; } From 55a8f3ce1dca0b2074d65d520e5a6b087e7403d3 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 19:36:43 +0100 Subject: [PATCH 1045/2553] output-stats: fix memleak This fixes: 16 bytes in 2 blocks are definitely lost in loss record 69 of 319 at 0x4C29C0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x85955D: OutputStatsLogThreadInit (output-stats.c:118) by 0x4CAE13: StatsMgmtThread (counters.c:352) by 0x68DE283: start_thread (pthread_create.c:333) by 0x80A6A4C: clone (in /lib/x86_64-linux-gnu/libc-2.21.so) --- src/output-stats.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output-stats.c b/src/output-stats.c index a6752fc5b7ae..8309755de62c 100644 --- a/src/output-stats.c +++ b/src/output-stats.c @@ -186,6 +186,8 @@ static TmEcode OutputStatsLogThreadDeinit(ThreadVars *tv, void *thread_data) store = next_store; logger = logger->next; } + + SCFree(op_thread_data); return TM_ECODE_OK; } From d3677506333e47323093fadc7c24621ae98699a8 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 20:52:45 +0100 Subject: [PATCH 1046/2553] defrag: free defrag tree at exit This fixes: 72 bytes in 3 blocks are definitely lost in loss record 153 of 316 at 0x4C29C0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x9AF041: SCRadixCreateRadixTree (util-radix-tree.c:430) by 0x50FF5D: DefragPolicyLoadFromConfig (defrag-config.c:138) by 0x5129F5: DefragInit (defrag.c:962) by 0x87ECFD: UnixSocketPcapFilesCheck (runmode-unix-socket.c:386) by 0x90FEC0: UnixCommandBackgroundTasks (unix-manager.c:430) by 0x913C6D: UnixManager (unix-manager.c:980) by 0x9072F3: TmThreadsManagement (tm-threads.c:602) by 0x68DE283: start_thread (pthread_create.c:333) by 0x80A6A4C: clone (in /lib/x86_64-linux-gnu/libc-2.21.so) --- src/defrag-config.c | 8 ++++++++ src/defrag-config.h | 1 + src/defrag.c | 1 + 3 files changed, 10 insertions(+) diff --git a/src/defrag-config.c b/src/defrag-config.c index 5bc4be36b67a..a1e1b4f94a94 100644 --- a/src/defrag-config.c +++ b/src/defrag-config.c @@ -160,3 +160,11 @@ void DefragPolicyLoadFromConfig(void) } } } + +void DefragTreeDestroy(void) +{ + if (defrag_tree != NULL) { + SCRadixReleaseRadixTree(defrag_tree); + } + defrag_tree = NULL; +} diff --git a/src/defrag-config.h b/src/defrag-config.h index a6c086ff0313..08abd00b9c16 100644 --- a/src/defrag-config.h +++ b/src/defrag-config.h @@ -28,5 +28,6 @@ void DefragSetDefaultTimeout(intmax_t timeout); void DefragPolicyLoadFromConfig(void); int DefragPolicyGetHostTimeout(Packet *p); +void DefragTreeDestroy(void); #endif /* DEFRAG_CONFIG_H_ */ diff --git a/src/defrag.c b/src/defrag.c index 1d86c44868bf..484a0994d625 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -978,6 +978,7 @@ void DefragDestroy(void) DefragHashShutdown(); DefragContextDestroy(defrag_context); defrag_context = NULL; + DefragTreeDestroy(); } #ifdef UNITTESTS From a53aef9c57a4f7855805bc41e8dd32d1b50ad32a Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 4 Mar 2016 19:52:08 +0100 Subject: [PATCH 1047/2553] tm-threads: unify thread names handling TmThreadCreate copy string provided as name for threads to avoid any issue is a non allocated string is used. This patch also introduce TmThreadSetGroupName function. This function is used to be sure we have an allocation when assigning the thread group name. This way we can free allocated memory at exit. Both code changes have required some fixes in different parts of the code to be in sync with the new API. Good point about these changes is that it fixes an inconsistency were some names were not allocated and some were. --- src/runmode-erf-file.c | 16 ++-------- src/runmode-pcap-file.c | 16 ++-------- src/runmode-tile.c | 7 +--- src/tm-threads.c | 29 ++++++++++++++++- src/tm-threads.h | 1 + src/util-runmodes.c | 71 ++++++----------------------------------- 6 files changed, 44 insertions(+), 96 deletions(-) diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index 19dbb683dfe0..0be5da148d4f 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -207,15 +207,8 @@ int RunModeErfFileAutoFp(void) SCLogDebug("tname %s, qname %s", tname, qname); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - printf("ERROR: Can't allocate thread name\n"); - exit(EXIT_FAILURE); - } - SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, qname, "flow", "packetpool", "packetpool", "varslot"); @@ -252,12 +245,7 @@ int RunModeErfFileAutoFp(void) } } - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - printf("Error allocating memory\n"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; + TmThreadSetGroupName(tv_detect_ncpu, "Detect"); /* add outputs as well */ SetupOutputs(tv_detect_ncpu); diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index fab14639b342..62e18c54583b 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -222,15 +222,8 @@ int RunModeFilePcapAutoFp(void) SCLogDebug("tname %s, qname %s", tname, qname); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "failed to strdup thread name"); - exit(EXIT_FAILURE); - } - SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, qname, "flow", "packetpool", "packetpool", "varslot"); @@ -254,12 +247,7 @@ int RunModeFilePcapAutoFp(void) TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); } - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; + TmThreadSetGroupName(tv_detect_ncpu, "Detect"); /* add outputs as well */ SetupOutputs(tv_detect_ncpu); diff --git a/src/runmode-tile.c b/src/runmode-tile.c index 38f5afecc0fd..688588c8be81 100644 --- a/src/runmode-tile.c +++ b/src/runmode-tile.c @@ -214,15 +214,10 @@ int RunModeTileMpipeWorkers(void) } snprintf(tname, sizeof(tname), "Worker%d", pipe+1); - thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - printf("ERROR: SCStrdup failed for ReceiveMpipe\n"); - exit(EXIT_FAILURE); - } /* create the threads */ ThreadVars *tv_worker = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); diff --git a/src/tm-threads.c b/src/tm-threads.c index d5326e9f2385..87b424b2e615 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1044,7 +1044,9 @@ ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name, SC_ATOMIC_INIT(tv->flags); SCMutexInit(&tv->perf_public_ctx.m, NULL); - tv->name = name; + tv->name = SCStrdup(name); + if (unlikely(tv->name == NULL)) + goto error; /* default state for every newly created thread */ TmThreadsSetFlag(tv, THV_PAUSE); TmThreadsSetFlag(tv, THV_USE); @@ -1658,6 +1660,13 @@ void TmThreadFree(ThreadVars *tv) TmThreadDeinitMC(tv); + if (tv->name) { + SCFree(tv->name); + } + if (tv->thread_group_name) { + SCFree(tv->thread_group_name); + } + s = (TmSlot *)tv->tm_slots; while (s) { ps = s; @@ -1669,6 +1678,24 @@ void TmThreadFree(ThreadVars *tv) SCFree(tv); } +void TmThreadSetGroupName(ThreadVars *tv, const char *name) +{ + char *thread_group_name = NULL; + + if (name == NULL) + return; + + if (tv == NULL) + return; + + thread_group_name = SCStrdup(name); + if (unlikely(thread_group_name == NULL)) { + SCLogError(SC_ERR_RUNMODE, "error allocating memory"); + return; + } + tv->thread_group_name = thread_group_name; +} + void TmThreadClearThreadsFamily(int family) { ThreadVars *tv = NULL; diff --git a/src/tm-threads.h b/src/tm-threads.h index 397fbd2e86b0..2127a73abdb8 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -102,6 +102,7 @@ void TmThreadKillThreads(void); void TmThreadClearThreadsFamily(int family); void TmThreadAppend(ThreadVars *, int); void TmThreadRemove(ThreadVars *, int); +void TmThreadSetGroupName(ThreadVars *tv, const char *name); TmEcode TmThreadSetCPUAffinity(ThreadVars *, uint16_t); TmEcode TmThreadSetThreadPriority(ThreadVars *, int); diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 110af4448f40..3c5f39a7752e 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -148,13 +148,8 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, /* create the threads */ for (thread = 0; thread < threads_count; thread++) { snprintf(tname, sizeof(tname), "%s%d", thread_name, thread+1); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } ThreadVars *tv_receive = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv_receive == NULL) { @@ -211,13 +206,8 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, for (thread = 0; thread < threads_count; thread++) { snprintf(tname, sizeof(tname), "%s%s%d", thread_name, live_dev, thread+1); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } ThreadVars *tv_receive = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv_receive == NULL) { @@ -254,13 +244,8 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, SCLogDebug("tname %s, qname %s", tname, qname); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, qname, "flow", "packetpool", "packetpool", "varslot"); @@ -286,12 +271,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; + TmThreadSetGroupName(tv_detect_ncpu, "Detect"); tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { @@ -334,7 +314,6 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod /* create the threads */ for (thread = 0; thread < threads_count; thread++) { char tname[TM_THREAD_NAME_MAX]; - char *n_thread_name = NULL; ThreadVars *tv = NULL; TmModule *tm_module = NULL; @@ -344,12 +323,7 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod snprintf(tname, sizeof(tname), "%s%s%d", thread_name, live_dev, thread+1); } - n_thread_name = SCStrdup(tname); - if (unlikely(n_thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } - tv = TmThreadCreatePacketHandler(n_thread_name, + tv = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); @@ -521,13 +495,8 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, memset(tname, 0, sizeof(tname)); snprintf(tname, sizeof(tname), "Recv-Q%s", cur_queue); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "thread name creation failed"); - exit(EXIT_FAILURE); - } ThreadVars *tv_receive = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv_receive == NULL) { @@ -562,13 +531,8 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, SCLogDebug("tname %s, qname %s", tname, qname); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, qname, "flow", "verdict-queue", "simple", "varslot"); @@ -596,12 +560,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, SetupOutputs(tv_detect_ncpu); - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; + TmThreadSetGroupName(tv_detect_ncpu, "Detect"); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); @@ -614,13 +573,8 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, memset(tname, 0, sizeof(tname)); snprintf(tname, sizeof(tname), "Verdict%d", i); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); - exit(EXIT_FAILURE); - } ThreadVars *tv_verdict = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "verdict-queue", "simple", "packetpool", "packetpool", "varslot"); @@ -678,12 +632,7 @@ int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, memset(tname, 0, sizeof(tname)); snprintf(tname, sizeof(tname), "Worker-Q%s", cur_queue); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); - exit(EXIT_FAILURE); - } - tv = TmThreadCreatePacketHandler(thread_name, + tv = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); From 50ea76a88b2ebcdcfeb6aa5a2a37975a99140fbd Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 6 Mar 2016 21:07:46 +0100 Subject: [PATCH 1048/2553] detect-tls: fix memleaks --- src/detect-tls.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/detect-tls.c b/src/detect-tls.c index 9b1d237baf0c..ba37aee0e623 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -277,6 +277,7 @@ static DetectTlsData *DetectTlsSubjectParse (char *str) } if (str_ptr[0] == '!') flag = DETECT_CONTENT_NEGATED; + pcre_free_substring(str_ptr); res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { @@ -295,6 +296,8 @@ static DetectTlsData *DetectTlsSubjectParse (char *str) if (unlikely(orig == NULL)) { goto error; } + pcre_free_substring(str_ptr); + tmp_str=orig; /* Let's see if we need to escape "'s */ @@ -484,6 +487,7 @@ static DetectTlsData *DetectTlsIssuerDNParse(char *str) } if (str_ptr[0] == '!') flag = DETECT_CONTENT_NEGATED; + pcre_free_substring(str_ptr); res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { @@ -502,6 +506,8 @@ static DetectTlsData *DetectTlsIssuerDNParse(char *str) if (unlikely(orig == NULL)) { goto error; } + pcre_free_substring(str_ptr); + tmp_str=orig; /* Let's see if we need to escape "'s */ @@ -627,6 +633,7 @@ static DetectTlsData *DetectTlsFingerprintParse (char *str) } if (str_ptr[0] == '!') flag = DETECT_CONTENT_NEGATED; + pcre_free_substring(str_ptr); res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { @@ -645,6 +652,8 @@ static DetectTlsData *DetectTlsFingerprintParse (char *str) if (unlikely(orig == NULL)) { goto error; } + pcre_free_substring(str_ptr); + tmp_str=orig; /* Let's see if we need to escape "'s */ From fe81bdc213a95a5e0f2253f01938350c1dd64352 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 6 Mar 2016 21:40:18 +0100 Subject: [PATCH 1049/2553] detect-ssl-version: simplify code and fix memlea --- src/detect-ssl-version.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index 599d26b87764..266c15d68d85 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -200,7 +200,7 @@ DetectSslVersionData *DetectSslVersionParse(char *str) } if (ret > 1) { - const char *str_ptr[5]; + const char *str_ptr; char *orig; uint8_t found = 0, neg = 0; char *tmp_str; @@ -212,7 +212,7 @@ DetectSslVersionData *DetectSslVersionParse(char *str) int i; for (i = 1; i < ret; i++) { - res = pcre_get_substring((char *) str, ov, MAX_SUBSTRINGS, i, &str_ptr[i]); + res = pcre_get_substring((char *) str, ov, MAX_SUBSTRINGS, i, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); if (found == 0) @@ -220,7 +220,7 @@ DetectSslVersionData *DetectSslVersionParse(char *str) break; } - orig = SCStrdup((char*) str_ptr[i]); + orig = SCStrdup((char*) str_ptr); if (unlikely(orig == NULL)) { goto error; } @@ -272,6 +272,7 @@ DetectSslVersionData *DetectSslVersionParse(char *str) found = 1; neg = 0; SCFree(orig); + pcre_free_substring(str_ptr); } } From 9c7e18dc89922e0e669529673efa9df75e8e1af7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 6 Mar 2016 21:40:26 +0100 Subject: [PATCH 1050/2553] detect-ssl-state: fix memleak --- src/detect-ssl-state.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index fa296631acf2..ffd6f39d68ed 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -261,6 +261,7 @@ DetectSslStateData *DetectSslStateParse(char *arg) pcre_free_substring(str1); str1 = str2; } + pcre_free_substring(str1); if ( (ssd = SCMalloc(sizeof(DetectSslStateData))) == NULL) { goto error; From f001c10ac4239bef5492fead14bcb4f830458028 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 7 Mar 2016 09:16:41 +0100 Subject: [PATCH 1051/2553] util-radix-tree: fix memleak Logic used when adding a new prefix to a node was not correct as we were allocating a prefix that could be at the end unused. This patch is updating the code to have a complete creation to be done if and only if we are needing the complete object. In the other cases, it was enough to use the function input values. This fixes: 104 (48 direct, 56 indirect) bytes in 2 blocks are definitely lost in loss record 184 of 327 at 0x4C29C0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x9C2DAD: SCRadixCreatePrefix (util-radix-tree.c:144) by 0x9AFA5B: SCRadixAddKey (util-radix-tree.c:522) by 0x9B1A4D: SCRadixAddKeyIPV4Netblock (util-radix-tree.c:897) by 0x67C824: IPOnlyPrepare (detect-engine-iponly.c:1197) by 0x55172B: SigAddressPrepareStage2 (detect.c:3534) by 0x5486F4: SigGroupBuild (detect.c:4671) by 0x547C87: SigLoadSignatures (detect.c:538) by 0x8FB5D0: LoadSignatures (suricata.c:1976) by 0x8F3B32: main (suricata.c:2342) --- src/util-radix-tree.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/util-radix-tree.c b/src/util-radix-tree.c index cbf49c7de7cb..2304d593f42d 100644 --- a/src/util-radix-tree.c +++ b/src/util-radix-tree.c @@ -496,9 +496,6 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, SCRadixNode *parent = NULL; SCRadixNode *inter_node = NULL; SCRadixNode *bottom_node = NULL; - - SCRadixPrefix *prefix = NULL; - void *ptmp; uint8_t *stream = NULL; @@ -519,14 +516,14 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, /* chop the ip address against a netmask */ MaskIPNetblock(key_stream, netmask, key_bitlen); - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, - netmask)) == NULL) { - SCLogError(SC_ERR_RADIX_TREE_GENERIC, "Error creating prefix"); - return NULL; - } - /* the very first element in the radix tree */ if (tree->head == NULL) { + SCRadixPrefix *prefix = NULL; + if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, + netmask)) == NULL) { + SCLogError(SC_ERR_RADIX_TREE_GENERIC, "Error creating prefix"); + return NULL; + } node = SCRadixCreateNode(); if (node == NULL) return NULL; @@ -558,8 +555,8 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, } node = tree->head; - stream = prefix->stream; - bitlen = prefix->bitlen; + stream = key_stream; + bitlen = key_bitlen; /* we walk down the tree only when we satisfy 2 conditions. The first one * being the incoming prefix is shorter than the differ bit of the current @@ -695,13 +692,19 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, } } } else { - node->prefix = SCRadixCreatePrefix(prefix->stream, prefix->bitlen, + node->prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, 255); } return node; } /* create the leaf node for the new key */ + SCRadixPrefix *prefix = NULL; + if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, + netmask)) == NULL) { + SCLogError(SC_ERR_RADIX_TREE_GENERIC, "Error creating prefix"); + return NULL; + } new_node = SCRadixCreateNode(); new_node->prefix = prefix; new_node->bit = prefix->bitlen; From c8399e8c51916d307dd7815999672617f2e4d7be Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Mon, 7 Mar 2016 21:33:14 +0100 Subject: [PATCH 1052/2553] configure: bypass libpcre 8.35 check When --with-libpcre-libraries is used we skip the libpcre 8.35 check since pkg-config might still point to the 8.35 version installed although newer version was passed with --with-libpcre-libraries. --- configure.ac | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 4cf76860ccf1..16e0dcfb42b4 100644 --- a/configure.ac +++ b/configure.ac @@ -481,16 +481,18 @@ # libpcre 8.35 (especially on debian) has a known issue that results in segfaults # see https://redmine.openinfosecfoundation.org/issues/1693 - PKG_CHECK_MODULES(LIBPCREVERSION, [libpcre = 8.35],[libpcre_buggy_found="yes"],[libprce_buggy_found="no"]) - if test "$libpcre_buggy_found" = "yes"; then - echo - echo " Warning! vulnerable libpcre version 8.35 found" - echo " This version has a known issue that could result in segfaults" - echo " please upgrade to a newer version of pcre which you can get from" - echo " www.pcre.org. For more information, see issue #1693" - echo - echo " Continuing for now with JIT disabled..." - echo + if test "$with_libpcre_libraries" = "no"; then + PKG_CHECK_MODULES(LIBPCREVERSION, [libpcre = 8.35],[libpcre_buggy_found="yes"],[libprce_buggy_found="no"]) + if test "$libpcre_buggy_found" = "yes"; then + echo + echo " Warning! vulnerable libpcre version 8.35 found" + echo " This version has a known issue that could result in segfaults" + echo " please upgrade to a newer version of pcre which you can get from" + echo " www.pcre.org. For more information, see issue #1693" + echo + echo " Continuing for now with JIT disabled..." + echo + fi fi # To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work From 3ac1468c1bf8d9c062e63fcc5e71d15f6ed8e5eb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 8 Mar 2016 15:13:03 +0100 Subject: [PATCH 1053/2553] packet pool: turn bad check into BUG_ON --- src/packet-queue.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/packet-queue.c b/src/packet-queue.c index c500971bd120..4b47beb2fb44 100644 --- a/src/packet-queue.c +++ b/src/packet-queue.c @@ -175,12 +175,11 @@ Packet *PacketDequeue (PacketQueue *q) /* pull the bottom packet from the queue */ p = q->bot; + /* Weird issue: sometimes it looks that two thread arrive * here at the same time so the bot ptr is NULL (only on OS X?) */ - if (p == NULL) { - return NULL; - } + BUG_ON (p == NULL); /* more packets in queue */ if (q->bot->prev != NULL) { From 4e90b54666956785fdb05fe3fd43138f63d50cfa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 8 Mar 2016 15:21:03 +0100 Subject: [PATCH 1054/2553] packet pool: make sure packet next ptr is always set --- src/packet-queue.c | 2 ++ src/tmqh-packetpool.c | 1 + 2 files changed, 3 insertions(+) diff --git a/src/packet-queue.c b/src/packet-queue.c index 4b47beb2fb44..cb766ff1b65c 100644 --- a/src/packet-queue.c +++ b/src/packet-queue.c @@ -192,6 +192,8 @@ Packet *PacketDequeue (PacketQueue *q) } //PacketQueueValidateDebug(q); + p->next = NULL; + p->prev = NULL; return p; } diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index 75139254ee67..c66025cf4dee 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -307,6 +307,7 @@ void PacketPoolReturnPacket(Packet *p) PktPool *pending_pool = my_pool->pending_pool; if (pending_pool == NULL) { /* No pending packet, so store the current packet. */ + p->next = NULL; my_pool->pending_pool = pool; my_pool->pending_head = p; my_pool->pending_tail = p; From 8f4eff5f5030ae921d3e68cd6b6a40ee7bd52215 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 8 Mar 2016 16:15:45 +0100 Subject: [PATCH 1055/2553] defrag: fix bad packet error handling When defrag creates a new reassembled IP packet, it then passes this packet to the IP decoder. If this decoder returns an error the packet is returned back to the packet pool with a call to TmqhOutputPacketpool This lead to the first problem. The returned packet had it's p->root pointer set, and it's PKT_TUNNEL flag set. This could cause problems in TmqhOutputPacketpool, as this may reference the packet referenced in p->root. The second and more glaring problem is that the packet that was returned to the packetpool, was still returned by the Defrag function and processed further. It would then at the end of it's processing be returned to the packet pool, which at this point already had a reference to this packet. This patch fixes both issues by unsetting the tunnel references and returning NULL from Defrag in this case. --- src/defrag.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/defrag.c b/src/defrag.c index 484a0994d625..f3de97edd9a3 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -783,7 +783,11 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, StatsIncr(tv, dtv->counter_defrag_ipv4_reassembled); if (pq && DecodeIPV4(tv, dtv, r, (void *)r->ip4h, IPV4_GET_IPLEN(r), pq) != TM_ECODE_OK) { + + UNSET_TUNNEL_PKT(r); + r->root = NULL; TmqhOutputPacketpool(tv, r); + r = NULL; } else { PacketDefragPktSetupParent(p); } @@ -796,7 +800,11 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, if (pq && DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h, IPV6_GET_PLEN(r) + IPV6_HEADER_LEN, pq) != TM_ECODE_OK) { + + UNSET_TUNNEL_PKT(r); + r->root = NULL; TmqhOutputPacketpool(tv, r); + r = NULL; } else { PacketDefragPktSetupParent(p); } From c0b16fa2bb624291274a8f05cc2b56cc2d44df9e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 8 Mar 2016 20:29:09 +0100 Subject: [PATCH 1056/2553] detect: allow for more than 64k mpm rules --- src/detect-content.h | 4 ++-- src/detect-engine-mpm.c | 12 ++++++------ src/detect.h | 2 +- src/suricata-common.h | 2 +- src/util-mpm-ac-bs.c | 2 +- src/util-mpm-ac-bs.h | 2 +- src/util-mpm-ac-gfbs.c | 2 +- src/util-mpm-ac-gfbs.h | 2 +- src/util-mpm-ac.c | 2 +- src/util-mpm-ac.h | 4 ++-- 10 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/detect-content.h b/src/detect-content.h index b2e0f9694f57..00c1ea3920d8 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -69,6 +69,8 @@ typedef struct DetectContentData_ { uint16_t replace_len; /* for chopped fast pattern, the length */ uint16_t fp_chop_len; + /* for chopped fast pattern, the offset */ + uint16_t fp_chop_offset; /* would want to move PatIntId here and flags down to remove the padding * gap, but I think the first four members was used as a template for * casting. \todo check this and fix it if posssible */ @@ -76,8 +78,6 @@ typedef struct DetectContentData_ { PatIntId id; uint16_t depth; uint16_t offset; - /* for chopped fast pattern, the offset */ - uint16_t fp_chop_offset; int32_t distance; int32_t within; /* Boyer Moore context (for spm search) */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 7fd532e5cc0e..5a21823ce845 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1064,14 +1064,14 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) * always used, etc. */ typedef struct ContentHash_ { DetectContentData *ptr; - uint16_t cnt; - uint8_t use; /* use no matter what */ + uint32_t cnt; + int use; /* use no matter what */ } ContentHash; typedef struct UricontentHash_ { DetectContentData *ptr; - uint16_t cnt; - uint8_t use; /* use no matter what */ + uint32_t cnt; + int use; /* use no matter what */ } UricontentHash; uint32_t ContentHashFunc(HashTable *ht, void *data, uint16_t datalen) @@ -2714,8 +2714,8 @@ typedef struct MpmPatternIdTableElmt_ { uint8_t *pattern; /**< ptr to the pattern */ uint16_t pattern_len; /**< pattern len */ PatIntId id; /**< pattern id */ - uint16_t dup_count; /**< duplicate count */ - uint8_t sm_list; /**< SigMatch list */ + uint32_t dup_count; /**< duplicate count */ + int sm_list; /**< SigMatch list */ } MpmPatternIdTableElmt; /** \brief Hash compare func for MpmPatternId api diff --git a/src/detect.h b/src/detect.h index 89ce35ab1ca2..c36b9ce1e955 100644 --- a/src/detect.h +++ b/src/detect.h @@ -640,7 +640,7 @@ typedef struct DetectEngineCtx_ { /** hash table for looking up patterns for * id sharing and id tracking. */ MpmPatternIdStore *mpm_pattern_id_store; - uint16_t max_fp_id; + uint32_t max_fp_id; MpmCtxFactoryContainer *mpm_ctx_factory_container; diff --git a/src/suricata-common.h b/src/suricata-common.h index 05bfcdf9ec3b..660a0bfecc3e 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -241,7 +241,7 @@ #define SigIntId uint32_t /** same for pattern id's */ -#define PatIntId uint16_t +#define PatIntId uint32_t /** FreeBSD does not define __WORDSIZE, but it uses __LONG_BIT */ #ifndef __WORDSIZE diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index d6c4e78502cd..f19acbcd4a53 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -1382,7 +1382,7 @@ void SCACBSDestroyCtx(MpmCtx *mpm_ctx) } if (ctx->pid_pat_list != NULL) { - int i; + uint32_t i; for (i = 0; i < (ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); diff --git a/src/util-mpm-ac-bs.h b/src/util-mpm-ac-bs.h index a66757e72a3d..ce9c59fc5c28 100644 --- a/src/util-mpm-ac-bs.h +++ b/src/util-mpm-ac-bs.h @@ -88,7 +88,7 @@ typedef struct SCACBSCtx_ { /* the size of each state */ uint16_t single_state_size; - uint16_t max_pat_id; + uint32_t max_pat_id; } SCACBSCtx; typedef struct SCACBSThreadCtx_ { diff --git a/src/util-mpm-ac-gfbs.c b/src/util-mpm-ac-gfbs.c index e0ace7f3e7f2..bfff68890898 100644 --- a/src/util-mpm-ac-gfbs.c +++ b/src/util-mpm-ac-gfbs.c @@ -1259,7 +1259,7 @@ void SCACGfbsDestroyCtx(MpmCtx *mpm_ctx) } if (ctx->pid_pat_list != NULL) { - int i; + uint32_t i; for (i = 0; i < (ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); diff --git a/src/util-mpm-ac-gfbs.h b/src/util-mpm-ac-gfbs.h index 4003a5b560a5..521c8db03530 100644 --- a/src/util-mpm-ac-gfbs.h +++ b/src/util-mpm-ac-gfbs.h @@ -97,7 +97,7 @@ typedef struct SCACGfbsCtx_ { /* the size of each state */ uint16_t single_state_size; - uint16_t max_pat_id; + uint32_t max_pat_id; } SCACGfbsCtx; typedef struct SCACGfbsThreadCtx_ { diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index c8f6be77a205..49df0d6ea927 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -1273,7 +1273,7 @@ void SCACDestroyCtx(MpmCtx *mpm_ctx) } if (ctx->pid_pat_list != NULL) { - int i; + uint32_t i; for (i = 0; i < (ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); diff --git a/src/util-mpm-ac.h b/src/util-mpm-ac.h index a837f5f01541..13bd16fbdcae 100644 --- a/src/util-mpm-ac.h +++ b/src/util-mpm-ac.h @@ -97,8 +97,8 @@ typedef struct SCACCtx_ { SCACPatternList *pid_pat_list; /* the size of each state */ - uint16_t single_state_size; - uint16_t max_pat_id; + uint32_t single_state_size; + uint32_t max_pat_id; uint32_t allocated_state_count; From bda9869af7d5db3f05eabc0716fd672a9cb2aa7c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 3 Dec 2015 13:06:19 +0100 Subject: [PATCH 1057/2553] dns: turn debug BUG_ON's into events --- src/app-layer-dns-common.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 3c67fe44d2cf..339610a705b5 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -788,10 +788,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ if ((fqdn_len = DNSResponseGetNameByOffset(input, input_len, data - input, fqdn, sizeof(fqdn))) == 0) { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto insufficient_data; } //PrintRawDataFp(stdout, fqdn, fqdn_len); @@ -806,10 +803,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ if ((fqdn_len = DNSResponseGetNameByOffset(input, input_len, offset, fqdn, sizeof(fqdn))) == 0) { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto insufficient_data; } //PrintRawDataFp(stdout, fqdn, fqdn_len); @@ -886,11 +880,9 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ } if ((name_len = DNSResponseGetNameByOffset(input, input_len, - data - input + skip, name, sizeof(name))) == 0) { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif + data - input + skip, name, sizeof(name))) == 0) + { + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto insufficient_data; } @@ -910,10 +902,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ if ((pname_len = DNSResponseGetNameByOffset(input, input_len, data - input, pname, sizeof(pname))) == 0) { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto insufficient_data; } @@ -929,10 +918,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ if ((pmail_len = DNSResponseGetNameByOffset(input, input_len, sdata - input, pmail, sizeof(pmail))) == 0) { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto insufficient_data; } SCLogDebug("pmail_len %u", pmail_len); From e4059fb541202964a54d56a38f261591e9d79a7f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 9 Mar 2016 13:21:45 +0100 Subject: [PATCH 1058/2553] stream: fix stream.inline default If stream.inline setting was missing it would default to IDS. This patch changes the default to 'auto', meaning that in IPS mode the stream engine also uses IPS mode and in IDS mode it's still in IDS mode. Bug #1570 --- src/stream-tcp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 80d1b8dffde4..9ccb6a2940eb 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -422,11 +422,10 @@ void StreamTcpInitConfig(char quiet) "enabled" : "disabled"); } - int inl = 0; - - char *temp_stream_inline_str; if (ConfGet("stream.inline", &temp_stream_inline_str) == 1) { + int inl = 0; + /* checking for "auto" and falling back to boolean to provide * backward compatibility */ if (strcmp(temp_stream_inline_str, "auto") == 0) { @@ -438,6 +437,13 @@ void StreamTcpInitConfig(char quiet) } else if (ConfGetBool("stream.inline", &inl) == 1) { stream_inline = inl; } + } else { + /* default to 'auto' */ + if (EngineModeIsIPS()) { + stream_inline = 1; + } else { + stream_inline = 0; + } } if (!quiet) { From 994bc15c2a42230cc4493f6a9df33db13764c32b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 9 Mar 2016 16:57:29 +0100 Subject: [PATCH 1059/2553] af-packet: disable most code when not built in When af-packet is not build we can avoid to build a large amount of code. --- src/runmode-af-packet.c | 6 ++++++ src/suricata.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index cd98b229505c..3d3b6cdeca0a 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -83,6 +83,9 @@ void RunModeIdsAFPRegister(void) return; } + +#ifdef HAVE_AF_PACKET + void AFPDerefConfig(void *conf) { AFPIfaceConfig *pfp = (AFPIfaceConfig *)conf; @@ -475,6 +478,9 @@ int AFPRunModeIsIPS() return has_ips; } +#endif + + int RunModeIdsAFPAutoFp(void) { SCEnter(); diff --git a/src/suricata.c b/src/suricata.c index e454b8b04319..cbdea55150b5 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -984,6 +984,7 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) /* not an error condition if we have a 1.0 config */ LiveBuildDeviceList("pfring"); } +#ifdef HAVE_AF_PACKET } else if (run_mode == RUNMODE_AFP_DEV) { /* iface has been set on command line */ if (strlen(pcap_dev)) { @@ -1002,6 +1003,7 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) EngineModeSetIPS(); } } +#endif #ifdef HAVE_NETMAP } else if (run_mode == RUNMODE_NETMAP) { /* iface has been set on command line */ From 11eb1d7c1d2b77d0706d7fd1632d9deeb7937a04 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 9 Mar 2016 14:10:26 +0100 Subject: [PATCH 1060/2553] af-packet: handle raw link If no link layer header is reported then it is a raw header. --- src/source-af-packet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 212e118424d1..f5b0ea399b31 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1307,6 +1307,7 @@ static int AFPGetDevLinktype(int fd, const char *ifname) case ARPHRD_LOOPBACK: return LINKTYPE_ETHERNET; case ARPHRD_PPP: + case ARPHRD_NONE: return LINKTYPE_RAW; default: return ifr.ifr_hwaddr.sa_family; From b7bf299e3bc285e751fa3c396292d35cd37c0cc1 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 9 Mar 2016 14:29:19 +0100 Subject: [PATCH 1061/2553] af-packet: don't check GRO LRO on non ethernet This way we avoid an error message when sniffing on a non Ethernet device. --- src/runmode-af-packet.c | 14 +++++++++++--- src/source-af-packet.c | 16 ++++++++++++++++ src/source-af-packet.h | 2 +- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 3d3b6cdeca0a..e561559a93ba 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -370,9 +370,17 @@ void *ParseAFPConfig(const char *iface) } } - if (GetIfaceOffloading(iface) == 1) { - SCLogWarning(SC_ERR_AFP_CREATE, - "Using AF_PACKET with GRO or LRO activated can lead to capture problems"); + + int ltype = AFPGetLinkType(iface); + switch (ltype) { + case LINKTYPE_ETHERNET: + if (GetIfaceOffloading(iface) == 1) { + SCLogWarning(SC_ERR_AFP_CREATE, + "Using AF_PACKET with GRO or LRO activated can lead to capture problems"); + } + case -1: + default: + break; } char *active_runmode = RunmodeGetActive(); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index f5b0ea399b31..2beb17037c72 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1314,6 +1314,22 @@ static int AFPGetDevLinktype(int fd, const char *ifname) } } +int AFPGetLinkType(const char *ifname) +{ + int ltype; + + int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (fd == -1) { + SCLogError(SC_ERR_AFP_CREATE, "Couldn't create a AF_PACKET socket, error %s", strerror(errno)); + return LINKTYPE_RAW; + } + + ltype = AFPGetDevLinktype(fd, ifname); + close(fd); + + return ltype; +} + static int AFPComputeRingParams(AFPThreadVars *ptv, int order) { /* Compute structure: diff --git a/src/source-af-packet.h b/src/source-af-packet.h index 61f4e69ea0bc..86ad97bba6a7 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -132,6 +132,6 @@ void TmModuleDecodeAFPRegister (void); TmEcode AFPPeersListInit(); TmEcode AFPPeersListCheck(); void AFPPeersListClean(); - +int AFPGetLinkType(const char *ifname); #endif /* __SOURCE_AFP_H__ */ From 44a7c12ad0afb6a6187090e485ed1268d49619a3 Mon Sep 17 00:00:00 2001 From: Maurizio Abba Date: Thu, 10 Mar 2016 13:58:21 +0000 Subject: [PATCH 1062/2553] decode-events: counters for decode events errors We want to add counters in order to track the number of times we hit a decode event. A decode event is related to an error in the protocol decoding over a certain packet. This patch fist modifies the decode-event list, reordering it in order to separate single packet events from stream-related events and adding the prefix "decoder" to decode events. The counters are created during the decode setup and the relative event counter is increased every time a packet with the flag PKT_IS_INVALID is finalized in the decode phase --- src/decode-events.c | 214 ++++++++++++++++++++++++++++++++++++ src/decode-events.h | 82 ++++++++------ src/decode.c | 18 +++- src/decode.h | 1 + src/detect-engine-event.c | 22 ++-- src/detect-engine-event.h | 221 -------------------------------------- 6 files changed, 292 insertions(+), 266 deletions(-) diff --git a/src/decode-events.c b/src/decode-events.c index cecf77c54d5a..f4a5bdd1ca81 100644 --- a/src/decode-events.c +++ b/src/decode-events.c @@ -23,5 +23,219 @@ #include "suricata-common.h" +#include "decode-events.h" /* code moved to app-layer-events */ +const struct DecodeEvents_ DEvents[] = { + /* IPV4 EVENTS */ + { "decoder.ipv4.pkt_too_small", IPV4_PKT_TOO_SMALL, }, + { "decoder.ipv4.hlen_too_small", IPV4_HLEN_TOO_SMALL, }, + { "decoder.ipv4.iplen_smaller_than_hlen", IPV4_IPLEN_SMALLER_THAN_HLEN, }, + { "decoder.ipv4.trunc_pkt", IPV4_TRUNC_PKT, }, + + /* IPV4 OPTIONS */ + { "decoder.ipv4.opt_invalid", IPV4_OPT_INVALID, }, + { "decoder.ipv4.opt_invalid_len", IPV4_OPT_INVALID_LEN, }, + { "decoder.ipv4.opt_malformed", IPV4_OPT_MALFORMED, }, + { "decoder.ipv4.opt_pad_required", IPV4_OPT_PAD_REQUIRED, }, + { "decoder.ipv4.opt_eol_required", IPV4_OPT_EOL_REQUIRED, }, + { "decoder.ipv4.opt_duplicate", IPV4_OPT_DUPLICATE, }, + { "decoder.ipv4.opt_unknown", IPV4_OPT_UNKNOWN, }, + { "decoder.ipv4.wrong_ip_version", IPV4_WRONG_IP_VER, }, + { "decoder.ipv4.icmpv6", IPV4_WITH_ICMPV6, }, + + /* ICMP EVENTS */ + { "decoder.icmpv4.pkt_too_small", ICMPV4_PKT_TOO_SMALL, }, + { "decoder.icmpv4.unknown_type", ICMPV4_UNKNOWN_TYPE, }, + { "decoder.icmpv4.unknown_code", ICMPV4_UNKNOWN_CODE, }, + { "decoder.icmpv4.ipv4_trunc_pkt", ICMPV4_IPV4_TRUNC_PKT, }, + { "decoder.icmpv4.ipv4_unknown_ver", ICMPV4_IPV4_UNKNOWN_VER, }, + + /* ICMPv6 EVENTS */ + { "decoder.icmpv6.unknown_type", ICMPV6_UNKNOWN_TYPE,}, + { "decoder.icmpv6.unknown_code", ICMPV6_UNKNOWN_CODE,}, + { "decoder.icmpv6.pkt_too_small", ICMPV6_PKT_TOO_SMALL,}, + { "decoder.icmpv6.ipv6_unknown_version", ICMPV6_IPV6_UNKNOWN_VER,}, + { "decoder.icmpv6.ipv6_trunc_pkt", ICMPV6_IPV6_TRUNC_PKT,}, + { "decoder.icmpv6.mld_message_with_invalid_hl", ICMPV6_MLD_MESSAGE_WITH_INVALID_HL,}, + { "decoder.icmpv6.unassigned_type", ICMPV6_UNASSIGNED_TYPE,}, + { "decoder.icmpv6.experimentation_type", ICMPV6_EXPERIMENTATION_TYPE,}, + + /* IPV6 EVENTS */ + { "decoder.ipv6.pkt_too_small", IPV6_PKT_TOO_SMALL, }, + { "decoder.ipv6.trunc_pkt", IPV6_TRUNC_PKT, }, + { "decoder.ipv6.trunc_exthdr", IPV6_TRUNC_EXTHDR, }, + { "decoder.ipv6.exthdr_dupl_fh", IPV6_EXTHDR_DUPL_FH, }, + { "decoder.ipv6.exthdr_useless_fh", IPV6_EXTHDR_USELESS_FH, }, + { "decoder.ipv6.exthdr_dupl_rh", IPV6_EXTHDR_DUPL_RH, }, + { "decoder.ipv6.exthdr_dupl_hh", IPV6_EXTHDR_DUPL_HH, }, + { "decoder.ipv6.exthdr_dupl_dh", IPV6_EXTHDR_DUPL_DH, }, + { "decoder.ipv6.exthdr_dupl_ah", IPV6_EXTHDR_DUPL_AH, }, + { "decoder.ipv6.exthdr_dupl_eh", IPV6_EXTHDR_DUPL_EH, }, + { "decoder.ipv6.exthdr_invalid_optlen", IPV6_EXTHDR_INVALID_OPTLEN, }, + { "decoder.ipv6.wrong_ip_version", IPV6_WRONG_IP_VER, }, + { "decoder.ipv6.exthdr_ah_res_not_null", IPV6_EXTHDR_AH_RES_NOT_NULL, }, + { "decoder.ipv6.hopopts_unknown_opt", IPV6_HOPOPTS_UNKNOWN_OPT, }, + { "decoder.ipv6.hopopts_only_padding", IPV6_HOPOPTS_ONLY_PADDING, }, + { "decoder.ipv6.dstopts_unknown_opt", IPV6_DSTOPTS_UNKNOWN_OPT, }, + { "decoder.ipv6.dstopts_only_padding", IPV6_DSTOPTS_ONLY_PADDING, }, + { "decoder.ipv6.rh_type_0", IPV6_EXTHDR_RH_TYPE_0, }, + { "decoder.ipv6.zero_len_padn", IPV6_EXTHDR_ZERO_LEN_PADN, }, + { "decoder.ipv6.fh_non_zero_reserved_field", IPV6_FH_NON_ZERO_RES_FIELD, }, + { "decoder.ipv6.data_after_none_header", IPV6_DATA_AFTER_NONE_HEADER, }, + { "decoder.ipv6.unknown_next_header", IPV6_UNKNOWN_NEXT_HEADER, }, + { "decoder.ipv6.icmpv4", IPV6_WITH_ICMPV4, }, + + /* TCP EVENTS */ + { "decoder.tcp.pkt_too_small", TCP_PKT_TOO_SMALL, }, + { "decoder.tcp.hlen_too_small", TCP_HLEN_TOO_SMALL, }, + { "decoder.tcp.invalid_optlen", TCP_INVALID_OPTLEN, }, + + /* TCP OPTIONS */ + { "decoder.tcp.opt_invalid_len", TCP_OPT_INVALID_LEN, }, + { "decoder.tcp.opt_duplicate", TCP_OPT_DUPLICATE, }, + + /* UDP EVENTS */ + { "decoder.udp.pkt_too_small", UDP_PKT_TOO_SMALL, }, + { "decoder.udp.hlen_too_small", UDP_HLEN_TOO_SMALL, }, + { "decoder.udp.hlen_invalid", UDP_HLEN_INVALID, }, + + /* SLL EVENTS */ + { "decoder.sll.pkt_too_small", SLL_PKT_TOO_SMALL, }, + + /* ETHERNET EVENTS */ + { "decoder.ethernet.pkt_too_small", ETHERNET_PKT_TOO_SMALL, }, + + /* PPP EVENTS */ + { "decoder.ppp.pkt_too_small", PPP_PKT_TOO_SMALL, }, + { "decoder.ppp.vju_pkt_too_small", PPPVJU_PKT_TOO_SMALL, }, + { "decoder.ppp.ip4_pkt_too_small", PPPIPV4_PKT_TOO_SMALL, }, + { "decoder.ppp.ip6_pkt_too_small", PPPIPV6_PKT_TOO_SMALL, }, + { "decoder.ppp.wrong_type", PPP_WRONG_TYPE, }, /** unknown & invalid protocol */ + { "decoder.ppp.unsup_proto", PPP_UNSUP_PROTO, }, /** unsupported but valid protocol */ + + /* PPPOE EVENTS */ + { "decoder.pppoe.pkt_too_small", PPPOE_PKT_TOO_SMALL, }, + { "decoder.pppoe.wrong_code", PPPOE_WRONG_CODE, }, + { "decoder.pppoe.malformed_tags", PPPOE_MALFORMED_TAGS, }, + + /* GRE EVENTS */ + { "decoder.gre.pkt_too_small", GRE_PKT_TOO_SMALL, }, + { "decoder.gre.wrong_version", GRE_WRONG_VERSION, }, + { "decoder.gre.version0_recur", GRE_VERSION0_RECUR, }, + { "decoder.gre.version0_flags", GRE_VERSION0_FLAGS, }, + { "decoder.gre.version0_hdr_too_big", GRE_VERSION0_HDR_TOO_BIG, }, + { "decoder.gre.version0_malformed_sre_hdr", GRE_VERSION0_MALFORMED_SRE_HDR, }, + { "decoder.gre.version1_chksum", GRE_VERSION1_CHKSUM, }, + { "decoder.gre.version1_route", GRE_VERSION1_ROUTE, }, + { "decoder.gre.version1_ssr", GRE_VERSION1_SSR, }, + { "decoder.gre.version1_recur", GRE_VERSION1_RECUR, }, + { "decoder.gre.version1_flags", GRE_VERSION1_FLAGS, }, + { "decoder.gre.version1_no_key", GRE_VERSION1_NO_KEY, }, + { "decoder.gre.version1_wrong_protocol", GRE_VERSION1_WRONG_PROTOCOL, }, + { "decoder.gre.version1_malformed_sre_hdr", GRE_VERSION1_MALFORMED_SRE_HDR, }, + { "decoder.gre.version1_hdr_too_big", GRE_VERSION1_HDR_TOO_BIG, }, + + /* VLAN EVENTS */ + { "decoder.vlan.header_too_small",VLAN_HEADER_TOO_SMALL, }, + { "decoder.vlan.unknown_type",VLAN_UNKNOWN_TYPE, }, + { "decoder.vlan.too_many_layers", VLAN_HEADER_TOO_MANY_LAYERS, }, + + /* RAW EVENTS */ + { "decoder.ipraw.invalid_ip_version",IPRAW_INVALID_IPV, }, + + /* LINKTYPE NULL EVENTS */ + { "decoder.ltnull.pkt_too_small", LTNULL_PKT_TOO_SMALL, }, + { "decoder.ltnull.unsupported_type", LTNULL_UNSUPPORTED_TYPE, }, + + /* SCTP EVENTS */ + { "decoder.sctp.pkt_too_small", SCTP_PKT_TOO_SMALL, }, + + /* Fragmentation reasembly events. */ + { "decoder.ipv4.frag_too_large", IPV4_FRAG_PKT_TOO_LARGE, }, + { "decoder.ipv6.frag_too_large", IPV6_FRAG_PKT_TOO_LARGE, }, + { "decoder.ipv4.frag_overlap", IPV4_FRAG_OVERLAP, }, + { "decoder.ipv6.frag_overlap", IPV6_FRAG_OVERLAP, }, + /* Fragment ignored due to internal error */ + { "decoder.ipv4.frag_ignored", IPV4_FRAG_IGNORED, }, + { "decoder.ipv6.frag_ignored", IPV6_FRAG_IGNORED, }, + + /* IPv4 in IPv6 events */ + { "decoder.ipv6.ipv4_in_ipv6_too_small", IPV4_IN_IPV6_PKT_TOO_SMALL, }, + { "decoder.ipv6.ipv4_in_ipv6_wrong_version", IPV4_IN_IPV6_WRONG_IP_VER, }, + /* IPv6 in IPv6 events */ + { "decoder.ipv6.ipv6_in_ipv6_too_small", IPV6_IN_IPV6_PKT_TOO_SMALL, }, + { "decoder.ipv6.ipv6_in_ipv6_wrong_version", IPV6_IN_IPV6_WRONG_IP_VER, }, + + /* MPLS events */ + { "decoder.mpls.bad_label_router_alert", MPLS_BAD_LABEL_ROUTER_ALERT, }, + { "decoder.mpls.bad_label_implicit_null", MPLS_BAD_LABEL_IMPLICIT_NULL, }, + { "decoder.mpls.bad_label_reserved", MPLS_BAD_LABEL_RESERVED, }, + { "decoder.mpls.unknown_payload_type", MPLS_UNKNOWN_PAYLOAD_TYPE, }, + + /* ERSPAN events */ + { "decoder.erspan.header_too_small", ERSPAN_HEADER_TOO_SMALL, }, + { "decoder.erspan.unsupported_version", ERSPAN_UNSUPPORTED_VERSION, }, + { "decoder.erspan.too_many_vlan_layers", ERSPAN_TOO_MANY_VLAN_LAYERS, }, + + /* STREAM EVENTS */ + { "stream.3whs_ack_in_wrong_dir", STREAM_3WHS_ACK_IN_WRONG_DIR, }, + { "stream.3whs_async_wrong_seq", STREAM_3WHS_ASYNC_WRONG_SEQ, }, + { "stream.3whs_right_seq_wrong_ack_evasion", STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION, }, + { "stream.3whs_synack_in_wrong_direction", STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION, }, + { "stream.3whs_synack_resend_with_different_ack", STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK, }, + { "stream.3whs_synack_resend_with_diff_seq", STREAM_3WHS_SYNACK_RESEND_WITH_DIFF_SEQ, }, + { "stream.3whs_synack_toserver_on_syn_recv", STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV, }, + { "stream.3whs_synack_with_wrong_ack", STREAM_3WHS_SYNACK_WITH_WRONG_ACK, }, + { "stream.3whs_synack_flood", STREAM_3WHS_SYNACK_FLOOD, }, + { "stream.3whs_syn_resend_diff_seq_on_syn_recv", STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV, }, + { "stream.3whs_syn_toclient_on_syn_recv", STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV, }, + { "stream.3whs_wrong_seq_wrong_ack", STREAM_3WHS_WRONG_SEQ_WRONG_ACK, }, + { "stream.4whs_synack_with_wrong_ack", STREAM_4WHS_SYNACK_WITH_WRONG_ACK, }, + { "stream.4whs_synack_with_wrong_syn", STREAM_4WHS_SYNACK_WITH_WRONG_SYN, }, + { "stream.4whs_wrong_seq", STREAM_4WHS_WRONG_SEQ, }, + { "stream.4whs_invalid_ack", STREAM_4WHS_INVALID_ACK, }, + { "stream.closewait_ack_out_of_window", STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW, }, + { "stream.closewait_fin_out_of_window", STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW, }, + { "stream.closewait_pkt_before_last_ack", STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK, }, + { "stream.closewait_invalid_ack", STREAM_CLOSEWAIT_INVALID_ACK, }, + { "stream.closing_ack_wrong_seq", STREAM_CLOSING_ACK_WRONG_SEQ, }, + { "stream.closing_invalid_ack", STREAM_CLOSING_INVALID_ACK, }, + { "stream.est_packet_out_of_window", STREAM_EST_PACKET_OUT_OF_WINDOW, }, + { "stream.est_pkt_before_last_ack", STREAM_EST_PKT_BEFORE_LAST_ACK, }, + { "stream.est_synack_resend", STREAM_EST_SYNACK_RESEND, }, + { "stream.est_synack_resend_with_different_ack", STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK, }, + { "stream.est_synack_resend_with_diff_seq", STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ, }, + { "stream.est_synack_toserver", STREAM_EST_SYNACK_TOSERVER, }, + { "stream.est_syn_resend", STREAM_EST_SYN_RESEND, }, + { "stream.est_syn_resend_diff_seq", STREAM_EST_SYN_RESEND_DIFF_SEQ, }, + { "stream.est_syn_toclient", STREAM_EST_SYN_TOCLIENT, }, + { "stream.est_invalid_ack", STREAM_EST_INVALID_ACK, }, + { "stream.fin_invalid_ack", STREAM_FIN_INVALID_ACK, }, + { "stream.fin1_ack_wrong_seq", STREAM_FIN1_ACK_WRONG_SEQ, }, + { "stream.fin1_fin_wrong_seq", STREAM_FIN1_FIN_WRONG_SEQ, }, + { "stream.fin1_invalid_ack", STREAM_FIN1_INVALID_ACK, }, + { "stream.fin2_ack_wrong_seq", STREAM_FIN2_ACK_WRONG_SEQ, }, + { "stream.fin2_fin_wrong_seq", STREAM_FIN2_FIN_WRONG_SEQ, }, + { "stream.fin2_invalid_ack", STREAM_FIN2_INVALID_ACK, }, + { "stream.fin_but_no_session", STREAM_FIN_BUT_NO_SESSION, }, + { "stream.fin_out_of_window", STREAM_FIN_OUT_OF_WINDOW, }, + { "stream.lastack_ack_wrong_seq", STREAM_LASTACK_ACK_WRONG_SEQ, }, + { "stream.lastack_invalid_ack", STREAM_LASTACK_INVALID_ACK, }, + { "stream.rst_but_no_session", STREAM_RST_BUT_NO_SESSION, }, + { "stream.timewait_ack_wrong_seq", STREAM_TIMEWAIT_ACK_WRONG_SEQ, }, + { "stream.timewait_invalid_ack", STREAM_TIMEWAIT_INVALID_ACK, }, + { "stream.pkt_invalid_timestamp", STREAM_PKT_INVALID_TIMESTAMP, }, + { "stream.pkt_invalid_ack", STREAM_PKT_INVALID_ACK, }, + { "stream.pkt_broken_ack", STREAM_PKT_BROKEN_ACK, }, + { "stream.rst_invalid_ack", STREAM_RST_INVALID_ACK, }, + { "stream.shutdown_syn_resend", STREAM_SHUTDOWN_SYN_RESEND, }, + { "stream.pkt_retransmission", STREAM_PKT_RETRANSMISSION, }, + { "stream.reassembly_segment_before_base_seq", STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ, }, + { "stream.reassembly_no_segment", STREAM_REASSEMBLY_NO_SEGMENT, }, + { "stream.reassembly_seq_gap", STREAM_REASSEMBLY_SEQ_GAP, }, + { "stream.reassembly_overlap_different_data", STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, }, + { "stream.pkt_bad_window_update", STREAM_PKT_BAD_WINDOW_UPDATE, }, + + { NULL, 0 }, +}; diff --git a/src/decode-events.h b/src/decode-events.h index 51889387a143..8e7395254300 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -28,7 +28,7 @@ /* packet decoder events */ enum { /* IPV4 EVENTS */ - IPV4_PKT_TOO_SMALL = 1, /**< ipv4 pkt smaller than minimum header size */ + IPV4_PKT_TOO_SMALL = 0, /**< ipv4 pkt smaller than minimum header size */ IPV4_HLEN_TOO_SMALL, /**< ipv4 header smaller than minimum size */ IPV4_IPLEN_SMALLER_THAN_HLEN, /**< ipv4 pkt len smaller than ip header size */ IPV4_TRUNC_PKT, /**< truncated ipv4 packet */ @@ -152,6 +152,44 @@ enum { LTNULL_PKT_TOO_SMALL, /**< pkt too small for lt:null */ LTNULL_UNSUPPORTED_TYPE, /**< pkt has a type that the decoder doesn't support */ + /* SCTP EVENTS */ + SCTP_PKT_TOO_SMALL, /**< sctp packet smaller than minimum size */ + + /* Fragmentation reasembly events. */ + IPV4_FRAG_PKT_TOO_LARGE, + IPV6_FRAG_PKT_TOO_LARGE, + IPV4_FRAG_OVERLAP, + IPV6_FRAG_OVERLAP, + IPV4_FRAG_TOO_LARGE, + IPV6_FRAG_TOO_LARGE, + + /* Fragment ignored due to internal error */ + IPV4_FRAG_IGNORED, + IPV6_FRAG_IGNORED, + + /* IPv4 in IPv6 events */ + IPV4_IN_IPV6_PKT_TOO_SMALL, + IPV4_IN_IPV6_WRONG_IP_VER, + + /* IPv6 in IPv6 events */ + IPV6_IN_IPV6_PKT_TOO_SMALL, + IPV6_IN_IPV6_WRONG_IP_VER, + + /* MPLS decode events. */ + MPLS_HEADER_TOO_SMALL, + MPLS_BAD_LABEL_ROUTER_ALERT, + MPLS_BAD_LABEL_IMPLICIT_NULL, + MPLS_BAD_LABEL_RESERVED, + MPLS_UNKNOWN_PAYLOAD_TYPE, + + /* ERSPAN events */ + ERSPAN_HEADER_TOO_SMALL, + ERSPAN_UNSUPPORTED_VERSION, + ERSPAN_TOO_MANY_VLAN_LAYERS, + + /* END OF DECODE EVENTS ON SINGLE PACKET */ + DECODE_EVENT_PACKET_MAX, + /* STREAM EVENTS */ STREAM_3WHS_ACK_IN_WRONG_DIR, STREAM_3WHS_ASYNC_WRONG_SEQ, @@ -214,41 +252,19 @@ enum { STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, - /* SCTP EVENTS */ - SCTP_PKT_TOO_SMALL, /**< sctp packet smaller than minimum size */ - - /* Fragmentation reasembly events. */ - IPV4_FRAG_PKT_TOO_LARGE, - IPV6_FRAG_PKT_TOO_LARGE, - IPV4_FRAG_OVERLAP, - IPV6_FRAG_OVERLAP, - IPV4_FRAG_TOO_LARGE, - IPV6_FRAG_TOO_LARGE, - /* Fragment ignored due to internal error */ - IPV4_FRAG_IGNORED, - IPV6_FRAG_IGNORED, - - /* IPv4 in IPv6 events */ - IPV4_IN_IPV6_PKT_TOO_SMALL, - IPV4_IN_IPV6_WRONG_IP_VER, - /* IPv6 in IPv6 events */ - IPV6_IN_IPV6_PKT_TOO_SMALL, - IPV6_IN_IPV6_WRONG_IP_VER, + /* should always be last! */ + DECODE_EVENT_MAX, +}; - /* MPLS decode events. */ - MPLS_HEADER_TOO_SMALL, - MPLS_BAD_LABEL_ROUTER_ALERT, - MPLS_BAD_LABEL_IMPLICIT_NULL, - MPLS_BAD_LABEL_RESERVED, - MPLS_UNKNOWN_PAYLOAD_TYPE, +#define EVENT_IS_DECODER_PACKET_ERROR(e) \ + ((e) < (DECODE_EVENT_PACKET_MAX)) - /* ERSPAN events */ - ERSPAN_HEADER_TOO_SMALL, - ERSPAN_UNSUPPORTED_VERSION, - ERSPAN_TOO_MANY_VLAN_LAYERS, +/* supported decoder events */ - /* should always be last! */ - DECODE_EVENT_MAX, +struct DecodeEvents_ { + char *event_name; + uint8_t code; }; +extern const struct DecodeEvents_ DEvents[DECODE_EVENT_MAX]; #endif /* __DECODE_EVENTS_H__ */ diff --git a/src/decode.c b/src/decode.c index 4be4b9e70289..80d603a78190 100644 --- a/src/decode.c +++ b/src/decode.c @@ -109,9 +109,15 @@ void PacketFree(Packet *p) void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { - if (p->flags & PKT_IS_INVALID) + if (p->flags & PKT_IS_INVALID) { StatsIncr(tv, dtv->counter_invalid); - + int i = 0; + for (i = 0; i < p->events.cnt; i++) { + if (EVENT_IS_DECODER_PACKET_ERROR(p->events.events[i])) { + StatsIncr(tv, dtv->counter_invalid_events[p->events.events[i]]); + } + } + } #ifdef __SC_CUDA_SUPPORT__ if (dtv->cuda_vars.mpm_is_cuda) CudaBufferPacket(&dtv->cuda_vars, p); @@ -419,7 +425,13 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) StatsRegisterCounter("defrag.ipv6.timeouts", tv); dtv->counter_defrag_max_hit = StatsRegisterCounter("defrag.max_frag_hits", tv); - + + int i = 0; + for (i = 0; i < DECODE_EVENT_PACKET_MAX; i++) { + dtv->counter_invalid_events[i] = StatsRegisterCounter( + DEvents[i].event_name, tv); + } + return; } diff --git a/src/decode.h b/src/decode.h index f57dcea997fb..313bd3f51df7 100644 --- a/src/decode.h +++ b/src/decode.h @@ -626,6 +626,7 @@ typedef struct DecodeThreadVars_ uint16_t counter_flow_memcap; + uint16_t counter_invalid_events[DECODE_EVENT_PACKET_MAX]; /* thread data for flow logging api: only used at forced * flow recycle during lookups */ void *output_flow_thread_data; diff --git a/src/detect-engine-event.c b/src/detect-engine-event.c index 6b685d70543e..9a8e23967e99 100644 --- a/src/detect-engine-event.c +++ b/src/detect-engine-event.c @@ -38,12 +38,11 @@ /* Need to get the DEvents[] array */ -#define DETECT_EVENTS #include "detect-engine-event.h" #include "util-unittest.h" -#define PARSE_REGEX "\\S[0-9A-z_]+[.][A-z0-9_+]+$" +#define PARSE_REGEX "\\S[0-9A-z_]+[.][A-z0-9_+.]+$" static pcre *parse_regex; static pcre_extra *parse_regex_study; @@ -252,7 +251,12 @@ static void DetectEngineEventFree(void *ptr) */ static int DetectDecodeEventSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { - return _DetectEngineEventSetup(de_ctx, s, rawstr, DETECT_DECODE_EVENT); + char drawstr[MAX_SUBSTRINGS * 2] = "decoder."; + + /* decoder:$EVENT alias command develop as decode-event:decoder.$EVENT */ + strlcat(drawstr, rawstr, 2 * MAX_SUBSTRINGS - strlen("decoder.") - 1); + + return _DetectEngineEventSetup(de_ctx, s, drawstr, DETECT_DECODE_EVENT); } /** @@ -279,7 +283,7 @@ static int DetectStreamEventSetup (DetectEngineCtx *de_ctx, Signature *s, char * int EngineEventTestParse01 (void) { DetectEngineEventData *de = NULL; - de = DetectEngineEventParse("ipv4.pkt_too_small"); + de = DetectEngineEventParse("decoder.ipv4.pkt_too_small"); if (de) { DetectEngineEventFree(de); return 1; @@ -295,7 +299,7 @@ int EngineEventTestParse01 (void) int EngineEventTestParse02 (void) { DetectEngineEventData *de = NULL; - de = DetectEngineEventParse("PPP.pkt_too_small"); + de = DetectEngineEventParse("decoder.PPP.pkt_too_small"); if (de) { DetectEngineEventFree(de); return 1; @@ -310,7 +314,7 @@ int EngineEventTestParse02 (void) int EngineEventTestParse03 (void) { DetectEngineEventData *de = NULL; - de = DetectEngineEventParse("IPV6.PKT_TOO_SMALL"); + de = DetectEngineEventParse("decoder.IPV6.PKT_TOO_SMALL"); if (de) { DetectEngineEventFree(de); return 1; @@ -325,7 +329,7 @@ int EngineEventTestParse03 (void) int EngineEventTestParse04 (void) { DetectEngineEventData *de = NULL; - de = DetectEngineEventParse("IPV6.INVALID_EVENT"); + de = DetectEngineEventParse("decoder.IPV6.INVALID_EVENT"); if (de) { DetectEngineEventFree(de); return 1; @@ -340,7 +344,7 @@ int EngineEventTestParse04 (void) int EngineEventTestParse05 (void) { DetectEngineEventData *de = NULL; - de = DetectEngineEventParse("IPV-6,INVALID_CHAR"); + de = DetectEngineEventParse("decoder.IPV-6,INVALID_CHAR"); if (de) { DetectEngineEventFree(de); return 1; @@ -368,7 +372,7 @@ int EngineEventTestParse06 (void) ENGINE_SET_EVENT(p,PPP_PKT_TOO_SMALL); - de = DetectEngineEventParse("ppp.pkt_too_small"); + de = DetectEngineEventParse("decoder.ppp.pkt_too_small"); if (de == NULL) goto error; diff --git a/src/detect-engine-event.h b/src/detect-engine-event.h index 9ee152766ee0..3f52753bc546 100644 --- a/src/detect-engine-event.h +++ b/src/detect-engine-event.h @@ -33,226 +33,5 @@ typedef struct DetectEngineEventData_ { /* prototypes */ void DetectEngineEventRegister (void); -/* supported decoder events */ - -#ifdef DETECT_EVENTS -struct DetectEngineEvents_ { - char *event_name; - uint8_t code; -} DEvents[] = { - /* IPV4 EVENTS */ - { "ipv4.pkt_too_small", IPV4_PKT_TOO_SMALL, }, - { "ipv4.hlen_too_small", IPV4_HLEN_TOO_SMALL, }, - { "ipv4.iplen_smaller_than_hlen", IPV4_IPLEN_SMALLER_THAN_HLEN, }, - { "ipv4.trunc_pkt", IPV4_TRUNC_PKT, }, - - /* IPV4 OPTIONS */ - { "ipv4.opt_invalid", IPV4_OPT_INVALID, }, - { "ipv4.opt_invalid_len", IPV4_OPT_INVALID_LEN, }, - { "ipv4.opt_malformed", IPV4_OPT_MALFORMED, }, - { "ipv4.opt_pad_required", IPV4_OPT_PAD_REQUIRED, }, - { "ipv4.opt_eol_required", IPV4_OPT_EOL_REQUIRED, }, - { "ipv4.opt_duplicate", IPV4_OPT_DUPLICATE, }, - { "ipv4.opt_unknown", IPV4_OPT_UNKNOWN, }, - { "ipv4.wrong_ip_version", IPV4_WRONG_IP_VER, }, - { "ipv4.icmpv6", IPV4_WITH_ICMPV6, }, - - /* ICMP EVENTS */ - { "icmpv4.pkt_too_small", ICMPV4_PKT_TOO_SMALL, }, - { "icmpv4.unknown_type", ICMPV4_UNKNOWN_TYPE, }, - { "icmpv4.unknown_code", ICMPV4_UNKNOWN_CODE, }, - { "icmpv4.ipv4_trunc_pkt", ICMPV4_IPV4_TRUNC_PKT, }, - { "icmpv4.ipv4_unknown_ver", ICMPV4_IPV4_UNKNOWN_VER, }, - - /* ICMPv6 EVENTS */ - { "icmpv6.unknown_type", ICMPV6_UNKNOWN_TYPE,}, - { "icmpv6.unknown_code", ICMPV6_UNKNOWN_CODE,}, - { "icmpv6.pkt_too_small", ICMPV6_PKT_TOO_SMALL,}, - { "icmpv6.ipv6_unknown_version", ICMPV6_IPV6_UNKNOWN_VER,}, - { "icmpv6.ipv6_trunc_pkt", ICMPV6_IPV6_TRUNC_PKT,}, - { "icmpv6.mld_message_with_invalid_hl", ICMPV6_MLD_MESSAGE_WITH_INVALID_HL,}, - { "icmpv6.unassigned_type", ICMPV6_UNASSIGNED_TYPE,}, - { "icmpv6.experimentation_type", ICMPV6_EXPERIMENTATION_TYPE,}, - - /* IPV6 EVENTS */ - { "ipv6.pkt_too_small", IPV6_PKT_TOO_SMALL, }, - { "ipv6.trunc_pkt", IPV6_TRUNC_PKT, }, - { "ipv6.trunc_exthdr", IPV6_TRUNC_EXTHDR, }, - { "ipv6.exthdr_dupl_fh", IPV6_EXTHDR_DUPL_FH, }, - { "ipv6.exthdr_useless_fh", IPV6_EXTHDR_USELESS_FH, }, - { "ipv6.exthdr_dupl_rh", IPV6_EXTHDR_DUPL_RH, }, - { "ipv6.exthdr_dupl_hh", IPV6_EXTHDR_DUPL_HH, }, - { "ipv6.exthdr_dupl_dh", IPV6_EXTHDR_DUPL_DH, }, - { "ipv6.exthdr_dupl_ah", IPV6_EXTHDR_DUPL_AH, }, - { "ipv6.exthdr_dupl_eh", IPV6_EXTHDR_DUPL_EH, }, - { "ipv6.exthdr_invalid_optlen", IPV6_EXTHDR_INVALID_OPTLEN, }, - { "ipv6.wrong_ip_version", IPV6_WRONG_IP_VER, }, - { "ipv6.exthdr_ah_res_not_null", IPV6_EXTHDR_AH_RES_NOT_NULL, }, - { "ipv6.hopopts_unknown_opt", IPV6_HOPOPTS_UNKNOWN_OPT, }, - { "ipv6.hopopts_only_padding", IPV6_HOPOPTS_ONLY_PADDING, }, - { "ipv6.dstopts_unknown_opt", IPV6_DSTOPTS_UNKNOWN_OPT, }, - { "ipv6.dstopts_only_padding", IPV6_DSTOPTS_ONLY_PADDING, }, - { "ipv6.rh_type_0", IPV6_EXTHDR_RH_TYPE_0, }, - { "ipv6.zero_len_padn", IPV6_EXTHDR_ZERO_LEN_PADN, }, - { "ipv6.fh_non_zero_reserved_field", IPV6_FH_NON_ZERO_RES_FIELD, }, - { "ipv6.data_after_none_header", IPV6_DATA_AFTER_NONE_HEADER, }, - { "ipv6.unknown_next_header", IPV6_UNKNOWN_NEXT_HEADER, }, - { "ipv6.icmpv4", IPV6_WITH_ICMPV4, }, - - /* TCP EVENTS */ - { "tcp.pkt_too_small", TCP_PKT_TOO_SMALL, }, - { "tcp.hlen_too_small", TCP_HLEN_TOO_SMALL, }, - { "tcp.invalid_optlen", TCP_INVALID_OPTLEN, }, - - /* TCP OPTIONS */ - { "tcp.opt_invalid_len", TCP_OPT_INVALID_LEN, }, - { "tcp.opt_duplicate", TCP_OPT_DUPLICATE, }, - - /* UDP EVENTS */ - { "udp.pkt_too_small", UDP_PKT_TOO_SMALL, }, - { "udp.hlen_too_small", UDP_HLEN_TOO_SMALL, }, - { "udp.hlen_invalid", UDP_HLEN_INVALID, }, - - /* SLL EVENTS */ - { "sll.pkt_too_small", SLL_PKT_TOO_SMALL, }, - - /* ETHERNET EVENTS */ - { "ethernet.pkt_too_small", ETHERNET_PKT_TOO_SMALL, }, - - /* PPP EVENTS */ - { "ppp.pkt_too_small", PPP_PKT_TOO_SMALL, }, - { "ppp.vju_pkt_too_small", PPPVJU_PKT_TOO_SMALL, }, - { "ppp.ip4_pkt_too_small", PPPIPV4_PKT_TOO_SMALL, }, - { "ppp.ip6_pkt_too_small", PPPIPV6_PKT_TOO_SMALL, }, - { "ppp.wrong_type", PPP_WRONG_TYPE, }, /** unknown & invalid protocol */ - { "ppp.unsup_proto", PPP_UNSUP_PROTO, }, /** unsupported but valid protocol */ - - /* PPPOE EVENTS */ - { "pppoe.pkt_too_small", PPPOE_PKT_TOO_SMALL, }, - { "pppoe.wrong_code", PPPOE_WRONG_CODE, }, - { "pppoe.malformed_tags", PPPOE_MALFORMED_TAGS, }, - - /* GRE EVENTS */ - { "gre.pkt_too_small", GRE_PKT_TOO_SMALL, }, - { "gre.wrong_version", GRE_WRONG_VERSION, }, - { "gre.version0_recur", GRE_VERSION0_RECUR, }, - { "gre.version0_flags", GRE_VERSION0_FLAGS, }, - { "gre.version0_hdr_too_big", GRE_VERSION0_HDR_TOO_BIG, }, - { "gre.version0_malformed_sre_hdr", GRE_VERSION0_MALFORMED_SRE_HDR, }, - { "gre.version1_chksum", GRE_VERSION1_CHKSUM, }, - { "gre.version1_route", GRE_VERSION1_ROUTE, }, - { "gre.version1_ssr", GRE_VERSION1_SSR, }, - { "gre.version1_recur", GRE_VERSION1_RECUR, }, - { "gre.version1_flags", GRE_VERSION1_FLAGS, }, - { "gre.version1_no_key", GRE_VERSION1_NO_KEY, }, - { "gre.version1_wrong_protocol", GRE_VERSION1_WRONG_PROTOCOL, }, - { "gre.version1_malformed_sre_hdr", GRE_VERSION1_MALFORMED_SRE_HDR, }, - { "gre.version1_hdr_too_big", GRE_VERSION1_HDR_TOO_BIG, }, - - /* VLAN EVENTS */ - { "vlan.header_too_small",VLAN_HEADER_TOO_SMALL, }, - { "vlan.unknown_type",VLAN_UNKNOWN_TYPE, }, - { "vlan.too_many_layers", VLAN_HEADER_TOO_MANY_LAYERS, }, - - /* RAW EVENTS */ - { "ipraw.invalid_ip_version",IPRAW_INVALID_IPV, }, - - /* LINKTYPE NULL EVENTS */ - { "ltnull.pkt_too_small", LTNULL_PKT_TOO_SMALL, }, - { "ltnull.unsupported_type", LTNULL_UNSUPPORTED_TYPE, }, - - /* STREAM EVENTS */ - { "stream.3whs_ack_in_wrong_dir", STREAM_3WHS_ACK_IN_WRONG_DIR, }, - { "stream.3whs_async_wrong_seq", STREAM_3WHS_ASYNC_WRONG_SEQ, }, - { "stream.3whs_right_seq_wrong_ack_evasion", STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION, }, - { "stream.3whs_synack_in_wrong_direction", STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION, }, - { "stream.3whs_synack_resend_with_different_ack", STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK, }, - { "stream.3whs_synack_resend_with_diff_seq", STREAM_3WHS_SYNACK_RESEND_WITH_DIFF_SEQ, }, - { "stream.3whs_synack_toserver_on_syn_recv", STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV, }, - { "stream.3whs_synack_with_wrong_ack", STREAM_3WHS_SYNACK_WITH_WRONG_ACK, }, - { "stream.3whs_synack_flood", STREAM_3WHS_SYNACK_FLOOD, }, - { "stream.3whs_syn_resend_diff_seq_on_syn_recv", STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV, }, - { "stream.3whs_syn_toclient_on_syn_recv", STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV, }, - { "stream.3whs_wrong_seq_wrong_ack", STREAM_3WHS_WRONG_SEQ_WRONG_ACK, }, - { "stream.4whs_synack_with_wrong_ack", STREAM_4WHS_SYNACK_WITH_WRONG_ACK, }, - { "stream.4whs_synack_with_wrong_syn", STREAM_4WHS_SYNACK_WITH_WRONG_SYN, }, - { "stream.4whs_wrong_seq", STREAM_4WHS_WRONG_SEQ, }, - { "stream.4whs_invalid_ack", STREAM_4WHS_INVALID_ACK, }, - { "stream.closewait_ack_out_of_window", STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW, }, - { "stream.closewait_fin_out_of_window", STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW, }, - { "stream.closewait_pkt_before_last_ack", STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK, }, - { "stream.closewait_invalid_ack", STREAM_CLOSEWAIT_INVALID_ACK, }, - { "stream.closing_ack_wrong_seq", STREAM_CLOSING_ACK_WRONG_SEQ, }, - { "stream.closing_invalid_ack", STREAM_CLOSING_INVALID_ACK, }, - { "stream.est_packet_out_of_window", STREAM_EST_PACKET_OUT_OF_WINDOW, }, - { "stream.est_pkt_before_last_ack", STREAM_EST_PKT_BEFORE_LAST_ACK, }, - { "stream.est_synack_resend", STREAM_EST_SYNACK_RESEND, }, - { "stream.est_synack_resend_with_different_ack", STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK, }, - { "stream.est_synack_resend_with_diff_seq", STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ, }, - { "stream.est_synack_toserver", STREAM_EST_SYNACK_TOSERVER, }, - { "stream.est_syn_resend", STREAM_EST_SYN_RESEND, }, - { "stream.est_syn_resend_diff_seq", STREAM_EST_SYN_RESEND_DIFF_SEQ, }, - { "stream.est_syn_toclient", STREAM_EST_SYN_TOCLIENT, }, - { "stream.est_invalid_ack", STREAM_EST_INVALID_ACK, }, - { "stream.fin_invalid_ack", STREAM_FIN_INVALID_ACK, }, - { "stream.fin1_ack_wrong_seq", STREAM_FIN1_ACK_WRONG_SEQ, }, - { "stream.fin1_fin_wrong_seq", STREAM_FIN1_FIN_WRONG_SEQ, }, - { "stream.fin1_invalid_ack", STREAM_FIN1_INVALID_ACK, }, - { "stream.fin2_ack_wrong_seq", STREAM_FIN2_ACK_WRONG_SEQ, }, - { "stream.fin2_fin_wrong_seq", STREAM_FIN2_FIN_WRONG_SEQ, }, - { "stream.fin2_invalid_ack", STREAM_FIN2_INVALID_ACK, }, - { "stream.fin_but_no_session", STREAM_FIN_BUT_NO_SESSION, }, - { "stream.fin_out_of_window", STREAM_FIN_OUT_OF_WINDOW, }, - { "stream.lastack_ack_wrong_seq", STREAM_LASTACK_ACK_WRONG_SEQ, }, - { "stream.lastack_invalid_ack", STREAM_LASTACK_INVALID_ACK, }, - { "stream.rst_but_no_session", STREAM_RST_BUT_NO_SESSION, }, - { "stream.timewait_ack_wrong_seq", STREAM_TIMEWAIT_ACK_WRONG_SEQ, }, - { "stream.timewait_invalid_ack", STREAM_TIMEWAIT_INVALID_ACK, }, - { "stream.pkt_invalid_timestamp", STREAM_PKT_INVALID_TIMESTAMP, }, - { "stream.pkt_invalid_ack", STREAM_PKT_INVALID_ACK, }, - { "stream.pkt_broken_ack", STREAM_PKT_BROKEN_ACK, }, - { "stream.rst_invalid_ack", STREAM_RST_INVALID_ACK, }, - { "stream.shutdown_syn_resend", STREAM_SHUTDOWN_SYN_RESEND, }, - { "stream.pkt_retransmission", STREAM_PKT_RETRANSMISSION, }, - { "stream.reassembly_segment_before_base_seq", STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ, }, - { "stream.reassembly_no_segment", STREAM_REASSEMBLY_NO_SEGMENT, }, - { "stream.reassembly_seq_gap", STREAM_REASSEMBLY_SEQ_GAP, }, - { "stream.reassembly_overlap_different_data", STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, }, - { "stream.pkt_bad_window_update", STREAM_PKT_BAD_WINDOW_UPDATE, }, - - /* SCTP EVENTS */ - { "sctp.pkt_too_small", SCTP_PKT_TOO_SMALL, }, - - /* Fragmentation reasembly events. */ - { "ipv4.frag_too_large", IPV4_FRAG_PKT_TOO_LARGE, }, - { "ipv6.frag_too_large", IPV6_FRAG_PKT_TOO_LARGE, }, - { "ipv4.frag_overlap", IPV4_FRAG_OVERLAP, }, - { "ipv6.frag_overlap", IPV6_FRAG_OVERLAP, }, - /* Fragment ignored due to internal error */ - { "ipv4.frag_ignored", IPV4_FRAG_IGNORED, }, - { "ipv6.frag_ignored", IPV6_FRAG_IGNORED, }, - - /* IPv4 in IPv6 events */ - { "ipv6.ipv4_in_ipv6_too_small", IPV4_IN_IPV6_PKT_TOO_SMALL, }, - { "ipv6.ipv4_in_ipv6_wrong_version", IPV4_IN_IPV6_WRONG_IP_VER, }, - /* IPv6 in IPv6 events */ - { "ipv6.ipv6_in_ipv6_too_small", IPV6_IN_IPV6_PKT_TOO_SMALL, }, - { "ipv6.ipv6_in_ipv6_wrong_version", IPV6_IN_IPV6_WRONG_IP_VER, }, - - /* MPLS events */ - { "mpls.bad_label_router_alert", MPLS_BAD_LABEL_ROUTER_ALERT, }, - { "mpls.bad_label_implicit_null", MPLS_BAD_LABEL_IMPLICIT_NULL, }, - { "mpls.bad_label_reserved", MPLS_BAD_LABEL_RESERVED, }, - { "mpls.unknown_payload_type", MPLS_UNKNOWN_PAYLOAD_TYPE, }, - - /* ERSPAN events */ - { "erspan.header_too_small", ERSPAN_HEADER_TOO_SMALL, }, - { "erspan.unsupported_version", ERSPAN_UNSUPPORTED_VERSION, }, - { "erspan.too_many_vlan_layers", ERSPAN_TOO_MANY_VLAN_LAYERS, }, - - { NULL, 0 }, -}; -#endif /* DETECT_EVENTS */ - #endif /*__DETECT_ENGINE_EVENT_H__ */ From 81878c1998759741baf511ca97149c5612369ffb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 7 Oct 2015 15:56:01 +0200 Subject: [PATCH 1063/2553] Add global MAX macro. --- src/suricata-common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/suricata-common.h b/src/suricata-common.h index 660a0bfecc3e..18791c3b04bc 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -297,6 +297,10 @@ #define MIN(x, y) (((x)<(y))?(x):(y)) #endif +#ifndef MAX +#define MAX(x, y) (((x)<(y))?(y):(x)) +#endif + typedef enum PacketProfileDetectId_ { PROF_DETECT_MPM, PROF_DETECT_MPM_PACKET, /* PKT MPM */ From 12d7c86efca06986b75c61865dd861115a05d571 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 22 Dec 2015 10:09:49 +0100 Subject: [PATCH 1064/2553] stream-tcp: improve function doc --- src/stream-tcp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 9ccb6a2940eb..f0a3fbdac987 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -641,9 +641,10 @@ void StreamTcpFreeConfig(char quiet) /** \brief The function is used to to fetch a TCP session from the * ssn_pool, when a TCP SYN is received. * - * \param quiet Packet P, which has been recieved for the new TCP session. + * \param p packet starting the new TCP session. + * \param id thread pool id * - * \retval TcpSession A new TCP session with field initilaized to 0/NULL. + * \retval ssn new TCP session. */ TcpSession *StreamTcpNewSession (Packet *p, int id) { From c91546022dc9a2161180ec6efcc62c108eb4f9d4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 9 Mar 2016 17:02:06 +0100 Subject: [PATCH 1065/2553] smtp: clean up thread local memory --- src/detect-engine.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 79fc15d30e3d..97032f260738 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1678,6 +1678,17 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) SCFree(det_ctx->hcbd); } + /* SMTP */ + if (det_ctx->smtp != NULL) { + SCLogDebug("det_ctx smtp %u", det_ctx->smtp_buffers_size); + for (i = 0; i < det_ctx->smtp_buffers_size; i++) { + if (det_ctx->smtp[i].buffer != NULL) + SCFree(det_ctx->smtp[i].buffer); + SCLogDebug("det_ctx->smtp[i].buffer_size %u", det_ctx->smtp[i].buffer_size); + } + SCFree(det_ctx->smtp); + } + /* Decoded base64 data. */ if (det_ctx->base64_decoded != NULL) { SCFree(det_ctx->base64_decoded); From e91b9bf22b5768f4919bde1606fdc93ab75951fd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 12 Mar 2016 10:32:54 +0100 Subject: [PATCH 1066/2553] Fix compilation on systems with Musl --- src/util-cpu.c | 2 +- src/util-privs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-cpu.c b/src/util-cpu.c index f8f748bc7060..9a5c25df1308 100644 --- a/src/util-cpu.c +++ b/src/util-cpu.c @@ -23,9 +23,9 @@ * Retrieve CPU information (configured CPUs, online CPUs) */ +#include "suricata-common.h" #include "util-error.h" #include "util-debug.h" -#include "suricata-common.h" /** * Ok, if they should use sysconf, check that they have the macro's diff --git a/src/util-privs.c b/src/util-privs.c index 635247c3e590..e6e3d6c591a8 100644 --- a/src/util-privs.c +++ b/src/util-privs.c @@ -28,8 +28,8 @@ #include #include -#include "util-debug.h" #include "suricata-common.h" +#include "util-debug.h" #include "suricata.h" #ifdef HAVE_LIBCAP_NG From 339f066533e94ca4be3a1c03cee476a377ac9ed0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 06:54:03 +0100 Subject: [PATCH 1067/2553] afpacket: suppress harmless Coverity warning (1192960) --- src/source-af-packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 2beb17037c72..9ae4643d9904 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -982,7 +982,7 @@ static int AFPReadAndDiscard(AFPThreadVars *ptv, struct timeval *synctv) iov.iov_len = ptv->datalen; iov.iov_base = ptv->data; - recvmsg(ptv->socket, &msg, MSG_TRUNC); + (void)recvmsg(ptv->socket, &msg, MSG_TRUNC); if (ioctl(ptv->socket, SIOCGSTAMP, &ts) == -1) { /* FIXME */ From dff9f65ce738094d1881053e1a41ddcfb9b032c7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 06:56:35 +0100 Subject: [PATCH 1068/2553] lua: fix minor coverity issues Remove checks that can never be false. CID 1232076, 1312012 --- src/output-lua.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/output-lua.c b/src/output-lua.c index 4bfe49558440..041e83efe783 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -471,7 +471,7 @@ static int LuaFileLogger(ThreadVars *tv, void *thread_data, const Packet *p, con /* Get the TX so the script can get more context about it. * TODO hardcoded to HTTP currently */ void *txptr = NULL; - if (p && p->flow && p->flow->alstate) + if (p->flow && p->flow->alstate) txptr = AppLayerParserGetTx(p->proto, ALPROTO_HTTP, p->flow->alstate, ff->txid); SCMutexLock(&td->lua_ctx->m); @@ -980,12 +980,9 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) return output_ctx; error: - - if (output_ctx != NULL) { - if (output_ctx->DeInit && output_ctx->data) - output_ctx->DeInit(output_ctx->data); - SCFree(output_ctx); - } + if (output_ctx->DeInit && output_ctx->data) + output_ctx->DeInit(output_ctx->data); + SCFree(output_ctx); return NULL; } From 2a7f06843814d3216e4f623c58e80ef4d19638c6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 07:01:06 +0100 Subject: [PATCH 1069/2553] ioctl: fix NULL check after dereference (CID 1204326) --- src/util-ioctl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 99a84a7e62c8..e0b5ef824b2d 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -117,18 +117,16 @@ int GetIfaceMTU(const char *pcap_dev) */ int GetIfaceMaxPacketSize(const char *pcap_dev) { - int ll_header = GetIfaceMaxHWHeaderLength(pcap_dev); - int mtu = 0; - if ((pcap_dev == NULL) || strlen(pcap_dev) == 0) return 0; - mtu = GetIfaceMTU(pcap_dev); + int mtu = GetIfaceMTU(pcap_dev); switch (mtu) { case 0: case -1: return 0; } + int ll_header = GetIfaceMaxHWHeaderLength(pcap_dev); if (ll_header == -1) { /* be conservative, choose a big one */ ll_header = 16; From c858bfea4a2e2cdd3d8d38b3223056d73afaf249 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 07:07:07 +0100 Subject: [PATCH 1070/2553] base64_decode: fix potential keyword parsing issue (CID 1340064) --- src/detect-base64-decode.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index bd9baea583ba..e06e6f870c28 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -310,6 +310,9 @@ static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s, } else { sm_list = SigMatchListSMBelongsTo(s, pm); + if (sm_list < 0) { + goto error; + } } } From a46c4da33886021c7847ce445634ab8f1b1be8ef Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 07:14:39 +0100 Subject: [PATCH 1071/2553] lua: fix unlikely null-deref during setup (CID 1351209) --- src/runmodes.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/runmodes.c b/src/runmodes.c index d9e06af78521..601d356b9173 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -822,6 +822,9 @@ void RunModeInitializeOutputs(void) } else if (strcmp(output->val, "lua") == 0) { SCLogDebug("handle lua"); + if (output_ctx == NULL) + continue; + OutputModule *lua_module = OutputGetModuleByConfName(output->val); BUG_ON(lua_module == NULL); AddOutputToFreeList(lua_module, output_ctx); From b4912f3bf984740b2288b080c785ae4d1b4bccb9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 09:23:07 +0100 Subject: [PATCH 1072/2553] unified2: fix unused value warning (CID 1247404) --- src/alert-unified2-alert.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index facc66b231a1..ebfa1822b49d 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -518,7 +518,6 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 int ethh_offset = 0; EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) }; uint32_t hdr_length = 0; - int datalink = p->datalink; memset(hdr, 0, sizeof(Unified2AlertFileHeader)); memset(phdr, 0, sizeof(Unified2Packet)); @@ -527,7 +526,7 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 aun->hdr = hdr; phdr->sensor_id = htonl(sensor_id); - phdr->linktype = htonl(datalink); + phdr->linktype = htonl(p->datalink); phdr->event_id = aun->event_id; phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec); phdr->packet_microsecond = htonl(p->ts.tv_usec); @@ -536,7 +535,6 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 if (p->datalink != DLT_EN10MB) { /* We have raw data here */ phdr->linktype = htonl(DLT_RAW); - datalink = DLT_RAW; } aun->length += sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE; @@ -550,8 +548,7 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 if (p->datalink == DLT_EN10MB) { /* Fake this */ ethh_offset = 14; - datalink = DLT_EN10MB; - phdr->linktype = htonl(datalink); + phdr->linktype = htonl(DLT_EN10MB); aun->length += ethh_offset; if (aun->length > aun->datalen) { @@ -593,8 +590,7 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 if (p->datalink == DLT_EN10MB) { /* Fake this */ ethh_offset = 14; - datalink = DLT_EN10MB; - phdr->linktype = htonl(datalink); + phdr->linktype = htonl(DLT_EN10MB); aun->length += ethh_offset; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); From bfc4be230c150ab3a1e1c8df2fdb4605a95a372b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 09:25:23 +0100 Subject: [PATCH 1073/2553] htp: fix dead code warning (CID 1153933) --- src/app-layer-htp.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 9a8c27dad562..384dbeea31b5 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -285,8 +285,9 @@ static void *HTPStateAlloc(void) SCEnter(); HtpState *s = HTPMalloc(sizeof(HtpState)); - if (unlikely(s == NULL)) - goto error; + if (unlikely(s == NULL)) { + SCReturnPtr(NULL, "void"); + } memset(s, 0x00, sizeof(HtpState)); @@ -299,13 +300,6 @@ static void *HTPStateAlloc(void) #endif SCReturnPtr((void *)s, "void"); - -error: - if (s != NULL) { - HTPFree(s, sizeof(HtpState)); - } - - SCReturnPtr(NULL, "void"); } static void HtpTxUserDataFree(HtpState *state, HtpTxUserData *htud) From 665cafbe3bb07683700bad68ba7f2c85a47da1c4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 09:29:20 +0100 Subject: [PATCH 1074/2553] htp: fix boundry error handling (CID 1153934) --- src/app-layer-htp.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 384dbeea31b5..008aeff4c8c3 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1090,7 +1090,7 @@ static int HtpRequestBodySetupBoundary(HtpTxUserData *htud, uint8_t eb_len = htud->boundary_len + 2; eb = (uint8_t *)HTPMalloc(eb_len); if (eb == NULL) { - goto error; + SCReturnInt(-1); } memset(eb, '-', eb_len); memcpy(eb + 2, htud->boundary, htud->boundary_len); @@ -1098,7 +1098,8 @@ static int HtpRequestBodySetupBoundary(HtpTxUserData *htud, uint8_t ebe_len = htud->boundary_len + 4; ebe = (uint8_t *)HTPMalloc(ebe_len); if (ebe == NULL) { - goto error; + HTPFree(eb, eb_len); + SCReturnInt(-1); } memset(ebe, '-', ebe_len); memcpy(ebe + 2, htud->boundary, htud->boundary_len); @@ -1109,15 +1110,6 @@ static int HtpRequestBodySetupBoundary(HtpTxUserData *htud, *expected_boundary_end_len = ebe_len; SCReturnInt(0); - -error: - if (eb != NULL) { - HTPFree(eb, eb_len); - } - if (ebe != NULL) { - HTPFree(ebe, ebe_len); - } - SCReturnInt(-1); } #define C_D_HDR "content-disposition:" From 444c4b546ea68d9a6adb25332ccdf757c89d9a60 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 09:39:20 +0100 Subject: [PATCH 1075/2553] htp: optimize multipart parsing Store boundary in a single stack buffer instead of 2 heap allocated buffers. --- src/app-layer-htp.c | 74 ++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 55 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 008aeff4c8c3..871519cb7cd5 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1077,41 +1077,6 @@ static int HtpRequestBodySetupMultipart(htp_tx_data_t *d, HtpTxUserData *htud) SCReturnInt(0); } -/** - * \brief Setup boundary buffers - */ -static int HtpRequestBodySetupBoundary(HtpTxUserData *htud, - uint8_t **expected_boundary, uint8_t *expected_boundary_len, - uint8_t **expected_boundary_end, uint8_t *expected_boundary_end_len) -{ - uint8_t *eb = NULL; - uint8_t *ebe = NULL; - - uint8_t eb_len = htud->boundary_len + 2; - eb = (uint8_t *)HTPMalloc(eb_len); - if (eb == NULL) { - SCReturnInt(-1); - } - memset(eb, '-', eb_len); - memcpy(eb + 2, htud->boundary, htud->boundary_len); - - uint8_t ebe_len = htud->boundary_len + 4; - ebe = (uint8_t *)HTPMalloc(ebe_len); - if (ebe == NULL) { - HTPFree(eb, eb_len); - SCReturnInt(-1); - } - memset(ebe, '-', ebe_len); - memcpy(ebe + 2, htud->boundary, htud->boundary_len); - - *expected_boundary = eb; - *expected_boundary_len = eb_len; - *expected_boundary_end = ebe; - *expected_boundary_end_len = ebe_len; - - SCReturnInt(0); -} - #define C_D_HDR "content-disposition:" #define C_D_HDR_LEN 20 #define C_T_HDR "content-type:" @@ -1261,14 +1226,23 @@ static void HtpRequestBodyReassemble(HtpTxUserData *htud, *chunks_buffer_len = buf_len; } +/** + * \brief Setup boundary buffers + */ +static void HtpRequestBodySetupBoundary(HtpTxUserData *htud, + uint8_t *boundary, uint32_t boundary_len) +{ + memset(boundary, '-', boundary_len); + memcpy(boundary + 2, htud->boundary, htud->boundary_len); +} + int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, void *tx, uint8_t *chunks_buffer, uint32_t chunks_buffer_len) { int result = 0; - uint8_t *expected_boundary = NULL; - uint8_t *expected_boundary_end = NULL; - uint8_t expected_boundary_len = 0; - uint8_t expected_boundary_end_len = 0; + uint8_t boundary[htud->boundary_len + 4]; /**< size limited to HTP_BOUNDARY_MAX + 4 */ + uint8_t expected_boundary_len = htud->boundary_len + 2; + uint8_t expected_boundary_end_len = htud->boundary_len + 4; int tx_progress = 0; #ifdef PRINT @@ -1277,21 +1251,18 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, printf("CHUNK END: \n"); #endif - if (HtpRequestBodySetupBoundary(htud, &expected_boundary, &expected_boundary_len, - &expected_boundary_end, &expected_boundary_end_len) < 0) { - goto end; - } + HtpRequestBodySetupBoundary(htud, boundary, htud->boundary_len + 4); /* search for the header start, header end and form end */ uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len, - expected_boundary, expected_boundary_len); + boundary, expected_boundary_len); uint8_t *header_end = NULL; if (header_start != NULL) { header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer), (uint8_t *)"\r\n\r\n", 4); } uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len, - expected_boundary_end, expected_boundary_end_len); + boundary, expected_boundary_end_len); SCLogDebug("header_start %p, header_end %p, form_end %p", header_start, header_end, form_end); @@ -1428,7 +1399,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, /* or is it? */ uint8_t *header_next = Bs2bmSearch(filedata, filedata_len, - expected_boundary, expected_boundary_len); + boundary, expected_boundary_len); if (header_next != NULL) { filedata_len -= (form_end - header_next); } @@ -1481,7 +1452,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, /* form doesn't end in this chunk, but part might. Lets * see if have another coming up */ uint8_t *header_next = Bs2bmSearch(filedata, filedata_len, - expected_boundary, expected_boundary_len); + boundary, expected_boundary_len); SCLogDebug("header_next %p", header_next); if (header_next == NULL) { /* no, but we'll handle the file data when we see the @@ -1531,7 +1502,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, uint32_t cursizeread = header_end - chunks_buffer; header_start = Bs2bmSearch(header_end + 4, chunks_buffer_len - (cursizeread + 4), - expected_boundary, expected_boundary_len); + boundary, expected_boundary_len); if (header_start != NULL) { header_end = Bs2bmSearch(header_end + 4, chunks_buffer_len - (cursizeread + 4), @@ -1552,13 +1523,6 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, } end: - if (expected_boundary != NULL) { - HTPFree(expected_boundary, expected_boundary_len); - } - if (expected_boundary_end != NULL) { - HTPFree(expected_boundary_end, expected_boundary_end_len); - } - SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed); return 0; } From ed93e9394d4ded1c34d19dc6beb2e1f5ef644a47 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 09:46:38 +0100 Subject: [PATCH 1076/2553] coverity: suppress CID 1038112 --- src/detect-pktvar.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detect-pktvar.c b/src/detect-pktvar.c index c841f69d359c..075744e41024 100644 --- a/src/detect-pktvar.c +++ b/src/detect-pktvar.c @@ -211,6 +211,8 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst len = x; } + /* coverity[alloc_strlen : FALSE] + * not an actual string, but a byte array */ cd->content = SCMalloc(len); if (cd->content == NULL) { SCFree(cd); From f17ef5e46b5fbcebf0027604a5b8f5fb8e5f2219 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 09:49:57 +0100 Subject: [PATCH 1077/2553] daemon: suppress coverity resource leak warning (CID 400725) --- src/util-daemon.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/util-daemon.c b/src/util-daemon.c index 2eec7af13b54..5aab8509e22a 100644 --- a/src/util-daemon.c +++ b/src/util-daemon.c @@ -89,12 +89,9 @@ static void SetupLogging (void) int fd = open("/dev/null", O_RDWR); if (fd < 0) return; - if (dup2(fd, 0) < 0) - return; - if (dup2(fd, 1) < 0) - return; - if (dup2(fd, 2) < 0) - return; + (void)dup2(fd, 0); + (void)dup2(fd, 1); + (void)dup2(fd, 2); close(fd); } From 7602f650b1ba3a7e043d80e7ac8dd1df5469b5ea Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 11 Mar 2016 12:55:38 +0100 Subject: [PATCH 1078/2553] app-layer-ssl: fix memleak Avoid that the SNI extension code is executed twice sometimes, causing memory leaks. --- src/app-layer-ssl.c | 40 ++++++++++++++++++++++++++++++++++++++-- src/app-layer-ssl.h | 6 ++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 5650509b4a62..8bb2e6b1d3ba 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -65,6 +65,9 @@ SCEnumCharMap tls_decoder_event_table[ ] = { { "INVALID_HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_INVALID_HEARTBEAT }, { "OVERFLOW_HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT }, { "DATALEAK_HEARTBEAT_MISMATCH", TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH }, + { "MULTIPLE_SNI_EXTENSIONS", TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS }, + { "INVALID_SNI_TYPE", TLS_DECODER_EVENT_INVALID_SNI_TYPE }, + { "INVALID_SNI_LENGTH", TLS_DECODER_EVENT_INVALID_SNI_LENGTH }, /* Certificates decoding messages */ { "INVALID_CERTIFICATE", TLS_DECODER_EVENT_INVALID_CERTIFICATE }, { "CERTIFICATE_MISSING_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT }, @@ -205,8 +208,31 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, switch (ext_type) { case SSL_EXTENSION_SNI: { - /* skip sni_list_length and sni_type */ - input += 3; + /* there must not be more than one extension of the same + type (RFC5246 section 7.4.1.4) */ + if (ssl_state->curr_connp->sni) { + SCLogDebug("Multiple SNI extensions"); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS); + return -1; + } + + /* skip sni_list_length */ + input += 2; + + if (!(HAS_SPACE(1))) + goto end; + + uint8_t sni_type = *(input++); + + /* currently the only type allowed is host_name + (RFC6066 section 3) */ + if (sni_type != SSL_SNI_TYPE_HOST_NAME) { + SCLogDebug("Unknown SNI type"); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SNI_TYPE); + return -1; + } if (!(HAS_SPACE(2))) goto end; @@ -217,6 +243,16 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, if (!(HAS_SPACE(sni_len))) goto end; + /* host_name contains the fully qualified domain name, + and should therefore be limited by the maximum domain + name length */ + if (sni_len > 255) { + SCLogDebug("SNI length >255"); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SNI_LENGTH); + return -1; + } + size_t sni_strlen = sni_len + 1; ssl_state->curr_connp->sni = SCMalloc(sni_strlen); diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index e6274249b9e4..b38035254ee9 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -40,6 +40,9 @@ enum { TLS_DECODER_EVENT_INVALID_HEARTBEAT, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT, TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH, + TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS, + TLS_DECODER_EVENT_INVALID_SNI_TYPE, + TLS_DECODER_EVENT_INVALID_SNI_LENGTH, /* Certificates decoding messages */ TLS_DECODER_EVENT_INVALID_CERTIFICATE, TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT, @@ -89,6 +92,9 @@ enum { /* extensions */ #define SSL_EXTENSION_SNI 0x0000 +/* SNI types */ +#define SSL_SNI_TYPE_HOST_NAME 0 + /* SSL versions. We'll use a unified format for all, with the top byte * holding the major version and the lower byte the minor version */ enum { From 33fd710367f492f80fc5f8a532a9f3afc7ab63bd Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 15 Mar 2016 08:08:07 +0100 Subject: [PATCH 1079/2553] rules: add rules for TLS SNI app layer events --- rules/tls-events.rules | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rules/tls-events.rules b/rules/tls-events.rules index f9e886894f05..eccaaf568277 100644 --- a/rules/tls-events.rules +++ b/rules/tls-events.rules @@ -18,10 +18,12 @@ alert tls any any -> any any (msg:"SURICATA TLS certificate invalid length"; flo alert tls any any -> any any (msg:"SURICATA TLS certificate invalid string"; flow:established; app-layer-event:tls.certificate_invalid_string; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230008; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS error message encountered"; flow:established; app-layer-event:tls.error_message_encountered; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230009; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS invalid record/traffic"; flow:established; app-layer-event:tls.invalid_ssl_record; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230010; rev:1;) - alert tls any any -> any any (msg:"SURICATA TLS heartbeat encountered"; flow:established; app-layer-event:tls.heartbeat_message; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230011; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS overflow heartbeat encountered, possible exploit attempt (heartbleed)"; flow:established; app-layer-event:tls.overflow_heartbeat_message; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; reference:cve,2014-0160; sid:2230012; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS invalid heartbeat encountered, possible exploit attempt (heartbleed)"; flow:established; app-layer-event:tls.invalid_heartbeat_message; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; reference:cve,2014-0160; sid:2230013; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS invalid encrypted heartbeat encountered, possible exploit attempt (heartbleed)"; flow:established; app-layer-event:tls.dataleak_heartbeat_mismatch; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; reference:cve,2014-0160; sid:2230014; rev:1;) +alert tls any any -> any any (msg:"SURICATA TLS multiple SNI extensions"; flow:established,to_server; app-layer-event:tls.multiple_sni_extensions; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230016; rev:1;) +alert tls any any -> any any (msg:"SURICATA TLS invalid SNI type"; flow:established,to_server; app-layer-event:tls.invalid_sni_type; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230017; rev:1;) +alert tls any any -> any any (msg:"SURICATA TLS invalid SNI length"; flow:established,to_server; app-layer-event:tls.invalid_sni_length; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230018; rev:1;) -#next sid is 2230016 +#next sid is 2230019 From 8394b38941492b7264e26c14b8fa435c859d2497 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 7 Mar 2016 16:55:09 +0100 Subject: [PATCH 1080/2553] cppcheck: work around snprintf warning Cppcheck 1.72 gives a warning on the following code pattern: char blah[32] = ""; snprintf(blah, sizeof(blah), "something"); The warning is: (error) Buffer is accessed out of bounds. While this appears to be a FP, in most cases the initialization to "" was unnecessary as the snprintf statement immediately follows the variable declaration. --- src/detect-engine-loader.c | 2 +- src/detect-engine.c | 4 +++- src/detect.c | 4 +++- src/flow-manager.c | 4 ++-- src/log-tcp-data.c | 5 +++-- src/output-json-flow.c | 2 +- src/output-json-netflow.c | 4 ++-- src/runmode-unix-socket.c | 2 +- src/util-classification-config.c | 2 +- src/util-debug.h | 5 ++--- src/util-reference-config.c | 2 +- src/util-rule-vars.c | 2 +- src/util-threshold-config.c | 2 +- 13 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/detect-engine-loader.c b/src/detect-engine-loader.c index b360cd0406b3..c3a79b5cbe14 100644 --- a/src/detect-engine-loader.c +++ b/src/detect-engine-loader.c @@ -267,7 +267,7 @@ void DetectLoaderThreadSpawn() for (i = 0; i < num_loaders; i++) { ThreadVars *tv_loader = NULL; - char name[32] = ""; + char name[32]; snprintf(name, sizeof(name), "DetectLoader%02d", i+1); tv_loader = TmThreadCreateCmdThreadByName("DetectLoader", diff --git a/src/detect-engine.c b/src/detect-engine.c index 97032f260738..492f2f108746 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2524,7 +2524,9 @@ int DetectEngineReload(const char *filename, SCInstance *suri) DetectEngineCtx *new_de_ctx = NULL; DetectEngineCtx *old_de_ctx = NULL; - char prefix[128] = ""; + char prefix[128]; + memset(prefix, 0, sizeof(prefix)); + if (filename != NULL) { snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++); if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { diff --git a/src/detect.c b/src/detect.c index 74a1b8a927c4..3626d2e21330 100644 --- a/src/detect.c +++ b/src/detect.c @@ -254,11 +254,13 @@ char *DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, char *sig_file) { char *defaultpath = NULL; char *path = NULL; - char varname[128] = "default-rule-path"; + char varname[128]; if (strlen(de_ctx->config_prefix) > 0) { snprintf(varname, sizeof(varname), "%s.default-rule-path", de_ctx->config_prefix); + } else { + snprintf(varname, sizeof(varname), "default-rule-path"); } /* Path not specified */ diff --git a/src/flow-manager.c b/src/flow-manager.c index 15ad6162a0f1..6bc10ba4ccf8 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -728,7 +728,7 @@ void FlowManagerThreadSpawn() for (u = 0; u < flowmgr_number; u++) { ThreadVars *tv_flowmgr = NULL; - char name[32] = ""; + char name[32]; snprintf(name, sizeof(name), "FlowManagerThread%02u", u+1); tv_flowmgr = TmThreadCreateMgmtThreadByName("FlowManagerThread", @@ -888,7 +888,7 @@ void FlowRecyclerThreadSpawn() for (u = 0; u < flowrec_number; u++) { ThreadVars *tv_flowmgr = NULL; - char name[32] = ""; + char name[32]; snprintf(name, sizeof(name), "FlowRecyclerThread%02u", u+1); tv_flowmgr = TmThreadCreateMgmtThreadByName("FlowRecyclerThread", diff --git a/src/log-tcp-data.c b/src/log-tcp-data.c index c41dd4c238c3..0cf2f225f392 100644 --- a/src/log-tcp-data.c +++ b/src/log-tcp-data.c @@ -112,9 +112,10 @@ static int LogTcpDataLoggerDir(ThreadVars *tv, void *thread_data, const Flow *f, char name[PATH_MAX]; - char tx[64] = ""; - if (flags & OUTPUT_STREAMING_FLAG_TRANSACTION) + char tx[64] = { 0 }; + if (flags & OUTPUT_STREAMING_FLAG_TRANSACTION) { snprintf(tx, sizeof(tx), "%"PRIu64, tx_id); + } snprintf(name, sizeof(name), "%s/%s/%s_%u-%s_%u-%s-%s.data", td->log_dir, diff --git a/src/output-json-flow.c b/src/output-json-flow.c index b59cf4f63b46..0a385d81969e 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -246,7 +246,7 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) TcpSession *ssn = f->protoctx; - char hexflags[3] = ""; + char hexflags[3]; snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->tcp_packet_flags : 0); json_object_set_new(tjs, "tcp_flags", json_string(hexflags)); diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index a55bc8cf4eaf..4065a535a0dd 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -224,7 +224,7 @@ static void JsonNetFlowLogJSONToServer(JsonNetFlowLogThread *aft, json_t *js, Fl TcpSession *ssn = f->protoctx; - char hexflags[3] = ""; + char hexflags[3]; snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->client.tcp_flags : 0); json_object_set_new(tjs, "tcp_flags", json_string(hexflags)); @@ -273,7 +273,7 @@ static void JsonNetFlowLogJSONToClient(JsonNetFlowLogThread *aft, json_t *js, Fl TcpSession *ssn = f->protoctx; - char hexflags[3] = ""; + char hexflags[3]; snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->server.tcp_flags : 0); json_object_set_new(tjs, "tcp_flags", json_string(hexflags)); diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 46aa3100a64f..09edb610d8e6 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -360,7 +360,7 @@ TmEcode UnixSocketPcapFilesCheck(void *data) } } if (cfile->tenant_id > 0) { - char tstr[16] = ""; + char tstr[16]; snprintf(tstr, sizeof(tstr), "%d", cfile->tenant_id); if (ConfSet("pcap-file.tenant-id", tstr) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENTS, diff --git a/src/util-classification-config.c b/src/util-classification-config.c index e88d4f20c58f..babddae3f510 100644 --- a/src/util-classification-config.c +++ b/src/util-classification-config.c @@ -163,9 +163,9 @@ FILE *SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) static char *SCClassConfGetConfFilename(const DetectEngineCtx *de_ctx) { char *log_filename = NULL; - char config_value[256] = ""; if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + char config_value[256]; snprintf(config_value, sizeof(config_value), "%s.classification-file", de_ctx->config_prefix); diff --git a/src/util-debug.h b/src/util-debug.h index 9c9d2e23eed3..7e52506b5aa3 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -198,7 +198,6 @@ extern int sc_log_module_initialized; extern int sc_log_module_cleaned; - #define SCLog(x, ...) \ do { \ if (sc_log_global_log_level >= x && \ @@ -208,7 +207,7 @@ extern int sc_log_module_cleaned; (sc_log_fd_filters_present == 0 || \ SCLogMatchFDFilter(__FUNCTION__) == 1)) \ { \ - char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN] = ""; \ + char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN]; \ \ snprintf(_sc_log_msg, SC_LOG_MAX_LOG_MSG_LEN, __VA_ARGS__); \ \ @@ -228,7 +227,7 @@ extern int sc_log_module_cleaned; (sc_log_fd_filters_present == 0 || \ SCLogMatchFDFilter(__FUNCTION__) == 1)) \ { \ - char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN] = ""; \ + char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN]; \ \ snprintf(_sc_log_msg, SC_LOG_MAX_LOG_MSG_LEN, __VA_ARGS__); \ \ diff --git a/src/util-reference-config.c b/src/util-reference-config.c index 299897ab35a2..249293e9eb87 100644 --- a/src/util-reference-config.c +++ b/src/util-reference-config.c @@ -162,9 +162,9 @@ static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE * static char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx) { char *path = NULL; - char config_value[256] = ""; if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + char config_value[256]; snprintf(config_value, sizeof(config_value), "%s.reference-config-file", de_ctx->config_prefix); diff --git a/src/util-rule-vars.c b/src/util-rule-vars.c index 57347f4ff849..2edb23e9c8cd 100644 --- a/src/util-rule-vars.c +++ b/src/util-rule-vars.c @@ -69,7 +69,7 @@ char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx, SCEnter(); const char *conf_var_type_name = NULL; - char conf_var_full_name[2048] = ""; + char conf_var_full_name[2048]; char *conf_var_full_name_value = NULL; if (conf_var_name == NULL) diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index 6698b16fa6db..f2f5ad3afe71 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -106,9 +106,9 @@ static pcre_extra *regex_suppress_study = NULL; static char *SCThresholdConfGetConfFilename(const DetectEngineCtx *de_ctx) { char *log_filename = NULL; - char config_value[256] = ""; if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + char config_value[256]; snprintf(config_value, sizeof(config_value), "%s.threshold-file", de_ctx->config_prefix); From 01a8cc4ec9466ff4d35c75f17f5ef5d0f4193b7c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 15 Mar 2016 18:00:54 +0100 Subject: [PATCH 1081/2553] afpacket: strip prio from vlan id --- src/source-af-packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 9ae4643d9904..3267b6c17248 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -811,7 +811,7 @@ int AFPReadFromRing(AFPThreadVars *ptv) /* get vlan id from header */ if ((!ptv->vlan_disabled) && (h.h2->tp_status & TP_STATUS_VLAN_VALID || h.h2->tp_vlan_tci)) { - p->vlan_id[0] = h.h2->tp_vlan_tci; + p->vlan_id[0] = h.h2->tp_vlan_tci & 0x0fff; p->vlan_idx = 1; p->vlanh[0] = NULL; } From 4783d5107f1058f1473169824f80530596c5f089 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 15 Mar 2016 18:01:06 +0100 Subject: [PATCH 1082/2553] pfring: strip prio from vlan id --- src/source-pfring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index 7f005bce5566..315953a66b4b 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -251,7 +251,7 @@ static inline void PfringProcessPacket(void *user, struct pfring_pkthdr *h, Pack * is not defined nor used in PF_RING code. And vlan_id is set to 0 * in PF_RING kernel code when there is no VLAN. */ if ((!ptv->vlan_disabled) && h->extended_hdr.parsed_pkt.vlan_id) { - p->vlan_id[0] = h->extended_hdr.parsed_pkt.vlan_id; + p->vlan_id[0] = h->extended_hdr.parsed_pkt.vlan_id & 0x0fff; p->vlan_idx = 1; p->vlanh[0] = NULL; } From 32bf68aef83aa3df393877860c249dde2b9f37fc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 14 Dec 2015 18:34:38 +0100 Subject: [PATCH 1083/2553] smtp: consider file state in file_data inspection limits --- src/detect-engine-filedata-smtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 829832f9dc70..2af1fe0dd237 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -137,7 +137,7 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, if ((smtp_config.content_limit == 0 || curr_file->content_len_so_far < smtp_config.content_limit) && curr_file->content_len_so_far < smtp_config.content_inspect_min_size && - !(flags & STREAM_EOF)) { + !(flags & STREAM_EOF) && !(curr_file->state > FILE_STATE_OPENED)) { SCLogDebug("we still haven't seen the entire content. " "Let's defer content inspection till we see the " "entire content."); From 4526aed2b1029fe3f909ea4ca12045e4cf209e08 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 15 Dec 2015 10:13:48 +0100 Subject: [PATCH 1084/2553] smtp: fix config parsing and config defaults --- src/app-layer-smtp.c | 54 ++++++++++++++++++++++++-------------------- suricata.yaml.in | 6 ++--- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index c5544de93da5..fd317c7e78df 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -58,11 +58,11 @@ #include "util-misc.h" /* content-limit default value */ -#define FILEDATA_CONTENT_LIMIT 1000 +#define FILEDATA_CONTENT_LIMIT 100000 /* content-inspect-min-size default value */ -#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 1000 +#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768 /* content-inspect-window default value */ -#define FILEDATA_CONTENT_INSPECT_WINDOW 1000 +#define FILEDATA_CONTENT_INSPECT_WINDOW 4096 #define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510 @@ -282,34 +282,40 @@ static void SMTPConfigure(void) { /* Pass mime config data to MimeDec API */ MimeDecSetConfig(&smtp_config.mime_config); + smtp_config.content_limit = FILEDATA_CONTENT_LIMIT; + smtp_config.content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; + smtp_config.content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; + ConfNode *t = ConfGetNode("app-layer.protocols.smtp.inspected-tracker"); ConfNode *p = NULL; - if (t == NULL) - return; - - TAILQ_FOREACH(p, &t->head, next) { - if (strcasecmp("content-limit", p->name) == 0) { - if (ParseSizeStringU32(p->val, &content_limit) < 0) { - SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-limit " - "from conf file - %s. Killing engine", p->val); - content_limit = FILEDATA_CONTENT_LIMIT; + if (t != NULL) { + TAILQ_FOREACH(p, &t->head, next) { + if (strcasecmp("content-limit", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_limit) < 0) { + SCLogWarning(SC_ERR_SIZE_PARSE, + "parsing content-limit %s failed", p->val); + content_limit = FILEDATA_CONTENT_LIMIT; + } + smtp_config.content_limit = content_limit; } - } - if (strcasecmp("content-inspect-min-size", p->name) == 0) { - if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) { - SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-inspect-min-size-limit " - "from conf file - %s. Killing engine", p->val); - content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; + if (strcasecmp("content-inspect-min-size", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) { + SCLogWarning(SC_ERR_SIZE_PARSE, + "parsing content-inspect-min-size %s failed", p->val); + content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; + } + smtp_config.content_inspect_min_size = content_inspect_min_size; } - } - if (strcasecmp("content-inspect-window", p->name) == 0) { - if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) { - SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-inspect-window " - "from conf file - %s. Killing engine", p->val); - content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; + if (strcasecmp("content-inspect-window", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) { + SCLogWarning(SC_ERR_SIZE_PARSE, + "parsing content-inspect-window %s failed", p->val); + content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; + } + smtp_config.content_inspect_window = content_inspect_window; } } } diff --git a/suricata.yaml.in b/suricata.yaml.in index 1f8a359cb99b..53ea4d472fcd 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1332,9 +1332,9 @@ app-layer: body-md5: no # Configure inspected-tracker for file_data keyword inspected-tracker: - content-limit: 1000 - content-inspect-min-size: 1000 - content-inspect-window: 1000 + content-limit: 100000 + content-inspect-min-size: 32768 + content-inspect-window: 4096 imap: enabled: detection-only msn: From c19412243a7f1c9cf3d07de0999c026bba313c69 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 10 Mar 2016 09:56:15 +0100 Subject: [PATCH 1085/2553] file logging: fix bad end of file check File storage could end file storing when the logger was invoked while no new data chunks were available. --- src/output-filedata.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/output-filedata.c b/src/output-filedata.c index 9818339dfc37..1e19cc9f7ef7 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -191,7 +191,7 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P * case we already logged the current ffd, which * is the last in our list. */ if (ffd->stored == 1) { - if (!(file_close == 1 || ffd->next == NULL)) { + if (!(file_close == 1 && ffd->next == NULL)) { continue; } @@ -199,6 +199,7 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P // so really a 'close' msg write_ffd = NULL; flags |= OUTPUT_FILEDATA_FLAG_CLOSE; + SCLogDebug("OUTPUT_FILEDATA_FLAG_CLOSE set"); } /* store */ @@ -216,13 +217,17 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P * loggers */ if ((file_close || file_trunc) && ff->state < FILE_STATE_CLOSED) { ff->state = FILE_STATE_TRUNCATED; + SCLogDebug("ff->state = FILE_STATE_TRUNCATED set"); } /* for the last data chunk we have, also tell the logger * we're closing up */ - if (ffd->next == NULL && ff->state >= FILE_STATE_CLOSED) + if (ffd->next == NULL && ff->state >= FILE_STATE_CLOSED) { flags |= OUTPUT_FILEDATA_FLAG_CLOSE; + SCLogDebug("OUTPUT_FILEDATA_FLAG_CLOSE set"); + } + SCLogDebug("ff %p ffd %p flags %02x", ff, write_ffd, flags); /* do the actual logging */ file_logged = CallLoggers(tv, store, p, ff, write_ffd, flags); From 5aee386fa99c643602d311a986a9c09ca98cb0ed Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 9 Mar 2016 17:24:51 +0100 Subject: [PATCH 1086/2553] smtp: add file_data debug code --- src/detect-engine-filedata-smtp.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 2af1fe0dd237..5b8f8dca4c8f 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -88,6 +88,7 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, uint32_t *buffer_len, uint32_t *stream_start_offset) { + SCEnter(); int index = 0; uint8_t *buffer = NULL; *buffer_len = 0; @@ -108,7 +109,9 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, if (det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len != 0) { *buffer_len = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len; *stream_start_offset = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].offset; - return det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer; + buffer = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer; + + SCReturnPtr(buffer, "uint8_t"); } } else { if (SMTPCreateSpace(det_ctx, (tx_id - det_ctx->smtp_start_tx_id) + 1) < 0) @@ -122,6 +125,11 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, index = (tx_id - det_ctx->smtp_start_tx_id); } + SCLogDebug("smtp_config.content_limit %u, smtp_config.content_inspect_min_size %u", + smtp_config.content_limit, smtp_config.content_inspect_min_size); + + SCLogDebug("file %p size %"PRIu64", state %d", curr_file, curr_file->content_len_so_far, curr_file->state); + /* no new data */ if (curr_file->content_inspected == curr_file->content_len_so_far) { SCLogDebug("no new data"); @@ -188,12 +196,15 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, /* updat inspected tracker */ curr_file->content_inspected = curr_file->chunks_tail->stream_offset + curr_file->chunks_tail->len; + SCLogDebug("curr_file->content_inspected now %"PRIu64, curr_file->content_inspected); buffer = det_ctx->smtp[index].buffer; *buffer_len = det_ctx->smtp[index].buffer_len; *stream_start_offset = det_ctx->smtp[index].offset; + end: - return buffer; + SCLogDebug("buffer %p, len %u", buffer, *buffer_len); + SCReturnPtr(buffer, "uint8_t"); } int DetectEngineInspectSMTPFiledata(ThreadVars *tv, From 77358a4113e4fab82464a257e95484f8dcb25d21 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 9 Mar 2016 20:43:54 +0100 Subject: [PATCH 1087/2553] file: optionally use detect tracking in pruning When the file API is used to do content inspection (currently only smtp does this), the detection should be considered while pruning the file chunks. This patch introduces a new flag for the file API: FILE_USE_DETECT When it is used, 'FilePrune' will not remove chunks that are (partly) beyond the File::content_inspected tracker. When using this flag, it's important to realize that when the detect engine is disabled or rules are not matching, content_inspected might not get updated. --- src/util-file.c | 12 ++++++++++++ src/util-file.h | 4 +++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/util-file.c b/src/util-file.c index 7e3ba16113c1..2b45f3360769 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -173,6 +173,14 @@ static int FilePruneFile(File *file) SCLogDebug("fd %p", fd); if (file->flags & FILE_NOSTORE || fd->stored == 1) { + /* keep chunks in memory as long as we still need to + * inspect them or parts of them */ + if (file->flags & FILE_USE_DETECT) { + uint64_t right_edge = fd->stream_offset + fd->len; + if (file->content_inspected < right_edge) + break; + } + file->chunks_head = fd->next; if (file->chunks_tail == fd) file->chunks_tail = fd->next; @@ -563,6 +571,10 @@ File *FileOpenFile(FileContainer *ffc, const uint8_t *name, uint16_t name_len, SCLogDebug("not doing md5 for this file"); ff->flags |= FILE_NOMD5; } + if (flags & FILE_USE_DETECT) { + SCLogDebug("considering content_inspect tracker when pruning"); + ff->flags |= FILE_USE_DETECT; + } #ifdef HAVE_NSS if (!(ff->flags & FILE_NOMD5) || g_file_force_md5) { diff --git a/src/util-file.h b/src/util-file.h index 4b590c2c389f..9d87b593df09 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -38,6 +38,7 @@ #define FILE_STORE 0x0040 #define FILE_STORED 0x0080 #define FILE_NOTRACK 0x0100 /**< track size of file */ +#define FILE_USE_DETECT 0x0200 /**< use content_inspected tracker */ typedef enum FileState_ { FILE_STATE_NONE = 0, /**< no state */ @@ -80,7 +81,8 @@ typedef struct File_ { uint64_t chunks_cnt_max; #endif uint64_t content_len_so_far; - uint64_t content_inspected; + uint64_t content_inspected; /**< used in pruning if FILE_USE_DETECT + * flag is set */ } File; typedef struct FileContainer_ { From 9afaf14ba4137f535aa6414982fdf488f0f3cce8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 9 Mar 2016 20:44:26 +0100 Subject: [PATCH 1088/2553] smtp: use detection file tracking As SMTP file_data detection uses the file API, the file's inspect tracker should be considered when pruning files. This patch sets the FILE_USE_DETECT flag on files tracked by smtp. It also adds logic to move inspected tracker ahead if detection doesn't do it, like when no rules are matching or detection engine is disabled. --- src/app-layer-smtp.c | 44 ++++++++++++++++++++++++++++--- src/detect-engine-filedata-smtp.c | 2 +- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index fd317c7e78df..1dd6cab1c2ca 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -347,9 +347,46 @@ static SMTPTransaction *SMTPTransactionCreate(void) return tx; } -int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state) { +/** \internal + * \brief update inspected tracker if it gets to far behind + * + * As smtp uses the FILE_USE_DETECT flag in the file API, we are responsible + * for making sure that File::content_inspected is not getting too far + * behind. + */ +static void SMTPPruneFiles(FileContainer *files) +{ + SCLogDebug("cfg: win %"PRIu32" min_size %"PRIu32, + smtp_config.content_inspect_window, smtp_config.content_inspect_min_size); + + File *file = files->head; + while (file) { + if (file->chunks_head) { + uint32_t window = smtp_config.content_inspect_window; + if (file->chunks_head->stream_offset == 0) + window = MAX(window, smtp_config.content_inspect_min_size); + + uint64_t file_size = file->content_len_so_far; + uint64_t data_size = file_size - file->chunks_head->stream_offset; + + SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64, + window, file_size, data_size); + + if (data_size > (window * 3)) { + uint64_t left_edge = file_size - window; + SCLogDebug("file->content_inspected now %"PRIu64, left_edge); + file->content_inspected = left_edge; + } + } + + file = file->next; + } +} +int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state) +{ + SCEnter(); int ret = MIME_DEC_OK; Flow *flow = (Flow *) state->data; SMTPState *smtp_state = (SMTPState *) flow->alstate; @@ -410,7 +447,7 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, } if (FileOpenFile(files, (uint8_t *) entity->filename, entity->filename_len, - (uint8_t *) chunk, len, flags) == NULL) { + (uint8_t *) chunk, len, flags|FILE_USE_DETECT) == NULL) { ret = MIME_DEC_ERR_DATA; SCLogDebug("FileOpenFile() failed"); } @@ -466,6 +503,7 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, } if (files != NULL) { + SMTPPruneFiles(files); FilePrune(files); } diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 5b8f8dca4c8f..f037dfec7a1a 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -357,7 +357,7 @@ static int DetectEngineSMTPFiledataTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST|PKT_STREAM_EOF; f.alproto = ALPROTO_SMTP; StreamTcpInitConfig(TRUE); From 3c3fe4b47d1f9bc23113d8b8c2ea98c5096e4e8f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 26 Jan 2016 23:22:27 -0600 Subject: [PATCH 1089/2553] detect: denote the max detection list; fix issue 1674. Denotes the max detection list so that rule validation can allow post-detection lists to come after base64_data, but disallow detection lists to come after it. --- src/detect-base64-data.c | 38 ++++++++++++++++++++++++++++++++++++++ src/detect-parse.c | 2 +- src/detect.h | 9 +++++++-- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c index b056b97a1e4c..b5fcefc53ce5 100644 --- a/src/detect-base64-data.c +++ b/src/detect-base64-data.c @@ -186,6 +186,10 @@ static int DetectBase64DataSetupTest02(void) return retval; } +/** + * \test Test that the rule fails to load if the detection list is + * changed after base64_data. + */ static int DetectBase64DataSetupTest03(void) { DetectEngineCtx *de_ctx = NULL; @@ -221,6 +225,38 @@ static int DetectBase64DataSetupTest03(void) return retval; } +/** + * \test Test that the list can be changed to post-detection lists + * after the base64 keyword. + */ +static int DetectBase64DataSetupTest04(void) +{ + DetectEngineCtx *de_ctx = NULL; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"some b64thing\"; flow:established,from_server; file_data; content:\"sometext\"; fast_pattern; base64_decode:relative; base64_data; content:\"foobar\"; nocase; tag:session,120,seconds; sid:1111111; rev:1;)"); + if (de_ctx->sig_list == NULL) { + printf("SigInit failed: "); + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + #endif static void DetectBase64DataRegisterTests(void) @@ -232,5 +268,7 @@ static void DetectBase64DataRegisterTests(void) 1); UtRegisterTest("DetectBase64DataSetupTest03", DetectBase64DataSetupTest03, 1); + UtRegisterTest("DetectBase64DataSetupTest04", DetectBase64DataSetupTest04, + 1); #endif /* UNITTESTS */ } diff --git a/src/detect-parse.c b/src/detect-parse.c index f91e759171b6..f451c5c87ecb 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1322,7 +1322,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (s->sm_lists[DETECT_SM_LIST_BASE64_DATA] != NULL) { int list; uint16_t idx = s->sm_lists[DETECT_SM_LIST_BASE64_DATA]->idx; - for (list = 0; list < DETECT_SM_LIST_MAX; list++) { + for (list = 0; list < DETECT_SM_LIST_DETECT_MAX; list++) { if (list != DETECT_SM_LIST_BASE64_DATA && s->sm_lists[list] != NULL) { if (s->sm_lists[list]->idx > idx) { diff --git a/src/detect.h b/src/detect.h index c36b9ce1e955..3ca3108fd296 100644 --- a/src/detect.h +++ b/src/detect.h @@ -116,7 +116,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_AMATCH, DETECT_SM_LIST_DMATCH, - DETECT_SM_LIST_TMATCH, DETECT_SM_LIST_FILEMATCH, @@ -130,8 +129,14 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + /* Demarcation between detection and post-detection lists. All + * detection lists must come before this. */ + DETECT_SM_LIST_DETECT_MAX, + /* list for post match actions: flowbit set, flowint increment, etc */ - DETECT_SM_LIST_POSTMATCH, + DETECT_SM_LIST_POSTMATCH = DETECT_SM_LIST_DETECT_MAX, + + DETECT_SM_LIST_TMATCH, /**< post-detection tagging */ /* lists for alert thresholding and suppression */ DETECT_SM_LIST_SUPPRESS, From a70ff19911b2be650c1b115eae7681480851f2e9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 16 Mar 2016 12:20:17 +0100 Subject: [PATCH 1090/2553] stats: fix unix socket crash Reset counters_global_id at ctx destruction. In the unix socket runmode the lack of this reset would cause the id's to increase with each pcap, leading to an ever larger stats array. --- src/counters.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/counters.c b/src/counters.c index 18f1093b3939..325442f2d6e9 100644 --- a/src/counters.c +++ b/src/counters.c @@ -288,6 +288,7 @@ static void StatsReleaseCtx() if (stats_ctx->counters_id_hash != NULL) { HashTableFree(stats_ctx->counters_id_hash); stats_ctx->counters_id_hash = NULL; + counters_global_id = 0; } StatsPublicThreadContextCleanup(&stats_ctx->global_counter_ctx); From ef4c71705281f38f7972b3a980bfb03d1d04d662 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 16 Mar 2016 12:37:25 +0100 Subject: [PATCH 1091/2553] ip parsing: fix cppcheck negative shift warning [src/util-ip.c:104]: (error) Shifting a negative value is undefined behaviour [src/util-radix-tree.c:1160]: (error) Shifting a negative value is undefined behaviour [src/util-radix-tree.c:1357]: (error) Shifting a negative value is undefined behaviour [src/util-radix-tree.c:1380]: (error) Shifting a negative value is undefined behaviour [src/util-radix-tree.c:1438]: (error) Shifting a negative value is undefined behaviour --- src/util-ip.c | 6 +++--- src/util-radix-tree.c | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/util-ip.c b/src/util-ip.c index 1f22d8640d20..91c3baab99eb 100644 --- a/src/util-ip.c +++ b/src/util-ip.c @@ -93,15 +93,15 @@ struct in6_addr *ValidateIPV6Address(const char *addr_str) */ void MaskIPNetblock(uint8_t *stream, uint8_t netmask, uint16_t key_bitlen) { - int mask = 0; + uint32_t mask = 0; int i = 0; int bytes = key_bitlen / 8; for (i = 0; i < bytes; i++) { - mask = -1; + mask = UINT_MAX; if ( ((i + 1) * 8) > netmask) { if ( ((i + 1) * 8 - netmask) < 8) - mask = -1 << ((i + 1) * 8 - netmask); + mask = UINT_MAX << ((i + 1) * 8 - netmask); else mask = 0; } diff --git a/src/util-radix-tree.c b/src/util-radix-tree.c index 2304d593f42d..928761d95153 100644 --- a/src/util-radix-tree.c +++ b/src/util-radix-tree.c @@ -1127,7 +1127,7 @@ static void SCRadixRemoveKey(uint8_t *key_stream, uint16_t key_bitlen, SCRadixPrefix *prefix = NULL; - int mask = 0; + uint32_t mask = 0; int i = 0; if (node == NULL) @@ -1157,7 +1157,7 @@ static void SCRadixRemoveKey(uint8_t *key_stream, uint16_t key_bitlen, i = prefix->bitlen / 8; if (SCMemcmp(node->prefix->stream, prefix->stream, i) == 0) { - mask = -1 << (8 - prefix->bitlen % 8); + mask = UINT_MAX << (8 - prefix->bitlen % 8); if (prefix->bitlen % 8 == 0 || (node->prefix->stream[i] & mask) == (prefix->stream[i] & mask)) { @@ -1334,7 +1334,7 @@ static inline SCRadixNode *SCRadixFindKeyIPNetblock(uint8_t *key_stream, uint8_t SCRadixNode *node, void **user_data_result) { SCRadixNode *netmask_node = NULL; - int mask = 0; + uint32_t mask = 0; int bytes = 0; int i = 0; int j = 0; @@ -1351,10 +1351,10 @@ static inline SCRadixNode *SCRadixFindKeyIPNetblock(uint8_t *key_stream, uint8_t for (j = 0; j < netmask_node->netmask_cnt; j++) { bytes = key_bitlen / 8; for (i = 0; i < bytes; i++) { - mask = -1; + mask = UINT_MAX; if ( ((i + 1) * 8) > netmask_node->netmasks[j]) { if ( ((i + 1) * 8 - netmask_node->netmasks[j]) < 8) - mask = -1 << ((i + 1) * 8 - netmask_node->netmasks[j]); + mask = UINT_MAX << ((i + 1) * 8 - netmask_node->netmasks[j]); else mask = 0; } @@ -1377,7 +1377,7 @@ static inline SCRadixNode *SCRadixFindKeyIPNetblock(uint8_t *key_stream, uint8_t return NULL; if (SCMemcmp(node->prefix->stream, key_stream, bytes) == 0) { - mask = -1 << (8 - key_bitlen % 8); + mask = UINT_MAX << (8 - key_bitlen % 8); if (key_bitlen % 8 == 0 || (node->prefix->stream[bytes] & mask) == (key_stream[bytes] & mask)) { @@ -1406,7 +1406,7 @@ static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint16_t key_bitlen, return NULL; SCRadixNode *node = tree->head; - int mask = 0; + uint32_t mask = 0; int bytes = 0; uint8_t tmp_stream[255]; @@ -1435,7 +1435,7 @@ static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint16_t key_bitlen, bytes = key_bitlen / 8; if (SCMemcmp(node->prefix->stream, tmp_stream, bytes) == 0) { - mask = -1 << (8 - key_bitlen % 8); + mask = UINT_MAX << (8 - key_bitlen % 8); if (key_bitlen % 8 == 0 || (node->prefix->stream[bytes] & mask) == (tmp_stream[bytes] & mask)) { From eb39487f48fd2daa16a8e131351aaebd42768eef Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 17 Mar 2016 11:56:52 +0100 Subject: [PATCH 1092/2553] app-layer-ssl: fix out of bounds memory read Added several checks to avoid out of bounds memory read caused by malformed traffic. --- src/app-layer-ssl.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 8bb2e6b1d3ba..9c571e06021e 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -745,6 +745,20 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, return (input - initial_input); } + /* record_length should never be 0 */ + if (ssl_state->curr_connp->record_length == 0) { + SCLogDebug("SSLv2 record length is 0"); + AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + return -1; + } + + /* record_lenghts_length should never be 0 */ + if (ssl_state->curr_connp->record_lengths_length == 0) { + SCLogDebug("SSLv2 record lengths length is 0"); + AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + return -1; + } + switch (ssl_state->curr_connp->content_type) { case SSLV2_MT_ERROR: SCLogDebug("SSLV2_MT_ERROR msg_type received. " @@ -972,6 +986,13 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, return -1; } + /* record_length should never be 0 */ + if (ssl_state->curr_connp->record_length == 0) { + SCLogDebug("SSLv3 Record length is 0"); + AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_TLS_HEADER); + return -1; + } + switch (ssl_state->curr_connp->content_type) { /* we don't need any data from these types */ @@ -1182,7 +1203,7 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt "previously left off"); retval = SSLv2Decode(direction, ssl_state, pstate, input, input_len); - if (retval == -1) { + if (retval < 0) { SCLogDebug("Error parsing SSLv2.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); From f891aadefc910354362144870d3f10387274e967 Mon Sep 17 00:00:00 2001 From: gureedo Date: Mon, 21 Mar 2016 14:38:53 +0500 Subject: [PATCH 1093/2553] netmap: remove workers zero copy mode restriction between interfaces Rationale: https://github.com/luigirizzo/netmap/issues/126 --- src/source-netmap.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index 061635b64768..f5b82e276e8b 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -632,14 +632,9 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da char const *active_runmode = RunmodeGetActive(); if ((aconf->copy_mode != NETMAP_COPY_MODE_NONE) && active_runmode && !strcmp("workers", active_runmode)) { - if (likely(ntv->ifsrc->mem == ntv->ifdst->mem)) { - ntv->flags |= NETMAP_FLAG_ZERO_COPY; - SCLogInfo("Enabling zero copy mode for %s->%s", - aconf->iface_name, aconf->out_iface_name); - } else { - SCLogInfo("Unable to set zero copy mode for %s->%s", - aconf->iface_name, aconf->out_iface_name); - } + ntv->flags |= NETMAP_FLAG_ZERO_COPY; + SCLogInfo("Enabling zero copy mode for %s->%s", + aconf->iface_name, aconf->out_iface_name); } if (aconf->bpf_filter) { From 02d4e729c4aba5b215fbaa64f709c2a101a1ba09 Mon Sep 17 00:00:00 2001 From: gureedo Date: Mon, 21 Mar 2016 14:41:42 +0500 Subject: [PATCH 1094/2553] netmap: fix log typo --- src/source-netmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index f5b82e276e8b..540f2faee308 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -654,7 +654,7 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da if (GetIfaceOffloading(aconf->iface) == 1) { SCLogWarning(SC_ERR_NETMAP_CREATE, - "Using mmap mode with GRO or LRO activated can lead to capture problems"); + "Using netmap mode with GRO or LRO activated can lead to capture problems"); } *data = (void *)ntv; From e4443fac53969f810a1713a0cd7dc73e71eaaf23 Mon Sep 17 00:00:00 2001 From: gureedo Date: Mon, 21 Mar 2016 15:14:34 +0500 Subject: [PATCH 1095/2553] netmap: fix issue 1717 Use packet pool only without packet allocation. Wait for N packets available in packet pool before netmap ring fetching. --- src/source-netmap.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index 540f2faee308..f55ac86bc885 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -80,7 +80,7 @@ #endif /* HAVE_NETMAP */ -extern int max_pending_packets; +extern intmax_t max_pending_packets; #ifndef HAVE_NETMAP @@ -635,6 +635,15 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da ntv->flags |= NETMAP_FLAG_ZERO_COPY; SCLogInfo("Enabling zero copy mode for %s->%s", aconf->iface_name, aconf->out_iface_name); + } else { + uint16_t ring_size = ntv->ifsrc->rings[0].rx->num_slots; + if (ring_size > max_pending_packets) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Packet pool size (%" PRIuMAX ") must be greater or equal than %s ring size (%" PRIu16 "). " + "Increase max_pending_packets option.", + max_pending_packets, aconf->iface_name, ring_size); + goto error_dst; + } } if (aconf->bpf_filter) { @@ -762,6 +771,10 @@ static int NetmapRingRead(NetmapThreadVars *ntv, int ring_id) uint32_t avail = nm_ring_space(rx); uint32_t cur = rx->cur; + if (!(ntv->flags & NETMAP_FLAG_ZERO_COPY)) { + PacketPoolWaitForN(avail); + } + while (likely(avail-- > 0)) { struct netmap_slot *slot = &rx->slot[cur]; unsigned char *slot_data = (unsigned char *)NETMAP_BUF(rx, slot->buf_idx); @@ -775,7 +788,7 @@ static int NetmapRingRead(NetmapThreadVars *ntv, int ring_id) } } - Packet *p = PacketGetFromQueueOrAlloc(); + Packet *p = PacketPoolGetPacket(); if (unlikely(p == NULL)) { SCReturnInt(NETMAP_FAILURE); } From b5972eeea282bf033fead106a6c69db459487348 Mon Sep 17 00:00:00 2001 From: JonZeolla Date: Wed, 16 Mar 2016 09:28:02 -0400 Subject: [PATCH 1096/2553] Fix typos in an error message Fix two minor typos in a SC_ERR_INVALID_ARGUMENT error message. --- src/util-affinity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-affinity.c b/src/util-affinity.c index 82456c20cd11..53ded80a0620 100644 --- a/src/util-affinity.c +++ b/src/util-affinity.c @@ -311,7 +311,7 @@ int AffinityGetNextCPU(ThreadsAffinityType *taf) } } if (iter == 2) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "cpu_set does not contains available cpus, cpu afinity conf is invalid"); + SCLogError(SC_ERR_INVALID_ARGUMENT, "cpu_set does not contain available cpus, cpu affinity conf is invalid"); } taf->lcpu = ncpu + 1; if (taf->lcpu >= UtilCpuGetNumProcessorsOnline()) From 92ad63abb78fc51b88d2c511f6c85a975509b8f9 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 18 Mar 2016 09:23:31 +0100 Subject: [PATCH 1097/2553] output-json-email: fix error code Returning early if first function call fail could avoid some issue. --- src/output-json-email-common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index f91f7f307388..b2750490d098 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -371,6 +371,10 @@ TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, F OutputJsonEmailCtx *email_ctx = aft->emaillog_ctx; SMTPTransaction *tx = (SMTPTransaction *) vtx; + if (sjs == NULL) { + SCReturnInt(TM_ECODE_FAILED); + } + if ((email_ctx->flags & LOG_EMAIL_EXTENDED) || (email_ctx->fields != 0)) JsonEmailLogJSONCustom(email_ctx, sjs, tx); From 9dec6d933fb36a939288873e68dd09d2d72e19d7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 18 Mar 2016 09:28:58 +0100 Subject: [PATCH 1098/2553] output-json-email: fix memleak in error path In JsonEmailLogJsonData function, an invalid state was leading to early exit without a proper freeing of resources. This should fix: Indirect leak of 72 byte(s) in 1 object(s) allocated from: #0 0x4c264b in malloc (/home/victor/qa/buildbot/donkey/z600fuzz/Private/src/.libs/lt-suricata+0x4c264b) #1 0x7fb09c1e886a in json_object (/usr/lib/x86_64-linux-gnu/libjansson.so.4+0x686a) #2 0xd6a272 in JsonEmailLogJson /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/output-json-email-common.c:370:19 #3 0xd956b9 in JsonSmtpLogger /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/output-json-smtp.c:103:9 #4 0xdcedac in OutputTxLog /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/output-tx.c:165:17 #5 0xff6669 in TmThreadsSlotVarRun /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/tm-threads.c:132:17 #6 0xffecc1 in TmThreadsSlotVar /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/tm-threads.c:474:17 #7 0x7fb09bfcc181 in start_thread /build/eglibc-3GlaMS/eglibc-2.19/nptl/pthread_create.c:312 --- src/output-json-email-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index b2750490d098..7ab9e727b02b 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -263,6 +263,7 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ } if ((mime_state != NULL)) { if (entity == NULL) { + json_decref(sjs); SCReturnPtr(NULL, "json_t"); } From a05cdbdf2810ded5116622ffb8dc49fa53780a42 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 18 Mar 2016 09:53:21 +0100 Subject: [PATCH 1099/2553] output-json-email: fix memleak This possibly fix: ndirect leak of 64 byte(s) in 1 object(s) allocated from: #0 0x4c264b in malloc (/home/victor/qa/buildbot/donkey/z600fuzz/Private/src/.libs/lt-suricata+0x4c264b) #1 0x7fb09c1e8aaa in json_array (/usr/lib/x86_64-linux-gnu/libjansson.so.4+0x6aaa) #2 0xd67553 in JsonEmailLogJsonData /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/output-json-email-common.c:290:27 #3 0xd6a272 in JsonEmailLogJson /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/output-json-email-common.c:370:19 #4 0xd956b9 in JsonSmtpLogger /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/output-json-smtp.c:103:9 #5 0xdcedac in OutputTxLog /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/output-tx.c:165:17 #6 0xff6669 in TmThreadsSlotVarRun /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/tm-threads.c:132:17 #7 0xffecc1 in TmThreadsSlotVar /home/victor/qa/buildbot/donkey/z600fuzz/Private/src/tm-threads.c:474:17 #8 0x7fb09bfcc181 in start_thread /build/eglibc-3GlaMS/eglibc-2.19/nptl/pthread_create.c:312 --- src/output-json-email-common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 7ab9e727b02b..2c10a7c1acc5 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -119,6 +119,9 @@ static json_t* JsonEmailJsonArrayFromCommaList(const uint8_t *val, size_t len) sp = SkipWhiteSpaceTill(p, savep); json_array_append_new(ajs, json_string(sp)); } + } else { + json_decref(ajs); + return NULL; } SCFree(to_line); } From 1b1cde68379a3e777ddd8632d748f302b479e6a7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 21 Mar 2016 15:27:55 +0100 Subject: [PATCH 1100/2553] output-json-email: fix memleak This patch fixes some error handling in code generating JSON output for email event. This fixes: Indirect leak of 128 byte(s) in 1 object(s) allocated from: #0 0x50c142 in malloc (/home/eric/git/oisf/src/.libs/lt-suricata+0x50c142) #1 0x7ff92394771c (/usr/lib/x86_64-linux-gnu/libjansson.so.4+0x371c) #2 0x1bd3309 in JsonEmailLogJson /home/eric/git/oisf/src/output-json-email-common.c:376:19 #3 0x1bfe774 in JsonSmtpLogger /home/eric/git/oisf/src/output-json-smtp.c:103:9 #4 0x1c378ff in OutputTxLog /home/eric/git/oisf/src/output-tx.c:165:17 #5 0x1f94ef3 in TmThreadsSlotVarRun /home/eric/git/oisf/src/tm-threads.c:134:17 #6 0x1d33478 in TmThreadsSlotProcessPkt /home/eric/git/oisf/src/./tm-threads.h:150:9 #7 0x1d32dd4 in PcapFileCallbackLoop /home/eric/git/oisf/src/source-pcap-file.c:184:9 #8 0x7ff924199013 (/usr/lib/x86_64-linux-gnu/libpcap.so.0.8+0x1f013) Indirect leak of 96 byte(s) in 3 object(s) allocated from: #0 0x50c142 in malloc (/home/eric/git/oisf/src/.libs/lt-suricata+0x50c142) #1 0x7ff92394bc7b (/usr/lib/x86_64-linux-gnu/libjansson.so.4+0x7c7b) Indirect leak of 82 byte(s) in 3 object(s) allocated from: #0 0x50c142 in malloc (/home/eric/git/oisf/src/.libs/lt-suricata+0x50c142) #1 0x7ff923949924 (/usr/lib/x86_64-linux-gnu/libjansson.so.4+0x5924) Indirect leak of 72 byte(s) in 1 object(s) allocated from: #0 0x50c142 in malloc (/home/eric/git/oisf/src/.libs/lt-suricata+0x50c142) #1 0x7ff92394bcda in json_object (/usr/lib/x86_64-linux-gnu/libjansson.so.4+0x7cda) #2 0x1bd3309 in JsonEmailLogJson /home/eric/git/oisf/src/output-json-email-common.c:376:19 #3 0x1bfe774 in JsonSmtpLogger /home/eric/git/oisf/src/output-json-smtp.c:103:9 #4 0x1c378ff in OutputTxLog /home/eric/git/oisf/src/output-tx.c:165:17 #5 0x1f94ef3 in TmThreadsSlotVarRun /home/eric/git/oisf/src/tm-threads.c:134:17 #6 0x1d33478 in TmThreadsSlotProcessPkt /home/eric/git/oisf/src/./tm-threads.h:150:9 #7 0x1d32dd4 in PcapFileCallbackLoop /home/eric/git/oisf/src/source-pcap-file.c:184:9 #8 0x7ff924199013 (/usr/lib/x86_64-linux-gnu/libpcap.so.0.8+0x1f013) Indirect leak of 64 byte(s) in 1 object(s) allocated from: #0 0x50c142 in malloc (/home/eric/git/oisf/src/.libs/lt-suricata+0x50c142) #1 0x7ff92394bf5a in json_array (/usr/lib/x86_64-linux-gnu/libjansson.so.4+0x7f5a) #2 0x1bd04b5 in JsonEmailLogJsonData /home/eric/git/oisf/src/output-json-email-common.c:296:27 #3 0x1bd3309 in JsonEmailLogJson /home/eric/git/oisf/src/output-json-email-common.c:376:19 #4 0x1bfe774 in JsonSmtpLogger /home/eric/git/oisf/src/output-json-smtp.c:103:9 #5 0x1c378ff in OutputTxLog /home/eric/git/oisf/src/output-tx.c:165:17 #6 0x1f94ef3 in TmThreadsSlotVarRun /home/eric/git/oisf/src/tm-threads.c:134:17 #7 0x1d33478 in TmThreadsSlotProcessPkt /home/eric/git/oisf/src/./tm-threads.h:150:9 #8 0x1d32dd4 in PcapFileCallbackLoop /home/eric/git/oisf/src/source-pcap-file.c:184:9 #9 0x7ff924199013 (/usr/lib/x86_64-linux-gnu/libpcap.so.0.8+0x1f013) Indirect leak of 48 byte(s) in 1 object(s) allocated from: #0 0x50c142 in malloc (/home/eric/git/oisf/src/.libs/lt-suricata+0x50c142) #1 0x7ff92394bf2a in json_array (/usr/lib/x86_64-linux-gnu/libjansson.so.4+0x7f2a) #2 0x1bd04b5 in JsonEmailLogJsonData /home/eric/git/oisf/src/output-json-email-common.c:296:27 #3 0x1bd3309 in JsonEmailLogJson /home/eric/git/oisf/src/output-json-email-common.c:376:19 #4 0x1bfe774 in JsonSmtpLogger /home/eric/git/oisf/src/output-json-smtp.c:103:9 #5 0x1c378ff in OutputTxLog /home/eric/git/oisf/src/output-tx.c:165:17 #6 0x1f94ef3 in TmThreadsSlotVarRun /home/eric/git/oisf/src/tm-threads.c:134:17 #7 0x1d33478 in TmThreadsSlotProcessPkt /home/eric/git/oisf/src/./tm-threads.h:150:9 #8 0x1d32dd4 in PcapFileCallbackLoop /home/eric/git/oisf/src/source-pcap-file.c:184:9 #9 0x7ff924199013 (/usr/lib/x86_64-linux-gnu/libpcap.so.0.8+0x1f013) --- src/output-json-email-common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c index 2c10a7c1acc5..a802b4a1218b 100644 --- a/src/output-json-email-common.c +++ b/src/output-json-email-common.c @@ -253,6 +253,7 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ smtp_state = (SMTPState *)state; if (smtp_state == NULL) { SCLogDebug("no smtp state, so no request logging"); + json_decref(sjs); SCReturnPtr(NULL, "json_t"); } SMTPTransaction *tx = vtx; @@ -262,6 +263,7 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ break; default: /* don't know how we got here */ + json_decref(sjs); SCReturnPtr(NULL, "json_t"); } if ((mime_state != NULL)) { @@ -306,8 +308,10 @@ json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_ } } - if (mime_state->stack == NULL || mime_state->stack->top == NULL || mime_state->stack->top->data == NULL) + if (mime_state->stack == NULL || mime_state->stack->top == NULL || mime_state->stack->top->data == NULL) { + json_decref(sjs); SCReturnPtr(NULL, "json_t"); + } entity = (MimeDecEntity *)mime_state->stack->top->data; int attch_cnt = 0; From 8edbc20a07e2fe5692889db1f7fbcd7cc87127b9 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 10 Mar 2016 14:32:06 -0600 Subject: [PATCH 1101/2553] flow: record the flow hash for use as the output flow id Provides a consistent hash for a flow, as well as a better distribution than using a memory address. --- src/flow-hash.c | 36 +++++++++++++++++------------------- src/flow.h | 13 ++++++++----- src/output-json.c | 7 +------ 3 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index 9ddb3713c47c..c17e6e4f0973 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -218,9 +218,9 @@ typedef struct FlowHashKey6_ { * * For ICMP we only consider UNREACHABLE errors atm. */ -static inline uint32_t FlowGetKey(const Packet *p) +static inline uint32_t FlowGetHash(const Packet *p) { - uint32_t key; + uint32_t hash = 0; if (p->ip4h != NULL) { if (p->tcph != NULL || p->udph != NULL) { @@ -244,8 +244,7 @@ static inline uint32_t FlowGetKey(const Packet *p) fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; - uint32_t hash = hashword(fhk.u32, 5, flow_config.hash_rand); - key = hash % flow_config.hash_size; + hash = hashword(fhk.u32, 5, flow_config.hash_rand); } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)); @@ -270,8 +269,7 @@ static inline uint32_t FlowGetKey(const Packet *p) fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; - uint32_t hash = hashword(fhk.u32, 5, flow_config.hash_rand); - key = hash % flow_config.hash_size; + hash = hashword(fhk.u32, 5, flow_config.hash_rand); } else { FlowHashKey4 fhk; @@ -289,8 +287,7 @@ static inline uint32_t FlowGetKey(const Packet *p) fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; - uint32_t hash = hashword(fhk.u32, 5, flow_config.hash_rand); - key = hash % flow_config.hash_size; + hash = hashword(fhk.u32, 5, flow_config.hash_rand); } } else if (p->ip6h != NULL) { FlowHashKey6 fhk; @@ -325,12 +322,10 @@ static inline uint32_t FlowGetKey(const Packet *p) fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; - uint32_t hash = hashword(fhk.u32, 11, flow_config.hash_rand); - key = hash % flow_config.hash_size; - } else - key = 0; + hash = hashword(fhk.u32, 11, flow_config.hash_rand); + } - return key; + return hash; } /* Since two or more flows can have the same hash key, we need to compare @@ -523,9 +518,9 @@ Flow *FlowGetFlowFromHashByPacket(const Packet *p) Flow *f = NULL; /* get the key to our bucket */ - uint32_t key = FlowGetKey(p); + uint32_t hash = FlowGetHash(p); /* get our hash bucket and lock it */ - FlowBucket *fb = &flow_hash[key]; + FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; FBLOCK_LOCK(fb); SCLogDebug("fb %p fb->head %p", fb, fb->head); @@ -544,6 +539,7 @@ Flow *FlowGetFlowFromHashByPacket(const Packet *p) /* got one, now lock, initialize and return */ FlowInit(f, p); + f->flow_hash = hash; f->fb = fb; /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); @@ -567,9 +563,9 @@ Flow *FlowLookupFlowFromHash(const Packet *p) Flow *f = NULL; /* get the key to our bucket */ - uint32_t key = FlowGetKey(p); + uint32_t hash = FlowGetHash(p); /* get our hash bucket and lock it */ - FlowBucket *fb = &flow_hash[key]; + FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; FBLOCK_LOCK(fb); SCLogDebug("fb %p fb->head %p", fb, fb->head); @@ -656,9 +652,9 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p FlowHashCountInit; /* get the key to our bucket */ - uint32_t key = FlowGetKey(p); + uint32_t hash = FlowGetHash(p); /* get our hash bucket and lock it */ - FlowBucket *fb = &flow_hash[key]; + FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; FBLOCK_LOCK(fb); SCLogDebug("fb %p fb->head %p", fb, fb->head); @@ -680,6 +676,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* got one, now lock, initialize and return */ FlowInit(f, p); + f->flow_hash = hash; f->fb = fb; /* update the last seen timestamp of this flow */ @@ -718,6 +715,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* initialize and return */ FlowInit(f, p); + f->flow_hash = hash; f->fb = fb; /* update the last seen timestamp of this flow */ diff --git a/src/flow.h b/src/flow.h index eab737760943..5953b55fcfae 100644 --- a/src/flow.h +++ b/src/flow.h @@ -314,6 +314,14 @@ typedef struct Flow_ uint8_t recursion_level; uint16_t vlan_id[2]; + /** flow hash - the flow hash before hash table size mod. */ + uint32_t flow_hash; + + /* time stamp of last update (last packet). Set/updated under the + * flow and flow hash row locks, safe to read under either the + * flow lock or flow hash row lock. */ + struct timeval lastts; + /* end of flow "header" */ SC_ATOMIC_DECLARE(FlowStateType, flow_state); @@ -338,11 +346,6 @@ typedef struct Flow_ uint32_t flags; - /* time stamp of last update (last packet). Set/updated under the - * flow and flow hash row locks, safe to read under either the - * flow lock or flow hash row lock. */ - struct timeval lastts; - #ifdef FLOWLOCK_RWLOCK SCRWLock r; #elif defined FLOWLOCK_MUTEX diff --git a/src/output-json.c b/src/output-json.c index 658ac473d700..bcc47840530f 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -167,12 +167,7 @@ void CreateJSONFlowId(json_t *js, const Flow *f) { if (f == NULL) return; -#if __WORDSIZE == 64 - uint64_t addr = (uint64_t)f; -#else - uint32_t addr = (uint32_t)f; -#endif - json_object_set_new(js, "flow_id", json_integer(addr)); + json_object_set_new(js, "flow_id", json_integer(f->flow_hash)); } json_t *CreateJSONHeader(const Packet *p, int direction_sensitive, From 0ac27e28abc735faded0ac71c0c48f9407cc3a5d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 23 Mar 2016 11:42:05 +0100 Subject: [PATCH 1102/2553] changelog: update for 3.0.1RC1 --- ChangeLog | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/ChangeLog b/ChangeLog index c3ef35c4ce69..ea4ab4deac43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,60 @@ +3.0.1RC1 -- 2016-03-23 + +Feature #1535: Expose the certificate itself in TLS-lua +Feature #1696: improve logged flow_id +Feature #1700: enable "relro" and "now" in compile options for 3.0 +Feature #1734: gre: support transparent ethernet bridge decoding +Feature #1740: Create counters for decode-events errors +Bug #873: suricata.yaml: .mgc is NOT actually added to value for magic file +Bug #1166: tls: CID 1197759: Resource leak (RESOURCE_LEAK) +Bug #1268: suricata and macos/darwin: [ERRCODE: SC_ERR_MAGIC_LOAD(197)] - magic_load failed: File 5.19 supports only version 12 magic files. `/usr/share/file/magic.mgc' is version 7 +Bug #1359: memory leak +Bug #1411: Suricata generates huge load when nfq_create_queue failed +Bug #1570: stream.inline defaults to IDS mode if missing +Bug #1591: afpacket: unsupported datalink type 65534 on tun device +Bug #1619: Per-Thread Delta Stats Broken +Bug #1638: rule parsing issues: rev +Bug #1641: Suricata won't build with --disable-unix-socket when libjansson is enabled +Bug #1646: smtp: fix inspected tracker values +Bug #1660: segv when using --set on a list +Bug #1669: Suricate 3.0RC3 segfault after 10 hours +Bug #1670: Modbus compiler warnings on Fedora 23 +Bug #1671: Cygwin Windows compilation with libjansson from source +Bug #1674: Cannot use 'tag:session' after base64_data keyword +Bug #1676: gentoo build error +Bug #1679: sensor-name configuration parameter specified in wrong place in default suricata.yaml +Bug #1680: Output sensor name in json +Bug #1684: eve: stream payload has wrong direction in IPS mode +Bug #1686: Conflicting "no" for "totals" and "threads" in stats output +Bug #1689: Stack overflow in case of variables misconfiguration +Bug #1693: Crash on Debian with libpcre 8.35 +Bug #1695: Unix Socket missing dump-counters mode +Bug #1698: Segmentation Fault at detect-engine-content-inspection.c:438 (master) +Bug #1699: CUDA build broken +Bug #1701: memory leaks +Bug #1702: TLS SNI parsing issue +Bug #1703: extreme slow down in HTTP multipart parsing +Bug #1706: smtp memory leaks +Bug #1707: malformed json if message is too big +Bug #1708: dcerpc memory leak +Bug #1709: http memory leak +Bug #1715: nfq: broken time stamps with recent Linux kernel 4.4 +Bug #1717: Memory leak on Suricata 3.0 with Netmap +Bug #1719: fileinfo output wrong in eve in http +Bug #1720: flowbit memleak +Bug #1724: alert-debuglog: non-decoder events won't trigger rotation. +Bug #1725: smtp logging memleak +Bug #1727: unix socket runmode per pcap memory leak +Bug #1728: unix manager command channel memory leaks +Bug #1729: PCRE jit is disabled/blacklisted when it should not +Bug #1731: detect-tls memory leak +Bug #1735: cppcheck: Shifting a negative value is undefined behaviour +Bug #1736: tls-sni: memory leaks on malformed traffic +Bug #1742: vlan use-for-tracking including Priority in hashing +Bug #1743: compilation with musl c library fails +Bug #1744: tls: out of bounds memory read on malformed traffic +Optimization #1642: Add --disable-python option + 3.0 -- 2016-01-27 Bug #1673: smtp: crash during mime parsing From 2e9279dd42840f5e2ba4e6ca969871f9f7b18ede Mon Sep 17 00:00:00 2001 From: cdwakelin Date: Wed, 23 Mar 2016 17:13:55 +0000 Subject: [PATCH 1103/2553] autofp: add "ippair" scheduler Add "ippair" autofp scheduler to split traffic based on source and destination IP only (not ports). - This is useful when using the "xbits" feature to track events that occur between the same hosts but not necessarily the same flow (such as exploit kit landings/expoits/payloads) - The disadvantage is that traffic may be balanced very unevenly between threads if some host pairs are much more frequently seen than others, so it may be only practicable for sandbox or pcap analysis - not tested for IPv6 See https://redmine.openinfosecfoundation.org/issues/1661 --- src/tmqh-flow.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index a1ec839bcfbe..49679b8fb203 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -41,6 +41,7 @@ Packet *TmqhInputFlow(ThreadVars *t); void TmqhOutputFlowHash(ThreadVars *t, Packet *p); +void TmqhOutputFlowIPPair(ThreadVars *t, Packet *p); void TmqhOutputFlowActivePackets(ThreadVars *t, Packet *p); void TmqhOutputFlowRoundRobin(ThreadVars *t, Packet *p); void *TmqhOutputFlowSetupCtx(char *queue_str); @@ -66,6 +67,9 @@ void TmqhFlowRegister(void) } else if (strcasecmp(scheduler, "hash") == 0) { SCLogInfo("AutoFP mode using \"Hash\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; + } else if (strcasecmp(scheduler, "ippair") == 0) { + SCLogInfo("AutoFP mode using \"ippair\" flow load balancer"); + tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowIPPair; } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry \"%s\" " "for autofp-scheduler in conf. Killing engine.", @@ -359,6 +363,56 @@ void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) return; } +/** + * \brief select the queue to output based on IP address pair. + * + * \param tv thread vars. + * \param p packet. + */ +void TmqhOutputFlowIPPair(ThreadVars *tv, Packet *p) +{ + int16_t qid = 0; + uint32_t addr_hash = 0; + int i; + + TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; + + /* if no flow we use the first queue, + * should be rare */ + if (p->flow != NULL) { + qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); + if (qid == -1) { + if (p->src.family == AF_INET6) { + for (i = 0; i < 4; i++) { + addr_hash += p->src.addr_data32[i] + p->dst.addr_data32[i]; + } + } else { + addr_hash = p->src.addr_data32[0] + p->dst.addr_data32[0]; + } + + /* we don't have to worry about possible overflow, since + * ctx->size will be lesser than 2 ** 31 for sure */ + qid = addr_hash % ctx->size; + (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, qid); + (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); + } + } else { + qid = ctx->last++; + + if (ctx->last == ctx->size) + ctx->last = 0; + } + (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); + + PacketQueue *q = ctx->queues[qid].q; + SCMutexLock(&q->mutex_q); + PacketEnqueue(q, p); + SCCondSignal(&q->cond_q); + SCMutexUnlock(&q->mutex_q); + + return; +} + #ifdef UNITTESTS static int TmqhOutputFlowSetupCtxTest01(void) From 1e0b5eb529bda9a2d978a1242016e222f5e6f5c3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 26 Mar 2016 10:59:52 +0100 Subject: [PATCH 1104/2553] autofp: print packet scheduler info only on autofp To avoid confusion about what runmode is active, only print autofp related scheduler information if autofp is the actual runmode. --- src/runmodes.c | 6 ++++++ src/tmqh-flow.c | 19 ++++++++++++++----- src/tmqh-flow.h | 2 ++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/runmodes.c b/src/runmodes.c index 601d356b9173..d4eda057af2b 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -49,6 +49,8 @@ #include "source-pfring.h" +#include "tmqh-flow.h" + int debuglog_enabled = 0; /** @@ -369,6 +371,10 @@ void RunModeDispatch(int runmode, const char *custom_mode) exit(EXIT_FAILURE); } + if (strcasecmp(active_runmode, "autofp") == 0) { + TmqhFlowPrintAutofpHandler(); + } + mode->RunModeFunc(); if (local_custom_mode != NULL) diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index 49679b8fb203..615546bf5999 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -59,16 +59,12 @@ void TmqhFlowRegister(void) char *scheduler = NULL; if (ConfGet("autofp-scheduler", &scheduler) == 1) { if (strcasecmp(scheduler, "round-robin") == 0) { - SCLogInfo("AutoFP mode using \"Round Robin\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowRoundRobin; } else if (strcasecmp(scheduler, "active-packets") == 0) { - SCLogInfo("AutoFP mode using \"Active Packets\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; } else if (strcasecmp(scheduler, "hash") == 0) { - SCLogInfo("AutoFP mode using \"Hash\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } else if (strcasecmp(scheduler, "ippair") == 0) { - SCLogInfo("AutoFP mode using \"ippair\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowIPPair; } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry \"%s\" " @@ -77,13 +73,26 @@ void TmqhFlowRegister(void) exit(EXIT_FAILURE); } } else { - SCLogInfo("AutoFP mode using default \"Active Packets\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; } return; } +void TmqhFlowPrintAutofpHandler(void) +{ +#define PRINT_IF_FUNC(f, msg) \ + if (tmqh_table[TMQH_FLOW].OutHandler == (f)) \ + SCLogInfo("AutoFP mode using \"%s\" flow load balancer", (msg)) + + PRINT_IF_FUNC(TmqhOutputFlowRoundRobin, "Round Robin"); + PRINT_IF_FUNC(TmqhOutputFlowActivePackets, "Active Packets"); + PRINT_IF_FUNC(TmqhOutputFlowHash, "Hash"); + PRINT_IF_FUNC(TmqhOutputFlowIPPair, "IPPair"); + +#undef PRINT_IF_FUNC +} + /* same as 'simple' */ Packet *TmqhInputFlow(ThreadVars *tv) { diff --git a/src/tmqh-flow.h b/src/tmqh-flow.h index ccf926333710..1206a05c13e5 100644 --- a/src/tmqh-flow.h +++ b/src/tmqh-flow.h @@ -45,4 +45,6 @@ typedef struct TmqhFlowCtx_ { void TmqhFlowRegister (void); void TmqhFlowRegisterTests(void); +void TmqhFlowPrintAutofpHandler(void); + #endif /* __TMQH_FLOW_H__ */ From 400fa5b9e5fab1bad4e78ab72e9ba8cda6ccd7e8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 26 Mar 2016 11:28:30 +0100 Subject: [PATCH 1105/2553] stats-log: fix layout issue due to decoder stats --- src/log-stats.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/log-stats.c b/src/log-stats.c index ad6ee547208d..ae7ed50605f0 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -90,17 +90,17 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) int days = in_hours / 24; MemBufferWriteString(aft->buffer, "----------------------------------------------" - "---------------------\n"); + "--------------------------------------\n"); MemBufferWriteString(aft->buffer, "Date: %" PRId32 "/%" PRId32 "/%04d -- " "%02d:%02d:%02d (uptime: %"PRId32"d, %02dh %02dm %02ds)\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, tms->tm_sec, days, hours, min, sec); MemBufferWriteString(aft->buffer, "----------------------------------------------" - "---------------------\n"); - MemBufferWriteString(aft->buffer, "%-25s | %-25s | %-s\n", "Counter", "TM Name", + "--------------------------------------\n"); + MemBufferWriteString(aft->buffer, "%-42s | %-25s | %-s\n", "Counter", "TM Name", "Value"); MemBufferWriteString(aft->buffer, "----------------------------------------------" - "---------------------\n"); + "--------------------------------------\n"); /* global stats */ uint32_t u = 0; @@ -112,8 +112,8 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) if (!(aft->statslog_ctx->flags & LOG_STATS_NULLS) && st->stats[u].value == 0) continue; - char line[1024]; - size_t len = snprintf(line, sizeof(line), "%-25s | %-25s | %-" PRIu64 "\n", + char line[256]; + size_t len = snprintf(line, sizeof(line), "%-42s | %-25s | %-" PRIu64 "\n", st->stats[u].name, st->stats[u].tm_name, st->stats[u].value); /* since we can have many threads, the buffer might not be big enough. @@ -138,8 +138,8 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) if (st->tstats[u].name == NULL) continue; - char line[1024]; - size_t len = snprintf(line, sizeof(line), "%-25s | %-25s | %-" PRIu64 "\n", + char line[256]; + size_t len = snprintf(line, sizeof(line), "%-42s | %-25s | %-" PRIu64 "\n", st->tstats[u].name, st->tstats[u].tm_name, st->tstats[u].value); /* since we can have many threads, the buffer might not be big enough. From a866d5d915bf472df535ed592218178ef5db0bc2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 17 Dec 2015 10:34:17 +0100 Subject: [PATCH 1106/2553] tx logging: fix potential missed logging issue Wrong scope of proto_logged variable could potentially lead to incrementing logged tx id w/o actually being logged. Reported-By: Jason Ish --- src/output-tx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output-tx.c b/src/output-tx.c index e05c540a076d..ca9216478be1 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -125,10 +125,10 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ int tx_progress_done_value_tc = AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto, STREAM_TOCLIENT); - int proto_logged = 0; - for (; tx_id < total_txs; tx_id++) { + int proto_logged = 0; + void *tx = AppLayerParserGetTx(p->proto, alproto, alstate, tx_id); if (tx == NULL) { SCLogDebug("tx is NULL not logging"); From f005310ddfcaf742c2ba8bb294c06014ac857abf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Sep 2015 12:12:37 +0200 Subject: [PATCH 1107/2553] detect: add corner case mpm test --- src/detect-content.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/detect-content.c b/src/detect-content.c index 5f315cc5befc..3130c86ceb8c 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -2260,6 +2260,18 @@ static int SigTest41TestNegatedContent(void) return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!\"GES\"; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n"); } +/** + * \test crash condition: as packet has no direction, it defaults to toclient + * in stream ctx inspection of packet. There a null ptr deref happens + * We don't care about the match/nomatch here. + */ +static int SigTest41aTestNegatedContent(void) +{ + (void)SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; flow:to_server; content:\"GET\"; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n"); + return 1; +} + + /** * \test A positive test that checks that the content string doesn't contain * the negated content within the specified depth @@ -2779,6 +2791,7 @@ void DetectContentRegisterTests(void) /* Negated content tests */ UtRegisterTest("SigTest41TestNegatedContent", SigTest41TestNegatedContent, 1); + UtRegisterTest("SigTest41aTestNegatedContent", SigTest41aTestNegatedContent, 1); UtRegisterTest("SigTest42TestNegatedContent", SigTest42TestNegatedContent, 1); UtRegisterTest("SigTest43TestNegatedContent", SigTest43TestNegatedContent, 1); UtRegisterTest("SigTest44TestNegatedContent", SigTest44TestNegatedContent, 1); From 9c5ee76455361feaac3fc7207ef40175c485f7d7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 26 Mar 2016 12:05:50 +0100 Subject: [PATCH 1108/2553] tcp: fix unlikely NULL-ptr dereference If a TCP packet could not get a flow (flow engine out of flows/memory) and there were *only* TCP inspecting rules with the direction explicitly set to 'to_server', a NULL pointer deref could happen. PacketPatternSearchWithStreamCtx would fall through to the 'to_client' case which was not initialized. --- src/detect-engine-mpm.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 5a21823ce845..9d1a9fc162ab 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -183,20 +183,25 @@ uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret = 0; + MpmCtx *mpm_ctx = NULL; if (p->flowflags & FLOW_PKT_TOSERVER) { DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtc, &det_ctx->pmq, - p->payload, p->payload_len); + mpm_ctx = det_ctx->sgh->mpm_stream_ctx_ts; + } else { DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_tc == NULL); - ret = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtc, &det_ctx->pmq, - p->payload, p->payload_len); + mpm_ctx = det_ctx->sgh->mpm_stream_ctx_tc; } + if (unlikely(mpm_ctx == NULL)) { + SCReturnInt(0); + } + + ret = mpm_table[mpm_ctx->mpm_type]. + Search(mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, + p->payload, p->payload_len); SCReturnInt(ret); } From dc7d0c736b9f34dc008490578e63e125f0e8ece8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 24 Mar 2016 09:31:19 +0100 Subject: [PATCH 1109/2553] pfring: use likely for fast path --- src/source-pfring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index 315953a66b4b..9b2db3841fd9 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -354,7 +354,7 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) PacketSetData(p, pkt_buffer, hdr.caplen); } - if (r == 1) { + if (likely(r == 1)) { //printf("RecievePfring src %" PRIu32 " sport %" PRIu32 " dst %" PRIu32 " dstport %" PRIu32 "\n", // hdr.parsed_pkt.ipv4_src,hdr.parsed_pkt.l4_src_port, hdr.parsed_pkt.ipv4_dst,hdr.parsed_pkt.l4_dst_port); From f78e990915803893c83dadb75b83d89cc12701e4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 24 Mar 2016 10:21:11 +0100 Subject: [PATCH 1110/2553] signals: handle INT/TERM signals in the main loop --- src/suricata.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index cbdea55150b5..05e5ffde7c57 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -276,12 +276,10 @@ int RunmodeGetCurrent(void) static void SignalHandlerSigint(/*@unused@*/ int sig) { sigint_count = 1; - suricata_ctl_flags |= SURICATA_STOP; } static void SignalHandlerSigterm(/*@unused@*/ int sig) { sigterm_count = 1; - suricata_ctl_flags |= SURICATA_KILL; } void SignalHandlerSigusr2StartingUp(int sig) @@ -2442,9 +2440,14 @@ int main(int argc, char **argv) int engine_retval = EXIT_SUCCESS; while(1) { + if (sigterm_count) { + suricata_ctl_flags |= SURICATA_KILL; + } else if (sigint_count) { + suricata_ctl_flags |= SURICATA_STOP; + } + if (suricata_ctl_flags & (SURICATA_KILL | SURICATA_STOP)) { SCLogNotice("Signal Received. Stopping engine."); - break; } From dd98bc353ea81c1626c4ab827a962140c42b7061 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 24 Mar 2016 11:51:49 +0100 Subject: [PATCH 1111/2553] signals: cleanup signal handling Simplify handling of USR2 signal. The SCLogInfo usage could lead to dead locks as the SCLog API can do many complicated things including memory allocations, syslog calls, libjansson message construction. If an existing malloc call was interupted, it could lead to the following dead lock: 0 __lll_lock_wait_private () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:97 1 0x0000003140c7d2df in _L_lock_10176 () from /lib64/libc.so.6 2 0x0000003140c7ab83 in __libc_malloc (bytes=211543457408) at malloc.c:3655 3 0x0000003140c80ec2 in __strdup (s=0x259ca40 "[%i] %t - (%f:%l) <%d> (%n) -- ") at strdup.c:43 4 0x000000000059dd4a in SCLogMessageGetBuffer (tval=0x7fff52b47360, color=1, type=SC_LOG_OP_TYPE_REGULAR, buffer=0x7fff52b47370 "", buffer_size=2048, log_format=0x259ca40 "[%i] %t - (%f:%l) <%d> (%n) -- ", log_level=SC_LOG_INFO, file=0x63dd00 "suricata.c", line=287, function=0x640f50 "SignalHandlerSigusr2StartingUp", error_code=SC_OK, message=0x7fff52b47bb0 "Live rule reload only possible after engine completely started.") at util-debug.c:307 5 0x000000000059e940 in SCLogMessage (log_level=SC_LOG_INFO, file=0x63dd00 "suricata.c", line=287, function=0x640f50 "SignalHandlerSigusr2StartingUp", error_code=SC_OK, message=0x7fff52b47bb0 "Live rule reload only possible after engine completely started.") at util-debug.c:549 6 0x000000000057e374 in SignalHandlerSigusr2StartingUp (sig=12) at suricata.c:287 7 8 _int_malloc (av=0x3140f8fe80, bytes=) at malloc.c:4751 9 0x0000003140c7ab1c in __libc_malloc (bytes=296) at malloc.c:3657 10 0x0000000000504d55 in FlowAlloc () at flow-util.c:60 11 0x00000000004fd909 in FlowInitConfig (quiet=0 '\000') at flow.c:454 12 0x0000000000584c8e in main (argc=6, argv=0x7fff52b4a3b8) at suricata.c:2300 This patch simply sets a variable and lets the main loop act on that. --- src/suricata.c | 51 ++++++++++++++++++++++---------------------------- src/suricata.h | 5 ----- 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 05e5ffde7c57..57e7afdb067a 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -273,6 +273,13 @@ int RunmodeGetCurrent(void) return run_mode; } +/** signal handlers + * + * WARNING: don't use the SCLog* API in the handlers. The API is complex + * with memory allocation possibly happening, calls to syslog, json message + * construction, etc. + */ + static void SignalHandlerSigint(/*@unused@*/ int sig) { sigint_count = 1; @@ -282,26 +289,11 @@ static void SignalHandlerSigterm(/*@unused@*/ int sig) sigterm_count = 1; } -void SignalHandlerSigusr2StartingUp(int sig) -{ - SCLogInfo("Live rule reload only possible after engine completely started."); -} - -void SignalHandlerSigusr2DelayedDetect(int sig) -{ - SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload blocked while delayed detect is still loading."); -} - -void SignalHandlerSigusr2SigFileStartup(int sig) -{ - SCLogInfo("Live rule reload not possible if -s or -S option used at runtime."); -} - /** * SIGUSR2 handler. Just set sigusr2_count. The main loop will act on * it. */ -void SignalHandlerSigusr2(int sig) +static void SignalHandlerSigusr2(int sig) { sigusr2_count = 1; } @@ -1829,6 +1821,7 @@ static int InitSignalHandler(SCInstance *suri) { /* registering signals we use */ UtilSignalHandlerSetup(SIGINT, SignalHandlerSigint); + UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); UtilSignalHandlerSetup(SIGTERM, SignalHandlerSigterm); UtilSignalHandlerSetup(SIGPIPE, SIG_IGN); UtilSignalHandlerSetup(SIGSYS, SIG_IGN); @@ -2163,11 +2156,6 @@ static int PostConfLoadedSetup(SCInstance *suri) DetectEngineRegisterAppInspectionEngines(); - if (suri->sig_file != NULL) - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2SigFileStartup); - else - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2StartingUp); - StorageFinalize(); TmModuleRunInit(); @@ -2422,11 +2410,6 @@ int main(int argc, char **argv) if (suri.delayed_detect) { /* force 'reload', this will load the rules and swap engines */ DetectEngineReload(NULL, &suri); - - if (suri.sig_file != NULL) - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2SigFileStartup); - else - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); SCLogNotice("Signature(s) loaded, Detect thread(s) activated."); } @@ -2459,11 +2442,21 @@ int main(int argc, char **argv) } if (sigusr2_count > 0) { - DetectEngineReload(conf_filename, &suri); + if (suri.sig_file != NULL) { + SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload not " + "possible if -s or -S option used at runtime."); + } else { + DetectEngineReload(conf_filename, &suri); + } sigusr2_count--; } else if (DetectEngineReloadIsStart()) { - DetectEngineReload(conf_filename, &suri); - DetectEngineReloadSetDone(); + if (suri.sig_file != NULL) { + SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload not " + "possible if -s or -S option used at runtime."); + } else { + DetectEngineReload(conf_filename, &suri); + DetectEngineReloadSetDone(); + } } usleep(10* 1000); diff --git a/src/suricata.h b/src/suricata.h index b11239ac2e9c..4ecab38c86a6 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -182,11 +182,6 @@ void EngineStop(void); void EngineKill(void); void EngineDone(void); -/* live rule swap required this to be made static */ -void SignalHandlerSigusr2(int); -void SignalHandlerSigusr2EngineShutdown(int); -void SignalHandlerSigusr2Idle(int sig); - int RunmodeIsUnittests(void); int RunmodeGetCurrent(void); int IsRuleReloadSet(int quiet); From eafd212661afbb57e07d237e7207ced2a44b5eee Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 23 Mar 2016 16:16:41 +0100 Subject: [PATCH 1112/2553] detect reload: call 'breakloop' on capture method Split wait loop into three steps: - first insert pseudo packets - 2nd nudge all capture threads to break out of their loop - third, wait for the detection thread contexts to be used Interupt capture more than once if needed Move packet injection into util func --- src/detect-engine.c | 77 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 492f2f108746..753593826020 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -541,6 +541,63 @@ int DetectEngineReloadIsDone(void) return r; } +/* nudge capture loops to wake up */ +static void BreakCapture(void) +{ + SCMutexLock(&tv_root_lock); + ThreadVars *tv = tv_root[TVT_PPT]; + while (tv) { + /* find the correct slot */ + TmSlot *slots = tv->tm_slots; + while (slots != NULL) { + if (suricata_ctl_flags != 0) { + return; + } + + TmModule *tm = TmModuleGetById(slots->tm_id); + if (!(tm->flags & TM_FLAG_RECEIVE_TM)) { + slots = slots->slot_next; + continue; + } + + if (tm->PktAcqLoop && tm->PktAcqBreakLoop) { + tm->PktAcqBreakLoop(tv, SC_ATOMIC_GET(slots->slot_data)); + } + break; + } + tv = tv->next; + } + SCMutexUnlock(&tv_root_lock); +} + +/** \internal + * \brief inject a pseudo packet into each detect thread that doesn't use the + * new det_ctx yet + */ +static void InjectPackets(ThreadVars **detect_tvs, + DetectEngineThreadCtx **new_det_ctx, + int no_of_detect_tvs) +{ + int i; + /* inject a fake packet if the detect thread isn't using the new ctx yet, + * this speeds up the process */ + for (i = 0; i < no_of_detect_tvs; i++) { + if (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) { + if (detect_tvs[i]->inq != NULL) { + Packet *p = PacketGetFromAlloc(); + if (p != NULL) { + p->flags |= PKT_PSEUDO_STREAM_END; + PacketQueue *q = &trans_q[detect_tvs[i]->inq->id]; + SCMutexLock(&q->mutex_q); + PacketEnqueue(q, p); + SCCondSignal(&q->cond_q); + SCMutexUnlock(&q->mutex_q); + } + } + } + } +} + /** \internal * \brief Update detect threads with new detect engine * @@ -675,11 +732,10 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) SCLogInfo("Live rule swap has swapped %d old det_ctx's with new ones, " "along with the new de_ctx", no_of_detect_tvs); - /* inject a fake packet if the detect thread isn't using the new ctx yet, - * this speeds up the process */ + InjectPackets(detect_tvs, new_det_ctx, no_of_detect_tvs); + for (i = 0; i < no_of_detect_tvs; i++) { int break_out = 0; - int pseudo_pkt_inserted = 0; usleep(1000); while (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) { if (suricata_ctl_flags != 0) { @@ -687,20 +743,7 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) break; } - if (pseudo_pkt_inserted == 0) { - pseudo_pkt_inserted = 1; - if (detect_tvs[i]->inq != NULL) { - Packet *p = PacketGetFromAlloc(); - if (p != NULL) { - p->flags |= PKT_PSEUDO_STREAM_END; - PacketQueue *q = &trans_q[detect_tvs[i]->inq->id]; - SCMutexLock(&q->mutex_q); - PacketEnqueue(q, p); - SCCondSignal(&q->cond_q); - SCMutexUnlock(&q->mutex_q); - } - } - } + BreakCapture(); usleep(1000); } if (break_out) From 11099cfa42db2d122cee47e0131ffa558048ec14 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 23 Mar 2016 17:05:14 +0100 Subject: [PATCH 1113/2553] detect reload: generic packet injection for capture Capture methods that are non blocking will still not generate packets that go through the system if there is no traffic. Some maintenance tasks, like rule reloads rely on packets to complete. This patch introduces a new thread flag, THV_CAPTURE_INJECT_PKT, that instructs the capture thread to create a fake packet. The capture implementations can call the TmThreadsCaptureInjectPacket utility function either with the packet they already got from the pool or without a packet. In this case the util func will get it's own packet. Implementations for pcap, AF_PACKET and PF_RING. --- src/detect-engine.c | 5 +++++ src/source-af-packet.c | 4 ++++ src/source-pcap.c | 2 ++ src/source-pfring.c | 8 ++++++++ src/threadvars.h | 5 +++++ src/tm-threads.h | 19 +++++++++++++++++++ 6 files changed, 43 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 753593826020..70afeda38c16 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -560,9 +560,14 @@ static void BreakCapture(void) continue; } + /* signal capture method that we need a packet. */ + TmThreadsSetFlag(tv, THV_CAPTURE_INJECT_PKT); + /* if the method supports it, BreakLoop. Otherwise we rely on + * the capture method's recv timeout */ if (tm->PktAcqLoop && tm->PktAcqBreakLoop) { tm->PktAcqBreakLoop(tv, SC_ATOMIC_GET(slots->slot_data)); } + break; } tv = tv->next; diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 3267b6c17248..942391dd4f02 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1241,6 +1241,10 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) AFPDumpCounters(ptv); break; } + } else if (unlikely(r == 0)) { + /* poll timed out, lets see if we need to inject a fake packet */ + TmThreadsCaptureInjectPacket(tv, ptv->slot, NULL); + } else if ((r < 0) && (errno != EINTR)) { SCLogError(SC_ERR_AFP_READ, "Error reading data from iface '%s': (%d" PRIu32 ") %s", ptv->iface, diff --git a/src/source-pcap.c b/src/source-pcap.c index 7c7a53e8c9a5..7b9a6161d325 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -339,6 +339,8 @@ TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot) } else if (ptv->cb_result == TM_ECODE_FAILED) { SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapCallbackLoop failed"); SCReturnInt(TM_ECODE_FAILED); + } else if (unlikely(r == 0)) { + TmThreadsCaptureInjectPacket(tv, ptv->slot, NULL); } StatsSyncCountersIfSignalled(tv); diff --git a/src/source-pfring.c b/src/source-pfring.c index 9b2db3841fd9..655031fb71f8 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -370,6 +370,14 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) PfringDumpCounters(ptv); last_dump = p->ts.tv_sec; } + } else if (unlikely(r == 0)) { + if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + SCReturnInt(TM_ECODE_OK); + } + + /* pfring didn't use the packet yet */ + TmThreadsCaptureInjectPacket(tv, ptv->slot, p); + } else { SCLogError(SC_ERR_PF_RING_RECV,"pfring_recv error %" PRId32 "", r); TmqhOutputPacketpool(ptv->tv, p); diff --git a/src/threadvars.h b/src/threadvars.h index 79a2b34dc4fd..578770c1aaac 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -48,6 +48,11 @@ struct TmSlot_; #define THV_KILL_PKTACQ (1 << 9) /**< flag thread to stop packet acq */ #define THV_FLOW_LOOP (1 << 10) /**< thread is in flow shutdown loop */ +/** signal thread's capture method to create a fake packet to force through + * the engine. This is to force timely handling of maintenance taks like + * rule reloads even if no packets are read by the capture method. */ +#define THV_CAPTURE_INJECT_PKT (1<<11) + /** Thread flags set and read by threads, to control the threads, when they * encounter certain conditions like failure */ #define THV_RESTART_THREAD 0x01 /** restart the thread */ diff --git a/src/tm-threads.h b/src/tm-threads.h index 2127a73abdb8..b39bf02f432c 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -197,6 +197,25 @@ static inline TmEcode TmThreadsSlotProcessPkt(ThreadVars *tv, TmSlot *s, Packet return r; } +/** \brief inject packet if THV_CAPTURE_INJECT_PKT is set + * Allow caller to supply their own packet + * + * Meant for detect reload process that interupts an sleeping capture thread + * to force a packet through the engine to complete a reload */ +static inline void TmThreadsCaptureInjectPacket(ThreadVars *tv, TmSlot *slot, Packet *p) +{ + if (TmThreadsCheckFlag(tv, THV_CAPTURE_INJECT_PKT)) { + TmThreadsUnsetFlag(tv, THV_CAPTURE_INJECT_PKT); + if (p == NULL) + p = PacketGetFromQueueOrAlloc(); + if (p != NULL) { + p->flags |= PKT_PSEUDO_STREAM_END; + if (TmThreadsSlotProcessPkt(tv, slot, p) != TM_ECODE_OK) { + TmqhOutputPacketpool(tv, p); + } + } + } +} void TmThreadsListThreads(void); int TmThreadsRegisterThread(ThreadVars *tv, const int type); From cae3ce9e1c141f47a31221c40a7f552af9fd6613 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 26 Mar 2016 19:56:00 +0100 Subject: [PATCH 1114/2553] netmap: implement capture inject packet flag --- src/source-netmap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/source-netmap.c b/src/source-netmap.c index f55ac86bc885..75f8d5d81508 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -901,6 +901,9 @@ static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) /* no events, timeout */ SCLogDebug("(%s:%d-%d) Poll timeout", ntv->ifsrc->ifname, ntv->src_ring_from, ntv->src_ring_to); + + /* poll timed out, lets see if we need to inject a fake packet */ + TmThreadsCaptureInjectPacket(tv, ntv->slot, NULL); continue; } From 30410e6900449a7f6d5798d5ac7bb86b7bd2b58d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Jun 2014 16:16:30 +0200 Subject: [PATCH 1115/2553] capture: warn -i user if faster options are available If af-packet, netmap or pfring are available, users should use those for best performance. --- src/suricata.c | 38 ++++++++++++++++++++++++++++++++++++++ src/util-error.c | 1 + src/util-error.h | 1 + 3 files changed, 40 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index 57e7afdb067a..5d8348ccfc5c 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1538,6 +1538,44 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) return TM_ECODE_FAILED; } + /* warn user if af-packet, netmap or pf-ring are available */ +#if defined HAVE_AF_PACKET || HAVE_PFRING || HAVE_NETMAP + int i = 0; +#ifdef HAVE_AF_PACKET + i++; +#endif +#ifdef HAVE_PFRING + i++; +#endif +#ifdef HAVE_NETMAP + i++; +#endif + SCLogWarning(SC_WARN_FASTER_CAPTURE_AVAILABLE, "faster capture " + "option%s %s available:" +#ifdef HAVE_AF_PACKET + " AF_PACKET (--af-packet=%s)" +#endif +#ifdef HAVE_PFRING + " PF_RING (--pfring-int=%s)" +#endif +#ifdef HAVE_NETMAP + " NETMAP (--netmap=%s)" +#endif + ". Use --pcap=%s to suppress this warning", + i == 1 ? "" : "s", i == 1 ? "is" : "are" + +#ifdef HAVE_AF_PACKET + , optarg +#endif +#ifdef HAVE_PFRING + , optarg +#endif +#ifdef HAVE_NETMAP + , optarg +#endif + , optarg + ); +#endif /* some windows shells require escaping of the \ in \Device. Otherwise * the backslashes are stripped. We put them back here. */ if (strlen(optarg) > 9 && strncmp(optarg, "DeviceNPF", 9) == 0) { diff --git a/src/util-error.c b/src/util-error.c index 5b03c5ad15f8..3bf695504a69 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -315,6 +315,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_STATS_LOG_NEGATED); CASE_CODE (SC_ERR_JSON_STATS_LOG_NEGATED); CASE_CODE (SC_ERR_DEPRECATED_CONF); + CASE_CODE (SC_WARN_FASTER_CAPTURE_AVAILABLE); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 0dcfb674d1fa..42fd74f9638e 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -305,6 +305,7 @@ typedef enum { SC_ERR_STATS_LOG_NEGATED, /** When totals and threads are both NO in yaml **/ SC_ERR_JSON_STATS_LOG_NEGATED, /** When totals and threads are both NO in yaml **/ SC_ERR_DEPRECATED_CONF, /**< Deprecated configuration parameter. */ + SC_WARN_FASTER_CAPTURE_AVAILABLE, } SCError; const char *SCErrorToString(SCError); From c8e01a3d62c116ee5cad4d4a86c300d55d3781e9 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Tue, 29 Mar 2016 09:32:26 +1100 Subject: [PATCH 1116/2553] util-hash-lookup3: Add hashlittle_safe() variant By default, hashlittle() will read off the end of the key, up to the next four-byte boundary, although the data beyond the end of the key doesn't affect the hash. This read causes uninitialized read warnings from Valgrind and Address Sanitizer. Here we add hashlittle_safe(), which avoids reading off the end of the buffer (using the code inside the VALGRIND-guarded block in the original hashlittle() implementation). --- src/util-hash-lookup3.c | 174 ++++++++++++++++++++++++++++++++++++++++ src/util-hash-lookup3.h | 5 ++ 2 files changed, 179 insertions(+) diff --git a/src/util-hash-lookup3.c b/src/util-hash-lookup3.c index f765521d6ed4..d13fa16af21b 100644 --- a/src/util-hash-lookup3.c +++ b/src/util-hash-lookup3.c @@ -449,6 +449,180 @@ uint32_t hashlittle( const void *key, size_t length, uint32_t initval) } +/* +------------------------------------------------------------------------------- +hashlittle_safe() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * Note that unlike hashlittle() above, we use the "safe" version of this + * block that is #ifdef VALGRIND above, in order to avoid warnings from + * Valgrind or Address Sanitizer. + */ + + const uint8_t *k8 = (const uint8_t *)k; + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} + + /* * hashlittle2: return 2 32-bit hash values * diff --git a/src/util-hash-lookup3.h b/src/util-hash-lookup3.h index 1e37e9104ed1..7ef4cf5d06d5 100644 --- a/src/util-hash-lookup3.h +++ b/src/util-hash-lookup3.h @@ -52,6 +52,11 @@ void hashword2 (const uint32_t *k, /* the key, an array of uint32_t val uint32_t hashlittle( const void *key, size_t length, uint32_t initval); +/* A variant of hashlittle() that ensures avoids accesses beyond the last byte + * of the string, which will cause warnings from tools like Valgrind or Address + * Sanitizer. */ +uint32_t hashlittle_safe(const void *key, size_t length, uint32_t initval); + void hashlittle2(const void *key, /* the key to hash */ size_t length, /* length of the key */ uint32_t *pc, /* IN: primary initval, OUT: primary hash */ From c37195c95fa57d8a9ce1b3bcf9c5e185b37fd5a3 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Tue, 15 Mar 2016 12:38:23 +1100 Subject: [PATCH 1117/2553] mpm: pass offset, depth args to add functions MpmAddPatternCI and MpmAddPatternCS had arguments for offset and depth, but these were not being passed in by the caller. --- src/detect-engine-mpm.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 9d1a9fc162ab..d5447aea7455 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1216,28 +1216,40 @@ static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, Signature *s, uint8_t flags, int chop) { + uint16_t pat_offset = cd->offset; + uint16_t pat_depth = cd->depth; + + /* recompute offset/depth to cope with chop */ + if (chop && (pat_depth || pat_offset)) { + pat_offset += cd->fp_chop_offset; + if (pat_depth) { + pat_depth -= cd->content_len; + pat_depth += cd->fp_chop_offset + cd->fp_chop_len; + } + } + if (cd->flags & DETECT_CONTENT_NOCASE) { if (chop) { MpmAddPatternCI(mpm_ctx, cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, + pat_offset, pat_depth, cd->id, s->num, flags); } else { MpmAddPatternCI(mpm_ctx, cd->content, cd->content_len, - 0, 0, + pat_offset, pat_depth, cd->id, s->num, flags); } } else { if (chop) { MpmAddPatternCS(mpm_ctx, cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, + pat_offset, pat_depth, cd->id, s->num, flags); } else { MpmAddPatternCS(mpm_ctx, cd->content, cd->content_len, - 0, 0, + pat_offset, pat_depth, cd->id, s->num, flags); } } From 13b87f5affa886d008caae4c54bce910f1c3c03d Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Tue, 15 Mar 2016 12:40:24 +1100 Subject: [PATCH 1118/2553] mpm: add Hyperscan integration This adds an MPM implementation that uses the Hyperscan regex engine library from Intel, accessible as the "hs" mpm-algo. --- configure.ac | 39 + src/Makefile.am | 1 + src/detect-engine.c | 3 + src/runmode-unittests.c | 4 + src/suricata.c | 5 + src/util-mpm-hs.c | 2198 +++++++++++++++++++++++++++++++++++++++ src/util-mpm-hs.h | 76 ++ src/util-mpm.c | 4 + src/util-mpm.h | 1 + 9 files changed, 2331 insertions(+) create mode 100644 src/util-mpm-hs.c create mode 100644 src/util-mpm-hs.h diff --git a/configure.ac b/configure.ac index 16e0dcfb42b4..2b05189718da 100644 --- a/configure.ac +++ b/configure.ac @@ -585,6 +585,44 @@ AC_MSG_RESULT(no) fi + # libhs + enable_hyperscan="no" + + # Try pkg-config first: + PKG_CHECK_MODULES([libhs], libhs,, [with_pkgconfig_libhs=no]) + if test "$with_pkgconfig_libhs" != "no"; then + CPPFLAGS="${CPPFLAGS} ${libhs_CFLAGS}" + LIBS="${LIBS} ${libhs_LIBS}" + fi + + AC_ARG_WITH(libhs_includes, + [ --with-libhs-includes=DIR libhs include directory], + [with_libhs_includes="$withval"],[with_libhs_includes=no]) + AC_ARG_WITH(libhs_libraries, + [ --with-libhs-libraries=DIR libhs library directory], + [with_libhs_libraries="$withval"],[with_libhs_libraries="no"]) + + if test "$with_libhs_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_libhs_includes}" + fi + AC_CHECK_HEADER(hs.h,HYPERSCAN="yes",HYPERSCAN="no") + if test "$HYPERSCAN" = "yes"; then + if test "$with_libhs_libraries" != "no"; then + LDFLAGS="${LDFLAGS} -L${with_libhs_libraries}" + fi + + AC_CHECK_LIB(hs,hs_compile,,HYPERSCAN="no") + enable_hyperscan="yes" + if test "$HYPERSCAN" = "no"; then + echo + echo " Hyperscan headers are present, but link test failed." + echo " Check that you have a shared library and C++ linkage available." + echo + enable_hyperscan="no" + fi + fi + AS_IF([test "x$enable_hyperscan" = "xyes"], [AC_DEFINE([BUILD_HYPERSCAN], [1], [Intel Hyperscan support enabled])]) + # libyaml AC_ARG_WITH(libyaml_includes, [ --with-libyaml-includes=DIR libyaml include directory], @@ -1896,6 +1934,7 @@ SURICATA_BUILD_CONF="Suricata Configuration: Non-bundled htp: ${enable_non_bundled_htp} Old barnyard2 support: ${enable_old_barnyard2} CUDA enabled: ${enable_cuda} + Hyperscan support: ${enable_hyperscan} Suricatasc install: ${enable_python} diff --git a/src/Makefile.am b/src/Makefile.am index 9555a28c5019..aed9022e1a58 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -372,6 +372,7 @@ util-mpm-ac-tile.c util-mpm-ac-tile.h \ util-mpm-ac-tile-small.c \ util-mpm-b2g.c util-mpm-b2g.h \ util-mpm-b3g.c util-mpm-b3g.h \ +util-mpm-hs.c util-mpm-hs.h \ util-mpm.c util-mpm.h \ util-mpm-wumanber.c util-mpm-wumanber.h \ util-optimize.h \ diff --git a/src/detect-engine.c b/src/detect-engine.c index 70afeda38c16..50a69153adc4 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1068,6 +1068,9 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) /* for now, since we still haven't implemented any intelligence into * understanding the patterns and distributing mpm_ctx across sgh */ if (de_ctx->mpm_matcher == DEFAULT_MPM || de_ctx->mpm_matcher == MPM_AC_GFBS || +#ifdef BUILD_HYPERSCAN + de_ctx->mpm_matcher == MPM_HS || +#endif #ifdef __SC_CUDA_SUPPORT__ de_ctx->mpm_matcher == MPM_AC_BS || de_ctx->mpm_matcher == MPM_AC_CUDA) { #else diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 332202095800..962e7c1dbb1a 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -108,6 +108,7 @@ #include "util-memrchr.h" #include "util-mpm-ac.h" +#include "util-mpm-hs.h" #include "detect-engine-mpm.h" #include "util-decode-asn1.h" @@ -288,6 +289,9 @@ void RunUnittests(int list_unittests, char *regex_arg) uint32_t failed = UtRunTests(regex_arg); PacketPoolDestroy(); UtCleanup(); +#ifdef BUILD_HYPERSCAN + MpmHSGlobalCleanup(); +#endif #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) MpmCudaBufferDeSetup(); diff --git a/src/suricata.c b/src/suricata.c index 5d8348ccfc5c..dbe1b139c33b 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -194,6 +194,7 @@ #include "util-cuda-buffer.h" #include "util-mpm-ac.h" #endif +#include "util-mpm-hs.h" #include "util-storage.h" #include "host-storage.h" @@ -2615,6 +2616,10 @@ int main(int argc, char **argv) SC_ATOMIC_DESTROY(engine_stage); +#ifdef BUILD_HYPERSCAN + MpmHSGlobalCleanup(); +#endif + #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) MpmCudaBufferDeSetup(); diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c new file mode 100644 index 000000000000..2f6237e9e7ae --- /dev/null +++ b/src/util-mpm-hs.c @@ -0,0 +1,2198 @@ +/* Copyright (C) 2007-2016 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 Jim Xu + * \author Justin Viiret + * + * MPM pattern matcher that calls the Hyperscan regex matcher. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" + +#include "conf.h" +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-memcmp.h" +#include "util-mpm-hs.h" +#include "util-memcpy.h" +#include "util-hash.h" +#include "util-hash-lookup3.h" + +#ifdef BUILD_HYPERSCAN + +#include + +void SCHSInitCtx(MpmCtx *); +void SCHSInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); +void SCHSDestroyCtx(MpmCtx *); +void SCHSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); +int SCHSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, + uint32_t, SigIntId, uint8_t); +int SCHSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, + uint32_t, SigIntId, uint8_t); +int SCHSPreparePatterns(MpmCtx *mpm_ctx); +uint32_t SCHSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); +void SCHSPrintInfo(MpmCtx *mpm_ctx); +void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); +void SCHSRegisterTests(void); + +/* size of the hash table used to speed up pattern insertions initially */ +#define INIT_HASH_SIZE 65536 + +/* Initial size of the global database hash (used for de-duplication). */ +#define INIT_DB_HASH_SIZE 1000 + +/* Global prototype scratch, built incrementally as Hyperscan databases are + * built and then cloned for each thread context. Access is serialised via + * g_scratch_proto_mutex. */ +static hs_scratch_t *g_scratch_proto = NULL; +static SCMutex g_scratch_proto_mutex = SCMUTEX_INITIALIZER; + +/* Global hash table of Hyperscan databases, used for de-duplication. Access is + * serialised via g_db_table_mutex. */ +static HashTable *g_db_table = NULL; +static SCMutex g_db_table_mutex = SCMUTEX_INITIALIZER; + +/** + * \internal + * \brief Wraps SCMalloc (which is a macro) so that it can be passed to + * hs_set_allocator() for Hyperscan's use. + */ +static void *SCHSMalloc(size_t size) +{ + return SCMalloc(size); +} + +/** + * \internal + * \brief Wraps SCFree (which is a macro) so that it can be passed to + * hs_set_allocator() for Hyperscan's use. + */ +static void SCHSFree(void *ptr) +{ + SCFree(ptr); +} + +/** \brief Register Suricata malloc/free with Hyperscan. + * + * Requests that Hyperscan use Suricata's allocator for allocation of + * databases, scratch space, etc. + */ +static void SCHSSetAllocators(void) +{ + hs_error_t err = hs_set_allocator(SCHSMalloc, SCHSFree); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Failed to set Hyperscan allocator."); + exit(EXIT_FAILURE); + } +} + +/** + * \internal + * \brief Convert a pattern into a regex string accepted by the Hyperscan + * compiler. + * + * For simplicity, we just take each byte of the original pattern and render it + * with a hex escape (i.e. ' ' -> "\x20")/ + */ +static char *SCHSRenderPattern(uint8_t *pat, uint16_t pat_len) +{ + if (pat == NULL) { + return NULL; + } + const size_t hex_len = (pat_len * 4) + 1; + char *str = SCMalloc(hex_len); + if (str == NULL) { + return NULL; + } + memset(str, 0, hex_len); + char *sp = str; + for (uint16_t i = 0; i < pat_len; i++) { + snprintf(sp, 5, "\\x%02x", pat[i]); + sp += 4; + } + *sp = '\0'; + return str; +} + +/** + * \internal + * \brief Creates a hash of the pattern. We use it for the hashing process + * during the initial pattern insertion time, to cull duplicate sigs. + * + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * + * \retval hash A 32 bit unsigned hash. + */ +static inline uint32_t SCHSInitHashRaw(uint8_t *pat, uint16_t patlen) +{ + uint32_t hash = patlen * pat[0]; + if (patlen > 1) + hash += pat[1]; + + return (hash % INIT_HASH_SIZE); +} + +/** + * \internal + * \brief Looks up a pattern. We use it for the hashing process during + * the initial pattern insertion time, to cull duplicate sigs. + * + * \param ctx Pointer to the HS ctx. + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * \param flags Flags. We don't need this. + * + * \retval hash A 32 bit unsigned hash. + */ +static inline SCHSPattern *SCHSInitHashLookup(SCHSCtx *ctx, uint8_t *pat, + uint16_t patlen, uint16_t offset, + uint16_t depth, char flags, + uint32_t pid) +{ + uint32_t hash = SCHSInitHashRaw(pat, patlen); + + if (ctx->init_hash == NULL) { + return NULL; + } + + SCHSPattern *t = ctx->init_hash[hash]; + for (; t != NULL; t = t->next) { + /* Since Hyperscan uses offset/depth, we must distinguish between + * patterns with the same ID but different offset/depth here. */ + if (t->id == pid && t->offset == offset && t->depth == depth) { + BUG_ON(t->len != patlen); + BUG_ON(SCMemcmp(t->original_pat, pat, patlen) != 0); + return t; + } + } + + return NULL; +} + +/** + * \internal + * \brief Allocates a new pattern instance. + * + * \param mpm_ctx Pointer to the mpm context. + * + * \retval p Pointer to the newly created pattern. + */ +static inline SCHSPattern *SCHSAllocPattern(MpmCtx *mpm_ctx) +{ + SCHSPattern *p = SCMalloc(sizeof(SCHSPattern)); + if (unlikely(p == NULL)) { + exit(EXIT_FAILURE); + } + memset(p, 0, sizeof(SCHSPattern)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(SCHSPattern); + + return p; +} + +/** + * \internal + * \brief Used to free SCHSPattern instances. + * + * \param mpm_ctx Pointer to the mpm context. + * \param p Pointer to the SCHSPattern instance to be freed. + * \param free Free the above pointer or not. + */ +static inline void SCHSFreePattern(MpmCtx *mpm_ctx, SCHSPattern *p) +{ + if (p != NULL && p->original_pat != NULL) { + SCFree(p->original_pat); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } + + if (p != NULL && p->sids != NULL) { + SCFree(p->sids); + } + + if (p != NULL) { + SCFree(p); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCHSPattern); + } +} + +static inline uint32_t SCHSInitHash(SCHSPattern *p) +{ + uint32_t hash = p->len * p->original_pat[0]; + if (p->len > 1) + hash += p->original_pat[1]; + + return (hash % INIT_HASH_SIZE); +} + +static inline int SCHSInitHashAdd(SCHSCtx *ctx, SCHSPattern *p) +{ + uint32_t hash = SCHSInitHash(p); + + if (ctx->init_hash == NULL) { + return 0; + } + + if (ctx->init_hash[hash] == NULL) { + ctx->init_hash[hash] = p; + return 0; + } + + SCHSPattern *tt = NULL; + SCHSPattern *t = ctx->init_hash[hash]; + + /* get the list tail */ + do { + tt = t; + t = t->next; + } while (t != NULL); + + tt->next = p; + + return 0; +} + +/** + * \internal + * \brief Add a pattern to the mpm-hs context. + * + * \param mpm_ctx Mpm context. + * \param pat Pointer to the pattern. + * \param patlen Length of the pattern. + * \param pid Pattern id + * \param sid Signature id (internal id). + * \param flags Pattern's MPM_PATTERN_* flags. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static int SCHSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + + if (offset != 0) { + flags |= MPM_PATTERN_FLAG_OFFSET; + } + if (depth != 0) { + flags |= MPM_PATTERN_FLAG_DEPTH; + } + + if (patlen == 0) { + SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); + return 0; + } + + /* check if we have already inserted this pattern */ + SCHSPattern *p = + SCHSInitHashLookup(ctx, pat, patlen, offset, depth, flags, pid); + if (p == NULL) { + SCLogDebug("Allocing new pattern"); + + /* p will never be NULL */ + p = SCHSAllocPattern(mpm_ctx); + + p->len = patlen; + p->flags = flags; + p->id = pid; + + p->offset = offset; + p->depth = depth; + + p->original_pat = SCMalloc(patlen); + if (p->original_pat == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy(p->original_pat, pat, patlen); + + /* put in the pattern hash */ + SCHSInitHashAdd(ctx, p); + + mpm_ctx->pattern_cnt++; + + if (mpm_ctx->maxlen < patlen) + mpm_ctx->maxlen = patlen; + + if (mpm_ctx->minlen == 0) { + mpm_ctx->minlen = patlen; + } else { + if (mpm_ctx->minlen > patlen) + mpm_ctx->minlen = patlen; + } + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + } else { + /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ + + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + if (!found) { + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + } + } + + return 0; + +error: + SCHSFreePattern(mpm_ctx, p); + return -1; +} + +/** + * \brief Pattern database information used only as input to the Hyperscan + * compiler. + */ +typedef struct SCHSCompileData_ { + unsigned int *ids; + unsigned int *flags; + char **expressions; + hs_expr_ext_t **ext; + unsigned int pattern_cnt; +} SCHSCompileData; + +static SCHSCompileData *SCHSAllocCompileData(unsigned int pattern_cnt) +{ + SCHSCompileData *cd = SCMalloc(pattern_cnt * sizeof(SCHSCompileData)); + if (cd == NULL) { + goto error; + } + memset(cd, 0, pattern_cnt * sizeof(SCHSCompileData)); + + cd->pattern_cnt = pattern_cnt; + + cd->ids = SCMalloc(pattern_cnt * sizeof(unsigned int)); + if (cd->ids == NULL) { + goto error; + } + memset(cd->ids, 0, pattern_cnt * sizeof(unsigned int)); + + cd->flags = SCMalloc(pattern_cnt * sizeof(unsigned int)); + if (cd->flags == NULL) { + goto error; + } + memset(cd->flags, 0, pattern_cnt * sizeof(unsigned int)); + + cd->expressions = SCMalloc(pattern_cnt * sizeof(char *)); + if (cd->expressions == NULL) { + goto error; + } + memset(cd->expressions, 0, pattern_cnt * sizeof(char *)); + + cd->ext = SCMalloc(pattern_cnt * sizeof(hs_expr_ext_t *)); + if (cd->ext == NULL) { + goto error; + } + memset(cd->ext, 0, pattern_cnt * sizeof(hs_expr_ext_t *)); + + return cd; + +error: + SCLogDebug("SCHSCompileData alloc failed"); + if (cd) { + SCFree(cd->ids); + SCFree(cd->flags); + SCFree(cd->expressions); + SCFree(cd->ext); + SCFree(cd); + } + return NULL; +} + +static void SCHSFreeCompileData(SCHSCompileData *cd) +{ + if (cd == NULL) { + return; + } + + SCFree(cd->ids); + SCFree(cd->flags); + if (cd->expressions) { + for (unsigned int i = 0; i < cd->pattern_cnt; i++) { + SCFree(cd->expressions[i]); + } + SCFree(cd->expressions); + } + if (cd->ext) { + for (unsigned int i = 0; i < cd->pattern_cnt; i++) { + SCFree(cd->ext[i]); + } + SCFree(cd->ext); + } + SCFree(cd); +} + +typedef struct PatternDatabase_ { + SCHSPattern **parray; + hs_database_t *hs_db; + uint32_t pattern_cnt; + + /* Reference count: number of MPM contexts using this pattern database. */ + uint32_t ref_cnt; +} PatternDatabase; + +static uint32_t SCHSPatternHash(const SCHSPattern *p, uint32_t hash) +{ + BUG_ON(p->original_pat == NULL); + BUG_ON(p->sids == NULL); + + hash = hashlittle_safe(&p->len, sizeof(p->len), hash); + hash = hashlittle_safe(&p->flags, sizeof(p->flags), hash); + hash = hashlittle_safe(p->original_pat, p->len, hash); + hash = hashlittle_safe(&p->id, sizeof(p->id), hash); + hash = hashlittle_safe(&p->offset, sizeof(p->offset), hash); + hash = hashlittle_safe(&p->depth, sizeof(p->depth), hash); + hash = hashlittle_safe(&p->sids_size, sizeof(p->sids_size), hash); + hash = hashlittle_safe(p->sids, p->sids_size * sizeof(SigIntId), hash); + return hash; +} + +static char SCHSPatternCompare(const SCHSPattern *p1, const SCHSPattern *p2) +{ + if ((p1->len != p2->len) || (p1->flags != p2->flags) || + (p1->id != p2->id) || (p1->offset != p2->offset) || + (p1->depth != p2->depth) || (p1->sids_size != p2->sids_size)) { + return 0; + } + + if (SCMemcmp(p1->original_pat, p2->original_pat, p1->len) != 0) { + return 0; + } + + if (SCMemcmp(p1->sids, p2->sids, p1->sids_size * sizeof(p1->sids[0])) != + 0) { + return 0; + } + + return 1; +} + +static uint32_t PatternDatabaseHash(HashTable *ht, void *data, uint16_t len) +{ + const PatternDatabase *pd = data; + uint32_t hash = 0; + hash = hashword(&pd->pattern_cnt, 1, hash); + + for (uint32_t i = 0; i < pd->pattern_cnt; i++) { + hash = SCHSPatternHash(pd->parray[i], hash); + } + + hash %= ht->array_size; + return hash; +} + +static char PatternDatabaseCompare(void *data1, uint16_t len1, void *data2, + uint16_t len2) +{ + const PatternDatabase *pd1 = data1; + const PatternDatabase *pd2 = data2; + + if (pd1->pattern_cnt != pd2->pattern_cnt) { + return 0; + } + + for (uint32_t i = 0; i < pd1->pattern_cnt; i++) { + if (SCHSPatternCompare(pd1->parray[i], pd2->parray[i]) == 0) { + return 0; + } + } + + return 1; +} + +static void PatternDatabaseFree(PatternDatabase *pd) +{ + BUG_ON(pd->ref_cnt != 0); + + if (pd->parray != NULL) { + for (uint32_t i = 0; i < pd->pattern_cnt; i++) { + SCHSPattern *p = pd->parray[i]; + if (p != NULL) { + SCFree(p->original_pat); + SCFree(p->sids); + SCFree(p); + } + } + SCFree(pd->parray); + } + + hs_free_database(pd->hs_db); + + SCFree(pd); +} + +static void PatternDatabaseTableFree(void *data) +{ + /* Stub function handed to hash table; actual freeing of PatternDatabase + * structures is done in MPM destruction when the ref_cnt drops to zero. */ +} + +static PatternDatabase *PatternDatabaseAlloc(uint32_t pattern_cnt) +{ + PatternDatabase *pd = SCMalloc(sizeof(PatternDatabase)); + if (pd == NULL) { + return NULL; + } + memset(pd, 0, sizeof(PatternDatabase)); + pd->pattern_cnt = pattern_cnt; + pd->ref_cnt = 0; + pd->hs_db = NULL; + + /* alloc the pattern array */ + pd->parray = + (SCHSPattern **)SCMalloc(pd->pattern_cnt * sizeof(SCHSPattern *)); + if (pd->parray == NULL) { + SCFree(pd); + return NULL; + } + memset(pd->parray, 0, pd->pattern_cnt * sizeof(SCHSPattern *)); + + return pd; +} + +/** + * \brief Process the patterns added to the mpm, and create the internal tables. + * + * \param mpm_ctx Pointer to the mpm context. + */ +int SCHSPreparePatterns(MpmCtx *mpm_ctx) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + + if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { + SCLogDebug("no patterns supplied to this mpm_ctx"); + return 0; + } + + hs_error_t err; + hs_compile_error_t *compile_err = NULL; + SCHSCompileData *cd = NULL; + PatternDatabase *pd = NULL; + + cd = SCHSAllocCompileData(mpm_ctx->pattern_cnt); + if (cd == NULL) { + goto error; + } + + pd = PatternDatabaseAlloc(mpm_ctx->pattern_cnt); + if (pd == NULL) { + goto error; + } + + /* populate the pattern array with the patterns in the hash */ + for (uint32_t i = 0, p = 0; i < INIT_HASH_SIZE; i++) { + SCHSPattern *node = ctx->init_hash[i], *nnode = NULL; + while (node != NULL) { + nnode = node->next; + node->next = NULL; + pd->parray[p++] = node; + node = nnode; + } + } + + /* we no longer need the hash, so free its memory */ + SCFree(ctx->init_hash); + ctx->init_hash = NULL; + + /* Serialise whole database compilation as a relatively easy way to ensure + * dedupe is safe. */ + SCMutexLock(&g_db_table_mutex); + + /* Init global pattern database hash if necessary. */ + if (g_db_table == NULL) { + g_db_table = HashTableInit(INIT_DB_HASH_SIZE, PatternDatabaseHash, + PatternDatabaseCompare, + PatternDatabaseTableFree); + if (g_db_table == NULL) { + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + } + + /* Check global hash table to see if we've seen this pattern database + * before, and reuse the Hyperscan database if so. */ + PatternDatabase *pd_cached = HashTableLookup(g_db_table, pd, 1); + + if (pd_cached != NULL) { + SCLogDebug("Reusing cached database %p with %" PRIu32 + " patterns (ref_cnt=%" PRIu32 ")", + pd_cached->hs_db, pd_cached->pattern_cnt, + pd_cached->ref_cnt); + pd_cached->ref_cnt++; + ctx->pattern_db = pd_cached; + SCMutexUnlock(&g_db_table_mutex); + PatternDatabaseFree(pd); + SCHSFreeCompileData(cd); + return 0; + } + + BUG_ON(ctx->pattern_db != NULL); /* already built? */ + + for (uint32_t i = 0; i < pd->pattern_cnt; i++) { + const SCHSPattern *p = pd->parray[i]; + + cd->ids[i] = i; + cd->flags[i] = HS_FLAG_SINGLEMATCH; + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + cd->flags[i] |= HS_FLAG_CASELESS; + } + + cd->expressions[i] = SCHSRenderPattern(p->original_pat, p->len); + + if (p->flags & (MPM_PATTERN_FLAG_OFFSET | MPM_PATTERN_FLAG_DEPTH)) { + cd->ext[i] = SCMalloc(sizeof(hs_expr_ext_t)); + if (cd->ext[i] == NULL) { + goto error; + } + memset(cd->ext[i], 0, sizeof(hs_expr_ext_t)); + + if (p->flags & MPM_PATTERN_FLAG_OFFSET) { + cd->ext[i]->flags |= HS_EXT_FLAG_MIN_OFFSET; + cd->ext[i]->min_offset = p->offset + p->len; + } + if (p->flags & MPM_PATTERN_FLAG_DEPTH) { + cd->ext[i]->flags |= HS_EXT_FLAG_MAX_OFFSET; + cd->ext[i]->max_offset = p->offset + p->depth; + } + } + } + + BUG_ON(mpm_ctx->pattern_cnt == 0); + + err = hs_compile_ext_multi((const char *const *)cd->expressions, cd->flags, + cd->ids, (const hs_expr_ext_t *const *)cd->ext, + cd->pattern_cnt, HS_MODE_BLOCK, NULL, &pd->hs_db, + &compile_err); + + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "failed to compile hyperscan database"); + if (compile_err) { + SCLogError(SC_ERR_FATAL, "compile error: %s", compile_err->message); + } + hs_free_compile_error(compile_err); + goto error; + } + + ctx->pattern_db = pd; + + SCMutexLock(&g_scratch_proto_mutex); + err = hs_alloc_scratch(pd->hs_db, &g_scratch_proto); + SCMutexUnlock(&g_scratch_proto_mutex); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "failed to allocate scratch"); + goto error; + } + + err = hs_database_size(pd->hs_db, &ctx->hs_db_size); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "failed to query database size"); + goto error; + } + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += ctx->hs_db_size; + + SCLogDebug("Built %" PRIu32 " patterns into a database of size %" PRIuMAX + " bytes", mpm_ctx->pattern_cnt, (uintmax_t)ctx->hs_db_size); + + /* Cache this database globally for later. */ + pd->ref_cnt = 1; + HashTableAdd(g_db_table, pd, 1); + SCMutexUnlock(&g_db_table_mutex); + + SCHSFreeCompileData(cd); + return 0; + +error: + SCMutexUnlock(&g_db_table_mutex); + if (pd) { + PatternDatabaseFree(pd); + } + if (cd) { + SCHSFreeCompileData(cd); + } + return -1; +} + +/** + * \brief Init the mpm thread context. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + * \param matchsize We don't need this. + */ +void SCHSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + uint32_t matchsize) +{ + memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + + SCHSThreadCtx *ctx = SCMalloc(sizeof(SCHSThreadCtx)); + if (ctx == NULL) { + exit(EXIT_FAILURE); + } + mpm_thread_ctx->ctx = ctx; + + memset(ctx, 0, sizeof(SCHSThreadCtx)); + mpm_thread_ctx->memory_cnt++; + mpm_thread_ctx->memory_size += sizeof(SCHSThreadCtx); + + ctx->scratch = NULL; + ctx->scratch_size = 0; + + SCMutexLock(&g_scratch_proto_mutex); + + if (g_scratch_proto == NULL) { + /* There is no scratch prototype: this means that we have not compiled + * any Hyperscan databases. */ + SCMutexUnlock(&g_scratch_proto_mutex); + SCLogDebug("No scratch space prototype"); + return; + } + + hs_error_t err = hs_clone_scratch(g_scratch_proto, + (hs_scratch_t **)&ctx->scratch); + + SCMutexUnlock(&g_scratch_proto_mutex); + + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Unable to clone scratch prototype"); + exit(EXIT_FAILURE); + } + + err = hs_scratch_size(ctx->scratch, &ctx->scratch_size); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Unable to query scratch size"); + exit(EXIT_FAILURE); + } + + mpm_thread_ctx->memory_cnt++; + mpm_thread_ctx->memory_size += ctx->scratch_size; +} + +/** + * \brief Initialize the HS context. + * + * \param mpm_ctx Mpm context. + */ +void SCHSInitCtx(MpmCtx *mpm_ctx) +{ + if (mpm_ctx->ctx != NULL) + return; + + mpm_ctx->ctx = SCMalloc(sizeof(SCHSCtx)); + if (mpm_ctx->ctx == NULL) { + exit(EXIT_FAILURE); + } + memset(mpm_ctx->ctx, 0, sizeof(SCHSCtx)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(SCHSCtx); + + /* initialize the hash we use to speed up pattern insertions */ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + ctx->init_hash = SCMalloc(sizeof(SCHSPattern *) * INIT_HASH_SIZE); + if (ctx->init_hash == NULL) { + exit(EXIT_FAILURE); + } + memset(ctx->init_hash, 0, sizeof(SCHSPattern *) * INIT_HASH_SIZE); +} + +/** + * \brief Destroy the mpm thread context. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + */ +void SCHSDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) +{ + SCHSPrintSearchStats(mpm_thread_ctx); + + SCHSThreadCtx *thr_ctx = (SCHSThreadCtx *)mpm_thread_ctx->ctx; + + if (thr_ctx->scratch != NULL) { + hs_free_scratch(thr_ctx->scratch); + mpm_thread_ctx->memory_cnt--; + mpm_thread_ctx->memory_size -= thr_ctx->scratch_size; + } + + if (mpm_thread_ctx->ctx != NULL) { + SCFree(mpm_thread_ctx->ctx); + mpm_thread_ctx->ctx = NULL; + mpm_thread_ctx->memory_cnt--; + mpm_thread_ctx->memory_size -= sizeof(SCHSThreadCtx); + } +} + +/** + * \brief Destroy the mpm context. + * + * \param mpm_ctx Pointer to the mpm context. + */ +void SCHSDestroyCtx(MpmCtx *mpm_ctx) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + if (ctx == NULL) + return; + + if (ctx->init_hash != NULL) { + SCFree(ctx->init_hash); + ctx->init_hash = NULL; + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCHSPattern *)); + } + + /* Decrement pattern database ref count, and delete it entirely if the + * count has dropped to zero. */ + SCMutexLock(&g_db_table_mutex); + PatternDatabase *pd = ctx->pattern_db; + if (pd) { + BUG_ON(pd->ref_cnt == 0); + pd->ref_cnt--; + if (pd->ref_cnt == 0) { + HashTableRemove(g_db_table, pd, 1); + PatternDatabaseFree(pd); + } + } + SCMutexUnlock(&g_db_table_mutex); + + SCFree(mpm_ctx->ctx); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCHSCtx); +} + +typedef struct SCHSCallbackCtx_ { + SCHSCtx *ctx; + void *pmq; + uint32_t match_count; +} SCHSCallbackCtx; + +/* Hyperscan MPM match event handler */ +static int SCHSMatchEvent(unsigned int id, unsigned long long from, + unsigned long long to, unsigned int flags, + void *ctx) +{ + SCHSCallbackCtx *cctx = ctx; + PatternMatcherQueue *pmq = cctx->pmq; + const PatternDatabase *pd = cctx->ctx->pattern_db; + const SCHSPattern *pat = pd->parray[id]; + + SCLogDebug("Hyperscan Match %" PRIu32 ": id=%" PRIu32 " @ %" PRIuMAX + " (pat id=%" PRIu32 ")", + cctx->match_count, (uint32_t)id, (uintmax_t)to, pat->id); + + pmq->pattern_id_bitarray[pat->id / 8] |= (1 << (pat->id % 8)); + MpmAddPid(pmq, pat->id); + MpmAddSids(pmq, pat->sids, pat->sids_size); + + cctx->match_count++; + return 0; +} + +/** + * \brief The Hyperscan search function. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + * \param pmq Pointer to the Pattern Matcher Queue to hold + * search matches. + * \param buf Buffer to be searched. + * \param buflen Buffer length. + * + * \retval matches Match count. + */ +uint32_t SCHSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) +{ + uint32_t ret = 0; + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + SCHSThreadCtx *hs_thread_ctx = (SCHSThreadCtx *)(mpm_thread_ctx->ctx); + const PatternDatabase *pd = ctx->pattern_db; + + SCHSCallbackCtx cctx = {.ctx = ctx, .pmq = pmq, .match_count = 0}; + + /* scratch should have been cloned from g_scratch_proto at thread init. */ + hs_scratch_t *scratch = hs_thread_ctx->scratch; + BUG_ON(pd->hs_db == NULL); + BUG_ON(scratch == NULL); + + hs_error_t err = hs_scan(pd->hs_db, (const char *)buf, buflen, 0, scratch, + SCHSMatchEvent, &cctx); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Scanning with Hyperscan returned error %d", + err); + } else { + ret = cctx.match_count; + } + + return ret; +} + +/** + * \brief Add a case insensitive pattern. Although we have different calls for + * adding case sensitive and insensitive patterns, we make a single call + * for either case. No special treatment for either case. + * + * \param mpm_ctx Pointer to the mpm context. + * \param pat The pattern to add. + * \param patlen The pattern length. + * \param offset The pattern offset. + * \param depth The pattern depth. + * \param pid The pattern id. + * \param sid The pattern signature id. + * \param flags Flags associated with this pattern. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCHSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags) +{ + flags |= MPM_PATTERN_FLAG_NOCASE; + return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +/** + * \brief Add a case sensitive pattern. Although we have different calls for + * adding case sensitive and insensitive patterns, we make a single call + * for either case. No special treatment for either case. + * + * \param mpm_ctx Pointer to the mpm context. + * \param pat The pattern to add. + * \param patlen The pattern length. + * \param offset The pattern offset. + * \param depth The pattern depth. + * \param pid The pattern id. + * \param sid The pattern signature id. + * \param flags Flags associated with this pattern. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCHSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags) +{ + return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) +{ + return; +} + +void SCHSPrintInfo(MpmCtx *mpm_ctx) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + PatternDatabase *pd = ctx->pattern_db; + + printf("MPM HS Information:\n"); + printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); + printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); + printf(" Sizeof:\n"); + printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); + printf(" SCHSCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSCtx)); + printf(" SCHSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSPattern)); + printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); + printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); + printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); + printf("\n"); + + if (ctx) { + char *db_info = NULL; + if (hs_database_info(pd->hs_db, &db_info) == HS_SUCCESS) { + printf("HS Database Info: %s\n", db_info); + SCFree(db_info); + } + printf("HS Database Size: %" PRIuMAX " bytes\n", + (uintmax_t)ctx->hs_db_size); + } + + printf("\n"); +} + +/************************** Mpm Registration ***************************/ + +/** + * \brief Register the Hyperscan MPM. + */ +void MpmHSRegister(void) +{ + mpm_table[MPM_HS].name = "hs"; + mpm_table[MPM_HS].max_pattern_length = 0; + + mpm_table[MPM_HS].InitCtx = SCHSInitCtx; + mpm_table[MPM_HS].InitThreadCtx = SCHSInitThreadCtx; + mpm_table[MPM_HS].DestroyCtx = SCHSDestroyCtx; + mpm_table[MPM_HS].DestroyThreadCtx = SCHSDestroyThreadCtx; + mpm_table[MPM_HS].AddPattern = SCHSAddPatternCS; + mpm_table[MPM_HS].AddPatternNocase = SCHSAddPatternCI; + mpm_table[MPM_HS].Prepare = SCHSPreparePatterns; + mpm_table[MPM_HS].Search = SCHSSearch; + mpm_table[MPM_HS].Cleanup = NULL; + mpm_table[MPM_HS].PrintCtx = SCHSPrintInfo; + mpm_table[MPM_HS].PrintThreadCtx = SCHSPrintSearchStats; + mpm_table[MPM_HS].RegisterUnittests = SCHSRegisterTests; + + /* Set Hyperscan memory allocators */ + SCHSSetAllocators(); +} + +/** + * \brief Clean up global memory used by all Hyperscan MPM instances. + * + * Currently, this is just the global scratch prototype. + */ +void MpmHSGlobalCleanup(void) +{ + SCMutexLock(&g_scratch_proto_mutex); + if (g_scratch_proto) { + SCLogInfo("Cleaning up Hyperscan global scratch"); + hs_free_scratch(g_scratch_proto); + g_scratch_proto = NULL; + } + SCMutexUnlock(&g_scratch_proto_mutex); + + SCMutexLock(&g_db_table_mutex); + if (g_db_table != NULL) { + SCLogInfo("Clearing Hyperscan database cache"); + HashTableFree(g_db_table); + g_db_table = NULL; + } + SCMutexUnlock(&g_db_table_mutex); +} + +/*************************************Unittests********************************/ + +#ifdef UNITTESTS + +static int SCHSTest01(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghjiklmnopqrstuvwxyz"; + + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest02(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest03(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); + PmqSetup(&pmq, 3); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest04(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq, 3); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest05(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq, 3); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest06(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcd"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest07(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* should match 30 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); + /* should match 29 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); + /* should match 28 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); + /* 26 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); + /* 21 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, + 0, 0, 5, 0, 0); + PmqSetup(&pmq, 6); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 6) + result = 1; + else + printf("6 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest08(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + uint32_t cnt = + SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest09(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + uint32_t cnt = + SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest10(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "abcdefgh" + "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest11(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) + goto end; + PmqSetup(&pmq, 5); + + if (SCHSPreparePatterns(&mpm_ctx) == -1) + goto end; + + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + result = 1; + + char *buf = "he"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)) == 1); + buf = "she"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)) == 2); + buf = "his"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)) == 1); + buf = "hers"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)) == 2); + +end: + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest12(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq, 2); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest13(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest14(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest15(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest16(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcdefghijklmnopqrstuvwxyzABC"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghijklmnopqrstuvwxyzABC"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest17(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcdefghijklmnopqrstuvwxyzAB"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghijklmnopqrstuvwxyzAB"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest18(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest19(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest20(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + char *pat = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest21(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + uint32_t cnt = + SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest22(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq, 2); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest23(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + uint32_t cnt = + SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 0) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest24(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + uint32_t cnt = + SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest25(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq, 3); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest26(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq, 2); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "works"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest27(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "tone"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest28(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PatternMatcherQueue pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq, 1); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + + char *buf = "tONE"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest29(void) +{ + uint8_t *buf = (uint8_t *)"onetwothreefourfivesixseveneightnine"; + uint16_t buflen = strlen((char *)buf); + Packet *p = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + de_ctx->mpm_matcher = MPM_HS; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit( + de_ctx, "alert tcp any any -> any any " + "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + de_ctx->sig_list->next = + SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"onetwothreefourfivesixseveneightnine\"; " + "fast_pattern:3,3; sid:2;)"); + if (de_ctx->sig_list->next == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1) != 1) { + printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); + goto end; + } + if (PacketAlertCheck(p, 2) != 1) { + printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + } + + UTHFreePackets(&p, 1); + return result; +} + +#endif /* UNITTESTS */ + +void SCHSRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SCHSTest01", SCHSTest01, 1); + UtRegisterTest("SCHSTest02", SCHSTest02, 1); + UtRegisterTest("SCHSTest03", SCHSTest03, 1); + UtRegisterTest("SCHSTest04", SCHSTest04, 1); + UtRegisterTest("SCHSTest05", SCHSTest05, 1); + UtRegisterTest("SCHSTest06", SCHSTest06, 1); + UtRegisterTest("SCHSTest07", SCHSTest07, 1); + UtRegisterTest("SCHSTest08", SCHSTest08, 1); + UtRegisterTest("SCHSTest09", SCHSTest09, 1); + UtRegisterTest("SCHSTest10", SCHSTest10, 1); + UtRegisterTest("SCHSTest11", SCHSTest11, 1); + UtRegisterTest("SCHSTest12", SCHSTest12, 1); + UtRegisterTest("SCHSTest13", SCHSTest13, 1); + UtRegisterTest("SCHSTest14", SCHSTest14, 1); + UtRegisterTest("SCHSTest15", SCHSTest15, 1); + UtRegisterTest("SCHSTest16", SCHSTest16, 1); + UtRegisterTest("SCHSTest17", SCHSTest17, 1); + UtRegisterTest("SCHSTest18", SCHSTest18, 1); + UtRegisterTest("SCHSTest19", SCHSTest19, 1); + UtRegisterTest("SCHSTest20", SCHSTest20, 1); + UtRegisterTest("SCHSTest21", SCHSTest21, 1); + UtRegisterTest("SCHSTest22", SCHSTest22, 1); + UtRegisterTest("SCHSTest23", SCHSTest23, 1); + UtRegisterTest("SCHSTest24", SCHSTest24, 1); + UtRegisterTest("SCHSTest25", SCHSTest25, 1); + UtRegisterTest("SCHSTest26", SCHSTest26, 1); + UtRegisterTest("SCHSTest27", SCHSTest27, 1); + UtRegisterTest("SCHSTest28", SCHSTest28, 1); + UtRegisterTest("SCHSTest29", SCHSTest29, 1); +#endif + + return; +} + +#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-mpm-hs.h b/src/util-mpm-hs.h new file mode 100644 index 000000000000..4778ab85012a --- /dev/null +++ b/src/util-mpm-hs.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2007-2016 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 Jim Xu + * \author Justin Viiret + * + * MPM pattern matcher that calls the Hyperscan regex matcher. + */ + +#ifndef __UTIL_MPM_HS__H__ +#define __UTIL_MPM_HS__H__ + +typedef struct SCHSPattern_ { + /* length of the pattern */ + uint16_t len; + /* flags describing the pattern */ + uint8_t flags; + /* holds the original pattern that was added */ + uint8_t *original_pat; + /* pattern id */ + uint32_t id; + + uint16_t offset; + uint16_t depth; + + /* sid(s) for this pattern */ + uint32_t sids_size; + SigIntId *sids; + + /* only used at ctx init time, when this structure is part of a hash + * table. */ + struct SCHSPattern_ *next; +} SCHSPattern; + +typedef struct SCHSCtx_ { + /* hash used during ctx initialization */ + SCHSPattern **init_hash; + + /* pattern database and pattern arrays. */ + void *pattern_db; + + /* size of database, for accounting. */ + size_t hs_db_size; +} SCHSCtx; + +typedef struct SCHSThreadCtx_ { + /* Hyperscan scratch space region for this thread, capable of handling any + * database that has been compiled. */ + void *scratch; + + /* size of scratch space, for accounting. */ + size_t scratch_size; +} SCHSThreadCtx; + +void MpmHSRegister(void); + +void MpmHSGlobalCleanup(void); + +#endif /* __UTIL_MPM_HS__H__ */ diff --git a/src/util-mpm.c b/src/util-mpm.c index ac185e301fa3..01aafc152f79 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -35,6 +35,7 @@ #include "util-mpm-ac-gfbs.h" #include "util-mpm-ac-bs.h" #include "util-mpm-ac-tile.h" +#include "util-mpm-hs.h" #include "util-hashlist.h" #include "detect-engine.h" @@ -674,6 +675,9 @@ void MpmTableSetup(void) MpmACBSRegister(); MpmACGfbsRegister(); MpmACTileRegister(); +#ifdef BUILD_HYPERSCAN + MpmHSRegister(); +#endif /* BUILD_HYPERSCAN */ #ifdef __SC_CUDA_SUPPORT__ MpmACCudaRegister(); #endif /* __SC_CUDA_SUPPORT__ */ diff --git a/src/util-mpm.h b/src/util-mpm.h index da650884b88f..15d8d5b9e3ff 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -72,6 +72,7 @@ enum { MPM_AC_GFBS, MPM_AC_BS, MPM_AC_TILE, + MPM_HS, /* table size */ MPM_TABLE_SIZE, }; From 31ed7042b55ddd85c3790346de8ab73055b0c47d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Mar 2016 11:44:00 +0200 Subject: [PATCH 1119/2553] hyperscan: add DrMemory suppressions --- qa/drmemory.suppress | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/qa/drmemory.suppress b/qa/drmemory.suppress index a4f61eb9ce83..7f1da7decd8d 100644 --- a/qa/drmemory.suppress +++ b/qa/drmemory.suppress @@ -27,3 +27,34 @@ libmagic.so.1!? libmagic.so.1!magic_load suricata!MagicInit +UNINITIALIZED READ +name=Hyperscan false positives due to DrMemory limitations 1 +... +libhs.so.*!hs_compile_ext_multi +suricata!SigGroupBuild +... +suricata!main + +UNINITIALIZED READ +name=Hyperscan false positives due to DrMemory limitations 2 +... +libhs.so.*!hs_compile_ext_multi +suricata!SigGroupBuild +... +libc.so.6!__clone + +WARNING +name=Prefetch warnings 1 +... +libhs.so.*!hs_scan +suricata!SCHSSearch +... +suricata!main + +WARNING +name=Prefetch warnings 2 +... +libhs.so.*!hs_scan +suricata!SCHSSearch +... +libc.so.6!__clone From f836256e20de1ede8d8fbb85e331278b8eb78eb1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 30 Mar 2016 09:39:46 +0200 Subject: [PATCH 1120/2553] detect: fix small mem leak on duplicate sigs Direct leak of 80 byte(s) in 5 object(s) allocated from: #0 0x4c673b in __interceptor_malloc (/home/victor/dev/suricata/src/suricata+0x4c673b) #1 0xb7a425 in DetectEngineSignatureIsDuplicate /home/victor/dev/suricata/src/detect-parse.c:1715:10 #2 0xb79390 in DetectEngineAppendSig /home/victor/dev/suricata/src/detect-parse.c:1836:19 #3 0x86fe56 in DetectLoadSigFile /home/victor/dev/suricata/src/detect.c:357:15 #4 0x815fee in ProcessSigFiles /home/victor/dev/suricata/src/detect.c:419:13 #5 0x8139a8 in SigLoadSignatures /home/victor/dev/suricata/src/detect.c:499:15 #6 0xfe435d in LoadSignatures /home/victor/dev/suricata/src/suricata.c:1979:9 #7 0xfcd87e in main /home/victor/dev/suricata/src/suricata.c:2345:17 #8 0x7fb66bf7cec4 in __libc_start_main /build/eglibc-3GlaMS/eglibc-2.19/csu/libc-start.c:287 --- src/detect-parse.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detect-parse.c b/src/detect-parse.c index f451c5c87ecb..54035d2e090c 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1749,6 +1749,8 @@ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, * and discard the other one */ if (sw->s->rev <= sw_dup->s->rev) { ret = 1; + SCFree(sw); + sw = NULL; goto end; } From ffb5498228a731ef1775408dfc0a5c1676777a66 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 30 Mar 2016 19:53:04 +0200 Subject: [PATCH 1121/2553] detect: fix potential deadlock during reload If interrupted during the BreakLoop stage during reload, a deadlock could happen. --- src/detect-engine.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 50a69153adc4..3d0b4b52d61d 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -551,6 +551,7 @@ static void BreakCapture(void) TmSlot *slots = tv->tm_slots; while (slots != NULL) { if (suricata_ctl_flags != 0) { + SCMutexUnlock(&tv_root_lock); return; } From 06dcaec335cf6b07d4759ca086915997b9b56c81 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 30 Mar 2016 08:46:30 -0600 Subject: [PATCH 1122/2553] byte-extract: for string, default to base "dec" if not provided For Snort compatibility, as Snort defaults to "dec" if not provided. Fixed issue 1697: https://redmine.openinfosecfoundation.org/issues/1697 --- src/detect-byte-extract.c | 50 +++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index bc8bdf2d6f92..a53a62472f56 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -465,11 +465,8 @@ static inline DetectByteExtractData *DetectByteExtractParse(char *arg) if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_STRING) { if (bed->base == DETECT_BYTE_EXTRACT_BASE_NONE) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Base not specified for " - "byte_extract, though string was specified. " - "The right options are (string, hex), (string, oct) " - "or (string, dec)"); - goto error; + /* Default to decimal if base not specified. */ + bed->base = DETECT_BYTE_EXTRACT_BASE_DEC; } if (bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "byte_extract can't have " @@ -4815,6 +4812,46 @@ int DetectByteExtractTest63(void) return result; } +int DetectByteExtractTestParseNoBase(void) +{ + int result = 0; + + DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, string"); + if (bed == NULL) + goto end; + + if (bed->nbytes != 4) { + goto end; + } + if (bed->offset != 2) { + goto end; + } + if (strcmp(bed->name, "one") != 0) { + goto end; + } + if (bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING) { + goto end; + } + if (bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE) { + goto end; + } + if (bed->base != DETECT_BYTE_EXTRACT_BASE_DEC) { + goto end; + } + if (bed->align_value != 0) { + goto end; + } + if (bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + goto end; + } + + result = 1; + end: + if (bed != NULL) + DetectByteExtractFree(bed); + return result; +} + #endif /* UNITTESTS */ void DetectByteExtractRegisterTests(void) @@ -4891,6 +4928,9 @@ void DetectByteExtractRegisterTests(void) UtRegisterTest("DetectByteExtractTest61", DetectByteExtractTest61, 1); UtRegisterTest("DetectByteExtractTest62", DetectByteExtractTest62, 1); UtRegisterTest("DetectByteExtractTest63", DetectByteExtractTest63, 1); + + UtRegisterTest("DetectByteExtractTestParseNoBase", + DetectByteExtractTestParseNoBase, 1); #endif /* UNITTESTS */ return; From d05883af9bae17e5fe915e1491ebe486c030dbc2 Mon Sep 17 00:00:00 2001 From: browner87 Date: Wed, 23 Mar 2016 11:05:05 -0400 Subject: [PATCH 1123/2553] Fix for redmine bug 1737 PCAP stats not reset between files in Unix socket mode. Added a memset to the Global Init function to clear these stats. --- src/source-pcap-file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 5f970d64fb84..737b7865d80e 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -136,6 +136,7 @@ void TmModuleDecodePcapFileRegister (void) void PcapFileGlobalInit() { + memset(&pcap_g, 0x00, sizeof(pcap_g)); SC_ATOMIC_INIT(pcap_g.invalid_checksums); } From 070a35fd3b2aad730f70331ddbd338440af675d6 Mon Sep 17 00:00:00 2001 From: browner87 Date: Thu, 24 Mar 2016 12:55:34 -0400 Subject: [PATCH 1124/2553] source-pcap-file: fix stats not being reset Fix for redmine #1737. Clears stats between each scanned PCAP instead of just on load in Unix socket mode. --- src/source-pcap-file.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 737b7865d80e..c2187eda1bbb 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -108,8 +108,6 @@ TmEcode DecodePcapFileThreadDeinit(ThreadVars *tv, void *data); void TmModuleReceivePcapFileRegister (void) { - memset(&pcap_g, 0x00, sizeof(pcap_g)); - tmm_modules[TMM_RECEIVEPCAPFILE].name = "ReceivePcapFile"; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadInit = ReceivePcapFileThreadInit; tmm_modules[TMM_RECEIVEPCAPFILE].Func = NULL; From 2ccf028eac9ed88fe16a6f7d473ae97c4062732a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 31 Mar 2016 10:04:44 +0200 Subject: [PATCH 1125/2553] hyperscan: fix minor coverity warning 1358024 *** CID 1358024: Null pointer dereferences (REVERSE_INULL) /src/util-mpm-hs.c: 1043 in SCHSPrintInfo() 1037 printf(" SCHSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSPattern)); 1038 printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); 1039 printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); 1040 printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); 1041 printf("\n"); 1042 >>> CID 1358024: Null pointer dereferences (REVERSE_INULL) >>> Null-checking "ctx" suggests that it may be null, but it has already been dereferenced on all paths leading to the check. 1043 if (ctx) { 1044 char *db_info = NULL; 1045 if (hs_database_info(pd->hs_db, &db_info) == HS_SUCCESS) { 1046 printf("HS Database Info: %s\n", db_info); 1047 SCFree(db_info); 1048 } --- src/util-mpm-hs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index 2f6237e9e7ae..be4a93d0cd87 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -1026,7 +1026,6 @@ void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) void SCHSPrintInfo(MpmCtx *mpm_ctx) { SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; - PatternDatabase *pd = ctx->pattern_db; printf("MPM HS Information:\n"); printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); @@ -1041,6 +1040,7 @@ void SCHSPrintInfo(MpmCtx *mpm_ctx) printf("\n"); if (ctx) { + PatternDatabase *pd = ctx->pattern_db; char *db_info = NULL; if (hs_database_info(pd->hs_db, &db_info) == HS_SUCCESS) { printf("HS Database Info: %s\n", db_info); From ba035e601e6f5d56a9ce2c5bbb4bb2c2c80d2eca Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 31 Mar 2016 10:07:01 +0200 Subject: [PATCH 1126/2553] hyperscan: fix minor coverity warning 1358023 *** CID 1358023: Null pointer dereferences (REVERSE_INULL) /src/util-mpm-hs.c: 860 in SCHSDestroyThreadCtx() 854 if (thr_ctx->scratch != NULL) { 855 hs_free_scratch(thr_ctx->scratch); 856 mpm_thread_ctx->memory_cnt--; 857 mpm_thread_ctx->memory_size -= thr_ctx->scratch_size; 858 } 859 >>> CID 1358023: Null pointer dereferences (REVERSE_INULL) >>> Null-checking "mpm_thread_ctx->ctx" suggests that it may be null, but it has already been dereferenced on all paths leading to the check. 860 if (mpm_thread_ctx->ctx != NULL) { 861 SCFree(mpm_thread_ctx->ctx); 862 mpm_thread_ctx->ctx = NULL; 863 mpm_thread_ctx->memory_cnt--; 864 mpm_thread_ctx->memory_size -= sizeof(SCHSThreadCtx); 865 } --- src/util-mpm-hs.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index be4a93d0cd87..c9c92db664b0 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -849,15 +849,15 @@ void SCHSDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { SCHSPrintSearchStats(mpm_thread_ctx); - SCHSThreadCtx *thr_ctx = (SCHSThreadCtx *)mpm_thread_ctx->ctx; + if (mpm_thread_ctx->ctx != NULL) { + SCHSThreadCtx *thr_ctx = (SCHSThreadCtx *)mpm_thread_ctx->ctx; - if (thr_ctx->scratch != NULL) { - hs_free_scratch(thr_ctx->scratch); - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= thr_ctx->scratch_size; - } + if (thr_ctx->scratch != NULL) { + hs_free_scratch(thr_ctx->scratch); + mpm_thread_ctx->memory_cnt--; + mpm_thread_ctx->memory_size -= thr_ctx->scratch_size; + } - if (mpm_thread_ctx->ctx != NULL) { SCFree(mpm_thread_ctx->ctx); mpm_thread_ctx->ctx = NULL; mpm_thread_ctx->memory_cnt--; From d07c495ed1a3f7d427ae0db604771ce935a1ccaf Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 31 Mar 2016 14:21:21 +0200 Subject: [PATCH 1127/2553] app-layer-tls-handshake: fix heap-buffer overflow Fix heap-buffer overflow that occurs when we are given repeatedly certificates with the length of zero. --- src/app-layer-tls-handshake.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/app-layer-tls-handshake.c b/src/app-layer-tls-handshake.c index 530a7c1fb04d..61e3790e497f 100644 --- a/src/app-layer-tls-handshake.c +++ b/src/app-layer-tls-handshake.c @@ -110,10 +110,23 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin i = 0; while (certificates_length > 0) { + if ((uint32_t)(input + 3 - start_data) > (uint32_t)input_len) { + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_CERTIFICATE); + return -1; + } + cur_cert_length = input[0]<<16 | input[1]<<8 | input[2]; input += 3; parsed += 3; + /* current certificate length should be greater than zero */ + if (cur_cert_length == 0) { + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_CERTIFICATE); + return -1; + } + if (input - start_data + cur_cert_length > input_len) { AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_CERTIFICATE); return -1; From c0dd91159103e0be75cb53b2562acad992171ded Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 31 Mar 2016 14:28:24 +0200 Subject: [PATCH 1128/2553] util-decode-der: fix heap-buffer-overflow --- src/util-decode-der.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util-decode-der.c b/src/util-decode-der.c index 05c4671ad853..67e7b0dda973 100644 --- a/src/util-decode-der.c +++ b/src/util-decode-der.c @@ -742,6 +742,9 @@ Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *er Asn1Generic *cert; uint8_t c; + if (size < 2) + return NULL; + /* Check that buffer is an ASN.1 structure (basic checks) */ if (d_ptr[0] != 0x30 && d_ptr[1] != 0x82) /* Sequence */ return NULL; From f9ac42b36f0dab7cf9325202425f20ef4ca0ebfe Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 31 Mar 2016 16:15:26 +0200 Subject: [PATCH 1129/2553] util-decode-der: fix NULL dereference bug Make sure that the length is not longer than the size of the buffer provided. --- src/util-decode-der.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util-decode-der.c b/src/util-decode-der.c index 67e7b0dda973..040e214b405c 100644 --- a/src/util-decode-der.c +++ b/src/util-decode-der.c @@ -216,6 +216,12 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t * sequence parsing will fail */ child->length += (d_ptr - save_d_ptr); + + if (child->length > max_size - (d_ptr - buffer)) { + SCFree(child); + return NULL; + } + break; }; if (child == NULL) From 71a3c4caac22b475c09ee2f082f11d443dc02cc0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 4 Apr 2016 12:15:12 +0200 Subject: [PATCH 1130/2553] Update Changelog for 3.0.1 --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index ea4ab4deac43..517d742370c2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +3.0.1 -- 2016-04-04 + +Feature #1704: hyperscan mpm integration +Feature #1661: Improved support for xbits/hostbits (in particular ip_pair) when running with multiple threads +Bug #1697: byte_extract incompatibility with Snort. +Bug #1737: Stats not reset between PCAPs when Suricata runs in socket mode + 3.0.1RC1 -- 2016-03-23 Feature #1535: Expose the certificate itself in TLS-lua From 3781b00dbcc4d8694886e82fef07b24e0e9567b7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 4 Apr 2016 18:04:32 +0200 Subject: [PATCH 1131/2553] Open Suricata 3.1 development branch --- configure.ac | 2 +- src/suricata.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 2b05189718da..5c5f1618ea74 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ - AC_INIT(suricata, 3.0dev) + AC_INIT(suricata, 3.1dev) m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([src/suricata.c]) diff --git a/src/suricata.h b/src/suricata.h index 4ecab38c86a6..8f3413ca3702 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -71,7 +71,7 @@ /* the name of our binary */ #define PROG_NAME "Suricata" -#define PROG_VER "3.0dev" +#define PROG_VER "3.1dev" /* workaround SPlint error (don't know __gnuc_va_list) */ #ifdef S_SPLINT_S From 887ddf1ed89f6d22080bce7b9a99c2c7deeb554e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 19 Sep 2015 22:59:03 +0200 Subject: [PATCH 1132/2553] mpm: introduce ac-ks Introduce 'ac-ks' or the Kenneth Steele AC implementation. It's actually 'ac-tile' written by Ken for the Tilera platform. This patch adds support for it on other architectures as well. Enable ac-tile for other archs as 'ac-ks'. Fix a bunch of OOB reads in the loops that triggered ASAN. --- src/util-mpm-ac-tile-small.c | 9 +++++--- src/util-mpm-ac-tile.c | 42 ++++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/util-mpm-ac-tile-small.c b/src/util-mpm-ac-tile-small.c index a99da0634e6e..fd937f4a6bbe 100644 --- a/src/util-mpm-ac-tile-small.c +++ b/src/util-mpm-ac-tile-small.c @@ -45,12 +45,12 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, STYPE state = 0; int c = xlate[buf[0]]; /* If buflen at least 4 bytes and buf 4-byte aligned. */ - if (buflen >= 4 && ((uint64_t)buf & 0x3) == 0) { + if (buflen >= (4 + EXTRA) && ((uint64_t)buf & 0x3) == 0) { BTYPE data = *(BTYPE* restrict)(&buf[0]); uint64_t index = 0; /* Process 4*floor(buflen/4) bytes. */ i = 0; - while (i < (buflen & ~0x3)) { + while ((i + EXTRA) < (buflen & ~0x3)) { BTYPE data1 = *(BTYPE* restrict)(&buf[i + 4]); index = SINDEX(index, state); state = SLOAD(state_table + index + c); @@ -88,7 +88,10 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, uint64_t index = 0 ; index = SINDEX(index, state); state = SLOAD(state_table + index + c); - c = xlate[buf[i+1]]; +#ifndef __tile__ + if (likely(i+1 < buflen)) +#endif + c = xlate[buf[i+1]]; if (unlikely(SCHECK(state))) { matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index f3a52d6e56cd..1fb43e9d59ce 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -80,15 +80,6 @@ #include "util-memcpy.h" #include "util-mpm-ac-tile.h" -#ifndef __tile__ -void MpmACTileRegister(void) -{ -} -#endif - -/* There are Tilera Tile-Gx specific optimizations in this code. */ -#ifdef __tile__ - void SCACTileInitCtx(MpmCtx *); void SCACTileInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void SCACTileDestroyCtx(MpmCtx *); @@ -1050,7 +1041,7 @@ static void SCACTileClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx) mpm_ctx->memory_cnt++; mpm_ctx->memory_size += size; - SCLogInfo("Delta Table size %d, alphabet: %d, %d-byte states: %d", + SCLogDebug("Delta Table size %d, alphabet: %d, %d-byte states: %d", size, ctx->alphabet_size, ctx->bytes_per_state, ctx->state_count); /* Copy next state from Goto table, which is 32 bits and encode it into the next @@ -1460,10 +1451,19 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) #define SCHECK(x) ((x) > 0) #define BTYPE int32_t // Extract byte N=0,1,2,3 from x +#ifdef __tile__ #define BYTE0(x) __insn_bfextu(x, 0, 7) #define BYTE1(x) __insn_bfextu(x, 8, 15) #define BYTE2(x) __insn_bfextu(x, 16, 23) #define BYTE3(x) __insn_bfextu(x, 24, 31) +#define EXTRA 0 +#else /* fallback */ +#define BYTE0(x) (((x) & 0x000000ff) >> 0) +#define BYTE1(x) (((x) & 0x0000ff00) >> 8) +#define BYTE2(x) (((x) & 0x00ff0000) >> 16) +#define BYTE3(x) (((x) & 0xff000000) >> 24) +#define EXTRA 4 // need 4 extra bytes to avoid OOB reads +#endif int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen, @@ -1494,7 +1494,11 @@ int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, /* Double check case-sensitve match now. */ if (patterns[k] >> 31) { uint16_t patlen = pattern_list[pindex].patlen; +#ifdef __tile__ if (SCMemcmpNZ(pattern_list[pindex].cs, buf_offset - patlen, patlen) != 0) { +#else + if (SCMemcmp(pattern_list[pindex].cs, buf_offset - patlen, patlen) != 0) { +#endif /* Case-sensitive match failed. */ continue; } @@ -1571,13 +1575,22 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct * Next state entry has MSB as "match" and 15 LSB bits as next-state index. */ // y = 1< Date: Fri, 9 Oct 2015 16:21:17 +0200 Subject: [PATCH 1133/2553] ac-ks: fix mem leaks --- src/util-mpm-ac-tile.c | 31 +++++++++++++++++++++++++++++-- src/util-mpm-ac-tile.h | 5 +++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 1fb43e9d59ce..025335d3ef88 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -305,6 +305,12 @@ static void SCACTileFreePattern(MpmCtx *mpm_ctx, SCACTilePattern *p) mpm_ctx->memory_size -= p->len; } + if (p != NULL && p->sids != NULL) { + SCFree(p->sids); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (p->sids_size * sizeof(SigIntId)); + } + if (p != NULL) { SCFree(p); mpm_ctx->memory_cnt--; @@ -1165,9 +1171,11 @@ static void SCACTilePrepareSearch(MpmCtx *mpm_ctx) /* TODO: Could be made more compact */ search_ctx->output_table = ctx->output_table; ctx->output_table = NULL; + search_ctx->state_count = ctx->state_count; search_ctx->pattern_list = ctx->pattern_list; ctx->pattern_list = NULL; + search_ctx->pattern_cnt = mpm_ctx->pattern_cnt; /* One bit per pattern, rounded up to the next byte size. */ search_ctx->mpm_bitarray_size = (mpm_ctx->pattern_cnt + 7) / 8; @@ -1260,6 +1268,8 @@ int SCACTilePreparePatterns(MpmCtx *mpm_ctx) /* ACPatternList now owns this memory */ ctx->pattern_list[i].sids_size = ctx->parray[i]->sids_size; ctx->pattern_list[i].sids = ctx->parray[i]->sids; + ctx->parray[i]->sids = NULL; + ctx->parray[i]->sids_size = 0; } /* prepare the state table required by AC */ @@ -1434,8 +1444,25 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) /* Free Search tables */ SCFree(search_ctx->state_table); - SCFree(search_ctx->pattern_list); - SCFree(search_ctx->output_table); + + if (search_ctx->pattern_list != NULL) { + uint32_t i; + for (i = 0; i < search_ctx->pattern_cnt; i++) { + if (search_ctx->pattern_list[i].sids != NULL) + SCFree(search_ctx->pattern_list[i].sids); + } + SCFree(search_ctx->pattern_list); + } + + if (search_ctx->output_table != NULL) { + uint32_t state; + for (state = 0; state < search_ctx->state_count; state++) { + if (search_ctx->output_table[state].patterns != NULL) { + SCFree(search_ctx->output_table[state].patterns); + } + } + SCFree(search_ctx->output_table); + } SCFree(search_ctx); mpm_ctx->ctx = NULL; diff --git a/src/util-mpm-ac-tile.h b/src/util-mpm-ac-tile.h index 63d5bc95eff9..a0d785714719 100644 --- a/src/util-mpm-ac-tile.h +++ b/src/util-mpm-ac-tile.h @@ -156,6 +156,11 @@ typedef struct SCACTileSearchCtx_ { /* Number of bytes in the array of bits. One bit per pattern in this MPM. */ uint32_t mpm_bitarray_size; + /* Number of states used by ac-tile */ + uint32_t state_count; + + uint32_t pattern_cnt; + /* MPM Creation data, only used at initialization. */ SCACTileCtx *init_ctx; From 0987fd16dce9a05d7f2b0fc61df4ad687368dc60 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 08:47:37 +0200 Subject: [PATCH 1134/2553] ac-ks: 32bit fixes --- src/util-mpm-ac-tile-small.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-mpm-ac-tile-small.c b/src/util-mpm-ac-tile-small.c index fd937f4a6bbe..e271dc96dbd7 100644 --- a/src/util-mpm-ac-tile-small.c +++ b/src/util-mpm-ac-tile-small.c @@ -45,7 +45,7 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, STYPE state = 0; int c = xlate[buf[0]]; /* If buflen at least 4 bytes and buf 4-byte aligned. */ - if (buflen >= (4 + EXTRA) && ((uint64_t)buf & 0x3) == 0) { + if (buflen >= (4 + EXTRA) && ((uintptr_t)buf & 0x3) == 0) { BTYPE data = *(BTYPE* restrict)(&buf[0]); uint64_t index = 0; /* Process 4*floor(buflen/4) bytes. */ @@ -85,7 +85,7 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, } /* Process buflen % 4 bytes. */ for (; i < buflen; i++) { - uint64_t index = 0 ; + size_t index = 0 ; index = SINDEX(index, state); state = SLOAD(state_table + index + c); #ifndef __tile__ From 58e533858bff2146ac07a2491314ef36e899961f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 20 Sep 2015 10:17:17 +0200 Subject: [PATCH 1135/2553] detect mpm: ac-tile/ac-ks default to single Use sgh-mpm-context single is it is set to 'auto' when ac-ks is used. --- src/detect-engine.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 3d0b4b52d61d..58478eb45f22 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1072,6 +1072,7 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) #ifdef BUILD_HYPERSCAN de_ctx->mpm_matcher == MPM_HS || #endif + de_ctx->mpm_matcher == MPM_AC_TILE || #ifdef __SC_CUDA_SUPPORT__ de_ctx->mpm_matcher == MPM_AC_BS || de_ctx->mpm_matcher == MPM_AC_CUDA) { #else From 262abbb49f579073ff5288dca104a5c3dab486f2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 12:49:06 +0200 Subject: [PATCH 1136/2553] mpm: fix ac-ks compilation on cygwin --- src/util-mpm-ac-tile-small.c | 4 ++-- src/util-mpm-ac-tile.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util-mpm-ac-tile-small.c b/src/util-mpm-ac-tile-small.c index e271dc96dbd7..d37d982e0113 100644 --- a/src/util-mpm-ac-tile-small.c +++ b/src/util-mpm-ac-tile-small.c @@ -46,12 +46,12 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, int c = xlate[buf[0]]; /* If buflen at least 4 bytes and buf 4-byte aligned. */ if (buflen >= (4 + EXTRA) && ((uintptr_t)buf & 0x3) == 0) { - BTYPE data = *(BTYPE* restrict)(&buf[0]); + BUF_TYPE data = *(BUF_TYPE* restrict)(&buf[0]); uint64_t index = 0; /* Process 4*floor(buflen/4) bytes. */ i = 0; while ((i + EXTRA) < (buflen & ~0x3)) { - BTYPE data1 = *(BTYPE* restrict)(&buf[i + 4]); + BUF_TYPE data1 = *(BUF_TYPE* restrict)(&buf[i + 4]); index = SINDEX(index, state); state = SLOAD(state_table + index + c); c = xlate[BYTE1(data)]; diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 025335d3ef88..747a24fc8867 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -1476,7 +1476,7 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) */ #define SCHECK(x) ((x) > 0) -#define BTYPE int32_t +#define BUF_TYPE int32_t // Extract byte N=0,1,2,3 from x #ifdef __tile__ #define BYTE0(x) __insn_bfextu(x, 0, 7) From 4f8e1f59a6c3d76f49863ddaafb97e04bfecc092 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 20 Oct 2015 10:19:40 +0200 Subject: [PATCH 1137/2553] mpm: remove obsolete mpm algos Remove: ac-gfbs, wumanber, b2g, b3g. --- src/Makefile.am | 4 - src/app-layer-detect-proto.c | 5 - src/detect-ack.c | 31 +- src/detect-content.c | 4 +- src/detect-distance.c | 1 - src/detect-engine-hrl.c | 38 - src/detect-engine-hrud.c | 2 - src/detect-engine-payload.c | 44 +- src/detect-engine-uri.c | 38 - src/detect-engine.c | 3 +- src/detect-fast-pattern.c | 1 - src/detect-parse.c | 2 - src/detect-pcre.c | 58 +- src/detect-sameip.c | 31 +- src/detect-uricontent.c | 5 - src/detect.c | 777 +------- src/util-mpm-ac-gfbs.c | 2722 ---------------------------- src/util-mpm-ac-gfbs.h | 110 -- src/util-mpm-b2g.c | 2832 ------------------------------ src/util-mpm-b2g.h | 127 -- src/util-mpm-b3g.c | 1807 ------------------- src/util-mpm-b3g.h | 130 -- src/util-mpm-wumanber.c | 3219 ---------------------------------- src/util-mpm-wumanber.h | 97 - src/util-mpm.c | 101 -- src/util-mpm.h | 41 - suricata.yaml.in | 29 - 27 files changed, 114 insertions(+), 12145 deletions(-) delete mode 100644 src/util-mpm-ac-gfbs.c delete mode 100644 src/util-mpm-ac-gfbs.h delete mode 100644 src/util-mpm-b2g.c delete mode 100644 src/util-mpm-b2g.h delete mode 100644 src/util-mpm-b3g.c delete mode 100644 src/util-mpm-b3g.h delete mode 100644 src/util-mpm-wumanber.c delete mode 100644 src/util-mpm-wumanber.h diff --git a/src/Makefile.am b/src/Makefile.am index aed9022e1a58..ec936181d2ac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -367,14 +367,10 @@ util-memrchr.c util-memrchr.h \ util-misc.c util-misc.h \ util-mpm-ac-bs.c util-mpm-ac-bs.h \ util-mpm-ac.c util-mpm-ac.h \ -util-mpm-ac-gfbs.c util-mpm-ac-gfbs.h \ util-mpm-ac-tile.c util-mpm-ac-tile.h \ util-mpm-ac-tile-small.c \ -util-mpm-b2g.c util-mpm-b2g.h \ -util-mpm-b3g.c util-mpm-b3g.h \ util-mpm-hs.c util-mpm-hs.h \ util-mpm.c util-mpm.h \ -util-mpm-wumanber.c util-mpm-wumanber.h \ util-optimize.h \ util-path.c util-path.h \ util-pidfile.c util-pidfile.h \ diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 221b50ffc801..da0de27f9454 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -3315,7 +3315,6 @@ static int AppLayerProtoDetectTest16(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " @@ -3409,7 +3408,6 @@ static int AppLayerProtoDetectTest17(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any " @@ -3505,7 +3503,6 @@ static int AppLayerProtoDetectTest18(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ftp any any -> any any " @@ -3597,7 +3594,6 @@ static int AppLayerProtoDetectTest19(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any " @@ -3700,7 +3696,6 @@ static int AppLayerProtoDetectTest20(void) ssn.toserver_smsg_head = stream_msg; ssn.toserver_smsg_tail = stream_msg; - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " diff --git a/src/detect-ack.c b/src/detect-ack.c index 5a84c6f9f94d..cb2bbc0858d9 100644 --- a/src/detect-ack.c +++ b/src/detect-ack.c @@ -146,7 +146,7 @@ static void DetectAckFree(void *ptr) * \internal * \brief This test tests sameip success and failure. */ -static int DetectAckSigTest01Real(int mpm_type) +static int DetectAckSigTest01(void) { Packet *p1 = NULL; Packet *p2 = NULL; @@ -173,7 +173,6 @@ static int DetectAckSigTest01Real(int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; /* These three are crammed in here as there is no Parse */ @@ -261,30 +260,6 @@ static int DetectAckSigTest01Real(int mpm_type) return result; } -/** - * \test DetectAckSigTest01B2g tests sameip under B2g MPM - */ -static int DetectAckSigTest01B2g(void) -{ - return DetectAckSigTest01Real(MPM_B2G); -} - -/** - * \test DetectAckSigTest01B2g tests sameip under B3g MPM - */ -static int DetectAckSigTest01B3g(void) -{ - return DetectAckSigTest01Real(MPM_B3G); -} - -/** - * \test DetectAckSigTest01B2g tests sameip under WuManber MPM - */ -static int DetectAckSigTest01Wm(void) -{ - return DetectAckSigTest01Real(MPM_WUMANBER); -} - #endif /* UNITTESTS */ /** @@ -294,9 +269,7 @@ static int DetectAckSigTest01Wm(void) static void DetectAckRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectAckSigTest01B2g", DetectAckSigTest01B2g, 1); - UtRegisterTest("DetectAckSigTest01B3g", DetectAckSigTest01B3g, 1); - UtRegisterTest("DetectAckSigTest01Wm", DetectAckSigTest01Wm, 1); + UtRegisterTest("DetectAckSigTest01", DetectAckSigTest01, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-content.c b/src/detect-content.c index 3130c86ceb8c..e49efd5728e5 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -2557,7 +2557,7 @@ static int SigTest76TestBug134(void) char sig[] = "alert tcp any any -> any 515 " "(msg:\"detect IFS\"; flow:to_server,established; content:\"${IFS}\";" " depth:50; offset:0; sid:900091; rev:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } @@ -2584,7 +2584,7 @@ static int SigTest77TestBug139(void) char sig[] = "alert udp any any -> any 53 (msg:\"dns testing\";" " content:\"|00 00|\"; depth:5; offset:13; sid:9436601;" " rev:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } diff --git a/src/detect-distance.c b/src/detect-distance.c index 33b32787f773..60a2ff517e4d 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -189,7 +189,6 @@ static int DetectDistanceTest01(void) goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (content:\"|AA BB|\"; content:\"|CC DD EE FF 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE|\"; distance: 4; within: 19; sid:1; rev:1;)"); diff --git a/src/detect-engine-hrl.c b/src/detect-engine-hrl.c index 5e5c0cb6214a..555b5af3720c 100644 --- a/src/detect-engine-hrl.c +++ b/src/detect-engine-hrl.c @@ -149,7 +149,6 @@ static int UriTestSig01(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -272,7 +271,6 @@ static int UriTestSig02(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -395,7 +393,6 @@ static int UriTestSig03(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -518,7 +515,6 @@ static int UriTestSig04(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -641,7 +637,6 @@ static int UriTestSig05(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -764,7 +759,6 @@ static int UriTestSig06(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -887,7 +881,6 @@ static int UriTestSig07(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1010,7 +1003,6 @@ static int UriTestSig08(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1133,7 +1125,6 @@ static int UriTestSig09(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1256,7 +1247,6 @@ static int UriTestSig10(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1379,7 +1369,6 @@ static int UriTestSig11(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1503,7 +1492,6 @@ static int UriTestSig12(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1627,7 +1615,6 @@ static int UriTestSig13(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1751,7 +1738,6 @@ static int UriTestSig14(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1875,7 +1861,6 @@ static int UriTestSig15(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1999,7 +1984,6 @@ static int UriTestSig16(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any (msg:\"ET TROJAN Downadup/Conficker A or B Worm reporting\"; flow:to_server,established; uricontent:\"/search?q=\"; pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; sid:2009024; rev:9;)"); @@ -2119,7 +2103,6 @@ static int UriTestSig17(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2215,7 +2198,6 @@ static int UriTestSig18(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2311,7 +2293,6 @@ static int UriTestSig19(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2408,7 +2389,6 @@ static int UriTestSig20(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2504,7 +2484,6 @@ static int UriTestSig21(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2600,7 +2579,6 @@ static int UriTestSig22(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2694,7 +2672,6 @@ static int UriTestSig23(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2788,7 +2765,6 @@ static int UriTestSig24(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2882,7 +2858,6 @@ static int UriTestSig25(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2976,7 +2951,6 @@ static int UriTestSig26(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3070,7 +3044,6 @@ static int UriTestSig27(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3196,7 +3169,6 @@ static int UriTestSig28(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3289,7 +3261,6 @@ static int UriTestSig29(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3382,7 +3353,6 @@ static int UriTestSig30(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3475,7 +3445,6 @@ static int UriTestSig31(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3568,7 +3537,6 @@ static int UriTestSig32(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3661,7 +3629,6 @@ static int UriTestSig33(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3752,7 +3719,6 @@ static int UriTestSig34(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3843,7 +3809,6 @@ static int UriTestSig35(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3934,7 +3899,6 @@ static int UriTestSig36(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -4025,7 +3989,6 @@ static int UriTestSig37(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -4116,7 +4079,6 @@ static int UriTestSig38(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index c715c0292683..585c736b6db8 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -3503,7 +3503,6 @@ static int DetectEngineHttpRawUriTest29(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3598,7 +3597,6 @@ static int DetectEngineHttpRawUriTest30(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index af0d9c3e3d2f..9b21085de40c 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -137,7 +137,7 @@ static int PayloadTestSig01 (void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"abc\"; content:\"d\"; distance:0; within:1; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -159,7 +159,7 @@ static int PayloadTestSig02 (void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"abc\"; nocase; content:\"d\"; distance:0; within:1; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -181,7 +181,7 @@ static int PayloadTestSig03 (void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"aBc\"; nocase; content:\"abca\"; distance:-10; within:4; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -206,7 +206,7 @@ static int PayloadTestSig04(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"this\"; content:\"is\"; within:6; content:\"big\"; within:8; " "content:\"string\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -231,7 +231,7 @@ static int PayloadTestSig05(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"this\"; content:\"is\"; within:9; content:\"big\"; within:12; " "content:\"string\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -256,7 +256,7 @@ static int PayloadTestSig06(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"now\"; content:\"this\"; content:\"is\"; within:12; content:\"big\"; within:8; " "content:\"string\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -281,7 +281,7 @@ static int PayloadTestSig07(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"thus\"; offset:8; content:\"is\"; within:6; content:\"big\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -307,7 +307,7 @@ static int PayloadTestSig08(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"fix\"; content:\"this\"; within:6; content:!\"and\"; distance:0; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) != 1) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) != 1) { goto end; } @@ -331,7 +331,7 @@ static int PayloadTestSig09(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "pcre:/super/; content:\"nova\"; within:7; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -356,7 +356,7 @@ static int PayloadTestSig10(void) char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "byte_test:4,>,2,0,relative; sid:11;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 1) { result = 0; goto end; } @@ -381,7 +381,7 @@ static int PayloadTestSig11(void) char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "byte_jump:1,0,relative; sid:11;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 1) { result = 0; goto end; } @@ -406,7 +406,7 @@ static int PayloadTestSig12(void) char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "isdataat:10,relative; sid:11;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 1) { result = 0; goto end; } @@ -446,7 +446,7 @@ static int PayloadTestSig13(void) uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; - uint16_t mpm_type = MPM_B2G; + uint16_t mpm_type = DEFAULT_MPM; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"aa\"; content:\"aa\"; distance:0; content:\"aa\"; distance:0; " @@ -528,7 +528,7 @@ static int PayloadTestSig14(void) //char sig[] = "alert tcp any any -> any any (content:\"User-Agent: Mozilla/5.0 (Macintosh; \"; content:\"Firefox/3.\"; distance:0; content:!\"Firefox/3.6.12\"; distance:-10; content:!\"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b4) Gecko/20090423 Firefox/3.6 GTB5\"; sid:1; rev:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 1) { goto end; } @@ -549,7 +549,7 @@ static int PayloadTestSig15(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; isdataat:18,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -572,7 +572,7 @@ static int PayloadTestSig16(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; isdataat:!20,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -596,7 +596,7 @@ static int PayloadTestSig17(void) "content:\"%\"; depth:4; offset:0; " "content:\"%\"; within:2; distance:1; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -964,7 +964,7 @@ static int PayloadTestSig30(void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"one\"; pcre:\"/^two/R\"; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -985,7 +985,7 @@ static int PayloadTestSig31(void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"one\"; pcre:\"/(fiv|^two)/R\"; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { result = 0; goto end; } @@ -1010,7 +1010,7 @@ static int PayloadTestSig32(void) char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_jump:2,-14,string,dec,relative; content:\"card\"; within:4; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) goto end; result = 1; @@ -1033,7 +1033,7 @@ static int PayloadTestSig33(void) char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_test:1,=,2,-14,string,dec,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) goto end; result = 1; @@ -1056,7 +1056,7 @@ static int PayloadTestSig34(void) char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_extract:1,-14,boom,string,dec,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) + if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) goto end; result = 1; diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index cd737157843f..500272150e1c 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -150,7 +150,6 @@ static int UriTestSig01(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -273,7 +272,6 @@ static int UriTestSig02(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -396,7 +394,6 @@ static int UriTestSig03(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -519,7 +516,6 @@ static int UriTestSig04(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -642,7 +638,6 @@ static int UriTestSig05(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -765,7 +760,6 @@ static int UriTestSig06(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -888,7 +882,6 @@ static int UriTestSig07(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1011,7 +1004,6 @@ static int UriTestSig08(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1134,7 +1126,6 @@ static int UriTestSig09(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1257,7 +1248,6 @@ static int UriTestSig10(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1380,7 +1370,6 @@ static int UriTestSig11(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1504,7 +1493,6 @@ static int UriTestSig12(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1628,7 +1616,6 @@ static int UriTestSig13(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1752,7 +1739,6 @@ static int UriTestSig14(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1876,7 +1862,6 @@ static int UriTestSig15(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2000,7 +1985,6 @@ static int UriTestSig16(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any (msg:\"ET TROJAN Downadup/Conficker A or B Worm reporting\"; flow:to_server,established; uricontent:\"/search?q=\"; pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; sid:2009024; rev:9;)"); @@ -2120,7 +2104,6 @@ static int UriTestSig17(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2216,7 +2199,6 @@ static int UriTestSig18(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2312,7 +2294,6 @@ static int UriTestSig19(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2409,7 +2390,6 @@ static int UriTestSig20(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2505,7 +2485,6 @@ static int UriTestSig21(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2601,7 +2580,6 @@ static int UriTestSig22(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2695,7 +2673,6 @@ static int UriTestSig23(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2789,7 +2766,6 @@ static int UriTestSig24(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2883,7 +2859,6 @@ static int UriTestSig25(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2977,7 +2952,6 @@ static int UriTestSig26(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3071,7 +3045,6 @@ static int UriTestSig27(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3197,7 +3170,6 @@ static int UriTestSig28(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3290,7 +3262,6 @@ static int UriTestSig29(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3383,7 +3354,6 @@ static int UriTestSig30(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3476,7 +3446,6 @@ static int UriTestSig31(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3569,7 +3538,6 @@ static int UriTestSig32(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3662,7 +3630,6 @@ static int UriTestSig33(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3753,7 +3720,6 @@ static int UriTestSig34(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3844,7 +3810,6 @@ static int UriTestSig35(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3935,7 +3900,6 @@ static int UriTestSig36(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -4026,7 +3990,6 @@ static int UriTestSig37(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -4117,7 +4080,6 @@ static int UriTestSig38(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " diff --git a/src/detect-engine.c b/src/detect-engine.c index 58478eb45f22..6ffbf7125a0f 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1068,11 +1068,10 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) if (sgh_mpm_context == NULL || strcmp(sgh_mpm_context, "auto") == 0) { /* for now, since we still haven't implemented any intelligence into * understanding the patterns and distributing mpm_ctx across sgh */ - if (de_ctx->mpm_matcher == DEFAULT_MPM || de_ctx->mpm_matcher == MPM_AC_GFBS || + if (de_ctx->mpm_matcher == DEFAULT_MPM || de_ctx->mpm_matcher == MPM_AC_TILE || #ifdef BUILD_HYPERSCAN de_ctx->mpm_matcher == MPM_HS || #endif - de_ctx->mpm_matcher == MPM_AC_TILE || #ifdef __SC_CUDA_SUPPORT__ de_ctx->mpm_matcher == MPM_AC_BS || de_ctx->mpm_matcher == MPM_AC_CUDA) { #else diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 01b8f398e8d5..27598ee458b1 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -1038,7 +1038,6 @@ int DetectFastPatternTest14(void) FlowInitConfig(FLOW_QUIET); - de_ctx->mpm_matcher = MPM_B3G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " diff --git a/src/detect-parse.c b/src/detect-parse.c index 54035d2e090c..e499b483c7ce 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -2987,7 +2987,6 @@ int SigTestBidirec04 (void) with source 192.168.1.1 80, all the sids should match */ SigGroupBuild(de_ctx); - //PatternMatchPrepare(mpm_ctx, MPM_B2G); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */ @@ -3000,7 +2999,6 @@ int SigTestBidirec04 (void) PACKET_RECYCLE(p); } FlowShutdown(); - //PatternMatchDestroy(mpm_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 563a6d884471..6184cc658bdb 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -1698,7 +1698,7 @@ static int DetectPcreParseTest27(void) return result; } -static int DetectPcreTestSig01Real(int mpm_type) +static int DetectPcreTestSig01(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" @@ -1739,7 +1739,6 @@ static int DetectPcreTestSig01Real(int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/^gEt/i\"; pcre:\"/\\/two\\//U; pcre:\"/GET \\/two\\//\"; pcre:\"/\\s+HTTP/R\"; sid:1;)"); @@ -1781,20 +1780,8 @@ static int DetectPcreTestSig01Real(int mpm_type) UTHFreePackets(&p, 1); return result; } -static int DetectPcreTestSig01B2g (void) -{ - return DetectPcreTestSig01Real(MPM_B2G); -} -static int DetectPcreTestSig01B3g (void) -{ - return DetectPcreTestSig01Real(MPM_B3G); -} -static int DetectPcreTestSig01Wm (void) -{ - return DetectPcreTestSig01Real(MPM_WUMANBER); -} -static int DetectPcreTestSig02Real(int mpm_type) +static int DetectPcreTestSig02(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" @@ -1827,7 +1814,6 @@ static int DetectPcreTestSig02Real(int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/two/O\"; sid:2;)"); @@ -1854,23 +1840,11 @@ static int DetectPcreTestSig02Real(int mpm_type) UTHFreePackets(&p, 1); return result; } -static int DetectPcreTestSig02B2g (void) -{ - return DetectPcreTestSig02Real(MPM_B2G); -} -static int DetectPcreTestSig02B3g (void) -{ - return DetectPcreTestSig02Real(MPM_B3G); -} -static int DetectPcreTestSig02Wm (void) -{ - return DetectPcreTestSig02Real(MPM_WUMANBER); -} /** * \test DetectPcreTestSig03Real negation test ! outside of "" this sig should not match */ -static int DetectPcreTestSig03Real(int mpm_type) +static int DetectPcreTestSig03(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" @@ -1895,7 +1869,6 @@ static int DetectPcreTestSig03Real(int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"GET\"; pcre:!\"/two/\"; sid:1;)"); @@ -1922,19 +1895,6 @@ static int DetectPcreTestSig03Real(int mpm_type) return result; } -static int DetectPcreTestSig03B2g (void) -{ - return DetectPcreTestSig03Real(MPM_B2G); -} -static int DetectPcreTestSig03B3g (void) -{ - return DetectPcreTestSig03Real(MPM_B3G); -} -static int DetectPcreTestSig03Wm (void) -{ - return DetectPcreTestSig03Real(MPM_WUMANBER); -} - /** * \test Check the signature with pcre modifier P (match with L7 to http body data) */ @@ -4161,15 +4121,9 @@ void DetectPcreRegisterTests(void) UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26, 1); UtRegisterTest("DetectPcreParseTest27", DetectPcreParseTest27, 1); - UtRegisterTest("DetectPcreTestSig01B2g -- pcre test", DetectPcreTestSig01B2g, 1); - UtRegisterTest("DetectPcreTestSig01B3g -- pcre test", DetectPcreTestSig01B3g, 1); - UtRegisterTest("DetectPcreTestSig01Wm -- pcre test", DetectPcreTestSig01Wm, 1); - UtRegisterTest("DetectPcreTestSig02B2g -- pcre test", DetectPcreTestSig02B2g, 1); - UtRegisterTest("DetectPcreTestSig02B3g -- pcre test", DetectPcreTestSig02B3g, 1); - UtRegisterTest("DetectPcreTestSig02Wm -- pcre test", DetectPcreTestSig02Wm, 1); - UtRegisterTest("DetectPcreTestSig03B2g -- negated pcre test", DetectPcreTestSig03B2g, 1); - UtRegisterTest("DetectPcreTestSig03B3g -- negated pcre test", DetectPcreTestSig03B3g, 1); - UtRegisterTest("DetectPcreTestSig03Wm -- negated pcre test", DetectPcreTestSig03Wm, 1); + UtRegisterTest("DetectPcreTestSig01 -- pcre test", DetectPcreTestSig01, 1); + UtRegisterTest("DetectPcreTestSig02 -- pcre test", DetectPcreTestSig02, 1); + UtRegisterTest("DetectPcreTestSig03 -- negated pcre test", DetectPcreTestSig03, 1); UtRegisterTest("DetectPcreModifPTest04 -- Modifier P", DetectPcreModifPTest04, 1); UtRegisterTest("DetectPcreModifPTest05 -- Modifier P fragmented", DetectPcreModifPTest05, 1); diff --git a/src/detect-sameip.c b/src/detect-sameip.c index a8e02908b9ed..dd18b16486d9 100644 --- a/src/detect-sameip.c +++ b/src/detect-sameip.c @@ -119,7 +119,7 @@ static int DetectSameipSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr * \internal * \brief This test tests sameip success and failure. */ -static int DetectSameipSigTest01Real(int mpm_type) +static int DetectSameipSigTest01(void) { uint8_t *buf = (uint8_t *) "GET / HTTP/1.0\r\n" @@ -144,7 +144,6 @@ static int DetectSameipSigTest01Real(int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -182,30 +181,6 @@ static int DetectSameipSigTest01Real(int mpm_type) return result; } -/** - * \test DetectSameipSigTest01B2g tests sameip under B2g MPM - */ -static int DetectSameipSigTest01B2g(void) -{ - return DetectSameipSigTest01Real(MPM_B2G); -} - -/** - * \test DetectSameipSigTest01B2g tests sameip under B3g MPM - */ -static int DetectSameipSigTest01B3g(void) -{ - return DetectSameipSigTest01Real(MPM_B3G); -} - -/** - * \test DetectSameipSigTest01B2g tests sameip under WuManber MPM - */ -static int DetectSameipSigTest01Wm(void) -{ - return DetectSameipSigTest01Real(MPM_WUMANBER); -} - #endif /* UNITTESTS */ /** @@ -215,8 +190,6 @@ static int DetectSameipSigTest01Wm(void) static void DetectSameipRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectSameipSigTest01B2g", DetectSameipSigTest01B2g, 1); - UtRegisterTest("DetectSameipSigTest01B3g", DetectSameipSigTest01B3g, 1); - UtRegisterTest("DetectSameipSigTest01Wm", DetectSameipSigTest01Wm, 1); + UtRegisterTest("DetectSameipSigTest01", DetectSameipSigTest01, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index 65d2ef9443fb..50df51c3f98e 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -635,7 +635,6 @@ static int DetectUriSigTest02(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" @@ -751,7 +750,6 @@ static int DetectUriSigTest03(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" @@ -1106,7 +1104,6 @@ static int DetectUriSigTest05(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" @@ -1235,7 +1232,6 @@ static int DetectUriSigTest06(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" @@ -1358,7 +1354,6 @@ static int DetectUriSigTest07(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" diff --git a/src/detect.c b/src/detect.c index 3626d2e21330..d39ce0b5e531 100644 --- a/src/detect.c +++ b/src/detect.c @@ -5237,7 +5237,7 @@ static const char *dummy_conf_string = " SSH_PORTS: 22\n" "\n"; -static int SigTest01Real (int mpm_type) +static int SigTest01 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" @@ -5251,7 +5251,7 @@ static int SigTest01Real (int mpm_type) int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, mpm_type) == 0) { + if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } @@ -5275,20 +5275,7 @@ static int SigTest01Real (int mpm_type) return result; } -static int SigTest01B2g (void) -{ - return SigTest01Real(MPM_B2G); -} -static int SigTest01B3g (void) -{ - return SigTest01Real(MPM_B3G); -} -static int SigTest01Wm (void) -{ - return SigTest01Real(MPM_WUMANBER); -} - -static int SigTest02Real (int mpm_type) +static int SigTest02 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" @@ -5300,26 +5287,12 @@ static int SigTest02Real (int mpm_type) uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); char sig[] = "alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: one.example.org\"; offset:20; depth:41; sid:1;)"; - int ret = UTHPacketMatchSigMpm(p, sig, mpm_type); + int ret = UTHPacketMatchSigMpm(p, sig, MPM_AC); UTHFreePacket(p); return ret; } -static int SigTest02B2g (void) -{ - return SigTest02Real(MPM_B2G); -} -static int SigTest02B3g (void) -{ - return SigTest02Real(MPM_B3G); -} -static int SigTest02Wm (void) -{ - return SigTest02Real(MPM_WUMANBER); -} - - -static int SigTest03Real (int mpm_type) +static int SigTest03 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" @@ -5343,7 +5316,6 @@ static int SigTest03Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: one.example.org\"; offset:20; depth:39; sid:1;)"); @@ -5353,7 +5325,6 @@ static int SigTest03Real (int mpm_type) } SigGroupBuild(de_ctx); - //PatternMatchPrepare(mpm_ctx, mpm_type); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -5364,27 +5335,13 @@ static int SigTest03Real (int mpm_type) SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } -static int SigTest03B2g (void) -{ - return SigTest03Real(MPM_B2G); -} -static int SigTest03B3g (void) -{ - return SigTest03Real(MPM_B3G); -} -static int SigTest03Wm (void) -{ - return SigTest03Real(MPM_WUMANBER); -} - -static int SigTest04Real (int mpm_type) +static int SigTest04 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" /* 20*/ @@ -5409,7 +5366,6 @@ static int SigTest04Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; offset:20; depth:25; content:\"Host:\"; distance:42; within:47; sid:1;)"); @@ -5434,21 +5390,8 @@ static int SigTest04Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTest04B2g (void) -{ - return SigTest04Real(MPM_B2G); -} -static int SigTest04B3g (void) -{ - return SigTest04Real(MPM_B3G); -} -static int SigTest04Wm (void) -{ - return SigTest04Real(MPM_WUMANBER); -} - -static int SigTest05Real (int mpm_type) +static int SigTest05 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" /* 20 */ @@ -5472,7 +5415,6 @@ static int SigTest05Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; offset:20; depth:25; content:\"Host:\"; distance:48; within:52; sid:1;)"); @@ -5500,21 +5442,8 @@ static int SigTest05Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTest05B2g (void) -{ - return SigTest05Real(MPM_B2G); -} -static int SigTest05B3g (void) -{ - return SigTest05Real(MPM_B3G); -} -static int SigTest05Wm (void) -{ - return SigTest05Real(MPM_WUMANBER); -} - -static int SigTest06Real (int mpm_type) +static int SigTest06 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" /* 20 */ @@ -5555,7 +5484,6 @@ static int SigTest06Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); @@ -5604,21 +5532,8 @@ static int SigTest06Real (int mpm_type) FLOW_DESTROY(&f); return result; } -static int SigTest06B2g (void) -{ - return SigTest06Real(MPM_B2G); -} -static int SigTest06B3g (void) -{ - return SigTest06Real(MPM_B3G); -} -static int SigTest06Wm (void) -{ - return SigTest06Real(MPM_WUMANBER); -} - -static int SigTest07Real (int mpm_type) +static int SigTest07 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" /* 20 */ @@ -5659,7 +5574,6 @@ static int SigTest07Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); @@ -5703,26 +5617,12 @@ static int SigTest07Real (int mpm_type) SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); return result; } -static int SigTest07B2g (void) -{ - return SigTest07Real(MPM_B2G); -} -static int SigTest07B3g (void) -{ - return SigTest07Real(MPM_B3G); -} -static int SigTest07Wm (void) -{ - return SigTest07Real(MPM_WUMANBER); -} - -static int SigTest08Real (int mpm_type) +static int SigTest08 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.0\r\n" /* 20 */ @@ -5763,7 +5663,6 @@ static int SigTest08Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); @@ -5813,21 +5712,8 @@ static int SigTest08Real (int mpm_type) FLOW_DESTROY(&f); return result; } -static int SigTest08B2g (void) -{ - return SigTest08Real(MPM_B2G); -} -static int SigTest08B3g (void) -{ - return SigTest08Real(MPM_B3G); -} -static int SigTest08Wm (void) -{ - return SigTest08Real(MPM_WUMANBER); -} - -static int SigTest09Real (int mpm_type) +static int SigTest09 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.0\r\n" /* 20 */ @@ -5868,7 +5754,6 @@ static int SigTest09Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); @@ -5915,21 +5800,8 @@ static int SigTest09Real (int mpm_type) FLOW_DESTROY(&f); return result; } -static int SigTest09B2g (void) -{ - return SigTest09Real(MPM_B2G); -} -static int SigTest09B3g (void) -{ - return SigTest09Real(MPM_B3G); -} -static int SigTest09Wm (void) -{ - return SigTest09Real(MPM_WUMANBER); -} - -static int SigTest10Real (int mpm_type) +static int SigTest10 (void) { uint8_t *buf = (uint8_t *) "ABC"; @@ -5965,7 +5837,6 @@ static int SigTest10Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Long content test (1)\"; content:\"ABCD\"; depth:4; sid:1;)"); @@ -5982,7 +5853,6 @@ static int SigTest10Real (int mpm_type) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { @@ -6013,21 +5883,8 @@ static int SigTest10Real (int mpm_type) FLOW_DESTROY(&f); return result; } -static int SigTest10B2g (void) -{ - return SigTest10Real(MPM_B2G); -} -static int SigTest10B3g (void) -{ - return SigTest10Real(MPM_B3G); -} -static int SigTest10Wm (void) -{ - return SigTest10Real(MPM_WUMANBER); -} - -static int SigTest11Real (int mpm_type) +static int SigTest11 (void) { uint8_t *buf = (uint8_t *) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; @@ -6061,7 +5918,6 @@ static int SigTest11Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); @@ -6091,21 +5947,8 @@ static int SigTest11Real (int mpm_type) FLOW_DESTROY(&f); return result; } -static int SigTest11B2g (void) -{ - return SigTest11Real(MPM_B2G); -} -static int SigTest11B3g (void) -{ - return SigTest11Real(MPM_B3G); -} -static int SigTest11Wm (void) -{ - return SigTest11Real(MPM_WUMANBER); -} - -static int SigTest12Real (int mpm_type) +static int SigTest12 (void) { uint8_t *buf = (uint8_t *) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; @@ -6130,7 +5973,6 @@ static int SigTest12Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); @@ -6160,21 +6002,8 @@ static int SigTest12Real (int mpm_type) FLOW_DESTROY(&f); return result; } -static int SigTest12B2g (void) -{ - return SigTest12Real(MPM_B2G); -} -static int SigTest12B3g (void) -{ - return SigTest12Real(MPM_B3G); -} -static int SigTest12Wm (void) -{ - return SigTest12Real(MPM_WUMANBER); -} - -static int SigTest13Real (int mpm_type) +static int SigTest13 (void) { uint8_t *buf = (uint8_t *) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; @@ -6199,7 +6028,6 @@ static int SigTest13Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; sid:1;)"); @@ -6226,21 +6054,8 @@ static int SigTest13Real (int mpm_type) FLOW_DESTROY(&f); return result; } -static int SigTest13B2g (void) -{ - return SigTest13Real(MPM_B2G); -} -static int SigTest13B3g (void) -{ - return SigTest13Real(MPM_B3G); -} -static int SigTest13Wm (void) -{ - return SigTest13Real(MPM_WUMANBER); -} - -static int SigTest14Real (int mpm_type) +static int SigTest14 (void) { uint8_t *buf = (uint8_t *) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; @@ -6259,7 +6074,6 @@ static int SigTest14Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; distance:0; sid:1;)"); @@ -6285,21 +6099,8 @@ static int SigTest14Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTest14B2g (void) -{ - return SigTest14Real(MPM_B2G); -} -static int SigTest14B3g (void) -{ - return SigTest14Real(MPM_B3G); -} -static int SigTest14Wm (void) -{ - return SigTest14Real(MPM_WUMANBER); -} - -static int SigTest15Real (int mpm_type) +static int SigTest15 (void) { uint8_t *buf = (uint8_t *) "CONNECT 213.92.8.7:31204 HTTP/1.1"; @@ -6329,8 +6130,6 @@ static int SigTest15Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); @@ -6358,21 +6157,8 @@ static int SigTest15Real (int mpm_type) SCFree(p); return result; } -static int SigTest15B2g (void) -{ - return SigTest15Real(MPM_B2G); -} -static int SigTest15B3g (void) -{ - return SigTest15Real(MPM_B3G); -} -static int SigTest15Wm (void) -{ - return SigTest15Real(MPM_WUMANBER); -} - -static int SigTest16Real (int mpm_type) +static int SigTest16 (void) { uint8_t *buf = (uint8_t *) "CONNECT 213.92.8.7:31204 HTTP/1.1"; @@ -6396,8 +6182,6 @@ static int SigTest16Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); @@ -6423,21 +6207,8 @@ static int SigTest16Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTest16B2g (void) -{ - return SigTest16Real(MPM_B2G); -} -static int SigTest16B3g (void) -{ - return SigTest16Real(MPM_B3G); -} -static int SigTest16Wm (void) -{ - return SigTest16Real(MPM_WUMANBER); -} - -static int SigTest17Real (int mpm_type) +static int SigTest17 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" /* 20 */ @@ -6465,7 +6236,6 @@ static int SigTest17Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any $HTTP_PORTS (msg:\"HTTP host cap\"; content:\"Host:\"; pcre:\"/^Host: (?P.*)\\r\\n/m\"; noalert; sid:1;)"); @@ -6505,20 +6275,8 @@ static int SigTest17Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTest17B2g (void) -{ - return SigTest17Real(MPM_B2G); -} -static int SigTest17B3g (void) -{ - return SigTest17Real(MPM_B3G); -} -static int SigTest17Wm (void) -{ - return SigTest17Real(MPM_WUMANBER); -} -static int SigTest18Real (int mpm_type) +static int SigTest18 (void) { uint8_t *buf = (uint8_t *) "220 (vsFTPd 2.0.5)\r\n"; @@ -6545,8 +6303,6 @@ static int SigTest18Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); @@ -6572,20 +6328,8 @@ static int SigTest18Real (int mpm_type) SCFree(p); return result; } -static int SigTest18B2g (void) -{ - return SigTest18Real(MPM_B2G); -} -static int SigTest18B3g (void) -{ - return SigTest18Real(MPM_B3G); -} -static int SigTest18Wm (void) -{ - return SigTest18Real(MPM_WUMANBER); -} -int SigTest19Real (int mpm_type) +static int SigTest19 (void) { uint8_t *buf = (uint8_t *) "220 (vsFTPd 2.0.5)\r\n"; @@ -6619,7 +6363,6 @@ int SigTest19Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert ip $HOME_NET any -> 1.2.3.4 any (msg:\"IP-ONLY test (1)\"; sid:999; rev:1;)"); @@ -6646,20 +6389,8 @@ int SigTest19Real (int mpm_type) SCFree(p); return result; } -static int SigTest19B2g (void) -{ - return SigTest19Real(MPM_B2G); -} -static int SigTest19B3g (void) -{ - return SigTest19Real(MPM_B3G); -} -static int SigTest19Wm (void) -{ - return SigTest19Real(MPM_WUMANBER); -} -static int SigTest20Real (int mpm_type) +static int SigTest20 (void) { uint8_t *buf = (uint8_t *) "220 (vsFTPd 2.0.5)\r\n"; @@ -6693,7 +6424,6 @@ static int SigTest20Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert ip $HOME_NET any -> [99.99.99.99,1.2.3.0/24,1.1.1.1,3.0.0.0/8] any (msg:\"IP-ONLY test (2)\"; sid:999; rev:1;)"); @@ -6703,9 +6433,7 @@ static int SigTest20Real (int mpm_type) } SigGroupBuild(de_ctx); - //PatternMatchPrepare(mpm_ctx, mpm_type); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - //DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 999)) @@ -6716,7 +6444,6 @@ static int SigTest20Real (int mpm_type) SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); end: ConfDeInit(); @@ -6724,21 +6451,8 @@ static int SigTest20Real (int mpm_type) SCFree(p); return result; } -static int SigTest20B2g (void) -{ - return SigTest20Real(MPM_B2G); -} -static int SigTest20B3g (void) -{ - return SigTest20Real(MPM_B3G); -} -static int SigTest20Wm (void) -{ - return SigTest20Real(MPM_WUMANBER); -} - -static int SigTest21Real (int mpm_type) +static int SigTest21 (void) { ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); @@ -6772,7 +6486,6 @@ static int SigTest21Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); @@ -6816,21 +6529,8 @@ static int SigTest21Real (int mpm_type) FLOW_DESTROY(&f); return result; } -static int SigTest21B2g (void) -{ - return SigTest21Real(MPM_B2G); -} -static int SigTest21B3g (void) -{ - return SigTest21Real(MPM_B3G); -} -static int SigTest21Wm (void) -{ - return SigTest21Real(MPM_WUMANBER); -} - -static int SigTest22Real (int mpm_type) +static int SigTest22 (void) { ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); @@ -6866,7 +6566,6 @@ static int SigTest22Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); @@ -6881,7 +6580,6 @@ static int SigTest22Real (int mpm_type) } SigGroupBuild(de_ctx); - //PatternMatchPrepare(mpm_ctx, mpm_type); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -6899,7 +6597,6 @@ static int SigTest22Real (int mpm_type) SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p1, 1); @@ -6907,20 +6604,8 @@ static int SigTest22Real (int mpm_type) FLOW_DESTROY(&f); return result; } -static int SigTest22B2g (void) -{ - return SigTest22Real(MPM_B2G); -} -static int SigTest22B3g (void) -{ - return SigTest22Real(MPM_B3G); -} -static int SigTest22Wm (void) -{ - return SigTest22Real(MPM_WUMANBER); -} -static int SigTest23Real (int mpm_type) +static int SigTest23 (void) { ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); @@ -6956,7 +6641,6 @@ static int SigTest23Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:toggle,TEST.one; flowbits:noalert; sid:1;)"); @@ -6995,18 +6679,6 @@ static int SigTest23Real (int mpm_type) FLOW_DESTROY(&f); return result; } -static int SigTest23B2g (void) -{ - return SigTest23Real(MPM_B2G); -} -static int SigTest23B3g (void) -{ - return SigTest23Real(MPM_B3G); -} -static int SigTest23Wm (void) -{ - return SigTest23Real(MPM_WUMANBER); -} int SigTest24IPV4Keyword(void) { @@ -8908,7 +8580,7 @@ int SigTest37NegativeICMPV6Keyword(void) return result; } -int SigTest38Real(int mpm_type) +static int SigTest38(void) { Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) @@ -8986,8 +8658,6 @@ int SigTest38Real(int mpm_type) if (de_ctx == NULL) { goto end; } - - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -9040,20 +8710,8 @@ int SigTest38Real(int mpm_type) SCFree(p1); return result; } -static int SigTest38B2g (void) -{ - return SigTest38Real(MPM_B2G); -} -static int SigTest38B3g (void) -{ - return SigTest38Real(MPM_B3G); -} -static int SigTest38Wm (void) -{ - return SigTest38Real(MPM_WUMANBER); -} -int SigTest39Real(int mpm_type) +static int SigTest39(void) { Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) @@ -9131,8 +8789,6 @@ int SigTest39Real(int mpm_type) if (de_ctx == NULL) { goto end; } - - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -9189,34 +8845,20 @@ int SigTest39Real(int mpm_type) SCFree(p1); return result; } -static int SigTest39B2g (void) -{ - return SigTest39Real(MPM_B2G); -} -static int SigTest39B3g (void) -{ - return SigTest39Real(MPM_B3G); -} -static int SigTest39Wm (void) -{ - return SigTest39Real(MPM_WUMANBER); -} - - /** * \test SigTest36ContentAndIsdataatKeywords01 is a test to check window with constructed packets, * \brief expecting to match a size */ -int SigTest36ContentAndIsdataatKeywords01Real (int mpm_type) +static int SigTest36ContentAndIsdataatKeywords01 (void) { int result = 0; // Buid and decode the packet uint8_t raw_eth [] = { - 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 + 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 @@ -9268,7 +8910,6 @@ int SigTest36ContentAndIsdataatKeywords01Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest36ContentAndIsdataatKeywords01 \"; content:\"HTTP\"; isdataat:404, relative; sid:101;)"); @@ -9278,7 +8919,6 @@ int SigTest36ContentAndIsdataatKeywords01Real (int mpm_type) } SigGroupBuild(de_ctx); - //PatternMatchPrepare(mpm_ctx, mpm_type); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -9293,7 +8933,6 @@ int SigTest36ContentAndIsdataatKeywords01Real (int mpm_type) SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); PACKET_RECYCLE(p); FlowShutdown(); @@ -9331,7 +8970,7 @@ int SigTest36ContentAndIsdataatKeywords01Real (int mpm_type) * \brief not expecting to match a size */ -int SigTest37ContentAndIsdataatKeywords02Real (int mpm_type) +static int SigTest37ContentAndIsdataatKeywords02 (void) { int result = 0; @@ -9390,7 +9029,6 @@ int SigTest37ContentAndIsdataatKeywords02Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; Signature *s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest37ContentAndIsdataatKeywords01 \"; content:\"HTTP\"; isdataat:500, relative; sid:101;)"); @@ -9404,16 +9042,6 @@ int SigTest37ContentAndIsdataatKeywords02Real (int mpm_type) printf("type not content: "); goto end; } -/* - if (s->sm_lists[DETECT_SM_LIST_PMATCH]->next == NULL) { - printf("s->sm_lists[DETECT_SM_LIST_PMATCH]->next == NULL: "); - goto end; - } - if (s->sm_lists[DETECT_SM_LIST_PMATCH]->next->type != DETECT_ISDATAAT) { - printf("type not isdataat: "); - goto end; - } -*/ SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -9460,41 +9088,12 @@ int SigTest37ContentAndIsdataatKeywords02Real (int mpm_type) return result; } - -// Wrapper functions to pass the mpm_type -static int SigTest36ContentAndIsdataatKeywords01B2g (void) -{ - return SigTest36ContentAndIsdataatKeywords01Real(MPM_B2G); -} -static int SigTest36ContentAndIsdataatKeywords01B3g (void) -{ - return SigTest36ContentAndIsdataatKeywords01Real(MPM_B3G); -} -static int SigTest36ContentAndIsdataatKeywords01Wm (void) -{ - return SigTest36ContentAndIsdataatKeywords01Real(MPM_WUMANBER); -} - -static int SigTest37ContentAndIsdataatKeywords02B2g (void) -{ - return SigTest37ContentAndIsdataatKeywords02Real(MPM_B2G); -} -static int SigTest37ContentAndIsdataatKeywords02B3g (void) -{ - return SigTest37ContentAndIsdataatKeywords02Real(MPM_B3G); -} -static int SigTest37ContentAndIsdataatKeywords02Wm (void) -{ - return SigTest37ContentAndIsdataatKeywords02Real(MPM_WUMANBER); -} - - /** * \test SigTest41NoPacketInspection is a test to check that when PKT_NOPACKET_INSPECTION * flag is set, we don't need to inspect the packet protocol header or its contents. */ -int SigTest40NoPacketInspection01(void) +static int SigTest40NoPacketInspection01(void) { uint8_t *buf = (uint8_t *) @@ -10484,7 +10083,7 @@ static int SigTestSgh05 (void) goto end; } de_ctx->flags |= DE_QUIET; - de_ctx->mpm_matcher = MPM_WUMANBER; + de_ctx->mpm_matcher = MPM_AC; de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.6 any (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -10515,8 +10114,8 @@ static int SigTestSgh05 (void) goto end; } - if (sgh->mpm_stream_ctx_ts->mpm_type != MPM_WUMANBER) { - printf("sgh->mpm_type != MPM_WUMANBER, expected %d, got %d: ", MPM_WUMANBER, sgh->mpm_stream_ctx_ts->mpm_type); + if (sgh->mpm_stream_ctx_ts->mpm_type != MPM_AC) { + printf("sgh->mpm_type != MPM_AC, expected %d, got %d: ", MPM_AC, sgh->mpm_stream_ctx_ts->mpm_type); goto end; } @@ -10530,7 +10129,7 @@ static int SigTestSgh05 (void) return result; } -static int SigTestContent01Real (int mpm_type) +static int SigTestContent01 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; uint16_t buflen = strlen((char *)buf); @@ -10548,7 +10147,6 @@ static int SigTestContent01Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); @@ -10575,20 +10173,8 @@ static int SigTestContent01Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestContent01B2g (void) -{ - return SigTestContent01Real(MPM_B2G); -} -static int SigTestContent01B3g (void) -{ - return SigTestContent01Real(MPM_B3G); -} -static int SigTestContent01Wm (void) -{ - return SigTestContent01Real(MPM_WUMANBER); -} -static int SigTestContent02Real (int mpm_type) +static int SigTestContent02 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; uint16_t buflen = strlen((char *)buf); @@ -10605,7 +10191,6 @@ static int SigTestContent02Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); @@ -10642,20 +10227,8 @@ static int SigTestContent02Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestContent02B2g (void) -{ - return SigTestContent02Real(MPM_B2G); -} -static int SigTestContent02B3g (void) -{ - return SigTestContent02Real(MPM_B3G); -} -static int SigTestContent02Wm (void) -{ - return SigTestContent02Real(MPM_WUMANBER); -} -static int SigTestContent03Real (int mpm_type) +static int SigTestContent03 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); @@ -10672,7 +10245,6 @@ static int SigTestContent03Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; sid:1;)"); @@ -10699,20 +10271,8 @@ static int SigTestContent03Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestContent03B2g (void) -{ - return SigTestContent03Real(MPM_B2G); -} -static int SigTestContent03B3g (void) -{ - return SigTestContent03Real(MPM_B3G); -} -static int SigTestContent03Wm (void) -{ - return SigTestContent03Real(MPM_WUMANBER); -} -static int SigTestContent04Real (int mpm_type) +static int SigTestContent04 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); @@ -10730,7 +10290,6 @@ static int SigTestContent04Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); @@ -10757,21 +10316,9 @@ static int SigTestContent04Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestContent04B2g (void) -{ - return SigTestContent04Real(MPM_B2G); -} -static int SigTestContent04B3g (void) -{ - return SigTestContent04Real(MPM_B3G); -} -static int SigTestContent04Wm (void) -{ - return SigTestContent04Real(MPM_WUMANBER); -} /** \test sigs with patterns at the limit of the pm's size limit */ -static int SigTestContent05Real (int mpm_type) +static int SigTestContent05 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901PADabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); @@ -10789,7 +10336,6 @@ static int SigTestContent05Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); @@ -10832,20 +10378,8 @@ static int SigTestContent05Real (int mpm_type) } return result; } -static int SigTestContent05B2g (void) -{ - return SigTestContent05Real(MPM_B2G); -} -static int SigTestContent05B3g (void) -{ - return SigTestContent05Real(MPM_B3G); -} -static int SigTestContent05Wm (void) -{ - return SigTestContent05Real(MPM_WUMANBER); -} -static int SigTestContent06Real (int mpm_type) +static int SigTestContent06 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); @@ -10862,7 +10396,6 @@ static int SigTestContent06Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Test 32 sig1\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); @@ -10903,20 +10436,8 @@ static int SigTestContent06Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestContent06B2g (void) -{ - return SigTestContent06Real(MPM_B2G); -} -static int SigTestContent06B3g (void) -{ - return SigTestContent06Real(MPM_B3G); -} -static int SigTestContent06Wm (void) -{ - return SigTestContent06Real(MPM_WUMANBER); -} -static int SigTestWithinReal01 (int mpm_type) +static int SigTestWithin01 (void) { DecodeThreadVars dtv; ThreadVars th_v; @@ -11026,7 +10547,6 @@ static int SigTestWithinReal01 (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"within test\"; content:\"Hi, this is a big test to check \"; content:\"content matches\"; distance:0; within:15; sid:556;)"); @@ -11130,20 +10650,7 @@ static int SigTestWithinReal01 (int mpm_type) return result; } -static int SigTestWithinReal01B2g (void) -{ - return SigTestWithinReal01(MPM_B2G); -} -static int SigTestWithinReal01B3g (void) -{ - return SigTestWithinReal01(MPM_B3G); -} -static int SigTestWithinReal01Wm (void) -{ - return SigTestWithinReal01(MPM_WUMANBER); -} - -static int SigTestDepthOffset01Real (int mpm_type) +static int SigTestDepthOffset01 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); @@ -11161,7 +10668,6 @@ static int SigTestDepthOffset01Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"depth offset\"; content:\"456\"; offset:4; depth:3; sid:1;)"); @@ -11186,18 +10692,6 @@ static int SigTestDepthOffset01Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestDepthOffset01B2g (void) -{ - return SigTestDepthOffset01Real(MPM_B2G); -} -static int SigTestDepthOffset01B3g (void) -{ - return SigTestDepthOffset01Real(MPM_B3G); -} -static int SigTestDepthOffset01Wm (void) -{ - return SigTestDepthOffset01Real(MPM_WUMANBER); -} static int SigTestDetectAlertCounter(void) { @@ -11213,7 +10707,6 @@ static int SigTestDetectAlertCounter(void) goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test counter\"; " @@ -11297,7 +10790,6 @@ static int SigTestDropFlow01(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop http any any -> any any " @@ -11400,7 +10892,6 @@ static int SigTestDropFlow02(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 " @@ -11522,7 +11013,6 @@ static int SigTestDropFlow03(void) goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 " @@ -11694,7 +11184,6 @@ static int SigTestDropFlow04(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 " @@ -11840,7 +11329,6 @@ static int SigTestPorts01(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any 80 " @@ -12128,97 +11616,29 @@ void SigRegisterTests(void) SigParseRegisterTests(); IPOnlyRegisterTests(); - UtRegisterTest("SigTest01B2g -- HTTP URI cap", SigTest01B2g, 1); - UtRegisterTest("SigTest01B3g -- HTTP URI cap", SigTest01B3g, 1); - UtRegisterTest("SigTest01Wm -- HTTP URI cap", SigTest01Wm, 1); - - UtRegisterTest("SigTest02B2g -- Offset/Depth match", SigTest02B2g, 1); - UtRegisterTest("SigTest02B3g -- Offset/Depth match", SigTest02B3g, 1); - UtRegisterTest("SigTest02Wm -- Offset/Depth match", SigTest02Wm, 1); - - UtRegisterTest("SigTest03B2g -- offset/depth mismatch", SigTest03B2g, 1); - UtRegisterTest("SigTest03B3g -- offset/depth mismatch", SigTest03B3g, 1); - UtRegisterTest("SigTest03Wm -- offset/depth mismatch", SigTest03Wm, 1); - - UtRegisterTest("SigTest04B2g -- distance/within match", SigTest04B2g, 1); - UtRegisterTest("SigTest04B3g -- distance/within match", SigTest04B3g, 1); - UtRegisterTest("SigTest04Wm -- distance/within match", SigTest04Wm, 1); - - UtRegisterTest("SigTest05B2g -- distance/within mismatch", SigTest05B2g, 1); - UtRegisterTest("SigTest05B3g -- distance/within mismatch", SigTest05B3g, 1); - UtRegisterTest("SigTest05Wm -- distance/within mismatch", SigTest05Wm, 1); - - UtRegisterTest("SigTest06B2g -- uricontent HTTP/1.1 match test", SigTest06B2g, 1); - UtRegisterTest("SigTest06B3g -- uricontent HTTP/1.1 match test", SigTest06B3g, 1); - UtRegisterTest("SigTest06wm -- uricontent HTTP/1.1 match test", SigTest06Wm, 1); - - UtRegisterTest("SigTest07B2g -- uricontent HTTP/1.1 mismatch test", SigTest07B2g, 1); - UtRegisterTest("SigTest07B3g -- uricontent HTTP/1.1 mismatch test", SigTest07B3g, 1); - UtRegisterTest("SigTest07Wm -- uricontent HTTP/1.1 mismatch test", SigTest07Wm, 1); - - UtRegisterTest("SigTest08B2g -- uricontent HTTP/1.0 match test", SigTest08B2g, 1); - UtRegisterTest("SigTest08B3g -- uricontent HTTP/1.0 match test", SigTest08B3g, 1); - UtRegisterTest("SigTest08Wm -- uricontent HTTP/1.0 match test", SigTest08Wm, 1); - - UtRegisterTest("SigTest09B2g -- uricontent HTTP/1.0 mismatch test", SigTest09B2g, 1); - UtRegisterTest("SigTest09B3g -- uricontent HTTP/1.0 mismatch test", SigTest09B3g, 1); - UtRegisterTest("SigTest09Wm -- uricontent HTTP/1.0 mismatch test", SigTest09Wm, 1); - - UtRegisterTest("SigTest10B2g -- long content match, longer than pkt", SigTest10B2g, 1); - UtRegisterTest("SigTest10B3g -- long content match, longer than pkt", SigTest10B3g, 1); - UtRegisterTest("SigTest10Wm -- long content match, longer than pkt", SigTest10Wm, 1); - - UtRegisterTest("SigTest11B2g -- mpm searching", SigTest11B2g, 1); - UtRegisterTest("SigTest11B3g -- mpm searching", SigTest11B3g, 1); - UtRegisterTest("SigTest11Wm -- mpm searching", SigTest11Wm, 1); - - UtRegisterTest("SigTest12B2g -- content order matching, normal", SigTest12B2g, 1); - UtRegisterTest("SigTest12B3g -- content order matching, normal", SigTest12B3g, 1); - UtRegisterTest("SigTest12Wm -- content order matching, normal", SigTest12Wm, 1); - - UtRegisterTest("SigTest13B2g -- content order matching, diff order", SigTest13B2g, 1); - UtRegisterTest("SigTest13B3g -- content order matching, diff order", SigTest13B3g, 1); - UtRegisterTest("SigTest13Wm -- content order matching, diff order", SigTest13Wm, 1); - - UtRegisterTest("SigTest14B2g -- content order matching, distance 0", SigTest14B2g, 1); - UtRegisterTest("SigTest14B3g -- content order matching, distance 0", SigTest14B3g, 1); - UtRegisterTest("SigTest14Wm -- content order matching, distance 0", SigTest14Wm, 1); - - UtRegisterTest("SigTest15B2g -- port negation sig (no match)", SigTest15B2g, 1); - UtRegisterTest("SigTest15B3g -- port negation sig (no match)", SigTest15B3g, 1); - UtRegisterTest("SigTest15Wm -- port negation sig (no match)", SigTest15Wm, 1); - - UtRegisterTest("SigTest16B2g -- port negation sig (match)", SigTest16B2g, 1); - UtRegisterTest("SigTest16B3g -- port negation sig (match)", SigTest16B3g, 1); - UtRegisterTest("SigTest16Wm -- port negation sig (match)", SigTest16Wm, 1); - - UtRegisterTest("SigTest17B2g -- HTTP Host Pkt var capture", SigTest17B2g, 1); - UtRegisterTest("SigTest17B3g -- HTTP Host Pkt var capture", SigTest17B3g, 1); - UtRegisterTest("SigTest17Wm -- HTTP Host Pkt var capture", SigTest17Wm, 1); - - UtRegisterTest("SigTest18B2g -- Ftp negation sig test", SigTest18B2g, 1); - UtRegisterTest("SigTest18B3g -- Ftp negation sig test", SigTest18B3g, 1); - UtRegisterTest("SigTest18Wm -- Ftp negation sig test", SigTest18Wm, 1); - - UtRegisterTest("SigTest19B2g -- IP-ONLY test (1)", SigTest19B2g, 1); - UtRegisterTest("SigTest19B3g -- IP-ONLY test (1)", SigTest19B3g, 1); - UtRegisterTest("SigTest19Wm -- IP-ONLY test (1)", SigTest19Wm, 1); - - UtRegisterTest("SigTest20B2g -- IP-ONLY test (2)", SigTest20B2g, 1); - UtRegisterTest("SigTest20B3g -- IP-ONLY test (2)", SigTest20B3g, 1); - UtRegisterTest("SigTest20Wm -- IP-ONLY test (2)", SigTest20Wm, 1); - - UtRegisterTest("SigTest21B2g -- FLOWBIT test (1)", SigTest21B2g, 1); - UtRegisterTest("SigTest21B3g -- FLOWBIT test (1)", SigTest21B3g, 1); - UtRegisterTest("SigTest21Wm -- FLOWBIT test (1)", SigTest21Wm, 1); - - UtRegisterTest("SigTest22B2g -- FLOWBIT test (2)", SigTest22B2g, 1); - UtRegisterTest("SigTest22B3g -- FLOWBIT test (2)", SigTest22B3g, 1); - UtRegisterTest("SigTest22Wm -- FLOWBIT test (2)", SigTest22Wm, 1); - - UtRegisterTest("SigTest23B2g -- FLOWBIT test (3)", SigTest23B2g, 1); - UtRegisterTest("SigTest23B3g -- FLOWBIT test (3)", SigTest23B3g, 1); - UtRegisterTest("SigTest23Wm -- FLOWBIT test (3)", SigTest23Wm, 1); + UtRegisterTest("SigTest01", SigTest01, 1); + UtRegisterTest("SigTest02 -- Offset/Depth match", SigTest02, 1); + UtRegisterTest("SigTest03 -- offset/depth mismatch", SigTest03, 1); + UtRegisterTest("SigTest04 -- distance/within match", SigTest04, 1); + UtRegisterTest("SigTest05 -- distance/within mismatch", SigTest05, 1); + UtRegisterTest("SigTest06 -- uricontent HTTP/1.1 match test", SigTest06, 1); + UtRegisterTest("SigTest07 -- uricontent HTTP/1.1 mismatch test", SigTest07, 1); + UtRegisterTest("SigTest08 -- uricontent HTTP/1.0 match test", SigTest08, 1); + UtRegisterTest("SigTest09 -- uricontent HTTP/1.0 mismatch test", SigTest09, 1); + UtRegisterTest("SigTest10 -- long content match, longer than pkt", SigTest10, 1); + UtRegisterTest("SigTest11 -- mpm searching", SigTest11, 1); + UtRegisterTest("SigTest12 -- content order matching, normal", SigTest12, 1); + UtRegisterTest("SigTest13 -- content order matching, diff order", SigTest13, 1); + UtRegisterTest("SigTest14 -- content order matching, distance 0", SigTest14, 1); + UtRegisterTest("SigTest15 -- port negation sig (no match)", SigTest15, 1); + UtRegisterTest("SigTest16 -- port negation sig (match)", SigTest16, 1); + UtRegisterTest("SigTest17 -- HTTP Host Pkt var capture", SigTest17, 1); + UtRegisterTest("SigTest18 -- Ftp negation sig test", SigTest18, 1); + UtRegisterTest("SigTest19 -- IP-ONLY test (1)", SigTest19, 1); + UtRegisterTest("SigTest20 -- IP-ONLY test (2)", SigTest20, 1); + UtRegisterTest("SigTest21 -- FLOWBIT test (1)", SigTest21, 1); + UtRegisterTest("SigTest22 -- FLOWBIT test (2)", SigTest22, 1); + UtRegisterTest("SigTest23 -- FLOWBIT test (3)", SigTest23, 1); UtRegisterTest("SigTest24IPV4Keyword", SigTest24IPV4Keyword, 1); UtRegisterTest("SigTest25NegativeIPV4Keyword", @@ -12246,23 +11666,10 @@ void SigRegisterTests(void) UtRegisterTest("SigTest35NegativeICMPV4Keyword", SigTest35NegativeICMPV4Keyword, 1); - /* The following tests check content options with isdataat options - relative to that content match - */ - - UtRegisterTest("SigTest36ContentAndIsdataatKeywords01B2g", - SigTest36ContentAndIsdataatKeywords01B2g, 1); - UtRegisterTest("SigTest36ContentAndIsdataatKeywords01B3g", - SigTest36ContentAndIsdataatKeywords01B3g, 1); - UtRegisterTest("SigTest36ContentAndIsdataatKeywords01Wm" , - SigTest36ContentAndIsdataatKeywords01Wm, 1); - - UtRegisterTest("SigTest37ContentAndIsdataatKeywords02B2g", - SigTest37ContentAndIsdataatKeywords02B2g, 1); - UtRegisterTest("SigTest37ContentAndIsdataatKeywords02B3g", - SigTest37ContentAndIsdataatKeywords02B3g, 1); - UtRegisterTest("SigTest37ContentAndIsdataatKeywords02Wm" , - SigTest37ContentAndIsdataatKeywords02Wm, 1); + UtRegisterTest("SigTest36ContentAndIsdataatKeywords01", + SigTest36ContentAndIsdataatKeywords01, 1); + UtRegisterTest("SigTest37ContentAndIsdataatKeywords02", + SigTest37ContentAndIsdataatKeywords02, 1); /* We need to enable these tests, as soon as we add the ICMPv6 protocol support in our rules engine */ @@ -12270,13 +11677,9 @@ void SigRegisterTests(void) //UtRegisterTest("SigTest37NegativeICMPV6Keyword", // SigTest37NegativeICMPV6Keyword, 1); - UtRegisterTest("SigTest38B2g -- byte_test test (1)", SigTest38B2g, 1); - UtRegisterTest("SigTest38B3g -- byte_test test (1)", SigTest38B3g, 1); - UtRegisterTest("SigTest38Wm -- byte_test test (1)", SigTest38Wm, 1); + UtRegisterTest("SigTest38 -- byte_test test (1)", SigTest38, 1); - UtRegisterTest("SigTest39B2g -- byte_jump test (2)", SigTest39B2g, 1); - UtRegisterTest("SigTest39B3g -- byte_jump test (2)", SigTest39B3g, 1); - UtRegisterTest("SigTest39Wm -- byte_jump test (2)", SigTest39Wm, 1); + UtRegisterTest("SigTest39 -- byte_jump test (2)", SigTest39, 1); UtRegisterTest("SigTest40NoPacketInspection01", SigTest40NoPacketInspection01, 1); UtRegisterTest("SigTest40NoPayloadInspection02", SigTest40NoPayloadInspection02, 1); @@ -12291,37 +11694,15 @@ void SigRegisterTests(void) UtRegisterTest("SigTestSgh04", SigTestSgh04, 1); UtRegisterTest("SigTestSgh05", SigTestSgh05, 1); - UtRegisterTest("SigTestContent01B2g -- 32 byte pattern", SigTestContent01B2g, 1); - UtRegisterTest("SigTestContent01B3g -- 32 byte pattern", SigTestContent01B3g, 1); - UtRegisterTest("SigTestContent01Wm -- 32 byte pattern", SigTestContent01Wm, 1); - - UtRegisterTest("SigTestContent02B2g -- 32+31 byte pattern", SigTestContent02B2g, 1); - UtRegisterTest("SigTestContent02B3g -- 32+31 byte pattern", SigTestContent02B3g, 1); - UtRegisterTest("SigTestContent02Wm -- 32+31 byte pattern", SigTestContent02Wm, 1); - - UtRegisterTest("SigTestContent03B2g -- 32 byte pattern, x2 + distance", SigTestContent03B2g, 1); - UtRegisterTest("SigTestContent03B3g -- 32 byte pattern, x2 + distance", SigTestContent03B3g, 1); - UtRegisterTest("SigTestContent03Wm -- 32 byte pattern, x2 + distance", SigTestContent03Wm, 1); - - UtRegisterTest("SigTestContent04B2g -- 32 byte pattern, x2 + distance/within", SigTestContent04B2g, 1); - UtRegisterTest("SigTestContent04B3g -- 32 byte pattern, x2 + distance/within", SigTestContent04B3g, 1); - UtRegisterTest("SigTestContent04Wm -- 32 byte pattern, x2 + distance/within", SigTestContent04Wm, 1); - - UtRegisterTest("SigTestContent05B2g -- distance/within", SigTestContent05B2g, 1); - UtRegisterTest("SigTestContent05B3g -- distance/within", SigTestContent05B3g, 1); - UtRegisterTest("SigTestContent05Wm -- distance/within", SigTestContent05Wm, 1); - - UtRegisterTest("SigTestContent06B2g -- distance/within ip only", SigTestContent06B2g, 1); - UtRegisterTest("SigTestContent06B3g -- distance/within ip only", SigTestContent06B3g, 1); - UtRegisterTest("SigTestContent06Wm -- distance/within ip only", SigTestContent06Wm, 1); - - UtRegisterTest("SigTestWithinReal01B2g", SigTestWithinReal01B2g, 1); - UtRegisterTest("SigTestWithinReal01B3g", SigTestWithinReal01B3g, 1); - UtRegisterTest("SigTestWithinReal01Wm", SigTestWithinReal01Wm, 1); + UtRegisterTest("SigTestContent01 -- 32 byte pattern", SigTestContent01, 1); + UtRegisterTest("SigTestContent02 -- 32+31 byte pattern", SigTestContent02, 1); + UtRegisterTest("SigTestContent03 -- 32 byte pattern, x2 + distance", SigTestContent03, 1); + UtRegisterTest("SigTestContent04 -- 32 byte pattern, x2 + distance/within", SigTestContent04, 1); + UtRegisterTest("SigTestContent05 -- distance/within", SigTestContent05, 1); + UtRegisterTest("SigTestContent06 -- distance/within ip only", SigTestContent06, 1); - UtRegisterTest("SigTestDepthOffset01B2g", SigTestDepthOffset01B2g, 1); - UtRegisterTest("SigTestDepthOffset01B3g", SigTestDepthOffset01B3g, 1); - UtRegisterTest("SigTestDepthOffset01Wm", SigTestDepthOffset01Wm, 1); + UtRegisterTest("SigTestWithinReal01", SigTestWithin01, 1); + UtRegisterTest("SigTestDepthOffset01", SigTestDepthOffset01, 1); UtRegisterTest("SigTestDetectAlertCounter", SigTestDetectAlertCounter, 1); diff --git a/src/util-mpm-ac-gfbs.c b/src/util-mpm-ac-gfbs.c deleted file mode 100644 index bfff68890898..000000000000 --- a/src/util-mpm-ac-gfbs.c +++ /dev/null @@ -1,2722 +0,0 @@ -/* 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 Anoop Saldanha - * - * Implementation of aho-corasick MPM from - - * - * Efficient String Matching: An Aid to Bibliographic Search - * Alfred V. Aho and Margaret J. Corasick - * - * - We use the goto-failure table to calculate transitions. - * - If we cross 2 ** 16 states, we use 4 bytes in the transition table - * to hold each state, otherwise we use 2 bytes. - * - To reduce memory consumption, we throw all the failure transitions - * out and use binary search to pick out the right transition in - * the modified goto table. - * - * \todo - Do a proper analyis of our existing MPMs and suggest a good one based - * on the pattern distribution and the expected traffic(say http). - * - Tried out loop unrolling without any perf increase. Need to dig deeper. - * - Try out holding whether they are any output strings from a particular - * state in one of the bytes of a state var. Will be useful in cuda esp. - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "util-mpm-ac-gfbs.h" - -#include "conf.h" -#include "util-memcmp.h" -#include "util-memcpy.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -void SCACGfbsInitCtx(MpmCtx *); -void SCACGfbsInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); -void SCACGfbsDestroyCtx(MpmCtx *); -void SCACGfbsDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); -int SCACGfbsAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, SigIntId, uint8_t); -int SCACGfbsAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, SigIntId, uint8_t); -int SCACGfbsPreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); -void SCACGfbsPrintInfo(MpmCtx *mpm_ctx); -void SCACGfbsPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void SCACGfbsRegisterTests(void); - -/* a placeholder to denote a failure transition in the goto table */ -#define SC_AC_GFBS_FAIL (-1) -/* size of the hash table used to speed up pattern insertions initially */ -#define INIT_HASH_SIZE 65536 - -#define STATE_QUEUE_CONTAINER_SIZE 65536 - -/** - * \brief Helper structure used by AC during state table creation - */ -typedef struct StateQueue_ { - int32_t store[STATE_QUEUE_CONTAINER_SIZE]; - int top; - int bot; -} StateQueue; - -/** - * \brief Register the goto failure table based aho-corasick mpm. - */ -void MpmACGfbsRegister(void) -{ - mpm_table[MPM_AC_GFBS].name = "ac-gfbs"; - /* don't need this. isn't that awesome? no more chopping and blah blah */ - mpm_table[MPM_AC_GFBS].max_pattern_length = 0; - - mpm_table[MPM_AC_GFBS].InitCtx = SCACGfbsInitCtx; - mpm_table[MPM_AC_GFBS].InitThreadCtx = SCACGfbsInitThreadCtx; - mpm_table[MPM_AC_GFBS].DestroyCtx = SCACGfbsDestroyCtx; - mpm_table[MPM_AC_GFBS].DestroyThreadCtx = SCACGfbsDestroyThreadCtx; - mpm_table[MPM_AC_GFBS].AddPattern = SCACGfbsAddPatternCS; - mpm_table[MPM_AC_GFBS].AddPatternNocase = SCACGfbsAddPatternCI; - mpm_table[MPM_AC_GFBS].Prepare = SCACGfbsPreparePatterns; - mpm_table[MPM_AC_GFBS].Search = SCACGfbsSearch; - mpm_table[MPM_AC_GFBS].Cleanup = NULL; - mpm_table[MPM_AC_GFBS].PrintCtx = SCACGfbsPrintInfo; - mpm_table[MPM_AC_GFBS].PrintThreadCtx = SCACGfbsPrintSearchStats; - mpm_table[MPM_AC_GFBS].RegisterUnittests = SCACGfbsRegisterTests; - - return; -} - -/** - * \internal - * \brief Initialize the AC context with user specified conf parameters. We - * aren't retrieving anything for AC conf now, but we will certainly - * need it, when we customize AC. - */ -static void SCACGfbsGetConfig() -{ - //ConfNode *ac_conf; - //const char *hash_val = NULL; - - //ConfNode *pm = ConfGetNode("pattern-matcher"); - - return; -} - -/** - * \internal - * \brief Creates a hash of the pattern. We use it for the hashing process - * during the initial pattern insertion time, to cull duplicate sigs. - * - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline uint32_t SCACGfbsInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -/** - * \internal - * \brief Looks up a pattern. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param ctx Pointer to the AC ctx. - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline SCACGfbsPattern *SCACGfbsInitHashLookup(SCACGfbsCtx *ctx, uint8_t *pat, - uint16_t patlen, char flags, - uint32_t pid) -{ - uint32_t hash = SCACGfbsInitHashRaw(pat, patlen); - - if (ctx->init_hash == NULL) - return NULL; - - SCACGfbsPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (t->id == pid) - return t; - } - - return NULL; -} - -/** - * \internal - * \brief Allocs a new pattern instance. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval p Pointer to the newly created pattern. - */ -static inline SCACGfbsPattern *SCACGfbsAllocPattern(MpmCtx *mpm_ctx) -{ - SCACGfbsPattern *p = SCMalloc(sizeof(SCACGfbsPattern)); - if (unlikely(p == NULL)) { - exit(EXIT_FAILURE); - } - memset(p, 0, sizeof(SCACGfbsPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACGfbsPattern); - - return p; -} - -/** - * \internal - * \brief Used to free SCACGfbsPattern instances. - * - * \param mpm_ctx Pointer to the mpm context. - * \param p Pointer to the SCACGfbsPattern instance to be freed. - */ -static inline void SCACGfbsFreePattern(MpmCtx *mpm_ctx, SCACGfbsPattern *p) -{ - if (p != NULL && p->cs != NULL && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->ci != NULL) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACGfbsPattern); - } - return; -} - -static inline uint32_t SCACGfbsInitHash(SCACGfbsPattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int SCACGfbsInitHashAdd(SCACGfbsCtx *ctx, SCACGfbsPattern *p) -{ - uint32_t hash = SCACGfbsInitHash(p); - - if (ctx->init_hash == NULL) { - return 0; - } - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - SCACGfbsPattern *tt = NULL; - SCACGfbsPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - -/** - * \internal - * \brief Add a pattern to the mpm-ac context. - * - * \param mpm_ctx Mpm context. - * \param pat Pointer to the pattern. - * \param patlen Length of the pattern. - * \param pid Pattern id - * \param sid Signature id (internal id). - * \param flags Pattern's MPM_PATTERN_* flags. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int SCACGfbsAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, - ctx, patlen, pid); - - if (patlen == 0) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); - return 0; - } - - /* check if we have already inserted this pattern */ - SCACGfbsPattern *p = SCACGfbsInitHashLookup(ctx, pat, patlen, flags, pid); - if (p == NULL) { - SCLogDebug("Allocing new pattern"); - - /* p will never be NULL */ - p = SCACGfbsAllocPattern(mpm_ctx); - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci, pat, p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - /* put in the pattern hash */ - SCACGfbsInitHashAdd(ctx, p); - - if (mpm_ctx->pattern_cnt == 65535) { - SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " - "insert anymore. Exiting"); - exit(EXIT_FAILURE); - } - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - - if (mpm_ctx->minlen == 0) { - mpm_ctx->minlen = patlen; - } else { - if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - /* we need the max pat id */ - if (pid > ctx->max_pat_id) - ctx->max_pat_id = pid; - - p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); - BUG_ON(p->sids == NULL); - p->sids[0] = sid; - } else { - /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ - - int found = 0; - uint32_t x = 0; - for (x = 0; x < p->sids_size; x++) { - if (p->sids[x] == sid) { - found = 1; - break; - } - } - if (!found) { - SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); - BUG_ON(sids == NULL); - p->sids = sids; - p->sids[p->sids_size] = sid; - p->sids_size++; - } - } - - return 0; - -error: - SCACGfbsFreePattern(mpm_ctx, p); - return -1; -} - -/** - * \internal - * \brief Initialize a new state in the goto and output tables. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval The state id, of the newly created state. - */ -static inline int SCACGfbsInitNewState(MpmCtx *mpm_ctx) -{ - void *ptmp; - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - int ascii_code = 0; - int size = 0; - - /* reallocate space in the goto table to include a new state */ - size = (ctx->state_count + 1) * 1024; - ptmp = SCRealloc(ctx->goto_table, size); - if (ptmp == NULL) { - SCFree(ctx->goto_table); - ctx->goto_table = NULL; - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - ctx->goto_table = ptmp; - - /* set all transitions for the newly assigned state as FAIL transitions */ - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - ctx->goto_table[ctx->state_count][ascii_code] = SC_AC_GFBS_FAIL; - } - - /* reallocate space in the output table for the new state */ - size = (ctx->state_count + 1) * sizeof(SCACGfbsOutputTable); - ptmp = SCRealloc(ctx->output_table, size); - if (ptmp == NULL) { - SCFree(ctx->output_table); - ctx->output_table = NULL; - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - ctx->output_table = ptmp; - - memset(ctx->output_table + ctx->state_count, 0, sizeof(SCACGfbsOutputTable)); - - /* \todo using it temporarily now during dev, since I have restricted - * state var in SCACGfbsCtx->state_table to uint16_t. */ - //if (ctx->state_count > 65536) { - // printf("state count exceeded\n"); - // exit(EXIT_FAILURE); - //} - - return ctx->state_count++; -} - -/** - * \internal - * \brief Adds a pid to the output table for a state. - * - * \param state The state to whose output table we should add the pid. - * \param pid The pattern id to add. - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACGfbsSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) -{ - void *ptmp; - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - SCACGfbsOutputTable *output_state = &ctx->output_table[state]; - uint32_t i = 0; - - for (i = 0; i < output_state->no_of_entries; i++) { - if (output_state->pids[i] == pid) - return; - } - - output_state->no_of_entries++; - ptmp = SCRealloc(output_state->pids, - output_state->no_of_entries * sizeof(uint32_t)); - if (ptmp == NULL) { - SCFree(output_state->pids); - output_state->pids = NULL; - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - output_state->pids = ptmp; - - output_state->pids[output_state->no_of_entries - 1] = pid; - - return; -} - -/** - * \brief Helper function used by SCACGfbsCreateGotoTable. Adds a pattern to the - * goto table. - * - * \param pattern Pointer to the pattern. - * \param pattern_len Pattern length. - * \param pid The pattern id, that corresponds to this pattern. We - * need it to updated the output table for this pattern. - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid, - MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - int32_t state = 0; - int32_t newstate = 0; - int i = 0; - int p = 0; - - /* walk down the trie till we have a match for the pattern prefix */ - state = 0; - for (i = 0; i < pattern_len; i++) { - if (ctx->goto_table[state][pattern[i]] != SC_AC_GFBS_FAIL) { - state = ctx->goto_table[state][pattern[i]]; - } else { - break; - } - } - - /* add the non-matching pattern suffix to the trie, from the last state - * we left off */ - for (p = i; p < pattern_len; p++) { - newstate = SCACGfbsInitNewState(mpm_ctx); - ctx->goto_table[state][pattern[p]] = newstate; - state = newstate; - } - - /* add this pattern id, to the output table of the last state, where the - * pattern ends in the trie */ - SCACGfbsSetOutputState(state, pid, mpm_ctx); - - return; -} - -/** - * \internal - * \brief Create the goto table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsCreateGotoTable(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - uint32_t i = 0; - - /* add each pattern to create the goto table */ - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - SCACGfbsEnter(ctx->parray[i]->ci, ctx->parray[i]->len, - ctx->parray[i]->id, mpm_ctx); - } - - int ascii_code = 0; - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[0][ascii_code] == SC_AC_GFBS_FAIL) { - ctx->goto_table[0][ascii_code] = 0; - } - } - - return; -} - -static inline int SCACGfbsStateQueueIsEmpty(StateQueue *q) -{ - if (q->top == q->bot) - return 1; - else - return 0; -} - -static inline void SCACGfbsEnqueue(StateQueue *q, int32_t state) -{ - int i = 0; - - /*if we already have this */ - for (i = q->bot; i < q->top; i++) { - if (q->store[i] == state) - return; - } - - q->store[q->top++] = state; - - if (q->top == STATE_QUEUE_CONTAINER_SIZE) - q->top = 0; - - if (q->top == q->bot) { - SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " - "Fatal Error. Exiting. Please file a bug report on this"); - exit(EXIT_FAILURE); - } - - return; -} - -static inline int32_t SCACGfbsDequeue(StateQueue *q) -{ - if (q->bot == STATE_QUEUE_CONTAINER_SIZE) - q->bot = 0; - - if (q->bot == q->top) { - SCLogCritical(SC_ERR_AHO_CORASICK, "StateQueue behaving weirdly. " - "Fatal Error. Exiting. Please file a bug report on this"); - exit(EXIT_FAILURE); - } - - return q->store[q->bot++]; -} - -/* -#define SCACGfbsStateQueueIsEmpty(q) (((q)->top == (q)->bot) ? 1 : 0) - -#define SCACGfbsEnqueue(q, state) do { \ - int i = 0; \ - \ - for (i = (q)->bot; i < (q)->top; i++) { \ - if ((q)->store[i] == state) \ - return; \ - } \ - \ - (q)->store[(q)->top++] = state; \ - \ - if ((q)->top == STATE_QUEUE_CONTAINER_SIZE) \ - (q)->top = 0; \ - \ - if ((q)->top == (q)->bot) { \ - SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " \ - "Fatal Error. Exiting. Please file a bug report on this"); \ - exit(EXIT_FAILURE); \ - } \ - } while (0) - -#define SCACGfbsDequeue(q) ( (((q)->bot == STATE_QUEUE_CONTAINER_SIZE)? ((q)->bot = 0): 0), \ - (((q)->bot == (q)->top) ? \ - (printf("StateQueue behaving " \ - "weirdly. Fatal Error. Exiting. Please " \ - "file a bug report on this"), \ - exit(EXIT_FAILURE)) : 0), \ - (q)->store[(q)->bot++]) \ -*/ - -/** - * \internal - * \brief Club the output data from 2 states and store it in the 1st state. - * dst_state_data = {dst_state_data} UNION {src_state_data} - * - * \todo Use a better way to find union of 2 sets. - * - * \param dst_state First state(also the destination) for the union operation. - * \param src_state Second state for the union operation. - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsClubOutputStates(int32_t dst_state, int32_t src_state, - MpmCtx *mpm_ctx) -{ - void *ptmp; - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - uint32_t i = 0; - uint32_t j = 0; - - SCACGfbsOutputTable *output_dst_state = &ctx->output_table[dst_state]; - SCACGfbsOutputTable *output_src_state = &ctx->output_table[src_state]; - - for (i = 0; i < output_src_state->no_of_entries; i++) { - for (j = 0; j < output_dst_state->no_of_entries; j++) { - if (output_src_state->pids[i] == output_dst_state->pids[j]) { - break; - } - } - if (j == output_dst_state->no_of_entries) { - output_dst_state->no_of_entries++; - - ptmp = SCRealloc(output_dst_state->pids, - (output_dst_state->no_of_entries * sizeof(uint32_t))); - if (ptmp == NULL) { - SCFree(output_dst_state->pids); - output_dst_state->pids = NULL; - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - output_dst_state->pids = ptmp; - - output_dst_state->pids[output_dst_state->no_of_entries - 1] = - output_src_state->pids[i]; - } - } - - return; -} - -/** - * \internal - * \brief Create the failure table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsCreateFailureTable(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - int ascii_code = 0; - int32_t state = 0; - int32_t r_state = 0; - - StateQueue q; - memset(&q, 0, sizeof(StateQueue)); - - /* allot space for the failure table. A failure entry in the table for - * every state(SCACGfbsCtx->state_count) */ - ctx->failure_table = SCMalloc(ctx->state_count * sizeof(int32_t)); - if (ctx->failure_table == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->failure_table, 0, ctx->state_count * sizeof(int32_t)); - - /* add the failure transitions for the 0th state, and add every non-fail - * transition from the 0th state to the queue for further processing - * of failure states */ - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - int32_t temp_state = ctx->goto_table[0][ascii_code]; - if (temp_state != 0) { - SCACGfbsEnqueue(&q, temp_state); - ctx->failure_table[temp_state] = 0; - } - } - - while (!SCACGfbsStateQueueIsEmpty(&q)) { - /* pick up every state from the queue and add failure transitions */ - r_state = SCACGfbsDequeue(&q); - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - int32_t temp_state = ctx->goto_table[r_state][ascii_code]; - if (temp_state == SC_AC_GFBS_FAIL) - continue; - SCACGfbsEnqueue(&q, temp_state); - state = ctx->failure_table[r_state]; - - while(ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) - state = ctx->failure_table[state]; - ctx->failure_table[temp_state] = ctx->goto_table[state][ascii_code]; - SCACGfbsClubOutputStates(temp_state, ctx->failure_table[temp_state], - mpm_ctx); - } - } - - return; -} - -/** - * \internal - * \brief Creates a new goto table structure(throw out all the failure - * transitions), to hold the existing goto table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsCreateModGotoTable(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - if (ctx->state_count < 32767) { - int size = 0; - int32_t state = 0; - for (state = 1; state < ctx->state_count; state++) { - int k = 0; - int ascii_code = 0; - for (; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) - continue; - k++; - } - - if ((k % 2) != 0) - size += 1; - } - - /* Let us use uint16_t for all. That way we don't have to worry about - * alignment. Technically 8 bits is all we need to store ascii codes, - * but by avoiding it, we save a lot of time on handling alignment */ - size += (ctx->state_count * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 3 + - ctx->state_count * sizeof(uint8_t) + - 256 * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 1); - ctx->goto_table_mod = SCMalloc(size); - if (ctx->goto_table_mod == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->goto_table_mod, 0, size); - //printf("size- %d\n", size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += size; - - /* buffer to hold pointers in the buffer, so that a state can use it - * directly to access its state data */ - ctx->goto_table_mod_pointers = SCMalloc(ctx->state_count * sizeof(uint8_t *)); - if (ctx->goto_table_mod_pointers == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->goto_table_mod_pointers, 0, - ctx->state_count * sizeof(uint8_t *)); - - SC_AC_GFBS_STATE_TYPE_U16 temp_states[256]; - uint16_t *curr_loc = (uint16_t *)ctx->goto_table_mod; - uint16_t *no_of_entries = NULL; - uint16_t *failure_entry = NULL; - uint8_t *ascii_codes = NULL; - uint16_t ascii_code = 0; - uint16_t k = 0; - for (state = 0; state < ctx->state_count; state++) { - /* store the starting location in the buffer for this state */ - ctx->goto_table_mod_pointers[state] = (uint8_t *)curr_loc; - no_of_entries = curr_loc++; - failure_entry = curr_loc++; - ascii_codes = (uint8_t *)curr_loc; - k = 0; - /* store all states that have non fail transitions in the temp buffer */ - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) - continue; - ascii_codes[k] = ascii_code; - temp_states[k] = ctx->goto_table[state][ascii_code]; - k++; - } - /* if we have any non fail transitions from our previous for search, - * store the acii codes as well the corresponding states */ - if (k > 0) { - no_of_entries[0] = k; - if (state != 0) { - int jump = (k + 1) & 0xFFE; - curr_loc += jump / 2; - } - memcpy(curr_loc, temp_states, k * sizeof(SC_AC_GFBS_STATE_TYPE_U16)); - curr_loc += k; - } - failure_entry[0] = ctx->failure_table[state]; - } - - /* > 33766 */ - } else { - int size = 0; - int32_t state = 0; - for (state = 1; state < ctx->state_count; state++) { - int k = 0; - int ascii_code = 0; - for (; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) - continue; - k++; - } - - if ( (k % 4) != 0) - size += (4 - (k % 4)); - } - - /* Let us use uint32_t for all. That way we don't have to worry about - * alignment. Technically 8 bits is all we need to store ascii codes, - * but by avoiding it, we save a lot of time on handling alignment */ - size += (ctx->state_count * (sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 3)+ - ctx->state_count * sizeof(uint8_t) + - 256 * (sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 1)); - ctx->goto_table_mod = SCMalloc(size); - if (ctx->goto_table_mod == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->goto_table_mod, 0, size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += size; - - /* buffer to hold pointers in the buffer, so that a state can use it - * directly to access its state data */ - ctx->goto_table_mod_pointers = SCMalloc(ctx->state_count * sizeof(uint8_t *)); - if (ctx->goto_table_mod_pointers == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->goto_table_mod_pointers, 0, - ctx->state_count * sizeof(uint8_t *)); - - SC_AC_GFBS_STATE_TYPE_U32 temp_states[256]; - uint32_t *curr_loc = (uint32_t *)ctx->goto_table_mod; - uint32_t *no_of_entries = NULL; - uint32_t *failure_entry = NULL; - uint8_t *ascii_codes = NULL; - uint16_t ascii_code = 0; - uint16_t k = 0; - for (state = 0; state < ctx->state_count; state++) { - /* store the starting location in the buffer for this state */ - ctx->goto_table_mod_pointers[state] = (uint8_t *)curr_loc; - no_of_entries = curr_loc++; - failure_entry = curr_loc++; - ascii_codes = (uint8_t *)curr_loc; - k = 0; - /* store all states that have non fail transitions in the temp buffer */ - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) - continue; - ascii_codes[k] = ascii_code; - temp_states[k] = ctx->goto_table[state][ascii_code]; - k++; - } - /* if we have any non fail transitions from our previous for search, - * store the acii codes as well the corresponding states */ - if (k > 0) { - no_of_entries[0] = k; - if (state != 0) { - int jump = (k + 3) & 0xFFC; - curr_loc += jump / 4; - } - memcpy(curr_loc, temp_states, k * sizeof(SC_AC_GFBS_STATE_TYPE_U32)); - curr_loc += k; - } - failure_entry[0] = ctx->failure_table[state]; - } - } - - return; -} - -static inline void SCACGfbsClubOutputStatePresenceWithModGotoTable(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - int state = 0; - int no_of_entries; - int i; - - if (ctx->state_count < 32767) { - uint16_t *states; - for (state = 0; state < ctx->state_count; state++) { - no_of_entries = *((uint16_t *)ctx->goto_table_mod_pointers[state]); - if (no_of_entries == 0) - continue; - - //if (*((uint16_t *)ctx->goto_table_mod_pointers[state] + 1) != 0) { - if (ctx->output_table[((uint16_t *)ctx->goto_table_mod_pointers[state] + 1)[0]].no_of_entries != 0) { - *((uint16_t *)ctx->goto_table_mod_pointers[state] + 1) |= (1 << 15); - } - - if (state == 0) - states = ((uint16_t *)ctx->goto_table_mod_pointers[state] + 2); - else - states = ((uint16_t *)ctx->goto_table_mod_pointers[state] + 2 + ((no_of_entries + 1) & 0xFFE) / 2); - for (i = 0; i < no_of_entries; i++) { - //if (states[i] == 0) - if (ctx->output_table[states[i]].no_of_entries == 0) - continue; - - states[i] |= (1 << 15); - } - } - - } else { - uint32_t *states; - for (state = 0; state < ctx->state_count; state++) { - no_of_entries = *((uint32_t *)ctx->goto_table_mod_pointers[state]); - if (no_of_entries == 0) - continue; - - //if (*((uint32_t *)ctx->goto_table_mod_pointers[state] + 1) != 0) { - if (ctx->output_table[((uint32_t *)ctx->goto_table_mod_pointers[state] + 1)[0]].no_of_entries != 0) { - *((uint32_t *)ctx->goto_table_mod_pointers[state] + 1) |= (1 << 24); - } - - if (state == 0) - states = ((uint32_t *)ctx->goto_table_mod_pointers[state] + 2); - else - states = ((uint32_t *)ctx->goto_table_mod_pointers[state] + 2 + ((no_of_entries + 3) & 0xFFC) / 4); - for (i = 0; i < no_of_entries; i++) { - //if (states[i] == 0) - if (ctx->output_table[states[i]].no_of_entries == 0) - continue; - - states[i] |= (1 << 24); - } - } - } - - return; -} - -static inline void SCACGfbsInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - int32_t state = 0; - uint32_t k = 0; - - for (state = 0; state < ctx->state_count; state++) { - if (ctx->output_table[state].no_of_entries == 0) - continue; - - for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { - if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { - ctx->output_table[state].pids[k] &= 0x0000FFFF; - ctx->output_table[state].pids[k] |= 1 << 16; - } - } - } - - return; -} - -/** - * \brief Process the patterns and prepare the state table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsPrepareStateTable(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - /* create the 0th state in the goto table and output_table */ - SCACGfbsInitNewState(mpm_ctx); - - /* create the goto table */ - SCACGfbsCreateGotoTable(mpm_ctx); - /* create the failure table */ - SCACGfbsCreateFailureTable(mpm_ctx); - /* create the final state(delta) table */ - SCACGfbsCreateModGotoTable(mpm_ctx); - /* club the output state presence with transition entries */ - SCACGfbsClubOutputStatePresenceWithModGotoTable(mpm_ctx); - - /* club nocase entries */ - SCACGfbsInsertCaseSensitiveEntriesForPatterns(mpm_ctx); - - /* we don't need this anymore */ - SCFree(ctx->goto_table); - ctx->goto_table = NULL; - SCFree(ctx->failure_table); - ctx->failure_table = NULL; - - return; -} - -/** - * \brief Process the patterns added to the mpm, and create the internal tables. - * - * \param mpm_ctx Pointer to the mpm context. - */ -int SCACGfbsPreparePatterns(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { - SCLogDebug("No patterns supplied to this mpm_ctx"); - return 0; - } - - /* alloc the pattern array */ - ctx->parray = (SCACGfbsPattern **)SCMalloc(mpm_ctx->pattern_cnt * - sizeof(SCACGfbsPattern *)); - if (ctx->parray == NULL) - goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - SCACGfbsPattern *node = ctx->init_hash[i], *nnode = NULL; - while(node != NULL) { - nnode = node->next; - node->next = NULL; - ctx->parray[p++] = node; - node = nnode; - } - } - - /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* the memory consumed by a single state in our goto table */ - //ctx->single_state_size = sizeof(int32_t) * 256; - - /* handle no case patterns */ - ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACGfbsPatternList)); - if (ctx->pid_pat_list == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACGfbsPatternList)); - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { - ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len); - if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs, - ctx->parray[i]->original_pat, ctx->parray[i]->len); - ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; - } - - /* ACPatternList now owns this memory */ - ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; - ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; - } - - /* prepare the state table required by AC */ - SCACGfbsPrepareStateTable(mpm_ctx); - - /* free all the stored patterns. Should save us a good 100-200 mbs */ - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - SCACGfbsFreePattern(mpm_ctx, ctx->parray[i]); - } - } - SCFree(ctx->parray); - ctx->parray = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); - - return 0; - -error: - return -1; -} - -/** - * \brief Init the mpm thread context. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - * \param matchsize We don't need this. - */ -void SCACGfbsInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - mpm_thread_ctx->ctx = SCMalloc(sizeof(SCACGfbsThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - memset(mpm_thread_ctx->ctx, 0, sizeof(SCACGfbsThreadCtx)); - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(SCACGfbsThreadCtx); - - return; -} - -/** - * \brief Initialize the AC context. - * - * \param mpm_ctx Mpm context. - * \param module_handle Cuda module handle from the cuda handler API. We don't - * have to worry about this here. - */ -void SCACGfbsInitCtx(MpmCtx *mpm_ctx) -{ - if (mpm_ctx->ctx != NULL) - return; - - mpm_ctx->ctx = SCMalloc(sizeof(SCACGfbsCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - memset(mpm_ctx->ctx, 0, sizeof(SCACGfbsCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACGfbsCtx); - - /* initialize the hash we use to speed up pattern insertions */ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(SCACGfbsPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { - exit(EXIT_FAILURE); - } - memset(ctx->init_hash, 0, sizeof(SCACGfbsPattern *) * INIT_HASH_SIZE); - - /* get conf values for AC from our yaml file. We have no conf values for - * now. We will certainly need this, as we develop the algo */ - SCACGfbsGetConfig(); - - SCReturn; -} - -/** - * \brief Destroy the mpm thread context. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - */ -void SCACGfbsDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - SCACGfbsPrintSearchStats(mpm_thread_ctx); - - if (mpm_thread_ctx->ctx != NULL) { - SCFree(mpm_thread_ctx->ctx); - mpm_thread_ctx->ctx = NULL; - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(SCACGfbsThreadCtx); - } - - return; -} - -/** - * \brief Destroy the mpm context. - * - * \param mpm_ctx Pointer to the mpm context. - */ -void SCACGfbsDestroyCtx(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCACGfbsPattern *)); - } - - if (ctx->parray != NULL) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - SCACGfbsFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - ctx->parray = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); - } - - if (ctx->goto_table_mod != NULL) { - SCFree(ctx->goto_table_mod); - ctx->goto_table_mod = NULL; - - mpm_ctx->memory_cnt--; - if (ctx->state_count < 32767) { - mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 3 + - 256 * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 2); - } else { - mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 3 + - 256 * sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 2); - } - } - - if (ctx->goto_table_mod_pointers != NULL) { - SCFree(ctx->goto_table_mod_pointers); - ctx->goto_table_mod_pointers = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= ctx->state_count * sizeof(uint8_t *); - } - - if (ctx->output_table != NULL) { - int32_t state_count; - for (state_count = 0; state_count < ctx->state_count; state_count++) { - if (ctx->output_table[state_count].pids != NULL) { - SCFree(ctx->output_table[state_count].pids); - } - } - SCFree(ctx->output_table); - } - - if (ctx->pid_pat_list != NULL) { - uint32_t i; - for (i = 0; i < (ctx->max_pat_id + 1); i++) { - if (ctx->pid_pat_list[i].cs != NULL) - SCFree(ctx->pid_pat_list[i].cs); - if (ctx->pid_pat_list[i].sids != NULL) - SCFree(ctx->pid_pat_list[i].sids); - } - SCFree(ctx->pid_pat_list); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACGfbsCtx); - - return; -} - -/** - * \brief The aho corasick search function. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - * \param pmq Pointer to the Pattern Matcher Queue to hold - * search matches. - * \param buf Buffer to be searched. - * \param buflen Buffer length. - * - * \retval matches Match count. - */ -uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - int matches = 0; - uint8_t buf_local; - - SCACGfbsPatternList *pid_pat_list = ctx->pid_pat_list; - - uint8_t bitarray[pmq->pattern_id_bitarray_size]; - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - - /* really hate the extra cmp here, but can't help it */ - if (ctx->state_count < 32767) { - /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ - int32_t temp_state; - uint16_t no_of_entries; - uint8_t *ascii_codes; - uint16_t **goto_table_mod_pointers = (uint16_t **)ctx->goto_table_mod_pointers; - - //int32_t *failure_table = ctx->failure_table; - int i; - /* \todo tried loop unrolling with register var, with no perf increase. Need - * to dig deeper */ - /* with so many var declarations the register declaration here is useless */ - register int32_t state = 0; - for (i = 0; i < buflen; i++) { - if (state == 0) { - state = (goto_table_mod_pointers[0] + 2)[u8_tolower(buf[i])]; - } else { - - /* get the goto state transition */ - no_of_entries = *(goto_table_mod_pointers[state & 0x7FFF]); - if (no_of_entries == 0) { - temp_state = SC_AC_GFBS_FAIL; - } else { - if (no_of_entries == 1) { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); - buf_local = u8_tolower(buf[i]); - if (buf_local == ascii_codes[0]) - temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[0]; - else - temp_state = SC_AC_GFBS_FAIL; - } else { - buf_local = u8_tolower(buf[i]); - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); - int low = 0; - int high = no_of_entries; - int mid; - temp_state = SC_AC_GFBS_FAIL; - while (low <= high) { - mid = (low + high) / 2; - if (ascii_codes[mid] == buf_local) { - temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[mid]; - break; - } else if (ascii_codes[mid] < buf_local) { - low = mid + 1; - } else { - high = mid - 1; - } - } - } - } - while (temp_state == SC_AC_GFBS_FAIL) { - state = *(goto_table_mod_pointers[state & 0x7FFF] + 1); - - /* get the goto state transition */ - no_of_entries = *(goto_table_mod_pointers[state & 0x7FFF]); - if (no_of_entries == 0) { - temp_state = SC_AC_GFBS_FAIL; - } else { - if (no_of_entries == 1) { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); - buf_local = u8_tolower(buf[i]); - if (buf_local == ascii_codes[0]) - temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[0]; - else - temp_state = SC_AC_GFBS_FAIL; - } else { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); - buf_local = u8_tolower(buf[i]); - if (state == 0) { - temp_state = ((uint16_t *)ascii_codes)[buf_local]; - } else { - int low = 0; - int high = no_of_entries; - int mid; - temp_state = SC_AC_GFBS_FAIL; - while (low <= high) { - mid = (low + high) / 2; - if (ascii_codes[mid] == buf_local) { - temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[mid]; - break; - } else if (ascii_codes[mid] < buf_local) { - low = mid + 1; - } else { - high = mid - 1; - } - } - } - } - } /* else - if (no_of_entries == 0) */ - } /* while (temp_state == SC_AC_GFBS_FAIL) */ - - state = temp_state; - - } - - if (state & 0x8000) { - uint32_t no_of_pid_entries = ctx->output_table[state & 0x7FFF].no_of_entries; - uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; - uint32_t k = 0; - for (k = 0; k < no_of_pid_entries; k++) { - if (pids[k] & 0xFFFF0000) { - uint32_t lower_pid = pids[k] & 0x0000FFFF; - if (SCMemcmp(pid_pat_list[lower_pid].cs, - buf + i - pid_pat_list[lower_pid].patlen + 1, - pid_pat_list[lower_pid].patlen) != 0) { - /* inside loop */ - continue; - } - - if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { - ; - } else { - bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - - MpmAddPid(pmq, lower_pid); - MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); - } - matches++; - } else { - if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { - ; - } else { - bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - - MpmAddPid(pmq, pids[k]); - MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); - } - matches++; - } - } - } /* if (ctx->output_table[state].no_of_entries != 0) */ - } /* for (i = 0; i < buflen; i++) */ - - } else { - /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ - int32_t temp_state = 0; - uint32_t no_of_entries; - uint8_t *ascii_codes = NULL; - uint32_t **goto_table_mod_pointers = (uint32_t **)ctx->goto_table_mod_pointers; - //int32_t *failure_table = ctx->failure_table; - int i = 0; - /* \todo tried loop unrolling with register var, with no perf increase. Need - * to dig deeper */ - register int32_t state = 0; - for (i = 0; i < buflen; i++) { - if (state == 0) { - state = (goto_table_mod_pointers[0] + 2)[u8_tolower(buf[i])]; - } else { - - /* get the goto state transition */ - no_of_entries = *(goto_table_mod_pointers[state & 0x00FFFFFF]); - if (no_of_entries == 0) { - temp_state = SC_AC_GFBS_FAIL; - } else { - if (no_of_entries == 1) { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); - buf_local = u8_tolower(buf[i]); - if (buf_local == ascii_codes[0]) - temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[0]; - else - temp_state = SC_AC_GFBS_FAIL; - } else { - buf_local = u8_tolower(buf[i]); - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); - int low = 0; - int high = no_of_entries; - int mid; - temp_state = SC_AC_GFBS_FAIL; - while (low <= high) { - mid = (low + high) / 2; - if (ascii_codes[mid] == buf_local) { - temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[mid]; - break; - } else if (ascii_codes[mid] < buf_local) { - low = mid + 1; - } else { - high = mid - 1; - } - } - } - } - while (temp_state == SC_AC_GFBS_FAIL) { - state = *(goto_table_mod_pointers[state & 0x00FFFFFF] + 1); - - /* get the goto state transition */ - no_of_entries = *(goto_table_mod_pointers[state & 0x00FFFFFF]); - if (no_of_entries == 0) { - temp_state = SC_AC_GFBS_FAIL; - } else { - if (no_of_entries == 1) { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); - buf_local = u8_tolower(buf[i]); - if (buf_local == ascii_codes[0]) - temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[0]; - else - temp_state = SC_AC_GFBS_FAIL; - } else { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); - buf_local = u8_tolower(buf[i]); - if (state == 0) { - temp_state = ((uint32_t *)ascii_codes)[buf_local]; - } else { - int low = 0; - int high = no_of_entries; - int mid; - temp_state = SC_AC_GFBS_FAIL; - while (low <= high) { - mid = (low + high) / 2; - if (ascii_codes[mid] == buf_local) { - temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[mid]; - break; - } else if (ascii_codes[mid] < buf_local) { - low = mid + 1; - } else { - high = mid - 1; - } - } - } - } /* else - if (no_of_entries[0] == 1) */ - } /* else - if (no_of_entries[0] == 0) */ - } /* while (temp_state == SC_AC_GFBS_FAIL) */ - state = temp_state; - - } - - if (state & 0x01000000) { - uint32_t no_of_pid_entries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; - uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; - uint32_t k = 0; - for (k = 0; k < no_of_pid_entries; k++) { - if (pids[k] & 0xFFFF0000) { - uint32_t lower_pid = pids[k] & 0x0000FFFF; - if (SCMemcmp(pid_pat_list[lower_pid].cs, - buf + i - pid_pat_list[lower_pid].patlen + 1, - pid_pat_list[lower_pid].patlen) != 0) { - /* inside loop */ - continue; - } - - if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { - ; - } else { - bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - - MpmAddPid(pmq, lower_pid); - MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); - } - matches++; - } else { - if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { - ; - } else { - bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - - MpmAddPid(pmq, pids[k]); - MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); - } - matches++; - } - //loop1: - //; - } - } /* if (ctx->output_table[state].no_of_entries != 0) */ - } /* for (i = 0; i < buflen; i++) */ - } - - return matches; -} - -/** - * \brief Add a case insensitive pattern. Although we have different calls for - * adding case sensitive and insensitive patterns, we make a single call - * for either case. No special treatment for either case. - * - * \param mpm_ctx Pointer to the mpm context. - * \param pat The pattern to add. - * \param patnen The pattern length. - * \param offset Ignored. - * \param depth Ignored. - * \param pid The pattern id. - * \param sid Ignored. - * \param flags Flags associated with this pattern. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCACGfbsAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return SCACGfbsAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -/** - * \brief Add a case sensitive pattern. Although we have different calls for - * adding case sensitive and insensitive patterns, we make a single call - * for either case. No special treatment for either case. - * - * \param mpm_ctx Pointer to the mpm context. - * \param pat The pattern to add. - * \param patnen The pattern length. - * \param offset Ignored. - * \param depth Ignored. - * \param pid The pattern id. - * \param sid Ignored. - * \param flags Flags associated with this pattern. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCACGfbsAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - return SCACGfbsAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -void SCACGfbsPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ - -#ifdef SC_AC_COUNTERS - SCACGfbsThreadCtx *ctx = (SCACGfbsThreadCtx *)mpm_thread_ctx->ctx; - printf("AC Thread Search stats (ctx %p)\n", ctx); - printf("Total calls: %" PRIu32 "\n", ctx->total_calls); - printf("Total matches: %" PRIu64 "\n", ctx->total_matches); -#endif /* SC_AC_COUNTERS */ - - return; -} - -void SCACGfbsPrintInfo(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - printf("MPM AC Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeof:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" SCACGfbsCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACGfbsCtx)); - printf(" SCACGfbsPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACGfbsPattern)); - printf(" SCACGfbsPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACGfbsPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Total states in the state table: %" PRIu32 "\n", ctx->state_count); - printf("\n"); - - return; -} - -/*************************************Unittests********************************/ - -#ifdef UNITTESTS - -static int SCACGfbsTest01(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest02(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest03(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest04(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest05(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest06(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcd"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest07(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); - /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); - /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); - /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); - /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - 30, 0, 0, 5, 0, 0); - /* total matches: 135 */ - PmqSetup(&pmq, 6); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest08(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest09(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest10(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest11(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) - goto end; - PmqSetup(&pmq, 4); - - if (SCACGfbsPreparePatterns(&mpm_ctx) == -1) - goto end; - - result = 1; - - char *buf = "he"; - result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 1); - buf = "she"; - result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 2); - buf = "his"; - result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 1); - buf = "hers"; - result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 2); - - end: - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest12(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest13(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest14(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest15(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest16(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcdefghijklmnopqrstuvwxyzABC"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyzABC"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest17(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcdefghijklmnopqrstuvwxyzAB"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyzAB"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest18(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcde""fghij""klmno""pqrst""uvwxy""z"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest19(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 */ - char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest20(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 */ - char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest21(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest22(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest23(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"aa", 2); - - if (cnt == 0) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest24(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"aa", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest25(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest26(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "works"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - if (cnt == 1) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest27(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 0 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "tone"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest28(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 0 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "tONE"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest29(void) -{ - uint8_t *buf = (uint8_t *)"onetwothreefourfivesixseveneightnine"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->mpm_matcher = MPM_AC_GFBS; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " - "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)"); - if (de_ctx->sig_list->next == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) != 1) { - printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); - goto end; - } - if (PacketAlertCheck(p, 2) != 1) { - printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); - goto end; - } - - result = 1; -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - UTHFreePackets(&p, 1); - return result; -} - -#endif /* UNITTESTS */ - -void SCACGfbsRegisterTests(void) -{ - -#ifdef UNITTESTS - UtRegisterTest("SCACGfbsTest01", SCACGfbsTest01, 1); - UtRegisterTest("SCACGfbsTest02", SCACGfbsTest02, 1); - UtRegisterTest("SCACGfbsTest03", SCACGfbsTest03, 1); - UtRegisterTest("SCACGfbsTest04", SCACGfbsTest04, 1); - UtRegisterTest("SCACGfbsTest05", SCACGfbsTest05, 1); - UtRegisterTest("SCACGfbsTest06", SCACGfbsTest06, 1); - UtRegisterTest("SCACGfbsTest07", SCACGfbsTest07, 1); - UtRegisterTest("SCACGfbsTest08", SCACGfbsTest08, 1); - UtRegisterTest("SCACGfbsTest09", SCACGfbsTest09, 1); - UtRegisterTest("SCACGfbsTest10", SCACGfbsTest10, 1); - UtRegisterTest("SCACGfbsTest11", SCACGfbsTest11, 1); - UtRegisterTest("SCACGfbsTest12", SCACGfbsTest12, 1); - UtRegisterTest("SCACGfbsTest13", SCACGfbsTest13, 1); - UtRegisterTest("SCACGfbsTest14", SCACGfbsTest14, 1); - UtRegisterTest("SCACGfbsTest15", SCACGfbsTest15, 1); - UtRegisterTest("SCACGfbsTest16", SCACGfbsTest16, 1); - UtRegisterTest("SCACGfbsTest17", SCACGfbsTest17, 1); - UtRegisterTest("SCACGfbsTest18", SCACGfbsTest18, 1); - UtRegisterTest("SCACGfbsTest19", SCACGfbsTest19, 1); - UtRegisterTest("SCACGfbsTest20", SCACGfbsTest20, 1); - UtRegisterTest("SCACGfbsTest21", SCACGfbsTest21, 1); - UtRegisterTest("SCACGfbsTest22", SCACGfbsTest22, 1); - UtRegisterTest("SCACGfbsTest23", SCACGfbsTest23, 1); - UtRegisterTest("SCACGfbsTest24", SCACGfbsTest24, 1); - UtRegisterTest("SCACGfbsTest25", SCACGfbsTest25, 1); - UtRegisterTest("SCACGfbsTest26", SCACGfbsTest26, 1); - UtRegisterTest("SCACGfbsTest27", SCACGfbsTest27, 1); - UtRegisterTest("SCACGfbsTest28", SCACGfbsTest28, 1); - UtRegisterTest("SCACGfbsTest29", SCACGfbsTest29, 1); -#endif - - return; -} diff --git a/src/util-mpm-ac-gfbs.h b/src/util-mpm-ac-gfbs.h deleted file mode 100644 index 521c8db03530..000000000000 --- a/src/util-mpm-ac-gfbs.h +++ /dev/null @@ -1,110 +0,0 @@ -/* 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 Anoop Saldanha - * - */ - -#define SC_AC_GFBS_STATE_TYPE_U16 uint16_t -#define SC_AC_GFBS_STATE_TYPE_U32 uint32_t - -typedef struct SCACGfbsPattern_ { - /* length of the pattern */ - uint16_t len; - /* flags decribing the pattern */ - uint8_t flags; - /* holds the original pattern that was added */ - uint8_t *original_pat; - /* case sensitive */ - uint8_t *cs; - /* case INsensitive */ - uint8_t *ci; - /* pattern id */ - uint32_t id; - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; - - struct SCACGfbsPattern_ *next; -} SCACGfbsPattern; - -typedef struct SCACGfbsPatternList_ { - uint8_t *cs; - uint16_t patlen; - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; -} SCACGfbsPatternList; - -typedef struct SCACGfbsOutputTable_ { - /* list of pattern sids */ - uint32_t *pids; - /* no of entries we have in pids */ - uint32_t no_of_entries; -} SCACGfbsOutputTable; - -typedef struct SCACGfbsGotoTableMod_ { - /* each of these below declarations will be of type uint32_t, if the state - * count exceeds 65535, the maximum value a 16 bit unsigned var can hold */ - - /* no of entries stored below */ - uint16_t no_of_entries; - - /* the ascii codes over which we have state transitions */ - uint16_t *ascii_codes; - /* the states that correspond to the ascii_codes above */ - uint16_t *states; -} SCACGfbsGotoTableMod_; - -typedef struct SCACGfbsCtx_ { - /* hash used during ctx initialization */ - SCACGfbsPattern **init_hash; - - /* pattern arrays. We need this only during the goto table creation phase */ - SCACGfbsPattern **parray; - - /* no of states used by ac */ - int32_t state_count; - /* the modified goto_table */ - uint8_t *goto_table_mod; - uint8_t **goto_table_mod_pointers; - - /* goto_table, failure table and output table. Needed to create state_table. - * Will be freed, once we have created the goto_table_mod */ - int32_t (*goto_table)[256]; - int32_t *failure_table; - SCACGfbsOutputTable *output_table; - SCACGfbsPatternList *pid_pat_list; - - /* the size of each state */ - uint16_t single_state_size; - uint32_t max_pat_id; -} SCACGfbsCtx; - -typedef struct SCACGfbsThreadCtx_ { - /* the total calls we make to the search function */ - uint32_t total_calls; - /* the total patterns that we ended up matching against */ - uint64_t total_matches; -} SCACGfbsThreadCtx; - -void MpmACGfbsRegister(void); diff --git a/src/util-mpm-b2g.c b/src/util-mpm-b2g.c deleted file mode 100644 index f71728391015..000000000000 --- a/src/util-mpm-b2g.c +++ /dev/null @@ -1,2832 +0,0 @@ -/* 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 - * - * Implementation of the SBNDMq pattern matching algorithm. - * - * Ideas: - * - B2g does a full match in the search of up to 'm' characters, - * in case of a case insensitive search we could say it's match if - * the pattern is of len 'm' or just compare the rest of the chars. - * - * \todo Try to get the S0 calculation right. - */ - -//#define PRINTMATCH - -#include "suricata-common.h" -#include "suricata.h" -#include "detect.h" -#include "util-bloomfilter.h" -#include "util-mpm-b2g.h" -#include "util-print.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-memcmp.h" -#include "util-memcpy.h" -#include "conf.h" - -#define INIT_HASH_SIZE 65536 - -#ifdef B2G_COUNTERS -#define COUNT(counter) \ - (counter) -#else -#define COUNT(counter) -#endif /* B2G_COUNTERS */ - -static uint32_t b2g_hash_size = 0; -static uint32_t b2g_bloom_size = 0; -static uint8_t b2g_hash_shift = 0; -static void *b2g_func; - -#define B2G_HASH16(a,b) (((a) << b2g_hash_shift) | (b)) - -void B2gInitCtx (MpmCtx *); -void B2gThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); -void B2gDestroyCtx(MpmCtx *); -void B2gThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); -int B2gAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags); -int B2gAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags); -int B2gPreparePatterns(MpmCtx *mpm_ctx); -uint32_t B2gSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#ifdef B2G_SEARCH2 -uint32_t B2gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#endif -uint32_t B2gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); -void B2gPrintInfo(MpmCtx *mpm_ctx); -void B2gPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void B2gRegisterTests(void); - -void MpmB2gRegister (void) -{ - mpm_table[MPM_B2G].name = "b2g"; - mpm_table[MPM_B2G].max_pattern_length = B2G_WORD_SIZE; - - mpm_table[MPM_B2G].InitCtx = B2gInitCtx; - mpm_table[MPM_B2G].InitThreadCtx = B2gThreadInitCtx; - mpm_table[MPM_B2G].DestroyCtx = B2gDestroyCtx; - mpm_table[MPM_B2G].DestroyThreadCtx = B2gThreadDestroyCtx; - mpm_table[MPM_B2G].AddPattern = B2gAddPatternCS; - mpm_table[MPM_B2G].AddPatternNocase = B2gAddPatternCI; - mpm_table[MPM_B2G].Prepare = B2gPreparePatterns; - mpm_table[MPM_B2G].Search = B2gSearchWrap; - mpm_table[MPM_B2G].Cleanup = NULL; - mpm_table[MPM_B2G].PrintCtx = B2gPrintInfo; - mpm_table[MPM_B2G].PrintThreadCtx = B2gPrintSearchStats; - mpm_table[MPM_B2G].RegisterUnittests = B2gRegisterTests; -} - -#ifdef PRINTMATCH -static void prt (uint8_t *buf, uint16_t buflen) -{ - uint16_t i; - - for (i = 0; i < buflen; i++) { - if (isprint(buf[i])) printf("%c", buf[i]); - else printf("\\x%02X", buf[i]); - } - //printf("\n"); -} -#endif - -void B2gPrintInfo(MpmCtx *mpm_ctx) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - - printf("MPM B2g Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeofs:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" B2gCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gCtx)); - printf(" B2gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gPattern)); - printf(" B2gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Hash size: %" PRIu32 "\n", ctx->hash_size); - printf("\n"); -} - -/** - * \brief B2gAllocPattern allocates a new pattern structure - * and initialize the data - * \initonly - */ -static inline B2gPattern *B2gAllocPattern(MpmCtx *mpm_ctx) -{ - B2gPattern *p = SCMalloc(sizeof(B2gPattern)); - if (unlikely(p == NULL)) - return NULL; - memset(p,0,sizeof(B2gPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gPattern); - return p; -} - -static inline B2gPattern * -B2gAllocHashItem(MpmCtx *mpm_ctx) -{ - B2gPattern *hi = SCMalloc(sizeof(B2gPattern)); - if (unlikely(hi == NULL)) - return NULL; - memset(hi,0,sizeof(B2gPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gPattern); - return hi; -} - -static void B2gHashFree(MpmCtx *mpm_ctx, B2gPattern *hi) -{ - if (hi == NULL) - return; - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gPattern); - B2gPattern *t = hi->next; - SCFree(hi); - - B2gHashFree(mpm_ctx, t); -} - -/* - * INIT HASH START - */ -static inline uint32_t B2gInitHash(B2gPattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline uint32_t B2gInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int B2gInitHashAdd(B2gCtx *ctx, B2gPattern *p) -{ - uint32_t hash = B2gInitHash(p); - - //printf("B2gInitHashAdd: %" PRIu32 "\n", hash); - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - //printf("B2gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - return 0; - } - - B2gPattern *tt = NULL; - B2gPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - //printf("B2gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - return 0; -} - -static inline int B2gCmpPattern(B2gPattern *p, uint8_t *pat, uint16_t patlen, char flags); - -static inline B2gPattern *B2gInitHashLookup(B2gCtx *ctx, uint8_t *pat, uint16_t patlen, char flags, - uint32_t pid) -{ - uint32_t hash = B2gInitHashRaw(pat,patlen); - - //printf("B2gInitHashLookup: %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - - if (ctx->init_hash[hash] == NULL) { - return NULL; - } - - B2gPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - //if (B2gCmpPattern(t,pat,patlen,flags) == 1) - if (t->id == pid) - return t; - } - - return NULL; -} - -static inline int B2gCmpPattern(B2gPattern *p, uint8_t *pat, uint16_t patlen, char flags) -{ - if (p->len != patlen) - return 0; - - if (p->flags != flags) - return 0; - - if (SCMemcmp(p->cs, pat, patlen) != 0) - return 0; - - return 1; -} - -/* - * INIT HASH END - */ - -void B2gFreePattern(MpmCtx *mpm_ctx, B2gPattern *p) -{ - if (p && p->cs && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p && p->ci) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p && p->sids) { - SCFree(p->sids); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->sids_size * sizeof(SigIntId); - } - - if (p) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gPattern); - } -} - -/** \internal - * \brief add a pattern to the mpm/b2g context - * - * \param pat ptr to the pattern - * \param patlen length of the pattern - * \param pid pattern id - * \param sid signature id (internal id) - * \param flags pattern MPM_PATTERN_* flags - * - * \initonly - */ -static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - - SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); - - if (patlen == 0) - return 0; - - /* get a memory piece */ - B2gPattern *p = B2gInitHashLookup(ctx, pat, patlen, flags, pid); - if (p == NULL) { - SCLogDebug("allocing new pattern"); - - p = B2gAllocPattern(mpm_ctx); - if (p == NULL) - goto error; - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - /* setup the case insensitive part of the pattern */ - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (SCMemcmp(p->ci,pat,p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); - BUG_ON(p->sids == NULL); - p->sids[0] = sid; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SigIntId); - - //printf("B2gAddPattern: ci \""); prt(p->ci,p->len); - //printf("\" cs \""); prt(p->cs,p->len); - //printf("\"\n"); - - /* put in the pattern hash */ - B2gInitHashAdd(ctx, p); - - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; - } else { - /* Multiple sids for the same pid, so keep an array of sids. */ - - /* TODO figure out how we can be called multiple times for the - * same CTX with the same sid */ - int found = 0; - uint32_t x = 0; - for (x = 0; x < p->sids_size; x++) { - if (p->sids[x] == sid) { - found = 1; - break; - } - } - if (!found) { - SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); - BUG_ON(sids == NULL); - p->sids = sids; - p->sids[p->sids_size] = sid; - p->sids_size++; - mpm_ctx->memory_size += sizeof(SigIntId); - } - } - - return 0; - -error: - B2gFreePattern(mpm_ctx, p); - return -1; -} - -int B2gAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return B2gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -int B2gAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) -{ - return B2gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -static inline uint32_t B2gBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint16_t i; - uint32_t hash = (uint32_t)u8_tolower(*d); - - for (i = 1; i < datalen; i++) { - d++; - hash += (u8_tolower(*d)) ^ i; - } - hash <<= (iter+1); - - hash %= hash_size; - return hash; -} - -static void B2gPrepareHash(MpmCtx *mpm_ctx) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - uint16_t i; - uint16_t idx = 0; - uint8_t idx8 = 0; - - ctx->hash = (B2gPattern **)SCMalloc(sizeof(B2gPattern *) * ctx->hash_size); - if (ctx->hash == NULL) - goto error; - memset(ctx->hash, 0, sizeof(B2gPattern *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2gPattern *) * ctx->hash_size); - -#ifdef B2G_SEARCH2 - ctx->hash2 = (B2gPattern **)SCMalloc(sizeof(B2gPattern *) * ctx->hash_size); - if (ctx->hash2 == NULL) - goto error; - memset(ctx->hash2, 0, sizeof(B2gPattern *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2gPattern *) * ctx->hash_size); -#endif - - /* alloc the pminlen array */ - ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); - if (ctx->pminlen == NULL) - goto error; - memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) - { - if(ctx->parray[i]->len == 1) { - idx8 = (uint8_t)ctx->parray[i]->ci[0]; - if (ctx->hash1[idx8].flags == 0) { - ctx->hash1[idx8].flags |= MPM_PATTERN_ONE_BYTE; - - B2gPattern *hi = &ctx->hash1[idx8]; - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->ci = ctx->parray[i]->ci; - hi->cs = ctx->parray[i]->cs; - hi->sids = ctx->parray[i]->sids; - hi->sids_size = ctx->parray[i]->sids_size; - - } else { - B2gPattern *hi = B2gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->flags |= MPM_PATTERN_ONE_BYTE; - - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->ci = ctx->parray[i]->ci; - hi->cs = ctx->parray[i]->cs; - hi->sids = ctx->parray[i]->sids; - hi->sids_size = ctx->parray[i]->sids_size; - - /* Append this HashItem to the list */ - B2gPattern *thi = &ctx->hash1[idx8]; - while (thi->next) thi = thi->next; - thi->next = hi; - } - ctx->pat_1_cnt++; -#ifdef B2G_SEARCH2 - } else if(ctx->parray[i]->len == 2) { - idx = B2G_HASH16(ctx->parray[i]->ci[0],ctx->parray[i]->ci[1]); - if (ctx->hash2[idx] == NULL) { - B2gPattern *hi = B2gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= MPM_PATTERN_ONE_BYTE; - - ctx->hash2[idx] = hi; - } else { - B2gPattern *hi = B2gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= MPM_PATTERN_ONE_BYTE; - - /* Append this HashItem to the list */ - B2gPattern *thi = ctx->hash2[idx]; - while (thi->next) thi = thi->next; - thi->next = hi; - } - ctx->pat_2_cnt++; -#endif - } else { - idx = B2G_HASH16(ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); - SCLogDebug("idx %" PRIu32 ", %c.%c", idx, ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); - - if (ctx->hash[idx] == NULL) { - B2gPattern *hi = B2gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - - ctx->pminlen[idx] = ctx->parray[i]->len; - - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->ci = ctx->parray[i]->ci; - hi->cs = ctx->parray[i]->cs; - hi->sids = ctx->parray[i]->sids; - hi->sids_size = ctx->parray[i]->sids_size; - - ctx->hash[idx] = hi; - } else { - B2gPattern *hi = B2gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - - hi->flags |= MPM_PATTERN_ONE_BYTE; - - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->ci = ctx->parray[i]->ci; - hi->cs = ctx->parray[i]->cs; - hi->sids = ctx->parray[i]->sids; - hi->sids_size = ctx->parray[i]->sids_size; - - if (ctx->parray[i]->len < ctx->pminlen[idx]) - ctx->pminlen[idx] = ctx->parray[i]->len; - - /* Append this HashItem to the list */ - B2gPattern *thi = ctx->hash[idx]; - while (thi->next) thi = thi->next; - thi->next = hi; - } - ctx->pat_x_cnt++; - } - } - - /* alloc the bloom array */ - ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); - if (ctx->bloom == NULL) - goto error; - memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); - - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - B2gPattern *hi = ctx->hash[h]; - if (hi == NULL) - continue; - - ctx->bloom[h] = BloomFilterInit(b2g_bloom_size, 2, B2gBloomHash); - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[h]); - - if (ctx->pminlen[h] > 8) - ctx->pminlen[h] = 8; - - B2gPattern *thi = hi; - do { - SCLogDebug("adding \"%c%c\" to the bloom", thi->ci[0], thi->ci[1]); - BloomFilterAdd(ctx->bloom[h], thi->ci, ctx->pminlen[h]); - thi = thi->next; - } while (thi != NULL); - } - - return; -error: - return; -} - -int B2gBuildMatchArray(MpmCtx *mpm_ctx) -{ - SCEnter(); - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - - ctx->B2G = SCMalloc(sizeof(B2G_TYPE) * ctx->hash_size); - if (ctx->B2G == NULL) - return -1; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2G_TYPE) * ctx->hash_size); - - memset(ctx->B2G,0, b2g_hash_size * sizeof(B2G_TYPE)); - - uint32_t j; - uint32_t a; - - /* fill the match array */ - for (j = 0; j <= (ctx->m - B2G_Q); j++) { - for (a = 0; a < mpm_ctx->pattern_cnt; a++) { - if (ctx->parray[a]->len < ctx->m) - continue; - - uint16_t h = B2G_HASH16(u8_tolower(ctx->parray[a]->ci[j]),u8_tolower(ctx->parray[a]->ci[j+1])); - ctx->B2G[h] = ctx->B2G[h] | (1 << (ctx->m - j)); - - SCLogDebug("h %"PRIu16", ctx->B2G[h] %"PRIu32"", h, ctx->B2G[h]); - } - } - - ctx->s0 = 1; - SCReturnInt(0); -} - -int B2gPreparePatterns(MpmCtx *mpm_ctx) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - - /* alloc the pattern array */ - ctx->parray = (B2gPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B2gPattern *)); - if (ctx->parray == NULL) - goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B2gPattern *)); - //printf("mpm_ctx %p, parray %p\n", mpm_ctx,ctx->parray); - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B2gPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - B2gPattern *node = ctx->init_hash[i], *nnode = NULL; - for ( ; node != NULL; ) { - nnode = node->next; - node->next = NULL; - - ctx->parray[p] = node; - - p++; - node = nnode; - } - } - /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* set 'm' to the smallest pattern size */ - ctx->m = mpm_ctx->minlen; - - /* make sure 'm' stays in bounds - m can be max WORD_SIZE - 1 */ - if (ctx->m >= B2G_WORD_SIZE) { - ctx->m = B2G_WORD_SIZE - 1; - } - if (ctx->m < 2) ctx->m = 2; - - ctx->hash_size = b2g_hash_size; - B2gPrepareHash(mpm_ctx); - B2gBuildMatchArray(mpm_ctx); - - SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); - if (ctx->pat_1_cnt) { - ctx->Search = B2gSearch1; -#ifdef B2G_SEARCH2 - ctx->Search = B2gSearch2; - if (ctx->pat_2_cnt) { - ctx->MBSearch2 = B2gSearch2; - } -#endif - ctx->MBSearch = b2g_func; -#ifdef B2G_SEARCH2 - } else if (ctx->pat_2_cnt) { - ctx->Search = B2gSearch2; - ctx->MBSearch = b2g_func; -#endif - } - - return 0; -error: - return -1; -} - -void B2gPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ -#ifdef B2G_COUNTERS - B2gThreadCtx *tctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; - - printf("B2g Thread Search stats (tctx %p)\n", tctx); - printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); - printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); - printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); - printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); - printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); - printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); - printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); - printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); - printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); - printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); - printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", tctx->stat_bloom_calls ? (float)((float)((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls)*(float)100) : 0, tctx->stat_bloom_hits); - printf("Avg pminlen: %0.2f\n\n", tctx->stat_pminlen_calls ? (float)((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls) : 0); -#endif /* B2G_COUNTERS */ -} - -/** - * \brief Function to get the user defined values for b2g algorithm from the - * config file 'suricata.yaml' - */ -static void B2gGetConfig() -{ - ConfNode *b2g_conf; - const char *hash_val = NULL; - const char *bloom_val = NULL; - const char *algo = NULL; - - /* init defaults */ - b2g_hash_size = HASHSIZE_LOW; - b2g_bloom_size = BLOOMSIZE_MEDIUM; - b2g_hash_shift = B2G_HASHSHIFT_LOW; - b2g_func = B2G_SEARCHFUNC; - - ConfNode *pm = ConfGetNode("pattern-matcher"); - - if (pm != NULL) { - - TAILQ_FOREACH(b2g_conf, &pm->head, next) { - if (strcmp(b2g_conf->val, "b2g") == 0) { - - algo = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "algo"); - hash_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "hash_size"); - bloom_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "bf_size"); - - if (algo != NULL) { - if (strcmp(algo, "B2gSearch") == 0) { - b2g_func = B2gSearch; - } else if (strcmp(algo, "B2gSearchBNDMq") == 0) { - b2g_func = B2gSearchBNDMq; - } - } - - if (hash_val != NULL) { - b2g_hash_size = MpmGetHashSize(hash_val); - switch (b2g_hash_size) { - case HASHSIZE_LOWEST: - b2g_hash_shift = B2G_HASHSHIFT_LOWEST; - break; - case HASHSIZE_LOW: - b2g_hash_shift = B2G_HASHSHIFT_LOW; - break; - case HASHSIZE_MEDIUM: - b2g_hash_shift = B2G_HASHSHIFT_MEDIUM; - break; - case HASHSIZE_HIGH: - b2g_hash_shift = B2G_HASHSHIFT_HIGH; - break; - case HASHSIZE_HIGHER: - b2g_hash_shift = B2G_HASHSHIFT_HIGHER; - break; - case HASHSIZE_MAX: - b2g_hash_shift = B2G_HASHSHIFT_MAX; - break; - } - } - - if (bloom_val != NULL) - b2g_bloom_size = MpmGetBloomSize(bloom_val); - - SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", - b2g_hash_size, b2g_bloom_size); - } - } - } -} - -void B2gInitCtx (MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); - - if (mpm_ctx->ctx != NULL) - return; - - //BUG_ON(mpm_ctx->ctx != NULL); - - mpm_ctx->ctx = SCMalloc(sizeof(B2gCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_ctx->ctx, 0, sizeof(B2gCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gCtx); - - /* initialize the hash we use to speed up pattern insertions */ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(B2gPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { - exit(EXIT_FAILURE); - } - - memset(ctx->init_hash, 0, sizeof(B2gPattern *) * INIT_HASH_SIZE); - - /* Initialize the defaults value from the config file. The given check make - sure that we query config file only once for config values */ - if (b2g_hash_size == 0) - B2gGetConfig(); - - /* init defaults search functions */ - ctx->Search = b2g_func; - - SCReturn; -} - -void B2gDestroyCtx(MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p", mpm_ctx); - - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash) { - SCFree(ctx->init_hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B2gPattern *)); - } - - if (ctx->parray) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - B2gFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B2gPattern)); - } - - if (ctx->B2G) { - SCFree(ctx->B2G); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2G_TYPE) * ctx->hash_size); - } - - if (ctx->bloom) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); - - BloomFilterFree(ctx->bloom[h]); - } - - SCFree(ctx->bloom); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); - } - - if (ctx->hash) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->hash[h] == NULL) - continue; - - B2gHashFree(mpm_ctx, ctx->hash[h]); - } - - SCFree(ctx->hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2gPattern) * ctx->hash_size); - } - - if (ctx->pminlen) { - SCFree(ctx->pminlen); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gCtx); -} - -void B2gThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - if (sizeof(B2gThreadCtx) > 0) { /* size can be null when optimized */ - mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_thread_ctx->ctx, 0, sizeof(B2gThreadCtx)); - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(B2gThreadCtx); - } -} - -void B2gThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - B2gThreadCtx *ctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; - - B2gPrintSearchStats(mpm_thread_ctx); - - if (ctx != NULL) { /* can be NULL if B2gThreadCtx is optimized to 0 */ - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(B2gThreadCtx); - SCFree(mpm_thread_ctx->ctx); - } -} - -uint32_t B2gSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; -} - -uint32_t B2gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; -#ifdef B2G_COUNTERS - B2gThreadCtx *tctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = ctx->m - B2G_Q + 1, matches = 0; - B2G_TYPE d; - - //printf("\n"); - //PrintRawDataFp(stdout, buf, buflen); - - SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32"", buflen, - ctx->m, pos); - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (pos <= (uint32_t)(buflen - B2G_Q + 1)) { - uint16_t h = B2G_HASH16(u8_tolower(buf[pos - 1]),u8_tolower(buf[pos])); - d = ctx->B2G[h]; - - if (d != 0) { - COUNT(tctx->stat_d0++); - uint32_t j = pos; - uint32_t first = pos - (ctx->m - B2G_Q + 1); - - do { - j = j - 1; - - if (d >= (uint32_t)(1 << (ctx->m - 1))) { - if (j > first) pos = j; - else { - /* get our patterns from the hash */ - h = B2G_HASH16(u8_tolower(buf[j + ctx->m - 2]),u8_tolower(buf[j + ctx->m - 1])); - - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((buflen - j) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf+j, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - - SCLogDebug("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "", - ctx->bloom[h], buflen, pos, ctx->pminlen[h]); - goto skip_loop; - } - } - } - - B2gPattern *hi = ctx->hash[h], *thi; - for (thi = hi; thi != NULL; thi = thi->next) { - COUNT(tctx->stat_d0_hashloop++); - if ((buflen - j) < thi->len) { - continue; - } - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - - //if (memcmp_lowercase(thi->ci, buf+j, thi->len) == 0) { - if (SCMemcmpLowercase(thi->ci, buf+j, thi->len) == 0) { -#ifdef PRINTMATCH - printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); -#endif - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, - bitarray, thi->sids, thi->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (SCMemcmp(thi->cs, buf+j, thi->len) == 0) { - //if (memcmp(thi->cs, buf+j, thi->len) == 0) { -#ifdef PRINTMATCH - printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); -#endif - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, - bitarray, thi->sids, thi->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } -skip_loop: - SCLogDebug("skipped"); - //SCLogDebug("output at pos %" PRIu32 ": ", j); prt(buf + (j), ctx->m); printf("\n"); - ; - } - } - - if (j == 0) { - break; - } - - h = B2G_HASH16(u8_tolower(buf[j - 1]),u8_tolower(buf[j])); - d = (d << 1) & ctx->B2G[h]; - } while (d != 0); - } - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (ctx->m - B2G_Q + 1)); - pos = pos + ctx->m - B2G_Q + 1; - - SCLogDebug("pos %"PRIu32"", pos); - } - - SCLogDebug("matches %"PRIu32"", matches); - return matches; -} - -uint32_t B2gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; -#ifdef B2G_COUNTERS - B2gThreadCtx *tctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = 0, matches = 0; - B2G_TYPE d; - uint32_t j; - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (pos <= (buflen - ctx->m)) { - j = ctx->m - 1; - d = ~0; - - do { - uint16_t h = B2G_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); - d = ((d << 1) & ctx->B2G[h]); - j = j - 1; - } while (d != 0 && j != 0); - - /* (partial) match, move on to verification */ - if (d != 0) { - COUNT(tctx->stat_d0++); - //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); - - /* get our patterns from the hash */ - uint16_t h = B2G_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); - - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((buflen - pos) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf+pos, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - - //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); - goto skip_loop; - } - } - } - - B2gPattern *hi = ctx->hash[h], *thi; - for (thi = hi; thi != NULL; thi = thi->next) { - COUNT(tctx->stat_d0_hashloop++); - //B2gPattern *p = ctx->parray[thi->idx]; - - if (buflen - pos < thi->len) - continue; - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - - if (SCMemcmpLowercase(thi->ci, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, - bitarray, thi->sids, thi->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (SCMemcmp(thi->cs, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, - bitarray, thi->sids, thi->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } -skip_loop: - //pos = pos + ctx->s0; - pos = pos + 1; - } else { - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (j + 1)); - - pos = pos + j + 1; - } - } - - //printf("Total matches %" PRIu32 "\n", matches); - return matches; -} - -#ifdef B2G_SEARCH2 -uint32_t B2gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - B2gPattern *p; - B2gPattern *thi, *hi; - - if (buflen < 2) - return 0; - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (buf <= bufend) { - uint8_t h8 = u8_tolower(*buf); - hi = &ctx->hash1[h8]; - - if (hi->flags & MPM_PATTERN_ONE_BYTE) { - for (thi = hi; thi != NULL; thi = thi->next) { - p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (h8 == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, - bitarray, thi->sids, thi->sids_size); - } - } else { - if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, - bitarray, thi->sids, thi->sids_size); - } - } - } - } - - /* save one conversion by reusing h8 */ - uint16_t h16 = B2G_HASH16(h8, u8_tolower(*(buf+1))); - hi = ctx->hash2[h16]; - - for (thi = hi; thi != NULL; thi = thi->next) { - p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (h8 == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { - //printf("CI Exact match: "); prt(p->ci, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B2gSearch1)\n"); -// for (em = p->em; em; em = em->next) { - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size)) - cnt++; -// } - } - } else { - if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { - //printf("CS Exact match: "); prt(p->cs, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B2gSearch1)\n"); -// for (em = p->em; em; em = em->next) { - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size)) - cnt++; -// } - } - } - } - buf += 1; - } - - //printf("B2gSearch2: after 2byte cnt %" PRIu32 "\n", cnt); - if (ctx->pat_x_cnt > 0) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - //printf("B2gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); - } - return cnt; -} -#endif - -uint32_t B2gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - SCEnter(); - - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; -// B2gPattern *p; - B2gPattern *thi, *hi; - - if (buflen == 0) - SCReturnUInt(0); - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (buf <= bufend) { - uint8_t h = u8_tolower(*buf); - hi = &ctx->hash1[h]; - - for (thi = hi; thi != NULL; thi = thi->next) { - if (hi->flags & MPM_PATTERN_ONE_BYTE) { - if (thi->len != 1) - continue; - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - if (u8_tolower(*buf) == thi->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, bitarray, thi->sids, thi->sids_size); - } - } else { - if (*buf == thi->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id, bitarray, thi->sids, thi->sids_size); - } - } - } - } - buf += 1; - } - - //printf("B2gSearch1: after 1byte cnt %" PRIu32 "\n", cnt); -#ifdef B2G_SEARCH2 - if (ctx->pat_2_cnt) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch2(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - //printf("B2gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); - } else -#endif - if (ctx->pat_x_cnt) { - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - } - SCReturnUInt(cnt); -} - -/* - * TESTS - */ - -#ifdef UNITTESTS -static int B2gTestInit01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->m == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->m); - - B2gDestroyCtx(&mpm_ctx); - return result; -} - -#if 0 -static int B2gTestS0Init01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->s0); - - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestS0Init02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestS0Init03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", ctx->s0); - - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestS0Init04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestS0Init05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", ctx->s0); - - B2gDestroyCtx(&mpm_ctx); - return result; -} -#endif - -static int B2gTestSearch01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -/* test patterns longer than 'm'. M is 4 here. */ -static int B2gTestSearch04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -/* case insensitive test patterns longer than 'm'. M is 4 here. */ -static int B2gTestSearch05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch05a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abCD", 4, 0, 0, 3, 0, 0); /* no match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 4, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 5, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 5) - result = 1; - else - printf("5 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch07 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch08 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch09 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch10 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch11 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch13 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch17 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch18 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch19 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 0, 0, 0); /* 1 */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch20 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32, 0, 0, 0, 0, 0); /* 1 */ - //MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32, 0, 0, 0, 0, 0); /* 1 */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - //uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32); - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch21 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); /* 1 */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} -#endif /* UNITTESTS */ - -#if 0 -static int B2gTestSearchXX (void) -{ - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - FILE *fp = fopen("/usr/share/dict/words", "r"); - if (fp == NULL) - exit(1); - - char *word; - char line[128]; - int w = 0; - int w_max = 4000; - - while((word = fgets(line, sizeof(line), fp)) != NULL) { - word[strlen(word) - 1] = '\0'; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)word, strlen(word), 0, 0, (uint32_t)w, 0, 0); - - w++; - - if (w_max == w) - break; - } - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - char *text = "Yes this is a text, it is not very long. But, it is still sufficient for testing our search! " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "Bjdhfahflkahsf;phf[hfihasfkhsfkjhalhflkafljhfkhakhfkahfkahfkjhdkffkjhafkhafkjakjfhkjahf;aj;jh"; - uint32_t len = strlen(text) - 1; - - int i; - uint32_t cnt; - for (i = 0; i < 100; i++) { - cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); - } - - printf("cnt %u ", cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - fclose(fp); - - return 1; -} -#endif - -void B2gRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("B2gTestInit01", B2gTestInit01, 1); -/* - UtRegisterTest("B2gTestS0Init01", B2gTestS0Init01, 1); - UtRegisterTest("B2gTestS0Init02", B2gTestS0Init02, 1); - UtRegisterTest("B2gTestS0Init03", B2gTestS0Init03, 1); - UtRegisterTest("B2gTestS0Init04", B2gTestS0Init04, 1); - UtRegisterTest("B2gTestS0Init05", B2gTestS0Init05, 1); -*/ - UtRegisterTest("B2gTestSearch01", B2gTestSearch01, 1); - UtRegisterTest("B2gTestSearch02", B2gTestSearch02, 1); - UtRegisterTest("B2gTestSearch03", B2gTestSearch03, 1); - UtRegisterTest("B2gTestSearch04", B2gTestSearch04, 1); - UtRegisterTest("B2gTestSearch05", B2gTestSearch05, 1); - UtRegisterTest("B2gTestSearch05a", B2gTestSearch05a, 1); - UtRegisterTest("B2gTestSearch06", B2gTestSearch06, 1); - UtRegisterTest("B2gTestSearch07", B2gTestSearch07, 1); - UtRegisterTest("B2gTestSearch08", B2gTestSearch08, 1); - UtRegisterTest("B2gTestSearch09", B2gTestSearch09, 1); - UtRegisterTest("B2gTestSearch10", B2gTestSearch10, 1); - UtRegisterTest("B2gTestSearch11", B2gTestSearch11, 1); - UtRegisterTest("B2gTestSearch12", B2gTestSearch12, 1); - UtRegisterTest("B2gTestSearch13", B2gTestSearch13, 1); - UtRegisterTest("B2gTestSearch14", B2gTestSearch14, 1); - UtRegisterTest("B2gTestSearch15", B2gTestSearch15, 1); - UtRegisterTest("B2gTestSearch16", B2gTestSearch16, 1); - UtRegisterTest("B2gTestSearch17", B2gTestSearch17, 1); - UtRegisterTest("B2gTestSearch18", B2gTestSearch18, 1); - UtRegisterTest("B2gTestSearch19", B2gTestSearch19, 1); - UtRegisterTest("B2gTestSearch20", B2gTestSearch20, 1); - UtRegisterTest("B2gTestSearch21", B2gTestSearch21, 1); -// UtRegisterTest("B2gTestSearchXX", B2gTestSearchXX, 1); -#endif /* UNITTESTS */ -} - diff --git a/src/util-mpm-b2g.h b/src/util-mpm-b2g.h deleted file mode 100644 index b3b59b092124..000000000000 --- a/src/util-mpm-b2g.h +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright (C) 2007-2010 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 - */ - -#ifndef __UTIL_MPM_B2G_H__ -#define __UTIL_MPM_B2G_H__ - -#include "util-mpm.h" -#include "util-bloomfilter.h" - -#define B2G_HASHSHIFT_MAX 8 -#define B2G_HASHSHIFT_HIGHER 7 -#define B2G_HASHSHIFT_HIGH 6 -#define B2G_HASHSHIFT_MEDIUM 5 -#define B2G_HASHSHIFT_LOW 4 -#define B2G_HASHSHIFT_LOWEST 3 - -//#define B2G_TYPE uint64_t -#define B2G_TYPE uint32_t -//#define B2G_TYPE uint16_t -//#define B2G_TYPE uint8_t -//#define B2G_WORD_SIZE 64 -#define B2G_WORD_SIZE 32 -//#define B2G_WORD_SIZE 16 -//#define B2G_WORD_SIZE 8 - -#define B2G_Q 2 - -#define B2G_SEARCHFUNC B2gSearchBNDMq -//#define B2G_SEARCHFUNC B2gSearch - -//#define B2G_SEARCH2 -//#define B2G_COUNTERS - -typedef struct B2gPattern_ { - uint16_t len; /**< \todo we're limited to 32/64 byte lengths, uint8_t would be fine here */ - uint8_t flags; - uint8_t pad0; - uint32_t id; - uint8_t *original_pat; - uint8_t *ci; /* case INsensitive */ - uint8_t *cs; /* case sensitive */ - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; - - struct B2gPattern_ *next; -} B2gPattern; - -typedef struct B2gCtx_ { - B2G_TYPE *B2G; - B2G_TYPE m; - BloomFilter **bloom; - uint8_t *pminlen; /* array containing the minimal length - of the patters in a hash bucket. Used - for the BloomFilter. */ - /* pattern arrays */ - B2gPattern **parray; - - uint16_t pat_1_cnt; -#ifdef B2G_SEARCH2 - uint16_t pat_2_cnt; -#endif - uint16_t pat_x_cnt; - - uint32_t hash_size; - B2gPattern **hash; - B2gPattern hash1[256]; -#ifdef B2G_SEARCH2 - B2gHashItem **hash2; -#endif - - /* hash used during ctx initialization */ - B2gPattern **init_hash; - - uint8_t s0; - - /* we store our own multi byte search func ptr here for B2gSearch1 */ - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - /* we store our own multi byte search func ptr here for B2gSearch1 */ - uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); -} B2gCtx; - -typedef struct B2gThreadCtx_ { -#ifdef B2G_COUNTERS - uint32_t stat_pminlen_calls; - uint32_t stat_pminlen_total; - uint32_t stat_bloom_calls; - uint32_t stat_bloom_hits; - uint32_t stat_calls; - uint32_t stat_m_total; - uint32_t stat_d0; - uint32_t stat_d0_hashloop; - uint32_t stat_loop_match; - uint32_t stat_loop_no_match; - uint32_t stat_num_shift; - uint32_t stat_total_shift; -#endif /* B2G_COUNTERS */ -} B2gThreadCtx; - -void MpmB2gRegister(void); - - -#endif - diff --git a/src/util-mpm-b3g.c b/src/util-mpm-b3g.c deleted file mode 100644 index bc74bc205338..000000000000 --- a/src/util-mpm-b3g.c +++ /dev/null @@ -1,1807 +0,0 @@ -/* Copyright (C) 2007-2010 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 - * - * 3 gram implementation of the (S)BNDMq pattern matching algorithm. - * - * Ideas: - * - B3g does a full match in the search of up to 'm' characters, - * in case of a case insensitive search we could say it's match if - * the pattern is of len 'm' or just compare the rest of the chars. - * - * \todo Try to get the S0 calculation right. - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-bloomfilter.h" -#include "util-mpm-b3g.h" -#include "util-unittest.h" -#include "conf.h" -#include "util-debug.h" -#include "util-memcpy.h" - -#define INIT_HASH_SIZE 65536 - -#ifdef B3G_COUNTERS -#define COUNT(counter) \ - (counter) -#else -#define COUNT(counter) -#endif /* B3G_COUNTERS */ - -static uint32_t b3g_hash_size = 0; -static uint32_t b3g_bloom_size = 0; -static uint8_t b3g_hash_shift = 0; -static uint8_t b3g_hash_shift2 = 0; -static void *b3g_func; - -#define B3G_HASH(a,b,c) (((a) << b3g_hash_shift) | (b) << (b3g_hash_shift2) |(c)) - -void B3gInitCtx (MpmCtx *); -void B3gThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); -void B3gDestroyCtx(MpmCtx *); -void B3gThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); -int B3gAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); -int B3gAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); -int B3gPreparePatterns(MpmCtx *); -uint32_t B3gSearchWrap(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -uint32_t B3gSearch1(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -uint32_t B3gSearch2(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -uint32_t B3gSearch12(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -uint32_t B3gSearch(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -uint32_t B3gSearchBNDMq(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -void B3gPrintInfo(MpmCtx *); -void B3gPrintSearchStats(MpmThreadCtx *); -void B3gRegisterTests(void); - -/** \todo XXX Unused??? */ -#if 0 -static void prt (uint8_t *buf, uint16_t buflen) -{ - uint16_t i; - - for (i = 0; i < buflen; i++) { - if (isprint(buf[i])) printf("%c", buf[i]); - else printf("\\x%" PRIX32, buf[i]); - } - //printf("\n"); -} -#endif - -void B3gPrintInfo(MpmCtx *mpm_ctx) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - - printf("MPM B3g Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeofs:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" B3gCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B3gCtx)); - printf(" B3gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B3gPattern)); - printf(" B3gHashItem %" PRIuMAX "\n", (uintmax_t)sizeof(B3gHashItem)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Hash size: %" PRIu32 "\n", ctx->hash_size); - printf("\n"); -} - -static inline B3gPattern *B3gAllocPattern(MpmCtx *mpm_ctx) -{ - B3gPattern *p = SCMalloc(sizeof(B3gPattern)); - if (unlikely(p == NULL)) - return NULL; - memset(p,0,sizeof(B3gPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B3gPattern); - return p; -} - -static inline B3gHashItem * -B3gAllocHashItem(MpmCtx *mpm_ctx) -{ - B3gHashItem *hi = SCMalloc(sizeof(B3gHashItem)); - if (unlikely(hi == NULL)) - return NULL; - memset(hi,0,sizeof(B3gHashItem)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B3gHashItem); - return hi; -} - -static void B3gHashFree(MpmCtx *mpm_ctx, B3gHashItem *hi) -{ - if (hi == NULL) - return; - - B3gHashItem *t = hi->nxt; - B3gHashFree(mpm_ctx, t); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B3gHashItem); - SCFree(hi); -} - -/* - * INIT HASH START - */ -static inline uint32_t B3gInitHash(B3gPattern *p) -{ - uint32_t hash = p->len * p->cs[0]; - if (p->len > 1) - hash += p->cs[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline uint32_t B3gInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int B3gInitHashAdd(B3gCtx *ctx, B3gPattern *p) -{ - uint32_t hash = B3gInitHash(p); - - //printf("B3gInitHashAdd: %" PRIu32 "\n", hash); - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - //printf("B3gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - return 0; - } - - B3gPattern *tt = NULL; - B3gPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - //printf("B3gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - - return 0; -} - -static inline int B3gCmpPattern(B3gPattern *p, uint8_t *pat, uint16_t patlen, char flags); - -static inline B3gPattern *B3gInitHashLookup(B3gCtx *ctx, uint8_t *pat, uint16_t patlen, char flags) -{ - uint32_t hash = B3gInitHashRaw(pat,patlen); - - //printf("B3gInitHashLookup: %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - - if (ctx->init_hash[hash] == NULL) { - return NULL; - } - - B3gPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (B3gCmpPattern(t,pat,patlen,flags) == 1) - return t; - } - - return NULL; -} - -static inline int B3gCmpPattern(B3gPattern *p, uint8_t *pat, uint16_t patlen, char flags) -{ - if (p->len != patlen) - return 0; - - if (p->flags != flags) - return 0; - - if (memcmp(p->cs, pat, patlen) != 0) - return 0; - - return 1; -} - -/* - * INIT HASH END - */ - -void B3gFreePattern(MpmCtx *mpm_ctx, B3gPattern *p) -{ - if (p && p->cs && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p && p->ci) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p && p->sids) { - SCFree(p->sids); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->sids_size * sizeof(SigIntId); - } - - if (p) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B3gPattern); - } -} - -/* B3gAddPattern - * - * pat: ptr to the pattern - * patlen: length of the pattern - * nocase: nocase flag: 1 enabled, 0 disable - * pid: pattern id - * sid: signature id (internal id) - */ -static int B3gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - - if (patlen == 0) - return 0; - - /* get a memory piece */ - B3gPattern *p = B3gInitHashLookup(ctx, pat, patlen, flags); - if (p == NULL) { - p = B3gAllocPattern(mpm_ctx); - if (p == NULL) - goto error; - - p->len = patlen; - p->flags = flags; - p->id = pid; - - /* setup the case insensitive part of the pattern */ - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci,pat,p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - //printf("B3gAddPattern: ci \""); prt(p->ci,p->len); - //printf("\" cs \""); prt(p->cs,p->len); - //printf("\" prefix_ci %" PRIu32 ", prefix_cs %" PRIu32 "\n", p->prefix_ci, p->prefix_cs); - - p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); - BUG_ON(p->sids == NULL); - p->sids[0] = sid; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SigIntId); - - /* put in the pattern hash */ - B3gInitHashAdd(ctx, p); - - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; - } else { - /* Multiple sids for the same pid, so keep an array of sids. */ - - /* TODO figure out how we can be called multiple times for the - * same CTX with the same sid */ - int found = 0; - uint32_t x = 0; - for (x = 0; x < p->sids_size; x++) { - if (p->sids[x] == sid) { - found = 1; - break; - } - } - if (!found) { - SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); - BUG_ON(sids == NULL); - p->sids = sids; - p->sids[p->sids_size] = sid; - p->sids_size++; - mpm_ctx->memory_size += sizeof(SigIntId); - } - } - - return 0; - -error: - B3gFreePattern(mpm_ctx, p); - return -1; -} - -int B3gAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return B3gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -int B3gAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) -{ - return B3gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -static uint32_t B3gBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint16_t i; - uint32_t hash = (uint32_t)u8_tolower(*d); - - for (i = 1; i < datalen; i++) { - d++; - hash += (u8_tolower(*d)) ^ i; - } - hash <<= (iter+1); - - hash %= hash_size; - return hash; -} - -static void B3gPrepareHash(MpmCtx *mpm_ctx) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - uint16_t i; - uint16_t idx = 0; - uint8_t idx8 = 0; - - ctx->hash = (B3gHashItem **)SCMalloc(sizeof(B3gHashItem *) * ctx->hash_size); - if (ctx->hash == NULL) - goto error; - memset(ctx->hash, 0, sizeof(B3gHashItem *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B3gHashItem *) * ctx->hash_size); - - /* 2 byte pattern hash */ - ctx->hash2 = (B3gHashItem **)SCMalloc(sizeof(B3gHashItem *) * ctx->hash_size); - if (ctx->hash2 == NULL) - goto error; - memset(ctx->hash2, 0, sizeof(B3gHashItem *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B3gHashItem *) * ctx->hash_size); - - /* alloc the pminlen array */ - ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); - if (ctx->pminlen == NULL) - goto error; - memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) - { - if(ctx->parray[i]->len == 1) { - idx8 = (uint8_t)ctx->parray[i]->ci[0]; - if (ctx->hash1[idx8].flags == 0) { - ctx->hash1[idx8].idx = i; - ctx->hash1[idx8].flags |= 0x01; - } else { - B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - /* Append this HashItem to the list */ - B3gHashItem *thi = &ctx->hash1[idx8]; - while (thi->nxt) thi = thi->nxt; - thi->nxt = hi; - } - ctx->pat_1_cnt++; - } else if(ctx->parray[i]->len == 2) { - idx = (uint16_t)(ctx->parray[i]->ci[0] << b3g_hash_shift | ctx->parray[i]->ci[1]); - if (ctx->hash2[idx] == NULL) { - B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - ctx->hash2[idx] = hi; - } else { - B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - /* Append this HashItem to the list */ - B3gHashItem *thi = ctx->hash2[idx]; - while (thi->nxt) thi = thi->nxt; - thi->nxt = hi; - } - ctx->pat_2_cnt++; - } else { - idx = B3G_HASH(ctx->parray[i]->ci[ctx->m - 3], ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); - //printf("idx %" PRIu32 ", %c.%c.%c\n", idx, ctx->parray[i]->ci[ctx->m - 3], ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); - - if (ctx->hash[idx] == NULL) { - B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - ctx->pminlen[idx] = ctx->parray[i]->len; - - ctx->hash[idx] = hi; - } else { - B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - if (ctx->parray[i]->len < ctx->pminlen[idx]) - ctx->pminlen[idx] = ctx->parray[i]->len; - - /* Append this HashItem to the list */ - B3gHashItem *thi = ctx->hash[idx]; - while (thi->nxt) thi = thi->nxt; - thi->nxt = hi; - } - ctx->pat_x_cnt++; - } - } - - /* alloc the bloom array */ - ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); - if (ctx->bloom == NULL) - goto error; - memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); - - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - B3gHashItem *hi = ctx->hash[h]; - if (hi == NULL) - continue; - - ctx->bloom[h] = BloomFilterInit(b3g_bloom_size, 2, B3gBloomHash); - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[h]); - - if (ctx->pminlen[h] > 8) - ctx->pminlen[h] = 8; - - B3gHashItem *thi = hi; - do { - BloomFilterAdd(ctx->bloom[h], ctx->parray[thi->idx]->ci, ctx->pminlen[h]); - thi = thi->nxt; - } while (thi != NULL); - } - - return; -error: - return; -} - -int B3gBuildMatchArray(MpmCtx *mpm_ctx) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - - ctx->B3G = SCMalloc(sizeof(B3G_TYPE) * ctx->hash_size); - if (ctx->B3G == NULL) - return -1; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B3G_TYPE) * ctx->hash_size); - - memset(ctx->B3G,0, b3g_hash_size * sizeof(B3G_TYPE)); - - uint32_t j; - uint32_t a; - - /* fill the match array */ - for (j = 0; j <= (ctx->m - B3G_Q); j++) { - for (a = 0; a < mpm_ctx->pattern_cnt; a++) { - if (ctx->parray[a]->len < ctx->m) - continue; - - uint16_t h = B3G_HASH(u8_tolower(ctx->parray[a]->ci[j]),u8_tolower(ctx->parray[a]->ci[j+1]), u8_tolower(ctx->parray[a]->ci[j+2])); -//printf("B3gBuildMatchArray: h %" PRIu32 ", %c.%c.%c\n", h, u8_tolower(ctx->parray[a]->ci[j]),u8_tolower(ctx->parray[a]->ci[j+1]), u8_tolower(ctx->parray[a]->ci[j+2])); - ctx->B3G[h] = ctx->B3G[h] | (1 << (ctx->m - j)); - } - } - - ctx->s0 = 1; - return 0; -} - -int B3gPreparePatterns(MpmCtx *mpm_ctx) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - - /* alloc the pattern array */ - ctx->parray = (B3gPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B3gPattern *)); - if (ctx->parray == NULL) - goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B3gPattern *)); - //printf("mpm_ctx %p, parray %p\n", mpm_ctx,ctx->parray); - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B3gPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - B3gPattern *node = ctx->init_hash[i], *nnode = NULL; - for ( ; node != NULL; ) { - nnode = node->next; - node->next = NULL; - - ctx->parray[p] = node; - - p++; - node = nnode; - } - } - /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* set 'm' to the smallest pattern size */ - ctx->m = mpm_ctx->minlen; - - /* make sure 'm' stays in bounds - m can be max WORD_SIZE - 1 */ - if (ctx->m >= B3G_WORD_SIZE) { - ctx->m = B3G_WORD_SIZE - 1; - } - if (ctx->m < 3) ctx->m = 3; - - - ctx->hash_size = b3g_hash_size; - B3gPrepareHash(mpm_ctx); - B3gBuildMatchArray(mpm_ctx); - - if (ctx->pat_1_cnt) { - ctx->Search = B3gSearch1; - if (ctx->pat_2_cnt) { - ctx->Search = B3gSearch12; - ctx->MBSearch = b3g_func; - } - ctx->MBSearch = b3g_func; - } else if (ctx->pat_2_cnt) { - ctx->Search = B3gSearch2; - ctx->MBSearch = b3g_func; - } - - - return 0; -error: - return -1; -} - -void B3gPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ -#ifdef B3G_COUNTERS - B3gThreadCtx *tctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; - - printf("B3g Thread Search stats (tctx %p)\n", tctx); - printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); - printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); - printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); - printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); - printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); - printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); - printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); - printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); - printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); - printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); - printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", tctx->stat_bloom_calls ? (float)((float)((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls)*(float)100) : 0, tctx->stat_bloom_hits); - printf("Avg pminlen: %0.2f\n\n", tctx->stat_pminlen_calls ? (float)((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls) : 0); -#endif /* B3G_COUNTERS */ -} - -static inline int -memcmp_lowercase(uint8_t *s1, uint8_t *s2, uint16_t n) -{ - size_t i; - - /* check backwards because we already tested the first - * 2 to 4 chars. This way we are more likely to detect - * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { - if (u8_tolower(*(s2+i)) != s1[i]) - return 1; - } - - return 0; -} - -/** - * \brief Function to get the user defined values for b3g algorithm from the - * config file 'suricata.yaml' - */ -void B3gGetConfig() -{ - ConfNode *b3g_conf; - const char *hash_val = NULL; - const char *bloom_val = NULL; - const char *algo = NULL; - - /* init defaults */ - b3g_hash_size = HASHSIZE_LOW; - b3g_bloom_size = BLOOMSIZE_MEDIUM; - b3g_func = B3G_SEARCHFUNC; - - ConfNode *pm = ConfGetNode("pattern-matcher"); - - if (pm != NULL) { - - TAILQ_FOREACH(b3g_conf, &pm->head, next) { - if (strncmp(b3g_conf->val, "b3g", 3) == 0) { - algo = ConfNodeLookupChildValue(b3g_conf->head.tqh_first, - "algo"); - hash_val = ConfNodeLookupChildValue(b3g_conf->head.tqh_first, - "hash_size"); - bloom_val = ConfNodeLookupChildValue(b3g_conf->head.tqh_first, - "bf_size"); - - if (algo != NULL) { - if (strcmp(algo, "B3gSearch") == 0) { - b3g_func = B3gSearch; - } else if (strcmp(algo, "B3gSearchBNDMq") == 0) { - b3g_func = B3gSearchBNDMq; - } - } - - if (hash_val != NULL) { - b3g_hash_size = MpmGetHashSize(hash_val); - switch (b3g_hash_size) { - case HASHSIZE_LOWEST: - b3g_hash_shift = B3G_HASHSHIFT_LOWEST; - b3g_hash_shift2 = B3G_HASHSHIFT_LOWEST2; - break; - case HASHSIZE_LOW: - b3g_hash_shift = B3G_HASHSHIFT_LOW; - b3g_hash_shift2 = B3G_HASHSHIFT_LOW2; - break; - case HASHSIZE_MEDIUM: - b3g_hash_shift = B3G_HASHSHIFT_MEDIUM; - b3g_hash_shift2 = B3G_HASHSHIFT_MEDIUM2; - break; - case HASHSIZE_HIGH: - b3g_hash_shift = B3G_HASHSHIFT_HIGH; - b3g_hash_shift2 = B3G_HASHSHIFT_HIGH2; - break; - case HASHSIZE_HIGHER: - b3g_hash_shift = B3G_HASHSHIFT_HIGHER; - b3g_hash_shift2 = B3G_HASHSHIFT_HIGHER2; - break; - case HASHSIZE_MAX: - b3g_hash_shift = B3G_HASHSHIFT_MAX; - b3g_hash_shift2 = B3G_HASHSHIFT_MAX2; - break; - } - } - - if (bloom_val != NULL) - b3g_bloom_size = MpmGetBloomSize(bloom_val); - - SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", - b3g_hash_size, b3g_bloom_size); - } - } - } -} - -void B3gInitCtx (MpmCtx *mpm_ctx) -{ - //printf("B3gInitCtx: mpm_ctx %p\n", mpm_ctx); - - mpm_ctx->ctx = SCMalloc(sizeof(B3gCtx)); - if (mpm_ctx->ctx == NULL) - return; - - memset(mpm_ctx->ctx, 0, sizeof(B3gCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B3gCtx); - - /* initialize the hash we use to speed up pattern insertions */ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(B3gPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) - return; - - memset(ctx->init_hash, 0, sizeof(B3gPattern *) * INIT_HASH_SIZE); - - /* Initialize the defaults value from the config file. The given check make - sure that we query config file only once for config values */ - if (b3g_hash_size == 0) - B3gGetConfig(); - - /* init default */ - ctx->Search = b3g_func; -} - -void B3gDestroyCtx(MpmCtx *mpm_ctx) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash) { - SCFree(ctx->init_hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B3gPattern *)); - } - - if (ctx->parray) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - B3gFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B3gPattern)); - } - - if (ctx->B3G) { - SCFree(ctx->B3G); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B3G_TYPE) * ctx->hash_size); - } - - if (ctx->bloom) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); - - BloomFilterFree(ctx->bloom[h]); - } - - SCFree(ctx->bloom); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); - } - - if (ctx->hash) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->hash[h] == NULL) - continue; - - B3gHashFree(mpm_ctx, ctx->hash[h]); - } - - SCFree(ctx->hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B3gHashItem) * ctx->hash_size); - } - if (ctx->hash2) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->hash2[h] == NULL) - continue; - - B3gHashFree(mpm_ctx, ctx->hash2[h]); - } - - SCFree(ctx->hash2); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B3gHashItem) * ctx->hash_size); - } - - if (ctx->pminlen) { - SCFree(ctx->pminlen); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B3gCtx); -} - -void B3gThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - if (sizeof(B3gThreadCtx) > 0) { /* size can be 0 when optimized */ - mpm_thread_ctx->ctx = SCMalloc(sizeof(B3gThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) - return; - - memset(mpm_thread_ctx->ctx, 0, sizeof(B3gThreadCtx)); - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(B3gThreadCtx); - } -} - -void B3gThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - B3gThreadCtx *ctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; - - B3gPrintSearchStats(mpm_thread_ctx); - - if (ctx != NULL) { /* can be NULL when optimized */ - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(B3gThreadCtx); - SCFree(mpm_thread_ctx->ctx); - } -} - -inline uint32_t B3gSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - return ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen); -} - -uint32_t B3gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; -#ifdef B3G_COUNTERS - B3gThreadCtx *tctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = ctx->m - B3G_Q + 1, matches = 0; - B3G_TYPE d; - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (pos <= (uint32_t)(buflen - B3G_Q + 1)) { - uint16_t h = B3G_HASH(u8_tolower(buf[pos - 1]), u8_tolower(buf[pos]),u8_tolower(buf[pos + 1])); - d = ctx->B3G[h]; - - if (d != 0) { - COUNT(tctx->stat_d0++); - uint32_t j = pos; - uint32_t first = pos - (ctx->m - B3G_Q + 1); - - do { - j = j - 1; - if (d >= (uint32_t)(1 << (ctx->m - 1))) { - if (j > first) pos = j; - else { - /* get our patterns from the hash */ - h = B3G_HASH(u8_tolower(buf[j + ctx->m - 3]), u8_tolower(buf[j + ctx->m - 2]),u8_tolower(buf[j + ctx->m - 1])); - - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((buflen - j) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf+j, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - - //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); - goto skip_loop; - } - } - } - - B3gHashItem *hi = ctx->hash[h], *thi; - for (thi = hi; thi != NULL; thi = thi->nxt) { - COUNT(tctx->stat_d0_hashloop++); - B3gPattern *p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (buflen - j < p->len) - continue; - - if (memcmp_lowercase(p->ci, buf+j, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (buflen - j < p->len) - continue; - - if (memcmp(p->cs, buf+j, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } -skip_loop: - //printf("output at pos %" PRIu32 ": ", j); prt(buf + (j), ctx->m); printf("\n"); - ; // gcc doesn't like the goto label without this :-S - } - } - - if (j == 0) - break; - - h = B3G_HASH(u8_tolower(buf[j - 1]), u8_tolower(buf[j - 0]),u8_tolower(buf[j+1])); - d = (d << 1) & ctx->B3G[h]; - } while (d != 0); - } - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (ctx->m - B3G_Q + 1)); - pos = pos + ctx->m - B3G_Q + 1; - } - return matches; -} - -uint32_t B3gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; -#ifdef B3G_COUNTERS - B3gThreadCtx *tctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = 0, matches = 0; - B3G_TYPE d; - uint32_t j; - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (pos <= (buflen - ctx->m)) { - j = ctx->m - 2; - d = ~0; - - do { - uint16_t h = B3G_HASH(u8_tolower(buf[pos + j - 1]), u8_tolower(buf[pos + j - 0]),u8_tolower(buf[pos + j + 1])); - d = ((d << 1) & ctx->B3G[h]); - j = j - 1; - } while (d != 0 && j != 0); - - /* (partial) match, move on to verification */ - if (d != 0) { - COUNT(tctx->stat_d0++); - //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); - - /* get our patterns from the hash */ - uint16_t h = B3G_HASH(u8_tolower(buf[pos + ctx->m - 3]), u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); - - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((buflen - pos) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf+pos, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - - //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); - goto skip_loop; - } - } - } - - B3gHashItem *hi = ctx->hash[h], *thi; - for (thi = hi; thi != NULL; thi = thi->nxt) { - COUNT(tctx->stat_d0_hashloop++); - B3gPattern *p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (buflen - pos < p->len) - continue; - - if (memcmp_lowercase(p->ci, buf+pos, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (buflen - pos < p->len) - continue; - - if (memcmp(p->cs, buf+pos, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } -skip_loop: - pos = pos + 1; - //pos = pos + ctx->s0; - } else { - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (j + 1)); - - pos = pos + j + 1; - } - } - - //printf("Total matches %" PRIu32 "\n", matches); - return matches; -} - -uint32_t B3gSearch12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - B3gPattern *p; - B3gHashItem *thi, *hi; - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (buf <= bufend) { - uint8_t h8 = u8_tolower(*buf); - hi = &ctx->hash1[h8]; - - if (hi->flags & 0x01) { - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (h8 == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } - } else { - if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } - } - } - } - - if (buf != bufend) { - /* save one conversion by reusing h8 */ - uint16_t h16 = (uint16_t)(h8 << b3g_hash_shift | u8_tolower(*(buf+1))); - hi = ctx->hash2[h16]; - - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (h8 == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } - } else { - if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } - } - } - } - buf += 1; - } - - //printf("B3gSearch12: after 1/2byte cnt %" PRIu32 "\n", cnt); - if (ctx->pat_x_cnt > 0) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - //printf("B3gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); - } - return cnt; -} - -uint32_t B3gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - B3gPattern *p; - B3gHashItem *thi, *hi; - - if (buflen < 2) - return 0; - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (buf <= bufend) { - uint16_t h = u8_tolower(*buf) << b3g_hash_shift | u8_tolower(*(buf+1)); - hi = ctx->hash2[h]; - - if (hi != NULL) { - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - if (p->len != 2) - continue; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (u8_tolower(*buf) == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { - //printf("CI Exact match: "); prt(p->ci, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B3gSearch1)\n"); - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size)) - cnt++; - } - } else { - if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { - //printf("CS Exact match: "); prt(p->cs, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B3gSearch1)\n"); - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size)) - cnt++; - } - } - } - } - buf += 1; - } - - //printf("B3gSearch2: after 2byte cnt %" PRIu32 "\n", cnt); - if (ctx->pat_x_cnt) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - //printf("B3gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); - } - return cnt; -} -uint32_t B3gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - B3gPattern *p; - B3gHashItem *thi, *hi; - - if (buflen == 0) - return 0; - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (buf <= bufend) { - uint8_t h = u8_tolower(*buf); - hi = &ctx->hash1[h]; - - if (hi->flags & 0x01) { - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - if (p->len != 1) - continue; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (u8_tolower(*buf) == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } - } else { - if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } - } - } - } - buf += 1; - } - - if (ctx->pat_2_cnt) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch2(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - } else if (ctx->pat_x_cnt) { - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - } - return cnt; -} - -void MpmB3gRegister (void) -{ - mpm_table[MPM_B3G].name = "b3g"; - mpm_table[MPM_B3G].max_pattern_length = B3G_WORD_SIZE; - mpm_table[MPM_B3G].InitCtx = B3gInitCtx; - mpm_table[MPM_B3G].InitThreadCtx = B3gThreadInitCtx; - mpm_table[MPM_B3G].DestroyCtx = B3gDestroyCtx; - mpm_table[MPM_B3G].DestroyThreadCtx = B3gThreadDestroyCtx; - mpm_table[MPM_B3G].AddPattern = B3gAddPatternCS; - mpm_table[MPM_B3G].AddPatternNocase = B3gAddPatternCI; - mpm_table[MPM_B3G].Prepare = B3gPreparePatterns; - mpm_table[MPM_B3G].Search = B3gSearchWrap; - mpm_table[MPM_B3G].Cleanup = NULL; - mpm_table[MPM_B3G].PrintCtx = B3gPrintInfo; - mpm_table[MPM_B3G].PrintThreadCtx = B3gPrintSearchStats; - mpm_table[MPM_B3G].RegisterUnittests = B3gRegisterTests; -} - -/* - * TESTS - */ - -#ifdef UNITTESTS -static int B3gTestInit01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->m == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->m); - - B3gDestroyCtx(&mpm_ctx); - return result; -} - -#if 0 -static int B3gTestS0Init01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->s0); - - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestS0Init02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestS0Init03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", ctx->s0); - - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestS0Init04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestS0Init05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", ctx->s0); - - B3gDestroyCtx(&mpm_ctx); - return result; -} -#endif - -static int B3gTestSearch01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -/* test patterns longer than 'm'. M is 4 here. */ -static int B3gTestSearch04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -/* case insensitive test patterns longer than 'm'. M is 4 here. */ -static int B3gTestSearch05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch07 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch08 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch09 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch10 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - char *input = "012345679012345679012345679012345679012345679012345679" - "012345679012345679012345679012345679abcdefgh0123456790" - "123456790123456790123456790123456790123456790123456790" - "12345679012345679012345679"; - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)input, strlen(input)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch11 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -#endif /* UNITTESTS */ - -void B3gRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("B3gTestInit01", B3gTestInit01, 1); -/* - UtRegisterTest("B3gTestS0Init01", B3gTestS0Init01, 1); - UtRegisterTest("B3gTestS0Init02", B3gTestS0Init02, 1); - UtRegisterTest("B3gTestS0Init03", B3gTestS0Init03, 1); - UtRegisterTest("B3gTestS0Init04", B3gTestS0Init04, 1); - UtRegisterTest("B3gTestS0Init05", B3gTestS0Init05, 1); -*/ - UtRegisterTest("B3gTestSearch01", B3gTestSearch01, 1); - - UtRegisterTest("B3gTestSearch02", B3gTestSearch02, 1); - UtRegisterTest("B3gTestSearch03", B3gTestSearch03, 1); - UtRegisterTest("B3gTestSearch04", B3gTestSearch04, 1); - UtRegisterTest("B3gTestSearch05", B3gTestSearch05, 1); - UtRegisterTest("B3gTestSearch06", B3gTestSearch06, 1); - UtRegisterTest("B3gTestSearch07", B3gTestSearch07, 1); - UtRegisterTest("B3gTestSearch08", B3gTestSearch08, 1); - UtRegisterTest("B3gTestSearch09", B3gTestSearch09, 1); - UtRegisterTest("B3gTestSearch10", B3gTestSearch10, 1); - UtRegisterTest("B3gTestSearch11", B3gTestSearch11, 1); - UtRegisterTest("B3gTestSearch12", B3gTestSearch12, 1); -#endif /* UNITTESTS */ -} - diff --git a/src/util-mpm-b3g.h b/src/util-mpm-b3g.h deleted file mode 100644 index d35aa0334d02..000000000000 --- a/src/util-mpm-b3g.h +++ /dev/null @@ -1,130 +0,0 @@ -/* Copyright (C) 2007-2010 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 - */ - -#ifndef __UTIL_MPM_B3G_H__ -#define __UTIL_MPM_B3G_H__ - -#include "util-mpm.h" -#include "util-bloomfilter.h" - -#define B3G_HASHSHIFT_MAX 8 -#define B3G_HASHSHIFT_MAX2 5 -#define B3G_HASHSHIFT_HIGHER 7 -#define B3G_HASHSHIFT_HIGHER2 4 -#define B3G_HASHSHIFT_HIGH 6 -#define B3G_HASHSHIFT_HIGH2 3 -#define B3G_HASHSHIFT_MEDIUM 5 -#define B3G_HASHSHIFT_MEDIUM2 2 -#define B3G_HASHSHIFT_LOW 4 -#define B3G_HASHSHIFT_LOW2 1 -#define B3G_HASHSHIFT_LOWEST 3 -#define B3G_HASHSHIFT_LOWEST2 1 - -#define B3G_TYPE uint32_t -//#define B3G_TYPE uint16_t -//#define B3G_TYPE uint8_t -//#define B3G_WORD_SIZE 16 -//#define B3G_WORD_SIZE 8 -#define B3G_WORD_SIZE 32 - -#define B3G_Q 3 - -//#define B3G_SEARCHFUNC B3gSearch -#define B3G_SEARCHFUNC B3gSearchBNDMq - -//#define B3G_COUNTERS - -typedef struct B3gPattern_ { - uint8_t *cs; /* case sensitive */ - uint8_t *ci; /* case INsensitive */ - uint16_t len; - uint8_t flags; - uint32_t id; - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; - - struct B3gPattern_ *next; - -} B3gPattern; - -typedef struct B3gHashItem_ { - uint8_t flags; - uint16_t idx; - struct B3gHashItem_ *nxt; -} B3gHashItem; - -typedef struct B3gCtx_ { - /* hash used during ctx initialization */ - B3gPattern **init_hash; - - B3G_TYPE m; - B3G_TYPE *B3G; - - uint8_t s0; - - uint16_t pat_1_cnt; - uint16_t pat_2_cnt; - uint16_t pat_x_cnt; - - uint32_t hash_size; - B3gHashItem **hash; - BloomFilter **bloom; - uint8_t *pminlen; /* array containing the minimal length - of the patters in a hash bucket. Used - for the BloomFilter. */ - B3gHashItem hash1[256]; - B3gHashItem **hash2; - - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - /* we store our own multi byte search func ptr here for B3gSearch1 */ - uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - /* pattern arrays */ - B3gPattern **parray; -} B3gCtx; - -typedef struct B3gThreadCtx_ { -#ifdef B3G_COUNTERS - uint32_t stat_pminlen_calls; - uint32_t stat_pminlen_total; - uint32_t stat_bloom_calls; - uint32_t stat_bloom_hits; - uint32_t stat_calls; - uint32_t stat_m_total; - uint32_t stat_d0; - uint32_t stat_d0_hashloop; - uint32_t stat_loop_match; - uint32_t stat_loop_no_match; - uint32_t stat_num_shift; - uint32_t stat_total_shift; -#endif /* B3G_COUNTERS */ -} B3gThreadCtx; - -void MpmB3gRegister(void); - -#endif - diff --git a/src/util-mpm-wumanber.c b/src/util-mpm-wumanber.c deleted file mode 100644 index dc78cde260ad..000000000000 --- a/src/util-mpm-wumanber.c +++ /dev/null @@ -1,3219 +0,0 @@ -/* 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 - * - * Implementation of the Wu-Manber pattern matching algorithm. - * - * Ideas: - * - the hash contains a list of patterns. Maybe we can 'train' the hash - * so the most common patterns always appear first in this list. - * - * \todo make hash1 a array of ptr and get rid of the flag field in the - * WmHashItem - * \todo remove exit() calls - * \todo only calc prefixci_buf for nocase patterns? -- would be in a - * loop though, so probably not a performance inprovement. - * \todo make sure runtime counters can be disabled (at compile time) - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-mpm.h" -#include "util-mpm-wumanber.h" -#include "conf.h" - -#include "util-unittest.h" -#include "util-debug.h" - -#define INIT_HASH_SIZE 65535 - -#define HASH16_SIZE 65536 -#define HASH16(a,b) (((a)<<8) | (b)) -#define HASH15_SIZE 32768 -#define HASH15(a,b) (((a)<<7) | (b)) -#define HASH14_SIZE 16384 -#define HASH14(a,b) (((a)<<6) | (b)) -#define HASH12_SIZE 4096 -#define HASH12(a,b) (((a)<<4) | (b)) -#define HASH9_SIZE 512 -#define HASH9(a,b) (((a)<<1) | (b)) - -static uint32_t wm_hash_size = 0; -static uint32_t wm_bloom_size = 0; - -void WmInitCtx (MpmCtx *mpm_ctx); -void WmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t); -void WmDestroyCtx(MpmCtx *mpm_ctx); -void WmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx); -int WmAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); -int WmAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); -int WmPreparePatterns(MpmCtx *mpm_ctx); -uint32_t WmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch2Hash9(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch2Hash12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch2Hash14(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch2Hash15(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch2Hash16(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -void WmPrintInfo(MpmCtx *mpm_ctx); -void WmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void WmRegisterTests(void); - -/* uppercase to lowercase conversion lookup table */ -static uint8_t lowercasetable[256]; -/* marco to do the actual lookup */ -#define wm_tolower(c) lowercasetable[(c)] - -#ifdef WUMANBER_COUNTERS -#define COUNT(counter) \ - (counter) -#else -#define COUNT(counter) -#endif /* WUMANBER_COUNTERS */ - -void prt (uint8_t *buf, uint16_t buflen) -{ - uint16_t i; - - for (i = 0; i < buflen; i++) { - if (isprint(buf[i])) printf("%c", buf[i]); - else printf("\\x%" PRIX32, buf[i]); - } - //printf("\n"); -} - -void WmPrintInfo(MpmCtx *mpm_ctx) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - - printf("MPM WuManber Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeofs:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" WmCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(WmCtx)); - printf(" WmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(WmPattern)); - printf(" WmHashItem %" PRIuMAX "\n", (uintmax_t)sizeof(WmHashItem)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Max shiftlen: %" PRIu32 "\n", ctx->shiftlen); - printf("Hash size: %" PRIu32 "\n", ctx->hash_size); - printf("Search function: "); - if (ctx->Search == WmSearch1) { - printf("WmSearch1 (allows single byte patterns)\n"); - printf("MBSearch funct: "); - if (ctx->MBSearch == WmSearch2Hash16) printf("WmSearch2Hash16\n"); - else if (ctx->MBSearch == WmSearch2Hash15) printf("WmSearch2Hash15\n"); - else if (ctx->MBSearch == WmSearch2Hash14) printf("WmSearch2Hash14\n"); - else if (ctx->MBSearch == WmSearch2Hash12) printf("WmSearch2Hash12\n"); - else if (ctx->MBSearch == WmSearch2Hash9) printf("WmSearch2Hash9\n"); - } - if (ctx->Search == WmSearch2Hash16) printf("WmSearch2Hash16 (only for multibyte patterns)\n"); - else if (ctx->Search == WmSearch2Hash15) printf("WmSearch2Hash15 (only for multibyte patterns)\n"); - else if (ctx->Search == WmSearch2Hash14) printf("WmSearch2Hash14 (only for multibyte patterns)\n"); - else if (ctx->Search == WmSearch2Hash12) printf("WmSearch2Hash12 (only for multibyte patterns)\n"); - else if (ctx->Search == WmSearch2Hash9) printf("WmSearch2Hash9 (only for multibyte patterns)\n"); - else printf("ERROR\n"); - printf("\n"); -} - -static inline WmPattern *WmAllocPattern(MpmCtx *mpm_ctx) -{ - WmPattern *p = SCMalloc(sizeof(WmPattern)); - if (unlikely(p == NULL)) - return NULL; - memset(p,0,sizeof(WmPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(WmPattern); - return p; -} - -static inline WmHashItem * -WmAllocHashItem(MpmCtx *mpm_ctx) -{ - WmHashItem *hi = SCMalloc(sizeof(WmHashItem)); - if (unlikely(hi == NULL)) - return NULL; - memset(hi,0,sizeof(WmHashItem)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(WmHashItem); - return hi; -} - -static void WmHashFree(MpmCtx *mpm_ctx, WmHashItem *hi) -{ - if (hi == NULL) - return; - - WmHashItem *t = hi->nxt; - WmHashFree(mpm_ctx, t); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(WmHashItem); - SCFree(hi); -} - -static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) -{ - uint16_t i; - for (i = 0; i < len; i++) { - d[i] = wm_tolower(s[i]); - } -} - -/* - * INIT HASH START - */ -static inline uint32_t WmInitHash(WmPattern *p) -{ - uint32_t hash = p->len * p->cs[0]; - if (p->len > 1) - hash += p->cs[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline uint32_t WmInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int WmInitHashAdd(WmCtx *ctx, WmPattern *p) -{ - uint32_t hash = WmInitHash(p); - - //printf("WmInitHashAdd: %" PRIu32 "\n", hash); - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - //printf("WmInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - return 0; - } - - WmPattern *tt = NULL; - WmPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - //printf("WmInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - - return 0; -} - -static inline int WmCmpPattern(WmPattern *p, uint8_t *pat, uint16_t patlen, char flags); - -static inline WmPattern *WmInitHashLookup(WmCtx *ctx, uint8_t *pat, uint16_t patlen, char flags) -{ - uint32_t hash = WmInitHashRaw(pat,patlen); - - //printf("WmInitHashLookup: %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - - if (ctx->init_hash[hash] == NULL) { - return NULL; - } - - WmPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (WmCmpPattern(t,pat,patlen,flags) == 1) - return t; - } - - return NULL; -} - -static inline int WmCmpPattern(WmPattern *p, uint8_t *pat, uint16_t patlen, char flags) -{ - if (p->len != patlen) - return 0; - - if (p->flags != flags) - return 0; - - if (memcmp(p->cs, pat, patlen) != 0) - return 0; - - return 1; -} - -/* - * INIT HASH END - */ - -void WmFreePattern(MpmCtx *mpm_ctx, WmPattern *p) -{ - if (p && p->cs && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p && p->ci) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p && p->sids) { - SCFree(p->sids); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->sids_size * sizeof(uint32_t); - } - - if (p) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(WmPattern); - } -} - -/* WmAddPattern - * - * pat: ptr to the pattern - * patlen: length of the pattern - * nocase: nocase flag: 1 enabled, 0 disable - * pid: pattern id - * sid: signature id (internal id) - */ -static int WmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - -// printf("WmAddPattern: ctx %p \"", mpm_ctx); prt(pat, patlen); -// printf("\" id %" PRIu32 ", nocase %s\n", id, nocase ? "true" : "false"); - - if (patlen == 0) - return 0; - - /* get a memory piece */ - WmPattern *p = WmInitHashLookup(ctx, pat, patlen, flags); - if (p == NULL) { -// printf("WmAddPattern: allocing new pattern\n"); - p = WmAllocPattern(mpm_ctx); - if (p == NULL) - goto error; - - p->len = patlen; - p->flags = flags; - p->id = pid; - - /* setup the case insensitive part of the pattern */ - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci,pat,p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - if (p->len > 1) { - p->prefix_cs = (uint16_t)(*(p->cs)+*(p->cs+1)); - p->prefix_ci = (uint16_t)(*(p->ci)+*(p->ci+1)); - } - - //printf("WmAddPattern: ci \""); prt(p->ci,p->len); - //printf("\" cs \""); prt(p->cs,p->len); - //printf("\" prefix_ci %" PRIu32 ", prefix_cs %" PRIu32 "\n", p->prefix_ci, p->prefix_cs); - - /* put in the pattern hash */ - WmInitHashAdd(ctx, p); - - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; - - p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); - BUG_ON(p->sids == NULL); - p->sids[0] = sid; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SigIntId); - - } else { - /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ - - int found = 0; - uint32_t x = 0; - for (x = 0; x < p->sids_size; x++) { - if (p->sids[x] == sid) { - found = 1; - break; - } - } - if (!found) { - SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); - BUG_ON(sids == NULL); - p->sids = sids; - p->sids[p->sids_size] = sid; - p->sids_size++; - mpm_ctx->memory_size += sizeof(uint32_t); - } - } - - return 0; - -error: - WmFreePattern(mpm_ctx, p); - return -1; -} - -int WmAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return WmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -int WmAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) -{ - return WmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -static uint32_t WmBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint16_t i; - uint32_t hash = (uint32_t)wm_tolower(*d); - - for (i = 1; i < datalen - 1; i++) { - hash += (wm_tolower((*d++))) ^ i; - } - hash <<= (iter+1); - - hash %= hash_size; - return hash; -} -/* -static uint32_t BloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint32_t i; - uint32_t hash = 0; - - for (i = 0; i < datalen; i++) { - if (i == 0) hash += (((uint32_t)*d++)); - else if (i == 1) hash += (((uint32_t)*d++) * datalen); - else hash *= (((uint32_t)*d++) * i); - } - - hash *= (iter + datalen); - hash %= hash_size; - return hash; -} -*/ -static void WmSearchPrepareHash(MpmCtx *mpm_ctx) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - uint16_t i; - uint16_t idx = 0; - uint8_t idx8 = 0; - - ctx->hash = (WmHashItem **)SCMalloc(sizeof(WmHashItem *) * ctx->hash_size); - if (ctx->hash == NULL) - goto error; - memset(ctx->hash, 0, sizeof(WmHashItem *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(WmHashItem *) * ctx->hash_size); - - /* alloc the pminlen array */ - ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); - if (ctx->pminlen == NULL) - goto error; - memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) - { - if(ctx->parray[i]->len == 1) { - idx8 = (uint8_t)ctx->parray[i]->ci[0]; - if (ctx->hash1[idx8].flags == 0) { - ctx->hash1[idx8].idx = i; - ctx->hash1[idx8].flags |= 0x01; - } else { - WmHashItem *hi = WmAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - /* Append this HashItem to the list */ - WmHashItem *thi = &ctx->hash1[idx8]; - while (thi->nxt) thi = thi->nxt; - thi->nxt = hi; - } - } else { - uint16_t patlen = ctx->shiftlen; - - if (ctx->hash_size == HASH9_SIZE) - idx = HASH9(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); - else if (ctx->hash_size == HASH12_SIZE) - idx = HASH12(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); - else if (ctx->hash_size == HASH14_SIZE) - idx = HASH14(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); - else if (ctx->hash_size == HASH15_SIZE) - idx = HASH15(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); - else - idx = HASH16(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); - - if (ctx->hash[idx] == NULL) { - WmHashItem *hi = WmAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - ctx->pminlen[idx] = ctx->parray[i]->len; - - ctx->hash[idx] = hi; - } else { - WmHashItem *hi = WmAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - if (ctx->parray[i]->len < ctx->pminlen[idx]) - ctx->pminlen[idx] = ctx->parray[i]->len; - - /* Append this HashItem to the list */ - WmHashItem *thi = ctx->hash[idx]; - while (thi->nxt) thi = thi->nxt; - thi->nxt = hi; - } - } - } - - /* alloc the bloom array */ - ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); - if (ctx->bloom == NULL) - goto error; - memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); - - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - WmHashItem *hi = ctx->hash[h]; - if (hi == NULL) - continue; - - ctx->bloom[h] = BloomFilterInit(wm_bloom_size, 2, WmBloomHash); - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[h]); - - if (ctx->pminlen[h] > 8) - ctx->pminlen[h] = 8; - - WmHashItem *thi = hi; - do { - BloomFilterAdd(ctx->bloom[h], ctx->parray[thi->idx]->ci, ctx->pminlen[h]); - thi = thi->nxt; - } while (thi != NULL); - } - return; -error: - return; -} -static void WmSearchPrepareShiftTable(MpmCtx *mpm_ctx) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - - uint16_t shift = 0, k = 0, idx = 0; - uint32_t i = 0; - - uint16_t smallest = mpm_ctx->minlen; - if (smallest > 255) smallest = 255; - if (smallest < 2) smallest = 2; - - ctx->shiftlen = smallest; - - ctx->shifttable = SCMalloc(sizeof(uint16_t) * ctx->hash_size); - if (ctx->shifttable == NULL) - return; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(uint16_t) * ctx->hash_size); - - /* default shift table is set to minimal shift */ - for (i = 0; i < ctx->hash_size; i++) - ctx->shifttable[i] = ctx->shiftlen; - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) - { - /* ignore one byte patterns */ - if (ctx->parray[i]->len == 1) - continue; - - /* add the first character of the pattern preceeded by - * every possible other character. */ - for (k = 0; k < 256; k++) { - shift = ctx->shiftlen - 1; - if (shift > 255) shift = 255; - - if (ctx->hash_size == HASH9_SIZE) { - idx = HASH9(ctx->parray[i]->ci[0], (uint8_t)k); - //printf("HASH9 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH12_SIZE) { - idx = HASH12(ctx->parray[i]->ci[0], (uint8_t)k); - //printf("HASH12 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH14_SIZE) { - idx = HASH14(ctx->parray[i]->ci[0], (uint8_t)k); - //printf("HASH14 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH15_SIZE) { - idx = HASH15(ctx->parray[i]->ci[0], (uint8_t)k); - //printf("HASH15 idx %" PRIu32 "\n", idx); - } else { - idx = HASH16(ctx->parray[i]->ci[0], (uint8_t)k); - //printf("HASH15 idx %" PRIu32 "\n", idx); - } - if (shift < ctx->shifttable[idx]) { - ctx->shifttable[idx] = shift; - } - } - - for (k = 0; k < ctx->shiftlen-1; k++) - { - shift = (ctx->shiftlen - 2 - k); - if (shift > 255) shift = 255; - - if (ctx->hash_size == HASH9_SIZE) { - idx = HASH9(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); - //printf("HASH9 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH12_SIZE) { - idx = HASH12(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); - //printf("HASH12 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH14_SIZE) { - idx = HASH14(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); - //printf("HASH14 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH15_SIZE) { - idx = HASH15(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); - //printf("HASH15 idx %" PRIu32 "\n", idx); - } else { - idx = HASH16(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); - //printf("HASH15 idx %" PRIu32 "\n", idx); - } - if (shift < ctx->shifttable[idx]) { - ctx->shifttable[idx] = shift; - } - //printf("WmPrepareShiftTable: i %" PRIu32 ", k %" PRIu32 ", idx %" PRIu32 ", shift set to %" PRIu32 ": \"%c%c\"\n", - // i, k, idx, shift, ctx->parray[i]->ci[k], ctx->parray[i]->ci[k+1]); - } - } -} - -int WmPreparePatterns(MpmCtx *mpm_ctx) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - - /* alloc the pattern array */ - ctx->parray = (WmPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(WmPattern *)); - if (ctx->parray == NULL) - goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(WmPattern *)); - //printf("mpm_ctx %p, parray %p\n", mpm_ctx,ctx->parray); - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(WmPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - WmPattern *node = ctx->init_hash[i], *nnode = NULL; - for ( ; node != NULL; ) { - nnode = node->next; - node->next = NULL; - - ctx->parray[p] = node; - - p++; - node = nnode; - } - } - /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* TODO VJ these values are chosen pretty much randomly, so - * we should do some performance testing - * */ - - if (ctx->hash_size == 0) { - if (mpm_ctx->pattern_cnt < 50) { - ctx->hash_size = HASH9_SIZE; - } else if(mpm_ctx->pattern_cnt < 300) { - ctx->hash_size = HASH12_SIZE; - } else if(mpm_ctx->pattern_cnt < 1200) { - ctx->hash_size = HASH14_SIZE; - } else if(mpm_ctx->pattern_cnt < 2400) { - ctx->hash_size = HASH15_SIZE; - } else { - ctx->hash_size = HASH16_SIZE; - } - } - - WmSearchPrepareShiftTable(mpm_ctx); - WmSearchPrepareHash(mpm_ctx); - - if (ctx->hash_size == HASH9_SIZE) { - ctx->MBSearch = WmSearch2Hash9; - ctx->Search = WmSearch2Hash9; - } else if (ctx->hash_size == HASH12_SIZE) { - ctx->MBSearch = WmSearch2Hash12; - ctx->Search = WmSearch2Hash12; - } else if (ctx->hash_size == HASH14_SIZE) { - ctx->MBSearch = WmSearch2Hash14; - ctx->Search = WmSearch2Hash14; - } else if (ctx->hash_size == HASH15_SIZE) { - ctx->MBSearch = WmSearch2Hash15; - ctx->Search = WmSearch2Hash15; - } else { - ctx->MBSearch = WmSearch2Hash16; - ctx->Search = WmSearch2Hash16; - } - - if (mpm_ctx->minlen == 1) { - ctx->Search = WmSearch1; - } - - return 0; -error: - return -1; -} - -void WmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; - - printf("Shift 0: %" PRIu32 "\n", tctx->stat_shift_null); - printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); - printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); - printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); - printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); -#endif /* WUMANBER_COUNTERS */ -} - -static inline int -memcmp_lowercase(uint8_t *s1, uint8_t *s2, uint16_t n) -{ - size_t i; - - /* check backwards because we already tested the first - * 2 to 4 chars. This way we are more likely to detect - * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { - if (wm_tolower(*(s2+i)) != s1[i]) - return 1; - } - - return 0; -} - -inline uint32_t WmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - return ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen); -} - -/* SCAN FUNCTIONS */ -uint32_t WmSearch2Hash9(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; -#endif /* WUMANBER_COUNTERS */ - uint32_t cnt = 0; - uint8_t *bufend = buf + buflen - 1; - uint16_t sl = ctx->shiftlen; - uint16_t h; - uint8_t shift; - WmHashItem *thi, *hi; - WmPattern *p; - uint16_t prefixci_buf; - uint16_t prefixcs_buf; - - if (buflen == 0) - return 0; - - //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf(" (sl %" PRIu32 ")\n", sl); - - buf+=(sl-1); - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (buf <= bufend) { - h = HASH9(wm_tolower(*buf),(wm_tolower(*(buf-1)))); - shift = ctx->shifttable[h]; - //printf("%p %" PRIu32 " search: h %" PRIu32 ", shift %" PRIu32 "\n", buf, buf - bufmin, h, shift); - - if (shift == 0) { - COUNT(tctx->stat_shift_null++); - - hi = ctx->hash[h]; - //printf("search: hi %p\n", hi); - if (hi != NULL) { - /* get our patterns from the hash */ - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((bufend - (buf-sl)) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - goto skip_loop; - } - } - } - - prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); - prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); - - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", - // p->prefix_ci, p->prefix_cs); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) - continue; - - if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { - //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) - continue; - if (memcmp(p->cs, buf-sl+1, p->len) == 0) { - //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } -skip_loop: - shift = 1; - } else { - COUNT(tctx->stat_total_shift += shift); - COUNT(tctx->stat_num_shift++); - } - buf += shift; - } - - //printf("cnt %" PRIu32 "\n", cnt); - return cnt; -} - -uint32_t WmSearch2Hash12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; -#endif /* WUMANBER_COUNTERS */ - uint32_t cnt = 0; - uint8_t *bufend = buf + buflen - 1; - uint16_t sl = ctx->shiftlen; - uint16_t h; - uint8_t shift; - WmHashItem *thi, *hi; - WmPattern *p; - uint16_t prefixci_buf; - uint16_t prefixcs_buf; - - if (buflen == 0) - return 0; - - //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); - - buf+=(sl-1); - //buf++; - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (buf <= bufend) { - //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); - h = HASH12(wm_tolower(*buf),(wm_tolower(*(buf-1)))); - shift = ctx->shifttable[h]; - //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); - - if (shift == 0) { - COUNT(tctx->stat_shift_null++); - /* get our hash item */ - hi = ctx->hash[h]; - //printf("search: hi %p\n", hi); - if (hi != NULL) { - /* get our patterns from the hash */ - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((bufend - (buf-sl)) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - goto skip_loop; - } - } - } - - prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); - prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); - //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", - // p->prefix_ci, p->prefix_cs); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) - continue; - - if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { - //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) - continue; - if (memcmp(p->cs, buf-sl+1, p->len) == 0) { - //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } -skip_loop: - shift = 1; - } else { - COUNT(tctx->stat_total_shift += shift); - COUNT(tctx->stat_num_shift++); - } - buf += shift; - } - - return cnt; -} - -uint32_t WmSearch2Hash14(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; -#endif /* WUMANBER_COUNTERS */ - uint32_t cnt = 0; - uint8_t *bufend = buf + buflen - 1; - uint16_t sl = ctx->shiftlen; - uint16_t h; - uint8_t shift; - WmHashItem *thi, *hi; - WmPattern *p; - uint16_t prefixci_buf; - uint16_t prefixcs_buf; - - if (buflen == 0) - return 0; - - //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); - - buf+=(sl-1); - //buf++; - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (buf <= bufend) { - //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); - h = HASH14(wm_tolower(*buf),(wm_tolower(*(buf-1)))); - shift = ctx->shifttable[h]; - //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); - - if (shift == 0) { - COUNT(tctx->stat_shift_null++); - /* get our hash item */ - hi = ctx->hash[h]; - //printf("search: hi %p\n", hi); - if (hi != NULL) { - /* get our patterns from the hash */ - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((bufend - (buf-sl)) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - goto skip_loop; - } - } - } - - prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); - prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); - //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", - // p->prefix_ci, p->prefix_cs); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) - continue; - - if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) - continue; - if (memcmp(p->cs, buf-sl+1, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } -skip_loop: - shift = 1; - } else { - COUNT(tctx->stat_total_shift += shift); - COUNT(tctx->stat_num_shift++); - } - buf += shift; - } - - return cnt; -} - -uint32_t WmSearch2Hash15(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; -#endif /* WUMANBER_COUNTERS */ - uint32_t cnt = 0; - uint8_t *bufend = buf + buflen - 1; - uint16_t sl = ctx->shiftlen; - uint16_t h; - uint8_t shift; - WmHashItem *thi, *hi; - WmPattern *p; - uint16_t prefixci_buf; - uint16_t prefixcs_buf; - - if (buflen == 0) - return 0; - - //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); - - buf+=(sl-1); - //buf++; - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (buf <= bufend) { - //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); - h = HASH15(wm_tolower(*buf),(wm_tolower(*(buf-1)))); - shift = ctx->shifttable[h]; - //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); - - if (shift == 0) { - COUNT(tctx->stat_shift_null++); - /* get our hash item */ - hi = ctx->hash[h]; - //printf("search: hi %p\n", hi); - if (hi != NULL) { - /* get our patterns from the hash */ - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((bufend - (buf-sl)) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - goto skip_loop; - } - } - } - - prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); - prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); - //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", - // p->prefix_ci, p->prefix_cs); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) - continue; - - if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { - //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) - continue; - if (memcmp(p->cs, buf-sl+1, p->len) == 0) { - //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } -skip_loop: - shift = 1; - } else { - COUNT(tctx->stat_total_shift += shift); - COUNT(tctx->stat_num_shift++); - } - buf += shift; - } - - return cnt; -} - -uint32_t WmSearch2Hash16(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; -#endif /* WUMANBER_COUNTERS */ - uint32_t cnt = 0; - uint8_t *bufend = buf + buflen - 1; - uint16_t sl = ctx->shiftlen; - uint16_t h; - uint8_t shift; - WmHashItem *thi, *hi; - WmPattern *p; - uint16_t prefixci_buf; - uint16_t prefixcs_buf; - - if (buflen == 0) - return 0; - - //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); - - buf+=(sl-1); - //buf++; - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - while (buf <= bufend) { - //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); - h = HASH16(wm_tolower(*buf),(wm_tolower(*(buf-1)))); - shift = ctx->shifttable[h]; - //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); - - if (shift == 0) { - COUNT(tctx->stat_shift_null++); - /* get our hash item */ - hi = ctx->hash[h]; - //printf("search: hi %p\n", hi); - if (hi != NULL) { - /* get our patterns from the hash */ - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((bufend - (buf-sl)) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - goto skip_loop; - } - } - } - - prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); - prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); - //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", - // p->prefix_ci, p->prefix_cs); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) - continue; - - if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) - continue; - if (memcmp(p->cs, buf-sl+1, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } -skip_loop: - shift = 1; - } else { - COUNT(tctx->stat_total_shift += shift); - COUNT(tctx->stat_num_shift++); - } - buf += shift; - } - - return cnt; -} - -uint32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - WmPattern *p; - WmHashItem *thi, *hi; - - if (buflen == 0) - return 0; - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - uint8_t *bitarray = NULL; - if (pmq) { - bitarray = alloca(pmq->pattern_id_bitarray_size); - memset(bitarray, 0, pmq->pattern_id_bitarray_size); - } - - if (mpm_ctx->minlen == 1) { - while (buf <= bufend) { - uint8_t h = wm_tolower(*buf); - hi = &ctx->hash1[h]; - - if (hi->flags & 0x01) { - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - if (p->len != 1) - continue; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (wm_tolower(*buf) == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } - } else { - if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id, bitarray, p->sids, p->sids_size); - } - } - } - } - buf += 1; - } - } - //printf("WmSearch1: after 1byte cnt %" PRIu32 "\n", cnt); - if (mpm_ctx->maxlen > 1) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - //printf("WmSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); - } - return cnt; -} - -/** - * \brief Function to get the user defined values for wumanber algorithm from - * the config file 'suricata.yaml' - */ -void WmGetConfig() -{ - ConfNode *wm_conf; - const char *hash_val = NULL; - const char *bloom_val = NULL; - - /* init defaults */ - wm_hash_size = HASHSIZE_LOW; - wm_bloom_size = BLOOMSIZE_MEDIUM; - - ConfNode *pm = ConfGetNode("pattern-matcher"); - - if (pm != NULL) { - - TAILQ_FOREACH(wm_conf, &pm->head, next) { - if (strncmp(wm_conf->val, "wumanber", 8) == 0) { - hash_val = ConfNodeLookupChildValue(wm_conf->head.tqh_first, - "hash_size"); - bloom_val = ConfNodeLookupChildValue(wm_conf->head.tqh_first, - "bf_size"); - - if (hash_val != NULL) - wm_hash_size = MpmGetHashSize(hash_val); - - if (bloom_val != NULL) - wm_bloom_size = MpmGetBloomSize(bloom_val); - - SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", - wm_hash_size, wm_bloom_size); - } - } - } -} - -void WmInitCtx (MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p", mpm_ctx); - - mpm_ctx->ctx = SCMalloc(sizeof(WmCtx)); - if (mpm_ctx->ctx == NULL) - return; - memset(mpm_ctx->ctx, 0, sizeof(WmCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(WmCtx); - - /* initialize the hash we use to speed up pattern insertions */ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(WmPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) - return; - - memset(ctx->init_hash, 0, sizeof(WmPattern *) * INIT_HASH_SIZE); - - /* Initialize the defaults value from the config file. The given check make - sure that we query config file only once for config values */ - if (wm_hash_size == 0) - WmGetConfig(); - -} - -void WmDestroyCtx(MpmCtx *mpm_ctx) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash) { - SCFree(ctx->init_hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(WmPattern *)); - } - - if (ctx->parray) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - WmFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(WmPattern)); - } - - if (ctx->bloom) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); - - BloomFilterFree(ctx->bloom[h]); - } - - SCFree(ctx->bloom); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); - } - - if (ctx->hash) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->hash[h] == NULL) - continue; - - WmHashFree(mpm_ctx, ctx->hash[h]); - } - - SCFree(ctx->hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(WmHashItem) * ctx->hash_size); - } - - if (ctx->shifttable) { - SCFree(ctx->shifttable); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(uint16_t) * ctx->hash_size); - } - - if (ctx->pminlen) { - SCFree(ctx->pminlen); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(WmCtx); -} - -void WmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - -#ifdef WUMANBER_COUNTERS - mpm_thread_ctx->ctx = SCMalloc(sizeof(WmThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) - return; - - memset(mpm_thread_ctx->ctx, 0, sizeof(WmThreadCtx)); - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(WmThreadCtx); -#endif -} - -void WmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - WmThreadCtx *ctx = (WmThreadCtx *)mpm_thread_ctx->ctx; - if (ctx != NULL) { /* size can be 0 when optimized */ - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(WmThreadCtx); - SCFree(mpm_thread_ctx->ctx); - } -} - -void MpmWuManberRegister (void) -{ - mpm_table[MPM_WUMANBER].name = "wumanber"; - mpm_table[MPM_WUMANBER].max_pattern_length = 0; - mpm_table[MPM_WUMANBER].InitCtx = WmInitCtx; - mpm_table[MPM_WUMANBER].InitThreadCtx = WmThreadInitCtx; - mpm_table[MPM_WUMANBER].DestroyCtx = WmDestroyCtx; - mpm_table[MPM_WUMANBER].DestroyThreadCtx = WmThreadDestroyCtx; - mpm_table[MPM_WUMANBER].AddPattern = WmAddPatternCS; - mpm_table[MPM_WUMANBER].AddPatternNocase = WmAddPatternCI; - mpm_table[MPM_WUMANBER].Prepare = WmPreparePatterns; - mpm_table[MPM_WUMANBER].Search = WmSearch; - mpm_table[MPM_WUMANBER].Cleanup = NULL; - mpm_table[MPM_WUMANBER].PrintCtx = WmPrintInfo; - mpm_table[MPM_WUMANBER].PrintThreadCtx = WmPrintSearchStats; - mpm_table[MPM_WUMANBER].RegisterUnittests = WmRegisterTests; - - /* create table for O(1) lowercase conversion lookup */ - int c = 0; - for ( ; c < 256; c++) { - if (c >= 'A' && c <= 'Z') - lowercasetable[c] = (c + ('a' - 'A')); - else - lowercasetable[c] = c; - } -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -int WmTestInitCtx01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - WmInitCtx(&mpm_ctx); - - if (mpm_ctx.ctx != NULL) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitCtx02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - WmInitCtx(&mpm_ctx); - - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - if (ctx->parray == NULL) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitCtx03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - if (mpm_table[MPM_WUMANBER].Search == WmSearch) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestThreadInitCtx01 (void) -{ -#ifdef WUMANBER_COUNTERS - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - if (mpm_thread_ctx.memory_cnt == 2) - result = 1; - else - printf("mpm_thread_ctx.memory_cnt %"PRIu32", expected 2: ", mpm_thread_ctx.memory_cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -#else - return 1; -#endif -} - -int WmTestThreadInitCtx02 (void) -{ -#ifdef WUMANBER_COUNTERS - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx.ctx; - - if (tctx->search_stat_shift_null == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); -#else - int result = 1; -#endif - return result; -} - -int WmTestInitAddPattern01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - int ret = MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - if (ret == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitAddPattern02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - if (ctx->init_hash != NULL) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitAddPattern03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, 0); - if (pat != NULL) { - if (pat->len == 4) - result = 1; - } - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitAddPattern04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, MPM_PATTERN_FLAG_NOCASE); - if (pat != NULL) { - if (pat->flags & MPM_PATTERN_FLAG_NOCASE) - result = 1; - } - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitAddPattern05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, 0); - if (pat != NULL) { - if (!(pat->flags & MPM_PATTERN_FLAG_NOCASE)) - result = 1; - } - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitAddPattern06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, 0); - if (pat != NULL) { - if (memcmp(pat->cs, "abcd", 4) == 0) - result = 1; - } - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - - if (ctx->Search == WmSearch1) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - if (ctx->shiftlen == 4) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - if (ctx->shifttable[1] == 4) - result = 1; - else - printf("4 != %" PRIu32 ": ", ctx->shifttable[1]); - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - - if (ctx->Search == WmSearch1) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - if (ctx->shiftlen == 4) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - if (ctx->shifttable[1] == 4) - result = 1; - else - printf("4 != %" PRIu32 ": ", ctx->shifttable[1]); - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //mpm_ctx.PrintCtx(&mpm_ctx); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch01Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - - ctx->hash_size = HASH12_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //mpm_ctx.PrintCtx(&mpm_ctx); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch01Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - - ctx->hash_size = HASH14_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //mpm_ctx.PrintCtx(&mpm_ctx); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch01Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - - ctx->hash_size = HASH15_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //mpm_ctx.PrintCtx(&mpm_ctx); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch01Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - - ctx->hash_size = HASH16_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //mpm_ctx.PrintCtx(&mpm_ctx); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abce", 4); - - if (cnt == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"efgh", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"eFgH", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdEfGh", 8); - - if (cnt == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch07 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"eFgH", 4, 0, 0, 1, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdEfGh", 8); - - if (cnt == 2) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch08 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 2) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch09 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch10 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bc", 2, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"gh", 2, 0, 0, 1, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 2) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch11 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"d", 1, 0, 0, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"h", 1, 0, 0, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 3) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"d", 1, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 ": ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch13 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"h", 1, 0, 0, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 ": ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 2) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -/** \todo VJ disabled because it tests the old match storage */ -#if 0 -int WmTestSearch15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 1, 1, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 1, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 1, 1, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - uint32_t len = mpm_thread_ctx.match[1].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 1, 1, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 1, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 1, 1, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch17 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch18Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH12_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch18Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH14_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch18Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH15_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch18 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH16_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch18Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH16_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch19 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch19Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH12_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch19Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH14_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch19Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH15_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch19Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH16_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch20 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch20Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH12_SIZE; /* force hash12 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch20Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH14_SIZE; /* force hash14 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch20Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH15_SIZE; /* force hash15 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch20Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH16_SIZE; /* force hash16 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch21 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch21Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH12_SIZE; /* force hash16 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //WmPrintInfo(&mpm_ctx); - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch21Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH14_SIZE; /* force hash16 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //WmPrintInfo(&mpm_ctx); - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch21Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH15_SIZE; /* force hash16 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //WmPrintInfo(&mpm_ctx); - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch21Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH16_SIZE; /* force hash16 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //WmPrintInfo(&mpm_ctx); - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} -#endif -static int WmTestSearch22Hash9 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - ctx->hash_size = HASH9_SIZE; /* force hash size */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch22Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - ctx->hash_size = HASH12_SIZE; /* force hash size */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch22Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - ctx->hash_size = HASH14_SIZE; /* force hash size */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch22Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - ctx->hash_size = HASH15_SIZE; /* force hash size */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch22Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - ctx->hash_size = HASH16_SIZE; /* force hash size */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} -#endif /* UNITTESTS */ - -void WmRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("WmTestInitCtx01", WmTestInitCtx01, 1); - UtRegisterTest("WmTestInitCtx02", WmTestInitCtx02, 1); - UtRegisterTest("WmTestInitCtx03", WmTestInitCtx03, 1); - - UtRegisterTest("WmTestThreadInitCtx01", WmTestThreadInitCtx01, 1); - UtRegisterTest("WmTestThreadInitCtx02", WmTestThreadInitCtx02, 1); - - UtRegisterTest("WmTestInitAddPattern01", WmTestInitAddPattern01, 1); - UtRegisterTest("WmTestInitAddPattern02", WmTestInitAddPattern02, 1); - UtRegisterTest("WmTestInitAddPattern03", WmTestInitAddPattern03, 1); - UtRegisterTest("WmTestInitAddPattern04", WmTestInitAddPattern04, 1); - UtRegisterTest("WmTestInitAddPattern05", WmTestInitAddPattern05, 1); - UtRegisterTest("WmTestInitAddPattern06", WmTestInitAddPattern06, 1); - - UtRegisterTest("WmTestPrepare01", WmTestPrepare01, 1); - UtRegisterTest("WmTestPrepare02", WmTestPrepare02, 1); - UtRegisterTest("WmTestPrepare03", WmTestPrepare03, 1); - UtRegisterTest("WmTestPrepare04", WmTestPrepare01, 1); - UtRegisterTest("WmTestPrepare05", WmTestPrepare02, 1); - UtRegisterTest("WmTestPrepare06", WmTestPrepare03, 1); - - UtRegisterTest("WmTestSearch01", WmTestSearch01, 1); - UtRegisterTest("WmTestSearch01Hash12", WmTestSearch01Hash12, 1); - UtRegisterTest("WmTestSearch01Hash14", WmTestSearch01Hash14, 1); - UtRegisterTest("WmTestSearch01Hash15", WmTestSearch01Hash15, 1); - UtRegisterTest("WmTestSearch01Hash16", WmTestSearch01Hash16, 1); - - UtRegisterTest("WmTestSearch02", WmTestSearch02, 1); - UtRegisterTest("WmTestSearch03", WmTestSearch03, 1); - UtRegisterTest("WmTestSearch04", WmTestSearch04, 1); - UtRegisterTest("WmTestSearch05", WmTestSearch05, 1); - UtRegisterTest("WmTestSearch06", WmTestSearch06, 1); - UtRegisterTest("WmTestSearch07", WmTestSearch07, 1); - UtRegisterTest("WmTestSearch08", WmTestSearch08, 1); - UtRegisterTest("WmTestSearch09", WmTestSearch09, 1); - UtRegisterTest("WmTestSearch10", WmTestSearch10, 1); - UtRegisterTest("WmTestSearch11", WmTestSearch11, 1); - UtRegisterTest("WmTestSearch12", WmTestSearch12, 1); - UtRegisterTest("WmTestSearch13", WmTestSearch13, 1); - - UtRegisterTest("WmTestSearch14", WmTestSearch14, 1); -#if 0 - UtRegisterTest("WmTestSearch15", WmTestSearch15, 1); - UtRegisterTest("WmTestSearch16", WmTestSearch16, 1); - UtRegisterTest("WmTestSearch17", WmTestSearch17, 1); - - UtRegisterTest("WmTestSearch18", WmTestSearch18, 1); - UtRegisterTest("WmTestSearch18Hash12", WmTestSearch18Hash12, 1); - UtRegisterTest("WmTestSearch18Hash14", WmTestSearch18Hash14, 1); - UtRegisterTest("WmTestSearch18Hash15", WmTestSearch18Hash15, 1); - UtRegisterTest("WmTestSearch18Hash16", WmTestSearch18Hash16, 1); - - UtRegisterTest("WmTestSearch19", WmTestSearch19, 1); - UtRegisterTest("WmTestSearch19Hash12", WmTestSearch19Hash12, 1); - UtRegisterTest("WmTestSearch19Hash14", WmTestSearch19Hash14, 1); - UtRegisterTest("WmTestSearch19Hash15", WmTestSearch19Hash15, 1); - UtRegisterTest("WmTestSearch19Hash16", WmTestSearch19Hash16, 1); - - UtRegisterTest("WmTestSearch20", WmTestSearch20, 1); - UtRegisterTest("WmTestSearch20Hash12", WmTestSearch20Hash12, 1); - UtRegisterTest("WmTestSearch20Hash14", WmTestSearch20Hash14, 1); - UtRegisterTest("WmTestSearch20Hash15", WmTestSearch20Hash15, 1); - UtRegisterTest("WmTestSearch20Hash16", WmTestSearch20Hash16, 1); - - UtRegisterTest("WmTestSearch21", WmTestSearch21, 1); - UtRegisterTest("WmTestSearch21Hash12", WmTestSearch21Hash12, 1); - UtRegisterTest("WmTestSearch21Hash14", WmTestSearch21Hash14, 1); - UtRegisterTest("WmTestSearch21Hash15", WmTestSearch21Hash15, 1); - UtRegisterTest("WmTestSearch21Hash16", WmTestSearch21Hash16, 1); -#endif - UtRegisterTest("WmTestSearch22Hash9", WmTestSearch22Hash9, 1); - UtRegisterTest("WmTestSearch22Hash12", WmTestSearch22Hash12, 1); - UtRegisterTest("WmTestSearch22Hash14", WmTestSearch22Hash14, 1); - UtRegisterTest("WmTestSearch22Hash15", WmTestSearch22Hash15, 1); - UtRegisterTest("WmTestSearch22Hash16", WmTestSearch22Hash16, 1); -#endif /* UNITTESTS */ -} - diff --git a/src/util-mpm-wumanber.h b/src/util-mpm-wumanber.h deleted file mode 100644 index ef6998145d1b..000000000000 --- a/src/util-mpm-wumanber.h +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright (C) 2007-2010 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 - */ - -#ifndef __UTIL_MPM_WUMANBER_H__ -#define __UTIL_MPM_WUMANBER_H__ - -#include "util-mpm.h" -#include "util-bloomfilter.h" - -//#define WUMANBER_COUNTERS - -typedef struct WmPattern_ { - uint8_t *cs; /* case sensitive */ - uint8_t *ci; /* case INsensitive */ - uint16_t len; - struct WmPattern_ *next; - uint16_t prefix_ci; - uint16_t prefix_cs; - uint8_t flags; - uint32_t id; /* global pattern id */ - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; - -} WmPattern; - -typedef struct WmHashItem_ { - uint8_t flags; - uint16_t idx; - struct WmHashItem_ *nxt; -} WmHashItem; - -typedef struct WmCtx_ { - /* hash used during ctx initialization */ - WmPattern **init_hash; - - uint16_t shiftlen; - - uint32_t hash_size; - WmHashItem **hash; - BloomFilter **bloom; - uint8_t *pminlen; /* array containing the minimal length - of the patters in a hash bucket. Used - for the BloomFilter. */ - WmHashItem hash1[256]; - - /* we store our own search func ptr here for WmSearch1 */ - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - /* we store our own multi byte search func ptr here for WmSearch1 */ - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - /* pattern arrays */ - WmPattern **parray; - - /* only used for multibyte pattern search */ - uint16_t *shifttable; -} WmCtx; - -typedef struct WmThreadCtx_ { -#ifdef WUMANBER_COUNTERS - uint32_t stat_pminlen_calls; - uint32_t stat_pminlen_total; - uint32_t stat_bloom_calls; - uint32_t stat_bloom_hits; - uint32_t stat_shift_null; - uint32_t stat_loop_match; - uint32_t stat_loop_no_match; - uint32_t stat_num_shift; - uint32_t stat_total_shift; -#endif /* WUMANBER_COUNTERS */ -} WmThreadCtx; - -void MpmWuManberRegister(void); - -#endif /* __UTIL_MPM_WUMANBER_H__ */ - diff --git a/src/util-mpm.c b/src/util-mpm.c index 01aafc152f79..9b9b97ce6d37 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -28,11 +28,7 @@ #include "util-debug.h" /* include pattern matchers */ -#include "util-mpm-wumanber.h" -#include "util-mpm-b2g.h" -#include "util-mpm-b3g.h" #include "util-mpm-ac.h" -#include "util-mpm-ac-gfbs.h" #include "util-mpm-ac-bs.h" #include "util-mpm-ac-tile.h" #include "util-mpm-hs.h" @@ -536,43 +532,6 @@ MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size) return new_size; } -/** \brief Verify and store a match - * - * used at search runtime - * - * \param thread_ctx mpm thread ctx - * \param pmq storage for match results - * \param patid pattern ID being checked - * \param bitarray Array of bits for patterns IDs found in current search - * \param sids pointer to array of Signature IDs - * \param sids_size number of Signature IDs in sids array. - * - * \retval 0 no match after all - * \retval 1 (new) match - */ -int -MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t patid, - uint8_t *bitarray, SigIntId *sids, uint32_t sids_size) -{ - SCEnter(); - - /* Handle pattern id storage */ - if (pmq != NULL && pmq->pattern_id_bitarray != NULL) { - SCLogDebug("using pattern id arrays, storing %"PRIu32, patid); - - if ((bitarray[(patid / 8)] & (1<<(patid % 8))) == 0) { - bitarray[(patid / 8)] |= (1<<(patid % 8)); - /* flag this pattern id as being added now */ - pmq->pattern_id_bitarray[(patid / 8)] |= (1<<(patid % 8)); - /* append the pattern_id to the array with matches */ - MpmAddPid(pmq, patid); - MpmAddSids(pmq, sids, sids_size); - } - } - - SCReturnInt(1); -} - /** * \brief Merge two pmq's bitarrays * @@ -668,12 +627,8 @@ void MpmTableSetup(void) { memset(mpm_table, 0, sizeof(mpm_table)); - MpmWuManberRegister(); - MpmB2gRegister(); - MpmB3gRegister(); MpmACRegister(); MpmACBSRegister(); - MpmACGfbsRegister(); MpmACTileRegister(); #ifdef BUILD_HYPERSCAN MpmHSRegister(); @@ -683,62 +638,6 @@ void MpmTableSetup(void) #endif /* __SC_CUDA_SUPPORT__ */ } -/** \brief Function to return the default hash size for the mpm algorithm, - * which has been defined by the user in the config file - * - * \param conf_val pointer to the string value of hash size - * \retval hash_value returns the hash value as defined by user, otherwise - * default low size value - */ -uint32_t MpmGetHashSize(const char *conf_val) -{ - SCEnter(); - uint32_t hash_value = HASHSIZE_LOW; - - if(strcmp(conf_val, "lowest") == 0) { - hash_value = HASHSIZE_LOWEST; - } else if(strcmp(conf_val, "low") == 0) { - hash_value = HASHSIZE_LOW; - } else if(strcmp(conf_val, "medium") == 0) { - hash_value = HASHSIZE_MEDIUM; - } else if(strcmp(conf_val, "high") == 0) { - hash_value = HASHSIZE_HIGH; - /* "highest" is supported in 1.0 to 1.0.2, so we keep supporting - * it for backwards compatibility */ - } else if(strcmp(conf_val, "highest") == 0) { - hash_value = HASHSIZE_HIGHER; - } else if(strcmp(conf_val, "higher") == 0) { - hash_value = HASHSIZE_HIGHER; - } else if(strcmp(conf_val, "max") == 0) { - hash_value = HASHSIZE_MAX; - } - - SCReturnInt(hash_value); -} - -/** \brief Function to return the default bloomfilter size for the mpm algorithm, - * which has been defined by the user in the config file - * - * \param conf_val pointer to the string value of bloom filter size - * \retval bloom_value returns the bloom filter value as defined by user, - * otherwise default medium size value - */ -uint32_t MpmGetBloomSize(const char *conf_val) -{ - SCEnter(); - uint32_t bloom_value = BLOOMSIZE_MEDIUM; - - if(strncmp(conf_val, "low", 3) == 0) { - bloom_value = BLOOMSIZE_LOW; - } else if(strncmp(conf_val, "medium", 6) == 0) { - bloom_value = BLOOMSIZE_MEDIUM; - } else if(strncmp(conf_val, "high", 4) == 0) { - bloom_value = BLOOMSIZE_HIGH; - } - - SCReturnInt(bloom_value); -} - int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) diff --git a/src/util-mpm.h b/src/util-mpm.h index 15d8d5b9e3ff..78ca934f0d07 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -25,51 +25,14 @@ #define __UTIL_MPM_H__ #include "suricata-common.h" -#define MPM_ENDMATCH_SINGLE 0x01 /**< A single match is sufficient. No - depth, offset, etc settings. */ -#define MPM_ENDMATCH_OFFSET 0x02 /**< has offset setting */ -#define MPM_ENDMATCH_DEPTH 0x04 /**< has depth setting */ -#define MPM_ENDMATCH_NOSEARCH 0x08 /**< if this matches, no search is - required (for this pattern) */ - -#define HASHSIZE_LOWEST 2048 /**< Lowest hash size for the multi - pattern matcher algorithms */ -#define HASHSIZE_LOW 4096 /**< Low hash size for the multi - pattern matcher algorithms */ -#define HASHSIZE_MEDIUM 8192 /**< Medium hash size for the multi - pattern matcher algorithms */ -#define HASHSIZE_HIGH 16384 /**< High hash size for the multi - pattern matcher algorithms */ -#define HASHSIZE_HIGHER 32768 /**< Higher hash size for the multi - pattern matcher algorithms */ -#define HASHSIZE_MAX 65536 /**< Max hash size for the multi - pattern matcher algorithms */ -#define BLOOMSIZE_LOW 512 /*<* Low bloomfilter size for the multi - pattern matcher algorithms */ -#define BLOOMSIZE_MEDIUM 1024 /**< Medium bloomfilter size for the multi - pattern matcher algorithms */ -#define BLOOMSIZE_HIGH 2048 /**< High bloomfilter size for the multi - pattern matcher algorithms */ - enum { MPM_NOTSET = 0, - /* wumanber as the name suggests */ - MPM_WUMANBER, - /* bndmq 2 gram */ - MPM_B2G, - /* bndmq 3 gram */ - MPM_B3G, - MPM_B2GC, - MPM_B2GM, - /* aho-corasick */ MPM_AC, #ifdef __SC_CUDA_SUPPORT__ MPM_AC_CUDA, #endif - /* aho-corasick-goto-failure state based */ - MPM_AC_GFBS, MPM_AC_BS, MPM_AC_TILE, MPM_HS, @@ -256,12 +219,8 @@ void PmqFree(PatternMatcherQueue *); void MpmTableSetup(void); void MpmRegisterTests(void); -int MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t patid, - uint8_t *bitarray, SigIntId *sids, uint32_t sids_size); void MpmInitCtx(MpmCtx *mpm_ctx, uint16_t matcher); void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t, uint32_t); -uint32_t MpmGetHashSize(const char *); -uint32_t MpmGetBloomSize(const char *); int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, diff --git a/suricata.yaml.in b/suricata.yaml.in index 53ea4d472fcd..152f2e757db5 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -711,35 +711,6 @@ cuda: mpm-algo: ac -# The memory settings for hash size of these algorithms can vary from lowest -# (2048) - low (4096) - medium (8192) - high (16384) - higher (32768) - max -# (65536). The bloomfilter sizes of these algorithms can vary from low (512) - -# medium (1024) - high (2048). -# -# For B2g/B3g algorithms, there is a support for two different scan/search -# algorithms. For B2g the scan algorithms are B2gScan & B2gScanBNDMq, and -# search algorithms are B2gSearch & B2gSearchBNDMq. For B3g scan algorithms -# are B3gScan & B3gScanBNDMq, and search algorithms are B3gSearch & -# B3gSearchBNDMq. -# -# For B2g the different scan/search algorithms and, hash and bloom -# filter size settings. For B3g the different scan/search algorithms and, hash -# and bloom filter size settings. For wumanber the hash and bloom filter size -# settings. - -pattern-matcher: - - b2g: - search-algo: B2gSearchBNDMq - hash-size: low - bf-size: medium - - b3g: - search-algo: B3gSearchBNDMq - hash-size: low - bf-size: medium - - wumanber: - hash-size: low - bf-size: medium - # Defrag settings: defrag: From 0d3f671b55d918d3e9c44222162c081df5c666b8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Sep 2015 11:15:09 +0200 Subject: [PATCH 1138/2553] detect: constify mpm/detect funcs --- src/detect-engine-analyzer.c | 4 ++-- src/detect-engine-analyzer.h | 2 +- src/detect-engine-mpm.c | 10 +++++----- src/detect-engine-mpm.h | 6 +++--- src/detect-engine-proto.c | 2 +- src/detect-engine-proto.h | 2 +- src/detect-engine-siggroup.c | 8 ++++---- src/detect-engine-siggroup.h | 2 +- src/detect-parse.c | 4 ++-- src/detect-parse.h | 2 +- src/util-mpm.c | 6 +++--- src/util-mpm.h | 6 +++--- 12 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 066d41c6edfa..cf9c2cf4fa60 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -402,7 +402,7 @@ int PerCentEncodingMatch (uint8_t *content, uint8_t content_len) return ret; } -static void EngineAnalysisRulesPrintFP(Signature *s) +static void EngineAnalysisRulesPrintFP(const Signature *s) { DetectContentData *fp_cd = NULL; SigMatch *mpm_sm = s->mpm_sm; @@ -506,7 +506,7 @@ void EngineAnalysisRulesFailure(char *line, char *file, int lineno) * * \param s Pointer to the signature. */ -void EngineAnalysisRules(Signature *s, char *line) +void EngineAnalysisRules(const Signature *s, const char *line) { uint32_t rule_bidirectional = 0; uint32_t rule_pcre = 0; diff --git a/src/detect-engine-analyzer.h b/src/detect-engine-analyzer.h index d92b20604c53..d9a808159594 100644 --- a/src/detect-engine-analyzer.h +++ b/src/detect-engine-analyzer.h @@ -36,7 +36,7 @@ int PerCentEncodingSetup (); int PerCentEncodingMatch (uint8_t *content, uint8_t content_len); void EngineAnalysisFP(Signature *s, char *line); -void EngineAnalysisRules(Signature *s, char *line); +void EngineAnalysisRules(const Signature *s, const char *line); void EngineAnalysisRulesFailure(char *line, char *file, int lineno); #endif /* __DETECT_ENGINE_ANALYZER_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index d5447aea7455..3fbe14fd993e 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -76,7 +76,7 @@ * \retval 1 true * \retval 0 false */ -int SignatureHasPacketContent(Signature *s) +int SignatureHasPacketContent(const Signature *s) { SCEnter(); @@ -110,7 +110,7 @@ int SignatureHasPacketContent(Signature *s) * \retval 1 true * \retval 0 false */ -int SignatureHasStreamContent(Signature *s) +int SignatureHasStreamContent(const Signature *s) { SCEnter(); @@ -1257,7 +1257,7 @@ static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, return; } -static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, +static void PopulateMpmAddPatternToMpm(const DetectEngineCtx *de_ctx, SigGroupHead *sgh, Signature *s, SigMatch *mpm_sm) { @@ -1929,7 +1929,7 @@ SigMatch *RetrieveFPForSigV2(Signature *s) * * \retval 0 Always. */ -static int PatternMatchPreparePopulateMpm(DetectEngineCtx *de_ctx, +static int PatternMatchPreparePopulateMpm(const DetectEngineCtx *de_ctx, SigGroupHead *sgh) { uint32_t sig = 0; @@ -1949,7 +1949,7 @@ static int PatternMatchPreparePopulateMpm(DetectEngineCtx *de_ctx, * \todo do error checking * \todo rewrite the COPY stuff */ -int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) +int PatternMatchPrepareGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sh) { Signature *s = NULL; uint32_t has_co_packet = 0; /**< our sgh has packet payload inspecting content */ diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 02df56f47bdc..d2ce148149a9 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -64,7 +64,7 @@ void PatternMatchDestroy(MpmCtx *, uint16_t); void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t); void PatternMatchThreadPrint(MpmThreadCtx *, uint16_t); -int PatternMatchPrepareGroup(DetectEngineCtx *, SigGroupHead *); +int PatternMatchPrepareGroup(const DetectEngineCtx *, SigGroupHead *); void DetectEngineThreadCtxInfo(ThreadVars *, DetectEngineThreadCtx *); void PatternMatchDestroyGroup(SigGroupHead *); @@ -78,8 +78,8 @@ void MpmPatternIdTableFreeHash(MpmPatternIdStore *); uint32_t MpmPatternIdStoreGetMaxId(MpmPatternIdStore *); uint32_t DetectContentGetId(MpmPatternIdStore *, DetectContentData *); -int SignatureHasPacketContent(Signature *); -int SignatureHasStreamContent(Signature *); +int SignatureHasPacketContent(const Signature *); +int SignatureHasStreamContent(const Signature *); SigMatch *RetrieveFPForSig(Signature *s); SigMatch *RetrieveFPForSigV2(Signature *s); diff --git a/src/detect-engine-proto.c b/src/detect-engine-proto.c index cacaeee3b72a..54f26b721699 100644 --- a/src/detect-engine-proto.c +++ b/src/detect-engine-proto.c @@ -162,7 +162,7 @@ int DetectProtoParse(DetectProto *dp, char *str) * \param proto protocol (such as IPPROTO_TCP) to look for * \retval 0 protocol not in the set * \retval 1 protocol is in the set */ -int DetectProtoContainsProto(DetectProto *dp, int proto) +int DetectProtoContainsProto(const DetectProto *dp, int proto) { if (dp->flags & DETECT_PROTO_ANY) return 1; diff --git a/src/detect-engine-proto.h b/src/detect-engine-proto.h index 4edfe3b5333b..05f8f4bef509 100644 --- a/src/detect-engine-proto.h +++ b/src/detect-engine-proto.h @@ -40,7 +40,7 @@ typedef struct DetectProto_ { /* prototypes */ int DetectProtoParse(DetectProto *dp, char *str); -int DetectProtoContainsProto(DetectProto *, int); +int DetectProtoContainsProto(const DetectProto *, int); void DetectProtoTests(void); diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 89e0eb797093..d25e8d257d54 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -150,7 +150,7 @@ void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh) * \retval sgh Pointer to the newly init SigGroupHead on success; or NULL in * case of error. */ -static SigGroupHead *SigGroupHeadAlloc(DetectEngineCtx *de_ctx, uint32_t size) +static SigGroupHead *SigGroupHeadAlloc(const DetectEngineCtx *de_ctx, uint32_t size) { SigGroupHead *sgh = SCMalloc(sizeof(SigGroupHead)); if (unlikely(sgh == NULL)) @@ -998,7 +998,7 @@ void SigGroupHeadFreeMpmArrays(DetectEngineCtx *de_ctx) return; } -static uint16_t SignatureGetMpmPatternLen(Signature *s, int list) +static uint16_t SignatureGetMpmPatternLen(const Signature *s, const int list) { if (s->sm_lists[list] != NULL && s->mpm_sm != NULL && SigMatchListSMBelongsTo(s, s->mpm_sm) == list) @@ -1020,8 +1020,8 @@ static uint16_t SignatureGetMpmPatternLen(Signature *s, int list) * \retval 0 On success. * \retval -1 On failure. */ -int SigGroupHeadAppendSig(DetectEngineCtx *de_ctx, SigGroupHead **sgh, - Signature *s) +int SigGroupHeadAppendSig(const DetectEngineCtx *de_ctx, SigGroupHead **sgh, + const Signature *s) { if (de_ctx == NULL) return 0; diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index cd6810a1bf22..69b24fd47335 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -26,7 +26,7 @@ void DetectSigGroupPrintMemory(void); -int SigGroupHeadAppendSig(DetectEngineCtx *, SigGroupHead **, Signature *); +int SigGroupHeadAppendSig(const DetectEngineCtx *, SigGroupHead **, const Signature *); int SigGroupHeadClearSigs(SigGroupHead *); int SigGroupHeadCopySigs(DetectEngineCtx *, SigGroupHead *, SigGroupHead **); diff --git a/src/detect-parse.c b/src/detect-parse.c index e499b483c7ce..4139b9b102fc 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -419,12 +419,12 @@ void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, return; } -int SigMatchListSMBelongsTo(Signature *s, SigMatch *key_sm) +int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm) { int list = 0; for (list = 0; list < DETECT_SM_LIST_MAX; list++) { - SigMatch *sm = s->sm_lists[list]; + const SigMatch *sm = s->sm_lists[list]; while (sm != NULL) { if (sm == key_sm) return list; diff --git a/src/detect-parse.h b/src/detect-parse.h index c90560a916cf..5c13e4c99834 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -55,7 +55,7 @@ Signature *DetectEngineAppendSig(DetectEngineCtx *, char *); void SigMatchAppendSMToList(Signature *, SigMatch *, int); void SigMatchRemoveSMFromList(Signature *, SigMatch *, int); -int SigMatchListSMBelongsTo(Signature *, SigMatch *); +int SigMatchListSMBelongsTo(const Signature *, const SigMatch *); int DetectParseDupSigHashInit(DetectEngineCtx *); void DetectParseDupSigHashFree(DetectEngineCtx *); diff --git a/src/util-mpm.c b/src/util-mpm.c index 9b9b97ce6d37..8398ac7556d2 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -184,7 +184,7 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam } } -int32_t MpmFactoryIsMpmCtxAvailable(DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) +int32_t MpmFactoryIsMpmCtxAvailable(const DetectEngineCtx *de_ctx, const MpmCtx *mpm_ctx) { if (mpm_ctx == NULL) return 0; @@ -203,7 +203,7 @@ int32_t MpmFactoryIsMpmCtxAvailable(DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) } } -MpmCtx *MpmFactoryGetMpmCtxForProfile(DetectEngineCtx *de_ctx, int32_t id, int direction) +MpmCtx *MpmFactoryGetMpmCtxForProfile(const DetectEngineCtx *de_ctx, int32_t id, int direction) { if (id == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { MpmCtx *mpm_ctx = SCMalloc(sizeof(MpmCtx)); @@ -226,7 +226,7 @@ MpmCtx *MpmFactoryGetMpmCtxForProfile(DetectEngineCtx *de_ctx, int32_t id, int d } } -void MpmFactoryReClaimMpmCtx(DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) +void MpmFactoryReClaimMpmCtx(const DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) { if (mpm_ctx == NULL) return; diff --git a/src/util-mpm.h b/src/util-mpm.h index 78ca934f0d07..72d56e611592 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -205,10 +205,10 @@ void MpmCudaEnvironmentSetup(); struct DetectEngineCtx_; int32_t MpmFactoryRegisterMpmCtxProfile(struct DetectEngineCtx_ *, const char *, uint8_t); -void MpmFactoryReClaimMpmCtx(struct DetectEngineCtx_ *, MpmCtx *); -MpmCtx *MpmFactoryGetMpmCtxForProfile(struct DetectEngineCtx_ *, int32_t, int); +void MpmFactoryReClaimMpmCtx(const struct DetectEngineCtx_ *, MpmCtx *); +MpmCtx *MpmFactoryGetMpmCtxForProfile(const struct DetectEngineCtx_ *, int32_t, int); void MpmFactoryDeRegisterAllMpmCtxProfiles(struct DetectEngineCtx_ *); -int32_t MpmFactoryIsMpmCtxAvailable(struct DetectEngineCtx_ *, MpmCtx *); +int32_t MpmFactoryIsMpmCtxAvailable(const struct DetectEngineCtx_ *, const MpmCtx *); int PmqSetup(PatternMatcherQueue *, uint32_t); void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst); From 14d9ce7b2ec6379187d88d651c0d5231d75a5755 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 3 Oct 2015 17:57:27 +0200 Subject: [PATCH 1139/2553] detect/mpm: remove unused max_id param from API --- src/app-layer-detect-proto.c | 2 +- src/app-layer-smtp.c | 2 +- src/detect-engine-mpm.c | 6 ++-- src/detect-engine-mpm.h | 2 +- src/detect-engine.c | 12 ++----- src/util-mpm-ac-bs.c | 62 ++++++++++++++++++------------------ src/util-mpm-ac-tile.c | 62 +++++++++++++++++------------------- src/util-mpm-ac.c | 60 +++++++++++++++++----------------- src/util-mpm-hs.c | 62 +++++++++++++++++------------------- src/util-mpm.c | 4 +-- src/util-mpm.h | 4 +-- 11 files changed, 134 insertions(+), 144 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index da0de27f9454..3ccc6d0c9ba7 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1690,7 +1690,7 @@ AppLayerProtoDetectThreadCtx *AppLayerProtoDetectGetCtxThread(void) for (j = 0; j < 2; j++) { mpm_ctx = &alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx; mpm_tctx = &alpd_tctx->mpm_tctx[i][j]; - mpm_table[mpm_ctx->mpm_type].InitThreadCtx(mpm_ctx, mpm_tctx, 0); + mpm_table[mpm_ctx->mpm_type].InitThreadCtx(mpm_ctx, mpm_tctx); } } diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 1dd6cab1c2ca..8ef3a966ccaf 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1437,7 +1437,7 @@ static void SMTPSetMpmState(void) exit(EXIT_FAILURE); } memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitThreadCtx(smtp_mpm_thread_ctx, SMTP_MPM, 0); + MpmInitThreadCtx(smtp_mpm_thread_ctx, SMTP_MPM); uint32_t i = 0; for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) { diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 3fbe14fd993e..557e24f86cbb 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -813,10 +813,10 @@ void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matche if (mpm_table[mpm_matcher].DestroyThreadCtx != NULL) mpm_table[mpm_matcher].DestroyThreadCtx(NULL, mpm_thread_ctx); } -void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher, uint32_t max_id) +void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) { - SCLogDebug("mpm_thread_ctx %p, type %"PRIu16", max_id %"PRIu32"", mpm_thread_ctx, mpm_matcher, max_id); - MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher, max_id); + SCLogDebug("mpm_thread_ctx %p, type %"PRIu16, mpm_thread_ctx, mpm_matcher); + MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher); } diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index d2ce148149a9..44f9f1ad86db 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -58,7 +58,7 @@ void PacketPatternCleanup(ThreadVars *, DetectEngineThreadCtx *); void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg); void PatternMatchPrepare(MpmCtx *, uint16_t); -void PatternMatchThreadPrepare(MpmThreadCtx *, uint16_t type, uint32_t max_id); +void PatternMatchThreadPrepare(MpmThreadCtx *, uint16_t type); void PatternMatchDestroy(MpmCtx *, uint16_t); void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t); diff --git a/src/detect-engine.c b/src/detect-engine.c index 6ffbf7125a0f..84bd79b0167c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1455,15 +1455,9 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * { int i; - /** \todo we still depend on the global mpm_ctx here - * - * Initialize the thread pattern match ctx with the max size - * of the content and uricontent id's so our match lookup - * table is always big enough - */ - PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx)); - PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx)); - PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher, DetectUricontentMaxId(de_ctx)); + PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher); + PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher); + PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher); PmqSetup(&det_ctx->pmq, de_ctx->max_fp_id); for (i = 0; i < DETECT_SMSG_PMQ_NUM; i++) { diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index f19acbcd4a53..07227b572672 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -61,7 +61,7 @@ #include "util-memcpy.h" void SCACBSInitCtx(MpmCtx *); -void SCACBSInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); +void SCACBSInitThreadCtx(MpmCtx *, MpmThreadCtx *); void SCACBSDestroyCtx(MpmCtx *); void SCACBSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACBSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, @@ -1252,7 +1252,7 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) * \param mpm_thread_ctx Pointer to the mpm thread context. * \param matchsize We don't need this. */ -void SCACBSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) +void SCACBSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1713,7 +1713,7 @@ static int SCACBSTest01(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -1747,7 +1747,7 @@ static int SCACBSTest02(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); @@ -1780,7 +1780,7 @@ static int SCACBSTest03(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -1817,7 +1817,7 @@ static int SCACBSTest04(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); @@ -1851,7 +1851,7 @@ static int SCACBSTest05(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); @@ -1885,7 +1885,7 @@ static int SCACBSTest06(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 1); @@ -1917,7 +1917,7 @@ static int SCACBSTest07(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* should match 30 times */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); @@ -1962,7 +1962,7 @@ static int SCACBSTest08(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -1994,7 +1994,7 @@ static int SCACBSTest09(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); @@ -2026,7 +2026,7 @@ static int SCACBSTest10(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); @@ -2063,7 +2063,7 @@ static int SCACBSTest11(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) goto end; @@ -2110,7 +2110,7 @@ static int SCACBSTest12(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); @@ -2145,7 +2145,7 @@ static int SCACBSTest13(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; @@ -2179,7 +2179,7 @@ static int SCACBSTest14(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; @@ -2213,7 +2213,7 @@ static int SCACBSTest15(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; @@ -2247,7 +2247,7 @@ static int SCACBSTest16(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; @@ -2281,7 +2281,7 @@ static int SCACBSTest17(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; @@ -2315,7 +2315,7 @@ static int SCACBSTest18(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; @@ -2349,7 +2349,7 @@ static int SCACBSTest19(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; @@ -2382,7 +2382,7 @@ static int SCACBSTest20(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; @@ -2416,7 +2416,7 @@ static int SCACBSTest21(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); @@ -2448,7 +2448,7 @@ static int SCACBSTest22(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -2483,7 +2483,7 @@ static int SCACBSTest23(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); @@ -2515,7 +2515,7 @@ static int SCACBSTest24(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); @@ -2547,7 +2547,7 @@ static int SCACBSTest25(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); @@ -2581,7 +2581,7 @@ static int SCACBSTest26(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); @@ -2614,7 +2614,7 @@ static int SCACBSTest27(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); @@ -2647,7 +2647,7 @@ static int SCACBSTest28(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); @@ -2680,7 +2680,7 @@ static int SCACBSTest29(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdef", 5, 0, 0, 1, 0, 0); diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 747a24fc8867..2230cb3f2813 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -81,7 +81,7 @@ #include "util-mpm-ac-tile.h" void SCACTileInitCtx(MpmCtx *); -void SCACTileInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); +void SCACTileInitThreadCtx(MpmCtx *, MpmThreadCtx *); void SCACTileDestroyCtx(MpmCtx *); void SCACTileDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACTileAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, @@ -1289,10 +1289,8 @@ int SCACTilePreparePatterns(MpmCtx *mpm_ctx) * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. - * \param matchsize We don't need this. */ -void SCACTileInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - uint32_t matchsize) +void SCACTileInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1850,7 +1848,7 @@ static int SCACTileTest01(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -1884,7 +1882,7 @@ static int SCACTileTest02(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); @@ -1917,7 +1915,7 @@ static int SCACTileTest03(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -1954,7 +1952,7 @@ static int SCACTileTest04(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); @@ -1988,7 +1986,7 @@ static int SCACTileTest05(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); @@ -2022,7 +2020,7 @@ static int SCACTileTest06(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 1); @@ -2054,7 +2052,7 @@ static int SCACTileTest07(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* should match 30 times */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); @@ -2099,7 +2097,7 @@ static int SCACTileTest08(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -2131,7 +2129,7 @@ static int SCACTileTest09(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); @@ -2163,7 +2161,7 @@ static int SCACTileTest10(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); @@ -2200,7 +2198,7 @@ static int SCACTileTest11(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) goto end; @@ -2247,7 +2245,7 @@ static int SCACTileTest12(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); @@ -2282,7 +2280,7 @@ static int SCACTileTest13(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; @@ -2316,7 +2314,7 @@ static int SCACTileTest14(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; @@ -2350,7 +2348,7 @@ static int SCACTileTest15(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; @@ -2384,7 +2382,7 @@ static int SCACTileTest16(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; @@ -2418,7 +2416,7 @@ static int SCACTileTest17(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; @@ -2452,7 +2450,7 @@ static int SCACTileTest18(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; @@ -2486,7 +2484,7 @@ static int SCACTileTest19(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; @@ -2520,7 +2518,7 @@ static int SCACTileTest20(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; @@ -2554,7 +2552,7 @@ static int SCACTileTest21(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); @@ -2586,7 +2584,7 @@ static int SCACTileTest22(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -2621,7 +2619,7 @@ static int SCACTileTest23(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); @@ -2653,7 +2651,7 @@ static int SCACTileTest24(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); @@ -2685,7 +2683,7 @@ static int SCACTileTest25(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); @@ -2719,7 +2717,7 @@ static int SCACTileTest26(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); @@ -2752,7 +2750,7 @@ static int SCACTileTest27(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); @@ -2785,7 +2783,7 @@ static int SCACTileTest28(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 49df0d6ea927..8cf31fcd9c1e 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -70,7 +70,7 @@ #endif /* __SC_CUDA_SUPPORT__ */ void SCACInitCtx(MpmCtx *); -void SCACInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); +void SCACInitThreadCtx(MpmCtx *, MpmThreadCtx *); void SCACDestroyCtx(MpmCtx *); void SCACDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, @@ -1144,7 +1144,7 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) * \param mpm_thread_ctx Pointer to the mpm thread context. * \param matchsize We don't need this. */ -void SCACInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) +void SCACInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2288,7 +2288,7 @@ static int SCACTest01(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -2322,7 +2322,7 @@ static int SCACTest02(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); @@ -2355,7 +2355,7 @@ static int SCACTest03(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -2392,7 +2392,7 @@ static int SCACTest04(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); @@ -2426,7 +2426,7 @@ static int SCACTest05(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); @@ -2460,7 +2460,7 @@ static int SCACTest06(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 1); @@ -2492,7 +2492,7 @@ static int SCACTest07(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* should match 30 times */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); @@ -2537,7 +2537,7 @@ static int SCACTest08(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -2569,7 +2569,7 @@ static int SCACTest09(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); @@ -2601,7 +2601,7 @@ static int SCACTest10(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); @@ -2638,7 +2638,7 @@ static int SCACTest11(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) goto end; @@ -2685,7 +2685,7 @@ static int SCACTest12(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); @@ -2720,7 +2720,7 @@ static int SCACTest13(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; @@ -2754,7 +2754,7 @@ static int SCACTest14(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; @@ -2788,7 +2788,7 @@ static int SCACTest15(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; @@ -2822,7 +2822,7 @@ static int SCACTest16(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; @@ -2856,7 +2856,7 @@ static int SCACTest17(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; @@ -2890,7 +2890,7 @@ static int SCACTest18(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; @@ -2924,7 +2924,7 @@ static int SCACTest19(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; @@ -2958,7 +2958,7 @@ static int SCACTest20(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; @@ -2992,7 +2992,7 @@ static int SCACTest21(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); @@ -3024,7 +3024,7 @@ static int SCACTest22(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -3059,7 +3059,7 @@ static int SCACTest23(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); @@ -3091,7 +3091,7 @@ static int SCACTest24(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); @@ -3123,7 +3123,7 @@ static int SCACTest25(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); @@ -3157,7 +3157,7 @@ static int SCACTest26(void) memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); @@ -3190,7 +3190,7 @@ static int SCACTest27(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); @@ -3223,7 +3223,7 @@ static int SCACTest28(void) memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index c9c92db664b0..3ad639b92519 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -46,7 +46,7 @@ #include void SCHSInitCtx(MpmCtx *); -void SCHSInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); +void SCHSInitThreadCtx(MpmCtx *, MpmThreadCtx *); void SCHSDestroyCtx(MpmCtx *); void SCHSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCHSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, @@ -761,10 +761,8 @@ int SCHSPreparePatterns(MpmCtx *mpm_ctx) * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. - * \param matchsize We don't need this. */ -void SCHSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - uint32_t matchsize) +void SCHSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1124,7 +1122,7 @@ static int SCHSTest01(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; @@ -1158,7 +1156,7 @@ static int SCHSTest02(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1195,7 +1193,7 @@ static int SCHSTest03(void) PmqSetup(&pmq, 3); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1229,7 +1227,7 @@ static int SCHSTest04(void) PmqSetup(&pmq, 3); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1263,7 +1261,7 @@ static int SCHSTest05(void) PmqSetup(&pmq, 3); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1295,7 +1293,7 @@ static int SCHSTest06(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcd"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1339,7 +1337,7 @@ static int SCHSTest07(void) PmqSetup(&pmq, 6); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1372,7 +1370,7 @@ static int SCHSTest08(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); @@ -1404,7 +1402,7 @@ static int SCHSTest09(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); @@ -1436,7 +1434,7 @@ static int SCHSTest10(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" @@ -1481,7 +1479,7 @@ static int SCHSTest11(void) if (SCHSPreparePatterns(&mpm_ctx) == -1) goto end; - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); result = 1; @@ -1523,7 +1521,7 @@ static int SCHSTest12(void) PmqSetup(&pmq, 2); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghijklmnopqrstuvwxyz"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1557,7 +1555,7 @@ static int SCHSTest13(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1591,7 +1589,7 @@ static int SCHSTest14(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1625,7 +1623,7 @@ static int SCHSTest15(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1659,7 +1657,7 @@ static int SCHSTest16(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABC"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1693,7 +1691,7 @@ static int SCHSTest17(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzAB"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1732,7 +1730,7 @@ static int SCHSTest18(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcde" "fghij" @@ -1771,7 +1769,7 @@ static int SCHSTest19(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1811,7 +1809,7 @@ static int SCHSTest20(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "AAAAA" "AAAAA" @@ -1850,7 +1848,7 @@ static int SCHSTest21(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); @@ -1884,7 +1882,7 @@ static int SCHSTest22(void) PmqSetup(&pmq, 2); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "abcdefghijklmnopqrstuvwxyz"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -1917,7 +1915,7 @@ static int SCHSTest23(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); @@ -1949,7 +1947,7 @@ static int SCHSTest24(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); @@ -1982,7 +1980,7 @@ static int SCHSTest25(void) PmqSetup(&pmq, 3); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -2015,7 +2013,7 @@ static int SCHSTest26(void) PmqSetup(&pmq, 2); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "works"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -2048,7 +2046,7 @@ static int SCHSTest27(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "tone"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, @@ -2081,7 +2079,7 @@ static int SCHSTest28(void) PmqSetup(&pmq, 1); SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); char *buf = "tONE"; uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, diff --git a/src/util-mpm.c b/src/util-mpm.c index 8398ac7556d2..e3c5b12db6b6 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -612,9 +612,9 @@ void PmqFree(PatternMatcherQueue *pmq) PmqCleanup(pmq); } -void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher, uint32_t max_id) +void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher) { - mpm_table[matcher].InitThreadCtx(NULL, mpm_thread_ctx, max_id); + mpm_table[matcher].InitThreadCtx(NULL, mpm_thread_ctx); } void MpmInitCtx (MpmCtx *mpm_ctx, uint16_t matcher) diff --git a/src/util-mpm.h b/src/util-mpm.h index 72d56e611592..afb694123291 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -138,7 +138,7 @@ typedef struct MpmTableElmt_ { char *name; uint8_t max_pattern_length; void (*InitCtx)(struct MpmCtx_ *); - void (*InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *, uint32_t); + void (*InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *); void (*DestroyCtx)(struct MpmCtx_ *); void (*DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *); @@ -220,7 +220,7 @@ void MpmTableSetup(void); void MpmRegisterTests(void); void MpmInitCtx(MpmCtx *mpm_ctx, uint16_t matcher); -void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t, uint32_t); +void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t); int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, From b3dcdb10bedb8044ac8e1cad65498df9abcd422b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Oct 2015 12:40:57 +0200 Subject: [PATCH 1140/2553] detect mpm: remove dead code --- src/detect-engine-mpm.c | 108 ---------------------------------------- 1 file changed, 108 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 557e24f86cbb..61d6ef1e1341 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1065,114 +1065,6 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) return; } -/** \brief Hash for looking up contents that are most used, - * always used, etc. */ -typedef struct ContentHash_ { - DetectContentData *ptr; - uint32_t cnt; - int use; /* use no matter what */ -} ContentHash; - -typedef struct UricontentHash_ { - DetectContentData *ptr; - uint32_t cnt; - int use; /* use no matter what */ -} UricontentHash; - -uint32_t ContentHashFunc(HashTable *ht, void *data, uint16_t datalen) -{ - ContentHash *ch = (ContentHash *)data; - DetectContentData *co = ch->ptr; - uint32_t hash = 0; - int i; - for (i = 0; i < co->content_len; i++) { - hash += co->content[i]; - } - hash = hash % ht->array_size; - SCLogDebug("hash %" PRIu32 "", hash); - return hash; -} - -uint32_t UricontentHashFunc(HashTable *ht, void *data, uint16_t datalen) -{ - UricontentHash *ch = (UricontentHash *)data; - DetectContentData *ud = ch->ptr; - uint32_t hash = 0; - int i; - for (i = 0; i < ud->content_len; i++) { - hash += ud->content[i]; - } - hash = hash % ht->array_size; - SCLogDebug("hash %" PRIu32 "", hash); - return hash; -} - -char ContentHashCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) -{ - ContentHash *ch1 = (ContentHash *)data1; - ContentHash *ch2 = (ContentHash *)data2; - DetectContentData *co1 = ch1->ptr; - DetectContentData *co2 = ch2->ptr; - - if (co1->content_len == co2->content_len && - ((co1->flags & DETECT_CONTENT_NOCASE) == (co2->flags & DETECT_CONTENT_NOCASE)) && - SCMemcmp(co1->content, co2->content, co1->content_len) == 0) - return 1; - - return 0; -} - -char UricontentHashCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) -{ - UricontentHash *ch1 = (UricontentHash *)data1; - UricontentHash *ch2 = (UricontentHash *)data2; - DetectContentData *ud1 = ch1->ptr; - DetectContentData *ud2 = ch2->ptr; - - if (ud1->content_len == ud2->content_len && - ((ud1->flags & DETECT_CONTENT_NOCASE) == (ud2->flags & DETECT_CONTENT_NOCASE)) && - SCMemcmp(ud1->content, ud2->content, ud1->content_len) == 0) - return 1; - - return 0; -} - -ContentHash *ContentHashAlloc(DetectContentData *ptr) -{ - ContentHash *ch = SCMalloc(sizeof(ContentHash)); - if (unlikely(ch == NULL)) - return NULL; - - ch->ptr = ptr; - ch->cnt = 1; - ch->use = 0; - - return ch; -} - -UricontentHash *UricontentHashAlloc(DetectContentData *ptr) -{ - UricontentHash *ch = SCMalloc(sizeof(UricontentHash)); - if (unlikely(ch == NULL)) - return NULL; - - ch->ptr = ptr; - ch->cnt = 1; - ch->use = 0; - - return ch; -} - -void ContentHashFree(void *ch) -{ - SCFree(ch); -} - -void UricontentHashFree(void *ch) -{ - SCFree(ch); -} - /** \brief Predict a strength value for patterns * * Patterns with high character diversity score higher. From 66b3dba676c50bfdc9f83a5d4ae94e6c6dc907e9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Oct 2015 19:00:24 +0200 Subject: [PATCH 1141/2553] detect: remove dead code --- src/detect-engine-mpm.c | 118 +--------------------------------------- src/detect-engine-mpm.h | 1 - src/detect.c | 2 +- 3 files changed, 2 insertions(+), 119 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 61d6ef1e1341..e96788218f66 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1576,122 +1576,6 @@ static void PopulateMpmAddPatternToMpm(const DetectEngineCtx *de_ctx, } SigMatch *RetrieveFPForSig(Signature *s) -{ - SigMatch *mpm_sm = NULL, *sm = NULL; - uint8_t has_non_negated_non_stream_pattern = 0; - - if (s->mpm_sm != NULL) - return s->mpm_sm; - - int list_id; - for (list_id = 0 ; list_id < DETECT_SM_LIST_MAX; list_id++) { - /* we have no keywords that support fp in this Signature sm list */ - if (!FastPatternSupportEnabledForSigMatchList(list_id)) - continue; - - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { - /* this keyword isn't registered for fp support */ - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - if (cd->flags & DETECT_CONTENT_FAST_PATTERN) - return sm; - if (!(cd->flags & DETECT_CONTENT_NEGATED) && - (list_id != DETECT_SM_LIST_PMATCH) && - (list_id != DETECT_SM_LIST_HMDMATCH) && - (list_id != DETECT_SM_LIST_HSMDMATCH) && - (list_id != DETECT_SM_LIST_HSCDMATCH)) { - has_non_negated_non_stream_pattern = 1; - } - } - } - - int max_len = 0; - int max_len_negated = 0; - int max_len_non_negated = 0; - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { - if (!FastPatternSupportEnabledForSigMatchList(list_id)) - continue; - - if (has_non_negated_non_stream_pattern && - ((list_id == DETECT_SM_LIST_PMATCH) || - (list_id == DETECT_SM_LIST_HMDMATCH) || - (list_id == DETECT_SM_LIST_HSMDMATCH) || - (list_id == DETECT_SM_LIST_HSCDMATCH))) { - continue; - } - - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - if (cd->flags & DETECT_CONTENT_NEGATED) { - if (max_len_negated < cd->content_len) - max_len_negated = cd->content_len; - } else { - if (max_len_non_negated < cd->content_len) - max_len_non_negated = cd->content_len; - } - } - } - - int skip_negated_content = 0; - if (max_len_non_negated == 0) { - max_len = max_len_negated; - skip_negated_content = 0; - } else { - max_len = max_len_non_negated; - skip_negated_content = 1; - } - - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { - if (!FastPatternSupportEnabledForSigMatchList(list_id)) - continue; - - if (has_non_negated_non_stream_pattern && - ((list_id == DETECT_SM_LIST_PMATCH) || - (list_id == DETECT_SM_LIST_HMDMATCH) || - (list_id == DETECT_SM_LIST_HSMDMATCH) || - (list_id == DETECT_SM_LIST_HSCDMATCH))) { - continue; - } - - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content) - continue; - if (cd->content_len < max_len) - continue; - - if (mpm_sm == NULL) { - mpm_sm = sm; - } else { - DetectContentData *data1 = (DetectContentData *)sm->ctx; - DetectContentData *data2 = (DetectContentData *)mpm_sm->ctx; - uint32_t ls = PatternStrength(data1->content, data1->content_len); - uint32_t ss = PatternStrength(data2->content, data2->content_len); - if (ls > ss) { - mpm_sm = sm; - } else if (ls == ss) { - /* if 2 patterns are of equal strength, we pick the longest */ - if (data1->content_len > data2->content_len) - mpm_sm = sm; - } else { - SCLogDebug("sticking with mpm_sm"); - } - } /* else - if (mpm == NULL) */ - } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */ - } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */ - - return mpm_sm; -} - -SigMatch *RetrieveFPForSigV2(Signature *s) { if (s->mpm_sm != NULL) return s->mpm_sm; @@ -2802,7 +2686,7 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) * true size, since duplicates are removed below, but counted here. */ for (s = de_ctx->sig_list; s != NULL; s = s->next) { - s->mpm_sm = RetrieveFPForSigV2(s); + s->mpm_sm = RetrieveFPForSig(s); if (s->mpm_sm != NULL) { DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; struct_total_size += sizeof(DetectFPAndItsId); diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 44f9f1ad86db..b0d9f12fca61 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -82,7 +82,6 @@ int SignatureHasPacketContent(const Signature *); int SignatureHasStreamContent(const Signature *); SigMatch *RetrieveFPForSig(Signature *s); -SigMatch *RetrieveFPForSigV2(Signature *s); /** * \brief Figured out the FP and their respective content ids for all the diff --git a/src/detect.c b/src/detect.c index d39ce0b5e531..2c44c8fd56c1 100644 --- a/src/detect.c +++ b/src/detect.c @@ -357,7 +357,7 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, sig = DetectEngineAppendSig(de_ctx, line); if (sig != NULL) { if (rule_engine_analysis_set || fp_engine_analysis_set) { - sig->mpm_sm = RetrieveFPForSigV2(sig); + sig->mpm_sm = RetrieveFPForSig(sig); if (fp_engine_analysis_set) { EngineAnalysisFP(sig, line); } From f720dfd21e72596e0dde9ad6dbe575e4949ad66d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 9 Oct 2015 11:18:36 +0200 Subject: [PATCH 1142/2553] detect: validate http_method pattern Leading and trailing spaces and tabs are invalid as these are not part of the buffer as returned by libhtp. --- src/detect-http-method.c | 37 ++++++++++++++++++++++++++++++++++++- src/detect-http-method.h | 1 + src/detect-parse.c | 4 ++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 4cc8a7873f7f..6807648c6e78 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -118,6 +118,41 @@ void DetectHttpMethodFree(void *ptr) SCFree(data); } +/** + * \retval 1 valid + * \retval 0 invalid + */ +int DetectHttpMethodValidateRule(const Signature *s) +{ + if (s->alproto != ALPROTO_HTTP) + return 1; + + if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { + const SigMatch *sm = s->sm_lists[DETECT_SM_LIST_HMDMATCH]; + for ( ; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + const DetectContentData *cd = (const DetectContentData *)sm->ctx; + if (cd->content && cd->content_len) { + if (cd->content[cd->content_len-1] == 0x20) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with trailing space"); + return 0; + } else if (cd->content[0] == 0x20) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with leading space"); + return 0; + } else if (cd->content[cd->content_len-1] == 0x09) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with trailing tab"); + return 0; + } else if (cd->content[0] == 0x09) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with leading tab"); + return 0; + } + } + } + } + return 1; +} + #ifdef UNITTESTS /* UNITTESTS */ #include "stream-tcp-reassemble.h" @@ -649,7 +684,7 @@ static int DetectHttpMethodSigTest03(void) s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " - "content:\" \"; " + "content:\"GET\"; " "http_method; sid:1;)"); if (s == NULL) { SCLogDebug("Bad signature"); diff --git a/src/detect-http-method.h b/src/detect-http-method.h index 9e6dc4dd95ef..d1593aed7603 100644 --- a/src/detect-http-method.h +++ b/src/detect-http-method.h @@ -28,6 +28,7 @@ void DetectHttpMethodRegister(void); int DetectHttpMethodDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Flow *, uint8_t, void *); +int DetectHttpMethodValidateRule(const Signature *s); #endif /* __DETECT_HTTP_METHOD_H__ */ diff --git a/src/detect-parse.c b/src/detect-parse.c index 4139b9b102fc..c392ba3fd1b0 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -43,6 +43,7 @@ #include "detect-engine-apt-event.h" #include "detect-lua.h" #include "detect-app-layer-event.h" +#include "detect-http-method.h" #include "pkt-var.h" #include "host.h" @@ -1206,6 +1207,9 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } + if (!DetectHttpMethodValidateRule(s)) + SCReturnInt(0); + //if (s->alproto != ALPROTO_UNKNOWN) { // if (s->flags & SIG_FLAG_STATE_MATCH) { // if (s->alproto == ALPROTO_DNS) { From b7d81fc3b024412ba0975e9bb691ea6f74924319 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 7 Oct 2015 15:38:58 +0200 Subject: [PATCH 1143/2553] detect: SYN flags Add funcs to see if a rule needs a SYN flag in the packet. --- src/detect-flags.c | 38 ++++++++++++++++++++++++++++++++++++++ src/detect-flags.h | 3 +++ 2 files changed, 41 insertions(+) diff --git a/src/detect-flags.c b/src/detect-flags.c index b5b1840a82b9..51768f1797cc 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -522,6 +522,44 @@ static void DetectFlagsFree(void *de_ptr) if(de) SCFree(de); } +int DetectFlagsSignatureNeedsSynPackets(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FLAGS: + { + const DetectFlagsData *fl = (const DetectFlagsData *)sm->ctx; + + if (!(fl->modifier == MODIFIER_NOT) && (fl->flags & TH_SYN)) { + return 1; + } + break; + } + } + } + return 0; +} + +int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FLAGS: + { + const DetectFlagsData *fl = (const DetectFlagsData *)sm->ctx; + + if (!(fl->modifier == MODIFIER_NOT) && (fl->flags == TH_SYN)) { + return 1; + } + break; + } + } + } + return 0; +} + /* * ONLY TESTS BELOW THIS COMMENT */ diff --git a/src/detect-flags.h b/src/detect-flags.h index 0eaaa28214c6..333ed910215c 100644 --- a/src/detect-flags.h +++ b/src/detect-flags.h @@ -56,4 +56,7 @@ void DetectFlagsRegister (void); void FlagsRegisterTests(void); +int DetectFlagsSignatureNeedsSynPackets(const Signature *s); +int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s); + #endif /*__DETECT_FLAGS_H__ */ From bfe49b60f7a0fdad8ded686b0291d04fde997d8a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 27 Sep 2015 10:33:48 +0200 Subject: [PATCH 1144/2553] rule analyzer: add no/both direction warning --- src/detect-engine-analyzer.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index cf9c2cf4fa60..80d76e607cc6 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -556,6 +556,8 @@ void EngineAnalysisRules(const Signature *s, const char *line) uint32_t warn_offset_depth_pkt_stream = 0; uint32_t warn_offset_depth_alproto = 0; uint32_t warn_non_alproto_fp_for_alproto_sig = 0; + uint32_t warn_no_direction = 0; + uint32_t warn_both_direction = 0; if (s->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; @@ -811,6 +813,15 @@ void EngineAnalysisRules(const Signature *s, const char *line) warn_non_alproto_fp_for_alproto_sig = 1; } + if ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) { + warn_no_direction += 1; + rule_warning += 1; + } + if ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) { + warn_both_direction += 1; + rule_warning += 1; + } + if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) { fprintf(rule_engine_analysis_FD, "== Sid: %u ==\n", s->id); fprintf(rule_engine_analysis_FD, "%s\n", line); @@ -917,6 +928,12 @@ void EngineAnalysisRules(const Signature *s, const char *line) "stream. Consider adding fast_pattern over a http " "buffer for increased performance."); } + if (warn_no_direction) { + fprintf(rule_engine_analysis_FD, " Warning: Rule has no direction indicator.\n"); + } + if (warn_both_direction) { + fprintf(rule_engine_analysis_FD, " Warning: Rule is inspecting both directions.\n"); + } if (rule_warning == 0) { fprintf(rule_engine_analysis_FD, " No warnings for this rule.\n"); } From 18dd54dfa77eddecc8a94da0a1e30041abfccddf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Nov 2014 23:43:45 +0100 Subject: [PATCH 1145/2553] Start rule inspect with mask check --- src/detect.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detect.c b/src/detect.c index 2c44c8fd56c1..34ae91b49f36 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1514,6 +1514,9 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SCLogDebug("inspecting signature id %"PRIu32"", s->id); + if ((s->mask & mask) != s->mask) + goto next; + /* if the sig has alproto and the session as well they should match */ if (likely(sflags & SIG_FLAG_APPLAYER)) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { From bb662a65f8630723cd4fef361b7d7313fed74e77 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Sep 2015 10:17:34 +0200 Subject: [PATCH 1146/2553] detect: delay sgh mpm setup --- src/detect.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/detect.c b/src/detect.c index 34ae91b49f36..22a6cf870c4f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3725,13 +3725,6 @@ int BuildDestinationAddressHeads(DetectEngineCtx *de_ctx, DetectAddressHead *hea /* put the contents in our sig group head */ SigGroupHeadSetSigCnt(sgr->sh, max_idx); SigGroupHeadBuildMatchArray(de_ctx, sgr->sh, max_idx); - - /* init the pattern matcher, this will respect the copy - * setting */ - if (PatternMatchPrepareGroup(de_ctx, sgr->sh) < 0) { - printf("PatternMatchPrepareGroup failed\n"); - goto error; - } SigGroupHeadHashAdd(de_ctx, sgr->sh); SigGroupHeadStore(de_ctx, sgr->sh); de_ctx->gh_unique++; @@ -3959,13 +3952,6 @@ int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, DetectAdd SigGroupHeadSetSigCnt(dp->sh, max_idx); SigGroupHeadBuildMatchArray(de_ctx,dp->sh, max_idx); - - /* init the pattern matcher, this will respect the copy - * setting */ - if (PatternMatchPrepareGroup(de_ctx, dp->sh) < 0) { - printf("PatternMatchPrepareGroup failed\n"); - goto error; - } SigGroupHeadDPortHashAdd(de_ctx, dp->sh); SigGroupHeadStore(de_ctx, dp->sh); de_ctx->gh_unique++; @@ -4263,6 +4249,7 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SigGroupHeadSetFilestoreCount(de_ctx, sgh); SCLogDebug("filestore count %u", sgh->filestore_cnt); + BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); SigGroupHeadBuildNonMpmArray(de_ctx, sgh); sgh->mpm_uricontent_minlen = SigGroupHeadGetMinMpmSize(de_ctx, sgh, DETECT_SM_LIST_UMATCH); From c71c991669d52c28bd2619489d39462206980559 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Sep 2015 16:02:15 +0200 Subject: [PATCH 1147/2553] detect: delay sgh cleanup --- src/detect.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/detect.c b/src/detect.c index 22a6cf870c4f..db6c80de8714 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4120,21 +4120,6 @@ int SigAddressPrepareStage3(DetectEngineCtx *de_ctx) /* prepare the decoder event sgh */ DetectEngineBuildDecoderEventSgh(de_ctx); - /* cleanup group head (uri)content_array's */ - SigGroupHeadFreeMpmArrays(de_ctx); - /* cleanup group head sig arrays */ - SigGroupHeadFreeSigArrays(de_ctx); - - /* cleanup the hashes now since we won't need them - * after the initialization phase. */ - SigGroupHeadHashFree(de_ctx); - SigGroupHeadDPortHashFree(de_ctx); - SigGroupHeadSPortHashFree(de_ctx); - SigGroupHeadMpmHashFree(de_ctx); - SigGroupHeadMpmUriHashFree(de_ctx); - DetectPortDpHashFree(de_ctx); - DetectPortSpHashFree(de_ctx); - if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("max sig id %" PRIu32 ", array size %" PRIu32 "", DetectEngineGetMaxSigId(de_ctx), DetectEngineGetMaxSigId(de_ctx) / 8 + 1); SCLogDebug("signature group heads: unique %" PRIu32 ", copies %" PRIu32 ".", de_ctx->gh_unique, de_ctx->gh_reuse); @@ -4261,6 +4246,21 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) * signature not decode event only. */ } + /* cleanup group head (uri)content_array's */ + SigGroupHeadFreeMpmArrays(de_ctx); + /* cleanup group head sig arrays */ + SigGroupHeadFreeSigArrays(de_ctx); + + /* cleanup the hashes now since we won't need them + * after the initialization phase. */ + SigGroupHeadHashFree(de_ctx); + SigGroupHeadDPortHashFree(de_ctx); + SigGroupHeadSPortHashFree(de_ctx); + SigGroupHeadMpmHashFree(de_ctx); + SigGroupHeadMpmUriHashFree(de_ctx); + DetectPortDpHashFree(de_ctx); + DetectPortSpHashFree(de_ctx); + SCFree(de_ctx->sgh_array); de_ctx->sgh_array_cnt = 0; de_ctx->sgh_array_size = 0; From e75a93b1256e604d2528baff76b9c236057dba64 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Sep 2015 10:00:36 +0200 Subject: [PATCH 1148/2553] detect: pass ipproto to rule grouping funcs --- src/detect.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/detect.c b/src/detect.c index db6c80de8714..0fb95edc733c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3004,7 +3004,9 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) return -1; } -static int DetectEngineLookupBuildSourceAddressList(DetectEngineCtx *de_ctx, DetectEngineLookupFlow *flow_gh, Signature *s, int family) +static int DetectEngineLookupBuildSourceAddressList(DetectEngineCtx *de_ctx, + DetectEngineLookupFlow *flow_gh, + Signature *s, int family) { DetectAddress *gr = NULL, *lookup_gr = NULL, *head = NULL; int proto; @@ -3641,7 +3643,9 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) /** * \brief Build the destination address portion of the match tree */ -int BuildDestinationAddressHeads(DetectEngineCtx *de_ctx, DetectAddressHead *head, int family, int flow) +int BuildDestinationAddressHeads(DetectEngineCtx *de_ctx, + DetectAddressHead *head, + int family, int flow, int ipproto) { Signature *tmp_s = NULL; DetectAddress *gr = NULL, *sgr = NULL, *lookup_gr = NULL; @@ -3753,7 +3757,9 @@ int BuildDestinationAddressHeads(DetectEngineCtx *de_ctx, DetectAddressHead *hea } //static -int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, DetectAddressHead *head, int family, int flow) +int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, + DetectAddressHead *head, + int family, int flow, int ipproto) { Signature *tmp_s = NULL; DetectAddress *src_gr = NULL, *dst_gr = NULL, *sig_gr = NULL, *lookup_gr = NULL; @@ -4050,47 +4056,47 @@ int SigAddressPrepareStage3(DetectEngineCtx *de_ctx) int f = 0; int proto; for (f = 0; f < FLOW_STATES; f++) { - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_INET,f); + r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_INET,f,IPPROTO_TCP); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); goto error; } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_INET,f); + r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_INET,f,IPPROTO_UDP); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); goto error; } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_INET,f); + r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_INET,f,IPPROTO_SCTP); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); goto error; } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_INET6,f); + r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_INET6,f,IPPROTO_TCP); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); goto error; } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_INET6,f); + r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_INET6,f,IPPROTO_UDP); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); goto error; } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_INET6,f); + r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_INET6,f,IPPROTO_SCTP); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); goto error; } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_UNSPEC,f); + r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_UNSPEC,f,IPPROTO_TCP); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); goto error; } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_UNSPEC,f); + r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_UNSPEC,f,IPPROTO_UDP); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); goto error; } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_UNSPEC,f); + r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_UNSPEC,f,IPPROTO_SCTP); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); goto error; @@ -4099,17 +4105,17 @@ int SigAddressPrepareStage3(DetectEngineCtx *de_ctx) if (proto == IPPROTO_TCP || proto == IPPROTO_UDP || proto == IPPROTO_SCTP) continue; - r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_INET,f); + r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_INET,f,proto); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_INET) failed\n", proto); goto error; } - r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_INET6,f); + r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_INET6,f,proto); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_INET6) failed\n", proto); goto error; } - r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_UNSPEC,f); /* for any */ + r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_UNSPEC,f,proto); /* for any */ if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_UNSPEC) failed\n", proto); goto error; From 27e63a1e1134812b414e189caa90e53d8266ed86 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Sep 2015 10:10:58 +0200 Subject: [PATCH 1149/2553] detect: track direction and ipproto of sgh Each SGH has a unique ipproto and direction. --- src/detect-engine-siggroup.c | 9 +++++++++ src/detect-engine-siggroup.h | 2 ++ src/detect.c | 2 ++ src/detect.h | 3 +++ 4 files changed, 16 insertions(+) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index d25e8d257d54..42f12f0cedca 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -1142,6 +1142,15 @@ void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx) return; } +void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, + uint8_t ipproto, uint8_t dir) +{ + if (sgh && sgh->init) { + sgh->init->protos[ipproto] = 1; + sgh->init->direction = dir; + } +} + /** * \brief Prints the memory statistics for the detect-engine-siggroup.[ch] module. */ diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index 69b24fd47335..c4470c09ffe3 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -73,6 +73,8 @@ int SigGroupHeadSPortHashRemove(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid); void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx); +void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, + uint8_t ipproto, uint8_t dir); int SigGroupHeadBuildMatchArray (DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t max_idx); void SigGroupHeadFreeSigArrays(DetectEngineCtx *de_ctx); diff --git a/src/detect.c b/src/detect.c index 0fb95edc733c..4a12286611df 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3728,6 +3728,7 @@ int BuildDestinationAddressHeads(DetectEngineCtx *de_ctx, if (sgh == NULL) { /* put the contents in our sig group head */ SigGroupHeadSetSigCnt(sgr->sh, max_idx); + SigGroupHeadSetProtoAndDirection(sgr->sh, ipproto, flow); SigGroupHeadBuildMatchArray(de_ctx, sgr->sh, max_idx); SigGroupHeadHashAdd(de_ctx, sgr->sh); SigGroupHeadStore(de_ctx, sgr->sh); @@ -3957,6 +3958,7 @@ int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, SCLogDebug("dp %p dp->sh %p is the original (sp %p, dst_gr %p, src_gr %p)", dp, dp->sh, sp, dst_gr, src_gr); SigGroupHeadSetSigCnt(dp->sh, max_idx); + SigGroupHeadSetProtoAndDirection(dp->sh, ipproto, flow); SigGroupHeadBuildMatchArray(de_ctx,dp->sh, max_idx); SigGroupHeadDPortHashAdd(de_ctx, dp->sh); SigGroupHeadStore(de_ctx, dp->sh); diff --git a/src/detect.h b/src/detect.h index 3ca3108fd296..3afd5b313217 100644 --- a/src/detect.h +++ b/src/detect.h @@ -983,6 +983,9 @@ typedef struct SigGroupHeadInitData_ { uint8_t *sig_array; /**< bit array of sig nums (internal id's) */ uint32_t sig_size; /**< size in bytes */ + uint8_t protos[256]; + uint8_t direction; + /* port ptr */ struct DetectPort_ *port; } SigGroupHeadInitData; From fd5a06017d84dfe8d8042cd6e19bd315a959cb7c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Nov 2014 23:14:26 +0100 Subject: [PATCH 1150/2553] detect: per port and proto rule grouping Replace tree based approach for rule grouping with a per port (tcp/udp) and per protocol approach. Grouping now looks like: +----+ |icmp+---> +----+ |gre +---> +----+ |esp +---> +----+ other|... | +----->-----+ | |N +---> | +----+ | | tcp +----+ +----+ +----->+ 80 +-->+ 139+--> | +----+ +----+ | | udp +----+ +----+ +---+----->+ 53 +-->+ 135+--> | +----+ +----+ |toserver +---> |toclient | +---> So the first 'split' in the rules is the direction: toserver or toclient. Rules that don't have a direction, are in both branches. Then the split is between tcp/udp and the other protocols. For tcp and udp port lists are used. For the other protocols, grouping is simply per protocol. The ports used are the destination ports for toserver sigs and source ports for toclient sigs. --- src/detect.c | 1728 +++++++------------------------------------------- src/detect.h | 5 +- 2 files changed, 237 insertions(+), 1496 deletions(-) diff --git a/src/detect.c b/src/detect.c index 4a12286611df..5b543ed936bb 100644 --- a/src/detect.c +++ b/src/detect.c @@ -615,38 +615,21 @@ SigGroupHead *SigMatchSignaturesGetSgh(DetectEngineCtx *de_ctx, DetectEngineThre else f = 1; - SCLogDebug("f %d", f); - SCLogDebug("IP_GET_IPPROTO(p) %u", IP_GET_IPPROTO(p)); - - /* find the right mpm instance */ - DetectAddress *ag = DetectAddressLookupInHead(de_ctx->flow_gh[f].src_gh[IP_GET_IPPROTO(p)], &p->src); - if (ag != NULL) { - /* source group found, lets try a dst group */ - ag = DetectAddressLookupInHead(ag->dst_gh, &p->dst); - if (ag != NULL) { - if (ag->port == NULL) { - SCLogDebug("we don't have ports"); - sgh = ag->sh; - } else { - SCLogDebug("we have ports"); - - DetectPort *sport = DetectPortLookupGroup(ag->port,p->sp); - if (sport != NULL) { - DetectPort *dport = DetectPortLookupGroup(sport->dst_ph,p->dp); - if (dport != NULL) { - sgh = dport->sh; - } else { - SCLogDebug("no dst port group found for the packet with dp %"PRIu16"", p->dp); - } - } else { - SCLogDebug("no src port group found for the packet with sp %"PRIu16"", p->sp); - } - } - } else { - SCLogDebug("no dst address group found for the packet"); - } + int proto = IP_GET_IPPROTO(p); + if (proto == IPPROTO_TCP) { + DetectPort *list = de_ctx->flow_gh[f].tcp; + uint16_t port = f ? p->dp : p->sp; + DetectPort *sghport = DetectPortLookupGroup(list, port); + if (sghport != NULL) + sgh = sghport->sh; + } else if (proto == IPPROTO_UDP) { + DetectPort *list = de_ctx->flow_gh[f].udp; + uint16_t port = f ? p->dp : p->sp; + DetectPort *sghport = DetectPortLookupGroup(list, port); + if (sghport != NULL) + sgh = sghport->sh; } else { - SCLogDebug("no src address group found for the packet"); + sgh = de_ctx->flow_gh[f].sgh[proto]; } SCReturnPtr(sgh, "SigGroupHead"); @@ -2878,6 +2861,93 @@ static void SigParseApplyDsizeToContent(Signature *s) } } +static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint32_t direction) { + /* step 1: create a list of 'DetectPort' objects based on all the + * rules. Each object will have a SGH with the sigs added + * that belong to the SGH. */ + + uint32_t max_idx = 0; + const Signature *s = de_ctx->sig_list; + DetectPort *list = NULL; + while (s) { + /* IP Only rules are handled separately */ + if (s->flags & SIG_FLAG_IPONLY) + goto next; + if (!(s->proto.proto[ipproto / 8] & (1<<(ipproto % 8)) || (s->proto.flags & DETECT_PROTO_ANY))) + goto next; + if (!(s->flags & direction)) + goto next; + + DetectPort *p = NULL; + if (direction == SIG_FLAG_TOSERVER) + p = s->dp; + else if (direction == SIG_FLAG_TOCLIENT) + p = s->sp; + else + BUG_ON(1); + + while (p) { + DetectPort *tmp = DetectPortCopySingle(de_ctx, p); + BUG_ON(tmp == NULL); + SigGroupHeadAppendSig(de_ctx, &tmp->sh, s); + + int r = DetectPortInsert(de_ctx, &list , tmp); + BUG_ON(r == -1); + + p = p->next; + } + max_idx = s->num; + next: + s = s->next; + } + + /* step 2: deduplicate the SGH's */ + SigGroupHeadHashFree(de_ctx); + SigGroupHeadHashInit(de_ctx); + + uint32_t cnt = 0; + uint32_t own = 0; + uint32_t ref = 0; + DetectPort *iter; + for (iter = list ; iter != NULL; iter = iter->next) { + BUG_ON (iter->sh == NULL); + cnt++; + + SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, iter->sh); + if (lookup_sgh == NULL) { + SCLogDebug("port group %p sgh %p is the original", iter, iter->sh); + + SigGroupHeadSetSigCnt(iter->sh, max_idx); + SigGroupHeadBuildMatchArray(de_ctx, iter->sh, max_idx); + + /* init the pattern matcher, this will respect the copy + * setting */ + BUG_ON(PatternMatchPrepareGroup(de_ctx, iter->sh) != 0); + SigGroupHeadHashAdd(de_ctx, iter->sh); + SigGroupHeadStore(de_ctx, iter->sh); + de_ctx->gh_unique++; + own++; + } else { + SCLogDebug("port group %p sgh %p is a copy", iter, iter->sh); + + SigGroupHeadFree(iter->sh); + iter->sh = lookup_sgh; + iter->flags |= PORT_SIGGROUPHEAD_COPY; + iter->sh->flags |= SIG_GROUP_HEAD_REFERENCED; + + de_ctx->gh_reuse++; + ref++; + } + } +#if 0 + for (iter = list ; iter != NULL; iter = iter->next) { + SCLogInfo("PORT %u-%u %p (sgh=%s)", iter->port, iter->port2, iter->sh, iter->flags & PORT_SIGGROUPHEAD_COPY ? "ref" : "own"); + } +#endif + SCLogInfo("%u port groups, %u unique SGH's, %u copies", cnt, own, ref); + return list; +} + /** * \brief Preprocess signature, classify ip-only, etc, build sig array * @@ -3004,83 +3074,36 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) return -1; } -static int DetectEngineLookupBuildSourceAddressList(DetectEngineCtx *de_ctx, - DetectEngineLookupFlow *flow_gh, - Signature *s, int family) -{ - DetectAddress *gr = NULL, *lookup_gr = NULL, *head = NULL; - int proto; - - if (family == AF_INET) { - head = s->src.ipv4_head; - } else if (family == AF_INET6) { - head = s->src.ipv6_head; - } else { - head = s->src.any_head; - } - - /* for each source address group in the signature... */ - for (gr = head; gr != NULL; gr = gr->next) { - BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); - - /* ...and each protocol the signature matches on... */ - for (proto = 0; proto < 256; proto++) { - if ((s->proto.proto[(proto/8)] & (1<<(proto%8))) || (s->proto.flags & DETECT_PROTO_ANY)) { - /* ...see if the group is in the tmp list, and if not add it. */ - if (family == AF_INET) { - lookup_gr = DetectAddressLookupInList(flow_gh->tmp_gh[proto]->ipv4_head,gr); - } else if (family == AF_INET6) { - lookup_gr = DetectAddressLookupInList(flow_gh->tmp_gh[proto]->ipv6_head,gr); - } else { - lookup_gr = DetectAddressLookupInList(flow_gh->tmp_gh[proto]->any_head,gr); - } - - if (lookup_gr == NULL) { - DetectAddress *grtmp = DetectAddressCopy(gr); - if (grtmp == NULL) { - goto error; - } - SigGroupHeadAppendSig(de_ctx, &grtmp->sh, s); - - /* add to the lookup list */ - if (family == AF_INET) { - DetectAddressAdd(&flow_gh->tmp_gh[proto]->ipv4_head, grtmp); - } else if (family == AF_INET6) { - DetectAddressAdd(&flow_gh->tmp_gh[proto]->ipv6_head, grtmp); - } else { - DetectAddressAdd(&flow_gh->tmp_gh[proto]->any_head, grtmp); - } - } else { - /* our group will only have one sig, this one. So add that. */ - SigGroupHeadAppendSig(de_ctx, &lookup_gr->sh, s); - lookup_gr->cnt++; - } - } - } - } - - return 0; -error: - return -1; -} - /** * \brief add signature to the right flow group(s) */ -static int DetectEngineLookupFlowAddSig(DetectEngineCtx *de_ctx, Signature *s, int family) +static int DetectEngineLookupFlowAddSig(DetectEngineCtx *de_ctx, Signature *s) { SCLogDebug("s->id %u", s->id); - if (s->flags & SIG_FLAG_TOCLIENT) { - SCLogDebug("s->id %u (toclient)", s->id); - DetectEngineLookupBuildSourceAddressList(de_ctx, - &de_ctx->flow_gh[0], s, family); + uint32_t cnt_ts = 0; + uint32_t cnt_tc = 0; + + int p; + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + continue; + + if (s->proto.proto[p / 8] & (1<<(p % 8)) || (s->proto.flags & DETECT_PROTO_ANY)) { + if (s->flags & SIG_FLAG_TOCLIENT) { + SigGroupHeadAppendSig(de_ctx, &de_ctx->flow_gh[0].sgh[p], s); + cnt_tc++; + } + if (s->flags & SIG_FLAG_TOSERVER) { + SigGroupHeadAppendSig(de_ctx, &de_ctx->flow_gh[1].sgh[p], s); + cnt_ts++; + } + } } - if (s->flags & SIG_FLAG_TOSERVER) { - SCLogDebug("s->id %u (toserver)", s->id); - DetectEngineLookupBuildSourceAddressList(de_ctx, - &de_ctx->flow_gh[1], s, family); + /* see which rules use many protos. > 2 as alert icmp actually is also icmpv6. */ + if (cnt_ts > 2 || cnt_tc > 2) { + SCLogDebug("Rule %u added to multiple proto groups (%u ts/%u tc)", s->id, cnt_ts, cnt_tc); } return 0; @@ -3476,19 +3499,10 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) IPOnlyInit(de_ctx, &de_ctx->io_ctx); - int f, proto; - for (f = 0; f < FLOW_STATES; f++) { - for (proto = 0; proto < 256; proto++) { - de_ctx->flow_gh[f].src_gh[proto] = DetectAddressHeadInit(); - if (de_ctx->flow_gh[f].src_gh[proto] == NULL) { - goto error; - } - de_ctx->flow_gh[f].tmp_gh[proto] = DetectAddressHeadInit(); - if (de_ctx->flow_gh[f].tmp_gh[proto] == NULL) { - goto error; - } - } - } + de_ctx->flow_gh[1].tcp = RulesGroupByPorts(de_ctx, IPPROTO_TCP, SIG_FLAG_TOSERVER); + de_ctx->flow_gh[0].tcp = RulesGroupByPorts(de_ctx, IPPROTO_TCP, SIG_FLAG_TOCLIENT); + de_ctx->flow_gh[1].udp = RulesGroupByPorts(de_ctx, IPPROTO_UDP, SIG_FLAG_TOSERVER); + de_ctx->flow_gh[0].udp = RulesGroupByPorts(de_ctx, IPPROTO_UDP, SIG_FLAG_TOCLIENT); /* now for every rule add the source group to our temp lists */ for (tmp_s = de_ctx->sig_list; tmp_s != NULL; tmp_s = tmp_s->next) { @@ -3496,9 +3510,8 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) if (tmp_s->flags & SIG_FLAG_IPONLY) { IPOnlyAddSignature(de_ctx, &de_ctx->io_ctx, tmp_s); } else { - DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_INET); - DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_INET6); - DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_UNSPEC); + /* handle non-tcp/non-udp rules */ + DetectEngineLookupFlowAddSig(de_ctx, tmp_s); } if (tmp_s->init_flags & SIG_FLAG_INIT_DEONLY) { @@ -3508,136 +3521,10 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) sigs++; } - /* create the final src addr list based on the tmplist. */ - for (f = 0; f < FLOW_STATES; f++) { - for (proto = 0; proto < 256; proto++) { - int groups = (f ? de_ctx->max_uniq_toserver_src_groups : de_ctx->max_uniq_toclient_src_groups); - - CreateGroupedAddrList(de_ctx, - de_ctx->flow_gh[f].tmp_gh[proto]->ipv4_head, AF_INET, - de_ctx->flow_gh[f].src_gh[proto], groups, - CreateGroupedAddrListCmpMpmMinlen, DetectEngineGetMaxSigId(de_ctx)); - - CreateGroupedAddrList(de_ctx, - de_ctx->flow_gh[f].tmp_gh[proto]->ipv6_head, AF_INET6, - de_ctx->flow_gh[f].src_gh[proto], groups, - CreateGroupedAddrListCmpMpmMinlen, DetectEngineGetMaxSigId(de_ctx)); - CreateGroupedAddrList(de_ctx, - de_ctx->flow_gh[f].tmp_gh[proto]->any_head, AF_UNSPEC, - de_ctx->flow_gh[f].src_gh[proto], groups, - CreateGroupedAddrListCmpMpmMinlen, DetectEngineGetMaxSigId(de_ctx)); - - DetectAddressHeadFree(de_ctx->flow_gh[f].tmp_gh[proto]); - de_ctx->flow_gh[f].tmp_gh[proto] = NULL; - } - } - //DetectAddressPrintMemory(); - //DetectSigGroupPrintMemory(); - - //printf("g_src_gh strt\n"); - //DetectAddressPrintList(g_src_gh->ipv4_head); - //printf("g_src_gh end\n"); - IPOnlyPrepare(de_ctx); IPOnlyPrint(de_ctx, &de_ctx->io_ctx); -#ifdef DEBUG - DetectAddress *gr = NULL; - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("%" PRIu32 " total signatures:", sigs); - } - - /* TCP */ - uint32_t cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_TCP]->any_head; gr != NULL; gr = gr->next) { - cnt_any++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_TCP]->ipv4_head; gr != NULL; gr = gr->next) { - cnt_ipv4++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_TCP]->ipv6_head; gr != NULL; gr = gr->next) { - cnt_ipv6++; - } - } - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("TCP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); - } - - cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; - /* UDP */ - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_UDP]->any_head; gr != NULL; gr = gr->next) { - cnt_any++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_UDP]->ipv4_head; gr != NULL; gr = gr->next) { - cnt_ipv4++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_UDP]->ipv6_head; gr != NULL; gr = gr->next) { - cnt_ipv6++; - } - } - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("UDP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); - } - - cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; - /* SCTP */ - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP]->any_head; gr != NULL; gr = gr->next) { - cnt_any++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP]->ipv4_head; gr != NULL; gr = gr->next) { - cnt_ipv4++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP]->ipv6_head; gr != NULL; gr = gr->next) { - cnt_ipv6++; - } - } - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("SCTP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); - } - - /* ICMP */ - cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[1]->any_head; gr != NULL; gr = gr->next) { - cnt_any++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[1]->ipv4_head; gr != NULL; gr = gr->next) { - cnt_ipv4++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[1]->ipv6_head; gr != NULL; gr = gr->next) { - cnt_ipv6++; - } - } - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("ICMP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); - } -#endif /* DEBUG */ - if (!(de_ctx->flags & DE_QUIET)) { - SCLogInfo("building signature grouping structure, stage 2: building source address list... complete"); - } return 0; -error: - printf("SigAddressPrepareStage2 error\n"); - return -1; } /** @@ -4045,100 +3932,9 @@ static void DetectEngineBuildDecoderEventSgh(DetectEngineCtx *de_ctx) int SigAddressPrepareStage3(DetectEngineCtx *de_ctx) { - int r; - - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("building signature grouping structure, stage 3: " - "building destination address lists..."); - } - //DetectAddressPrintMemory(); - //DetectSigGroupPrintMemory(); - //DetectPortPrintMemory(); - - int f = 0; - int proto; - for (f = 0; f < FLOW_STATES; f++) { - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_INET,f,IPPROTO_TCP); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_INET,f,IPPROTO_UDP); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_INET,f,IPPROTO_SCTP); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_INET6,f,IPPROTO_TCP); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_INET6,f,IPPROTO_UDP); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_INET6,f,IPPROTO_SCTP); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_UNSPEC,f,IPPROTO_TCP); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_UNSPEC,f,IPPROTO_UDP); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_UNSPEC,f,IPPROTO_SCTP); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); - goto error; - } - for (proto = 0; proto < 256; proto++) { - if (proto == IPPROTO_TCP || proto == IPPROTO_UDP || proto == IPPROTO_SCTP) - continue; - - r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_INET,f,proto); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_INET) failed\n", proto); - goto error; - } - r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_INET6,f,proto); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_INET6) failed\n", proto); - goto error; - } - r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_UNSPEC,f,proto); /* for any */ - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_UNSPEC) failed\n", proto); - goto error; - } - } - } - /* prepare the decoder event sgh */ DetectEngineBuildDecoderEventSgh(de_ctx); - - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("max sig id %" PRIu32 ", array size %" PRIu32 "", DetectEngineGetMaxSigId(de_ctx), DetectEngineGetMaxSigId(de_ctx) / 8 + 1); - SCLogDebug("signature group heads: unique %" PRIu32 ", copies %" PRIu32 ".", de_ctx->gh_unique, de_ctx->gh_reuse); - SCLogDebug("port maxgroups: %" PRIu32 ", avg %" PRIu32 ", tot %" PRIu32 "", g_groupportlist_maxgroups, g_groupportlist_groupscnt ? g_groupportlist_totgroups/g_groupportlist_groupscnt : 0, g_groupportlist_totgroups); - - SCLogInfo("building signature grouping structure, stage 3: building destination address lists... complete"); - } return 0; -error: - printf("SigAddressPrepareStage3 error\n"); - return -1; } int SigAddressCleanupStage1(DetectEngineCtx *de_ctx) @@ -4148,16 +3944,6 @@ int SigAddressCleanupStage1(DetectEngineCtx *de_ctx) if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("cleaning up signature grouping structure..."); } - - int f, proto; - for (f = 0; f < FLOW_STATES; f++) { - for (proto = 0; proto < 256; proto++) { - /* XXX fix this */ - DetectAddressHeadFree(de_ctx->flow_gh[f].src_gh[proto]); - de_ctx->flow_gh[f].src_gh[proto] = NULL; - } - } - if (de_ctx->decoder_event_sgh) SigGroupHeadFree(de_ctx->decoder_event_sgh); de_ctx->decoder_event_sgh = NULL; @@ -4232,6 +4018,32 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) uint32_t idx = 0; + for (idx = 0; idx < 256; idx++) { + int f = 0; + for (f = 0; f <= 1; f++) { + SigGroupHead *sgh = de_ctx->flow_gh[f].sgh[idx]; + if (sgh == NULL) { + //SCLogInfo("skipped %u/%d", idx, f); + continue; + } + + uint32_t max_idx = DetectEngineGetMaxSigId(de_ctx); + SigGroupHeadSetSigCnt(sgh, max_idx); + SigGroupHeadSetProtoAndDirection(sgh, idx, + ((f == 1) ? SIG_FLAG_TOSERVER : SIG_FLAG_TOCLIENT)); + SigGroupHeadBuildMatchArray(de_ctx, sgh, max_idx); + SigGroupHeadSetFilemagicFlag(de_ctx, sgh); + SigGroupHeadSetFileMd5Flag(de_ctx, sgh); + SigGroupHeadSetFilesizeFlag(de_ctx, sgh); + SigGroupHeadSetFilestoreCount(de_ctx, sgh); + SCLogDebug("filestore count %u", sgh->filestore_cnt); + + PatternMatchPrepareGroup(de_ctx, sgh); + SigGroupHeadBuildNonMpmArray(de_ctx, sgh); + } + } + + for (idx = 0; idx < de_ctx->sgh_array_cnt; idx++) { SigGroupHead *sgh = de_ctx->sgh_array[idx]; if (sgh == NULL) @@ -4276,371 +4088,59 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SCReturnInt(0); } -/* shortcut for debugging. If enabled Stage5 will - * print sigid's for all groups */ -#define PRINTSIGS - -/* just printing */ -int SigAddressPrepareStage5(DetectEngineCtx *de_ctx) +static int SigMatchListLen(SigMatch *sm) { - DetectAddressHead *global_dst_gh = NULL; - DetectAddress *global_src_gr = NULL, *global_dst_gr = NULL; - uint32_t u; + int len = 0; + for (; sm != NULL; sm = sm->next) + len++; - printf("* Building signature grouping structure, stage 5: print...\n"); + return len; +} - int f, proto; - printf("\n"); - for (f = 0; f < FLOW_STATES; f++) { - printf("\n"); - for (proto = 0; proto < 256; proto++) { - if (proto != IPPROTO_TCP) - continue; +static int SigMatchPrepare(DetectEngineCtx *de_ctx) +{ + SCEnter(); - for (global_src_gr = de_ctx->flow_gh[f].src_gh[proto]->ipv4_head; global_src_gr != NULL; - global_src_gr = global_src_gr->next) - { - printf("1 Src Addr: "); DetectAddressPrint(global_src_gr); - printf(" (sh %p)\n", global_src_gr->sh); - //printf("\n"); - -#ifdef PRINTSIGS - SigGroupHeadPrintSigs(de_ctx, global_src_gr->sh); - if (global_src_gr->sh != NULL) { - printf(" - "); - for (u = 0; u < global_src_gr->sh->sig_cnt; u++) { - Signature *s = global_src_gr->sh->match_array[u]; - printf("%" PRIu32 " ", s->id); - } - printf("\n"); + Signature *s = de_ctx->sig_list; + for (; s != NULL; s = s->next) { + int type; + for (type = 0; type < DETECT_SM_LIST_MAX; type++) { + SigMatch *sm = s->sm_lists[type]; + int len = SigMatchListLen(sm); + if (len == 0) + s->sm_arrays[type] = NULL; + else { + SigMatchData *smd = (SigMatchData*)SCMalloc(len * sizeof(SigMatchData)); + if (smd == NULL) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + exit(EXIT_FAILURE); } -#endif - - global_dst_gh = global_src_gr->dst_gh; - if (global_dst_gh == NULL) - continue; + /* Copy sm type and Context into array */ + s->sm_arrays[type] = smd; + for (; sm != NULL; sm = sm->next, smd++) { + smd->type = sm->type; + smd->ctx = sm->ctx; + smd->is_last = (sm->next == NULL); + } + } + } + } - for (global_dst_gr = global_dst_gh->ipv4_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" 2 Dst Addr: "); DetectAddressPrint(global_dst_gr); + SCReturnInt(0); +} - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf(" (COPY): "); - } else { - printf(" (ORIGINAL): "); - } - } else { - printf(" "); - } - -#ifdef PRINTSIGS - if (global_dst_gr->sh != NULL) { - printf(" - "); - for (u = 0; u < global_dst_gr->sh->sig_cnt; u++) { - Signature *s = global_dst_gr->sh->match_array[u]; - printf("%" PRIu32 " ", s->id); - } - printf("\n"); - } -#endif - - - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" 3 Src port(range): "); DetectPortPrint(sp); - //printf(" (sh %p)", sp->sh); - printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" 4 Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ", sgh %p, minlen %" PRIu32 ")", dp->sh->sig_cnt, dp->sh, dp->sh->mpm_content_minlen); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = dp->sh->match_array[u]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } - } - for (global_dst_gr = global_dst_gh->any_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = dp->sh->match_array[u]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } - } - } -#if 0 - for (global_src_gr = de_ctx->flow_gh[f].src_gh[proto]->ipv6_head; global_src_gr != NULL; - global_src_gr = global_src_gr->next) - { - printf("- "); DetectAddressPrint(global_src_gr); - //printf(" (sh %p)\n", global_src_gr->sh); - - global_dst_gh = global_src_gr->dst_gh; - if (global_dst_gh == NULL) - continue; - - for (global_dst_gr = global_dst_gh->ipv6_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } - } - for (global_dst_gr = global_dst_gh->any_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } - } - } - - for (global_src_gr = de_ctx->flow_gh[f].src_gh[proto]->any_head; global_src_gr != NULL; - global_src_gr = global_src_gr->next) - { - printf("- "); DetectAddressPrint(global_src_gr); - //printf(" (sh %p)\n", global_src_gr->sh); - - global_dst_gh = global_src_gr->dst_gh; - if (global_dst_gh == NULL) - continue; - - for (global_dst_gr = global_dst_gh->any_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } - } - for (global_dst_gr = global_dst_gh->ipv4_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } - } - for (global_dst_gr = global_dst_gh->ipv6_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } - } - } -#endif - } - } - - printf("* Building signature grouping structure, stage 5: print... done\n"); - return 0; -} - -static int SigMatchListLen(SigMatch *sm) -{ - int len = 0; - for (; sm != NULL; sm = sm->next) - len++; - - return len; -} - -static int SigMatchPrepare(DetectEngineCtx *de_ctx) -{ - SCEnter(); - - Signature *s = de_ctx->sig_list; - for (; s != NULL; s = s->next) { - int type; - for (type = 0; type < DETECT_SM_LIST_MAX; type++) { - SigMatch *sm = s->sm_lists[type]; - int len = SigMatchListLen(sm); - if (len == 0) - s->sm_arrays[type] = NULL; - else { - SigMatchData *smd = (SigMatchData*)SCMalloc(len * sizeof(SigMatchData)); - if (smd == NULL) { - SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); - exit(EXIT_FAILURE); - } - /* Copy sm type and Context into array */ - s->sm_arrays[type] = smd; - for (; sm != NULL; sm = sm->next, smd++) { - smd->type = sm->type; - smd->ctx = sm->ctx; - smd->is_last = (sm->next == NULL); - } - } - } - } - - SCReturnInt(0); -} - -/** - * \brief Convert the signature list into the runtime match structure. - * - * \param de_ctx Pointer to the Detection Engine Context whose Signatures have - * to be processed - * - * \retval 0 On Success. - * \retval -1 On failure. - */ -int SigGroupBuild(DetectEngineCtx *de_ctx) -{ - Signature *s = de_ctx->sig_list; +/** + * \brief Convert the signature list into the runtime match structure. + * + * \param de_ctx Pointer to the Detection Engine Context whose Signatures have + * to be processed + * + * \retval 0 On Success. + * \retval -1 On failure. + */ +int SigGroupBuild(DetectEngineCtx *de_ctx) +{ + Signature *s = de_ctx->sig_list; /* Assign the unique order id of signatures after sorting, * so the IP Only engine process them in order too. Also @@ -9375,15 +8875,18 @@ printf("@exit\n\n"); return result; } -static int SigTestSgh01 (void) +static int SigTestContent01 (void) { + uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; + uint16_t buflen = strlen((char *)buf); ThreadVars th_v; - int result = 0; DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; + memset(&th_v, 0, sizeof(th_v)); Packet *p = NULL; - p = UTHBuildPacketSrcDstPorts((uint8_t *)"a", 1, IPPROTO_TCP, 12345, 80); + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -9391,129 +8894,42 @@ static int SigTestSgh01 (void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"1\"; content:\"one\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - if (de_ctx->sig_list->num != 0) { - printf("internal id != 0: "); - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 81 (msg:\"2\"; content:\"two\"; content:\"abcd\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->num != 1) { - printf("internal id != 1: "); - goto end; - } - - de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"3\"; content:\"three\"; sid:3;)"); - if (de_ctx->sig_list->next->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->next->num != 2) { - printf("internal id != 2: "); - goto end; - } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } -#if 0 - printf("-\n"); - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); -#endif - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->match_array == NULL) { - printf("sgh->match_array == NULL: "); - goto end; - } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; - } - - p->dp = 81; - - SigGroupHead *sgh2 = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh2 == NULL) { - printf("no sgh2: "); - goto end; - } -#if 0 - if (!(SigGroupHeadContainsSigId(de_ctx, sgh2, 1))) { - printf("sgh2 doesn't have sid 1: "); - goto end; - } -#endif - if (sgh2->sig_cnt != 1) { - printf("expected one sig, got %u in sgh2: ", sgh2->sig_cnt); - goto end; - } - - if (sgh2->match_array[0] != de_ctx->sig_list->next) { - printf("sgh doesn't contain sid 2, should have (sgh2->match_array[0] %p, expected %p): ", - sgh2->match_array[0], de_ctx->sig_list->next); - goto end; - } - -#if 0 - printf("-\n"); - printf("sgh2->mpm_content_minlen %u\n", sgh2->mpm_content_minlen); - printf("sgh2->mpm_uricontent_minlen %u\n", sgh2->mpm_uricontent_minlen); - printf("sgh2->sig_cnt %u\n", sgh2->sig_cnt); - printf("sgh2->sig_size %u\n", sgh2->sig_size); -#endif - if (sgh2->mpm_content_minlen != 4) { - printf("sgh2->mpm_content_minlen %u, expected 4: ", sgh2->mpm_content_minlen); - goto end; - } + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) + result = 1; + else + printf("sig 1 didn't match: "); - if (sgh2->match_array[0] != de_ctx->sig_list->next) { - printf("sgh2 doesn't contain sid 2, should have: "); - goto end; - } + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); - - result = 1; end: + UTHFreePackets(&p, 1); return result; } -static int SigTestSgh02 (void) +static int SigTestContent02 (void) { + uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; + uint16_t buflen = strlen((char *)buf); ThreadVars th_v; - int result = 0; DetectEngineThreadCtx *det_ctx = NULL; - Packet *p = NULL; - p = UTHBuildPacketSrcDstPorts((uint8_t *)"a", 1, IPPROTO_TCP, 12345, 80); + int result = 0; memset(&th_v, 0, sizeof(th_v)); + Packet *p = NULL; + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -9521,703 +8937,33 @@ static int SigTestSgh02 (void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80:82 (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - if (de_ctx->sig_list->num != 0) { - printf("internal id != 0: "); - goto end; - } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 81 (msg:\"2\"; content:\"two2\"; content:\"abcdef\"; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 31\"; content:\"0123456789012345678901234567890\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } - if (de_ctx->sig_list->next->num != 1) { - printf("internal id != 1: "); - goto end; - } - de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> any 80:81 (msg:\"3\"; content:\"three\"; content:\"abcdefgh\"; sid:3;)"); - if (de_ctx->sig_list->next->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->next->num != 2) { - printf("internal id != 2: "); - goto end; - } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + if (PacketAlertCheck(p, 2)) { + result = 1; + } else + printf("sig 2 didn't match: "); } + else + printf("sig 1 didn't match: "); - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->match_array == NULL) { - printf("sgh->match_array == NULL: "); - goto end; - } - - if (sgh->sig_cnt != 2) { - printf("sgh sig cnt %u, expected 2: ", sgh->sig_cnt); - goto end; - } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->dp = 81; - - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } - - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->sig_cnt != 3) { - printf("sgh sig cnt %u, expected 3: ", sgh->sig_cnt); - goto end; - } - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next) { - printf("sgh doesn't contain sid 2, should have: "); - goto end; - } - if (sgh->match_array[2] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->dp = 82; - - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } - - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->sig_cnt != 1) { - printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); - goto end; - } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->src.family = AF_INET6; - p->dst.family = AF_INET6; - - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } - - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->sig_cnt != 1) { - printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); - goto end; - } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); - - result = 1; -end: - return result; -} - -static int SigTestSgh03 (void) -{ - ThreadVars th_v; - int result = 0; - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload_len = 1; - p->proto = IPPROTO_TCP; - p->dp = 80; - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.6 any (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->num != 0) { - printf("internal id != 0: "); - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.5 any (msg:\"2\"; content:\"two2\"; content:\"abcdef\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->num != 1) { - printf("internal id != 1: "); - goto end; - } - de_ctx->sig_list->next->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.5 any (msg:\"3\"; content:\"three\"; content:\"abcdefgh\"; sid:3;)"); - if (de_ctx->sig_list->next->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->next->num != 2) { - printf("internal id != 2: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } -#if 0 - printf("-\n"); - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->match_array == NULL) { - printf("sgh->match_array == NULL: "); - goto end; - } - - if (sgh->sig_cnt != 2) { - printf("sgh sig cnt %u, expected 2: ", sgh->sig_cnt); - goto end; - } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; - } - - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.5"); - - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } -#if 0 - printf("-\n"); - printf("sgh %p\n", sgh); - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - if (sgh->sig_cnt != 3) { - printf("sgh sig cnt %u, expected 3: ", sgh->sig_cnt); - goto end; - } - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - if (sgh->match_array[2] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3 (%x): ", sgh->mpm_content_minlen, p->dst.addr_data32[0]); - goto end; - } - - - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.6"); - - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } -#if 0 - printf("-\n"); - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->sig_cnt != 1) { - printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); - goto end; - } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); - - result = 1; -end: - SCFree(p); - return result; -} - -static int SigTestSgh04 (void) -{ - ThreadVars th_v; - int result = 0; - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload_len = 1; - p->proto = IPPROTO_TCP; - p->dp = 80; - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.6 any (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->num != 0) { - printf("internal id != 0: "); - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.5 any (msg:\"2\"; content:\"two2\"; content:\"abcdef\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->num != 1) { - printf("internal id != 1: "); - goto end; - } - de_ctx->sig_list->next->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.5 any (msg:\"3\"; content:\"three\"; content:\"abcdefgh\"; sid:3;)"); - if (de_ctx->sig_list->next->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->next->num != 2) { - printf("internal id != 2: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } - - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->match_array == NULL) { - printf("sgh->match_array == NULL: "); - goto end; - } - - if (sgh->sig_cnt != 2) { - printf("sgh sig cnt %u, expected 2: ", sgh->sig_cnt); - goto end; - } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.5"); - - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } - - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->sig_cnt != 3) { - printf("sgh sig cnt %u, expected 3: ", sgh->sig_cnt); - goto end; - } - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next) { - printf("sgh doesn't contain sid 2, should have: "); - goto end; - } - if (sgh->match_array[2] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.6"); - - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } - - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->sig_cnt != 1) { - printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); - goto end; - } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->proto = IPPROTO_GRE; - - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } -#if 0 - printf("-\n"); - printf("sgh->mpm_content_minlen %u\n", sgh->mpm_content_minlen); - printf("sgh->mpm_uricontent_minlen %u\n", sgh->mpm_uricontent_minlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - if (sgh->mpm_content_minlen != 3) { - printf("sgh->mpm_content_minlen %u, expected 3: ", sgh->mpm_content_minlen); - goto end; - } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); - - result = 1; -end: - SCFree(p); - return result; -} - -/** \test setting of mpm type */ -static int SigTestSgh05 (void) -{ - ThreadVars th_v; - int result = 0; - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload_len = 1; - p->proto = IPPROTO_TCP; - p->dp = 80; - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - de_ctx->mpm_matcher = MPM_AC; - - de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.6 any (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } - - if (sgh->mpm_proto_tcp_ctx_ts != NULL || sgh->mpm_proto_tcp_ctx_tc != NULL || - sgh->mpm_proto_udp_ctx_ts != NULL || sgh->mpm_proto_udp_ctx_tc != NULL || - sgh->mpm_proto_other_ctx != NULL) { - printf("sgh->mpm_proto_tcp_ctx_ts != NULL || sgh->mpm_proto_tcp_ctx_tc != NULL" - "sgh->mpm_proto_udp_ctx_ts != NULL || sgh->mpm_proto_udp_ctx_tc != NULL" - "sgh->mpm_proto_other_ctx != NULL: "); - goto end; - } - - if (sgh->mpm_stream_ctx_ts == NULL || sgh->mpm_stream_ctx_tc == NULL) { - printf("sgh->mpm_stream_ctx == NULL || sgh->mpm_stream_ctx_tc == NULL: "); - goto end; - } - - if (sgh->mpm_stream_ctx_ts->mpm_type != MPM_AC) { - printf("sgh->mpm_type != MPM_AC, expected %d, got %d: ", MPM_AC, sgh->mpm_stream_ctx_ts->mpm_type); - goto end; - } - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); - - result = 1; -end: - SCFree(p); - return result; -} - -static int SigTestContent01 (void) -{ - uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; - uint16_t buflen = strlen((char *)buf); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - - Packet *p = NULL; - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - result = 1; - else - printf("sig 1 didn't match: "); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); -end: - UTHFreePackets(&p, 1); - return result; -} - -static int SigTestContent02 (void) -{ - uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; - uint16_t buflen = strlen((char *)buf); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - Packet *p = NULL; - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 31\"; content:\"0123456789012345678901234567890\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - if (PacketAlertCheck(p, 2)) { - result = 1; - } else - printf("sig 2 didn't match: "); - } - else - printf("sig 1 didn't match: "); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); @@ -11686,12 +10432,6 @@ void SigRegisterTests(void) UtRegisterTest("SigTestMemory02", SigTestMemory02, 1); UtRegisterTest("SigTestMemory03", SigTestMemory03, 1); - UtRegisterTest("SigTestSgh01", SigTestSgh01, 1); - UtRegisterTest("SigTestSgh02", SigTestSgh02, 1); - UtRegisterTest("SigTestSgh03", SigTestSgh03, 1); - UtRegisterTest("SigTestSgh04", SigTestSgh04, 1); - UtRegisterTest("SigTestSgh05", SigTestSgh05, 1); - UtRegisterTest("SigTestContent01 -- 32 byte pattern", SigTestContent01, 1); UtRegisterTest("SigTestContent02 -- 32+31 byte pattern", SigTestContent02, 1); UtRegisterTest("SigTestContent03 -- 32 byte pattern, x2 + distance", SigTestContent03, 1); diff --git a/src/detect.h b/src/detect.h index 3afd5b313217..01756e033577 100644 --- a/src/detect.h +++ b/src/detect.h @@ -525,8 +525,9 @@ typedef struct DetectEngineIPOnlyCtx_ { } DetectEngineIPOnlyCtx; typedef struct DetectEngineLookupFlow_ { - DetectAddressHead *src_gh[256]; /* a head for each protocol */ - DetectAddressHead *tmp_gh[256]; + DetectPort *tcp; + DetectPort *udp; + struct SigGroupHead_ *sgh[256]; } DetectEngineLookupFlow; /* Flow status From 9ae4cb9e0234ca7f64c73a30b97598a00ca41a11 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Sep 2015 23:20:03 +0200 Subject: [PATCH 1151/2553] detect: debug output --- src/detect.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index 5b543ed936bb..62aa6a8bc80e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -618,16 +618,23 @@ SigGroupHead *SigMatchSignaturesGetSgh(DetectEngineCtx *de_ctx, DetectEngineThre int proto = IP_GET_IPPROTO(p); if (proto == IPPROTO_TCP) { DetectPort *list = de_ctx->flow_gh[f].tcp; + SCLogDebug("tcp toserver %p, tcp toclient %p: going to use %p", + de_ctx->flow_gh[1].tcp, de_ctx->flow_gh[0].tcp, de_ctx->flow_gh[f].tcp); uint16_t port = f ? p->dp : p->sp; + SCLogDebug("tcp port %u -> %u:%u", port, p->sp, p->dp); DetectPort *sghport = DetectPortLookupGroup(list, port); if (sghport != NULL) sgh = sghport->sh; + SCLogDebug("TCP list %p, port %u, direction %s, sghport %p, sgh %p", + list, port, f ? "toserver" : "toclient", sghport, sgh); } else if (proto == IPPROTO_UDP) { DetectPort *list = de_ctx->flow_gh[f].udp; uint16_t port = f ? p->dp : p->sp; DetectPort *sghport = DetectPortLookupGroup(list, port); if (sghport != NULL) sgh = sghport->sh; + SCLogDebug("UDP list %p, port %u, direction %s, sghport %p, sgh %p", + list, port, f ? "toserver" : "toclient", sghport, sgh); } else { sgh = de_ctx->flow_gh[f].sgh[proto]; } @@ -861,6 +868,8 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, const uint8_t flags, const AppProto alproto, const int has_state, uint8_t *sms_runflags) { + SCEnter(); + /* have a look at the reassembled stream (if any) */ if (p->flowflags & FLOW_PKT_ESTABLISHED) { SCLogDebug("p->flowflags & FLOW_PKT_ESTABLISHED"); @@ -1081,7 +1090,11 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_PACKET); *sms_runflags |= SMS_USED_PM; + } else { + SCLogDebug("not packet"); } + } else { + SCLogDebug("how did we get here?"); } /* UDP DNS inspection is independent of est or not */ @@ -1309,9 +1322,11 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_START(p, PROF_DETECT_GETSGH); if ((p->flowflags & FLOW_PKT_TOSERVER) && (pflow->flags & FLOW_SGH_TOSERVER)) { det_ctx->sgh = pflow->sgh_toserver; + SCLogDebug("det_ctx->sgh = pflow->sgh_toserver; => %p", det_ctx->sgh); sms_runflags |= SMS_USE_FLOW_SGH; } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && (pflow->flags & FLOW_SGH_TOCLIENT)) { det_ctx->sgh = pflow->sgh_toclient; + SCLogDebug("det_ctx->sgh = pflow->sgh_toclient; => %p", det_ctx->sgh); sms_runflags |= SMS_USE_FLOW_SGH; } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_GETSGH); @@ -1714,11 +1729,14 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh KEYWORD_PROFILING_START; if (sigmatch_table[smd->type].Match(th_v, det_ctx, p, s, smd->ctx) <= 0) { KEYWORD_PROFILING_END(det_ctx, smd->type, 0); + SCLogDebug("no match"); goto next; } KEYWORD_PROFILING_END(det_ctx, smd->type, 1); - if (smd->is_last) + if (smd->is_last) { + SCLogDebug("match and is_last"); break; + } smd++; } } @@ -2944,7 +2962,10 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 SCLogInfo("PORT %u-%u %p (sgh=%s)", iter->port, iter->port2, iter->sh, iter->flags & PORT_SIGGROUPHEAD_COPY ? "ref" : "own"); } #endif - SCLogInfo("%u port groups, %u unique SGH's, %u copies", cnt, own, ref); + SCLogInfo("%s %s: %u port groups, %u unique SGH's, %u copies", + ipproto == 6 ? "TCP" : "UDP", + direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", + cnt, own, ref); return list; } From 4223ce9aba0b8303e7b11092ce7e490ac026610a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Sep 2015 13:20:20 +0200 Subject: [PATCH 1152/2553] detect: remove obsolete grouping code --- src/detect.c | 587 --------------------------------------------------- 1 file changed, 587 deletions(-) diff --git a/src/detect.c b/src/detect.c index 62aa6a8bc80e..d118fa73c200 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3130,204 +3130,11 @@ static int DetectEngineLookupFlowAddSig(DetectEngineCtx *de_ctx, Signature *s) return 0; } -static DetectAddress *GetHeadPtr(DetectAddressHead *head, int family) -{ - DetectAddress *grhead; - - if (head == NULL) - return NULL; - - if (family == AF_INET) { - grhead = head->ipv4_head; - } else if (family == AF_INET6) { - grhead = head->ipv6_head; - } else { - grhead = head->any_head; - } - - return grhead; -} - //#define SMALL_MPM(c) 0 #define SMALL_MPM(c) ((c) == 1) // || (c) == 2) // || (c) == 3) -int CreateGroupedAddrListCmpCnt(DetectAddress *a, DetectAddress *b) -{ - if (a->cnt > b->cnt) - return 1; - return 0; -} - -int CreateGroupedAddrListCmpMpmMinlen(DetectAddress *a, DetectAddress *b) -{ - if (a->sh == NULL || b->sh == NULL) - return 0; - - if (SMALL_MPM(a->sh->mpm_content_minlen)) - return 1; - - if (a->sh->mpm_content_minlen < b->sh->mpm_content_minlen) - return 1; - return 0; -} - -/* set unique_groups to 0 for no grouping. - * - * srchead is a ordered "inserted" list w/o internal overlap - * - */ -int CreateGroupedAddrList(DetectEngineCtx *de_ctx, DetectAddress *srchead, - int family, DetectAddressHead *newhead, - uint32_t unique_groups, - int (*CompareFunc)(DetectAddress *, DetectAddress *), - uint32_t max_idx) -{ - DetectAddress *tmplist = NULL, *tmplist2 = NULL, *joingr = NULL; - char insert = 0; - DetectAddress *gr, *next_gr; - uint32_t groups = 0; - - /* insert the addresses into the tmplist, where it will - * be sorted descending on 'cnt'. */ - for (gr = srchead; gr != NULL; gr = gr->next) { - BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); - - if (SMALL_MPM(gr->sh->mpm_content_minlen) && unique_groups > 0) - unique_groups++; - - groups++; - - /* alloc a copy */ - DetectAddress *newtmp = DetectAddressCopy(gr); - if (newtmp == NULL) { - goto error; - } - SigGroupHeadCopySigs(de_ctx, gr->sh,&newtmp->sh); - - DetectPort *port = gr->port; - for ( ; port != NULL; port = port->next) { - DetectPortInsertCopy(de_ctx,&newtmp->port, port); - newtmp->flags |= ADDRESS_HAVEPORT; - } - - /* insert it */ - DetectAddress *tmpgr = tmplist, *prevtmpgr = NULL; - if (tmplist == NULL) { - /* empty list, set head */ - tmplist = newtmp; - } else { - /* look for the place to insert */ - for ( ; tmpgr != NULL&&!insert; tmpgr = tmpgr->next) { - if (CompareFunc(gr, tmpgr)) { - if (tmpgr == tmplist) { - newtmp->next = tmplist; - tmplist = newtmp; - } else { - newtmp->next = prevtmpgr->next; - prevtmpgr->next = newtmp; - } - insert = 1; - } - prevtmpgr = tmpgr; - } - if (insert == 0) { - newtmp->next = NULL; - prevtmpgr->next = newtmp; - } - insert = 0; - } - } - - uint32_t i = unique_groups; - if (i == 0) i = groups; - - for (gr = tmplist; gr != NULL; ) { - BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); - - if (i == 0) { - if (joingr == NULL) { - joingr = DetectAddressCopy(gr); - if (joingr == NULL) { - goto error; - } - - SigGroupHeadCopySigs(de_ctx,gr->sh,&joingr->sh); - - DetectPort *port = gr->port; - for ( ; port != NULL; port = port->next) { - DetectPortInsertCopy(de_ctx,&joingr->port, port); - joingr->flags |= ADDRESS_HAVEPORT; - } - } else { - DetectAddressJoin(de_ctx, joingr, gr); - } - } else { - DetectAddress *newtmp = DetectAddressCopy(gr); - if (newtmp == NULL) { - goto error; - } - - SigGroupHeadCopySigs(de_ctx,gr->sh,&newtmp->sh); - - DetectPort *port = gr->port; - for ( ; port != NULL; port = port->next) { - DetectPortInsertCopy(de_ctx,&newtmp->port, port); - newtmp->flags |= ADDRESS_HAVEPORT; - } - - if (tmplist2 == NULL) { - tmplist2 = newtmp; - } else { - newtmp->next = tmplist2; - tmplist2 = newtmp; - } - } - if (i)i--; - - next_gr = gr->next; - DetectAddressFree(gr); - gr = next_gr; - } - - /* we now have a tmplist2 containing the 'unique' groups and - * possibly a joingr that covers the rest. Now build the newhead - * that we will pass back to the caller. - * - * Start with inserting the unique groups */ - for (gr = tmplist2; gr != NULL; ) { - BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); - - DetectAddress *newtmp = DetectAddressCopy(gr); - if (newtmp == NULL) { - goto error; - } - SigGroupHeadCopySigs(de_ctx, gr->sh,&newtmp->sh); - - DetectPort *port = gr->port; - for ( ; port != NULL; port = port->next) { - DetectPortInsertCopy(de_ctx, &newtmp->port, port); - newtmp->flags |= ADDRESS_HAVEPORT; - } - - DetectAddressInsert(de_ctx, newhead, newtmp); - - next_gr = gr->next; - DetectAddressFree(gr); - gr = next_gr; - } - - /* if present, insert the joingr that covers the rest */ - if (joingr != NULL) { - DetectAddressInsert(de_ctx, newhead, joingr); - } - - return 0; -error: - return -1; -} - int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b) { if (a->cnt > b->cnt) @@ -3548,399 +3355,6 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) return 0; } -/** - * \brief Build the destination address portion of the match tree - */ -int BuildDestinationAddressHeads(DetectEngineCtx *de_ctx, - DetectAddressHead *head, - int family, int flow, int ipproto) -{ - Signature *tmp_s = NULL; - DetectAddress *gr = NULL, *sgr = NULL, *lookup_gr = NULL; - uint32_t max_idx = 0; - - DetectAddress *grhead = NULL, *grdsthead = NULL, *grsighead = NULL; - - /* based on the family, select the list we are using in the head */ - grhead = GetHeadPtr(head, family); - - /* loop through the global source address list */ - for (gr = grhead; gr != NULL; gr = gr->next) { - //printf(" * Source group (BuildDestinationAddressHeads): "); DetectAddressPrint(gr); printf(" (%p)\n", gr); - - /* initialize the destination group head */ - gr->dst_gh = DetectAddressHeadInit(); - if (gr->dst_gh == NULL) { - goto error; - } - - /* use a tmp list for speeding up insertions */ - DetectAddress *tmp_gr_list = NULL; - - /* loop through all signatures in this source address group - * and build the temporary destination address list for it */ - uint32_t sig; - for (sig = 0; sig < de_ctx->sig_array_len; sig++) { - if (!(gr->sh->init->sig_array[(sig/8)] & (1<<(sig%8)))) - continue; - - tmp_s = de_ctx->sig_array[sig]; - if (tmp_s == NULL) - continue; - - //printf(" * (tmp) Signature %u (num %u)\n", tmp_s->id, tmp_s->num); - - max_idx = sig; - - /* build the temp list */ - grsighead = GetHeadPtr(&tmp_s->dst, family); - for (sgr = grsighead; sgr != NULL; sgr = sgr->next) { - //printf(" * (tmp) dst group: "); DetectAddressPrint(sgr); printf(" (%p)\n", sgr); - - if ((lookup_gr = DetectAddressLookupInList(tmp_gr_list, sgr)) == NULL) { - DetectAddress *grtmp = DetectAddressCopy(sgr); - if (grtmp == NULL) { - goto error; - } - SigGroupHeadAppendSig(de_ctx,&grtmp->sh,tmp_s); - - DetectAddressAdd(&tmp_gr_list,grtmp); - } else { - /* our group will only have one sig, this one. So add that. */ - SigGroupHeadAppendSig(de_ctx, &lookup_gr->sh, tmp_s); - lookup_gr->cnt++; - } - } - - } - - /* Create the destination address list, keeping in - * mind the limits we use. */ - int groups = (flow ? de_ctx->max_uniq_toserver_dst_groups : de_ctx->max_uniq_toclient_dst_groups); - - CreateGroupedAddrList(de_ctx, tmp_gr_list, family, gr->dst_gh, groups, - CreateGroupedAddrListCmpMpmMinlen, max_idx); - - /* see if the sig group head of each address group is the - * same as an earlier one. If it is, free our head and use - * a pointer to the earlier one. This saves _a lot_ of memory. - */ - grdsthead = GetHeadPtr(gr->dst_gh, family); - for (sgr = grdsthead; sgr != NULL; sgr = sgr->next) { - //printf(" * Destination group: "); DetectAddressPrint(sgr); printf("\n"); - - /* Because a pattern matcher context uses quite some - * memory, we first check if we can reuse it from - * another group head. */ - SigGroupHead *sgh = SigGroupHeadHashLookup(de_ctx, sgr->sh); - if (sgh == NULL) { - /* put the contents in our sig group head */ - SigGroupHeadSetSigCnt(sgr->sh, max_idx); - SigGroupHeadSetProtoAndDirection(sgr->sh, ipproto, flow); - SigGroupHeadBuildMatchArray(de_ctx, sgr->sh, max_idx); - SigGroupHeadHashAdd(de_ctx, sgr->sh); - SigGroupHeadStore(de_ctx, sgr->sh); - de_ctx->gh_unique++; - } else { - SCLogDebug("calling SigGroupHeadFree sgr %p, sgr->sh %p", sgr, sgr->sh); - SigGroupHeadFree(sgr->sh); - sgr->sh = sgh; - - de_ctx->gh_reuse++; - sgr->flags |= ADDRESS_SIGGROUPHEAD_COPY; - sgr->sh->flags |= SIG_GROUP_HEAD_REFERENCED; - } - } - - /* free the temp list */ - DetectAddressCleanupList(tmp_gr_list); - /* clear now unneeded sig group head */ - SCLogDebug("calling SigGroupHeadFree gr %p, gr->sh %p", gr, gr->sh); - SigGroupHeadFree(gr->sh); - gr->sh = NULL; - } - - return 0; -error: - return -1; -} - -//static -int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, - DetectAddressHead *head, - int family, int flow, int ipproto) -{ - Signature *tmp_s = NULL; - DetectAddress *src_gr = NULL, *dst_gr = NULL, *sig_gr = NULL, *lookup_gr = NULL; - DetectAddress *src_gr_head = NULL, *dst_gr_head = NULL, *sig_gr_head = NULL; - uint32_t max_idx = 0; - - /* loop through the global source address list */ - src_gr_head = GetHeadPtr(head,family); - for (src_gr = src_gr_head; src_gr != NULL; src_gr = src_gr->next) { - //printf(" * Source group: "); DetectAddressPrint(src_gr); printf("\n"); - - /* initialize the destination group head */ - src_gr->dst_gh = DetectAddressHeadInit(); - if (src_gr->dst_gh == NULL) { - goto error; - } - - /* use a tmp list for speeding up insertions */ - DetectAddress *tmp_gr_list = NULL; - - /* loop through all signatures in this source address group - * and build the temporary destination address list for it */ - uint32_t sig; - for (sig = 0; sig < de_ctx->sig_array_len; sig++) { - if (!(src_gr->sh->init->sig_array[(sig/8)] & (1<<(sig%8)))) - continue; - - tmp_s = de_ctx->sig_array[sig]; - if (tmp_s == NULL) - continue; - - //printf(" * Source group: "); DetectAddressPrint(src_gr); printf("\n"); - - max_idx = sig; - - /* build the temp list */ - sig_gr_head = GetHeadPtr(&tmp_s->dst,family); - for (sig_gr = sig_gr_head; sig_gr != NULL; sig_gr = sig_gr->next) { - //printf(" * Sig dst addr: "); DetectAddressPrint(sig_gr); printf("\n"); - - if ((lookup_gr = DetectAddressLookupInList(tmp_gr_list, sig_gr)) == NULL) { - DetectAddress *grtmp = DetectAddressCopy(sig_gr); - if (grtmp == NULL) { - goto error; - } - SigGroupHeadAppendSig(de_ctx, &grtmp->sh, tmp_s); - - DetectAddressAdd(&tmp_gr_list,grtmp); - } else { - /* our group will only have one sig, this one. So add that. */ - SigGroupHeadAppendSig(de_ctx, &lookup_gr->sh, tmp_s); - lookup_gr->cnt++; - } - - SCLogDebug("calling SigGroupHeadFree sig_gr %p, sig_gr->sh %p", sig_gr, sig_gr->sh); - SigGroupHeadFree(sig_gr->sh); - sig_gr->sh = NULL; - } - } - - /* Create the destination address list, keeping in - * mind the limits we use. */ - int groups = (flow ? de_ctx->max_uniq_toserver_dst_groups : de_ctx->max_uniq_toclient_dst_groups); - - CreateGroupedAddrList(de_ctx, tmp_gr_list, family, src_gr->dst_gh, groups, - CreateGroupedAddrListCmpMpmMinlen, max_idx); - - /* add the ports to the dst address groups and the sigs - * to the ports */ - dst_gr_head = GetHeadPtr(src_gr->dst_gh,family); - for (dst_gr = dst_gr_head; dst_gr != NULL; dst_gr = dst_gr->next) { - //printf(" * Destination group: "); DetectAddressPrint(dst_gr); printf("\n"); - - dst_gr->flags |= ADDRESS_HAVEPORT; - - if (dst_gr->sh == NULL) - continue; - - /* we will reuse address sig group heads at this points, - * because if the sigs are the same, the ports will be - * the same. Saves memory and a lot of init time. */ - SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, dst_gr->sh); - if (lookup_sgh == NULL) { - DetectPortSpHashReset(de_ctx); - - uint32_t sig2; - for (sig2 = 0; sig2 < max_idx+1; sig2++) { - if (!(dst_gr->sh->init->sig_array[(sig2/8)] & (1<<(sig2%8)))) - continue; - - Signature *s = de_ctx->sig_array[sig2]; - if (s == NULL) - continue; - - //printf(" + Destination group (grouped): "); DetectAddressPrint(dst_gr); printf("\n"); - - DetectPort *sdp = s->sp; - for ( ; sdp != NULL; sdp = sdp->next) { - DetectPort *lookup_port = DetectPortSpHashLookup(de_ctx, sdp); - if (lookup_port == NULL) { - DetectPort *port = DetectPortCopySingle(de_ctx,sdp); - if (port == NULL) - goto error; - - SigGroupHeadAppendSig(de_ctx, &port->sh, s); - DetectPortSpHashAdd(de_ctx, port); - port->cnt = 1; - } else { - SigGroupHeadAppendSig(de_ctx, &lookup_port->sh, s); - lookup_port->cnt++; - } - } - } - - int spgroups = (flow ? de_ctx->max_uniq_toserver_sp_groups : de_ctx->max_uniq_toclient_sp_groups); - - CreateGroupedPortList(de_ctx, de_ctx->sport_hash_table, &dst_gr->port, spgroups, - CreateGroupedPortListCmpMpmMinlen, max_idx); - - SCLogDebug("adding sgh %p to the hash", dst_gr->sh); - SigGroupHeadHashAdd(de_ctx, dst_gr->sh); - - dst_gr->sh->init->port = dst_gr->port; - /* mark this head for deletion once we no longer need - * the hash. We're only using the port ptr, so no problem - * when we remove this after initialization is done */ - dst_gr->sh->flags |= SIG_GROUP_HEAD_FREE; - - /* for each destination port we setup the siggrouphead here */ - DetectPort *sp = dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - //printf(" * Src Port(range): "); DetectPortPrint(sp); printf("\n"); - - if (sp->sh == NULL) - continue; - - /* we will reuse address sig group heads at this points, - * because if the sigs are the same, the ports will be - * the same. Saves memory and a lot of init time. */ - SigGroupHead *lookup_sp_sgh = SigGroupHeadSPortHashLookup(de_ctx, sp->sh); - if (lookup_sp_sgh == NULL) { - DetectPortDpHashReset(de_ctx); - uint32_t sig2; - for (sig2 = 0; sig2 < max_idx+1; sig2++) { - if (!(sp->sh->init->sig_array[(sig2/8)] & (1<<(sig2%8)))) - continue; - - Signature *s = de_ctx->sig_array[sig2]; - if (s == NULL) - continue; - - DetectPort *sdp = s->dp; - for ( ; sdp != NULL; sdp = sdp->next) { - DetectPort *lookup_port = DetectPortDpHashLookup(de_ctx,sdp); - if (lookup_port == NULL) { - DetectPort *port = DetectPortCopySingle(de_ctx,sdp); - if (port == NULL) - goto error; - - SigGroupHeadAppendSig(de_ctx, &port->sh, s); - DetectPortDpHashAdd(de_ctx,port); - port->cnt = 1; - } else { - SigGroupHeadAppendSig(de_ctx, &lookup_port->sh, s); - lookup_port->cnt++; - } - } - } - - int dpgroups = (flow ? de_ctx->max_uniq_toserver_dp_groups : de_ctx->max_uniq_toclient_dp_groups); - - CreateGroupedPortList(de_ctx, de_ctx->dport_hash_table, - &sp->dst_ph, dpgroups, - CreateGroupedPortListCmpMpmMinlen, max_idx); - - SigGroupHeadSPortHashAdd(de_ctx, sp->sh); - - sp->sh->init->port = sp->dst_ph; - /* mark this head for deletion once we no longer need - * the hash. We're only using the port ptr, so no problem - * when we remove this after initialization is done */ - sp->sh->flags |= SIG_GROUP_HEAD_FREE; - - /* for each destination port we setup the siggrouphead here */ - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - if (dp->sh == NULL) - continue; - - /* Because a pattern matcher context uses quite some - * memory, we first check if we can reuse it from - * another group head. */ - SigGroupHead *lookup_dp_sgh = SigGroupHeadDPortHashLookup(de_ctx, dp->sh); - if (lookup_dp_sgh == NULL) { - SCLogDebug("dp %p dp->sh %p is the original (sp %p, dst_gr %p, src_gr %p)", dp, dp->sh, sp, dst_gr, src_gr); - - SigGroupHeadSetSigCnt(dp->sh, max_idx); - SigGroupHeadSetProtoAndDirection(dp->sh, ipproto, flow); - SigGroupHeadBuildMatchArray(de_ctx,dp->sh, max_idx); - SigGroupHeadDPortHashAdd(de_ctx, dp->sh); - SigGroupHeadStore(de_ctx, dp->sh); - de_ctx->gh_unique++; - } else { - SCLogDebug("dp %p dp->sh %p is a copy", dp, dp->sh); - - SigGroupHeadFree(dp->sh); - dp->sh = lookup_dp_sgh; - dp->flags |= PORT_SIGGROUPHEAD_COPY; - dp->sh->flags |= SIG_GROUP_HEAD_REFERENCED; - - de_ctx->gh_reuse++; - } - } - /* sig group head found in hash, free it and use the hashed one */ - } else { - SigGroupHeadFree(sp->sh); - sp->sh = lookup_sp_sgh; - sp->flags |= PORT_SIGGROUPHEAD_COPY; - sp->sh->flags |= SIG_GROUP_HEAD_REFERENCED; - - SCLogDebug("replacing sp->dst_ph %p with lookup_sp_sgh->init->port %p", sp->dst_ph, lookup_sp_sgh->init->port); - DetectPortCleanupList(sp->dst_ph); - sp->dst_ph = lookup_sp_sgh->init->port; - sp->flags |= PORT_GROUP_PORTS_COPY; - - de_ctx->gh_reuse++; - } - } - } else { - SigGroupHeadFree(dst_gr->sh); - dst_gr->sh = lookup_sgh; - dst_gr->flags |= ADDRESS_SIGGROUPHEAD_COPY; - dst_gr->sh->flags |= SIG_GROUP_HEAD_REFERENCED; - - SCLogDebug("replacing dst_gr->port %p with lookup_sgh->init->port %p", dst_gr->port, lookup_sgh->init->port); - DetectPortCleanupList(dst_gr->port); - dst_gr->port = lookup_sgh->init->port; - dst_gr->flags |= ADDRESS_PORTS_COPY; - - de_ctx->gh_reuse++; - } - } - /* free the temp list */ - DetectAddressCleanupList(tmp_gr_list); - /* clear now unneeded sig group head */ - SigGroupHeadFree(src_gr->sh); - src_gr->sh = NULL; - - /* free dst addr sgh's */ - dst_gr_head = GetHeadPtr(src_gr->dst_gh,family); - for (dst_gr = dst_gr_head; dst_gr != NULL; dst_gr = dst_gr->next) { - if (!(dst_gr->flags & ADDRESS_SIGGROUPHEAD_COPY)) { - if (!(dst_gr->sh->flags & SIG_GROUP_HEAD_REFERENCED)) { - SCLogDebug("removing sgh %p from hash", dst_gr->sh); - - int r = SigGroupHeadHashRemove(de_ctx,dst_gr->sh); - BUG_ON(r == -1); - if (r == 0) { - SCLogDebug("removed sgh %p from hash", dst_gr->sh); - SigGroupHeadFree(dst_gr->sh); - dst_gr->sh = NULL; - } - } - } - } - } - - return 0; -error: - return -1; -} - static void DetectEngineBuildDecoderEventSgh(DetectEngineCtx *de_ctx) { if (de_ctx->decoder_event_sgh == NULL) @@ -4424,7 +3838,6 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) } -// SigAddressPrepareStage5(de_ctx); // DetectAddressPrintMemory(); // DetectSigGroupPrintMemory(); // DetectPortPrintMemory(); From d82df4eb8b50064d5e6e5da6b1fe684eb190b08d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Sep 2015 16:03:48 +0200 Subject: [PATCH 1153/2553] detect-mpm: make sgh setup proto aware Allow multi-proto, multi-direction sgh's. --- src/detect-engine-mpm.c | 451 ++++++++++++++++------------------- src/detect-engine-siggroup.c | 5 +- src/detect-engine-siggroup.h | 2 +- src/detect.c | 5 +- src/detect.h | 4 +- 5 files changed, 213 insertions(+), 254 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index e96788218f66..3ccfc5d8e890 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1149,6 +1149,139 @@ static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, return; } +#define SGH_PROTO(sgh, p) ((sgh)->init->protos[(p)] == 1) +#define SGH_DIRECTION_TS(sgh) ((sgh)->init->direction & SIG_FLAG_TOSERVER) +#define SGH_DIRECTION_TC(sgh) ((sgh)->init->direction & SIG_FLAG_TOCLIENT) + +/* TODO the sig updates don't belong here */ +static void PopulateMpmAddPatternToMpmPMATCH(const DetectEngineCtx *de_ctx, + SigGroupHead *sgh, Signature *s, + SigMatch *mpm_sm) +{ + DetectContentData *cd = (DetectContentData *)mpm_sm->ctx; + + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + if (DETECT_CONTENT_IS_SINGLE(cd) && + !(cd->flags & DETECT_CONTENT_NEGATED) && + !(cd->flags & DETECT_CONTENT_REPLACE) && + cd->content_len == cd->fp_chop_len) + { + cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; + } + } else { + if (DETECT_CONTENT_IS_SINGLE(cd) && + !(cd->flags & DETECT_CONTENT_NEGATED) && + !(cd->flags & DETECT_CONTENT_REPLACE)) + { + cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; + } + } + + /* add the content to the "packet" mpm: + * chop is handled in PopulateMpmHelperAddPatternToPktCtx + */ + if (SignatureHasPacketContent(s)) { + /* per TCP packet mpm */ + if (SGH_PROTO(sgh, IPPROTO_TCP) && (s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) { + if (SGH_DIRECTION_TS(sgh) && s->flags & SIG_FLAG_TOSERVER) { + PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_ts, + cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); + } + if (SGH_DIRECTION_TC(sgh) && s->flags & SIG_FLAG_TOCLIENT) { + PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_tc, + cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); + } + } + } + /* per UDP packet mpm */ + if (SGH_PROTO(sgh, IPPROTO_UDP) && (s->proto.proto[IPPROTO_UDP / 8] & 1 << (IPPROTO_UDP % 8))) { + if (SGH_DIRECTION_TS(sgh) && s->flags & SIG_FLAG_TOSERVER) { + PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_ts, + cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); + } + if (SGH_DIRECTION_TC(sgh) && s->flags & SIG_FLAG_TOCLIENT) { + PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_tc, + cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); + } + } + + /* other IP protocols */ + if (!(SGH_PROTO(sgh, IPPROTO_TCP) || SGH_PROTO(sgh, IPPROTO_UDP))) { + PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_other_ctx, + cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); + } + + /* tell matcher we are inspecting packet */ + s->flags |= SIG_FLAG_MPM_PACKET; + s->mpm_pattern_id_div_8 = cd->id / 8; + s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); + if (cd->flags & DETECT_CONTENT_NEGATED) { + SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); + s->flags |= SIG_FLAG_MPM_PACKET_NEG; + } + sgh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + + /* for TCP, we have a special "stream" mpm as well */ + if (SGH_PROTO(sgh, IPPROTO_TCP) && SignatureHasStreamContent(s)) { + if (cd->flags & DETECT_CONTENT_NOCASE) { + if (SGH_DIRECTION_TS(sgh) && s->flags & SIG_FLAG_TOSERVER) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + MpmAddPatternCI(sgh->mpm_stream_ctx_ts, + cd->content + cd->fp_chop_offset, cd->fp_chop_len, + 0, 0, cd->id, s->num, 0); + } else { + MpmAddPatternCI(sgh->mpm_stream_ctx_ts, + cd->content, cd->content_len, + 0, 0, cd->id, s->num, 0); + } + } + if (SGH_DIRECTION_TC(sgh) && s->flags & SIG_FLAG_TOCLIENT) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + MpmAddPatternCI(sgh->mpm_stream_ctx_tc, + cd->content + cd->fp_chop_offset, cd->fp_chop_len, + 0, 0, cd->id, s->num, 0); + } else { + MpmAddPatternCI(sgh->mpm_stream_ctx_tc, + cd->content, cd->content_len, + 0, 0, cd->id, s->num, 0); + } + } + } else { + if (SGH_DIRECTION_TS(sgh) && s->flags & SIG_FLAG_TOSERVER) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + MpmAddPatternCS(sgh->mpm_stream_ctx_ts, + cd->content + cd->fp_chop_offset, cd->fp_chop_len, + 0, 0, cd->id, s->num, 0); + } else { + MpmAddPatternCS(sgh->mpm_stream_ctx_ts, + cd->content, cd->content_len, + 0, 0, cd->id, s->num, 0); + } + } + if (SGH_DIRECTION_TC(sgh) && s->flags & SIG_FLAG_TOCLIENT) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + MpmAddPatternCS(sgh->mpm_stream_ctx_tc, + cd->content + cd->fp_chop_offset, cd->fp_chop_len, + 0, 0, cd->id, s->num, 0); + } else { + MpmAddPatternCS(sgh->mpm_stream_ctx_tc, + cd->content, cd->content_len, + 0, 0, cd->id, s->num, 0); + } + } + } + /* tell matcher we are inspecting stream */ + s->flags |= SIG_FLAG_MPM_STREAM; + s->mpm_pattern_id_div_8 = cd->id / 8; + s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); + if (cd->flags & DETECT_CONTENT_NEGATED) { + SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); + s->flags |= SIG_FLAG_MPM_STREAM_NEG; + } + sgh->flags |= SIG_GROUP_HEAD_MPM_STREAM; + } +} + static void PopulateMpmAddPatternToMpm(const DetectEngineCtx *de_ctx, SigGroupHead *sgh, Signature *s, SigMatch *mpm_sm) @@ -1171,187 +1304,7 @@ static void PopulateMpmAddPatternToMpm(const DetectEngineCtx *de_ctx, switch (sm_list) { case DETECT_SM_LIST_PMATCH: { - cd = (DetectContentData *)mpm_sm->ctx; - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE) && - cd->content_len == cd->fp_chop_len) { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - - /* add the content to the "packet" mpm */ - if (SignatureHasPacketContent(s)) { - if (s->proto.proto[6 / 8] & 1 << (6 % 8)) { - if (s->flags & SIG_FLAG_TOSERVER) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_ts, - cd, s, flags, 1); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_tc, - cd, s, flags, 1); - } - } - if (s->proto.proto[17 / 8] & 1 << (17 % 8)) { - if (s->flags & SIG_FLAG_TOSERVER) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_ts, - cd, s, flags, 1); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_tc, - cd, s, flags, 1); - } - } - int i; - for (i = 0; i < 256; i++) { - if (i == 6 || i == 17) - continue; - if (s->proto.proto[i / 8] & (1 << (i % 8))) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_other_ctx, - cd, s, flags, 1); - break; - } - } - /* tell matcher we are inspecting packet */ - s->flags |= SIG_FLAG_MPM_PACKET; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_PACKET_NEG; - } - } - if (SignatureHasStreamContent(s)) { - if (cd->flags & DETECT_CONTENT_NOCASE) { - if (s->flags & SIG_FLAG_TOSERVER) { - MpmAddPatternCI(sgh->mpm_stream_ctx_ts, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - MpmAddPatternCI(sgh->mpm_stream_ctx_tc, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - } else { - if (s->flags & SIG_FLAG_TOSERVER) { - MpmAddPatternCS(sgh->mpm_stream_ctx_ts, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - MpmAddPatternCS(sgh->mpm_stream_ctx_tc, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - } - /* tell matcher we are inspecting stream */ - s->flags |= SIG_FLAG_MPM_STREAM; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_STREAM_NEG; - } - } - } else { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE)) { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - - if (SignatureHasPacketContent(s)) { - /* add the content to the "packet" mpm */ - if (s->proto.proto[6 / 8] & 1 << (6 % 8)) { - if (s->flags & SIG_FLAG_TOSERVER) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_ts, - cd, s, flags, 0); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_tc, - cd, s, flags, 0); - } - } - if (s->proto.proto[17 / 8] & 1 << (17 % 8)) { - if (s->flags & SIG_FLAG_TOSERVER) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_ts, - cd, s, flags, 0); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_tc, - cd, s, flags, 0); - } - } - int i; - for (i = 0; i < 256; i++) { - if (i == 6 || i == 17) - continue; - if (s->proto.proto[i / 8] & (1 << (i % 8))) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_other_ctx, - cd, s, flags, 0); - break; - } - } - /* tell matcher we are inspecting packet */ - s->flags |= SIG_FLAG_MPM_PACKET; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_PACKET_NEG; - } - } - if (SignatureHasStreamContent(s)) { - /* add the content to the "packet" mpm */ - if (cd->flags & DETECT_CONTENT_NOCASE) { - if (s->flags & SIG_FLAG_TOSERVER) { - MpmAddPatternCI(sgh->mpm_stream_ctx_ts, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - MpmAddPatternCI(sgh->mpm_stream_ctx_tc, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - } else { - if (s->flags & SIG_FLAG_TOSERVER) { - MpmAddPatternCS(sgh->mpm_stream_ctx_ts, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - MpmAddPatternCS(sgh->mpm_stream_ctx_tc, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - } - /* tell matcher we are inspecting stream */ - s->flags |= SIG_FLAG_MPM_STREAM; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_STREAM_NEG; - } - } - } - if (SignatureHasPacketContent(s)) { - sgh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - } - if (SignatureHasStreamContent(s)) { - sgh->flags |= SIG_GROUP_HEAD_MPM_STREAM; - } - + PopulateMpmAddPatternToMpmPMATCH(de_ctx, sgh, s, mpm_sm); break; } /* case DETECT_CONTENT */ @@ -1767,94 +1720,101 @@ int PatternMatchPrepareGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sh) s = sh->match_array[sig]; if (s == NULL) continue; - - if (SignatureHasPacketContent(s) == 1) { + if (!(SGH_PROTO(sh, IPPROTO_TCP)) || + (SGH_PROTO(sh, IPPROTO_TCP) && SignatureHasPacketContent(s) == 1)) + { has_co_packet = 1; } - if (SignatureHasStreamContent(s) == 1) { - has_co_stream = 1; - } - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { - has_co_uri = 1; - } + if (SGH_PROTO(sh, IPPROTO_TCP)) { + if (SignatureHasStreamContent(s) == 1) { + has_co_stream = 1; + } - if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { - has_co_hcbd = 1; - } + if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { + has_co_uri = 1; + } - if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) { - if (s->alproto == ALPROTO_SMTP) - has_co_smtp = 1; - else if (s->alproto == ALPROTO_HTTP) - has_co_hsbd = 1; - else if (s->alproto == ALPROTO_UNKNOWN) { - has_co_smtp = 1; - has_co_hsbd = 1; + if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { + has_co_hcbd = 1; } - } - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { - has_co_hhd = 1; - } + if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) { + if (s->alproto == ALPROTO_SMTP) + has_co_smtp = 1; + else if (s->alproto == ALPROTO_HTTP) + has_co_hsbd = 1; + else if (s->alproto == ALPROTO_UNKNOWN) { + has_co_smtp = 1; + has_co_hsbd = 1; + } + } - if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { - has_co_hrhd = 1; - } + if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { + has_co_hhd = 1; + } - if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { - has_co_hmd = 1; - } + if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { + has_co_hrhd = 1; + } - if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) { - has_co_hcd = 1; - } + if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { + has_co_hmd = 1; + } - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { - has_co_hrud = 1; - } + if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) { + has_co_hcd = 1; + } - if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { - has_co_hsmd = 1; - } + if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { + has_co_hrud = 1; + } - if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { - has_co_hscd = 1; - } + if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { + has_co_hsmd = 1; + } - if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { - has_co_huad = 1; - } + if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + has_co_hscd = 1; + } - if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { - has_co_hhhd = 1; - } + if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { + has_co_huad = 1; + } + + if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { + has_co_hhhd = 1; + } - if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { - has_co_hrhhd = 1; + if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { + has_co_hrhhd = 1; + } } - if (s->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH] != NULL) { - has_co_dnsquery = 1; + if (SGH_PROTO(sh, IPPROTO_TCP) || SGH_PROTO(sh, IPPROTO_UDP)) { + if (s->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH] != NULL) { + has_co_dnsquery = 1; + } } } /* intialize contexes */ if (has_co_packet) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_proto_tcp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); - sh->mpm_proto_tcp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); - } else { - sh->mpm_proto_tcp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_proto_tcp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_proto_tcp_ctx_ts == NULL || sh->mpm_proto_tcp_ctx_tc == NULL) { - SCLogDebug("sh->mpm_proto_tcp_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); + if (SGH_PROTO(sh, IPPROTO_TCP)) { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { + sh->mpm_proto_tcp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); + sh->mpm_proto_tcp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); + } else { + sh->mpm_proto_tcp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); + sh->mpm_proto_tcp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); + } + if (sh->mpm_proto_tcp_ctx_ts == NULL || sh->mpm_proto_tcp_ctx_tc == NULL) { + SCLogDebug("sh->mpm_proto_tcp_ctx == NULL. This should never happen"); + exit(EXIT_FAILURE); + } + MpmInitCtx(sh->mpm_proto_tcp_ctx_ts, de_ctx->mpm_matcher); + MpmInitCtx(sh->mpm_proto_tcp_ctx_tc, de_ctx->mpm_matcher); } - MpmInitCtx(sh->mpm_proto_tcp_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_proto_tcp_ctx_tc, de_ctx->mpm_matcher); - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_proto_udp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); sh->mpm_proto_udp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); @@ -2136,6 +2096,7 @@ int PatternMatchPrepareGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sh) has_co_hrhhd || has_co_dnsquery) { + /* add the patterns of all the rules to the mpms of this sgh */ PatternMatchPreparePopulateMpm(de_ctx, sh); if (sh->mpm_proto_tcp_ctx_ts != NULL) { diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 42f12f0cedca..f46815fa2493 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -1143,11 +1143,12 @@ void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx) } void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, - uint8_t ipproto, uint8_t dir) + uint8_t ipproto, int dir) { if (sgh && sgh->init) { + SCLogDebug("setting proto %u and dir %d on sgh %p", ipproto, dir, sgh); sgh->init->protos[ipproto] = 1; - sgh->init->direction = dir; + sgh->init->direction |= dir; } } diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index c4470c09ffe3..133051edd5d9 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -74,7 +74,7 @@ int SigGroupHeadSPortHashRemove(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid); void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx); void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, - uint8_t ipproto, uint8_t dir); + uint8_t ipproto, int dir); int SigGroupHeadBuildMatchArray (DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t max_idx); void SigGroupHeadFreeSigArrays(DetectEngineCtx *de_ctx); diff --git a/src/detect.c b/src/detect.c index d118fa73c200..ecfdca6f8ff4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2937,10 +2937,7 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 SigGroupHeadSetSigCnt(iter->sh, max_idx); SigGroupHeadBuildMatchArray(de_ctx, iter->sh, max_idx); - - /* init the pattern matcher, this will respect the copy - * setting */ - BUG_ON(PatternMatchPrepareGroup(de_ctx, iter->sh) != 0); + SigGroupHeadSetProtoAndDirection(iter->sh, ipproto, direction); SigGroupHeadHashAdd(de_ctx, iter->sh); SigGroupHeadStore(de_ctx, iter->sh); de_ctx->gh_unique++; diff --git a/src/detect.h b/src/detect.h index 01756e033577..8249b0780ab2 100644 --- a/src/detect.h +++ b/src/detect.h @@ -984,8 +984,8 @@ typedef struct SigGroupHeadInitData_ { uint8_t *sig_array; /**< bit array of sig nums (internal id's) */ uint32_t sig_size; /**< size in bytes */ - uint8_t protos[256]; - uint8_t direction; + uint8_t protos[256]; /**< proto(s) this sgh is for */ + uint32_t direction; /**< set to SIG_FLAG_TOSERVER, SIG_FLAG_TOCLIENT or both */ /* port ptr */ struct DetectPort_ *port; From eda9552e9531471b0ad5890698ee2d28ad424a6e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Sep 2015 16:46:21 +0200 Subject: [PATCH 1154/2553] detect: group proto sghs --- src/detect.c | 189 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 124 insertions(+), 65 deletions(-) diff --git a/src/detect.c b/src/detect.c index ecfdca6f8ff4..5c174e6689df 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2879,6 +2879,127 @@ static void SigParseApplyDsizeToContent(Signature *s) } } +int RulesGroupByProto(DetectEngineCtx *de_ctx) +{ + Signature *s = de_ctx->sig_list; + + uint32_t max_idx = 0; + SigGroupHead *sgh_ts[256] = {NULL}; + SigGroupHead *sgh_tc[256] = {NULL}; + + for ( ; s != NULL; s = s->next) { + if (s->flags & SIG_FLAG_IPONLY) + continue; + + int p; + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) { + continue; + } + if (!(s->proto.proto[p / 8] & (1<<(p % 8)) || (s->proto.flags & DETECT_PROTO_ANY))) { + continue; + } + + if (s->flags & SIG_FLAG_TOCLIENT) { + SigGroupHeadAppendSig(de_ctx, &sgh_tc[p], s); + max_idx = s->num; + } + if (s->flags & SIG_FLAG_TOSERVER) { + SigGroupHeadAppendSig(de_ctx, &sgh_ts[p], s); + max_idx = s->num; + } + } + } + SCLogDebug("max_idx %u", max_idx); + + /* lets look at deduplicating this list */ + SigGroupHeadHashFree(de_ctx); + SigGroupHeadHashInit(de_ctx); + + uint32_t cnt = 0; + uint32_t own = 0; + uint32_t ref = 0; + int p; + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + continue; + if (sgh_ts[p] == NULL) + continue; + + cnt++; + + SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, sgh_ts[p]); + if (lookup_sgh == NULL) { + SCLogDebug("proto group %d sgh %p is the original", p, sgh_ts[p]); + + SigGroupHeadSetSigCnt(sgh_ts[p], max_idx); + SigGroupHeadBuildMatchArray(de_ctx, sgh_ts[p], max_idx); + + SigGroupHeadHashAdd(de_ctx, sgh_ts[p]); + SigGroupHeadStore(de_ctx, sgh_ts[p]); + + de_ctx->gh_unique++; + own++; + } else { + SCLogDebug("proto group %d sgh %p is a copy", p, sgh_ts[p]); + + SigGroupHeadFree(sgh_ts[p]); + sgh_ts[p] = lookup_sgh; + sgh_ts[p]->flags |= SIG_GROUP_HEAD_REFERENCED; + + de_ctx->gh_reuse++; + ref++; + } + } + SCLogInfo("OTHER %s: %u proto groups, %u unique SGH's, %u copies", "toserver", cnt, own, ref); + + cnt = 0; + own = 0; + ref = 0; + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + continue; + if (sgh_tc[p] == NULL) + continue; + + cnt++; + + SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, sgh_tc[p]); + if (lookup_sgh == NULL) { + SCLogDebug("proto group %d sgh %p is the original", p, sgh_tc[p]); + + SigGroupHeadSetSigCnt(sgh_tc[p], max_idx); + SigGroupHeadBuildMatchArray(de_ctx, sgh_tc[p], max_idx); + + SigGroupHeadHashAdd(de_ctx, sgh_tc[p]); + SigGroupHeadStore(de_ctx, sgh_tc[p]); + + de_ctx->gh_unique++; + own++; + } else { + SCLogDebug("proto group %d sgh %p is a copy", p, sgh_tc[p]); + + SigGroupHeadFree(sgh_tc[p]); + sgh_tc[p] = lookup_sgh; + sgh_tc[p]->flags |= SIG_GROUP_HEAD_REFERENCED; + + de_ctx->gh_reuse++; + ref++; + } + } + SCLogInfo("OTHER %s: %u proto groups, %u unique SGH's, %u copies", "toclient", cnt, own, ref); + + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + continue; + + de_ctx->flow_gh[0].sgh[p] = sgh_tc[p]; + de_ctx->flow_gh[1].sgh[p] = sgh_ts[p]; + } + + return 0; +} + static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint32_t direction) { /* step 1: create a list of 'DetectPort' objects based on all the * rules. Each object will have a SGH with the sigs added @@ -3092,41 +3213,6 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) return -1; } -/** - * \brief add signature to the right flow group(s) - */ -static int DetectEngineLookupFlowAddSig(DetectEngineCtx *de_ctx, Signature *s) -{ - SCLogDebug("s->id %u", s->id); - - uint32_t cnt_ts = 0; - uint32_t cnt_tc = 0; - - int p; - for (p = 0; p < 256; p++) { - if (p == IPPROTO_TCP || p == IPPROTO_UDP) - continue; - - if (s->proto.proto[p / 8] & (1<<(p % 8)) || (s->proto.flags & DETECT_PROTO_ANY)) { - if (s->flags & SIG_FLAG_TOCLIENT) { - SigGroupHeadAppendSig(de_ctx, &de_ctx->flow_gh[0].sgh[p], s); - cnt_tc++; - } - if (s->flags & SIG_FLAG_TOSERVER) { - SigGroupHeadAppendSig(de_ctx, &de_ctx->flow_gh[1].sgh[p], s); - cnt_ts++; - } - } - } - - /* see which rules use many protos. > 2 as alert icmp actually is also icmpv6. */ - if (cnt_ts > 2 || cnt_tc > 2) { - SCLogDebug("Rule %u added to multiple proto groups (%u ts/%u tc)", s->id, cnt_ts, cnt_tc); - } - - return 0; -} - //#define SMALL_MPM(c) 0 #define SMALL_MPM(c) ((c) == 1) // || (c) == 2) @@ -3329,14 +3415,14 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) de_ctx->flow_gh[1].udp = RulesGroupByPorts(de_ctx, IPPROTO_UDP, SIG_FLAG_TOSERVER); de_ctx->flow_gh[0].udp = RulesGroupByPorts(de_ctx, IPPROTO_UDP, SIG_FLAG_TOCLIENT); + /* Setup the other IP Protocols (so not TCP/UDP) */ + RulesGroupByProto(de_ctx); + /* now for every rule add the source group to our temp lists */ for (tmp_s = de_ctx->sig_list; tmp_s != NULL; tmp_s = tmp_s->next) { SCLogDebug("tmp_s->id %"PRIu32, tmp_s->id); if (tmp_s->flags & SIG_FLAG_IPONLY) { IPOnlyAddSignature(de_ctx, &de_ctx->io_ctx, tmp_s); - } else { - /* handle non-tcp/non-udp rules */ - DetectEngineLookupFlowAddSig(de_ctx, tmp_s); } if (tmp_s->init_flags & SIG_FLAG_INIT_DEONLY) { @@ -3449,33 +3535,6 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) //SCLogInfo("sgh's %"PRIu32, de_ctx->sgh_array_cnt); uint32_t idx = 0; - - for (idx = 0; idx < 256; idx++) { - int f = 0; - for (f = 0; f <= 1; f++) { - SigGroupHead *sgh = de_ctx->flow_gh[f].sgh[idx]; - if (sgh == NULL) { - //SCLogInfo("skipped %u/%d", idx, f); - continue; - } - - uint32_t max_idx = DetectEngineGetMaxSigId(de_ctx); - SigGroupHeadSetSigCnt(sgh, max_idx); - SigGroupHeadSetProtoAndDirection(sgh, idx, - ((f == 1) ? SIG_FLAG_TOSERVER : SIG_FLAG_TOCLIENT)); - SigGroupHeadBuildMatchArray(de_ctx, sgh, max_idx); - SigGroupHeadSetFilemagicFlag(de_ctx, sgh); - SigGroupHeadSetFileMd5Flag(de_ctx, sgh); - SigGroupHeadSetFilesizeFlag(de_ctx, sgh); - SigGroupHeadSetFilestoreCount(de_ctx, sgh); - SCLogDebug("filestore count %u", sgh->filestore_cnt); - - PatternMatchPrepareGroup(de_ctx, sgh); - SigGroupHeadBuildNonMpmArray(de_ctx, sgh); - } - } - - for (idx = 0; idx < de_ctx->sgh_array_cnt; idx++) { SigGroupHead *sgh = de_ctx->sgh_array[idx]; if (sgh == NULL) From e570b10abe72b00c1768f3385cc52ae522a17de1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Sep 2015 17:40:59 +0200 Subject: [PATCH 1155/2553] detect: display unique sgh count --- src/detect.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detect.c b/src/detect.c index 5c174e6689df..8c1da4a7fe4e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3534,6 +3534,7 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) //SCLogInfo("sgh's %"PRIu32, de_ctx->sgh_array_cnt); + uint32_t cnt = 0; uint32_t idx = 0; for (idx = 0; idx < de_ctx->sgh_array_cnt; idx++) { SigGroupHead *sgh = de_ctx->sgh_array[idx]; @@ -3550,7 +3551,9 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) sgh->mpm_uricontent_minlen = SigGroupHeadGetMinMpmSize(de_ctx, sgh, DETECT_SM_LIST_UMATCH); SCLogDebug("http_uri content min mpm len: %u", sgh->mpm_uricontent_minlen); + cnt++; } + SCLogInfo("Unique rule groups: %u", cnt); if (de_ctx->decoder_event_sgh != NULL) { /* no need to set filestore count here as that would make a From a3928123029217099dd04dc1ea2d4fbf3ad6632e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Sep 2015 18:42:16 +0200 Subject: [PATCH 1156/2553] detect: sort/group port sigs --- src/detect.c | 55 +++++++++++++++++----------------------------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/src/detect.c b/src/detect.c index 8c1da4a7fe4e..41ec249bd65c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3000,6 +3000,9 @@ int RulesGroupByProto(DetectEngineCtx *de_ctx) return 0; } +int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx); +int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b); + static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint32_t direction) { /* step 1: create a list of 'DetectPort' objects based on all the * rules. Each object will have a SGH with the sigs added @@ -3040,6 +3043,12 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 s = s->next; } + SCLogDebug("rules analyzed"); + + DetectPort *newlist = NULL; + CreateGroupedPortList(de_ctx, list, &newlist, 10, CreateGroupedPortListCmpCnt, max_idx); + list = newlist; + /* step 2: deduplicate the SGH's */ SigGroupHeadHashFree(de_ctx); SigGroupHeadHashInit(de_ctx); @@ -3213,55 +3222,30 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) return -1; } -//#define SMALL_MPM(c) 0 -#define SMALL_MPM(c) ((c) == 1) -// || (c) == 2) -// || (c) == 3) - int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b) { - if (a->cnt > b->cnt) - return 1; - return 0; -} - -int CreateGroupedPortListCmpMpmMinlen(DetectPort *a, DetectPort *b) -{ - if (a->sh == NULL || b->sh == NULL) - return 0; - - if (SMALL_MPM(a->sh->mpm_content_minlen)) + if (a->sh->sig_cnt > b->sh->sig_cnt) return 1; - - if (a->sh->mpm_content_minlen < b->sh->mpm_content_minlen) - return 1; - return 0; } -static uint32_t g_groupportlist_maxgroups = 0; -static uint32_t g_groupportlist_groupscnt = 0; -static uint32_t g_groupportlist_totgroups = 0; - -int CreateGroupedPortList(DetectEngineCtx *de_ctx,HashListTable *port_hash, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx) +int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx) { DetectPort *tmplist = NULL, *tmplist2 = NULL, *joingr = NULL; char insert = 0; DetectPort *gr, *next_gr; uint32_t groups = 0; - - HashListTableBucket *htb = HashListTableGetListHead(port_hash); + DetectPort *list; /* insert the addresses into the tmplist, where it will * be sorted descending on 'cnt'. */ - for ( ; htb != NULL; htb = HashListTableGetListNext(htb)) { - gr = (DetectPort *)HashListTableGetListData(htb); + for (list = port_list; list != NULL; list = list->next) { + gr = (DetectPort *)list; SCLogDebug("hash list gr %p", gr); DetectPortPrint(gr); - if (SMALL_MPM(gr->sh->mpm_content_minlen) && unique_groups > 0) - unique_groups++; + SigGroupHeadSetSigCnt(gr->sh, max_idx); groups++; @@ -3270,6 +3254,7 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx,HashListTable *port_hash, Dete if (newtmp == NULL) { goto error; } + SigGroupHeadSetSigCnt(newtmp->sh, max_idx); /* insert it */ DetectPort *tmpgr = tmplist, *prevtmpgr = NULL; @@ -3300,12 +3285,8 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx,HashListTable *port_hash, Dete } uint32_t i = unique_groups; - if (i == 0) i = groups; - - if (unique_groups > g_groupportlist_maxgroups) - g_groupportlist_maxgroups = unique_groups; - g_groupportlist_groupscnt++; - g_groupportlist_totgroups += unique_groups; + if (i == 0) + i = groups; for (gr = tmplist; gr != NULL; ) { SCLogDebug("temp list gr %p", gr); From df529b13ce7d851ac5ba08c81afeb3e94c3fa212 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 30 Sep 2015 11:56:42 +0200 Subject: [PATCH 1157/2553] detect: change port grouping Update port grouping logic. Previously it would create one consistent list w/o overlap. It largely still does this, except for the 'catch all' port group at the end of the list. This port group contains all the sigs that didn't fit into the other groups. --- src/detect.c | 155 +++++++++++++++++++++++++++------------------------ 1 file changed, 83 insertions(+), 72 deletions(-) diff --git a/src/detect.c b/src/detect.c index 41ec249bd65c..1fdbe10812eb 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3224,137 +3224,148 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b) { - if (a->sh->sig_cnt > b->sh->sig_cnt) + if (a->sh->sig_cnt > b->sh->sig_cnt) { + SCLogDebug("pg %u:%u %u > %u:%u %u", + a->port, a->port2, a->sh->sig_cnt, + b->port, b->port2, b->sh->sig_cnt); return 1; + } return 0; } +/** \internal + * \brief Create a list of DetectPort objects sorted based on CompareFunc's + * logic. + * + * List can limit the number of groups. In this case an extra "join" group + * is created that contains the sigs belonging to that. It's *appended* to + * the list, meaning that if the list is walked linearly it's found last. + * The joingr is meant to be a catch all. + * + */ int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx) { - DetectPort *tmplist = NULL, *tmplist2 = NULL, *joingr = NULL; + DetectPort *tmplist = NULL, *joingr = NULL; char insert = 0; - DetectPort *gr, *next_gr; uint32_t groups = 0; DetectPort *list; - /* insert the addresses into the tmplist, where it will - * be sorted descending on 'cnt'. */ - for (list = port_list; list != NULL; list = list->next) { - gr = (DetectPort *)list; + /* insert the addresses into the tmplist, where it will + * be sorted descending on 'cnt' and on wehther a group + * is whitelisted. */ - SCLogDebug("hash list gr %p", gr); - DetectPortPrint(gr); - - SigGroupHeadSetSigCnt(gr->sh, max_idx); + DetectPort *oldhead = port_list; + while (oldhead) { + /* take the top of the list */ + list = oldhead; + oldhead = oldhead->next; + list->next = NULL; groups++; - /* alloc a copy */ - DetectPort *newtmp = DetectPortCopySingle(de_ctx, gr); - if (newtmp == NULL) { - goto error; - } - SigGroupHeadSetSigCnt(newtmp->sh, max_idx); + SigGroupHeadSetSigCnt(list->sh, max_idx); /* insert it */ DetectPort *tmpgr = tmplist, *prevtmpgr = NULL; if (tmplist == NULL) { /* empty list, set head */ - tmplist = newtmp; + tmplist = list; } else { /* look for the place to insert */ - for ( ; tmpgr != NULL&&!insert; tmpgr = tmpgr->next) { - if (CompareFunc(gr, tmpgr)) { + for ( ; tmpgr != NULL && !insert; tmpgr = tmpgr->next) { + if (CompareFunc(list, tmpgr) == 1) { if (tmpgr == tmplist) { - newtmp->next = tmplist; - tmplist = newtmp; + list->next = tmplist; + tmplist = list; + SCLogDebug("new list top: %u:%u", tmplist->port, tmplist->port2); } else { - newtmp->next = prevtmpgr->next; - prevtmpgr->next = newtmp; + list->next = prevtmpgr->next; + prevtmpgr->next = list; } insert = 1; + break; } prevtmpgr = tmpgr; } if (insert == 0) { - newtmp->next = NULL; - prevtmpgr->next = newtmp; + list->next = NULL; + prevtmpgr->next = list; } insert = 0; } } - uint32_t i = unique_groups; - if (i == 0) - i = groups; + uint32_t left = unique_groups; + if (left == 0) + left = groups; + /* create another list: take the port groups from above + * and add them to the 2nd list until we have met our + * count. The rest is added to the 'join' group. */ + DetectPort *tmplist2 = NULL, *tmplist2_tail = NULL; + DetectPort *gr, *next_gr; for (gr = tmplist; gr != NULL; ) { - SCLogDebug("temp list gr %p", gr); + next_gr = gr->next; + + SCLogDebug("temp list gr %p %u:%u", gr, gr->port, gr->port2); DetectPortPrint(gr); - if (i == 0) { + /* if we've set up all the unique groups, add the rest to the + * catch-all joingr */ + if (left == 0) { if (joingr == NULL) { - joingr = DetectPortCopySingle(de_ctx,gr); + DetectPortParse(de_ctx, &joingr, "0:65535"); if (joingr == NULL) { goto error; } - } else { - DetectPortJoin(de_ctx,joingr, gr); + SCLogDebug("joingr => %u-%u", joingr->port, joingr->port2); + joingr->next = NULL; } + SigGroupHeadCopySigs(de_ctx,gr->sh,&joingr->sh); + + /* when a group's sigs are added to the joingr, we can free it */ + gr->next = NULL; + DetectPortFree(gr); + gr = NULL; + + /* append */ } else { - DetectPort *newtmp = DetectPortCopySingle(de_ctx,gr); - if (newtmp == NULL) { - goto error; - } + gr->next = NULL; if (tmplist2 == NULL) { - tmplist2 = newtmp; + tmplist2 = gr; + tmplist2_tail = gr; } else { - newtmp->next = tmplist2; - tmplist2 = newtmp; + tmplist2_tail->next = gr; + tmplist2_tail = gr; } } - if (i)i--; - next_gr = gr->next; - gr->next = NULL; - DetectPortFree(gr); - gr = next_gr; - } - - /* we now have a tmplist2 containing the 'unique' groups and - * possibly a joingr that covers the rest. Now build the newhead - * that we will pass back to the caller. - * - * Start with inserting the unique groups */ - for (gr = tmplist2; gr != NULL; ) { - SCLogDebug("temp list2 gr %p", gr); - DetectPortPrint(gr); - - DetectPort *newtmp = DetectPortCopySingle(de_ctx,gr); - if (newtmp == NULL) { - goto error; - } - - int r = DetectPortInsert(de_ctx,newhead,newtmp); - BUG_ON(r == -1); + if (left > 0) + left--; - next_gr = gr->next; - gr->next = NULL; - DetectPortFree(gr); gr = next_gr; } - DetectPortPrintList(*newhead); - - /* if present, insert the joingr that covers the rest */ + /* if present, append the joingr that covers the rest */ if (joingr != NULL) { - SCLogDebug("inserting joingr %p", joingr); - DetectPortInsert(de_ctx,newhead,joingr); + SCLogDebug("appending joingr %p %u:%u", joingr, joingr->port, joingr->port2); + + if (tmplist2 == NULL) { + tmplist2 = joingr; + tmplist2_tail = joingr; + } else { + tmplist2_tail->next = joingr; + tmplist2_tail = joingr; + } } else { SCLogDebug("no joingr"); } + /* pass back our new list to the caller */ + *newhead = tmplist2; + DetectPortPrintList(*newhead); + return 0; error: return -1; From ae80ed596408ebe0cae58d73537d295ecd9de3b7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 30 Sep 2015 12:41:42 +0200 Subject: [PATCH 1158/2553] detect: make port grouping use config limits --- src/detect.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/detect.c b/src/detect.c index 1fdbe10812eb..c7d1040d7c2a 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3046,7 +3046,9 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 SCLogDebug("rules analyzed"); DetectPort *newlist = NULL; - CreateGroupedPortList(de_ctx, list, &newlist, 10, CreateGroupedPortListCmpCnt, max_idx); + uint16_t groupmax = (direction == SIG_FLAG_TOCLIENT) ? de_ctx->max_uniq_toclient_dp_groups : + de_ctx->max_uniq_toserver_dp_groups; + CreateGroupedPortList(de_ctx, list, &newlist, groupmax, CreateGroupedPortListCmpCnt, max_idx); list = newlist; /* step 2: deduplicate the SGH's */ From 1f70ccfc23cc64baee66f48d9540bc1c84da5abf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 2 Oct 2015 20:16:25 +0200 Subject: [PATCH 1159/2553] detect: remove unused grouping settings --- src/detect-engine.c | 144 +------------------------------------------- src/detect.h | 6 -- 2 files changed, 2 insertions(+), 148 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 84bd79b0167c..bc619da65c6c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1022,14 +1022,7 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) uint8_t profile = ENGINE_PROFILE_UNKNOWN; char *de_ctx_profile = NULL; - const char *max_uniq_toclient_src_groups_str = NULL; - const char *max_uniq_toclient_dst_groups_str = NULL; - const char *max_uniq_toclient_sp_groups_str = NULL; const char *max_uniq_toclient_dp_groups_str = NULL; - - const char *max_uniq_toserver_src_groups_str = NULL; - const char *max_uniq_toserver_dst_groups_str = NULL; - const char *max_uniq_toserver_sp_groups_str = NULL; const char *max_uniq_toserver_dp_groups_str = NULL; char *sgh_mpm_context = NULL; @@ -1110,87 +1103,24 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) opt = NULL; switch (profile) { case ENGINE_PROFILE_LOW: - de_ctx->max_uniq_toclient_src_groups = 2; - de_ctx->max_uniq_toclient_dst_groups = 2; - de_ctx->max_uniq_toclient_sp_groups = 2; de_ctx->max_uniq_toclient_dp_groups = 3; - de_ctx->max_uniq_toserver_src_groups = 2; - de_ctx->max_uniq_toserver_dst_groups = 2; - de_ctx->max_uniq_toserver_sp_groups = 2; de_ctx->max_uniq_toserver_dp_groups = 3; break; case ENGINE_PROFILE_HIGH: - de_ctx->max_uniq_toclient_src_groups = 15; - de_ctx->max_uniq_toclient_dst_groups = 15; - de_ctx->max_uniq_toclient_sp_groups = 15; de_ctx->max_uniq_toclient_dp_groups = 20; - de_ctx->max_uniq_toserver_src_groups = 15; - de_ctx->max_uniq_toserver_dst_groups = 15; - de_ctx->max_uniq_toserver_sp_groups = 15; de_ctx->max_uniq_toserver_dp_groups = 40; break; case ENGINE_PROFILE_CUSTOM: TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { if (strcmp(opt->val, "custom-values") == 0) { - max_uniq_toclient_src_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-src-groups"); - max_uniq_toclient_dst_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-dst-groups"); - max_uniq_toclient_sp_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-sp-groups"); max_uniq_toclient_dp_groups_str = ConfNodeLookupChildValue (opt->head.tqh_first, "toclient-dp-groups"); - max_uniq_toserver_src_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-src-groups"); - max_uniq_toserver_dst_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-dst-groups"); - max_uniq_toserver_sp_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-sp-groups"); max_uniq_toserver_dp_groups_str = ConfNodeLookupChildValue (opt->head.tqh_first, "toserver-dp-groups"); } } - if (max_uniq_toclient_src_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_src_groups, 10, - strlen(max_uniq_toclient_src_groups_str), - (const char *)max_uniq_toclient_src_groups_str) <= 0) { - de_ctx->max_uniq_toclient_src_groups = 4; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toclient-src-groups failed, using %u", - max_uniq_toclient_src_groups_str, - de_ctx->max_uniq_toclient_src_groups); - } - } else { - de_ctx->max_uniq_toclient_src_groups = 4; - } - if (max_uniq_toclient_dst_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_dst_groups, 10, - strlen(max_uniq_toclient_dst_groups_str), - (const char *)max_uniq_toclient_dst_groups_str) <= 0) { - de_ctx->max_uniq_toclient_dst_groups = 4; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toclient-dst-groups failed, using %u", - max_uniq_toclient_dst_groups_str, - de_ctx->max_uniq_toclient_dst_groups); - } - } else { - de_ctx->max_uniq_toclient_dst_groups = 4; - } - if (max_uniq_toclient_sp_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_sp_groups, 10, - strlen(max_uniq_toclient_sp_groups_str), - (const char *)max_uniq_toclient_sp_groups_str) <= 0) { - de_ctx->max_uniq_toclient_sp_groups = 4; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toclient-sp-groups failed, using %u", - max_uniq_toclient_sp_groups_str, - de_ctx->max_uniq_toclient_sp_groups); - } - } else { - de_ctx->max_uniq_toclient_sp_groups = 4; - } if (max_uniq_toclient_dp_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_dp_groups, 10, strlen(max_uniq_toclient_dp_groups_str), @@ -1204,45 +1134,6 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) } else { de_ctx->max_uniq_toclient_dp_groups = 6; } - if (max_uniq_toserver_src_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_src_groups, 10, - strlen(max_uniq_toserver_src_groups_str), - (const char *)max_uniq_toserver_src_groups_str) <= 0) { - de_ctx->max_uniq_toserver_src_groups = 4; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toserver-src-groups failed, using %u", - max_uniq_toserver_src_groups_str, - de_ctx->max_uniq_toserver_src_groups); - } - } else { - de_ctx->max_uniq_toserver_src_groups = 4; - } - if (max_uniq_toserver_dst_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_dst_groups, 10, - strlen(max_uniq_toserver_dst_groups_str), - (const char *)max_uniq_toserver_dst_groups_str) <= 0) { - de_ctx->max_uniq_toserver_dst_groups = 8; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toserver-dst-groups failed, using %u", - max_uniq_toserver_dst_groups_str, - de_ctx->max_uniq_toserver_dst_groups); - } - } else { - de_ctx->max_uniq_toserver_dst_groups = 8; - } - if (max_uniq_toserver_sp_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_sp_groups, 10, - strlen(max_uniq_toserver_sp_groups_str), - (const char *)max_uniq_toserver_sp_groups_str) <= 0) { - de_ctx->max_uniq_toserver_sp_groups = 4; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toserver-sp-groups failed, using %u", - max_uniq_toserver_sp_groups_str, - de_ctx->max_uniq_toserver_sp_groups); - } - } else { - de_ctx->max_uniq_toserver_sp_groups = 4; - } if (max_uniq_toserver_dp_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_dp_groups, 10, strlen(max_uniq_toserver_dp_groups_str), @@ -1262,14 +1153,7 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) case ENGINE_PROFILE_MEDIUM: case ENGINE_PROFILE_UNKNOWN: default: - de_ctx->max_uniq_toclient_src_groups = 4; - de_ctx->max_uniq_toclient_dst_groups = 4; - de_ctx->max_uniq_toclient_sp_groups = 4; de_ctx->max_uniq_toclient_dp_groups = 6; - - de_ctx->max_uniq_toserver_src_groups = 4; - de_ctx->max_uniq_toserver_dst_groups = 8; - de_ctx->max_uniq_toserver_sp_groups = 4; de_ctx->max_uniq_toserver_dp_groups = 30; break; } @@ -3252,13 +3136,7 @@ static int DetectEngineTest08(void) "detect-engine:\n" " - profile: custom\n" " - custom-values:\n" - " toclient-src-groups: 20\n" - " toclient-dst-groups: 21\n" - " toclient-sp-groups: 22\n" " toclient-dp-groups: 23\n" - " toserver-src-groups: 24\n" - " toserver-dst-groups: 25\n" - " toserver-sp-groups: 26\n" " toserver-dp-groups: 27\n"; DetectEngineCtx *de_ctx = NULL; @@ -3270,13 +3148,7 @@ static int DetectEngineTest08(void) if (de_ctx == NULL) goto end; - if (de_ctx->max_uniq_toclient_src_groups == 20 && - de_ctx->max_uniq_toclient_dst_groups == 21 && - de_ctx->max_uniq_toclient_sp_groups == 22 && - de_ctx->max_uniq_toclient_dp_groups == 23 && - de_ctx->max_uniq_toserver_src_groups == 24 && - de_ctx->max_uniq_toserver_dst_groups == 25 && - de_ctx->max_uniq_toserver_sp_groups == 26 && + if (de_ctx->max_uniq_toclient_dp_groups == 23 && de_ctx->max_uniq_toserver_dp_groups == 27) result = 1; @@ -3298,13 +3170,7 @@ static int DetectEngineTest09(void) "detect-engine:\n" " - profile: custom\n" " - custom-values:\n" - " toclient-src-groups: BA\n" - " toclient-dst-groups: BA\n" - " toclient-sp-groups: BA\n" " toclient-dp-groups: BA\n" - " toserver-src-groups: BA\n" - " toserver-dst-groups: BA\n" - " toserver-sp-groups: BA\n" " toserver-dp-groups: BA\n" " - inspection-recursion-limit: 10\n"; @@ -3317,13 +3183,7 @@ static int DetectEngineTest09(void) if (de_ctx == NULL) goto end; - if (de_ctx->max_uniq_toclient_src_groups == 4 && - de_ctx->max_uniq_toclient_dst_groups == 4 && - de_ctx->max_uniq_toclient_sp_groups == 4 && - de_ctx->max_uniq_toclient_dp_groups == 6 && - de_ctx->max_uniq_toserver_src_groups == 4 && - de_ctx->max_uniq_toserver_dst_groups == 8 && - de_ctx->max_uniq_toserver_sp_groups == 4 && + if (de_ctx->max_uniq_toclient_dp_groups == 6 && de_ctx->max_uniq_toserver_dp_groups == 30) result = 1; diff --git a/src/detect.h b/src/detect.h index 8249b0780ab2..545efba70989 100644 --- a/src/detect.h +++ b/src/detect.h @@ -630,14 +630,8 @@ typedef struct DetectEngineCtx_ { /* 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; /* specify the configuration for mpm context factory */ From 2ee9bf2aef46856d74d4b1a3dcc1b0ff7f5fd23c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 2 Oct 2015 20:23:50 +0200 Subject: [PATCH 1160/2553] detect: rename groupings vars --- src/detect-engine.c | 76 ++++++++++++++++++++++----------------------- src/detect.c | 4 +-- src/detect.h | 5 ++- 3 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index bc619da65c6c..af3343c97383 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1022,8 +1022,8 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) uint8_t profile = ENGINE_PROFILE_UNKNOWN; char *de_ctx_profile = NULL; - const char *max_uniq_toclient_dp_groups_str = NULL; - const char *max_uniq_toserver_dp_groups_str = NULL; + const char *max_uniq_toclient_groups_str = NULL; + const char *max_uniq_toserver_groups_str = NULL; char *sgh_mpm_context = NULL; @@ -1103,49 +1103,49 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) opt = NULL; switch (profile) { case ENGINE_PROFILE_LOW: - de_ctx->max_uniq_toclient_dp_groups = 3; - de_ctx->max_uniq_toserver_dp_groups = 3; + de_ctx->max_uniq_toclient_groups = 3; + de_ctx->max_uniq_toserver_groups = 3; break; case ENGINE_PROFILE_HIGH: - de_ctx->max_uniq_toclient_dp_groups = 20; - de_ctx->max_uniq_toserver_dp_groups = 40; + de_ctx->max_uniq_toclient_groups = 20; + de_ctx->max_uniq_toserver_groups = 40; break; case ENGINE_PROFILE_CUSTOM: TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { if (strcmp(opt->val, "custom-values") == 0) { - max_uniq_toclient_dp_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-dp-groups"); - max_uniq_toserver_dp_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-dp-groups"); + max_uniq_toclient_groups_str = ConfNodeLookupChildValue + (opt->head.tqh_first, "toclient-groups"); + max_uniq_toserver_groups_str = ConfNodeLookupChildValue + (opt->head.tqh_first, "toserver-groups"); } } - if (max_uniq_toclient_dp_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_dp_groups, 10, - strlen(max_uniq_toclient_dp_groups_str), - (const char *)max_uniq_toclient_dp_groups_str) <= 0) { - de_ctx->max_uniq_toclient_dp_groups = 6; + if (max_uniq_toclient_groups_str != NULL) { + if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_groups, 10, + strlen(max_uniq_toclient_groups_str), + (const char *)max_uniq_toclient_groups_str) <= 0) { + de_ctx->max_uniq_toclient_groups = 6; SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toclient-dp-groups failed, using %u", - max_uniq_toclient_dp_groups_str, - de_ctx->max_uniq_toclient_dp_groups); + "toclient-groups failed, using %u", + max_uniq_toclient_groups_str, + de_ctx->max_uniq_toclient_groups); } } else { - de_ctx->max_uniq_toclient_dp_groups = 6; + de_ctx->max_uniq_toclient_groups = 6; } - if (max_uniq_toserver_dp_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_dp_groups, 10, - strlen(max_uniq_toserver_dp_groups_str), - (const char *)max_uniq_toserver_dp_groups_str) <= 0) { - de_ctx->max_uniq_toserver_dp_groups = 30; + if (max_uniq_toserver_groups_str != NULL) { + if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_groups, 10, + strlen(max_uniq_toserver_groups_str), + (const char *)max_uniq_toserver_groups_str) <= 0) { + de_ctx->max_uniq_toserver_groups = 30; SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toserver-dp-groups failed, using %u", - max_uniq_toserver_dp_groups_str, - de_ctx->max_uniq_toserver_dp_groups); + "toserver-groups failed, using %u", + max_uniq_toserver_groups_str, + de_ctx->max_uniq_toserver_groups); } } else { - de_ctx->max_uniq_toserver_dp_groups = 30; + de_ctx->max_uniq_toserver_groups = 30; } break; @@ -1153,8 +1153,8 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) case ENGINE_PROFILE_MEDIUM: case ENGINE_PROFILE_UNKNOWN: default: - de_ctx->max_uniq_toclient_dp_groups = 6; - de_ctx->max_uniq_toserver_dp_groups = 30; + de_ctx->max_uniq_toclient_groups = 6; + de_ctx->max_uniq_toserver_groups = 30; break; } @@ -3136,8 +3136,8 @@ static int DetectEngineTest08(void) "detect-engine:\n" " - profile: custom\n" " - custom-values:\n" - " toclient-dp-groups: 23\n" - " toserver-dp-groups: 27\n"; + " toclient-groups: 23\n" + " toserver-groups: 27\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3148,8 +3148,8 @@ static int DetectEngineTest08(void) if (de_ctx == NULL) goto end; - if (de_ctx->max_uniq_toclient_dp_groups == 23 && - de_ctx->max_uniq_toserver_dp_groups == 27) + if (de_ctx->max_uniq_toclient_groups == 23 && + de_ctx->max_uniq_toserver_groups == 27) result = 1; end: @@ -3170,8 +3170,8 @@ static int DetectEngineTest09(void) "detect-engine:\n" " - profile: custom\n" " - custom-values:\n" - " toclient-dp-groups: BA\n" - " toserver-dp-groups: BA\n" + " toclient-groups: BA\n" + " toserver-groups: BA\n" " - inspection-recursion-limit: 10\n"; DetectEngineCtx *de_ctx = NULL; @@ -3183,8 +3183,8 @@ static int DetectEngineTest09(void) if (de_ctx == NULL) goto end; - if (de_ctx->max_uniq_toclient_dp_groups == 6 && - de_ctx->max_uniq_toserver_dp_groups == 30) + if (de_ctx->max_uniq_toclient_groups == 6 && + de_ctx->max_uniq_toserver_groups == 30) result = 1; end: diff --git a/src/detect.c b/src/detect.c index c7d1040d7c2a..1907f0de109e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3046,8 +3046,8 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 SCLogDebug("rules analyzed"); DetectPort *newlist = NULL; - uint16_t groupmax = (direction == SIG_FLAG_TOCLIENT) ? de_ctx->max_uniq_toclient_dp_groups : - de_ctx->max_uniq_toserver_dp_groups; + uint16_t groupmax = (direction == SIG_FLAG_TOCLIENT) ? de_ctx->max_uniq_toclient_groups : + de_ctx->max_uniq_toserver_groups; CreateGroupedPortList(de_ctx, list, &newlist, groupmax, CreateGroupedPortListCmpCnt, max_idx); list = newlist; diff --git a/src/detect.h b/src/detect.h index 545efba70989..9f9389948f3c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -630,9 +630,8 @@ typedef struct DetectEngineCtx_ { /* Config options */ - uint16_t max_uniq_toclient_dp_groups; - - uint16_t max_uniq_toserver_dp_groups; + uint16_t max_uniq_toclient_groups; + uint16_t max_uniq_toserver_groups; /* specify the configuration for mpm context factory */ uint8_t sgh_mpm_context; From 10b049304f36f55536b28ffb30c818f6ae795ce1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 2 Oct 2015 20:29:55 +0200 Subject: [PATCH 1161/2553] detect: set new defaults for grouping --- src/detect-engine.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index af3343c97383..f61c0c347c4f 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1103,13 +1103,13 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) opt = NULL; switch (profile) { case ENGINE_PROFILE_LOW: - de_ctx->max_uniq_toclient_groups = 3; - de_ctx->max_uniq_toserver_groups = 3; + de_ctx->max_uniq_toclient_groups = 15; + de_ctx->max_uniq_toserver_groups = 25; break; case ENGINE_PROFILE_HIGH: - de_ctx->max_uniq_toclient_groups = 20; - de_ctx->max_uniq_toserver_groups = 40; + de_ctx->max_uniq_toclient_groups = 75; + de_ctx->max_uniq_toserver_groups = 75; break; case ENGINE_PROFILE_CUSTOM: @@ -1124,28 +1124,32 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) if (max_uniq_toclient_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_groups, 10, strlen(max_uniq_toclient_groups_str), - (const char *)max_uniq_toclient_groups_str) <= 0) { - de_ctx->max_uniq_toclient_groups = 6; + (const char *)max_uniq_toclient_groups_str) <= 0) + { + de_ctx->max_uniq_toclient_groups = 20; + SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " "toclient-groups failed, using %u", max_uniq_toclient_groups_str, de_ctx->max_uniq_toclient_groups); } } else { - de_ctx->max_uniq_toclient_groups = 6; + de_ctx->max_uniq_toclient_groups = 20; } if (max_uniq_toserver_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_groups, 10, strlen(max_uniq_toserver_groups_str), - (const char *)max_uniq_toserver_groups_str) <= 0) { - de_ctx->max_uniq_toserver_groups = 30; + (const char *)max_uniq_toserver_groups_str) <= 0) + { + de_ctx->max_uniq_toserver_groups = 40; + SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " "toserver-groups failed, using %u", max_uniq_toserver_groups_str, de_ctx->max_uniq_toserver_groups); } } else { - de_ctx->max_uniq_toserver_groups = 30; + de_ctx->max_uniq_toserver_groups = 40; } break; @@ -1153,8 +1157,8 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) case ENGINE_PROFILE_MEDIUM: case ENGINE_PROFILE_UNKNOWN: default: - de_ctx->max_uniq_toclient_groups = 6; - de_ctx->max_uniq_toserver_groups = 30; + de_ctx->max_uniq_toclient_groups = 20; + de_ctx->max_uniq_toserver_groups = 40; break; } @@ -3183,8 +3187,8 @@ static int DetectEngineTest09(void) if (de_ctx == NULL) goto end; - if (de_ctx->max_uniq_toclient_groups == 6 && - de_ctx->max_uniq_toserver_groups == 30) + if (de_ctx->max_uniq_toclient_groups == 20 && + de_ctx->max_uniq_toserver_groups == 40) result = 1; end: From f0ba00e51dfdb0f3fd0df78cd065183e8f94ed22 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 3 Oct 2015 17:02:30 +0200 Subject: [PATCH 1162/2553] detect: remove old unused code --- src/detect-content.c | 6 - src/detect-engine-mpm.c | 159 -------- src/detect-engine-port.c | 191 ---------- src/detect-engine-siggroup.c | 697 ----------------------------------- src/detect-engine-siggroup.h | 19 - src/detect-engine.c | 15 - src/detect-uricontent.c | 9 - src/detect.c | 4 - src/detect.h | 10 - 9 files changed, 1110 deletions(-) diff --git a/src/detect-content.c b/src/detect-content.c index e49efd5728e5..83091886674b 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -65,12 +65,6 @@ void DetectContentRegister (void) sigmatch_table[DETECT_CONTENT].flags |= SIGMATCH_PAYLOAD; } -/* pass on the content_max_id */ -uint32_t DetectContentMaxId(DetectEngineCtx *de_ctx) -{ - return MpmPatternIdStoreGetMaxId(de_ctx->mpm_pattern_id_store); -} - /** * \brief Parse a content string, ie "abc|DE|fgh" * diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 3ccfc5d8e890..d678e9aa9f5b 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -2459,165 +2459,6 @@ int PatternMatchPrepareGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sh) return 0; } -/** \brief Pattern ID Hash for sharing pattern id's - * - * A per detection engine hash to make sure each pattern has a unique - * global id but patterns that are the same share id's. - */ -typedef struct MpmPatternIdTableElmt_ { - uint8_t *pattern; /**< ptr to the pattern */ - uint16_t pattern_len; /**< pattern len */ - PatIntId id; /**< pattern id */ - uint32_t dup_count; /**< duplicate count */ - int sm_list; /**< SigMatch list */ -} MpmPatternIdTableElmt; - -/** \brief Hash compare func for MpmPatternId api - * \retval 1 patterns are the same - * \retval 0 patterns are not the same - **/ -static char MpmPatternIdCompare(void *p1, uint16_t len1, void *p2, uint16_t len2) -{ - SCEnter(); - BUG_ON(len1 < sizeof(MpmPatternIdTableElmt)); - BUG_ON(len2 < sizeof(MpmPatternIdTableElmt)); - - MpmPatternIdTableElmt *e1 = (MpmPatternIdTableElmt *)p1; - MpmPatternIdTableElmt *e2 = (MpmPatternIdTableElmt *)p2; - - if (e1->pattern_len != e2->pattern_len || - e1->sm_list != e2->sm_list) { - SCReturnInt(0); - } - - if (SCMemcmp(e1->pattern, e2->pattern, e1->pattern_len) != 0) { - SCReturnInt(0); - } - - SCReturnInt(1); -} - -/** \brief Hash func for MpmPatternId api - * \retval hash hash value - */ -static uint32_t MpmPatternIdHashFunc(HashTable *ht, void *p, uint16_t len) -{ - SCEnter(); - BUG_ON(len < sizeof(MpmPatternIdTableElmt)); - - MpmPatternIdTableElmt *e = (MpmPatternIdTableElmt *)p; - uint32_t hash = e->pattern_len; - uint16_t u = 0; - - for (u = 0; u < e->pattern_len; u++) { - hash += e->pattern[u]; - } - - SCReturnUInt(hash % ht->array_size); -} - -/** \brief free a MpmPatternIdTableElmt */ -static void MpmPatternIdTableElmtFree(void *e) -{ - SCEnter(); - MpmPatternIdTableElmt *c = (MpmPatternIdTableElmt *)e; - SCFree(c->pattern); - SCFree(c); - SCReturn; -} - -/** \brief alloc initialize the MpmPatternIdHash */ -MpmPatternIdStore *MpmPatternIdTableInitHash(void) -{ - SCEnter(); - - MpmPatternIdStore *ht = SCMalloc(sizeof(MpmPatternIdStore)); - BUG_ON(ht == NULL); - memset(ht, 0x00, sizeof(MpmPatternIdStore)); - - ht->hash = HashTableInit(65536, MpmPatternIdHashFunc, MpmPatternIdCompare, MpmPatternIdTableElmtFree); - BUG_ON(ht->hash == NULL); - - SCReturnPtr(ht, "MpmPatternIdStore"); -} - -void MpmPatternIdTableFreeHash(MpmPatternIdStore *ht) -{ - SCEnter(); - - if (ht == NULL) { - SCReturn; - } - - if (ht->hash != NULL) { - HashTableFree(ht->hash); - } - - SCFree(ht); - SCReturn; -} - -uint32_t MpmPatternIdStoreGetMaxId(MpmPatternIdStore *ht) -{ - if (ht == NULL) { - return 0; - } - - return ht->max_id; -} - -/** - * \brief Get the pattern id for a content pattern - * - * \param ht mpm pattern id hash table store - * \param co content pattern data - * - * \retval id pattern id - * \initonly - */ -uint32_t DetectContentGetId(MpmPatternIdStore *ht, DetectContentData *co) -{ - SCEnter(); - - BUG_ON(ht == NULL || ht->hash == NULL); - - MpmPatternIdTableElmt *e = NULL; - MpmPatternIdTableElmt *r = NULL; - uint32_t id = 0; - - e = SCMalloc(sizeof(MpmPatternIdTableElmt)); - BUG_ON(e == NULL); - memset(e, 0, sizeof(MpmPatternIdTableElmt)); - e->pattern = SCMalloc(co->content_len); - BUG_ON(e->pattern == NULL); - memcpy(e->pattern, co->content, co->content_len); - e->pattern_len = co->content_len; - e->id = 0; - - r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt)); - if (r == NULL) { - e->id = ht->max_id; - ht->max_id++; - id = e->id; - - int ret = HashTableAdd(ht->hash, e, sizeof(MpmPatternIdTableElmt)); - BUG_ON(ret != 0); - - e = NULL; - - ht->unique_patterns++; - } else { - id = r->id; - - ht->shared_patterns++; - } - - if (e != NULL) - MpmPatternIdTableElmtFree(e); - - SCReturnUInt(id); -} - typedef struct DetectFPAndItsId_ { PatIntId id; uint16_t content_len; diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index 2585e6bdbef5..ac530f1d9884 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -1534,197 +1534,6 @@ int DetectPortIsValidRange(char *port) } /********************** End parsing routines ********************/ - -/********************* Hash function routines *******************/ -#define PORT_HASH_SIZE 1024 - -/** - * \brief Generate a hash for a DetectPort group - * - * \param ht HashListTable - * \param data Pointer to the DetectPort - * \param datalen sizeof data (not used here atm) - * - * \retval uint32_t the value of the generated hash - */ -uint32_t DetectPortHashFunc(HashListTable *ht, void *data, uint16_t datalen) -{ - DetectPort *p = (DetectPort *)data; - uint32_t hash = p->port * p->port2; - - return hash % ht->array_size; -} - -/** - * \brief Function that return if the two DetectPort groups are equal or not - * - * \param data1 Pointer to the DetectPort 1 - * \param len1 sizeof data 1 (not used here atm) - * \param data2 Pointer to the DetectPort 2 - * \param len2 sizeof data 2 (not used here atm) - * - * \retval 1 if the DetectPort groups are equal - * \retval 0 if not equal - */ -char DetectPortCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) -{ - DetectPort *p1 = (DetectPort *)data1; - DetectPort *p2 = (DetectPort *)data2; - - if (p1->port2 == p2->port2 && p1->port == p2->port && - p1->flags == p2->flags) - return 1; - - return 0; -} - -void DetectPortFreeFunc(void *p) -{ - DetectPort *dp = (DetectPort *)p; - DetectPortFree(dp); -} - -/** - * \brief Function that initialize the HashListTable of destination DetectPort - * - * \param de_ctx Pointer to the current DetectionEngineContext - * - * \retval 0 HashListTable initialization succes - * \retval -1 Error - */ -int DetectPortDpHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->dport_hash_table = HashListTableInit(PORT_HASH_SIZE, - DetectPortHashFunc, DetectPortCompareFunc, DetectPortFreeFunc); - if (de_ctx->dport_hash_table == NULL) - goto error; - - return 0; -error: - return -1; -} - -/** - * \brief Function that free the HashListTable of destination DetectPort - * - * \param de_ctx Pointer to the current DetectionEngineCtx - */ -void DetectPortDpHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->dport_hash_table == NULL) - return; - - HashListTableFree(de_ctx->dport_hash_table); - de_ctx->dport_hash_table = NULL; -} - -/** - * \brief Function that reset the HashListTable of destination DetectPort - * (Free and Initialize it) - * - * \param de_ctx Pointer to the current DetectionEngineCtx - */ -void DetectPortDpHashReset(DetectEngineCtx *de_ctx) -{ - DetectPortDpHashFree(de_ctx); - DetectPortDpHashInit(de_ctx); -} - -/** - * \brief Function that add a destination DetectPort into the hashtable - * - * \param de_ctx Pointer to the current DetectionEngineCtx - * \param p Pointer to the DetectPort to add - */ -int DetectPortDpHashAdd(DetectEngineCtx *de_ctx, DetectPort *p) -{ - return HashListTableAdd(de_ctx->dport_hash_table, (void *)p, 0); -} - -/** - * \brief Function that search a destination DetectPort in the hashtable - * - * \param de_ctx Pointer to the current DetectionEngineCtx - * \param p Pointer to the DetectPort to search - */ -DetectPort *DetectPortDpHashLookup(DetectEngineCtx *de_ctx, DetectPort *p) -{ - DetectPort *rp = HashListTableLookup(de_ctx->dport_hash_table, - (void *)p, 0); - return rp; -} - -/** - * \brief Function that initialize the HashListTable of source DetectPort - * - * \param de_ctx Pointer to the current DetectionEngineContext - * - * \retval 0 HashListTable initialization succes - * \retval -1 Error - */ -int DetectPortSpHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sport_hash_table = HashListTableInit(PORT_HASH_SIZE, - DetectPortHashFunc, DetectPortCompareFunc, DetectPortFreeFunc); - if (de_ctx->sport_hash_table == NULL) - goto error; - - return 0; -error: - return -1; -} - -/** - * \brief Function that free the HashListTable of source DetectPort - * - * \param de_ctx Pointer to the current DetectionEngineCtx - */ -void DetectPortSpHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->sport_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sport_hash_table); - de_ctx->sport_hash_table = NULL; -} - -/** - * \brief Function that reset the HashListTable of source DetectPort - * (Free and Initialize it) - * - * \param de_ctx Pointer to the current DetectionEngineCtx - */ -void DetectPortSpHashReset(DetectEngineCtx *de_ctx) -{ - DetectPortSpHashFree(de_ctx); - DetectPortSpHashInit(de_ctx); -} - -/** - * \brief Function that add a source DetectPort into the hashtable - * - * \param de_ctx Pointer to the current DetectionEngineCtx - * \param p Pointer to the DetectPort to add - */ -int DetectPortSpHashAdd(DetectEngineCtx *de_ctx, DetectPort *p) -{ - return HashListTableAdd(de_ctx->sport_hash_table, (void *)p, 0); -} - -/** - * \brief Function that search a source DetectPort in the hashtable - * - * \param de_ctx Pointer to the current DetectionEngineCtx - * \param p Pointer to the DetectPort to search - */ -DetectPort *DetectPortSpHashLookup(DetectEngineCtx *de_ctx, DetectPort *p) -{ - DetectPort *rp = HashListTableLookup(de_ctx->sport_hash_table, - (void *)p, 0); - return rp; -} - /*---------------------- Unittests -------------------------*/ #ifdef UNITTESTS diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index f46815fa2493..fd2f404bd420 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -68,16 +68,6 @@ static uint32_t detect_siggroup_matcharray_free_cnt = 0; void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid) { - if (sghid->content_array != NULL) { - SCFree(sghid->content_array); - sghid->content_array = NULL; - sghid->content_size = 0; - } - if (sghid->uri_content_array != NULL) { - SCFree(sghid->uri_content_array); - sghid->uri_content_array = NULL; - sghid->uri_content_size = 0; - } if (sghid->sig_array != NULL) { SCFree(sghid->sig_array); sghid->sig_array = NULL; @@ -340,258 +330,6 @@ void SigGroupHeadMpmHashFree(DetectEngineCtx *de_ctx) return; } -/** - * \brief The hash function to be the used by the mpm uri SigGroupHead hash - * table - DetectEngineCtx->sgh_mpm_uri_hash_table. - * - * \param ht Pointer to the hash table. - * \param data Pointer to the SigGroupHead. - * \param datalen Not used in our case. - * - * \retval hash The generated hash value. - */ -uint32_t SigGroupHeadMpmUriHashFunc(HashListTable *ht, void *data, uint16_t datalen) -{ - SigGroupHead *sgh = (SigGroupHead *)data; - uint32_t hash = 0; - uint32_t b = 0; - - for (b = 0; b < sgh->init->uri_content_size; b++) - hash += sgh->init->uri_content_array[b]; - - return hash % ht->array_size; -} - -/** - * \brief The Compare function to be used by the mpm uri SigGroupHead hash - * table - DetectEngineCtx->sgh_mpm_uri_hash_table. - * - * \param data1 Pointer to the first SigGroupHead. - * \param len1 Not used. - * \param data2 Pointer to the second SigGroupHead. - * \param len2 Not used. - * - * \retval 1 If the 2 SigGroupHeads sent as args match. - * \retval 0 If the 2 SigGroupHeads sent as args do not match. - */ -char SigGroupHeadMpmUriCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) -{ - SigGroupHead *sgh1 = (SigGroupHead *)data1; - SigGroupHead *sgh2 = (SigGroupHead *)data2; - - if (sgh1->init->uri_content_size != sgh2->init->uri_content_size) - return 0; - - if (SCMemcmp(sgh1->init->uri_content_array, sgh2->init->uri_content_array, - sgh1->init->uri_content_size) != 0) { - return 0; - } - - return 1; -} - -/** - * \brief Initializes the mpm uri hash table to be used by the detection engine - * context. - * - * \param de_ctx Pointer to the detection engine context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadMpmUriHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sgh_mpm_uri_hash_table = HashListTableInit(4096, - SigGroupHeadMpmUriHashFunc, - SigGroupHeadMpmUriCompareFunc, - NULL); - if (de_ctx->sgh_mpm_uri_hash_table == NULL) - goto error; - - return 0; - -error: - return -1; -} - -/** - * \brief Adds a SigGroupHead to the detection engine context SigGroupHead - * mpm uri hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. - */ -int SigGroupHeadMpmUriHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - int ret = HashListTableAdd(de_ctx->sgh_mpm_uri_hash_table, (void *)sgh, 0); - - return ret; -} - -/** - * \brief Used to lookup a SigGroupHead from the detection engine context - * SigGroupHead mpm uri hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is - * found in the hash table; NULL on failure. - */ -SigGroupHead *SigGroupHeadMpmUriHashLookup(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_mpm_uri_hash_table, - (void *)sgh, 0); - - return rsgh; -} - -/** - * \brief Frees the hash table - DetectEngineCtx->sgh_mpm_uri_hash_table, - * allocated by SigGroupHeadMpmUriHashInit() function. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadMpmUriHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->sgh_mpm_uri_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sgh_mpm_uri_hash_table); - de_ctx->sgh_mpm_uri_hash_table = NULL; - - return; -} - -/** - * \brief The hash function to be the used by the mpm uri SigGroupHead hash - * table - DetectEngineCtx->sgh_mpm_uri_hash_table. - * - * \param ht Pointer to the hash table. - * \param data Pointer to the SigGroupHead. - * \param datalen Not used in our case. - * - * \retval hash The generated hash value. - */ -uint32_t SigGroupHeadMpmStreamHashFunc(HashListTable *ht, void *data, uint16_t datalen) -{ - SigGroupHead *sgh = (SigGroupHead *)data; - uint32_t hash = 0; - uint32_t b = 0; - - for (b = 0; b < sgh->init->stream_content_size; b++) - hash += sgh->init->stream_content_array[b]; - - return hash % ht->array_size; -} - -/** - * \brief The Compare function to be used by the mpm uri SigGroupHead hash - * table - DetectEngineCtx->sgh_mpm_uri_hash_table. - * - * \param data1 Pointer to the first SigGroupHead. - * \param len1 Not used. - * \param data2 Pointer to the second SigGroupHead. - * \param len2 Not used. - * - * \retval 1 If the 2 SigGroupHeads sent as args match. - * \retval 0 If the 2 SigGroupHeads sent as args do not match. - */ -char SigGroupHeadMpmStreamCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) -{ - SigGroupHead *sgh1 = (SigGroupHead *)data1; - SigGroupHead *sgh2 = (SigGroupHead *)data2; - - if (sgh1->init->stream_content_size != sgh2->init->stream_content_size) - return 0; - - if (SCMemcmp(sgh1->init->stream_content_array, sgh2->init->stream_content_array, - sgh1->init->stream_content_size) != 0) { - return 0; - } - - return 1; -} - -/** - * \brief Initializes the mpm uri hash table to be used by the detection engine - * context. - * - * \param de_ctx Pointer to the detection engine context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadMpmStreamHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sgh_mpm_stream_hash_table = HashListTableInit(4096, - SigGroupHeadMpmStreamHashFunc, SigGroupHeadMpmStreamCompareFunc, NULL); - if (de_ctx->sgh_mpm_stream_hash_table == NULL) - goto error; - - return 0; - -error: - return -1; -} - -/** - * \brief Adds a SigGroupHead to the detection engine context SigGroupHead - * mpm uri hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. - */ -int SigGroupHeadMpmStreamHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - int ret = HashListTableAdd(de_ctx->sgh_mpm_stream_hash_table, (void *)sgh, 0); - - return ret; -} - -/** - * \brief Used to lookup a SigGroupHead from the detection engine context - * SigGroupHead mpm uri hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is - * found in the hash table; NULL on failure. - */ -SigGroupHead *SigGroupHeadMpmStreamHashLookup(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_mpm_stream_hash_table, - (void *)sgh, 0); - - return rsgh; -} - -/** - * \brief Frees the hash table - DetectEngineCtx->sgh_mpm_uri_hash_table, - * allocated by SigGroupHeadMpmUriHashInit() function. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadMpmStreamHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->sgh_mpm_stream_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sgh_mpm_stream_hash_table); - de_ctx->sgh_mpm_stream_hash_table = NULL; - - return; -} - /** * \brief The hash function to be the used by the hash table - * DetectEngineCtx->sgh_hash_table. @@ -806,88 +544,6 @@ void SigGroupHeadDPortHashFree(DetectEngineCtx *de_ctx) return; } -/** - * \brief Initializes the sport based SigGroupHead hash table to hold the - * SigGroupHeads. The hash table that would be initialized is - * DetectEngineCtx->sgh_sport_hash_table. - * - * \param de_ctx Pointer to the detection engine context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadSPortHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sgh_sport_hash_table = HashListTableInit(4096, - SigGroupHeadHashFunc, - SigGroupHeadCompareFunc, - NULL); - if (de_ctx->sgh_sport_hash_table == NULL) - goto error; - - return 0; - -error: - return -1; -} - -/** - * \brief Adds a SigGroupHead to the detection engine context dport based - * SigGroupHead hash table(DetectEngineCtx->sgh_sport_hash_table). - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. - */ -int SigGroupHeadSPortHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - int ret = HashListTableAdd(de_ctx->sgh_sport_hash_table, (void *)sgh, 0); - - return ret; -} - -int SigGroupHeadSPortHashRemove(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - return HashListTableRemove(de_ctx->sgh_sport_hash_table, (void *)sgh, 0); -} - -/** - * \brief Used to lookup a SigGroupHead hash from the detection engine ctx sport - * based SigGroupHead hash table(DetectEngineCtx->sgh_dport_hash_table). - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is - * found in the hash table; NULL on failure. - */ -SigGroupHead *SigGroupHeadSPortHashLookup(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_sport_hash_table, - (void *)sgh, 0); - - return rsgh; -} - -/** - * \brief Frees the hash table - DetectEngineCtx->sgh_sport_hash_table, - * allocated by the SigGroupHeadSPortHashInit() function. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadSPortHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->sgh_sport_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sgh_sport_hash_table); - de_ctx->sgh_sport_hash_table = NULL; - - return; -} - /** * \brief Used to free the signature array, content_array and uri_content_array * members from the SigGroupHeads in the HashListTable. @@ -964,7 +620,6 @@ void SigGroupHeadFreeSigArrays(DetectEngineCtx *de_ctx) { SigGroupHeadFreeSigArraysHash2(de_ctx, de_ctx->sgh_hash_table); SigGroupHeadFreeSigArraysHash(de_ctx, de_ctx->sgh_dport_hash_table); - SigGroupHeadFreeSigArraysHash(de_ctx, de_ctx->sgh_sport_hash_table); return; } @@ -987,14 +642,6 @@ void SigGroupHeadFreeMpmArrays(DetectEngineCtx *de_ctx) } } - for (htb = HashListTableGetListHead(de_ctx->sgh_sport_hash_table); htb != NULL; htb = HashListTableGetListNext(htb)) { - sgh = (SigGroupHead *)HashListTableGetListData(htb); - if (sgh->init != NULL) { - SigGroupHeadInitDataFree(sgh->init); - sgh->init = NULL; - } - } - return; } @@ -1236,304 +883,6 @@ void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) SCReturn; } -/** - * \brief Helper function used to print the content ids of all the contents that - * have been added to the bitarray of this SigGroupHead. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - */ -void SigGroupHeadPrintContent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - SCEnter(); - - uint32_t i = 0; - - SCLogDebug("Contents with the following content ids are present in this " - "SigGroupHead - "); - for (i = 0; i < DetectContentMaxId(de_ctx); i++) { - if (sgh->init->content_array[i / 8] & (1 << (i % 8))) - SCLogDebug("%" PRIu32, i); - } - - SCReturn; -} - -/** - * \brief Helper function used to print the total no of contents that have - * been added to the bitarray for this SigGroupHead. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - */ -void SigGroupHeadPrintContentCnt(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - SCEnter(); - - uint32_t i = 0; - uint32_t cnt = 0; - - for (i = 0; i < DetectContentMaxId(de_ctx); i++) { - if (sgh->init->content_array[i / 8] & (1 << (i % 8))) - cnt++; - } - - SCLogDebug("Total contents added to the SigGroupHead content bitarray: " - "%" PRIu32, cnt); - - SCReturn; -} - -/** - * \brief Loads all the content ids from all the contents belonging to all the - * Signatures in this SigGroupHead, into a bitarray. A fast and an - * efficient way of comparing pattern sets. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval 0 On success, i.e. on either the detection engine context being NULL - * or on successfully allocating memory and updating it with relevant - * data. - * \retval -1 On failure. - */ -int SigGroupHeadLoadContent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - Signature *s = NULL; - SigMatch *sm = NULL; - uint32_t sig = 0; - DetectContentData *co = NULL; - - if (sgh == NULL) - return 0; - - if (DetectContentMaxId(de_ctx) == 0) - return 0; - - BUG_ON(sgh->init == NULL); - - sgh->init->content_size = (DetectContentMaxId(de_ctx) / 8) + 1; - sgh->init->content_array = SCMalloc(sgh->init->content_size); - if (sgh->init->content_array == NULL) - return -1; - - memset(sgh->init->content_array,0, sgh->init->content_size); - - for (sig = 0; sig < sgh->sig_cnt; sig++) { - s = sgh->match_array[sig]; - if (s == NULL) - continue; - - if (s->alproto != ALPROTO_UNKNOWN) - continue; - - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; - if (sm == NULL) - continue; - - for ( ;sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - co = (DetectContentData *)sm->ctx; - - sgh->init->content_array[co->id / 8] |= 1 << (co->id % 8); - } - } - } - - return 0; -} - -/** - * \brief Clears the memory allocated by SigGroupHeadLoadContent() for the - * bitarray to hold the content ids for a SigGroupHead. - * - * \param Pointer to the SigGroupHead whose content_array would to be cleared. - * - * \ret 0 Always. - */ -int SigGroupHeadClearContent(SigGroupHead *sh) -{ - if (sh == NULL) - return 0; - - if (sh->init->content_array != NULL) { - SCFree(sh->init->content_array); - sh->init->content_array = NULL; - sh->init->content_size = 0; - } - return 0; -} - -/** - * \brief Loads all the uri content ids from all the uri contents belonging to - * all the Signatures in this SigGroupHead, into a bitarray. A fast and - * an efficient way of comparing pattern sets. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval 0 On success, i.e. on either the detection engine context being NULL - * or on successfully allocating memory and updating it with relevant - * data. - * \retval -1 On failure. - */ -int SigGroupHeadLoadUricontent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - Signature *s = NULL; - SigMatch *sm = NULL; - uint32_t sig = 0; - DetectContentData *co = NULL; - - if (sgh == NULL) - return 0; - - if (DetectUricontentMaxId(de_ctx) == 0) - return 0; - - BUG_ON(sgh->init == NULL); - - sgh->init->uri_content_size = (DetectUricontentMaxId(de_ctx) / 8) + 1; - sgh->init->uri_content_array = SCMalloc(sgh->init->uri_content_size); - if (sgh->init->uri_content_array == NULL) - return -1; - - memset(sgh->init->uri_content_array, 0, sgh->init->uri_content_size); - - for (sig = 0; sig < sgh->sig_cnt; sig++) { - s = sgh->match_array[sig]; - - if (s == NULL) - continue; - - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; - if (sm == NULL) - continue; - - for ( ;sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - co = (DetectContentData *)sm->ctx; - - sgh->init->uri_content_array[co->id / 8] |= 1 << (co->id % 8); - } - } - } - - return 0; -} - -/** - * \brief Clears the memory allocated by SigGroupHeadLoadUriContent() for the - * bitarray to hold the uri content ids for a SigGroupHead. - * - * \param Pointer to the SigGroupHead whose uri_content_array would to be - * cleared. - * - * \retval 0 Always. - */ -int SigGroupHeadClearUricontent(SigGroupHead *sh) -{ - if (sh == NULL) - return 0; - - if (sh->init->uri_content_array != NULL) { - SCFree(sh->init->uri_content_array); - sh->init->uri_content_array = NULL; - sh->init->uri_content_size = 0; - } - - return 0; -} - -/** - * \brief Loads all the content ids from all the contents belonging to all the - * Signatures in this SigGroupHead, into a bitarray. A fast and an - * efficient way of comparing pattern sets. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval 0 On success, i.e. on either the detection engine context being NULL - * or on successfully allocating memory and updating it with relevant - * data. - * \retval -1 On failure. - */ -int SigGroupHeadLoadStreamContent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - SCEnter(); - - Signature *s = NULL; - SigMatch *sm = NULL; - uint32_t sig = 0; - DetectContentData *co = NULL; - - if (sgh == NULL) { - SCReturnInt(0); - } - - if (DetectContentMaxId(de_ctx) == 0) { - SCReturnInt(0); - } - - BUG_ON(sgh->init == NULL); - - sgh->init->stream_content_size = (DetectContentMaxId(de_ctx) / 8) + 1; - sgh->init->stream_content_array = SCMalloc(sgh->init->stream_content_size); - if (sgh->init->stream_content_array == NULL) { - SCReturnInt(-1); - } - - memset(sgh->init->stream_content_array,0, sgh->init->stream_content_size); - - for (sig = 0; sig < sgh->sig_cnt; sig++) { - s = sgh->match_array[sig]; - - SCLogDebug("s %"PRIu32, s->id); - - if (s == NULL) - continue; - - if (SignatureHasPacketContent(s)) { - SCLogDebug("Sig has packet content"); - continue; - } - - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; - if (sm == NULL) - continue; - - for ( ;sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - co = (DetectContentData *)sm->ctx; - - sgh->init->stream_content_array[co->id / 8] |= 1 << (co->id % 8); - } - } - } - - SCReturnInt(0); -} - -/** - * \brief Clears the memory allocated by SigGroupHeadLoadContent() for the - * bitarray to hold the content ids for a SigGroupHead. - * - * \param Pointer to the SigGroupHead whose content_array would to be cleared. - * - * \ret 0 Always. - */ -int SigGroupHeadClearStreamContent(SigGroupHead *sh) -{ - if (sh == NULL) - return 0; - - if (sh->init->stream_content_array != NULL) { - SCFree(sh->init->stream_content_array); - sh->init->stream_content_array = NULL; - sh->init->stream_content_size = 0; - } - return 0; -} - /** * \brief Create an array with all the internal ids of the sigs that this * sig group head will check for. @@ -1865,28 +1214,6 @@ static int SigGroupHeadTest01(void) return result; } -/** - * \test Check if a SigGroupHead mpm uri hash table is properly allocated and - * deallocated when calling SigGroupHeadMpmUriHashInit() and - * SigGroupHeadMpmUriHashFree() respectively. - */ -static int SigGroupHeadTest02(void) -{ - int result = 1; - - DetectEngineCtx de_ctx; - - SigGroupHeadMpmUriHashInit(&de_ctx); - - result &= (de_ctx.sgh_mpm_uri_hash_table != NULL); - - SigGroupHeadMpmUriHashFree(&de_ctx); - - result &= (de_ctx.sgh_mpm_uri_hash_table == NULL); - - return result; -} - /** * \test Check if a SigGroupHead hash table is properly allocated and * deallocated when calling SigGroupHeadHashInit() and @@ -1931,28 +1258,6 @@ static int SigGroupHeadTest04(void) return result; } -/** - * \test Check if a SigGroupHead dport hash table is properly allocated and - * deallocated when calling SigGroupHeadSPortHashInit() and - * SigGroupHeadSportHashFree() respectively. - */ -static int SigGroupHeadTest05(void) -{ - int result = 1; - - DetectEngineCtx de_ctx; - - SigGroupHeadSPortHashInit(&de_ctx); - - result &= (de_ctx.sgh_sport_hash_table != NULL); - - SigGroupHeadSPortHashFree(&de_ctx); - - result &= (de_ctx.sgh_sport_hash_table == NULL); - - return result; -} - /** * \test Check if a SigGroupHeadAppendSig() correctly appends a sid to a * SigGroupHead() and SigGroupHeadContainsSigId() correctly indicates @@ -2416,10 +1721,8 @@ void SigGroupHeadRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SigGroupHeadTest01", SigGroupHeadTest01, 1); - UtRegisterTest("SigGroupHeadTest02", SigGroupHeadTest02, 1); UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03, 1); UtRegisterTest("SigGroupHeadTest04", SigGroupHeadTest04, 1); - UtRegisterTest("SigGroupHeadTest05", SigGroupHeadTest05, 1); UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06, 1); UtRegisterTest("SigGroupHeadTest07", SigGroupHeadTest07, 1); UtRegisterTest("SigGroupHeadTest08", SigGroupHeadTest08, 1); diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index 133051edd5d9..14b46609c4a9 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -30,46 +30,27 @@ int SigGroupHeadAppendSig(const DetectEngineCtx *, SigGroupHead **, const Signat int SigGroupHeadClearSigs(SigGroupHead *); int SigGroupHeadCopySigs(DetectEngineCtx *, SigGroupHead *, SigGroupHead **); -int SigGroupHeadLoadContent(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadLoadUricontent(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadLoadStreamContent(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadClearContent(SigGroupHead *); -int SigGroupHeadClearUricontent(SigGroupHead *); -int SigGroupHeadClearStreamContent(SigGroupHead *); - void SigGroupHeadFree(SigGroupHead *); void SigGroupHeadFreeMpmArrays(DetectEngineCtx *); SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *, SigGroupHead *); SigGroupHead *SigGroupHeadMpmHashLookup(DetectEngineCtx *, SigGroupHead *); -SigGroupHead *SigGroupHeadMpmUriHashLookup(DetectEngineCtx *, SigGroupHead *); -SigGroupHead *SigGroupHeadMpmStreamHashLookup(DetectEngineCtx *, SigGroupHead *); SigGroupHead *SigGroupHeadDPortHashLookup(DetectEngineCtx *, SigGroupHead *); -SigGroupHead *SigGroupHeadSPortHashLookup(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadMpmHashAdd(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadMpmUriHashAdd(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadMpmStreamHashAdd(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadHashAdd(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadDPortHashAdd(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadSPortHashAdd(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadHashFree(DetectEngineCtx *); void SigGroupHeadMpmHashFree(DetectEngineCtx *); -void SigGroupHeadMpmUriHashFree(DetectEngineCtx *); -void SigGroupHeadMpmStreamHashFree(DetectEngineCtx *); void SigGroupHeadDPortHashFree(DetectEngineCtx *); -void SigGroupHeadSPortHashFree(DetectEngineCtx *); int SigGroupHeadHashInit(DetectEngineCtx *); int SigGroupHeadMpmHashInit(DetectEngineCtx *); -int SigGroupHeadMpmUriHashInit(DetectEngineCtx *); int SigGroupHeadDPortHashInit(DetectEngineCtx *); -int SigGroupHeadSPortHashInit(DetectEngineCtx *); int SigGroupHeadHashRemove(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadSPortHashRemove(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid); void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx); diff --git a/src/detect-engine.c b/src/detect-engine.c index f61c0c347c4f..0885e590c04c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -872,20 +872,11 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) SigGroupHeadHashInit(de_ctx); SigGroupHeadMpmHashInit(de_ctx); - SigGroupHeadMpmUriHashInit(de_ctx); - SigGroupHeadSPortHashInit(de_ctx); SigGroupHeadDPortHashInit(de_ctx); - DetectPortSpHashInit(de_ctx); - DetectPortDpHashInit(de_ctx); ThresholdHashInit(de_ctx); VariableNameInitHash(de_ctx); DetectParseDupSigHashInit(de_ctx); - de_ctx->mpm_pattern_id_store = MpmPatternIdTableInitHash(); - if (de_ctx->mpm_pattern_id_store == NULL) { - goto error; - } - /* init iprep... ignore errors for now */ (void)SRepInit(de_ctx); @@ -964,17 +955,11 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) /* Normally the hashes are freed elsewhere, but * to be sure look at them again here. */ - MpmPatternIdTableFreeHash(de_ctx->mpm_pattern_id_store); /* normally cleaned up in SigGroupBuild */ - SigGroupHeadHashFree(de_ctx); SigGroupHeadMpmHashFree(de_ctx); - SigGroupHeadMpmUriHashFree(de_ctx); - SigGroupHeadSPortHashFree(de_ctx); SigGroupHeadDPortHashFree(de_ctx); DetectParseDupSigHashFree(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); - DetectPortSpHashFree(de_ctx); - DetectPortDpHashFree(de_ctx); ThresholdContextDestroy(de_ctx); SigCleanSignatures(de_ctx); diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index 50df51c3f98e..dbc30cb627fe 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -82,15 +82,6 @@ void DetectUricontentRegister (void) sigmatch_table[DETECT_URICONTENT].flags |= SIGMATCH_PAYLOAD; } -/** - * \brief pass on the uricontent_max_id - * \param de_ctx pointer to the detect egine context whose max id is asked - */ -uint32_t DetectUricontentMaxId(DetectEngineCtx *de_ctx) -{ - return MpmPatternIdStoreGetMaxId(de_ctx->mpm_pattern_id_store); -} - /** * \brief this function will Free memory associated with DetectContentData * diff --git a/src/detect.c b/src/detect.c index 1907f0de109e..10180e438ba0 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3563,11 +3563,7 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) * after the initialization phase. */ SigGroupHeadHashFree(de_ctx); SigGroupHeadDPortHashFree(de_ctx); - SigGroupHeadSPortHashFree(de_ctx); SigGroupHeadMpmHashFree(de_ctx); - SigGroupHeadMpmUriHashFree(de_ctx); - DetectPortDpHashFree(de_ctx); - DetectPortSpHashFree(de_ctx); SCFree(de_ctx->sgh_array); de_ctx->sgh_array_cnt = 0; diff --git a/src/detect.h b/src/detect.h index 9f9389948f3c..ae4011c2685f 100644 --- a/src/detect.h +++ b/src/detect.h @@ -607,15 +607,9 @@ typedef struct DetectEngineCtx_ { 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; @@ -969,10 +963,6 @@ typedef struct SigGroupHeadInitData_ { /* list of content containers */ 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; uint8_t *sig_array; /**< bit array of sig nums (internal id's) */ uint32_t sig_size; /**< size in bytes */ From fac2cc056077c44ed826219bf51004b253dc1e56 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Oct 2015 10:25:03 +0200 Subject: [PATCH 1163/2553] detect: mpm deduplication Create hash for mpm's that we can reuse. Have packet/stream mpms use this. --- src/detect-engine-mpm.c | 915 +++++++++++++++++++++-------------- src/detect-engine-mpm.h | 7 +- src/detect-engine-siggroup.c | 150 ------ src/detect-engine.c | 4 +- src/detect.c | 5 +- src/detect.h | 28 +- 6 files changed, 589 insertions(+), 520 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index d678e9aa9f5b..4c37958e0573 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -60,8 +60,17 @@ #endif #include "util-validate.h" -/** \todo make it possible to use multiple pattern matcher algorithms next to - each other. */ +const char *builtin_mpms[] = { + "toserver TCP packet", + "toclient TCP packet", + "toserver TCP stream", + "toclient TCP stream", + "toserver UDP packet", + "toclient UDP packet", + "other IP packet", + + NULL }; + #define POPULATE_MPM_AVOID_PACKET_MPM_PATTERNS 0x01 #define POPULATE_MPM_AVOID_STREAM_MPM_PATTERNS 0x02 @@ -1104,8 +1113,8 @@ uint32_t PatternStrength(uint8_t *pat, uint16_t patlen) } static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, - DetectContentData *cd, - Signature *s, uint8_t flags, + const DetectContentData *cd, + const Signature *s, uint8_t flags, int chop) { uint16_t pat_offset = cd->offset; @@ -1153,135 +1162,6 @@ static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, #define SGH_DIRECTION_TS(sgh) ((sgh)->init->direction & SIG_FLAG_TOSERVER) #define SGH_DIRECTION_TC(sgh) ((sgh)->init->direction & SIG_FLAG_TOCLIENT) -/* TODO the sig updates don't belong here */ -static void PopulateMpmAddPatternToMpmPMATCH(const DetectEngineCtx *de_ctx, - SigGroupHead *sgh, Signature *s, - SigMatch *mpm_sm) -{ - DetectContentData *cd = (DetectContentData *)mpm_sm->ctx; - - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE) && - cd->content_len == cd->fp_chop_len) - { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - } else { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE)) - { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - } - - /* add the content to the "packet" mpm: - * chop is handled in PopulateMpmHelperAddPatternToPktCtx - */ - if (SignatureHasPacketContent(s)) { - /* per TCP packet mpm */ - if (SGH_PROTO(sgh, IPPROTO_TCP) && (s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) { - if (SGH_DIRECTION_TS(sgh) && s->flags & SIG_FLAG_TOSERVER) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_ts, - cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); - } - if (SGH_DIRECTION_TC(sgh) && s->flags & SIG_FLAG_TOCLIENT) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_tc, - cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); - } - } - } - /* per UDP packet mpm */ - if (SGH_PROTO(sgh, IPPROTO_UDP) && (s->proto.proto[IPPROTO_UDP / 8] & 1 << (IPPROTO_UDP % 8))) { - if (SGH_DIRECTION_TS(sgh) && s->flags & SIG_FLAG_TOSERVER) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_ts, - cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); - } - if (SGH_DIRECTION_TC(sgh) && s->flags & SIG_FLAG_TOCLIENT) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_tc, - cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); - } - } - - /* other IP protocols */ - if (!(SGH_PROTO(sgh, IPPROTO_TCP) || SGH_PROTO(sgh, IPPROTO_UDP))) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_other_ctx, - cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); - } - - /* tell matcher we are inspecting packet */ - s->flags |= SIG_FLAG_MPM_PACKET; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_PACKET_NEG; - } - sgh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - - /* for TCP, we have a special "stream" mpm as well */ - if (SGH_PROTO(sgh, IPPROTO_TCP) && SignatureHasStreamContent(s)) { - if (cd->flags & DETECT_CONTENT_NOCASE) { - if (SGH_DIRECTION_TS(sgh) && s->flags & SIG_FLAG_TOSERVER) { - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - MpmAddPatternCI(sgh->mpm_stream_ctx_ts, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, cd->id, s->num, 0); - } else { - MpmAddPatternCI(sgh->mpm_stream_ctx_ts, - cd->content, cd->content_len, - 0, 0, cd->id, s->num, 0); - } - } - if (SGH_DIRECTION_TC(sgh) && s->flags & SIG_FLAG_TOCLIENT) { - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - MpmAddPatternCI(sgh->mpm_stream_ctx_tc, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, cd->id, s->num, 0); - } else { - MpmAddPatternCI(sgh->mpm_stream_ctx_tc, - cd->content, cd->content_len, - 0, 0, cd->id, s->num, 0); - } - } - } else { - if (SGH_DIRECTION_TS(sgh) && s->flags & SIG_FLAG_TOSERVER) { - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - MpmAddPatternCS(sgh->mpm_stream_ctx_ts, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, cd->id, s->num, 0); - } else { - MpmAddPatternCS(sgh->mpm_stream_ctx_ts, - cd->content, cd->content_len, - 0, 0, cd->id, s->num, 0); - } - } - if (SGH_DIRECTION_TC(sgh) && s->flags & SIG_FLAG_TOCLIENT) { - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - MpmAddPatternCS(sgh->mpm_stream_ctx_tc, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, cd->id, s->num, 0); - } else { - MpmAddPatternCS(sgh->mpm_stream_ctx_tc, - cd->content, cd->content_len, - 0, 0, cd->id, s->num, 0); - } - } - } - /* tell matcher we are inspecting stream */ - s->flags |= SIG_FLAG_MPM_STREAM; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_STREAM_NEG; - } - sgh->flags |= SIG_GROUP_HEAD_MPM_STREAM; - } -} - static void PopulateMpmAddPatternToMpm(const DetectEngineCtx *de_ctx, SigGroupHead *sgh, Signature *s, SigMatch *mpm_sm) @@ -1304,7 +1184,7 @@ static void PopulateMpmAddPatternToMpm(const DetectEngineCtx *de_ctx, switch (sm_list) { case DETECT_SM_LIST_PMATCH: { - PopulateMpmAddPatternToMpmPMATCH(de_ctx, sgh, s, mpm_sm); + BUG_ON(1); break; } /* case DETECT_CONTENT */ @@ -1666,23 +1546,481 @@ static int PatternMatchPreparePopulateMpm(const DetectEngineCtx *de_ctx, Signature *s = sgh->match_array[sig]; if (s == NULL) continue; + if (s->mpm_sm == NULL) + continue; + int list = SigMatchListSMBelongsTo(s, s->mpm_sm); + if (list < 0) + continue; + if (list == DETECT_SM_LIST_PMATCH) + continue; PopulateMpmAddPatternToMpm(de_ctx, sgh, s, s->mpm_sm); } /* for (sig = 0; sig < sgh->sig_cnt; sig++) */ return 0; } +/** \internal + * \brief The hash function for MpmStore + * + * \param ht Pointer to the hash table. + * \param data Pointer to the MpmStore. + * \param datalen Not used in our case. + * + * \retval hash The generated hash value. + */ +static uint32_t MpmStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen) +{ + const MpmStore *ms = (MpmStore *)data; + uint32_t hash = 0; + uint32_t b = 0; + + for (b = 0; b < ms->sid_array_size; b++) + hash += ms->sid_array[b]; + + return hash % ht->array_size; +} + +/** + * \brief The Compare function for MpmStore + * + * \param data1 Pointer to the first MpmStore. + * \param len1 Not used. + * \param data2 Pointer to the second MpmStore. + * \param len2 Not used. + * + * \retval 1 If the 2 MpmStores sent as args match. + * \retval 0 If the 2 MpmStores sent as args do not match. + */ +static char MpmStoreCompareFunc(void *data1, uint16_t len1, void *data2, + uint16_t len2) +{ + const MpmStore *ms1 = (MpmStore *)data1; + const MpmStore *ms2 = (MpmStore *)data2; + + if (ms1->sid_array_size != ms2->sid_array_size) + return 0; + + if (ms1->buffer != ms2->buffer) + return 0; + + if (ms1->direction != ms2->direction) + return 0; + + if (SCMemcmp(ms1->sid_array, ms2->sid_array, + ms1->sid_array_size) != 0) + { + return 0; + } + + return 1; +} + +/** + * \brief Initializes the MpmStore mpm hash table to be used by the detection + * engine context. + * + * \param de_ctx Pointer to the detection engine context. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int MpmStoreInit(DetectEngineCtx *de_ctx) +{ + de_ctx->mpm_hash_table = HashListTableInit(4096, + MpmStoreHashFunc, + MpmStoreCompareFunc, + NULL); + if (de_ctx->mpm_hash_table == NULL) + goto error; + + return 0; + +error: + return -1; +} + +/** + * \brief Adds a MpmStore to the detection engine context MpmStore + * + * \param de_ctx Pointer to the detection engine context. + * \param sgh Pointer to the MpmStore. + * + * \retval ret 0 on Successfully adding the argument sgh; -1 on failure. + */ +static int MpmStoreAdd(DetectEngineCtx *de_ctx, MpmStore *s) +{ + int ret = HashListTableAdd(de_ctx->mpm_hash_table, (void *)s, 0); + return ret; +} + +/** + * \brief Used to lookup a MpmStore from the MpmStore + * + * \param de_ctx Pointer to the detection engine context. + * \param sgh Pointer to the MpmStore. + * + * \retval rsgh On success a pointer to the MpmStore if the MpmStore is + * found in the hash table; NULL on failure. + */ +static MpmStore *MpmStoreLookup(DetectEngineCtx *de_ctx, MpmStore *s) +{ + MpmStore *rs = HashListTableLookup(de_ctx->mpm_hash_table, + (void *)s, 0); + return rs; +} + +void MpmStoreReportStats(const DetectEngineCtx *de_ctx) +{ + HashListTableBucket *htb = NULL; + + uint32_t stats[MPMB_MAX] = {0}; + + for (htb = HashListTableGetListHead(de_ctx->mpm_hash_table); + htb != NULL; + htb = HashListTableGetListNext(htb)) + { + const MpmStore *ms = (MpmStore *)HashListTableGetListData(htb); + if (ms == NULL) { + continue; + } + stats[ms->buffer]++; + } + + uint32_t x; + for (x = 0; x < MPMB_MAX; x++) { + SCLogInfo("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]); + } +} + +/** + * \brief Frees the hash table - DetectEngineCtx->mpm_hash_table, allocated by + * MpmStoreInit() function. + * + * \param de_ctx Pointer to the detection engine context. + */ +void MpmStoreFree(DetectEngineCtx *de_ctx) +{ + if (de_ctx->mpm_hash_table == NULL) + return; + + HashListTableFree(de_ctx->mpm_hash_table); + de_ctx->mpm_hash_table = NULL; + return; +} + +void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) +{ + Signature *s = NULL; // TODO const + uint32_t sig; + + int32_t sgh_mpm_context = 0; + switch (ms->buffer) { + case MPMB_TCP_PKT_TS: + case MPMB_TCP_PKT_TC: + sgh_mpm_context = de_ctx->sgh_mpm_context_proto_tcp_packet; + break; + case MPMB_TCP_STREAM_TS: + case MPMB_TCP_STREAM_TC: + sgh_mpm_context = de_ctx->sgh_mpm_context_stream; + break; + case MPMB_UDP_TS: + case MPMB_UDP_TC: + sgh_mpm_context = de_ctx->sgh_mpm_context_proto_udp_packet; + break; + case MPMB_OTHERIP: + sgh_mpm_context = de_ctx->sgh_mpm_context_proto_other_packet; + break; + default: + break; + } + + int dir = 0; + switch (ms->buffer) { + /* TS is 1 */ + case MPMB_TCP_PKT_TS: + case MPMB_TCP_STREAM_TS: + case MPMB_UDP_TS: + dir = 1; + break; + + /* TC is 0 */ + default: + case MPMB_UDP_TC: + case MPMB_TCP_STREAM_TC: + case MPMB_TCP_PKT_TC: + case MPMB_OTHERIP: /**< use 0 for other */ + dir = 0; + break; + } + + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { + ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, sgh_mpm_context, dir); + } else { + ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, dir); + } + MpmInitCtx(ms->mpm_ctx, de_ctx->mpm_matcher); + + /* add the patterns */ + for (sig = 0; sig < (ms->sid_array_size * 8); sig++) { + if (ms->sid_array[sig / 8] & (1 << (sig % 8))) { + s = de_ctx->sig_array[sig]; + if (s == NULL) + continue; + if (s->mpm_sm == NULL) + continue; + int list = SigMatchListSMBelongsTo(s, s->mpm_sm); + if (list < 0) + continue; + if (list != DETECT_SM_LIST_PMATCH) + continue; + + SCLogDebug("adding %u", s->id); + + DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; // TODO const + /* TODO move this into cd setup code */ + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + if (DETECT_CONTENT_IS_SINGLE(cd) && + !(cd->flags & DETECT_CONTENT_NEGATED) && + !(cd->flags & DETECT_CONTENT_REPLACE) && + cd->content_len == cd->fp_chop_len) + { + cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; + } + } else { + if (DETECT_CONTENT_IS_SINGLE(cd) && + !(cd->flags & DETECT_CONTENT_NEGATED) && + !(cd->flags & DETECT_CONTENT_REPLACE)) + { + cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; + } + } + PopulateMpmHelperAddPatternToPktCtx(ms->mpm_ctx, + cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); + + /* tell matcher we are inspecting packet */ +/* TODO remove! */ + if (!(ms->buffer == MPMB_TCP_STREAM_TC || ms->buffer == MPMB_TCP_STREAM_TS)) { + s->flags |= SIG_FLAG_MPM_PACKET; + s->mpm_pattern_id_div_8 = cd->id / 8; + s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); + if (cd->flags & DETECT_CONTENT_NEGATED) { + SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); + s->flags |= SIG_FLAG_MPM_PACKET_NEG; + } + } else { + /* tell matcher we are inspecting stream */ + s->flags |= SIG_FLAG_MPM_STREAM; + s->mpm_pattern_id_div_8 = cd->id / 8; + s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); + if (cd->flags & DETECT_CONTENT_NEGATED) { + SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); + s->flags |= SIG_FLAG_MPM_STREAM_NEG; + } + } + } + } + + if (ms->mpm_ctx != NULL) { + if (ms->mpm_ctx->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, ms->mpm_ctx); + ms->mpm_ctx = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (mpm_table[ms->mpm_ctx->mpm_type].Prepare != NULL) { + mpm_table[ms->mpm_ctx->mpm_type].Prepare(ms->mpm_ctx); + } + } + } + } +} + + +/** \brief Get MpmStore for a built-in buffer type + * + */ +MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + enum MpmBuiltinBuffers buf) +{ + const Signature *s = NULL; + uint32_t sig; + uint32_t cnt = 0; + int direction = 0; + uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1; + uint8_t sids_array[max_sid]; + memset(sids_array, 0x00, max_sid); + + switch(buf) { + case MPMB_TCP_PKT_TS: + case MPMB_TCP_STREAM_TS: + case MPMB_UDP_TS: + direction = SIG_FLAG_TOSERVER; + break; + + case MPMB_TCP_PKT_TC: + case MPMB_TCP_STREAM_TC: + case MPMB_UDP_TC: + direction = SIG_FLAG_TOCLIENT; + break; + + case MPMB_OTHERIP: + direction = (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER); + break; + + case MPMB_MAX: + BUG_ON(1); + break; + } + + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; + + if (s->mpm_sm == NULL) + continue; + + int list = SigMatchListSMBelongsTo(s, s->mpm_sm); + if (list < 0) + continue; + + if (list != DETECT_SM_LIST_PMATCH) + continue; + + switch (buf) { + case MPMB_TCP_PKT_TS: + case MPMB_TCP_PKT_TC: + if (SignatureHasPacketContent(s) == 1) + { + sids_array[s->num / 8] |= 1 << (s->num % 8); + cnt++; + } + break; + case MPMB_TCP_STREAM_TS: + case MPMB_TCP_STREAM_TC: + if (SignatureHasStreamContent(s) == 1) + { + sids_array[s->num / 8] |= 1 << (s->num % 8); + cnt++; + } + break; + case MPMB_UDP_TS: + case MPMB_UDP_TC: + sids_array[s->num / 8] |= 1 << (s->num % 8); + cnt++; + break; + case MPMB_OTHERIP: + sids_array[s->num / 8] |= 1 << (s->num % 8); + cnt++; + break; + default: + break; + } + } + + if (cnt == 0) + return NULL; + + MpmStore lookup = { sids_array, max_sid, direction, buf, NULL}; + + MpmStore *result = MpmStoreLookup(de_ctx, &lookup); + if (result == NULL) { + MpmStore *copy = SCCalloc(1, sizeof(MpmStore)); + if (copy == NULL) + return NULL; + uint8_t *sids = SCCalloc(1, max_sid); + if (sids == NULL) { + SCFree(copy); + return NULL; + } + + memcpy(sids, sids_array, max_sid); + copy->sid_array = sids; + copy->sid_array_size = max_sid; + copy->buffer = buf; + copy->direction = direction; + + MpmStoreSetup(de_ctx, copy); + MpmStoreAdd(de_ctx, copy); + return copy; + } else { + return result; + } +} + /** \brief Prepare the pattern matcher ctx in a sig group head. * * \todo determine if a content match can set the 'single' flag * \todo do error checking * \todo rewrite the COPY stuff */ -int PatternMatchPrepareGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sh) +int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) { + MpmStore *mpm_store = NULL; + if (SGH_PROTO(sh, IPPROTO_TCP)) { + if (SGH_DIRECTION_TS(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TS); + if (mpm_store != NULL) { + sh->mpm_proto_tcp_ctx_ts = mpm_store->mpm_ctx; + if (sh->mpm_proto_tcp_ctx_ts) + sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + } + + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TS); + if (mpm_store != NULL) { + BUG_ON(mpm_store == NULL); + sh->mpm_stream_ctx_ts = mpm_store->mpm_ctx; + if (sh->mpm_stream_ctx_ts) + sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; + } + } + if (SGH_DIRECTION_TC(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TC); + if (mpm_store != NULL) { + sh->mpm_proto_tcp_ctx_tc = mpm_store->mpm_ctx; + if (sh->mpm_proto_tcp_ctx_tc) + sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + } + + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TC); + if (mpm_store != NULL) { + sh->mpm_stream_ctx_tc = mpm_store->mpm_ctx; + if (sh->mpm_stream_ctx_tc) + sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; + } + } + } else if (SGH_PROTO(sh, IPPROTO_UDP)) { + if (SGH_DIRECTION_TS(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TS); + if (mpm_store != NULL) { + BUG_ON(mpm_store == NULL); + sh->mpm_proto_udp_ctx_ts = mpm_store->mpm_ctx; + + if (sh->mpm_proto_udp_ctx_ts != NULL) + sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + } + } + if (SGH_DIRECTION_TC(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TC); + if (mpm_store != NULL) { + sh->mpm_proto_udp_ctx_tc = mpm_store->mpm_ctx; + + if (sh->mpm_proto_udp_ctx_tc != NULL) + sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + } + } + } else { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_OTHERIP); + if (mpm_store != NULL) { + sh->mpm_proto_other_ctx = mpm_store->mpm_ctx; + + if (sh->mpm_proto_other_ctx != NULL) + sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + } + } + + + Signature *s = NULL; - uint32_t has_co_packet = 0; /**< our sgh has packet payload inspecting content */ - uint32_t has_co_stream = 0; /**< our sgh has stream inspecting content */ uint32_t has_co_uri = 0; /**< our sgh has uri inspecting content */ /* used to indicate if sgh has atleast one sig with http_client_body */ uint32_t has_co_hcbd = 0; @@ -1720,145 +2058,106 @@ int PatternMatchPrepareGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sh) s = sh->match_array[sig]; if (s == NULL) continue; - if (!(SGH_PROTO(sh, IPPROTO_TCP)) || - (SGH_PROTO(sh, IPPROTO_TCP) && SignatureHasPacketContent(s) == 1)) - { - has_co_packet = 1; - } + if (s->mpm_sm == NULL) + continue; - if (SGH_PROTO(sh, IPPROTO_TCP)) { - if (SignatureHasStreamContent(s) == 1) { - has_co_stream = 1; - } + int list = SigMatchListSMBelongsTo(s, s->mpm_sm); + if (list < 0) + continue; + if (list == DETECT_SM_LIST_PMATCH) + continue; - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { - has_co_uri = 1; - } - if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { - has_co_hcbd = 1; - } + if (SGH_PROTO(sh, IPPROTO_TCP)) { + switch (list) { + case DETECT_SM_LIST_UMATCH: + has_co_uri = 1; + break; + + case DETECT_SM_LIST_HCBDMATCH: + has_co_hcbd = 1; + break; + + case DETECT_SM_LIST_FILEDATA: + if (s->alproto == ALPROTO_SMTP) + has_co_smtp = 1; + else if (s->alproto == ALPROTO_HTTP) + has_co_hsbd = 1; + else if (s->alproto == ALPROTO_UNKNOWN) { + has_co_smtp = 1; + has_co_hsbd = 1; + } + break; - if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) { - if (s->alproto == ALPROTO_SMTP) - has_co_smtp = 1; - else if (s->alproto == ALPROTO_HTTP) - has_co_hsbd = 1; - else if (s->alproto == ALPROTO_UNKNOWN) { - has_co_smtp = 1; - has_co_hsbd = 1; - } - } + case DETECT_SM_LIST_HHDMATCH: + has_co_hhd = 1; + break; - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { - has_co_hhd = 1; - } + case DETECT_SM_LIST_HRHDMATCH: + has_co_hrhd = 1; + break; - if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { - has_co_hrhd = 1; - } + case DETECT_SM_LIST_HMDMATCH: + has_co_hmd = 1; + break; - if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { - has_co_hmd = 1; - } + case DETECT_SM_LIST_HCDMATCH: + has_co_hcd = 1; + break; - if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) { - has_co_hcd = 1; - } + case DETECT_SM_LIST_HRUDMATCH: + has_co_hrud = 1; + break; - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { - has_co_hrud = 1; - } + case DETECT_SM_LIST_HSMDMATCH: + has_co_hsmd = 1; + break; - if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { - has_co_hsmd = 1; - } + case DETECT_SM_LIST_HSCDMATCH: + has_co_hscd = 1; + break; - if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { - has_co_hscd = 1; - } + case DETECT_SM_LIST_HUADMATCH: + has_co_huad = 1; + break; - if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { - has_co_huad = 1; - } + case DETECT_SM_LIST_HHHDMATCH: + has_co_hhhd = 1; + break; - if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { - has_co_hhhd = 1; - } + case DETECT_SM_LIST_HRHHDMATCH: + has_co_hrhhd = 1; + break; - if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { - has_co_hrhhd = 1; - } - } + case DETECT_SM_LIST_DNSQUERYNAME_MATCH: + has_co_dnsquery = 1; + break; - if (SGH_PROTO(sh, IPPROTO_TCP) || SGH_PROTO(sh, IPPROTO_UDP)) { - if (s->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH] != NULL) { - has_co_dnsquery = 1; + default: + BUG_ON(1); } - } - } - /* intialize contexes */ - if (has_co_packet) { - if (SGH_PROTO(sh, IPPROTO_TCP)) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_proto_tcp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); - sh->mpm_proto_tcp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); - } else { - sh->mpm_proto_tcp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_proto_tcp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_proto_tcp_ctx_ts == NULL || sh->mpm_proto_tcp_ctx_tc == NULL) { - SCLogDebug("sh->mpm_proto_tcp_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - MpmInitCtx(sh->mpm_proto_tcp_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_proto_tcp_ctx_tc, de_ctx->mpm_matcher); - } - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_proto_udp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); - sh->mpm_proto_udp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); - } else { - sh->mpm_proto_udp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_proto_udp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_proto_udp_ctx_ts == NULL || sh->mpm_proto_udp_ctx_tc == NULL) { - SCLogDebug("sh->mpm_proto_udp_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - MpmInitCtx(sh->mpm_proto_udp_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_proto_udp_ctx_tc, de_ctx->mpm_matcher); + /* UDP */ + } else if (SGH_PROTO(sh, IPPROTO_UDP)) { + switch (list) { + case DETECT_SM_LIST_DNSQUERYNAME_MATCH: + has_co_dnsquery = 1; + break; - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_proto_other_ctx = - MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0); - } else { - sh->mpm_proto_other_ctx = - MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_proto_other_ctx == NULL) { - SCLogDebug("sh->mpm_proto_other_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - MpmInitCtx(sh->mpm_proto_other_ctx, de_ctx->mpm_matcher); - } /* if (has_co_packet) */ + default: + BUG_ON(1); + } - if (has_co_stream) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_stream_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); - sh->mpm_stream_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1); + /* all other protos just support PMATCH */ } else { - sh->mpm_stream_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_stream_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_stream_ctx_tc == NULL || sh->mpm_stream_ctx_ts == NULL) { - SCLogDebug("sh->mpm_stream_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); + switch (list) { + default: + BUG_ON(1); + } } - MpmInitCtx(sh->mpm_stream_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_stream_ctx_tc, de_ctx->mpm_matcher); } + /* intialize contexes */ if (has_co_uri) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_uri_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 0); @@ -2078,9 +2377,7 @@ int PatternMatchPrepareGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sh) MpmInitCtx(sh->mpm_dnsquery_ctx_ts, de_ctx->mpm_matcher); } - if (has_co_packet || - has_co_stream || - has_co_uri || + if (has_co_uri || has_co_hcbd || has_co_hsbd || has_co_smtp || @@ -2099,97 +2396,6 @@ int PatternMatchPrepareGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sh) /* add the patterns of all the rules to the mpms of this sgh */ PatternMatchPreparePopulateMpm(de_ctx, sh); - if (sh->mpm_proto_tcp_ctx_ts != NULL) { - if (sh->mpm_proto_tcp_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_ts); - sh->mpm_proto_tcp_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type]. - Prepare(sh->mpm_proto_tcp_ctx_ts); - } - } - } - } - if (sh->mpm_proto_tcp_ctx_tc != NULL) { - if (sh->mpm_proto_tcp_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_tc); - sh->mpm_proto_tcp_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type]. - Prepare(sh->mpm_proto_tcp_ctx_tc); - } - } - } - } - - if (sh->mpm_proto_udp_ctx_ts != NULL) { - if (sh->mpm_proto_udp_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_ts); - sh->mpm_proto_udp_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type]. - Prepare(sh->mpm_proto_udp_ctx_ts); - } - } - } - } - if (sh->mpm_proto_udp_ctx_tc != NULL) { - if (sh->mpm_proto_udp_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_tc); - sh->mpm_proto_udp_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type]. - Prepare(sh->mpm_proto_udp_ctx_tc); - } - } - } - } - - if (sh->mpm_proto_other_ctx != NULL) { - if (sh->mpm_proto_other_ctx->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx); - sh->mpm_proto_other_ctx = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_other_ctx->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_other_ctx->mpm_type]. - Prepare(sh->mpm_proto_other_ctx); - } - } - } - } - - if (sh->mpm_stream_ctx_ts != NULL) { - if (sh->mpm_stream_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_ts); - sh->mpm_stream_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_stream_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_stream_ctx_ts->mpm_type].Prepare(sh->mpm_stream_ctx_ts); - } - } - } - if (sh->mpm_stream_ctx_tc != NULL) { - if (sh->mpm_stream_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_tc); - sh->mpm_stream_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_stream_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_stream_ctx_tc->mpm_type].Prepare(sh->mpm_stream_ctx_tc); - } - } - } - if (sh->mpm_uri_ctx_ts != NULL) { if (sh->mpm_uri_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_ts); @@ -2404,15 +2610,6 @@ int PatternMatchPrepareGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sh) } } } else { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx); - sh->mpm_proto_other_ctx = NULL; - - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_ts); - sh->mpm_proto_tcp_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_ts); - sh->mpm_proto_udp_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_ts); - sh->mpm_stream_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_ts); sh->mpm_uri_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_ts); @@ -2438,12 +2635,6 @@ int PatternMatchPrepareGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sh) MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_smtp_filedata_ctx_ts); sh->mpm_smtp_filedata_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_tc); - sh->mpm_proto_tcp_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_tc); - sh->mpm_proto_udp_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_tc); - sh->mpm_stream_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_tc); sh->mpm_hhd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_tc); diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index b0d9f12fca61..235b96da08f4 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -64,7 +64,7 @@ void PatternMatchDestroy(MpmCtx *, uint16_t); void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t); void PatternMatchThreadPrint(MpmThreadCtx *, uint16_t); -int PatternMatchPrepareGroup(const DetectEngineCtx *, SigGroupHead *); +int PatternMatchPrepareGroup(DetectEngineCtx *, SigGroupHead *); void DetectEngineThreadCtxInfo(ThreadVars *, DetectEngineThreadCtx *); void PatternMatchDestroyGroup(SigGroupHead *); @@ -83,6 +83,11 @@ int SignatureHasStreamContent(const Signature *); SigMatch *RetrieveFPForSig(Signature *s); +int MpmStoreInit(DetectEngineCtx *); +void MpmStoreFree(DetectEngineCtx *); +void MpmStoreReportStats(const DetectEngineCtx *de_ctx); +MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, enum MpmBuiltinBuffers buf); + /** * \brief Figured out the FP and their respective content ids for all the * sigs in the engine. diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index fd2f404bd420..9d04697cc937 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -203,133 +203,6 @@ void SigGroupHeadFree(SigGroupHead *sgh) return; } -/** - * \brief The hash function to be the used by the mpm SigGroupHead hash table - - * DetectEngineCtx->sgh_mpm_hash_table. - * - * \param ht Pointer to the hash table. - * \param data Pointer to the SigGroupHead. - * \param datalen Not used in our case. - * - * \retval hash The generated hash value. - */ -uint32_t SigGroupHeadMpmHashFunc(HashListTable *ht, void *data, uint16_t datalen) -{ - SigGroupHead *sgh = (SigGroupHead *)data; - uint32_t hash = 0; - uint32_t b = 0; - - for (b = 0; b < sgh->init->content_size; b++) - hash += sgh->init->content_array[b]; - - return hash % ht->array_size; -} - -/** - * \brief The Compare function to be used by the mpm SigGroupHead hash table - - * DetectEngineCtx->sgh_mpm_hash_table. - * - * \param data1 Pointer to the first SigGroupHead. - * \param len1 Not used. - * \param data2 Pointer to the second SigGroupHead. - * \param len2 Not used. - * - * \retval 1 If the 2 SigGroupHeads sent as args match. - * \retval 0 If the 2 SigGroupHeads sent as args do not match. - */ -char SigGroupHeadMpmCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) -{ - SigGroupHead *sgh1 = (SigGroupHead *)data1; - SigGroupHead *sgh2 = (SigGroupHead *)data2; - - if (sgh1->init->content_size != sgh2->init->content_size) - return 0; - - if (SCMemcmp(sgh1->init->content_array, sgh2->init->content_array, - sgh1->init->content_size) != 0) { - return 0; - } - - return 1; -} - -/** - * \brief Initializes the SigGroupHead mpm hash table to be used by the detection - * engine context. - * - * \param de_ctx Pointer to the detection engine context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadMpmHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sgh_mpm_hash_table = HashListTableInit(4096, SigGroupHeadMpmHashFunc, - SigGroupHeadMpmCompareFunc, - NULL); - - if (de_ctx->sgh_mpm_hash_table == NULL) - goto error; - - return 0; - -error: - return -1; -} - -/** - * \brief Adds a SigGroupHead to the detection engine context SigGroupHead - * mpm hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval ret 0 on Successfully adding the argument sgh; -1 on failure. - */ -int SigGroupHeadMpmHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - int ret = HashListTableAdd(de_ctx->sgh_mpm_hash_table, (void *)sgh, 0); - - return ret; -} - -/** - * \brief Used to lookup a SigGroupHead from the detection engine context - * SigGroupHead mpm hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is - * found in the hash table; NULL on failure. - */ -SigGroupHead *SigGroupHeadMpmHashLookup(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_mpm_hash_table, - (void *)sgh, 0); - - return rsgh; -} - -/** - * \brief Frees the hash table - DetectEngineCtx->sgh_mpm_hash_table, allocated by - * SigGroupHeadMpmHashInit() function. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadMpmHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->sgh_mpm_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sgh_mpm_hash_table); - de_ctx->sgh_mpm_hash_table = NULL; - - return; -} - /** * \brief The hash function to be the used by the hash table - * DetectEngineCtx->sgh_hash_table. @@ -1192,28 +1065,6 @@ int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int SigAddressPrepareStage1(DetectEngineCtx *); -/** - * \test Check if a SigGroupHead mpm hash table is properly allocated and - * deallocated when calling SigGroupHeadMpmHashInit() and - * SigGroupHeadMpmHashFree() respectively. - */ -static int SigGroupHeadTest01(void) -{ - int result = 1; - - DetectEngineCtx de_ctx; - - SigGroupHeadMpmHashInit(&de_ctx); - - result &= (de_ctx.sgh_mpm_hash_table != NULL); - - SigGroupHeadMpmHashFree(&de_ctx); - - result &= (de_ctx.sgh_mpm_hash_table == NULL); - - return result; -} - /** * \test Check if a SigGroupHead hash table is properly allocated and * deallocated when calling SigGroupHeadHashInit() and @@ -1720,7 +1571,6 @@ static int SigGroupHeadTest11(void) void SigGroupHeadRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SigGroupHeadTest01", SigGroupHeadTest01, 1); UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03, 1); UtRegisterTest("SigGroupHeadTest04", SigGroupHeadTest04, 1); UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06, 1); diff --git a/src/detect-engine.c b/src/detect-engine.c index 0885e590c04c..80a701e7e9c9 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -871,7 +871,7 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) DetectEngineCtxLoadConf(de_ctx); SigGroupHeadHashInit(de_ctx); - SigGroupHeadMpmHashInit(de_ctx); + MpmStoreInit(de_ctx); SigGroupHeadDPortHashInit(de_ctx); ThresholdHashInit(de_ctx); VariableNameInitHash(de_ctx); @@ -956,7 +956,7 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) * to be sure look at them again here. */ SigGroupHeadHashFree(de_ctx); - SigGroupHeadMpmHashFree(de_ctx); + MpmStoreFree(de_ctx); SigGroupHeadDPortHashFree(de_ctx); DetectParseDupSigHashFree(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); diff --git a/src/detect.c b/src/detect.c index 10180e438ba0..1abf9d5459fc 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3534,6 +3534,7 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SigGroupHead *sgh = de_ctx->sgh_array[idx]; if (sgh == NULL) continue; + SigGroupHeadSetFilemagicFlag(de_ctx, sgh); SigGroupHeadSetFileMd5Flag(de_ctx, sgh); SigGroupHeadSetFilesizeFlag(de_ctx, sgh); @@ -3549,6 +3550,8 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) } SCLogInfo("Unique rule groups: %u", cnt); + MpmStoreReportStats(de_ctx); + if (de_ctx->decoder_event_sgh != NULL) { /* no need to set filestore count here as that would make a * signature not decode event only. */ @@ -3563,7 +3566,7 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) * after the initialization phase. */ SigGroupHeadHashFree(de_ctx); SigGroupHeadDPortHashFree(de_ctx); - SigGroupHeadMpmHashFree(de_ctx); + MpmStoreFree(de_ctx); SCFree(de_ctx->sgh_array); de_ctx->sgh_array_cnt = 0; diff --git a/src/detect.h b/src/detect.h index ae4011c2685f..e1c441b0dafd 100644 --- a/src/detect.h +++ b/src/detect.h @@ -606,7 +606,7 @@ typedef struct DetectEngineCtx_ { /* init phase vars */ HashListTable *sgh_hash_table; - HashListTable *sgh_mpm_hash_table; + HashListTable *mpm_hash_table; HashListTable *sgh_dport_hash_table; @@ -959,10 +959,30 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 23) #define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 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; + + MpmCtx *mpm_ctx; + +} MpmStore; + typedef struct SigGroupHeadInitData_ { - /* list of content containers */ - uint8_t *content_array; - uint32_t content_size; + MpmStore mpm_store[MPMB_MAX]; uint8_t *sig_array; /**< bit array of sig nums (internal id's) */ uint32_t sig_size; /**< size in bytes */ From 102a82fc7bc47b7cf3c4c20bfbbd5da8363f987e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Oct 2015 19:15:58 +0200 Subject: [PATCH 1164/2553] detect: use mpm store for app layer mpms Rework app-layer mpm setup and registration to make this possible. --- src/detect-engine-mpm.c | 1290 ++++++++++----------------------------- src/detect-engine-mpm.h | 3 + src/detect.c | 192 +----- src/detect.h | 21 +- src/util-mpm-ac.c | 188 ------ 5 files changed, 323 insertions(+), 1371 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 4c37958e0573..6bed2e556ee0 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -71,10 +71,77 @@ const char *builtin_mpms[] = { NULL }; +typedef struct AppLayerMpms_ { + const char *name; + int32_t sgh_mpm_context; /**< mpm factory id */ + int direction; /**< SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT */ + int sm_list; + uint32_t flags; /**< flags set to SGH when this mpm is present */ + int id; /**< index into this array and result arrays */ +} AppLayerMpms; + +AppLayerMpms app_mpms[] = { + { "http_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_UMATCH, SIG_GROUP_HEAD_MPM_URI, 0 }, + { "http_raw_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRUDMATCH, SIG_GROUP_HEAD_MPM_HRUD, 1 }, + + { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, 2}, + { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, 3}, + + { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, SIG_GROUP_HEAD_MPM_HUAD, 4}, + + { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, 5}, + { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, 6}, + + { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, SIG_GROUP_HEAD_MPM_HMD, 7}, + + { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_FD_SMTP, 8}, /* smtp */ + { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_HSBD, 9}, /* http server body */ + + { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, SIG_GROUP_HEAD_MPM_HSMD, 10}, + { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, SIG_GROUP_HEAD_MPM_HSCD, 11}, + + { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, SIG_GROUP_HEAD_MPM_HCBD, 12}, + + { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, SIG_GROUP_HEAD_MPM_HHHD, 13}, + { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, SIG_GROUP_HEAD_MPM_HRHHD, 14}, + + { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, 15}, + { "http_cookie", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, 16}, + + { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, SIG_GROUP_HEAD_MPM_DNSQUERY, 17}, + + { NULL, 0, 0, 0, 0, 0, } +}; + +void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) +{ + int i; + for (i = 0; i < APP_MPMS_MAX; i++) { + AppLayerMpms *am = &app_mpms[i]; -#define POPULATE_MPM_AVOID_PACKET_MPM_PATTERNS 0x01 -#define POPULATE_MPM_AVOID_STREAM_MPM_PATTERNS 0x02 -#define POPULATE_MPM_AVOID_URI_MPM_PATTERNS 0x04 + am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name, + MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); + + SCLogDebug("AppLayer MPM %s: %u", am->name, am->sgh_mpm_context); + } +} + +void DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx) +{ + int i; + for (i = 0; i < APP_MPMS_MAX; i++) { + AppLayerMpms *am = &app_mpms[i]; + + int dir = (am->direction == SIG_FLAG_TOSERVER) ? 1 : 0; + + MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, dir); + if (mpm_ctx != NULL) { + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + } + } +} /** * \brief check if a signature has patterns that are to be inspected @@ -1162,252 +1229,6 @@ static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, #define SGH_DIRECTION_TS(sgh) ((sgh)->init->direction & SIG_FLAG_TOSERVER) #define SGH_DIRECTION_TC(sgh) ((sgh)->init->direction & SIG_FLAG_TOCLIENT) -static void PopulateMpmAddPatternToMpm(const DetectEngineCtx *de_ctx, - SigGroupHead *sgh, Signature *s, - SigMatch *mpm_sm) -{ - s->mpm_sm = mpm_sm; - - if (mpm_sm == NULL) { - SCLogDebug("%"PRIu32" no mpm pattern selected", s->id); - return; - } - - int sm_list = SigMatchListSMBelongsTo(s, mpm_sm); - if (sm_list == -1) - BUG_ON(SigMatchListSMBelongsTo(s, mpm_sm) == -1); - - uint8_t flags = 0; - - DetectContentData *cd = NULL; - - switch (sm_list) { - case DETECT_SM_LIST_PMATCH: - { - BUG_ON(1); - break; - } /* case DETECT_CONTENT */ - - case DETECT_SM_LIST_UMATCH: - case DETECT_SM_LIST_HRUDMATCH: - case DETECT_SM_LIST_HCBDMATCH: - case DETECT_SM_LIST_FILEDATA: - case DETECT_SM_LIST_HHDMATCH: - case DETECT_SM_LIST_HRHDMATCH: - case DETECT_SM_LIST_HMDMATCH: - case DETECT_SM_LIST_HCDMATCH: - case DETECT_SM_LIST_HSMDMATCH: - case DETECT_SM_LIST_HSCDMATCH: - case DETECT_SM_LIST_HUADMATCH: - case DETECT_SM_LIST_HHHDMATCH: - case DETECT_SM_LIST_HRHHDMATCH: - case DETECT_SM_LIST_DNSQUERYNAME_MATCH: - { - MpmCtx *mpm_ctx_ts = NULL; - MpmCtx *mpm_ctx_tc = NULL; - - cd = (DetectContentData *)mpm_sm->ctx; - - if (sm_list == DETECT_SM_LIST_UMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_uri_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_URI; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HCBDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hcbd_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HCBD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_FILEDATA) { - if (s->flags & SIG_FLAG_TOCLIENT) { - mpm_ctx_tc = sgh->mpm_hsbd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HSBD; - } - if (s->flags & SIG_FLAG_TOSERVER) { - mpm_ctx_ts = sgh->mpm_smtp_filedata_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_FD_SMTP; - } - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HHDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hhd_ctx_ts; - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hhd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HHD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HRHDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hrhd_ctx_ts; - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hrhd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HRHD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HMDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hmd_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HMD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HCDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hcd_ctx_ts; - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hcd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HCD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HRUDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hrud_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HRUD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HSMDMATCH) { - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hsmd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HSMD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HSCDMATCH) { - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hscd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HSCD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HUADMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_huad_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HUAD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HHHDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hhhd_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HHHD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HRHHDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hrhhd_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HRHHD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_DNSQUERYNAME_MATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_dnsquery_ctx_ts; - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = NULL; - sgh->flags |= SIG_GROUP_HEAD_MPM_DNSQUERY; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } - - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE) && - cd->content_len == cd->fp_chop_len) { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - - /* add the content to the mpm */ - if (cd->flags & DETECT_CONTENT_NOCASE) { - if (mpm_ctx_ts != NULL) { - MpmAddPatternCI(mpm_ctx_ts, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - if (mpm_ctx_tc != NULL) { - MpmAddPatternCI(mpm_ctx_tc, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - } else { - if (mpm_ctx_ts != NULL) { - MpmAddPatternCS(mpm_ctx_ts, - cd->content + cd->fp_chop_offset, - cd->fp_chop_len, - 0, 0, cd->id, s->num, flags); - } - if (mpm_ctx_tc != NULL) { - MpmAddPatternCS(mpm_ctx_tc, - cd->content + cd->fp_chop_offset, - cd->fp_chop_len, - 0, 0, cd->id, s->num, flags); - } - } - } else { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE)) { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - - /* add the content to the "uri" mpm */ - if (cd->flags & DETECT_CONTENT_NOCASE) { - if (mpm_ctx_ts != NULL) { - MpmAddPatternCI(mpm_ctx_ts, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - if (mpm_ctx_tc != NULL) { - MpmAddPatternCI(mpm_ctx_tc, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - } else { - if (mpm_ctx_ts != NULL) { - MpmAddPatternCS(mpm_ctx_ts, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - if (mpm_ctx_tc != NULL) { - MpmAddPatternCS(mpm_ctx_tc, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - } - } - /* tell matcher we are inspecting uri */ - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - - break; - } - } /* switch (mpm_sm->type) */ - - SCLogDebug("%"PRIu32" adding cd->id %"PRIu32" to the mpm phase " - "(s->num %"PRIu32")", s->id, - ((DetectContentData *)mpm_sm->ctx)->id, s->num); - - return; -} - SigMatch *RetrieveFPForSig(Signature *s) { if (s->mpm_sm != NULL) @@ -1528,37 +1349,6 @@ SigMatch *RetrieveFPForSig(Signature *s) return mpm_sm; } -/** - * \internal - * \brief Setup the mpm content. - * - * \param de_ctx Pointer to the detect engine context. - * \param sgh Pointer to the signature group head against which we are - * adding patterns to the mpm ctx. - * - * \retval 0 Always. - */ -static int PatternMatchPreparePopulateMpm(const DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - uint32_t sig = 0; - for (sig = 0; sig < sgh->sig_cnt; sig++) { - Signature *s = sgh->match_array[sig]; - if (s == NULL) - continue; - if (s->mpm_sm == NULL) - continue; - int list = SigMatchListSMBelongsTo(s, s->mpm_sm); - if (list < 0) - continue; - if (list == DETECT_SM_LIST_PMATCH) - continue; - PopulateMpmAddPatternToMpm(de_ctx, sgh, s, s->mpm_sm); - } /* for (sig = 0; sig < sgh->sig_cnt; sig++) */ - - return 0; -} - /** \internal * \brief The hash function for MpmStore * @@ -1606,6 +1396,9 @@ static char MpmStoreCompareFunc(void *data1, uint16_t len1, void *data2, if (ms1->direction != ms2->direction) return 0; + if (ms1->sm_list != ms2->sm_list) + return 0; + if (SCMemcmp(ms1->sid_array, ms2->sid_array, ms1->sid_array_size) != 0) { @@ -1674,6 +1467,7 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx) HashListTableBucket *htb = NULL; uint32_t stats[MPMB_MAX] = {0}; + uint32_t appstats[APP_MPMS_MAX] = {0}; for (htb = HashListTableGetListHead(de_ctx->mpm_hash_table); htb != NULL; @@ -1683,13 +1477,38 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx) if (ms == NULL) { continue; } - stats[ms->buffer]++; + if (ms->buffer < MPMB_MAX) + stats[ms->buffer]++; + else if (ms->sm_list != DETECT_SM_LIST_PMATCH) { + int i; + for (i = 0; i < APP_MPMS_MAX; i++) { + AppLayerMpms *am = &app_mpms[i]; + if (ms->sm_list == am->sm_list && + ms->direction == am->direction) + { + SCLogDebug("%s %s: %u patterns. Min %u, Max %u. Ctx %p", am->name, + am->direction == SIG_FLAG_TOSERVER ? "toserver":"toclient", + ms->mpm_ctx->pattern_cnt, + ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen, + ms->mpm_ctx); + appstats[i]++; + break; + } + } + } } uint32_t x; for (x = 0; x < MPMB_MAX; x++) { SCLogInfo("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]); } + for (x = 0; x < APP_MPMS_MAX; x++) { + if (appstats[x] == 0) + continue; + const char *name = app_mpms[x].name; + char *direction = app_mpms[x].direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient"; + SCLogInfo("AppLayer MPM \"%s %s\": %u", direction, name, appstats[x]); + } } /** @@ -1713,48 +1532,41 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) Signature *s = NULL; // TODO const uint32_t sig; - int32_t sgh_mpm_context = 0; - switch (ms->buffer) { - case MPMB_TCP_PKT_TS: - case MPMB_TCP_PKT_TC: - sgh_mpm_context = de_ctx->sgh_mpm_context_proto_tcp_packet; - break; - case MPMB_TCP_STREAM_TS: - case MPMB_TCP_STREAM_TC: - sgh_mpm_context = de_ctx->sgh_mpm_context_stream; - break; - case MPMB_UDP_TS: - case MPMB_UDP_TC: - sgh_mpm_context = de_ctx->sgh_mpm_context_proto_udp_packet; - break; - case MPMB_OTHERIP: - sgh_mpm_context = de_ctx->sgh_mpm_context_proto_other_packet; - break; - default: - break; - } - int dir = 0; - switch (ms->buffer) { - /* TS is 1 */ - case MPMB_TCP_PKT_TS: - case MPMB_TCP_STREAM_TS: - case MPMB_UDP_TS: - dir = 1; - break; - /* TC is 0 */ - default: - case MPMB_UDP_TC: - case MPMB_TCP_STREAM_TC: - case MPMB_TCP_PKT_TC: - case MPMB_OTHERIP: /**< use 0 for other */ + if (ms->buffer != MPMB_MAX) { + BUG_ON(ms->sm_list != DETECT_SM_LIST_PMATCH); + + switch (ms->buffer) { + /* TS is 1 */ + case MPMB_TCP_PKT_TS: + case MPMB_TCP_STREAM_TS: + case MPMB_UDP_TS: + dir = 1; + break; + + /* TC is 0 */ + default: + case MPMB_UDP_TC: + case MPMB_TCP_STREAM_TC: + case MPMB_TCP_PKT_TC: + case MPMB_OTHERIP: /**< use 0 for other */ + dir = 0; + break; + } + } else { + BUG_ON(ms->sm_list == DETECT_SM_LIST_PMATCH); + BUG_ON(ms->direction == 0); + BUG_ON(ms->direction == (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)); + + if (ms->direction == SIG_FLAG_TOSERVER) + dir = 1; + else dir = 0; - break; } if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, sgh_mpm_context, dir); + ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, ms->sgh_mpm_context, dir); } else { ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, dir); } @@ -1771,7 +1583,9 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) int list = SigMatchListSMBelongsTo(s, s->mpm_sm); if (list < 0) continue; - if (list != DETECT_SM_LIST_PMATCH) + if (list != ms->sm_list) + continue; + if ((s->flags & ms->direction) == 0) continue; SCLogDebug("adding %u", s->id); @@ -1797,25 +1611,34 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) PopulateMpmHelperAddPatternToPktCtx(ms->mpm_ctx, cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); - /* tell matcher we are inspecting packet */ -/* TODO remove! */ - if (!(ms->buffer == MPMB_TCP_STREAM_TC || ms->buffer == MPMB_TCP_STREAM_TS)) { - s->flags |= SIG_FLAG_MPM_PACKET; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_PACKET_NEG; + if (ms->buffer != MPMB_MAX) { + /* tell matcher we are inspecting packet */ + /* TODO remove! */ + if (!(ms->buffer == MPMB_TCP_STREAM_TC || ms->buffer == MPMB_TCP_STREAM_TS)) { + s->flags |= SIG_FLAG_MPM_PACKET; + s->mpm_pattern_id_div_8 = cd->id / 8; + s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); + if (cd->flags & DETECT_CONTENT_NEGATED) { + SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); + s->flags |= SIG_FLAG_MPM_PACKET_NEG; + } + } else { + /* tell matcher we are inspecting stream */ + s->flags |= SIG_FLAG_MPM_STREAM; + s->mpm_pattern_id_div_8 = cd->id / 8; + s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); + if (cd->flags & DETECT_CONTENT_NEGATED) { + SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); + s->flags |= SIG_FLAG_MPM_STREAM_NEG; + } } } else { - /* tell matcher we are inspecting stream */ - s->flags |= SIG_FLAG_MPM_STREAM; + /* tell matcher we are inspecting app-layer */ s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_STREAM_NEG; - } + s->flags |= SIG_FLAG_MPM_APPLAYER; + if (cd->flags & DETECT_CONTENT_NEGATED) + s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; } } } @@ -1848,6 +1671,27 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1; uint8_t sids_array[max_sid]; memset(sids_array, 0x00, max_sid); + int sgh_mpm_context = 0; + + switch (buf) { + case MPMB_TCP_PKT_TS: + case MPMB_TCP_PKT_TC: + sgh_mpm_context = de_ctx->sgh_mpm_context_proto_tcp_packet; + break; + case MPMB_TCP_STREAM_TS: + case MPMB_TCP_STREAM_TC: + sgh_mpm_context = de_ctx->sgh_mpm_context_stream; + break; + case MPMB_UDP_TS: + case MPMB_UDP_TC: + sgh_mpm_context = de_ctx->sgh_mpm_context_proto_udp_packet; + break; + case MPMB_OTHERIP: + sgh_mpm_context = de_ctx->sgh_mpm_context_proto_other_packet; + break; + default: + break; + } switch(buf) { case MPMB_TCP_PKT_TS: @@ -1920,7 +1764,7 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, if (cnt == 0) return NULL; - MpmStore lookup = { sids_array, max_sid, direction, buf, NULL}; + MpmStore lookup = { sids_array, max_sid, direction, buf, DETECT_SM_LIST_PMATCH, 0, NULL}; MpmStore *result = MpmStoreLookup(de_ctx, &lookup); if (result == NULL) { @@ -1938,6 +1782,8 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, copy->sid_array_size = max_sid; copy->buffer = buf; copy->direction = direction; + copy->sm_list = DETECT_SM_LIST_PMATCH; + copy->sgh_mpm_context = sgh_mpm_context; MpmStoreSetup(de_ctx, copy); MpmStoreAdd(de_ctx, copy); @@ -1947,706 +1793,192 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, } } -/** \brief Prepare the pattern matcher ctx in a sig group head. - * - * \todo determine if a content match can set the 'single' flag - * \todo do error checking - * \todo rewrite the COPY stuff - */ -int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) +MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, AppLayerMpms *am) { - MpmStore *mpm_store = NULL; - if (SGH_PROTO(sh, IPPROTO_TCP)) { - if (SGH_DIRECTION_TS(sh)) { - mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TS); - if (mpm_store != NULL) { - sh->mpm_proto_tcp_ctx_ts = mpm_store->mpm_ctx; - if (sh->mpm_proto_tcp_ctx_ts) - sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - } + const Signature *s = NULL; + uint32_t sig; + uint32_t cnt = 0; + uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1; + uint8_t sids_array[max_sid]; + memset(sids_array, 0x00, max_sid); - mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TS); - if (mpm_store != NULL) { - BUG_ON(mpm_store == NULL); - sh->mpm_stream_ctx_ts = mpm_store->mpm_ctx; - if (sh->mpm_stream_ctx_ts) - sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; - } - } - if (SGH_DIRECTION_TC(sh)) { - mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TC); - if (mpm_store != NULL) { - sh->mpm_proto_tcp_ctx_tc = mpm_store->mpm_ctx; - if (sh->mpm_proto_tcp_ctx_tc) - sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - } + SCLogDebug("handling %s direction %s for list %d", am->name, + am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", am->sm_list); - mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TC); - if (mpm_store != NULL) { - sh->mpm_stream_ctx_tc = mpm_store->mpm_ctx; - if (sh->mpm_stream_ctx_tc) - sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; - } - } - } else if (SGH_PROTO(sh, IPPROTO_UDP)) { - if (SGH_DIRECTION_TS(sh)) { - mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TS); - if (mpm_store != NULL) { - BUG_ON(mpm_store == NULL); - sh->mpm_proto_udp_ctx_ts = mpm_store->mpm_ctx; - - if (sh->mpm_proto_udp_ctx_ts != NULL) - sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - } - } - if (SGH_DIRECTION_TC(sh)) { - mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TC); - if (mpm_store != NULL) { - sh->mpm_proto_udp_ctx_tc = mpm_store->mpm_ctx; - - if (sh->mpm_proto_udp_ctx_tc != NULL) - sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - } - } - } else { - mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_OTHERIP); - if (mpm_store != NULL) { - sh->mpm_proto_other_ctx = mpm_store->mpm_ctx; - - if (sh->mpm_proto_other_ctx != NULL) - sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - } - } - - - - Signature *s = NULL; - uint32_t has_co_uri = 0; /**< our sgh has uri inspecting content */ - /* used to indicate if sgh has atleast one sig with http_client_body */ - uint32_t has_co_hcbd = 0; - /* used to indicate if sgh has atleast one sig with http_server_body */ - uint32_t has_co_hsbd = 0; - /* used to indicate if sgh has smtp file_data inspecting content */ - uint32_t has_co_smtp = 0; - /* used to indicate if sgh has atleast one sig with http_header */ - uint32_t has_co_hhd = 0; - /* used to indicate if sgh has atleast one sig with http_raw_header */ - uint32_t has_co_hrhd = 0; - /* used to indicate if sgh has atleast one sig with http_method */ - uint32_t has_co_hmd = 0; - /* used to indicate if sgh has atleast one sig with http_cookie */ - uint32_t has_co_hcd = 0; - /* used to indicate if sgh has atleast one sig with http_raw_uri */ - uint32_t has_co_hrud = 0; - /* used to indicate if sgh has atleast one sig with http_stat_msg */ - uint32_t has_co_hsmd = 0; - /* used to indicate if sgh has atleast one sig with http_stat_code */ - uint32_t has_co_hscd = 0; - /* used to indicate if sgh has atleast one sig with http_user_agent */ - uint32_t has_co_huad = 0; - /* used to indicate if sgh has atleast one sig with http_host */ - uint32_t has_co_hhhd = 0; - /* used to indicate if sgh has atleast one sig with http_raw_host */ - uint32_t has_co_hrhhd = 0; - //uint32_t cnt = 0; - uint32_t sig = 0; - /* sgh has at least one sig with dns_query */ - int has_co_dnsquery = 0; - - /* see if this head has content and/or uricontent */ - for (sig = 0; sig < sh->sig_cnt; sig++) { - s = sh->match_array[sig]; + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; if (s == NULL) continue; + if (s->mpm_sm == NULL) continue; int list = SigMatchListSMBelongsTo(s, s->mpm_sm); if (list < 0) continue; - if (list == DETECT_SM_LIST_PMATCH) - continue; - - - if (SGH_PROTO(sh, IPPROTO_TCP)) { - switch (list) { - case DETECT_SM_LIST_UMATCH: - has_co_uri = 1; - break; - - case DETECT_SM_LIST_HCBDMATCH: - has_co_hcbd = 1; - break; - - case DETECT_SM_LIST_FILEDATA: - if (s->alproto == ALPROTO_SMTP) - has_co_smtp = 1; - else if (s->alproto == ALPROTO_HTTP) - has_co_hsbd = 1; - else if (s->alproto == ALPROTO_UNKNOWN) { - has_co_smtp = 1; - has_co_hsbd = 1; - } - break; - - case DETECT_SM_LIST_HHDMATCH: - has_co_hhd = 1; - break; - - case DETECT_SM_LIST_HRHDMATCH: - has_co_hrhd = 1; - break; - - case DETECT_SM_LIST_HMDMATCH: - has_co_hmd = 1; - break; - case DETECT_SM_LIST_HCDMATCH: - has_co_hcd = 1; - break; - - case DETECT_SM_LIST_HRUDMATCH: - has_co_hrud = 1; - break; - - case DETECT_SM_LIST_HSMDMATCH: - has_co_hsmd = 1; - break; - - case DETECT_SM_LIST_HSCDMATCH: - has_co_hscd = 1; - break; - - case DETECT_SM_LIST_HUADMATCH: - has_co_huad = 1; - break; - - case DETECT_SM_LIST_HHHDMATCH: - has_co_hhhd = 1; - break; - - case DETECT_SM_LIST_HRHHDMATCH: - has_co_hrhhd = 1; - break; - - case DETECT_SM_LIST_DNSQUERYNAME_MATCH: - has_co_dnsquery = 1; - break; - - default: - BUG_ON(1); - } - - /* UDP */ - } else if (SGH_PROTO(sh, IPPROTO_UDP)) { - switch (list) { - case DETECT_SM_LIST_DNSQUERYNAME_MATCH: - has_co_dnsquery = 1; - break; - - default: - BUG_ON(1); - } - - /* all other protos just support PMATCH */ - } else { - switch (list) { - default: - BUG_ON(1); - } - } - } - - /* intialize contexes */ - if (has_co_uri) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_uri_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 0); - } else { - sh->mpm_uri_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_uri_ctx_ts == NULL) { - SCLogDebug("sh->mpm_uri_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - - MpmInitCtx(sh->mpm_uri_ctx_ts, de_ctx->mpm_matcher); - } - - if (has_co_hcbd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hcbd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 0); - } else { - sh->mpm_hcbd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_hcbd_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hcbd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - - MpmInitCtx(sh->mpm_hcbd_ctx_ts, de_ctx->mpm_matcher); - } - - if (has_co_hsbd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hsbd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsbd, 1); - } else { - sh->mpm_hsbd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_hsbd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hsbd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - - MpmInitCtx(sh->mpm_hsbd_ctx_tc, de_ctx->mpm_matcher); - } - - if (has_co_smtp) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_smtp_filedata_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_smtp, 0); - } else { - sh->mpm_smtp_filedata_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_smtp_filedata_ctx_ts == NULL) { - SCLogDebug("sh->mpm_smtp_filedata_ctx_ts == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - - MpmInitCtx(sh->mpm_smtp_filedata_ctx_ts, de_ctx->mpm_matcher); - } - - if (has_co_hhd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 0); - sh->mpm_hhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 1); - } else { - sh->mpm_hhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_hhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_hhd_ctx_ts == NULL || sh->mpm_hhd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hhd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - - MpmInitCtx(sh->mpm_hhd_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_hhd_ctx_tc, de_ctx->mpm_matcher); - } - - if (has_co_hrhd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hrhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 0); - sh->mpm_hrhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 1); - } else { - sh->mpm_hrhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_hrhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_hrhd_ctx_ts == NULL || sh->mpm_hrhd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hrhd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - - MpmInitCtx(sh->mpm_hrhd_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_hrhd_ctx_tc, de_ctx->mpm_matcher); - } - - if (has_co_hmd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hmd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 0); - } else { - sh->mpm_hmd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_hmd_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hmd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - - MpmInitCtx(sh->mpm_hmd_ctx_ts, de_ctx->mpm_matcher); - } + if ((s->flags & am->direction) == 0) + continue; - if (has_co_hcd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hcd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 0); - sh->mpm_hcd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 1); - } else { - sh->mpm_hcd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_hcd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_hcd_ctx_ts == NULL || sh->mpm_hcd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hcd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } + if (list != am->sm_list) + continue; - MpmInitCtx(sh->mpm_hcd_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_hcd_ctx_tc, de_ctx->mpm_matcher); + sids_array[s->num / 8] |= 1 << (s->num % 8); + cnt++; } - if (has_co_hrud) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hrud_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 0); - } else { - sh->mpm_hrud_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_hrud_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hrud_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } + if (cnt == 0) + return NULL; - MpmInitCtx(sh->mpm_hrud_ctx_ts, de_ctx->mpm_matcher); - } + MpmStore lookup = { sids_array, max_sid, am->direction, MPMB_MAX, am->sm_list, 0, NULL}; - if (has_co_hsmd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hsmd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 1); - } else { - sh->mpm_hsmd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_hsmd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hsmd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - - MpmInitCtx(sh->mpm_hsmd_ctx_tc, de_ctx->mpm_matcher); - } + MpmStore *result = MpmStoreLookup(de_ctx, &lookup); + if (result == NULL) { + SCLogDebug("new unique mpm for %s %s: %u patterns", + am->name, am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", cnt); - if (has_co_hscd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hscd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 1); - } else { - sh->mpm_hscd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_hscd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hscd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); + MpmStore *copy = SCCalloc(1, sizeof(MpmStore)); + if (copy == NULL) + return NULL; + uint8_t *sids = SCCalloc(1, max_sid); + if (sids == NULL) { + SCFree(copy); + return NULL; } - MpmInitCtx(sh->mpm_hscd_ctx_tc, de_ctx->mpm_matcher); - } - - if (has_co_huad) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_huad_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 0); - } else { - sh->mpm_huad_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_huad_ctx_ts == NULL) { - SCLogDebug("sh->mpm_huad_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } + memcpy(sids, sids_array, max_sid); + copy->sid_array = sids; + copy->sid_array_size = max_sid; + copy->buffer = MPMB_MAX; + copy->direction = am->direction; + copy->sm_list = am->sm_list; + copy->sgh_mpm_context = am->sgh_mpm_context; - MpmInitCtx(sh->mpm_huad_ctx_ts, de_ctx->mpm_matcher); + MpmStoreSetup(de_ctx, copy); + MpmStoreAdd(de_ctx, copy); + return copy; + } else { + return result; } + return NULL; +} - if (has_co_hhhd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhhd, 0); - } else { - sh->mpm_hhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_hhhd_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hhhd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } +/** \todo fixup old mpm ptrs. We could use the array directly later */ +void MpmStoreFixup(SigGroupHead *sgh) +{ + int i = 0; + sgh->mpm_uri_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_hrud_ctx_ts = sgh->app_mpms[i++]; - MpmInitCtx(sh->mpm_hhhd_ctx_ts, de_ctx->mpm_matcher); - } + sgh->mpm_hhd_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_hhd_ctx_tc = sgh->app_mpms[i++]; - if (has_co_hrhhd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hrhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhhd, 0); - } else { - sh->mpm_hrhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_hrhhd_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hrhhd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } + sgh->mpm_huad_ctx_ts = sgh->app_mpms[i++]; - MpmInitCtx(sh->mpm_hrhhd_ctx_ts, de_ctx->mpm_matcher); - } + sgh->mpm_hrhd_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_hrhd_ctx_tc = sgh->app_mpms[i++]; - if (has_co_dnsquery) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_dnsquery_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_dnsquery, 0); - } else { - sh->mpm_dnsquery_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_dnsquery_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hrhhd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } + sgh->mpm_hmd_ctx_ts = sgh->app_mpms[i++]; - MpmInitCtx(sh->mpm_dnsquery_ctx_ts, de_ctx->mpm_matcher); - } - - if (has_co_uri || - has_co_hcbd || - has_co_hsbd || - has_co_smtp || - has_co_hhd || - has_co_hrhd || - has_co_hmd || - has_co_hcd || - has_co_hsmd || - has_co_hscd || - has_co_hrud || - has_co_huad || - has_co_hhhd || - has_co_hrhhd || - has_co_dnsquery) - { - /* add the patterns of all the rules to the mpms of this sgh */ - PatternMatchPreparePopulateMpm(de_ctx, sh); + sgh->mpm_smtp_filedata_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_hsbd_ctx_tc = sgh->app_mpms[i++]; - if (sh->mpm_uri_ctx_ts != NULL) { - if (sh->mpm_uri_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_ts); - sh->mpm_uri_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_uri_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_uri_ctx_ts->mpm_type].Prepare(sh->mpm_uri_ctx_ts); - } - } - } + sgh->mpm_hsmd_ctx_tc = sgh->app_mpms[i++]; + sgh->mpm_hscd_ctx_tc = sgh->app_mpms[i++]; - if (sh->mpm_hcbd_ctx_ts != NULL) { - if (sh->mpm_hcbd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_ts); - sh->mpm_hcbd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].Prepare(sh->mpm_hcbd_ctx_ts); - } - } - } + sgh->mpm_hcbd_ctx_ts = sgh->app_mpms[i++]; - if (sh->mpm_hsbd_ctx_tc != NULL) { - if (sh->mpm_hsbd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsbd_ctx_tc); - sh->mpm_hsbd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].Prepare(sh->mpm_hsbd_ctx_tc); - } - } - } + sgh->mpm_hhhd_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_hrhhd_ctx_ts = sgh->app_mpms[i++]; - if (sh->mpm_smtp_filedata_ctx_ts != NULL) { - if (sh->mpm_smtp_filedata_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_smtp_filedata_ctx_ts); - sh->mpm_smtp_filedata_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_smtp_filedata_ctx_ts->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_smtp_filedata_ctx_ts->mpm_type].Prepare(sh->mpm_smtp_filedata_ctx_ts); - } - } - } - } + sgh->mpm_hcd_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_hcd_ctx_tc = sgh->app_mpms[i++]; - if (sh->mpm_hhd_ctx_ts != NULL) { - if (sh->mpm_hhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_ts); - sh->mpm_hhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].Prepare(sh->mpm_hhd_ctx_ts); - } - } - } - if (sh->mpm_hhd_ctx_tc != NULL) { - if (sh->mpm_hhd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_tc); - sh->mpm_hhd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].Prepare(sh->mpm_hhd_ctx_tc); - } - } - } + sgh->mpm_dnsquery_ctx_ts = sgh->app_mpms[i++]; - if (sh->mpm_hrhd_ctx_ts != NULL) { - if (sh->mpm_hrhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_ts); - sh->mpm_hrhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].Prepare(sh->mpm_hrhd_ctx_ts); - } - } - } - if (sh->mpm_hrhd_ctx_tc != NULL) { - if (sh->mpm_hrhd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_tc); - sh->mpm_hrhd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].Prepare(sh->mpm_hrhd_ctx_tc); - } - } - } - - if (sh->mpm_hmd_ctx_ts != NULL) { - if (sh->mpm_hmd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hmd_ctx_ts); - sh->mpm_hmd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].Prepare(sh->mpm_hmd_ctx_ts); - } - } - } + BUG_ON(APP_MPMS_MAX != 18 || i != 18); +} - if (sh->mpm_hcd_ctx_ts != NULL) { - if (sh->mpm_hcd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_ts); - sh->mpm_hcd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].Prepare(sh->mpm_hcd_ctx_ts); - } - } - } - if (sh->mpm_hcd_ctx_tc != NULL) { - if (sh->mpm_hcd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_tc); - sh->mpm_hcd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].Prepare(sh->mpm_hcd_ctx_tc); - } +/** \brief Prepare the pattern matcher ctx in a sig group head. + * + */ +int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) +{ + MpmStore *mpm_store = NULL; + if (SGH_PROTO(sh, IPPROTO_TCP)) { + if (SGH_DIRECTION_TS(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TS); + if (mpm_store != NULL) { + sh->mpm_proto_tcp_ctx_ts = mpm_store->mpm_ctx; + if (sh->mpm_proto_tcp_ctx_ts) + sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } - } - if (sh->mpm_hrud_ctx_ts != NULL) { - if (sh->mpm_hrud_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrud_ctx_ts); - sh->mpm_hrud_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].Prepare(sh->mpm_hrud_ctx_ts); - } + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TS); + if (mpm_store != NULL) { + BUG_ON(mpm_store == NULL); + sh->mpm_stream_ctx_ts = mpm_store->mpm_ctx; + if (sh->mpm_stream_ctx_ts) + sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; } } - - if (sh->mpm_hsmd_ctx_tc != NULL) { - if (sh->mpm_hsmd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsmd_ctx_tc); - sh->mpm_hsmd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].Prepare(sh->mpm_hsmd_ctx_tc); - } + if (SGH_DIRECTION_TC(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TC); + if (mpm_store != NULL) { + sh->mpm_proto_tcp_ctx_tc = mpm_store->mpm_ctx; + if (sh->mpm_proto_tcp_ctx_tc) + sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } - } - if (sh->mpm_hscd_ctx_tc != NULL) { - if (sh->mpm_hscd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hscd_ctx_tc); - sh->mpm_hscd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].Prepare(sh->mpm_hscd_ctx_tc); - } + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TC); + if (mpm_store != NULL) { + sh->mpm_stream_ctx_tc = mpm_store->mpm_ctx; + if (sh->mpm_stream_ctx_tc) + sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; } - } + } + } else if (SGH_PROTO(sh, IPPROTO_UDP)) { + if (SGH_DIRECTION_TS(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TS); + if (mpm_store != NULL) { + BUG_ON(mpm_store == NULL); + sh->mpm_proto_udp_ctx_ts = mpm_store->mpm_ctx; - if (sh->mpm_huad_ctx_ts != NULL) { - if (sh->mpm_huad_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_huad_ctx_ts); - sh->mpm_huad_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare(sh->mpm_huad_ctx_ts); - } + if (sh->mpm_proto_udp_ctx_ts != NULL) + sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } } + if (SGH_DIRECTION_TC(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TC); + if (mpm_store != NULL) { + sh->mpm_proto_udp_ctx_tc = mpm_store->mpm_ctx; - if (sh->mpm_hhhd_ctx_ts != NULL) { - if (sh->mpm_hhhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhhd_ctx_ts); - sh->mpm_hhhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hhhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hhhd_ctx_ts->mpm_type].Prepare(sh->mpm_hhhd_ctx_ts); - } + if (sh->mpm_proto_udp_ctx_tc != NULL) + sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } } + } else { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_OTHERIP); + if (mpm_store != NULL) { + sh->mpm_proto_other_ctx = mpm_store->mpm_ctx; - if (sh->mpm_hrhhd_ctx_ts != NULL) { - if (sh->mpm_hrhhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_ts); - sh->mpm_hrhhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrhhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrhhd_ctx_ts->mpm_type].Prepare(sh->mpm_hrhhd_ctx_ts); - } - } + if (sh->mpm_proto_other_ctx != NULL) + sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } + } - if (sh->mpm_dnsquery_ctx_ts != NULL) { - if (sh->mpm_dnsquery_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_dnsquery_ctx_ts); - sh->mpm_dnsquery_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].Prepare(sh->mpm_dnsquery_ctx_ts); - } - } + AppLayerMpms *a = app_mpms; + while (a->name != NULL) { + mpm_store = MpmStorePrepareBuffer2(de_ctx, sh, a); + if (mpm_store != NULL) { + sh->app_mpms[a->id] = mpm_store->mpm_ctx; + if (sh->app_mpms[a->id] != NULL) + sh->flags |= a->flags; } - } else { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_ts); - sh->mpm_uri_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_ts); - sh->mpm_hcbd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_ts); - sh->mpm_hhd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_ts); - sh->mpm_hrhd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hmd_ctx_ts); - sh->mpm_hmd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_ts); - sh->mpm_hcd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrud_ctx_ts); - sh->mpm_hrud_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_huad_ctx_ts); - sh->mpm_huad_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhhd_ctx_ts); - sh->mpm_hhhd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_ts); - sh->mpm_hrhhd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_dnsquery_ctx_ts); - sh->mpm_dnsquery_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_smtp_filedata_ctx_ts); - sh->mpm_smtp_filedata_ctx_ts = NULL; - - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_tc); - sh->mpm_hhd_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_tc); - sh->mpm_hrhd_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_tc); - sh->mpm_hcd_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsmd_ctx_tc); - sh->mpm_hsmd_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hscd_ctx_tc); - sh->mpm_hscd_ctx_tc = NULL; + a++; } + MpmStoreFixup(sh); return 0; } diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 235b96da08f4..4cbc0fbe8068 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -32,6 +32,9 @@ #include "stream.h" +void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx); +void DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx); + uint16_t PatternMatchDefaultMatcher(void); uint32_t PatternStrength(uint8_t *, uint16_t); diff --git a/src/detect.c b/src/detect.c index 1abf9d5459fc..23df4b30eb2b 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2732,54 +2732,14 @@ static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) de_ctx->sgh_mpm_context_proto_other_packet = MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_other", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_uri = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "uri", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_stream = MpmFactoryRegisterMpmCtxProfile(de_ctx, "stream", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hcbd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hcbd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hsbd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hsbd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_smtp = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "smtp", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hhd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hhd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hrhd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hrhd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hmd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hmd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hcd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hcd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hrud = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hrud", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hsmd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hsmd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hscd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hscd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_huad = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "huad", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hhhd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hhhd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hrhhd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hrhhd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_app_proto_detect = MpmFactoryRegisterMpmCtxProfile(de_ctx, "app_proto_detect", 0); + DetectMpmInitializeAppMpms(de_ctx); + return; } @@ -3690,7 +3650,6 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) } } #endif - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); @@ -3717,96 +3676,6 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) } //printf("packet- %d\n", mpm_ctx->pattern_cnt); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("uri- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hcbd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsbd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsbd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hsbd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_smtp, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_smtp, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("smtp- %d\n"; mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hhd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hrhd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hmd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hcd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hrud- %d\n", mpm_ctx->pattern_cnt); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); @@ -3817,62 +3686,7 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) } //printf("stream- %d\n", mpm_ctx->pattern_cnt); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hsmd- %d\n", mpm_ctx->pattern_cnt); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hsmd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hscd- %d\n", mpm_ctx->pattern_cnt); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hscd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("huad- %d\n", mpm_ctx->pattern_cnt); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("huad- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhhd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hhhd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhhd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hhhd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhhd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hrhhd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhhd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hrhhd- %d\n", mpm_ctx->pattern_cnt); + DetectMpmPrepareAppMpms(de_ctx); #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) { diff --git a/src/detect.h b/src/detect.h index e1c441b0dafd..5ca200f82dad 100644 --- a/src/detect.h +++ b/src/detect.h @@ -655,22 +655,7 @@ typedef struct DetectEngineCtx_ { 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; - int32_t sgh_mpm_context_smtp; /* the max local id used amongst all sigs */ int32_t byte_extract_max_local_id; @@ -959,6 +944,8 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 23) #define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 24) +#define APP_MPMS_MAX 18 + enum MpmBuiltinBuffers { MPMB_TCP_PKT_TS, MPMB_TCP_PKT_TC, @@ -976,6 +963,8 @@ typedef struct MpmStore_ { int direction; enum MpmBuiltinBuffers buffer; + int sm_list; + int32_t sgh_mpm_context; MpmCtx *mpm_ctx; @@ -1055,6 +1044,8 @@ typedef struct SigGroupHead_ { /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ Signature **match_array; + MpmCtx *app_mpms[APP_MPMS_MAX]; + /* ptr to our init data we only use at... init :) */ SigGroupHeadInitData *init; } SigGroupHead; diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 8cf31fcd9c1e..341ac5079fc7 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -1550,197 +1550,9 @@ void DetermineCudaStateTableSize(DetectEngineCtx *de_ctx) ac_32_tables++; } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - if (ac_16_tables > 0 && ac_32_tables > 0) SCACConstructBoth16and32StateTables(); - SCLogDebug("Total mpm ac 16 bit state tables - %d\n", ac_16_tables); SCLogDebug("Total mpm ac 32 bit state tables - %d\n", ac_32_tables); From 26517b8b61d69ac21ef2d48ee8301639be005ec2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 6 Oct 2015 15:04:33 +0200 Subject: [PATCH 1165/2553] detect: mpm store frees mpm_ctx' it owns --- src/detect-engine-mpm.c | 265 +++-------------------------------- src/detect-engine-mpm.h | 1 - src/detect-engine-siggroup.c | 2 - src/detect.c | 1 - 4 files changed, 18 insertions(+), 251 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 6bed2e556ee0..6dbdedc0d06b 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -895,252 +895,6 @@ void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matche MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher); } - -/* free the pattern matcher part of a SigGroupHead */ -void PatternMatchDestroyGroup(SigGroupHead *sh) -{ - /* content */ - if (!(sh->flags & SIG_GROUP_HEAD_MPM_COPY)) { - if (sh->mpm_proto_tcp_ctx_ts != NULL && - !sh->mpm_proto_tcp_ctx_ts->global) - { - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_tcp_ctx_ts, sh); - mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type]. - DestroyCtx(sh->mpm_proto_tcp_ctx_ts); - SCFree(sh->mpm_proto_tcp_ctx_ts); - } - /* ready for reuse */ - sh->mpm_proto_tcp_ctx_ts = NULL; - - if (sh->mpm_proto_tcp_ctx_tc != NULL && - !sh->mpm_proto_tcp_ctx_tc->global) - { - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_tcp_ctx_tc, sh); - mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type]. - DestroyCtx(sh->mpm_proto_tcp_ctx_tc); - SCFree(sh->mpm_proto_tcp_ctx_tc); - } - /* ready for reuse */ - sh->mpm_proto_tcp_ctx_tc = NULL; - - if (sh->mpm_proto_udp_ctx_ts != NULL && - !sh->mpm_proto_udp_ctx_ts->global) - { - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_udp_ctx_ts, sh); - mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type]. - DestroyCtx(sh->mpm_proto_udp_ctx_ts); - SCFree(sh->mpm_proto_udp_ctx_ts); - } - /* ready for reuse */ - sh->mpm_proto_udp_ctx_ts = NULL; - - if (sh->mpm_proto_udp_ctx_tc != NULL && - !sh->mpm_proto_udp_ctx_tc->global) - { - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_udp_ctx_tc, sh); - mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type]. - DestroyCtx(sh->mpm_proto_udp_ctx_tc); - SCFree(sh->mpm_proto_udp_ctx_tc); - } - /* ready for reuse */ - sh->mpm_proto_udp_ctx_tc = NULL; - - if (sh->mpm_proto_other_ctx != NULL && - !sh->mpm_proto_other_ctx->global) - { - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_other_ctx, sh); - mpm_table[sh->mpm_proto_other_ctx->mpm_type]. - DestroyCtx(sh->mpm_proto_other_ctx); - SCFree(sh->mpm_proto_other_ctx); - } - /* ready for reuse */ - sh->mpm_proto_other_ctx = NULL; - } - - /* uricontent */ - if ((sh->mpm_uri_ctx_ts != NULL) && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) { - if (sh->mpm_uri_ctx_ts != NULL) { - if (!sh->mpm_uri_ctx_ts->global) { - SCLogDebug("destroying mpm_uri_ctx %p (sh %p)", sh->mpm_uri_ctx_ts, sh); - mpm_table[sh->mpm_uri_ctx_ts->mpm_type].DestroyCtx(sh->mpm_uri_ctx_ts); - SCFree(sh->mpm_uri_ctx_ts); - } - /* ready for reuse */ - sh->mpm_uri_ctx_ts = NULL; - } - } - - /* stream content */ - if ((sh->mpm_stream_ctx_ts != NULL || sh->mpm_stream_ctx_tc != NULL) && - !(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)) { - if (sh->mpm_stream_ctx_ts != NULL) { - if (!sh->mpm_stream_ctx_ts->global) { - SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx_ts, sh); - mpm_table[sh->mpm_stream_ctx_ts->mpm_type].DestroyCtx(sh->mpm_stream_ctx_ts); - SCFree(sh->mpm_stream_ctx_ts); - } - /* ready for reuse */ - sh->mpm_stream_ctx_ts = NULL; - } - if (sh->mpm_stream_ctx_tc != NULL) { - if (!sh->mpm_stream_ctx_tc->global) { - SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx_tc, sh); - mpm_table[sh->mpm_stream_ctx_tc->mpm_type].DestroyCtx(sh->mpm_stream_ctx_tc); - SCFree(sh->mpm_stream_ctx_tc); - } - /* ready for reuse */ - sh->mpm_stream_ctx_tc = NULL; - } - } - - if (sh->mpm_hcbd_ctx_ts != NULL) { - if (sh->mpm_hcbd_ctx_ts != NULL) { - if (!sh->mpm_hcbd_ctx_ts->global) { - mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hcbd_ctx_ts); - SCFree(sh->mpm_hcbd_ctx_ts); - } - sh->mpm_hcbd_ctx_ts = NULL; - } - } - - if (sh->mpm_hsbd_ctx_tc != NULL) { - if (sh->mpm_hsbd_ctx_tc != NULL) { - if (!sh->mpm_hsbd_ctx_tc->global) { - mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hsbd_ctx_tc); - SCFree(sh->mpm_hsbd_ctx_tc); - } - sh->mpm_hsbd_ctx_tc = NULL; - } - } - - if (sh->mpm_smtp_filedata_ctx_ts != NULL) { - if (sh->mpm_smtp_filedata_ctx_ts != NULL) { - if (!sh->mpm_smtp_filedata_ctx_ts->global) { - mpm_table[sh->mpm_smtp_filedata_ctx_ts->mpm_type].DestroyCtx(sh->mpm_smtp_filedata_ctx_ts); - SCFree(sh->mpm_smtp_filedata_ctx_ts); - } - sh->mpm_smtp_filedata_ctx_ts = NULL; - } - } - - if (sh->mpm_hhd_ctx_ts != NULL || sh->mpm_hhd_ctx_tc != NULL) { - if (sh->mpm_hhd_ctx_ts != NULL) { - if (!sh->mpm_hhd_ctx_ts->global) { - mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hhd_ctx_ts); - SCFree(sh->mpm_hhd_ctx_ts); - } - sh->mpm_hhd_ctx_ts = NULL; - } - if (sh->mpm_hhd_ctx_tc != NULL) { - if (!sh->mpm_hhd_ctx_tc->global) { - mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hhd_ctx_tc); - SCFree(sh->mpm_hhd_ctx_tc); - } - sh->mpm_hhd_ctx_tc = NULL; - } - } - - if (sh->mpm_hrhd_ctx_ts != NULL || sh->mpm_hrhd_ctx_tc != NULL) { - if (sh->mpm_hrhd_ctx_ts != NULL) { - if (!sh->mpm_hrhd_ctx_ts->global) { - mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hrhd_ctx_ts); - SCFree(sh->mpm_hrhd_ctx_ts); - } - sh->mpm_hrhd_ctx_ts = NULL; - } - if (sh->mpm_hrhd_ctx_tc != NULL) { - if (!sh->mpm_hrhd_ctx_tc->global) { - mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hrhd_ctx_tc); - SCFree(sh->mpm_hrhd_ctx_tc); - } - sh->mpm_hrhd_ctx_tc = NULL; - } - } - - if (sh->mpm_hmd_ctx_ts != NULL) { - if (sh->mpm_hmd_ctx_ts != NULL) { - if (!sh->mpm_hmd_ctx_ts->global) { - mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hmd_ctx_ts); - SCFree(sh->mpm_hmd_ctx_ts); - } - sh->mpm_hmd_ctx_ts = NULL; - } - } - - if (sh->mpm_hcd_ctx_ts != NULL || sh->mpm_hcd_ctx_tc != NULL) { - if (sh->mpm_hcd_ctx_ts != NULL) { - if (!sh->mpm_hcd_ctx_ts->global) { - mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hcd_ctx_ts); - SCFree(sh->mpm_hcd_ctx_ts); - } - sh->mpm_hcd_ctx_ts = NULL; - } - if (sh->mpm_hcd_ctx_tc != NULL) { - if (!sh->mpm_hcd_ctx_tc->global) { - mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hcd_ctx_tc); - SCFree(sh->mpm_hcd_ctx_tc); - } - sh->mpm_hcd_ctx_tc = NULL; - } - } - - if (sh->mpm_hrud_ctx_ts != NULL) { - if (sh->mpm_hrud_ctx_ts != NULL) { - if (!sh->mpm_hrud_ctx_ts->global) { - mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hrud_ctx_ts); - SCFree(sh->mpm_hrud_ctx_ts); - } - sh->mpm_hrud_ctx_ts = NULL; - } - } - - if (sh->mpm_hsmd_ctx_tc != NULL) { - if (sh->mpm_hsmd_ctx_tc != NULL) { - if (!sh->mpm_hsmd_ctx_tc->global) { - mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hsmd_ctx_tc); - SCFree(sh->mpm_hsmd_ctx_tc); - } - sh->mpm_hsmd_ctx_tc = NULL; - } - } - - if (sh->mpm_hscd_ctx_tc != NULL) { - if (sh->mpm_hscd_ctx_tc != NULL) { - if (!sh->mpm_hscd_ctx_tc->global) { - mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hscd_ctx_tc); - SCFree(sh->mpm_hscd_ctx_tc); - } - sh->mpm_hscd_ctx_tc = NULL; - } - } - - if (sh->mpm_huad_ctx_ts != NULL) { - if (sh->mpm_huad_ctx_ts != NULL) { - if (!sh->mpm_huad_ctx_ts->global) { - mpm_table[sh->mpm_huad_ctx_ts->mpm_type].DestroyCtx(sh->mpm_huad_ctx_ts); - SCFree(sh->mpm_huad_ctx_ts); - } - sh->mpm_huad_ctx_ts = NULL; - } - } - - /* dns query */ - if (sh->mpm_dnsquery_ctx_ts != NULL) { - if (!sh->mpm_dnsquery_ctx_ts->global) { - mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].DestroyCtx(sh->mpm_dnsquery_ctx_ts); - SCFree(sh->mpm_dnsquery_ctx_ts); - } - sh->mpm_dnsquery_ctx_ts = NULL; - } - - return; -} - /** \brief Predict a strength value for patterns * * Patterns with high character diversity score higher. @@ -1408,6 +1162,23 @@ static char MpmStoreCompareFunc(void *data1, uint16_t len1, void *data2, return 1; } +static void MpmStoreFreeFunc(void *ptr) +{ + MpmStore *ms = ptr; + if (ms != NULL) { + if (ms->mpm_ctx != NULL && !ms->mpm_ctx->global) + { + SCLogDebug("destroying mpm_ctx %p", ms->mpm_ctx); + mpm_table[ms->mpm_ctx->mpm_type].DestroyCtx(ms->mpm_ctx); + SCFree(ms->mpm_ctx); + } + ms->mpm_ctx = NULL; + + SCFree(ms->sid_array); + SCFree(ms); + } +} + /** * \brief Initializes the MpmStore mpm hash table to be used by the detection * engine context. @@ -1422,7 +1193,7 @@ int MpmStoreInit(DetectEngineCtx *de_ctx) de_ctx->mpm_hash_table = HashListTableInit(4096, MpmStoreHashFunc, MpmStoreCompareFunc, - NULL); + MpmStoreFreeFunc); if (de_ctx->mpm_hash_table == NULL) goto error; diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 4cbc0fbe8068..9984791c2679 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -69,7 +69,6 @@ void PatternMatchThreadPrint(MpmThreadCtx *, uint16_t); int PatternMatchPrepareGroup(DetectEngineCtx *, SigGroupHead *); void DetectEngineThreadCtxInfo(ThreadVars *, DetectEngineThreadCtx *); -void PatternMatchDestroyGroup(SigGroupHead *); TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **); TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *); diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 9d04697cc937..1ec12111e750 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -173,8 +173,6 @@ void SigGroupHeadFree(SigGroupHead *sgh) SCLogDebug("sgh %p", sgh); - PatternMatchDestroyGroup(sgh); - if (sgh->match_array != NULL) { detect_siggroup_matcharray_free_cnt++; detect_siggroup_matcharray_memory -= (sgh->sig_cnt * sizeof(Signature *)); diff --git a/src/detect.c b/src/detect.c index 23df4b30eb2b..4a63c4d39f05 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3526,7 +3526,6 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) * after the initialization phase. */ SigGroupHeadHashFree(de_ctx); SigGroupHeadDPortHashFree(de_ctx); - MpmStoreFree(de_ctx); SCFree(de_ctx->sgh_array); de_ctx->sgh_array_cnt = 0; From e48d745ed71d6a14bfca1b13d088c041a70c9174 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 7 Oct 2015 06:48:44 +0200 Subject: [PATCH 1166/2553] mpm: constify search func args --- src/detect-engine-mpm.c | 4 +- src/detect.h | 54 ++++++++++++------------ src/util-bloomfilter.c | 5 ++- src/util-bloomfilter.h | 8 ++-- src/util-mpm-ac-bs.c | 10 ++--- src/util-mpm-ac-tile-small.c | 6 +-- src/util-mpm-ac-tile.c | 80 ++++++++++++++++++------------------ src/util-mpm-ac-tile.h | 8 ++-- src/util-mpm-ac.c | 14 +++---- src/util-mpm-ac.h | 2 +- src/util-mpm-hs.c | 8 ++-- src/util-mpm.h | 2 +- 12 files changed, 101 insertions(+), 100 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 6dbdedc0d06b..036ed2899c3f 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -259,7 +259,7 @@ uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret = 0; - MpmCtx *mpm_ctx = NULL; + const MpmCtx *mpm_ctx = NULL; if (p->flowflags & FLOW_PKT_TOSERVER) { DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_ts == NULL); @@ -294,7 +294,7 @@ uint32_t PacketPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p) SCEnter(); uint32_t ret; - MpmCtx *mpm_ctx = NULL; + const MpmCtx *mpm_ctx = NULL; if (p->proto == IPPROTO_TCP) { if (p->flowflags & FLOW_PKT_TOSERVER) { diff --git a/src/detect.h b/src/detect.h index 5ca200f82dad..afef28f54745 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1007,33 +1007,33 @@ typedef struct SigGroupHead_ { uint32_t non_mpm_store_cnt; /* 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_smtp_filedata_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; + const MpmCtx *mpm_proto_other_ctx; + + const MpmCtx *mpm_proto_tcp_ctx_ts; + const MpmCtx *mpm_proto_udp_ctx_ts; + const MpmCtx *mpm_stream_ctx_ts; + const MpmCtx *mpm_uri_ctx_ts; + const MpmCtx *mpm_hcbd_ctx_ts; + const MpmCtx *mpm_hhd_ctx_ts; + const MpmCtx *mpm_hrhd_ctx_ts; + const MpmCtx *mpm_hmd_ctx_ts; + const MpmCtx *mpm_hcd_ctx_ts; + const MpmCtx *mpm_hrud_ctx_ts; + const MpmCtx *mpm_huad_ctx_ts; + const MpmCtx *mpm_hhhd_ctx_ts; + const MpmCtx *mpm_hrhhd_ctx_ts; + const MpmCtx *mpm_dnsquery_ctx_ts; + const MpmCtx *mpm_smtp_filedata_ctx_ts; + + const MpmCtx *mpm_proto_tcp_ctx_tc; + const MpmCtx *mpm_proto_udp_ctx_tc; + const MpmCtx *mpm_stream_ctx_tc; + const MpmCtx *mpm_hsbd_ctx_tc; + const MpmCtx *mpm_hhd_ctx_tc; + const MpmCtx *mpm_hrhd_ctx_tc; + const MpmCtx *mpm_hcd_ctx_tc; + const MpmCtx *mpm_hsmd_ctx_tc; + const MpmCtx *mpm_hscd_ctx_tc; uint16_t mpm_uricontent_minlen; /**< len of shortest mpm pattern in sgh */ diff --git a/src/util-bloomfilter.c b/src/util-bloomfilter.c index 5718fb1002c6..8dcd7a310b8d 100644 --- a/src/util-bloomfilter.c +++ b/src/util-bloomfilter.c @@ -27,7 +27,8 @@ #include "util-bloomfilter.h" #include "util-unittest.h" -BloomFilter *BloomFilterInit(uint32_t size, uint8_t iter, uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t)) { +BloomFilter *BloomFilterInit(uint32_t size, uint8_t iter, + uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)) { BloomFilter *bf = NULL; if (size == 0 || iter == 0) @@ -122,7 +123,7 @@ uint32_t BloomFilterMemorySize(BloomFilter *bf) */ #ifdef UNITTESTS -static uint32_t BloomFilterTestHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) +static uint32_t BloomFilterTestHash(const void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint32_t i; diff --git a/src/util-bloomfilter.h b/src/util-bloomfilter.h index e7a5874f612d..59b5dcdca5ab 100644 --- a/src/util-bloomfilter.h +++ b/src/util-bloomfilter.h @@ -27,13 +27,13 @@ /* Bloom Filter structure */ typedef struct BloomFilter_ { uint8_t hash_iterations; - uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t); + uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t); uint32_t bitarray_size; uint8_t *bitarray; } BloomFilter; /* prototypes */ -BloomFilter *BloomFilterInit(uint32_t, uint8_t, uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t)); +BloomFilter *BloomFilterInit(uint32_t, uint8_t, uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)); void BloomFilterFree(BloomFilter *); void BloomFilterPrint(BloomFilter *); int BloomFilterAdd(BloomFilter *, void *, uint16_t); @@ -44,9 +44,9 @@ void BloomFilterRegisterTests(void); /** ----- Inline functions ---- */ -static inline int BloomFilterTest(BloomFilter *, void *, uint16_t); +static inline int BloomFilterTest(const BloomFilter *, const void *, uint16_t); -static inline int BloomFilterTest(BloomFilter *bf, void *data, uint16_t datalen) +static inline int BloomFilterTest(const BloomFilter *bf, const void *data, uint16_t datalen) { uint8_t iter = 0; uint32_t hash = 0; diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 07227b572672..23c37e8d03a2 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -69,8 +69,8 @@ int SCACBSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, int SCACBSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int SCACBSPreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); +uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen); void SCACBSPrintInfo(MpmCtx *mpm_ctx); void SCACBSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACBSRegisterTests(void); @@ -1421,10 +1421,10 @@ void SCACBSDestroyCtx(MpmCtx *mpm_ctx) * * \retval matches Match count. */ -uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) +uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen) { - SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; + const SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int i = 0; int matches = 0; uint8_t buf_local; diff --git a/src/util-mpm-ac-tile-small.c b/src/util-mpm-ac-tile-small.c index d37d982e0113..0a875778d643 100644 --- a/src/util-mpm-ac-tile-small.c +++ b/src/util-mpm-ac-tile-small.c @@ -31,8 +31,8 @@ #ifdef FUNC_NAME /* This function handles (ctx->state_count < 32767) */ -uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) +uint32_t FUNC_NAME(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen) { int i = 0; int matches = 0; @@ -40,7 +40,7 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, uint8_t mpm_bitarray[ctx->mpm_bitarray_size]; memset(mpm_bitarray, 0, ctx->mpm_bitarray_size); - uint8_t* restrict xlate = ctx->translate_table; + const uint8_t* restrict xlate = ctx->translate_table; STYPE *state_table = (STYPE*)ctx->state_table; STYPE state = 0; int c = xlate[buf[0]]; diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 2230cb3f2813..f0d873b6c1f8 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -89,53 +89,53 @@ int SCACTileAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, int SCACTileAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int SCACTilePreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCACTileSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, +uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen); void SCACTilePrintInfo(MpmCtx *mpm_ctx); void SCACTilePrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACTileRegisterTests(void); -uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, +uint32_t SCACTileSearchLarge(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall256(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall256(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall128(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall128(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall64(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall64(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall32(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall32(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall16(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall16(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall8(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall8(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); + const uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny256(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny128(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny64(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, +uint32_t SCACTileSearchTiny256(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny32(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchTiny128(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny16(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny8(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchTiny64(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchTiny32(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchTiny16(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchTiny8(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, + const uint8_t *buf, uint16_t buflen); static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx); @@ -1490,13 +1490,13 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) #define EXTRA 4 // need 4 extra bytes to avoid OOB reads #endif -int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen, +int CheckMatch(const SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, + const uint8_t *buf, uint16_t buflen, uint16_t state, int i, int matches, uint8_t *mpm_bitarray) { SCACTilePatternList *pattern_list = ctx->pattern_list; - uint8_t *buf_offset = buf + i + 1; // Lift out of loop + const uint8_t *buf_offset = buf + i + 1; // Lift out of loop uint32_t no_of_entries = ctx->output_table[state].no_of_entries; MpmPatternIndex *patterns = ctx->output_table[state].patterns; uint8_t *pmq_bitarray = pmq->pattern_id_bitarray; @@ -1559,10 +1559,10 @@ int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, * * \retval matches Match count. */ -uint32_t SCACTileSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) +uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen) { - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + const SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; if (buflen == 0) return 0; @@ -1572,9 +1572,9 @@ uint32_t SCACTileSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } /* This function handles (ctx->state_count >= 32767) */ -uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, +uint32_t SCACTileSearchLarge(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen) + const uint8_t *buf, uint16_t buflen) { int i = 0; int matches = 0; @@ -1582,7 +1582,7 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct uint8_t mpm_bitarray[ctx->mpm_bitarray_size]; memset(mpm_bitarray, 0, ctx->mpm_bitarray_size); - uint8_t* restrict xlate = ctx->translate_table; + const uint8_t* restrict xlate = ctx->translate_table; register int state = 0; int32_t (*state_table_u32)[256] = ctx->state_table; for (i = 0; i < buflen; i++) { diff --git a/src/util-mpm-ac-tile.h b/src/util-mpm-ac-tile.h index a0d785714719..62e3649fab9c 100644 --- a/src/util-mpm-ac-tile.h +++ b/src/util-mpm-ac-tile.h @@ -84,8 +84,8 @@ typedef struct SCACTileCtx_ { * number of states could make the next state could be 16 bits or * 32 bits. */ - uint32_t (*search)(struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, - PatternMatcherQueue *, uint8_t *, uint16_t); + uint32_t (*search)(const struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, + PatternMatcherQueue *, const uint8_t *, uint16_t); /* Function to set the next state based on size of next state * (bytes_per_state). @@ -140,8 +140,8 @@ typedef struct SCACTileSearchCtx_ { * number of states could make the next state could be 16 bits or * 32 bits. */ - uint32_t (*search)(struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, - PatternMatcherQueue *, uint8_t *, uint16_t); + uint32_t (*search)(const struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, + PatternMatcherQueue *, const uint8_t *, uint16_t); /* Convert input character to matching alphabet */ uint8_t translate_table[256]; diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 341ac5079fc7..d5b535f51a41 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -78,8 +78,8 @@ int SCACAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, int SCACAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int SCACPreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); +uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen); void SCACPrintInfo(MpmCtx *mpm_ctx); void SCACPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACRegisterTests(void); @@ -1302,10 +1302,10 @@ void SCACDestroyCtx(MpmCtx *mpm_ctx) * * \retval matches Match count. */ -uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) +uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + const SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; int i = 0; int matches = 0; @@ -1829,8 +1829,8 @@ static void *SCACCudaDispatcher(void *arg) #undef BLOCK_SIZE } -uint32_t SCACCudaPacketResultsProcessing(Packet *p, MpmCtx *mpm_ctx, - PatternMatcherQueue *pmq) +uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, + PatternMatcherQueue *pmq) { uint32_t u = 0; diff --git a/src/util-mpm-ac.h b/src/util-mpm-ac.h index 13bd16fbdcae..ac6f46467775 100644 --- a/src/util-mpm-ac.h +++ b/src/util-mpm-ac.h @@ -209,7 +209,7 @@ int MpmCudaBufferSetup(void); int MpmCudaBufferDeSetup(void); void SCACCudaStartDispatcher(void); void SCACCudaKillDispatcher(void); -uint32_t SCACCudaPacketResultsProcessing(Packet *p, MpmCtx *mpm_ctx, +uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, PatternMatcherQueue *pmq); void DetermineCudaStateTableSize(DetectEngineCtx *de_ctx); diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index 3ad639b92519..4f7ed52fc029 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -54,8 +54,8 @@ int SCHSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, int SCHSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int SCHSPreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCHSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); +uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, const uint8_t *buf, const uint16_t buflen); void SCHSPrintInfo(MpmCtx *mpm_ctx); void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCHSRegisterTests(void); @@ -940,8 +940,8 @@ static int SCHSMatchEvent(unsigned int id, unsigned long long from, * * \retval matches Match count. */ -uint32_t SCHSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) +uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PatternMatcherQueue *pmq, const uint8_t *buf, const uint16_t buflen) { uint32_t ret = 0; SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; diff --git a/src/util-mpm.h b/src/util-mpm.h index afb694123291..cbb236d13022 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -156,7 +156,7 @@ typedef struct MpmTableElmt_ { int (*AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int (*AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int (*Prepare)(struct MpmCtx_ *); - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); + uint32_t (*Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, const uint8_t *, uint16_t); void (*Cleanup)(struct MpmThreadCtx_ *); void (*PrintCtx)(struct MpmCtx_ *); void (*PrintThreadCtx)(struct MpmThreadCtx_ *); From 2ce03fbabb3468c72cf7d4c27fa64f557c97d10c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Oct 2015 19:29:45 +0200 Subject: [PATCH 1167/2553] detect: split non-mpm list into syn/nosyn Since SYN inspecting rules are expensive, this patch splits the 'non-mpm' list (i.e. the rules that are always considered) into a 'syn' and 'non-syn' list. The SYN list is only inspected if the packet has the SYN flag set, otherwise the non-syn list is used. The syn-list contains _all_ rules. The non-syn list contains all minus the rules requiring the SYN bit in a packet. --- src/detect-engine-siggroup.c | 70 ++++++++++++++++++++++-------------- src/detect.c | 30 +++++++++++++--- src/detect.h | 22 ++++++++---- 3 files changed, 84 insertions(+), 38 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 1ec12111e750..87cfe4b1b042 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -39,6 +39,7 @@ #include "detect-content.h" #include "detect-uricontent.h" +#include "detect-flags.h" #include "util-hash.h" #include "util-hashlist.h" @@ -180,10 +181,16 @@ void SigGroupHeadFree(SigGroupHead *sgh) sgh->match_array = NULL; } - if (sgh->non_mpm_store_array != NULL) { - SCFree(sgh->non_mpm_store_array); - sgh->non_mpm_store_array = NULL; - sgh->non_mpm_store_cnt = 0; + if (sgh->non_mpm_other_store_array != NULL) { + SCFree(sgh->non_mpm_other_store_array); + sgh->non_mpm_other_store_array = NULL; + sgh->non_mpm_other_store_cnt = 0; + } + + if (sgh->non_mpm_syn_store_array != NULL) { + SCFree(sgh->non_mpm_syn_store_array); + sgh->non_mpm_syn_store_array = NULL; + sgh->non_mpm_syn_store_cnt = 0; } sgh->sig_cnt = 0; @@ -957,53 +964,64 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) Signature *s = NULL; uint32_t sig = 0; uint32_t non_mpm = 0; + uint32_t non_mpm_syn = 0; if (sgh == NULL) return 0; - BUG_ON(sgh->non_mpm_store_array != NULL); + BUG_ON(sgh->non_mpm_other_store_array != NULL); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; - if (s->mpm_sm == NULL) - non_mpm++; - else if (s->flags & (SIG_FLAG_MPM_PACKET_NEG|SIG_FLAG_MPM_STREAM_NEG|SIG_FLAG_MPM_APPLAYER_NEG)) - non_mpm++; + if (s->mpm_sm == NULL || (s->flags & (SIG_FLAG_MPM_PACKET_NEG|SIG_FLAG_MPM_STREAM_NEG|SIG_FLAG_MPM_APPLAYER_NEG))) { + if (!(DetectFlagsSignatureNeedsSynPackets(s))) { + non_mpm++; + } + non_mpm_syn++; + } } - if (non_mpm == 0) { - sgh->non_mpm_store_array = NULL; + if (non_mpm == 0 && non_mpm_syn == 0) { + sgh->non_mpm_other_store_array = NULL; + sgh->non_mpm_syn_store_array = NULL; return 0; } - sgh->non_mpm_store_array = SCMalloc(non_mpm * sizeof(SignatureNonMpmStore)); - BUG_ON(sgh->non_mpm_store_array == NULL); - memset(sgh->non_mpm_store_array, 0, non_mpm * sizeof(SignatureNonMpmStore)); + sgh->non_mpm_other_store_array = SCMalloc(non_mpm * sizeof(SignatureNonMpmStore)); + BUG_ON(sgh->non_mpm_other_store_array == NULL); + memset(sgh->non_mpm_other_store_array, 0, non_mpm * sizeof(SignatureNonMpmStore)); + + sgh->non_mpm_syn_store_array = SCMalloc(non_mpm_syn * sizeof(SignatureNonMpmStore)); + BUG_ON(sgh->non_mpm_syn_store_array == NULL); + memset(sgh->non_mpm_syn_store_array, 0, non_mpm_syn * sizeof(SignatureNonMpmStore)); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; - if (s->mpm_sm == NULL) { - BUG_ON(sgh->non_mpm_store_cnt >= non_mpm); - sgh->non_mpm_store_array[sgh->non_mpm_store_cnt].id = s->num; - sgh->non_mpm_store_array[sgh->non_mpm_store_cnt].mask = s->mask; - sgh->non_mpm_store_cnt++; - } else if (s->flags & (SIG_FLAG_MPM_PACKET_NEG|SIG_FLAG_MPM_STREAM_NEG|SIG_FLAG_MPM_APPLAYER_NEG)) { - BUG_ON(sgh->non_mpm_store_cnt >= non_mpm); - sgh->non_mpm_store_array[sgh->non_mpm_store_cnt].id = s->num; - sgh->non_mpm_store_array[sgh->non_mpm_store_cnt].mask = s->mask; - sgh->non_mpm_store_cnt++; + if (s->mpm_sm == NULL || (s->flags & (SIG_FLAG_MPM_PACKET_NEG|SIG_FLAG_MPM_STREAM_NEG|SIG_FLAG_MPM_APPLAYER_NEG))) { + if (!(DetectFlagsSignatureNeedsSynPackets(s))) { + BUG_ON(sgh->non_mpm_other_store_cnt >= non_mpm); + sgh->non_mpm_other_store_array[sgh->non_mpm_other_store_cnt].id = s->num; + sgh->non_mpm_other_store_array[sgh->non_mpm_other_store_cnt].mask = s->mask; + sgh->non_mpm_other_store_cnt++; + } + + BUG_ON(sgh->non_mpm_syn_store_cnt >= non_mpm_syn); + sgh->non_mpm_syn_store_array[sgh->non_mpm_syn_store_cnt].id = s->num; + sgh->non_mpm_syn_store_array[sgh->non_mpm_syn_store_cnt].mask = s->mask; + sgh->non_mpm_syn_store_cnt++; } } /* track highest cnt for any sgh in our de_ctx */ - if (sgh->non_mpm_store_cnt > de_ctx->non_mpm_store_cnt_max) - de_ctx->non_mpm_store_cnt_max = sgh->non_mpm_store_cnt; + uint32_t max = MAX(sgh->non_mpm_other_store_cnt, sgh->non_mpm_syn_store_cnt); + if (max > de_ctx->non_mpm_store_cnt_max) + de_ctx->non_mpm_store_cnt_max = max; return 0; } diff --git a/src/detect.c b/src/detect.c index 4a63c4d39f05..107d0e4f2690 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1213,16 +1213,34 @@ static void AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(Packet *p, DetectEn static inline void DetectPrefilterBuildNonMpmList(DetectEngineThreadCtx *det_ctx, SignatureMask mask) { uint32_t x = 0; - for (x = 0; x < det_ctx->sgh->non_mpm_store_cnt; x++) { + for (x = 0; x < det_ctx->non_mpm_store_cnt; x++) { /* only if the mask matches this rule can possibly match, * so build the non_mpm array only for match candidates */ - SignatureMask rule_mask = det_ctx->sgh->non_mpm_store_array[x].mask; + SignatureMask rule_mask = det_ctx->non_mpm_store_ptr[x].mask; if ((rule_mask & mask) == rule_mask) { - det_ctx->non_mpm_id_array[det_ctx->non_mpm_id_cnt++] = det_ctx->sgh->non_mpm_store_array[x].id; + det_ctx->non_mpm_id_array[det_ctx->non_mpm_id_cnt++] = det_ctx->non_mpm_store_ptr[x].id; } } } +/** \internal + * \brief select non-mpm list + * Based on the packet properties, select the non-mpm list to use */ +static inline void DetectPrefilterSetNonMpmList(const Packet *p, DetectEngineThreadCtx *det_ctx) +{ + if ((p->proto == IPPROTO_TCP) && (p->tcph != NULL) && (p->tcph->th_flags & TH_SYN)) { + det_ctx->non_mpm_store_ptr = det_ctx->sgh->non_mpm_syn_store_array; + det_ctx->non_mpm_store_cnt = det_ctx->sgh->non_mpm_syn_store_cnt; + } else { + det_ctx->non_mpm_store_ptr = det_ctx->sgh->non_mpm_other_store_array; + det_ctx->non_mpm_store_cnt = det_ctx->sgh->non_mpm_other_store_cnt; + } + SCLogDebug("sgh non_mpm ptr %p cnt %u (syn %p/%u, other %p/%u)", + det_ctx->non_mpm_store_ptr, det_ctx->non_mpm_store_cnt, + det_ctx->sgh->non_mpm_syn_store_array, det_ctx->sgh->non_mpm_syn_store_cnt, + det_ctx->sgh->non_mpm_other_store_array, det_ctx->sgh->non_mpm_other_store_cnt); +} + /** * \brief Signature match function * @@ -1429,6 +1447,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh goto end; } + DetectPrefilterSetNonMpmList(p, det_ctx); + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); /* stateful app layer detection */ if ((p->flags & PKT_HAS_FLOW) && has_state) { @@ -1452,7 +1472,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* build and prefilter non_mpm list against the mask of the packet */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_NONMPMLIST); det_ctx->non_mpm_id_cnt = 0; - if (likely(det_ctx->sgh->non_mpm_store_cnt > 0)) { + if (likely(det_ctx->non_mpm_store_cnt > 0)) { DetectPrefilterBuildNonMpmList(det_ctx, mask); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_NONMPMLIST); @@ -1466,7 +1486,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh StatsAddUI64(th_v, det_ctx->counter_mpm_list, (uint64_t)det_ctx->pmq.rule_id_array_cnt); StatsAddUI64(th_v, det_ctx->counter_nonmpm_list, - (uint64_t)det_ctx->sgh->non_mpm_store_cnt); + (uint64_t)det_ctx->non_mpm_store_cnt); /* non mpm sigs after mask prefilter */ StatsAddUI64(th_v, det_ctx->counter_fnonmpm_list, (uint64_t)det_ctx->non_mpm_id_cnt); diff --git a/src/detect.h b/src/detect.h index afef28f54745..9d83a793a6ef 100644 --- a/src/detect.h +++ b/src/detect.h @@ -736,6 +736,11 @@ typedef struct FiledataReassembledBody_ { /** \todo review how many we actually need here */ #define DETECT_SMSG_PMQ_NUM 256 +typedef struct SignatureNonMpmStore_ { + SigIntId id; + SignatureMask mask; +} SignatureNonMpmStore; + /** * Detection engine thread data. */ @@ -832,6 +837,10 @@ typedef struct DetectEngineThreadCtx_ { uint8_t *de_state_sig_array; struct SigGroupHead_ *sgh; + + SignatureNonMpmStore *non_mpm_store_ptr; + uint32_t non_mpm_store_cnt; + /** pointer to the current mpm ctx that is stored * in a rule group head -- can be either a content * or uricontent ctx. */ @@ -983,11 +992,6 @@ typedef struct SigGroupHeadInitData_ { struct DetectPort_ *port; } SigGroupHeadInitData; -typedef struct SignatureNonMpmStore_ { - SigIntId id; - SignatureMask mask; -} SignatureNonMpmStore; - /** \brief Container for matching data for a signature group */ typedef struct SigGroupHead_ { uint32_t flags; @@ -1003,8 +1007,12 @@ typedef struct SigGroupHead_ { SignatureMask *mask_array; #endif - SignatureNonMpmStore *non_mpm_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) - uint32_t non_mpm_store_cnt; + /* non mpm list excluding SYN rules */ + SignatureNonMpmStore *non_mpm_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) + uint32_t non_mpm_other_store_cnt; + /* non mpm list including SYN rules */ + SignatureNonMpmStore *non_mpm_syn_store_array; // size is non_mpm_syn_store_cnt * sizeof(SignatureNonMpmStore) + uint32_t non_mpm_syn_store_cnt; /* pattern matcher instances */ const MpmCtx *mpm_proto_other_ctx; From 5772f526dcd235f80d3c9f65bb9fb5a7c1d8c0de Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 7 Oct 2015 07:08:02 +0200 Subject: [PATCH 1168/2553] detect grouping: warn on and fix up bad sigs Only inspect directionless SYN scan sigs toserver. Issue a warning for those rules. --- src/detect.c | 14 ++++++++++++++ src/util-error.c | 1 + src/util-error.h | 1 + 3 files changed, 16 insertions(+) diff --git a/src/detect.c b/src/detect.c index 107d0e4f2690..f50dd4855f3f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3008,6 +3008,20 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 else BUG_ON(1); + /* see if we want to exclude directionless sigs that really care only for + * to_server syn scans/floods */ + if ((direction == SIG_FLAG_TOCLIENT) && + DetectFlagsSignatureNeedsSynPackets(s) && + DetectFlagsSignatureNeedsSynOnlyPackets(s) && + ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) && + (!(s->dp->port == 0 && s->dp->port2 == 65535))) + { + SCLogWarning(SC_WARN_POOR_RULE, "rule %u: SYN-only to port(s) %u:%u " + "w/o direction specified, disabling for toclient direction", + s->id, s->dp->port, s->dp->port2); + goto next; + } + while (p) { DetectPort *tmp = DetectPortCopySingle(de_ctx, p); BUG_ON(tmp == NULL); diff --git a/src/util-error.c b/src/util-error.c index 3bf695504a69..3706789b2bfa 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -316,6 +316,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_JSON_STATS_LOG_NEGATED); CASE_CODE (SC_ERR_DEPRECATED_CONF); CASE_CODE (SC_WARN_FASTER_CAPTURE_AVAILABLE); + CASE_CODE (SC_WARN_POOR_RULE); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 42fd74f9638e..1e9ef4f0260c 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -306,6 +306,7 @@ typedef enum { SC_ERR_JSON_STATS_LOG_NEGATED, /** When totals and threads are both NO in yaml **/ SC_ERR_DEPRECATED_CONF, /**< Deprecated configuration parameter. */ SC_WARN_FASTER_CAPTURE_AVAILABLE, + SC_WARN_POOR_RULE, } SCError; const char *SCErrorToString(SCError); From 3c184c19cd56be39974463b3d4f2e43ceee9a837 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 30 Sep 2015 18:26:00 +0200 Subject: [PATCH 1169/2553] detect grouping: port based group whitelisting Whitelist some ports in grouping to make sure they get their own group. --- src/detect-engine-siggroup.c | 3 +++ src/detect.c | 39 +++++++++++++++++++++++++++++++++++- src/detect.h | 1 + 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 87cfe4b1b042..86afa4e7962f 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -629,6 +629,9 @@ int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHea for (idx = 0; idx < src->init->sig_size; idx++) (*dst)->init->sig_array[idx] = (*dst)->init->sig_array[idx] | src->init->sig_array[idx]; + if (src->init->whitelist) + (*dst)->init->whitelist = 1; + if (src->mpm_content_minlen != 0) { if ((*dst)->mpm_content_minlen == 0) (*dst)->mpm_content_minlen = src->mpm_content_minlen; diff --git a/src/detect.c b/src/detect.c index f50dd4855f3f..681fc082161d 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2980,6 +2980,24 @@ int RulesGroupByProto(DetectEngineCtx *de_ctx) return 0; } +int tcp_whitelisted[] = { 53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080, -1 }; +int udp_whitelisted[] = { 53, 135, 5060, -1 }; + +static int PortIsWhitelisted(const DetectPort *a, int ipproto) +{ + int *w = tcp_whitelisted; + if (ipproto == IPPROTO_UDP) + w = udp_whitelisted; + while (*w++ != -1) { + if (a->port >= *w && a->port2 <= *w) { + SCLogDebug("port group %u:%u whitelisted -> %d", a->port, a->port2, *w); + return 1; + } + } + + return 0; +} + int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx); int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b); @@ -3026,6 +3044,13 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 DetectPort *tmp = DetectPortCopySingle(de_ctx, p); BUG_ON(tmp == NULL); SigGroupHeadAppendSig(de_ctx, &tmp->sh, s); + tmp->sh->init->whitelist = PortIsWhitelisted(tmp, ipproto); + if (tmp->sh->init->whitelist) { + SCLogDebug("%s/%s Rule %u whitelisted port group %u:%u", + direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", + ipproto == 6 ? "TCP" : "UDP", + s->id, p->port, p->port2); + } int r = DetectPortInsert(de_ctx, &list , tmp); BUG_ON(r == -1); @@ -3082,7 +3107,10 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 } #if 0 for (iter = list ; iter != NULL; iter = iter->next) { - SCLogInfo("PORT %u-%u %p (sgh=%s)", iter->port, iter->port2, iter->sh, iter->flags & PORT_SIGGROUPHEAD_COPY ? "ref" : "own"); + SCLogInfo("PORT %u-%u %p (sgh=%s, whitelisted=%s)", + iter->port, iter->port2, iter->sh, + iter->flags & PORT_SIGGROUPHEAD_COPY ? "ref" : "own", + iter->sh->init->whitelist ? "true" : "false"); } #endif SCLogInfo("%s %s: %u port groups, %u unique SGH's, %u copies", @@ -3218,8 +3246,17 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) return -1; } +static int PortGroupIsWhitelisted(const DetectPort *a) +{ + return a->sh->init->whitelist; +} + int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b) { + if (PortGroupIsWhitelisted(a) && !PortGroupIsWhitelisted(b)) + return 1; + if (!PortGroupIsWhitelisted(a) && PortGroupIsWhitelisted(b)) + return 0; if (a->sh->sig_cnt > b->sh->sig_cnt) { SCLogDebug("pg %u:%u %u > %u:%u %u", a->port, a->port2, a->sh->sig_cnt, diff --git a/src/detect.h b/src/detect.h index 9d83a793a6ef..11c2c1933960 100644 --- a/src/detect.h +++ b/src/detect.h @@ -987,6 +987,7 @@ typedef struct SigGroupHeadInitData_ { 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 */ /* port ptr */ struct DetectPort_ *port; From b84d6d402f7d73a892a819ba038b67ee2e5a946c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Oct 2015 15:33:42 +0200 Subject: [PATCH 1170/2553] detect grouping: multiple whitelist conditions Instead of the binary yes/no whitelisting used so far, use different values for different sorts of whitelist reasons. The port list will be sorted by whitelist value first, then by rule count. The goal is to whitelist groups that have weak sigs: - 1 byte pattern groups - SYN sigs Rules that check for SYN packets are mostly scan detection rules. They will be checked often as SYN packets are very common. e.g. alert tcp any any -> any 22 (flags:S,12; sid:123;) This patch adds whitelisting for SYN-sigs, so that the sigs end up in as unique groups as possible. - negated mpm sigs Currently negated mpm sigs are inspected often, so they are quite expensive. For this reason, try to whitelist them. These values are set during 'stage 1', rule preprocessing. --- src/detect-engine-siggroup.c | 2 +- src/detect.c | 120 ++++++++++++++++++++++++++++++++--- src/detect.h | 5 ++ 3 files changed, 116 insertions(+), 11 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 86afa4e7962f..96a6775ad862 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -630,7 +630,7 @@ int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHea (*dst)->init->sig_array[idx] = (*dst)->init->sig_array[idx] | src->init->sig_array[idx]; if (src->init->whitelist) - (*dst)->init->whitelist = 1; + (*dst)->init->whitelist = MAX((*dst)->init->whitelist, src->init->whitelist); if (src->mpm_content_minlen != 0) { if ((*dst)->mpm_content_minlen == 0) diff --git a/src/detect.c b/src/detect.c index 681fc082161d..235396924475 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2859,6 +2859,40 @@ static void SigParseApplyDsizeToContent(Signature *s) } } +/** \brief Pure-PCRE or bytetest rule */ +int RuleInspectsPayloadHasNoMpm(const Signature *s) +{ + if (s->mpm_sm == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) + return 1; + return 0; +} + +int RuleGetMpmPatternSize(const Signature *s) +{ + if (s->mpm_sm == NULL) + return -1; + int mpm_list = SigMatchListSMBelongsTo(s, s->mpm_sm); + if (mpm_list < 0) + return -1; + const DetectContentData *cd = (const DetectContentData *)s->mpm_sm->ctx; + if (cd == NULL) + return -1; + return (int)cd->content_len; +} + +int RuleMpmIsNegated(const Signature *s) +{ + if (s->mpm_sm == NULL) + return 0; + int mpm_list = SigMatchListSMBelongsTo(s, s->mpm_sm); + if (mpm_list < 0) + return 0; + const DetectContentData *cd = (const DetectContentData *)s->mpm_sm->ctx; + if (cd == NULL) + return 0; + return (cd->flags & DETECT_CONTENT_NEGATED); +} + int RulesGroupByProto(DetectEngineCtx *de_ctx) { Signature *s = de_ctx->sig_list; @@ -2998,6 +3032,49 @@ static int PortIsWhitelisted(const DetectPort *a, int ipproto) return 0; } +static int RuleSetWhitelist(Signature *s) +{ + DetectPort *p = NULL; + if (s->flags & SIG_FLAG_TOSERVER) + p = s->dp; + else if (s->flags & SIG_FLAG_TOCLIENT) + p = s->sp; + else + return 0; + + /* for sigs that don't use 'any' as port, see if we want to + * whitelist poor sigs */ + int wl = 0; + if (!(p->port == 0 && p->port2 == 65535)) { + /* pure pcre, bytetest, etc rules */ + if (RuleInspectsPayloadHasNoMpm(s)) { + SCLogDebug("Rule %u MPM has 1 byte fast_pattern. Whitelisting SGH's.", s->id); + wl = 99; + + } else if (RuleMpmIsNegated(s)) { + SCLogDebug("Rule %u MPM is negated. Whitelisting SGH's.", s->id); + wl = 77; + + /* one byte pattern in packet/stream payloads */ + } else if (s->mpm_sm != NULL && + SigMatchListSMBelongsTo(s, s->mpm_sm) == DETECT_SM_LIST_PMATCH && + RuleGetMpmPatternSize(s) == 1) + { + SCLogDebug("Rule %u No MPM. Payload inspecting. Whitelisting SGH's.", s->id); + wl = 55; + + } else if (DetectFlagsSignatureNeedsSynPackets(s) && + DetectFlagsSignatureNeedsSynOnlyPackets(s)) + { + SCLogDebug("Rule %u Needs SYN, so inspected often. Whitelisting SGH's.", s->id); + wl = 33; + } + } + + s->whitelist = wl; + return wl; +} + int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx); int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b); @@ -3040,11 +3117,14 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 goto next; } + int wl = s->whitelist; while (p) { DetectPort *tmp = DetectPortCopySingle(de_ctx, p); BUG_ON(tmp == NULL); SigGroupHeadAppendSig(de_ctx, &tmp->sh, s); - tmp->sh->init->whitelist = PortIsWhitelisted(tmp, ipproto); + + int pwl = PortIsWhitelisted(tmp, ipproto) ? 111 : 0; + tmp->sh->init->whitelist = MAX(wl, pwl); if (tmp->sh->init->whitelist) { SCLogDebug("%s/%s Rule %u whitelisted port group %u:%u", direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", @@ -3107,10 +3187,11 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 } #if 0 for (iter = list ; iter != NULL; iter = iter->next) { - SCLogInfo("PORT %u-%u %p (sgh=%s, whitelisted=%s)", + SCLogInfo("PORT %u-%u %p (sgh=%s, whitelisted=%s/%d)", iter->port, iter->port2, iter->sh, iter->flags & PORT_SIGGROUPHEAD_COPY ? "ref" : "own", - iter->sh->init->whitelist ? "true" : "false"); + iter->sh->init->whitelist ? "true" : "false", + iter->sh->init->whitelist); } #endif SCLogInfo("%s %s: %u port groups, %u unique SGH's, %u copies", @@ -3223,6 +3304,8 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) SignatureCreateMask(tmp_s); SigParseApplyDsizeToContent(tmp_s); + RuleSetWhitelist(tmp_s); + de_ctx->sig_cnt++; } @@ -3246,23 +3329,40 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) return -1; } -static int PortGroupIsWhitelisted(const DetectPort *a) +static int PortGroupWhitelist(const DetectPort *a) { return a->sh->init->whitelist; } int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b) { - if (PortGroupIsWhitelisted(a) && !PortGroupIsWhitelisted(b)) + if (PortGroupWhitelist(a) && !PortGroupWhitelist(b)) { + SCLogDebug("%u:%u (cnt %u, wl %d) wins against %u:%u (cnt %u, wl %d)", + a->port, a->port2, a->sh->sig_cnt, PortGroupWhitelist(a), + b->port, b->port2, b->sh->sig_cnt, PortGroupWhitelist(b)); return 1; - if (!PortGroupIsWhitelisted(a) && PortGroupIsWhitelisted(b)) + } else if (!PortGroupWhitelist(a) && PortGroupWhitelist(b)) { + SCLogDebug("%u:%u (cnt %u, wl %d) loses against %u:%u (cnt %u, wl %d)", + a->port, a->port2, a->sh->sig_cnt, PortGroupWhitelist(a), + b->port, b->port2, b->sh->sig_cnt, PortGroupWhitelist(b)); return 0; - if (a->sh->sig_cnt > b->sh->sig_cnt) { - SCLogDebug("pg %u:%u %u > %u:%u %u", - a->port, a->port2, a->sh->sig_cnt, - b->port, b->port2, b->sh->sig_cnt); + } else if (PortGroupWhitelist(a) > PortGroupWhitelist(b)) { + SCLogDebug("%u:%u (cnt %u, wl %d) wins against %u:%u (cnt %u, wl %d)", + a->port, a->port2, a->sh->sig_cnt, PortGroupWhitelist(a), + b->port, b->port2, b->sh->sig_cnt, PortGroupWhitelist(b)); return 1; + } else if (PortGroupWhitelist(a) == PortGroupWhitelist(b)) { + if (a->sh->sig_cnt > b->sh->sig_cnt) { + SCLogDebug("%u:%u (cnt %u, wl %d) wins against %u:%u (cnt %u, wl %d)", + a->port, a->port2, a->sh->sig_cnt, PortGroupWhitelist(a), + b->port, b->port2, b->sh->sig_cnt, PortGroupWhitelist(b)); + return 1; + } } + + SCLogDebug("%u:%u (cnt %u, wl %d) loses against %u:%u (cnt %u, wl %d)", + a->port, a->port2, a->sh->sig_cnt, PortGroupWhitelist(a), + b->port, b->port2, b->sh->sig_cnt, PortGroupWhitelist(b)); return 0; } diff --git a/src/detect.h b/src/detect.h index 11c2c1933960..03c354da8d1d 100644 --- a/src/detect.h +++ b/src/detect.h @@ -460,6 +460,11 @@ typedef struct Signature_ { /* SigMatch list used for adding content and friends. E.g. file_data; */ int list; + /** score to influence rule grouping. A higher value leads to a higher + * likelyhood of a rulegroup with this sig ending up as a contained + * group. */ + int whitelist; + /* Be careful, this pointer is only valid while parsing the sig, * to warn the user about any possible problem */ char *sig_str; From a34be2300251b0e0bdc4baaf31751e30f3ba786e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 10 Oct 2015 14:36:45 +0200 Subject: [PATCH 1171/2553] detect: simplify negated mpm handling --- src/detect-engine-mpm.c | 10 ------ src/detect-engine-siggroup.c | 4 +-- src/detect.c | 63 +++++------------------------------- src/detect.h | 8 ++--- 4 files changed, 13 insertions(+), 72 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 036ed2899c3f..620cda3cce44 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1389,27 +1389,17 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) s->flags |= SIG_FLAG_MPM_PACKET; s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_PACKET_NEG; - } } else { /* tell matcher we are inspecting stream */ s->flags |= SIG_FLAG_MPM_STREAM; s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_STREAM_NEG; - } } } else { /* tell matcher we are inspecting app-layer */ s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; } } } diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 96a6775ad862..544a32d29176 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -979,7 +979,7 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) if (s == NULL) continue; - if (s->mpm_sm == NULL || (s->flags & (SIG_FLAG_MPM_PACKET_NEG|SIG_FLAG_MPM_STREAM_NEG|SIG_FLAG_MPM_APPLAYER_NEG))) { + if (s->mpm_sm == NULL || (s->flags & SIG_FLAG_MPM_NEG)) { if (!(DetectFlagsSignatureNeedsSynPackets(s))) { non_mpm++; } @@ -1006,7 +1006,7 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) if (s == NULL) continue; - if (s->mpm_sm == NULL || (s->flags & (SIG_FLAG_MPM_PACKET_NEG|SIG_FLAG_MPM_STREAM_NEG|SIG_FLAG_MPM_APPLAYER_NEG))) { + if (s->mpm_sm == NULL || (s->flags & SIG_FLAG_MPM_NEG)) { if (!(DetectFlagsSignatureNeedsSynPackets(s))) { BUG_ON(sgh->non_mpm_other_store_cnt >= non_mpm); sgh->non_mpm_other_store_array[sgh->non_mpm_other_store_cnt].id = s->num; diff --git a/src/detect.c b/src/detect.c index 235396924475..7682f28aa570 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1558,28 +1558,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } } - /* check for a pattern match of the one pattern in this sig. */ - if (likely(sflags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_APPLAYER))) { - /* filter out sigs that want pattern matches, but - * have no matches */ - if (!(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { - if (sflags & SIG_FLAG_MPM_PACKET) { - if (!(sflags & SIG_FLAG_MPM_PACKET_NEG)) { - goto next; - } - } else if (sflags & SIG_FLAG_MPM_STREAM) { - /* filter out sigs that want pattern matches, but - * have no matches */ - if (!(sflags & SIG_FLAG_MPM_STREAM_NEG)) { - goto next; - } - } else if (sflags & SIG_FLAG_MPM_APPLAYER) { - if (!(sflags & SIG_FLAG_MPM_APPLAYER_NEG)) { - goto next; - } - } - } - } if (sflags & SIG_FLAG_STATE_MATCH) { if (det_ctx->de_state_sig_array[s->num] & DE_STATE_MATCH_NO_NEW_STATE) goto next; @@ -1673,14 +1651,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh uint8_t pmq_idx = 0; StreamMsg *smsg_inspect = smsg; for ( ; smsg_inspect != NULL; smsg_inspect = smsg_inspect->next, pmq_idx++) { - /* filter out sigs that want pattern matches, but - * have no matches */ - if ((sflags & SIG_FLAG_MPM_STREAM) && !(sflags & SIG_FLAG_MPM_STREAM_NEG) && - !(det_ctx->smsg_pmq[pmq_idx].pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { - SCLogDebug("no match in this smsg"); - continue; - } - if (DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, pflow, smsg_inspect->data, smsg_inspect->data_len) == 1) { SCLogDebug("match in smsg %p", smsg); pmatch = 1; @@ -1706,34 +1676,13 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh goto next; } - if (sms_runflags & SMS_USED_PM) { - if ((sflags & SIG_FLAG_MPM_PACKET) && !(sflags & SIG_FLAG_MPM_PACKET_NEG) && - !(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & - s->mpm_pattern_id_mod_8)) { - goto next; - } - if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { - goto next; - } - } else { - if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { - goto next; - } - } - } - } else { - if (sms_runflags & SMS_USED_PM) { - if ((sflags & SIG_FLAG_MPM_PACKET) && !(sflags & SIG_FLAG_MPM_PACKET_NEG) && - !(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & - s->mpm_pattern_id_mod_8)) { - goto next; - } if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { goto next; } - } else { - if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) - goto next; + } + } else { + if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { + goto next; } } } @@ -3301,6 +3250,10 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) } #endif /* DEBUG */ + if (RuleMpmIsNegated(tmp_s)) { + tmp_s->flags |= SIG_FLAG_MPM_NEG; + } + SignatureCreateMask(tmp_s); SigParseApplyDsizeToContent(tmp_s); diff --git a/src/detect.h b/src/detect.h index 03c354da8d1d..ab4674508b26 100644 --- a/src/detect.h +++ b/src/detect.h @@ -276,12 +276,10 @@ typedef struct DetectPort_ { #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_NEG (1<<11) +#define SIG_FLAG_MPM_PACKET (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_MPM_APPLAYER (1<<14) #define SIG_FLAG_REQUIRE_FLOWVAR (1<<17) /**< signature can only match if a flowbit, flowvar or flowint is available. */ From b2fcb17859f02dcf6d69c4d2836d44b16a3c73dc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 10 Oct 2015 17:10:13 +0200 Subject: [PATCH 1172/2553] proto detect: in mpm switch to rule id Use the rule id API instead of pattern id API. --- src/app-layer-detect-proto.c | 80 ++++++++++++++---------------------- 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 3ccc6d0c9ba7..b6b1f4f7554c 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -106,6 +106,7 @@ typedef struct AppLayerProtoDetectProbingParser_ { typedef struct AppLayerProtoDetectPMSignature_ { AppProto alproto; + SigIntId id; /* \todo Change this into a non-pointer */ DetectContentData *cd; struct AppLayerProtoDetectPMSignature_ *next; @@ -124,6 +125,7 @@ typedef struct AppLayerProtoDetectPMCtx_ { /* \todo we don't need this except at setup time. Get rid of it. */ PatIntId max_pat_id; + SigIntId max_sig_id; } AppLayerProtoDetectPMCtx; typedef struct AppLayerProtoDetectCtxIpproto_ { @@ -254,8 +256,8 @@ static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx /* loop through unique pattern id's. Can't use search_cnt here, * as that contains all matches, tctx->pmq.pattern_id_array_cnt * contains only *unique* matches. */ - for (cnt = 0; cnt < tctx->pmq.pattern_id_array_cnt; cnt++) { - const AppLayerProtoDetectPMSignature *s = pm_ctx->map[tctx->pmq.pattern_id_array[cnt]]; + for (cnt = 0; cnt < tctx->pmq.rule_id_array_cnt; cnt++) { + const AppLayerProtoDetectPMSignature *s = pm_ctx->map[tctx->pmq.rule_id_array[cnt]]; while (s != NULL) { AppProto proto = AppLayerProtoDetectPMMatchSignature(s, buf, searchlen, ipproto); @@ -1027,8 +1029,6 @@ static void AppLayerProtoDetectPMGetIpprotos(AppProto alproto, SCEnter(); const AppLayerProtoDetectPMSignature *s = NULL; - int pat_id, max_pat_id; - int i, j; uint8_t ipproto; @@ -1036,15 +1036,12 @@ static void AppLayerProtoDetectPMGetIpprotos(AppProto alproto, ipproto = FlowGetReverseProtoMapping(i); for (j = 0; j < 2; j++) { AppLayerProtoDetectPMCtx *pm_ctx = &alpd_ctx.ctx_ipp[i].ctx_pm[j]; - max_pat_id = pm_ctx->max_pat_id; - - for (pat_id = 0; pat_id < max_pat_id; pat_id++) { - s = pm_ctx->map[pat_id]; - while (s != NULL) { - if (s->alproto == alproto) - ipprotos[ipproto / 8] |= 1 << (ipproto % 8); - s = s->next; - } + + SigIntId x; + for (x = 0; x < pm_ctx->max_sig_id;x++) { + s = pm_ctx->map[x]; + if (s->alproto == alproto) + ipprotos[ipproto / 8] |= 1 << (ipproto % 8); } } } @@ -1081,6 +1078,7 @@ static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx) for (s = ctx->head; s != NULL; s = s->next) { struct_total_size += sizeof(TempContainer); content_total_size += s->cd->content_len; + ctx->max_sig_id++; } ahb = SCMalloc(sizeof(uint8_t) * (struct_total_size + content_total_size)); @@ -1134,54 +1132,40 @@ static int AppLayerProtoDetectPMMapSignatures(AppLayerProtoDetectPMCtx *ctx) SCEnter(); int ret = 0; - PatIntId max_pat_id = 0, tmp_pat_id; AppLayerProtoDetectPMSignature *s, *next_s; int mpm_ret; + SigIntId id = 0; - max_pat_id = ctx->max_pat_id; - - ctx->map = SCMalloc((max_pat_id) * sizeof(AppLayerProtoDetectPMSignature *)); + ctx->map = SCMalloc(ctx->max_sig_id * sizeof(AppLayerProtoDetectPMSignature *)); if (ctx->map == NULL) goto error; - memset(ctx->map, 0, (max_pat_id) * sizeof(AppLayerProtoDetectPMSignature *)); + memset(ctx->map, 0, ctx->max_sig_id * sizeof(AppLayerProtoDetectPMSignature *)); - /* add an array indexed by pattern id to look up the sig */ - for (s = ctx->head; s != NULL;) { + /* add an array indexed by rule id to look up the sig */ + for (s = ctx->head; s != NULL; ) { next_s = s->next; - s->next = ctx->map[s->cd->id]; - ctx->map[s->cd->id] = s; - s = next_s; - } - ctx->head = NULL; + s->id = id++; + SCLogDebug("s->id %u", s->id); - - for (tmp_pat_id = 0; tmp_pat_id < max_pat_id; tmp_pat_id++) { - s = NULL; - for (s = ctx->map[tmp_pat_id]; s != NULL; s = s->next) { - if (s->cd->flags & DETECT_CONTENT_NOCASE) { - break; - } - } - /* if s != NULL now, it's CI. If NULL, CS */ - - if (s != NULL) { + if (s->cd->flags & DETECT_CONTENT_NOCASE) { mpm_ret = MpmAddPatternCI(&ctx->mpm_ctx, s->cd->content, s->cd->content_len, - 0, 0, tmp_pat_id, 0, 0); + 0, 0, s->cd->id, s->id, 0); if (mpm_ret < 0) goto error; } else { - s = ctx->map[tmp_pat_id]; - if (s == NULL) - goto error; - mpm_ret = MpmAddPatternCS(&ctx->mpm_ctx, s->cd->content, s->cd->content_len, - 0, 0, tmp_pat_id, 0, 0); + 0, 0, s->cd->id, s->id, 0); if (mpm_ret < 0) goto error; } + + ctx->map[s->id] = s; + s->next = NULL; + s = next_s; } + ctx->head = NULL; goto end; error: @@ -1356,7 +1340,7 @@ int AppLayerProtoDetectPrepareState(void) if (AppLayerProtoDetectPMSetContentIDs(ctx_pm) < 0) goto error; - if (ctx_pm->max_pat_id == 0) + if (ctx_pm->max_sig_id == 0) continue; if (AppLayerProtoDetectPMMapSignatures(ctx_pm) < 0) @@ -1553,19 +1537,15 @@ int AppLayerProtoDetectDeSetup(void) int dir = 0; PatIntId id = 0; AppLayerProtoDetectPMCtx *pm_ctx = NULL; - AppLayerProtoDetectPMSignature *sig = NULL, *next_sig = NULL; + AppLayerProtoDetectPMSignature *sig = NULL; for (ipproto_map = 0; ipproto_map < FLOW_PROTO_DEFAULT; ipproto_map++) { for (dir = 0; dir < 2; dir++) { pm_ctx = &alpd_ctx.ctx_ipp[ipproto_map].ctx_pm[dir]; mpm_table[pm_ctx->mpm_ctx.mpm_type].DestroyCtx(pm_ctx->mpm_ctx.ctx); - for (id = 0; id < pm_ctx->max_pat_id; id++) { + for (id = 0; id < pm_ctx->max_sig_id; id++) { sig = pm_ctx->map[id]; - while (sig != NULL) { - next_sig = sig->next; - AppLayerProtoDetectPMFreeSignature(sig); - sig = next_sig; - } + AppLayerProtoDetectPMFreeSignature(sig); } } } From cd8283bb729c4437f6a532b80c0b62d75ee8b76e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 10:14:25 +0200 Subject: [PATCH 1173/2553] smtp: use rule_id mpm support instead of pattern id --- src/app-layer-smtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 8ef3a966ccaf..b7450af9dc78 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -925,7 +925,7 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, state->current_line[0], state->current_line[1], state->current_line[2]); SCReturnInt(-1); } - reply_code = smtp_reply_map[pmq->pattern_id_array[0]].enum_value; + reply_code = smtp_reply_map[pmq->rule_id_array[0]].enum_value; if (state->cmds_idx == state->cmds_cnt) { if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { @@ -1445,7 +1445,7 @@ static void SMTPSetMpmState(void) /* The third argument is 3, because reply code is always 3 bytes. */ MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3, 0 /* defunct */, 0 /* defunct */, - i /* pattern id */, 0, 0 /* no flags */); + i /* pattern id */, i /* rule id */ , 0 /* no flags */); } mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx); From 4edb03ab9d6ede0afb539687a36829913691f1b2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 10:39:16 +0200 Subject: [PATCH 1174/2553] mpm: ac use internal pattern id tracking --- src/util-mpm-ac.c | 8 +++++--- src/util-mpm-ac.h | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index d5b535f51a41..85acc77b5f5a 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -990,7 +990,7 @@ static void SCACPrintDeltaTable(MpmCtx *mpm_ctx) * * \param mpm_ctx Pointer to the mpm context. */ -static inline void SCACPrepareStateTable(MpmCtx *mpm_ctx) +static void SCACPrepareStateTable(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; @@ -1131,6 +1131,8 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); + ctx->pattern_id_bitarray_size = (ctx->max_pat_id / 8) + 1; + return 0; error: @@ -1314,8 +1316,8 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ SCACPatternList *pid_pat_list = ctx->pid_pat_list; - uint8_t bitarray[pmq->pattern_id_bitarray_size]; - memset(bitarray, 0, pmq->pattern_id_bitarray_size); + uint8_t bitarray[ctx->pattern_id_bitarray_size]; + memset(bitarray, 0, ctx->pattern_id_bitarray_size); if (ctx->state_count < 32767) { register SC_AC_STATE_TYPE_U16 state = 0; diff --git a/src/util-mpm-ac.h b/src/util-mpm-ac.h index ac6f46467775..394ad6781f2d 100644 --- a/src/util-mpm-ac.h +++ b/src/util-mpm-ac.h @@ -84,6 +84,9 @@ typedef struct SCACCtx_ { /* no of states used by ac */ uint32_t state_count; + + uint32_t pattern_id_bitarray_size; + /* the all important memory hungry state_table */ SC_AC_STATE_TYPE_U16 (*state_table_u16)[256]; /* the all important memory hungry state_table */ From 69d38a3222415dc2c7fc2ea2686f4c1c9b0dd2d4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 10:41:57 +0200 Subject: [PATCH 1175/2553] mpm: ac-bs use internal pattern id tracking --- src/util-mpm-ac-bs.c | 6 ++++-- src/util-mpm-ac-bs.h | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 23c37e8d03a2..ade031a4f313 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -1239,6 +1239,8 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); + ctx->pattern_id_bitarray_size = (ctx->max_pat_id / 8) + 1; + return 0; error: @@ -1434,8 +1436,8 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ SCACBSPatternList *pid_pat_list = ctx->pid_pat_list; - uint8_t bitarray[pmq->pattern_id_bitarray_size]; - memset(bitarray, 0, pmq->pattern_id_bitarray_size); + uint8_t bitarray[ctx->pattern_id_bitarray_size]; + memset(bitarray, 0, ctx->pattern_id_bitarray_size); if (ctx->state_count < 32767) { register SC_AC_BS_STATE_TYPE_U16 state = 0; diff --git a/src/util-mpm-ac-bs.h b/src/util-mpm-ac-bs.h index ce9c59fc5c28..42d254c585a2 100644 --- a/src/util-mpm-ac-bs.h +++ b/src/util-mpm-ac-bs.h @@ -71,6 +71,9 @@ typedef struct SCACBSCtx_ { /* no of states used by ac */ uint32_t state_count; + + uint16_t pattern_id_bitarray_size; + /* the all important memory hungry state_table */ SC_AC_BS_STATE_TYPE_U16 (*state_table_u16)[256]; /* the all important memory hungry state_table */ From fa885e1d85f7522283c77eb4f6c9921006eb1bc5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 10:15:16 +0200 Subject: [PATCH 1176/2553] mpm: remove pattern id logic --- src/app-layer-detect-proto.c | 2 +- src/app-layer-smtp.c | 3 +- src/detect-engine.c | 4 +- src/util-mpm-ac-bs.c | 69 ++++++++++------------- src/util-mpm-ac-tile.c | 63 ++++++++++----------- src/util-mpm-ac.c | 77 ++++++++++++------------- src/util-mpm-hs.c | 58 ++++++++++--------- src/util-mpm.c | 105 ++++------------------------------- src/util-mpm.h | 28 +--------- 9 files changed, 138 insertions(+), 271 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index b6b1f4f7554c..e5c36695b36a 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1663,7 +1663,7 @@ AppLayerProtoDetectThreadCtx *AppLayerProtoDetectGetCtxThread(void) memset(alpd_tctx, 0, sizeof(*alpd_tctx)); /* Get the max pat id for all the mpm ctxs. */ - if (PmqSetup(&alpd_tctx->pmq, max_pat_id) < 0) + if (PmqSetup(&alpd_tctx->pmq) < 0) goto error; for (i = 0; i < FLOW_PROTO_DEFAULT; i++) { diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index b7450af9dc78..94693a233969 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1341,8 +1341,7 @@ static void *SMTPLocalStorageAlloc(void) if (unlikely(pmq == NULL)) { exit(EXIT_FAILURE); } - PmqSetup(pmq, - sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 2); + PmqSetup(pmq); return pmq; } diff --git a/src/detect-engine.c b/src/detect-engine.c index 80a701e7e9c9..deecae489535 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1332,9 +1332,9 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher); PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher); - PmqSetup(&det_ctx->pmq, de_ctx->max_fp_id); + PmqSetup(&det_ctx->pmq); for (i = 0; i < DETECT_SMSG_PMQ_NUM; i++) { - PmqSetup(&det_ctx->smsg_pmq[i], de_ctx->max_fp_id); + PmqSetup(&det_ctx->smsg_pmq[i]); } /* sized to the max of our sgh settings. A max setting of 0 implies that all diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index ade031a4f313..6883f567246e 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -1503,8 +1503,6 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - MpmAddPid(pmq, lower_pid); MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; @@ -1513,9 +1511,6 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - - MpmAddPid(pmq, pids[k]); MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; @@ -1590,9 +1585,6 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - - MpmAddPid(pmq, lower_pid); MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; @@ -1601,9 +1593,6 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - - MpmAddPid(pmq, pids[k]); MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; @@ -1719,7 +1708,7 @@ static int SCACBSTest01(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1753,7 +1742,7 @@ static int SCACBSTest02(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1790,7 +1779,7 @@ static int SCACBSTest03(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1824,7 +1813,7 @@ static int SCACBSTest04(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1858,7 +1847,7 @@ static int SCACBSTest05(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1890,7 +1879,7 @@ static int SCACBSTest06(void) SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1934,7 +1923,7 @@ static int SCACBSTest07(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); - PmqSetup(&pmq, 6); + PmqSetup(&pmq); /* total matches: 135 */ SCACBSPreparePatterns(&mpm_ctx); @@ -1968,7 +1957,7 @@ static int SCACBSTest08(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2000,7 +1989,7 @@ static int SCACBSTest09(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2032,7 +2021,7 @@ static int SCACBSTest10(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2075,7 +2064,7 @@ static int SCACBSTest11(void) goto end; if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) goto end; - PmqSetup(&pmq, 5); + PmqSetup(&pmq); if (SCACBSPreparePatterns(&mpm_ctx) == -1) goto end; @@ -2118,7 +2107,7 @@ static int SCACBSTest12(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2152,7 +2141,7 @@ static int SCACBSTest13(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2186,7 +2175,7 @@ static int SCACBSTest14(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2220,7 +2209,7 @@ static int SCACBSTest15(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2254,7 +2243,7 @@ static int SCACBSTest16(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2288,7 +2277,7 @@ static int SCACBSTest17(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2322,7 +2311,7 @@ static int SCACBSTest18(void) /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2356,7 +2345,7 @@ static int SCACBSTest19(void) /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2389,7 +2378,7 @@ static int SCACBSTest20(void) /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2422,7 +2411,7 @@ static int SCACBSTest21(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2456,7 +2445,7 @@ static int SCACBSTest22(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2489,7 +2478,7 @@ static int SCACBSTest23(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2521,7 +2510,7 @@ static int SCACBSTest24(void) /* 1 */ MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2554,7 +2543,7 @@ static int SCACBSTest25(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2587,7 +2576,7 @@ static int SCACBSTest26(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2620,7 +2609,7 @@ static int SCACBSTest27(void) /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2653,7 +2642,7 @@ static int SCACBSTest28(void) /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2688,7 +2677,7 @@ static int SCACBSTest29(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdef", 5, 0, 0, 1, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdefg", 5, 0, 0, 3, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"defgh", 5, 0, 0, 4, 0, 0); - PmqSetup(&pmq, 4); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index f0d873b6c1f8..663eb6607133 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -1499,7 +1499,6 @@ int CheckMatch(const SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, const uint8_t *buf_offset = buf + i + 1; // Lift out of loop uint32_t no_of_entries = ctx->output_table[state].no_of_entries; MpmPatternIndex *patterns = ctx->output_table[state].patterns; - uint8_t *pmq_bitarray = pmq->pattern_id_bitarray; uint32_t k; for (k = 0; k < no_of_entries; k++) { @@ -1515,7 +1514,6 @@ int CheckMatch(const SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, matches++; continue; } - uint32_t pid = pattern_list[pindex].pid; /* Double check case-sensitve match now. */ if (patterns[k] >> 31) { uint16_t patlen = pattern_list[pindex].patlen; @@ -1531,11 +1529,6 @@ int CheckMatch(const SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, /* New match found */ mpm_bitarray[pindex / 8] |= (1 << (pindex % 8)); - if ((pmq_bitarray[pid / 8] & (1 << (pid % 8))) == 0) { - pmq_bitarray[(pid) / 8] |= (1 << ((pid) % 8)); - MpmAddPid(pmq, pid); - } - /* Always add the Signature IDs, since they could be different in the current MPM * than in a previous MPM on the same PMQ when finding the same pattern. */ @@ -1852,7 +1845,7 @@ static int SCACTileTest01(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -1886,7 +1879,7 @@ static int SCACTileTest02(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -1923,7 +1916,7 @@ static int SCACTileTest03(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -1957,7 +1950,7 @@ static int SCACTileTest04(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -1991,7 +1984,7 @@ static int SCACTileTest05(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2023,7 +2016,7 @@ static int SCACTileTest06(void) SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2067,7 +2060,7 @@ static int SCACTileTest07(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); - PmqSetup(&pmq, 6); + PmqSetup(&pmq); /* total matches: 135 */ SCACTilePreparePatterns(&mpm_ctx); @@ -2101,7 +2094,7 @@ static int SCACTileTest08(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2133,7 +2126,7 @@ static int SCACTileTest09(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2165,7 +2158,7 @@ static int SCACTileTest10(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2208,7 +2201,7 @@ static int SCACTileTest11(void) goto end; if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) goto end; - PmqSetup(&pmq, 5); + PmqSetup(&pmq); if (SCACTilePreparePatterns(&mpm_ctx) == -1) goto end; @@ -2251,7 +2244,7 @@ static int SCACTileTest12(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2285,7 +2278,7 @@ static int SCACTileTest13(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2319,7 +2312,7 @@ static int SCACTileTest14(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2353,7 +2346,7 @@ static int SCACTileTest15(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2387,7 +2380,7 @@ static int SCACTileTest16(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2421,7 +2414,7 @@ static int SCACTileTest17(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2455,7 +2448,7 @@ static int SCACTileTest18(void) /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2489,7 +2482,7 @@ static int SCACTileTest19(void) /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2523,7 +2516,7 @@ static int SCACTileTest20(void) /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2556,7 +2549,7 @@ static int SCACTileTest21(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2590,7 +2583,7 @@ static int SCACTileTest22(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2623,7 +2616,7 @@ static int SCACTileTest23(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2655,7 +2648,7 @@ static int SCACTileTest24(void) /* 1 */ MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2688,7 +2681,7 @@ static int SCACTileTest25(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2721,7 +2714,7 @@ static int SCACTileTest26(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2754,7 +2747,7 @@ static int SCACTileTest27(void) /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2787,7 +2780,7 @@ static int SCACTileTest28(void) /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 85acc77b5f5a..2dca134f5138 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -1340,9 +1340,7 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - MpmAddPid(pmq, lower_pid); MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; @@ -1350,9 +1348,7 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { - pmq->pattern_id_bitarray[(pids[k]) / 8] |= (1 << ((pids[k]) % 8)); bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - MpmAddPid(pmq, pids[k]); MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; @@ -1384,9 +1380,7 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - MpmAddPid(pmq, lower_pid); MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; @@ -1394,9 +1388,7 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { - pmq->pattern_id_bitarray[(pids[k]) / 8] |= (1 << ((pids[k]) % 8)); bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - MpmAddPid(pmq, pids[k]); MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; @@ -1860,6 +1852,9 @@ uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, SCACOutputTable *output_table = ctx->output_table; SCACPatternList *pid_pat_list = ctx->pid_pat_list; + uint8_t bitarray[ctx->pattern_id_bitarray_size]; + memset(bitarray, 0, ctx->pattern_id_bitarray_size); + for (u = 0; u < cuda_matches; u += 2) { uint32_t offset = results[u]; uint32_t state = results[u + 1]; @@ -1882,17 +1877,19 @@ uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); } matches++; } @@ -2106,7 +2103,7 @@ static int SCACTest01(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2140,7 +2137,7 @@ static int SCACTest02(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2177,7 +2174,7 @@ static int SCACTest03(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2211,7 +2208,7 @@ static int SCACTest04(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2245,7 +2242,7 @@ static int SCACTest05(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2277,7 +2274,7 @@ static int SCACTest06(void) SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2321,7 +2318,7 @@ static int SCACTest07(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); - PmqSetup(&pmq, 6); + PmqSetup(&pmq); /* total matches: 135 */ SCACPreparePatterns(&mpm_ctx); @@ -2355,7 +2352,7 @@ static int SCACTest08(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2387,7 +2384,7 @@ static int SCACTest09(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2419,7 +2416,7 @@ static int SCACTest10(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2462,7 +2459,7 @@ static int SCACTest11(void) goto end; if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) goto end; - PmqSetup(&pmq, 5); + PmqSetup(&pmq); if (SCACPreparePatterns(&mpm_ctx) == -1) goto end; @@ -2505,7 +2502,7 @@ static int SCACTest12(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2539,7 +2536,7 @@ static int SCACTest13(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2573,7 +2570,7 @@ static int SCACTest14(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2607,7 +2604,7 @@ static int SCACTest15(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2641,7 +2638,7 @@ static int SCACTest16(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2675,7 +2672,7 @@ static int SCACTest17(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2709,7 +2706,7 @@ static int SCACTest18(void) /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2743,7 +2740,7 @@ static int SCACTest19(void) /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2777,7 +2774,7 @@ static int SCACTest20(void) /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2810,7 +2807,7 @@ static int SCACTest21(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2844,7 +2841,7 @@ static int SCACTest22(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2877,7 +2874,7 @@ static int SCACTest23(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2909,7 +2906,7 @@ static int SCACTest24(void) /* 1 */ MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2942,7 +2939,7 @@ static int SCACTest25(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2975,7 +2972,7 @@ static int SCACTest26(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -3008,7 +3005,7 @@ static int SCACTest27(void) /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -3041,7 +3038,7 @@ static int SCACTest28(void) /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index 4f7ed52fc029..e71a533d128d 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -920,8 +920,6 @@ static int SCHSMatchEvent(unsigned int id, unsigned long long from, " (pat id=%" PRIu32 ")", cctx->match_count, (uint32_t)id, (uintmax_t)to, pat->id); - pmq->pattern_id_bitarray[pat->id / 8] |= (1 << (pat->id % 8)); - MpmAddPid(pmq, pat->id); MpmAddSids(pmq, pat->sids, pat->sids_size); cctx->match_count++; @@ -1119,7 +1117,7 @@ static int SCHSTest01(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1153,7 +1151,7 @@ static int SCHSTest02(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1190,7 +1188,7 @@ static int SCHSTest03(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1224,7 +1222,7 @@ static int SCHSTest04(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1258,7 +1256,7 @@ static int SCHSTest05(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1290,7 +1288,7 @@ static int SCHSTest06(void) MpmInitCtx(&mpm_ctx, MPM_HS); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1334,7 +1332,7 @@ static int SCHSTest07(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); - PmqSetup(&pmq, 6); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1367,7 +1365,7 @@ static int SCHSTest08(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1399,7 +1397,7 @@ static int SCHSTest09(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1431,7 +1429,7 @@ static int SCHSTest10(void) /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1474,7 +1472,7 @@ static int SCHSTest11(void) goto end; if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) goto end; - PmqSetup(&pmq, 5); + PmqSetup(&pmq); if (SCHSPreparePatterns(&mpm_ctx) == -1) goto end; @@ -1518,7 +1516,7 @@ static int SCHSTest12(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1552,7 +1550,7 @@ static int SCHSTest13(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1586,7 +1584,7 @@ static int SCHSTest14(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1620,7 +1618,7 @@ static int SCHSTest15(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1654,7 +1652,7 @@ static int SCHSTest16(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1688,7 +1686,7 @@ static int SCHSTest17(void) /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1727,7 +1725,7 @@ static int SCHSTest18(void) "uvwxy" "z"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1766,7 +1764,7 @@ static int SCHSTest19(void) /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1806,7 +1804,7 @@ static int SCHSTest20(void) "AAAAA" "AA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1845,7 +1843,7 @@ static int SCHSTest21(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1879,7 +1877,7 @@ static int SCHSTest22(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1912,7 +1910,7 @@ static int SCHSTest23(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1944,7 +1942,7 @@ static int SCHSTest24(void) /* 1 */ MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -1977,7 +1975,7 @@ static int SCHSTest25(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -2010,7 +2008,7 @@ static int SCHSTest26(void) MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -2043,7 +2041,7 @@ static int SCHSTest27(void) /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); @@ -2076,7 +2074,7 @@ static int SCHSTest28(void) /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCHSPreparePatterns(&mpm_ctx); SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); diff --git a/src/util-mpm.c b/src/util-mpm.c index e3c5b12db6b6..1c4fe42e8a8b 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -409,16 +409,13 @@ void MpmCudaEnvironmentSetup() * \brief Setup a pmq * * \param pmq Pattern matcher queue to be initialized - * \param maxid Max sig id to be matched on - * \param patmaxid Max pattern id to be matched on * * \retval -1 error * \retval 0 ok */ -int PmqSetup(PatternMatcherQueue *pmq, uint32_t patmaxid) +int PmqSetup(PatternMatcherQueue *pmq) { SCEnter(); - SCLogDebug("patmaxid %u", patmaxid); if (pmq == NULL) { SCReturnInt(-1); @@ -426,38 +423,16 @@ int PmqSetup(PatternMatcherQueue *pmq, uint32_t patmaxid) memset(pmq, 0, sizeof(PatternMatcherQueue)); - if (patmaxid > 0) { - pmq->pattern_id_array_size = 32; /* Intial size, TODO Make this configure option */ - pmq->pattern_id_array_cnt = 0; - - pmq->pattern_id_array = SCCalloc(pmq->pattern_id_array_size, sizeof(uint32_t)); - if (pmq->pattern_id_array == NULL) { - SCReturnInt(-1); - } - - /* lookup bitarray */ - pmq->pattern_id_bitarray_size = (patmaxid / 8) + 1; - - pmq->pattern_id_bitarray = SCMalloc(pmq->pattern_id_bitarray_size); - if (pmq->pattern_id_bitarray == NULL) { - SCReturnInt(-1); - } - memset(pmq->pattern_id_bitarray, 0, pmq->pattern_id_bitarray_size); - - SCLogDebug("pmq->pattern_id_array %p, pmq->pattern_id_bitarray %p", - pmq->pattern_id_array, pmq->pattern_id_bitarray); - - pmq->rule_id_array_size = 128; /* Initial size, TODO: Make configure option. */ - pmq->rule_id_array_cnt = 0; + pmq->rule_id_array_size = 128; /* Initial size, TODO: Make configure option. */ + pmq->rule_id_array_cnt = 0; - size_t bytes = pmq->rule_id_array_size * sizeof(SigIntId); - pmq->rule_id_array = (SigIntId*)SCMalloc(bytes); - if (pmq->rule_id_array == NULL) { - pmq->rule_id_array_size = 0; - SCReturnInt(-1); - } - // Don't need to zero memory since it is always written first. + size_t bytes = pmq->rule_id_array_size * sizeof(SigIntId); + pmq->rule_id_array = (SigIntId*)SCMalloc(bytes); + if (pmq->rule_id_array == NULL) { + pmq->rule_id_array_size = 0; + SCReturnInt(-1); } + // Don't need to zero memory since it is always written first. SCReturnInt(0); } @@ -498,40 +473,6 @@ MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size) return new_size; } -/** \brief Increase the size of the Pattern rule ID array. - * - * \param pmq storage for match results - * \param new_size number of Signature IDs needing to be stored. - * - * \return 0 on failure. - */ -int -MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size) -{ - /* Need to make the array bigger. Double the size needed to - * also handle the case that sids_size might still be - * larger than the old size. - */ - new_size = new_size * 2; - uint32_t *new_array = (uint32_t*)SCRealloc(pmq->pattern_id_array, - new_size * sizeof(uint32_t)); - if (unlikely(new_array == NULL)) { - // Failed to allocate 2x, so try 1x. - new_size = new_size / 2; - new_array = (uint32_t*)SCRealloc(pmq->pattern_id_array, - new_size * sizeof(uint32_t)); - if (unlikely(new_array == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Failed to realloc PatternMatchQueue" - " pattern ID array. Some new Pattern ID matches were lost."); - return 0; - } - } - pmq->pattern_id_array = new_array; - pmq->pattern_id_array_size = new_size; - - return new_size; -} - /** * \brief Merge two pmq's bitarrays * @@ -540,17 +481,9 @@ MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size) */ void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst) { - uint32_t u; - - if (src->pattern_id_array_cnt == 0) + if (src->rule_id_array_cnt == 0) return; - for (u = 0; u < src->pattern_id_bitarray_size && u < dst->pattern_id_bitarray_size; u++) { - dst->pattern_id_bitarray[u] |= src->pattern_id_bitarray[u]; - } - - /** \todo now set merged flag? */ - if (src->rule_id_array && dst->rule_id_array) { MpmAddSids(dst, src->rule_id_array, src->rule_id_array_cnt); } @@ -566,10 +499,6 @@ void PmqReset(PatternMatcherQueue *pmq) if (pmq == NULL) return; - memset(pmq->pattern_id_bitarray, 0, pmq->pattern_id_bitarray_size); - - pmq->pattern_id_array_cnt = 0; - pmq->rule_id_array_cnt = 0; /* TODO: Realloc the rule id array smaller at some size? */ } @@ -581,24 +510,10 @@ void PmqCleanup(PatternMatcherQueue *pmq) { if (pmq == NULL) return; - - if (pmq->pattern_id_array != NULL) { - SCFree(pmq->pattern_id_array); - pmq->pattern_id_array = NULL; - } - - if (pmq->pattern_id_bitarray != NULL) { - SCFree(pmq->pattern_id_bitarray); - pmq->pattern_id_bitarray = NULL; - } - if (pmq->rule_id_array != NULL) { SCFree(pmq->rule_id_array); pmq->rule_id_array = NULL; } - - pmq->pattern_id_array_cnt = 0; - pmq->pattern_id_array_size = 0; } /** \brief Cleanup and free a Pmq diff --git a/src/util-mpm.h b/src/util-mpm.h index cbb236d13022..5cbdc9355b7e 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -65,16 +65,8 @@ typedef struct MpmThreadCtx_ { * thread has this and passes a pointer to it to the pattern matcher. * The actual pattern matcher will fill the structure. */ typedef struct PatternMatcherQueue_ { - uint32_t *pattern_id_array; /** array with pattern id's that had a - pattern match. These will be inspected - futher by the detection engine. */ - uint32_t pattern_id_array_cnt; /**< Number currently stored */ - uint32_t pattern_id_array_size; /**< Allocated size in bytes */ - - uint8_t *pattern_id_bitarray; /** bitarray with pattern id matches */ - uint32_t pattern_id_bitarray_size; /**< size in bytes */ - /* used for storing rule id's */ + /* Array of rule IDs found. */ SigIntId *rule_id_array; /* Number of rule IDs in the array. */ @@ -210,7 +202,7 @@ MpmCtx *MpmFactoryGetMpmCtxForProfile(const struct DetectEngineCtx_ *, int32_t, void MpmFactoryDeRegisterAllMpmCtxProfiles(struct DetectEngineCtx_ *); int32_t MpmFactoryIsMpmCtxAvailable(const struct DetectEngineCtx_ *, const MpmCtx *); -int PmqSetup(PatternMatcherQueue *, uint32_t); +int PmqSetup(PatternMatcherQueue *); void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst); void PmqReset(PatternMatcherQueue *); void PmqCleanup(PatternMatcherQueue *); @@ -265,20 +257,4 @@ MpmAddSids(PatternMatcherQueue *pmq, SigIntId *sids, uint32_t sids_size) } while (ptr != end); pmq->rule_id_array_cnt += sids_size; } - -/* Resize Pattern ID array. Only called from MpmAddPid(). */ -int MpmAddPidResize(PatternMatcherQueue *pmq, uint32_t new_size); - -static inline void -MpmAddPid(PatternMatcherQueue *pmq, uint32_t patid) -{ - uint32_t new_size = pmq->pattern_id_array_cnt + 1; - if (new_size > pmq->pattern_id_array_size) { - if (MpmAddPidResize(pmq, new_size) == 0) - return; - } - pmq->pattern_id_array[pmq->pattern_id_array_cnt] = patid; - pmq->pattern_id_array_cnt = new_size; - SCLogDebug("pattern_id_array_cnt %u", pmq->pattern_id_array_cnt); -} #endif /* __UTIL_MPM_H__ */ From 810d2d3ec692053d860009271a9cb2d3827c7fc0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 9 Oct 2015 10:12:11 +0200 Subject: [PATCH 1177/2553] detect: add list id to string funcs --- src/detect.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/detect.c b/src/detect.c index 7682f28aa570..0d7fb84b11b4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2808,6 +2808,85 @@ static void SigParseApplyDsizeToContent(Signature *s) } } +const char *DetectListToHumanString(int list) +{ +#define CASE_CODE_STRING(E, S) case E: return S; break + switch (list) { + CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); + CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); + CASE_CODE_STRING(DETECT_SM_LIST_UMATCH, "http_uri"); + CASE_CODE_STRING(DETECT_SM_LIST_HRUDMATCH, "http_raw_uri"); + CASE_CODE_STRING(DETECT_SM_LIST_HCBDMATCH, "http_client_body"); + CASE_CODE_STRING(DETECT_SM_LIST_FILEDATA, "file_data"); + CASE_CODE_STRING(DETECT_SM_LIST_HHDMATCH, "http_header"); + CASE_CODE_STRING(DETECT_SM_LIST_HRHDMATCH, "http_raw_header"); + CASE_CODE_STRING(DETECT_SM_LIST_HSMDMATCH, "http_stat_msg"); + CASE_CODE_STRING(DETECT_SM_LIST_HSCDMATCH, "http_stat_code"); + CASE_CODE_STRING(DETECT_SM_LIST_HHHDMATCH, "http_host"); + CASE_CODE_STRING(DETECT_SM_LIST_HRHHDMATCH, "http_raw_host"); + CASE_CODE_STRING(DETECT_SM_LIST_HMDMATCH, "http_method"); + CASE_CODE_STRING(DETECT_SM_LIST_HCDMATCH, "http_cookie"); + CASE_CODE_STRING(DETECT_SM_LIST_HUADMATCH, "http_user_agent"); + CASE_CODE_STRING(DETECT_SM_LIST_HRLMATCH, "http_request_line"); + CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); + CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); + CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); + CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); + CASE_CODE_STRING(DETECT_SM_LIST_FILEMATCH, "file"); + CASE_CODE_STRING(DETECT_SM_LIST_DNSREQUEST_MATCH, "dns_request"); + CASE_CODE_STRING(DETECT_SM_LIST_DNSRESPONSE_MATCH, "dns_response"); + CASE_CODE_STRING(DETECT_SM_LIST_DNSQUERYNAME_MATCH, "dns_query"); + CASE_CODE_STRING(DETECT_SM_LIST_MODBUS_MATCH, "modbus"); + CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); + CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); + CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress"); + CASE_CODE_STRING(DETECT_SM_LIST_THRESHOLD, "threshold"); + CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)"); + CASE_CODE_STRING(DETECT_SM_LIST_NOTSET, "not set (internal)"); + } +#undef CASE_CODE_STRING + return "unknown"; +} + +#define CASE_CODE(E) case E: return #E +const char *DetectListToString(int list) +{ + switch (list) { + CASE_CODE(DETECT_SM_LIST_MATCH); + CASE_CODE(DETECT_SM_LIST_PMATCH); + CASE_CODE(DETECT_SM_LIST_UMATCH); + CASE_CODE(DETECT_SM_LIST_HRUDMATCH); + CASE_CODE(DETECT_SM_LIST_HCBDMATCH); + CASE_CODE(DETECT_SM_LIST_FILEDATA); + CASE_CODE(DETECT_SM_LIST_HHDMATCH); + CASE_CODE(DETECT_SM_LIST_HRHDMATCH); + CASE_CODE(DETECT_SM_LIST_HSMDMATCH); + CASE_CODE(DETECT_SM_LIST_HSCDMATCH); + CASE_CODE(DETECT_SM_LIST_HHHDMATCH); + CASE_CODE(DETECT_SM_LIST_HRHHDMATCH); + CASE_CODE(DETECT_SM_LIST_HMDMATCH); + CASE_CODE(DETECT_SM_LIST_HCDMATCH); + CASE_CODE(DETECT_SM_LIST_HUADMATCH); + CASE_CODE(DETECT_SM_LIST_HRLMATCH); + CASE_CODE(DETECT_SM_LIST_APP_EVENT); + CASE_CODE(DETECT_SM_LIST_AMATCH); + CASE_CODE(DETECT_SM_LIST_DMATCH); + CASE_CODE(DETECT_SM_LIST_TMATCH); + CASE_CODE(DETECT_SM_LIST_FILEMATCH); + CASE_CODE(DETECT_SM_LIST_DNSREQUEST_MATCH); + CASE_CODE(DETECT_SM_LIST_DNSRESPONSE_MATCH); + CASE_CODE(DETECT_SM_LIST_DNSQUERYNAME_MATCH); + CASE_CODE(DETECT_SM_LIST_MODBUS_MATCH); + CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); + CASE_CODE(DETECT_SM_LIST_POSTMATCH); + CASE_CODE(DETECT_SM_LIST_SUPPRESS); + CASE_CODE(DETECT_SM_LIST_THRESHOLD); + CASE_CODE(DETECT_SM_LIST_MAX); + CASE_CODE(DETECT_SM_LIST_NOTSET); + } + return "unknown"; +} + /** \brief Pure-PCRE or bytetest rule */ int RuleInspectsPayloadHasNoMpm(const Signature *s) { From 4ba1ac55f063d488f6f3b0b513b0f93317c753f0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 30 Sep 2015 09:59:05 +0200 Subject: [PATCH 1178/2553] detect: output sgh stats Output stats for the rule groups into a json format. --- src/detect.c | 310 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) diff --git a/src/detect.c b/src/detect.c index 0d7fb84b11b4..62cbb15a8436 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2921,6 +2921,313 @@ int RuleMpmIsNegated(const Signature *s) return (cd->flags & DETECT_CONTENT_NEGATED); } +#ifdef HAVE_LIBJANSSON +json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh) +{ + uint32_t mpm_cnt = 0; + uint32_t nonmpm_cnt = 0; + uint32_t negmpm_cnt = 0; + uint32_t any5_cnt = 0; + uint32_t payload_no_mpm_cnt = 0; + uint32_t syn_cnt = 0; + + uint32_t mpms_total = 0; + uint32_t mpms_min = 0; + uint32_t mpms_max = 0; + + struct { + uint32_t total; + uint32_t cnt; + uint32_t min; + uint32_t max; + } mpm_stats[DETECT_SM_LIST_MAX]; + memset(mpm_stats, 0x00, sizeof(mpm_stats)); + + uint32_t alstats[ALPROTO_MAX] = {0}; + uint32_t mpm_sizes[DETECT_SM_LIST_MAX][256]; + memset(mpm_sizes, 0, sizeof(mpm_sizes)); + uint32_t alproto_mpm_bufs[ALPROTO_MAX][DETECT_SM_LIST_MAX]; + memset(alproto_mpm_bufs, 0, sizeof(alproto_mpm_bufs)); + + json_t *js = json_object(); + if (unlikely(js == NULL)) + return NULL; + + json_t *js_array = json_array(); + + const Signature *s; + uint32_t x; + for (x = 0; x < sgh->sig_cnt; x++) { + s = sgh->match_array[x]; + if (s == NULL) + continue; +#if 0 + json_t *js_sig = json_object(); + if (unlikely(js == NULL)) + continue; + json_object_set_new(js_sig, "sig_id", json_integer(s->id)); +#endif + int any = 0; + if (s->proto.flags & DETECT_PROTO_ANY) { + any++; + } + if (s->flags & SIG_FLAG_DST_ANY) { + any++; + } + if (s->flags & SIG_FLAG_SRC_ANY) { + any++; + } + if (s->flags & SIG_FLAG_DP_ANY) { + any++; + } + if (s->flags & SIG_FLAG_SP_ANY) { + any++; + } + if (any == 5) { + any5_cnt++; + } + + if (s->mpm_sm == NULL) { + nonmpm_cnt++; + + if (s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { + SCLogDebug("SGH %p Non-MPM inspecting only packets. Rule %u", sgh, s->id); + } + + DetectPort *sp = s->sp; + DetectPort *dp = s->dp; + + if (s->flags & SIG_FLAG_TOSERVER && (dp->port == 0 && dp->port2 == 65535)) { + SCLogDebug("SGH %p Non-MPM toserver and to 'any'. Rule %u", sgh, s->id); + } + if (s->flags & SIG_FLAG_TOCLIENT && (sp->port == 0 && sp->port2 == 65535)) { + SCLogDebug("SGH %p Non-MPM toclient and to 'any'. Rule %u", sgh, s->id); + } + + if (DetectFlagsSignatureNeedsSynPackets(s)) { + syn_cnt++; + } + + } else { + int mpm_list = SigMatchListSMBelongsTo(s, s->mpm_sm); + BUG_ON(mpm_list < 0); + const DetectContentData *cd = (const DetectContentData *)s->mpm_sm->ctx; + uint32_t size = cd->content_len < 256 ? cd->content_len : 255; + + mpm_sizes[mpm_list][size]++; + if (s->alproto != ALPROTO_UNKNOWN) { + alproto_mpm_bufs[s->alproto][mpm_list]++; + } + + if (mpm_list == DETECT_SM_LIST_PMATCH) { + if (size == 1) { + DetectPort *sp = s->sp; + DetectPort *dp = s->dp; + if (s->flags & SIG_FLAG_TOSERVER) { + if (dp->port == 0 && dp->port2 == 65535) { + SCLogDebug("SGH %p toserver 1byte fast_pattern to ANY. Rule %u", sgh, s->id); + } else { + SCLogDebug("SGH %p toserver 1byte fast_pattern to port(s) %u-%u. Rule %u", sgh, dp->port, dp->port2, s->id); + } + } + if (s->flags & SIG_FLAG_TOCLIENT) { + if (sp->port == 0 && sp->port2 == 65535) { + SCLogDebug("SGH %p toclient 1byte fast_pattern to ANY. Rule %u", sgh, s->id); + } else { + SCLogDebug("SGH %p toclient 1byte fast_pattern to port(s) %u-%u. Rule %u", sgh, sp->port, sp->port2, s->id); + } + } + } + } + + uint32_t w = PatternStrength(cd->content, cd->content_len); + mpms_total += w; + if (mpms_min == 0) + mpms_min = w; + if (w < mpms_min) + mpms_min = w; + if (w > mpms_max) + mpms_max = w; + + mpm_stats[mpm_list].total += w; + mpm_stats[mpm_list].cnt++; + if (mpm_stats[mpm_list].min == 0 || w < mpm_stats[mpm_list].min) + mpm_stats[mpm_list].min = w; + if (w > mpm_stats[mpm_list].max) + mpm_stats[mpm_list].max = w; + + mpm_cnt++; + + if (w < 10) { + SCLogDebug("SGH %p Weak MPM Pattern on %s. Rule %u", sgh, DetectListToString(mpm_list), s->id); + } + if (w < 10 && any == 5) { + SCLogDebug("SGH %p Weak MPM Pattern on %s, rule is 5xAny. Rule %u", sgh, DetectListToString(mpm_list), s->id); + } + + if (cd->flags & DETECT_CONTENT_NEGATED) { + SCLogDebug("SGH %p MPM Pattern on %s, is negated. Rule %u", sgh, DetectListToString(mpm_list), s->id); + negmpm_cnt++; + } + } + + if (RuleInspectsPayloadHasNoMpm(s)) { + SCLogDebug("SGH %p No MPM. Payload inspecting. Rule %u", sgh, s->id); + payload_no_mpm_cnt++; + } + + if (s->alproto != ALPROTO_UNKNOWN) { + alstats[s->alproto]++; + } +// json_array_append_new(js_array, js_sig); + } + + json_object_set_new(js, "rules", js_array); + + json_t *stats = json_object(); + json_object_set_new(stats, "total", json_integer(sgh->sig_cnt)); + + json_t *types = json_object(); + json_object_set_new(types, "mpm", json_integer(mpm_cnt)); + json_object_set_new(types, "non_mpm", json_integer(nonmpm_cnt)); + json_object_set_new(types, "negated_mpm", json_integer(negmpm_cnt)); + json_object_set_new(types, "payload_but_no_mpm", json_integer(payload_no_mpm_cnt)); + json_object_set_new(types, "syn", json_integer(syn_cnt)); + json_object_set_new(types, "any5", json_integer(any5_cnt)); + json_object_set_new(stats, "types", types); + + int i; + for (i = 0; i < ALPROTO_MAX; i++) { + if (alstats[i] > 0) { + json_t *app = json_object(); + json_object_set_new(app, "total", json_integer(alstats[i])); + + for (x = 0; x < DETECT_SM_LIST_MAX; x++) { + if (alproto_mpm_bufs[i][x] == 0) + continue; + json_object_set_new(app, DetectListToHumanString(x), json_integer(alproto_mpm_bufs[i][x])); + } + + json_object_set_new(stats, AppProtoToString(i), app); + } + } + + json_t *mpm_js = json_object(); + + for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + if (mpm_stats[i].cnt > 0) { + + json_t *mpm_sizes_array = json_array(); + for (x = 0; x < 256; x++) { + if (mpm_sizes[i][x] == 0) + continue; + + json_t *e = json_object(); + json_object_set_new(e, "size", json_integer(x)); + json_object_set_new(e, "count", json_integer(mpm_sizes[i][x])); + json_array_append_new(mpm_sizes_array, e); + } + + json_t *buf = json_object(); + json_object_set_new(buf, "total", json_integer(mpm_stats[i].cnt)); + json_object_set_new(buf, "avg_strength", json_integer(mpm_stats[i].total / mpm_stats[i].cnt)); + json_object_set_new(buf, "min_strength", json_integer(mpm_stats[i].min)); + json_object_set_new(buf, "max_strength", json_integer(mpm_stats[i].max)); + + json_object_set_new(buf, "sizes", mpm_sizes_array); + + json_object_set_new(mpm_js, DetectListToHumanString(i), buf); + } + } + + json_object_set_new(stats, "mpm", mpm_js); + json_object_set_new(js, "stats", stats); + + json_object_set_new(js, "whitelist", json_integer(sgh->init->whitelist)); + + return js; +} +#endif /* HAVE_LIBJANSSON */ + +void RulesDumpGrouping(const DetectEngineCtx *de_ctx) +{ +#ifdef HAVE_LIBJANSSON + json_t *js = json_object(); + if (unlikely(js == NULL)) + return; + + int p; + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) { + const char *name = (p == IPPROTO_TCP) ? "tcp" : "udp"; + + json_t *tcp = json_object(); + + json_t *ts_array = json_array(); + DetectPort *list = (p == IPPROTO_TCP) ? de_ctx->flow_gh[1].tcp : + de_ctx->flow_gh[1].udp; + while (list != NULL) { + json_t *port = json_object(); + json_object_set_new(port, "port", json_integer(list->port)); + json_object_set_new(port, "port2", json_integer(list->port2)); + + json_t *tcp_ts = RulesGroupPrintSghStats(list->sh); + json_object_set_new(port, "rulegroup", tcp_ts); + json_array_append_new(ts_array, port); + + list = list->next; + } + json_object_set_new(tcp, "toserver", ts_array); + + json_t *tc_array = json_array(); + list = (p == IPPROTO_TCP) ? de_ctx->flow_gh[0].tcp : + de_ctx->flow_gh[0].udp; + while (list != NULL) { + json_t *port = json_object(); + json_object_set_new(port, "port", json_integer(list->port)); + json_object_set_new(port, "port2", json_integer(list->port2)); + + json_t *tcp_tc = RulesGroupPrintSghStats(list->sh); + json_object_set_new(port, "rulegroup", tcp_tc); + json_array_append_new(tc_array, port); + + list = list->next; + } + json_object_set_new(tcp, "toclient", tc_array); + + json_object_set_new(js, name, tcp); + } + + } + + const char *filename = "rule_group.json"; + const char *log_dir = ConfigGetLogDirectory(); + char log_path[PATH_MAX] = ""; + + snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename); + + FILE *fp = fopen(log_path, "w"); + if (fp == NULL) { + return; + } + + char *js_s = json_dumps(js, + JSON_PRESERVE_ORDER|JSON_ESCAPE_SLASH); + if (unlikely(js_s == NULL)) { + fclose(fp); + return; + } + + json_object_clear(js); + json_decref(js); + + fprintf(fp, "%s\n", js_s); + free(js_s); + fclose(fp); +#endif + return; +} + int RulesGroupByProto(DetectEngineCtx *de_ctx) { Signature *s = de_ctx->sig_list; @@ -3018,6 +3325,7 @@ int RulesGroupByProto(DetectEngineCtx *de_ctx) de_ctx->gh_unique++; own++; + } else { SCLogDebug("proto group %d sgh %p is a copy", p, sgh_tc[p]); @@ -3734,6 +4042,8 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) de_ctx->sgh_array_cnt = 0; de_ctx->sgh_array_size = 0; + RulesDumpGrouping(de_ctx); + SCReturnInt(0); } From 2ab20d0b9bfa8af1688c886869938192e18f2f26 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 17:49:25 +0200 Subject: [PATCH 1179/2553] detect: free lookup structures --- src/detect.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/detect.c b/src/detect.c index 62cbb15a8436..7dec44493529 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3507,6 +3507,7 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 SigGroupHeadSetProtoAndDirection(iter->sh, ipproto, direction); SigGroupHeadHashAdd(de_ctx, iter->sh); SigGroupHeadStore(de_ctx, iter->sh); + iter->flags |= PORT_SIGGROUPHEAD_COPY; de_ctx->gh_unique++; own++; } else { @@ -3931,6 +3932,21 @@ int SigAddressCleanupStage1(DetectEngineCtx *de_ctx) SigGroupHeadFree(de_ctx->decoder_event_sgh); de_ctx->decoder_event_sgh = NULL; + int f; + for (f = 0; f < FLOW_STATES; f++) { + int p; + for (p = 0; p < 256; p++) { + de_ctx->flow_gh[f].sgh[p] = NULL; + } + + /* free lookup lists */ + DetectPortCleanupList(de_ctx->flow_gh[f].tcp); + de_ctx->flow_gh[f].tcp = NULL; + DetectPortCleanupList(de_ctx->flow_gh[f].udp); + de_ctx->flow_gh[f].udp = NULL; + } + + IPOnlyDeinit(de_ctx, &de_ctx->io_ctx); if (!(de_ctx->flags & DE_QUIET)) { From e8c95980354bc1e0ce2dfdc039b2684095d626d5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 18:21:42 +0200 Subject: [PATCH 1180/2553] detect sgh: remove unused field --- src/detect.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/detect.h b/src/detect.h index ab4674508b26..55bfafa2f456 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1005,12 +1005,6 @@ typedef struct SigGroupHead_ { /* track min pattern length for content. Used in grouping */ uint16_t mpm_content_minlen; - /** array of masks, used to check multiple masks against - * a packet using SIMD. */ -#if defined(__SSE3__) || defined(__tile__) - SignatureMask *mask_array; -#endif - /* non mpm list excluding SYN rules */ SignatureNonMpmStore *non_mpm_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) uint32_t non_mpm_other_store_cnt; From 1f7e33a4b002167045e98d4878b45b73d6401194 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 18:39:57 +0200 Subject: [PATCH 1181/2553] detect: remove unused flag --- src/detect.c | 3 --- src/detect.h | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/detect.c b/src/detect.c index 7dec44493529..64c14025be8a 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3294,7 +3294,6 @@ int RulesGroupByProto(DetectEngineCtx *de_ctx) SigGroupHeadFree(sgh_ts[p]); sgh_ts[p] = lookup_sgh; - sgh_ts[p]->flags |= SIG_GROUP_HEAD_REFERENCED; de_ctx->gh_reuse++; ref++; @@ -3331,7 +3330,6 @@ int RulesGroupByProto(DetectEngineCtx *de_ctx) SigGroupHeadFree(sgh_tc[p]); sgh_tc[p] = lookup_sgh; - sgh_tc[p]->flags |= SIG_GROUP_HEAD_REFERENCED; de_ctx->gh_reuse++; ref++; @@ -3516,7 +3514,6 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 SigGroupHeadFree(iter->sh); iter->sh = lookup_sgh; iter->flags |= PORT_SIGGROUPHEAD_COPY; - iter->sh->flags |= SIG_GROUP_HEAD_REFERENCED; de_ctx->gh_reuse++; ref++; diff --git a/src/detect.h b/src/detect.h index 55bfafa2f456..41ca8412d41d 100644 --- a/src/detect.h +++ b/src/detect.h @@ -949,7 +949,7 @@ typedef struct SigTableElmt_ { #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) From e6248b0dbe849274871a7291019ad337fba90e02 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 20:05:42 +0200 Subject: [PATCH 1182/2553] detect: clean up sgh's at detect engine free --- src/detect.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/detect.c b/src/detect.c index 64c14025be8a..475bbbb5a46e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3943,6 +3943,19 @@ int SigAddressCleanupStage1(DetectEngineCtx *de_ctx) de_ctx->flow_gh[f].udp = NULL; } + uint32_t idx; + for (idx = 0; idx < de_ctx->sgh_array_cnt; idx++) { + SigGroupHead *sgh = de_ctx->sgh_array[idx]; + if (sgh == NULL) + continue; + + SCLogDebug("sgh %p", sgh); + SigGroupHeadFree(sgh); + } + SCFree(de_ctx->sgh_array); + de_ctx->sgh_array = NULL; + de_ctx->sgh_array_cnt = 0; + de_ctx->sgh_array_size = 0; IPOnlyDeinit(de_ctx, &de_ctx->io_ctx); @@ -4019,6 +4032,8 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) if (sgh == NULL) continue; + SCLogDebug("sgh %p", sgh); + SigGroupHeadSetFilemagicFlag(de_ctx, sgh); SigGroupHeadSetFileMd5Flag(de_ctx, sgh); SigGroupHeadSetFilesizeFlag(de_ctx, sgh); @@ -4051,10 +4066,6 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SigGroupHeadHashFree(de_ctx); SigGroupHeadDPortHashFree(de_ctx); - SCFree(de_ctx->sgh_array); - de_ctx->sgh_array_cnt = 0; - de_ctx->sgh_array_size = 0; - RulesDumpGrouping(de_ctx); SCReturnInt(0); From a96fa0fc2fca9763ad007fd692abd88b8d003315 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 21:33:44 +0200 Subject: [PATCH 1183/2553] detect: remove unused dport sgh hash --- src/detect-engine-port.h | 16 --- src/detect-engine-siggroup.c | 202 ----------------------------------- src/detect-engine.c | 2 - src/detect.c | 6 -- src/detect.h | 2 - 5 files changed, 228 deletions(-) diff --git a/src/detect-engine-port.h b/src/detect-engine-port.h index e23c1e476e63..1c089e9f9648 100644 --- a/src/detect-engine-port.h +++ b/src/detect-engine-port.h @@ -33,26 +33,10 @@ int DetectPortInsertCopy(DetectEngineCtx *,DetectPort **, DetectPort *); int DetectPortInsert(DetectEngineCtx *,DetectPort **, DetectPort *); void DetectPortCleanupList (DetectPort *head); -DetectPort *DetectPortLookup(DetectPort *head, DetectPort *dp); -int DetectPortAdd(DetectPort **head, DetectPort *dp); - DetectPort *DetectPortLookupGroup(DetectPort *dp, uint16_t port); void DetectPortPrintMemory(void); -DetectPort *DetectPortDpHashLookup(DetectEngineCtx *, DetectPort *); -DetectPort *DetectPortDpHashGetListPtr(DetectEngineCtx *); -int DetectPortDpHashInit(DetectEngineCtx *); -void DetectPortDpHashFree(DetectEngineCtx *); -int DetectPortDpHashAdd(DetectEngineCtx *, DetectPort *); -void DetectPortDpHashReset(DetectEngineCtx *); - -DetectPort *DetectPortSpHashLookup(DetectEngineCtx *, DetectPort *); -int DetectPortSpHashInit(DetectEngineCtx *); -void DetectPortSpHashFree(DetectEngineCtx *); -int DetectPortSpHashAdd(DetectEngineCtx *, DetectPort *); -void DetectPortSpHashReset(DetectEngineCtx *); - int DetectPortJoin(DetectEngineCtx *,DetectPort *target, DetectPort *source); void DetectPortPrint(DetectPort *); diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 544a32d29176..243cf6aeb7ef 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -344,185 +344,6 @@ void SigGroupHeadHashFree(DetectEngineCtx *de_ctx) return; } -/** - * \brief Initializes the dport based SigGroupHead hash table to hold the - * SigGroupHeads. The hash table that would be initialized is - * DetectEngineCtx->sgh_dport_hash_table. - * - * \param de_ctx Pointer to the detection engine context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadDPortHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sgh_dport_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc, - SigGroupHeadCompareFunc, - NULL); - if (de_ctx->sgh_dport_hash_table == NULL) - goto error; - - return 0; - -error: - return -1; -} - -/** - * \brief Adds a SigGroupHead to the detection engine context dport based - * SigGroupHead hash table(DetectEngineCtx->sgh_dport_hash_table). - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. - */ -int SigGroupHeadDPortHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - int ret = HashListTableAdd(de_ctx->sgh_dport_hash_table, (void *)sgh, 0); - - return ret; -} - -/** - * \brief Used to lookup a SigGroupHead hash from the detection engine ctx dport - * based SigGroupHead hash table(DetectEngineCtx->sgh_dport_hash_table). - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is - * found in the hash table; NULL on failure. - */ -SigGroupHead *SigGroupHeadDPortHashLookup(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - SCEnter(); - - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_dport_hash_table, - (void *)sgh, 0); - - SCReturnPtr(rsgh,"SigGroupHead"); -} - -/** - * \brief Frees the hash table - DetectEngineCtx->sgh_dport_hash_table, - * allocated by the SigGroupHeadDPortHashInit() function. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadDPortHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->sgh_dport_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sgh_dport_hash_table); - de_ctx->sgh_dport_hash_table = NULL; - - return; -} - -/** - * \brief Used to free the signature array, content_array and uri_content_array - * members from the SigGroupHeads in the HashListTable. - * - * \param de_ctx Pointer to the detection engine context. - * \param ht Pointer to the HashListTable - */ -static void SigGroupHeadFreeSigArraysHash2(DetectEngineCtx *de_ctx, - HashListTable *ht) -{ - HashListTableBucket *htb = NULL; - SigGroupHead *sgh = NULL; - - for (htb = HashListTableGetListHead(ht); - htb != NULL; - htb = HashListTableGetListNext(htb)) - { - sgh = (SigGroupHead *)HashListTableGetListData(htb); - if (sgh == NULL) { - continue; - } - - if (sgh->init->sig_array != NULL) { - detect_siggroup_sigarray_free_cnt++; - detect_siggroup_sigarray_memory -= sgh->init->sig_size; - - SCFree(sgh->init->sig_array); - sgh->init->sig_array = NULL; - sgh->init->sig_size = 0; - } - - SigGroupHeadInitDataFree(sgh->init); - sgh->init = NULL; - } - - return; -} - -/** - * \brief Used to free the sig_array member of the SigGroupHeads present - * in the HashListTable. - * - * \param de_ctx Pointer to the detection engine context. - * \param ht Pointer to the HashListTable - */ -static void SigGroupHeadFreeSigArraysHash(DetectEngineCtx *de_ctx, - HashListTable *ht) -{ - HashListTableBucket *htb = NULL; - SigGroupHead *sgh = NULL; - - for (htb = HashListTableGetListHead(ht); - htb != NULL; - htb = HashListTableGetListNext(htb)) { - sgh = (SigGroupHead *)HashListTableGetListData(htb); - - if (sgh->init != NULL) { - SigGroupHeadInitDataFree(sgh->init); - sgh->init = NULL; - } - } - - return; -} - -/** - * \brief Free the sigarrays in the sgh's. Those are only used during the init - * stage. - * - * \param de_ctx Pointer to the detection engine context whose sigarrays have to - * be freed. - */ -void SigGroupHeadFreeSigArrays(DetectEngineCtx *de_ctx) -{ - SigGroupHeadFreeSigArraysHash2(de_ctx, de_ctx->sgh_hash_table); - SigGroupHeadFreeSigArraysHash(de_ctx, de_ctx->sgh_dport_hash_table); - - return; -} - -/** - * \brief Free the mpm arrays that are only used during the init stage. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadFreeMpmArrays(DetectEngineCtx *de_ctx) -{ - HashListTableBucket *htb = NULL; - SigGroupHead *sgh = NULL; - - for (htb = HashListTableGetListHead(de_ctx->sgh_dport_hash_table); htb != NULL; htb = HashListTableGetListNext(htb)) { - sgh = (SigGroupHead *)HashListTableGetListData(htb); - if (sgh->init != NULL) { - SigGroupHeadInitDataFree(sgh->init); - sgh->init = NULL; - } - } - - return; -} - static uint16_t SignatureGetMpmPatternLen(const Signature *s, const int list) { if (s->sm_lists[list] != NULL && s->mpm_sm != NULL && @@ -1106,28 +927,6 @@ static int SigGroupHeadTest03(void) return result; } -/** - * \test Check if a SigGroupHead dport hash table is properly allocated and - * deallocated when calling SigGroupHeadDPortHashInit() and - * SigGroupHeadDportHashFree() respectively. - */ -static int SigGroupHeadTest04(void) -{ - int result = 1; - - DetectEngineCtx de_ctx; - - SigGroupHeadDPortHashInit(&de_ctx); - - result &= (de_ctx.sgh_dport_hash_table != NULL); - - SigGroupHeadDPortHashFree(&de_ctx); - - result &= (de_ctx.sgh_dport_hash_table == NULL); - - return result; -} - /** * \test Check if a SigGroupHeadAppendSig() correctly appends a sid to a * SigGroupHead() and SigGroupHeadContainsSigId() correctly indicates @@ -1591,7 +1390,6 @@ void SigGroupHeadRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03, 1); - UtRegisterTest("SigGroupHeadTest04", SigGroupHeadTest04, 1); UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06, 1); UtRegisterTest("SigGroupHeadTest07", SigGroupHeadTest07, 1); UtRegisterTest("SigGroupHeadTest08", SigGroupHeadTest08, 1); diff --git a/src/detect-engine.c b/src/detect-engine.c index deecae489535..842e8db26125 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -872,7 +872,6 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) SigGroupHeadHashInit(de_ctx); MpmStoreInit(de_ctx); - SigGroupHeadDPortHashInit(de_ctx); ThresholdHashInit(de_ctx); VariableNameInitHash(de_ctx); DetectParseDupSigHashInit(de_ctx); @@ -957,7 +956,6 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) */ SigGroupHeadHashFree(de_ctx); MpmStoreFree(de_ctx); - SigGroupHeadDPortHashFree(de_ctx); DetectParseDupSigHashFree(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); ThresholdContextDestroy(de_ctx); diff --git a/src/detect.c b/src/detect.c index 475bbbb5a46e..9189b4612ff8 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4056,15 +4056,9 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) * signature not decode event only. */ } - /* cleanup group head (uri)content_array's */ - SigGroupHeadFreeMpmArrays(de_ctx); - /* cleanup group head sig arrays */ - SigGroupHeadFreeSigArrays(de_ctx); - /* cleanup the hashes now since we won't need them * after the initialization phase. */ SigGroupHeadHashFree(de_ctx); - SigGroupHeadDPortHashFree(de_ctx); RulesDumpGrouping(de_ctx); diff --git a/src/detect.h b/src/detect.h index 41ca8412d41d..9ef5f18dd94d 100644 --- a/src/detect.h +++ b/src/detect.h @@ -611,8 +611,6 @@ typedef struct DetectEngineCtx_ { HashListTable *mpm_hash_table; - HashListTable *sgh_dport_hash_table; - HashListTable *variable_names; HashListTable *variable_idxs; uint16_t variable_names_idx; From cbf80de6fe6de423344a40597aca1891b192fed2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 21:48:41 +0200 Subject: [PATCH 1184/2553] detect-port: cleanup --- src/detect-engine-port.c | 41 ---------------------------------------- src/detect.h | 14 +++----------- 2 files changed, 3 insertions(+), 52 deletions(-) diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index ac530f1d9884..f8c2e48f2f26 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -99,13 +99,6 @@ void DetectPortFree(DetectPort *dp) } dp->sh = NULL; - if (dp->dst_ph != NULL && !(dp->flags & PORT_GROUP_PORTS_COPY)) { - DetectPortCleanupList(dp->dst_ph); - } - dp->dst_ph = NULL; - - //BUG_ON(dp->next != NULL); - detect_port_memory -= sizeof(DetectPort); detect_port_free_cnt++; SCFree(dp); @@ -289,7 +282,6 @@ int DetectPortInsert(DetectEngineCtx *de_ctx, DetectPort **head, /* exact overlap/match */ if (cur != new) { SigGroupHeadCopySigs(de_ctx, new->sh, &cur->sh); - cur->cnt += new->cnt; DetectPortFree(new); return 0; } @@ -421,9 +413,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, SigGroupHeadCopySigs(de_ctx,b->sh,&tmp_c->sh); /* copy old b to c */ SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); /* copy a to b */ - tmp_c->cnt += b->cnt; - b->cnt += a->cnt; - /** * We have 3 parts: [bbb[baba]aaa] * part a: b_port1 <-> a_port1 - 1 @@ -461,13 +450,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += tmp->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; - /** * We have 2 or three parts: * @@ -497,7 +479,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, /** 'b' overlaps 'a' so 'a' needs the 'b' sigs */ SigGroupHeadCopySigs(de_ctx,b->sh,&a->sh); - a->cnt += b->cnt; } else if (a_port2 == b_port2) { SCLogDebug("2"); @@ -514,12 +495,9 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, * clear a * copy tmp to a */ SigGroupHeadCopySigs(de_ctx,b->sh,&tmp->sh); /* store old a list */ - tmp->cnt = b->cnt; SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); - b->cnt += a->cnt; SigGroupHeadClearSigs(a->sh); /* clean a list */ SigGroupHeadCopySigs(de_ctx,tmp->sh,&a->sh);/* merge old a with b */ - a->cnt = tmp->cnt; SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ } else { SCLogDebug("3"); @@ -551,13 +529,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, SigGroupHeadCopySigs(de_ctx,tmp->sh,&b->sh);/* merge old a with b */ SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ - - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += b->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; } /** * We have 2 or three parts: @@ -594,12 +565,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, SigGroupHeadClearSigs(tmp->sh); - tmp->cnt += b->cnt; - b->cnt = 0; - b->cnt += a->cnt; - a->cnt += tmp->cnt; - tmp->cnt = 0; - } else if (a_port2 == b_port2) { SCLogDebug("2"); @@ -612,8 +577,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, /** 'a' overlaps 'b' so 'b' needs the 'a' sigs */ SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); - b->cnt += a->cnt; - } else { SCLogDebug("3"); a->port = a_port1; @@ -634,9 +597,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); SigGroupHeadCopySigs(de_ctx,a->sh,&tmp_c->sh); - - b->cnt += a->cnt; - tmp_c->cnt += a->cnt; } } @@ -899,7 +859,6 @@ int DetectPortJoin(DetectEngineCtx *de_ctx, DetectPort *target, if (target == NULL || source == NULL) return -1; - target->cnt += source->cnt; SigGroupHeadCopySigs(de_ctx,source->sh,&target->sh); if (source->port < target->port) diff --git a/src/detect.h b/src/detect.h index 9ef5f18dd94d..b5cba45460a7 100644 --- a/src/detect.h +++ b/src/detect.h @@ -237,27 +237,19 @@ enum { #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; + uint8_t flags; /**< flags for this port */ + /* 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_ *prev; struct DetectPort_ *next; - - uint32_t cnt; - uint8_t flags; /**< flags for this port */ } DetectPort; /* Signature flags */ From a7d126738a3f4c82b4b71c5787cae48cabc12bff Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Oct 2015 21:54:32 +0200 Subject: [PATCH 1185/2553] detect address: remove unused features --- src/detect-engine-address-ipv4.c | 84 -------------------------------- src/detect-engine-address-ipv6.c | 82 ------------------------------- src/detect-engine-address.c | 29 ----------- src/detect.h | 11 ----- 4 files changed, 206 deletions(-) diff --git a/src/detect-engine-address-ipv4.c b/src/detect-engine-address-ipv4.c index 20e9e57e5df2..ca3b76b1b3a4 100644 --- a/src/detect-engine-address-ipv4.c +++ b/src/detect-engine-address-ipv4.c @@ -117,7 +117,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, uint32_t a_ip2 = ntohl(a->ip2.addr_data32[0]); uint32_t b_ip1 = ntohl(b->ip.addr_data32[0]); uint32_t b_ip2 = ntohl(b->ip2.addr_data32[0]); - DetectPort *port = NULL; DetectAddress *tmp = NULL; DetectAddress *tmp_c = NULL; int r = 0; @@ -162,14 +161,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, if (de_ctx != NULL) { SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp_c->port, port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - - tmp_c->cnt += b->cnt; - b->cnt += a->cnt; } /* we have 3 parts: [bbb[baba]aaa] @@ -211,22 +202,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); /* clean tmp list */ SigGroupHeadClearSigs(tmp->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &a->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp_c->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += tmp->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; } /* we have 2 or three parts: @@ -260,10 +235,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, if (de_ctx != NULL) { /* 'b' overlaps 'a' so 'a' needs the 'b' sigs */ SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &a->port, port); - a->cnt += b->cnt; } } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); @@ -280,19 +251,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, SigGroupHeadClearSigs(a->sh); SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); SigGroupHeadClearSigs(tmp->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp->port, a->port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &a->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; } } else { SCLogDebug("3"); @@ -328,22 +286,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); /* clean tmp list */ SigGroupHeadClearSigs(tmp->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp_c->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &a->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += b->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; } } /* we have 2 or three parts: @@ -381,19 +323,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); SigGroupHeadClearSigs(tmp->sh); - - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp->port, b->port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &a->port, port); - - tmp->cnt += b->cnt; - b->cnt = 0; - b->cnt += a->cnt; - a->cnt += tmp->cnt; - tmp->cnt = 0; } } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); @@ -407,11 +336,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, if (de_ctx != NULL) { /* 'a' overlaps 'b' so a needs the 'a' sigs */ SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - - b->cnt += a->cnt; } } else { SCLogDebug("DetectAddressCutIPv4: 3"); @@ -437,14 +361,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, * 'c' gets 'a' sigs */ SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); SigGroupHeadCopySigs(de_ctx, a->sh, &tmp_c->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp_c->port, port); - - b->cnt += a->cnt; - tmp_c->cnt += a->cnt; } } } diff --git a/src/detect-engine-address-ipv6.c b/src/detect-engine-address-ipv6.c index 84a04d593360..fa692b1a0c6e 100644 --- a/src/detect-engine-address-ipv6.c +++ b/src/detect-engine-address-ipv6.c @@ -367,7 +367,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, uint32_t b_ip2[4] = { ntohl(b->ip2.addr_data32[0]), ntohl(b->ip2.addr_data32[1]), ntohl(b->ip2.addr_data32[2]), ntohl(b->ip2.addr_data32[3]) }; - DetectPort *port = NULL; DetectAddress *tmp = NULL; /* default to NULL */ @@ -412,14 +411,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, /* copy old b to a */ SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp_c->port, port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - - tmp_c->cnt += b->cnt; - b->cnt += a->cnt; - /* we have 3 parts: [bbb[baba]aaa] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> b_ip2 @@ -459,23 +450,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, /* clean tmp list */ SigGroupHeadClearSigs(tmp->sh); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&a->port, port); - - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp_c->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += tmp->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; - /* we have 2 or three parts: * * 2 part: [[abab]bbb] or [bbb[baba]] @@ -501,11 +475,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, /* 'b' overlaps 'a' so 'a' needs the 'b' sigs */ SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&a->port, port); - - a->cnt += b->cnt; - } else if (AddressIPv6EqU32(a_ip2, b_ip2) == 1) { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); @@ -519,18 +488,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); SigGroupHeadClearSigs(tmp->sh); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp->port, a->port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&a->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; } else { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); @@ -565,22 +522,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, /* clean tmp list */ SigGroupHeadClearSigs(tmp->sh); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp_c->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&a->port, port); - - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += b->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; } /* we have 2 or three parts: * @@ -611,18 +552,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); SigGroupHeadClearSigs(tmp->sh); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp->port, b->port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&a->port, port); - - tmp->cnt += b->cnt; - b->cnt = 0; - b->cnt += a->cnt; - a->cnt += tmp->cnt; - tmp->cnt = 0; } else if (AddressIPv6EqU32(a_ip2, b_ip2) == 1) { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(b_ip1, a->ip2.addr_data32); @@ -633,10 +562,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, /* 'a' overlaps 'b' so a needs the 'a' sigs */ SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - - b->cnt += a->cnt; } else { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(b_ip1, a->ip2.addr_data32); @@ -660,13 +585,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); SigGroupHeadCopySigs(de_ctx, a->sh, &tmp_c->sh); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp_c->port, port); - - b->cnt += a->cnt; - tmp_c->cnt += a->cnt; } } diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 764af6a85f5a..c3ce599d3ff1 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -107,22 +107,6 @@ void DetectAddressFree(DetectAddress *ag) } ag->sh = NULL; - if (!(ag->flags & ADDRESS_HAVEPORT)) { - SCLogDebug("- ag %p dst_gh %p", ag, ag->dst_gh); - - if (ag->dst_gh != NULL) - DetectAddressHeadFree(ag->dst_gh); - ag->dst_gh = NULL; - } else { - SCLogDebug("- ag %p port %p", ag, ag->port); - - if (ag->port != NULL && !(ag->flags & ADDRESS_PORTS_COPY)) { - SCLogDebug("- ag %p port %p, not a copy so call DetectPortCleanupList", - ag, ag->port); - DetectPortCleanupList(ag->port); - } - ag->port = NULL; - } #ifdef DEBUG detect_address_group_memory -= sizeof(DetectAddress); detect_address_group_free_cnt++; @@ -153,8 +137,6 @@ DetectAddress *DetectAddressCopy(DetectAddress *orig) COPY_ADDRESS(&orig->ip, &ag->ip); COPY_ADDRESS(&orig->ip2, &ag->ip2); - ag->cnt = 1; - return ag; } @@ -407,11 +389,7 @@ int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, if (r == ADDRESS_EQ) { /* exact overlap/match */ if (cur != new) { - DetectPort *port = new->port; - for ( ; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &cur->port, port); SigGroupHeadCopySigs(de_ctx, new->sh, &cur->sh); - cur->cnt += new->cnt; DetectAddressFree(new); return 0; @@ -523,21 +501,14 @@ int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, int DetectAddressJoin(DetectEngineCtx *de_ctx, DetectAddress *target, DetectAddress *source) { - DetectPort *port = NULL; - if (target == NULL || source == NULL) return -1; if (target->ip.family != source->ip.family) return -1; - target->cnt += source->cnt; SigGroupHeadCopySigs(de_ctx, source->sh, &target->sh); - port = source->port; - for ( ; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &target->port, port); - if (target->ip.family == AF_INET) return DetectAddressJoinIPv4(de_ctx, target, source); else if (target->ip.family == AF_INET6) diff --git a/src/detect.h b/src/detect.h index b5cba45460a7..d701a0d52999 100644 --- a/src/detect.h +++ b/src/detect.h @@ -165,9 +165,6 @@ enum { #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. * @@ -178,12 +175,6 @@ typedef struct DetectAddress_ { Address ip; Address ip2; - /** 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; @@ -194,8 +185,6 @@ typedef struct DetectAddress_ { 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 */ From 7c94077892cea1b1153c8a814c126b13eb81c08c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 13 Oct 2015 08:44:45 +0200 Subject: [PATCH 1186/2553] detect mpm: remove unused mpm flags --- src/detect-engine-mpm.c | 5 ----- src/detect.h | 3 --- 2 files changed, 8 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 620cda3cce44..65baebf9e4f0 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1386,20 +1386,15 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) /* tell matcher we are inspecting packet */ /* TODO remove! */ if (!(ms->buffer == MPMB_TCP_STREAM_TC || ms->buffer == MPMB_TCP_STREAM_TS)) { - s->flags |= SIG_FLAG_MPM_PACKET; s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); } else { - /* tell matcher we are inspecting stream */ - s->flags |= SIG_FLAG_MPM_STREAM; s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); } } else { - /* tell matcher we are inspecting app-layer */ s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - s->flags |= SIG_FLAG_MPM_APPLAYER; } } } diff --git a/src/detect.h b/src/detect.h index d701a0d52999..faa752f8a101 100644 --- a/src/detect.h +++ b/src/detect.h @@ -258,9 +258,6 @@ typedef struct DetectPort_ { #define SIG_FLAG_REQUIRE_STREAM (1<<10) /**< signature is requiring stream match */ #define SIG_FLAG_MPM_NEG (1<<11) -#define SIG_FLAG_MPM_PACKET (1<<12) -#define SIG_FLAG_MPM_STREAM (1<<13) -#define SIG_FLAG_MPM_APPLAYER (1<<14) #define SIG_FLAG_REQUIRE_FLOWVAR (1<<17) /**< signature can only match if a flowbit, flowvar or flowint is available. */ From c87fcb29ffb95feace6c1c8decc668d84c198ac7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 13 Oct 2015 08:33:27 +0200 Subject: [PATCH 1187/2553] detect mpm: fast_pattern assignment cleanup --- src/detect-engine-mpm.c | 38 +++++++++++++++++++++++--------------- src/detect-engine-mpm.h | 2 +- src/detect.c | 2 +- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 65baebf9e4f0..34964c432d82 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -983,11 +983,10 @@ static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, #define SGH_DIRECTION_TS(sgh) ((sgh)->init->direction & SIG_FLAG_TOSERVER) #define SGH_DIRECTION_TC(sgh) ((sgh)->init->direction & SIG_FLAG_TOCLIENT) -SigMatch *RetrieveFPForSig(Signature *s) +void RetrieveFPForSig(Signature *s) { if (s->mpm_sm != NULL) - return s->mpm_sm; - + return; SigMatch *mpm_sm = NULL, *sm = NULL; int nn_sm_list[DETECT_SM_LIST_MAX]; @@ -998,6 +997,8 @@ SigMatch *RetrieveFPForSig(Signature *s) int count_n_sm_list = 0; int list_id; + /* inspect rule to see if we have the fast_pattern keyword to + * force using a sig, otherwise keep stats about the patterns */ for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { if (!FastPatternSupportEnabledForSigMatchList(list_id)) continue; @@ -1007,8 +1008,13 @@ SigMatch *RetrieveFPForSig(Signature *s) continue; DetectContentData *cd = (DetectContentData *)sm->ctx; - if ((cd->flags & DETECT_CONTENT_FAST_PATTERN)) - return sm; + + /* fast_pattern set in rule, so using this pattern */ + if ((cd->flags & DETECT_CONTENT_FAST_PATTERN)) { + s->mpm_sm = sm; + return; + } + if (cd->flags & DETECT_CONTENT_NEGATED) { n_sm_list[list_id] = 1; count_n_sm_list++; @@ -1016,9 +1022,10 @@ SigMatch *RetrieveFPForSig(Signature *s) nn_sm_list[list_id] = 1; count_nn_sm_list++; } - } /* for */ - } /* for */ + } + } + /* prefer normal not-negated over negated */ int *curr_sm_list = NULL; int skip_negated_content = 1; if (count_nn_sm_list > 0) { @@ -1027,7 +1034,7 @@ SigMatch *RetrieveFPForSig(Signature *s) curr_sm_list = n_sm_list; skip_negated_content = 0; } else { - return NULL; + return; } int final_sm_list[DETECT_SM_LIST_MAX]; @@ -1038,8 +1045,8 @@ SigMatch *RetrieveFPForSig(Signature *s) while (tmp != NULL) { for (priority = tmp->priority; tmp != NULL && priority == tmp->priority; - tmp = tmp->next) { - + tmp = tmp->next) + { if (curr_sm_list[tmp->list_id] == 0) continue; final_sm_list[count_final_sm_list++] = tmp->list_id; @@ -1096,11 +1103,12 @@ SigMatch *RetrieveFPForSig(Signature *s) } else { SCLogDebug("sticking with mpm_sm"); } - } /* else - if */ - } /* for */ - } /* for */ + } + } + } - return mpm_sm; + s->mpm_sm = mpm_sm; + return; } /** \internal @@ -1767,7 +1775,7 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) * true size, since duplicates are removed below, but counted here. */ for (s = de_ctx->sig_list; s != NULL; s = s->next) { - s->mpm_sm = RetrieveFPForSig(s); + RetrieveFPForSig(s); if (s->mpm_sm != NULL) { DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; struct_total_size += sizeof(DetectFPAndItsId); diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 9984791c2679..7231caf6ae9f 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -83,7 +83,7 @@ uint32_t DetectContentGetId(MpmPatternIdStore *, DetectContentData *); int SignatureHasPacketContent(const Signature *); int SignatureHasStreamContent(const Signature *); -SigMatch *RetrieveFPForSig(Signature *s); +void RetrieveFPForSig(Signature *s); int MpmStoreInit(DetectEngineCtx *); void MpmStoreFree(DetectEngineCtx *); diff --git a/src/detect.c b/src/detect.c index 9189b4612ff8..7a3f6575388e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -357,7 +357,7 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, sig = DetectEngineAppendSig(de_ctx, line); if (sig != NULL) { if (rule_engine_analysis_set || fp_engine_analysis_set) { - sig->mpm_sm = RetrieveFPForSig(sig); + RetrieveFPForSig(sig); if (fp_engine_analysis_set) { EngineAnalysisFP(sig, line); } From 4e8e5917153d8bf1b06c7a3f56457f540034a8d1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 13 Oct 2015 08:49:23 +0200 Subject: [PATCH 1188/2553] detect mpm: mpm store cleanup Move all rule modification to the fast_pattern assigment. --- src/detect-engine-mpm.c | 70 ++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 34964c432d82..e996a290e65f 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -983,6 +983,34 @@ static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, #define SGH_DIRECTION_TS(sgh) ((sgh)->init->direction & SIG_FLAG_TOSERVER) #define SGH_DIRECTION_TC(sgh) ((sgh)->init->direction & SIG_FLAG_TOCLIENT) +static void SetMpm(Signature *s, SigMatch *mpm_sm) +{ + if (s == NULL || mpm_sm == NULL) + return; + + DetectContentData *cd = (DetectContentData *)mpm_sm->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + if (DETECT_CONTENT_IS_SINGLE(cd) && + !(cd->flags & DETECT_CONTENT_NEGATED) && + !(cd->flags & DETECT_CONTENT_REPLACE) && + cd->content_len == cd->fp_chop_len) + { + cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; + } + } else { + if (DETECT_CONTENT_IS_SINGLE(cd) && + !(cd->flags & DETECT_CONTENT_NEGATED) && + !(cd->flags & DETECT_CONTENT_REPLACE)) + { + cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; + } + } + s->mpm_pattern_id_div_8 = cd->id / 8; + s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); + s->mpm_sm = mpm_sm; + return; +} + void RetrieveFPForSig(Signature *s) { if (s->mpm_sm != NULL) @@ -1011,7 +1039,7 @@ void RetrieveFPForSig(Signature *s) /* fast_pattern set in rule, so using this pattern */ if ((cd->flags & DETECT_CONTENT_FAST_PATTERN)) { - s->mpm_sm = sm; + SetMpm(s, sm); return; } @@ -1107,7 +1135,8 @@ void RetrieveFPForSig(Signature *s) } } - s->mpm_sm = mpm_sm; + /* assign to signature */ + SetMpm(s, mpm_sm); return; } @@ -1308,7 +1337,7 @@ void MpmStoreFree(DetectEngineCtx *de_ctx) void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) { - Signature *s = NULL; // TODO const + const Signature *s = NULL; uint32_t sig; int dir = 0; @@ -1369,41 +1398,10 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) SCLogDebug("adding %u", s->id); - DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; // TODO const - /* TODO move this into cd setup code */ - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE) && - cd->content_len == cd->fp_chop_len) - { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - } else { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE)) - { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - } + const DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; + PopulateMpmHelperAddPatternToPktCtx(ms->mpm_ctx, cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); - - if (ms->buffer != MPMB_MAX) { - /* tell matcher we are inspecting packet */ - /* TODO remove! */ - if (!(ms->buffer == MPMB_TCP_STREAM_TC || ms->buffer == MPMB_TCP_STREAM_TS)) { - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - } else { - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - } - } else { - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - } } } From c1ad08d11e70f02b6f913c51ec59a6748ce177c5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 13 Oct 2015 10:27:26 +0200 Subject: [PATCH 1189/2553] detect: remove stream pmq array --- src/detect-engine-mpm.c | 26 ++------------------------ src/detect-engine-mpm.h | 1 - src/detect-engine.c | 11 ++--------- src/detect.c | 7 ------- src/detect.h | 3 --- 5 files changed, 4 insertions(+), 44 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index e996a290e65f..889f49935328 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -745,14 +745,9 @@ uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p, for ( ; smsg != NULL; smsg = smsg->next) { r = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtcs, - &det_ctx->smsg_pmq[cnt], smsg->data, smsg->data_len); + &det_ctx->pmq, smsg->data, smsg->data_len); if (r > 0) { ret += r; - - SCLogDebug("smsg match stored in det_ctx->smsg_pmq[%u]", cnt); - - /* merge results with overall pmq */ - PmqMerge(&det_ctx->smsg_pmq[cnt], &det_ctx->pmq); } cnt++; @@ -761,14 +756,9 @@ uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p, for ( ; smsg != NULL; smsg = smsg->next) { r = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtcs, - &det_ctx->smsg_pmq[cnt], smsg->data, smsg->data_len); + &det_ctx->pmq, smsg->data, smsg->data_len); if (r > 0) { ret += r; - - SCLogDebug("smsg match stored in det_ctx->smsg_pmq[%u]", cnt); - - /* merge results with overall pmq */ - PmqMerge(&det_ctx->smsg_pmq[cnt], &det_ctx->pmq); } cnt++; @@ -854,18 +844,6 @@ void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) return; } -void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg) -{ - uint8_t cnt = 0; - - while (smsg != NULL) { - PmqReset(&det_ctx->smsg_pmq[cnt]); - - smsg = smsg->next; - cnt++; - } -} - void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher) { SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher); diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 7231caf6ae9f..3f88c164127d 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -58,7 +58,6 @@ uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *buffer, uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *buffer, uint32_t buffer_len, uint8_t flags); void PacketPatternCleanup(ThreadVars *, DetectEngineThreadCtx *); -void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg); void PatternMatchPrepare(MpmCtx *, uint16_t); void PatternMatchThreadPrepare(MpmThreadCtx *, uint16_t type); diff --git a/src/detect-engine.c b/src/detect-engine.c index 842e8db26125..5827af8900b0 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1324,16 +1324,11 @@ static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThread */ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { - int i; - PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher); PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher); PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher); PmqSetup(&det_ctx->pmq); - for (i = 0; i < DETECT_SMSG_PMQ_NUM; i++) { - PmqSetup(&det_ctx->smsg_pmq[i]); - } /* sized to the max of our sgh settings. A max setting of 0 implies that all * sgh's have: sgh->non_mpm_store_cnt == 0 */ @@ -1525,6 +1520,8 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) { + int i; + if (det_ctx->tenant_array != NULL) { SCFree(det_ctx->tenant_array); det_ctx->tenant_array = NULL; @@ -1545,10 +1542,6 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) } PmqFree(&det_ctx->pmq); - int i; - for (i = 0; i < DETECT_SMSG_PMQ_NUM; i++) { - PmqFree(&det_ctx->smsg_pmq[i]); - } if (det_ctx->non_mpm_id_array != NULL) SCFree(det_ctx->non_mpm_id_array); diff --git a/src/detect.c b/src/detect.c index 7a3f6575388e..e975f6d31ba4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -847,7 +847,6 @@ static void QuickSortSigIntId(SigIntId *sids, uint32_t n) #define SMS_USE_FLOW_SGH 0x01 #define SMS_USED_PM 0x02 -#define SMS_USED_STREAM_PM 0x04 /** * \internal @@ -1064,8 +1063,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_STREAM); StreamPatternSearch(det_ctx, p, smsg, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_STREAM); - - *sms_runflags |= SMS_USED_STREAM_PM; } else { SCLogDebug("smsg NULL or no stream mpm for this sgh"); } @@ -1808,10 +1805,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh * up again for the next packet. Also return any stream chunk we processed * to the pool. */ if (p->flags & PKT_HAS_FLOW) { - if (sms_runflags & SMS_USED_STREAM_PM) { - StreamPatternCleanup(th_v, det_ctx, smsg); - } - FLOWLOCK_WRLOCK(pflow); if (debuglog_enabled) { if (p->alerts.cnt > 0) { diff --git a/src/detect.h b/src/detect.h index faa752f8a101..6f41f7247851 100644 --- a/src/detect.h +++ b/src/detect.h @@ -712,8 +712,6 @@ typedef struct FiledataReassembledBody_ { } FiledataReassembledBody; #define DETECT_FILESTORE_MAX 15 -/** \todo review how many we actually need here */ -#define DETECT_SMSG_PMQ_NUM 256 typedef struct SignatureNonMpmStore_ { SigIntId id; @@ -827,7 +825,6 @@ typedef struct DetectEngineThreadCtx_ { 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; From 46734ec41be6eb7121c3e1a5b71e2ae245ce8640 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 13 Oct 2015 10:39:54 +0200 Subject: [PATCH 1190/2553] mpm: remove unused pmq merge function --- src/util-mpm.c | 16 ---------------- src/util-mpm.h | 1 - 2 files changed, 17 deletions(-) diff --git a/src/util-mpm.c b/src/util-mpm.c index 1c4fe42e8a8b..27f5a86c072f 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -473,22 +473,6 @@ MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size) return new_size; } -/** - * \brief Merge two pmq's bitarrays - * - * \param src source pmq - * \param dst destination pmq to merge into - */ -void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst) -{ - if (src->rule_id_array_cnt == 0) - return; - - if (src->rule_id_array && dst->rule_id_array) { - MpmAddSids(dst, src->rule_id_array, src->rule_id_array_cnt); - } -} - /** \brief Reset a Pmq for reusage. Meant to be called after a single search. * \param pmq Pattern matcher to be reset. * \todo memset is expensive, but we need it as we merge pmq's. We might use diff --git a/src/util-mpm.h b/src/util-mpm.h index 5cbdc9355b7e..209a3fddfd67 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -203,7 +203,6 @@ void MpmFactoryDeRegisterAllMpmCtxProfiles(struct DetectEngineCtx_ *); int32_t MpmFactoryIsMpmCtxAvailable(const struct DetectEngineCtx_ *, const MpmCtx *); int PmqSetup(PatternMatcherQueue *); -void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst); void PmqReset(PatternMatcherQueue *); void PmqCleanup(PatternMatcherQueue *); void PmqFree(PatternMatcherQueue *); From 9e71ef4c3bc878f018cdd8fadfab5e33ada17fb6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 13 Oct 2015 14:56:01 +0200 Subject: [PATCH 1191/2553] detect: remove signature pattern id reference --- src/detect-engine-mpm.c | 2 -- src/detect.h | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 889f49935328..7295813e0c32 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -983,8 +983,6 @@ static void SetMpm(Signature *s, SigMatch *mpm_sm) cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; } } - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); s->mpm_sm = mpm_sm; return; } diff --git a/src/detect.h b/src/detect.h index 6f41f7247851..f728e9bd8b66 100644 --- a/src/detect.h +++ b/src/detect.h @@ -360,9 +360,6 @@ typedef struct Signature_ { uint16_t dsize_low; uint16_t dsize_high; - uint16_t mpm_pattern_id_div_8; - uint8_t mpm_pattern_id_mod_8; - SignatureMask mask; SigIntId num; /**< signature number, internal id */ From ba9d43cce56932ea98603084648614e6a4523064 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Oct 2015 13:11:44 +0200 Subject: [PATCH 1192/2553] mpm: improve negated mpm The idea is: if mpm is negated, it's both on mpm and nonmpm sid lists and we can kick it out in that case during the merge sort. It only works for patterns that are 'independent'. This means that the rule doesn't need to only match if the negated mpm pattern is limited to the first 10 bytes for example. Or more generally, an negated mpm pattern that has depth, offset, distance or within settings can't be handled this way. These patterns are not added to the mpm at all, but just to to non-mpm list. This makes sense as they will *always* need manual inspection. Similarly, a pattern that is 'chopped' always needs validation. This is because in this case we only inspect a part of the final pattern. --- src/detect-content.h | 12 ++++++++++++ src/detect-engine-mpm.c | 19 +++++++++++++++++-- src/detect.c | 40 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/detect-content.h b/src/detect-content.h index 00c1ea3920d8..51300e7ea912 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -61,6 +61,18 @@ ((c)->flags & DETECT_CONTENT_DEPTH) || \ ((c)->flags & DETECT_CONTENT_OFFSET) )) +/* if a pattern has no depth/offset limits, no relative specifiers and isn't + * chopped for the mpm, we can take the mpm and consider this pattern a match + * w/o futher inspection. Warning: this may still mean other patterns depend + * on this pattern that force match validation anyway. */ +#define DETECT_CONTENT_MPM_IS_CONCLUSIVE(c) \ + !( ((c)->flags & DETECT_CONTENT_DISTANCE) || \ + ((c)->flags & DETECT_CONTENT_WITHIN) || \ + ((c)->flags & DETECT_CONTENT_DEPTH) || \ + ((c)->flags & DETECT_CONTENT_OFFSET) || \ + ((c)->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)) + + #include "util-spm-bm.h" typedef struct DetectContentData_ { diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 7295813e0c32..1faa3fe19274 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1376,8 +1376,23 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) const DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; - PopulateMpmHelperAddPatternToPktCtx(ms->mpm_ctx, - cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); + int skip = 0; + /* negated logic: if mpm match can't be used to be sure about this + * pattern, we have to inspect the rule fully regardless of mpm + * match. So in this case there is no point of adding it at all. + * The non-mpm list entry for the sig will make sure the sig is + * inspected. */ + if ((cd->flags & DETECT_CONTENT_NEGATED) && + !(DETECT_CONTENT_MPM_IS_CONCLUSIVE(cd))) + { + skip = 1; + SCLogDebug("not adding negated mpm as it's not 'single'"); + } + + if (!skip) { + PopulateMpmHelperAddPatternToPktCtx(ms->mpm_ctx, + cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); + } } } diff --git a/src/detect.c b/src/detect.c index e975f6d31ba4..404dac4d5309 100644 --- a/src/detect.c +++ b/src/detect.c @@ -765,7 +765,7 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, goto final; } while (1) { - if (mpm <= nonmpm) { + if (mpm < nonmpm) { /* Take from mpm list */ id = mpm; @@ -778,12 +778,12 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, if (unlikely(--m_cnt == 0)) { /* mpm list is now empty */ final_ptr = nonmpm_ptr; - final_cnt = n_cnt; - goto final; + final_cnt = n_cnt; + goto final; } mpm_ptr++; mpm = *mpm_ptr; - } else { + } else if (mpm > nonmpm) { id = nonmpm; s = sig_array[id]; @@ -799,6 +799,38 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, } nonmpm_ptr++; nonmpm = *nonmpm_ptr; + + } else { /* implied mpm == nonmpm */ + /* special case: if on both lists, it's a negated mpm pattern */ + + /* mpm list may have dups, so skip past them here */ + while (--m_cnt != 0) { + mpm_ptr++; + mpm = *mpm_ptr; + if (mpm != nonmpm) + break; + } + /* if mpm is done, update nonmpm_ptrs and jump to final */ + if (unlikely(m_cnt == 0)) { + n_cnt--; + + /* mpm list is now empty */ + final_ptr = ++nonmpm_ptr; + final_cnt = n_cnt; + goto final; + } + /* otherwise, if nonmpm is done jump to final for mpm + * mpm ptrs alrady updated */ + if (unlikely(--n_cnt == 0)) { + final_ptr = mpm_ptr; + final_cnt = m_cnt; + goto final; + } + + /* not at end of the lists, update nonmpm. Mpm already + * updated in while loop above. */ + nonmpm_ptr++; + nonmpm = *nonmpm_ptr; } } From 9b3d4f7e2483f907698d6e16aca99a2f4fd5b9ce Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Oct 2015 10:31:05 +0200 Subject: [PATCH 1193/2553] mpm: unify & localize mpm pattern (id) handling So far, the patterns as passed to the mpm's would use global id's that were shared among all buffers, directions. This would lead to a fairly large pattern id space. As the mpm algo's use the pattern id's to prevent duplicate matching through a pattern id based bitarray, shrinking this space will optimize performance. This patch implements this. It sets a flag before adding the pattern to the mpm ctx, instructing the mpm to ignore the provided pid and handle pids management itself. This leads to a shrinking of the bitarray size. This is made possible by the previous work that removes the pid logic from the code. Next to this, this patch moves the pattern setup stage to common util functions. This avoids code duplication. Update ac, ac-bs and ac-ks to use this. --- src/detect-engine-mpm.c | 8 +- src/util-mpm-ac-bs.c | 329 ++++-------------------------------- src/util-mpm-ac-bs.h | 31 +--- src/util-mpm-ac-tile.c | 362 +++------------------------------------- src/util-mpm-ac-tile.h | 26 +-- src/util-mpm-ac.c | 340 ++++--------------------------------- src/util-mpm-ac.h | 27 +-- src/util-mpm.c | 282 +++++++++++++++++++++++++++++++ src/util-mpm.h | 38 +++++ 9 files changed, 408 insertions(+), 1035 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 1faa3fe19274..776622ab6e93 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -933,24 +933,24 @@ static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, MpmAddPatternCI(mpm_ctx, cd->content + cd->fp_chop_offset, cd->fp_chop_len, pat_offset, pat_depth, - cd->id, s->num, flags); + cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); } else { MpmAddPatternCI(mpm_ctx, cd->content, cd->content_len, pat_offset, pat_depth, - cd->id, s->num, flags); + cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); } } else { if (chop) { MpmAddPatternCS(mpm_ctx, cd->content + cd->fp_chop_offset, cd->fp_chop_len, pat_offset, pat_depth, - cd->id, s->num, flags); + cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); } else { MpmAddPatternCS(mpm_ctx, cd->content, cd->content_len, pat_offset, pat_depth, - cd->id, s->num, flags); + cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); } } diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 6883f567246e..f8e313a17545 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -77,8 +77,6 @@ void SCACBSRegisterTests(void); /* a placeholder to denote a failure transition in the goto table */ #define SC_AC_BS_FAIL (-1) -/* size of the hash table used to speed up pattern insertions initially */ -#define INIT_HASH_SIZE 65536 #define STATE_QUEUE_CONTAINER_SIZE 65536 @@ -132,276 +130,6 @@ static void SCACBSGetConfig() return; } -/** - * \internal - * \brief Creates a hash of the pattern. We use it for the hashing process - * during the initial pattern insertion time, to cull duplicate sigs. - * - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline uint32_t SCACBSInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -/** - * \internal - * \brief Looks up a pattern. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param ctx Pointer to the AC ctx. - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline SCACBSPattern *SCACBSInitHashLookup(SCACBSCtx *ctx, uint8_t *pat, - uint16_t patlen, char flags, - uint32_t pid) -{ - uint32_t hash = SCACBSInitHashRaw(pat, patlen); - - if (ctx->init_hash == NULL) { - return NULL; - } - - SCACBSPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (t->id == pid) - return t; - } - - return NULL; -} - -/** - * \internal - * \brief Allocs a new pattern instance. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval p Pointer to the newly created pattern. - */ -static inline SCACBSPattern *SCACBSAllocPattern(MpmCtx *mpm_ctx) -{ - SCACBSPattern *p = SCMalloc(sizeof(SCACBSPattern)); - if (unlikely(p == NULL)) { - exit(EXIT_FAILURE); - } - memset(p, 0, sizeof(SCACBSPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACBSPattern); - - return p; -} - -/** - * \internal - * \brief Used to free SCACBSPattern instances. - * - * \param mpm_ctx Pointer to the mpm context. - * \param p Pointer to the SCACBSPattern instance to be freed. - */ -static inline void SCACBSFreePattern(MpmCtx *mpm_ctx, SCACBSPattern *p) -{ - if (p != NULL && p->cs != NULL && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->ci != NULL) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACBSPattern); - } - return; -} - -static inline uint32_t SCACBSInitHash(SCACBSPattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int SCACBSInitHashAdd(SCACBSCtx *ctx, SCACBSPattern *p) -{ - uint32_t hash = SCACBSInitHash(p); - - if (ctx->init_hash == NULL) { - return 0; - } - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - SCACBSPattern *tt = NULL; - SCACBSPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - -/** - * \internal - * \brief Add a pattern to the mpm-ac context. - * - * \param mpm_ctx Mpm context. - * \param pat Pointer to the pattern. - * \param patlen Length of the pattern. - * \param pid Pattern id - * \param sid Signature id (internal id). - * \param flags Pattern's MPM_PATTERN_* flags. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int SCACBSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; - - SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, - ctx, patlen, pid); - - if (patlen == 0) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); - return 0; - } - - /* check if we have already inserted this pattern */ - SCACBSPattern *p = SCACBSInitHashLookup(ctx, pat, patlen, flags, pid); - if (p == NULL) { - SCLogDebug("Allocing new pattern"); - - /* p will never be NULL */ - p = SCACBSAllocPattern(mpm_ctx); - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci, pat, p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - /* put in the pattern hash */ - SCACBSInitHashAdd(ctx, p); - - //if (mpm_ctx->pattern_cnt == 65535) { - // SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " - // "insert anymore. Exiting"); - // exit(EXIT_FAILURE); - //} - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - - if (mpm_ctx->minlen == 0) { - mpm_ctx->minlen = patlen; - } else { - if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - /* we need the max pat id */ - if (pid > ctx->max_pat_id) - ctx->max_pat_id = pid; - - p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); - BUG_ON(p->sids == NULL); - p->sids[0] = sid; - } else { - /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ - - int found = 0; - uint32_t x = 0; - for (x = 0; x < p->sids_size; x++) { - if (p->sids[x] == sid) { - found = 1; - break; - } - } - if (!found) { - SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); - BUG_ON(sids == NULL); - p->sids = sids; - p->sids[p->sids_size] = sid; - p->sids_size++; - } - } - - return 0; - -error: - SCACBSFreePattern(mpm_ctx, p); - return -1; -} - /** * \internal * \brief Initialize a new state in the goto and output tables. @@ -1167,24 +895,24 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; - if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { + if (mpm_ctx->pattern_cnt == 0 || mpm_ctx->init_hash == NULL) { SCLogDebug("no patterns supplied to this mpm_ctx"); return 0; } /* alloc the pattern array */ - ctx->parray = (SCACBSPattern **)SCMalloc(mpm_ctx->pattern_cnt * - sizeof(SCACBSPattern *)); + ctx->parray = (MpmPattern **)SCMalloc(mpm_ctx->pattern_cnt * + sizeof(MpmPattern *)); if (ctx->parray == NULL) goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); + memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); + mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - SCACBSPattern *node = ctx->init_hash[i], *nnode = NULL; + for (i = 0; i < MPM_INIT_HASH_SIZE; i++) { + MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; while(node != NULL) { nnode = node->next; node->next = NULL; @@ -1194,19 +922,19 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) } /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; /* the memory consumed by a single state in our goto table */ ctx->single_state_size = sizeof(int32_t) * 256; /* handle no case patterns */ - ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACBSPatternList)); + ctx->pid_pat_list = SCMalloc((mpm_ctx->max_pat_id + 1)* sizeof(SCACBSPatternList)); if (ctx->pid_pat_list == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACBSPatternList)); + memset(ctx->pid_pat_list, 0, (mpm_ctx->max_pat_id + 1) * sizeof(SCACBSPatternList)); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { @@ -1231,15 +959,15 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) /* free all the stored patterns. Should save us a good 100-200 mbs */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { - SCACBSFreePattern(mpm_ctx, ctx->parray[i]); + MpmFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); - ctx->pattern_id_bitarray_size = (ctx->max_pat_id / 8) + 1; + ctx->pattern_id_bitarray_size = (mpm_ctx->max_pat_id / 8) + 1; return 0; @@ -1291,12 +1019,11 @@ void SCACBSInitCtx(MpmCtx *mpm_ctx) mpm_ctx->memory_size += sizeof(SCACBSCtx); /* initialize the hash we use to speed up pattern insertions */ - SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(SCACBSPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { + mpm_ctx->init_hash = SCMalloc(sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); + if (mpm_ctx->init_hash == NULL) { exit(EXIT_FAILURE); } - memset(ctx->init_hash, 0, sizeof(SCACBSPattern *) * INIT_HASH_SIZE); + memset(mpm_ctx->init_hash, 0, sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); /* get conf values for AC from our yaml file. We have no conf values for * now. We will certainly need this, as we develop the algo */ @@ -1336,25 +1063,25 @@ void SCACBSDestroyCtx(MpmCtx *mpm_ctx) if (ctx == NULL) return; - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + if (mpm_ctx->init_hash != NULL) { + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCACBSPattern *)); + mpm_ctx->memory_size -= (MPM_INIT_HASH_SIZE * sizeof(MpmPattern *)); } if (ctx->parray != NULL) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { - SCACBSFreePattern(mpm_ctx, ctx->parray[i]); + MpmFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); } if (ctx->state_table_u16 != NULL) { @@ -1385,7 +1112,7 @@ void SCACBSDestroyCtx(MpmCtx *mpm_ctx) if (ctx->pid_pat_list != NULL) { uint32_t i; - for (i = 0; i < (ctx->max_pat_id + 1); i++) { + for (i = 0; i < (mpm_ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); if (ctx->pid_pat_list[i].sids != NULL) @@ -1629,7 +1356,7 @@ int SCACBSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; - return SCACBSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } /** @@ -1653,7 +1380,7 @@ int SCACBSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) { - return SCACBSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } void SCACBSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) @@ -1679,8 +1406,8 @@ void SCACBSPrintInfo(MpmCtx *mpm_ctx) printf(" Sizeof:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" SCACBSCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACBSCtx)); - printf(" SCACBSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACBSPattern)); - printf(" SCACBSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACBSPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); diff --git a/src/util-mpm-ac-bs.h b/src/util-mpm-ac-bs.h index 42d254c585a2..80ac0f4b06e8 100644 --- a/src/util-mpm-ac-bs.h +++ b/src/util-mpm-ac-bs.h @@ -22,30 +22,11 @@ * */ +#include "util-mpm.h" + #define SC_AC_BS_STATE_TYPE_U16 uint16_t #define SC_AC_BS_STATE_TYPE_U32 uint32_t -typedef struct SCACBSPattern_ { - /* length of the pattern */ - uint16_t len; - /* flags decribing the pattern */ - uint8_t flags; - /* holds the original pattern that was added */ - uint8_t *original_pat; - /* case sensitive */ - uint8_t *cs; - /* case INsensitive */ - uint8_t *ci; - /* pattern id */ - uint32_t id; - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; - - struct SCACBSPattern_ *next; -} SCACBSPattern; - typedef struct SCACBSPatternList_ { uint8_t *cs; uint16_t patlen; @@ -63,16 +44,13 @@ typedef struct SCACBSOutputTable_ { } SCACBSOutputTable; typedef struct SCACBSCtx_ { - /* hash used during ctx initialization */ - SCACBSPattern **init_hash; - /* pattern arrays. We need this only during the goto table creation phase */ - SCACBSPattern **parray; + MpmPattern **parray; /* no of states used by ac */ uint32_t state_count; - uint16_t pattern_id_bitarray_size; + uint32_t pattern_id_bitarray_size; /* the all important memory hungry state_table */ SC_AC_BS_STATE_TYPE_U16 (*state_table_u16)[256]; @@ -91,7 +69,6 @@ typedef struct SCACBSCtx_ { /* the size of each state */ uint16_t single_state_size; - uint32_t max_pat_id; } SCACBSCtx; typedef struct SCACBSThreadCtx_ { diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 663eb6607133..72b293696214 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -143,8 +143,6 @@ static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx); /* a placeholder to denote a failure transition in the goto table */ #define SC_AC_TILE_FAIL (-1) -/* size of the hash table used to speed up pattern insertions initially */ -#define INIT_HASH_SIZE 65536 #define STATE_QUEUE_CONTAINER_SIZE 65536 @@ -167,193 +165,6 @@ static void SCACTileGetConfig() { } -/** - * \internal - * \brief Compares 2 patterns. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param p Pointer to the first pattern(SCACTilePattern). - * \param pat Pointer to the second pattern(raw pattern array). - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline int SCACTileCmpPattern(SCACTilePattern *p, uint8_t *pat, - uint16_t patlen, char flags) -{ - if (p->len != patlen) - return 0; - - if (p->flags != flags) - return 0; - - if (flags & MPM_PATTERN_FLAG_NOCASE) { - // Case insensitive - if (SCMemcmpLowercase(p->cs, pat, patlen) != 0) - return 0; - - } else { - // Case sensitive - if (SCMemcmp(p->cs, pat, patlen) != 0) - return 0; - } - - return 1; -} - -/** - * \internal - * \brief Creates a hash of the pattern. We use it for the hashing process - * during the initial pattern insertion time, to cull duplicate sigs. - * - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline uint32_t SCACTileInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -/** - * \internal - * \brief Looks up a pattern. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param ctx Pointer to the AC ctx. - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline SCACTilePattern *SCACTileInitHashLookup(SCACTileCtx *ctx, - uint8_t *pat, - uint16_t patlen, - char flags, - uint32_t pid) -{ - uint32_t hash = SCACTileInitHashRaw(pat, patlen); - - if (ctx->init_hash == NULL) { - return NULL; - } - - SCACTilePattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (t->id == pid) { - return t; - } - } - - return NULL; -} - -/** - * \internal - * \brief Allocs a new pattern instance. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval p Pointer to the newly created pattern. - */ -static inline SCACTilePattern *SCACTileAllocPattern(MpmCtx *mpm_ctx) -{ - SCACTilePattern *p = SCMalloc(sizeof(SCACTilePattern)); - if (unlikely(p == NULL)) { - exit(EXIT_FAILURE); - } - memset(p, 0, sizeof(SCACTilePattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACTilePattern); - - return p; -} - -/** - * \internal - * \brief Used to free SCACTilePattern instances. - * - * \param mpm_ctx Pointer to the mpm context. - * \param p Pointer to the SCACTilePattern instance to be freed. - * \param free Free the above pointer or not. - */ -static void SCACTileFreePattern(MpmCtx *mpm_ctx, SCACTilePattern *p) -{ - if (p != NULL && p->cs != NULL && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->ci != NULL) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->sids != NULL) { - SCFree(p->sids); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (p->sids_size * sizeof(SigIntId)); - } - - if (p != NULL) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACTilePattern); - } -} - -static inline uint32_t SCACTileInitHash(SCACTilePattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int SCACTileInitHashAdd(SCACTileCtx *ctx, SCACTilePattern *p) -{ - uint32_t hash = SCACTileInitHash(p); - - if (ctx->init_hash == NULL) { - return 0; - } - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - SCACTilePattern *tt = NULL; - SCACTilePattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - /** * \internal @@ -362,7 +173,7 @@ static inline int SCACTileInitHashAdd(SCACTileCtx *ctx, SCACTilePattern *p) * characters, so could just set to 1 instead of counting. */ static inline void SCACTileHistogramAlphabet(SCACTileCtx *ctx, - SCACTilePattern *p) + MpmPattern *p) { for (int i = 0; i < p->len; i++) { ctx->alpha_hist[p->ci[i]]++; @@ -413,137 +224,6 @@ static void SCACTileInitTranslateTable(SCACTileCtx *ctx) ctx->alphabet_storage = 256; } -/** - * \internal - * \brief Add a pattern to the mpm-ac context. - * - * \param mpm_ctx Mpm context. - * \param pat Pointer to the pattern. - * \param patlen Length of the pattern. - * \param pid Pattern id - * \param sid Signature id (internal id). - * \param flags Pattern's MPM_PATTERN_* flags. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int SCACTileAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, - ctx, patlen, pid); - - if (patlen == 0) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); - return 0; - } - - /* Check if we have already inserted this pattern. */ - SCACTilePattern *p = SCACTileInitHashLookup(ctx, pat, patlen, flags, pid); - if (p == NULL) { - SCLogDebug("Allocing new pattern"); - - /* p will never be NULL */ - p = SCACTileAllocPattern(mpm_ctx); - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci, pat, p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - /* put in the pattern hash */ - SCACTileInitHashAdd(ctx, p); - /* Count alphabet usages */ - SCACTileHistogramAlphabet(ctx, p); - - //if (mpm_ctx->pattern_cnt == 65535) { - // SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " - // "insert anymore. Exiting"); - // exit(EXIT_FAILURE); - //} - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - - if (mpm_ctx->minlen == 0) { - mpm_ctx->minlen = patlen; - } else { - if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); - BUG_ON(p->sids == NULL); - p->sids[0] = sid; - //SCLogInfo("MPM added %u:%u", pid, sid); - } else { - /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ - - int found = 0; - uint32_t x = 0; - for (x = 0; x < p->sids_size; x++) { - if (p->sids[x] == sid) { - found = 1; - break; - } - } - if (!found) { - SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); - BUG_ON(sids == NULL); - p->sids = sids; - p->sids[p->sids_size] = sid; - p->sids_size++; - //SCLogInfo("p->sids_size %u", p->sids_size); - //SCLogInfo("MPM added %u:%u (append)", pid, sid); - } else { - //SCLogInfo("rule %u already part of pid %u", sid, pid); - } - } - - return 0; - -error: - SCACTileFreePattern(mpm_ctx, p); - return -1; -} - static void SCACTileReallocOutputTable(SCACTileCtx *ctx, int new_state_count) { @@ -1198,33 +878,34 @@ int SCACTilePreparePatterns(MpmCtx *mpm_ctx) return 0; } SCACTileCtx *ctx = search_ctx->init_ctx; - if (ctx->init_hash == NULL) { + if (mpm_ctx->init_hash == NULL) { SCLogDebug("no patterns supplied to this mpm_ctx"); return 0; } /* alloc the pattern array */ - ctx->parray = (SCACTilePattern **)SCMalloc(mpm_ctx->pattern_cnt * - sizeof(SCACTilePattern *)); + ctx->parray = (MpmPattern **)SCMalloc(mpm_ctx->pattern_cnt * + sizeof(MpmPattern *)); if (ctx->parray == NULL) goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACTilePattern *)); + memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - SCACTilePattern *node = ctx->init_hash[i], *nnode = NULL; + for (i = 0; i < MPM_INIT_HASH_SIZE; i++) { + MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; while(node != NULL) { nnode = node->next; node->next = NULL; ctx->parray[p++] = node; + SCACTileHistogramAlphabet(ctx, node); node = nnode; } } /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; /* Handle case patterns by storing a copy of the pattern to compare * to each possible match (no-case). @@ -1336,12 +1017,11 @@ void SCACTileInitCtx(MpmCtx *mpm_ctx) mpm_ctx->memory_size += sizeof(SCACTileCtx); /* initialize the hash we use to speed up pattern insertions */ - SCACTileCtx *ctx = search_ctx->init_ctx; - ctx->init_hash = SCMalloc(sizeof(SCACTilePattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { + mpm_ctx->init_hash = SCMalloc(sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); + if (mpm_ctx->init_hash == NULL) { exit(EXIT_FAILURE); } - memset(ctx->init_hash, 0, sizeof(SCACTilePattern *) * INIT_HASH_SIZE); + memset(mpm_ctx->init_hash, 0, sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); /* get conf values for AC from our yaml file. We have no conf values for * now. We will certainly need this, as we develop the algo */ @@ -1374,16 +1054,16 @@ static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx) if (ctx == NULL) return; - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + if (mpm_ctx->init_hash != NULL) { + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; } if (ctx->parray != NULL) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { - SCACTileFreePattern(mpm_ctx, ctx->parray[i]); + MpmFreePattern(mpm_ctx, ctx->parray[i]); } } @@ -1739,7 +1419,7 @@ int SCACTileAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; - return SCACTileAddPattern(mpm_ctx, pat, patlen, offset, depth, + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } @@ -1764,7 +1444,7 @@ int SCACTileAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) { - return SCACTileAddPattern(mpm_ctx, pat, patlen, offset, depth, + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } @@ -1789,8 +1469,8 @@ void SCACTilePrintInfo(MpmCtx *mpm_ctx) printf(" Sizeof:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" SCACTileCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACTileCtx)); - printf(" SCACTilePattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACTilePattern)); - printf(" SCACTilePattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACTilePattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); diff --git a/src/util-mpm-ac-tile.h b/src/util-mpm-ac-tile.h index 62e3649fab9c..5f47f23018d7 100644 --- a/src/util-mpm-ac-tile.h +++ b/src/util-mpm-ac-tile.h @@ -26,27 +26,6 @@ #ifndef __UTIL_MPM_AC_TILE__H__ #define __UTIL_MPM_AC_TILE__H__ -typedef struct SCACTilePattern_ { - /* length of the pattern */ - uint16_t len; - /* flags decribing the pattern */ - uint8_t flags; - /* holds the original pattern that was added */ - uint8_t *original_pat; - /* case sensitive */ - uint8_t *cs; - /* case INsensitive */ - uint8_t *ci; - /* pattern id */ - uint32_t id; - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; - - struct SCACTilePattern_ *next; -} SCACTilePattern; - typedef struct SCACTilePatternList_ { uint8_t *cs; uint16_t patlen; @@ -98,12 +77,9 @@ typedef struct SCACTileCtx_ { /* Indexed by MpmPatternIndex */ SCACTilePatternList *pattern_list; - /* hash used during ctx initialization */ - SCACTilePattern **init_hash; - /* pattern arrays. We need this only during the goto table creation phase */ - SCACTilePattern **parray; + MpmPattern **parray; /* goto_table, failure table and output table. Needed to create * state_table. Will be freed, once we have created the diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 2dca134f5138..fe37af19baee 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -86,8 +86,6 @@ void SCACRegisterTests(void); /* a placeholder to denote a failure transition in the goto table */ #define SC_AC_FAIL (-1) -/* size of the hash table used to speed up pattern insertions initially */ -#define INIT_HASH_SIZE 65536 #define STATE_QUEUE_CONTAINER_SIZE 65536 @@ -118,286 +116,6 @@ static void SCACGetConfig() return; } -/** - * \internal - * \brief Creates a hash of the pattern. We use it for the hashing process - * during the initial pattern insertion time, to cull duplicate sigs. - * - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline uint32_t SCACInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -/** - * \internal - * \brief Looks up a pattern. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param ctx Pointer to the AC ctx. - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline SCACPattern *SCACInitHashLookup(SCACCtx *ctx, uint8_t *pat, - uint16_t patlen, char flags, - uint32_t pid) -{ - uint32_t hash = SCACInitHashRaw(pat, patlen); - - if (ctx->init_hash == NULL) { - return NULL; - } - - SCACPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (t->id == pid) - return t; - } - - return NULL; -} - -/** - * \internal - * \brief Allocs a new pattern instance. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval p Pointer to the newly created pattern. - */ -static inline SCACPattern *SCACAllocPattern(MpmCtx *mpm_ctx) -{ - SCACPattern *p = SCMalloc(sizeof(SCACPattern)); - if (unlikely(p == NULL)) { - exit(EXIT_FAILURE); - } - memset(p, 0, sizeof(SCACPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACPattern); - - return p; -} - -/** - * \internal - * \brief Used to free SCACPattern instances. - * - * \param mpm_ctx Pointer to the mpm context. - * \param p Pointer to the SCACPattern instance to be freed. - * \param free Free the above pointer or not. - */ -static inline void SCACFreePattern(MpmCtx *mpm_ctx, SCACPattern *p) -{ - if (p != NULL && p->cs != NULL && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->ci != NULL) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->sids != NULL) { - SCFree(p->sids); - } - - if (p != NULL) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACPattern); - } - return; -} - -static inline uint32_t SCACInitHash(SCACPattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int SCACInitHashAdd(SCACCtx *ctx, SCACPattern *p) -{ - uint32_t hash = SCACInitHash(p); - - if (ctx->init_hash == NULL) { - return 0; - } - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - SCACPattern *tt = NULL; - SCACPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - -/** - * \internal - * \brief Add a pattern to the mpm-ac context. - * - * \param mpm_ctx Mpm context. - * \param pat Pointer to the pattern. - * \param patlen Length of the pattern. - * \param pid Pattern id - * \param sid Signature id (internal id). - * \param flags Pattern's MPM_PATTERN_* flags. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int SCACAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - - SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, - ctx, patlen, pid); - - if (patlen == 0) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); - return 0; - } - - /* check if we have already inserted this pattern */ - SCACPattern *p = SCACInitHashLookup(ctx, pat, patlen, flags, pid); - if (p == NULL) { - SCLogDebug("Allocing new pattern"); - - /* p will never be NULL */ - p = SCACAllocPattern(mpm_ctx); - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci, pat, p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - /* put in the pattern hash */ - SCACInitHashAdd(ctx, p); - - //if (mpm_ctx->pattern_cnt == 65535) { - // SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " - // "insert anymore. Exiting"); - // exit(EXIT_FAILURE); - //} - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - - if (mpm_ctx->minlen == 0) { - mpm_ctx->minlen = patlen; - } else { - if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - /* we need the max pat id */ - if (pid > ctx->max_pat_id) - ctx->max_pat_id = pid; - - p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); - BUG_ON(p->sids == NULL); - p->sids[0] = sid; - //SCLogInfo("MPM added %u:%u", pid, sid); - } else { - /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ - - int found = 0; - uint32_t x = 0; - for (x = 0; x < p->sids_size; x++) { - if (p->sids[x] == sid) { - found = 1; - break; - } - } - if (!found) { - SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); - BUG_ON(sids == NULL); - p->sids = sids; - p->sids[p->sids_size] = sid; - p->sids_size++; - //SCLogInfo("p->sids_size %u", p->sids_size); - //SCLogInfo("MPM added %u:%u (append)", pid, sid); - } else { - //SCLogInfo("rule %u already part of pid %u", sid, pid); - } - } - - return 0; - -error: - SCACFreePattern(mpm_ctx, p); - return -1; -} - /** * \internal * \brief Initialize a new state in the goto and output tables. @@ -1036,24 +754,24 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { + if (mpm_ctx->pattern_cnt == 0 || mpm_ctx->init_hash == NULL) { SCLogDebug("no patterns supplied to this mpm_ctx"); return 0; } /* alloc the pattern array */ - ctx->parray = (SCACPattern **)SCMalloc(mpm_ctx->pattern_cnt * - sizeof(SCACPattern *)); + ctx->parray = (MpmPattern **)SCMalloc(mpm_ctx->pattern_cnt * + sizeof(MpmPattern *)); if (ctx->parray == NULL) goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); + memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); + mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - SCACPattern *node = ctx->init_hash[i], *nnode = NULL; + for (i = 0; i < MPM_INIT_HASH_SIZE; i++) { + MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; while(node != NULL) { nnode = node->next; node->next = NULL; @@ -1063,19 +781,19 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) } /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; /* the memory consumed by a single state in our goto table */ ctx->single_state_size = sizeof(int32_t) * 256; /* handle no case patterns */ - ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACPatternList)); + ctx->pid_pat_list = SCMalloc((mpm_ctx->max_pat_id + 1)* sizeof(SCACPatternList)); if (ctx->pid_pat_list == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACPatternList)); + memset(ctx->pid_pat_list, 0, (mpm_ctx->max_pat_id + 1) * sizeof(SCACPatternList)); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { @@ -1123,15 +841,16 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) /* free all the stored patterns. Should save us a good 100-200 mbs */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { - SCACFreePattern(mpm_ctx, ctx->parray[i]); + MpmFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); - ctx->pattern_id_bitarray_size = (ctx->max_pat_id / 8) + 1; + ctx->pattern_id_bitarray_size = (mpm_ctx->max_pat_id / 8) + 1; + SCLogDebug("ctx->pattern_id_bitarray_size %u", ctx->pattern_id_bitarray_size); return 0; @@ -1181,12 +900,11 @@ void SCACInitCtx(MpmCtx *mpm_ctx) mpm_ctx->memory_size += sizeof(SCACCtx); /* initialize the hash we use to speed up pattern insertions */ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(SCACPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { + mpm_ctx->init_hash = SCMalloc(sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); + if (mpm_ctx->init_hash == NULL) { exit(EXIT_FAILURE); } - memset(ctx->init_hash, 0, sizeof(SCACPattern *) * INIT_HASH_SIZE); + memset(mpm_ctx->init_hash, 0, sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); /* get conf values for AC from our yaml file. We have no conf values for * now. We will certainly need this, as we develop the algo */ @@ -1226,25 +944,25 @@ void SCACDestroyCtx(MpmCtx *mpm_ctx) if (ctx == NULL) return; - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + if (mpm_ctx->init_hash != NULL) { + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCACPattern *)); + mpm_ctx->memory_size -= (MPM_INIT_HASH_SIZE * sizeof(MpmPattern *)); } if (ctx->parray != NULL) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { - SCACFreePattern(mpm_ctx, ctx->parray[i]); + MpmFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); } if (ctx->state_table_u16 != NULL) { @@ -1276,7 +994,7 @@ void SCACDestroyCtx(MpmCtx *mpm_ctx) if (ctx->pid_pat_list != NULL) { uint32_t i; - for (i = 0; i < (ctx->max_pat_id + 1); i++) { + for (i = 0; i < (mpm_ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); if (ctx->pid_pat_list[i].sids != NULL) @@ -1425,7 +1143,7 @@ int SCACAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; - return SCACAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } /** @@ -1449,7 +1167,7 @@ int SCACAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) { - return SCACAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } void SCACPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) @@ -1475,8 +1193,8 @@ void SCACPrintInfo(MpmCtx *mpm_ctx) printf(" Sizeof:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" SCACCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACCtx)); - printf(" SCACPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACPattern)); - printf(" SCACPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); diff --git a/src/util-mpm-ac.h b/src/util-mpm-ac.h index 394ad6781f2d..97ae48e8d710 100644 --- a/src/util-mpm-ac.h +++ b/src/util-mpm-ac.h @@ -38,27 +38,6 @@ #include "flow.h" #endif /* __SC_CUDA_SUPPORT__ */ -typedef struct SCACPattern_ { - /* length of the pattern */ - uint16_t len; - /* flags decribing the pattern */ - uint8_t flags; - /* holds the original pattern that was added */ - uint8_t *original_pat; - /* case sensitive */ - uint8_t *cs; - /* case INsensitive */ - uint8_t *ci; - /* pattern id */ - uint32_t id; - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; - - struct SCACPattern_ *next; -} SCACPattern; - typedef struct SCACPatternList_ { uint8_t *cs; uint16_t patlen; @@ -76,11 +55,8 @@ typedef struct SCACOutputTable_ { } SCACOutputTable; typedef struct SCACCtx_ { - /* hash used during ctx initialization */ - SCACPattern **init_hash; - /* pattern arrays. We need this only during the goto table creation phase */ - SCACPattern **parray; + MpmPattern **parray; /* no of states used by ac */ uint32_t state_count; @@ -101,7 +77,6 @@ typedef struct SCACCtx_ { /* the size of each state */ uint32_t single_state_size; - uint32_t max_pat_id; uint32_t allocated_state_count; diff --git a/src/util-mpm.c b/src/util-mpm.c index 27f5a86c072f..9fbf6c22794a 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -45,6 +45,7 @@ #include "util-cuda-handlers.h" #include "detect-engine-mpm.h" #endif +#include "util-memcpy.h" /** * \brief Register a new Mpm Context. @@ -556,6 +557,287 @@ int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, } +/** + * \internal + * \brief Creates a hash of the pattern. We use it for the hashing process + * during the initial pattern insertion time, to cull duplicate sigs. + * + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * + * \retval hash A 32 bit unsigned hash. + */ +static inline uint32_t MpmInitHashRaw(uint8_t *pat, uint16_t patlen) +{ + uint32_t hash = patlen * pat[0]; + if (patlen > 1) + hash += pat[1]; + + return (hash % MPM_INIT_HASH_SIZE); +} + +/** + * \internal + * \brief Looks up a pattern. We use it for the hashing process during the + * the initial pattern insertion time, to cull duplicate sigs. + * + * \param ctx Pointer to the AC ctx. + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * \param flags Flags. We don't need this. + * + * \retval hash A 32 bit unsigned hash. + */ +static inline MpmPattern *MpmInitHashLookup(MpmCtx *ctx, uint8_t *pat, + uint16_t patlen, char flags, + uint32_t pid) +{ + uint32_t hash = MpmInitHashRaw(pat, patlen); + + if (ctx->init_hash == NULL) { + return NULL; + } + + MpmPattern *t = ctx->init_hash[hash]; + for ( ; t != NULL; t = t->next) { + if (!(flags & MPM_PATTERN_CTX_OWNS_ID)) { + if (t->id == pid) + return t; + } else { + if (t->len == patlen && + memcmp(pat, t->original_pat, patlen) == 0 && + t->flags == flags) + { + return t; + } + } + } + + return NULL; +} + +/** + * \internal + * \brief Allocs a new pattern instance. + * + * \param mpm_ctx Pointer to the mpm context. + * + * \retval p Pointer to the newly created pattern. + */ +static inline MpmPattern *MpmAllocPattern(MpmCtx *mpm_ctx) +{ + MpmPattern *p = SCMalloc(sizeof(MpmPattern)); + if (unlikely(p == NULL)) { + exit(EXIT_FAILURE); + } + memset(p, 0, sizeof(MpmPattern)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(MpmPattern); + + return p; +} + +/** + * \internal + * \brief Used to free MpmPattern instances. + * + * \param mpm_ctx Pointer to the mpm context. + * \param p Pointer to the MpmPattern instance to be freed. + */ +void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p) +{ + if (p != NULL && p->cs != NULL && p->cs != p->ci) { + SCFree(p->cs); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } + + if (p != NULL && p->ci != NULL) { + SCFree(p->ci); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } + + if (p != NULL && p->original_pat != NULL) { + SCFree(p->original_pat); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } + + if (p != NULL) { + SCFree(p); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(MpmPattern); + } + return; +} + +static inline uint32_t MpmInitHash(MpmPattern *p) +{ + uint32_t hash = p->len * p->original_pat[0]; + if (p->len > 1) + hash += p->original_pat[1]; + + return (hash % MPM_INIT_HASH_SIZE); +} + +static inline int MpmInitHashAdd(MpmCtx *ctx, MpmPattern *p) +{ + uint32_t hash = MpmInitHash(p); + + if (ctx->init_hash == NULL) { + return 0; + } + + if (ctx->init_hash[hash] == NULL) { + ctx->init_hash[hash] = p; + return 0; + } + + MpmPattern *tt = NULL; + MpmPattern *t = ctx->init_hash[hash]; + + /* get the list tail */ + do { + tt = t; + t = t->next; + } while (t != NULL); + + tt->next = p; + + return 0; +} + +/** + * \internal + * \brief Add a pattern to the mpm-ac context. + * + * \param mpm_ctx Mpm context. + * \param pat Pointer to the pattern. + * \param patlen Length of the pattern. + * \param pid Pattern id + * \param sid Signature id (internal id). + * \param flags Pattern's MPM_PATTERN_* flags. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int MpmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags) +{ + SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, + mpm_ctx, patlen, pid); + + if (patlen == 0) { + SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); + return 0; + } + + if (flags & MPM_PATTERN_CTX_OWNS_ID) + pid = UINT_MAX; + + /* check if we have already inserted this pattern */ + MpmPattern *p = MpmInitHashLookup(mpm_ctx, pat, patlen, flags, pid); + if (p == NULL) { + SCLogDebug("Allocing new pattern"); + + /* p will never be NULL */ + p = MpmAllocPattern(mpm_ctx); + + p->len = patlen; + p->flags = flags; + if (flags & MPM_PATTERN_CTX_OWNS_ID) + p->id = mpm_ctx->max_pat_id++; + else + p->id = pid; + + p->original_pat = SCMalloc(patlen); + if (p->original_pat == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy(p->original_pat, pat, patlen); + + p->ci = SCMalloc(patlen); + if (p->ci == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy_tolower(p->ci, pat, patlen); + + /* setup the case sensitive part of the pattern */ + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + /* nocase means no difference between cs and ci */ + p->cs = p->ci; + } else { + if (memcmp(p->ci, pat, p->len) == 0) { + /* no diff between cs and ci: pat is lowercase */ + p->cs = p->ci; + } else { + p->cs = SCMalloc(patlen); + if (p->cs == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy(p->cs, pat, patlen); + } + } + + /* put in the pattern hash */ + MpmInitHashAdd(mpm_ctx, p); + + mpm_ctx->pattern_cnt++; + + if (mpm_ctx->maxlen < patlen) + mpm_ctx->maxlen = patlen; + + if (mpm_ctx->minlen == 0) { + mpm_ctx->minlen = patlen; + } else { + if (mpm_ctx->minlen > patlen) + mpm_ctx->minlen = patlen; + } + + /* we need the max pat id */ + if (p->id > mpm_ctx->max_pat_id) + mpm_ctx->max_pat_id = p->id; + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + } else { + /* we can be called multiple times for the same sid in the case + * of the 'single' modus. Here multiple rule groups share the + * same mpm ctx and might be adding the same pattern to the + * mpm_ctx */ + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + + if (!found) { + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + } + } + + return 0; + +error: + MpmFreePattern(mpm_ctx, p); + return -1; +} + /************************************Unittests*********************************/ diff --git a/src/util-mpm.h b/src/util-mpm.h index 209a3fddfd67..2cf85e59804b 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -25,6 +25,9 @@ #define __UTIL_MPM_H__ #include "suricata-common.h" + +#define MPM_INIT_HASH_SIZE 65536 + enum { MPM_NOTSET = 0, @@ -76,6 +79,27 @@ typedef struct PatternMatcherQueue_ { } PatternMatcherQueue; +typedef struct MpmPattern_ { + /* length of the pattern */ + uint16_t len; + /* flags decribing the pattern */ + uint8_t flags; + /* holds the original pattern that was added */ + uint8_t *original_pat; + /* case sensitive */ + uint8_t *cs; + /* case INsensitive */ + uint8_t *ci; + /* pattern id */ + uint32_t id; + + /* sid(s) for this pattern */ + uint32_t sids_size; + SigIntId *sids; + + struct MpmPattern_ *next; +} MpmPattern; + typedef struct MpmCtx_ { void *ctx; uint16_t mpm_type; @@ -94,6 +118,11 @@ typedef struct MpmCtx_ { uint32_t memory_cnt; uint32_t memory_size; + + uint32_t max_pat_id; + + /* hash used during ctx initialization */ + MpmPattern **init_hash; } MpmCtx; /* if we want to retrieve an unique mpm context from the mpm context factory @@ -125,6 +154,9 @@ typedef struct MpmCtxFactoryContainer_ { #define MPM_PATTERN_FLAG_OFFSET 0x08 /** one byte pattern (used in b2g) */ #define MPM_PATTERN_ONE_BYTE 0x10 +/** the ctx uses it's own internal id instead of + * what is passed through the API */ +#define MPM_PATTERN_CTX_OWNS_ID 0x20 typedef struct MpmTableElmt_ { char *name; @@ -220,6 +252,12 @@ int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags); +void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p); + +int MpmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags); + /* Resize Signature ID array. Only called from MpmAddSids(). */ int MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size); From c804102a9a2cf3b53bc45fb912cfa462dc52f5b3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Oct 2015 14:52:01 +0200 Subject: [PATCH 1194/2553] detect: move app_mpms array to init data --- src/detect-engine-mpm.c | 40 ++++++++++++++++++++-------------------- src/detect.h | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 776622ab6e93..e861e0ba5d88 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1620,34 +1620,34 @@ MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, App void MpmStoreFixup(SigGroupHead *sgh) { int i = 0; - sgh->mpm_uri_ctx_ts = sgh->app_mpms[i++]; - sgh->mpm_hrud_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_uri_ctx_ts = sgh->init->app_mpms[i++]; + sgh->mpm_hrud_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_hhd_ctx_ts = sgh->app_mpms[i++]; - sgh->mpm_hhd_ctx_tc = sgh->app_mpms[i++]; + sgh->mpm_hhd_ctx_ts = sgh->init->app_mpms[i++]; + sgh->mpm_hhd_ctx_tc = sgh->init->app_mpms[i++]; - sgh->mpm_huad_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_huad_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_hrhd_ctx_ts = sgh->app_mpms[i++]; - sgh->mpm_hrhd_ctx_tc = sgh->app_mpms[i++]; + sgh->mpm_hrhd_ctx_ts = sgh->init->app_mpms[i++]; + sgh->mpm_hrhd_ctx_tc = sgh->init->app_mpms[i++]; - sgh->mpm_hmd_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_hmd_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_smtp_filedata_ctx_ts = sgh->app_mpms[i++]; - sgh->mpm_hsbd_ctx_tc = sgh->app_mpms[i++]; + sgh->mpm_smtp_filedata_ctx_ts = sgh->init->app_mpms[i++]; + sgh->mpm_hsbd_ctx_tc = sgh->init->app_mpms[i++]; - sgh->mpm_hsmd_ctx_tc = sgh->app_mpms[i++]; - sgh->mpm_hscd_ctx_tc = sgh->app_mpms[i++]; + sgh->mpm_hsmd_ctx_tc = sgh->init->app_mpms[i++]; + sgh->mpm_hscd_ctx_tc = sgh->init->app_mpms[i++]; - sgh->mpm_hcbd_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_hcbd_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_hhhd_ctx_ts = sgh->app_mpms[i++]; - sgh->mpm_hrhhd_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_hhhd_ctx_ts = sgh->init->app_mpms[i++]; + sgh->mpm_hrhhd_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_hcd_ctx_ts = sgh->app_mpms[i++]; - sgh->mpm_hcd_ctx_tc = sgh->app_mpms[i++]; + sgh->mpm_hcd_ctx_ts = sgh->init->app_mpms[i++]; + sgh->mpm_hcd_ctx_tc = sgh->init->app_mpms[i++]; - sgh->mpm_dnsquery_ctx_ts = sgh->app_mpms[i++]; + sgh->mpm_dnsquery_ctx_ts = sgh->init->app_mpms[i++]; BUG_ON(APP_MPMS_MAX != 18 || i != 18); } @@ -1724,8 +1724,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) while (a->name != NULL) { mpm_store = MpmStorePrepareBuffer2(de_ctx, sh, a); if (mpm_store != NULL) { - sh->app_mpms[a->id] = mpm_store->mpm_ctx; - if (sh->app_mpms[a->id] != NULL) + sh->init->app_mpms[a->id] = mpm_store->mpm_ctx; + if (sh->init->app_mpms[a->id] != NULL) sh->flags |= a->flags; } a++; diff --git a/src/detect.h b/src/detect.h index f728e9bd8b66..cad6f7c6bb61 100644 --- a/src/detect.h +++ b/src/detect.h @@ -962,6 +962,8 @@ typedef struct SigGroupHeadInitData_ { 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[APP_MPMS_MAX]; + /* port ptr */ struct DetectPort_ *port; } SigGroupHeadInitData; @@ -1020,8 +1022,6 @@ typedef struct SigGroupHead_ { /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ Signature **match_array; - MpmCtx *app_mpms[APP_MPMS_MAX]; - /* ptr to our init data we only use at... init :) */ SigGroupHeadInitData *init; } SigGroupHead; From c880b79f45b0ddc269e5710a45549b23da748743 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Oct 2015 15:22:44 +0200 Subject: [PATCH 1195/2553] detect: shrink sgh Turn list of mpm_ctx pointers into a union so that we don't waste space. The sgh's for tcp and udp are in one direction only, so the ts and tc ones are now in the union. --- src/detect-engine-mpm.c | 56 ++++++++++++++++++++++----------- src/detect.h | 68 ++++++++++++++++++++++------------------- 2 files changed, 74 insertions(+), 50 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index e861e0ba5d88..9a8a8bd6f985 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1619,37 +1619,57 @@ MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, App /** \todo fixup old mpm ptrs. We could use the array directly later */ void MpmStoreFixup(SigGroupHead *sgh) { + if (!(SGH_PROTO(sgh, IPPROTO_TCP) || SGH_PROTO(sgh, IPPROTO_UDP))) + return; + +#define SET_TS(sgh, ptr) do { \ + if (SGH_DIRECTION_TS((sgh))) \ + (ptr) = (sgh)->init->app_mpms[i++]; \ + else \ + i++; \ + } while(0) + +#define SET_TC(sgh, ptr) do { \ + if (SGH_DIRECTION_TC((sgh))) \ + (ptr) = (sgh)->init->app_mpms[i++]; \ + else \ + i++; \ + } while(0) + int i = 0; - sgh->mpm_uri_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_hrud_ctx_ts = sgh->init->app_mpms[i++]; + SET_TS(sgh, sgh->mpm_uri_ctx_ts); + SET_TS(sgh, sgh->mpm_hrud_ctx_ts); - sgh->mpm_hhd_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_hhd_ctx_tc = sgh->init->app_mpms[i++]; + SET_TS(sgh, sgh->mpm_hhd_ctx_ts); + SET_TC(sgh, sgh->mpm_hhd_ctx_tc); - sgh->mpm_huad_ctx_ts = sgh->init->app_mpms[i++]; + SET_TS(sgh, sgh->mpm_huad_ctx_ts); - sgh->mpm_hrhd_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_hrhd_ctx_tc = sgh->init->app_mpms[i++]; + SET_TS(sgh, sgh->mpm_hrhd_ctx_ts); + SET_TC(sgh, sgh->mpm_hrhd_ctx_tc); - sgh->mpm_hmd_ctx_ts = sgh->init->app_mpms[i++]; + SET_TS(sgh, sgh->mpm_hmd_ctx_ts); - sgh->mpm_smtp_filedata_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_hsbd_ctx_tc = sgh->init->app_mpms[i++]; + SET_TS(sgh, sgh->mpm_smtp_filedata_ctx_ts); + SET_TC(sgh, sgh->mpm_hsbd_ctx_tc); - sgh->mpm_hsmd_ctx_tc = sgh->init->app_mpms[i++]; - sgh->mpm_hscd_ctx_tc = sgh->init->app_mpms[i++]; + SET_TC(sgh, sgh->mpm_hsmd_ctx_tc); + SET_TC(sgh, sgh->mpm_hscd_ctx_tc); - sgh->mpm_hcbd_ctx_ts = sgh->init->app_mpms[i++]; + SET_TS(sgh, sgh->mpm_hcbd_ctx_ts); - sgh->mpm_hhhd_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_hrhhd_ctx_ts = sgh->init->app_mpms[i++]; + SET_TS(sgh, sgh->mpm_hhhd_ctx_ts); + SET_TS(sgh, sgh->mpm_hrhhd_ctx_ts); - sgh->mpm_hcd_ctx_ts = sgh->init->app_mpms[i++]; - sgh->mpm_hcd_ctx_tc = sgh->init->app_mpms[i++]; + SET_TS(sgh, sgh->mpm_hcd_ctx_ts); + SET_TC(sgh, sgh->mpm_hcd_ctx_tc); - sgh->mpm_dnsquery_ctx_ts = sgh->init->app_mpms[i++]; + SET_TS(sgh, sgh->mpm_dnsquery_ctx_ts); BUG_ON(APP_MPMS_MAX != 18 || i != 18); + +#undef SET_TS +#undef SET_TC } /** \brief Prepare the pattern matcher ctx in a sig group head. diff --git a/src/detect.h b/src/detect.h index cad6f7c6bb61..6535be6d2a14 100644 --- a/src/detect.h +++ b/src/detect.h @@ -976,49 +976,53 @@ typedef struct SigGroupHead_ { /* track min pattern length for content. Used in grouping */ uint16_t mpm_content_minlen; + uint16_t mpm_uricontent_minlen; /**< len of shortest mpm pattern in sgh */ /* non mpm list excluding SYN rules */ - SignatureNonMpmStore *non_mpm_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) uint32_t non_mpm_other_store_cnt; + SignatureNonMpmStore *non_mpm_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) /* non mpm list including SYN rules */ SignatureNonMpmStore *non_mpm_syn_store_array; // size is non_mpm_syn_store_cnt * sizeof(SignatureNonMpmStore) uint32_t non_mpm_syn_store_cnt; - /* pattern matcher instances */ - const MpmCtx *mpm_proto_other_ctx; - - const MpmCtx *mpm_proto_tcp_ctx_ts; - const MpmCtx *mpm_proto_udp_ctx_ts; - const MpmCtx *mpm_stream_ctx_ts; - const MpmCtx *mpm_uri_ctx_ts; - const MpmCtx *mpm_hcbd_ctx_ts; - const MpmCtx *mpm_hhd_ctx_ts; - const MpmCtx *mpm_hrhd_ctx_ts; - const MpmCtx *mpm_hmd_ctx_ts; - const MpmCtx *mpm_hcd_ctx_ts; - const MpmCtx *mpm_hrud_ctx_ts; - const MpmCtx *mpm_huad_ctx_ts; - const MpmCtx *mpm_hhhd_ctx_ts; - const MpmCtx *mpm_hrhhd_ctx_ts; - const MpmCtx *mpm_dnsquery_ctx_ts; - const MpmCtx *mpm_smtp_filedata_ctx_ts; - - const MpmCtx *mpm_proto_tcp_ctx_tc; - const MpmCtx *mpm_proto_udp_ctx_tc; - const MpmCtx *mpm_stream_ctx_tc; - const MpmCtx *mpm_hsbd_ctx_tc; - const MpmCtx *mpm_hhd_ctx_tc; - const MpmCtx *mpm_hrhd_ctx_tc; - const MpmCtx *mpm_hcd_ctx_tc; - const MpmCtx *mpm_hsmd_ctx_tc; - const MpmCtx *mpm_hscd_ctx_tc; - - uint16_t mpm_uricontent_minlen; /**< len of shortest mpm pattern in sgh */ - /** the number of signatures in this sgh that have the filestore keyword * set. */ uint16_t filestore_cnt; + /* pattern matcher instances */ + const MpmCtx *mpm_proto_other_ctx; + + union { + struct { + const MpmCtx *mpm_proto_tcp_ctx_ts; + const MpmCtx *mpm_proto_udp_ctx_ts; + const MpmCtx *mpm_stream_ctx_ts; + const MpmCtx *mpm_uri_ctx_ts; + const MpmCtx *mpm_hcbd_ctx_ts; + const MpmCtx *mpm_hhd_ctx_ts; + const MpmCtx *mpm_hrhd_ctx_ts; + const MpmCtx *mpm_hmd_ctx_ts; + const MpmCtx *mpm_hcd_ctx_ts; + const MpmCtx *mpm_hrud_ctx_ts; + const MpmCtx *mpm_huad_ctx_ts; + const MpmCtx *mpm_hhhd_ctx_ts; + const MpmCtx *mpm_hrhhd_ctx_ts; + const MpmCtx *mpm_dnsquery_ctx_ts; + const MpmCtx *mpm_smtp_filedata_ctx_ts; + }; + struct { + const MpmCtx *mpm_proto_tcp_ctx_tc; + const MpmCtx *mpm_proto_udp_ctx_tc; + const MpmCtx *mpm_stream_ctx_tc; + const MpmCtx *mpm_hsbd_ctx_tc; + const MpmCtx *mpm_hhd_ctx_tc; + const MpmCtx *mpm_hrhd_ctx_tc; + const MpmCtx *mpm_hcd_ctx_tc; + const MpmCtx *mpm_hsmd_ctx_tc; + const MpmCtx *mpm_hscd_ctx_tc; + }; + }; + /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ Signature **match_array; From e310a033be69d40026cb6ae9f605da78699d37c8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Oct 2015 13:34:55 +0100 Subject: [PATCH 1196/2553] detect: assign id to sgh --- src/detect.c | 4 ++++ src/detect.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/detect.c b/src/detect.c index 404dac4d5309..2293f69b11fc 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2978,6 +2978,8 @@ json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh) if (unlikely(js == NULL)) return NULL; + json_object_set_new(js, "id", json_integer(sgh->id)); + json_t *js_array = json_array(); const Signature *s; @@ -4070,6 +4072,8 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) sgh->mpm_uricontent_minlen = SigGroupHeadGetMinMpmSize(de_ctx, sgh, DETECT_SM_LIST_UMATCH); SCLogDebug("http_uri content min mpm len: %u", sgh->mpm_uricontent_minlen); + + sgh->id = idx; cnt++; } SCLogInfo("Unique rule groups: %u", cnt); diff --git a/src/detect.h b/src/detect.h index 6535be6d2a14..02728200c108 100644 --- a/src/detect.h +++ b/src/detect.h @@ -989,6 +989,8 @@ typedef struct SigGroupHead_ { * set. */ uint16_t filestore_cnt; + uint32_t id; /**< unique id used to index sgh_array for stats */ + /* pattern matcher instances */ const MpmCtx *mpm_proto_other_ctx; From 722e2dbf7cb916845fc50d5408000dcc6da9eabc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Oct 2015 00:21:00 +0200 Subject: [PATCH 1197/2553] profiling: initial rulegroup tracking Per rule group tracking of checks, use of lists, mpm matches, post filter counts. Logs SGH id so it can be compared with the rule_group.json output. Implemented both in a human readable text format and a JSON format. --- src/Makefile.am | 1 + src/detect-engine.c | 5 + src/detect.c | 5 + src/detect.h | 3 + src/runmode-unix-socket.c | 1 + src/suricata.c | 1 + src/util-profiling-keywords.c | 2 +- src/util-profiling-rulegroups.c | 407 ++++++++++++++++++++++++++++++++ src/util-profiling.h | 15 ++ suricata.yaml.in | 6 + 10 files changed, 445 insertions(+), 1 deletion(-) create mode 100644 src/util-profiling-rulegroups.c diff --git a/src/Makefile.am b/src/Makefile.am index ec936181d2ac..c3c7c679c116 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -382,6 +382,7 @@ util-profiling.c util-profiling.h \ util-profiling-locks.c util-profiling-locks.h \ util-profiling-rules.c \ util-profiling-keywords.c \ +util-profiling-rulegroups.c \ util-proto-name.c util-proto-name.h \ util-radix-tree.c util-radix-tree.h \ util-random.c util-random.h \ diff --git a/src/detect-engine.c b/src/detect-engine.c index 5827af8900b0..c293a2ea8122 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -949,6 +949,9 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) SCProfilingKeywordDestroyCtx(de_ctx);//->profile_keyword_ctx); // de_ctx->profile_keyword_ctx = NULL; } + if (de_ctx->profile_sgh_ctx != NULL) { + SCProfilingSghDestroyCtx(de_ctx); + } #endif /* Normally the hashes are freed elsewhere, but @@ -1380,6 +1383,7 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * #ifdef PROFILING SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx); SCProfilingKeywordThreadSetup(de_ctx->profile_keyword_ctx, det_ctx); + SCProfilingSghThreadSetup(de_ctx->profile_sgh_ctx, det_ctx); #endif SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect); @@ -1530,6 +1534,7 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) #ifdef PROFILING SCProfilingRuleThreadCleanup(det_ctx); SCProfilingKeywordThreadCleanup(det_ctx); + SCProfilingSghThreadCleanup(det_ctx); #endif DetectEngineIPOnlyThreadDeinit(&det_ctx->io_ctx); diff --git a/src/detect.c b/src/detect.c index 2293f69b11fc..90699debd4fb 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1538,6 +1538,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh #endif Signature **match_array = det_ctx->match_array; + SGH_PROFILING_RECORD(det_ctx, det_ctx->sgh); + uint32_t sflags, next_sflags = 0; if (match_cnt) { next_s = *match_array++; @@ -4091,6 +4093,9 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) RulesDumpGrouping(de_ctx); +#ifdef PROFILING + SCProfilingSghInitCounters(de_ctx); +#endif SCReturnInt(0); } diff --git a/src/detect.h b/src/detect.h index 02728200c108..f70493f3cb4c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -660,6 +660,7 @@ typedef struct DetectEngineCtx_ { struct SCProfileDetectCtx_ *profile_ctx; struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx; struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; + struct SCProfileSghDetectCtx_ *profile_sgh_ctx; #endif char config_prefix[64]; @@ -858,6 +859,7 @@ typedef struct DetectEngineThreadCtx_ { 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_* */ + struct SCProfileSghData_ *sgh_perf_data; #endif } DetectEngineThreadCtx; @@ -1030,6 +1032,7 @@ typedef struct SigGroupHead_ { /* ptr to our init data we only use at... init :) */ SigGroupHeadInitData *init; + } SigGroupHead; /** sigmatch has no options, so the parser shouldn't expect any */ diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 09edb610d8e6..3ccf89b98d39 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -381,6 +381,7 @@ TmEcode UnixSocketPcapFilesCheck(void *data) #ifdef PROFILING SCProfilingRulesGlobalInit(); SCProfilingKeywordsGlobalInit(); + SCProfilingSghsGlobalInit(); SCProfilingInit(); #endif /* PROFILING */ DefragInit(); diff --git a/src/suricata.c b/src/suricata.c index dbe1b139c33b..5eb6482be768 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2167,6 +2167,7 @@ static int PostConfLoadedSetup(SCInstance *suri) if (suri->run_mode != RUNMODE_UNIX_SOCKET) { SCProfilingRulesGlobalInit(); SCProfilingKeywordsGlobalInit(); + SCProfilingSghsGlobalInit(); SCProfilingInit(); } #endif /* PROFILING */ diff --git a/src/util-profiling-keywords.c b/src/util-profiling-keywords.c index 9f3019aa5d4f..444406c1275a 100644 --- a/src/util-profiling-keywords.c +++ b/src/util-profiling-keywords.c @@ -100,7 +100,7 @@ void SCProfilingKeywordsGlobalInit(void) } } -void DoDump(SCProfileKeywordDetectCtx *rules_ctx, FILE *fp, const char *name) +static void DoDump(SCProfileKeywordDetectCtx *rules_ctx, FILE *fp, const char *name) { int i; fprintf(fp, " ----------------------------------------------" diff --git a/src/util-profiling-rulegroups.c b/src/util-profiling-rulegroups.c new file mode 100644 index 000000000000..e4112ccc13b2 --- /dev/null +++ b/src/util-profiling-rulegroups.c @@ -0,0 +1,407 @@ +/* Copyright (C) 2007-2015 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 Endace Technology Limited. + * \author Victor Julien + * + * An API for rule profiling operations. + */ + +#include "suricata-common.h" +#include "decode.h" +#include "detect.h" +#include "detect-engine.h" +#include "conf.h" + +#include "tm-threads.h" + +#include "util-unittest.h" +#include "util-byte.h" +#include "util-profiling.h" +#include "util-profiling-locks.h" + +#ifdef PROFILING + +/** + * Extra data for rule profiling. + */ +typedef struct SCProfileSghData_ { + uint64_t checks; + + uint64_t non_mpm_generic; + uint64_t non_mpm_syn; + + uint64_t post_prefilter_sigs_total; + uint64_t post_prefilter_sigs_max; + + uint64_t mpm_match_cnt_total; + uint64_t mpm_match_cnt_max; + +} SCProfileSghData; + +typedef struct SCProfileSghDetectCtx_ { + uint32_t cnt; + SCProfileSghData *data; + pthread_mutex_t data_m; +} SCProfileSghDetectCtx; + +static int profiling_sghs_output_to_file = 0; +int profiling_sghs_enabled = 0; +static char *profiling_file_name = ""; +static const char *profiling_file_mode = "a"; +static int profiling_rulegroup_json = 0; + +void SCProfilingSghsGlobalInit(void) +{ + ConfNode *conf; + + conf = ConfGetNode("profiling.rulegroups"); + if (conf != NULL) { + if (ConfNodeChildValueIsTrue(conf, "enabled")) { + profiling_sghs_enabled = 1; + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename != NULL) { + + char *log_dir; + log_dir = ConfigGetLogDirectory(); + + profiling_file_name = SCMalloc(PATH_MAX); + if (unlikely(profiling_file_name == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); + exit(EXIT_FAILURE); + } + snprintf(profiling_file_name, PATH_MAX, "%s/%s", log_dir, filename); + + const char *v = ConfNodeLookupChildValue(conf, "append"); + if (v == NULL || ConfValIsTrue(v)) { + profiling_file_mode = "a"; + } else { + profiling_file_mode = "w"; + } + + profiling_sghs_output_to_file = 1; + } + if (ConfNodeChildValueIsTrue(conf, "json")) { +#ifdef HAVE_LIBJANSSON + profiling_rulegroup_json = 1; +#else + SCLogWarning(SC_ERR_NO_JSON_SUPPORT, "no json support compiled in, using plain output"); +#endif + } + } + } +} + +#ifdef HAVE_LIBJANSSON +static void DoDumpJSON(SCProfileSghDetectCtx *rules_ctx, FILE *fp, const char *name) +{ + char timebuf[64]; + uint32_t i; + struct timeval tval; + + json_t *js = json_object(); + if (js == NULL) + return; + json_t *jsa = json_array(); + if (jsa == NULL) { + json_decref(js); + return; + } + + gettimeofday(&tval, NULL); + CreateIsoTimeString(&tval, timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); + + for (i = 0; i < rules_ctx->cnt; i++) { + SCProfileSghData *d = &rules_ctx->data[i]; + if (d == NULL || d->checks == 0) + continue; + + double avgsigs = 0; + double avgmpms = 0; + + if (d->post_prefilter_sigs_total && d->checks) { + avgsigs = (double)((double)d->post_prefilter_sigs_total / (double)d->checks); + } + if (d->mpm_match_cnt_total && d->checks) { + avgmpms = (double)((double)d->mpm_match_cnt_total / (double)d->checks); + } + + json_t *jsm = json_object(); + if (jsm) { + json_object_set_new(jsm, "id", json_integer(i)); + json_object_set_new(jsm, "checks", json_integer(d->checks)); + json_object_set_new(jsm, "non_mpm_generic", json_integer(d->non_mpm_generic)); + json_object_set_new(jsm, "non_mpm_syn", json_integer(d->non_mpm_syn)); + json_object_set_new(jsm, "avgmpms", json_real(avgmpms)); + json_object_set_new(jsm, "mpm_match_cnt_max", json_integer(d->mpm_match_cnt_max)); + json_object_set_new(jsm, "avgsigs", json_real(avgsigs)); + json_object_set_new(jsm, "post_prefilter_sigs_max", json_integer(d->post_prefilter_sigs_max)); + json_array_append_new(jsa, jsm); + } + } + json_object_set_new(js, "rule_groups", jsa); + + char *js_s = json_dumps(js, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| + JSON_ESCAPE_SLASH); + if (likely(js_s != NULL)) { + fprintf(fp, "%s", js_s); + free(js_s); + } + json_decref(js); +} +#endif /* HAVE_LIBJANSSON */ + +static void DoDump(SCProfileSghDetectCtx *rules_ctx, FILE *fp, const char *name) +{ + uint32_t i; + struct timeval tval; + struct tm *tms; + struct tm local_tm; + + gettimeofday(&tval, NULL); + tms = SCLocalTime(tval.tv_sec, &local_tm); + + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, + tms->tm_hour,tms->tm_min, tms->tm_sec); + + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " Stats for: %s %u\n", name, rules_ctx->cnt); + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " %-16s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Sgh", "Checks", "Non-MPM(gen)", "Non-Mpm(syn)", "MPM Matches", "MPM Match Max", "Post-Filter", "Post-Filter Max"); + fprintf(fp, " ---------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "\n"); + for (i = 0; i < rules_ctx->cnt; i++) { + SCProfileSghData *d = &rules_ctx->data[i]; + if (d == NULL || d->checks == 0) + continue; + + double avgsigs = 0; + double avgmpms = 0; + + if (d->post_prefilter_sigs_total && d->checks) { + avgsigs = (double)((double)d->post_prefilter_sigs_total / (double)d->checks); + } + if (d->mpm_match_cnt_total && d->checks) { + avgmpms = (double)((double)d->mpm_match_cnt_total / (double)d->checks); + } + + fprintf(fp, + " %-16u %-15"PRIu64" %-15"PRIu64" %-15"PRIu64" %-15.2f %-15"PRIu64" %-15.2f %-15"PRIu64"\n", + i, + d->checks, + d->non_mpm_generic, + d->non_mpm_syn, + avgmpms, + d->mpm_match_cnt_max, + avgsigs, + d->post_prefilter_sigs_max); + } + fprintf(fp,"\n"); +} + +void +SCProfilingSghDump(DetectEngineCtx *de_ctx) +{ + FILE *fp; + + if (profiling_sghs_enabled == 0) + return; + + if (profiling_sghs_output_to_file == 1) { + SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode); + + fp = fopen(profiling_file_name, profiling_file_mode); + + if (fp == NULL) { + SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", profiling_file_name, + strerror(errno)); + return; + } + } else { + fp = stdout; + } + +#ifdef HAVE_LIBJANSSON + if (profiling_rulegroup_json) { + DoDumpJSON(de_ctx->profile_sgh_ctx, fp, "rule groups"); + } else +#endif + { + DoDump(de_ctx->profile_sgh_ctx, fp, "rule groups"); + } + + if (fp != stdout) + fclose(fp); + + SCLogInfo("Done dumping rulegroup profiling data."); +} + +/** + * \brief Update a rule counter. + * + * \param id The ID of this counter. + * \param ticks Number of CPU ticks for this rule. + * \param match Did the rule match? + */ +void +SCProfilingSghUpdateCounter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh) +{ + if (det_ctx != NULL && det_ctx->sgh_perf_data != NULL && sgh->id < det_ctx->de_ctx->sgh_array_cnt) { + SCProfileSghData *p = &det_ctx->sgh_perf_data[sgh->id]; + p->checks++; + + if (det_ctx->non_mpm_store_cnt > 0) { + if (det_ctx->non_mpm_store_ptr == sgh->non_mpm_syn_store_array) + p->non_mpm_syn++; + else + p->non_mpm_generic++; + } + p->post_prefilter_sigs_total += det_ctx->match_array_cnt; + if (det_ctx->match_array_cnt > p->post_prefilter_sigs_max) + p->post_prefilter_sigs_max = det_ctx->match_array_cnt; + p->mpm_match_cnt_total += det_ctx->pmq.rule_id_array_cnt; + if (det_ctx->pmq.rule_id_array_cnt > p->mpm_match_cnt_max) + p->mpm_match_cnt_max = det_ctx->pmq.rule_id_array_cnt; + } +} + +SCProfileSghDetectCtx *SCProfilingSghInitCtx(void) +{ + SCProfileSghDetectCtx *ctx = SCCalloc(1, sizeof(SCProfileSghDetectCtx)); + if (ctx != NULL) { + if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { + SCLogError(SC_ERR_MUTEX, + "Failed to initialize mutex."); + exit(EXIT_FAILURE); + } + } + + return ctx; +} + +static void DetroyCtx(SCProfileSghDetectCtx *ctx) +{ + if (ctx) { + if (ctx->data != NULL) + SCFree(ctx->data); + pthread_mutex_destroy(&ctx->data_m); + SCFree(ctx); + } +} + +void SCProfilingSghDestroyCtx(DetectEngineCtx *de_ctx) +{ + if (de_ctx != NULL) { + SCProfilingSghDump(de_ctx); + + DetroyCtx(de_ctx->profile_sgh_ctx); + } +} + +void SCProfilingSghThreadSetup(SCProfileSghDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) +{ + if (ctx == NULL) + return; + + uint32_t array_size = det_ctx->de_ctx->sgh_array_cnt; + + SCProfileSghData *a = SCCalloc(array_size, sizeof(SCProfileSghData)); + if (a != NULL) { + det_ctx->sgh_perf_data = a; + } +} + +static void SCProfilingSghThreadMerge(DetectEngineCtx *de_ctx, const DetectEngineThreadCtx *det_ctx) +{ + if (de_ctx == NULL || de_ctx->profile_sgh_ctx == NULL || + de_ctx->profile_sgh_ctx->data == NULL || det_ctx == NULL || + det_ctx->sgh_perf_data == NULL) + return; + +#define ADD(name) de_ctx->profile_sgh_ctx->data[i].name += det_ctx->sgh_perf_data[i].name + uint32_t i; + for (i = 0; i < de_ctx->sgh_array_cnt; i++) { + ADD(checks); + ADD(non_mpm_generic); + ADD(non_mpm_syn); + ADD(post_prefilter_sigs_total); + ADD(mpm_match_cnt_total); + + if (det_ctx->sgh_perf_data[i].mpm_match_cnt_max > de_ctx->profile_sgh_ctx->data[i].mpm_match_cnt_max) + de_ctx->profile_sgh_ctx->data[i].mpm_match_cnt_max = det_ctx->sgh_perf_data[i].mpm_match_cnt_max; + if (det_ctx->sgh_perf_data[i].post_prefilter_sigs_max > de_ctx->profile_sgh_ctx->data[i].post_prefilter_sigs_max) + de_ctx->profile_sgh_ctx->data[i].post_prefilter_sigs_max = det_ctx->sgh_perf_data[i].post_prefilter_sigs_max; + } +#undef ADD +} + +void SCProfilingSghThreadCleanup(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->sgh_perf_data == NULL) + return; + + pthread_mutex_lock(&det_ctx->de_ctx->profile_sgh_ctx->data_m); + SCProfilingSghThreadMerge(det_ctx->de_ctx, det_ctx); + pthread_mutex_unlock(&det_ctx->de_ctx->profile_sgh_ctx->data_m); + + SCFree(det_ctx->sgh_perf_data); + det_ctx->sgh_perf_data = NULL; +} + +/** + * \brief Register the keyword profiling counters. + * + * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. + */ +void +SCProfilingSghInitCounters(DetectEngineCtx *de_ctx) +{ + if (profiling_sghs_enabled == 0) + return; + + de_ctx->profile_sgh_ctx = SCProfilingSghInitCtx(); + BUG_ON(de_ctx->profile_sgh_ctx == NULL); + + de_ctx->profile_sgh_ctx->data = SCCalloc(de_ctx->sgh_array_cnt, sizeof(SCProfileSghData)); + BUG_ON(de_ctx->profile_sgh_ctx->data == NULL); + + de_ctx->profile_sgh_ctx->cnt = de_ctx->sgh_array_cnt; + + SCLogInfo("Registered %"PRIu32" rulegroup profiling counters.", de_ctx->sgh_array_cnt); +} + +#endif /* PROFILING */ diff --git a/src/util-profiling.h b/src/util-profiling.h index 763d8414ae60..cc7ea0270071 100644 --- a/src/util-profiling.h +++ b/src/util-profiling.h @@ -32,6 +32,7 @@ extern int profiling_rules_enabled; extern int profiling_packets_enabled; +extern int profiling_sghs_enabled; extern __thread int profiling_rules_entered; void SCProfilingPrintPacketProfile(Packet *); @@ -229,6 +230,11 @@ PktProfiling *SCProfilePacketStart(void); } \ } +#define SGH_PROFILING_RECORD(det_ctx, sgh) \ + if (profiling_sghs_enabled) { \ + SCProfilingSghUpdateCounter((det_ctx), (sgh)); \ + } + void SCProfilingRulesGlobalInit(void); void SCProfilingRuleDestroyCtx(struct SCProfileDetectCtx_ *); @@ -244,6 +250,13 @@ void SCProfilingKeywordUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uin void SCProfilingKeywordThreadSetup(struct SCProfileKeywordDetectCtx_ *, DetectEngineThreadCtx *); void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *); +void SCProfilingSghsGlobalInit(void); +void SCProfilingSghDestroyCtx(DetectEngineCtx *); +void SCProfilingSghInitCounters(DetectEngineCtx *); +void SCProfilingSghUpdateCounter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh); +void SCProfilingSghThreadSetup(struct SCProfileSghDetectCtx_ *, DetectEngineThreadCtx *); +void SCProfilingSghThreadCleanup(DetectEngineThreadCtx *); + void SCProfilingInit(void); void SCProfilingDestroy(void); void SCProfilingRegisterTests(void); @@ -277,6 +290,8 @@ void SCProfilingDump(void); #define PACKET_PROFILING_DETECT_START(p, id) #define PACKET_PROFILING_DETECT_END(p, id) +#define SGH_PROFILING_RECORD(det_ctx, sgh) + #endif /* PROFILING */ #endif /* ! __UTIL_PROFILE_H__ */ diff --git a/suricata.yaml.in b/suricata.yaml.in index 152f2e757db5..368ee3408c5d 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1497,6 +1497,12 @@ profiling: filename: keyword_perf.log append: yes + # per rulegroup profiling + rulegroups: + enabled: yes + filename: rule_group_perf.log + append: yes + # packet profiling packets: From 92c571b26d4518ad630117a06990d80f92dfb4f6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 1 Mar 2016 17:42:40 +0100 Subject: [PATCH 1198/2553] detect: move sm_list to string funcs to parser code --- src/detect-parse.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++ src/detect-parse.h | 3 ++ src/detect.c | 79 ---------------------------------------------- 3 files changed, 82 insertions(+), 79 deletions(-) diff --git a/src/detect-parse.c b/src/detect-parse.c index c392ba3fd1b0..45982587679e 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -140,6 +140,85 @@ typedef struct SignatureParser_ { char opts[DETECT_MAX_RULE_SIZE]; } SignatureParser; +const char *DetectListToHumanString(int list) +{ +#define CASE_CODE_STRING(E, S) case E: return S; break + switch (list) { + CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); + CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); + CASE_CODE_STRING(DETECT_SM_LIST_UMATCH, "http_uri"); + CASE_CODE_STRING(DETECT_SM_LIST_HRUDMATCH, "http_raw_uri"); + CASE_CODE_STRING(DETECT_SM_LIST_HCBDMATCH, "http_client_body"); + CASE_CODE_STRING(DETECT_SM_LIST_FILEDATA, "file_data"); + CASE_CODE_STRING(DETECT_SM_LIST_HHDMATCH, "http_header"); + CASE_CODE_STRING(DETECT_SM_LIST_HRHDMATCH, "http_raw_header"); + CASE_CODE_STRING(DETECT_SM_LIST_HSMDMATCH, "http_stat_msg"); + CASE_CODE_STRING(DETECT_SM_LIST_HSCDMATCH, "http_stat_code"); + CASE_CODE_STRING(DETECT_SM_LIST_HHHDMATCH, "http_host"); + CASE_CODE_STRING(DETECT_SM_LIST_HRHHDMATCH, "http_raw_host"); + CASE_CODE_STRING(DETECT_SM_LIST_HMDMATCH, "http_method"); + CASE_CODE_STRING(DETECT_SM_LIST_HCDMATCH, "http_cookie"); + CASE_CODE_STRING(DETECT_SM_LIST_HUADMATCH, "http_user_agent"); + CASE_CODE_STRING(DETECT_SM_LIST_HRLMATCH, "http_request_line"); + CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); + CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); + CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); + CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); + CASE_CODE_STRING(DETECT_SM_LIST_FILEMATCH, "file"); + CASE_CODE_STRING(DETECT_SM_LIST_DNSREQUEST_MATCH, "dns_request"); + CASE_CODE_STRING(DETECT_SM_LIST_DNSRESPONSE_MATCH, "dns_response"); + CASE_CODE_STRING(DETECT_SM_LIST_DNSQUERYNAME_MATCH, "dns_query"); + CASE_CODE_STRING(DETECT_SM_LIST_MODBUS_MATCH, "modbus"); + CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); + CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); + CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress"); + CASE_CODE_STRING(DETECT_SM_LIST_THRESHOLD, "threshold"); + CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)"); + CASE_CODE_STRING(DETECT_SM_LIST_NOTSET, "not set (internal)"); + } +#undef CASE_CODE_STRING + return "unknown"; +} + +#define CASE_CODE(E) case E: return #E +const char *DetectListToString(int list) +{ + switch (list) { + CASE_CODE(DETECT_SM_LIST_MATCH); + CASE_CODE(DETECT_SM_LIST_PMATCH); + CASE_CODE(DETECT_SM_LIST_UMATCH); + CASE_CODE(DETECT_SM_LIST_HRUDMATCH); + CASE_CODE(DETECT_SM_LIST_HCBDMATCH); + CASE_CODE(DETECT_SM_LIST_FILEDATA); + CASE_CODE(DETECT_SM_LIST_HHDMATCH); + CASE_CODE(DETECT_SM_LIST_HRHDMATCH); + CASE_CODE(DETECT_SM_LIST_HSMDMATCH); + CASE_CODE(DETECT_SM_LIST_HSCDMATCH); + CASE_CODE(DETECT_SM_LIST_HHHDMATCH); + CASE_CODE(DETECT_SM_LIST_HRHHDMATCH); + CASE_CODE(DETECT_SM_LIST_HMDMATCH); + CASE_CODE(DETECT_SM_LIST_HCDMATCH); + CASE_CODE(DETECT_SM_LIST_HUADMATCH); + CASE_CODE(DETECT_SM_LIST_HRLMATCH); + CASE_CODE(DETECT_SM_LIST_APP_EVENT); + CASE_CODE(DETECT_SM_LIST_AMATCH); + CASE_CODE(DETECT_SM_LIST_DMATCH); + CASE_CODE(DETECT_SM_LIST_TMATCH); + CASE_CODE(DETECT_SM_LIST_FILEMATCH); + CASE_CODE(DETECT_SM_LIST_DNSREQUEST_MATCH); + CASE_CODE(DETECT_SM_LIST_DNSRESPONSE_MATCH); + CASE_CODE(DETECT_SM_LIST_DNSQUERYNAME_MATCH); + CASE_CODE(DETECT_SM_LIST_MODBUS_MATCH); + CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); + CASE_CODE(DETECT_SM_LIST_POSTMATCH); + CASE_CODE(DETECT_SM_LIST_SUPPRESS); + CASE_CODE(DETECT_SM_LIST_THRESHOLD); + CASE_CODE(DETECT_SM_LIST_MAX); + CASE_CODE(DETECT_SM_LIST_NOTSET); + } + return "unknown"; +} + int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg, uint8_t sm_type, uint8_t sm_list, AppProto alproto, void (*CustomCallback)(Signature *s)) diff --git a/src/detect-parse.h b/src/detect-parse.h index 5c13e4c99834..cb2ae0f3b37d 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -64,5 +64,8 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s uint8_t sm_type, uint8_t sm_list, AppProto alproto, void (*CustomCallback)(Signature *s)); +const char *DetectListToHumanString(int list); +const char *DetectListToString(int list); + #endif /* __DETECT_PARSE_H__ */ diff --git a/src/detect.c b/src/detect.c index 90699debd4fb..49bd118c3749 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2835,85 +2835,6 @@ static void SigParseApplyDsizeToContent(Signature *s) } } -const char *DetectListToHumanString(int list) -{ -#define CASE_CODE_STRING(E, S) case E: return S; break - switch (list) { - CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); - CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); - CASE_CODE_STRING(DETECT_SM_LIST_UMATCH, "http_uri"); - CASE_CODE_STRING(DETECT_SM_LIST_HRUDMATCH, "http_raw_uri"); - CASE_CODE_STRING(DETECT_SM_LIST_HCBDMATCH, "http_client_body"); - CASE_CODE_STRING(DETECT_SM_LIST_FILEDATA, "file_data"); - CASE_CODE_STRING(DETECT_SM_LIST_HHDMATCH, "http_header"); - CASE_CODE_STRING(DETECT_SM_LIST_HRHDMATCH, "http_raw_header"); - CASE_CODE_STRING(DETECT_SM_LIST_HSMDMATCH, "http_stat_msg"); - CASE_CODE_STRING(DETECT_SM_LIST_HSCDMATCH, "http_stat_code"); - CASE_CODE_STRING(DETECT_SM_LIST_HHHDMATCH, "http_host"); - CASE_CODE_STRING(DETECT_SM_LIST_HRHHDMATCH, "http_raw_host"); - CASE_CODE_STRING(DETECT_SM_LIST_HMDMATCH, "http_method"); - CASE_CODE_STRING(DETECT_SM_LIST_HCDMATCH, "http_cookie"); - CASE_CODE_STRING(DETECT_SM_LIST_HUADMATCH, "http_user_agent"); - CASE_CODE_STRING(DETECT_SM_LIST_HRLMATCH, "http_request_line"); - CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); - CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); - CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); - CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); - CASE_CODE_STRING(DETECT_SM_LIST_FILEMATCH, "file"); - CASE_CODE_STRING(DETECT_SM_LIST_DNSREQUEST_MATCH, "dns_request"); - CASE_CODE_STRING(DETECT_SM_LIST_DNSRESPONSE_MATCH, "dns_response"); - CASE_CODE_STRING(DETECT_SM_LIST_DNSQUERYNAME_MATCH, "dns_query"); - CASE_CODE_STRING(DETECT_SM_LIST_MODBUS_MATCH, "modbus"); - CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); - CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); - CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress"); - CASE_CODE_STRING(DETECT_SM_LIST_THRESHOLD, "threshold"); - CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)"); - CASE_CODE_STRING(DETECT_SM_LIST_NOTSET, "not set (internal)"); - } -#undef CASE_CODE_STRING - return "unknown"; -} - -#define CASE_CODE(E) case E: return #E -const char *DetectListToString(int list) -{ - switch (list) { - CASE_CODE(DETECT_SM_LIST_MATCH); - CASE_CODE(DETECT_SM_LIST_PMATCH); - CASE_CODE(DETECT_SM_LIST_UMATCH); - CASE_CODE(DETECT_SM_LIST_HRUDMATCH); - CASE_CODE(DETECT_SM_LIST_HCBDMATCH); - CASE_CODE(DETECT_SM_LIST_FILEDATA); - CASE_CODE(DETECT_SM_LIST_HHDMATCH); - CASE_CODE(DETECT_SM_LIST_HRHDMATCH); - CASE_CODE(DETECT_SM_LIST_HSMDMATCH); - CASE_CODE(DETECT_SM_LIST_HSCDMATCH); - CASE_CODE(DETECT_SM_LIST_HHHDMATCH); - CASE_CODE(DETECT_SM_LIST_HRHHDMATCH); - CASE_CODE(DETECT_SM_LIST_HMDMATCH); - CASE_CODE(DETECT_SM_LIST_HCDMATCH); - CASE_CODE(DETECT_SM_LIST_HUADMATCH); - CASE_CODE(DETECT_SM_LIST_HRLMATCH); - CASE_CODE(DETECT_SM_LIST_APP_EVENT); - CASE_CODE(DETECT_SM_LIST_AMATCH); - CASE_CODE(DETECT_SM_LIST_DMATCH); - CASE_CODE(DETECT_SM_LIST_TMATCH); - CASE_CODE(DETECT_SM_LIST_FILEMATCH); - CASE_CODE(DETECT_SM_LIST_DNSREQUEST_MATCH); - CASE_CODE(DETECT_SM_LIST_DNSRESPONSE_MATCH); - CASE_CODE(DETECT_SM_LIST_DNSQUERYNAME_MATCH); - CASE_CODE(DETECT_SM_LIST_MODBUS_MATCH); - CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); - CASE_CODE(DETECT_SM_LIST_POSTMATCH); - CASE_CODE(DETECT_SM_LIST_SUPPRESS); - CASE_CODE(DETECT_SM_LIST_THRESHOLD); - CASE_CODE(DETECT_SM_LIST_MAX); - CASE_CODE(DETECT_SM_LIST_NOTSET); - } - return "unknown"; -} - /** \brief Pure-PCRE or bytetest rule */ int RuleInspectsPayloadHasNoMpm(const Signature *s) { From caea596ce5682fadcb113a6a7c8ab4a2bc15a1b2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Oct 2015 17:39:57 +0200 Subject: [PATCH 1199/2553] profiling: output post-prefilter matches Dump a json record containing all sigs that need to be inspected after prefilter. Part of profiling. Only dump if threshold is met, which is currently set by: --set detect.profiling.inspect-logging-threshold=200 A file called packet_inspected_rules.json is created in the default log dir. --- src/Makefile.am | 1 + src/detect-engine-profile.c | 136 ++++++++++++++++++++++++++++++++++++ src/detect-engine-profile.h | 29 ++++++++ src/detect-engine.c | 5 ++ src/detect.c | 7 +- src/detect.h | 1 + suricata.yaml.in | 7 ++ 7 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 src/detect-engine-profile.c create mode 100644 src/detect-engine-profile.h diff --git a/src/Makefile.am b/src/Makefile.am index c3c7c679c116..4d0490a1f3f3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -121,6 +121,7 @@ detect-engine-mpm.c detect-engine-mpm.h \ detect-engine-payload.c detect-engine-payload.h \ detect-engine-port.c detect-engine-port.h \ detect-engine-proto.c detect-engine-proto.h \ +detect-engine-profile.c detect-engine-profile.h \ detect-engine-siggroup.c detect-engine-siggroup.h \ detect-engine-sigorder.c detect-engine-sigorder.h \ detect-engine-state.c detect-engine-state.h \ diff --git a/src/detect-engine-profile.c b/src/detect-engine-profile.c new file mode 100644 index 000000000000..f5127657236d --- /dev/null +++ b/src/detect-engine-profile.c @@ -0,0 +1,136 @@ +/* Copyright (C) 2016 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 + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-content.h" +#include "output-json.h" +#include "util-buffer.h" +#include "util-print.h" + +#ifdef PROFILING +static void DumpFp(const SigMatch *sm, char *pat_orig, uint32_t pat_orig_sz, char *pat_chop, uint32_t pat_chop_sz) +{ + int fast_pattern_chop_set = 0; + const DetectContentData *cd = (DetectContentData *)sm->ctx; + + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + fast_pattern_chop_set = 1; + } + } + + uint32_t off = 0; + PrintRawUriBuf(pat_orig, &off, pat_orig_sz, cd->content, cd->content_len); + + if (fast_pattern_chop_set) { + off = 0; + PrintRawUriBuf(pat_chop, &off, pat_chop_sz, cd->content + cd->fp_chop_offset, cd->fp_chop_len); + } +} + +SCMutex g_rule_dump_write_m = SCMUTEX_INITIALIZER; +void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, const Packet *p) +{ + json_t *js = CreateJSONHeader(p, 0, "inspectedrules"); + if (js == NULL) + return; + json_t *ir = json_object(); + if (ir == NULL) + return; + + json_object_set_new(ir, "rule_group_id", json_integer(det_ctx->sgh->id)); + json_object_set_new(ir, "rule_cnt", json_integer(det_ctx->match_array_cnt)); + + json_t *js_array = json_array(); + uint32_t x; + for (x = 0; x < det_ctx->match_array_cnt; x++) + { + const Signature *s = det_ctx->match_array[x]; + if (s == NULL) + continue; + + json_t *js_sig = json_object(); + if (unlikely(js == NULL)) + continue; + json_object_set_new(js_sig, "sig_id", json_integer(s->id)); + + json_object_set_new(js_sig, "mpm", (s->mpm_sm != NULL) ? json_true() : json_false()); + + if (s->mpm_sm != NULL) { + char orig[256] = ""; + char chop[256] = ""; + + DumpFp(s->mpm_sm, orig, sizeof(orig), chop, sizeof(chop)); + + json_object_set_new(js_sig, "mpm_buffer", json_string(DetectListToHumanString(SigMatchListSMBelongsTo(s, s->mpm_sm)))); + json_object_set_new(js_sig, "mpm_pattern", json_string(orig)); + + if (strlen(chop) > 0) { + json_object_set_new(js_sig, "mpm_pattern_chop", json_string(chop)); + } + } + json_array_append_new(js_array, js_sig); + } + + json_object_set_new(ir, "rules", js_array); + json_object_set_new(js, "inspectedrules", ir); + + const char *filename = "packet_inspected_rules.json"; + const char *log_dir = ConfigGetLogDirectory(); + char log_path[PATH_MAX] = ""; + snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename); + + MemBuffer *mbuf = NULL; + mbuf = MemBufferCreateNew(4096); + BUG_ON(mbuf == NULL); + + OutputJSONMemBufferWrapper wrapper = { + .buffer = &mbuf, + .expand_by = 4096, + }; + + int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| + JSON_ESCAPE_SLASH); + if (r != 0) { + SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object"); + } else { + MemBufferWriteString(mbuf, "\n"); + SCMutexLock(&g_rule_dump_write_m); + FILE *fp = fopen(log_path, "a"); + if (fp != NULL) { + MemBufferPrintToFPAsString(mbuf, fp); + fclose(fp); + SCMutexUnlock(&g_rule_dump_write_m); + } + } + + MemBufferFree(mbuf); + json_object_clear(js); + json_decref(js); +} +#endif /* PROFILING */ diff --git a/src/detect-engine-profile.h b/src/detect-engine-profile.h new file mode 100644 index 000000000000..d7ed1c93ea74 --- /dev/null +++ b/src/detect-engine-profile.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2016 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 + */ + +#ifndef _DETECT_ENGINE_PROFILE_H +#define _DETECT_ENGINE_PROFILE_H + +void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, const Packet *p); + +#endif /* _DETECT_ENGINE_PROFILE_H */ diff --git a/src/detect-engine.c b/src/detect-engine.c index c293a2ea8122..e9e9ecec5aad 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -881,6 +881,11 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) #ifdef PROFILING SCProfilingKeywordInitCounters(de_ctx); + de_ctx->profile_match_logging_threshold = UINT_MAX; // disabled + + intmax_t v = 0; + if (ConfGetInt("detect.profiling.inspect-logging-threshold", &v) == 1) + de_ctx->profile_match_logging_threshold = (uint32_t)v; #endif SCClassConfLoadClassficationConfigFile(de_ctx, NULL); diff --git a/src/detect.c b/src/detect.c index 49bd118c3749..bdf85559a1e3 100644 --- a/src/detect.c +++ b/src/detect.c @@ -33,6 +33,7 @@ #include "detect-parse.h" #include "detect-engine.h" +#include "detect-engine-profile.h" #include "detect-engine-alert.h" #include "detect-engine-siggroup.h" @@ -201,7 +202,6 @@ #include "util-optimize.h" #include "util-path.h" #include "util-mpm-ac.h" - #include "runmodes.h" #include @@ -1540,6 +1540,11 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SGH_PROFILING_RECORD(det_ctx, det_ctx->sgh); +#ifdef PROFILING + if (match_cnt >= de_ctx->profile_match_logging_threshold) + RulesDumpMatchArray(det_ctx, p); +#endif + uint32_t sflags, next_sflags = 0; if (match_cnt) { next_s = *match_array++; diff --git a/src/detect.h b/src/detect.h index f70493f3cb4c..beb4aca097bf 100644 --- a/src/detect.h +++ b/src/detect.h @@ -661,6 +661,7 @@ typedef struct DetectEngineCtx_ { struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx; struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; struct SCProfileSghDetectCtx_ *profile_sgh_ctx; + uint32_t profile_match_logging_threshold; #endif char config_prefix[64]; diff --git a/suricata.yaml.in b/suricata.yaml.in index 368ee3408c5d..59c4d8e161f3 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -608,6 +608,13 @@ detect-engine: # is started. This will limit the downtime in IPS mode. #- delayed-detect: yes + profiling: + # Log the rules that made it past the prefilter stage, per packet + # default is off. The threshold setting determines how many rules + # must have made it past pre-filter for that rule to trigger the + # logging. + #inspect-logging-threshold: 200 + # Suricata is multi-threaded. Here the threading can be influenced. threading: # On some cpu's/architectures it is beneficial to tie individual threads From eb19fc4c7bbcc00e781dd5fe2ed1f74f13bd9671 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 20 Oct 2015 10:49:10 +0200 Subject: [PATCH 1200/2553] mpm: remove unused structure --- src/util-mpm.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/util-mpm.h b/src/util-mpm.h index 2cf85e59804b..e8256b4ba5cd 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -52,10 +52,6 @@ enum { /* Internal Pattern Index: 0 to pattern_cnt-1 */ typedef uint32_t MpmPatternIndex; -typedef struct MpmMatchBucket_ { - uint32_t len; -} MpmMatchBucket; - typedef struct MpmThreadCtx_ { void *ctx; From e57e7d1b961e77f5d8cec28adfcbb24ebf8ec50c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 20 Oct 2015 10:55:41 +0200 Subject: [PATCH 1201/2553] mpm: cleanup, remove unused structs and prototypes --- src/detect-engine-mpm.h | 5 ----- src/detect.h | 12 ------------ 2 files changed, 17 deletions(-) diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 3f88c164127d..de687876a3f7 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -74,11 +74,6 @@ TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *); void DbgPrintSearchStats(); -MpmPatternIdStore *MpmPatternIdTableInitHash(void); -void MpmPatternIdTableFreeHash(MpmPatternIdStore *); -uint32_t MpmPatternIdStoreGetMaxId(MpmPatternIdStore *); -uint32_t DetectContentGetId(MpmPatternIdStore *, DetectContentData *); - int SignatureHasPacketContent(const Signature *); int SignatureHasStreamContent(const Signature *); diff --git a/src/detect.h b/src/detect.h index beb4aca097bf..765a870aa23e 100644 --- a/src/detect.h +++ b/src/detect.h @@ -515,15 +515,6 @@ typedef struct DetectEngineLookupFlow_ { */ #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 */ @@ -606,9 +597,6 @@ typedef struct DetectEngineCtx_ { /* 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; uint32_t max_fp_id; MpmCtxFactoryContainer *mpm_ctx_factory_container; From 6bb2b001a33e542f840dfef0e1b0d01db86f0d15 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 20 Oct 2015 17:49:32 +0200 Subject: [PATCH 1202/2553] mpm: cleanup: move mpm funcs into buffer specific files --- src/detect-dns-query.c | 35 -- src/detect-engine-dns.c | 63 ++++ src/detect-engine-filedata-smtp.c | 30 ++ src/detect-engine-hcbd.c | 28 ++ src/detect-engine-hcd.c | 33 ++ src/detect-engine-hhd.c | 34 ++ src/detect-engine-hhhd.c | 28 ++ src/detect-engine-hmd.c | 27 ++ src/detect-engine-hrhd.c | 33 ++ src/detect-engine-hrhhd.c | 28 ++ src/detect-engine-hrud.c | 27 ++ src/detect-engine-hsbd.c | 28 ++ src/detect-engine-hscd.c | 27 ++ src/detect-engine-hsmd.c | 27 ++ src/detect-engine-hua.c | 27 ++ src/detect-engine-mpm.c | 546 ------------------------------ src/detect-engine-mpm.h | 14 - src/detect-engine-payload.c | 134 ++++++++ src/detect-engine-uri.c | 93 +++++ src/detect-uricontent.c | 66 ---- 20 files changed, 667 insertions(+), 661 deletions(-) diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 55742f8982fc..63babd8f136a 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -98,41 +98,6 @@ static int DetectDnsQuerySetup(DetectEngineCtx *de_ctx, Signature *s, char *str) return 0; } -/** - * \brief Run the pattern matcher against the queries - * - * \param f locked flow - * \param dns_state initialized dns state - * - * \warning Make sure the flow/state is locked - * \todo what should we return? Just the fact that we matched? - */ -uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - DNSState *dns_state, uint8_t flags, void *txv, - uint64_t tx_id) -{ - SCEnter(); - - DNSTransaction *tx = (DNSTransaction *)txv; - DNSQueryEntry *query = NULL; - uint8_t *buffer; - uint16_t buffer_len; - uint32_t cnt = 0; - - TAILQ_FOREACH(query, &tx->query_list, next) { - SCLogDebug("tx %p query %p", tx, query); - - buffer = (uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)); - buffer_len = query->len; - - cnt += DnsQueryPatternSearch(det_ctx, - buffer, buffer_len, - flags); - } - - SCReturnUInt(cnt); -} - #ifdef UNITTESTS /** \test simple google.com query matching */ static int DetectDnsQueryTest01(void) diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index b08681c01e95..3efb848f01e1 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -44,6 +44,7 @@ #include "util-unittest.h" #include "util-unittest-helper.h" +#include "util-validate.h" /** \brief Do the content inspection & validation for a signature * @@ -93,6 +94,68 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, return r; } +/** + * \brief DNS query match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param hrh Buffer to inspect. + * \param hrh_len buffer length. + * \param flags Flags + * + * \retval ret Number of matches. + */ +static uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *buffer, uint32_t buffer_len, + uint8_t flags) +{ + SCEnter(); + + uint32_t ret = 0; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_dnsquery_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_dnsquery_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); + + SCReturnUInt(ret); +} + +/** + * \brief Run the pattern matcher against the queries + * + * \param f locked flow + * \param dns_state initialized dns state + * + * \warning Make sure the flow/state is locked + * \todo what should we return? Just the fact that we matched? + */ +uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, + DNSState *dns_state, uint8_t flags, void *txv, + uint64_t tx_id) +{ + SCEnter(); + + DNSTransaction *tx = (DNSTransaction *)txv; + DNSQueryEntry *query = NULL; + uint8_t *buffer; + uint16_t buffer_len; + uint32_t cnt = 0; + + TAILQ_FOREACH(query, &tx->query_list, next) { + SCLogDebug("tx %p query %p", tx, query); + + buffer = (uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)); + buffer_len = query->len; + + cnt += DnsQueryPatternSearch(det_ctx, + buffer, buffer_len, + flags); + } + + SCReturnUInt(cnt); +} /** \brief Do the content inspection & validation for a signature * diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index f037dfec7a1a..8b2f5caead6e 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -49,6 +49,8 @@ #include "app-layer-protos.h" #include "app-layer-parser.h" +#include "util-validate.h" + #include "conf.h" #include "conf-yaml-loader.h" @@ -269,6 +271,34 @@ void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx) return; } +/** + * \brief SMTP Filedata match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param buffer Buffer to inspect. + * \param buffer_len buffer length. + * \param flags Flags + * + * \retval ret Number of matches. + */ +static uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *buffer, uint32_t buffer_len, + uint8_t flags) +{ + SCEnter(); + + uint32_t ret = 0; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_smtp_filedata_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_smtp_filedata_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_smtp_filedata_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); + + SCReturnUInt(ret); +} + int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, SMTPState *smtp_state, uint8_t flags, diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 09b7980a1c37..28ebfe584fa9 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -60,6 +60,8 @@ #include "conf.h" #include "conf-yaml-loader.h" +#include "util-validate.h" + #define BUFFER_STEP 50 static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) @@ -219,6 +221,32 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return buffer; } +/** \brief Http client body pattern match -- searches for one pattern per + * signature. + * + * \param det_ctx Detection engine thread ctx. + * \param body The request body to inspect. + * \param body_len Body length. + * + * \retval ret Number of matches. + */ +static uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *body, uint32_t body_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcbd_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hcbd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, body, body_len); + + SCReturnUInt(ret); +} + int DetectEngineRunHttpClientBodyMpm(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index 5fcfa51fd368..432266e706b4 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -56,6 +56,39 @@ #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" + +/** + * \brief Http cookie match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param cookie Cookie to inspect. + * \param cookie_len Cookie length. + * + * \retval ret Number of matches. + */ +static uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *cookie, uint32_t cookie_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + if (flags & STREAM_TOSERVER) { + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcd_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hcd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, cookie, cookie_len); + } else { + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcd_ctx_tc == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hcd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, cookie, cookie_len); + } + + SCReturnUInt(ret); +} int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 3bec4fd2f2ea..0656b112af89 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -58,6 +58,8 @@ #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" + #define BUFFER_STEP 50 static inline int HHDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) @@ -212,6 +214,38 @@ static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return headers_buffer; } +/** + * \brief Http header match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param headers Headers to inspect. + * \param headers_len Headers length. + * + * \retval ret Number of matches. + */ +static uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *headers, uint32_t headers_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + if (flags & STREAM_TOSERVER) { + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhd_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hhd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, headers, headers_len); + } else { + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhd_ctx_tc == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hhd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, headers, headers_len); + } + + SCReturnUInt(ret); +} + int DetectEngineRunHttpHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, void *tx, uint64_t idx) diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 65aebd070acd..0882d16d1a3a 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -58,6 +58,34 @@ #include "app-layer-protos.h" #include "detect-engine-hhhd.h" +#include "util-validate.h" + +/** + * \brief Http host header match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param hh Host header to inspect. + * \param hh_len Host header buffer length. + * \param flags Flags + * + * \retval ret Number of matches. + */ +static uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *hh, uint32_t hh_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhhd_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hhhd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, hh, hh_len); + + SCReturnUInt(ret); +} int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 5a4b7d8ad149..f80e279a3997 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -56,6 +56,33 @@ #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" + +/** + * \brief Http method match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param method Method to inspect. + * \param method_len Method length. + * + * \retval ret Number of matches. + */ +static uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *raw_method, uint32_t raw_method_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hmd_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hmd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, raw_method, raw_method_len); + + SCReturnUInt(ret); +} int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 90cf1d5e907d..54618a3df19b 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -57,6 +57,39 @@ #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" + +/** + * \brief Http raw header match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param headers Raw headers to inspect. + * \param headers_len Raw headers length. + * + * \retval ret Number of matches. + */ +static uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *raw_headers, uint32_t raw_headers_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + if (flags & STREAM_TOSERVER) { + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhd_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hrhd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, raw_headers, raw_headers_len); + } else { + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhd_ctx_tc == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hrhd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, raw_headers, raw_headers_len); + } + + SCReturnUInt(ret); +} int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index f1acf100189b..732226c46861 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -58,6 +58,34 @@ #include "app-layer-protos.h" #include "detect-engine-hrhhd.h" +#include "util-validate.h" + +/** + * \brief Http raw host header match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param hrh Raw hostname to inspect. + * \param hrh_len Raw hostname buffer length. + * \param flags Flags + * + * \retval ret Number of matches. + */ +static uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *hrh, uint32_t hrh_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hrhhd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, hrh, hrh_len); + + SCReturnUInt(ret); +} int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 585c736b6db8..4249cccc3a5a 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -56,6 +56,33 @@ #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" + +/** + * \brief Http raw uri match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param uri Raw uri to inspect. + * \param uri_len Raw uri length. + * + * \retval ret Number of matches. + */ +static uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *uri, uint32_t uri_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrud_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hrud_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, uri, uri_len); + + SCReturnUInt(ret); +} /** * \brief Run the mpm against raw http uris. diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 7d52c7d8f683..401296e38d2f 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -62,6 +62,8 @@ #include "conf.h" #include "conf-yaml-loader.h" +#include "util-validate.h" + #define BUFFER_STEP 50 static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) @@ -313,6 +315,32 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return buffer; } +/** \brief Http server body pattern match -- searches for one pattern per + * signature. + * + * \param det_ctx Detection engine thread ctx. + * \param body The request body to inspect. + * \param body_len Body length. + * + * \retval ret Number of matches. + */ +static uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *body, uint32_t body_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + + DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsbd_ctx_tc == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hsbd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, body, body_len); + + SCReturnUInt(ret); +} + int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index a38562b1932b..6fd938d184a1 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -53,6 +53,33 @@ #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" + +/** + * \brief Http stat code match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param stat_code Stat code to inspect. + * \param stat_code_len Stat code length. + * + * \retval ret Number of matches. + */ +static uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *stat_code, uint32_t stat_code_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + + DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hscd_ctx_tc == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hscd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, stat_code, stat_code_len); + + SCReturnUInt(ret); +} /** * \brief Run the mpm against http stat code. diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 61c8e2e9b5f3..9017ebfd55d8 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -53,6 +53,33 @@ #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" + +/** + * \brief Http stat msg match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param stat_msg Stat msg to inspect. + * \param stat_msg_len Stat msg length. + * + * \retval ret Number of matches. + */ +static uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *stat_msg, uint32_t stat_msg_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + + DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsmd_ctx_tc == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hsmd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, stat_msg, stat_msg_len); + + SCReturnUInt(ret); +} /** * \brief Run the mpm against http stat msg. diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index 8cafa423af3a..27e1383f0f96 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -57,6 +57,33 @@ #include "app-layer-protos.h" #include "detect-engine-hua.h" +#include "util-validate.h" + +/** + * \brief Http user agent match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param cookie User-Agent to inspect. + * \param cookie_len User-Agent buffer length. + * + * \retval ret Number of matches. + */ +static uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *ua, uint32_t ua_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_huad_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, ua, ua_len); + + SCReturnUInt(ret); +} int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 9a8a8bd6f985..04f455e38b77 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -55,9 +55,6 @@ #include "util-debug.h" #include "util-print.h" #include "util-memcmp.h" -#ifdef __SC_CUDA_SUPPORT__ -#include "util-mpm-ac.h" -#endif #include "util-validate.h" const char *builtin_mpms[] = { @@ -253,549 +250,6 @@ uint16_t PatternMatchDefaultMatcher(void) return mpm_algo_val; } -uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, - Packet *p) -{ - SCEnter(); - - uint32_t ret = 0; - const MpmCtx *mpm_ctx = NULL; - - if (p->flowflags & FLOW_PKT_TOSERVER) { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_ts == NULL); - - mpm_ctx = det_ctx->sgh->mpm_stream_ctx_ts; - - } else { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_tc == NULL); - - mpm_ctx = det_ctx->sgh->mpm_stream_ctx_tc; - } - if (unlikely(mpm_ctx == NULL)) { - SCReturnInt(0); - } - - ret = mpm_table[mpm_ctx->mpm_type]. - Search(mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, - p->payload, p->payload_len); - - SCReturnInt(ret); -} - -/** \brief Pattern match -- searches for only one pattern per signature. - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * - * \retval ret number of matches - */ -uint32_t PacketPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p) -{ - SCEnter(); - - uint32_t ret; - const MpmCtx *mpm_ctx = NULL; - - if (p->proto == IPPROTO_TCP) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - mpm_ctx = det_ctx->sgh->mpm_proto_tcp_ctx_ts; - } else { - mpm_ctx = det_ctx->sgh->mpm_proto_tcp_ctx_tc; - } - } else if (p->proto == IPPROTO_UDP) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - mpm_ctx = det_ctx->sgh->mpm_proto_udp_ctx_ts; - } else { - mpm_ctx = det_ctx->sgh->mpm_proto_udp_ctx_tc; - } - } else { - mpm_ctx = det_ctx->sgh->mpm_proto_other_ctx; - } - if (unlikely(mpm_ctx == NULL)) - SCReturnInt(0); - -#ifdef __SC_CUDA_SUPPORT__ - if (p->cuda_pkt_vars.cuda_mpm_enabled && p->pkt_src == PKT_SRC_WIRE) { - ret = SCACCudaPacketResultsProcessing(p, mpm_ctx, &det_ctx->pmq); - } else { - ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtc, - &det_ctx->pmq, - p->payload, - p->payload_len); - } -#else - ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtc, - &det_ctx->pmq, - p->payload, - p->payload_len); -#endif - - SCReturnInt(ret); -} - -/** \brief Uri Pattern match -- searches for one pattern per signature. - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * - * \retval ret number of matches - */ -uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *uri, uint16_t uri_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_uri_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_uri_ctx_ts, - &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); - - //PrintRawDataFp(stdout, uri, uri_len); - - SCReturnUInt(ret); -} - -/** \brief Http client body pattern match -- searches for one pattern per - * signature. - * - * \param det_ctx Detection engine thread ctx. - * \param body The request body to inspect. - * \param body_len Body length. - * - * \retval ret Number of matches. - */ -uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *body, uint32_t body_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcbd_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hcbd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, body, body_len); - - SCReturnUInt(ret); -} - -/** \brief Http server body pattern match -- searches for one pattern per - * signature. - * - * \param det_ctx Detection engine thread ctx. - * \param body The request body to inspect. - * \param body_len Body length. - * - * \retval ret Number of matches. - */ -uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *body, uint32_t body_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - - DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsbd_ctx_tc == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hsbd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, body, body_len); - - SCReturnUInt(ret); -} - -/** - * \brief Http header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param headers Headers to inspect. - * \param headers_len Headers length. - * - * \retval ret Number of matches. - */ -uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *headers, uint32_t headers_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhd_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, headers, headers_len); - } else { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhd_ctx_tc == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hhd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, headers, headers_len); - } - - SCReturnUInt(ret); -} - -/** - * \brief Http raw header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param headers Raw headers to inspect. - * \param headers_len Raw headers length. - * - * \retval ret Number of matches. - */ -uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *raw_headers, uint32_t raw_headers_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhd_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, raw_headers, raw_headers_len); - } else { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhd_ctx_tc == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hrhd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, raw_headers, raw_headers_len); - } - - SCReturnUInt(ret); -} - -/** - * \brief Http method match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param method Method to inspect. - * \param method_len Method length. - * - * \retval ret Number of matches. - */ -uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *raw_method, uint32_t raw_method_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hmd_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hmd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, raw_method, raw_method_len); - - SCReturnUInt(ret); -} - -/** - * \brief Http cookie match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param cookie Cookie to inspect. - * \param cookie_len Cookie length. - * - * \retval ret Number of matches. - */ -uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *cookie, uint32_t cookie_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcd_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hcd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, cookie, cookie_len); - } else { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcd_ctx_tc == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hcd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, cookie, cookie_len); - } - - SCReturnUInt(ret); -} - -/** - * \brief Http raw uri match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param uri Raw uri to inspect. - * \param uri_len Raw uri length. - * - * \retval ret Number of matches. - */ -uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *uri, uint32_t uri_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrud_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrud_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, uri, uri_len); - - SCReturnUInt(ret); -} - -/** - * \brief Http stat msg match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param stat_msg Stat msg to inspect. - * \param stat_msg_len Stat msg length. - * - * \retval ret Number of matches. - */ -uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *stat_msg, uint32_t stat_msg_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - - DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsmd_ctx_tc == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hsmd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, stat_msg, stat_msg_len); - - SCReturnUInt(ret); -} - -/** - * \brief Http stat code match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param stat_code Stat code to inspect. - * \param stat_code_len Stat code length. - * - * \retval ret Number of matches. - */ -uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *stat_code, uint32_t stat_code_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - - DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hscd_ctx_tc == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hscd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, stat_code, stat_code_len); - - SCReturnUInt(ret); -} - -/** - * \brief Http user agent match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param cookie User-Agent to inspect. - * \param cookie_len User-Agent buffer length. - * - * \retval ret Number of matches. - */ -uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *ua, uint32_t ua_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_huad_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, ua, ua_len); - - SCReturnUInt(ret); -} - -/** - * \brief Http host header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param hh Host header to inspect. - * \param hh_len Host header buffer length. - * \param flags Flags - * - * \retval ret Number of matches. - */ -uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *hh, uint32_t hh_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhhd_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hhhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, hh, hh_len); - - SCReturnUInt(ret); -} - -/** - * \brief Http raw host header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param hrh Raw hostname to inspect. - * \param hrh_len Raw hostname buffer length. - * \param flags Flags - * - * \retval ret Number of matches. - */ -uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *hrh, uint32_t hrh_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrhhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, hrh, hrh_len); - - SCReturnUInt(ret); -} - -/** - * \brief DNS query match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param hrh Buffer to inspect. - * \param hrh_len buffer length. - * \param flags Flags - * - * \retval ret Number of matches. - */ -uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *buffer, uint32_t buffer_len, - uint8_t flags) -{ - SCEnter(); - - uint32_t ret = 0; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_dnsquery_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_dnsquery_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); - - SCReturnUInt(ret); -} - -/** \brief Pattern match -- searches for only one pattern per signature. - * - * \param det_ctx detection engine thread ctx - * \param p packet - * \param smsg stream msg (reassembled stream data) - * \param flags stream flags - * - * \retval ret number of matches - */ -uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p, - StreamMsg *smsg, uint8_t flags) -{ - SCEnter(); - - uint32_t ret = 0; - uint8_t cnt = 0; - - //PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); - - uint32_t r; - if (flags & STREAM_TOSERVER) { - for ( ; smsg != NULL; smsg = smsg->next) { - r = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtcs, - &det_ctx->pmq, smsg->data, smsg->data_len); - if (r > 0) { - ret += r; - } - - cnt++; - } - } else { - for ( ; smsg != NULL; smsg = smsg->next) { - r = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtcs, - &det_ctx->pmq, smsg->data, smsg->data_len); - if (r > 0) { - ret += r; - } - - cnt++; - } - } - - SCReturnInt(ret); -} - -/** - * \brief SMTP Filedata match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param buffer Buffer to inspect. - * \param buffer_len buffer length. - * \param flags Flags - * - * \retval ret Number of matches. - */ -uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *buffer, uint32_t buffer_len, - uint8_t flags) -{ - SCEnter(); - - uint32_t ret = 0; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_smtp_filedata_ctx_ts == NULL); - - ret = mpm_table[det_ctx->sgh->mpm_smtp_filedata_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_smtp_filedata_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); - - SCReturnUInt(ret); -} - /** \brief cleans up the mpm instance after a match */ void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) { diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index de687876a3f7..4bb7fe31a53c 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -40,22 +40,8 @@ uint16_t PatternMatchDefaultMatcher(void); uint32_t PatternStrength(uint8_t *, uint16_t); uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *, Packet *); uint32_t PacketPatternSearch(DetectEngineThreadCtx *, Packet *); -uint32_t UriPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint16_t, uint8_t); uint32_t StreamPatternSearch(DetectEngineThreadCtx *, Packet *, StreamMsg *, uint8_t); -uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *buffer, uint32_t buffer_len, uint8_t flags); -uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *buffer, uint32_t buffer_len, uint8_t flags); void PacketPatternCleanup(ThreadVars *, DetectEngineThreadCtx *); diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index 9b21085de40c..f952deafd0fa 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -33,11 +33,145 @@ #include "detect-parse.h" #include "detect-engine-content-inspection.h" +#include "stream.h" + #include "util-debug.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" +#include "util-validate.h" + +#include "util-mpm-ac.h" + +uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, + Packet *p) +{ + SCEnter(); + + uint32_t ret = 0; + const MpmCtx *mpm_ctx = NULL; + + if (p->flowflags & FLOW_PKT_TOSERVER) { + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_ts == NULL); + + mpm_ctx = det_ctx->sgh->mpm_stream_ctx_ts; + + } else { + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_tc == NULL); + + mpm_ctx = det_ctx->sgh->mpm_stream_ctx_tc; + } + if (unlikely(mpm_ctx == NULL)) { + SCReturnInt(0); + } + + ret = mpm_table[mpm_ctx->mpm_type]. + Search(mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, + p->payload, p->payload_len); + + SCReturnInt(ret); +} + +/** \brief Pattern match -- searches for only one pattern per signature. + * + * \param det_ctx detection engine thread ctx + * \param p packet + * \param smsg stream msg (reassembled stream data) + * \param flags stream flags + * + * \retval ret number of matches + */ +uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p, + StreamMsg *smsg, uint8_t flags) +{ + SCEnter(); + + uint32_t ret = 0; + uint8_t cnt = 0; + + //PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); + + uint32_t r; + if (flags & STREAM_TOSERVER) { + for ( ; smsg != NULL; smsg = smsg->next) { + r = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtcs, + &det_ctx->pmq, smsg->data, smsg->data_len); + if (r > 0) { + ret += r; + } + + cnt++; + } + } else if (flags & STREAM_TOCLIENT) { + for ( ; smsg != NULL; smsg = smsg->next) { + r = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtcs, + &det_ctx->pmq, smsg->data, smsg->data_len); + if (r > 0) { + ret += r; + } + + cnt++; + } + } + + SCReturnInt(ret); +} + +/** \brief Pattern match -- searches for only one pattern per signature. + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * + * \retval ret number of matches + */ +uint32_t PacketPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p) +{ + SCEnter(); + + uint32_t ret; + const MpmCtx *mpm_ctx = NULL; + + if (p->proto == IPPROTO_TCP) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + mpm_ctx = det_ctx->sgh->mpm_proto_tcp_ctx_ts; + } else if (p->flowflags & FLOW_PKT_TOCLIENT) { + mpm_ctx = det_ctx->sgh->mpm_proto_tcp_ctx_tc; + } + } else if (p->proto == IPPROTO_UDP) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + mpm_ctx = det_ctx->sgh->mpm_proto_udp_ctx_ts; + } else if (p->flowflags & FLOW_PKT_TOCLIENT) { + mpm_ctx = det_ctx->sgh->mpm_proto_udp_ctx_tc; + } + } else { + mpm_ctx = det_ctx->sgh->mpm_proto_other_ctx; + } + if (unlikely(mpm_ctx == NULL)) + SCReturnInt(0); + +#ifdef __SC_CUDA_SUPPORT__ + if (p->cuda_pkt_vars.cuda_mpm_enabled && p->pkt_src == PKT_SRC_WIRE) { + ret = SCACCudaPacketResultsProcessing(p, mpm_ctx, &det_ctx->pmq); + } else { + ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtc, + &det_ctx->pmq, + p->payload, + p->payload_len); + } +#else + ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtc, + &det_ctx->pmq, + p->payload, + p->payload_len); +#endif + + SCReturnInt(ret); +} /** * \brief Do the content inspection & validation for a signature diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index 500272150e1c..f8ace30a3aba 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -47,6 +47,99 @@ #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" + +/** \brief Uri Pattern match -- searches for one pattern per signature. + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * + * \retval ret number of matches + */ +static uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *uri, uint16_t uri_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_uri_ctx_ts == NULL); + + ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_uri_ctx_ts, + &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); + + //PrintRawDataFp(stdout, uri, uri_len); + + SCReturnUInt(ret); +} + +/** + * \brief Checks if the content sent as the argument, has a uricontent which + * has been provided in the rule. This match function matches the + * normalized http uri against the given rule using multi pattern + * search algorithms. + * + * \param det_ctx Pointer to the detection engine thread context + * \param content Pointer to the uri content currently being matched + * \param content_len Content_len of the received uri content + * + * \retval 1 if the uri contents match; 0 no match + */ +static inline int DoDetectAppLayerUricontentMatch (DetectEngineThreadCtx *det_ctx, + uint8_t *uri, uint16_t uri_len, uint8_t flags) +{ + int ret = 0; + /* run the pattern matcher against the uri */ + if (det_ctx->sgh->mpm_uricontent_minlen > uri_len) { + SCLogDebug("not searching as uri len is smaller than the " + "shortest uricontent length we need to match"); + } else { + SCLogDebug("search: (%p, minlen %" PRIu32 ", sgh->sig_cnt " + "%" PRIu32 ")", det_ctx->sgh, + det_ctx->sgh->mpm_uricontent_minlen, det_ctx->sgh->sig_cnt); + + ret += UriPatternSearch(det_ctx, uri, uri_len, flags); + + SCLogDebug("post search: cnt %" PRIu32, ret); + } + return ret; +} + +/** + * \brief Run the pattern matcher against the uri(s) + * + * We run against _all_ uri(s) we have as the pattern matcher will + * flag each sig that has a match. We need to do this for all uri(s) + * to not miss possible events. + * + * \param f locked flow + * \param htp_state initialized htp state + * + * \warning Make sure the flow/state is locked + * \todo what should we return? Just the fact that we matched? + */ +uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, + HtpState *htp_state, uint8_t flags, + void *txv, uint64_t idx) +{ + SCEnter(); + + htp_tx_t *tx = (htp_tx_t *)txv; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + uint32_t cnt = 0; + + if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) + goto end; + cnt = DoDetectAppLayerUricontentMatch(det_ctx, (uint8_t *) + bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized), + flags); + +end: + SCReturnUInt(cnt); +} /** * \brief Do the content inspection & validation for a signature diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index dbc30cb627fe..b6927d205b8d 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -190,72 +190,6 @@ int DetectUricontentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentst SCReturnInt(-1); } -/** - * \brief Checks if the content sent as the argument, has a uricontent which - * has been provided in the rule. This match function matches the - * normalized http uri against the given rule using multi pattern - * search algorithms. - * - * \param det_ctx Pointer to the detection engine thread context - * \param content Pointer to the uri content currently being matched - * \param content_len Content_len of the received uri content - * - * \retval 1 if the uri contents match; 0 no match - */ -static inline int DoDetectAppLayerUricontentMatch (DetectEngineThreadCtx *det_ctx, - uint8_t *uri, uint16_t uri_len, uint8_t flags) -{ - int ret = 0; - /* run the pattern matcher against the uri */ - if (det_ctx->sgh->mpm_uricontent_minlen > uri_len) { - SCLogDebug("not searching as uri len is smaller than the " - "shortest uricontent length we need to match"); - } else { - SCLogDebug("search: (%p, minlen %" PRIu32 ", sgh->sig_cnt " - "%" PRIu32 ")", det_ctx->sgh, - det_ctx->sgh->mpm_uricontent_minlen, det_ctx->sgh->sig_cnt); - - ret += UriPatternSearch(det_ctx, uri, uri_len, flags); - - SCLogDebug("post search: cnt %" PRIu32, ret); - } - return ret; -} - -/** - * \brief Run the pattern matcher against the uri(s) - * - * We run against _all_ uri(s) we have as the pattern matcher will - * flag each sig that has a match. We need to do this for all uri(s) - * to not miss possible events. - * - * \param f locked flow - * \param htp_state initialized htp state - * - * \warning Make sure the flow/state is locked - * \todo what should we return? Just the fact that we matched? - */ -uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) -{ - SCEnter(); - - htp_tx_t *tx = (htp_tx_t *)txv; - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - uint32_t cnt = 0; - - if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) - goto end; - cnt = DoDetectAppLayerUricontentMatch(det_ctx, (uint8_t *) - bstr_ptr(tx_ud->request_uri_normalized), - bstr_len(tx_ud->request_uri_normalized), - flags); - -end: - SCReturnUInt(cnt); -} - /* * UNITTTESTS */ From 58576605682c5f0863fb8e2150db498e17fbf5b3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Oct 2015 07:36:48 +0200 Subject: [PATCH 1203/2553] http_uri: mpm cleanup. Use mpm_ctx's minlen --- src/detect-engine-uri.c | 53 ++++++++++------------------------------- src/detect.c | 3 --- src/detect.h | 1 - 3 files changed, 12 insertions(+), 45 deletions(-) diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index f8ace30a3aba..72a9a037bfc3 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -57,56 +57,27 @@ * \retval ret number of matches */ static uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *uri, uint16_t uri_len, uint8_t flags) + const uint8_t *uri, const uint16_t uri_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_uri_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_uri_ctx_ts, - &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); + if (uri_len >= det_ctx->sgh->mpm_uri_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_uri_ctx_ts, + &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); + } //PrintRawDataFp(stdout, uri, uri_len); SCReturnUInt(ret); } -/** - * \brief Checks if the content sent as the argument, has a uricontent which - * has been provided in the rule. This match function matches the - * normalized http uri against the given rule using multi pattern - * search algorithms. - * - * \param det_ctx Pointer to the detection engine thread context - * \param content Pointer to the uri content currently being matched - * \param content_len Content_len of the received uri content - * - * \retval 1 if the uri contents match; 0 no match - */ -static inline int DoDetectAppLayerUricontentMatch (DetectEngineThreadCtx *det_ctx, - uint8_t *uri, uint16_t uri_len, uint8_t flags) -{ - int ret = 0; - /* run the pattern matcher against the uri */ - if (det_ctx->sgh->mpm_uricontent_minlen > uri_len) { - SCLogDebug("not searching as uri len is smaller than the " - "shortest uricontent length we need to match"); - } else { - SCLogDebug("search: (%p, minlen %" PRIu32 ", sgh->sig_cnt " - "%" PRIu32 ")", det_ctx->sgh, - det_ctx->sgh->mpm_uricontent_minlen, det_ctx->sgh->sig_cnt); - - ret += UriPatternSearch(det_ctx, uri, uri_len, flags); - - SCLogDebug("post search: cnt %" PRIu32, ret); - } - return ret; -} - /** * \brief Run the pattern matcher against the uri(s) * @@ -132,10 +103,10 @@ uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) goto end; - cnt = DoDetectAppLayerUricontentMatch(det_ctx, (uint8_t *) - bstr_ptr(tx_ud->request_uri_normalized), - bstr_len(tx_ud->request_uri_normalized), - flags); + cnt = UriPatternSearch(det_ctx, (const uint8_t *) + bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized), + flags); end: SCReturnUInt(cnt); diff --git a/src/detect.c b/src/detect.c index bdf85559a1e3..2c8ff73351cf 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3998,9 +3998,6 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); SigGroupHeadBuildNonMpmArray(de_ctx, sgh); - sgh->mpm_uricontent_minlen = SigGroupHeadGetMinMpmSize(de_ctx, sgh, DETECT_SM_LIST_UMATCH); - SCLogDebug("http_uri content min mpm len: %u", sgh->mpm_uricontent_minlen); - sgh->id = idx; cnt++; } diff --git a/src/detect.h b/src/detect.h index 765a870aa23e..da3d1b88d73a 100644 --- a/src/detect.h +++ b/src/detect.h @@ -967,7 +967,6 @@ typedef struct SigGroupHead_ { /* track min pattern length for content. Used in grouping */ uint16_t mpm_content_minlen; - uint16_t mpm_uricontent_minlen; /**< len of shortest mpm pattern in sgh */ /* non mpm list excluding SYN rules */ uint32_t non_mpm_other_store_cnt; From e43c4f3ea2b9d72a58df6e4c4ada9057bcf01101 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Oct 2015 08:19:21 +0200 Subject: [PATCH 1204/2553] mpm: optimize calls For all mpm wrapper functions, check minlen vs the input buffer to see if we can bypass the mpm search. Next to this, make all the function inline. Also constify the input and do other minor cleanups. --- src/detect-engine-dns.c | 14 ++++++----- src/detect-engine-filedata-smtp.c | 14 ++++++----- src/detect-engine-hcbd.c | 15 ++++++----- src/detect-engine-hcd.c | 24 +++++++++++------- src/detect-engine-hhd.c | 24 +++++++++++------- src/detect-engine-hhhd.c | 21 +++++++++------- src/detect-engine-hmd.c | 19 ++++++++------ src/detect-engine-hrhd.c | 42 ++++++++++++++++++------------- src/detect-engine-hrhhd.c | 30 ++++++++++++---------- src/detect-engine-hrud.c | 19 ++++++++------ src/detect-engine-hsbd.c | 17 +++++++------ src/detect-engine-hscd.c | 20 ++++++++------- src/detect-engine-hsmd.c | 18 +++++++------ src/detect-engine-hua.c | 22 ++++++++-------- src/detect-engine-payload.c | 41 ++++++++++++++++-------------- src/detect-engine-uri.c | 6 ++--- 16 files changed, 199 insertions(+), 147 deletions(-) diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index 3efb848f01e1..915533f150d3 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -104,9 +104,9 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, * * \retval ret Number of matches. */ -static uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *buffer, uint32_t buffer_len, - uint8_t flags) +static inline uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *buffer, const uint32_t buffer_len, + const uint8_t flags) { SCEnter(); @@ -115,9 +115,11 @@ static uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_dnsquery_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_dnsquery_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); + if (buffer_len >= det_ctx->sgh->mpm_dnsquery_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_dnsquery_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_dnsquery_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); + } SCReturnUInt(ret); } diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 8b2f5caead6e..80fec628dcee 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -281,9 +281,9 @@ void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx) * * \retval ret Number of matches. */ -static uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *buffer, uint32_t buffer_len, - uint8_t flags) +static inline uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *buffer, const uint32_t buffer_len, + const uint8_t flags) { SCEnter(); @@ -292,9 +292,11 @@ static uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_smtp_filedata_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_smtp_filedata_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_smtp_filedata_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); + if (buffer_len >= det_ctx->sgh->mpm_smtp_filedata_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_smtp_filedata_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_smtp_filedata_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); + } SCReturnUInt(ret); } diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 28ebfe584fa9..42ef760aa2e8 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -230,19 +230,22 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, * * \retval ret Number of matches. */ -static uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *body, uint32_t body_len, uint8_t flags) +static inline uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *body, const uint32_t body_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcbd_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hcbd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, body, body_len); + if (body_len >= det_ctx->sgh->mpm_hcbd_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hcbd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, body, body_len); + } SCReturnUInt(ret); } diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index 432266e706b4..dfc97a9add6d 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -67,24 +67,30 @@ * * \retval ret Number of matches. */ -static uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *cookie, uint32_t cookie_len, uint8_t flags) +static inline uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *cookie, const uint32_t cookie_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; + if (flags & STREAM_TOSERVER) { DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcd_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hcd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, cookie, cookie_len); + if (cookie_len >= det_ctx->sgh->mpm_hcd_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hcd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, cookie, cookie_len); + } } else { DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcd_ctx_tc == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hcd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, cookie, cookie_len); + if (cookie_len >= det_ctx->sgh->mpm_hcd_ctx_tc->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hcd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, cookie, cookie_len); + } } SCReturnUInt(ret); diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 0656b112af89..acfae6f54b26 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -223,24 +223,30 @@ static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, * * \retval ret Number of matches. */ -static uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *headers, uint32_t headers_len, uint8_t flags) +static inline uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *headers, const uint32_t headers_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; + if (flags & STREAM_TOSERVER) { DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhd_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, headers, headers_len); + if (headers_len >= det_ctx->sgh->mpm_hhd_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hhd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, headers, headers_len); + } } else { DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhd_ctx_tc == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hhd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, headers, headers_len); + if (headers_len >= det_ctx->sgh->mpm_hhd_ctx_tc->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hhd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, headers, headers_len); + } } SCReturnUInt(ret); diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 0882d16d1a3a..e86debc2436d 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -70,19 +70,22 @@ * * \retval ret Number of matches. */ -static uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *hh, uint32_t hh_len, uint8_t flags) +static inline uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *hh, const uint32_t hh_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhhd_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hhhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, hh, hh_len); + if (hh_len >= det_ctx->sgh->mpm_hhhd_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hhhd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, hh, hh_len); + } SCReturnUInt(ret); } @@ -95,12 +98,12 @@ int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, htp_tx_t *tx = (htp_tx_t *)txv; if (tx->request_hostname == NULL) goto end; - uint8_t *hname = (uint8_t *)bstr_ptr(tx->request_hostname); + const uint8_t *hname = (const uint8_t *)bstr_ptr(tx->request_hostname); if (hname == NULL) goto end; - uint32_t hname_len = bstr_len(tx->request_hostname); + const uint32_t hname_len = bstr_len(tx->request_hostname); - cnt += HttpHHPatternSearch(det_ctx, hname, hname_len, flags); + cnt = HttpHHPatternSearch(det_ctx, hname, hname_len, flags); end: return cnt; diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index f80e279a3997..e4102868598b 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -67,19 +67,22 @@ * * \retval ret Number of matches. */ -static uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *raw_method, uint32_t raw_method_len, uint8_t flags) +static inline uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *raw_method, const uint32_t raw_method_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hmd_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hmd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, raw_method, raw_method_len); + if (raw_method_len >= det_ctx->sgh->mpm_hmd_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hmd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, raw_method, raw_method_len); + } SCReturnUInt(ret); } @@ -92,11 +95,11 @@ int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, Flow *f, htp_tx_t *tx = (htp_tx_t *)txv; if (tx->request_method == NULL) goto end; + cnt = HttpMethodPatternSearch(det_ctx, - (uint8_t *)bstr_ptr(tx->request_method), + (const uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method), flags); - end: return cnt; } diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 54618a3df19b..2dd26f2f234b 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -62,30 +62,36 @@ /** * \brief Http raw header match -- searches for one pattern per signature. * - * \param det_ctx Detection engine thread ctx. - * \param headers Raw headers to inspect. - * \param headers_len Raw headers length. + * \param det_ctx Detection engine thread ctx. + * \param raw_headers Raw headers to inspect. + * \param raw_headers_len Raw headers length. * * \retval ret Number of matches. */ -static uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *raw_headers, uint32_t raw_headers_len, uint8_t flags) +static inline uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *raw_headers, const uint32_t raw_headers_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; + if (flags & STREAM_TOSERVER) { DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhd_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, raw_headers, raw_headers_len); + if (raw_headers_len >= det_ctx->sgh->mpm_hrhd_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hrhd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, raw_headers, raw_headers_len); + } } else { DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhd_ctx_tc == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hrhd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, raw_headers, raw_headers_len); + if (raw_headers_len >= det_ctx->sgh->mpm_hrhd_ctx_tc->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hrhd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, raw_headers, raw_headers_len); + } } SCReturnUInt(ret); @@ -98,14 +104,16 @@ int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, SCEnter(); uint32_t cnt = 0; + htp_tx_t *tx = (htp_tx_t *)txv; HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - if (tx_ud == NULL) - SCReturnInt(cnt); + if (tx_ud == NULL) { + SCReturnInt(0); + } if (flags & STREAM_TOSERVER) { if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_REQUEST_HEADERS) - SCReturnInt(cnt); + SCReturnInt(0); if (tx_ud->request_headers_raw != NULL) { cnt = HttpRawHeaderPatternSearch(det_ctx, @@ -115,10 +123,10 @@ int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, } } else { if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_RESPONSE_HEADERS) - SCReturnInt(cnt); + SCReturnInt(0); if (tx_ud->response_headers_raw != NULL) { - cnt += HttpRawHeaderPatternSearch(det_ctx, + cnt = HttpRawHeaderPatternSearch(det_ctx, tx_ud->response_headers_raw, tx_ud->response_headers_raw_len, flags); diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index 732226c46861..bee6cd8eff8e 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -70,19 +70,22 @@ * * \retval ret Number of matches. */ -static uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *hrh, uint32_t hrh_len, uint8_t flags) +static inline uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *hrh, const uint32_t hrh_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrhhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, hrh, hrh_len); + if (hrh_len >= det_ctx->sgh->mpm_hrhhd_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hrhhd_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, hrh, hrh_len); + } SCReturnUInt(ret); } @@ -93,7 +96,7 @@ int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, { uint32_t cnt = 0; htp_tx_t *tx = (htp_tx_t *)txv; - uint8_t *hname = NULL; + const uint8_t *hname = NULL; uint32_t hname_len = 0; if (tx->parsed_uri == NULL || tx->parsed_uri->hostname == NULL) { @@ -102,21 +105,22 @@ int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, htp_header_t *h = NULL; h = (htp_header_t *)htp_table_get_c(tx->request_headers, "Host"); if (h != NULL) { - SCLogDebug("HTTP host header not present in this request"); - hname = (uint8_t *)bstr_ptr(h->value); - hname_len = bstr_len(h->value); + hname = (const uint8_t *)bstr_ptr(h->value); + if (hname != NULL) + hname_len = bstr_len(h->value); } else { + SCLogDebug("HTTP host header not present in this request"); goto end; } } else { hname = (uint8_t *)bstr_ptr(tx->parsed_uri->hostname); if (hname != NULL) hname_len = bstr_len(tx->parsed_uri->hostname); - else - goto end; } - cnt = HttpHRHPatternSearch(det_ctx, hname, hname_len, flags); + if (hname != NULL) { + cnt = HttpHRHPatternSearch(det_ctx, hname, hname_len, flags); + } end: return cnt; diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 4249cccc3a5a..e7b08cf5367c 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -67,19 +67,22 @@ * * \retval ret Number of matches. */ -static uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *uri, uint32_t uri_len, uint8_t flags) +static inline uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *uri, const uint32_t uri_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrud_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrud_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, uri, uri_len); + if (uri_len >= det_ctx->sgh->mpm_hrud_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_hrud_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, uri, uri_len); + } SCReturnUInt(ret); } @@ -99,10 +102,10 @@ int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, Flow *f, uint32_t cnt = 0; if (tx->request_uri == NULL) goto end; + cnt = HttpRawUriPatternSearch(det_ctx, - (uint8_t *)bstr_ptr(tx->request_uri), + (const uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri), flags); - end: SCReturnInt(cnt); } diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 401296e38d2f..93d9adee6d99 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -324,19 +324,22 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, * * \retval ret Number of matches. */ -static uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *body, uint32_t body_len, uint8_t flags) +static inline uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *body, const uint32_t body_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsbd_ctx_tc == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hsbd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, body, body_len); + if (body_len >= det_ctx->sgh->mpm_hsbd_ctx_tc->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hsbd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, body, body_len); + } SCReturnUInt(ret); } @@ -349,7 +352,7 @@ int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, uint32_t cnt = 0; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, idx, + const uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, idx, de_ctx, det_ctx, f, htp_state, flags, diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 6fd938d184a1..72df1c8d5f7f 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -64,19 +64,22 @@ * * \retval ret Number of matches. */ -static uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *stat_code, uint32_t stat_code_len, uint8_t flags) +static inline uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *stat_code, const uint32_t stat_code_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hscd_ctx_tc == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hscd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, stat_code, stat_code_len); + if (stat_code_len >= det_ctx->sgh->mpm_hscd_ctx_tc->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hscd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, stat_code, stat_code_len); + } SCReturnUInt(ret); } @@ -98,9 +101,8 @@ int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, Flow *f, goto end; cnt = HttpStatCodePatternSearch(det_ctx, - (uint8_t *)bstr_ptr(tx->response_status), - bstr_len(tx->response_status), flags); - + (const uint8_t *)bstr_ptr(tx->response_status), + bstr_len(tx->response_status), flags); end: SCReturnInt(cnt); } diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 9017ebfd55d8..3b8a0004d950 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -64,19 +64,22 @@ * * \retval ret Number of matches. */ -static uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *stat_msg, uint32_t stat_msg_len, uint8_t flags) +static inline uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *stat_msg, const uint32_t stat_msg_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsmd_ctx_tc == NULL); - ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hsmd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, stat_msg, stat_msg_len); + if (stat_msg_len >= det_ctx->sgh->mpm_hsmd_ctx_tc->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_hsmd_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, stat_msg, stat_msg_len); + } SCReturnUInt(ret); } @@ -98,9 +101,8 @@ int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, Flow *f, goto end; cnt = HttpStatMsgPatternSearch(det_ctx, - (uint8_t *)bstr_ptr(tx->response_message), + (const uint8_t *)bstr_ptr(tx->response_message), bstr_len(tx->response_message), flags); - end: SCReturnInt(cnt); } diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index 27e1383f0f96..a459776b6e25 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -63,24 +63,27 @@ * \brief Http user agent match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. - * \param cookie User-Agent to inspect. - * \param cookie_len User-Agent buffer length. + * \param ua User-Agent to inspect. + * \param ua_len User-Agent buffer length. * * \retval ret Number of matches. */ -static uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *ua, uint32_t ua_len, uint8_t flags) +static inline uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *ua, const uint32_t ua_len, + const uint8_t flags) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_huad_ctx_ts == NULL); - ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, ua, ua_len); + if (ua_len >= det_ctx->sgh->mpm_huad_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, ua, ua_len); + } SCReturnUInt(ret); } @@ -101,9 +104,8 @@ int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, Flow *f, goto end; } cnt = HttpUAPatternSearch(det_ctx, - (uint8_t *)bstr_ptr(h->value), + (const uint8_t *)bstr_ptr(h->value), bstr_len(h->value), flags); - end: return cnt; } diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index f952deafd0fa..ab63d16f86fc 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -66,9 +66,11 @@ uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, SCReturnInt(0); } - ret = mpm_table[mpm_ctx->mpm_type]. - Search(mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, - p->payload, p->payload_len); + if (p->payload_len >= mpm_ctx->minlen) { + ret = mpm_table[mpm_ctx->mpm_type]. + Search(mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, + p->payload, p->payload_len); + } SCReturnInt(ret); } @@ -88,32 +90,31 @@ uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p, SCEnter(); uint32_t ret = 0; - uint8_t cnt = 0; //PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); uint32_t r; if (flags & STREAM_TOSERVER) { for ( ; smsg != NULL; smsg = smsg->next) { - r = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtcs, - &det_ctx->pmq, smsg->data, smsg->data_len); - if (r > 0) { - ret += r; + if (smsg->data_len >= det_ctx->sgh->mpm_stream_ctx_ts->minlen) { + r = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtcs, + &det_ctx->pmq, smsg->data, smsg->data_len); + if (r > 0) { + ret += r; + } } - - cnt++; } } else if (flags & STREAM_TOCLIENT) { for ( ; smsg != NULL; smsg = smsg->next) { - r = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtcs, - &det_ctx->pmq, smsg->data, smsg->data_len); - if (r > 0) { - ret += r; + if (smsg->data_len >= det_ctx->sgh->mpm_stream_ctx_tc->minlen) { + r = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtcs, + &det_ctx->pmq, smsg->data, smsg->data_len); + if (r > 0) { + ret += r; + } } - - cnt++; } } @@ -131,7 +132,7 @@ uint32_t PacketPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p) { SCEnter(); - uint32_t ret; + uint32_t ret = 0; const MpmCtx *mpm_ctx = NULL; if (p->proto == IPPROTO_TCP) { @@ -151,6 +152,8 @@ uint32_t PacketPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p) } if (unlikely(mpm_ctx == NULL)) SCReturnInt(0); + if (p->payload_len < mpm_ctx->minlen) + SCReturnInt(0); #ifdef __SC_CUDA_SUPPORT__ if (p->cuda_pkt_vars.cuda_mpm_enabled && p->pkt_src == PKT_SRC_WIRE) { diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index 72a9a037bfc3..e88b8d7e234b 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -56,9 +56,9 @@ * * \retval ret number of matches */ -static uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *uri, const uint16_t uri_len, - const uint8_t flags) +static inline uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *uri, const uint16_t uri_len, + const uint8_t flags) { SCEnter(); From de273d88ccaf30bcf32e86b392e72534ddc6189c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Oct 2015 08:32:00 +0200 Subject: [PATCH 1205/2553] detect: remove unused content minlen tracking --- src/detect-engine-siggroup.c | 27 +-------------------------- src/detect.c | 4 ++-- src/detect.h | 3 --- 3 files changed, 3 insertions(+), 31 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 243cf6aeb7ef..18c36c6959db 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -224,7 +224,7 @@ uint32_t SigGroupHeadHashFunc(HashListTable *ht, void *data, uint16_t datalen) uint32_t hash = 0; uint32_t b = 0; - SCLogDebug("hashing sgh %p (mpm_content_minlen %u)", sgh, sgh->mpm_content_minlen); + SCLogDebug("hashing sgh %p", sgh); for (b = 0; b < sgh->init->sig_size; b++) hash += sgh->init->sig_array[b]; @@ -382,20 +382,6 @@ int SigGroupHeadAppendSig(const DetectEngineCtx *de_ctx, SigGroupHead **sgh, /* enable the sig in the bitarray */ (*sgh)->init->sig_array[s->num / 8] |= 1 << (s->num % 8); - /* update minlen for mpm */ - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { - /* check with the precalculated values from the sig */ - uint16_t mpm_content_minlen = SignatureGetMpmPatternLen(s, DETECT_SM_LIST_PMATCH); - if (mpm_content_minlen > 0) { - if ((*sgh)->mpm_content_minlen == 0) - (*sgh)->mpm_content_minlen = mpm_content_minlen; - - if ((*sgh)->mpm_content_minlen > mpm_content_minlen) - (*sgh)->mpm_content_minlen = mpm_content_minlen; - - SCLogDebug("(%p)->mpm_content_minlen %u", *sgh, (*sgh)->mpm_content_minlen); - } - } return 0; error: @@ -453,17 +439,6 @@ int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHea if (src->init->whitelist) (*dst)->init->whitelist = MAX((*dst)->init->whitelist, src->init->whitelist); - if (src->mpm_content_minlen != 0) { - if ((*dst)->mpm_content_minlen == 0) - (*dst)->mpm_content_minlen = src->mpm_content_minlen; - - if ((*dst)->mpm_content_minlen > src->mpm_content_minlen) - (*dst)->mpm_content_minlen = src->mpm_content_minlen; - - SCLogDebug("src (%p)->mpm_content_minlen %u", src, src->mpm_content_minlen); - SCLogDebug("dst (%p)->mpm_content_minlen %u", (*dst), (*dst)->mpm_content_minlen); - BUG_ON((*dst)->mpm_content_minlen == 0); - } return 0; error: diff --git a/src/detect.c b/src/detect.c index 2c8ff73351cf..223644708e2b 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1111,8 +1111,8 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_PACKET) { /* run the multi packet matcher against the payload of the packet */ - SCLogDebug("search: (%p, minlen %" PRIu32 ", sgh->sig_cnt %" PRIu32 ")", - det_ctx->sgh, det_ctx->sgh->mpm_content_minlen, det_ctx->sgh->sig_cnt); + SCLogDebug("search: (%p, sgh->sig_cnt %" PRIu32 ")", + det_ctx->sgh, det_ctx->sgh->sig_cnt); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_PACKET); PacketPatternSearch(det_ctx, p); diff --git a/src/detect.h b/src/detect.h index da3d1b88d73a..721cd8a29ac9 100644 --- a/src/detect.h +++ b/src/detect.h @@ -965,9 +965,6 @@ typedef struct SigGroupHead_ { /* number of sigs in this head */ SigIntId sig_cnt; - /* track min pattern length for content. Used in grouping */ - uint16_t mpm_content_minlen; - /* non mpm list excluding SYN rules */ uint32_t non_mpm_other_store_cnt; SignatureNonMpmStore *non_mpm_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) From af3bf3dc7a6580b6cdca273201eb82998715d94f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Oct 2015 08:35:24 +0200 Subject: [PATCH 1206/2553] detect: optimize sgh layout --- src/detect.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect.h b/src/detect.h index 721cd8a29ac9..808fd69820dc 100644 --- a/src/detect.h +++ b/src/detect.h @@ -967,10 +967,10 @@ typedef struct SigGroupHead_ { /* non mpm list excluding SYN rules */ uint32_t non_mpm_other_store_cnt; + uint32_t non_mpm_syn_store_cnt; SignatureNonMpmStore *non_mpm_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) /* non mpm list including SYN rules */ SignatureNonMpmStore *non_mpm_syn_store_array; // size is non_mpm_syn_store_cnt * sizeof(SignatureNonMpmStore) - uint32_t non_mpm_syn_store_cnt; /** the number of signatures in this sgh that have the filestore keyword * set. */ From 30755265ee4bbb424ce221e06dcb586ece0f8846 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Oct 2015 08:59:04 +0200 Subject: [PATCH 1207/2553] http_raw_header: improve mpm progress handling --- src/detect-engine-hrhd.c | 6 ------ src/detect.c | 16 +++++++++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 2dd26f2f234b..3756a104bdc9 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -112,9 +112,6 @@ int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, } if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_REQUEST_HEADERS) - SCReturnInt(0); - if (tx_ud->request_headers_raw != NULL) { cnt = HttpRawHeaderPatternSearch(det_ctx, tx_ud->request_headers_raw, @@ -122,9 +119,6 @@ int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, flags); } } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_RESPONSE_HEADERS) - SCReturnInt(0); - if (tx_ud->response_headers_raw != NULL) { cnt = HttpRawHeaderPatternSearch(det_ctx, tx_ud->response_headers_raw, diff --git a/src/detect.c b/src/detect.c index 223644708e2b..c9902f73f06e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -977,6 +977,9 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHD); } + } + + if (tx_progress > HTP_REQUEST_HEADERS) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHD); DetectEngineRunHttpRawHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); @@ -1013,11 +1016,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHD); } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHD); - DetectEngineRunHttpRawHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHD); - } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCD); DetectEngineRunHttpCookieMpm(det_ctx, p->flow, alstate, flags, tx, idx); @@ -1025,6 +1023,14 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } } + if (tx_progress > HTP_RESPONSE_HEADERS) { + if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHD) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHD); + DetectEngineRunHttpRawHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHD); + } + } + if (tx_progress >= HTP_RESPONSE_BODY) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSBD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSBD); From 87f3adbe4c25a3047acf40670eba151af49cbd78 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 26 Oct 2015 14:18:37 +0100 Subject: [PATCH 1208/2553] detect/mpm: unify packet/stream mpm_ctx pointers SGH's for tcp and udp are now always only per proto and per direction. This means we can simply reuse the packet and stream mpm pointers. The SGH's for the other protocols already used a directionless catch all mpm pointer. --- src/detect-engine-mpm.c | 67 +++++++++++++++---------------------- src/detect-engine-payload.c | 64 +++++++---------------------------- src/detect.h | 9 ++--- 3 files changed, 42 insertions(+), 98 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 04f455e38b77..0e1c7839c3cf 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -259,27 +259,9 @@ void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) return; /* content */ - if (det_ctx->sgh->mpm_proto_tcp_ctx_ts != NULL && - mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_ts->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_ts->mpm_type].Cleanup(&det_ctx->mtc); - } - if (det_ctx->sgh->mpm_proto_tcp_ctx_tc != NULL && - mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_tc->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_tc->mpm_type].Cleanup(&det_ctx->mtc); - } - - if (det_ctx->sgh->mpm_proto_udp_ctx_ts != NULL && - mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_ts->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_ts->mpm_type].Cleanup(&det_ctx->mtc); - } - if (det_ctx->sgh->mpm_proto_udp_ctx_tc != NULL && - mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_tc->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_tc->mpm_type].Cleanup(&det_ctx->mtc); - } - - if (det_ctx->sgh->mpm_proto_other_ctx != NULL && - mpm_table[det_ctx->sgh->mpm_proto_other_ctx->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_proto_other_ctx->mpm_type].Cleanup(&det_ctx->mtc); + if (det_ctx->sgh->mpm_packet_ctx != NULL && + mpm_table[det_ctx->sgh->mpm_packet_ctx->mpm_type].Cleanup != NULL) { + mpm_table[det_ctx->sgh->mpm_packet_ctx->mpm_type].Cleanup(&det_ctx->mtc); } /* uricontent */ @@ -288,11 +270,9 @@ void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) } /* stream content */ - if (det_ctx->sgh->mpm_stream_ctx_ts != NULL && mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type].Cleanup(&det_ctx->mtcs); - } - if (det_ctx->sgh->mpm_stream_ctx_tc != NULL && mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type].Cleanup(&det_ctx->mtcs); + if (det_ctx->sgh->mpm_stream_ctx != NULL && + mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type].Cleanup != NULL) { + mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type].Cleanup(&det_ctx->mtcs); } return; @@ -1136,31 +1116,35 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (SGH_DIRECTION_TS(sh)) { mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TS); if (mpm_store != NULL) { - sh->mpm_proto_tcp_ctx_ts = mpm_store->mpm_ctx; - if (sh->mpm_proto_tcp_ctx_ts) + BUG_ON(sh->mpm_packet_ctx); + sh->mpm_packet_ctx = mpm_store->mpm_ctx; + if (sh->mpm_packet_ctx) sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TS); if (mpm_store != NULL) { BUG_ON(mpm_store == NULL); - sh->mpm_stream_ctx_ts = mpm_store->mpm_ctx; - if (sh->mpm_stream_ctx_ts) + BUG_ON(sh->mpm_stream_ctx); + sh->mpm_stream_ctx = mpm_store->mpm_ctx; + if (sh->mpm_stream_ctx) sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; } } if (SGH_DIRECTION_TC(sh)) { mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TC); if (mpm_store != NULL) { - sh->mpm_proto_tcp_ctx_tc = mpm_store->mpm_ctx; - if (sh->mpm_proto_tcp_ctx_tc) + BUG_ON(sh->mpm_packet_ctx); + sh->mpm_packet_ctx = mpm_store->mpm_ctx; + if (sh->mpm_packet_ctx) sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TC); if (mpm_store != NULL) { - sh->mpm_stream_ctx_tc = mpm_store->mpm_ctx; - if (sh->mpm_stream_ctx_tc) + BUG_ON(sh->mpm_stream_ctx); + sh->mpm_stream_ctx = mpm_store->mpm_ctx; + if (sh->mpm_stream_ctx) sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; } } @@ -1169,27 +1153,30 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TS); if (mpm_store != NULL) { BUG_ON(mpm_store == NULL); - sh->mpm_proto_udp_ctx_ts = mpm_store->mpm_ctx; + BUG_ON(sh->mpm_packet_ctx); + sh->mpm_packet_ctx = mpm_store->mpm_ctx; - if (sh->mpm_proto_udp_ctx_ts != NULL) + if (sh->mpm_packet_ctx != NULL) sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } } if (SGH_DIRECTION_TC(sh)) { mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TC); if (mpm_store != NULL) { - sh->mpm_proto_udp_ctx_tc = mpm_store->mpm_ctx; + BUG_ON(sh->mpm_packet_ctx); + sh->mpm_packet_ctx = mpm_store->mpm_ctx; - if (sh->mpm_proto_udp_ctx_tc != NULL) + if (sh->mpm_packet_ctx != NULL) sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } } } else { mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_OTHERIP); if (mpm_store != NULL) { - sh->mpm_proto_other_ctx = mpm_store->mpm_ctx; + BUG_ON(sh->mpm_packet_ctx); + sh->mpm_packet_ctx = mpm_store->mpm_ctx; - if (sh->mpm_proto_other_ctx != NULL) + if (sh->mpm_packet_ctx != NULL) sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } } diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index ab63d16f86fc..f5cd077c6106 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -50,25 +50,14 @@ uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, SCEnter(); uint32_t ret = 0; - const MpmCtx *mpm_ctx = NULL; - - if (p->flowflags & FLOW_PKT_TOSERVER) { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_ts == NULL); - mpm_ctx = det_ctx->sgh->mpm_stream_ctx_ts; - - } else { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx_tc == NULL); - - mpm_ctx = det_ctx->sgh->mpm_stream_ctx_tc; - } - if (unlikely(mpm_ctx == NULL)) { + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx == NULL); + if (det_ctx->sgh->mpm_stream_ctx == NULL) SCReturnInt(0); - } - if (p->payload_len >= mpm_ctx->minlen) { - ret = mpm_table[mpm_ctx->mpm_type]. - Search(mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, + if (p->payload_len >= det_ctx->sgh->mpm_stream_ctx->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type]. + Search(det_ctx->sgh->mpm_stream_ctx, &det_ctx->mtc, &det_ctx->pmq, p->payload, p->payload_len); } @@ -94,26 +83,13 @@ uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p, //PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); uint32_t r; - if (flags & STREAM_TOSERVER) { - for ( ; smsg != NULL; smsg = smsg->next) { - if (smsg->data_len >= det_ctx->sgh->mpm_stream_ctx_ts->minlen) { - r = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtcs, - &det_ctx->pmq, smsg->data, smsg->data_len); - if (r > 0) { - ret += r; - } - } - } - } else if (flags & STREAM_TOCLIENT) { - for ( ; smsg != NULL; smsg = smsg->next) { - if (smsg->data_len >= det_ctx->sgh->mpm_stream_ctx_tc->minlen) { - r = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtcs, - &det_ctx->pmq, smsg->data, smsg->data_len); - if (r > 0) { - ret += r; - } + for ( ; smsg != NULL; smsg = smsg->next) { + if (smsg->data_len >= det_ctx->sgh->mpm_stream_ctx->minlen) { + r = mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type]. + Search(det_ctx->sgh->mpm_stream_ctx, &det_ctx->mtcs, + &det_ctx->pmq, smsg->data, smsg->data_len); + if (r > 0) { + ret += r; } } } @@ -135,21 +111,7 @@ uint32_t PacketPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p) uint32_t ret = 0; const MpmCtx *mpm_ctx = NULL; - if (p->proto == IPPROTO_TCP) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - mpm_ctx = det_ctx->sgh->mpm_proto_tcp_ctx_ts; - } else if (p->flowflags & FLOW_PKT_TOCLIENT) { - mpm_ctx = det_ctx->sgh->mpm_proto_tcp_ctx_tc; - } - } else if (p->proto == IPPROTO_UDP) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - mpm_ctx = det_ctx->sgh->mpm_proto_udp_ctx_ts; - } else if (p->flowflags & FLOW_PKT_TOCLIENT) { - mpm_ctx = det_ctx->sgh->mpm_proto_udp_ctx_tc; - } - } else { - mpm_ctx = det_ctx->sgh->mpm_proto_other_ctx; - } + mpm_ctx = det_ctx->sgh->mpm_packet_ctx; if (unlikely(mpm_ctx == NULL)) SCReturnInt(0); if (p->payload_len < mpm_ctx->minlen) diff --git a/src/detect.h b/src/detect.h index 808fd69820dc..7f54d13fff46 100644 --- a/src/detect.h +++ b/src/detect.h @@ -979,13 +979,11 @@ typedef struct SigGroupHead_ { uint32_t id; /**< unique id used to index sgh_array for stats */ /* pattern matcher instances */ - const MpmCtx *mpm_proto_other_ctx; + const MpmCtx *mpm_packet_ctx; + const MpmCtx *mpm_stream_ctx; union { struct { - const MpmCtx *mpm_proto_tcp_ctx_ts; - const MpmCtx *mpm_proto_udp_ctx_ts; - const MpmCtx *mpm_stream_ctx_ts; const MpmCtx *mpm_uri_ctx_ts; const MpmCtx *mpm_hcbd_ctx_ts; const MpmCtx *mpm_hhd_ctx_ts; @@ -1000,9 +998,6 @@ typedef struct SigGroupHead_ { const MpmCtx *mpm_smtp_filedata_ctx_ts; }; struct { - const MpmCtx *mpm_proto_tcp_ctx_tc; - const MpmCtx *mpm_proto_udp_ctx_tc; - const MpmCtx *mpm_stream_ctx_tc; const MpmCtx *mpm_hsbd_ctx_tc; const MpmCtx *mpm_hhd_ctx_tc; const MpmCtx *mpm_hrhd_ctx_tc; From a2223bb066955c76848760bd76f3a29bd7994153 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 26 Oct 2015 17:04:47 +0100 Subject: [PATCH 1209/2553] mpm: consify packet/stream search --- src/detect-engine-payload.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index f5cd077c6106..d1c0924d0512 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -45,7 +45,7 @@ #include "util-mpm-ac.h" uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, - Packet *p) + const Packet *p) { SCEnter(); @@ -73,8 +73,8 @@ uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, * * \retval ret number of matches */ -uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p, - StreamMsg *smsg, uint8_t flags) +uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, const Packet *p, + const StreamMsg *smsg, const uint8_t flags) { SCEnter(); From 0311f01b970d7ca9d4e5786f6f3a3e3782429cb4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 26 Oct 2015 17:26:49 +0100 Subject: [PATCH 1210/2553] rule grouping: speed up port based grouping Create a hash table of unique DetectPort objects before trying to create a unique list of these objects. This safes a lot of cycles in the creation of the list. --- src/detect-engine-port.c | 133 +++++++++++++++++++++++++++++++++++++++ src/detect-engine-port.h | 5 ++ src/detect.c | 48 +++++++++----- src/detect.h | 3 + 4 files changed, 173 insertions(+), 16 deletions(-) diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index f8c2e48f2f26..8b4bafa7072c 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -1493,6 +1493,139 @@ int DetectPortIsValidRange(char *port) } /********************** End parsing routines ********************/ +/* hash table */ + +/** + * \brief The hash function to be the used by the hash table - + * DetectEngineCtx->dport_hash_table. + * + * \param ht Pointer to the hash table. + * \param data Pointer to the DetectPort. + * \param datalen Not used in our case. + * + * \retval hash The generated hash value. + */ +static uint32_t DetectPortHashFunc(HashListTable *ht, void *data, uint16_t datalen) +{ + DetectPort *p = (DetectPort *)data; + uint32_t hash = 0; + + SCLogDebug("hashing sgh %p", p); + + hash = (p->port << 16) | p->port2; + + hash %= ht->array_size; + SCLogDebug("hash %"PRIu32, hash); + return hash; +} + +/** + * \brief The Compare function to be used by the DetectPort hash table - + * DetectEngineCtx->dport_hash_table. + * + * \param data1 Pointer to the first DetectPort. + * \param len1 Not used. + * \param data2 Pointer to the second DetectPort. + * \param len2 Not used. + * + * \retval 1 If the 2 DetectPort sent as args match. + * \retval 0 If the 2 DetectPort sent as args do not match. + */ +static char DetectPortCompareFunc(void *data1, uint16_t len1, + void *data2, uint16_t len2) +{ + DetectPort *dp1 = (DetectPort *)data1; + DetectPort *dp2 = (DetectPort *)data2; + + if (data1 == NULL || data2 == NULL) + return 0; + + if (dp1->port == dp2->port && dp1->port2 == dp2->port2) + return 1; + + return 0; +} + +static void DetectPortHashFreeFunc(void *ptr) +{ + DetectPort *p = ptr; + DetectPortFree(p); +} + +/** + * \brief Initializes the hash table in the detection engine context to hold the + * DetectPort hash. + * + * \param de_ctx Pointer to the detection engine context. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int DetectPortHashInit(DetectEngineCtx *de_ctx) +{ + de_ctx->dport_hash_table = HashListTableInit(4096, DetectPortHashFunc, + DetectPortCompareFunc, + DetectPortHashFreeFunc); + if (de_ctx->dport_hash_table == NULL) + goto error; + + return 0; + +error: + return -1; +} + +/** + * \brief Adds a DetectPort to the detection engine context DetectPort + * hash table. + * + * \param de_ctx Pointer to the detection engine context. + * \param dp Pointer to the DetectPort. + * + * \retval ret 0 on Successfully adding the DetectPort; -1 on failure. + */ +int DetectPortHashAdd(DetectEngineCtx *de_ctx, DetectPort *dp) +{ + int ret = HashListTableAdd(de_ctx->dport_hash_table, (void *)dp, 0); + return ret; +} + +/** + * \brief Used to lookup a DetectPort hash from the detection engine context + * DetectPort hash table. + * + * \param de_ctx Pointer to the detection engine context. + * \param sgh Pointer to the DetectPort. + * + * \retval rsgh On success a pointer to the DetectPort if the DetectPort is + * found in the hash table; NULL on failure. + */ +DetectPort *DetectPortHashLookup(DetectEngineCtx *de_ctx, DetectPort *dp) +{ + SCEnter(); + + DetectPort *rdp = HashListTableLookup(de_ctx->dport_hash_table, (void *)dp, 0); + + SCReturnPtr(rdp, "DetectPort"); +} + +/** + * \brief Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by + * DetectPortInit() function. + * + * \param de_ctx Pointer to the detection engine context. + */ +void DetectPortHashFree(DetectEngineCtx *de_ctx) +{ + if (de_ctx->sgh_hash_table == NULL) + return; + + HashListTableFree(de_ctx->dport_hash_table); + de_ctx->dport_hash_table = NULL; + + return; +} + /*---------------------- Unittests -------------------------*/ #ifdef UNITTESTS diff --git a/src/detect-engine-port.h b/src/detect-engine-port.h index 1c089e9f9648..9f9bef6ef726 100644 --- a/src/detect-engine-port.h +++ b/src/detect-engine-port.h @@ -46,6 +46,11 @@ void DetectPortFree(DetectPort *); int DetectPortTestConfVars(void); +DetectPort *DetectPortHashLookup(DetectEngineCtx *de_ctx, DetectPort *dp); +void DetectPortHashFree(DetectEngineCtx *de_ctx); +int DetectPortHashAdd(DetectEngineCtx *de_ctx, DetectPort *dp); +int DetectPortHashInit(DetectEngineCtx *de_ctx); + void DetectPortTests(void); #endif /* __DETECT_PORT_H__ */ diff --git a/src/detect.c b/src/detect.c index c9902f73f06e..2db63f08b4fd 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3374,9 +3374,10 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, Detect int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b); static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint32_t direction) { - /* step 1: create a list of 'DetectPort' objects based on all the + /* step 1: create a hash of 'DetectPort' objects based on all the * rules. Each object will have a SGH with the sigs added * that belong to the SGH. */ + DetectPortHashInit(de_ctx); uint32_t max_idx = 0; const Signature *s = de_ctx->sig_list; @@ -3414,21 +3415,20 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 int wl = s->whitelist; while (p) { - DetectPort *tmp = DetectPortCopySingle(de_ctx, p); - BUG_ON(tmp == NULL); - SigGroupHeadAppendSig(de_ctx, &tmp->sh, s); - - int pwl = PortIsWhitelisted(tmp, ipproto) ? 111 : 0; - tmp->sh->init->whitelist = MAX(wl, pwl); - if (tmp->sh->init->whitelist) { - SCLogDebug("%s/%s Rule %u whitelisted port group %u:%u", - direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", - ipproto == 6 ? "TCP" : "UDP", - s->id, p->port, p->port2); - } + int pwl = PortIsWhitelisted(p, ipproto) ? 111 : 0; + pwl = MAX(wl,pwl); - int r = DetectPortInsert(de_ctx, &list , tmp); - BUG_ON(r == -1); + DetectPort *lookup = DetectPortHashLookup(de_ctx, p); + if (lookup) { + SigGroupHeadAppendSig(de_ctx, &lookup->sh, s); + lookup->sh->init->whitelist = MAX(lookup->sh->init->whitelist, pwl); + } else { + DetectPort *tmp2 = DetectPortCopySingle(de_ctx, p); + BUG_ON(tmp2 == NULL); + SigGroupHeadAppendSig(de_ctx, &tmp2->sh, s); + tmp2->sh->init->whitelist = pwl; + DetectPortHashAdd(de_ctx, tmp2); + } p = p->next; } @@ -3437,15 +3437,31 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 s = s->next; } + /* step 2: create a list of DetectPort objects */ + HashListTableBucket *htb = NULL; + for (htb = HashListTableGetListHead(de_ctx->dport_hash_table); + htb != NULL; + htb = HashListTableGetListNext(htb)) + { + DetectPort *p = HashListTableGetListData(htb); + DetectPort *tmp = DetectPortCopySingle(de_ctx, p); + BUG_ON(tmp == NULL); + int r = DetectPortInsert(de_ctx, &list , tmp); + BUG_ON(r == -1); + } + DetectPortHashFree(de_ctx); + de_ctx->dport_hash_table = NULL; + SCLogDebug("rules analyzed"); + /* step 3: group the list and shrink it if necessary */ DetectPort *newlist = NULL; uint16_t groupmax = (direction == SIG_FLAG_TOCLIENT) ? de_ctx->max_uniq_toclient_groups : de_ctx->max_uniq_toserver_groups; CreateGroupedPortList(de_ctx, list, &newlist, groupmax, CreateGroupedPortListCmpCnt, max_idx); list = newlist; - /* step 2: deduplicate the SGH's */ + /* step 4: deduplicate the SGH's */ SigGroupHeadHashFree(de_ctx); SigGroupHeadHashInit(de_ctx); diff --git a/src/detect.h b/src/detect.h index 7f54d13fff46..4c5068b02032 100644 --- a/src/detect.h +++ b/src/detect.h @@ -665,6 +665,9 @@ typedef struct DetectEngineCtx_ { /** id of loader thread 'owning' this de_ctx */ int loader_id; + + HashListTable *dport_hash_table; + } DetectEngineCtx; /* Engine groups profiles (low, medium, high, custom) */ From 2b84387ea4571775d1b3dd64b3170610ae13f072 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Oct 2015 21:49:00 +0100 Subject: [PATCH 1211/2553] detect: work around cocci limitation --- src/detect.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index 2db63f08b4fd..add8f53b1ba0 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3388,8 +3388,13 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 goto next; if (!(s->proto.proto[ipproto / 8] & (1<<(ipproto % 8)) || (s->proto.flags & DETECT_PROTO_ANY))) goto next; - if (!(s->flags & direction)) - goto next; + if (direction == SIG_FLAG_TOSERVER) { + if (!(s->flags & SIG_FLAG_TOSERVER)) + goto next; + } else if (direction == SIG_FLAG_TOCLIENT) { + if (!(s->flags & SIG_FLAG_TOCLIENT)) + goto next; + } DetectPort *p = NULL; if (direction == SIG_FLAG_TOSERVER) From 4e91f6b1e65a6a46fbb88dcc411508790a97a801 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Oct 2015 08:07:28 +0100 Subject: [PATCH 1212/2553] mpm: in factory register, consider name const --- src/util-mpm.c | 14 ++------------ src/util-mpm.h | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/util-mpm.c b/src/util-mpm.c index 9fbf6c22794a..73e13d2260be 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -72,11 +72,7 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam exit(EXIT_FAILURE); } - item[0].name = SCStrdup(name); - if (item[0].name == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } + item[0].name = name; /* toserver */ item[0].mpm_ctx_ts = SCMalloc(sizeof(MpmCtx)); @@ -152,11 +148,7 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam de_ctx->mpm_ctx_factory_container->items = items; MpmCtxFactoryItem *new_item = &items[de_ctx->mpm_ctx_factory_container->no_of_items]; - new_item[0].name = SCStrdup(name); - if (new_item[0].name == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } + new_item[0].name = name; /* toserver */ new_item[0].mpm_ctx_ts = SCMalloc(sizeof(MpmCtx)); @@ -249,8 +241,6 @@ void MpmFactoryDeRegisterAllMpmCtxProfiles(DetectEngineCtx *de_ctx) int i = 0; MpmCtxFactoryItem *items = de_ctx->mpm_ctx_factory_container->items; for (i = 0; i < de_ctx->mpm_ctx_factory_container->no_of_items; i++) { - if (items[i].name != NULL) - SCFree(items[i].name); if (items[i].mpm_ctx_ts != NULL) { if (items[i].mpm_ctx_ts->mpm_type != MPM_NOTSET) mpm_table[items[i].mpm_ctx_ts->mpm_type].DestroyCtx(items[i].mpm_ctx_ts); diff --git a/src/util-mpm.h b/src/util-mpm.h index e8256b4ba5cd..50a0b8a58648 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -128,7 +128,7 @@ typedef struct MpmCtx_ { #define MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD 0x01 typedef struct MpmCtxFactoryItem_ { - char *name; + const char *name; MpmCtx *mpm_ctx_ts; MpmCtx *mpm_ctx_tc; int32_t id; From fdd05e8fb40887a02dc138cbc0aaa1dfdefd6003 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Oct 2015 08:32:29 +0100 Subject: [PATCH 1213/2553] mpm: remove unused app proto factory --- src/detect.c | 2 -- src/detect.h | 1 - 2 files changed, 3 deletions(-) diff --git a/src/detect.c b/src/detect.c index add8f53b1ba0..8acacc1c9289 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2742,8 +2742,6 @@ static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) de_ctx->sgh_mpm_context_stream = MpmFactoryRegisterMpmCtxProfile(de_ctx, "stream", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_app_proto_detect = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "app_proto_detect", 0); DetectMpmInitializeAppMpms(de_ctx); diff --git a/src/detect.h b/src/detect.h index 4c5068b02032..c4f98f3159e5 100644 --- a/src/detect.h +++ b/src/detect.h @@ -619,7 +619,6 @@ typedef struct DetectEngineCtx_ { 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_app_proto_detect; /* the max local id used amongst all sigs */ int32_t byte_extract_max_local_id; From 157ca89dd7e25b88a25eb64143b8335663817d69 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Oct 2015 08:37:28 +0100 Subject: [PATCH 1214/2553] mpm: remove useless flag from factory --- src/detect-engine-mpm.c | 3 +-- src/detect.c | 12 ++++-------- src/util-mpm.c | 7 +------ src/util-mpm.h | 5 +---- 4 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 0e1c7839c3cf..c923b5936118 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -116,8 +116,7 @@ void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) for (i = 0; i < APP_MPMS_MAX; i++) { AppLayerMpms *am = &app_mpms[i]; - am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name, - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); + am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name); SCLogDebug("AppLayer MPM %s: %u", am->name, am->sgh_mpm_context); } diff --git a/src/detect.c b/src/detect.c index 8acacc1c9289..40ba84bbb6af 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2731,17 +2731,13 @@ static int SignatureCreateMask(Signature *s) static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) { de_ctx->sgh_mpm_context_proto_tcp_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_tcp", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); + MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_tcp"); de_ctx->sgh_mpm_context_proto_udp_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_udp", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); + MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_udp"); de_ctx->sgh_mpm_context_proto_other_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_other", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); + MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_other"); de_ctx->sgh_mpm_context_stream = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "stream", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); + MpmFactoryRegisterMpmCtxProfile(de_ctx, "stream"); DetectMpmInitializeAppMpms(de_ctx); diff --git a/src/util-mpm.c b/src/util-mpm.c index 73e13d2260be..af2ecffc4a13 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -54,7 +54,7 @@ * * \retval id Return the id created for the new MpmCtx profile. */ -int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *name, uint8_t flags) +int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *name) { void *ptmp; /* the very first entry */ @@ -96,9 +96,6 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam * the array */ item[0].id = 0; - /* store the flag */ - item[0].flags = flags; - /* store the newly created item */ de_ctx->mpm_ctx_factory_container->items = item; de_ctx->mpm_ctx_factory_container->no_of_items++; @@ -129,7 +126,6 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam memset(items[i].mpm_ctx_tc, 0, sizeof(MpmCtx)); items[i].mpm_ctx_tc->global = 1; } - items[i].flags = flags; return items[i].id; } } @@ -169,7 +165,6 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam new_item[0].mpm_ctx_tc->global = 1; new_item[0].id = de_ctx->mpm_ctx_factory_container->no_of_items; - new_item[0].flags = flags; de_ctx->mpm_ctx_factory_container->no_of_items++; /* the newly created id */ diff --git a/src/util-mpm.h b/src/util-mpm.h index 50a0b8a58648..d689cc9fc433 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -125,14 +125,11 @@ typedef struct MpmCtx_ { * we should supply this as the key */ #define MPM_CTX_FACTORY_UNIQUE_CONTEXT -1 -#define MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD 0x01 - typedef struct MpmCtxFactoryItem_ { const char *name; MpmCtx *mpm_ctx_ts; MpmCtx *mpm_ctx_tc; int32_t id; - uint8_t flags; } MpmCtxFactoryItem; typedef struct MpmCtxFactoryContainer_ { @@ -224,7 +221,7 @@ void MpmCudaEnvironmentSetup(); struct DetectEngineCtx_; -int32_t MpmFactoryRegisterMpmCtxProfile(struct DetectEngineCtx_ *, const char *, uint8_t); +int32_t MpmFactoryRegisterMpmCtxProfile(struct DetectEngineCtx_ *, const char *); void MpmFactoryReClaimMpmCtx(const struct DetectEngineCtx_ *, MpmCtx *); MpmCtx *MpmFactoryGetMpmCtxForProfile(const struct DetectEngineCtx_ *, int32_t, int); void MpmFactoryDeRegisterAllMpmCtxProfiles(struct DetectEngineCtx_ *); From 79a96b2b9096e5850f276d98ba621439d892e7ff Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Oct 2015 09:17:45 +0100 Subject: [PATCH 1215/2553] mpm: refactor 'single' setup handling --- src/detect-engine-mpm.c | 12 ++++++------ src/detect.c | 29 ++++++++++++++++------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index c923b5936118..dd454ce5a461 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -116,7 +116,11 @@ void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) for (i = 0; i < APP_MPMS_MAX; i++) { AppLayerMpms *am = &app_mpms[i]; - am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name); + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { + am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name); + } else { + am->sgh_mpm_context = MPM_CTX_FACTORY_UNIQUE_CONTEXT; + } SCLogDebug("AppLayer MPM %s: %u", am->name, am->sgh_mpm_context); } @@ -782,11 +786,7 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) dir = 0; } - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, ms->sgh_mpm_context, dir); - } else { - ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, dir); - } + ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, ms->sgh_mpm_context, dir); MpmInitCtx(ms->mpm_ctx, de_ctx->mpm_matcher); /* add the patterns */ diff --git a/src/detect.c b/src/detect.c index 40ba84bbb6af..734117cf0761 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2730,14 +2730,21 @@ static int SignatureCreateMask(Signature *s) static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) { - de_ctx->sgh_mpm_context_proto_tcp_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_tcp"); - de_ctx->sgh_mpm_context_proto_udp_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_udp"); - de_ctx->sgh_mpm_context_proto_other_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_other"); - de_ctx->sgh_mpm_context_stream = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "stream"); + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { + de_ctx->sgh_mpm_context_proto_tcp_packet = + MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_tcp"); + de_ctx->sgh_mpm_context_proto_udp_packet = + MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_udp"); + de_ctx->sgh_mpm_context_proto_other_packet = + MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_other"); + de_ctx->sgh_mpm_context_stream = + MpmFactoryRegisterMpmCtxProfile(de_ctx, "stream"); + } else { + de_ctx->sgh_mpm_context_proto_tcp_packet = MPM_CTX_FACTORY_UNIQUE_CONTEXT; + de_ctx->sgh_mpm_context_proto_udp_packet = MPM_CTX_FACTORY_UNIQUE_CONTEXT; + de_ctx->sgh_mpm_context_proto_other_packet = MPM_CTX_FACTORY_UNIQUE_CONTEXT; + de_ctx->sgh_mpm_context_stream = MPM_CTX_FACTORY_UNIQUE_CONTEXT; + } DetectMpmInitializeAppMpms(de_ctx); @@ -4112,11 +4119,7 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) if (DetectSetFastPatternAndItsId(de_ctx) < 0) return -1; - /* if we are using single sgh_mpm_context then let us init the standard mpm - * contexts using the mpm_ctx factory */ - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - SigInitStandardMpmFactoryContexts(de_ctx); - } + SigInitStandardMpmFactoryContexts(de_ctx); if (SigAddressPrepareStage1(de_ctx) != 0) { SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); From 6ef27c9f92fd68f7b0a389957e451a73e7274e9f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Oct 2015 17:02:40 +0100 Subject: [PATCH 1216/2553] mpm: allow app buffer shared/unique Allow setting of shared or unique setting per app buffer type: e.g. detect.mpm.http_uri.shared=true --- src/detect-engine-mpm.c | 36 ++++++++++++++++++++++++++++-------- src/detect.c | 4 +--- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index dd454ce5a461..179085603f70 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -116,16 +116,33 @@ void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) for (i = 0; i < APP_MPMS_MAX; i++) { AppLayerMpms *am = &app_mpms[i]; - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name); - } else { + /* default to whatever the global setting is */ + int shared = (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE); + + /* see if we use a unique or shared mpm ctx for this type */ + int confshared = 0; + char confstring[256] = "detect.mpm."; + strlcat(confstring, am->name, sizeof(confstring)); + strlcat(confstring, ".shared", sizeof(confstring)); + if (ConfGetBool(confstring, &confshared) == 1) + shared = confshared; + + if (shared == 0) { + SCLogInfo("using unique mpm ctx' for %s", am->name); am->sgh_mpm_context = MPM_CTX_FACTORY_UNIQUE_CONTEXT; + } else { + SCLogInfo("using shared mpm ctx' for %s", am->name); + am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name); } SCLogDebug("AppLayer MPM %s: %u", am->name, am->sgh_mpm_context); } } +/** + * \brief initialize mpm contexts for applayer buffers that are in + * "single or "shared" mode. + */ void DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx) { int i; @@ -134,10 +151,13 @@ void DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx) int dir = (am->direction == SIG_FLAG_TOSERVER) ? 1 : 0; - MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, dir); - if (mpm_ctx != NULL) { - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + if (am->sgh_mpm_context != MPM_CTX_FACTORY_UNIQUE_CONTEXT) + { + MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, dir); + if (mpm_ctx != NULL) { + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } } } } @@ -834,7 +854,7 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) MpmFactoryReClaimMpmCtx(de_ctx, ms->mpm_ctx); ms->mpm_ctx = NULL; } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { + if (ms->sgh_mpm_context == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { if (mpm_table[ms->mpm_ctx->mpm_type].Prepare != NULL) { mpm_table[ms->mpm_ctx->mpm_type].Prepare(ms->mpm_ctx); } diff --git a/src/detect.c b/src/detect.c index 734117cf0761..a322bfc75561 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4197,8 +4197,6 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) } //printf("stream- %d\n", mpm_ctx->pattern_cnt); - DetectMpmPrepareAppMpms(de_ctx); - #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) { int r = SCCudaCtxPopCurrent(NULL); @@ -4212,8 +4210,8 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) * \todo Support this. */ DetermineCudaStateTableSize(de_ctx); #endif - } + DetectMpmPrepareAppMpms(de_ctx); // DetectAddressPrintMemory(); // DetectSigGroupPrintMemory(); From 1dd135d512bb536287d92895cdd6cf33e2ecc573 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Oct 2015 20:52:00 +0100 Subject: [PATCH 1217/2553] mpm: always cleanup factory --- src/detect-engine.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index e9e9ecec5aad..42a130cc4c86 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -978,9 +978,7 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) SigGroupCleanup(de_ctx); - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx); - } + MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx); DetectEngineCtxFreeThreadKeywordData(de_ctx); SRepDestroy(de_ctx); From ac2c206359922a2296b5d019be0355ba23ae430b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Oct 2015 21:47:37 +0100 Subject: [PATCH 1218/2553] mpm: clean up builtin mpm setup, enable single/full --- src/detect-engine-mpm.c | 82 +++++++++++++++++++++++++++++++++++++++++ src/detect-engine-mpm.h | 6 ++- src/detect.c | 56 +--------------------------- 3 files changed, 88 insertions(+), 56 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 179085603f70..89cc643b90b4 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -163,6 +163,88 @@ void DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx) } } +static int32_t SetupBuiltinMpm(DetectEngineCtx *de_ctx, const char *name) +{ + /* default to whatever the global setting is */ + int shared = (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE); + + /* see if we use a unique or shared mpm ctx for this type */ + int confshared = 0; + char confstring[256] = "detect.mpm."; + strlcat(confstring, name, sizeof(confstring)); + strlcat(confstring, ".shared", sizeof(confstring)); + if (ConfGetBool(confstring, &confshared) == 1) + shared = confshared; + + int32_t ctx; + if (shared == 0) { + ctx = MPM_CTX_FACTORY_UNIQUE_CONTEXT; + SCLogInfo("using unique mpm ctx' for %s", name); + } else { + ctx = MpmFactoryRegisterMpmCtxProfile(de_ctx, name); + SCLogInfo("using shared mpm ctx' for %s", name); + } + return ctx; +} + +void DetectMpmInitializeBuiltinMpms(DetectEngineCtx *de_ctx) +{ + de_ctx->sgh_mpm_context_proto_tcp_packet = SetupBuiltinMpm(de_ctx, "tcp-packet"); + de_ctx->sgh_mpm_context_stream = SetupBuiltinMpm(de_ctx, "tcp-stream"); + + de_ctx->sgh_mpm_context_proto_udp_packet = SetupBuiltinMpm(de_ctx, "udp-packet"); + de_ctx->sgh_mpm_context_proto_other_packet = SetupBuiltinMpm(de_ctx, "other-ip"); +} + +/** + * \brief initialize mpm contexts for builtin buffers that are in + * "single or "shared" mode. + */ +void DetectMpmPrepareBuiltinMpms(DetectEngineCtx *de_ctx) +{ + MpmCtx *mpm_ctx = NULL; + + if (de_ctx->sgh_mpm_context_proto_tcp_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + } + + if (de_ctx->sgh_mpm_context_proto_udp_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + } + + if (de_ctx->sgh_mpm_context_proto_other_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + } + + if (de_ctx->sgh_mpm_context_stream != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + } +} + /** * \brief check if a signature has patterns that are to be inspected * against a packets payload (as opposed to the stream payload) diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 4bb7fe31a53c..5e83a2553987 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -34,10 +34,12 @@ void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx); void DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx); - -uint16_t PatternMatchDefaultMatcher(void); +void DetectMpmInitializeBuiltinMpms(DetectEngineCtx *de_ctx); +void DetectMpmPrepareBuiltinMpms(DetectEngineCtx *de_ctx); uint32_t PatternStrength(uint8_t *, uint16_t); + +uint16_t PatternMatchDefaultMatcher(void); uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *, Packet *); uint32_t PacketPatternSearch(DetectEngineThreadCtx *, Packet *); uint32_t StreamPatternSearch(DetectEngineThreadCtx *, Packet *, StreamMsg *, uint8_t); diff --git a/src/detect.c b/src/detect.c index a322bfc75561..fd99ed761ae7 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2730,22 +2730,7 @@ static int SignatureCreateMask(Signature *s) static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - de_ctx->sgh_mpm_context_proto_tcp_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_tcp"); - de_ctx->sgh_mpm_context_proto_udp_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_udp"); - de_ctx->sgh_mpm_context_proto_other_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_other"); - de_ctx->sgh_mpm_context_stream = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "stream"); - } else { - de_ctx->sgh_mpm_context_proto_tcp_packet = MPM_CTX_FACTORY_UNIQUE_CONTEXT; - de_ctx->sgh_mpm_context_proto_udp_packet = MPM_CTX_FACTORY_UNIQUE_CONTEXT; - de_ctx->sgh_mpm_context_proto_other_packet = MPM_CTX_FACTORY_UNIQUE_CONTEXT; - de_ctx->sgh_mpm_context_stream = MPM_CTX_FACTORY_UNIQUE_CONTEXT; - } - + DetectMpmInitializeBuiltinMpms(de_ctx); DetectMpmInitializeAppMpms(de_ctx); return; @@ -4141,8 +4126,6 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) } if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - MpmCtx *mpm_ctx = NULL; - #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) { /* setting it to default. You've gotta remove it once you fix the state table thing */ @@ -4161,42 +4144,6 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) } } #endif - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("packet- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("packet- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("packet- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("stream- %d\n", mpm_ctx->pattern_cnt); - #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) { int r = SCCudaCtxPopCurrent(NULL); @@ -4211,6 +4158,7 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) DetermineCudaStateTableSize(de_ctx); #endif } + DetectMpmPrepareBuiltinMpms(de_ctx); DetectMpmPrepareAppMpms(de_ctx); // DetectAddressPrintMemory(); From 725d6c37395f21e62c93da34530a383500c07e67 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 23 Nov 2015 19:03:47 +0100 Subject: [PATCH 1219/2553] yaml: convert detect-engine to just detect Instead of detect-engine which used a list for no good reason, use a simple map now. detect: profile: medium custom-values: toclient-groups: 3 toserver-groups: 25 sgh-mpm-context: auto inspection-recursion-limit: 3000 # If set to yes, the loading of signatures will be made after the capture # is started. This will limit the downtime in IPS mode. #delayed-detect: yes --- src/detect-engine.c | 144 ++++++++++++++++++++++++++------------------ src/suricata.c | 14 +++-- suricata.yaml.in | 26 +++----- 3 files changed, 105 insertions(+), 79 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 42a130cc4c86..e66035e25fe7 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -104,7 +104,7 @@ static uint32_t detect_engine_ctx_id = 1; static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt); -static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *); +static int DetectEngineCtxLoadConf(DetectEngineCtx *); static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, 0, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL,}; @@ -809,11 +809,6 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) { DetectEngineCtx *de_ctx; - ConfNode *seq_node = NULL; - ConfNode *insp_recursion_limit_node = NULL; - ConfNode *de_engine_node = NULL; - char *insp_recursion_limit = NULL; - de_ctx = SCMalloc(sizeof(DetectEngineCtx)); if (unlikely(de_ctx == NULL)) goto error; @@ -834,39 +829,6 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) SCLogDebug("ConfGetBool could not load the value."); } - de_engine_node = ConfGetNode("detect-engine"); - if (de_engine_node != NULL) { - TAILQ_FOREACH(seq_node, &de_engine_node->head, next) { - if (strcmp(seq_node->val, "inspection-recursion-limit") != 0) - continue; - - insp_recursion_limit_node = ConfNodeLookupChild(seq_node, seq_node->val); - if (insp_recursion_limit_node == NULL) { - SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Error retrieving conf " - "entry for detect-engine:inspection-recursion-limit"); - break; - } - insp_recursion_limit = insp_recursion_limit_node->val; - SCLogDebug("Found detect-engine:inspection-recursion-limit - %s:%s", - insp_recursion_limit_node->name, insp_recursion_limit_node->val); - - break; - } - } - - if (insp_recursion_limit != NULL) { - de_ctx->inspection_recursion_limit = atoi(insp_recursion_limit); - } else { - de_ctx->inspection_recursion_limit = - DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT; - } - - if (de_ctx->inspection_recursion_limit == 0) - de_ctx->inspection_recursion_limit = -1; - - SCLogDebug("de_ctx->inspection_recursion_limit: %d", - de_ctx->inspection_recursion_limit); - de_ctx->mpm_matcher = PatternMatchDefaultMatcher(); DetectEngineCtxLoadConf(de_ctx); @@ -1006,25 +968,32 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) * \retval 0 if no config provided, 1 if config was provided * and loaded successfuly */ -static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) +static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) { uint8_t profile = ENGINE_PROFILE_UNKNOWN; + char *max_uniq_toclient_groups_str = NULL; + char *max_uniq_toserver_groups_str = NULL; + char *sgh_mpm_context = NULL; char *de_ctx_profile = NULL; - const char *max_uniq_toclient_groups_str = NULL; - const char *max_uniq_toserver_groups_str = NULL; - - char *sgh_mpm_context = NULL; + (void)ConfGet("detect.profile", &de_ctx_profile); + (void)ConfGet("detect.sgh-mpm-context", &sgh_mpm_context); ConfNode *de_ctx_custom = ConfGetNode("detect-engine"); ConfNode *opt = NULL; if (de_ctx_custom != NULL) { TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { - if (strcmp(opt->val, "profile") == 0) { - de_ctx_profile = opt->head.tqh_first->val; - } else if (strcmp(opt->val, "sgh-mpm-context") == 0) { - sgh_mpm_context = opt->head.tqh_first->val; + if (de_ctx_profile == NULL) { + if (strcmp(opt->val, "profile") == 0) { + de_ctx_profile = opt->head.tqh_first->val; + } + } + + if (sgh_mpm_context == NULL) { + if (strcmp(opt->val, "sgh-mpm-context") == 0) { + sgh_mpm_context = opt->head.tqh_first->val; + } } } } @@ -1089,6 +1058,7 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) de_ctx->sgh_mpm_context = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL; } + /* parse profile custom-values */ opt = NULL; switch (profile) { case ENGINE_PROFILE_LOW: @@ -1102,12 +1072,23 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) break; case ENGINE_PROFILE_CUSTOM: - TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { - if (strcmp(opt->val, "custom-values") == 0) { - max_uniq_toclient_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-groups"); - max_uniq_toserver_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-groups"); + (void)ConfGet("detect.custom-values.toclient-groups", + &max_uniq_toclient_groups_str); + (void)ConfGet("detect.custom-values.toserver-groups", + &max_uniq_toserver_groups_str); + + if (de_ctx_custom != NULL) { + TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { + if (strcmp(opt->val, "custom-values") == 0) { + if (max_uniq_toclient_groups_str == NULL) { + max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue + (opt->head.tqh_first, "toclient-groups"); + } + if (max_uniq_toserver_groups_str == NULL) { + max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue + (opt->head.tqh_first, "toserver-groups"); + } + } } } if (max_uniq_toclient_groups_str != NULL) { @@ -1151,9 +1132,58 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) break; } - if (profile == ENGINE_PROFILE_UNKNOWN) - return 0; - return 1; + if (profile == ENGINE_PROFILE_UNKNOWN) { + goto error; + } + + intmax_t value = 0; + if (ConfGetInt("detect.inspection-recursion-limit", &value) == 1) + { + if (value >= 0 && value <= INT_MAX) { + de_ctx->inspection_recursion_limit = (int)value; + } + + /* fall back to old config parsing */ + } else { + ConfNode *insp_recursion_limit_node = NULL; + char *insp_recursion_limit = NULL; + + if (de_ctx_custom != NULL) { + opt = NULL; + TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { + if (strcmp(opt->val, "inspection-recursion-limit") != 0) + continue; + + insp_recursion_limit_node = ConfNodeLookupChild(opt, opt->val); + if (insp_recursion_limit_node == NULL) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Error retrieving conf " + "entry for detect-engine:inspection-recursion-limit"); + break; + } + insp_recursion_limit = insp_recursion_limit_node->val; + SCLogDebug("Found detect-engine.inspection-recursion-limit - %s:%s", + insp_recursion_limit_node->name, insp_recursion_limit_node->val); + break; + } + + if (insp_recursion_limit != NULL) { + de_ctx->inspection_recursion_limit = atoi(insp_recursion_limit); + } else { + de_ctx->inspection_recursion_limit = + DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT; + } + } + } + + if (de_ctx->inspection_recursion_limit == 0) + de_ctx->inspection_recursion_limit = -1; + + SCLogDebug("de_ctx->inspection_recursion_limit: %d", + de_ctx->inspection_recursion_limit); + + return 0; +error: + return -1; } /* diff --git a/src/suricata.c b/src/suricata.c index 5eb6482be768..f47aa5aa8f90 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1985,12 +1985,14 @@ static void SetupDelayedDetect(SCInstance *suri) if (suri->offline) { suri->delayed_detect = 0; } else { - ConfNode *denode = NULL; - ConfNode *decnf = ConfGetNode("detect-engine"); - if (decnf != NULL) { - TAILQ_FOREACH(denode, &decnf->head, next) { - if (strcmp(denode->val, "delayed-detect") == 0) { - (void)ConfGetChildValueBool(denode, "delayed-detect", &suri->delayed_detect); + if (ConfGetBool("detect.delayed-detect", &suri->delayed_detect) != 1) { + ConfNode *denode = NULL; + ConfNode *decnf = ConfGetNode("detect-engine"); + if (decnf != NULL) { + TAILQ_FOREACH(denode, &decnf->head, next) { + if (strcmp(denode->val, "delayed-detect") == 0) { + (void)ConfGetChildValueBool(denode, "delayed-detect", &suri->delayed_detect); + } } } } diff --git a/suricata.yaml.in b/suricata.yaml.in index 59c4d8e161f3..a9db90babb6e 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -591,22 +591,16 @@ legacy: # might end up taking too much time in the content inspection code. # If the argument specified is 0, the engine uses an internally defined # default limit. On not specifying a value, we use no limits on the recursion. -detect-engine: - - profile: medium - - custom-values: - toclient-src-groups: 2 - toclient-dst-groups: 2 - toclient-sp-groups: 2 - toclient-dp-groups: 3 - toserver-src-groups: 2 - toserver-dst-groups: 4 - toserver-sp-groups: 2 - toserver-dp-groups: 25 - - sgh-mpm-context: auto - - inspection-recursion-limit: 3000 +detect: + profile: medium + custom-values: + toclient-groups: 3 + toserver-groups: 25 + sgh-mpm-context: auto + inspection-recursion-limit: 3000 # If set to yes, the loading of signatures will be made after the capture # is started. This will limit the downtime in IPS mode. - #- delayed-detect: yes + #delayed-detect: yes profiling: # Log the rules that made it past the prefilter stage, per packet @@ -706,8 +700,8 @@ cuda: # ac, ac-bs and ac-gfbs. # # The mpm you choose also decides the distribution of mpm contexts for -# signature groups, specified by the conf - "detect-engine.sgh-mpm-context". -# Selecting "ac" as the mpm would require "detect-engine.sgh-mpm-context" +# signature groups, specified by the conf - "detect.sgh-mpm-context". +# Selecting "ac" as the mpm would require "detect.sgh-mpm-context" # to be set to "single", because of ac's memory requirements, unless the # ruleset is small enough to fit in one's memory, in which case one can # use "full" with "ac". Rest of the mpms can be run in "full" mode. From 5b1d75f0bd67175415ed355eb477392d1a0d166f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Nov 2015 17:27:56 +0100 Subject: [PATCH 1220/2553] detect: suppress output --- src/detect-engine-mpm.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 89cc643b90b4..eb7edcbe54b5 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -128,10 +128,14 @@ void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) shared = confshared; if (shared == 0) { - SCLogInfo("using unique mpm ctx' for %s", am->name); + if (!(de_ctx->flags & DE_QUIET)) { + SCLogInfo("using unique mpm ctx' for %s", am->name); + } am->sgh_mpm_context = MPM_CTX_FACTORY_UNIQUE_CONTEXT; } else { - SCLogInfo("using shared mpm ctx' for %s", am->name); + if (!(de_ctx->flags & DE_QUIET)) { + SCLogInfo("using shared mpm ctx' for %s", am->name); + } am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name); } @@ -821,16 +825,18 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx) } } - uint32_t x; - for (x = 0; x < MPMB_MAX; x++) { - SCLogInfo("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]); - } - for (x = 0; x < APP_MPMS_MAX; x++) { - if (appstats[x] == 0) - continue; - const char *name = app_mpms[x].name; - char *direction = app_mpms[x].direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient"; - SCLogInfo("AppLayer MPM \"%s %s\": %u", direction, name, appstats[x]); + if (!(de_ctx->flags & DE_QUIET)) { + uint32_t x; + for (x = 0; x < MPMB_MAX; x++) { + SCLogInfo("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]); + } + for (x = 0; x < APP_MPMS_MAX; x++) { + if (appstats[x] == 0) + continue; + const char *name = app_mpms[x].name; + char *direction = app_mpms[x].direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient"; + SCLogInfo("AppLayer MPM \"%s %s\": %u", direction, name, appstats[x]); + } } } From d6ba01b1b73dfccc6ee009f5ce3d0880cbc2b6d1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 2 Mar 2016 13:37:14 +0100 Subject: [PATCH 1221/2553] detect: make port whitelisting configurable Make the port grouping whitelisting configurable. A whitelisted port ends up in it's own port group. detect: grouping: tcp-whitelist: 80, 443 udp-whitelist: 53, 5060 No portranges are allowed at this point. --- src/detect-engine.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ src/detect.c | 20 ++++++++--------- src/detect.h | 3 +++ suricata.yaml.in | 8 +++++++ 4 files changed, 73 insertions(+), 10 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index e66035e25fe7..fb06a7c0f35b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -957,6 +957,9 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) #endif } + DetectPortCleanupList(de_ctx->tcp_whitelist); + DetectPortCleanupList(de_ctx->udp_whitelist); + SCFree(de_ctx); //DetectAddressGroupPrintMemory(); //DetectSigGroupPrintMemory(); @@ -1181,6 +1184,55 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) SCLogDebug("de_ctx->inspection_recursion_limit: %d", de_ctx->inspection_recursion_limit); + /* parse port grouping whitelisting settings */ + + char *ports = NULL; + (void)ConfGet("detect.grouping.tcp-whitelist", &ports); + if (ports) { + SCLogInfo("grouping: tcp-whitelist %s", ports); + } else { + ports = "53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080"; + SCLogInfo("grouping: tcp-whitelist (default) %s", ports); + + } + if (DetectPortParse(de_ctx, &de_ctx->tcp_whitelist, ports) != 0) { + SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value " + "for detect.grouping.tcp-whitelist", ports); + } + DetectPort *x = de_ctx->tcp_whitelist; + for ( ; x != NULL; x = x->next) { + if (x->port != x->port2) { + SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value " + "for detect.grouping.tcp-whitelist: only single ports allowed", ports); + DetectPortCleanupList(de_ctx->tcp_whitelist); + de_ctx->tcp_whitelist = NULL; + break; + } + } + + ports = NULL; + (void)ConfGet("detect.grouping.udp-whitelist", &ports); + if (ports) { + SCLogInfo("grouping: udp-whitelist %s", ports); + } else { + ports = "53, 135, 5060"; + SCLogInfo("grouping: udp-whitelist (default) %s", ports); + + } + if (DetectPortParse(de_ctx, &de_ctx->udp_whitelist, ports) != 0) { + SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value " + "forr detect.grouping.udp-whitelist", ports); + } + for (x = de_ctx->udp_whitelist; x != NULL; x = x->next) { + if (x->port != x->port2) { + SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value " + "for detect.grouping.udp-whitelist: only single ports allowed", ports); + DetectPortCleanupList(de_ctx->udp_whitelist); + de_ctx->udp_whitelist = NULL; + break; + } + } + return 0; error: return -1; diff --git a/src/detect.c b/src/detect.c index fd99ed761ae7..3f3ff4164d9c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3295,19 +3295,19 @@ int RulesGroupByProto(DetectEngineCtx *de_ctx) return 0; } -int tcp_whitelisted[] = { 53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080, -1 }; -int udp_whitelisted[] = { 53, 135, 5060, -1 }; - -static int PortIsWhitelisted(const DetectPort *a, int ipproto) +static int PortIsWhitelisted(const DetectEngineCtx *de_ctx, + const DetectPort *a, int ipproto) { - int *w = tcp_whitelisted; + DetectPort *w = de_ctx->tcp_whitelist; if (ipproto == IPPROTO_UDP) - w = udp_whitelisted; - while (*w++ != -1) { - if (a->port >= *w && a->port2 <= *w) { - SCLogDebug("port group %u:%u whitelisted -> %d", a->port, a->port2, *w); + w = de_ctx->udp_whitelist; + + while (w) { + if (a->port >= w->port && a->port2 <= w->port) { + SCLogDebug("port group %u:%u whitelisted -> %d", a->port, a->port2, w->port); return 1; } + w = w->next; } return 0; @@ -3406,7 +3406,7 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 int wl = s->whitelist; while (p) { - int pwl = PortIsWhitelisted(p, ipproto) ? 111 : 0; + int pwl = PortIsWhitelisted(de_ctx, p, ipproto) ? 111 : 0; pwl = MAX(wl,pwl); DetectPort *lookup = DetectPortHashLookup(de_ctx, p); diff --git a/src/detect.h b/src/detect.h index c4f98f3159e5..2aa20bfa8bd9 100644 --- a/src/detect.h +++ b/src/detect.h @@ -667,6 +667,9 @@ typedef struct DetectEngineCtx_ { HashListTable *dport_hash_table; + DetectPort *tcp_whitelist; + DetectPort *udp_whitelist; + } DetectEngineCtx; /* Engine groups profiles (low, medium, high, custom) */ diff --git a/suricata.yaml.in b/suricata.yaml.in index a9db90babb6e..e428f1069939 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -602,6 +602,14 @@ detect: # is started. This will limit the downtime in IPS mode. #delayed-detect: yes + # the grouping values above control how many groups are created per + # direction. Port whitelisting forces that port to get it's own group. + # Very common ports will benefit, as well as ports with many expensive + # rules. + grouping: + #tcp-whitelist: 53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080 + #udp-whitelist: 53, 135, 5060 + profiling: # Log the rules that made it past the prefilter stage, per packet # default is off. The threshold setting determines how many rules From 5f676167a357a7cf679b6481d6c17c4c56dc44a9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 2 Mar 2016 16:38:02 +0100 Subject: [PATCH 1222/2553] detect grouping: make json dump configurable Make the rule grouping dump to rule_group.json configurable. detect: profiling: grouping: dump-to-disk: false include-rules: false # very verbose include-mpm-stats: false --- src/detect.c | 84 +++++++++++++++++++++++++++++------------------- suricata.yaml.in | 4 +++ 2 files changed, 55 insertions(+), 33 deletions(-) diff --git a/src/detect.c b/src/detect.c index 3f3ff4164d9c..2461a7f24a4e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2867,7 +2867,8 @@ int RuleMpmIsNegated(const Signature *s) } #ifdef HAVE_LIBJANSSON -json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh) +json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh, + const int add_rules, const int add_mpm_stats) { uint32_t mpm_cnt = 0; uint32_t nonmpm_cnt = 0; @@ -2908,12 +2909,7 @@ json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh) s = sgh->match_array[x]; if (s == NULL) continue; -#if 0 - json_t *js_sig = json_object(); - if (unlikely(js == NULL)) - continue; - json_object_set_new(js_sig, "sig_id", json_integer(s->id)); -#endif + int any = 0; if (s->proto.flags & DETECT_PROTO_ANY) { any++; @@ -3026,7 +3022,14 @@ json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh) if (s->alproto != ALPROTO_UNKNOWN) { alstats[s->alproto]++; } -// json_array_append_new(js_array, js_sig); + + if (add_rules) { + json_t *js_sig = json_object(); + if (unlikely(js == NULL)) + continue; + json_object_set_new(js_sig, "sig_id", json_integer(s->id)); + json_array_append_new(js_array, js_sig); + } } json_object_set_new(js, "rules", js_array); @@ -3059,35 +3062,37 @@ json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh) } } - json_t *mpm_js = json_object(); + if (add_mpm_stats) { + json_t *mpm_js = json_object(); - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { - if (mpm_stats[i].cnt > 0) { + for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + if (mpm_stats[i].cnt > 0) { - json_t *mpm_sizes_array = json_array(); - for (x = 0; x < 256; x++) { - if (mpm_sizes[i][x] == 0) - continue; + json_t *mpm_sizes_array = json_array(); + for (x = 0; x < 256; x++) { + if (mpm_sizes[i][x] == 0) + continue; - json_t *e = json_object(); - json_object_set_new(e, "size", json_integer(x)); - json_object_set_new(e, "count", json_integer(mpm_sizes[i][x])); - json_array_append_new(mpm_sizes_array, e); - } + json_t *e = json_object(); + json_object_set_new(e, "size", json_integer(x)); + json_object_set_new(e, "count", json_integer(mpm_sizes[i][x])); + json_array_append_new(mpm_sizes_array, e); + } - json_t *buf = json_object(); - json_object_set_new(buf, "total", json_integer(mpm_stats[i].cnt)); - json_object_set_new(buf, "avg_strength", json_integer(mpm_stats[i].total / mpm_stats[i].cnt)); - json_object_set_new(buf, "min_strength", json_integer(mpm_stats[i].min)); - json_object_set_new(buf, "max_strength", json_integer(mpm_stats[i].max)); + json_t *buf = json_object(); + json_object_set_new(buf, "total", json_integer(mpm_stats[i].cnt)); + json_object_set_new(buf, "avg_strength", json_integer(mpm_stats[i].total / mpm_stats[i].cnt)); + json_object_set_new(buf, "min_strength", json_integer(mpm_stats[i].min)); + json_object_set_new(buf, "max_strength", json_integer(mpm_stats[i].max)); - json_object_set_new(buf, "sizes", mpm_sizes_array); + json_object_set_new(buf, "sizes", mpm_sizes_array); - json_object_set_new(mpm_js, DetectListToHumanString(i), buf); + json_object_set_new(mpm_js, DetectListToHumanString(i), buf); + } } - } - json_object_set_new(stats, "mpm", mpm_js); + json_object_set_new(stats, "mpm", mpm_js); + } json_object_set_new(js, "stats", stats); json_object_set_new(js, "whitelist", json_integer(sgh->init->whitelist)); @@ -3096,7 +3101,8 @@ json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh) } #endif /* HAVE_LIBJANSSON */ -void RulesDumpGrouping(const DetectEngineCtx *de_ctx) +void RulesDumpGrouping(const DetectEngineCtx *de_ctx, + const int add_rules, const int add_mpm_stats) { #ifdef HAVE_LIBJANSSON json_t *js = json_object(); @@ -3118,7 +3124,8 @@ void RulesDumpGrouping(const DetectEngineCtx *de_ctx) json_object_set_new(port, "port", json_integer(list->port)); json_object_set_new(port, "port2", json_integer(list->port2)); - json_t *tcp_ts = RulesGroupPrintSghStats(list->sh); + json_t *tcp_ts = RulesGroupPrintSghStats(list->sh, + add_rules, add_mpm_stats); json_object_set_new(port, "rulegroup", tcp_ts); json_array_append_new(ts_array, port); @@ -3134,7 +3141,8 @@ void RulesDumpGrouping(const DetectEngineCtx *de_ctx) json_object_set_new(port, "port", json_integer(list->port)); json_object_set_new(port, "port2", json_integer(list->port2)); - json_t *tcp_tc = RulesGroupPrintSghStats(list->sh); + json_t *tcp_tc = RulesGroupPrintSghStats(list->sh, + add_rules, add_mpm_stats); json_object_set_new(port, "rulegroup", tcp_tc); json_array_append_new(tc_array, port); @@ -4027,7 +4035,17 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) * after the initialization phase. */ SigGroupHeadHashFree(de_ctx); - RulesDumpGrouping(de_ctx); + int dump_grouping = 0; + (void)ConfGetBool("detect.profiling.grouping.dump-to-disk", &dump_grouping); + + if (dump_grouping) { + int add_rules = 0; + (void)ConfGetBool("detect.profiling.grouping.include-rules", &add_rules); + int add_mpm_stats = 0; + (void)ConfGetBool("detect.profiling.grouping.include-mpm-stats", &add_rules); + + RulesDumpGrouping(de_ctx, add_rules, add_mpm_stats); + } #ifdef PROFILING SCProfilingSghInitCounters(de_ctx); diff --git a/suricata.yaml.in b/suricata.yaml.in index e428f1069939..f307b7a8d363 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -616,6 +616,10 @@ detect: # must have made it past pre-filter for that rule to trigger the # logging. #inspect-logging-threshold: 200 + grouping: + dump-to-disk: false + include-rules: false # very verbose + include-mpm-stats: false # Suricata is multi-threaded. Here the threading can be influenced. threading: From e0111fbb904524de93a03cb72b2cb4066887e66f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 25 Mar 2016 12:00:52 +0100 Subject: [PATCH 1223/2553] detect grouping: remove debug mem counters --- src/detect-engine-siggroup.c | 92 ------------------------------------ src/detect-engine-siggroup.h | 2 - src/detect-ipproto.c | 1 - src/detect-rpc.c | 1 - src/detect.c | 8 ---- 5 files changed, 104 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 18c36c6959db..60217690835f 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -54,32 +54,13 @@ /* prototypes */ int SigGroupHeadClearSigs(SigGroupHead *); -static uint32_t detect_siggroup_head_memory = 0; -static uint32_t detect_siggroup_head_init_cnt = 0; -static uint32_t detect_siggroup_head_free_cnt = 0; -static uint32_t detect_siggroup_head_initdata_memory = 0; -static uint32_t detect_siggroup_head_initdata_init_cnt = 0; -static uint32_t detect_siggroup_head_initdata_free_cnt = 0; -static uint32_t detect_siggroup_sigarray_memory = 0; -static uint32_t detect_siggroup_sigarray_init_cnt = 0; -static uint32_t detect_siggroup_sigarray_free_cnt = 0; -static uint32_t detect_siggroup_matcharray_memory = 0; -static uint32_t detect_siggroup_matcharray_init_cnt = 0; -static uint32_t detect_siggroup_matcharray_free_cnt = 0; - void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid) { if (sghid->sig_array != NULL) { SCFree(sghid->sig_array); sghid->sig_array = NULL; - - detect_siggroup_sigarray_free_cnt++; - detect_siggroup_sigarray_memory -= sghid->sig_size; } SCFree(sghid); - - detect_siggroup_head_initdata_free_cnt++; - detect_siggroup_head_initdata_memory -= sizeof(SigGroupHeadInitData); } static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size) @@ -90,9 +71,6 @@ static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size) memset(sghid, 0x00, sizeof(SigGroupHeadInitData)); - detect_siggroup_head_initdata_init_cnt++; - detect_siggroup_head_initdata_memory += sizeof(SigGroupHeadInitData); - /* initialize the signature bitarray */ sghid->sig_size = size; if ( (sghid->sig_array = SCMalloc(sghid->sig_size)) == NULL) @@ -100,9 +78,6 @@ static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size) memset(sghid->sig_array, 0, sghid->sig_size); - detect_siggroup_sigarray_init_cnt++; - detect_siggroup_sigarray_memory += sghid->sig_size; - return sghid; error: SigGroupHeadInitDataFree(sghid); @@ -152,9 +127,6 @@ static SigGroupHead *SigGroupHeadAlloc(const DetectEngineCtx *de_ctx, uint32_t s if (sgh->init == NULL) goto error; - detect_siggroup_head_init_cnt++; - detect_siggroup_head_memory += sizeof(SigGroupHead); - return sgh; error: @@ -175,8 +147,6 @@ void SigGroupHeadFree(SigGroupHead *sgh) SCLogDebug("sgh %p", sgh); if (sgh->match_array != NULL) { - detect_siggroup_matcharray_free_cnt++; - detect_siggroup_matcharray_memory -= (sgh->sig_cnt * sizeof(Signature *)); SCFree(sgh->match_array); sgh->match_array = NULL; } @@ -202,9 +172,6 @@ void SigGroupHeadFree(SigGroupHead *sgh) SCFree(sgh); - detect_siggroup_head_free_cnt++; - detect_siggroup_head_memory -= sizeof(SigGroupHead); - return; } @@ -476,62 +443,6 @@ void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, } } -/** - * \brief Prints the memory statistics for the detect-engine-siggroup.[ch] module. - */ -void DetectSigGroupPrintMemory(void) -{ - SCLogDebug(" * Sig group head memory stats (SigGroupHead %" PRIuMAX "):", - (uintmax_t)sizeof(SigGroupHead)); - SCLogDebug(" - detect_siggroup_head_memory %" PRIu32, - detect_siggroup_head_memory); - SCLogDebug(" - detect_siggroup_head_init_cnt %" PRIu32, - detect_siggroup_head_init_cnt); - SCLogDebug(" - detect_siggroup_head_free_cnt %" PRIu32, - detect_siggroup_head_free_cnt); - SCLogDebug(" - outstanding sig group heads %" PRIu32, - detect_siggroup_head_init_cnt - detect_siggroup_head_free_cnt); - SCLogDebug(" * Sig group head memory stats done"); - SCLogDebug(" * Sig group head initdata memory stats (SigGroupHeadInitData %" PRIuMAX "):", - (uintmax_t)sizeof(SigGroupHeadInitData)); - SCLogDebug(" - detect_siggroup_head_initdata_memory %" PRIu32, - detect_siggroup_head_initdata_memory); - SCLogDebug(" - detect_siggroup_head_initdata_init_cnt %" PRIu32, - detect_siggroup_head_initdata_init_cnt); - SCLogDebug(" - detect_siggroup_head_initdata_free_cnt %" PRIu32, - detect_siggroup_head_initdata_free_cnt); - SCLogDebug(" - outstanding sig group head initdatas %" PRIu32, - detect_siggroup_head_initdata_init_cnt - detect_siggroup_head_initdata_free_cnt); - SCLogDebug(" * Sig group head memory initdata stats done"); - SCLogDebug(" * Sig group sigarray memory stats:"); - SCLogDebug(" - detect_siggroup_sigarray_memory %" PRIu32, - detect_siggroup_sigarray_memory); - SCLogDebug(" - detect_siggroup_sigarray_init_cnt %" PRIu32, - detect_siggroup_sigarray_init_cnt); - SCLogDebug(" - detect_siggroup_sigarray_free_cnt %" PRIu32, - detect_siggroup_sigarray_free_cnt); - SCLogDebug(" - outstanding sig group sigarrays %" PRIu32, - (detect_siggroup_sigarray_init_cnt - - detect_siggroup_sigarray_free_cnt)); - SCLogDebug(" * Sig group sigarray memory stats done"); - SCLogDebug(" * Sig group matcharray memory stats:"); - SCLogDebug(" - detect_siggroup_matcharray_memory %" PRIu32, - detect_siggroup_matcharray_memory); - SCLogDebug(" - detect_siggroup_matcharray_init_cnt %" PRIu32, - detect_siggroup_matcharray_init_cnt); - SCLogDebug(" - detect_siggroup_matcharray_free_cnt %" PRIu32, - detect_siggroup_matcharray_free_cnt); - SCLogDebug(" - outstanding sig group matcharrays %" PRIu32, - (detect_siggroup_matcharray_init_cnt - - detect_siggroup_matcharray_free_cnt)); - SCLogDebug(" * Sig group sigarray memory stats done"); - SCLogDebug(" X Total %" PRIu32, - (detect_siggroup_head_memory + detect_siggroup_sigarray_memory + - detect_siggroup_matcharray_memory)); - - return; -} - /** * \brief Helper function used to print the list of sids for the Signatures * present in this SigGroupHead. @@ -589,9 +500,6 @@ int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, memset(sgh->match_array,0, sgh->sig_cnt * sizeof(Signature *)); - detect_siggroup_matcharray_init_cnt++; - detect_siggroup_matcharray_memory += (sgh->sig_cnt * sizeof(Signature *)); - for (sig = 0; sig < max_idx + 1; sig++) { if (!(sgh->init->sig_array[(sig / 8)] & (1 << (sig % 8))) ) continue; diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index 14b46609c4a9..7b88bbc7c715 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -24,8 +24,6 @@ #ifndef __DETECT_ENGINE_SIGGROUP_H__ #define __DETECT_ENGINE_SIGGROUP_H__ -void DetectSigGroupPrintMemory(void); - int SigGroupHeadAppendSig(const DetectEngineCtx *, SigGroupHead **, const Signature *); int SigGroupHeadClearSigs(SigGroupHead *); int SigGroupHeadCopySigs(DetectEngineCtx *, SigGroupHead *, SigGroupHead **); diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index d8ffc44b7910..3be710ac699b 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -9269,7 +9269,6 @@ static int DetectIPProtoTestSig1(void) UTHFreePacket(p); end: - DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); return result; } diff --git a/src/detect-rpc.c b/src/detect-rpc.c index 86fc03c645af..dfaf5f3f6f92 100644 --- a/src/detect-rpc.c +++ b/src/detect-rpc.c @@ -585,7 +585,6 @@ static int DetectRpcTestSig01(void) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); UTHFreePackets(&p, 1); end: diff --git a/src/detect.c b/src/detect.c index 2461a7f24a4e..164201794590 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3528,7 +3528,6 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) uint32_t cnt_deonly = 0; //DetectAddressPrintMemory(); - //DetectSigGroupPrintMemory(); //DetectPortPrintMemory(); if (!(de_ctx->flags & DE_QUIET)) { @@ -3624,7 +3623,6 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) } //DetectAddressPrintMemory(); - //DetectSigGroupPrintMemory(); //DetectPortPrintMemory(); if (!(de_ctx->flags & DE_QUIET)) { @@ -4180,7 +4178,6 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) DetectMpmPrepareAppMpms(de_ctx); // DetectAddressPrintMemory(); -// DetectSigGroupPrintMemory(); // DetectPortPrintMemory(); if (SigMatchPrepare(de_ctx) != 0) { @@ -8542,7 +8539,6 @@ static int SigTestMemory01 (void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); printf("@pre cleanup\n\n"); - DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); DetectPortPrintMemory(); @@ -8551,7 +8547,6 @@ printf("@pre cleanup\n\n"); DetectEngineCtxFree(de_ctx); printf("@exit\n\n"); - DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); DetectPortPrintMemory(); @@ -8592,11 +8587,9 @@ printf("@cleanup\n\n"); DetectEngineCtxFree(de_ctx); printf("@exit\n\n"); - DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); DetectPortPrintMemory(); printf("@exit\n\n"); - DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); DetectPortPrintMemory(); @@ -8641,7 +8634,6 @@ printf("@cleanup\n\n"); DetectEngineCtxFree(de_ctx); printf("@exit\n\n"); - DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); DetectPortPrintMemory(); From 9bd8197009ff36ffb7dbf8f6362f6f8570b0bd2b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 25 Mar 2016 12:27:11 +0100 Subject: [PATCH 1224/2553] detect-address: remove debug mem counters --- src/detect-engine-address.c | 66 ------------------------------------- src/detect-engine-address.h | 1 - src/detect-ipproto.c | 4 +-- src/detect-rpc.c | 1 - src/detect.c | 5 --- 5 files changed, 1 insertion(+), 76 deletions(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index c3ce599d3ff1..30bd5b7e729c 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -54,18 +54,6 @@ static int DetectAddressCut(DetectEngineCtx *, DetectAddress *, DetectAddress *, DetectAddress **); int DetectAddressMergeNot(DetectAddressHead *gh, DetectAddressHead *ghn); -/** memory usage counters - * \todo not MT safe */ -#ifdef DEBUG -static uint32_t detect_address_group_memory = 0; -static uint32_t detect_address_group_init_cnt = 0; -static uint32_t detect_address_group_free_cnt = 0; - -static uint32_t detect_address_group_head_memory = 0; -static uint32_t detect_address_group_head_init_cnt = 0; -static uint32_t detect_address_group_head_free_cnt = 0; -#endif - /** * \brief Creates and returns a new instance of a DetectAddress. * @@ -79,11 +67,6 @@ DetectAddress *DetectAddressInit(void) return NULL; memset(ag, 0, sizeof(DetectAddress)); -#ifdef DEBUG - detect_address_group_memory += sizeof(DetectAddress); - detect_address_group_init_cnt++; -#endif - return ag; } @@ -107,10 +90,6 @@ void DetectAddressFree(DetectAddress *ag) } ag->sh = NULL; -#ifdef DEBUG - detect_address_group_memory -= sizeof(DetectAddress); - detect_address_group_free_cnt++; -#endif SCFree(ag); return; @@ -140,42 +119,6 @@ DetectAddress *DetectAddressCopy(DetectAddress *orig) return ag; } -/** - * \brief Prints the memory statistics for the detection-engine-address section. - */ -void DetectAddressPrintMemory(void) -{ -#ifdef DEBUG - SCLogDebug(" * Address group memory stats (DetectAddress %" PRIuMAX "):", - (uintmax_t)sizeof(DetectAddress)); - SCLogDebug(" - detect_address_group_memory %" PRIu32, - detect_address_group_memory); - SCLogDebug(" - detect_address_group_init_cnt %" PRIu32, - detect_address_group_init_cnt); - SCLogDebug(" - detect_address_group_free_cnt %" PRIu32, - detect_address_group_free_cnt); - SCLogDebug(" - outstanding groups %" PRIu32, - detect_address_group_init_cnt - detect_address_group_free_cnt); - SCLogDebug(" * Address group memory stats done"); - SCLogDebug(" * Address group head memory stats (DetectAddressHead %" PRIuMAX "):", - (uintmax_t)sizeof(DetectAddressHead)); - SCLogDebug(" - detect_address_group_head_memory %" PRIu32, - detect_address_group_head_memory); - SCLogDebug(" - detect_address_group_head_init_cnt %" PRIu32, - detect_address_group_head_init_cnt); - SCLogDebug(" - detect_address_group_head_free_cnt %" PRIu32, - detect_address_group_head_free_cnt); - SCLogDebug(" - outstanding groups %" PRIu32, - (detect_address_group_head_init_cnt - - detect_address_group_head_free_cnt)); - SCLogDebug(" * Address group head memory stats done"); - SCLogDebug(" X Total %" PRIu32 "\n", (detect_address_group_memory + - detect_address_group_head_memory)); -#endif - - return; -} - /** * \brief Used to check if a DetectAddress list contains an instance with * a similar DetectAddress. The comparison done is not the one that @@ -1485,11 +1428,6 @@ DetectAddressHead *DetectAddressHeadInit(void) return NULL; memset(gh, 0, sizeof(DetectAddressHead)); -#ifdef DEBUG - detect_address_group_head_init_cnt++; - detect_address_group_head_memory += sizeof(DetectAddressHead); -#endif - return gh; } @@ -1531,10 +1469,6 @@ void DetectAddressHeadFree(DetectAddressHead *gh) if (gh != NULL) { DetectAddressHeadCleanup(gh); SCFree(gh); -#ifdef DEBUG - detect_address_group_head_free_cnt++; - detect_address_group_head_memory -= sizeof(DetectAddressHead); -#endif } return; diff --git a/src/detect-engine-address.h b/src/detect-engine-address.h index b29cff1b4c92..3b84f2257703 100644 --- a/src/detect-engine-address.h +++ b/src/detect-engine-address.h @@ -26,7 +26,6 @@ /* prototypes */ void DetectAddressRegister (void); -void DetectAddressPrintMemory(void); DetectAddressHead *DetectAddressHeadInit(void); void DetectAddressHeadFree(DetectAddressHead *); diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index 3be710ac699b..c0de5e95c10a 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -9241,7 +9241,7 @@ static int DetectIPProtoTestSig1(void) uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) - goto end; + return 0; char *sigs[4]; sigs[0] = "alert ip any any -> any any " @@ -9268,8 +9268,6 @@ static int DetectIPProtoTestSig1(void) result = UTHGenericTest(&p, 1, sigs, sid, results, 4); UTHFreePacket(p); -end: - DetectAddressPrintMemory(); return result; } diff --git a/src/detect-rpc.c b/src/detect-rpc.c index dfaf5f3f6f92..fe693deb19f8 100644 --- a/src/detect-rpc.c +++ b/src/detect-rpc.c @@ -585,7 +585,6 @@ static int DetectRpcTestSig01(void) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - DetectAddressPrintMemory(); UTHFreePackets(&p, 1); end: return result; diff --git a/src/detect.c b/src/detect.c index 164201794590..f89649da9782 100644 --- a/src/detect.c +++ b/src/detect.c @@ -8539,7 +8539,6 @@ static int SigTestMemory01 (void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); printf("@pre cleanup\n\n"); - DetectAddressPrintMemory(); DetectPortPrintMemory(); SigGroupCleanup(de_ctx); @@ -8547,7 +8546,6 @@ printf("@pre cleanup\n\n"); DetectEngineCtxFree(de_ctx); printf("@exit\n\n"); - DetectAddressPrintMemory(); DetectPortPrintMemory(); result = 1; @@ -8587,10 +8585,8 @@ printf("@cleanup\n\n"); DetectEngineCtxFree(de_ctx); printf("@exit\n\n"); - DetectAddressPrintMemory(); DetectPortPrintMemory(); printf("@exit\n\n"); - DetectAddressPrintMemory(); DetectPortPrintMemory(); result = 1; @@ -8634,7 +8630,6 @@ printf("@cleanup\n\n"); DetectEngineCtxFree(de_ctx); printf("@exit\n\n"); - DetectAddressPrintMemory(); DetectPortPrintMemory(); result = 1; From d5c6d08bc816321172992c17e83edb0575adf724 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 25 Mar 2016 12:28:33 +0100 Subject: [PATCH 1225/2553] detect-port: remove debug mem counters --- src/detect-engine-port.c | 25 ------------------------- src/detect-engine-port.h | 2 -- src/detect.c | 16 ---------------- 3 files changed, 43 deletions(-) diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index 8b4bafa7072c..e4d9008200d2 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -59,11 +59,6 @@ static int DetectPortCut(DetectEngineCtx *, DetectPort *, DetectPort *, DetectPort *PortParse(char *str); int DetectPortIsValidRange(char *); -/** Memory usage counters */ -static uint32_t detect_port_memory = 0; -static uint32_t detect_port_init_cnt = 0; -static uint32_t detect_port_free_cnt = 0; - /** * \brief Alloc a DetectPort structure and update counters * @@ -77,9 +72,6 @@ DetectPort *DetectPortInit(void) return NULL; memset(dp, 0, sizeof(DetectPort)); - detect_port_memory += sizeof(DetectPort); - detect_port_init_cnt++; - return dp; } @@ -99,26 +91,9 @@ void DetectPortFree(DetectPort *dp) } dp->sh = NULL; - detect_port_memory -= sizeof(DetectPort); - detect_port_free_cnt++; SCFree(dp); } -/** - * \brief Prints Memory statistics of the counters at detect-engine-port.[c,h] - */ -void DetectPortPrintMemory(void) -{ - SCLogDebug(" * Port memory stats (DetectPort %" PRIuMAX "):", - (uintmax_t)sizeof(DetectPort)); - SCLogDebug(" - detect_port_memory %" PRIu32 "", detect_port_memory); - SCLogDebug(" - detect_port_init_cnt %" PRIu32 "", detect_port_init_cnt); - SCLogDebug(" - detect_port_free_cnt %" PRIu32 "", detect_port_free_cnt); - SCLogDebug(" - outstanding ports %" PRIu32 "", - detect_port_init_cnt - detect_port_free_cnt); - SCLogDebug(" * Port memory stats done"); -} - /** * \brief Used to see if the exact same portrange exists in the list * diff --git a/src/detect-engine-port.h b/src/detect-engine-port.h index 9f9bef6ef726..924f710ce85d 100644 --- a/src/detect-engine-port.h +++ b/src/detect-engine-port.h @@ -35,8 +35,6 @@ void DetectPortCleanupList (DetectPort *head); DetectPort *DetectPortLookupGroup(DetectPort *dp, uint16_t port); -void DetectPortPrintMemory(void); - int DetectPortJoin(DetectEngineCtx *,DetectPort *target, DetectPort *source); void DetectPortPrint(DetectPort *); diff --git a/src/detect.c b/src/detect.c index f89649da9782..e94e2c605354 100644 --- a/src/detect.c +++ b/src/detect.c @@ -8538,16 +8538,10 @@ static int SigTestMemory01 (void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); -printf("@pre cleanup\n\n"); - DetectPortPrintMemory(); - SigGroupCleanup(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -printf("@exit\n\n"); - DetectPortPrintMemory(); - result = 1; end: SCFree(p); @@ -8580,15 +8574,9 @@ static int SigTestMemory02 (void) SigGroupBuild(de_ctx); -printf("@cleanup\n\n"); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); -printf("@exit\n\n"); - DetectPortPrintMemory(); -printf("@exit\n\n"); - DetectPortPrintMemory(); - result = 1; end: return result; @@ -8625,13 +8613,9 @@ static int SigTestMemory03 (void) SigGroupBuild(de_ctx); -printf("@cleanup\n\n"); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); -printf("@exit\n\n"); - DetectPortPrintMemory(); - result = 1; end: return result; From ef6f347f84f556dace8acce4a8fcc39d2c263aba Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 25 Mar 2016 12:32:49 +0100 Subject: [PATCH 1226/2553] detect-address: remove sgh pointer as it's unused --- src/detect-engine-address-ipv4.c | 74 ------- src/detect-engine-address-ipv6.c | 67 ------- src/detect-engine-address.c | 334 ------------------------------- src/detect.h | 5 - 4 files changed, 480 deletions(-) diff --git a/src/detect-engine-address-ipv4.c b/src/detect-engine-address-ipv4.c index ca3b76b1b3a4..9e78dab8cf41 100644 --- a/src/detect-engine-address-ipv4.c +++ b/src/detect-engine-address-ipv4.c @@ -158,11 +158,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c->ip2.addr_data32[0] = htonl(b_ip2); *c = tmp_c; - if (de_ctx != NULL) { - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - } - /* we have 3 parts: [bbb[baba]aaa] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> b_ip2 @@ -186,24 +181,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c->ip2.addr_data32[0] = htonl(a_ip2); *c = tmp_c; - if (de_ctx != NULL) { - /* 'a' gets clean and then 'b' sigs - * 'b' gets clean, then 'a' then 'b' sigs - * 'c' gets 'a' sigs */ - /* store old a list */ - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); - /* clean a list */ - SigGroupHeadClearSigs(a->sh); - /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &tmp_c->sh); - /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - /* prepend old a before b */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); - /* clean tmp list */ - SigGroupHeadClearSigs(tmp->sh); - } - /* we have 2 or three parts: * * 2 part: [[abab]bbb] or [bbb[baba]] @@ -232,10 +209,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, b->ip.addr_data32[0] = htonl(a_ip2 + 1); b->ip2.addr_data32[0] = htonl(b_ip2); - if (de_ctx != NULL) { - /* 'b' overlaps 'a' so 'a' needs the 'b' sigs */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - } } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); @@ -245,13 +218,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, b->ip.addr_data32[0] = htonl(a_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); - if (de_ctx != NULL) { - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadClearSigs(a->sh); - SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); - SigGroupHeadClearSigs(tmp->sh); - } } else { SCLogDebug("3"); @@ -269,24 +235,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c->ip.addr_data32[0] = htonl(a_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(b_ip2); *c = tmp_c; - - if (de_ctx != NULL) { - /* 'a' gets clean and then 'b' sigs - * 'b' gets clean, then 'a' then 'b' sigs - * 'c' gets 'b' sigs */ - /* store old a list */ - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); - /* clean a list */ - SigGroupHeadClearSigs(a->sh); - /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); - /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - /* prepend old a before b */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); - /* clean tmp list */ - SigGroupHeadClearSigs(tmp->sh); - } } /* we have 2 or three parts: * @@ -315,15 +263,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, b->ip.addr_data32[0] = htonl(b_ip2 + 1); b->ip2.addr_data32[0] = htonl(a_ip2); - - if (de_ctx != NULL) { - /* 'b' overlaps 'a' so a needs the 'b' sigs */ - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); - SigGroupHeadClearSigs(b->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); - SigGroupHeadClearSigs(tmp->sh); - } } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); @@ -332,11 +271,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, b->ip.addr_data32[0] = htonl(b_ip1); b->ip2.addr_data32[0] = htonl(b_ip2); - - if (de_ctx != NULL) { - /* 'a' overlaps 'b' so a needs the 'a' sigs */ - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - } } else { SCLogDebug("DetectAddressCutIPv4: 3"); @@ -354,14 +288,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c->ip.addr_data32[0] = htonl(b_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(a_ip2); *c = tmp_c; - - if (de_ctx != NULL) { - /* 'a' stays the same wrt sigs - * 'b' keeps it's own sigs and gets a's sigs prepended - * 'c' gets 'a' sigs */ - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp_c->sh); - } } } diff --git a/src/detect-engine-address-ipv6.c b/src/detect-engine-address-ipv6.c index fa692b1a0c6e..21d7f30bd2aa 100644 --- a/src/detect-engine-address-ipv6.c +++ b/src/detect-engine-address-ipv6.c @@ -406,11 +406,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, *c = tmp_c; - /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); - /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - /* we have 3 parts: [bbb[baba]aaa] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> b_ip2 @@ -433,23 +428,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6Copy(a_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; - /* 'a' gets clean and then 'b' sigs - * 'b' gets clean, then 'a' then 'b' sigs - * 'c' gets 'a' sigs */ - /* store old a list */ - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); - /* clean a list */ - SigGroupHeadClearSigs(a->sh); - /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &tmp_c->sh); - /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - /* prepend old a before b */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); - - /* clean tmp list */ - SigGroupHeadClearSigs(tmp->sh); - /* we have 2 or three parts: * * 2 part: [[abab]bbb] or [bbb[baba]] @@ -472,9 +450,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6CopyAddOne(a_ip2, b->ip.addr_data32); AddressCutIPv6Copy(b_ip2, b->ip2.addr_data32); - /* 'b' overlaps 'a' so 'a' needs the 'b' sigs */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - } else if (AddressIPv6EqU32(a_ip2, b_ip2) == 1) { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); @@ -482,12 +457,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6Copy(a_ip1, b->ip.addr_data32); AddressCutIPv6Copy(a_ip2, b->ip2.addr_data32); - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadClearSigs(a->sh); - SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); - SigGroupHeadClearSigs(tmp->sh); - } else { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); @@ -505,23 +474,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6Copy(b_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; - /* 'a' gets clean and then 'b' sigs - * 'b' gets clean, then 'a' then 'b' sigs - * 'c' gets 'b' sigs */ - /* store old a list */ - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); - /* clean a list */ - SigGroupHeadClearSigs(a->sh); - /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); - /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - /* prepend old a before b */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); - - /* clean tmp list */ - SigGroupHeadClearSigs(tmp->sh); - } /* we have 2 or three parts: * @@ -544,24 +496,12 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6CopyAddOne(b_ip2, b->ip.addr_data32); AddressCutIPv6Copy(a_ip2, b->ip2.addr_data32); - - /* 'b' overlaps 'a' so a needs the 'b' sigs */ - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); - SigGroupHeadClearSigs(b->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); - SigGroupHeadClearSigs(tmp->sh); - } else if (AddressIPv6EqU32(a_ip2, b_ip2) == 1) { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(b_ip1, a->ip2.addr_data32); AddressCutIPv6Copy(b_ip1, b->ip.addr_data32); AddressCutIPv6Copy(b_ip2, b->ip2.addr_data32); - - /* 'a' overlaps 'b' so a needs the 'a' sigs */ - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - } else { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(b_ip1, a->ip2.addr_data32); @@ -578,13 +518,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6CopyAddOne(b_ip2, tmp_c->ip.addr_data32); AddressCutIPv6Copy(a_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; - - /* 'a' stays the same wrt sigs - * 'b' keeps it's own sigs and gets a's sigs prepended - * 'c' gets 'a' sigs */ - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp_c->sh); - } } diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 30bd5b7e729c..1c65198aaba5 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -80,16 +80,6 @@ void DetectAddressFree(DetectAddress *ag) if (ag == NULL) return; - SCLogDebug("ag %p, sh %p", ag, ag->sh); - - /* only free the head if we have the original */ - if (ag->sh != NULL && !(ag->flags & ADDRESS_SIGGROUPHEAD_COPY)) { - SCLogDebug("- ag %p, sh %p not a copy, so call SigGroupHeadFree", ag, - ag->sh); - SigGroupHeadFree(ag->sh); - } - ag->sh = NULL; - SCFree(ag); return; @@ -159,7 +149,6 @@ void DetectAddressPrintList(DetectAddress *head) SCLogInfo("list:"); if (head != NULL) { for (cur = head; cur != NULL; cur = cur->next) { - SCLogInfo("SIGS %6u ", cur->sh ? cur->sh->sig_cnt : 0); DetectAddressPrint(cur); } } @@ -332,9 +321,7 @@ int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, if (r == ADDRESS_EQ) { /* exact overlap/match */ if (cur != new) { - SigGroupHeadCopySigs(de_ctx, new->sh, &cur->sh); DetectAddressFree(new); - return 0; } @@ -450,8 +437,6 @@ int DetectAddressJoin(DetectEngineCtx *de_ctx, DetectAddress *target, if (target->ip.family != source->ip.family) return -1; - SigGroupHeadCopySigs(de_ctx, source->sh, &target->sh); - if (target->ip.family == AF_INET) return DetectAddressJoinIPv4(de_ctx, target, source); else if (target->ip.family == AF_INET6) @@ -4823,320 +4808,6 @@ int AddressConfVarsTest05(void) return result; } -#include "detect-engine.h" - -/** - * \test Test sig distribution over address groups - */ -static int AddressTestFunctions01(void) -{ - DetectAddress *a1 = NULL; - DetectAddress *a2 = NULL; - DetectAddressHead *h = NULL; - int result = 0; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - Signature s[2]; - memset(s,0x00,sizeof(s)); - - s[0].num = 0; - s[1].num = 1; - - a1 = DetectAddressParseSingle("255.0.0.0/8"); - if (a1 == NULL) { - printf("a1 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); - - a2 = DetectAddressParseSingle("0.0.0.0/0"); - if (a2 == NULL) { - printf("a2 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); - - SCLogDebug("a1"); - DetectAddressPrint(a1); - SCLogDebug("a2"); - DetectAddressPrint(a2); - - h = DetectAddressHeadInit(); - if (h == NULL) - goto end; - DetectAddressInsert(de_ctx, h, a1); - DetectAddressInsert(de_ctx, h, a2); - - if (h == NULL) - goto end; - - DetectAddress *x = h->ipv4_head; - for ( ; x != NULL; x = x->next) { - SCLogDebug("x %p next %p", x, x->next); - DetectAddressPrint(x); - //SigGroupHeadPrintSigs(de_ctx, x->sh); - } - - DetectAddress *one = h->ipv4_head; - DetectAddress *two = one->next; - - int sig = 0; - if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'two', but it shouldn't: ", sig); - goto end; - } - - result = 1; -end: - if (h != NULL) - DetectAddressHeadFree(h); - return result; -} - -/** - * \test Test sig distribution over address groups - */ -static int AddressTestFunctions02(void) -{ - DetectAddress *a1 = NULL; - DetectAddress *a2 = NULL; - DetectAddressHead *h = NULL; - int result = 0; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - Signature s[2]; - memset(s,0x00,sizeof(s)); - - s[0].num = 0; - s[1].num = 1; - - a1 = DetectAddressParseSingle("255.0.0.0/8"); - if (a1 == NULL) { - printf("a1 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); - - a2 = DetectAddressParseSingle("0.0.0.0/0"); - if (a2 == NULL) { - printf("a2 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); - - SCLogDebug("a1"); - DetectAddressPrint(a1); - SCLogDebug("a2"); - DetectAddressPrint(a2); - - h = DetectAddressHeadInit(); - if (h == NULL) - goto end; - DetectAddressInsert(de_ctx, h, a2); - DetectAddressInsert(de_ctx, h, a1); - - BUG_ON(h == NULL); - - SCLogDebug("dp3"); - - DetectAddress *x = h->ipv4_head; - for ( ; x != NULL; x = x->next) { - DetectAddressPrint(x); - //SigGroupHeadPrintSigs(de_ctx, x->sh); - } - - DetectAddress *one = h->ipv4_head; - DetectAddress *two = one->next; - - int sig = 0; - if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'two', but it shouldn't: ", sig); - goto end; - } - - result = 1; -end: - if (h != NULL) - DetectAddressHeadFree(h); - return result; -} - -/** - * \test Test sig distribution over address groups - */ -static int AddressTestFunctions03(void) -{ - DetectAddress *a1 = NULL; - DetectAddress *a2 = NULL; - DetectAddressHead *h = NULL; - int result = 0; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - Signature s[2]; - memset(s,0x00,sizeof(s)); - - s[0].num = 0; - s[1].num = 1; - - a1 = DetectAddressParseSingle("ffff::/16"); - if (a1 == NULL) { - printf("a1 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); - - a2 = DetectAddressParseSingle("::/0"); - if (a2 == NULL) { - printf("a2 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); - - SCLogDebug("a1"); - DetectAddressPrint(a1); - SCLogDebug("a2"); - DetectAddressPrint(a2); - - h = DetectAddressHeadInit(); - if (h == NULL) - goto end; - DetectAddressInsert(de_ctx, h, a1); - DetectAddressInsert(de_ctx, h, a2); - - if (h == NULL) - goto end; - - DetectAddress *x = h->ipv6_head; - for ( ; x != NULL; x = x->next) { - SCLogDebug("x %p next %p", x, x->next); - DetectAddressPrint(x); - //SigGroupHeadPrintSigs(de_ctx, x->sh); - } - - DetectAddress *one = h->ipv6_head; - DetectAddress *two = one->next; - - int sig = 0; - if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'two', but it shouldn't: ", sig); - goto end; - } - - result = 1; -end: - if (h != NULL) - DetectAddressHeadFree(h); - return result; -} - -/** - * \test Test sig distribution over address groups - */ -static int AddressTestFunctions04(void) -{ - DetectAddress *a1 = NULL; - DetectAddress *a2 = NULL; - DetectAddressHead *h = NULL; - int result = 0; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - Signature s[2]; - memset(s,0x00,sizeof(s)); - - s[0].num = 0; - s[1].num = 1; - - a1 = DetectAddressParseSingle("ffff::/16"); - if (a1 == NULL) { - printf("a1 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); - - a2 = DetectAddressParseSingle("::/0"); - if (a2 == NULL) { - printf("a2 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); - - SCLogDebug("a1"); - DetectAddressPrint(a1); - SCLogDebug("a2"); - DetectAddressPrint(a2); - - h = DetectAddressHeadInit(); - if (h == NULL) - goto end; - DetectAddressInsert(de_ctx, h, a2); - DetectAddressInsert(de_ctx, h, a1); - - BUG_ON(h == NULL); - - SCLogDebug("dp3"); - - DetectAddress *x = h->ipv6_head; - for ( ; x != NULL; x = x->next) { - DetectAddressPrint(x); - //SigGroupHeadPrintSigs(de_ctx, x->sh); - } - - DetectAddress *one = h->ipv6_head; - DetectAddress *two = one->next; - - int sig = 0; - if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'two', but it shouldn't: ", sig); - goto end; - } - - result = 1; -end: - if (h != NULL) - DetectAddressHeadFree(h); - return result; -} - #endif /* UNITTESTS */ void DetectAddressTests(void) @@ -5339,10 +5010,5 @@ void DetectAddressTests(void) UtRegisterTest("AddressConfVarsTest03 ", AddressConfVarsTest03, 1); UtRegisterTest("AddressConfVarsTest04 ", AddressConfVarsTest04, 1); UtRegisterTest("AddressConfVarsTest05 ", AddressConfVarsTest05, 1); - - UtRegisterTest("AddressTestFunctions01", AddressTestFunctions01, 1); - UtRegisterTest("AddressTestFunctions02", AddressTestFunctions02, 1); - UtRegisterTest("AddressTestFunctions03", AddressTestFunctions03, 1); - UtRegisterTest("AddressTestFunctions04", AddressTestFunctions04, 1); #endif /* UNITTESTS */ } diff --git a/src/detect.h b/src/detect.h index 2aa20bfa8bd9..663fbc2b0b31 100644 --- a/src/detect.h +++ b/src/detect.h @@ -164,8 +164,6 @@ enum { #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 */ - /** \brief address structure for use in the detection engine. * * Contains the address information and matching information. @@ -175,9 +173,6 @@ typedef struct DetectAddress_ { Address ip; Address ip2; - /** signatures that belong in this group */ - struct SigGroupHead_ *sh; - /** flags affecting this address */ uint8_t flags; From adc453eec6e61db7520bb3fe0dd8ad4a249486a6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 25 Mar 2016 12:48:08 +0100 Subject: [PATCH 1227/2553] detect-port: improve comment about sgh pointer --- src/detect.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/detect.h b/src/detect.h index 663fbc2b0b31..6abd89379447 100644 --- a/src/detect.h +++ b/src/detect.h @@ -229,7 +229,11 @@ typedef struct DetectPort_ { uint8_t flags; /**< flags for this port */ - /* signatures that belong in this group */ + /* 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; From e2789a87c2a7d3a575fc197cae49a399085e30f7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 25 Mar 2016 12:55:23 +0100 Subject: [PATCH 1228/2553] detect: shrink IPOnlyCIDRItem with 8 bytes --- src/detect.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect.h b/src/detect.h index 6abd89379447..3bee26fcd93e 100644 --- a/src/detect.h +++ b/src/detect.h @@ -312,12 +312,12 @@ typedef struct DetectPort_ { 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; + + uint32_t ip[4]; SigIntId signum; /**< our internal id */ /* linked list, the header should be the biggest network */ From f1ee1258107945f6ab8316093e5e7241462f95b5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 25 Mar 2016 12:58:55 +0100 Subject: [PATCH 1229/2553] detect-flowvar: shrink mem structure by 8 bytes --- src/detect.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect.h b/src/detect.h index 3bee26fcd93e..e321d5ca1d2a 100644 --- a/src/detect.h +++ b/src/detect.h @@ -461,9 +461,9 @@ typedef struct DetectReplaceList_ { typedef struct DetectFlowvarList_ { uint16_t idx; /**< flowvar name idx */ uint16_t len; /**< data len */ + int type; /**< type of store candidate POSTMATCH or ALWAYS */ 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; From 9b6e292a28ac862684056f8dee912f0629590cbf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 25 Mar 2016 13:11:04 +0100 Subject: [PATCH 1230/2553] mpm: remove unused max pattern len field --- src/util-mpm-ac-bs.c | 3 --- src/util-mpm-ac-tile.c | 2 -- src/util-mpm-ac.c | 6 ------ src/util-mpm-hs.c | 2 -- src/util-mpm.h | 3 +-- 5 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index f8e313a17545..3c3eac540bc8 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -95,9 +95,6 @@ typedef struct StateQueue_ { void MpmACBSRegister(void) { mpm_table[MPM_AC_BS].name = "ac-bs"; - /* don't need this. isn't that awesome? no more chopping and blah blah */ - mpm_table[MPM_AC_BS].max_pattern_length = 0; - mpm_table[MPM_AC_BS].InitCtx = SCACBSInitCtx; mpm_table[MPM_AC_BS].InitThreadCtx = SCACBSInitThreadCtx; mpm_table[MPM_AC_BS].DestroyCtx = SCACBSDestroyCtx; diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 72b293696214..3d7b3b5a91f2 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -1490,8 +1490,6 @@ void MpmACTileRegister(void) #else mpm_table[MPM_AC_TILE].name = "ac-ks"; #endif - mpm_table[MPM_AC_TILE].max_pattern_length = 0; - mpm_table[MPM_AC_TILE].InitCtx = SCACTileInitCtx; mpm_table[MPM_AC_TILE].InitThreadCtx = SCACTileInitThreadCtx; mpm_table[MPM_AC_TILE].DestroyCtx = SCACTileDestroyCtx; diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index fe37af19baee..6c3370b0d42d 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -1755,9 +1755,6 @@ int MpmCudaBufferDeSetup(void) void MpmACRegister(void) { mpm_table[MPM_AC].name = "ac"; - /* don't need this. isn't that awesome? no more chopping and blah blah */ - mpm_table[MPM_AC].max_pattern_length = 0; - mpm_table[MPM_AC].InitCtx = SCACInitCtx; mpm_table[MPM_AC].InitThreadCtx = SCACInitThreadCtx; mpm_table[MPM_AC].DestroyCtx = SCACDestroyCtx; @@ -1782,9 +1779,6 @@ void MpmACRegister(void) void MpmACCudaRegister(void) { mpm_table[MPM_AC_CUDA].name = "ac-cuda"; - /* don't need this. isn't that awesome? no more chopping and blah blah */ - mpm_table[MPM_AC_CUDA].max_pattern_length = 0; - mpm_table[MPM_AC_CUDA].InitCtx = SCACInitCtx; mpm_table[MPM_AC_CUDA].InitThreadCtx = SCACInitThreadCtx; mpm_table[MPM_AC_CUDA].DestroyCtx = SCACDestroyCtx; diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index e71a533d128d..b046bfc94094 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -1057,8 +1057,6 @@ void SCHSPrintInfo(MpmCtx *mpm_ctx) void MpmHSRegister(void) { mpm_table[MPM_HS].name = "hs"; - mpm_table[MPM_HS].max_pattern_length = 0; - mpm_table[MPM_HS].InitCtx = SCHSInitCtx; mpm_table[MPM_HS].InitThreadCtx = SCHSInitThreadCtx; mpm_table[MPM_HS].DestroyCtx = SCHSDestroyCtx; diff --git a/src/util-mpm.h b/src/util-mpm.h index d689cc9fc433..2c165bedab03 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -152,8 +152,7 @@ typedef struct MpmCtxFactoryContainer_ { #define MPM_PATTERN_CTX_OWNS_ID 0x20 typedef struct MpmTableElmt_ { - char *name; - uint8_t max_pattern_length; + const char *name; void (*InitCtx)(struct MpmCtx_ *); void (*InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *); void (*DestroyCtx)(struct MpmCtx_ *); From 2ee3e726a9f4f5b68213a68dda82599d8523db22 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 5 Apr 2016 12:59:54 +0200 Subject: [PATCH 1231/2553] detect: don't set unused variable detect.c:3801:13: warning: Value stored to 'tmplist2_tail' is never read tmplist2_tail = joingr; ^ ~~~~~~ detect.c:3804:13: warning: Value stored to 'tmplist2_tail' is never read tmplist2_tail = joingr; ^ ~~~~~~ 2 warnings generated. --- src/detect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index e94e2c605354..a93696fd6942 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3798,10 +3798,10 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, Detect if (tmplist2 == NULL) { tmplist2 = joingr; - tmplist2_tail = joingr; + //tmplist2_tail = joingr; } else { tmplist2_tail->next = joingr; - tmplist2_tail = joingr; + //tmplist2_tail = joingr; } } else { SCLogDebug("no joingr"); From dc008206e346ea339af8a2e3c600eafe98ac187f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 5 Apr 2016 13:05:08 +0200 Subject: [PATCH 1232/2553] detect: fix scan-build warning detect-engine-siggroup.c:700:38: warning: Call to 'malloc' has an allocation size of 0 bytes sgh->non_mpm_other_store_array = SCMalloc(non_mpm * sizeof(SignatureNonMpmStore)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./util-mem.h:177:14: note: expanded from macro 'SCMalloc' ptrmem = malloc((a)); \ ^~~~~~~~~~~ 1 warning generated. --- src/detect-engine-siggroup.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 60217690835f..b3b40ab127be 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -697,13 +697,17 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return 0; } - sgh->non_mpm_other_store_array = SCMalloc(non_mpm * sizeof(SignatureNonMpmStore)); - BUG_ON(sgh->non_mpm_other_store_array == NULL); - memset(sgh->non_mpm_other_store_array, 0, non_mpm * sizeof(SignatureNonMpmStore)); + if (non_mpm > 0) { + sgh->non_mpm_other_store_array = SCMalloc(non_mpm * sizeof(SignatureNonMpmStore)); + BUG_ON(sgh->non_mpm_other_store_array == NULL); + memset(sgh->non_mpm_other_store_array, 0, non_mpm * sizeof(SignatureNonMpmStore)); + } - sgh->non_mpm_syn_store_array = SCMalloc(non_mpm_syn * sizeof(SignatureNonMpmStore)); - BUG_ON(sgh->non_mpm_syn_store_array == NULL); - memset(sgh->non_mpm_syn_store_array, 0, non_mpm_syn * sizeof(SignatureNonMpmStore)); + if (non_mpm_syn > 0) { + sgh->non_mpm_syn_store_array = SCMalloc(non_mpm_syn * sizeof(SignatureNonMpmStore)); + BUG_ON(sgh->non_mpm_syn_store_array == NULL); + memset(sgh->non_mpm_syn_store_array, 0, non_mpm_syn * sizeof(SignatureNonMpmStore)); + } for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; @@ -713,12 +717,14 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) if (s->mpm_sm == NULL || (s->flags & SIG_FLAG_MPM_NEG)) { if (!(DetectFlagsSignatureNeedsSynPackets(s))) { BUG_ON(sgh->non_mpm_other_store_cnt >= non_mpm); + BUG_ON(sgh->non_mpm_other_store_array == NULL); sgh->non_mpm_other_store_array[sgh->non_mpm_other_store_cnt].id = s->num; sgh->non_mpm_other_store_array[sgh->non_mpm_other_store_cnt].mask = s->mask; sgh->non_mpm_other_store_cnt++; } BUG_ON(sgh->non_mpm_syn_store_cnt >= non_mpm_syn); + BUG_ON(sgh->non_mpm_syn_store_array == NULL); sgh->non_mpm_syn_store_array[sgh->non_mpm_syn_store_cnt].id = s->num; sgh->non_mpm_syn_store_array[sgh->non_mpm_syn_store_cnt].mask = s->mask; sgh->non_mpm_syn_store_cnt++; From d085362e610f1a64e08132d40890c791757c28e5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 5 Apr 2016 13:14:03 +0200 Subject: [PATCH 1233/2553] detect: fix error handling in mpm setup *** CID 1358124: Null pointer dereferences (REVERSE_INULL) /src/detect-engine-mpm.c: 940 in MpmStoreSetup() 934 PopulateMpmHelperAddPatternToPktCtx(ms->mpm_ctx, 935 cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); 936 } 937 } 938 } 939 >>> CID 1358124: Null pointer dereferences (REVERSE_INULL) >>> Null-checking "ms->mpm_ctx" suggests that it may be null, but it has already been dereferenced on all paths leading to the check. 940 if (ms->mpm_ctx != NULL) { 941 if (ms->mpm_ctx->pattern_cnt == 0) { 942 MpmFactoryReClaimMpmCtx(de_ctx, ms->mpm_ctx); 943 ms->mpm_ctx = NULL; 944 } else { 945 if (ms->sgh_mpm_context == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { --- src/detect-engine-mpm.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index eb7edcbe54b5..39393e2bcbd9 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -895,6 +895,9 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) } ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, ms->sgh_mpm_context, dir); + if (ms->mpm_ctx == NULL) + return; + MpmInitCtx(ms->mpm_ctx, de_ctx->mpm_matcher); /* add the patterns */ @@ -937,15 +940,13 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) } } - if (ms->mpm_ctx != NULL) { - if (ms->mpm_ctx->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, ms->mpm_ctx); - ms->mpm_ctx = NULL; - } else { - if (ms->sgh_mpm_context == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { - if (mpm_table[ms->mpm_ctx->mpm_type].Prepare != NULL) { - mpm_table[ms->mpm_ctx->mpm_type].Prepare(ms->mpm_ctx); - } + if (ms->mpm_ctx->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, ms->mpm_ctx); + ms->mpm_ctx = NULL; + } else { + if (ms->sgh_mpm_context == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + if (mpm_table[ms->mpm_ctx->mpm_type].Prepare != NULL) { + mpm_table[ms->mpm_ctx->mpm_type].Prepare(ms->mpm_ctx); } } } From 7ef8558e79d1a2b2c9155599676d16a2db7f632b Mon Sep 17 00:00:00 2001 From: Torgeir Natvig Date: Wed, 6 Apr 2016 16:08:39 +0200 Subject: [PATCH 1234/2553] lua_close() segfaults on null pointers --- src/output-lua.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/output-lua.c b/src/output-lua.c index 041e83efe783..c671bc4a687a 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -731,7 +731,8 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { lua_close(luastate); return 0; error: - lua_close(luastate); + if (luastate) + lua_close(luastate); return -1; } @@ -796,7 +797,8 @@ static lua_State *LuaScriptSetup(const char *filename) SCLogDebug("lua_State %p is set up", luastate); return luastate; error: - lua_close(luastate); + if (luastate) + lua_close(luastate); return NULL; } From 38f67d88ea996e6af00398deb8facb5e7c2b4a05 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 16 Dec 2015 13:10:05 +0100 Subject: [PATCH 1235/2553] tcp: reduce TCP options storage in packets Until now, the TCP options would all be stored in the Packet structure. The commonly used ones (wscale, ts, sack, sackok and mss*) then had a pointer to the position in the option array. Overall this option array was large. About 360 bytes on 64bit systems. Since no part of the engine would every access this array other than through the common short cuts, this was actually just wasteful. This patch changes the approach. It stores just the common ones in the packet. The rest is gone. This shrinks the packet structure with almost 300 bytes. * even though mss wasn't actually used --- src/decode-tcp.c | 68 +++++++++++++++++++++++++++--------------------- src/decode-tcp.h | 49 +++++++++++++++++----------------- src/stream-tcp.c | 62 +++++++++++++++++-------------------------- 3 files changed, 87 insertions(+), 92 deletions(-) diff --git a/src/decode-tcp.c b/src/decode-tcp.c index 428e7ae4e390..ae3650be11cf 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -42,8 +42,16 @@ #include "pkt-var.h" #include "host.h" +#define SET_OPTS(dst, src) \ + (dst).type = (src).type; \ + (dst).len = (src).len; \ + (dst).data = (src).data + static int DecodeTCPOptions(Packet *p, uint8_t *pkt, uint16_t len) { + uint8_t tcp_opt_cnt = 0; + TCPOpt tcp_opts[TCP_OPTMAX]; + uint16_t plen = len; while (plen) { @@ -68,81 +76,81 @@ static int DecodeTCPOptions(Packet *p, uint8_t *pkt, uint16_t len) return -1; } - p->TCP_OPTS[p->TCP_OPTS_CNT].type = *pkt; - p->TCP_OPTS[p->TCP_OPTS_CNT].len = *(pkt+1); + tcp_opts[tcp_opt_cnt].type = *pkt; + tcp_opts[tcp_opt_cnt].len = *(pkt+1); if (plen > 2) - p->TCP_OPTS[p->TCP_OPTS_CNT].data = (pkt+2); + tcp_opts[tcp_opt_cnt].data = (pkt+2); else - p->TCP_OPTS[p->TCP_OPTS_CNT].data = NULL; + tcp_opts[tcp_opt_cnt].data = NULL; /* we are parsing the most commonly used opts to prevent * us from having to walk the opts list for these all the * time. */ - switch (p->TCP_OPTS[p->TCP_OPTS_CNT].type) { + switch (tcp_opts[tcp_opt_cnt].type) { case TCP_OPT_WS: - if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_WS_LEN) { + if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_WS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.ws != NULL) { + if (p->tcpvars.ws.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - p->tcpvars.ws = &p->TCP_OPTS[p->TCP_OPTS_CNT]; + SET_OPTS(p->tcpvars.ws, tcp_opts[tcp_opt_cnt]); } } break; case TCP_OPT_MSS: - if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_MSS_LEN) { + if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_MSS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.mss != NULL) { + if (p->tcpvars.mss.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - p->tcpvars.mss = &p->TCP_OPTS[p->TCP_OPTS_CNT]; + SET_OPTS(p->tcpvars.mss, tcp_opts[tcp_opt_cnt]); } } break; case TCP_OPT_SACKOK: - if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_SACKOK_LEN) { + if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_SACKOK_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.sackok != NULL) { + if (p->tcpvars.sackok.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - p->tcpvars.sackok = &p->TCP_OPTS[p->TCP_OPTS_CNT]; + SET_OPTS(p->tcpvars.sackok, tcp_opts[tcp_opt_cnt]); } } break; case TCP_OPT_TS: - if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_TS_LEN) { + if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_TS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.ts != NULL) { + if (p->tcpvars.ts.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - p->tcpvars.ts = &p->TCP_OPTS[p->TCP_OPTS_CNT]; + SET_OPTS(p->tcpvars.ts, tcp_opts[tcp_opt_cnt]); } } break; case TCP_OPT_SACK: - SCLogDebug("SACK option, len %u", p->TCP_OPTS[p->TCP_OPTS_CNT].len); - if (p->TCP_OPTS[p->TCP_OPTS_CNT].len < TCP_OPT_SACK_MIN_LEN || - p->TCP_OPTS[p->TCP_OPTS_CNT].len > TCP_OPT_SACK_MAX_LEN || - !((p->TCP_OPTS[p->TCP_OPTS_CNT].len - 2) % 8 == 0)) + SCLogDebug("SACK option, len %u", tcp_opts[tcp_opt_cnt].len); + if (tcp_opts[tcp_opt_cnt].len < TCP_OPT_SACK_MIN_LEN || + tcp_opts[tcp_opt_cnt].len > TCP_OPT_SACK_MAX_LEN || + !((tcp_opts[tcp_opt_cnt].len - 2) % 8 == 0)) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.sack != NULL) { + if (p->tcpvars.sack.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - p->tcpvars.sack = &p->TCP_OPTS[p->TCP_OPTS_CNT]; + SET_OPTS(p->tcpvars.sack, tcp_opts[tcp_opt_cnt]); } } break; } - pkt += p->TCP_OPTS[p->TCP_OPTS_CNT].len; - plen -= (p->TCP_OPTS[p->TCP_OPTS_CNT].len); - p->TCP_OPTS_CNT++; + pkt += tcp_opts[tcp_opt_cnt].len; + plen -= (tcp_opts[tcp_opt_cnt].len); + tcp_opt_cnt++; } } return 0; @@ -197,9 +205,9 @@ int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui #ifdef DEBUG SCLogDebug("TCP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 " %s%s%s%s%s", GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_HLEN(p), len, - p->tcpvars.sackok ? "SACKOK " : "", p->tcpvars.sack ? "SACK " : "", - p->tcpvars.ws ? "WS " : "", p->tcpvars.ts ? "TS " : "", - p->tcpvars.mss ? "MSS " : ""); + TCP_HAS_SACKOK(p) ? "SACKOK " : "", TCP_HAS_SACK(p) ? "SACK " : "", + TCP_HAS_WSCALE(p) ? "WS " : "", TCP_HAS_TS(p) ? "TS " : "", + TCP_HAS_MSS(p) ? "MSS " : ""); #endif /* Flow is an integral part of us */ @@ -468,7 +476,7 @@ static int TCPGetSackTest01(void) goto end; } - if (p->tcpvars.sack == NULL) { + if (!TCP_HAS_SACK(p)) { printf("tcp packet sack not decoded: "); goto end; } diff --git a/src/decode-tcp.h b/src/decode-tcp.h index 29c02dfb2fea..955800e17ade 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -62,9 +62,6 @@ /** Max valid wscale value. */ #define TCP_WSCALE_MAX 14 -#define TCP_OPTS tcpvars.tcp_opts -#define TCP_OPTS_CNT tcpvars.tcp_opt_cnt - #define TCP_GET_RAW_OFFSET(tcph) (((tcph)->th_offx2 & 0xf0) >> 4) #define TCP_GET_RAW_X2(tcph) (unsigned char)((tcph)->th_offx2 & 0x0f) #define TCP_GET_RAW_SRC_PORT(tcph) ntohs((tcph)->th_sport) @@ -82,19 +79,27 @@ /** macro for getting the first timestamp from the packet. Timestamp is in host * order and either returned from the cache or from the packet directly. */ #define TCP_GET_TSVAL(p) \ - (uint32_t)ntohl((*(uint32_t *)(p)->tcpvars.ts->data)) + (uint32_t)ntohl((*(uint32_t *)(p)->tcpvars.ts.data)) /** macro for getting the second timestamp from the packet. Timestamp is in * host order and either returned from the cache or from the packet directly. */ #define TCP_GET_TSECR(p) \ - (uint32_t)ntohl((*(uint32_t *)((p)->tcpvars.ts->data+4))) + (uint32_t)ntohl((*(uint32_t *)((p)->tcpvars.ts.data+4))) + +#define TCP_HAS_WSCALE(p) ((p)->tcpvars.ws.type == TCP_OPT_WS) +#define TCP_HAS_SACK(p) ((p)->tcpvars.sack.type == TCP_OPT_SACK) +#define TCP_HAS_SACKOK(p) ((p)->tcpvars.sackok.type == TCP_OPT_SACKOK) +#define TCP_HAS_TS(p) ((p)->tcpvars.ts.type == TCP_OPT_TS) +#define TCP_HAS_MSS(p) ((p)->tcpvars.mss.type == TCP_OPT_MSS) /** macro for getting the wscale from the packet. */ -#define TCP_GET_WSCALE(p) ((p)->tcpvars.ws ? (((*(uint8_t *)(p)->tcpvars.ws->data) <= TCP_WSCALE_MAX) ? (*(uint8_t *)((p)->tcpvars.ws->data)) : 0) : 0) +#define TCP_GET_WSCALE(p) (TCP_HAS_WSCALE((p)) ? \ + (((*(uint8_t *)(p)->tcpvars.ws.data) <= TCP_WSCALE_MAX) ? \ + (*(uint8_t *)((p)->tcpvars.ws.data)) : 0) : 0) -#define TCP_GET_SACKOK(p) ((p)->tcpvars.sackok ? 1 : 0) -#define TCP_GET_SACK_PTR(p) (p)->tcpvars.sack ? (p)->tcpvars.sack->data : NULL -#define TCP_GET_SACK_CNT(p) ((p)->tcpvars.sack ? (((p)->tcpvars.sack->len - 2) / 8) : 0) +#define TCP_GET_SACKOK(p) (TCP_HAS_SACKOK((p)) ? 1 : 0) +#define TCP_GET_SACK_PTR(p) TCP_HAS_SACK((p)) ? (p)->tcpvars.sack.data : NULL +#define TCP_GET_SACK_CNT(p) (TCP_HAS_SACK((p)) ? (((p)->tcpvars.sack.len - 2) / 8) : 0) #define TCP_GET_OFFSET(p) TCP_GET_RAW_OFFSET((p)->tcph) #define TCP_GET_HLEN(p) (TCP_GET_OFFSET((p)) << 2) @@ -140,26 +145,22 @@ typedef struct TCPHdr_ typedef struct TCPVars_ { - uint8_t tcp_opt_cnt; - TCPOpt tcp_opts[TCP_OPTMAX]; - - /* ptrs to commonly used and needed opts */ - TCPOpt *ts; - TCPOpt *sack; - TCPOpt *sackok; - TCPOpt *ws; - TCPOpt *mss; + /* commonly used and needed opts */ + TCPOpt ts; + TCPOpt sack; + TCPOpt sackok; + TCPOpt ws; + TCPOpt mss; } TCPVars; #define CLEAR_TCP_PACKET(p) { \ (p)->tcph = NULL; \ (p)->level4_comp_csum = -1; \ - (p)->tcpvars.tcp_opt_cnt = 0; \ - (p)->tcpvars.ts = NULL; \ - (p)->tcpvars.sack = NULL; \ - (p)->tcpvars.sackok = NULL; \ - (p)->tcpvars.ws = NULL; \ - (p)->tcpvars.mss = NULL; \ + (p)->tcpvars.ts.type = 0; \ + (p)->tcpvars.sack.type = 0; \ + (p)->tcpvars.sackok.type = 0; \ + (p)->tcpvars.ws.type = 0; \ + (p)->tcpvars.mss.type = 0; \ } void DecodeTCPRegisterTests(void); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index f0a3fbdac987..2f1a9f250d94 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -896,7 +896,7 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, /** If the client has a wscale option the server had it too, * so set the wscale for the server to max. Otherwise none * will have the wscale opt just like it should. */ - if (p->tcpvars.ws != NULL) { + if (TCP_HAS_WSCALE(p)) { ssn->client.wscale = TCP_GET_WSCALE(p); ssn->server.wscale = TCP_WSCALE_MAX; } @@ -912,7 +912,7 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, /* Set the timestamp value for both streams, if packet has timestamp * option enabled.*/ - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { ssn->server.last_ts = TCP_GET_TSVAL(p); ssn->client.last_ts = TCP_GET_TSECR(p); SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" " @@ -963,10 +963,9 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, /* Set the stream timestamp value, if packet has timestamp option * enabled. */ - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { ssn->client.last_ts = TCP_GET_TSVAL(p); - SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn, p->tcpvars.ts, - ssn->client.last_ts); + SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts); if (ssn->client.last_ts == 0) ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP; @@ -976,7 +975,7 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, } ssn->server.window = TCP_GET_WINDOW(p); - if (p->tcpvars.ws != NULL) { + if (TCP_HAS_WSCALE(p)) { ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE; ssn->server.wscale = TCP_GET_WSCALE(p); } @@ -1041,7 +1040,7 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, /* Set the timestamp value for both streams, if packet has timestamp * option enabled.*/ - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { ssn->client.last_ts = TCP_GET_TSVAL(p); ssn->server.last_ts = TCP_GET_TSECR(p); SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" " @@ -1089,11 +1088,11 @@ static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q) if (TCP_GET_SACKOK(p) == 1) q->flags |= STREAMTCP_QUEUE_FLAG_SACK; - if (p->tcpvars.ws != NULL) { + if (TCP_HAS_WSCALE(p)) { q->flags |= STREAMTCP_QUEUE_FLAG_WS; q->wscale = TCP_GET_WSCALE(p); } - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { q->flags |= STREAMTCP_QUEUE_FLAG_TS; q->ts = TCP_GET_TSVAL(p); } @@ -1363,7 +1362,7 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, /* Set the timestamp values used to validate the timestamp of * received packets. */ - if ((p->tcpvars.ts != NULL) && + if ((TCP_HAS_TS(p)) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) { ssn->client.last_ts = TCP_GET_TSVAL(p); @@ -1386,7 +1385,7 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, /** check for the presense of the ws ptr to determine if we * support wscale at all */ if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) && - (p->tcpvars.ws != NULL)) + (TCP_HAS_WSCALE(p))) { ssn->server.wscale = TCP_GET_WSCALE(p); } else { @@ -1462,10 +1461,9 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, /* Set the stream timestamp value, if packet has timestamp * option enabled. */ - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { ssn->server.last_ts = TCP_GET_TSVAL(p); - SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn, - p->tcpvars.ts, ssn->server.last_ts); + SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts); if (ssn->server.last_ts == 0) ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP; @@ -1474,7 +1472,7 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, } ssn->server.window = TCP_GET_WINDOW(p); - if (p->tcpvars.ws != NULL) { + if (TCP_HAS_WSCALE(p)) { ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE; ssn->server.wscale = TCP_GET_WSCALE(p); } else { @@ -1551,7 +1549,7 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, /* Set the timestamp values used to validate the timestamp of * received packets.*/ - if (p->tcpvars.ts != NULL && + if (TCP_HAS_TS(p) && (ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) { ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; @@ -5370,7 +5368,7 @@ static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p) StreamTcpSetOSPolicy(receiver_stream, p); } - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { uint32_t ts = TCP_GET_TSVAL(p); uint32_t last_pkt_ts = sender_stream->last_pkt_ts; uint32_t last_ts = sender_stream->last_ts; @@ -5512,7 +5510,7 @@ static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p) StreamTcpSetOSPolicy(receiver_stream, p); } - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { uint32_t ts = TCP_GET_TSVAL(p); if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) { @@ -6466,8 +6464,6 @@ static int StreamTcpTest07 (void) StreamTcpThread stt; TCPHdr tcph; uint8_t payload[1] = {0x42}; - TCPVars tcpvars; - TCPOpt ts; uint32_t data[2]; PacketQueue pq; @@ -6477,8 +6473,6 @@ static int StreamTcpTest07 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof(StreamTcpThread)); memset(&tcph, 0, sizeof(TCPHdr)); - memset(&tcpvars, 0, sizeof(TCPVars)); - memset(&ts, 0, sizeof(TCPOpt)); FLOW_INITIALIZE(&f); p->flow = &f; @@ -6500,11 +6494,9 @@ static int StreamTcpTest07 (void) data[0] = htonl(10); data[1] = htonl(11); - ts.type = TCP_OPT_TS; - ts.len = 10; - ts.data = (uint8_t *)data; - tcpvars.ts = &ts; - p->tcpvars = tcpvars; + p->tcpvars.ts.type = TCP_OPT_TS; + p->tcpvars.ts.len = 10; + p->tcpvars.ts.data = (uint8_t *)data; p->payload = payload; p->payload_len = 1; @@ -6519,7 +6511,7 @@ static int StreamTcpTest07 (void) p->flowflags = FLOW_PKT_TOSERVER; data[0] = htonl(2); - p->tcpvars.ts->data = (uint8_t *)data; + p->tcpvars.ts.data = (uint8_t *)data; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { if (((TcpSession *) (p->flow->protoctx))->client.next_seq != 11) { @@ -6558,8 +6550,6 @@ static int StreamTcpTest08 (void) StreamTcpThread stt; TCPHdr tcph; uint8_t payload[1] = {0x42}; - TCPVars tcpvars; - TCPOpt ts; uint32_t data[2]; memset(p, 0, SIZE_OF_PACKET); @@ -6569,8 +6559,6 @@ static int StreamTcpTest08 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof(StreamTcpThread)); memset(&tcph, 0, sizeof(TCPHdr)); - memset(&tcpvars, 0, sizeof(TCPVars)); - memset(&ts, 0, sizeof(TCPOpt)); FLOW_INITIALIZE(&f); p->flow = &f; @@ -6592,11 +6580,9 @@ static int StreamTcpTest08 (void) data[0] = htonl(10); data[1] = htonl(11); - ts.type = TCP_OPT_TS; - ts.len = 10; - ts.data = (uint8_t *)data; - tcpvars.ts = &ts; - p->tcpvars = tcpvars; + p->tcpvars.ts.type = TCP_OPT_TS; + p->tcpvars.ts.len = 10; + p->tcpvars.ts.data = (uint8_t *)data; p->payload = payload; p->payload_len = 1; @@ -6611,7 +6597,7 @@ static int StreamTcpTest08 (void) p->flowflags = FLOW_PKT_TOSERVER; data[0] = htonl(12); - p->tcpvars.ts->data = (uint8_t *)data; + p->tcpvars.ts.data = (uint8_t *)data; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; From 50b33ad5082e4947f8e5996c15b57958b2417b1b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 31 Mar 2016 10:22:11 +0200 Subject: [PATCH 1236/2553] prscript: update logic of sync with master test Code now get master sha on github and check if it is in current branch with a git command. It also sync first that the current local branch is in sync with github corresponding branch. Signed-off-by: Eric Leblond --- qa/prscript.py | 57 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index 02dd0ad948c0..840d59526a00 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -30,6 +30,7 @@ import sys import os import copy +from subprocess import Popen, PIPE GOT_NOTIFY = True try: @@ -118,15 +119,32 @@ def TestRepoSync(branch): page = urllib2.urlopen(request) json_result = json.loads(page.read()) sha_orig = json_result[0]["sha"] - request = urllib2.Request(GITHUB_BASE_URI + username + "/" + args.repository + "/commits?sha=" + branch + "&per_page=100") - page = urllib2.urlopen(request) + check_command = ["git", "branch", "--contains", sha_orig ] + p1 = Popen(check_command, stdout=PIPE) + p2 = Popen(["grep", branch], stdin=p1.stdout, stdout=PIPE) + p1.stdout.close() + output = p2.communicate()[0] + if len(output) == 0: + return -1 + return 0 + +def TestGithubSync(branch): + request = urllib2.Request(GITHUB_BASE_URI + username + "/" + args.repository + "/commits?sha=" + branch + "&per_page=1") + try: + page = urllib2.urlopen(request) + except urllib2.HTTPError, e: + if e.code == 404: + return -2 + else: + raise(e) json_result = json.loads(page.read()) - found = -1 - for commit in json_result: - if commit["sha"] == sha_orig: - found = 1 - break - return found + sha_github = json_result[0]["sha"] + check_command = ["git", "rev-parse", branch] + p1 = Popen(check_command, stdout=PIPE) + sha_local = p1.communicate()[0].rstrip() + if sha_local != sha_github: + return -1 + return 0 def OpenBuildbotSession(): auth_params = { 'username':username,'passwd':password, 'name':'login'} @@ -220,12 +238,23 @@ def WaitForBuildResult(builder, buildid, extension="", builder_name = None): return res # check that github branch and inliniac master branch are sync -if not args.local and TestRepoSync(args.branch) == -1: - if args.norebase: - print "Branch " + args.branch + " is not in sync with inliniac's master branch. Continuing due to --norebase option." - else: - print "Branch " + args.branch + " is not in sync with inliniac's master branch. Rebase needed." - sys.exit(-1) +if not args.local: + ret = TestGithubSync(args.branch) + if ret != 0: + if ret == -2: + print "Branch " + args.branch + " is not pushed to Github." + sys.exit(-1) + if args.norebase: + print "Branch " + args.branch + " is not in sync with corresponding Github branch. Continuing due to --norebase option." + else: + print "Branch " + args.branch + " is not in sync with corresponding Github branch. Push may be needed." + sys.exit(-1) + if TestRepoSync(args.branch) != 0: + if args.norebase: + print "Branch " + args.branch + " is not in sync with inliniac's master branch. Continuing due to --norebase option." + else: + print "Branch " + args.branch + " is not in sync with inliniac's master branch. Rebase needed." + sys.exit(-1) def CreateContainer(): cli = Client() From 52983bf314dc7f84c6295141fa5ed6c5f0b9a88f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 6 Apr 2016 15:35:13 -0600 Subject: [PATCH 1237/2553] tests: convert all test to return 0 on failure, 1 on success --- src/app-layer-smtp.c | 25 ++++---- src/counters.c | 12 ++-- src/decode-ethernet.c | 4 +- src/decode-icmpv4.c | 4 +- src/decode-icmpv6.c | 4 +- src/decode-ipv4.c | 4 +- src/decode-raw.c | 25 ++++---- src/decode-tcp.c | 8 +-- src/decode-udp.c | 8 +-- src/detect-detection-filter.c | 18 +++--- src/detect-engine-event.c | 12 ++-- src/detect-engine-filedata-smtp.c | 4 +- src/detect-file-data.c | 18 +++--- src/detect-flags.c | 41 +++++++------ src/detect-flowbits.c | 24 ++++---- src/detect-fragbits.c | 13 ++-- src/detect-fragoffset.c | 6 +- src/detect-icmp-seq.c | 6 +- src/detect-ipopts.c | 13 ++-- src/detect-iprep.c | 16 ++--- src/detect-mark.c | 12 ++-- src/detect-replace.c | 20 +++---- src/detect-threshold.c | 12 ++-- src/util-decode-mime.c | 98 +++++++++++++++---------------- src/util-threshold-config.c | 4 +- src/util-unittest.c | 6 +- 26 files changed, 210 insertions(+), 207 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 94693a233969..534d92e8d465 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -4868,7 +4868,7 @@ int SMTPProcessDataChunkTest01(void){ int ret; ret = SMTPProcessDataChunk(NULL, 0, state); - return ret; + return ret == 0; } @@ -4925,8 +4925,7 @@ int SMTPProcessDataChunkTest02(void){ int ret; ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); - - return ret; + return ret == 0; } @@ -4981,7 +4980,7 @@ int SMTPProcessDataChunkTest03(void){ if(ret) goto end; end: - return ret; + return ret == 0; } @@ -5022,7 +5021,7 @@ int SMTPProcessDataChunkTest04(void){ if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end; end: - return ret; + return ret == 0; } int SMTPProcessDataChunkTest05(void){ @@ -5057,13 +5056,13 @@ int SMTPProcessDataChunkTest05(void){ if(ret){goto end;} printf("%u\t%u\n", (uint32_t) file->size, (uint32_t) file_size); if(file->size == file_size){ - return 0; - }else{ return 1; + }else{ + return 0; } end: - return ret; + return ret == 0; } #endif /* UNITTESTS */ @@ -5085,11 +5084,11 @@ void SMTPParserRegisterTests(void) UtRegisterTest("SMTPParserTest12", SMTPParserTest12, 1); UtRegisterTest("SMTPParserTest13", SMTPParserTest13, 1); UtRegisterTest("SMTPParserTest14", SMTPParserTest14, 1); - UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01, 0); - UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02, 0); - UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03, 0); - UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04, 0); - UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05, 0); + UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01, 1); + UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02, 1); + UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03, 1); + UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04, 1); + UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05, 1); #endif /* UNITTESTS */ return; diff --git a/src/counters.c b/src/counters.c index 325442f2d6e9..1086e10c3697 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1286,7 +1286,7 @@ static int StatsTestCounterReg02() memset(&pctx, 0, sizeof(StatsPublicThreadContext)); - return RegisterCounter(NULL, NULL, &pctx); + return RegisterCounter(NULL, NULL, &pctx) == 0; } static int StatsTestCounterReg03() @@ -1384,7 +1384,7 @@ static int StatsTestCntArraySize07() StatsReleaseCounters(tv.perf_public_ctx.head); StatsReleasePrivateThreadContext(pca); - return result; + return result == 2; } static int StatsTestUpdateCounter08() @@ -1409,7 +1409,7 @@ static int StatsTestUpdateCounter08() StatsReleaseCounters(tv.perf_public_ctx.head); StatsReleasePrivateThreadContext(pca); - return result; + return result == 101; } static int StatsTestUpdateCounter09() @@ -1519,13 +1519,13 @@ static int StatsTestCounterValues11() void StatsRegisterTests() { #ifdef UNITTESTS - UtRegisterTest("StatsTestCounterReg02", StatsTestCounterReg02, 0); + UtRegisterTest("StatsTestCounterReg02", StatsTestCounterReg02, 1); UtRegisterTest("StatsTestCounterReg03", StatsTestCounterReg03, 1); UtRegisterTest("StatsTestCounterReg04", StatsTestCounterReg04, 1); UtRegisterTest("StatsTestGetCntArray05", StatsTestGetCntArray05, 1); UtRegisterTest("StatsTestGetCntArray06", StatsTestGetCntArray06, 1); - UtRegisterTest("StatsTestCntArraySize07", StatsTestCntArraySize07, 2); - UtRegisterTest("StatsTestUpdateCounter08", StatsTestUpdateCounter08, 101); + UtRegisterTest("StatsTestCntArraySize07", StatsTestCntArraySize07, 1); + UtRegisterTest("StatsTestUpdateCounter08", StatsTestUpdateCounter08, 1); UtRegisterTest("StatsTestUpdateCounter09", StatsTestUpdateCounter09, 1); UtRegisterTest("StatsTestUpdateGlobalCounter10", StatsTestUpdateGlobalCounter10, 1); diff --git a/src/decode-ethernet.c b/src/decode-ethernet.c index ee4157236cb8..0bc85cf5a7c0 100644 --- a/src/decode-ethernet.c +++ b/src/decode-ethernet.c @@ -132,7 +132,7 @@ static int DecodeEthernetTest01 (void) DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth), NULL); SCFree(p); - return 0; + return 1; } #endif /* UNITTESTS */ @@ -144,7 +144,7 @@ static int DecodeEthernetTest01 (void) void DecodeEthernetRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeEthernetTest01", DecodeEthernetTest01, 0); + UtRegisterTest("DecodeEthernetTest01", DecodeEthernetTest01, 1); #endif /* UNITTESTS */ } /** diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index 45b213f6704e..e67b68455e2d 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -665,7 +665,7 @@ static int ICMPV4CalculateInvalidChecksumtest06(void) 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; csum = *( ((uint16_t *)raw_icmpv4) + 1); - return (csum == ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); + return (csum != ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); } static int ICMPV4InvalidType07(void) @@ -777,7 +777,7 @@ void DecodeICMPV4RegisterTests(void) UtRegisterTest("ICMPV4CalculateValidChecksumtest05", ICMPV4CalculateValidChecksumtest05, 1); UtRegisterTest("ICMPV4CalculateInvalidChecksumtest06", - ICMPV4CalculateInvalidChecksumtest06, 0); + ICMPV4CalculateInvalidChecksumtest06, 1); UtRegisterTest("DecodeICMPV4InvalidType", ICMPV4InvalidType07, 1); UtRegisterTest("DecodeICMPV4test08", DecodeICMPV4test08, 1); #endif /* UNITTESTS */ diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index a7a77b5a1967..d2e19aa366f8 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -422,7 +422,7 @@ static int ICMPV6CalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)(raw_ipv6 + 56))); - return (csum == ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + return (csum != ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 68)); } @@ -1613,7 +1613,7 @@ void DecodeICMPV6RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("ICMPV6CalculateValidChecksumtest01", ICMPV6CalculateValidChecksumtest01, 1); - UtRegisterTest("ICMPV6CalculateInValidChecksumtest02", ICMPV6CalculateInvalidChecksumtest02, 0); + UtRegisterTest("ICMPV6CalculateInValidChecksumtest02", ICMPV6CalculateInvalidChecksumtest02, 1); UtRegisterTest("ICMPV6ParamProbTest01 (Valid)", ICMPV6ParamProbTest01, 1); UtRegisterTest("ICMPV6DestUnreachTest01 (Valid)", ICMPV6DestUnreachTest01, 1); diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 63aae4ede45b..7979e975bb9a 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -1449,7 +1449,7 @@ static int IPV4CalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_ipv4) + 5); - return (csum == IPV4CalculateChecksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4))); + return (csum != IPV4CalculateChecksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4))); } /** @@ -1902,7 +1902,7 @@ void DecodeIPV4RegisterTests(void) UtRegisterTest("IPV4CalculateValidChecksumtest01", IPV4CalculateValidChecksumtest01, 1); UtRegisterTest("IPV4CalculateInvalidChecksumtest02", - IPV4CalculateInvalidChecksumtest02, 0); + IPV4CalculateInvalidChecksumtest02, 1); UtRegisterTest("DecodeIPV4DefragTest01", DecodeIPV4DefragTest01, 1); UtRegisterTest("DecodeIPV4DefragTest02", DecodeIPV4DefragTest02, 1); UtRegisterTest("DecodeIPV4DefragTest03", DecodeIPV4DefragTest03, 1); diff --git a/src/decode-raw.c b/src/decode-raw.c index 22e1b9e1e908..8df2bc845dfc 100644 --- a/src/decode-raw.c +++ b/src/decode-raw.c @@ -100,7 +100,7 @@ static int DecodeRawTest01 (void) if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { SCFree(p); - return 1; + return 0; } FlowInitConfig(FLOW_QUIET); @@ -110,13 +110,13 @@ static int DecodeRawTest01 (void) printf("expected a valid ipv6 header but it was NULL: "); FlowShutdown(); SCFree(p); - return 1; + return 0; } PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return 0; + return 1; } /** DecodeRawtest02 @@ -146,7 +146,7 @@ static int DecodeRawTest02 (void) if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { SCFree(p); - return 1; + return 0; } FlowInitConfig(FLOW_QUIET); @@ -157,13 +157,13 @@ static int DecodeRawTest02 (void) PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return 1; + return 0; } PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return 0; + return 1; } /** DecodeRawtest03 * \brief Valid Raw packet @@ -194,18 +194,17 @@ static int DecodeRawTest03 (void) if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { SCFree(p); - return 1; + return 0; } FlowInitConfig(FLOW_QUIET); DecodeRaw(&tv, &dtv, p, raw_ip, GET_PKT_LEN(p), NULL); - if (ENGINE_ISSET_EVENT(p,IPRAW_INVALID_IPV)) { + if (!ENGINE_ISSET_EVENT(p,IPRAW_INVALID_IPV)) { + printf("expected IPRAW_INVALID_IPV to be set but it wasn't: "); FlowShutdown(); SCFree(p); return 0; - } else { - printf("expected IPRAW_INVALID_IPV to be set but it wasn't: "); } PACKET_RECYCLE(p); FlowShutdown(); @@ -222,9 +221,9 @@ static int DecodeRawTest03 (void) void DecodeRawRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeRawTest01", DecodeRawTest01, 0); - UtRegisterTest("DecodeRawTest02", DecodeRawTest02, 0); - UtRegisterTest("DecodeRawTest03", DecodeRawTest03, 0); + UtRegisterTest("DecodeRawTest01", DecodeRawTest01, 1); + UtRegisterTest("DecodeRawTest02", DecodeRawTest02, 1); + UtRegisterTest("DecodeRawTest03", DecodeRawTest03, 1); #endif /* UNITTESTS */ } /** diff --git a/src/decode-tcp.c b/src/decode-tcp.c index ae3650be11cf..d7f3522c05eb 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -253,7 +253,7 @@ static int TCPCalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_tcp) + 8); - return (csum == TCPCalculateChecksum((uint16_t *) raw_ipshdr, + return (csum != TCPCalculateChecksum((uint16_t *) raw_ipshdr, (uint16_t *)raw_tcp, sizeof(raw_tcp))); } @@ -299,7 +299,7 @@ static int TCPV6CalculateInvalidChecksumtest04(void) csum = *( ((uint16_t *)(raw_ipv6 + 70))); - return (csum == TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + return (csum != TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 32)); } @@ -513,11 +513,11 @@ void DecodeTCPRegisterTests(void) UtRegisterTest("TCPCalculateValidChecksumtest01", TCPCalculateValidChecksumtest01, 1); UtRegisterTest("TCPCalculateInvalidChecksumtest02", - TCPCalculateInvalidChecksumtest02, 0); + TCPCalculateInvalidChecksumtest02, 1); UtRegisterTest("TCPV6CalculateValidChecksumtest03", TCPV6CalculateValidChecksumtest03, 1); UtRegisterTest("TCPV6CalculateInvalidChecksumtest04", - TCPV6CalculateInvalidChecksumtest04, 0); + TCPV6CalculateInvalidChecksumtest04, 1); UtRegisterTest("TCPGetWscaleTest01", TCPGetWscaleTest01, 1); UtRegisterTest("TCPGetWscaleTest02", TCPGetWscaleTest02, 1); UtRegisterTest("TCPGetWscaleTest03", TCPGetWscaleTest03, 1); diff --git a/src/decode-udp.c b/src/decode-udp.c index 14ba7887d3aa..cef9a45488ee 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -150,7 +150,7 @@ static int UDPV4CalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_udp) + 3); - return (csum == UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, + return (csum != UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, (uint16_t *)raw_udp, sizeof(raw_udp))); } @@ -195,7 +195,7 @@ static int UDPV6CalculateInvalidChecksumtest04(void) csum = *( ((uint16_t *)(raw_ipv6 + 60))); - return (csum == UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + return (csum != UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 20)); } #endif /* UNITTESTS */ @@ -206,11 +206,11 @@ void DecodeUDPV4RegisterTests(void) UtRegisterTest("UDPV4CalculateValidChecksumtest01", UDPV4CalculateValidChecksumtest01, 1); UtRegisterTest("UDPV4CalculateInvalidChecksumtest02", - UDPV4CalculateInvalidChecksumtest02, 0); + UDPV4CalculateInvalidChecksumtest02, 1); UtRegisterTest("UDPV6CalculateValidChecksumtest03", UDPV6CalculateValidChecksumtest03, 1); UtRegisterTest("UDPV6CalculateInvalidChecksumtest04", - UDPV6CalculateInvalidChecksumtest04, 0); + UDPV6CalculateInvalidChecksumtest04, 1); #endif /* UNITTESTS */ } /** diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 7e1ee8bc9b8e..7a95446f8b52 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -322,10 +322,10 @@ int DetectDetectionFilterTestParse02 (void) df = DetectDetectionFilterParse("track both,count 10,seconds 60"); if (df && (df->track == TRACK_DST || df->track == TRACK_SRC) && (df->count == 10) && (df->seconds == 60)) { DetectDetectionFilterFree(df); - return 1; + return 0; } - return 0; + return 1; } /** @@ -359,10 +359,10 @@ int DetectDetectionFilterTestParse04 (void) df = DetectDetectionFilterParse("count 10, track by_dst, seconds 60, count 10"); if (df && (df->track == TRACK_DST) && (df->count == 10) && (df->seconds == 60)) { DetectDetectionFilterFree(df); - return 1; + return 0; } - return 0; + return 1; } /** @@ -395,10 +395,10 @@ int DetectDetectionFilterTestParse06 (void) df = DetectDetectionFilterParse("count 10, track by_dst, seconds 0"); if (df && (df->track == TRACK_DST) && (df->count == 10) && (df->seconds == 0)) { DetectDetectionFilterFree(df); - return 1; + return 0; } - return 0; + return 1; } /** @@ -652,11 +652,11 @@ void DetectDetectionFilterRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectDetectionFilterTestParse01", DetectDetectionFilterTestParse01, 1); - UtRegisterTest("DetectDetectionFilterTestParse02", DetectDetectionFilterTestParse02, 0); + UtRegisterTest("DetectDetectionFilterTestParse02", DetectDetectionFilterTestParse02, 1); UtRegisterTest("DetectDetectionFilterTestParse03", DetectDetectionFilterTestParse03, 1); - UtRegisterTest("DetectDetectionFilterTestParse04", DetectDetectionFilterTestParse04, 0); + UtRegisterTest("DetectDetectionFilterTestParse04", DetectDetectionFilterTestParse04, 1); UtRegisterTest("DetectDetectionFilterTestParse05", DetectDetectionFilterTestParse05, 1); - UtRegisterTest("DetectDetectionFilterTestParse06", DetectDetectionFilterTestParse06, 0); + UtRegisterTest("DetectDetectionFilterTestParse06", DetectDetectionFilterTestParse06, 1); UtRegisterTest("DetectDetectionFilterTestSig1", DetectDetectionFilterTestSig1, 1); UtRegisterTest("DetectDetectionFilterTestSig2", DetectDetectionFilterTestSig2, 1); UtRegisterTest("DetectDetectionFilterTestSig3", DetectDetectionFilterTestSig3, 1); diff --git a/src/detect-engine-event.c b/src/detect-engine-event.c index 9a8e23967e99..a03c63093382 100644 --- a/src/detect-engine-event.c +++ b/src/detect-engine-event.c @@ -332,10 +332,10 @@ int EngineEventTestParse04 (void) de = DetectEngineEventParse("decoder.IPV6.INVALID_EVENT"); if (de) { DetectEngineEventFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -347,10 +347,10 @@ int EngineEventTestParse05 (void) de = DetectEngineEventParse("decoder.IPV-6,INVALID_CHAR"); if (de) { DetectEngineEventFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -409,8 +409,8 @@ void EngineEventRegisterTests(void) UtRegisterTest("EngineEventTestParse01", EngineEventTestParse01, 1); UtRegisterTest("EngineEventTestParse02", EngineEventTestParse02, 1); UtRegisterTest("EngineEventTestParse03", EngineEventTestParse03, 1); - UtRegisterTest("EngineEventTestParse04", EngineEventTestParse04, 0); - UtRegisterTest("EngineEventTestParse05", EngineEventTestParse05, 0); + UtRegisterTest("EngineEventTestParse04", EngineEventTestParse04, 1); + UtRegisterTest("EngineEventTestParse05", EngineEventTestParse05, 1); UtRegisterTest("EngineEventTestParse06", EngineEventTestParse06, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 80fec628dcee..1f7c66640421 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -585,7 +585,7 @@ static int DetectEngineSMTPFiledataTest03(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + return result == 0; } #endif /* UNITTESTS */ @@ -598,7 +598,7 @@ void DetectEngineSMTPFiledataRegisterTests(void) UtRegisterTest("DetectEngineSMTPFiledataTest02", DetectEngineSMTPFiledataTest02, 1); UtRegisterTest("DetectEngineSMTPFiledataTest03", - DetectEngineSMTPFiledataTest03, 0); + DetectEngineSMTPFiledataTest03, 1); #endif /* UNITTESTS */ return; diff --git a/src/detect-file-data.c b/src/detect-file-data.c index 258a135cf0a4..f8654b017f01 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -213,6 +213,9 @@ static int DetectFiledataParseTest03(void) return result; } +/** + * \test Test the file_data fails with flow:to_server. + */ static int DetectFiledataParseTest04(void) { DetectEngineCtx *de_ctx = NULL; @@ -227,11 +230,9 @@ static int DetectFiledataParseTest04(void) "alert smtp any any -> any any " "(msg:\"test\"; flow:to_client,established; file_data; content:\"abc\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; + result = 1; } - result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -240,6 +241,9 @@ static int DetectFiledataParseTest04(void) return result; } +/** + * \test Test the file_data fails with flow:to_server. + */ static int DetectFiledataParseTest05(void) { DetectEngineCtx *de_ctx = NULL; @@ -254,11 +258,9 @@ static int DetectFiledataParseTest05(void) "alert http any any -> any any " "(msg:\"test\"; flow:to_server,established; file_data; content:\"abc\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; + result = 1; } - result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -274,7 +276,7 @@ void DetectFiledataRegisterTests(void) UtRegisterTest("DetectFiledataParseTest01", DetectFiledataParseTest01, 1); UtRegisterTest("DetectFiledataParseTest02", DetectFiledataParseTest02, 1); UtRegisterTest("DetectFiledataParseTest03", DetectFiledataParseTest03, 1); - UtRegisterTest("DetectFiledataParseTest04", DetectFiledataParseTest04, 0); - UtRegisterTest("DetectFiledataParseTest05", DetectFiledataParseTest05, 0); + UtRegisterTest("DetectFiledataParseTest04", DetectFiledataParseTest04, 1); + UtRegisterTest("DetectFiledataParseTest05", DetectFiledataParseTest05, 1); #endif } diff --git a/src/detect-flags.c b/src/detect-flags.c index 51768f1797cc..bdf3147d0caa 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -595,10 +595,10 @@ static int FlagsTestParse02 (void) de = DetectFlagsParse("G"); if (de) { DetectFlagsFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -701,14 +701,15 @@ static int FlagsTestParse04 (void) if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 1; + return 0; } + /* Error expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } /** @@ -756,14 +757,15 @@ static int FlagsTestParse05 (void) if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 1; + return 0; } + /* Error expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } /** @@ -866,14 +868,15 @@ static int FlagsTestParse07 (void) if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 1; + return 0; } + /* Error expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } /** @@ -1086,14 +1089,15 @@ static int FlagsTestParse11 (void) if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 1; + return 0; } + /* Expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } /** @@ -1143,14 +1147,15 @@ static int FlagsTestParse12 (void) if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 1; + return 0; } + /* Expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } /** @@ -1359,17 +1364,17 @@ void FlagsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("FlagsTestParse01", FlagsTestParse01, 1); - UtRegisterTest("FlagsTestParse02", FlagsTestParse02, 0); + UtRegisterTest("FlagsTestParse02", FlagsTestParse02, 1); UtRegisterTest("FlagsTestParse03", FlagsTestParse03, 1); - UtRegisterTest("FlagsTestParse04", FlagsTestParse04, 0); - UtRegisterTest("FlagsTestParse05", FlagsTestParse05, 0); + UtRegisterTest("FlagsTestParse04", FlagsTestParse04, 1); + UtRegisterTest("FlagsTestParse05", FlagsTestParse05, 1); UtRegisterTest("FlagsTestParse06", FlagsTestParse06, 1); - UtRegisterTest("FlagsTestParse07", FlagsTestParse07, 0); + UtRegisterTest("FlagsTestParse07", FlagsTestParse07, 1); UtRegisterTest("FlagsTestParse08", FlagsTestParse08, 1); UtRegisterTest("FlagsTestParse09", FlagsTestParse09, 1); UtRegisterTest("FlagsTestParse10", FlagsTestParse10, 1); - UtRegisterTest("FlagsTestParse11", FlagsTestParse11, 0); - UtRegisterTest("FlagsTestParse12", FlagsTestParse12, 0); + UtRegisterTest("FlagsTestParse11", FlagsTestParse11, 1); + UtRegisterTest("FlagsTestParse12", FlagsTestParse12, 1); UtRegisterTest("FlagsTestParse13", FlagsTestParse13, 1); UtRegisterTest("FlagsTestParse14", FlagsTestParse14, 1); UtRegisterTest("FlagsTestParse15", FlagsTestParse15, 1); diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 2c10f4995528..792c1e1ef776 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -452,7 +452,7 @@ static int FlowBitsTestSig01(void) } SCFree(p); - return result; + return result == 0; } /** @@ -574,7 +574,7 @@ static int FlowBitsTestSig02(void) } SCFree(p); - return result; + return result == 0; } /** @@ -652,7 +652,7 @@ static int FlowBitsTestSig03(void) SCFree(p); - return result; + return result == 0; } /** @@ -1004,7 +1004,7 @@ static int FlowBitsTestSig07(void) FLOW_DESTROY(&f); SCFree(p); - return result; + return result == 0; end: if (de_ctx != NULL) { @@ -1024,7 +1024,7 @@ static int FlowBitsTestSig07(void) FLOW_DESTROY(&f); SCFree(p); - return result; + return result == 0; } /** @@ -1113,7 +1113,7 @@ static int FlowBitsTestSig08(void) FLOW_DESTROY(&f); SCFree(p); - return result; + return result == 0; end: if (de_ctx != NULL) { @@ -1133,7 +1133,7 @@ static int FlowBitsTestSig08(void) FLOW_DESTROY(&f); SCFree(p); - return result; + return result == 0; } #endif /* UNITTESTS */ @@ -1144,13 +1144,13 @@ void FlowBitsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01, 1); - UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01, 0); - UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02, 0); - UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03, 0); + UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01, 1); + UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02, 1); + UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03, 1); UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04, 1); UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05, 1); UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06, 1); - UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07, 0); - UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08, 0); + UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07, 1); + UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-fragbits.c b/src/detect-fragbits.c index 7a564ba01af5..663735cc14f4 100644 --- a/src/detect-fragbits.c +++ b/src/detect-fragbits.c @@ -362,10 +362,10 @@ static int FragBitsTestParse02 (void) de = DetectFragBitsParse("G"); if (de) { DetectFragBitsFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -554,16 +554,17 @@ static int FragBitsTestParse04 (void) PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return 1; + return 0; } + /* Error expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return 0; + return 1; } #endif /* UNITTESTS */ @@ -574,8 +575,8 @@ void FragBitsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("FragBitsTestParse01", FragBitsTestParse01, 1); - UtRegisterTest("FragBitsTestParse02", FragBitsTestParse02, 0); + UtRegisterTest("FragBitsTestParse02", FragBitsTestParse02, 1); UtRegisterTest("FragBitsTestParse03", FragBitsTestParse03, 1); - UtRegisterTest("FragBitsTestParse04", FragBitsTestParse04, 0); + UtRegisterTest("FragBitsTestParse04", FragBitsTestParse04, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index c887b7b97986..62e1852d2933 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -299,9 +299,9 @@ int DetectFragOffsetParseTest03 (void) fragoff = DetectFragOffsetParse("badc"); if (fragoff != NULL) { DetectFragOffsetFree(fragoff); - return 1; + return 0; } - return 0; + return 1; } /** @@ -389,7 +389,7 @@ void DetectFragOffsetRegisterTests (void) #ifdef UNITTESTS UtRegisterTest("DetectFragOffsetParseTest01", DetectFragOffsetParseTest01, 1); UtRegisterTest("DetectFragOffsetParseTest02", DetectFragOffsetParseTest02, 1); - UtRegisterTest("DetectFragOffsetParseTest03", DetectFragOffsetParseTest03, 0); + UtRegisterTest("DetectFragOffsetParseTest03", DetectFragOffsetParseTest03, 1); UtRegisterTest("DetectFragOffsetMatchTest01", DetectFragOffsetMatchTest01, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index 4e3fe1ac1961..4c5784210139 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -310,9 +310,9 @@ int DetectIcmpSeqParseTest03 (void) iseq = DetectIcmpSeqParse("badc"); if (iseq != NULL) { DetectIcmpSeqFree(iseq); - return 1; + return 0; } - return 0; + return 1; } /** @@ -383,7 +383,7 @@ void DetectIcmpSeqRegisterTests (void) #ifdef UNITTESTS UtRegisterTest("DetectIcmpSeqParseTest01", DetectIcmpSeqParseTest01, 1); UtRegisterTest("DetectIcmpSeqParseTest02", DetectIcmpSeqParseTest02, 1); - UtRegisterTest("DetectIcmpSeqParseTest03", DetectIcmpSeqParseTest03, 0); + UtRegisterTest("DetectIcmpSeqParseTest03", DetectIcmpSeqParseTest03, 1); UtRegisterTest("DetectIcmpSeqMatchTest01", DetectIcmpSeqMatchTest01, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index 159578ee0e89..fbe143abea99 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -261,10 +261,10 @@ int IpOptsTestParse02 (void) de = DetectIpOptsParse("invalidopt"); if (de) { DetectIpOptsFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -361,14 +361,15 @@ int IpOptsTestParse04 (void) if(ret) { SCFree(p); - return 1; + return 0; } + /* Error expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } #endif /* UNITTESTS */ @@ -379,8 +380,8 @@ void IpOptsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("IpOptsTestParse01", IpOptsTestParse01, 1); - UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02, 0); + UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02, 1); UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03, 1); - UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04, 0); + UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-iprep.c b/src/detect-iprep.c index 4e47acdcb6a0..6944a71f2cb8 100644 --- a/src/detect-iprep.c +++ b/src/detect-iprep.c @@ -757,7 +757,7 @@ static int DetectIPRepTest05(void) DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + return result == 0; } static int DetectIPRepTest06(void) @@ -819,7 +819,7 @@ static int DetectIPRepTest06(void) DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + return result == 0; } static int DetectIPRepTest07(void) @@ -881,7 +881,7 @@ static int DetectIPRepTest07(void) DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + return result == 0; } static int DetectIPRepTest08(void) @@ -944,7 +944,7 @@ static int DetectIPRepTest08(void) DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + return result == 0; } static int DetectIPRepTest09(void) @@ -1021,10 +1021,10 @@ void IPRepRegisterTests(void) UtRegisterTest("DetectIPRepTest02", DetectIPRepTest02, 1); UtRegisterTest("DetectIPRepTest03", DetectIPRepTest03, 1); UtRegisterTest("DetectIPRepTest04", DetectIPRepTest04, 1); - UtRegisterTest("DetectIPRepTest05", DetectIPRepTest05, 0); - UtRegisterTest("DetectIPRepTest06", DetectIPRepTest06, 0); - UtRegisterTest("DetectIPRepTest07", DetectIPRepTest07, 0); - UtRegisterTest("DetectIPRepTest08", DetectIPRepTest08, 0); + UtRegisterTest("DetectIPRepTest05", DetectIPRepTest05, 1); + UtRegisterTest("DetectIPRepTest06", DetectIPRepTest06, 1); + UtRegisterTest("DetectIPRepTest07", DetectIPRepTest07, 1); + UtRegisterTest("DetectIPRepTest08", DetectIPRepTest08, 1); UtRegisterTest("DetectIPRepTest09", DetectIPRepTest09, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-mark.c b/src/detect-mark.c index 695a7b412cc9..74edf3ce34aa 100644 --- a/src/detect-mark.c +++ b/src/detect-mark.c @@ -288,11 +288,11 @@ static int MarkTestParse02 (void) data = DetectMarkParse("4"); if (data == NULL) { - return 0; + return 1; } DetectMarkDataFree(data); - return 1; + return 0; } /** @@ -328,11 +328,11 @@ static int MarkTestParse04 (void) data = DetectMarkParse("0x1g/0xff"); if (data == NULL) { - return 0; + return 1; } DetectMarkDataFree(data); - return 1; + return 0; } @@ -346,8 +346,8 @@ void MarkRegisterTests(void) { #if defined UNITTESTS && defined NFQ UtRegisterTest("MarkTestParse01", MarkTestParse01, 1); - UtRegisterTest("MarkTestParse02", MarkTestParse02, 0); + UtRegisterTest("MarkTestParse02", MarkTestParse02, 1); UtRegisterTest("MarkTestParse03", MarkTestParse03, 1); - UtRegisterTest("MarkTestParse04", MarkTestParse04, 0); + UtRegisterTest("MarkTestParse04", MarkTestParse04, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-replace.c b/src/detect-replace.c index 57e06e7aeb4f..082f59832075 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -443,7 +443,7 @@ static int DetectReplaceMatchTest05(void) " content:\"th\"; replace:\"TH\"; content:\"nutella\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"TH\"; sid:2;)"; - return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); + return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** @@ -456,7 +456,7 @@ static int DetectReplaceMatchTest06(void) " content:\"nutella\"; replace:\"commode\"; content:\"this is\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"commode\"; sid:2;)"; - return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); + return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** @@ -492,7 +492,7 @@ static int DetectReplaceMatchTest09(void) " content:\"big\"; depth:16; replace:\"pig\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"this is a pig test\"; sid:2;)"; - return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); + return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** @@ -528,7 +528,7 @@ static int DetectReplaceMatchTest12(void) " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 4; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"pig\"; depth:17; offset:14; sid:2;)"; - return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); + return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** @@ -552,7 +552,7 @@ static int DetectReplaceMatchTest14(void) " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 2; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"pig\"; depth:17; offset:14; sid:2;)"; - return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); + return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** @@ -822,16 +822,16 @@ void DetectReplaceRegisterTests(void) UtRegisterTest("DetectReplaceMatchTest02", DetectReplaceMatchTest02, 1); UtRegisterTest("DetectReplaceMatchTest03", DetectReplaceMatchTest03, 1); UtRegisterTest("DetectReplaceMatchTest04", DetectReplaceMatchTest04, 1); - UtRegisterTest("DetectReplaceMatchTest05", DetectReplaceMatchTest05, 0); - UtRegisterTest("DetectReplaceMatchTest06", DetectReplaceMatchTest06, 0); + UtRegisterTest("DetectReplaceMatchTest05", DetectReplaceMatchTest05, 1); + UtRegisterTest("DetectReplaceMatchTest06", DetectReplaceMatchTest06, 1); UtRegisterTest("DetectReplaceMatchTest07", DetectReplaceMatchTest07, 1); UtRegisterTest("DetectReplaceMatchTest08", DetectReplaceMatchTest08, 1); - UtRegisterTest("DetectReplaceMatchTest09", DetectReplaceMatchTest09, 0); + UtRegisterTest("DetectReplaceMatchTest09", DetectReplaceMatchTest09, 1); UtRegisterTest("DetectReplaceMatchTest10", DetectReplaceMatchTest10, 1); UtRegisterTest("DetectReplaceMatchTest11", DetectReplaceMatchTest11, 1); - UtRegisterTest("DetectReplaceMatchTest12", DetectReplaceMatchTest12, 0); + UtRegisterTest("DetectReplaceMatchTest12", DetectReplaceMatchTest12, 1); UtRegisterTest("DetectReplaceMatchTest13", DetectReplaceMatchTest13, 1); - UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14, 0); + UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14, 1); UtRegisterTest("DetectReplaceMatchTest15", DetectReplaceMatchTest15, 1); /* parsing */ UtRegisterTest("DetectReplaceParseTest01", DetectReplaceParseTest01, 1); diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 236b6bf627ac..e0850a3c9b68 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -333,10 +333,10 @@ static int ThresholdTestParse02(void) de = DetectThresholdParse("type any,track by_dst,count 10,seconds 60"); if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { DetectThresholdFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -370,10 +370,10 @@ static int ThresholdTestParse04(void) de = DetectThresholdParse("count 10, track by_dst, seconds 60, type both, count 10"); if (de && (de->type == TYPE_BOTH) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { DetectThresholdFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -1501,9 +1501,9 @@ void ThresholdRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("ThresholdTestParse01", ThresholdTestParse01, 1); - UtRegisterTest("ThresholdTestParse02", ThresholdTestParse02, 0); + UtRegisterTest("ThresholdTestParse02", ThresholdTestParse02, 1); UtRegisterTest("ThresholdTestParse03", ThresholdTestParse03, 1); - UtRegisterTest("ThresholdTestParse04", ThresholdTestParse04, 0); + UtRegisterTest("ThresholdTestParse04", ThresholdTestParse04, 1); UtRegisterTest("ThresholdTestParse05", ThresholdTestParse05, 1); UtRegisterTest("DetectThresholdTestSig1", DetectThresholdTestSig1, 1); UtRegisterTest("DetectThresholdTestSig2", DetectThresholdTestSig2, 1); diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index ded4cd6044d4..8664a9438c3c 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -2691,18 +2691,18 @@ static int MimeDecParseLineTest01(void) ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); if (ret != MIME_DEC_OK) { - return ret; + return 0; } /* Completed */ ret = MimeDecParseComplete(state); if (ret != MIME_DEC_OK) { - return ret; + return 0; } MimeDecEntity *msg = state->msg; if (msg->next != NULL || msg->child != NULL) { SCLogInfo("Error: Invalid sibling or child message"); - return -1; + return 0; } MimeDecFreeEntity(msg); @@ -2715,10 +2715,10 @@ static int MimeDecParseLineTest01(void) if (expected_count != line_count) { SCLogInfo("Error: Line count is invalid: expected - %d actual - %d", expected_count, line_count); - return -1; + return 0; } - return ret; + return 1; } /* Test simple case of EXE URL extraction */ @@ -2757,19 +2757,19 @@ static int MimeDecParseLineTest02(void) ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); if (ret != MIME_DEC_OK) { - return ret; + return 0; } /* Completed */ ret = MimeDecParseComplete(state); if (ret != MIME_DEC_OK) { - return ret; + return 0; } MimeDecEntity *msg = state->msg; if (msg->url_list == NULL || (msg->url_list != NULL && !(msg->url_list->url_flags & URL_IS_EXE))) { SCLogInfo("Warning: Expected EXE URL not found"); - return -1; + return 0; } MimeDecFreeEntity(msg); @@ -2782,17 +2782,15 @@ static int MimeDecParseLineTest02(void) if (expected_count != line_count) { SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", expected_count, line_count); - return -1; + return 0; } - return ret; + return 1; } /* Test full message with linebreaks */ static int MimeDecParseFullMsgTest01(void) { - int ret = MIME_DEC_OK; - uint32_t expected_count = 3; uint32_t line_count = 0; @@ -2808,7 +2806,7 @@ static int MimeDecParseFullMsgTest01(void) TestDataChunkCallback); if (entity == NULL) { SCLogInfo("Warning: Message failed to parse"); - return -1; + return 0; } MimeDecFreeEntity(entity); @@ -2816,17 +2814,15 @@ static int MimeDecParseFullMsgTest01(void) if (expected_count != line_count) { SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", expected_count, line_count); - return -1; + return 0; } - return ret; + return 1; } /* Test full message with linebreaks */ static int MimeDecParseFullMsgTest02(void) { - int ret = MIME_DEC_OK; - uint32_t expected_count = 3; uint32_t line_count = 0; @@ -2844,23 +2840,23 @@ static int MimeDecParseFullMsgTest02(void) if (entity == NULL) { SCLogInfo("Warning: Message failed to parse"); - return -1; + return 0; } MimeDecField *field = MimeDecFindField(entity, "subject"); if (field == NULL) { SCLogInfo("Warning: Message failed to parse"); - return -1; + return 0; } if (field->value_len != sizeof("subject2") - 1) { SCLogInfo("Warning: failed to get subject"); - return -1; + return 0; } if (memcmp(field->value, "subject2", field->value_len) != 0) { SCLogInfo("Warning: failed to get subject"); - return -1; + return 0; } @@ -2869,15 +2865,15 @@ static int MimeDecParseFullMsgTest02(void) if (expected_count != line_count) { SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", expected_count, line_count); - return -1; + return 0; } - return ret; + return 1; } static int MimeBase64DecodeTest01(void) { - int ret = -1; + int ret = 0; char *msg = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@" "#$%^&*()-=_+,./;'[]<>?:"; @@ -2891,7 +2887,7 @@ static int MimeBase64DecodeTest01(void) ret = DecodeBase64(dst, (const uint8_t *)base64msg, strlen(base64msg), 1); if (memcmp(dst, msg, strlen(msg)) == 0) { - ret = 0; + ret = 1; } SCFree(dst); @@ -2901,7 +2897,7 @@ static int MimeBase64DecodeTest01(void) static int MimeIsExeURLTest01(void) { - int ret = -1; + int ret = 0; char *url1 = "http://www.google.com/"; char *url2 = "http://www.google.com/test.exe"; @@ -2913,7 +2909,7 @@ static int MimeIsExeURLTest01(void) SCLogDebug("Debug: URL2 error"); goto end; } - ret = 0; + ret = 1; end: @@ -2923,67 +2919,67 @@ static int MimeIsExeURLTest01(void) static int MimeIsIpv4HostTest01(void) { if(IsIpv4Host((const uint8_t *)"192.168.1.1", 11) != 1) { - return 1; + return 0; } if(IsIpv4Host((const uint8_t *)"999.oogle.com", 14) != 0) { - return 1; + return 0; } if(IsIpv4Host((const uint8_t *)"0:0:0:0:0:0:0:0", 15) != 0) { - return 1; + return 0; } if (IsIpv4Host((const uint8_t *)"192.168.255.255", 15) != 1) { - return 1; + return 0; } if (IsIpv4Host((const uint8_t *)"192.168.255.255/testurl.html", 28) != 1) { - return 1; + return 0; } if (IsIpv4Host((const uint8_t *)"www.google.com", 14) != 0) { - return 1; + return 0; } - return 0; + return 1; } static int MimeIsIpv6HostTest01(void) { if(IsIpv6Host((const uint8_t *)"0:0:0:0:0:0:0:0", 19) != 1) { - return 1; + return 0; } if(IsIpv6Host((const uint8_t *)"0000:0000:0000:0000:0000:0000:0000:0000", 39) != 1) { - return 1; + return 0; } if(IsIpv6Host((const uint8_t *)"0:0:0:0:0:0:0:0", 19) != 1) { - return 1; + return 0; } if(IsIpv6Host((const uint8_t *)"192:168:1:1:0:0:0:0", 19) != 1) { - return 1; + return 0; } if(IsIpv6Host((const uint8_t *)"999.oogle.com", 14) != 0) { - return 1; + return 0; } if (IsIpv6Host((const uint8_t *)"192.168.255.255", 15) != 0) { - return 1; + return 0; } if (IsIpv6Host((const uint8_t *)"192.168.255.255/testurl.html", 28) != 0) { - return 1; + return 0; } if (IsIpv6Host((const uint8_t *)"www.google.com", 14) != 0) { - return 1; + return 0; } - return 0; + return 1; } #endif /* UNITTESTS */ @@ -2991,13 +2987,13 @@ static int MimeIsIpv6HostTest01(void) void MimeDecRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01, 0); - UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02, 0); - UtRegisterTest("MimeDecParseFullMsgTest01", MimeDecParseFullMsgTest01, 0); - UtRegisterTest("MimeDecParseFullMsgTest02", MimeDecParseFullMsgTest02, 0); - UtRegisterTest("MimeBase64DecodeTest01", MimeBase64DecodeTest01, 0); - UtRegisterTest("MimeIsExeURLTest01", MimeIsExeURLTest01, 0); - UtRegisterTest("MimeIsIpv4HostTest01", MimeIsIpv4HostTest01, 0); - UtRegisterTest("MimeIsIpv6HostTest01", MimeIsIpv6HostTest01, 0); + UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01, 1); + UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02, 1); + UtRegisterTest("MimeDecParseFullMsgTest01", MimeDecParseFullMsgTest01, 1); + UtRegisterTest("MimeDecParseFullMsgTest02", MimeDecParseFullMsgTest02, 1); + UtRegisterTest("MimeBase64DecodeTest01", MimeBase64DecodeTest01, 1); + UtRegisterTest("MimeIsExeURLTest01", MimeIsExeURLTest01, 1); + UtRegisterTest("MimeIsIpv4HostTest01", MimeIsIpv4HostTest01, 1); + UtRegisterTest("MimeIsIpv6HostTest01", MimeIsIpv6HostTest01, 1); #endif /* UNITTESTS */ } diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index f2f5ad3afe71..f6c34bd0e9fa 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -1590,7 +1590,7 @@ int SCThresholdConfTest04(void) SigGroupBuild(de_ctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - return result; + return result == 0; } /** @@ -2882,7 +2882,7 @@ void SCThresholdConfRegisterTests(void) UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01, 1); UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02, 1); UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03, 1); - UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04, 0); + UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04, 1); UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05, 1); UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06, 1); UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07, 1); diff --git a/src/util-unittest.c b/src/util-unittest.c index c3f0fdb29604..b172e9a0ffbc 100644 --- a/src/util-unittest.c +++ b/src/util-unittest.c @@ -292,8 +292,8 @@ int UtSelftestTrue(void) int UtSelftestFalse(void) { - if (0)return 1; - else return 0; + if (0)return 0; + else return 1; } #endif /* UNITTESTS */ @@ -312,7 +312,7 @@ int UtRunSelftest (char *regex_arg) UtInitialize(); UtRegisterTest("true", UtSelftestTrue, 1); - UtRegisterTest("false", UtSelftestFalse, 0); + UtRegisterTest("false", UtSelftestFalse, 1); int ret = UtRunTests(regex_arg); if (ret == 0) From 796dd5223bf17083a48c2a8a8a2944d1dc9b7033 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 6 Apr 2016 15:58:40 -0600 Subject: [PATCH 1238/2553] tests: no longer necessary to provide successful return code 1 pass, 0 is fail. --- src/alert-fastlog.c | 4 +- src/alert-unified2-alert.c | 13 +- src/app-layer-dcerpc-udp.c | 2 +- src/app-layer-dcerpc.c | 38 +- src/app-layer-detect-proto.c | 40 +- src/app-layer-dns-udp.c | 10 +- src/app-layer-ftp.c | 10 +- src/app-layer-htp-file.c | 22 +- src/app-layer-htp-xff.c | 18 +- src/app-layer-htp.c | 74 +- src/app-layer-modbus.c | 36 +- src/app-layer-parser.c | 4 +- src/app-layer-smb.c | 20 +- src/app-layer-smb2.c | 2 +- src/app-layer-smtp.c | 38 +- src/app-layer-ssh.c | 48 +- src/app-layer-ssl.c | 52 +- src/app-layer.c | 22 +- src/conf-yaml-loader.c | 16 +- src/conf.c | 38 +- src/counters.c | 20 +- src/decode-ethernet.c | 2 +- src/decode-gre.c | 6 +- src/decode-icmpv4.c | 18 +- src/decode-icmpv6.c | 59 +- src/decode-ipv4.c | 69 +- src/decode-ipv6.c | 6 +- src/decode-mpls.c | 10 +- src/decode-ppp.c | 8 +- src/decode-pppoe.c | 12 +- src/decode-raw.c | 6 +- src/decode-tcp.c | 16 +- src/decode-udp.c | 8 +- src/decode-vlan.c | 6 +- src/defrag.c | 63 +- src/detect-ack.c | 2 +- src/detect-app-layer-event.c | 10 +- src/detect-app-layer-protocol.c | 27 +- src/detect-asn1.c | 56 +- src/detect-base64-data.c | 12 +- src/detect-base64-decode.c | 18 +- src/detect-byte-extract.c | 144 ++-- src/detect-bytejump.c | 40 +- src/detect-bytetest.c | 54 +- src/detect-classtype.c | 6 +- src/detect-content.c | 208 ++--- src/detect-csum.c | 45 +- src/detect-dce-iface.c | 28 +- src/detect-dce-opnum.c | 18 +- src/detect-dce-stub-data.c | 15 +- src/detect-detection-filter.c | 27 +- src/detect-distance.c | 5 +- src/detect-dns-query.c | 17 +- src/detect-dsize.c | 44 +- src/detect-engine-address-ipv4.c | 20 +- src/detect-engine-address-ipv6.c | 85 +- src/detect-engine-address.c | 270 +++--- src/detect-engine-dcepayload.c | 92 +- src/detect-engine-event.c | 12 +- src/detect-engine-filedata-smtp.c | 6 +- src/detect-engine-hcbd.c | 62 +- src/detect-engine-hcd.c | 34 +- src/detect-engine-hhd.c | 66 +- src/detect-engine-hhhd.c | 75 +- src/detect-engine-hmd.c | 34 +- src/detect-engine-hrhd.c | 62 +- src/detect-engine-hrhhd.c | 75 +- src/detect-engine-hrl.c | 78 +- src/detect-engine-hrud.c | 60 +- src/detect-engine-hsbd.c | 80 +- src/detect-engine-hscd.c | 30 +- src/detect-engine-hsmd.c | 30 +- src/detect-engine-hua.c | 51 +- src/detect-engine-iponly.c | 30 +- src/detect-engine-modbus.c | 27 +- src/detect-engine-payload.c | 72 +- src/detect-engine-port.c | 85 +- src/detect-engine-proto.c | 26 +- src/detect-engine-siggroup.c | 14 +- src/detect-engine-sigorder.c | 26 +- src/detect-engine-state.c | 20 +- src/detect-engine-tag.c | 14 +- src/detect-engine-uri.c | 78 +- src/detect-engine.c | 18 +- src/detect-fast-pattern.c | 1342 ++++++++++++++--------------- src/detect-file-data.c | 10 +- src/detect-fileext.c | 6 +- src/detect-filemagic.c | 6 +- src/detect-filemd5.c | 2 +- src/detect-filename.c | 6 +- src/detect-filesize.c | 12 +- src/detect-flags.c | 34 +- src/detect-flow.c | 72 +- src/detect-flowbits.c | 18 +- src/detect-flowint.c | 64 +- src/detect-fragbits.c | 8 +- src/detect-fragoffset.c | 8 +- src/detect-ftpbounce.c | 6 +- src/detect-geoip.c | 30 +- src/detect-gid.c | 6 +- src/detect-hostbits.c | 14 +- src/detect-http-client-body.c | 62 +- src/detect-http-cookie.c | 30 +- src/detect-http-header.c | 48 +- src/detect-http-hh.c | 60 +- src/detect-http-hrh.c | 62 +- src/detect-http-method.c | 27 +- src/detect-http-raw-header.c | 42 +- src/detect-http-raw-uri.c | 24 +- src/detect-http-server-body.c | 92 +- src/detect-http-stat-code.c | 12 +- src/detect-http-stat-msg.c | 10 +- src/detect-http-ua.c | 60 +- src/detect-http-uri.c | 24 +- src/detect-icmp-id.c | 14 +- src/detect-icmp-seq.c | 8 +- src/detect-icode.c | 18 +- src/detect-id.c | 10 +- src/detect-ipopts.c | 8 +- src/detect-ipproto.c | 302 +++---- src/detect-iprep.c | 18 +- src/detect-isdataat.c | 40 +- src/detect-itype.c | 18 +- src/detect-l3proto.c | 6 +- src/detect-lua.c | 12 +- src/detect-mark.c | 8 +- src/detect-modbus.c | 27 +- src/detect-msg.c | 4 +- src/detect-parse.c | 98 +-- src/detect-pcre.c | 129 +-- src/detect-pkt-data.c | 2 +- src/detect-priority.c | 4 +- src/detect-reference.c | 6 +- src/detect-replace.c | 44 +- src/detect-rpc.c | 12 +- src/detect-sameip.c | 2 +- src/detect-seq.c | 4 +- src/detect-sid.c | 6 +- src/detect-ssh-proto-version.c | 15 +- src/detect-ssh-software-version.c | 18 +- src/detect-ssl-state.c | 14 +- src/detect-ssl-version.c | 15 +- src/detect-stream_size.c | 8 +- src/detect-tag.c | 10 +- src/detect-template-buffer.c | 2 +- src/detect-template.c | 5 +- src/detect-threshold.c | 35 +- src/detect-tls-version.c | 13 +- src/detect-tos.c | 24 +- src/detect-ttl.c | 18 +- src/detect-uricontent.c | 60 +- src/detect-urilen.c | 24 +- src/detect-window.c | 10 +- src/detect-within.c | 6 +- src/detect-xbits.c | 4 +- src/detect.c | 144 ++-- src/flow-bit.c | 22 +- src/flow-manager.c | 15 +- src/flow-storage.c | 6 +- src/flow.c | 14 +- src/host-bit.c | 22 +- src/host-storage.c | 6 +- src/ippair-bit.c | 22 +- src/ippair-storage.c | 6 +- src/log-droplog.c | 4 +- src/reputation.c | 30 +- src/stream-tcp-inline.c | 14 +- src/stream-tcp-reassemble.c | 180 ++-- src/stream-tcp-sack.c | 38 +- src/stream-tcp-util.c | 6 +- src/stream-tcp.c | 85 +- src/threads.c | 8 +- src/tmqh-flow.c | 9 +- src/util-action.c | 50 +- src/util-atomic.c | 2 +- src/util-bloomfilter-counting.c | 34 +- src/util-bloomfilter.c | 18 +- src/util-byte.c | 32 +- src/util-classification-config.c | 12 +- src/util-cuda-buffer.c | 12 +- src/util-cuda.c | 4 +- src/util-debug.c | 10 +- src/util-decode-asn1.c | 20 +- src/util-decode-mime.c | 16 +- src/util-hash.c | 24 +- src/util-hashlist.c | 24 +- src/util-host-os-info.c | 32 +- src/util-magic.c | 19 +- src/util-memcmp.c | 36 +- src/util-memrchr.c | 2 +- src/util-misc.c | 3 +- src/util-mpm-ac-bs.c | 60 +- src/util-mpm-ac-tile.c | 58 +- src/util-mpm-ac.c | 58 +- src/util-mpm-hs.c | 58 +- src/util-pool-thread.c | 16 +- src/util-pool.c | 14 +- src/util-profiling.c | 2 +- src/util-radix-tree.c | 44 +- src/util-reference-config.c | 12 +- src/util-ringbuffer.c | 10 +- src/util-rule-vars.c | 10 +- src/util-spm.c | 87 +- src/util-storage.c | 6 +- src/util-threshold-config.c | 55 +- src/util-unittest-helper.c | 20 +- src/util-unittest.c | 13 +- src/util-unittest.h | 3 +- 208 files changed, 4068 insertions(+), 3941 deletions(-) diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 41630f8a3ac0..9c2469df03b8 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -378,8 +378,8 @@ void AlertFastLogRegisterTests(void) #ifdef UNITTESTS - UtRegisterTest("AlertFastLogTest01", AlertFastLogTest01, 1); - UtRegisterTest("AlertFastLogTest02", AlertFastLogTest02, 1); + UtRegisterTest("AlertFastLogTest01", AlertFastLogTest01); + UtRegisterTest("AlertFastLogTest02", AlertFastLogTest02); #endif /* UNITTESTS */ diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index ebfa1822b49d..9b7c6d52b092 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -1967,11 +1967,12 @@ static int Unified2TestRotate01(void) void Unified2RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("Unified2Test01 -- Ipv4 test", Unified2Test01, 1); - UtRegisterTest("Unified2Test02 -- Ipv6 test", Unified2Test02, 1); - UtRegisterTest("Unified2Test03 -- GRE test", Unified2Test03, 1); - UtRegisterTest("Unified2Test04 -- PPP test", Unified2Test04, 1); - UtRegisterTest("Unified2Test05 -- Inline test", Unified2Test05, 1); - UtRegisterTest("Unified2TestRotate01 -- Rotate File", Unified2TestRotate01, 1); + UtRegisterTest("Unified2Test01 -- Ipv4 test", Unified2Test01); + UtRegisterTest("Unified2Test02 -- Ipv6 test", Unified2Test02); + UtRegisterTest("Unified2Test03 -- GRE test", Unified2Test03); + UtRegisterTest("Unified2Test04 -- PPP test", Unified2Test04); + UtRegisterTest("Unified2Test05 -- Inline test", Unified2Test05); + UtRegisterTest("Unified2TestRotate01 -- Rotate File", + Unified2TestRotate01); #endif /* UNITTESTS */ } diff --git a/src/app-layer-dcerpc-udp.c b/src/app-layer-dcerpc-udp.c index 58d714d040f4..a9c58df09faf 100644 --- a/src/app-layer-dcerpc-udp.c +++ b/src/app-layer-dcerpc-udp.c @@ -1110,6 +1110,6 @@ int DCERPCUDPParserTest01(void) void DCERPCUDPParserRegisterTests(void) { - UtRegisterTest("DCERPCUDPParserTest01", DCERPCUDPParserTest01, 1); + UtRegisterTest("DCERPCUDPParserTest01", DCERPCUDPParserTest01); } #endif diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 5e1d5ba784b8..1916b72aa2de 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -6382,25 +6382,25 @@ int DCERPCParserTest19(void) void DCERPCParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DCERPCParserTest01", DCERPCParserTest01, 1); - UtRegisterTest("DCERPCParserTest02", DCERPCParserTest02, 1); - UtRegisterTest("DCERPCParserTest03", DCERPCParserTest03, 1); - UtRegisterTest("DCERPCParserTest04", DCERPCParserTest04, 1); - UtRegisterTest("DCERPCParserTest05", DCERPCParserTest05, 1); - UtRegisterTest("DCERPCParserTest06", DCERPCParserTest06, 1); - UtRegisterTest("DCERPCParserTest07", DCERPCParserTest07, 1); - UtRegisterTest("DCERPCParserTest08", DCERPCParserTest08, 1); - UtRegisterTest("DCERPCParserTest09", DCERPCParserTest09, 1); - UtRegisterTest("DCERPCParserTest10", DCERPCParserTest10, 1); - UtRegisterTest("DCERPCParserTest11", DCERPCParserTest11, 1); - UtRegisterTest("DCERPCParserTest12", DCERPCParserTest12, 1); - UtRegisterTest("DCERPCParserTest13", DCERPCParserTest13, 1); - UtRegisterTest("DCERPCParserTest14", DCERPCParserTest14, 1); - UtRegisterTest("DCERPCParserTest15", DCERPCParserTest15, 1); - UtRegisterTest("DCERPCParserTest16", DCERPCParserTest16, 1); - UtRegisterTest("DCERPCParserTest17", DCERPCParserTest17, 1); - UtRegisterTest("DCERPCParserTest18", DCERPCParserTest18, 1); - UtRegisterTest("DCERPCParserTest19", DCERPCParserTest19, 1); + UtRegisterTest("DCERPCParserTest01", DCERPCParserTest01); + UtRegisterTest("DCERPCParserTest02", DCERPCParserTest02); + UtRegisterTest("DCERPCParserTest03", DCERPCParserTest03); + UtRegisterTest("DCERPCParserTest04", DCERPCParserTest04); + UtRegisterTest("DCERPCParserTest05", DCERPCParserTest05); + UtRegisterTest("DCERPCParserTest06", DCERPCParserTest06); + UtRegisterTest("DCERPCParserTest07", DCERPCParserTest07); + UtRegisterTest("DCERPCParserTest08", DCERPCParserTest08); + UtRegisterTest("DCERPCParserTest09", DCERPCParserTest09); + UtRegisterTest("DCERPCParserTest10", DCERPCParserTest10); + UtRegisterTest("DCERPCParserTest11", DCERPCParserTest11); + UtRegisterTest("DCERPCParserTest12", DCERPCParserTest12); + UtRegisterTest("DCERPCParserTest13", DCERPCParserTest13); + UtRegisterTest("DCERPCParserTest14", DCERPCParserTest14); + UtRegisterTest("DCERPCParserTest15", DCERPCParserTest15); + UtRegisterTest("DCERPCParserTest16", DCERPCParserTest16); + UtRegisterTest("DCERPCParserTest17", DCERPCParserTest17); + UtRegisterTest("DCERPCParserTest18", DCERPCParserTest18); + UtRegisterTest("DCERPCParserTest19", DCERPCParserTest19); #endif /* UNITTESTS */ return; diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index e5c36695b36a..323e0857ab8b 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -3728,26 +3728,26 @@ void AppLayerProtoDetectUnittestsRegister(void) { SCEnter(); - UtRegisterTest("AppLayerProtoDetectTest01", AppLayerProtoDetectTest01, 1); - UtRegisterTest("AppLayerProtoDetectTest02", AppLayerProtoDetectTest02, 1); - UtRegisterTest("AppLayerProtoDetectTest03", AppLayerProtoDetectTest03, 1); - UtRegisterTest("AppLayerProtoDetectTest04", AppLayerProtoDetectTest04, 1); - UtRegisterTest("AppLayerProtoDetectTest05", AppLayerProtoDetectTest05, 1); - UtRegisterTest("AppLayerProtoDetectTest06", AppLayerProtoDetectTest06, 1); - UtRegisterTest("AppLayerProtoDetectTest07", AppLayerProtoDetectTest07, 1); - UtRegisterTest("AppLayerProtoDetectTest08", AppLayerProtoDetectTest08, 1); - UtRegisterTest("AppLayerProtoDetectTest09", AppLayerProtoDetectTest09, 1); - UtRegisterTest("AppLayerProtoDetectTest10", AppLayerProtoDetectTest10, 1); - UtRegisterTest("AppLayerProtoDetectTest11", AppLayerProtoDetectTest11, 1); - UtRegisterTest("AppLayerProtoDetectTest12", AppLayerProtoDetectTest12, 1); - UtRegisterTest("AppLayerProtoDetectTest13", AppLayerProtoDetectTest13, 1); - UtRegisterTest("AppLayerProtoDetectTest14", AppLayerProtoDetectTest14, 1); - UtRegisterTest("AppLayerProtoDetectTest15", AppLayerProtoDetectTest15, 1); - UtRegisterTest("AppLayerProtoDetectTest16", AppLayerProtoDetectTest16, 1); - UtRegisterTest("AppLayerProtoDetectTest17", AppLayerProtoDetectTest17, 1); - UtRegisterTest("AppLayerProtoDetectTest18", AppLayerProtoDetectTest18, 1); - UtRegisterTest("AppLayerProtoDetectTest19", AppLayerProtoDetectTest19, 1); - UtRegisterTest("AppLayerProtoDetectTest20", AppLayerProtoDetectTest20, 1); + UtRegisterTest("AppLayerProtoDetectTest01", AppLayerProtoDetectTest01); + UtRegisterTest("AppLayerProtoDetectTest02", AppLayerProtoDetectTest02); + UtRegisterTest("AppLayerProtoDetectTest03", AppLayerProtoDetectTest03); + UtRegisterTest("AppLayerProtoDetectTest04", AppLayerProtoDetectTest04); + UtRegisterTest("AppLayerProtoDetectTest05", AppLayerProtoDetectTest05); + UtRegisterTest("AppLayerProtoDetectTest06", AppLayerProtoDetectTest06); + UtRegisterTest("AppLayerProtoDetectTest07", AppLayerProtoDetectTest07); + UtRegisterTest("AppLayerProtoDetectTest08", AppLayerProtoDetectTest08); + UtRegisterTest("AppLayerProtoDetectTest09", AppLayerProtoDetectTest09); + UtRegisterTest("AppLayerProtoDetectTest10", AppLayerProtoDetectTest10); + UtRegisterTest("AppLayerProtoDetectTest11", AppLayerProtoDetectTest11); + UtRegisterTest("AppLayerProtoDetectTest12", AppLayerProtoDetectTest12); + UtRegisterTest("AppLayerProtoDetectTest13", AppLayerProtoDetectTest13); + UtRegisterTest("AppLayerProtoDetectTest14", AppLayerProtoDetectTest14); + UtRegisterTest("AppLayerProtoDetectTest15", AppLayerProtoDetectTest15); + UtRegisterTest("AppLayerProtoDetectTest16", AppLayerProtoDetectTest16); + UtRegisterTest("AppLayerProtoDetectTest17", AppLayerProtoDetectTest17); + UtRegisterTest("AppLayerProtoDetectTest18", AppLayerProtoDetectTest18); + UtRegisterTest("AppLayerProtoDetectTest19", AppLayerProtoDetectTest19); + UtRegisterTest("AppLayerProtoDetectTest20", AppLayerProtoDetectTest20); SCReturn; } diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index e3ee01ffab43..01393ceee726 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -626,10 +626,10 @@ static int DNSUDPParserTest05 (void) void DNSUDPParserRegisterTests(void) { - UtRegisterTest("DNSUDPParserTest01", DNSUDPParserTest01, 1); - UtRegisterTest("DNSUDPParserTest02", DNSUDPParserTest02, 1); - UtRegisterTest("DNSUDPParserTest03", DNSUDPParserTest03, 1); - UtRegisterTest("DNSUDPParserTest04", DNSUDPParserTest04, 1); - UtRegisterTest("DNSUDPParserTest05", DNSUDPParserTest05, 1); + UtRegisterTest("DNSUDPParserTest01", DNSUDPParserTest01); + UtRegisterTest("DNSUDPParserTest02", DNSUDPParserTest02); + UtRegisterTest("DNSUDPParserTest03", DNSUDPParserTest03); + UtRegisterTest("DNSUDPParserTest04", DNSUDPParserTest04); + UtRegisterTest("DNSUDPParserTest05", DNSUDPParserTest05); } #endif diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index b5d4a03d98ec..985a75e02e06 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -671,11 +671,11 @@ int FTPParserTest10(void) void FTPParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("FTPParserTest01", FTPParserTest01, 1); - UtRegisterTest("FTPParserTest03", FTPParserTest03, 1); - UtRegisterTest("FTPParserTest06", FTPParserTest06, 1); - UtRegisterTest("FTPParserTest07", FTPParserTest07, 1); - UtRegisterTest("FTPParserTest10", FTPParserTest10, 1); + UtRegisterTest("FTPParserTest01", FTPParserTest01); + UtRegisterTest("FTPParserTest03", FTPParserTest03); + UtRegisterTest("FTPParserTest06", FTPParserTest06); + UtRegisterTest("FTPParserTest07", FTPParserTest07); + UtRegisterTest("FTPParserTest10", FTPParserTest10); #endif /* UNITTESTS */ } diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index 6de9d655720d..effc4fe08afa 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -1621,16 +1621,16 @@ static int HTPFileParserTest11(void) void HTPFileParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01, 1); - UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02, 1); - UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03, 1); - UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04, 1); - UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05, 1); - UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06, 1); - UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07, 1); - UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08, 1); - UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09, 1); - UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10, 1); - UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11, 1); + UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01); + UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02); + UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03); + UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04); + UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05); + UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06); + UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07); + UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08); + UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09); + UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10); + UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11); #endif /* UNITTESTS */ } diff --git a/src/app-layer-htp-xff.c b/src/app-layer-htp-xff.c index edc5168eea8f..8ba6637e9a1a 100644 --- a/src/app-layer-htp-xff.c +++ b/src/app-layer-htp-xff.c @@ -351,14 +351,14 @@ static int XFFTest09(void) { void HTPXFFParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("XFFTest01", XFFTest01, 1); - UtRegisterTest("XFFTest02", XFFTest02, 1); - UtRegisterTest("XFFTest03", XFFTest03, 1); - UtRegisterTest("XFFTest04", XFFTest04, 1); - UtRegisterTest("XFFTest05", XFFTest05, 1); - UtRegisterTest("XFFTest06", XFFTest06, 1); - UtRegisterTest("XFFTest07", XFFTest07, 1); - UtRegisterTest("XFFTest08", XFFTest08, 1); - UtRegisterTest("XFFTest09", XFFTest09, 1); + UtRegisterTest("XFFTest01", XFFTest01); + UtRegisterTest("XFFTest02", XFFTest02); + UtRegisterTest("XFFTest03", XFFTest03); + UtRegisterTest("XFFTest04", XFFTest04); + UtRegisterTest("XFFTest05", XFFTest05); + UtRegisterTest("XFFTest06", XFFTest06); + UtRegisterTest("XFFTest07", XFFTest07); + UtRegisterTest("XFFTest08", XFFTest08); + UtRegisterTest("XFFTest09", XFFTest09); #endif } diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 871519cb7cd5..50ff3e731460 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -6442,47 +6442,47 @@ int HTPParserTest19(void) void HTPParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HTPParserTest01", HTPParserTest01, 1); - UtRegisterTest("HTPParserTest01a", HTPParserTest01a, 1); - UtRegisterTest("HTPParserTest02", HTPParserTest02, 1); - UtRegisterTest("HTPParserTest03", HTPParserTest03, 1); - UtRegisterTest("HTPParserTest04", HTPParserTest04, 1); - UtRegisterTest("HTPParserTest05", HTPParserTest05, 1); - UtRegisterTest("HTPParserTest06", HTPParserTest06, 1); - UtRegisterTest("HTPParserTest07", HTPParserTest07, 1); - UtRegisterTest("HTPParserTest08", HTPParserTest08, 1); - UtRegisterTest("HTPParserTest09", HTPParserTest09, 1); - UtRegisterTest("HTPParserTest10", HTPParserTest10, 1); - UtRegisterTest("HTPParserTest11", HTPParserTest11, 1); - UtRegisterTest("HTPParserTest12", HTPParserTest12, 1); - UtRegisterTest("HTPParserTest13", HTPParserTest13, 1); - UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01, 1); - UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02, 1); - UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03, 1); + UtRegisterTest("HTPParserTest01", HTPParserTest01); + UtRegisterTest("HTPParserTest01a", HTPParserTest01a); + UtRegisterTest("HTPParserTest02", HTPParserTest02); + UtRegisterTest("HTPParserTest03", HTPParserTest03); + UtRegisterTest("HTPParserTest04", HTPParserTest04); + UtRegisterTest("HTPParserTest05", HTPParserTest05); + UtRegisterTest("HTPParserTest06", HTPParserTest06); + UtRegisterTest("HTPParserTest07", HTPParserTest07); + UtRegisterTest("HTPParserTest08", HTPParserTest08); + UtRegisterTest("HTPParserTest09", HTPParserTest09); + UtRegisterTest("HTPParserTest10", HTPParserTest10); + UtRegisterTest("HTPParserTest11", HTPParserTest11); + UtRegisterTest("HTPParserTest12", HTPParserTest12); + UtRegisterTest("HTPParserTest13", HTPParserTest13); + UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01); + UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02); + UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03); #if 0 /* disabled when we upgraded to libhtp 0.5.x */ UtRegisterTest("HTPParserConfigTest04", HTPParserConfigTest04, 1); #endif - UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01, 1); - UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02, 1); - UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03, 1); - UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04, 1); - UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05, 1); - UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06, 1); - UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07, 1); - UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08, 1); - UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09, 1); - - UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01, 1); - - UtRegisterTest("HTPSegvTest01", HTPSegvTest01, 1); - - UtRegisterTest("HTPParserTest14", HTPParserTest14, 1); - UtRegisterTest("HTPParserTest15", HTPParserTest15, 1); - UtRegisterTest("HTPParserTest16", HTPParserTest16, 1); - UtRegisterTest("HTPParserTest17", HTPParserTest17, 1); - UtRegisterTest("HTPParserTest18", HTPParserTest18, 1); - UtRegisterTest("HTPParserTest19", HTPParserTest19, 1); + UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01); + UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02); + UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03); + UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04); + UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05); + UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06); + UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07); + UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08); + UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09); + + UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01); + + UtRegisterTest("HTPSegvTest01", HTPSegvTest01); + + UtRegisterTest("HTPParserTest14", HTPParserTest14); + UtRegisterTest("HTPParserTest15", HTPParserTest15); + UtRegisterTest("HTPParserTest16", HTPParserTest16); + UtRegisterTest("HTPParserTest17", HTPParserTest17); + UtRegisterTest("HTPParserTest18", HTPParserTest18); + UtRegisterTest("HTPParserTest19", HTPParserTest19); HTPFileParserRegisterTests(); HTPXFFParserRegisterTests(); diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 3d3cda231aed..827f4042e3c5 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -2647,17 +2647,29 @@ static int ModbusParserTest12(void) { void ModbusParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request", ModbusParserTest01, 1); - UtRegisterTest("ModbusParserTest02 - Modbus Write Multiple registers request", ModbusParserTest02, 1); - UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request", ModbusParserTest03, 1); - UtRegisterTest("ModbusParserTest04 - Modbus Force Listen Only Mode request", ModbusParserTest04, 1); - UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version", ModbusParserTest05, 1); - UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response", ModbusParserTest06, 1); - UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request", ModbusParserTest07, 1); - UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid", ModbusParserTest08, 1); - UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets", ModbusParserTest09, 1); - UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet", ModbusParserTest10, 1); - UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request", ModbusParserTest11, 1); - UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length", ModbusParserTest12, 1); + UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request", + ModbusParserTest01); + UtRegisterTest("ModbusParserTest02 - Modbus Write Multiple registers request", + ModbusParserTest02); + UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request", + ModbusParserTest03); + UtRegisterTest("ModbusParserTest04 - Modbus Force Listen Only Mode request", + ModbusParserTest04); + UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version", + ModbusParserTest05); + UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response", + ModbusParserTest06); + UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request", + ModbusParserTest07); + UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid", + ModbusParserTest08); + UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets", + ModbusParserTest09); + UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet", + ModbusParserTest10); + UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request", + ModbusParserTest11); + UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length", + ModbusParserTest12); #endif /* UNITTESTS */ } diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 2650863e2082..ffbc0978af01 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -1378,8 +1378,8 @@ void AppLayerParserRegisterUnittests(void) } } - UtRegisterTest("AppLayerParserTest01", AppLayerParserTest01, 1); - UtRegisterTest("AppLayerParserTest02", AppLayerParserTest02, 1); + UtRegisterTest("AppLayerParserTest01", AppLayerParserTest01); + UtRegisterTest("AppLayerParserTest02", AppLayerParserTest02); SCReturn; } diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index c56422c21434..561d283f3530 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -2687,16 +2687,16 @@ int SMBParserTest10(void) void SMBParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SMBParserTest01", SMBParserTest01, 1); - UtRegisterTest("SMBParserTest02", SMBParserTest02, 1); - UtRegisterTest("SMBParserTest03", SMBParserTest03, 1); - UtRegisterTest("SMBParserTest04", SMBParserTest04, 1); - UtRegisterTest("SMBParserTest05", SMBParserTest05, 1); - UtRegisterTest("SMBParserTest06", SMBParserTest06, 1); - UtRegisterTest("SMBParserTest07", SMBParserTest07, 1); - UtRegisterTest("SMBParserTest08", SMBParserTest08, 1); - UtRegisterTest("SMBParserTest09", SMBParserTest09, 1); - UtRegisterTest("SMBParserTest10", SMBParserTest10, 1); + UtRegisterTest("SMBParserTest01", SMBParserTest01); + UtRegisterTest("SMBParserTest02", SMBParserTest02); + UtRegisterTest("SMBParserTest03", SMBParserTest03); + UtRegisterTest("SMBParserTest04", SMBParserTest04); + UtRegisterTest("SMBParserTest05", SMBParserTest05); + UtRegisterTest("SMBParserTest06", SMBParserTest06); + UtRegisterTest("SMBParserTest07", SMBParserTest07); + UtRegisterTest("SMBParserTest08", SMBParserTest08); + UtRegisterTest("SMBParserTest09", SMBParserTest09); + UtRegisterTest("SMBParserTest10", SMBParserTest10); #endif } diff --git a/src/app-layer-smb2.c b/src/app-layer-smb2.c index f412e1dfeebb..7f5ea2051be1 100644 --- a/src/app-layer-smb2.c +++ b/src/app-layer-smb2.c @@ -684,7 +684,7 @@ int SMB2ParserTest01(void) void SMB2ParserRegisterTests(void) { - UtRegisterTest("SMB2ParserTest01", SMB2ParserTest01, 1); + UtRegisterTest("SMB2ParserTest01", SMB2ParserTest01); } #endif diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 534d92e8d465..3402edfd27e4 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -5070,25 +5070,25 @@ int SMTPProcessDataChunkTest05(void){ void SMTPParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SMTPParserTest01", SMTPParserTest01, 1); - UtRegisterTest("SMTPParserTest02", SMTPParserTest02, 1); - UtRegisterTest("SMTPParserTest03", SMTPParserTest03, 1); - UtRegisterTest("SMTPParserTest04", SMTPParserTest04, 1); - UtRegisterTest("SMTPParserTest05", SMTPParserTest05, 1); - UtRegisterTest("SMTPParserTest06", SMTPParserTest06, 1); - UtRegisterTest("SMTPParserTest07", SMTPParserTest07, 1); - UtRegisterTest("SMTPParserTest08", SMTPParserTest08, 1); - UtRegisterTest("SMTPParserTest09", SMTPParserTest09, 1); - UtRegisterTest("SMTPParserTest10", SMTPParserTest10, 1); - UtRegisterTest("SMTPParserTest11", SMTPParserTest11, 1); - UtRegisterTest("SMTPParserTest12", SMTPParserTest12, 1); - UtRegisterTest("SMTPParserTest13", SMTPParserTest13, 1); - UtRegisterTest("SMTPParserTest14", SMTPParserTest14, 1); - UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01, 1); - UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02, 1); - UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03, 1); - UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04, 1); - UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05, 1); + UtRegisterTest("SMTPParserTest01", SMTPParserTest01); + UtRegisterTest("SMTPParserTest02", SMTPParserTest02); + UtRegisterTest("SMTPParserTest03", SMTPParserTest03); + UtRegisterTest("SMTPParserTest04", SMTPParserTest04); + UtRegisterTest("SMTPParserTest05", SMTPParserTest05); + UtRegisterTest("SMTPParserTest06", SMTPParserTest06); + UtRegisterTest("SMTPParserTest07", SMTPParserTest07); + UtRegisterTest("SMTPParserTest08", SMTPParserTest08); + UtRegisterTest("SMTPParserTest09", SMTPParserTest09); + UtRegisterTest("SMTPParserTest10", SMTPParserTest10); + UtRegisterTest("SMTPParserTest11", SMTPParserTest11); + UtRegisterTest("SMTPParserTest12", SMTPParserTest12); + UtRegisterTest("SMTPParserTest13", SMTPParserTest13); + UtRegisterTest("SMTPParserTest14", SMTPParserTest14); + UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01); + UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02); + UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03); + UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04); + UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05); #endif /* UNITTESTS */ return; diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index bbebcf698347..b96f6c9cad9a 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -2578,30 +2578,30 @@ static int SSHParserTest24(void) void SSHParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01, 1); - UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02, 1); - UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03, 1); - UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04, 1); - UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05, 1); - UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06, 1); - UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07, 1); - UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08, 1); - UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09, 1); - UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10, 1); - UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11, 1); - UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12, 1); - UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13, 1); - UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14, 1); - UtRegisterTest("SSHParserTest15", SSHParserTest15, 1); - UtRegisterTest("SSHParserTest16", SSHParserTest16, 1); - UtRegisterTest("SSHParserTest17", SSHParserTest17, 1); - UtRegisterTest("SSHParserTest18", SSHParserTest18, 1); - UtRegisterTest("SSHParserTest19", SSHParserTest19, 1); - UtRegisterTest("SSHParserTest20", SSHParserTest20, 1); - UtRegisterTest("SSHParserTest21", SSHParserTest21, 1); - UtRegisterTest("SSHParserTest22", SSHParserTest22, 1); - UtRegisterTest("SSHParserTest23", SSHParserTest23, 1); - UtRegisterTest("SSHParserTest24", SSHParserTest24, 1); + UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01); + UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02); + UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03); + UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04); + UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05); + UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06); + UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07); + UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08); + UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09); + UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10); + UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11); + UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12); + UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13); + UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14); + UtRegisterTest("SSHParserTest15", SSHParserTest15); + UtRegisterTest("SSHParserTest16", SSHParserTest16); + UtRegisterTest("SSHParserTest17", SSHParserTest17); + UtRegisterTest("SSHParserTest18", SSHParserTest18); + UtRegisterTest("SSHParserTest19", SSHParserTest19); + UtRegisterTest("SSHParserTest20", SSHParserTest20); + UtRegisterTest("SSHParserTest21", SSHParserTest21); + UtRegisterTest("SSHParserTest22", SSHParserTest22); + UtRegisterTest("SSHParserTest23", SSHParserTest23); + UtRegisterTest("SSHParserTest24", SSHParserTest24); #endif /* UNITTESTS */ } diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 9c571e06021e..6934586e1741 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -4340,36 +4340,36 @@ static int SSLParserTest25(void) void SSLParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SSLParserTest01", SSLParserTest01, 1); - UtRegisterTest("SSLParserTest02", SSLParserTest02, 1); - UtRegisterTest("SSLParserTest03", SSLParserTest03, 1); - UtRegisterTest("SSLParserTest04", SSLParserTest04, 1); + UtRegisterTest("SSLParserTest01", SSLParserTest01); + UtRegisterTest("SSLParserTest02", SSLParserTest02); + UtRegisterTest("SSLParserTest03", SSLParserTest03); + UtRegisterTest("SSLParserTest04", SSLParserTest04); /* Updated by Anoop Saldanha. Faulty tests. Disable it for now */ //UtRegisterTest("SSLParserTest05", SSLParserTest05, 1); //UtRegisterTest("SSLParserTest06", SSLParserTest06, 1); - UtRegisterTest("SSLParserTest07", SSLParserTest07, 1); + UtRegisterTest("SSLParserTest07", SSLParserTest07); //UtRegisterTest("SSLParserTest08", SSLParserTest08, 1); - UtRegisterTest("SSLParserTest09", SSLParserTest09, 1); - UtRegisterTest("SSLParserTest10", SSLParserTest10, 1); - UtRegisterTest("SSLParserTest11", SSLParserTest11, 1); - UtRegisterTest("SSLParserTest12", SSLParserTest12, 1); - UtRegisterTest("SSLParserTest13", SSLParserTest13, 1); - - UtRegisterTest("SSLParserTest14", SSLParserTest14, 1); - UtRegisterTest("SSLParserTest15", SSLParserTest15, 1); - UtRegisterTest("SSLParserTest16", SSLParserTest16, 1); - UtRegisterTest("SSLParserTest17", SSLParserTest17, 1); - UtRegisterTest("SSLParserTest18", SSLParserTest18, 1); - UtRegisterTest("SSLParserTest19", SSLParserTest19, 1); - UtRegisterTest("SSLParserTest20", SSLParserTest20, 1); - UtRegisterTest("SSLParserTest21", SSLParserTest21, 1); - UtRegisterTest("SSLParserTest22", SSLParserTest22, 1); - UtRegisterTest("SSLParserTest23", SSLParserTest23, 1); - UtRegisterTest("SSLParserTest24", SSLParserTest24, 1); - UtRegisterTest("SSLParserTest25", SSLParserTest25, 1); - - UtRegisterTest("SSLParserMultimsgTest01", SSLParserMultimsgTest01, 1); - UtRegisterTest("SSLParserMultimsgTest02", SSLParserMultimsgTest02, 1); + UtRegisterTest("SSLParserTest09", SSLParserTest09); + UtRegisterTest("SSLParserTest10", SSLParserTest10); + UtRegisterTest("SSLParserTest11", SSLParserTest11); + UtRegisterTest("SSLParserTest12", SSLParserTest12); + UtRegisterTest("SSLParserTest13", SSLParserTest13); + + UtRegisterTest("SSLParserTest14", SSLParserTest14); + UtRegisterTest("SSLParserTest15", SSLParserTest15); + UtRegisterTest("SSLParserTest16", SSLParserTest16); + UtRegisterTest("SSLParserTest17", SSLParserTest17); + UtRegisterTest("SSLParserTest18", SSLParserTest18); + UtRegisterTest("SSLParserTest19", SSLParserTest19); + UtRegisterTest("SSLParserTest20", SSLParserTest20); + UtRegisterTest("SSLParserTest21", SSLParserTest21); + UtRegisterTest("SSLParserTest22", SSLParserTest22); + UtRegisterTest("SSLParserTest23", SSLParserTest23); + UtRegisterTest("SSLParserTest24", SSLParserTest24); + UtRegisterTest("SSLParserTest25", SSLParserTest25); + + UtRegisterTest("SSLParserMultimsgTest01", SSLParserMultimsgTest01); + UtRegisterTest("SSLParserMultimsgTest02", SSLParserMultimsgTest02); #endif /* UNITTESTS */ return; diff --git a/src/app-layer.c b/src/app-layer.c index 96fa252c9c7e..5d29f127474b 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -3503,17 +3503,17 @@ void AppLayerUnittestsRegister(void) { SCEnter(); - UtRegisterTest("AppLayerTest01", AppLayerTest01, 1); - UtRegisterTest("AppLayerTest02", AppLayerTest02, 1); - UtRegisterTest("AppLayerTest03", AppLayerTest03, 1); - UtRegisterTest("AppLayerTest04", AppLayerTest04, 1); - UtRegisterTest("AppLayerTest05", AppLayerTest05, 1); - UtRegisterTest("AppLayerTest06", AppLayerTest06, 1); - UtRegisterTest("AppLayerTest07", AppLayerTest07, 1); - UtRegisterTest("AppLayerTest08", AppLayerTest08, 1); - UtRegisterTest("AppLayerTest09", AppLayerTest09, 1); - UtRegisterTest("AppLayerTest10", AppLayerTest10, 1); - UtRegisterTest("AppLayerTest11", AppLayerTest11, 1); + UtRegisterTest("AppLayerTest01", AppLayerTest01); + UtRegisterTest("AppLayerTest02", AppLayerTest02); + UtRegisterTest("AppLayerTest03", AppLayerTest03); + UtRegisterTest("AppLayerTest04", AppLayerTest04); + UtRegisterTest("AppLayerTest05", AppLayerTest05); + UtRegisterTest("AppLayerTest06", AppLayerTest06); + UtRegisterTest("AppLayerTest07", AppLayerTest07); + UtRegisterTest("AppLayerTest08", AppLayerTest08); + UtRegisterTest("AppLayerTest09", AppLayerTest09); + UtRegisterTest("AppLayerTest10", AppLayerTest10); + UtRegisterTest("AppLayerTest11", AppLayerTest11); SCReturn; } diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index 13ec04884571..85c65702c993 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -936,14 +936,14 @@ void ConfYamlRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ConfYamlSequenceTest", ConfYamlSequenceTest, 1); - UtRegisterTest("ConfYamlLoggingOutputTest", ConfYamlLoggingOutputTest, 1); - UtRegisterTest("ConfYamlNonYamlFileTest", ConfYamlNonYamlFileTest, 1); - UtRegisterTest("ConfYamlBadYamlVersionTest", ConfYamlBadYamlVersionTest, 1); + UtRegisterTest("ConfYamlSequenceTest", ConfYamlSequenceTest); + UtRegisterTest("ConfYamlLoggingOutputTest", ConfYamlLoggingOutputTest); + UtRegisterTest("ConfYamlNonYamlFileTest", ConfYamlNonYamlFileTest); + UtRegisterTest("ConfYamlBadYamlVersionTest", ConfYamlBadYamlVersionTest); UtRegisterTest("ConfYamlSecondLevelSequenceTest", - ConfYamlSecondLevelSequenceTest, 1); - UtRegisterTest("ConfYamlFileIncludeTest", ConfYamlFileIncludeTest, 1); - UtRegisterTest("ConfYamlOverrideTest", ConfYamlOverrideTest, 1); - UtRegisterTest("ConfYamlOverrideFinalTest", ConfYamlOverrideFinalTest, 1); + ConfYamlSecondLevelSequenceTest); + UtRegisterTest("ConfYamlFileIncludeTest", ConfYamlFileIncludeTest); + UtRegisterTest("ConfYamlOverrideTest", ConfYamlOverrideTest); + UtRegisterTest("ConfYamlOverrideFinalTest", ConfYamlOverrideFinalTest); #endif /* UNITTESTS */ } diff --git a/src/conf.c b/src/conf.c index e279a526d7ee..29af449209be 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1524,23 +1524,27 @@ static int ConfSetFromStringTest(void) void ConfRegisterTests(void) { - UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant, 1); - UtRegisterTest("ConfSetTest", ConfSetTest, 1); - UtRegisterTest("ConfTestSetAndGet", ConfTestSetAndGet, 1); - UtRegisterTest("ConfTestOverrideValue1", ConfTestOverrideValue1, 1); - UtRegisterTest("ConfTestOverrideValue2", ConfTestOverrideValue2, 1); - UtRegisterTest("ConfTestGetInt", ConfTestGetInt, 1); - UtRegisterTest("ConfTestGetBool", ConfTestGetBool, 1); - UtRegisterTest("ConfNodeLookupChildTest", ConfNodeLookupChildTest, 1); - UtRegisterTest("ConfNodeLookupChildValueTest", ConfNodeLookupChildValueTest, 1); - UtRegisterTest("ConfNodeRemoveTest", ConfNodeRemoveTest, 1); - UtRegisterTest("ConfGetChildValueWithDefaultTest", ConfGetChildValueWithDefaultTest, 1); - UtRegisterTest("ConfGetChildValueIntWithDefaultTest", ConfGetChildValueIntWithDefaultTest, 1); - UtRegisterTest("ConfGetChildValueBoolWithDefaultTest", ConfGetChildValueBoolWithDefaultTest, 1); - UtRegisterTest("ConfGetNodeOrCreateTest", ConfGetNodeOrCreateTest, 1); - UtRegisterTest("ConfNodePruneTest", ConfNodePruneTest, 1); - UtRegisterTest("ConfNodeIsSequenceTest", ConfNodeIsSequenceTest, 1); - UtRegisterTest("ConfSetFromStringTest", ConfSetFromStringTest, 1); + UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant); + UtRegisterTest("ConfSetTest", ConfSetTest); + UtRegisterTest("ConfTestSetAndGet", ConfTestSetAndGet); + UtRegisterTest("ConfTestOverrideValue1", ConfTestOverrideValue1); + UtRegisterTest("ConfTestOverrideValue2", ConfTestOverrideValue2); + UtRegisterTest("ConfTestGetInt", ConfTestGetInt); + UtRegisterTest("ConfTestGetBool", ConfTestGetBool); + UtRegisterTest("ConfNodeLookupChildTest", ConfNodeLookupChildTest); + UtRegisterTest("ConfNodeLookupChildValueTest", + ConfNodeLookupChildValueTest); + UtRegisterTest("ConfNodeRemoveTest", ConfNodeRemoveTest); + UtRegisterTest("ConfGetChildValueWithDefaultTest", + ConfGetChildValueWithDefaultTest); + UtRegisterTest("ConfGetChildValueIntWithDefaultTest", + ConfGetChildValueIntWithDefaultTest); + UtRegisterTest("ConfGetChildValueBoolWithDefaultTest", + ConfGetChildValueBoolWithDefaultTest); + UtRegisterTest("ConfGetNodeOrCreateTest", ConfGetNodeOrCreateTest); + UtRegisterTest("ConfNodePruneTest", ConfNodePruneTest); + UtRegisterTest("ConfNodeIsSequenceTest", ConfNodeIsSequenceTest); + UtRegisterTest("ConfSetFromStringTest", ConfSetFromStringTest); } #endif /* UNITTESTS */ diff --git a/src/counters.c b/src/counters.c index 1086e10c3697..c00b4fcf296f 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1519,16 +1519,16 @@ static int StatsTestCounterValues11() void StatsRegisterTests() { #ifdef UNITTESTS - UtRegisterTest("StatsTestCounterReg02", StatsTestCounterReg02, 1); - UtRegisterTest("StatsTestCounterReg03", StatsTestCounterReg03, 1); - UtRegisterTest("StatsTestCounterReg04", StatsTestCounterReg04, 1); - UtRegisterTest("StatsTestGetCntArray05", StatsTestGetCntArray05, 1); - UtRegisterTest("StatsTestGetCntArray06", StatsTestGetCntArray06, 1); - UtRegisterTest("StatsTestCntArraySize07", StatsTestCntArraySize07, 1); - UtRegisterTest("StatsTestUpdateCounter08", StatsTestUpdateCounter08, 1); - UtRegisterTest("StatsTestUpdateCounter09", StatsTestUpdateCounter09, 1); + UtRegisterTest("StatsTestCounterReg02", StatsTestCounterReg02); + UtRegisterTest("StatsTestCounterReg03", StatsTestCounterReg03); + UtRegisterTest("StatsTestCounterReg04", StatsTestCounterReg04); + UtRegisterTest("StatsTestGetCntArray05", StatsTestGetCntArray05); + UtRegisterTest("StatsTestGetCntArray06", StatsTestGetCntArray06); + UtRegisterTest("StatsTestCntArraySize07", StatsTestCntArraySize07); + UtRegisterTest("StatsTestUpdateCounter08", StatsTestUpdateCounter08); + UtRegisterTest("StatsTestUpdateCounter09", StatsTestUpdateCounter09); UtRegisterTest("StatsTestUpdateGlobalCounter10", - StatsTestUpdateGlobalCounter10, 1); - UtRegisterTest("StatsTestCounterValues11", StatsTestCounterValues11, 1); + StatsTestUpdateGlobalCounter10); + UtRegisterTest("StatsTestCounterValues11", StatsTestCounterValues11); #endif } diff --git a/src/decode-ethernet.c b/src/decode-ethernet.c index 0bc85cf5a7c0..cd82886c6bb6 100644 --- a/src/decode-ethernet.c +++ b/src/decode-ethernet.c @@ -144,7 +144,7 @@ static int DecodeEthernetTest01 (void) void DecodeEthernetRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeEthernetTest01", DecodeEthernetTest01, 1); + UtRegisterTest("DecodeEthernetTest01", DecodeEthernetTest01); #endif /* UNITTESTS */ } /** diff --git a/src/decode-gre.c b/src/decode-gre.c index 4c555ac010fd..da310bf350e0 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -403,9 +403,9 @@ static int DecodeGREtest03 (void) void DecodeGRERegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeGREtest01", DecodeGREtest01, 1); - UtRegisterTest("DecodeGREtest02", DecodeGREtest02, 1); - UtRegisterTest("DecodeGREtest03", DecodeGREtest03, 1); + UtRegisterTest("DecodeGREtest01", DecodeGREtest01); + UtRegisterTest("DecodeGREtest02", DecodeGREtest02); + UtRegisterTest("DecodeGREtest03", DecodeGREtest03); #endif /* UNITTESTS */ } /** diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index e67b68455e2d..3e08daa19753 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -769,17 +769,17 @@ static int DecodeICMPV4test08(void) void DecodeICMPV4RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeICMPV4test01", DecodeICMPV4test01, 1); - UtRegisterTest("DecodeICMPV4test02", DecodeICMPV4test02, 1); - UtRegisterTest("DecodeICMPV4test03", DecodeICMPV4test03, 1); - UtRegisterTest("DecodeICMPV4test04", DecodeICMPV4test04, 1); - UtRegisterTest("DecodeICMPV4test05", DecodeICMPV4test05, 1); + UtRegisterTest("DecodeICMPV4test01", DecodeICMPV4test01); + UtRegisterTest("DecodeICMPV4test02", DecodeICMPV4test02); + UtRegisterTest("DecodeICMPV4test03", DecodeICMPV4test03); + UtRegisterTest("DecodeICMPV4test04", DecodeICMPV4test04); + UtRegisterTest("DecodeICMPV4test05", DecodeICMPV4test05); UtRegisterTest("ICMPV4CalculateValidChecksumtest05", - ICMPV4CalculateValidChecksumtest05, 1); + ICMPV4CalculateValidChecksumtest05); UtRegisterTest("ICMPV4CalculateInvalidChecksumtest06", - ICMPV4CalculateInvalidChecksumtest06, 1); - UtRegisterTest("DecodeICMPV4InvalidType", ICMPV4InvalidType07, 1); - UtRegisterTest("DecodeICMPV4test08", DecodeICMPV4test08, 1); + ICMPV4CalculateInvalidChecksumtest06); + UtRegisterTest("DecodeICMPV4InvalidType", ICMPV4InvalidType07); + UtRegisterTest("DecodeICMPV4test08", DecodeICMPV4test08); #endif /* UNITTESTS */ } /** diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index d2e19aa366f8..238a6cf6faeb 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -1612,46 +1612,49 @@ static int ICMPV6RedirectTestUnknownCode(void) void DecodeICMPV6RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ICMPV6CalculateValidChecksumtest01", ICMPV6CalculateValidChecksumtest01, 1); - UtRegisterTest("ICMPV6CalculateInValidChecksumtest02", ICMPV6CalculateInvalidChecksumtest02, 1); - - UtRegisterTest("ICMPV6ParamProbTest01 (Valid)", ICMPV6ParamProbTest01, 1); - UtRegisterTest("ICMPV6DestUnreachTest01 (Valid)", ICMPV6DestUnreachTest01, 1); - UtRegisterTest("ICMPV6PktTooBigTest01 (Valid)", ICMPV6PktTooBigTest01, 1); - UtRegisterTest("ICMPV6TimeExceedTest01 (Valid)", ICMPV6TimeExceedTest01, 1); - UtRegisterTest("ICMPV6EchoReqTest01 (Valid)", ICMPV6EchoReqTest01, 1); - UtRegisterTest("ICMPV6EchoRepTest01 (Valid)", ICMPV6EchoRepTest01, 1); - - UtRegisterTest("ICMPV6ParamProbTest02 (Invalid)", ICMPV6ParamProbTest02, 1); - UtRegisterTest("ICMPV6DestUnreachTest02 (Invalid)", ICMPV6DestUnreachTest02, 1); - UtRegisterTest("ICMPV6PktTooBigTest02 (Invalid)", ICMPV6PktTooBigTest02, 1); - UtRegisterTest("ICMPV6TimeExceedTest02 (Invalid)", ICMPV6TimeExceedTest02, 1); - UtRegisterTest("ICMPV6EchoReqTest02 (Invalid)", ICMPV6EchoReqTest02, 1); - UtRegisterTest("ICMPV6EchoRepTest02 (Invalid)", ICMPV6EchoRepTest02, 1); - - UtRegisterTest("ICMPV6PayloadTest01", ICMPV6PayloadTest01, 1); + UtRegisterTest("ICMPV6CalculateValidChecksumtest01", + ICMPV6CalculateValidChecksumtest01); + UtRegisterTest("ICMPV6CalculateInValidChecksumtest02", + ICMPV6CalculateInvalidChecksumtest02); + + UtRegisterTest("ICMPV6ParamProbTest01 (Valid)", ICMPV6ParamProbTest01); + UtRegisterTest("ICMPV6DestUnreachTest01 (Valid)", ICMPV6DestUnreachTest01); + UtRegisterTest("ICMPV6PktTooBigTest01 (Valid)", ICMPV6PktTooBigTest01); + UtRegisterTest("ICMPV6TimeExceedTest01 (Valid)", ICMPV6TimeExceedTest01); + UtRegisterTest("ICMPV6EchoReqTest01 (Valid)", ICMPV6EchoReqTest01); + UtRegisterTest("ICMPV6EchoRepTest01 (Valid)", ICMPV6EchoRepTest01); + + UtRegisterTest("ICMPV6ParamProbTest02 (Invalid)", ICMPV6ParamProbTest02); + UtRegisterTest("ICMPV6DestUnreachTest02 (Invalid)", + ICMPV6DestUnreachTest02); + UtRegisterTest("ICMPV6PktTooBigTest02 (Invalid)", ICMPV6PktTooBigTest02); + UtRegisterTest("ICMPV6TimeExceedTest02 (Invalid)", ICMPV6TimeExceedTest02); + UtRegisterTest("ICMPV6EchoReqTest02 (Invalid)", ICMPV6EchoReqTest02); + UtRegisterTest("ICMPV6EchoRepTest02 (Invalid)", ICMPV6EchoRepTest02); + + UtRegisterTest("ICMPV6PayloadTest01", ICMPV6PayloadTest01); UtRegisterTest("ICMPV6RouterSolicitTestKnownCode", - ICMPV6RouterSolicitTestKnownCode, 1); + ICMPV6RouterSolicitTestKnownCode); UtRegisterTest("ICMPV6RouterSolicitTestUnknownCode", - ICMPV6RouterSolicitTestUnknownCode, 1); + ICMPV6RouterSolicitTestUnknownCode); UtRegisterTest("ICMPV6RouterAdvertTestKnownCode", - ICMPV6RouterAdvertTestKnownCode, 1); + ICMPV6RouterAdvertTestKnownCode); UtRegisterTest("ICMPV6RouterAdvertTestUnknownCode", - ICMPV6RouterAdvertTestUnknownCode, 1); + ICMPV6RouterAdvertTestUnknownCode); UtRegisterTest("ICMPV6NeighbourSolicitTestKnownCode", - ICMPV6NeighbourSolicitTestKnownCode, 1); + ICMPV6NeighbourSolicitTestKnownCode); UtRegisterTest("ICMPV6NeighbourSolicitTestUnknownCode", - ICMPV6NeighbourSolicitTestUnknownCode, 1); + ICMPV6NeighbourSolicitTestUnknownCode); UtRegisterTest("ICMPV6NeighbourAdvertTestKnownCode", - ICMPV6NeighbourAdvertTestKnownCode, 1); + ICMPV6NeighbourAdvertTestKnownCode); UtRegisterTest("ICMPV6NeighbourAdvertTestUnknownCode", - ICMPV6NeighbourAdvertTestUnknownCode, 1); + ICMPV6NeighbourAdvertTestUnknownCode); - UtRegisterTest("ICMPV6RedirectTestKnownCode", ICMPV6RedirectTestKnownCode, 1); + UtRegisterTest("ICMPV6RedirectTestKnownCode", ICMPV6RedirectTestKnownCode); UtRegisterTest("ICMPV6RedirectTestUnknownCode", - ICMPV6RedirectTestUnknownCode, 1); + ICMPV6RedirectTestUnknownCode); #endif /* UNITTESTS */ } /** diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 7979e975bb9a..807ad78ed94a 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -1871,41 +1871,44 @@ int DecodeIPV4DefragTest03(void) void DecodeIPV4RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeIPV4OptionsNONETest01", DecodeIPV4OptionsNONETest01, 1); - UtRegisterTest("DecodeIPV4OptionsEOLTest01", DecodeIPV4OptionsEOLTest01, 1); - UtRegisterTest("DecodeIPV4OptionsNOPTest01", DecodeIPV4OptionsNOPTest01, 1); - UtRegisterTest("DecodeIPV4OptionsRRTest01", DecodeIPV4OptionsRRTest01, 1); - UtRegisterTest("DecodeIPV4OptionsRRTest02", DecodeIPV4OptionsRRTest02, 1); - UtRegisterTest("DecodeIPV4OptionsRRTest03", DecodeIPV4OptionsRRTest03, 1); - UtRegisterTest("DecodeIPV4OptionsRRTest04", DecodeIPV4OptionsRRTest04, 1); - UtRegisterTest("DecodeIPV4OptionsQSTest01", DecodeIPV4OptionsQSTest01, 1); - UtRegisterTest("DecodeIPV4OptionsQSTest02", DecodeIPV4OptionsQSTest02, 1); - UtRegisterTest("DecodeIPV4OptionsTSTest01", DecodeIPV4OptionsTSTest01, 1); - UtRegisterTest("DecodeIPV4OptionsTSTest02", DecodeIPV4OptionsTSTest02, 1); - UtRegisterTest("DecodeIPV4OptionsTSTest03", DecodeIPV4OptionsTSTest03, 1); - UtRegisterTest("DecodeIPV4OptionsTSTest04", DecodeIPV4OptionsTSTest04, 1); - UtRegisterTest("DecodeIPV4OptionsSECTest01", DecodeIPV4OptionsSECTest01, 1); - UtRegisterTest("DecodeIPV4OptionsSECTest02", DecodeIPV4OptionsSECTest02, 1); - UtRegisterTest("DecodeIPV4OptionsLSRRTest01", DecodeIPV4OptionsLSRRTest01, 1); - UtRegisterTest("DecodeIPV4OptionsLSRRTest02", DecodeIPV4OptionsLSRRTest02, 1); - UtRegisterTest("DecodeIPV4OptionsLSRRTest03", DecodeIPV4OptionsLSRRTest03, 1); - UtRegisterTest("DecodeIPV4OptionsLSRRTest04", DecodeIPV4OptionsLSRRTest04, 1); - UtRegisterTest("DecodeIPV4OptionsCIPSOTest01", DecodeIPV4OptionsCIPSOTest01, 1); - UtRegisterTest("DecodeIPV4OptionsSIDTest01", DecodeIPV4OptionsSIDTest01, 1); - UtRegisterTest("DecodeIPV4OptionsSIDTest02", DecodeIPV4OptionsSIDTest02, 1); - UtRegisterTest("DecodeIPV4OptionsSSRRTest01", DecodeIPV4OptionsSSRRTest01, 1); - UtRegisterTest("DecodeIPV4OptionsSSRRTest02", DecodeIPV4OptionsSSRRTest02, 1); - UtRegisterTest("DecodeIPV4OptionsSSRRTest03", DecodeIPV4OptionsSSRRTest03, 1); - UtRegisterTest("DecodeIPV4OptionsSSRRTest04", DecodeIPV4OptionsSSRRTest04, 1); - UtRegisterTest("DecodeIPV4OptionsRTRALTTest01", DecodeIPV4OptionsRTRALTTest01, 1); - UtRegisterTest("DecodeIPV4OptionsRTRALTTest02", DecodeIPV4OptionsRTRALTTest02, 1); + UtRegisterTest("DecodeIPV4OptionsNONETest01", DecodeIPV4OptionsNONETest01); + UtRegisterTest("DecodeIPV4OptionsEOLTest01", DecodeIPV4OptionsEOLTest01); + UtRegisterTest("DecodeIPV4OptionsNOPTest01", DecodeIPV4OptionsNOPTest01); + UtRegisterTest("DecodeIPV4OptionsRRTest01", DecodeIPV4OptionsRRTest01); + UtRegisterTest("DecodeIPV4OptionsRRTest02", DecodeIPV4OptionsRRTest02); + UtRegisterTest("DecodeIPV4OptionsRRTest03", DecodeIPV4OptionsRRTest03); + UtRegisterTest("DecodeIPV4OptionsRRTest04", DecodeIPV4OptionsRRTest04); + UtRegisterTest("DecodeIPV4OptionsQSTest01", DecodeIPV4OptionsQSTest01); + UtRegisterTest("DecodeIPV4OptionsQSTest02", DecodeIPV4OptionsQSTest02); + UtRegisterTest("DecodeIPV4OptionsTSTest01", DecodeIPV4OptionsTSTest01); + UtRegisterTest("DecodeIPV4OptionsTSTest02", DecodeIPV4OptionsTSTest02); + UtRegisterTest("DecodeIPV4OptionsTSTest03", DecodeIPV4OptionsTSTest03); + UtRegisterTest("DecodeIPV4OptionsTSTest04", DecodeIPV4OptionsTSTest04); + UtRegisterTest("DecodeIPV4OptionsSECTest01", DecodeIPV4OptionsSECTest01); + UtRegisterTest("DecodeIPV4OptionsSECTest02", DecodeIPV4OptionsSECTest02); + UtRegisterTest("DecodeIPV4OptionsLSRRTest01", DecodeIPV4OptionsLSRRTest01); + UtRegisterTest("DecodeIPV4OptionsLSRRTest02", DecodeIPV4OptionsLSRRTest02); + UtRegisterTest("DecodeIPV4OptionsLSRRTest03", DecodeIPV4OptionsLSRRTest03); + UtRegisterTest("DecodeIPV4OptionsLSRRTest04", DecodeIPV4OptionsLSRRTest04); + UtRegisterTest("DecodeIPV4OptionsCIPSOTest01", + DecodeIPV4OptionsCIPSOTest01); + UtRegisterTest("DecodeIPV4OptionsSIDTest01", DecodeIPV4OptionsSIDTest01); + UtRegisterTest("DecodeIPV4OptionsSIDTest02", DecodeIPV4OptionsSIDTest02); + UtRegisterTest("DecodeIPV4OptionsSSRRTest01", DecodeIPV4OptionsSSRRTest01); + UtRegisterTest("DecodeIPV4OptionsSSRRTest02", DecodeIPV4OptionsSSRRTest02); + UtRegisterTest("DecodeIPV4OptionsSSRRTest03", DecodeIPV4OptionsSSRRTest03); + UtRegisterTest("DecodeIPV4OptionsSSRRTest04", DecodeIPV4OptionsSSRRTest04); + UtRegisterTest("DecodeIPV4OptionsRTRALTTest01", + DecodeIPV4OptionsRTRALTTest01); + UtRegisterTest("DecodeIPV4OptionsRTRALTTest02", + DecodeIPV4OptionsRTRALTTest02); UtRegisterTest("IPV4CalculateValidChecksumtest01", - IPV4CalculateValidChecksumtest01, 1); + IPV4CalculateValidChecksumtest01); UtRegisterTest("IPV4CalculateInvalidChecksumtest02", - IPV4CalculateInvalidChecksumtest02, 1); - UtRegisterTest("DecodeIPV4DefragTest01", DecodeIPV4DefragTest01, 1); - UtRegisterTest("DecodeIPV4DefragTest02", DecodeIPV4DefragTest02, 1); - UtRegisterTest("DecodeIPV4DefragTest03", DecodeIPV4DefragTest03, 1); + IPV4CalculateInvalidChecksumtest02); + UtRegisterTest("DecodeIPV4DefragTest01", DecodeIPV4DefragTest01); + UtRegisterTest("DecodeIPV4DefragTest02", DecodeIPV4DefragTest02); + UtRegisterTest("DecodeIPV4DefragTest03", DecodeIPV4DefragTest03); #endif /* UNITTESTS */ } /** diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index 21ae5226e2ce..e63624219957 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -990,9 +990,9 @@ static int DecodeIPV6HopTest01 (void) void DecodeIPV6RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeIPV6FragTest01", DecodeIPV6FragTest01, 1); - UtRegisterTest("DecodeIPV6RouteTest01", DecodeIPV6RouteTest01, 1); - UtRegisterTest("DecodeIPV6HopTest01", DecodeIPV6HopTest01, 1); + UtRegisterTest("DecodeIPV6FragTest01", DecodeIPV6FragTest01); + UtRegisterTest("DecodeIPV6RouteTest01", DecodeIPV6RouteTest01); + UtRegisterTest("DecodeIPV6HopTest01", DecodeIPV6HopTest01); #endif /* UNITTESTS */ } diff --git a/src/decode-mpls.c b/src/decode-mpls.c index 1569ebfbf6b7..815592e1ff58 100644 --- a/src/decode-mpls.c +++ b/src/decode-mpls.c @@ -312,14 +312,14 @@ void DecodeMPLSRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeMPLSTestHeaderTooSmall", - DecodeMPLSTestHeaderTooSmall, 1); + DecodeMPLSTestHeaderTooSmall); UtRegisterTest("DecodeMPLSTestBadLabelRouterAlert", - DecodeMPLSTestBadLabelRouterAlert, 1); + DecodeMPLSTestBadLabelRouterAlert); UtRegisterTest("DecodeMPLSTestBadLabelImplicitNull", - DecodeMPLSTestBadLabelImplicitNull, 1); + DecodeMPLSTestBadLabelImplicitNull); UtRegisterTest("DecodeMPLSTestBadLabelReserved", - DecodeMPLSTestBadLabelReserved, 1); + DecodeMPLSTestBadLabelReserved); UtRegisterTest("DecodeMPLSTestUnknownPayloadType", - DecodeMPLSTestUnknownPayloadType, 1); + DecodeMPLSTestUnknownPayloadType); #endif /* UNITTESTS */ } diff --git a/src/decode-ppp.c b/src/decode-ppp.c index f4ea670cfe49..6fff62cd174c 100644 --- a/src/decode-ppp.c +++ b/src/decode-ppp.c @@ -300,10 +300,10 @@ static int DecodePPPtest04 (void) void DecodePPPRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodePPPtest01", DecodePPPtest01, 1); - UtRegisterTest("DecodePPPtest02", DecodePPPtest02, 1); - UtRegisterTest("DecodePPPtest03", DecodePPPtest03, 1); - UtRegisterTest("DecodePPPtest04", DecodePPPtest04, 1); + UtRegisterTest("DecodePPPtest01", DecodePPPtest01); + UtRegisterTest("DecodePPPtest02", DecodePPPtest02); + UtRegisterTest("DecodePPPtest03", DecodePPPtest03); + UtRegisterTest("DecodePPPtest04", DecodePPPtest04); #endif /* UNITTESTS */ } diff --git a/src/decode-pppoe.c b/src/decode-pppoe.c index b6f5031fa7db..ae2e8127b76c 100644 --- a/src/decode-pppoe.c +++ b/src/decode-pppoe.c @@ -446,12 +446,12 @@ static int DecodePPPOEtest06 (void) void DecodePPPOERegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodePPPOEtest01", DecodePPPOEtest01, 1); - UtRegisterTest("DecodePPPOEtest02", DecodePPPOEtest02, 1); - UtRegisterTest("DecodePPPOEtest03", DecodePPPOEtest03, 1); - UtRegisterTest("DecodePPPOEtest04", DecodePPPOEtest04, 1); - UtRegisterTest("DecodePPPOEtest05", DecodePPPOEtest05, 1); - UtRegisterTest("DecodePPPOEtest06", DecodePPPOEtest06, 1); + UtRegisterTest("DecodePPPOEtest01", DecodePPPOEtest01); + UtRegisterTest("DecodePPPOEtest02", DecodePPPOEtest02); + UtRegisterTest("DecodePPPOEtest03", DecodePPPOEtest03); + UtRegisterTest("DecodePPPOEtest04", DecodePPPOEtest04); + UtRegisterTest("DecodePPPOEtest05", DecodePPPOEtest05); + UtRegisterTest("DecodePPPOEtest06", DecodePPPOEtest06); #endif /* UNITTESTS */ } diff --git a/src/decode-raw.c b/src/decode-raw.c index 8df2bc845dfc..d174ab376617 100644 --- a/src/decode-raw.c +++ b/src/decode-raw.c @@ -221,9 +221,9 @@ static int DecodeRawTest03 (void) void DecodeRawRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeRawTest01", DecodeRawTest01, 1); - UtRegisterTest("DecodeRawTest02", DecodeRawTest02, 1); - UtRegisterTest("DecodeRawTest03", DecodeRawTest03, 1); + UtRegisterTest("DecodeRawTest01", DecodeRawTest01); + UtRegisterTest("DecodeRawTest02", DecodeRawTest02); + UtRegisterTest("DecodeRawTest03", DecodeRawTest03); #endif /* UNITTESTS */ } /** diff --git a/src/decode-tcp.c b/src/decode-tcp.c index d7f3522c05eb..36a63d3c30b6 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -511,17 +511,17 @@ void DecodeTCPRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("TCPCalculateValidChecksumtest01", - TCPCalculateValidChecksumtest01, 1); + TCPCalculateValidChecksumtest01); UtRegisterTest("TCPCalculateInvalidChecksumtest02", - TCPCalculateInvalidChecksumtest02, 1); + TCPCalculateInvalidChecksumtest02); UtRegisterTest("TCPV6CalculateValidChecksumtest03", - TCPV6CalculateValidChecksumtest03, 1); + TCPV6CalculateValidChecksumtest03); UtRegisterTest("TCPV6CalculateInvalidChecksumtest04", - TCPV6CalculateInvalidChecksumtest04, 1); - UtRegisterTest("TCPGetWscaleTest01", TCPGetWscaleTest01, 1); - UtRegisterTest("TCPGetWscaleTest02", TCPGetWscaleTest02, 1); - UtRegisterTest("TCPGetWscaleTest03", TCPGetWscaleTest03, 1); - UtRegisterTest("TCPGetSackTest01", TCPGetSackTest01, 1); + TCPV6CalculateInvalidChecksumtest04); + UtRegisterTest("TCPGetWscaleTest01", TCPGetWscaleTest01); + UtRegisterTest("TCPGetWscaleTest02", TCPGetWscaleTest02); + UtRegisterTest("TCPGetWscaleTest03", TCPGetWscaleTest03); + UtRegisterTest("TCPGetSackTest01", TCPGetSackTest01); #endif /* UNITTESTS */ } /** diff --git a/src/decode-udp.c b/src/decode-udp.c index cef9a45488ee..24f9207b8cbf 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -204,13 +204,13 @@ void DecodeUDPV4RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("UDPV4CalculateValidChecksumtest01", - UDPV4CalculateValidChecksumtest01, 1); + UDPV4CalculateValidChecksumtest01); UtRegisterTest("UDPV4CalculateInvalidChecksumtest02", - UDPV4CalculateInvalidChecksumtest02, 1); + UDPV4CalculateInvalidChecksumtest02); UtRegisterTest("UDPV6CalculateValidChecksumtest03", - UDPV6CalculateValidChecksumtest03, 1); + UDPV6CalculateValidChecksumtest03); UtRegisterTest("UDPV6CalculateInvalidChecksumtest04", - UDPV6CalculateInvalidChecksumtest04, 1); + UDPV6CalculateInvalidChecksumtest04); #endif /* UNITTESTS */ } /** diff --git a/src/decode-vlan.c b/src/decode-vlan.c index 166be0ff0a16..dc07a6851902 100644 --- a/src/decode-vlan.c +++ b/src/decode-vlan.c @@ -268,9 +268,9 @@ static int DecodeVLANtest03 (void) void DecodeVLANRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeVLANtest01", DecodeVLANtest01, 1); - UtRegisterTest("DecodeVLANtest02", DecodeVLANtest02, 1); - UtRegisterTest("DecodeVLANtest03", DecodeVLANtest03, 1); + UtRegisterTest("DecodeVLANtest01", DecodeVLANtest01); + UtRegisterTest("DecodeVLANtest02", DecodeVLANtest02); + UtRegisterTest("DecodeVLANtest03", DecodeVLANtest03); #endif /* UNITTESTS */ } diff --git a/src/defrag.c b/src/defrag.c index f3de97edd9a3..6ed46fe87288 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -2544,50 +2544,41 @@ void DefragRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DefragInOrderSimpleTest", - DefragInOrderSimpleTest, 1); - UtRegisterTest("DefragReverseSimpleTest", - DefragReverseSimpleTest, 1); - UtRegisterTest("DefragSturgesNovakBsdTest", - DefragSturgesNovakBsdTest, 1); - UtRegisterTest("DefragSturgesNovakLinuxTest", - DefragSturgesNovakLinuxTest, 1); + UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest); + UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest); + UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest); + UtRegisterTest("DefragSturgesNovakLinuxTest", DefragSturgesNovakLinuxTest); UtRegisterTest("DefragSturgesNovakWindowsTest", - DefragSturgesNovakWindowsTest, 1); + DefragSturgesNovakWindowsTest); UtRegisterTest("DefragSturgesNovakSolarisTest", - DefragSturgesNovakSolarisTest, 1); - UtRegisterTest("DefragSturgesNovakFirstTest", - DefragSturgesNovakFirstTest, 1); - UtRegisterTest("DefragSturgesNovakLastTest", - DefragSturgesNovakLastTest, 1); - - UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest, 1); - UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest, 1); - - UtRegisterTest("IPV6DefragInOrderSimpleTest", - IPV6DefragInOrderSimpleTest, 1); - UtRegisterTest("IPV6DefragReverseSimpleTest", - IPV6DefragReverseSimpleTest, 1); + DefragSturgesNovakSolarisTest); + UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest); + UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest); + + UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest); + UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest); + + UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest); + UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest); UtRegisterTest("IPV6DefragSturgesNovakBsdTest", - IPV6DefragSturgesNovakBsdTest, 1); + IPV6DefragSturgesNovakBsdTest); UtRegisterTest("IPV6DefragSturgesNovakLinuxTest", - IPV6DefragSturgesNovakLinuxTest, 1); + IPV6DefragSturgesNovakLinuxTest); UtRegisterTest("IPV6DefragSturgesNovakWindowsTest", - IPV6DefragSturgesNovakWindowsTest, 1); + IPV6DefragSturgesNovakWindowsTest); UtRegisterTest("IPV6DefragSturgesNovakSolarisTest", - IPV6DefragSturgesNovakSolarisTest, 1); + IPV6DefragSturgesNovakSolarisTest); UtRegisterTest("IPV6DefragSturgesNovakFirstTest", - IPV6DefragSturgesNovakFirstTest, 1); + IPV6DefragSturgesNovakFirstTest); UtRegisterTest("IPV6DefragSturgesNovakLastTest", - IPV6DefragSturgesNovakLastTest, 1); - - UtRegisterTest("DefragVlanTest", DefragVlanTest, 1); - UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest, 1); - UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest, 1); - UtRegisterTest("DefragTimeoutTest", - DefragTimeoutTest, 1); - UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test, 1); - UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test, 1); + IPV6DefragSturgesNovakLastTest); + + UtRegisterTest("DefragVlanTest", DefragVlanTest); + UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest); + UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest); + UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest); + UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test); + UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test); #endif /* UNITTESTS */ } diff --git a/src/detect-ack.c b/src/detect-ack.c index cb2bbc0858d9..eb1d8e64959d 100644 --- a/src/detect-ack.c +++ b/src/detect-ack.c @@ -269,7 +269,7 @@ static int DetectAckSigTest01(void) static void DetectAckRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectAckSigTest01", DetectAckSigTest01, 1); + UtRegisterTest("DetectAckSigTest01", DetectAckSigTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 63d401173830..0c9e0d949da6 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -825,11 +825,11 @@ int DetectAppLayerEventTest05(void) void DetectAppLayerEventRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectAppLayerEventTest01", DetectAppLayerEventTest01, 1); - UtRegisterTest("DetectAppLayerEventTest02", DetectAppLayerEventTest02, 1); - UtRegisterTest("DetectAppLayerEventTest03", DetectAppLayerEventTest03, 1); - UtRegisterTest("DetectAppLayerEventTest04", DetectAppLayerEventTest04, 1); - UtRegisterTest("DetectAppLayerEventTest05", DetectAppLayerEventTest05, 1); + UtRegisterTest("DetectAppLayerEventTest01", DetectAppLayerEventTest01); + UtRegisterTest("DetectAppLayerEventTest02", DetectAppLayerEventTest02); + UtRegisterTest("DetectAppLayerEventTest03", DetectAppLayerEventTest03); + UtRegisterTest("DetectAppLayerEventTest04", DetectAppLayerEventTest04); + UtRegisterTest("DetectAppLayerEventTest05", DetectAppLayerEventTest05); #endif /* UNITTESTS */ return; diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 65af621e910c..c0d210900b0c 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -392,15 +392,24 @@ int DetectAppLayerProtocolTest09(void) void DetectAppLayerProtocolRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectAppLayerProtocolTest01", DetectAppLayerProtocolTest01, 1); - UtRegisterTest("DetectAppLayerProtocolTest02", DetectAppLayerProtocolTest02, 1); - UtRegisterTest("DetectAppLayerProtocolTest03", DetectAppLayerProtocolTest03, 1); - UtRegisterTest("DetectAppLayerProtocolTest04", DetectAppLayerProtocolTest04, 1); - UtRegisterTest("DetectAppLayerProtocolTest05", DetectAppLayerProtocolTest05, 1); - UtRegisterTest("DetectAppLayerProtocolTest06", DetectAppLayerProtocolTest06, 1); - UtRegisterTest("DetectAppLayerProtocolTest07", DetectAppLayerProtocolTest07, 1); - UtRegisterTest("DetectAppLayerProtocolTest08", DetectAppLayerProtocolTest08, 1); - UtRegisterTest("DetectAppLayerProtocolTest09", DetectAppLayerProtocolTest09, 1); + UtRegisterTest("DetectAppLayerProtocolTest01", + DetectAppLayerProtocolTest01); + UtRegisterTest("DetectAppLayerProtocolTest02", + DetectAppLayerProtocolTest02); + UtRegisterTest("DetectAppLayerProtocolTest03", + DetectAppLayerProtocolTest03); + UtRegisterTest("DetectAppLayerProtocolTest04", + DetectAppLayerProtocolTest04); + UtRegisterTest("DetectAppLayerProtocolTest05", + DetectAppLayerProtocolTest05); + UtRegisterTest("DetectAppLayerProtocolTest06", + DetectAppLayerProtocolTest06); + UtRegisterTest("DetectAppLayerProtocolTest07", + DetectAppLayerProtocolTest07); + UtRegisterTest("DetectAppLayerProtocolTest08", + DetectAppLayerProtocolTest08); + UtRegisterTest("DetectAppLayerProtocolTest09", + DetectAppLayerProtocolTest09); #endif /* UNITTESTS */ return; diff --git a/src/detect-asn1.c b/src/detect-asn1.c index 69d90829e27c..bb12180750fb 100644 --- a/src/detect-asn1.c +++ b/src/detect-asn1.c @@ -1333,34 +1333,34 @@ int DetectAsn1TestReal04(void) void DetectAsn1RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectAsn1TestParse01", DetectAsn1TestParse01, 1); - UtRegisterTest("DetectAsn1TestParse02", DetectAsn1TestParse02, 1); - UtRegisterTest("DetectAsn1TestParse03", DetectAsn1TestParse03, 1); - - UtRegisterTest("DetectAsn1TestParse04", DetectAsn1TestParse04, 1); - UtRegisterTest("DetectAsn1TestParse05", DetectAsn1TestParse05, 1); - UtRegisterTest("DetectAsn1TestParse06", DetectAsn1TestParse06, 1); - - UtRegisterTest("DetectAsn1TestParse07", DetectAsn1TestParse07, 1); - UtRegisterTest("DetectAsn1TestParse08", DetectAsn1TestParse08, 1); - UtRegisterTest("DetectAsn1TestParse09", DetectAsn1TestParse09, 1); - - UtRegisterTest("DetectAsn1TestParse10", DetectAsn1TestParse10, 1); - UtRegisterTest("DetectAsn1TestParse11", DetectAsn1TestParse11, 1); - UtRegisterTest("DetectAsn1TestParse12", DetectAsn1TestParse12, 1); - UtRegisterTest("DetectAsn1TestParse13", DetectAsn1TestParse13, 1); - UtRegisterTest("DetectAsn1TestParse14", DetectAsn1TestParse14, 1); - UtRegisterTest("DetectAsn1TestParse15", DetectAsn1TestParse15, 1); - UtRegisterTest("DetectAsn1Test01 - oversize_len", DetectAsn1Test01, 1); - UtRegisterTest("DetectAsn1Test02 - oversize_len", DetectAsn1Test02, 1); - UtRegisterTest("DetectAsn1Test03 - bitstring_ovf", DetectAsn1Test03, 1); - UtRegisterTest("DetectAsn1Test04 - bitstring_ovf", DetectAsn1Test04, 1); - UtRegisterTest("DetectAsn1Test05 - double_ovf", DetectAsn1Test05, 1); - UtRegisterTest("DetectAsn1Test06 - double_ovf", DetectAsn1Test06, 1); - UtRegisterTest("DetectAsn1TestReal01", DetectAsn1TestReal01, 1); - UtRegisterTest("DetectAsn1TestReal02", DetectAsn1TestReal02, 1); - UtRegisterTest("DetectAsn1TestReal03", DetectAsn1TestReal03, 1); - UtRegisterTest("DetectAsn1TestReal04", DetectAsn1TestReal04, 1); + UtRegisterTest("DetectAsn1TestParse01", DetectAsn1TestParse01); + UtRegisterTest("DetectAsn1TestParse02", DetectAsn1TestParse02); + UtRegisterTest("DetectAsn1TestParse03", DetectAsn1TestParse03); + + UtRegisterTest("DetectAsn1TestParse04", DetectAsn1TestParse04); + UtRegisterTest("DetectAsn1TestParse05", DetectAsn1TestParse05); + UtRegisterTest("DetectAsn1TestParse06", DetectAsn1TestParse06); + + UtRegisterTest("DetectAsn1TestParse07", DetectAsn1TestParse07); + UtRegisterTest("DetectAsn1TestParse08", DetectAsn1TestParse08); + UtRegisterTest("DetectAsn1TestParse09", DetectAsn1TestParse09); + + UtRegisterTest("DetectAsn1TestParse10", DetectAsn1TestParse10); + UtRegisterTest("DetectAsn1TestParse11", DetectAsn1TestParse11); + UtRegisterTest("DetectAsn1TestParse12", DetectAsn1TestParse12); + UtRegisterTest("DetectAsn1TestParse13", DetectAsn1TestParse13); + UtRegisterTest("DetectAsn1TestParse14", DetectAsn1TestParse14); + UtRegisterTest("DetectAsn1TestParse15", DetectAsn1TestParse15); + UtRegisterTest("DetectAsn1Test01 - oversize_len", DetectAsn1Test01); + UtRegisterTest("DetectAsn1Test02 - oversize_len", DetectAsn1Test02); + UtRegisterTest("DetectAsn1Test03 - bitstring_ovf", DetectAsn1Test03); + UtRegisterTest("DetectAsn1Test04 - bitstring_ovf", DetectAsn1Test04); + UtRegisterTest("DetectAsn1Test05 - double_ovf", DetectAsn1Test05); + UtRegisterTest("DetectAsn1Test06 - double_ovf", DetectAsn1Test06); + UtRegisterTest("DetectAsn1TestReal01", DetectAsn1TestReal01); + UtRegisterTest("DetectAsn1TestReal02", DetectAsn1TestReal02); + UtRegisterTest("DetectAsn1TestReal03", DetectAsn1TestReal03); + UtRegisterTest("DetectAsn1TestReal04", DetectAsn1TestReal04); #endif /* UNITTESTS */ } diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c index b5fcefc53ce5..eeea153d2946 100644 --- a/src/detect-base64-data.c +++ b/src/detect-base64-data.c @@ -262,13 +262,9 @@ static int DetectBase64DataSetupTest04(void) static void DetectBase64DataRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectBase64DataSetupTest01", DetectBase64DataSetupTest01, - 1); - UtRegisterTest("DetectBase64DataSetupTest02", DetectBase64DataSetupTest02, - 1); - UtRegisterTest("DetectBase64DataSetupTest03", DetectBase64DataSetupTest03, - 1); - UtRegisterTest("DetectBase64DataSetupTest04", DetectBase64DataSetupTest04, - 1); + UtRegisterTest("DetectBase64DataSetupTest01", DetectBase64DataSetupTest01); + UtRegisterTest("DetectBase64DataSetupTest02", DetectBase64DataSetupTest02); + UtRegisterTest("DetectBase64DataSetupTest03", DetectBase64DataSetupTest03); + UtRegisterTest("DetectBase64DataSetupTest04", DetectBase64DataSetupTest04); #endif /* UNITTESTS */ } diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index e06e6f870c28..a693de151372 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -763,19 +763,17 @@ static int DetectBase64DecodeTestDecodeRelative(void) static void DetectBase64DecodeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectBase64TestDecodeParse", DetectBase64TestDecodeParse, - 1); - UtRegisterTest("DetectBase64DecodeTestSetup", DetectBase64DecodeTestSetup, - 1); + UtRegisterTest("DetectBase64TestDecodeParse", DetectBase64TestDecodeParse); + UtRegisterTest("DetectBase64DecodeTestSetup", DetectBase64DecodeTestSetup); UtRegisterTest("DetectBase64DecodeHttpHeaderTestSetup", - DetectBase64DecodeHttpHeaderTestSetup, 1); - UtRegisterTest("DetectBase64DecodeTestDecode", DetectBase64DecodeTestDecode, - 1); + DetectBase64DecodeHttpHeaderTestSetup); + UtRegisterTest("DetectBase64DecodeTestDecode", + DetectBase64DecodeTestDecode); UtRegisterTest("DetectBase64DecodeTestDecodeWithOffset", - DetectBase64DecodeTestDecodeWithOffset, 1); + DetectBase64DecodeTestDecodeWithOffset); UtRegisterTest("DetectBase64DecodeTestDecodeLargeOffset", - DetectBase64DecodeTestDecodeLargeOffset, 1); + DetectBase64DecodeTestDecodeLargeOffset); UtRegisterTest("DetectBase64DecodeTestDecodeRelative", - DetectBase64DecodeTestDecodeRelative, 1); + DetectBase64DecodeTestDecodeRelative); #endif /* UNITTESTS */ } diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index a53a62472f56..8b71c7970d01 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -4857,80 +4857,80 @@ int DetectByteExtractTestParseNoBase(void) void DetectByteExtractRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectByteExtractTest01", DetectByteExtractTest01, 1); - UtRegisterTest("DetectByteExtractTest02", DetectByteExtractTest02, 1); - UtRegisterTest("DetectByteExtractTest03", DetectByteExtractTest03, 1); - UtRegisterTest("DetectByteExtractTest04", DetectByteExtractTest04, 1); - UtRegisterTest("DetectByteExtractTest05", DetectByteExtractTest05, 1); - UtRegisterTest("DetectByteExtractTest06", DetectByteExtractTest06, 1); - UtRegisterTest("DetectByteExtractTest07", DetectByteExtractTest07, 1); - UtRegisterTest("DetectByteExtractTest08", DetectByteExtractTest08, 1); - UtRegisterTest("DetectByteExtractTest09", DetectByteExtractTest09, 1); - UtRegisterTest("DetectByteExtractTest10", DetectByteExtractTest10, 1); - UtRegisterTest("DetectByteExtractTest11", DetectByteExtractTest11, 1); - UtRegisterTest("DetectByteExtractTest12", DetectByteExtractTest12, 1); - UtRegisterTest("DetectByteExtractTest13", DetectByteExtractTest13, 1); - UtRegisterTest("DetectByteExtractTest14", DetectByteExtractTest14, 1); - UtRegisterTest("DetectByteExtractTest15", DetectByteExtractTest15, 1); - UtRegisterTest("DetectByteExtractTest16", DetectByteExtractTest16, 1); - UtRegisterTest("DetectByteExtractTest17", DetectByteExtractTest17, 1); - UtRegisterTest("DetectByteExtractTest18", DetectByteExtractTest18, 1); - UtRegisterTest("DetectByteExtractTest19", DetectByteExtractTest19, 1); - UtRegisterTest("DetectByteExtractTest20", DetectByteExtractTest20, 1); - UtRegisterTest("DetectByteExtractTest21", DetectByteExtractTest21, 1); - UtRegisterTest("DetectByteExtractTest22", DetectByteExtractTest22, 1); - UtRegisterTest("DetectByteExtractTest23", DetectByteExtractTest23, 1); - UtRegisterTest("DetectByteExtractTest24", DetectByteExtractTest24, 1); - UtRegisterTest("DetectByteExtractTest25", DetectByteExtractTest25, 1); - UtRegisterTest("DetectByteExtractTest26", DetectByteExtractTest26, 1); - UtRegisterTest("DetectByteExtractTest27", DetectByteExtractTest27, 1); - UtRegisterTest("DetectByteExtractTest28", DetectByteExtractTest28, 1); - UtRegisterTest("DetectByteExtractTest29", DetectByteExtractTest29, 1); - UtRegisterTest("DetectByteExtractTest30", DetectByteExtractTest30, 1); - UtRegisterTest("DetectByteExtractTest31", DetectByteExtractTest31, 1); - UtRegisterTest("DetectByteExtractTest32", DetectByteExtractTest32, 1); - UtRegisterTest("DetectByteExtractTest33", DetectByteExtractTest33, 1); - UtRegisterTest("DetectByteExtractTest34", DetectByteExtractTest34, 1); - UtRegisterTest("DetectByteExtractTest35", DetectByteExtractTest35, 1); - UtRegisterTest("DetectByteExtractTest36", DetectByteExtractTest36, 1); - UtRegisterTest("DetectByteExtractTest37", DetectByteExtractTest37, 1); - UtRegisterTest("DetectByteExtractTest38", DetectByteExtractTest38, 1); - UtRegisterTest("DetectByteExtractTest39", DetectByteExtractTest39, 1); - UtRegisterTest("DetectByteExtractTest40", DetectByteExtractTest40, 1); - UtRegisterTest("DetectByteExtractTest41", DetectByteExtractTest41, 1); - UtRegisterTest("DetectByteExtractTest42", DetectByteExtractTest42, 1); - - UtRegisterTest("DetectByteExtractTest43", DetectByteExtractTest43, 1); - UtRegisterTest("DetectByteExtractTest44", DetectByteExtractTest44, 1); - - UtRegisterTest("DetectByteExtractTest45", DetectByteExtractTest45, 1); - UtRegisterTest("DetectByteExtractTest46", DetectByteExtractTest46, 1); - - UtRegisterTest("DetectByteExtractTest47", DetectByteExtractTest47, 1); - UtRegisterTest("DetectByteExtractTest48", DetectByteExtractTest48, 1); - - UtRegisterTest("DetectByteExtractTest49", DetectByteExtractTest49, 1); - UtRegisterTest("DetectByteExtractTest50", DetectByteExtractTest50, 1); - - UtRegisterTest("DetectByteExtractTest51", DetectByteExtractTest51, 1); - UtRegisterTest("DetectByteExtractTest52", DetectByteExtractTest52, 1); - - UtRegisterTest("DetectByteExtractTest53", DetectByteExtractTest53, 1); - UtRegisterTest("DetectByteExtractTest54", DetectByteExtractTest54, 1); - - UtRegisterTest("DetectByteExtractTest55", DetectByteExtractTest55, 1); - UtRegisterTest("DetectByteExtractTest56", DetectByteExtractTest56, 1); - UtRegisterTest("DetectByteExtractTest57", DetectByteExtractTest57, 1); - - UtRegisterTest("DetectByteExtractTest58", DetectByteExtractTest58, 1); - UtRegisterTest("DetectByteExtractTest59", DetectByteExtractTest59, 1); - UtRegisterTest("DetectByteExtractTest60", DetectByteExtractTest60, 1); - UtRegisterTest("DetectByteExtractTest61", DetectByteExtractTest61, 1); - UtRegisterTest("DetectByteExtractTest62", DetectByteExtractTest62, 1); - UtRegisterTest("DetectByteExtractTest63", DetectByteExtractTest63, 1); + UtRegisterTest("DetectByteExtractTest01", DetectByteExtractTest01); + UtRegisterTest("DetectByteExtractTest02", DetectByteExtractTest02); + UtRegisterTest("DetectByteExtractTest03", DetectByteExtractTest03); + UtRegisterTest("DetectByteExtractTest04", DetectByteExtractTest04); + UtRegisterTest("DetectByteExtractTest05", DetectByteExtractTest05); + UtRegisterTest("DetectByteExtractTest06", DetectByteExtractTest06); + UtRegisterTest("DetectByteExtractTest07", DetectByteExtractTest07); + UtRegisterTest("DetectByteExtractTest08", DetectByteExtractTest08); + UtRegisterTest("DetectByteExtractTest09", DetectByteExtractTest09); + UtRegisterTest("DetectByteExtractTest10", DetectByteExtractTest10); + UtRegisterTest("DetectByteExtractTest11", DetectByteExtractTest11); + UtRegisterTest("DetectByteExtractTest12", DetectByteExtractTest12); + UtRegisterTest("DetectByteExtractTest13", DetectByteExtractTest13); + UtRegisterTest("DetectByteExtractTest14", DetectByteExtractTest14); + UtRegisterTest("DetectByteExtractTest15", DetectByteExtractTest15); + UtRegisterTest("DetectByteExtractTest16", DetectByteExtractTest16); + UtRegisterTest("DetectByteExtractTest17", DetectByteExtractTest17); + UtRegisterTest("DetectByteExtractTest18", DetectByteExtractTest18); + UtRegisterTest("DetectByteExtractTest19", DetectByteExtractTest19); + UtRegisterTest("DetectByteExtractTest20", DetectByteExtractTest20); + UtRegisterTest("DetectByteExtractTest21", DetectByteExtractTest21); + UtRegisterTest("DetectByteExtractTest22", DetectByteExtractTest22); + UtRegisterTest("DetectByteExtractTest23", DetectByteExtractTest23); + UtRegisterTest("DetectByteExtractTest24", DetectByteExtractTest24); + UtRegisterTest("DetectByteExtractTest25", DetectByteExtractTest25); + UtRegisterTest("DetectByteExtractTest26", DetectByteExtractTest26); + UtRegisterTest("DetectByteExtractTest27", DetectByteExtractTest27); + UtRegisterTest("DetectByteExtractTest28", DetectByteExtractTest28); + UtRegisterTest("DetectByteExtractTest29", DetectByteExtractTest29); + UtRegisterTest("DetectByteExtractTest30", DetectByteExtractTest30); + UtRegisterTest("DetectByteExtractTest31", DetectByteExtractTest31); + UtRegisterTest("DetectByteExtractTest32", DetectByteExtractTest32); + UtRegisterTest("DetectByteExtractTest33", DetectByteExtractTest33); + UtRegisterTest("DetectByteExtractTest34", DetectByteExtractTest34); + UtRegisterTest("DetectByteExtractTest35", DetectByteExtractTest35); + UtRegisterTest("DetectByteExtractTest36", DetectByteExtractTest36); + UtRegisterTest("DetectByteExtractTest37", DetectByteExtractTest37); + UtRegisterTest("DetectByteExtractTest38", DetectByteExtractTest38); + UtRegisterTest("DetectByteExtractTest39", DetectByteExtractTest39); + UtRegisterTest("DetectByteExtractTest40", DetectByteExtractTest40); + UtRegisterTest("DetectByteExtractTest41", DetectByteExtractTest41); + UtRegisterTest("DetectByteExtractTest42", DetectByteExtractTest42); + + UtRegisterTest("DetectByteExtractTest43", DetectByteExtractTest43); + UtRegisterTest("DetectByteExtractTest44", DetectByteExtractTest44); + + UtRegisterTest("DetectByteExtractTest45", DetectByteExtractTest45); + UtRegisterTest("DetectByteExtractTest46", DetectByteExtractTest46); + + UtRegisterTest("DetectByteExtractTest47", DetectByteExtractTest47); + UtRegisterTest("DetectByteExtractTest48", DetectByteExtractTest48); + + UtRegisterTest("DetectByteExtractTest49", DetectByteExtractTest49); + UtRegisterTest("DetectByteExtractTest50", DetectByteExtractTest50); + + UtRegisterTest("DetectByteExtractTest51", DetectByteExtractTest51); + UtRegisterTest("DetectByteExtractTest52", DetectByteExtractTest52); + + UtRegisterTest("DetectByteExtractTest53", DetectByteExtractTest53); + UtRegisterTest("DetectByteExtractTest54", DetectByteExtractTest54); + + UtRegisterTest("DetectByteExtractTest55", DetectByteExtractTest55); + UtRegisterTest("DetectByteExtractTest56", DetectByteExtractTest56); + UtRegisterTest("DetectByteExtractTest57", DetectByteExtractTest57); + + UtRegisterTest("DetectByteExtractTest58", DetectByteExtractTest58); + UtRegisterTest("DetectByteExtractTest59", DetectByteExtractTest59); + UtRegisterTest("DetectByteExtractTest60", DetectByteExtractTest60); + UtRegisterTest("DetectByteExtractTest61", DetectByteExtractTest61); + UtRegisterTest("DetectByteExtractTest62", DetectByteExtractTest62); + UtRegisterTest("DetectByteExtractTest63", DetectByteExtractTest63); UtRegisterTest("DetectByteExtractTestParseNoBase", - DetectByteExtractTestParseNoBase, 1); + DetectByteExtractTestParseNoBase); #endif /* UNITTESTS */ return; diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 46a2a3e49a41..7111bd67f3ac 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -1404,26 +1404,26 @@ int DetectByteJumpTestPacket07 (void) void DetectBytejumpRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01, 1); - UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02, 1); - UtRegisterTest("DetectBytejumpTestParse03", DetectBytejumpTestParse03, 1); - UtRegisterTest("DetectBytejumpTestParse04", DetectBytejumpTestParse04, 1); - UtRegisterTest("DetectBytejumpTestParse05", DetectBytejumpTestParse05, 1); - UtRegisterTest("DetectBytejumpTestParse06", DetectBytejumpTestParse06, 1); - UtRegisterTest("DetectBytejumpTestParse07", DetectBytejumpTestParse07, 1); - UtRegisterTest("DetectBytejumpTestParse08", DetectBytejumpTestParse08, 1); - UtRegisterTest("DetectBytejumpTestParse09", DetectBytejumpTestParse09, 1); - UtRegisterTest("DetectBytejumpTestParse10", DetectBytejumpTestParse10, 1); - UtRegisterTest("DetectBytejumpTestParse11", DetectBytejumpTestParse11, 1); - UtRegisterTest("DetectBytejumpTestParse12", DetectBytejumpTestParse12, 1); - - UtRegisterTest("DetectByteJumpTestPacket01", DetectByteJumpTestPacket01, 1); - UtRegisterTest("DetectByteJumpTestPacket02", DetectByteJumpTestPacket02, 1); - UtRegisterTest("DetectByteJumpTestPacket03", DetectByteJumpTestPacket03, 1); - UtRegisterTest("DetectByteJumpTestPacket04", DetectByteJumpTestPacket04, 1); - UtRegisterTest("DetectByteJumpTestPacket05", DetectByteJumpTestPacket05, 1); - UtRegisterTest("DetectByteJumpTestPacket06", DetectByteJumpTestPacket06, 1); - UtRegisterTest("DetectByteJumpTestPacket07", DetectByteJumpTestPacket07, 1); + UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01); + UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02); + UtRegisterTest("DetectBytejumpTestParse03", DetectBytejumpTestParse03); + UtRegisterTest("DetectBytejumpTestParse04", DetectBytejumpTestParse04); + UtRegisterTest("DetectBytejumpTestParse05", DetectBytejumpTestParse05); + UtRegisterTest("DetectBytejumpTestParse06", DetectBytejumpTestParse06); + UtRegisterTest("DetectBytejumpTestParse07", DetectBytejumpTestParse07); + UtRegisterTest("DetectBytejumpTestParse08", DetectBytejumpTestParse08); + UtRegisterTest("DetectBytejumpTestParse09", DetectBytejumpTestParse09); + UtRegisterTest("DetectBytejumpTestParse10", DetectBytejumpTestParse10); + UtRegisterTest("DetectBytejumpTestParse11", DetectBytejumpTestParse11); + UtRegisterTest("DetectBytejumpTestParse12", DetectBytejumpTestParse12); + + UtRegisterTest("DetectByteJumpTestPacket01", DetectByteJumpTestPacket01); + UtRegisterTest("DetectByteJumpTestPacket02", DetectByteJumpTestPacket02); + UtRegisterTest("DetectByteJumpTestPacket03", DetectByteJumpTestPacket03); + UtRegisterTest("DetectByteJumpTestPacket04", DetectByteJumpTestPacket04); + UtRegisterTest("DetectByteJumpTestPacket05", DetectByteJumpTestPacket05); + UtRegisterTest("DetectByteJumpTestPacket06", DetectByteJumpTestPacket06); + UtRegisterTest("DetectByteJumpTestPacket07", DetectByteJumpTestPacket07); #endif /* UNITTESTS */ } diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 365ad55c8a69..1802303ed8d5 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -1548,33 +1548,33 @@ int DetectByteTestTestPacket05(void) void DetectBytetestRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectBytetestTestParse01", DetectBytetestTestParse01, 1); - UtRegisterTest("DetectBytetestTestParse02", DetectBytetestTestParse02, 1); - UtRegisterTest("DetectBytetestTestParse03", DetectBytetestTestParse03, 1); - UtRegisterTest("DetectBytetestTestParse04", DetectBytetestTestParse04, 1); - UtRegisterTest("DetectBytetestTestParse05", DetectBytetestTestParse05, 1); - UtRegisterTest("DetectBytetestTestParse06", DetectBytetestTestParse06, 1); - UtRegisterTest("DetectBytetestTestParse07", DetectBytetestTestParse07, 1); - UtRegisterTest("DetectBytetestTestParse08", DetectBytetestTestParse08, 1); - UtRegisterTest("DetectBytetestTestParse09", DetectBytetestTestParse09, 1); - UtRegisterTest("DetectBytetestTestParse10", DetectBytetestTestParse10, 1); - UtRegisterTest("DetectBytetestTestParse11", DetectBytetestTestParse11, 1); - UtRegisterTest("DetectBytetestTestParse12", DetectBytetestTestParse12, 1); - UtRegisterTest("DetectBytetestTestParse13", DetectBytetestTestParse13, 1); - UtRegisterTest("DetectBytetestTestParse14", DetectBytetestTestParse14, 1); - UtRegisterTest("DetectBytetestTestParse15", DetectBytetestTestParse15, 1); - UtRegisterTest("DetectBytetestTestParse17", DetectBytetestTestParse17, 1); - UtRegisterTest("DetectBytetestTestParse18", DetectBytetestTestParse18, 1); - UtRegisterTest("DetectBytetestTestParse19", DetectBytetestTestParse19, 1); - UtRegisterTest("DetectBytetestTestParse20", DetectBytetestTestParse20, 1); - UtRegisterTest("DetectBytetestTestParse21", DetectBytetestTestParse21, 1); - UtRegisterTest("DetectBytetestTestParse22", DetectBytetestTestParse22, 1); - - UtRegisterTest("DetectByteTestTestPacket01", DetectByteTestTestPacket01, 1); - UtRegisterTest("DetectByteTestTestPacket02", DetectByteTestTestPacket02, 1); - UtRegisterTest("DetectByteTestTestPacket03", DetectByteTestTestPacket03, 1); - UtRegisterTest("DetectByteTestTestPacket04", DetectByteTestTestPacket04, 1); - UtRegisterTest("DetectByteTestTestPacket05", DetectByteTestTestPacket05, 1); + UtRegisterTest("DetectBytetestTestParse01", DetectBytetestTestParse01); + UtRegisterTest("DetectBytetestTestParse02", DetectBytetestTestParse02); + UtRegisterTest("DetectBytetestTestParse03", DetectBytetestTestParse03); + UtRegisterTest("DetectBytetestTestParse04", DetectBytetestTestParse04); + UtRegisterTest("DetectBytetestTestParse05", DetectBytetestTestParse05); + UtRegisterTest("DetectBytetestTestParse06", DetectBytetestTestParse06); + UtRegisterTest("DetectBytetestTestParse07", DetectBytetestTestParse07); + UtRegisterTest("DetectBytetestTestParse08", DetectBytetestTestParse08); + UtRegisterTest("DetectBytetestTestParse09", DetectBytetestTestParse09); + UtRegisterTest("DetectBytetestTestParse10", DetectBytetestTestParse10); + UtRegisterTest("DetectBytetestTestParse11", DetectBytetestTestParse11); + UtRegisterTest("DetectBytetestTestParse12", DetectBytetestTestParse12); + UtRegisterTest("DetectBytetestTestParse13", DetectBytetestTestParse13); + UtRegisterTest("DetectBytetestTestParse14", DetectBytetestTestParse14); + UtRegisterTest("DetectBytetestTestParse15", DetectBytetestTestParse15); + UtRegisterTest("DetectBytetestTestParse17", DetectBytetestTestParse17); + UtRegisterTest("DetectBytetestTestParse18", DetectBytetestTestParse18); + UtRegisterTest("DetectBytetestTestParse19", DetectBytetestTestParse19); + UtRegisterTest("DetectBytetestTestParse20", DetectBytetestTestParse20); + UtRegisterTest("DetectBytetestTestParse21", DetectBytetestTestParse21); + UtRegisterTest("DetectBytetestTestParse22", DetectBytetestTestParse22); + + UtRegisterTest("DetectByteTestTestPacket01", DetectByteTestTestPacket01); + UtRegisterTest("DetectByteTestTestPacket02", DetectByteTestTestPacket02); + UtRegisterTest("DetectByteTestTestPacket03", DetectByteTestTestPacket03); + UtRegisterTest("DetectByteTestTestPacket04", DetectByteTestTestPacket04); + UtRegisterTest("DetectByteTestTestPacket05", DetectByteTestTestPacket05); #endif /* UNITTESTS */ } diff --git a/src/detect-classtype.c b/src/detect-classtype.c index bc77371006ca..f81d8378dba3 100644 --- a/src/detect-classtype.c +++ b/src/detect-classtype.c @@ -333,9 +333,9 @@ void DetectClasstypeRegisterTests(void) #ifdef UNITTESTS - UtRegisterTest("DetectClasstypeTest01", DetectClasstypeTest01, 1); - UtRegisterTest("DetectClasstypeTest02", DetectClasstypeTest02, 1); - UtRegisterTest("DetectClasstypeTest03", DetectClasstypeTest03, 1); + UtRegisterTest("DetectClasstypeTest01", DetectClasstypeTest01); + UtRegisterTest("DetectClasstypeTest02", DetectClasstypeTest02); + UtRegisterTest("DetectClasstypeTest03", DetectClasstypeTest03); #endif /* UNITTESTS */ diff --git a/src/detect-content.c b/src/detect-content.c index 83091886674b..372a5da1eae4 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -2725,107 +2725,119 @@ static int DetectLongContentTest3(void) void DetectContentRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01, 1); - UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02, 1); - UtRegisterTest("DetectContentParseTest03", DetectContentParseTest03, 1); - UtRegisterTest("DetectContentParseTest04", DetectContentParseTest04, 1); - UtRegisterTest("DetectContentParseTest05", DetectContentParseTest05, 1); - UtRegisterTest("DetectContentParseTest06", DetectContentParseTest06, 1); - UtRegisterTest("DetectContentParseTest07", DetectContentParseTest07, 1); - UtRegisterTest("DetectContentParseTest08", DetectContentParseTest08, 1); - UtRegisterTest("DetectContentParseTest09", DetectContentParseTest09, 1); - UtRegisterTest("DetectContentParseTest10", DetectContentParseTest10, 1); - UtRegisterTest("DetectContentParseNegTest11", DetectContentParseNegTest11, 1); - UtRegisterTest("DetectContentParseNegTest12", DetectContentParseNegTest12, 1); - UtRegisterTest("DetectContentParseNegTest13", DetectContentParseNegTest13, 1); - UtRegisterTest("DetectContentParseNegTest14", DetectContentParseNegTest14, 1); - UtRegisterTest("DetectContentParseNegTest15", DetectContentParseNegTest15, 1); - UtRegisterTest("DetectContentParseNegTest16", DetectContentParseNegTest16, 1); - UtRegisterTest("DetectContentParseTest17", DetectContentParseTest17, 1); - UtRegisterTest("DetectContentParseTest18", DetectContentParseTest18, 1); - UtRegisterTest("DetectContentParseTest19", DetectContentParseTest19, 1); - UtRegisterTest("DetectContentParseTest20", DetectContentParseTest20, 1); - UtRegisterTest("DetectContentParseTest21", DetectContentParseTest21, 1); - UtRegisterTest("DetectContentParseTest22", DetectContentParseTest22, 1); - UtRegisterTest("DetectContentParseTest23", DetectContentParseTest23, 1); - UtRegisterTest("DetectContentParseTest24", DetectContentParseTest24, 1); - UtRegisterTest("DetectContentParseTest25", DetectContentParseTest25, 1); - UtRegisterTest("DetectContentParseTest26", DetectContentParseTest26, 1); - UtRegisterTest("DetectContentParseTest27", DetectContentParseTest27, 1); - UtRegisterTest("DetectContentParseTest28", DetectContentParseTest28, 1); - UtRegisterTest("DetectContentParseTest29", DetectContentParseTest29, 1); - UtRegisterTest("DetectContentParseTest30", DetectContentParseTest30, 1); - UtRegisterTest("DetectContentParseTest31", DetectContentParseTest31, 1); - UtRegisterTest("DetectContentParseTest32", DetectContentParseTest32, 1); - UtRegisterTest("DetectContentParseTest33", DetectContentParseTest33, 1); - UtRegisterTest("DetectContentParseTest34", DetectContentParseTest34, 1); - UtRegisterTest("DetectContentParseTest35", DetectContentParseTest35, 1); - UtRegisterTest("DetectContentParseTest36", DetectContentParseTest36, 1); - UtRegisterTest("DetectContentParseTest37", DetectContentParseTest37, 1); - UtRegisterTest("DetectContentParseTest38", DetectContentParseTest38, 1); - UtRegisterTest("DetectContentParseTest39", DetectContentParseTest39, 1); - UtRegisterTest("DetectContentParseTest40", DetectContentParseTest40, 1); - UtRegisterTest("DetectContentParseTest41", DetectContentParseTest41, 1); - UtRegisterTest("DetectContentParseTest42", DetectContentParseTest42, 1); - UtRegisterTest("DetectContentParseTest43", DetectContentParseTest43, 1); - UtRegisterTest("DetectContentParseTest44", DetectContentParseTest44, 1); + UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01); + UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02); + UtRegisterTest("DetectContentParseTest03", DetectContentParseTest03); + UtRegisterTest("DetectContentParseTest04", DetectContentParseTest04); + UtRegisterTest("DetectContentParseTest05", DetectContentParseTest05); + UtRegisterTest("DetectContentParseTest06", DetectContentParseTest06); + UtRegisterTest("DetectContentParseTest07", DetectContentParseTest07); + UtRegisterTest("DetectContentParseTest08", DetectContentParseTest08); + UtRegisterTest("DetectContentParseTest09", DetectContentParseTest09); + UtRegisterTest("DetectContentParseTest10", DetectContentParseTest10); + UtRegisterTest("DetectContentParseNegTest11", DetectContentParseNegTest11); + UtRegisterTest("DetectContentParseNegTest12", DetectContentParseNegTest12); + UtRegisterTest("DetectContentParseNegTest13", DetectContentParseNegTest13); + UtRegisterTest("DetectContentParseNegTest14", DetectContentParseNegTest14); + UtRegisterTest("DetectContentParseNegTest15", DetectContentParseNegTest15); + UtRegisterTest("DetectContentParseNegTest16", DetectContentParseNegTest16); + UtRegisterTest("DetectContentParseTest17", DetectContentParseTest17); + UtRegisterTest("DetectContentParseTest18", DetectContentParseTest18); + UtRegisterTest("DetectContentParseTest19", DetectContentParseTest19); + UtRegisterTest("DetectContentParseTest20", DetectContentParseTest20); + UtRegisterTest("DetectContentParseTest21", DetectContentParseTest21); + UtRegisterTest("DetectContentParseTest22", DetectContentParseTest22); + UtRegisterTest("DetectContentParseTest23", DetectContentParseTest23); + UtRegisterTest("DetectContentParseTest24", DetectContentParseTest24); + UtRegisterTest("DetectContentParseTest25", DetectContentParseTest25); + UtRegisterTest("DetectContentParseTest26", DetectContentParseTest26); + UtRegisterTest("DetectContentParseTest27", DetectContentParseTest27); + UtRegisterTest("DetectContentParseTest28", DetectContentParseTest28); + UtRegisterTest("DetectContentParseTest29", DetectContentParseTest29); + UtRegisterTest("DetectContentParseTest30", DetectContentParseTest30); + UtRegisterTest("DetectContentParseTest31", DetectContentParseTest31); + UtRegisterTest("DetectContentParseTest32", DetectContentParseTest32); + UtRegisterTest("DetectContentParseTest33", DetectContentParseTest33); + UtRegisterTest("DetectContentParseTest34", DetectContentParseTest34); + UtRegisterTest("DetectContentParseTest35", DetectContentParseTest35); + UtRegisterTest("DetectContentParseTest36", DetectContentParseTest36); + UtRegisterTest("DetectContentParseTest37", DetectContentParseTest37); + UtRegisterTest("DetectContentParseTest38", DetectContentParseTest38); + UtRegisterTest("DetectContentParseTest39", DetectContentParseTest39); + UtRegisterTest("DetectContentParseTest40", DetectContentParseTest40); + UtRegisterTest("DetectContentParseTest41", DetectContentParseTest41); + UtRegisterTest("DetectContentParseTest42", DetectContentParseTest42); + UtRegisterTest("DetectContentParseTest43", DetectContentParseTest43); + UtRegisterTest("DetectContentParseTest44", DetectContentParseTest44); /* The reals */ - UtRegisterTest("DetectContentLongPatternMatchTest01", DetectContentLongPatternMatchTest01, 1); - UtRegisterTest("DetectContentLongPatternMatchTest02", DetectContentLongPatternMatchTest02, 1); - UtRegisterTest("DetectContentLongPatternMatchTest03", DetectContentLongPatternMatchTest03, 1); - UtRegisterTest("DetectContentLongPatternMatchTest04", DetectContentLongPatternMatchTest04, 1); - UtRegisterTest("DetectContentLongPatternMatchTest05", DetectContentLongPatternMatchTest05, 1); - UtRegisterTest("DetectContentLongPatternMatchTest06", DetectContentLongPatternMatchTest06, 1); - UtRegisterTest("DetectContentLongPatternMatchTest07", DetectContentLongPatternMatchTest07, 1); - UtRegisterTest("DetectContentLongPatternMatchTest08", DetectContentLongPatternMatchTest08, 1); - UtRegisterTest("DetectContentLongPatternMatchTest09", DetectContentLongPatternMatchTest09, 1); - UtRegisterTest("DetectContentLongPatternMatchTest10", DetectContentLongPatternMatchTest10, 1); - UtRegisterTest("DetectContentLongPatternMatchTest11", DetectContentLongPatternMatchTest11, 1); + UtRegisterTest("DetectContentLongPatternMatchTest01", + DetectContentLongPatternMatchTest01); + UtRegisterTest("DetectContentLongPatternMatchTest02", + DetectContentLongPatternMatchTest02); + UtRegisterTest("DetectContentLongPatternMatchTest03", + DetectContentLongPatternMatchTest03); + UtRegisterTest("DetectContentLongPatternMatchTest04", + DetectContentLongPatternMatchTest04); + UtRegisterTest("DetectContentLongPatternMatchTest05", + DetectContentLongPatternMatchTest05); + UtRegisterTest("DetectContentLongPatternMatchTest06", + DetectContentLongPatternMatchTest06); + UtRegisterTest("DetectContentLongPatternMatchTest07", + DetectContentLongPatternMatchTest07); + UtRegisterTest("DetectContentLongPatternMatchTest08", + DetectContentLongPatternMatchTest08); + UtRegisterTest("DetectContentLongPatternMatchTest09", + DetectContentLongPatternMatchTest09); + UtRegisterTest("DetectContentLongPatternMatchTest10", + DetectContentLongPatternMatchTest10); + UtRegisterTest("DetectContentLongPatternMatchTest11", + DetectContentLongPatternMatchTest11); /* Negated content tests */ - UtRegisterTest("SigTest41TestNegatedContent", SigTest41TestNegatedContent, 1); - UtRegisterTest("SigTest41aTestNegatedContent", SigTest41aTestNegatedContent, 1); - UtRegisterTest("SigTest42TestNegatedContent", SigTest42TestNegatedContent, 1); - UtRegisterTest("SigTest43TestNegatedContent", SigTest43TestNegatedContent, 1); - UtRegisterTest("SigTest44TestNegatedContent", SigTest44TestNegatedContent, 1); - UtRegisterTest("SigTest45TestNegatedContent", SigTest45TestNegatedContent, 1); - UtRegisterTest("SigTest46TestNegatedContent", SigTest46TestNegatedContent, 1); - UtRegisterTest("SigTest47TestNegatedContent", SigTest47TestNegatedContent, 1); - UtRegisterTest("SigTest48TestNegatedContent", SigTest48TestNegatedContent, 1); - UtRegisterTest("SigTest49TestNegatedContent", SigTest49TestNegatedContent, 1); - UtRegisterTest("SigTest50TestNegatedContent", SigTest50TestNegatedContent, 1); - UtRegisterTest("SigTest51TestNegatedContent", SigTest51TestNegatedContent, 1); - UtRegisterTest("SigTest52TestNegatedContent", SigTest52TestNegatedContent, 1); - UtRegisterTest("SigTest53TestNegatedContent", SigTest53TestNegatedContent, 1); - UtRegisterTest("SigTest54TestNegatedContent", SigTest54TestNegatedContent, 1); - UtRegisterTest("SigTest55TestNegatedContent", SigTest55TestNegatedContent, 1); - UtRegisterTest("SigTest56TestNegatedContent", SigTest56TestNegatedContent, 1); - UtRegisterTest("SigTest57TestNegatedContent", SigTest57TestNegatedContent, 1); - UtRegisterTest("SigTest58TestNegatedContent", SigTest58TestNegatedContent, 1); - UtRegisterTest("SigTest59TestNegatedContent", SigTest59TestNegatedContent, 1); - UtRegisterTest("SigTest60TestNegatedContent", SigTest60TestNegatedContent, 1); - UtRegisterTest("SigTest61TestNegatedContent", SigTest61TestNegatedContent, 1); - UtRegisterTest("SigTest62TestNegatedContent", SigTest62TestNegatedContent, 1); - UtRegisterTest("SigTest63TestNegatedContent", SigTest63TestNegatedContent, 1); - UtRegisterTest("SigTest64TestNegatedContent", SigTest64TestNegatedContent, 1); - UtRegisterTest("SigTest65TestNegatedContent", SigTest65TestNegatedContent, 1); - UtRegisterTest("SigTest66TestNegatedContent", SigTest66TestNegatedContent, 1); - UtRegisterTest("SigTest67TestNegatedContent", SigTest67TestNegatedContent, 1); - UtRegisterTest("SigTest68TestNegatedContent", SigTest68TestNegatedContent, 1); - UtRegisterTest("SigTest69TestNegatedContent", SigTest69TestNegatedContent, 1); - UtRegisterTest("SigTest70TestNegatedContent", SigTest70TestNegatedContent, 1); - UtRegisterTest("SigTest71TestNegatedContent", SigTest71TestNegatedContent, 1); - UtRegisterTest("SigTest72TestNegatedContent", SigTest72TestNegatedContent, 1); - UtRegisterTest("SigTest73TestNegatedContent", SigTest73TestNegatedContent, 1); - UtRegisterTest("SigTest74TestNegatedContent", SigTest74TestNegatedContent, 1); - UtRegisterTest("SigTest75TestNegatedContent", SigTest75TestNegatedContent, 1); - - UtRegisterTest("SigTest76TestBug134", SigTest76TestBug134, 1); - UtRegisterTest("SigTest77TestBug139", SigTest77TestBug139, 1); - - UtRegisterTest("DetectLongContentTest1", DetectLongContentTest1, 1); - UtRegisterTest("DetectLongContentTest2", DetectLongContentTest2, 1); - UtRegisterTest("DetectLongContentTest3", DetectLongContentTest3, 1); + UtRegisterTest("SigTest41TestNegatedContent", SigTest41TestNegatedContent); + UtRegisterTest("SigTest41aTestNegatedContent", + SigTest41aTestNegatedContent); + UtRegisterTest("SigTest42TestNegatedContent", SigTest42TestNegatedContent); + UtRegisterTest("SigTest43TestNegatedContent", SigTest43TestNegatedContent); + UtRegisterTest("SigTest44TestNegatedContent", SigTest44TestNegatedContent); + UtRegisterTest("SigTest45TestNegatedContent", SigTest45TestNegatedContent); + UtRegisterTest("SigTest46TestNegatedContent", SigTest46TestNegatedContent); + UtRegisterTest("SigTest47TestNegatedContent", SigTest47TestNegatedContent); + UtRegisterTest("SigTest48TestNegatedContent", SigTest48TestNegatedContent); + UtRegisterTest("SigTest49TestNegatedContent", SigTest49TestNegatedContent); + UtRegisterTest("SigTest50TestNegatedContent", SigTest50TestNegatedContent); + UtRegisterTest("SigTest51TestNegatedContent", SigTest51TestNegatedContent); + UtRegisterTest("SigTest52TestNegatedContent", SigTest52TestNegatedContent); + UtRegisterTest("SigTest53TestNegatedContent", SigTest53TestNegatedContent); + UtRegisterTest("SigTest54TestNegatedContent", SigTest54TestNegatedContent); + UtRegisterTest("SigTest55TestNegatedContent", SigTest55TestNegatedContent); + UtRegisterTest("SigTest56TestNegatedContent", SigTest56TestNegatedContent); + UtRegisterTest("SigTest57TestNegatedContent", SigTest57TestNegatedContent); + UtRegisterTest("SigTest58TestNegatedContent", SigTest58TestNegatedContent); + UtRegisterTest("SigTest59TestNegatedContent", SigTest59TestNegatedContent); + UtRegisterTest("SigTest60TestNegatedContent", SigTest60TestNegatedContent); + UtRegisterTest("SigTest61TestNegatedContent", SigTest61TestNegatedContent); + UtRegisterTest("SigTest62TestNegatedContent", SigTest62TestNegatedContent); + UtRegisterTest("SigTest63TestNegatedContent", SigTest63TestNegatedContent); + UtRegisterTest("SigTest64TestNegatedContent", SigTest64TestNegatedContent); + UtRegisterTest("SigTest65TestNegatedContent", SigTest65TestNegatedContent); + UtRegisterTest("SigTest66TestNegatedContent", SigTest66TestNegatedContent); + UtRegisterTest("SigTest67TestNegatedContent", SigTest67TestNegatedContent); + UtRegisterTest("SigTest68TestNegatedContent", SigTest68TestNegatedContent); + UtRegisterTest("SigTest69TestNegatedContent", SigTest69TestNegatedContent); + UtRegisterTest("SigTest70TestNegatedContent", SigTest70TestNegatedContent); + UtRegisterTest("SigTest71TestNegatedContent", SigTest71TestNegatedContent); + UtRegisterTest("SigTest72TestNegatedContent", SigTest72TestNegatedContent); + UtRegisterTest("SigTest73TestNegatedContent", SigTest73TestNegatedContent); + UtRegisterTest("SigTest74TestNegatedContent", SigTest74TestNegatedContent); + UtRegisterTest("SigTest75TestNegatedContent", SigTest75TestNegatedContent); + + UtRegisterTest("SigTest76TestBug134", SigTest76TestBug134); + UtRegisterTest("SigTest77TestBug139", SigTest77TestBug139); + + UtRegisterTest("DetectLongContentTest1", DetectLongContentTest1); + UtRegisterTest("DetectLongContentTest2", DetectLongContentTest2); + UtRegisterTest("DetectLongContentTest3", DetectLongContentTest3); #endif /* UNITTESTS */ } diff --git a/src/detect-csum.c b/src/detect-csum.c index 2cf5b4ce79f2..37d2b22163cc 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -1590,56 +1590,55 @@ void DetectCsumRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectCsumIPV4ValidArgsTestParse01", - DetectCsumIPV4ValidArgsTestParse01, 1); + DetectCsumIPV4ValidArgsTestParse01); UtRegisterTest("DetectCsumIPV4InValidArgsTestParse02", - DetectCsumIPV4InValidArgsTestParse02, 1); + DetectCsumIPV4InValidArgsTestParse02); UtRegisterTest("DetectCsumIPV4ValidArgsTestParse03", - DetectCsumIPV4ValidArgsTestParse03, 1); + DetectCsumIPV4ValidArgsTestParse03); UtRegisterTest("DetectCsumICMPV4ValidArgsTestParse01", - DetectCsumICMPV4ValidArgsTestParse01, 1); + DetectCsumICMPV4ValidArgsTestParse01); UtRegisterTest("DetectCsumICMPV4InValidArgsTestParse02", - DetectCsumICMPV4InValidArgsTestParse02, 1); + DetectCsumICMPV4InValidArgsTestParse02); UtRegisterTest("DetectCsumICMPV4ValidArgsTestParse03", - DetectCsumICMPV4ValidArgsTestParse03, 1); + DetectCsumICMPV4ValidArgsTestParse03); UtRegisterTest("DetectCsumTCPV4ValidArgsTestParse01", - DetectCsumTCPV4ValidArgsTestParse01, 1); + DetectCsumTCPV4ValidArgsTestParse01); UtRegisterTest("DetectCsumTCPV4InValidArgsTestParse02", - DetectCsumTCPV4InValidArgsTestParse02, 1); + DetectCsumTCPV4InValidArgsTestParse02); UtRegisterTest("DetectCsumTCPV4ValidArgsTestParse03", - DetectCsumTCPV4ValidArgsTestParse03, 1); + DetectCsumTCPV4ValidArgsTestParse03); UtRegisterTest("DetectCsumUDPV4ValidArgsTestParse01", - DetectCsumUDPV4ValidArgsTestParse01, 1); + DetectCsumUDPV4ValidArgsTestParse01); UtRegisterTest("DetectCsumUDPV4InValidArgsTestParse02", - DetectCsumUDPV4InValidArgsTestParse02, 1); + DetectCsumUDPV4InValidArgsTestParse02); UtRegisterTest("DetectCsumUDPV4ValidArgsTestParse03", - DetectCsumUDPV4ValidArgsTestParse03, 1); + DetectCsumUDPV4ValidArgsTestParse03); UtRegisterTest("DetectCsumUDPV6ValidArgsTestParse01", - DetectCsumUDPV6ValidArgsTestParse01, 1); + DetectCsumUDPV6ValidArgsTestParse01); UtRegisterTest("DetectCsumUDPV6InValidArgsTestParse02", - DetectCsumUDPV6InValidArgsTestParse02, 1); + DetectCsumUDPV6InValidArgsTestParse02); UtRegisterTest("DetectCsumUDPV6ValidArgsTestParse03", - DetectCsumUDPV6ValidArgsTestParse03, 1); + DetectCsumUDPV6ValidArgsTestParse03); UtRegisterTest("DetectCsumTCPV6ValidArgsTestParse01", - DetectCsumTCPV6ValidArgsTestParse01, 1); + DetectCsumTCPV6ValidArgsTestParse01); UtRegisterTest("DetectCsumTCPV6InValidArgsTestParse02", - DetectCsumTCPV6InValidArgsTestParse02, 1); + DetectCsumTCPV6InValidArgsTestParse02); UtRegisterTest("DetectCsumTCPV6ValidArgsTestParse03", - DetectCsumTCPV6ValidArgsTestParse03, 1); + DetectCsumTCPV6ValidArgsTestParse03); UtRegisterTest("DetectCsumICMPV6ValidArgsTestParse01", - DetectCsumICMPV6ValidArgsTestParse01, 1); + DetectCsumICMPV6ValidArgsTestParse01); UtRegisterTest("DetectCsumICMPV6InValidArgsTestParse02", - DetectCsumICMPV6InValidArgsTestParse02, 1); + DetectCsumICMPV6InValidArgsTestParse02); UtRegisterTest("DetectCsumICMPV6ValidArgsTestParse03", - DetectCsumICMPV6ValidArgsTestParse03, 1); + DetectCsumICMPV6ValidArgsTestParse03); - UtRegisterTest("DetectCsumICMPV6Test01", - DetectCsumICMPV6Test01, 1); + UtRegisterTest("DetectCsumICMPV6Test01", DetectCsumICMPV6Test01); #endif /* UNITTESTS */ diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 60da43ed05a6..e66ca94d0ae6 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -1812,25 +1812,25 @@ void DetectDceIfaceRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectDceIfaceTestParse01", DetectDceIfaceTestParse01, 1); - UtRegisterTest("DetectDceIfaceTestParse02", DetectDceIfaceTestParse02, 1); - UtRegisterTest("DetectDceIfaceTestParse03", DetectDceIfaceTestParse03, 1); - UtRegisterTest("DetectDceIfaceTestParse04", DetectDceIfaceTestParse04, 1); - UtRegisterTest("DetectDceIfaceTestParse05", DetectDceIfaceTestParse05, 1); - UtRegisterTest("DetectDceIfaceTestParse06", DetectDceIfaceTestParse06, 1); - UtRegisterTest("DetectDceIfaceTestParse07", DetectDceIfaceTestParse07, 1); - UtRegisterTest("DetectDceIfaceTestParse08", DetectDceIfaceTestParse08, 1); - UtRegisterTest("DetectDceIfaceTestParse09", DetectDceIfaceTestParse09, 1); - UtRegisterTest("DetectDceIfaceTestParse10", DetectDceIfaceTestParse10, 1); - UtRegisterTest("DetectDceIfaceTestParse11", DetectDceIfaceTestParse11, 1); - UtRegisterTest("DetectDceIfaceTestParse12", DetectDceIfaceTestParse12, 1); + UtRegisterTest("DetectDceIfaceTestParse01", DetectDceIfaceTestParse01); + UtRegisterTest("DetectDceIfaceTestParse02", DetectDceIfaceTestParse02); + UtRegisterTest("DetectDceIfaceTestParse03", DetectDceIfaceTestParse03); + UtRegisterTest("DetectDceIfaceTestParse04", DetectDceIfaceTestParse04); + UtRegisterTest("DetectDceIfaceTestParse05", DetectDceIfaceTestParse05); + UtRegisterTest("DetectDceIfaceTestParse06", DetectDceIfaceTestParse06); + UtRegisterTest("DetectDceIfaceTestParse07", DetectDceIfaceTestParse07); + UtRegisterTest("DetectDceIfaceTestParse08", DetectDceIfaceTestParse08); + UtRegisterTest("DetectDceIfaceTestParse09", DetectDceIfaceTestParse09); + UtRegisterTest("DetectDceIfaceTestParse10", DetectDceIfaceTestParse10); + UtRegisterTest("DetectDceIfaceTestParse11", DetectDceIfaceTestParse11); + UtRegisterTest("DetectDceIfaceTestParse12", DetectDceIfaceTestParse12); /* Disabled because of bug_753. Would be enabled, once we rewrite * dce parser */ #if 0 UtRegisterTest("DetectDceIfaceTestParse13", DetectDceIfaceTestParse13, 1); #endif - UtRegisterTest("DetectDceIfaceTestParse14", DetectDceIfaceTestParse14, 1); - UtRegisterTest("DetectDceIfaceTestParse15", DetectDceIfaceTestParse15, 1); + UtRegisterTest("DetectDceIfaceTestParse14", DetectDceIfaceTestParse14); + UtRegisterTest("DetectDceIfaceTestParse15", DetectDceIfaceTestParse15); #endif return; diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 0885666374eb..8e33c8b18924 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -2927,15 +2927,15 @@ void DetectDceOpnumRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectDceOpnumTestParse01", DetectDceOpnumTestParse01, 1); - UtRegisterTest("DetectDceOpnumTestParse02", DetectDceOpnumTestParse02, 1); - UtRegisterTest("DetectDceOpnumTestParse03", DetectDceOpnumTestParse03, 1); - UtRegisterTest("DetectDceOpnumTestParse04", DetectDceOpnumTestParse04, 1); - UtRegisterTest("DetectDceOpnumTestParse05", DetectDceOpnumTestParse05, 1); - UtRegisterTest("DetectDceOpnumTestParse06", DetectDceOpnumTestParse06, 1); - UtRegisterTest("DetectDceOpnumTestParse07", DetectDceOpnumTestParse07, 1); - UtRegisterTest("DetectDceOpnumTestParse08", DetectDceOpnumTestParse08, 1); - UtRegisterTest("DetectDceOpnumTestParse09", DetectDceOpnumTestParse09, 1); + UtRegisterTest("DetectDceOpnumTestParse01", DetectDceOpnumTestParse01); + UtRegisterTest("DetectDceOpnumTestParse02", DetectDceOpnumTestParse02); + UtRegisterTest("DetectDceOpnumTestParse03", DetectDceOpnumTestParse03); + UtRegisterTest("DetectDceOpnumTestParse04", DetectDceOpnumTestParse04); + UtRegisterTest("DetectDceOpnumTestParse05", DetectDceOpnumTestParse05); + UtRegisterTest("DetectDceOpnumTestParse06", DetectDceOpnumTestParse06); + UtRegisterTest("DetectDceOpnumTestParse07", DetectDceOpnumTestParse07); + UtRegisterTest("DetectDceOpnumTestParse08", DetectDceOpnumTestParse08); + UtRegisterTest("DetectDceOpnumTestParse09", DetectDceOpnumTestParse09); /* Disabled because of bug_753. Would be enabled, once we rewrite * dce parser */ #if 0 diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index d5e660ebd442..b3b6da859815 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -1837,11 +1837,16 @@ static int DetectDceStubDataTestParse05(void) void DetectDceStubDataRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectDceStubDataTestParse01", DetectDceStubDataTestParse01, 1); - UtRegisterTest("DetectDceStubDataTestParse02", DetectDceStubDataTestParse02, 1); - UtRegisterTest("DetectDceStubDataTestParse03", DetectDceStubDataTestParse03, 1); - UtRegisterTest("DetectDceStubDataTestParse04", DetectDceStubDataTestParse04, 1); - UtRegisterTest("DetectDceStubDataTestParse05", DetectDceStubDataTestParse05, 1); + UtRegisterTest("DetectDceStubDataTestParse01", + DetectDceStubDataTestParse01); + UtRegisterTest("DetectDceStubDataTestParse02", + DetectDceStubDataTestParse02); + UtRegisterTest("DetectDceStubDataTestParse03", + DetectDceStubDataTestParse03); + UtRegisterTest("DetectDceStubDataTestParse04", + DetectDceStubDataTestParse04); + UtRegisterTest("DetectDceStubDataTestParse05", + DetectDceStubDataTestParse05); #endif return; diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 7a95446f8b52..14df7c47ded9 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -651,15 +651,24 @@ static int DetectDetectionFilterTestSig3(void) void DetectDetectionFilterRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectDetectionFilterTestParse01", DetectDetectionFilterTestParse01, 1); - UtRegisterTest("DetectDetectionFilterTestParse02", DetectDetectionFilterTestParse02, 1); - UtRegisterTest("DetectDetectionFilterTestParse03", DetectDetectionFilterTestParse03, 1); - UtRegisterTest("DetectDetectionFilterTestParse04", DetectDetectionFilterTestParse04, 1); - UtRegisterTest("DetectDetectionFilterTestParse05", DetectDetectionFilterTestParse05, 1); - UtRegisterTest("DetectDetectionFilterTestParse06", DetectDetectionFilterTestParse06, 1); - UtRegisterTest("DetectDetectionFilterTestSig1", DetectDetectionFilterTestSig1, 1); - UtRegisterTest("DetectDetectionFilterTestSig2", DetectDetectionFilterTestSig2, 1); - UtRegisterTest("DetectDetectionFilterTestSig3", DetectDetectionFilterTestSig3, 1); + UtRegisterTest("DetectDetectionFilterTestParse01", + DetectDetectionFilterTestParse01); + UtRegisterTest("DetectDetectionFilterTestParse02", + DetectDetectionFilterTestParse02); + UtRegisterTest("DetectDetectionFilterTestParse03", + DetectDetectionFilterTestParse03); + UtRegisterTest("DetectDetectionFilterTestParse04", + DetectDetectionFilterTestParse04); + UtRegisterTest("DetectDetectionFilterTestParse05", + DetectDetectionFilterTestParse05); + UtRegisterTest("DetectDetectionFilterTestParse06", + DetectDetectionFilterTestParse06); + UtRegisterTest("DetectDetectionFilterTestSig1", + DetectDetectionFilterTestSig1); + UtRegisterTest("DetectDetectionFilterTestSig2", + DetectDetectionFilterTestSig2); + UtRegisterTest("DetectDetectionFilterTestSig3", + DetectDetectionFilterTestSig3); #endif /* UNITTESTS */ } diff --git a/src/detect-distance.c b/src/detect-distance.c index 60a2ff517e4d..fe5d36599a37 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -264,8 +264,9 @@ int DetectDistanceTestPacket01 (void) void DetectDistanceRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectDistanceTest01 -- distance / within mix", DetectDistanceTest01, 1); - UtRegisterTest("DetectDistanceTestPacket01", DetectDistanceTestPacket01, 1); + UtRegisterTest("DetectDistanceTest01 -- distance / within mix", + DetectDistanceTest01); + UtRegisterTest("DetectDistanceTestPacket01", DetectDistanceTestPacket01); #endif /* UNITTESTS */ } diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 63babd8f136a..3bf708f3babe 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -1134,12 +1134,15 @@ static int DetectDnsQueryTest07(void) static void DetectDnsQueryRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectDnsQueryTest01", DetectDnsQueryTest01, 1); - UtRegisterTest("DetectDnsQueryTest02", DetectDnsQueryTest02, 1); - UtRegisterTest("DetectDnsQueryTest03 -- tcp", DetectDnsQueryTest03, 1); - UtRegisterTest("DetectDnsQueryTest04 -- tcp splicing", DetectDnsQueryTest04, 1); - UtRegisterTest("DetectDnsQueryTest05 -- tcp splicing/multi tx", DetectDnsQueryTest05, 1); - UtRegisterTest("DetectDnsQueryTest06 -- pcre", DetectDnsQueryTest06, 1); - UtRegisterTest("DetectDnsQueryTest07 -- app layer event", DetectDnsQueryTest07, 1); + UtRegisterTest("DetectDnsQueryTest01", DetectDnsQueryTest01); + UtRegisterTest("DetectDnsQueryTest02", DetectDnsQueryTest02); + UtRegisterTest("DetectDnsQueryTest03 -- tcp", DetectDnsQueryTest03); + UtRegisterTest("DetectDnsQueryTest04 -- tcp splicing", + DetectDnsQueryTest04); + UtRegisterTest("DetectDnsQueryTest05 -- tcp splicing/multi tx", + DetectDnsQueryTest05); + UtRegisterTest("DetectDnsQueryTest06 -- pcre", DetectDnsQueryTest06); + UtRegisterTest("DetectDnsQueryTest07 -- app layer event", + DetectDnsQueryTest07); #endif } diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 9858a5f2a467..6d4e598f8da2 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -811,28 +811,28 @@ int DetectDsizeIcmpv6Test01 (void) void DsizeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DsizeTestParse01", DsizeTestParse01, 1); - UtRegisterTest("DsizeTestParse02", DsizeTestParse02, 1); - UtRegisterTest("DsizeTestParse03", DsizeTestParse03, 1); - UtRegisterTest("DsizeTestParse04", DsizeTestParse04, 1); - UtRegisterTest("DsizeTestParse05", DsizeTestParse05, 1); - UtRegisterTest("DsizeTestParse06", DsizeTestParse06, 1); - UtRegisterTest("DsizeTestParse07", DsizeTestParse07, 1); - UtRegisterTest("DsizeTestParse08", DsizeTestParse08, 1); - UtRegisterTest("DsizeTestParse09", DsizeTestParse09, 1); - UtRegisterTest("DsizeTestParse10", DsizeTestParse10, 1); - UtRegisterTest("DsizeTestParse11", DsizeTestParse11, 1); - UtRegisterTest("DsizeTestParse12", DsizeTestParse12, 1); - UtRegisterTest("DsizeTestParse13", DsizeTestParse13, 1); - UtRegisterTest("DsizeTestParse14", DsizeTestParse14, 1); - UtRegisterTest("DsizeTestParse15", DsizeTestParse15, 1); - UtRegisterTest("DsizeTestParse16", DsizeTestParse16, 1); - UtRegisterTest("DsizeTestParse17", DsizeTestParse17, 1); - UtRegisterTest("DsizeTestParse18", DsizeTestParse18, 1); - UtRegisterTest("DsizeTestParse19", DsizeTestParse19, 1); - UtRegisterTest("DsizeTestParse20", DsizeTestParse20, 1); - - UtRegisterTest("DetectDsizeIcmpv6Test01", DetectDsizeIcmpv6Test01, 1); + UtRegisterTest("DsizeTestParse01", DsizeTestParse01); + UtRegisterTest("DsizeTestParse02", DsizeTestParse02); + UtRegisterTest("DsizeTestParse03", DsizeTestParse03); + UtRegisterTest("DsizeTestParse04", DsizeTestParse04); + UtRegisterTest("DsizeTestParse05", DsizeTestParse05); + UtRegisterTest("DsizeTestParse06", DsizeTestParse06); + UtRegisterTest("DsizeTestParse07", DsizeTestParse07); + UtRegisterTest("DsizeTestParse08", DsizeTestParse08); + UtRegisterTest("DsizeTestParse09", DsizeTestParse09); + UtRegisterTest("DsizeTestParse10", DsizeTestParse10); + UtRegisterTest("DsizeTestParse11", DsizeTestParse11); + UtRegisterTest("DsizeTestParse12", DsizeTestParse12); + UtRegisterTest("DsizeTestParse13", DsizeTestParse13); + UtRegisterTest("DsizeTestParse14", DsizeTestParse14); + UtRegisterTest("DsizeTestParse15", DsizeTestParse15); + UtRegisterTest("DsizeTestParse16", DsizeTestParse16); + UtRegisterTest("DsizeTestParse17", DsizeTestParse17); + UtRegisterTest("DsizeTestParse18", DsizeTestParse18); + UtRegisterTest("DsizeTestParse19", DsizeTestParse19); + UtRegisterTest("DsizeTestParse20", DsizeTestParse20); + + UtRegisterTest("DetectDsizeIcmpv6Test01", DetectDsizeIcmpv6Test01); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-address-ipv4.c b/src/detect-engine-address-ipv4.c index 9e78dab8cf41..8950f5800706 100644 --- a/src/detect-engine-address-ipv4.c +++ b/src/detect-engine-address-ipv4.c @@ -1439,18 +1439,18 @@ void DetectAddressIPv4Tests(void) { #ifdef UNITTESTS UtRegisterTest("DetectAddressIPv4TestAddressCmp01", - DetectAddressIPv4TestAddressCmp01, 1); + DetectAddressIPv4TestAddressCmp01); UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace02", - DetectAddressIPv4IsCompleteIPSpace02, 1); + DetectAddressIPv4IsCompleteIPSpace02); UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace03", - DetectAddressIPv4IsCompleteIPSpace03, 1); + DetectAddressIPv4IsCompleteIPSpace03); UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace04", - DetectAddressIPv4IsCompleteIPSpace04, 1); - UtRegisterTest("DetectAddressIPv4CutNot05", DetectAddressIPv4CutNot05, 1); - UtRegisterTest("DetectAddressIPv4CutNot06", DetectAddressIPv4CutNot06, 1); - UtRegisterTest("DetectAddressIPv4CutNot07", DetectAddressIPv4CutNot07, 1); - UtRegisterTest("DetectAddressIPv4CutNot08", DetectAddressIPv4CutNot08, 1); - UtRegisterTest("DetectAddressIPv4CutNot09", DetectAddressIPv4CutNot09, 1); - UtRegisterTest("DetectAddressIPv4Join10", DetectAddressIPv4Join10, 1); + DetectAddressIPv4IsCompleteIPSpace04); + UtRegisterTest("DetectAddressIPv4CutNot05", DetectAddressIPv4CutNot05); + UtRegisterTest("DetectAddressIPv4CutNot06", DetectAddressIPv4CutNot06); + UtRegisterTest("DetectAddressIPv4CutNot07", DetectAddressIPv4CutNot07); + UtRegisterTest("DetectAddressIPv4CutNot08", DetectAddressIPv4CutNot08); + UtRegisterTest("DetectAddressIPv4CutNot09", DetectAddressIPv4CutNot09); + UtRegisterTest("DetectAddressIPv4Join10", DetectAddressIPv4Join10); #endif } diff --git a/src/detect-engine-address-ipv6.c b/src/detect-engine-address-ipv6.c index 21d7f30bd2aa..2195ae10df0e 100644 --- a/src/detect-engine-address-ipv6.c +++ b/src/detect-engine-address-ipv6.c @@ -2081,49 +2081,48 @@ void DetectAddressIPv6Tests(void) { #ifdef UNITTESTS - UtRegisterTest("AddressTestIPv6Gt01", AddressTestIPv6Gt01, 1); - UtRegisterTest("AddressTestIPv6Gt02", AddressTestIPv6Gt02, 1); - UtRegisterTest("AddressTestIPv6Gt03", AddressTestIPv6Gt03, 1); - UtRegisterTest("AddressTestIPv6Gt04", AddressTestIPv6Gt04, 1); - - UtRegisterTest("AddressTestIPv6Lt01", AddressTestIPv6Lt01, 1); - UtRegisterTest("AddressTestIPv6Lt02", AddressTestIPv6Lt02, 1); - UtRegisterTest("AddressTestIPv6Lt03", AddressTestIPv6Lt03, 1); - UtRegisterTest("AddressTestIPv6Lt04", AddressTestIPv6Lt04, 1); - - UtRegisterTest("AddressTestIPv6Eq01", AddressTestIPv6Eq01, 1); - UtRegisterTest("AddressTestIPv6Eq02", AddressTestIPv6Eq02, 1); - UtRegisterTest("AddressTestIPv6Eq03", AddressTestIPv6Eq03, 1); - UtRegisterTest("AddressTestIPv6Eq04", AddressTestIPv6Eq04, 1); - - UtRegisterTest("AddressTestIPv6Le01", AddressTestIPv6Le01, 1); - UtRegisterTest("AddressTestIPv6Le02", AddressTestIPv6Le02, 1); - UtRegisterTest("AddressTestIPv6Le03", AddressTestIPv6Le03, 1); - UtRegisterTest("AddressTestIPv6Le04", AddressTestIPv6Le04, 1); - UtRegisterTest("AddressTestIPv6Le05", AddressTestIPv6Le05, 1); - - UtRegisterTest("AddressTestIPv6Ge01", AddressTestIPv6Ge01, 1); - UtRegisterTest("AddressTestIPv6Ge02", AddressTestIPv6Ge02, 1); - UtRegisterTest("AddressTestIPv6Ge03", AddressTestIPv6Ge03, 1); - UtRegisterTest("AddressTestIPv6Ge04", AddressTestIPv6Ge04, 1); - UtRegisterTest("AddressTestIPv6Ge05", AddressTestIPv6Ge05, 1); - - UtRegisterTest("AddressTestIPv6SubOne01", AddressTestIPv6SubOne01, 1); - UtRegisterTest("AddressTestIPv6SubOne02", AddressTestIPv6SubOne02, 1); - - UtRegisterTest("AddressTestIPv6AddOne01", AddressTestIPv6AddOne01, 1); - UtRegisterTest("AddressTestIPv6AddOne02", AddressTestIPv6AddOne02, 1); - - UtRegisterTest("AddressTestIPv6AddressCmp01", - AddressTestIPv6AddressCmp01, 1); - - UtRegisterTest("AddressTestIPv6CutNot01", AddressTestIPv6CutNot01, 1); - UtRegisterTest("AddressTestIPv6CutNot02", AddressTestIPv6CutNot02, 1); - UtRegisterTest("AddressTestIPv6CutNot03", AddressTestIPv6CutNot03, 1); - UtRegisterTest("AddressTestIPv6CutNot04", AddressTestIPv6CutNot04, 1); - UtRegisterTest("AddressTestIPv6CutNot05", AddressTestIPv6CutNot05, 1); - - UtRegisterTest("AddressTestIPv6Join01", AddressTestIPv6Join01, 1); + UtRegisterTest("AddressTestIPv6Gt01", AddressTestIPv6Gt01); + UtRegisterTest("AddressTestIPv6Gt02", AddressTestIPv6Gt02); + UtRegisterTest("AddressTestIPv6Gt03", AddressTestIPv6Gt03); + UtRegisterTest("AddressTestIPv6Gt04", AddressTestIPv6Gt04); + + UtRegisterTest("AddressTestIPv6Lt01", AddressTestIPv6Lt01); + UtRegisterTest("AddressTestIPv6Lt02", AddressTestIPv6Lt02); + UtRegisterTest("AddressTestIPv6Lt03", AddressTestIPv6Lt03); + UtRegisterTest("AddressTestIPv6Lt04", AddressTestIPv6Lt04); + + UtRegisterTest("AddressTestIPv6Eq01", AddressTestIPv6Eq01); + UtRegisterTest("AddressTestIPv6Eq02", AddressTestIPv6Eq02); + UtRegisterTest("AddressTestIPv6Eq03", AddressTestIPv6Eq03); + UtRegisterTest("AddressTestIPv6Eq04", AddressTestIPv6Eq04); + + UtRegisterTest("AddressTestIPv6Le01", AddressTestIPv6Le01); + UtRegisterTest("AddressTestIPv6Le02", AddressTestIPv6Le02); + UtRegisterTest("AddressTestIPv6Le03", AddressTestIPv6Le03); + UtRegisterTest("AddressTestIPv6Le04", AddressTestIPv6Le04); + UtRegisterTest("AddressTestIPv6Le05", AddressTestIPv6Le05); + + UtRegisterTest("AddressTestIPv6Ge01", AddressTestIPv6Ge01); + UtRegisterTest("AddressTestIPv6Ge02", AddressTestIPv6Ge02); + UtRegisterTest("AddressTestIPv6Ge03", AddressTestIPv6Ge03); + UtRegisterTest("AddressTestIPv6Ge04", AddressTestIPv6Ge04); + UtRegisterTest("AddressTestIPv6Ge05", AddressTestIPv6Ge05); + + UtRegisterTest("AddressTestIPv6SubOne01", AddressTestIPv6SubOne01); + UtRegisterTest("AddressTestIPv6SubOne02", AddressTestIPv6SubOne02); + + UtRegisterTest("AddressTestIPv6AddOne01", AddressTestIPv6AddOne01); + UtRegisterTest("AddressTestIPv6AddOne02", AddressTestIPv6AddOne02); + + UtRegisterTest("AddressTestIPv6AddressCmp01", AddressTestIPv6AddressCmp01); + + UtRegisterTest("AddressTestIPv6CutNot01", AddressTestIPv6CutNot01); + UtRegisterTest("AddressTestIPv6CutNot02", AddressTestIPv6CutNot02); + UtRegisterTest("AddressTestIPv6CutNot03", AddressTestIPv6CutNot03); + UtRegisterTest("AddressTestIPv6CutNot04", AddressTestIPv6CutNot04); + UtRegisterTest("AddressTestIPv6CutNot05", AddressTestIPv6CutNot05); + + UtRegisterTest("AddressTestIPv6Join01", AddressTestIPv6Join01); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 1c65198aaba5..5f601309d2f4 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -4816,199 +4816,199 @@ void DetectAddressTests(void) DetectAddressIPv4Tests(); DetectAddressIPv6Tests(); - UtRegisterTest("AddressTestParse01", AddressTestParse01, 1); - UtRegisterTest("AddressTestParse02", AddressTestParse02, 1); - UtRegisterTest("AddressTestParse03", AddressTestParse03, 1); - UtRegisterTest("AddressTestParse04", AddressTestParse04, 1); - UtRegisterTest("AddressTestParse05", AddressTestParse05, 1); - UtRegisterTest("AddressTestParse06", AddressTestParse06, 1); - UtRegisterTest("AddressTestParse07", AddressTestParse07, 1); - UtRegisterTest("AddressTestParse08", AddressTestParse08, 1); - UtRegisterTest("AddressTestParse09", AddressTestParse09, 1); - UtRegisterTest("AddressTestParse10", AddressTestParse10, 1); - UtRegisterTest("AddressTestParse11", AddressTestParse11, 1); - UtRegisterTest("AddressTestParse12", AddressTestParse12, 1); - UtRegisterTest("AddressTestParse13", AddressTestParse13, 1); - UtRegisterTest("AddressTestParse14", AddressTestParse14, 1); - UtRegisterTest("AddressTestParse15", AddressTestParse15, 1); - UtRegisterTest("AddressTestParse16", AddressTestParse16, 1); - UtRegisterTest("AddressTestParse17", AddressTestParse17, 1); - UtRegisterTest("AddressTestParse18", AddressTestParse18, 1); - UtRegisterTest("AddressTestParse19", AddressTestParse19, 1); - UtRegisterTest("AddressTestParse20", AddressTestParse20, 1); - UtRegisterTest("AddressTestParse21", AddressTestParse21, 1); - UtRegisterTest("AddressTestParse22", AddressTestParse22, 1); - UtRegisterTest("AddressTestParse23", AddressTestParse23, 1); - UtRegisterTest("AddressTestParse24", AddressTestParse24, 1); - UtRegisterTest("AddressTestParse25", AddressTestParse25, 1); - UtRegisterTest("AddressTestParse26", AddressTestParse26, 1); - UtRegisterTest("AddressTestParse27", AddressTestParse27, 1); - UtRegisterTest("AddressTestParse28", AddressTestParse28, 1); - UtRegisterTest("AddressTestParse29", AddressTestParse29, 1); - UtRegisterTest("AddressTestParse30", AddressTestParse30, 1); - UtRegisterTest("AddressTestParse31", AddressTestParse31, 1); - UtRegisterTest("AddressTestParse32", AddressTestParse32, 1); - UtRegisterTest("AddressTestParse33", AddressTestParse33, 1); - UtRegisterTest("AddressTestParse34", AddressTestParse34, 1); - UtRegisterTest("AddressTestParse35", AddressTestParse35, 1); - UtRegisterTest("AddressTestParse36", AddressTestParse36, 1); - UtRegisterTest("AddressTestParse37", AddressTestParse37, 1); - - UtRegisterTest("AddressTestMatch01", AddressTestMatch01, 1); - UtRegisterTest("AddressTestMatch02", AddressTestMatch02, 1); - UtRegisterTest("AddressTestMatch03", AddressTestMatch03, 1); - UtRegisterTest("AddressTestMatch04", AddressTestMatch04, 1); - UtRegisterTest("AddressTestMatch05", AddressTestMatch05, 1); - UtRegisterTest("AddressTestMatch06", AddressTestMatch06, 1); - UtRegisterTest("AddressTestMatch07", AddressTestMatch07, 1); - UtRegisterTest("AddressTestMatch08", AddressTestMatch08, 1); - UtRegisterTest("AddressTestMatch09", AddressTestMatch09, 1); - UtRegisterTest("AddressTestMatch10", AddressTestMatch10, 1); - UtRegisterTest("AddressTestMatch11", AddressTestMatch11, 1); - - UtRegisterTest("AddressTestCmp01", AddressTestCmp01, 1); - UtRegisterTest("AddressTestCmp02", AddressTestCmp02, 1); - UtRegisterTest("AddressTestCmp03", AddressTestCmp03, 1); - UtRegisterTest("AddressTestCmp04", AddressTestCmp04, 1); - UtRegisterTest("AddressTestCmp05", AddressTestCmp05, 1); - UtRegisterTest("AddressTestCmp06", AddressTestCmp06, 1); - UtRegisterTest("AddressTestCmpIPv407", AddressTestCmpIPv407, 1); - UtRegisterTest("AddressTestCmpIPv408", AddressTestCmpIPv408, 1); - - UtRegisterTest("AddressTestCmp07", AddressTestCmp07, 1); - UtRegisterTest("AddressTestCmp08", AddressTestCmp08, 1); - UtRegisterTest("AddressTestCmp09", AddressTestCmp09, 1); - UtRegisterTest("AddressTestCmp10", AddressTestCmp10, 1); - UtRegisterTest("AddressTestCmp11", AddressTestCmp11, 1); - UtRegisterTest("AddressTestCmp12", AddressTestCmp12, 1); + UtRegisterTest("AddressTestParse01", AddressTestParse01); + UtRegisterTest("AddressTestParse02", AddressTestParse02); + UtRegisterTest("AddressTestParse03", AddressTestParse03); + UtRegisterTest("AddressTestParse04", AddressTestParse04); + UtRegisterTest("AddressTestParse05", AddressTestParse05); + UtRegisterTest("AddressTestParse06", AddressTestParse06); + UtRegisterTest("AddressTestParse07", AddressTestParse07); + UtRegisterTest("AddressTestParse08", AddressTestParse08); + UtRegisterTest("AddressTestParse09", AddressTestParse09); + UtRegisterTest("AddressTestParse10", AddressTestParse10); + UtRegisterTest("AddressTestParse11", AddressTestParse11); + UtRegisterTest("AddressTestParse12", AddressTestParse12); + UtRegisterTest("AddressTestParse13", AddressTestParse13); + UtRegisterTest("AddressTestParse14", AddressTestParse14); + UtRegisterTest("AddressTestParse15", AddressTestParse15); + UtRegisterTest("AddressTestParse16", AddressTestParse16); + UtRegisterTest("AddressTestParse17", AddressTestParse17); + UtRegisterTest("AddressTestParse18", AddressTestParse18); + UtRegisterTest("AddressTestParse19", AddressTestParse19); + UtRegisterTest("AddressTestParse20", AddressTestParse20); + UtRegisterTest("AddressTestParse21", AddressTestParse21); + UtRegisterTest("AddressTestParse22", AddressTestParse22); + UtRegisterTest("AddressTestParse23", AddressTestParse23); + UtRegisterTest("AddressTestParse24", AddressTestParse24); + UtRegisterTest("AddressTestParse25", AddressTestParse25); + UtRegisterTest("AddressTestParse26", AddressTestParse26); + UtRegisterTest("AddressTestParse27", AddressTestParse27); + UtRegisterTest("AddressTestParse28", AddressTestParse28); + UtRegisterTest("AddressTestParse29", AddressTestParse29); + UtRegisterTest("AddressTestParse30", AddressTestParse30); + UtRegisterTest("AddressTestParse31", AddressTestParse31); + UtRegisterTest("AddressTestParse32", AddressTestParse32); + UtRegisterTest("AddressTestParse33", AddressTestParse33); + UtRegisterTest("AddressTestParse34", AddressTestParse34); + UtRegisterTest("AddressTestParse35", AddressTestParse35); + UtRegisterTest("AddressTestParse36", AddressTestParse36); + UtRegisterTest("AddressTestParse37", AddressTestParse37); + + UtRegisterTest("AddressTestMatch01", AddressTestMatch01); + UtRegisterTest("AddressTestMatch02", AddressTestMatch02); + UtRegisterTest("AddressTestMatch03", AddressTestMatch03); + UtRegisterTest("AddressTestMatch04", AddressTestMatch04); + UtRegisterTest("AddressTestMatch05", AddressTestMatch05); + UtRegisterTest("AddressTestMatch06", AddressTestMatch06); + UtRegisterTest("AddressTestMatch07", AddressTestMatch07); + UtRegisterTest("AddressTestMatch08", AddressTestMatch08); + UtRegisterTest("AddressTestMatch09", AddressTestMatch09); + UtRegisterTest("AddressTestMatch10", AddressTestMatch10); + UtRegisterTest("AddressTestMatch11", AddressTestMatch11); + + UtRegisterTest("AddressTestCmp01", AddressTestCmp01); + UtRegisterTest("AddressTestCmp02", AddressTestCmp02); + UtRegisterTest("AddressTestCmp03", AddressTestCmp03); + UtRegisterTest("AddressTestCmp04", AddressTestCmp04); + UtRegisterTest("AddressTestCmp05", AddressTestCmp05); + UtRegisterTest("AddressTestCmp06", AddressTestCmp06); + UtRegisterTest("AddressTestCmpIPv407", AddressTestCmpIPv407); + UtRegisterTest("AddressTestCmpIPv408", AddressTestCmpIPv408); + + UtRegisterTest("AddressTestCmp07", AddressTestCmp07); + UtRegisterTest("AddressTestCmp08", AddressTestCmp08); + UtRegisterTest("AddressTestCmp09", AddressTestCmp09); + UtRegisterTest("AddressTestCmp10", AddressTestCmp10); + UtRegisterTest("AddressTestCmp11", AddressTestCmp11); + UtRegisterTest("AddressTestCmp12", AddressTestCmp12); UtRegisterTest("AddressTestAddressGroupSetup01", - AddressTestAddressGroupSetup01, 1); + AddressTestAddressGroupSetup01); UtRegisterTest("AddressTestAddressGroupSetup02", - AddressTestAddressGroupSetup02, 1); + AddressTestAddressGroupSetup02); UtRegisterTest("AddressTestAddressGroupSetup03", - AddressTestAddressGroupSetup03, 1); + AddressTestAddressGroupSetup03); UtRegisterTest("AddressTestAddressGroupSetup04", - AddressTestAddressGroupSetup04, 1); + AddressTestAddressGroupSetup04); UtRegisterTest("AddressTestAddressGroupSetup05", - AddressTestAddressGroupSetup05, 1); + AddressTestAddressGroupSetup05); UtRegisterTest("AddressTestAddressGroupSetup06", - AddressTestAddressGroupSetup06, 1); + AddressTestAddressGroupSetup06); UtRegisterTest("AddressTestAddressGroupSetup07", - AddressTestAddressGroupSetup07, 1); + AddressTestAddressGroupSetup07); UtRegisterTest("AddressTestAddressGroupSetup08", - AddressTestAddressGroupSetup08, 1); + AddressTestAddressGroupSetup08); UtRegisterTest("AddressTestAddressGroupSetup09", - AddressTestAddressGroupSetup09, 1); + AddressTestAddressGroupSetup09); UtRegisterTest("AddressTestAddressGroupSetup10", - AddressTestAddressGroupSetup10, 1); + AddressTestAddressGroupSetup10); UtRegisterTest("AddressTestAddressGroupSetup11", - AddressTestAddressGroupSetup11, 1); + AddressTestAddressGroupSetup11); UtRegisterTest("AddressTestAddressGroupSetup12", - AddressTestAddressGroupSetup12, 1); + AddressTestAddressGroupSetup12); UtRegisterTest("AddressTestAddressGroupSetup13", - AddressTestAddressGroupSetup13, 1); + AddressTestAddressGroupSetup13); UtRegisterTest("AddressTestAddressGroupSetupIPv414", - AddressTestAddressGroupSetupIPv414, 1); + AddressTestAddressGroupSetupIPv414); UtRegisterTest("AddressTestAddressGroupSetupIPv415", - AddressTestAddressGroupSetupIPv415, 1); + AddressTestAddressGroupSetupIPv415); UtRegisterTest("AddressTestAddressGroupSetupIPv416", - AddressTestAddressGroupSetupIPv416, 1); + AddressTestAddressGroupSetupIPv416); UtRegisterTest("AddressTestAddressGroupSetup14", - AddressTestAddressGroupSetup14, 1); + AddressTestAddressGroupSetup14); UtRegisterTest("AddressTestAddressGroupSetup15", - AddressTestAddressGroupSetup15, 1); + AddressTestAddressGroupSetup15); UtRegisterTest("AddressTestAddressGroupSetup16", - AddressTestAddressGroupSetup16, 1); + AddressTestAddressGroupSetup16); UtRegisterTest("AddressTestAddressGroupSetup17", - AddressTestAddressGroupSetup17, 1); + AddressTestAddressGroupSetup17); UtRegisterTest("AddressTestAddressGroupSetup18", - AddressTestAddressGroupSetup18, 1); + AddressTestAddressGroupSetup18); UtRegisterTest("AddressTestAddressGroupSetup19", - AddressTestAddressGroupSetup19, 1); + AddressTestAddressGroupSetup19); UtRegisterTest("AddressTestAddressGroupSetup20", - AddressTestAddressGroupSetup20, 1); + AddressTestAddressGroupSetup20); UtRegisterTest("AddressTestAddressGroupSetup21", - AddressTestAddressGroupSetup21, 1); + AddressTestAddressGroupSetup21); UtRegisterTest("AddressTestAddressGroupSetup22", - AddressTestAddressGroupSetup22, 1); + AddressTestAddressGroupSetup22); UtRegisterTest("AddressTestAddressGroupSetup23", - AddressTestAddressGroupSetup23, 1); + AddressTestAddressGroupSetup23); UtRegisterTest("AddressTestAddressGroupSetup24", - AddressTestAddressGroupSetup24, 1); + AddressTestAddressGroupSetup24); UtRegisterTest("AddressTestAddressGroupSetup25", - AddressTestAddressGroupSetup25, 1); + AddressTestAddressGroupSetup25); UtRegisterTest("AddressTestAddressGroupSetup26", - AddressTestAddressGroupSetup26, 1); + AddressTestAddressGroupSetup26); UtRegisterTest("AddressTestAddressGroupSetup27", - AddressTestAddressGroupSetup27, 1); + AddressTestAddressGroupSetup27); UtRegisterTest("AddressTestAddressGroupSetup28", - AddressTestAddressGroupSetup28, 1); + AddressTestAddressGroupSetup28); UtRegisterTest("AddressTestAddressGroupSetup29", - AddressTestAddressGroupSetup29, 1); + AddressTestAddressGroupSetup29); UtRegisterTest("AddressTestAddressGroupSetup30", - AddressTestAddressGroupSetup30, 1); + AddressTestAddressGroupSetup30); UtRegisterTest("AddressTestAddressGroupSetup31", - AddressTestAddressGroupSetup31, 1); + AddressTestAddressGroupSetup31); UtRegisterTest("AddressTestAddressGroupSetup32", - AddressTestAddressGroupSetup32, 1); + AddressTestAddressGroupSetup32); UtRegisterTest("AddressTestAddressGroupSetup33", - AddressTestAddressGroupSetup33, 1); + AddressTestAddressGroupSetup33); UtRegisterTest("AddressTestAddressGroupSetup34", - AddressTestAddressGroupSetup34, 1); + AddressTestAddressGroupSetup34); UtRegisterTest("AddressTestAddressGroupSetup35", - AddressTestAddressGroupSetup35, 1); + AddressTestAddressGroupSetup35); UtRegisterTest("AddressTestAddressGroupSetup36", - AddressTestAddressGroupSetup36, 1); + AddressTestAddressGroupSetup36); UtRegisterTest("AddressTestAddressGroupSetup37", - AddressTestAddressGroupSetup37, 1); + AddressTestAddressGroupSetup37); UtRegisterTest("AddressTestAddressGroupSetup38", - AddressTestAddressGroupSetup38, 1); + AddressTestAddressGroupSetup38); UtRegisterTest("AddressTestAddressGroupSetup39", - AddressTestAddressGroupSetup39, 1); + AddressTestAddressGroupSetup39); UtRegisterTest("AddressTestAddressGroupSetup40", - AddressTestAddressGroupSetup40, 1); + AddressTestAddressGroupSetup40); UtRegisterTest("AddressTestAddressGroupSetup41", - AddressTestAddressGroupSetup41, 1); + AddressTestAddressGroupSetup41); UtRegisterTest("AddressTestAddressGroupSetup42", - AddressTestAddressGroupSetup42, 1); + AddressTestAddressGroupSetup42); UtRegisterTest("AddressTestAddressGroupSetup43", - AddressTestAddressGroupSetup43, 1); + AddressTestAddressGroupSetup43); UtRegisterTest("AddressTestAddressGroupSetup44", - AddressTestAddressGroupSetup44, 1); + AddressTestAddressGroupSetup44); UtRegisterTest("AddressTestAddressGroupSetup45", - AddressTestAddressGroupSetup45, 1); + AddressTestAddressGroupSetup45); UtRegisterTest("AddressTestAddressGroupSetup46", - AddressTestAddressGroupSetup46, 1); + AddressTestAddressGroupSetup46); UtRegisterTest("AddressTestAddressGroupSetup47", - AddressTestAddressGroupSetup47, 1); + AddressTestAddressGroupSetup47); UtRegisterTest("AddressTestAddressGroupSetup48", - AddressTestAddressGroupSetup48, 1); - - UtRegisterTest("AddressTestCutIPv401", AddressTestCutIPv401, 1); - UtRegisterTest("AddressTestCutIPv402", AddressTestCutIPv402, 1); - UtRegisterTest("AddressTestCutIPv403", AddressTestCutIPv403, 1); - UtRegisterTest("AddressTestCutIPv404", AddressTestCutIPv404, 1); - UtRegisterTest("AddressTestCutIPv405", AddressTestCutIPv405, 1); - UtRegisterTest("AddressTestCutIPv406", AddressTestCutIPv406, 1); - UtRegisterTest("AddressTestCutIPv407", AddressTestCutIPv407, 1); - UtRegisterTest("AddressTestCutIPv408", AddressTestCutIPv408, 1); - UtRegisterTest("AddressTestCutIPv409", AddressTestCutIPv409, 1); - UtRegisterTest("AddressTestCutIPv410", AddressTestCutIPv410, 1); + AddressTestAddressGroupSetup48); + + UtRegisterTest("AddressTestCutIPv401", AddressTestCutIPv401); + UtRegisterTest("AddressTestCutIPv402", AddressTestCutIPv402); + UtRegisterTest("AddressTestCutIPv403", AddressTestCutIPv403); + UtRegisterTest("AddressTestCutIPv404", AddressTestCutIPv404); + UtRegisterTest("AddressTestCutIPv405", AddressTestCutIPv405); + UtRegisterTest("AddressTestCutIPv406", AddressTestCutIPv406); + UtRegisterTest("AddressTestCutIPv407", AddressTestCutIPv407); + UtRegisterTest("AddressTestCutIPv408", AddressTestCutIPv408); + UtRegisterTest("AddressTestCutIPv409", AddressTestCutIPv409); + UtRegisterTest("AddressTestCutIPv410", AddressTestCutIPv410); UtRegisterTest("AddressTestParseInvalidMask01", - AddressTestParseInvalidMask01, 1); + AddressTestParseInvalidMask01); UtRegisterTest("AddressTestParseInvalidMask02", - AddressTestParseInvalidMask02, 1); + AddressTestParseInvalidMask02); UtRegisterTest("AddressTestParseInvalidMask03", - AddressTestParseInvalidMask03, 1); + AddressTestParseInvalidMask03); - UtRegisterTest("AddressConfVarsTest01 ", AddressConfVarsTest01, 1); - UtRegisterTest("AddressConfVarsTest02 ", AddressConfVarsTest02, 1); - UtRegisterTest("AddressConfVarsTest03 ", AddressConfVarsTest03, 1); - UtRegisterTest("AddressConfVarsTest04 ", AddressConfVarsTest04, 1); - UtRegisterTest("AddressConfVarsTest05 ", AddressConfVarsTest05, 1); + UtRegisterTest("AddressConfVarsTest01 ", AddressConfVarsTest01); + UtRegisterTest("AddressConfVarsTest02 ", AddressConfVarsTest02); + UtRegisterTest("AddressConfVarsTest03 ", AddressConfVarsTest03); + UtRegisterTest("AddressConfVarsTest04 ", AddressConfVarsTest04); + UtRegisterTest("AddressConfVarsTest05 ", AddressConfVarsTest05); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index c2f7610eb54a..c28f05752a3a 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -10134,58 +10134,58 @@ void DcePayloadRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DcePayloadTest01", DcePayloadTest01, 1); - UtRegisterTest("DcePayloadTest02", DcePayloadTest02, 1); - UtRegisterTest("DcePayloadTest03", DcePayloadTest03, 1); - UtRegisterTest("DcePayloadTest04", DcePayloadTest04, 1); - UtRegisterTest("DcePayloadTest05", DcePayloadTest05, 1); - UtRegisterTest("DcePayloadTest06", DcePayloadTest06, 1); - UtRegisterTest("DcePayloadTest07", DcePayloadTest07, 1); - UtRegisterTest("DcePayloadTest08", DcePayloadTest08, 1); - UtRegisterTest("DcePayloadTest09", DcePayloadTest09, 1); - UtRegisterTest("DcePayloadTest10", DcePayloadTest10, 1); - UtRegisterTest("DcePayloadTest11", DcePayloadTest11, 1); - UtRegisterTest("DcePayloadTest12", DcePayloadTest12, 1); + UtRegisterTest("DcePayloadTest01", DcePayloadTest01); + UtRegisterTest("DcePayloadTest02", DcePayloadTest02); + UtRegisterTest("DcePayloadTest03", DcePayloadTest03); + UtRegisterTest("DcePayloadTest04", DcePayloadTest04); + UtRegisterTest("DcePayloadTest05", DcePayloadTest05); + UtRegisterTest("DcePayloadTest06", DcePayloadTest06); + UtRegisterTest("DcePayloadTest07", DcePayloadTest07); + UtRegisterTest("DcePayloadTest08", DcePayloadTest08); + UtRegisterTest("DcePayloadTest09", DcePayloadTest09); + UtRegisterTest("DcePayloadTest10", DcePayloadTest10); + UtRegisterTest("DcePayloadTest11", DcePayloadTest11); + UtRegisterTest("DcePayloadTest12", DcePayloadTest12); /* Disabled because of bug_753. Would be enabled, once we rewrite * dce parser */ #if 0 UtRegisterTest("DcePayloadTest13", DcePayloadTest13, 1); UtRegisterTest("DcePayloadTest14", DcePayloadTest14, 1); #endif - UtRegisterTest("DcePayloadTest15", DcePayloadTest15, 1); - UtRegisterTest("DcePayloadTest16", DcePayloadTest16, 1); - UtRegisterTest("DcePayloadTest17", DcePayloadTest17, 1); - UtRegisterTest("DcePayloadTest18", DcePayloadTest18, 1); - UtRegisterTest("DcePayloadTest19", DcePayloadTest19, 1); - UtRegisterTest("DcePayloadTest20", DcePayloadTest20, 1); - UtRegisterTest("DcePayloadTest21", DcePayloadTest21, 1); - UtRegisterTest("DcePayloadTest22", DcePayloadTest22, 1); - UtRegisterTest("DcePayloadTest23", DcePayloadTest23, 1); - - UtRegisterTest("DcePayloadParseTest25", DcePayloadParseTest25, 1); - UtRegisterTest("DcePayloadParseTest26", DcePayloadParseTest26, 1); - UtRegisterTest("DcePayloadParseTest27", DcePayloadParseTest27, 1); - UtRegisterTest("DcePayloadParseTest28", DcePayloadParseTest28, 1); - UtRegisterTest("DcePayloadParseTest29", DcePayloadParseTest29, 1); - UtRegisterTest("DcePayloadParseTest30", DcePayloadParseTest30, 1); - UtRegisterTest("DcePayloadParseTest31", DcePayloadParseTest31, 1); - UtRegisterTest("DcePayloadParseTest32", DcePayloadParseTest32, 1); - UtRegisterTest("DcePayloadParseTest33", DcePayloadParseTest33, 1); - UtRegisterTest("DcePayloadParseTest34", DcePayloadParseTest34, 1); - UtRegisterTest("DcePayloadParseTest35", DcePayloadParseTest35, 1); - UtRegisterTest("DcePayloadParseTest36", DcePayloadParseTest36, 1); - UtRegisterTest("DcePayloadParseTest37", DcePayloadParseTest37, 1); - UtRegisterTest("DcePayloadParseTest38", DcePayloadParseTest38, 1); - UtRegisterTest("DcePayloadParseTest39", DcePayloadParseTest39, 1); - UtRegisterTest("DcePayloadParseTest40", DcePayloadParseTest40, 1); - UtRegisterTest("DcePayloadParseTest41", DcePayloadParseTest41, 1); - - UtRegisterTest("DcePayloadTest42", DcePayloadTest42, 1); - UtRegisterTest("DcePayloadTest43", DcePayloadTest43, 1); - - UtRegisterTest("DcePayloadParseTest44", DcePayloadParseTest44, 1); - UtRegisterTest("DcePayloadParseTest45", DcePayloadParseTest45, 1); - UtRegisterTest("DcePayloadParseTest46", DcePayloadParseTest46, 1); + UtRegisterTest("DcePayloadTest15", DcePayloadTest15); + UtRegisterTest("DcePayloadTest16", DcePayloadTest16); + UtRegisterTest("DcePayloadTest17", DcePayloadTest17); + UtRegisterTest("DcePayloadTest18", DcePayloadTest18); + UtRegisterTest("DcePayloadTest19", DcePayloadTest19); + UtRegisterTest("DcePayloadTest20", DcePayloadTest20); + UtRegisterTest("DcePayloadTest21", DcePayloadTest21); + UtRegisterTest("DcePayloadTest22", DcePayloadTest22); + UtRegisterTest("DcePayloadTest23", DcePayloadTest23); + + UtRegisterTest("DcePayloadParseTest25", DcePayloadParseTest25); + UtRegisterTest("DcePayloadParseTest26", DcePayloadParseTest26); + UtRegisterTest("DcePayloadParseTest27", DcePayloadParseTest27); + UtRegisterTest("DcePayloadParseTest28", DcePayloadParseTest28); + UtRegisterTest("DcePayloadParseTest29", DcePayloadParseTest29); + UtRegisterTest("DcePayloadParseTest30", DcePayloadParseTest30); + UtRegisterTest("DcePayloadParseTest31", DcePayloadParseTest31); + UtRegisterTest("DcePayloadParseTest32", DcePayloadParseTest32); + UtRegisterTest("DcePayloadParseTest33", DcePayloadParseTest33); + UtRegisterTest("DcePayloadParseTest34", DcePayloadParseTest34); + UtRegisterTest("DcePayloadParseTest35", DcePayloadParseTest35); + UtRegisterTest("DcePayloadParseTest36", DcePayloadParseTest36); + UtRegisterTest("DcePayloadParseTest37", DcePayloadParseTest37); + UtRegisterTest("DcePayloadParseTest38", DcePayloadParseTest38); + UtRegisterTest("DcePayloadParseTest39", DcePayloadParseTest39); + UtRegisterTest("DcePayloadParseTest40", DcePayloadParseTest40); + UtRegisterTest("DcePayloadParseTest41", DcePayloadParseTest41); + + UtRegisterTest("DcePayloadTest42", DcePayloadTest42); + UtRegisterTest("DcePayloadTest43", DcePayloadTest43); + + UtRegisterTest("DcePayloadParseTest44", DcePayloadParseTest44); + UtRegisterTest("DcePayloadParseTest45", DcePayloadParseTest45); + UtRegisterTest("DcePayloadParseTest46", DcePayloadParseTest46); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-event.c b/src/detect-engine-event.c index a03c63093382..6028e9895d3a 100644 --- a/src/detect-engine-event.c +++ b/src/detect-engine-event.c @@ -406,11 +406,11 @@ int EngineEventTestParse06 (void) void EngineEventRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("EngineEventTestParse01", EngineEventTestParse01, 1); - UtRegisterTest("EngineEventTestParse02", EngineEventTestParse02, 1); - UtRegisterTest("EngineEventTestParse03", EngineEventTestParse03, 1); - UtRegisterTest("EngineEventTestParse04", EngineEventTestParse04, 1); - UtRegisterTest("EngineEventTestParse05", EngineEventTestParse05, 1); - UtRegisterTest("EngineEventTestParse06", EngineEventTestParse06, 1); + UtRegisterTest("EngineEventTestParse01", EngineEventTestParse01); + UtRegisterTest("EngineEventTestParse02", EngineEventTestParse02); + UtRegisterTest("EngineEventTestParse03", EngineEventTestParse03); + UtRegisterTest("EngineEventTestParse04", EngineEventTestParse04); + UtRegisterTest("EngineEventTestParse05", EngineEventTestParse05); + UtRegisterTest("EngineEventTestParse06", EngineEventTestParse06); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 1f7c66640421..c55450beedc4 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -594,11 +594,11 @@ void DetectEngineSMTPFiledataRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineSMTPFiledataTest01", - DetectEngineSMTPFiledataTest01, 1); + DetectEngineSMTPFiledataTest01); UtRegisterTest("DetectEngineSMTPFiledataTest02", - DetectEngineSMTPFiledataTest02, 1); + DetectEngineSMTPFiledataTest02); UtRegisterTest("DetectEngineSMTPFiledataTest03", - DetectEngineSMTPFiledataTest03, 1); + DetectEngineSMTPFiledataTest03); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 42ef760aa2e8..5fc48c5fc057 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -1076,68 +1076,68 @@ void DetectEngineHttpClientBodyRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpClientBodyTest01", - DetectEngineHttpClientBodyTest01, 1); + DetectEngineHttpClientBodyTest01); UtRegisterTest("DetectEngineHttpClientBodyTest02", - DetectEngineHttpClientBodyTest02, 1); + DetectEngineHttpClientBodyTest02); UtRegisterTest("DetectEngineHttpClientBodyTest03", - DetectEngineHttpClientBodyTest03, 1); + DetectEngineHttpClientBodyTest03); UtRegisterTest("DetectEngineHttpClientBodyTest04", - DetectEngineHttpClientBodyTest04, 1); + DetectEngineHttpClientBodyTest04); UtRegisterTest("DetectEngineHttpClientBodyTest05", - DetectEngineHttpClientBodyTest05, 1); + DetectEngineHttpClientBodyTest05); UtRegisterTest("DetectEngineHttpClientBodyTest06", - DetectEngineHttpClientBodyTest06, 1); + DetectEngineHttpClientBodyTest06); UtRegisterTest("DetectEngineHttpClientBodyTest07", - DetectEngineHttpClientBodyTest07, 1); + DetectEngineHttpClientBodyTest07); UtRegisterTest("DetectEngineHttpClientBodyTest08", - DetectEngineHttpClientBodyTest08, 1); + DetectEngineHttpClientBodyTest08); UtRegisterTest("DetectEngineHttpClientBodyTest09", - DetectEngineHttpClientBodyTest09, 1); + DetectEngineHttpClientBodyTest09); UtRegisterTest("DetectEngineHttpClientBodyTest10", - DetectEngineHttpClientBodyTest10, 1); + DetectEngineHttpClientBodyTest10); UtRegisterTest("DetectEngineHttpClientBodyTest11", - DetectEngineHttpClientBodyTest11, 1); + DetectEngineHttpClientBodyTest11); UtRegisterTest("DetectEngineHttpClientBodyTest12", - DetectEngineHttpClientBodyTest12, 1); + DetectEngineHttpClientBodyTest12); UtRegisterTest("DetectEngineHttpClientBodyTest13", - DetectEngineHttpClientBodyTest13, 1); + DetectEngineHttpClientBodyTest13); UtRegisterTest("DetectEngineHttpClientBodyTest14", - DetectEngineHttpClientBodyTest14, 1); + DetectEngineHttpClientBodyTest14); UtRegisterTest("DetectEngineHttpClientBodyTest15", - DetectEngineHttpClientBodyTest15, 1); + DetectEngineHttpClientBodyTest15); UtRegisterTest("DetectEngineHttpClientBodyTest16", - DetectEngineHttpClientBodyTest16, 1); + DetectEngineHttpClientBodyTest16); UtRegisterTest("DetectEngineHttpClientBodyTest17", - DetectEngineHttpClientBodyTest17, 1); + DetectEngineHttpClientBodyTest17); UtRegisterTest("DetectEngineHttpClientBodyTest18", - DetectEngineHttpClientBodyTest18, 1); + DetectEngineHttpClientBodyTest18); UtRegisterTest("DetectEngineHttpClientBodyTest19", - DetectEngineHttpClientBodyTest19, 1); + DetectEngineHttpClientBodyTest19); UtRegisterTest("DetectEngineHttpClientBodyTest20", - DetectEngineHttpClientBodyTest20, 1); + DetectEngineHttpClientBodyTest20); UtRegisterTest("DetectEngineHttpClientBodyTest21", - DetectEngineHttpClientBodyTest21, 1); + DetectEngineHttpClientBodyTest21); UtRegisterTest("DetectEngineHttpClientBodyTest22", - DetectEngineHttpClientBodyTest22, 1); + DetectEngineHttpClientBodyTest22); UtRegisterTest("DetectEngineHttpClientBodyTest23", - DetectEngineHttpClientBodyTest23, 1); + DetectEngineHttpClientBodyTest23); UtRegisterTest("DetectEngineHttpClientBodyTest24", - DetectEngineHttpClientBodyTest24, 1); + DetectEngineHttpClientBodyTest24); UtRegisterTest("DetectEngineHttpClientBodyTest25", - DetectEngineHttpClientBodyTest25, 1); + DetectEngineHttpClientBodyTest25); UtRegisterTest("DetectEngineHttpClientBodyTest26", - DetectEngineHttpClientBodyTest26, 1); + DetectEngineHttpClientBodyTest26); UtRegisterTest("DetectEngineHttpClientBodyTest27", - DetectEngineHttpClientBodyTest27, 1); + DetectEngineHttpClientBodyTest27); UtRegisterTest("DetectEngineHttpClientBodyTest28", - DetectEngineHttpClientBodyTest28, 1); + DetectEngineHttpClientBodyTest28); UtRegisterTest("DetectEngineHttpClientBodyTest29", - DetectEngineHttpClientBodyTest29, 1); + DetectEngineHttpClientBodyTest29); UtRegisterTest("DetectEngineHttpClientBodyTest30", - DetectEngineHttpClientBodyTest30, 1); + DetectEngineHttpClientBodyTest30); UtRegisterTest("DetectEngineHttpClientBodyTest31", - DetectEngineHttpClientBodyTest31, 1); + DetectEngineHttpClientBodyTest31); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index dfc97a9add6d..f7ec7fca1a53 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -1875,39 +1875,39 @@ void DetectEngineHttpCookieRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpCookieTest01", - DetectEngineHttpCookieTest01, 1); + DetectEngineHttpCookieTest01); UtRegisterTest("DetectEngineHttpCookieTest02", - DetectEngineHttpCookieTest02, 1); + DetectEngineHttpCookieTest02); UtRegisterTest("DetectEngineHttpCookieTest03", - DetectEngineHttpCookieTest03, 1); + DetectEngineHttpCookieTest03); UtRegisterTest("DetectEngineHttpCookieTest04", - DetectEngineHttpCookieTest04, 1); + DetectEngineHttpCookieTest04); UtRegisterTest("DetectEngineHttpCookieTest05", - DetectEngineHttpCookieTest05, 1); + DetectEngineHttpCookieTest05); UtRegisterTest("DetectEngineHttpCookieTest06", - DetectEngineHttpCookieTest06, 1); + DetectEngineHttpCookieTest06); UtRegisterTest("DetectEngineHttpCookieTest07", - DetectEngineHttpCookieTest07, 1); + DetectEngineHttpCookieTest07); UtRegisterTest("DetectEngineHttpCookieTest08", - DetectEngineHttpCookieTest08, 1); + DetectEngineHttpCookieTest08); UtRegisterTest("DetectEngineHttpCookieTest09", - DetectEngineHttpCookieTest09, 1); + DetectEngineHttpCookieTest09); UtRegisterTest("DetectEngineHttpCookieTest10", - DetectEngineHttpCookieTest10, 1); + DetectEngineHttpCookieTest10); UtRegisterTest("DetectEngineHttpCookieTest11", - DetectEngineHttpCookieTest11, 1); + DetectEngineHttpCookieTest11); UtRegisterTest("DetectEngineHttpCookieTest12", - DetectEngineHttpCookieTest12, 1); + DetectEngineHttpCookieTest12); UtRegisterTest("DetectEngineHttpCookieTest13", - DetectEngineHttpCookieTest13, 1); + DetectEngineHttpCookieTest13); UtRegisterTest("DetectEngineHttpCookieTest14", - DetectEngineHttpCookieTest14, 1); + DetectEngineHttpCookieTest14); UtRegisterTest("DetectEngineHttpCookieTest15", - DetectEngineHttpCookieTest15, 1); + DetectEngineHttpCookieTest15); UtRegisterTest("DetectEngineHttpCookieTest16", - DetectEngineHttpCookieTest16, 1); + DetectEngineHttpCookieTest16); UtRegisterTest("DetectEngineHttpCookieTest17", - DetectEngineHttpCookieTest17, 1); + DetectEngineHttpCookieTest17); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index acfae6f54b26..9419989938fd 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -3866,75 +3866,75 @@ void DetectEngineHttpHeaderRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpHeaderTest01", - DetectEngineHttpHeaderTest01, 1); + DetectEngineHttpHeaderTest01); UtRegisterTest("DetectEngineHttpHeaderTest02", - DetectEngineHttpHeaderTest02, 1); + DetectEngineHttpHeaderTest02); UtRegisterTest("DetectEngineHttpHeaderTest03", - DetectEngineHttpHeaderTest03, 1); + DetectEngineHttpHeaderTest03); UtRegisterTest("DetectEngineHttpHeaderTest04", - DetectEngineHttpHeaderTest04, 1); + DetectEngineHttpHeaderTest04); UtRegisterTest("DetectEngineHttpHeaderTest05", - DetectEngineHttpHeaderTest05, 1); + DetectEngineHttpHeaderTest05); UtRegisterTest("DetectEngineHttpHeaderTest06", - DetectEngineHttpHeaderTest06, 1); + DetectEngineHttpHeaderTest06); UtRegisterTest("DetectEngineHttpHeaderTest07", - DetectEngineHttpHeaderTest07, 1); + DetectEngineHttpHeaderTest07); UtRegisterTest("DetectEngineHttpHeaderTest08", - DetectEngineHttpHeaderTest08, 1); + DetectEngineHttpHeaderTest08); UtRegisterTest("DetectEngineHttpHeaderTest09", - DetectEngineHttpHeaderTest09, 1); + DetectEngineHttpHeaderTest09); UtRegisterTest("DetectEngineHttpHeaderTest10", - DetectEngineHttpHeaderTest10, 1); + DetectEngineHttpHeaderTest10); UtRegisterTest("DetectEngineHttpHeaderTest11", - DetectEngineHttpHeaderTest11, 1); + DetectEngineHttpHeaderTest11); UtRegisterTest("DetectEngineHttpHeaderTest12", - DetectEngineHttpHeaderTest12, 1); + DetectEngineHttpHeaderTest12); UtRegisterTest("DetectEngineHttpHeaderTest13", - DetectEngineHttpHeaderTest13, 1); + DetectEngineHttpHeaderTest13); UtRegisterTest("DetectEngineHttpHeaderTest14", - DetectEngineHttpHeaderTest14, 1); + DetectEngineHttpHeaderTest14); UtRegisterTest("DetectEngineHttpHeaderTest15", - DetectEngineHttpHeaderTest15, 1); + DetectEngineHttpHeaderTest15); UtRegisterTest("DetectEngineHttpHeaderTest16", - DetectEngineHttpHeaderTest16, 1); + DetectEngineHttpHeaderTest16); UtRegisterTest("DetectEngineHttpHeaderTest17", - DetectEngineHttpHeaderTest17, 1); + DetectEngineHttpHeaderTest17); UtRegisterTest("DetectEngineHttpHeaderTest18", - DetectEngineHttpHeaderTest18, 1); + DetectEngineHttpHeaderTest18); UtRegisterTest("DetectEngineHttpHeaderTest19", - DetectEngineHttpHeaderTest19, 1); + DetectEngineHttpHeaderTest19); UtRegisterTest("DetectEngineHttpHeaderTest20", - DetectEngineHttpHeaderTest20, 1); + DetectEngineHttpHeaderTest20); UtRegisterTest("DetectEngineHttpHeaderTest21", - DetectEngineHttpHeaderTest21, 1); + DetectEngineHttpHeaderTest21); UtRegisterTest("DetectEngineHttpHeaderTest22", - DetectEngineHttpHeaderTest22, 1); + DetectEngineHttpHeaderTest22); UtRegisterTest("DetectEngineHttpHeaderTest23", - DetectEngineHttpHeaderTest23, 1); + DetectEngineHttpHeaderTest23); UtRegisterTest("DetectEngineHttpHeaderTest24", - DetectEngineHttpHeaderTest24, 1); + DetectEngineHttpHeaderTest24); UtRegisterTest("DetectEngineHttpHeaderTest25", - DetectEngineHttpHeaderTest25, 1); + DetectEngineHttpHeaderTest25); UtRegisterTest("DetectEngineHttpHeaderTest26", - DetectEngineHttpHeaderTest26, 1); + DetectEngineHttpHeaderTest26); UtRegisterTest("DetectEngineHttpHeaderTest27", - DetectEngineHttpHeaderTest27, 1); + DetectEngineHttpHeaderTest27); UtRegisterTest("DetectEngineHttpHeaderTest28", - DetectEngineHttpHeaderTest28, 1); + DetectEngineHttpHeaderTest28); UtRegisterTest("DetectEngineHttpHeaderTest29", - DetectEngineHttpHeaderTest29, 1); + DetectEngineHttpHeaderTest29); UtRegisterTest("DetectEngineHttpHeaderTest30", - DetectEngineHttpHeaderTest30, 1); + DetectEngineHttpHeaderTest30); UtRegisterTest("DetectEngineHttpHeaderTest31", - DetectEngineHttpHeaderTest31, 1); + DetectEngineHttpHeaderTest31); #if 0 UtRegisterTest("DetectEngineHttpHeaderTest30", DetectEngineHttpHeaderTest30, 1); #endif UtRegisterTest("DetectEngineHttpHeaderTest32", - DetectEngineHttpHeaderTest32, 1); + DetectEngineHttpHeaderTest32); UtRegisterTest("DetectEngineHttpHeaderTest33", - DetectEngineHttpHeaderTest33, 1); + DetectEngineHttpHeaderTest33); #endif /* UNITTESTS */ diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index e86debc2436d..e0d8ac9e9604 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -2588,56 +2588,31 @@ void DetectEngineHttpHHRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectEngineHttpHHTest01", - DetectEngineHttpHHTest01, 1); - UtRegisterTest("DetectEngineHttpHHTest02", - DetectEngineHttpHHTest02, 1); - UtRegisterTest("DetectEngineHttpHHTest03", - DetectEngineHttpHHTest03, 1); - UtRegisterTest("DetectEngineHttpHHTest04", - DetectEngineHttpHHTest04, 1); - UtRegisterTest("DetectEngineHttpHHTest05", - DetectEngineHttpHHTest05, 1); - UtRegisterTest("DetectEngineHttpHHTest06", - DetectEngineHttpHHTest06, 1); - UtRegisterTest("DetectEngineHttpHHTest07", - DetectEngineHttpHHTest07, 1); - UtRegisterTest("DetectEngineHttpHHTest08", - DetectEngineHttpHHTest08, 1); - UtRegisterTest("DetectEngineHttpHHTest09", - DetectEngineHttpHHTest09, 1); - UtRegisterTest("DetectEngineHttpHHTest10", - DetectEngineHttpHHTest10, 1); - UtRegisterTest("DetectEngineHttpHHTest11", - DetectEngineHttpHHTest11, 1); - UtRegisterTest("DetectEngineHttpHHTest12", - DetectEngineHttpHHTest12, 1); - UtRegisterTest("DetectEngineHttpHHTest13", - DetectEngineHttpHHTest13, 1); - UtRegisterTest("DetectEngineHttpHHTest14", - DetectEngineHttpHHTest14, 1); - UtRegisterTest("DetectEngineHttpHHTest15", - DetectEngineHttpHHTest15, 1); - UtRegisterTest("DetectEngineHttpHHTest16", - DetectEngineHttpHHTest16, 1); - UtRegisterTest("DetectEngineHttpHHTest17", - DetectEngineHttpHHTest17, 1); - UtRegisterTest("DetectEngineHttpHHTest18", - DetectEngineHttpHHTest18, 1); - UtRegisterTest("DetectEngineHttpHHTest19", - DetectEngineHttpHHTest19, 1); - UtRegisterTest("DetectEngineHttpHHTest20", - DetectEngineHttpHHTest20, 1); - UtRegisterTest("DetectEngineHttpHHTest21", - DetectEngineHttpHHTest21, 1); - UtRegisterTest("DetectEngineHttpHHTest22", - DetectEngineHttpHHTest22, 1); - UtRegisterTest("DetectEngineHttpHHTest23", - DetectEngineHttpHHTest23, 1); - UtRegisterTest("DetectEngineHttpHHTest24", - DetectEngineHttpHHTest24, 1); - UtRegisterTest("DetectEngineHttpHHTest25", - DetectEngineHttpHHTest25, 1); + UtRegisterTest("DetectEngineHttpHHTest01", DetectEngineHttpHHTest01); + UtRegisterTest("DetectEngineHttpHHTest02", DetectEngineHttpHHTest02); + UtRegisterTest("DetectEngineHttpHHTest03", DetectEngineHttpHHTest03); + UtRegisterTest("DetectEngineHttpHHTest04", DetectEngineHttpHHTest04); + UtRegisterTest("DetectEngineHttpHHTest05", DetectEngineHttpHHTest05); + UtRegisterTest("DetectEngineHttpHHTest06", DetectEngineHttpHHTest06); + UtRegisterTest("DetectEngineHttpHHTest07", DetectEngineHttpHHTest07); + UtRegisterTest("DetectEngineHttpHHTest08", DetectEngineHttpHHTest08); + UtRegisterTest("DetectEngineHttpHHTest09", DetectEngineHttpHHTest09); + UtRegisterTest("DetectEngineHttpHHTest10", DetectEngineHttpHHTest10); + UtRegisterTest("DetectEngineHttpHHTest11", DetectEngineHttpHHTest11); + UtRegisterTest("DetectEngineHttpHHTest12", DetectEngineHttpHHTest12); + UtRegisterTest("DetectEngineHttpHHTest13", DetectEngineHttpHHTest13); + UtRegisterTest("DetectEngineHttpHHTest14", DetectEngineHttpHHTest14); + UtRegisterTest("DetectEngineHttpHHTest15", DetectEngineHttpHHTest15); + UtRegisterTest("DetectEngineHttpHHTest16", DetectEngineHttpHHTest16); + UtRegisterTest("DetectEngineHttpHHTest17", DetectEngineHttpHHTest17); + UtRegisterTest("DetectEngineHttpHHTest18", DetectEngineHttpHHTest18); + UtRegisterTest("DetectEngineHttpHHTest19", DetectEngineHttpHHTest19); + UtRegisterTest("DetectEngineHttpHHTest20", DetectEngineHttpHHTest20); + UtRegisterTest("DetectEngineHttpHHTest21", DetectEngineHttpHHTest21); + UtRegisterTest("DetectEngineHttpHHTest22", DetectEngineHttpHHTest22); + UtRegisterTest("DetectEngineHttpHHTest23", DetectEngineHttpHHTest23); + UtRegisterTest("DetectEngineHttpHHTest24", DetectEngineHttpHHTest24); + UtRegisterTest("DetectEngineHttpHHTest25", DetectEngineHttpHHTest25); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index e4102868598b..00c7dc9904e2 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -1815,39 +1815,39 @@ void DetectEngineHttpMethodRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpMethodTest01", - DetectEngineHttpMethodTest01, 1); + DetectEngineHttpMethodTest01); UtRegisterTest("DetectEngineHttpMethodTest02", - DetectEngineHttpMethodTest02, 1); + DetectEngineHttpMethodTest02); UtRegisterTest("DetectEngineHttpMethodTest03", - DetectEngineHttpMethodTest03, 1); + DetectEngineHttpMethodTest03); UtRegisterTest("DetectEngineHttpMethodTest04", - DetectEngineHttpMethodTest04, 1); + DetectEngineHttpMethodTest04); UtRegisterTest("DetectEngineHttpMethodTest05", - DetectEngineHttpMethodTest05, 1); + DetectEngineHttpMethodTest05); UtRegisterTest("DetectEngineHttpMethodTest06", - DetectEngineHttpMethodTest06, 1); + DetectEngineHttpMethodTest06); UtRegisterTest("DetectEngineHttpMethodTest07", - DetectEngineHttpMethodTest07, 1); + DetectEngineHttpMethodTest07); UtRegisterTest("DetectEngineHttpMethodTest08", - DetectEngineHttpMethodTest08, 1); + DetectEngineHttpMethodTest08); UtRegisterTest("DetectEngineHttpMethodTest09", - DetectEngineHttpMethodTest09, 1); + DetectEngineHttpMethodTest09); UtRegisterTest("DetectEngineHttpMethodTest10", - DetectEngineHttpMethodTest10, 1); + DetectEngineHttpMethodTest10); UtRegisterTest("DetectEngineHttpMethodTest11", - DetectEngineHttpMethodTest11, 1); + DetectEngineHttpMethodTest11); UtRegisterTest("DetectEngineHttpMethodTest12", - DetectEngineHttpMethodTest12, 1); + DetectEngineHttpMethodTest12); UtRegisterTest("DetectEngineHttpMethodTest13", - DetectEngineHttpMethodTest13, 1); + DetectEngineHttpMethodTest13); UtRegisterTest("DetectEngineHttpMethodTest14", - DetectEngineHttpMethodTest14, 1); + DetectEngineHttpMethodTest14); UtRegisterTest("DetectEngineHttpMethodTest15", - DetectEngineHttpMethodTest15, 1); + DetectEngineHttpMethodTest15); UtRegisterTest("DetectEngineHttpMethodTest16", - DetectEngineHttpMethodTest16, 1); + DetectEngineHttpMethodTest16); UtRegisterTest("DetectEngineHttpMethodTest17", - DetectEngineHttpMethodTest17, 1); + DetectEngineHttpMethodTest17); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 3756a104bdc9..7395cbfa6177 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -3506,71 +3506,71 @@ void DetectEngineHttpRawHeaderRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpRawHeaderTest01", - DetectEngineHttpRawHeaderTest01, 1); + DetectEngineHttpRawHeaderTest01); UtRegisterTest("DetectEngineHttpRawHeaderTest02", - DetectEngineHttpRawHeaderTest02, 1); + DetectEngineHttpRawHeaderTest02); UtRegisterTest("DetectEngineHttpRawHeaderTest03", - DetectEngineHttpRawHeaderTest03, 1); + DetectEngineHttpRawHeaderTest03); UtRegisterTest("DetectEngineHttpRawHeaderTest04", - DetectEngineHttpRawHeaderTest04, 1); + DetectEngineHttpRawHeaderTest04); UtRegisterTest("DetectEngineHttpRawHeaderTest05", - DetectEngineHttpRawHeaderTest05, 1); + DetectEngineHttpRawHeaderTest05); UtRegisterTest("DetectEngineHttpRawHeaderTest06", - DetectEngineHttpRawHeaderTest06, 1); + DetectEngineHttpRawHeaderTest06); UtRegisterTest("DetectEngineHttpRawHeaderTest07", - DetectEngineHttpRawHeaderTest07, 1); + DetectEngineHttpRawHeaderTest07); UtRegisterTest("DetectEngineHttpRawHeaderTest08", - DetectEngineHttpRawHeaderTest08, 1); + DetectEngineHttpRawHeaderTest08); UtRegisterTest("DetectEngineHttpRawHeaderTest09", - DetectEngineHttpRawHeaderTest09, 1); + DetectEngineHttpRawHeaderTest09); UtRegisterTest("DetectEngineHttpRawHeaderTest10", - DetectEngineHttpRawHeaderTest10, 1); + DetectEngineHttpRawHeaderTest10); UtRegisterTest("DetectEngineHttpRawHeaderTest11", - DetectEngineHttpRawHeaderTest11, 1); + DetectEngineHttpRawHeaderTest11); UtRegisterTest("DetectEngineHttpRawHeaderTest12", - DetectEngineHttpRawHeaderTest12, 1); + DetectEngineHttpRawHeaderTest12); UtRegisterTest("DetectEngineHttpRawHeaderTest13", - DetectEngineHttpRawHeaderTest13, 1); + DetectEngineHttpRawHeaderTest13); UtRegisterTest("DetectEngineHttpRawHeaderTest14", - DetectEngineHttpRawHeaderTest14, 1); + DetectEngineHttpRawHeaderTest14); UtRegisterTest("DetectEngineHttpRawHeaderTest15", - DetectEngineHttpRawHeaderTest15, 1); + DetectEngineHttpRawHeaderTest15); UtRegisterTest("DetectEngineHttpRawHeaderTest16", - DetectEngineHttpRawHeaderTest16, 1); + DetectEngineHttpRawHeaderTest16); UtRegisterTest("DetectEngineHttpRawHeaderTest17", - DetectEngineHttpRawHeaderTest17, 1); + DetectEngineHttpRawHeaderTest17); UtRegisterTest("DetectEngineHttpRawHeaderTest18", - DetectEngineHttpRawHeaderTest18, 1); + DetectEngineHttpRawHeaderTest18); UtRegisterTest("DetectEngineHttpRawHeaderTest19", - DetectEngineHttpRawHeaderTest19, 1); + DetectEngineHttpRawHeaderTest19); UtRegisterTest("DetectEngineHttpRawHeaderTest20", - DetectEngineHttpRawHeaderTest20, 1); + DetectEngineHttpRawHeaderTest20); UtRegisterTest("DetectEngineHttpRawHeaderTest21", - DetectEngineHttpRawHeaderTest21, 1); + DetectEngineHttpRawHeaderTest21); UtRegisterTest("DetectEngineHttpRawHeaderTest22", - DetectEngineHttpRawHeaderTest22, 1); + DetectEngineHttpRawHeaderTest22); UtRegisterTest("DetectEngineHttpRawHeaderTest23", - DetectEngineHttpRawHeaderTest23, 1); + DetectEngineHttpRawHeaderTest23); UtRegisterTest("DetectEngineHttpRawHeaderTest24", - DetectEngineHttpRawHeaderTest24, 1); + DetectEngineHttpRawHeaderTest24); UtRegisterTest("DetectEngineHttpRawHeaderTest25", - DetectEngineHttpRawHeaderTest25, 1); + DetectEngineHttpRawHeaderTest25); UtRegisterTest("DetectEngineHttpRawHeaderTest26", - DetectEngineHttpRawHeaderTest26, 1); + DetectEngineHttpRawHeaderTest26); UtRegisterTest("DetectEngineHttpRawHeaderTest27", - DetectEngineHttpRawHeaderTest27, 1); + DetectEngineHttpRawHeaderTest27); UtRegisterTest("DetectEngineHttpRawHeaderTest28", - DetectEngineHttpRawHeaderTest28, 1); + DetectEngineHttpRawHeaderTest28); UtRegisterTest("DetectEngineHttpRawHeaderTest29", - DetectEngineHttpRawHeaderTest29, 1); + DetectEngineHttpRawHeaderTest29); #if 0 UtRegisterTest("DetectEngineHttpRawHeaderTest30", DetectEngineHttpRawHeaderTest30, 1); #endif UtRegisterTest("DetectEngineHttpRawHeaderTest31", - DetectEngineHttpRawHeaderTest31, 1); + DetectEngineHttpRawHeaderTest31); UtRegisterTest("DetectEngineHttpRawHeaderTest32", - DetectEngineHttpRawHeaderTest32, 1); + DetectEngineHttpRawHeaderTest32); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index bee6cd8eff8e..b3c894dd4efc 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -2616,56 +2616,31 @@ void DetectEngineHttpHRHRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectEngineHttpHRHTest01", - DetectEngineHttpHRHTest01, 1); - UtRegisterTest("DetectEngineHttpHRHTest02", - DetectEngineHttpHRHTest02, 1); - UtRegisterTest("DetectEngineHttpHRHTest03", - DetectEngineHttpHRHTest03, 1); - UtRegisterTest("DetectEngineHttpHRHTest04", - DetectEngineHttpHRHTest04, 1); - UtRegisterTest("DetectEngineHttpHRHTest05", - DetectEngineHttpHRHTest05, 1); - UtRegisterTest("DetectEngineHttpHRHTest06", - DetectEngineHttpHRHTest06, 1); - UtRegisterTest("DetectEngineHttpHRHTest07", - DetectEngineHttpHRHTest07, 1); - UtRegisterTest("DetectEngineHttpHRHTest08", - DetectEngineHttpHRHTest08, 1); - UtRegisterTest("DetectEngineHttpHRHTest09", - DetectEngineHttpHRHTest09, 1); - UtRegisterTest("DetectEngineHttpHRHTest10", - DetectEngineHttpHRHTest10, 1); - UtRegisterTest("DetectEngineHttpHRHTest11", - DetectEngineHttpHRHTest11, 1); - UtRegisterTest("DetectEngineHttpHRHTest12", - DetectEngineHttpHRHTest12, 1); - UtRegisterTest("DetectEngineHttpHRHTest13", - DetectEngineHttpHRHTest13, 1); - UtRegisterTest("DetectEngineHttpHRHTest14", - DetectEngineHttpHRHTest14, 1); - UtRegisterTest("DetectEngineHttpHRHTest15", - DetectEngineHttpHRHTest15, 1); - UtRegisterTest("DetectEngineHttpHRHTest16", - DetectEngineHttpHRHTest16, 1); - UtRegisterTest("DetectEngineHttpHRHTest17", - DetectEngineHttpHRHTest17, 1); - UtRegisterTest("DetectEngineHttpHRHTest18", - DetectEngineHttpHRHTest18, 1); - UtRegisterTest("DetectEngineHttpHRHTest19", - DetectEngineHttpHRHTest19, 1); - UtRegisterTest("DetectEngineHttpHRHTest20", - DetectEngineHttpHRHTest20, 1); - UtRegisterTest("DetectEngineHttpHRHTest21", - DetectEngineHttpHRHTest21, 1); - UtRegisterTest("DetectEngineHttpHRHTest22", - DetectEngineHttpHRHTest22, 1); - UtRegisterTest("DetectEngineHttpHRHTest23", - DetectEngineHttpHRHTest23, 1); - UtRegisterTest("DetectEngineHttpHRHTest24", - DetectEngineHttpHRHTest24, 1); - UtRegisterTest("DetectEngineHttpHRHTest25", - DetectEngineHttpHRHTest25, 1); + UtRegisterTest("DetectEngineHttpHRHTest01", DetectEngineHttpHRHTest01); + UtRegisterTest("DetectEngineHttpHRHTest02", DetectEngineHttpHRHTest02); + UtRegisterTest("DetectEngineHttpHRHTest03", DetectEngineHttpHRHTest03); + UtRegisterTest("DetectEngineHttpHRHTest04", DetectEngineHttpHRHTest04); + UtRegisterTest("DetectEngineHttpHRHTest05", DetectEngineHttpHRHTest05); + UtRegisterTest("DetectEngineHttpHRHTest06", DetectEngineHttpHRHTest06); + UtRegisterTest("DetectEngineHttpHRHTest07", DetectEngineHttpHRHTest07); + UtRegisterTest("DetectEngineHttpHRHTest08", DetectEngineHttpHRHTest08); + UtRegisterTest("DetectEngineHttpHRHTest09", DetectEngineHttpHRHTest09); + UtRegisterTest("DetectEngineHttpHRHTest10", DetectEngineHttpHRHTest10); + UtRegisterTest("DetectEngineHttpHRHTest11", DetectEngineHttpHRHTest11); + UtRegisterTest("DetectEngineHttpHRHTest12", DetectEngineHttpHRHTest12); + UtRegisterTest("DetectEngineHttpHRHTest13", DetectEngineHttpHRHTest13); + UtRegisterTest("DetectEngineHttpHRHTest14", DetectEngineHttpHRHTest14); + UtRegisterTest("DetectEngineHttpHRHTest15", DetectEngineHttpHRHTest15); + UtRegisterTest("DetectEngineHttpHRHTest16", DetectEngineHttpHRHTest16); + UtRegisterTest("DetectEngineHttpHRHTest17", DetectEngineHttpHRHTest17); + UtRegisterTest("DetectEngineHttpHRHTest18", DetectEngineHttpHRHTest18); + UtRegisterTest("DetectEngineHttpHRHTest19", DetectEngineHttpHRHTest19); + UtRegisterTest("DetectEngineHttpHRHTest20", DetectEngineHttpHRHTest20); + UtRegisterTest("DetectEngineHttpHRHTest21", DetectEngineHttpHRHTest21); + UtRegisterTest("DetectEngineHttpHRHTest22", DetectEngineHttpHRHTest22); + UtRegisterTest("DetectEngineHttpHRHTest23", DetectEngineHttpHRHTest23); + UtRegisterTest("DetectEngineHttpHRHTest24", DetectEngineHttpHRHTest24); + UtRegisterTest("DetectEngineHttpHRHTest25", DetectEngineHttpHRHTest25); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hrl.c b/src/detect-engine-hrl.c index 555b5af3720c..da1c14c577e8 100644 --- a/src/detect-engine-hrl.c +++ b/src/detect-engine-hrl.c @@ -4138,45 +4138,45 @@ void HttpRequestLineRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("UriTestSig01", UriTestSig01, 1); - UtRegisterTest("UriTestSig02", UriTestSig02, 1); - UtRegisterTest("UriTestSig03", UriTestSig03, 1); - UtRegisterTest("UriTestSig04", UriTestSig04, 1); - UtRegisterTest("UriTestSig05", UriTestSig05, 1); - UtRegisterTest("UriTestSig06", UriTestSig06, 1); - UtRegisterTest("UriTestSig07", UriTestSig07, 1); - UtRegisterTest("UriTestSig08", UriTestSig08, 1); - UtRegisterTest("UriTestSig09", UriTestSig09, 1); - UtRegisterTest("UriTestSig10", UriTestSig10, 1); - UtRegisterTest("UriTestSig11", UriTestSig11, 1); - UtRegisterTest("UriTestSig12", UriTestSig12, 1); - UtRegisterTest("UriTestSig13", UriTestSig13, 1); - UtRegisterTest("UriTestSig14", UriTestSig14, 1); - UtRegisterTest("UriTestSig15", UriTestSig15, 1); - UtRegisterTest("UriTestSig16", UriTestSig16, 1); - UtRegisterTest("UriTestSig17", UriTestSig17, 1); - UtRegisterTest("UriTestSig18", UriTestSig18, 1); - UtRegisterTest("UriTestSig19", UriTestSig19, 1); - UtRegisterTest("UriTestSig20", UriTestSig20, 1); - UtRegisterTest("UriTestSig21", UriTestSig21, 1); - UtRegisterTest("UriTestSig22", UriTestSig22, 1); - UtRegisterTest("UriTestSig23", UriTestSig23, 1); - UtRegisterTest("UriTestSig24", UriTestSig24, 1); - UtRegisterTest("UriTestSig25", UriTestSig25, 1); - UtRegisterTest("UriTestSig26", UriTestSig26, 1); - UtRegisterTest("UriTestSig27", UriTestSig27, 1); - - UtRegisterTest("UriTestSig28", UriTestSig28, 1); - UtRegisterTest("UriTestSig29", UriTestSig29, 1); - UtRegisterTest("UriTestSig30", UriTestSig30, 1); - UtRegisterTest("UriTestSig31", UriTestSig31, 1); - UtRegisterTest("UriTestSig32", UriTestSig32, 1); - UtRegisterTest("UriTestSig33", UriTestSig33, 1); - UtRegisterTest("UriTestSig34", UriTestSig34, 1); - UtRegisterTest("UriTestSig35", UriTestSig35, 1); - UtRegisterTest("UriTestSig36", UriTestSig36, 1); - UtRegisterTest("UriTestSig37", UriTestSig37, 1); - UtRegisterTest("UriTestSig38", UriTestSig38, 1); + UtRegisterTest("UriTestSig01", UriTestSig01); + UtRegisterTest("UriTestSig02", UriTestSig02); + UtRegisterTest("UriTestSig03", UriTestSig03); + UtRegisterTest("UriTestSig04", UriTestSig04); + UtRegisterTest("UriTestSig05", UriTestSig05); + UtRegisterTest("UriTestSig06", UriTestSig06); + UtRegisterTest("UriTestSig07", UriTestSig07); + UtRegisterTest("UriTestSig08", UriTestSig08); + UtRegisterTest("UriTestSig09", UriTestSig09); + UtRegisterTest("UriTestSig10", UriTestSig10); + UtRegisterTest("UriTestSig11", UriTestSig11); + UtRegisterTest("UriTestSig12", UriTestSig12); + UtRegisterTest("UriTestSig13", UriTestSig13); + UtRegisterTest("UriTestSig14", UriTestSig14); + UtRegisterTest("UriTestSig15", UriTestSig15); + UtRegisterTest("UriTestSig16", UriTestSig16); + UtRegisterTest("UriTestSig17", UriTestSig17); + UtRegisterTest("UriTestSig18", UriTestSig18); + UtRegisterTest("UriTestSig19", UriTestSig19); + UtRegisterTest("UriTestSig20", UriTestSig20); + UtRegisterTest("UriTestSig21", UriTestSig21); + UtRegisterTest("UriTestSig22", UriTestSig22); + UtRegisterTest("UriTestSig23", UriTestSig23); + UtRegisterTest("UriTestSig24", UriTestSig24); + UtRegisterTest("UriTestSig25", UriTestSig25); + UtRegisterTest("UriTestSig26", UriTestSig26); + UtRegisterTest("UriTestSig27", UriTestSig27); + + UtRegisterTest("UriTestSig28", UriTestSig28); + UtRegisterTest("UriTestSig29", UriTestSig29); + UtRegisterTest("UriTestSig30", UriTestSig30); + UtRegisterTest("UriTestSig31", UriTestSig31); + UtRegisterTest("UriTestSig32", UriTestSig32); + UtRegisterTest("UriTestSig33", UriTestSig33); + UtRegisterTest("UriTestSig34", UriTestSig34); + UtRegisterTest("UriTestSig35", UriTestSig35); + UtRegisterTest("UriTestSig36", UriTestSig36); + UtRegisterTest("UriTestSig37", UriTestSig37); + UtRegisterTest("UriTestSig38", UriTestSig38); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index e7b08cf5367c..38d7ea7867ec 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -3686,65 +3686,65 @@ void DetectEngineHttpRawUriRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpRawUriTest01", - DetectEngineHttpRawUriTest01, 1); + DetectEngineHttpRawUriTest01); UtRegisterTest("DetectEngineHttpRawUriTest02", - DetectEngineHttpRawUriTest02, 1); + DetectEngineHttpRawUriTest02); UtRegisterTest("DetectEngineHttpRawUriTest03", - DetectEngineHttpRawUriTest03, 1); + DetectEngineHttpRawUriTest03); UtRegisterTest("DetectEngineHttpRawUriTest04", - DetectEngineHttpRawUriTest04, 1); + DetectEngineHttpRawUriTest04); UtRegisterTest("DetectEngineHttpRawUriTest05", - DetectEngineHttpRawUriTest05, 1); + DetectEngineHttpRawUriTest05); UtRegisterTest("DetectEngineHttpRawUriTest06", - DetectEngineHttpRawUriTest06, 1); + DetectEngineHttpRawUriTest06); UtRegisterTest("DetectEngineHttpRawUriTest07", - DetectEngineHttpRawUriTest07, 1); + DetectEngineHttpRawUriTest07); UtRegisterTest("DetectEngineHttpRawUriTest08", - DetectEngineHttpRawUriTest08, 1); + DetectEngineHttpRawUriTest08); UtRegisterTest("DetectEngineHttpRawUriTest09", - DetectEngineHttpRawUriTest09, 1); + DetectEngineHttpRawUriTest09); UtRegisterTest("DetectEngineHttpRawUriTest10", - DetectEngineHttpRawUriTest10, 1); + DetectEngineHttpRawUriTest10); UtRegisterTest("DetectEngineHttpRawUriTest11", - DetectEngineHttpRawUriTest11, 1); + DetectEngineHttpRawUriTest11); UtRegisterTest("DetectEngineHttpRawUriTest12", - DetectEngineHttpRawUriTest12, 1); + DetectEngineHttpRawUriTest12); UtRegisterTest("DetectEngineHttpRawUriTest13", - DetectEngineHttpRawUriTest13, 1); + DetectEngineHttpRawUriTest13); UtRegisterTest("DetectEngineHttpRawUriTest14", - DetectEngineHttpRawUriTest14, 1); + DetectEngineHttpRawUriTest14); UtRegisterTest("DetectEngineHttpRawUriTest15", - DetectEngineHttpRawUriTest15, 1); + DetectEngineHttpRawUriTest15); UtRegisterTest("DetectEngineHttpRawUriTest16", - DetectEngineHttpRawUriTest16, 1); + DetectEngineHttpRawUriTest16); UtRegisterTest("DetectEngineHttpRawUriTest17", - DetectEngineHttpRawUriTest17, 1); + DetectEngineHttpRawUriTest17); UtRegisterTest("DetectEngineHttpRawUriTest18", - DetectEngineHttpRawUriTest18, 1); + DetectEngineHttpRawUriTest18); UtRegisterTest("DetectEngineHttpRawUriTest19", - DetectEngineHttpRawUriTest19, 1); + DetectEngineHttpRawUriTest19); UtRegisterTest("DetectEngineHttpRawUriTest20", - DetectEngineHttpRawUriTest20, 1); + DetectEngineHttpRawUriTest20); UtRegisterTest("DetectEngineHttpRawUriTest21", - DetectEngineHttpRawUriTest21, 1); + DetectEngineHttpRawUriTest21); UtRegisterTest("DetectEngineHttpRawUriTest22", - DetectEngineHttpRawUriTest22, 1); + DetectEngineHttpRawUriTest22); UtRegisterTest("DetectEngineHttpRawUriTest23", - DetectEngineHttpRawUriTest23, 1); + DetectEngineHttpRawUriTest23); UtRegisterTest("DetectEngineHttpRawUriTest24", - DetectEngineHttpRawUriTest24, 1); + DetectEngineHttpRawUriTest24); UtRegisterTest("DetectEngineHttpRawUriTest25", - DetectEngineHttpRawUriTest25, 1); + DetectEngineHttpRawUriTest25); UtRegisterTest("DetectEngineHttpRawUriTest26", - DetectEngineHttpRawUriTest26, 1); + DetectEngineHttpRawUriTest26); UtRegisterTest("DetectEngineHttpRawUriTest27", - DetectEngineHttpRawUriTest27, 1); + DetectEngineHttpRawUriTest27); UtRegisterTest("DetectEngineHttpRawUriTest28", - DetectEngineHttpRawUriTest28, 1); + DetectEngineHttpRawUriTest28); UtRegisterTest("DetectEngineHttpRawUriTest29", - DetectEngineHttpRawUriTest29, 1); + DetectEngineHttpRawUriTest29); UtRegisterTest("DetectEngineHttpRawUriTest30", - DetectEngineHttpRawUriTest30, 1); + DetectEngineHttpRawUriTest30); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 93d9adee6d99..48648e3f4e3b 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -4456,86 +4456,86 @@ void DetectEngineHttpServerBodyRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpServerBodyTest01", - DetectEngineHttpServerBodyTest01, 1); + DetectEngineHttpServerBodyTest01); UtRegisterTest("DetectEngineHttpServerBodyTest02", - DetectEngineHttpServerBodyTest02, 1); + DetectEngineHttpServerBodyTest02); UtRegisterTest("DetectEngineHttpServerBodyTest03", - DetectEngineHttpServerBodyTest03, 1); + DetectEngineHttpServerBodyTest03); UtRegisterTest("DetectEngineHttpServerBodyTest04", - DetectEngineHttpServerBodyTest04, 1); + DetectEngineHttpServerBodyTest04); UtRegisterTest("DetectEngineHttpServerBodyTest05", - DetectEngineHttpServerBodyTest05, 1); + DetectEngineHttpServerBodyTest05); UtRegisterTest("DetectEngineHttpServerBodyTest06", - DetectEngineHttpServerBodyTest06, 1); + DetectEngineHttpServerBodyTest06); UtRegisterTest("DetectEngineHttpServerBodyTest07", - DetectEngineHttpServerBodyTest07, 1); + DetectEngineHttpServerBodyTest07); UtRegisterTest("DetectEngineHttpServerBodyTest08", - DetectEngineHttpServerBodyTest08, 1); + DetectEngineHttpServerBodyTest08); UtRegisterTest("DetectEngineHttpServerBodyTest09", - DetectEngineHttpServerBodyTest09, 1); + DetectEngineHttpServerBodyTest09); UtRegisterTest("DetectEngineHttpServerBodyTest10", - DetectEngineHttpServerBodyTest10, 1); + DetectEngineHttpServerBodyTest10); UtRegisterTest("DetectEngineHttpServerBodyTest11", - DetectEngineHttpServerBodyTest11, 1); + DetectEngineHttpServerBodyTest11); UtRegisterTest("DetectEngineHttpServerBodyTest12", - DetectEngineHttpServerBodyTest12, 1); + DetectEngineHttpServerBodyTest12); UtRegisterTest("DetectEngineHttpServerBodyTest13", - DetectEngineHttpServerBodyTest13, 1); + DetectEngineHttpServerBodyTest13); UtRegisterTest("DetectEngineHttpServerBodyTest14", - DetectEngineHttpServerBodyTest14, 1); + DetectEngineHttpServerBodyTest14); UtRegisterTest("DetectEngineHttpServerBodyTest15", - DetectEngineHttpServerBodyTest15, 1); + DetectEngineHttpServerBodyTest15); UtRegisterTest("DetectEngineHttpServerBodyTest16", - DetectEngineHttpServerBodyTest16, 1); + DetectEngineHttpServerBodyTest16); UtRegisterTest("DetectEngineHttpServerBodyTest17", - DetectEngineHttpServerBodyTest17, 1); + DetectEngineHttpServerBodyTest17); UtRegisterTest("DetectEngineHttpServerBodyTest18", - DetectEngineHttpServerBodyTest18, 1); + DetectEngineHttpServerBodyTest18); UtRegisterTest("DetectEngineHttpServerBodyTest19", - DetectEngineHttpServerBodyTest19, 1); + DetectEngineHttpServerBodyTest19); UtRegisterTest("DetectEngineHttpServerBodyTest20", - DetectEngineHttpServerBodyTest20, 1); + DetectEngineHttpServerBodyTest20); UtRegisterTest("DetectEngineHttpServerBodyTest21", - DetectEngineHttpServerBodyTest21, 1); + DetectEngineHttpServerBodyTest21); UtRegisterTest("DetectEngineHttpServerBodyTest22", - DetectEngineHttpServerBodyTest22, 1); + DetectEngineHttpServerBodyTest22); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest01", - DetectEngineHttpServerBodyFileDataTest01, 1); + DetectEngineHttpServerBodyFileDataTest01); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest02", - DetectEngineHttpServerBodyFileDataTest02, 1); + DetectEngineHttpServerBodyFileDataTest02); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest03", - DetectEngineHttpServerBodyFileDataTest03, 1); + DetectEngineHttpServerBodyFileDataTest03); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest04", - DetectEngineHttpServerBodyFileDataTest04, 1); + DetectEngineHttpServerBodyFileDataTest04); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest05", - DetectEngineHttpServerBodyFileDataTest05, 1); + DetectEngineHttpServerBodyFileDataTest05); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest06", - DetectEngineHttpServerBodyFileDataTest06, 1); + DetectEngineHttpServerBodyFileDataTest06); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest07", - DetectEngineHttpServerBodyFileDataTest07, 1); + DetectEngineHttpServerBodyFileDataTest07); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest08", - DetectEngineHttpServerBodyFileDataTest08, 1); + DetectEngineHttpServerBodyFileDataTest08); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest09", - DetectEngineHttpServerBodyFileDataTest09, 1); + DetectEngineHttpServerBodyFileDataTest09); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest10", - DetectEngineHttpServerBodyFileDataTest10, 1); + DetectEngineHttpServerBodyFileDataTest10); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest11", - DetectEngineHttpServerBodyFileDataTest11, 1); + DetectEngineHttpServerBodyFileDataTest11); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest12", - DetectEngineHttpServerBodyFileDataTest12, 1); + DetectEngineHttpServerBodyFileDataTest12); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest13", - DetectEngineHttpServerBodyFileDataTest13, 1); + DetectEngineHttpServerBodyFileDataTest13); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest14", - DetectEngineHttpServerBodyFileDataTest14, 1); + DetectEngineHttpServerBodyFileDataTest14); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest15", - DetectEngineHttpServerBodyFileDataTest15, 1); + DetectEngineHttpServerBodyFileDataTest15); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest16", - DetectEngineHttpServerBodyFileDataTest16, 1); + DetectEngineHttpServerBodyFileDataTest16); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest17", - DetectEngineHttpServerBodyFileDataTest17, 1); + DetectEngineHttpServerBodyFileDataTest17); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest18", - DetectEngineHttpServerBodyFileDataTest18, 1); + DetectEngineHttpServerBodyFileDataTest18); #endif /* UNITTESTS */ diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 72df1c8d5f7f..7159835ab236 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -2087,35 +2087,35 @@ void DetectEngineHttpStatCodeRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpStatCodeTest01", - DetectEngineHttpStatCodeTest01, 1); + DetectEngineHttpStatCodeTest01); UtRegisterTest("DetectEngineHttpStatCodeTest02", - DetectEngineHttpStatCodeTest02, 1); + DetectEngineHttpStatCodeTest02); UtRegisterTest("DetectEngineHttpStatCodeTest03", - DetectEngineHttpStatCodeTest03, 1); + DetectEngineHttpStatCodeTest03); UtRegisterTest("DetectEngineHttpStatCodeTest04", - DetectEngineHttpStatCodeTest04, 1); + DetectEngineHttpStatCodeTest04); UtRegisterTest("DetectEngineHttpStatCodeTest05", - DetectEngineHttpStatCodeTest05, 1); + DetectEngineHttpStatCodeTest05); UtRegisterTest("DetectEngineHttpStatCodeTest06", - DetectEngineHttpStatCodeTest06, 1); + DetectEngineHttpStatCodeTest06); UtRegisterTest("DetectEngineHttpStatCodeTest07", - DetectEngineHttpStatCodeTest07, 1); + DetectEngineHttpStatCodeTest07); UtRegisterTest("DetectEngineHttpStatCodeTest08", - DetectEngineHttpStatCodeTest08, 1); + DetectEngineHttpStatCodeTest08); UtRegisterTest("DetectEngineHttpStatCodeTest09", - DetectEngineHttpStatCodeTest09, 1); + DetectEngineHttpStatCodeTest09); UtRegisterTest("DetectEngineHttpStatCodeTest10", - DetectEngineHttpStatCodeTest10, 1); + DetectEngineHttpStatCodeTest10); UtRegisterTest("DetectEngineHttpStatCodeTest11", - DetectEngineHttpStatCodeTest11, 1); + DetectEngineHttpStatCodeTest11); UtRegisterTest("DetectEngineHttpStatCodeTest12", - DetectEngineHttpStatCodeTest12, 1); + DetectEngineHttpStatCodeTest12); UtRegisterTest("DetectEngineHttpStatCodeTest13", - DetectEngineHttpStatCodeTest13, 1); + DetectEngineHttpStatCodeTest13); UtRegisterTest("DetectEngineHttpStatCodeTest14", - DetectEngineHttpStatCodeTest14, 1); + DetectEngineHttpStatCodeTest14); UtRegisterTest("DetectEngineHttpStatCodeTest15", - DetectEngineHttpStatCodeTest15, 1); + DetectEngineHttpStatCodeTest15); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 3b8a0004d950..3d662c54afd8 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -2087,35 +2087,35 @@ void DetectEngineHttpStatMsgRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpStatMsgTest01", - DetectEngineHttpStatMsgTest01, 1); + DetectEngineHttpStatMsgTest01); UtRegisterTest("DetectEngineHttpStatMsgTest02", - DetectEngineHttpStatMsgTest02, 1); + DetectEngineHttpStatMsgTest02); UtRegisterTest("DetectEngineHttpStatMsgTest03", - DetectEngineHttpStatMsgTest03, 1); + DetectEngineHttpStatMsgTest03); UtRegisterTest("DetectEngineHttpStatMsgTest04", - DetectEngineHttpStatMsgTest04, 1); + DetectEngineHttpStatMsgTest04); UtRegisterTest("DetectEngineHttpStatMsgTest05", - DetectEngineHttpStatMsgTest05, 1); + DetectEngineHttpStatMsgTest05); UtRegisterTest("DetectEngineHttpStatMsgTest06", - DetectEngineHttpStatMsgTest06, 1); + DetectEngineHttpStatMsgTest06); UtRegisterTest("DetectEngineHttpStatMsgTest07", - DetectEngineHttpStatMsgTest07, 1); + DetectEngineHttpStatMsgTest07); UtRegisterTest("DetectEngineHttpStatMsgTest08", - DetectEngineHttpStatMsgTest08, 1); + DetectEngineHttpStatMsgTest08); UtRegisterTest("DetectEngineHttpStatMsgTest09", - DetectEngineHttpStatMsgTest09, 1); + DetectEngineHttpStatMsgTest09); UtRegisterTest("DetectEngineHttpStatMsgTest10", - DetectEngineHttpStatMsgTest10, 1); + DetectEngineHttpStatMsgTest10); UtRegisterTest("DetectEngineHttpStatMsgTest11", - DetectEngineHttpStatMsgTest11, 1); + DetectEngineHttpStatMsgTest11); UtRegisterTest("DetectEngineHttpStatMsgTest12", - DetectEngineHttpStatMsgTest12, 1); + DetectEngineHttpStatMsgTest12); UtRegisterTest("DetectEngineHttpStatMsgTest13", - DetectEngineHttpStatMsgTest13, 1); + DetectEngineHttpStatMsgTest13); UtRegisterTest("DetectEngineHttpStatMsgTest14", - DetectEngineHttpStatMsgTest14, 1); + DetectEngineHttpStatMsgTest14); UtRegisterTest("DetectEngineHttpStatMsgTest15", - DetectEngineHttpStatMsgTest15, 1); + DetectEngineHttpStatMsgTest15); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index a459776b6e25..acd00a2fedd3 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -1841,40 +1841,23 @@ void DetectEngineHttpUARegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectEngineHttpUATest01", - DetectEngineHttpUATest01, 1); - UtRegisterTest("DetectEngineHttpUATest02", - DetectEngineHttpUATest02, 1); - UtRegisterTest("DetectEngineHttpUATest03", - DetectEngineHttpUATest03, 1); - UtRegisterTest("DetectEngineHttpUATest04", - DetectEngineHttpUATest04, 1); - UtRegisterTest("DetectEngineHttpUATest05", - DetectEngineHttpUATest05, 1); - UtRegisterTest("DetectEngineHttpUATest06", - DetectEngineHttpUATest06, 1); - UtRegisterTest("DetectEngineHttpUATest07", - DetectEngineHttpUATest07, 1); - UtRegisterTest("DetectEngineHttpUATest08", - DetectEngineHttpUATest08, 1); - UtRegisterTest("DetectEngineHttpUATest09", - DetectEngineHttpUATest09, 1); - UtRegisterTest("DetectEngineHttpUATest10", - DetectEngineHttpUATest10, 1); - UtRegisterTest("DetectEngineHttpUATest11", - DetectEngineHttpUATest11, 1); - UtRegisterTest("DetectEngineHttpUATest12", - DetectEngineHttpUATest12, 1); - UtRegisterTest("DetectEngineHttpUATest13", - DetectEngineHttpUATest13, 1); - UtRegisterTest("DetectEngineHttpUATest14", - DetectEngineHttpUATest14, 1); - UtRegisterTest("DetectEngineHttpUATest15", - DetectEngineHttpUATest15, 1); - UtRegisterTest("DetectEngineHttpUATest16", - DetectEngineHttpUATest16, 1); - UtRegisterTest("DetectEngineHttpUATest17", - DetectEngineHttpUATest17, 1); + UtRegisterTest("DetectEngineHttpUATest01", DetectEngineHttpUATest01); + UtRegisterTest("DetectEngineHttpUATest02", DetectEngineHttpUATest02); + UtRegisterTest("DetectEngineHttpUATest03", DetectEngineHttpUATest03); + UtRegisterTest("DetectEngineHttpUATest04", DetectEngineHttpUATest04); + UtRegisterTest("DetectEngineHttpUATest05", DetectEngineHttpUATest05); + UtRegisterTest("DetectEngineHttpUATest06", DetectEngineHttpUATest06); + UtRegisterTest("DetectEngineHttpUATest07", DetectEngineHttpUATest07); + UtRegisterTest("DetectEngineHttpUATest08", DetectEngineHttpUATest08); + UtRegisterTest("DetectEngineHttpUATest09", DetectEngineHttpUATest09); + UtRegisterTest("DetectEngineHttpUATest10", DetectEngineHttpUATest10); + UtRegisterTest("DetectEngineHttpUATest11", DetectEngineHttpUATest11); + UtRegisterTest("DetectEngineHttpUATest12", DetectEngineHttpUATest12); + UtRegisterTest("DetectEngineHttpUATest13", DetectEngineHttpUATest13); + UtRegisterTest("DetectEngineHttpUATest14", DetectEngineHttpUATest14); + UtRegisterTest("DetectEngineHttpUATest15", DetectEngineHttpUATest15); + UtRegisterTest("DetectEngineHttpUATest16", DetectEngineHttpUATest16); + UtRegisterTest("DetectEngineHttpUATest17", DetectEngineHttpUATest17); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index 06983fc0153b..d39e6d501a05 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -2284,36 +2284,36 @@ int IPOnlyTestSig17(void) void IPOnlyRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("IPOnlyTestSig01", IPOnlyTestSig01, 1); - UtRegisterTest("IPOnlyTestSig02", IPOnlyTestSig02, 1); - UtRegisterTest("IPOnlyTestSig03", IPOnlyTestSig03, 1); - UtRegisterTest("IPOnlyTestSig04", IPOnlyTestSig04, 1); + UtRegisterTest("IPOnlyTestSig01", IPOnlyTestSig01); + UtRegisterTest("IPOnlyTestSig02", IPOnlyTestSig02); + UtRegisterTest("IPOnlyTestSig03", IPOnlyTestSig03); + UtRegisterTest("IPOnlyTestSig04", IPOnlyTestSig04); - UtRegisterTest("IPOnlyTestSig05", IPOnlyTestSig05, 1); - UtRegisterTest("IPOnlyTestSig06", IPOnlyTestSig06, 1); + UtRegisterTest("IPOnlyTestSig05", IPOnlyTestSig05); + UtRegisterTest("IPOnlyTestSig06", IPOnlyTestSig06); /* \todo fix it. We have disabled this unittest because 599 exposes 608, * which is why these unittests fail. When we fix 608, we need to renable * these sigs */ #if 0 UtRegisterTest("IPOnlyTestSig07", IPOnlyTestSig07, 1); #endif - UtRegisterTest("IPOnlyTestSig08", IPOnlyTestSig08, 1); + UtRegisterTest("IPOnlyTestSig08", IPOnlyTestSig08); - UtRegisterTest("IPOnlyTestSig09", IPOnlyTestSig09, 1); - UtRegisterTest("IPOnlyTestSig10", IPOnlyTestSig10, 1); + UtRegisterTest("IPOnlyTestSig09", IPOnlyTestSig09); + UtRegisterTest("IPOnlyTestSig10", IPOnlyTestSig10); /* \todo fix it. We have disabled this unittest because 599 exposes 608, * which is why these unittests fail. When we fix 608, we need to renable * these sigs */ #if 0 UtRegisterTest("IPOnlyTestSig11", IPOnlyTestSig11, 1); #endif - UtRegisterTest("IPOnlyTestSig12", IPOnlyTestSig12, 1); - UtRegisterTest("IPOnlyTestSig13", IPOnlyTestSig13, 1); - UtRegisterTest("IPOnlyTestSig14", IPOnlyTestSig14, 1); - UtRegisterTest("IPOnlyTestSig15", IPOnlyTestSig15, 1); - UtRegisterTest("IPOnlyTestSig16", IPOnlyTestSig16, 1); + UtRegisterTest("IPOnlyTestSig12", IPOnlyTestSig12); + UtRegisterTest("IPOnlyTestSig13", IPOnlyTestSig13); + UtRegisterTest("IPOnlyTestSig14", IPOnlyTestSig14); + UtRegisterTest("IPOnlyTestSig15", IPOnlyTestSig15); + UtRegisterTest("IPOnlyTestSig16", IPOnlyTestSig16); - UtRegisterTest("IPOnlyTestSig17", IPOnlyTestSig17, 1); + UtRegisterTest("IPOnlyTestSig17", IPOnlyTestSig17); #endif return; diff --git a/src/detect-engine-modbus.c b/src/detect-engine-modbus.c index 8bbe58286f4f..d1811d461694 100644 --- a/src/detect-engine-modbus.c +++ b/src/detect-engine-modbus.c @@ -1331,15 +1331,24 @@ static int DetectEngineInspectModbusTest09(void) void DetectEngineInspectModbusRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectEngineInspectModbusTest01 - Code function", DetectEngineInspectModbusTest01, 1); - UtRegisterTest("DetectEngineInspectModbusTest02 - code function and code subfunction", DetectEngineInspectModbusTest02, 1); - UtRegisterTest("DetectEngineInspectModbusTest03 - Function category", DetectEngineInspectModbusTest03, 1); - UtRegisterTest("DetectEngineInspectModbusTest04 - Negative function category", DetectEngineInspectModbusTest04, 1); - UtRegisterTest("DetectEngineInspectModbusTest05 - Access type", DetectEngineInspectModbusTest05, 1); - UtRegisterTest("DetectEngineInspectModbusTest06 - Access function", DetectEngineInspectModbusTest06, 1); - UtRegisterTest("DetectEngineInspectModbusTest07 - Read access at an address", DetectEngineInspectModbusTest07, 1); - UtRegisterTest("DetectEngineInspectModbusTest08 - Read access at a range of address", DetectEngineInspectModbusTest08, 1); - UtRegisterTest("DetectEngineInspectModbusTest09 - Write access at an address a range of value", DetectEngineInspectModbusTest09, 1); + UtRegisterTest("DetectEngineInspectModbusTest01 - Code function", + DetectEngineInspectModbusTest01); + UtRegisterTest("DetectEngineInspectModbusTest02 - code function and code subfunction", + DetectEngineInspectModbusTest02); + UtRegisterTest("DetectEngineInspectModbusTest03 - Function category", + DetectEngineInspectModbusTest03); + UtRegisterTest("DetectEngineInspectModbusTest04 - Negative function category", + DetectEngineInspectModbusTest04); + UtRegisterTest("DetectEngineInspectModbusTest05 - Access type", + DetectEngineInspectModbusTest05); + UtRegisterTest("DetectEngineInspectModbusTest06 - Access function", + DetectEngineInspectModbusTest06); + UtRegisterTest("DetectEngineInspectModbusTest07 - Read access at an address", + DetectEngineInspectModbusTest07); + UtRegisterTest("DetectEngineInspectModbusTest08 - Read access at a range of address", + DetectEngineInspectModbusTest08); + UtRegisterTest("DetectEngineInspectModbusTest09 - Write access at an address a range of value", + DetectEngineInspectModbusTest09); #endif /* UNITTESTS */ return; } diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index d1c0924d0512..d3a17bac35fe 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -1170,42 +1170,42 @@ static int PayloadTestSig34(void) void PayloadRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("PayloadTestSig01", PayloadTestSig01, 1); - UtRegisterTest("PayloadTestSig02", PayloadTestSig02, 1); - UtRegisterTest("PayloadTestSig03", PayloadTestSig03, 1); - UtRegisterTest("PayloadTestSig04", PayloadTestSig04, 1); - UtRegisterTest("PayloadTestSig05", PayloadTestSig05, 1); - UtRegisterTest("PayloadTestSig06", PayloadTestSig06, 1); - UtRegisterTest("PayloadTestSig07", PayloadTestSig07, 1); - UtRegisterTest("PayloadTestSig08", PayloadTestSig08, 1); - UtRegisterTest("PayloadTestSig09", PayloadTestSig09, 1); - UtRegisterTest("PayloadTestSig10", PayloadTestSig10, 1); - UtRegisterTest("PayloadTestSig11", PayloadTestSig11, 1); - UtRegisterTest("PayloadTestSig12", PayloadTestSig12, 1); - UtRegisterTest("PayloadTestSig13", PayloadTestSig13, 1); - UtRegisterTest("PayloadTestSig14", PayloadTestSig14, 1); - UtRegisterTest("PayloadTestSig15", PayloadTestSig15, 1); - UtRegisterTest("PayloadTestSig16", PayloadTestSig16, 1); - UtRegisterTest("PayloadTestSig17", PayloadTestSig17, 1); - - UtRegisterTest("PayloadTestSig18", PayloadTestSig18, 1); - UtRegisterTest("PayloadTestSig19", PayloadTestSig19, 1); - UtRegisterTest("PayloadTestSig20", PayloadTestSig20, 1); - UtRegisterTest("PayloadTestSig21", PayloadTestSig21, 1); - UtRegisterTest("PayloadTestSig22", PayloadTestSig22, 1); - UtRegisterTest("PayloadTestSig23", PayloadTestSig23, 1); - UtRegisterTest("PayloadTestSig24", PayloadTestSig24, 1); - UtRegisterTest("PayloadTestSig25", PayloadTestSig25, 1); - UtRegisterTest("PayloadTestSig26", PayloadTestSig26, 1); - UtRegisterTest("PayloadTestSig27", PayloadTestSig27, 1); - UtRegisterTest("PayloadTestSig28", PayloadTestSig28, 1); - UtRegisterTest("PayloadTestSig29", PayloadTestSig29, 1); - - UtRegisterTest("PayloadTestSig30", PayloadTestSig30, 1); - UtRegisterTest("PayloadTestSig31", PayloadTestSig31, 1); - UtRegisterTest("PayloadTestSig32", PayloadTestSig32, 1); - UtRegisterTest("PayloadTestSig33", PayloadTestSig33, 1); - UtRegisterTest("PayloadTestSig34", PayloadTestSig34, 1); + UtRegisterTest("PayloadTestSig01", PayloadTestSig01); + UtRegisterTest("PayloadTestSig02", PayloadTestSig02); + UtRegisterTest("PayloadTestSig03", PayloadTestSig03); + UtRegisterTest("PayloadTestSig04", PayloadTestSig04); + UtRegisterTest("PayloadTestSig05", PayloadTestSig05); + UtRegisterTest("PayloadTestSig06", PayloadTestSig06); + UtRegisterTest("PayloadTestSig07", PayloadTestSig07); + UtRegisterTest("PayloadTestSig08", PayloadTestSig08); + UtRegisterTest("PayloadTestSig09", PayloadTestSig09); + UtRegisterTest("PayloadTestSig10", PayloadTestSig10); + UtRegisterTest("PayloadTestSig11", PayloadTestSig11); + UtRegisterTest("PayloadTestSig12", PayloadTestSig12); + UtRegisterTest("PayloadTestSig13", PayloadTestSig13); + UtRegisterTest("PayloadTestSig14", PayloadTestSig14); + UtRegisterTest("PayloadTestSig15", PayloadTestSig15); + UtRegisterTest("PayloadTestSig16", PayloadTestSig16); + UtRegisterTest("PayloadTestSig17", PayloadTestSig17); + + UtRegisterTest("PayloadTestSig18", PayloadTestSig18); + UtRegisterTest("PayloadTestSig19", PayloadTestSig19); + UtRegisterTest("PayloadTestSig20", PayloadTestSig20); + UtRegisterTest("PayloadTestSig21", PayloadTestSig21); + UtRegisterTest("PayloadTestSig22", PayloadTestSig22); + UtRegisterTest("PayloadTestSig23", PayloadTestSig23); + UtRegisterTest("PayloadTestSig24", PayloadTestSig24); + UtRegisterTest("PayloadTestSig25", PayloadTestSig25); + UtRegisterTest("PayloadTestSig26", PayloadTestSig26); + UtRegisterTest("PayloadTestSig27", PayloadTestSig27); + UtRegisterTest("PayloadTestSig28", PayloadTestSig28); + UtRegisterTest("PayloadTestSig29", PayloadTestSig29); + + UtRegisterTest("PayloadTestSig30", PayloadTestSig30); + UtRegisterTest("PayloadTestSig31", PayloadTestSig31); + UtRegisterTest("PayloadTestSig32", PayloadTestSig32); + UtRegisterTest("PayloadTestSig33", PayloadTestSig33); + UtRegisterTest("PayloadTestSig34", PayloadTestSig34); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index e4d9008200d2..59fd2d08f444 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -2691,49 +2691,48 @@ static int PortTestMatchDoubleNegation(void) void DetectPortTests(void) { #ifdef UNITTESTS - UtRegisterTest("PortTestParse01", PortTestParse01, 1); - UtRegisterTest("PortTestParse02", PortTestParse02, 1); - UtRegisterTest("PortTestParse03", PortTestParse03, 1); - UtRegisterTest("PortTestParse04", PortTestParse04, 1); - UtRegisterTest("PortTestParse05", PortTestParse05, 1); - UtRegisterTest("PortTestParse06", PortTestParse06, 1); - UtRegisterTest("PortTestParse07", PortTestParse07, 1); - UtRegisterTest("PortTestParse08", PortTestParse08, 1); - UtRegisterTest("PortTestParse09", PortTestParse09, 1); - UtRegisterTest("PortTestParse10", PortTestParse10, 1); - UtRegisterTest("PortTestParse11", PortTestParse11, 1); - UtRegisterTest("PortTestParse12", PortTestParse12, 1); - UtRegisterTest("PortTestParse13", PortTestParse13, 1); - UtRegisterTest("PortTestParse14", PortTestParse14, 1); - UtRegisterTest("PortTestParse15", PortTestParse15, 1); - UtRegisterTest("PortTestParse16", PortTestParse16, 1); - UtRegisterTest("PortTestFunctions01", PortTestFunctions01, 1); - UtRegisterTest("PortTestFunctions02", PortTestFunctions02, 1); - UtRegisterTest("PortTestFunctions03", PortTestFunctions03, 1); - UtRegisterTest("PortTestFunctions04", PortTestFunctions04, 1); - UtRegisterTest("PortTestFunctions05", PortTestFunctions05, 1); - UtRegisterTest("PortTestFunctions06", PortTestFunctions06, 1); - UtRegisterTest("PortTestMatchReal01", PortTestMatchReal01, 1); - UtRegisterTest("PortTestMatchReal02", PortTestMatchReal02, 1); - UtRegisterTest("PortTestMatchReal03", PortTestMatchReal03, 1); - UtRegisterTest("PortTestMatchReal04", PortTestMatchReal04, 1); - UtRegisterTest("PortTestMatchReal05", PortTestMatchReal05, 1); - UtRegisterTest("PortTestMatchReal06", PortTestMatchReal06, 1); - UtRegisterTest("PortTestMatchReal07", PortTestMatchReal07, 1); - UtRegisterTest("PortTestMatchReal08", PortTestMatchReal08, 1); - UtRegisterTest("PortTestMatchReal09", PortTestMatchReal09, 1); - UtRegisterTest("PortTestMatchReal10", PortTestMatchReal10, 1); - UtRegisterTest("PortTestMatchReal11", PortTestMatchReal11, 1); - UtRegisterTest("PortTestMatchReal12", PortTestMatchReal12, 1); - UtRegisterTest("PortTestMatchReal13", PortTestMatchReal13, 1); - UtRegisterTest("PortTestMatchReal14", PortTestMatchReal14, 1); - UtRegisterTest("PortTestMatchReal15", PortTestMatchReal15, 1); - UtRegisterTest("PortTestMatchReal16", PortTestMatchReal16, 1); - UtRegisterTest("PortTestMatchReal17", PortTestMatchReal17, 1); - UtRegisterTest("PortTestMatchReal18", PortTestMatchReal18, 1); - UtRegisterTest("PortTestMatchReal19", - PortTestMatchReal19, 1); - UtRegisterTest("PortTestMatchDoubleNegation", PortTestMatchDoubleNegation, 1); + UtRegisterTest("PortTestParse01", PortTestParse01); + UtRegisterTest("PortTestParse02", PortTestParse02); + UtRegisterTest("PortTestParse03", PortTestParse03); + UtRegisterTest("PortTestParse04", PortTestParse04); + UtRegisterTest("PortTestParse05", PortTestParse05); + UtRegisterTest("PortTestParse06", PortTestParse06); + UtRegisterTest("PortTestParse07", PortTestParse07); + UtRegisterTest("PortTestParse08", PortTestParse08); + UtRegisterTest("PortTestParse09", PortTestParse09); + UtRegisterTest("PortTestParse10", PortTestParse10); + UtRegisterTest("PortTestParse11", PortTestParse11); + UtRegisterTest("PortTestParse12", PortTestParse12); + UtRegisterTest("PortTestParse13", PortTestParse13); + UtRegisterTest("PortTestParse14", PortTestParse14); + UtRegisterTest("PortTestParse15", PortTestParse15); + UtRegisterTest("PortTestParse16", PortTestParse16); + UtRegisterTest("PortTestFunctions01", PortTestFunctions01); + UtRegisterTest("PortTestFunctions02", PortTestFunctions02); + UtRegisterTest("PortTestFunctions03", PortTestFunctions03); + UtRegisterTest("PortTestFunctions04", PortTestFunctions04); + UtRegisterTest("PortTestFunctions05", PortTestFunctions05); + UtRegisterTest("PortTestFunctions06", PortTestFunctions06); + UtRegisterTest("PortTestMatchReal01", PortTestMatchReal01); + UtRegisterTest("PortTestMatchReal02", PortTestMatchReal02); + UtRegisterTest("PortTestMatchReal03", PortTestMatchReal03); + UtRegisterTest("PortTestMatchReal04", PortTestMatchReal04); + UtRegisterTest("PortTestMatchReal05", PortTestMatchReal05); + UtRegisterTest("PortTestMatchReal06", PortTestMatchReal06); + UtRegisterTest("PortTestMatchReal07", PortTestMatchReal07); + UtRegisterTest("PortTestMatchReal08", PortTestMatchReal08); + UtRegisterTest("PortTestMatchReal09", PortTestMatchReal09); + UtRegisterTest("PortTestMatchReal10", PortTestMatchReal10); + UtRegisterTest("PortTestMatchReal11", PortTestMatchReal11); + UtRegisterTest("PortTestMatchReal12", PortTestMatchReal12); + UtRegisterTest("PortTestMatchReal13", PortTestMatchReal13); + UtRegisterTest("PortTestMatchReal14", PortTestMatchReal14); + UtRegisterTest("PortTestMatchReal15", PortTestMatchReal15); + UtRegisterTest("PortTestMatchReal16", PortTestMatchReal16); + UtRegisterTest("PortTestMatchReal17", PortTestMatchReal17); + UtRegisterTest("PortTestMatchReal18", PortTestMatchReal18); + UtRegisterTest("PortTestMatchReal19", PortTestMatchReal19); + UtRegisterTest("PortTestMatchDoubleNegation", PortTestMatchDoubleNegation); #endif /* UNITTESTS */ diff --git a/src/detect-engine-proto.c b/src/detect-engine-proto.c index 54f26b721699..0d2d4193ee3d 100644 --- a/src/detect-engine-proto.c +++ b/src/detect-engine-proto.c @@ -609,19 +609,19 @@ static int DetectProtoTestSig02(void) void DetectProtoTests(void) { #ifdef UNITTESTS - UtRegisterTest("ProtoTestParse01", ProtoTestParse01, 1); - UtRegisterTest("ProtoTestParse02", ProtoTestParse02, 1); - UtRegisterTest("ProtoTestParse03", ProtoTestParse03, 1); - UtRegisterTest("ProtoTestParse04", ProtoTestParse04, 1); - UtRegisterTest("ProtoTestParse05", ProtoTestParse05, 1); - UtRegisterTest("ProtoTestParse06", ProtoTestParse06, 1); - UtRegisterTest("ProtoTestParse07", ProtoTestParse07, 1); - - UtRegisterTest("DetectProtoTestSetup01", DetectProtoTestSetup01, 1); - UtRegisterTest("DetectProtoTestSetup02", DetectProtoTestSetup02, 1); - - UtRegisterTest("DetectProtoTestSig01", DetectProtoTestSig01, 1); - UtRegisterTest("DetectProtoTestSig02", DetectProtoTestSig02, 1); + UtRegisterTest("ProtoTestParse01", ProtoTestParse01); + UtRegisterTest("ProtoTestParse02", ProtoTestParse02); + UtRegisterTest("ProtoTestParse03", ProtoTestParse03); + UtRegisterTest("ProtoTestParse04", ProtoTestParse04); + UtRegisterTest("ProtoTestParse05", ProtoTestParse05); + UtRegisterTest("ProtoTestParse06", ProtoTestParse06); + UtRegisterTest("ProtoTestParse07", ProtoTestParse07); + + UtRegisterTest("DetectProtoTestSetup01", DetectProtoTestSetup01); + UtRegisterTest("DetectProtoTestSetup02", DetectProtoTestSetup02); + + UtRegisterTest("DetectProtoTestSig01", DetectProtoTestSig01); + UtRegisterTest("DetectProtoTestSig02", DetectProtoTestSig02); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index b3b40ab127be..a55b53046863 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -1278,12 +1278,12 @@ static int SigGroupHeadTest11(void) void SigGroupHeadRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03, 1); - UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06, 1); - UtRegisterTest("SigGroupHeadTest07", SigGroupHeadTest07, 1); - UtRegisterTest("SigGroupHeadTest08", SigGroupHeadTest08, 1); - UtRegisterTest("SigGroupHeadTest09", SigGroupHeadTest09, 1); - UtRegisterTest("SigGroupHeadTest10", SigGroupHeadTest10, 1); - UtRegisterTest("SigGroupHeadTest11", SigGroupHeadTest11, 1); + UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03); + UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06); + UtRegisterTest("SigGroupHeadTest07", SigGroupHeadTest07); + UtRegisterTest("SigGroupHeadTest08", SigGroupHeadTest08); + UtRegisterTest("SigGroupHeadTest09", SigGroupHeadTest09); + UtRegisterTest("SigGroupHeadTest10", SigGroupHeadTest10); + UtRegisterTest("SigGroupHeadTest11", SigGroupHeadTest11); #endif } diff --git a/src/detect-engine-sigorder.c b/src/detect-engine-sigorder.c index 0baa87a22e0d..9e3d819fbc38 100644 --- a/src/detect-engine-sigorder.c +++ b/src/detect-engine-sigorder.c @@ -2184,18 +2184,18 @@ void SCSigRegisterSignatureOrderingTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCSigOrderingTest01", SCSigOrderingTest01, 1); - UtRegisterTest("SCSigOrderingTest02", SCSigOrderingTest02, 1); - UtRegisterTest("SCSigOrderingTest03", SCSigOrderingTest03, 1); - UtRegisterTest("SCSigOrderingTest04", SCSigOrderingTest04, 1); - UtRegisterTest("SCSigOrderingTest05", SCSigOrderingTest05, 1); - UtRegisterTest("SCSigOrderingTest06", SCSigOrderingTest06, 1); - UtRegisterTest("SCSigOrderingTest07", SCSigOrderingTest07, 1); - UtRegisterTest("SCSigOrderingTest08", SCSigOrderingTest08, 1); - UtRegisterTest("SCSigOrderingTest09", SCSigOrderingTest09, 1); - UtRegisterTest("SCSigOrderingTest10", SCSigOrderingTest10, 1); - UtRegisterTest("SCSigOrderingTest11", SCSigOrderingTest11, 1); - UtRegisterTest("SCSigOrderingTest12", SCSigOrderingTest12, 1); - UtRegisterTest("SCSigOrderingTest13", SCSigOrderingTest13, 1); + UtRegisterTest("SCSigOrderingTest01", SCSigOrderingTest01); + UtRegisterTest("SCSigOrderingTest02", SCSigOrderingTest02); + UtRegisterTest("SCSigOrderingTest03", SCSigOrderingTest03); + UtRegisterTest("SCSigOrderingTest04", SCSigOrderingTest04); + UtRegisterTest("SCSigOrderingTest05", SCSigOrderingTest05); + UtRegisterTest("SCSigOrderingTest06", SCSigOrderingTest06); + UtRegisterTest("SCSigOrderingTest07", SCSigOrderingTest07); + UtRegisterTest("SCSigOrderingTest08", SCSigOrderingTest08); + UtRegisterTest("SCSigOrderingTest09", SCSigOrderingTest09); + UtRegisterTest("SCSigOrderingTest10", SCSigOrderingTest10); + UtRegisterTest("SCSigOrderingTest11", SCSigOrderingTest11); + UtRegisterTest("SCSigOrderingTest12", SCSigOrderingTest12); + UtRegisterTest("SCSigOrderingTest13", SCSigOrderingTest13); #endif } diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 05ca25d57fc7..b465917a18af 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -2326,16 +2326,16 @@ static int DeStateSigTest07(void) void DeStateRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DeStateTest01", DeStateTest01, 1); - UtRegisterTest("DeStateTest02", DeStateTest02, 1); - UtRegisterTest("DeStateTest03", DeStateTest03, 1); - UtRegisterTest("DeStateSigTest01", DeStateSigTest01, 1); - UtRegisterTest("DeStateSigTest02", DeStateSigTest02, 1); - UtRegisterTest("DeStateSigTest03", DeStateSigTest03, 1); - UtRegisterTest("DeStateSigTest04", DeStateSigTest04, 1); - UtRegisterTest("DeStateSigTest05", DeStateSigTest05, 1); - UtRegisterTest("DeStateSigTest06", DeStateSigTest06, 1); - UtRegisterTest("DeStateSigTest07", DeStateSigTest07, 1); + UtRegisterTest("DeStateTest01", DeStateTest01); + UtRegisterTest("DeStateTest02", DeStateTest02); + UtRegisterTest("DeStateTest03", DeStateTest03); + UtRegisterTest("DeStateSigTest01", DeStateSigTest01); + UtRegisterTest("DeStateSigTest02", DeStateSigTest02); + UtRegisterTest("DeStateSigTest03", DeStateSigTest03); + UtRegisterTest("DeStateSigTest04", DeStateSigTest04); + UtRegisterTest("DeStateSigTest05", DeStateSigTest05); + UtRegisterTest("DeStateSigTest06", DeStateSigTest06); + UtRegisterTest("DeStateSigTest07", DeStateSigTest07); #endif return; diff --git a/src/detect-engine-tag.c b/src/detect-engine-tag.c index 7c8caabba082..0eb90a228566 100644 --- a/src/detect-engine-tag.c +++ b/src/detect-engine-tag.c @@ -1507,13 +1507,13 @@ static int DetectTagTestPacket07 (void) void DetectEngineTagRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectTagTestPacket01", DetectTagTestPacket01, 1); - UtRegisterTest("DetectTagTestPacket02", DetectTagTestPacket02, 1); - UtRegisterTest("DetectTagTestPacket03", DetectTagTestPacket03, 1); - UtRegisterTest("DetectTagTestPacket04", DetectTagTestPacket04, 1); - UtRegisterTest("DetectTagTestPacket05", DetectTagTestPacket05, 1); - UtRegisterTest("DetectTagTestPacket06", DetectTagTestPacket06, 1); - UtRegisterTest("DetectTagTestPacket07", DetectTagTestPacket07, 1); + UtRegisterTest("DetectTagTestPacket01", DetectTagTestPacket01); + UtRegisterTest("DetectTagTestPacket02", DetectTagTestPacket02); + UtRegisterTest("DetectTagTestPacket03", DetectTagTestPacket03); + UtRegisterTest("DetectTagTestPacket04", DetectTagTestPacket04); + UtRegisterTest("DetectTagTestPacket05", DetectTagTestPacket05); + UtRegisterTest("DetectTagTestPacket06", DetectTagTestPacket06); + UtRegisterTest("DetectTagTestPacket07", DetectTagTestPacket07); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index e88b8d7e234b..81504bcb669b 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -4203,45 +4203,45 @@ void UriRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("UriTestSig01", UriTestSig01, 1); - UtRegisterTest("UriTestSig02", UriTestSig02, 1); - UtRegisterTest("UriTestSig03", UriTestSig03, 1); - UtRegisterTest("UriTestSig04", UriTestSig04, 1); - UtRegisterTest("UriTestSig05", UriTestSig05, 1); - UtRegisterTest("UriTestSig06", UriTestSig06, 1); - UtRegisterTest("UriTestSig07", UriTestSig07, 1); - UtRegisterTest("UriTestSig08", UriTestSig08, 1); - UtRegisterTest("UriTestSig09", UriTestSig09, 1); - UtRegisterTest("UriTestSig10", UriTestSig10, 1); - UtRegisterTest("UriTestSig11", UriTestSig11, 1); - UtRegisterTest("UriTestSig12", UriTestSig12, 1); - UtRegisterTest("UriTestSig13", UriTestSig13, 1); - UtRegisterTest("UriTestSig14", UriTestSig14, 1); - UtRegisterTest("UriTestSig15", UriTestSig15, 1); - UtRegisterTest("UriTestSig16", UriTestSig16, 1); - UtRegisterTest("UriTestSig17", UriTestSig17, 1); - UtRegisterTest("UriTestSig18", UriTestSig18, 1); - UtRegisterTest("UriTestSig19", UriTestSig19, 1); - UtRegisterTest("UriTestSig20", UriTestSig20, 1); - UtRegisterTest("UriTestSig21", UriTestSig21, 1); - UtRegisterTest("UriTestSig22", UriTestSig22, 1); - UtRegisterTest("UriTestSig23", UriTestSig23, 1); - UtRegisterTest("UriTestSig24", UriTestSig24, 1); - UtRegisterTest("UriTestSig25", UriTestSig25, 1); - UtRegisterTest("UriTestSig26", UriTestSig26, 1); - UtRegisterTest("UriTestSig27", UriTestSig27, 1); - - UtRegisterTest("UriTestSig28", UriTestSig28, 1); - UtRegisterTest("UriTestSig29", UriTestSig29, 1); - UtRegisterTest("UriTestSig30", UriTestSig30, 1); - UtRegisterTest("UriTestSig31", UriTestSig31, 1); - UtRegisterTest("UriTestSig32", UriTestSig32, 1); - UtRegisterTest("UriTestSig33", UriTestSig33, 1); - UtRegisterTest("UriTestSig34", UriTestSig34, 1); - UtRegisterTest("UriTestSig35", UriTestSig35, 1); - UtRegisterTest("UriTestSig36", UriTestSig36, 1); - UtRegisterTest("UriTestSig37", UriTestSig37, 1); - UtRegisterTest("UriTestSig38", UriTestSig38, 1); + UtRegisterTest("UriTestSig01", UriTestSig01); + UtRegisterTest("UriTestSig02", UriTestSig02); + UtRegisterTest("UriTestSig03", UriTestSig03); + UtRegisterTest("UriTestSig04", UriTestSig04); + UtRegisterTest("UriTestSig05", UriTestSig05); + UtRegisterTest("UriTestSig06", UriTestSig06); + UtRegisterTest("UriTestSig07", UriTestSig07); + UtRegisterTest("UriTestSig08", UriTestSig08); + UtRegisterTest("UriTestSig09", UriTestSig09); + UtRegisterTest("UriTestSig10", UriTestSig10); + UtRegisterTest("UriTestSig11", UriTestSig11); + UtRegisterTest("UriTestSig12", UriTestSig12); + UtRegisterTest("UriTestSig13", UriTestSig13); + UtRegisterTest("UriTestSig14", UriTestSig14); + UtRegisterTest("UriTestSig15", UriTestSig15); + UtRegisterTest("UriTestSig16", UriTestSig16); + UtRegisterTest("UriTestSig17", UriTestSig17); + UtRegisterTest("UriTestSig18", UriTestSig18); + UtRegisterTest("UriTestSig19", UriTestSig19); + UtRegisterTest("UriTestSig20", UriTestSig20); + UtRegisterTest("UriTestSig21", UriTestSig21); + UtRegisterTest("UriTestSig22", UriTestSig22); + UtRegisterTest("UriTestSig23", UriTestSig23); + UtRegisterTest("UriTestSig24", UriTestSig24); + UtRegisterTest("UriTestSig25", UriTestSig25); + UtRegisterTest("UriTestSig26", UriTestSig26); + UtRegisterTest("UriTestSig27", UriTestSig27); + + UtRegisterTest("UriTestSig28", UriTestSig28); + UtRegisterTest("UriTestSig29", UriTestSig29); + UtRegisterTest("UriTestSig30", UriTestSig30); + UtRegisterTest("UriTestSig31", UriTestSig31); + UtRegisterTest("UriTestSig32", UriTestSig32); + UtRegisterTest("UriTestSig33", UriTestSig33); + UtRegisterTest("UriTestSig34", UriTestSig34); + UtRegisterTest("UriTestSig35", UriTestSig35); + UtRegisterTest("UriTestSig36", UriTestSig36); + UtRegisterTest("UriTestSig37", UriTestSig37); + UtRegisterTest("UriTestSig38", UriTestSig38); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine.c b/src/detect-engine.c index fb06a7c0f35b..37dc6245d1ed 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -3272,15 +3272,15 @@ void DetectEngineRegisterTests() { #ifdef UNITTESTS - UtRegisterTest("DetectEngineTest01", DetectEngineTest01, 1); - UtRegisterTest("DetectEngineTest02", DetectEngineTest02, 1); - UtRegisterTest("DetectEngineTest03", DetectEngineTest03, 1); - UtRegisterTest("DetectEngineTest04", DetectEngineTest04, 1); - UtRegisterTest("DetectEngineTest05", DetectEngineTest05, 1); - UtRegisterTest("DetectEngineTest06", DetectEngineTest06, 1); - UtRegisterTest("DetectEngineTest07", DetectEngineTest07, 1); - UtRegisterTest("DetectEngineTest08", DetectEngineTest08, 1); - UtRegisterTest("DetectEngineTest09", DetectEngineTest09, 1); + UtRegisterTest("DetectEngineTest01", DetectEngineTest01); + UtRegisterTest("DetectEngineTest02", DetectEngineTest02); + UtRegisterTest("DetectEngineTest03", DetectEngineTest03); + UtRegisterTest("DetectEngineTest04", DetectEngineTest04); + UtRegisterTest("DetectEngineTest05", DetectEngineTest05); + UtRegisterTest("DetectEngineTest06", DetectEngineTest06); + UtRegisterTest("DetectEngineTest07", DetectEngineTest07); + UtRegisterTest("DetectEngineTest08", DetectEngineTest08); + UtRegisterTest("DetectEngineTest09", DetectEngineTest09); #endif return; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 27598ee458b1..99fb409c0387 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -19439,708 +19439,708 @@ void DetectFastPatternRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01, 1); - UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02, 1); - UtRegisterTest("DetectFastPatternTest03", DetectFastPatternTest03, 1); - UtRegisterTest("DetectFastPatternTest04", DetectFastPatternTest04, 1); - UtRegisterTest("DetectFastPatternTest05", DetectFastPatternTest05, 1); - UtRegisterTest("DetectFastPatternTest06", DetectFastPatternTest06, 1); - UtRegisterTest("DetectFastPatternTest07", DetectFastPatternTest07, 1); - UtRegisterTest("DetectFastPatternTest08", DetectFastPatternTest08, 1); - UtRegisterTest("DetectFastPatternTest09", DetectFastPatternTest09, 1); - UtRegisterTest("DetectFastPatternTest10", DetectFastPatternTest10, 1); - UtRegisterTest("DetectFastPatternTest11", DetectFastPatternTest11, 1); - UtRegisterTest("DetectFastPatternTest12", DetectFastPatternTest12, 1); - UtRegisterTest("DetectFastPatternTest13", DetectFastPatternTest13, 1); - UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14, 1); - UtRegisterTest("DetectFastPatternTest15", DetectFastPatternTest15, 1); - UtRegisterTest("DetectFastPatternTest16", DetectFastPatternTest16, 1); - UtRegisterTest("DetectFastPatternTest17", DetectFastPatternTest17, 1); - UtRegisterTest("DetectFastPatternTest18", DetectFastPatternTest18, 1); - UtRegisterTest("DetectFastPatternTest19", DetectFastPatternTest19, 1); - UtRegisterTest("DetectFastPatternTest20", DetectFastPatternTest20, 1); - UtRegisterTest("DetectFastPatternTest21", DetectFastPatternTest21, 1); - UtRegisterTest("DetectFastPatternTest22", DetectFastPatternTest22, 1); - UtRegisterTest("DetectFastPatternTest23", DetectFastPatternTest23, 1); - UtRegisterTest("DetectFastPatternTest24", DetectFastPatternTest24, 1); - UtRegisterTest("DetectFastPatternTest25", DetectFastPatternTest25, 1); - UtRegisterTest("DetectFastPatternTest26", DetectFastPatternTest26, 1); - UtRegisterTest("DetectFastPatternTest27", DetectFastPatternTest27, 1); - UtRegisterTest("DetectFastPatternTest28", DetectFastPatternTest28, 1); - UtRegisterTest("DetectFastPatternTest29", DetectFastPatternTest29, 1); - UtRegisterTest("DetectFastPatternTest30", DetectFastPatternTest30, 1); - UtRegisterTest("DetectFastPatternTest31", DetectFastPatternTest31, 1); - UtRegisterTest("DetectFastPatternTest32", DetectFastPatternTest32, 1); - UtRegisterTest("DetectFastPatternTest33", DetectFastPatternTest33, 1); - UtRegisterTest("DetectFastPatternTest34", DetectFastPatternTest34, 1); - UtRegisterTest("DetectFastPatternTest35", DetectFastPatternTest35, 1); - UtRegisterTest("DetectFastPatternTest36", DetectFastPatternTest36, 1); - UtRegisterTest("DetectFastPatternTest37", DetectFastPatternTest37, 1); - UtRegisterTest("DetectFastPatternTest38", DetectFastPatternTest38, 1); - UtRegisterTest("DetectFastPatternTest39", DetectFastPatternTest39, 1); - UtRegisterTest("DetectFastPatternTest40", DetectFastPatternTest40, 1); - UtRegisterTest("DetectFastPatternTest41", DetectFastPatternTest41, 1); - UtRegisterTest("DetectFastPatternTest42", DetectFastPatternTest42, 1); - UtRegisterTest("DetectFastPatternTest43", DetectFastPatternTest43, 1); - UtRegisterTest("DetectFastPatternTest44", DetectFastPatternTest44, 1); - UtRegisterTest("DetectFastPatternTest45", DetectFastPatternTest45, 1); - UtRegisterTest("DetectFastPatternTest46", DetectFastPatternTest46, 1); - UtRegisterTest("DetectFastPatternTest47", DetectFastPatternTest47, 1); - UtRegisterTest("DetectFastPatternTest48", DetectFastPatternTest48, 1); - UtRegisterTest("DetectFastPatternTest49", DetectFastPatternTest49, 1); - UtRegisterTest("DetectFastPatternTest50", DetectFastPatternTest50, 1); - UtRegisterTest("DetectFastPatternTest51", DetectFastPatternTest51, 1); - UtRegisterTest("DetectFastPatternTest52", DetectFastPatternTest52, 1); - UtRegisterTest("DetectFastPatternTest53", DetectFastPatternTest53, 1); + UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); + UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); + UtRegisterTest("DetectFastPatternTest03", DetectFastPatternTest03); + UtRegisterTest("DetectFastPatternTest04", DetectFastPatternTest04); + UtRegisterTest("DetectFastPatternTest05", DetectFastPatternTest05); + UtRegisterTest("DetectFastPatternTest06", DetectFastPatternTest06); + UtRegisterTest("DetectFastPatternTest07", DetectFastPatternTest07); + UtRegisterTest("DetectFastPatternTest08", DetectFastPatternTest08); + UtRegisterTest("DetectFastPatternTest09", DetectFastPatternTest09); + UtRegisterTest("DetectFastPatternTest10", DetectFastPatternTest10); + UtRegisterTest("DetectFastPatternTest11", DetectFastPatternTest11); + UtRegisterTest("DetectFastPatternTest12", DetectFastPatternTest12); + UtRegisterTest("DetectFastPatternTest13", DetectFastPatternTest13); + UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14); + UtRegisterTest("DetectFastPatternTest15", DetectFastPatternTest15); + UtRegisterTest("DetectFastPatternTest16", DetectFastPatternTest16); + UtRegisterTest("DetectFastPatternTest17", DetectFastPatternTest17); + UtRegisterTest("DetectFastPatternTest18", DetectFastPatternTest18); + UtRegisterTest("DetectFastPatternTest19", DetectFastPatternTest19); + UtRegisterTest("DetectFastPatternTest20", DetectFastPatternTest20); + UtRegisterTest("DetectFastPatternTest21", DetectFastPatternTest21); + UtRegisterTest("DetectFastPatternTest22", DetectFastPatternTest22); + UtRegisterTest("DetectFastPatternTest23", DetectFastPatternTest23); + UtRegisterTest("DetectFastPatternTest24", DetectFastPatternTest24); + UtRegisterTest("DetectFastPatternTest25", DetectFastPatternTest25); + UtRegisterTest("DetectFastPatternTest26", DetectFastPatternTest26); + UtRegisterTest("DetectFastPatternTest27", DetectFastPatternTest27); + UtRegisterTest("DetectFastPatternTest28", DetectFastPatternTest28); + UtRegisterTest("DetectFastPatternTest29", DetectFastPatternTest29); + UtRegisterTest("DetectFastPatternTest30", DetectFastPatternTest30); + UtRegisterTest("DetectFastPatternTest31", DetectFastPatternTest31); + UtRegisterTest("DetectFastPatternTest32", DetectFastPatternTest32); + UtRegisterTest("DetectFastPatternTest33", DetectFastPatternTest33); + UtRegisterTest("DetectFastPatternTest34", DetectFastPatternTest34); + UtRegisterTest("DetectFastPatternTest35", DetectFastPatternTest35); + UtRegisterTest("DetectFastPatternTest36", DetectFastPatternTest36); + UtRegisterTest("DetectFastPatternTest37", DetectFastPatternTest37); + UtRegisterTest("DetectFastPatternTest38", DetectFastPatternTest38); + UtRegisterTest("DetectFastPatternTest39", DetectFastPatternTest39); + UtRegisterTest("DetectFastPatternTest40", DetectFastPatternTest40); + UtRegisterTest("DetectFastPatternTest41", DetectFastPatternTest41); + UtRegisterTest("DetectFastPatternTest42", DetectFastPatternTest42); + UtRegisterTest("DetectFastPatternTest43", DetectFastPatternTest43); + UtRegisterTest("DetectFastPatternTest44", DetectFastPatternTest44); + UtRegisterTest("DetectFastPatternTest45", DetectFastPatternTest45); + UtRegisterTest("DetectFastPatternTest46", DetectFastPatternTest46); + UtRegisterTest("DetectFastPatternTest47", DetectFastPatternTest47); + UtRegisterTest("DetectFastPatternTest48", DetectFastPatternTest48); + UtRegisterTest("DetectFastPatternTest49", DetectFastPatternTest49); + UtRegisterTest("DetectFastPatternTest50", DetectFastPatternTest50); + UtRegisterTest("DetectFastPatternTest51", DetectFastPatternTest51); + UtRegisterTest("DetectFastPatternTest52", DetectFastPatternTest52); + UtRegisterTest("DetectFastPatternTest53", DetectFastPatternTest53); /* content fast_pattern tests ^ */ /* uricontent fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest54", DetectFastPatternTest54, 1); - UtRegisterTest("DetectFastPatternTest55", DetectFastPatternTest55, 1); - UtRegisterTest("DetectFastPatternTest56", DetectFastPatternTest56, 1); - UtRegisterTest("DetectFastPatternTest57", DetectFastPatternTest57, 1); - UtRegisterTest("DetectFastPatternTest58", DetectFastPatternTest58, 1); - UtRegisterTest("DetectFastPatternTest59", DetectFastPatternTest59, 1); - UtRegisterTest("DetectFastPatternTest60", DetectFastPatternTest60, 1); - UtRegisterTest("DetectFastPatternTest61", DetectFastPatternTest61, 1); - UtRegisterTest("DetectFastPatternTest62", DetectFastPatternTest62, 1); - UtRegisterTest("DetectFastPatternTest63", DetectFastPatternTest63, 1); - UtRegisterTest("DetectFastPatternTest64", DetectFastPatternTest64, 1); - UtRegisterTest("DetectFastPatternTest65", DetectFastPatternTest65, 1); - UtRegisterTest("DetectFastPatternTest66", DetectFastPatternTest66, 1); - UtRegisterTest("DetectFastPatternTest67", DetectFastPatternTest67, 1); - UtRegisterTest("DetectFastPatternTest68", DetectFastPatternTest68, 1); - UtRegisterTest("DetectFastPatternTest69", DetectFastPatternTest69, 1); - UtRegisterTest("DetectFastPatternTest70", DetectFastPatternTest70, 1); - UtRegisterTest("DetectFastPatternTest71", DetectFastPatternTest71, 1); - UtRegisterTest("DetectFastPatternTest72", DetectFastPatternTest72, 1); - UtRegisterTest("DetectFastPatternTest73", DetectFastPatternTest73, 1); - UtRegisterTest("DetectFastPatternTest74", DetectFastPatternTest74, 1); - UtRegisterTest("DetectFastPatternTest75", DetectFastPatternTest75, 1); - UtRegisterTest("DetectFastPatternTest76", DetectFastPatternTest76, 1); - UtRegisterTest("DetectFastPatternTest77", DetectFastPatternTest77, 1); - UtRegisterTest("DetectFastPatternTest78", DetectFastPatternTest78, 1); - UtRegisterTest("DetectFastPatternTest79", DetectFastPatternTest79, 1); - UtRegisterTest("DetectFastPatternTest80", DetectFastPatternTest80, 1); - UtRegisterTest("DetectFastPatternTest81", DetectFastPatternTest81, 1); - UtRegisterTest("DetectFastPatternTest82", DetectFastPatternTest82, 1); - UtRegisterTest("DetectFastPatternTest83", DetectFastPatternTest83, 1); - UtRegisterTest("DetectFastPatternTest84", DetectFastPatternTest84, 1); - UtRegisterTest("DetectFastPatternTest85", DetectFastPatternTest85, 1); - UtRegisterTest("DetectFastPatternTest86", DetectFastPatternTest86, 1); - UtRegisterTest("DetectFastPatternTest87", DetectFastPatternTest87, 1); - UtRegisterTest("DetectFastPatternTest88", DetectFastPatternTest88, 1); - UtRegisterTest("DetectFastPatternTest89", DetectFastPatternTest89, 1); - UtRegisterTest("DetectFastPatternTest90", DetectFastPatternTest90, 1); - UtRegisterTest("DetectFastPatternTest91", DetectFastPatternTest91, 1); - UtRegisterTest("DetectFastPatternTest92", DetectFastPatternTest92, 1); + UtRegisterTest("DetectFastPatternTest54", DetectFastPatternTest54); + UtRegisterTest("DetectFastPatternTest55", DetectFastPatternTest55); + UtRegisterTest("DetectFastPatternTest56", DetectFastPatternTest56); + UtRegisterTest("DetectFastPatternTest57", DetectFastPatternTest57); + UtRegisterTest("DetectFastPatternTest58", DetectFastPatternTest58); + UtRegisterTest("DetectFastPatternTest59", DetectFastPatternTest59); + UtRegisterTest("DetectFastPatternTest60", DetectFastPatternTest60); + UtRegisterTest("DetectFastPatternTest61", DetectFastPatternTest61); + UtRegisterTest("DetectFastPatternTest62", DetectFastPatternTest62); + UtRegisterTest("DetectFastPatternTest63", DetectFastPatternTest63); + UtRegisterTest("DetectFastPatternTest64", DetectFastPatternTest64); + UtRegisterTest("DetectFastPatternTest65", DetectFastPatternTest65); + UtRegisterTest("DetectFastPatternTest66", DetectFastPatternTest66); + UtRegisterTest("DetectFastPatternTest67", DetectFastPatternTest67); + UtRegisterTest("DetectFastPatternTest68", DetectFastPatternTest68); + UtRegisterTest("DetectFastPatternTest69", DetectFastPatternTest69); + UtRegisterTest("DetectFastPatternTest70", DetectFastPatternTest70); + UtRegisterTest("DetectFastPatternTest71", DetectFastPatternTest71); + UtRegisterTest("DetectFastPatternTest72", DetectFastPatternTest72); + UtRegisterTest("DetectFastPatternTest73", DetectFastPatternTest73); + UtRegisterTest("DetectFastPatternTest74", DetectFastPatternTest74); + UtRegisterTest("DetectFastPatternTest75", DetectFastPatternTest75); + UtRegisterTest("DetectFastPatternTest76", DetectFastPatternTest76); + UtRegisterTest("DetectFastPatternTest77", DetectFastPatternTest77); + UtRegisterTest("DetectFastPatternTest78", DetectFastPatternTest78); + UtRegisterTest("DetectFastPatternTest79", DetectFastPatternTest79); + UtRegisterTest("DetectFastPatternTest80", DetectFastPatternTest80); + UtRegisterTest("DetectFastPatternTest81", DetectFastPatternTest81); + UtRegisterTest("DetectFastPatternTest82", DetectFastPatternTest82); + UtRegisterTest("DetectFastPatternTest83", DetectFastPatternTest83); + UtRegisterTest("DetectFastPatternTest84", DetectFastPatternTest84); + UtRegisterTest("DetectFastPatternTest85", DetectFastPatternTest85); + UtRegisterTest("DetectFastPatternTest86", DetectFastPatternTest86); + UtRegisterTest("DetectFastPatternTest87", DetectFastPatternTest87); + UtRegisterTest("DetectFastPatternTest88", DetectFastPatternTest88); + UtRegisterTest("DetectFastPatternTest89", DetectFastPatternTest89); + UtRegisterTest("DetectFastPatternTest90", DetectFastPatternTest90); + UtRegisterTest("DetectFastPatternTest91", DetectFastPatternTest91); + UtRegisterTest("DetectFastPatternTest92", DetectFastPatternTest92); /* uricontent fast_pattern tests ^ */ /* http_uri fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest93", DetectFastPatternTest93, 1); - UtRegisterTest("DetectFastPatternTest94", DetectFastPatternTest94, 1); - UtRegisterTest("DetectFastPatternTest95", DetectFastPatternTest95, 1); - UtRegisterTest("DetectFastPatternTest96", DetectFastPatternTest96, 1); - UtRegisterTest("DetectFastPatternTest97", DetectFastPatternTest97, 1); - UtRegisterTest("DetectFastPatternTest98", DetectFastPatternTest98, 1); - UtRegisterTest("DetectFastPatternTest99", DetectFastPatternTest99, 1); - UtRegisterTest("DetectFastPatternTest100", DetectFastPatternTest100, 1); - UtRegisterTest("DetectFastPatternTest101", DetectFastPatternTest101, 1); - UtRegisterTest("DetectFastPatternTest102", DetectFastPatternTest102, 1); - UtRegisterTest("DetectFastPatternTest103", DetectFastPatternTest103, 1); - UtRegisterTest("DetectFastPatternTest104", DetectFastPatternTest104, 1); - UtRegisterTest("DetectFastPatternTest105", DetectFastPatternTest105, 1); - UtRegisterTest("DetectFastPatternTest106", DetectFastPatternTest106, 1); - UtRegisterTest("DetectFastPatternTest107", DetectFastPatternTest107, 1); - UtRegisterTest("DetectFastPatternTest108", DetectFastPatternTest108, 1); - UtRegisterTest("DetectFastPatternTest109", DetectFastPatternTest109, 1); - UtRegisterTest("DetectFastPatternTest110", DetectFastPatternTest110, 1); - UtRegisterTest("DetectFastPatternTest111", DetectFastPatternTest111, 1); - UtRegisterTest("DetectFastPatternTest112", DetectFastPatternTest112, 1); - UtRegisterTest("DetectFastPatternTest113", DetectFastPatternTest113, 1); - UtRegisterTest("DetectFastPatternTest114", DetectFastPatternTest114, 1); - UtRegisterTest("DetectFastPatternTest115", DetectFastPatternTest115, 1); - UtRegisterTest("DetectFastPatternTest116", DetectFastPatternTest116, 1); - UtRegisterTest("DetectFastPatternTest117", DetectFastPatternTest117, 1); - UtRegisterTest("DetectFastPatternTest118", DetectFastPatternTest118, 1); - UtRegisterTest("DetectFastPatternTest119", DetectFastPatternTest119, 1); - UtRegisterTest("DetectFastPatternTest120", DetectFastPatternTest120, 1); - UtRegisterTest("DetectFastPatternTest121", DetectFastPatternTest121, 1); - UtRegisterTest("DetectFastPatternTest122", DetectFastPatternTest122, 1); - UtRegisterTest("DetectFastPatternTest123", DetectFastPatternTest123, 1); - UtRegisterTest("DetectFastPatternTest124", DetectFastPatternTest124, 1); - UtRegisterTest("DetectFastPatternTest125", DetectFastPatternTest125, 1); - UtRegisterTest("DetectFastPatternTest126", DetectFastPatternTest126, 1); - UtRegisterTest("DetectFastPatternTest127", DetectFastPatternTest127, 1); - UtRegisterTest("DetectFastPatternTest128", DetectFastPatternTest128, 1); - UtRegisterTest("DetectFastPatternTest129", DetectFastPatternTest129, 1); - UtRegisterTest("DetectFastPatternTest130", DetectFastPatternTest130, 1); - UtRegisterTest("DetectFastPatternTest131", DetectFastPatternTest131, 1); - UtRegisterTest("DetectFastPatternTest132", DetectFastPatternTest132, 1); - UtRegisterTest("DetectFastPatternTest133", DetectFastPatternTest133, 1); + UtRegisterTest("DetectFastPatternTest93", DetectFastPatternTest93); + UtRegisterTest("DetectFastPatternTest94", DetectFastPatternTest94); + UtRegisterTest("DetectFastPatternTest95", DetectFastPatternTest95); + UtRegisterTest("DetectFastPatternTest96", DetectFastPatternTest96); + UtRegisterTest("DetectFastPatternTest97", DetectFastPatternTest97); + UtRegisterTest("DetectFastPatternTest98", DetectFastPatternTest98); + UtRegisterTest("DetectFastPatternTest99", DetectFastPatternTest99); + UtRegisterTest("DetectFastPatternTest100", DetectFastPatternTest100); + UtRegisterTest("DetectFastPatternTest101", DetectFastPatternTest101); + UtRegisterTest("DetectFastPatternTest102", DetectFastPatternTest102); + UtRegisterTest("DetectFastPatternTest103", DetectFastPatternTest103); + UtRegisterTest("DetectFastPatternTest104", DetectFastPatternTest104); + UtRegisterTest("DetectFastPatternTest105", DetectFastPatternTest105); + UtRegisterTest("DetectFastPatternTest106", DetectFastPatternTest106); + UtRegisterTest("DetectFastPatternTest107", DetectFastPatternTest107); + UtRegisterTest("DetectFastPatternTest108", DetectFastPatternTest108); + UtRegisterTest("DetectFastPatternTest109", DetectFastPatternTest109); + UtRegisterTest("DetectFastPatternTest110", DetectFastPatternTest110); + UtRegisterTest("DetectFastPatternTest111", DetectFastPatternTest111); + UtRegisterTest("DetectFastPatternTest112", DetectFastPatternTest112); + UtRegisterTest("DetectFastPatternTest113", DetectFastPatternTest113); + UtRegisterTest("DetectFastPatternTest114", DetectFastPatternTest114); + UtRegisterTest("DetectFastPatternTest115", DetectFastPatternTest115); + UtRegisterTest("DetectFastPatternTest116", DetectFastPatternTest116); + UtRegisterTest("DetectFastPatternTest117", DetectFastPatternTest117); + UtRegisterTest("DetectFastPatternTest118", DetectFastPatternTest118); + UtRegisterTest("DetectFastPatternTest119", DetectFastPatternTest119); + UtRegisterTest("DetectFastPatternTest120", DetectFastPatternTest120); + UtRegisterTest("DetectFastPatternTest121", DetectFastPatternTest121); + UtRegisterTest("DetectFastPatternTest122", DetectFastPatternTest122); + UtRegisterTest("DetectFastPatternTest123", DetectFastPatternTest123); + UtRegisterTest("DetectFastPatternTest124", DetectFastPatternTest124); + UtRegisterTest("DetectFastPatternTest125", DetectFastPatternTest125); + UtRegisterTest("DetectFastPatternTest126", DetectFastPatternTest126); + UtRegisterTest("DetectFastPatternTest127", DetectFastPatternTest127); + UtRegisterTest("DetectFastPatternTest128", DetectFastPatternTest128); + UtRegisterTest("DetectFastPatternTest129", DetectFastPatternTest129); + UtRegisterTest("DetectFastPatternTest130", DetectFastPatternTest130); + UtRegisterTest("DetectFastPatternTest131", DetectFastPatternTest131); + UtRegisterTest("DetectFastPatternTest132", DetectFastPatternTest132); + UtRegisterTest("DetectFastPatternTest133", DetectFastPatternTest133); /* http_uri fast_pattern tests ^ */ /* http_client_body fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest134", DetectFastPatternTest134, 1); - UtRegisterTest("DetectFastPatternTest135", DetectFastPatternTest135, 1); - UtRegisterTest("DetectFastPatternTest136", DetectFastPatternTest136, 1); - UtRegisterTest("DetectFastPatternTest137", DetectFastPatternTest137, 1); - UtRegisterTest("DetectFastPatternTest138", DetectFastPatternTest138, 1); - UtRegisterTest("DetectFastPatternTest139", DetectFastPatternTest139, 1); - UtRegisterTest("DetectFastPatternTest140", DetectFastPatternTest140, 1); - UtRegisterTest("DetectFastPatternTest141", DetectFastPatternTest141, 1); - UtRegisterTest("DetectFastPatternTest142", DetectFastPatternTest142, 1); - UtRegisterTest("DetectFastPatternTest143", DetectFastPatternTest143, 1); - UtRegisterTest("DetectFastPatternTest144", DetectFastPatternTest144, 1); - UtRegisterTest("DetectFastPatternTest145", DetectFastPatternTest145, 1); - UtRegisterTest("DetectFastPatternTest146", DetectFastPatternTest146, 1); - UtRegisterTest("DetectFastPatternTest147", DetectFastPatternTest147, 1); - UtRegisterTest("DetectFastPatternTest148", DetectFastPatternTest148, 1); - UtRegisterTest("DetectFastPatternTest149", DetectFastPatternTest149, 1); - UtRegisterTest("DetectFastPatternTest150", DetectFastPatternTest150, 1); - UtRegisterTest("DetectFastPatternTest151", DetectFastPatternTest151, 1); - UtRegisterTest("DetectFastPatternTest152", DetectFastPatternTest152, 1); - UtRegisterTest("DetectFastPatternTest153", DetectFastPatternTest153, 1); - UtRegisterTest("DetectFastPatternTest154", DetectFastPatternTest154, 1); - UtRegisterTest("DetectFastPatternTest155", DetectFastPatternTest155, 1); - UtRegisterTest("DetectFastPatternTest156", DetectFastPatternTest156, 1); - UtRegisterTest("DetectFastPatternTest157", DetectFastPatternTest157, 1); - UtRegisterTest("DetectFastPatternTest158", DetectFastPatternTest158, 1); - UtRegisterTest("DetectFastPatternTest159", DetectFastPatternTest159, 1); - UtRegisterTest("DetectFastPatternTest160", DetectFastPatternTest160, 1); - UtRegisterTest("DetectFastPatternTest161", DetectFastPatternTest161, 1); - UtRegisterTest("DetectFastPatternTest162", DetectFastPatternTest162, 1); - UtRegisterTest("DetectFastPatternTest163", DetectFastPatternTest163, 1); - UtRegisterTest("DetectFastPatternTest164", DetectFastPatternTest164, 1); - UtRegisterTest("DetectFastPatternTest165", DetectFastPatternTest165, 1); - UtRegisterTest("DetectFastPatternTest166", DetectFastPatternTest166, 1); - UtRegisterTest("DetectFastPatternTest167", DetectFastPatternTest167, 1); - UtRegisterTest("DetectFastPatternTest168", DetectFastPatternTest168, 1); - UtRegisterTest("DetectFastPatternTest169", DetectFastPatternTest169, 1); - UtRegisterTest("DetectFastPatternTest170", DetectFastPatternTest170, 1); - UtRegisterTest("DetectFastPatternTest171", DetectFastPatternTest171, 1); - UtRegisterTest("DetectFastPatternTest172", DetectFastPatternTest172, 1); - UtRegisterTest("DetectFastPatternTest173", DetectFastPatternTest173, 1); - UtRegisterTest("DetectFastPatternTest174", DetectFastPatternTest174, 1); + UtRegisterTest("DetectFastPatternTest134", DetectFastPatternTest134); + UtRegisterTest("DetectFastPatternTest135", DetectFastPatternTest135); + UtRegisterTest("DetectFastPatternTest136", DetectFastPatternTest136); + UtRegisterTest("DetectFastPatternTest137", DetectFastPatternTest137); + UtRegisterTest("DetectFastPatternTest138", DetectFastPatternTest138); + UtRegisterTest("DetectFastPatternTest139", DetectFastPatternTest139); + UtRegisterTest("DetectFastPatternTest140", DetectFastPatternTest140); + UtRegisterTest("DetectFastPatternTest141", DetectFastPatternTest141); + UtRegisterTest("DetectFastPatternTest142", DetectFastPatternTest142); + UtRegisterTest("DetectFastPatternTest143", DetectFastPatternTest143); + UtRegisterTest("DetectFastPatternTest144", DetectFastPatternTest144); + UtRegisterTest("DetectFastPatternTest145", DetectFastPatternTest145); + UtRegisterTest("DetectFastPatternTest146", DetectFastPatternTest146); + UtRegisterTest("DetectFastPatternTest147", DetectFastPatternTest147); + UtRegisterTest("DetectFastPatternTest148", DetectFastPatternTest148); + UtRegisterTest("DetectFastPatternTest149", DetectFastPatternTest149); + UtRegisterTest("DetectFastPatternTest150", DetectFastPatternTest150); + UtRegisterTest("DetectFastPatternTest151", DetectFastPatternTest151); + UtRegisterTest("DetectFastPatternTest152", DetectFastPatternTest152); + UtRegisterTest("DetectFastPatternTest153", DetectFastPatternTest153); + UtRegisterTest("DetectFastPatternTest154", DetectFastPatternTest154); + UtRegisterTest("DetectFastPatternTest155", DetectFastPatternTest155); + UtRegisterTest("DetectFastPatternTest156", DetectFastPatternTest156); + UtRegisterTest("DetectFastPatternTest157", DetectFastPatternTest157); + UtRegisterTest("DetectFastPatternTest158", DetectFastPatternTest158); + UtRegisterTest("DetectFastPatternTest159", DetectFastPatternTest159); + UtRegisterTest("DetectFastPatternTest160", DetectFastPatternTest160); + UtRegisterTest("DetectFastPatternTest161", DetectFastPatternTest161); + UtRegisterTest("DetectFastPatternTest162", DetectFastPatternTest162); + UtRegisterTest("DetectFastPatternTest163", DetectFastPatternTest163); + UtRegisterTest("DetectFastPatternTest164", DetectFastPatternTest164); + UtRegisterTest("DetectFastPatternTest165", DetectFastPatternTest165); + UtRegisterTest("DetectFastPatternTest166", DetectFastPatternTest166); + UtRegisterTest("DetectFastPatternTest167", DetectFastPatternTest167); + UtRegisterTest("DetectFastPatternTest168", DetectFastPatternTest168); + UtRegisterTest("DetectFastPatternTest169", DetectFastPatternTest169); + UtRegisterTest("DetectFastPatternTest170", DetectFastPatternTest170); + UtRegisterTest("DetectFastPatternTest171", DetectFastPatternTest171); + UtRegisterTest("DetectFastPatternTest172", DetectFastPatternTest172); + UtRegisterTest("DetectFastPatternTest173", DetectFastPatternTest173); + UtRegisterTest("DetectFastPatternTest174", DetectFastPatternTest174); /* http_client_body fast_pattern tests ^ */ /* content fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest175", DetectFastPatternTest175, 1); - UtRegisterTest("DetectFastPatternTest176", DetectFastPatternTest176, 1); - UtRegisterTest("DetectFastPatternTest177", DetectFastPatternTest177, 1); - UtRegisterTest("DetectFastPatternTest178", DetectFastPatternTest178, 1); + UtRegisterTest("DetectFastPatternTest175", DetectFastPatternTest175); + UtRegisterTest("DetectFastPatternTest176", DetectFastPatternTest176); + UtRegisterTest("DetectFastPatternTest177", DetectFastPatternTest177); + UtRegisterTest("DetectFastPatternTest178", DetectFastPatternTest178); /* content fast_pattern tests ^ */ /* http_header fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest179", DetectFastPatternTest179, 1); - UtRegisterTest("DetectFastPatternTest180", DetectFastPatternTest180, 1); - UtRegisterTest("DetectFastPatternTest181", DetectFastPatternTest181, 1); - UtRegisterTest("DetectFastPatternTest182", DetectFastPatternTest182, 1); - UtRegisterTest("DetectFastPatternTest183", DetectFastPatternTest183, 1); - UtRegisterTest("DetectFastPatternTest184", DetectFastPatternTest184, 1); - UtRegisterTest("DetectFastPatternTest185", DetectFastPatternTest185, 1); - UtRegisterTest("DetectFastPatternTest186", DetectFastPatternTest186, 1); - UtRegisterTest("DetectFastPatternTest187", DetectFastPatternTest187, 1); - UtRegisterTest("DetectFastPatternTest188", DetectFastPatternTest188, 1); - UtRegisterTest("DetectFastPatternTest189", DetectFastPatternTest189, 1); - UtRegisterTest("DetectFastPatternTest190", DetectFastPatternTest190, 1); - UtRegisterTest("DetectFastPatternTest191", DetectFastPatternTest191, 1); - UtRegisterTest("DetectFastPatternTest192", DetectFastPatternTest192, 1); - UtRegisterTest("DetectFastPatternTest193", DetectFastPatternTest193, 1); - UtRegisterTest("DetectFastPatternTest194", DetectFastPatternTest194, 1); - UtRegisterTest("DetectFastPatternTest195", DetectFastPatternTest195, 1); - UtRegisterTest("DetectFastPatternTest196", DetectFastPatternTest196, 1); - UtRegisterTest("DetectFastPatternTest197", DetectFastPatternTest197, 1); - UtRegisterTest("DetectFastPatternTest198", DetectFastPatternTest198, 1); - UtRegisterTest("DetectFastPatternTest199", DetectFastPatternTest199, 1); - UtRegisterTest("DetectFastPatternTest200", DetectFastPatternTest200, 1); - UtRegisterTest("DetectFastPatternTest201", DetectFastPatternTest201, 1); - UtRegisterTest("DetectFastPatternTest202", DetectFastPatternTest202, 1); - UtRegisterTest("DetectFastPatternTest203", DetectFastPatternTest203, 1); - UtRegisterTest("DetectFastPatternTest204", DetectFastPatternTest204, 1); - UtRegisterTest("DetectFastPatternTest205", DetectFastPatternTest205, 1); - UtRegisterTest("DetectFastPatternTest206", DetectFastPatternTest206, 1); - UtRegisterTest("DetectFastPatternTest207", DetectFastPatternTest207, 1); - UtRegisterTest("DetectFastPatternTest208", DetectFastPatternTest208, 1); - UtRegisterTest("DetectFastPatternTest209", DetectFastPatternTest209, 1); - UtRegisterTest("DetectFastPatternTest210", DetectFastPatternTest210, 1); - UtRegisterTest("DetectFastPatternTest211", DetectFastPatternTest211, 1); - UtRegisterTest("DetectFastPatternTest212", DetectFastPatternTest212, 1); - UtRegisterTest("DetectFastPatternTest213", DetectFastPatternTest213, 1); - UtRegisterTest("DetectFastPatternTest214", DetectFastPatternTest214, 1); - UtRegisterTest("DetectFastPatternTest215", DetectFastPatternTest215, 1); - UtRegisterTest("DetectFastPatternTest216", DetectFastPatternTest216, 1); - UtRegisterTest("DetectFastPatternTest217", DetectFastPatternTest217, 1); - UtRegisterTest("DetectFastPatternTest218", DetectFastPatternTest218, 1); - UtRegisterTest("DetectFastPatternTest219", DetectFastPatternTest219, 1); + UtRegisterTest("DetectFastPatternTest179", DetectFastPatternTest179); + UtRegisterTest("DetectFastPatternTest180", DetectFastPatternTest180); + UtRegisterTest("DetectFastPatternTest181", DetectFastPatternTest181); + UtRegisterTest("DetectFastPatternTest182", DetectFastPatternTest182); + UtRegisterTest("DetectFastPatternTest183", DetectFastPatternTest183); + UtRegisterTest("DetectFastPatternTest184", DetectFastPatternTest184); + UtRegisterTest("DetectFastPatternTest185", DetectFastPatternTest185); + UtRegisterTest("DetectFastPatternTest186", DetectFastPatternTest186); + UtRegisterTest("DetectFastPatternTest187", DetectFastPatternTest187); + UtRegisterTest("DetectFastPatternTest188", DetectFastPatternTest188); + UtRegisterTest("DetectFastPatternTest189", DetectFastPatternTest189); + UtRegisterTest("DetectFastPatternTest190", DetectFastPatternTest190); + UtRegisterTest("DetectFastPatternTest191", DetectFastPatternTest191); + UtRegisterTest("DetectFastPatternTest192", DetectFastPatternTest192); + UtRegisterTest("DetectFastPatternTest193", DetectFastPatternTest193); + UtRegisterTest("DetectFastPatternTest194", DetectFastPatternTest194); + UtRegisterTest("DetectFastPatternTest195", DetectFastPatternTest195); + UtRegisterTest("DetectFastPatternTest196", DetectFastPatternTest196); + UtRegisterTest("DetectFastPatternTest197", DetectFastPatternTest197); + UtRegisterTest("DetectFastPatternTest198", DetectFastPatternTest198); + UtRegisterTest("DetectFastPatternTest199", DetectFastPatternTest199); + UtRegisterTest("DetectFastPatternTest200", DetectFastPatternTest200); + UtRegisterTest("DetectFastPatternTest201", DetectFastPatternTest201); + UtRegisterTest("DetectFastPatternTest202", DetectFastPatternTest202); + UtRegisterTest("DetectFastPatternTest203", DetectFastPatternTest203); + UtRegisterTest("DetectFastPatternTest204", DetectFastPatternTest204); + UtRegisterTest("DetectFastPatternTest205", DetectFastPatternTest205); + UtRegisterTest("DetectFastPatternTest206", DetectFastPatternTest206); + UtRegisterTest("DetectFastPatternTest207", DetectFastPatternTest207); + UtRegisterTest("DetectFastPatternTest208", DetectFastPatternTest208); + UtRegisterTest("DetectFastPatternTest209", DetectFastPatternTest209); + UtRegisterTest("DetectFastPatternTest210", DetectFastPatternTest210); + UtRegisterTest("DetectFastPatternTest211", DetectFastPatternTest211); + UtRegisterTest("DetectFastPatternTest212", DetectFastPatternTest212); + UtRegisterTest("DetectFastPatternTest213", DetectFastPatternTest213); + UtRegisterTest("DetectFastPatternTest214", DetectFastPatternTest214); + UtRegisterTest("DetectFastPatternTest215", DetectFastPatternTest215); + UtRegisterTest("DetectFastPatternTest216", DetectFastPatternTest216); + UtRegisterTest("DetectFastPatternTest217", DetectFastPatternTest217); + UtRegisterTest("DetectFastPatternTest218", DetectFastPatternTest218); + UtRegisterTest("DetectFastPatternTest219", DetectFastPatternTest219); /* http_header fast_pattern tests ^ */ /* http_raw_header fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest220", DetectFastPatternTest220, 1); - UtRegisterTest("DetectFastPatternTest221", DetectFastPatternTest221, 1); - UtRegisterTest("DetectFastPatternTest222", DetectFastPatternTest222, 1); - UtRegisterTest("DetectFastPatternTest223", DetectFastPatternTest223, 1); - UtRegisterTest("DetectFastPatternTest224", DetectFastPatternTest224, 1); - UtRegisterTest("DetectFastPatternTest225", DetectFastPatternTest225, 1); - UtRegisterTest("DetectFastPatternTest226", DetectFastPatternTest226, 1); - UtRegisterTest("DetectFastPatternTest227", DetectFastPatternTest227, 1); - UtRegisterTest("DetectFastPatternTest228", DetectFastPatternTest228, 1); - UtRegisterTest("DetectFastPatternTest229", DetectFastPatternTest229, 1); - UtRegisterTest("DetectFastPatternTest230", DetectFastPatternTest230, 1); - UtRegisterTest("DetectFastPatternTest231", DetectFastPatternTest231, 1); - UtRegisterTest("DetectFastPatternTest232", DetectFastPatternTest232, 1); - UtRegisterTest("DetectFastPatternTest233", DetectFastPatternTest233, 1); - UtRegisterTest("DetectFastPatternTest234", DetectFastPatternTest234, 1); - UtRegisterTest("DetectFastPatternTest235", DetectFastPatternTest235, 1); - UtRegisterTest("DetectFastPatternTest236", DetectFastPatternTest236, 1); - UtRegisterTest("DetectFastPatternTest237", DetectFastPatternTest237, 1); - UtRegisterTest("DetectFastPatternTest238", DetectFastPatternTest238, 1); - UtRegisterTest("DetectFastPatternTest239", DetectFastPatternTest239, 1); - UtRegisterTest("DetectFastPatternTest240", DetectFastPatternTest240, 1); - UtRegisterTest("DetectFastPatternTest241", DetectFastPatternTest241, 1); - UtRegisterTest("DetectFastPatternTest242", DetectFastPatternTest242, 1); - UtRegisterTest("DetectFastPatternTest243", DetectFastPatternTest243, 1); - UtRegisterTest("DetectFastPatternTest244", DetectFastPatternTest244, 1); - UtRegisterTest("DetectFastPatternTest245", DetectFastPatternTest245, 1); - UtRegisterTest("DetectFastPatternTest246", DetectFastPatternTest246, 1); - UtRegisterTest("DetectFastPatternTest247", DetectFastPatternTest247, 1); - UtRegisterTest("DetectFastPatternTest248", DetectFastPatternTest248, 1); - UtRegisterTest("DetectFastPatternTest249", DetectFastPatternTest249, 1); - UtRegisterTest("DetectFastPatternTest250", DetectFastPatternTest250, 1); - UtRegisterTest("DetectFastPatternTest251", DetectFastPatternTest251, 1); - UtRegisterTest("DetectFastPatternTest252", DetectFastPatternTest252, 1); - UtRegisterTest("DetectFastPatternTest253", DetectFastPatternTest253, 1); - UtRegisterTest("DetectFastPatternTest254", DetectFastPatternTest254, 1); - UtRegisterTest("DetectFastPatternTest255", DetectFastPatternTest255, 1); - UtRegisterTest("DetectFastPatternTest256", DetectFastPatternTest256, 1); - UtRegisterTest("DetectFastPatternTest257", DetectFastPatternTest257, 1); - UtRegisterTest("DetectFastPatternTest258", DetectFastPatternTest258, 1); - UtRegisterTest("DetectFastPatternTest259", DetectFastPatternTest259, 1); - UtRegisterTest("DetectFastPatternTest260", DetectFastPatternTest260, 1); + UtRegisterTest("DetectFastPatternTest220", DetectFastPatternTest220); + UtRegisterTest("DetectFastPatternTest221", DetectFastPatternTest221); + UtRegisterTest("DetectFastPatternTest222", DetectFastPatternTest222); + UtRegisterTest("DetectFastPatternTest223", DetectFastPatternTest223); + UtRegisterTest("DetectFastPatternTest224", DetectFastPatternTest224); + UtRegisterTest("DetectFastPatternTest225", DetectFastPatternTest225); + UtRegisterTest("DetectFastPatternTest226", DetectFastPatternTest226); + UtRegisterTest("DetectFastPatternTest227", DetectFastPatternTest227); + UtRegisterTest("DetectFastPatternTest228", DetectFastPatternTest228); + UtRegisterTest("DetectFastPatternTest229", DetectFastPatternTest229); + UtRegisterTest("DetectFastPatternTest230", DetectFastPatternTest230); + UtRegisterTest("DetectFastPatternTest231", DetectFastPatternTest231); + UtRegisterTest("DetectFastPatternTest232", DetectFastPatternTest232); + UtRegisterTest("DetectFastPatternTest233", DetectFastPatternTest233); + UtRegisterTest("DetectFastPatternTest234", DetectFastPatternTest234); + UtRegisterTest("DetectFastPatternTest235", DetectFastPatternTest235); + UtRegisterTest("DetectFastPatternTest236", DetectFastPatternTest236); + UtRegisterTest("DetectFastPatternTest237", DetectFastPatternTest237); + UtRegisterTest("DetectFastPatternTest238", DetectFastPatternTest238); + UtRegisterTest("DetectFastPatternTest239", DetectFastPatternTest239); + UtRegisterTest("DetectFastPatternTest240", DetectFastPatternTest240); + UtRegisterTest("DetectFastPatternTest241", DetectFastPatternTest241); + UtRegisterTest("DetectFastPatternTest242", DetectFastPatternTest242); + UtRegisterTest("DetectFastPatternTest243", DetectFastPatternTest243); + UtRegisterTest("DetectFastPatternTest244", DetectFastPatternTest244); + UtRegisterTest("DetectFastPatternTest245", DetectFastPatternTest245); + UtRegisterTest("DetectFastPatternTest246", DetectFastPatternTest246); + UtRegisterTest("DetectFastPatternTest247", DetectFastPatternTest247); + UtRegisterTest("DetectFastPatternTest248", DetectFastPatternTest248); + UtRegisterTest("DetectFastPatternTest249", DetectFastPatternTest249); + UtRegisterTest("DetectFastPatternTest250", DetectFastPatternTest250); + UtRegisterTest("DetectFastPatternTest251", DetectFastPatternTest251); + UtRegisterTest("DetectFastPatternTest252", DetectFastPatternTest252); + UtRegisterTest("DetectFastPatternTest253", DetectFastPatternTest253); + UtRegisterTest("DetectFastPatternTest254", DetectFastPatternTest254); + UtRegisterTest("DetectFastPatternTest255", DetectFastPatternTest255); + UtRegisterTest("DetectFastPatternTest256", DetectFastPatternTest256); + UtRegisterTest("DetectFastPatternTest257", DetectFastPatternTest257); + UtRegisterTest("DetectFastPatternTest258", DetectFastPatternTest258); + UtRegisterTest("DetectFastPatternTest259", DetectFastPatternTest259); + UtRegisterTest("DetectFastPatternTest260", DetectFastPatternTest260); /* http_raw_header fast_pattern tests ^ */ /* http_method fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest261", DetectFastPatternTest261, 1); - UtRegisterTest("DetectFastPatternTest262", DetectFastPatternTest262, 1); - UtRegisterTest("DetectFastPatternTest263", DetectFastPatternTest263, 1); - UtRegisterTest("DetectFastPatternTest264", DetectFastPatternTest264, 1); - UtRegisterTest("DetectFastPatternTest265", DetectFastPatternTest265, 1); - UtRegisterTest("DetectFastPatternTest266", DetectFastPatternTest266, 1); - UtRegisterTest("DetectFastPatternTest267", DetectFastPatternTest267, 1); - UtRegisterTest("DetectFastPatternTest268", DetectFastPatternTest268, 1); - UtRegisterTest("DetectFastPatternTest269", DetectFastPatternTest269, 1); - UtRegisterTest("DetectFastPatternTest270", DetectFastPatternTest270, 1); - UtRegisterTest("DetectFastPatternTest271", DetectFastPatternTest271, 1); - UtRegisterTest("DetectFastPatternTest272", DetectFastPatternTest272, 1); - UtRegisterTest("DetectFastPatternTest273", DetectFastPatternTest273, 1); - UtRegisterTest("DetectFastPatternTest274", DetectFastPatternTest274, 1); - UtRegisterTest("DetectFastPatternTest275", DetectFastPatternTest275, 1); - UtRegisterTest("DetectFastPatternTest276", DetectFastPatternTest276, 1); - UtRegisterTest("DetectFastPatternTest277", DetectFastPatternTest277, 1); - UtRegisterTest("DetectFastPatternTest278", DetectFastPatternTest278, 1); - UtRegisterTest("DetectFastPatternTest279", DetectFastPatternTest279, 1); - UtRegisterTest("DetectFastPatternTest280", DetectFastPatternTest280, 1); - UtRegisterTest("DetectFastPatternTest281", DetectFastPatternTest281, 1); - UtRegisterTest("DetectFastPatternTest282", DetectFastPatternTest282, 1); - UtRegisterTest("DetectFastPatternTest283", DetectFastPatternTest283, 1); - UtRegisterTest("DetectFastPatternTest284", DetectFastPatternTest284, 1); - UtRegisterTest("DetectFastPatternTest285", DetectFastPatternTest285, 1); - UtRegisterTest("DetectFastPatternTest286", DetectFastPatternTest286, 1); - UtRegisterTest("DetectFastPatternTest287", DetectFastPatternTest287, 1); - UtRegisterTest("DetectFastPatternTest288", DetectFastPatternTest288, 1); - UtRegisterTest("DetectFastPatternTest289", DetectFastPatternTest289, 1); - UtRegisterTest("DetectFastPatternTest290", DetectFastPatternTest290, 1); - UtRegisterTest("DetectFastPatternTest291", DetectFastPatternTest291, 1); - UtRegisterTest("DetectFastPatternTest292", DetectFastPatternTest292, 1); - UtRegisterTest("DetectFastPatternTest293", DetectFastPatternTest293, 1); - UtRegisterTest("DetectFastPatternTest294", DetectFastPatternTest294, 1); - UtRegisterTest("DetectFastPatternTest295", DetectFastPatternTest295, 1); - UtRegisterTest("DetectFastPatternTest296", DetectFastPatternTest296, 1); - UtRegisterTest("DetectFastPatternTest297", DetectFastPatternTest297, 1); - UtRegisterTest("DetectFastPatternTest298", DetectFastPatternTest298, 1); - UtRegisterTest("DetectFastPatternTest299", DetectFastPatternTest299, 1); - UtRegisterTest("DetectFastPatternTest300", DetectFastPatternTest300, 1); - UtRegisterTest("DetectFastPatternTest301", DetectFastPatternTest301, 1); + UtRegisterTest("DetectFastPatternTest261", DetectFastPatternTest261); + UtRegisterTest("DetectFastPatternTest262", DetectFastPatternTest262); + UtRegisterTest("DetectFastPatternTest263", DetectFastPatternTest263); + UtRegisterTest("DetectFastPatternTest264", DetectFastPatternTest264); + UtRegisterTest("DetectFastPatternTest265", DetectFastPatternTest265); + UtRegisterTest("DetectFastPatternTest266", DetectFastPatternTest266); + UtRegisterTest("DetectFastPatternTest267", DetectFastPatternTest267); + UtRegisterTest("DetectFastPatternTest268", DetectFastPatternTest268); + UtRegisterTest("DetectFastPatternTest269", DetectFastPatternTest269); + UtRegisterTest("DetectFastPatternTest270", DetectFastPatternTest270); + UtRegisterTest("DetectFastPatternTest271", DetectFastPatternTest271); + UtRegisterTest("DetectFastPatternTest272", DetectFastPatternTest272); + UtRegisterTest("DetectFastPatternTest273", DetectFastPatternTest273); + UtRegisterTest("DetectFastPatternTest274", DetectFastPatternTest274); + UtRegisterTest("DetectFastPatternTest275", DetectFastPatternTest275); + UtRegisterTest("DetectFastPatternTest276", DetectFastPatternTest276); + UtRegisterTest("DetectFastPatternTest277", DetectFastPatternTest277); + UtRegisterTest("DetectFastPatternTest278", DetectFastPatternTest278); + UtRegisterTest("DetectFastPatternTest279", DetectFastPatternTest279); + UtRegisterTest("DetectFastPatternTest280", DetectFastPatternTest280); + UtRegisterTest("DetectFastPatternTest281", DetectFastPatternTest281); + UtRegisterTest("DetectFastPatternTest282", DetectFastPatternTest282); + UtRegisterTest("DetectFastPatternTest283", DetectFastPatternTest283); + UtRegisterTest("DetectFastPatternTest284", DetectFastPatternTest284); + UtRegisterTest("DetectFastPatternTest285", DetectFastPatternTest285); + UtRegisterTest("DetectFastPatternTest286", DetectFastPatternTest286); + UtRegisterTest("DetectFastPatternTest287", DetectFastPatternTest287); + UtRegisterTest("DetectFastPatternTest288", DetectFastPatternTest288); + UtRegisterTest("DetectFastPatternTest289", DetectFastPatternTest289); + UtRegisterTest("DetectFastPatternTest290", DetectFastPatternTest290); + UtRegisterTest("DetectFastPatternTest291", DetectFastPatternTest291); + UtRegisterTest("DetectFastPatternTest292", DetectFastPatternTest292); + UtRegisterTest("DetectFastPatternTest293", DetectFastPatternTest293); + UtRegisterTest("DetectFastPatternTest294", DetectFastPatternTest294); + UtRegisterTest("DetectFastPatternTest295", DetectFastPatternTest295); + UtRegisterTest("DetectFastPatternTest296", DetectFastPatternTest296); + UtRegisterTest("DetectFastPatternTest297", DetectFastPatternTest297); + UtRegisterTest("DetectFastPatternTest298", DetectFastPatternTest298); + UtRegisterTest("DetectFastPatternTest299", DetectFastPatternTest299); + UtRegisterTest("DetectFastPatternTest300", DetectFastPatternTest300); + UtRegisterTest("DetectFastPatternTest301", DetectFastPatternTest301); /* http_method fast_pattern tests ^ */ /* http_cookie fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest302", DetectFastPatternTest302, 1); - UtRegisterTest("DetectFastPatternTest303", DetectFastPatternTest303, 1); - UtRegisterTest("DetectFastPatternTest304", DetectFastPatternTest304, 1); - UtRegisterTest("DetectFastPatternTest305", DetectFastPatternTest305, 1); - UtRegisterTest("DetectFastPatternTest306", DetectFastPatternTest306, 1); - UtRegisterTest("DetectFastPatternTest307", DetectFastPatternTest307, 1); - UtRegisterTest("DetectFastPatternTest308", DetectFastPatternTest308, 1); - UtRegisterTest("DetectFastPatternTest309", DetectFastPatternTest309, 1); - UtRegisterTest("DetectFastPatternTest310", DetectFastPatternTest310, 1); - UtRegisterTest("DetectFastPatternTest311", DetectFastPatternTest311, 1); - UtRegisterTest("DetectFastPatternTest312", DetectFastPatternTest312, 1); - UtRegisterTest("DetectFastPatternTest313", DetectFastPatternTest313, 1); - UtRegisterTest("DetectFastPatternTest314", DetectFastPatternTest314, 1); - UtRegisterTest("DetectFastPatternTest315", DetectFastPatternTest315, 1); - UtRegisterTest("DetectFastPatternTest316", DetectFastPatternTest316, 1); - UtRegisterTest("DetectFastPatternTest317", DetectFastPatternTest317, 1); - UtRegisterTest("DetectFastPatternTest318", DetectFastPatternTest318, 1); - UtRegisterTest("DetectFastPatternTest319", DetectFastPatternTest319, 1); - UtRegisterTest("DetectFastPatternTest320", DetectFastPatternTest320, 1); - UtRegisterTest("DetectFastPatternTest321", DetectFastPatternTest321, 1); - UtRegisterTest("DetectFastPatternTest322", DetectFastPatternTest322, 1); - UtRegisterTest("DetectFastPatternTest323", DetectFastPatternTest323, 1); - UtRegisterTest("DetectFastPatternTest324", DetectFastPatternTest324, 1); - UtRegisterTest("DetectFastPatternTest325", DetectFastPatternTest325, 1); - UtRegisterTest("DetectFastPatternTest326", DetectFastPatternTest326, 1); - UtRegisterTest("DetectFastPatternTest327", DetectFastPatternTest327, 1); - UtRegisterTest("DetectFastPatternTest328", DetectFastPatternTest328, 1); - UtRegisterTest("DetectFastPatternTest329", DetectFastPatternTest329, 1); - UtRegisterTest("DetectFastPatternTest330", DetectFastPatternTest330, 1); - UtRegisterTest("DetectFastPatternTest331", DetectFastPatternTest331, 1); - UtRegisterTest("DetectFastPatternTest332", DetectFastPatternTest332, 1); - UtRegisterTest("DetectFastPatternTest333", DetectFastPatternTest333, 1); - UtRegisterTest("DetectFastPatternTest334", DetectFastPatternTest334, 1); - UtRegisterTest("DetectFastPatternTest335", DetectFastPatternTest335, 1); - UtRegisterTest("DetectFastPatternTest336", DetectFastPatternTest336, 1); - UtRegisterTest("DetectFastPatternTest337", DetectFastPatternTest337, 1); - UtRegisterTest("DetectFastPatternTest338", DetectFastPatternTest338, 1); - UtRegisterTest("DetectFastPatternTest339", DetectFastPatternTest339, 1); - UtRegisterTest("DetectFastPatternTest340", DetectFastPatternTest340, 1); - UtRegisterTest("DetectFastPatternTest341", DetectFastPatternTest341, 1); - UtRegisterTest("DetectFastPatternTest342", DetectFastPatternTest342, 1); + UtRegisterTest("DetectFastPatternTest302", DetectFastPatternTest302); + UtRegisterTest("DetectFastPatternTest303", DetectFastPatternTest303); + UtRegisterTest("DetectFastPatternTest304", DetectFastPatternTest304); + UtRegisterTest("DetectFastPatternTest305", DetectFastPatternTest305); + UtRegisterTest("DetectFastPatternTest306", DetectFastPatternTest306); + UtRegisterTest("DetectFastPatternTest307", DetectFastPatternTest307); + UtRegisterTest("DetectFastPatternTest308", DetectFastPatternTest308); + UtRegisterTest("DetectFastPatternTest309", DetectFastPatternTest309); + UtRegisterTest("DetectFastPatternTest310", DetectFastPatternTest310); + UtRegisterTest("DetectFastPatternTest311", DetectFastPatternTest311); + UtRegisterTest("DetectFastPatternTest312", DetectFastPatternTest312); + UtRegisterTest("DetectFastPatternTest313", DetectFastPatternTest313); + UtRegisterTest("DetectFastPatternTest314", DetectFastPatternTest314); + UtRegisterTest("DetectFastPatternTest315", DetectFastPatternTest315); + UtRegisterTest("DetectFastPatternTest316", DetectFastPatternTest316); + UtRegisterTest("DetectFastPatternTest317", DetectFastPatternTest317); + UtRegisterTest("DetectFastPatternTest318", DetectFastPatternTest318); + UtRegisterTest("DetectFastPatternTest319", DetectFastPatternTest319); + UtRegisterTest("DetectFastPatternTest320", DetectFastPatternTest320); + UtRegisterTest("DetectFastPatternTest321", DetectFastPatternTest321); + UtRegisterTest("DetectFastPatternTest322", DetectFastPatternTest322); + UtRegisterTest("DetectFastPatternTest323", DetectFastPatternTest323); + UtRegisterTest("DetectFastPatternTest324", DetectFastPatternTest324); + UtRegisterTest("DetectFastPatternTest325", DetectFastPatternTest325); + UtRegisterTest("DetectFastPatternTest326", DetectFastPatternTest326); + UtRegisterTest("DetectFastPatternTest327", DetectFastPatternTest327); + UtRegisterTest("DetectFastPatternTest328", DetectFastPatternTest328); + UtRegisterTest("DetectFastPatternTest329", DetectFastPatternTest329); + UtRegisterTest("DetectFastPatternTest330", DetectFastPatternTest330); + UtRegisterTest("DetectFastPatternTest331", DetectFastPatternTest331); + UtRegisterTest("DetectFastPatternTest332", DetectFastPatternTest332); + UtRegisterTest("DetectFastPatternTest333", DetectFastPatternTest333); + UtRegisterTest("DetectFastPatternTest334", DetectFastPatternTest334); + UtRegisterTest("DetectFastPatternTest335", DetectFastPatternTest335); + UtRegisterTest("DetectFastPatternTest336", DetectFastPatternTest336); + UtRegisterTest("DetectFastPatternTest337", DetectFastPatternTest337); + UtRegisterTest("DetectFastPatternTest338", DetectFastPatternTest338); + UtRegisterTest("DetectFastPatternTest339", DetectFastPatternTest339); + UtRegisterTest("DetectFastPatternTest340", DetectFastPatternTest340); + UtRegisterTest("DetectFastPatternTest341", DetectFastPatternTest341); + UtRegisterTest("DetectFastPatternTest342", DetectFastPatternTest342); /* http_cookie fast_pattern tests ^ */ /* http_raw_uri fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest343", DetectFastPatternTest343, 1); - UtRegisterTest("DetectFastPatternTest344", DetectFastPatternTest344, 1); - UtRegisterTest("DetectFastPatternTest345", DetectFastPatternTest345, 1); - UtRegisterTest("DetectFastPatternTest346", DetectFastPatternTest346, 1); - UtRegisterTest("DetectFastPatternTest347", DetectFastPatternTest347, 1); - UtRegisterTest("DetectFastPatternTest348", DetectFastPatternTest348, 1); - UtRegisterTest("DetectFastPatternTest349", DetectFastPatternTest349, 1); - UtRegisterTest("DetectFastPatternTest350", DetectFastPatternTest350, 1); - UtRegisterTest("DetectFastPatternTest351", DetectFastPatternTest351, 1); - UtRegisterTest("DetectFastPatternTest352", DetectFastPatternTest352, 1); - UtRegisterTest("DetectFastPatternTest353", DetectFastPatternTest353, 1); - UtRegisterTest("DetectFastPatternTest354", DetectFastPatternTest354, 1); - UtRegisterTest("DetectFastPatternTest355", DetectFastPatternTest355, 1); - UtRegisterTest("DetectFastPatternTest356", DetectFastPatternTest356, 1); - UtRegisterTest("DetectFastPatternTest357", DetectFastPatternTest357, 1); - UtRegisterTest("DetectFastPatternTest358", DetectFastPatternTest358, 1); - UtRegisterTest("DetectFastPatternTest359", DetectFastPatternTest359, 1); - UtRegisterTest("DetectFastPatternTest360", DetectFastPatternTest360, 1); - UtRegisterTest("DetectFastPatternTest361", DetectFastPatternTest361, 1); - UtRegisterTest("DetectFastPatternTest362", DetectFastPatternTest362, 1); - UtRegisterTest("DetectFastPatternTest363", DetectFastPatternTest363, 1); - UtRegisterTest("DetectFastPatternTest364", DetectFastPatternTest364, 1); - UtRegisterTest("DetectFastPatternTest365", DetectFastPatternTest365, 1); - UtRegisterTest("DetectFastPatternTest366", DetectFastPatternTest366, 1); - UtRegisterTest("DetectFastPatternTest367", DetectFastPatternTest367, 1); - UtRegisterTest("DetectFastPatternTest368", DetectFastPatternTest368, 1); - UtRegisterTest("DetectFastPatternTest369", DetectFastPatternTest369, 1); - UtRegisterTest("DetectFastPatternTest370", DetectFastPatternTest370, 1); - UtRegisterTest("DetectFastPatternTest371", DetectFastPatternTest371, 1); - UtRegisterTest("DetectFastPatternTest372", DetectFastPatternTest372, 1); - UtRegisterTest("DetectFastPatternTest373", DetectFastPatternTest373, 1); - UtRegisterTest("DetectFastPatternTest374", DetectFastPatternTest374, 1); - UtRegisterTest("DetectFastPatternTest375", DetectFastPatternTest375, 1); - UtRegisterTest("DetectFastPatternTest376", DetectFastPatternTest376, 1); - UtRegisterTest("DetectFastPatternTest377", DetectFastPatternTest377, 1); - UtRegisterTest("DetectFastPatternTest378", DetectFastPatternTest378, 1); - UtRegisterTest("DetectFastPatternTest379", DetectFastPatternTest379, 1); - UtRegisterTest("DetectFastPatternTest380", DetectFastPatternTest380, 1); - UtRegisterTest("DetectFastPatternTest381", DetectFastPatternTest381, 1); - UtRegisterTest("DetectFastPatternTest382", DetectFastPatternTest382, 1); - UtRegisterTest("DetectFastPatternTest383", DetectFastPatternTest383, 1); + UtRegisterTest("DetectFastPatternTest343", DetectFastPatternTest343); + UtRegisterTest("DetectFastPatternTest344", DetectFastPatternTest344); + UtRegisterTest("DetectFastPatternTest345", DetectFastPatternTest345); + UtRegisterTest("DetectFastPatternTest346", DetectFastPatternTest346); + UtRegisterTest("DetectFastPatternTest347", DetectFastPatternTest347); + UtRegisterTest("DetectFastPatternTest348", DetectFastPatternTest348); + UtRegisterTest("DetectFastPatternTest349", DetectFastPatternTest349); + UtRegisterTest("DetectFastPatternTest350", DetectFastPatternTest350); + UtRegisterTest("DetectFastPatternTest351", DetectFastPatternTest351); + UtRegisterTest("DetectFastPatternTest352", DetectFastPatternTest352); + UtRegisterTest("DetectFastPatternTest353", DetectFastPatternTest353); + UtRegisterTest("DetectFastPatternTest354", DetectFastPatternTest354); + UtRegisterTest("DetectFastPatternTest355", DetectFastPatternTest355); + UtRegisterTest("DetectFastPatternTest356", DetectFastPatternTest356); + UtRegisterTest("DetectFastPatternTest357", DetectFastPatternTest357); + UtRegisterTest("DetectFastPatternTest358", DetectFastPatternTest358); + UtRegisterTest("DetectFastPatternTest359", DetectFastPatternTest359); + UtRegisterTest("DetectFastPatternTest360", DetectFastPatternTest360); + UtRegisterTest("DetectFastPatternTest361", DetectFastPatternTest361); + UtRegisterTest("DetectFastPatternTest362", DetectFastPatternTest362); + UtRegisterTest("DetectFastPatternTest363", DetectFastPatternTest363); + UtRegisterTest("DetectFastPatternTest364", DetectFastPatternTest364); + UtRegisterTest("DetectFastPatternTest365", DetectFastPatternTest365); + UtRegisterTest("DetectFastPatternTest366", DetectFastPatternTest366); + UtRegisterTest("DetectFastPatternTest367", DetectFastPatternTest367); + UtRegisterTest("DetectFastPatternTest368", DetectFastPatternTest368); + UtRegisterTest("DetectFastPatternTest369", DetectFastPatternTest369); + UtRegisterTest("DetectFastPatternTest370", DetectFastPatternTest370); + UtRegisterTest("DetectFastPatternTest371", DetectFastPatternTest371); + UtRegisterTest("DetectFastPatternTest372", DetectFastPatternTest372); + UtRegisterTest("DetectFastPatternTest373", DetectFastPatternTest373); + UtRegisterTest("DetectFastPatternTest374", DetectFastPatternTest374); + UtRegisterTest("DetectFastPatternTest375", DetectFastPatternTest375); + UtRegisterTest("DetectFastPatternTest376", DetectFastPatternTest376); + UtRegisterTest("DetectFastPatternTest377", DetectFastPatternTest377); + UtRegisterTest("DetectFastPatternTest378", DetectFastPatternTest378); + UtRegisterTest("DetectFastPatternTest379", DetectFastPatternTest379); + UtRegisterTest("DetectFastPatternTest380", DetectFastPatternTest380); + UtRegisterTest("DetectFastPatternTest381", DetectFastPatternTest381); + UtRegisterTest("DetectFastPatternTest382", DetectFastPatternTest382); + UtRegisterTest("DetectFastPatternTest383", DetectFastPatternTest383); /* http_raw_uri fast_pattern tests ^ */ /* http_stat_msg fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest384", DetectFastPatternTest384, 1); - UtRegisterTest("DetectFastPatternTest385", DetectFastPatternTest385, 1); - UtRegisterTest("DetectFastPatternTest386", DetectFastPatternTest386, 1); - UtRegisterTest("DetectFastPatternTest387", DetectFastPatternTest387, 1); - UtRegisterTest("DetectFastPatternTest388", DetectFastPatternTest388, 1); - UtRegisterTest("DetectFastPatternTest389", DetectFastPatternTest389, 1); - UtRegisterTest("DetectFastPatternTest390", DetectFastPatternTest390, 1); - UtRegisterTest("DetectFastPatternTest391", DetectFastPatternTest391, 1); - UtRegisterTest("DetectFastPatternTest392", DetectFastPatternTest392, 1); - UtRegisterTest("DetectFastPatternTest393", DetectFastPatternTest393, 1); - UtRegisterTest("DetectFastPatternTest394", DetectFastPatternTest394, 1); - UtRegisterTest("DetectFastPatternTest395", DetectFastPatternTest395, 1); - UtRegisterTest("DetectFastPatternTest396", DetectFastPatternTest396, 1); - UtRegisterTest("DetectFastPatternTest397", DetectFastPatternTest397, 1); - UtRegisterTest("DetectFastPatternTest398", DetectFastPatternTest398, 1); - UtRegisterTest("DetectFastPatternTest399", DetectFastPatternTest399, 1); - UtRegisterTest("DetectFastPatternTest400", DetectFastPatternTest400, 1); - UtRegisterTest("DetectFastPatternTest401", DetectFastPatternTest401, 1); - UtRegisterTest("DetectFastPatternTest402", DetectFastPatternTest402, 1); - UtRegisterTest("DetectFastPatternTest403", DetectFastPatternTest403, 1); - UtRegisterTest("DetectFastPatternTest404", DetectFastPatternTest404, 1); - UtRegisterTest("DetectFastPatternTest405", DetectFastPatternTest405, 1); - UtRegisterTest("DetectFastPatternTest406", DetectFastPatternTest406, 1); - UtRegisterTest("DetectFastPatternTest407", DetectFastPatternTest407, 1); - UtRegisterTest("DetectFastPatternTest408", DetectFastPatternTest408, 1); - UtRegisterTest("DetectFastPatternTest409", DetectFastPatternTest409, 1); - UtRegisterTest("DetectFastPatternTest410", DetectFastPatternTest410, 1); - UtRegisterTest("DetectFastPatternTest411", DetectFastPatternTest411, 1); - UtRegisterTest("DetectFastPatternTest412", DetectFastPatternTest412, 1); - UtRegisterTest("DetectFastPatternTest413", DetectFastPatternTest413, 1); - UtRegisterTest("DetectFastPatternTest414", DetectFastPatternTest414, 1); - UtRegisterTest("DetectFastPatternTest415", DetectFastPatternTest415, 1); - UtRegisterTest("DetectFastPatternTest416", DetectFastPatternTest415, 1); - UtRegisterTest("DetectFastPatternTest417", DetectFastPatternTest417, 1); - UtRegisterTest("DetectFastPatternTest418", DetectFastPatternTest418, 1); - UtRegisterTest("DetectFastPatternTest419", DetectFastPatternTest419, 1); - UtRegisterTest("DetectFastPatternTest420", DetectFastPatternTest420, 1); - UtRegisterTest("DetectFastPatternTest421", DetectFastPatternTest421, 1); - UtRegisterTest("DetectFastPatternTest422", DetectFastPatternTest422, 1); - UtRegisterTest("DetectFastPatternTest423", DetectFastPatternTest423, 1); - UtRegisterTest("DetectFastPatternTest424", DetectFastPatternTest424, 1); + UtRegisterTest("DetectFastPatternTest384", DetectFastPatternTest384); + UtRegisterTest("DetectFastPatternTest385", DetectFastPatternTest385); + UtRegisterTest("DetectFastPatternTest386", DetectFastPatternTest386); + UtRegisterTest("DetectFastPatternTest387", DetectFastPatternTest387); + UtRegisterTest("DetectFastPatternTest388", DetectFastPatternTest388); + UtRegisterTest("DetectFastPatternTest389", DetectFastPatternTest389); + UtRegisterTest("DetectFastPatternTest390", DetectFastPatternTest390); + UtRegisterTest("DetectFastPatternTest391", DetectFastPatternTest391); + UtRegisterTest("DetectFastPatternTest392", DetectFastPatternTest392); + UtRegisterTest("DetectFastPatternTest393", DetectFastPatternTest393); + UtRegisterTest("DetectFastPatternTest394", DetectFastPatternTest394); + UtRegisterTest("DetectFastPatternTest395", DetectFastPatternTest395); + UtRegisterTest("DetectFastPatternTest396", DetectFastPatternTest396); + UtRegisterTest("DetectFastPatternTest397", DetectFastPatternTest397); + UtRegisterTest("DetectFastPatternTest398", DetectFastPatternTest398); + UtRegisterTest("DetectFastPatternTest399", DetectFastPatternTest399); + UtRegisterTest("DetectFastPatternTest400", DetectFastPatternTest400); + UtRegisterTest("DetectFastPatternTest401", DetectFastPatternTest401); + UtRegisterTest("DetectFastPatternTest402", DetectFastPatternTest402); + UtRegisterTest("DetectFastPatternTest403", DetectFastPatternTest403); + UtRegisterTest("DetectFastPatternTest404", DetectFastPatternTest404); + UtRegisterTest("DetectFastPatternTest405", DetectFastPatternTest405); + UtRegisterTest("DetectFastPatternTest406", DetectFastPatternTest406); + UtRegisterTest("DetectFastPatternTest407", DetectFastPatternTest407); + UtRegisterTest("DetectFastPatternTest408", DetectFastPatternTest408); + UtRegisterTest("DetectFastPatternTest409", DetectFastPatternTest409); + UtRegisterTest("DetectFastPatternTest410", DetectFastPatternTest410); + UtRegisterTest("DetectFastPatternTest411", DetectFastPatternTest411); + UtRegisterTest("DetectFastPatternTest412", DetectFastPatternTest412); + UtRegisterTest("DetectFastPatternTest413", DetectFastPatternTest413); + UtRegisterTest("DetectFastPatternTest414", DetectFastPatternTest414); + UtRegisterTest("DetectFastPatternTest415", DetectFastPatternTest415); + UtRegisterTest("DetectFastPatternTest416", DetectFastPatternTest415); + UtRegisterTest("DetectFastPatternTest417", DetectFastPatternTest417); + UtRegisterTest("DetectFastPatternTest418", DetectFastPatternTest418); + UtRegisterTest("DetectFastPatternTest419", DetectFastPatternTest419); + UtRegisterTest("DetectFastPatternTest420", DetectFastPatternTest420); + UtRegisterTest("DetectFastPatternTest421", DetectFastPatternTest421); + UtRegisterTest("DetectFastPatternTest422", DetectFastPatternTest422); + UtRegisterTest("DetectFastPatternTest423", DetectFastPatternTest423); + UtRegisterTest("DetectFastPatternTest424", DetectFastPatternTest424); /* http_stat_msg fast_pattern tests ^ */ /* http_stat_code fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest425", DetectFastPatternTest425, 1); - UtRegisterTest("DetectFastPatternTest426", DetectFastPatternTest426, 1); - UtRegisterTest("DetectFastPatternTest427", DetectFastPatternTest427, 1); - UtRegisterTest("DetectFastPatternTest428", DetectFastPatternTest428, 1); - UtRegisterTest("DetectFastPatternTest429", DetectFastPatternTest429, 1); - UtRegisterTest("DetectFastPatternTest430", DetectFastPatternTest430, 1); - UtRegisterTest("DetectFastPatternTest431", DetectFastPatternTest431, 1); - UtRegisterTest("DetectFastPatternTest432", DetectFastPatternTest432, 1); - UtRegisterTest("DetectFastPatternTest433", DetectFastPatternTest433, 1); - UtRegisterTest("DetectFastPatternTest434", DetectFastPatternTest434, 1); - UtRegisterTest("DetectFastPatternTest435", DetectFastPatternTest435, 1); - UtRegisterTest("DetectFastPatternTest436", DetectFastPatternTest436, 1); - UtRegisterTest("DetectFastPatternTest437", DetectFastPatternTest437, 1); - UtRegisterTest("DetectFastPatternTest438", DetectFastPatternTest438, 1); - UtRegisterTest("DetectFastPatternTest439", DetectFastPatternTest439, 1); - UtRegisterTest("DetectFastPatternTest440", DetectFastPatternTest440, 1); - UtRegisterTest("DetectFastPatternTest441", DetectFastPatternTest441, 1); - UtRegisterTest("DetectFastPatternTest442", DetectFastPatternTest442, 1); - UtRegisterTest("DetectFastPatternTest443", DetectFastPatternTest443, 1); - UtRegisterTest("DetectFastPatternTest444", DetectFastPatternTest444, 1); - UtRegisterTest("DetectFastPatternTest445", DetectFastPatternTest445, 1); - UtRegisterTest("DetectFastPatternTest446", DetectFastPatternTest446, 1); - UtRegisterTest("DetectFastPatternTest447", DetectFastPatternTest447, 1); - UtRegisterTest("DetectFastPatternTest448", DetectFastPatternTest448, 1); - UtRegisterTest("DetectFastPatternTest449", DetectFastPatternTest449, 1); - UtRegisterTest("DetectFastPatternTest450", DetectFastPatternTest450, 1); - UtRegisterTest("DetectFastPatternTest451", DetectFastPatternTest451, 1); - UtRegisterTest("DetectFastPatternTest452", DetectFastPatternTest452, 1); - UtRegisterTest("DetectFastPatternTest453", DetectFastPatternTest453, 1); - UtRegisterTest("DetectFastPatternTest454", DetectFastPatternTest454, 1); - UtRegisterTest("DetectFastPatternTest455", DetectFastPatternTest455, 1); - UtRegisterTest("DetectFastPatternTest456", DetectFastPatternTest456, 1); - UtRegisterTest("DetectFastPatternTest457", DetectFastPatternTest457, 1); - UtRegisterTest("DetectFastPatternTest458", DetectFastPatternTest458, 1); - UtRegisterTest("DetectFastPatternTest459", DetectFastPatternTest459, 1); - UtRegisterTest("DetectFastPatternTest460", DetectFastPatternTest460, 1); - UtRegisterTest("DetectFastPatternTest461", DetectFastPatternTest461, 1); - UtRegisterTest("DetectFastPatternTest462", DetectFastPatternTest462, 1); - UtRegisterTest("DetectFastPatternTest463", DetectFastPatternTest463, 1); - UtRegisterTest("DetectFastPatternTest464", DetectFastPatternTest464, 1); - UtRegisterTest("DetectFastPatternTest465", DetectFastPatternTest465, 1); + UtRegisterTest("DetectFastPatternTest425", DetectFastPatternTest425); + UtRegisterTest("DetectFastPatternTest426", DetectFastPatternTest426); + UtRegisterTest("DetectFastPatternTest427", DetectFastPatternTest427); + UtRegisterTest("DetectFastPatternTest428", DetectFastPatternTest428); + UtRegisterTest("DetectFastPatternTest429", DetectFastPatternTest429); + UtRegisterTest("DetectFastPatternTest430", DetectFastPatternTest430); + UtRegisterTest("DetectFastPatternTest431", DetectFastPatternTest431); + UtRegisterTest("DetectFastPatternTest432", DetectFastPatternTest432); + UtRegisterTest("DetectFastPatternTest433", DetectFastPatternTest433); + UtRegisterTest("DetectFastPatternTest434", DetectFastPatternTest434); + UtRegisterTest("DetectFastPatternTest435", DetectFastPatternTest435); + UtRegisterTest("DetectFastPatternTest436", DetectFastPatternTest436); + UtRegisterTest("DetectFastPatternTest437", DetectFastPatternTest437); + UtRegisterTest("DetectFastPatternTest438", DetectFastPatternTest438); + UtRegisterTest("DetectFastPatternTest439", DetectFastPatternTest439); + UtRegisterTest("DetectFastPatternTest440", DetectFastPatternTest440); + UtRegisterTest("DetectFastPatternTest441", DetectFastPatternTest441); + UtRegisterTest("DetectFastPatternTest442", DetectFastPatternTest442); + UtRegisterTest("DetectFastPatternTest443", DetectFastPatternTest443); + UtRegisterTest("DetectFastPatternTest444", DetectFastPatternTest444); + UtRegisterTest("DetectFastPatternTest445", DetectFastPatternTest445); + UtRegisterTest("DetectFastPatternTest446", DetectFastPatternTest446); + UtRegisterTest("DetectFastPatternTest447", DetectFastPatternTest447); + UtRegisterTest("DetectFastPatternTest448", DetectFastPatternTest448); + UtRegisterTest("DetectFastPatternTest449", DetectFastPatternTest449); + UtRegisterTest("DetectFastPatternTest450", DetectFastPatternTest450); + UtRegisterTest("DetectFastPatternTest451", DetectFastPatternTest451); + UtRegisterTest("DetectFastPatternTest452", DetectFastPatternTest452); + UtRegisterTest("DetectFastPatternTest453", DetectFastPatternTest453); + UtRegisterTest("DetectFastPatternTest454", DetectFastPatternTest454); + UtRegisterTest("DetectFastPatternTest455", DetectFastPatternTest455); + UtRegisterTest("DetectFastPatternTest456", DetectFastPatternTest456); + UtRegisterTest("DetectFastPatternTest457", DetectFastPatternTest457); + UtRegisterTest("DetectFastPatternTest458", DetectFastPatternTest458); + UtRegisterTest("DetectFastPatternTest459", DetectFastPatternTest459); + UtRegisterTest("DetectFastPatternTest460", DetectFastPatternTest460); + UtRegisterTest("DetectFastPatternTest461", DetectFastPatternTest461); + UtRegisterTest("DetectFastPatternTest462", DetectFastPatternTest462); + UtRegisterTest("DetectFastPatternTest463", DetectFastPatternTest463); + UtRegisterTest("DetectFastPatternTest464", DetectFastPatternTest464); + UtRegisterTest("DetectFastPatternTest465", DetectFastPatternTest465); /* http_stat_code fast_pattern tests ^ */ /* http_server_body fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest466", DetectFastPatternTest466, 1); - UtRegisterTest("DetectFastPatternTest467", DetectFastPatternTest467, 1); - UtRegisterTest("DetectFastPatternTest468", DetectFastPatternTest468, 1); - UtRegisterTest("DetectFastPatternTest469", DetectFastPatternTest469, 1); - UtRegisterTest("DetectFastPatternTest470", DetectFastPatternTest470, 1); - UtRegisterTest("DetectFastPatternTest471", DetectFastPatternTest471, 1); - UtRegisterTest("DetectFastPatternTest472", DetectFastPatternTest472, 1); - UtRegisterTest("DetectFastPatternTest473", DetectFastPatternTest473, 1); - UtRegisterTest("DetectFastPatternTest474", DetectFastPatternTest474, 1); - UtRegisterTest("DetectFastPatternTest475", DetectFastPatternTest475, 1); - UtRegisterTest("DetectFastPatternTest476", DetectFastPatternTest476, 1); - UtRegisterTest("DetectFastPatternTest477", DetectFastPatternTest477, 1); - UtRegisterTest("DetectFastPatternTest478", DetectFastPatternTest478, 1); - UtRegisterTest("DetectFastPatternTest479", DetectFastPatternTest479, 1); - UtRegisterTest("DetectFastPatternTest480", DetectFastPatternTest480, 1); - UtRegisterTest("DetectFastPatternTest481", DetectFastPatternTest481, 1); - UtRegisterTest("DetectFastPatternTest482", DetectFastPatternTest482, 1); - UtRegisterTest("DetectFastPatternTest483", DetectFastPatternTest483, 1); - UtRegisterTest("DetectFastPatternTest484", DetectFastPatternTest484, 1); - UtRegisterTest("DetectFastPatternTest485", DetectFastPatternTest485, 1); - UtRegisterTest("DetectFastPatternTest486", DetectFastPatternTest486, 1); - UtRegisterTest("DetectFastPatternTest487", DetectFastPatternTest487, 1); - UtRegisterTest("DetectFastPatternTest488", DetectFastPatternTest488, 1); - UtRegisterTest("DetectFastPatternTest489", DetectFastPatternTest489, 1); - UtRegisterTest("DetectFastPatternTest490", DetectFastPatternTest490, 1); - UtRegisterTest("DetectFastPatternTest491", DetectFastPatternTest491, 1); - UtRegisterTest("DetectFastPatternTest492", DetectFastPatternTest492, 1); - UtRegisterTest("DetectFastPatternTest493", DetectFastPatternTest493, 1); - UtRegisterTest("DetectFastPatternTest494", DetectFastPatternTest494, 1); - UtRegisterTest("DetectFastPatternTest495", DetectFastPatternTest495, 1); - UtRegisterTest("DetectFastPatternTest496", DetectFastPatternTest496, 1); - UtRegisterTest("DetectFastPatternTest497", DetectFastPatternTest497, 1); - UtRegisterTest("DetectFastPatternTest498", DetectFastPatternTest498, 1); - UtRegisterTest("DetectFastPatternTest499", DetectFastPatternTest499, 1); - UtRegisterTest("DetectFastPatternTest500", DetectFastPatternTest500, 1); - UtRegisterTest("DetectFastPatternTest501", DetectFastPatternTest501, 1); - UtRegisterTest("DetectFastPatternTest502", DetectFastPatternTest502, 1); - UtRegisterTest("DetectFastPatternTest503", DetectFastPatternTest503, 1); - UtRegisterTest("DetectFastPatternTest504", DetectFastPatternTest504, 1); - UtRegisterTest("DetectFastPatternTest505", DetectFastPatternTest505, 1); - UtRegisterTest("DetectFastPatternTest506", DetectFastPatternTest506, 1); + UtRegisterTest("DetectFastPatternTest466", DetectFastPatternTest466); + UtRegisterTest("DetectFastPatternTest467", DetectFastPatternTest467); + UtRegisterTest("DetectFastPatternTest468", DetectFastPatternTest468); + UtRegisterTest("DetectFastPatternTest469", DetectFastPatternTest469); + UtRegisterTest("DetectFastPatternTest470", DetectFastPatternTest470); + UtRegisterTest("DetectFastPatternTest471", DetectFastPatternTest471); + UtRegisterTest("DetectFastPatternTest472", DetectFastPatternTest472); + UtRegisterTest("DetectFastPatternTest473", DetectFastPatternTest473); + UtRegisterTest("DetectFastPatternTest474", DetectFastPatternTest474); + UtRegisterTest("DetectFastPatternTest475", DetectFastPatternTest475); + UtRegisterTest("DetectFastPatternTest476", DetectFastPatternTest476); + UtRegisterTest("DetectFastPatternTest477", DetectFastPatternTest477); + UtRegisterTest("DetectFastPatternTest478", DetectFastPatternTest478); + UtRegisterTest("DetectFastPatternTest479", DetectFastPatternTest479); + UtRegisterTest("DetectFastPatternTest480", DetectFastPatternTest480); + UtRegisterTest("DetectFastPatternTest481", DetectFastPatternTest481); + UtRegisterTest("DetectFastPatternTest482", DetectFastPatternTest482); + UtRegisterTest("DetectFastPatternTest483", DetectFastPatternTest483); + UtRegisterTest("DetectFastPatternTest484", DetectFastPatternTest484); + UtRegisterTest("DetectFastPatternTest485", DetectFastPatternTest485); + UtRegisterTest("DetectFastPatternTest486", DetectFastPatternTest486); + UtRegisterTest("DetectFastPatternTest487", DetectFastPatternTest487); + UtRegisterTest("DetectFastPatternTest488", DetectFastPatternTest488); + UtRegisterTest("DetectFastPatternTest489", DetectFastPatternTest489); + UtRegisterTest("DetectFastPatternTest490", DetectFastPatternTest490); + UtRegisterTest("DetectFastPatternTest491", DetectFastPatternTest491); + UtRegisterTest("DetectFastPatternTest492", DetectFastPatternTest492); + UtRegisterTest("DetectFastPatternTest493", DetectFastPatternTest493); + UtRegisterTest("DetectFastPatternTest494", DetectFastPatternTest494); + UtRegisterTest("DetectFastPatternTest495", DetectFastPatternTest495); + UtRegisterTest("DetectFastPatternTest496", DetectFastPatternTest496); + UtRegisterTest("DetectFastPatternTest497", DetectFastPatternTest497); + UtRegisterTest("DetectFastPatternTest498", DetectFastPatternTest498); + UtRegisterTest("DetectFastPatternTest499", DetectFastPatternTest499); + UtRegisterTest("DetectFastPatternTest500", DetectFastPatternTest500); + UtRegisterTest("DetectFastPatternTest501", DetectFastPatternTest501); + UtRegisterTest("DetectFastPatternTest502", DetectFastPatternTest502); + UtRegisterTest("DetectFastPatternTest503", DetectFastPatternTest503); + UtRegisterTest("DetectFastPatternTest504", DetectFastPatternTest504); + UtRegisterTest("DetectFastPatternTest505", DetectFastPatternTest505); + UtRegisterTest("DetectFastPatternTest506", DetectFastPatternTest506); /* http_server_body fast_pattern tests ^ */ /* file_data fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest507", DetectFastPatternTest507, 1); - UtRegisterTest("DetectFastPatternTest508", DetectFastPatternTest508, 1); - UtRegisterTest("DetectFastPatternTest509", DetectFastPatternTest509, 1); - UtRegisterTest("DetectFastPatternTest510", DetectFastPatternTest510, 1); - UtRegisterTest("DetectFastPatternTest511", DetectFastPatternTest511, 1); - UtRegisterTest("DetectFastPatternTest512", DetectFastPatternTest512, 1); - UtRegisterTest("DetectFastPatternTest513", DetectFastPatternTest513, 1); - UtRegisterTest("DetectFastPatternTest514", DetectFastPatternTest514, 1); - UtRegisterTest("DetectFastPatternTest515", DetectFastPatternTest515, 1); - UtRegisterTest("DetectFastPatternTest516", DetectFastPatternTest516, 1); - UtRegisterTest("DetectFastPatternTest517", DetectFastPatternTest517, 1); - UtRegisterTest("DetectFastPatternTest518", DetectFastPatternTest518, 1); - UtRegisterTest("DetectFastPatternTest519", DetectFastPatternTest519, 1); - UtRegisterTest("DetectFastPatternTest520", DetectFastPatternTest520, 1); - UtRegisterTest("DetectFastPatternTest521", DetectFastPatternTest521, 1); - UtRegisterTest("DetectFastPatternTest522", DetectFastPatternTest522, 1); - UtRegisterTest("DetectFastPatternTest523", DetectFastPatternTest523, 1); - UtRegisterTest("DetectFastPatternTest524", DetectFastPatternTest524, 1); - UtRegisterTest("DetectFastPatternTest525", DetectFastPatternTest525, 1); - UtRegisterTest("DetectFastPatternTest526", DetectFastPatternTest526, 1); - UtRegisterTest("DetectFastPatternTest527", DetectFastPatternTest527, 1); - UtRegisterTest("DetectFastPatternTest528", DetectFastPatternTest528, 1); - UtRegisterTest("DetectFastPatternTest529", DetectFastPatternTest529, 1); - UtRegisterTest("DetectFastPatternTest530", DetectFastPatternTest530, 1); - UtRegisterTest("DetectFastPatternTest531", DetectFastPatternTest531, 1); - UtRegisterTest("DetectFastPatternTest532", DetectFastPatternTest532, 1); - UtRegisterTest("DetectFastPatternTest533", DetectFastPatternTest533, 1); - UtRegisterTest("DetectFastPatternTest534", DetectFastPatternTest534, 1); - UtRegisterTest("DetectFastPatternTest535", DetectFastPatternTest535, 1); - UtRegisterTest("DetectFastPatternTest536", DetectFastPatternTest536, 1); - UtRegisterTest("DetectFastPatternTest537", DetectFastPatternTest537, 1); - UtRegisterTest("DetectFastPatternTest538", DetectFastPatternTest538, 1); - UtRegisterTest("DetectFastPatternTest539", DetectFastPatternTest539, 1); - UtRegisterTest("DetectFastPatternTest540", DetectFastPatternTest540, 1); - UtRegisterTest("DetectFastPatternTest541", DetectFastPatternTest541, 1); - UtRegisterTest("DetectFastPatternTest542", DetectFastPatternTest542, 1); - UtRegisterTest("DetectFastPatternTest543", DetectFastPatternTest543, 1); - UtRegisterTest("DetectFastPatternTest544", DetectFastPatternTest544, 1); - UtRegisterTest("DetectFastPatternTest545", DetectFastPatternTest545, 1); - UtRegisterTest("DetectFastPatternTest546", DetectFastPatternTest546, 1); - UtRegisterTest("DetectFastPatternTest547", DetectFastPatternTest547, 1); + UtRegisterTest("DetectFastPatternTest507", DetectFastPatternTest507); + UtRegisterTest("DetectFastPatternTest508", DetectFastPatternTest508); + UtRegisterTest("DetectFastPatternTest509", DetectFastPatternTest509); + UtRegisterTest("DetectFastPatternTest510", DetectFastPatternTest510); + UtRegisterTest("DetectFastPatternTest511", DetectFastPatternTest511); + UtRegisterTest("DetectFastPatternTest512", DetectFastPatternTest512); + UtRegisterTest("DetectFastPatternTest513", DetectFastPatternTest513); + UtRegisterTest("DetectFastPatternTest514", DetectFastPatternTest514); + UtRegisterTest("DetectFastPatternTest515", DetectFastPatternTest515); + UtRegisterTest("DetectFastPatternTest516", DetectFastPatternTest516); + UtRegisterTest("DetectFastPatternTest517", DetectFastPatternTest517); + UtRegisterTest("DetectFastPatternTest518", DetectFastPatternTest518); + UtRegisterTest("DetectFastPatternTest519", DetectFastPatternTest519); + UtRegisterTest("DetectFastPatternTest520", DetectFastPatternTest520); + UtRegisterTest("DetectFastPatternTest521", DetectFastPatternTest521); + UtRegisterTest("DetectFastPatternTest522", DetectFastPatternTest522); + UtRegisterTest("DetectFastPatternTest523", DetectFastPatternTest523); + UtRegisterTest("DetectFastPatternTest524", DetectFastPatternTest524); + UtRegisterTest("DetectFastPatternTest525", DetectFastPatternTest525); + UtRegisterTest("DetectFastPatternTest526", DetectFastPatternTest526); + UtRegisterTest("DetectFastPatternTest527", DetectFastPatternTest527); + UtRegisterTest("DetectFastPatternTest528", DetectFastPatternTest528); + UtRegisterTest("DetectFastPatternTest529", DetectFastPatternTest529); + UtRegisterTest("DetectFastPatternTest530", DetectFastPatternTest530); + UtRegisterTest("DetectFastPatternTest531", DetectFastPatternTest531); + UtRegisterTest("DetectFastPatternTest532", DetectFastPatternTest532); + UtRegisterTest("DetectFastPatternTest533", DetectFastPatternTest533); + UtRegisterTest("DetectFastPatternTest534", DetectFastPatternTest534); + UtRegisterTest("DetectFastPatternTest535", DetectFastPatternTest535); + UtRegisterTest("DetectFastPatternTest536", DetectFastPatternTest536); + UtRegisterTest("DetectFastPatternTest537", DetectFastPatternTest537); + UtRegisterTest("DetectFastPatternTest538", DetectFastPatternTest538); + UtRegisterTest("DetectFastPatternTest539", DetectFastPatternTest539); + UtRegisterTest("DetectFastPatternTest540", DetectFastPatternTest540); + UtRegisterTest("DetectFastPatternTest541", DetectFastPatternTest541); + UtRegisterTest("DetectFastPatternTest542", DetectFastPatternTest542); + UtRegisterTest("DetectFastPatternTest543", DetectFastPatternTest543); + UtRegisterTest("DetectFastPatternTest544", DetectFastPatternTest544); + UtRegisterTest("DetectFastPatternTest545", DetectFastPatternTest545); + UtRegisterTest("DetectFastPatternTest546", DetectFastPatternTest546); + UtRegisterTest("DetectFastPatternTest547", DetectFastPatternTest547); /* file_data fast_pattern tests ^ */ /* http_user_agent fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest548", DetectFastPatternTest548, 1); - UtRegisterTest("DetectFastPatternTest549", DetectFastPatternTest549, 1); - UtRegisterTest("DetectFastPatternTest550", DetectFastPatternTest550, 1); - UtRegisterTest("DetectFastPatternTest551", DetectFastPatternTest551, 1); - UtRegisterTest("DetectFastPatternTest552", DetectFastPatternTest552, 1); - UtRegisterTest("DetectFastPatternTest553", DetectFastPatternTest553, 1); - UtRegisterTest("DetectFastPatternTest554", DetectFastPatternTest554, 1); - UtRegisterTest("DetectFastPatternTest555", DetectFastPatternTest555, 1); - UtRegisterTest("DetectFastPatternTest556", DetectFastPatternTest556, 1); - UtRegisterTest("DetectFastPatternTest557", DetectFastPatternTest557, 1); - UtRegisterTest("DetectFastPatternTest558", DetectFastPatternTest558, 1); - UtRegisterTest("DetectFastPatternTest559", DetectFastPatternTest559, 1); - UtRegisterTest("DetectFastPatternTest560", DetectFastPatternTest560, 1); - UtRegisterTest("DetectFastPatternTest561", DetectFastPatternTest561, 1); - UtRegisterTest("DetectFastPatternTest562", DetectFastPatternTest562, 1); - UtRegisterTest("DetectFastPatternTest563", DetectFastPatternTest563, 1); - UtRegisterTest("DetectFastPatternTest564", DetectFastPatternTest564, 1); - UtRegisterTest("DetectFastPatternTest565", DetectFastPatternTest565, 1); - UtRegisterTest("DetectFastPatternTest566", DetectFastPatternTest566, 1); - UtRegisterTest("DetectFastPatternTest567", DetectFastPatternTest567, 1); - UtRegisterTest("DetectFastPatternTest568", DetectFastPatternTest568, 1); - UtRegisterTest("DetectFastPatternTest569", DetectFastPatternTest569, 1); - UtRegisterTest("DetectFastPatternTest570", DetectFastPatternTest570, 1); - UtRegisterTest("DetectFastPatternTest571", DetectFastPatternTest571, 1); - UtRegisterTest("DetectFastPatternTest572", DetectFastPatternTest572, 1); - UtRegisterTest("DetectFastPatternTest573", DetectFastPatternTest573, 1); - UtRegisterTest("DetectFastPatternTest574", DetectFastPatternTest574, 1); - UtRegisterTest("DetectFastPatternTest575", DetectFastPatternTest575, 1); - UtRegisterTest("DetectFastPatternTest576", DetectFastPatternTest576, 1); - UtRegisterTest("DetectFastPatternTest577", DetectFastPatternTest577, 1); - UtRegisterTest("DetectFastPatternTest578", DetectFastPatternTest578, 1); - UtRegisterTest("DetectFastPatternTest579", DetectFastPatternTest579, 1); - UtRegisterTest("DetectFastPatternTest580", DetectFastPatternTest580, 1); - UtRegisterTest("DetectFastPatternTest581", DetectFastPatternTest581, 1); - UtRegisterTest("DetectFastPatternTest582", DetectFastPatternTest582, 1); - UtRegisterTest("DetectFastPatternTest583", DetectFastPatternTest583, 1); - UtRegisterTest("DetectFastPatternTest584", DetectFastPatternTest584, 1); - UtRegisterTest("DetectFastPatternTest585", DetectFastPatternTest585, 1); - UtRegisterTest("DetectFastPatternTest586", DetectFastPatternTest586, 1); - UtRegisterTest("DetectFastPatternTest587", DetectFastPatternTest587, 1); - UtRegisterTest("DetectFastPatternTest588", DetectFastPatternTest588, 1); + UtRegisterTest("DetectFastPatternTest548", DetectFastPatternTest548); + UtRegisterTest("DetectFastPatternTest549", DetectFastPatternTest549); + UtRegisterTest("DetectFastPatternTest550", DetectFastPatternTest550); + UtRegisterTest("DetectFastPatternTest551", DetectFastPatternTest551); + UtRegisterTest("DetectFastPatternTest552", DetectFastPatternTest552); + UtRegisterTest("DetectFastPatternTest553", DetectFastPatternTest553); + UtRegisterTest("DetectFastPatternTest554", DetectFastPatternTest554); + UtRegisterTest("DetectFastPatternTest555", DetectFastPatternTest555); + UtRegisterTest("DetectFastPatternTest556", DetectFastPatternTest556); + UtRegisterTest("DetectFastPatternTest557", DetectFastPatternTest557); + UtRegisterTest("DetectFastPatternTest558", DetectFastPatternTest558); + UtRegisterTest("DetectFastPatternTest559", DetectFastPatternTest559); + UtRegisterTest("DetectFastPatternTest560", DetectFastPatternTest560); + UtRegisterTest("DetectFastPatternTest561", DetectFastPatternTest561); + UtRegisterTest("DetectFastPatternTest562", DetectFastPatternTest562); + UtRegisterTest("DetectFastPatternTest563", DetectFastPatternTest563); + UtRegisterTest("DetectFastPatternTest564", DetectFastPatternTest564); + UtRegisterTest("DetectFastPatternTest565", DetectFastPatternTest565); + UtRegisterTest("DetectFastPatternTest566", DetectFastPatternTest566); + UtRegisterTest("DetectFastPatternTest567", DetectFastPatternTest567); + UtRegisterTest("DetectFastPatternTest568", DetectFastPatternTest568); + UtRegisterTest("DetectFastPatternTest569", DetectFastPatternTest569); + UtRegisterTest("DetectFastPatternTest570", DetectFastPatternTest570); + UtRegisterTest("DetectFastPatternTest571", DetectFastPatternTest571); + UtRegisterTest("DetectFastPatternTest572", DetectFastPatternTest572); + UtRegisterTest("DetectFastPatternTest573", DetectFastPatternTest573); + UtRegisterTest("DetectFastPatternTest574", DetectFastPatternTest574); + UtRegisterTest("DetectFastPatternTest575", DetectFastPatternTest575); + UtRegisterTest("DetectFastPatternTest576", DetectFastPatternTest576); + UtRegisterTest("DetectFastPatternTest577", DetectFastPatternTest577); + UtRegisterTest("DetectFastPatternTest578", DetectFastPatternTest578); + UtRegisterTest("DetectFastPatternTest579", DetectFastPatternTest579); + UtRegisterTest("DetectFastPatternTest580", DetectFastPatternTest580); + UtRegisterTest("DetectFastPatternTest581", DetectFastPatternTest581); + UtRegisterTest("DetectFastPatternTest582", DetectFastPatternTest582); + UtRegisterTest("DetectFastPatternTest583", DetectFastPatternTest583); + UtRegisterTest("DetectFastPatternTest584", DetectFastPatternTest584); + UtRegisterTest("DetectFastPatternTest585", DetectFastPatternTest585); + UtRegisterTest("DetectFastPatternTest586", DetectFastPatternTest586); + UtRegisterTest("DetectFastPatternTest587", DetectFastPatternTest587); + UtRegisterTest("DetectFastPatternTest588", DetectFastPatternTest588); /* http_user_agent fast_pattern tests ^ */ /* http_host fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest589", DetectFastPatternTest589, 1); - UtRegisterTest("DetectFastPatternTest590", DetectFastPatternTest590, 1); - UtRegisterTest("DetectFastPatternTest591", DetectFastPatternTest591, 1); - UtRegisterTest("DetectFastPatternTest592", DetectFastPatternTest592, 1); - UtRegisterTest("DetectFastPatternTest593", DetectFastPatternTest593, 1); - UtRegisterTest("DetectFastPatternTest594", DetectFastPatternTest594, 1); - UtRegisterTest("DetectFastPatternTest595", DetectFastPatternTest595, 1); - UtRegisterTest("DetectFastPatternTest596", DetectFastPatternTest596, 1); - UtRegisterTest("DetectFastPatternTest597", DetectFastPatternTest597, 1); - UtRegisterTest("DetectFastPatternTest598", DetectFastPatternTest598, 1); - UtRegisterTest("DetectFastPatternTest599", DetectFastPatternTest599, 1); - UtRegisterTest("DetectFastPatternTest600", DetectFastPatternTest600, 1); - UtRegisterTest("DetectFastPatternTest601", DetectFastPatternTest601, 1); - UtRegisterTest("DetectFastPatternTest602", DetectFastPatternTest602, 1); - UtRegisterTest("DetectFastPatternTest603", DetectFastPatternTest603, 1); - UtRegisterTest("DetectFastPatternTest604", DetectFastPatternTest604, 1); - UtRegisterTest("DetectFastPatternTest605", DetectFastPatternTest605, 1); - UtRegisterTest("DetectFastPatternTest606", DetectFastPatternTest606, 1); - UtRegisterTest("DetectFastPatternTest607", DetectFastPatternTest607, 1); - UtRegisterTest("DetectFastPatternTest608", DetectFastPatternTest608, 1); - UtRegisterTest("DetectFastPatternTest609", DetectFastPatternTest609, 1); - UtRegisterTest("DetectFastPatternTest610", DetectFastPatternTest610, 1); - UtRegisterTest("DetectFastPatternTest611", DetectFastPatternTest611, 1); - UtRegisterTest("DetectFastPatternTest612", DetectFastPatternTest612, 1); - UtRegisterTest("DetectFastPatternTest613", DetectFastPatternTest613, 1); - UtRegisterTest("DetectFastPatternTest614", DetectFastPatternTest614, 1); - UtRegisterTest("DetectFastPatternTest615", DetectFastPatternTest615, 1); - UtRegisterTest("DetectFastPatternTest616", DetectFastPatternTest616, 1); - UtRegisterTest("DetectFastPatternTest617", DetectFastPatternTest617, 1); - UtRegisterTest("DetectFastPatternTest618", DetectFastPatternTest618, 1); - UtRegisterTest("DetectFastPatternTest619", DetectFastPatternTest619, 1); - UtRegisterTest("DetectFastPatternTest620", DetectFastPatternTest620, 1); - UtRegisterTest("DetectFastPatternTest621", DetectFastPatternTest621, 1); - UtRegisterTest("DetectFastPatternTest622", DetectFastPatternTest622, 1); - UtRegisterTest("DetectFastPatternTest623", DetectFastPatternTest623, 1); - UtRegisterTest("DetectFastPatternTest624", DetectFastPatternTest624, 1); - UtRegisterTest("DetectFastPatternTest625", DetectFastPatternTest625, 1); - UtRegisterTest("DetectFastPatternTest626", DetectFastPatternTest626, 1); - UtRegisterTest("DetectFastPatternTest627", DetectFastPatternTest627, 1); - UtRegisterTest("DetectFastPatternTest628", DetectFastPatternTest628, 1); - UtRegisterTest("DetectFastPatternTest629", DetectFastPatternTest629, 1); + UtRegisterTest("DetectFastPatternTest589", DetectFastPatternTest589); + UtRegisterTest("DetectFastPatternTest590", DetectFastPatternTest590); + UtRegisterTest("DetectFastPatternTest591", DetectFastPatternTest591); + UtRegisterTest("DetectFastPatternTest592", DetectFastPatternTest592); + UtRegisterTest("DetectFastPatternTest593", DetectFastPatternTest593); + UtRegisterTest("DetectFastPatternTest594", DetectFastPatternTest594); + UtRegisterTest("DetectFastPatternTest595", DetectFastPatternTest595); + UtRegisterTest("DetectFastPatternTest596", DetectFastPatternTest596); + UtRegisterTest("DetectFastPatternTest597", DetectFastPatternTest597); + UtRegisterTest("DetectFastPatternTest598", DetectFastPatternTest598); + UtRegisterTest("DetectFastPatternTest599", DetectFastPatternTest599); + UtRegisterTest("DetectFastPatternTest600", DetectFastPatternTest600); + UtRegisterTest("DetectFastPatternTest601", DetectFastPatternTest601); + UtRegisterTest("DetectFastPatternTest602", DetectFastPatternTest602); + UtRegisterTest("DetectFastPatternTest603", DetectFastPatternTest603); + UtRegisterTest("DetectFastPatternTest604", DetectFastPatternTest604); + UtRegisterTest("DetectFastPatternTest605", DetectFastPatternTest605); + UtRegisterTest("DetectFastPatternTest606", DetectFastPatternTest606); + UtRegisterTest("DetectFastPatternTest607", DetectFastPatternTest607); + UtRegisterTest("DetectFastPatternTest608", DetectFastPatternTest608); + UtRegisterTest("DetectFastPatternTest609", DetectFastPatternTest609); + UtRegisterTest("DetectFastPatternTest610", DetectFastPatternTest610); + UtRegisterTest("DetectFastPatternTest611", DetectFastPatternTest611); + UtRegisterTest("DetectFastPatternTest612", DetectFastPatternTest612); + UtRegisterTest("DetectFastPatternTest613", DetectFastPatternTest613); + UtRegisterTest("DetectFastPatternTest614", DetectFastPatternTest614); + UtRegisterTest("DetectFastPatternTest615", DetectFastPatternTest615); + UtRegisterTest("DetectFastPatternTest616", DetectFastPatternTest616); + UtRegisterTest("DetectFastPatternTest617", DetectFastPatternTest617); + UtRegisterTest("DetectFastPatternTest618", DetectFastPatternTest618); + UtRegisterTest("DetectFastPatternTest619", DetectFastPatternTest619); + UtRegisterTest("DetectFastPatternTest620", DetectFastPatternTest620); + UtRegisterTest("DetectFastPatternTest621", DetectFastPatternTest621); + UtRegisterTest("DetectFastPatternTest622", DetectFastPatternTest622); + UtRegisterTest("DetectFastPatternTest623", DetectFastPatternTest623); + UtRegisterTest("DetectFastPatternTest624", DetectFastPatternTest624); + UtRegisterTest("DetectFastPatternTest625", DetectFastPatternTest625); + UtRegisterTest("DetectFastPatternTest626", DetectFastPatternTest626); + UtRegisterTest("DetectFastPatternTest627", DetectFastPatternTest627); + UtRegisterTest("DetectFastPatternTest628", DetectFastPatternTest628); + UtRegisterTest("DetectFastPatternTest629", DetectFastPatternTest629); /* http_host fast_pattern tests ^ */ /* http_rawhost fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest630", DetectFastPatternTest630, 1); - UtRegisterTest("DetectFastPatternTest631", DetectFastPatternTest631, 1); - UtRegisterTest("DetectFastPatternTest632", DetectFastPatternTest632, 1); - UtRegisterTest("DetectFastPatternTest633", DetectFastPatternTest633, 1); - UtRegisterTest("DetectFastPatternTest634", DetectFastPatternTest634, 1); - UtRegisterTest("DetectFastPatternTest635", DetectFastPatternTest635, 1); - UtRegisterTest("DetectFastPatternTest636", DetectFastPatternTest636, 1); - UtRegisterTest("DetectFastPatternTest637", DetectFastPatternTest637, 1); - UtRegisterTest("DetectFastPatternTest638", DetectFastPatternTest638, 1); - UtRegisterTest("DetectFastPatternTest639", DetectFastPatternTest639, 1); - UtRegisterTest("DetectFastPatternTest640", DetectFastPatternTest640, 1); - UtRegisterTest("DetectFastPatternTest641", DetectFastPatternTest641, 1); - UtRegisterTest("DetectFastPatternTest642", DetectFastPatternTest642, 1); - UtRegisterTest("DetectFastPatternTest643", DetectFastPatternTest643, 1); - UtRegisterTest("DetectFastPatternTest644", DetectFastPatternTest644, 1); - UtRegisterTest("DetectFastPatternTest645", DetectFastPatternTest645, 1); - UtRegisterTest("DetectFastPatternTest646", DetectFastPatternTest646, 1); - UtRegisterTest("DetectFastPatternTest647", DetectFastPatternTest647, 1); - UtRegisterTest("DetectFastPatternTest648", DetectFastPatternTest648, 1); - UtRegisterTest("DetectFastPatternTest649", DetectFastPatternTest649, 1); - UtRegisterTest("DetectFastPatternTest650", DetectFastPatternTest650, 1); - UtRegisterTest("DetectFastPatternTest651", DetectFastPatternTest651, 1); - UtRegisterTest("DetectFastPatternTest652", DetectFastPatternTest652, 1); - UtRegisterTest("DetectFastPatternTest653", DetectFastPatternTest653, 1); - UtRegisterTest("DetectFastPatternTest654", DetectFastPatternTest654, 1); - UtRegisterTest("DetectFastPatternTest655", DetectFastPatternTest655, 1); - UtRegisterTest("DetectFastPatternTest656", DetectFastPatternTest656, 1); - UtRegisterTest("DetectFastPatternTest657", DetectFastPatternTest657, 1); - UtRegisterTest("DetectFastPatternTest658", DetectFastPatternTest658, 1); - UtRegisterTest("DetectFastPatternTest659", DetectFastPatternTest659, 1); - UtRegisterTest("DetectFastPatternTest660", DetectFastPatternTest660, 1); - UtRegisterTest("DetectFastPatternTest661", DetectFastPatternTest661, 1); - UtRegisterTest("DetectFastPatternTest662", DetectFastPatternTest662, 1); - UtRegisterTest("DetectFastPatternTest663", DetectFastPatternTest663, 1); - UtRegisterTest("DetectFastPatternTest664", DetectFastPatternTest664, 1); - UtRegisterTest("DetectFastPatternTest665", DetectFastPatternTest665, 1); - UtRegisterTest("DetectFastPatternTest666", DetectFastPatternTest666, 1); - UtRegisterTest("DetectFastPatternTest667", DetectFastPatternTest667, 1); - UtRegisterTest("DetectFastPatternTest668", DetectFastPatternTest668, 1); - UtRegisterTest("DetectFastPatternTest669", DetectFastPatternTest669, 1); - UtRegisterTest("DetectFastPatternTest670", DetectFastPatternTest670, 1); + UtRegisterTest("DetectFastPatternTest630", DetectFastPatternTest630); + UtRegisterTest("DetectFastPatternTest631", DetectFastPatternTest631); + UtRegisterTest("DetectFastPatternTest632", DetectFastPatternTest632); + UtRegisterTest("DetectFastPatternTest633", DetectFastPatternTest633); + UtRegisterTest("DetectFastPatternTest634", DetectFastPatternTest634); + UtRegisterTest("DetectFastPatternTest635", DetectFastPatternTest635); + UtRegisterTest("DetectFastPatternTest636", DetectFastPatternTest636); + UtRegisterTest("DetectFastPatternTest637", DetectFastPatternTest637); + UtRegisterTest("DetectFastPatternTest638", DetectFastPatternTest638); + UtRegisterTest("DetectFastPatternTest639", DetectFastPatternTest639); + UtRegisterTest("DetectFastPatternTest640", DetectFastPatternTest640); + UtRegisterTest("DetectFastPatternTest641", DetectFastPatternTest641); + UtRegisterTest("DetectFastPatternTest642", DetectFastPatternTest642); + UtRegisterTest("DetectFastPatternTest643", DetectFastPatternTest643); + UtRegisterTest("DetectFastPatternTest644", DetectFastPatternTest644); + UtRegisterTest("DetectFastPatternTest645", DetectFastPatternTest645); + UtRegisterTest("DetectFastPatternTest646", DetectFastPatternTest646); + UtRegisterTest("DetectFastPatternTest647", DetectFastPatternTest647); + UtRegisterTest("DetectFastPatternTest648", DetectFastPatternTest648); + UtRegisterTest("DetectFastPatternTest649", DetectFastPatternTest649); + UtRegisterTest("DetectFastPatternTest650", DetectFastPatternTest650); + UtRegisterTest("DetectFastPatternTest651", DetectFastPatternTest651); + UtRegisterTest("DetectFastPatternTest652", DetectFastPatternTest652); + UtRegisterTest("DetectFastPatternTest653", DetectFastPatternTest653); + UtRegisterTest("DetectFastPatternTest654", DetectFastPatternTest654); + UtRegisterTest("DetectFastPatternTest655", DetectFastPatternTest655); + UtRegisterTest("DetectFastPatternTest656", DetectFastPatternTest656); + UtRegisterTest("DetectFastPatternTest657", DetectFastPatternTest657); + UtRegisterTest("DetectFastPatternTest658", DetectFastPatternTest658); + UtRegisterTest("DetectFastPatternTest659", DetectFastPatternTest659); + UtRegisterTest("DetectFastPatternTest660", DetectFastPatternTest660); + UtRegisterTest("DetectFastPatternTest661", DetectFastPatternTest661); + UtRegisterTest("DetectFastPatternTest662", DetectFastPatternTest662); + UtRegisterTest("DetectFastPatternTest663", DetectFastPatternTest663); + UtRegisterTest("DetectFastPatternTest664", DetectFastPatternTest664); + UtRegisterTest("DetectFastPatternTest665", DetectFastPatternTest665); + UtRegisterTest("DetectFastPatternTest666", DetectFastPatternTest666); + UtRegisterTest("DetectFastPatternTest667", DetectFastPatternTest667); + UtRegisterTest("DetectFastPatternTest668", DetectFastPatternTest668); + UtRegisterTest("DetectFastPatternTest669", DetectFastPatternTest669); + UtRegisterTest("DetectFastPatternTest670", DetectFastPatternTest670); /* Unittest to check * - if we assign different content_ids to duplicate patterns, but one of the @@ -20148,7 +20148,7 @@ void DetectFastPatternRegisterTests(void) * - if 2 unique patterns get unique ids. * - if 2 duplicate patterns, with no chop set get unique ids. */ - UtRegisterTest("DetectFastPatternTest671", DetectFastPatternTest671, 1); + UtRegisterTest("DetectFastPatternTest671", DetectFastPatternTest671); #endif return; diff --git a/src/detect-file-data.c b/src/detect-file-data.c index f8654b017f01..a5cb650788f6 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -273,10 +273,10 @@ static int DetectFiledataParseTest05(void) void DetectFiledataRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectFiledataParseTest01", DetectFiledataParseTest01, 1); - UtRegisterTest("DetectFiledataParseTest02", DetectFiledataParseTest02, 1); - UtRegisterTest("DetectFiledataParseTest03", DetectFiledataParseTest03, 1); - UtRegisterTest("DetectFiledataParseTest04", DetectFiledataParseTest04, 1); - UtRegisterTest("DetectFiledataParseTest05", DetectFiledataParseTest05, 1); + UtRegisterTest("DetectFiledataParseTest01", DetectFiledataParseTest01); + UtRegisterTest("DetectFiledataParseTest02", DetectFiledataParseTest02); + UtRegisterTest("DetectFiledataParseTest03", DetectFiledataParseTest03); + UtRegisterTest("DetectFiledataParseTest04", DetectFiledataParseTest04); + UtRegisterTest("DetectFiledataParseTest05", DetectFiledataParseTest05); #endif } diff --git a/src/detect-fileext.c b/src/detect-fileext.c index 7b5e9103d4f3..e4f146e29f53 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -308,8 +308,8 @@ int DetectFileextTestParse03 (void) void DetectFileextRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectFileextTestParse01", DetectFileextTestParse01, 1); - UtRegisterTest("DetectFileextTestParse02", DetectFileextTestParse02, 1); - UtRegisterTest("DetectFileextTestParse03", DetectFileextTestParse03, 1); + UtRegisterTest("DetectFileextTestParse01", DetectFileextTestParse01); + UtRegisterTest("DetectFileextTestParse02", DetectFileextTestParse02); + UtRegisterTest("DetectFileextTestParse03", DetectFileextTestParse03); #endif /* UNITTESTS */ } diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index ab85feed3e3b..c854005a1675 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -498,8 +498,8 @@ int DetectFilemagicTestParse03 (void) void DetectFilemagicRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectFilemagicTestParse01", DetectFilemagicTestParse01, 1); - UtRegisterTest("DetectFilemagicTestParse02", DetectFilemagicTestParse02, 1); - UtRegisterTest("DetectFilemagicTestParse03", DetectFilemagicTestParse03, 1); + UtRegisterTest("DetectFilemagicTestParse01", DetectFilemagicTestParse01); + UtRegisterTest("DetectFilemagicTestParse02", DetectFilemagicTestParse02); + UtRegisterTest("DetectFilemagicTestParse03", DetectFilemagicTestParse03); #endif /* UNITTESTS */ } diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index 87f3f35e9b34..faedb11c0b07 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -420,7 +420,7 @@ static int MD5MatchTest01(void) void DetectFileMd5RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("MD5MatchTest01", MD5MatchTest01, 1); + UtRegisterTest("MD5MatchTest01", MD5MatchTest01); #endif } diff --git a/src/detect-filename.c b/src/detect-filename.c index 8e5ddc1c0fee..2bc9a09d4f38 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -314,8 +314,8 @@ int DetectFilenameTestParse03 (void) void DetectFilenameRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectFilenameTestParse01", DetectFilenameTestParse01, 1); - UtRegisterTest("DetectFilenameTestParse02", DetectFilenameTestParse02, 1); - UtRegisterTest("DetectFilenameTestParse03", DetectFilenameTestParse03, 1); + UtRegisterTest("DetectFilenameTestParse01", DetectFilenameTestParse01); + UtRegisterTest("DetectFilenameTestParse02", DetectFilenameTestParse02); + UtRegisterTest("DetectFilenameTestParse03", DetectFilenameTestParse03); #endif /* UNITTESTS */ } diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 17a01216b8a3..d65b594f1d29 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -522,11 +522,11 @@ static int DetectFilesizeSetpTest01(void) void DetectFilesizeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectFilesizeParseTest01", DetectFilesizeParseTest01, 1); - UtRegisterTest("DetectFilesizeParseTest02", DetectFilesizeParseTest02, 1); - UtRegisterTest("DetectFilesizeParseTest03", DetectFilesizeParseTest03, 1); - UtRegisterTest("DetectFilesizeParseTest04", DetectFilesizeParseTest04, 1); - UtRegisterTest("DetectFilesizeParseTest05", DetectFilesizeParseTest05, 1); - UtRegisterTest("DetectFilesizeSetpTest01", DetectFilesizeSetpTest01, 1); + UtRegisterTest("DetectFilesizeParseTest01", DetectFilesizeParseTest01); + UtRegisterTest("DetectFilesizeParseTest02", DetectFilesizeParseTest02); + UtRegisterTest("DetectFilesizeParseTest03", DetectFilesizeParseTest03); + UtRegisterTest("DetectFilesizeParseTest04", DetectFilesizeParseTest04); + UtRegisterTest("DetectFilesizeParseTest05", DetectFilesizeParseTest05); + UtRegisterTest("DetectFilesizeSetpTest01", DetectFilesizeSetpTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-flags.c b/src/detect-flags.c index bdf3147d0caa..860d38a86a76 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -1363,22 +1363,22 @@ static int FlagsTestParse17(void) void FlagsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("FlagsTestParse01", FlagsTestParse01, 1); - UtRegisterTest("FlagsTestParse02", FlagsTestParse02, 1); - UtRegisterTest("FlagsTestParse03", FlagsTestParse03, 1); - UtRegisterTest("FlagsTestParse04", FlagsTestParse04, 1); - UtRegisterTest("FlagsTestParse05", FlagsTestParse05, 1); - UtRegisterTest("FlagsTestParse06", FlagsTestParse06, 1); - UtRegisterTest("FlagsTestParse07", FlagsTestParse07, 1); - UtRegisterTest("FlagsTestParse08", FlagsTestParse08, 1); - UtRegisterTest("FlagsTestParse09", FlagsTestParse09, 1); - UtRegisterTest("FlagsTestParse10", FlagsTestParse10, 1); - UtRegisterTest("FlagsTestParse11", FlagsTestParse11, 1); - UtRegisterTest("FlagsTestParse12", FlagsTestParse12, 1); - UtRegisterTest("FlagsTestParse13", FlagsTestParse13, 1); - UtRegisterTest("FlagsTestParse14", FlagsTestParse14, 1); - UtRegisterTest("FlagsTestParse15", FlagsTestParse15, 1); - UtRegisterTest("FlagsTestParse16", FlagsTestParse16, 1); - UtRegisterTest("FlagsTestParse17", FlagsTestParse17, 1); + UtRegisterTest("FlagsTestParse01", FlagsTestParse01); + UtRegisterTest("FlagsTestParse02", FlagsTestParse02); + UtRegisterTest("FlagsTestParse03", FlagsTestParse03); + UtRegisterTest("FlagsTestParse04", FlagsTestParse04); + UtRegisterTest("FlagsTestParse05", FlagsTestParse05); + UtRegisterTest("FlagsTestParse06", FlagsTestParse06); + UtRegisterTest("FlagsTestParse07", FlagsTestParse07); + UtRegisterTest("FlagsTestParse08", FlagsTestParse08); + UtRegisterTest("FlagsTestParse09", FlagsTestParse09); + UtRegisterTest("FlagsTestParse10", FlagsTestParse10); + UtRegisterTest("FlagsTestParse11", FlagsTestParse11); + UtRegisterTest("FlagsTestParse12", FlagsTestParse12); + UtRegisterTest("FlagsTestParse13", FlagsTestParse13); + UtRegisterTest("FlagsTestParse14", FlagsTestParse14); + UtRegisterTest("FlagsTestParse15", FlagsTestParse15); + UtRegisterTest("FlagsTestParse16", FlagsTestParse16); + UtRegisterTest("FlagsTestParse17", FlagsTestParse17); #endif /* UNITTESTS */ } diff --git a/src/detect-flow.c b/src/detect-flow.c index 9c2db944c305..652dc654d6a5 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -1087,41 +1087,41 @@ static int DetectFlowSigTest01(void) void DetectFlowRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectFlowTestParse01", DetectFlowTestParse01, 1); - UtRegisterTest("DetectFlowTestParse02", DetectFlowTestParse02, 1); - UtRegisterTest("DetectFlowTestParse03", DetectFlowTestParse03, 1); - UtRegisterTest("DetectFlowTestParse04", DetectFlowTestParse04, 1); - UtRegisterTest("DetectFlowTestParse05", DetectFlowTestParse05, 1); - UtRegisterTest("DetectFlowTestParse06", DetectFlowTestParse06, 1); - UtRegisterTest("DetectFlowTestParse07", DetectFlowTestParse07, 1); - UtRegisterTest("DetectFlowTestParse08", DetectFlowTestParse08, 1); - UtRegisterTest("DetectFlowTestParse09", DetectFlowTestParse09, 1); - UtRegisterTest("DetectFlowTestParse10", DetectFlowTestParse10, 1); - UtRegisterTest("DetectFlowTestParse11", DetectFlowTestParse11, 1); - UtRegisterTest("DetectFlowTestParseNocase01", DetectFlowTestParseNocase01, 1); - UtRegisterTest("DetectFlowTestParseNocase02", DetectFlowTestParseNocase02, 1); - UtRegisterTest("DetectFlowTestParseNocase03", DetectFlowTestParseNocase03, 1); - UtRegisterTest("DetectFlowTestParseNocase04", DetectFlowTestParseNocase04, 1); - UtRegisterTest("DetectFlowTestParseNocase05", DetectFlowTestParseNocase05, 1); - UtRegisterTest("DetectFlowTestParseNocase06", DetectFlowTestParseNocase06, 1); - UtRegisterTest("DetectFlowTestParseNocase07", DetectFlowTestParseNocase07, 1); - UtRegisterTest("DetectFlowTestParseNocase08", DetectFlowTestParseNocase08, 1); - UtRegisterTest("DetectFlowTestParseNocase09", DetectFlowTestParseNocase09, 1); - UtRegisterTest("DetectFlowTestParseNocase10", DetectFlowTestParseNocase10, 1); - UtRegisterTest("DetectFlowTestParseNocase11", DetectFlowTestParseNocase11, 1); - UtRegisterTest("DetectFlowTestParse12", DetectFlowTestParse12, 1); - UtRegisterTest("DetectFlowTestParse13", DetectFlowTestParse13, 1); - UtRegisterTest("DetectFlowTestParse14", DetectFlowTestParse14, 1); - UtRegisterTest("DetectFlowTestParse15", DetectFlowTestParse15, 1); - UtRegisterTest("DetectFlowTestParse16", DetectFlowTestParse16, 1); - UtRegisterTest("DetectFlowTestParse17", DetectFlowTestParse17, 1); - UtRegisterTest("DetectFlowTestParse18", DetectFlowTestParse18, 1); - UtRegisterTest("DetectFlowTestParseNocase18", DetectFlowTestParseNocase18, 1); - UtRegisterTest("DetectFlowTestParse19", DetectFlowTestParse19, 1); - UtRegisterTest("DetectFlowTestParse20", DetectFlowTestParse20, 1); - UtRegisterTest("DetectFlowTestParseNocase20", DetectFlowTestParseNocase20, 1); - UtRegisterTest("DetectFlowTestParse21", DetectFlowTestParse21, 1); - - UtRegisterTest("DetectFlowSigTest01", DetectFlowSigTest01, 1); + UtRegisterTest("DetectFlowTestParse01", DetectFlowTestParse01); + UtRegisterTest("DetectFlowTestParse02", DetectFlowTestParse02); + UtRegisterTest("DetectFlowTestParse03", DetectFlowTestParse03); + UtRegisterTest("DetectFlowTestParse04", DetectFlowTestParse04); + UtRegisterTest("DetectFlowTestParse05", DetectFlowTestParse05); + UtRegisterTest("DetectFlowTestParse06", DetectFlowTestParse06); + UtRegisterTest("DetectFlowTestParse07", DetectFlowTestParse07); + UtRegisterTest("DetectFlowTestParse08", DetectFlowTestParse08); + UtRegisterTest("DetectFlowTestParse09", DetectFlowTestParse09); + UtRegisterTest("DetectFlowTestParse10", DetectFlowTestParse10); + UtRegisterTest("DetectFlowTestParse11", DetectFlowTestParse11); + UtRegisterTest("DetectFlowTestParseNocase01", DetectFlowTestParseNocase01); + UtRegisterTest("DetectFlowTestParseNocase02", DetectFlowTestParseNocase02); + UtRegisterTest("DetectFlowTestParseNocase03", DetectFlowTestParseNocase03); + UtRegisterTest("DetectFlowTestParseNocase04", DetectFlowTestParseNocase04); + UtRegisterTest("DetectFlowTestParseNocase05", DetectFlowTestParseNocase05); + UtRegisterTest("DetectFlowTestParseNocase06", DetectFlowTestParseNocase06); + UtRegisterTest("DetectFlowTestParseNocase07", DetectFlowTestParseNocase07); + UtRegisterTest("DetectFlowTestParseNocase08", DetectFlowTestParseNocase08); + UtRegisterTest("DetectFlowTestParseNocase09", DetectFlowTestParseNocase09); + UtRegisterTest("DetectFlowTestParseNocase10", DetectFlowTestParseNocase10); + UtRegisterTest("DetectFlowTestParseNocase11", DetectFlowTestParseNocase11); + UtRegisterTest("DetectFlowTestParse12", DetectFlowTestParse12); + UtRegisterTest("DetectFlowTestParse13", DetectFlowTestParse13); + UtRegisterTest("DetectFlowTestParse14", DetectFlowTestParse14); + UtRegisterTest("DetectFlowTestParse15", DetectFlowTestParse15); + UtRegisterTest("DetectFlowTestParse16", DetectFlowTestParse16); + UtRegisterTest("DetectFlowTestParse17", DetectFlowTestParse17); + UtRegisterTest("DetectFlowTestParse18", DetectFlowTestParse18); + UtRegisterTest("DetectFlowTestParseNocase18", DetectFlowTestParseNocase18); + UtRegisterTest("DetectFlowTestParse19", DetectFlowTestParse19); + UtRegisterTest("DetectFlowTestParse20", DetectFlowTestParse20); + UtRegisterTest("DetectFlowTestParseNocase20", DetectFlowTestParseNocase20); + UtRegisterTest("DetectFlowTestParse21", DetectFlowTestParse21); + + UtRegisterTest("DetectFlowSigTest01", DetectFlowSigTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 792c1e1ef776..6853f323fbbd 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -1143,14 +1143,14 @@ static int FlowBitsTestSig08(void) void FlowBitsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01, 1); - UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01, 1); - UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02, 1); - UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03, 1); - UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04, 1); - UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05, 1); - UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06, 1); - UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07, 1); - UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08, 1); + UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01); + UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01); + UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02); + UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03); + UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04); + UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05); + UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06); + UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07); + UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08); #endif /* UNITTESTS */ } diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 54303cd3ae4c..80ddfe9d356e 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -2128,51 +2128,33 @@ int DetectFlowintTestPacket03Real() void DetectFlowintRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectFlowintTestParseVal01", - DetectFlowintTestParseVal01, 1); - UtRegisterTest("DetectFlowintTestParseVar01", - DetectFlowintTestParseVar01, 1); - UtRegisterTest("DetectFlowintTestParseVal02", - DetectFlowintTestParseVal02, 1); - UtRegisterTest("DetectFlowintTestParseVar02", - DetectFlowintTestParseVar02, 1); - UtRegisterTest("DetectFlowintTestParseVal03", - DetectFlowintTestParseVal03, 1); - UtRegisterTest("DetectFlowintTestParseVar03", - DetectFlowintTestParseVar03, 1); - UtRegisterTest("DetectFlowintTestParseVal04", - DetectFlowintTestParseVal04, 1); - UtRegisterTest("DetectFlowintTestParseVar04", - DetectFlowintTestParseVar04, 1); - UtRegisterTest("DetectFlowintTestParseVal05", - DetectFlowintTestParseVal05, 1); - UtRegisterTest("DetectFlowintTestParseVar05", - DetectFlowintTestParseVar05, 1); - UtRegisterTest("DetectFlowintTestParseVal06", - DetectFlowintTestParseVal06, 1); - UtRegisterTest("DetectFlowintTestParseVar06", - DetectFlowintTestParseVar06, 1); - UtRegisterTest("DetectFlowintTestParseVal07", - DetectFlowintTestParseVal07, 1); - UtRegisterTest("DetectFlowintTestParseVar07", - DetectFlowintTestParseVar07, 1); - UtRegisterTest("DetectFlowintTestParseVal08", - DetectFlowintTestParseVal08, 1); - UtRegisterTest("DetectFlowintTestParseVar08", - DetectFlowintTestParseVar08, 1); - UtRegisterTest("DetectFlowintTestParseVal09", - DetectFlowintTestParseVal09, 1); - UtRegisterTest("DetectFlowintTestParseVar09", - DetectFlowintTestParseVar09, 1); + UtRegisterTest("DetectFlowintTestParseVal01", DetectFlowintTestParseVal01); + UtRegisterTest("DetectFlowintTestParseVar01", DetectFlowintTestParseVar01); + UtRegisterTest("DetectFlowintTestParseVal02", DetectFlowintTestParseVal02); + UtRegisterTest("DetectFlowintTestParseVar02", DetectFlowintTestParseVar02); + UtRegisterTest("DetectFlowintTestParseVal03", DetectFlowintTestParseVal03); + UtRegisterTest("DetectFlowintTestParseVar03", DetectFlowintTestParseVar03); + UtRegisterTest("DetectFlowintTestParseVal04", DetectFlowintTestParseVal04); + UtRegisterTest("DetectFlowintTestParseVar04", DetectFlowintTestParseVar04); + UtRegisterTest("DetectFlowintTestParseVal05", DetectFlowintTestParseVal05); + UtRegisterTest("DetectFlowintTestParseVar05", DetectFlowintTestParseVar05); + UtRegisterTest("DetectFlowintTestParseVal06", DetectFlowintTestParseVal06); + UtRegisterTest("DetectFlowintTestParseVar06", DetectFlowintTestParseVar06); + UtRegisterTest("DetectFlowintTestParseVal07", DetectFlowintTestParseVal07); + UtRegisterTest("DetectFlowintTestParseVar07", DetectFlowintTestParseVar07); + UtRegisterTest("DetectFlowintTestParseVal08", DetectFlowintTestParseVal08); + UtRegisterTest("DetectFlowintTestParseVar08", DetectFlowintTestParseVar08); + UtRegisterTest("DetectFlowintTestParseVal09", DetectFlowintTestParseVal09); + UtRegisterTest("DetectFlowintTestParseVar09", DetectFlowintTestParseVar09); UtRegisterTest("DetectFlowintTestParseIsset10", - DetectFlowintTestParseIsset10, 1); + DetectFlowintTestParseIsset10); UtRegisterTest("DetectFlowintTestParseInvalidSyntaxis01", - DetectFlowintTestParseInvalidSyntaxis01, 1); + DetectFlowintTestParseInvalidSyntaxis01); UtRegisterTest("DetectFlowintTestPacket01Real", - DetectFlowintTestPacket01Real, 1); + DetectFlowintTestPacket01Real); UtRegisterTest("DetectFlowintTestPacket02Real", - DetectFlowintTestPacket02Real, 1); + DetectFlowintTestPacket02Real); UtRegisterTest("DetectFlowintTestPacket03Real", - DetectFlowintTestPacket03Real, 1); + DetectFlowintTestPacket03Real); #endif /* UNITTESTS */ } diff --git a/src/detect-fragbits.c b/src/detect-fragbits.c index 663735cc14f4..a60f9e22a79d 100644 --- a/src/detect-fragbits.c +++ b/src/detect-fragbits.c @@ -574,9 +574,9 @@ static int FragBitsTestParse04 (void) void FragBitsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("FragBitsTestParse01", FragBitsTestParse01, 1); - UtRegisterTest("FragBitsTestParse02", FragBitsTestParse02, 1); - UtRegisterTest("FragBitsTestParse03", FragBitsTestParse03, 1); - UtRegisterTest("FragBitsTestParse04", FragBitsTestParse04, 1); + UtRegisterTest("FragBitsTestParse01", FragBitsTestParse01); + UtRegisterTest("FragBitsTestParse02", FragBitsTestParse02); + UtRegisterTest("FragBitsTestParse03", FragBitsTestParse03); + UtRegisterTest("FragBitsTestParse04", FragBitsTestParse04); #endif /* UNITTESTS */ } diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index 62e1852d2933..fed8f5584cd2 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -387,10 +387,10 @@ int DetectFragOffsetMatchTest01 (void) void DetectFragOffsetRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("DetectFragOffsetParseTest01", DetectFragOffsetParseTest01, 1); - UtRegisterTest("DetectFragOffsetParseTest02", DetectFragOffsetParseTest02, 1); - UtRegisterTest("DetectFragOffsetParseTest03", DetectFragOffsetParseTest03, 1); - UtRegisterTest("DetectFragOffsetMatchTest01", DetectFragOffsetMatchTest01, 1); + UtRegisterTest("DetectFragOffsetParseTest01", DetectFragOffsetParseTest01); + UtRegisterTest("DetectFragOffsetParseTest02", DetectFragOffsetParseTest02); + UtRegisterTest("DetectFragOffsetParseTest03", DetectFragOffsetParseTest03); + UtRegisterTest("DetectFragOffsetMatchTest01", DetectFragOffsetMatchTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-ftpbounce.c b/src/detect-ftpbounce.c index 39e1c5a2a027..f4102089b397 100644 --- a/src/detect-ftpbounce.c +++ b/src/detect-ftpbounce.c @@ -551,10 +551,10 @@ static int DetectFtpbounceTestALMatch03(void) void DetectFtpbounceRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectFtpbounceTestSetup01", DetectFtpbounceTestSetup01, 1); + UtRegisterTest("DetectFtpbounceTestSetup01", DetectFtpbounceTestSetup01); UtRegisterTest("DetectFtpbounceTestALMatch02", - DetectFtpbounceTestALMatch02, 1); + DetectFtpbounceTestALMatch02); UtRegisterTest("DetectFtpbounceTestALMatch03", - DetectFtpbounceTestALMatch03, 1); + DetectFtpbounceTestALMatch03); #endif /* UNITTESTS */ } diff --git a/src/detect-geoip.c b/src/detect-geoip.c index 53c950f88c82..0b1d29a3d262 100644 --- a/src/detect-geoip.c +++ b/src/detect-geoip.c @@ -597,21 +597,21 @@ static int GeoipMatchTest07(void) static void DetectGeoipRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("GeoipParseTest01", GeoipParseTest01, 1); - UtRegisterTest("GeoipParseTest02", GeoipParseTest02, 1); - UtRegisterTest("GeoipParseTest03", GeoipParseTest03, 1); - UtRegisterTest("GeoipParseTest04", GeoipParseTest04, 1); - UtRegisterTest("GeoipParseTest05", GeoipParseTest05, 1); - UtRegisterTest("GeoipParseTest06", GeoipParseTest06, 1); - UtRegisterTest("GeoipParseTest07", GeoipParseTest07, 1); - - UtRegisterTest("GeoipMatchTest01", GeoipMatchTest01, 1); - UtRegisterTest("GeoipMatchTest02", GeoipMatchTest02, 1); - UtRegisterTest("GeoipMatchTest03", GeoipMatchTest03, 1); - UtRegisterTest("GeoipMatchTest04", GeoipMatchTest04, 2); - UtRegisterTest("GeoipMatchTest05", GeoipMatchTest05, 1); - UtRegisterTest("GeoipMatchTest06", GeoipMatchTest06, 1); - UtRegisterTest("GeoipMatchTest07", GeoipMatchTest07, 2); + UtRegisterTest("GeoipParseTest01", GeoipParseTest01); + UtRegisterTest("GeoipParseTest02", GeoipParseTest02); + UtRegisterTest("GeoipParseTest03", GeoipParseTest03); + UtRegisterTest("GeoipParseTest04", GeoipParseTest04); + UtRegisterTest("GeoipParseTest05", GeoipParseTest05); + UtRegisterTest("GeoipParseTest06", GeoipParseTest06); + UtRegisterTest("GeoipParseTest07", GeoipParseTest07); + + UtRegisterTest("GeoipMatchTest01", GeoipMatchTest01); + UtRegisterTest("GeoipMatchTest02", GeoipMatchTest02); + UtRegisterTest("GeoipMatchTest03", GeoipMatchTest03); + UtRegisterTest("GeoipMatchTest04", GeoipMatchTest04); + UtRegisterTest("GeoipMatchTest05", GeoipMatchTest05); + UtRegisterTest("GeoipMatchTest06", GeoipMatchTest06); + UtRegisterTest("GeoipMatchTest07", GeoipMatchTest07); #endif /* UNITTESTS */ } diff --git a/src/detect-gid.c b/src/detect-gid.c index f63ea28a7405..4cbbc8a9e123 100644 --- a/src/detect-gid.c +++ b/src/detect-gid.c @@ -195,8 +195,8 @@ static int GidTestParse03 (void) void GidRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("GidTestParse01", GidTestParse01, 1); - UtRegisterTest("GidTestParse02", GidTestParse02, 1); - UtRegisterTest("GidTestParse03", GidTestParse03, 1); + UtRegisterTest("GidTestParse01", GidTestParse01); + UtRegisterTest("GidTestParse02", GidTestParse02); + UtRegisterTest("GidTestParse03", GidTestParse03); #endif /* UNITTESTS */ } diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index ad1fce57b5c0..362dbf598b05 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -1456,18 +1456,18 @@ static int HostBitsTestSig08(void) void HostBitsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HostBitsTestParse01", HostBitsTestParse01, 1); - UtRegisterTest("HostBitsTestSig01", HostBitsTestSig01, 1); - UtRegisterTest("HostBitsTestSig02", HostBitsTestSig02, 1); + UtRegisterTest("HostBitsTestParse01", HostBitsTestParse01); + UtRegisterTest("HostBitsTestSig01", HostBitsTestSig01); + UtRegisterTest("HostBitsTestSig02", HostBitsTestSig02); #if 0 UtRegisterTest("HostBitsTestSig03", HostBitsTestSig03, 0); #endif - UtRegisterTest("HostBitsTestSig04", HostBitsTestSig04, 1); - UtRegisterTest("HostBitsTestSig05", HostBitsTestSig05, 1); + UtRegisterTest("HostBitsTestSig04", HostBitsTestSig04); + UtRegisterTest("HostBitsTestSig05", HostBitsTestSig05); #if 0 UtRegisterTest("HostBitsTestSig06", HostBitsTestSig06, 1); #endif - UtRegisterTest("HostBitsTestSig07", HostBitsTestSig07, 1); - UtRegisterTest("HostBitsTestSig08", HostBitsTestSig08, 1); + UtRegisterTest("HostBitsTestSig07", HostBitsTestSig07); + UtRegisterTest("HostBitsTestSig08", HostBitsTestSig08); #endif /* UNITTESTS */ } diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index e6c902aab155..e5c9a5af94b0 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -2367,37 +2367,37 @@ int DetectHttpClientBodyTest36(void) void DetectHttpClientBodyRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpClientBodyTest01", DetectHttpClientBodyTest01, 1); - UtRegisterTest("DetectHttpClientBodyTest02", DetectHttpClientBodyTest02, 1); - UtRegisterTest("DetectHttpClientBodyTest03", DetectHttpClientBodyTest03, 1); - UtRegisterTest("DetectHttpClientBodyTest04", DetectHttpClientBodyTest04, 1); - UtRegisterTest("DetectHttpClientBodyTest05", DetectHttpClientBodyTest05, 1); - UtRegisterTest("DetectHttpClientBodyTest06", DetectHttpClientBodyTest06, 1); - UtRegisterTest("DetectHttpClientBodyTest07", DetectHttpClientBodyTest07, 1); - UtRegisterTest("DetectHttpClientBodyTest08", DetectHttpClientBodyTest08, 1); - UtRegisterTest("DetectHttpClientBodyTest09", DetectHttpClientBodyTest09, 1); - UtRegisterTest("DetectHttpClientBodyTest10", DetectHttpClientBodyTest10, 1); - UtRegisterTest("DetectHttpClientBodyTest11", DetectHttpClientBodyTest11, 1); - UtRegisterTest("DetectHttpClientBodyTest12", DetectHttpClientBodyTest12, 1); - UtRegisterTest("DetectHttpClientBodyTest13", DetectHttpClientBodyTest13, 1); - UtRegisterTest("DetectHttpClientBodyTest14", DetectHttpClientBodyTest14, 1); - UtRegisterTest("DetectHttpClientBodyTest15", DetectHttpClientBodyTest15, 1); - - UtRegisterTest("DetectHttpClientBodyTest22", DetectHttpClientBodyTest22, 1); - UtRegisterTest("DetectHttpClientBodyTest23", DetectHttpClientBodyTest23, 1); - UtRegisterTest("DetectHttpClientBodyTest24", DetectHttpClientBodyTest24, 1); - UtRegisterTest("DetectHttpClientBodyTest25", DetectHttpClientBodyTest25, 1); - UtRegisterTest("DetectHttpClientBodyTest26", DetectHttpClientBodyTest26, 1); - UtRegisterTest("DetectHttpClientBodyTest27", DetectHttpClientBodyTest27, 1); - UtRegisterTest("DetectHttpClientBodyTest28", DetectHttpClientBodyTest28, 1); - UtRegisterTest("DetectHttpClientBodyTest29", DetectHttpClientBodyTest29, 1); - UtRegisterTest("DetectHttpClientBodyTest30", DetectHttpClientBodyTest30, 1); - UtRegisterTest("DetectHttpClientBodyTest31", DetectHttpClientBodyTest31, 1); - UtRegisterTest("DetectHttpClientBodyTest32", DetectHttpClientBodyTest32, 1); - UtRegisterTest("DetectHttpClientBodyTest33", DetectHttpClientBodyTest33, 1); - UtRegisterTest("DetectHttpClientBodyTest34", DetectHttpClientBodyTest34, 1); - UtRegisterTest("DetectHttpClientBodyTest35", DetectHttpClientBodyTest35, 1); - UtRegisterTest("DetectHttpClientBodyTest36", DetectHttpClientBodyTest36, 1); + UtRegisterTest("DetectHttpClientBodyTest01", DetectHttpClientBodyTest01); + UtRegisterTest("DetectHttpClientBodyTest02", DetectHttpClientBodyTest02); + UtRegisterTest("DetectHttpClientBodyTest03", DetectHttpClientBodyTest03); + UtRegisterTest("DetectHttpClientBodyTest04", DetectHttpClientBodyTest04); + UtRegisterTest("DetectHttpClientBodyTest05", DetectHttpClientBodyTest05); + UtRegisterTest("DetectHttpClientBodyTest06", DetectHttpClientBodyTest06); + UtRegisterTest("DetectHttpClientBodyTest07", DetectHttpClientBodyTest07); + UtRegisterTest("DetectHttpClientBodyTest08", DetectHttpClientBodyTest08); + UtRegisterTest("DetectHttpClientBodyTest09", DetectHttpClientBodyTest09); + UtRegisterTest("DetectHttpClientBodyTest10", DetectHttpClientBodyTest10); + UtRegisterTest("DetectHttpClientBodyTest11", DetectHttpClientBodyTest11); + UtRegisterTest("DetectHttpClientBodyTest12", DetectHttpClientBodyTest12); + UtRegisterTest("DetectHttpClientBodyTest13", DetectHttpClientBodyTest13); + UtRegisterTest("DetectHttpClientBodyTest14", DetectHttpClientBodyTest14); + UtRegisterTest("DetectHttpClientBodyTest15", DetectHttpClientBodyTest15); + + UtRegisterTest("DetectHttpClientBodyTest22", DetectHttpClientBodyTest22); + UtRegisterTest("DetectHttpClientBodyTest23", DetectHttpClientBodyTest23); + UtRegisterTest("DetectHttpClientBodyTest24", DetectHttpClientBodyTest24); + UtRegisterTest("DetectHttpClientBodyTest25", DetectHttpClientBodyTest25); + UtRegisterTest("DetectHttpClientBodyTest26", DetectHttpClientBodyTest26); + UtRegisterTest("DetectHttpClientBodyTest27", DetectHttpClientBodyTest27); + UtRegisterTest("DetectHttpClientBodyTest28", DetectHttpClientBodyTest28); + UtRegisterTest("DetectHttpClientBodyTest29", DetectHttpClientBodyTest29); + UtRegisterTest("DetectHttpClientBodyTest30", DetectHttpClientBodyTest30); + UtRegisterTest("DetectHttpClientBodyTest31", DetectHttpClientBodyTest31); + UtRegisterTest("DetectHttpClientBodyTest32", DetectHttpClientBodyTest32); + UtRegisterTest("DetectHttpClientBodyTest33", DetectHttpClientBodyTest33); + UtRegisterTest("DetectHttpClientBodyTest34", DetectHttpClientBodyTest34); + UtRegisterTest("DetectHttpClientBodyTest35", DetectHttpClientBodyTest35); + UtRegisterTest("DetectHttpClientBodyTest36", DetectHttpClientBodyTest36); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 94f76765ad17..be08b2dc1f2a 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -1254,21 +1254,21 @@ static int DetectHttpCookieSigTest09(void) void DetectHttpCookieRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectHttpCookieTest01", DetectHttpCookieTest01, 1); - UtRegisterTest("DetectHttpCookieTest02", DetectHttpCookieTest02, 1); - UtRegisterTest("DetectHttpCookieTest03", DetectHttpCookieTest03, 1); - UtRegisterTest("DetectHttpCookieTest04", DetectHttpCookieTest04, 1); - UtRegisterTest("DetectHttpCookieTest05", DetectHttpCookieTest05, 1); - UtRegisterTest("DetectHttpCookieTest06", DetectHttpCookieTest06, 1); - UtRegisterTest("DetectHttpCookieSigTest01", DetectHttpCookieSigTest01, 1); - UtRegisterTest("DetectHttpCookieSigTest02", DetectHttpCookieSigTest02, 1); - UtRegisterTest("DetectHttpCookieSigTest03", DetectHttpCookieSigTest03, 1); - UtRegisterTest("DetectHttpCookieSigTest04", DetectHttpCookieSigTest04, 1); - UtRegisterTest("DetectHttpCookieSigTest05", DetectHttpCookieSigTest05, 1); - UtRegisterTest("DetectHttpCookieSigTest06", DetectHttpCookieSigTest06, 1); - UtRegisterTest("DetectHttpCookieSigTest07", DetectHttpCookieSigTest07, 1); - UtRegisterTest("DetectHttpCookieSigTest08", DetectHttpCookieSigTest08, 1); - UtRegisterTest("DetectHttpCookieSigTest09", DetectHttpCookieSigTest09, 1); + UtRegisterTest("DetectHttpCookieTest01", DetectHttpCookieTest01); + UtRegisterTest("DetectHttpCookieTest02", DetectHttpCookieTest02); + UtRegisterTest("DetectHttpCookieTest03", DetectHttpCookieTest03); + UtRegisterTest("DetectHttpCookieTest04", DetectHttpCookieTest04); + UtRegisterTest("DetectHttpCookieTest05", DetectHttpCookieTest05); + UtRegisterTest("DetectHttpCookieTest06", DetectHttpCookieTest06); + UtRegisterTest("DetectHttpCookieSigTest01", DetectHttpCookieSigTest01); + UtRegisterTest("DetectHttpCookieSigTest02", DetectHttpCookieSigTest02); + UtRegisterTest("DetectHttpCookieSigTest03", DetectHttpCookieSigTest03); + UtRegisterTest("DetectHttpCookieSigTest04", DetectHttpCookieSigTest04); + UtRegisterTest("DetectHttpCookieSigTest05", DetectHttpCookieSigTest05); + UtRegisterTest("DetectHttpCookieSigTest06", DetectHttpCookieSigTest06); + UtRegisterTest("DetectHttpCookieSigTest07", DetectHttpCookieSigTest07); + UtRegisterTest("DetectHttpCookieSigTest08", DetectHttpCookieSigTest08); + UtRegisterTest("DetectHttpCookieSigTest09", DetectHttpCookieSigTest09); #endif /* UNITTESTS */ } diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 6c9fea9a340a..7d3e1a2d23e4 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -1789,30 +1789,30 @@ static int DetectHttpHeaderTest30(void) void DetectHttpHeaderRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpHeaderTest01", DetectHttpHeaderTest01, 1); - UtRegisterTest("DetectHttpHeaderTest02", DetectHttpHeaderTest02, 1); - UtRegisterTest("DetectHttpHeaderTest03", DetectHttpHeaderTest03, 1); - UtRegisterTest("DetectHttpHeaderTest04", DetectHttpHeaderTest04, 1); - UtRegisterTest("DetectHttpHeaderTest05", DetectHttpHeaderTest05, 1); - UtRegisterTest("DetectHttpHeaderTest06", DetectHttpHeaderTest06, 1); - UtRegisterTest("DetectHttpHeaderTest07", DetectHttpHeaderTest07, 1); - UtRegisterTest("DetectHttpHeaderTest08", DetectHttpHeaderTest08, 1); - UtRegisterTest("DetectHttpHeaderTest09", DetectHttpHeaderTest09, 1); - UtRegisterTest("DetectHttpHeaderTest10", DetectHttpHeaderTest10, 1); - UtRegisterTest("DetectHttpHeaderTest11", DetectHttpHeaderTest11, 1); - UtRegisterTest("DetectHttpHeaderTest12", DetectHttpHeaderTest12, 1); - UtRegisterTest("DetectHttpHeaderTest13", DetectHttpHeaderTest13, 1); - UtRegisterTest("DetectHttpHeaderTest20", DetectHttpHeaderTest20, 1); - UtRegisterTest("DetectHttpHeaderTest21", DetectHttpHeaderTest21, 1); - UtRegisterTest("DetectHttpHeaderTest22", DetectHttpHeaderTest22, 1); - UtRegisterTest("DetectHttpHeaderTest23", DetectHttpHeaderTest23, 1); - UtRegisterTest("DetectHttpHeaderTest24", DetectHttpHeaderTest24, 1); - UtRegisterTest("DetectHttpHeaderTest25", DetectHttpHeaderTest25, 1); - UtRegisterTest("DetectHttpHeaderTest26", DetectHttpHeaderTest26, 1); - UtRegisterTest("DetectHttpHeaderTest27", DetectHttpHeaderTest27, 1); - UtRegisterTest("DetectHttpHeaderTest28", DetectHttpHeaderTest28, 1); - UtRegisterTest("DetectHttpHeaderTest29", DetectHttpHeaderTest29, 1); - UtRegisterTest("DetectHttpHeaderTest30", DetectHttpHeaderTest30, 1); + UtRegisterTest("DetectHttpHeaderTest01", DetectHttpHeaderTest01); + UtRegisterTest("DetectHttpHeaderTest02", DetectHttpHeaderTest02); + UtRegisterTest("DetectHttpHeaderTest03", DetectHttpHeaderTest03); + UtRegisterTest("DetectHttpHeaderTest04", DetectHttpHeaderTest04); + UtRegisterTest("DetectHttpHeaderTest05", DetectHttpHeaderTest05); + UtRegisterTest("DetectHttpHeaderTest06", DetectHttpHeaderTest06); + UtRegisterTest("DetectHttpHeaderTest07", DetectHttpHeaderTest07); + UtRegisterTest("DetectHttpHeaderTest08", DetectHttpHeaderTest08); + UtRegisterTest("DetectHttpHeaderTest09", DetectHttpHeaderTest09); + UtRegisterTest("DetectHttpHeaderTest10", DetectHttpHeaderTest10); + UtRegisterTest("DetectHttpHeaderTest11", DetectHttpHeaderTest11); + UtRegisterTest("DetectHttpHeaderTest12", DetectHttpHeaderTest12); + UtRegisterTest("DetectHttpHeaderTest13", DetectHttpHeaderTest13); + UtRegisterTest("DetectHttpHeaderTest20", DetectHttpHeaderTest20); + UtRegisterTest("DetectHttpHeaderTest21", DetectHttpHeaderTest21); + UtRegisterTest("DetectHttpHeaderTest22", DetectHttpHeaderTest22); + UtRegisterTest("DetectHttpHeaderTest23", DetectHttpHeaderTest23); + UtRegisterTest("DetectHttpHeaderTest24", DetectHttpHeaderTest24); + UtRegisterTest("DetectHttpHeaderTest25", DetectHttpHeaderTest25); + UtRegisterTest("DetectHttpHeaderTest26", DetectHttpHeaderTest26); + UtRegisterTest("DetectHttpHeaderTest27", DetectHttpHeaderTest27); + UtRegisterTest("DetectHttpHeaderTest28", DetectHttpHeaderTest28); + UtRegisterTest("DetectHttpHeaderTest29", DetectHttpHeaderTest29); + UtRegisterTest("DetectHttpHeaderTest30", DetectHttpHeaderTest30); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 19e87e162431..883cdbefface 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -2067,36 +2067,36 @@ int DetectHttpHHTest36(void) void DetectHttpHHRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpHHTest01", DetectHttpHHTest01, 1); - UtRegisterTest("DetectHttpHHTest02", DetectHttpHHTest02, 1); - UtRegisterTest("DetectHttpHHTest03", DetectHttpHHTest03, 1); - UtRegisterTest("DetectHttpHHTest04", DetectHttpHHTest04, 1); - UtRegisterTest("DetectHttpHHTest05", DetectHttpHHTest05, 1); - UtRegisterTest("DetectHttpHHTest06", DetectHttpHHTest06, 1); - UtRegisterTest("DetectHttpHHTest07", DetectHttpHHTest07, 1); - UtRegisterTest("DetectHttpHHTest08", DetectHttpHHTest08, 1); - UtRegisterTest("DetectHttpHHTest09", DetectHttpHHTest09, 1); - UtRegisterTest("DetectHttpHHTest10", DetectHttpHHTest10, 1); - UtRegisterTest("DetectHttpHHTest11", DetectHttpHHTest11, 1); - UtRegisterTest("DetectHttpHHTest12", DetectHttpHHTest12, 1); - UtRegisterTest("DetectHttpHHTest13", DetectHttpHHTest13, 1); - UtRegisterTest("DetectHttpHHTest14", DetectHttpHHTest14, 1); - - UtRegisterTest("DetectHttpHHTest22", DetectHttpHHTest22, 1); - UtRegisterTest("DetectHttpHHTest23", DetectHttpHHTest23, 1); - UtRegisterTest("DetectHttpHHTest24", DetectHttpHHTest24, 1); - UtRegisterTest("DetectHttpHHTest25", DetectHttpHHTest25, 1); - UtRegisterTest("DetectHttpHHTest26", DetectHttpHHTest26, 1); - UtRegisterTest("DetectHttpHHTest27", DetectHttpHHTest27, 1); - UtRegisterTest("DetectHttpHHTest28", DetectHttpHHTest28, 1); - UtRegisterTest("DetectHttpHHTest29", DetectHttpHHTest29, 1); - UtRegisterTest("DetectHttpHHTest30", DetectHttpHHTest30, 1); - UtRegisterTest("DetectHttpHHTest31", DetectHttpHHTest31, 1); - UtRegisterTest("DetectHttpHHTest32", DetectHttpHHTest32, 1); - UtRegisterTest("DetectHttpHHTest33", DetectHttpHHTest33, 1); - UtRegisterTest("DetectHttpHHTest34", DetectHttpHHTest34, 1); - UtRegisterTest("DetectHttpHHTest35", DetectHttpHHTest35, 1); - UtRegisterTest("DetectHttpHHTest36", DetectHttpHHTest36, 1); + UtRegisterTest("DetectHttpHHTest01", DetectHttpHHTest01); + UtRegisterTest("DetectHttpHHTest02", DetectHttpHHTest02); + UtRegisterTest("DetectHttpHHTest03", DetectHttpHHTest03); + UtRegisterTest("DetectHttpHHTest04", DetectHttpHHTest04); + UtRegisterTest("DetectHttpHHTest05", DetectHttpHHTest05); + UtRegisterTest("DetectHttpHHTest06", DetectHttpHHTest06); + UtRegisterTest("DetectHttpHHTest07", DetectHttpHHTest07); + UtRegisterTest("DetectHttpHHTest08", DetectHttpHHTest08); + UtRegisterTest("DetectHttpHHTest09", DetectHttpHHTest09); + UtRegisterTest("DetectHttpHHTest10", DetectHttpHHTest10); + UtRegisterTest("DetectHttpHHTest11", DetectHttpHHTest11); + UtRegisterTest("DetectHttpHHTest12", DetectHttpHHTest12); + UtRegisterTest("DetectHttpHHTest13", DetectHttpHHTest13); + UtRegisterTest("DetectHttpHHTest14", DetectHttpHHTest14); + + UtRegisterTest("DetectHttpHHTest22", DetectHttpHHTest22); + UtRegisterTest("DetectHttpHHTest23", DetectHttpHHTest23); + UtRegisterTest("DetectHttpHHTest24", DetectHttpHHTest24); + UtRegisterTest("DetectHttpHHTest25", DetectHttpHHTest25); + UtRegisterTest("DetectHttpHHTest26", DetectHttpHHTest26); + UtRegisterTest("DetectHttpHHTest27", DetectHttpHHTest27); + UtRegisterTest("DetectHttpHHTest28", DetectHttpHHTest28); + UtRegisterTest("DetectHttpHHTest29", DetectHttpHHTest29); + UtRegisterTest("DetectHttpHHTest30", DetectHttpHHTest30); + UtRegisterTest("DetectHttpHHTest31", DetectHttpHHTest31); + UtRegisterTest("DetectHttpHHTest32", DetectHttpHHTest32); + UtRegisterTest("DetectHttpHHTest33", DetectHttpHHTest33); + UtRegisterTest("DetectHttpHHTest34", DetectHttpHHTest34); + UtRegisterTest("DetectHttpHHTest35", DetectHttpHHTest35); + UtRegisterTest("DetectHttpHHTest36", DetectHttpHHTest36); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index a6a56b1080ca..4c3cdb24e666 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -2193,37 +2193,37 @@ static int DetectHttpHRHTest37(void) void DetectHttpHRHRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpHRHTest01", DetectHttpHRHTest01, 1); - UtRegisterTest("DetectHttpHRHTest02", DetectHttpHRHTest02, 1); - UtRegisterTest("DetectHttpHRHTest03", DetectHttpHRHTest03, 1); - UtRegisterTest("DetectHttpHRHTest04", DetectHttpHRHTest04, 1); - UtRegisterTest("DetectHttpHRHTest05", DetectHttpHRHTest05, 1); - UtRegisterTest("DetectHttpHRHTest06", DetectHttpHRHTest06, 1); - UtRegisterTest("DetectHttpHRHTest07", DetectHttpHRHTest07, 1); - UtRegisterTest("DetectHttpHRHTest08", DetectHttpHRHTest08, 1); - UtRegisterTest("DetectHttpHRHTest09", DetectHttpHRHTest09, 1); - UtRegisterTest("DetectHttpHRHTest10", DetectHttpHRHTest10, 1); - UtRegisterTest("DetectHttpHRHTest11", DetectHttpHRHTest11, 1); - UtRegisterTest("DetectHttpHRHTest12", DetectHttpHRHTest12, 1); - UtRegisterTest("DetectHttpHRHTest13", DetectHttpHRHTest13, 1); - UtRegisterTest("DetectHttpHRHTest14", DetectHttpHRHTest14, 1); - - UtRegisterTest("DetectHttpHRHTest22", DetectHttpHRHTest22, 1); - UtRegisterTest("DetectHttpHRHTest23", DetectHttpHRHTest23, 1); - UtRegisterTest("DetectHttpHRHTest24", DetectHttpHRHTest24, 1); - UtRegisterTest("DetectHttpHRHTest25", DetectHttpHRHTest25, 1); - UtRegisterTest("DetectHttpHRHTest26", DetectHttpHRHTest26, 1); - UtRegisterTest("DetectHttpHRHTest27", DetectHttpHRHTest27, 1); - UtRegisterTest("DetectHttpHRHTest28", DetectHttpHRHTest28, 1); - UtRegisterTest("DetectHttpHRHTest29", DetectHttpHRHTest29, 1); - UtRegisterTest("DetectHttpHRHTest30", DetectHttpHRHTest30, 1); - UtRegisterTest("DetectHttpHRHTest31", DetectHttpHRHTest31, 1); - UtRegisterTest("DetectHttpHRHTest32", DetectHttpHRHTest32, 1); - UtRegisterTest("DetectHttpHRHTest33", DetectHttpHRHTest33, 1); - UtRegisterTest("DetectHttpHRHTest34", DetectHttpHRHTest34, 1); - UtRegisterTest("DetectHttpHRHTest35", DetectHttpHRHTest35, 1); - UtRegisterTest("DetectHttpHRHTest36", DetectHttpHRHTest36, 1); - UtRegisterTest("DetectHttpHRHTest37", DetectHttpHRHTest37, 1); + UtRegisterTest("DetectHttpHRHTest01", DetectHttpHRHTest01); + UtRegisterTest("DetectHttpHRHTest02", DetectHttpHRHTest02); + UtRegisterTest("DetectHttpHRHTest03", DetectHttpHRHTest03); + UtRegisterTest("DetectHttpHRHTest04", DetectHttpHRHTest04); + UtRegisterTest("DetectHttpHRHTest05", DetectHttpHRHTest05); + UtRegisterTest("DetectHttpHRHTest06", DetectHttpHRHTest06); + UtRegisterTest("DetectHttpHRHTest07", DetectHttpHRHTest07); + UtRegisterTest("DetectHttpHRHTest08", DetectHttpHRHTest08); + UtRegisterTest("DetectHttpHRHTest09", DetectHttpHRHTest09); + UtRegisterTest("DetectHttpHRHTest10", DetectHttpHRHTest10); + UtRegisterTest("DetectHttpHRHTest11", DetectHttpHRHTest11); + UtRegisterTest("DetectHttpHRHTest12", DetectHttpHRHTest12); + UtRegisterTest("DetectHttpHRHTest13", DetectHttpHRHTest13); + UtRegisterTest("DetectHttpHRHTest14", DetectHttpHRHTest14); + + UtRegisterTest("DetectHttpHRHTest22", DetectHttpHRHTest22); + UtRegisterTest("DetectHttpHRHTest23", DetectHttpHRHTest23); + UtRegisterTest("DetectHttpHRHTest24", DetectHttpHRHTest24); + UtRegisterTest("DetectHttpHRHTest25", DetectHttpHRHTest25); + UtRegisterTest("DetectHttpHRHTest26", DetectHttpHRHTest26); + UtRegisterTest("DetectHttpHRHTest27", DetectHttpHRHTest27); + UtRegisterTest("DetectHttpHRHTest28", DetectHttpHRHTest28); + UtRegisterTest("DetectHttpHRHTest29", DetectHttpHRHTest29); + UtRegisterTest("DetectHttpHRHTest30", DetectHttpHRHTest30); + UtRegisterTest("DetectHttpHRHTest31", DetectHttpHRHTest31); + UtRegisterTest("DetectHttpHRHTest32", DetectHttpHRHTest32); + UtRegisterTest("DetectHttpHRHTest33", DetectHttpHRHTest33); + UtRegisterTest("DetectHttpHRHTest34", DetectHttpHRHTest34); + UtRegisterTest("DetectHttpHRHTest35", DetectHttpHRHTest35); + UtRegisterTest("DetectHttpHRHTest36", DetectHttpHRHTest36); + UtRegisterTest("DetectHttpHRHTest37", DetectHttpHRHTest37); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 6807648c6e78..ee5291016c92 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -847,19 +847,20 @@ void DetectHttpMethodRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ SCLogDebug("Registering tests for DetectHttpMethod..."); - UtRegisterTest("DetectHttpMethodTest01", DetectHttpMethodTest01, 1); - UtRegisterTest("DetectHttpMethodTest02", DetectHttpMethodTest02, 1); - UtRegisterTest("DetectHttpMethodTest03", DetectHttpMethodTest03, 1); - UtRegisterTest("DetectHttpMethodTest04", DetectHttpMethodTest04, 1); - UtRegisterTest("DetectHttpMethodTest05", DetectHttpMethodTest05, 1); - UtRegisterTest("DetectHttpMethodTest12 -- nocase flag", DetectHttpMethodTest12, 1); - UtRegisterTest("DetectHttpMethodTest13", DetectHttpMethodTest13, 1); - UtRegisterTest("DetectHttpMethodTest14", DetectHttpMethodTest14, 1); - UtRegisterTest("DetectHttpMethodTest15", DetectHttpMethodTest15, 1); - UtRegisterTest("DetectHttpMethodSigTest01", DetectHttpMethodSigTest01, 1); - UtRegisterTest("DetectHttpMethodSigTest02", DetectHttpMethodSigTest02, 1); - UtRegisterTest("DetectHttpMethodSigTest03", DetectHttpMethodSigTest03, 1); - UtRegisterTest("DetectHttpMethodSigTest04", DetectHttpMethodSigTest04, 1); + UtRegisterTest("DetectHttpMethodTest01", DetectHttpMethodTest01); + UtRegisterTest("DetectHttpMethodTest02", DetectHttpMethodTest02); + UtRegisterTest("DetectHttpMethodTest03", DetectHttpMethodTest03); + UtRegisterTest("DetectHttpMethodTest04", DetectHttpMethodTest04); + UtRegisterTest("DetectHttpMethodTest05", DetectHttpMethodTest05); + UtRegisterTest("DetectHttpMethodTest12 -- nocase flag", + DetectHttpMethodTest12); + UtRegisterTest("DetectHttpMethodTest13", DetectHttpMethodTest13); + UtRegisterTest("DetectHttpMethodTest14", DetectHttpMethodTest14); + UtRegisterTest("DetectHttpMethodTest15", DetectHttpMethodTest15); + UtRegisterTest("DetectHttpMethodSigTest01", DetectHttpMethodSigTest01); + UtRegisterTest("DetectHttpMethodSigTest02", DetectHttpMethodSigTest02); + UtRegisterTest("DetectHttpMethodSigTest03", DetectHttpMethodSigTest03); + UtRegisterTest("DetectHttpMethodSigTest04", DetectHttpMethodSigTest04); #endif /* UNITTESTS */ } diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index 1a5f0eb27571..67b1fa7c7ad4 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -1527,27 +1527,27 @@ int DetectHttpRawHeaderTest27(void) void DetectHttpRawHeaderRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpRawHeaderTest01", DetectHttpRawHeaderTest01, 1); - UtRegisterTest("DetectHttpRawHeaderTest02", DetectHttpRawHeaderTest02, 1); - UtRegisterTest("DetectHttpRawHeaderTest03", DetectHttpRawHeaderTest03, 1); - UtRegisterTest("DetectHttpRawHeaderTest04", DetectHttpRawHeaderTest04, 1); - UtRegisterTest("DetectHttpRawHeaderTest05", DetectHttpRawHeaderTest05, 1); - UtRegisterTest("DetectHttpRawHeaderTest06", DetectHttpRawHeaderTest06, 1); - UtRegisterTest("DetectHttpRawHeaderTest07", DetectHttpRawHeaderTest07, 1); - UtRegisterTest("DetectHttpRawHeaderTest08", DetectHttpRawHeaderTest08, 1); - UtRegisterTest("DetectHttpRawHeaderTest09", DetectHttpRawHeaderTest09, 1); - UtRegisterTest("DetectHttpRawHeaderTest10", DetectHttpRawHeaderTest10, 1); - UtRegisterTest("DetectHttpRawHeaderTest11", DetectHttpRawHeaderTest11, 1); - UtRegisterTest("DetectHttpRawHeaderTest12", DetectHttpRawHeaderTest12, 1); - UtRegisterTest("DetectHttpRawHeaderTest13", DetectHttpRawHeaderTest13, 1); - UtRegisterTest("DetectHttpRawHeaderTest20", DetectHttpRawHeaderTest20, 1); - UtRegisterTest("DetectHttpRawHeaderTest21", DetectHttpRawHeaderTest21, 1); - UtRegisterTest("DetectHttpRawHeaderTest22", DetectHttpRawHeaderTest22, 1); - UtRegisterTest("DetectHttpRawHeaderTest23", DetectHttpRawHeaderTest23, 1); - UtRegisterTest("DetectHttpRawHeaderTest24", DetectHttpRawHeaderTest24, 1); - UtRegisterTest("DetectHttpRawHeaderTest25", DetectHttpRawHeaderTest25, 1); - UtRegisterTest("DetectHttpRawHeaderTest26", DetectHttpRawHeaderTest26, 1); - UtRegisterTest("DetectHttpRawHeaderTest27", DetectHttpRawHeaderTest27, 1); + UtRegisterTest("DetectHttpRawHeaderTest01", DetectHttpRawHeaderTest01); + UtRegisterTest("DetectHttpRawHeaderTest02", DetectHttpRawHeaderTest02); + UtRegisterTest("DetectHttpRawHeaderTest03", DetectHttpRawHeaderTest03); + UtRegisterTest("DetectHttpRawHeaderTest04", DetectHttpRawHeaderTest04); + UtRegisterTest("DetectHttpRawHeaderTest05", DetectHttpRawHeaderTest05); + UtRegisterTest("DetectHttpRawHeaderTest06", DetectHttpRawHeaderTest06); + UtRegisterTest("DetectHttpRawHeaderTest07", DetectHttpRawHeaderTest07); + UtRegisterTest("DetectHttpRawHeaderTest08", DetectHttpRawHeaderTest08); + UtRegisterTest("DetectHttpRawHeaderTest09", DetectHttpRawHeaderTest09); + UtRegisterTest("DetectHttpRawHeaderTest10", DetectHttpRawHeaderTest10); + UtRegisterTest("DetectHttpRawHeaderTest11", DetectHttpRawHeaderTest11); + UtRegisterTest("DetectHttpRawHeaderTest12", DetectHttpRawHeaderTest12); + UtRegisterTest("DetectHttpRawHeaderTest13", DetectHttpRawHeaderTest13); + UtRegisterTest("DetectHttpRawHeaderTest20", DetectHttpRawHeaderTest20); + UtRegisterTest("DetectHttpRawHeaderTest21", DetectHttpRawHeaderTest21); + UtRegisterTest("DetectHttpRawHeaderTest22", DetectHttpRawHeaderTest22); + UtRegisterTest("DetectHttpRawHeaderTest23", DetectHttpRawHeaderTest23); + UtRegisterTest("DetectHttpRawHeaderTest24", DetectHttpRawHeaderTest24); + UtRegisterTest("DetectHttpRawHeaderTest25", DetectHttpRawHeaderTest25); + UtRegisterTest("DetectHttpRawHeaderTest26", DetectHttpRawHeaderTest26); + UtRegisterTest("DetectHttpRawHeaderTest27", DetectHttpRawHeaderTest27); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index e269686e5deb..8c4a95044061 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -545,18 +545,18 @@ int DetectHttpRawUriTest18(void) static void DetectHttpRawUriRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectHttpRawUriTest01", DetectHttpRawUriTest01, 1); - UtRegisterTest("DetectHttpRawUriTest02", DetectHttpRawUriTest02, 1); - UtRegisterTest("DetectHttpRawUriTest03", DetectHttpRawUriTest03, 1); - UtRegisterTest("DetectHttpRawUriTest04", DetectHttpRawUriTest04, 1); - UtRegisterTest("DetectHttpRawUriTest05", DetectHttpRawUriTest05, 1); - UtRegisterTest("DetectHttpRawUriTest12", DetectHttpRawUriTest12, 1); - UtRegisterTest("DetectHttpRawUriTest13", DetectHttpRawUriTest13, 1); - UtRegisterTest("DetectHttpRawUriTest14", DetectHttpRawUriTest14, 1); - UtRegisterTest("DetectHttpRawUriTest15", DetectHttpRawUriTest15, 1); - UtRegisterTest("DetectHttpRawUriTest16", DetectHttpRawUriTest16, 1); - UtRegisterTest("DetectHttpRawUriTest17", DetectHttpRawUriTest17, 1); - UtRegisterTest("DetectHttpRawUriTest18", DetectHttpRawUriTest18, 1); + UtRegisterTest("DetectHttpRawUriTest01", DetectHttpRawUriTest01); + UtRegisterTest("DetectHttpRawUriTest02", DetectHttpRawUriTest02); + UtRegisterTest("DetectHttpRawUriTest03", DetectHttpRawUriTest03); + UtRegisterTest("DetectHttpRawUriTest04", DetectHttpRawUriTest04); + UtRegisterTest("DetectHttpRawUriTest05", DetectHttpRawUriTest05); + UtRegisterTest("DetectHttpRawUriTest12", DetectHttpRawUriTest12); + UtRegisterTest("DetectHttpRawUriTest13", DetectHttpRawUriTest13); + UtRegisterTest("DetectHttpRawUriTest14", DetectHttpRawUriTest14); + UtRegisterTest("DetectHttpRawUriTest15", DetectHttpRawUriTest15); + UtRegisterTest("DetectHttpRawUriTest16", DetectHttpRawUriTest16); + UtRegisterTest("DetectHttpRawUriTest17", DetectHttpRawUriTest17); + UtRegisterTest("DetectHttpRawUriTest18", DetectHttpRawUriTest18); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index a5463b66b356..828e84e5006b 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -3823,47 +3823,57 @@ static int DetectHttpServerBodyFileDataTest10(void) void DetectHttpServerBodyRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpServerBodyTest01", DetectHttpServerBodyTest01, 1); - UtRegisterTest("DetectHttpServerBodyTest02", DetectHttpServerBodyTest02, 1); - UtRegisterTest("DetectHttpServerBodyTest03", DetectHttpServerBodyTest03, 1); - UtRegisterTest("DetectHttpServerBodyTest04", DetectHttpServerBodyTest04, 1); - UtRegisterTest("DetectHttpServerBodyTest05", DetectHttpServerBodyTest05, 1); - UtRegisterTest("DetectHttpServerBodyTest06", DetectHttpServerBodyTest06, 1); - UtRegisterTest("DetectHttpServerBodyTest07", DetectHttpServerBodyTest07, 1); - UtRegisterTest("DetectHttpServerBodyTest08", DetectHttpServerBodyTest08, 1); - UtRegisterTest("DetectHttpServerBodyTest09", DetectHttpServerBodyTest09, 1); - UtRegisterTest("DetectHttpServerBodyTest10", DetectHttpServerBodyTest10, 1); - UtRegisterTest("DetectHttpServerBodyTest11", DetectHttpServerBodyTest11, 1); - UtRegisterTest("DetectHttpServerBodyTest12", DetectHttpServerBodyTest12, 1); - UtRegisterTest("DetectHttpServerBodyTest13", DetectHttpServerBodyTest13, 1); - UtRegisterTest("DetectHttpServerBodyTest14", DetectHttpServerBodyTest14, 1); - UtRegisterTest("DetectHttpServerBodyTest15", DetectHttpServerBodyTest15, 1); - UtRegisterTest("DetectHttpServerBodyTest22", DetectHttpServerBodyTest22, 1); - UtRegisterTest("DetectHttpServerBodyTest23", DetectHttpServerBodyTest23, 1); - UtRegisterTest("DetectHttpServerBodyTest24", DetectHttpServerBodyTest24, 1); - UtRegisterTest("DetectHttpServerBodyTest25", DetectHttpServerBodyTest25, 1); - UtRegisterTest("DetectHttpServerBodyTest26", DetectHttpServerBodyTest26, 1); - UtRegisterTest("DetectHttpServerBodyTest27", DetectHttpServerBodyTest27, 1); - UtRegisterTest("DetectHttpServerBodyTest28", DetectHttpServerBodyTest28, 1); - UtRegisterTest("DetectHttpServerBodyTest29", DetectHttpServerBodyTest29, 1); - UtRegisterTest("DetectHttpServerBodyTest30", DetectHttpServerBodyTest30, 1); - UtRegisterTest("DetectHttpServerBodyTest31", DetectHttpServerBodyTest31, 1); - UtRegisterTest("DetectHttpServerBodyTest32", DetectHttpServerBodyTest32, 1); - UtRegisterTest("DetectHttpServerBodyTest33", DetectHttpServerBodyTest33, 1); - UtRegisterTest("DetectHttpServerBodyTest34", DetectHttpServerBodyTest34, 1); - UtRegisterTest("DetectHttpServerBodyTest35", DetectHttpServerBodyTest35, 1); - UtRegisterTest("DetectHttpServerBodyTest36", DetectHttpServerBodyTest36, 1); - - UtRegisterTest("DetectHttpServerBodyFileDataTest01", DetectHttpServerBodyFileDataTest01, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest02", DetectHttpServerBodyFileDataTest02, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest03", DetectHttpServerBodyFileDataTest03, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest04", DetectHttpServerBodyFileDataTest04, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest05", DetectHttpServerBodyFileDataTest05, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest06", DetectHttpServerBodyFileDataTest06, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest07", DetectHttpServerBodyFileDataTest07, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest08", DetectHttpServerBodyFileDataTest08, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest09", DetectHttpServerBodyFileDataTest09, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest10", DetectHttpServerBodyFileDataTest10, 1); + UtRegisterTest("DetectHttpServerBodyTest01", DetectHttpServerBodyTest01); + UtRegisterTest("DetectHttpServerBodyTest02", DetectHttpServerBodyTest02); + UtRegisterTest("DetectHttpServerBodyTest03", DetectHttpServerBodyTest03); + UtRegisterTest("DetectHttpServerBodyTest04", DetectHttpServerBodyTest04); + UtRegisterTest("DetectHttpServerBodyTest05", DetectHttpServerBodyTest05); + UtRegisterTest("DetectHttpServerBodyTest06", DetectHttpServerBodyTest06); + UtRegisterTest("DetectHttpServerBodyTest07", DetectHttpServerBodyTest07); + UtRegisterTest("DetectHttpServerBodyTest08", DetectHttpServerBodyTest08); + UtRegisterTest("DetectHttpServerBodyTest09", DetectHttpServerBodyTest09); + UtRegisterTest("DetectHttpServerBodyTest10", DetectHttpServerBodyTest10); + UtRegisterTest("DetectHttpServerBodyTest11", DetectHttpServerBodyTest11); + UtRegisterTest("DetectHttpServerBodyTest12", DetectHttpServerBodyTest12); + UtRegisterTest("DetectHttpServerBodyTest13", DetectHttpServerBodyTest13); + UtRegisterTest("DetectHttpServerBodyTest14", DetectHttpServerBodyTest14); + UtRegisterTest("DetectHttpServerBodyTest15", DetectHttpServerBodyTest15); + UtRegisterTest("DetectHttpServerBodyTest22", DetectHttpServerBodyTest22); + UtRegisterTest("DetectHttpServerBodyTest23", DetectHttpServerBodyTest23); + UtRegisterTest("DetectHttpServerBodyTest24", DetectHttpServerBodyTest24); + UtRegisterTest("DetectHttpServerBodyTest25", DetectHttpServerBodyTest25); + UtRegisterTest("DetectHttpServerBodyTest26", DetectHttpServerBodyTest26); + UtRegisterTest("DetectHttpServerBodyTest27", DetectHttpServerBodyTest27); + UtRegisterTest("DetectHttpServerBodyTest28", DetectHttpServerBodyTest28); + UtRegisterTest("DetectHttpServerBodyTest29", DetectHttpServerBodyTest29); + UtRegisterTest("DetectHttpServerBodyTest30", DetectHttpServerBodyTest30); + UtRegisterTest("DetectHttpServerBodyTest31", DetectHttpServerBodyTest31); + UtRegisterTest("DetectHttpServerBodyTest32", DetectHttpServerBodyTest32); + UtRegisterTest("DetectHttpServerBodyTest33", DetectHttpServerBodyTest33); + UtRegisterTest("DetectHttpServerBodyTest34", DetectHttpServerBodyTest34); + UtRegisterTest("DetectHttpServerBodyTest35", DetectHttpServerBodyTest35); + UtRegisterTest("DetectHttpServerBodyTest36", DetectHttpServerBodyTest36); + + UtRegisterTest("DetectHttpServerBodyFileDataTest01", + DetectHttpServerBodyFileDataTest01); + UtRegisterTest("DetectHttpServerBodyFileDataTest02", + DetectHttpServerBodyFileDataTest02); + UtRegisterTest("DetectHttpServerBodyFileDataTest03", + DetectHttpServerBodyFileDataTest03); + UtRegisterTest("DetectHttpServerBodyFileDataTest04", + DetectHttpServerBodyFileDataTest04); + UtRegisterTest("DetectHttpServerBodyFileDataTest05", + DetectHttpServerBodyFileDataTest05); + UtRegisterTest("DetectHttpServerBodyFileDataTest06", + DetectHttpServerBodyFileDataTest06); + UtRegisterTest("DetectHttpServerBodyFileDataTest07", + DetectHttpServerBodyFileDataTest07); + UtRegisterTest("DetectHttpServerBodyFileDataTest08", + DetectHttpServerBodyFileDataTest08); + UtRegisterTest("DetectHttpServerBodyFileDataTest09", + DetectHttpServerBodyFileDataTest09); + UtRegisterTest("DetectHttpServerBodyFileDataTest10", + DetectHttpServerBodyFileDataTest10); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index 0237009f81c6..f5b1bb7e6c3e 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -673,12 +673,12 @@ void DetectHttpStatCodeRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectHttpStatCodeTest01", DetectHttpStatCodeTest01, 1); - UtRegisterTest("DetectHttpStatCodeTest02", DetectHttpStatCodeTest02, 1); - UtRegisterTest("DetectHttpStatCodeSigTest01", DetectHttpStatCodeSigTest01, 1); - UtRegisterTest("DetectHttpStatCodeSigTest02", DetectHttpStatCodeSigTest02, 1); - UtRegisterTest("DetectHttpStatCodeSigTest03", DetectHttpStatCodeSigTest03, 1); - UtRegisterTest("DetectHttpStatCodeSigTest04", DetectHttpStatCodeSigTest04, 1); + UtRegisterTest("DetectHttpStatCodeTest01", DetectHttpStatCodeTest01); + UtRegisterTest("DetectHttpStatCodeTest02", DetectHttpStatCodeTest02); + UtRegisterTest("DetectHttpStatCodeSigTest01", DetectHttpStatCodeSigTest01); + UtRegisterTest("DetectHttpStatCodeSigTest02", DetectHttpStatCodeSigTest02); + UtRegisterTest("DetectHttpStatCodeSigTest03", DetectHttpStatCodeSigTest03); + UtRegisterTest("DetectHttpStatCodeSigTest04", DetectHttpStatCodeSigTest04); #endif /* UNITTESTS */ } diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index d2d7685edd0e..235764528665 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -551,11 +551,11 @@ void DetectHttpStatMsgRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectHttpStatMsgTest01", DetectHttpStatMsgTest01, 1); - UtRegisterTest("DetectHttpStatMsgTest02", DetectHttpStatMsgTest02, 1); - UtRegisterTest("DetectHttpStatMsgSigTest01", DetectHttpStatMsgSigTest01, 1); - UtRegisterTest("DetectHttpStatMsgSigTest02", DetectHttpStatMsgSigTest02, 1); - UtRegisterTest("DetectHttpStatMsgSigTest03", DetectHttpStatMsgSigTest03, 1); + UtRegisterTest("DetectHttpStatMsgTest01", DetectHttpStatMsgTest01); + UtRegisterTest("DetectHttpStatMsgTest02", DetectHttpStatMsgTest02); + UtRegisterTest("DetectHttpStatMsgSigTest01", DetectHttpStatMsgSigTest01); + UtRegisterTest("DetectHttpStatMsgSigTest02", DetectHttpStatMsgSigTest02); + UtRegisterTest("DetectHttpStatMsgSigTest03", DetectHttpStatMsgSigTest03); #endif /* UNITTESTS */ } diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index cae5e9faee00..c3ee465d76ca 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -2071,36 +2071,36 @@ int DetectHttpUATest36(void) void DetectHttpUARegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpUATest01", DetectHttpUATest01, 1); - UtRegisterTest("DetectHttpUATest02", DetectHttpUATest02, 1); - UtRegisterTest("DetectHttpUATest03", DetectHttpUATest03, 1); - UtRegisterTest("DetectHttpUATest04", DetectHttpUATest04, 1); - UtRegisterTest("DetectHttpUATest05", DetectHttpUATest05, 1); - UtRegisterTest("DetectHttpUATest06", DetectHttpUATest06, 1); - UtRegisterTest("DetectHttpUATest07", DetectHttpUATest07, 1); - UtRegisterTest("DetectHttpUATest08", DetectHttpUATest08, 1); - UtRegisterTest("DetectHttpUATest09", DetectHttpUATest09, 1); - UtRegisterTest("DetectHttpUATest10", DetectHttpUATest10, 1); - UtRegisterTest("DetectHttpUATest11", DetectHttpUATest11, 1); - UtRegisterTest("DetectHttpUATest12", DetectHttpUATest12, 1); - UtRegisterTest("DetectHttpUATest13", DetectHttpUATest13, 1); - UtRegisterTest("DetectHttpUATest14", DetectHttpUATest14, 1); - - UtRegisterTest("DetectHttpUATest22", DetectHttpUATest22, 1); - UtRegisterTest("DetectHttpUATest23", DetectHttpUATest23, 1); - UtRegisterTest("DetectHttpUATest24", DetectHttpUATest24, 1); - UtRegisterTest("DetectHttpUATest25", DetectHttpUATest25, 1); - UtRegisterTest("DetectHttpUATest26", DetectHttpUATest26, 1); - UtRegisterTest("DetectHttpUATest27", DetectHttpUATest27, 1); - UtRegisterTest("DetectHttpUATest28", DetectHttpUATest28, 1); - UtRegisterTest("DetectHttpUATest29", DetectHttpUATest29, 1); - UtRegisterTest("DetectHttpUATest30", DetectHttpUATest30, 1); - UtRegisterTest("DetectHttpUATest31", DetectHttpUATest31, 1); - UtRegisterTest("DetectHttpUATest32", DetectHttpUATest32, 1); - UtRegisterTest("DetectHttpUATest33", DetectHttpUATest33, 1); - UtRegisterTest("DetectHttpUATest34", DetectHttpUATest34, 1); - UtRegisterTest("DetectHttpUATest35", DetectHttpUATest35, 1); - UtRegisterTest("DetectHttpUATest36", DetectHttpUATest36, 1); + UtRegisterTest("DetectHttpUATest01", DetectHttpUATest01); + UtRegisterTest("DetectHttpUATest02", DetectHttpUATest02); + UtRegisterTest("DetectHttpUATest03", DetectHttpUATest03); + UtRegisterTest("DetectHttpUATest04", DetectHttpUATest04); + UtRegisterTest("DetectHttpUATest05", DetectHttpUATest05); + UtRegisterTest("DetectHttpUATest06", DetectHttpUATest06); + UtRegisterTest("DetectHttpUATest07", DetectHttpUATest07); + UtRegisterTest("DetectHttpUATest08", DetectHttpUATest08); + UtRegisterTest("DetectHttpUATest09", DetectHttpUATest09); + UtRegisterTest("DetectHttpUATest10", DetectHttpUATest10); + UtRegisterTest("DetectHttpUATest11", DetectHttpUATest11); + UtRegisterTest("DetectHttpUATest12", DetectHttpUATest12); + UtRegisterTest("DetectHttpUATest13", DetectHttpUATest13); + UtRegisterTest("DetectHttpUATest14", DetectHttpUATest14); + + UtRegisterTest("DetectHttpUATest22", DetectHttpUATest22); + UtRegisterTest("DetectHttpUATest23", DetectHttpUATest23); + UtRegisterTest("DetectHttpUATest24", DetectHttpUATest24); + UtRegisterTest("DetectHttpUATest25", DetectHttpUATest25); + UtRegisterTest("DetectHttpUATest26", DetectHttpUATest26); + UtRegisterTest("DetectHttpUATest27", DetectHttpUATest27); + UtRegisterTest("DetectHttpUATest28", DetectHttpUATest28); + UtRegisterTest("DetectHttpUATest29", DetectHttpUATest29); + UtRegisterTest("DetectHttpUATest30", DetectHttpUATest30); + UtRegisterTest("DetectHttpUATest31", DetectHttpUATest31); + UtRegisterTest("DetectHttpUATest32", DetectHttpUATest32); + UtRegisterTest("DetectHttpUATest33", DetectHttpUATest33); + UtRegisterTest("DetectHttpUATest34", DetectHttpUATest34); + UtRegisterTest("DetectHttpUATest35", DetectHttpUATest35); + UtRegisterTest("DetectHttpUATest36", DetectHttpUATest36); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 92c4803e18ba..9d005a9ce794 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -536,18 +536,18 @@ int DetectHttpUriTest18(void) void DetectHttpUriRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectHttpUriTest01", DetectHttpUriTest01, 1); - UtRegisterTest("DetectHttpUriTest02", DetectHttpUriTest02, 1); - UtRegisterTest("DetectHttpUriTest03", DetectHttpUriTest03, 1); - UtRegisterTest("DetectHttpUriTest04", DetectHttpUriTest04, 1); - UtRegisterTest("DetectHttpUriTest05", DetectHttpUriTest05, 1); - UtRegisterTest("DetectHttpUriTest12", DetectHttpUriTest12, 1); - UtRegisterTest("DetectHttpUriTest13", DetectHttpUriTest13, 1); - UtRegisterTest("DetectHttpUriTest14", DetectHttpUriTest14, 1); - UtRegisterTest("DetectHttpUriTest15", DetectHttpUriTest15, 1); - UtRegisterTest("DetectHttpUriTest16", DetectHttpUriTest16, 1); - UtRegisterTest("DetectHttpUriTest17", DetectHttpUriTest17, 1); - UtRegisterTest("DetectHttpUriTest18", DetectHttpUriTest18, 1); + UtRegisterTest("DetectHttpUriTest01", DetectHttpUriTest01); + UtRegisterTest("DetectHttpUriTest02", DetectHttpUriTest02); + UtRegisterTest("DetectHttpUriTest03", DetectHttpUriTest03); + UtRegisterTest("DetectHttpUriTest04", DetectHttpUriTest04); + UtRegisterTest("DetectHttpUriTest05", DetectHttpUriTest05); + UtRegisterTest("DetectHttpUriTest12", DetectHttpUriTest12); + UtRegisterTest("DetectHttpUriTest13", DetectHttpUriTest13); + UtRegisterTest("DetectHttpUriTest14", DetectHttpUriTest14); + UtRegisterTest("DetectHttpUriTest15", DetectHttpUriTest15); + UtRegisterTest("DetectHttpUriTest16", DetectHttpUriTest16); + UtRegisterTest("DetectHttpUriTest17", DetectHttpUriTest17); + UtRegisterTest("DetectHttpUriTest18", DetectHttpUriTest18); #endif /* UNITTESTS */ } diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index 5d6f7f263985..59d1e9ae679c 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -488,13 +488,13 @@ int DetectIcmpIdMatchTest02 (void) void DetectIcmpIdRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("DetectIcmpIdParseTest01", DetectIcmpIdParseTest01, 1); - UtRegisterTest("DetectIcmpIdParseTest02", DetectIcmpIdParseTest02, 1); - UtRegisterTest("DetectIcmpIdParseTest03", DetectIcmpIdParseTest03, 1); - UtRegisterTest("DetectIcmpIdParseTest04", DetectIcmpIdParseTest04, 1); - UtRegisterTest("DetectIcmpIdParseTest05", DetectIcmpIdParseTest05, 1); - UtRegisterTest("DetectIcmpIdMatchTest01", DetectIcmpIdMatchTest01, 1); - UtRegisterTest("DetectIcmpIdMatchTest02", DetectIcmpIdMatchTest02, 1); + UtRegisterTest("DetectIcmpIdParseTest01", DetectIcmpIdParseTest01); + UtRegisterTest("DetectIcmpIdParseTest02", DetectIcmpIdParseTest02); + UtRegisterTest("DetectIcmpIdParseTest03", DetectIcmpIdParseTest03); + UtRegisterTest("DetectIcmpIdParseTest04", DetectIcmpIdParseTest04); + UtRegisterTest("DetectIcmpIdParseTest05", DetectIcmpIdParseTest05); + UtRegisterTest("DetectIcmpIdMatchTest01", DetectIcmpIdMatchTest01); + UtRegisterTest("DetectIcmpIdMatchTest02", DetectIcmpIdMatchTest02); #endif /* UNITTESTS */ } diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index 4c5784210139..e48003a0a979 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -381,10 +381,10 @@ int DetectIcmpSeqMatchTest01 (void) void DetectIcmpSeqRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("DetectIcmpSeqParseTest01", DetectIcmpSeqParseTest01, 1); - UtRegisterTest("DetectIcmpSeqParseTest02", DetectIcmpSeqParseTest02, 1); - UtRegisterTest("DetectIcmpSeqParseTest03", DetectIcmpSeqParseTest03, 1); - UtRegisterTest("DetectIcmpSeqMatchTest01", DetectIcmpSeqMatchTest01, 1); + UtRegisterTest("DetectIcmpSeqParseTest01", DetectIcmpSeqParseTest01); + UtRegisterTest("DetectIcmpSeqParseTest02", DetectIcmpSeqParseTest02); + UtRegisterTest("DetectIcmpSeqParseTest03", DetectIcmpSeqParseTest03); + UtRegisterTest("DetectIcmpSeqMatchTest01", DetectIcmpSeqMatchTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-icode.c b/src/detect-icode.c index 05c35a722169..33f3e0eff433 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -515,14 +515,14 @@ int DetectICodeMatchTest01(void) void DetectICodeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectICodeParseTest01", DetectICodeParseTest01, 1); - UtRegisterTest("DetectICodeParseTest02", DetectICodeParseTest02, 1); - UtRegisterTest("DetectICodeParseTest03", DetectICodeParseTest03, 1); - UtRegisterTest("DetectICodeParseTest04", DetectICodeParseTest04, 1); - UtRegisterTest("DetectICodeParseTest05", DetectICodeParseTest05, 1); - UtRegisterTest("DetectICodeParseTest06", DetectICodeParseTest06, 1); - UtRegisterTest("DetectICodeParseTest07", DetectICodeParseTest07, 1); - UtRegisterTest("DetectICodeParseTest08", DetectICodeParseTest08, 1); - UtRegisterTest("DetectICodeMatchTest01", DetectICodeMatchTest01, 1); + UtRegisterTest("DetectICodeParseTest01", DetectICodeParseTest01); + UtRegisterTest("DetectICodeParseTest02", DetectICodeParseTest02); + UtRegisterTest("DetectICodeParseTest03", DetectICodeParseTest03); + UtRegisterTest("DetectICodeParseTest04", DetectICodeParseTest04); + UtRegisterTest("DetectICodeParseTest05", DetectICodeParseTest05); + UtRegisterTest("DetectICodeParseTest06", DetectICodeParseTest06); + UtRegisterTest("DetectICodeParseTest07", DetectICodeParseTest07); + UtRegisterTest("DetectICodeParseTest08", DetectICodeParseTest08); + UtRegisterTest("DetectICodeMatchTest01", DetectICodeMatchTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-id.c b/src/detect-id.c index 5df2a6d1823e..a15e32284004 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -374,11 +374,11 @@ int DetectIdTestMatch01(void) void DetectIdRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectIdTestParse01", DetectIdTestParse01, 1); - UtRegisterTest("DetectIdTestParse02", DetectIdTestParse02, 1); - UtRegisterTest("DetectIdTestParse03", DetectIdTestParse03, 1); - UtRegisterTest("DetectIdTestParse04", DetectIdTestParse04, 1); - UtRegisterTest("DetectIdTestMatch01", DetectIdTestMatch01, 1); + UtRegisterTest("DetectIdTestParse01", DetectIdTestParse01); + UtRegisterTest("DetectIdTestParse02", DetectIdTestParse02); + UtRegisterTest("DetectIdTestParse03", DetectIdTestParse03); + UtRegisterTest("DetectIdTestParse04", DetectIdTestParse04); + UtRegisterTest("DetectIdTestMatch01", DetectIdTestMatch01); #endif /* UNITTESTS */ } diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index fbe143abea99..ef9b54302764 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -379,9 +379,9 @@ int IpOptsTestParse04 (void) void IpOptsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("IpOptsTestParse01", IpOptsTestParse01, 1); - UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02, 1); - UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03, 1); - UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04, 1); + UtRegisterTest("IpOptsTestParse01", IpOptsTestParse01); + UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02); + UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03); + UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04); #endif /* UNITTESTS */ } diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index c0de5e95c10a..0cade5691433 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -9451,156 +9451,156 @@ static int DetectIPProtoTestSig3(void) static void DetectIPProtoRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectIPProtoTestParse01", DetectIPProtoTestParse01, 1); - UtRegisterTest("DetectIPProtoTestParse02", DetectIPProtoTestParse02, 1); - UtRegisterTest("DetectIPProtoTestSetup01", DetectIPProtoTestSetup01, 1); - UtRegisterTest("DetectIPProtoTestSetup02", DetectIPProtoTestSetup02, 1); - UtRegisterTest("DetectIPProtoTestSetup03", DetectIPProtoTestSetup03, 1); - UtRegisterTest("DetectIPProtoTestSetup04", DetectIPProtoTestSetup04, 1); - UtRegisterTest("DetectIPProtoTestSetup05", DetectIPProtoTestSetup05, 1); - UtRegisterTest("DetectIPProtoTestSetup06", DetectIPProtoTestSetup06, 1); - UtRegisterTest("DetectIPProtoTestSetup07", DetectIPProtoTestSetup07, 1); - UtRegisterTest("DetectIPProtoTestSetup08", DetectIPProtoTestSetup08, 1); - UtRegisterTest("DetectIPProtoTestSetup09", DetectIPProtoTestSetup09, 1); - UtRegisterTest("DetectIPProtoTestSetup10", DetectIPProtoTestSetup10, 1); - UtRegisterTest("DetectIPProtoTestSetup11", DetectIPProtoTestSetup11, 1); - UtRegisterTest("DetectIPProtoTestSetup12", DetectIPProtoTestSetup12, 1); - UtRegisterTest("DetectIPProtoTestSetup13", DetectIPProtoTestSetup13, 1); - UtRegisterTest("DetectIPProtoTestSetup14", DetectIPProtoTestSetup14, 1); - UtRegisterTest("DetectIPProtoTestSetup15", DetectIPProtoTestSetup15, 1); - UtRegisterTest("DetectIPProtoTestSetup16", DetectIPProtoTestSetup16, 1); - UtRegisterTest("DetectIPProtoTestSetup17", DetectIPProtoTestSetup17, 1); - UtRegisterTest("DetectIPProtoTestSetup18", DetectIPProtoTestSetup18, 1); - UtRegisterTest("DetectIPProtoTestSetup19", DetectIPProtoTestSetup19, 1); - UtRegisterTest("DetectIPProtoTestSetup20", DetectIPProtoTestSetup20, 1); - UtRegisterTest("DetectIPProtoTestSetup21", DetectIPProtoTestSetup21, 1); - UtRegisterTest("DetectIPProtoTestSetup22", DetectIPProtoTestSetup22, 1); - UtRegisterTest("DetectIPProtoTestSetup23", DetectIPProtoTestSetup23, 1); - UtRegisterTest("DetectIPProtoTestSetup24", DetectIPProtoTestSetup24, 1); - UtRegisterTest("DetectIPProtoTestSetup25", DetectIPProtoTestSetup25, 1); - UtRegisterTest("DetectIPProtoTestSetup26", DetectIPProtoTestSetup26, 1); - UtRegisterTest("DetectIPProtoTestSetup27", DetectIPProtoTestSetup27, 1); - UtRegisterTest("DetectIPProtoTestSetup28", DetectIPProtoTestSetup28, 1); - UtRegisterTest("DetectIPProtoTestSetup29", DetectIPProtoTestSetup29, 1); - UtRegisterTest("DetectIPProtoTestSetup30", DetectIPProtoTestSetup30, 1); - UtRegisterTest("DetectIPProtoTestSetup31", DetectIPProtoTestSetup31, 1); - UtRegisterTest("DetectIPProtoTestSetup32", DetectIPProtoTestSetup32, 1); - UtRegisterTest("DetectIPProtoTestSetup33", DetectIPProtoTestSetup33, 1); - UtRegisterTest("DetectIPProtoTestSetup34", DetectIPProtoTestSetup34, 1); - UtRegisterTest("DetectIPProtoTestSetup35", DetectIPProtoTestSetup35, 1); - UtRegisterTest("DetectIPProtoTestSetup36", DetectIPProtoTestSetup36, 1); - UtRegisterTest("DetectIPProtoTestSetup37", DetectIPProtoTestSetup37, 1); - UtRegisterTest("DetectIPProtoTestSetup38", DetectIPProtoTestSetup38, 1); - UtRegisterTest("DetectIPProtoTestSetup39", DetectIPProtoTestSetup39, 1); - UtRegisterTest("DetectIPProtoTestSetup40", DetectIPProtoTestSetup40, 1); - UtRegisterTest("DetectIPProtoTestSetup41", DetectIPProtoTestSetup41, 1); - UtRegisterTest("DetectIPProtoTestSetup42", DetectIPProtoTestSetup42, 1); - UtRegisterTest("DetectIPProtoTestSetup43", DetectIPProtoTestSetup43, 1); - UtRegisterTest("DetectIPProtoTestSetup44", DetectIPProtoTestSetup44, 1); - UtRegisterTest("DetectIPProtoTestSetup45", DetectIPProtoTestSetup45, 1); - UtRegisterTest("DetectIPProtoTestSetup46", DetectIPProtoTestSetup46, 1); - UtRegisterTest("DetectIPProtoTestSetup47", DetectIPProtoTestSetup47, 1); - UtRegisterTest("DetectIPProtoTestSetup48", DetectIPProtoTestSetup48, 1); - UtRegisterTest("DetectIPProtoTestSetup49", DetectIPProtoTestSetup49, 1); - UtRegisterTest("DetectIPProtoTestSetup50", DetectIPProtoTestSetup50, 1); - UtRegisterTest("DetectIPProtoTestSetup51", DetectIPProtoTestSetup51, 1); - UtRegisterTest("DetectIPProtoTestSetup52", DetectIPProtoTestSetup52, 1); - UtRegisterTest("DetectIPProtoTestSetup53", DetectIPProtoTestSetup53, 1); - UtRegisterTest("DetectIPProtoTestSetup54", DetectIPProtoTestSetup54, 1); - UtRegisterTest("DetectIPProtoTestSetup55", DetectIPProtoTestSetup55, 1); - UtRegisterTest("DetectIPProtoTestSetup56", DetectIPProtoTestSetup56, 1); - UtRegisterTest("DetectIPProtoTestSetup57", DetectIPProtoTestSetup57, 1); - UtRegisterTest("DetectIPProtoTestSetup58", DetectIPProtoTestSetup58, 1); - UtRegisterTest("DetectIPProtoTestSetup59", DetectIPProtoTestSetup59, 1); - UtRegisterTest("DetectIPProtoTestSetup60", DetectIPProtoTestSetup60, 1); - UtRegisterTest("DetectIPProtoTestSetup61", DetectIPProtoTestSetup61, 1); - UtRegisterTest("DetectIPProtoTestSetup62", DetectIPProtoTestSetup62, 1); - UtRegisterTest("DetectIPProtoTestSetup63", DetectIPProtoTestSetup63, 1); - UtRegisterTest("DetectIPProtoTestSetup64", DetectIPProtoTestSetup64, 1); - UtRegisterTest("DetectIPProtoTestSetup65", DetectIPProtoTestSetup65, 1); - UtRegisterTest("DetectIPProtoTestSetup66", DetectIPProtoTestSetup66, 1); - UtRegisterTest("DetectIPProtoTestSetup67", DetectIPProtoTestSetup67, 1); - UtRegisterTest("DetectIPProtoTestSetup68", DetectIPProtoTestSetup68, 1); - UtRegisterTest("DetectIPProtoTestSetup69", DetectIPProtoTestSetup69, 1); - UtRegisterTest("DetectIPProtoTestSetup70", DetectIPProtoTestSetup70, 1); - UtRegisterTest("DetectIPProtoTestSetup71", DetectIPProtoTestSetup71, 1); - UtRegisterTest("DetectIPProtoTestSetup72", DetectIPProtoTestSetup72, 1); - UtRegisterTest("DetectIPProtoTestSetup73", DetectIPProtoTestSetup73, 1); - UtRegisterTest("DetectIPProtoTestSetup74", DetectIPProtoTestSetup74, 1); - UtRegisterTest("DetectIPProtoTestSetup75", DetectIPProtoTestSetup75, 1); - UtRegisterTest("DetectIPProtoTestSetup76", DetectIPProtoTestSetup76, 1); - UtRegisterTest("DetectIPProtoTestSetup77", DetectIPProtoTestSetup77, 1); - UtRegisterTest("DetectIPProtoTestSetup78", DetectIPProtoTestSetup78, 1); - UtRegisterTest("DetectIPProtoTestSetup79", DetectIPProtoTestSetup79, 1); - UtRegisterTest("DetectIPProtoTestSetup80", DetectIPProtoTestSetup80, 1); - UtRegisterTest("DetectIPProtoTestSetup81", DetectIPProtoTestSetup81, 1); - UtRegisterTest("DetectIPProtoTestSetup82", DetectIPProtoTestSetup82, 1); - UtRegisterTest("DetectIPProtoTestSetup83", DetectIPProtoTestSetup83, 1); - UtRegisterTest("DetectIPProtoTestSetup84", DetectIPProtoTestSetup84, 1); - UtRegisterTest("DetectIPProtoTestSetup85", DetectIPProtoTestSetup85, 1); - UtRegisterTest("DetectIPProtoTestSetup86", DetectIPProtoTestSetup86, 1); - UtRegisterTest("DetectIPProtoTestSetup87", DetectIPProtoTestSetup87, 1); - UtRegisterTest("DetectIPProtoTestSetup88", DetectIPProtoTestSetup88, 1); - UtRegisterTest("DetectIPProtoTestSetup89", DetectIPProtoTestSetup89, 1); - UtRegisterTest("DetectIPProtoTestSetup90", DetectIPProtoTestSetup90, 1); - UtRegisterTest("DetectIPProtoTestSetup91", DetectIPProtoTestSetup91, 1); - UtRegisterTest("DetectIPProtoTestSetup92", DetectIPProtoTestSetup92, 1); - UtRegisterTest("DetectIPProtoTestSetup93", DetectIPProtoTestSetup93, 1); - UtRegisterTest("DetectIPProtoTestSetup94", DetectIPProtoTestSetup94, 1); - UtRegisterTest("DetectIPProtoTestSetup95", DetectIPProtoTestSetup95, 1); - UtRegisterTest("DetectIPProtoTestSetup96", DetectIPProtoTestSetup96, 1); - UtRegisterTest("DetectIPProtoTestSetup97", DetectIPProtoTestSetup97, 1); - UtRegisterTest("DetectIPProtoTestSetup98", DetectIPProtoTestSetup98, 1); - UtRegisterTest("DetectIPProtoTestSetup99", DetectIPProtoTestSetup99, 1); - UtRegisterTest("DetectIPProtoTestSetup100", DetectIPProtoTestSetup100, 1); - UtRegisterTest("DetectIPProtoTestSetup101", DetectIPProtoTestSetup101, 1); - UtRegisterTest("DetectIPProtoTestSetup102", DetectIPProtoTestSetup102, 1); - UtRegisterTest("DetectIPProtoTestSetup103", DetectIPProtoTestSetup103, 1); - UtRegisterTest("DetectIPProtoTestSetup104", DetectIPProtoTestSetup104, 1); - UtRegisterTest("DetectIPProtoTestSetup105", DetectIPProtoTestSetup105, 1); - UtRegisterTest("DetectIPProtoTestSetup106", DetectIPProtoTestSetup106, 1); - UtRegisterTest("DetectIPProtoTestSetup107", DetectIPProtoTestSetup107, 1); - UtRegisterTest("DetectIPProtoTestSetup108", DetectIPProtoTestSetup108, 1); - UtRegisterTest("DetectIPProtoTestSetup109", DetectIPProtoTestSetup109, 1); - UtRegisterTest("DetectIPProtoTestSetup110", DetectIPProtoTestSetup110, 1); - UtRegisterTest("DetectIPProtoTestSetup111", DetectIPProtoTestSetup111, 1); - UtRegisterTest("DetectIPProtoTestSetup112", DetectIPProtoTestSetup112, 1); - UtRegisterTest("DetectIPProtoTestSetup113", DetectIPProtoTestSetup113, 1); - UtRegisterTest("DetectIPProtoTestSetup114", DetectIPProtoTestSetup114, 1); - UtRegisterTest("DetectIPProtoTestSetup115", DetectIPProtoTestSetup115, 1); - UtRegisterTest("DetectIPProtoTestSetup116", DetectIPProtoTestSetup116, 1); - UtRegisterTest("DetectIPProtoTestSetup117", DetectIPProtoTestSetup117, 1); - UtRegisterTest("DetectIPProtoTestSetup118", DetectIPProtoTestSetup118, 1); - UtRegisterTest("DetectIPProtoTestSetup119", DetectIPProtoTestSetup119, 1); - UtRegisterTest("DetectIPProtoTestSetup120", DetectIPProtoTestSetup120, 1); - UtRegisterTest("DetectIPProtoTestSetup121", DetectIPProtoTestSetup121, 1); - UtRegisterTest("DetectIPProtoTestSetup122", DetectIPProtoTestSetup122, 1); - UtRegisterTest("DetectIPProtoTestSetup123", DetectIPProtoTestSetup123, 1); - UtRegisterTest("DetectIPProtoTestSetup124", DetectIPProtoTestSetup124, 1); - UtRegisterTest("DetectIPProtoTestSetup125", DetectIPProtoTestSetup125, 1); - UtRegisterTest("DetectIPProtoTestSetup126", DetectIPProtoTestSetup126, 1); - UtRegisterTest("DetectIPProtoTestSetup127", DetectIPProtoTestSetup127, 1); - UtRegisterTest("DetectIPProtoTestSetup128", DetectIPProtoTestSetup128, 1); - UtRegisterTest("DetectIPProtoTestSetup129", DetectIPProtoTestSetup129, 1); - UtRegisterTest("DetectIPProtoTestSetup130", DetectIPProtoTestSetup130, 1); - UtRegisterTest("DetectIPProtoTestSetup131", DetectIPProtoTestSetup131, 1); - UtRegisterTest("DetectIPProtoTestSetup132", DetectIPProtoTestSetup132, 1); - UtRegisterTest("DetectIPProtoTestSetup133", DetectIPProtoTestSetup133, 1); - UtRegisterTest("DetectIPProtoTestSetup134", DetectIPProtoTestSetup134, 1); - UtRegisterTest("DetectIPProtoTestSetup135", DetectIPProtoTestSetup135, 1); - UtRegisterTest("DetectIPProtoTestSetup136", DetectIPProtoTestSetup136, 1); - UtRegisterTest("DetectIPProtoTestSetup137", DetectIPProtoTestSetup137, 1); - UtRegisterTest("DetectIPProtoTestSetup138", DetectIPProtoTestSetup138, 1); - UtRegisterTest("DetectIPProtoTestSetup139", DetectIPProtoTestSetup139, 1); - UtRegisterTest("DetectIPProtoTestSetup140", DetectIPProtoTestSetup140, 1); - UtRegisterTest("DetectIPProtoTestSetup141", DetectIPProtoTestSetup141, 1); - UtRegisterTest("DetectIPProtoTestSetup142", DetectIPProtoTestSetup142, 1); - UtRegisterTest("DetectIPProtoTestSetup143", DetectIPProtoTestSetup143, 1); - UtRegisterTest("DetectIPProtoTestSetup144", DetectIPProtoTestSetup144, 1); - UtRegisterTest("DetectIPProtoTestSetup145", DetectIPProtoTestSetup145, 1); - - UtRegisterTest("DetectIPProtoTestSig1", DetectIPProtoTestSig1, 1); - UtRegisterTest("DetectIPProtoTestSig2", DetectIPProtoTestSig2, 1); - UtRegisterTest("DetectIPProtoTestSig3", DetectIPProtoTestSig3, 1); + UtRegisterTest("DetectIPProtoTestParse01", DetectIPProtoTestParse01); + UtRegisterTest("DetectIPProtoTestParse02", DetectIPProtoTestParse02); + UtRegisterTest("DetectIPProtoTestSetup01", DetectIPProtoTestSetup01); + UtRegisterTest("DetectIPProtoTestSetup02", DetectIPProtoTestSetup02); + UtRegisterTest("DetectIPProtoTestSetup03", DetectIPProtoTestSetup03); + UtRegisterTest("DetectIPProtoTestSetup04", DetectIPProtoTestSetup04); + UtRegisterTest("DetectIPProtoTestSetup05", DetectIPProtoTestSetup05); + UtRegisterTest("DetectIPProtoTestSetup06", DetectIPProtoTestSetup06); + UtRegisterTest("DetectIPProtoTestSetup07", DetectIPProtoTestSetup07); + UtRegisterTest("DetectIPProtoTestSetup08", DetectIPProtoTestSetup08); + UtRegisterTest("DetectIPProtoTestSetup09", DetectIPProtoTestSetup09); + UtRegisterTest("DetectIPProtoTestSetup10", DetectIPProtoTestSetup10); + UtRegisterTest("DetectIPProtoTestSetup11", DetectIPProtoTestSetup11); + UtRegisterTest("DetectIPProtoTestSetup12", DetectIPProtoTestSetup12); + UtRegisterTest("DetectIPProtoTestSetup13", DetectIPProtoTestSetup13); + UtRegisterTest("DetectIPProtoTestSetup14", DetectIPProtoTestSetup14); + UtRegisterTest("DetectIPProtoTestSetup15", DetectIPProtoTestSetup15); + UtRegisterTest("DetectIPProtoTestSetup16", DetectIPProtoTestSetup16); + UtRegisterTest("DetectIPProtoTestSetup17", DetectIPProtoTestSetup17); + UtRegisterTest("DetectIPProtoTestSetup18", DetectIPProtoTestSetup18); + UtRegisterTest("DetectIPProtoTestSetup19", DetectIPProtoTestSetup19); + UtRegisterTest("DetectIPProtoTestSetup20", DetectIPProtoTestSetup20); + UtRegisterTest("DetectIPProtoTestSetup21", DetectIPProtoTestSetup21); + UtRegisterTest("DetectIPProtoTestSetup22", DetectIPProtoTestSetup22); + UtRegisterTest("DetectIPProtoTestSetup23", DetectIPProtoTestSetup23); + UtRegisterTest("DetectIPProtoTestSetup24", DetectIPProtoTestSetup24); + UtRegisterTest("DetectIPProtoTestSetup25", DetectIPProtoTestSetup25); + UtRegisterTest("DetectIPProtoTestSetup26", DetectIPProtoTestSetup26); + UtRegisterTest("DetectIPProtoTestSetup27", DetectIPProtoTestSetup27); + UtRegisterTest("DetectIPProtoTestSetup28", DetectIPProtoTestSetup28); + UtRegisterTest("DetectIPProtoTestSetup29", DetectIPProtoTestSetup29); + UtRegisterTest("DetectIPProtoTestSetup30", DetectIPProtoTestSetup30); + UtRegisterTest("DetectIPProtoTestSetup31", DetectIPProtoTestSetup31); + UtRegisterTest("DetectIPProtoTestSetup32", DetectIPProtoTestSetup32); + UtRegisterTest("DetectIPProtoTestSetup33", DetectIPProtoTestSetup33); + UtRegisterTest("DetectIPProtoTestSetup34", DetectIPProtoTestSetup34); + UtRegisterTest("DetectIPProtoTestSetup35", DetectIPProtoTestSetup35); + UtRegisterTest("DetectIPProtoTestSetup36", DetectIPProtoTestSetup36); + UtRegisterTest("DetectIPProtoTestSetup37", DetectIPProtoTestSetup37); + UtRegisterTest("DetectIPProtoTestSetup38", DetectIPProtoTestSetup38); + UtRegisterTest("DetectIPProtoTestSetup39", DetectIPProtoTestSetup39); + UtRegisterTest("DetectIPProtoTestSetup40", DetectIPProtoTestSetup40); + UtRegisterTest("DetectIPProtoTestSetup41", DetectIPProtoTestSetup41); + UtRegisterTest("DetectIPProtoTestSetup42", DetectIPProtoTestSetup42); + UtRegisterTest("DetectIPProtoTestSetup43", DetectIPProtoTestSetup43); + UtRegisterTest("DetectIPProtoTestSetup44", DetectIPProtoTestSetup44); + UtRegisterTest("DetectIPProtoTestSetup45", DetectIPProtoTestSetup45); + UtRegisterTest("DetectIPProtoTestSetup46", DetectIPProtoTestSetup46); + UtRegisterTest("DetectIPProtoTestSetup47", DetectIPProtoTestSetup47); + UtRegisterTest("DetectIPProtoTestSetup48", DetectIPProtoTestSetup48); + UtRegisterTest("DetectIPProtoTestSetup49", DetectIPProtoTestSetup49); + UtRegisterTest("DetectIPProtoTestSetup50", DetectIPProtoTestSetup50); + UtRegisterTest("DetectIPProtoTestSetup51", DetectIPProtoTestSetup51); + UtRegisterTest("DetectIPProtoTestSetup52", DetectIPProtoTestSetup52); + UtRegisterTest("DetectIPProtoTestSetup53", DetectIPProtoTestSetup53); + UtRegisterTest("DetectIPProtoTestSetup54", DetectIPProtoTestSetup54); + UtRegisterTest("DetectIPProtoTestSetup55", DetectIPProtoTestSetup55); + UtRegisterTest("DetectIPProtoTestSetup56", DetectIPProtoTestSetup56); + UtRegisterTest("DetectIPProtoTestSetup57", DetectIPProtoTestSetup57); + UtRegisterTest("DetectIPProtoTestSetup58", DetectIPProtoTestSetup58); + UtRegisterTest("DetectIPProtoTestSetup59", DetectIPProtoTestSetup59); + UtRegisterTest("DetectIPProtoTestSetup60", DetectIPProtoTestSetup60); + UtRegisterTest("DetectIPProtoTestSetup61", DetectIPProtoTestSetup61); + UtRegisterTest("DetectIPProtoTestSetup62", DetectIPProtoTestSetup62); + UtRegisterTest("DetectIPProtoTestSetup63", DetectIPProtoTestSetup63); + UtRegisterTest("DetectIPProtoTestSetup64", DetectIPProtoTestSetup64); + UtRegisterTest("DetectIPProtoTestSetup65", DetectIPProtoTestSetup65); + UtRegisterTest("DetectIPProtoTestSetup66", DetectIPProtoTestSetup66); + UtRegisterTest("DetectIPProtoTestSetup67", DetectIPProtoTestSetup67); + UtRegisterTest("DetectIPProtoTestSetup68", DetectIPProtoTestSetup68); + UtRegisterTest("DetectIPProtoTestSetup69", DetectIPProtoTestSetup69); + UtRegisterTest("DetectIPProtoTestSetup70", DetectIPProtoTestSetup70); + UtRegisterTest("DetectIPProtoTestSetup71", DetectIPProtoTestSetup71); + UtRegisterTest("DetectIPProtoTestSetup72", DetectIPProtoTestSetup72); + UtRegisterTest("DetectIPProtoTestSetup73", DetectIPProtoTestSetup73); + UtRegisterTest("DetectIPProtoTestSetup74", DetectIPProtoTestSetup74); + UtRegisterTest("DetectIPProtoTestSetup75", DetectIPProtoTestSetup75); + UtRegisterTest("DetectIPProtoTestSetup76", DetectIPProtoTestSetup76); + UtRegisterTest("DetectIPProtoTestSetup77", DetectIPProtoTestSetup77); + UtRegisterTest("DetectIPProtoTestSetup78", DetectIPProtoTestSetup78); + UtRegisterTest("DetectIPProtoTestSetup79", DetectIPProtoTestSetup79); + UtRegisterTest("DetectIPProtoTestSetup80", DetectIPProtoTestSetup80); + UtRegisterTest("DetectIPProtoTestSetup81", DetectIPProtoTestSetup81); + UtRegisterTest("DetectIPProtoTestSetup82", DetectIPProtoTestSetup82); + UtRegisterTest("DetectIPProtoTestSetup83", DetectIPProtoTestSetup83); + UtRegisterTest("DetectIPProtoTestSetup84", DetectIPProtoTestSetup84); + UtRegisterTest("DetectIPProtoTestSetup85", DetectIPProtoTestSetup85); + UtRegisterTest("DetectIPProtoTestSetup86", DetectIPProtoTestSetup86); + UtRegisterTest("DetectIPProtoTestSetup87", DetectIPProtoTestSetup87); + UtRegisterTest("DetectIPProtoTestSetup88", DetectIPProtoTestSetup88); + UtRegisterTest("DetectIPProtoTestSetup89", DetectIPProtoTestSetup89); + UtRegisterTest("DetectIPProtoTestSetup90", DetectIPProtoTestSetup90); + UtRegisterTest("DetectIPProtoTestSetup91", DetectIPProtoTestSetup91); + UtRegisterTest("DetectIPProtoTestSetup92", DetectIPProtoTestSetup92); + UtRegisterTest("DetectIPProtoTestSetup93", DetectIPProtoTestSetup93); + UtRegisterTest("DetectIPProtoTestSetup94", DetectIPProtoTestSetup94); + UtRegisterTest("DetectIPProtoTestSetup95", DetectIPProtoTestSetup95); + UtRegisterTest("DetectIPProtoTestSetup96", DetectIPProtoTestSetup96); + UtRegisterTest("DetectIPProtoTestSetup97", DetectIPProtoTestSetup97); + UtRegisterTest("DetectIPProtoTestSetup98", DetectIPProtoTestSetup98); + UtRegisterTest("DetectIPProtoTestSetup99", DetectIPProtoTestSetup99); + UtRegisterTest("DetectIPProtoTestSetup100", DetectIPProtoTestSetup100); + UtRegisterTest("DetectIPProtoTestSetup101", DetectIPProtoTestSetup101); + UtRegisterTest("DetectIPProtoTestSetup102", DetectIPProtoTestSetup102); + UtRegisterTest("DetectIPProtoTestSetup103", DetectIPProtoTestSetup103); + UtRegisterTest("DetectIPProtoTestSetup104", DetectIPProtoTestSetup104); + UtRegisterTest("DetectIPProtoTestSetup105", DetectIPProtoTestSetup105); + UtRegisterTest("DetectIPProtoTestSetup106", DetectIPProtoTestSetup106); + UtRegisterTest("DetectIPProtoTestSetup107", DetectIPProtoTestSetup107); + UtRegisterTest("DetectIPProtoTestSetup108", DetectIPProtoTestSetup108); + UtRegisterTest("DetectIPProtoTestSetup109", DetectIPProtoTestSetup109); + UtRegisterTest("DetectIPProtoTestSetup110", DetectIPProtoTestSetup110); + UtRegisterTest("DetectIPProtoTestSetup111", DetectIPProtoTestSetup111); + UtRegisterTest("DetectIPProtoTestSetup112", DetectIPProtoTestSetup112); + UtRegisterTest("DetectIPProtoTestSetup113", DetectIPProtoTestSetup113); + UtRegisterTest("DetectIPProtoTestSetup114", DetectIPProtoTestSetup114); + UtRegisterTest("DetectIPProtoTestSetup115", DetectIPProtoTestSetup115); + UtRegisterTest("DetectIPProtoTestSetup116", DetectIPProtoTestSetup116); + UtRegisterTest("DetectIPProtoTestSetup117", DetectIPProtoTestSetup117); + UtRegisterTest("DetectIPProtoTestSetup118", DetectIPProtoTestSetup118); + UtRegisterTest("DetectIPProtoTestSetup119", DetectIPProtoTestSetup119); + UtRegisterTest("DetectIPProtoTestSetup120", DetectIPProtoTestSetup120); + UtRegisterTest("DetectIPProtoTestSetup121", DetectIPProtoTestSetup121); + UtRegisterTest("DetectIPProtoTestSetup122", DetectIPProtoTestSetup122); + UtRegisterTest("DetectIPProtoTestSetup123", DetectIPProtoTestSetup123); + UtRegisterTest("DetectIPProtoTestSetup124", DetectIPProtoTestSetup124); + UtRegisterTest("DetectIPProtoTestSetup125", DetectIPProtoTestSetup125); + UtRegisterTest("DetectIPProtoTestSetup126", DetectIPProtoTestSetup126); + UtRegisterTest("DetectIPProtoTestSetup127", DetectIPProtoTestSetup127); + UtRegisterTest("DetectIPProtoTestSetup128", DetectIPProtoTestSetup128); + UtRegisterTest("DetectIPProtoTestSetup129", DetectIPProtoTestSetup129); + UtRegisterTest("DetectIPProtoTestSetup130", DetectIPProtoTestSetup130); + UtRegisterTest("DetectIPProtoTestSetup131", DetectIPProtoTestSetup131); + UtRegisterTest("DetectIPProtoTestSetup132", DetectIPProtoTestSetup132); + UtRegisterTest("DetectIPProtoTestSetup133", DetectIPProtoTestSetup133); + UtRegisterTest("DetectIPProtoTestSetup134", DetectIPProtoTestSetup134); + UtRegisterTest("DetectIPProtoTestSetup135", DetectIPProtoTestSetup135); + UtRegisterTest("DetectIPProtoTestSetup136", DetectIPProtoTestSetup136); + UtRegisterTest("DetectIPProtoTestSetup137", DetectIPProtoTestSetup137); + UtRegisterTest("DetectIPProtoTestSetup138", DetectIPProtoTestSetup138); + UtRegisterTest("DetectIPProtoTestSetup139", DetectIPProtoTestSetup139); + UtRegisterTest("DetectIPProtoTestSetup140", DetectIPProtoTestSetup140); + UtRegisterTest("DetectIPProtoTestSetup141", DetectIPProtoTestSetup141); + UtRegisterTest("DetectIPProtoTestSetup142", DetectIPProtoTestSetup142); + UtRegisterTest("DetectIPProtoTestSetup143", DetectIPProtoTestSetup143); + UtRegisterTest("DetectIPProtoTestSetup144", DetectIPProtoTestSetup144); + UtRegisterTest("DetectIPProtoTestSetup145", DetectIPProtoTestSetup145); + + UtRegisterTest("DetectIPProtoTestSig1", DetectIPProtoTestSig1); + UtRegisterTest("DetectIPProtoTestSig2", DetectIPProtoTestSig2); + UtRegisterTest("DetectIPProtoTestSig3", DetectIPProtoTestSig3); #endif /* UNITTESTS */ } diff --git a/src/detect-iprep.c b/src/detect-iprep.c index 6944a71f2cb8..09457fdecee8 100644 --- a/src/detect-iprep.c +++ b/src/detect-iprep.c @@ -1017,14 +1017,14 @@ static int DetectIPRepTest09(void) void IPRepRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectIPRepTest01", DetectIPRepTest01, 1); - UtRegisterTest("DetectIPRepTest02", DetectIPRepTest02, 1); - UtRegisterTest("DetectIPRepTest03", DetectIPRepTest03, 1); - UtRegisterTest("DetectIPRepTest04", DetectIPRepTest04, 1); - UtRegisterTest("DetectIPRepTest05", DetectIPRepTest05, 1); - UtRegisterTest("DetectIPRepTest06", DetectIPRepTest06, 1); - UtRegisterTest("DetectIPRepTest07", DetectIPRepTest07, 1); - UtRegisterTest("DetectIPRepTest08", DetectIPRepTest08, 1); - UtRegisterTest("DetectIPRepTest09", DetectIPRepTest09, 1); + UtRegisterTest("DetectIPRepTest01", DetectIPRepTest01); + UtRegisterTest("DetectIPRepTest02", DetectIPRepTest02); + UtRegisterTest("DetectIPRepTest03", DetectIPRepTest03); + UtRegisterTest("DetectIPRepTest04", DetectIPRepTest04); + UtRegisterTest("DetectIPRepTest05", DetectIPRepTest05); + UtRegisterTest("DetectIPRepTest06", DetectIPRepTest06); + UtRegisterTest("DetectIPRepTest07", DetectIPRepTest07); + UtRegisterTest("DetectIPRepTest08", DetectIPRepTest08); + UtRegisterTest("DetectIPRepTest09", DetectIPRepTest09); #endif /* UNITTESTS */ } diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index e6a16f40d087..f7dcfb9b0596 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -1225,25 +1225,25 @@ int DetectIsdataatTestPacket03 (void) void DetectIsdataatRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectIsdataatTestParse01", DetectIsdataatTestParse01, 1); - UtRegisterTest("DetectIsdataatTestParse02", DetectIsdataatTestParse02, 1); - UtRegisterTest("DetectIsdataatTestParse03", DetectIsdataatTestParse03, 1); - UtRegisterTest("DetectIsdataatTestParse04", DetectIsdataatTestParse04, 1); - UtRegisterTest("DetectIsdataatTestParse05", DetectIsdataatTestParse05, 1); - UtRegisterTest("DetectIsdataatTestParse06", DetectIsdataatTestParse06, 1); - UtRegisterTest("DetectIsdataatTestParse07", DetectIsdataatTestParse07, 1); - UtRegisterTest("DetectIsdataatTestParse08", DetectIsdataatTestParse08, 1); - UtRegisterTest("DetectIsdataatTestParse09", DetectIsdataatTestParse09, 1); - UtRegisterTest("DetectIsdataatTestParse10", DetectIsdataatTestParse10, 1); - UtRegisterTest("DetectIsdataatTestParse11", DetectIsdataatTestParse11, 1); - UtRegisterTest("DetectIsdataatTestParse12", DetectIsdataatTestParse12, 1); - UtRegisterTest("DetectIsdataatTestParse13", DetectIsdataatTestParse13, 1); - UtRegisterTest("DetectIsdataatTestParse14", DetectIsdataatTestParse14, 1); - UtRegisterTest("DetectIsdataatTestParse15", DetectIsdataatTestParse15, 1); - UtRegisterTest("DetectIsdataatTestParse16", DetectIsdataatTestParse16, 1); - - UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01, 1); - UtRegisterTest("DetectIsdataatTestPacket02", DetectIsdataatTestPacket02, 1); - UtRegisterTest("DetectIsdataatTestPacket03", DetectIsdataatTestPacket03, 1); + UtRegisterTest("DetectIsdataatTestParse01", DetectIsdataatTestParse01); + UtRegisterTest("DetectIsdataatTestParse02", DetectIsdataatTestParse02); + UtRegisterTest("DetectIsdataatTestParse03", DetectIsdataatTestParse03); + UtRegisterTest("DetectIsdataatTestParse04", DetectIsdataatTestParse04); + UtRegisterTest("DetectIsdataatTestParse05", DetectIsdataatTestParse05); + UtRegisterTest("DetectIsdataatTestParse06", DetectIsdataatTestParse06); + UtRegisterTest("DetectIsdataatTestParse07", DetectIsdataatTestParse07); + UtRegisterTest("DetectIsdataatTestParse08", DetectIsdataatTestParse08); + UtRegisterTest("DetectIsdataatTestParse09", DetectIsdataatTestParse09); + UtRegisterTest("DetectIsdataatTestParse10", DetectIsdataatTestParse10); + UtRegisterTest("DetectIsdataatTestParse11", DetectIsdataatTestParse11); + UtRegisterTest("DetectIsdataatTestParse12", DetectIsdataatTestParse12); + UtRegisterTest("DetectIsdataatTestParse13", DetectIsdataatTestParse13); + UtRegisterTest("DetectIsdataatTestParse14", DetectIsdataatTestParse14); + UtRegisterTest("DetectIsdataatTestParse15", DetectIsdataatTestParse15); + UtRegisterTest("DetectIsdataatTestParse16", DetectIsdataatTestParse16); + + UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01); + UtRegisterTest("DetectIsdataatTestPacket02", DetectIsdataatTestPacket02); + UtRegisterTest("DetectIsdataatTestPacket03", DetectIsdataatTestPacket03); #endif } diff --git a/src/detect-itype.c b/src/detect-itype.c index 1be076478460..fa8cfa6e8aeb 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -516,14 +516,14 @@ int DetectITypeMatchTest01(void) void DetectITypeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectITypeParseTest01", DetectITypeParseTest01, 1); - UtRegisterTest("DetectITypeParseTest02", DetectITypeParseTest02, 1); - UtRegisterTest("DetectITypeParseTest03", DetectITypeParseTest03, 1); - UtRegisterTest("DetectITypeParseTest04", DetectITypeParseTest04, 1); - UtRegisterTest("DetectITypeParseTest05", DetectITypeParseTest05, 1); - UtRegisterTest("DetectITypeParseTest06", DetectITypeParseTest06, 1); - UtRegisterTest("DetectITypeParseTest07", DetectITypeParseTest07, 1); - UtRegisterTest("DetectITypeParseTest08", DetectITypeParseTest08, 1); - UtRegisterTest("DetectITypeMatchTest01", DetectITypeMatchTest01, 1); + UtRegisterTest("DetectITypeParseTest01", DetectITypeParseTest01); + UtRegisterTest("DetectITypeParseTest02", DetectITypeParseTest02); + UtRegisterTest("DetectITypeParseTest03", DetectITypeParseTest03); + UtRegisterTest("DetectITypeParseTest04", DetectITypeParseTest04); + UtRegisterTest("DetectITypeParseTest05", DetectITypeParseTest05); + UtRegisterTest("DetectITypeParseTest06", DetectITypeParseTest06); + UtRegisterTest("DetectITypeParseTest07", DetectITypeParseTest07); + UtRegisterTest("DetectITypeParseTest08", DetectITypeParseTest08); + UtRegisterTest("DetectITypeMatchTest01", DetectITypeMatchTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-l3proto.c b/src/detect-l3proto.c index f7e4995290d0..b04057a92fe4 100644 --- a/src/detect-l3proto.c +++ b/src/detect-l3proto.c @@ -386,8 +386,8 @@ static int DetectL3protoTestSig3(void) void DetectL3protoRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectL3protoTestSig1", DetectL3protoTestSig1, 1); - UtRegisterTest("DetectL3protoTestSig2", DetectL3protoTestSig2, 1); - UtRegisterTest("DetectL3protoTestSig3", DetectL3protoTestSig3, 1); + UtRegisterTest("DetectL3protoTestSig1", DetectL3protoTestSig1); + UtRegisterTest("DetectL3protoTestSig2", DetectL3protoTestSig2); + UtRegisterTest("DetectL3protoTestSig3", DetectL3protoTestSig3); #endif /* UNITTESTS */ } diff --git a/src/detect-lua.c b/src/detect-lua.c index c4a49bdda780..ffaed2d1518f 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -2077,12 +2077,12 @@ static int LuaMatchTest06(void) void DetectLuaRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("LuaMatchTest01", LuaMatchTest01, 1); - UtRegisterTest("LuaMatchTest02", LuaMatchTest02, 1); - UtRegisterTest("LuaMatchTest03", LuaMatchTest03, 1); - UtRegisterTest("LuaMatchTest04", LuaMatchTest04, 1); - UtRegisterTest("LuaMatchTest05", LuaMatchTest05, 1); - UtRegisterTest("LuaMatchTest06", LuaMatchTest06, 1); + UtRegisterTest("LuaMatchTest01", LuaMatchTest01); + UtRegisterTest("LuaMatchTest02", LuaMatchTest02); + UtRegisterTest("LuaMatchTest03", LuaMatchTest03); + UtRegisterTest("LuaMatchTest04", LuaMatchTest04); + UtRegisterTest("LuaMatchTest05", LuaMatchTest05); + UtRegisterTest("LuaMatchTest06", LuaMatchTest06); #endif } diff --git a/src/detect-mark.c b/src/detect-mark.c index 74edf3ce34aa..247bf4898ddc 100644 --- a/src/detect-mark.c +++ b/src/detect-mark.c @@ -345,9 +345,9 @@ static int MarkTestParse04 (void) void MarkRegisterTests(void) { #if defined UNITTESTS && defined NFQ - UtRegisterTest("MarkTestParse01", MarkTestParse01, 1); - UtRegisterTest("MarkTestParse02", MarkTestParse02, 1); - UtRegisterTest("MarkTestParse03", MarkTestParse03, 1); - UtRegisterTest("MarkTestParse04", MarkTestParse04, 1); + UtRegisterTest("MarkTestParse01", MarkTestParse01); + UtRegisterTest("MarkTestParse02", MarkTestParse02); + UtRegisterTest("MarkTestParse03", MarkTestParse03); + UtRegisterTest("MarkTestParse04", MarkTestParse04); #endif /* UNITTESTS */ } diff --git a/src/detect-modbus.c b/src/detect-modbus.c index d1e4ec507d53..2fc5386cb3d0 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -884,14 +884,23 @@ static int DetectModbusTest09(void) void DetectModbusRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectModbusTest01 - Testing function", DetectModbusTest01, 1); - UtRegisterTest("DetectModbusTest02 - Testing function and subfunction", DetectModbusTest02, 1); - UtRegisterTest("DetectModbusTest03 - Testing category function", DetectModbusTest03, 1); - UtRegisterTest("DetectModbusTest04 - Testing category function in negative", DetectModbusTest04, 1); - UtRegisterTest("DetectModbusTest05 - Testing access type", DetectModbusTest05, 1); - UtRegisterTest("DetectModbusTest06 - Testing access function", DetectModbusTest06, 1); - UtRegisterTest("DetectModbusTest07 - Testing access at address", DetectModbusTest07, 1); - UtRegisterTest("DetectModbusTest08 - Testing a range of address", DetectModbusTest08, 1); - UtRegisterTest("DetectModbusTest09 - Testing write a range of value", DetectModbusTest09, 1); + UtRegisterTest("DetectModbusTest01 - Testing function", + DetectModbusTest01); + UtRegisterTest("DetectModbusTest02 - Testing function and subfunction", + DetectModbusTest02); + UtRegisterTest("DetectModbusTest03 - Testing category function", + DetectModbusTest03); + UtRegisterTest("DetectModbusTest04 - Testing category function in negative", + DetectModbusTest04); + UtRegisterTest("DetectModbusTest05 - Testing access type", + DetectModbusTest05); + UtRegisterTest("DetectModbusTest06 - Testing access function", + DetectModbusTest06); + UtRegisterTest("DetectModbusTest07 - Testing access at address", + DetectModbusTest07); + UtRegisterTest("DetectModbusTest08 - Testing a range of address", + DetectModbusTest08); + UtRegisterTest("DetectModbusTest09 - Testing write a range of value", + DetectModbusTest09); #endif /* UNITTESTS */ } diff --git a/src/detect-msg.c b/src/detect-msg.c index 5a5f4c5dfd51..8de5da567536 100644 --- a/src/detect-msg.c +++ b/src/detect-msg.c @@ -206,8 +206,8 @@ static int DetectMsgParseTest02(void) void DetectMsgRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectMsgParseTest01", DetectMsgParseTest01, 1); - UtRegisterTest("DetectMsgParseTest02", DetectMsgParseTest02, 1); + UtRegisterTest("DetectMsgParseTest01", DetectMsgParseTest01); + UtRegisterTest("DetectMsgParseTest02", DetectMsgParseTest02); #endif /* UNITTESTS */ } diff --git a/src/detect-parse.c b/src/detect-parse.c index 45982587679e..670dd28879fe 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -3469,54 +3469,54 @@ static int SigParseTestAppLayerTLS03(void) void SigParseRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SigParseTest01", SigParseTest01, 1); - UtRegisterTest("SigParseTest02", SigParseTest02, 1); - UtRegisterTest("SigParseTest03", SigParseTest03, 1); - UtRegisterTest("SigParseTest04", SigParseTest04, 1); - UtRegisterTest("SigParseTest05", SigParseTest05, 1); - UtRegisterTest("SigParseTest06", SigParseTest06, 1); - UtRegisterTest("SigParseTest07", SigParseTest07, 1); - UtRegisterTest("SigParseTest08", SigParseTest08, 1); - UtRegisterTest("SigParseTest09", SigParseTest09, 1); - UtRegisterTest("SigParseTest10", SigParseTest10, 1); - UtRegisterTest("SigParseTest11", SigParseTest11, 1); - UtRegisterTest("SigParseTest12", SigParseTest12, 1); - UtRegisterTest("SigParseTest13", SigParseTest13, 1); - UtRegisterTest("SigParseTest14", SigParseTest14, 1); - UtRegisterTest("SigParseTest15", SigParseTest15, 1); - UtRegisterTest("SigParseTest16", SigParseTest16, 1); - UtRegisterTest("SigParseTest17", SigParseTest17, 1); - UtRegisterTest("SigParseTest18", SigParseTest18, 1); - UtRegisterTest("SigParseTest19", SigParseTest19, 1); - UtRegisterTest("SigParseTest20", SigParseTest20, 1); - UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21, 1); - UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22, 1); - - UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06, 1); - UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07, 1); - UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08, 1); - UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09, 1); - UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10, 1); - UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11, 1); - UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12, 1); - UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13, 1); - UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14, 1); - UtRegisterTest("SigTestBidirec01", SigTestBidirec01, 1); - UtRegisterTest("SigTestBidirec02", SigTestBidirec02, 1); - UtRegisterTest("SigTestBidirec03", SigTestBidirec03, 1); - UtRegisterTest("SigTestBidirec04", SigTestBidirec04, 1); - UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01, 1); - UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02, 1); - UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03, 1); - UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04, 1); - UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05, 1); - UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06, 1); - UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07, 1); - UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08, 1); - UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01, 1); - UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02, 1); - UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01, 1); - UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02, 1); - UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03, 1); + UtRegisterTest("SigParseTest01", SigParseTest01); + UtRegisterTest("SigParseTest02", SigParseTest02); + UtRegisterTest("SigParseTest03", SigParseTest03); + UtRegisterTest("SigParseTest04", SigParseTest04); + UtRegisterTest("SigParseTest05", SigParseTest05); + UtRegisterTest("SigParseTest06", SigParseTest06); + UtRegisterTest("SigParseTest07", SigParseTest07); + UtRegisterTest("SigParseTest08", SigParseTest08); + UtRegisterTest("SigParseTest09", SigParseTest09); + UtRegisterTest("SigParseTest10", SigParseTest10); + UtRegisterTest("SigParseTest11", SigParseTest11); + UtRegisterTest("SigParseTest12", SigParseTest12); + UtRegisterTest("SigParseTest13", SigParseTest13); + UtRegisterTest("SigParseTest14", SigParseTest14); + UtRegisterTest("SigParseTest15", SigParseTest15); + UtRegisterTest("SigParseTest16", SigParseTest16); + UtRegisterTest("SigParseTest17", SigParseTest17); + UtRegisterTest("SigParseTest18", SigParseTest18); + UtRegisterTest("SigParseTest19", SigParseTest19); + UtRegisterTest("SigParseTest20", SigParseTest20); + UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21); + UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22); + + UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06); + UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07); + UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08); + UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09); + UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10); + UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11); + UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12); + UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13); + UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14); + UtRegisterTest("SigTestBidirec01", SigTestBidirec01); + UtRegisterTest("SigTestBidirec02", SigTestBidirec02); + UtRegisterTest("SigTestBidirec03", SigTestBidirec03); + UtRegisterTest("SigTestBidirec04", SigTestBidirec04); + UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01); + UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02); + UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03); + UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04); + UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05); + UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06); + UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07); + UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08); + UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01); + UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02); + UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01); + UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02); + UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03); #endif /* UNITTESTS */ } diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 6184cc658bdb..c3274e4f519b 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -4093,61 +4093,80 @@ static int DetectPcreParseHttpHost(void) void DetectPcreRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01, 1); - UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02, 1); - UtRegisterTest("DetectPcreParseTest03", DetectPcreParseTest03, 1); - UtRegisterTest("DetectPcreParseTest04", DetectPcreParseTest04, 1); - UtRegisterTest("DetectPcreParseTest05", DetectPcreParseTest05, 1); - UtRegisterTest("DetectPcreParseTest06", DetectPcreParseTest06, 1); - UtRegisterTest("DetectPcreParseTest07", DetectPcreParseTest07, 1); - UtRegisterTest("DetectPcreParseTest08", DetectPcreParseTest08, 1); - UtRegisterTest("DetectPcreParseTest09", DetectPcreParseTest09, 1); - UtRegisterTest("DetectPcreParseTest10", DetectPcreParseTest10, 1); - UtRegisterTest("DetectPcreParseTest11", DetectPcreParseTest11, 1); - UtRegisterTest("DetectPcreParseTest12", DetectPcreParseTest12, 1); - UtRegisterTest("DetectPcreParseTest13", DetectPcreParseTest13, 1); - UtRegisterTest("DetectPcreParseTest14", DetectPcreParseTest14, 1); - UtRegisterTest("DetectPcreParseTest15", DetectPcreParseTest15, 1); - UtRegisterTest("DetectPcreParseTest16", DetectPcreParseTest16, 1); - UtRegisterTest("DetectPcreParseTest17", DetectPcreParseTest17, 1); - UtRegisterTest("DetectPcreParseTest18", DetectPcreParseTest18, 1); - UtRegisterTest("DetectPcreParseTest19", DetectPcreParseTest19, 1); - UtRegisterTest("DetectPcreParseTest20", DetectPcreParseTest20, 1); - UtRegisterTest("DetectPcreParseTest21", DetectPcreParseTest21, 1); - UtRegisterTest("DetectPcreParseTest22", DetectPcreParseTest22, 1); - UtRegisterTest("DetectPcreParseTest23", DetectPcreParseTest23, 1); - UtRegisterTest("DetectPcreParseTest24", DetectPcreParseTest24, 1); - UtRegisterTest("DetectPcreParseTest25", DetectPcreParseTest25, 1); - UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26, 1); - UtRegisterTest("DetectPcreParseTest27", DetectPcreParseTest27, 1); - - UtRegisterTest("DetectPcreTestSig01 -- pcre test", DetectPcreTestSig01, 1); - UtRegisterTest("DetectPcreTestSig02 -- pcre test", DetectPcreTestSig02, 1); - UtRegisterTest("DetectPcreTestSig03 -- negated pcre test", DetectPcreTestSig03, 1); - - UtRegisterTest("DetectPcreModifPTest04 -- Modifier P", DetectPcreModifPTest04, 1); - UtRegisterTest("DetectPcreModifPTest05 -- Modifier P fragmented", DetectPcreModifPTest05, 1); - UtRegisterTest("DetectPcreTestSig06", DetectPcreTestSig06, 1); - UtRegisterTest("DetectPcreTestSig07 -- anchored pcre", DetectPcreTestSig07, 1); - UtRegisterTest("DetectPcreTestSig08 -- anchored pcre", DetectPcreTestSig08, 1); - UtRegisterTest("DetectPcreTestSig09 -- Cookie modifier", DetectPcreTestSig09, 1); - UtRegisterTest("DetectPcreTestSig10 -- negated Cookie modifier", DetectPcreTestSig10, 1); - UtRegisterTest("DetectPcreTestSig11 -- Method modifier", DetectPcreTestSig11, 1); - UtRegisterTest("DetectPcreTestSig12 -- negated Method modifier", DetectPcreTestSig12, 1); - UtRegisterTest("DetectPcreTestSig13 -- Header modifier", DetectPcreTestSig13, 1); - UtRegisterTest("DetectPcreTestSig14 -- negated Header modifier", DetectPcreTestSig14, 1); - UtRegisterTest("DetectPcreTestSig15 -- relative Cookie modifier", DetectPcreTestSig15, 1); - UtRegisterTest("DetectPcreTestSig16 -- relative Method modifier", DetectPcreTestSig16, 1); - - UtRegisterTest("DetectPcreTxBodyChunksTest01", DetectPcreTxBodyChunksTest01, 1); - UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest02, 1); - UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest03, 1); - - UtRegisterTest("DetectPcreFlowvarCapture01 -- capture for http_header", DetectPcreFlowvarCapture01, 1); - UtRegisterTest("DetectPcreFlowvarCapture02 -- capture for http_header", DetectPcreFlowvarCapture02, 1); - UtRegisterTest("DetectPcreFlowvarCapture03 -- capture for http_header", DetectPcreFlowvarCapture03, 1); - - UtRegisterTest("DetectPcreParseHttpHost", DetectPcreParseHttpHost, 1); + UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01); + UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02); + UtRegisterTest("DetectPcreParseTest03", DetectPcreParseTest03); + UtRegisterTest("DetectPcreParseTest04", DetectPcreParseTest04); + UtRegisterTest("DetectPcreParseTest05", DetectPcreParseTest05); + UtRegisterTest("DetectPcreParseTest06", DetectPcreParseTest06); + UtRegisterTest("DetectPcreParseTest07", DetectPcreParseTest07); + UtRegisterTest("DetectPcreParseTest08", DetectPcreParseTest08); + UtRegisterTest("DetectPcreParseTest09", DetectPcreParseTest09); + UtRegisterTest("DetectPcreParseTest10", DetectPcreParseTest10); + UtRegisterTest("DetectPcreParseTest11", DetectPcreParseTest11); + UtRegisterTest("DetectPcreParseTest12", DetectPcreParseTest12); + UtRegisterTest("DetectPcreParseTest13", DetectPcreParseTest13); + UtRegisterTest("DetectPcreParseTest14", DetectPcreParseTest14); + UtRegisterTest("DetectPcreParseTest15", DetectPcreParseTest15); + UtRegisterTest("DetectPcreParseTest16", DetectPcreParseTest16); + UtRegisterTest("DetectPcreParseTest17", DetectPcreParseTest17); + UtRegisterTest("DetectPcreParseTest18", DetectPcreParseTest18); + UtRegisterTest("DetectPcreParseTest19", DetectPcreParseTest19); + UtRegisterTest("DetectPcreParseTest20", DetectPcreParseTest20); + UtRegisterTest("DetectPcreParseTest21", DetectPcreParseTest21); + UtRegisterTest("DetectPcreParseTest22", DetectPcreParseTest22); + UtRegisterTest("DetectPcreParseTest23", DetectPcreParseTest23); + UtRegisterTest("DetectPcreParseTest24", DetectPcreParseTest24); + UtRegisterTest("DetectPcreParseTest25", DetectPcreParseTest25); + UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26); + UtRegisterTest("DetectPcreParseTest27", DetectPcreParseTest27); + + UtRegisterTest("DetectPcreTestSig01 -- pcre test", DetectPcreTestSig01); + UtRegisterTest("DetectPcreTestSig02 -- pcre test", DetectPcreTestSig02); + UtRegisterTest("DetectPcreTestSig03 -- negated pcre test", + DetectPcreTestSig03); + + UtRegisterTest("DetectPcreModifPTest04 -- Modifier P", + DetectPcreModifPTest04); + UtRegisterTest("DetectPcreModifPTest05 -- Modifier P fragmented", + DetectPcreModifPTest05); + UtRegisterTest("DetectPcreTestSig06", DetectPcreTestSig06); + UtRegisterTest("DetectPcreTestSig07 -- anchored pcre", + DetectPcreTestSig07); + UtRegisterTest("DetectPcreTestSig08 -- anchored pcre", + DetectPcreTestSig08); + UtRegisterTest("DetectPcreTestSig09 -- Cookie modifier", + DetectPcreTestSig09); + UtRegisterTest("DetectPcreTestSig10 -- negated Cookie modifier", + DetectPcreTestSig10); + UtRegisterTest("DetectPcreTestSig11 -- Method modifier", + DetectPcreTestSig11); + UtRegisterTest("DetectPcreTestSig12 -- negated Method modifier", + DetectPcreTestSig12); + UtRegisterTest("DetectPcreTestSig13 -- Header modifier", + DetectPcreTestSig13); + UtRegisterTest("DetectPcreTestSig14 -- negated Header modifier", + DetectPcreTestSig14); + UtRegisterTest("DetectPcreTestSig15 -- relative Cookie modifier", + DetectPcreTestSig15); + UtRegisterTest("DetectPcreTestSig16 -- relative Method modifier", + DetectPcreTestSig16); + + UtRegisterTest("DetectPcreTxBodyChunksTest01", + DetectPcreTxBodyChunksTest01); + UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx", + DetectPcreTxBodyChunksTest02); + UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx", + DetectPcreTxBodyChunksTest03); + + UtRegisterTest("DetectPcreFlowvarCapture01 -- capture for http_header", + DetectPcreFlowvarCapture01); + UtRegisterTest("DetectPcreFlowvarCapture02 -- capture for http_header", + DetectPcreFlowvarCapture02); + UtRegisterTest("DetectPcreFlowvarCapture03 -- capture for http_header", + DetectPcreFlowvarCapture03); + + UtRegisterTest("DetectPcreParseHttpHost", DetectPcreParseHttpHost); #endif /* UNITTESTS */ } diff --git a/src/detect-pkt-data.c b/src/detect-pkt-data.c index df65444a5d70..fc04d3b21f93 100644 --- a/src/detect-pkt-data.c +++ b/src/detect-pkt-data.c @@ -146,7 +146,7 @@ static int DetectPktDataTest01(void) static void DetectPktDataTestRegister(void) { #ifdef UNITTESTS - UtRegisterTest("DetectPktDataTest01", DetectPktDataTest01, 1); + UtRegisterTest("DetectPktDataTest01", DetectPktDataTest01); #endif } diff --git a/src/detect-priority.c b/src/detect-priority.c index 5bb0359f85ca..66b736fb5739 100644 --- a/src/detect-priority.c +++ b/src/detect-priority.c @@ -213,8 +213,8 @@ void SCPriorityRegisterTests(void) #ifdef UNITTESTS - UtRegisterTest("DetectPriorityTest01", DetectPriorityTest01, 1); - UtRegisterTest("DetectPriorityTest02", DetectPriorityTest02, 1); + UtRegisterTest("DetectPriorityTest01", DetectPriorityTest01); + UtRegisterTest("DetectPriorityTest02", DetectPriorityTest02); #endif /* UNITTESTS */ diff --git a/src/detect-reference.c b/src/detect-reference.c index a672f5c2fcdc..d1473cc1b87c 100644 --- a/src/detect-reference.c +++ b/src/detect-reference.c @@ -367,9 +367,9 @@ static int DetectReferenceParseTest03(void) void ReferenceRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectReferenceParseTest01", DetectReferenceParseTest01, 1); - UtRegisterTest("DetectReferenceParseTest02", DetectReferenceParseTest02, 1); - UtRegisterTest("DetectReferenceParseTest03", DetectReferenceParseTest03, 1); + UtRegisterTest("DetectReferenceParseTest01", DetectReferenceParseTest01); + UtRegisterTest("DetectReferenceParseTest02", DetectReferenceParseTest02); + UtRegisterTest("DetectReferenceParseTest03", DetectReferenceParseTest03); #endif /* UNITTESTS */ return; diff --git a/src/detect-replace.c b/src/detect-replace.c index 082f59832075..9e9269172c72 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -818,28 +818,28 @@ void DetectReplaceRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ /* matching */ - UtRegisterTest("DetectReplaceMatchTest01", DetectReplaceMatchTest01, 1); - UtRegisterTest("DetectReplaceMatchTest02", DetectReplaceMatchTest02, 1); - UtRegisterTest("DetectReplaceMatchTest03", DetectReplaceMatchTest03, 1); - UtRegisterTest("DetectReplaceMatchTest04", DetectReplaceMatchTest04, 1); - UtRegisterTest("DetectReplaceMatchTest05", DetectReplaceMatchTest05, 1); - UtRegisterTest("DetectReplaceMatchTest06", DetectReplaceMatchTest06, 1); - UtRegisterTest("DetectReplaceMatchTest07", DetectReplaceMatchTest07, 1); - UtRegisterTest("DetectReplaceMatchTest08", DetectReplaceMatchTest08, 1); - UtRegisterTest("DetectReplaceMatchTest09", DetectReplaceMatchTest09, 1); - UtRegisterTest("DetectReplaceMatchTest10", DetectReplaceMatchTest10, 1); - UtRegisterTest("DetectReplaceMatchTest11", DetectReplaceMatchTest11, 1); - UtRegisterTest("DetectReplaceMatchTest12", DetectReplaceMatchTest12, 1); - UtRegisterTest("DetectReplaceMatchTest13", DetectReplaceMatchTest13, 1); - UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14, 1); - UtRegisterTest("DetectReplaceMatchTest15", DetectReplaceMatchTest15, 1); + UtRegisterTest("DetectReplaceMatchTest01", DetectReplaceMatchTest01); + UtRegisterTest("DetectReplaceMatchTest02", DetectReplaceMatchTest02); + UtRegisterTest("DetectReplaceMatchTest03", DetectReplaceMatchTest03); + UtRegisterTest("DetectReplaceMatchTest04", DetectReplaceMatchTest04); + UtRegisterTest("DetectReplaceMatchTest05", DetectReplaceMatchTest05); + UtRegisterTest("DetectReplaceMatchTest06", DetectReplaceMatchTest06); + UtRegisterTest("DetectReplaceMatchTest07", DetectReplaceMatchTest07); + UtRegisterTest("DetectReplaceMatchTest08", DetectReplaceMatchTest08); + UtRegisterTest("DetectReplaceMatchTest09", DetectReplaceMatchTest09); + UtRegisterTest("DetectReplaceMatchTest10", DetectReplaceMatchTest10); + UtRegisterTest("DetectReplaceMatchTest11", DetectReplaceMatchTest11); + UtRegisterTest("DetectReplaceMatchTest12", DetectReplaceMatchTest12); + UtRegisterTest("DetectReplaceMatchTest13", DetectReplaceMatchTest13); + UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14); + UtRegisterTest("DetectReplaceMatchTest15", DetectReplaceMatchTest15); /* parsing */ - UtRegisterTest("DetectReplaceParseTest01", DetectReplaceParseTest01, 1); - UtRegisterTest("DetectReplaceParseTest02", DetectReplaceParseTest02, 1); - UtRegisterTest("DetectReplaceParseTest03", DetectReplaceParseTest03, 1); - UtRegisterTest("DetectReplaceParseTest04", DetectReplaceParseTest04, 1); - UtRegisterTest("DetectReplaceParseTest05", DetectReplaceParseTest05, 1); - UtRegisterTest("DetectReplaceParseTest06", DetectReplaceParseTest06, 1); - UtRegisterTest("DetectReplaceParseTest07", DetectReplaceParseTest07, 1); + UtRegisterTest("DetectReplaceParseTest01", DetectReplaceParseTest01); + UtRegisterTest("DetectReplaceParseTest02", DetectReplaceParseTest02); + UtRegisterTest("DetectReplaceParseTest03", DetectReplaceParseTest03); + UtRegisterTest("DetectReplaceParseTest04", DetectReplaceParseTest04); + UtRegisterTest("DetectReplaceParseTest05", DetectReplaceParseTest05); + UtRegisterTest("DetectReplaceParseTest06", DetectReplaceParseTest06); + UtRegisterTest("DetectReplaceParseTest07", DetectReplaceParseTest07); #endif /* UNITTESTS */ } diff --git a/src/detect-rpc.c b/src/detect-rpc.c index fe693deb19f8..844eb346478d 100644 --- a/src/detect-rpc.c +++ b/src/detect-rpc.c @@ -597,11 +597,11 @@ static int DetectRpcTestSig01(void) void DetectRpcRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectRpcTestParse01", DetectRpcTestParse01, 1); - UtRegisterTest("DetectRpcTestParse02", DetectRpcTestParse02, 1); - UtRegisterTest("DetectRpcTestParse03", DetectRpcTestParse03, 1); - UtRegisterTest("DetectRpcTestParse04", DetectRpcTestParse04, 1); - UtRegisterTest("DetectRpcTestParse05", DetectRpcTestParse05, 1); - UtRegisterTest("DetectRpcTestSig01", DetectRpcTestSig01, 1); + UtRegisterTest("DetectRpcTestParse01", DetectRpcTestParse01); + UtRegisterTest("DetectRpcTestParse02", DetectRpcTestParse02); + UtRegisterTest("DetectRpcTestParse03", DetectRpcTestParse03); + UtRegisterTest("DetectRpcTestParse04", DetectRpcTestParse04); + UtRegisterTest("DetectRpcTestParse05", DetectRpcTestParse05); + UtRegisterTest("DetectRpcTestSig01", DetectRpcTestSig01); #endif /* UNITTESTS */ } diff --git a/src/detect-sameip.c b/src/detect-sameip.c index dd18b16486d9..351b95ec5bf6 100644 --- a/src/detect-sameip.c +++ b/src/detect-sameip.c @@ -190,6 +190,6 @@ static int DetectSameipSigTest01(void) static void DetectSameipRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectSameipSigTest01", DetectSameipSigTest01, 1); + UtRegisterTest("DetectSameipSigTest01", DetectSameipSigTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-seq.c b/src/detect-seq.c index 4d285ca344a1..279a54b19f5c 100644 --- a/src/detect-seq.c +++ b/src/detect-seq.c @@ -236,8 +236,8 @@ static int DetectSeqSigTest02(void) static void DetectSeqRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectSeqSigTest01", DetectSeqSigTest01, 1); - UtRegisterTest("DetectSeqSigTest02", DetectSeqSigTest02, 1); + UtRegisterTest("DetectSeqSigTest01", DetectSeqSigTest01); + UtRegisterTest("DetectSeqSigTest02", DetectSeqSigTest02); #endif /* UNITTESTS */ } diff --git a/src/detect-sid.c b/src/detect-sid.c index a3ed34031535..649604fb129f 100644 --- a/src/detect-sid.c +++ b/src/detect-sid.c @@ -158,8 +158,8 @@ static int SidTestParse03(void) static void DetectSidRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SidTestParse01", SidTestParse01, 1); - UtRegisterTest("SidTestParse02", SidTestParse02, 1); - UtRegisterTest("SidTestParse03", SidTestParse03, 1); + UtRegisterTest("SidTestParse01", SidTestParse01); + UtRegisterTest("SidTestParse02", SidTestParse02); + UtRegisterTest("SidTestParse03", SidTestParse03); #endif /* UNITTESTS */ } diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index 96a8b6763050..98306483890b 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -689,12 +689,15 @@ static int DetectSshVersionTestDetect03(void) void DetectSshVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectSshVersionTestParse01", DetectSshVersionTestParse01, 1); - UtRegisterTest("DetectSshVersionTestParse02", DetectSshVersionTestParse02, 1); - UtRegisterTest("DetectSshVersionTestParse03", DetectSshVersionTestParse03, 1); - UtRegisterTest("DetectSshVersionTestDetect01", DetectSshVersionTestDetect01, 1); - UtRegisterTest("DetectSshVersionTestDetect02", DetectSshVersionTestDetect02, 1); - UtRegisterTest("DetectSshVersionTestDetect03", DetectSshVersionTestDetect03, 1); + UtRegisterTest("DetectSshVersionTestParse01", DetectSshVersionTestParse01); + UtRegisterTest("DetectSshVersionTestParse02", DetectSshVersionTestParse02); + UtRegisterTest("DetectSshVersionTestParse03", DetectSshVersionTestParse03); + UtRegisterTest("DetectSshVersionTestDetect01", + DetectSshVersionTestDetect01); + UtRegisterTest("DetectSshVersionTestDetect02", + DetectSshVersionTestDetect02); + UtRegisterTest("DetectSshVersionTestDetect03", + DetectSshVersionTestDetect03); #endif /* UNITTESTS */ } diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index 4197bfffffdf..12ba869e445f 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -662,12 +662,18 @@ static int DetectSshSoftwareVersionTestDetect03(void) void DetectSshSoftwareVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectSshSoftwareVersionTestParse01", DetectSshSoftwareVersionTestParse01, 1); - UtRegisterTest("DetectSshSoftwareVersionTestParse02", DetectSshSoftwareVersionTestParse02, 1); - UtRegisterTest("DetectSshSoftwareVersionTestParse03", DetectSshSoftwareVersionTestParse03, 1); - UtRegisterTest("DetectSshSoftwareVersionTestDetect01", DetectSshSoftwareVersionTestDetect01, 1); - UtRegisterTest("DetectSshSoftwareVersionTestDetect02", DetectSshSoftwareVersionTestDetect02, 1); - UtRegisterTest("DetectSshSoftwareVersionTestDetect03", DetectSshSoftwareVersionTestDetect03, 1); + UtRegisterTest("DetectSshSoftwareVersionTestParse01", + DetectSshSoftwareVersionTestParse01); + UtRegisterTest("DetectSshSoftwareVersionTestParse02", + DetectSshSoftwareVersionTestParse02); + UtRegisterTest("DetectSshSoftwareVersionTestParse03", + DetectSshSoftwareVersionTestParse03); + UtRegisterTest("DetectSshSoftwareVersionTestDetect01", + DetectSshSoftwareVersionTestDetect01); + UtRegisterTest("DetectSshSoftwareVersionTestDetect02", + DetectSshSoftwareVersionTestDetect02); + UtRegisterTest("DetectSshSoftwareVersionTestDetect03", + DetectSshSoftwareVersionTestDetect03); #endif /* UNITTESTS */ } diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index ffd6f39d68ed..770ed659b417 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -901,13 +901,13 @@ static int DetectSslStateTest07(void) void DetectSslStateRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectSslStateTest01", DetectSslStateTest01, 1); - UtRegisterTest("DetectSslStateTest02", DetectSslStateTest02, 1); - UtRegisterTest("DetectSslStateTest03", DetectSslStateTest03, 1); - UtRegisterTest("DetectSslStateTest04", DetectSslStateTest04, 1); - UtRegisterTest("DetectSslStateTest05", DetectSslStateTest05, 1); - UtRegisterTest("DetectSslStateTest06", DetectSslStateTest06, 1); - UtRegisterTest("DetectSslStateTest07", DetectSslStateTest07, 1); + UtRegisterTest("DetectSslStateTest01", DetectSslStateTest01); + UtRegisterTest("DetectSslStateTest02", DetectSslStateTest02); + UtRegisterTest("DetectSslStateTest03", DetectSslStateTest03); + UtRegisterTest("DetectSslStateTest04", DetectSslStateTest04); + UtRegisterTest("DetectSslStateTest05", DetectSslStateTest05); + UtRegisterTest("DetectSslStateTest06", DetectSslStateTest06); + UtRegisterTest("DetectSslStateTest07", DetectSslStateTest07); #endif return; diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index 266c15d68d85..03a1f39eb25d 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -793,12 +793,15 @@ static int DetectSslVersionTestDetect03(void) void DetectSslVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectSslVersionTestParse01", DetectSslVersionTestParse01, 1); - UtRegisterTest("DetectSslVersionTestParse02", DetectSslVersionTestParse02, 1); - UtRegisterTest("DetectSslVersionTestParse03", DetectSslVersionTestParse03, 1); - UtRegisterTest("DetectSslVersionTestDetect01", DetectSslVersionTestDetect01, 1); - UtRegisterTest("DetectSslVersionTestDetect02", DetectSslVersionTestDetect02, 1); - UtRegisterTest("DetectSslVersionTestDetect03", DetectSslVersionTestDetect03, 1); + UtRegisterTest("DetectSslVersionTestParse01", DetectSslVersionTestParse01); + UtRegisterTest("DetectSslVersionTestParse02", DetectSslVersionTestParse02); + UtRegisterTest("DetectSslVersionTestParse03", DetectSslVersionTestParse03); + UtRegisterTest("DetectSslVersionTestDetect01", + DetectSslVersionTestDetect01); + UtRegisterTest("DetectSslVersionTestDetect02", + DetectSslVersionTestDetect02); + UtRegisterTest("DetectSslVersionTestDetect03", + DetectSslVersionTestDetect03); #endif /* UNITTESTS */ return; diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c index c3eaad90f014..c58ecf5a2216 100644 --- a/src/detect-stream_size.c +++ b/src/detect-stream_size.c @@ -523,10 +523,10 @@ static int DetectStreamSizeParseTest04 (void) void DetectStreamSizeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectStreamSizeParseTest01", DetectStreamSizeParseTest01, 1); - UtRegisterTest("DetectStreamSizeParseTest02", DetectStreamSizeParseTest02, 1); - UtRegisterTest("DetectStreamSizeParseTest03", DetectStreamSizeParseTest03, 1); - UtRegisterTest("DetectStreamSizeParseTest04", DetectStreamSizeParseTest04, 1); + UtRegisterTest("DetectStreamSizeParseTest01", DetectStreamSizeParseTest01); + UtRegisterTest("DetectStreamSizeParseTest02", DetectStreamSizeParseTest02); + UtRegisterTest("DetectStreamSizeParseTest03", DetectStreamSizeParseTest03); + UtRegisterTest("DetectStreamSizeParseTest04", DetectStreamSizeParseTest04); #endif /* UNITTESTS */ } diff --git a/src/detect-tag.c b/src/detect-tag.c index d011a0bea4d3..6a3f8ad8c0b3 100644 --- a/src/detect-tag.c +++ b/src/detect-tag.c @@ -477,11 +477,11 @@ static int DetectTagTestParse05(void) void DetectTagRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectTagTestParse01", DetectTagTestParse01, 1); - UtRegisterTest("DetectTagTestParse02", DetectTagTestParse02, 1); - UtRegisterTest("DetectTagTestParse03", DetectTagTestParse03, 1); - UtRegisterTest("DetectTagTestParse04", DetectTagTestParse04, 1); - UtRegisterTest("DetectTagTestParse05", DetectTagTestParse05, 1); + UtRegisterTest("DetectTagTestParse01", DetectTagTestParse01); + UtRegisterTest("DetectTagTestParse02", DetectTagTestParse02); + UtRegisterTest("DetectTagTestParse03", DetectTagTestParse03); + UtRegisterTest("DetectTagTestParse04", DetectTagTestParse04); + UtRegisterTest("DetectTagTestParse05", DetectTagTestParse05); DetectEngineTagRegisterTests(); #endif /* UNITTESTS */ diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index d9f9aa67ce55..50521f937f94 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -165,6 +165,6 @@ static int DetectTemplateBufferTest(void) static void DetectTemplateBufferRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectTemplateBufferTest", DetectTemplateBufferTest, 1); + UtRegisterTest("DetectTemplateBufferTest", DetectTemplateBufferTest); #endif /* UNITTESTS */ } diff --git a/src/detect-template.c b/src/detect-template.c index ecad7880b55b..b2fb26d6c306 100644 --- a/src/detect-template.c +++ b/src/detect-template.c @@ -295,9 +295,8 @@ static int DetectTemplateSignatureTest01 (void) { */ void DetectTemplateRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectTemplateParseTest01", - DetectTemplateParseTest01, 1); + UtRegisterTest("DetectTemplateParseTest01", DetectTemplateParseTest01); UtRegisterTest("DetectTemplateSignatureTest01", - DetectTemplateSignatureTest01, 1); + DetectTemplateSignatureTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-threshold.c b/src/detect-threshold.c index e0850a3c9b68..7410b2c282ed 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -1500,23 +1500,24 @@ static int DetectThresholdTestSig12(void) void ThresholdRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ThresholdTestParse01", ThresholdTestParse01, 1); - UtRegisterTest("ThresholdTestParse02", ThresholdTestParse02, 1); - UtRegisterTest("ThresholdTestParse03", ThresholdTestParse03, 1); - UtRegisterTest("ThresholdTestParse04", ThresholdTestParse04, 1); - UtRegisterTest("ThresholdTestParse05", ThresholdTestParse05, 1); - UtRegisterTest("DetectThresholdTestSig1", DetectThresholdTestSig1, 1); - UtRegisterTest("DetectThresholdTestSig2", DetectThresholdTestSig2, 1); - UtRegisterTest("DetectThresholdTestSig3", DetectThresholdTestSig3, 1); - UtRegisterTest("DetectThresholdTestSig4", DetectThresholdTestSig4, 1); - UtRegisterTest("DetectThresholdTestSig5", DetectThresholdTestSig5, 1); - UtRegisterTest("DetectThresholdTestSig6Ticks", DetectThresholdTestSig6Ticks, 1); - UtRegisterTest("DetectThresholdTestSig7", DetectThresholdTestSig7, 1); - UtRegisterTest("DetectThresholdTestSig8", DetectThresholdTestSig8, 1); - UtRegisterTest("DetectThresholdTestSig9", DetectThresholdTestSig9, 1); - UtRegisterTest("DetectThresholdTestSig10", DetectThresholdTestSig10, 1); - UtRegisterTest("DetectThresholdTestSig11", DetectThresholdTestSig11, 1); - UtRegisterTest("DetectThresholdTestSig12", DetectThresholdTestSig12, 1); + UtRegisterTest("ThresholdTestParse01", ThresholdTestParse01); + UtRegisterTest("ThresholdTestParse02", ThresholdTestParse02); + UtRegisterTest("ThresholdTestParse03", ThresholdTestParse03); + UtRegisterTest("ThresholdTestParse04", ThresholdTestParse04); + UtRegisterTest("ThresholdTestParse05", ThresholdTestParse05); + UtRegisterTest("DetectThresholdTestSig1", DetectThresholdTestSig1); + UtRegisterTest("DetectThresholdTestSig2", DetectThresholdTestSig2); + UtRegisterTest("DetectThresholdTestSig3", DetectThresholdTestSig3); + UtRegisterTest("DetectThresholdTestSig4", DetectThresholdTestSig4); + UtRegisterTest("DetectThresholdTestSig5", DetectThresholdTestSig5); + UtRegisterTest("DetectThresholdTestSig6Ticks", + DetectThresholdTestSig6Ticks); + UtRegisterTest("DetectThresholdTestSig7", DetectThresholdTestSig7); + UtRegisterTest("DetectThresholdTestSig8", DetectThresholdTestSig8); + UtRegisterTest("DetectThresholdTestSig9", DetectThresholdTestSig9); + UtRegisterTest("DetectThresholdTestSig10", DetectThresholdTestSig10); + UtRegisterTest("DetectThresholdTestSig11", DetectThresholdTestSig11); + UtRegisterTest("DetectThresholdTestSig12", DetectThresholdTestSig12); #endif /* UNITTESTS */ } diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index 26fb7405408b..144b5031e8fc 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -713,11 +713,14 @@ static int DetectTlsVersionTestDetect03(void) void DetectTlsVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectTlsVersionTestParse01", DetectTlsVersionTestParse01, 1); - UtRegisterTest("DetectTlsVersionTestParse02", DetectTlsVersionTestParse02, 1); - UtRegisterTest("DetectTlsVersionTestDetect01", DetectTlsVersionTestDetect01, 1); - UtRegisterTest("DetectTlsVersionTestDetect02", DetectTlsVersionTestDetect02, 1); - UtRegisterTest("DetectTlsVersionTestDetect03", DetectTlsVersionTestDetect03, 1); + UtRegisterTest("DetectTlsVersionTestParse01", DetectTlsVersionTestParse01); + UtRegisterTest("DetectTlsVersionTestParse02", DetectTlsVersionTestParse02); + UtRegisterTest("DetectTlsVersionTestDetect01", + DetectTlsVersionTestDetect01); + UtRegisterTest("DetectTlsVersionTestDetect02", + DetectTlsVersionTestDetect02); + UtRegisterTest("DetectTlsVersionTestDetect03", + DetectTlsVersionTestDetect03); #endif /* UNITTESTS */ } diff --git a/src/detect-tos.c b/src/detect-tos.c index 40928261d782..f82dc453a95d 100644 --- a/src/detect-tos.c +++ b/src/detect-tos.c @@ -412,18 +412,18 @@ int DetectTosTest12(void) void DetectTosRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectTosTest01", DetectTosTest01, 1); - UtRegisterTest("DetectTosTest02", DetectTosTest02, 1); - UtRegisterTest("DetectTosTest03", DetectTosTest03, 1); - UtRegisterTest("DetectTosTest04", DetectTosTest04, 1); - UtRegisterTest("DetectTosTest05", DetectTosTest05, 1); - UtRegisterTest("DetectTosTest06", DetectTosTest06, 1); - UtRegisterTest("DetectTosTest07", DetectTosTest07, 1); - UtRegisterTest("DetectTosTest08", DetectTosTest08, 1); - UtRegisterTest("DetectTosTest09", DetectTosTest09, 1); - UtRegisterTest("DetectTosTest10", DetectTosTest10, 1); - UtRegisterTest("DetectTosTest11", DetectTosTest11, 1); - UtRegisterTest("DetectTosTest12", DetectTosTest12, 1); + UtRegisterTest("DetectTosTest01", DetectTosTest01); + UtRegisterTest("DetectTosTest02", DetectTosTest02); + UtRegisterTest("DetectTosTest03", DetectTosTest03); + UtRegisterTest("DetectTosTest04", DetectTosTest04); + UtRegisterTest("DetectTosTest05", DetectTosTest05); + UtRegisterTest("DetectTosTest06", DetectTosTest06); + UtRegisterTest("DetectTosTest07", DetectTosTest07); + UtRegisterTest("DetectTosTest08", DetectTosTest08); + UtRegisterTest("DetectTosTest09", DetectTosTest09); + UtRegisterTest("DetectTosTest10", DetectTosTest10); + UtRegisterTest("DetectTosTest11", DetectTosTest11); + UtRegisterTest("DetectTosTest12", DetectTosTest12); #endif return; diff --git a/src/detect-ttl.c b/src/detect-ttl.c index 80f3966726af..316af96967f1 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -625,14 +625,14 @@ static int DetectTtlTestSig1(void) void DetectTtlRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectTtlParseTest01", DetectTtlParseTest01, 1); - UtRegisterTest("DetectTtlParseTest02", DetectTtlParseTest02, 1); - UtRegisterTest("DetectTtlParseTest03", DetectTtlParseTest03, 1); - UtRegisterTest("DetectTtlParseTest04", DetectTtlParseTest04, 1); - UtRegisterTest("DetectTtlParseTest05", DetectTtlParseTest05, 1); - UtRegisterTest("DetectTtlParseTest06", DetectTtlParseTest06, 1); - UtRegisterTest("DetectTtlParseTest07", DetectTtlParseTest07, 1); - UtRegisterTest("DetectTtlSetpTest01", DetectTtlSetpTest01, 1); - UtRegisterTest("DetectTtlTestSig1", DetectTtlTestSig1, 1); + UtRegisterTest("DetectTtlParseTest01", DetectTtlParseTest01); + UtRegisterTest("DetectTtlParseTest02", DetectTtlParseTest02); + UtRegisterTest("DetectTtlParseTest03", DetectTtlParseTest03); + UtRegisterTest("DetectTtlParseTest04", DetectTtlParseTest04); + UtRegisterTest("DetectTtlParseTest05", DetectTtlParseTest05); + UtRegisterTest("DetectTtlParseTest06", DetectTtlParseTest06); + UtRegisterTest("DetectTtlParseTest07", DetectTtlParseTest07); + UtRegisterTest("DetectTtlSetpTest01", DetectTtlSetpTest01); + UtRegisterTest("DetectTtlTestSig1", DetectTtlTestSig1); #endif /* UNITTESTS */ } diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index b6927d205b8d..6b79636b3c5e 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -1869,35 +1869,35 @@ int DetectUriContentParseTest24(void) void HttpUriRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HTTPUriTest01", HTTPUriTest01, 1); - UtRegisterTest("HTTPUriTest02", HTTPUriTest02, 1); - UtRegisterTest("HTTPUriTest03", HTTPUriTest03, 1); - UtRegisterTest("HTTPUriTest04", HTTPUriTest04, 1); - - UtRegisterTest("DetectUriSigTest01", DetectUriSigTest01, 1); - UtRegisterTest("DetectUriSigTest02", DetectUriSigTest02, 1); - UtRegisterTest("DetectUriSigTest03", DetectUriSigTest03, 1); - UtRegisterTest("DetectUriSigTest04 - Modifiers", DetectUriSigTest04, 1); - UtRegisterTest("DetectUriSigTest05 - Inspection", DetectUriSigTest05, 1); - UtRegisterTest("DetectUriSigTest06 - Inspection", DetectUriSigTest06, 1); - UtRegisterTest("DetectUriSigTest07 - Inspection", DetectUriSigTest07, 1); - UtRegisterTest("DetectUriSigTest08", DetectUriSigTest08, 1); - UtRegisterTest("DetectUriSigTest09", DetectUriSigTest09, 1); - UtRegisterTest("DetectUriSigTest10", DetectUriSigTest10, 1); - UtRegisterTest("DetectUriSigTest11", DetectUriSigTest11, 1); - UtRegisterTest("DetectUriSigTest12", DetectUriSigTest12, 1); - - UtRegisterTest("DetectUriContentParseTest13", DetectUriContentParseTest13, 1); - UtRegisterTest("DetectUriContentParseTest14", DetectUriContentParseTest14, 1); - UtRegisterTest("DetectUriContentParseTest15", DetectUriContentParseTest15, 1); - UtRegisterTest("DetectUriContentParseTest16", DetectUriContentParseTest16, 1); - UtRegisterTest("DetectUriContentParseTest17", DetectUriContentParseTest17, 1); - UtRegisterTest("DetectUriContentParseTest18", DetectUriContentParseTest18, 1); - UtRegisterTest("DetectUriContentParseTest19", DetectUriContentParseTest19, 1); - UtRegisterTest("DetectUriContentParseTest20", DetectUriContentParseTest20, 1); - UtRegisterTest("DetectUriContentParseTest21", DetectUriContentParseTest21, 1); - UtRegisterTest("DetectUriContentParseTest22", DetectUriContentParseTest22, 1); - UtRegisterTest("DetectUriContentParseTest23", DetectUriContentParseTest23, 1); - UtRegisterTest("DetectUriContentParseTest24", DetectUriContentParseTest24, 1); + UtRegisterTest("HTTPUriTest01", HTTPUriTest01); + UtRegisterTest("HTTPUriTest02", HTTPUriTest02); + UtRegisterTest("HTTPUriTest03", HTTPUriTest03); + UtRegisterTest("HTTPUriTest04", HTTPUriTest04); + + UtRegisterTest("DetectUriSigTest01", DetectUriSigTest01); + UtRegisterTest("DetectUriSigTest02", DetectUriSigTest02); + UtRegisterTest("DetectUriSigTest03", DetectUriSigTest03); + UtRegisterTest("DetectUriSigTest04 - Modifiers", DetectUriSigTest04); + UtRegisterTest("DetectUriSigTest05 - Inspection", DetectUriSigTest05); + UtRegisterTest("DetectUriSigTest06 - Inspection", DetectUriSigTest06); + UtRegisterTest("DetectUriSigTest07 - Inspection", DetectUriSigTest07); + UtRegisterTest("DetectUriSigTest08", DetectUriSigTest08); + UtRegisterTest("DetectUriSigTest09", DetectUriSigTest09); + UtRegisterTest("DetectUriSigTest10", DetectUriSigTest10); + UtRegisterTest("DetectUriSigTest11", DetectUriSigTest11); + UtRegisterTest("DetectUriSigTest12", DetectUriSigTest12); + + UtRegisterTest("DetectUriContentParseTest13", DetectUriContentParseTest13); + UtRegisterTest("DetectUriContentParseTest14", DetectUriContentParseTest14); + UtRegisterTest("DetectUriContentParseTest15", DetectUriContentParseTest15); + UtRegisterTest("DetectUriContentParseTest16", DetectUriContentParseTest16); + UtRegisterTest("DetectUriContentParseTest17", DetectUriContentParseTest17); + UtRegisterTest("DetectUriContentParseTest18", DetectUriContentParseTest18); + UtRegisterTest("DetectUriContentParseTest19", DetectUriContentParseTest19); + UtRegisterTest("DetectUriContentParseTest20", DetectUriContentParseTest20); + UtRegisterTest("DetectUriContentParseTest21", DetectUriContentParseTest21); + UtRegisterTest("DetectUriContentParseTest22", DetectUriContentParseTest22); + UtRegisterTest("DetectUriContentParseTest23", DetectUriContentParseTest23); + UtRegisterTest("DetectUriContentParseTest24", DetectUriContentParseTest24); #endif /* UNITTESTS */ } diff --git a/src/detect-urilen.c b/src/detect-urilen.c index 1355f5594232..d7e5bdd8c86b 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -684,17 +684,17 @@ static int DetectUrilenSigTest01(void) void DetectUrilenRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectUrilenParseTest01", DetectUrilenParseTest01, 1); - UtRegisterTest("DetectUrilenParseTest02", DetectUrilenParseTest02, 1); - UtRegisterTest("DetectUrilenParseTest03", DetectUrilenParseTest03, 1); - UtRegisterTest("DetectUrilenParseTest04", DetectUrilenParseTest04, 1); - UtRegisterTest("DetectUrilenParseTest05", DetectUrilenParseTest05, 1); - UtRegisterTest("DetectUrilenParseTest06", DetectUrilenParseTest06, 1); - UtRegisterTest("DetectUrilenParseTest07", DetectUrilenParseTest07, 1); - UtRegisterTest("DetectUrilenParseTest08", DetectUrilenParseTest08, 1); - UtRegisterTest("DetectUrilenParseTest09", DetectUrilenParseTest09, 1); - UtRegisterTest("DetectUrilenParseTest10", DetectUrilenParseTest10, 1); - UtRegisterTest("DetectUrilenSetpTest01", DetectUrilenSetpTest01, 1); - UtRegisterTest("DetectUrilenSigTest01", DetectUrilenSigTest01, 1); + UtRegisterTest("DetectUrilenParseTest01", DetectUrilenParseTest01); + UtRegisterTest("DetectUrilenParseTest02", DetectUrilenParseTest02); + UtRegisterTest("DetectUrilenParseTest03", DetectUrilenParseTest03); + UtRegisterTest("DetectUrilenParseTest04", DetectUrilenParseTest04); + UtRegisterTest("DetectUrilenParseTest05", DetectUrilenParseTest05); + UtRegisterTest("DetectUrilenParseTest06", DetectUrilenParseTest06); + UtRegisterTest("DetectUrilenParseTest07", DetectUrilenParseTest07); + UtRegisterTest("DetectUrilenParseTest08", DetectUrilenParseTest08); + UtRegisterTest("DetectUrilenParseTest09", DetectUrilenParseTest09); + UtRegisterTest("DetectUrilenParseTest10", DetectUrilenParseTest10); + UtRegisterTest("DetectUrilenSetpTest01", DetectUrilenSetpTest01); + UtRegisterTest("DetectUrilenSigTest01", DetectUrilenSigTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-window.c b/src/detect-window.c index 0fb1afb86501..d3704f4f81c4 100644 --- a/src/detect-window.c +++ b/src/detect-window.c @@ -358,10 +358,10 @@ int DetectWindowTestPacket01 (void) void DetectWindowRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectWindowTestParse01", DetectWindowTestParse01, 1); - UtRegisterTest("DetectWindowTestParse02", DetectWindowTestParse02, 1); - UtRegisterTest("DetectWindowTestParse03", DetectWindowTestParse03, 1); - UtRegisterTest("DetectWindowTestParse04", DetectWindowTestParse04, 1); - UtRegisterTest("DetectWindowTestPacket01" , DetectWindowTestPacket01 , 1); + UtRegisterTest("DetectWindowTestParse01", DetectWindowTestParse01); + UtRegisterTest("DetectWindowTestParse02", DetectWindowTestParse02); + UtRegisterTest("DetectWindowTestParse03", DetectWindowTestParse03); + UtRegisterTest("DetectWindowTestParse04", DetectWindowTestParse04); + UtRegisterTest("DetectWindowTestPacket01", DetectWindowTestPacket01); #endif /* UNITTESTS */ } diff --git a/src/detect-within.c b/src/detect-within.c index 2845856fe291..14cd60af2fa7 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -287,8 +287,8 @@ static int DetectWithinTestVarSetup(void) void DetectWithinRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectWithinTestPacket01", DetectWithinTestPacket01, 1); - UtRegisterTest("DetectWithinTestPacket02", DetectWithinTestPacket02, 1); - UtRegisterTest("DetectWithinTestVarSetup", DetectWithinTestVarSetup, 1); + UtRegisterTest("DetectWithinTestPacket01", DetectWithinTestPacket01); + UtRegisterTest("DetectWithinTestPacket02", DetectWithinTestPacket02); + UtRegisterTest("DetectWithinTestVarSetup", DetectWithinTestVarSetup); #endif /* UNITTESTS */ } diff --git a/src/detect-xbits.c b/src/detect-xbits.c index 876ddc36dfdc..f6f3ba74daba 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -539,7 +539,7 @@ static int XBitsTestSig02(void) void XBitsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("XBitsTestSig01", XBitsTestSig01, 1); - UtRegisterTest("XBitsTestSig02", XBitsTestSig02, 1); + UtRegisterTest("XBitsTestSig01", XBitsTestSig01); + UtRegisterTest("XBitsTestSig02", XBitsTestSig02); #endif /* UNITTESTS */ } diff --git a/src/detect.c b/src/detect.c index a93696fd6942..8e8b2597a7f4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -10106,60 +10106,67 @@ void SigRegisterTests(void) SigParseRegisterTests(); IPOnlyRegisterTests(); - UtRegisterTest("SigTest01", SigTest01, 1); - UtRegisterTest("SigTest02 -- Offset/Depth match", SigTest02, 1); - UtRegisterTest("SigTest03 -- offset/depth mismatch", SigTest03, 1); - UtRegisterTest("SigTest04 -- distance/within match", SigTest04, 1); - UtRegisterTest("SigTest05 -- distance/within mismatch", SigTest05, 1); - UtRegisterTest("SigTest06 -- uricontent HTTP/1.1 match test", SigTest06, 1); - UtRegisterTest("SigTest07 -- uricontent HTTP/1.1 mismatch test", SigTest07, 1); - UtRegisterTest("SigTest08 -- uricontent HTTP/1.0 match test", SigTest08, 1); - UtRegisterTest("SigTest09 -- uricontent HTTP/1.0 mismatch test", SigTest09, 1); - UtRegisterTest("SigTest10 -- long content match, longer than pkt", SigTest10, 1); - UtRegisterTest("SigTest11 -- mpm searching", SigTest11, 1); - UtRegisterTest("SigTest12 -- content order matching, normal", SigTest12, 1); - UtRegisterTest("SigTest13 -- content order matching, diff order", SigTest13, 1); - UtRegisterTest("SigTest14 -- content order matching, distance 0", SigTest14, 1); - UtRegisterTest("SigTest15 -- port negation sig (no match)", SigTest15, 1); - UtRegisterTest("SigTest16 -- port negation sig (match)", SigTest16, 1); - UtRegisterTest("SigTest17 -- HTTP Host Pkt var capture", SigTest17, 1); - UtRegisterTest("SigTest18 -- Ftp negation sig test", SigTest18, 1); - UtRegisterTest("SigTest19 -- IP-ONLY test (1)", SigTest19, 1); - UtRegisterTest("SigTest20 -- IP-ONLY test (2)", SigTest20, 1); - UtRegisterTest("SigTest21 -- FLOWBIT test (1)", SigTest21, 1); - UtRegisterTest("SigTest22 -- FLOWBIT test (2)", SigTest22, 1); - UtRegisterTest("SigTest23 -- FLOWBIT test (3)", SigTest23, 1); - - UtRegisterTest("SigTest24IPV4Keyword", SigTest24IPV4Keyword, 1); + UtRegisterTest("SigTest01", SigTest01); + UtRegisterTest("SigTest02 -- Offset/Depth match", SigTest02); + UtRegisterTest("SigTest03 -- offset/depth mismatch", SigTest03); + UtRegisterTest("SigTest04 -- distance/within match", SigTest04); + UtRegisterTest("SigTest05 -- distance/within mismatch", SigTest05); + UtRegisterTest("SigTest06 -- uricontent HTTP/1.1 match test", SigTest06); + UtRegisterTest("SigTest07 -- uricontent HTTP/1.1 mismatch test", + SigTest07); + UtRegisterTest("SigTest08 -- uricontent HTTP/1.0 match test", SigTest08); + UtRegisterTest("SigTest09 -- uricontent HTTP/1.0 mismatch test", + SigTest09); + UtRegisterTest("SigTest10 -- long content match, longer than pkt", + SigTest10); + UtRegisterTest("SigTest11 -- mpm searching", SigTest11); + UtRegisterTest("SigTest12 -- content order matching, normal", SigTest12); + UtRegisterTest("SigTest13 -- content order matching, diff order", + SigTest13); + UtRegisterTest("SigTest14 -- content order matching, distance 0", + SigTest14); + UtRegisterTest("SigTest15 -- port negation sig (no match)", SigTest15); + UtRegisterTest("SigTest16 -- port negation sig (match)", SigTest16); + UtRegisterTest("SigTest17 -- HTTP Host Pkt var capture", SigTest17); + UtRegisterTest("SigTest18 -- Ftp negation sig test", SigTest18); + UtRegisterTest("SigTest19 -- IP-ONLY test (1)", SigTest19); + UtRegisterTest("SigTest20 -- IP-ONLY test (2)", SigTest20); + UtRegisterTest("SigTest21 -- FLOWBIT test (1)", SigTest21); + UtRegisterTest("SigTest22 -- FLOWBIT test (2)", SigTest22); + UtRegisterTest("SigTest23 -- FLOWBIT test (3)", SigTest23); + + UtRegisterTest("SigTest24IPV4Keyword", SigTest24IPV4Keyword); UtRegisterTest("SigTest25NegativeIPV4Keyword", - SigTest25NegativeIPV4Keyword, 1); + SigTest25NegativeIPV4Keyword); - UtRegisterTest("SigTest26TCPV4Keyword", SigTest26TCPV4Keyword, 1); - UtRegisterTest("SigTest26TCPV4AndNegativeIPV4Keyword", SigTest26TCPV4AndNegativeIPV4Keyword, 1); - UtRegisterTest("SigTest26TCPV4AndIPV4Keyword", SigTest26TCPV4AndIPV4Keyword, 1); + UtRegisterTest("SigTest26TCPV4Keyword", SigTest26TCPV4Keyword); + UtRegisterTest("SigTest26TCPV4AndNegativeIPV4Keyword", + SigTest26TCPV4AndNegativeIPV4Keyword); + UtRegisterTest("SigTest26TCPV4AndIPV4Keyword", + SigTest26TCPV4AndIPV4Keyword); UtRegisterTest("SigTest27NegativeTCPV4Keyword", - SigTest27NegativeTCPV4Keyword, 1); + SigTest27NegativeTCPV4Keyword); - UtRegisterTest("SigTest28TCPV6Keyword", SigTest28TCPV6Keyword, 1); + UtRegisterTest("SigTest28TCPV6Keyword", SigTest28TCPV6Keyword); UtRegisterTest("SigTest29NegativeTCPV6Keyword", - SigTest29NegativeTCPV6Keyword, 1); + SigTest29NegativeTCPV6Keyword); - UtRegisterTest("SigTest30UDPV4Keyword", SigTest30UDPV4Keyword, 1); + UtRegisterTest("SigTest30UDPV4Keyword", SigTest30UDPV4Keyword); UtRegisterTest("SigTest31NegativeUDPV4Keyword", - SigTest31NegativeUDPV4Keyword, 1); + SigTest31NegativeUDPV4Keyword); - UtRegisterTest("SigTest32UDPV6Keyword", SigTest32UDPV6Keyword, 1); + UtRegisterTest("SigTest32UDPV6Keyword", SigTest32UDPV6Keyword); UtRegisterTest("SigTest33NegativeUDPV6Keyword", - SigTest33NegativeUDPV6Keyword, 1); + SigTest33NegativeUDPV6Keyword); - UtRegisterTest("SigTest34ICMPV4Keyword", SigTest34ICMPV4Keyword, 1); + UtRegisterTest("SigTest34ICMPV4Keyword", SigTest34ICMPV4Keyword); UtRegisterTest("SigTest35NegativeICMPV4Keyword", - SigTest35NegativeICMPV4Keyword, 1); + SigTest35NegativeICMPV4Keyword); UtRegisterTest("SigTest36ContentAndIsdataatKeywords01", - SigTest36ContentAndIsdataatKeywords01, 1); + SigTest36ContentAndIsdataatKeywords01); UtRegisterTest("SigTest37ContentAndIsdataatKeywords02", - SigTest37ContentAndIsdataatKeywords02, 1); + SigTest37ContentAndIsdataatKeywords02); /* We need to enable these tests, as soon as we add the ICMPv6 protocol support in our rules engine */ @@ -10167,41 +10174,46 @@ void SigRegisterTests(void) //UtRegisterTest("SigTest37NegativeICMPV6Keyword", // SigTest37NegativeICMPV6Keyword, 1); - UtRegisterTest("SigTest38 -- byte_test test (1)", SigTest38, 1); + UtRegisterTest("SigTest38 -- byte_test test (1)", SigTest38); - UtRegisterTest("SigTest39 -- byte_jump test (2)", SigTest39, 1); + UtRegisterTest("SigTest39 -- byte_jump test (2)", SigTest39); - UtRegisterTest("SigTest40NoPacketInspection01", SigTest40NoPacketInspection01, 1); - UtRegisterTest("SigTest40NoPayloadInspection02", SigTest40NoPayloadInspection02, 1); + UtRegisterTest("SigTest40NoPacketInspection01", + SigTest40NoPacketInspection01); + UtRegisterTest("SigTest40NoPayloadInspection02", + SigTest40NoPayloadInspection02); - UtRegisterTest("SigTestMemory01", SigTestMemory01, 1); - UtRegisterTest("SigTestMemory02", SigTestMemory02, 1); - UtRegisterTest("SigTestMemory03", SigTestMemory03, 1); + UtRegisterTest("SigTestMemory01", SigTestMemory01); + UtRegisterTest("SigTestMemory02", SigTestMemory02); + UtRegisterTest("SigTestMemory03", SigTestMemory03); - UtRegisterTest("SigTestContent01 -- 32 byte pattern", SigTestContent01, 1); - UtRegisterTest("SigTestContent02 -- 32+31 byte pattern", SigTestContent02, 1); - UtRegisterTest("SigTestContent03 -- 32 byte pattern, x2 + distance", SigTestContent03, 1); - UtRegisterTest("SigTestContent04 -- 32 byte pattern, x2 + distance/within", SigTestContent04, 1); - UtRegisterTest("SigTestContent05 -- distance/within", SigTestContent05, 1); - UtRegisterTest("SigTestContent06 -- distance/within ip only", SigTestContent06, 1); + UtRegisterTest("SigTestContent01 -- 32 byte pattern", SigTestContent01); + UtRegisterTest("SigTestContent02 -- 32+31 byte pattern", SigTestContent02); + UtRegisterTest("SigTestContent03 -- 32 byte pattern, x2 + distance", + SigTestContent03); + UtRegisterTest("SigTestContent04 -- 32 byte pattern, x2 + distance/within", + SigTestContent04); + UtRegisterTest("SigTestContent05 -- distance/within", SigTestContent05); + UtRegisterTest("SigTestContent06 -- distance/within ip only", + SigTestContent06); - UtRegisterTest("SigTestWithinReal01", SigTestWithin01, 1); - UtRegisterTest("SigTestDepthOffset01", SigTestDepthOffset01, 1); + UtRegisterTest("SigTestWithinReal01", SigTestWithin01); + UtRegisterTest("SigTestDepthOffset01", SigTestDepthOffset01); - UtRegisterTest("SigTestDetectAlertCounter", SigTestDetectAlertCounter, 1); + UtRegisterTest("SigTestDetectAlertCounter", SigTestDetectAlertCounter); - UtRegisterTest("SigTestDropFlow01", SigTestDropFlow01, 1); - UtRegisterTest("SigTestDropFlow02", SigTestDropFlow02, 1); - UtRegisterTest("SigTestDropFlow03", SigTestDropFlow03, 1); - UtRegisterTest("SigTestDropFlow04", SigTestDropFlow04, 1); + UtRegisterTest("SigTestDropFlow01", SigTestDropFlow01); + UtRegisterTest("SigTestDropFlow02", SigTestDropFlow02); + UtRegisterTest("SigTestDropFlow03", SigTestDropFlow03); + UtRegisterTest("SigTestDropFlow04", SigTestDropFlow04); - UtRegisterTest("DetectAddressYamlParsing01", DetectAddressYamlParsing01, 1); - UtRegisterTest("DetectAddressYamlParsing02", DetectAddressYamlParsing02, 1); - UtRegisterTest("DetectAddressYamlParsing03", DetectAddressYamlParsing03, 1); - UtRegisterTest("DetectAddressYamlParsing04", DetectAddressYamlParsing04, 1); + UtRegisterTest("DetectAddressYamlParsing01", DetectAddressYamlParsing01); + UtRegisterTest("DetectAddressYamlParsing02", DetectAddressYamlParsing02); + UtRegisterTest("DetectAddressYamlParsing03", DetectAddressYamlParsing03); + UtRegisterTest("DetectAddressYamlParsing04", DetectAddressYamlParsing04); - UtRegisterTest("SigTestPorts01", SigTestPorts01, 1); - UtRegisterTest("SigTestBug01", SigTestBug01, 1); + UtRegisterTest("SigTestPorts01", SigTestPorts01); + UtRegisterTest("SigTestBug01", SigTestBug01); #if 0 DetectSimdRegisterTests(); diff --git a/src/flow-bit.c b/src/flow-bit.c index 188fc6aae36c..07f549625166 100644 --- a/src/flow-bit.c +++ b/src/flow-bit.c @@ -427,17 +427,17 @@ static int FlowBitTest11 (void) void FlowBitRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("FlowBitTest01", FlowBitTest01, 1); - UtRegisterTest("FlowBitTest02", FlowBitTest02, 1); - UtRegisterTest("FlowBitTest03", FlowBitTest03, 1); - UtRegisterTest("FlowBitTest04", FlowBitTest04, 1); - UtRegisterTest("FlowBitTest05", FlowBitTest05, 1); - UtRegisterTest("FlowBitTest06", FlowBitTest06, 1); - UtRegisterTest("FlowBitTest07", FlowBitTest07, 1); - UtRegisterTest("FlowBitTest08", FlowBitTest08, 1); - UtRegisterTest("FlowBitTest09", FlowBitTest09, 1); - UtRegisterTest("FlowBitTest10", FlowBitTest10, 1); - UtRegisterTest("FlowBitTest11", FlowBitTest11, 1); + UtRegisterTest("FlowBitTest01", FlowBitTest01); + UtRegisterTest("FlowBitTest02", FlowBitTest02); + UtRegisterTest("FlowBitTest03", FlowBitTest03); + UtRegisterTest("FlowBitTest04", FlowBitTest04); + UtRegisterTest("FlowBitTest05", FlowBitTest05); + UtRegisterTest("FlowBitTest06", FlowBitTest06); + UtRegisterTest("FlowBitTest07", FlowBitTest07); + UtRegisterTest("FlowBitTest08", FlowBitTest08); + UtRegisterTest("FlowBitTest09", FlowBitTest09); + UtRegisterTest("FlowBitTest10", FlowBitTest10); + UtRegisterTest("FlowBitTest11", FlowBitTest11); #endif /* UNITTESTS */ } diff --git a/src/flow-manager.c b/src/flow-manager.c index 6bc10ba4ccf8..4cd53aacd558 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -1276,10 +1276,15 @@ static int FlowMgrTest05 (void) void FlowMgrRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("FlowMgrTest01 -- Timeout a flow having fresh TcpSession", FlowMgrTest01, 1); - UtRegisterTest("FlowMgrTest02 -- Timeout a flow having TcpSession with segments", FlowMgrTest02, 1); - UtRegisterTest("FlowMgrTest03 -- Timeout a flow in emergency having fresh TcpSession", FlowMgrTest03, 1); - UtRegisterTest("FlowMgrTest04 -- Timeout a flow in emergency having TcpSession with segments", FlowMgrTest04, 1); - UtRegisterTest("FlowMgrTest05 -- Test flow Allocations when it reach memcap", FlowMgrTest05, 1); + UtRegisterTest("FlowMgrTest01 -- Timeout a flow having fresh TcpSession", + FlowMgrTest01); + UtRegisterTest("FlowMgrTest02 -- Timeout a flow having TcpSession with segments", + FlowMgrTest02); + UtRegisterTest("FlowMgrTest03 -- Timeout a flow in emergency having fresh TcpSession", + FlowMgrTest03); + UtRegisterTest("FlowMgrTest04 -- Timeout a flow in emergency having TcpSession with segments", + FlowMgrTest04); + UtRegisterTest("FlowMgrTest05 -- Test flow Allocations when it reach memcap", + FlowMgrTest05); #endif /* UNITTESTS */ } diff --git a/src/flow-storage.c b/src/flow-storage.c index e4f4f8aeb256..155b3fc10dee 100644 --- a/src/flow-storage.c +++ b/src/flow-storage.c @@ -289,8 +289,8 @@ static int FlowStorageTest03(void) void RegisterFlowStorageTests(void) { #ifdef UNITTESTS - UtRegisterTest("FlowStorageTest01", FlowStorageTest01, 1); - UtRegisterTest("FlowStorageTest02", FlowStorageTest02, 1); - UtRegisterTest("FlowStorageTest03", FlowStorageTest03, 1); + UtRegisterTest("FlowStorageTest01", FlowStorageTest01); + UtRegisterTest("FlowStorageTest02", FlowStorageTest02); + UtRegisterTest("FlowStorageTest03", FlowStorageTest03); #endif } diff --git a/src/flow.c b/src/flow.c index cae7c4c0442f..fa8b21ba9587 100644 --- a/src/flow.c +++ b/src/flow.c @@ -1131,11 +1131,15 @@ static int FlowTest09 (void) void FlowRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("FlowTest01 -- Protocol Specific Timeouts", FlowTest01, 1); - UtRegisterTest("FlowTest02 -- Setting Protocol Specific Free Function", FlowTest02, 1); - UtRegisterTest("FlowTest07 -- Test flow Allocations when it reach memcap", FlowTest07, 1); - UtRegisterTest("FlowTest08 -- Test flow Allocations when it reach memcap", FlowTest08, 1); - UtRegisterTest("FlowTest09 -- Test flow Allocations when it reach memcap", FlowTest09, 1); + UtRegisterTest("FlowTest01 -- Protocol Specific Timeouts", FlowTest01); + UtRegisterTest("FlowTest02 -- Setting Protocol Specific Free Function", + FlowTest02); + UtRegisterTest("FlowTest07 -- Test flow Allocations when it reach memcap", + FlowTest07); + UtRegisterTest("FlowTest08 -- Test flow Allocations when it reach memcap", + FlowTest08); + UtRegisterTest("FlowTest09 -- Test flow Allocations when it reach memcap", + FlowTest09); FlowMgrRegisterTests(); RegisterFlowStorageTests(); diff --git a/src/host-bit.c b/src/host-bit.c index 6225673f5daf..db86924ee5a0 100644 --- a/src/host-bit.c +++ b/src/host-bit.c @@ -488,16 +488,16 @@ static int HostBitTest11 (void) void HostBitRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HostBitTest01", HostBitTest01, 1); - UtRegisterTest("HostBitTest02", HostBitTest02, 1); - UtRegisterTest("HostBitTest03", HostBitTest03, 1); - UtRegisterTest("HostBitTest04", HostBitTest04, 1); - UtRegisterTest("HostBitTest05", HostBitTest05, 1); - UtRegisterTest("HostBitTest06", HostBitTest06, 1); - UtRegisterTest("HostBitTest07", HostBitTest07, 1); - UtRegisterTest("HostBitTest08", HostBitTest08, 1); - UtRegisterTest("HostBitTest09", HostBitTest09, 1); - UtRegisterTest("HostBitTest10", HostBitTest10, 1); - UtRegisterTest("HostBitTest11", HostBitTest11, 1); + UtRegisterTest("HostBitTest01", HostBitTest01); + UtRegisterTest("HostBitTest02", HostBitTest02); + UtRegisterTest("HostBitTest03", HostBitTest03); + UtRegisterTest("HostBitTest04", HostBitTest04); + UtRegisterTest("HostBitTest05", HostBitTest05); + UtRegisterTest("HostBitTest06", HostBitTest06); + UtRegisterTest("HostBitTest07", HostBitTest07); + UtRegisterTest("HostBitTest08", HostBitTest08); + UtRegisterTest("HostBitTest09", HostBitTest09); + UtRegisterTest("HostBitTest10", HostBitTest10); + UtRegisterTest("HostBitTest11", HostBitTest11); #endif /* UNITTESTS */ } diff --git a/src/host-storage.c b/src/host-storage.c index fe157692725c..ba1f812a466d 100644 --- a/src/host-storage.c +++ b/src/host-storage.c @@ -330,8 +330,8 @@ static int HostStorageTest03(void) void RegisterHostStorageTests(void) { #ifdef UNITTESTS - UtRegisterTest("HostStorageTest01", HostStorageTest01, 1); - UtRegisterTest("HostStorageTest02", HostStorageTest02, 1); - UtRegisterTest("HostStorageTest03", HostStorageTest03, 1); + UtRegisterTest("HostStorageTest01", HostStorageTest01); + UtRegisterTest("HostStorageTest02", HostStorageTest02); + UtRegisterTest("HostStorageTest03", HostStorageTest03); #endif } diff --git a/src/ippair-bit.c b/src/ippair-bit.c index 0cf5c60c67c2..b69fec2fd8d7 100644 --- a/src/ippair-bit.c +++ b/src/ippair-bit.c @@ -491,16 +491,16 @@ static int IPPairBitTest11 (void) void IPPairBitRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("IPPairBitTest01", IPPairBitTest01, 1); - UtRegisterTest("IPPairBitTest02", IPPairBitTest02, 1); - UtRegisterTest("IPPairBitTest03", IPPairBitTest03, 1); - UtRegisterTest("IPPairBitTest04", IPPairBitTest04, 1); - UtRegisterTest("IPPairBitTest05", IPPairBitTest05, 1); - UtRegisterTest("IPPairBitTest06", IPPairBitTest06, 1); - UtRegisterTest("IPPairBitTest07", IPPairBitTest07, 1); - UtRegisterTest("IPPairBitTest08", IPPairBitTest08, 1); - UtRegisterTest("IPPairBitTest09", IPPairBitTest09, 1); - UtRegisterTest("IPPairBitTest10", IPPairBitTest10, 1); - UtRegisterTest("IPPairBitTest11", IPPairBitTest11, 1); + UtRegisterTest("IPPairBitTest01", IPPairBitTest01); + UtRegisterTest("IPPairBitTest02", IPPairBitTest02); + UtRegisterTest("IPPairBitTest03", IPPairBitTest03); + UtRegisterTest("IPPairBitTest04", IPPairBitTest04); + UtRegisterTest("IPPairBitTest05", IPPairBitTest05); + UtRegisterTest("IPPairBitTest06", IPPairBitTest06); + UtRegisterTest("IPPairBitTest07", IPPairBitTest07); + UtRegisterTest("IPPairBitTest08", IPPairBitTest08); + UtRegisterTest("IPPairBitTest09", IPPairBitTest09); + UtRegisterTest("IPPairBitTest10", IPPairBitTest10); + UtRegisterTest("IPPairBitTest11", IPPairBitTest11); #endif /* UNITTESTS */ } diff --git a/src/ippair-storage.c b/src/ippair-storage.c index dddc71365811..890b0c9c18ac 100644 --- a/src/ippair-storage.c +++ b/src/ippair-storage.c @@ -292,8 +292,8 @@ static int IPPairStorageTest03(void) void RegisterIPPairStorageTests(void) { #ifdef UNITTESTS - UtRegisterTest("IPPairStorageTest01", IPPairStorageTest01, 1); - UtRegisterTest("IPPairStorageTest02", IPPairStorageTest02, 1); - UtRegisterTest("IPPairStorageTest03", IPPairStorageTest03, 1); + UtRegisterTest("IPPairStorageTest01", IPPairStorageTest01); + UtRegisterTest("IPPairStorageTest02", IPPairStorageTest02); + UtRegisterTest("IPPairStorageTest03", IPPairStorageTest03); #endif } diff --git a/src/log-droplog.c b/src/log-droplog.c index 67cbd1b1ad4a..bc092af0c1b8 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -487,8 +487,8 @@ int LogDropLogTest02() */ static void LogDropLogRegisterTests(void) { - UtRegisterTest("LogDropLogTest01", LogDropLogTest01, 1); - UtRegisterTest("LogDropLogTest02", LogDropLogTest02, 1); + UtRegisterTest("LogDropLogTest01", LogDropLogTest01); + UtRegisterTest("LogDropLogTest02", LogDropLogTest02); } #endif diff --git a/src/reputation.c b/src/reputation.c index b9e87455cf8f..31fe821de3eb 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -2325,30 +2325,30 @@ void SCReputationRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCReputationTestIPV4AddRemoveHost01", - SCReputationTestIPV4AddRemoveHost01, 1); + SCReputationTestIPV4AddRemoveHost01); UtRegisterTest("SCReputationTestIPV6AddRemoveHost01", - SCReputationTestIPV6AddRemoveHost01, 1); + SCReputationTestIPV6AddRemoveHost01); UtRegisterTest("SCReputationTestIPV4BestExactMatch01", - SCReputationTestIPV4BestExactMatch01, 1); + SCReputationTestIPV4BestExactMatch01); UtRegisterTest("SCReputationTestIPV4AddRemoveHost02", - SCReputationTestIPV4AddRemoveHost02, 1); + SCReputationTestIPV4AddRemoveHost02); UtRegisterTest("SCReputationTestIPV6AddRemoveHost02", - SCReputationTestIPV6AddRemoveHost02, 1); + SCReputationTestIPV6AddRemoveHost02); UtRegisterTest("SCReputationTestIPV4Update01", - SCReputationTestIPV4Update01, 1); + SCReputationTestIPV4Update01); UtRegisterTest("SCReputationTestIPV6Update01", - SCReputationTestIPV6Update01, 1); - - UtRegisterTest("SRepTest01", SRepTest01, 1); - UtRegisterTest("SRepTest02", SRepTest02, 1); - UtRegisterTest("SRepTest03", SRepTest03, 1); - UtRegisterTest("SRepTest04", SRepTest04, 1); - UtRegisterTest("SRepTest05", SRepTest05, 1); - UtRegisterTest("SRepTest06", SRepTest06, 1); - UtRegisterTest("SRepTest07", SRepTest07, 1); + SCReputationTestIPV6Update01); + + UtRegisterTest("SRepTest01", SRepTest01); + UtRegisterTest("SRepTest02", SRepTest02); + UtRegisterTest("SRepTest03", SRepTest03); + UtRegisterTest("SRepTest04", SRepTest04); + UtRegisterTest("SRepTest05", SRepTest05); + UtRegisterTest("SRepTest06", SRepTest06); + UtRegisterTest("SRepTest07", SRepTest07); #endif /* UNITTESTS */ } diff --git a/src/stream-tcp-inline.c b/src/stream-tcp-inline.c index b8961ba287fd..97f8555d3c65 100644 --- a/src/stream-tcp-inline.c +++ b/src/stream-tcp-inline.c @@ -645,13 +645,13 @@ static int StreamTcpInlineTest07(void) void StreamTcpInlineRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("StreamTcpInlineTest01", StreamTcpInlineTest01, 1); - UtRegisterTest("StreamTcpInlineTest02", StreamTcpInlineTest02, 1); - UtRegisterTest("StreamTcpInlineTest03", StreamTcpInlineTest03, 1); - UtRegisterTest("StreamTcpInlineTest04", StreamTcpInlineTest04, 1); - UtRegisterTest("StreamTcpInlineTest05", StreamTcpInlineTest05, 1); - UtRegisterTest("StreamTcpInlineTest06", StreamTcpInlineTest06, 1); - UtRegisterTest("StreamTcpInlineTest07", StreamTcpInlineTest07, 1); + UtRegisterTest("StreamTcpInlineTest01", StreamTcpInlineTest01); + UtRegisterTest("StreamTcpInlineTest02", StreamTcpInlineTest02); + UtRegisterTest("StreamTcpInlineTest03", StreamTcpInlineTest03); + UtRegisterTest("StreamTcpInlineTest04", StreamTcpInlineTest04); + UtRegisterTest("StreamTcpInlineTest05", StreamTcpInlineTest05); + UtRegisterTest("StreamTcpInlineTest06", StreamTcpInlineTest06); + UtRegisterTest("StreamTcpInlineTest07", StreamTcpInlineTest07); #endif /* UNITTESTS */ } diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 94deab4311a8..10276ddb4838 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -8697,67 +8697,125 @@ static int StreamTcpReassembleInsertTest03(void) void StreamTcpReassembleRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("StreamTcpReassembleTest01 -- BSD OS Before Reassembly Test", StreamTcpReassembleTest01, 1); - UtRegisterTest("StreamTcpReassembleTest02 -- BSD OS At Same Reassembly Test", StreamTcpReassembleTest02, 1); - UtRegisterTest("StreamTcpReassembleTest03 -- BSD OS After Reassembly Test", StreamTcpReassembleTest03, 1); - UtRegisterTest("StreamTcpReassembleTest04 -- BSD OS Complete Reassembly Test", StreamTcpReassembleTest04, 1); - UtRegisterTest("StreamTcpReassembleTest05 -- VISTA OS Before Reassembly Test", StreamTcpReassembleTest05, 1); - UtRegisterTest("StreamTcpReassembleTest06 -- VISTA OS At Same Reassembly Test", StreamTcpReassembleTest06, 1); - UtRegisterTest("StreamTcpReassembleTest07 -- VISTA OS After Reassembly Test", StreamTcpReassembleTest07, 1); - UtRegisterTest("StreamTcpReassembleTest08 -- VISTA OS Complete Reassembly Test", StreamTcpReassembleTest08, 1); - UtRegisterTest("StreamTcpReassembleTest09 -- LINUX OS Before Reassembly Test", StreamTcpReassembleTest09, 1); - UtRegisterTest("StreamTcpReassembleTest10 -- LINUX OS At Same Reassembly Test", StreamTcpReassembleTest10, 1); - UtRegisterTest("StreamTcpReassembleTest11 -- LINUX OS After Reassembly Test", StreamTcpReassembleTest11, 1); - UtRegisterTest("StreamTcpReassembleTest12 -- LINUX OS Complete Reassembly Test", StreamTcpReassembleTest12, 1); - UtRegisterTest("StreamTcpReassembleTest13 -- LINUX_OLD OS Before Reassembly Test", StreamTcpReassembleTest13, 1); - UtRegisterTest("StreamTcpReassembleTest14 -- LINUX_OLD At Same Reassembly Test", StreamTcpReassembleTest14, 1); - UtRegisterTest("StreamTcpReassembleTest15 -- LINUX_OLD OS After Reassembly Test", StreamTcpReassembleTest15, 1); - UtRegisterTest("StreamTcpReassembleTest16 -- LINUX_OLD OS Complete Reassembly Test", StreamTcpReassembleTest16, 1); - UtRegisterTest("StreamTcpReassembleTest17 -- SOLARIS OS Before Reassembly Test", StreamTcpReassembleTest17, 1); - UtRegisterTest("StreamTcpReassembleTest18 -- SOLARIS At Same Reassembly Test", StreamTcpReassembleTest18, 1); - UtRegisterTest("StreamTcpReassembleTest19 -- SOLARIS OS After Reassembly Test", StreamTcpReassembleTest19, 1); - UtRegisterTest("StreamTcpReassembleTest20 -- SOLARIS OS Complete Reassembly Test", StreamTcpReassembleTest20, 1); - UtRegisterTest("StreamTcpReassembleTest21 -- LAST OS Before Reassembly Test", StreamTcpReassembleTest21, 1); - UtRegisterTest("StreamTcpReassembleTest22 -- LAST OS At Same Reassembly Test", StreamTcpReassembleTest22, 1); - UtRegisterTest("StreamTcpReassembleTest23 -- LAST OS After Reassembly Test", StreamTcpReassembleTest23, 1); - UtRegisterTest("StreamTcpReassembleTest24 -- LAST OS Complete Reassembly Test", StreamTcpReassembleTest24, 1); - UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test", StreamTcpReassembleTest25, 1); - UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test", StreamTcpReassembleTest26, 1); - UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after Reassembly Test", StreamTcpReassembleTest27, 1); - UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test", StreamTcpReassembleTest28, 1); - UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test", StreamTcpReassembleTest29, 1); - UtRegisterTest("StreamTcpReassembleTest30 -- Gap at End IDS missed packet Reassembly Test", StreamTcpReassembleTest30, 1); - UtRegisterTest("StreamTcpReassembleTest31 -- Fast Track Reassembly Test", StreamTcpReassembleTest31, 1); - UtRegisterTest("StreamTcpReassembleTest32 -- Bug test", StreamTcpReassembleTest32, 1); - UtRegisterTest("StreamTcpReassembleTest33 -- Bug test", StreamTcpReassembleTest33, 1); - UtRegisterTest("StreamTcpReassembleTest34 -- Bug test", StreamTcpReassembleTest34, 1); - UtRegisterTest("StreamTcpReassembleTest35 -- Bug56 test", StreamTcpReassembleTest35, 1); - UtRegisterTest("StreamTcpReassembleTest36 -- Bug57 test", StreamTcpReassembleTest36, 1); - UtRegisterTest("StreamTcpReassembleTest37 -- Bug76 test", StreamTcpReassembleTest37, 1); - UtRegisterTest("StreamTcpReassembleTest38 -- app proto test", StreamTcpReassembleTest38, 1); - UtRegisterTest("StreamTcpReassembleTest39 -- app proto test", StreamTcpReassembleTest39, 1); - UtRegisterTest("StreamTcpReassembleTest40 -- app proto test", StreamTcpReassembleTest40, 1); - UtRegisterTest("StreamTcpReassembleTest43 -- min smsg size test", StreamTcpReassembleTest43, 1); - UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", StreamTcpReassembleTest44, 1); - UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test", StreamTcpReassembleTest45, 1); - UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test", StreamTcpReassembleTest46, 1); - UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test", StreamTcpReassembleTest47, 1); - - UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra", StreamTcpReassembleInlineTest01, 1); - UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2", StreamTcpReassembleInlineTest02, 1); - UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3", StreamTcpReassembleInlineTest03, 1); - UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4", StreamTcpReassembleInlineTest04, 1); - UtRegisterTest("StreamTcpReassembleInlineTest05 -- inline RAW ra 5 GAP", StreamTcpReassembleInlineTest05, 1); - UtRegisterTest("StreamTcpReassembleInlineTest06 -- inline RAW ra 6 GAP", StreamTcpReassembleInlineTest06, 1); - UtRegisterTest("StreamTcpReassembleInlineTest07 -- inline RAW ra 7 GAP", StreamTcpReassembleInlineTest07, 1); - UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup", StreamTcpReassembleInlineTest08, 1); - UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup", StreamTcpReassembleInlineTest09, 1); - - UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10", StreamTcpReassembleInlineTest10, 1); - - UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap", StreamTcpReassembleInsertTest01, 1); - UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap", StreamTcpReassembleInsertTest02, 1); - UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap", StreamTcpReassembleInsertTest03, 1); + UtRegisterTest("StreamTcpReassembleTest01 -- BSD OS Before Reassembly Test", + StreamTcpReassembleTest01); + UtRegisterTest("StreamTcpReassembleTest02 -- BSD OS At Same Reassembly Test", + StreamTcpReassembleTest02); + UtRegisterTest("StreamTcpReassembleTest03 -- BSD OS After Reassembly Test", + StreamTcpReassembleTest03); + UtRegisterTest("StreamTcpReassembleTest04 -- BSD OS Complete Reassembly Test", + StreamTcpReassembleTest04); + UtRegisterTest("StreamTcpReassembleTest05 -- VISTA OS Before Reassembly Test", + StreamTcpReassembleTest05); + UtRegisterTest("StreamTcpReassembleTest06 -- VISTA OS At Same Reassembly Test", + StreamTcpReassembleTest06); + UtRegisterTest("StreamTcpReassembleTest07 -- VISTA OS After Reassembly Test", + StreamTcpReassembleTest07); + UtRegisterTest("StreamTcpReassembleTest08 -- VISTA OS Complete Reassembly Test", + StreamTcpReassembleTest08); + UtRegisterTest("StreamTcpReassembleTest09 -- LINUX OS Before Reassembly Test", + StreamTcpReassembleTest09); + UtRegisterTest("StreamTcpReassembleTest10 -- LINUX OS At Same Reassembly Test", + StreamTcpReassembleTest10); + UtRegisterTest("StreamTcpReassembleTest11 -- LINUX OS After Reassembly Test", + StreamTcpReassembleTest11); + UtRegisterTest("StreamTcpReassembleTest12 -- LINUX OS Complete Reassembly Test", + StreamTcpReassembleTest12); + UtRegisterTest("StreamTcpReassembleTest13 -- LINUX_OLD OS Before Reassembly Test", + StreamTcpReassembleTest13); + UtRegisterTest("StreamTcpReassembleTest14 -- LINUX_OLD At Same Reassembly Test", + StreamTcpReassembleTest14); + UtRegisterTest("StreamTcpReassembleTest15 -- LINUX_OLD OS After Reassembly Test", + StreamTcpReassembleTest15); + UtRegisterTest("StreamTcpReassembleTest16 -- LINUX_OLD OS Complete Reassembly Test", + StreamTcpReassembleTest16); + UtRegisterTest("StreamTcpReassembleTest17 -- SOLARIS OS Before Reassembly Test", + StreamTcpReassembleTest17); + UtRegisterTest("StreamTcpReassembleTest18 -- SOLARIS At Same Reassembly Test", + StreamTcpReassembleTest18); + UtRegisterTest("StreamTcpReassembleTest19 -- SOLARIS OS After Reassembly Test", + StreamTcpReassembleTest19); + UtRegisterTest("StreamTcpReassembleTest20 -- SOLARIS OS Complete Reassembly Test", + StreamTcpReassembleTest20); + UtRegisterTest("StreamTcpReassembleTest21 -- LAST OS Before Reassembly Test", + StreamTcpReassembleTest21); + UtRegisterTest("StreamTcpReassembleTest22 -- LAST OS At Same Reassembly Test", + StreamTcpReassembleTest22); + UtRegisterTest("StreamTcpReassembleTest23 -- LAST OS After Reassembly Test", + StreamTcpReassembleTest23); + UtRegisterTest("StreamTcpReassembleTest24 -- LAST OS Complete Reassembly Test", + StreamTcpReassembleTest24); + UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test", + StreamTcpReassembleTest25); + UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test", + StreamTcpReassembleTest26); + UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after Reassembly Test", + StreamTcpReassembleTest27); + UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test", + StreamTcpReassembleTest28); + UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test", + StreamTcpReassembleTest29); + UtRegisterTest("StreamTcpReassembleTest30 -- Gap at End IDS missed packet Reassembly Test", + StreamTcpReassembleTest30); + UtRegisterTest("StreamTcpReassembleTest31 -- Fast Track Reassembly Test", + StreamTcpReassembleTest31); + UtRegisterTest("StreamTcpReassembleTest32 -- Bug test", + StreamTcpReassembleTest32); + UtRegisterTest("StreamTcpReassembleTest33 -- Bug test", + StreamTcpReassembleTest33); + UtRegisterTest("StreamTcpReassembleTest34 -- Bug test", + StreamTcpReassembleTest34); + UtRegisterTest("StreamTcpReassembleTest35 -- Bug56 test", + StreamTcpReassembleTest35); + UtRegisterTest("StreamTcpReassembleTest36 -- Bug57 test", + StreamTcpReassembleTest36); + UtRegisterTest("StreamTcpReassembleTest37 -- Bug76 test", + StreamTcpReassembleTest37); + UtRegisterTest("StreamTcpReassembleTest38 -- app proto test", + StreamTcpReassembleTest38); + UtRegisterTest("StreamTcpReassembleTest39 -- app proto test", + StreamTcpReassembleTest39); + UtRegisterTest("StreamTcpReassembleTest40 -- app proto test", + StreamTcpReassembleTest40); + UtRegisterTest("StreamTcpReassembleTest43 -- min smsg size test", + StreamTcpReassembleTest43); + UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", + StreamTcpReassembleTest44); + UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test", + StreamTcpReassembleTest45); + UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test", + StreamTcpReassembleTest46); + UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test", + StreamTcpReassembleTest47); + + UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra", + StreamTcpReassembleInlineTest01); + UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2", + StreamTcpReassembleInlineTest02); + UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3", + StreamTcpReassembleInlineTest03); + UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4", + StreamTcpReassembleInlineTest04); + UtRegisterTest("StreamTcpReassembleInlineTest05 -- inline RAW ra 5 GAP", + StreamTcpReassembleInlineTest05); + UtRegisterTest("StreamTcpReassembleInlineTest06 -- inline RAW ra 6 GAP", + StreamTcpReassembleInlineTest06); + UtRegisterTest("StreamTcpReassembleInlineTest07 -- inline RAW ra 7 GAP", + StreamTcpReassembleInlineTest07); + UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup", + StreamTcpReassembleInlineTest08); + UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup", + StreamTcpReassembleInlineTest09); + + UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10", + StreamTcpReassembleInlineTest10); + + UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap", + StreamTcpReassembleInsertTest01); + UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap", + StreamTcpReassembleInsertTest02); + UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap", + StreamTcpReassembleInsertTest03); StreamTcpInlineRegisterTests(); StreamTcpUtilRegisterTests(); diff --git a/src/stream-tcp-sack.c b/src/stream-tcp-sack.c index 9e5503f79834..7f95d04c4cda 100644 --- a/src/stream-tcp-sack.c +++ b/src/stream-tcp-sack.c @@ -928,33 +928,23 @@ static int StreamTcpSackTest14 (void) { void StreamTcpSackRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("StreamTcpSackTest01 -- Insertion", - StreamTcpSackTest01, 1); - UtRegisterTest("StreamTcpSackTest02 -- Insertion", - StreamTcpSackTest02, 1); - UtRegisterTest("StreamTcpSackTest03 -- Insertion", - StreamTcpSackTest03, 1); - UtRegisterTest("StreamTcpSackTest04 -- Insertion", - StreamTcpSackTest04, 1); - UtRegisterTest("StreamTcpSackTest05 -- Insertion", - StreamTcpSackTest05, 1); - UtRegisterTest("StreamTcpSackTest06 -- Insertion", - StreamTcpSackTest06, 1); - UtRegisterTest("StreamTcpSackTest07 -- Pruning", - StreamTcpSackTest07, 1); - UtRegisterTest("StreamTcpSackTest08 -- Pruning", - StreamTcpSackTest08, 1); - UtRegisterTest("StreamTcpSackTest09 -- Pruning", - StreamTcpSackTest09, 1); - UtRegisterTest("StreamTcpSackTest10 -- Pruning", - StreamTcpSackTest10, 1); + UtRegisterTest("StreamTcpSackTest01 -- Insertion", StreamTcpSackTest01); + UtRegisterTest("StreamTcpSackTest02 -- Insertion", StreamTcpSackTest02); + UtRegisterTest("StreamTcpSackTest03 -- Insertion", StreamTcpSackTest03); + UtRegisterTest("StreamTcpSackTest04 -- Insertion", StreamTcpSackTest04); + UtRegisterTest("StreamTcpSackTest05 -- Insertion", StreamTcpSackTest05); + UtRegisterTest("StreamTcpSackTest06 -- Insertion", StreamTcpSackTest06); + UtRegisterTest("StreamTcpSackTest07 -- Pruning", StreamTcpSackTest07); + UtRegisterTest("StreamTcpSackTest08 -- Pruning", StreamTcpSackTest08); + UtRegisterTest("StreamTcpSackTest09 -- Pruning", StreamTcpSackTest09); + UtRegisterTest("StreamTcpSackTest10 -- Pruning", StreamTcpSackTest10); UtRegisterTest("StreamTcpSackTest11 -- Insertion && Pruning", - StreamTcpSackTest11, 1); + StreamTcpSackTest11); UtRegisterTest("StreamTcpSackTest12 -- Insertion && Pruning", - StreamTcpSackTest12, 1); + StreamTcpSackTest12); UtRegisterTest("StreamTcpSackTest13 -- Insertion out of window", - StreamTcpSackTest13, 1); + StreamTcpSackTest13); UtRegisterTest("StreamTcpSackTest14 -- Insertion out of window", - StreamTcpSackTest14, 1); + StreamTcpSackTest14); #endif } diff --git a/src/stream-tcp-util.c b/src/stream-tcp-util.c index 405684fd9451..54c500bc9309 100644 --- a/src/stream-tcp-util.c +++ b/src/stream-tcp-util.c @@ -256,9 +256,9 @@ int StreamTcpUtilStreamTest02(void) void StreamTcpUtilRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("StreamTcpUtilTest01", StreamTcpUtilTest01, 1); - UtRegisterTest("StreamTcpUtilStreamTest01", StreamTcpUtilStreamTest01, 1); - UtRegisterTest("StreamTcpUtilStreamTest02", StreamTcpUtilStreamTest02, 1); + UtRegisterTest("StreamTcpUtilTest01", StreamTcpUtilTest01); + UtRegisterTest("StreamTcpUtilStreamTest01", StreamTcpUtilStreamTest01); + UtRegisterTest("StreamTcpUtilStreamTest02", StreamTcpUtilStreamTest02); #endif /* UNITTESTS */ } diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 2f1a9f250d94..ae1a67a729a3 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -10736,52 +10736,50 @@ void StreamTcpRegisterTests (void) { #ifdef UNITTESTS UtRegisterTest("StreamTcpTest01 -- TCP session allocation", - StreamTcpTest01, 1); + StreamTcpTest01); UtRegisterTest("StreamTcpTest02 -- TCP session deallocation", - StreamTcpTest02, 1); + StreamTcpTest02); UtRegisterTest("StreamTcpTest03 -- SYN missed MidStream session", - StreamTcpTest03, 1); + StreamTcpTest03); UtRegisterTest("StreamTcpTest04 -- SYN/ACK missed MidStream session", - StreamTcpTest04, 1); + StreamTcpTest04); UtRegisterTest("StreamTcpTest05 -- 3WHS missed MidStream session", - StreamTcpTest05, 1); + StreamTcpTest05); UtRegisterTest("StreamTcpTest06 -- FIN, RST message MidStream session", - StreamTcpTest06, 1); + StreamTcpTest06); UtRegisterTest("StreamTcpTest07 -- PAWS invalid timestamp", - StreamTcpTest07, 1); - UtRegisterTest("StreamTcpTest08 -- PAWS valid timestamp", - StreamTcpTest08, 1); - UtRegisterTest("StreamTcpTest09 -- No Client Reassembly", - StreamTcpTest09, 1); + StreamTcpTest07); + UtRegisterTest("StreamTcpTest08 -- PAWS valid timestamp", StreamTcpTest08); + UtRegisterTest("StreamTcpTest09 -- No Client Reassembly", StreamTcpTest09); UtRegisterTest("StreamTcpTest10 -- No missed packet Async stream", - StreamTcpTest10, 1); + StreamTcpTest10); UtRegisterTest("StreamTcpTest11 -- SYN missed Async stream", - StreamTcpTest11, 1); + StreamTcpTest11); UtRegisterTest("StreamTcpTest12 -- SYN/ACK missed Async stream", - StreamTcpTest12, 1); - UtRegisterTest("StreamTcpTest13 -- opposite stream packets for Async " - "stream", StreamTcpTest13, 1); - UtRegisterTest("StreamTcp4WHSTest01", StreamTcp4WHSTest01, 1); - UtRegisterTest("StreamTcp4WHSTest02", StreamTcp4WHSTest02, 1); - UtRegisterTest("StreamTcp4WHSTest03", StreamTcp4WHSTest03, 1); - UtRegisterTest("StreamTcpTest14 -- setup OS policy", StreamTcpTest14, 1); - UtRegisterTest("StreamTcpTest15 -- setup OS policy", StreamTcpTest15, 1); - UtRegisterTest("StreamTcpTest16 -- setup OS policy", StreamTcpTest16, 1); - UtRegisterTest("StreamTcpTest17 -- setup OS policy", StreamTcpTest17, 1); - UtRegisterTest("StreamTcpTest18 -- setup OS policy", StreamTcpTest18, 1); - UtRegisterTest("StreamTcpTest19 -- setup OS policy", StreamTcpTest19, 1); - UtRegisterTest("StreamTcpTest20 -- setup OS policy", StreamTcpTest20, 1); - UtRegisterTest("StreamTcpTest21 -- setup OS policy", StreamTcpTest21, 1); - UtRegisterTest("StreamTcpTest22 -- setup OS policy", StreamTcpTest22, 1); - UtRegisterTest("StreamTcpTest23 -- stream memory leaks", StreamTcpTest23, 1); - UtRegisterTest("StreamTcpTest24 -- stream memory leaks", StreamTcpTest24, 1); + StreamTcpTest12); + UtRegisterTest("StreamTcpTest13 -- opposite stream packets for Async " "stream", + StreamTcpTest13); + UtRegisterTest("StreamTcp4WHSTest01", StreamTcp4WHSTest01); + UtRegisterTest("StreamTcp4WHSTest02", StreamTcp4WHSTest02); + UtRegisterTest("StreamTcp4WHSTest03", StreamTcp4WHSTest03); + UtRegisterTest("StreamTcpTest14 -- setup OS policy", StreamTcpTest14); + UtRegisterTest("StreamTcpTest15 -- setup OS policy", StreamTcpTest15); + UtRegisterTest("StreamTcpTest16 -- setup OS policy", StreamTcpTest16); + UtRegisterTest("StreamTcpTest17 -- setup OS policy", StreamTcpTest17); + UtRegisterTest("StreamTcpTest18 -- setup OS policy", StreamTcpTest18); + UtRegisterTest("StreamTcpTest19 -- setup OS policy", StreamTcpTest19); + UtRegisterTest("StreamTcpTest20 -- setup OS policy", StreamTcpTest20); + UtRegisterTest("StreamTcpTest21 -- setup OS policy", StreamTcpTest21); + UtRegisterTest("StreamTcpTest22 -- setup OS policy", StreamTcpTest22); + UtRegisterTest("StreamTcpTest23 -- stream memory leaks", StreamTcpTest23); + UtRegisterTest("StreamTcpTest24 -- stream memory leaks", StreamTcpTest24); UtRegisterTest("StreamTcpTest25 -- test ecn/cwr sessions", - StreamTcpTest25, 1); + StreamTcpTest25); UtRegisterTest("StreamTcpTest26 -- test ecn/cwr sessions", - StreamTcpTest26, 1); + StreamTcpTest26); UtRegisterTest("StreamTcpTest27 -- test ecn/cwr sessions", - StreamTcpTest27, 1); - UtRegisterTest("StreamTcpTest28 -- Memcap Test", StreamTcpTest28, 1); + StreamTcpTest27); + UtRegisterTest("StreamTcpTest28 -- Memcap Test", StreamTcpTest28); #if 0 /* VJ 2010/09/01 disabled since they blow up on Fedora and Fedora is * right about blowing up. The checksum functions are not used properly @@ -10795,18 +10793,19 @@ void StreamTcpRegisterTests (void) UtRegisterTest("StreamTcpTest35 -- SYN-URG Test", StreamTcpTest35, 1); UtRegisterTest("StreamTcpTest36 -- PUSH-URG Test", StreamTcpTest36, 1); #endif - UtRegisterTest("StreamTcpTest37 -- Out of order FIN Test", StreamTcpTest37, 1); + UtRegisterTest("StreamTcpTest37 -- Out of order FIN Test", + StreamTcpTest37); - UtRegisterTest("StreamTcpTest38 -- validate ACK", StreamTcpTest38, 1); - UtRegisterTest("StreamTcpTest39 -- update next_seq", StreamTcpTest39, 1); + UtRegisterTest("StreamTcpTest38 -- validate ACK", StreamTcpTest38); + UtRegisterTest("StreamTcpTest39 -- update next_seq", StreamTcpTest39); - UtRegisterTest("StreamTcpTest40 -- pseudo setup", StreamTcpTest40, 1); - UtRegisterTest("StreamTcpTest41 -- pseudo setup", StreamTcpTest41, 1); + UtRegisterTest("StreamTcpTest40 -- pseudo setup", StreamTcpTest40); + UtRegisterTest("StreamTcpTest41 -- pseudo setup", StreamTcpTest41); - UtRegisterTest("StreamTcpTest42 -- SYN/ACK queue", StreamTcpTest42, 1); - UtRegisterTest("StreamTcpTest43 -- SYN/ACK queue", StreamTcpTest43, 1); - UtRegisterTest("StreamTcpTest44 -- SYN/ACK queue", StreamTcpTest44, 1); - UtRegisterTest("StreamTcpTest45 -- SYN/ACK queue", StreamTcpTest45, 1); + UtRegisterTest("StreamTcpTest42 -- SYN/ACK queue", StreamTcpTest42); + UtRegisterTest("StreamTcpTest43 -- SYN/ACK queue", StreamTcpTest43); + UtRegisterTest("StreamTcpTest44 -- SYN/ACK queue", StreamTcpTest44); + UtRegisterTest("StreamTcpTest45 -- SYN/ACK queue", StreamTcpTest45); /* set up the reassembly tests as well */ StreamTcpReassembleRegisterTests(); diff --git a/src/threads.c b/src/threads.c index 6e58582534f6..19f55d805df1 100644 --- a/src/threads.c +++ b/src/threads.c @@ -143,9 +143,9 @@ int ThreadMacrosTest05RWLocks(void) void ThreadMacrosRegisterTests(void) { #ifdef UNITTESTS /* UNIT TESTS */ - UtRegisterTest("ThreadMacrosTest01Mutex", ThreadMacrosTest01Mutex, 1); - UtRegisterTest("ThreadMacrosTest02Spinlocks", ThreadMacrosTest02Spinlocks, 1); - UtRegisterTest("ThreadMacrosTest03RWLocks", ThreadMacrosTest03RWLocks, 1); - UtRegisterTest("ThreadMacrosTest04RWLocks", ThreadMacrosTest04RWLocks, 1); + UtRegisterTest("ThreadMacrosTest01Mutex", ThreadMacrosTest01Mutex); + UtRegisterTest("ThreadMacrosTest02Spinlocks", ThreadMacrosTest02Spinlocks); + UtRegisterTest("ThreadMacrosTest03RWLocks", ThreadMacrosTest03RWLocks); + UtRegisterTest("ThreadMacrosTest04RWLocks", ThreadMacrosTest04RWLocks); #endif /* UNIT TESTS */ } diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index 615546bf5999..29b8a6ad98d6 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -565,9 +565,12 @@ static int TmqhOutputFlowSetupCtxTest03(void) void TmqhFlowRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("TmqhOutputFlowSetupCtxTest01", TmqhOutputFlowSetupCtxTest01, 1); - UtRegisterTest("TmqhOutputFlowSetupCtxTest02", TmqhOutputFlowSetupCtxTest02, 1); - UtRegisterTest("TmqhOutputFlowSetupCtxTest03", TmqhOutputFlowSetupCtxTest03, 1); + UtRegisterTest("TmqhOutputFlowSetupCtxTest01", + TmqhOutputFlowSetupCtxTest01); + UtRegisterTest("TmqhOutputFlowSetupCtxTest02", + TmqhOutputFlowSetupCtxTest02); + UtRegisterTest("TmqhOutputFlowSetupCtxTest03", + TmqhOutputFlowSetupCtxTest03); #endif return; diff --git a/src/util-action.c b/src/util-action.c index 2b3497489891..d0bc235f9739 100644 --- a/src/util-action.c +++ b/src/util-action.c @@ -1598,30 +1598,30 @@ void UtilActionRegisterTests(void) { #ifdef UNITTESTS /* Generic tests */ - UtRegisterTest("UtilActionTest01", UtilActionTest01, 1); - UtRegisterTest("UtilActionTest02", UtilActionTest02, 1); - UtRegisterTest("UtilActionTest02", UtilActionTest02, 1); - UtRegisterTest("UtilActionTest03", UtilActionTest03, 1); - UtRegisterTest("UtilActionTest04", UtilActionTest04, 1); - UtRegisterTest("UtilActionTest05", UtilActionTest05, 1); - UtRegisterTest("UtilActionTest06", UtilActionTest06, 1); - UtRegisterTest("UtilActionTest07", UtilActionTest07, 1); - UtRegisterTest("UtilActionTest08", UtilActionTest08, 1); - UtRegisterTest("UtilActionTest09", UtilActionTest09, 1); - UtRegisterTest("UtilActionTest10", UtilActionTest10, 1); - UtRegisterTest("UtilActionTest11", UtilActionTest11, 1); - UtRegisterTest("UtilActionTest12", UtilActionTest12, 1); - UtRegisterTest("UtilActionTest13", UtilActionTest13, 1); - UtRegisterTest("UtilActionTest14", UtilActionTest14, 1); - UtRegisterTest("UtilActionTest15", UtilActionTest15, 1); - UtRegisterTest("UtilActionTest16", UtilActionTest16, 1); - UtRegisterTest("UtilActionTest17", UtilActionTest17, 1); - UtRegisterTest("UtilActionTest18", UtilActionTest18, 1); - UtRegisterTest("UtilActionTest19", UtilActionTest19, 1); - UtRegisterTest("UtilActionTest20", UtilActionTest20, 1); - UtRegisterTest("UtilActionTest21", UtilActionTest21, 1); - UtRegisterTest("UtilActionTest22", UtilActionTest22, 1); - UtRegisterTest("UtilActionTest23", UtilActionTest23, 1); - UtRegisterTest("UtilActionTest24", UtilActionTest24, 1); + UtRegisterTest("UtilActionTest01", UtilActionTest01); + UtRegisterTest("UtilActionTest02", UtilActionTest02); + UtRegisterTest("UtilActionTest02", UtilActionTest02); + UtRegisterTest("UtilActionTest03", UtilActionTest03); + UtRegisterTest("UtilActionTest04", UtilActionTest04); + UtRegisterTest("UtilActionTest05", UtilActionTest05); + UtRegisterTest("UtilActionTest06", UtilActionTest06); + UtRegisterTest("UtilActionTest07", UtilActionTest07); + UtRegisterTest("UtilActionTest08", UtilActionTest08); + UtRegisterTest("UtilActionTest09", UtilActionTest09); + UtRegisterTest("UtilActionTest10", UtilActionTest10); + UtRegisterTest("UtilActionTest11", UtilActionTest11); + UtRegisterTest("UtilActionTest12", UtilActionTest12); + UtRegisterTest("UtilActionTest13", UtilActionTest13); + UtRegisterTest("UtilActionTest14", UtilActionTest14); + UtRegisterTest("UtilActionTest15", UtilActionTest15); + UtRegisterTest("UtilActionTest16", UtilActionTest16); + UtRegisterTest("UtilActionTest17", UtilActionTest17); + UtRegisterTest("UtilActionTest18", UtilActionTest18); + UtRegisterTest("UtilActionTest19", UtilActionTest19); + UtRegisterTest("UtilActionTest20", UtilActionTest20); + UtRegisterTest("UtilActionTest21", UtilActionTest21); + UtRegisterTest("UtilActionTest22", UtilActionTest22); + UtRegisterTest("UtilActionTest23", UtilActionTest23); + UtRegisterTest("UtilActionTest24", UtilActionTest24); #endif } diff --git a/src/util-atomic.c b/src/util-atomic.c index 9ad448e693d4..569f4c0a344f 100644 --- a/src/util-atomic.c +++ b/src/util-atomic.c @@ -66,7 +66,7 @@ static int SCAtomicTest01(void) void SCAtomicRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCAtomicTest01", SCAtomicTest01, 1); + UtRegisterTest("SCAtomicTest01", SCAtomicTest01); #endif return; diff --git a/src/util-bloomfilter-counting.c b/src/util-bloomfilter-counting.c index 443b8d79e9ad..66dac54d77f7 100644 --- a/src/util-bloomfilter-counting.c +++ b/src/util-bloomfilter-counting.c @@ -393,18 +393,28 @@ static int BloomFilterCountingTestFull02 (void) void BloomFilterCountingRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("BloomFilterCountingTestInit01", BloomFilterCountingTestInit01, 1); - UtRegisterTest("BloomFilterCountingTestInit02", BloomFilterCountingTestInit02, 1); - UtRegisterTest("BloomFilterCountingTestInit03", BloomFilterCountingTestInit03, 1); - UtRegisterTest("BloomFilterCountingTestInit04", BloomFilterCountingTestInit04, 1); - UtRegisterTest("BloomFilterCountingTestInit05", BloomFilterCountingTestInit05, 1); - UtRegisterTest("BloomFilterCountingTestInit06", BloomFilterCountingTestInit06, 1); - - UtRegisterTest("BloomFilterCountingTestAdd01", BloomFilterCountingTestAdd01, 1); - UtRegisterTest("BloomFilterCountingTestAdd02", BloomFilterCountingTestAdd02, 1); - - UtRegisterTest("BloomFilterCountingTestFull01", BloomFilterCountingTestFull01, 1); - UtRegisterTest("BloomFilterCountingTestFull02", BloomFilterCountingTestFull02, 1); + UtRegisterTest("BloomFilterCountingTestInit01", + BloomFilterCountingTestInit01); + UtRegisterTest("BloomFilterCountingTestInit02", + BloomFilterCountingTestInit02); + UtRegisterTest("BloomFilterCountingTestInit03", + BloomFilterCountingTestInit03); + UtRegisterTest("BloomFilterCountingTestInit04", + BloomFilterCountingTestInit04); + UtRegisterTest("BloomFilterCountingTestInit05", + BloomFilterCountingTestInit05); + UtRegisterTest("BloomFilterCountingTestInit06", + BloomFilterCountingTestInit06); + + UtRegisterTest("BloomFilterCountingTestAdd01", + BloomFilterCountingTestAdd01); + UtRegisterTest("BloomFilterCountingTestAdd02", + BloomFilterCountingTestAdd02); + + UtRegisterTest("BloomFilterCountingTestFull01", + BloomFilterCountingTestFull01); + UtRegisterTest("BloomFilterCountingTestFull02", + BloomFilterCountingTestFull02); #endif } diff --git a/src/util-bloomfilter.c b/src/util-bloomfilter.c index 8dcd7a310b8d..7403f5f7629f 100644 --- a/src/util-bloomfilter.c +++ b/src/util-bloomfilter.c @@ -275,17 +275,17 @@ static int BloomFilterTestFull02 (void) void BloomFilterRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("BloomFilterTestInit01", BloomFilterTestInit01, 1); - UtRegisterTest("BloomFilterTestInit02", BloomFilterTestInit02, 1); - UtRegisterTest("BloomFilterTestInit03", BloomFilterTestInit03, 1); - UtRegisterTest("BloomFilterTestInit04", BloomFilterTestInit04, 1); - UtRegisterTest("BloomFilterTestInit05", BloomFilterTestInit05, 1); + UtRegisterTest("BloomFilterTestInit01", BloomFilterTestInit01); + UtRegisterTest("BloomFilterTestInit02", BloomFilterTestInit02); + UtRegisterTest("BloomFilterTestInit03", BloomFilterTestInit03); + UtRegisterTest("BloomFilterTestInit04", BloomFilterTestInit04); + UtRegisterTest("BloomFilterTestInit05", BloomFilterTestInit05); - UtRegisterTest("BloomFilterTestAdd01", BloomFilterTestAdd01, 1); - UtRegisterTest("BloomFilterTestAdd02", BloomFilterTestAdd02, 1); + UtRegisterTest("BloomFilterTestAdd01", BloomFilterTestAdd01); + UtRegisterTest("BloomFilterTestAdd02", BloomFilterTestAdd02); - UtRegisterTest("BloomFilterTestFull01", BloomFilterTestFull01, 1); - UtRegisterTest("BloomFilterTestFull02", BloomFilterTestFull02, 1); + UtRegisterTest("BloomFilterTestFull01", BloomFilterTestFull01); + UtRegisterTest("BloomFilterTestFull02", BloomFilterTestFull02); #endif /* UNITTESTS */ } diff --git a/src/util-byte.c b/src/util-byte.c index 1d8e088a6a99..f0d0a1332cef 100644 --- a/src/util-byte.c +++ b/src/util-byte.c @@ -607,22 +607,22 @@ static int ByteTest16 (void) void ByteRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ByteTest01", ByteTest01, 1); - UtRegisterTest("ByteTest02", ByteTest02, 1); - UtRegisterTest("ByteTest03", ByteTest03, 1); - UtRegisterTest("ByteTest04", ByteTest04, 1); - UtRegisterTest("ByteTest05", ByteTest05, 1); - UtRegisterTest("ByteTest06", ByteTest06, 1); - UtRegisterTest("ByteTest07", ByteTest07, 1); - UtRegisterTest("ByteTest08", ByteTest08, 1); - UtRegisterTest("ByteTest09", ByteTest09, 1); - UtRegisterTest("ByteTest10", ByteTest10, 1); - UtRegisterTest("ByteTest11", ByteTest11, 1); - UtRegisterTest("ByteTest12", ByteTest12, 1); - UtRegisterTest("ByteTest13", ByteTest13, 1); - UtRegisterTest("ByteTest14", ByteTest14, 1); - UtRegisterTest("ByteTest15", ByteTest15, 1); - UtRegisterTest("ByteTest16", ByteTest16, 1); + UtRegisterTest("ByteTest01", ByteTest01); + UtRegisterTest("ByteTest02", ByteTest02); + UtRegisterTest("ByteTest03", ByteTest03); + UtRegisterTest("ByteTest04", ByteTest04); + UtRegisterTest("ByteTest05", ByteTest05); + UtRegisterTest("ByteTest06", ByteTest06); + UtRegisterTest("ByteTest07", ByteTest07); + UtRegisterTest("ByteTest08", ByteTest08); + UtRegisterTest("ByteTest09", ByteTest09); + UtRegisterTest("ByteTest10", ByteTest10); + UtRegisterTest("ByteTest11", ByteTest11); + UtRegisterTest("ByteTest12", ByteTest12); + UtRegisterTest("ByteTest13", ByteTest13); + UtRegisterTest("ByteTest14", ByteTest14); + UtRegisterTest("ByteTest15", ByteTest15); + UtRegisterTest("ByteTest16", ByteTest16); #endif /* UNITTESTS */ } diff --git a/src/util-classification-config.c b/src/util-classification-config.c index babddae3f510..a5d4bdbe99a8 100644 --- a/src/util-classification-config.c +++ b/src/util-classification-config.c @@ -827,12 +827,12 @@ void SCClassConfRegisterTests(void) #ifdef UNITTESTS - UtRegisterTest("SCClassConfTest01", SCClassConfTest01, 1); - UtRegisterTest("SCClassConfTest02", SCClassConfTest02, 1); - UtRegisterTest("SCClassConfTest03", SCClassConfTest03, 1); - UtRegisterTest("SCClassConfTest04", SCClassConfTest04, 1); - UtRegisterTest("SCClassConfTest05", SCClassConfTest05, 1); - UtRegisterTest("SCClassConfTest06", SCClassConfTest06, 1); + UtRegisterTest("SCClassConfTest01", SCClassConfTest01); + UtRegisterTest("SCClassConfTest02", SCClassConfTest02); + UtRegisterTest("SCClassConfTest03", SCClassConfTest03); + UtRegisterTest("SCClassConfTest04", SCClassConfTest04); + UtRegisterTest("SCClassConfTest05", SCClassConfTest05); + UtRegisterTest("SCClassConfTest06", SCClassConfTest06); #endif /* UNITTESTS */ diff --git a/src/util-cuda-buffer.c b/src/util-cuda-buffer.c index 47b4bc5e2258..54ae272a524a 100644 --- a/src/util-cuda-buffer.c +++ b/src/util-cuda-buffer.c @@ -1344,12 +1344,12 @@ int CudaBufferTest06(void) void CudaBufferRegisterUnittests(void) { #ifdef UNITTESTS - UtRegisterTest("CudaBufferTest01", CudaBufferTest01, 1); - UtRegisterTest("CudaBufferTest02", CudaBufferTest02, 1); - UtRegisterTest("CudaBufferTest03", CudaBufferTest03, 1); - UtRegisterTest("CudaBufferTest04", CudaBufferTest04, 1); - UtRegisterTest("CudaBufferTest05", CudaBufferTest05, 1); - UtRegisterTest("CudaBufferTest06", CudaBufferTest06, 1); + UtRegisterTest("CudaBufferTest01", CudaBufferTest01); + UtRegisterTest("CudaBufferTest02", CudaBufferTest02); + UtRegisterTest("CudaBufferTest03", CudaBufferTest03); + UtRegisterTest("CudaBufferTest04", CudaBufferTest04); + UtRegisterTest("CudaBufferTest05", CudaBufferTest05); + UtRegisterTest("CudaBufferTest06", CudaBufferTest06); #endif return; diff --git a/src/util-cuda.c b/src/util-cuda.c index 1df4a2c3da58..288631176be7 100644 --- a/src/util-cuda.c +++ b/src/util-cuda.c @@ -5445,8 +5445,8 @@ int SCCudaTest02(void) void SCCudaRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCCudaTest01", SCCudaTest01, 1); - UtRegisterTest("SCCudaTest02", SCCudaTest02, 1); + UtRegisterTest("SCCudaTest01", SCCudaTest01); + UtRegisterTest("SCCudaTest02", SCCudaTest02); #endif return; diff --git a/src/util-debug.c b/src/util-debug.c index e1a9af4539d0..6e71102a9016 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -1637,11 +1637,11 @@ void SCLogRegisterTests() #ifdef UNITTESTS - UtRegisterTest("SCLogTestInit01", SCLogTestInit01, 1); - UtRegisterTest("SCLogTestInit02", SCLogTestInit02, 1); - UtRegisterTest("SCLogTestInit03", SCLogTestInit03, 1); - UtRegisterTest("SCLogTestInit04", SCLogTestInit04, 1); - UtRegisterTest("SCLogTestInit05", SCLogTestInit05, 1); + UtRegisterTest("SCLogTestInit01", SCLogTestInit01); + UtRegisterTest("SCLogTestInit02", SCLogTestInit02); + UtRegisterTest("SCLogTestInit03", SCLogTestInit03); + UtRegisterTest("SCLogTestInit04", SCLogTestInit04); + UtRegisterTest("SCLogTestInit05", SCLogTestInit05); #endif /* UNITTESTS */ diff --git a/src/util-decode-asn1.c b/src/util-decode-asn1.c index 4e4115a104ff..2404c3d843c6 100644 --- a/src/util-decode-asn1.c +++ b/src/util-decode-asn1.c @@ -888,19 +888,19 @@ int DecodeAsn1Test10(void) void DecodeAsn1RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeAsn1Test01", DecodeAsn1Test01, 1); - UtRegisterTest("DecodeAsn1Test02", DecodeAsn1Test02, 1); - UtRegisterTest("DecodeAsn1Test03", DecodeAsn1Test03, 1); + UtRegisterTest("DecodeAsn1Test01", DecodeAsn1Test01); + UtRegisterTest("DecodeAsn1Test02", DecodeAsn1Test02); + UtRegisterTest("DecodeAsn1Test03", DecodeAsn1Test03); - UtRegisterTest("DecodeAsn1Test04", DecodeAsn1Test04, 1); - UtRegisterTest("DecodeAsn1Test05", DecodeAsn1Test05, 1); - UtRegisterTest("DecodeAsn1Test06", DecodeAsn1Test06, 1); + UtRegisterTest("DecodeAsn1Test04", DecodeAsn1Test04); + UtRegisterTest("DecodeAsn1Test05", DecodeAsn1Test05); + UtRegisterTest("DecodeAsn1Test06", DecodeAsn1Test06); - UtRegisterTest("DecodeAsn1Test07", DecodeAsn1Test07, 1); - UtRegisterTest("DecodeAsn1Test08", DecodeAsn1Test08, 1); - UtRegisterTest("DecodeAsn1Test09", DecodeAsn1Test09, 1); + UtRegisterTest("DecodeAsn1Test07", DecodeAsn1Test07); + UtRegisterTest("DecodeAsn1Test08", DecodeAsn1Test08); + UtRegisterTest("DecodeAsn1Test09", DecodeAsn1Test09); - UtRegisterTest("DecodeAsn1Test10", DecodeAsn1Test10, 1); + UtRegisterTest("DecodeAsn1Test10", DecodeAsn1Test10); #endif } diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 8664a9438c3c..8ba56b6f1c04 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -2987,13 +2987,13 @@ static int MimeIsIpv6HostTest01(void) void MimeDecRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01, 1); - UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02, 1); - UtRegisterTest("MimeDecParseFullMsgTest01", MimeDecParseFullMsgTest01, 1); - UtRegisterTest("MimeDecParseFullMsgTest02", MimeDecParseFullMsgTest02, 1); - UtRegisterTest("MimeBase64DecodeTest01", MimeBase64DecodeTest01, 1); - UtRegisterTest("MimeIsExeURLTest01", MimeIsExeURLTest01, 1); - UtRegisterTest("MimeIsIpv4HostTest01", MimeIsIpv4HostTest01, 1); - UtRegisterTest("MimeIsIpv6HostTest01", MimeIsIpv6HostTest01, 1); + UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01); + UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02); + UtRegisterTest("MimeDecParseFullMsgTest01", MimeDecParseFullMsgTest01); + UtRegisterTest("MimeDecParseFullMsgTest02", MimeDecParseFullMsgTest02); + UtRegisterTest("MimeBase64DecodeTest01", MimeBase64DecodeTest01); + UtRegisterTest("MimeIsExeURLTest01", MimeIsExeURLTest01); + UtRegisterTest("MimeIsIpv4HostTest01", MimeIsIpv4HostTest01); + UtRegisterTest("MimeIsIpv6HostTest01", MimeIsIpv6HostTest01); #endif /* UNITTESTS */ } diff --git a/src/util-hash.c b/src/util-hash.c index 7552867fb542..9dbe36983c7c 100644 --- a/src/util-hash.c +++ b/src/util-hash.c @@ -415,18 +415,18 @@ static int HashTableTestFull02 (void) void HashTableRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HashTableTestInit01", HashTableTestInit01, 1); - UtRegisterTest("HashTableTestInit02", HashTableTestInit02, 1); - UtRegisterTest("HashTableTestInit03", HashTableTestInit03, 1); - UtRegisterTest("HashTableTestInit04", HashTableTestInit04, 1); - UtRegisterTest("HashTableTestInit05", HashTableTestInit05, 1); - UtRegisterTest("HashTableTestInit06", HashTableTestInit06, 1); - - UtRegisterTest("HashTableTestAdd01", HashTableTestAdd01, 1); - UtRegisterTest("HashTableTestAdd02", HashTableTestAdd02, 1); - - UtRegisterTest("HashTableTestFull01", HashTableTestFull01, 1); - UtRegisterTest("HashTableTestFull02", HashTableTestFull02, 1); + UtRegisterTest("HashTableTestInit01", HashTableTestInit01); + UtRegisterTest("HashTableTestInit02", HashTableTestInit02); + UtRegisterTest("HashTableTestInit03", HashTableTestInit03); + UtRegisterTest("HashTableTestInit04", HashTableTestInit04); + UtRegisterTest("HashTableTestInit05", HashTableTestInit05); + UtRegisterTest("HashTableTestInit06", HashTableTestInit06); + + UtRegisterTest("HashTableTestAdd01", HashTableTestAdd01); + UtRegisterTest("HashTableTestAdd02", HashTableTestAdd02); + + UtRegisterTest("HashTableTestFull01", HashTableTestFull01); + UtRegisterTest("HashTableTestFull02", HashTableTestFull02); #endif } diff --git a/src/util-hashlist.c b/src/util-hashlist.c index db8ba9050e9b..52ad1b1350c4 100644 --- a/src/util-hashlist.c +++ b/src/util-hashlist.c @@ -501,18 +501,18 @@ static int HashListTableTestFull02 (void) void HashListTableRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HashListTableTestInit01", HashListTableTestInit01, 1); - UtRegisterTest("HashListTableTestInit02", HashListTableTestInit02, 1); - UtRegisterTest("HashListTableTestInit03", HashListTableTestInit03, 1); - UtRegisterTest("HashListTableTestInit04", HashListTableTestInit04, 1); - - UtRegisterTest("HashListTableTestAdd01", HashListTableTestAdd01, 1); - UtRegisterTest("HashListTableTestAdd02", HashListTableTestAdd02, 1); - UtRegisterTest("HashListTableTestAdd03", HashListTableTestAdd03, 1); - UtRegisterTest("HashListTableTestAdd04", HashListTableTestAdd04, 1); - - UtRegisterTest("HashListTableTestFull01", HashListTableTestFull01, 1); - UtRegisterTest("HashListTableTestFull02", HashListTableTestFull02, 1); + UtRegisterTest("HashListTableTestInit01", HashListTableTestInit01); + UtRegisterTest("HashListTableTestInit02", HashListTableTestInit02); + UtRegisterTest("HashListTableTestInit03", HashListTableTestInit03); + UtRegisterTest("HashListTableTestInit04", HashListTableTestInit04); + + UtRegisterTest("HashListTableTestAdd01", HashListTableTestAdd01); + UtRegisterTest("HashListTableTestAdd02", HashListTableTestAdd02); + UtRegisterTest("HashListTableTestAdd03", HashListTableTestAdd03); + UtRegisterTest("HashListTableTestAdd04", HashListTableTestAdd04); + + UtRegisterTest("HashListTableTestFull01", HashListTableTestFull01); + UtRegisterTest("HashListTableTestFull02", HashListTableTestFull02); #endif /* UNITTESTS */ } diff --git a/src/util-host-os-info.c b/src/util-host-os-info.c index f04d6326c76a..eed01c7134e6 100644 --- a/src/util-host-os-info.c +++ b/src/util-host-os-info.c @@ -1629,32 +1629,28 @@ void SCHInfoRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("SCHInfoTesInvalidOSFlavour01", - SCHInfoTestInvalidOSFlavour01, 1); + SCHInfoTestInvalidOSFlavour01); UtRegisterTest("SCHInfoTestInvalidIPV4Address02", - SCHInfoTestInvalidIPV4Address02, 1); + SCHInfoTestInvalidIPV4Address02); UtRegisterTest("SCHInfoTestInvalidIPV6Address03", - SCHInfoTestInvalidIPV6Address03, 1); + SCHInfoTestInvalidIPV6Address03); UtRegisterTest("SCHInfoTestValidIPV4Address04", - SCHInfoTestValidIPV4Address04, 1); + SCHInfoTestValidIPV4Address04); UtRegisterTest("SCHInfoTestValidIPV4Address05", - SCHInfoTestValidIPV4Address05, 1); + SCHInfoTestValidIPV4Address05); UtRegisterTest("SCHInfoTestValidIPV6Address06", - SCHInfoTestValidIPV6Address06, 1); + SCHInfoTestValidIPV6Address06); UtRegisterTest("SCHInfoTestValidIPV6Address07", - SCHInfoTestValidIPV6Address07, 1); + SCHInfoTestValidIPV6Address07); UtRegisterTest("SCHInfoTestValidIPV6Address08", - SCHInfoTestValidIPV6Address08, 1); + SCHInfoTestValidIPV6Address08); UtRegisterTest("SCHInfoTestValidIPV4Address09", - SCHInfoTestValidIPV4Address09, 1); - - UtRegisterTest("SCHInfoTestLoadFromConfig01", - SCHInfoTestLoadFromConfig01, 1); - UtRegisterTest("SCHInfoTestLoadFromConfig02", - SCHInfoTestLoadFromConfig02, 1); - UtRegisterTest("SCHInfoTestLoadFromConfig03", - SCHInfoTestLoadFromConfig03, 1); - UtRegisterTest("SCHInfoTestLoadFromConfig04", - SCHInfoTestLoadFromConfig04, 1); + SCHInfoTestValidIPV4Address09); + + UtRegisterTest("SCHInfoTestLoadFromConfig01", SCHInfoTestLoadFromConfig01); + UtRegisterTest("SCHInfoTestLoadFromConfig02", SCHInfoTestLoadFromConfig02); + UtRegisterTest("SCHInfoTestLoadFromConfig03", SCHInfoTestLoadFromConfig03); + UtRegisterTest("SCHInfoTestLoadFromConfig04", SCHInfoTestLoadFromConfig04); #endif /* UNITTESTS */ } diff --git a/src/util-magic.c b/src/util-magic.c index 0fbb6994ae38..5d8615b182e4 100644 --- a/src/util-magic.c +++ b/src/util-magic.c @@ -667,19 +667,20 @@ static int MagicDetectTest10ValgrindError(void) void MagicRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("MagicInitTest01", MagicInitTest01, 1); - UtRegisterTest("MagicInitTest02", MagicInitTest02, 1); - UtRegisterTest("MagicDetectTest01", MagicDetectTest01, 1); + UtRegisterTest("MagicInitTest01", MagicInitTest01); + UtRegisterTest("MagicInitTest02", MagicInitTest02); + UtRegisterTest("MagicDetectTest01", MagicDetectTest01); //UtRegisterTest("MagicDetectTest02", MagicDetectTest02, 1); - UtRegisterTest("MagicDetectTest03", MagicDetectTest03, 1); - UtRegisterTest("MagicDetectTest04", MagicDetectTest04, 1); - UtRegisterTest("MagicDetectTest05", MagicDetectTest05, 1); + UtRegisterTest("MagicDetectTest03", MagicDetectTest03); + UtRegisterTest("MagicDetectTest04", MagicDetectTest04); + UtRegisterTest("MagicDetectTest05", MagicDetectTest05); //UtRegisterTest("MagicDetectTest06", MagicDetectTest06, 1); - UtRegisterTest("MagicDetectTest07", MagicDetectTest07, 1); - UtRegisterTest("MagicDetectTest08", MagicDetectTest08, 1); + UtRegisterTest("MagicDetectTest07", MagicDetectTest07); + UtRegisterTest("MagicDetectTest08", MagicDetectTest08); /* fails in valgrind, somehow it returns different pointers then. UtRegisterTest("MagicDetectTest09", MagicDetectTest09, 1); */ - UtRegisterTest("MagicDetectTest10ValgrindError", MagicDetectTest10ValgrindError, 1); + UtRegisterTest("MagicDetectTest10ValgrindError", + MagicDetectTest10ValgrindError); #endif /* UNITTESTS */ } diff --git a/src/util-memcmp.c b/src/util-memcmp.c index c1b03490da92..2dd06ecc7f46 100644 --- a/src/util-memcmp.c +++ b/src/util-memcmp.c @@ -384,24 +384,24 @@ static int MemcmpTest18 (void) void MemcmpRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("MemcmpTest01", MemcmpTest01, 1); - UtRegisterTest("MemcmpTest02", MemcmpTest02, 1); - UtRegisterTest("MemcmpTest03", MemcmpTest03, 1); - UtRegisterTest("MemcmpTest04", MemcmpTest04, 1); - UtRegisterTest("MemcmpTest05", MemcmpTest05, 1); - UtRegisterTest("MemcmpTest06", MemcmpTest06, 1); - UtRegisterTest("MemcmpTest07", MemcmpTest07, 1); - UtRegisterTest("MemcmpTest08", MemcmpTest08, 1); - UtRegisterTest("MemcmpTest09", MemcmpTest09, 1); - UtRegisterTest("MemcmpTest10", MemcmpTest10, 1); - UtRegisterTest("MemcmpTest11", MemcmpTest11, 1); - UtRegisterTest("MemcmpTest12", MemcmpTest12, 1); - UtRegisterTest("MemcmpTest13", MemcmpTest13, 1); - UtRegisterTest("MemcmpTest14", MemcmpTest14, 1); - UtRegisterTest("MemcmpTest15", MemcmpTest15, 1); - UtRegisterTest("MemcmpTest16", MemcmpTest16, 1); - UtRegisterTest("MemcmpTest17", MemcmpTest17, 1); - UtRegisterTest("MemcmpTest18", MemcmpTest18, 1); + UtRegisterTest("MemcmpTest01", MemcmpTest01); + UtRegisterTest("MemcmpTest02", MemcmpTest02); + UtRegisterTest("MemcmpTest03", MemcmpTest03); + UtRegisterTest("MemcmpTest04", MemcmpTest04); + UtRegisterTest("MemcmpTest05", MemcmpTest05); + UtRegisterTest("MemcmpTest06", MemcmpTest06); + UtRegisterTest("MemcmpTest07", MemcmpTest07); + UtRegisterTest("MemcmpTest08", MemcmpTest08); + UtRegisterTest("MemcmpTest09", MemcmpTest09); + UtRegisterTest("MemcmpTest10", MemcmpTest10); + UtRegisterTest("MemcmpTest11", MemcmpTest11); + UtRegisterTest("MemcmpTest12", MemcmpTest12); + UtRegisterTest("MemcmpTest13", MemcmpTest13); + UtRegisterTest("MemcmpTest14", MemcmpTest14); + UtRegisterTest("MemcmpTest15", MemcmpTest15); + UtRegisterTest("MemcmpTest16", MemcmpTest16); + UtRegisterTest("MemcmpTest17", MemcmpTest17); + UtRegisterTest("MemcmpTest18", MemcmpTest18); #endif /* UNITTESTS */ } diff --git a/src/util-memrchr.c b/src/util-memrchr.c index ebac1764f02f..6e49fc86f49e 100644 --- a/src/util-memrchr.c +++ b/src/util-memrchr.c @@ -62,6 +62,6 @@ static int MemrchrTest01 (void) void MemrchrRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("MemrchrTest01", MemrchrTest01, 1); + UtRegisterTest("MemrchrTest01", MemrchrTest01); #endif } diff --git a/src/util-misc.c b/src/util-misc.c index b72aa05e8e6b..1643e7e1f2af 100644 --- a/src/util-misc.c +++ b/src/util-misc.c @@ -1134,7 +1134,8 @@ int UtilMiscParseSizeStringTest01(void) void UtilMiscRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("UtilMiscParseSizeStringTest01", UtilMiscParseSizeStringTest01, 1); + UtRegisterTest("UtilMiscParseSizeStringTest01", + UtilMiscParseSizeStringTest01); #endif /* UNITTESTS */ return; diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 3c3eac540bc8..85d3b3bef8f0 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -2481,36 +2481,36 @@ void SCACBSRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCACBSTest01", SCACBSTest01, 1); - UtRegisterTest("SCACBSTest02", SCACBSTest02, 1); - UtRegisterTest("SCACBSTest03", SCACBSTest03, 1); - UtRegisterTest("SCACBSTest04", SCACBSTest04, 1); - UtRegisterTest("SCACBSTest05", SCACBSTest05, 1); - UtRegisterTest("SCACBSTest06", SCACBSTest06, 1); - UtRegisterTest("SCACBSTest07", SCACBSTest07, 1); - UtRegisterTest("SCACBSTest08", SCACBSTest08, 1); - UtRegisterTest("SCACBSTest09", SCACBSTest09, 1); - UtRegisterTest("SCACBSTest10", SCACBSTest10, 1); - UtRegisterTest("SCACBSTest11", SCACBSTest11, 1); - UtRegisterTest("SCACBSTest12", SCACBSTest12, 1); - UtRegisterTest("SCACBSTest13", SCACBSTest13, 1); - UtRegisterTest("SCACBSTest14", SCACBSTest14, 1); - UtRegisterTest("SCACBSTest15", SCACBSTest15, 1); - UtRegisterTest("SCACBSTest16", SCACBSTest16, 1); - UtRegisterTest("SCACBSTest17", SCACBSTest17, 1); - UtRegisterTest("SCACBSTest18", SCACBSTest18, 1); - UtRegisterTest("SCACBSTest19", SCACBSTest19, 1); - UtRegisterTest("SCACBSTest20", SCACBSTest20, 1); - UtRegisterTest("SCACBSTest21", SCACBSTest21, 1); - UtRegisterTest("SCACBSTest22", SCACBSTest22, 1); - UtRegisterTest("SCACBSTest23", SCACBSTest23, 1); - UtRegisterTest("SCACBSTest24", SCACBSTest24, 1); - UtRegisterTest("SCACBSTest25", SCACBSTest25, 1); - UtRegisterTest("SCACBSTest26", SCACBSTest26, 1); - UtRegisterTest("SCACBSTest27", SCACBSTest27, 1); - UtRegisterTest("SCACBSTest28", SCACBSTest28, 1); - UtRegisterTest("SCACBSTest29", SCACBSTest29, 1); - UtRegisterTest("SCACBSTest30", SCACBSTest30, 1); + UtRegisterTest("SCACBSTest01", SCACBSTest01); + UtRegisterTest("SCACBSTest02", SCACBSTest02); + UtRegisterTest("SCACBSTest03", SCACBSTest03); + UtRegisterTest("SCACBSTest04", SCACBSTest04); + UtRegisterTest("SCACBSTest05", SCACBSTest05); + UtRegisterTest("SCACBSTest06", SCACBSTest06); + UtRegisterTest("SCACBSTest07", SCACBSTest07); + UtRegisterTest("SCACBSTest08", SCACBSTest08); + UtRegisterTest("SCACBSTest09", SCACBSTest09); + UtRegisterTest("SCACBSTest10", SCACBSTest10); + UtRegisterTest("SCACBSTest11", SCACBSTest11); + UtRegisterTest("SCACBSTest12", SCACBSTest12); + UtRegisterTest("SCACBSTest13", SCACBSTest13); + UtRegisterTest("SCACBSTest14", SCACBSTest14); + UtRegisterTest("SCACBSTest15", SCACBSTest15); + UtRegisterTest("SCACBSTest16", SCACBSTest16); + UtRegisterTest("SCACBSTest17", SCACBSTest17); + UtRegisterTest("SCACBSTest18", SCACBSTest18); + UtRegisterTest("SCACBSTest19", SCACBSTest19); + UtRegisterTest("SCACBSTest20", SCACBSTest20); + UtRegisterTest("SCACBSTest21", SCACBSTest21); + UtRegisterTest("SCACBSTest22", SCACBSTest22); + UtRegisterTest("SCACBSTest23", SCACBSTest23); + UtRegisterTest("SCACBSTest24", SCACBSTest24); + UtRegisterTest("SCACBSTest25", SCACBSTest25); + UtRegisterTest("SCACBSTest26", SCACBSTest26); + UtRegisterTest("SCACBSTest27", SCACBSTest27); + UtRegisterTest("SCACBSTest28", SCACBSTest28); + UtRegisterTest("SCACBSTest29", SCACBSTest29); + UtRegisterTest("SCACBSTest30", SCACBSTest30); #endif return; diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 3d7b3b5a91f2..f2a4713cc0cd 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -2537,35 +2537,35 @@ void SCACTileRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCACTileTest01", SCACTileTest01, 1); - UtRegisterTest("SCACTileTest02", SCACTileTest02, 1); - UtRegisterTest("SCACTileTest03", SCACTileTest03, 1); - UtRegisterTest("SCACTileTest04", SCACTileTest04, 1); - UtRegisterTest("SCACTileTest05", SCACTileTest05, 1); - UtRegisterTest("SCACTileTest06", SCACTileTest06, 1); - UtRegisterTest("SCACTileTest07", SCACTileTest07, 1); - UtRegisterTest("SCACTileTest08", SCACTileTest08, 1); - UtRegisterTest("SCACTileTest09", SCACTileTest09, 1); - UtRegisterTest("SCACTileTest10", SCACTileTest10, 1); - UtRegisterTest("SCACTileTest11", SCACTileTest11, 1); - UtRegisterTest("SCACTileTest12", SCACTileTest12, 1); - UtRegisterTest("SCACTileTest13", SCACTileTest13, 1); - UtRegisterTest("SCACTileTest14", SCACTileTest14, 1); - UtRegisterTest("SCACTileTest15", SCACTileTest15, 1); - UtRegisterTest("SCACTileTest16", SCACTileTest16, 1); - UtRegisterTest("SCACTileTest17", SCACTileTest17, 1); - UtRegisterTest("SCACTileTest18", SCACTileTest18, 1); - UtRegisterTest("SCACTileTest19", SCACTileTest19, 1); - UtRegisterTest("SCACTileTest20", SCACTileTest20, 1); - UtRegisterTest("SCACTileTest21", SCACTileTest21, 1); - UtRegisterTest("SCACTileTest22", SCACTileTest22, 1); - UtRegisterTest("SCACTileTest23", SCACTileTest23, 1); - UtRegisterTest("SCACTileTest24", SCACTileTest24, 1); - UtRegisterTest("SCACTileTest25", SCACTileTest25, 1); - UtRegisterTest("SCACTileTest26", SCACTileTest26, 1); - UtRegisterTest("SCACTileTest27", SCACTileTest27, 1); - UtRegisterTest("SCACTileTest28", SCACTileTest28, 1); - UtRegisterTest("SCACTileTest29", SCACTileTest29, 1); + UtRegisterTest("SCACTileTest01", SCACTileTest01); + UtRegisterTest("SCACTileTest02", SCACTileTest02); + UtRegisterTest("SCACTileTest03", SCACTileTest03); + UtRegisterTest("SCACTileTest04", SCACTileTest04); + UtRegisterTest("SCACTileTest05", SCACTileTest05); + UtRegisterTest("SCACTileTest06", SCACTileTest06); + UtRegisterTest("SCACTileTest07", SCACTileTest07); + UtRegisterTest("SCACTileTest08", SCACTileTest08); + UtRegisterTest("SCACTileTest09", SCACTileTest09); + UtRegisterTest("SCACTileTest10", SCACTileTest10); + UtRegisterTest("SCACTileTest11", SCACTileTest11); + UtRegisterTest("SCACTileTest12", SCACTileTest12); + UtRegisterTest("SCACTileTest13", SCACTileTest13); + UtRegisterTest("SCACTileTest14", SCACTileTest14); + UtRegisterTest("SCACTileTest15", SCACTileTest15); + UtRegisterTest("SCACTileTest16", SCACTileTest16); + UtRegisterTest("SCACTileTest17", SCACTileTest17); + UtRegisterTest("SCACTileTest18", SCACTileTest18); + UtRegisterTest("SCACTileTest19", SCACTileTest19); + UtRegisterTest("SCACTileTest20", SCACTileTest20); + UtRegisterTest("SCACTileTest21", SCACTileTest21); + UtRegisterTest("SCACTileTest22", SCACTileTest22); + UtRegisterTest("SCACTileTest23", SCACTileTest23); + UtRegisterTest("SCACTileTest24", SCACTileTest24); + UtRegisterTest("SCACTileTest25", SCACTileTest25); + UtRegisterTest("SCACTileTest26", SCACTileTest26); + UtRegisterTest("SCACTileTest27", SCACTileTest27); + UtRegisterTest("SCACTileTest28", SCACTileTest28); + UtRegisterTest("SCACTileTest29", SCACTileTest29); #endif } diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 6c3370b0d42d..62100d41a737 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -2829,35 +2829,35 @@ void SCACRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCACTest01", SCACTest01, 1); - UtRegisterTest("SCACTest02", SCACTest02, 1); - UtRegisterTest("SCACTest03", SCACTest03, 1); - UtRegisterTest("SCACTest04", SCACTest04, 1); - UtRegisterTest("SCACTest05", SCACTest05, 1); - UtRegisterTest("SCACTest06", SCACTest06, 1); - UtRegisterTest("SCACTest07", SCACTest07, 1); - UtRegisterTest("SCACTest08", SCACTest08, 1); - UtRegisterTest("SCACTest09", SCACTest09, 1); - UtRegisterTest("SCACTest10", SCACTest10, 1); - UtRegisterTest("SCACTest11", SCACTest11, 1); - UtRegisterTest("SCACTest12", SCACTest12, 1); - UtRegisterTest("SCACTest13", SCACTest13, 1); - UtRegisterTest("SCACTest14", SCACTest14, 1); - UtRegisterTest("SCACTest15", SCACTest15, 1); - UtRegisterTest("SCACTest16", SCACTest16, 1); - UtRegisterTest("SCACTest17", SCACTest17, 1); - UtRegisterTest("SCACTest18", SCACTest18, 1); - UtRegisterTest("SCACTest19", SCACTest19, 1); - UtRegisterTest("SCACTest20", SCACTest20, 1); - UtRegisterTest("SCACTest21", SCACTest21, 1); - UtRegisterTest("SCACTest22", SCACTest22, 1); - UtRegisterTest("SCACTest23", SCACTest23, 1); - UtRegisterTest("SCACTest24", SCACTest24, 1); - UtRegisterTest("SCACTest25", SCACTest25, 1); - UtRegisterTest("SCACTest26", SCACTest26, 1); - UtRegisterTest("SCACTest27", SCACTest27, 1); - UtRegisterTest("SCACTest28", SCACTest28, 1); - UtRegisterTest("SCACTest29", SCACTest29, 1); + UtRegisterTest("SCACTest01", SCACTest01); + UtRegisterTest("SCACTest02", SCACTest02); + UtRegisterTest("SCACTest03", SCACTest03); + UtRegisterTest("SCACTest04", SCACTest04); + UtRegisterTest("SCACTest05", SCACTest05); + UtRegisterTest("SCACTest06", SCACTest06); + UtRegisterTest("SCACTest07", SCACTest07); + UtRegisterTest("SCACTest08", SCACTest08); + UtRegisterTest("SCACTest09", SCACTest09); + UtRegisterTest("SCACTest10", SCACTest10); + UtRegisterTest("SCACTest11", SCACTest11); + UtRegisterTest("SCACTest12", SCACTest12); + UtRegisterTest("SCACTest13", SCACTest13); + UtRegisterTest("SCACTest14", SCACTest14); + UtRegisterTest("SCACTest15", SCACTest15); + UtRegisterTest("SCACTest16", SCACTest16); + UtRegisterTest("SCACTest17", SCACTest17); + UtRegisterTest("SCACTest18", SCACTest18); + UtRegisterTest("SCACTest19", SCACTest19); + UtRegisterTest("SCACTest20", SCACTest20); + UtRegisterTest("SCACTest21", SCACTest21); + UtRegisterTest("SCACTest22", SCACTest22); + UtRegisterTest("SCACTest23", SCACTest23); + UtRegisterTest("SCACTest24", SCACTest24); + UtRegisterTest("SCACTest25", SCACTest25); + UtRegisterTest("SCACTest26", SCACTest26); + UtRegisterTest("SCACTest27", SCACTest27); + UtRegisterTest("SCACTest28", SCACTest28); + UtRegisterTest("SCACTest29", SCACTest29); #endif return; diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index b046bfc94094..c7659974a7d0 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -2155,35 +2155,35 @@ static int SCHSTest29(void) void SCHSRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCHSTest01", SCHSTest01, 1); - UtRegisterTest("SCHSTest02", SCHSTest02, 1); - UtRegisterTest("SCHSTest03", SCHSTest03, 1); - UtRegisterTest("SCHSTest04", SCHSTest04, 1); - UtRegisterTest("SCHSTest05", SCHSTest05, 1); - UtRegisterTest("SCHSTest06", SCHSTest06, 1); - UtRegisterTest("SCHSTest07", SCHSTest07, 1); - UtRegisterTest("SCHSTest08", SCHSTest08, 1); - UtRegisterTest("SCHSTest09", SCHSTest09, 1); - UtRegisterTest("SCHSTest10", SCHSTest10, 1); - UtRegisterTest("SCHSTest11", SCHSTest11, 1); - UtRegisterTest("SCHSTest12", SCHSTest12, 1); - UtRegisterTest("SCHSTest13", SCHSTest13, 1); - UtRegisterTest("SCHSTest14", SCHSTest14, 1); - UtRegisterTest("SCHSTest15", SCHSTest15, 1); - UtRegisterTest("SCHSTest16", SCHSTest16, 1); - UtRegisterTest("SCHSTest17", SCHSTest17, 1); - UtRegisterTest("SCHSTest18", SCHSTest18, 1); - UtRegisterTest("SCHSTest19", SCHSTest19, 1); - UtRegisterTest("SCHSTest20", SCHSTest20, 1); - UtRegisterTest("SCHSTest21", SCHSTest21, 1); - UtRegisterTest("SCHSTest22", SCHSTest22, 1); - UtRegisterTest("SCHSTest23", SCHSTest23, 1); - UtRegisterTest("SCHSTest24", SCHSTest24, 1); - UtRegisterTest("SCHSTest25", SCHSTest25, 1); - UtRegisterTest("SCHSTest26", SCHSTest26, 1); - UtRegisterTest("SCHSTest27", SCHSTest27, 1); - UtRegisterTest("SCHSTest28", SCHSTest28, 1); - UtRegisterTest("SCHSTest29", SCHSTest29, 1); + UtRegisterTest("SCHSTest01", SCHSTest01); + UtRegisterTest("SCHSTest02", SCHSTest02); + UtRegisterTest("SCHSTest03", SCHSTest03); + UtRegisterTest("SCHSTest04", SCHSTest04); + UtRegisterTest("SCHSTest05", SCHSTest05); + UtRegisterTest("SCHSTest06", SCHSTest06); + UtRegisterTest("SCHSTest07", SCHSTest07); + UtRegisterTest("SCHSTest08", SCHSTest08); + UtRegisterTest("SCHSTest09", SCHSTest09); + UtRegisterTest("SCHSTest10", SCHSTest10); + UtRegisterTest("SCHSTest11", SCHSTest11); + UtRegisterTest("SCHSTest12", SCHSTest12); + UtRegisterTest("SCHSTest13", SCHSTest13); + UtRegisterTest("SCHSTest14", SCHSTest14); + UtRegisterTest("SCHSTest15", SCHSTest15); + UtRegisterTest("SCHSTest16", SCHSTest16); + UtRegisterTest("SCHSTest17", SCHSTest17); + UtRegisterTest("SCHSTest18", SCHSTest18); + UtRegisterTest("SCHSTest19", SCHSTest19); + UtRegisterTest("SCHSTest20", SCHSTest20); + UtRegisterTest("SCHSTest21", SCHSTest21); + UtRegisterTest("SCHSTest22", SCHSTest22); + UtRegisterTest("SCHSTest23", SCHSTest23); + UtRegisterTest("SCHSTest24", SCHSTest24); + UtRegisterTest("SCHSTest25", SCHSTest25); + UtRegisterTest("SCHSTest26", SCHSTest26); + UtRegisterTest("SCHSTest27", SCHSTest27); + UtRegisterTest("SCHSTest28", SCHSTest28); + UtRegisterTest("SCHSTest29", SCHSTest29); #endif return; diff --git a/src/util-pool-thread.c b/src/util-pool-thread.c index fe83a788f829..2795ebcad0a4 100644 --- a/src/util-pool-thread.c +++ b/src/util-pool-thread.c @@ -439,17 +439,17 @@ static int PoolThreadTestGrow03(void) void PoolThreadRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("PoolThreadTestInit01", PoolThreadTestInit01, 1); - UtRegisterTest("PoolThreadTestInit02", PoolThreadTestInit02, 1); + UtRegisterTest("PoolThreadTestInit01", PoolThreadTestInit01); + UtRegisterTest("PoolThreadTestInit02", PoolThreadTestInit02); - UtRegisterTest("PoolThreadTestGet01", PoolThreadTestGet01, 1); - UtRegisterTest("PoolThreadTestGet02", PoolThreadTestGet02, 1); + UtRegisterTest("PoolThreadTestGet01", PoolThreadTestGet01); + UtRegisterTest("PoolThreadTestGet02", PoolThreadTestGet02); - UtRegisterTest("PoolThreadTestReturn01", PoolThreadTestReturn01, 1); + UtRegisterTest("PoolThreadTestReturn01", PoolThreadTestReturn01); - UtRegisterTest("PoolThreadTestGrow01", PoolThreadTestGrow01, 1); - UtRegisterTest("PoolThreadTestGrow02", PoolThreadTestGrow02, 1); - UtRegisterTest("PoolThreadTestGrow03", PoolThreadTestGrow03, 1); + UtRegisterTest("PoolThreadTestGrow01", PoolThreadTestGrow01); + UtRegisterTest("PoolThreadTestGrow02", PoolThreadTestGrow02); + UtRegisterTest("PoolThreadTestGrow03", PoolThreadTestGrow03); #endif } diff --git a/src/util-pool.c b/src/util-pool.c index 4d4d5e40ea21..dc536df7fff2 100644 --- a/src/util-pool.c +++ b/src/util-pool.c @@ -719,13 +719,13 @@ static int PoolTestInit07 (void) void PoolRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("PoolTestInit01", PoolTestInit01, 1); - UtRegisterTest("PoolTestInit02", PoolTestInit02, 1); - UtRegisterTest("PoolTestInit03", PoolTestInit03, 1); - UtRegisterTest("PoolTestInit04", PoolTestInit04, 1); - UtRegisterTest("PoolTestInit05", PoolTestInit05, 1); - UtRegisterTest("PoolTestInit06", PoolTestInit06, 1); - UtRegisterTest("PoolTestInit07", PoolTestInit07, 1); + UtRegisterTest("PoolTestInit01", PoolTestInit01); + UtRegisterTest("PoolTestInit02", PoolTestInit02); + UtRegisterTest("PoolTestInit03", PoolTestInit03); + UtRegisterTest("PoolTestInit04", PoolTestInit04); + UtRegisterTest("PoolTestInit05", PoolTestInit05); + UtRegisterTest("PoolTestInit06", PoolTestInit06); + UtRegisterTest("PoolTestInit07", PoolTestInit07); PoolThreadRegisterTests(); #endif /* UNITTESTS */ diff --git a/src/util-profiling.c b/src/util-profiling.c index dfe8c7744b96..ee25076e8ca7 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1153,7 +1153,7 @@ void SCProfilingRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ProfilingGenericTicksTest01", ProfilingGenericTicksTest01, 1); + UtRegisterTest("ProfilingGenericTicksTest01", ProfilingGenericTicksTest01); #endif /* UNITTESTS */ } diff --git a/src/util-radix-tree.c b/src/util-radix-tree.c index 928761d95153..ba63e6432c43 100644 --- a/src/util-radix-tree.c +++ b/src/util-radix-tree.c @@ -4181,50 +4181,50 @@ void SCRadixRegisterTests(void) #ifdef UNITTESTS //UtRegisterTest("SCRadixTestInsertion01", SCRadixTestInsertion01, 1); //UtRegisterTest("SCRadixTestInsertion02", SCRadixTestInsertion02, 1); - UtRegisterTest("SCRadixTestIPV4Insertion03", SCRadixTestIPV4Insertion03, 1); - UtRegisterTest("SCRadixTestIPV4Removal04", SCRadixTestIPV4Removal04, 1); + UtRegisterTest("SCRadixTestIPV4Insertion03", SCRadixTestIPV4Insertion03); + UtRegisterTest("SCRadixTestIPV4Removal04", SCRadixTestIPV4Removal04); //UtRegisterTest("SCRadixTestCharacterInsertion05", // SCRadixTestCharacterInsertion05, 1); //UtRegisterTest("SCRadixTestCharacterRemoval06", // SCRadixTestCharacterRemoval06, 1); - UtRegisterTest("SCRadixTestIPV6Insertion07", SCRadixTestIPV6Insertion07, 1); - UtRegisterTest("SCRadixTestIPV6Removal08", SCRadixTestIPV6Removal08, 1); + UtRegisterTest("SCRadixTestIPV6Insertion07", SCRadixTestIPV6Insertion07); + UtRegisterTest("SCRadixTestIPV6Removal08", SCRadixTestIPV6Removal08); UtRegisterTest("SCRadixTestIPV4NetblockInsertion09", - SCRadixTestIPV4NetblockInsertion09, 1); + SCRadixTestIPV4NetblockInsertion09); UtRegisterTest("SCRadixTestIPV4NetblockInsertion10", - SCRadixTestIPV4NetblockInsertion10, 1); + SCRadixTestIPV4NetblockInsertion10); UtRegisterTest("SCRadixTestIPV4NetblockInsertion11", - SCRadixTestIPV4NetblockInsertion11, 1); + SCRadixTestIPV4NetblockInsertion11); UtRegisterTest("SCRadixTestIPV4NetblockInsertion12", - SCRadixTestIPV4NetblockInsertion12, 1); + SCRadixTestIPV4NetblockInsertion12); UtRegisterTest("SCRadixTestIPV6NetblockInsertion13", - SCRadixTestIPV6NetblockInsertion13, 1); + SCRadixTestIPV6NetblockInsertion13); UtRegisterTest("SCRadixTestIPV6NetblockInsertion14", - SCRadixTestIPV6NetblockInsertion14, 1); + SCRadixTestIPV6NetblockInsertion14); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch15", - SCRadixTestIPV4NetBlocksAndBestSearch15, 1); + SCRadixTestIPV4NetBlocksAndBestSearch15); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch16", - SCRadixTestIPV4NetBlocksAndBestSearch16, 1); + SCRadixTestIPV4NetBlocksAndBestSearch16); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch17", - SCRadixTestIPV4NetBlocksAndBestSearch17, 1); + SCRadixTestIPV4NetBlocksAndBestSearch17); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch18", - SCRadixTestIPV4NetBlocksAndBestSearch18, 1); + SCRadixTestIPV4NetBlocksAndBestSearch18); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch19", - SCRadixTestIPV4NetBlocksAndBestSearch19, 1); + SCRadixTestIPV4NetBlocksAndBestSearch19); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch20", - SCRadixTestIPV6NetBlocksAndBestSearch20, 1); + SCRadixTestIPV6NetBlocksAndBestSearch20); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch21", - SCRadixTestIPV6NetBlocksAndBestSearch21, 1); + SCRadixTestIPV6NetBlocksAndBestSearch21); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch22", - SCRadixTestIPV6NetBlocksAndBestSearch22, 1); + SCRadixTestIPV6NetBlocksAndBestSearch22); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch23", - SCRadixTestIPV6NetBlocksAndBestSearch23, 1); + SCRadixTestIPV6NetBlocksAndBestSearch23); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch24", - SCRadixTestIPV6NetBlocksAndBestSearch24, 1); + SCRadixTestIPV6NetBlocksAndBestSearch24); UtRegisterTest("SCRadixTestIPV4NetblockInsertion25", - SCRadixTestIPV4NetblockInsertion25, 1); + SCRadixTestIPV4NetblockInsertion25); UtRegisterTest("SCRadixTestIPV4NetblockInsertion26", - SCRadixTestIPV4NetblockInsertion26, 1); + SCRadixTestIPV4NetblockInsertion26); #endif return; diff --git a/src/util-reference-config.c b/src/util-reference-config.c index 249293e9eb87..3703353940b3 100644 --- a/src/util-reference-config.c +++ b/src/util-reference-config.c @@ -796,12 +796,12 @@ void SCRConfRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCRConfTest01", SCRConfTest01, 1); - UtRegisterTest("SCRConfTest02", SCRConfTest02, 1); - UtRegisterTest("SCRConfTest03", SCRConfTest03, 1); - UtRegisterTest("SCRConfTest04", SCRConfTest04, 1); - UtRegisterTest("SCRConfTest05", SCRConfTest05, 1); - UtRegisterTest("SCRConfTest06", SCRConfTest06, 1); + UtRegisterTest("SCRConfTest01", SCRConfTest01); + UtRegisterTest("SCRConfTest02", SCRConfTest02); + UtRegisterTest("SCRConfTest03", SCRConfTest03); + UtRegisterTest("SCRConfTest04", SCRConfTest04); + UtRegisterTest("SCRConfTest05", SCRConfTest05); + UtRegisterTest("SCRConfTest06", SCRConfTest06); #endif /* UNITTESTS */ return; diff --git a/src/util-ringbuffer.c b/src/util-ringbuffer.c index 4566bf9f527a..e4457f40d4a1 100644 --- a/src/util-ringbuffer.c +++ b/src/util-ringbuffer.c @@ -1078,11 +1078,11 @@ static int RingBuffer8SrSwGet02 (void) void DetectRingBufferRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("RingBuffer8SrSwInit01", RingBuffer8SrSwInit01, 1); - UtRegisterTest("RingBuffer8SrSwPut01", RingBuffer8SrSwPut01, 1); - UtRegisterTest("RingBuffer8SrSwPut02", RingBuffer8SrSwPut02, 1); - UtRegisterTest("RingBuffer8SrSwGet01", RingBuffer8SrSwGet01, 1); - UtRegisterTest("RingBuffer8SrSwGet02", RingBuffer8SrSwGet02, 1); + UtRegisterTest("RingBuffer8SrSwInit01", RingBuffer8SrSwInit01); + UtRegisterTest("RingBuffer8SrSwPut01", RingBuffer8SrSwPut01); + UtRegisterTest("RingBuffer8SrSwPut02", RingBuffer8SrSwPut02); + UtRegisterTest("RingBuffer8SrSwGet01", RingBuffer8SrSwGet01); + UtRegisterTest("RingBuffer8SrSwGet02", RingBuffer8SrSwGet02); #endif /* UNITTESTS */ } diff --git a/src/util-rule-vars.c b/src/util-rule-vars.c index 2edb23e9c8cd..12ced4d193e6 100644 --- a/src/util-rule-vars.c +++ b/src/util-rule-vars.c @@ -520,12 +520,12 @@ int SCRuleVarsMTest01(void) void SCRuleVarsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCRuleVarsPositiveTest01", SCRuleVarsPositiveTest01, 1); - UtRegisterTest("SCRuleVarsNegativeTest02", SCRuleVarsNegativeTest02, 1); - UtRegisterTest("SCRuleVarsPositiveTest03", SCRuleVarsPositiveTest03, 1); - UtRegisterTest("SCRuleVarsNegativeTest04", SCRuleVarsNegativeTest04, 1); + UtRegisterTest("SCRuleVarsPositiveTest01", SCRuleVarsPositiveTest01); + UtRegisterTest("SCRuleVarsNegativeTest02", SCRuleVarsNegativeTest02); + UtRegisterTest("SCRuleVarsPositiveTest03", SCRuleVarsPositiveTest03); + UtRegisterTest("SCRuleVarsNegativeTest04", SCRuleVarsNegativeTest04); - UtRegisterTest("SCRuleVarsMTest01", SCRuleVarsMTest01, 1); + UtRegisterTest("SCRuleVarsMTest01", SCRuleVarsMTest01); #endif return; diff --git a/src/util-spm.c b/src/util-spm.c index 845795b8d8b3..f4e03e288e2d 100644 --- a/src/util-spm.c +++ b/src/util-spm.c @@ -2323,49 +2323,66 @@ void UtilSpmSearchRegistertests(void) { #ifdef UNITTESTS /* Generic tests */ - UtRegisterTest("UtilSpmBasicSearchTest01", UtilSpmBasicSearchTest01, 1); - UtRegisterTest("UtilSpmBasicSearchNocaseTest01", UtilSpmBasicSearchNocaseTest01, 1); - - UtRegisterTest("UtilSpmBs2bmSearchTest01", UtilSpmBs2bmSearchTest01, 1); - UtRegisterTest("UtilSpmBs2bmSearchNocaseTest01", UtilSpmBs2bmSearchNocaseTest01, 1); - - UtRegisterTest("UtilSpmBoyerMooreSearchTest01", UtilSpmBoyerMooreSearchTest01, 1); - UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest01", UtilSpmBoyerMooreSearchNocaseTest01, 1); - UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTestIssue130", UtilSpmBoyerMooreSearchNocaseTestIssue130, 1); - - UtRegisterTest("UtilSpmBs2bmSearchTest02", UtilSpmBs2bmSearchTest02, 1); - UtRegisterTest("UtilSpmBs2bmSearchNocaseTest02", UtilSpmBs2bmSearchNocaseTest02, 1); - - UtRegisterTest("UtilSpmBasicSearchTest02", UtilSpmBasicSearchTest02, 1); - UtRegisterTest("UtilSpmBasicSearchNocaseTest02", UtilSpmBasicSearchNocaseTest02, 1); - - UtRegisterTest("UtilSpmBoyerMooreSearchTest02", UtilSpmBoyerMooreSearchTest02, 1); - UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest02", UtilSpmBoyerMooreSearchNocaseTest02, 1); + UtRegisterTest("UtilSpmBasicSearchTest01", UtilSpmBasicSearchTest01); + UtRegisterTest("UtilSpmBasicSearchNocaseTest01", + UtilSpmBasicSearchNocaseTest01); + + UtRegisterTest("UtilSpmBs2bmSearchTest01", UtilSpmBs2bmSearchTest01); + UtRegisterTest("UtilSpmBs2bmSearchNocaseTest01", + UtilSpmBs2bmSearchNocaseTest01); + + UtRegisterTest("UtilSpmBoyerMooreSearchTest01", + UtilSpmBoyerMooreSearchTest01); + UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest01", + UtilSpmBoyerMooreSearchNocaseTest01); + UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTestIssue130", + UtilSpmBoyerMooreSearchNocaseTestIssue130); + + UtRegisterTest("UtilSpmBs2bmSearchTest02", UtilSpmBs2bmSearchTest02); + UtRegisterTest("UtilSpmBs2bmSearchNocaseTest02", + UtilSpmBs2bmSearchNocaseTest02); + + UtRegisterTest("UtilSpmBasicSearchTest02", UtilSpmBasicSearchTest02); + UtRegisterTest("UtilSpmBasicSearchNocaseTest02", + UtilSpmBasicSearchNocaseTest02); + + UtRegisterTest("UtilSpmBoyerMooreSearchTest02", + UtilSpmBoyerMooreSearchTest02); + UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest02", + UtilSpmBoyerMooreSearchNocaseTest02); /* test matches at any offset */ - UtRegisterTest("UtilSpmSearchOffsetsTest01", UtilSpmSearchOffsetsTest01, 1); - UtRegisterTest("UtilSpmSearchOffsetsNocaseTest01", UtilSpmSearchOffsetsNocaseTest01, 1); + UtRegisterTest("UtilSpmSearchOffsetsTest01", UtilSpmSearchOffsetsTest01); + UtRegisterTest("UtilSpmSearchOffsetsNocaseTest01", + UtilSpmSearchOffsetsNocaseTest01); #ifdef ENABLE_SEARCH_STATS /* Give some stats searching given a prepared context (look at the wrappers) */ - UtRegisterTest("UtilSpmSearchStatsTest01", UtilSpmSearchStatsTest01, 1); - UtRegisterTest("UtilSpmSearchStatsTest02", UtilSpmSearchStatsTest02, 1); - UtRegisterTest("UtilSpmSearchStatsTest03", UtilSpmSearchStatsTest03, 1); + UtRegisterTest("UtilSpmSearchStatsTest01", UtilSpmSearchStatsTest01); + UtRegisterTest("UtilSpmSearchStatsTest02", UtilSpmSearchStatsTest02); + UtRegisterTest("UtilSpmSearchStatsTest03", UtilSpmSearchStatsTest03); - UtRegisterTest("UtilSpmNocaseSearchStatsTest01", UtilSpmNocaseSearchStatsTest01, 1); - UtRegisterTest("UtilSpmNocaseSearchStatsTest02", UtilSpmNocaseSearchStatsTest02, 1); - UtRegisterTest("UtilSpmNocaseSearchStatsTest03", UtilSpmNocaseSearchStatsTest03, 1); + UtRegisterTest("UtilSpmNocaseSearchStatsTest01", + UtilSpmNocaseSearchStatsTest01); + UtRegisterTest("UtilSpmNocaseSearchStatsTest02", + UtilSpmNocaseSearchStatsTest02); + UtRegisterTest("UtilSpmNocaseSearchStatsTest03", + UtilSpmNocaseSearchStatsTest03); /* Stats building context and searching */ - UtRegisterTest("UtilSpmSearchStatsTest04", UtilSpmSearchStatsTest04, 1); - UtRegisterTest("UtilSpmSearchStatsTest05", UtilSpmSearchStatsTest05, 1); - UtRegisterTest("UtilSpmSearchStatsTest06", UtilSpmSearchStatsTest06, 1); - UtRegisterTest("UtilSpmSearchStatsTest07", UtilSpmSearchStatsTest07, 1); - - UtRegisterTest("UtilSpmNocaseSearchStatsTest04", UtilSpmNocaseSearchStatsTest04, 1); - UtRegisterTest("UtilSpmNocaseSearchStatsTest05", UtilSpmNocaseSearchStatsTest05, 1); - UtRegisterTest("UtilSpmNocaseSearchStatsTest06", UtilSpmNocaseSearchStatsTest06, 1); - UtRegisterTest("UtilSpmNocaseSearchStatsTest07", UtilSpmNocaseSearchStatsTest07, 1); + UtRegisterTest("UtilSpmSearchStatsTest04", UtilSpmSearchStatsTest04); + UtRegisterTest("UtilSpmSearchStatsTest05", UtilSpmSearchStatsTest05); + UtRegisterTest("UtilSpmSearchStatsTest06", UtilSpmSearchStatsTest06); + UtRegisterTest("UtilSpmSearchStatsTest07", UtilSpmSearchStatsTest07); + + UtRegisterTest("UtilSpmNocaseSearchStatsTest04", + UtilSpmNocaseSearchStatsTest04); + UtRegisterTest("UtilSpmNocaseSearchStatsTest05", + UtilSpmNocaseSearchStatsTest05); + UtRegisterTest("UtilSpmNocaseSearchStatsTest06", + UtilSpmNocaseSearchStatsTest06); + UtRegisterTest("UtilSpmNocaseSearchStatsTest07", + UtilSpmNocaseSearchStatsTest07); #endif #endif diff --git a/src/util-storage.c b/src/util-storage.c index ba9aa7168558..5c4c0e05bb9b 100644 --- a/src/util-storage.c +++ b/src/util-storage.c @@ -538,8 +538,8 @@ static int StorageTest03(void) void StorageRegisterTests(void) { - UtRegisterTest("StorageTest01", StorageTest01, 1); - UtRegisterTest("StorageTest02", StorageTest02, 1); - UtRegisterTest("StorageTest03", StorageTest03, 1); + UtRegisterTest("StorageTest01", StorageTest01); + UtRegisterTest("StorageTest02", StorageTest02); + UtRegisterTest("StorageTest03", StorageTest03); } #endif diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index f6c34bd0e9fa..d7f24769e2b9 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -2879,28 +2879,39 @@ static int SCThresholdConfTest21(void) void SCThresholdConfRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01, 1); - UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02, 1); - UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03, 1); - UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04, 1); - UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05, 1); - UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06, 1); - UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07, 1); - UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08, 1); - UtRegisterTest("SCThresholdConfTest09 - rate_filter", SCThresholdConfTest09, 1); - UtRegisterTest("SCThresholdConfTest10 - rate_filter", SCThresholdConfTest10, 1); - UtRegisterTest("SCThresholdConfTest11 - event_filter", SCThresholdConfTest11, 1); - UtRegisterTest("SCThresholdConfTest12 - event_filter", SCThresholdConfTest12, 1); - UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13, 1); - UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14, 1); - UtRegisterTest("SCThresholdConfTest15 - suppress drop", SCThresholdConfTest15, 1); - UtRegisterTest("SCThresholdConfTest16 - suppress drop", SCThresholdConfTest16, 1); - UtRegisterTest("SCThresholdConfTest17 - suppress drop", SCThresholdConfTest17, 1); - - UtRegisterTest("SCThresholdConfTest18 - suppress parsing", SCThresholdConfTest18, 1); - UtRegisterTest("SCThresholdConfTest19 - suppress parsing", SCThresholdConfTest19, 1); - UtRegisterTest("SCThresholdConfTest20 - suppress parsing", SCThresholdConfTest20, 1); - UtRegisterTest("SCThresholdConfTest21 - suppress parsing", SCThresholdConfTest21, 1); + UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01); + UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02); + UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03); + UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04); + UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05); + UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06); + UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07); + UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08); + UtRegisterTest("SCThresholdConfTest09 - rate_filter", + SCThresholdConfTest09); + UtRegisterTest("SCThresholdConfTest10 - rate_filter", + SCThresholdConfTest10); + UtRegisterTest("SCThresholdConfTest11 - event_filter", + SCThresholdConfTest11); + UtRegisterTest("SCThresholdConfTest12 - event_filter", + SCThresholdConfTest12); + UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13); + UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14); + UtRegisterTest("SCThresholdConfTest15 - suppress drop", + SCThresholdConfTest15); + UtRegisterTest("SCThresholdConfTest16 - suppress drop", + SCThresholdConfTest16); + UtRegisterTest("SCThresholdConfTest17 - suppress drop", + SCThresholdConfTest17); + + UtRegisterTest("SCThresholdConfTest18 - suppress parsing", + SCThresholdConfTest18); + UtRegisterTest("SCThresholdConfTest19 - suppress parsing", + SCThresholdConfTest19); + UtRegisterTest("SCThresholdConfTest20 - suppress parsing", + SCThresholdConfTest20); + UtRegisterTest("SCThresholdConfTest21 - suppress parsing", + SCThresholdConfTest21); #endif /* UNITTESTS */ } diff --git a/src/util-unittest-helper.c b/src/util-unittest-helper.c index a318205d70f0..94756e7a6ccf 100644 --- a/src/util-unittest-helper.c +++ b/src/util-unittest-helper.c @@ -1066,15 +1066,17 @@ int UTHBuildPacketSrcDstPortsTest02(void) void UTHRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01, 1); - UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02, 1); - UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01, 1); - UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02, 1); - UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01, 1); - UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02, 1); - UtRegisterTest("UTHBuildPacketSrcDstPortsTest01", UTHBuildPacketSrcDstPortsTest01, 1); - UtRegisterTest("UTHBuildPacketSrcDstPortsTest02", UTHBuildPacketSrcDstPortsTest02, 1); - UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01, 1); + UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01); + UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02); + UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01); + UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02); + UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01); + UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02); + UtRegisterTest("UTHBuildPacketSrcDstPortsTest01", + UTHBuildPacketSrcDstPortsTest01); + UtRegisterTest("UTHBuildPacketSrcDstPortsTest02", + UTHBuildPacketSrcDstPortsTest02); + UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01); #endif /* UNITTESTS */ } diff --git a/src/util-unittest.c b/src/util-unittest.c index b172e9a0ffbc..f4e9a454512e 100644 --- a/src/util-unittest.c +++ b/src/util-unittest.c @@ -85,11 +85,9 @@ static int UtAppendTest(UtTest **list, UtTest *test) * * \param name Unit test name * \param TestFn Unit test function - * \param evalue Unit test function return value - * */ -void UtRegisterTest(char *name, int(*TestFn)(void), int evalue) +void UtRegisterTest(char *name, int(*TestFn)(void)) { UtTest *ut = UtAllocTest(); if (ut == NULL) @@ -97,7 +95,6 @@ void UtRegisterTest(char *name, int(*TestFn)(void), int evalue) ut->name = name; ut->TestFn = TestFn; - ut->evalue = evalue; ut->next = NULL; /* append */ @@ -206,8 +203,8 @@ uint32_t UtRunTests(char *regex_arg) TimeSetToCurrentTime(); ret = ut->TestFn(); - printf("%s\n", (ret == ut->evalue) ? "pass" : "FAILED"); - if (ret != ut->evalue) { + printf("%s\n", ret ? "pass" : "FAILED"); + if (!ret) { if (failure_fatal == 1) { fprintf(stderr, "ERROR: unittest failed.\n"); exit(EXIT_FAILURE); @@ -311,8 +308,8 @@ int UtRunSelftest (char *regex_arg) UtInitialize(); - UtRegisterTest("true", UtSelftestTrue, 1); - UtRegisterTest("false", UtSelftestFalse, 1); + UtRegisterTest("true", UtSelftestTrue); + UtRegisterTest("false", UtSelftestFalse); int ret = UtRunTests(regex_arg); if (ret == 0) diff --git a/src/util-unittest.h b/src/util-unittest.h index ebad947089b9..ccf8ff6f9cb5 100644 --- a/src/util-unittest.h +++ b/src/util-unittest.h @@ -33,14 +33,13 @@ typedef struct UtTest_ { char *name; int(*TestFn)(void); - int evalue; struct UtTest_ *next; } UtTest; -void UtRegisterTest(char *name, int(*TestFn)(void), int evalue); +void UtRegisterTest(char *name, int(*TestFn)(void)); uint32_t UtRunTests(char *regex_arg); void UtInitialize(void); void UtCleanup(void); From 13cf2f829e7ed3acbd8555bd6c2d652ffaa1b770 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 6 Apr 2016 16:50:08 -0600 Subject: [PATCH 1239/2553] testing: new test macros, new testing documentation group. Unit testing support macros for failing on expressions, as well as passing tests on expressions. If fatal unittests are enabled BUG_ON will be triggered for an assertion providing the line number of the failure, otherwise the test will simply fail. Moved the fatal flag to a global var instead of a configuration parameter for ease of access from a macro. --- src/suricata.c | 5 +--- src/util-unittest.c | 23 +++++++++++----- src/util-unittest.h | 64 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 12 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index f47aa5aa8f90..280181b13eb9 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1398,10 +1398,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) } else if(strcmp((long_opts[option_index]).name, "fatal-unittests") == 0) { #ifdef UNITTESTS - if (ConfSetFinal("unittests.failure-fatal", "1") != 1) { - fprintf(stderr, "ERROR: Failed to set unittests failure-fatal.\n"); - return TM_ECODE_FAILED; - } + unittests_fatal = 1; #else fprintf(stderr, "ERROR: Unit tests not enabled. Make sure to pass --enable-unittests to configure when building.\n"); return TM_ECODE_FAILED; diff --git a/src/util-unittest.c b/src/util-unittest.c index f4e9a454512e..0503a2431b0a 100644 --- a/src/util-unittest.c +++ b/src/util-unittest.c @@ -24,6 +24,14 @@ * Unit test framework */ +/** + * \defgroup Testing Testing + * + * \brief Unit testing support functions. + * + * @{ + */ + #include "suricata-common.h" #include "runmodes.h" #include "util-unittest.h" @@ -38,6 +46,8 @@ static pcre_extra *parse_regex_study; static UtTest *ut_list; +int unittests_fatal = 0; + /** * \brief Allocate UtTest list member * @@ -181,12 +191,6 @@ uint32_t UtRunTests(char *regex_arg) uint32_t good = 0, bad = 0, matchcnt = 0; int ret = 0, rcomp = 0; int ov[MAX_SUBSTRINGS]; - int failure_fatal; - - if (ConfGetBool("unittests.failure-fatal", &failure_fatal) != 1) { - SCLogDebug("ConfGetBool could not load the value."); - failure_fatal = 0; - } rcomp = UtRegex(regex_arg); @@ -205,7 +209,7 @@ uint32_t UtRunTests(char *regex_arg) ret = ut->TestFn(); printf("%s\n", ret ? "pass" : "FAILED"); if (!ret) { - if (failure_fatal == 1) { + if (unittests_fatal == 1) { fprintf(stderr, "ERROR: unittest failed.\n"); exit(EXIT_FAILURE); } @@ -292,6 +296,7 @@ int UtSelftestFalse(void) if (0)return 0; else return 1; } + #endif /* UNITTESTS */ /** \brief Run self tests @@ -321,3 +326,7 @@ int UtRunSelftest (char *regex_arg) #endif /* UNITTESTS */ return 0; } + +/** + * @} + */ diff --git a/src/util-unittest.h b/src/util-unittest.h index ccf8ff6f9cb5..cca59b869b56 100644 --- a/src/util-unittest.h +++ b/src/util-unittest.h @@ -24,6 +24,12 @@ * Unit test framework */ +/** + * \addtogroup Testing + * + * @{ + */ + #ifndef __UTIL_UNITTEST_H__ #define __UTIL_UNITTEST_H__ @@ -38,7 +44,6 @@ typedef struct UtTest_ { } UtTest; - void UtRegisterTest(char *name, int(*TestFn)(void)); uint32_t UtRunTests(char *regex_arg); void UtInitialize(void); @@ -47,7 +52,64 @@ int UtRunSelftest (char *regex_arg); void UtListTests(char *regex_arg); void UtRunModeRegister(void); +extern int unittests_fatal; + +/** + * \brief Fail a test if expression evaluates to false. + */ +#define FAIL_IF(expr) do { \ + if (unittests_fatal) { \ + BUG_ON(expr); \ + } else if (expr) { \ + return 0; \ + } \ + } while (0) + +/** + * \brief Fail a test if expression to true. + */ +#define FAIL_IF_NOT(expr) do { \ + FAIL_IF(!(expr)); \ + } while (0) + +/** + * \brief Fail a test if expression evaluates to NULL. + */ +#define FAIL_IF_NULL(expr) do { \ + FAIL_IF(NULL == expr); \ + } while (0) + +/** + * \brief Fail a test if expression evaluates to non-NULL. + */ +#define FAIL_IF_NOT_NULL(expr) do { \ + FAIL_IF(NULL != expr); \ + } while (0) + +/** + * \brief Pass the test. + * + * Only to be used at the end of a function instead instead of "return 1." + */ +#define PASS do { \ + return 1; \ + } while (0) + #endif +/** + * \brief Pass the test if expression evaluates to true. + * + * Only to be used at the end of a function instead of returning the + * result of an expression. + */ +#define PASS_IF(expr) do { \ + FAIL_IF(!(expr)); \ + PASS; \ + } while (0) + #endif /* __UTIL_UNITTEST_H__ */ +/** + * @} + */ From d7d05b007cffd92003a50f5b3861010a6b30505f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 6 Apr 2016 16:51:43 -0600 Subject: [PATCH 1240/2553] conf: use new testing macros Also don't bother with cleanup on failure. --- src/conf.c | 426 ++++++++++++++++------------------------------------- 1 file changed, 124 insertions(+), 302 deletions(-) diff --git a/src/conf.c b/src/conf.c index 29af449209be..d575d2734c97 100644 --- a/src/conf.c +++ b/src/conf.c @@ -893,7 +893,8 @@ static int ConfTestGetNonExistant(void) char name[] = "non-existant-value"; char *value; - return !ConfGet(name, &value); + FAIL_IF(ConfGet(name, &value)); + PASS; } /** @@ -905,17 +906,14 @@ static int ConfTestSetAndGet(void) char value[] = "some-value"; char *value0; - if (ConfSet(name, value) != 1) - return 0; - if (ConfGet(name, &value0) != 1) - return 0; - if (strcmp(value, value0) != 0) - return 0; + FAIL_IF(ConfSet(name, value) != 1); + FAIL_IF(ConfGet(name, &value0) != 1); + FAIL_IF(strcmp(value, value0) != 0); /* Cleanup. */ ConfRemove(name); - return 1; + PASS; } /** @@ -928,21 +926,16 @@ static int ConfTestOverrideValue1(void) char value0[] = "some-value"; char value1[] = "new-value"; char *val; - int rc; - - if (ConfSet(name, value0) != 1) - return 0; - if (ConfSet(name, value1) != 1) - return 0; - if (ConfGet(name, &val) != 1) - return 0; - rc = !strcmp(val, value1); + FAIL_IF(ConfSet(name, value0) != 1); + FAIL_IF(ConfSet(name, value1) != 1); + FAIL_IF(ConfGet(name, &val) != 1); + FAIL_IF(strcmp(val, value1)); /* Cleanup. */ ConfRemove(name); - return rc; + PASS; } /** @@ -954,21 +947,16 @@ static int ConfTestOverrideValue2(void) char value0[] = "some-value"; char value1[] = "new-value"; char *val; - int rc; - if (ConfSetFinal(name, value0) != 1) - return 0; - if (ConfSet(name, value1) != 0) - return 0; - if (ConfGet(name, &val) != 1) - return 0; - - rc = !strcmp(val, value0); + FAIL_IF(ConfSetFinal(name, value0) != 1); + FAIL_IF(ConfSet(name, value1) != 0); + FAIL_IF(ConfGet(name, &val) != 1); + FAIL_IF(strcmp(val, value0)); /* Cleanup. */ ConfRemove(name); - return rc; + PASS; } /** @@ -979,34 +967,22 @@ static int ConfTestGetInt(void) char name[] = "some-int.x"; intmax_t val; - if (ConfSet(name, "0") != 1) - return 0; - if (ConfGetInt(name, &val) != 1) - return 0; + FAIL_IF(ConfSet(name, "0") != 1); + FAIL_IF(ConfGetInt(name, &val) != 1); + FAIL_IF(val != 0); - if (val != 0) - return 0; + FAIL_IF(ConfSet(name, "-1") != 1); + FAIL_IF(ConfGetInt(name, &val) != 1); + FAIL_IF(val != -1); - if (ConfSet(name, "-1") != 1) - return 0; - if (ConfGetInt(name, &val) != 1) - return 0; - if (val != -1) - return 0; - - if (ConfSet(name, "0xffff") != 1) - return 0; - if (ConfGetInt(name, &val) != 1) - return 0; - if (val != 0xffff) - return 0; + FAIL_IF(ConfSet(name, "0xffff") != 1); + FAIL_IF(ConfGetInt(name, &val) != 1); + FAIL_IF(val != 0xffff); - if (ConfSet(name, "not-an-int") != 1) - return 0; - if (ConfGetInt(name, &val) != 0) - return 0; + FAIL_IF(ConfSet(name, "not-an-int") != 1); + FAIL_IF(ConfGetInt(name, &val) != 0); - return 1; + PASS; } /** @@ -1032,29 +1008,22 @@ static int ConfTestGetBool(void) size_t u; for (u = 0; u < sizeof(trues) / sizeof(trues[0]); u++) { - if (ConfSet(name, trues[u]) != 1) - return 0; - if (ConfGetBool(name, &val) != 1) - return 0; - if (val != 1) - return 0; + FAIL_IF(ConfSet(name, trues[u]) != 1); + FAIL_IF(ConfGetBool(name, &val) != 1); + FAIL_IF(val != 1); } for (u = 0; u < sizeof(falses) / sizeof(falses[0]); u++) { - if (ConfSet(name, falses[u]) != 1) - return 0; - if (ConfGetBool(name, &val) != 1) - return 0; - if (val != 0) - return 0; + FAIL_IF(ConfSet(name, falses[u]) != 1); + FAIL_IF(ConfGetBool(name, &val) != 1); + FAIL_IF(val != 0); } - return 1; + PASS; } static int ConfNodeLookupChildTest(void) { - int retval = 0; char *test_vals[] = { "one", "two", "three" }; size_t u; @@ -1069,45 +1038,30 @@ static int ConfNodeLookupChildTest(void) } child = ConfNodeLookupChild(parent, "one"); - if (child == NULL) - goto end; - if (strcmp(child->name, "one") != 0) - goto end; - if (strcmp(child->val, "one") != 0) - goto end; + FAIL_IF(child == NULL); + FAIL_IF(strcmp(child->name, "one") != 0); + FAIL_IF(strcmp(child->val, "one") != 0); child = ConfNodeLookupChild(parent, "two"); - if (child == NULL) - goto end; - if (strcmp(child->name, "two") != 0) - goto end; - if (strcmp(child->val, "two") != 0) - goto end; + FAIL_IF(child == NULL); + FAIL_IF(strcmp(child->name, "two") != 0); + FAIL_IF(strcmp(child->val, "two") != 0); child = ConfNodeLookupChild(parent, "three"); - if (child == NULL) - goto end; - if (strcmp(child->name, "three") != 0) - goto end; - if (strcmp(child->val, "three") != 0) - goto end; + FAIL_IF(child == NULL); + FAIL_IF(strcmp(child->name, "three") != 0); + FAIL_IF(strcmp(child->val, "three") != 0); child = ConfNodeLookupChild(parent, "four"); - if (child != NULL) - goto end; + FAIL_IF(child != NULL); - if (ConfNodeLookupChild(NULL, NULL) != NULL) { - goto end; - } - - retval = 1; + FAIL_IF(ConfNodeLookupChild(NULL, NULL) != NULL); -end: if (parent != NULL) { ConfNodeFree(parent); } - return retval; + PASS; } static int ConfNodeLookupChildValueTest(void) @@ -1127,36 +1081,28 @@ static int ConfNodeLookupChildValueTest(void) } value = (char *)ConfNodeLookupChildValue(parent, "one"); - if (value == NULL) - return 0; - if (strcmp(value, "one") != 0) - return 0; + FAIL_IF(value == NULL); + FAIL_IF(strcmp(value, "one") != 0); value = (char *)ConfNodeLookupChildValue(parent, "two"); - if (value == NULL) - return 0; - if (strcmp(value, "two") != 0) - return 0; + FAIL_IF(value == NULL); + FAIL_IF(strcmp(value, "two") != 0); value = (char *)ConfNodeLookupChildValue(parent, "three"); - if (value == NULL) - return 0; - if (strcmp(value, "three") != 0) - return 0; + FAIL_IF(value == NULL); + FAIL_IF(strcmp(value, "three") != 0); value = (char *)ConfNodeLookupChildValue(parent, "four"); - if (value != NULL) - return 0; + FAIL_IF(value != NULL); ConfNodeFree(parent); - return 1; + PASS; } static int ConfGetChildValueWithDefaultTest(void) { char *val = ""; - int ret = 1; ConfCreateContextBackup(); ConfInit(); ConfSet("af-packet.0.interface", "eth0"); @@ -1166,21 +1112,16 @@ static int ConfGetChildValueWithDefaultTest(void) ConfNode *root = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); ConfGetChildValueWithDefault(root, dflt, "cluster-type", &val); - if (strcmp(val, "cluster_cpu")) { - ConfDeInit(); - ConfRestoreContextBackup(); - return 0; - } + FAIL_IF(strcmp(val, "cluster_cpu")); ConfSet("af-packet.0.cluster-type", "cluster_flow"); ConfGetChildValueWithDefault(root, dflt, "cluster-type", &val); - if (strcmp(val, "cluster_flow")) { - ret = 0; - } + FAIL_IF(strcmp(val, "cluster_flow")); + ConfDeInit(); ConfRestoreContextBackup(); - return ret; + PASS; } static int ConfGetChildValueIntWithDefaultTest(void) @@ -1195,21 +1136,16 @@ static int ConfGetChildValueIntWithDefaultTest(void) ConfNode *root = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); ConfGetChildValueIntWithDefault(root, dflt, "threads", &val); - if (val != 2) { - ConfDeInit(); - ConfRestoreContextBackup(); - return 0; - } + FAIL_IF(val != 2); ConfSet("af-packet.0.threads", "1"); ConfGetChildValueIntWithDefault(root, dflt, "threads", &val); + FAIL_IF(val != 1); ConfDeInit(); ConfRestoreContextBackup(); - if (val != 1) { - return 0; - } - return 1; + + PASS; } static int ConfGetChildValueBoolWithDefaultTest(void) @@ -1224,21 +1160,16 @@ static int ConfGetChildValueBoolWithDefaultTest(void) ConfNode *root = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); ConfGetChildValueBoolWithDefault(root, dflt, "use-mmap", &val); - if (val == 0) { - ConfDeInit(); - ConfRestoreContextBackup(); - return 0; - } + FAIL_IF(val == 0); ConfSet("af-packet.0.use-mmap", "no"); ConfGetChildValueBoolWithDefault(root, dflt, "use-mmap", &val); + FAIL_IF(val); ConfDeInit(); ConfRestoreContextBackup(); - if (val) { - return 0; - } - return 1; + + PASS; } /** @@ -1249,22 +1180,19 @@ static int ConfNodeRemoveTest(void) ConfCreateContextBackup(); ConfInit(); - if (ConfSet("some.nested.parameter", "blah") != 1) - return 0; + FAIL_IF(ConfSet("some.nested.parameter", "blah") != 1); ConfNode *node = ConfGetNode("some.nested.parameter"); - if (node == NULL) - return 0; + FAIL_IF(node == NULL); ConfNodeRemove(node); node = ConfGetNode("some.nested.parameter"); - if (node != NULL) - return 0; + FAIL_IF(node != NULL); ConfDeInit(); ConfRestoreContextBackup(); - return 1; + PASS; } static int ConfSetTest(void) @@ -1273,37 +1201,31 @@ static int ConfSetTest(void) ConfInit(); /* Set some value with 2 levels. */ - if (ConfSet("one.two", "three") != 1) - return 0; + FAIL_IF(ConfSet("one.two", "three") != 1); ConfNode *n = ConfGetNode("one.two"); - if (n == NULL) - return 0; + FAIL_IF(n == NULL); /* Set another 2 level parameter with the same first level, this * used to trigger a bug that caused the second level of the name * to become a first level node. */ - if (ConfSet("one.three", "four") != 1) - return 0; + FAIL_IF(ConfSet("one.three", "four") != 1); n = ConfGetNode("one.three"); - if (n == NULL) - return 0; + FAIL_IF(n == NULL); /* A top level node of "three" should not exist. */ n = ConfGetNode("three"); - if (n != NULL) - return 0; + FAIL_IF(n != NULL); ConfDeInit(); ConfRestoreContextBackup(); - return 1; + PASS; } static int ConfGetNodeOrCreateTest(void) { ConfNode *node; - int ret = 0; ConfCreateContextBackup(); ConfInit(); @@ -1311,215 +1233,115 @@ static int ConfGetNodeOrCreateTest(void) /* Get a node that should not exist, give it a value, re-get it * and make sure the second time it returns the existing node. */ node = ConfGetNodeOrCreate("node0", 0); - if (node == NULL) { - fprintf(stderr, "returned null\n"); - goto end; - } - if (node->parent == NULL || node->parent != root) { - fprintf(stderr, "unexpected parent node\n"); - goto end; - } - if (node->val != NULL) { - fprintf(stderr, "node already existed\n"); - goto end; - } + FAIL_IF(node == NULL); + FAIL_IF(node->parent == NULL || node->parent != root); + FAIL_IF(node->val != NULL); node->val = SCStrdup("node0"); node = ConfGetNodeOrCreate("node0", 0); - if (node == NULL) { - fprintf(stderr, "returned null\n"); - goto end; - } - if (node->val == NULL) { - fprintf(stderr, "new node was allocated\n"); - goto end; - } - if (strcmp(node->val, "node0") != 0) { - fprintf(stderr, "node did not have expected value\n"); - goto end; - } + FAIL_IF(node == NULL); + FAIL_IF(node->val == NULL); + FAIL_IF(strcmp(node->val, "node0") != 0); /* Do the same, but for something deeply nested. */ node = ConfGetNodeOrCreate("parent.child.grandchild", 0); - if (node == NULL) { - fprintf(stderr, "returned null\n"); - goto end; - } - if (node->parent == NULL || node->parent == root) { - fprintf(stderr, "unexpected parent node\n"); - goto end; - } - if (node->val != NULL) { - fprintf(stderr, "node already existed\n"); - goto end; - } + FAIL_IF(node == NULL); + FAIL_IF(node->parent == NULL || node->parent == root); + FAIL_IF(node->val != NULL); node->val = SCStrdup("parent.child.grandchild"); node = ConfGetNodeOrCreate("parent.child.grandchild", 0); - if (node == NULL) { - fprintf(stderr, "returned null\n"); - goto end; - } - if (node->val == NULL) { - fprintf(stderr, "new node was allocated\n"); - goto end; - } - if (strcmp(node->val, "parent.child.grandchild") != 0) { - fprintf(stderr, "node did not have expected value\n"); - goto end; - } + FAIL_IF(node == NULL); + FAIL_IF(node->val == NULL); + FAIL_IF(strcmp(node->val, "parent.child.grandchild") != 0); /* Test that 2 child nodes have the same root. */ ConfNode *child1 = ConfGetNodeOrCreate("parent.kids.child1", 0); ConfNode *child2 = ConfGetNodeOrCreate("parent.kids.child2", 0); - if (child1 == NULL || child2 == NULL) { - fprintf(stderr, "returned null\n"); - goto end; - } - if (child1->parent != child2->parent) { - fprintf(stderr, "child nodes have different parents\n"); - goto end; - } - if (strcmp(child1->parent->name, "kids") != 0) { - fprintf(stderr, "parent node had unexpected name\n"); - goto end; - } - - ret = 1; + FAIL_IF(child1 == NULL || child2 == NULL); + FAIL_IF(child1->parent != child2->parent); + FAIL_IF(strcmp(child1->parent->name, "kids") != 0); -end: ConfDeInit(); ConfRestoreContextBackup(); - return ret; + PASS; } static int ConfNodePruneTest(void) { - int ret = 0; ConfNode *node; ConfCreateContextBackup(); ConfInit(); /* Test that final nodes exist after a prune. */ - if (ConfSet("node.notfinal", "notfinal") != 1) - goto end; - if (ConfSetFinal("node.final", "final") != 1) - goto end; - if (ConfGetNode("node.notfinal") == NULL) - goto end; - if (ConfGetNode("node.final") == NULL) - goto end; - if ((node = ConfGetNode("node")) == NULL) - goto end; + FAIL_IF(ConfSet("node.notfinal", "notfinal") != 1); + FAIL_IF(ConfSetFinal("node.final", "final") != 1); + FAIL_IF(ConfGetNode("node.notfinal") == NULL); + FAIL_IF(ConfGetNode("node.final") == NULL); + FAIL_IF((node = ConfGetNode("node")) == NULL); ConfNodePrune(node); - if (ConfGetNode("node.notfinal") != NULL) - goto end; - if (ConfGetNode("node.final") == NULL) - goto end; + FAIL_IF(ConfGetNode("node.notfinal") != NULL); + FAIL_IF(ConfGetNode("node.final") == NULL); /* Test that everything under a final node exists after a prune. */ - if (ConfSet("node.final.one", "one") != 1) - goto end; - if (ConfSet("node.final.two", "two") != 1) - goto end; + FAIL_IF(ConfSet("node.final.one", "one") != 1); + FAIL_IF(ConfSet("node.final.two", "two") != 1); ConfNodePrune(node); - if (ConfNodeLookupChild(node, "final") == NULL) - goto end; - if (ConfGetNode("node.final.one") == NULL) - goto end; - if (ConfGetNode("node.final.two") == NULL) - goto end; + FAIL_IF(ConfNodeLookupChild(node, "final") == NULL); + FAIL_IF(ConfGetNode("node.final.one") == NULL); + FAIL_IF(ConfGetNode("node.final.two") == NULL); - ret = 1; - -end: ConfDeInit(); ConfRestoreContextBackup(); - return ret; + PASS; } int ConfNodeIsSequenceTest(void) { - int retval = 0; ConfNode *node = ConfNodeNew(); - if (node == NULL) { - goto end; - } - if (ConfNodeIsSequence(node)) { - goto end; - } + FAIL_IF(node == NULL); + FAIL_IF(ConfNodeIsSequence(node)); node->is_seq = 1; - if (!ConfNodeIsSequence(node)) { - goto end; - } - - retval = 1; + FAIL_IF(!ConfNodeIsSequence(node)); -end: if (node != NULL) { ConfNodeFree(node); } - return retval; + PASS; } static int ConfSetFromStringTest(void) { - int retval = 0; ConfNode *n; ConfCreateContextBackup(); ConfInit(); - if (!ConfSetFromString("stream.midstream=true", 0)) { - goto end; - } + FAIL_IF_NOT(ConfSetFromString("stream.midstream=true", 0)); n = ConfGetNode("stream.midstream"); - if (n == NULL) { - goto end; - } - if (n->val == NULL || strcmp("true", n->val)) { - goto end; - } + FAIL_IF_NULL(n); + FAIL_IF_NULL(n->val); + FAIL_IF(strcmp("true", n->val)); - if (!ConfSetFromString("stream.midstream =false", 0)) { - goto end; - } + FAIL_IF_NOT(ConfSetFromString("stream.midstream =false", 0)); n = ConfGetNode("stream.midstream"); - if (n == NULL) { - goto end; - } - if (n->val == NULL || strcmp("false", n->val)) { - goto end; - } + FAIL_IF_NULL(n); + FAIL_IF(n->val == NULL || strcmp("false", n->val)); - if (!ConfSetFromString("stream.midstream= true", 0)) { - goto end; - } + FAIL_IF_NOT(ConfSetFromString("stream.midstream= true", 0)); n = ConfGetNode("stream.midstream"); - if (n == NULL) { - goto end; - } - if (n->val == NULL || strcmp("true", n->val)) { - goto end; - } + FAIL_IF_NULL(n); + FAIL_IF(n->val == NULL || strcmp("true", n->val)); - if (!ConfSetFromString("stream.midstream = false", 0)) { - goto end; - } + FAIL_IF_NOT(ConfSetFromString("stream.midstream = false", 0)); n = ConfGetNode("stream.midstream"); - if (n == NULL) { - goto end; - } - if (n->val == NULL || strcmp("false", n->val)) { - goto end; - } + FAIL_IF_NULL(n); + FAIL_IF(n->val == NULL || strcmp("false", n->val)); - retval = 1; -end: ConfDeInit(); ConfRestoreContextBackup(); - return retval; + PASS; } void ConfRegisterTests(void) From da1dec6d65f1c9913ececb0e1c86a8c8260ed0cc Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 7 Apr 2016 10:57:27 -0600 Subject: [PATCH 1241/2553] counters: use some of the new macros in tests --- src/counters.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/counters.c b/src/counters.c index c00b4fcf296f..add05fca7904 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1384,7 +1384,7 @@ static int StatsTestCntArraySize07() StatsReleaseCounters(tv.perf_public_ctx.head); StatsReleasePrivateThreadContext(pca); - return result == 2; + PASS_IF(result == 2); } static int StatsTestUpdateCounter08() From 52f6d214631199fcf5371f55e1dfb0fff3a6afe4 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 7 Apr 2016 10:57:45 -0600 Subject: [PATCH 1242/2553] flowbits: use some of the new test macros --- src/detect-flowbits.c | 97 +++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 64 deletions(-) diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 6853f323fbbd..5cc727c3e71b 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -315,69 +315,38 @@ void DetectFlowbitFree (void *ptr) static int FlowBitsTestParse01(void) { - int ret = 0; char command[16] = "", name[16] = ""; /* Single argument version. */ - if (!DetectFlowbitParse("noalert", command, sizeof(command), name, - sizeof(name))) { - goto end; - } - if (strcmp(command, "noalert") != 0) { - goto end; - } + FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name, + sizeof(name))); + FAIL_IF(strcmp(command, "noalert") != 0); /* No leading or trailing spaces. */ - if (!DetectFlowbitParse("set,flowbit", command, sizeof(command), name, - sizeof(name))) { - goto end; - } - if (strcmp(command, "set") != 0) { - goto end; - } - if (strcmp(name, "flowbit") != 0) { - goto end; - } + FAIL_IF(!DetectFlowbitParse("set,flowbit", command, sizeof(command), name, + sizeof(name))); + FAIL_IF(strcmp(command, "set") != 0); + FAIL_IF(strcmp(name, "flowbit") != 0); /* Leading space. */ - if (!DetectFlowbitParse("set, flowbit", command, sizeof(command), name, - sizeof(name))) { - goto end; - } - if (strcmp(command, "set") != 0) { - goto end; - } - if (strcmp(name, "flowbit") != 0) { - goto end; - } + FAIL_IF(!DetectFlowbitParse("set, flowbit", command, sizeof(command), name, + sizeof(name))); + FAIL_IF(strcmp(command, "set") != 0); + FAIL_IF(strcmp(name, "flowbit") != 0); /* Trailing space. */ - if (!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name, - sizeof(name))) { - goto end; - } - if (strcmp(command, "set") != 0) { - goto end; - } - if (strcmp(name, "flowbit") != 0) { - goto end; - } + FAIL_IF(!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name, + sizeof(name))); + FAIL_IF(strcmp(command, "set") != 0); + FAIL_IF(strcmp(name, "flowbit") != 0); /* Leading and trailing space. */ - if (!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name, - sizeof(name))) { - goto end; - } - if (strcmp(command, "set") != 0) { - goto end; - } - if (strcmp(name, "flowbit") != 0) { - goto end; - } + FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name, + sizeof(name))); + FAIL_IF(strcmp(command, "set") != 0); + FAIL_IF(strcmp(name, "flowbit") != 0); - ret = 1; -end: - return ret; + PASS; } /** @@ -452,7 +421,7 @@ static int FlowBitsTestSig01(void) } SCFree(p); - return result == 0; + PASS_IF(result == 0); } /** @@ -574,7 +543,7 @@ static int FlowBitsTestSig02(void) } SCFree(p); - return result == 0; + PASS_IF(result == 0); } /** @@ -652,7 +621,7 @@ static int FlowBitsTestSig03(void) SCFree(p); - return result == 0; + PASS_IF(result == 0); } /** @@ -716,7 +685,7 @@ static int FlowBitsTestSig04(void) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); SCFree(p); - return result; + PASS_IF(result); end: @@ -734,7 +703,7 @@ static int FlowBitsTestSig04(void) } SCFree(p); - return result; + PASS_IF(result); } /** @@ -796,7 +765,7 @@ static int FlowBitsTestSig05(void) DetectEngineCtxFree(de_ctx); SCFree(p); - return result; + PASS_IF(result); end: if (de_ctx != NULL) { @@ -813,7 +782,7 @@ static int FlowBitsTestSig05(void) } SCFree(p); - return result; + PASS_IF(result); } /** @@ -898,7 +867,7 @@ static int FlowBitsTestSig06(void) FLOW_DESTROY(&f); SCFree(p); - return result; + PASS_IF(result); end: if (de_ctx != NULL) { @@ -917,7 +886,7 @@ static int FlowBitsTestSig06(void) if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); - return result; + PASS_IF(result); } /** @@ -1004,7 +973,7 @@ static int FlowBitsTestSig07(void) FLOW_DESTROY(&f); SCFree(p); - return result == 0; + PASS_IF(result == 0); end: if (de_ctx != NULL) { @@ -1024,7 +993,7 @@ static int FlowBitsTestSig07(void) FLOW_DESTROY(&f); SCFree(p); - return result == 0; + PASS_IF(result == 0); } /** @@ -1113,7 +1082,7 @@ static int FlowBitsTestSig08(void) FLOW_DESTROY(&f); SCFree(p); - return result == 0; + PASS_IF(result == 0); end: if (de_ctx != NULL) { @@ -1133,7 +1102,7 @@ static int FlowBitsTestSig08(void) FLOW_DESTROY(&f); SCFree(p); - return result == 0; + PASS_IF(result == 0); } #endif /* UNITTESTS */ From fdff9e97e466d9b442cecd826f0074f8adc6b861 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 7 Apr 2016 10:57:54 -0600 Subject: [PATCH 1243/2553] doxygen: define UNITTESTS to generate test framework docs --- doxygen.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen.cfg b/doxygen.cfg index 6edc71333bfe..0d77ce20ab37 100644 --- a/doxygen.cfg +++ b/doxygen.cfg @@ -1601,7 +1601,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = NFQ IPFW HAVE_PFRING HAVE_AF_PACKET PRELUDE HAVE_NAPATECH HAVE_DAG PROFILING +PREDEFINED = NFQ IPFW HAVE_PFRING HAVE_AF_PACKET PRELUDE HAVE_NAPATECH HAVE_DAG PROFILING UNITTESTS # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. From e27ad81a43c9780f0756ffba4eb5c2ed97d0bfb0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 11 Apr 2016 14:08:39 +0200 Subject: [PATCH 1244/2553] autotools: add AS_VERSION_COMPARE stub for CentOS 5 --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 5c5f1618ea74..7faf9a63cd90 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,6 @@ AC_INIT(suricata, 3.1dev) m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])AM_SILENT_RULES([yes]) + m4_ifndef([AS_VERSION_COMPARE], [AC_DEFUN([AS_VERSION_COMPARE],[])]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([src/suricata.c]) AC_CONFIG_MACRO_DIR(m4) From 365015c2d54f484b9547f60f4851c2a5a979dc24 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Thu, 7 Apr 2016 10:31:25 +0300 Subject: [PATCH 1245/2553] Support sending rejects via libnet when running under non-root. Since version 1.1.6 libnet handles capabilities correctly. So changing libnet's version checking a little bit should do the trick. --- configure.ac | 13 ++++++++++++- src/detect-parse.c | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 7faf9a63cd90..e9de6f2d12cf 100644 --- a/configure.ac +++ b/configure.ac @@ -970,7 +970,9 @@ AC_MSG_CHECKING(for libnet.h version 1.1.x) if test "$LIBNET_INC_DIR" != ""; then - if eval "grep LIBNET_VERSION $LIBNET_INC_DIR/libnet.h | grep -v '1.[[12]]' >/dev/null"; then + LIBNET_VER=`grep LIBNET_VERSION $LIBNET_INC_DIR/libnet.h | grep '1.[[12]]' | sed 's/[[^"]]*"\([[^"]]*\).*/\1/'` + + if test -z "$LIBNET_VER" ; then AC_MSG_RESULT(no) LIBNET_DETECT_FAIL="yes" LIBNET_FAIL_WARN($libnet_dir) @@ -1012,6 +1014,15 @@ fi LIBS="${TMPLIBS}" fi + + # See if we have libnet 1.1.6 or newer - these versions handle capabilities correctly + # Some patched 1.1.4 versions are also good, but it's not guaranteed for all distros. + # + # Details: https://bugzilla.redhat.com/show_bug.cgi?id=589770 + AS_VERSION_COMPARE([LIBNET_VER], [1.1.6], + [], + [AC_DEFINE([HAVE_LIBNET_CAPABILITIES],[1], (libnet_have_capabilities_patch))], + [AC_DEFINE([HAVE_LIBNET_CAPABILITIES],[1], (libnet_have_capabilities_patch))]) fi else LIBNET_DETECT_FAIL="yes" diff --git a/src/detect-parse.c b/src/detect-parse.c index 670dd28879fe..62e1f49a51c0 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -751,7 +751,7 @@ static int SigParsePort(const DetectEngineCtx *de_ctx, static int SigParseActionRejectValidate(const char *action) { #ifdef HAVE_LIBNET11 -#ifdef HAVE_LIBCAP_NG +#if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES if (sc_set_caps == TRUE) { SCLogError(SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG, "Libnet 1.1 is " "incompatible with POSIX based capabilities with privs dropping. " From 434b09563abe5c159b3605415d65b54880431b36 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 1 Apr 2016 09:40:56 +0200 Subject: [PATCH 1246/2553] app-layer-tls-handshake: remove duplicate include --- src/app-layer-tls-handshake.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app-layer-tls-handshake.c b/src/app-layer-tls-handshake.c index 61e3790e497f..1161f61aa3b0 100644 --- a/src/app-layer-tls-handshake.c +++ b/src/app-layer-tls-handshake.c @@ -45,8 +45,6 @@ #include "app-layer-tls-handshake.h" -#include - #include "util-decode-der.h" #include "util-decode-der-get.h" From 550823455ed62a1d213c125f013af6ea3ad17631 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 1 Apr 2016 11:48:44 +0200 Subject: [PATCH 1247/2553] app-layer-tls-handshake: code cleanup --- src/app-layer-tls-handshake.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/app-layer-tls-handshake.c b/src/app-layer-tls-handshake.c index 1161f61aa3b0..9f034016cb46 100644 --- a/src/app-layer-tls-handshake.c +++ b/src/app-layer-tls-handshake.c @@ -39,20 +39,18 @@ #include "decode.h" #include "app-layer-parser.h" -#include "decode-events.h" - #include "app-layer-ssl.h" - #include "app-layer-tls-handshake.h" +#include "decode-events.h" #include "util-decode-der.h" #include "util-decode-der-get.h" - #include "util-crypt.h" #define SSLV3_RECORD_LEN 5 -static void TLSCertificateErrCodeToWarning(SSLState *ssl_state, uint32_t errcode) +static void TLSCertificateErrCodeToWarning(SSLState *ssl_state, + uint32_t errcode) { if (errcode == 0) return; @@ -83,7 +81,8 @@ static void TLSCertificateErrCodeToWarning(SSLState *ssl_state, uint32_t errcode }; } -int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uint32_t input_len) +int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, + uint32_t input_len) { uint32_t certificates_length, cur_cert_length; int i; @@ -126,20 +125,25 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin } if (input - start_data + cur_cert_length > input_len) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_CERTIFICATE); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_CERTIFICATE); return -1; } + cert = DecodeDer(input, cur_cert_length, &errcode); if (cert == NULL) { TLSCertificateErrCodeToWarning(ssl_state, errcode); } + if (cert != NULL) { rc = Asn1DerGetSubjectDN(cert, buffer, sizeof(buffer), &errcode); + if (rc != 0) { TLSCertificateErrCodeToWarning(ssl_state, errcode); } else { SSLCertsChain *ncert; //SCLogInfo("TLS Cert %d: %s\n", i, buffer); + if (i == 0) { if (ssl_state->server_connp.cert0_subject == NULL) ssl_state->server_connp.cert0_subject = SCStrdup(buffer); @@ -148,16 +152,19 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin return -1; } } + ncert = (SSLCertsChain *)SCMalloc(sizeof(SSLCertsChain)); if (ncert == NULL) { DerFree(cert); return -1; } + memset(ncert, 0, sizeof(*ncert)); ncert->cert_data = input; ncert->cert_len = cur_cert_length; TAILQ_INSERT_TAIL(&ssl_state->server_connp.certs, ncert, next); } + rc = Asn1DerGetIssuerDN(cert, buffer, sizeof(buffer), &errcode); if (rc != 0) { TLSCertificateErrCodeToWarning(ssl_state, errcode); @@ -172,6 +179,7 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin } } } + DerFree(cert); if (i == 0 && ssl_state->server_connp.cert0_fingerprint == NULL) { @@ -188,7 +196,8 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin // TODO maybe an event here? } else { for (j = 0; j < hash_len; j++, p += 3) { - snprintf(p, 4, j == hash_len - 1 ? "%02x" : "%02x:", hash[j]); + snprintf(p, 4, j == hash_len - 1 ? "%02x" : "%02x:", + hash[j]); } SCFree(hash); ssl_state->server_connp.cert0_fingerprint = SCStrdup(out); @@ -200,7 +209,6 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin ssl_state->server_connp.cert_input = input; ssl_state->server_connp.cert_input_len = cur_cert_length; } - } i++; @@ -210,6 +218,5 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin } return parsed; - } From e117461d4bc02bc7e0e84850e9309629c1f3c07c Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 1 Apr 2016 19:27:37 +0200 Subject: [PATCH 1248/2553] app-layer-ssl: code cleanup --- src/app-layer-ssl.c | 470 ++++++++++++++++++++++++++------------------ 1 file changed, 284 insertions(+), 186 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 6934586e1741..44b4f579290b 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -28,9 +28,6 @@ #include "decode.h" #include "threads.h" -#include "util-print.h" -#include "util-pool.h" - #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" @@ -40,7 +37,6 @@ #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-ssl.h" - #include "app-layer-tls-handshake.h" #include "decode-events.h" @@ -49,11 +45,12 @@ #include "util-spm.h" #include "util-unittest.h" #include "util-debug.h" +#include "util-print.h" +#include "util-pool.h" +#include "util-byte.h" #include "flow-util.h" #include "flow-private.h" -#include "util-byte.h" - SCEnumCharMap tls_decoder_event_table[ ] = { /* TLS protocol messages */ { "INVALID_SSLV2_HEADER", TLS_DECODER_EVENT_INVALID_SSLV2_HEADER }, @@ -68,7 +65,7 @@ SCEnumCharMap tls_decoder_event_table[ ] = { { "MULTIPLE_SNI_EXTENSIONS", TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS }, { "INVALID_SNI_TYPE", TLS_DECODER_EVENT_INVALID_SNI_TYPE }, { "INVALID_SNI_LENGTH", TLS_DECODER_EVENT_INVALID_SNI_LENGTH }, - /* Certificates decoding messages */ + /* certificate decoding messages */ { "INVALID_CERTIFICATE", TLS_DECODER_EVENT_INVALID_CERTIFICATE }, { "CERTIFICATE_MISSING_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT }, { "CERTIFICATE_UNKNOWN_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_UNKNOWN_ELEMENT }, @@ -87,47 +84,47 @@ typedef struct SslConfig_ { SslConfig ssl_config; /* SSLv3 record types */ -#define SSLV3_CHANGE_CIPHER_SPEC 20 -#define SSLV3_ALERT_PROTOCOL 21 -#define SSLV3_HANDSHAKE_PROTOCOL 22 -#define SSLV3_APPLICATION_PROTOCOL 23 -#define SSLV3_HEARTBEAT_PROTOCOL 24 +#define SSLV3_CHANGE_CIPHER_SPEC 20 +#define SSLV3_ALERT_PROTOCOL 21 +#define SSLV3_HANDSHAKE_PROTOCOL 22 +#define SSLV3_APPLICATION_PROTOCOL 23 +#define SSLV3_HEARTBEAT_PROTOCOL 24 /* SSLv3 handshake protocol types */ -#define SSLV3_HS_HELLO_REQUEST 0 -#define SSLV3_HS_CLIENT_HELLO 1 -#define SSLV3_HS_SERVER_HELLO 2 -#define SSLV3_HS_NEW_SESSION_TICKET 4 -#define SSLV3_HS_CERTIFICATE 11 -#define SSLV3_HS_SERVER_KEY_EXCHANGE 12 -#define SSLV3_HS_CERTIFICATE_REQUEST 13 -#define SSLV3_HS_SERVER_HELLO_DONE 14 -#define SSLV3_HS_CERTIFICATE_VERIFY 15 -#define SSLV3_HS_CLIENT_KEY_EXCHANGE 16 -#define SSLV3_HS_FINISHED 20 -#define SSLV3_HS_CERTIFICATE_URL 21 -#define SSLV3_HS_CERTIFICATE_STATUS 22 +#define SSLV3_HS_HELLO_REQUEST 0 +#define SSLV3_HS_CLIENT_HELLO 1 +#define SSLV3_HS_SERVER_HELLO 2 +#define SSLV3_HS_NEW_SESSION_TICKET 4 +#define SSLV3_HS_CERTIFICATE 11 +#define SSLV3_HS_SERVER_KEY_EXCHANGE 12 +#define SSLV3_HS_CERTIFICATE_REQUEST 13 +#define SSLV3_HS_SERVER_HELLO_DONE 14 +#define SSLV3_HS_CERTIFICATE_VERIFY 15 +#define SSLV3_HS_CLIENT_KEY_EXCHANGE 16 +#define SSLV3_HS_FINISHED 20 +#define SSLV3_HS_CERTIFICATE_URL 21 +#define SSLV3_HS_CERTIFICATE_STATUS 22 /* SSLv2 protocol message types */ -#define SSLV2_MT_ERROR 0 -#define SSLV2_MT_CLIENT_HELLO 1 -#define SSLV2_MT_CLIENT_MASTER_KEY 2 -#define SSLV2_MT_CLIENT_FINISHED 3 -#define SSLV2_MT_SERVER_HELLO 4 -#define SSLV2_MT_SERVER_VERIFY 5 -#define SSLV2_MT_SERVER_FINISHED 6 -#define SSLV2_MT_REQUEST_CERTIFICATE 7 -#define SSLV2_MT_CLIENT_CERTIFICATE 8 - -#define SSLV3_RECORD_HDR_LEN 5 -#define SSLV3_MESSAGE_HDR_LEN 4 - -#define SSLV3_CLIENT_HELLO_VERSION_LEN 2 -#define SSLV3_CLIENT_HELLO_RANDOM_LEN 32 +#define SSLV2_MT_ERROR 0 +#define SSLV2_MT_CLIENT_HELLO 1 +#define SSLV2_MT_CLIENT_MASTER_KEY 2 +#define SSLV2_MT_CLIENT_FINISHED 3 +#define SSLV2_MT_SERVER_HELLO 4 +#define SSLV2_MT_SERVER_VERIFY 5 +#define SSLV2_MT_SERVER_FINISHED 6 +#define SSLV2_MT_REQUEST_CERTIFICATE 7 +#define SSLV2_MT_CLIENT_CERTIFICATE 8 + +#define SSLV3_RECORD_HDR_LEN 5 +#define SSLV3_MESSAGE_HDR_LEN 4 + +#define SSLV3_CLIENT_HELLO_VERSION_LEN 2 +#define SSLV3_CLIENT_HELLO_RANDOM_LEN 32 /* TLS heartbeat protocol types */ -#define TLS_HB_REQUEST 1 -#define TLS_HB_RESPONSE 2 +#define TLS_HB_REQUEST 1 +#define TLS_HB_RESPONSE 2 #define HAS_SPACE(n) ((uint32_t)((input) + (n) - (initial_input)) > (uint32_t)(input_len)) ? 0 : 1 @@ -291,16 +288,23 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, case SSLV3_HS_CERTIFICATE: if (ssl_state->curr_connp->trec == NULL) { - ssl_state->curr_connp->trec_len = 2 * ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN + 1; - ssl_state->curr_connp->trec = SCMalloc( ssl_state->curr_connp->trec_len ); + ssl_state->curr_connp->trec_len = + 2 * ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN + 1; + ssl_state->curr_connp->trec = + SCMalloc(ssl_state->curr_connp->trec_len); } - if (ssl_state->curr_connp->trec_pos + input_len >= ssl_state->curr_connp->trec_len) { - ssl_state->curr_connp->trec_len = ssl_state->curr_connp->trec_len + 2 * input_len + 1; + if (ssl_state->curr_connp->trec_pos + input_len >= + ssl_state->curr_connp->trec_len) { + ssl_state->curr_connp->trec_len = + ssl_state->curr_connp->trec_len + 2 * input_len + 1; ptmp = SCRealloc(ssl_state->curr_connp->trec, - ssl_state->curr_connp->trec_len); + ssl_state->curr_connp->trec_len); + if (unlikely(ptmp == NULL)) { SCFree(ssl_state->curr_connp->trec); } + ssl_state->curr_connp->trec = ptmp; } if (unlikely(ssl_state->curr_connp->trec == NULL)) { @@ -312,30 +316,44 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, } uint32_t write_len = 0; - if ((ssl_state->curr_connp->bytes_processed + input_len) > ssl_state->curr_connp->record_length + (SSLV3_RECORD_HDR_LEN)) { - if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + if ((ssl_state->curr_connp->bytes_processed + input_len) > + ssl_state->curr_connp->record_length + + (SSLV3_RECORD_HDR_LEN)) { + if ((ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN) < + ssl_state->curr_connp->bytes_processed) { + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - write_len = (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) - ssl_state->curr_connp->bytes_processed; + write_len = (ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN) - + ssl_state->curr_connp->bytes_processed; } else { write_len = input_len; } - memcpy(ssl_state->curr_connp->trec + ssl_state->curr_connp->trec_pos, initial_input, write_len); + + memcpy(ssl_state->curr_connp->trec + + ssl_state->curr_connp->trec_pos, initial_input, write_len); ssl_state->curr_connp->trec_pos += write_len; - rc = DecodeTLSHandshakeServerCertificate(ssl_state, ssl_state->curr_connp->trec, ssl_state->curr_connp->trec_pos); + rc = DecodeTLSHandshakeServerCertificate(ssl_state, + ssl_state->curr_connp->trec, + ssl_state->curr_connp->trec_pos); + if (rc > 0) { /* do not return normally if the packet was fragmented: - * we would return the size of the *entire* message, - * while we expect only the number of bytes parsed bytes - * from the *current* fragment - */ + we would return the size of the _entire_ message, + while we expect only the number of bytes parsed bytes + from the _current_ fragment */ if (write_len < (ssl_state->curr_connp->trec_pos - rc)) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - uint32_t diff = write_len - (ssl_state->curr_connp->trec_pos - rc); + + uint32_t diff = write_len - + (ssl_state->curr_connp->trec_pos - rc); ssl_state->curr_connp->bytes_processed += diff; ssl_state->curr_connp->trec_pos = 0; @@ -362,28 +380,40 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, SCLogDebug("new session ticket"); break; default: - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } uint32_t write_len = 0; - if ((ssl_state->curr_connp->bytes_processed + input_len) >= ssl_state->curr_connp->record_length + (SSLV3_RECORD_HDR_LEN)) { - if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + if ((ssl_state->curr_connp->bytes_processed + input_len) >= + ssl_state->curr_connp->record_length + (SSLV3_RECORD_HDR_LEN)) { + if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < + ssl_state->curr_connp->bytes_processed) { + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - write_len = (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) - ssl_state->curr_connp->bytes_processed; + write_len = (ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN) - ssl_state->curr_connp->bytes_processed; } else { write_len = input_len; } - if ((ssl_state->curr_connp->trec_pos + write_len) >= ssl_state->curr_connp->message_length) { - if (ssl_state->curr_connp->message_length < ssl_state->curr_connp->trec_pos) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + + if ((ssl_state->curr_connp->trec_pos + write_len) >= + ssl_state->curr_connp->message_length) { + if (ssl_state->curr_connp->message_length < + ssl_state->curr_connp->trec_pos) { + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - parsed += ssl_state->curr_connp->message_length - ssl_state->curr_connp->trec_pos; + parsed += ssl_state->curr_connp->message_length - + ssl_state->curr_connp->trec_pos; - ssl_state->curr_connp->bytes_processed += ssl_state->curr_connp->message_length - ssl_state->curr_connp->trec_pos; + ssl_state->curr_connp->bytes_processed += + ssl_state->curr_connp->message_length - + ssl_state->curr_connp->trec_pos; ssl_state->curr_connp->handshake_type = 0; ssl_state->curr_connp->hs_bytes_processed = 0; @@ -405,10 +435,8 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, uint8_t *input, uint8_t *initial_input = input; int retval; - if (input_len == 0 || - ssl_state->curr_connp->bytes_processed == - (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) - { + if (input_len == 0 || ssl_state->curr_connp->bytes_processed == + (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) { return 0; } @@ -417,40 +445,41 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, uint8_t *input, ssl_state->curr_connp->handshake_type = *(input++); ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; - if (--input_len == 0 || - ssl_state->curr_connp->bytes_processed == - (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) - { + if (--input_len == 0 || ssl_state->curr_connp->bytes_processed == + (ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN)) { return (input - initial_input); } + /* fall through */ case 1: ssl_state->curr_connp->message_length = *(input++) << 16; ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; - if (--input_len == 0 || - ssl_state->curr_connp->bytes_processed == - (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) - { + if (--input_len == 0 || ssl_state->curr_connp->bytes_processed == + (ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN)) { return (input - initial_input); } + /* fall through */ case 2: ssl_state->curr_connp->message_length |= *(input++) << 8; ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; - if (--input_len == 0 || - ssl_state->curr_connp->bytes_processed == - (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) - { + if (--input_len == 0 || ssl_state->curr_connp->bytes_processed == + (ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN)) { return (input - initial_input); } + /* fall through */ case 3: ssl_state->curr_connp->message_length |= *(input++); ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; --input_len; + /* fall through */ } @@ -458,6 +487,7 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, uint8_t *input, if (retval < 0) { return retval; } + input += retval; return (input - initial_input); @@ -468,7 +498,7 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, uint8_t *input, * \brief TLS Heartbeat parser (see RFC 6520) * * \param sslstate Pointer to the SSL state. - * \param input Pointer the received input data. + * \param input Pointer to the received input data. * \param input_len Length in bytes of the received data. * \param direction 1 toclient, 0 toserver * @@ -481,10 +511,11 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input, uint16_t payload_len; uint16_t padding_len; - // expect at least 3 bytes, heartbeat type (1) + length (2) + /* expect at least 3 bytes: heartbeat type (1) + length (2) */ if (input_len < 3) { return 0; } + hb_type = *input++; if (!(ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { @@ -499,73 +530,80 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input, ssl_state->flags |= SSL_AL_FLAG_HB_INFLIGHT; if (direction) { + SCLogDebug("HeartBeat Record type sent in the toclient direction!"); ssl_state->flags |= SSL_AL_FLAG_HB_SERVER_INIT; - SCLogDebug("HeartBeat Record type sent in the toclient " - "direction!"); } else { + SCLogDebug("HeartBeat Record type sent in the toserver direction!"); ssl_state->flags |= SSL_AL_FLAG_HB_CLIENT_INIT; - SCLogDebug("HeartBeat Record type sent in the toserver " - "direction!"); } - /* if we reach this poin then can we assume that the HB request - * is encrypted if so lets set the heartbeat record len */ + + /* if we reach this point, then we can assume that the HB request + is encrypted. If so, let's set the HB record length */ if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) { ssl_state->hb_record_len = ssl_state->curr_connp->record_length; - SCLogDebug("Encrypted HeartBeat Request In-flight. Storing len %u", ssl_state->hb_record_len); + SCLogDebug("Encrypted HeartBeat Request In-flight. Storing len %u", + ssl_state->hb_record_len); return (ssl_state->curr_connp->record_length - 3); } payload_len = (*input++) << 8; payload_len |= (*input++); - // check that the requested payload length is really present in record (CVE-2014-0160) + /* check that the requested payload length is really present in + the record (CVE-2014-0160) */ if ((uint32_t)(payload_len+3) > ssl_state->curr_connp->record_length) { SCLogDebug("We have a short record in HeartBeat Request"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT); return -1; } - // check the padding length - // it must be at least 16 bytes (RFC 6520, section 4) + /* check the padding length. It must be at least 16 bytes + (RFC 6520, section 4) */ padding_len = ssl_state->curr_connp->record_length - payload_len - 3; if (padding_len < 16) { SCLogDebug("We have a short record in HeartBeat Request"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HEARTBEAT); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; } - if (input_len < payload_len+padding_len) { // we don't have the payload + /* we don't have the payload */ + if (input_len < payload_len + padding_len) { return 0; } /* OpenSSL still seems to discard multiple in-flight - * heartbeats although some tools send multiple at once */ + heartbeats although some tools send multiple at once */ } else if (direction == 1 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && (ssl_state->flags & SSL_AL_FLAG_HB_SERVER_INIT)) { - SCLogDebug("Multiple In-Flight Server Intiated HeartBeats"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HEARTBEAT); + SCLogDebug("Multiple in-flight server initiated HeartBeats"); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; + } else if (direction == 0 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && (ssl_state->flags & SSL_AL_FLAG_HB_CLIENT_INIT)) { - SCLogDebug("Multiple In-Flight Client Intiated HeartBeats"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HEARTBEAT); + SCLogDebug("Multiple in-flight client initiated HeartBeats"); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; + } else { - /* we have a HB record in the opposite direction of the request - * lets reset our flags */ + /* we have a HB record in the opposite direction of the request, + let's reset our flags */ ssl_state->flags &= ~SSL_AL_FLAG_HB_INFLIGHT; ssl_state->flags &= ~SSL_AL_FLAG_HB_SERVER_INIT; ssl_state->flags &= ~SSL_AL_FLAG_HB_CLIENT_INIT; - /* if we reach this poin then can we assume that the HB request is - *encrypted if so lets set the heartbeat record len */ + /* if we reach this point, then we can assume that the HB request + is encrypted. If so, let's set the HB record length */ if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) { /* check to see if the encrypted response is longer than the - * encrypted request */ - if (ssl_state->hb_record_len > 0 && - ssl_state->hb_record_len < ssl_state->curr_connp->record_length) - { - SCLogDebug("My Heart It's Bleeding.. OpenSSL HeartBleed Response (%u)", + encrypted request */ + if (ssl_state->hb_record_len > 0 && ssl_state->hb_record_len < + ssl_state->curr_connp->record_length) { + SCLogDebug("My heart is bleeding.. OpenSSL HeartBleed response (%u)", ssl_state->hb_record_len); AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH); @@ -573,11 +611,14 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input, return -1; } } - /* reset the hb record len in-case we have legit hb's followed by a bad one */ + + /* reset the HB record length in case we have a legit HB followed + by a bad one */ ssl_state->hb_record_len = 0; } - /* skip the heartbeat, 3 bytes were already parsed, e.g |18 03 02| for TLS 1.2 */ + /* skip the HeartBeat, 3 bytes were already parsed, + e.g |18 03 02| for TLS 1.2 */ return (ssl_state->curr_connp->record_length - 3); } @@ -605,28 +646,33 @@ static int SSLv3ParseRecord(uint8_t direction, SSLState *ssl_state, if (--input_len == 0) break; } + /* fall through */ case 1: ssl_state->curr_connp->version = *(input++) << 8; if (--input_len == 0) break; + /* fall through */ case 2: ssl_state->curr_connp->version |= *(input++); if (--input_len == 0) break; + /* fall through */ case 3: ssl_state->curr_connp->record_length = *(input++) << 8; if (--input_len == 0) break; + /* fall through */ case 4: ssl_state->curr_connp->record_length |= *(input++); if (--input_len == 0) break; + /* fall through */ - } /* switch (ssl_state->curr_connp->bytes_processed) */ + } ssl_state->curr_connp->bytes_processed += (input - initial_input); @@ -662,14 +708,16 @@ static int SSLv2ParseRecord(uint8_t direction, SSLState *ssl_state, ssl_state->curr_connp->record_length |= *(input++); if (--input_len == 0) break; + /* fall through */ case 2: ssl_state->curr_connp->content_type = *(input++); ssl_state->curr_connp->version = SSL_VERSION_2; if (--input_len == 0) break; + /* fall through */ - } /* switch (ssl_state->curr_connp->bytes_processed) */ + } } else { switch (ssl_state->curr_connp->bytes_processed) { @@ -685,6 +733,7 @@ static int SSLv2ParseRecord(uint8_t direction, SSLState *ssl_state, if (--input_len == 0) break; } + /* fall through */ case 1: ssl_state->curr_connp->record_length |= *(input++); @@ -704,8 +753,9 @@ static int SSLv2ParseRecord(uint8_t direction, SSLState *ssl_state, ssl_state->curr_connp->version = SSL_VERSION_2; if (--input_len == 0) break; + /* fall through */ - } /* switch (ssl_state->curr_connp->bytes_processed) */ + } } ssl_state->curr_connp->bytes_processed += (input - initial_input); @@ -728,12 +778,14 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, } } - /* the + 1 because, we also read one extra byte inside SSLv2ParseRecord - * to read the msg_type */ - if (ssl_state->curr_connp->bytes_processed < (ssl_state->curr_connp->record_lengths_length + 1)) { + /* the +1 is because we read one extra byte inside SSLv2ParseRecord + to read the msg_type */ + if (ssl_state->curr_connp->bytes_processed < + (ssl_state->curr_connp->record_lengths_length + 1)) { retval = SSLv2ParseRecord(direction, ssl_state, input, input_len); if (retval == -1) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); return -1; } else { input += retval; @@ -745,26 +797,28 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, return (input - initial_input); } - /* record_length should never be 0 */ + /* record_length should never be zero */ if (ssl_state->curr_connp->record_length == 0) { - SCLogDebug("SSLv2 record length is 0"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + SCLogDebug("SSLv2 record length is zero"); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); return -1; } - /* record_lenghts_length should never be 0 */ + /* record_lenghts_length should never be zero */ if (ssl_state->curr_connp->record_lengths_length == 0) { - SCLogDebug("SSLv2 record lengths length is 0"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + SCLogDebug("SSLv2 record lengths length is zero"); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); return -1; } switch (ssl_state->curr_connp->content_type) { case SSLV2_MT_ERROR: - SCLogDebug("SSLV2_MT_ERROR msg_type received. " - "Error encountered in establishing the sslv2 " - "session, may be version"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED); + SCLogDebug("SSLV2_MT_ERROR msg_type received. Error encountered " + "in establishing the sslv2 session, may be version"); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED); break; @@ -784,6 +838,7 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, if (ssl_state->curr_connp->session_id_length == 0) { ssl_state->flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; } + break; } else { input++; @@ -791,40 +846,45 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, if (--input_len == 0) break; } + /* fall through */ case 5: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + /* fall through */ case 6: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + /* fall through */ case 7: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + /* fall through */ case 8: ssl_state->curr_connp->session_id_length = *(input++) << 8; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + /* fall through */ case 9: ssl_state->curr_connp->session_id_length |= *(input++); ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + /* fall through */ - } /* switch (ssl_state->curr_connp->bytes_processed) */ + } - /* ssl_state->curr_connp->record_lengths_length is 3 */ } else { switch (ssl_state->curr_connp->bytes_processed) { case 3: @@ -837,6 +897,7 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, if (ssl_state->curr_connp->session_id_length == 0) { ssl_state->flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; } + break; } else { input++; @@ -844,41 +905,47 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, if (--input_len == 0) break; } + case 4: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + case 5: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + case 6: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + case 7: ssl_state->curr_connp->session_id_length = *(input++) << 8; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + case 8: ssl_state->curr_connp->session_id_length |= *(input++); ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; - } /* switch (ssl_state->curr_connp->bytes_processed) */ - } /* else - if (ssl_state->curr_connp->record_lengths_length == 3) */ + } + } break; case SSLV2_MT_CLIENT_MASTER_KEY: - if ( !(ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS)) { + if (!(ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS)) { SCLogDebug("Client hello is not seen before master key " - "message!!"); + "message!"); } + ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY; break; @@ -890,20 +957,23 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, } else { ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_KEYX; } + /* fall through */ case SSLV2_MT_SERVER_VERIFY: case SSLV2_MT_SERVER_FINISHED: if (direction == 0 && - !(ssl_state->curr_connp->content_type & SSLV2_MT_CLIENT_CERTIFICATE)) { + !(ssl_state->curr_connp->content_type & + SSLV2_MT_CLIENT_CERTIFICATE)) { SCLogDebug("Incorrect SSL Record type sent in the toserver " "direction!"); } + /* fall through */ case SSLV2_MT_CLIENT_FINISHED: case SSLV2_MT_REQUEST_CERTIFICATE: - /* both ways hello seen */ + /* both client hello and server hello must be seen */ if ((ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) && - (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_HS)) { + (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_HS)) { if (direction == 0) { if (ssl_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) { @@ -919,11 +989,12 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, } if ((ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED) && - (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED)) { + (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED)) { AppLayerParserStateSetFlag(pstate, - APP_LAYER_PARSER_NO_INSPECTION); + APP_LAYER_PARSER_NO_INSPECTION); if (ssl_config.no_reassemble == 1) - AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY); + AppLayerParserStateSetFlag(pstate, + APP_LAYER_PARSER_NO_REASSEMBLY); SCLogDebug("SSLv2 No reassembly & inspection has been set"); } } @@ -938,16 +1009,19 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, } if (input_len + ssl_state->curr_connp->bytes_processed >= - (ssl_state->curr_connp->record_length + ssl_state->curr_connp->record_lengths_length)) { - /* looks like we have another record after this*/ + (ssl_state->curr_connp->record_length + + ssl_state->curr_connp->record_lengths_length)) { + + /* looks like we have another record after this */ uint32_t diff = ssl_state->curr_connp->record_length + - ssl_state->curr_connp->record_lengths_length + - ssl_state->curr_connp->bytes_processed; + ssl_state->curr_connp->record_lengths_length + - + ssl_state->curr_connp->bytes_processed; input += diff; SSLParserReset(ssl_state); return (input - initial_input); - /* we still don't have the entire record for the one we are - * currently parsing */ + /* we still don't have the entire record for the one we are + currently parsing */ } else { input += input_len; ssl_state->curr_connp->bytes_processed += input_len; @@ -965,7 +1039,8 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, if (ssl_state->curr_connp->bytes_processed < SSLV3_RECORD_HDR_LEN) { retval = SSLv3ParseRecord(direction, ssl_state, input, input_len); if (retval < 0) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_TLS_HEADER); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_TLS_HEADER); return -1; } else { parsed += retval; @@ -979,17 +1054,18 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, /* check record version */ if (ssl_state->curr_connp->version < SSL_VERSION_3 || - ssl_state->curr_connp->version > TLS_VERSION_12) { + ssl_state->curr_connp->version > TLS_VERSION_12) { AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_RECORD_VERSION); return -1; } - /* record_length should never be 0 */ + /* record_length should never be zero */ if (ssl_state->curr_connp->record_length == 0) { SCLogDebug("SSLv3 Record length is 0"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_TLS_HEADER); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_TLS_HEADER); return -1; } @@ -1008,15 +1084,17 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, case SSLV3_ALERT_PROTOCOL: break; + case SSLV3_APPLICATION_PROTOCOL: if ((ssl_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) && - (ssl_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC)) { + (ssl_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC)) { /* AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION); if (ssl_config.no_reassemble == 1) AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY); */ - AppLayerParserStateSetFlag(pstate,APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD); + AppLayerParserStateSetFlag(pstate, + APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD); } break; @@ -1027,26 +1105,34 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, if (ssl_state->curr_connp->record_length < 4) { SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } retval = SSLv3ParseHandshakeProtocol(ssl_state, input + parsed, input_len); if (retval < 0) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { if ((uint32_t)retval > input_len) { - SCLogDebug("Error parsing SSLv3.x. Reseting parser " - "state. Let's get outta here"); + SCLogDebug("Error parsing SSLv3.x. Reseting parser " + "state. Let's get outta here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } + parsed += retval; input_len -= retval; - if (ssl_state->curr_connp->bytes_processed == ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { + + if (ssl_state->curr_connp->bytes_processed == + ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN) { SSLParserReset(ssl_state); } @@ -1056,23 +1142,31 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, } break; + case SSLV3_HEARTBEAT_PROTOCOL: - retval = SSLv3ParseHeartbeatProtocol(ssl_state, input + parsed, input_len, direction); + retval = SSLv3ParseHeartbeatProtocol(ssl_state, input + parsed, + input_len, direction); if (retval < 0) return -1; + break; default: /* \todo fix the event from invalid rule to unknown rule */ - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_RECORD_TYPE); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_RECORD_TYPE); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - if (input_len + ssl_state->curr_connp->bytes_processed >= ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { - if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { - /* defensive checks. Something's wrong. */ - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + if (input_len + ssl_state->curr_connp->bytes_processed >= + ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { + if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < + ssl_state->curr_connp->bytes_processed) { + /* defensive checks. Something is wrong. */ + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } @@ -1080,13 +1174,14 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, AppLayerParserTriggerRawStreamReassembly(ssl_state->f); /* looks like we have another record */ - uint32_t diff = ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN - ssl_state->curr_connp->bytes_processed; + uint32_t diff = ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN - ssl_state->curr_connp->bytes_processed; parsed += diff; SSLParserReset(ssl_state); return parsed; - /* we still don't have the entire record for the one we are - * currently parsing */ + /* we still don't have the entire record for the one we are + currently parsing */ } else { parsed += input_len; ssl_state->curr_connp->bytes_processed += input_len; @@ -1126,7 +1221,8 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt ssl_state->f = f; - if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + if (input == NULL && + AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); } else if (input == NULL || input_len == 0) { SCReturnInt(-1); @@ -1140,16 +1236,16 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt /* if we have more than one record */ while (input_len > 0) { if (counter++ == 30) { - SCLogDebug("Looks like we have looped quite a bit. Reset state " + SCLogDebug("Looks like we have looped quite a bit. Reset state " "and get out of here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - /* ssl_state->bytes_processed is 0 for a - * fresh record or positive to indicate a record currently being - * parsed */ + /* ssl_state->bytes_processed is zero for a fresh record or + positive to indicate a record currently being parsed */ switch (ssl_state->curr_connp->bytes_processed) { /* fresh record */ case 0: @@ -1160,10 +1256,11 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt retval = SSLv2Decode(direction, ssl_state, pstate, input, input_len); if (retval < 0) { - SCLogDebug("Error parsing SSLv2.x. Reseting parser " - "state. Let's get outta here"); + SCLogDebug("Error parsing SSLv2.x. Reseting parser " + "state. Let's get outta here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { input_len -= retval; @@ -1172,15 +1269,16 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt } else { SCLogDebug("SSLv3.x detected"); /* we will keep it this way till our record parser tells - * us what exact version it is */ + us what exact version this is */ ssl_state->curr_connp->version = TLS_VERSION_UNKNOWN; retval = SSLv3Decode(direction, ssl_state, pstate, input, input_len); if (retval < 0) { - SCLogDebug("Error parsing SSLv3.x. Reseting parser " - "state. Let's get outta here"); + SCLogDebug("Error parsing SSLv3.x. Reseting parser " + "state. Let's get outta here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + AppLayerDecoderEventsSetEvent(ssl_state->f, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { input_len -= retval; From a985b450e347b84ea7f53a4fbdd37c2da80a5d1c Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Sat, 2 Apr 2016 12:09:55 +0200 Subject: [PATCH 1249/2553] util-decode-der: code cleanup --- src/util-decode-der.c | 255 ++++++++++++++++++++++++++++++------------ 1 file changed, 186 insertions(+), 69 deletions(-) diff --git a/src/util-decode-der.c b/src/util-decode-der.c index 040e214b405c..f97497665f77 100644 --- a/src/util-decode-der.c +++ b/src/util-decode-der.c @@ -49,19 +49,45 @@ #define MAX_OID_LENGTH 256 -static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); static Asn1Generic * Asn1GenericNew(void) { @@ -98,7 +124,9 @@ static int Asn1SequenceAppend(Asn1Generic *seq, Asn1Generic *node) return 0; } -static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t max_size, uint8_t depth, int seq_index, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + int seq_index, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t numbytes, el_max_size; @@ -119,23 +147,26 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t switch (el.cls) { case ASN1_CLASS_CONTEXTSPEC: - /* get element type from definition - * see http://www.ietf.org/rfc/rfc3280.txt) - */ + /* get element type from definition, see: + http://www.ietf.org/rfc/rfc3280.txt */ if (depth == 2 && el.tag == 0) { - el_type = ASN1_SEQUENCE; /* TBSCertificate */ + /* TBSCertificate */ + el_type = ASN1_SEQUENCE; break; } if (depth == 2 && el.tag == 1) { - el_type = ASN1_BITSTRING; /* issuerUniqueID */ + /* issuerUniqueID */ + el_type = ASN1_BITSTRING; break; } if (depth == 2 && el.tag == 2) { - el_type = ASN1_BITSTRING; /* subjectUniqueID */ + /* subjectUniqueID */ + el_type = ASN1_BITSTRING; break; } if (depth == 2 && el.tag == 3) { - el_type = ASN1_SEQUENCE; /* extensions */ + /* extensions */ + el_type = ASN1_SEQUENCE; break; } /* unknown context specific value - do not decode */ @@ -154,22 +185,27 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t child = DecodeAsn1DerNull(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_BITSTRING: - child = DecodeAsn1DerBitstring(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerBitstring(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_OID: child = DecodeAsn1DerOid(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_IA5STRING: - child = DecodeAsn1DerIA5String(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerIA5String(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_OCTETSTRING: - child = DecodeAsn1DerOctetString(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerOctetString(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_UTF8STRING: - child = DecodeAsn1DerUTF8String(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerUTF8String(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_PRINTSTRING: - child = DecodeAsn1DerPrintableString(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerPrintableString(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_SEQUENCE: child = DecodeAsn1DerSequence(d_ptr, el_max_size, depth+1, errcode); @@ -178,7 +214,8 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t child = DecodeAsn1DerSet(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_T61STRING: - child = DecodeAsn1DerT61String(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerT61String(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_UTCTIME: child = DecodeAsn1DerUTCTime(d_ptr, el_max_size, depth+1, errcode); @@ -189,15 +226,20 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t child = Asn1GenericNew(); if (child == NULL) break; + child->type = el.tag; + /* total sequence length */ const unsigned char * save_d_ptr = d_ptr; d_ptr++; c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { child->length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; if (numbytes > el_max_size) { SCFree(child); @@ -212,9 +254,9 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t d_ptr++; } } - /* fix the length for unknown objects, else - * sequence parsing will fail - */ + + /* fix the length for unknown objects, else sequence parsing + will fail */ child->length += (d_ptr - save_d_ptr); if (child->length > max_size - (d_ptr - buffer)) { @@ -224,6 +266,7 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t break; }; + if (child == NULL) return NULL; @@ -231,7 +274,9 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t return child; } -static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint8_t numbytes; @@ -250,6 +295,7 @@ static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t d_ptr += 2; value = 0; + /* Here we need to ensure that numbytes is less than 4 so integer affectation is possible. We set the value to 0xffffffff which is by convention the unknown value. @@ -265,6 +311,7 @@ static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_INTEGER; a->length = (d_ptr - buffer) + numbytes; a->value = value; @@ -274,21 +321,25 @@ static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t SCFree(a); return NULL; } + for (i=0; istr + 2*i, 2*(numbytes-i)+1, "%02X", d_ptr[i]); } - a->str[2*numbytes]='\0'; + a->str[2*numbytes]= '\0'; return a; } -static int DecodeAsn1BuildValue(const unsigned char **d_ptr, uint32_t *val, uint8_t numbytes, uint32_t *errcode) +static int DecodeAsn1BuildValue(const unsigned char **d_ptr, uint32_t *val, + uint8_t numbytes, uint32_t *errcode) { int i; uint32_t value = 0; + if (numbytes > 4) { if (errcode) *errcode = ERR_DER_INVALID_SIZE; + /* too big won't fit: set it to 0xffffffff by convention */ value = 0xffffffff; *val = value; @@ -299,11 +350,14 @@ static int DecodeAsn1BuildValue(const unsigned char **d_ptr, uint32_t *val, uint (*d_ptr)++; } } + *val = value; return 0; } -static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint8_t numbytes; @@ -316,9 +370,11 @@ static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, uint32_t if (DecodeAsn1BuildValue(&d_ptr, &value, numbytes, errcode) == -1) { return NULL; } + a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_BOOLEAN; a->length = (d_ptr - buffer); a->value = value; @@ -326,7 +382,9 @@ static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, uint32_t return a; } -static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint8_t numbytes; @@ -335,12 +393,15 @@ static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, uint32_t siz numbytes = d_ptr[1]; d_ptr += 2; + if (DecodeAsn1BuildValue(&d_ptr, &value, numbytes, errcode) == -1) { return NULL; } + a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_NULL; a->length = (d_ptr - buffer); a->value = 0; @@ -348,7 +409,9 @@ static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, uint32_t siz return a; } -static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length; @@ -359,24 +422,29 @@ static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, uint32_ /* size */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } + if (length > max_size) return NULL; a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_BITSTRING; a->strlen = length; + a->str = SCMalloc(length); if (a->str == NULL) { SCFree(a); @@ -390,7 +458,9 @@ static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, uint32_ return a; } -static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t oid_length, oid_value; @@ -402,23 +472,28 @@ static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t max_ /* size */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { oid_length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &oid_length, numbytes, errcode) == -1) { return NULL; } } + if (oid_length > max_size) return NULL; a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_OID; + a->str = SCMalloc(MAX_OID_LENGTH); if (a->str == NULL) { SCFree(a); @@ -429,8 +504,8 @@ static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t max_ snprintf(a->str, MAX_OID_LENGTH, "%d.%d", (d_ptr[0]/40), (d_ptr[0]%40)); d_ptr++; - /* sub-identifiers are multi valued, coded and 7 bits, first bit of the 8bits is used - to indicate, if a new value is starting */ + /* sub-identifiers are multi-valued, coded and 7 bits, first bit of + the 8bits is used to indicate, if a new value is starting */ for (i=1; istr); c = d_ptr[0]; @@ -451,7 +526,9 @@ static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t max_ return a; } -static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length, numbytes; @@ -462,16 +539,19 @@ static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_ /* total sequence length */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } + if (length == UINT32_MAX || length > max_size) { if (errcode) *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; @@ -481,8 +561,10 @@ static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_ a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_IA5STRING; a->strlen = length; + a->str = SCMalloc(length+1); if (a->str == NULL) { SCFree(a); @@ -497,7 +579,9 @@ static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_ return a; } -static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length, numbytes; @@ -508,16 +592,19 @@ static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint3 /* total sequence length */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } + if (length == UINT32_MAX || length > max_size) { if (errcode) *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; @@ -527,10 +614,12 @@ static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint3 a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_OCTETSTRING; a->strlen = length; - /* Add one to the octet string for the 0. This will then - * allow us to use the string in printf */ + + /* add one to the octet string for the 0. This will then allow us to + use the string in printf */ a->str = SCMalloc(length + 1); if (a->str == NULL) { SCFree(a); @@ -545,15 +634,21 @@ static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint3 return a; } -static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { Asn1Generic *a = DecodeAsn1DerOctetString(buffer, max_size, depth, errcode); if (a != NULL) a->type = ASN1_UTF8STRING; + return a; } -static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, + uint32_t max_size, + uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length, numbytes; @@ -564,16 +659,19 @@ static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, u /* total sequence length */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } + if (length == UINT32_MAX || length > max_size) { if (errcode) *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; @@ -583,8 +681,10 @@ static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, u a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_PRINTSTRING; a->strlen = length; + a->str = SCMalloc(length+1); if (a->str == NULL) { SCFree(a); @@ -599,7 +699,9 @@ static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, u return a; } -static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t d_length, parsed_bytes, numbytes, el_max_size; @@ -612,14 +714,17 @@ static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t node = Asn1GenericNew(); if (node == NULL) return NULL; + node->type = ASN1_SEQUENCE; /* total sequence length */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { d_length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) { @@ -642,7 +747,8 @@ static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t while (parsed_bytes < d_length) { el_max_size = max_size - (d_ptr-buffer); - Asn1Generic *child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, seq_index, errcode); + Asn1Generic *child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, + seq_index, errcode); if (child == NULL) { if (errcode && *errcode != 0) { DerFree(node); @@ -660,13 +766,14 @@ static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t parsed_bytes += child->length; d_ptr += child->length; seq_index++; - } return (Asn1Generic *)node; } -static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t d_length, numbytes, el_max_size; @@ -685,10 +792,12 @@ static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_ /* total sequence length */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { d_length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) { @@ -696,6 +805,7 @@ static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_ return NULL; } } + node->length = d_length + (d_ptr - buffer); if (node->length > max_size || node->length < d_length /* wrap */) { @@ -708,6 +818,7 @@ static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_ seq_index = 0; el_max_size = max_size - (d_ptr-buffer); + child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, seq_index, errcode); if (child == NULL) { DerFree(node); @@ -719,7 +830,9 @@ static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_ return (Asn1Generic *)node; } -static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { Asn1Generic *a; @@ -730,7 +843,9 @@ static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, uint32_ return a; } -static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { Asn1Generic *a; @@ -741,7 +856,8 @@ static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, uint32_t return a; } -Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *errcode) +Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t d_length, numbytes; @@ -751,7 +867,7 @@ Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *er if (size < 2) return NULL; - /* Check that buffer is an ASN.1 structure (basic checks) */ + /* check that buffer is an ASN.1 structure (basic checks) */ if (d_ptr[0] != 0x30 && d_ptr[1] != 0x82) /* Sequence */ return NULL; @@ -764,6 +880,7 @@ Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *er if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) { return NULL; } + if (d_length+(d_ptr-buffer) != size) return NULL; From 18f88a6344e3d981da4966d59662d029b2713065 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Sat, 2 Apr 2016 13:44:43 +0200 Subject: [PATCH 1250/2553] util-decode-der-get: code cleanup --- src/util-decode-der-get.c | 40 ++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/util-decode-der-get.c b/src/util-decode-der-get.c index 4323eb39d4ec..1c556c837d4f 100644 --- a/src/util-decode-der-get.c +++ b/src/util-decode-der-get.c @@ -42,31 +42,31 @@ static const uint8_t SEQ_IDX_SUBJECT[] = { 0, 4 }; static const char *Oid2ShortStr(const char *oid) { - if (strcmp(oid, "1.2.840.113549.1.9.1")==0) + if (strcmp(oid, "1.2.840.113549.1.9.1") == 0) return "emailAddress"; - if (strcmp(oid, "2.5.4.3")==0) + if (strcmp(oid, "2.5.4.3") == 0) return "CN"; - if (strcmp(oid, "2.5.4.5")==0) + if (strcmp(oid, "2.5.4.5") == 0) return "serialNumber"; - if (strcmp(oid, "2.5.4.6")==0) + if (strcmp(oid, "2.5.4.6") == 0) return "C"; - if (strcmp(oid, "2.5.4.7")==0) + if (strcmp(oid, "2.5.4.7") == 0) return "L"; - if (strcmp(oid, "2.5.4.8")==0) + if (strcmp(oid, "2.5.4.8") == 0) return "ST"; - if (strcmp(oid, "2.5.4.10")==0) + if (strcmp(oid, "2.5.4.10") == 0) return "O"; - if (strcmp(oid, "2.5.4.11")==0) + if (strcmp(oid, "2.5.4.11") == 0) return "OU"; - if (strcmp(oid, "0.9.2342.19200300.100.1.25")==0) + if (strcmp(oid, "0.9.2342.19200300.100.1.25") == 0) return "DC"; return "unknown"; @@ -78,7 +78,8 @@ static const char *Oid2ShortStr(const char *oid) * * \retval The matching node, or NULL */ -const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, const uint32_t seqsz, uint32_t *errcode) +const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, + const uint32_t seqsz, uint32_t *errcode) { const Asn1Generic * node; uint8_t idx, i; @@ -128,10 +129,12 @@ const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, return node; } -int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode) +int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, + uint32_t *errcode) { const Asn1Generic *node_oid; - const Asn1Generic *node, *it; + const Asn1Generic *node; + const Asn1Generic *it; const Asn1Generic *node_set; const Asn1Generic *node_str; const char *shortname; @@ -143,6 +146,7 @@ int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, u if (length < 10) goto issuer_dn_error; + buffer[0] = '\0'; node = Asn1DerGet(cert, SEQ_IDX_ISSUER, sizeof(SEQ_IDX_ISSUER), errcode); @@ -186,7 +190,7 @@ int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, u goto issuer_dn_error; } - if (strcmp(shortname,"CN")==0) + if (strcmp(shortname,"CN") == 0) separator = "/"; if (it->next != NULL) strlcat(buffer, separator, length); @@ -201,10 +205,12 @@ int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, u return rc; } -int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode) +int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, + uint32_t *errcode) { const Asn1Generic *node_oid; - const Asn1Generic *node, *it; + const Asn1Generic *node; + const Asn1Generic *it; const Asn1Generic *node_set; const Asn1Generic *node_str; const char *shortname; @@ -216,6 +222,7 @@ int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, if (length < 10) goto subject_dn_error; + buffer[0] = '\0'; node = Asn1DerGet(cert, SEQ_IDX_SUBJECT, sizeof(SEQ_IDX_SUBJECT), errcode); @@ -260,7 +267,7 @@ int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, goto subject_dn_error; } - if (strcmp(shortname,"CN")==0) + if (strcmp(shortname,"CN") == 0) separator = "/"; if (it->next != NULL) strlcat(buffer, separator, length); @@ -275,4 +282,3 @@ int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, return rc; } -/* vim: set et ts=4 sw=4: */ From c2f0f82bb4aadf5eaf7bc72f4c990dd875d91731 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Sun, 10 Apr 2016 14:57:19 +0200 Subject: [PATCH 1251/2553] util-decode-der: fix hang detected by AFL Fix hang that occurs when child->length is zero, resulting in an endless loop. --- src/util-decode-der.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util-decode-der.c b/src/util-decode-der.c index f97497665f77..be56b5e546f7 100644 --- a/src/util-decode-der.c +++ b/src/util-decode-der.c @@ -270,6 +270,12 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, if (child == NULL) return NULL; + /* child length should never be zero */ + if (child->length == 0) { + SCFree(child); + return NULL; + } + child->header = el; return child; } From 167d94efff23075db331bf9205f5c4366677dea0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 26 Mar 2016 00:43:40 +0100 Subject: [PATCH 1252/2553] dns: improve handling of tx pick up on response --- src/app-layer-dns-udp.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index 01393ceee726..dcb2f5aa18b8 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -277,27 +277,29 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, } } - /* parse rcode, e.g. "noerror" or "nxdomain" */ - uint8_t rcode = ntohs(dns_header->flags) & 0x0F; - if (rcode <= DNS_RCODE_NOTZONE) { - SCLogDebug("rcode %u", rcode); - if (tx != NULL) - tx->rcode = rcode; - } else { - /* this is not invalid, rcodes can be user defined */ - SCLogDebug("unexpected DNS rcode %u", rcode); + /* if we previously didn't have a tx, it could have been created by the + * above code, so lets check again */ + if (tx == NULL) { + tx = DNSTransactionFindByTxId(dns_state, ntohs(dns_header->tx_id)); } + if (tx != NULL) { + /* parse rcode, e.g. "noerror" or "nxdomain" */ + uint8_t rcode = ntohs(dns_header->flags) & 0x0F; + if (rcode <= DNS_RCODE_NOTZONE) { + SCLogDebug("rcode %u", rcode); + tx->rcode = rcode; + } else { + /* this is not invalid, rcodes can be user defined */ + SCLogDebug("unexpected DNS rcode %u", rcode); + } - if (ntohs(dns_header->flags) & 0x0080) { - SCLogDebug("recursion desired"); - if (tx != NULL) + if (ntohs(dns_header->flags) & 0x0080) { + SCLogDebug("recursion desired"); tx->recursion_desired = 1; - } + } - if (tx != NULL) { tx->replied = 1; } - SCReturnInt(1); bad_data: From 4a2e816bea7b58765742012a925cb96a77063a6b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 29 Feb 2016 12:46:22 +0100 Subject: [PATCH 1253/2553] detect parser: add parse regex util function Add regex setup and free util functions. Keywords often use a regex to parse rule input. Introduce a common function to do this setup. Also create a list of registered regexes to free at engine shutdown. --- src/detect-parse.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++ src/detect-parse.h | 8 ++++++ src/suricata.c | 1 + 3 files changed, 72 insertions(+) diff --git a/src/detect-parse.c b/src/detect-parse.c index 62e1f49a51c0..ca08ceaf76ac 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1956,6 +1956,69 @@ Signature *DetectEngineAppendSig(DetectEngineCtx *de_ctx, char *sigstr) return NULL; } +typedef struct DetectParseRegex_ { + pcre *regex; + pcre_extra *study; + struct DetectParseRegex_ *next; +} DetectParseRegex; + +static DetectParseRegex *g_detect_parse_regex_list = NULL; + +void DetectParseFreeRegexes(void) +{ + DetectParseRegex *r = g_detect_parse_regex_list; + while (r) { + DetectParseRegex *next = r->next; + + if (r->regex) { + pcre_free(r->regex); + } + if (r->study) { + pcre_free_study(r->study); + } + SCFree(r); + r = next; + } + g_detect_parse_regex_list = NULL; +} + +/** \brief add regex and/or study to at exit free list + */ +void DetectParseRegexAddToFreeList(pcre *regex, pcre_extra *study) +{ + DetectParseRegex *r = SCCalloc(1, sizeof(*r)); + if (r == NULL) { + FatalError(SC_ERR_MEM_ALLOC, "failed to alloc memory for pcre free list"); + } + r->regex = regex; + r->study = study; + r->next = g_detect_parse_regex_list; + g_detect_parse_regex_list = r; +} + +void DetectSetupParseRegexes(const char *parse_str, + pcre **parse_regex, + pcre_extra **parse_regex_study) +{ + const char *eb; + int eo; + int opts = 0; + + *parse_regex = pcre_compile(parse_str, opts, &eb, &eo, NULL); + if (*parse_regex == NULL) { + FatalError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " + "offset %" PRId32 ": %s", parse_str, eo, eb); + } + + *parse_regex_study = pcre_study(*parse_regex, 0, &eb); + if (eb != NULL) { + FatalError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + } + + DetectParseRegexAddToFreeList(*parse_regex, *parse_regex_study); + return; +} + /* * TESTS */ diff --git a/src/detect-parse.h b/src/detect-parse.h index cb2ae0f3b37d..bdc82ef15c02 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -67,5 +67,13 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s const char *DetectListToHumanString(int list); const char *DetectListToString(int list); +/* parse regex setup and free util funcs */ + +void DetectSetupParseRegexes(const char *parse_str, + pcre **parse_regex, + pcre_extra **parse_regex_study); +void DetectParseRegexAddToFreeList(pcre *regex, pcre_extra *study); +void DetectParseFreeRegexes(void); + #endif /* __DETECT_PARSE_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 280181b13eb9..13eb25012422 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2627,5 +2627,6 @@ int main(int argc, char **argv) #endif ConfDeInit(); + DetectParseFreeRegexes(); exit(engine_retval); } From e67ae0f174f81bc85b49b9ea106c4a4b798e1925 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 29 Feb 2016 12:49:19 +0100 Subject: [PATCH 1254/2553] detect keywords: use parse regex util func --- src/detect-base64-decode.c | 18 +--------- src/detect-byte-extract.c | 21 +---------- src/detect-bytejump.c | 24 +------------ src/detect-bytetest.c | 24 +------------ src/detect-classtype.c | 24 ++----------- src/detect-dce-iface.c | 26 ++------------ src/detect-dce-opnum.c | 26 ++------------ src/detect-detection-filter.c | 22 +----------- src/detect-dsize.c | 23 +----------- src/detect-engine-event.c | 23 +----------- src/detect-fast-pattern.c | 27 ++------------ src/detect-filesize.c | 25 +------------ src/detect-filestore.c | 23 +----------- src/detect-flags.c | 22 +----------- src/detect-flow.c | 23 +----------- src/detect-flowbits.c | 23 +----------- src/detect-flowint.c | 22 +----------- src/detect-flowvar.c | 23 +----------- src/detect-fragbits.c | 22 +----------- src/detect-fragoffset.c | 20 +---------- src/detect-gid.c | 2 -- src/detect-hostbits.c | 23 +----------- src/detect-icmp-id.c | 20 +---------- src/detect-icmp-seq.c | 20 +---------- src/detect-icode.c | 22 +----------- src/detect-id.c | 23 +----------- src/detect-ipopts.c | 23 +----------- src/detect-ipproto.c | 26 +------------- src/detect-iprep.c | 23 +----------- src/detect-isdataat.c | 21 +---------- src/detect-itype.c | 22 +----------- src/detect-mark.c | 22 +----------- src/detect-modbus.c | 39 +++------------------ src/detect-pcre.c | 33 +++++------------- src/detect-pktvar.c | 23 +----------- src/detect-priority.c | 22 ++---------- src/detect-reference.c | 22 +----------- src/detect-rpc.c | 23 +----------- src/detect-ssh-proto-version.c | 23 +----------- src/detect-ssh-software-version.c | 23 +----------- src/detect-ssl-state.c | 38 ++------------------ src/detect-ssl-version.c | 24 +------------ src/detect-stream_size.c | 22 +----------- src/detect-tag.c | 23 +----------- src/detect-template.c | 25 +------------ src/detect-threshold.c | 22 +----------- src/detect-tls-version.c | 23 +----------- src/detect-tls.c | 58 ++++--------------------------- src/detect-tos.c | 22 +----------- src/detect-ttl.c | 21 +---------- src/detect-urilen.c | 25 +------------ src/detect-window.c | 27 +------------- src/detect-xbits.c | 23 +----------- 53 files changed, 74 insertions(+), 1195 deletions(-) diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index a693de151372..781f3d3ef0ed 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -38,9 +38,6 @@ static void DetectBase64DecodeRegisterTests(void); void DetectBase64DecodeRegister(void) { - const char *pcre_errptr; - int pcre_erroffset; - sigmatch_table[DETECT_BASE64_DECODE].name = "base64_decode"; sigmatch_table[DETECT_BASE64_DECODE].desc = "Decodes base64 encoded data."; @@ -54,20 +51,7 @@ void DetectBase64DecodeRegister(void) sigmatch_table[DETECT_BASE64_DECODE].flags |= SIGMATCH_PAYLOAD; sigmatch_table[DETECT_BASE64_DECODE].flags |= SIGMATCH_OPTIONAL_OPT; - decode_pcre = pcre_compile(decode_pattern, 0, &pcre_errptr, &pcre_erroffset, - NULL); - if (decode_pcre == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Failed to compile pattern \"%s\" at" - " offset %d: %s", decode_pattern, pcre_erroffset, pcre_errptr); - exit(EXIT_FAILURE); - } - - decode_pcre_study = pcre_study(decode_pcre, 0, &pcre_errptr); - if (pcre_errptr != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "Failed to study pattern \"%s\": %s", - decode_pattern, pcre_errptr); - exit(EXIT_FAILURE); - } + DetectSetupParseRegexes(decode_pattern, &decode_pcre, &decode_pcre_study); } int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 8b71c7970d01..a4549a1d6d08 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -100,10 +100,6 @@ void DetectByteExtractFree(void *); */ void DetectByteExtractRegister(void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_BYTE_EXTRACT].name = "byte_extract"; sigmatch_table[DETECT_BYTE_EXTRACT].Match = NULL; sigmatch_table[DETECT_BYTE_EXTRACT].AppLayerMatch = NULL; @@ -113,22 +109,7 @@ void DetectByteExtractRegister(void) sigmatch_table[DETECT_BYTE_EXTRACT].flags |= SIGMATCH_PAYLOAD; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed " - "at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, SigMatch *sm, diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 7111bd67f3ac..cf89e9fca950 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -64,10 +64,6 @@ void DetectBytejumpRegisterTests(void); void DetectBytejumpRegister (void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_BYTEJUMP].name = "byte_jump"; sigmatch_table[DETECT_BYTEJUMP].Match = DetectBytejumpMatch; sigmatch_table[DETECT_BYTEJUMP].Setup = DetectBytejumpSetup; @@ -76,25 +72,7 @@ void DetectBytejumpRegister (void) sigmatch_table[DETECT_BYTEJUMP].flags |= SIGMATCH_PAYLOAD; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed " - "at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** \brief Byte jump match function diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 1802303ed8d5..2eaddadb0fa7 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -66,10 +66,6 @@ void DetectBytetestRegisterTests(void); void DetectBytetestRegister (void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_BYTETEST].name = "byte_test"; sigmatch_table[DETECT_BYTETEST].Match = DetectBytetestMatch; sigmatch_table[DETECT_BYTETEST].Setup = DetectBytetestSetup; @@ -78,25 +74,7 @@ void DetectBytetestRegister (void) sigmatch_table[DETECT_BYTETEST].flags |= SIGMATCH_PAYLOAD; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " - "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** \brief Bytetest detection code diff --git a/src/detect-classtype.c b/src/detect-classtype.c index f81d8378dba3..c1ce60774468 100644 --- a/src/detect-classtype.c +++ b/src/detect-classtype.c @@ -37,7 +37,7 @@ #include "util-debug.h" #include "util-unittest.h" -#define DETECT_CLASSTYPE_REGEX "^\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*$" +#define PARSE_REGEX "^\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*$" static pcre *regex = NULL; static pcre_extra *regex_study = NULL; @@ -50,12 +50,6 @@ void DetectClasstypeRegisterTests(void); */ void DetectClasstypeRegister(void) { - const char *eb = NULL; - int eo; - int opts = 0; - - SCLogDebug("Registering the Classtype keyword handler"); - sigmatch_table[DETECT_CLASSTYPE].name = "classtype"; sigmatch_table[DETECT_CLASSTYPE].desc = "information about the classification of rules and alerts"; sigmatch_table[DETECT_CLASSTYPE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Classtype"; @@ -64,21 +58,7 @@ void DetectClasstypeRegister(void) sigmatch_table[DETECT_CLASSTYPE].Free = NULL; sigmatch_table[DETECT_CLASSTYPE].RegisterTests = DetectClasstypeRegisterTests; - regex = pcre_compile(DETECT_CLASSTYPE_REGEX, opts, &eb, &eo, NULL); - if (regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - DETECT_CLASSTYPE_REGEX, eo, eb); - goto end; - } - - regex_study = pcre_study(regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto end; - } - - end: - return; + DetectSetupParseRegexes(PARSE_REGEX, ®ex, ®ex_study); } /** diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index e66ca94d0ae6..3e89feb5572d 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -47,7 +47,7 @@ #include "util-unittest-helper.h" #include "stream-tcp.h" -#define DETECT_DCE_IFACE_PCRE_PARSE_ARGS "^\\s*([0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12})(?:\\s*,(<|>|=|!)([0-9]{1,5}))?(?:\\s*,(any_frag))?\\s*$" +#define PARSE_REGEX "^\\s*([0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12})(?:\\s*,(<|>|=|!)([0-9]{1,5}))?(?:\\s*,(any_frag))?\\s*$" static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; @@ -62,10 +62,6 @@ void DetectDceIfaceFree(void *); */ void DetectDceIfaceRegister(void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_DCE_IFACE].name = "dce_iface"; sigmatch_table[DETECT_DCE_IFACE].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_IFACE].Match = NULL; @@ -76,25 +72,7 @@ void DetectDceIfaceRegister(void) sigmatch_table[DETECT_DCE_IFACE].flags |= SIGMATCH_PAYLOAD; - parse_regex = pcre_compile(DETECT_DCE_IFACE_PCRE_PARSE_ARGS, opts, &eb, - &eo, NULL); - if (parse_regex == NULL) { - SCLogDebug("pcre compile of \"%s\" failed at offset %" PRId32 ": %s", - DETECT_DCE_IFACE_PCRE_PARSE_ARGS, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogDebug("pcre study failed: %s", eb); - goto error; - } - - return; - - error: - /* we need to handle error?! */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 8e33c8b18924..b650fe27ce4b 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -47,7 +47,7 @@ #include "util-unittest-helper.h" #include "stream-tcp.h" -#define DETECT_DCE_OPNUM_PCRE_PARSE_ARGS "^\\s*([0-9]{1,5}(\\s*-\\s*[0-9]{1,5}\\s*)?)(,\\s*[0-9]{1,5}(\\s*-\\s*[0-9]{1,5})?\\s*)*$" +#define PARSE_REGEX "^\\s*([0-9]{1,5}(\\s*-\\s*[0-9]{1,5}\\s*)?)(,\\s*[0-9]{1,5}(\\s*-\\s*[0-9]{1,5})?\\s*)*$" static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; @@ -62,10 +62,6 @@ void DetectDceOpnumFree(void *); */ void DetectDceOpnumRegister(void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_DCE_OPNUM].name = "dce_opnum"; sigmatch_table[DETECT_DCE_OPNUM].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_OPNUM].Match = NULL; @@ -76,25 +72,7 @@ void DetectDceOpnumRegister(void) sigmatch_table[DETECT_DCE_OPNUM].flags |= SIGMATCH_PAYLOAD; - parse_regex = pcre_compile(DETECT_DCE_OPNUM_PCRE_PARSE_ARGS, opts, &eb, - &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", - DETECT_DCE_OPNUM_PCRE_PARSE_ARGS, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - - error: - /* we need to handle error?! */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 14df7c47ded9..6ffca0e315ef 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -71,27 +71,7 @@ void DetectDetectionFilterRegister (void) /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_DETECTION_FILTER].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } int DetectDetectionFilterMatch (ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 6d4e598f8da2..a331f6f4d213 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -66,28 +66,7 @@ void DetectDsizeRegister (void) sigmatch_table[DETECT_DSIZE].Free = DetectDsizeFree; sigmatch_table[DETECT_DSIZE].RegisterTests = DsizeRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-engine-event.c b/src/detect-engine-event.c index 6028e9895d3a..ebfe865acc1a 100644 --- a/src/detect-engine-event.c +++ b/src/detect-engine-event.c @@ -77,28 +77,7 @@ void DetectEngineEventRegister (void) sigmatch_table[DETECT_STREAM_EVENT].Setup = DetectStreamEventSetup; sigmatch_table[DETECT_STREAM_EVENT].Free = DetectEngineEventFree; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s\n", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s\n", eb); - goto error; - } - return; - -error: - return; - + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 99fb409c0387..dff7a4cc4aeb 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -37,7 +37,7 @@ #include "util-unittest.h" #include "util-unittest-helper.h" -#define DETECT_FAST_PATTERN_REGEX "^(\\s*only\\s*)|\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*$" +#define PARSE_REGEX "^(\\s*only\\s*)|\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*$" static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; @@ -164,30 +164,7 @@ void DetectFastPatternRegister(void) sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_PAYLOAD; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(DETECT_FAST_PATTERN_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " - "offset %" PRId32 ": %s", DETECT_FAST_PATTERN_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - - error: - /* get some way to return an error code! */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } //static int DetectFastPatternParseArg( diff --git a/src/detect-filesize.c b/src/detect-filesize.c index d65b594f1d29..709097f54211 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -70,30 +70,7 @@ void DetectFilesizeRegister(void) sigmatch_table[DETECT_FILESIZE].RegisterTests = DetectFilesizeRegisterTests; sigmatch_table[DETECT_FILESIZE].flags |= SIGMATCH_PAYLOAD; /** XXX necessary? */ - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogDebug("pcre compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogDebug("pcre study failed: %s", eb); - goto error; - } - return; - -error: - if (parse_regex != NULL) - SCFree(parse_regex); - if (parse_regex_study != NULL) - SCFree(parse_regex_study); - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 00e8aacc8fd4..0f96e86871c9 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -79,28 +79,7 @@ void DetectFilestoreRegister(void) sigmatch_table[DETECT_FILESTORE].RegisterTests = NULL; sigmatch_table[DETECT_FILESTORE].flags = SIGMATCH_OPTIONAL_OPT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - SCLogDebug("registering filestore rule option"); - return; -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-flags.c b/src/detect-flags.c index 860d38a86a76..1d6c3d11aadf 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -72,27 +72,7 @@ void DetectFlagsRegister (void) sigmatch_table[DETECT_FLAGS].Free = DetectFlagsFree; sigmatch_table[DETECT_FLAGS].RegisterTests = FlagsRegisterTests; - const char *eb; - int opts = 0; - int eo; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - return; - + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-flow.c b/src/detect-flow.c index 652dc654d6a5..304d97d9b937 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -66,28 +66,7 @@ void DetectFlowRegister (void) sigmatch_table[DETECT_FLOW].Free = DetectFlowFree; sigmatch_table[DETECT_FLOW].RegisterTests = DetectFlowRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /* diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 5cc727c3e71b..70056f02dd97 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -67,28 +67,7 @@ void DetectFlowbitsRegister (void) /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_FLOWBITS].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 80ddfe9d356e..dff26125cb43 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -67,27 +67,7 @@ void DetectFlowintRegister(void) sigmatch_table[DETECT_FLOWINT].Free = DetectFlowintFree; sigmatch_table[DETECT_FLOWINT].RegisterTests = DetectFlowintRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; -error: - SCLogInfo("Error registering flowint detection plugin"); - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index f6ff82d60891..1fbc3eff63c2 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -64,28 +64,7 @@ void DetectFlowvarRegister (void) sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Free = DetectFlowvarDataFree; sigmatch_table[DETECT_FLOWVAR_POSTMATCH].RegisterTests = NULL; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-fragbits.c b/src/detect-fragbits.c index a60f9e22a79d..4150d3a6f5c4 100644 --- a/src/detect-fragbits.c +++ b/src/detect-fragbits.c @@ -83,27 +83,7 @@ void DetectFragBitsRegister (void) sigmatch_table[DETECT_FRAGBITS].Free = DetectFragBitsFree; sigmatch_table[DETECT_FRAGBITS].RegisterTests = FragBitsRegisterTests; - const char *eb; - int opts = 0; - int eo; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - return; - + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index fed8f5584cd2..6e6049fb44c0 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -61,25 +61,7 @@ void DetectFragOffsetRegister (void) sigmatch_table[DETECT_FRAGOFFSET].Free = DetectFragOffsetFree; sigmatch_table[DETECT_FRAGOFFSET].RegisterTests = DetectFragOffsetRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-gid.c b/src/detect-gid.c index 4cbbc8a9e123..3344fe37997d 100644 --- a/src/detect-gid.c +++ b/src/detect-gid.c @@ -36,8 +36,6 @@ #include "util-unittest.h" #include "util-debug.h" -#define PARSE_REGEX "[0-9]+" - static int DetectGidSetup (DetectEngineCtx *, Signature *, char *); /** diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 362dbf598b05..2c325eb346f7 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -82,28 +82,7 @@ void DetectHostbitsRegister (void) /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_HOSTBITS].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } static int DetectHostbitMatchToggle (Packet *p, const DetectXbitsData *fd) diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index 59d1e9ae679c..675e03e41038 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -60,25 +60,7 @@ void DetectIcmpIdRegister (void) sigmatch_table[DETECT_ICMP_ID].Free = DetectIcmpIdFree; sigmatch_table[DETECT_ICMP_ID].RegisterTests = DetectIcmpIdRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index e48003a0a979..1fbefb7c29cd 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -60,25 +60,7 @@ void DetectIcmpSeqRegister (void) sigmatch_table[DETECT_ICMP_SEQ].Free = DetectIcmpSeqFree; sigmatch_table[DETECT_ICMP_SEQ].RegisterTests = DetectIcmpSeqRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-icode.c b/src/detect-icode.c index 33f3e0eff433..fc5c572d1a6d 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -64,27 +64,7 @@ void DetectICodeRegister (void) sigmatch_table[DETECT_ICODE].Free = DetectICodeFree; sigmatch_table[DETECT_ICODE].RegisterTests = DetectICodeRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-id.c b/src/detect-id.c index a15e32284004..9b2b7a849f54 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -67,28 +67,7 @@ void DetectIdRegister (void) sigmatch_table[DETECT_ID].Free = DetectIdFree; sigmatch_table[DETECT_ID].RegisterTests = DetectIdRegisterTests; - const char *eb; - int eo; - int opts = 0; - - SCLogDebug("registering id rule option"); - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index ef9b54302764..4a3bb31873c5 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -64,28 +64,7 @@ void DetectIpOptsRegister (void) sigmatch_table[DETECT_IPOPTS].Free = DetectIpOptsFree; sigmatch_table[DETECT_IPOPTS].RegisterTests = IpOptsRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; - + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index 0cade5691433..e0c2635a0eea 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -61,10 +61,6 @@ static void DetectIPProtoFree(void *); void DetectIPProtoRegister(void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_IPPROTO].name = "ip_proto"; sigmatch_table[DETECT_IPPROTO].desc = "match on the IP protocol in the packet-header"; sigmatch_table[DETECT_IPPROTO].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#ip_proto"; @@ -73,27 +69,7 @@ void DetectIPProtoRegister(void) sigmatch_table[DETECT_IPPROTO].Free = DetectIPProtoFree; sigmatch_table[DETECT_IPPROTO].RegisterTests = DetectIPProtoRegisterTests; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " - "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - if (parse_regex) - pcre_free(parse_regex); - if (parse_regex_study) - pcre_free_study(parse_regex_study); - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-iprep.c b/src/detect-iprep.c index 09457fdecee8..10da976a86a8 100644 --- a/src/detect-iprep.c +++ b/src/detect-iprep.c @@ -67,28 +67,7 @@ void DetectIPRepRegister (void) /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_IPREP].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } static uint8_t GetHostRepSrc(Packet *p, uint8_t cat, uint32_t version) diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index f7dcfb9b0596..1329839ab8d0 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -75,26 +75,7 @@ void DetectIsdataatRegister(void) sigmatch_table[DETECT_ISDATAAT].flags |= SIGMATCH_PAYLOAD; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-itype.c b/src/detect-itype.c index fa8cfa6e8aeb..45e3a6ddf165 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -64,27 +64,7 @@ void DetectITypeRegister (void) sigmatch_table[DETECT_ITYPE].Free = DetectITypeFree; sigmatch_table[DETECT_ITYPE].RegisterTests = DetectITypeRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-mark.c b/src/detect-mark.c index 247bf4898ddc..b298ccfe7faa 100644 --- a/src/detect-mark.c +++ b/src/detect-mark.c @@ -58,27 +58,7 @@ void DetectMarkRegister (void) sigmatch_table[DETECT_MARK].Free = DetectMarkDataFree; sigmatch_table[DETECT_MARK].RegisterTests = MarkRegisterTests; - const char *eb; - int opts = 0; - int eo; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - return; - + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } #ifdef NFQ diff --git a/src/detect-modbus.c b/src/detect-modbus.c index 2fc5386cb3d0..f0cf9c6c85b9 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -409,41 +409,10 @@ void DetectModbusRegister(void) sigmatch_table[DETECT_AL_MODBUS].Free = DetectModbusFree; sigmatch_table[DETECT_AL_MODBUS].RegisterTests = DetectModbusRegisterTests; - const char *eb; - int eo, opts = 0; - - SCLogDebug("registering modbus rule option"); - - /* Function PARSE_REGEX */ - function_parse_regex = pcre_compile(PARSE_REGEX_FUNCTION, opts, &eb, &eo, NULL); - if (function_parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX_FUNCTION, eo, eb); - goto error; - } - - function_parse_regex_study = pcre_study(function_parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - /* Access PARSE_REGEX */ - access_parse_regex = pcre_compile(PARSE_REGEX_ACCESS, opts, &eb, &eo, NULL); - if (access_parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX_ACCESS, eo, eb); - goto error; - } - - access_parse_regex_study = pcre_study(access_parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - SCReturn; + DetectSetupParseRegexes(PARSE_REGEX_FUNCTION, + &function_parse_regex, &function_parse_regex_study); + DetectSetupParseRegexes(PARSE_REGEX_ACCESS, + &access_parse_regex, &access_parse_regex_study); } #ifdef UNITTESTS /* UNITTESTS */ diff --git a/src/detect-pcre.c b/src/detect-pcre.c index c3274e4f519b..0f1915495560 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -97,9 +97,6 @@ void DetectPcreRegister (void) sigmatch_table[DETECT_PCRE].flags |= SIGMATCH_PAYLOAD; - const char *eb; - int eo; - int opts = 0; intmax_t val = 0; if (!ConfGetInt("pcre.match-limit", &val)) { @@ -130,38 +127,26 @@ void DetectPcreRegister (void) } } - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } + /* setup the capture regex, as it needs PCRE_UNGREEDY we do it manually */ + const char *eb; + int eo; + int opts = PCRE_UNGREEDY; /* pkt_http_ua should be pkt, http_ua, for this reason the UNGREEDY */ - opts |= PCRE_UNGREEDY; /* pkt_http_ua should be pkt, http_ua, for this reason the UNGREEDY */ parse_capture_regex = pcre_compile(PARSE_CAPTURE_REGEX, opts, &eb, &eo, NULL); - if(parse_capture_regex == NULL) + if (parse_capture_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_CAPTURE_REGEX, eo, eb); - goto error; + FatalError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_CAPTURE_REGEX, eo, eb); } parse_capture_regex_study = pcre_study(parse_capture_regex, 0, &eb); if(eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; + FatalError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); } - return; -error: - /* XXX */ + DetectParseRegexAddToFreeList(parse_capture_regex, parse_capture_regex_study); return; } diff --git a/src/detect-pktvar.c b/src/detect-pktvar.c index 075744e41024..d319bd8882cf 100644 --- a/src/detect-pktvar.c +++ b/src/detect-pktvar.c @@ -52,28 +52,7 @@ void DetectPktvarRegister (void) sigmatch_table[DETECT_PKTVAR].flags |= SIGMATCH_PAYLOAD; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /* diff --git a/src/detect-priority.c b/src/detect-priority.c index 66b736fb5739..2a7a80b5365e 100644 --- a/src/detect-priority.c +++ b/src/detect-priority.c @@ -33,7 +33,7 @@ #include "util-debug.h" #include "util-unittest.h" -#define DETECT_PRIORITY_REGEX "^\\s*(\\d+|\"\\d+\")\\s*$" +#define PARSE_REGEX "^\\s*(\\d+|\"\\d+\")\\s*$" static pcre *regex = NULL; static pcre_extra *regex_study = NULL; @@ -46,10 +46,6 @@ void SCPriorityRegisterTests(void); */ void DetectPriorityRegister (void) { - const char *eb = NULL; - int eo; - int opts = 0; - sigmatch_table[DETECT_PRIORITY].name = "priority"; sigmatch_table[DETECT_PRIORITY].desc = "rules with a higher priority will be examined first"; sigmatch_table[DETECT_PRIORITY].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Priority"; @@ -58,21 +54,7 @@ void DetectPriorityRegister (void) sigmatch_table[DETECT_PRIORITY].Free = NULL; sigmatch_table[DETECT_PRIORITY].RegisterTests = SCPriorityRegisterTests; - regex = pcre_compile(DETECT_PRIORITY_REGEX, opts, &eb, &eo, NULL); - if (regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - DETECT_PRIORITY_REGEX, eo, eb); - goto end; - } - - regex_study = pcre_study(regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto end; - } - - end: - return; + DetectSetupParseRegexes(PARSE_REGEX, ®ex, ®ex_study); } static int DetectPrioritySetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) diff --git a/src/detect-reference.c b/src/detect-reference.c index d1473cc1b87c..6fe04a2b9159 100644 --- a/src/detect-reference.c +++ b/src/detect-reference.c @@ -63,27 +63,7 @@ void DetectReferenceRegister(void) sigmatch_table[DETECT_REFERENCE].Free = NULL; sigmatch_table[DETECT_REFERENCE].RegisterTests = ReferenceRegisterTests; - const char *eb; - int opts = 0; - int eo; - - opts |= PCRE_CASELESS; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " - "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-rpc.c b/src/detect-rpc.c index 844eb346478d..52f6d7469a16 100644 --- a/src/detect-rpc.c +++ b/src/detect-rpc.c @@ -66,28 +66,7 @@ void DetectRpcRegister (void) sigmatch_table[DETECT_RPC].Free = DetectRpcFree; sigmatch_table[DETECT_RPC].RegisterTests = DetectRpcRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /* diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index 98306483890b..abf86fe6fa9e 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -80,28 +80,7 @@ void DetectSshVersionRegister(void) sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Free = DetectSshVersionFree; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].RegisterTests = DetectSshVersionRegisterTests; - const char *eb; - int eo; - int opts = 0; - - SCLogDebug("registering ssh.protoversion rule option"); - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index 12ba869e445f..ff45a7f6ab06 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -85,28 +85,7 @@ void DetectSshSoftwareVersionRegister(void) sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Free = DetectSshSoftwareVersionFree; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].RegisterTests = DetectSshSoftwareVersionRegisterTests; - const char *eb; - int eo; - int opts = 0; - - SCLogDebug("registering ssh.softwareversion rule option"); - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 770ed659b417..2e837f208d3a 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -78,42 +78,8 @@ void DetectSslStateRegister(void) sigmatch_table[DETECT_AL_SSL_STATE].Free = DetectSslStateFree; sigmatch_table[DETECT_AL_SSL_STATE].RegisterTests = DetectSslStateRegisterTests; - const char *eb; - int eo; - int opts = 0; - - SCLogDebug("registering ssl_state rule option"); - - /* PARSE_REGEX1 */ - parse_regex1 = pcre_compile(PARSE_REGEX1, opts, &eb, &eo, NULL); - if (parse_regex1 == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX1, eo, eb); - goto error; - } - - parse_regex1_study = pcre_study(parse_regex1, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - /* PARSE_REGEX2 */ - parse_regex2 = pcre_compile(PARSE_REGEX2, opts, &eb, &eo, NULL); - if (parse_regex2 == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX2, eo, eb); - goto error; - } - - parse_regex2_study = pcre_study(parse_regex2, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX1, &parse_regex1, &parse_regex1_study); + DetectSetupParseRegexes(PARSE_REGEX2, &parse_regex2, &parse_regex2_study); } /** diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index 03a1f39eb25d..5259187eb6e7 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -79,29 +79,7 @@ void DetectSslVersionRegister(void) sigmatch_table[DETECT_AL_SSL_VERSION].Free = DetectSslVersionFree; sigmatch_table[DETECT_AL_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests; - const char *eb; - int eo; - int opts = 0; - - SCLogDebug("registering ssl_version rule option"); - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c index c58ecf5a2216..159d4d6f7c84 100644 --- a/src/detect-stream_size.c +++ b/src/detect-stream_size.c @@ -63,27 +63,7 @@ void DetectStreamSizeRegister(void) sigmatch_table[DETECT_STREAM_SIZE].Free = DetectStreamSizeFree; sigmatch_table[DETECT_STREAM_SIZE].RegisterTests = DetectStreamSizeRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - if (parse_regex != NULL) SCFree(parse_regex); - if (parse_regex_study != NULL) SCFree(parse_regex_study); - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-tag.c b/src/detect-tag.c index 6a3f8ad8c0b3..dfa762d190bb 100644 --- a/src/detect-tag.c +++ b/src/detect-tag.c @@ -74,28 +74,7 @@ void DetectTagRegister(void) sigmatch_table[DETECT_TAG].RegisterTests = DetectTagRegisterTests; sigmatch_table[DETECT_TAG].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-template.c b/src/detect-template.c index b2fb26d6c306..b415783a60f9 100644 --- a/src/detect-template.c +++ b/src/detect-template.c @@ -69,30 +69,7 @@ void DetectTemplateRegister(void) { sigmatch_table[DETECT_TEMPLATE].RegisterTests = DetectTemplateRegisterTests; /* set up the PCRE for keyword parsing */ - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " - "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - if (parse_regex != NULL) - SCFree(parse_regex); - if (parse_regex_study != NULL) - SCFree(parse_regex_study); - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 7410b2c282ed..28edd6e5c21f 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -85,27 +85,7 @@ void DetectThresholdRegister(void) /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_THRESHOLD].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int opts = 0; - int eo; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - return; - + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } static int DetectThresholdMatch(ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index 144b5031e8fc..200ba959f898 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -79,28 +79,7 @@ void DetectTlsVersionRegister (void) sigmatch_table[DETECT_AL_TLS_VERSION].Free = DetectTlsVersionFree; sigmatch_table[DETECT_AL_TLS_VERSION].RegisterTests = DetectTlsVersionRegisterTests; - const char *eb; - int eo; - int opts = 0; - - SCLogDebug("registering tls.version rule option"); - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-tls.c b/src/detect-tls.c index ba37aee0e623..b2ff99b613d9 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -134,58 +134,12 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_STORE].RegisterTests = NULL; sigmatch_table[DETECT_AL_TLS_STORE].flags |= SIGMATCH_NOOPT; - const char *eb; - int eo; - int opts = 0; - - SCLogDebug("registering tls.subject rule option"); - - subject_parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (subject_parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - subject_parse_regex_study = pcre_study(subject_parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - SCLogDebug("registering tls.issuerdn rule option"); - - issuerdn_parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (issuerdn_parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - issuerdn_parse_regex_study = pcre_study(issuerdn_parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - SCLogDebug("registering tls.fingerprint rule option"); - - fingerprint_parse_regex = pcre_compile(PARSE_REGEX_FINGERPRINT, opts, &eb, &eo, NULL); - if (fingerprint_parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX_FINGERPRINT, eo, eb); - goto error; - } - - fingerprint_parse_regex_study = pcre_study(fingerprint_parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, + &subject_parse_regex, &subject_parse_regex_study); + DetectSetupParseRegexes(PARSE_REGEX, + &issuerdn_parse_regex, &issuerdn_parse_regex_study); + DetectSetupParseRegexes(PARSE_REGEX_FINGERPRINT, + &fingerprint_parse_regex, &fingerprint_parse_regex_study); } /** diff --git a/src/detect-tos.c b/src/detect-tos.c index f82dc453a95d..8beeb329eb35 100644 --- a/src/detect-tos.c +++ b/src/detect-tos.c @@ -68,27 +68,7 @@ void DetectTosRegister(void) sigmatch_table[DETECT_TOS].Free = DetectTosFree; sigmatch_table[DETECT_TOS].RegisterTests = DetectTosRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at " - "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-ttl.c b/src/detect-ttl.c index 316af96967f1..dbd8e21cc958 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -61,26 +61,7 @@ void DetectTtlRegister(void) sigmatch_table[DETECT_TTL].Free = DetectTtlFree; sigmatch_table[DETECT_TTL].RegisterTests = DetectTtlRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - if (parse_regex != NULL) SCFree(parse_regex); - if (parse_regex_study != NULL) SCFree(parse_regex_study); + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); return; } diff --git a/src/detect-urilen.c b/src/detect-urilen.c index d7e5bdd8c86b..44de1f514326 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -70,30 +70,7 @@ void DetectUrilenRegister(void) sigmatch_table[DETECT_AL_URILEN].RegisterTests = DetectUrilenRegisterTests; sigmatch_table[DETECT_AL_URILEN].flags |= SIGMATCH_PAYLOAD; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogDebug("pcre compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogDebug("pcre study failed: %s", eb); - goto error; - } - return; - -error: - if (parse_regex != NULL) - pcre_free(parse_regex); - if (parse_regex_study != NULL) - pcre_free_study(parse_regex_study); - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-window.c b/src/detect-window.c index d3704f4f81c4..39f879aa935c 100644 --- a/src/detect-window.c +++ b/src/detect-window.c @@ -65,32 +65,7 @@ void DetectWindowRegister (void) sigmatch_table[DETECT_WINDOW].Free = DetectWindowFree; sigmatch_table[DETECT_WINDOW].RegisterTests = DetectWindowRegisterTests; - const char *eb; - int eo; - int opts = 0; - - #ifdef WINDOW_DEBUG - printf("detect-window: Registering window rule option\n"); - #endif - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** diff --git a/src/detect-xbits.c b/src/detect-xbits.c index f6f3ba74daba..af9384fb486a 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -74,28 +74,7 @@ void DetectXbitsRegister (void) /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_XBITS].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } static int DetectIPPairbitMatchToggle (Packet *p, const DetectXbitsData *fd) From 0ab83288acf824b7295a15a09ec6e582665939c1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 29 May 2015 14:00:40 +0200 Subject: [PATCH 1255/2553] startup: move RunUnittests to StartInternalRunMode --- src/suricata.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 13eb25012422..f5ed5136e16d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1930,6 +1930,8 @@ int StartInternalRunMode(SCInstance *suri, int argc, char **argv) return TM_ECODE_DONE; case RUNMODE_LIST_UNITTEST: RunUnittests(1, suri->regex_arg); + case RUNMODE_UNITTEST: + RunUnittests(0, suri->regex_arg); #ifdef OS_WIN32 case RUNMODE_INSTALL_SERVICE: if (SCServiceInstall(argc, argv)) { @@ -2243,6 +2245,10 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + if (FinalizeRunMode(&suri, argv) != TM_ECODE_OK) { + exit(EXIT_FAILURE); + } + switch (StartInternalRunMode(&suri, argc, argv)) { case TM_ECODE_DONE: exit(EXIT_SUCCESS); @@ -2250,13 +2256,6 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - if (FinalizeRunMode(&suri, argv) != TM_ECODE_OK) { - exit(EXIT_FAILURE); - } - - if (suri.run_mode == RUNMODE_UNITTEST) - RunUnittests(0, suri.regex_arg); - #ifdef __SC_CUDA_SUPPORT__ /* Init the CUDA environment */ SCCudaInitCudaEnvironment(); From c0294521dd3124bd0795bdb009f6eef1892017d1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 29 May 2015 14:41:44 +0200 Subject: [PATCH 1256/2553] startup: move more into PostConfLoadedSetup --- src/runmodes.c | 14 +++++++++ src/suricata.c | 83 +++++++++++++++++++++++--------------------------- 2 files changed, 52 insertions(+), 45 deletions(-) diff --git a/src/runmodes.c b/src/runmodes.c index d4eda057af2b..ee93b0c05edf 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -51,6 +51,11 @@ #include "tmqh-flow.h" +#ifdef __SC_CUDA_SUPPORT__ +#include "util-cuda-buffer.h" +#include "util-mpm-ac.h" +#endif + int debuglog_enabled = 0; /** @@ -379,6 +384,15 @@ void RunModeDispatch(int runmode, const char *custom_mode) if (local_custom_mode != NULL) SCFree(local_custom_mode); + +#ifdef __SC_CUDA_SUPPORT__ + if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) + SCACCudaStartDispatcher(); +#endif + + /* Check if the alloted queues have at least 1 reader and writer */ + TmValidateQueueState(); + return; } diff --git a/src/suricata.c b/src/suricata.c index f5ed5136e16d..73115613455a 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -920,12 +920,12 @@ void RegisterAllModules() } -TmEcode LoadYamlConfig(char *conf_filename) +static TmEcode LoadYamlConfig(void) { SCEnter(); if (conf_filename == NULL) - SCReturnInt(TM_ECODE_OK); + conf_filename = DEFAULT_CONF_FILE; if (ConfYamlLoadFile(conf_filename) != 0) { /* Error already displayed. */ @@ -1974,6 +1974,9 @@ static int FinalizeRunMode(SCInstance *suri, char **argv) /* Set the global run mode */ run_mode = suri->run_mode; + if (!CheckValidDaemonModes(suri->daemon, suri->run_mode)) { + return TM_ECODE_FAILED; + } return TM_ECODE_OK; } @@ -2202,6 +2205,33 @@ static int PostConfLoadedSetup(SCInstance *suri) TmModuleRunInit(); PcapLogProfileSetup(); + + if (MayDaemonize(suri) != TM_ECODE_OK) + SCReturnInt(TM_ECODE_FAILED); + + if (InitSignalHandler(suri) != TM_ECODE_OK) + SCReturnInt(TM_ECODE_FAILED); + +#ifdef HAVE_NSS + /* init NSS for md5 */ + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + NSS_NoDB_Init(NULL); +#endif + + if (suri->disabled_detect) { + /* disable raw reassembly */ + (void)ConfSetFinal("stream.reassembly.raw", "false"); + } + + HostInitConfig(HOST_VERBOSE); + + if (MagicInit() != 0) + SCReturnInt(TM_ECODE_FAILED); + + SCAsn1LoadConfig(); + + CoredumpLoadConfig(); + SCReturnInt(TM_ECODE_OK); } @@ -2262,10 +2292,6 @@ int main(int argc, char **argv) CudaBufferInit(); #endif - if (!CheckValidDaemonModes(suri.daemon, suri.run_mode)) { - exit(EXIT_FAILURE); - } - /* Initializations for global vars, queues, etc (memsets, mutex init..) */ GlobalInits(); TimeInit(); @@ -2274,12 +2300,8 @@ int main(int argc, char **argv) StatsInit(); } - if (conf_filename == NULL) - conf_filename = DEFAULT_CONF_FILE; - - /** \todo we need an api for these */ /* Load yaml configuration file if provided. */ - if (LoadYamlConfig(conf_filename) != TM_ECODE_OK) { + if (LoadYamlConfig() != TM_ECODE_OK) { exit(EXIT_FAILURE); } @@ -2304,24 +2326,6 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - if (MayDaemonize(&suri) != TM_ECODE_OK) - exit(EXIT_FAILURE); - - if (InitSignalHandler(&suri) != TM_ECODE_OK) - exit(EXIT_FAILURE); - -#ifdef HAVE_NSS - /* init NSS for md5 */ - PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); - NSS_NoDB_Init(NULL); -#endif - - if (suri.disabled_detect) { - /* disable raw reassembly */ - (void)ConfSetFinal("stream.reassembly.raw", "false"); - } - - HostInitConfig(HOST_VERBOSE); if (suri.run_mode != RUNMODE_UNIX_SOCKET) { FlowInitConfig(FLOW_VERBOSE); StreamTcpInitConfig(STREAM_VERBOSE); @@ -2329,9 +2333,6 @@ int main(int argc, char **argv) AppLayerRegisterGlobalCounters(); } - if (MagicInit() != 0) - exit(EXIT_FAILURE); - DetectEngineCtx *de_ctx = NULL; if (!suri.disabled_detect) { SCClassConfInit(); @@ -2378,10 +2379,6 @@ int main(int argc, char **argv) RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveLogOnly); } - SCAsn1LoadConfig(); - - CoredumpLoadConfig(); - SCSetStartTime(&suri); SCDropMainThreadCaps(suri.userid, suri.groupid); @@ -2391,7 +2388,11 @@ int main(int argc, char **argv) StatsSetupPostConfig(); } - if(suri.run_mode == RUNMODE_CONF_TEST){ + if (ParseInterfacesList(suri.run_mode, suri.pcap_dev) != TM_ECODE_OK) { + exit(EXIT_FAILURE); + } + + if (suri.run_mode == RUNMODE_CONF_TEST){ SCLogNotice("Configuration provided was successfully loaded. Exiting."); exit(EXIT_SUCCESS); } @@ -2418,14 +2419,6 @@ int main(int argc, char **argv) StatsSpawnThreads(); } -#ifdef __SC_CUDA_SUPPORT__ - if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) - SCACCudaStartDispatcher(); -#endif - - /* Check if the alloted queues have at least 1 reader and writer */ - TmValidateQueueState(); - /* Wait till all the threads have been initialized */ if (TmThreadWaitOnThreadInit() == TM_ECODE_FAILED) { SCLogError(SC_ERR_INITIALIZATION, "Engine initialization failed, " From 4c1c13d1100feb6dc44d0f72f62f9e7b793928b9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 12 Apr 2016 08:21:13 +0200 Subject: [PATCH 1257/2553] detect reload: improve signal logic --- src/suricata.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 73115613455a..68736961f77d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2476,14 +2476,21 @@ int main(int argc, char **argv) if (suri.sig_file != NULL) { SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload not " "possible if -s or -S option used at runtime."); + sigusr2_count--; } else { - DetectEngineReload(conf_filename, &suri); + if (!(DetectEngineReloadIsStart())) { + DetectEngineReloadStart(); + DetectEngineReload(conf_filename, &suri); + DetectEngineReloadSetDone(); + sigusr2_count--; + } } - sigusr2_count--; + } else if (DetectEngineReloadIsStart()) { if (suri.sig_file != NULL) { SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload not " "possible if -s or -S option used at runtime."); + DetectEngineReloadSetDone(); } else { DetectEngineReload(conf_filename, &suri); DetectEngineReloadSetDone(); From b2695600bab7abf86e652b18c7a6d6f22f1c0503 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 5 Dec 2015 14:14:58 +0100 Subject: [PATCH 1258/2553] afl: add define to disable rand_r use The randomness affects AFL. It creates variable test cases, which we need to avoid. --- src/defrag-hash.c | 3 ++- src/flow.c | 3 ++- src/host.c | 3 ++- src/ippair.c | 3 ++- src/suricata-common.h | 2 ++ 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/defrag-hash.c b/src/defrag-hash.c index e37a08738d85..284b582f6e73 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -132,10 +132,11 @@ void DefragInitConfig(char quiet) SC_ATOMIC_INIT(defragtracker_prune_idx); DefragTrackerQueueInit(&defragtracker_spare_q); +#ifndef AFLFUZZ_NO_RANDOM unsigned int seed = RandomTimePreseed(); /* set defaults */ defrag_config.hash_rand = (int)(DEFRAG_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); - +#endif defrag_config.hash_size = DEFRAG_DEFAULT_HASHSIZE; defrag_config.memcap = DEFRAG_DEFAULT_MEMCAP; defrag_config.prealloc = DEFRAG_DEFAULT_PREALLOC; diff --git a/src/flow.c b/src/flow.c index fa8b21ba9587..4cedf2685db9 100644 --- a/src/flow.c +++ b/src/flow.c @@ -355,10 +355,11 @@ void FlowInitConfig(char quiet) FlowQueueInit(&flow_spare_q); FlowQueueInit(&flow_recycle_q); +#ifndef AFLFUZZ_NO_RANDOM unsigned int seed = RandomTimePreseed(); /* set defaults */ flow_config.hash_rand = (int)( FLOW_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); - +#endif flow_config.hash_size = FLOW_DEFAULT_HASHSIZE; flow_config.memcap = FLOW_DEFAULT_MEMCAP; flow_config.prealloc = FLOW_DEFAULT_PREALLOC; diff --git a/src/host.c b/src/host.c index a28639cce454..faf9513bde87 100644 --- a/src/host.c +++ b/src/host.c @@ -141,10 +141,11 @@ void HostInitConfig(char quiet) SC_ATOMIC_INIT(host_prune_idx); HostQueueInit(&host_spare_q); +#ifndef AFLFUZZ_NO_RANDOM unsigned int seed = RandomTimePreseed(); /* set defaults */ host_config.hash_rand = (int)( HOST_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); - +#endif host_config.hash_size = HOST_DEFAULT_HASHSIZE; host_config.memcap = HOST_DEFAULT_MEMCAP; host_config.prealloc = HOST_DEFAULT_PREALLOC; diff --git a/src/ippair.c b/src/ippair.c index 79ecb76ca806..736cdce5bad5 100644 --- a/src/ippair.c +++ b/src/ippair.c @@ -137,10 +137,11 @@ void IPPairInitConfig(char quiet) SC_ATOMIC_INIT(ippair_prune_idx); IPPairQueueInit(&ippair_spare_q); +#ifndef AFLFUZZ_NO_RANDOM unsigned int seed = RandomTimePreseed(); /* set defaults */ ippair_config.hash_rand = (int)( IPPAIR_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); - +#endif ippair_config.hash_size = IPPAIR_DEFAULT_HASHSIZE; ippair_config.memcap = IPPAIR_DEFAULT_MEMCAP; ippair_config.prealloc = IPPAIR_DEFAULT_PREALLOC; diff --git a/src/suricata-common.h b/src/suricata-common.h index 18791c3b04bc..4910c4185d7c 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -228,6 +228,8 @@ #endif #endif +#define AFLFUZZ_NO_RANDOM 1 + /* we need this to stringify the defines which are supplied at compiletime see: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/cpp/Stringification.html#Stringification */ #define xstr(s) str(s) From a42251d459833c061358687cc16da34d53045feb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 5 Dec 2015 14:29:14 +0100 Subject: [PATCH 1259/2553] afl: add define to disable mgt threads The inherent non-deterministic nature of the management threads creates variable test cases. --- src/counters.c | 4 ++++ src/flow-manager.c | 12 ++++++++++++ src/suricata-common.h | 1 + 3 files changed, 17 insertions(+) diff --git a/src/counters.c b/src/counters.c index add05fca7904..5e6d558c46fe 100644 --- a/src/counters.c +++ b/src/counters.c @@ -221,6 +221,10 @@ static ConfNode *GetConfig(void) { static void StatsInitCtx(void) { SCEnter(); +#ifdef AFLFUZZ_DISABLE_MGTTHREADS + stats_enabled = FALSE; + SCReturn; +#endif ConfNode *stats = GetConfig(); if (stats != NULL) { const char *enabled = ConfNodeLookupChildValue(stats, "enabled"); diff --git a/src/flow-manager.c b/src/flow-manager.c index 4cd53aacd558..9b9920eb4d1b 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -105,6 +105,9 @@ typedef struct FlowTimeoutCounters_ { */ void FlowDisableFlowManagerThread(void) { +#ifdef AFLFUZZ_DISABLE_MGTTHREADS + return; +#endif ThreadVars *tv = NULL; int cnt = 0; @@ -708,6 +711,9 @@ static uint64_t FlowGetMemuse(void) /** \brief spawn the flow manager thread */ void FlowManagerThreadSpawn() { +#ifdef AFLFUZZ_DISABLE_MGTTHREADS + return; +#endif intmax_t setting = 1; (void)ConfGetInt("flow.managers", &setting); @@ -868,6 +874,9 @@ int FlowRecyclerReadyToShutdown(void) /** \brief spawn the flow recycler thread */ void FlowRecyclerThreadSpawn() { +#ifdef AFLFUZZ_DISABLE_MGTTHREADS + return; +#endif intmax_t setting = 1; (void)ConfGetInt("flow.recyclers", &setting); @@ -917,6 +926,9 @@ void FlowRecyclerThreadSpawn() */ void FlowDisableFlowRecyclerThread(void) { +#ifdef AFLFUZZ_DISABLE_MGTTHREADS + return; +#endif ThreadVars *tv = NULL; int cnt = 0; diff --git a/src/suricata-common.h b/src/suricata-common.h index 4910c4185d7c..ff8d51472529 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -229,6 +229,7 @@ #endif #define AFLFUZZ_NO_RANDOM 1 +#define AFLFUZZ_DISABLE_MGTTHREADS 1 /* we need this to stringify the defines which are supplied at compiletime see: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/cpp/Stringification.html#Stringification */ From e824a8be763135d70e134f94ac04d7c45b6e7917 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 5 Dec 2015 14:48:05 +0100 Subject: [PATCH 1260/2553] afl: special 'single' runmode To avoid threading, this 'single' mode doesn't run in it's own thread but instead runs in the main thread. --- src/runmode-pcap-file.c | 6 ++ src/suricata-common.h | 1 + src/tm-threads.c | 118 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index 62e18c54583b..4d44814be73b 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -116,10 +116,16 @@ int RunModeFilePcapSingle(void) TmThreadSetCPU(tv, DETECT_CPU_SET); +#ifndef AFLFUZZ_PCAP_RUNMODE if (TmThreadSpawn(tv) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } +#else + /* in afl mode we don't spawn a new thread, but run the pipeline + * in the main thread */ + tv->tm_func(tv); +#endif return 0; } diff --git a/src/suricata-common.h b/src/suricata-common.h index ff8d51472529..da6487e162cc 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -230,6 +230,7 @@ #define AFLFUZZ_NO_RANDOM 1 #define AFLFUZZ_DISABLE_MGTTHREADS 1 +#define AFLFUZZ_PCAP_RUNMODE 1 /* we need this to stringify the defines which are supplied at compiletime see: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/cpp/Stringification.html#Stringification */ diff --git a/src/tm-threads.c b/src/tm-threads.c index 87b424b2e615..a1cf5528fb0e 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -386,6 +386,120 @@ void *TmThreadsSlotPktAcqLoop(void *td) return NULL; } +#ifdef AFLFUZZ_PCAP_RUNMODE +/** \brief simplified loop to speed up AFL + * + * The loop runs in the caller's thread. No separate thread. + */ +void *TmThreadsSlotPktAcqLoopAFL(void *td) +{ + SCLogNotice("AFL mode starting"); + + ThreadVars *tv = (ThreadVars *)td; + TmSlot *s = tv->tm_slots; + char run = 1; + TmEcode r = TM_ECODE_OK; + TmSlot *slot = NULL; + + PacketPoolInit(); + + /* check if we are setup properly */ + if (s == NULL || s->PktAcqLoop == NULL || tv->tmqh_in == NULL || tv->tmqh_out == NULL) { + SCLogError(SC_ERR_FATAL, "TmSlot or ThreadVars badly setup: s=%p," + " PktAcqLoop=%p, tmqh_in=%p," + " tmqh_out=%p", + s, s ? s->PktAcqLoop : NULL, tv->tmqh_in, tv->tmqh_out); + EngineKill(); + + TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); + return NULL; + } + + for (slot = s; slot != NULL; slot = slot->slot_next) { + if (slot->SlotThreadInit != NULL) { + void *slot_data = NULL; + r = slot->SlotThreadInit(tv, slot->slot_initdata, &slot_data); + if (r != TM_ECODE_OK) { + if (r == TM_ECODE_DONE) { + EngineDone(); + TmThreadsSetFlag(tv, THV_CLOSED | THV_INIT_DONE | THV_RUNNING_DONE); + goto error; + } else { + EngineKill(); + TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); + goto error; + } + } + (void)SC_ATOMIC_SET(slot->slot_data, slot_data); + } + memset(&slot->slot_pre_pq, 0, sizeof(PacketQueue)); + SCMutexInit(&slot->slot_pre_pq.mutex_q, NULL); + memset(&slot->slot_post_pq, 0, sizeof(PacketQueue)); + SCMutexInit(&slot->slot_post_pq.mutex_q, NULL); + + /* get the 'pre qeueue' from module before the stream module */ + if (slot->slot_next != NULL && slot->slot_next->tm_id == TMM_STREAMTCP) { + SCLogDebug("pre-stream packetqueue %p (postq)", &s->slot_post_pq); + tv->stream_pq = &slot->slot_post_pq; + /* if the stream module is the first, get the threads input queue */ + } else if (slot == (TmSlot *)tv->tm_slots && slot->tm_id == TMM_STREAMTCP) { + tv->stream_pq = &trans_q[tv->inq->id]; + SCLogDebug("pre-stream packetqueue %p (inq)", &slot->slot_pre_pq); + } + } + + StatsSetupPrivate(tv); + + TmThreadsSetFlag(tv, THV_INIT_DONE); + + while(run) { + /* run right away */ + + r = s->PktAcqLoop(tv, SC_ATOMIC_GET(s->slot_data), s); + + if (r == TM_ECODE_FAILED || TmThreadsCheckFlag(tv, THV_KILL_PKTACQ) + || suricata_ctl_flags) { + run = 0; + } + if (r == TM_ECODE_DONE) { + run = 0; + } + } + StatsSyncCounters(tv); + + TmThreadsSetFlag(tv, THV_FLOW_LOOP); + + TmThreadsSetFlag(tv, THV_RUNNING_DONE); + + PacketPoolDestroy(); + + for (slot = s; slot != NULL; slot = slot->slot_next) { + if (slot->SlotThreadExitPrintStats != NULL) { + slot->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(slot->slot_data)); + } + + if (slot->SlotThreadDeinit != NULL) { + r = slot->SlotThreadDeinit(tv, SC_ATOMIC_GET(slot->slot_data)); + if (r != TM_ECODE_OK) { + TmThreadsSetFlag(tv, THV_CLOSED); + goto error; + } + } + + BUG_ON(slot->slot_pre_pq.len); + BUG_ON(slot->slot_post_pq.len); + } + + tv->stream_pq = NULL; + SCLogDebug("%s ending", tv->name); + TmThreadsSetFlag(tv, THV_CLOSED); + return NULL; + +error: + tv->stream_pq = NULL; + return NULL; +} +#endif /** * \todo Only the first "slot" currently makes the "post_pq" available @@ -655,7 +769,11 @@ TmEcode TmThreadSetSlots(ThreadVars *tv, char *name, void *(*fn_p)(void *)) if (strcmp(name, "varslot") == 0) { tv->tm_func = TmThreadsSlotVar; } else if (strcmp(name, "pktacqloop") == 0) { +#ifndef AFLFUZZ_PCAP_RUNMODE tv->tm_func = TmThreadsSlotPktAcqLoop; +#else + tv->tm_func = TmThreadsSlotPktAcqLoopAFL; +#endif } else if (strcmp(name, "management") == 0) { tv->tm_func = TmThreadsManagement; } else if (strcmp(name, "command") == 0) { From d46183751180a87b7ab3461334db4044fad5864c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 8 Dec 2015 10:42:03 +0100 Subject: [PATCH 1261/2553] afl: add --afl-parse-rules to return 0 on any rule When fuzzing, AFL will create lots of malformed rules. We don't want to error out on those. As we're fuzzing the parser any non-crash should return 0. Crashes (ASAN or not) will return a non-0 code. --- src/suricata-common.h | 1 + src/suricata.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/suricata-common.h b/src/suricata-common.h index da6487e162cc..ea97b3303b4a 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -231,6 +231,7 @@ #define AFLFUZZ_NO_RANDOM 1 #define AFLFUZZ_DISABLE_MGTTHREADS 1 #define AFLFUZZ_PCAP_RUNMODE 1 +#define AFLFUZZ_CONF_TEST 1 /* we need this to stringify the defines which are supplied at compiletime see: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/cpp/Stringification.html#Stringification */ diff --git a/src/suricata.c b/src/suricata.c index 68736961f77d..543f662fc294 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1113,6 +1113,9 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) int list_keywords = 0; int build_info = 0; int conf_test = 0; +#ifdef AFLFUZZ_CONF_TEST + int conf_test_force_success = 0; +#endif int engine_analysis = 0; int set_log_directory = 0; int ret = TM_ECODE_OK; @@ -1167,6 +1170,9 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"set", required_argument, 0, 0}, #ifdef HAVE_NFLOG {"nflog", optional_argument, 0, 0}, +#endif +#ifdef AFLFUZZ_CONF_TEST + {"afl-parse-rules", 0, &conf_test_force_success, 1}, #endif {NULL, 0, NULL, 0} }; @@ -1761,6 +1767,11 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) SCLogError(SC_ERR_INITIALIZATION, "can't use -s/-S when detection is disabled"); return TM_ECODE_FAILED; } +#ifdef AFLFUZZ_CONF_TEST + if (conf_test && conf_test_force_success) { + (void)ConfSetFinal("engine.init-failure-fatal", "0"); + } +#endif if ((suri->run_mode == RUNMODE_UNIX_SOCKET) && set_log_directory) { SCLogError(SC_ERR_INITIALIZATION, "can't use -l and unix socket runmode at the same time"); From 09242fb4a8a04c2ed9486cf973862d6a89269397 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 8 Dec 2015 19:55:40 +0100 Subject: [PATCH 1262/2553] afl: optionally exit right after afl single runmode Exit right away if afl.exit_after_pcap is set to true. Safes time as fuzzing the shutdown code may not be as interesting. --- src/runmode-pcap-file.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index 4d44814be73b..eede9f4d11dc 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -125,6 +125,12 @@ int RunModeFilePcapSingle(void) /* in afl mode we don't spawn a new thread, but run the pipeline * in the main thread */ tv->tm_func(tv); + int afl_runmode_exit_immediately = 0; + (void)ConfGetBool("afl.exit_after_pcap", &afl_runmode_exit_immediately); + if (afl_runmode_exit_immediately) { + SCLogNotice("exit because of afl-runmode-exit-after-pcap commandline option"); + exit(EXIT_SUCCESS); + } #endif return 0; From ca81c33e14219adbf90af3894e05f69bb85774c8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 8 Feb 2016 16:32:47 +0100 Subject: [PATCH 1263/2553] afl: add --enable-afl configure option --- configure.ac | 10 ++++++++++ src/suricata-common.h | 5 ----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index e9de6f2d12cf..21e07fc40b96 100644 --- a/configure.ac +++ b/configure.ac @@ -259,6 +259,16 @@ esac AC_MSG_RESULT(ok) + # enable modifications for AFL fuzzing + AC_ARG_ENABLE(afl, + AS_HELP_STRING([--enable-afl], Enable AFL fuzzing logic[])], [enable_afl="$enableval"],[enable_afl=no]) + AS_IF([test "x$enable_afl" = "xyes"], [ + AC_DEFINE([AFLFUZZ_NO_RANDOM], [1], [Disable all use of random functions]) + AC_DEFINE([AFLFUZZ_DISABLE_MGTTHREADS], [1], [Disable all management threads]) + AC_DEFINE([AFLFUZZ_PCAP_RUNMODE], [1], [Enable special AFL 'single' runmode]) + AC_DEFINE([AFLFUZZ_CONF_TEST], [1], [Enable special --afl-parse-rules commandline option]) + ]) + # disable TLS on user request AC_ARG_ENABLE(threading-tls, AS_HELP_STRING([--disable-threading-tls], [Disable TLS (thread local storage)]), [enable_tls="$enableval"],[enable_tls=yes]) diff --git a/src/suricata-common.h b/src/suricata-common.h index ea97b3303b4a..18791c3b04bc 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -228,11 +228,6 @@ #endif #endif -#define AFLFUZZ_NO_RANDOM 1 -#define AFLFUZZ_DISABLE_MGTTHREADS 1 -#define AFLFUZZ_PCAP_RUNMODE 1 -#define AFLFUZZ_CONF_TEST 1 - /* we need this to stringify the defines which are supplied at compiletime see: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/cpp/Stringification.html#Stringification */ #define xstr(s) str(s) From 077ac81688c335724532ed97796cce0322f31253 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Mar 2016 12:00:22 +0100 Subject: [PATCH 1264/2553] QA: direct access from commandline to AppLayer API This patch introduces a new set of commandline options meant for assisting in fuzz testing the app layer implementations. Per protocol, 2 commandline options are added: --afl-http-request= --afl-http= In the former case, the contents of the file are passed directly to the HTTP parser as request data. In the latter case, the data is devided between request and responses. First 64 bytes are request, then next 64 are response, next 64 are request, etc, etc. --- configure.ac | 1 + src/app-layer-htp.c | 6 ++ src/app-layer-modbus.c | 9 ++- src/app-layer-parser.c | 135 +++++++++++++++++++++++++++++++++++++++++ src/app-layer-parser.h | 5 ++ src/suricata.c | 109 +++++++++++++++++++++++++++++++++ 6 files changed, 264 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 21e07fc40b96..47fe5e942dee 100644 --- a/configure.ac +++ b/configure.ac @@ -267,6 +267,7 @@ AC_DEFINE([AFLFUZZ_DISABLE_MGTTHREADS], [1], [Disable all management threads]) AC_DEFINE([AFLFUZZ_PCAP_RUNMODE], [1], [Enable special AFL 'single' runmode]) AC_DEFINE([AFLFUZZ_CONF_TEST], [1], [Enable special --afl-parse-rules commandline option]) + AC_DEFINE([AFLFUZZ_APPLAYER], [1], [Enable --afl-$proto-request commandline option]) ]) # disable TLS on user request diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 50ff3e731460..a3db82b1895b 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2162,7 +2162,11 @@ static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec) cfg_prec->request_inspect_window = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW; cfg_prec->response_inspect_min_size = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE; cfg_prec->response_inspect_window = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW; +#ifndef AFLFUZZ_NO_RANDOM cfg_prec->randomize = HTP_CONFIG_DEFAULT_RANDOMIZE; +#else + cfg_prec->randomize = 0; +#endif cfg_prec->randomize_range = HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE; htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData); @@ -2441,7 +2445,9 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT, (size_t)limit); } else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) { +#ifndef AFLFUZZ_NO_RANDOM cfg_prec->randomize = ConfValIsTrue(p->val); +#endif } else if (strcasecmp("randomize-inspection-range", p->name) == 0) { uint32_t range = atoi(p->val); if (range > 100) { diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 827f4042e3c5..e55c431bf100 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1433,7 +1433,9 @@ void RegisterModbusParsers(void) proto_name, ALPROTO_MODBUS, 0, sizeof(ModbusHeader), ModbusProbingParser)) { +#ifndef AFLFUZZ_APPLAYER return; +#endif } } @@ -1448,11 +1450,16 @@ void RegisterModbusParsers(void) } SCLogInfo("Modbus request flood protection level: %u", request_flood); } else { +#ifndef AFLFUZZ_APPLAYER SCLogInfo("Protocol detection and parser disabled for %s protocol.", proto_name); return; +#endif } - +#ifndef AFLFUZZ_APPLAYER if (AppLayerParserConfParserEnabled("tcp", proto_name)) { +#else + if (1) { +#endif AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOSERVER, ModbusParseRequest); AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOCLIENT, ModbusParseResponse); AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateAlloc, ModbusStateFree); diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index ffbc0978af01..51efa30d4028 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -1189,6 +1189,141 @@ void AppLayerParserStatePrintDetails(AppLayerParserState *pstate) } #endif +#ifdef AFLFUZZ_APPLAYER +int AppLayerParserRequestFromFile(AppProto alproto, char *filename) +{ + int result = 1; + Flow *f = NULL; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = SCCalloc(1, sizeof(Flow)); + if (f == NULL) + goto end; + FLOW_INITIALIZE(f); + + f->flags |= FLOW_IPV4; + f->src.addr_data32[0] = 0x01020304; + f->dst.addr_data32[0] = 0x05060708; + f->sp = 10000; + f->dp = 80; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = alproto; + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + uint8_t buffer[256]; + + int start = 1; + while (1) { + int done = 0; + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) + done = 1; + + //SCLogInfo("result %u done %d start %d", (uint)result, done, start); + + uint8_t flags = STREAM_TOSERVER; + + if (start--) { + flags |= STREAM_START; + } + if (done) { + flags |= STREAM_EOF; + } + //PrintRawDataFp(stdout, buffer, result); + + (void)AppLayerParserParse(alp_tctx, f, alproto, flags, buffer, result); + if (done) + break; + } + + result = 0; + fclose(fp); +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (f != NULL) { + FlowFree(f); + } + return result; +} + +int AppLayerParserFromFile(AppProto alproto, char *filename) +{ + int result = 1; + Flow *f = NULL; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = SCCalloc(1, sizeof(Flow)); + if (f == NULL) + goto end; + FLOW_INITIALIZE(f); + + f->flags |= FLOW_IPV4; + f->src.addr_data32[0] = 0x01020304; + f->dst.addr_data32[0] = 0x05060708; + f->sp = 10000; + f->dp = 80; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = alproto; + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + uint8_t buffer[64]; + + int start = 1; + int flip = 0; + while (1) { + int done = 0; + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) + done = 1; + + //SCLogInfo("result %u done %d start %d", (uint)result, done, start); + + uint8_t flags = 0; + if (flip) { + flags = STREAM_TOCLIENT; + flip = 0; + } else { + flags = STREAM_TOSERVER; + flip = 1; + } + + if (start--) { + flags |= STREAM_START; + } + if (done) { + flags |= STREAM_EOF; + } + //PrintRawDataFp(stdout, buffer, result); + + (void)AppLayerParserParse(alp_tctx, f, alproto, flags, buffer, result); + if (done) + break; + } + + result = 0; + fclose(fp); +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (f != NULL) { + FlowFree(f); + } + return result; +} +#endif /***** Unittests *****/ diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index 62cb8f68691f..2dee75e7c76f 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -222,6 +222,11 @@ void AppLayerParserStateFree(AppLayerParserState *pstate); void AppLayerParserStatePrintDetails(AppLayerParserState *pstate); #endif +#ifdef AFLFUZZ_APPLAYER +int AppLayerParserRequestFromFile(AppProto alproto, char *filename); +int AppLayerParserFromFile(AppProto alproto, char *filename); +#endif + /***** Unittests *****/ #ifdef UNITTESTS diff --git a/src/suricata.c b/src/suricata.c index 543f662fc294..d3b069ef6a54 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -145,6 +145,13 @@ #include "app-layer.h" #include "app-layer-parser.h" #include "app-layer-htp.h" +#include "app-layer-ssl.h" +#include "app-layer-dns-tcp.h" +#include "app-layer-ssh.h" +#include "app-layer-ftp.h" +#include "app-layer-smtp.h" +#include "app-layer-smb.h" +#include "app-layer-modbus.h" #include "util-radix-tree.h" #include "util-host-os-info.h" @@ -1136,6 +1143,22 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"netmap", optional_argument, 0, 0}, {"pcap", optional_argument, 0, 0}, {"simulate-ips", 0, 0 , 0}, + {"afl-http-request", required_argument, 0 , 0}, + {"afl-http", required_argument, 0 , 0}, + {"afl-tls-request", required_argument, 0 , 0}, + {"afl-tls", required_argument, 0 , 0}, + {"afl-dns-request", required_argument, 0 , 0}, + {"afl-dns", required_argument, 0 , 0}, + {"afl-ssh-request", required_argument, 0 , 0}, + {"afl-ssh", required_argument, 0 , 0}, + {"afl-ftp-request", required_argument, 0 , 0}, + {"afl-ftp", required_argument, 0 , 0}, + {"afl-smtp-request", required_argument, 0 , 0}, + {"afl-smtp", required_argument, 0 , 0}, + {"afl-smb-request", required_argument, 0 , 0}, + {"afl-smb", required_argument, 0 , 0}, + {"afl-modbus-request", required_argument, 0 , 0}, + {"afl-modbus", required_argument, 0 , 0}, #ifdef BUILD_UNIX_SOCKET {"unix-socket", optional_argument, 0, 0}, #endif @@ -1324,6 +1347,92 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) usage(argv[0]); return TM_ECODE_FAILED; } +#ifdef AFLFUZZ_APPLAYER + } else if(strcmp((long_opts[option_index]).name, "afl-http-request") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterHTPParsers(); + exit(AppLayerParserRequestFromFile(ALPROTO_HTTP, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-http") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterHTPParsers(); + exit(AppLayerParserFromFile(ALPROTO_HTTP, optarg)); + + } else if(strcmp((long_opts[option_index]).name, "afl-tls-request") == 0) { + //printf("arg: //%s\n", optarg); + RegisterSSLParsers(); + exit(AppLayerParserRequestFromFile(ALPROTO_TLS, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-tls") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterSSLParsers(); + exit(AppLayerParserFromFile(ALPROTO_TLS, optarg)); + + } else if(strcmp((long_opts[option_index]).name, "afl-dns-request") == 0) { + //printf("arg: //%s\n", optarg); + RegisterDNSTCPParsers(); + exit(AppLayerParserRequestFromFile(ALPROTO_DNS, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-dns") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterDNSTCPParsers(); + exit(AppLayerParserFromFile(ALPROTO_DNS, optarg)); + + } else if(strcmp((long_opts[option_index]).name, "afl-ssh-request") == 0) { + //printf("arg: //%s\n", optarg); + RegisterSSHParsers(); + exit(AppLayerParserRequestFromFile(ALPROTO_SSH, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-ssh") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterSSHParsers(); + exit(AppLayerParserFromFile(ALPROTO_SSH, optarg)); + + } else if(strcmp((long_opts[option_index]).name, "afl-ftp-request") == 0) { + //printf("arg: //%s\n", optarg); + RegisterFTPParsers(); + exit(AppLayerParserRequestFromFile(ALPROTO_FTP, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-ftp") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterFTPParsers(); + exit(AppLayerParserFromFile(ALPROTO_FTP, optarg)); + + } else if(strcmp((long_opts[option_index]).name, "afl-smtp-request") == 0) { + //printf("arg: //%s\n", optarg); + MpmTableSetup(); + AppLayerParserSetup(); + RegisterSMTPParsers(); + exit(AppLayerParserRequestFromFile(ALPROTO_SMTP, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-smtp") == 0) { + //printf("arg: //%s\n", optarg); + MpmTableSetup(); + AppLayerParserSetup(); + RegisterSMTPParsers(); + exit(AppLayerParserFromFile(ALPROTO_SMTP, optarg)); + + } else if(strcmp((long_opts[option_index]).name, "afl-smb-request") == 0) { + //printf("arg: //%s\n", optarg); + RegisterSMBParsers(); + exit(AppLayerParserRequestFromFile(ALPROTO_SMB, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-smb") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterSMBParsers(); + exit(AppLayerParserFromFile(ALPROTO_SMB, optarg)); + + } else if(strcmp((long_opts[option_index]).name, "afl-modbus-request") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterModbusParsers(); + exit(AppLayerParserRequestFromFile(ALPROTO_MODBUS, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-modbus") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterModbusParsers(); + exit(AppLayerParserFromFile(ALPROTO_MODBUS, optarg)); +#endif } else if(strcmp((long_opts[option_index]).name, "simulate-ips") == 0) { SCLogInfo("Setting IPS mode"); EngineModeSetIPS(); From bdaba1d8156a948934686f4f4aa25303a238b1f6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 25 Mar 2016 14:25:22 +0100 Subject: [PATCH 1265/2553] QA: expose Mime decoding API to commandline using --afl-mime= --- configure.ac | 1 + src/suricata.c | 6 ++++++ src/util-decode-mime.c | 46 ++++++++++++++++++++++++++++++++++++++++++ src/util-decode-mime.h | 4 ++++ 4 files changed, 57 insertions(+) diff --git a/configure.ac b/configure.ac index 47fe5e942dee..e0e2efdbd6b6 100644 --- a/configure.ac +++ b/configure.ac @@ -268,6 +268,7 @@ AC_DEFINE([AFLFUZZ_PCAP_RUNMODE], [1], [Enable special AFL 'single' runmode]) AC_DEFINE([AFLFUZZ_CONF_TEST], [1], [Enable special --afl-parse-rules commandline option]) AC_DEFINE([AFLFUZZ_APPLAYER], [1], [Enable --afl-$proto-request commandline option]) + AC_DEFINE([AFLFUZZ_MIME], [1], [Enable --afl-mime commandline option]) ]) # disable TLS on user request diff --git a/src/suricata.c b/src/suricata.c index d3b069ef6a54..e3edc0d49300 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1159,6 +1159,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"afl-smb", required_argument, 0 , 0}, {"afl-modbus-request", required_argument, 0 , 0}, {"afl-modbus", required_argument, 0 , 0}, + {"afl-mime", required_argument, 0 , 0}, #ifdef BUILD_UNIX_SOCKET {"unix-socket", optional_argument, 0, 0}, #endif @@ -1432,6 +1433,11 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerParserSetup(); RegisterModbusParsers(); exit(AppLayerParserFromFile(ALPROTO_MODBUS, optarg)); +#endif +#ifdef AFLFUZZ_MIME + } else if(strcmp((long_opts[option_index]).name, "afl-mime") == 0) { + //printf("arg: //%s\n", optarg); + exit(MimeParserDataFromFile(optarg)); #endif } else if(strcmp((long_opts[option_index]).name, "simulate-ips") == 0) { SCLogInfo("Setting IPS mode"); diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 8ba56b6f1c04..7d8e88843780 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -2614,6 +2614,52 @@ MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *dat return msg; } +#ifdef AFLFUZZ_MIME +static int MimeParserDataFromFileCB(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state) +{ + return MIME_DEC_OK; +} + +int MimeParserDataFromFile(char *filename) +{ + int result = 1; + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + uint8_t buffer[256]; + + uint32_t line_count = 0; + + MimeDecParseState *state = MimeDecInitParser(&line_count, + MimeParserDataFromFileCB); + + while (1) { + int done = 0; + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) + done = 1; + + (void) MimeDecParseLine(buffer, result, 1, state); + + if (done) + break; + } + + /* Completed */ + (void)MimeDecParseComplete(state); + + if (state->msg) { + MimeDecFreeEntity(state->msg); + } + /* De Init parser */ + MimeDecDeInitParser(state); + + result = 0; + fclose(fp); + return result; +} +#endif + #ifdef UNITTESTS /* Helper body chunk callback function */ diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h index 02b3bb13dd95..0e5fb7cb0516 100644 --- a/src/util-decode-mime.h +++ b/src/util-decode-mime.h @@ -239,6 +239,10 @@ MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *dat int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); const char *MimeDecParseStateGetStatus(MimeDecParseState *state); +#ifdef AFLFUZZ_MIME +int MimeParserDataFromFile(char *filename); +#endif + /* Test functions */ void MimeDecRegisterTests(void); From d16590639798ffed6a6b078aecc074c97ee1b694 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Mar 2016 18:18:20 +0200 Subject: [PATCH 1266/2553] QA: add --afl-decoder-ppp= --- configure.ac | 1 + src/decode.c | 37 +++++++++++++++++++++++++++++++++++++ src/decode.h | 7 +++++++ src/suricata.c | 12 ++++++++++++ 4 files changed, 57 insertions(+) diff --git a/configure.ac b/configure.ac index e0e2efdbd6b6..f3741e578b77 100644 --- a/configure.ac +++ b/configure.ac @@ -269,6 +269,7 @@ AC_DEFINE([AFLFUZZ_CONF_TEST], [1], [Enable special --afl-parse-rules commandline option]) AC_DEFINE([AFLFUZZ_APPLAYER], [1], [Enable --afl-$proto-request commandline option]) AC_DEFINE([AFLFUZZ_MIME], [1], [Enable --afl-mime commandline option]) + AC_DEFINE([AFLFUZZ_DECODER], [1], [Enable --afl-decoder-$proto commandline option]) ]) # disable TLS on user request diff --git a/src/decode.c b/src/decode.c index 80d603a78190..75159f6f32f7 100644 --- a/src/decode.c +++ b/src/decode.c @@ -580,6 +580,43 @@ void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s) s->counter_ips_replaced = StatsRegisterCounter("ips.replaced", tv); } +#ifdef AFLFUZZ_DECODER +int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder) { + int result = 1; + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + uint8_t buffer[65536]; + + ThreadVars tv; + memset(&tv, 0, sizeof(tv)); + DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv); + DecodeRegisterPerfCounters(dtv, &tv); + StatsSetupPrivate(&tv); + + while (1) { + int done = 0; + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) + done = 1; + + Packet *p = PacketGetFromAlloc(); + if (p != NULL) { + (void) Decoder (&tv, dtv, p, buffer, result, NULL); + PacketFree(p); + } + + if (done) + break; + } + DecodeThreadVarsFree(&tv, dtv); + + result = 0; + fclose(fp); + return result; + +} +#endif + /** * @} */ diff --git a/src/decode.h b/src/decode.h index 313bd3f51df7..4c83d08300c8 100644 --- a/src/decode.h +++ b/src/decode.h @@ -907,6 +907,13 @@ int DecodeERSPAN(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t void AddressDebugPrint(Address *); +#ifdef AFLFUZZ_DECODER +typedef int (*DecoderFunc)(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, + uint8_t *pkt, uint16_t len, PacketQueue *pq); + +int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder); +#endif + /** \brief Set the No payload inspection Flag for the packet. * * \param p Packet to set the flag in diff --git a/src/suricata.c b/src/suricata.c index e3edc0d49300..a81b81682410 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1160,6 +1160,8 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"afl-modbus-request", required_argument, 0 , 0}, {"afl-modbus", required_argument, 0 , 0}, {"afl-mime", required_argument, 0 , 0}, + + {"afl-decoder-ppp", required_argument, 0 , 0}, #ifdef BUILD_UNIX_SOCKET {"unix-socket", optional_argument, 0, 0}, #endif @@ -1438,6 +1440,16 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) } else if(strcmp((long_opts[option_index]).name, "afl-mime") == 0) { //printf("arg: //%s\n", optarg); exit(MimeParserDataFromFile(optarg)); +#endif +#ifdef AFLFUZZ_DECODER + } else if(strcmp((long_opts[option_index]).name, "afl-decoder-ppp") == 0) { + StatsInit(); + MpmTableSetup(); + AppLayerProtoDetectSetup(); + DefragInit(); + FlowInitConfig(FLOW_QUIET); + //printf("arg: //%s\n", optarg); + exit(DecoderParseDataFromFile(optarg, DecodePPP)); #endif } else if(strcmp((long_opts[option_index]).name, "simulate-ips") == 0) { SCLogInfo("Setting IPS mode"); From 8111eb934fa8d874dae9b0cee2726b9d9b96ed35 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Sun, 10 Apr 2016 13:41:02 +0200 Subject: [PATCH 1267/2553] QA: add --afl-der= Expose SSL/TLS certificate decoding (DER) to commandline using --afl-der=. --- configure.ac | 1 + src/suricata.c | 7 +++++++ src/util-decode-der.c | 28 ++++++++++++++++++++++++++++ src/util-decode-der.h | 4 ++++ 4 files changed, 40 insertions(+) diff --git a/configure.ac b/configure.ac index f3741e578b77..a6c3f3aa8cda 100644 --- a/configure.ac +++ b/configure.ac @@ -270,6 +270,7 @@ AC_DEFINE([AFLFUZZ_APPLAYER], [1], [Enable --afl-$proto-request commandline option]) AC_DEFINE([AFLFUZZ_MIME], [1], [Enable --afl-mime commandline option]) AC_DEFINE([AFLFUZZ_DECODER], [1], [Enable --afl-decoder-$proto commandline option]) + AC_DEFINE([AFLFUZZ_DER], [1], [Enable --afl-der commandline option]) ]) # disable TLS on user request diff --git a/src/suricata.c b/src/suricata.c index a81b81682410..d2d816028e75 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -153,6 +153,7 @@ #include "app-layer-smb.h" #include "app-layer-modbus.h" +#include "util-decode-der.h" #include "util-radix-tree.h" #include "util-host-os-info.h" #include "util-cidr.h" @@ -1162,6 +1163,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"afl-mime", required_argument, 0 , 0}, {"afl-decoder-ppp", required_argument, 0 , 0}, + {"afl-der", required_argument, 0, 0}, #ifdef BUILD_UNIX_SOCKET {"unix-socket", optional_argument, 0, 0}, #endif @@ -1450,6 +1452,11 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) FlowInitConfig(FLOW_QUIET); //printf("arg: //%s\n", optarg); exit(DecoderParseDataFromFile(optarg, DecodePPP)); +#endif +#ifdef AFLFUZZ_DER + } else if(strcmp((long_opts[option_index]).name, "afl-der") == 0) { + //printf("arg: //%s\n", optarg); + exit(DerParseDataFromFile(optarg)); #endif } else if(strcmp((long_opts[option_index]).name, "simulate-ips") == 0) { SCLogInfo("Setting IPS mode"); diff --git a/src/util-decode-der.c b/src/util-decode-der.c index be56b5e546f7..c080cefd9353 100644 --- a/src/util-decode-der.c +++ b/src/util-decode-der.c @@ -898,6 +898,34 @@ Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, return cert; } +#ifdef AFLFUZZ_DER +int DerParseDataFromFile(char *filename) +{ + int result = 1; + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + uint8_t buffer[65536]; + + uint32_t errcode = 0; + + while (1) { + int done = 0; + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) + done = 1; + + DecodeDer(buffer, result, &errcode); + + if (done) + break; + } + + result = 0; + fclose(fp); + return result; +} +#endif + void DerFree(Asn1Generic *a) { Asn1Generic *it, *n; diff --git a/src/util-decode-der.h b/src/util-decode-der.h index 4c4b1aaf1c4a..b923c12d40cd 100644 --- a/src/util-decode-der.h +++ b/src/util-decode-der.h @@ -93,4 +93,8 @@ typedef struct Asn1Generic_ { Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *errcode); void DerFree(Asn1Generic *a); +#ifdef AFLFUZZ_DER +int DerParseDataFromFile(char *filename); +#endif + #endif /* __UTIL_DECODE_DER_H__ */ From 45d87d66c031307dc70c25734f4fc508143d50eb Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 12 Apr 2016 12:07:43 +0200 Subject: [PATCH 1268/2553] afl: add support for AFL PERSISTANT_MODE Add support for AFL PERSISTANT_MODE when Suricata is compiled with a supported compiler (only afl-clang-fast for now). This gives a ~10x performance boost when fuzzing. --- configure.ac | 39 ++++++++----- src/app-layer-parser.c | 125 ++++++++++++++++++++++++----------------- src/decode.c | 60 ++++++++++++-------- src/util-decode-der.c | 29 +++++----- src/util-decode-mime.c | 57 +++++++++++-------- 5 files changed, 184 insertions(+), 126 deletions(-) diff --git a/configure.ac b/configure.ac index a6c3f3aa8cda..2c294fdbe32d 100644 --- a/configure.ac +++ b/configure.ac @@ -8,6 +8,31 @@ AC_LANG_C AC_PROG_CC_C99 + + # enable modifications for AFL fuzzing + AC_ARG_ENABLE(afl, + AS_HELP_STRING([--enable-afl], Enable AFL fuzzing logic[])], [enable_afl="$enableval"],[enable_afl=no]) + + AS_IF([test "x$enable_afl" = "xyes"], [ + AC_DISABLE_SHARED + AC_DEFINE([AFLFUZZ_NO_RANDOM], [1], [Disable all use of random functions]) + AC_DEFINE([AFLFUZZ_DISABLE_MGTTHREADS], [1], [Disable all management threads]) + AC_DEFINE([AFLFUZZ_PCAP_RUNMODE], [1], [Enable special AFL 'single' runmode]) + AC_DEFINE([AFLFUZZ_CONF_TEST], [1], [Enable special --afl-parse-rules commandline option]) + AC_DEFINE([AFLFUZZ_APPLAYER], [1], [Enable --afl-$proto-request commandline option]) + AC_DEFINE([AFLFUZZ_MIME], [1], [Enable --afl-mime commandline option]) + AC_DEFINE([AFLFUZZ_DECODER], [1], [Enable --afl-decoder-$proto commandline option]) + AC_DEFINE([AFLFUZZ_DER], [1], [Enable --afl-der commandline option]) + + # test for AFL PERSISTANT_MODE support + CFLAGS_ORIG=$CFLAGS + CFLAGS="-Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[while (__AFL_LOOP(1000))]])], + [AC_DEFINE([AFLFUZZ_PERSISTANT_MODE], [1], [Enable AFL PERSISTANT_MODE])], + []) + CFLAGS=$CFLAGS_ORIG + ]) + AC_PROG_LIBTOOL PKG_PROG_PKG_CONFIG(0.21) # 0.21 is the CentOS 5.11 version @@ -259,20 +284,6 @@ esac AC_MSG_RESULT(ok) - # enable modifications for AFL fuzzing - AC_ARG_ENABLE(afl, - AS_HELP_STRING([--enable-afl], Enable AFL fuzzing logic[])], [enable_afl="$enableval"],[enable_afl=no]) - AS_IF([test "x$enable_afl" = "xyes"], [ - AC_DEFINE([AFLFUZZ_NO_RANDOM], [1], [Disable all use of random functions]) - AC_DEFINE([AFLFUZZ_DISABLE_MGTTHREADS], [1], [Disable all management threads]) - AC_DEFINE([AFLFUZZ_PCAP_RUNMODE], [1], [Enable special AFL 'single' runmode]) - AC_DEFINE([AFLFUZZ_CONF_TEST], [1], [Enable special --afl-parse-rules commandline option]) - AC_DEFINE([AFLFUZZ_APPLAYER], [1], [Enable --afl-$proto-request commandline option]) - AC_DEFINE([AFLFUZZ_MIME], [1], [Enable --afl-mime commandline option]) - AC_DEFINE([AFLFUZZ_DECODER], [1], [Enable --afl-decoder-$proto commandline option]) - AC_DEFINE([AFLFUZZ_DER], [1], [Enable --afl-der commandline option]) - ]) - # disable TLS on user request AC_ARG_ENABLE(threading-tls, AS_HELP_STRING([--disable-threading-tls], [Disable TLS (thread local storage)]), [enable_tls="$enableval"],[enable_tls=yes]) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 51efa30d4028..d7aeb81cc177 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -1213,37 +1213,49 @@ int AppLayerParserRequestFromFile(AppProto alproto, char *filename) f->proto = IPPROTO_TCP; f->alproto = alproto; - FILE *fp = fopen(filename, "r"); - BUG_ON(fp == NULL); + uint8_t buffer[64]; - uint8_t buffer[256]; +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ - int start = 1; - while (1) { - int done = 0; - size_t result = fread(&buffer, 1, sizeof(buffer), fp); - if (result < sizeof(buffer)) - done = 1; + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); - //SCLogInfo("result %u done %d start %d", (uint)result, done, start); + int start = 1; + while (1) { + int done = 0; + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) + done = 1; - uint8_t flags = STREAM_TOSERVER; + //SCLogInfo("result %u done %d start %d", (uint)result, done, start); - if (start--) { - flags |= STREAM_START; - } - if (done) { - flags |= STREAM_EOF; + uint8_t flags = STREAM_TOSERVER; + + if (start--) { + flags |= STREAM_START; + } + if (done) { + flags |= STREAM_EOF; + } + //PrintRawDataFp(stdout, buffer, result); + + (void)AppLayerParserParse(alp_tctx, f, alproto, flags, buffer, result); + if (done) + break; } - //PrintRawDataFp(stdout, buffer, result); - (void)AppLayerParserParse(alp_tctx, f, alproto, flags, buffer, result); - if (done) - break; + fclose(fp); + +#ifdef AFLFUZZ_PERSISTANT_MODE } +#endif /* AFLFUZZ_PERSISTANT_MODE */ result = 0; - fclose(fp); + end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -1276,45 +1288,56 @@ int AppLayerParserFromFile(AppProto alproto, char *filename) f->proto = IPPROTO_TCP; f->alproto = alproto; - FILE *fp = fopen(filename, "r"); - BUG_ON(fp == NULL); - uint8_t buffer[64]; - int start = 1; - int flip = 0; - while (1) { - int done = 0; - size_t result = fread(&buffer, 1, sizeof(buffer), fp); - if (result < sizeof(buffer)) - done = 1; +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + int start = 1; + int flip = 0; + while (1) { + int done = 0; + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) + done = 1; + + //SCLogInfo("result %u done %d start %d", (uint)result, done, start); + + uint8_t flags = 0; + if (flip) { + flags = STREAM_TOCLIENT; + flip = 0; + } else { + flags = STREAM_TOSERVER; + flip = 1; + } - //SCLogInfo("result %u done %d start %d", (uint)result, done, start); + if (start--) { + flags |= STREAM_START; + } + if (done) { + flags |= STREAM_EOF; + } + //PrintRawDataFp(stdout, buffer, result); - uint8_t flags = 0; - if (flip) { - flags = STREAM_TOCLIENT; - flip = 0; - } else { - flags = STREAM_TOSERVER; - flip = 1; + (void)AppLayerParserParse(alp_tctx, f, alproto, flags, buffer, result); + if (done) + break; } - if (start--) { - flags |= STREAM_START; - } - if (done) { - flags |= STREAM_EOF; - } - //PrintRawDataFp(stdout, buffer, result); + fclose(fp); - (void)AppLayerParserParse(alp_tctx, f, alproto, flags, buffer, result); - if (done) - break; +#ifdef AFLFUZZ_PERSISTANT_MODE } +#endif /* AFLFUZZ_PERSISTANT_MODE */ result = 0; - fclose(fp); end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -1323,7 +1346,7 @@ int AppLayerParserFromFile(AppProto alproto, char *filename) } return result; } -#endif +#endif /* AFLFUZZ_APPLAYER */ /***** Unittests *****/ diff --git a/src/decode.c b/src/decode.c index 75159f6f32f7..1b73722e3ab1 100644 --- a/src/decode.c +++ b/src/decode.c @@ -582,40 +582,52 @@ void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s) #ifdef AFLFUZZ_DECODER int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder) { - int result = 1; - FILE *fp = fopen(filename, "r"); - BUG_ON(fp == NULL); uint8_t buffer[65536]; + int result = 1; + +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + ThreadVars tv; + memset(&tv, 0, sizeof(tv)); + DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv); + DecodeRegisterPerfCounters(dtv, &tv); + StatsSetupPrivate(&tv); + + while (1) { + int done = 0; + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) + done = 1; + + Packet *p = PacketGetFromAlloc(); + if (p != NULL) { + (void) Decoder (&tv, dtv, p, buffer, result, NULL); + PacketFree(p); + } - ThreadVars tv; - memset(&tv, 0, sizeof(tv)); - DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv); - DecodeRegisterPerfCounters(dtv, &tv); - StatsSetupPrivate(&tv); - - while (1) { - int done = 0; - size_t result = fread(&buffer, 1, sizeof(buffer), fp); - if (result < sizeof(buffer)) - done = 1; - - Packet *p = PacketGetFromAlloc(); - if (p != NULL) { - (void) Decoder (&tv, dtv, p, buffer, result, NULL); - PacketFree(p); + if (done) + break; } + DecodeThreadVarsFree(&tv, dtv); - if (done) - break; + fclose(fp); + +#ifdef AFLFUZZ_PERSISTANT_MODE } - DecodeThreadVarsFree(&tv, dtv); +#endif /* AFLFUZZ_PERSISTANT_MODE */ result = 0; - fclose(fp); return result; } -#endif +#endif /* AFLFUZZ_DECODER */ /** * @} diff --git a/src/util-decode-der.c b/src/util-decode-der.c index c080cefd9353..00c1bccaef07 100644 --- a/src/util-decode-der.c +++ b/src/util-decode-der.c @@ -901,30 +901,29 @@ Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, #ifdef AFLFUZZ_DER int DerParseDataFromFile(char *filename) { - int result = 1; - FILE *fp = fopen(filename, "r"); - BUG_ON(fp == NULL); uint8_t buffer[65536]; - uint32_t errcode = 0; - while (1) { - int done = 0; - size_t result = fread(&buffer, 1, sizeof(buffer), fp); - if (result < sizeof(buffer)) - done = 1; +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + size_t result = fread(&buffer, 1, sizeof(buffer), fp); DecodeDer(buffer, result, &errcode); + fclose(fp); - if (done) - break; +#ifdef AFLFUZZ_PERSISTANT_MODE } +#endif /* AFLFUZZ_PERSISTANT_MODE */ - result = 0; - fclose(fp); - return result; + return 0; } -#endif +#endif /* AFLFUZZ_DER */ void DerFree(Asn1Generic *a) { diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 7d8e88843780..81d8bc720bd1 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -2624,41 +2624,54 @@ static int MimeParserDataFromFileCB(const uint8_t *chunk, uint32_t len, int MimeParserDataFromFile(char *filename) { int result = 1; - FILE *fp = fopen(filename, "r"); - BUG_ON(fp == NULL); uint8_t buffer[256]; - uint32_t line_count = 0; +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ - MimeDecParseState *state = MimeDecInitParser(&line_count, - MimeParserDataFromFileCB); + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); - while (1) { - int done = 0; - size_t result = fread(&buffer, 1, sizeof(buffer), fp); - if (result < sizeof(buffer)) - done = 1; + uint32_t line_count = 0; - (void) MimeDecParseLine(buffer, result, 1, state); + MimeDecParseState *state = MimeDecInitParser(&line_count, + MimeParserDataFromFileCB); - if (done) - break; - } + while (1) { + int done = 0; + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) + done = 1; - /* Completed */ - (void)MimeDecParseComplete(state); + (void) MimeDecParseLine(buffer, result, 1, state); + + if (done) + break; + } - if (state->msg) { - MimeDecFreeEntity(state->msg); + /* Completed */ + (void)MimeDecParseComplete(state); + + if (state->msg) { + MimeDecFreeEntity(state->msg); + } + + /* De Init parser */ + MimeDecDeInitParser(state); + + fclose(fp); + +#ifdef AFLFUZZ_PERSISTANT_MODE } - /* De Init parser */ - MimeDecDeInitParser(state); +#endif /* AFLFUZZ_PERSISTANT_MODE */ result = 0; - fclose(fp); return result; } -#endif +#endif /* AFLFUZZ_MIME */ #ifdef UNITTESTS From faad6bd335274a244771177c036dcb59fca83d48 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 Apr 2016 09:08:59 +0200 Subject: [PATCH 1269/2553] configure: don't use AC_DISABLE_SHARED as it breaks OSX --- configure.ac | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/configure.ac b/configure.ac index 2c294fdbe32d..a54cc7d4b41a 100644 --- a/configure.ac +++ b/configure.ac @@ -8,31 +8,6 @@ AC_LANG_C AC_PROG_CC_C99 - - # enable modifications for AFL fuzzing - AC_ARG_ENABLE(afl, - AS_HELP_STRING([--enable-afl], Enable AFL fuzzing logic[])], [enable_afl="$enableval"],[enable_afl=no]) - - AS_IF([test "x$enable_afl" = "xyes"], [ - AC_DISABLE_SHARED - AC_DEFINE([AFLFUZZ_NO_RANDOM], [1], [Disable all use of random functions]) - AC_DEFINE([AFLFUZZ_DISABLE_MGTTHREADS], [1], [Disable all management threads]) - AC_DEFINE([AFLFUZZ_PCAP_RUNMODE], [1], [Enable special AFL 'single' runmode]) - AC_DEFINE([AFLFUZZ_CONF_TEST], [1], [Enable special --afl-parse-rules commandline option]) - AC_DEFINE([AFLFUZZ_APPLAYER], [1], [Enable --afl-$proto-request commandline option]) - AC_DEFINE([AFLFUZZ_MIME], [1], [Enable --afl-mime commandline option]) - AC_DEFINE([AFLFUZZ_DECODER], [1], [Enable --afl-decoder-$proto commandline option]) - AC_DEFINE([AFLFUZZ_DER], [1], [Enable --afl-der commandline option]) - - # test for AFL PERSISTANT_MODE support - CFLAGS_ORIG=$CFLAGS - CFLAGS="-Werror" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[while (__AFL_LOOP(1000))]])], - [AC_DEFINE([AFLFUZZ_PERSISTANT_MODE], [1], [Enable AFL PERSISTANT_MODE])], - []) - CFLAGS=$CFLAGS_ORIG - ]) - AC_PROG_LIBTOOL PKG_PROG_PKG_CONFIG(0.21) # 0.21 is the CentOS 5.11 version @@ -284,6 +259,29 @@ esac AC_MSG_RESULT(ok) + # enable modifications for AFL fuzzing + AC_ARG_ENABLE(afl, + AS_HELP_STRING([--enable-afl], Enable AFL fuzzing logic[])], [enable_afl="$enableval"],[enable_afl=no]) + + AS_IF([test "x$enable_afl" = "xyes"], [ + AC_DEFINE([AFLFUZZ_NO_RANDOM], [1], [Disable all use of random functions]) + AC_DEFINE([AFLFUZZ_DISABLE_MGTTHREADS], [1], [Disable all management threads]) + AC_DEFINE([AFLFUZZ_PCAP_RUNMODE], [1], [Enable special AFL 'single' runmode]) + AC_DEFINE([AFLFUZZ_CONF_TEST], [1], [Enable special --afl-parse-rules commandline option]) + AC_DEFINE([AFLFUZZ_APPLAYER], [1], [Enable --afl-$proto-request commandline option]) + AC_DEFINE([AFLFUZZ_MIME], [1], [Enable --afl-mime commandline option]) + AC_DEFINE([AFLFUZZ_DECODER], [1], [Enable --afl-decoder-$proto commandline option]) + AC_DEFINE([AFLFUZZ_DER], [1], [Enable --afl-der commandline option]) + + # test for AFL PERSISTANT_MODE support + CFLAGS_ORIG=$CFLAGS + CFLAGS="-Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[while (__AFL_LOOP(1000))]])], + [AC_DEFINE([AFLFUZZ_PERSISTANT_MODE], [1], [Enable AFL PERSISTANT_MODE])], + []) + CFLAGS=$CFLAGS_ORIG + ]) + # disable TLS on user request AC_ARG_ENABLE(threading-tls, AS_HELP_STRING([--disable-threading-tls], [Disable TLS (thread local storage)]), [enable_tls="$enableval"],[enable_tls=yes]) From 65a3ff81ef2f50ac773394eb48dd8f896c16ef9b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 12 Apr 2016 18:54:06 +0200 Subject: [PATCH 1270/2553] readme: initial readme for github --- README.md | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000000..cd4a63d04929 --- /dev/null +++ b/README.md @@ -0,0 +1,109 @@ +======== +Suricata +======== + +Introduction +============ + +Suricata is a network IDS, IPS and NSM engine. + + +Installation +============ + +https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Installation + +User Guide +========== + +https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_User_Guide + + +Contributing +============ + +We're happily taking patches and other contributions. Please see https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Contributing for how to get started. + +Suricata is a complex piece of software dealing with mostly untrusted input. Mishandling this input will have serious consequences: in IPS mode a crash may knock a network offline; in passive mode a compromise of the IDS may lead to loss of critical and confidential data; missed detection may lead to undetected compromise of the network. In other words, we think the stakes are pretty high, especially since in many common cases the IDS/IPS will be directly reachable by an attacker. + +For this reason, we have developed a QA process that is quite extensive. A consequence is that contributing to Suricata can be a somewhat lengthy process. + +On a high level, the steps are: + +1. Travis-CI based build & unit testing. This runs automatically when a pull request is made. + +2. Review by devs from the team and community + +3. QA runs + + + +Overview of Suricata's QA steps +------------------------------- + +Trusted devs and core team members are able to submit builds to our (semi) public Buildbot instance. It will run a series of build tests and a regression suite to confirm no existing features break. + +The final QA run takes a few hours minimally, and is started by Victor. It currently runs: + +- extensive build tests on different OS', compilers, optimization levels, configure features +- static code analysis using cppcheck, scan-build +- runtime code analysis using valgrind, DrMemory, AddressSanitizer, LeakSanitizer +- regression tests for past bugs +- output validation of logging +- unix socket testing +- pcap based fuzz testing using ASAN and LSAN + +Next to these tests, based on the type of code change further tests can be run manually: + +- traffic replay testing (multi-gigabit) +- large pcap collection processing (multi-terabytes) +- AFL based fuzz testing (might take multiple days or even weeks) +- pcap based performance testing +- live performance testing +- various other manual tests based on evaluation of the proposed changes + + +It's important to realize that almost all of the tests above are used as acceptance tests. If something fails, it's up to you to address this in your code. + + +One step of the QA is currently run post-merge. We submit builds to the Coverity Scan program. Due to limitations of this (free) service, we can submit once a day max. +Of course it can happen that after the merge the community will find issues. For both cases we request you to help address the issues as they may come up. + + + + +FAQ +--- + +__Q: Will you accept my PR?__ + +A: That depends on a number of things, including the code quality. With new features it also depends on whether the team and/or the community think the feature is useful, how much it affects other code and features, the risk of performance regressions, etc. + + +__Q: When will my PR be merged?__ + +A: It depends, if it's a major feature or considered a high risk change, it will probably go into the next major version. + + +__Q: Why was my PR closed?__ + +A: As documented in the Suricata Github workflow here https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Github_work_flow, we expect a new pull request for every change. + +Normally, the team (or community) will give feedback on a pull request after which it is expected to be replaced by an improved PR. So look at the comments. If you disagree with the comments we can still discuss them in the closed PR. + +If the PR was closed without comments it's likely due to QA failure. If the Travis-CI check failed, the PR should be fixed right away. No need for a discussion about it, unless you believe the QA failure is incorrect. + + +__Q: the compiler/code analyser/tool is wrong, what now?__ + +A: to assist in the automation of the QA, we're not accepting warnings or errors to stay. In some cases this could mean that we add a suppression if the tool supports that (e.g. valgrind, DrMemory). Some warnings can be disabled. In some exceptional cases the only 'solution' is to refactor the code to work around a static code checker limitation false positive. While frusterating, we prefer this over leaving warnings in the output. Warnings tend to get ignored and then increase risk of hiding other warnings. + + +__Q: I think your QA test is wrong__ + +A: If you really think it is, we can discuss how to improve it. But don't come to this conclusion to quickly, moreoften it's the code that turns out to be wrong. + + +__Q: do you require signing of a contributor license agreement?__ + +A: Yes, we do this to keep the ownership of Suricata in one hand: the Open Information Security Foundation. See http://suricata-ids.org/about/open-source/ and http://suricata-ids.org/about/contribution-agreement/ From 7ac7f9cd55fa3d3562aea439c19c05e29eef617a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 7 Nov 2015 19:07:40 +0100 Subject: [PATCH 1271/2553] instance: add progname as ptr to argv[0] --- src/suricata.c | 1 + src/suricata.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index d2d816028e75..4f43dddfcca1 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2385,6 +2385,7 @@ int main(int argc, char **argv) SCInstance suri; SCInstanceInit(&suri); + suri.progname = argv[0]; sc_set_caps = FALSE; diff --git a/src/suricata.h b/src/suricata.h index 8f3413ca3702..b361b3932993 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -155,6 +155,7 @@ typedef struct SCInstance_ { struct timeval start_time; char *log_dir; + const char *progname; /**< pointer to argv[0] */ } SCInstance; From 1fe09a38e0e73ecff5aab4f7509a08b4400b53d0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 7 Nov 2015 19:03:48 +0100 Subject: [PATCH 1272/2553] commandline: move pcap parsing into util func --- src/suricata.c | 164 ++++++++++++++++++++++++++----------------------- 1 file changed, 86 insertions(+), 78 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 4f43dddfcca1..ecd26f13934d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1109,6 +1109,91 @@ static void SCPrintElapsedTime(SCInstance *suri) SCLogInfo("time elapsed %.3fs", (float)milliseconds/(float)1000); } +static int ParseCommandLinePcapLive(SCInstance *suri, const char *optarg) +{ + memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); + + if (optarg == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "no option argument (optarg) for -i"); + return TM_ECODE_FAILED; + } + + /* warn user if af-packet, netmap or pf-ring are available */ +#if defined HAVE_AF_PACKET || HAVE_PFRING || HAVE_NETMAP + int i = 0; +#ifdef HAVE_AF_PACKET + i++; +#endif +#ifdef HAVE_PFRING + i++; +#endif +#ifdef HAVE_NETMAP + i++; +#endif + SCLogWarning(SC_WARN_FASTER_CAPTURE_AVAILABLE, "faster capture " + "option%s %s available:" +#ifdef HAVE_AF_PACKET + " AF_PACKET (--af-packet=%s)" +#endif +#ifdef HAVE_PFRING + " PF_RING (--pfring-int=%s)" +#endif +#ifdef HAVE_NETMAP + " NETMAP (--netmap=%s)" +#endif + ". Use --pcap=%s to suppress this warning", + i == 1 ? "" : "s", i == 1 ? "is" : "are" + +#ifdef HAVE_AF_PACKET + , optarg +#endif +#ifdef HAVE_PFRING + , optarg +#endif +#ifdef HAVE_NETMAP + , optarg +#endif + , optarg + ); +#endif + /* some windows shells require escaping of the \ in \Device. Otherwise + * the backslashes are stripped. We put them back here. */ + if (strlen(optarg) > 9 && strncmp(optarg, "DeviceNPF", 9) == 0) { + snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", optarg+9); + } else { + strlcpy(suri->pcap_dev, optarg, ((strlen(optarg) < sizeof(suri->pcap_dev)) ? (strlen(optarg)+1) : (sizeof(suri->pcap_dev)))); + PcapTranslateIPToDevice(suri->pcap_dev, sizeof(suri->pcap_dev)); + } + + if (strcmp(suri->pcap_dev, optarg) != 0) { + SCLogInfo("translated %s to pcap device %s", optarg, suri->pcap_dev); + } else if (strlen(suri->pcap_dev) > 0 && isdigit((unsigned char)suri->pcap_dev[0])) { + SCLogError(SC_ERR_PCAP_TRANSLATE, "failed to find a pcap device for IP %s", optarg); + return TM_ECODE_FAILED; + } + + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_PCAP_DEV; + LiveRegisterDevice(suri->pcap_dev); + } else if (suri->run_mode == RUNMODE_PCAP_DEV) { +#ifdef OS_WIN32 + SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " + "support is not (yet) supported on Windows."); + return TM_ECODE_FAILED; +#else + SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " + "multiple pcap devices to get packets is experimental."); + LiveRegisterDevice(suri->pcap_dev); +#endif + } else { + SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " + "has been specified"); + usage(suri->progname); + return TM_ECODE_FAILED; + } + return TM_ECODE_OK; +} + static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) { int opt; @@ -1669,84 +1754,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) suri->run_mode = RUNMODE_PRINT_USAGE; return TM_ECODE_OK; case 'i': - memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - - if (optarg == NULL) { - SCLogError(SC_ERR_INITIALIZATION, "no option argument (optarg) for -i"); - return TM_ECODE_FAILED; - } - - /* warn user if af-packet, netmap or pf-ring are available */ -#if defined HAVE_AF_PACKET || HAVE_PFRING || HAVE_NETMAP - int i = 0; -#ifdef HAVE_AF_PACKET - i++; -#endif -#ifdef HAVE_PFRING - i++; -#endif -#ifdef HAVE_NETMAP - i++; -#endif - SCLogWarning(SC_WARN_FASTER_CAPTURE_AVAILABLE, "faster capture " - "option%s %s available:" -#ifdef HAVE_AF_PACKET - " AF_PACKET (--af-packet=%s)" -#endif -#ifdef HAVE_PFRING - " PF_RING (--pfring-int=%s)" -#endif -#ifdef HAVE_NETMAP - " NETMAP (--netmap=%s)" -#endif - ". Use --pcap=%s to suppress this warning", - i == 1 ? "" : "s", i == 1 ? "is" : "are" - -#ifdef HAVE_AF_PACKET - , optarg -#endif -#ifdef HAVE_PFRING - , optarg -#endif -#ifdef HAVE_NETMAP - , optarg -#endif - , optarg - ); -#endif - /* some windows shells require escaping of the \ in \Device. Otherwise - * the backslashes are stripped. We put them back here. */ - if (strlen(optarg) > 9 && strncmp(optarg, "DeviceNPF", 9) == 0) { - snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", optarg+9); - } else { - strlcpy(suri->pcap_dev, optarg, ((strlen(optarg) < sizeof(suri->pcap_dev)) ? (strlen(optarg)+1) : (sizeof(suri->pcap_dev)))); - PcapTranslateIPToDevice(suri->pcap_dev, sizeof(suri->pcap_dev)); - } - - if (strcmp(suri->pcap_dev, optarg) != 0) { - SCLogInfo("translated %s to pcap device %s", optarg, suri->pcap_dev); - } else if (strlen(suri->pcap_dev) > 0 && isdigit((unsigned char)suri->pcap_dev[0])) { - SCLogError(SC_ERR_PCAP_TRANSLATE, "failed to find a pcap device for IP %s", optarg); - return TM_ECODE_FAILED; - } - - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_PCAP_DEV; - LiveRegisterDevice(suri->pcap_dev); - } else if (suri->run_mode == RUNMODE_PCAP_DEV) { -#ifdef OS_WIN32 - SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " - "support is not (yet) supported on Windows."); - return TM_ECODE_FAILED; -#else - SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " - "multiple pcap devices to get packets is experimental."); - LiveRegisterDevice(suri->pcap_dev); -#endif - } else { - SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " - "has been specified"); - usage(argv[0]); + if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } break; From b50111a5a77785801f52053de53675c68d22afca Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 7 Nov 2015 19:28:49 +0100 Subject: [PATCH 1273/2553] commandline: move afpacket parsing into util func --- src/suricata.c | 68 ++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index ecd26f13934d..6bc348a5d894 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1109,6 +1109,41 @@ static void SCPrintElapsedTime(SCInstance *suri) SCLogInfo("time elapsed %.3fs", (float)milliseconds/(float)1000); } +static int ParseCommandLineAfpacket(SCInstance *suri, const char *optarg) +{ +#ifdef HAVE_AF_PACKET + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_AFP_DEV; + if (optarg) { + LiveRegisterDevice(optarg); + memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); + strlcpy(suri->pcap_dev, optarg, + ((strlen(optarg) < sizeof(suri->pcap_dev)) ? + (strlen(optarg) + 1) : sizeof(suri->pcap_dev))); + } + } else if (suri->run_mode == RUNMODE_AFP_DEV) { + SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " + "multiple devices to get packets is experimental."); + if (optarg) { + LiveRegisterDevice(optarg); + } else { + SCLogInfo("Multiple af-packet option without interface on each is useless"); + } + } else { + SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " + "has been specified"); + usage(suri->progname); + return TM_ECODE_FAILED; + } + return TM_ECODE_OK; +#else + SCLogError(SC_ERR_NO_AF_PACKET,"AF_PACKET not enabled. On Linux " + "host, make sure to pass --enable-af-packet to " + "configure when building."); + return TM_ECODE_FAILED; +#endif +} + static int ParseCommandLinePcapLive(SCInstance *suri, const char *optarg) { memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); @@ -1339,38 +1374,11 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) return TM_ECODE_FAILED; #endif /* HAVE_PFRING */ } - else if (strcmp((long_opts[option_index]).name , "af-packet") == 0){ -#ifdef HAVE_AF_PACKET - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_AFP_DEV; - if (optarg) { - LiveRegisterDevice(optarg); - memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - strlcpy(suri->pcap_dev, optarg, - ((strlen(optarg) < sizeof(suri->pcap_dev)) ? - (strlen(optarg) + 1) : sizeof(suri->pcap_dev))); - } - } else if (suri->run_mode == RUNMODE_AFP_DEV) { - SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " - "multiple devices to get packets is experimental."); - if (optarg) { - LiveRegisterDevice(optarg); - } else { - SCLogInfo("Multiple af-packet option without interface on each is useless"); - break; - } - } else { - SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " - "has been specified"); - usage(argv[0]); + else if (strcmp((long_opts[option_index]).name , "af-packet") == 0) + { + if (ParseCommandLineAfpacket(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } -#else - SCLogError(SC_ERR_NO_AF_PACKET,"AF_PACKET not enabled. On Linux " - "host, make sure to pass --enable-af-packet to " - "configure when building."); - return TM_ECODE_FAILED; -#endif } else if (strcmp((long_opts[option_index]).name , "netmap") == 0){ #ifdef HAVE_NETMAP if (suri->run_mode == RUNMODE_UNKNOWN) { From a3a7d9b2990fe80e76522eb25f3daf643e353d7a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 8 Nov 2015 10:02:11 +0100 Subject: [PATCH 1274/2553] pcap: unify -i and --pcap parsing --- src/suricata.c | 91 ++++++++++++++++++-------------------------------- 1 file changed, 33 insertions(+), 58 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 6bc348a5d894..7263d82953ad 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1148,63 +1148,60 @@ static int ParseCommandLinePcapLive(SCInstance *suri, const char *optarg) { memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - if (optarg == NULL) { - SCLogError(SC_ERR_INITIALIZATION, "no option argument (optarg) for -i"); - return TM_ECODE_FAILED; - } - - /* warn user if af-packet, netmap or pf-ring are available */ + if (optarg != NULL) { + /* warn user if af-packet, netmap or pf-ring are available */ #if defined HAVE_AF_PACKET || HAVE_PFRING || HAVE_NETMAP - int i = 0; + int i = 0; #ifdef HAVE_AF_PACKET - i++; + i++; #endif #ifdef HAVE_PFRING - i++; + i++; #endif #ifdef HAVE_NETMAP - i++; + i++; #endif - SCLogWarning(SC_WARN_FASTER_CAPTURE_AVAILABLE, "faster capture " - "option%s %s available:" + SCLogWarning(SC_WARN_FASTER_CAPTURE_AVAILABLE, "faster capture " + "option%s %s available:" #ifdef HAVE_AF_PACKET - " AF_PACKET (--af-packet=%s)" + " AF_PACKET (--af-packet=%s)" #endif #ifdef HAVE_PFRING - " PF_RING (--pfring-int=%s)" + " PF_RING (--pfring-int=%s)" #endif #ifdef HAVE_NETMAP - " NETMAP (--netmap=%s)" + " NETMAP (--netmap=%s)" #endif - ". Use --pcap=%s to suppress this warning", - i == 1 ? "" : "s", i == 1 ? "is" : "are" + ". Use --pcap=%s to suppress this warning", + i == 1 ? "" : "s", i == 1 ? "is" : "are" #ifdef HAVE_AF_PACKET - , optarg + , optarg #endif #ifdef HAVE_PFRING - , optarg + , optarg #endif #ifdef HAVE_NETMAP - , optarg + , optarg #endif - , optarg - ); + , optarg + ); #endif - /* some windows shells require escaping of the \ in \Device. Otherwise - * the backslashes are stripped. We put them back here. */ - if (strlen(optarg) > 9 && strncmp(optarg, "DeviceNPF", 9) == 0) { - snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", optarg+9); - } else { - strlcpy(suri->pcap_dev, optarg, ((strlen(optarg) < sizeof(suri->pcap_dev)) ? (strlen(optarg)+1) : (sizeof(suri->pcap_dev)))); - PcapTranslateIPToDevice(suri->pcap_dev, sizeof(suri->pcap_dev)); - } + /* some windows shells require escaping of the \ in \Device. Otherwise + * the backslashes are stripped. We put them back here. */ + if (strlen(optarg) > 9 && strncmp(optarg, "DeviceNPF", 9) == 0) { + snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", optarg+9); + } else { + strlcpy(suri->pcap_dev, optarg, ((strlen(optarg) < sizeof(suri->pcap_dev)) ? (strlen(optarg)+1) : (sizeof(suri->pcap_dev)))); + PcapTranslateIPToDevice(suri->pcap_dev, sizeof(suri->pcap_dev)); + } - if (strcmp(suri->pcap_dev, optarg) != 0) { - SCLogInfo("translated %s to pcap device %s", optarg, suri->pcap_dev); - } else if (strlen(suri->pcap_dev) > 0 && isdigit((unsigned char)suri->pcap_dev[0])) { - SCLogError(SC_ERR_PCAP_TRANSLATE, "failed to find a pcap device for IP %s", optarg); - return TM_ECODE_FAILED; + if (strcmp(suri->pcap_dev, optarg) != 0) { + SCLogInfo("translated %s to pcap device %s", optarg, suri->pcap_dev); + } else if (strlen(suri->pcap_dev) > 0 && isdigit((unsigned char)suri->pcap_dev[0])) { + SCLogError(SC_ERR_PCAP_TRANSLATE, "failed to find a pcap device for IP %s", optarg); + return TM_ECODE_FAILED; + } } if (suri->run_mode == RUNMODE_UNKNOWN) { @@ -1420,29 +1417,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) return TM_ECODE_FAILED; #endif /* HAVE_NFLOG */ } else if (strcmp((long_opts[option_index]).name , "pcap") == 0) { - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_PCAP_DEV; - if (optarg) { - LiveRegisterDevice(optarg); - memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - strlcpy(suri->pcap_dev, optarg, - ((strlen(optarg) < sizeof(suri->pcap_dev)) ? - (strlen(optarg) + 1) : sizeof(suri->pcap_dev))); - } - } else if (suri->run_mode == RUNMODE_PCAP_DEV) { -#ifdef OS_WIN32 - SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " - "support is not (yet) supported on Windows."); - return TM_ECODE_FAILED; -#else - SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " - "multiple pcap devices to get packets is experimental."); - LiveRegisterDevice(optarg); -#endif - } else { - SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " - "has been specified"); - usage(argv[0]); + if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } #ifdef AFLFUZZ_APPLAYER From f8852f4415c5b6c1485e1979bfb8a2e490277fdd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 8 Nov 2015 10:02:31 +0100 Subject: [PATCH 1275/2553] commandline: use afpacket for -i if available --- src/suricata.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index 7263d82953ad..f25c074d2d94 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1737,9 +1737,15 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) suri->run_mode = RUNMODE_PRINT_USAGE; return TM_ECODE_OK; case 'i': +#ifdef HAVE_AF_PACKET + if (ParseCommandLineAfpacket(suri, optarg) != TM_ECODE_OK) { + return TM_ECODE_FAILED; + } +#else if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } +#endif break; case 'l': if (optarg == NULL) { From 053b96458f9a759b44d7e9559db466e2970de8ba Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 7 Nov 2015 23:50:17 +0100 Subject: [PATCH 1276/2553] commandline: add -i arg check --- src/suricata.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index f25c074d2d94..9ca72a4ba6d7 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1737,6 +1737,10 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) suri->run_mode = RUNMODE_PRINT_USAGE; return TM_ECODE_OK; case 'i': + if (optarg == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "no option argument (optarg) for -i"); + return TM_ECODE_FAILED; + } #ifdef HAVE_AF_PACKET if (ParseCommandLineAfpacket(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; From 9b08cdae7488303bc4893257ace5f0a4390aaf50 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 12 Apr 2016 12:30:20 +0200 Subject: [PATCH 1277/2553] capture: only check for faster methods on -i Also, since we now default to AF_PACKET for -i if available, only check for PF_RING and NETMAP. --- src/suricata.c | 68 +++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 9ca72a4ba6d7..85a7a51637da 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1149,44 +1149,6 @@ static int ParseCommandLinePcapLive(SCInstance *suri, const char *optarg) memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); if (optarg != NULL) { - /* warn user if af-packet, netmap or pf-ring are available */ -#if defined HAVE_AF_PACKET || HAVE_PFRING || HAVE_NETMAP - int i = 0; -#ifdef HAVE_AF_PACKET - i++; -#endif -#ifdef HAVE_PFRING - i++; -#endif -#ifdef HAVE_NETMAP - i++; -#endif - SCLogWarning(SC_WARN_FASTER_CAPTURE_AVAILABLE, "faster capture " - "option%s %s available:" -#ifdef HAVE_AF_PACKET - " AF_PACKET (--af-packet=%s)" -#endif -#ifdef HAVE_PFRING - " PF_RING (--pfring-int=%s)" -#endif -#ifdef HAVE_NETMAP - " NETMAP (--netmap=%s)" -#endif - ". Use --pcap=%s to suppress this warning", - i == 1 ? "" : "s", i == 1 ? "is" : "are" - -#ifdef HAVE_AF_PACKET - , optarg -#endif -#ifdef HAVE_PFRING - , optarg -#endif -#ifdef HAVE_NETMAP - , optarg -#endif - , optarg - ); -#endif /* some windows shells require escaping of the \ in \Device. Otherwise * the backslashes are stripped. We put them back here. */ if (strlen(optarg) > 9 && strncmp(optarg, "DeviceNPF", 9) == 0) { @@ -1745,7 +1707,35 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) if (ParseCommandLineAfpacket(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } -#else +#else /* not afpacket */ + /* warn user if netmap or pf-ring are available */ +#if defined HAVE_PFRING || HAVE_NETMAP + int i = 0; +#ifdef HAVE_PFRING + i++; +#endif +#ifdef HAVE_NETMAP + i++; +#endif + SCLogWarning(SC_WARN_FASTER_CAPTURE_AVAILABLE, "faster capture " + "option%s %s available:" +#ifdef HAVE_PFRING + " PF_RING (--pfring-int=%s)" +#endif +#ifdef HAVE_NETMAP + " NETMAP (--netmap=%s)" +#endif + ". Use --pcap=%s to suppress this warning", + i == 1 ? "" : "s", i == 1 ? "is" : "are" +#ifdef HAVE_PFRING + , optarg +#endif +#ifdef HAVE_NETMAP + , optarg +#endif + , optarg + ); +#endif /* have faster methods */ if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } From 93fa2919222cafc5436945f7bfcc6096882c8eee Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 Apr 2016 09:46:18 +0200 Subject: [PATCH 1278/2553] stream-tcp: unify ssn clean up functions There were 2 separate function doing ssn cleanup. To prevent issues common with code duplication, unify them. --- src/stream-tcp.c | 102 ++++++++++++++++++----------------------------- src/stream-tcp.h | 4 ++ 2 files changed, 42 insertions(+), 64 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index ae1a67a729a3..a7619e5dbdbe 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -166,33 +166,25 @@ int StreamTcpCheckMemcap(uint64_t size) } /** - * \brief Function to return the stream back to the pool. It returns the - * segments in the stream to the segment pool. - * - * This function is called when the flow is destroyed, so it should free - * *everything* related to the tcp session. So including the app layer - * data. We are guaranteed to only get here when the flow's use_cnt is 0. - * - * \param ssn Void ptr to the ssn. + * \brief Session cleanup function. Does not free the ssn. + * \param ssn tcp session */ -void StreamTcpSessionClear(void *ssnptr) +void StreamTcpSessionCleanup(TcpSession *ssn) { SCEnter(); + StreamMsg *smsg = NULL; TcpStateQueue *q, *q_next; - TcpSession *ssn = (TcpSession *)ssnptr; if (ssn == NULL) - SCReturn; - - StreamTcpReturnStreamSegments(&ssn->client); - StreamTcpReturnStreamSegments(&ssn->server); - - //AppLayerParserCleanupState(ssn); + return; StreamTcpSackFreeList(&ssn->client); StreamTcpSackFreeList(&ssn->server); + StreamTcpReturnStreamSegments(&ssn->client); + StreamTcpReturnStreamSegments(&ssn->server); + /* if we have (a) smsg(s), return to the pool */ smsg = ssn->toserver_smsg_head; while(smsg != NULL) { @@ -226,6 +218,28 @@ void StreamTcpSessionClear(void *ssnptr) ssn->queue = NULL; ssn->queue_len = 0; + SCReturn; +} + +/** + * \brief Function to return the stream back to the pool. It returns the + * segments in the stream to the segment pool. + * + * This function is called when the flow is destroyed, so it should free + * *everything* related to the tcp session. So including the app layer + * data. We are guaranteed to only get here when the flow's use_cnt is 0. + * + * \param ssn Void ptr to the ssn. + */ +void StreamTcpSessionClear(void *ssnptr) +{ + SCEnter(); + TcpSession *ssn = (TcpSession *)ssnptr; + if (ssn == NULL) + return; + + StreamTcpSessionCleanup(ssn); + memset(ssn, 0, sizeof(TcpSession)); PoolThreadReturn(ssn_pool, ssn); #ifdef DEBUG @@ -264,7 +278,7 @@ void StreamTcpSessionPktFree (Packet *p) /** \brief Stream alloc function for the Pool * \retval ptr void ptr to TcpSession structure with all vars set to 0/NULL */ -void *StreamTcpSessionPoolAlloc() +static void *StreamTcpSessionPoolAlloc() { void *ptr = NULL; @@ -278,7 +292,7 @@ void *StreamTcpSessionPoolAlloc() return ptr; } -int StreamTcpSessionPoolInit(void *data, void* initdata) +static int StreamTcpSessionPoolInit(void *data, void* initdata) { memset(data, 0, sizeof(TcpSession)); StreamTcpIncrMemuse((uint64_t)sizeof(TcpSession)); @@ -286,55 +300,15 @@ int StreamTcpSessionPoolInit(void *data, void* initdata) return 1; } -/** \brief Pool free function +/** \brief Pool cleanup function * \param s Void ptr to TcpSession memory */ -void StreamTcpSessionPoolCleanup(void *s) +static void StreamTcpSessionPoolCleanup(void *s) { - StreamMsg *smsg = NULL; - TcpStateQueue *q, *q_next; - - if (s == NULL) - return; - - TcpSession *ssn = (TcpSession *)s; - - StreamTcpReturnStreamSegments(&ssn->client); - StreamTcpReturnStreamSegments(&ssn->server); - - /* if we have (a) smsg(s), return to the pool */ - smsg = ssn->toserver_smsg_head; - while(smsg != NULL) { - StreamMsg *smsg_next = smsg->next; - SCLogDebug("returning smsg %p to pool", smsg); - smsg->next = NULL; - smsg->prev = NULL; - StreamMsgReturnToPool(smsg); - smsg = smsg_next; + if (s != NULL) { + StreamTcpSessionCleanup(s); + /** \todo not very clean, as the memory is not freed here */ + StreamTcpDecrMemuse((uint64_t)sizeof(TcpSession)); } - ssn->toserver_smsg_head = NULL; - - smsg = ssn->toclient_smsg_head; - while(smsg != NULL) { - StreamMsg *smsg_next = smsg->next; - SCLogDebug("returning smsg %p to pool", smsg); - smsg->next = NULL; - smsg->prev = NULL; - StreamMsgReturnToPool(smsg); - smsg = smsg_next; - } - ssn->toclient_smsg_head = NULL; - - q = ssn->queue; - while (q != NULL) { - q_next = q->next; - SCFree(q); - q = q_next; - StreamTcpDecrMemuse((uint64_t)sizeof(TcpStateQueue)); - } - ssn->queue = NULL; - ssn->queue_len = 0; - - StreamTcpDecrMemuse((uint64_t)sizeof(TcpSession)); } /** \brief To initialize the stream global configuration data diff --git a/src/stream-tcp.h b/src/stream-tcp.h index f7c3ab108b2c..dc3ccbf6761a 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -225,7 +225,11 @@ TmEcode StreamTcpThreadInit(ThreadVars *, void *, void **); TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data); int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueue *pq); +/* clear ssn and return to pool */ void StreamTcpSessionClear(void *ssnptr); +/* cleanup ssn, but don't free ssn */ +void StreamTcpSessionCleanup(TcpSession *ssn); + uint32_t StreamTcpGetStreamSize(TcpStream *stream); #endif /* __STREAM_TCP_H__ */ From 3aea0bd4f38ff5ad6b220a2c4ee0b9e65a8b166e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 Apr 2016 10:13:50 +0200 Subject: [PATCH 1279/2553] stream-tcp: introduce stream cleanup function --- src/stream-tcp.c | 15 ++++++++++----- src/stream-tcp.h | 3 +++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index a7619e5dbdbe..f17a76136999 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -165,6 +165,14 @@ int StreamTcpCheckMemcap(uint64_t size) return 0; } +void StreamTcpStreamCleanup(TcpStream *stream) +{ + if (stream != NULL) { + StreamTcpSackFreeList(stream); + StreamTcpReturnStreamSegments(stream); + } +} + /** * \brief Session cleanup function. Does not free the ssn. * \param ssn tcp session @@ -179,11 +187,8 @@ void StreamTcpSessionCleanup(TcpSession *ssn) if (ssn == NULL) return; - StreamTcpSackFreeList(&ssn->client); - StreamTcpSackFreeList(&ssn->server); - - StreamTcpReturnStreamSegments(&ssn->client); - StreamTcpReturnStreamSegments(&ssn->server); + StreamTcpStreamCleanup(&ssn->client); + StreamTcpStreamCleanup(&ssn->server); /* if we have (a) smsg(s), return to the pool */ smsg = ssn->toserver_smsg_head; diff --git a/src/stream-tcp.h b/src/stream-tcp.h index dc3ccbf6761a..416cd5aa808f 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -229,6 +229,9 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, void StreamTcpSessionClear(void *ssnptr); /* cleanup ssn, but don't free ssn */ void StreamTcpSessionCleanup(TcpSession *ssn); +/* cleanup stream, but don't free the stream */ +void StreamTcpStreamCleanup(TcpStream *stream); + uint32_t StreamTcpGetStreamSize(TcpStream *stream); From c4575d141946e5200d84047bfa8b78c7d05fa551 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 Apr 2016 10:14:35 +0200 Subject: [PATCH 1280/2553] stream-tcp: improve test function cleanup --- src/stream-tcp-util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/stream-tcp-util.c b/src/stream-tcp-util.c index 54c500bc9309..b58db5c2838f 100644 --- a/src/stream-tcp-util.c +++ b/src/stream-tcp-util.c @@ -68,6 +68,7 @@ void StreamTcpUTClearSession(TcpSession *ssn) { StreamTcpUTClearStream(&ssn->client); StreamTcpUTClearStream(&ssn->server); + StreamTcpSessionCleanup(ssn); } void StreamTcpUTSetupStream(TcpStream *s, uint32_t isn) @@ -80,7 +81,7 @@ void StreamTcpUTSetupStream(TcpStream *s, uint32_t isn) void StreamTcpUTClearStream(TcpStream *s) { - StreamTcpReturnStreamSegments(s); + StreamTcpStreamCleanup(s); } int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len) From 3f16ebe4762775e4d11c2d63d0153643016e4012 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 Apr 2016 09:46:56 +0200 Subject: [PATCH 1281/2553] dns: don't read uninitialized memory in name parsing AFL+ASAN found that with certain input we used an uninitialized byte in the length calculation. Probably harmless as the length was still validated afterwards. --- src/app-layer-dns-common.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 339610a705b5..664a6e0a93c9 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -656,7 +656,7 @@ void DNSStoreAnswerInState(DNSState *dns_state, const int rtype, const uint8_t * static uint16_t DNSResponseGetNameByOffset(const uint8_t * const input, const uint32_t input_len, const uint16_t offset, uint8_t *fqdn, const size_t fqdn_size) { - if (input + input_len < input + offset + 1) { + if (offset >= input_len) { SCLogDebug("input buffer too small for domain of len %u", offset); goto insufficient_data; } @@ -672,13 +672,18 @@ static uint16_t DNSResponseGetNameByOffset(const uint8_t * const input, const ui SCReturnUInt(6U); } + if ((uint64_t)((qdata + 1) - input) >= (uint64_t)input_len) { + SCLogDebug("input buffer too small"); + goto insufficient_data; + } + while (length != 0) { int cnt = 0; while (length & 0xc0) { uint16_t offset = ((length & 0x3f) << 8) + *(qdata+1); qdata = (const uint8_t *)input + offset; - if (input + input_len < qdata + 1) { + if ((uint64_t)((qdata + 1) - input) >= (uint64_t)input_len) { SCLogDebug("input buffer too small"); goto insufficient_data; } @@ -710,8 +715,8 @@ static uint16_t DNSResponseGetNameByOffset(const uint8_t * const input, const ui } qdata += length; - if (input + input_len < qdata + 1) { - SCLogDebug("input buffer too small for len field"); + if ((uint64_t)((qdata + 1) - input) >= (uint64_t)input_len) { + SCLogDebug("input buffer too small"); goto insufficient_data; } From c3efc4e0721e6548faed1174445c734d61ba643d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 15 Apr 2016 12:26:40 +0200 Subject: [PATCH 1282/2553] pcap: small cleanups --- src/source-pcap-file.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index c2187eda1bbb..4df2c72a61cf 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -59,8 +59,6 @@ extern int max_pending_packets; -//static int pcap_max_read_packets = 0; - typedef struct PcapFileGlobalVars_ { pcap_t *pcap_handle; int (*Decoder)(ThreadVars *, DecodeThreadVars *, Packet *, u_int8_t *, u_int16_t, PacketQueue *); @@ -73,9 +71,6 @@ typedef struct PcapFileGlobalVars_ { } PcapFileGlobalVars; -/** max packets < 65536 */ -//#define PCAP_FILE_MAX_PKTS 256 - typedef struct PcapFileThreadVars_ { uint32_t tenant_id; @@ -260,8 +255,10 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); + char *tmpbpfstring = NULL; char *tmpstring = NULL; + if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "error: initdata == NULL"); SCReturnInt(TM_ECODE_FAILED); @@ -302,14 +299,15 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) } else { SCLogInfo("using bpf-filter \"%s\"", tmpbpfstring); - if(pcap_compile(pcap_g.pcap_handle,&pcap_g.filter,tmpbpfstring,1,0) < 0) { - SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(pcap_g.pcap_handle)); + if (pcap_compile(pcap_g.pcap_handle, &pcap_g.filter, tmpbpfstring, 1, 0) < 0) { + SCLogError(SC_ERR_BPF,"bpf compilation error %s", + pcap_geterr(pcap_g.pcap_handle)); SCFree(ptv); return TM_ECODE_FAILED; } - if(pcap_setfilter(pcap_g.pcap_handle,&pcap_g.filter) < 0) { - SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(pcap_g.pcap_handle)); + if (pcap_setfilter(pcap_g.pcap_handle, &pcap_g.filter) < 0) { + SCLogError(SC_ERR_BPF,"could not set bpf filter %s", pcap_geterr(pcap_g.pcap_handle)); SCFree(ptv); return TM_ECODE_FAILED; } @@ -318,7 +316,7 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) pcap_g.datalink = pcap_datalink(pcap_g.pcap_handle); SCLogDebug("datalink %" PRId32 "", pcap_g.datalink); - switch(pcap_g.datalink) { + switch (pcap_g.datalink) { case LINKTYPE_LINUX_SLL: pcap_g.Decoder = DecodeSll; break; From 1c8775b340579de2c26398a8611071c6e7dbd0ff Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 15 Apr 2016 07:47:55 +0200 Subject: [PATCH 1283/2553] QA: --afl-rules for faster rule fuzzing --- configure.ac | 1 + src/detect-parse.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/detect-parse.h | 4 ++++ src/suricata.c | 5 +++++ 4 files changed, 55 insertions(+) diff --git a/configure.ac b/configure.ac index a54cc7d4b41a..16ca5edd4fd6 100644 --- a/configure.ac +++ b/configure.ac @@ -272,6 +272,7 @@ AC_DEFINE([AFLFUZZ_MIME], [1], [Enable --afl-mime commandline option]) AC_DEFINE([AFLFUZZ_DECODER], [1], [Enable --afl-decoder-$proto commandline option]) AC_DEFINE([AFLFUZZ_DER], [1], [Enable --afl-der commandline option]) + AC_DEFINE([AFLFUZZ_RULES], [1], [Enable --afl-rules commandline option]) # test for AFL PERSISTANT_MODE support CFLAGS_ORIG=$CFLAGS diff --git a/src/detect-parse.c b/src/detect-parse.c index ca08ceaf76ac..e28154ad7fbc 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -2019,6 +2019,51 @@ void DetectSetupParseRegexes(const char *parse_str, return; } +#ifdef AFLFUZZ_RULES +#include "util-reference-config.h" +int RuleParseDataFromFile(char *filename) +{ + char buffer[65536]; + + SigTableSetup(); + SigParsePrepare(); + SCReferenceConfInit(); + SCClassConfInit(); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + return 0; + +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(10000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) { + buffer[result] = '\0'; + Signature *s = SigInit(de_ctx, buffer); + if (s != NULL) { + SigFree(s); + } + } + fclose(fp); + +#ifdef AFLFUZZ_PERSISTANT_MODE + } +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + DetectEngineCtxFree(de_ctx); + SCClassConfDeinit(); + SCReferenceConfDeinit(); + return 0; +} +#endif /* AFLFUZZ_RULES */ + /* * TESTS */ diff --git a/src/detect-parse.h b/src/detect-parse.h index bdc82ef15c02..e780b86ad67e 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -75,5 +75,9 @@ void DetectSetupParseRegexes(const char *parse_str, void DetectParseRegexAddToFreeList(pcre *regex, pcre_extra *study); void DetectParseFreeRegexes(void); +#ifdef AFLFUZZ_RULES +int RuleParseDataFromFile(char *filename); +#endif + #endif /* __DETECT_PARSE_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 85a7a51637da..ee0d40fff737 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1223,6 +1223,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"netmap", optional_argument, 0, 0}, {"pcap", optional_argument, 0, 0}, {"simulate-ips", 0, 0 , 0}, + {"afl-rules", required_argument, 0 , 0}, {"afl-http-request", required_argument, 0 , 0}, {"afl-http", required_argument, 0 , 0}, {"afl-tls-request", required_argument, 0 , 0}, @@ -1382,6 +1383,10 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } +#ifdef AFLFUZZ_RULES + } else if(strcmp((long_opts[option_index]).name, "afl-rules") == 0) { + exit(RuleParseDataFromFile(optarg)); +#endif #ifdef AFLFUZZ_APPLAYER } else if(strcmp((long_opts[option_index]).name, "afl-http-request") == 0) { //printf("arg: //%s\n", optarg); From 554080cced6f01f364e6d794acb6a7e8be582a1c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 11 Feb 2016 18:10:00 +0100 Subject: [PATCH 1284/2553] lua: print lua script func/line/file in SCLog* funcs Instead of printing the func/line/file of the C code SCLog* wrappers, print them from inside the lua script. They are not always available. --- src/util-debug.h | 69 +++++++++++++++++++++++++------------------ src/util-lua-common.c | 27 ++++++++++++++--- 2 files changed, 63 insertions(+), 33 deletions(-) diff --git a/src/util-debug.h b/src/util-debug.h index 7e52506b5aa3..1f97d6565d81 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -198,43 +198,37 @@ extern int sc_log_module_initialized; extern int sc_log_module_cleaned; -#define SCLog(x, ...) \ +#define SCLog(x, file, func, line, ...) \ do { \ if (sc_log_global_log_level >= x && \ (sc_log_fg_filters_present == 0 || \ - SCLogMatchFGFilterWL(__FILE__, __FUNCTION__, __LINE__) == 1 || \ - SCLogMatchFGFilterBL(__FILE__, __FUNCTION__, __LINE__) == 1) && \ + SCLogMatchFGFilterWL(file, func, line) == 1 || \ + SCLogMatchFGFilterBL(file, func, line) == 1) && \ (sc_log_fd_filters_present == 0 || \ - SCLogMatchFDFilter(__FUNCTION__) == 1)) \ + SCLogMatchFDFilter(func) == 1)) \ { \ char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN]; \ \ snprintf(_sc_log_msg, SC_LOG_MAX_LOG_MSG_LEN, __VA_ARGS__); \ \ - SCLogMessage(x, \ - __FILE__, \ - __LINE__, \ - __FUNCTION__, SC_OK, _sc_log_msg); \ + SCLogMessage(x, file, line, func, SC_OK, _sc_log_msg); \ } \ } while(0) -#define SCLogErr(x, err, ...) \ +#define SCLogErr(x, file, func, line, err, ...) \ do { \ if (sc_log_global_log_level >= x && \ (sc_log_fg_filters_present == 0 || \ - SCLogMatchFGFilterWL(__FILE__, __FUNCTION__, __LINE__) == 1 || \ - SCLogMatchFGFilterBL(__FILE__, __FUNCTION__, __LINE__) == 1) && \ + SCLogMatchFGFilterWL(file, func, line) == 1 || \ + SCLogMatchFGFilterBL(file, func, line) == 1) && \ (sc_log_fd_filters_present == 0 || \ - SCLogMatchFDFilter(__FUNCTION__) == 1)) \ + SCLogMatchFDFilter(func) == 1)) \ { \ char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN]; \ \ snprintf(_sc_log_msg, SC_LOG_MAX_LOG_MSG_LEN, __VA_ARGS__); \ \ - SCLogMessage(x, \ - __FILE__, \ - __LINE__, \ - __FUNCTION__, err, _sc_log_msg); \ + SCLogMessage(x, file, line, func, err, _sc_log_msg); \ } \ } while(0) @@ -243,14 +237,20 @@ extern int sc_log_module_cleaned; * * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogInfo(...) SCLog(SC_LOG_INFO, __VA_ARGS__) +#define SCLogInfo(...) SCLog(SC_LOG_INFO, \ + __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) +#define SCLogInfoRaw(file, func, line, ...) SCLog(SC_LOG_INFO, \ + (file), (func), (line), __VA_ARGS__) /** * \brief Macro used to log NOTICE messages. * * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogNotice(...) SCLog(SC_LOG_NOTICE, __VA_ARGS__) +#define SCLogNotice(...) SCLog(SC_LOG_NOTICE, \ + __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) +#define SCLogNoticeRaw(file, func, line, ... ) SCLog(SC_LOG_NOTICE, \ + (file), (func), (line), __VA_ARGS__) /** * \brief Macro used to log WARNING messages. @@ -259,8 +259,12 @@ extern int sc_log_module_cleaned; * warning message * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogWarning(err_code, ...) SCLogErr(SC_LOG_WARNING, err_code, \ - __VA_ARGS__) +#define SCLogWarning(err_code, ...) SCLogErr(SC_LOG_WARNING, \ + __FILE__, __FUNCTION__, __LINE__, \ + err_code, __VA_ARGS__) +#define SCLogWarningRaw(err_code, file, func, line, ...) \ + SCLogErr(SC_LOG_WARNING, (file), (func), (line), err_code, __VA_ARGS__) + /** * \brief Macro used to log ERROR messages. * @@ -268,8 +272,12 @@ extern int sc_log_module_cleaned; * error message * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogError(err_code, ...) SCLogErr(SC_LOG_ERROR, err_code, \ - __VA_ARGS__) +#define SCLogError(err_code, ...) SCLogErr(SC_LOG_ERROR, \ + __FILE__, __FUNCTION__, __LINE__, \ + err_code, __VA_ARGS__) +#define SCLogErrorRaw(err_code, file, func, line, ...) SCLogErr(SC_LOG_ERROR, \ + (file), (func), (line), err_code, __VA_ARGS__) + /** * \brief Macro used to log CRITICAL messages. * @@ -277,8 +285,9 @@ extern int sc_log_module_cleaned; * critical message * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogCritical(err_code, ...) SCLogErr(SC_LOG_CRITICAL, err_code, \ - __VA_ARGS__) +#define SCLogCritical(err_code, ...) SCLogErr(SC_LOG_CRITICAL, \ + __FILE__, __FUNCTION__, __LINE__, \ + err_code, __VA_ARGS__) /** * \brief Macro used to log ALERT messages. * @@ -286,8 +295,9 @@ extern int sc_log_module_cleaned; * alert message * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogAlert(err_code, ...) SCLogErr(SC_LOG_ALERT, err_code, \ - __VA_ARGS__) +#define SCLogAlert(err_code, ...) SCLogErr(SC_LOG_ALERT, \ + __FILE__, __FUNCTION__, __LINE__, \ + err_code, __VA_ARGS__) /** * \brief Macro used to log EMERGENCY messages. * @@ -295,8 +305,9 @@ extern int sc_log_module_cleaned; * emergency message * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogEmerg(err_code, ...) SCLogErr(SC_LOG_EMERGENCY, err_code, \ - __VA_ARGS__) +#define SCLogEmerg(err_code, ...) SCLogErr(SC_LOG_EMERGENCY, \ + __FILE__, __FUNCTION__, __LINE__, \ + err_code, __VA_ARGS__) /* Avoid the overhead of using the debugging subsystem, in production mode */ @@ -332,7 +343,7 @@ extern int sc_log_module_cleaned; * * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogDebug(...) SCLog(SC_LOG_DEBUG, __VA_ARGS__) +#define SCLogDebug(...) SCLog(SC_LOG_DEBUG, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) /** * \brief Macro used to log debug messages on function entry. Comes under the diff --git a/src/util-lua-common.c b/src/util-lua-common.c index 82013485f2e3..0db230910246 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -545,7 +545,12 @@ static int LuaCallbackLogInfo(lua_State *luastate) const char *msg = LuaGetStringArgument(luastate, 1); if (msg == NULL) return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - SCLogInfo("%s", msg); + + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogInfoRaw(ar.short_src, funcname, ar.currentline, "%s", msg); return 0; } @@ -554,7 +559,12 @@ static int LuaCallbackLogNotice(lua_State *luastate) const char *msg = LuaGetStringArgument(luastate, 1); if (msg == NULL) return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - SCLogNotice("%s", msg); + + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogNoticeRaw(ar.short_src, funcname, ar.currentline, "%s", msg); return 0; } @@ -563,7 +573,12 @@ static int LuaCallbackLogWarning(lua_State *luastate) const char *msg = LuaGetStringArgument(luastate, 1); if (msg == NULL) return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - SCLogWarning(SC_WARN_LUA_SCRIPT, "%s", msg); + + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogWarningRaw(SC_WARN_LUA_SCRIPT, ar.short_src, funcname, ar.currentline, "%s", msg); return 0; } @@ -572,7 +587,11 @@ static int LuaCallbackLogError(lua_State *luastate) const char *msg = LuaGetStringArgument(luastate, 1); if (msg == NULL) return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - SCLogError(SC_ERR_LUA_SCRIPT, "%s", msg); + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogErrorRaw(SC_ERR_LUA_SCRIPT, ar.short_src, funcname, ar.currentline, "%s", msg); return 0; } From c6bbd89251432af2c458a7a6f5114bcf54667f5d Mon Sep 17 00:00:00 2001 From: maxtors Date: Fri, 22 Apr 2016 19:18:40 +0200 Subject: [PATCH 1285/2553] Added payload-buffer-size option to yaml configuration --- suricata.yaml.in | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index f307b7a8d363..b5d292ca8a79 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -118,13 +118,14 @@ outputs: # batch-size: 10 ## number of entry to keep in buffer types: - alert: - # payload: yes # enable dumping payload in Base64 - # payload-printable: yes # enable dumping payload in printable (lossy) format - # packet: yes # enable dumping of packet (without stream segments) - # http: yes # enable dumping of http fields - # tls: yes # enable dumping of tls fields - # ssh: yes # enable dumping of ssh fields - # smtp: yes # enable dumping of smtp fields + # payload: yes # enable dumping payload in Base64 + # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log + # payload-printable: yes # enable dumping payload in printable (lossy) format + # packet: yes # enable dumping of packet (without stream segments) + # http: yes # enable dumping of http fields + # tls: yes # enable dumping of tls fields + # ssh: yes # enable dumping of ssh fields + # smtp: yes # enable dumping of smtp fields # HTTP X-Forwarded-For support by adding an extra field or overwriting # the source or destination IP address (depending on flow direction) From 7f2f7cc48de7d842ce6b7dc3dae2a1d5c52aa3f9 Mon Sep 17 00:00:00 2001 From: maxtors Date: Fri, 22 Apr 2016 20:15:21 +0200 Subject: [PATCH 1286/2553] Added parsing and utilization of yaml defined payload buffer value. --- src/output-json-alert.c | 31 ++++++++++++++++++++++++------- src/util-error.c | 1 + src/util-error.h | 1 + 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index bd8f93e9a637..a54d66a2b0b9 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -35,6 +35,7 @@ #include "threadvars.h" #include "util-debug.h" +#include "util-misc.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -83,6 +84,7 @@ typedef struct AlertJsonOutputCtx_ { LogFileCtx* file_ctx; uint8_t flags; + uint32_t payload_buffer_size; HttpXFFCfg *xff_cfg; } AlertJsonOutputCtx; @@ -285,7 +287,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) (void *)payload); if (json_output_ctx->flags & LOG_JSON_PAYLOAD_BASE64) { - unsigned long len = JSON_STREAM_BUFFER_SIZE * 2; + unsigned long len = json_output_ctx->payload_buffer_size * 2; uint8_t encoded[len]; Base64Encode(payload->buffer, payload->offset, encoded, &len); json_object_set_new(js, "payload", json_string((char *)encoded)); @@ -479,17 +481,17 @@ static TmEcode JsonAlertLogThreadInit(ThreadVars *t, void *initdata, void **data return TM_ECODE_FAILED; } - aft->payload_buffer = MemBufferCreateNew(JSON_STREAM_BUFFER_SIZE); - if (aft->payload_buffer == NULL) { - SCFree(aft); - return TM_ECODE_FAILED; - } - /** Use the Output Context (file pointer and mutex) */ AlertJsonOutputCtx *json_output_ctx = ((OutputCtx *)initdata)->data; aft->file_ctx = json_output_ctx->file_ctx; aft->json_output_ctx = json_output_ctx; + aft->payload_buffer = MemBufferCreateNew(json_output_ctx->payload_buffer_size); + if (aft->payload_buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + *data = (void *)aft; return TM_ECODE_OK; } @@ -556,8 +558,11 @@ static void XffSetup(AlertJsonOutputCtx *json_output_ctx, ConfNode *conf) json_output_ctx->xff_cfg = xff_cfg; + uint32_t payload_buffer_size = JSON_STREAM_BUFFER_SIZE; + if (conf != NULL) { const char *payload = ConfNodeLookupChildValue(conf, "payload"); + const char *payload_buffer_value = ConfNodeLookupChildValue(conf, "payload-buffer-size"); const char *packet = ConfNodeLookupChildValue(conf, "packet"); const char *payload_printable = ConfNodeLookupChildValue(conf, "payload-printable"); const char *http = ConfNodeLookupChildValue(conf, "http"); @@ -595,12 +600,24 @@ static void XffSetup(AlertJsonOutputCtx *json_output_ctx, ConfNode *conf) json_output_ctx->flags |= LOG_JSON_PAYLOAD_BASE64; } } + if (payload_buffer_value != NULL) { + uint32_t value; + if (ParseSizeStringU32(payload_buffer_value, &value) < 0) { + SCLogError(SC_ERR_ALERT_PAYLOAD_BUFFER, "Error parsing " + "payload-buffer-size - %s. Killing engine", + payload_buffer_value); + exit(EXIT_FAILURE); + } else { + payload_buffer_size = value; + } + } if (packet != NULL) { if (ConfValIsTrue(packet)) { json_output_ctx->flags |= LOG_JSON_PACKET; } } + json_output_ctx->payload_buffer_size = payload_buffer_size; HttpXFFGetCfg(conf, xff_cfg); } } diff --git a/src/util-error.c b/src/util-error.c index 3706789b2bfa..ea1d74d9d089 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -317,6 +317,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_DEPRECATED_CONF); CASE_CODE (SC_WARN_FASTER_CAPTURE_AVAILABLE); CASE_CODE (SC_WARN_POOR_RULE); + CASE_CODE (SC_ERR_ALERT_PAYLOAD_BUFFER); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 1e9ef4f0260c..00eadd09b384 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -307,6 +307,7 @@ typedef enum { SC_ERR_DEPRECATED_CONF, /**< Deprecated configuration parameter. */ SC_WARN_FASTER_CAPTURE_AVAILABLE, SC_WARN_POOR_RULE, + SC_ERR_ALERT_PAYLOAD_BUFFER, } SCError; const char *SCErrorToString(SCError); From 69863f7b1c34fadf6148066dbc099e17812cabee Mon Sep 17 00:00:00 2001 From: maxtors Date: Sun, 24 Apr 2016 11:04:59 +0200 Subject: [PATCH 1287/2553] Corrected and unified debugmessages for init data errors in *ThreadInit. --- src/alert-debuglog.c | 2 +- src/alert-unified2-alert.c | 2 +- src/log-dnslog.c | 2 +- src/log-filestore.c | 2 +- src/log-httplog.c | 2 +- src/log-pcap.c | 2 +- src/log-stats.c | 2 +- src/log-tlsstore.c | 2 +- src/output-json-alert.c | 2 +- src/output-json-dns.c | 2 +- src/output-json-drop.c | 2 +- src/output-json-file.c | 2 +- src/output-json-flow.c | 2 +- src/output-json-http.c | 2 +- src/output-json-netflow.c | 2 +- src/output-json-smtp.c | 2 +- src/output-json-ssh.c | 2 +- src/output-json-stats.c | 2 +- src/output-json-template.c | 2 +- src/output-json-tls.c | 2 +- src/output-json.c | 4 ++-- 21 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 43bbbf98bf1e..e939df3ed013 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -401,7 +401,7 @@ static TmEcode AlertDebugLogThreadInit(ThreadVars *t, void *initdata, void **dat if(initdata == NULL) { - SCLogDebug("Error getting context for DebugLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for AlertDebugLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 9b7c6d52b092..30179d803ed1 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -1176,7 +1176,7 @@ TmEcode Unified2AlertThreadInit(ThreadVars *t, void *initdata, void **data) memset(aun, 0, sizeof(Unified2AlertThread)); if(initdata == NULL) { - SCLogDebug("Error getting context for Unified2Alert. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for AlertUnified2. \"initdata\" argument NULL"); SCFree(aun); return TM_ECODE_FAILED; } diff --git a/src/log-dnslog.c b/src/log-dnslog.c index e30c3d3e0c1a..cfb0afccb7a5 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -248,7 +248,7 @@ static TmEcode LogDnsLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for DNSLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for LogDNSLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/log-filestore.c b/src/log-filestore.c index c2507163fbd2..61a9800f743b 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -351,7 +351,7 @@ static TmEcode LogFilestoreLogThreadInit(ThreadVars *t, void *initdata, void **d if (initdata == NULL) { - SCLogDebug("Error getting context for LogFilestore. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for LogFileStore. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/log-httplog.c b/src/log-httplog.c index b9723d8c15ae..10bc4160fe22 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -542,7 +542,7 @@ TmEcode LogHttpLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for LogHTTPLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/log-pcap.c b/src/log-pcap.c index 21d41e8bd3b1..076c44269e3e 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -471,7 +471,7 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl) static TmEcode PcapLogDataInit(ThreadVars *t, void *initdata, void **data) { if (initdata == NULL) { - SCLogDebug("Error getting context for PcapLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for LogPcap. \"initdata\" argument NULL"); return TM_ECODE_FAILED; } diff --git a/src/log-stats.c b/src/log-stats.c index ae7ed50605f0..72eb3bd0891d 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -172,7 +172,7 @@ TmEcode LogStatsLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for LogStats. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c index da23908e7cf2..afb6e4a03970 100644 --- a/src/log-tlsstore.c +++ b/src/log-tlsstore.c @@ -316,7 +316,7 @@ static TmEcode LogTlsStoreLogThreadInit(ThreadVars *t, void *initdata, void **da memset(aft, 0, sizeof(LogTlsStoreLogThread)); if (initdata == NULL) { - SCLogDebug("Error getting context for LogTlsStore. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for LogTLSStore. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-alert.c b/src/output-json-alert.c index a54d66a2b0b9..f6133de8e96d 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -470,7 +470,7 @@ static TmEcode JsonAlertLogThreadInit(ThreadVars *t, void *initdata, void **data memset(aft, 0, sizeof(JsonAlertLogThread)); if(initdata == NULL) { - SCLogDebug("Error getting context for AlertFastLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogAlert. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 288142cd1191..87b276521bfc 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -286,7 +286,7 @@ static TmEcode LogDnsLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for DNSLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogDNS. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-drop.c b/src/output-json-drop.c index f93c22f4db2d..f795824b1dfe 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -184,7 +184,7 @@ static TmEcode JsonDropLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for AlertFastLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogDrop. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-file.c b/src/output-json-file.c index 0e1db3746505..964638ea6132 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -197,7 +197,7 @@ static TmEcode JsonFileLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogFile. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 0a385d81969e..6c500b466096 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -415,7 +415,7 @@ static TmEcode JsonFlowLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogFlow. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-http.c b/src/output-json-http.c index 716515fe6381..d41874909333 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -549,7 +549,7 @@ static TmEcode JsonHttpLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogHTTP. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 4065a535a0dd..3a91ec5a3ed3 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -397,7 +397,7 @@ static TmEcode JsonNetFlowLogThreadInit(ThreadVars *t, void *initdata, void **da if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogNetflow. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index b4b0bfdda01b..b205b60b039a 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -224,7 +224,7 @@ static TmEcode JsonSmtpLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for SMTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogSMTP. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 4a5542a9a12e..5218ccb81c36 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -150,7 +150,7 @@ static TmEcode JsonSshLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogSSH. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 1cc5521cc361..1b2633afe016 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -216,7 +216,7 @@ static TmEcode JsonStatsLogThreadInit(ThreadVars *t, void *initdata, void **data if(initdata == NULL) { - SCLogDebug("Error getting context for json stats. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogStats. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json-template.c b/src/output-json-template.c index 15bea7c51371..eba2cebd68e4 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -146,7 +146,7 @@ static TmEcode JsonTemplateLogThreadInit(ThreadVars *t, void *initdata, void **d } if (initdata == NULL) { - SCLogDebug("Error getting context for Template. \"initdata\" is NULL."); + SCLogDebug("Error getting context for EveLogTemplate. \"initdata\" is NULL."); SCFree(thread); return TM_ECODE_FAILED; } diff --git a/src/output-json-tls.c b/src/output-json-tls.c index cd88f1e58007..cdf03b283924 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -190,7 +190,7 @@ static TmEcode JsonTlsLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogTLS. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } diff --git a/src/output-json.c b/src/output-json.c index bcc47840530f..b3e6f7b033b3 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -20,7 +20,7 @@ * * \author Tom DeCanio * - * Logs alerts in JSON format. + * Logs detection and monitoring events in JSON format. * */ @@ -383,7 +383,7 @@ TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for AlertJson. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } From 06d74b5775a92579372dd767c38584586b373e11 Mon Sep 17 00:00:00 2001 From: maxtors Date: Sun, 24 Apr 2016 11:18:50 +0200 Subject: [PATCH 1288/2553] Module specific error code for init ctx error. --- src/log-stats.c | 2 +- src/log-tcp-data.c | 2 +- src/output-json-flow.c | 2 +- src/output-json-netflow.c | 2 +- src/output-json-smtp.c | 2 +- src/output-json-ssh.c | 2 +- src/output-json-stats.c | 2 +- src/output-json-tls.c | 2 +- src/util-error.c | 6 ++++++ src/util-error.h | 6 ++++++ 10 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/log-stats.c b/src/log-stats.c index 72eb3bd0891d..e08c6888cded 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -221,7 +221,7 @@ OutputCtx *LogStatsLogInitCtx(ConfNode *conf) { LogFileCtx *file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_STATS_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } diff --git a/src/log-tcp-data.c b/src/log-tcp-data.c index 0cf2f225f392..c3dadd4416b7 100644 --- a/src/log-tcp-data.c +++ b/src/log-tcp-data.c @@ -249,7 +249,7 @@ OutputCtx *LogTcpDataLogInitCtx(ConfNode *conf) LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_TCPDATA_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 6c500b466096..1ce4b6f2f73b 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -346,7 +346,7 @@ OutputCtx *OutputFlowLogInit(ConfNode *conf) SCLogInfo("hi"); LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_FLOW_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 3a91ec5a3ed3..52ff013cada3 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -329,7 +329,7 @@ OutputCtx *OutputNetFlowLogInit(ConfNode *conf) SCLogInfo("hi"); LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_NETFLOW_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index b205b60b039a..fd9683b920b9 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -154,7 +154,7 @@ OutputCtx *OutputSmtpLogInit(ConfNode *conf) { LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_SMTP_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 5218ccb81c36..94853c87b055 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -205,7 +205,7 @@ OutputCtx *OutputSshLogInit(ConfNode *conf) LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_SSH_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 1b2633afe016..3f45732bb443 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -265,7 +265,7 @@ OutputCtx *OutputStatsLogInit(ConfNode *conf) { LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_STATS_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } diff --git a/src/output-json-tls.c b/src/output-json-tls.c index cdf03b283924..94f6a3645b76 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -245,7 +245,7 @@ OutputCtx *OutputTlsLogInit(ConfNode *conf) LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_TLS_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } diff --git a/src/util-error.c b/src/util-error.c index ea1d74d9d089..2cd58e5c2ec1 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -318,6 +318,12 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_WARN_FASTER_CAPTURE_AVAILABLE); CASE_CODE (SC_WARN_POOR_RULE); CASE_CODE (SC_ERR_ALERT_PAYLOAD_BUFFER); + CASE_CODE (SC_ERR_STATS_LOG_GENERIC); + CASE_CODE (SC_ERR_TCPDATA_LOG_GENERIC); + CASE_CODE (SC_ERR_FLOW_LOG_GENERIC); + CASE_CODE (SC_ERR_NETFLOW_LOG_GENERIC); + CASE_CODE (SC_ERR_SMTP_LOG_GENERIC); + CASE_CODE (SC_ERR_SSH_LOG_GENERIC); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 00eadd09b384..1825b77005ea 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -308,6 +308,12 @@ typedef enum { SC_WARN_FASTER_CAPTURE_AVAILABLE, SC_WARN_POOR_RULE, SC_ERR_ALERT_PAYLOAD_BUFFER, + SC_ERR_STATS_LOG_GENERIC, + SC_ERR_TCPDATA_LOG_GENERIC, + SC_ERR_FLOW_LOG_GENERIC, + SC_ERR_NETFLOW_LOG_GENERIC, + SC_ERR_SMTP_LOG_GENERIC, + SC_ERR_SSH_LOG_GENERIC, } SCError; const char *SCErrorToString(SCError); From 9d3fd828490a3f116947bb8f35ff745d1ebe8578 Mon Sep 17 00:00:00 2001 From: maxtors Date: Sun, 24 Apr 2016 16:19:39 +0200 Subject: [PATCH 1289/2553] Removed duplicate include statements. --- src/alert-fastlog.c | 1 - src/alert-unified2-alert.c | 3 --- src/app-layer-htp-body.c | 1 - src/app-layer-htp-file.c | 1 - src/app-layer-smtp.c | 1 - src/app-layer.c | 4 ---- src/detect-app-layer-event.c | 2 -- src/detect-base64-decode.c | 3 --- src/detect-depth.c | 1 - src/detect-detection-filter.c | 2 -- src/detect-distance.c | 1 - src/detect-dns-query.c | 1 - src/detect-dsize.c | 2 +- src/detect-engine-address-ipv4.c | 1 - src/detect-engine-filedata-smtp.c | 1 - src/detect-engine-mpm.c | 1 - src/detect-engine-state.c | 1 - src/detect-engine.c | 1 - src/detect-filemagic.c | 1 - src/detect-filesize.c | 2 -- src/detect-flowbits.c | 1 - src/detect-fragoffset.c | 2 -- src/detect-icmp-id.c | 2 -- src/detect-icmp-seq.c | 2 -- src/detect-icode.c | 2 -- src/detect-ipproto.c | 3 --- src/detect-itype.c | 1 - src/detect-l3proto.c | 4 ---- src/detect-parse.c | 1 - src/detect-pcre.c | 4 ---- src/detect-threshold.c | 4 ---- src/detect-ttl.c | 2 -- src/detect-urilen.c | 1 - src/detect-within.c | 1 - src/detect.c | 2 -- src/flow.c | 1 - src/log-droplog.c | 1 - src/output-json-alert.c | 1 - src/output-json-drop.c | 1 - src/output-json.c | 1 - src/reputation.c | 2 -- src/runmode-unittests.c | 1 - src/runmode-unix-socket.c | 3 --- src/source-mpipe.c | 1 - src/util-action.c | 1 - 45 files changed, 1 insertion(+), 75 deletions(-) diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 9c2469df03b8..900fafb55a3f 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -41,7 +41,6 @@ #include "util-unittest.h" #include "util-unittest-helper.h" -#include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 30179d803ed1..5450024680dc 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -42,8 +42,6 @@ #include "alert-unified2-alert.h" #include "decode-ipv4.h" -#include "flow.h" - #include "host.h" #include "util-profiling.h" #include "decode.h" @@ -61,7 +59,6 @@ #include "app-layer-htp-xff.h" #include "output.h" -#include "alert-unified2-alert.h" #include "util-privs.h" #include "stream.h" diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index 863b8ae37451..d3720f8d39bb 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -47,7 +47,6 @@ #include "util-spm.h" #include "util-debug.h" -#include "app-layer-htp.h" #include "app-layer-htp-file.h" #include "util-time.h" diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index effc4fe08afa..9e68f097085c 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -46,7 +46,6 @@ #include "util-spm.h" #include "util-debug.h" -#include "app-layer-htp.h" #include "util-time.h" #include "util-unittest.h" diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 3402edfd27e4..701b97dcf07d 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -42,7 +42,6 @@ #include "util-debug.h" #include "util-byte.h" #include "util-unittest.h" -#include "util-byte.h" #include "util-unittest-helper.h" #include "util-memcmp.h" #include "flow-util.h" diff --git a/src/app-layer.c b/src/app-layer.c index 5d29f127474b..9c058800ae59 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -654,11 +654,7 @@ void AppLayerRegisterGlobalCounters(void) /***** Unittests *****/ #ifdef UNITTESTS - #include "stream-tcp.h" -#include "stream-tcp-private.h" -#include "stream-tcp-reassemble.h" -#include "stream-tcp-inline.h" #include "stream-tcp-util.h" #include "stream.h" #include "util-unittest.h" diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 0c9e0d949da6..173313aa1491 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -316,11 +316,9 @@ int DetectAppLayerEventPrepare(Signature *s) /**********************************Unittests***********************************/ #ifdef UNITTESTS /* UNITTESTS */ - #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" -#include "app-layer.h" #define APP_LAYER_EVENT_TEST_MAP_EVENT1 0 #define APP_LAYER_EVENT_TEST_MAP_EVENT2 1 diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index 781f3d3ef0ed..25010e43644a 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -331,10 +331,7 @@ static void DetectBase64DecodeFree(void *ptr) #ifdef UNITTESTS - -#include "detect.h" #include "detect-engine.h" -#include "detect-parse.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer-parser.h" diff --git a/src/detect-depth.c b/src/detect-depth.c index 9e323f6bf829..90661e61aa6d 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -33,7 +33,6 @@ #include "detect-content.h" #include "detect-uricontent.h" #include "detect-byte-extract.h" -#include "detect-parse.h" #include "flow-var.h" #include "app-layer.h" diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 6ffca0e315ef..32e39393f473 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -264,8 +264,6 @@ void DetectDetectionFilterFree(void *df_ptr) * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS - -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-threshold.h" diff --git a/src/detect-distance.c b/src/detect-distance.c index fe5d36599a37..6f1c492052d0 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -32,7 +32,6 @@ #include "detect-parse.h" #include "detect-engine.h" #include "app-layer.h" -#include "detect-parse.h" #include "detect-content.h" #include "detect-uricontent.h" diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 3bf708f3babe..33ffa31a96b9 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -55,7 +55,6 @@ #include "app-layer-dns-common.h" #include "detect-dns-query.h" -#include "util-unittest.h" #include "util-unittest-helper.h" static int DetectDnsQuerySetup (DetectEngineCtx *, Signature *, char *); diff --git a/src/detect-dsize.c b/src/detect-dsize.c index a331f6f4d213..00da7727e697 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -301,8 +301,8 @@ void DetectDsizeFree(void *de_ptr) */ #ifdef UNITTESTS -#include "detect.h" #include "detect-engine.h" + /** * \test this is a test for a valid dsize value 1 * diff --git a/src/detect-engine-address-ipv4.c b/src/detect-engine-address-ipv4.c index 8950f5800706..7de2af6a899a 100644 --- a/src/detect-engine-address-ipv4.c +++ b/src/detect-engine-address-ipv4.c @@ -38,7 +38,6 @@ #include "util-error.h" #include "util-debug.h" -#include "util-unittest.h" /** * \brief Compares 2 addresses(address ranges) and returns the relationship diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index c55450beedc4..64c3ba661ba5 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -47,7 +47,6 @@ #include "app-layer.h" #include "app-layer-smtp.h" #include "app-layer-protos.h" -#include "app-layer-parser.h" #include "util-validate.h" diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 39393e2bcbd9..75232c50345f 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -54,7 +54,6 @@ #include "util-enum.h" #include "util-debug.h" #include "util-print.h" -#include "util-memcmp.h" #include "util-validate.h" const char *builtin_mpms[] = { diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index b465917a18af..30c40737e482 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -1170,7 +1170,6 @@ void DetectEngineStateResetTxs(Flow *f) /*********Unittests*********/ #ifdef UNITTESTS -#include "flow-util.h" static int DeStateTest01(void) { diff --git a/src/detect-engine.c b/src/detect-engine.c index 37dc6245d1ed..c19afc2f3318 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -45,7 +45,6 @@ #include "detect-engine-tag.h" #include "detect-engine-uri.h" -#include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index c854005a1675..0ffabe741d8d 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -53,7 +53,6 @@ #include "detect-filemagic.h" #include "conf.h" -#include "util-magic.h" static int DetectFilemagicMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, Signature *, SigMatch *); diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 709097f54211..b9a1177af431 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -319,11 +319,9 @@ static void DetectFilesizeFree(void *ptr) } #ifdef UNITTESTS - #include "stream.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "app-layer-parser.h" diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 70056f02dd97..238eb91b4ccf 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -41,7 +41,6 @@ #include "detect-engine-mpm.h" #include "detect-engine-state.h" -#include "flow-bit.h" #include "util-var-name.h" #include "util-unittest.h" #include "util-debug.h" diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index 6e6049fb44c0..28d66e9bf848 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -238,8 +238,6 @@ void DetectFragOffsetFree (void *ptr) } #ifdef UNITTESTS - -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index 675e03e41038..34be0d7bb421 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -248,8 +248,6 @@ void DetectIcmpIdFree (void *ptr) } #ifdef UNITTESTS - -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index 1fbefb7c29cd..4026b3756128 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -249,8 +249,6 @@ void DetectIcmpSeqFree (void *ptr) } #ifdef UNITTESTS - -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" diff --git a/src/detect-icode.c b/src/detect-icode.c index fc5c572d1a6d..cc91bce1fabc 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -264,8 +264,6 @@ void DetectICodeFree(void *ptr) } #ifdef UNITTESTS - -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index e0c2635a0eea..dec6ad3ab5f4 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -560,9 +560,6 @@ static void DetectIPProtoFree(void *ptr) /* UNITTESTS */ #ifdef UNITTESTS -#include "detect-engine.h" -#include "detect-parse.h" - /** * \test DetectIPProtoTestParse01 is a test for an invalid proto number */ diff --git a/src/detect-itype.c b/src/detect-itype.c index 45e3a6ddf165..00ad80288612 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -265,7 +265,6 @@ void DetectITypeFree(void *ptr) #ifdef UNITTESTS -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" diff --git a/src/detect-l3proto.c b/src/detect-l3proto.c index b04057a92fe4..fb94a9a0f65f 100644 --- a/src/detect-l3proto.c +++ b/src/detect-l3proto.c @@ -122,10 +122,6 @@ static int DetectL3ProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst #ifdef UNITTESTS -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" - /** * \test DetectL3protoTestSig01 is a test for checking the working of ttl keyword * by setting up the signature and later testing its working by matching diff --git a/src/detect-parse.c b/src/detect-parse.c index e28154ad7fbc..d86826cdf1ae 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -68,7 +68,6 @@ #include "detect-parse.h" #include "detect-engine-iponly.h" #include "app-layer-detect-proto.h" -#include "app-layer.h" extern int sc_set_caps; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 0f1915495560..b4303744f4a7 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -57,10 +57,6 @@ #include "stream-tcp-reassemble.h" #include "app-layer-protos.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" - -#include "stream.h" - #define PARSE_CAPTURE_REGEX "\\(\\?P\\<([A-z]+)\\_([A-z0-9_]+)\\>" #define PARSE_REGEX "(? #include #include -#include /* Align "p" mod "align", assuming "p" is a "void*". */ #define ALIGN(p, align) do { (p) += -(long)(p) & ((align) - 1); } while(0) diff --git a/src/util-action.c b/src/util-action.c index d0bc235f9739..a47e79dfcad6 100644 --- a/src/util-action.c +++ b/src/util-action.c @@ -163,7 +163,6 @@ int ActionInitConfig() } #ifdef UNITTESTS -#include "util-unittest.h" /** * \test Check that we invalidate duplicated actions From 5c514c904ffee373b8d872ee13ff3eda7d1fec9c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 21 Apr 2016 14:37:43 +0200 Subject: [PATCH 1290/2553] smtp: fix file logging and matching When no rules with 'file content' keywords like filemd5 or filestore were used, and non of the file outputs would force 'output' like 'force-md5' and 'force-magic', the file would not be tracked at all. This meant that logging wouldn't work and neither would filename and fileext inspection. This patch removes the tracking bypass from the SMTP code and leaves decisions to the file API. --- src/app-layer-smtp.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 701b97dcf07d..79d4f16b83cc 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -406,13 +406,6 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, flags |= FILE_NOMD5; } - /* Determine whether to process files */ - if ((flags & (FILE_NOSTORE | FILE_NOMAGIC | FILE_NOMD5)) == - (FILE_NOSTORE | FILE_NOMAGIC | FILE_NOMD5)) { - SCLogDebug("File content ignored"); - return 0; - } - /* Find file */ if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { From 19d112ba077cae4d79beb5f4944ec78a0a69f8fd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 21 Apr 2016 15:14:45 +0200 Subject: [PATCH 1291/2553] smtp/mime: allow unquoted name/filename fields Don't enforce that name/filename fields are quoted. Reported-By: Blair Steven --- src/util-decode-mime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 81d8bc720bd1..60206c20e32c 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -1891,7 +1891,7 @@ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, /* Check for file attachment in content disposition */ field = MimeDecFindField(entity, CTNT_DISP_STR); if (field != NULL) { - bptr = FindMimeHeaderToken(field, "filename=\"", TOK_END_STR, &blen); + bptr = FindMimeHeaderToken(field, "filename=", TOK_END_STR, &blen); if (bptr != NULL) { SCLogDebug("File attachment found in disposition"); entity->ctnt_flags |= CTNT_IS_ATTACHMENT; @@ -1933,7 +1933,7 @@ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, /* Look for file name (if not already found) */ if (!(entity->ctnt_flags & CTNT_IS_ATTACHMENT)) { - bptr = FindMimeHeaderToken(field, "name=\"", TOK_END_STR, &blen); + bptr = FindMimeHeaderToken(field, "name=", TOK_END_STR, &blen); if (bptr != NULL) { SCLogDebug("File attachment found"); entity->ctnt_flags |= CTNT_IS_ATTACHMENT; From 807fe4ac9fc49f9bbdfbab14aef77e70fe331627 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 22 Apr 2016 08:53:19 +0200 Subject: [PATCH 1292/2553] detect state: fix issues with multiple files per tx Make sure multiple files in a single tx are inspected correctly. This requires resetting part of the stored state on new files. --- src/detect-engine-state.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 30c40737e482..2ba935b58041 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -721,6 +721,7 @@ static int DoInspectItem(ThreadVars *tv, { item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; + item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; } if ((flags & STREAM_TOSERVER) && @@ -728,6 +729,7 @@ static int DoInspectItem(ThreadVars *tv, { item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; + item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; } } @@ -1055,6 +1057,9 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } } } + + tx_dir_state->flags &= + ~(DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW|DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW); } /* if the current tx is in progress, we won't advance to any newer * tx' just yet. */ From aa4ad9d25b042fc7f6cb9f0d704a3c7420fd6d32 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 20 Apr 2016 17:27:41 +0200 Subject: [PATCH 1293/2553] smtp: flag detect state that new files are available The stateful detection engine needs some assistance when inspecting transactions with multiple files. This patch flags the detect state (if any) about the availability of new files in smtp. --- src/app-layer-smtp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 79d4f16b83cc..0444610a8ae8 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -382,6 +382,14 @@ static void SMTPPruneFiles(FileContainer *files) } } +static void FlagDetectStateNewFile(SMTPTransaction *tx) +{ + if (tx && tx->de_state) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW set"); + tx->de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW; + } +} + int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state) { @@ -443,6 +451,7 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, ret = MIME_DEC_ERR_DATA; SCLogDebug("FileOpenFile() failed"); } + FlagDetectStateNewFile(smtp_state->curr_tx); /* If close in the same chunk, then pass in empty bytes */ if (state->body_end) { From 83e0529b2b7cf953c83a6fbf5c59279f02574caf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 20 Apr 2016 18:42:01 +0200 Subject: [PATCH 1294/2553] http: flag destate about new files The stateful detection engine needs some assistance when inspecting transactions with multiple files. This patch flags the detect state (if any) about the availability of new files in http. For http it should only apply to multipart bodies although the flag is set for all files. --- src/app-layer-htp.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index a3db82b1895b..4e76c5feb20e 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1226,6 +1226,19 @@ static void HtpRequestBodyReassemble(HtpTxUserData *htud, *chunks_buffer_len = buf_len; } +static void FlagDetectStateNewFile(HtpTxUserData *tx, int dir) +{ + if (tx && tx->de_state) { + if (dir == STREAM_TOSERVER) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW set"); + tx->de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW; + } else if (STREAM_TOCLIENT) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW set"); + tx->de_state->dir_state[1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW; + } + } +} + /** * \brief Setup boundary buffers */ @@ -1428,6 +1441,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, goto end; } } + FlagDetectStateNewFile(htud, STREAM_TOSERVER); htud->request_body.body_parsed += (header_end - chunks_buffer); htud->tsflags &= ~HTP_FILENAME_SET; @@ -1472,6 +1486,8 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } + FlagDetectStateNewFile(htud, STREAM_TOSERVER); + } else if (header_next - filedata > 2) { filedata_len = header_next - filedata - 2; SCLogDebug("filedata_len %u", filedata_len); @@ -1488,6 +1504,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, goto end; } } + FlagDetectStateNewFile(htud, STREAM_TOSERVER); htud->tsflags &= ~HTP_FILENAME_SET; htud->request_body.body_parsed += (header_end - chunks_buffer); @@ -1568,6 +1585,7 @@ static int HtpRequestBodyHandlePOST(HtpState *hstate, HtpTxUserData *htud, } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } else { + FlagDetectStateNewFile(htud, STREAM_TOSERVER); htud->tsflags |= HTP_FILENAME_SET; htud->tsflags &= ~HTP_DONTSTORE; } @@ -1621,6 +1639,7 @@ static int HtpRequestBodyHandlePUT(HtpState *hstate, HtpTxUserData *htud, } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } else { + FlagDetectStateNewFile(htud, STREAM_TOSERVER); htud->tsflags |= HTP_FILENAME_SET; htud->tsflags &= ~HTP_DONTSTORE; } @@ -1688,6 +1707,7 @@ int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud, } else if (result == -2) { htud->tcflags |= HTP_DONTSTORE; } else { + FlagDetectStateNewFile(htud, STREAM_TOCLIENT); htud->tcflags |= HTP_FILENAME_SET; htud->tcflags &= ~HTP_DONTSTORE; } From ea0067add8006f125bb0fa185d89f9228dad5a5e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 20 Apr 2016 17:47:31 +0200 Subject: [PATCH 1295/2553] debug: add various detect engine debug statements --- src/detect-engine-state.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 2ba935b58041..45449ee1b337 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -415,6 +415,7 @@ static void StoreStateTxHandleFiles(DetectEngineThreadCtx *det_ctx, Flow *f, DetectEngineState *destate, const uint8_t flags, const uint64_t tx_id, const uint16_t file_no_match) { + SCLogDebug("tx %u, file_no_match %u", (uint)tx_id, file_no_match); DeStateStoreFileNoMatchCnt(destate, file_no_match, flags); if (DeStateStoreFilestoreSigsCantMatch(det_ctx->sgh, destate, flags) == 1) { FileDisableStoringForTransaction(f, flags & (STREAM_TOCLIENT | STREAM_TOSERVER), tx_id); @@ -464,6 +465,8 @@ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, SCLogDebug("destate created for %"PRIu64, tx_id); } + SCLogDebug("file_no_match %u", file_no_match); + if (check_before_add == 0 || DeStateSearchState(destate, flags, s->num) == 0) DeStateSignatureAppend(destate, s, inspect_flags, flags); DeStateStoreStateVersion(f, alversion, flags); @@ -485,6 +488,8 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, int alert_cnt = 0; int check_before_add = 0; + SCLogDebug("rule %u", s->id); + FLOWLOCK_WRLOCK(f); /* TX based matches (inspect engines) */ if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { @@ -516,18 +521,24 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, for (; tx_id < total_txs; tx_id++) { int total_matches = 0; void *tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id); + SCLogDebug("tx %p", tx); if (tx == NULL) continue; det_ctx->tx_id = tx_id; det_ctx->tx_id_set = 1; + DetectEngineAppInspectionEngine *engine = app_inspection_engine[f->protomap][alproto][direction]; + SCLogDebug("engine %p", engine); inspect_flags = 0; while (engine != NULL) { + SCLogDebug("engine %p", engine); + SCLogDebug("inspect_flags %x", inspect_flags); if (s->sm_lists[engine->sm_list] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); int match = engine->Callback(tv, de_ctx, det_ctx, s, f, flags, alstate, tx, tx_id); + SCLogDebug("engine %p match %d", engine, match); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { inspect_flags |= engine->inspect_flags; engine = engine->next; @@ -545,6 +556,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } engine = engine->next; } + SCLogDebug("inspect_flags %x", inspect_flags); /* all the engines seem to be exhausted at this point. If we * didn't have a match in one of the engines we would have * broken off and engine wouldn't be NULL. Hence the alert. */ @@ -712,6 +724,8 @@ static int DoInspectItem(ThreadVars *tv, { Signature *s = de_ctx->sig_array[item->sid]; + SCLogDebug("file_no_match %u, sid %u", *file_no_match, s->id); + /* check if a sig in state 'full inspect' needs to be reconsidered * as the result of a new file in the existing tx */ if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { @@ -719,6 +733,7 @@ static int DoInspectItem(ThreadVars *tv, if ((flags & STREAM_TOCLIENT) && (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW)) { + SCLogDebug("~DE_STATE_FLAG_FILE_TC_INSPECT"); item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; @@ -727,6 +742,7 @@ static int DoInspectItem(ThreadVars *tv, if ((flags & STREAM_TOSERVER) && (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW)) { + SCLogDebug("~DE_STATE_FLAG_FILE_TS_INSPECT"); item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; @@ -736,7 +752,7 @@ static int DoInspectItem(ThreadVars *tv, if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { if (TxIsLast(inspect_tx_id, total_txs) || inprogress || next_tx_no_progress) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - SCLogDebug("skip and bypass: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + SCLogDebug("skip and bypass %u: tx %u packet %u", s->id, (uint)inspect_tx_id, (uint)p->pcap_cnt); } else { SCLogDebug("just skip: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); @@ -758,17 +774,23 @@ static int DoInspectItem(ThreadVars *tv, /* check if a sig in state 'cant match' needs to be reconsidered * as the result of a new file in the existing tx */ + SCLogDebug("item->flags %x", item->flags); if (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) { + SCLogDebug("DE_STATE_FLAG_SIG_CANT_MATCH"); + if ((flags & STREAM_TOSERVER) && (item->flags & DE_STATE_FLAG_FILE_TS_INSPECT) && (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW)) { + SCLogDebug("unset ~DE_STATE_FLAG_FILE_TS_INSPECT ~DE_STATE_FLAG_SIG_CANT_MATCH"); item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; + } else if ((flags & STREAM_TOCLIENT) && (item->flags & DE_STATE_FLAG_FILE_TC_INSPECT) && (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW)) { + SCLogDebug("unset ~DE_STATE_FLAG_FILE_TC_INSPECT ~DE_STATE_FLAG_SIG_CANT_MATCH"); item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; } else { @@ -821,6 +843,7 @@ static int DoInspectItem(ThreadVars *tv, if (!(item->flags & engine->inspect_flags) && s->sm_lists[engine->sm_list] != NULL) { + SCLogDebug("inspect_flags %x", inspect_flags); KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); int match = engine->Callback(tv, de_ctx, det_ctx, s, f, flags, alstate, inspect_tx, inspect_tx_id); @@ -841,6 +864,7 @@ static int DoInspectItem(ThreadVars *tv, } engine = engine->next; } + SCLogDebug("inspect_flags %x", inspect_flags); if (total_matches > 0 && (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { if (engine == NULL) alert = 1; @@ -1025,6 +1049,8 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineStateDirection *tx_dir_state = &tx_de_state->dir_state[direction]; DeStateStore *tx_store = tx_dir_state->head; + SCLogDebug("tx_dir_state->filestore_cnt %u", tx_dir_state->filestore_cnt); + /* see if we need to consider the next tx in our decision to add * a sig to the 'no inspect array'. */ if (!TxIsLast(inspect_tx_id, total_txs)) { From 8cd4405c213bc5f4344f2d5d37cf7a3dacbeeec5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 21 Apr 2016 10:08:06 +0200 Subject: [PATCH 1296/2553] detect file: cleanups --- src/detect-engine-file.c | 64 ++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index 319936851b94..8c7082c53f82 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -106,31 +106,31 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, if ((s->file_flags & FILE_SIG_NEED_FILENAME) && file->name == NULL) { SCLogDebug("sig needs filename, but we don't have any"); - r = 0; + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } if ((s->file_flags & FILE_SIG_NEED_MAGIC) && file->chunks_head == NULL) { SCLogDebug("sig needs file content, but we don't have any"); - r = 0; + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } if ((s->file_flags & FILE_SIG_NEED_FILECONTENT) && file->chunks_head == NULL) { SCLogDebug("sig needs file content, but we don't have any"); - r = 0; + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } if ((s->file_flags & FILE_SIG_NEED_MD5) && (!(file->flags & FILE_MD5))) { SCLogDebug("sig needs file md5, but we don't have any"); - r = 0; + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } if ((s->file_flags & FILE_SIG_NEED_SIZE) && file->state < FILE_STATE_CLOSED) { SCLogDebug("sig needs filesize, but state < FILE_STATE_CLOSED"); - r = 0; + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } @@ -144,10 +144,10 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, FileMatch(tv, det_ctx, f, flags, file, s, sm); KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); if (match == 0) { - r = 2; + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; break; } else if (sm->next == NULL) { - r = 1; + r = DETECT_ENGINE_INSPECT_SIG_MATCH; break; } } @@ -156,13 +156,13 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, /* continue inspection for other files as we may want to store * those as well. We'll return 1 (match) regardless of their * results though */ - if (r == 1) - store_r = 1; + if (r == DETECT_ENGINE_INSPECT_SIG_MATCH) + store_r = DETECT_ENGINE_INSPECT_SIG_MATCH; /* if this is a filestore sig, and the sig can't match * return 3 so we can distinguish */ - if ((s->flags & SIG_FLAG_FILESTORE) && r == 2) - r = 3; + if ((s->flags & SIG_FLAG_FILESTORE) && r == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; /* continue, this file may (or may not) be unable to match * maybe we have more that can :) */ @@ -182,14 +182,14 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); if (match == 1) { - r = 1; + r = DETECT_ENGINE_INSPECT_SIG_MATCH; } } } } - if (store_r == 1) - r = 1; + if (store_r == DETECT_ENGINE_INSPECT_SIG_MATCH) + r = DETECT_ENGINE_INSPECT_SIG_MATCH; SCReturnInt(r); } @@ -225,18 +225,14 @@ int DetectFileInspectHttp(ThreadVars *tv, ffc = htp_state->files_ts; int match = DetectFileInspect(tv, det_ctx, f, s, flags, ffc); - if (match == 1) { + if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { r = DETECT_ENGINE_INSPECT_SIG_MATCH; - } else if (match == 2) { - if (r != 1) { - SCLogDebug("sid %u can't match on this transaction", s->id); - r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } - } else if (match == 3) { - if (r != 1) { - SCLogDebug("sid %u can't match on this transaction (filestore sig)", s->id); - r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; - } + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { + SCLogDebug("sid %u can't match on this transaction", s->id); + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { + SCLogDebug("sid %u can't match on this transaction (filestore sig)", s->id); + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; } return r; @@ -281,18 +277,14 @@ int DetectFileInspectSmtp(ThreadVars *tv, goto end; int match = DetectFileInspect(tv, det_ctx, f, s, flags, ffc); - if (match == 1) { + if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { r = DETECT_ENGINE_INSPECT_SIG_MATCH; - } else if (match == 2) { - if (r != 1) { - SCLogDebug("sid %u can't match on this transaction", s->id); - r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } - } else if (match == 3) { - if (r != 1) { - SCLogDebug("sid %u can't match on this transaction (filestore sig)", s->id); - r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; - } + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { + SCLogDebug("sid %u can't match on this transaction", s->id); + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { + SCLogDebug("sid %u can't match on this transaction (filestore sig)", s->id); + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; } From c4a9580fce91bafc5e2cfcf366dd50a3ec16eaaa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 21 Apr 2016 13:17:33 +0200 Subject: [PATCH 1297/2553] detect file: improve multi file handling When multiple files were in a tx, the first one(s) closed/complete and a new open one as well, a match in the former could lead to not inspecting the latter. This patch adds a workaround for this case, by allowing the file inspection code to return a special code for 'match, but more files available in tx'. The stateful detection engine will then not make this match final for the tx. It relies on the file pruning to kick in to make sure the already complete files are removed from the tx before the next time the detection engine is called on the tx. --- src/app-layer-smtp.c | 5 +++++ src/detect-engine-file.c | 10 ++++++++-- src/detect-engine-state.c | 14 ++++++++++++++ src/detect-engine-state.h | 6 ++++++ src/util-file.c | 4 ++++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 0444610a8ae8..bbfc1a5e29bc 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -360,6 +360,7 @@ static void SMTPPruneFiles(FileContainer *files) File *file = files->head; while (file) { + SCLogDebug("file %p, file->chunks_head %p", file, file->chunks_head); if (file->chunks_head) { uint32_t window = smtp_config.content_inspect_window; if (file->chunks_head->stream_offset == 0) @@ -387,6 +388,10 @@ static void FlagDetectStateNewFile(SMTPTransaction *tx) if (tx && tx->de_state) { SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW set"); tx->de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW; + } else if (tx == NULL) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW NOT set, no TX"); + } else if (tx->de_state == NULL) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW NOT set, no TX DESTATE"); } } diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index 8c7082c53f82..e50b4ce964dd 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -88,7 +88,6 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, File *file = ffc->head; for (; file != NULL; file = file->next) { SCLogDebug("file"); - if (file->state == FILE_STATE_NONE) { SCLogDebug("file state FILE_STATE_NONE"); continue; @@ -188,6 +187,11 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, } } + if (r == DETECT_ENGINE_INSPECT_SIG_NO_MATCH && store_r == DETECT_ENGINE_INSPECT_SIG_MATCH) { + SCLogDebug("stored MATCH, current file NOMATCH"); + SCReturnInt(DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES); + } + if (store_r == DETECT_ENGINE_INSPECT_SIG_MATCH) r = DETECT_ENGINE_INSPECT_SIG_MATCH; SCReturnInt(r); @@ -285,9 +289,11 @@ int DetectFileInspectSmtp(ThreadVars *tv, } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { SCLogDebug("sid %u can't match on this transaction (filestore sig)", s->id); r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; + } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) { + SCLogDebug("match with more files ahead"); + r = match; } - end: SCReturnInt(r); } diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 45449ee1b337..436fdf125966 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -544,6 +544,13 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, engine = engine->next; total_matches++; continue; + } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) { + /* if the file engine matched, but indicated more + * files are still in progress, we don't set inspect + * flags as these would end inspection for this tx */ + engine = engine->next; + total_matches++; + continue; } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; inspect_flags |= engine->inspect_flags; @@ -852,6 +859,13 @@ static int DoInspectItem(ThreadVars *tv, engine = engine->next; total_matches++; continue; + } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) { + /* if the file engine matched, but indicated more + * files are still in progress, we don't set inspect + * flags as these would end inspection for this tx */ + engine = engine->next; + total_matches++; + continue; } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; inspect_flags |= engine->inspect_flags; diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index c8944cffd17c..c5264816ee5b 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -52,6 +52,12 @@ #define DETECT_ENGINE_INSPECT_SIG_MATCH 1 #define DETECT_ENGINE_INSPECT_SIG_CANT_MATCH 2 #define DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE 3 +/** hack to work around a file inspection limitation. Since there can be + * multiple files in a TX and the detection engine really don't know + * about that, we have to give the file inspection engine a way to + * indicate that one of the files matched, but that there are still + * more files that have ongoing inspection. */ +#define DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES 4 /** number of DeStateStoreItem's in one DeStateStore object */ #define DE_STATE_CHUNK_SIZE 15 diff --git a/src/util-file.c b/src/util-file.c index 2b45f3360769..c9aab3e1266b 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -199,6 +199,8 @@ static int FilePruneFile(File *file) } } + SCLogDebug("file->state %d. Is >= FILE_STATE_CLOSED: %s", file->state, (file->state >= FILE_STATE_CLOSED) ? "yes" : "no"); + /* file is done when state is closed+, logging/storing is done (if any) */ if (file->state >= FILE_STATE_CLOSED && (!RunModeOutputFileEnabled() || (file->flags & FILE_LOGGED)) && @@ -220,6 +222,8 @@ void FilePrune(FileContainer *ffc) BUG_ON(file != ffc->head); + SCLogDebug("removing file %p", file); + File *file_next = file->next; /* update head and tail */ From 7f700a137cd54497c16d99a0c4418f1296a87aaa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 21 Apr 2016 16:51:54 +0200 Subject: [PATCH 1298/2553] smtp: fix test --- src/app-layer-smtp.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index bbfc1a5e29bc..c7385d8d5ade 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -5040,35 +5040,28 @@ int SMTPProcessDataChunkTest05(void){ 0x41, 0x3D, 0x3D, 0x0D, 0x0A,}; Flow f; + int ret; FLOW_INITIALIZE(&f); f.alstate = SMTPStateAlloc(); + FAIL_IF(f.alstate == NULL); MimeDecParseState *state = MimeDecInitParser(&f, NULL); ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + FAIL_IF(state == NULL); state->body_begin = 1; - int ret; - uint64_t file_size = 0; ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + FAIL_IF(ret != 0); state->body_begin = 0; - if(ret){goto end;} SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate; FileContainer *files = smtp_state->files_ts; + FAIL_IF(files == NULL); File *file = files->head; - file_size = file->size; - - FileDisableStoring(&f, STREAM_TOSERVER); - FileDisableMagic(&f, STREAM_TOSERVER); - FileDisableMd5(&f, STREAM_TOSERVER); + FAIL_IF(file == NULL); ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); - if(ret){goto end;} - printf("%u\t%u\n", (uint32_t) file->size, (uint32_t) file_size); - if(file->size == file_size){ - return 1; - }else{ - return 0; - } - - end: - return ret == 0; + FAIL_IF(ret != 0); + FAIL_IF(file->size != 106); + SMTPStateFree(smtp_state); + FLOW_DESTROY(&f); + PASS; } #endif /* UNITTESTS */ From 63937cd9039f7b5205ba732209b850396d07ede8 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 29 Apr 2016 19:49:11 +0200 Subject: [PATCH 1299/2553] detect-msg: fix option parsing Code removing the space before the double quote at msg option start was not working correctly for option starting with a space. --- src/detect-msg.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/detect-msg.c b/src/detect-msg.c index 8de5da567536..31484511a902 100644 --- a/src/detect-msg.c +++ b/src/detect-msg.c @@ -64,7 +64,7 @@ static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *msgstr) /* Strip leading and trailing "s. */ if (msgstr[pos] == '\"') { - str = SCStrdup(msgstr+1); + str = SCStrdup(msgstr + pos + 1); if (unlikely(str == NULL)) goto error; if (strlen(str) && str[strlen(str) - 1] == '\"') { @@ -198,6 +198,36 @@ static int DetectMsgParseTest02(void) return result; } +static int DetectMsgParseTest03(void) +{ + int result = 0; + Signature *sig = NULL; + char *teststringparsed = "flow stateless to_server"; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); + + sig = SigInit(de_ctx, "alert tcp any any -> any any (msg: \"flow stateless to_server\"; flow:stateless,to_server; content:\"flowstatelesscheck\"; classtype:bad-unknown; sid: 40000002; rev: 1;)"); + if(sig == NULL) + goto end; + + if (strcmp(sig->msg, teststringparsed) != 0) { + printf("got \"%s\", expected: \"%s\": ", sig->msg, teststringparsed); + goto end; + } + + result = 1; +end: + if (sig != NULL) + SigFree(sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + #endif /* UNITTESTS */ /** @@ -208,6 +238,7 @@ void DetectMsgRegisterTests(void) #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectMsgParseTest01", DetectMsgParseTest01); UtRegisterTest("DetectMsgParseTest02", DetectMsgParseTest02); + UtRegisterTest("DetectMsgParseTest03", DetectMsgParseTest03); #endif /* UNITTESTS */ } From 10d1450e4995630834736bcb5ed192a463d87659 Mon Sep 17 00:00:00 2001 From: maxtors Date: Wed, 15 Apr 2015 15:21:24 +0200 Subject: [PATCH 1300/2553] Added shortening of listening interface in util-runmodes Added function LiveSafeDeviceName in util-device that shortens an NIC device name if the name is over a given length and turns it in to Ex: longi...eeth1 --- src/util-device.c | 25 +++++++++++++++++++++++++ src/util-device.h | 1 + src/util-runmodes.c | 6 ++++++ 3 files changed, 32 insertions(+) diff --git a/src/util-device.c b/src/util-device.c index 9332fcec4f5c..917e98953735 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -19,6 +19,9 @@ #include "conf.h" #include "util-device.h" +#define MAX_DEVNAME 12 +#define DEVNAME_CHUNCK 5 + /** * \file * @@ -105,6 +108,28 @@ char *LiveGetDeviceName(int number) return NULL; } +/** + * \brief Shorten a device name that is to long + * + * \param device name from config and destination for modified + * + * \retval None, is added to destination char *newdevname + */ +void LiveSafeDeviceName(const char *devname, char *newdevname) +{ + size_t devnamelen = strlen(devname); + + if (devnamelen > MAX_DEVNAME) { + strncpy(newdevname, devname, DEVNAME_CHUNCK); + strncpy(newdevname+DEVNAME_CHUNCK, "...", 3); + strncpy(newdevname+8, devname+(devnamelen-DEVNAME_CHUNCK), DEVNAME_CHUNCK); + strncpy(newdevname+13, "\0", 1); + SCLogInfo("Shortening device name to: %s", newdevname); + } else { + strcpy(newdevname, devname); + } +} + /** * \brief Get a pointer to the device at idx * diff --git a/src/util-device.h b/src/util-device.h index 1fabdbe59665..5260db16f0c6 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -35,6 +35,7 @@ typedef struct LiveDevice_ { int LiveRegisterDevice(const char *dev); int LiveGetDeviceCount(void); char *LiveGetDeviceName(int number); +void LiveSafeDeviceName(const char *devname, char *newdevname); LiveDevice *LiveGetDevice(const char *dev); int LiveBuildDeviceList(const char *base); void LiveDeviceHasNoStats(void); diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 3c5f39a7752e..cfeba9a845f9 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -186,6 +186,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, for (lthread = 0; lthread < nlive; lthread++) { char *live_dev = LiveGetDeviceName(lthread); + char visual_devname[14] = ""; void *aconf; int threads_count; @@ -204,6 +205,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, threads_count = ModThreadsCount(aconf); for (thread = 0; thread < threads_count; thread++) { + LiveSafeDeviceName(live_dev, visual_devname); snprintf(tname, sizeof(tname), "%s%s%d", thread_name, live_dev, thread+1); ThreadVars *tv_receive = @@ -314,12 +316,16 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod /* create the threads */ for (thread = 0; thread < threads_count; thread++) { char tname[TM_THREAD_NAME_MAX]; + char *n_thread_name = NULL; + char visual_devname[13] = ""; ThreadVars *tv = NULL; TmModule *tm_module = NULL; if (single_mode) { snprintf(tname, sizeof(tname), "%s", thread_name); } else { + LiveSafeDeviceName(live_dev, visual_devname); + SCLogInfo("New dev name %s", visual_devname); snprintf(tname, sizeof(tname), "%s%s%d", thread_name, live_dev, thread+1); } From 88a6e7960799370b9e9f56a94a3be630043e3c3d Mon Sep 17 00:00:00 2001 From: maxtors Date: Wed, 15 Apr 2015 16:38:58 +0200 Subject: [PATCH 1301/2553] Fixed string copy and cat functions and made shortening safer. Changed out strcpy, strncpy to strlcat and strlcpy. Also added checks to see if the shortening did work or if it would fail in advance. Fixed code in util-device and util-runmodes. --- src/util-device.c | 20 ++++++++++++++------ src/util-device.h | 2 +- src/util-runmodes.c | 25 +++++++++++++++++++++---- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/util-device.c b/src/util-device.c index 917e98953735..6d0e0d3d7d66 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -115,19 +115,27 @@ char *LiveGetDeviceName(int number) * * \retval None, is added to destination char *newdevname */ -void LiveSafeDeviceName(const char *devname, char *newdevname) +int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen) { size_t devnamelen = strlen(devname); + // If we have to shorten the interface name if (devnamelen > MAX_DEVNAME) { - strncpy(newdevname, devname, DEVNAME_CHUNCK); - strncpy(newdevname+DEVNAME_CHUNCK, "...", 3); - strncpy(newdevname+8, devname+(devnamelen-DEVNAME_CHUNCK), DEVNAME_CHUNCK); - strncpy(newdevname+13, "\0", 1); + + // We need 13 chars to do this shortening + if (destlen < 13) { + return 1; + } + + size_t length; + length = strlcpy(newdevname, devname, DEVNAME_CHUNCK); + length = strlcat(newdevname, "...", DEVNAME_CHUNCK+3); + length = strlcat(newdevname, devname+(devnamelen-DEVNAME_CHUNCK), length+DEVNAME_CHUNCK); SCLogInfo("Shortening device name to: %s", newdevname); } else { - strcpy(newdevname, devname); + strlcpy(newdevname, devname, destlen); } + return 0; } /** diff --git a/src/util-device.h b/src/util-device.h index 5260db16f0c6..a6f78dd50b1a 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -35,7 +35,7 @@ typedef struct LiveDevice_ { int LiveRegisterDevice(const char *dev); int LiveGetDeviceCount(void); char *LiveGetDeviceName(int number); -void LiveSafeDeviceName(const char *devname, char *newdevname); +int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen); LiveDevice *LiveGetDevice(const char *dev); int LiveBuildDeviceList(const char *base); void LiveDeviceHasNoStats(void); diff --git a/src/util-runmodes.c b/src/util-runmodes.c index cfeba9a845f9..85c1d50190db 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -187,6 +187,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, for (lthread = 0; lthread < nlive; lthread++) { char *live_dev = LiveGetDeviceName(lthread); char visual_devname[14] = ""; + int shortening_result; void *aconf; int threads_count; @@ -205,9 +206,20 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, threads_count = ModThreadsCount(aconf); for (thread = 0; thread < threads_count; thread++) { - LiveSafeDeviceName(live_dev, visual_devname); + shortening_result = LiveSafeDeviceName(live_dev, visual_devname, 13); + if (shortening_result != 0) { + SCLogError(SC_ERR_INVALID_VALUE, "Could not shorten long devicename: %s", live_dev); + exit(EXIT_FAILURE); + } + snprintf(tname, sizeof(tname), "%s%s%d", thread_name, live_dev, thread+1); + + char *thread_name = SCStrdup(tname); + if (unlikely(thread_name == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); + exit(EXIT_FAILURE); + } ThreadVars *tv_receive = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", @@ -317,15 +329,20 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod for (thread = 0; thread < threads_count; thread++) { char tname[TM_THREAD_NAME_MAX]; char *n_thread_name = NULL; - char visual_devname[13] = ""; + char visual_devname[14] = ""; + int shortening_result; ThreadVars *tv = NULL; TmModule *tm_module = NULL; if (single_mode) { snprintf(tname, sizeof(tname), "%s", thread_name); } else { - LiveSafeDeviceName(live_dev, visual_devname); - SCLogInfo("New dev name %s", visual_devname); + shortening_result = LiveSafeDeviceName(live_dev, visual_devname, 13); + if (shortening_result != 0) { + SCLogError(SC_ERR_INVALID_VALUE, "Could not shorten long devicename: %s", live_dev); + exit(EXIT_FAILURE); + } + snprintf(tname, sizeof(tname), "%s%s%d", thread_name, live_dev, thread+1); } From a17ac21077a9b3264020793e7a67518b339a3680 Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 16 Apr 2015 22:22:54 +0200 Subject: [PATCH 1302/2553] Reworked how shortening should be performed. The shortening of the interfacenames is now dependent on the size of the destination buffer, so that this can be easily changed in the future. The process uses snprintf and strlcat. Also changed the buffer sizes in the util-runmodes to 12 so that they can hold 11 chars + null terminator. --- src/util-device.c | 41 +++++++++++++++++++++++++++++++++-------- src/util-runmodes.c | 8 ++++---- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/util-device.c b/src/util-device.c index 6d0e0d3d7d66..b29583f57495 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -19,8 +19,7 @@ #include "conf.h" #include "util-device.h" -#define MAX_DEVNAME 12 -#define DEVNAME_CHUNCK 5 +#define MAX_DEVNAME 11 /** * \file @@ -119,18 +118,44 @@ int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen) { size_t devnamelen = strlen(devname); - // If we have to shorten the interface name + /* If we have to shorten the interface name */ if (devnamelen > MAX_DEVNAME) { - // We need 13 chars to do this shortening - if (destlen < 13) { + /* IF the dest length is over 11 chars long it will not do any + * good for the shortening. The shortening is done due to the + * max length of pthread names (15 chars) and we use 2 chars + * for the threadname indicator eg. "W-" and one-two chars for + * the thread number. And if the destination buffer is under + * 6 chars there is point in shortening it since we must at + * lest enter two periodes (.) into the string.. + */ + if ((destlen-1) > 11 && (destlen-1) < 6) { return 1; } size_t length; - length = strlcpy(newdevname, devname, DEVNAME_CHUNCK); - length = strlcat(newdevname, "...", DEVNAME_CHUNCK+3); - length = strlcat(newdevname, devname+(devnamelen-DEVNAME_CHUNCK), length+DEVNAME_CHUNCK); + size_t half; + size_t spaces; + + half = (destlen-1) / 2; + + /* If the destlen is an even number */ + if (half * 2 == (destlen-1)) { + half = half - 1; + } + + spaces = (destlen-1) - (half*2); + length = half; + + /* Add the first half to the new dev name */ + snprintf(newdevname, half+1, "%s", devname); + + /* Add the amount of spaces wanted */ + for (uint i = half; i < half+spaces; i++) { + length = strlcat(newdevname, ".", destlen); + } + + snprintf(newdevname+length, half+1, "%s", devname+(devnamelen-half)); SCLogInfo("Shortening device name to: %s", newdevname); } else { strlcpy(newdevname, devname, destlen); diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 85c1d50190db..30b410e2cd23 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -186,7 +186,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, for (lthread = 0; lthread < nlive; lthread++) { char *live_dev = LiveGetDeviceName(lthread); - char visual_devname[14] = ""; + char visual_devname[12] = ""; int shortening_result; void *aconf; int threads_count; @@ -206,7 +206,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, threads_count = ModThreadsCount(aconf); for (thread = 0; thread < threads_count; thread++) { - shortening_result = LiveSafeDeviceName(live_dev, visual_devname, 13); + shortening_result = LiveSafeDeviceName(live_dev, visual_devname, sizeof(visual_devname)); if (shortening_result != 0) { SCLogError(SC_ERR_INVALID_VALUE, "Could not shorten long devicename: %s", live_dev); exit(EXIT_FAILURE); @@ -329,7 +329,7 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod for (thread = 0; thread < threads_count; thread++) { char tname[TM_THREAD_NAME_MAX]; char *n_thread_name = NULL; - char visual_devname[14] = ""; + char visual_devname[12] = ""; int shortening_result; ThreadVars *tv = NULL; TmModule *tm_module = NULL; @@ -337,7 +337,7 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod if (single_mode) { snprintf(tname, sizeof(tname), "%s", thread_name); } else { - shortening_result = LiveSafeDeviceName(live_dev, visual_devname, 13); + shortening_result = LiveSafeDeviceName(live_dev, visual_devname, sizeof(visual_devname)); if (shortening_result != 0) { SCLogError(SC_ERR_INVALID_VALUE, "Could not shorten long devicename: %s", live_dev); exit(EXIT_FAILURE); From a6adb5dbbf9cf4ac634f9f85d551a4c777676813 Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 7 May 2015 14:09:04 +0200 Subject: [PATCH 1303/2553] Changed naming of flowmanager/recycler. - Changed FlowManagerThread to FM- - Changed FlowRecyclerThread to FR- - Changed use of strcasecmp to strncasecmp. This was used in the killing and disabling of FM/FR Threads. --- src/flow-manager.c | 17 +++++++++++------ src/tm-threads.c | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 9b9920eb4d1b..864668580f80 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -122,7 +122,7 @@ void FlowDisableFlowManagerThread(void) tv = tv_root[TVT_MGMT]; while (tv != NULL) { - if (strcasecmp(tv->name, "FlowManagerThread") == 0) { + if (strncasecmp(tv->name, "FM", 2) == 0) { TmThreadsSetFlag(tv, THV_KILL); cnt++; @@ -734,10 +734,10 @@ void FlowManagerThreadSpawn() for (u = 0; u < flowmgr_number; u++) { ThreadVars *tv_flowmgr = NULL; - char name[32]; - snprintf(name, sizeof(name), "FlowManagerThread%02u", u+1); + char name[32] = ""; + snprintf(name, sizeof(name), "FM%02u", u+1); - tv_flowmgr = TmThreadCreateMgmtThreadByName("FlowManagerThread", + tv_flowmgr = TmThreadCreateMgmtThreadByName(SCStrdup(name), "FlowManager", 0); BUG_ON(tv_flowmgr == NULL); @@ -897,10 +897,15 @@ void FlowRecyclerThreadSpawn() for (u = 0; u < flowrec_number; u++) { ThreadVars *tv_flowmgr = NULL; +<<<<<<< HEAD char name[32]; snprintf(name, sizeof(name), "FlowRecyclerThread%02u", u+1); +======= + char name[32] = ""; + snprintf(name, sizeof(name), "FR%02u", u+1); +>>>>>>> Changed naming of flowmanager/recycler. - tv_flowmgr = TmThreadCreateMgmtThreadByName("FlowRecyclerThread", + tv_flowmgr = TmThreadCreateMgmtThreadByName(SCStrdup(name), "FlowRecycler", 0); BUG_ON(tv_flowmgr == NULL); @@ -952,7 +957,7 @@ void FlowDisableFlowRecyclerThread(void) tv = tv_root[TVT_MGMT]; while (tv != NULL) { - if (strcasecmp(tv->name, "FlowRecyclerThread") == 0) { + if (strncasecmp(tv->name, "FR", 2) == 0) { TmThreadsSetFlag(tv, THV_KILL); cnt++; diff --git a/src/tm-threads.c b/src/tm-threads.c index a1cf5528fb0e..ad460232a781 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1793,6 +1793,7 @@ void TmThreadFree(ThreadVars *tv) } TmThreadsUnregisterThread(tv->id); + SCFree(tv->name); SCFree(tv); } From 19bc6c1f9f8ab7d8b969d724d081ff754f662ead Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Fri, 18 Sep 2015 23:15:54 -0400 Subject: [PATCH 1304/2553] Update thread naming convention for all IDS modes. - Change 'Detect' to 'W' - Enforce 2 digit numbering in thread names with leading zero - Add 01 after W for single mode: W01 --- src/util-runmodes.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 30b410e2cd23..637c2da318b2 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -147,7 +147,12 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, /* create the threads */ for (thread = 0; thread < threads_count; thread++) { - snprintf(tname, sizeof(tname), "%s%d", thread_name, thread+1); + snprintf(tname, sizeof(tname), "%s%02d", thread_name, thread+1); + char *thread_name = SCStrdup(tname); + if (unlikely(thread_name == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); + exit(EXIT_FAILURE); + } ThreadVars *tv_receive = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", @@ -212,8 +217,8 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, exit(EXIT_FAILURE); } - snprintf(tname, sizeof(tname), "%s%s%d", thread_name, - live_dev, thread+1); + snprintf(tname, sizeof(tname), "%s%02d-%s", thread_name, + thread+1, visual_devname); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { @@ -253,7 +258,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%d", thread+1); + snprintf(tname, sizeof(tname), "W%02d", thread+1); snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); @@ -335,7 +340,7 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod TmModule *tm_module = NULL; if (single_mode) { - snprintf(tname, sizeof(tname), "%s", thread_name); + snprintf(tname, sizeof(tname), "%s01", thread_name); } else { shortening_result = LiveSafeDeviceName(live_dev, visual_devname, sizeof(visual_devname)); if (shortening_result != 0) { @@ -343,8 +348,8 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod exit(EXIT_FAILURE); } - snprintf(tname, sizeof(tname), "%s%s%d", - thread_name, live_dev, thread+1); + snprintf(tname, sizeof(tname), "%s%02d-%s", thread_name, + thread+1, visual_devname); } tv = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", From 1bfebae8c414df1499211ae7a0aca7a69e05d4f1 Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Sun, 20 Sep 2015 21:58:46 -0400 Subject: [PATCH 1305/2553] Update IPS thread names to new name standard. --- src/util-runmodes.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 637c2da318b2..9ac5c7df4b4b 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -521,7 +521,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, exit(EXIT_FAILURE); } memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Recv-Q%s", cur_queue); + snprintf(tname, sizeof(tname), "RX-Q%s", cur_queue); ThreadVars *tv_receive = TmThreadCreatePacketHandler(tname, @@ -554,7 +554,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%d", thread+1); + snprintf(tname, sizeof(tname), "W%02d", thread+1); snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); @@ -599,7 +599,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, /* create the threads */ for (int i = 0; i < nqueue; i++) { memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Verdict%d", i); + snprintf(tname, sizeof(tname), "TX%02d", i); ThreadVars *tv_verdict = TmThreadCreatePacketHandler(tname, @@ -658,7 +658,7 @@ int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, exit(EXIT_FAILURE); } memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Worker-Q%s", cur_queue); + snprintf(tname, sizeof(tname), "W-Q%s", cur_queue); tv = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", From 41c768ce2837355e6556a13d076dd5bdd81d6c82 Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Wed, 4 Nov 2015 22:47:04 -0500 Subject: [PATCH 1306/2553] Update threads to use global thread names. Update FlowManager/Recycler to use global name. Also add # into thread number. Update af-packet to use global threadnames. Update pcap to use global threadnames. Update pfring to use global threadnames. Update erf-dag to use global threadnames. Update nflog to use global threadnames. Update netmap to use global threadnames. Update napatech to use global threadnames. --- src/flow-manager.c | 29 ++++++++++++++++------------- src/runmode-af-packet.c | 6 +++--- src/runmode-erf-dag.c | 6 +++--- src/runmode-napatech.c | 4 ++-- src/runmode-netmap.c | 6 +++--- src/runmode-nflog.c | 6 +++--- src/runmode-pcap.c | 6 +++--- src/runmode-pfring.c | 6 +++--- 8 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 864668580f80..1ae68b954ac4 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -121,8 +121,11 @@ void FlowDisableFlowManagerThread(void) /* flow manager thread(s) is/are a part of mgmt threads */ tv = tv_root[TVT_MGMT]; - while (tv != NULL) { - if (strncasecmp(tv->name, "FM", 2) == 0) { + while (tv != NULL) + { + if (strncasecmp(tv->name, thread_name_flow_mgr, + strlen(thread_name_flow_mgr)) == 0) + { TmThreadsSetFlag(tv, THV_KILL); cnt++; @@ -731,11 +734,12 @@ void FlowManagerThreadSpawn() StatsRegisterGlobalCounter("flow.memuse", FlowGetMemuse); uint32_t u; - for (u = 0; u < flowmgr_number; u++) { + for (u = 0; u < flowmgr_number; u++) + { ThreadVars *tv_flowmgr = NULL; char name[32] = ""; - snprintf(name, sizeof(name), "FM%02u", u+1); + snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_mgr, u+1); tv_flowmgr = TmThreadCreateMgmtThreadByName(SCStrdup(name), "FlowManager", 0); @@ -894,16 +898,12 @@ void FlowRecyclerThreadSpawn() uint32_t u; - for (u = 0; u < flowrec_number; u++) { + for (u = 0; u < flowrec_number; u++) + { ThreadVars *tv_flowmgr = NULL; -<<<<<<< HEAD - char name[32]; - snprintf(name, sizeof(name), "FlowRecyclerThread%02u", u+1); -======= char name[32] = ""; - snprintf(name, sizeof(name), "FR%02u", u+1); ->>>>>>> Changed naming of flowmanager/recycler. + snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_rec, u+1); tv_flowmgr = TmThreadCreateMgmtThreadByName(SCStrdup(name), "FlowRecycler", 0); @@ -956,8 +956,11 @@ void FlowDisableFlowRecyclerThread(void) /* flow recycler thread(s) is/are a part of mgmt threads */ tv = tv_root[TVT_MGMT]; - while (tv != NULL) { - if (strncasecmp(tv->name, "FR", 2) == 0) { + while (tv != NULL) + { + if (strncasecmp(tv->name, thread_name_flow_rec, + strlen(thread_name_flow_rec)) == 0) + { TmThreadsSetFlag(tv, THV_KILL); cnt++; diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index e561559a93ba..ee44042a2c85 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -514,7 +514,7 @@ int RunModeIdsAFPAutoFp(void) ret = RunModeSetLiveCaptureAutoFp(ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", - "DecodeAFP", "RxAFP", + "DecodeAFP", thread_name_autofp, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -556,7 +556,7 @@ int RunModeIdsAFPSingle(void) ret = RunModeSetLiveCaptureSingle(ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", - "DecodeAFP", "AFPacket", + "DecodeAFP", thread_name_single, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -601,7 +601,7 @@ int RunModeIdsAFPWorkers(void) ret = RunModeSetLiveCaptureWorkers(ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", - "DecodeAFP", "AFPacket", + "DecodeAFP", thread_name_workers, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); diff --git a/src/runmode-erf-dag.c b/src/runmode-erf-dag.c index 5653b9ecfbe0..a27544f22fab 100644 --- a/src/runmode-erf-dag.c +++ b/src/runmode-erf-dag.c @@ -85,7 +85,7 @@ int RunModeIdsErfDagSingle(void) DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", - "RxDAG", + thread_name_single, NULL); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "DAG single runmode failed to start"); @@ -111,7 +111,7 @@ int RunModeIdsErfDagAutoFp(void) DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", - "RxDAG", + thread_name_autofp, NULL); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "DAG autofp runmode failed to start"); @@ -137,7 +137,7 @@ int RunModeIdsErfDagWorkers(void) DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", - "RxDAG", + thread_name_workers, NULL); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "DAG workers runmode failed to start"); diff --git a/src/runmode-napatech.c b/src/runmode-napatech.c index 7c161ad864ae..6d883f740201 100644 --- a/src/runmode-napatech.c +++ b/src/runmode-napatech.c @@ -204,12 +204,12 @@ static int NapatechInit(int runmode) case NT_RUNMODE_AUTOFP: ret = RunModeSetLiveCaptureAutoFp(NapatechConfigParser, NapatechGetThreadsCount, "NapatechStream", "NapatechDecode", - "RxNT", NULL); + thread_name_autofp, NULL); break; case NT_RUNMODE_WORKERS: ret = RunModeSetLiveCaptureWorkers(NapatechConfigParser, NapatechGetThreadsCount, "NapatechStream", "NapatechDecode", - "RxNT", NULL); + thread_name_workers, NULL); break; default: ret = -1; diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 3289275ed37e..75eb0c6fe25d 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -372,7 +372,7 @@ int RunModeIdsNetmapAutoFp(void) ParseNetmapConfig, NetmapConfigGeThreadsCount, "ReceiveNetmap", - "DecodeNetmap", "RxNetmap", + "DecodeNetmap", thread_name_autofp, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -405,7 +405,7 @@ int RunModeIdsNetmapSingle(void) ParseNetmapConfig, NetmapConfigGeThreadsCount, "ReceiveNetmap", - "DecodeNetmap", "NetmapPkt", + "DecodeNetmap", thread_name_single, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -441,7 +441,7 @@ int RunModeIdsNetmapWorkers(void) ParseNetmapConfig, NetmapConfigGeThreadsCount, "ReceiveNetmap", - "DecodeNetmap", "NetmapPkt", + "DecodeNetmap", thread_name_workers, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); diff --git a/src/runmode-nflog.c b/src/runmode-nflog.c index 9c08f9aef060..f312ad642038 100644 --- a/src/runmode-nflog.c +++ b/src/runmode-nflog.c @@ -184,7 +184,7 @@ int RunModeIdsNflogAutoFp(void) NflogConfigGeThreadsCount, "ReceiveNFLOG", "DecodeNFLOG", - "RecvNFLOG", + thread_name_autofp, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -212,7 +212,7 @@ int RunModeIdsNflogSingle(void) NflogConfigGeThreadsCount, "ReceiveNFLOG", "DecodeNFLOG", - "RecvNFLOG", + thread_name_single, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -240,7 +240,7 @@ int RunModeIdsNflogWorkers(void) NflogConfigGeThreadsCount, "ReceiveNFLOG", "DecodeNFLOG", - "RecvNFLOG", + thread_name_workers, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); diff --git a/src/runmode-pcap.c b/src/runmode-pcap.c index 6561c1c8c4c8..52eff0f9bf91 100644 --- a/src/runmode-pcap.c +++ b/src/runmode-pcap.c @@ -242,7 +242,7 @@ int RunModeIdsPcapSingle(void) ret = RunModeSetLiveCaptureSingle(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", - "DecodePcap", "PcapLive", + "DecodePcap", thread_name_single, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); @@ -283,7 +283,7 @@ int RunModeIdsPcapAutoFp(void) ret = RunModeSetLiveCaptureAutoFp(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", - "DecodePcap", "RxPcap", + "DecodePcap", thread_name_autofp, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); @@ -315,7 +315,7 @@ int RunModeIdsPcapWorkers(void) ret = RunModeSetLiveCaptureWorkers(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", - "DecodePcap", "RxPcap", + "DecodePcap", thread_name_workers, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); diff --git a/src/runmode-pfring.c b/src/runmode-pfring.c index f08bdad80296..ca37649c7c0c 100644 --- a/src/runmode-pfring.c +++ b/src/runmode-pfring.c @@ -437,7 +437,7 @@ int RunModeIdsPfringAutoFp(void) ret = RunModeSetLiveCaptureAutoFp(tparser, PfringConfigGeThreadsCount, "ReceivePfring", - "DecodePfring", "RxPFR", + "DecodePfring", thread_name_autofp, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); @@ -474,7 +474,7 @@ int RunModeIdsPfringSingle(void) ret = RunModeSetLiveCaptureSingle(tparser, PfringConfigGeThreadsCount, "ReceivePfring", - "DecodePfring", "RxPFR", + "DecodePfring", thread_name_single, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); @@ -511,7 +511,7 @@ int RunModeIdsPfringWorkers(void) ret = RunModeSetLiveCaptureWorkers(tparser, PfringConfigGeThreadsCount, "ReceivePfring", - "DecodePfring", "RxPFR", + "DecodePfring", thread_name_workers, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); From f8a40dd9068298214a065237bdf76449a06858c7 Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Wed, 4 Nov 2015 23:43:31 -0500 Subject: [PATCH 1307/2553] Update pcap-file runmode to adhere to new thread standard. --- src/runmode-pcap-file.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index eede9f4d11dc..fdd0fe077c5b 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -62,6 +62,8 @@ void RunModeFilePcapRegister(void) int RunModeFilePcapSingle(void) { char *file = NULL; + char tname[TM_THREAD_NAME_MAX]; + if (ConfGet("pcap-file.file", &file) == 0) { SCLogError(SC_ERR_RUNMODE, "Failed retrieving pcap-file from Conf"); exit(EXIT_FAILURE); @@ -72,8 +74,17 @@ int RunModeFilePcapSingle(void) PcapFileGlobalInit(); + snprintf(tname, sizeof(tname), "%s#01", thread_name_single); + + char *thread_name = SCStrdup(tname); + if (unlikely(thread_name == NULL)) + { + SCLogError(SC_ERR_RUNMODE, "failed to strdup thread name"); + exit(EXIT_FAILURE); + } + /* create the threads */ - ThreadVars *tv = TmThreadCreatePacketHandler("PcapFile", + ThreadVars *tv = TmThreadCreatePacketHandler(thread_name, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); @@ -195,9 +206,17 @@ int RunModeFilePcapAutoFp(void) exit(EXIT_FAILURE); } + snprintf(tname, sizeof(tname), "%s#01", thread_name_autofp); + + char *thread_name = SCStrdup(tname); + if (unlikely(thread_name == NULL)) { + SCLogError(SC_ERR_RUNMODE, "failed to strdup thread name"); + exit(EXIT_FAILURE); + } + /* create the threads */ ThreadVars *tv_receivepcap = - TmThreadCreatePacketHandler("ReceivePcapFile", + TmThreadCreatePacketHandler(thread_name, "packetpool", "packetpool", queues, "flow", "pktacqloop"); @@ -229,11 +248,18 @@ int RunModeFilePcapAutoFp(void) } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%d", thread+1); + snprintf(tname, sizeof(tname), "%s#%02u", thread_name_workers, thread+1); snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); + thread_name = SCStrdup(tname); + if (unlikely(thread_name == NULL)) { + SCLogError(SC_ERR_RUNMODE, "failed to strdup thread name"); + exit(EXIT_FAILURE); + } + SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(tname, qname, "flow", From 8c8759c189cd3f55d6630aac54112681cf833780 Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Thu, 5 Nov 2015 00:30:31 -0500 Subject: [PATCH 1308/2553] Add global threadnames. Update thread naming convention to follow: W#01-eth0. Add interface name where applicable, add #. --- src/runmodes.c | 8 ++++++++ src/runmodes.h | 8 ++++++++ src/util-runmodes.c | 34 +++++++++++++++++----------------- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/runmodes.c b/src/runmodes.c index ee93b0c05edf..99a28fcddb47 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -58,6 +58,14 @@ int debuglog_enabled = 0; +/* Runmode Global Thread Names */ +char *thread_name_autofp = "RX"; +char *thread_name_single = "W"; +char *thread_name_workers = "W"; +char *thread_name_verdict = "TX"; +char *thread_name_flow_mgr = "FM"; +char *thread_name_flow_rec = "FR"; + /** * \brief Holds description for a runmode. */ diff --git a/src/runmodes.h b/src/runmodes.h index bd8d03263eb9..726d49992d33 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -60,6 +60,14 @@ enum { RUNMODE_MAX, }; +/* Run Mode Global Thread Names */ +extern char *thread_name_autofp; +extern char *thread_name_single; +extern char *thread_name_workers; +extern char *thread_name_verdict; +extern char *thread_name_flow_mgr; +extern char *thread_name_flow_rec; + char *RunmodeGetActive(void); const char *RunModeGetMainMode(void); diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 9ac5c7df4b4b..5e6f736629e6 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -147,7 +147,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, /* create the threads */ for (thread = 0; thread < threads_count; thread++) { - snprintf(tname, sizeof(tname), "%s%02d", thread_name, thread+1); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name, thread+1); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); @@ -191,7 +191,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, for (lthread = 0; lthread < nlive; lthread++) { char *live_dev = LiveGetDeviceName(lthread); - char visual_devname[12] = ""; + char visual_devname[11] = ""; int shortening_result; void *aconf; int threads_count; @@ -217,7 +217,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, exit(EXIT_FAILURE); } - snprintf(tname, sizeof(tname), "%s%02d-%s", thread_name, + snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, thread+1, visual_devname); char *thread_name = SCStrdup(tname); @@ -258,7 +258,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "W%02d", thread+1); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_workers, thread+1); snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); @@ -334,21 +334,21 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod for (thread = 0; thread < threads_count; thread++) { char tname[TM_THREAD_NAME_MAX]; char *n_thread_name = NULL; - char visual_devname[12] = ""; + char visual_devname[11] = ""; int shortening_result; ThreadVars *tv = NULL; TmModule *tm_module = NULL; + shortening_result = LiveSafeDeviceName(live_dev, visual_devname, sizeof(visual_devname)); + if (shortening_result != 0) { + SCLogError(SC_ERR_INVALID_VALUE, "Could not shorten long devicename: %s", live_dev); + exit(EXIT_FAILURE); + } + if (single_mode) { - snprintf(tname, sizeof(tname), "%s01", thread_name); + snprintf(tname, sizeof(tname), "%s#01-%s", thread_name, visual_devname); } else { - shortening_result = LiveSafeDeviceName(live_dev, visual_devname, sizeof(visual_devname)); - if (shortening_result != 0) { - SCLogError(SC_ERR_INVALID_VALUE, "Could not shorten long devicename: %s", live_dev); - exit(EXIT_FAILURE); - } - - snprintf(tname, sizeof(tname), "%s%02d-%s", thread_name, + snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, thread+1, visual_devname); } tv = TmThreadCreatePacketHandler(tname, @@ -521,7 +521,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, exit(EXIT_FAILURE); } memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "RX-Q%s", cur_queue); + snprintf(tname, sizeof(tname), "%s-Q%s", thread_name_autofp, cur_queue); ThreadVars *tv_receive = TmThreadCreatePacketHandler(tname, @@ -554,7 +554,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "W%02d", thread+1); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_workers, thread+1); snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); @@ -599,7 +599,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, /* create the threads */ for (int i = 0; i < nqueue; i++) { memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "TX%02d", i); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_verdict, i); ThreadVars *tv_verdict = TmThreadCreatePacketHandler(tname, @@ -658,7 +658,7 @@ int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, exit(EXIT_FAILURE); } memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "W-Q%s", cur_queue); + snprintf(tname, sizeof(tname), "%s-Q%s", thread_name_workers, cur_queue); tv = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", From 885747218bfb23b8e880f2444f23228cf3bff527 Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Wed, 4 Nov 2015 22:55:13 -0500 Subject: [PATCH 1309/2553] Update shortening algorithm to account for addition of #. --- src/util-device.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/util-device.c b/src/util-device.c index b29583f57495..f58bbc35a88e 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -19,7 +19,7 @@ #include "conf.h" #include "util-device.h" -#define MAX_DEVNAME 11 +#define MAX_DEVNAME 10 /** * \file @@ -121,15 +121,15 @@ int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen) /* If we have to shorten the interface name */ if (devnamelen > MAX_DEVNAME) { - /* IF the dest length is over 11 chars long it will not do any + /* IF the dest length is over 10 chars long it will not do any * good for the shortening. The shortening is done due to the - * max length of pthread names (15 chars) and we use 2 chars - * for the threadname indicator eg. "W-" and one-two chars for + * max length of pthread names (15 chars) and we use 3 chars + * for the threadname indicator eg. "W#-" and one-two chars for * the thread number. And if the destination buffer is under * 6 chars there is point in shortening it since we must at * lest enter two periodes (.) into the string.. */ - if ((destlen-1) > 11 && (destlen-1) < 6) { + if ((destlen-1) > 10 && (destlen-1) < 6) { return 1; } From 10d3d90f06117e3740d9915e7df9a9ba80e608c5 Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Sat, 5 Dec 2015 19:56:55 -0500 Subject: [PATCH 1310/2553] Change thread name from pointer to buffer. Remove pointer free. --- src/threadvars.h | 2 +- src/tm-threads.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/threadvars.h b/src/threadvars.h index 578770c1aaac..c72dcc734ddb 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -64,7 +64,7 @@ struct TmSlot_; /** \brief Per thread variable structure */ typedef struct ThreadVars_ { pthread_t t; - char *name; + char name[16]; char *thread_group_name; SC_ATOMIC_DECLARE(unsigned int, flags); diff --git a/src/tm-threads.c b/src/tm-threads.c index ad460232a781..b21357871e3f 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1162,9 +1162,8 @@ ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name, SC_ATOMIC_INIT(tv->flags); SCMutexInit(&tv->perf_public_ctx.m, NULL); - tv->name = SCStrdup(name); - if (unlikely(tv->name == NULL)) - goto error; + strlcpy(tv->name, name, sizeof(tv->name)); + /* default state for every newly created thread */ TmThreadsSetFlag(tv, THV_PAUSE); TmThreadsSetFlag(tv, THV_USE); @@ -1793,7 +1792,6 @@ void TmThreadFree(ThreadVars *tv) } TmThreadsUnregisterThread(tv->id); - SCFree(tv->name); SCFree(tv); } From 68cfa009a0105ff2ae3f116d587f41ed92d5ef3e Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Sat, 5 Dec 2015 19:52:20 -0500 Subject: [PATCH 1311/2553] Update thread creation and threads to use global thread names. Thread name is now stored as a static string buffer, string duplication and alloc/de-alloc is no longer required. --- src/counters.c | 5 +++-- src/detect-engine-loader.c | 7 ++++--- src/flow-manager.c | 8 ++++---- src/runmode-erf-file.c | 8 +++++--- src/runmode-pcap-file.c | 25 +++---------------------- src/runmode-tile.c | 2 +- src/runmodes.c | 4 ++++ src/runmodes.h | 4 ++++ src/unix-manager.c | 2 +- src/util-runmodes.c | 11 ----------- 10 files changed, 29 insertions(+), 47 deletions(-) diff --git a/src/counters.c b/src/counters.c index 5e6d558c46fe..e40e225778d5 100644 --- a/src/counters.c +++ b/src/counters.c @@ -36,6 +36,7 @@ #include "util-privs.h" #include "util-signal.h" #include "unix-manager.h" +#include "runmodes.h" #include "output.h" #include "output-stats.h" @@ -843,7 +844,7 @@ void StatsSpawnThreads(void) ThreadVars *tv_mgmt = NULL; /* spawn the stats wakeup thread */ - tv_wakeup = TmThreadCreateMgmtThread("StatsWakeupThread", + tv_wakeup = TmThreadCreateMgmtThread(thread_name_counter_wakeup, StatsWakeupThread, 1); if (tv_wakeup == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadCreateMgmtThread " @@ -858,7 +859,7 @@ void StatsSpawnThreads(void) } /* spawn the stats mgmt thread */ - tv_mgmt = TmThreadCreateMgmtThread("StatsMgmtThread", + tv_mgmt = TmThreadCreateMgmtThread(thread_name_counter_stats, StatsMgmtThread, 1); if (tv_mgmt == NULL) { SCLogError(SC_ERR_THREAD_CREATE, diff --git a/src/detect-engine-loader.c b/src/detect-engine-loader.c index c3a79b5cbe14..c85265ea4502 100644 --- a/src/detect-engine-loader.c +++ b/src/detect-engine-loader.c @@ -26,6 +26,7 @@ #include "conf.h" #include "debug.h" #include "detect.h" +#include "runmodes.h" #include "threads.h" #include "threadvars.h" #include "tm-threads.h" @@ -267,10 +268,10 @@ void DetectLoaderThreadSpawn() for (i = 0; i < num_loaders; i++) { ThreadVars *tv_loader = NULL; - char name[32]; - snprintf(name, sizeof(name), "DetectLoader%02d", i+1); + char name[TM_THREAD_NAME_MAX] = ""; + snprintf(name, sizeof(name), "%s#%02d", thread_name_detect_loader, i+1); - tv_loader = TmThreadCreateCmdThreadByName("DetectLoader", + tv_loader = TmThreadCreateCmdThreadByName(name, "DetectLoader", 1); BUG_ON(tv_loader == NULL); diff --git a/src/flow-manager.c b/src/flow-manager.c index 1ae68b954ac4..b204966e46ae 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -738,10 +738,10 @@ void FlowManagerThreadSpawn() { ThreadVars *tv_flowmgr = NULL; - char name[32] = ""; + char name[TM_THREAD_NAME_MAX] = ""; snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_mgr, u+1); - tv_flowmgr = TmThreadCreateMgmtThreadByName(SCStrdup(name), + tv_flowmgr = TmThreadCreateMgmtThreadByName(name, "FlowManager", 0); BUG_ON(tv_flowmgr == NULL); @@ -902,10 +902,10 @@ void FlowRecyclerThreadSpawn() { ThreadVars *tv_flowmgr = NULL; - char name[32] = ""; + char name[TM_THREAD_NAME_MAX] = ""; snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_rec, u+1); - tv_flowmgr = TmThreadCreateMgmtThreadByName(SCStrdup(name), + tv_flowmgr = TmThreadCreateMgmtThreadByName(name, "FlowRecycler", 0); BUG_ON(tv_flowmgr == NULL); diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index 0be5da148d4f..abb85244a2d9 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -71,7 +71,7 @@ int RunModeErfFileSingle(void) /* Basically the same setup as PCAP files. */ - ThreadVars *tv = TmThreadCreatePacketHandler("ErfFile", + ThreadVars *tv = TmThreadCreatePacketHandler(thread_name_single, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); @@ -166,7 +166,7 @@ int RunModeErfFileAutoFp(void) /* create the threads */ ThreadVars *tv = - TmThreadCreatePacketHandler("ReceiveErfFile", + TmThreadCreatePacketHandler(thread_name_autofp, "packetpool", "packetpool", queues, "flow", "pktacqloop"); @@ -202,11 +202,13 @@ int RunModeErfFileAutoFp(void) } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%d", thread+1); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_workers, thread+1); snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); + SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(tname, qname, "flow", diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index fdd0fe077c5b..29a65eeebf54 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -76,15 +76,8 @@ int RunModeFilePcapSingle(void) snprintf(tname, sizeof(tname), "%s#01", thread_name_single); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) - { - SCLogError(SC_ERR_RUNMODE, "failed to strdup thread name"); - exit(EXIT_FAILURE); - } - /* create the threads */ - ThreadVars *tv = TmThreadCreatePacketHandler(thread_name, + ThreadVars *tv = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); @@ -208,15 +201,9 @@ int RunModeFilePcapAutoFp(void) snprintf(tname, sizeof(tname), "%s#01", thread_name_autofp); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "failed to strdup thread name"); - exit(EXIT_FAILURE); - } - /* create the threads */ ThreadVars *tv_receivepcap = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); @@ -252,13 +239,7 @@ int RunModeFilePcapAutoFp(void) snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); - - thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "failed to strdup thread name"); - exit(EXIT_FAILURE); - } - SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); + SCLogDebug("Assigning %s affinity to cpu %u", tname, cpu); ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(tname, diff --git a/src/runmode-tile.c b/src/runmode-tile.c index 688588c8be81..913ee562f69b 100644 --- a/src/runmode-tile.c +++ b/src/runmode-tile.c @@ -213,7 +213,7 @@ int RunModeTileMpipeWorkers(void) exit(EXIT_FAILURE); } - snprintf(tname, sizeof(tname), "Worker%d", pipe+1); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_workers, pipe+1); /* create the threads */ ThreadVars *tv_worker = diff --git a/src/runmodes.c b/src/runmodes.c index 99a28fcddb47..65cccdea2dea 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -65,6 +65,10 @@ char *thread_name_workers = "W"; char *thread_name_verdict = "TX"; char *thread_name_flow_mgr = "FM"; char *thread_name_flow_rec = "FR"; +char *thread_name_unix_socket = "US"; +char *thread_name_detect_loader = "DL"; +char *thread_name_counter_stats = "CS"; +char *thread_name_counter_wakeup = "CW"; /** * \brief Holds description for a runmode. diff --git a/src/runmodes.h b/src/runmodes.h index 726d49992d33..165bfe45c881 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -67,6 +67,10 @@ extern char *thread_name_workers; extern char *thread_name_verdict; extern char *thread_name_flow_mgr; extern char *thread_name_flow_rec; +extern char *thread_name_unix_socket; +extern char *thread_name_detect_loader; +extern char *thread_name_counter_stats; +extern char *thread_name_counter_wakeup; char *RunmodeGetActive(void); const char *RunModeGetMainMode(void); diff --git a/src/unix-manager.c b/src/unix-manager.c index c2b87ad3d9ea..919651cce887 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -994,7 +994,7 @@ void UnixManagerThreadSpawn(int mode) SCCtrlCondInit(&unix_manager_ctrl_cond, NULL); SCCtrlMutexInit(&unix_manager_ctrl_mutex, NULL); - tv_unixmgr = TmThreadCreateCmdThreadByName("UnixManagerThread", + tv_unixmgr = TmThreadCreateCmdThreadByName(thread_name_unix_socket, "UnixManager", 0); if (tv_unixmgr == NULL) { diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 5e6f736629e6..9920653a3f6c 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -148,11 +148,6 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, /* create the threads */ for (thread = 0; thread < threads_count; thread++) { snprintf(tname, sizeof(tname), "%s#%02d", thread_name, thread+1); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } ThreadVars *tv_receive = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", @@ -220,11 +215,6 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, thread+1, visual_devname); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } ThreadVars *tv_receive = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", @@ -333,7 +323,6 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod /* create the threads */ for (thread = 0; thread < threads_count; thread++) { char tname[TM_THREAD_NAME_MAX]; - char *n_thread_name = NULL; char visual_devname[11] = ""; int shortening_result; ThreadVars *tv = NULL; From f211fa48f46b23e34dc396667cc9c53152a38f8f Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Sun, 6 Dec 2015 11:36:26 -0500 Subject: [PATCH 1312/2553] Update unit test to account for 'name' type change. --- src/detect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect.c b/src/detect.c index 385a5414601e..19e7571ee5f3 100644 --- a/src/detect.c +++ b/src/detect.c @@ -9204,7 +9204,7 @@ static int SigTestDetectAlertCounter(void) } SigGroupBuild(de_ctx); - tv.name = "detect_test"; + strlcpy(tv.name, "detect_test", sizeof(tv.name)); DetectEngineThreadCtxInit(&tv, de_ctx, (void *)&det_ctx); /* init counters */ From 71018cd2cecabe69c381e8b9a78ecbe9cbc86a4a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 24 Nov 2015 18:57:47 +0100 Subject: [PATCH 1313/2553] runmodes: constify names --- src/runmode-erf-file.c | 2 +- src/runmodes.c | 20 ++++++++++---------- src/runmodes.h | 20 ++++++++++---------- src/tm-threads.c | 10 +++++----- src/tm-threads.h | 10 +++++----- src/util-runmodes.c | 29 +++++++++++++++-------------- src/util-runmodes.h | 28 ++++++++++++++-------------- 7 files changed, 60 insertions(+), 59 deletions(-) diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index abb85244a2d9..f449a953a295 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -207,7 +207,7 @@ int RunModeErfFileAutoFp(void) SCLogDebug("tname %s, qname %s", tname, qname); - SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); + SCLogDebug("Assigning %s affinity to cpu %u", tname, cpu); ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(tname, diff --git a/src/runmodes.c b/src/runmodes.c index 65cccdea2dea..b4bf31b6c7a7 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -59,16 +59,16 @@ int debuglog_enabled = 0; /* Runmode Global Thread Names */ -char *thread_name_autofp = "RX"; -char *thread_name_single = "W"; -char *thread_name_workers = "W"; -char *thread_name_verdict = "TX"; -char *thread_name_flow_mgr = "FM"; -char *thread_name_flow_rec = "FR"; -char *thread_name_unix_socket = "US"; -char *thread_name_detect_loader = "DL"; -char *thread_name_counter_stats = "CS"; -char *thread_name_counter_wakeup = "CW"; +const char *thread_name_autofp = "RX"; +const char *thread_name_single = "W"; +const char *thread_name_workers = "W"; +const char *thread_name_verdict = "TX"; +const char *thread_name_flow_mgr = "FM"; +const char *thread_name_flow_rec = "FR"; +const char *thread_name_unix_socket = "US"; +const char *thread_name_detect_loader = "DL"; +const char *thread_name_counter_stats = "CS"; +const char *thread_name_counter_wakeup = "CW"; /** * \brief Holds description for a runmode. diff --git a/src/runmodes.h b/src/runmodes.h index 165bfe45c881..d935b9a3fef0 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -61,16 +61,16 @@ enum { }; /* Run Mode Global Thread Names */ -extern char *thread_name_autofp; -extern char *thread_name_single; -extern char *thread_name_workers; -extern char *thread_name_verdict; -extern char *thread_name_flow_mgr; -extern char *thread_name_flow_rec; -extern char *thread_name_unix_socket; -extern char *thread_name_detect_loader; -extern char *thread_name_counter_stats; -extern char *thread_name_counter_wakeup; +extern const char *thread_name_autofp; +extern const char *thread_name_single; +extern const char *thread_name_workers; +extern const char *thread_name_verdict; +extern const char *thread_name_flow_mgr; +extern const char *thread_name_flow_rec; +extern const char *thread_name_unix_socket; +extern const char *thread_name_detect_loader; +extern const char *thread_name_counter_stats; +extern const char *thread_name_counter_wakeup; char *RunmodeGetActive(void); const char *RunModeGetMainMode(void); diff --git a/src/tm-threads.c b/src/tm-threads.c index b21357871e3f..4fbc54a2e2bb 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1143,7 +1143,7 @@ TmEcode TmThreadSetupOptions(ThreadVars *tv) * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name, +ThreadVars *TmThreadCreate(const char *name, char *inq_name, char *inqh_name, char *outq_name, char *outqh_name, char *slots, void * (*fn_p)(void *), int mucond) { @@ -1266,7 +1266,7 @@ ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name, * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreatePacketHandler(char *name, char *inq_name, +ThreadVars *TmThreadCreatePacketHandler(const char *name, char *inq_name, char *inqh_name, char *outq_name, char *outqh_name, char *slots) { @@ -1296,7 +1296,7 @@ ThreadVars *TmThreadCreatePacketHandler(char *name, char *inq_name, * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), +ThreadVars *TmThreadCreateMgmtThread(const char *name, void *(fn_p)(void *), int mucond) { ThreadVars *tv = NULL; @@ -1324,7 +1324,7 @@ ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, +ThreadVars *TmThreadCreateMgmtThreadByName(const char *name, char *module, int mucond) { ThreadVars *tv = NULL; @@ -1357,7 +1357,7 @@ ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreateCmdThreadByName(char *name, char *module, +ThreadVars *TmThreadCreateCmdThreadByName(const char *name, char *module, int mucond) { ThreadVars *tv = NULL; diff --git a/src/tm-threads.h b/src/tm-threads.h index b39bf02f432c..d92e1a946201 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -84,14 +84,14 @@ void TmSlotSetFuncAppend(ThreadVars *, TmModule *, void *); void TmSlotSetFuncAppendDelayed(ThreadVars *, TmModule *, void *, int delayed); TmSlot *TmSlotGetSlotForTM(int); -ThreadVars *TmThreadCreate(char *, char *, char *, char *, char *, char *, +ThreadVars *TmThreadCreate(const char *, char *, char *, char *, char *, char *, void *(fn_p)(void *), int); -ThreadVars *TmThreadCreatePacketHandler(char *, char *, char *, char *, char *, +ThreadVars *TmThreadCreatePacketHandler(const char *, char *, char *, char *, char *, char *); -ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), int); -ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, +ThreadVars *TmThreadCreateMgmtThread(const char *name, void *(fn_p)(void *), int); +ThreadVars *TmThreadCreateMgmtThreadByName(const char *name, char *module, int mucond); -ThreadVars *TmThreadCreateCmdThreadByName(char *name, char *module, +ThreadVars *TmThreadCreateCmdThreadByName(const char *name, char *module, int mucond); TmEcode TmThreadSpawn(ThreadVars *); void TmThreadSetFlags(ThreadVars *, uint8_t); diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 9920653a3f6c..03ec2ba29357 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -102,8 +102,9 @@ char *RunmodeAutoFpCreatePickupQueuesString(int n) */ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, + const char *thread_name, const char *live_dev) { char tname[TM_THREAD_NAME_MAX]; @@ -305,8 +306,8 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, /** */ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev, void *aconf, unsigned char single_mode) { @@ -401,8 +402,8 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev) { int nlive = LiveGetDeviceCount(); @@ -436,8 +437,8 @@ int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev) { int nlive = LiveGetDeviceCount(); @@ -471,9 +472,9 @@ int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, /** */ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name) + const char *recv_mod_name, + const char *verdict_mod_name, + const char *decode_mod_name) { SCEnter(); char tname[TM_THREAD_NAME_MAX]; @@ -628,9 +629,9 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, /** */ int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name) + const char *recv_mod_name, + const char *verdict_mod_name, + const char *decode_mod_name) { char tname[TM_THREAD_NAME_MAX]; ThreadVars *tv = NULL; diff --git a/src/util-runmodes.h b/src/util-runmodes.h index 607895a4ab38..02d1323749e1 100644 --- a/src/util-runmodes.h +++ b/src/util-runmodes.h @@ -32,37 +32,37 @@ typedef int (*ConfigIfaceThreadsCountFunc) (void *); int RunModeSetLiveCaptureAuto(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name); + const char *recv_mod_name, + const char *verdict_mod_name, + const char *decode_mod_name); int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name); + const char *recv_mod_name, + const char *verdict_mod_name, + const char *decode_mod_name); char *RunmodeAutoFpCreatePickupQueuesString(int n); From dbbca37a942f8122929cd2a4af1dd9ae425c9c56 Mon Sep 17 00:00:00 2001 From: Zachary Rasmor Date: Wed, 27 Apr 2016 00:51:54 -0400 Subject: [PATCH 1314/2553] Remove free operation on thread name field. Name field is now a pre-allocated array - free is no longer necessary. Fix issue leading to segfault during interface shortening in Single runmode. --- src/tm-threads.c | 3 --- src/util-runmodes.c | 6 ++++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index 4fbc54a2e2bb..b21770e4ea7c 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1777,9 +1777,6 @@ void TmThreadFree(ThreadVars *tv) TmThreadDeinitMC(tv); - if (tv->name) { - SCFree(tv->name); - } if (tv->thread_group_name) { SCFree(tv->thread_group_name); } diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 03ec2ba29357..13724e98fe01 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -442,6 +442,7 @@ int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, const char *live_dev) { int nlive = LiveGetDeviceCount(); + const char *live_dev_c = NULL; void *aconf; if (nlive > 1) { @@ -452,8 +453,9 @@ int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, if (live_dev != NULL) { aconf = ConfigParser(live_dev); + live_dev_c = live_dev; } else { - const char *live_dev_c = LiveGetDeviceName(0); + live_dev_c = LiveGetDeviceName(0); aconf = ConfigParser(live_dev_c); /* \todo Set threads number in config to 1 */ } @@ -463,7 +465,7 @@ int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, recv_mod_name, decode_mod_name, thread_name, - live_dev, + live_dev_c, aconf, 1); } From d9639fba60a0f81e9d8c3181e5577243a7bffd2b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 2 May 2016 11:59:47 +0200 Subject: [PATCH 1315/2553] cppcheck: fix harmless warnings [src/detect-engine-loader.c:272]: (error) Buffer is accessed out of bounds. [src/flow-manager.c:742]: (error) Buffer is accessed out of bounds. [src/flow-manager.c:906]: (error) Buffer is accessed out of bounds. --- src/detect-engine-loader.c | 2 +- src/flow-manager.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-loader.c b/src/detect-engine-loader.c index c85265ea4502..f88cc99850d7 100644 --- a/src/detect-engine-loader.c +++ b/src/detect-engine-loader.c @@ -268,7 +268,7 @@ void DetectLoaderThreadSpawn() for (i = 0; i < num_loaders; i++) { ThreadVars *tv_loader = NULL; - char name[TM_THREAD_NAME_MAX] = ""; + char name[TM_THREAD_NAME_MAX]; snprintf(name, sizeof(name), "%s#%02d", thread_name_detect_loader, i+1); tv_loader = TmThreadCreateCmdThreadByName(name, diff --git a/src/flow-manager.c b/src/flow-manager.c index b204966e46ae..aa13e7225f12 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -738,7 +738,7 @@ void FlowManagerThreadSpawn() { ThreadVars *tv_flowmgr = NULL; - char name[TM_THREAD_NAME_MAX] = ""; + char name[TM_THREAD_NAME_MAX]; snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_mgr, u+1); tv_flowmgr = TmThreadCreateMgmtThreadByName(name, @@ -902,7 +902,7 @@ void FlowRecyclerThreadSpawn() { ThreadVars *tv_flowmgr = NULL; - char name[TM_THREAD_NAME_MAX] = ""; + char name[TM_THREAD_NAME_MAX]; snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_rec, u+1); tv_flowmgr = TmThreadCreateMgmtThreadByName(name, From 98185573690895122f0c040ec16b5e498b82cffa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 2 May 2016 14:30:35 +0200 Subject: [PATCH 1316/2553] stats: fix stats.log ignoring null-values for threads --- src/log-stats.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/log-stats.c b/src/log-stats.c index e08c6888cded..a02e4a1225a3 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -138,6 +138,9 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) if (st->tstats[u].name == NULL) continue; + if (!(aft->statslog_ctx->flags & LOG_STATS_NULLS) && st->tstats[u].value == 0) + continue; + char line[256]; size_t len = snprintf(line, sizeof(line), "%-42s | %-25s | %-" PRIu64 "\n", st->tstats[u].name, st->tstats[u].tm_name, st->tstats[u].value); From 2b80da424baab58478ba90b4ce3d7ec23d55f871 Mon Sep 17 00:00:00 2001 From: maxtors Date: Mon, 25 Apr 2016 18:08:28 +0200 Subject: [PATCH 1317/2553] Update ASN1_MAX_FRAMES to reflect default in suricata.yaml.in --- src/util-decode-asn1.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-decode-asn1.h b/src/util-decode-asn1.h index d3ff9a3e8674..ed0fc7970932 100644 --- a/src/util-decode-asn1.h +++ b/src/util-decode-asn1.h @@ -34,7 +34,7 @@ #include #include -#define ASN1_MAX_FRAMES 128 +#define ASN1_MAX_FRAMES 256 /* For future enconding type implementations */ enum { From 16e4c92b69da3274e294dd80aed2dce3cdb955db Mon Sep 17 00:00:00 2001 From: maxtors Date: Tue, 26 Apr 2016 13:53:42 +0200 Subject: [PATCH 1318/2553] Changed "enabled" parsing to use ConfValIs(true|false) --- src/app-layer-parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index d7aeb81cc177..d885a761984a 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -280,9 +280,9 @@ int AppLayerParserConfParserEnabled(const char *ipproto, } } - if (strcasecmp(node->val, "yes") == 0) { + if (ConfValIsTrue(node->val)) { goto enabled; - } else if (strcasecmp(node->val, "no") == 0) { + } else if (ConfValIsFalse(node->val)) { goto disabled; } else if (strcasecmp(node->val, "detection-only") == 0) { goto disabled; From 387919e203a8f5405b37754666d59bb6d9437bea Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 28 Apr 2016 12:59:23 +0200 Subject: [PATCH 1319/2553] Added more DNS Resource Record Types. --- src/app-layer-dns-common.c | 147 ++++++++++++++++++++++++++++++++++--- src/app-layer-dns-common.h | 83 ++++++++++++++------- 2 files changed, 193 insertions(+), 37 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 664a6e0a93c9..83105e4cc0b6 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -1016,11 +1016,11 @@ void DNSCreateTypeString(uint16_t type, char *str, size_t str_size) case DNS_RECORD_TYPE_NS: snprintf(str, str_size, "NS"); break; - case DNS_RECORD_TYPE_AAAA: - snprintf(str, str_size, "AAAA"); + case DNS_RECORD_TYPE_MD: + snprintf(str, str_size, "MD"); break; - case DNS_RECORD_TYPE_TXT: - snprintf(str, str_size, "TXT"); + case DNS_RECORD_TYPE_MF: + snprintf(str, str_size, "MF"); break; case DNS_RECORD_TYPE_CNAME: snprintf(str, str_size, "CNAME"); @@ -1028,39 +1028,162 @@ void DNSCreateTypeString(uint16_t type, char *str, size_t str_size) case DNS_RECORD_TYPE_SOA: snprintf(str, str_size, "SOA"); break; - case DNS_RECORD_TYPE_MX: - snprintf(str, str_size, "MX"); + case DNS_RECORD_TYPE_MB: + snprintf(str, str_size, "MB"); + break; + case DNS_RECORD_TYPE_MG: + snprintf(str, str_size, "MG"); + break; + case DNS_RECORD_TYPE_MR: + snprintf(str, str_size, "MR"); + break; + case DNS_RECORD_TYPE_NULL: + snprintf(str, str_size, "NULL"); + break; + case DNS_RECORD_TYPE_WKS: + snprintf(str, str_size, "WKS"); break; case DNS_RECORD_TYPE_PTR: snprintf(str, str_size, "PTR"); break; - case DNS_RECORD_TYPE_ANY: - snprintf(str, str_size, "ANY"); + case DNS_RECORD_TYPE_HINFO: + snprintf(str, str_size, "HINFO"); break; - case DNS_RECORD_TYPE_TKEY: - snprintf(str, str_size, "TKEY"); + case DNS_RECORD_TYPE_MINFO: + snprintf(str, str_size, "MINFO"); break; - case DNS_RECORD_TYPE_TSIG: - snprintf(str, str_size, "TSIG"); + case DNS_RECORD_TYPE_MX: + snprintf(str, str_size, "MX"); + break; + case DNS_RECORD_TYPE_TXT: + snprintf(str, str_size, "TXT"); + break; + case DNS_RECORD_TYPE_RP: + snprintf(str, str_size, "RP"); + break; + case DNS_RECORD_TYPE_AFSDB: + snprintf(str, str_size, "AFSDB"); + break; + case DNS_RECORD_TYPE_X25: + snprintf(str, str_size, "X25"); + break; + case DNS_RECORD_TYPE_ISDN: + snprintf(str, str_size, "ISDN"); + break; + case DNS_RECORD_TYPE_RT: + snprintf(str, str_size, "RT"); + break; + case DNS_RECORD_TYPE_NSAP: + snprintf(str, str_size, "NSAP"); + break; + case DNS_RECORD_TYPE_NSAPPTR: + snprintf(str, str_size, "NSAPPTR"); + break; + case DNS_RECORD_TYPE_SIG: + snprintf(str, str_size, "SIG"); + break; + case DNS_RECORD_TYPE_KEY: + snprintf(str, str_size, "KEY"); + break; + case DNS_RECORD_TYPE_PX: + snprintf(str, str_size, "PX"); + break; + case DNS_RECORD_TYPE_GPOS: + snprintf(str, str_size, "GPOS"); + break; + case DNS_RECORD_TYPE_AAAA: + snprintf(str, str_size, "AAAA"); + break; + case DNS_RECORD_TYPE_LOC: + snprintf(str, str_size, "LOC"); + break; + case DNS_RECORD_TYPE_NXT: + snprintf(str, str_size, "NXT"); break; case DNS_RECORD_TYPE_SRV: snprintf(str, str_size, "SRV"); break; + case DNS_RECORD_TYPE_ATMA: + snprintf(str, str_size, "ATMA"); + break; case DNS_RECORD_TYPE_NAPTR: snprintf(str, str_size, "NAPTR"); break; + case DNS_RECORD_TYPE_KX: + snprintf(str, str_size, "KX"); + break; + case DNS_RECORD_TYPE_CERT: + snprintf(str, str_size, "CERT"); + break; + case DNS_RECORD_TYPE_A6: + snprintf(str, str_size, "A6"); + break; + case DNS_RECORD_TYPE_DNAME: + snprintf(str, str_size, "DNAME"); + break; + case DNS_RECORD_TYPE_OPT: + snprintf(str, str_size, "OPT"); + break; + case DNS_RECORD_TYPE_APL: + snprintf(str, str_size, "APL"); + break; case DNS_RECORD_TYPE_DS: snprintf(str, str_size, "DS"); break; + case DNS_RECORD_TYPE_SSHFP: + snprintf(str, str_size, "SSHFP"); + break; + case DNS_RECORD_TYPE_IPSECKEY: + snprintf(str, str_size, "IPSECKEY"); + break; case DNS_RECORD_TYPE_RRSIG: snprintf(str, str_size, "RRSIG"); break; case DNS_RECORD_TYPE_NSEC: snprintf(str, str_size, "NSEC"); break; + case DNS_RECORD_TYPE_DNSKEY: + snprintf(str, str_size, "DNSKEY"); + break; + case DNS_RECORD_TYPE_DHCID: + snprintf(str, str_size, "DHCID"); + break; case DNS_RECORD_TYPE_NSEC3: snprintf(str, str_size, "NSEC3"); break; + case DNS_RECORD_TYPE_NSEC3PARAM: + snprintf(str, str_size, "NSEC3PARAM"); + break; + case DNS_RECORD_TYPE_TLSA: + snprintf(str, str_size, "TLSA"); + break; + case DNS_RECORD_TYPE_HIP: + snprintf(str, str_size, "HIP"); + break; + case DNS_RECORD_TYPE_CDS: + snprintf(str, str_size, "CDS"); + break; + case DNS_RECORD_TYPE_CDNSKEY: + snprintf(str, str_size, "CDNSKEY"); + break; + case DNS_RECORD_TYPE_SPF: + snprintf(str, str_size, "SPF"); + break; + case DNS_RECORD_TYPE_TKEY: + snprintf(str, str_size, "TKEY"); + break; + case DNS_RECORD_TYPE_TSIG: + snprintf(str, str_size, "TSIG"); + break; + case DNS_RECORD_TYPE_MAILA: + snprintf(str, str_size, "MAILA"); + break; + case DNS_RECORD_TYPE_ANY: + snprintf(str, str_size, "ANY"); + break; + case DNS_RECORD_TYPE_URI: + snprintf(str, str_size, "URI"); + break; default: snprintf(str, str_size, "%04x/%u", type, type); } diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index c19795268a4b..df68abcfe760 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -32,33 +32,66 @@ #define DNS_MAX_SIZE 256 -#define DNS_RECORD_TYPE_A 1 -#define DNS_RECORD_TYPE_NS 2 -#define DNS_RECORD_TYPE_CNAME 5 -#define DNS_RECORD_TYPE_SOA 6 +#define DNS_RECORD_TYPE_A 1 +#define DNS_RECORD_TYPE_NS 2 +#define DNS_RECORD_TYPE_MD 3 // Obsolete +#define DNS_RECORD_TYPE_MF 4 // Obsolete +#define DNS_RECORD_TYPE_CNAME 5 +#define DNS_RECORD_TYPE_SOA 6 +#define DNS_RECORD_TYPE_MB 7 // Experimental +#define DNS_RECORD_TYPE_MG 8 // Experimental +#define DNS_RECORD_TYPE_MR 9 // Experimental +#define DNS_RECORD_TYPE_NULL 10 // Experimental +#define DNS_RECORD_TYPE_WKS 11 +#define DNS_RECORD_TYPE_PTR 12 +#define DNS_RECORD_TYPE_HINFO 13 +#define DNS_RECORD_TYPE_MINFO 14 +#define DNS_RECORD_TYPE_MX 15 +#define DNS_RECORD_TYPE_TXT 16 +#define DNS_RECORD_TYPE_RP 17 +#define DNS_RECORD_TYPE_AFSDB 18 +#define DNS_RECORD_TYPE_X25 19 +#define DNS_RECORD_TYPE_ISDN 20 +#define DNS_RECORD_TYPE_RT 21 +#define DNS_RECORD_TYPE_NSAP 22 +#define DNS_RECORD_TYPE_NSAPPTR 23 +#define DNS_RECORD_TYPE_SIG 24 +#define DNS_RECORD_TYPE_KEY 25 +#define DNS_RECORD_TYPE_PX 26 +#define DNS_RECORD_TYPE_GPOS 27 +#define DNS_RECORD_TYPE_AAAA 28 +#define DNS_RECORD_TYPE_LOC 29 +#define DNS_RECORD_TYPE_NXT 30 // Obosolete +#define DNS_RECORD_TYPE_SRV 33 +#define DNS_RECORD_TYPE_ATMA 34 +#define DNS_RECORD_TYPE_NAPTR 35 +#define DNS_RECORD_TYPE_KX 36 +#define DNS_RECORD_TYPE_CERT 37 +#define DNS_RECORD_TYPE_A6 38 // Obsolete +#define DNS_RECORD_TYPE_DNAME 39 +#define DNS_RECORD_TYPE_OPT 41 +#define DNS_RECORD_TYPE_APL 42 +#define DNS_RECORD_TYPE_DS 43 +#define DNS_RECORD_TYPE_SSHFP 44 +#define DNS_RECORD_TYPE_IPSECKEY 45 +#define DNS_RECORD_TYPE_RRSIG 46 +#define DNS_RECORD_TYPE_NSEC 47 +#define DNS_RECORD_TYPE_DNSKEY 48 +#define DNS_RECORD_TYPE_DHCID 49 +#define DNS_RECORD_TYPE_NSEC3 50 +#define DNS_RECORD_TYPE_NSEC3PARAM 51 +#define DNS_RECORD_TYPE_TLSA 52 +#define DNS_RECORD_TYPE_HIP 55 +#define DNS_RECORD_TYPE_CDS 59 +#define DNS_RECORD_TYPE_CDNSKEY 60 +#define DNS_RECORD_TYPE_SPF 99 // Obsolete +#define DNS_RECORD_TYPE_TKEY 249 +#define DNS_RECORD_TYPE_TSIG 250 +#define DNS_RECORD_TYPE_MAILA 254 // Obsolete +#define DNS_RECORD_TYPE_ANY 255 +#define DNS_RECORD_TYPE_URI 256 -#define DNS_RECORD_TYPE_PTR 12 -#define DNS_RECORD_TYPE_MX 15 -#define DNS_RECORD_TYPE_TXT 16 - -#define DNS_RECORD_TYPE_AAAA 28 - -#define DNS_RECORD_TYPE_SRV 33 - -#define DNS_RECORD_TYPE_NAPTR 35 - -#define DNS_RECORD_TYPE_DS 43 - -#define DNS_RECORD_TYPE_RRSIG 46 -#define DNS_RECORD_TYPE_NSEC 47 - -#define DNS_RECORD_TYPE_NSEC3 50 - -#define DNS_RECORD_TYPE_TKEY 249 -#define DNS_RECORD_TYPE_TSIG 250 - -#define DNS_RECORD_TYPE_ANY 255 #define DNS_RCODE_NOERROR 0 #define DNS_RCODE_FORMERR 1 From 0e5bbe8564dbb916e4dae3a3edbe3ac4fe09c692 Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 28 Apr 2016 15:11:06 +0200 Subject: [PATCH 1320/2553] Reordering of RRTYPE switch case for performance. --- src/app-layer-dns-common.c | 110 ++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 83105e4cc0b6..d74547ba21d9 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -1016,35 +1016,50 @@ void DNSCreateTypeString(uint16_t type, char *str, size_t str_size) case DNS_RECORD_TYPE_NS: snprintf(str, str_size, "NS"); break; - case DNS_RECORD_TYPE_MD: - snprintf(str, str_size, "MD"); - break; - case DNS_RECORD_TYPE_MF: - snprintf(str, str_size, "MF"); + case DNS_RECORD_TYPE_AAAA: + snprintf(str, str_size, "AAAA"); break; case DNS_RECORD_TYPE_CNAME: snprintf(str, str_size, "CNAME"); break; + case DNS_RECORD_TYPE_TXT: + snprintf(str, str_size, "TXT"); + break; + case DNS_RECORD_TYPE_MX: + snprintf(str, str_size, "MX"); + break; case DNS_RECORD_TYPE_SOA: snprintf(str, str_size, "SOA"); break; - case DNS_RECORD_TYPE_MB: - snprintf(str, str_size, "MB"); - break; - case DNS_RECORD_TYPE_MG: - snprintf(str, str_size, "MG"); + case DNS_RECORD_TYPE_PTR: + snprintf(str, str_size, "PTR"); break; - case DNS_RECORD_TYPE_MR: - snprintf(str, str_size, "MR"); + case DNS_RECORD_TYPE_SIG: + snprintf(str, str_size, "SIG"); break; - case DNS_RECORD_TYPE_NULL: - snprintf(str, str_size, "NULL"); + case DNS_RECORD_TYPE_KEY: + snprintf(str, str_size, "KEY"); break; case DNS_RECORD_TYPE_WKS: snprintf(str, str_size, "WKS"); break; - case DNS_RECORD_TYPE_PTR: - snprintf(str, str_size, "PTR"); + case DNS_RECORD_TYPE_TKEY: + snprintf(str, str_size, "TKEY"); + break; + case DNS_RECORD_TYPE_TSIG: + snprintf(str, str_size, "TSIG"); + break; + case DNS_RECORD_TYPE_ANY: + snprintf(str, str_size, "ANY"); + break; + case DNS_RECORD_TYPE_RRSIG: + snprintf(str, str_size, "RRSIG"); + break; + case DNS_RECORD_TYPE_NSEC: + snprintf(str, str_size, "NSEC"); + break; + case DNS_RECORD_TYPE_DNSKEY: + snprintf(str, str_size, "DNSKEY"); break; case DNS_RECORD_TYPE_HINFO: snprintf(str, str_size, "HINFO"); @@ -1052,12 +1067,6 @@ void DNSCreateTypeString(uint16_t type, char *str, size_t str_size) case DNS_RECORD_TYPE_MINFO: snprintf(str, str_size, "MINFO"); break; - case DNS_RECORD_TYPE_MX: - snprintf(str, str_size, "MX"); - break; - case DNS_RECORD_TYPE_TXT: - snprintf(str, str_size, "TXT"); - break; case DNS_RECORD_TYPE_RP: snprintf(str, str_size, "RP"); break; @@ -1079,27 +1088,15 @@ void DNSCreateTypeString(uint16_t type, char *str, size_t str_size) case DNS_RECORD_TYPE_NSAPPTR: snprintf(str, str_size, "NSAPPTR"); break; - case DNS_RECORD_TYPE_SIG: - snprintf(str, str_size, "SIG"); - break; - case DNS_RECORD_TYPE_KEY: - snprintf(str, str_size, "KEY"); - break; case DNS_RECORD_TYPE_PX: snprintf(str, str_size, "PX"); break; case DNS_RECORD_TYPE_GPOS: snprintf(str, str_size, "GPOS"); break; - case DNS_RECORD_TYPE_AAAA: - snprintf(str, str_size, "AAAA"); - break; case DNS_RECORD_TYPE_LOC: snprintf(str, str_size, "LOC"); break; - case DNS_RECORD_TYPE_NXT: - snprintf(str, str_size, "NXT"); - break; case DNS_RECORD_TYPE_SRV: snprintf(str, str_size, "SRV"); break; @@ -1136,15 +1133,6 @@ void DNSCreateTypeString(uint16_t type, char *str, size_t str_size) case DNS_RECORD_TYPE_IPSECKEY: snprintf(str, str_size, "IPSECKEY"); break; - case DNS_RECORD_TYPE_RRSIG: - snprintf(str, str_size, "RRSIG"); - break; - case DNS_RECORD_TYPE_NSEC: - snprintf(str, str_size, "NSEC"); - break; - case DNS_RECORD_TYPE_DNSKEY: - snprintf(str, str_size, "DNSKEY"); - break; case DNS_RECORD_TYPE_DHCID: snprintf(str, str_size, "DHCID"); break; @@ -1166,24 +1154,36 @@ void DNSCreateTypeString(uint16_t type, char *str, size_t str_size) case DNS_RECORD_TYPE_CDNSKEY: snprintf(str, str_size, "CDNSKEY"); break; - case DNS_RECORD_TYPE_SPF: - snprintf(str, str_size, "SPF"); - break; - case DNS_RECORD_TYPE_TKEY: - snprintf(str, str_size, "TKEY"); - break; - case DNS_RECORD_TYPE_TSIG: - snprintf(str, str_size, "TSIG"); - break; case DNS_RECORD_TYPE_MAILA: snprintf(str, str_size, "MAILA"); break; - case DNS_RECORD_TYPE_ANY: - snprintf(str, str_size, "ANY"); - break; case DNS_RECORD_TYPE_URI: snprintf(str, str_size, "URI"); break; + case DNS_RECORD_TYPE_MB: + snprintf(str, str_size, "MB"); + break; + case DNS_RECORD_TYPE_MG: + snprintf(str, str_size, "MG"); + break; + case DNS_RECORD_TYPE_MR: + snprintf(str, str_size, "MR"); + break; + case DNS_RECORD_TYPE_NULL: + snprintf(str, str_size, "NULL"); + break; + case DNS_RECORD_TYPE_SPF: + snprintf(str, str_size, "SPF"); + break; + case DNS_RECORD_TYPE_NXT: + snprintf(str, str_size, "NXT"); + break; + case DNS_RECORD_TYPE_MD: + snprintf(str, str_size, "MD"); + break; + case DNS_RECORD_TYPE_MF: + snprintf(str, str_size, "MF"); + break; default: snprintf(str, str_size, "%04x/%u", type, type); } From dd86ac07f71d593f16244710ebd8fec3b4e48277 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 28 Apr 2016 15:09:18 -0600 Subject: [PATCH 1321/2553] smb: check that there is enough input data Conditional was checking the word count, but indexing much further into the input data. --- src/app-layer-smb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 561d283f3530..11c8539e8e3f 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -414,7 +414,7 @@ static uint32_t SMBParseTransact(Flow *f, void *smb_state, switch (sstate->andx.andxbytesprocessed) { case 0: sstate->andx.paddingparsed = 0; - if (input_len >= sstate->wordcount.wordcount) { + if (input_len >= 26) { sstate->andx.datalength = *(p + 22); sstate->andx.datalength |= *(p + 23) << 8; sstate->andx.dataoffset = *(p + 24); @@ -423,8 +423,8 @@ static uint32_t SMBParseTransact(Flow *f, void *smb_state, sstate->andx.datalength |= (uint64_t) *(p + 15) << 48; sstate->andx.datalength |= (uint64_t) *(p + 16) << 40; sstate->andx.datalength |= (uint64_t) *(p + 17) << 32; - sstate->bytesprocessed += sstate->wordcount.wordcount; - sstate->andx.andxbytesprocessed += sstate->wordcount.wordcount; + sstate->bytesprocessed += 26; + sstate->andx.andxbytesprocessed += 26; SCReturnUInt(sstate->wordcount.wordcount); } else { /* total parameter count 1 */ From db4ec46f1864dd7ab6333e47c1294b0c4a41cc8c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 3 May 2016 10:29:05 +0200 Subject: [PATCH 1322/2553] coverty: fix dead code warning --- src/util-device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util-device.c b/src/util-device.c index f58bbc35a88e..a4e634ee0c66 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -126,10 +126,10 @@ int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen) * max length of pthread names (15 chars) and we use 3 chars * for the threadname indicator eg. "W#-" and one-two chars for * the thread number. And if the destination buffer is under - * 6 chars there is point in shortening it since we must at - * lest enter two periodes (.) into the string.. + * 6 chars there is no point in shortening it since we must at + * least enter two periods (.) into the string. */ - if ((destlen-1) > 10 && (destlen-1) < 6) { + if ((destlen-1) > 10 || (destlen-1) < 6) { return 1; } From c742a818d558216512290c1602ffdd3bce3a1325 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 3 May 2016 11:48:56 +0200 Subject: [PATCH 1323/2553] profiling: suppress inferior version of UtilCpuGetTicks warning --- src/util-cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-cpu.c b/src/util-cpu.c index 9a5c25df1308..655bffbd55c0 100644 --- a/src/util-cpu.c +++ b/src/util-cpu.c @@ -221,7 +221,7 @@ uint64_t UtilCpuGetTicks(void) #endif #else /* #if defined(__GNU__) */ -#warning Using inferior version of UtilCpuGetTicks +//#warning Using inferior version of UtilCpuGetTicks struct timeval now; gettimeofday(&now, NULL); val = (now.tv_sec * 1000000) + now.tv_usec; From 524c6271948129f04d393220026628b21627fdc8 Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 5 May 2016 10:41:42 +0200 Subject: [PATCH 1324/2553] Use ConfValIs* for parsing pcap-file.checksum-checks. --- src/source-pcap-file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 4df2c72a61cf..cff52542a198 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -352,9 +352,9 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) } else { if (strcmp(tmpstring, "auto") == 0) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_AUTO; - } else if (strcmp(tmpstring, "yes") == 0) { + } else if (ConfValIsTrue(tmpstring)){ pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(tmpstring, "no") == 0) { + } else if (ConfValIsFalse(tmpstring)) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_DISABLE; } } From 3d4cdd11175469e99b8ef4f9d76f71fb6398e976 Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 5 May 2016 10:44:06 +0200 Subject: [PATCH 1325/2553] Use ConfValIs* for parseing mpipe.checksum-checks. --- src/source-mpipe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/source-mpipe.c b/src/source-mpipe.c index 9f9c9a3b0a1d..d304b4a8b108 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -352,9 +352,9 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) ptv->checksum_mode = CHECKSUM_VALIDATION_DISABLE; if (ConfGet("mpipe.checksum-checks", &ctype) == 1) { - if (strcmp(ctype, "yes") == 0) { + if (ConfValIsTrue(ctype)) { ptv->checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(ctype, "no") == 0) { + } else if (ConfValIsFalse(ctype)) { ptv->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, From d18e2f6e9a5a9a6f944bf54dbb648473d9e49fa5 Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 5 May 2016 10:50:21 +0200 Subject: [PATCH 1326/2553] Use ConfValIs* for parsing af-packet.checksum-checks. --- src/runmode-af-packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index ee44042a2c85..85d4c770a0f6 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -359,9 +359,9 @@ void *ParseAFPConfig(const char *iface) if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; - } else if (strcmp(tmpctype, "yes") == 0) { + } else if (ConfValIsTrue(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(tmpctype, "no") == 0) { + } else if (ConfValIsFalse(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else if (strcmp(tmpctype, "kernel") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; From b28ebae088324af35d1ff87e115f9442d1ca3f9f Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 5 May 2016 10:51:57 +0200 Subject: [PATCH 1327/2553] Use ConfValIs* for parsing netmap.checksum-checks. --- src/runmode-netmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 75eb0c6fe25d..13a0c2b3d900 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -254,9 +254,9 @@ static void *ParseNetmapConfig(const char *iface_name) if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; - } else if (strcmp(tmpctype, "yes") == 0) { + } else if (ConfValIsTrue(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(tmpctype, "no") == 0) { + } else if (ConfValIsFalse(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface_name); From 70b864d06b7b35958adda92c2ad2725cb11dbbcd Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 5 May 2016 10:53:41 +0200 Subject: [PATCH 1328/2553] Use ConfValIs* for parsing pcap.checksum-checks. --- src/runmode-pcap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runmode-pcap.c b/src/runmode-pcap.c index 52eff0f9bf91..a08150109f47 100644 --- a/src/runmode-pcap.c +++ b/src/runmode-pcap.c @@ -191,9 +191,9 @@ void *ParsePcapConfig(const char *iface) if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; - } else if (strcmp(tmpctype, "yes") == 0) { + } else if (ConfValIsTrue(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(tmpctype, "no") == 0) { + } else if (ConfValIsFalse(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface); From a81796654f5becc59e4793cd9ff50b77e51f4d9a Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 5 May 2016 10:58:24 +0200 Subject: [PATCH 1329/2553] Use ConfValIs* for parsing pf-ring.checksum-checks. --- src/runmode-pfring.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runmode-pfring.c b/src/runmode-pfring.c index ca37649c7c0c..f7aa410a5dac 100644 --- a/src/runmode-pfring.c +++ b/src/runmode-pfring.c @@ -354,9 +354,9 @@ void *ParsePfringConfig(const char *iface) if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { pfconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; - } else if (strcmp(tmpctype, "yes") == 0) { + } else if (ConfValIsTrue(tmpctype)) { pfconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(tmpctype, "no") == 0) { + } else if (ConfValIsFalse(tmpctype)) { pfconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else if (strcmp(tmpctype, "rx-only") == 0) { pfconf->checksum_mode = CHECKSUM_VALIDATION_RXONLY; From 3c15c1f8d5699ff3a2642d4e2770d10b758ab47d Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 5 May 2016 11:06:57 +0200 Subject: [PATCH 1330/2553] Use ConfValIsTrue for parsing TILE PCIE logging append value. --- src/util-logopenfile-tile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-logopenfile-tile.c b/src/util-logopenfile-tile.c index c2414fc49b45..82e9bbf3b4a2 100644 --- a/src/util-logopenfile-tile.c +++ b/src/util-logopenfile-tile.c @@ -349,7 +349,7 @@ PcieFile *TileOpenPcieFp(LogFileCtx *log_ctx, const char *path, const char *append_setting) { PcieFile *ret = NULL; - if (strcasecmp(append_setting, "yes") == 0) { + if (ConfValIsTrue(append_setting)) { ret = TileOpenPcieFpInternal(path, 'a'); } else { ret = TileOpenPcieFpInternal(path, 'w'); From bf551ace4ef2e5a116184f0e77d17e6b10b0535c Mon Sep 17 00:00:00 2001 From: maxtors Date: Thu, 5 May 2016 11:12:22 +0200 Subject: [PATCH 1331/2553] Use ConfValIsTrue for parseing util-logfile append value. --- src/util-logopenfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 04173d48f1ef..63cc05acbb7c 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -172,7 +172,7 @@ SCLogOpenFileFp(const char *path, const char *append_setting) { FILE *ret = NULL; - if (strcasecmp(append_setting, "yes") == 0) { + if (ConfValIsTrue(append_setting)) { ret = fopen(path, "a"); } else { ret = fopen(path, "w"); From e29e9056cb83de896d5b06fcf4d049169750901e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 9 May 2016 00:06:57 +0200 Subject: [PATCH 1332/2553] config-test: fix memory leak detect by ASAN NSS library was not deinit at exit resulting in memory leak. As it is useless for a config test, the patch updates the code so it is not initialized. Patch also calls MagicDeinit to free memory used by libmagic. --- src/suricata.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index ee0d40fff737..d6285382ac52 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2353,10 +2353,13 @@ static int PostConfLoadedSetup(SCInstance *suri) if (InitSignalHandler(suri) != TM_ECODE_OK) SCReturnInt(TM_ECODE_FAILED); + #ifdef HAVE_NSS - /* init NSS for md5 */ - PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); - NSS_NoDB_Init(NULL); + if (suri->run_mode != RUNMODE_CONF_TEST) { + /* init NSS for md5 */ + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + NSS_NoDB_Init(NULL); + } #endif if (suri->disabled_detect) { @@ -2536,6 +2539,7 @@ int main(int argc, char **argv) if (suri.run_mode == RUNMODE_CONF_TEST){ SCLogNotice("Configuration provided was successfully loaded. Exiting."); + MagicDeinit(); exit(EXIT_SUCCESS); } From aa8e747e4d39fb32349ea6638649f5653e2519b6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 5 May 2016 09:41:45 -0600 Subject: [PATCH 1333/2553] sources: allow interface definitions to be reordered For af-packet, pf-ring, netmap, and pcap use a generic lookup function to find the configuration node for an interface. The new lookup function does not depend on the ordering of the items inside the device configuration. --- src/runmode-af-packet.c | 6 +++--- src/runmode-netmap.c | 4 ++-- src/runmode-pcap.c | 4 ++-- src/runmode-pfring.c | 4 ++-- src/util-conf.c | 28 ++++++++++++++++++++++++++++ src/util-conf.h | 4 ++++ 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 85d4c770a0f6..73bd263e1e35 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -163,9 +163,9 @@ void *ParseAFPConfig(const char *iface) return aconf; } - if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", iface); + if_root = ConfFindDeviceConfig(af_packet_node, iface); - if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default"); + if_default = ConfFindDeviceConfig(af_packet_node, "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find af-packet config for " @@ -433,7 +433,7 @@ int AFPRunModeIsIPS() return 0; } char *copymodestr = NULL; - if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", live_dev); + if_root = ConfFindDeviceConfig(af_packet_node, live_dev); if (if_root == NULL) { if (if_default == NULL) { diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 13a0c2b3d900..6ddad0439197 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -159,9 +159,9 @@ static void *ParseNetmapConfig(const char *iface_name) return aconf; } - if_root = ConfNodeLookupKeyValue(netmap_node, "interface", aconf->iface_name); + if_root = ConfFindDeviceConfig(netmap_node, "interface", aconf->iface_name); - if_default = ConfNodeLookupKeyValue(netmap_node, "interface", "default"); + if_default = ConfFindDeviceConfig(netmap_node, "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find netmap config for " diff --git a/src/runmode-pcap.c b/src/runmode-pcap.c index a08150109f47..c2d806fff93a 100644 --- a/src/runmode-pcap.c +++ b/src/runmode-pcap.c @@ -121,9 +121,9 @@ void *ParsePcapConfig(const char *iface) return aconf; } - if_root = ConfNodeLookupKeyValue(pcap_node, "interface", iface); + if_root = ConfFindDeviceConfig(pcap_node, "iface"); - if_default = ConfNodeLookupKeyValue(pcap_node, "interface", "default"); + if_default = ConfFindDeviceConfig(pcap_node, "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find pcap config for " diff --git a/src/runmode-pfring.c b/src/runmode-pfring.c index f7aa410a5dac..5332252570f5 100644 --- a/src/runmode-pfring.c +++ b/src/runmode-pfring.c @@ -230,9 +230,9 @@ void *ParsePfringConfig(const char *iface) return pfconf; } - if_root = ConfNodeLookupKeyValue(pf_ring_node, "interface", iface); + if_root = ConfFindDeviceConfig(pf_ring_node, iface); - if_default = ConfNodeLookupKeyValue(pf_ring_node, "interface", "default"); + if_default = ConfFindDeviceConfig(pf_ring_node, "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find pfring config for " diff --git a/src/util-conf.c b/src/util-conf.c index e0f25d1d6395..17f5edfe32aa 100644 --- a/src/util-conf.c +++ b/src/util-conf.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "config.h" #include "conf.h" +#include "util-conf.h" TmEcode ConfigSetLogDirectory(char *name) { @@ -63,3 +64,30 @@ TmEcode ConfigCheckLogDirectory(char *log_dir) } SCReturnInt(TM_ECODE_OK); } + +/** + * \brief Find the configuration node for a specific device. + + * Basically hunts through the list of maps for the first one with a + * key of "interface", and a value of the provided interface. + * + * \param node The node to start looking for the device + * configuration. Typically this would be something like the af-packet + * or pf-ring node. + * + * \param iface The name of the interface to find the config for. + */ +ConfNode *ConfFindDeviceConfig(ConfNode *node, const char *iface) +{ + ConfNode *if_node, *item; + TAILQ_FOREACH(if_node, &node->head, next) { + TAILQ_FOREACH(item, &if_node->head, next) { + if (strcmp(item->name, "interface") == 0 && + strcmp(item->val, iface) == 0) { + return if_node; + } + } + } + + return NULL; +} diff --git a/src/util-conf.h b/src/util-conf.h index 74d87e305a78..4f6399af8e1b 100644 --- a/src/util-conf.h +++ b/src/util-conf.h @@ -25,8 +25,12 @@ #ifndef __UTIL_UTIL_CONF_H__ #define __UTIL_UTIL_CONF_H__ +#include "conf.h" + TmEcode ConfigSetLogDirectory(char *name); char *ConfigGetLogDirectory(); TmEcode ConfigCheckLogDirectory(char *log_dir); +ConfNode *ConfFindDeviceConfig(ConfNode *node, const char *iface); + #endif /* __UTIL_UTIL_CONF_H__ */ From c64815e4a892a78cc4cc1a0bfe1b25f6b1a24216 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 11:04:29 +0200 Subject: [PATCH 1334/2553] decode-mime: don't call memcpy on NULL pointer --- src/util-decode-mime.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 60206c20e32c..01cb28fb145e 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -1210,7 +1210,9 @@ static uint8_t ProcessBase64Remainder(const uint8_t *buf, uint32_t len, /* Fill in block with first few bytes of current line */ remainder = B64_BLOCK - state->bvr_len; remainder = remainder < len ? remainder : len; - memcpy(state->bvremain + state->bvr_len, buf, remainder); + if (remainder && buf) { + memcpy(state->bvremain + state->bvr_len, buf, remainder); + } state->bvr_len += remainder; /* If data chunk buffer will be full, then clear it now */ From 76c8c077c59e4f83e5f0558d23639649612322e7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 12:43:11 +0200 Subject: [PATCH 1335/2553] tcp: fix alignment issues with tcp timestamps --- src/decode-tcp.c | 8 ++++-- src/decode-tcp.h | 22 +++++++-------- src/stream-tcp.c | 72 ++++++++++++++---------------------------------- 3 files changed, 37 insertions(+), 65 deletions(-) diff --git a/src/decode-tcp.c b/src/decode-tcp.c index 36a63d3c30b6..b3c73b5d8910 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -124,10 +124,14 @@ static int DecodeTCPOptions(Packet *p, uint8_t *pkt, uint16_t len) if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_TS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.ts.type != 0) { + if (p->tcpvars.ts_set) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - SET_OPTS(p->tcpvars.ts, tcp_opts[tcp_opt_cnt]); + uint32_t values[2]; + memcpy(&values, tcp_opts[tcp_opt_cnt].data, sizeof(values)); + p->tcpvars.ts_val = ntohl(values[0]); + p->tcpvars.ts_ecr = ntohl(values[1]); + p->tcpvars.ts_set = TRUE; } } break; diff --git a/src/decode-tcp.h b/src/decode-tcp.h index 955800e17ade..72ed8179740b 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -76,20 +76,16 @@ #define TCP_GET_RAW_WINDOW(tcph) ntohs((tcph)->th_win) #define TCP_GET_RAW_URG_POINTER(tcph) ntohs((tcph)->th_urp) -/** macro for getting the first timestamp from the packet. Timestamp is in host - * order and either returned from the cache or from the packet directly. */ -#define TCP_GET_TSVAL(p) \ - (uint32_t)ntohl((*(uint32_t *)(p)->tcpvars.ts.data)) +/** macro for getting the first timestamp from the packet in host order */ +#define TCP_GET_TSVAL(p) ((p)->tcpvars.ts_val) -/** macro for getting the second timestamp from the packet. Timestamp is in - * host order and either returned from the cache or from the packet directly. */ -#define TCP_GET_TSECR(p) \ - (uint32_t)ntohl((*(uint32_t *)((p)->tcpvars.ts.data+4))) +/** macro for getting the second timestamp from the packet in host order. */ +#define TCP_GET_TSECR(p) ((p)->tcpvars.ts_ecr) #define TCP_HAS_WSCALE(p) ((p)->tcpvars.ws.type == TCP_OPT_WS) #define TCP_HAS_SACK(p) ((p)->tcpvars.sack.type == TCP_OPT_SACK) #define TCP_HAS_SACKOK(p) ((p)->tcpvars.sackok.type == TCP_OPT_SACKOK) -#define TCP_HAS_TS(p) ((p)->tcpvars.ts.type == TCP_OPT_TS) +#define TCP_HAS_TS(p) ((p)->tcpvars.ts_set == TRUE) #define TCP_HAS_MSS(p) ((p)->tcpvars.mss.type == TCP_OPT_MSS) /** macro for getting the wscale from the packet. */ @@ -146,7 +142,9 @@ typedef struct TCPHdr_ typedef struct TCPVars_ { /* commonly used and needed opts */ - TCPOpt ts; + _Bool ts_set; + uint32_t ts_val; /* host-order */ + uint32_t ts_ecr; /* host-order */ TCPOpt sack; TCPOpt sackok; TCPOpt ws; @@ -156,7 +154,9 @@ typedef struct TCPVars_ #define CLEAR_TCP_PACKET(p) { \ (p)->tcph = NULL; \ (p)->level4_comp_csum = -1; \ - (p)->tcpvars.ts.type = 0; \ + (p)->tcpvars.ts_set = FALSE; \ + (p)->tcpvars.ts_val = 0; \ + (p)->tcpvars.ts_ecr = 0; \ (p)->tcpvars.sack.type = 0; \ (p)->tcpvars.sackok.type = 0; \ (p)->tcpvars.ws.type = 0; \ diff --git a/src/stream-tcp.c b/src/stream-tcp.c index f17a76136999..875a9d6f3e4c 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -6436,14 +6436,12 @@ static int StreamTcpTest06 (void) static int StreamTcpTest07 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF(unlikely(p == NULL)); Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[1] = {0x42}; - uint32_t data[2]; PacketQueue pq; memset(p, 0, SIZE_OF_PACKET); @@ -6455,7 +6453,6 @@ static int StreamTcpTest07 (void) FLOW_INITIALIZE(&f); p->flow = &f; - int ret = 0; StreamTcpInitConfig(TRUE); stream_config.midstream = TRUE; @@ -6470,45 +6467,33 @@ static int StreamTcpTest07 (void) tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; - data[0] = htonl(10); - data[1] = htonl(11); - - p->tcpvars.ts.type = TCP_OPT_TS; - p->tcpvars.ts.len = 10; - p->tcpvars.ts.data = (uint8_t *)data; + p->tcpvars.ts_set = TRUE; + p->tcpvars.ts_val = 10; + p->tcpvars.ts_ecr = 11; p->payload = payload; p->payload_len = 1; SCMutexLock(&f.m); - if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) - goto end; + FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1); p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; - data[0] = htonl(2); - p->tcpvars.ts.data = (uint8_t *)data; + p->tcpvars.ts_val = 2; - if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { - if (((TcpSession *) (p->flow->protoctx))->client.next_seq != 11) { - printf("the timestamp values are client %"PRIu32" server %" PRIu32"" - " seq %" PRIu32 "\n", TCP_GET_TSVAL(p), TCP_GET_TSECR(p), - ((TcpSession *) (p->flow->protoctx))->client.next_seq); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) != -1); - StreamTcpSessionClear(p->flow->protoctx); - ret = 1; - } -end: + FAIL_IF (((TcpSession *) (p->flow->protoctx))->client.next_seq != 11); + + StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); FLOW_DESTROY(&f); - return ret; + PASS; } /** @@ -6520,16 +6505,13 @@ static int StreamTcpTest07 (void) static int StreamTcpTest08 (void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF(unlikely(p == NULL)); Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[1] = {0x42}; - uint32_t data[2]; memset(p, 0, SIZE_OF_PACKET); PacketQueue pq; @@ -6541,7 +6523,6 @@ static int StreamTcpTest08 (void) FLOW_INITIALIZE(&f); p->flow = &f; - int ret = 0; StreamTcpInitConfig(TRUE); stream_config.midstream = TRUE; @@ -6556,47 +6537,34 @@ static int StreamTcpTest08 (void) tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; - data[0] = htonl(10); - data[1] = htonl(11); - - p->tcpvars.ts.type = TCP_OPT_TS; - p->tcpvars.ts.len = 10; - p->tcpvars.ts.data = (uint8_t *)data; + p->tcpvars.ts_set = TRUE; + p->tcpvars.ts_val = 10; + p->tcpvars.ts_ecr = 11; p->payload = payload; p->payload_len = 1; SCMutexLock(&f.m); - if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) - goto end; + FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1); p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(20); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; - data[0] = htonl(12); - p->tcpvars.ts.data = (uint8_t *)data; + p->tcpvars.ts_val = 12; - if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) - goto end; + FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1); - if (((TcpSession *) (p->flow->protoctx))->client.next_seq != 12) { - printf("the timestamp values are client %"PRIu32" server %" PRIu32 " " - "seq %" PRIu32 "\n", TCP_GET_TSVAL(p), TCP_GET_TSECR(p), - ((TcpSession *) (p->flow->protoctx))->client.next_seq); - goto end; - } + FAIL_IF(((TcpSession *) (p->flow->protoctx))->client.next_seq != 12); StreamTcpSessionClear(p->flow->protoctx); - ret = 1; -end: StreamTcpFreeConfig(TRUE); SCMutexUnlock(&f.m); SCFree(p); FLOW_DESTROY(&f); - return ret; + PASS; } /** From b112af817dd5ee518fd8ec595ea64c9a00ece080 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 12:49:33 +0200 Subject: [PATCH 1336/2553] flow: fix alignment issues --- src/flow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flow.c b/src/flow.c index 2ce66d6f5782..a2e1a64cd42a 100644 --- a/src/flow.c +++ b/src/flow.c @@ -422,7 +422,7 @@ void FlowInitConfig(char quiet) (uintmax_t)sizeof(FlowBucket)); exit(EXIT_FAILURE); } - flow_hash = SCCalloc(flow_config.hash_size, sizeof(FlowBucket)); + flow_hash = SCMallocAligned(flow_config.hash_size * sizeof(FlowBucket), CLS); if (unlikely(flow_hash == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in FlowInitConfig. Exiting..."); exit(EXIT_FAILURE); @@ -515,7 +515,7 @@ void FlowShutdown(void) FBLOCK_DESTROY(&flow_hash[u]); } - SCFree(flow_hash); + SCFreeAligned(flow_hash); flow_hash = NULL; } (void) SC_ATOMIC_SUB(flow_memuse, flow_config.hash_size * sizeof(FlowBucket)); From 31b632a17df9e650f3dc9c9ea48774757488d972 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 12:50:01 +0200 Subject: [PATCH 1337/2553] host: fix alignment issues --- src/host.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/host.c b/src/host.c index faf9513bde87..86092d9ef31d 100644 --- a/src/host.c +++ b/src/host.c @@ -196,7 +196,7 @@ void HostInitConfig(char quiet) (uintmax_t)sizeof(HostHashRow)); exit(EXIT_FAILURE); } - host_hash = SCCalloc(host_config.hash_size, sizeof(HostHashRow)); + host_hash = SCMallocAligned(host_config.hash_size * sizeof(HostHashRow), CLS); if (unlikely(host_hash == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in HostInitConfig. Exiting..."); exit(EXIT_FAILURE); @@ -284,7 +284,7 @@ void HostShutdown(void) HRLOCK_DESTROY(&host_hash[u]); } - SCFree(host_hash); + SCFreeAligned(host_hash); host_hash = NULL; } (void) SC_ATOMIC_SUB(host_memuse, host_config.hash_size * sizeof(HostHashRow)); From 35d081a797a1eaff6351eefb072b0741e8241471 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 12:50:15 +0200 Subject: [PATCH 1338/2553] ippair: fix alignment issues --- src/ippair.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ippair.c b/src/ippair.c index 736cdce5bad5..e86d67b5316e 100644 --- a/src/ippair.c +++ b/src/ippair.c @@ -192,7 +192,7 @@ void IPPairInitConfig(char quiet) (uintmax_t)sizeof(IPPairHashRow)); exit(EXIT_FAILURE); } - ippair_hash = SCCalloc(ippair_config.hash_size, sizeof(IPPairHashRow)); + ippair_hash = SCMallocAligned(ippair_config.hash_size * sizeof(IPPairHashRow), CLS); if (unlikely(ippair_hash == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in IPPairInitConfig. Exiting..."); exit(EXIT_FAILURE); @@ -280,7 +280,7 @@ void IPPairShutdown(void) HRLOCK_DESTROY(&ippair_hash[u]); } - SCFree(ippair_hash); + SCFreeAligned(ippair_hash); ippair_hash = NULL; } (void) SC_ATOMIC_SUB(ippair_memuse, ippair_config.hash_size * sizeof(IPPairHashRow)); From 001e87310d8e2b366934abc7d57b8248f323f2cc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 12:54:37 +0200 Subject: [PATCH 1339/2553] decode: don't call memcpy on NULL-ptr on pseudo packets --- src/decode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/decode.c b/src/decode.c index 1b73722e3ab1..345cb6cdae2e 100644 --- a/src/decode.c +++ b/src/decode.c @@ -347,7 +347,9 @@ Packet *PacketDefragPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t p->root = parent; /* copy packet and set lenght, proto */ - PacketCopyData(p, pkt, len); + if (pkt && len) { + PacketCopyData(p, pkt, len); + } p->recursion_level = parent->recursion_level; /* NOT incremented */ p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; From 9235dd498f6e4a14d09dc63f2b0b721636788498 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 13:06:15 +0200 Subject: [PATCH 1340/2553] detect port: fix integer handling in hashing --- src/detect-engine-port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index 59fd2d08f444..d545dc16d377 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -1487,7 +1487,7 @@ static uint32_t DetectPortHashFunc(HashListTable *ht, void *data, uint16_t datal SCLogDebug("hashing sgh %p", p); - hash = (p->port << 16) | p->port2; + hash = ((uint32_t)p->port << 16) | p->port2; hash %= ht->array_size; SCLogDebug("hash %"PRIu32, hash); From ed5a01e8ddb5d83abed8cf04f0e794279758f91f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 14:57:55 +0200 Subject: [PATCH 1341/2553] dcerpc: improve integer handling --- src/app-layer-dcerpc-udp.c | 72 +++++++++++++++++++------------------- src/app-layer-dcerpc.c | 24 ++++++------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/app-layer-dcerpc-udp.c b/src/app-layer-dcerpc-udp.c index a9c58df09faf..7ab5f83ab2e3 100644 --- a/src/app-layer-dcerpc-udp.c +++ b/src/app-layer-dcerpc-udp.c @@ -196,18 +196,18 @@ static int DCERPCUDPParseHeader(Flow *f, void *dcerpcudp_state, sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p + 54); sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p + 55); if (sstate->dcerpc.dcerpchdrudp.drep[0] == 0x10) { - sstate->dcerpc.dcerpchdrudp.server_boot = *(p + 56); - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 57) << 8; - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 58) << 16; - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 59) << 24; - sstate->dcerpc.dcerpchdrudp.if_vers = *(p + 60); - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 61) << 8; - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 62) << 16; - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 63) << 24; - sstate->dcerpc.dcerpchdrudp.seqnum = *(p + 64); - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 65) << 8; - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 66) << 16; - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 67) << 24; + sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p + 56); + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 57) << 8; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 58) << 16; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 59) << 24; + sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p + 60); + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 61) << 8; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 62) << 16; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 63) << 24; + sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p + 64); + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 65) << 8; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 66) << 16; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 67) << 24; sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68); sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 8; sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70); @@ -219,18 +219,18 @@ static int DCERPCUDPParseHeader(Flow *f, void *dcerpcudp_state, sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76); sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77) << 8; } else { - sstate->dcerpc.dcerpchdrudp.server_boot = *(p + 56) << 24; - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 57) << 16; - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 58) << 8; - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 59); - sstate->dcerpc.dcerpchdrudp.if_vers = *(p + 60) << 24; - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 61) << 16; - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 62) << 8; - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 63); - sstate->dcerpc.dcerpchdrudp.seqnum = *(p + 64) << 24; - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 65) << 16; - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 66) << 8; - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 67); + sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p + 56) << 24; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 57) << 16; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 58) << 8; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 59); + sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p + 60) << 24; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 61) << 16; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 62) << 8; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 63); + sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p + 64) << 24; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 65) << 16; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 66) << 8; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 67); sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68) << 24; sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 16; sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70) << 8; @@ -553,62 +553,62 @@ static int DCERPCUDPParseHeader(Flow *f, void *dcerpcudp_state, break; /* fall through */ case 56: - sstate->dcerpc.dcerpchdrudp.server_boot = *(p++); + sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p++); if (!(--input_len)) break; /* fall through */ case 57: - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p++) << 8; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 8; if (!(--input_len)) break; /* fall through */ case 58: - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p++) << 16; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 16; if (!(--input_len)) break; /* fall through */ case 59: - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p++) << 24; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 24; if (!(--input_len)) break; /* fall through */ case 60: - sstate->dcerpc.dcerpchdrudp.if_vers = *(p++); + sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p++); if (!(--input_len)) break; /* fall through */ case 61: - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p++) << 8; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 8; if (!(--input_len)) break; /* fall through */ case 62: - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p++) << 16; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 16; if (!(--input_len)) break; /* fall through */ case 63: - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p++) << 24; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 24; if (!(--input_len)) break; /* fall through */ case 64: - sstate->dcerpc.dcerpchdrudp.seqnum = *(p++); + sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p++); if (!(--input_len)) break; /* fall through */ case 65: - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p++) << 8; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 8; if (!(--input_len)) break; /* fall through */ case 66: - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p++) << 16; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 16; if (!(--input_len)) break; /* fall through */ case 67: - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p++) << 24; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 24; if (!(--input_len)) break; /* fall through */ diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 1916b72aa2de..ece676e7f143 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -1295,19 +1295,19 @@ static int DCERPCParseHeader(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) dcerpc->dcerpchdr.frag_length |= *(p + 9) << 8; dcerpc->dcerpchdr.auth_length = *(p + 10); dcerpc->dcerpchdr.auth_length |= *(p + 11) << 8; - dcerpc->dcerpchdr.call_id = *(p + 12) << 24; - dcerpc->dcerpchdr.call_id |= *(p + 13) << 16; - dcerpc->dcerpchdr.call_id |= *(p + 14) << 8; - dcerpc->dcerpchdr.call_id |= *(p + 15); + dcerpc->dcerpchdr.call_id = (uint32_t) *(p + 12) << 24; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 13) << 16; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 14) << 8; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 15); } else { dcerpc->dcerpchdr.frag_length = *(p + 8) << 8; dcerpc->dcerpchdr.frag_length |= *(p + 9); dcerpc->dcerpchdr.auth_length = *(p + 10) << 8; dcerpc->dcerpchdr.auth_length |= *(p + 11); - dcerpc->dcerpchdr.call_id = *(p + 12); - dcerpc->dcerpchdr.call_id |= *(p + 13) << 8; - dcerpc->dcerpchdr.call_id |= *(p + 14) << 16; - dcerpc->dcerpchdr.call_id |= *(p + 15) << 24; + dcerpc->dcerpchdr.call_id = (uint32_t) *(p + 12); + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 13) << 8; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 14) << 16; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 15) << 24; } dcerpc->bytesprocessed = DCERPC_HDR_LEN; SCReturnInt(16); @@ -1382,22 +1382,22 @@ static int DCERPCParseHeader(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) break; /* fall through */ case 12: - dcerpc->dcerpchdr.call_id = *(p++); + dcerpc->dcerpchdr.call_id = (uint32_t) *(p++); if (!(--input_len)) break; /* fall through */ case 13: - dcerpc->dcerpchdr.call_id |= *(p++) << 8; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p++) << 8; if (!(--input_len)) break; /* fall through */ case 14: - dcerpc->dcerpchdr.call_id |= *(p++) << 16; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p++) << 16; if (!(--input_len)) break; /* fall through */ case 15: - dcerpc->dcerpchdr.call_id |= *(p++) << 24; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p++) << 24; if (!(dcerpc->dcerpchdr.packed_drep[0] & 0x10)) { dcerpc->dcerpchdr.frag_length = SCByteSwap16(dcerpc->dcerpchdr.frag_length); dcerpc->dcerpchdr.auth_length = SCByteSwap16(dcerpc->dcerpchdr.auth_length); From 055f8bea105bf0472dd448f93e67db9c80a25c11 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 15:00:10 +0200 Subject: [PATCH 1342/2553] smb: improve integer handling --- src/app-layer-smb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 11c8539e8e3f..22a9439e0918 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -946,10 +946,10 @@ static int SMBParseHeader(Flow *f, void *smb_state, SCReturnInt(-1); } sstate->smb.command = *(p + 4); - sstate->smb.status = *(p + 5) << 24; - sstate->smb.status |= *(p + 6) << 16; - sstate->smb.status |= *(p + 7) << 8; - sstate->smb.status |= *(p + 8); + sstate->smb.status = (uint32_t) *(p + 5) << 24; + sstate->smb.status |= (uint32_t) *(p + 6) << 16; + sstate->smb.status |= (uint32_t) *(p + 7) << 8; + sstate->smb.status |= (uint32_t) *(p + 8); sstate->smb.flags = *(p + 9); sstate->smb.flags2 = *(p + 10) << 8; sstate->smb.flags2 |= *(p + 11); From d79208d93ba9a2171a586c6b4692c32c80d02d60 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 15:04:07 +0200 Subject: [PATCH 1343/2553] tcp sack: fix alignment issues --- src/stream-tcp-sack.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/stream-tcp-sack.c b/src/stream-tcp-sack.c index 7f95d04c4cda..9d0071aac69d 100644 --- a/src/stream-tcp-sack.c +++ b/src/stream-tcp-sack.c @@ -254,8 +254,13 @@ int StreamTcpSackUpdatePacket(TcpStream *stream, Packet *p) { int records = TCP_GET_SACK_CNT(p); int record = 0; + const uint8_t *data = TCP_GET_SACK_PTR(p); - TCPOptSackRecord *sack_rec = (TCPOptSackRecord *)(TCP_GET_SACK_PTR(p)); + if (records == 0 || data == NULL) + return 0; + + TCPOptSackRecord rec[records], *sack_rec = rec; + memcpy(&rec, data, sizeof(TCPOptSackRecord) * records); for (record = 0; record < records; record++) { SCLogDebug("%p last_ack %u, left edge %u, right edge %u", sack_rec, From 542492d6c21c678e726ea34ba4f58c3b4641a277 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 15:09:36 +0200 Subject: [PATCH 1344/2553] yaml: initialize var to prevent uninitialized read --- src/conf-yaml-loader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index 85c65702c993..d73faa88c791 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -167,6 +167,7 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) { ConfNode *node = parent; yaml_event_t event; + memset(&event, 0, sizeof(event)); int done = 0; int state = 0; int seq_idx = 0; From e13f9561006e58724d4b3e52ad34cb596b06138f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 15:09:52 +0200 Subject: [PATCH 1345/2553] yaml: minor cleanup --- src/conf-yaml-loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index d73faa88c791..db5340696675 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -193,8 +193,8 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) fprintf(stderr, "%%YAML 1.1\n---\n\n"); goto fail; } - int major = event.data.document_start.version_directive->major; - int minor = event.data.document_start.version_directive->minor; + int major = ver->major; + int minor = ver->minor; if (!(major == YAML_VERSION_MAJOR && minor == YAML_VERSION_MINOR)) { fprintf(stderr, "ERROR: Invalid YAML version. Must be 1.1\n"); goto fail; From 4875040dcac2e0f4837765268742bafad4c00ff1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 15:10:42 +0200 Subject: [PATCH 1346/2553] pcre: initialize var before use --- src/util-misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-misc.c b/src/util-misc.c index 1643e7e1f2af..53ee0d3dc89b 100644 --- a/src/util-misc.c +++ b/src/util-misc.c @@ -34,7 +34,7 @@ static pcre_extra *parse_regex_study = NULL; void ParseSizeInit(void) { - const char *eb; + const char *eb = NULL; int eo; int opts = 0; From 8db7b70e93f34aa86bd69a7d9fe73ebc9cd89b95 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 15:12:29 +0200 Subject: [PATCH 1347/2553] unittests: don't call memcpy on NULL-ptr --- src/util-unittest-helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util-unittest-helper.c b/src/util-unittest-helper.c index 94756e7a6ccf..dd2c20dc9c08 100644 --- a/src/util-unittest-helper.c +++ b/src/util-unittest-helper.c @@ -233,7 +233,9 @@ Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, /* TODO: Add more protocols */ } - PacketCopyDataOffset(p, hdr_offset, payload, payload_len); + if (payload && payload_len) { + PacketCopyDataOffset(p, hdr_offset, payload, payload_len); + } SET_PKT_LEN(p, hdr_offset + payload_len); p->payload = GET_PKT_DATA(p)+hdr_offset; From 3979cb0e579f901158322f96e8a5931a036932f4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 15:13:21 +0200 Subject: [PATCH 1348/2553] ac-ks: fix integer handling issue --- src/util-mpm-ac-tile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index f2a4713cc0cd..425d22376664 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -759,7 +759,7 @@ static inline void SCACTileInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx if (ctx->pattern_list[ctx->output_table[state].patterns[k]].cs != NULL) { /* TODO - Find better way to store this. */ ctx->output_table[state].patterns[k] &= 0x0FFFFFFF; - ctx->output_table[state].patterns[k] |= 1 << 31; + ctx->output_table[state].patterns[k] |= (uint32_t)1 << 31; } } } From 79c1904ab24ccd8dd34c5847d4302431034633a4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 15:18:57 +0200 Subject: [PATCH 1349/2553] ipv6: fix alignment issue in address to string code --- src/util-print.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/util-print.c b/src/util-print.c index 3e34756c7a0d..5882b1865ebb 100644 --- a/src/util-print.c +++ b/src/util-print.c @@ -237,9 +237,10 @@ void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32 static const char *PrintInetIPv6(const void *src, char *dst, socklen_t size) { - struct in6_addr * insrc = (struct in6_addr *) src; int i; char s_part[6]; + uint16_t x[8]; + memcpy(&x, src, 16); /* current IPv6 format is fixed size */ if (size < 8 * 5) { @@ -248,7 +249,7 @@ static const char *PrintInetIPv6(const void *src, char *dst, socklen_t size) } memset(dst, 0, size); for(i = 0; i < 8; i++) { - snprintf(s_part, 6, "%04x:", htons(insrc->s6_addr16[i])); + snprintf(s_part, sizeof(s_part), "%04x:", htons(x[i])); strlcat(dst, s_part, size); } /* suppress last ':' */ From 271bd045396b618cd52079be17ca083c4931f87e Mon Sep 17 00:00:00 2001 From: DIALLO David Date: Wed, 4 May 2016 09:58:01 +0200 Subject: [PATCH 1350/2553] modbus: fix AddressSanitizer error (segmentation fault) In case of Mask Write register or Write single register request with no data (malformed packet), app-layer-modbus checks response content (data) with the none stored request content. That causes the segmentation fault. Before accessing to request content, app-layer-modbus checks now if content has been previously stored. 4 unitests have been adding, 2 of them to test the management of Mask Write register and Write single register requests, and the 2 others to check invalid Mask Write register and Write single register requests. --- src/app-layer-modbus.c | 452 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 435 insertions(+), 17 deletions(-) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index e55c431bf100..2b1875256089 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -784,13 +784,17 @@ static void ModbusParseWriteResponse(ModbusTransaction *tx, goto error; if (type & MODBUS_TYP_SINGLE) { - /* Outputs/Registers value (2 bytes) */ - if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) - goto end; + /* Check if Outputs/Registers value has been stored */ + if (tx->data != NULL) + { + /* Outputs/Registers value (2 bytes) */ + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; - /* Check with Outputs/Registers from request */ - if (word != tx->data[0]) - goto error; + /* Check with Outputs/Registers from request */ + if (word != tx->data[0]) + goto error; + } } else if (type & MODBUS_TYP_MULTIPLE) { /* Quantity (2 bytes) */ if (ModbusExtractUint16(modbus, &quantity, input, input_len, offset)) @@ -811,20 +815,25 @@ static void ModbusParseWriteResponse(ModbusTransaction *tx, if (quantity != tx->write.quantity) goto error; } else { - /* And_Mask value (2 bytes) */ - if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) - goto end; + /* Check if And_Mask and Or_Mask values have been stored */ + if (tx->data != NULL) + { + /* And_Mask value (2 bytes) */ + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; - /* Check And_Mask value according to the request */ - if (word != tx->data[0]) - goto error; + /* Check And_Mask value according to the request */ + if (word != tx->data[0]) + goto error; - /* And_Or_Mask value (2 bytes) */ - if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + /* And_Or_Mask value (2 bytes) */ + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; - /* Check Or_Mask value according to the request */ - if (word != tx->data[1]) - goto error; + /* Check Or_Mask value according to the request */ + if (word != tx->data[1]) + goto error; + } /* The length of Mask Write Register (code 22) function response is 8 */ /* Modbus Application Protocol Specification V1.1b3 6.16 */ @@ -1529,6 +1538,31 @@ static uint8_t readCoilsErrorRsp[] = {/* Transaction ID */ 0x00, 0x00, /* Function code */ 0x81, /* Exception code */ 0x05}; +/* Modbus Application Protocol Specification V1.1b3 6.6: Write Single register */ +/* Example of a request to write register 2 to 00 03 hex */ +static uint8_t writeSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x06, + /* Register Address */ 0x00, 0x01, + /* Register Value */ 0x00, 0x03}; + +static uint8_t invalidWriteSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x04, + /* Unit ID */ 0x00, + /* Function code */ 0x06, + /* Register Address */ 0x00, 0x01}; + +static uint8_t writeSingleRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x06, + /* Register Address */ 0x00, 0x01, + /* Register Value */ 0x00, 0x03}; + /* Modbus Application Protocol Specification V1.1b3 6.12: Write Multiple registers */ /* Example of a request to write two registers starting at 2 to 00 0A and 01 02 hex */ static uint8_t writeMultipleRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A, @@ -1550,6 +1584,34 @@ static uint8_t writeMultipleRegistersRsp[] = {/* Transaction ID */ 0x00 /* Starting Address */ 0x00, 0x01, /* Quantity of Registers */ 0x00, 0x02}; +/* Modbus Application Protocol Specification V1.1b3 6.16: Mask Write Register */ +/* Example of a request to mask write to register 5 */ +static uint8_t maskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x08, + /* Unit ID */ 0x00, + /* Function code */ 0x16, + /* Reference Address */ 0x00, 0x04, + /* And_Mask */ 0x00, 0xF2, + /* Or_Mask */ 0x00, 0x25}; + +static uint8_t invalidMaskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x16, + /* Reference Address */ 0x00, 0x04, + /* And_Mask */ 0x00, 0xF2}; + +static uint8_t maskWriteRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x08, + /* Unit ID */ 0x00, + /* Function code */ 0x16, + /* Reference Address */ 0x00, 0x04, + /* And_Mask */ 0x00, 0xF2, + /* Or_Mask */ 0x00, 0x25}; + /* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */ /* Example of a request to read six registers starting at register 4, */ /* and to write three registers starting at register 15 */ @@ -2650,6 +2712,354 @@ static int ModbusParserTest12(void) { UTHFreePackets(&p, 1); return result; } + +/** \test Send Modbus Mask Write register request/response. */ +static int ModbusParserTest13(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + maskWriteRegisterReq, sizeof(maskWriteRegisterReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 22) || (tx->data[0] != 0x00F2) || (tx->data[1] != 0x0025)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); + printf("expected And_Mask %" PRIu8 ", got %" PRIu8 ": ", 0x00F2, tx->data[0]); + printf("expected Or_Mask %" PRIu8 ", got %" PRIu8 ": ", 0x0025, tx->data[1]); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + maskWriteRegisterRsp, sizeof(maskWriteRegisterRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send Modbus Write single register request/response. */ +static int ModbusParserTest14(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + writeSingleRegisterReq, sizeof(writeSingleRegisterReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 6) || (tx->write.address != 0x0001) || (tx->data[0] != 0x0003)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %" PRIu8 ", got %" PRIu8 ": ", 0x01, tx->write.address); + printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x03, tx->data[0]); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + writeSingleRegisterRsp, sizeof(writeSingleRegisterRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send invalid Modbus Mask Write register request. */ +static int ModbusParserTest15(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidMaskWriteRegisterReq, + sizeof(invalidMaskWriteRegisterReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if (tx->function != 22) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + maskWriteRegisterRsp, sizeof(maskWriteRegisterRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send invalid Modbus Mask Write register request. */ +static int ModbusParserTest16(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidWriteSingleRegisterReq, sizeof(invalidWriteSingleRegisterReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 6) || (tx->write.address != 0x0001)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %" PRIu8 ", got %" PRIu8 ": ", 0x01, tx->write.address); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + writeSingleRegisterRsp, sizeof(writeSingleRegisterRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} #endif /* UNITTESTS */ void ModbusParserRegisterTests(void) { @@ -2678,5 +3088,13 @@ void ModbusParserRegisterTests(void) { ModbusParserTest11); UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length", ModbusParserTest12); + UtRegisterTest("ModbusParserTest13 - Modbus Mask Write register request", + ModbusParserTest13); + UtRegisterTest("ModbusParserTest14 - Modbus Write single register request", + ModbusParserTest14); + UtRegisterTest("ModbusParserTest15 - Modbus invalid Mask Write register request", + ModbusParserTest15); + UtRegisterTest("ModbusParserTest16 - Modbus invalid Write single register request", + ModbusParserTest16); #endif /* UNITTESTS */ } From 3a36dea358cef2996ae366da53f245f9048039c1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 19 Apr 2016 12:03:35 +0200 Subject: [PATCH 1351/2553] detect: add missing sigorder case --- src/detect-engine-sigorder.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect-engine-sigorder.c b/src/detect-engine-sigorder.c index 9e3d819fbc38..1186636f5eaf 100644 --- a/src/detect-engine-sigorder.c +++ b/src/detect-engine-sigorder.c @@ -199,6 +199,7 @@ static inline int SCSigGetFlowintType(Signature *sig) fi->modifier == FLOWINT_MODIFIER_NE || fi->modifier == FLOWINT_MODIFIER_GE || fi->modifier == FLOWINT_MODIFIER_GT || + fi->modifier == FLOWINT_MODIFIER_NOTSET || fi->modifier == FLOWINT_MODIFIER_ISSET) { read++; } else { From 2c7cd1c22a6618dbc5207e927f3f99636c7fa204 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 19 Apr 2016 11:38:25 +0200 Subject: [PATCH 1352/2553] flowint: redo tests --- src/detect-flowint.c | 1084 ++++++------------------------------------ 1 file changed, 145 insertions(+), 939 deletions(-) diff --git a/src/detect-flowint.c b/src/detect-flowint.c index dff26125cb43..f63ddf4ed5c0 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -35,10 +35,12 @@ #include "util-var-name.h" #include "util-debug.h" #include "util-unittest.h" +#include "util-unittest-helper.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" +#include "detect-engine-sigorder.h" #include "pkt-var.h" #include "host.h" @@ -1101,673 +1103,144 @@ int DetectFlowintTestParseInvalidSyntaxis01(void) */ int DetectFlowintTestPacket01Real() { - int result = 1; - - uint8_t pkt1[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0xc2, 0x26, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x67, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, - 0x16, 0xd0, 0xe8, 0xb0, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x72, - 0x40, 0x93, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt2[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, - 0xb6, 0x8e, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xdd, 0x17, 0x51, 0x82, 0xb6, 0xa0, 0x12, - 0x16, 0x80, 0x17, 0x8a, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xac, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x29, - 0x23, 0x63, 0x01, 0x72, 0x40, 0x93, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt3[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x27, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6e, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x10, - 0x00, 0x2e, 0x5c, 0xa0, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63 - }; - - uint8_t pkt4[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x01, 0x12, 0xc2, 0x28, 0x40, 0x00, 0x40, 0x06, - 0xf3, 0x8f, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x18, - 0x00, 0x2e, 0x24, 0x39, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20, - 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, - 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, - 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, - 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65, 0x78, - 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x20, - 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, - 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x2f, 0x63, 0x73, 0x73, 0x2c, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x2c, - 0x20, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, - 0x2e, 0x30, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, - 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, - 0x69, 0x70, 0x2c, 0x20, 0x62, 0x7a, 0x69, 0x70, - 0x32, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x2d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, - 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x0d, 0x0a, - 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x3a, 0x20, 0x4c, 0x79, 0x6e, 0x78, - 0x2f, 0x32, 0x2e, 0x38, 0x2e, 0x36, 0x72, 0x65, - 0x6c, 0x2e, 0x34, 0x20, 0x6c, 0x69, 0x62, 0x77, - 0x77, 0x77, 0x2d, 0x46, 0x4d, 0x2f, 0x32, 0x2e, - 0x31, 0x34, 0x20, 0x53, 0x53, 0x4c, 0x2d, 0x4d, - 0x4d, 0x2f, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x20, - 0x47, 0x4e, 0x55, 0x54, 0x4c, 0x53, 0x2f, 0x32, - 0x2e, 0x30, 0x2e, 0x34, 0x0d, 0x0a, 0x0d, 0x0a - }; - - uint8_t pkt5[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbd, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd9, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x10, - 0x00, 0x2d, 0x5b, 0xc3, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt6[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x01, 0xe4, 0xa8, 0xbe, 0x40, 0x00, 0x40, 0x06, - 0x0c, 0x28, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x18, - 0x00, 0x2d, 0x1b, 0x84, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, - 0x2e, 0x31, 0x20, 0x34, 0x30, 0x31, 0x20, 0x55, - 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x65, 0x64, 0x0d, 0x0a, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6d, 0x69, 0x63, - 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, - 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, - 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, - 0x65, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, - 0x20, 0x57, 0x65, 0x64, 0x2c, 0x20, 0x31, 0x34, - 0x20, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x30, 0x30, - 0x39, 0x20, 0x31, 0x33, 0x3a, 0x34, 0x39, 0x3a, - 0x35, 0x33, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, - 0x57, 0x57, 0x57, 0x2d, 0x41, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x3a, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, - 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x3d, 0x22, 0x44, - 0x53, 0x4c, 0x20, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x72, 0x22, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, - 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, - 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, - 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, - 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, - 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x34, 0x30, 0x31, - 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, - 0x45, 0x41, 0x44, 0x3e, 0x0a, 0x3c, 0x42, 0x4f, - 0x44, 0x59, 0x20, 0x42, 0x47, 0x43, 0x4f, 0x4c, - 0x4f, 0x52, 0x3d, 0x22, 0x23, 0x63, 0x63, 0x39, - 0x39, 0x39, 0x39, 0x22, 0x3e, 0x3c, 0x48, 0x34, - 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, - 0x64, 0x3c, 0x2f, 0x48, 0x34, 0x3e, 0x0a, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x0a, 0x3c, - 0x48, 0x52, 0x3e, 0x0a, 0x3c, 0x41, 0x44, 0x44, - 0x52, 0x45, 0x53, 0x53, 0x3e, 0x3c, 0x41, 0x20, - 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, - 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, - 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, - 0x72, 0x65, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, - 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x2f, 0x22, - 0x3e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, - 0x74, 0x74, 0x70, 0x64, 0x3c, 0x2f, 0x41, 0x3e, - 0x3c, 0x2f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, - 0x53, 0x3e, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, - 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, - 0x3e, 0x0a - }; - - uint8_t pkt7[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x29, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6c, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8e, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xfa, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x9c, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt8[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbf, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8e, 0x17, 0x51, 0x83, 0x94, 0x80, 0x11, - 0x00, 0x2d, 0x5a, 0x0b, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt9[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2a, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6b, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xef, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0xa6, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt10[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2b, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6a, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x11, - 0x00, 0x36, 0x57, 0x0a, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x43, 0x8a, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt11[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0x10, 0xaf, 0x40, 0x00, 0x40, 0x06, - 0xa5, 0xe7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8f, 0x17, 0x51, 0x83, 0x95, 0x80, 0x10, - 0x00, 0x2d, 0x54, 0xbb, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x25, 0xc2, 0x01, 0x72, - 0x43, 0x8a - }; - - uint8_t *pkts[] = { - pkt1, pkt2, pkt3, pkt4, pkt5, pkt6, pkt7, pkt8, - pkt9, pkt10, pkt11 - }; - - uint16_t pktssizes[] = { - sizeof(pkt1), sizeof(pkt2), sizeof(pkt3), sizeof(pkt4), sizeof(pkt5), - sizeof(pkt6), sizeof(pkt7), sizeof(pkt8), sizeof(pkt9), sizeof(pkt10), - sizeof(pkt11) - }; - - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - DecodeThreadVars dtv; + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - - memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); - FlowInitConfig(FLOW_QUIET); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - /* Now that we have the array of packets for the flow, prepare the signatures */ - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint:myvar,=,1; flowint:maxvar,=,6; sid:101;)"); - - de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint: myvar,+,2; sid:102;)"); - - de_ctx->sig_list->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar,==,3; flowint: cntpackets, =, 0; sid:103;)"); - - de_ctx->sig_list->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: myvar,==,3; flowint: cntpackets, +, 1; noalert;sid:104;)"); - - /* comparation of myvar with maxvar */ - de_ctx->sig_list->next->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, ==, maxvar; sid:105;)"); - - /* I know it's a bit ugly, */ - de_ctx->sig_list->next->next->next->next->next = NULL; - + char *sigs[5]; + sigs[0] = "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint:myvar,=,1; flowint:maxvar,=,6; sid:101;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint: myvar,+,2; sid:102;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar,==,3; flowint: cntpackets, =, 0; sid:103;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: myvar,==,3; flowint: cntpackets, +, 1; noalert;sid:104;)"; + sigs[4] = "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, ==, maxvar; sid:105;)"; + FAIL_IF(UTHAppendSigs(de_ctx, sigs, 5) == 0); + + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); - /* Decode the packets, and test the matches*/ - int i; - for (i = 0;i < 11;i++) { - memset(p, 0, SIZE_OF_PACKET); - PACKET_INITIALIZE(p); - DecodeEthernet(&th_v, &dtv, p, pkts[i], pktssizes[i], NULL); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - switch(i) { - case 3: - if (PacketAlertCheck(p, 101) == 0) { - SCLogDebug("Not declared/initialized!"); - result = 0; - } - break; - case 5: - if (PacketAlertCheck(p, 102) == 0) { - SCLogDebug("Not incremented!"); - result = 0; - } - - if (PacketAlertCheck(p, 103) == 0) { - SCLogDebug("myvar is not 3 or bad cmp!!"); - result = 0; - } - break; - case 10: - if (PacketAlertCheck(p, 105) == 0) { - SCLogDebug("Not declared/initialized/or well incremented the" - " second var!"); - result = 0; - } - break; - } - SCLogDebug("Raw Packet %d has %u alerts ", i, p->alerts.cnt); - PACKET_RECYCLE(p); - } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - + Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", + 41424, 80); + FAIL_IF(f == NULL); + f->proto = IPPROTO_TCP; + + p = UTHBuildPacket((uint8_t *)"GET", 3, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 101)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"Unauthorized", 12, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 102)); + FAIL_IF(!PacketAlertCheck(p, 103)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"1", 1, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"X", 1, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 105)); + UTHFreePacket(p); + + UTHFreeFlow(f); DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); DetectEngineCtxFree(de_ctx); - FlowShutdown(); - - SCFree(p); - return result; -end: - if (de_ctx) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); - if (de_ctx) - DetectEngineCtxFree(de_ctx); - - PACKET_RECYCLE(p); - FlowShutdown(); - SCFree(p); - return result; + PASS; } /** * \test DetectFlowintTestPacket02Real * \brief like DetectFlowintTestPacket01Real but using isset/notset keywords */ -int DetectFlowintTestPacket02Real() +static int DetectFlowintTestPacket02Real() { - int result = 1; - - uint8_t pkt1[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0xc2, 0x26, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x67, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, - 0x16, 0xd0, 0xe8, 0xb0, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x72, - 0x40, 0x93, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt2[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, - 0xb6, 0x8e, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xdd, 0x17, 0x51, 0x82, 0xb6, 0xa0, 0x12, - 0x16, 0x80, 0x17, 0x8a, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xac, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x29, - 0x23, 0x63, 0x01, 0x72, 0x40, 0x93, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt3[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x27, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6e, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x10, - 0x00, 0x2e, 0x5c, 0xa0, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63 - }; - - uint8_t pkt4[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x01, 0x12, 0xc2, 0x28, 0x40, 0x00, 0x40, 0x06, - 0xf3, 0x8f, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x18, - 0x00, 0x2e, 0x24, 0x39, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20, - 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, - 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, - 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, - 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65, 0x78, - 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x20, - 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, - 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x2f, 0x63, 0x73, 0x73, 0x2c, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x2c, - 0x20, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, - 0x2e, 0x30, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, - 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, - 0x69, 0x70, 0x2c, 0x20, 0x62, 0x7a, 0x69, 0x70, - 0x32, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x2d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, - 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x0d, 0x0a, - 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x3a, 0x20, 0x4c, 0x79, 0x6e, 0x78, - 0x2f, 0x32, 0x2e, 0x38, 0x2e, 0x36, 0x72, 0x65, - 0x6c, 0x2e, 0x34, 0x20, 0x6c, 0x69, 0x62, 0x77, - 0x77, 0x77, 0x2d, 0x46, 0x4d, 0x2f, 0x32, 0x2e, - 0x31, 0x34, 0x20, 0x53, 0x53, 0x4c, 0x2d, 0x4d, - 0x4d, 0x2f, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x20, - 0x47, 0x4e, 0x55, 0x54, 0x4c, 0x53, 0x2f, 0x32, - 0x2e, 0x30, 0x2e, 0x34, 0x0d, 0x0a, 0x0d, 0x0a - }; - - uint8_t pkt5[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbd, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd9, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x10, - 0x00, 0x2d, 0x5b, 0xc3, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt6[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x01, 0xe4, 0xa8, 0xbe, 0x40, 0x00, 0x40, 0x06, - 0x0c, 0x28, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x18, - 0x00, 0x2d, 0x1b, 0x84, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, - 0x2e, 0x31, 0x20, 0x34, 0x30, 0x31, 0x20, 0x55, - 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x65, 0x64, 0x0d, 0x0a, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6d, 0x69, 0x63, - 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, - 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, - 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, - 0x65, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, - 0x20, 0x57, 0x65, 0x64, 0x2c, 0x20, 0x31, 0x34, - 0x20, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x30, 0x30, - 0x39, 0x20, 0x31, 0x33, 0x3a, 0x34, 0x39, 0x3a, - 0x35, 0x33, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, - 0x57, 0x57, 0x57, 0x2d, 0x41, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x3a, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, - 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x3d, 0x22, 0x44, - 0x53, 0x4c, 0x20, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x72, 0x22, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, - 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, - 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, - 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, - 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, - 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x34, 0x30, 0x31, - 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, - 0x45, 0x41, 0x44, 0x3e, 0x0a, 0x3c, 0x42, 0x4f, - 0x44, 0x59, 0x20, 0x42, 0x47, 0x43, 0x4f, 0x4c, - 0x4f, 0x52, 0x3d, 0x22, 0x23, 0x63, 0x63, 0x39, - 0x39, 0x39, 0x39, 0x22, 0x3e, 0x3c, 0x48, 0x34, - 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, - 0x64, 0x3c, 0x2f, 0x48, 0x34, 0x3e, 0x0a, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x0a, 0x3c, - 0x48, 0x52, 0x3e, 0x0a, 0x3c, 0x41, 0x44, 0x44, - 0x52, 0x45, 0x53, 0x53, 0x3e, 0x3c, 0x41, 0x20, - 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, - 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, - 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, - 0x72, 0x65, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, - 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x2f, 0x22, - 0x3e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, - 0x74, 0x74, 0x70, 0x64, 0x3c, 0x2f, 0x41, 0x3e, - 0x3c, 0x2f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, - 0x53, 0x3e, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, - 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, - 0x3e, 0x0a - }; - - uint8_t pkt7[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x29, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6c, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8e, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xfa, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x9c, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt8[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbf, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8e, 0x17, 0x51, 0x83, 0x94, 0x80, 0x11, - 0x00, 0x2d, 0x5a, 0x0b, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt9[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2a, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6b, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xef, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0xa6, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt10[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2b, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6a, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x11, - 0x00, 0x36, 0x57, 0x0a, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x43, 0x8a, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt11[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0x10, 0xaf, 0x40, 0x00, 0x40, 0x06, - 0xa5, 0xe7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8f, 0x17, 0x51, 0x83, 0x95, 0x80, 0x10, - 0x00, 0x2d, 0x54, 0xbb, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x25, 0xc2, 0x01, 0x72, - 0x43, 0x8a - }; - - uint8_t *pkts[] = { - pkt1, pkt2, pkt3, pkt4, pkt5, pkt6, pkt7, pkt8, - pkt9, pkt10, pkt11 - }; - - uint16_t pktssizes[] = { - sizeof(pkt1), sizeof(pkt2), sizeof(pkt3), sizeof(pkt4), sizeof(pkt5), - sizeof(pkt6), sizeof(pkt7), sizeof(pkt8), sizeof(pkt9), sizeof(pkt10), - sizeof(pkt11) - }; - - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - DecodeThreadVars dtv; - + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - - memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); - FlowInitConfig(FLOW_QUIET); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - /* Now that we have the array of packets for the flow, prepare the signatures */ - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint: myvar, notset; flowint:maxvar,notset; flowint: myvar,=,1; flowint: maxvar,=,6; sid:101;)"); - - de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: myvar,+,2; sid:102;)"); - - de_ctx->sig_list->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar, isset; flowint: myvar,==,3; flowint:cntpackets,notset; flowint: cntpackets, =, 0; sid:103;)"); - - de_ctx->sig_list->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: cntpackets,isset; flowint: cntpackets, +, 1; noalert;sid:104;)"); - - /* comparation of myvar with maxvar */ - de_ctx->sig_list->next->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, isset; flowint: maxvar,isset; flowint: cntpackets, ==, maxvar; sid:105;)"); - - /* I know it's a bit ugly, */ - de_ctx->sig_list->next->next->next->next->next = NULL; - + char *sigs[5]; + sigs[0] = "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint: myvar, notset; flowint:maxvar,notset; flowint: myvar,=,1; flowint: maxvar,=,6; sid:101;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: myvar,+,2; sid:102;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar, isset; flowint: myvar,==,3; flowint:cntpackets,notset; flowint: cntpackets, =, 0; sid:103;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: cntpackets,isset; flowint: cntpackets, +, 1; noalert;sid:104;)"; + sigs[4] = "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, isset; flowint: maxvar,isset; flowint: cntpackets, ==, maxvar; sid:105;)"; + FAIL_IF(UTHAppendSigs(de_ctx, sigs, 5) == 0); + + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); - int i; - - /* Decode the packets, and test the matches*/ - for (i = 0;i < 11;i++) { - memset(p, 0, SIZE_OF_PACKET); - PACKET_INITIALIZE(p); - DecodeEthernet(&th_v, &dtv, p, pkts[i], pktssizes[i], NULL); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - switch(i) { - case 3: - if (PacketAlertCheck(p, 101) == 0) { - SCLogDebug("Not declared/initialized!"); - result = 0; - } - break; - case 5: - if (PacketAlertCheck(p, 102) == 0) { - SCLogDebug("Not incremented!"); - result = 0; - } - - if (PacketAlertCheck(p, 103) == 0) { - SCLogDebug("myvar is not 3 or bad cmp!!"); - result = 0; - } - break; - case 10: - if (PacketAlertCheck(p, 105) == 0) { - SCLogDebug("Not declared/initialized/or well incremented the" - " second var!"); - result = 0; - } - break; - } - SCLogDebug("Raw Packet %d has %u alerts ", i, p->alerts.cnt); - PACKET_RECYCLE(p); - } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - + Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", + 41424, 80); + FAIL_IF(f == NULL); + f->proto = IPPROTO_TCP; + + p = UTHBuildPacket((uint8_t *)"GET", 3, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 101)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"Unauthorized", 12, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 102)); + FAIL_IF(!PacketAlertCheck(p, 103)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"1", 1, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"X", 1, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 105)); + UTHFreePacket(p); + + UTHFreeFlow(f); DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); - //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); - FlowShutdown(); - - SCFree(p); - return result; -end: - if (de_ctx) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); - //PatternMatchDestroy(mpm_ctx); - if (de_ctx) - DetectEngineCtxFree(de_ctx); - - FlowShutdown(); - SCFree(p); - return result; + PASS; } /** @@ -1776,328 +1249,61 @@ int DetectFlowintTestPacket02Real() */ int DetectFlowintTestPacket03Real() { - int result = 1; - - uint8_t pkt1[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0xc2, 0x26, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x67, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, - 0x16, 0xd0, 0xe8, 0xb0, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x72, - 0x40, 0x93, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt2[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, - 0xb6, 0x8e, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xdd, 0x17, 0x51, 0x82, 0xb6, 0xa0, 0x12, - 0x16, 0x80, 0x17, 0x8a, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xac, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x29, - 0x23, 0x63, 0x01, 0x72, 0x40, 0x93, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt3[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x27, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6e, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x10, - 0x00, 0x2e, 0x5c, 0xa0, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63 - }; - - uint8_t pkt4[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x01, 0x12, 0xc2, 0x28, 0x40, 0x00, 0x40, 0x06, - 0xf3, 0x8f, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x18, - 0x00, 0x2e, 0x24, 0x39, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20, - 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, - 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, - 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, - 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65, 0x78, - 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x20, - 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, - 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x2f, 0x63, 0x73, 0x73, 0x2c, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x2c, - 0x20, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, - 0x2e, 0x30, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, - 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, - 0x69, 0x70, 0x2c, 0x20, 0x62, 0x7a, 0x69, 0x70, - 0x32, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x2d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, - 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x0d, 0x0a, - 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x3a, 0x20, 0x4c, 0x79, 0x6e, 0x78, - 0x2f, 0x32, 0x2e, 0x38, 0x2e, 0x36, 0x72, 0x65, - 0x6c, 0x2e, 0x34, 0x20, 0x6c, 0x69, 0x62, 0x77, - 0x77, 0x77, 0x2d, 0x46, 0x4d, 0x2f, 0x32, 0x2e, - 0x31, 0x34, 0x20, 0x53, 0x53, 0x4c, 0x2d, 0x4d, - 0x4d, 0x2f, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x20, - 0x47, 0x4e, 0x55, 0x54, 0x4c, 0x53, 0x2f, 0x32, - 0x2e, 0x30, 0x2e, 0x34, 0x0d, 0x0a, 0x0d, 0x0a - }; - - uint8_t pkt5[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbd, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd9, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x10, - 0x00, 0x2d, 0x5b, 0xc3, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt6[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x01, 0xe4, 0xa8, 0xbe, 0x40, 0x00, 0x40, 0x06, - 0x0c, 0x28, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x18, - 0x00, 0x2d, 0x1b, 0x84, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, - 0x2e, 0x31, 0x20, 0x34, 0x30, 0x31, 0x20, 0x55, - 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x65, 0x64, 0x0d, 0x0a, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6d, 0x69, 0x63, - 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, - 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, - 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, - 0x65, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, - 0x20, 0x57, 0x65, 0x64, 0x2c, 0x20, 0x31, 0x34, - 0x20, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x30, 0x30, - 0x39, 0x20, 0x31, 0x33, 0x3a, 0x34, 0x39, 0x3a, - 0x35, 0x33, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, - 0x57, 0x57, 0x57, 0x2d, 0x41, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x3a, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, - 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x3d, 0x22, 0x44, - 0x53, 0x4c, 0x20, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x72, 0x22, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, - 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, - 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, - 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, - 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, - 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x34, 0x30, 0x31, - 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, - 0x45, 0x41, 0x44, 0x3e, 0x0a, 0x3c, 0x42, 0x4f, - 0x44, 0x59, 0x20, 0x42, 0x47, 0x43, 0x4f, 0x4c, - 0x4f, 0x52, 0x3d, 0x22, 0x23, 0x63, 0x63, 0x39, - 0x39, 0x39, 0x39, 0x22, 0x3e, 0x3c, 0x48, 0x34, - 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, - 0x64, 0x3c, 0x2f, 0x48, 0x34, 0x3e, 0x0a, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x0a, 0x3c, - 0x48, 0x52, 0x3e, 0x0a, 0x3c, 0x41, 0x44, 0x44, - 0x52, 0x45, 0x53, 0x53, 0x3e, 0x3c, 0x41, 0x20, - 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, - 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, - 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, - 0x72, 0x65, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, - 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x2f, 0x22, - 0x3e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, - 0x74, 0x74, 0x70, 0x64, 0x3c, 0x2f, 0x41, 0x3e, - 0x3c, 0x2f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, - 0x53, 0x3e, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, - 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, - 0x3e, 0x0a - }; - - uint8_t pkt7[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x29, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6c, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8e, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xfa, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x9c, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt8[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbf, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8e, 0x17, 0x51, 0x83, 0x94, 0x80, 0x11, - 0x00, 0x2d, 0x5a, 0x0b, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt9[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2a, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6b, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xef, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0xa6, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt10[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2b, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6a, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x11, - 0x00, 0x36, 0x57, 0x0a, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x43, 0x8a, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt11[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0x10, 0xaf, 0x40, 0x00, 0x40, 0x06, - 0xa5, 0xe7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8f, 0x17, 0x51, 0x83, 0x95, 0x80, 0x10, - 0x00, 0x2d, 0x54, 0xbb, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x25, 0xc2, 0x01, 0x72, - 0x43, 0x8a - }; - - uint8_t *pkts[] = { - pkt1, pkt2, pkt3, pkt4, pkt5, pkt6, pkt7, pkt8, - pkt9, pkt10, pkt11 - }; - - uint16_t pktssizes[] = { - sizeof(pkt1), sizeof(pkt2), sizeof(pkt3), sizeof(pkt4), sizeof(pkt5), - sizeof(pkt6), sizeof(pkt7), sizeof(pkt8), sizeof(pkt9), sizeof(pkt10), - sizeof(pkt11) - }; - - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - DecodeThreadVars dtv; - + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - - memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); - FlowInitConfig(FLOW_QUIET); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - /* Now that we have the array of packets for the flow, prepare the signatures */ - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"check notset\"; content:\"GET\"; flowint: myvar, notset; flowint: myvar,=,0; flowint: other,=,10; sid:101;)"); - - de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"check isset\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: other,isset; sid:102;)"); - - de_ctx->sig_list->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"check notset\"; content:\"Unauthorized\"; flowint:lala,isset; sid:103;)"); - - de_ctx->sig_list->next->next->next = NULL; + char *sigs[3]; + sigs[0] = "alert tcp any any -> any any (msg:\"check notset\"; content:\"GET\"; flowint: myvar, notset; flowint: myvar,=,0; flowint: other,=,10; sid:101;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"check isset\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: other,isset; sid:102;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"check notset\"; content:\"Unauthorized\"; flowint:lala,isset; sid:103;)"; + FAIL_IF(UTHAppendSigs(de_ctx, sigs, 3) == 0); + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); - int i; - - /* Decode the packets, and test the matches*/ - for (i = 0;i < 11;i++) { - memset(p, 0, SIZE_OF_PACKET); - PACKET_INITIALIZE(p); - DecodeEthernet(&th_v, &dtv, p, pkts[i], pktssizes[i], NULL); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - switch(i) { - case 3: - if (PacketAlertCheck(p, 101) == 0) { - SCLogDebug("Not declared/initialized but match!"); - result = 0; - } - if (PacketAlertCheck(p, 103) != 0) { - SCLogDebug(" var lala is never set, it should NOT match!!"); - result = 0; - } - break; - case 5: - if (PacketAlertCheck(p, 102) == 0) { - SCLogDebug("Not incremented!"); - result = 0; - } - - if (PacketAlertCheck(p, 103) != 0) { - SCLogDebug(" var lala is never set, it should NOT match!!"); - result = 0; - } - break; - } - SCLogDebug("Raw Packet %d has %u alerts ", i, p->alerts.cnt); - PACKET_RECYCLE(p); - } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - + Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", + 41424, 80); + FAIL_IF(f == NULL); + f->proto = IPPROTO_TCP; + + p = UTHBuildPacket((uint8_t *)"GET", 3, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 101)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"Unauthorized", 12, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 102)); + FAIL_IF(PacketAlertCheck(p, 103)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"1", 1, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(PacketAlertCheck(p, 102)); + FAIL_IF(PacketAlertCheck(p, 103)); + UTHFreePacket(p); + + UTHFreeFlow(f); DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); - //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); - FlowShutdown(); - - SCFree(p); - return result; - -end: - if (de_ctx) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); - //PatternMatchDestroy(mpm_ctx); - if (de_ctx) - DetectEngineCtxFree(de_ctx); - FlowShutdown(); - SCFree(p); - return result; + PASS; } #endif /* UNITTESTS */ From ba64069b3562a656490e03a302e914dd3229b1b5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 18 Apr 2016 16:26:18 +0200 Subject: [PATCH 1353/2553] flow: remove unused debug code --- src/flow-hash.c | 108 --------------------------------------------- src/flow-hash.h | 13 ------ src/flow-manager.c | 10 ----- 3 files changed, 131 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index c17e6e4f0973..f6d746630c2a 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -55,101 +55,6 @@ SC_ATOMIC_EXTERN(unsigned int, flow_flags); static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv); static int handle_tcp_reuse = 1; -#ifdef FLOW_DEBUG_STATS -#define FLOW_DEBUG_STATS_PROTO_ALL 0 -#define FLOW_DEBUG_STATS_PROTO_TCP 1 -#define FLOW_DEBUG_STATS_PROTO_UDP 2 -#define FLOW_DEBUG_STATS_PROTO_ICMP 3 -#define FLOW_DEBUG_STATS_PROTO_OTHER 4 - -static uint64_t flow_hash_count[5] = { 0, 0, 0, 0, 0 }; /* how often are we looking for a hash */ -static uint64_t flow_hash_loop_count[5] = { 0, 0, 0, 0, 0 }; /* how often do we loop through a hash bucket */ -static FILE *flow_hash_count_fp = NULL; -static SCSpinlock flow_hash_count_lock; - -#define FlowHashCountUpdate do { \ - SCSpinLock(&flow_hash_count_lock); \ - flow_hash_count[FLOW_DEBUG_STATS_PROTO_ALL]++; \ - flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ALL] += _flow_hash_counter; \ - if (f != NULL) { \ - if (p->proto == IPPROTO_TCP) { \ - flow_hash_count[FLOW_DEBUG_STATS_PROTO_TCP]++; \ - flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP] += _flow_hash_counter; \ - } else if (p->proto == IPPROTO_UDP) {\ - flow_hash_count[FLOW_DEBUG_STATS_PROTO_UDP]++; \ - flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_UDP] += _flow_hash_counter; \ - } else if (p->proto == IPPROTO_ICMP) {\ - flow_hash_count[FLOW_DEBUG_STATS_PROTO_ICMP]++; \ - flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ICMP] += _flow_hash_counter; \ - } else {\ - flow_hash_count[FLOW_DEBUG_STATS_PROTO_OTHER]++; \ - flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_OTHER] += _flow_hash_counter; \ - } \ - } \ - SCSpinUnlock(&flow_hash_count_lock); \ -} while(0); - -#define FlowHashCountInit uint64_t _flow_hash_counter = 0 -#define FlowHashCountIncr _flow_hash_counter++; - -void FlowHashDebugInit(void) -{ -#ifdef FLOW_DEBUG_STATS - SCSpinInit(&flow_hash_count_lock, 0); -#endif - flow_hash_count_fp = fopen("flow-debug.log", "w+"); - if (flow_hash_count_fp != NULL) { - fprintf(flow_hash_count_fp, "ts,all,tcp,udp,icmp,other\n"); - } -} - -void FlowHashDebugPrint(uint32_t ts) -{ -#ifdef FLOW_DEBUG_STATS - if (flow_hash_count_fp == NULL) - return; - - float avg_all = 0, avg_tcp = 0, avg_udp = 0, avg_icmp = 0, avg_other = 0; - SCSpinLock(&flow_hash_count_lock); - if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ALL] != 0) - avg_all = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ALL]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_ALL])); - if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP] != 0) - avg_tcp = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_TCP])); - if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_UDP] != 0) - avg_udp = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_UDP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_UDP])); - if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ICMP] != 0) - avg_icmp= (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ICMP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_ICMP])); - if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_OTHER] != 0) - avg_other= (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_OTHER]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_OTHER])); - fprintf(flow_hash_count_fp, "%"PRIu32",%02.3f,%02.3f,%02.3f,%02.3f,%02.3f\n", ts, avg_all, avg_tcp, avg_udp, avg_icmp, avg_other); - fflush(flow_hash_count_fp); - memset(&flow_hash_count, 0, sizeof(flow_hash_count)); - memset(&flow_hash_loop_count, 0, sizeof(flow_hash_loop_count)); - SCSpinUnlock(&flow_hash_count_lock); -#endif -} - -void FlowHashDebugDeinit(void) -{ -#ifdef FLOW_DEBUG_STATS - struct timeval ts; - memset(&ts, 0, sizeof(ts)); - TimeGet(&ts); - FlowHashDebugPrint((uint32_t)ts.tv_sec); - if (flow_hash_count_fp != NULL) - fclose(flow_hash_count_fp); - SCSpinDestroy(&flow_hash_count_lock); -#endif -} - -#else - -#define FlowHashCountUpdate -#define FlowHashCountInit -#define FlowHashCountIncr - -#endif /* FLOW_DEBUG_STATS */ - void FlowDisableTcpReuseHandling(void) { handle_tcp_reuse = 0; @@ -582,8 +487,6 @@ Flow *FlowLookupFlowFromHash(const Packet *p) /* see if this is the flow we are looking for */ if (FlowCompare(f, p) == 0) { while (f) { - FlowHashCountIncr; - f = f->hnext; if (f == NULL) { @@ -649,7 +552,6 @@ Flow *FlowLookupFlowFromHash(const Packet *p) Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) { Flow *f = NULL; - FlowHashCountInit; /* get the key to our bucket */ uint32_t hash = FlowGetHash(p); @@ -659,14 +561,11 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p SCLogDebug("fb %p fb->head %p", fb, fb->head); - FlowHashCountIncr; - /* see if the bucket already has a flow */ if (fb->head == NULL) { f = FlowGetNew(tv, dtv, p); if (f == NULL) { FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return NULL; } @@ -683,7 +582,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p COPY_TIMESTAMP(&p->ts,&f->lastts); FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return f; } @@ -695,8 +593,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p Flow *pf = NULL; /* previous flow */ while (f) { - FlowHashCountIncr; - pf = f; f = f->hnext; @@ -704,7 +600,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p f = pf->hnext = FlowGetNew(tv, dtv, p); if (f == NULL) { FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return NULL; } fb->tail = f; @@ -722,7 +617,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p COPY_TIMESTAMP(&p->ts,&f->lastts); FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return f; } @@ -750,7 +644,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p COPY_TIMESTAMP(&p->ts,&f->lastts); FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return f; } } @@ -762,7 +655,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p COPY_TIMESTAMP(&p->ts,&f->lastts); FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return f; } diff --git a/src/flow-hash.h b/src/flow-hash.h index 4272896b5a62..16d408521b54 100644 --- a/src/flow-hash.h +++ b/src/flow-hash.h @@ -72,18 +72,5 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *) void FlowDisableTcpReuseHandling(void); -/** enable to print stats on hash lookups in flow-debug.log */ -//#define FLOW_DEBUG_STATS - -#ifdef FLOW_DEBUG_STATS -void FlowHashDebugInit(void); -void FlowHashDebugDeinit(void); -void FlowHashDebugPrint(uint32_t); -#else -#define FlowHashDebugInit(...) -#define FlowHashDebugPrint(...) -#define FlowHashDebugDeinit(...) -#endif - #endif /* __FLOW_HASH_H__ */ diff --git a/src/flow-manager.c b/src/flow-manager.c index aa13e7225f12..31e907d3f92c 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -573,7 +573,6 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) uint32_t established_cnt = 0, new_cnt = 0, closing_cnt = 0; int emerg = FALSE; int prev_emerg = FALSE; - uint32_t last_sec = 0; struct timespec cond_time; int flow_update_delay_sec = FLOW_NORMAL_MODE_UPDATE_DELAY_SEC; int flow_update_delay_nsec = FLOW_NORMAL_MODE_UPDATE_DELAY_NSEC; @@ -585,8 +584,6 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) */ memset(&ts, 0, sizeof(ts)); - FlowHashDebugInit(); - while (1) { if (TmThreadsCheckFlag(th_v, THV_PAUSE)) { @@ -612,11 +609,6 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) TimeGet(&ts); SCLogDebug("ts %" PRIdMAX "", (intmax_t)ts.tv_sec); - if (((uint32_t)ts.tv_sec - last_sec) > 600) { - FlowHashDebugPrint((uint32_t)ts.tv_sec); - last_sec = (uint32_t)ts.tv_sec; - } - /* see if we still have enough spare flows */ if (ftd->instance == 1) FlowUpdateSpareFlows(); @@ -696,8 +688,6 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) StatsSyncCountersIfSignalled(th_v); } - FlowHashDebugDeinit(); - SCLogInfo("%" PRIu32 " new flows, %" PRIu32 " established flows were " "timed out, %"PRIu32" flows in closed state", new_cnt, established_cnt, closing_cnt); From be714a2f0218ad501a86f0a3b7dd029cccd9bc39 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 Mar 2015 11:24:26 +0100 Subject: [PATCH 1354/2553] flow queue handler: use int16_t Use int16_t instead of int to store the autofp queue id. We should not easily get to 32k threads so 2 bytes per flow is sufficient. --- src/stream-tcp.c | 2 +- src/tmqh-flow.c | 9 ++++----- src/tmqh-flow.h | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 875a9d6f3e4c..b83d45c33644 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4907,7 +4907,7 @@ static void TcpSessionReuseHandle(Packet *p) { /* get some settings that we move over to the new flow */ FlowThreadId thread_id = old_f->thread_id; - int autofp_tmqh_flow_qid = SC_ATOMIC_GET(old_f->autofp_tmqh_flow_qid); + int16_t autofp_tmqh_flow_qid = SC_ATOMIC_GET(old_f->autofp_tmqh_flow_qid); /* disconnect the packet from the old flow */ FlowHandlePacketUpdateRemove(p->flow, p); diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index 29b8a6ad98d6..5a6b40c9f58f 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -289,13 +289,12 @@ void TmqhOutputFlowActivePackets(ThreadVars *tv, Packet *p) TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; - /* if no flow we use the first queue, - * should be rare */ + /* if no flow we round robin the packets over the queues */ if (p->flow != NULL) { qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); if (qid == -1) { - uint16_t i = 0; - int lowest_id = 0; + int16_t i = 0; + int16_t lowest_id = 0; TmqhFlowMode *queues = ctx->queues; uint32_t lowest = queues[i].q->len; for (i = 1; i < ctx->size; i++) { @@ -350,7 +349,7 @@ void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) addr >>= 7; /* we don't have to worry about possible overflow, since - * ctx->size will be lesser than 2 ** 31 for sure */ + * ctx->size will be less than 2 ** 15 for sure */ qid = addr % ctx->size; (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, qid); (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); diff --git a/src/tmqh-flow.h b/src/tmqh-flow.h index 1206a05c13e5..e710ffeca468 100644 --- a/src/tmqh-flow.h +++ b/src/tmqh-flow.h @@ -39,7 +39,7 @@ typedef struct TmqhFlowCtx_ { TmqhFlowMode *queues; - SC_ATOMIC_DECLARE(uint16_t, round_robin_idx); + SC_ATOMIC_DECLARE(int16_t, round_robin_idx); } TmqhFlowCtx; void TmqhFlowRegister (void); From 8dc477f85aead004447effaad6de8e9411bc1cc7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 10 May 2016 08:50:37 +0200 Subject: [PATCH 1355/2553] sources: fix netmap compilation and pcap setup --- src/runmode-netmap.c | 2 +- src/runmode-pcap.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 6ddad0439197..5d76e417d2f7 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -159,7 +159,7 @@ static void *ParseNetmapConfig(const char *iface_name) return aconf; } - if_root = ConfFindDeviceConfig(netmap_node, "interface", aconf->iface_name); + if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name); if_default = ConfFindDeviceConfig(netmap_node, "default"); diff --git a/src/runmode-pcap.c b/src/runmode-pcap.c index c2d806fff93a..bcd8358ece6a 100644 --- a/src/runmode-pcap.c +++ b/src/runmode-pcap.c @@ -121,7 +121,7 @@ void *ParsePcapConfig(const char *iface) return aconf; } - if_root = ConfFindDeviceConfig(pcap_node, "iface"); + if_root = ConfFindDeviceConfig(pcap_node, iface); if_default = ConfFindDeviceConfig(pcap_node, "default"); From a422ae9f3c0cc029f7d4982652f8cb08a9c2d8ab Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 12 May 2016 11:54:05 +0200 Subject: [PATCH 1356/2553] tls-sni: fix alignment issues --- src/app-layer-ssl.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 44b4f579290b..952663f9b045 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -167,7 +167,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, goto end; /* skip cipher suites */ - uint16_t cipher_suites_length = ntohs(*(uint16_t *)input); + uint16_t cipher_suites_length = input[0] << 8 | input[1]; input += 2; input += cipher_suites_length; @@ -183,7 +183,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, if (!(HAS_SPACE(2))) goto end; - uint16_t extensions_len = ntohs(*(uint16_t *)input); + uint16_t extensions_len = input[0] << 8 | input[1]; input += 2; uint16_t processed_len = 0; @@ -192,16 +192,15 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, if (!(HAS_SPACE(2))) goto end; - uint16_t ext_type = ntohs(*(uint16_t *)input); + uint16_t ext_type = input[0] << 8 | input[1]; input += 2; if (!(HAS_SPACE(2))) goto end; - uint16_t ext_len = ntohs(*(uint16_t *)input); + uint16_t ext_len = input[0] << 8 | input[1]; input += 2; - switch (ext_type) { case SSL_EXTENSION_SNI: { @@ -234,7 +233,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, if (!(HAS_SPACE(2))) goto end; - uint16_t sni_len = ntohs(*(uint16_t *)input); + uint16_t sni_len = input[0] << 8 | input[1]; input += 2; if (!(HAS_SPACE(sni_len))) From e4f03b18bacb7e4bfe295672d393d6a00912010d Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 13 Apr 2016 08:28:16 +0200 Subject: [PATCH 1357/2553] tls: make TX aware --- src/app-layer-ssl.c | 211 +++++++++++++++++++++++++--------- src/app-layer-ssl.h | 24 +++- src/app-layer-tls-handshake.c | 20 ++-- src/detect.c | 4 + 4 files changed, 193 insertions(+), 66 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 952663f9b045..6869614d41be 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -133,6 +133,87 @@ static void SSLParserReset(SSLState *ssl_state) ssl_state->curr_connp->bytes_processed = 0; } +void SSLSetEvent(SSLState *ssl_state, uint8_t event) +{ + if (ssl_state == NULL) { + SCLogDebug("Could not set decoder event: %u", event); + return; + } + + AppLayerDecoderEventsSetEventRaw(&ssl_state->decoder_events, event); + ssl_state->events++; +} + +AppLayerDecoderEvents *SSLGetEvents(void *state, uint64_t id) +{ + SSLState *ssl_state = (SSLState *)state; + return ssl_state->decoder_events; +} + +int SSLHasEvents(void *state) +{ + SSLState *ssl_state = (SSLState *)state; + return (ssl_state->events > 0); +} + +int SSLStateHasTxDetectState(void *state) +{ + SSLState *ssl_state = (SSLState *)state; + if (ssl_state->de_state) + return 1; + + return 0; +} + +int SSLSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + SSLState *ssl_state = (SSLState *)state; + ssl_state->de_state = de_state; + return 0; +} + +DetectEngineState *SSLGetTxDetectState(void *vtx) +{ + SSLState *ssl_state = (SSLState *)vtx; + return ssl_state->de_state; +} + +void *SSLGetTx(void *state, uint64_t tx_id) +{ + SSLState *ssl_state = (SSLState *)state; + return ssl_state; +} + +uint64_t SSLGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +int SSLGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return TLS_STATE_FINISHED; +} + +int SSLGetAlstateProgress(void *tx, uint8_t direction) +{ + SSLState *ssl_state = (SSLState *)tx; + + /* we don't care about direction, only that app-layer parser is done + and have sent an EOF */ + if (ssl_state->flags & SSL_AL_FLAG_STATE_FINISHED) { + return TLS_STATE_FINISHED; + } + + /* we want the logger to log when the handshake is done, even if the + state is not finished */ + if (ssl_state->flags & SSL_AL_FLAG_HANDSHAKE_DONE) { + return TLS_HANDSHAKE_DONE; + } + + return TLS_STATE_IN_PROGRESS; +} + static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, uint32_t input_len) { @@ -208,7 +289,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, type (RFC5246 section 7.4.1.4) */ if (ssl_state->curr_connp->sni) { SCLogDebug("Multiple SNI extensions"); - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS); return -1; } @@ -225,7 +306,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, (RFC6066 section 3) */ if (sni_type != SSL_SNI_TYPE_HOST_NAME) { SCLogDebug("Unknown SNI type"); - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SNI_TYPE); return -1; } @@ -244,7 +325,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, name length */ if (sni_len > 255) { SCLogDebug("SNI length >255"); - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SNI_LENGTH); return -1; } @@ -321,7 +402,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } @@ -346,7 +427,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, while we expect only the number of bytes parsed bytes from the _current_ fragment */ if (write_len < (ssl_state->curr_connp->trec_pos - rc)) { - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } @@ -379,8 +460,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, SCLogDebug("new session ticket"); break; default: - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } @@ -389,8 +469,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, ssl_state->curr_connp->record_length + (SSLV3_RECORD_HDR_LEN)) { if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } write_len = (ssl_state->curr_connp->record_length + @@ -403,8 +482,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, ssl_state->curr_connp->message_length) { if (ssl_state->curr_connp->message_length < ssl_state->curr_connp->trec_pos) { - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } parsed += ssl_state->curr_connp->message_length - @@ -519,8 +597,7 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input, if (!(ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { if (!(hb_type == TLS_HB_REQUEST || hb_type == TLS_HB_RESPONSE)) { - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_HEARTBEAT); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; } } @@ -552,8 +629,7 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input, the record (CVE-2014-0160) */ if ((uint32_t)(payload_len+3) > ssl_state->curr_connp->record_length) { SCLogDebug("We have a short record in HeartBeat Request"); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT); return -1; } @@ -562,8 +638,7 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input, padding_len = ssl_state->curr_connp->record_length - payload_len - 3; if (padding_len < 16) { SCLogDebug("We have a short record in HeartBeat Request"); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_HEARTBEAT); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; } @@ -577,15 +652,13 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input, } else if (direction == 1 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && (ssl_state->flags & SSL_AL_FLAG_HB_SERVER_INIT)) { SCLogDebug("Multiple in-flight server initiated HeartBeats"); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_HEARTBEAT); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; } else if (direction == 0 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && (ssl_state->flags & SSL_AL_FLAG_HB_CLIENT_INIT)) { SCLogDebug("Multiple in-flight client initiated HeartBeats"); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_HEARTBEAT); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; } else { @@ -604,7 +677,7 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input, ssl_state->curr_connp->record_length) { SCLogDebug("My heart is bleeding.. OpenSSL HeartBleed response (%u)", ssl_state->hb_record_len); - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH); ssl_state->hb_record_len = 0; return -1; @@ -783,8 +856,7 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, (ssl_state->curr_connp->record_lengths_length + 1)) { retval = SSLv2ParseRecord(direction, ssl_state, input, input_len); if (retval == -1) { - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); return -1; } else { input += retval; @@ -799,16 +871,14 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, /* record_length should never be zero */ if (ssl_state->curr_connp->record_length == 0) { SCLogDebug("SSLv2 record length is zero"); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); return -1; } /* record_lenghts_length should never be zero */ if (ssl_state->curr_connp->record_lengths_length == 0) { SCLogDebug("SSLv2 record lengths length is zero"); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); return -1; } @@ -816,8 +886,7 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, case SSLV2_MT_ERROR: SCLogDebug("SSLV2_MT_ERROR msg_type received. Error encountered " "in establishing the sslv2 session, may be version"); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED); break; @@ -1038,8 +1107,7 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, if (ssl_state->curr_connp->bytes_processed < SSLV3_RECORD_HDR_LEN) { retval = SSLv3ParseRecord(direction, ssl_state, input, input_len); if (retval < 0) { - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_TLS_HEADER); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_TLS_HEADER); return -1; } else { parsed += retval; @@ -1055,16 +1123,14 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, if (ssl_state->curr_connp->version < SSL_VERSION_3 || ssl_state->curr_connp->version > TLS_VERSION_12) { - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_RECORD_VERSION); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_VERSION); return -1; } /* record_length should never be zero */ if (ssl_state->curr_connp->record_length == 0) { SCLogDebug("SSLv3 Record length is 0"); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_TLS_HEADER); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_TLS_HEADER); return -1; } @@ -1096,6 +1162,10 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD); } + /* if we see (encrypted) aplication data, then this means the + handshake must be done */ + ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; + break; case SSLV3_HANDSHAKE_PROTOCOL: @@ -1104,16 +1174,15 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, if (ssl_state->curr_connp->record_length < 4) { SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } retval = SSLv3ParseHandshakeProtocol(ssl_state, input + parsed, input_len); if (retval < 0) { - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE); - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { @@ -1121,7 +1190,7 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, SCLogDebug("Error parsing SSLv3.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } @@ -1152,10 +1221,8 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, default: /* \todo fix the event from invalid rule to unknown rule */ - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_RECORD_TYPE); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_TYPE); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } @@ -1164,8 +1231,7 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { /* defensive checks. Something is wrong. */ - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } @@ -1222,6 +1288,8 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + /* flag session as finished if APP_LAYER_PARSER_EOF is set */ + ssl_state->flags |= SSL_AL_FLAG_STATE_FINISHED; SCReturnInt(1); } else if (input == NULL || input_len == 0) { SCReturnInt(-1); @@ -1238,8 +1306,7 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt SCLogDebug("Looks like we have looped quite a bit. Reset state " "and get out of here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } @@ -1258,7 +1325,7 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt SCLogDebug("Error parsing SSLv2.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { @@ -1276,7 +1343,7 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt SCLogDebug("Error parsing SSLv3.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { @@ -1339,6 +1406,15 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt } /* switch (ssl_state->curr_connp->bytes_processed) */ } /* while (input_len) */ + /* mark handshake as done if we have subject and issuer */ + if (ssl_state->server_connp.cert0_subject && + ssl_state->server_connp.cert0_issuerdn) + ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; + + /* flag session as finished if APP_LAYER_PARSER_EOF is set */ + if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) + ssl_state->flags |= SSL_AL_FLAG_STATE_FINISHED; + return 1; } @@ -1404,6 +1480,12 @@ void SSLStateFree(void *p) if (ssl_state->server_connp.sni) SCFree(ssl_state->server_connp.sni); + AppLayerDecoderEventsFreeEvents(&ssl_state->decoder_events); + + if (ssl_state->de_state != NULL) { + DetectEngineStateFree(ssl_state->de_state); + } + /* Free certificate chain */ while ((item = TAILQ_FIRST(&ssl_state->server_connp.certs))) { TAILQ_REMOVE(&ssl_state->server_connp.certs, item, next); @@ -1416,6 +1498,11 @@ void SSLStateFree(void *p) return; } +void SSLStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + static uint16_t SSLProbingParser(uint8_t *input, uint32_t ilen, uint32_t *offset) { /* probably a rst/fin sending an eof */ @@ -1442,7 +1529,7 @@ int SSLStateGetEventInfo(const char *event_name, return -1; } - *event_type = APP_LAYER_EVENT_TYPE_GENERAL; + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; return 0; } @@ -1631,11 +1718,31 @@ void RegisterSSLParsers(void) AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TLS, STREAM_TOCLIENT, SSLParseServerRecord); + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TLS, SSLStateGetEventInfo); AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TLS, SSLStateAlloc, SSLStateFree); + AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_TLS, STREAM_TOSERVER); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TLS, SSLStateTransactionFree); + + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetEvents); + + AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_TLS, SSLHasEvents); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_TLS, SSLStateHasTxDetectState, + SSLGetTxDetectState, SSLSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TLS, SSLGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TLS, SSLGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetAlstateProgress); + + AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_TLS, + SSLGetAlstateProgressCompletionStatus); + /* Get the value of no reassembly option from the config file */ if (ConfGetNode("app-layer.protocols.tls.no-reassemble") == NULL) { if (ConfGetBool("tls.no-reassemble", &ssl_config.no_reassemble) != 1) diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index b38035254ee9..12f76219a8ed 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -26,6 +26,8 @@ #ifndef __APP_LAYER_SSL_H__ #define __APP_LAYER_SSL_H__ +#include "app-layer-protos.h" +#include "app-layer-parser.h" #include "decode-events.h" #include "queue.h" @@ -53,6 +55,12 @@ enum { TLS_DECODER_EVENT_INVALID_SSL_RECORD, }; +enum { + TLS_STATE_IN_PROGRESS = 0, + TLS_HANDSHAKE_DONE = 1, + TLS_STATE_FINISHED = 2 +}; + /* Flag to indicate that server will now on send encrypted msgs */ #define SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC 0x0001 /* Flag to indicate that client will now on send encrypted msgs */ @@ -76,11 +84,17 @@ enum { #define SSL_AL_FLAG_STATE_LOGGED 0x4000 +/* flag to indicate that session is finished */ +#define SSL_AL_FLAG_STATE_FINISHED 0x4000 + /* flags specific to HeartBeat state */ #define SSL_AL_FLAG_HB_INFLIGHT 0x8000 #define SSL_AL_FLAG_HB_CLIENT_INIT 0x10000 #define SSL_AL_FLAG_HB_SERVER_INIT 0x20000 +/* flag to indicate that handshake is done */ +#define SSL_AL_FLAG_HANDSHAKE_DONE 0x80000 + /* flags for file storage */ #define SSL_AL_FLAG_STATE_STORED 0x40000 @@ -169,16 +183,22 @@ typedef struct SSLState_ { /* holds some state flags we need */ uint32_t flags; + /* there might be a better place to store this*/ + uint16_t hb_record_len; + + uint16_t events; + SSLStateConnp *curr_connp; SSLStateConnp client_connp; SSLStateConnp server_connp; - /* there might be a better place to store this*/ - uint16_t hb_record_len; + DetectEngineState *de_state; + AppLayerDecoderEvents *decoder_events; } SSLState; void RegisterSSLParsers(void); void SSLParserRegisterTests(void); +void SSLSetEvent(SSLState *ssl_state, uint8_t event); #endif /* __APP_LAYER_SSL_H__ */ diff --git a/src/app-layer-tls-handshake.c b/src/app-layer-tls-handshake.c index 9f034016cb46..c95fd4373a05 100644 --- a/src/app-layer-tls-handshake.c +++ b/src/app-layer-tls-handshake.c @@ -58,25 +58,24 @@ static void TLSCertificateErrCodeToWarning(SSLState *ssl_state, switch (errcode) { case ERR_DER_ELEMENT_SIZE_TOO_BIG: case ERR_DER_INVALID_SIZE: - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH); break; case ERR_DER_UNSUPPORTED_STRING: - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_STRING); break; case ERR_DER_UNKNOWN_ELEMENT: - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_UNKNOWN_ELEMENT); break; case ERR_DER_MISSING_ELEMENT: - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT); break; case ERR_DER_GENERIC: default: - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_CERTIFICATE); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); break; }; } @@ -108,8 +107,7 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, i = 0; while (certificates_length > 0) { if ((uint32_t)(input + 3 - start_data) > (uint32_t)input_len) { - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_CERTIFICATE); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); return -1; } @@ -119,14 +117,12 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, /* current certificate length should be greater than zero */ if (cur_cert_length == 0) { - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_CERTIFICATE); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); return -1; } if (input - start_data + cur_cert_length > input_len) { - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_CERTIFICATE); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); return -1; } diff --git a/src/detect.c b/src/detect.c index 19e7571ee5f3..60ca9795f578 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2579,6 +2579,10 @@ static int SignatureCreateMask(Signature *s) s->mask |= SIG_MASK_REQUIRE_DNS_STATE; SCLogDebug("sig %u requires dns app state (dns event)", s->id); break; + case ALPROTO_TLS: + s->mask |= SIG_MASK_REQUIRE_TLS_STATE; + SCLogDebug("sig %u requires tls app state (tls event)", s->id); + break; } break; } From c4b918b6c4acfde858cf9662631df105daf37efb Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 4 May 2016 10:00:26 +0200 Subject: [PATCH 1358/2553] tx: do not store ProgressCompletionStatus per ipproto Change AppLayerParserRegisterGetStateProgressCompletionStatus to only store one ProgressCompletionStatus callback function for each alproto, instead of storing one for each ipproto. This enables us to use AppLayerParserGetStateProgressCompletionStatus in functions where we do not know the ipproto used. --- src/app-layer-dns-tcp.c | 2 +- src/app-layer-dns-udp.c | 2 +- src/app-layer-htp.c | 2 +- src/app-layer-modbus.c | 2 +- src/app-layer-parser.c | 17 ++++++++--------- src/app-layer-parser.h | 6 ++---- src/app-layer-smtp.c | 2 +- src/app-layer-ssl.c | 2 +- src/app-layer-template.c | 4 ++-- src/detect-engine-apt-event.c | 2 +- src/detect-engine-state.c | 4 ++-- src/output-streaming.c | 8 ++++---- src/output-tx.c | 4 ++-- 13 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 9e85ca298119..54c34ba6a396 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -664,7 +664,7 @@ void RegisterDNSTCPParsers(void) AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DNS, DNSGetTxCnt); AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_DNS, DNSGetAlstateProgress); - AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_DNS, + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNS, DNSGetAlstateProgressCompletionStatus); DNSAppLayerRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_DNS); } else { diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index dcb2f5aa18b8..ffe61aa8d943 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -422,7 +422,7 @@ void RegisterDNSUDPParsers(void) DNSGetTxCnt); AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_DNS, DNSGetAlstateProgress); - AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_UDP, ALPROTO_DNS, + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNS, DNSGetAlstateProgressCompletionStatus); DNSAppLayerRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_DNS); diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 4e76c5feb20e..c1d68bf7b05f 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2769,7 +2769,7 @@ void RegisterHTPParsers(void) AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetAlstateProgress); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTxCnt); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTx); - AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_HTTP, + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_HTTP, HTPStateGetAlstateProgressCompletionStatus); AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPHasEvents); AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPGetEvents); diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 2b1875256089..77a735da8732 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1483,7 +1483,7 @@ void RegisterModbusParsers(void) AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateTxFree); AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetAlstateProgress); - AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_MODBUS, + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_MODBUS, ModbusGetAlstateProgressCompletionStatus); AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateGetEventInfo); diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index d885a761984a..f3985625e40a 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -449,13 +449,12 @@ void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, SCReturn; } -void AppLayerParserRegisterGetStateProgressCompletionStatus(uint8_t ipproto, - AppProto alproto, +void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int (*StateGetProgressCompletionStatus)(uint8_t direction)) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]. StateGetProgressCompletionStatus = StateGetProgressCompletionStatus; SCReturn; @@ -555,7 +554,7 @@ void AppLayerParserSetTransactionInspectId(AppLayerParserState *pstate, int direction = (flags & STREAM_TOSERVER) ? 0 : 1; uint64_t total_txs = AppLayerParserGetTxCnt(ipproto, alproto, alstate); uint64_t idx = AppLayerParserGetTransactionInspectId(pstate, flags); - int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(ipproto, alproto, flags); + int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(alproto, flags); void *tx; int state_progress; @@ -663,7 +662,7 @@ uint64_t AppLayerTransactionGetActiveLogOnly(Flow *f, uint8_t flags) /* logger is disabled, return highest 'complete' tx id */ uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, f->alproto, f->alstate); uint64_t idx = AppLayerParserGetTransactionInspectId(f->alparser, flags); - int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(f->proto, f->alproto, flags); + int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(f->alproto, flags); void *tx; int state_progress; @@ -739,7 +738,7 @@ int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, SCEnter(); int r = 0; if (unlikely(IS_DISRUPTED(flags))) { - r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + r = alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]. StateGetProgressCompletionStatus(flags); } else { r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. @@ -766,12 +765,12 @@ void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint SCReturnPtr(r, "void *"); } -int AppLayerParserGetStateProgressCompletionStatus(uint8_t ipproto, AppProto alproto, - uint8_t direction) +int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, + uint8_t direction) { SCEnter(); int r = 0; - r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + r = alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]. StateGetProgressCompletionStatus(direction); SCReturnInt(r); } diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index 2dee75e7c76f..a5eb3747068f 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -136,8 +136,7 @@ void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t (*StateGetTxCnt)(void *alstate)); void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id)); -void AppLayerParserRegisterGetStateProgressCompletionStatus(uint8_t ipproto, - AppProto alproto, +void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int (*StateGetStateProgressCompletionStatus)(uint8_t direction)); void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int (*StateGetEventInfo)(const char *event_name, int *event_id, @@ -171,8 +170,7 @@ int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t direction); uint64_t AppLayerParserGetTxCnt(uint8_t ipproto, AppProto alproto, void *alstate); void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id); -int AppLayerParserGetStateProgressCompletionStatus(uint8_t ipproto, AppProto alproto, - uint8_t direction); +int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, uint8_t direction); int AppLayerParserGetEventInfo(uint8_t ipproto, AppProto alproto, const char *event_name, int *event_id, AppLayerEventType *event_type); diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index c7385d8d5ade..d89b2c3588f0 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1642,7 +1642,7 @@ void RegisterSMTPParsers(void) AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx); - AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_SMTP, + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SMTP, SMTPStateGetAlstateProgressCompletionStatus); AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate); } else { diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 6869614d41be..cde8497e90e8 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -1740,7 +1740,7 @@ void RegisterSSLParsers(void) AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetAlstateProgress); - AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_TLS, + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_TLS, SSLGetAlstateProgressCompletionStatus); /* Get the value of no reassembly option from the config file */ diff --git a/src/app-layer-template.c b/src/app-layer-template.c index 5eafa67e1ae5..9506ea841577 100644 --- a/src/app-layer-template.c +++ b/src/app-layer-template.c @@ -501,8 +501,8 @@ void RegisterTemplateParsers(void) TemplateGetTxCnt); /* Transaction handling. */ - AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, - ALPROTO_TEMPLATE, TemplateGetAlstateProgressCompletionStatus); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_TEMPLATE, + TemplateGetAlstateProgressCompletionStatus); AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, TemplateGetStateProgress); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TEMPLATE, diff --git a/src/detect-engine-apt-event.c b/src/detect-engine-apt-event.c index 5ca416892dc6..344102970ad9 100644 --- a/src/detect-engine-apt-event.c +++ b/src/detect-engine-apt-event.c @@ -68,7 +68,7 @@ int DetectEngineAptEventInspect(ThreadVars *tv, return DETECT_ENGINE_INSPECT_SIG_MATCH; } else { if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) == - AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)) + AppLayerParserGetStateProgressCompletionStatus(alproto, flags)) { return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } else { diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 436fdf125966..7069972ac46e 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -581,7 +581,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, /* if this is the last tx in our list, and it's incomplete: then * we store the state so that ContinueDetection knows about it */ int tx_is_done = (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) >= - AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)); + AppLayerParserGetStateProgressCompletionStatus(alproto, flags)); /* see if we need to consider the next tx in our decision to add * a sig to the 'no inspect array'. */ int next_tx_no_progress = 0; @@ -1048,7 +1048,7 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); if (inspect_tx != NULL) { int a = AppLayerParserGetStateProgress(f->proto, alproto, inspect_tx, flags); - int b = AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags); + int b = AppLayerParserGetStateProgressCompletionStatus(alproto, flags); if (a < b) { inspect_tx_inprogress = 1; } diff --git a/src/output-streaming.c b/src/output-streaming.c index d416cbc3c6c4..73aa115b4030 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -147,11 +147,11 @@ int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) HtpState *s = f->alstate; if (s != NULL && s->conn != NULL) { int tx_progress_done_value_ts = - AppLayerParserGetStateProgressCompletionStatus(IPPROTO_TCP, - ALPROTO_HTTP, STREAM_TOSERVER); + AppLayerParserGetStateProgressCompletionStatus(ALPROTO_HTTP, + STREAM_TOSERVER); int tx_progress_done_value_tc = - AppLayerParserGetStateProgressCompletionStatus(IPPROTO_TCP, - ALPROTO_HTTP, STREAM_TOCLIENT); + AppLayerParserGetStateProgressCompletionStatus(ALPROTO_HTTP, + STREAM_TOCLIENT); // for each tx uint64_t tx_id = 0; diff --git a/src/output-tx.c b/src/output-tx.c index ca9216478be1..1e3396bd5f53 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -120,10 +120,10 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ uint64_t total_txs = AppLayerParserGetTxCnt(p->proto, alproto, alstate); uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); int tx_progress_done_value_ts = - AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto, + AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER); int tx_progress_done_value_tc = - AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto, + AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT); for (; tx_id < total_txs; tx_id++) { From f3599323e4ff649fa9e5a033df87361e05dc643b Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 4 May 2016 11:03:57 +0200 Subject: [PATCH 1359/2553] tx: add functions for logging Add function AppLayerParserRegisterLoggerFuncs for registering a callback function for checking if a specific logger has logged a transaction, and a callback function for specifying that it has. Also add functions AppLayerParserGetTxLogged and AppLayerParserSetTxLogged to invoke these callback functions. --- src/app-layer-parser.c | 47 ++++++++++++++++++++++++++++++++++++++++++ src/app-layer-parser.h | 7 +++++++ 2 files changed, 54 insertions(+) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index f3985625e40a..018214cc0723 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -107,6 +107,9 @@ typedef struct AppLayerParserProtoCtx_ int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type); + int (*StateGetTxLogged)(void *alstate, void *tx, uint32_t logger); + void (*StateSetTxLogged)(void *alstate, void *tx, uint32_t logger); + int (*StateHasTxDetectState)(void *alstate); DetectEngineState *(*GetTxDetectState)(void *tx); int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *); @@ -386,6 +389,21 @@ void AppLayerParserRegisterHasEventsFunc(uint8_t ipproto, AppProto alproto, SCReturn; } +void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, + int (*StateGetTxLogged)(void *, void *, uint32_t), + void (*StateSetTxLogged)(void *, void *, uint32_t)) +{ + SCEnter(); + + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxLogged = + StateGetTxLogged; + + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateSetTxLogged = + StateSetTxLogged; + + SCReturn; +} + void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto) { SCEnter(); @@ -518,6 +536,35 @@ void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto a SCReturn; } +void AppLayerParserSetTxLogged(uint8_t ipproto, AppProto alproto, + void *alstate, void *tx, uint32_t logger) +{ + SCEnter(); + + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateSetTxLogged != NULL) { + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateSetTxLogged(alstate, tx, logger); + } + + SCReturn; +} + +int AppLayerParserGetTxLogged(uint8_t ipproto, AppProto alproto, + void *alstate, void *tx, uint32_t logger) +{ + SCEnter(); + + uint8_t r = 0; + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateGetTxLogged != NULL) { + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateGetTxLogged(alstate, tx, logger); + } + + SCReturnInt(r); +} + uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate) { SCEnter(); diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index a5eb3747068f..7a319510c688 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -125,6 +125,9 @@ void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto proto, AppLayerDecoderEvents *(*StateGetEvents)(void *, uint64_t)); void AppLayerParserRegisterHasEventsFunc(uint8_t ipproto, AppProto alproto, int (*StateHasEvents)(void *)); +void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, + int (*StateGetTxLogged)(void *, void *, uint32_t), + void (*StateSetTxLogged)(void *, void *, uint32_t)); void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto); void AppLayerParserRegisterTruncateFunc(uint8_t ipproto, AppProto alproto, void (*Truncate)(void *, uint8_t)); @@ -155,6 +158,10 @@ void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto a uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate); void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate); +void AppLayerParserSetTxLogged(uint8_t ipproto, AppProto alproto, void *alstate, + void *tx, uint32_t logger); +int AppLayerParserGetTxLogged(uint8_t ipproto, AppProto alproto, void *alstate, + void *tx, uint32_t logger); uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction); void AppLayerParserSetTransactionInspectId(AppLayerParserState *pstate, const uint8_t ipproto, const AppProto alproto, void *alstate, From 1f98915ebe072e7af1c7c93a223d901f91f71c09 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 4 May 2016 12:14:13 +0200 Subject: [PATCH 1360/2553] tls: register logger functions --- src/app-layer-ssl.c | 18 ++++++++++++++++++ src/app-layer-ssl.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index cde8497e90e8..057ae2a1550a 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -190,6 +190,22 @@ uint64_t SSLGetTxCnt(void *state) return 1; } +void SSLSetTxLogged(void *state, void *tx, uint32_t logger) +{ + SSLState *ssl_state = (SSLState *)state; + if (ssl_state) + ssl_state->logged |= logger; +} + +int SSLGetTxLogged(void *state, void *tx, uint32_t logger) +{ + SSLState *ssl_state = (SSLState *)state; + if (ssl_state && (ssl_state->logged & logger)) + return 1; + + return 0; +} + int SSLGetAlstateProgressCompletionStatus(uint8_t direction) { return TLS_STATE_FINISHED; @@ -1740,6 +1756,8 @@ void RegisterSSLParsers(void) AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetAlstateProgress); + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_TLS, SSLGetTxLogged, SSLSetTxLogged); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_TLS, SSLGetAlstateProgressCompletionStatus); diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 12f76219a8ed..2df1362ebe0f 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -183,6 +183,9 @@ typedef struct SSLState_ { /* holds some state flags we need */ uint32_t flags; + /* specifies which loggers are done logging */ + uint32_t logged; + /* there might be a better place to store this*/ uint16_t hb_record_len; From dacb860d24f221fd7ad5a3fc775ad35f556717e0 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 4 May 2016 12:35:06 +0200 Subject: [PATCH 1361/2553] dns: register logger functions --- src/app-layer-dns-common.c | 15 +++++++++++++++ src/app-layer-dns-common.h | 3 +++ src/app-layer-dns-tcp.c | 2 ++ src/app-layer-dns-udp.c | 2 ++ 4 files changed, 22 insertions(+) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index d74547ba21d9..16a2252b4cb9 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -236,6 +236,21 @@ int DNSGetAlstateProgress(void *tx, uint8_t direction) } } +void DNSSetTxLogged(void *alstate, void *tx, uint32_t logger) +{ + DNSTransaction *dns_tx = (DNSTransaction *)tx; + dns_tx->logged |= logger; +} + +int DNSGetTxLogged(void *alstate, void *tx, uint32_t logger) +{ + DNSTransaction *dns_tx = (DNSTransaction *)tx; + if (dns_tx->logged & logger) + return 1; + + return 0; +} + /** \brief get value for 'complete' status in DNS * * For DNS we use a simple bool. 1 means done. diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index df68abcfe760..a3bdd9351d8b 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -191,6 +191,7 @@ typedef struct DNSAnswerEntry_ { typedef struct DNSTransaction_ { uint16_t tx_num; /**< internal: id */ uint16_t tx_id; /**< transaction id */ + uint32_t logged; /**< flags for loggers done logging */ uint8_t replied; /**< bool indicating request is replied to. */ uint8_t reply_lost; @@ -253,6 +254,8 @@ void DNSAppLayerRegisterGetEventInfo(uint8_t ipproto, AppProto alproto); void *DNSGetTx(void *alstate, uint64_t tx_id); uint64_t DNSGetTxCnt(void *alstate); +void DNSSetTxLogged(void *alstate, void *tx, uint32_t logger); +int DNSGetTxLogged(void *alstate, void *tx, uint32_t logger); int DNSGetAlstateProgress(void *tx, uint8_t direction); int DNSGetAlstateProgressCompletionStatus(uint8_t direction); diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 54c34ba6a396..dbce7ce30a8d 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -662,6 +662,8 @@ void RegisterDNSTCPParsers(void) AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNS, DNSGetTx); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DNS, DNSGetTxCnt); + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_DNS, DNSGetTxLogged, + DNSSetTxLogged); AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_DNS, DNSGetAlstateProgress); AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNS, diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index ffe61aa8d943..77a6cb3c7724 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -420,6 +420,8 @@ void RegisterDNSUDPParsers(void) DNSGetTx); AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_DNS, DNSGetTxCnt); + AppLayerParserRegisterLoggerFuncs(IPPROTO_UDP, ALPROTO_DNS, DNSGetTxLogged, + DNSSetTxLogged); AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_DNS, DNSGetAlstateProgress); AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNS, From d484812d05669b10e82a5f782666d7e57fe43955 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 4 May 2016 12:53:55 +0200 Subject: [PATCH 1362/2553] smtp: register logger functions --- src/app-layer-smtp.c | 17 +++++++++++++++++ src/app-layer-smtp.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index d89b2c3588f0..5f89aea0344c 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1545,6 +1545,21 @@ static void *SMTPStateGetTx(void *state, uint64_t id) } +static void SMTPStateSetTxLogged(void *state, void *vtx, uint32_t logger) +{ + SMTPTransaction *tx = vtx; + tx->logged |= logger; +} + +static int SMTPStateGetTxLogged(void *state, void *vtx, uint32_t logger) +{ + SMTPTransaction *tx = vtx; + if (tx->logged & logger) + return 1; + + return 0; +} + static int SMTPStateGetAlstateProgressCompletionStatus(uint8_t direction) { return 1; } @@ -1642,6 +1657,8 @@ void RegisterSMTPParsers(void) AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx); + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxLogged, + SMTPStateSetTxLogged); AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SMTP, SMTPStateGetAlstateProgressCompletionStatus); AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate); diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 06ade068c71b..f36029efe169 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -66,6 +66,8 @@ typedef struct SMTPTransaction_ { /** id of this tx, starting at 0 */ uint64_t tx_id; int done; + /** indicates loggers done logging */ + uint32_t logged; /** the first message contained in the session */ MimeDecEntity *msg_head; /** the last message contained in the session */ From c52fe9a5fa1761f3d8f334fbd13315f3ce921c70 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 4 May 2016 13:16:03 +0200 Subject: [PATCH 1363/2553] http: register logger functions --- src/app-layer-htp.c | 20 ++++++++++++++++++++ src/app-layer-htp.h | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index c1d68bf7b05f..45c14d7d81fe 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2634,6 +2634,24 @@ static void *HTPStateGetTx(void *alstate, uint64_t tx_id) return NULL; } +static void HTPStateSetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + htp_tx_t *tx = (htp_tx_t *)vtx; + HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); + if (tx_ud) + tx_ud->logged |= logger; +} + +static int HTPStateGetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + htp_tx_t *tx = (htp_tx_t *)vtx; + HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); + if (tx_ud && (tx_ud->logged & logger)) + return 1; + + return 0; +} + static int HTPStateGetAlstateProgressCompletionStatus(uint8_t direction) { return (direction & STREAM_TOSERVER) ? HTP_REQUEST_COMPLETE : HTP_RESPONSE_COMPLETE; @@ -2769,6 +2787,8 @@ void RegisterHTPParsers(void) AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetAlstateProgress); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTxCnt); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTx); + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTxLogged, + HTPStateSetTxLogged); AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_HTTP, HTPStateGetAlstateProgressCompletionStatus); AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPHasEvents); diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 275bc4b7efbd..d7aab9399372 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -205,6 +205,10 @@ typedef struct HtpTxUserData_ { /* Body of the request (if any) */ uint8_t request_body_init; uint8_t response_body_init; + + /* indicates which loggers that have logged */ + uint32_t logged; + HtpBody request_body; HtpBody response_body; From 593f81527ac902f320136a6080a85a21648d55a6 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 4 May 2016 13:25:03 +0200 Subject: [PATCH 1364/2553] modbus: register logger functions --- src/app-layer-modbus.c | 17 +++++++++++++++++ src/app-layer-modbus.h | 1 + 2 files changed, 18 insertions(+) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 77a735da8732..c3502f2e59d4 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -249,6 +249,21 @@ void *ModbusGetTx(void *alstate, uint64_t tx_id) { return NULL; } +void ModbusSetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + ModbusTransaction *tx = (ModbusTransaction *)vtx; + tx->logged |= logger; +} + +int ModbusGetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + ModbusTransaction *tx = (ModbusTransaction *)vtx; + if (tx->logged & logger) + return 1; + + return 0; +} + uint64_t ModbusGetTxCnt(void *alstate) { return ((uint64_t) ((ModbusState *) alstate)->transaction_max); } @@ -1480,6 +1495,8 @@ void RegisterModbusParsers(void) AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTx); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTxCnt); + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTxLogged, + ModbusSetTxLogged); AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateTxFree); AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetAlstateProgress); diff --git a/src/app-layer-modbus.h b/src/app-layer-modbus.h index 25ac519afd39..a8545dfbdc8c 100644 --- a/src/app-layer-modbus.h +++ b/src/app-layer-modbus.h @@ -83,6 +83,7 @@ typedef struct ModbusTransaction_ { struct ModbusState_ *modbus; uint64_t tx_num; /**< internal: id */ + uint32_t logged; /**< flags indicating which loggers have logged */ uint16_t transactionId; uint16_t length; uint8_t function; From 4166ec306414230d1b69fb28710824ba27c3af0d Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 4 May 2016 13:37:04 +0200 Subject: [PATCH 1365/2553] template: register logger functions --- src/app-layer-template.c | 18 ++++++++++++++++++ src/app-layer-template.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/src/app-layer-template.c b/src/app-layer-template.c index 9506ea841577..c89e7b241d86 100644 --- a/src/app-layer-template.c +++ b/src/app-layer-template.c @@ -364,6 +364,21 @@ static void *TemplateGetTx(void *state, uint64_t tx_id) return NULL; } +static void TemplateSetTxLogged(void *state, void *vtx, uint32_t logger) +{ + TemplateTransaction *tx = (TemplateTransaction *)vtx; + tx->logged |= logger; +} + +static int TemplateGetTxLogged(void *state, void *vtx, uint32_t logger) +{ + TemplateTransaction *tx = (TemplateTransaction *)vtx; + if (tx->logged & logger) + return 1; + + return 0; +} + /** * \brief Called by the application layer. * @@ -496,6 +511,9 @@ void RegisterTemplateParsers(void) AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, TemplateStateTxFree); + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateGetTxLogged, TemplateSetTxLogged); + /* Register a function to return the current transaction count. */ AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEMPLATE, TemplateGetTxCnt); diff --git a/src/app-layer-template.h b/src/app-layer-template.h index 4e58fa89b52a..191e0933b541 100644 --- a/src/app-layer-template.h +++ b/src/app-layer-template.h @@ -37,6 +37,9 @@ typedef struct TemplateTransaction_ { uint8_t *request_buffer; uint32_t request_buffer_len; + /* flags indicating which loggers that have logged */ + uint32_t logged; + uint8_t *response_buffer; uint32_t response_buffer_len; From fa6257b66ab4415ad51a0ca09a24cb6c65bd36ef Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 27 Apr 2016 14:13:44 +0200 Subject: [PATCH 1366/2553] output: add new logger to log at specified state Sometimes we want to log when we reach a specified state instead of waiting for the session to end. E.g for TLS we want to log as soon as the handshake is done. To do this, a new logger is added, where it is possible to specify a custom "ProgressCompletionStatus". --- src/output-tx.c | 91 ++++++++++++++++++++++++++++++++++--------------- src/output-tx.h | 3 +- src/output.c | 49 +++++++++++++++++++++----- src/output.h | 9 +++++ src/runmodes.c | 3 +- 5 files changed, 117 insertions(+), 38 deletions(-) diff --git a/src/output-tx.c b/src/output-tx.c index 1e3396bd5f53..79b896325917 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -51,11 +51,16 @@ typedef struct OutputTxLogger_ { struct OutputTxLogger_ *next; const char *name; TmmId module_id; + uint32_t id; + int tc_log_progress; + int ts_log_progress; } OutputTxLogger; static OutputTxLogger *list = NULL; -int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *output_ctx) +int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, + OutputCtx *output_ctx, int tc_log_progress, + int ts_log_progress) { int module_id = TmModuleGetIdByName(name); if (module_id < 0) @@ -72,12 +77,34 @@ int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, op->name = name; op->module_id = (TmmId) module_id; - if (list == NULL) + if (tc_log_progress) { + op->tc_log_progress = tc_log_progress; + } else { + op->tc_log_progress = + AppLayerParserGetStateProgressCompletionStatus(alproto, + STREAM_TOCLIENT); + } + + if (ts_log_progress) { + op->ts_log_progress = ts_log_progress; + } else { + op->ts_log_progress = + AppLayerParserGetStateProgressCompletionStatus(alproto, + STREAM_TOSERVER); + } + + if (list == NULL) { + op->id = 1; list = op; - else { + } else { OutputTxLogger *t = list; while (t->next) t = t->next; + if (t->id * 2 > UINT32_MAX) { + SCLogError(SC_ERR_FATAL, "Too many loggers registered."); + exit(EXIT_FAILURE); + } + op->id = t->id * 2; t->next = op; } @@ -119,15 +146,10 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ uint64_t total_txs = AppLayerParserGetTxCnt(p->proto, alproto, alstate); uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); - int tx_progress_done_value_ts = - AppLayerParserGetStateProgressCompletionStatus(alproto, - STREAM_TOSERVER); - int tx_progress_done_value_tc = - AppLayerParserGetStateProgressCompletionStatus(alproto, - STREAM_TOCLIENT); + for (; tx_id < total_txs; tx_id++) { - int proto_logged = 0; + int logger_not_logged = 0; void *tx = AppLayerParserGetTx(p->proto, alproto, alstate, tx_id); if (tx == NULL) { @@ -135,22 +157,11 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ continue; } - if (!(AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_EOF))) - { - int tx_progress = AppLayerParserGetStateProgress(p->proto, alproto, - tx, FlowGetDisruptionFlags(f, STREAM_TOSERVER)); - if (tx_progress < tx_progress_done_value_ts) { - SCLogDebug("progress not far enough, not logging"); - break; - } + int tx_progress_ts = AppLayerParserGetStateProgress(p->proto, alproto, + tx, FlowGetDisruptionFlags(f, STREAM_TOSERVER)); - tx_progress = AppLayerParserGetStateProgress(p->proto, alproto, - tx, FlowGetDisruptionFlags(f, STREAM_TOCLIENT)); - if (tx_progress < tx_progress_done_value_tc) { - SCLogDebug("progress not far enough, not logging"); - break; - } - } + int tx_progress_tc = AppLayerParserGetStateProgress(p->proto, alproto, + tx, FlowGetDisruptionFlags(f, STREAM_TOCLIENT)); // call each logger here (pseudo code) logger = list; @@ -161,12 +172,38 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ SCLogDebug("logger %p", logger); if (logger->alproto == alproto) { SCLogDebug("alproto match, logging tx_id %ju", tx_id); + + if (AppLayerParserGetTxLogged(p->proto, alproto, alstate, tx, + logger->id)) { + SCLogDebug("logger has already logged this transaction"); + + goto next; + } + + if (!(AppLayerParserStateIssetFlag(f->alparser, + APP_LAYER_PARSER_EOF))) { + if (tx_progress_tc < logger->tc_log_progress) { + SCLogDebug("progress not far enough, not logging"); + logger_not_logged = 1; + goto next; + } + + if (tx_progress_ts < logger->ts_log_progress) { + SCLogDebug("progress not far enough, not logging"); + logger_not_logged = 1; + goto next; + } + } + PACKET_PROFILING_TMM_START(p, logger->module_id); logger->LogFunc(tv, store->thread_data, p, f, alstate, tx, tx_id); PACKET_PROFILING_TMM_END(p, logger->module_id); - proto_logged = 1; + + AppLayerParserSetTxLogged(p->proto, alproto, alstate, tx, + logger->id); } +next: logger = logger->next; store = store->next; @@ -174,7 +211,7 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ BUG_ON(logger != NULL && store == NULL); } - if (proto_logged) { + if (!logger_not_logged) { SCLogDebug("updating log tx_id %ju", tx_id); AppLayerParserSetTransactionLogId(f->alparser); } diff --git a/src/output-tx.h b/src/output-tx.h index 7ffb8a6d25e8..e8e8163d8907 100644 --- a/src/output-tx.h +++ b/src/output-tx.h @@ -36,7 +36,8 @@ typedef int (*TxLogger)(ThreadVars *, void *thread_data, const Packet *, Flow *f */ //typedef int (*TxLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *); +int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, + OutputCtx *, int tc_log_progress, int ts_log_progress); void TmModuleTxLoggerRegister (void); diff --git a/src/output.c b/src/output.c index 1146b7b22673..d7c5ff910ee9 100644 --- a/src/output.c +++ b/src/output.c @@ -150,17 +150,16 @@ OutputRegisterPacketSubModule(const char *parent_name, const char *name, } /** - * \brief Register a tx output module. + * \brief Register a tx output module with progress. * * This function will register an output module so it can be * configured with the configuration file. * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterTxModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc) +void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -176,6 +175,8 @@ OutputRegisterTxModule(const char *name, const char *conf_name, module->InitFunc = InitFunc; module->TxLogFunc = TxLogFunc; module->alproto = alproto; + module->tc_log_progress = tc_log_progress; + module->ts_log_progress = ts_log_progress; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Tx logger \"%s\" registered.", name); @@ -185,10 +186,10 @@ OutputRegisterTxModule(const char *name, const char *conf_name, exit(EXIT_FAILURE); } -void -OutputRegisterTxSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - AppProto alproto, TxLogger TxLogFunc) +void OutputRegisterTxSubModuleWithProgress(const char *parent_name, + const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, + OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, + int tc_log_progress, int ts_log_progress) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -205,6 +206,8 @@ OutputRegisterTxSubModule(const char *parent_name, const char *name, module->InitSubFunc = InitFunc; module->TxLogFunc = TxLogFunc; module->alproto = alproto; + module->tc_log_progress = tc_log_progress; + module->ts_log_progress = ts_log_progress; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Tx logger \"%s\" registered.", name); @@ -214,6 +217,34 @@ OutputRegisterTxSubModule(const char *parent_name, const char *name, exit(EXIT_FAILURE); } +/** + * \brief Register a tx output module. + * + * This function will register an output module so it can be + * configured with the configuration file. + * + * \retval Returns 0 on success, -1 on failure. + */ +void +OutputRegisterTxModule(const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + TxLogger TxLogFunc) +{ + /* wrapper function */ + OutputRegisterTxModuleWithProgress(name, conf_name, InitFunc, alproto, + TxLogFunc, 0, 0); +} + +void +OutputRegisterTxSubModule(const char *parent_name, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), + AppProto alproto, TxLogger TxLogFunc) +{ + /* wrapper function */ + OutputRegisterTxSubModuleWithProgress(parent_name, name, conf_name, + InitFunc, alproto, TxLogFunc, 0, 0); +} + /** * \brief Register a file output module. * diff --git a/src/output.h b/src/output.h index 9a4add0efb53..152262b72a60 100644 --- a/src/output.h +++ b/src/output.h @@ -55,6 +55,8 @@ typedef struct OutputModule_ { StatsLogger StatsLogFunc; AppProto alproto; enum OutputStreamingType stream_type; + int tc_log_progress; + int ts_log_progress; TAILQ_ENTRY(OutputModule_) entries; } OutputModule; @@ -75,6 +77,13 @@ void OutputRegisterTxSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc); +void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress); +void OutputRegisterTxSubModuleWithProgress(const char *parent_name, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), + AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress); + void OutputRegisterFileModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc); void OutputRegisterFileSubModule(const char *parent_name, const char *name, diff --git a/src/runmodes.c b/src/runmodes.c index b4bf31b6c7a7..e0154a1f55a5 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -617,7 +617,8 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } else if (module->TxLogFunc) { SCLogDebug("%s is a tx logger", module->name); OutputRegisterTxLogger(module->name, module->alproto, - module->TxLogFunc, output_ctx); + module->TxLogFunc, output_ctx, module->tc_log_progress, + module->ts_log_progress); /* need one instance of the tx logger module */ if (tx_logger_module == NULL) { From 88bf866381f295cfde3805eab0a4cb1b0630f853 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 13 Apr 2016 08:43:54 +0200 Subject: [PATCH 1367/2553] output-lua: use LuaTxLogger for TLS --- src/app-layer-ssl.h | 2 -- src/output-lua.c | 84 ++------------------------------------------- 2 files changed, 2 insertions(+), 84 deletions(-) diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 2df1362ebe0f..23e74654cada 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -98,8 +98,6 @@ enum { /* flags for file storage */ #define SSL_AL_FLAG_STATE_STORED 0x40000 -#define SSL_AL_FLAG_STATE_LOGGED_LUA 0x80000 - /* config flags */ #define SSL_TLS_LOG_PEM (1 << 0) diff --git a/src/output-lua.c b/src/output-lua.c index c671bc4a687a..56a1a817b76e 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -232,86 +232,6 @@ static int LuaPacketConditionAlerts(ThreadVars *tv, const Packet *p) return FALSE; } -/** \internal - * \brief Packet Logger for lua scripts, for tls - * - * A single call to this function will run one script for a single - * packet. If it is called, it means that the registered condition - * function has returned TRUE. - * - * The script is called once for each packet. - */ -static int LuaPacketLoggerTls(ThreadVars *tv, void *thread_data, const Packet *p) -{ - LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data; - - char timebuf[64]; - CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); - - SCMutexLock(&td->lua_ctx->m); - - lua_getglobal(td->lua_ctx->luastate, "log"); - - LuaStateSetThreadVars(td->lua_ctx->luastate, tv); - LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); - LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* unlocked */LUA_FLOW_NOT_LOCKED_BY_PARENT); - - int retval = lua_pcall(td->lua_ctx->luastate, 0, 0, 0); - if (retval != 0) { - SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1)); - } - - SCMutexUnlock(&td->lua_ctx->m); - FLOWLOCK_WRLOCK(p->flow); - - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); - if (ssl_state != NULL) - ssl_state->flags |= SSL_AL_FLAG_STATE_LOGGED_LUA; - - FLOWLOCK_UNLOCK(p->flow); - SCReturnInt(0); -} - -static int LuaPacketConditionTls(ThreadVars *tv, const Packet *p) -{ - if (p->flow == NULL) { - return FALSE; - } - - if (!(PKT_IS_IPV4(p)) && !(PKT_IS_IPV6(p))) { - return FALSE; - } - - if (!(PKT_IS_TCP(p))) { - return FALSE; - } - - FLOWLOCK_RDLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto dontlog; - - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); - if (ssl_state == NULL) { - SCLogDebug("no tls state, so no request logging"); - goto dontlog; - } - - if (ssl_state->server_connp.cert0_issuerdn == NULL || - ssl_state->server_connp.cert0_subject == NULL) - goto dontlog; - - /* We only log the state once */ - if (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED_LUA) - goto dontlog; - - FLOWLOCK_UNLOCK(p->flow); - return TRUE; -dontlog: - FLOWLOCK_UNLOCK(p->flow); - return FALSE; -} - /** \internal * \brief Packet Logger for lua scripts, for ssh * @@ -945,8 +865,8 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) om->alproto = ALPROTO_HTTP; AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP); } else if (opts.alproto == ALPROTO_TLS) { - om->PacketLogFunc = LuaPacketLoggerTls; - om->PacketConditionFunc = LuaPacketConditionTls; + om->TxLogFunc = LuaTxLogger; + om->alproto = ALPROTO_TLS; } else if (opts.alproto == ALPROTO_DNS) { om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_DNS; From c6a61e009b65b19dbe745d23022fad518a24c369 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 14 Apr 2016 09:51:18 +0200 Subject: [PATCH 1368/2553] tlslog: use TxLogger --- src/log-tlslog.c | 85 +++++++----------------------------------------- src/output-lua.c | 4 ++- 2 files changed, 15 insertions(+), 74 deletions(-) diff --git a/src/log-tlslog.c b/src/log-tlslog.c index 53ebad8bfc56..cf4cceaeddad 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -270,87 +270,31 @@ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf) return NULL; } -/** \internal - * \brief Condition function for TLS logger - * \retval bool true or false -- log now? - */ -static int LogTlsCondition(ThreadVars *tv, const Packet *p) -{ - if (p->flow == NULL) { - return FALSE; - } - - if (!(PKT_IS_TCP(p))) { - return FALSE; - } - - FLOWLOCK_RDLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto dontlog; - - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); - if (ssl_state == NULL) { - SCLogDebug("no tls state, so no request logging"); - goto dontlog; - } - - /* we only log the state once if we don't have to write - * the cert due to tls.store keyword. */ - if (!(ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) && - (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED)) - goto dontlog; - - if (ssl_state->server_connp.cert0_issuerdn == NULL || - ssl_state->server_connp.cert0_subject == NULL) - goto dontlog; - - /* todo: logic to log once */ - - FLOWLOCK_UNLOCK(p->flow); - return TRUE; -dontlog: - FLOWLOCK_UNLOCK(p->flow); - return FALSE; -} - -static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) +static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, + Flow *f, void *state, void *tx, uint64_t tx_id) { LogTlsLogThread *aft = (LogTlsLogThread *)thread_data; LogTlsFileCtx *hlog = aft->tlslog_ctx; char timebuf[64]; int ipproto = (PKT_IS_IPV4(p)) ? AF_INET : AF_INET6; - if (unlikely(p->flow == NULL)) { + SSLState *ssl_state = (SSLState *)state; + if (unlikely(ssl_state == NULL)) { return 0; } - /* check if we have TLS state or not */ - FLOWLOCK_WRLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto end; - - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); - if (unlikely(ssl_state == NULL)) { - goto end; + if (ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) { + return 0; } - if (ssl_state->server_connp.cert0_issuerdn == NULL || ssl_state->server_connp.cert0_subject == NULL) - goto end; - - /* Don't log again the state. If we are here it was because we had - * to store the cert. */ - if (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED) - goto end; - CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); #define PRINT_BUF_LEN 46 char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; Port sp, dp; - if (!TLSGetIPInformations(p, srcip, PRINT_BUF_LEN, - &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) { - goto end; + if (!TLSGetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, + PRINT_BUF_LEN, &dp, ipproto)) { + return 0; } MemBufferReset(aft->buffer); @@ -373,10 +317,6 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); SCMutexUnlock(&hlog->file_ctx->fp_mutex); - /* we only log the state once */ - ssl_state->flags |= SSL_AL_FLAG_STATE_LOGGED; -end: - FLOWLOCK_UNLOCK(p->flow); return 0; } @@ -384,13 +324,12 @@ void TmModuleLogTlsLogRegister(void) { tmm_modules[TMM_LOGTLSLOG].name = MODULE_NAME; tmm_modules[TMM_LOGTLSLOG].ThreadInit = LogTlsLogThreadInit; - tmm_modules[TMM_LOGTLSLOG].Func = NULL; tmm_modules[TMM_LOGTLSLOG].ThreadExitPrintStats = LogTlsLogExitPrintStats; tmm_modules[TMM_LOGTLSLOG].ThreadDeinit = LogTlsLogThreadDeinit; tmm_modules[TMM_LOGTLSLOG].RegisterTests = NULL; tmm_modules[TMM_LOGTLSLOG].cap_flags = 0; tmm_modules[TMM_LOGTLSLOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterPacketModule(MODULE_NAME, "tls-log", LogTlsLogInitCtx, - LogTlsLogger, LogTlsCondition); + OutputRegisterTxModuleWithProgress(MODULE_NAME, "tls-log", LogTlsLogInitCtx, + ALPROTO_TLS, LogTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE); } diff --git a/src/output-lua.c b/src/output-lua.c index 56a1a817b76e..c2aadbbbdf8c 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -867,7 +867,9 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) } else if (opts.alproto == ALPROTO_TLS) { om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_TLS; - } else if (opts.alproto == ALPROTO_DNS) { + om->tc_log_progress = TLS_HANDSHAKE_DONE; + om->ts_log_progress = TLS_HANDSHAKE_DONE; + } else if (opts.alproto == ALPROTO_DNS) { om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_DNS; AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNS); From e9074bc829d1ef9932b5fdf420bd610775d8fb91 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 15 Apr 2016 09:07:09 +0200 Subject: [PATCH 1369/2553] jsontls: use TxLogger --- src/output-json-tls.c | 88 ++++++++++--------------------------------- 1 file changed, 20 insertions(+), 68 deletions(-) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 94f6a3645b76..54cda16eb8cf 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -125,37 +125,29 @@ void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) json_object_set_new(tjs, "version", json_string(ssl_version)); } -static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) +static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, + Flow *f, void *state, void *txptr, uint64_t tx_id) { JsonTlsLogThread *aft = (JsonTlsLogThread *)thread_data; OutputTlsCtx *tls_ctx = aft->tlslog_ctx; - if (unlikely(p->flow == NULL)) { - return 0; - } - - /* check if we have TLS state or not */ - FLOWLOCK_WRLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto end; - - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + SSLState *ssl_state = (SSLState *)state; if (unlikely(ssl_state == NULL)) { - goto end; + return 0; } - if (ssl_state->server_connp.cert0_issuerdn == NULL || ssl_state->server_connp.cert0_subject == NULL) - goto end; + if (ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) + return 0; - json_t *js = CreateJSONHeader((Packet *)p, 0, "tls");//TODO + json_t *js = CreateJSONHeader((Packet *)p, 0, "tls"); if (unlikely(js == NULL)) - goto end; + return 0; json_t *tjs = json_object(); if (tjs == NULL) { free(js); - goto end; + return 0; } /* reset */ @@ -173,10 +165,6 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) json_object_clear(js); json_decref(js); - /* we only log the state once */ - ssl_state->flags |= SSL_AL_FLAG_STATE_LOGGED; -end: - FLOWLOCK_UNLOCK(p->flow); return 0; } @@ -282,6 +270,8 @@ OutputCtx *OutputTlsLogInit(ConfNode *conf) output_ctx->data = tls_ctx; output_ctx->DeInit = OutputTlsLogDeinit; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); + return output_ctx; } @@ -329,49 +319,9 @@ OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) output_ctx->data = tls_ctx; output_ctx->DeInit = OutputTlsLogDeinitSub; - return output_ctx; -} - -/** \internal - * \brief Condition function for TLS logger - * \retval bool true or false -- log now? - */ -static int JsonTlsCondition(ThreadVars *tv, const Packet *p) -{ - if (p->flow == NULL) { - return FALSE; - } - - if (!(PKT_IS_TCP(p))) { - return FALSE; - } - - FLOWLOCK_RDLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto dontlog; - - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); - if (ssl_state == NULL) { - SCLogDebug("no tls state, so no request logging"); - goto dontlog; - } - - /* we only log the state once */ - if (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED) - goto dontlog; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); - if (ssl_state->server_connp.cert0_issuerdn == NULL || - ssl_state->server_connp.cert0_subject == NULL) - goto dontlog; - - /* todo: logic to log once */ - - FLOWLOCK_UNLOCK(p->flow); - return TRUE; -dontlog: - FLOWLOCK_UNLOCK(p->flow); - return FALSE; + return output_ctx; } void TmModuleJsonTlsLogRegister (void) @@ -384,12 +334,14 @@ void TmModuleJsonTlsLogRegister (void) tmm_modules[TMM_JSONTLSLOG].flags = TM_FLAG_LOGAPI_TM; /* register as separate module */ - OutputRegisterPacketModule("JsonTlsLog", "tls-json-log", OutputTlsLogInit, - JsonTlsLogger, JsonTlsCondition); + OutputRegisterTxModuleWithProgress("JsonTlsLog", "dns-json-log", + OutputTlsLogInit, ALPROTO_TLS, JsonTlsLogger, TLS_HANDSHAKE_DONE, + TLS_HANDSHAKE_DONE); /* also register as child of eve-log */ - OutputRegisterPacketSubModule("eve-log", "JsonTlsLog", "eve-log.tls", OutputTlsLogInitSub, - JsonTlsLogger, JsonTlsCondition); + OutputRegisterTxSubModuleWithProgress("eve-log", "JsonTlsLog", + "eve-log.tls", OutputTlsLogInitSub, ALPROTO_TLS, JsonTlsLogger, + TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE); } #else From 47a4daeeb88729af0efd56ce574ab81297c11117 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 15 Apr 2016 09:19:36 +0200 Subject: [PATCH 1370/2553] output: allow more than one TLS logger --- src/app-layer-ssl.h | 2 -- src/log-tlslog.c | 8 -------- src/output-json-tls.c | 16 ---------------- src/output.c | 16 ---------------- src/output.h | 3 --- 5 files changed, 45 deletions(-) diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 23e74654cada..d42f3c535d7d 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -82,8 +82,6 @@ enum { #define SSL_AL_FLAG_STATE_SERVER_KEYX 0x1000 #define SSL_AL_FLAG_STATE_UNKNOWN 0x2000 -#define SSL_AL_FLAG_STATE_LOGGED 0x4000 - /* flag to indicate that session is finished */ #define SSL_AL_FLAG_STATE_FINISHED 0x4000 diff --git a/src/log-tlslog.c b/src/log-tlslog.c index cf4cceaeddad..c5fb14642d8a 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -194,8 +194,6 @@ static TmEcode LogTlsLogThreadDeinit(ThreadVars *t, void *data) static void LogTlsLogDeInitCtx(OutputCtx *output_ctx) { - OutputTlsLoggerDisable(); - LogTlsFileCtx *tlslog_ctx = (LogTlsFileCtx *) output_ctx->data; LogFileFreeCtx(tlslog_ctx->file_ctx); SCFree(tlslog_ctx); @@ -218,12 +216,6 @@ static void LogTlsLogExitPrintStats(ThreadVars *tv, void *data) * */ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf) { - if (OutputTlsLoggerEnable() != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'tls' logger " - "can be enabled"); - return NULL; - } - LogFileCtx* file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 54cda16eb8cf..adb0a4e1f603 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -213,8 +213,6 @@ static TmEcode JsonTlsLogThreadDeinit(ThreadVars *t, void *data) static void OutputTlsLogDeinit(OutputCtx *output_ctx) { - OutputTlsLoggerDisable(); - OutputTlsCtx *tls_ctx = output_ctx->data; LogFileCtx *logfile_ctx = tls_ctx->file_ctx; LogFileFreeCtx(logfile_ctx); @@ -225,12 +223,6 @@ static void OutputTlsLogDeinit(OutputCtx *output_ctx) #define DEFAULT_LOG_FILENAME "tls.json" OutputCtx *OutputTlsLogInit(ConfNode *conf) { - if (OutputTlsLoggerEnable() != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'tls' logger " - "can be enabled"); - return NULL; - } - LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { SCLogError(SC_ERR_TLS_LOG_GENERIC, "couldn't create new file_ctx"); @@ -277,8 +269,6 @@ OutputCtx *OutputTlsLogInit(ConfNode *conf) static void OutputTlsLogDeinitSub(OutputCtx *output_ctx) { - OutputTlsLoggerDisable(); - OutputTlsCtx *tls_ctx = output_ctx->data; SCFree(tls_ctx); SCFree(output_ctx); @@ -288,12 +278,6 @@ OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { OutputJsonCtx *ojc = parent_ctx->data; - if (OutputTlsLoggerEnable() != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'tls' logger " - "can be enabled"); - return NULL; - } - OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); if (unlikely(tls_ctx == NULL)) return NULL; diff --git a/src/output.c b/src/output.c index d7c5ff910ee9..6a9ab3a6a3c1 100644 --- a/src/output.c +++ b/src/output.c @@ -647,22 +647,6 @@ void OutputDropLoggerDisable(void) drop_loggers--; } -static int tls_loggers = 0; - -int OutputTlsLoggerEnable(void) -{ - if (tls_loggers) - return -1; - tls_loggers++; - return 0; -} - -void OutputTlsLoggerDisable(void) -{ - if (tls_loggers) - tls_loggers--; -} - static int ssh_loggers = 0; int OutputSshLoggerEnable(void) diff --git a/src/output.h b/src/output.h index 152262b72a60..85ae93252755 100644 --- a/src/output.h +++ b/src/output.h @@ -121,9 +121,6 @@ void OutputDeregisterAll(void); int OutputDropLoggerEnable(void); void OutputDropLoggerDisable(void); -int OutputTlsLoggerEnable(void); -void OutputTlsLoggerDisable(void); - int OutputSshLoggerEnable(void); void OutputSshLoggerDisable(void); From 663273a31e0903ad6f58849d4e1b4ac0052277a5 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 27 Apr 2016 10:17:15 +0200 Subject: [PATCH 1371/2553] tls: change flag checking in SSLParserTest23 Change flag checking in SSLParserTest23 to check each flag individually to enable adding more flags without the test failing. --- src/app-layer-ssl.c | 55 ++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 057ae2a1550a..288370737307 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -3898,9 +3898,9 @@ static int SSLParserTest23(void) goto end; } - if (app_state->flags != - (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | - SSL_AL_FLAG_SSL_NO_SESSION_ID)) { + if ((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0 || + (app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0 || + (app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0) { printf("flags not set\n"); result = 0; goto end; @@ -3932,9 +3932,10 @@ static int SSLParserTest23(void) goto end; } - if (app_state->flags != - (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | - SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO)) { + if ((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0 || + (app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0 || + (app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0 || + (app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0) { printf("flags not set\n"); result = 0; goto end; @@ -3967,11 +3968,13 @@ static int SSLParserTest23(void) goto end; } - if (app_state->flags != - (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | - SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO | - SSL_AL_FLAG_STATE_CLIENT_KEYX | SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC | - SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { + if ((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0 || + (app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0 || + (app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0 || + (app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0 || + (app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0 || + (app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0 || + (app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0) { printf("flags not set\n"); result = 0; goto end; @@ -4004,12 +4007,15 @@ static int SSLParserTest23(void) goto end; } - if (app_state->flags != - (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | - SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO | - SSL_AL_FLAG_STATE_CLIENT_KEYX | SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC | - SSL_AL_FLAG_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC | - SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { + if ((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0 || + (app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0 || + (app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0 || + (app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0 || + (app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0 || + (app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0 || + (app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0 || + (app_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC) == 0 || + (app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0) { printf("flags not set\n"); result = 0; goto end; @@ -4040,12 +4046,15 @@ static int SSLParserTest23(void) goto end; } - if (app_state->flags != - (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | - SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO | - SSL_AL_FLAG_STATE_CLIENT_KEYX | SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC | - SSL_AL_FLAG_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC | - SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { + if ((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0 || + (app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0 || + (app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0 || + (app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0 || + (app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0 || + (app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0 || + (app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0 || + (app_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC) == 0 || + (app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0) { printf("flags not set\n"); result = 0; goto end; From 77cc03505b3e59c73e359c71ffa9f696bb3eb8d9 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 12 May 2016 08:11:53 +0200 Subject: [PATCH 1372/2553] output: add new tx logger to log at certain condition Some loggers needs certain conditions to be met before logging. This enables us to use conditions on the tx logger. --- src/output-tx.c | 33 ++++++++++++++------- src/output-tx.h | 5 ++-- src/output.c | 77 ++++++++++++++++++++++++++++++++++++++++++------- src/output.h | 9 ++++++ src/runmodes.c | 2 +- 5 files changed, 101 insertions(+), 25 deletions(-) diff --git a/src/output-tx.c b/src/output-tx.c index 79b896325917..e94e418897f4 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -47,6 +47,7 @@ typedef struct OutputLoggerThreadData_ { typedef struct OutputTxLogger_ { AppProto alproto; TxLogger LogFunc; + TxLoggerCondition LogCondition; OutputCtx *output_ctx; struct OutputTxLogger_ *next; const char *name; @@ -60,7 +61,7 @@ static OutputTxLogger *list = NULL; int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *output_ctx, int tc_log_progress, - int ts_log_progress) + int ts_log_progress, TxLoggerCondition LogCondition) { int module_id = TmModuleGetIdByName(name); if (module_id < 0) @@ -73,6 +74,7 @@ int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, op->alproto = alproto; op->LogFunc = LogFunc; + op->LogCondition = LogCondition; op->output_ctx = output_ctx; op->name = name; op->module_id = (TmmId) module_id; @@ -182,16 +184,25 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ if (!(AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_EOF))) { - if (tx_progress_tc < logger->tc_log_progress) { - SCLogDebug("progress not far enough, not logging"); - logger_not_logged = 1; - goto next; - } - - if (tx_progress_ts < logger->ts_log_progress) { - SCLogDebug("progress not far enough, not logging"); - logger_not_logged = 1; - goto next; + if (logger->LogCondition) { + int r = logger->LogCondition(tv, p, alstate, tx, tx_id); + if (r == FALSE) { + SCLogDebug("conditions not met, not logging"); + logger_not_logged = 1; + goto next; + } + } else { + if (tx_progress_tc < logger->tc_log_progress) { + SCLogDebug("progress not far enough, not logging"); + logger_not_logged = 1; + goto next; + } + + if (tx_progress_ts < logger->ts_log_progress) { + SCLogDebug("progress not far enough, not logging"); + logger_not_logged = 1; + goto next; + } } } diff --git a/src/output-tx.h b/src/output-tx.h index e8e8163d8907..e73c305ce64b 100644 --- a/src/output-tx.h +++ b/src/output-tx.h @@ -34,10 +34,11 @@ typedef int (*TxLogger)(ThreadVars *, void *thread_data, const Packet *, Flow *f /** packet logger condition function pointer type, * must return true for packets that should be logged */ -//typedef int (*TxLogCondition)(ThreadVars *, const Packet *); +typedef int (*TxLoggerCondition)(ThreadVars *, const Packet *, void *state, void *tx, uint64_t tx_id); int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, - OutputCtx *, int tc_log_progress, int ts_log_progress); + OutputCtx *, int tc_log_progress, int ts_log_progress, + TxLoggerCondition LogCondition); void TmModuleTxLoggerRegister (void); diff --git a/src/output.c b/src/output.c index 6a9ab3a6a3c1..e0f86ae0fda5 100644 --- a/src/output.c +++ b/src/output.c @@ -150,16 +150,17 @@ OutputRegisterPacketSubModule(const char *parent_name, const char *name, } /** - * \brief Register a tx output module with progress. + * \brief Wrapper function for tx output modules. * * This function will register an output module so it can be * configured with the configuration file. * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, +void OutputRegisterTxModuleWrapper(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress) + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, + TxLoggerCondition TxLogCondition) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -174,6 +175,7 @@ void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, module->conf_name = conf_name; module->InitFunc = InitFunc; module->TxLogFunc = TxLogFunc; + module->TxLogCondition = TxLogCondition; module->alproto = alproto; module->tc_log_progress = tc_log_progress; module->ts_log_progress = ts_log_progress; @@ -186,10 +188,11 @@ void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, exit(EXIT_FAILURE); } -void OutputRegisterTxSubModuleWithProgress(const char *parent_name, +void OutputRegisterTxSubModuleWrapper(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, - int tc_log_progress, int ts_log_progress) + int tc_log_progress, int ts_log_progress, + TxLoggerCondition TxLogCondition) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -205,6 +208,7 @@ void OutputRegisterTxSubModuleWithProgress(const char *parent_name, module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->TxLogFunc = TxLogFunc; + module->TxLogCondition = TxLogCondition; module->alproto = alproto; module->tc_log_progress = tc_log_progress; module->ts_log_progress = ts_log_progress; @@ -217,6 +221,59 @@ void OutputRegisterTxSubModuleWithProgress(const char *parent_name, exit(EXIT_FAILURE); } +/** + * \brief Register a tx output module with condition. + * + * This function will register an output module so it can be + * configured with the configuration file. + * + * \retval Returns 0 on success, -1 on failure. + */ +void OutputRegisterTxModuleWithCondition(const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + TxLogger TxLogFunc, TxLoggerCondition TxLogCondition) +{ + OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, + TxLogFunc, 0, 0, TxLogCondition); +} + +void OutputRegisterTxSubModuleWithCondition(const char *parent_name, + const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, + OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, + TxLoggerCondition TxLogCondition) +{ + OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, InitFunc, + alproto, TxLogFunc, 0, 0, + TxLogCondition); +} + +/** + * \brief Register a tx output module with progress. + * + * This function will register an output module so it can be + * configured with the configuration file. + * + * \retval Returns 0 on success, -1 on failure. + */ +void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress) +{ + OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, + TxLogFunc, tc_log_progress, ts_log_progress, + NULL); +} + +void OutputRegisterTxSubModuleWithProgress(const char *parent_name, + const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, + OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, + int tc_log_progress, int ts_log_progress) +{ + OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, InitFunc, + alproto, TxLogFunc, tc_log_progress, + ts_log_progress, NULL); +} + /** * \brief Register a tx output module. * @@ -230,9 +287,8 @@ OutputRegisterTxModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc) { - /* wrapper function */ - OutputRegisterTxModuleWithProgress(name, conf_name, InitFunc, alproto, - TxLogFunc, 0, 0); + OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, + TxLogFunc, 0, 0, NULL); } void @@ -240,9 +296,8 @@ OutputRegisterTxSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc) { - /* wrapper function */ - OutputRegisterTxSubModuleWithProgress(parent_name, name, conf_name, - InitFunc, alproto, TxLogFunc, 0, 0); + OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, + InitFunc, alproto, TxLogFunc, 0, 0, NULL); } /** diff --git a/src/output.h b/src/output.h index 85ae93252755..91d8bd2708c1 100644 --- a/src/output.h +++ b/src/output.h @@ -48,6 +48,7 @@ typedef struct OutputModule_ { PacketLogger PacketLogFunc; PacketLogCondition PacketConditionFunc; TxLogger TxLogFunc; + TxLoggerCondition TxLogCondition; FileLogger FileLogFunc; FiledataLogger FiledataLogFunc; FlowLogger FlowLogFunc; @@ -77,6 +78,14 @@ void OutputRegisterTxSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc); +void OutputRegisterTxModuleWithCondition(const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + TxLogger TxLogFunc, TxLoggerCondition TxLogCondition); +void OutputRegisterTxSubModuleWithCondition(const char *parent_name, + const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, + OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, + TxLoggerCondition TxLogCondition); + void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress); diff --git a/src/runmodes.c b/src/runmodes.c index e0154a1f55a5..fa920cec1ca5 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -618,7 +618,7 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu SCLogDebug("%s is a tx logger", module->name); OutputRegisterTxLogger(module->name, module->alproto, module->TxLogFunc, output_ctx, module->tc_log_progress, - module->ts_log_progress); + module->ts_log_progress, module->TxLogCondition); /* need one instance of the tx logger module */ if (tx_logger_module == NULL) { From ed33f5f14859b6bbe2b290ee5351e9a445e1a9aa Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 12 May 2016 08:14:52 +0200 Subject: [PATCH 1373/2553] tlsstore: use TxLogger --- src/app-layer-ssl.h | 3 --- src/log-tlsstore.c | 41 ++++++++++++++--------------------------- 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index d42f3c535d7d..991b4c2bdd71 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -93,9 +93,6 @@ enum { /* flag to indicate that handshake is done */ #define SSL_AL_FLAG_HANDSHAKE_DONE 0x80000 -/* flags for file storage */ -#define SSL_AL_FLAG_STATE_STORED 0x40000 - /* config flags */ #define SSL_TLS_LOG_PEM (1 << 0) diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c index afb6e4a03970..a572a627ac88 100644 --- a/src/log-tlsstore.c +++ b/src/log-tlsstore.c @@ -244,7 +244,8 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s * \brief Condition function for TLS logger * \retval bool true or false -- log now? */ -static int LogTlsStoreCondition(ThreadVars *tv, const Packet *p) +static int LogTlsStoreCondition(ThreadVars *tv, const Packet *p, void *state, + void *tx, uint64_t tx_id) { if (p->flow == NULL) { return FALSE; @@ -254,57 +255,39 @@ static int LogTlsStoreCondition(ThreadVars *tv, const Packet *p) return FALSE; } - FLOWLOCK_RDLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto dontlog; - - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, so no request logging"); goto dontlog; } - /* we only log the state once if we don't have to write - * the cert due to tls.store keyword. */ - if (!(ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) && - (ssl_state->flags & SSL_AL_FLAG_STATE_STORED)) + if ((ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) == 0) goto dontlog; if (ssl_state->server_connp.cert0_issuerdn == NULL || ssl_state->server_connp.cert0_subject == NULL) goto dontlog; - FLOWLOCK_UNLOCK(p->flow); return TRUE; dontlog: - FLOWLOCK_UNLOCK(p->flow); return FALSE; } -static int LogTlsStoreLogger(ThreadVars *tv, void *thread_data, const Packet *p) +static int LogTlsStoreLogger(ThreadVars *tv, void *thread_data, const Packet *p, + Flow *f, void *state, void *tx, uint64_t tx_id) { LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)thread_data; int ipproto = (PKT_IS_IPV4(p)) ? AF_INET : AF_INET6; - /* check if we have TLS state or not */ - FLOWLOCK_WRLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto end; - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + SSLState *ssl_state = (SSLState *)state; if (unlikely(ssl_state == NULL)) { - goto end; + return 0; } if (ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) { LogTlsLogPem(aft, p, ssl_state, ipproto); } - /* we only store the state once */ - ssl_state->flags |= SSL_AL_FLAG_STATE_STORED; -end: - FLOWLOCK_UNLOCK(p->flow); return 0; } @@ -415,6 +398,9 @@ static OutputCtx *LogTlsStoreLogInitCtx(ConfNode *conf) SCLogInfo("storing certs in %s", tls_logfile_base_dir); + /* enable the logger for the app layer */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); + SCReturnPtr(output_ctx, "OutputCtx"); } @@ -430,8 +416,9 @@ void TmModuleLogTlsStoreRegister (void) tmm_modules[TMM_TLSSTORE].flags = TM_FLAG_LOGAPI_TM; tmm_modules[TMM_TLSSTORE].priority = 10; - OutputRegisterPacketModule(MODULE_NAME, "tls-store", LogTlsStoreLogInitCtx, - LogTlsStoreLogger, LogTlsStoreCondition); + OutputRegisterTxModuleWithCondition(MODULE_NAME, "tls-store", + LogTlsStoreLogInitCtx, ALPROTO_TLS, LogTlsStoreLogger, + LogTlsStoreCondition); SC_ATOMIC_INIT(cert_id); From 45342078e4032deb0916b0f7fb11f1471bf05ee7 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 13 May 2016 08:00:19 +0200 Subject: [PATCH 1374/2553] tlsstore: fix memleak Bug #1771. Direct leak of 1834 byte(s) in 1 object(s) allocated from: #0 0x4e2e65 in realloc ??:? #1 0xcec27b in LogTlsLogPem /home/mats/suricata/src/log-tlsstore.c:130 #2 0xcea4f5 in LogTlsStoreLogger /home/mats/suricata/src/log-tlsstore.c:303 #3 0xd8b99c in OutputPacketLog /home/mats/suricata/src/output-packet.c:104 --- src/log-tlsstore.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c index a572a627ac88..317f80ffc4b7 100644 --- a/src/log-tlsstore.c +++ b/src/log-tlsstore.c @@ -166,6 +166,7 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s goto end_fwrite_fp; } fclose(fp); + SCFree(aft->enc_buf); //Logging certificate informations memcpy(filename + (strlen(filename) - 3), "meta", 4); @@ -222,6 +223,7 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s end_fwrite_fp: fclose(fp); + SCFree(aft->enc_buf); if (logging_dir_not_writable < LOGGING_WRITE_ISSUE_LIMIT) { SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate"); logging_dir_not_writable++; From 667e4e68bf01e0cc19d0cac501ae6d4df80095e9 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 16 May 2016 01:21:33 -0600 Subject: [PATCH 1375/2553] configure.ac: escape $srcdir when used in a variable $srcdir needs to be escaped for proper expansion when used as part of a Makefile variable. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 16ca5edd4fd6..c6c5e9a172d9 100644 --- a/configure.ac +++ b/configure.ac @@ -1273,7 +1273,7 @@ HTP_LDADD="../libhtp/htp/libhtp.la" AC_SUBST(HTP_LDADD) # make sure libhtp is added to the includes - CPPFLAGS="-I${srcdir}/../libhtp/ ${CPPFLAGS}" + CPPFLAGS="-I\${srcdir}/../libhtp/ ${CPPFLAGS}" AC_CHECK_HEADER(iconv.h,,[AC_ERROR(iconv.h not found ...)]) AC_CHECK_LIB(iconv, libiconv_close) From 90414472eda57134ca58cb9f338df2d169520896 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 May 2016 18:35:26 +0200 Subject: [PATCH 1376/2553] thread storage: fix memset 0 after realloc Thread storage expansion would not properly memset 0 the new part of the memory. --- src/tm-threads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index b21770e4ea7c..1d7b5fe149cc 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -2283,7 +2283,7 @@ int TmThreadsRegisterThread(ThreadVars *tv, const int type) void *newmem = SCRealloc(thread_store.threads, ((thread_store.threads_size + STEP) * sizeof(Thread))); BUG_ON(newmem == NULL); thread_store.threads = newmem; - memset((uint8_t *)thread_store.threads + (thread_store.threads_size * sizeof(Thread)), 0x00, STEP); + memset((uint8_t *)thread_store.threads + (thread_store.threads_size * sizeof(Thread)), 0x00, STEP * sizeof(Thread)); Thread *t = &thread_store.threads[thread_store.threads_size]; t->name = tv->name; From 80716f860e72758cd032dec91376d056fb80743f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 7 May 2016 17:20:12 +0200 Subject: [PATCH 1377/2553] app-layer: test fixes --- src/app-layer.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 9c058800ae59..b0955769c995 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -676,7 +676,6 @@ static int AppLayerTest01(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -688,6 +687,7 @@ static int AppLayerTest01(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -916,7 +916,6 @@ static int AppLayerTest02(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -928,6 +927,7 @@ static int AppLayerTest02(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); /* handshake */ tcph.th_win = htons(5480); @@ -1205,7 +1205,6 @@ static int AppLayerTest03(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -1217,6 +1216,7 @@ static int AppLayerTest03(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -1444,7 +1444,6 @@ static int AppLayerTest04(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -1456,6 +1455,7 @@ static int AppLayerTest04(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); /* handshake */ tcph.th_win = htons(5480); @@ -1732,7 +1732,6 @@ static int AppLayerTest05(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -1744,6 +1743,7 @@ static int AppLayerTest05(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -1972,7 +1972,6 @@ static int AppLayerTest06(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -1984,6 +1983,7 @@ static int AppLayerTest06(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -2188,7 +2188,6 @@ static int AppLayerTest07(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -2200,6 +2199,7 @@ static int AppLayerTest07(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -2428,7 +2428,6 @@ static int AppLayerTest08(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -2440,6 +2439,7 @@ static int AppLayerTest08(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -2670,7 +2670,6 @@ static int AppLayerTest09(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -2682,6 +2681,7 @@ static int AppLayerTest09(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -2951,7 +2951,6 @@ static int AppLayerTest10(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -2963,6 +2962,7 @@ static int AppLayerTest10(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -3208,7 +3208,6 @@ static int AppLayerTest11(void) memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); @@ -3220,6 +3219,7 @@ static int AppLayerTest11(void) int ret = 0; StreamTcpInitConfig(TRUE); + StreamTcpThreadInit(&tv, NULL, (void **)&stt); tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; From fbf0a7aa45254405e2432a73cfa9935b5d181fba Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 7 May 2016 17:21:04 +0200 Subject: [PATCH 1378/2553] detect app-layer-event: fix tests --- src/detect-app-layer-event.c | 147 +++++++++++------------------------ 1 file changed, 44 insertions(+), 103 deletions(-) diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 173313aa1491..8ca0804bf0ca 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -44,7 +44,7 @@ #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" - +#include "stream-tcp-util.h" static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx); @@ -489,7 +489,6 @@ int DetectAppLayerEventTest02(void) int DetectAppLayerEventTest03(void) { - int result = 0; ThreadVars tv; TcpReassemblyThreadCtx *ra_ctx = NULL; Packet *p = NULL; @@ -530,70 +529,53 @@ int DetectAppLayerEventTest03(void) ssn.data_first_seen_dir = STREAM_TOSERVER; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(app-layer-event: applayer_mismatch_protocol_both_directions; " "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); - if (f == NULL) - goto end; + FAIL_IF(f == NULL); FLOW_INITIALIZE(f); f->protoctx = &ssn; f->proto = IPPROTO_TCP; f->flags |= FLOW_IPV4; p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - goto end; + FAIL_IF(unlikely(p == NULL)); p->flow = f; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; - ra_ctx = StreamTcpReassembleInitThreadCtx(&tv); - if (ra_ctx == NULL) - goto end; - StreamTcpInitConfig(TRUE); + StreamTcpUTInit(&ra_ctx); p->flowflags = FLOW_PKT_TOSERVER; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, - sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF(AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, + sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0); + SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } + + FAIL_IF (PacketAlertCheck(p, 1)); p->flowflags = FLOW_PKT_TOCLIENT; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, - sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, + sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0); + SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - result = 1; - end: - return result; + FAIL_IF(PacketAlertCheck(p, 1)); + + StreamTcpUTDeinit(ra_ctx); + PASS; } int DetectAppLayerEventTest04(void) { - int result = 0; ThreadVars tv; TcpReassemblyThreadCtx *ra_ctx = NULL; Packet *p = NULL; @@ -634,70 +616,49 @@ int DetectAppLayerEventTest04(void) ssn.data_first_seen_dir = STREAM_TOSERVER; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF (de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(app-layer-event: applayer_detect_protocol_only_one_direction; " "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); - if (f == NULL) - goto end; + FAIL_IF (f == NULL); FLOW_INITIALIZE(f); f->protoctx = &ssn; f->proto = IPPROTO_TCP; f->flags |= FLOW_IPV4; p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - goto end; + FAIL_IF(unlikely(p == NULL)); p->flow = f; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; - ra_ctx = StreamTcpReassembleInitThreadCtx(&tv); - if (ra_ctx == NULL) - goto end; - StreamTcpInitConfig(TRUE); + StreamTcpUTInit(&ra_ctx); p->flowflags = FLOW_PKT_TOSERVER; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, - sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF(AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, + sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0); SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } + FAIL_IF (PacketAlertCheck(p, 1)); p->flowflags = FLOW_PKT_TOCLIENT; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, - sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, + sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0); SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sid 1 didn't match but should have\n"); - goto end; - } + FAIL_IF (!PacketAlertCheck(p, 1)); - result = 1; - end: - return result; + StreamTcpUTDeinit(ra_ctx); + PASS; } int DetectAppLayerEventTest05(void) { - int result = 0; ThreadVars tv; TcpReassemblyThreadCtx *ra_ctx = NULL; Packet *p = NULL; @@ -754,65 +715,45 @@ int DetectAppLayerEventTest05(void) ssn.data_first_seen_dir = STREAM_TOSERVER; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF (de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(app-layer-event: applayer_mismatch_protocol_both_directions; " "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; + FAIL_IF (de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); - if (f == NULL) - goto end; + FAIL_IF (f == NULL); FLOW_INITIALIZE(f); f->protoctx = &ssn; f->proto = IPPROTO_TCP; f->flags |= FLOW_IPV4; p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - goto end; + FAIL_IF (unlikely(p == NULL)); p->flow = f; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; - ra_ctx = StreamTcpReassembleInitThreadCtx(&tv); - if (ra_ctx == NULL) - goto end; - StreamTcpInitConfig(TRUE); + StreamTcpUTInit(&ra_ctx); p->flowflags = FLOW_PKT_TOSERVER; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, - sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, + sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0); SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } + FAIL_IF (PacketAlertCheck(p, 1)); p->flowflags = FLOW_PKT_TOCLIENT; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, - sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, + sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0); SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sid 1 didn't match but should have\n"); - goto end; - } + FAIL_IF (!PacketAlertCheck(p, 1)); - result = 1; - end: - return result; + StreamTcpUTDeinit(ra_ctx); + PASS; } #endif /* UNITTESTS */ From d84dc02bd706694a97f99775239e5af67e6c6104 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 7 May 2016 17:22:22 +0200 Subject: [PATCH 1379/2553] tcp sack: improve tests --- src/stream-tcp-sack.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/stream-tcp-sack.c b/src/stream-tcp-sack.c index 9d0071aac69d..d3be60e9200c 100644 --- a/src/stream-tcp-sack.c +++ b/src/stream-tcp-sack.c @@ -396,6 +396,7 @@ static int StreamTcpSackTest01 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -432,6 +433,7 @@ static int StreamTcpSackTest02 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -470,6 +472,7 @@ static int StreamTcpSackTest03 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -505,6 +508,7 @@ static int StreamTcpSackTest04 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -540,6 +544,7 @@ static int StreamTcpSackTest05 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -577,6 +582,7 @@ static int StreamTcpSackTest06 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -623,6 +629,7 @@ static int StreamTcpSackTest07 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -669,6 +676,7 @@ static int StreamTcpSackTest08 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -716,6 +724,7 @@ static int StreamTcpSackTest09 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -762,6 +771,7 @@ static int StreamTcpSackTest10 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -808,6 +818,7 @@ static int StreamTcpSackTest11 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -861,6 +872,7 @@ static int StreamTcpSackTest12 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -893,6 +905,7 @@ static int StreamTcpSackTest13 (void) { retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -925,6 +938,7 @@ static int StreamTcpSackTest14 (void) { retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } From ce408c4d107342c6c078a9fc8e7d047f8abac398 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Thu, 28 Apr 2016 15:23:05 +1000 Subject: [PATCH 1380/2553] spm: add SinglePatternMatchDefaultMatcher Allows selecting SPM algorithm with the 'spm-algo' value in the YAML config file. --- src/detect-engine.c | 2 ++ src/detect.h | 1 + src/util-spm.c | 22 ++++++++++++++++++++++ src/util-spm.h | 7 +++++++ 4 files changed, 32 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index c19afc2f3318..0912167293ad 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -84,6 +84,7 @@ #include "util-action.h" #include "util-magic.h" #include "util-signal.h" +#include "util-spm.h" #include "util-var-name.h" @@ -829,6 +830,7 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) } de_ctx->mpm_matcher = PatternMatchDefaultMatcher(); + de_ctx->spm_matcher = SinglePatternMatchDefaultMatcher(); DetectEngineCtxLoadConf(de_ctx); SigGroupHeadHashInit(de_ctx); diff --git a/src/detect.h b/src/detect.h index e321d5ca1d2a..67dee32db253 100644 --- a/src/detect.h +++ b/src/detect.h @@ -587,6 +587,7 @@ typedef struct DetectEngineCtx_ { ThresholdCtx ths_ctx; uint16_t mpm_matcher; /**< mpm matcher this ctx uses */ + uint16_t spm_matcher; /**< spm matcher this ctx uses */ /* Config options */ diff --git a/src/util-spm.c b/src/util-spm.c index f4e03e288e2d..97c5587ec57d 100644 --- a/src/util-spm.c +++ b/src/util-spm.c @@ -47,12 +47,34 @@ #include "suricata.h" #include "util-unittest.h" +#include "conf.h" + #include "util-spm.h" #include "util-spm-bs.h" #include "util-spm-bs2bm.h" #include "util-spm-bm.h" #include "util-clock.h" +/** + * \brief Returns the single pattern matcher algorithm to be used, based on the + * spm-algo setting in yaml. + */ +uint16_t SinglePatternMatchDefaultMatcher(void) { + char *spm_algo; + if ((ConfGet("spm-algo", &spm_algo)) == 1) { + if (strcmp("bm", spm_algo) == 0) { + return SPM_BM; + } + + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, + "Invalid spm algo supplied " + "in the yaml conf file: \"%s\"", + spm_algo); + exit(EXIT_FAILURE); + } + + return SPM_BM; /* default to Boyer-Moore */ +} /** * Wrappers for building context and searching (Bs2Bm and boyermoore) diff --git a/src/util-spm.h b/src/util-spm.h index bd1826923143..11149867a1bf 100644 --- a/src/util-spm.h +++ b/src/util-spm.h @@ -28,6 +28,13 @@ #include "util-spm-bs2bm.h" #include "util-spm-bm.h" +enum { + SPM_BM, /* Boyer-Moore */ + /* Other SPM matchers will go here. */ +}; + +uint16_t SinglePatternMatchDefaultMatcher(void); + /** Default algorithm to use: Boyer Moore */ uint8_t *Bs2bmSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); uint8_t *Bs2bmNocaseSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); From 7ba9dbe36ac055a2bb99197f68afd9b0eecbb5b2 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Thu, 12 May 2016 13:08:30 +1000 Subject: [PATCH 1381/2553] suricata.yaml: document spm-algo option --- suricata.yaml.in | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/suricata.yaml.in b/suricata.yaml.in index b5d292ca8a79..12a18faf17e4 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -725,6 +725,13 @@ cuda: mpm-algo: ac +# Select the matching algorithm you want to use for single-pattern searches. +# +# Supported algorithms are "bm" (Boyer-Moore) and "hs" (Hyperscan, only +# available if Suricata has been built with Hyperscan support). + +spm-algo: bm + # Defrag settings: defrag: From cce2d114e8a8175240c65aba572666b5faa05709 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Wed, 11 May 2016 14:10:27 +1000 Subject: [PATCH 1382/2553] spm: add and use new SPM API This new API allows for different SPM implementations, using a function pointer table like that used for MPM. This change also switches over the paths that make use of DetectContentData (which previously used BoyerMoore directly) to the new API. --- src/app-layer-detect-proto.c | 40 +++- src/detect-content.c | 166 ++++++++++++--- src/detect-content.h | 12 +- src/detect-engine-content-inspection.c | 7 +- src/detect-engine.c | 18 ++ src/detect-http-client-body.c | 2 +- src/detect-http-hh.c | 2 +- src/detect-http-hrh.c | 2 +- src/detect-http-server-body.c | 2 +- src/detect-http-ua.c | 2 +- src/detect-nocase.c | 14 +- src/detect-uricontent.c | 3 +- src/detect-uricontent.h | 1 - src/detect.h | 9 + src/runmode-unittests.c | 1 + src/suricata.c | 1 + src/util-spm-bm.c | 131 ++++++++++++ src/util-spm-bm.h | 2 + src/util-spm.c | 275 ++++++++++++++++++++++++- src/util-spm.h | 55 +++++ 20 files changed, 687 insertions(+), 58 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 323e0857ab8b..aeed07259a60 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -142,6 +142,9 @@ typedef struct AppLayerProtoDetectCtx_ { * implemented if needed. Waste of space otherwise. */ AppLayerProtoDetectCtxIpproto ctx_ipp[FLOW_PROTO_DEFAULT]; + /* Global SPM thread context prototype. */ + SpmGlobalThreadCtx *spm_global_thread_ctx; + AppLayerProtoDetectProbingParser *ctx_pp; /* Indicates the protocols that have registered themselves @@ -157,6 +160,7 @@ struct AppLayerProtoDetectThreadCtx_ { PatternMatcherQueue pmq; /* The value 2 is for direction(0 - toserver, 1 - toclient). */ MpmThreadCtx mpm_tctx[FLOW_PROTO_DEFAULT][2]; + SpmThreadCtx *spm_thread_ctx; }; /* The global app layer proto detection context. */ @@ -167,6 +171,7 @@ static AppLayerProtoDetectCtx alpd_ctx; /** \internal * \brief Handle SPM search for Signature */ static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMSignature *s, + AppLayerProtoDetectThreadCtx *tctx, uint8_t *buf, uint16_t buflen, uint8_t ipproto) { @@ -191,10 +196,7 @@ static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMS SCLogDebug("s->co->offset (%"PRIu16") s->cd->depth (%"PRIu16")", s->cd->offset, s->cd->depth); - if (s->cd->flags & DETECT_CONTENT_NOCASE) - found = BoyerMooreNocase(s->cd->content, s->cd->content_len, sbuf, sbuflen, s->cd->bm_ctx); - else - found = BoyerMoore(s->cd->content, s->cd->content_len, sbuf, sbuflen, s->cd->bm_ctx); + found = SpmScan(s->cd->spm_ctx, tctx->spm_thread_ctx, sbuf, sbuflen); if (found != NULL) proto = s->alproto; @@ -260,7 +262,7 @@ static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx const AppLayerProtoDetectPMSignature *s = pm_ctx->map[tctx->pmq.rule_id_array[cnt]]; while (s != NULL) { AppProto proto = AppLayerProtoDetectPMMatchSignature(s, - buf, searchlen, ipproto); + tctx, buf, searchlen, ipproto); /* store each unique proto once */ if (proto != ALPROTO_UNKNOWN && @@ -1240,13 +1242,20 @@ static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alprot DetectContentData *cd; int ret = 0; - cd = DetectContentParseEncloseQuotes(pattern); + cd = DetectContentParseEncloseQuotes(alpd_ctx.spm_global_thread_ctx, + pattern); if (cd == NULL) goto error; cd->depth = depth; cd->offset = offset; if (!is_cs) { - BoyerMooreCtxToNocase(cd->bm_ctx, cd->content, cd->content_len); + /* Rebuild as nocase */ + SpmDestroyCtx(cd->spm_ctx); + cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1, + alpd_ctx.spm_global_thread_ctx); + if (cd->spm_ctx == NULL) { + goto error; + } cd->flags |= DETECT_CONTENT_NOCASE; } if (depth < cd->content_len) @@ -1518,6 +1527,13 @@ int AppLayerProtoDetectSetup(void) memset(&alpd_ctx, 0, sizeof(alpd_ctx)); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + alpd_ctx.spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + if (alpd_ctx.spm_global_thread_ctx == NULL) { + SCLogError(SC_ERR_FATAL, "Unable to alloc SpmGlobalThreadCtx."); + exit(EXIT_FAILURE); + } + for (i = 0; i < FLOW_PROTO_DEFAULT; i++) { for (j = 0; j < 2; j++) { MpmInitCtx(&alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx, MPM_AC); @@ -1550,6 +1566,8 @@ int AppLayerProtoDetectDeSetup(void) } } + SpmDestroyGlobalThreadCtx(alpd_ctx.spm_global_thread_ctx); + AppLayerProtoDetectFreeProbingParsers(alpd_ctx.ctx_pp); SCReturnInt(0); @@ -1674,6 +1692,11 @@ AppLayerProtoDetectThreadCtx *AppLayerProtoDetectGetCtxThread(void) } } + alpd_tctx->spm_thread_ctx = SpmMakeThreadCtx(alpd_ctx.spm_global_thread_ctx); + if (alpd_tctx->spm_thread_ctx == NULL) { + goto error; + } + goto end; error: if (alpd_tctx != NULL) @@ -1699,6 +1722,9 @@ void AppLayerProtoDetectDestroyCtxThread(AppLayerProtoDetectThreadCtx *alpd_tctx } } PmqFree(&alpd_tctx->pmq); + if (alpd_tctx->spm_thread_ctx != NULL) { + SpmDestroyThreadCtx(alpd_tctx->spm_thread_ctx); + } SCFree(alpd_tctx); SCReturn; diff --git a/src/detect-content.c b/src/detect-content.c index 372a5da1eae4..1bbb6f7c18b9 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -41,7 +41,7 @@ #include "util-unittest.h" #include "util-print.h" #include "util-debug.h" -#include "util-spm-bm.h" +#include "util-spm.h" #include "threads.h" #include "util-unittest-helper.h" #include "pkt-var.h" @@ -217,7 +217,8 @@ int DetectContentDataParse(const char *keyword, const char *contentstr, * \brief DetectContentParse * \initonly */ -DetectContentData *DetectContentParse (char *contentstr) +DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, + char *contentstr) { DetectContentData *cd = NULL; uint8_t *content = NULL; @@ -245,8 +246,15 @@ DetectContentData *DetectContentParse (char *contentstr) memcpy(cd->content, content, len); cd->content_len = len; - /* Prepare Boyer Moore context for searching faster */ - cd->bm_ctx = BoyerMooreCtxInit(cd->content, cd->content_len); + /* Prepare SPM search context. */ + cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 0, + spm_global_thread_ctx); + if (cd->spm_ctx == NULL) { + SCFree(content); + SCFree(cd); + return NULL; + } + cd->depth = 0; cd->offset = 0; cd->within = 0; @@ -257,7 +265,8 @@ DetectContentData *DetectContentParse (char *contentstr) } -DetectContentData *DetectContentParseEncloseQuotes(char *contentstr) +DetectContentData *DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx, + char *contentstr) { char str[strlen(contentstr) + 3]; // 2 for quotes, 1 for \0 @@ -266,7 +275,7 @@ DetectContentData *DetectContentParseEncloseQuotes(char *contentstr) str[strlen(contentstr) + 1] = '\"'; str[strlen(contentstr) + 2] = '\0'; - return DetectContentParse(str); + return DetectContentParse(spm_global_thread_ctx, str); } /** @@ -370,7 +379,7 @@ int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentstr) DetectContentData *cd = NULL; SigMatch *sm = NULL; - cd = DetectContentParse(contentstr); + cd = DetectContentParse(de_ctx->spm_global_thread_ctx, contentstr); if (cd == NULL) goto error; DetectContentPrint(cd); @@ -415,7 +424,7 @@ void DetectContentFree(void *ptr) if (cd == NULL) SCReturn; - BoyerMooreCtxDeInit(cd->bm_ctx); + SpmDestroyCtx(cd->spm_ctx); SCFree(cd); SCReturn; @@ -433,7 +442,11 @@ int DetectContentParseTest01 (void) char *teststring = "\"abc\\:def\""; char *teststringparsed = "abc:def"; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); @@ -446,6 +459,7 @@ int DetectContentParseTest01 (void) SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -459,7 +473,11 @@ int DetectContentParseTest02 (void) char *teststring = "\"abc\\;def\""; char *teststringparsed = "abc;def"; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); @@ -472,6 +490,7 @@ int DetectContentParseTest02 (void) SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -485,7 +504,11 @@ int DetectContentParseTest03 (void) char *teststring = "\"abc\\\"def\""; char *teststringparsed = "abc\"def"; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); @@ -498,6 +521,7 @@ int DetectContentParseTest03 (void) SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -511,7 +535,11 @@ int DetectContentParseTest04 (void) char *teststring = "\"abc\\\\def\""; char *teststringparsed = "abc\\def"; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { uint16_t len = (cd->content_len > strlen(teststringparsed)); if (memcmp(cd->content, teststringparsed, len) != 0) { @@ -525,6 +553,7 @@ int DetectContentParseTest04 (void) SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -537,7 +566,11 @@ int DetectContentParseTest05 (void) DetectContentData *cd = NULL; char *teststring = "\"abc\\def\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { SCLogDebug("expected NULL got "); PrintRawUriFp(stdout,cd->content,cd->content_len); @@ -545,6 +578,7 @@ int DetectContentParseTest05 (void) result = 0; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -558,7 +592,11 @@ int DetectContentParseTest06 (void) char *teststring = "\"a|42|c|44|e|46|\""; char *teststringparsed = "abcdef"; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { uint16_t len = (cd->content_len > strlen(teststringparsed)); if (memcmp(cd->content, teststringparsed, len) != 0) { @@ -572,6 +610,7 @@ int DetectContentParseTest06 (void) SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -584,12 +623,17 @@ int DetectContentParseTest07 (void) DetectContentData *cd = NULL; char *teststring = "\"\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { SCLogDebug("expected NULL got %p: ", cd); result = 0; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -602,12 +646,17 @@ int DetectContentParseTest08 (void) DetectContentData *cd = NULL; char *teststring = "\"\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { SCLogDebug("expected NULL got %p: ", cd); result = 0; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -887,14 +936,18 @@ int DetectContentParseTest09(void) DetectContentData *cd = NULL; char *teststring = "!\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } - + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -904,13 +957,18 @@ int DetectContentParseTest10(void) DetectContentData *cd = NULL; char *teststring = "!\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -920,13 +978,18 @@ int DetectContentParseNegTest11(void) DetectContentData *cd = NULL; char *teststring = "\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (!(cd->flags & DETECT_CONTENT_NEGATED)) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -936,13 +999,18 @@ int DetectContentParseNegTest12(void) DetectContentData *cd = NULL; char *teststring = "\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (!(cd->flags & DETECT_CONTENT_NEGATED)) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -952,13 +1020,18 @@ int DetectContentParseNegTest13(void) DetectContentData *cd = NULL; char *teststring = "!\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -968,13 +1041,18 @@ int DetectContentParseNegTest14(void) DetectContentData *cd = NULL; char *teststring = " \"!boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (!(cd->flags & DETECT_CONTENT_NEGATED)) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -984,13 +1062,18 @@ int DetectContentParseNegTest15(void) DetectContentData *cd = NULL; char *teststring = " !\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -1000,11 +1083,16 @@ int DetectContentParseNegTest16(void) DetectContentData *cd = NULL; char *teststring = " \"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { result = (cd->content_len == 3 && memcmp(cd->content,"boo",3) == 0); DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -2095,12 +2183,17 @@ int DetectContentParseTest41(void) teststring[idx++] = '\"'; teststring[idx++] = '\0'; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd == NULL) { SCLogDebug("expected not NULL"); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); SCFree(teststring); DetectContentFree(cd); return result; @@ -2125,12 +2218,17 @@ int DetectContentParseTest42(void) teststring[idx++] = '\"'; teststring[idx++] = '\0'; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd == NULL) { SCLogDebug("expected not NULL"); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); SCFree(teststring); DetectContentFree(cd); return result; @@ -2156,12 +2254,17 @@ int DetectContentParseTest43(void) teststring[idx++] = '\"'; teststring[idx++] = '\0'; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd == NULL) { SCLogDebug("expected not NULL"); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); SCFree(teststring); DetectContentFree(cd); return result; @@ -2190,12 +2293,17 @@ int DetectContentParseTest44(void) teststring[idx++] = '\"'; teststring[idx++] = '\0'; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd == NULL) { SCLogDebug("expected not NULL"); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); SCFree(teststring); DetectContentFree(cd); return result; diff --git a/src/detect-content.h b/src/detect-content.h index 51300e7ea912..5976adb86855 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -73,7 +73,7 @@ ((c)->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)) -#include "util-spm-bm.h" +#include "util-spm.h" typedef struct DetectContentData_ { uint8_t *content; @@ -92,8 +92,8 @@ typedef struct DetectContentData_ { uint16_t offset; int32_t distance; int32_t within; - /* Boyer Moore context (for spm search) */ - BmCtx *bm_ctx; + /* SPM search context. */ + SpmCtx *spm_ctx; /* pointer to replacement data */ uint8_t *replace; } DetectContentData; @@ -101,10 +101,12 @@ typedef struct DetectContentData_ { /* prototypes */ void DetectContentRegister (void); uint32_t DetectContentMaxId(DetectEngineCtx *); -DetectContentData *DetectContentParse (char *contentstr); +DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, + char *contentstr); int DetectContentDataParse(const char *keyword, const char *contentstr, uint8_t **pstr, uint16_t *plen, uint32_t *flags); -DetectContentData *DetectContentParseEncloseQuotes(char *); +DetectContentData *DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx, + char *contentstr); int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentstr); void DetectContentPrint(DetectContentData *); diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index be6d09f6cd7a..9a13d28faf18 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -48,7 +48,6 @@ #include "app-layer-dcerpc.h" #include "util-spm.h" -#include "util-spm-bm.h" #include "util-debug.h" #include "util-print.h" @@ -279,10 +278,8 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx * greater than sbuffer_len found is anyways NULL */ /* do the actual search */ - if (cd->flags & DETECT_CONTENT_NOCASE) - found = BoyerMooreNocase(cd->content, cd->content_len, sbuffer, sbuffer_len, cd->bm_ctx); - else - found = BoyerMoore(cd->content, cd->content_len, sbuffer, sbuffer_len, cd->bm_ctx); + found = SpmScan(cd->spm_ctx, det_ctx->spm_thread_ctx, sbuffer, + sbuffer_len); /* next we evaluate the result in combination with the * negation flag. */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 0912167293ad..1546aef3eed7 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -831,6 +831,13 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) de_ctx->mpm_matcher = PatternMatchDefaultMatcher(); de_ctx->spm_matcher = SinglePatternMatchDefaultMatcher(); + + de_ctx->spm_global_thread_ctx = SpmInitGlobalThreadCtx(de_ctx->spm_matcher); + if (de_ctx->spm_global_thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmGlobalThreadCtx."); + goto error; + } + DetectEngineCtxLoadConf(de_ctx); SigGroupHeadHashInit(de_ctx); @@ -941,6 +948,8 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) SigGroupCleanup(de_ctx); + SpmDestroyGlobalThreadCtx(de_ctx->spm_global_thread_ctx); + MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx); DetectEngineCtxFreeThreadKeywordData(de_ctx); @@ -1419,6 +1428,11 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * PmqSetup(&det_ctx->pmq); + det_ctx->spm_thread_ctx = SpmMakeThreadCtx(de_ctx->spm_global_thread_ctx); + if (det_ctx->spm_thread_ctx == NULL) { + return TM_ECODE_FAILED; + } + /* sized to the max of our sgh settings. A max setting of 0 implies that all * sgh's have: sgh->non_mpm_store_cnt == 0 */ if (de_ctx->non_mpm_store_cnt_max > 0) { @@ -1634,6 +1648,10 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) PmqFree(&det_ctx->pmq); + if (det_ctx->spm_thread_ctx != NULL) { + SpmDestroyThreadCtx(det_ctx->spm_thread_ctx); + } + if (det_ctx->non_mpm_id_array != NULL) SCFree(det_ctx->non_mpm_id_array); diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index e5c9a5af94b0..729629a098ba 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -123,7 +123,7 @@ void DetectHttpClientBodyFree(void *ptr) if (hcbd->content != NULL) SCFree(hcbd->content); - BoyerMooreCtxDeInit(hcbd->bm_ctx); + SpmDestroyCtx(hcbd->spm_ctx); SCFree(hcbd); SCReturn; diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 883cdbefface..859782f9f57c 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -118,7 +118,7 @@ void DetectHttpHHFree(void *ptr) if (hhhd->content != NULL) SCFree(hhhd->content); - BoyerMooreCtxDeInit(hhhd->bm_ctx); + SpmDestroyCtx(hhhd->spm_ctx); SCFree(hhhd); return; diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index 4c3cdb24e666..2663b306b222 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -118,7 +118,7 @@ void DetectHttpHRHFree(void *ptr) if (hrhhd->content != NULL) SCFree(hrhhd->content); - BoyerMooreCtxDeInit(hrhhd->bm_ctx); + SpmDestroyCtx(hrhhd->spm_ctx); SCFree(hrhhd); return; diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index 828e84e5006b..c2b7a078df99 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -127,7 +127,7 @@ void DetectHttpServerBodyFree(void *ptr) if (hsbd->content != NULL) SCFree(hsbd->content); - BoyerMooreCtxDeInit(hsbd->bm_ctx); + SpmDestroyCtx(hsbd->spm_ctx); SCFree(hsbd); SCReturn; diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index c3ee465d76ca..237b8f26e60d 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -119,7 +119,7 @@ void DetectHttpUAFree(void *ptr) if (huad->content != NULL) SCFree(huad->content); - BoyerMooreCtxDeInit(huad->bm_ctx); + SpmDestroyCtx(huad->spm_ctx); SCFree(huad); return; diff --git a/src/detect-nocase.c b/src/detect-nocase.c index 9968e3c45738..b9dbda34cf54 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -117,9 +117,21 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple nocase modifiers with the same content"); goto end; } + + /* for consistency in later use (e.g. by MPM construction and hashing), + * coerce the content string to lower-case. */ + for (uint8_t *c = cd->content; c < cd->content + cd->content_len; c++) { + *c = u8_tolower(*c); + } + cd->flags |= DETECT_CONTENT_NOCASE; /* Recreate the context with nocase chars */ - BoyerMooreCtxToNocase(cd->bm_ctx, cd->content, cd->content_len); + SpmDestroyCtx(cd->spm_ctx); + cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1, + de_ctx->spm_global_thread_ctx); + if (cd->spm_ctx == NULL) { + goto end; + } ret = 0; end: diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index 6b79636b3c5e..2955dab0ff07 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -54,7 +54,6 @@ #include "util-unittest-helper.h" #include "util-binsearch.h" #include "util-spm.h" -#include "util-spm-bm.h" #include "conf.h" /* prototypes */ @@ -95,7 +94,7 @@ void DetectUricontentFree(void *ptr) if (cd == NULL) SCReturn; - BoyerMooreCtxDeInit(cd->bm_ctx); + SpmDestroyCtx(cd->spm_ctx); SCFree(cd); SCReturn; diff --git a/src/detect-uricontent.h b/src/detect-uricontent.h index c32a923e35a6..812e69db9c85 100644 --- a/src/detect-uricontent.h +++ b/src/detect-uricontent.h @@ -27,7 +27,6 @@ #include "detect-content.h" -#include "util-spm-bm.h" #include "app-layer-htp.h" /* prototypes */ diff --git a/src/detect.h b/src/detect.h index 67dee32db253..333381457be2 100644 --- a/src/detect.h +++ b/src/detect.h @@ -33,6 +33,7 @@ #include "packet-queue.h" #include "util-mpm.h" +#include "util-spm.h" #include "util-hash.h" #include "util-hashlist.h" #include "util-debug.h" @@ -589,6 +590,10 @@ typedef struct DetectEngineCtx_ { uint16_t mpm_matcher; /**< mpm matcher this ctx uses */ uint16_t spm_matcher; /**< spm matcher this ctx uses */ + /* 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; @@ -818,6 +823,10 @@ typedef struct DetectEngineThreadCtx_ { MpmThreadCtx mtcs; /**< thread ctx for stream mpm */ PatternMatcherQueue pmq; + /** SPM thread context used for scanning. This has been cloned from the + * prototype held by DetectEngineCtx. */ + SpmThreadCtx *spm_thread_ctx; + /** ip only rules ctx */ DetectEngineIPOnlyThreadCtx io_ctx; diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 14df0c49e604..523d81afddfa 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -151,6 +151,7 @@ void RunUnittests(int list_unittests, char *regex_arg) #ifdef __SC_CUDA_SUPPORT__ MpmCudaEnvironmentSetup(); #endif + SpmTableSetup(); AppLayerSetup(); diff --git a/src/suricata.c b/src/suricata.c index d6285382ac52..37ba4aa90f8e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2225,6 +2225,7 @@ static int PostConfLoadedSetup(SCInstance *suri) #ifdef __SC_CUDA_SUPPORT__ MpmCudaEnvironmentSetup(); #endif + SpmTableSetup(); switch (suri->checksum_validation) { case 0: diff --git a/src/util-spm-bm.c b/src/util-spm-bm.c index dd16bb99dd47..906927697ecd 100644 --- a/src/util-spm-bm.c +++ b/src/util-spm-bm.c @@ -34,6 +34,7 @@ #include "suricata.h" #include "util-spm-bm.h" +#include "util-spm.h" #include "util-debug.h" #include "util-error.h" #include "util-memcpy.h" @@ -380,3 +381,133 @@ uint8_t *BoyerMooreNocase(const uint8_t *x, uint16_t m, const uint8_t *y, int32_ return NULL; } +typedef struct SpmBmCtx_ { + BmCtx *bm_ctx; + uint8_t *needle; + uint16_t needle_len; + int nocase; +} SpmBmCtx; + +static SpmCtx *BMInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *global_thread_ctx) +{ + SpmCtx *ctx = SCMalloc(sizeof(SpmCtx)); + if (ctx == NULL) { + SCLogDebug("Unable to alloc SpmCtx."); + return NULL; + } + memset(ctx, 0, sizeof(*ctx)); + ctx->matcher = SPM_BM; + + SpmBmCtx *sctx = SCMalloc(sizeof(SpmBmCtx)); + if (sctx == NULL) { + SCLogDebug("Unable to alloc SpmBmCtx."); + SCFree(ctx); + return NULL; + } + memset(sctx, 0, sizeof(*sctx)); + + sctx->needle = SCMalloc(needle_len); + if (sctx->needle == NULL) { + SCLogDebug("Unable to alloc string."); + SCFree(sctx); + SCFree(ctx); + return NULL; + } + memcpy(sctx->needle, needle, needle_len); + sctx->needle_len = needle_len; + + if (nocase) { + sctx->bm_ctx = BoyerMooreNocaseCtxInit(sctx->needle, sctx->needle_len); + sctx->nocase = 1; + } else { + sctx->bm_ctx = BoyerMooreCtxInit(sctx->needle, sctx->needle_len); + sctx->nocase = 0; + } + + ctx->ctx = sctx; + return ctx; +} + +static void BMDestroyCtx(SpmCtx *ctx) +{ + if (ctx == NULL) { + return; + } + + SpmBmCtx *sctx = ctx->ctx; + if (sctx != NULL) { + BoyerMooreCtxDeInit(sctx->bm_ctx); + if (sctx->needle != NULL) { + SCFree(sctx->needle); + } + SCFree(sctx); + } + + SCFree(ctx); +} + +static uint8_t *BMScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, + const uint8_t *haystack, uint16_t haystack_len) +{ + const SpmBmCtx *sctx = ctx->ctx; + + if (sctx->nocase) { + return BoyerMooreNocase(sctx->needle, sctx->needle_len, haystack, + haystack_len, sctx->bm_ctx); + } else { + return BoyerMoore(sctx->needle, sctx->needle_len, haystack, + haystack_len, sctx->bm_ctx); + } +} + +static SpmGlobalThreadCtx *BMInitGlobalThreadCtx(void) +{ + SpmGlobalThreadCtx *global_thread_ctx = SCMalloc(sizeof(SpmGlobalThreadCtx)); + if (global_thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmThreadCtx."); + return NULL; + } + memset(global_thread_ctx, 0, sizeof(*global_thread_ctx)); + global_thread_ctx->matcher = SPM_BM; + return global_thread_ctx; +} + +static void BMDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) +{ + if (global_thread_ctx == NULL) { + return; + } + SCFree(global_thread_ctx); +} + +static void BMDestroyThreadCtx(SpmThreadCtx *thread_ctx) +{ + if (thread_ctx == NULL) { + return; + } + SCFree(thread_ctx); +} + +static SpmThreadCtx *BMMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) { + SpmThreadCtx *thread_ctx = SCMalloc(sizeof(SpmThreadCtx)); + if (thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmThreadCtx."); + return NULL; + } + memset(thread_ctx, 0, sizeof(*thread_ctx)); + thread_ctx->matcher = SPM_BM; + return thread_ctx; +} + +void SpmBMRegister(void) +{ + spm_table[SPM_BM].name = "bm"; + spm_table[SPM_BM].InitGlobalThreadCtx = BMInitGlobalThreadCtx; + spm_table[SPM_BM].DestroyGlobalThreadCtx = BMDestroyGlobalThreadCtx; + spm_table[SPM_BM].MakeThreadCtx = BMMakeThreadCtx; + spm_table[SPM_BM].DestroyThreadCtx = BMDestroyThreadCtx; + spm_table[SPM_BM].InitCtx = BMInitCtx; + spm_table[SPM_BM].DestroyCtx = BMDestroyCtx; + spm_table[SPM_BM].Scan = BMScan; +} diff --git a/src/util-spm-bm.h b/src/util-spm-bm.h index 051a10243b75..a1c6b4c3158c 100644 --- a/src/util-spm-bm.h +++ b/src/util-spm-bm.h @@ -45,5 +45,7 @@ uint8_t *BoyerMoore(const uint8_t *x, uint16_t m, const uint8_t *y, int32_t n, B uint8_t *BoyerMooreNocase(const uint8_t *x, uint16_t m, const uint8_t *y, int32_t n, BmCtx *bm_ctx); void BoyerMooreCtxDeInit(BmCtx *); +void SpmBMRegister(void); + #endif /* __UTIL_SPM_BM__ */ diff --git a/src/util-spm.c b/src/util-spm.c index 97c5587ec57d..aa09b98bc8e0 100644 --- a/src/util-spm.c +++ b/src/util-spm.c @@ -59,11 +59,19 @@ * \brief Returns the single pattern matcher algorithm to be used, based on the * spm-algo setting in yaml. */ -uint16_t SinglePatternMatchDefaultMatcher(void) { +uint16_t SinglePatternMatchDefaultMatcher(void) +{ char *spm_algo; if ((ConfGet("spm-algo", &spm_algo)) == 1) { - if (strcmp("bm", spm_algo) == 0) { - return SPM_BM; + if (spm_algo != NULL) { + for (uint16_t i = 0; i < SPM_TABLE_SIZE; i++) { + if (spm_table[i].name == NULL) { + continue; + } + if (strcmp(spm_table[i].name, spm_algo) == 0) { + return i; + } + } } SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, @@ -76,6 +84,56 @@ uint16_t SinglePatternMatchDefaultMatcher(void) { return SPM_BM; /* default to Boyer-Moore */ } +void SpmTableSetup(void) +{ + memset(spm_table, 0, sizeof(spm_table)); + + SpmBMRegister(); +} + +SpmGlobalThreadCtx *SpmInitGlobalThreadCtx(uint16_t matcher) +{ + return spm_table[matcher].InitGlobalThreadCtx(); +} + +void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) +{ + uint16_t matcher = global_thread_ctx->matcher; + spm_table[matcher].DestroyGlobalThreadCtx(global_thread_ctx); +} + +SpmThreadCtx *SpmMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) +{ + uint16_t matcher = global_thread_ctx->matcher; + return spm_table[matcher].MakeThreadCtx(global_thread_ctx); +} + +void SpmDestroyThreadCtx(SpmThreadCtx *thread_ctx) +{ + uint16_t matcher = thread_ctx->matcher; + spm_table[matcher].DestroyThreadCtx(thread_ctx); +} + +SpmCtx *SpmInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *global_thread_ctx) +{ + uint16_t matcher = global_thread_ctx->matcher; + return spm_table[matcher].InitCtx(needle, needle_len, nocase, + global_thread_ctx); +} + +void SpmDestroyCtx(SpmCtx *ctx) +{ + spm_table[ctx->matcher].DestroyCtx(ctx); +} + +uint8_t *SpmScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, + const uint8_t *haystack, uint16_t haystack_len) +{ + uint16_t matcher = ctx->matcher; + return spm_table[matcher].Scan(ctx, thread_ctx, haystack, haystack_len); +} + /** * Wrappers for building context and searching (Bs2Bm and boyermoore) * Use them if you cant store the context @@ -2338,6 +2396,213 @@ int UtilSpmNocaseSearchStatsTest07() return 1; } +/* Unit tests for new SPM API. */ + +#define SPM_NO_MATCH UINT32_MAX + +/* Helper structure describing a particular search. */ +typedef struct SpmTestData_ { + const char *needle; + uint16_t needle_len; + const char *haystack; + uint16_t haystack_len; + int nocase; + uint32_t match_offset; /* offset in haystack, or SPM_NO_MATCH. */ +} SpmTestData; + +/* Helper function to conduct a search with a particular SPM matcher. */ +static int SpmTestSearch(const SpmTestData *d, uint16_t matcher) +{ + int ret = 1; + SpmGlobalThreadCtx *global_thread_ctx = NULL; + SpmThreadCtx *thread_ctx = NULL; + SpmCtx *ctx = NULL; + uint8_t *found = NULL; + + global_thread_ctx = SpmInitGlobalThreadCtx(matcher); + if (global_thread_ctx == NULL) { + ret = 0; + goto exit; + } + + ctx = SpmInitCtx((const uint8_t *)d->needle, d->needle_len, d->nocase, + global_thread_ctx); + if (ctx == NULL) { + ret = 0; + goto exit; + } + + thread_ctx = SpmMakeThreadCtx(global_thread_ctx); + if (thread_ctx == NULL) { + ret = 0; + goto exit; + } + + found = SpmScan(ctx, thread_ctx, (const uint8_t *)d->haystack, + d->haystack_len); + if (found == NULL) { + if (d->match_offset != SPM_NO_MATCH) { + printf(" should have matched at %" PRIu32 " but didn't\n", + d->match_offset); + ret = 0; + } + } else { + uint32_t offset = (uint32_t)(found - (const uint8_t *)d->haystack); + if (offset != d->match_offset) { + printf(" should have matched at %" PRIu32 + " but matched at %" PRIu32 "\n", + d->match_offset, offset); + ret = 0; + } + } + +exit: + SpmDestroyCtx(ctx); + SpmDestroyThreadCtx(thread_ctx); + SpmDestroyGlobalThreadCtx(global_thread_ctx); + return ret; +} + +int SpmSearchTest01() { + SpmTableSetup(); + printf("\n"); + + /* Each of the following tests will be run against every registered SPM + * algorithm. */ + + static const SpmTestData data[] = { + /* Some trivial single-character case/nocase tests */ + {"a", 1, "a", 1, 0, 0}, + {"a", 1, "A", 1, 1, 0}, + {"A", 1, "A", 1, 0, 0}, + {"A", 1, "a", 1, 1, 0}, + {"a", 1, "A", 1, 0, SPM_NO_MATCH}, + {"A", 1, "a", 1, 0, SPM_NO_MATCH}, + /* Nulls and odd characters */ + {"\x00", 1, "test\x00test", 9, 0, 4}, + {"\x00", 1, "testtest", 8, 0, SPM_NO_MATCH}, + {"\n", 1, "new line\n", 9, 0, 8}, + {"\n", 1, "new line\x00\n", 10, 0, 9}, + {"\xff", 1, "abcdef\xff", 7, 0, 6}, + {"\xff", 1, "abcdef\xff", 7, 1, 6}, + {"$", 1, "dollar$", 7, 0, 6}, + {"^", 1, "caret^", 6, 0, 5}, + /* Longer literals */ + {"Suricata", 8, "This is a Suricata test", 23, 0, 10}, + {"Suricata", 8, "This is a suricata test", 23, 1, 10}, + {"Suricata", 8, "This is a suriCATA test", 23, 1, 10}, + {"suricata", 8, "This is a Suricata test", 23, 0, SPM_NO_MATCH}, + {"Suricata", 8, "This is a Suricat_ test", 23, 0, SPM_NO_MATCH}, + {"Suricata", 8, "This is a _uricata test", 23, 0, SPM_NO_MATCH}, + /* First occurrence with the correct case should match */ + {"foo", 3, "foofoofoo", 9, 0, 0}, + {"foo", 3, "_foofoofoo", 9, 0, 1}, + {"FOO", 3, "foofoofoo", 9, 1, 0}, + {"FOO", 3, "_foofoofoo", 9, 1, 1}, + {"FOO", 3, "foo Foo FOo fOo foO FOO", 23, 0, 20}, + {"foo", 3, "Foo FOo fOo foO FOO foo", 23, 0, 20}, + }; + + int ret = 1; + + uint16_t matcher; + for (matcher = 0; matcher < SPM_TABLE_SIZE; matcher++) { + const SpmTableElmt *m = &spm_table[matcher]; + if (m->name == NULL) { + continue; + } + printf("matcher: %s\n", m->name); + + uint32_t i; + for (i = 0; i < sizeof(data)/sizeof(data[0]); i++) { + const SpmTestData *d = &data[i]; + if (SpmTestSearch(d, matcher) == 0) { + printf(" test %" PRIu32 ": fail\n", i); + ret = 0; + } + } + printf(" %" PRIu32 " tests passed\n", i); + } + + return ret; +} + +int SpmSearchTest02() { + SpmTableSetup(); + printf("\n"); + + /* Test that we can find needles of various lengths at various alignments + * in the haystack. Note that these are passed to strlen. */ + + static const char* needles[] = { + /* Single bytes */ + "a", "b", "c", ":", "/", "\x7f", "\xff", + /* Repeats */ + "aa", "aaa", "aaaaaaaaaaaaaaaaaaaaaaa", + /* Longer literals */ + "suricata", "meerkat", "aardvark", "raptor", "marmot", "lemming", + /* Mixed case */ + "Suricata", "CAPS LOCK", "mIxEd cAsE", + }; + + int ret = 1; + + uint16_t matcher; + for (matcher = 0; matcher < SPM_TABLE_SIZE; matcher++) { + const SpmTableElmt *m = &spm_table[matcher]; + if (m->name == NULL) { + continue; + } + printf("matcher: %s\n", m->name); + + SpmTestData d; + + uint32_t i; + for (i = 0; i < sizeof(needles) / sizeof(needles[0]); i++) { + const char *needle = needles[i]; + uint16_t prefix; + for (prefix = 0; prefix < 32; prefix++) { + d.needle = needle; + d.needle_len = strlen(needle); + uint16_t haystack_len = prefix + d.needle_len; + char *haystack = SCMalloc(haystack_len); + if (haystack == NULL) { + printf("alloc failure\n"); + return 0; + } + memset(haystack, ' ', haystack_len); + memcpy(haystack + prefix, d.needle, d.needle_len); + d.haystack = haystack; + d.haystack_len = haystack_len; + d.nocase = 0; + d.match_offset = prefix; + + /* Case-sensitive scan */ + if (SpmTestSearch(&d, matcher) == 0) { + printf(" test %" PRIu32 ": fail (case-sensitive)\n", i); + ret = 0; + } + + /* Case-insensitive scan */ + d.nocase = 1; + uint16_t j; + for (j = 0; j < haystack_len; j++) { + haystack[j] = toupper(haystack[j]); + } + if (SpmTestSearch(&d, matcher) == 0) { + printf(" test %" PRIu32 ": fail (case-insensitive)\n", i); + ret = 0; + } + + SCFree(haystack); + } + } + printf(" %" PRIu32 " tests passed\n", i); + } + + return ret; +} + #endif /* Register unittests */ @@ -2378,6 +2643,10 @@ void UtilSpmSearchRegistertests(void) UtRegisterTest("UtilSpmSearchOffsetsNocaseTest01", UtilSpmSearchOffsetsNocaseTest01); + /* new SPM API */ + UtRegisterTest("SpmSearchTest01", SpmSearchTest01); + UtRegisterTest("SpmSearchTest02", SpmSearchTest02); + #ifdef ENABLE_SEARCH_STATS /* Give some stats searching given a prepared context (look at the wrappers) */ UtRegisterTest("UtilSpmSearchStatsTest01", UtilSpmSearchStatsTest01); diff --git a/src/util-spm.h b/src/util-spm.h index 11149867a1bf..310285695c3b 100644 --- a/src/util-spm.h +++ b/src/util-spm.h @@ -31,10 +31,65 @@ enum { SPM_BM, /* Boyer-Moore */ /* Other SPM matchers will go here. */ + SPM_TABLE_SIZE }; uint16_t SinglePatternMatchDefaultMatcher(void); +/** Structure holding an immutable "built" SPM matcher (such as the Boyer-Moore + * tables, Hyperscan database etc) that is passed to the Scan call. */ +typedef struct SpmCtx_ { + uint16_t matcher; + void *ctx; +} SpmCtx; + +/** Structure holding a global prototype for per-thread scratch space, passed + * to each InitCtx call. */ +typedef struct SpmGlobalThreadCtx_ { + uint16_t matcher; + void *ctx; +} SpmGlobalThreadCtx; + +/** Structure holding some mutable per-thread space for use by a matcher at + * scan time. Constructed from SpmGlobalThreadCtx by the MakeThreadCtx call. */ +typedef struct SpmThreadCtx_ { + uint16_t matcher; + void *ctx; +} SpmThreadCtx; + +typedef struct SpmTableElmt_ { + const char *name; + SpmGlobalThreadCtx *(*InitGlobalThreadCtx)(void); + void (*DestroyGlobalThreadCtx)(SpmGlobalThreadCtx *g_thread_ctx); + SpmThreadCtx *(*MakeThreadCtx)(const SpmGlobalThreadCtx *g_thread_ctx); + void (*DestroyThreadCtx)(SpmThreadCtx *thread_ctx); + SpmCtx *(*InitCtx)(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *g_thread_ctx); + void (*DestroyCtx)(SpmCtx *); + uint8_t *(*Scan)(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, + const uint8_t *haystack, uint16_t haystack_len); +} SpmTableElmt; + +SpmTableElmt spm_table[SPM_TABLE_SIZE]; + +void SpmTableSetup(void); + +SpmGlobalThreadCtx *SpmInitGlobalThreadCtx(uint16_t matcher); + +void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *g_thread_ctx); + +SpmThreadCtx *SpmMakeThreadCtx(const SpmGlobalThreadCtx *g_thread_ctx); + +void SpmDestroyThreadCtx(SpmThreadCtx *thread_ctx); + +SpmCtx *SpmInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *g_thread_ctx); + +void SpmDestroyCtx(SpmCtx *ctx); + +uint8_t *SpmScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, + const uint8_t *haystack, uint16_t haystack_len); + /** Default algorithm to use: Boyer Moore */ uint8_t *Bs2bmSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); uint8_t *Bs2bmNocaseSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); From 6a6d0192454962fc936b62e548de008e5b6649cb Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Thu, 28 Apr 2016 12:48:38 +1000 Subject: [PATCH 1383/2553] spm: add Hyperscan implementation --- src/Makefile.am | 2 + src/util-hyperscan.c | 59 +++++++++++ src/util-hyperscan.h | 31 ++++++ src/util-mpm-hs.c | 31 +----- src/util-spm-hs.c | 237 +++++++++++++++++++++++++++++++++++++++++++ src/util-spm-hs.h | 31 ++++++ src/util-spm.c | 4 + src/util-spm.h | 1 + 8 files changed, 367 insertions(+), 29 deletions(-) create mode 100644 src/util-hyperscan.c create mode 100644 src/util-hyperscan.h create mode 100644 src/util-spm-hs.c create mode 100644 src/util-spm-hs.h diff --git a/src/Makefile.am b/src/Makefile.am index 4d0490a1f3f3..e2369c70f79c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -350,6 +350,7 @@ util-hashlist.c util-hashlist.h \ util-hash-lookup3.c util-hash-lookup3.h \ util-host-os-info.c util-host-os-info.h \ util-host-info.c util-host-info.h \ +util-hyperscan.c util-hyperscan.h \ util-ioctl.h util-ioctl.c \ util-ip.h util-ip.c \ util-logopenfile.h util-logopenfile.c \ @@ -397,6 +398,7 @@ util-signal.c util-signal.h \ util-spm-bm.c util-spm-bm.h \ util-spm-bs2bm.c util-spm-bs2bm.h \ util-spm-bs.c util-spm-bs.h \ +util-spm-hs.c util-spm-hs.h \ util-spm.c util-spm.h util-clock.h \ util-storage.c util-storage.h \ util-strlcatu.c \ diff --git a/src/util-hyperscan.c b/src/util-hyperscan.c new file mode 100644 index 000000000000..edcf73f66580 --- /dev/null +++ b/src/util-hyperscan.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2016 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 Justin Viiret + * + * Support functions for Hyperscan library integration. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#ifdef BUILD_HYPERSCAN + +/** + * \internal + * \brief Convert a pattern into a regex string accepted by the Hyperscan + * compiler. + * + * For simplicity, we just take each byte of the original pattern and render it + * with a hex escape (i.e. ' ' -> "\x20")/ + */ +char *HSRenderPattern(const uint8_t *pat, uint16_t pat_len) +{ + if (pat == NULL) { + return NULL; + } + const size_t hex_len = (pat_len * 4) + 1; + char *str = SCMalloc(hex_len); + if (str == NULL) { + return NULL; + } + memset(str, 0, hex_len); + char *sp = str; + for (uint16_t i = 0; i < pat_len; i++) { + snprintf(sp, 5, "\\x%02x", pat[i]); + sp += 4; + } + *sp = '\0'; + return str; +} + +#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-hyperscan.h b/src/util-hyperscan.h new file mode 100644 index 000000000000..67bcabf49d84 --- /dev/null +++ b/src/util-hyperscan.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2007-2016 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 Justin Viiret + * + * Support functions for Hyperscan library integration. + */ + +#ifndef __UTIL_HYPERSCAN__H__ +#define __UTIL_HYPERSCAN__H__ + +char *HSRenderPattern(const uint8_t *pat, uint16_t pat_len); + +#endif /* __UTIL_HYPERSCAN__H__ */ diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index c7659974a7d0..8b993ae16089 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -40,6 +40,7 @@ #include "util-memcpy.h" #include "util-hash.h" #include "util-hash-lookup3.h" +#include "util-hyperscan.h" #ifdef BUILD_HYPERSCAN @@ -111,34 +112,6 @@ static void SCHSSetAllocators(void) } } -/** - * \internal - * \brief Convert a pattern into a regex string accepted by the Hyperscan - * compiler. - * - * For simplicity, we just take each byte of the original pattern and render it - * with a hex escape (i.e. ' ' -> "\x20")/ - */ -static char *SCHSRenderPattern(uint8_t *pat, uint16_t pat_len) -{ - if (pat == NULL) { - return NULL; - } - const size_t hex_len = (pat_len * 4) + 1; - char *str = SCMalloc(hex_len); - if (str == NULL) { - return NULL; - } - memset(str, 0, hex_len); - char *sp = str; - for (uint16_t i = 0; i < pat_len; i++) { - snprintf(sp, 5, "\\x%02x", pat[i]); - sp += 4; - } - *sp = '\0'; - return str; -} - /** * \internal * \brief Creates a hash of the pattern. We use it for the hashing process @@ -679,7 +652,7 @@ int SCHSPreparePatterns(MpmCtx *mpm_ctx) cd->flags[i] |= HS_FLAG_CASELESS; } - cd->expressions[i] = SCHSRenderPattern(p->original_pat, p->len); + cd->expressions[i] = HSRenderPattern(p->original_pat, p->len); if (p->flags & (MPM_PATTERN_FLAG_OFFSET | MPM_PATTERN_FLAG_DEPTH)) { cd->ext[i] = SCMalloc(sizeof(hs_expr_ext_t)); diff --git a/src/util-spm-hs.c b/src/util-spm-hs.c new file mode 100644 index 000000000000..5ca0d333d0b9 --- /dev/null +++ b/src/util-spm-hs.c @@ -0,0 +1,237 @@ +/* Copyright (C) 2016 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 Justin Viiret + * + * Single pattern matcher that uses the Hyperscan regex matcher. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "util-hyperscan.h" +#include "util-spm-hs.h" + +#ifdef BUILD_HYPERSCAN + +#include + +/** + * \internal + * \brief Hyperscan match callback, called by hs_scan. + */ +static int MatchEvent(unsigned int id, unsigned long long from, + unsigned long long to, unsigned int flags, void *context) +{ + uint64_t *match_offset = context; + BUG_ON(*match_offset != UINT64_MAX); + *match_offset = to; + return 1; /* Terminate matching. */ +} + +typedef struct SpmHsCtx_ { + hs_database_t *db; + uint16_t needle_len; +} SpmHsCtx; + +static void HSDestroyCtx(SpmCtx *ctx) +{ + if (ctx == NULL) { + return; + } + SpmHsCtx *sctx = ctx->ctx; + if (sctx) { + hs_free_database(sctx->db); + SCFree(sctx); + } + SCFree(ctx); +} + +static int HSBuildDatabase(const uint8_t *needle, uint16_t needle_len, + int nocase, SpmHsCtx *sctx, + SpmGlobalThreadCtx *global_thread_ctx) +{ + char *expr = HSRenderPattern(needle, needle_len); + if (expr == NULL) { + SCLogDebug("HSRenderPattern returned NULL"); + return -1; + } + + unsigned flags = nocase ? HS_FLAG_CASELESS : 0; + + hs_database_t *db = NULL; + hs_compile_error_t *compile_err = NULL; + hs_error_t err = hs_compile(expr, flags, HS_MODE_BLOCK, NULL, &db, + &compile_err); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Unable to compile '%s' with Hyperscan, " + "returned %d.", expr, err); + exit(EXIT_FAILURE); + } + + SCFree(expr); + + /* Update scratch for this database. */ + hs_scratch_t *scratch = global_thread_ctx->ctx; + err = hs_alloc_scratch(db, &scratch); + if (err != HS_SUCCESS) { + /* If scratch allocation failed, this is not recoverable: other SPM + * contexts may need this scratch space. */ + SCLogError(SC_ERR_FATAL, + "Unable to alloc scratch for Hyperscan, returned %d.", err); + exit(EXIT_FAILURE); + } + global_thread_ctx->ctx = scratch; + sctx->db = db; + sctx->needle_len = needle_len; + + return 0; +} + +static SpmCtx *HSInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *global_thread_ctx) +{ + SpmCtx *ctx = SCMalloc(sizeof(SpmCtx)); + if (ctx == NULL) { + SCLogDebug("Unable to alloc SpmCtx."); + return NULL; + } + memset(ctx, 0, sizeof(SpmCtx)); + ctx->matcher = SPM_HS; + + SpmHsCtx *sctx = SCMalloc(sizeof(SpmHsCtx)); + if (sctx == NULL) { + SCLogDebug("Unable to alloc SpmHsCtx."); + SCFree(ctx); + return NULL; + } + ctx->ctx = sctx; + + memset(sctx, 0, sizeof(SpmHsCtx)); + if (HSBuildDatabase(needle, needle_len, nocase, sctx, + global_thread_ctx) != 0) { + SCLogDebug("HSBuildDatabase failed."); + HSDestroyCtx(ctx); + return NULL; + } + + return ctx; +} + +static uint8_t *HSScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, + const uint8_t *haystack, uint16_t haystack_len) +{ + const SpmHsCtx *sctx = ctx->ctx; + hs_scratch_t *scratch = thread_ctx->ctx; + + uint64_t match_offset = UINT64_MAX; + hs_error_t err = hs_scan(sctx->db, (const char *)haystack, haystack_len, 0, + scratch, MatchEvent, &match_offset); + if (err != HS_SUCCESS && err != HS_SCAN_TERMINATED) { + /* An error value (other than HS_SCAN_TERMINATED) from hs_scan() + * indicates that it was passed an invalid database or scratch region, + * which is not something we can recover from at scan time. */ + SCLogError(SC_ERR_FATAL, "Hyperscan returned fatal error %d.", err); + exit(EXIT_FAILURE); + } + + if (match_offset == UINT64_MAX) { + return NULL; + } + + BUG_ON(match_offset < sctx->needle_len); + BUG_ON(match_offset > UINT16_MAX); /* haystack_len is a uint16_t */ + + /* Note: existing API returns non-const ptr */ + return (uint8_t *)haystack + (match_offset - sctx->needle_len); +} + +static SpmGlobalThreadCtx *HSInitGlobalThreadCtx(void) +{ + SpmGlobalThreadCtx *global_thread_ctx = SCMalloc(sizeof(SpmGlobalThreadCtx)); + if (global_thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmGlobalThreadCtx."); + return NULL; + } + memset(global_thread_ctx, 0, sizeof(*global_thread_ctx)); + global_thread_ctx->matcher = SPM_HS; + + /* We store scratch in the HS-specific ctx. This will be initialized as + * patterns are compiled by SpmInitCtx. */ + global_thread_ctx->ctx = NULL; + + return global_thread_ctx; +} + +static void HSDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) +{ + if (global_thread_ctx == NULL) { + return; + } + hs_free_scratch(global_thread_ctx->ctx); + SCFree(global_thread_ctx); +} + +static void HSDestroyThreadCtx(SpmThreadCtx *thread_ctx) +{ + if (thread_ctx == NULL) { + return; + } + hs_free_scratch(thread_ctx->ctx); + SCFree(thread_ctx); +} + +static SpmThreadCtx *HSMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) +{ + SpmThreadCtx *thread_ctx = SCMalloc(sizeof(SpmThreadCtx)); + if (thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmThreadCtx."); + return NULL; + } + memset(thread_ctx, 0, sizeof(*thread_ctx)); + thread_ctx->matcher = SPM_HS; + + if (global_thread_ctx->ctx != NULL) { + hs_scratch_t *scratch = NULL; + hs_error_t err = hs_clone_scratch(global_thread_ctx->ctx, &scratch); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Unable to clone scratch (error %d).", + err); + exit(EXIT_FAILURE); + } + thread_ctx->ctx = scratch; + } + + return thread_ctx; +} + +void SpmHSRegister(void) +{ + spm_table[SPM_HS].name = "hs"; + spm_table[SPM_HS].InitGlobalThreadCtx = HSInitGlobalThreadCtx; + spm_table[SPM_HS].DestroyGlobalThreadCtx = HSDestroyGlobalThreadCtx; + spm_table[SPM_HS].MakeThreadCtx = HSMakeThreadCtx; + spm_table[SPM_HS].DestroyThreadCtx = HSDestroyThreadCtx; + spm_table[SPM_HS].InitCtx = HSInitCtx; + spm_table[SPM_HS].DestroyCtx = HSDestroyCtx; + spm_table[SPM_HS].Scan = HSScan; +} + +#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-spm-hs.h b/src/util-spm-hs.h new file mode 100644 index 000000000000..e362198819c8 --- /dev/null +++ b/src/util-spm-hs.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2016 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 Justin Viiret + * + * Single pattern matcher that uses the Hyperscan regex matcher. + */ + +#ifndef __UTIL_SPM_HS_H__ +#define __UTIL_SPM_HS_H__ + +void SpmHSRegister(void); + +#endif /* __UTIL_SPM_HS_H__ */ diff --git a/src/util-spm.c b/src/util-spm.c index aa09b98bc8e0..6e1192a892db 100644 --- a/src/util-spm.c +++ b/src/util-spm.c @@ -53,6 +53,7 @@ #include "util-spm-bs.h" #include "util-spm-bs2bm.h" #include "util-spm-bm.h" +#include "util-spm-hs.h" #include "util-clock.h" /** @@ -89,6 +90,9 @@ void SpmTableSetup(void) memset(spm_table, 0, sizeof(spm_table)); SpmBMRegister(); +#ifdef BUILD_HYPERSCAN + SpmHSRegister(); +#endif } SpmGlobalThreadCtx *SpmInitGlobalThreadCtx(uint16_t matcher) diff --git a/src/util-spm.h b/src/util-spm.h index 310285695c3b..a29da29d32d9 100644 --- a/src/util-spm.h +++ b/src/util-spm.h @@ -30,6 +30,7 @@ enum { SPM_BM, /* Boyer-Moore */ + SPM_HS, /* Hyperscan */ /* Other SPM matchers will go here. */ SPM_TABLE_SIZE }; From 91011b30a6409296e6c7fe29cc643bc83a006123 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Mon, 16 May 2016 14:15:45 +1000 Subject: [PATCH 1384/2553] spm: add "spm-algo: auto" setting This will default to Hyperscan when Suricata is built with Hyperscan support. Otherwise, Boyer-Moore is used by default. --- src/util-spm.c | 13 ++++++++++++- suricata.yaml.in | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/util-spm.c b/src/util-spm.c index 6e1192a892db..04e7676f5cde 100644 --- a/src/util-spm.c +++ b/src/util-spm.c @@ -65,6 +65,9 @@ uint16_t SinglePatternMatchDefaultMatcher(void) char *spm_algo; if ((ConfGet("spm-algo", &spm_algo)) == 1) { if (spm_algo != NULL) { + if (strcmp("auto", spm_algo) == 0) { + goto default_matcher; + } for (uint16_t i = 0; i < SPM_TABLE_SIZE; i++) { if (spm_table[i].name == NULL) { continue; @@ -82,7 +85,15 @@ uint16_t SinglePatternMatchDefaultMatcher(void) exit(EXIT_FAILURE); } - return SPM_BM; /* default to Boyer-Moore */ +default_matcher: + /* When Suricata is built with Hyperscan support, default to using it for + * SPM. */ +#ifdef BUILD_HYPERSCAN + return SPM_HS; +#else + /* Otherwise, default to Boyer-Moore */ + return SPM_BM; +#endif } void SpmTableSetup(void) diff --git a/suricata.yaml.in b/suricata.yaml.in index 12a18faf17e4..c93bfd613aba 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -729,8 +729,10 @@ mpm-algo: ac # # Supported algorithms are "bm" (Boyer-Moore) and "hs" (Hyperscan, only # available if Suricata has been built with Hyperscan support). +# +# The default of "auto" will use "hs" if available, otherwise "bm". -spm-algo: bm +spm-algo: auto # Defrag settings: From 8dc63f625f9a8a890d231e1d7dc7c38a30a95168 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 May 2016 10:50:51 +0200 Subject: [PATCH 1385/2553] qa: update drmemory suppressions for hyperscan spm matching --- qa/drmemory.suppress | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/qa/drmemory.suppress b/qa/drmemory.suppress index 7f1da7decd8d..30fa0d5d85e7 100644 --- a/qa/drmemory.suppress +++ b/qa/drmemory.suppress @@ -43,6 +43,34 @@ suricata!SigGroupBuild ... libc.so.6!__clone +UNINITIALIZED READ +name=Hyperscan false positives due to DrMemory limitations 3 +... +libhs.so.*!hs_compile +suricata!SpmInitCtx +... +suricata!main + +UNINITIALIZED READ +name=Hyperscan false positives due to DrMemory limitations 4 +... +libhs.so.*!hs_compile +suricata!SpmInitCtx +... +libc.so.6!__clone + +UNINITIALIZED READ +name=Hyperscan false positives due to DrMemory limitations 5 +... +libhs.so.*!hs_compile +suricata!HSBuildDatabase + +UNINITIALIZED READ +name=Hyperscan false positives due to DrMemory limitations 6 +... +libhs.so.*!hs_compile +suricata!HSBuildDatabase + WARNING name=Prefetch warnings 1 ... @@ -58,3 +86,26 @@ libhs.so.*!hs_scan suricata!SCHSSearch ... libc.so.6!__clone + +WARNING +name=Prefetch warnings 3 +... +libhs.so.*!hs_scan +suricata!HSScan +... +suricata!main + +WARNING +name=Prefetch warnings 4 +... +libhs.so.*!hs_scan +suricata!HSScan +... +libc.so.6!__clone + +WARNING +name=Prefetch warnings 5 +... +libhs.so.*!hs_scan +suricata!HSScan +* From be5a5df1f7bf14d0f81122c6d1bd75e95d9588b7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 15 May 2016 18:29:25 +0200 Subject: [PATCH 1386/2553] ipv4: shrink per packet ipopts storage --- src/decode-ipv4.c | 758 +++++++++++++++----------------------------- src/decode-ipv4.h | 39 +-- src/detect-ipopts.c | 51 +-- 3 files changed, 305 insertions(+), 543 deletions(-) diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 807ad78ed94a..3dd47f622467 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -59,27 +59,27 @@ static int IPV4OptValidateGeneric(Packet *p, const IPV4Opt *o) switch (o->type) { /* See: RFC 4782 */ case IPV4_OPT_QS: - if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len < IPV4_OPT_QS_MIN) { + if (o->len < IPV4_OPT_QS_MIN) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } break; /* See: RFC 1108 */ case IPV4_OPT_SEC: - if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len != IPV4_OPT_SEC_LEN) { + if (o->len != IPV4_OPT_SEC_LEN) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } break; case IPV4_OPT_SID: - if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len != IPV4_OPT_SID_LEN) { + if (o->len != IPV4_OPT_SID_LEN) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } break; /* See: RFC 2113 */ case IPV4_OPT_RTRALT: - if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len != IPV4_OPT_RTRALT_LEN) { + if (o->len != IPV4_OPT_RTRALT_LEN) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } @@ -284,15 +284,25 @@ static int IPV4OptValidateCIPSO(Packet *p, const IPV4Opt *o) return 0; } +typedef struct IPV4Options_ { + IPV4Opt o_rr; + IPV4Opt o_qs; + IPV4Opt o_ts; + IPV4Opt o_sec; + IPV4Opt o_lsrr; + IPV4Opt o_cipso; + IPV4Opt o_sid; + IPV4Opt o_ssrr; + IPV4Opt o_rtralt; +} IPV4Options; + /** * Decode/Validate IPv4 Options. */ -static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len) +static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options *opts) { uint16_t plen = len; - p->IPV4_OPTS_CNT = 0; - #ifdef DEBUG if (SCLogDebugEnabled()) { uint16_t i; @@ -314,11 +324,14 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len) while (plen) { + p->ip4vars.opt_cnt++; + /* single byte options */ if (*pkt == IPV4_OPT_EOL) { /** \todo What if more data exist after EOL (possible covert channel or data leakage)? */ SCLogDebug("IPV4OPT %" PRIu16 " len 1 @ %" PRIu16 "/%" PRIu16 "", *pkt, (len - plen), (len - 1)); + p->ip4vars.eol = TRUE; break; } else if (*pkt == IPV4_OPT_NOP) { SCLogDebug("IPV4OPT %" PRIu16 " len 1 @ %" PRIu16 "/%" PRIu16 "", @@ -326,6 +339,8 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len) pkt++; plen--; + p->ip4vars.nop = TRUE; + /* multibyte options */ } else { if (unlikely(plen < 2)) { @@ -341,133 +356,129 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len) return -1; } - p->IPV4_OPTS[p->IPV4_OPTS_CNT].type = *pkt; - p->IPV4_OPTS[p->IPV4_OPTS_CNT].len = *(pkt+1); - if (plen > 2) - p->IPV4_OPTS[p->IPV4_OPTS_CNT].data = (pkt+2); - else - p->IPV4_OPTS[p->IPV4_OPTS_CNT].data = NULL; - - SCLogDebug("IPV4OPT %" PRIu16 " len %" PRIu16 " @ %" PRIu16 "/%" PRIu16 "", - p->IPV4_OPTS[p->IPV4_OPTS_CNT].type, p->IPV4_OPTS[p->IPV4_OPTS_CNT].len, - (len - plen), (len - 1)); + IPV4Opt opt = {*pkt, *(pkt+1), plen > 2 ? (pkt + 2) : NULL }; /* we already know that the total options len is valid, * so here the len of the specific option must be bad. * Also check for invalid lengths 0 and 1. */ - if (unlikely(p->IPV4_OPTS[p->IPV4_OPTS_CNT].len > plen || - p->IPV4_OPTS[p->IPV4_OPTS_CNT].len < 2)) { + if (unlikely(opt.len > plen || opt.len < 2)) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } - /* we are parsing the most commonly used opts to prevent * us from having to walk the opts list for these all the * time. */ /** \todo Figure out which IP options are more common and list them first */ - switch (p->IPV4_OPTS[p->IPV4_OPTS_CNT].type) { + switch (opt.type) { case IPV4_OPT_TS: - if (p->ip4vars.o_ts != NULL) { + if (opts->o_ts.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateTimestamp(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { + } else if (IPV4OptValidateTimestamp(p, &opt)) { return -1; } - p->ip4vars.o_ts = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_ts = opt; + p->ip4vars.ts = TRUE; break; case IPV4_OPT_RR: - if (p->ip4vars.o_rr != NULL) { + if (opts->o_rr.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateRoute(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { + } else if (IPV4OptValidateRoute(p, &opt) != 0) { return -1; } - p->ip4vars.o_rr = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_rr = opt; + p->ip4vars.rr = TRUE; break; case IPV4_OPT_QS: - if (p->ip4vars.o_qs != NULL) { + if (opts->o_qs.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { + } else if (IPV4OptValidateGeneric(p, &opt)) { return -1; } - p->ip4vars.o_qs = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_qs = opt; + p->ip4vars.qs = TRUE; break; case IPV4_OPT_SEC: - if (p->ip4vars.o_sec != NULL) { + if (opts->o_sec.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { + } else if (IPV4OptValidateGeneric(p, &opt)) { return -1; } - p->ip4vars.o_sec = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_sec = opt; + p->ip4vars.sec = TRUE; break; case IPV4_OPT_LSRR: - if (p->ip4vars.o_lsrr != NULL) { + if (opts->o_lsrr.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateRoute(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { + } else if (IPV4OptValidateRoute(p, &opt) != 0) { return -1; } - p->ip4vars.o_lsrr = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_lsrr = opt; + p->ip4vars.lsrr = TRUE; break; case IPV4_OPT_CIPSO: - if (p->ip4vars.o_cipso != NULL) { + if (opts->o_cipso.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateCIPSO(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { + } else if (IPV4OptValidateCIPSO(p, &opt) != 0) { return -1; } - p->ip4vars.o_cipso = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_cipso = opt; + p->ip4vars.cipso = TRUE; break; case IPV4_OPT_SID: - if (p->ip4vars.o_sid != NULL) { + if (opts->o_sid.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { + } else if (IPV4OptValidateGeneric(p, &opt)) { return -1; } - p->ip4vars.o_sid = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_sid = opt; + p->ip4vars.sid = TRUE; break; case IPV4_OPT_SSRR: - if (p->ip4vars.o_ssrr != NULL) { + if (opts->o_ssrr.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateRoute(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { + } else if (IPV4OptValidateRoute(p, &opt) != 0) { return -1; } - p->ip4vars.o_ssrr = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_ssrr = opt; + p->ip4vars.ssrr = TRUE; break; case IPV4_OPT_RTRALT: - if (p->ip4vars.o_rtralt != NULL) { + if (opts->o_rtralt.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { + } else if (IPV4OptValidateGeneric(p, &opt)) { return -1; } - p->ip4vars.o_rtralt = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_rtralt = opt; + p->ip4vars.rtralt = TRUE; break; default: - SCLogDebug("IPV4OPT (%" PRIu8 ") len %" PRIu8 "", - p->IPV4_OPTS[p->IPV4_OPTS_CNT].type, - p->IPV4_OPTS[p->IPV4_OPTS_CNT].len); + SCLogDebug("IPV4OPT (%" PRIu8 ") len %" PRIu8, + opt.type, opt.len); ENGINE_SET_EVENT(p,IPV4_OPT_INVALID); /* Warn - we can keep going */ break; } - pkt += p->IPV4_OPTS[p->IPV4_OPTS_CNT].len; - plen -= (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len); - p->IPV4_OPTS_CNT++; + pkt += opt.len; + plen -= opt.len; } } @@ -511,7 +522,9 @@ static int DecodeIPV4Packet(Packet *p, uint8_t *pkt, uint16_t len) /* save the options len */ uint8_t ip_opt_len = IPV4_GET_HLEN(p) - IPV4_HEADER_LEN; if (ip_opt_len > 0) { - DecodeIPV4Options(p, pkt + IPV4_HEADER_LEN, ip_opt_len); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + DecodeIPV4Options(p, pkt + IPV4_HEADER_LEN, ip_opt_len, &opts); } return 0; @@ -609,63 +622,20 @@ int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u /* UNITTESTS */ #ifdef UNITTESTS -void DecodeIPV4OptionsPrint(Packet *p) -{ - IPV4Vars *pv = &p->ip4vars; - - printf("DecodeIPV4Options: cnt=%" PRIu8 - ",rr={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",qs={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",ts={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",sec={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",lsrr={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",cipso={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",sid={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",ssrr={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",rtralt={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - "}\n", - pv->ip_opt_cnt, - (pv->o_rr ? pv->o_rr->type : 0), (pv->o_rr ? pv->o_rr->len : 0), (pv->o_rr ? pv->o_rr->data : 0), - (pv->o_qs ? pv->o_qs->type : 0), (pv->o_qs ? pv->o_qs->len : 0), (pv->o_qs ? pv->o_qs->data : 0), - (pv->o_ts ? pv->o_ts->type : 0), (pv->o_ts ? pv->o_ts->len : 0), (pv->o_ts ? pv->o_ts->data : 0), - (pv->o_sec ? pv->o_sec->type : 0), (pv->o_sec ? pv->o_sec->len : 0), (pv->o_sec ? pv->o_sec->data : 0), - (pv->o_lsrr ? pv->o_lsrr->type : 0), (pv->o_lsrr ? pv->o_lsrr->len : 0), (pv->o_lsrr ? pv->o_lsrr->data : 0), - (pv->o_cipso ? pv->o_cipso->type : 0), (pv->o_cipso ? pv->o_cipso->len : 0), (pv->o_cipso ? pv->o_cipso->data : 0), - (pv->o_sid ? pv->o_sid->type : 0), (pv->o_sid ? pv->o_sid->len : 0), (pv->o_sid ? pv->o_sid->data : 0), - (pv->o_ssrr ? pv->o_ssrr->type : 0), (pv->o_ssrr ? pv->o_ssrr->len : 0), (pv->o_ssrr ? pv->o_ssrr->data : 0), - (pv->o_rtralt ? pv->o_rtralt->type : 0), (pv->o_rtralt ? pv->o_rtralt->len : 0), (pv->o_rtralt ? pv->o_rtralt->data : 0)); -} - /** \test IPV4 with no options. */ int DecodeIPV4OptionsNONETest01(void) { uint8_t raw_opts[] = { }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - uint8_t *data = (uint8_t *)p; - uint16_t i; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - if (rc != 0) { - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } + FAIL_IF(unlikely(p == NULL)); - for (i = 0; i < (uint16_t)SIZE_OF_PACKET; i++) { - if (*data) { - /* Should not have modified packet data */ - //printf("Data modified at offset %" PRIu16 "\n", i); - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } - } + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); SCFree(p); - return 1; + PASS; } /** \test IPV4 with EOL option. */ @@ -675,31 +645,13 @@ int DecodeIPV4OptionsEOLTest01(void) IPV4_OPT_EOL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - uint8_t *data = (uint8_t *)p; - uint16_t i; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - if (rc != 0) { - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } - - for (i = 0; i < (uint16_t)SIZE_OF_PACKET; i++) { - if (*data) { - /* Should not have modified packet data */ - //printf("Data modified at offset %" PRIu16 "\n", i); - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } - } - + FAIL_IF(unlikely(p == NULL)); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF (rc != 0); SCFree(p); - return 1; + PASS; } /** \test IPV4 with NOP option. */ @@ -709,31 +661,13 @@ int DecodeIPV4OptionsNOPTest01(void) IPV4_OPT_NOP, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - uint8_t *data = (uint8_t *)p; - uint16_t i; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - if (rc != 0) { - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } - - for (i = 0; i < (uint16_t)SIZE_OF_PACKET; i++) { - if (*data) { - /* Should not have modified packet data */ - //printf("Data modified at offset %" PRIu16 "\n", i); - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } - } - + FAIL_IF(unlikely(p == NULL)); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF (rc != 0); SCFree(p); - return 1; + PASS; } /** \test IPV4 with RR option. */ @@ -747,25 +681,15 @@ int DecodeIPV4OptionsRRTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_RR) - && (p->IPV4_OPTS[0].len == 0x27) - && (p->ip4vars.o_rr == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_rr.type != IPV4_OPT_RR); SCFree(p); - return 0; + PASS; } /** \test IPV4 with RR option (len too large). */ @@ -779,20 +703,15 @@ int DecodeIPV4OptionsRRTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_rr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with RR option (ptr too large). */ @@ -806,20 +725,15 @@ int DecodeIPV4OptionsRRTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_rr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with RR option (ptr not in 4 byte increment). */ @@ -833,20 +747,15 @@ int DecodeIPV4OptionsRRTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_rr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with QS option. */ @@ -856,25 +765,15 @@ int DecodeIPV4OptionsQSTest01(void) IPV4_OPT_QS, 0x08, 0x0d, 0x00, 0xbe, 0xef, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",qs=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_qs, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_QS) - && (p->IPV4_OPTS[0].len == 0x08) - && (p->ip4vars.o_qs == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_qs.type != IPV4_OPT_QS); SCFree(p); - return 0; + PASS; } /** \test IPV4 with QS option (len too small) */ @@ -884,20 +783,15 @@ int DecodeIPV4OptionsQSTest02(void) IPV4_OPT_QS, 0x07, 0x0d, 0x00, 0xbe, 0xef, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",qs=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_qs, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_qs.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with TS option. */ @@ -911,25 +805,15 @@ int DecodeIPV4OptionsTSTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_TS) - && (p->IPV4_OPTS[0].len == 0x24) - && (p->ip4vars.o_ts == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_ts.type != IPV4_OPT_TS); SCFree(p); - return 0; + PASS; } /** \test IPV4 with TS option (ptr too small). */ @@ -943,20 +827,15 @@ int DecodeIPV4OptionsTSTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ts.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with TS option (ptr too large). */ @@ -970,20 +849,15 @@ int DecodeIPV4OptionsTSTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ts.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with TS option (ptr not valid). */ @@ -997,20 +871,15 @@ int DecodeIPV4OptionsTSTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ts.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SEC option. */ @@ -1021,25 +890,15 @@ int DecodeIPV4OptionsSECTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sec=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sec, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_SEC) - && (p->IPV4_OPTS[0].len == 0x0b) - && (p->ip4vars.o_sec == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_sec.type != IPV4_OPT_SEC); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SEC option (invalid length). */ @@ -1050,20 +909,15 @@ int DecodeIPV4OptionsSECTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sec=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sec, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_sec.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with LSRR option. */ @@ -1077,25 +931,15 @@ int DecodeIPV4OptionsLSRRTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_LSRR) - && (p->IPV4_OPTS[0].len == 0x27) - && (p->ip4vars.o_lsrr == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_lsrr.type != IPV4_OPT_LSRR); SCFree(p); - return 0; + PASS; } /** \test IPV4 with LSRR option (len too large). */ @@ -1109,20 +953,15 @@ int DecodeIPV4OptionsLSRRTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_lsrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with LSRR option (ptr too large). */ @@ -1136,20 +975,15 @@ int DecodeIPV4OptionsLSRRTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_lsrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with LSRR option (ptr not in 4 byte increment). */ @@ -1163,20 +997,15 @@ int DecodeIPV4OptionsLSRRTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_lsrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with CIPSO option. */ @@ -1188,25 +1017,15 @@ int DecodeIPV4OptionsCIPSOTest01(void) 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_cipso, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_CIPSO) - && (p->IPV4_OPTS[0].len == 0x18) - && (p->ip4vars.o_cipso == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_cipso.type != IPV4_OPT_CIPSO); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SID option. */ @@ -1216,25 +1035,15 @@ int DecodeIPV4OptionsSIDTest01(void) IPV4_OPT_SID, 0x04, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sid=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sid, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_SID) - && (p->IPV4_OPTS[0].len == 0x04) - && (p->ip4vars.o_sid == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_sid.type != IPV4_OPT_SID); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SID option (len invalid. */ @@ -1244,20 +1053,15 @@ int DecodeIPV4OptionsSIDTest02(void) IPV4_OPT_SID, 0x05, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sid=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sid, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_sid.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SSRR option. */ @@ -1271,25 +1075,15 @@ int DecodeIPV4OptionsSSRRTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_SSRR) - && (p->IPV4_OPTS[0].len == 0x27) - && (p->ip4vars.o_ssrr == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_ssrr.type != IPV4_OPT_SSRR); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SSRR option (len too large). */ @@ -1303,20 +1097,15 @@ int DecodeIPV4OptionsSSRRTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ssrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SSRR option (ptr too large). */ @@ -1330,20 +1119,15 @@ int DecodeIPV4OptionsSSRRTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ssrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SSRR option (ptr not in 4 byte increment). */ @@ -1357,20 +1141,15 @@ int DecodeIPV4OptionsSSRRTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ssrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with RTRALT option. */ @@ -1380,25 +1159,15 @@ int DecodeIPV4OptionsRTRALTTest01(void) IPV4_OPT_RTRALT, 0x04, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rtralt=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rtralt, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_RTRALT) - && (p->IPV4_OPTS[0].len == 0x04) - && (p->ip4vars.o_rtralt == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_rtralt.type != IPV4_OPT_RTRALT); SCFree(p); - return 0; + PASS; } /** \test IPV4 with RTRALT option (len invalid. */ @@ -1408,20 +1177,15 @@ int DecodeIPV4OptionsRTRALTTest02(void) IPV4_OPT_RTRALT, 0x05, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rtralt=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rtralt, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_rtralt.type != 0); SCFree(p); - return 0; + PASS; } static int IPV4CalculateValidChecksumtest01(void) diff --git a/src/decode-ipv4.h b/src/decode-ipv4.h index be212bf2fadb..7c2a74fb3ccd 100644 --- a/src/decode-ipv4.h +++ b/src/decode-ipv4.h @@ -151,18 +151,7 @@ typedef struct IPV4Hdr_ #define CLEAR_IPV4_PACKET(p) do { \ (p)->ip4h = NULL; \ (p)->level3_comp_csum = -1; \ - (p)->ip4vars.ip_src_u32 = 0; \ - (p)->ip4vars.ip_dst_u32 = 0; \ - (p)->ip4vars.ip_opt_cnt = 0; \ - (p)->ip4vars.o_rr = NULL; \ - (p)->ip4vars.o_qs = NULL; \ - (p)->ip4vars.o_ts = NULL; \ - (p)->ip4vars.o_sec = NULL; \ - (p)->ip4vars.o_lsrr = NULL; \ - (p)->ip4vars.o_cipso = NULL; \ - (p)->ip4vars.o_sid = NULL; \ - (p)->ip4vars.o_ssrr = NULL; \ - (p)->ip4vars.o_rtralt = NULL; \ + memset(&p->ip4vars, 0x00, sizeof(p->ip4vars)); \ } while (0) /* helper structure with parsed ipv4 info */ @@ -172,19 +161,19 @@ typedef struct IPV4Vars_ uint32_t ip_src_u32; /* source IP */ uint32_t ip_dst_u32; /* dest IP */ - IPV4Opt ip_opts[IPV4_OPTMAX]; - uint8_t ip_opt_cnt; - - /* These are here for direct access and dup tracking */ - IPV4Opt *o_rr; - IPV4Opt *o_qs; - IPV4Opt *o_ts; - IPV4Opt *o_sec; - IPV4Opt *o_lsrr; - IPV4Opt *o_cipso; - IPV4Opt *o_sid; - IPV4Opt *o_ssrr; - IPV4Opt *o_rtralt; + uint16_t opt_cnt; + _Bool rr; + _Bool lsrr; + _Bool eol; + _Bool nop; + _Bool ts; + _Bool sec; + _Bool sid; + _Bool qs; + _Bool cipso; + _Bool rtralt; + _Bool ssrr; + } IPV4Vars; diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index 4a3bb31873c5..bf957441241c 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -82,31 +82,44 @@ void DetectIpOptsRegister (void) */ int DetectIpOptsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - int ipopt = 0; const DetectIpOptsData *de = (const DetectIpOptsData *)ctx; if (!de || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) - return ret; + return 0; /* IPV4_OPT_ANY matches on any options */ - - if (p->IPV4_OPTS_CNT && (de->ipopt == IPV4_OPT_ANY)) { + if (p->ip4vars.opt_cnt && (de->ipopt == IPV4_OPT_ANY)) { return 1; } - /* Loop through instead of using o_xxx direct access fields so that - * future options do not require any modification here. - */ - - while(ipopt < p->IPV4_OPTS_CNT) { - if (p->IPV4_OPTS[ipopt].type == de->ipopt) { - return 1; - } - ipopt++; + switch (de->ipopt) { + case IPV4_OPT_RR: + return (p->ip4vars.rr); + break; + case IPV4_OPT_LSRR: + return (p->ip4vars.lsrr); + break; + case IPV4_OPT_EOL: + return (p->ip4vars.eol); + break; + case IPV4_OPT_NOP: + return (p->ip4vars.nop); + break; + case IPV4_OPT_TS: + return (p->ip4vars.ts); + break; + case IPV4_OPT_SEC: + return (p->ip4vars.sec); + break; + case IPV4_OPT_SSRR: + return (p->ip4vars.ssrr); + break; + case IPV4_OPT_SID: + return (p->ip4vars.sid); + break; } - return ret; + return 0; } /** @@ -268,9 +281,7 @@ int IpOptsTestParse03 (void) memset(&ip4h, 0, sizeof(IPV4Hdr)); p->ip4h = &ip4h; - p->IPV4_OPTS[0].type = IPV4_OPT_RR; - - p->IPV4_OPTS_CNT++; + p->ip4vars.rr = TRUE; de = DetectIpOptsParse("rr"); @@ -320,9 +331,7 @@ int IpOptsTestParse04 (void) memset(&ip4h, 0, sizeof(IPV4Hdr)); p->ip4h = &ip4h; - p->IPV4_OPTS[0].type = IPV4_OPT_RR; - - p->IPV4_OPTS_CNT++; + p->ip4vars.rr = TRUE; de = DetectIpOptsParse("lsrr"); From 8c37906cf9e2f79431a1a1babadc438e79aeed75 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 16 May 2016 12:15:42 +0200 Subject: [PATCH 1387/2553] ipv4: store ipopts as flags, not bools --- src/decode-ipv4.c | 22 +++++++++++----------- src/decode-ipv4.h | 27 +++++++++++++++------------ src/detect-ipopts.c | 20 ++++++++++---------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 3dd47f622467..a41c35bfd7b0 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -331,7 +331,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options /** \todo What if more data exist after EOL (possible covert channel or data leakage)? */ SCLogDebug("IPV4OPT %" PRIu16 " len 1 @ %" PRIu16 "/%" PRIu16 "", *pkt, (len - plen), (len - 1)); - p->ip4vars.eol = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_EOL; break; } else if (*pkt == IPV4_OPT_NOP) { SCLogDebug("IPV4OPT %" PRIu16 " len 1 @ %" PRIu16 "/%" PRIu16 "", @@ -339,7 +339,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options pkt++; plen--; - p->ip4vars.nop = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_NOP; /* multibyte options */ } else { @@ -379,7 +379,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options return -1; } opts->o_ts = opt; - p->ip4vars.ts = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_TS; break; case IPV4_OPT_RR: if (opts->o_rr.type != 0) { @@ -390,7 +390,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options return -1; } opts->o_rr = opt; - p->ip4vars.rr = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_RR; break; case IPV4_OPT_QS: if (opts->o_qs.type != 0) { @@ -401,7 +401,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options return -1; } opts->o_qs = opt; - p->ip4vars.qs = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_QS; break; case IPV4_OPT_SEC: if (opts->o_sec.type != 0) { @@ -412,7 +412,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options return -1; } opts->o_sec = opt; - p->ip4vars.sec = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_SEC; break; case IPV4_OPT_LSRR: if (opts->o_lsrr.type != 0) { @@ -423,7 +423,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options return -1; } opts->o_lsrr = opt; - p->ip4vars.lsrr = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_LSRR; break; case IPV4_OPT_CIPSO: if (opts->o_cipso.type != 0) { @@ -434,7 +434,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options return -1; } opts->o_cipso = opt; - p->ip4vars.cipso = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_CIPSO; break; case IPV4_OPT_SID: if (opts->o_sid.type != 0) { @@ -445,7 +445,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options return -1; } opts->o_sid = opt; - p->ip4vars.sid = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_SID; break; case IPV4_OPT_SSRR: if (opts->o_ssrr.type != 0) { @@ -456,7 +456,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options return -1; } opts->o_ssrr = opt; - p->ip4vars.ssrr = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_SSRR; break; case IPV4_OPT_RTRALT: if (opts->o_rtralt.type != 0) { @@ -467,7 +467,7 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options return -1; } opts->o_rtralt = opt; - p->ip4vars.rtralt = TRUE; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_RTRALT; break; default: SCLogDebug("IPV4OPT (%" PRIu8 ") len %" PRIu8, diff --git a/src/decode-ipv4.h b/src/decode-ipv4.h index 7c2a74fb3ccd..27e13c4a989d 100644 --- a/src/decode-ipv4.h +++ b/src/decode-ipv4.h @@ -154,6 +154,20 @@ typedef struct IPV4Hdr_ memset(&p->ip4vars, 0x00, sizeof(p->ip4vars)); \ } while (0) +enum IPV4OptionFlags { + IPV4_OPT_FLAG_EOL = 0, + IPV4_OPT_FLAG_NOP, + IPV4_OPT_FLAG_RR, + IPV4_OPT_FLAG_TS, + IPV4_OPT_FLAG_QS, + IPV4_OPT_FLAG_LSRR, + IPV4_OPT_FLAG_SSRR, + IPV4_OPT_FLAG_SID, + IPV4_OPT_FLAG_SEC, + IPV4_OPT_FLAG_CIPSO, + IPV4_OPT_FLAG_RTRALT, +}; + /* helper structure with parsed ipv4 info */ typedef struct IPV4Vars_ { @@ -162,18 +176,7 @@ typedef struct IPV4Vars_ uint32_t ip_dst_u32; /* dest IP */ uint16_t opt_cnt; - _Bool rr; - _Bool lsrr; - _Bool eol; - _Bool nop; - _Bool ts; - _Bool sec; - _Bool sid; - _Bool qs; - _Bool cipso; - _Bool rtralt; - _Bool ssrr; - + uint16_t opts_set; } IPV4Vars; diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index bf957441241c..6fce99f5b2ae 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -94,28 +94,28 @@ int DetectIpOptsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, switch (de->ipopt) { case IPV4_OPT_RR: - return (p->ip4vars.rr); + return (p->ip4vars.opts_set & IPV4_OPT_FLAG_RR); break; case IPV4_OPT_LSRR: - return (p->ip4vars.lsrr); + return (p->ip4vars.opts_set & IPV4_OPT_FLAG_LSRR); break; case IPV4_OPT_EOL: - return (p->ip4vars.eol); + return (p->ip4vars.opts_set & IPV4_OPT_FLAG_EOL); break; case IPV4_OPT_NOP: - return (p->ip4vars.nop); + return (p->ip4vars.opts_set & IPV4_OPT_FLAG_NOP); break; case IPV4_OPT_TS: - return (p->ip4vars.ts); + return (p->ip4vars.opts_set & IPV4_OPT_FLAG_TS); break; case IPV4_OPT_SEC: - return (p->ip4vars.sec); + return (p->ip4vars.opts_set & IPV4_OPT_FLAG_SEC); break; case IPV4_OPT_SSRR: - return (p->ip4vars.ssrr); + return (p->ip4vars.opts_set & IPV4_OPT_FLAG_SSRR); break; case IPV4_OPT_SID: - return (p->ip4vars.sid); + return (p->ip4vars.opts_set & IPV4_OPT_FLAG_SID); break; } @@ -281,7 +281,7 @@ int IpOptsTestParse03 (void) memset(&ip4h, 0, sizeof(IPV4Hdr)); p->ip4h = &ip4h; - p->ip4vars.rr = TRUE; + p->ip4vars.opts_set = IPV4_OPT_FLAG_RR; de = DetectIpOptsParse("rr"); @@ -331,7 +331,7 @@ int IpOptsTestParse04 (void) memset(&ip4h, 0, sizeof(IPV4Hdr)); p->ip4h = &ip4h; - p->ip4vars.rr = TRUE; + p->ip4vars.opts_set = IPV4_OPT_FLAG_RR; de = DetectIpOptsParse("lsrr"); From 6ea0db2f603791d46d95749a43a48341454a11aa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 16 May 2016 12:17:38 +0200 Subject: [PATCH 1388/2553] ipv4: removed unused variables --- src/decode-ipv4.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/decode-ipv4.h b/src/decode-ipv4.h index 27e13c4a989d..77af6762bc20 100644 --- a/src/decode-ipv4.h +++ b/src/decode-ipv4.h @@ -172,8 +172,6 @@ enum IPV4OptionFlags { typedef struct IPV4Vars_ { int32_t comp_csum; /* checksum computed over the ipv4 packet */ - uint32_t ip_src_u32; /* source IP */ - uint32_t ip_dst_u32; /* dest IP */ uint16_t opt_cnt; uint16_t opts_set; From 3ab7dfd98813a19754f01db7f081f7d7419cac3f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 16 May 2016 12:26:22 +0200 Subject: [PATCH 1389/2553] detect-ipopts: cleanup --- src/detect-ipopts.c | 36 ++++++++++++++++++++++++++++++------ src/detect-ipopts.h | 29 ----------------------------- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index 6fce99f5b2ae..bd47c3b0c61f 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -35,9 +35,6 @@ #include "util-debug.h" -/* Need to get the DIpOpts[] array */ -#define DETECT_EVENTS - #include "detect-ipopts.h" #include "util-unittest.h" @@ -67,6 +64,33 @@ void DetectIpOptsRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } +/** + * Used to check ipopts:any + */ + +#define IPV4_OPT_ANY 0xff + +/** + * \struct DetectIpOptss_ + * DetectIpOptss_ is used to store supported iptops values + */ + +struct DetectIpOptss_ { + char *ipopt_name; /**< Ip option name */ + uint8_t code; /**< Ip option value */ +} ipopts[] = { + { "rr", IPV4_OPT_RR, }, + { "lsrr", IPV4_OPT_LSRR, }, + { "eol", IPV4_OPT_EOL, }, + { "nop", IPV4_OPT_NOP, }, + { "ts", IPV4_OPT_TS, }, + { "sec", IPV4_OPT_SEC, }, + { "ssrr", IPV4_OPT_SSRR, }, + { "satid", IPV4_OPT_SID, }, + { "any", IPV4_OPT_ANY, }, + { NULL, 0 }, +}; + /** * \internal * \brief This function is used to match ip option on a packet with those passed via ipopts: @@ -145,8 +169,8 @@ DetectIpOptsData *DetectIpOptsParse (char *rawstr) goto error; } - for(i = 0; DIpOpts[i].ipopt_name != NULL; i++) { - if((strcasecmp(DIpOpts[i].ipopt_name,rawstr)) == 0) { + for(i = 0; ipopts[i].ipopt_name != NULL; i++) { + if((strcasecmp(ipopts[i].ipopt_name,rawstr)) == 0) { found = 1; break; } @@ -159,7 +183,7 @@ DetectIpOptsData *DetectIpOptsParse (char *rawstr) if (unlikely(de == NULL)) goto error; - de->ipopt = DIpOpts[i].code; + de->ipopt = ipopts[i].code; return de; diff --git a/src/detect-ipopts.h b/src/detect-ipopts.h index bd346256171c..bb402a0731b5 100644 --- a/src/detect-ipopts.h +++ b/src/detect-ipopts.h @@ -47,34 +47,5 @@ typedef struct DetectIpOptsData_ { void DetectIpOptsRegister (void); -#ifdef DETECT_EVENTS - -/** - * Used to check ipopts:any - */ - -#define IPV4_OPT_ANY 0xff - -/** - * \struct DetectIpOptss_ - * DetectIpOptss_ is used to store supported iptops values - */ - -struct DetectIpOptss_ { - char *ipopt_name; /**< Ip option name */ - uint8_t code; /**< Ip option value */ -} DIpOpts[] = { - { "rr", IPV4_OPT_RR, }, - { "lsrr", IPV4_OPT_LSRR, }, - { "eol", IPV4_OPT_EOL, }, - { "nop", IPV4_OPT_NOP, }, - { "ts", IPV4_OPT_TS, }, - { "sec", IPV4_OPT_SEC, }, - { "ssrr", IPV4_OPT_SSRR, }, - { "satid", IPV4_OPT_SID, }, - { "any", IPV4_OPT_ANY, }, - { NULL, 0 }, -}; -#endif /* DETECT_EVENTS */ #endif /*__DETECT_IPOPTS_H__ */ From 64405ae194d8ab4fa73de223d35a8e521c66b23d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 16 May 2016 12:31:07 +0200 Subject: [PATCH 1390/2553] detect-ipopts: optimize matching --- src/detect-ipopts.c | 60 ++++++++++----------------------------------- src/detect-ipopts.h | 2 +- 2 files changed, 14 insertions(+), 48 deletions(-) diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index bd47c3b0c61f..d861b21909de 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -64,30 +64,24 @@ void DetectIpOptsRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/** - * Used to check ipopts:any - */ - -#define IPV4_OPT_ANY 0xff - /** * \struct DetectIpOptss_ * DetectIpOptss_ is used to store supported iptops values */ -struct DetectIpOptss_ { - char *ipopt_name; /**< Ip option name */ - uint8_t code; /**< Ip option value */ +struct DetectIpOpts_ { + const char *ipopt_name; /**< ip option name */ + uint16_t code; /**< ip option flag value */ } ipopts[] = { - { "rr", IPV4_OPT_RR, }, - { "lsrr", IPV4_OPT_LSRR, }, - { "eol", IPV4_OPT_EOL, }, - { "nop", IPV4_OPT_NOP, }, - { "ts", IPV4_OPT_TS, }, - { "sec", IPV4_OPT_SEC, }, - { "ssrr", IPV4_OPT_SSRR, }, - { "satid", IPV4_OPT_SID, }, - { "any", IPV4_OPT_ANY, }, + { "rr", IPV4_OPT_FLAG_RR, }, + { "lsrr", IPV4_OPT_FLAG_LSRR, }, + { "eol", IPV4_OPT_FLAG_EOL, }, + { "nop", IPV4_OPT_FLAG_NOP, }, + { "ts", IPV4_OPT_FLAG_TS, }, + { "sec", IPV4_OPT_FLAG_SEC, }, + { "ssrr", IPV4_OPT_FLAG_SSRR, }, + { "satid", IPV4_OPT_FLAG_SID, }, + { "any", 0xffff, }, { NULL, 0 }, }; @@ -111,38 +105,10 @@ int DetectIpOptsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, if (!de || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) return 0; - /* IPV4_OPT_ANY matches on any options */ - if (p->ip4vars.opt_cnt && (de->ipopt == IPV4_OPT_ANY)) { + if (p->ip4vars.opts_set & de->ipopt) { return 1; } - switch (de->ipopt) { - case IPV4_OPT_RR: - return (p->ip4vars.opts_set & IPV4_OPT_FLAG_RR); - break; - case IPV4_OPT_LSRR: - return (p->ip4vars.opts_set & IPV4_OPT_FLAG_LSRR); - break; - case IPV4_OPT_EOL: - return (p->ip4vars.opts_set & IPV4_OPT_FLAG_EOL); - break; - case IPV4_OPT_NOP: - return (p->ip4vars.opts_set & IPV4_OPT_FLAG_NOP); - break; - case IPV4_OPT_TS: - return (p->ip4vars.opts_set & IPV4_OPT_FLAG_TS); - break; - case IPV4_OPT_SEC: - return (p->ip4vars.opts_set & IPV4_OPT_FLAG_SEC); - break; - case IPV4_OPT_SSRR: - return (p->ip4vars.opts_set & IPV4_OPT_FLAG_SSRR); - break; - case IPV4_OPT_SID: - return (p->ip4vars.opts_set & IPV4_OPT_FLAG_SID); - break; - } - return 0; } diff --git a/src/detect-ipopts.h b/src/detect-ipopts.h index bb402a0731b5..2c599d82e2e4 100644 --- a/src/detect-ipopts.h +++ b/src/detect-ipopts.h @@ -38,7 +38,7 @@ */ typedef struct DetectIpOptsData_ { - uint8_t ipopt; /**< Ip option */ + uint16_t ipopt; /**< ip option flag */ } DetectIpOptsData; /** From 68c7fae79fdcf70e817a76022c989f77b176b3fe Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 15 May 2016 13:35:10 +0200 Subject: [PATCH 1391/2553] ipv6: simplify ext hdr parsing and storage This reduces size of the IPV6ExtHdr structure part of every packet significantly. Clean up macro's in the ipv6 header. --- src/decode-ipv6.c | 241 +++++++++++++++++----------------------- src/decode-ipv6.h | 141 +++++------------------ src/defrag.c | 22 ++-- src/detect-fragoffset.c | 2 +- 4 files changed, 141 insertions(+), 265 deletions(-) diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index e63624219957..c13b8806c993 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -113,6 +113,14 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt char dstopts = 0; char exthdr_fh_done = 0; + uint8_t ip6_exthdrs_cnt = 0; + IPV6GenOptHdr ip6_exthdrs[IPV6_MAX_OPT]; + + int hh = 0; + int rh = 0; + int eh = 0; + int ah = 0; + nh = IPV6_GET_NH(p); plen = len; @@ -161,16 +169,16 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt SCReturn; } - if (p->IPV6_EH_CNT < IPV6_MAX_OPT) + if (ip6_exthdrs_cnt < IPV6_MAX_OPT) { - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; - p->IPV6_EH_CNT++; + ip6_exthdrs[ip6_exthdrs_cnt].type = nh; + ip6_exthdrs[ip6_exthdrs_cnt].next = *pkt; + ip6_exthdrs[ip6_exthdrs_cnt].len = hdrextlen; + ip6_exthdrs[ip6_exthdrs_cnt].data = pkt+2; + ip6_exthdrs_cnt++; } - if (IPV6_EXTHDR_ISSET_RH(p)) { + if (rh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_RH); /* skip past this extension so we can continue parsing the rest * of the packet */ @@ -180,26 +188,14 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt break; } - IPV6_EXTHDR_SET_RH(p, pkt); - - /** \todo move into own function and load on demand */ - if (IPV6_EXTHDR_RH(p)->ip6rh_type == 0) { -#if 0 // XXX usused and broken, original packet is modified in the memcpy - uint8_t i; - - uint8_t n = hdrextlen / 2; - /* because we devide the header len by 2 (as rfc 2460 tells us to) - * we devide the result by 8 and not 16 as the header fields are - * sized */ - for (i = 0; i < (n/8) && i < sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr)/sizeof(struct in6_addr); ++i) { - /* the address header fields are 16 bytes in size */ - /** \todo do this without memcpy since it's expensive */ - memcpy(&IPV6_EXTHDR_RH(p)->ip6rh0_addr[i], pkt+(i*16)+8, sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr[i])); - } - IPV6_EXTHDR_RH(p)->ip6rh0_num_addrs = i; -#endif + rh = 1; + IPV6_EXTHDR_SET_RH(p); + + uint8_t ip6rh_type = *(pkt + 2); + if (ip6rh_type == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_RH_TYPE_0); } + p->ip6eh.rh_type = ip6rh_type; nh = *pkt; pkt += hdrextlen; @@ -209,9 +205,9 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt case IPPROTO_HOPOPTS: case IPPROTO_DSTOPTS: { - IPV6OptHAO *hao = NULL; - IPV6OptRA *ra = NULL; - IPV6OptJumbo *jumbo = NULL; + IPV6OptHAO hao_s, *hao = &hao_s; + IPV6OptRA ra_s, *ra = &ra_s; + IPV6OptJumbo jumbo_s, *jumbo = &jumbo_s; uint16_t optslen = 0; IPV6_SET_L4PROTO(p,nh); @@ -221,13 +217,13 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt SCReturn; } - if (p->IPV6_EH_CNT < IPV6_MAX_OPT) + if (ip6_exthdrs_cnt < IPV6_MAX_OPT) { - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; - p->IPV6_EH_CNT++; + ip6_exthdrs[ip6_exthdrs_cnt].type = nh; + ip6_exthdrs[ip6_exthdrs_cnt].next = *pkt; + ip6_exthdrs[ip6_exthdrs_cnt].len = hdrextlen; + ip6_exthdrs[ip6_exthdrs_cnt].data = pkt+2; + ip6_exthdrs_cnt++; } uint8_t *ptr = pkt + 2; /* +2 to go past nxthdr and len */ @@ -235,7 +231,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt /* point the pointers to right structures * in Packet. */ if (nh == IPPROTO_HOPOPTS) { - if (IPV6_EXTHDR_ISSET_HH(p)) { + if (hh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_HH); /* skip past this extension so we can continue parsing the rest * of the packet */ @@ -245,28 +241,17 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt break; } - IPV6_EXTHDR_SET_HH(p, pkt); - hao = &IPV6_EXTHDR_HH_HAO(p); - ra = &IPV6_EXTHDR_HH_RA(p); - jumbo = &IPV6_EXTHDR_HH_JUMBO(p); + hh = 1; - optslen = ((IPV6_EXTHDR_HH(p)->ip6hh_len+1)<<3)-2; + optslen = ((*(pkt + 1) + 1 ) << 3) - 2; } else if (nh == IPPROTO_DSTOPTS) { if (dstopts == 0) { - IPV6_EXTHDR_SET_DH1(p, pkt); - hao = &IPV6_EXTHDR_DH1_HAO(p); - ra = &IPV6_EXTHDR_DH1_RA(p); - jumbo = &IPV6_EXTHDR_DH2_JUMBO(p); - optslen = ((IPV6_EXTHDR_DH1(p)->ip6dh_len+1)<<3)-2; + optslen = ((*(pkt + 1) + 1 ) << 3) - 2; dstopts = 1; } else if (dstopts == 1) { - IPV6_EXTHDR_SET_DH2(p, pkt); - hao = &IPV6_EXTHDR_DH2_HAO(p); - ra = &IPV6_EXTHDR_DH2_RA(p); - jumbo = &IPV6_EXTHDR_DH2_JUMBO(p); - optslen = ((IPV6_EXTHDR_DH2(p)->ip6dh_len+1)<<3)-2; + optslen = ((*(pkt + 1) + 1 ) << 3) - 2; dstopts = 2; } else { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_DH); @@ -424,13 +409,13 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt /* non fatal, lets try to continue */ } - if(p->IPV6_EH_CNTIPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; - p->IPV6_EH_CNT++; + ip6_exthdrs[ip6_exthdrs_cnt].type = nh; + ip6_exthdrs[ip6_exthdrs_cnt].next = *pkt; + ip6_exthdrs[ip6_exthdrs_cnt].len = hdrextlen; + ip6_exthdrs[ip6_exthdrs_cnt].data = pkt+2; + ip6_exthdrs_cnt++; } if (IPV6_EXTHDR_ISSET_FH(p)) { @@ -441,14 +426,49 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt break; } - /* set the header ptr first */ - IPV6_EXTHDR_SET_FH(p, pkt); + /* set the header flag first */ + IPV6_EXTHDR_SET_FH(p); + + uint16_t frag_offset = (*(pkt + 2) << 8 | *(pkt + 3)) & 0xFFF8; + int frag_morefrags = (*(pkt + 2) << 8 | *(pkt + 3)) & 0x0001; + + p->ip6eh.fh_offset = frag_offset; + p->ip6eh.fh_more_frags_set = frag_morefrags ? TRUE : FALSE; + p->ip6eh.fh_nh = *pkt; + + uint32_t fh_id; + memcpy(&fh_id, pkt+4, 4); + p->ip6eh.fh_id = ntohl(fh_id); + + SCLogDebug("IPV6 FH: offset %u, mf %s, nh %u, id %u/%x", + p->ip6eh.fh_offset, + p->ip6eh.fh_more_frags_set ? "true" : "false", + p->ip6eh.fh_nh, + p->ip6eh.fh_id, p->ip6eh.fh_id); + + // store header offset, data offset + uint16_t frag_hdr_offset = (uint16_t)(pkt - GET_PKT_DATA(p)); + uint16_t data_offset = (uint16_t)(frag_hdr_offset + hdrextlen); + uint16_t data_len = plen - hdrextlen; + + p->ip6eh.fh_header_offset = frag_hdr_offset; + p->ip6eh.fh_data_offset = data_offset; + p->ip6eh.fh_data_len = data_len; + + /* if we have a prev hdr, store the type and offset of it */ + if (ip6_exthdrs_cnt > 1) { + p->ip6eh.fh_prev_hdr_offset = frag_hdr_offset - ip6_exthdrs[ip6_exthdrs_cnt - 1].len; + } + + SCLogDebug("IPV6 FH: frag_hdr_offset %u, data_offset %u, data_len %u", + p->ip6eh.fh_header_offset, p->ip6eh.fh_data_offset, + p->ip6eh.fh_data_len); /* if FH has offset 0 and no more fragments are coming, we * parse this packet further right away, no defrag will be * needed. It is a useless FH then though, so we do set an * decoder event. */ - if (IPV6_EXTHDR_GET_FH_FLAG(p) == 0 && IPV6_EXTHDR_GET_FH_OFFSET(p) == 0) { + if (frag_morefrags == 0 && frag_offset == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_USELESS_FH); nh = *pkt; @@ -470,21 +490,21 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt SCReturn; } - if(p->IPV6_EH_CNTIPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = IPPROTO_NONE; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; - p->IPV6_EH_CNT++; + ip6_exthdrs[ip6_exthdrs_cnt].type = nh; + ip6_exthdrs[ip6_exthdrs_cnt].next = IPPROTO_NONE; + ip6_exthdrs[ip6_exthdrs_cnt].len = hdrextlen; + ip6_exthdrs[ip6_exthdrs_cnt].data = pkt+2; + ip6_exthdrs_cnt++; } - if (IPV6_EXTHDR_ISSET_EH(p)) { + if (eh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_EH); SCReturn; } - IPV6_EXTHDR_SET_EH(p, pkt); + eh = 1; nh = IPPROTO_NONE; pkt += hdrextlen; @@ -513,16 +533,16 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt ENGINE_SET_EVENT(p, IPV6_EXTHDR_AH_RES_NOT_NULL); } - if(p->IPV6_EH_CNT < IPV6_MAX_OPT) + if(ip6_exthdrs_cnt < IPV6_MAX_OPT) { - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; - p->IPV6_EH_CNT++; + ip6_exthdrs[ip6_exthdrs_cnt].type = nh; + ip6_exthdrs[ip6_exthdrs_cnt].next = *pkt; + ip6_exthdrs[ip6_exthdrs_cnt].len = hdrextlen; + ip6_exthdrs[ip6_exthdrs_cnt].data = pkt+2; + ip6_exthdrs_cnt++; } - if (IPV6_EXTHDR_ISSET_AH(p)) { + if (ah) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_AH); nh = *pkt; pkt += hdrextlen; @@ -530,7 +550,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt break; } - IPV6_EXTHDR_SET_AH(p, pkt); + ah = 1; nh = *pkt; pkt += hdrextlen; @@ -677,30 +697,6 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u } } -#ifdef DEBUG - if (IPV6_EXTHDR_ISSET_FH(p)) { - SCLogDebug("IPV6 FRAG - HDRLEN: %" PRIuMAX " NH: %" PRIu32 " OFFSET: %" PRIu32 " ID: %" PRIu32 "", - (uintmax_t)IPV6_EXTHDR_GET_FH_HDRLEN(p), IPV6_EXTHDR_GET_FH_NH(p), - IPV6_EXTHDR_GET_FH_OFFSET(p), IPV6_EXTHDR_GET_FH_ID(p)); - } - if (IPV6_EXTHDR_ISSET_RH(p)) { - SCLogDebug("IPV6 ROUTE - HDRLEN: %" PRIu32 " NH: %" PRIu32 " TYPE: %" PRIu32 "", - IPV6_EXTHDR_GET_RH_HDRLEN(p), IPV6_EXTHDR_GET_RH_NH(p), - IPV6_EXTHDR_GET_RH_TYPE(p)); - } - if (IPV6_EXTHDR_ISSET_HH(p)) { - SCLogDebug("IPV6 HOPOPT - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", - IPV6_EXTHDR_GET_HH_HDRLEN(p), IPV6_EXTHDR_GET_HH_NH(p)); - } - if (IPV6_EXTHDR_ISSET_DH1(p)) { - SCLogDebug("IPV6 DSTOPT1 - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", - IPV6_EXTHDR_GET_DH1_HDRLEN(p), IPV6_EXTHDR_GET_DH1_NH(p)); - } - if (IPV6_EXTHDR_ISSET_DH2(p)) { - SCLogDebug("IPV6 DSTOPT2 - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", - IPV6_EXTHDR_GET_DH2_HDRLEN(p), IPV6_EXTHDR_GET_DH2_NH(p)); - } -#endif return TM_ECODE_OK; } @@ -879,7 +875,6 @@ static int DecodeIPV6FragTest01 (void) */ static int DecodeIPV6RouteTest01 (void) { - uint8_t raw_pkt1[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x2b, 0x40, 0x20, 0x01, 0xaa, 0xaa, 0x00, 0x01, 0x00, 0x00, @@ -893,11 +888,9 @@ static int DecodeIPV6RouteTest01 (void) 0xfa, 0x87, 0x00, 0x00, }; Packet *p1 = PacketGetFromAlloc(); - if (unlikely(p1 == NULL)) - return 0; + FAIL_IF(unlikely(p1 == NULL)); ThreadVars tv; DecodeThreadVars dtv; - int result = 0; PacketQueue pq; FlowInitConfig(FLOW_QUIET); @@ -910,22 +903,12 @@ static int DecodeIPV6RouteTest01 (void) DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1), &pq); - if (!(IPV6_EXTHDR_ISSET_RH(p1))) { - printf("ipv6 routing header not detected: "); - goto end; - } - - if (p1->ip6eh.ip6_exthdrs[0].len != 8) { - printf("ipv6 routing length incorrect: "); - goto end; - } - - result = 1; -end: + FAIL_IF (!(IPV6_EXTHDR_ISSET_RH(p1))); + FAIL_IF (p1->ip6eh.rh_type != 0); PACKET_RECYCLE(p1); SCFree(p1); FlowShutdown(); - return result; + PASS; } /** @@ -936,16 +919,15 @@ static int DecodeIPV6HopTest01 (void) uint8_t raw_pkt1[] = { 0x60,0x00,0x00,0x00,0x00,0x20,0x00,0x01,0xfe,0x80,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x0f,0xfe,0xff,0xfe,0x98,0x3d,0x01,0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x3a,0x00,0x05,0x02,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x3a,0x00,0xff, /* 0xff is a nonsene opt */ + 0x02,0x00,0x00,0x00,0x00, 0x82,0x00,0x1c,0x6f,0x27,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; Packet *p1 = PacketGetFromAlloc(); - if (unlikely(p1 == NULL)) - return 0; + FAIL_IF(unlikely(p1 == NULL)); ThreadVars tv; DecodeThreadVars dtv; - int result = 0; PacketQueue pq; FlowInitConfig(FLOW_QUIET); @@ -958,27 +940,12 @@ static int DecodeIPV6HopTest01 (void) DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1), &pq); - if (!(IPV6_EXTHDR_ISSET_HH(p1))) { - printf("ipv6 routing header not detected: "); - goto end; - } - - if (p1->ip6eh.ip6_exthdrs[0].len != 8) { - printf("ipv6 routing length incorrect: "); - goto end; - } + FAIL_IF (!(ENGINE_ISSET_EVENT(p1, IPV6_HOPOPTS_UNKNOWN_OPT))); - if (ENGINE_ISSET_EVENT(p1, IPV6_HOPOPTS_UNKNOWN_OPT)) { - printf("engine event IPV6_HOPOPTS_UNKNOWN_OPT set: "); - goto end; - } - - result = 1; -end: PACKET_RECYCLE(p1); SCFree(p1); FlowShutdown(); - return result; + PASS; } #endif /* UNITTESTS */ diff --git a/src/decode-ipv6.h b/src/decode-ipv6.h index da58d9e2b384..c30580cbf4b1 100644 --- a/src/decode-ipv6.h +++ b/src/decode-ipv6.h @@ -109,14 +109,7 @@ typedef struct IPV6Vars_ (p)->ip6h = NULL; \ (p)->ip6vars.ip_opts_len = 0; \ (p)->ip6vars.l4proto = 0; \ - (p)->ip6eh.ip6fh = NULL; \ - (p)->ip6eh.fh_offset = 0; \ - (p)->ip6eh.ip6rh = NULL; \ - (p)->ip6eh.ip6eh = NULL; \ - (p)->ip6eh.ip6dh1 = NULL; \ - (p)->ip6eh.ip6dh2 = NULL; \ - (p)->ip6eh.ip6hh = NULL; \ - (p)->ip6eh.ip6_exthdrs_cnt = 0; \ + memset(&(p)->ip6eh, 0x00, sizeof((p)->ip6eh)); \ } while (0) /* Fragment header */ @@ -128,17 +121,10 @@ typedef struct IPV6FragHdr_ uint32_t ip6fh_ident; /* identification */ } __attribute__((__packed__)) IPV6FragHdr; -#define IPV6_EXTHDR_GET_RAW_FH_NH(p) ((p)->ip6eh.ip6fh->ip6fh_nxt) -#define IPV6_EXTHDR_GET_RAW_FH_HDRLEN(p) sizeof(IPV6FragHdr) -#define IPV6_EXTHDR_GET_RAW_FH_OFFSET(p) (ntohs((p)->ip6eh.ip6fh->ip6fh_offlg) & 0xFFF8) -#define IPV6_EXTHDR_GET_RAW_FH_FLAG(p) (ntohs((p)->ip6eh.ip6fh->ip6fh_offlg) & 0x0001) -#define IPV6_EXTHDR_GET_RAW_FH_ID(p) (ntohl((p)->ip6eh.ip6fh->ip6fh_ident)) - -#define IPV6_EXTHDR_GET_FH_NH(p) IPV6_EXTHDR_GET_RAW_FH_NH((p)) -#define IPV6_EXTHDR_GET_FH_HDRLEN(p) IPV6_EXTHDR_GET_RAW_FH_HDRLEN((p)) -#define IPV6_EXTHDR_GET_FH_OFFSET(p) IPV6_EXTHDR_GET_RAW_FH_OFFSET((p)) -#define IPV6_EXTHDR_GET_FH_FLAG(p) IPV6_EXTHDR_GET_RAW_FH_FLAG((p)) -#define IPV6_EXTHDR_GET_FH_ID(p) IPV6_EXTHDR_GET_RAW_FH_ID((p)) +#define IPV6_EXTHDR_GET_FH_NH(p) (p)->ip6eh.fh_nh +#define IPV6_EXTHDR_GET_FH_OFFSET(p) (p)->ip6eh.fh_offset +#define IPV6_EXTHDR_GET_FH_FLAG(p) (p)->ip6eh.fh_more_frags_set +#define IPV6_EXTHDR_GET_FH_ID(p) (p)->ip6eh.fh_id /* rfc 1826 */ typedef struct IPV6AuthHdr_ @@ -164,24 +150,8 @@ typedef struct IPV6RouteHdr_ including first 8 bytes. */ uint8_t ip6rh_type; /* routing type */ uint8_t ip6rh_segsleft; /* segments left */ -#if 0 - struct in6_addr ip6rh0_addr[23]; /* type 0 addresses */ - uint8_t ip6rh0_num_addrs; /* number of actual addresses in the - array/packet. The array is guarranteed - to be filled up to this number. */ -#endif } __attribute__((__packed__)) IPV6RouteHdr; -#define IPV6_EXTHDR_GET_RAW_RH_NH(p) ((p)->ip6eh.ip6rh->ip6rh_nxt) -#define IPV6_EXTHDR_GET_RAW_RH_HDRLEN(p) ((p)->ip6eh.ip6rh->ip6rh_len) -#define IPV6_EXTHDR_GET_RAW_RH_TYPE(p) (ntohs((p)->ip6eh.ip6rh->ip6rh_type)) -/* XXX */ - -#define IPV6_EXTHDR_GET_RH_NH(p) IPV6_EXTHDR_GET_RAW_RH_NH((p)) -#define IPV6_EXTHDR_GET_RH_HDRLEN(p) IPV6_EXTHDR_GET_RAW_RH_HDRLEN((p)) -#define IPV6_EXTHDR_GET_RH_TYPE(p) IPV6_EXTHDR_GET_RAW_RH_TYPE((p)) -/* XXX */ - /* Hop-by-Hop header and Destination Options header use options that are * defined here. */ @@ -223,14 +193,6 @@ typedef struct IPV6HopOptsHdr_ including first 8 bytes. */ } __attribute__((__packed__)) IPV6HopOptsHdr; -#define IPV6_EXTHDR_GET_RAW_HH_NH(p) ((p)->ip6eh.ip6hh->ip6hh_nxt) -#define IPV6_EXTHDR_GET_RAW_HH_HDRLEN(p) ((p)->ip6eh.ip6hh->ip6hh_len) -/* XXX */ - -#define IPV6_EXTHDR_GET_HH_NH(p) IPV6_EXTHDR_GET_RAW_HH_NH((p)) -#define IPV6_EXTHDR_GET_HH_HDRLEN(p) IPV6_EXTHDR_GET_RAW_HH_HDRLEN((p)) -/* XXX */ - typedef struct IPV6DstOptsHdr_ { uint8_t ip6dh_nxt; /* next header */ @@ -238,22 +200,6 @@ typedef struct IPV6DstOptsHdr_ including first 8 bytes. */ } __attribute__((__packed__)) IPV6DstOptsHdr; -#define IPV6_EXTHDR_GET_RAW_DH1_NH(p) ((p)->ip6eh.ip6dh1->ip6dh_nxt) -#define IPV6_EXTHDR_GET_RAW_DH1_HDRLEN(p) ((p)->ip6eh.ip6dh1->ip6dh_len) -/* XXX */ - -#define IPV6_EXTHDR_GET_DH1_NH(p) IPV6_EXTHDR_GET_RAW_DH1_NH((p)) -#define IPV6_EXTHDR_GET_DH1_HDRLEN(p) IPV6_EXTHDR_GET_RAW_DH1_HDRLEN((p)) -/* XXX */ - -#define IPV6_EXTHDR_GET_RAW_DH2_NH(p) ((p)->ip6eh.ip6dh2->ip6dh_nxt) -#define IPV6_EXTHDR_GET_RAW_DH2_HDRLEN(p) ((p)->ip6eh.ip6dh2->ip6dh_len) -/* XXX */ - -#define IPV6_EXTHDR_GET_DH2_NH(p) IPV6_EXTHDR_GET_RAW_DH2_NH((p)) -#define IPV6_EXTHDR_GET_DH2_HDRLEN(p) IPV6_EXTHDR_GET_RAW_DH2_HDRLEN((p)) -/* XXX */ - typedef struct IPV6GenOptHdr_ { uint8_t type; @@ -264,69 +210,32 @@ typedef struct IPV6GenOptHdr_ typedef struct IPV6ExtHdrs_ { - const IPV6FragHdr *ip6fh; + _Bool rh_set; + uint8_t rh_type; + + _Bool fh_set; + _Bool fh_more_frags_set; + uint8_t fh_nh; + + uint8_t fh_prev_nh; + uint16_t fh_prev_hdr_offset; + + uint16_t fh_header_offset; + uint16_t fh_data_offset; + uint16_t fh_data_len; + /* In fh_offset we store the offset of this extension into the packet past * the ipv6 header. We use it in defrag for creating a defragmented packet * without the frag header */ - uint16_t fh_offset; - - const IPV6RouteHdr *ip6rh; - const IPV6AuthHdr *ip6ah; - const IPV6EspHdr *ip6eh; - const IPV6DstOptsHdr *ip6dh1; - const IPV6DstOptsHdr *ip6dh2; - const IPV6HopOptsHdr *ip6hh; - - /* Hop-By-Hop options */ - IPV6OptHAO ip6hh_opt_hao; - IPV6OptRA ip6hh_opt_ra; - IPV6OptJumbo ip6hh_opt_jumbo; - /* Dest Options 1 */ - IPV6OptHAO ip6dh1_opt_hao; - IPV6OptRA ip6dh1_opt_ra; - IPV6OptJumbo ip6dh1_opt_jumbo; - /* Dest Options 2 */ - IPV6OptHAO ip6dh2_opt_hao; - IPV6OptRA ip6dh2_opt_ra; - IPV6OptJumbo ip6dh2_opt_jumbo; - - IPV6GenOptHdr ip6_exthdrs[IPV6_MAX_OPT]; - uint8_t ip6_exthdrs_cnt; + uint16_t fh_offset; + uint32_t fh_id; } IPV6ExtHdrs; -#define IPV6_EXTHDR_FH(p) (p)->ip6eh.ip6fh -#define IPV6_EXTHDR_RH(p) (p)->ip6eh.ip6rh -#define IPV6_EXTHDR_AH(p) (p)->ip6eh.ip6ah -#define IPV6_EXTHDR_EH(p) (p)->ip6eh.ip6eh -#define IPV6_EXTHDR_DH1(p) (p)->ip6eh.ip6dh1 -#define IPV6_EXTHDR_DH2(p) (p)->ip6eh.ip6dh2 -#define IPV6_EXTHDR_HH(p) (p)->ip6eh.ip6hh - -#define IPV6_EXTHDR_HH_HAO(p) (p)->ip6eh.ip6hh_opt_hao -#define IPV6_EXTHDR_DH1_HAO(p) (p)->ip6eh.ip6dh1_opt_hao -#define IPV6_EXTHDR_DH2_HAO(p) (p)->ip6eh.ip6dh2_opt_hao -#define IPV6_EXTHDR_HH_RA(p) (p)->ip6eh.ip6hh_opt_ra -#define IPV6_EXTHDR_DH1_RA(p) (p)->ip6eh.ip6dh1_opt_ra -#define IPV6_EXTHDR_DH2_RA(p) (p)->ip6eh.ip6dh2_opt_ra -#define IPV6_EXTHDR_HH_JUMBO(p) (p)->ip6eh.ip6hh_opt_jumbo -#define IPV6_EXTHDR_DH1_JUMBO(p) (p)->ip6eh.ip6dh1_opt_jumbo -#define IPV6_EXTHDR_DH2_JUMBO(p) (p)->ip6eh.ip6dh2_opt_jumbo - -#define IPV6_EXTHDR_SET_FH(p,pkt) IPV6_EXTHDR_FH((p)) = (IPV6FragHdr *)pkt -#define IPV6_EXTHDR_ISSET_FH(p) (IPV6_EXTHDR_FH((p)) != NULL) -#define IPV6_EXTHDR_SET_RH(p,pkt) IPV6_EXTHDR_RH((p)) = (IPV6RouteHdr *)pkt -#define IPV6_EXTHDR_ISSET_RH(p) (IPV6_EXTHDR_RH((p)) != NULL) -#define IPV6_EXTHDR_SET_AH(p,pkt) IPV6_EXTHDR_AH((p)) = (IPV6AuthHdr *)pkt -#define IPV6_EXTHDR_ISSET_AH(p) (IPV6_EXTHDR_AH((p)) != NULL) -#define IPV6_EXTHDR_SET_EH(p,pkt) IPV6_EXTHDR_EH((p)) = (IPV6EspHdr *)pkt -#define IPV6_EXTHDR_ISSET_EH(p) (IPV6_EXTHDR_EH((p)) != NULL) -#define IPV6_EXTHDR_SET_DH1(p,pkt) IPV6_EXTHDR_DH1((p)) = (IPV6DstOptsHdr *)pkt -#define IPV6_EXTHDR_ISSET_DH1(p) (IPV6_EXTHDR_DH1((p)) != NULL) -#define IPV6_EXTHDR_SET_DH2(p,pkt) IPV6_EXTHDR_DH2((p)) = (IPV6DstOptsHdr *)pkt -#define IPV6_EXTHDR_ISSET_DH2(p) (IPV6_EXTHDR_DH2((p)) != NULL) -#define IPV6_EXTHDR_SET_HH(p,pkt) IPV6_EXTHDR_HH((p)) = (IPV6HopOptsHdr *)pkt -#define IPV6_EXTHDR_ISSET_HH(p) (IPV6_EXTHDR_HH((p)) != NULL) +#define IPV6_EXTHDR_SET_FH(p) (p)->ip6eh.fh_set = TRUE +#define IPV6_EXTHDR_ISSET_FH(p) (p)->ip6eh.fh_set +#define IPV6_EXTHDR_SET_RH(p) (p)->ip6eh.rh_set = TRUE +#define IPV6_EXTHDR_ISSET_RH(p) (p)->ip6eh.rh_set void DecodeIPV6RegisterTests(void); diff --git a/src/defrag.c b/src/defrag.c index 6ed46fe87288..488f9113ea93 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -559,26 +559,27 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, else if (tracker->af == AF_INET6) { more_frags = IPV6_EXTHDR_GET_FH_FLAG(p); frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p); - data_offset = (uint8_t *)p->ip6eh.ip6fh + sizeof(IPV6FragHdr) - GET_PKT_DATA(p); - data_len = IPV6_GET_PLEN(p) - ( - ((uint8_t *)p->ip6eh.ip6fh + sizeof(IPV6FragHdr)) - - ((uint8_t *)p->ip6h + sizeof(IPV6Hdr))); + data_offset = p->ip6eh.fh_data_offset; + data_len = p->ip6eh.fh_data_len; frag_end = frag_offset + data_len; ip_hdr_offset = (uint8_t *)p->ip6h - GET_PKT_DATA(p); - frag_hdr_offset = (uint8_t *)p->ip6eh.ip6fh - GET_PKT_DATA(p); + frag_hdr_offset = p->ip6eh.fh_header_offset; + + SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, " + "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u", + more_frags ? "true" : "false", frag_offset, data_offset, + data_len, frag_end, ip_hdr_offset, frag_hdr_offset); /* handle unfragmentable exthdrs */ if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) { - SCLogDebug("we have exthdrs before fraghdr %u bytes (%u hdrs total)", - (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN)), - p->ip6eh.ip6_exthdrs_cnt); + SCLogDebug("we have exthdrs before fraghdr %u bytes", + (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN))); /* get the offset of the 'next' field in exthdr before the FH, * relative to the buffer start */ - int t_offset = (int)((p->ip6eh.ip6_exthdrs[p->ip6eh.ip6_exthdrs_cnt - 2].data - 2) - GET_PKT_DATA(p)); /* store offset and FH 'next' value for updating frag buffer below */ - ip6_nh_set_offset = (int)t_offset; + ip6_nh_set_offset = p->ip6eh.fh_prev_hdr_offset; ip6_nh_set_value = IPV6_EXTHDR_GET_FH_NH(p); SCLogDebug("offset %d, value %u", ip6_nh_set_offset, ip6_nh_set_value); } @@ -1109,7 +1110,6 @@ IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, fh->ip6fh_nxt = IPPROTO_ICMP; fh->ip6fh_ident = htonl(id); fh->ip6fh_offlg = htons((off << 3) | mf); - p->ip6eh.ip6fh = fh; pcontent = SCCalloc(1, content_len); if (unlikely(pcontent == NULL)) diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index 28d66e9bf848..28d467b67044 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -87,7 +87,7 @@ int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet if (PKT_IS_IPV4(p)) { frag = IPV4_GET_IPOFFSET(p); } else if (PKT_IS_IPV6(p)) { - if(IPV6_EXTHDR_FH(p)) { + if (IPV6_EXTHDR_ISSET_FH(p)) { frag = IPV6_EXTHDR_GET_FH_OFFSET(p); } else { return 0; From abb0a31aed88f0f6f48ffa3bb5129e10afbd20dc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 15 May 2016 20:05:44 +0200 Subject: [PATCH 1392/2553] defrag: work around packet creation issues Defrag tests set up packets but don't call Decode on them. Work around failing IPv6 tests. --- src/decode-ipv6.c | 82 +++++++++++++++++++++++++++-------------------- src/defrag.c | 6 ++++ 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index c13b8806c993..9ca063065239 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -101,6 +101,49 @@ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint return TM_ECODE_OK; } +#ifndef UNITTESTS // ugly, but we need this in defrag tests +static inline +#endif +void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, + uint16_t hdrextlen, uint16_t plen, + uint16_t ip6_exthdrs_cnt, IPV6GenOptHdr *ip6_exthdrs) +{ + uint16_t frag_offset = (*(pkt + 2) << 8 | *(pkt + 3)) & 0xFFF8; + int frag_morefrags = (*(pkt + 2) << 8 | *(pkt + 3)) & 0x0001; + + p->ip6eh.fh_offset = frag_offset; + p->ip6eh.fh_more_frags_set = frag_morefrags ? TRUE : FALSE; + p->ip6eh.fh_nh = *pkt; + + uint32_t fh_id; + memcpy(&fh_id, pkt+4, 4); + p->ip6eh.fh_id = ntohl(fh_id); + + SCLogDebug("IPV6 FH: offset %u, mf %s, nh %u, id %u/%x", + p->ip6eh.fh_offset, + p->ip6eh.fh_more_frags_set ? "true" : "false", + p->ip6eh.fh_nh, + p->ip6eh.fh_id, p->ip6eh.fh_id); + + // store header offset, data offset + uint16_t frag_hdr_offset = (uint16_t)(pkt - GET_PKT_DATA(p)); + uint16_t data_offset = (uint16_t)(frag_hdr_offset + hdrextlen); + uint16_t data_len = plen - hdrextlen; + + p->ip6eh.fh_header_offset = frag_hdr_offset; + p->ip6eh.fh_data_offset = data_offset; + p->ip6eh.fh_data_len = data_len; + + /* if we have a prev hdr, store the type and offset of it */ + if (ip6_exthdrs_cnt > 1) { + p->ip6eh.fh_prev_hdr_offset = frag_hdr_offset - ip6_exthdrs[ip6_exthdrs_cnt - 1].len; + } + + SCLogDebug("IPV6 FH: frag_hdr_offset %u, data_offset %u, data_len %u", + p->ip6eh.fh_header_offset, p->ip6eh.fh_data_offset, + p->ip6eh.fh_data_len); +} + static void DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { @@ -429,46 +472,15 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt /* set the header flag first */ IPV6_EXTHDR_SET_FH(p); - uint16_t frag_offset = (*(pkt + 2) << 8 | *(pkt + 3)) & 0xFFF8; - int frag_morefrags = (*(pkt + 2) << 8 | *(pkt + 3)) & 0x0001; - - p->ip6eh.fh_offset = frag_offset; - p->ip6eh.fh_more_frags_set = frag_morefrags ? TRUE : FALSE; - p->ip6eh.fh_nh = *pkt; - - uint32_t fh_id; - memcpy(&fh_id, pkt+4, 4); - p->ip6eh.fh_id = ntohl(fh_id); - - SCLogDebug("IPV6 FH: offset %u, mf %s, nh %u, id %u/%x", - p->ip6eh.fh_offset, - p->ip6eh.fh_more_frags_set ? "true" : "false", - p->ip6eh.fh_nh, - p->ip6eh.fh_id, p->ip6eh.fh_id); - - // store header offset, data offset - uint16_t frag_hdr_offset = (uint16_t)(pkt - GET_PKT_DATA(p)); - uint16_t data_offset = (uint16_t)(frag_hdr_offset + hdrextlen); - uint16_t data_len = plen - hdrextlen; - - p->ip6eh.fh_header_offset = frag_hdr_offset; - p->ip6eh.fh_data_offset = data_offset; - p->ip6eh.fh_data_len = data_len; - - /* if we have a prev hdr, store the type and offset of it */ - if (ip6_exthdrs_cnt > 1) { - p->ip6eh.fh_prev_hdr_offset = frag_hdr_offset - ip6_exthdrs[ip6_exthdrs_cnt - 1].len; - } - - SCLogDebug("IPV6 FH: frag_hdr_offset %u, data_offset %u, data_len %u", - p->ip6eh.fh_header_offset, p->ip6eh.fh_data_offset, - p->ip6eh.fh_data_len); + /* parse the header and setup the vars */ + DecodeIPV6FragHeader(p, pkt, hdrextlen, plen, + ip6_exthdrs_cnt, ip6_exthdrs); /* if FH has offset 0 and no more fragments are coming, we * parse this packet further right away, no defrag will be * needed. It is a useless FH then though, so we do set an * decoder event. */ - if (frag_morefrags == 0 && frag_offset == 0) { + if (p->ip6eh.fh_more_frags_set == 0 && p->ip6eh.fh_offset == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_USELESS_FH); nh = *pkt; diff --git a/src/defrag.c b/src/defrag.c index 488f9113ea93..fd89a757f574 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -1071,6 +1071,10 @@ BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content, return NULL; } +void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, + uint16_t hdrextlen, uint16_t plen, + uint16_t ip6_exthdrs_cnt, IPV6GenOptHdr *ip6_exthdrs); + static Packet * IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, int content_len) @@ -1111,6 +1115,8 @@ IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, fh->ip6fh_ident = htonl(id); fh->ip6fh_offlg = htons((off << 3) | mf); + DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0, NULL); + pcontent = SCCalloc(1, content_len); if (unlikely(pcontent == NULL)) return NULL; From b77d30727235e9195e581dfc15fca05a2dac9be6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 16 May 2016 14:11:56 +0200 Subject: [PATCH 1393/2553] ipv6: simplify ext hdr parsing --- src/decode-ipv6.c | 64 ++++++----------------------------------------- src/defrag.c | 4 +-- 2 files changed, 10 insertions(+), 58 deletions(-) diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index 9ca063065239..ac0ad752ba2a 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -106,7 +106,7 @@ static inline #endif void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, uint16_t hdrextlen, uint16_t plen, - uint16_t ip6_exthdrs_cnt, IPV6GenOptHdr *ip6_exthdrs) + uint16_t prev_hdrextlen) { uint16_t frag_offset = (*(pkt + 2) << 8 | *(pkt + 3)) & 0xFFF8; int frag_morefrags = (*(pkt + 2) << 8 | *(pkt + 3)) & 0x0001; @@ -135,8 +135,8 @@ void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, p->ip6eh.fh_data_len = data_len; /* if we have a prev hdr, store the type and offset of it */ - if (ip6_exthdrs_cnt > 1) { - p->ip6eh.fh_prev_hdr_offset = frag_hdr_offset - ip6_exthdrs[ip6_exthdrs_cnt - 1].len; + if (prev_hdrextlen) { + p->ip6eh.fh_prev_hdr_offset = frag_hdr_offset - prev_hdrextlen; } SCLogDebug("IPV6 FH: frag_hdr_offset %u, data_offset %u, data_len %u", @@ -151,14 +151,10 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt uint8_t *orig_pkt = pkt; uint8_t nh = 0; /* careful, 0 is actually a real type */ - uint16_t hdrextlen; + uint16_t hdrextlen = 0; uint16_t plen; char dstopts = 0; char exthdr_fh_done = 0; - - uint8_t ip6_exthdrs_cnt = 0; - IPV6GenOptHdr ip6_exthdrs[IPV6_MAX_OPT]; - int hh = 0; int rh = 0; int eh = 0; @@ -212,15 +208,6 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt SCReturn; } - if (ip6_exthdrs_cnt < IPV6_MAX_OPT) - { - ip6_exthdrs[ip6_exthdrs_cnt].type = nh; - ip6_exthdrs[ip6_exthdrs_cnt].next = *pkt; - ip6_exthdrs[ip6_exthdrs_cnt].len = hdrextlen; - ip6_exthdrs[ip6_exthdrs_cnt].data = pkt+2; - ip6_exthdrs_cnt++; - } - if (rh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_RH); /* skip past this extension so we can continue parsing the rest @@ -260,15 +247,6 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt SCReturn; } - if (ip6_exthdrs_cnt < IPV6_MAX_OPT) - { - ip6_exthdrs[ip6_exthdrs_cnt].type = nh; - ip6_exthdrs[ip6_exthdrs_cnt].next = *pkt; - ip6_exthdrs[ip6_exthdrs_cnt].len = hdrextlen; - ip6_exthdrs[ip6_exthdrs_cnt].data = pkt+2; - ip6_exthdrs_cnt++; - } - uint8_t *ptr = pkt + 2; /* +2 to go past nxthdr and len */ /* point the pointers to right structures @@ -431,6 +409,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt } case IPPROTO_FRAGMENT: + { IPV6_SET_L4PROTO(p,nh); /* store the offset of this extension into the packet * past the ipv6 header. We use it in defrag for creating @@ -440,6 +419,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt exthdr_fh_done = 1; } + uint16_t prev_hdrextlen = hdrextlen; hdrextlen = sizeof(IPV6FragHdr); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); @@ -452,15 +432,6 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt /* non fatal, lets try to continue */ } - if(ip6_exthdrs_cntflags |= PKT_IS_FRAGMENT; SCReturn; - + } case IPPROTO_ESP: { IPV6_SET_L4PROTO(p,nh); @@ -502,15 +472,6 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt SCReturn; } - if(ip6_exthdrs_cntip6fh_ident = htonl(id); fh->ip6fh_offlg = htons((off << 3) | mf); - DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0, NULL); + DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0); pcontent = SCCalloc(1, content_len); if (unlikely(pcontent == NULL)) From baf528e751ba8a7fada47aca4ebd2cba2d2ed4a1 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 17 May 2016 13:40:01 -0600 Subject: [PATCH 1394/2553] typos: surictsc -> suricatasc Reported by Markus Lude on the mailing list. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c6c5e9a172d9..d5719d7748ed 100644 --- a/configure.ac +++ b/configure.ac @@ -120,14 +120,14 @@ if test "x$enable_python" = "xno" ; then echo echo " Warning! python disabled, you will not be " - echo " able to install surictasc unix socket client " + echo " able to install suricatasc unix socket client " echo enable_python="no" fi if test "$HAVE_PYTHON_CONFIG" = "no"; then echo echo " Warning! python not found, you will not be " - echo " able to install surictasc unix socket client " + echo " able to install suricatasc unix socket client " echo enable_python="no" fi From 3da79610afda76f9f32aad13c1bae202f9d803f6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 17 May 2016 13:40:43 -0600 Subject: [PATCH 1395/2553] typo: SURCATA -> SURICATA --- src/app-layer-template.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-template.c b/src/app-layer-template.c index c89e7b241d86..1a2cce0ec186 100644 --- a/src/app-layer-template.c +++ b/src/app-layer-template.c @@ -49,7 +49,7 @@ * * Example rule: * - * alert template any any -> any any (msg:"SURCATA Template empty message"; \ + * alert template any any -> any any (msg:"SURICATA Template empty message"; \ * app-layer-event:template.empty_message; sid:X; rev:Y;) */ enum { From a13df67864d05ba56a9751e7310001296f7c6d59 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 18 May 2016 13:49:47 +0200 Subject: [PATCH 1396/2553] detect: add (mpm) keyword for tls_sni Match on server name indication (SNI) extension in TLS using tls_sni keyword, e.g: alert tls any any -> any any (msg:"SNI test"; tls_sni; content:"example.com"; sid:12345;) --- src/Makefile.am | 2 + src/detect-engine-analyzer.c | 2 + src/detect-engine-content-inspection.h | 1 + src/detect-engine-mpm.c | 6 +- src/detect-engine-state.h | 3 +- src/detect-engine-tls.c | 145 +++++++++++ src/detect-engine-tls.h | 31 +++ src/detect-engine.c | 11 + src/detect-fast-pattern.c | 12 +- src/detect-parse.c | 6 + src/detect-tls-sni.c | 341 +++++++++++++++++++++++++ src/detect-tls-sni.h | 33 +++ src/detect.c | 20 ++ src/detect.h | 9 +- src/suricata-common.h | 1 + src/util-profiling.c | 1 + 16 files changed, 616 insertions(+), 8 deletions(-) create mode 100644 src/detect-engine-tls.c create mode 100644 src/detect-engine-tls.h create mode 100644 src/detect-tls-sni.c create mode 100644 src/detect-tls-sni.h diff --git a/src/Makefile.am b/src/Makefile.am index e2369c70f79c..b81bb7be562e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -87,6 +87,7 @@ detect-depth.c detect-depth.h \ detect-detection-filter.c detect-detection-filter.h \ detect-distance.c detect-distance.h \ detect-dns-query.c detect-dns-query.h \ +detect-tls-sni.c detect-tls-sni.h \ detect-dsize.c detect-dsize.h \ detect-engine-address.c detect-engine-address.h \ detect-engine-address-ipv4.c detect-engine-address-ipv4.h \ @@ -98,6 +99,7 @@ detect-engine.c detect-engine.h \ detect-engine-content-inspection.c detect-engine-content-inspection.h \ detect-engine-dcepayload.c detect-engine-dcepayload.h \ detect-engine-dns.c detect-engine-dns.h \ +detect-engine-tls.c detect-engine-tls.h \ detect-engine-modbus.c detect-engine-modbus.h \ detect-engine-event.c detect-engine-event.h \ detect-engine-file.c detect-engine-file.h \ diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 80d76e607cc6..ade8ec0946ec 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -478,6 +478,8 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "http user agent content"); else if (list_type == DETECT_SM_LIST_DNSQUERYNAME_MATCH) fprintf(rule_engine_analysis_FD, "dns query name content"); + else if (list_type == DETECT_SM_LIST_TLSSNI_MATCH) + fprintf(rule_engine_analysis_FD, "tls sni extension content"); fprintf(rule_engine_analysis_FD, "\" buffer.\n"); diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 5e80b9b8ccd5..7636fdf2c0d5 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -49,6 +49,7 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSNI, DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, DETECT_ENGINE_CONTENT_INSPECTION_MODE_BASE64, DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 75232c50345f..04cca7844f7b 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -106,6 +106,8 @@ AppLayerMpms app_mpms[] = { { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, SIG_GROUP_HEAD_MPM_DNSQUERY, 17}, + { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, SIG_GROUP_HEAD_MPM_TLSSNI, 18}, + { NULL, 0, 0, 0, 0, 0, } }; @@ -1207,7 +1209,9 @@ void MpmStoreFixup(SigGroupHead *sgh) SET_TS(sgh, sgh->mpm_dnsquery_ctx_ts); - BUG_ON(APP_MPMS_MAX != 18 || i != 18); + SET_TS(sgh, sgh->mpm_tlssni_ctx_ts); + + BUG_ON(APP_MPMS_MAX != 19 || i != 19); #undef SET_TS #undef SET_TC diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index c5264816ee5b..7b48f2c5b7cd 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -87,7 +87,8 @@ #define DE_STATE_FLAG_FD_SMTP_INSPECT (1 << 21) #define DE_STATE_FLAG_DNSREQUEST_INSPECT (1 << 22) #define DE_STATE_FLAG_DNSRESPONSE_INSPECT (1 << 23) -#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT (1 << 24) +#define DE_STATE_FLAG_TLSSNI_INSPECT (1 << 24) +#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT (1 << 25) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c new file mode 100644 index 000000000000..2cac96a01ce7 --- /dev/null +++ b/src/detect-engine-tls.c @@ -0,0 +1,145 @@ +/* Copyright (C) 2016 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 Mats Klepsland + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-engine-content-inspection.h" + +#include "flow-util.h" +#include "util-debug.h" +#include "util-print.h" +#include "flow.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-protos.h" +#include "app-layer-ssl.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-validate.h" + +/** + * \brief TLS sni match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx + * \param hrh Buffer to inspect + * \param hrh_len Buffer length + * \param flags Flags + * + * \retval ret Number of matches + */ +static inline uint32_t TlsSniPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *buffer, + const uint32_t buffer_len, + const uint8_t flags) +{ + SCEnter(); + + uint32_t ret = 0; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_tlssni_ctx_ts == NULL); + + if (buffer_len >= det_ctx->sgh->mpm_tlssni_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_tlssni_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_tlssni_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); + } + + SCReturnUInt(ret); +} + +/** + * \brief Run the pattern matcher against the SNI buffer + * + * \param det_ctx Detection engine thread ctx + * \param f Locked flow + * \param dns_state Initialized dns state + * \param flags Flags + * + * \retval cnt Number of matches + */ +uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, + SSLState *ssl_state, uint8_t flags) +{ + SCEnter(); + + uint8_t *buffer; + uint32_t buffer_len; + uint32_t cnt = 0; + + if (ssl_state->client_connp.sni == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->client_connp.sni; + buffer_len = strlen(ssl_state->client_connp.sni); + + cnt = TlsSniPatternSearch(det_ctx, buffer, buffer_len, flags); + + SCReturnUInt(cnt); +} + +/** \brief Do the content inspection and validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags App layer flags + * \param state App layer state + * + * \retval 0 No match + * \retval 1 Match + */ +int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, + Flow *f, uint8_t flags, void *alstate, void *txv, + uint64_t tx_id) +{ + uint8_t *buffer; + uint16_t buffer_len; + int cnt = 0; + + SSLState *ssl_state = (SSLState *)alstate; + + if (ssl_state->client_connp.sni == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->client_connp.sni; + buffer_len = strlen(ssl_state->client_connp.sni); + + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_TLSSNI_MATCH], + f, buffer, buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSNI, NULL); + + return cnt; +} diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h new file mode 100644 index 000000000000..3a9d530f0c9f --- /dev/null +++ b/src/detect-engine-tls.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2016 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 Mats Klepsland + */ + +#ifndef __DETECT_ENGINE_TLS_H__ +#define __DETECT_ENGINE_TLS_H__ + +int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); + +#endif /* __DETECT_ENGINE_TLS_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 1546aef3eed7..6a66a45d9fee 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -59,6 +59,7 @@ #include "detect-engine-hrhhd.h" #include "detect-engine-file.h" #include "detect-engine-dns.h" +#include "detect-engine-tls.h" #include "detect-engine-modbus.h" #include "detect-engine-filedata-smtp.h" #include "detect-engine-template.h" @@ -269,6 +270,13 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_DNSREQUEST_INSPECT, 0, DetectEngineInspectDnsRequest }, + /* TLS */ + { IPPROTO_TCP, + ALPROTO_TLS, + DETECT_SM_LIST_TLSSNI_MATCH, + DE_STATE_FLAG_TLSSNI_INSPECT, + 0, + DetectEngineInspectTlsSni }, /* SMTP */ { IPPROTO_TCP, ALPROTO_SMTP, @@ -2726,6 +2734,9 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_DNSRESPONSE_MATCH: return "dns response"; + case DETECT_SM_LIST_TLSSNI_MATCH: + return "tls sni extension"; + case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index dff7a4cc4aeb..dc7d94c64e09 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -136,6 +136,8 @@ void SupportFastPatternForSigMatchTypes(void) SupportFastPatternForSigMatchList(DETECT_SM_LIST_DNSQUERYNAME_MATCH, 2); + SupportFastPatternForSigMatchList(DETECT_SM_LIST_TLSSNI_MATCH, 2); + #if 0 SCFPSupportSMList *tmp = sm_fp_support_smlist_list; while (tmp != NULL) { @@ -202,15 +204,16 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL) { + s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL && + s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH] == NULL) { SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " "rule, without a preceding content based keyword. " "Currently we provide fast_pattern support for content, " "uricontent, http_client_body, http_server_body, http_header, " "http_raw_header, http_method, http_cookie, " "http_raw_uri, http_stat_msg, http_stat_code, " - "http_user_agent, http_host, http_raw_host or " - "dns_query option"); + "http_user_agent, http_host, http_raw_host, " + "dns_query or tls_sni option"); return -1; } @@ -229,7 +232,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " "the rule, without a content context. Please use a " diff --git a/src/detect-parse.c b/src/detect-parse.c index d86826cdf1ae..4adef8f84ea4 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -167,6 +167,7 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_DNSREQUEST_MATCH, "dns_request"); CASE_CODE_STRING(DETECT_SM_LIST_DNSRESPONSE_MATCH, "dns_response"); CASE_CODE_STRING(DETECT_SM_LIST_DNSQUERYNAME_MATCH, "dns_query"); + CASE_CODE_STRING(DETECT_SM_LIST_TLSSNI_MATCH, "tls_sni"); CASE_CODE_STRING(DETECT_SM_LIST_MODBUS_MATCH, "modbus"); CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); @@ -207,6 +208,7 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_DNSREQUEST_MATCH); CASE_CODE(DETECT_SM_LIST_DNSRESPONSE_MATCH); CASE_CODE(DETECT_SM_LIST_DNSQUERYNAME_MATCH); + CASE_CODE(DETECT_SM_LIST_TLSSNI_MATCH); CASE_CODE(DETECT_SM_LIST_MODBUS_MATCH); CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); CASE_CODE(DETECT_SM_LIST_POSTMATCH); @@ -1554,6 +1556,10 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; } + /* TLS */ + if (sig->sm_lists[DETECT_SM_LIST_TLSSNI_MATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_MODBUS_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_APP_EVENT]) diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c new file mode 100644 index 000000000000..31c001c1f70b --- /dev/null +++ b/src/detect-tls-sni.c @@ -0,0 +1,341 @@ +/* Copyright (C) 2007-2016 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 Mats Klepsland + * + * Implements support for tls_sni keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-spm.h" +#include "util-print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-ssl.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static int DetectTlsSniSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTlsSniRegisterTests(void); + +/** + * \brief Registration function for keyword: tls_sni + */ +void DetectTlsSniRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_SNI].name = "tls_sni"; + sigmatch_table[DETECT_AL_TLS_SNI].desc = "content modifier to match specifically and only on the TLS SNI buffer"; + sigmatch_table[DETECT_AL_TLS_SNI].Match = NULL; + sigmatch_table[DETECT_AL_TLS_SNI].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_TLS_SNI].alproto = ALPROTO_TLS; + sigmatch_table[DETECT_AL_TLS_SNI].Setup = DetectTlsSniSetup; + sigmatch_table[DETECT_AL_TLS_SNI].Free = NULL; + sigmatch_table[DETECT_AL_TLS_SNI].RegisterTests = DetectTlsSniRegisterTests; + + sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_PAYLOAD; +} + + +/** + * \brief this function setup the tls_sni modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectTlsSniSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + s->list = DETECT_SM_LIST_TLSSNI_MATCH; + s->alproto = ALPROTO_TLS; + return 0; +} + +#ifdef UNITTESTS + +/** + * \test Test matching on a simple google.com SNI + */ +static int DetectTlsSniTest01(void) +{ + /* client hello */ + uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0xAE, 0x01, 0x00, 0x00, 0xAA, + 0x03, 0x03, 0x57, 0x04, 0x9F, 0x5D, 0xC9, 0x5C, 0x87, + 0xAE, 0xF2, 0xA7, 0x4A, 0xFC, 0x59, 0x78, 0x23, 0x31, + 0x61, 0x2D, 0x29, 0x92, 0xB6, 0x70, 0xA5, 0xA1, 0xFC, + 0x0E, 0x79, 0xFE, 0xC3, 0x97, 0x37, 0xC0, 0x00, 0x00, + 0x44, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0D, + 0x00, 0x10, 0x00, 0x13, 0x00, 0x16, 0x00, 0x2F, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, + 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, + 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40, + 0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00, 0x66, 0x00, + 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B, + 0x00, 0x84, 0x00, 0x87, 0x00, 0xFF, 0x01, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x00, + 0x0A, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x63, + 0x6F, 0x6D, }; + + int result = 0; + Flow f; + SSLState *ssl_state = NULL; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", + 41424, 443); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER|FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_TLS; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_sni option\"; " + "tls_sni; content:\"google.com\"; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf, sizeof(buf)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ssl_state = f.alstate; + if (ssl_state == NULL) { + printf("no ssl state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert, but it should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** + * \test Test matching on a simple google.com SNI with pcre + */ +static int DetectTlsSniTest02(void) +{ + /* client hello */ + uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0xAE, 0x01, 0x00, 0x00, 0xAA, + 0x03, 0x03, 0x57, 0x04, 0x9F, 0x5D, 0xC9, 0x5C, 0x87, + 0xAE, 0xF2, 0xA7, 0x4A, 0xFC, 0x59, 0x78, 0x23, 0x31, + 0x61, 0x2D, 0x29, 0x92, 0xB6, 0x70, 0xA5, 0xA1, 0xFC, + 0x0E, 0x79, 0xFE, 0xC3, 0x97, 0x37, 0xC0, 0x00, 0x00, + 0x44, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0D, + 0x00, 0x10, 0x00, 0x13, 0x00, 0x16, 0x00, 0x2F, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, + 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, + 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40, + 0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00, 0x66, 0x00, + 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B, + 0x00, 0x84, 0x00, 0x87, 0x00, 0xFF, 0x01, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x00, + 0x0A, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x63, + 0x6F, 0x6D, }; + + int result = 0; + Flow f; + SSLState *ssl_state = NULL; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", + 41424, 443); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER|FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_TLS; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_sni option\"; " + "tls_sni; content:\"google\"; nocase; " + "pcre:\"/google\\.com$/i\"; sid:1;)"); + if (s == NULL) { + goto end; + } + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_sni option\"; " + "tls_sni; content:\"google\"; nocase; " + "pcre:\"/^\\.[a-z]{2,3}$/iR\"; sid:2;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf, sizeof(buf)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ssl_state = f.alstate; + if (ssl_state == NULL) { + printf("no ssl state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert, but it should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 2))) { + printf("sig 2 didn't alert, but it should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +#endif + +static void DetectTlsSniRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectTlsSniTest01", DetectTlsSniTest01); + UtRegisterTest("DetectTlsSniTest02", DetectTlsSniTest02); +#endif +} diff --git a/src/detect-tls-sni.h b/src/detect-tls-sni.h new file mode 100644 index 000000000000..8e6d93086cad --- /dev/null +++ b/src/detect-tls-sni.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2016 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 Mats Klepsland + */ + +#ifndef __DETECT_TLS_SNI_H__ +#define __DETECT_TLS_SNI_H__ + +#include "app-layer-ssl.h" + +void DetectTlsSniRegister(void); +uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, + SSLState *ssl_state, uint8_t flags); + +#endif /* __DETECT_TLS_SNI_H__ */ diff --git a/src/detect.c b/src/detect.c index 60ca9795f578..3c5929516bfb 100644 --- a/src/detect.c +++ b/src/detect.c @@ -48,6 +48,7 @@ #include "detect-engine-dcepayload.h" #include "detect-engine-uri.h" #include "detect-dns-query.h" +#include "detect-tls-sni.h" #include "detect-engine-state.h" #include "detect-engine-analyzer.h" #include "detect-engine-filedata-smtp.h" @@ -1065,6 +1066,24 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectDnsQueryInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY); } + FLOWLOCK_UNLOCK(p->flow); + } + } + } else if (alproto == ALPROTO_TLS && has_state) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSSNI) { + FLOWLOCK_RDLOCK(p->flow); + void *alstate = FlowGetAppState(p->flow); + if (alstate == NULL) { + SCLogDebug("no alstate"); + FLOWLOCK_UNLOCK(p->flow); + return; + } + + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSSNI); + DetectTlsSniInspectMpm(det_ctx, p->flow, alstate, flags); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSNI); + FLOWLOCK_UNLOCK(p->flow); } } @@ -4407,6 +4426,7 @@ void SigTableSetup(void) DetectLuaRegister(); DetectIPRepRegister(); DetectDnsQueryRegister(); + DetectTlsSniRegister(); DetectModbusRegister(); DetectAppLayerProtocolRegister(); DetectBase64DecodeRegister(); diff --git a/src/detect.h b/src/detect.h index 333381457be2..90c650298425 100644 --- a/src/detect.h +++ b/src/detect.h @@ -124,6 +124,8 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_DNSRESPONSE_MATCH, /**< per DNS response tx match list */ DETECT_SM_LIST_DNSQUERYNAME_MATCH, /**< per query in a tx list */ + DETECT_SM_LIST_TLSSNI_MATCH, + DETECT_SM_LIST_MODBUS_MATCH, DETECT_SM_LIST_BASE64_DATA, @@ -929,9 +931,10 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_HAVEFILEMD5 (1 << 21) #define SIG_GROUP_HEAD_HAVEFILESIZE (1 << 22) #define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 23) -#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 24) +#define SIG_GROUP_HEAD_MPM_TLSSNI (1 << 24) +#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 25) -#define APP_MPMS_MAX 18 +#define APP_MPMS_MAX 19 enum MpmBuiltinBuffers { MPMB_TCP_PKT_TS, @@ -1009,6 +1012,7 @@ typedef struct SigGroupHead_ { const MpmCtx *mpm_hhhd_ctx_ts; const MpmCtx *mpm_hrhhd_ctx_ts; const MpmCtx *mpm_dnsquery_ctx_ts; + const MpmCtx *mpm_tlssni_ctx_ts; const MpmCtx *mpm_smtp_filedata_ctx_ts; }; struct { @@ -1209,6 +1213,7 @@ enum { DETECT_IPREP, DETECT_AL_DNS_QUERY, + DETECT_AL_TLS_SNI, DETECT_AL_MODBUS, DETECT_XBITS, diff --git a/src/suricata-common.h b/src/suricata-common.h index 18791c3b04bc..141e8671d961 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -320,6 +320,7 @@ typedef enum PacketProfileDetectId_ { PROF_DETECT_MPM_HHHD, PROF_DETECT_MPM_HRHHD, PROF_DETECT_MPM_DNSQUERY, + PROF_DETECT_MPM_TLSSNI, PROF_DETECT_IPONLY, PROF_DETECT_RULES, PROF_DETECT_STATEFUL, diff --git a/src/util-profiling.c b/src/util-profiling.c index ee25076e8ca7..f63ee92987e4 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1028,6 +1028,7 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id) CASE_CODE (PROF_DETECT_MPM_HSCD); CASE_CODE (PROF_DETECT_MPM_HUAD); CASE_CODE (PROF_DETECT_MPM_DNSQUERY); + CASE_CODE (PROF_DETECT_MPM_TLSSNI); CASE_CODE (PROF_DETECT_IPONLY); CASE_CODE (PROF_DETECT_RULES); CASE_CODE (PROF_DETECT_PREFILTER); From a81766c046ef463c3a1c527770702552765f9843 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 16 Apr 2016 21:30:32 +0200 Subject: [PATCH 1397/2553] detect: split detect entry into flow/noflow This is a preparation for flow locking updates. --- src/detect.c | 85 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/src/detect.c b/src/detect.c index 3c5929516bfb..de8dab978f49 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1979,18 +1979,10 @@ static DetectEngineThreadCtx *GetTenantById(HashTable *h, uint32_t id) return HashTableLookup(h, &id, 0); } -/** \brief Detection engine thread wrapper. - * \param tv thread vars - * \param p packet to inspect - * \param data thread specific data - * \param pq packet queue - * \retval TM_ECODE_FAILED error - * \retval TM_ECODE_OK ok - */ -TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) +static void DetectFlow(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Packet *p) { - DEBUG_VALIDATE_PACKET(p); - /* No need to perform any detection on this packet, if the the given flag is set.*/ if ((p->flags & PKT_NOPACKET_INSPECTION) || (PACKET_TEST_ACTION(p, ACTION_DROP))) @@ -1998,25 +1990,53 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue /* hack: if we are in pass the entire flow mode, we need to still * update the inspect_id forward. So test for the condition here, * and call the update code if necessary. */ - if (p->flow) { - uint8_t flags = 0; - FLOWLOCK_RDLOCK(p->flow); - int pass = ((p->flow->flags & FLOW_NOPACKET_INSPECTION)); - flags = FlowGetDisruptionFlags(p->flow, flags); - AppProto alproto = FlowGetAppProtocol(p->flow); - FLOWLOCK_UNLOCK(p->flow); - if (pass && AppLayerParserProtocolSupportsTxs(p->proto, alproto)) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - flags |= STREAM_TOSERVER; - } else { - flags |= STREAM_TOCLIENT; - } - DeStateUpdateInspectTransactionId(p->flow, flags); + int pass = ((p->flow->flags & FLOW_NOPACKET_INSPECTION)); + uint8_t flags = FlowGetDisruptionFlags(p->flow, 0); + AppProto alproto = FlowGetAppProtocol(p->flow); + if (pass && AppLayerParserProtocolSupportsTxs(p->proto, alproto)) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + flags |= STREAM_TOSERVER; + } else { + flags |= STREAM_TOCLIENT; } + DeStateUpdateInspectTransactionId(p->flow, flags); } - return 0; + return; } + /* see if the packet matches one or more of the sigs */ + (void)SigMatchSignatures(tv,de_ctx,det_ctx,p); +} + + +static void DetectNoFlow(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Packet *p) +{ + /* No need to perform any detection on this packet, if the the given flag is set.*/ + if ((p->flags & PKT_NOPACKET_INSPECTION) || + (PACKET_TEST_ACTION(p, ACTION_DROP))) + { + return; + } + + /* see if the packet matches one or more of the sigs */ + (void)SigMatchSignatures(tv,de_ctx,det_ctx,p); + return; +} + +/** \brief Detection engine thread wrapper. + * \param tv thread vars + * \param p packet to inspect + * \param data thread specific data + * \param pq packet queue + * \retval TM_ECODE_FAILED error + * \retval TM_ECODE_OK ok + */ +TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) +{ + DEBUG_VALIDATE_PACKET(p); + DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; if (det_ctx == NULL) { @@ -2024,7 +2044,7 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue goto error; } - if (SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0) { + if (unlikely(SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0)) { (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); SCLogDebug("Detect Engine using new det_ctx - %p", det_ctx); @@ -2046,7 +2066,7 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue if (de_ctx == NULL) return TM_ECODE_OK; - if (SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0) { + if (unlikely(SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0)) { (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); SCLogDebug("MT de_ctx %p det_ctx %p (tenant %u)", de_ctx, det_ctx, tenant_id); } @@ -2058,11 +2078,12 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue de_ctx = det_ctx->de_ctx; } - /* see if the packet matches one or more of the sigs */ - int r = SigMatchSignatures(tv,de_ctx,det_ctx,p); - if (r >= 0) { - return TM_ECODE_OK; + if (p->flow) { + DetectFlow(tv, de_ctx, det_ctx, p); + } else { + DetectNoFlow(tv, de_ctx, det_ctx, p); } + return TM_ECODE_OK; error: return TM_ECODE_FAILED; From ae7aae81dc25271f30d4c26f0588f65ad8f44c09 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 Mar 2015 12:48:14 +0100 Subject: [PATCH 1398/2553] flow: get flow reference during lookup Update Flow lookup functions to get a flow reference during lookup. This reference is set under the FlowBucket lock. This paves the way to not getting a flow lock during lookups. --- src/flow-hash.c | 13 ++++++++++--- src/flow-hash.h | 2 +- src/flow.c | 5 +---- src/flow.h | 4 ++-- src/stream-tcp.c | 4 ++-- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index f6d746630c2a..20f1d36c611d 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -418,7 +418,7 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) return f; } -Flow *FlowGetFlowFromHashByPacket(const Packet *p) +Flow *FlowGetFlowFromHashByPacket(const Packet *p, Flow **dest) { Flow *f = NULL; @@ -448,6 +448,7 @@ Flow *FlowGetFlowFromHashByPacket(const Packet *p) f->fb = fb; /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); + FlowReference(dest, f); } FBLOCK_UNLOCK(fb); @@ -463,7 +464,7 @@ Flow *FlowGetFlowFromHashByPacket(const Packet *p) * * \retval f flow or NULL if not found */ -Flow *FlowLookupFlowFromHash(const Packet *p) +Flow *FlowLookupFlowFromHash(const Packet *p, Flow **dest) { Flow *f = NULL; @@ -516,6 +517,7 @@ Flow *FlowLookupFlowFromHash(const Packet *p) FLOWLOCK_WRLOCK(f); /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); + FlowReference(dest, f); FBLOCK_UNLOCK(fb); return f; @@ -527,6 +529,7 @@ Flow *FlowLookupFlowFromHash(const Packet *p) FLOWLOCK_WRLOCK(f); /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); + FlowReference(dest, f); FBLOCK_UNLOCK(fb); return f; @@ -549,7 +552,7 @@ Flow *FlowLookupFlowFromHash(const Packet *p) * * \retval f *LOCKED* flow or NULL */ -Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) +Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p, Flow **dest) { Flow *f = NULL; @@ -580,6 +583,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); + FlowReference(dest, f); FBLOCK_UNLOCK(fb); return f; @@ -615,6 +619,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); + FlowReference(dest, f); FBLOCK_UNLOCK(fb); return f; @@ -642,6 +647,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p FLOWLOCK_WRLOCK(f); /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); + FlowReference(dest, f); FBLOCK_UNLOCK(fb); return f; @@ -653,6 +659,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p FLOWLOCK_WRLOCK(f); /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); + FlowReference(dest, f); FBLOCK_UNLOCK(fb); return f; diff --git a/src/flow-hash.h b/src/flow-hash.h index 16d408521b54..e570b055513c 100644 --- a/src/flow-hash.h +++ b/src/flow-hash.h @@ -68,7 +68,7 @@ typedef struct FlowBucket_ { /* prototypes */ -Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *); +Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *, Flow **); void FlowDisableTcpReuseHandling(void); diff --git a/src/flow.c b/src/flow.c index a2e1a64cd42a..9c3973e65495 100644 --- a/src/flow.c +++ b/src/flow.c @@ -270,9 +270,6 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p) { SCLogDebug("packet %"PRIu64" -- flow %p", p->pcap_cnt, f); - /* Point the Packet at the Flow */ - FlowReference(&p->flow, f); - /* update flags and counters */ if (FlowGetPacketDirection(f, p) == TOSERVER) { f->todstpktcnt++; @@ -329,7 +326,7 @@ void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) /* Get this packet's flow from the hash. FlowHandlePacket() will setup * a new flow if nescesary. If we get NULL, we're out of flow memory. * The returned flow is locked. */ - Flow *f = FlowGetFlowFromHash(tv, dtv, p); + Flow *f = FlowGetFlowFromHash(tv, dtv, p, &p->flow); if (f == NULL) return; diff --git a/src/flow.h b/src/flow.h index 5953b55fcfae..2085f32242ed 100644 --- a/src/flow.h +++ b/src/flow.h @@ -580,8 +580,8 @@ uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags); void FlowHandlePacketUpdateRemove(Flow *f, Packet *p); void FlowHandlePacketUpdate(Flow *f, Packet *p); -Flow *FlowGetFlowFromHashByPacket(const Packet *p); -Flow *FlowLookupFlowFromHash(const Packet *p); +Flow *FlowGetFlowFromHashByPacket(const Packet *p, Flow **dest); +Flow *FlowLookupFlowFromHash(const Packet *p, Flow **dest); #endif /* __FLOW_H__ */ diff --git a/src/stream-tcp.c b/src/stream-tcp.c index b83d45c33644..22cb446c8f45 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4920,7 +4920,7 @@ static void TcpSessionReuseHandle(Packet *p) { * a different thread. */ /* Get a flow. It will be either a locked flow or NULL */ - Flow *new_f = FlowGetFlowFromHashByPacket(p); + Flow *new_f = FlowGetFlowFromHashByPacket(p, &p->flow); if (new_f == NULL) { FlowDeReference(&old_f); // < can't disappear while usecnt >0 return; @@ -4992,7 +4992,7 @@ static void TcpSessionReuseHandleApplyToPacket(Packet *p) FlowDeReference(&p->flow); // < can't disappear while usecnt >0 /* find the new flow that does belong to this packet */ - Flow *new_f = FlowLookupFlowFromHash(p); + Flow *new_f = FlowLookupFlowFromHash(p, &p->flow); if (new_f == NULL) { // TODO reset packet flag wrt flow: direction, HAS_FLOW etc p->flags &= ~PKT_HAS_FLOW; From 2f0e0f17dbb4f289f045ab38cf13dc2ef209a148 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 15 Apr 2016 17:08:50 +0200 Subject: [PATCH 1399/2553] flow: move flow handling into worker threads Instead of handling the packet update during flow lookup, handle it in the stream/detect threads. This lowers the load of the capture thread(s) in autofp mode. The decoders now set a flag in the packet if the packet needs a flow lookup. Then the workers will take care of this. The decoders also already calculate the raw flow hash value. This is so that this value can be used in flow balancing in autofp. Because the flow lookup/creation is now done in the worker threads, the flow balancing can no longer use the flow. It's not yet available. Autofp load balancing uses raw hash values instead. In the same line, move UDP AppLayer out of the DecodeUDP module, and also into the stream/detect threads. Handle TCP session reuse inside the flow engine itself. If a looked up flow matches the packet, but is a TCP stream starter, check if the ssn needs to be reused. If that is the case handle it within the lookup function. Simplies the locking and removes potential race conditions. --- src/app-layer.c | 5 +- src/decode-icmpv4.c | 2 +- src/decode-icmpv6.c | 3 +- src/decode-ipv4.c | 8 +- src/decode-sctp.c | 3 +- src/decode-tcp.c | 3 +- src/decode-udp.c | 10 +- src/decode.h | 8 ++ src/flow-hash.c | 173 +++++++++----------------------- src/flow.c | 35 ------- src/flow.h | 9 +- src/runmode-erf-file.c | 1 - src/runmode-pcap-file.c | 1 - src/stream-tcp.c | 200 +++++++------------------------------ src/stream-tcp.h | 4 - src/tmqh-flow.c | 34 ++++++- src/util-runmodes.c | 19 ---- src/util-unittest-helper.c | 4 +- 18 files changed, 143 insertions(+), 379 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index b0955769c995..db4fa3abed95 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -461,7 +461,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, * If the protocol is yet unknown, the proto detection code is run first. * * \param dp_ctx Thread app layer detect context - * \param f unlocked flow + * \param f *locked* flow * \param p UDP packet * * \retval 0 ok @@ -473,8 +473,6 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * int r = 0; - FLOWLOCK_WRLOCK(f); - uint8_t flags = 0; if (p->flowflags & FLOW_PKT_TOSERVER) { flags |= STREAM_TOSERVER; @@ -527,7 +525,6 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * } } - FLOWLOCK_UNLOCK(f); PACKET_PROFILING_APP_STORE(tctx, p); SCReturnInt(r); diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index 3e08daa19753..1cfaf780780a 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -194,7 +194,7 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, { /* ICMP ICMP_DEST_UNREACH influence TCP/UDP flows */ if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { - FlowHandlePacket(tv, dtv, p); + FlowSetupPacket(p); } } } diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index 238a6cf6faeb..26a48b7439af 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -362,8 +362,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, SCLogDebug("Unknown Type, ICMPV6_UNKNOWN_TYPE"); #endif - /* Flow is an integral part of us */ - FlowHandlePacket(tv, dtv, p); + FlowSetupPacket(p); return TM_ECODE_OK; } diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index a41c35bfd7b0..c21d22460045 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -1518,7 +1518,6 @@ int DecodeIPV4DefragTest03(void) 0x80, 0x00, 0xb1, 0xa3, 0x00, 0x00 }; - Flow *f = NULL; Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -1542,12 +1541,11 @@ int DecodeIPV4DefragTest03(void) result = 0; goto end; } - if (p->flow == NULL) { + if (!(p->flags & PKT_WANTS_FLOW)) { printf("packet flow shouldn't be NULL\n"); result = 0; goto end; } - f = p->flow; PACKET_RECYCLE(p); PacketCopyData(p, pkt1, sizeof(pkt1)); @@ -1585,11 +1583,11 @@ int DecodeIPV4DefragTest03(void) result = 0; goto end; } - if (tp->flow == NULL) { + if (!(tp->flags & PKT_WANTS_FLOW)) { result = 0; goto end; } - if (tp->flow != f) { + if (tp->flow_hash != p->flow_hash) { result = 0; goto end; } diff --git a/src/decode-sctp.c b/src/decode-sctp.c index 2d493c6690fe..f787933ebd9d 100644 --- a/src/decode-sctp.c +++ b/src/decode-sctp.c @@ -73,8 +73,7 @@ int DecodeSCTP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u SCTP_GET_SRC_PORT(p), SCTP_GET_DST_PORT(p)); #endif - /* Flow is an integral part of us */ - FlowHandlePacket(tv, dtv, p); + FlowSetupPacket(p); return TM_ECODE_OK; } diff --git a/src/decode-tcp.c b/src/decode-tcp.c index b3c73b5d8910..51dbfaaa26ac 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -214,8 +214,7 @@ int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui TCP_HAS_MSS(p) ? "MSS " : ""); #endif - /* Flow is an integral part of us */ - FlowHandlePacket(tv, dtv, p); + FlowSetupPacket(p); return TM_ECODE_OK; } diff --git a/src/decode-udp.c b/src/decode-udp.c index 24f9207b8cbf..d45d57f2548e 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -85,17 +85,11 @@ int DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui if (unlikely(DecodeTeredo(tv, dtv, p, p->payload, p->payload_len, pq) == TM_ECODE_OK)) { /* Here we have a Teredo packet and don't need to handle app * layer */ - FlowHandlePacket(tv, dtv, p); + FlowSetupPacket(p); return TM_ECODE_OK; } - /* Flow is an integral part of us */ - FlowHandlePacket(tv, dtv, p); - - /* handle the app layer part of the UDP packet payload */ - if (unlikely(p->flow != NULL)) { - AppLayerHandleUdp(tv, dtv->app_tctx, p, p->flow); - } + FlowSetupPacket(p); return TM_ECODE_OK; } diff --git a/src/decode.h b/src/decode.h index 4c83d08300c8..a8641a23a057 100644 --- a/src/decode.h +++ b/src/decode.h @@ -399,6 +399,10 @@ typedef struct Packet_ struct Flow_ *flow; + /* raw hash value for looking up the flow, will need to modulated to the + * hash size still */ + uint32_t flow_hash; + struct timeval ts; union { @@ -1049,6 +1053,10 @@ int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder); #define PKT_IS_INVALID (1<<20) #define PKT_PROFILE (1<<21) +/** indication by decoder that it feels the packet should be handled by + * flow engine: Packet::flow_hash will be set */ +#define PKT_WANTS_FLOW (1<<22) + /** \brief return 1 if the packet is a pseudo packet */ #define PKT_IS_PSEUDOPKT(p) ((p)->flags & PKT_PSEUDO_STREAM_END) diff --git a/src/flow-hash.c b/src/flow-hash.c index 20f1d36c611d..c7418aa29491 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -53,12 +53,6 @@ SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx); SC_ATOMIC_EXTERN(unsigned int, flow_flags); static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv); -static int handle_tcp_reuse = 1; - -void FlowDisableTcpReuseHandling(void) -{ - handle_tcp_reuse = 0; -} /** \brief compare two raw ipv6 addrs * @@ -297,6 +291,12 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p) return 0; } +void FlowSetupPacket(Packet *p) +{ + p->flags |= PKT_WANTS_FLOW; + p->flow_hash = FlowGetHash(p); +} + int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, void *tcp_ssn); static inline int FlowCompare(Flow *f, const Packet *p) @@ -312,17 +312,6 @@ static inline int FlowCompare(Flow *f, const Packet *p) if (f->flags & FLOW_TCP_REUSED) return 0; - if (handle_tcp_reuse == 1) { - /* lets see if we need to consider the existing session reuse */ - if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) { - /* okay, we need to setup a new flow for this packet. - * Flag the flow that it's been replaced by a new one */ - f->flags |= FLOW_TCP_REUSED; - SCLogDebug("flow obsolete: TCP reuse will use a new flow " - "starting with packet %"PRIu64, p->pcap_cnt); - return 0; - } - } return 1; } else { return CMP_FLOW(f, p); @@ -418,120 +407,41 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) return f; } -Flow *FlowGetFlowFromHashByPacket(const Packet *p, Flow **dest) +static Flow *TcpReuseReplace(ThreadVars *tv, DecodeThreadVars *dtv, + FlowBucket *fb, Flow *old_f, + const uint32_t hash, const Packet *p) { - Flow *f = NULL; - - /* get the key to our bucket */ - uint32_t hash = FlowGetHash(p); - /* get our hash bucket and lock it */ - FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; - FBLOCK_LOCK(fb); + /* tag flow as reused so future lookups won't find it */ + old_f->flags |= FLOW_TCP_REUSED; + /* get some settings that we move over to the new flow */ + FlowThreadId thread_id = old_f->thread_id; + int16_t autofp_tmqh_flow_qid = SC_ATOMIC_GET(old_f->autofp_tmqh_flow_qid); - SCLogDebug("fb %p fb->head %p", fb, fb->head); - - f = FlowGetNew(NULL, NULL, p); - if (f != NULL) { - /* flow is locked */ - if (fb->head == NULL) { - fb->head = f; - fb->tail = f; - } else { - f->hprev = fb->tail; - fb->tail->hnext = f; - fb->tail = f; - } - - /* got one, now lock, initialize and return */ - FlowInit(f, p); - f->flow_hash = hash; - f->fb = fb; - /* update the last seen timestamp of this flow */ - COPY_TIMESTAMP(&p->ts,&f->lastts); - FlowReference(dest, f); + /* since fb lock is still held this flow won't be found until we are done */ + FLOWLOCK_UNLOCK(old_f); - } - FBLOCK_UNLOCK(fb); - return f; -} - -/** \brief Lookup flow based on packet - * - * Find the flow belonging to this packet. If not found, no new flow - * is set up. - * - * \param p packet to lookup the flow for - * - * \retval f flow or NULL if not found - */ -Flow *FlowLookupFlowFromHash(const Packet *p, Flow **dest) -{ - Flow *f = NULL; - - /* get the key to our bucket */ - uint32_t hash = FlowGetHash(p); - /* get our hash bucket and lock it */ - FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; - FBLOCK_LOCK(fb); - - SCLogDebug("fb %p fb->head %p", fb, fb->head); - - /* see if the bucket already has a flow */ - if (fb->head == NULL) { - FBLOCK_UNLOCK(fb); + /* Get a new flow. It will be either a locked flow or NULL */ + Flow *f = FlowGetNew(tv, dtv, p); + if (f == NULL) { return NULL; } - /* ok, we have a flow in the bucket. Let's find out if it is our flow */ - f = fb->head; - - /* see if this is the flow we are looking for */ - if (FlowCompare(f, p) == 0) { - while (f) { - f = f->hnext; - - if (f == NULL) { - FBLOCK_UNLOCK(fb); - return NULL; - } + /* flow is locked */ - if (FlowCompare(f, p) != 0) { - /* we found our flow, lets put it on top of the - * hash list -- this rewards active flows */ - if (f->hnext) { - f->hnext->hprev = f->hprev; - } - if (f->hprev) { - f->hprev->hnext = f->hnext; - } - if (f == fb->tail) { - fb->tail = f->hprev; - } + /* put at the start of the list */ + f->hnext = fb->head; + fb->head->hprev = f; + fb->head = f; - f->hnext = fb->head; - f->hprev = NULL; - fb->head->hprev = f; - fb->head = f; + /* initialize and return */ + FlowInit(f, p); + f->flow_hash = hash; + f->fb = fb; - /* found our flow, lock & return */ - FLOWLOCK_WRLOCK(f); - /* update the last seen timestamp of this flow */ - COPY_TIMESTAMP(&p->ts,&f->lastts); - FlowReference(dest, f); - - FBLOCK_UNLOCK(fb); - return f; - } - } + f->thread_id = thread_id; + if (autofp_tmqh_flow_qid != -1) { + SC_ATOMIC_SET(f->autofp_tmqh_flow_qid, autofp_tmqh_flow_qid); } - - /* lock & return */ - FLOWLOCK_WRLOCK(f); - /* update the last seen timestamp of this flow */ - COPY_TIMESTAMP(&p->ts,&f->lastts); - FlowReference(dest, f); - - FBLOCK_UNLOCK(fb); return f; } @@ -556,10 +466,9 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p { Flow *f = NULL; - /* get the key to our bucket */ - uint32_t hash = FlowGetHash(p); /* get our hash bucket and lock it */ - FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; + const uint32_t hash = p->flow_hash; + FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; FBLOCK_LOCK(fb); SCLogDebug("fb %p fb->head %p", fb, fb->head); @@ -645,6 +554,14 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* found our flow, lock & return */ FLOWLOCK_WRLOCK(f); + if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) { + f = TcpReuseReplace(tv, dtv, fb, f, hash, p); + if (f == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + } + /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); FlowReference(dest, f); @@ -657,6 +574,14 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* lock & return */ FLOWLOCK_WRLOCK(f); + if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) { + f = TcpReuseReplace(tv, dtv, fb, f, hash, p); + if (f == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + } + /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); FlowReference(dest, f); diff --git a/src/flow.c b/src/flow.c index 9c3973e65495..9c6b1653d6e3 100644 --- a/src/flow.c +++ b/src/flow.c @@ -226,37 +226,6 @@ static inline int FlowUpdateSeenFlag(const Packet *p) return 1; } -/** - * - * Remove packet from flow. This assumes this happens *before* the packet - * is added to the stream engine and other higher state. - * - * \todo we can't restore the lastts - */ -void FlowHandlePacketUpdateRemove(Flow *f, Packet *p) -{ - if (p->flowflags & FLOW_PKT_TOSERVER) { - f->todstpktcnt--; - f->todstbytecnt -= GET_PKT_LEN(p); - p->flowflags &= ~(FLOW_PKT_TOSERVER|FLOW_PKT_TOSERVER_FIRST); - } else { - f->tosrcpktcnt--; - f->tosrcbytecnt -= GET_PKT_LEN(p); - p->flowflags &= ~(FLOW_PKT_TOCLIENT|FLOW_PKT_TOCLIENT_FIRST); - } - p->flowflags &= ~FLOW_PKT_ESTABLISHED; - - /*set the detection bypass flags*/ - if (f->flags & FLOW_NOPACKET_INSPECTION) { - SCLogDebug("unsetting FLOW_NOPACKET_INSPECTION flag on flow %p", f); - DecodeUnsetNoPacketInspectionFlag(p); - } - if (f->flags & FLOW_NOPAYLOAD_INSPECTION) { - SCLogDebug("unsetting FLOW_NOPAYLOAD_INSPECTION flag on flow %p", f); - DecodeUnsetNoPayloadInspectionFlag(p); - } -} - /** \brief Update Packet and Flow * * Updates packet and flow based on the new packet. @@ -330,10 +299,6 @@ void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) if (f == NULL) return; - FlowHandlePacketUpdate(f, p); - - FLOWLOCK_UNLOCK(f); - /* set the flow in the packet */ p->flags |= PKT_HAS_FLOW; return; diff --git a/src/flow.h b/src/flow.h index 2085f32242ed..f0fcc226ab98 100644 --- a/src/flow.h +++ b/src/flow.h @@ -432,6 +432,11 @@ typedef struct FlowProto_ { void (*Freefunc)(void *); } FlowProto; +/** \brief prepare packet for a life with flow + * Set PKT_WANTS_FLOW flag to incidate workers should do a flow lookup + * and calc the hash value to be used in the lookup and autofp flow + * balancing. */ +void FlowSetupPacket(Packet *p); void FlowHandlePacket (ThreadVars *, DecodeThreadVars *, Packet *); void FlowInitConfig (char); void FlowPrintQueueInfo (void); @@ -577,11 +582,7 @@ AppProto FlowGetAppProtocol(const Flow *f); void *FlowGetAppState(const Flow *f); uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags); -void FlowHandlePacketUpdateRemove(Flow *f, Packet *p); void FlowHandlePacketUpdate(Flow *f, Packet *p); -Flow *FlowGetFlowFromHashByPacket(const Packet *p, Flow **dest); -Flow *FlowLookupFlowFromHash(const Packet *p, Flow **dest); - #endif /* __FLOW_H__ */ diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index f449a953a295..e2ffde4b4f48 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -132,7 +132,6 @@ int RunModeErfFileAutoFp(void) int thread; RunModeInitialize(); - RunmodeSetFlowStreamAsync(); char *file = NULL; if (ConfGet("erf-file.file", &file) == 0) { diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index 29a65eeebf54..cf99fac6fc61 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -165,7 +165,6 @@ int RunModeFilePcapAutoFp(void) int thread; RunModeInitialize(); - RunmodeSetFlowStreamAsync(); char *file = NULL; if (ConfGet("pcap-file.file", &file) == 0) { diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 22cb446c8f45..eec197f9fd52 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4863,145 +4863,14 @@ int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn return 0; } -/** \brief Handle TCP reuse of tuple - * - * Logic: - * 1. see if packet could trigger a new session - * 2. see if the flow/ssn is in a state where we want to support the reuse - * 3. disconnect packet from the old flow - * -> at this point new packets can still find the old flow - * -> as the flow's reference count != 0, it can't disappear - * 4. setup a new flow unconditionally - * 5. attach packet to new flow - * 6. tag old flow as FLOW_TCP_REUSED - * -> NEW packets won't find it - * -> existing packets in our queues may still reference it - * 7. dereference the old flow (reference cnt *may* now be 0, - * if no other packets reference it) - * - * The packets that still hold a reference to the old flow are updated - * by HandleFlowReuseApplyToPacket() - */ -static void TcpSessionReuseHandle(Packet *p) { - if (likely(TcpSessionPacketIsStreamStarter(p) == 0)) - return; - - int reuse = 0; - FLOWLOCK_RDLOCK(p->flow); - reuse = TcpSessionReuseDoneEnough(p, p->flow, p->flow->protoctx); - if (!reuse) { - SCLogDebug("steam starter packet %"PRIu64", but state not " - "ready to be reused", p->pcap_cnt); - FLOWLOCK_UNLOCK(p->flow); - return; - } - - SCLogDebug("steam starter packet %"PRIu64", and state " - "ready to be reused", p->pcap_cnt); - - /* ok, this packet needs a new flow */ - - /* first, get a reference to the old flow */ - Flow *old_f = NULL; - FlowReference(&old_f, p->flow); - - /* get some settings that we move over to the new flow */ - FlowThreadId thread_id = old_f->thread_id; - int16_t autofp_tmqh_flow_qid = SC_ATOMIC_GET(old_f->autofp_tmqh_flow_qid); - - /* disconnect the packet from the old flow */ - FlowHandlePacketUpdateRemove(p->flow, p); - FLOWLOCK_UNLOCK(p->flow); - FlowDeReference(&p->flow); // < can't disappear while usecnt >0 - - /* Can't tag flow as reused yet, would be a race condition: - * new packets will not get old flow because of FLOW_TCP_REUSED, - * so new flow may be created. This new flow could be handled in - * a different thread. */ - - /* Get a flow. It will be either a locked flow or NULL */ - Flow *new_f = FlowGetFlowFromHashByPacket(p, &p->flow); - if (new_f == NULL) { - FlowDeReference(&old_f); // < can't disappear while usecnt >0 - return; - } - - /* update flow and packet */ - FlowHandlePacketUpdate(new_f, p); - BUG_ON(new_f != p->flow); - - /* copy flow balancing settings */ - new_f->thread_id = thread_id; - SC_ATOMIC_SET(new_f->autofp_tmqh_flow_qid, autofp_tmqh_flow_qid); - - FLOWLOCK_UNLOCK(new_f); - - /* tag original flow that it's now unused */ - FLOWLOCK_WRLOCK(old_f); - SCLogDebug("old flow %p tagged with FLOW_TCP_REUSED by packet %"PRIu64"!", old_f, p->pcap_cnt); - old_f->flags |= FLOW_TCP_REUSED; - FLOWLOCK_UNLOCK(old_f); - FlowDeReference(&old_f); // < can't disappear while usecnt >0 - - SCLogDebug("new flow %p set up for packet %"PRIu64"!", p->flow, p->pcap_cnt); -} - -/** \brief Handle packets that reference the wrong flow because of TCP reuse - * - * In the case of TCP reuse we can have many packets that were assigned - * a flow by the capture/decode threads before the stream engine decided - * that a new flow was needed for these packets. - * When HandleFlowReuse creates a new flow, the packets already processed - * by the flow engine will still reference the old flow. - * - * This function detects this case and replaces the flow for those packets. - * It's a fairly expensive operation, but it should be rare as it's only - * done for packets that were already in the engine when the TCP reuse - * case was handled. New packets are assigned the correct flow by the - * flow engine. - */ -static void TcpSessionReuseHandleApplyToPacket(Packet *p) +void FlowUpdate(ThreadVars *tv, StreamTcpThread *stt, Packet *p) { - int need_flow_replace = 0; - - FLOWLOCK_WRLOCK(p->flow); - if (p->flow->flags & FLOW_TCP_REUSED) { - SCLogDebug("packet %"PRIu64" attached to outdated flow and ssn", p->pcap_cnt); - need_flow_replace = 1; - } - - if (likely(need_flow_replace == 0)) { - /* Work around a race condition: if HandleFlowReuse has inserted a new flow, - * it will not have seen both sides of the session yet. The packet we have here - * may be the first that got the flow directly from the hash right after the - * flow was added. In this case it won't have FLOW_PKT_ESTABLISHED flag set. */ - if ((p->flow->flags & FLOW_TO_DST_SEEN) && (p->flow->flags & FLOW_TO_SRC_SEEN)) { - p->flowflags |= FLOW_PKT_ESTABLISHED; - SCLogDebug("packet %"PRIu64" / flow %p: p->flowflags |= FLOW_PKT_ESTABLISHED (%u/%u)", p->pcap_cnt, p->flow, p->flow->todstpktcnt, p->flow->tosrcpktcnt); - } else { - SCLogDebug("packet %"PRIu64" / flow %p: p->flowflags NOT FLOW_PKT_ESTABLISHED (%u/%u)", p->pcap_cnt, p->flow, p->flow->todstpktcnt, p->flow->tosrcpktcnt); - } - SCLogDebug("packet %"PRIu64" attached to regular flow %p and ssn", p->pcap_cnt, p->flow); - FLOWLOCK_UNLOCK(p->flow); - return; - } - - /* disconnect packet from old flow */ - FlowHandlePacketUpdateRemove(p->flow, p); - FLOWLOCK_UNLOCK(p->flow); - FlowDeReference(&p->flow); // < can't disappear while usecnt >0 + FlowHandlePacketUpdate(p->flow, p); - /* find the new flow that does belong to this packet */ - Flow *new_f = FlowLookupFlowFromHash(p, &p->flow); - if (new_f == NULL) { - // TODO reset packet flag wrt flow: direction, HAS_FLOW etc - p->flags &= ~PKT_HAS_FLOW; - return; + /* handle the app layer part of the UDP packet payload */ + if (p->proto == IPPROTO_UDP) { + AppLayerHandleUdp(tv, stt->ra_ctx->app_tctx, p, p->flow); } - FlowHandlePacketUpdate(new_f, p); - BUG_ON(new_f != p->flow); - FLOWLOCK_UNLOCK(new_f); - SCLogDebug("packet %"PRIu64" switched over to new flow %p!", p->pcap_cnt, p->flow); } TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) @@ -5009,49 +4878,59 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe StreamTcpThread *stt = (StreamTcpThread *)data; TmEcode ret = TM_ECODE_OK; - if (!(PKT_IS_TCP(p))) + SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); + + if (p->flow && p->flags & PKT_PSEUDO_STREAM_END) { + FLOWLOCK_WRLOCK(p->flow); + AppLayerProfilingReset(stt->ra_ctx->app_tctx); + (void)StreamTcpPacket(tv, p, stt, pq); + p->flags |= PKT_IGNORE_CHECKSUM; + stt->pkts++; + FLOWLOCK_UNLOCK(p->flow); return TM_ECODE_OK; + } + + if (!(p->flags & PKT_WANTS_FLOW)) { + return TM_ECODE_OK; + } + + FlowHandlePacket(tv, NULL, p); //TODO what to do about decoder thread vars + if (likely(p->flow != NULL)) { + FlowUpdate(tv, stt, p); + } + + if (!(PKT_IS_TCP(p))) { + goto unlock; + } if (p->flow == NULL) { StatsIncr(tv, stt->counter_tcp_no_flow); - return TM_ECODE_OK; + goto unlock; } + /* only TCP packets with a flow from here */ + if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) { if (StreamTcpValidateChecksum(p) == 0) { StatsIncr(tv, stt->counter_tcp_invalid_checksum); - return TM_ECODE_OK; + goto unlock; } } else { p->flags |= PKT_IGNORE_CHECKSUM; } - - if (stt->runmode_flow_stream_async) { - /* "autofp" handling of TCP session/flow reuse */ - if (!(p->flags & PKT_PSEUDO_STREAM_END)) { - /* apply previous reuses to this packet */ - TcpSessionReuseHandleApplyToPacket(p); - if (p->flow == NULL) - return ret; - - if (!(p->flowflags & FLOW_PKT_TOSERVER_FIRST)) { - /* after that, check for 'new' reuse */ - TcpSessionReuseHandle(p); - if (p->flow == NULL) - return ret; - } - } - } AppLayerProfilingReset(stt->ra_ctx->app_tctx); - FLOWLOCK_WRLOCK(p->flow); ret = StreamTcpPacket(tv, p, stt, pq); - FLOWLOCK_UNLOCK(p->flow); //if (ret) // return TM_ECODE_FAILED; stt->pkts++; + + unlock: + if (p->flow) { + FLOWLOCK_UNLOCK(p->flow); + } return ret; } @@ -5114,11 +4993,6 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) if (stt->ssn_pool_id < 0 || ssn_pool == NULL) SCReturnInt(TM_ECODE_FAILED); - /* see if need to enable the TCP reuse handling in the stream engine */ - stt->runmode_flow_stream_async = RunmodeGetFlowStreamAsync(); - SCLogDebug("Flow and Stream engine run %s", - stt->runmode_flow_stream_async ? "asynchronous" : "synchronous"); - SCReturnInt(TM_ECODE_OK); } diff --git a/src/stream-tcp.h b/src/stream-tcp.h index 416cd5aa808f..e23d9eab71e7 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -76,10 +76,6 @@ typedef struct TcpStreamCnf_ { typedef struct StreamTcpThread_ { int ssn_pool_id; - /** if set to true, we activate the TCP tuple reuse code in the - * stream engine. */ - int runmode_flow_stream_async; - uint64_t pkts; /** queue for pseudo packet(s) that were created in the stream diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index 5a6b40c9f58f..881c5985cae8 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -61,7 +61,9 @@ void TmqhFlowRegister(void) if (strcasecmp(scheduler, "round-robin") == 0) { tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowRoundRobin; } else if (strcasecmp(scheduler, "active-packets") == 0) { - tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; + //tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; + SCLogNotice("FIXME: using flow hash instead of active packets"); + tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } else if (strcasecmp(scheduler, "hash") == 0) { tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } else if (strcasecmp(scheduler, "ippair") == 0) { @@ -73,7 +75,8 @@ void TmqhFlowRegister(void) exit(EXIT_FAILURE); } } else { - tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; + //tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; + tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } return; @@ -330,7 +333,7 @@ void TmqhOutputFlowActivePackets(ThreadVars *tv, Packet *p) * \param tv thread vars. * \param p packet. */ -void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) +void TmqhOutputFlowHash2(ThreadVars *tv, Packet *p) { int16_t qid = 0; @@ -371,6 +374,31 @@ void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) return; } +void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) +{ + int16_t qid = 0; + + TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; + + if (p->flags & PKT_WANTS_FLOW) { + uint32_t hash = p->flow_hash; + qid = hash % ctx->size; + } else { + qid = ctx->last++; + + if (ctx->last == ctx->size) + ctx->last = 0; + } + (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); + + PacketQueue *q = ctx->queues[qid].q; + SCMutexLock(&q->mutex_q); + PacketEnqueue(q, p); + SCCondSignal(&q->cond_q); + SCMutexUnlock(&q->mutex_q); + + return; +} /** * \brief select the queue to output based on IP address pair. * diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 13724e98fe01..8242c8172461 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -51,21 +51,6 @@ #include "flow-hash.h" -/** set to true if flow engine and stream engine run in different - * threads. */ -static int runmode_flow_stream_async = 0; - -void RunmodeSetFlowStreamAsync(void) -{ - runmode_flow_stream_async = 1; - FlowDisableTcpReuseHandling(); -} - -int RunmodeGetFlowStreamAsync(void) -{ - return runmode_flow_stream_async; -} - /** \brief create a queue string for autofp to pass to * the flow queue handler. * @@ -121,8 +106,6 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, if (thread_max < 1) thread_max = 1; - RunmodeSetFlowStreamAsync(); - queues = RunmodeAutoFpCreatePickupQueuesString(thread_max); if (queues == NULL) { SCLogError(SC_ERR_RUNMODE, "RunmodeAutoFpCreatePickupQueuesString failed"); @@ -497,8 +480,6 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, if (thread_max < 1) thread_max = 1; - RunmodeSetFlowStreamAsync(); - queues = RunmodeAutoFpCreatePickupQueuesString(thread_max); if (queues == NULL) { SCLogError(SC_ERR_RUNMODE, "RunmodeAutoFpCreatePickupQueuesString failed"); diff --git a/src/util-unittest-helper.c b/src/util-unittest-helper.c index dd2c20dc9c08..e58644a5308c 100644 --- a/src/util-unittest-helper.c +++ b/src/util-unittest-helper.c @@ -854,8 +854,10 @@ uint32_t UTHBuildPacketOfFlows(uint32_t start, uint32_t end, uint8_t dir) p->dst.addr_data32[0] = i; } FlowHandlePacket(NULL, NULL, p); - if (p->flow != NULL) + if (p->flow != NULL) { SC_ATOMIC_RESET(p->flow->use_cnt); + FLOWLOCK_UNLOCK(p->flow); + } /* Now the queues shoul be updated */ UTHFreePacket(p); From 6f560144c1b97906ad41f621cadc08f4c99dff89 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 18 Apr 2016 15:09:13 +0200 Subject: [PATCH 1400/2553] time: improve offline time handling When we run on live traffic, time handling is simple. Packets have a timestamp set by the capture method. Management threads can simply use 'gettimeofday' to know the current time. There should never be any serious gap between the two or major differnces between the threads. In offline mode, things are dramatically different. Here we try to keep the time from the pcap, which means that if the packets are recorded in 2011 the log output should also reflect this. Multiple issues: 1. merged pcaps might have huge time jumps or time going backward 2. slowly recorded pcaps may be processed much faster than their 'realtime' 3. management threads need a concept of what the 'current' time is for enforcing timeouts 4. due to (1) individual threads may have very different views on what the current time is. E.g. T1 processed packet 1 with TS X, while T2 at the very same time processes packet 2 with TS X+100000s. The changes in flow handling make the problems worse. The capture thread no longer handles the flow lookup, while it did set the global 'time'. This meant that a thread may be working on Packet 1 with TS 1, while the capture thread already saw packet 2 with TS 10000. Management threads would take TS 10000 as the 'current time', considering a flow created by the first thread as timed out immediately. This was less of a problem before the flow changes as the capture thread would also create a flow reference for a packet, meaning the flow couldn't time out as easily. Packets in the queues between capture thread and workers would all hold such references. The patch updates the time handling to be as follows. In offline mode we keep the timestamp per thread. If a management thread needs current time, it will get the minimum of the threads' values. This is to avoid the problem that T2s time value might already trigger a flow timeout as the flow lastts + 100000s is almost certainly meaning the flow would be considered timed out. --- src/source-pcap-file.c | 4 --- src/stream-tcp.c | 2 ++ src/tm-threads.c | 49 +++++++++++++++++++++++++++++++ src/tm-threads.h | 3 ++ src/util-time.c | 59 ++++++++++++++++++++++++++++++++++---- src/util-time.h | 5 +++- src/util-unittest-helper.c | 2 +- 7 files changed, 112 insertions(+), 12 deletions(-) diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index cff52542a198..92fb6f6fa20a 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -420,10 +420,6 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P FlowWakeupFlowManagerThread(); } - /* update the engine time representation based on the timestamp - * of the packet. */ - TimeSet(&p->ts); - /* call the decoder */ pcap_g.Decoder(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index eec197f9fd52..941211dc4d7b 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4880,6 +4880,8 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); + TimeSetByThread(tv->id, &p->ts); + if (p->flow && p->flags & PKT_PSEUDO_STREAM_END) { FLOWLOCK_WRLOCK(p->flow); AppLayerProfilingReset(stt->ra_ctx->app_tctx); diff --git a/src/tm-threads.c b/src/tm-threads.c index 1d7b5fe149cc..89db9812b421 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -2224,6 +2224,8 @@ typedef struct Thread_ { const char *name; int type; int in_use; /**< bool to indicate this is in use */ + + struct timeval ts; /**< current time of this thread (offline mode) */ } Thread; typedef struct Threads_ { @@ -2332,6 +2334,53 @@ void TmThreadsUnregisterThread(const int id) SCMutexUnlock(&thread_store_lock); } +void TmThreadsSetThreadTimestamp(const int id, const struct timeval *ts) +{ + SCMutexLock(&thread_store_lock); + if (unlikely(id <= 0 || id > (int)thread_store.threads_size)) { + SCMutexUnlock(&thread_store_lock); + return; + } + + int idx = id - 1; + Thread *t = &thread_store.threads[idx]; + t->ts.tv_sec = ts->tv_sec; + t->ts.tv_usec = ts->tv_usec; + SCMutexUnlock(&thread_store_lock); +} + +#define COPY_TIMESTAMP(src,dst) ((dst)->tv_sec = (src)->tv_sec, (dst)->tv_usec = (src)->tv_usec) // XXX unify with flow-util.h +void TmreadsGetMinimalTimestamp(struct timeval *ts) +{ + struct timeval local, nullts; + memset(&local, 0, sizeof(local)); + memset(&nullts, 0, sizeof(nullts)); + int set = 0; + size_t s; + + SCMutexLock(&thread_store_lock); + for (s = 0; s < thread_store.threads_size; s++) { + Thread *t = &thread_store.threads[s]; + if (t == NULL || t->in_use == 0) + continue; + if (!(timercmp(&t->ts, &nullts, ==))) { + if (!set) { + local.tv_sec = t->ts.tv_sec; + local.tv_usec = t->ts.tv_usec; + set = 1; + } else { + if (timercmp(&t->ts, &local, <)) { + COPY_TIMESTAMP(&t->ts, &local); + } + } + } + } + SCMutexUnlock(&thread_store_lock); + COPY_TIMESTAMP(&local, ts); + SCLogDebug("ts->tv_sec %u", (uint)ts->tv_sec); +} +#undef COPY_TIMESTAMP + /** * \retval r 1 if packet was accepted, 0 otherwise * \note if packet was not accepted, it's still the responsibility diff --git a/src/tm-threads.h b/src/tm-threads.h index d92e1a946201..1942ae1ce54a 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -222,4 +222,7 @@ int TmThreadsRegisterThread(ThreadVars *tv, const int type); void TmThreadsUnregisterThread(const int id); int TmThreadsInjectPacketsById(Packet **, int id); +void TmThreadsSetThreadTimestamp(const int id, const struct timeval *ts); +void TmreadsGetMinimalTimestamp(struct timeval *ts); + #endif /* __TM_THREADS_H__ */ diff --git a/src/util-time.c b/src/util-time.c index 7c7a362458bb..f768ac733db0 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,17 +25,44 @@ * And time string generation for alerts. */ +/* Real time vs offline time + * + * When we run on live traffic, time handling is simple. Packets have a + * timestamp set by the capture method. Management threads can simply + * use 'gettimeofday' to know the current time. There should never be + * any serious gap between the two. + * + * In offline mode, things are dramatically different. Here we try to keep + * the time from the pcap, which means that if the packets are in 2011 the + * log output should also reflect this. Multiple issues: + * 1. merged pcaps might have huge time jumps or time going backward + * 2. slowly recorded pcaps may be processed much faster than their 'realtime' + * 3. management threads need a concept of what the 'current' time is for + * enforcing timeouts + * 4. due to (1) individual threads may have very different views on what + * the current time is. E.g. T1 processed packet 1 with TS X, while T2 + * at the very same time processes packet 2 with TS X+100000s. + * + * In offline mode we keep the timestamp per thread. If a management thread + * needs current time, it will get the minimum of the threads' values. This + * is to avoid the problem that T2s time value might already trigger a flow + * timeout as the flow lastts + 100000s is almost certainly meaning the flow + * would be considered timed out. + */ + #include "suricata-common.h" #include "detect.h" #include "threads.h" +#include "tm-threads.h" #include "util-debug.h" +#ifdef UNITTESTS static struct timeval current_time = { 0, 0 }; +#endif //static SCMutex current_time_mutex = SCMUTEX_INITIALIZER; static SCSpinlock current_time_spinlock; static char live = TRUE; - struct tm *SCLocalTime(time_t timep, struct tm *result); void TimeInit(void) @@ -63,6 +90,15 @@ void TimeModeSetOffline (void) SCLogDebug("offline time mode enabled"); } +void TimeSetByThread(const int thread_id, const struct timeval *tv) +{ + if (live == TRUE) + return; + + TmThreadsSetThreadTimestamp(thread_id, tv); +} + +#ifdef UNITTESTS void TimeSet(struct timeval *tv) { if (live == TRUE) @@ -91,6 +127,7 @@ void TimeSetToCurrentTime(void) TimeSet(&tv); } +#endif void TimeGet(struct timeval *tv) { @@ -100,16 +137,25 @@ void TimeGet(struct timeval *tv) if (live == TRUE) { gettimeofday(tv, NULL); } else { - SCSpinLock(¤t_time_spinlock); - tv->tv_sec = current_time.tv_sec; - tv->tv_usec = current_time.tv_usec; - SCSpinUnlock(¤t_time_spinlock); +#ifdef UNITTESTS + if (unlikely(RunmodeIsUnittests())) { + SCSpinLock(¤t_time_spinlock); + tv->tv_sec = current_time.tv_sec; + tv->tv_usec = current_time.tv_usec; + SCSpinUnlock(¤t_time_spinlock); + } else { +#endif + TmreadsGetMinimalTimestamp(tv); +#ifdef UNITTESTS + } +#endif } SCLogDebug("time we got is %" PRIuMAX " sec, %" PRIuMAX " usec", (uintmax_t)tv->tv_sec, (uintmax_t)tv->tv_usec); } +#ifdef UNITTESTS /** \brief increment the time in the engine * \param tv_sec seconds to increment the time with */ void TimeSetIncrementTime(uint32_t tv_sec) @@ -122,6 +168,7 @@ void TimeSetIncrementTime(uint32_t tv_sec) TimeSet(&tv); } +#endif void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size) { diff --git a/src/util-time.h b/src/util-time.h index cdf1d5bf7afe..350f8bf4407d 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -37,11 +37,14 @@ typedef struct SCTimeval32_ { void TimeInit(void); void TimeDeinit(void); -void TimeSet(struct timeval *); +void TimeSetByThread(const int thread_id, const struct timeval *tv); void TimeGet(struct timeval *); +#ifdef UNITTESTS +void TimeSet(struct timeval *); void TimeSetToCurrentTime(void); void TimeSetIncrementTime(uint32_t); +#endif void TimeModeSetLive(void); void TimeModeSetOffline (void); diff --git a/src/util-unittest-helper.c b/src/util-unittest-helper.c index e58644a5308c..2eb2df207385 100644 --- a/src/util-unittest-helper.c +++ b/src/util-unittest-helper.c @@ -85,7 +85,7 @@ Packet *UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len, if (unlikely(p == NULL)) return NULL; - TimeSet(&p->ts); + TimeGet(&p->ts); p->src.family = AF_INET6; p->dst.family = AF_INET6; From 408948815f4cc4a6b7a9fbcbc7bc9bbe073a30f3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 16 Apr 2016 23:06:33 +0200 Subject: [PATCH 1401/2553] detect: simplify flow locking To simplify locking, move all locking out of the individual detect code. Instead at the start of detection lock the flow, and at the end of detection unlock it. The lua code can be called without a lock still (from the output code paths), so still pass around a lock hint to take care of this. --- src/detect-engine-alert.c | 10 +++----- src/detect-engine-content-inspection.c | 6 +---- src/detect-engine-state.c | 18 ------------- src/detect-engine-tag.c | 4 --- src/detect-filestore.c | 6 ----- src/detect-flowint.c | 6 ----- src/detect-flowvar.c | 4 --- src/detect-lua.c | 20 +++++++++------ src/detect-lua.h | 4 +-- src/detect.c | 35 ++++---------------------- src/flow-bit.c | 4 --- src/flow.c | 16 +----------- src/flow.h | 3 +-- 13 files changed, 25 insertions(+), 111 deletions(-) diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index c2d7e4206524..f48da78023bd 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -267,8 +267,7 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx if (p->flow != NULL) { /* Update flow flags for iponly */ - FLOWLOCK_WRLOCK(p->flow); - FlowSetIPOnlyFlagNoLock(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? 1 : 0); + FlowSetIPOnlyFlag(p->flow, (p->flowflags & FLOW_PKT_TOSERVER) ? 1 : 0); if (s->action & ACTION_DROP) p->flow->flags |= FLOW_ACTION_DROP; @@ -281,7 +280,6 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx if (s->action & ACTION_PASS) { FlowSetNoPacketInspectionFlag(p->flow); } - FLOWLOCK_UNLOCK(p->flow); } } } @@ -299,7 +297,7 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx (p->alerts.alerts[i].flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH))) { - FlowLockSetNoPacketInspectionFlag(p->flow); + FlowSetNoPacketInspectionFlag(p->flow); } break; @@ -310,10 +308,8 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx (s->flags & SIG_FLAG_APPLAYER)) && p->flow != NULL) { - FLOWLOCK_WRLOCK(p->flow); /* This will apply only on IPS mode (check StreamTcpPacket) */ - p->flow->flags |= FLOW_ACTION_DROP; - FLOWLOCK_UNLOCK(p->flow); + p->flow->flags |= FLOW_ACTION_DROP; // XXX API? } } diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index 9a13d28faf18..af1b10346220 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -536,13 +536,9 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx } else if (sm->type == DETECT_LUA) { SCLogDebug("lua starting"); - /* for flowvar gets and sets we need to know the flow's lock status */ - int flow_lock = LUA_FLOW_LOCKED_BY_PARENT; - if (inspection_mode <= DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM) - flow_lock = LUA_FLOW_NOT_LOCKED_BY_PARENT; if (DetectLuaMatchBuffer(det_ctx, s, sm, buffer, buffer_len, - det_ctx->buffer_offset, f, flow_lock) != 1) + det_ctx->buffer_offset, f) != 1) { SCLogDebug("lua no_match"); goto no_match; diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 7069972ac46e..e05d18dbbf4b 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -378,8 +378,6 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, { int r = 0; - FLOWLOCK_WRLOCK(f); - if (!(flags & STREAM_EOF) && f->de_state && f->detect_alversion[flags & STREAM_TOSERVER ? 0 : 1] == alversion) { SCLogDebug("unchanged state"); @@ -389,8 +387,6 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, } else { r = 0; } - FLOWLOCK_UNLOCK(f); - return r; } @@ -490,7 +486,6 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SCLogDebug("rule %u", s->id); - FLOWLOCK_WRLOCK(f); /* TX based matches (inspect engines) */ if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { uint64_t tx_id = 0; @@ -713,8 +708,6 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } end: - FLOWLOCK_UNLOCK(f); - det_ctx->tx_id = 0; det_ctx->tx_id_set = 0; return alert_cnt ? 1:0; @@ -907,9 +900,7 @@ static int DoInspectItem(ThreadVars *tv, RULE_PROFILING_END(det_ctx, s, (alert == 1), p); if (alert) { - det_ctx->flow_locked = 1; SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); - det_ctx->flow_locked = 0; if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, inspect_tx_id, @@ -1000,9 +991,7 @@ static int DoInspectFlowRule(ThreadVars *tv, item->nm = sm; if (alert) { - det_ctx->flow_locked = 1; SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); - det_ctx->flow_locked = 0; if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, 0, @@ -1028,14 +1017,11 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, uint64_t total_txs = 0; uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; - FLOWLOCK_WRLOCK(f); - SCLogDebug("starting continue detection for packet %"PRIu64, p->pcap_cnt); if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { void *alstate = FlowGetAppState(f); if (!StateIsValid(alproto, alstate)) { - FLOWLOCK_UNLOCK(f); return; } @@ -1134,7 +1120,6 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } end: - FLOWLOCK_UNLOCK(f); det_ctx->tx_id = 0; det_ctx->tx_id_set = 0; return; @@ -1147,13 +1132,10 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, * \note it is possible that f->alstate, f->alparser are NULL */ void DeStateUpdateInspectTransactionId(Flow *f, const uint8_t flags) { - FLOWLOCK_WRLOCK(f); if (f->alparser && f->alstate) { AppLayerParserSetTransactionInspectId(f->alparser, f->proto, f->alproto, f->alstate, flags); } - FLOWLOCK_UNLOCK(f); - return; } diff --git a/src/detect-engine-tag.c b/src/detect-engine-tag.c index 0eb90a228566..3716d982e19a 100644 --- a/src/detect-engine-tag.c +++ b/src/detect-engine-tag.c @@ -132,7 +132,6 @@ int TagFlowAdd(Packet *p, DetectTagDataEntry *tde) if (p->flow == NULL) return 1; - FLOWLOCK_WRLOCK(p->flow); iter = FlowGetStorageById(p->flow, flow_tag_id); if (iter != NULL) { /* First iterate installed entries searching a duplicated sid/gid */ @@ -169,7 +168,6 @@ int TagFlowAdd(Packet *p, DetectTagDataEntry *tde) SCLogDebug("Max tags for sessions reached (%"PRIu16")", tag_cnt); } - FLOWLOCK_UNLOCK(p->flow); return updated; } @@ -516,9 +514,7 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, /* First update and get session tags */ if (p->flow != NULL) { - FLOWLOCK_WRLOCK(p->flow); TagHandlePacketFlow(p->flow, p); - FLOWLOCK_UNLOCK(p->flow); } Host *src = HostLookupHostFromHash(&p->src); diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 0f96e86871c9..8927ff5d1beb 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -203,9 +203,6 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack else flags |= STREAM_TOSERVER; - if (det_ctx->flow_locked == 0) - FLOWLOCK_WRLOCK(p->flow); - FileContainer *ffc = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, flags); @@ -225,9 +222,6 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack } } - if (det_ctx->flow_locked == 0) - FLOWLOCK_UNLOCK(p->flow); - SCReturnInt(0); } diff --git a/src/detect-flowint.c b/src/detect-flowint.c index f63ddf4ed5c0..e8a7a2c7d98e 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -89,16 +89,12 @@ void DetectFlowintRegister(void) int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - const int flow_locked = det_ctx->flow_locked; const DetectFlowintData *sfd = (const DetectFlowintData *)ctx; FlowVar *fv; FlowVar *fvt; uint32_t targetval; int ret = 0; - if (flow_locked == 0) - FLOWLOCK_WRLOCK(p->flow); - /** ATM If we are going to compare the current var with another * that doesn't exist, the default value will be zero; * if you don't want this behaviour, you can use the keyword @@ -210,8 +206,6 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } end: - if (flow_locked == 0) - FLOWLOCK_UNLOCK(p->flow); return ret; } diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index 1fbc3eff63c2..962ec6fdc600 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -98,9 +98,6 @@ int DetectFlowvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p int ret = 0; DetectFlowvarData *fd = (DetectFlowvarData *)ctx; - /* we need a lock */ - FLOWLOCK_RDLOCK(p->flow); - FlowVar *fv = FlowVarGet(p->flow, fd->idx); if (fv != NULL) { uint8_t *ptr = SpmSearch(fv->data.fv_str.value, @@ -109,7 +106,6 @@ int DetectFlowvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p if (ptr != NULL) ret = 1; } - FLOWLOCK_UNLOCK(p->flow); return ret; } diff --git a/src/detect-lua.c b/src/detect-lua.c index ffaed2d1518f..a05583e00359 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -293,7 +293,7 @@ void LuaDumpStack(lua_State *state) int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, uint8_t *buffer, uint32_t buffer_len, uint32_t offset, - Flow *f, int flow_lock) + Flow *f) { SCEnter(); int ret = 0; @@ -310,6 +310,10 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch SCReturnInt(0); /* setup extension data for use in lua c functions */ + int flow_lock = (f != NULL) ? /* if we have a flow, it's locked */ + LUA_FLOW_LOCKED_BY_PARENT : + LUA_FLOW_NOT_LOCKED_BY_PARENT; + LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, f, flow_lock, /* no packet in the ctx */NULL, 0); @@ -419,8 +423,13 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, flags = STREAM_TOCLIENT; LuaStateSetThreadVars(tluajit->luastate, tv); + + int flow_lock = (p->flow != NULL) ? /* if we have a flow, it's locked */ + LUA_FLOW_LOCKED_BY_PARENT : + LUA_FLOW_NOT_LOCKED_BY_PARENT; + LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, - p->flow, /* flow not locked */LUA_FLOW_NOT_LOCKED_BY_PARENT, p, flags); + p->flow, flow_lock, p, flags); if ((tluajit->flags & DATATYPE_PAYLOAD) && p->payload_len == 0) SCReturnInt(0); @@ -430,10 +439,7 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, if (p->flow == NULL) SCReturnInt(0); - FLOWLOCK_RDLOCK(p->flow); - int alproto = p->flow->alproto; - FLOWLOCK_UNLOCK(p->flow); - + AppProto alproto = p->flow->alproto; if (tluajit->alproto != alproto) SCReturnInt(0); } @@ -452,7 +458,6 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, lua_settable(tluajit->luastate, -3); } if (tluajit->alproto == ALPROTO_HTTP) { - FLOWLOCK_RDLOCK(p->flow); HtpState *htp_state = p->flow->alstate; if (htp_state != NULL && htp_state->connp != NULL) { htp_tx_t *tx = NULL; @@ -474,7 +479,6 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, } } } - FLOWLOCK_UNLOCK(p->flow); } int retval = lua_pcall(tluajit->luastate, 1, 1, 0); diff --git a/src/detect-lua.h b/src/detect-lua.h index f7dc5de41494..f1e86c2f2efb 100644 --- a/src/detect-lua.h +++ b/src/detect-lua.h @@ -44,7 +44,7 @@ typedef struct DetectLuaData { int negated; char *filename; uint32_t flags; - int alproto; + AppProto alproto; char *buffername; /* buffer name in case of a single buffer */ uint16_t flowint[DETECT_LUAJIT_MAX_FLOWINTS]; uint16_t flowints; @@ -61,7 +61,7 @@ typedef struct DetectLuaData { void DetectLuaRegister (void); int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, uint8_t *buffer, uint32_t buffer_len, uint32_t offset, - Flow *f, int flow_lock); + Flow *f); #ifdef HAVE_LUAJIT int DetectLuajitSetupStatesPool(int num, int reloads); diff --git a/src/detect.c b/src/detect.c index de8dab978f49..03dcad3ab201 100644 --- a/src/detect.c +++ b/src/detect.c @@ -907,18 +907,15 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, /* all http based mpms */ if (has_state && alproto == ALPROTO_HTTP) { - FLOWLOCK_WRLOCK(p->flow); void *alstate = FlowGetAppState(p->flow); if (alstate == NULL) { SCLogDebug("no alstate"); - FLOWLOCK_UNLOCK(p->flow); return; } HtpState *htp_state = (HtpState *)alstate; if (htp_state->connp == NULL) { SCLogDebug("no HTTP connp"); - FLOWLOCK_UNLOCK(p->flow); return; } @@ -1040,18 +1037,14 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } } } /* for */ - - FLOWLOCK_UNLOCK(p->flow); } /* all dns based mpms */ else if (alproto == ALPROTO_DNS && has_state) { if (p->flowflags & FLOW_PKT_TOSERVER) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_DNSQUERY) { - FLOWLOCK_RDLOCK(p->flow); void *alstate = FlowGetAppState(p->flow); if (alstate == NULL) { SCLogDebug("no alstate"); - FLOWLOCK_UNLOCK(p->flow); return; } @@ -1066,35 +1059,28 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectDnsQueryInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY); } - FLOWLOCK_UNLOCK(p->flow); } } } else if (alproto == ALPROTO_TLS && has_state) { if (p->flowflags & FLOW_PKT_TOSERVER) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSSNI) { - FLOWLOCK_RDLOCK(p->flow); void *alstate = FlowGetAppState(p->flow); if (alstate == NULL) { SCLogDebug("no alstate"); - FLOWLOCK_UNLOCK(p->flow); return; } PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSSNI); DetectTlsSniInspectMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSNI); - - FLOWLOCK_UNLOCK(p->flow); } } } else if (alproto == ALPROTO_SMTP && has_state) { if (p->flowflags & FLOW_PKT_TOSERVER) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_FD_SMTP) { - FLOWLOCK_RDLOCK(p->flow); void *alstate = FlowGetAppState(p->flow); if (alstate == NULL) { SCLogDebug("no alstate"); - FLOWLOCK_UNLOCK(p->flow); return; } @@ -1110,7 +1096,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunSMTPMpm(de_ctx, det_ctx, p->flow, smtp_state, flags, tx, idx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_FD_SMTP); } - FLOWLOCK_UNLOCK(p->flow); } } } @@ -1155,11 +1140,9 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, if (p->flowflags & FLOW_PKT_TOSERVER) { SCLogDebug("mpm inspection"); if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_DNSQUERY) { - FLOWLOCK_RDLOCK(p->flow); void *alstate = FlowGetAppState(p->flow); if (alstate == NULL) { SCLogDebug("no alstate"); - FLOWLOCK_UNLOCK(p->flow); return; } @@ -1174,7 +1157,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectDnsQueryInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY); } - FLOWLOCK_UNLOCK(p->flow); } } } @@ -1353,7 +1335,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SCLogDebug("STREAM_EOF set"); } - FLOWLOCK_WRLOCK(pflow); { /* store tenant_id in the flow so that we can use it * for creating pseudo packets */ @@ -1436,7 +1417,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh pflow->alparser, flow_flags); } - FLOWLOCK_UNLOCK(pflow); if (((p->flowflags & FLOW_PKT_TOSERVER) && !(p->flowflags & FLOW_PKT_TOSERVER_IPONLY_SET)) || ((p->flowflags & FLOW_PKT_TOCLIENT) && !(p->flowflags & FLOW_PKT_TOCLIENT_IPONLY_SET))) @@ -1447,8 +1427,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh IPOnlyMatchPacket(th_v, de_ctx, det_ctx, &de_ctx->io_ctx, &det_ctx->io_ctx, p); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_IPONLY); - /* save in the flow that we scanned this direction... locking is - * done in the FlowSetIPOnlyFlag function. */ + /* save in the flow that we scanned this direction... */ FlowSetIPOnlyFlag(pflow, p->flowflags & FLOW_PKT_TOSERVER ? 1 : 0); } else if (((p->flowflags & FLOW_PKT_TOSERVER) && @@ -1474,9 +1453,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh #ifdef DEBUG if (pflow) { - SCMutexLock(&pflow->m); DebugInspectIds(p, pflow, smsg); - SCMutexUnlock(&pflow->m); } #endif } else { /* p->flags & PKT_HAS_FLOW */ @@ -1627,9 +1604,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh * and if so, if we actually have any in the flow. If not, the sig * can't match and we skip it. */ if ((p->flags & PKT_HAS_FLOW) && (sflags & SIG_FLAG_REQUIRE_FLOWVAR)) { - FLOWLOCK_RDLOCK(pflow); int m = pflow->flowvar ? 1 : 0; - FLOWLOCK_UNLOCK(pflow); /* no flowvars? skip this sig */ if (m == 0) { @@ -1868,7 +1843,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh * up again for the next packet. Also return any stream chunk we processed * to the pool. */ if (p->flags & PKT_HAS_FLOW) { - FLOWLOCK_WRLOCK(pflow); if (debuglog_enabled) { if (p->alerts.cnt > 0) { AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(p, de_ctx); @@ -1946,8 +1920,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* if we had no alerts that involved the smsgs, * we can get rid of them now. */ StreamMsgReturnListToPool(smsg); - - FLOWLOCK_UNLOCK(pflow); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_CLEANUP); @@ -2079,12 +2051,15 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue } if (p->flow) { + det_ctx->flow_locked = 1; + FLOWLOCK_WRLOCK(p->flow); DetectFlow(tv, de_ctx, det_ctx, p); + FLOWLOCK_UNLOCK(p->flow); + det_ctx->flow_locked = 0; } else { DetectNoFlow(tv, de_ctx, det_ctx, p); } return TM_ECODE_OK; - error: return TM_ECODE_FAILED; } diff --git a/src/flow-bit.c b/src/flow-bit.c index 07f549625166..02c7fc474158 100644 --- a/src/flow-bit.c +++ b/src/flow-bit.c @@ -125,28 +125,24 @@ void FlowBitToggle(Flow *f, uint16_t idx) int FlowBitIsset(Flow *f, uint16_t idx) { int r = 0; - FLOWLOCK_RDLOCK(f); FlowBit *fb = FlowBitGet(f, idx); if (fb != NULL) { r = 1; } - FLOWLOCK_UNLOCK(f); return r; } int FlowBitIsnotset(Flow *f, uint16_t idx) { int r = 0; - FLOWLOCK_RDLOCK(f); FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) { r = 1; } - FLOWLOCK_UNLOCK(f); return r; } diff --git a/src/flow.c b/src/flow.c index 9c6b1653d6e3..66e6b1d98234 100644 --- a/src/flow.c +++ b/src/flow.c @@ -147,26 +147,12 @@ int FlowUpdateSpareFlows(void) return 1; } -/** \brief Set the IPOnly scanned flag for 'direction'. This function - * handles the locking too. - * \param f Flow to set the flag in - * \param direction direction to set the flag in - */ -void FlowSetIPOnlyFlag(Flow *f, char direction) -{ - FLOWLOCK_WRLOCK(f); - direction ? (f->flags |= FLOW_TOSERVER_IPONLY_SET) : - (f->flags |= FLOW_TOCLIENT_IPONLY_SET); - FLOWLOCK_UNLOCK(f); - return; -} - /** \brief Set the IPOnly scanned flag for 'direction'. * * \param f Flow to set the flag in * \param direction direction to set the flag in */ -void FlowSetIPOnlyFlagNoLock(Flow *f, char direction) +void FlowSetIPOnlyFlag(Flow *f, int direction) { direction ? (f->flags |= FLOW_TOSERVER_IPONLY_SET) : (f->flags |= FLOW_TOCLIENT_IPONLY_SET); diff --git a/src/flow.h b/src/flow.h index f0fcc226ab98..3335f967972e 100644 --- a/src/flow.h +++ b/src/flow.h @@ -441,8 +441,7 @@ void FlowHandlePacket (ThreadVars *, DecodeThreadVars *, Packet *); void FlowInitConfig (char); void FlowPrintQueueInfo (void); void FlowShutdown(void); -void FlowSetIPOnlyFlag(Flow *, char); -void FlowSetIPOnlyFlagNoLock(Flow *, char); +void FlowSetIPOnlyFlag(Flow *, int); void FlowRegisterTests (void); int FlowSetProtoTimeout(uint8_t ,uint32_t ,uint32_t ,uint32_t); From 52d500c670a343a1503dc959c2b087979eb8346f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 19 Apr 2016 18:06:32 +0200 Subject: [PATCH 1402/2553] flowworker: initial support Initial version of the 'FlowWorker' thread module. This module combines Flow handling, TCP handling, App layer handling and Detection in a single module. It does all flow related processing under a single flow lock. --- src/Makefile.am | 1 + src/detect-engine.c | 5 +- src/detect.c | 2 - src/flow-worker.c | 233 ++++++++++++++++++++++++++++++++++++++++ src/flow-worker.h | 26 +++++ src/runmode-erf-file.c | 27 +---- src/runmode-pcap-file.c | 27 +---- src/runmode-tile.c | 13 +-- src/stream-tcp.c | 61 +++-------- src/suricata.c | 3 + src/tm-modules.c | 1 + src/tm-threads-common.h | 1 + src/tm-threads.c | 20 ++-- src/util-runmodes.c | 53 ++------- src/util-validate.h | 2 - 15 files changed, 314 insertions(+), 161 deletions(-) create mode 100644 src/flow-worker.c create mode 100644 src/flow-worker.h diff --git a/src/Makefile.am b/src/Makefile.am index b81bb7be562e..b729388ee337 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -222,6 +222,7 @@ flow-storage.c flow-storage.h \ flow-timeout.c flow-timeout.h \ flow-util.c flow-util.h \ flow-var.c flow-var.h \ +flow-worker.c flow-worker.h \ host.c host.h \ host-bit.c host-bit.h \ host-queue.c host-queue.h \ diff --git a/src/detect-engine.c b/src/detect-engine.c index 6a66a45d9fee..34f15652023b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -28,6 +28,7 @@ #include "flow.h" #include "flow-private.h" #include "flow-util.h" +#include "flow-worker.h" #include "conf.h" #include "conf-yaml-loader.h" @@ -695,7 +696,7 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) continue; } - old_det_ctx[i] = SC_ATOMIC_GET(slots->slot_data); + old_det_ctx[i] = FlowWorkerGetDetectCtxPtr(SC_ATOMIC_GET(slots->slot_data)); detect_tvs[i] = tv; new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx, 1); @@ -733,7 +734,7 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) } SCLogDebug("swapping new det_ctx - %p with older one - %p", new_det_ctx[i], SC_ATOMIC_GET(slots->slot_data)); - (void)SC_ATOMIC_SET(slots->slot_data, new_det_ctx[i++]); + FlowWorkerReplaceDetectCtx(SC_ATOMIC_GET(slots->slot_data), new_det_ctx[i++]); break; } tv = tv->next; diff --git a/src/detect.c b/src/detect.c index 03dcad3ab201..860b330b3dce 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2052,9 +2052,7 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue if (p->flow) { det_ctx->flow_locked = 1; - FLOWLOCK_WRLOCK(p->flow); DetectFlow(tv, de_ctx, det_ctx, p); - FLOWLOCK_UNLOCK(p->flow); det_ctx->flow_locked = 0; } else { DetectNoFlow(tv, de_ctx, det_ctx, p); diff --git a/src/flow-worker.c b/src/flow-worker.c new file mode 100644 index 000000000000..d6137944facb --- /dev/null +++ b/src/flow-worker.c @@ -0,0 +1,233 @@ +/* Copyright (C) 2016 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 + * + * Flow Workers are single thread modules taking care of (almost) + * everything related to packets with flows: + * + * - Lookup/creation + * - Stream tracking, reassembly + * - Applayer update + * - Detection + * + * This all while holding the flow lock. + * + * TODO + * - once we have a single entry point into the outputs they + * will have to move into this as well. + * - once outputs are here we can also call StreamTcpPrune here + * instead of in the packet pool return code + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "decode.h" +#include "stream-tcp.h" +#include "app-layer.h" +#include "detect-engine.h" + +#include "util-validate.h" + +typedef DetectEngineThreadCtx *DetectEngineThreadCtxPtr; + +typedef struct FlowWorkerThreadData_ { + union { + StreamTcpThread *stream_thread; + void *stream_thread_ptr; + }; + + SC_ATOMIC_DECLARE(DetectEngineThreadCtxPtr, detect_thread); + +#if 0 + void *output_thread; // XXX multiple, not a single state +#endif + PacketQueue pq; + +} FlowWorkerThreadData; + +/** \brief handle flow for packet + * + * Handle flow creation/lookup + */ +static void FlowUpdate(ThreadVars *tv, StreamTcpThread *stt, Packet *p) +{ + FlowHandlePacketUpdate(p->flow, p); + + /* handle the app layer part of the UDP packet payload */ + if (p->proto == IPPROTO_UDP) { + AppLayerHandleUdp(tv, stt->ra_ctx->app_tctx, p, p->flow); + } +} + +static TmEcode FlowWorkerThreadInit(ThreadVars *tv, void *initdata, void **data) +{ + FlowWorkerThreadData *fw = SCCalloc(1, sizeof(*fw)); + BUG_ON(fw == NULL); + SC_ATOMIC_INIT(fw->detect_thread); + SC_ATOMIC_SET(fw->detect_thread, NULL); + + /* setup TCP */ + BUG_ON(StreamTcpThreadInit(tv, NULL, &fw->stream_thread_ptr) != TM_ECODE_OK); + + if (DetectEngineEnabled()) { + /* setup DETECT */ + void *detect_thread = NULL; + BUG_ON(DetectEngineThreadCtxInit(tv, NULL, &detect_thread) != TM_ECODE_OK); + SC_ATOMIC_SET(fw->detect_thread, detect_thread); + } +#if 0 + // setup OUTPUTS +#endif + + /* setup pq for stream end pkts */ + memset(&fw->pq, 0, sizeof(PacketQueue)); + SCMutexInit(&fw->pq.mutex_q, NULL); + + *data = fw; + return TM_ECODE_OK; +} + +static TmEcode FlowWorkerThreadDeinit(ThreadVars *tv, void *data) +{ + FlowWorkerThreadData *fw = data; + + /* free TCP */ + StreamTcpThreadDeinit(tv, (void *)fw->stream_thread); + + /* free DETECT */ + void *detect_thread = SC_ATOMIC_GET(fw->detect_thread); + if (detect_thread != NULL) + DetectEngineThreadCtxDeinit(tv, detect_thread); + SC_ATOMIC_SET(fw->detect_thread, NULL); +#if 0 + // free OUTPUT +#endif + + /* free pq */ + BUG_ON(fw->pq.len); + SCMutexDestroy(&fw->pq.mutex_q); + + SCFree(fw); + return TM_ECODE_OK; +} + +TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq); +TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); + +TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, PacketQueue *unused) +{ + FlowWorkerThreadData *fw = data; + void *detect_thread = SC_ATOMIC_GET(fw->detect_thread); + + SCLogDebug("packet %"PRIu64, p->pcap_cnt); + + /* update time */ + if (!(PKT_IS_PSEUDOPKT(p))) + TimeSetByThread(tv->id, &p->ts); + + /* handle Flow */ + if (p->flags & PKT_WANTS_FLOW) { + FlowHandlePacket(tv, NULL, p); //TODO what to do about decoder thread vars + if (likely(p->flow != NULL)) { + DEBUG_ASSERT_FLOW_LOCKED(p->flow); + FlowUpdate(tv, fw->stream_thread, p); + } + /* Flow is now LOCKED */ + + /* if PKT_WANTS_FLOW is not set, but PKT_HAS_FLOW is, then this is a + * pseudo packet created by the flow manager. */ + } else if (p->flags & PKT_HAS_FLOW) { + FLOWLOCK_WRLOCK(p->flow); + } + + SCLogDebug("packet %"PRIu64" has flow? %s", p->pcap_cnt, p->flow ? "yes" : "no"); + + /* handle TCP and app layer */ + if (PKT_IS_TCP(p)) { + SCLogDebug("packet %"PRIu64" is TCP", p->pcap_cnt); + DEBUG_ASSERT_FLOW_LOCKED(p->flow); + + StreamTcp(tv, p, fw->stream_thread, &fw->pq, NULL); + + /* Packets here can safely access p->flow as it's locked */ + SCLogDebug("packet %"PRIu64": extra packets %u", p->pcap_cnt, fw->pq.len); + Packet *x; + while ((x = PacketDequeue(&fw->pq))) { + SCLogDebug("packet %"PRIu64" extra packet %p", p->pcap_cnt, x); + + // TODO do we need to call StreamTcp on these pseudo packets or not? + //StreamTcp(tv, x, fw->stream_thread, &fw->pq, NULL); + if (detect_thread != NULL) + Detect(tv, x, detect_thread, NULL, NULL); +#if 0 + // Outputs +#endif + /* put these packets in the preq queue so that they are + * by the other thread modules before packet 'p'. */ + PacketEnqueue(preq, x); + } + } + + /* handle Detect */ + DEBUG_ASSERT_FLOW_LOCKED(p->flow); + SCLogDebug("packet %"PRIu64" calling Detect", p->pcap_cnt); + + if (detect_thread != NULL) { + Detect(tv, p, detect_thread, NULL, NULL); + } +#if 0 + // Outputs + + // StreamTcpPruneSession (from TmqhOutputPacketpool) +#endif + + if (p->flow) { + DEBUG_ASSERT_FLOW_LOCKED(p->flow); + FLOWLOCK_UNLOCK(p->flow); + } + + return TM_ECODE_OK; +} + +void FlowWorkerReplaceDetectCtx(void *flow_worker, void *detect_ctx) +{ + FlowWorkerThreadData *fw = flow_worker; + + SC_ATOMIC_SET(fw->detect_thread, detect_ctx); +} + +void *FlowWorkerGetDetectCtxPtr(void *flow_worker) +{ + FlowWorkerThreadData *fw = flow_worker; + + return SC_ATOMIC_GET(fw->detect_thread); +} + +void TmModuleFlowWorkerRegister (void) +{ + tmm_modules[TMM_FLOWWORKER].name = "FlowWorker"; + tmm_modules[TMM_FLOWWORKER].ThreadInit = FlowWorkerThreadInit; + tmm_modules[TMM_FLOWWORKER].Func = FlowWorker; + tmm_modules[TMM_FLOWWORKER].ThreadDeinit = FlowWorkerThreadDeinit; + tmm_modules[TMM_FLOWWORKER].cap_flags = 0; + tmm_modules[TMM_FLOWWORKER].flags = TM_FLAG_STREAM_TM|TM_FLAG_DETECT_TM; +} diff --git a/src/flow-worker.h b/src/flow-worker.h new file mode 100644 index 000000000000..a3528e628607 --- /dev/null +++ b/src/flow-worker.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2016 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. + */ + +#ifndef __FLOW_WORKER_H__ +#define __FLOW_WORKER_H__ + +void FlowWorkerReplaceDetectCtx(void *flow_worker, void *detect_ctx); +void *FlowWorkerGetDetectCtxPtr(void *flow_worker); + +void TmModuleFlowWorkerRegister (void); + +#endif /* __FLOW_WORKER_H__ */ diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index e2ffde4b4f48..5e0b097ab600 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -94,22 +94,13 @@ int RunModeErfFileSingle(void) } TmSlotSetFuncAppend(tv, tm_module, NULL); - tm_module = TmModuleGetByName("StreamTcp"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (DetectEngineEnabled()) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName Detect failed\n"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv, tm_module, NULL); - } - SetupOutputs(tv); if (TmThreadSpawn(tv) != TM_ECODE_OK) { @@ -217,22 +208,14 @@ int RunModeErfFileAutoFp(void) printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } - tm_module = TmModuleGetByName("StreamTcp"); + + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (DetectEngineEnabled()) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName Detect failed\n"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - } - if (threading_set_cpu_affinity) { TmThreadSetCPUAffinity(tv_detect_ncpu, (int)cpu); /* If we have more than one core/cpu, the first Detect thread diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index cf99fac6fc61..c6fea2b2defb 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -100,22 +100,13 @@ int RunModeFilePcapSingle(void) } TmSlotSetFuncAppend(tv, tm_module, NULL); - tm_module = TmModuleGetByName("StreamTcp"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (DetectEngineEnabled()) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv, tm_module, NULL); - } - SetupOutputs(tv); TmThreadSetCPU(tv, DETECT_CPU_SET); @@ -249,22 +240,14 @@ int RunModeFilePcapAutoFp(void) SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } - tm_module = TmModuleGetByName("StreamTcp"); + + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (DetectEngineEnabled()) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - } - TmThreadSetGroupName(tv_detect_ncpu, "Detect"); /* add outputs as well */ diff --git a/src/runmode-tile.c b/src/runmode-tile.c index 913ee562f69b..4e94e24dab4e 100644 --- a/src/runmode-tile.c +++ b/src/runmode-tile.c @@ -245,22 +245,13 @@ int RunModeTileMpipeWorkers(void) } TmSlotSetFuncAppend(tv_worker, tm_module, NULL); - tm_module = TmModuleGetByName("StreamTcp"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_worker, tm_module, NULL); - if (DetectEngineEnabled()) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName Detect failed\n"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_worker, tm_module, NULL); - } - tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName for RespondReject failed\n"); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 941211dc4d7b..d1d1470bf3b0 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4863,77 +4863,42 @@ int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn return 0; } -void FlowUpdate(ThreadVars *tv, StreamTcpThread *stt, Packet *p) -{ - FlowHandlePacketUpdate(p->flow, p); - - /* handle the app layer part of the UDP packet payload */ - if (p->proto == IPPROTO_UDP) { - AppLayerHandleUdp(tv, stt->ra_ctx->app_tctx, p, p->flow); - } -} - TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { StreamTcpThread *stt = (StreamTcpThread *)data; - TmEcode ret = TM_ECODE_OK; SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); - TimeSetByThread(tv->id, &p->ts); - - if (p->flow && p->flags & PKT_PSEUDO_STREAM_END) { - FLOWLOCK_WRLOCK(p->flow); - AppLayerProfilingReset(stt->ra_ctx->app_tctx); - (void)StreamTcpPacket(tv, p, stt, pq); - p->flags |= PKT_IGNORE_CHECKSUM; - stt->pkts++; - FLOWLOCK_UNLOCK(p->flow); - return TM_ECODE_OK; - } - - if (!(p->flags & PKT_WANTS_FLOW)) { - return TM_ECODE_OK; - } - - FlowHandlePacket(tv, NULL, p); //TODO what to do about decoder thread vars - if (likely(p->flow != NULL)) { - FlowUpdate(tv, stt, p); - } - if (!(PKT_IS_TCP(p))) { - goto unlock; + return TM_ECODE_OK; } if (p->flow == NULL) { StatsIncr(tv, stt->counter_tcp_no_flow); - goto unlock; + return TM_ECODE_OK; } /* only TCP packets with a flow from here */ - if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) { - if (StreamTcpValidateChecksum(p) == 0) { - StatsIncr(tv, stt->counter_tcp_invalid_checksum); - goto unlock; + if (!(p->flags & PKT_PSEUDO_STREAM_END)) { + if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) { + if (StreamTcpValidateChecksum(p) == 0) { + StatsIncr(tv, stt->counter_tcp_invalid_checksum); + return TM_ECODE_OK; + } + } else { + p->flags |= PKT_IGNORE_CHECKSUM; } } else { - p->flags |= PKT_IGNORE_CHECKSUM; + p->flags |= PKT_IGNORE_CHECKSUM; //TODO check that this is set at creation } AppLayerProfilingReset(stt->ra_ctx->app_tctx); - ret = StreamTcpPacket(tv, p, stt, pq); - - //if (ret) - // return TM_ECODE_FAILED; + (void)StreamTcpPacket(tv, p, stt, pq); stt->pkts++; - unlock: - if (p->flow) { - FLOWLOCK_UNLOCK(p->flow); - } - return ret; + return TM_ECODE_OK; } TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) diff --git a/src/suricata.c b/src/suricata.c index 37ba4aa90f8e..71a742c421b8 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -43,6 +43,7 @@ #include "packet-queue.h" #include "threads.h" #include "threadvars.h" +#include "flow-worker.h" #include "util-atomic.h" #include "util-spm.h" @@ -856,6 +857,8 @@ void RegisterAllModules() TmModuleNapatechStreamRegister(); TmModuleNapatechDecodeRegister(); + /* flow worker */ + TmModuleFlowWorkerRegister(); /* stream engine */ TmModuleStreamTcpRegister(); /* detection */ diff --git a/src/tm-modules.c b/src/tm-modules.c index 06190b654905..b798d1d4d836 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -199,6 +199,7 @@ void TmModuleRegisterTests(void) const char * TmModuleTmmIdToString(TmmId id) { switch (id) { + CASE_CODE (TMM_FLOWWORKER); CASE_CODE (TMM_RECEIVENFLOG); CASE_CODE (TMM_DECODENFLOG); CASE_CODE (TMM_DECODENFQ); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 6a66b41795f9..dc70af9bc44e 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -31,6 +31,7 @@ * in tm-modules.c */ typedef enum { + TMM_FLOWWORKER, TMM_DECODENFQ, TMM_VERDICTNFQ, TMM_RECEIVENFQ, diff --git a/src/tm-threads.c b/src/tm-threads.c index 89db9812b421..506430d3f817 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -192,14 +192,18 @@ static int TmThreadTimeoutLoop(ThreadVars *tv, TmSlot *s) int r = TM_ECODE_OK; for (slot = s; slot != NULL; slot = slot->slot_next) { - if (slot->tm_id == TMM_STREAMTCP) { + if (slot->tm_id == TMM_FLOWWORKER || + slot->tm_id == TMM_STREAMTCP) + { stream_slot = slot; break; } } - if (tv->stream_pq == NULL || stream_slot == NULL) + if (tv->stream_pq == NULL || stream_slot == NULL) { + SCLogDebug("not running TmThreadTimeoutLoop %p/%p", tv->stream_pq, stream_slot); return r; + } SCLogDebug("flow end loop starting"); while(run) { @@ -314,11 +318,11 @@ void *TmThreadsSlotPktAcqLoop(void *td) SCMutexInit(&slot->slot_post_pq.mutex_q, NULL); /* get the 'pre qeueue' from module before the stream module */ - if (slot->slot_next != NULL && slot->slot_next->tm_id == TMM_STREAMTCP) { + if (slot->slot_next != NULL && (slot->slot_next->tm_id == TMM_FLOWWORKER)) { SCLogDebug("pre-stream packetqueue %p (postq)", &s->slot_post_pq); tv->stream_pq = &slot->slot_post_pq; /* if the stream module is the first, get the threads input queue */ - } else if (slot == (TmSlot *)tv->tm_slots && slot->tm_id == TMM_STREAMTCP) { + } else if (slot == (TmSlot *)tv->tm_slots && (slot->tm_id == TMM_FLOWWORKER)) { tv->stream_pq = &trans_q[tv->inq->id]; SCLogDebug("pre-stream packetqueue %p (inq)", &slot->slot_pre_pq); } @@ -438,11 +442,11 @@ void *TmThreadsSlotPktAcqLoopAFL(void *td) SCMutexInit(&slot->slot_post_pq.mutex_q, NULL); /* get the 'pre qeueue' from module before the stream module */ - if (slot->slot_next != NULL && slot->slot_next->tm_id == TMM_STREAMTCP) { + if (slot->slot_next != NULL && (slot->slot_next->tm_id == TMM_FLOWWORKER)) { SCLogDebug("pre-stream packetqueue %p (postq)", &s->slot_post_pq); tv->stream_pq = &slot->slot_post_pq; /* if the stream module is the first, get the threads input queue */ - } else if (slot == (TmSlot *)tv->tm_slots && slot->tm_id == TMM_STREAMTCP) { + } else if (slot == (TmSlot *)tv->tm_slots && (slot->tm_id == TMM_FLOWWORKER)) { tv->stream_pq = &trans_q[tv->inq->id]; SCLogDebug("pre-stream packetqueue %p (inq)", &slot->slot_pre_pq); } @@ -559,11 +563,11 @@ void *TmThreadsSlotVar(void *td) * from the flow timeout code */ /* get the 'pre qeueue' from module before the stream module */ - if (s->slot_next != NULL && s->slot_next->tm_id == TMM_STREAMTCP) { + if (s->slot_next != NULL && (s->slot_next->tm_id == TMM_FLOWWORKER)) { SCLogDebug("pre-stream packetqueue %p (preq)", &s->slot_pre_pq); tv->stream_pq = &s->slot_pre_pq; /* if the stream module is the first, get the threads input queue */ - } else if (s == (TmSlot *)tv->tm_slots && s->tm_id == TMM_STREAMTCP) { + } else if (s == (TmSlot *)tv->tm_slots && (s->tm_id == TMM_FLOWWORKER)) { tv->stream_pq = &trans_q[tv->inq->id]; SCLogDebug("pre-stream packetqueue %p (inq)", &s->slot_pre_pq); } diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 8242c8172461..375295b1044b 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -246,22 +246,13 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } - TmModule *tm_module = TmModuleGetByName("StreamTcp"); + TmModule *tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (DetectEngineEnabled()) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - } - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); TmThreadSetGroupName(tv_detect_ncpu, "Detect"); @@ -347,22 +338,13 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod } TmSlotSetFuncAppend(tv, tm_module, NULL); - tm_module = TmModuleGetByName("StreamTcp"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (DetectEngineEnabled()) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv, tm_module, NULL); - } - tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName RespondReject failed"); @@ -541,22 +523,14 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } - TmModule *tm_module = TmModuleGetByName("StreamTcp"); + + TmModule *tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (DetectEngineEnabled()) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - } - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); SetupOutputs(tv_detect_ncpu); @@ -656,22 +630,13 @@ int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, } TmSlotSetFuncAppend(tv, tm_module, NULL); - tm_module = TmModuleGetByName("StreamTcp"); + TmModule *tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (DetectEngineEnabled()) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv, tm_module, NULL); - } - tm_module = TmModuleGetByName(verdict_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", verdict_mod_name); diff --git a/src/util-validate.h b/src/util-validate.h index b7647a7d4da8..c0dac20b78be 100644 --- a/src/util-validate.h +++ b/src/util-validate.h @@ -53,14 +53,12 @@ */ #define DEBUG_VALIDATE_FLOW(f) do { \ if ((f) != NULL) { \ - SCMutexLock(&(f)->m); \ BUG_ON((f)->flags & FLOW_IPV4 && \ (f)->flags & FLOW_IPV6); \ if ((f)->proto == IPPROTO_TCP) { \ BUG_ON((f)->alstate != NULL && \ (f)->alparser == NULL); \ } \ - SCMutexUnlock(&(f)->m); \ } \ } while(0) From 61ce05e7ed8a8ef7b02ff57f2e7c6281003ef62c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 May 2016 18:05:26 +0200 Subject: [PATCH 1403/2553] flow: remove dead code --- src/flow.h | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/flow.h b/src/flow.h index 3335f967972e..95f3333a65dc 100644 --- a/src/flow.h +++ b/src/flow.h @@ -453,33 +453,13 @@ 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 *); int FlowGetPacketDirection(const Flow *, const 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 @@ -494,22 +474,6 @@ static inline void FlowSetNoPacketInspectionFlag(Flow *f) 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 From 78ecfe8780ca3d06bba9318c42775f51e132e45f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 May 2016 18:34:55 +0200 Subject: [PATCH 1404/2553] autofp: update queue handlers Now that the flow lookup is done in the worker threads the flow queue handlers running after the capture thread(s) no longer have access to the flow. This limits the options of how flow balancing can be done. This patch removes all code that is now useless. The only 2 methods that still make sense are 'hash' and 'ippair'. --- src/flow-hash.c | 4 - src/flow-util.h | 6 -- src/flow.h | 3 - src/tmqh-flow.c | 193 +++--------------------------------------------- src/tmqh-flow.h | 4 - 5 files changed, 12 insertions(+), 198 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index c7418aa29491..466b246cc59b 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -415,7 +415,6 @@ static Flow *TcpReuseReplace(ThreadVars *tv, DecodeThreadVars *dtv, old_f->flags |= FLOW_TCP_REUSED; /* get some settings that we move over to the new flow */ FlowThreadId thread_id = old_f->thread_id; - int16_t autofp_tmqh_flow_qid = SC_ATOMIC_GET(old_f->autofp_tmqh_flow_qid); /* since fb lock is still held this flow won't be found until we are done */ FLOWLOCK_UNLOCK(old_f); @@ -439,9 +438,6 @@ static Flow *TcpReuseReplace(ThreadVars *tv, DecodeThreadVars *dtv, f->fb = fb; f->thread_id = thread_id; - if (autofp_tmqh_flow_qid != -1) { - SC_ATOMIC_SET(f->autofp_tmqh_flow_qid, autofp_tmqh_flow_qid); - } return f; } diff --git a/src/flow-util.h b/src/flow-util.h index ca6a49cccb29..7ab08f6c4f0a 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -70,8 +70,6 @@ (f)->hprev = NULL; \ (f)->lnext = NULL; \ (f)->lprev = NULL; \ - SC_ATOMIC_INIT((f)->autofp_tmqh_flow_qid); \ - (void) SC_ATOMIC_SET((f)->autofp_tmqh_flow_qid, -1); \ RESET_COUNTERS((f)); \ } while (0) @@ -113,9 +111,6 @@ (f)->sgh_toclient = NULL; \ GenericVarFree((f)->flowvar); \ (f)->flowvar = NULL; \ - if (SC_ATOMIC_GET((f)->autofp_tmqh_flow_qid) != -1) { \ - (void) SC_ATOMIC_SET((f)->autofp_tmqh_flow_qid, -1); \ - } \ RESET_COUNTERS((f)); \ } while(0) @@ -129,7 +124,6 @@ DetectEngineStateFlowFree((f)->de_state); \ } \ GenericVarFree((f)->flowvar); \ - SC_ATOMIC_DESTROY((f)->autofp_tmqh_flow_qid); \ } while(0) /** \brief check if a memory alloc would fit in the memcap diff --git a/src/flow.h b/src/flow.h index 95f3333a65dc..0400250e2362 100644 --- a/src/flow.h +++ b/src/flow.h @@ -334,9 +334,6 @@ typedef struct Flow_ */ SC_ATOMIC_DECLARE(FlowRefCount, use_cnt); - /** flow queue id, used with autofp */ - SC_ATOMIC_DECLARE(int16_t, autofp_tmqh_flow_qid); - /** flow tenant id, used to setup flow timeout and stream pseudo * packets with the correct tenant id set */ uint32_t tenant_id; diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index 881c5985cae8..480e909c32a0 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -42,8 +42,6 @@ Packet *TmqhInputFlow(ThreadVars *t); void TmqhOutputFlowHash(ThreadVars *t, Packet *p); void TmqhOutputFlowIPPair(ThreadVars *t, Packet *p); -void TmqhOutputFlowActivePackets(ThreadVars *t, Packet *p); -void TmqhOutputFlowRoundRobin(ThreadVars *t, Packet *p); void *TmqhOutputFlowSetupCtx(char *queue_str); void TmqhOutputFlowFreeCtx(void *ctx); void TmqhFlowRegisterTests(void); @@ -59,10 +57,10 @@ void TmqhFlowRegister(void) char *scheduler = NULL; if (ConfGet("autofp-scheduler", &scheduler) == 1) { if (strcasecmp(scheduler, "round-robin") == 0) { - tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowRoundRobin; + SCLogNotice("using flow hash instead of round robin"); + tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } else if (strcasecmp(scheduler, "active-packets") == 0) { - //tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; - SCLogNotice("FIXME: using flow hash instead of active packets"); + SCLogNotice("using flow hash instead of active packets"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } else if (strcasecmp(scheduler, "hash") == 0) { tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; @@ -75,7 +73,6 @@ void TmqhFlowRegister(void) exit(EXIT_FAILURE); } } else { - //tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } @@ -88,8 +85,6 @@ void TmqhFlowPrintAutofpHandler(void) if (tmqh_table[TMQH_FLOW].OutHandler == (f)) \ SCLogInfo("AutoFP mode using \"%s\" flow load balancer", (msg)) - PRINT_IF_FUNC(TmqhOutputFlowRoundRobin, "Round Robin"); - PRINT_IF_FUNC(TmqhOutputFlowActivePackets, "Active Packets"); PRINT_IF_FUNC(TmqhOutputFlowHash, "Hash"); PRINT_IF_FUNC(TmqhOutputFlowIPPair, "IPPair"); @@ -153,8 +148,6 @@ static int StoreQueueId(TmqhFlowCtx *ctx, char *name) memset(ctx->queues + (ctx->size - 1), 0, sizeof(TmqhFlowMode)); } ctx->queues[ctx->size - 1].q = &trans_q[id]; - SC_ATOMIC_INIT(ctx->queues[ctx->size - 1].total_packets); - SC_ATOMIC_INIT(ctx->queues[ctx->size - 1].total_flows); return 0; } @@ -205,8 +198,6 @@ void *TmqhOutputFlowSetupCtx(char *queue_str) tstr = comma ? (comma + 1) : comma; } while (tstr != NULL); - SC_ATOMIC_INIT(ctx->round_robin_idx); - SCFree(str); return (void *)ctx; @@ -219,161 +210,16 @@ void *TmqhOutputFlowSetupCtx(char *queue_str) void TmqhOutputFlowFreeCtx(void *ctx) { - int i; TmqhFlowCtx *fctx = (TmqhFlowCtx *)ctx; SCLogInfo("AutoFP - Total flow handler queues - %" PRIu16, fctx->size); - for (i = 0; i < fctx->size; i++) { - SCLogInfo("AutoFP - Queue %-2"PRIu32 " - pkts: %-12"PRIu64" flows: %-12"PRIu64, i, - SC_ATOMIC_GET(fctx->queues[i].total_packets), - SC_ATOMIC_GET(fctx->queues[i].total_flows)); - SC_ATOMIC_DESTROY(fctx->queues[i].total_packets); - SC_ATOMIC_DESTROY(fctx->queues[i].total_flows); - } - SCFree(fctx->queues); SCFree(fctx); return; } -/** - * \brief select the queue to output in a round robin fashion. - * - * \param tv thread vars - * \param p packet - */ -void TmqhOutputFlowRoundRobin(ThreadVars *tv, Packet *p) -{ - int16_t qid = 0; - - TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; - - /* if no flow we use the first queue, - * should be rare */ - if (p->flow != NULL) { - qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); - if (qid == -1) { - qid = SC_ATOMIC_ADD(ctx->round_robin_idx, 1); - if (qid >= ctx->size) { - SC_ATOMIC_RESET(ctx->round_robin_idx); - qid = 0; - } - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); - (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, qid); - } - } else { - qid = ctx->last++; - - if (ctx->last == ctx->size) - ctx->last = 0; - } - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); - - PacketQueue *q = ctx->queues[qid].q; - SCMutexLock(&q->mutex_q); - PacketEnqueue(q, p); - SCCondSignal(&q->cond_q); - SCMutexUnlock(&q->mutex_q); - - return; -} - -/** - * \brief select the queue to output to based on queue lengths. - * - * \param tv thread vars - * \param p packet - */ -void TmqhOutputFlowActivePackets(ThreadVars *tv, Packet *p) -{ - int16_t qid = 0; - - TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; - - /* if no flow we round robin the packets over the queues */ - if (p->flow != NULL) { - qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); - if (qid == -1) { - int16_t i = 0; - int16_t lowest_id = 0; - TmqhFlowMode *queues = ctx->queues; - uint32_t lowest = queues[i].q->len; - for (i = 1; i < ctx->size; i++) { - if (queues[i].q->len < lowest) { - lowest = queues[i].q->len; - lowest_id = i; - } - } - qid = lowest_id; - (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, lowest_id); - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); - } - } else { - qid = ctx->last++; - - if (ctx->last == ctx->size) - ctx->last = 0; - } - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); - - PacketQueue *q = ctx->queues[qid].q; - SCMutexLock(&q->mutex_q); - PacketEnqueue(q, p); - SCCondSignal(&q->cond_q); - SCMutexUnlock(&q->mutex_q); - - return; -} - -/** - * \brief select the queue to output based on address hash. - * - * \param tv thread vars. - * \param p packet. - */ -void TmqhOutputFlowHash2(ThreadVars *tv, Packet *p) -{ - int16_t qid = 0; - - TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; - - /* if no flow we use the first queue, - * should be rare */ - if (p->flow != NULL) { - qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); - if (qid == -1) { -#if __WORDSIZE == 64 - uint64_t addr = (uint64_t)p->flow; -#else - uint32_t addr = (uint32_t)p->flow; -#endif - addr >>= 7; - - /* we don't have to worry about possible overflow, since - * ctx->size will be less than 2 ** 15 for sure */ - qid = addr % ctx->size; - (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, qid); - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); - } - } else { - qid = ctx->last++; - - if (ctx->last == ctx->size) - ctx->last = 0; - } - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); - - PacketQueue *q = ctx->queues[qid].q; - SCMutexLock(&q->mutex_q); - PacketEnqueue(q, p); - SCCondSignal(&q->cond_q); - SCMutexUnlock(&q->mutex_q); - - return; -} - void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) { int16_t qid = 0; @@ -389,7 +235,6 @@ void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) if (ctx->last == ctx->size) ctx->last = 0; } - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); PacketQueue *q = ctx->queues[qid].q; SCMutexLock(&q->mutex_q); @@ -399,6 +244,7 @@ void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) return; } + /** * \brief select the queue to output based on IP address pair. * @@ -413,32 +259,17 @@ void TmqhOutputFlowIPPair(ThreadVars *tv, Packet *p) TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; - /* if no flow we use the first queue, - * should be rare */ - if (p->flow != NULL) { - qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); - if (qid == -1) { - if (p->src.family == AF_INET6) { - for (i = 0; i < 4; i++) { - addr_hash += p->src.addr_data32[i] + p->dst.addr_data32[i]; - } - } else { - addr_hash = p->src.addr_data32[0] + p->dst.addr_data32[0]; - } - - /* we don't have to worry about possible overflow, since - * ctx->size will be lesser than 2 ** 31 for sure */ - qid = addr_hash % ctx->size; - (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, qid); - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); + if (p->src.family == AF_INET6) { + for (i = 0; i < 4; i++) { + addr_hash += p->src.addr_data32[i] + p->dst.addr_data32[i]; } } else { - qid = ctx->last++; - - if (ctx->last == ctx->size) - ctx->last = 0; + addr_hash = p->src.addr_data32[0] + p->dst.addr_data32[0]; } - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); + + /* we don't have to worry about possible overflow, since + * ctx->size will be lesser than 2 ** 31 for sure */ + qid = addr_hash % ctx->size; PacketQueue *q = ctx->queues[qid].q; SCMutexLock(&q->mutex_q); diff --git a/src/tmqh-flow.h b/src/tmqh-flow.h index e710ffeca468..3cec7a165f5b 100644 --- a/src/tmqh-flow.h +++ b/src/tmqh-flow.h @@ -26,8 +26,6 @@ typedef struct TmqhFlowMode_ { PacketQueue *q; - SC_ATOMIC_DECLARE(uint64_t, total_packets); - SC_ATOMIC_DECLARE(uint64_t, total_flows); } TmqhFlowMode; /** \brief Ctx for the flow queue handler @@ -38,8 +36,6 @@ typedef struct TmqhFlowCtx_ { uint16_t last; TmqhFlowMode *queues; - - SC_ATOMIC_DECLARE(int16_t, round_robin_idx); } TmqhFlowCtx; void TmqhFlowRegister (void); From 81b2984c4e4b244afd87502bec94209a3d0d8094 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 8 Nov 2015 18:30:05 +0100 Subject: [PATCH 1405/2553] streaming: buffer API Add a new API to store data from streaming sources, like HTTP body processing or TCP data. Currently most of the code uses a pattern of list of data chunks (e.g. TcpSegment) that is reassembled into a large buffer on-demand. The Streaming Buffer API changes the logic to store the data in reassembled form from the start, with the segments/chunks pointing to the reassembled data. The main buffer storing the data slides forward, automatically or manually. The *NoTrack calls allows for a segmentless mode of operation. This approach has two main advantages: 1. accessing the reassembled data is virtually cost-free 2. reduction of allocations and memory management --- src/Makefile.am | 1 + src/output-streaming.c | 2 +- src/runmode-unittests.c | 4 + src/util-streaming-buffer.c | 725 ++++++++++++++++++++++++++++++++++++ src/util-streaming-buffer.h | 140 +++++++ 5 files changed, 871 insertions(+), 1 deletion(-) create mode 100644 src/util-streaming-buffer.c create mode 100644 src/util-streaming-buffer.h diff --git a/src/Makefile.am b/src/Makefile.am index b729388ee337..65f175e8c512 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -404,6 +404,7 @@ util-spm-bs.c util-spm-bs.h \ util-spm-hs.c util-spm-hs.h \ util-spm.c util-spm.h util-clock.h \ util-storage.c util-storage.h \ +util-streaming-buffer.c util-streaming-buffer.h \ util-strlcatu.c \ util-strlcpyu.c \ util-syslog.c util-syslog.h \ diff --git a/src/output-streaming.c b/src/output-streaming.c index 73aa115b4030..4ae7c58c2e5e 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -98,7 +98,7 @@ typedef struct StreamerCallbackData_ { enum OutputStreamingType type; } StreamerCallbackData; -int Streamer(void *cbdata, Flow *f, uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags) +int Streamer(void *cbdata, Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags) { StreamerCallbackData *streamer_cbdata = (StreamerCallbackData *)cbdata; BUG_ON(streamer_cbdata == NULL); diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 523d81afddfa..6f572d3fce1b 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -118,6 +118,8 @@ #include "defrag.h" #include "detect-engine-siggroup.h" +#include "util-streaming-buffer.h" + #endif /* UNITTESTS */ void RegisterAllModules(); @@ -278,6 +280,8 @@ void RunUnittests(int list_unittests, char *regex_arg) #endif AppLayerUnittestsRegister(); MimeDecRegisterTests(); + StreamingBufferRegisterTests(); + if (list_unittests) { UtListTests(regex_arg); } else { diff --git a/src/util-streaming-buffer.c b/src/util-streaming-buffer.c new file mode 100644 index 000000000000..d0df5f687da2 --- /dev/null +++ b/src/util-streaming-buffer.c @@ -0,0 +1,725 @@ +/* Copyright (C) 2015-2016 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. + */ + +#include "suricata-common.h" +#include "util-streaming-buffer.h" +#include "util-unittest.h" +#include "util-print.h" + +/** + * \file + * + * \author Victor Julien + * + * \brief Streaming Buffer API + */ + +/* memory handling wrappers. If config doesn't define it's own set of + * functions, use the defaults */ +#define MALLOC(cfg, s) \ + (cfg)->Malloc ? (cfg)->Malloc((s)) : SCMalloc((s)) +#define CALLOC(cfg, n, s) \ + (cfg)->Calloc ? (cfg)->Calloc((n), (s)) : SCCalloc((n), (s)) +#define REALLOC(cfg, ptr, orig_s, s) \ + (cfg)->Realloc ? (cfg)->Realloc((ptr), (orig_s), (s)) : SCRealloc((ptr), (s)) +#define FREE(cfg, ptr, s) \ + (cfg)->Free ? (cfg)->Free((ptr), (s)) : SCFree((ptr)) + +static inline int InitBuffer(StreamingBuffer *sb) +{ + sb->buf = CALLOC(sb->cfg, 1, sb->cfg->buf_size); + if (sb->buf == NULL) { + return -1; + } + sb->buf_size = sb->cfg->buf_size; + return 0; +} + +StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg) +{ + StreamingBuffer *sb = CALLOC(cfg, 1, sizeof(StreamingBuffer)); + if (sb != NULL) { + sb->buf_size = cfg->buf_size; + sb->cfg = cfg; + + if (cfg->buf_size > 0) { + if (InitBuffer(sb) == 0) { + return sb; + } + FREE(cfg, sb, sizeof(StreamingBuffer)); + /* implied buf_size == 0 */ + } else { + return sb; + } + } + return NULL; +} + +void StreamingBufferClear(StreamingBuffer *sb) +{ + if (sb != NULL) { + SCLogDebug("sb->buf_size %u max %u", sb->buf_size, sb->buf_size_max); + + if (sb->buf != NULL) { + FREE(sb->cfg, sb->buf, sb->buf_size); + sb->buf = NULL; + } + } +} + +void StreamingBufferFree(StreamingBuffer *sb) +{ + if (sb != NULL) { + StreamingBufferClear(sb); + FREE(sb->cfg, sb, sizeof(StreamingBuffer)); + } +} + +/** + * \internal + * \brief move buffer forward by 'slide' + */ +static void AutoSlide(StreamingBuffer *sb) +{ + uint32_t size = sb->cfg->buf_slide; + uint32_t slide = sb->buf_offset - size; + SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size); + memmove(sb->buf, sb->buf+slide, size); + sb->stream_offset += slide; + sb->buf_offset = size; +} + +static void GrowToSize(StreamingBuffer *sb, uint32_t size) +{ + /* try to grow in multiples of sb->cfg->buf_size */ + uint32_t x = sb->cfg->buf_size ? size % sb->cfg->buf_size : 0; + uint32_t base = size - x; + uint32_t grow = base + sb->cfg->buf_size; + + void *ptr = REALLOC(sb->cfg, sb->buf, sb->buf_size, grow); + if (ptr != NULL) { + /* for safe printing and general caution, lets memset the + * new data to 0 */ + size_t diff = grow - sb->buf_size; + void *new_mem = ((char *)ptr) + sb->buf_size; + memset(new_mem, 0, diff); + + sb->buf = ptr; + sb->buf_size = grow; + SCLogDebug("grown buffer to %u", grow); +#ifdef DEBUG + if (sb->buf_size > sb->buf_size_max) { + sb->buf_size_max = sb->buf_size; + } +#endif + } +} + +static void Grow(StreamingBuffer *sb) +{ + uint32_t grow = sb->buf_size * 2; + void *ptr = REALLOC(sb->cfg, sb->buf, sb->buf_size, grow); + if (ptr != NULL) { + /* for safe printing and general caution, lets memset the + * new data to 0 */ + size_t diff = grow - sb->buf_size; + void *new_mem = ((char *)ptr) + sb->buf_size; + memset(new_mem, 0, diff); + + sb->buf = ptr; + sb->buf_size = grow; + SCLogDebug("grown buffer to %u", grow); +#ifdef DEBUG + if (sb->buf_size > sb->buf_size_max) { + sb->buf_size_max = sb->buf_size; + } +#endif + } +} + +/** + * \brief slide to absolute offset + * \todo if sliding beyond window, we could perhaps reset? + */ +void StreamingBufferSlideToOffset(StreamingBuffer *sb, uint64_t offset) +{ + if (offset > sb->stream_offset && + offset <= sb->stream_offset + sb->buf_offset) + { + uint32_t slide = offset - sb->stream_offset; + uint32_t size = sb->buf_offset - slide; + SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size); + memmove(sb->buf, sb->buf+slide, size); + sb->stream_offset += slide; + sb->buf_offset = size; + } +} + +void StreamingBufferSlide(StreamingBuffer *sb, uint32_t slide) +{ + uint32_t size = sb->buf_offset - slide; + SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size); + memmove(sb->buf, sb->buf+slide, size); + sb->stream_offset += slide; + sb->buf_offset = size; +} + +#define DATA_FITS(sb, len) \ + ((sb)->buf_offset + (len) <= (sb)->buf_size) + +StreamingBufferSegment *StreamingBufferAppendRaw(StreamingBuffer *sb, const uint8_t *data, uint32_t data_len) +{ + if (sb->buf == NULL) { + if (InitBuffer(sb) == -1) + return NULL; + } + + StreamingBufferSegment *seg = CALLOC(sb->cfg, 1, sizeof(StreamingBufferSegment)); + if (seg != NULL) { + if (!DATA_FITS(sb, data_len)) { + if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) + AutoSlide(sb); + if (sb->buf_size == 0) { + GrowToSize(sb, data_len); + } else { + while (!DATA_FITS(sb, data_len)) { + Grow(sb); + } + } + } + if (!DATA_FITS(sb, data_len)) { + FREE(sb->cfg, seg, sizeof(StreamingBufferSegment)); + return NULL; + } + + memcpy(sb->buf + sb->buf_offset, data, data_len); + seg->stream_offset = sb->stream_offset + sb->buf_offset; + seg->segment_len = data_len; + sb->buf_offset += data_len; + return seg; + } + return NULL; +} + +void StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len) +{ + BUG_ON(seg == NULL); + + if (sb->buf == NULL) { + if (InitBuffer(sb) == -1) + return; + } + + if (!DATA_FITS(sb, data_len)) { + if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) + AutoSlide(sb); + if (sb->buf_size == 0) { + GrowToSize(sb, data_len); + } else { + while (!DATA_FITS(sb, data_len)) { + Grow(sb); + } + } + } + if (!DATA_FITS(sb, data_len)) { + return; + } + + memcpy(sb->buf + sb->buf_offset, data, data_len); + seg->stream_offset = sb->stream_offset + sb->buf_offset; + seg->segment_len = data_len; + sb->buf_offset += data_len; +} + +/** + * \brief add data w/o tracking a segment + */ +void StreamingBufferAppendNoTrack(StreamingBuffer *sb, + const uint8_t *data, uint32_t data_len) +{ + if (sb->buf == NULL) { + if (InitBuffer(sb) == -1) + return; + } + + if (!DATA_FITS(sb, data_len)) { + if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) + AutoSlide(sb); + if (sb->buf_size == 0) { + GrowToSize(sb, data_len); + } else { + while (!DATA_FITS(sb, data_len)) { + Grow(sb); + } + } + } + if (!DATA_FITS(sb, data_len)) { + return; + } + + memcpy(sb->buf + sb->buf_offset, data, data_len); + sb->buf_offset += data_len; +} + +#define DATA_FITS_AT_OFFSET(sb, len, offset) \ + ((offset) + (len) <= (sb)->buf_size) + +/** + * \param offset offset relative to StreamingBuffer::stream_offset + */ +void StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len, + uint64_t offset) +{ + BUG_ON(seg == NULL); + + if (offset < sb->stream_offset) + return; + + if (sb->buf == NULL) { + if (InitBuffer(sb) == -1) + return; + } + + uint32_t rel_offset = offset - sb->stream_offset; + if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) { + if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) { + AutoSlide(sb); + rel_offset = offset - sb->stream_offset; + } + if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) { + GrowToSize(sb, (rel_offset + data_len)); + } + } + BUG_ON(!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)); + + memcpy(sb->buf + rel_offset, data, data_len); + seg->stream_offset = offset; + seg->segment_len = data_len; + if (rel_offset + data_len > sb->buf_offset) + sb->buf_offset = rel_offset + data_len; + + +} + +int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb, + const StreamingBufferSegment *seg) +{ + if (seg->stream_offset < sb->stream_offset) { + if (seg->stream_offset + seg->segment_len <= sb->stream_offset) { + return 1; + } + } + return 0; +} + +void StreamingBufferSegmentGetData(const StreamingBuffer *sb, + const StreamingBufferSegment *seg, + const uint8_t **data, uint32_t *data_len) +{ + if (seg->stream_offset >= sb->stream_offset) { + uint64_t offset = seg->stream_offset - sb->stream_offset; + *data = sb->buf + offset; + if (offset + seg->segment_len > sb->buf_size) + *data_len = sb->buf_size - offset; + else + *data_len = seg->segment_len; + return; + } else { + uint64_t offset = sb->stream_offset - seg->stream_offset; + if (offset < seg->segment_len) { + *data = sb->buf; + *data_len = seg->segment_len - offset; + return; + } + } + *data = NULL; + *data_len = 0; + return; +} + +/** + * \retval 1 data is the same + * \retval 0 data is different + */ +int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb, + const StreamingBufferSegment *seg, + const uint8_t *rawdata, uint32_t rawdata_len) +{ + const uint8_t *segdata = NULL; + uint32_t segdata_len = 0; + StreamingBufferSegmentGetData(sb, seg, &segdata, &segdata_len); + if (segdata && segdata_len && + segdata_len == rawdata_len && + memcmp(segdata, rawdata, segdata_len) == 0) + { + return 1; + } + return 0; +} + +int StreamingBufferGetData(const StreamingBuffer *sb, + const uint8_t **data, uint32_t *data_len, + uint64_t *stream_offset) +{ + if (sb != NULL && sb->buf != NULL) { + *data = sb->buf; + *data_len = sb->buf_offset; + *stream_offset = sb->stream_offset; + return 1; + } else { + *data = NULL; + *data_len = 0; + *stream_offset = 0; + return 0; + } +} + +int StreamingBufferGetDataAtOffset (const StreamingBuffer *sb, + const uint8_t **data, uint32_t *data_len, + uint64_t offset) +{ + if (sb != NULL && sb->buf != NULL && + offset >= sb->stream_offset && + offset < (sb->stream_offset + sb->buf_offset)) + { + uint32_t skip = offset - sb->stream_offset; + *data = sb->buf + skip; + *data_len = sb->buf_offset - skip; + return 1; + } else { + *data = NULL; + *data_len = 0; + return 0; + } +} + +/** + * \retval 1 data is the same + * \retval 0 data is different + */ +int StreamingBufferCompareRawData(const StreamingBuffer *sb, + const uint8_t *rawdata, uint32_t rawdata_len) +{ + const uint8_t *sbdata = NULL; + uint32_t sbdata_len = 0; + uint64_t offset = 0; + StreamingBufferGetData(sb, &sbdata, &sbdata_len, &offset); + if (offset == 0 && + sbdata && sbdata_len && + sbdata_len == rawdata_len && + memcmp(sbdata, rawdata, sbdata_len) == 0) + { + return 1; + } + SCLogInfo("sbdata_len %u, offset %u", sbdata_len, (uint)offset); + PrintRawDataFp(stdout, sbdata,sbdata_len); + return 0; +} + +void Dump(StreamingBuffer *sb) +{ + PrintRawDataFp(stdout, sb->buf, sb->buf_offset); +} + +void DumpSegment(StreamingBuffer *sb, StreamingBufferSegment *seg) +{ + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(sb, seg, &data, &data_len); + if (data && data_len) { + PrintRawDataFp(stdout, data, data_len); + } +} + +#ifdef UNITTESTS +static int StreamingBufferTest01(void) +{ + StreamingBufferConfig cfg = { STREAMING_BUFFER_AUTOSLIDE, 8, 16, NULL, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment *seg1 = StreamingBufferAppendRaw(sb, (const uint8_t *)"ABCDEFGH", 8); + StreamingBufferSegment *seg2 = StreamingBufferAppendRaw(sb, (const uint8_t *)"01234567", 8); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 16); + FAIL_IF(seg1->stream_offset != 0); + FAIL_IF(seg2->stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg1,(const uint8_t *)"ABCDEFGH", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg2,(const uint8_t *)"01234567", 8)); + Dump(sb); + + StreamingBufferSegment *seg3 = StreamingBufferAppendRaw(sb, (const uint8_t *)"QWERTY", 6); + FAIL_IF(sb->stream_offset != 8); + FAIL_IF(sb->buf_offset != 14); + FAIL_IF(seg3->stream_offset != 16); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg3,(const uint8_t *)"QWERTY", 6)); + Dump(sb); + + StreamingBufferSegment *seg4 = StreamingBufferAppendRaw(sb, (const uint8_t *)"KLM", 3); + FAIL_IF(sb->stream_offset != 14); + FAIL_IF(sb->buf_offset != 11); + FAIL_IF(seg4->stream_offset != 22); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg4,(const uint8_t *)"KLM", 3)); + Dump(sb); + + StreamingBufferSegment *seg5 = StreamingBufferAppendRaw(sb, (const uint8_t *)"!@#$%^&*()_+<>?/,.;:'[]{}-=", 27); + FAIL_IF(sb->stream_offset != 17); + FAIL_IF(sb->buf_offset != 35); + FAIL_IF(seg5->stream_offset != 25); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1)); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg5)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg5,(const uint8_t *)"!@#$%^&*()_+<>?/,.;:'[]{}-=", 27)); + Dump(sb); + + StreamingBufferSegment *seg6 = StreamingBufferAppendRaw(sb, (const uint8_t *)"UVWXYZ", 6); + FAIL_IF(sb->stream_offset != 17); + FAIL_IF(sb->buf_offset != 41); + FAIL_IF(seg6->stream_offset != 52); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1)); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg5)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg6)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg6,(const uint8_t *)"UVWXYZ", 6)); + Dump(sb); + + SCFree(seg1); + SCFree(seg2); + SCFree(seg3); + SCFree(seg4); + SCFree(seg5); + SCFree(seg6); + StreamingBufferFree(sb); + PASS; +} + +static int StreamingBufferTest02(void) +{ + StreamingBufferConfig cfg = { 0, 8, 24, NULL, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8); + StreamingBufferSegment seg2; + StreamingBufferAppend(sb, &seg2, (const uint8_t *)"01234567", 8); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 16); + FAIL_IF(seg1.stream_offset != 0); + FAIL_IF(seg2.stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + + StreamingBufferSlide(sb, 6); + + StreamingBufferSegment seg3; + StreamingBufferAppend(sb, &seg3, (const uint8_t *)"QWERTY", 6); + FAIL_IF(sb->stream_offset != 6); + FAIL_IF(sb->buf_offset != 16); + FAIL_IF(seg3.stream_offset != 16); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + + StreamingBufferSlide(sb, 6); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + + StreamingBufferFree(sb); + PASS; +} + +static int StreamingBufferTest03(void) +{ + StreamingBufferConfig cfg = { 0, 8, 24, NULL, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8); + StreamingBufferSegment seg2; + StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 22); + FAIL_IF(seg1.stream_offset != 0); + FAIL_IF(seg2.stream_offset != 14); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + + StreamingBufferSegment seg3; + StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 22); + FAIL_IF(seg3.stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + + StreamingBufferSlide(sb, 10); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + + StreamingBufferFree(sb); + PASS; +} + +static int StreamingBufferTest04(void) +{ + StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8); + StreamingBufferSegment seg2; + StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 22); + FAIL_IF(seg1.stream_offset != 0); + FAIL_IF(seg2.stream_offset != 14); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + + StreamingBufferSegment seg3; + StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 22); + FAIL_IF(seg3.stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + + /* far ahead of curve: */ + StreamingBufferSegment seg4; + StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"XYZ", 3, 124); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 127); + FAIL_IF(sb->buf_size != 128); + FAIL_IF(seg4.stream_offset != 124); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg4)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + DumpSegment(sb, &seg4); + + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg1,(const uint8_t *)"ABCDEFGH", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg2,(const uint8_t *)"01234567", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg3,(const uint8_t *)"QWERTY", 6)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg4,(const uint8_t *)"XYZ", 3)); + + StreamingBufferFree(sb); + PASS; +} + +static int StreamingBufferTest05(void) +{ + StreamingBufferConfig cfg = { STREAMING_BUFFER_AUTOSLIDE, 8, 32, NULL, NULL, NULL, NULL }; + StreamingBuffer sb = STREAMING_BUFFER_INITIALIZER(&cfg); + + StreamingBufferSegment *seg1 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"AAAAAAAA", 8); + StreamingBufferSegment *seg2 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"BBBBBBBB", 8); + StreamingBufferSegment *seg3 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"CCCCCCCC", 8); + StreamingBufferSegment *seg4 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"DDDDDDDD", 8); + FAIL_IF(sb.stream_offset != 0); + FAIL_IF(sb.buf_offset != 32); + FAIL_IF(seg1->stream_offset != 0); + FAIL_IF(seg2->stream_offset != 8); + FAIL_IF(seg3->stream_offset != 16); + FAIL_IF(seg4->stream_offset != 24); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg4)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg1,(const uint8_t *)"AAAAAAAA", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg2,(const uint8_t *)"BBBBBBBB", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg3,(const uint8_t *)"CCCCCCCC", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg4,(const uint8_t *)"DDDDDDDD", 8)); + Dump(&sb); + StreamingBufferSegment *seg5 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"EEEEEEEE", 8); + FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg5,(const uint8_t *)"EEEEEEEE", 8)); + Dump(&sb); + + SCFree(seg1); + SCFree(seg2); + SCFree(seg3); + SCFree(seg4); + SCFree(seg5); + StreamingBufferClear(&sb); + PASS; +} +#endif + +void StreamingBufferRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("StreamingBufferTest01", StreamingBufferTest01); + UtRegisterTest("StreamingBufferTest02", StreamingBufferTest02); + UtRegisterTest("StreamingBufferTest03", StreamingBufferTest03); + UtRegisterTest("StreamingBufferTest04", StreamingBufferTest04); + UtRegisterTest("StreamingBufferTest05", StreamingBufferTest05); +#endif +} diff --git a/src/util-streaming-buffer.h b/src/util-streaming-buffer.h new file mode 100644 index 000000000000..d35e1aaca4f8 --- /dev/null +++ b/src/util-streaming-buffer.h @@ -0,0 +1,140 @@ +/* Copyright (C) 2015-2016 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. + */ + +/* + * This API is meant to be used with streaming data. A single memory + * block is used to store the data. StreamingBufferSegment points to + * chunk of data in the single StreamingBuffer. It points by offset + * and length, so no pointers. The buffer is resized on demand and + * slides forward, either automatically or manually. + * + * When a segment needs it's data it uses StreamingBufferSegmentGetData + * which takes care of checking if the segment still has a valid offset + * and length. + * + * The StreamingBuffer::stream_offset is an absolute offset since the + * start of the data streaming. + * + * Similarly, StreamingBufferSegment::stream_offset is also an absolute + * offset. + * + * Using the segments is optional. + * + * + * stream_offset buf_offset stream_offset + buf_size + * ^ ^ ^ + * | | | + * | | | + * +--------------------------------------------+ + * | data | empty | + * | xxxxxxxxxx | | + * +------^--------^--------+-------------------+ + * | | + * | | + * | | + * | | + * | | + * +------+--------+-------+ + * | StreamingBufferSegment| + * +-----------+-----------+ + * | offset | len | + * +-----------+-----------+ + */ + + +#ifndef __UTIL_STREAMING_BUFFER_H__ +#define __UTIL_STREAMING_BUFFER_H__ + +#define STREAMING_BUFFER_NOFLAGS 0 +#define STREAMING_BUFFER_AUTOSLIDE (1<<0) + +typedef struct StreamingBufferConfig_ { + uint32_t flags; + uint32_t buf_slide; + uint32_t buf_size; + void *(*Malloc)(size_t size); + void *(*Calloc)(size_t n, size_t size); + void *(*Realloc)(void *ptr, size_t orig_size, size_t size); + void (*Free)(void *ptr, size_t size); +} StreamingBufferConfig; + +#define STREAMING_BUFFER_CONFIG_INITIALIZER { 0, 0, 0, NULL, NULL, NULL, NULL, } + +typedef struct StreamingBuffer_ { + const StreamingBufferConfig *cfg; + uint64_t stream_offset; /**< offset of the start of the memory block */ + + uint8_t *buf; /**< memory block for reassembly */ + uint32_t buf_size; /**< size of memory block */ + uint32_t buf_offset; /**< how far we are in buf_size */ +#ifdef DEBUG + uint32_t buf_size_max; +#endif +} StreamingBuffer; + +#ifndef DEBUG +#define STREAMING_BUFFER_INITIALIZER(cfg) { (cfg), 0, NULL, 0, 0, }; +#else +#define STREAMING_BUFFER_INITIALIZER(cfg) { (cfg), 0, NULL, 0, 0, 0 }; +#endif + +typedef struct StreamingBufferSegment_ { + uint64_t stream_offset; + uint32_t segment_len; +} __attribute__((__packed__)) StreamingBufferSegment; + +StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg); +void StreamingBufferClear(StreamingBuffer *sb); +void StreamingBufferFree(StreamingBuffer *sb); + +void StreamingBufferSlide(StreamingBuffer *sb, uint32_t slide); +void StreamingBufferSlideToOffset(StreamingBuffer *sb, uint64_t offset); + +StreamingBufferSegment *StreamingBufferAppendRaw(StreamingBuffer *sb, + const uint8_t *data, uint32_t data_len); +void StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len); +void StreamingBufferAppendNoTrack(StreamingBuffer *sb, + const uint8_t *data, uint32_t data_len); +void StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len, + uint64_t offset); + +void StreamingBufferSegmentGetData(const StreamingBuffer *sb, + const StreamingBufferSegment *seg, + const uint8_t **data, uint32_t *data_len); + +int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb, + const StreamingBufferSegment *seg, + const uint8_t *rawdata, uint32_t rawdata_len); +int StreamingBufferCompareRawData(const StreamingBuffer *sb, + const uint8_t *rawdata, uint32_t rawdata_len); + +int StreamingBufferGetData(const StreamingBuffer *sb, + const uint8_t **data, uint32_t *data_len, + uint64_t *stream_offset); + +int StreamingBufferGetDataAtOffset (const StreamingBuffer *sb, + const uint8_t **data, uint32_t *data_len, + uint64_t offset); + +int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb, + const StreamingBufferSegment *seg); + +void StreamingBufferRegisterTests(void); + +#endif /* __UTIL_STREAMING_BUFFER_H__ */ From 46e55f1e346101ed1998ad45681e288a857a7766 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 12 Nov 2015 00:19:52 +0100 Subject: [PATCH 1406/2553] http body handling: use streaming buffer API Convert HTTP body handling to use the Streaming Buffer API. This means the HtpBodyChunks no longer maintain their own data segments, but instead add their data to the StreamingBuffer instance in the HtpBody structure. In case the HtpBodyChunk needs to access it's data it can do so still through the Streaming Buffer API. Updates & simplifies the various users of the reassembled bodies: multipart parsing and the detection engine. --- src/app-layer-htp-body.c | 80 +++++++++--------- src/app-layer-htp-file.c | 7 +- src/app-layer-htp.c | 76 ++++------------- src/app-layer-htp.h | 9 +- src/detect-engine-hcbd.c | 57 +++---------- src/detect-engine-hsbd.c | 152 ++++------------------------------ src/detect-engine.c | 10 --- src/detect-http-client-body.c | 8 +- src/detect-pcre.c | 8 +- src/detect.h | 2 +- src/output-streaming.c | 10 ++- src/util-lua-http.c | 11 ++- 12 files changed, 116 insertions(+), 314 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index d3720f8d39bb..53194307b4b8 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -62,6 +62,9 @@ #include "util-memcmp.h" +static StreamingBufferConfig default_cfg = { + 0, 0, 3072, HTPMalloc, HTPCalloc, HTPRealloc, HTPFree }; + /** * \brief Append a chunk of body to the HtpBody struct * @@ -82,20 +85,19 @@ int HtpBodyAppendChunk(HtpBody *body, const uint8_t *data, uint32_t len) SCReturnInt(0); } + if (body->sb == NULL) { + body->sb = StreamingBufferInit(&default_cfg); + if (body->sb == NULL) + SCReturnInt(-1); + } + if (body->first == NULL) { /* New chunk */ bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); if (bd == NULL) goto error; - bd->len = len; - bd->stream_offset = 0; - - bd->data = HTPCalloc(1, len); - if (bd->data == NULL) { - goto error; - } - memcpy(bd->data, data, len); + StreamingBufferAppend(body->sb, &bd->sbseg, data, len); body->first = body->last = bd; @@ -105,29 +107,19 @@ int HtpBodyAppendChunk(HtpBody *body, const uint8_t *data, uint32_t len) if (bd == NULL) goto error; - bd->len = len; - bd->stream_offset = body->content_len_so_far; - - bd->data = HTPCalloc(1, len); - if (bd->data == NULL) { - goto error; - } - memcpy(bd->data, data, len); + StreamingBufferAppend(body->sb, &bd->sbseg, data, len); body->last->next = bd; body->last = bd; body->content_len_so_far += len; } - SCLogDebug("Body %p; data %p, len %"PRIu32, body, bd->data, (uint32_t)bd->len); + SCLogDebug("body %p", body); SCReturnInt(0); error: if (bd != NULL) { - if (bd->data != NULL) { - HTPFree(bd->data, bd->len); - } HTPFree(bd, sizeof(HtpBodyChunk)); } SCReturnInt(-1); @@ -150,9 +142,12 @@ void HtpBodyPrint(HtpBody *body) SCLogDebug("--- Start body chunks at %p ---", body); printf("--- Start body chunks at %p ---\n", body); for (cur = body->first; cur != NULL; cur = cur->next) { - SCLogDebug("Body %p; data %p, len %"PRIu32, body, cur->data, (uint32_t)cur->len); - printf("Body %p; data %p, len %"PRIu32"\n", body, cur->data, (uint32_t)cur->len); - PrintRawDataFp(stdout, (uint8_t*)cur->data, cur->len); + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(body->sb, &cur->sbseg, &data, &data_len); + SCLogDebug("Body %p; data %p, len %"PRIu32, body, data, data_len); + printf("Body %p; data %p, len %"PRIu32"\n", body, data, data_len); + PrintRawDataFp(stdout, data, data_len); } SCLogDebug("--- End body chunks at %p ---", body); } @@ -170,8 +165,7 @@ void HtpBodyFree(HtpBody *body) if (body->first == NULL) return; - SCLogDebug("Removing chunks of Body %p; data %p, len %"PRIu32, body, - body->last->data, (uint32_t)body->last->len); + SCLogDebug("removing chunks of body %p", body); HtpBodyChunk *cur = NULL; HtpBodyChunk *prev = NULL; @@ -179,12 +173,12 @@ void HtpBodyFree(HtpBody *body) prev = body->first; while (prev != NULL) { cur = prev->next; - if (prev->data != NULL) - HTPFree(prev->data, prev->len); HTPFree(prev, sizeof(HtpBodyChunk)); prev = cur; } body->first = body->last = NULL; + + StreamingBufferFree(body->sb); } /** @@ -230,24 +224,26 @@ void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) SCReturn; } - SCLogDebug("Pruning chunks of Body %p; data %p, len %"PRIu32, body, - body->last->data, (uint32_t)body->last->len); + uint64_t left_edge = body->body_inspected; + if (left_edge <= min_size || left_edge <= window) + left_edge = 0; + if (left_edge) + left_edge -= window; + + if (left_edge) { + SCLogDebug("sliding body to offset %"PRIu64, left_edge); + StreamingBufferSlideToOffset(body->sb, left_edge); + } + + SCLogDebug("pruning chunks of body %p", body); HtpBodyChunk *cur = body->first; while (cur != NULL) { HtpBodyChunk *next = cur->next; + SCLogDebug("cur %p", cur); - SCLogDebug("cur->stream_offset %"PRIu64" + cur->len %u = %"PRIu64", " - "body->body_parsed %"PRIu64, cur->stream_offset, cur->len, - cur->stream_offset + cur->len, body->body_parsed); - - uint64_t left_edge = body->body_inspected; - if (left_edge <= min_size || left_edge <= window) - left_edge = 0; - if (left_edge) - left_edge -= window; - - if (cur->stream_offset + cur->len > left_edge) { + if (!StreamingBufferSegmentIsBeforeWindow(body->sb, &cur->sbseg)) { + SCLogDebug("not removed"); break; } @@ -256,12 +252,10 @@ void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) body->last = next; } - if (cur->data != NULL) { - HTPFree(cur->data, cur->len); - } HTPFree(cur, sizeof(HtpBodyChunk)); cur = next; + SCLogDebug("removed"); } SCReturn; diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index 9e68f097085c..33b747f13e95 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -629,8 +629,11 @@ static int HTPFileParserTest03(void) goto end; } - if (http_state->files_ts->head->chunks_head->len != 11) { - printf("filedata len not 11 but %u: ", http_state->files_ts->head->chunks_head->len); + if (http_state->files_ts->head->chunks_head == NULL || + http_state->files_ts->head->chunks_head->len != 11) + { + if (http_state->files_ts->head->chunks_head != NULL) + printf("filedata len not 11 but %u: ", http_state->files_ts->head->chunks_head->len); goto end; } diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 45c14d7d81fe..f8069c757b7b 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1170,60 +1170,11 @@ static void HtpRequestBodyMultipartParseHeader(HtpState *hstate, * \param chunks_buffer_len pointer to pass back the buffer length to the caller */ static void HtpRequestBodyReassemble(HtpTxUserData *htud, - uint8_t **chunks_buffer, uint32_t *chunks_buffer_len) + const uint8_t **chunks_buffer, uint32_t *chunks_buffer_len) { - uint8_t *buf = NULL; - uint8_t *pbuf = NULL; - uint32_t buf_len = 0; - HtpBodyChunk *cur = htud->request_body.first; - - for ( ; cur != NULL; cur = cur->next) { - SCLogDebug("chunk %p", cur); - - /* skip body chunks entirely before what we parsed already */ - if ((uint64_t )cur->stream_offset + cur->len <= htud->request_body.body_parsed) { - SCLogDebug("skipping chunk"); - continue; - } - - SCLogDebug("cur->stream_offset %"PRIu64", cur->len %"PRIu32", body_parsed %"PRIu64, - cur->stream_offset, cur->len, htud->request_body.body_parsed); - - if (cur->stream_offset < htud->request_body.body_parsed && - cur->stream_offset + cur->len >= htud->request_body.body_parsed) { - SCLogDebug("use part"); - - uint32_t toff = htud->request_body.body_parsed - cur->stream_offset; - uint32_t tlen = (cur->stream_offset + cur->len) - htud->request_body.body_parsed; - uint8_t *pbuf = NULL; - - buf_len += tlen; - if ((pbuf = HTPRealloc(buf, buf_len - tlen, buf_len)) == NULL) { - HTPFree(buf, buf_len - tlen); - buf = NULL; - buf_len = 0; - break; - } - buf = pbuf; - memcpy(buf + buf_len - tlen, cur->data + toff, tlen); - - } else { - SCLogDebug("use entire chunk"); - - buf_len += cur->len; - if ((pbuf = HTPRealloc(buf, buf_len - cur->len, buf_len)) == NULL) { - HTPFree(buf, buf_len - cur->len); - buf = NULL; - buf_len = 0; - break; - } - buf = pbuf; - memcpy(buf + buf_len - cur->len, cur->data, cur->len); - } - } - - *chunks_buffer = buf; - *chunks_buffer_len = buf_len; + StreamingBufferGetDataAtOffset(htud->request_body.sb, + chunks_buffer, chunks_buffer_len, + htud->request_body.body_parsed); } static void FlagDetectStateNewFile(HtpTxUserData *tx, int dir) @@ -1249,8 +1200,8 @@ static void HtpRequestBodySetupBoundary(HtpTxUserData *htud, memcpy(boundary + 2, htud->boundary, htud->boundary_len); } -int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, - void *tx, uint8_t *chunks_buffer, uint32_t chunks_buffer_len) +int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, void *tx, + const uint8_t *chunks_buffer, uint32_t chunks_buffer_len) { int result = 0; uint8_t boundary[htud->boundary_len + 4]; /**< size limited to HTP_BOUNDARY_MAX + 4 */ @@ -1288,7 +1239,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, if (header_start != NULL || form_end != NULL || (tx_progress > HTP_REQUEST_BODY)) { SCLogDebug("reached the end of the file"); - uint8_t *filedata = chunks_buffer; + const uint8_t *filedata = chunks_buffer; uint32_t filedata_len = 0; uint8_t flags = 0; @@ -1328,7 +1279,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, SCLogDebug("not yet at the end of the file"); if (chunks_buffer_len > expected_boundary_end_len) { - uint8_t *filedata = chunks_buffer; + const uint8_t *filedata = chunks_buffer; uint32_t filedata_len = chunks_buffer_len - expected_boundary_len; #ifdef PRINT printf("FILEDATA (part) START: \n"); @@ -1816,7 +1767,7 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) HtpBodyAppendChunk(&tx_ud->request_body, d->data, len); - uint8_t *chunks_buffer = NULL; + const uint8_t *chunks_buffer = NULL; uint32_t chunks_buffer_len = 0; if (tx_ud->request_body_type == HTP_BODY_REQUEST_MULTIPART) { @@ -1837,9 +1788,6 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) HtpRequestBodyHandleMultipart(hstate, tx_ud, d->tx, chunks_buffer, chunks_buffer_len); - if (chunks_buffer != NULL) { - HTPFree(chunks_buffer, chunks_buffer_len); - } } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_POST) { HtpRequestBodyHandlePOST(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_PUT) { @@ -2189,6 +2137,10 @@ static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec) #endif cfg_prec->randomize_range = HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE; + cfg_prec->sbcfg.flags = 0; + cfg_prec->sbcfg.buf_size = cfg_prec->request_inspect_window; + cfg_prec->sbcfg.buf_slide = 0; + htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData); htp_config_register_request_trailer_data(cfg_prec->cfg, HTPCallbackRequestHeaderData); htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData); @@ -5666,7 +5618,7 @@ static int HTPBodyReassemblyTest01(void) r = HtpBodyAppendChunk(&htud.request_body, chunk2, sizeof(chunk2)-1); BUG_ON(r != 0); - uint8_t *chunks_buffer = NULL; + const uint8_t *chunks_buffer = NULL; uint32_t chunks_buffer_len = 0; HtpRequestBodyReassemble(&htud, &chunks_buffer, &chunks_buffer_len); diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index d7aab9399372..3c7ae66cbf17 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -37,6 +37,7 @@ #include "util-file.h" #include "app-layer-htp-mem.h" #include "detect-engine-state.h" +#include "util-streaming-buffer.h" #include @@ -158,14 +159,14 @@ typedef struct HTPCfgRec_ { int randomize; int randomize_range; int http_body_inline; + + StreamingBufferConfig sbcfg; } HTPCfgRec; /** Struct used to hold chunks of a body on a request */ struct HtpBodyChunk_ { - uint8_t *data; /**< Pointer to the data of the chunk */ struct HtpBodyChunk_ *next; /**< Pointer to the next chunk */ - uint64_t stream_offset; - uint32_t len; /**< Length of the chunk */ + StreamingBufferSegment sbseg; int logged; } __attribute__((__packed__)); typedef struct HtpBodyChunk_ HtpBodyChunk; @@ -175,6 +176,8 @@ typedef struct HtpBody_ { HtpBodyChunk *first; /**< Pointer to the first chunk */ HtpBodyChunk *last; /**< Pointer to the last chunk */ + StreamingBuffer *sb; + /* Holds the length of the htp request body seen so far */ uint64_t content_len_so_far; /* parser tracker */ diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 5fc48c5fc057..1b4b1534a3d1 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -97,7 +97,7 @@ static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) /** */ -static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, +static const uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, @@ -106,7 +106,7 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, uint32_t *stream_start_offset) { int index = 0; - uint8_t *buffer = NULL; + const uint8_t *buffer = NULL; *buffer_len = 0; *stream_start_offset = 0; @@ -170,49 +170,12 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, goto end; } - int first = 1; - while (cur != NULL) { - /* see if we can filter out chunks */ - if (htud->request_body.body_inspected > 0) { - if (cur->stream_offset < htud->request_body.body_inspected) { - if ((htud->request_body.body_inspected - cur->stream_offset) > htp_state->cfg->request_inspect_min_size) { - cur = cur->next; - continue; - } else { - /* include this one */ - } - } else { - /* include this one */ - } - } - - if (first) { - det_ctx->hcbd[index].offset = cur->stream_offset; - first = 0; - } - - /* see if we need to grow the buffer */ - if (det_ctx->hcbd[index].buffer == NULL || (det_ctx->hcbd[index].buffer_len + cur->len) > det_ctx->hcbd[index].buffer_size) { - void *ptmp; - det_ctx->hcbd[index].buffer_size += cur->len * 2; - - if ((ptmp = SCRealloc(det_ctx->hcbd[index].buffer, det_ctx->hcbd[index].buffer_size)) == NULL) { - SCFree(det_ctx->hcbd[index].buffer); - det_ctx->hcbd[index].buffer = NULL; - det_ctx->hcbd[index].buffer_size = 0; - det_ctx->hcbd[index].buffer_len = 0; - goto end; - } - det_ctx->hcbd[index].buffer = ptmp; - } - memcpy(det_ctx->hcbd[index].buffer + det_ctx->hcbd[index].buffer_len, cur->data, cur->len); - det_ctx->hcbd[index].buffer_len += cur->len; - - cur = cur->next; - } + StreamingBufferGetData(htud->request_body.sb, + &det_ctx->hcbd[index].buffer, &det_ctx->hcbd[index].buffer_len, + &det_ctx->hcbd[index].offset); /* update inspected tracker */ - htud->request_body.body_inspected = htud->request_body.last->stream_offset + htud->request_body.last->len; + htud->request_body.body_inspected = htud->request_body.last->sbseg.stream_offset + htud->request_body.last->sbseg.segment_len; buffer = det_ctx->hcbd[index].buffer; *buffer_len = det_ctx->hcbd[index].buffer_len; @@ -258,7 +221,7 @@ int DetectEngineRunHttpClientBodyMpm(DetectEngineCtx *de_ctx, uint32_t cnt = 0; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, idx, + const uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, idx, de_ctx, det_ctx, f, htp_state, flags, @@ -267,7 +230,7 @@ int DetectEngineRunHttpClientBodyMpm(DetectEngineCtx *de_ctx, if (buffer_len == 0) goto end; - cnt = HttpClientBodyPatternSearch(det_ctx, buffer, buffer_len, flags); + cnt = HttpClientBodyPatternSearch(det_ctx, (uint8_t *)buffer, buffer_len, flags); end: return cnt; @@ -282,7 +245,7 @@ int DetectEngineInspectHttpClientBody(ThreadVars *tv, HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, tx_id, + const uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, tx_id, de_ctx, det_ctx, f, htp_state, flags, @@ -296,7 +259,7 @@ int DetectEngineInspectHttpClientBody(ThreadVars *tv, det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HCBDMATCH], f, - buffer, + (uint8_t *)buffer, buffer_len, stream_start_offset, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCBD, NULL); diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 48648e3f4e3b..3918c6e094c3 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -96,134 +96,7 @@ static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) return 0; } -static void HSBDGetBufferForTXInIDSMode(DetectEngineThreadCtx *det_ctx, - HtpState *htp_state, HtpBodyChunk *cur, - HtpTxUserData *htud, int index) -{ - int first = 1; - while (cur != NULL) { - /* see if we can filter out chunks */ - if (htud->response_body.body_inspected > 0) { - if (cur->stream_offset < htud->response_body.body_inspected) { - if ((htud->response_body.body_inspected - cur->stream_offset) > htp_state->cfg->response_inspect_window) { - cur = cur->next; - continue; - } else { - /* include this one */ - } - } else { - /* include this one */ - } - } - - if (first) { - det_ctx->hsbd[index].offset = cur->stream_offset; - first = 0; - } - - /* see if we need to grow the buffer */ - if (det_ctx->hsbd[index].buffer == NULL || (det_ctx->hsbd[index].buffer_len + cur->len) > det_ctx->hsbd[index].buffer_size) { - void *ptmp; - uint32_t newsize = det_ctx->hsbd[index].buffer_size + (cur->len * 2); - - if ((ptmp = HTPRealloc(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size, newsize)) == NULL) { - HTPFree(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size); - det_ctx->hsbd[index].buffer = NULL; - det_ctx->hsbd[index].buffer_size = 0; - det_ctx->hsbd[index].buffer_len = 0; - return; - } - det_ctx->hsbd[index].buffer = ptmp; - det_ctx->hsbd[index].buffer_size = newsize; - } - memcpy(det_ctx->hsbd[index].buffer + det_ctx->hsbd[index].buffer_len, cur->data, cur->len); - det_ctx->hsbd[index].buffer_len += cur->len; - - cur = cur->next; - } - - /* update inspected tracker */ - htud->response_body.body_inspected = htud->response_body.last->stream_offset + htud->response_body.last->len; -} - -#define MAX_WINDOW 10*1024*1024 -static void HSBDGetBufferForTXInIPSMode(DetectEngineThreadCtx *det_ctx, - HtpState *htp_state, HtpBodyChunk *cur, - HtpTxUserData *htud, int index) -{ - uint32_t window_size = 0; - - /* how much from before body_inspected will we consider? */ - uint32_t cfg_win = - htud->response_body.body_inspected >= htp_state->cfg->response_inspect_min_size ? - htp_state->cfg->response_inspect_window : - htp_state->cfg->response_inspect_min_size; - - /* but less if we don't have that much before body_inspected */ - if ((htud->response_body.body_inspected - htud->response_body.first->stream_offset) < cfg_win) { - cfg_win = htud->response_body.body_inspected - htud->response_body.first->stream_offset; - } - window_size = (htud->response_body.content_len_so_far - htud->response_body.body_inspected) + cfg_win; - if (window_size > MAX_WINDOW) { - SCLogDebug("weird: body size is %uk", window_size/1024); - window_size = MAX_WINDOW; - } - - if (det_ctx->hsbd[index].buffer == NULL || window_size > det_ctx->hsbd[index].buffer_size) { - void *ptmp; - - if ((ptmp = HTPRealloc(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size, window_size)) == NULL) { - HTPFree(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size); - det_ctx->hsbd[index].buffer = NULL; - det_ctx->hsbd[index].buffer_size = 0; - det_ctx->hsbd[index].buffer_len = 0; - return; - } - det_ctx->hsbd[index].buffer = ptmp; - det_ctx->hsbd[index].buffer_size = window_size; - } - - uint32_t left_edge = htud->response_body.body_inspected - cfg_win; - - int first = 1; - while (cur != NULL) { - if (first) { - det_ctx->hsbd[index].offset = cur->stream_offset; - first = 0; - } - - /* entirely before our window */ - if ((cur->stream_offset + cur->len) <= left_edge) { - cur = cur->next; - continue; - } else { - uint32_t offset = 0; - if (cur->stream_offset < left_edge && (cur->stream_offset + cur->len) > left_edge) { - offset = left_edge - cur->stream_offset; - BUG_ON(offset > cur->len); - } - - /* unusual: if window isn't big enough, we just give up */ - if (det_ctx->hsbd[index].buffer_len + (cur->len - offset) > window_size) { - htud->response_body.body_inspected = cur->stream_offset; - SCReturn; - } - - BUG_ON(det_ctx->hsbd[index].buffer_len + (cur->len - offset) > window_size); - - memcpy(det_ctx->hsbd[index].buffer + det_ctx->hsbd[index].buffer_len, cur->data + offset, cur->len - offset); - det_ctx->hsbd[index].buffer_len += (cur->len - offset); - det_ctx->hsbd[index].offset -= offset; - } - - cur = cur->next; - } - - /* update inspected tracker to point before the current window */ - htud->response_body.body_inspected = htud->response_body.content_len_so_far; -} - -static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, +static const uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, @@ -232,7 +105,7 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, uint32_t *stream_start_offset) { int index = 0; - uint8_t *buffer = NULL; + const uint8_t *buffer = NULL; *buffer_len = 0; *stream_start_offset = 0; @@ -303,14 +176,25 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, "entire body."); goto end; } - HSBDGetBufferForTXInIDSMode(det_ctx, htp_state, cur, htud, index); + } + + StreamingBufferGetData(htud->response_body.sb, + &det_ctx->hsbd[index].buffer, &det_ctx->hsbd[index].buffer_len, + &det_ctx->hsbd[index].offset); + + /* update inspected tracker */ + if (!htp_state->cfg->http_body_inline) { + htud->response_body.body_inspected = htud->response_body.last->sbseg.stream_offset + + htud->response_body.last->sbseg.segment_len; } else { - HSBDGetBufferForTXInIPSMode(det_ctx, htp_state, cur, htud, index); + htud->response_body.body_inspected = htud->response_body.content_len_so_far; } + SCLogDebug("htud->response_body.body_inspected now: %"PRIu64, htud->response_body.body_inspected); buffer = det_ctx->hsbd[index].buffer; *buffer_len = det_ctx->hsbd[index].buffer_len; *stream_start_offset = det_ctx->hsbd[index].offset; + end: return buffer; } @@ -361,7 +245,7 @@ int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, if (buffer_len == 0) goto end; - cnt = HttpServerBodyPatternSearch(det_ctx, buffer, buffer_len, flags); + cnt = HttpServerBodyPatternSearch(det_ctx, (uint8_t *)buffer, buffer_len, flags); end: return cnt; @@ -377,7 +261,7 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv, HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, tx_id, + const uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, tx_id, de_ctx, det_ctx, f, htp_state, flags, @@ -391,7 +275,7 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv, det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_FILEDATA], f, - buffer, + (uint8_t *)buffer, buffer_len, stream_start_offset, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSBD, NULL); diff --git a/src/detect-engine.c b/src/detect-engine.c index 34f15652023b..f591056848fa 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1687,22 +1687,12 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) /* HSBD */ if (det_ctx->hsbd != NULL) { SCLogDebug("det_ctx hsbd %u", det_ctx->hsbd_buffers_size); - for (i = 0; i < det_ctx->hsbd_buffers_size; i++) { - if (det_ctx->hsbd[i].buffer != NULL) { - HTPFree(det_ctx->hsbd[i].buffer, det_ctx->hsbd[i].buffer_size); - } - } SCFree(det_ctx->hsbd); } /* HSCB */ if (det_ctx->hcbd != NULL) { SCLogDebug("det_ctx hcbd %u", det_ctx->hcbd_buffers_size); - for (i = 0; i < det_ctx->hcbd_buffers_size; i++) { - if (det_ctx->hcbd[i].buffer != NULL) - SCFree(det_ctx->hcbd[i].buffer); - SCLogDebug("det_ctx->hcbd[i].buffer_size %u", det_ctx->hcbd[i].buffer_size); - } SCFree(det_ctx->hcbd); } diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 729629a098ba..2813d4ca995d 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -1641,7 +1641,9 @@ static int DetectHttpClientBodyTest15(void) goto end; } - if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) { + if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, + (uint8_t *)"Body one!!", 10) != 1) + { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } @@ -1654,7 +1656,9 @@ static int DetectHttpClientBodyTest15(void) goto end; } - if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) { + if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, + (uint8_t *)"Body two!!", 10) != 1) + { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } diff --git a/src/detect-pcre.c b/src/detect-pcre.c index b4303744f4a7..72692ee0734a 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -3116,7 +3116,7 @@ static int DetectPcreTxBodyChunksTest01(void) goto end; } - if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) { + if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } @@ -3129,7 +3129,7 @@ static int DetectPcreTxBodyChunksTest01(void) goto end; } - if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) { + if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } @@ -3358,7 +3358,7 @@ static int DetectPcreTxBodyChunksTest02(void) goto end; } - if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) { + if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } @@ -3371,7 +3371,7 @@ static int DetectPcreTxBodyChunksTest02(void) goto end; } - if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) { + if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } diff --git a/src/detect.h b/src/detect.h index 90c650298425..8a57b0816165 100644 --- a/src/detect.h +++ b/src/detect.h @@ -697,7 +697,7 @@ enum { }; typedef struct HttpReassembledBody_ { - uint8_t *buffer; + const 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 */ diff --git a/src/output-streaming.c b/src/output-streaming.c index 4ae7c58c2e5e..234fbee70ebd 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -205,7 +205,7 @@ int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) } uint8_t flags = iflags | OUTPUT_STREAMING_FLAG_TRANSACTION; - if (chunk->stream_offset == 0) + if (chunk->sbseg.stream_offset == 0) flags |= OUTPUT_STREAMING_FLAG_OPEN; /* if we need to close and we're at the last segment in the list * we add the 'close' flag so the logger can close up. */ @@ -213,9 +213,13 @@ int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) flags |= OUTPUT_STREAMING_FLAG_CLOSE; } + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(body->sb, &chunk->sbseg, &data, &data_len); + // invoke Streamer - Streamer(cbdata, f, chunk->data, (uint32_t)chunk->len, tx_id, flags); - //PrintRawDataFp(stdout, chunk->data, chunk->len); + Streamer(cbdata, f, data, data_len, tx_id, flags); + //PrintRawDataFp(stdout, data, data_len); chunk->logged = 1; tx_logged = 1; } diff --git a/src/util-lua-http.c b/src/util-lua-http.c index 3d97b0f640ac..1207f7f9ef3e 100644 --- a/src/util-lua-http.c +++ b/src/util-lua-http.c @@ -285,7 +285,12 @@ static int HttpGetBody(lua_State *luastate, int dir) lua_newtable(luastate); while (chunk != NULL) { lua_pushinteger(luastate, index); - LuaPushStringBuffer(luastate, chunk->data, chunk->len); + + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(body->sb, &chunk->sbseg, &data, &data_len); + LuaPushStringBuffer(luastate, data, data_len); + lua_settable(luastate, -3); chunk = chunk->next; @@ -293,8 +298,8 @@ static int HttpGetBody(lua_State *luastate, int dir) } if (body->first && body->last) { - lua_pushinteger(luastate, body->first->stream_offset); - lua_pushinteger(luastate, body->last->stream_offset + body->last->len); + lua_pushinteger(luastate, body->first->sbseg.stream_offset); + lua_pushinteger(luastate, body->last->sbseg.stream_offset + body->last->sbseg.segment_len); return 3; } else { return 1; From 6fb808fc1aebc1ce4b2d7f601f529395f6d98fe6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 14 Nov 2015 00:14:02 +0100 Subject: [PATCH 1407/2553] http: add per direction config for body parsing The HTPCfgDir structure is meant to contain config for per direction body parsing parameters. This patch stores the streaming API config. --- src/app-layer-htp-body.c | 6 ++++-- src/app-layer-htp-body.h | 2 +- src/app-layer-htp.c | 29 +++++++++++++++++++++-------- src/app-layer-htp.h | 7 ++++++- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index 53194307b4b8..65ce30ad3963 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -75,7 +75,8 @@ static StreamingBufferConfig default_cfg = { * \retval 0 ok * \retval -1 error */ -int HtpBodyAppendChunk(HtpBody *body, const uint8_t *data, uint32_t len) +int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, + const uint8_t *data, uint32_t len) { SCEnter(); @@ -86,7 +87,8 @@ int HtpBodyAppendChunk(HtpBody *body, const uint8_t *data, uint32_t len) } if (body->sb == NULL) { - body->sb = StreamingBufferInit(&default_cfg); + const StreamingBufferConfig *cfg = hcfg ? &hcfg->sbcfg : &default_cfg; + body->sb = StreamingBufferInit(cfg); if (body->sb == NULL) SCReturnInt(-1); } diff --git a/src/app-layer-htp-body.h b/src/app-layer-htp-body.h index e7d051e8545f..637eb07d61d1 100644 --- a/src/app-layer-htp-body.h +++ b/src/app-layer-htp-body.h @@ -28,7 +28,7 @@ #ifndef __APP_LAYER_HTP_BODY_H__ #define __APP_LAYER_HTP_BODY_H__ -int HtpBodyAppendChunk(HtpBody *, const uint8_t *, uint32_t); +int HtpBodyAppendChunk(const HTPCfgDir *, HtpBody *, const uint8_t *, uint32_t); void HtpBodyPrint(HtpBody *); void HtpBodyFree(HtpBody *); void HtpBodyPrune(HtpState *, HtpBody *, int); diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index f8069c757b7b..00d39365de22 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1765,7 +1765,7 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) } SCLogDebug("len %u", len); - HtpBodyAppendChunk(&tx_ud->request_body, d->data, len); + HtpBodyAppendChunk(&hstate->cfg->request, &tx_ud->request_body, d->data, len); const uint8_t *chunks_buffer = NULL; uint32_t chunks_buffer_len = 0; @@ -1861,7 +1861,7 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) } SCLogDebug("len %u", len); - HtpBodyAppendChunk(&tx_ud->response_body, d->data, len); + HtpBodyAppendChunk(&hstate->cfg->response, &tx_ud->response_body, d->data, len); HtpResponseBodyHandle(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); } else { @@ -2137,10 +2137,6 @@ static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec) #endif cfg_prec->randomize_range = HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE; - cfg_prec->sbcfg.flags = 0; - cfg_prec->sbcfg.buf_size = cfg_prec->request_inspect_window; - cfg_prec->sbcfg.buf_slide = 0; - htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData); htp_config_register_request_trailer_data(cfg_prec->cfg, HTPCallbackRequestHeaderData); htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData); @@ -2213,6 +2209,23 @@ static void HTPConfigSetDefaultsPhase2(char *name, HTPCfgRec *cfg_prec) htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine); + cfg_prec->request.sbcfg.flags = 0; + cfg_prec->request.sbcfg.buf_size = cfg_prec->request_inspect_window ? + cfg_prec->request_inspect_window : 256; + cfg_prec->request.sbcfg.buf_slide = 0; + cfg_prec->request.sbcfg.Malloc = HTPMalloc; + cfg_prec->request.sbcfg.Calloc = HTPCalloc; + cfg_prec->request.sbcfg.Realloc = HTPRealloc; + cfg_prec->request.sbcfg.Free = HTPFree; + + cfg_prec->response.sbcfg.flags = 0; + cfg_prec->response.sbcfg.buf_size = cfg_prec->response_inspect_window ? + cfg_prec->response_inspect_window : 256; + cfg_prec->response.sbcfg.buf_slide = 0; + cfg_prec->response.sbcfg.Malloc = HTPMalloc; + cfg_prec->response.sbcfg.Calloc = HTPCalloc; + cfg_prec->response.sbcfg.Realloc = HTPRealloc; + cfg_prec->response.sbcfg.Free = HTPFree; return; } @@ -5613,9 +5626,9 @@ static int HTPBodyReassemblyTest01(void) uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; uint8_t chunk2[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; - int r = HtpBodyAppendChunk(&htud.request_body, chunk1, sizeof(chunk1)-1); + int r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk1, sizeof(chunk1)-1); BUG_ON(r != 0); - r = HtpBodyAppendChunk(&htud.request_body, chunk2, sizeof(chunk2)-1); + r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk2, sizeof(chunk2)-1); BUG_ON(r != 0); const uint8_t *chunks_buffer = NULL; diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 3c7ae66cbf17..039b1cfe8e4a 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -140,6 +140,10 @@ enum { #define HTP_PCRE_HAS_MATCH 0x02 /**< Flag to indicate that the chunks matched on some rule */ +typedef struct HTPCfgDir_ { + StreamingBufferConfig sbcfg; +} HTPCfgDir; + /** Need a linked list in order to keep track of these */ typedef struct HTPCfgRec_ { htp_cfg_t *cfg; @@ -160,7 +164,8 @@ typedef struct HTPCfgRec_ { int randomize_range; int http_body_inline; - StreamingBufferConfig sbcfg; + HTPCfgDir request; + HTPCfgDir response; } HTPCfgRec; /** Struct used to hold chunks of a body on a request */ From 24a2f51569e59b5e9506fe746cb263a5e0e1a460 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 15 Nov 2015 13:20:14 +0100 Subject: [PATCH 1408/2553] http: move body settings into per dir struct --- src/app-layer-htp-body.c | 8 ++--- src/app-layer-htp.c | 76 ++++++++++++++++++++-------------------- src/app-layer-htp.h | 11 ++---- src/detect-engine-hcbd.c | 6 ++-- src/detect-engine-hsbd.c | 14 ++++---- 5 files changed, 55 insertions(+), 60 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index 65ce30ad3963..b4ba2ffbeaf7 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -205,12 +205,12 @@ void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) } /* get the configured inspect sizes. Default to response values */ - uint32_t min_size = state->cfg->response_inspect_min_size; - uint32_t window = state->cfg->response_inspect_window; + uint32_t min_size = state->cfg->response.inspect_min_size; + uint32_t window = state->cfg->response.inspect_window; if (direction == STREAM_TOSERVER) { - min_size = state->cfg->request_inspect_min_size; - window = state->cfg->request_inspect_window; + min_size = state->cfg->request.inspect_min_size; + window = state->cfg->request.inspect_window; } uint64_t max_window = ((min_size > window) ? min_size : window); diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 00d39365de22..b40e2ed9bdb0 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1750,17 +1750,17 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER); SCLogDebug("tx_ud->request_body.content_len_so_far %"PRIu64, tx_ud->request_body.content_len_so_far); - SCLogDebug("hstate->cfg->request_body_limit %u", hstate->cfg->request_body_limit); + SCLogDebug("hstate->cfg->request.body_limit %u", hstate->cfg->request.body_limit); /* within limits, add the body chunk to the state. */ - if (hstate->cfg->request_body_limit == 0 || tx_ud->request_body.content_len_so_far < hstate->cfg->request_body_limit) + if (hstate->cfg->request.body_limit == 0 || tx_ud->request_body.content_len_so_far < hstate->cfg->request.body_limit) { uint32_t len = (uint32_t)d->len; - if (hstate->cfg->request_body_limit > 0 && - (tx_ud->request_body.content_len_so_far + len) > hstate->cfg->request_body_limit) + if (hstate->cfg->request.body_limit > 0 && + (tx_ud->request_body.content_len_so_far + len) > hstate->cfg->request.body_limit) { - len = hstate->cfg->request_body_limit - tx_ud->request_body.content_len_so_far; + len = hstate->cfg->request.body_limit - tx_ud->request_body.content_len_so_far; BUG_ON(len > (uint32_t)d->len); } SCLogDebug("len %u", len); @@ -1846,17 +1846,17 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT); SCLogDebug("tx_ud->response_body.content_len_so_far %"PRIu64, tx_ud->response_body.content_len_so_far); - SCLogDebug("hstate->cfg->response_body_limit %u", hstate->cfg->response_body_limit); + SCLogDebug("hstate->cfg->response.body_limit %u", hstate->cfg->response.body_limit); /* within limits, add the body chunk to the state. */ - if (hstate->cfg->response_body_limit == 0 || tx_ud->response_body.content_len_so_far < hstate->cfg->response_body_limit) + if (hstate->cfg->response.body_limit == 0 || tx_ud->response_body.content_len_so_far < hstate->cfg->response.body_limit) { uint32_t len = (uint32_t)d->len; - if (hstate->cfg->response_body_limit > 0 && - (tx_ud->response_body.content_len_so_far + len) > hstate->cfg->response_body_limit) + if (hstate->cfg->response.body_limit > 0 && + (tx_ud->response_body.content_len_so_far + len) > hstate->cfg->response.body_limit) { - len = hstate->cfg->response_body_limit - tx_ud->response_body.content_len_so_far; + len = hstate->cfg->response.body_limit - tx_ud->response_body.content_len_so_far; BUG_ON(len > (uint32_t)d->len); } SCLogDebug("len %u", len); @@ -2124,12 +2124,12 @@ static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data) static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec) { cfg_prec->uri_include_all = FALSE; - cfg_prec->request_body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT; - cfg_prec->response_body_limit = HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT; - cfg_prec->request_inspect_min_size = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE; - cfg_prec->request_inspect_window = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW; - cfg_prec->response_inspect_min_size = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE; - cfg_prec->response_inspect_window = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW; + cfg_prec->request.body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT; + cfg_prec->response.body_limit = HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT; + cfg_prec->request.inspect_min_size = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE; + cfg_prec->request.inspect_window = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW; + cfg_prec->response.inspect_min_size = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE; + cfg_prec->response.inspect_window = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW; #ifndef AFLFUZZ_NO_RANDOM cfg_prec->randomize = HTP_CONFIG_DEFAULT_RANDOMIZE; #else @@ -2178,40 +2178,40 @@ static void HTPConfigSetDefaultsPhase2(char *name, HTPCfgRec *cfg_prec) if (cfg_prec->randomize) { int rdrange = cfg_prec->randomize_range; - cfg_prec->request_inspect_min_size += - (int) (cfg_prec->request_inspect_min_size * + cfg_prec->request.inspect_min_size += + (int) (cfg_prec->request.inspect_min_size * (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100); - cfg_prec->request_inspect_window += - (int) (cfg_prec->request_inspect_window * + cfg_prec->request.inspect_window += + (int) (cfg_prec->request.inspect_window * (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100); SCLogInfo("'%s' server has 'request-body-minimal-inspect-size' set to" " %d and 'request-body-inspect-window' set to %d after" " randomization.", name, - cfg_prec->request_inspect_min_size, - cfg_prec->request_inspect_window); + cfg_prec->request.inspect_min_size, + cfg_prec->request.inspect_window); - cfg_prec->response_inspect_min_size += - (int) (cfg_prec->response_inspect_min_size * + cfg_prec->response.inspect_min_size += + (int) (cfg_prec->response.inspect_min_size * (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100); - cfg_prec->response_inspect_window += - (int) (cfg_prec->response_inspect_window * + cfg_prec->response.inspect_window += + (int) (cfg_prec->response.inspect_window * (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100); SCLogInfo("'%s' server has 'response-body-minimal-inspect-size' set to" " %d and 'response-body-inspect-window' set to %d after" " randomization.", name, - cfg_prec->response_inspect_min_size, - cfg_prec->response_inspect_window); + cfg_prec->response.inspect_min_size, + cfg_prec->response.inspect_window); } htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine); cfg_prec->request.sbcfg.flags = 0; - cfg_prec->request.sbcfg.buf_size = cfg_prec->request_inspect_window ? - cfg_prec->request_inspect_window : 256; + cfg_prec->request.sbcfg.buf_size = cfg_prec->request.inspect_window ? + cfg_prec->request.inspect_window : 256; cfg_prec->request.sbcfg.buf_slide = 0; cfg_prec->request.sbcfg.Malloc = HTPMalloc; cfg_prec->request.sbcfg.Calloc = HTPCalloc; @@ -2219,8 +2219,8 @@ static void HTPConfigSetDefaultsPhase2(char *name, HTPCfgRec *cfg_prec) cfg_prec->request.sbcfg.Free = HTPFree; cfg_prec->response.sbcfg.flags = 0; - cfg_prec->response.sbcfg.buf_size = cfg_prec->response_inspect_window ? - cfg_prec->response_inspect_window : 256; + cfg_prec->response.sbcfg.buf_size = cfg_prec->response.inspect_window ? + cfg_prec->response.inspect_window : 256; cfg_prec->response.sbcfg.buf_slide = 0; cfg_prec->response.sbcfg.Malloc = HTPMalloc; cfg_prec->response.sbcfg.Calloc = HTPCalloc; @@ -2295,28 +2295,28 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, } else if (strcasecmp("request-body-limit", p->name) == 0 || strcasecmp("request_body_limit", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->request_body_limit) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->request.body_limit) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-limit " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("response-body-limit", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->response_body_limit) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->response.body_limit) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-limit " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->request_inspect_min_size) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_min_size) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-minimal-inspect-size " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("request-body-inspect-window", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->request_inspect_window) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_window) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-inspect-window " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); @@ -2335,14 +2335,14 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, } } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->response_inspect_min_size) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_min_size) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-minimal-inspect-size " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("response-body-inspect-window", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->response_inspect_window) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_window) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-inspect-window " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 039b1cfe8e4a..123609dee289 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -141,6 +141,9 @@ enum { matched on some rule */ typedef struct HTPCfgDir_ { + uint32_t body_limit; + uint32_t inspect_min_size; + uint32_t inspect_window; StreamingBufferConfig sbcfg; } HTPCfgDir; @@ -152,14 +155,6 @@ typedef struct HTPCfgRec_ { int uri_include_all; /**< use all info in uri (bool) */ /** max size of the client body we inspect */ - uint32_t request_body_limit; - uint32_t response_body_limit; - - uint32_t request_inspect_min_size; - uint32_t request_inspect_window; - - uint32_t response_inspect_min_size; - uint32_t response_inspect_window; int randomize; int randomize_range; int http_body_inline; diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 1b4b1534a3d1..deaaa8a14a10 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -159,9 +159,9 @@ static const uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_i /* inspect the body if the transfer is complete or we have hit * our body size limit */ - if ((htp_state->cfg->request_body_limit == 0 || - htud->request_body.content_len_so_far < htp_state->cfg->request_body_limit) && - htud->request_body.content_len_so_far < htp_state->cfg->request_inspect_min_size && + if ((htp_state->cfg->request.body_limit == 0 || + htud->request_body.content_len_so_far < htp_state->cfg->request.body_limit) && + htud->request_body.content_len_so_far < htp_state->cfg->request.inspect_min_size && !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY) && !(flags & STREAM_EOF)) { SCLogDebug("we still haven't seen the entire request body. " diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 3918c6e094c3..8ef2c17a5aa7 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -155,20 +155,20 @@ static const uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_i goto end; } - SCLogDebug("response_body_limit %u response_body.content_len_so_far %"PRIu64 - ", response_inspect_min_size %"PRIu32", EOF %s, progress > body? %s", - htp_state->cfg->response_body_limit, + SCLogDebug("response.body_limit %u response_body.content_len_so_far %"PRIu64 + ", response.inspect_min_size %"PRIu32", EOF %s, progress > body? %s", + htp_state->cfg->response.body_limit, htud->response_body.content_len_so_far, - htp_state->cfg->response_inspect_min_size, + htp_state->cfg->response.inspect_min_size, flags & STREAM_EOF ? "true" : "false", (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY) ? "true" : "false"); if (!htp_state->cfg->http_body_inline) { /* inspect the body if the transfer is complete or we have hit * our body size limit */ - if ((htp_state->cfg->response_body_limit == 0 || - htud->response_body.content_len_so_far < htp_state->cfg->response_body_limit) && - htud->response_body.content_len_so_far < htp_state->cfg->response_inspect_min_size && + if ((htp_state->cfg->response.body_limit == 0 || + htud->response_body.content_len_so_far < htp_state->cfg->response.body_limit) && + htud->response_body.content_len_so_far < htp_state->cfg->response.inspect_min_size && !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY) && !(flags & STREAM_EOF)) { SCLogDebug("we still haven't seen the entire response body. " From feafc838db4cac7002580d8f72e9cf4f742db03c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 15 Nov 2015 13:21:59 +0100 Subject: [PATCH 1409/2553] http: make htpstate cfg ptr const --- src/app-layer-htp.c | 2 +- src/app-layer-htp.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index b40e2ed9bdb0..63c244298830 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2000,7 +2000,7 @@ static int HTPCallbackRequestLine(htp_tx_t *tx) HtpTxUserData *tx_ud; bstr *request_uri_normalized; HtpState *hstate = htp_connp_get_user_data(tx->connp); - HTPCfgRec *cfg = hstate->cfg; + const HTPCfgRec *cfg = hstate->cfg; request_uri_normalized = SCHTPGenerateNormalizedUri(tx, tx->parsed_uri, cfg->uri_include_all); if (request_uri_normalized == NULL) diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 123609dee289..859979fbeb54 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -252,7 +252,7 @@ typedef struct HtpState_ { uint64_t store_tx_id; FileContainer *files_ts; FileContainer *files_tc; - struct HTPCfgRec_ *cfg; + const struct HTPCfgRec_ *cfg; uint16_t flags; uint16_t events; uint16_t htp_messages_offset; /**< offset into conn->messages list */ From e836a750c8d333c5d14b70e9621c8b69b39ad32c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 16 Nov 2015 10:05:56 +0100 Subject: [PATCH 1410/2553] http: improve body inspection Enforce inspect window also in IDS mode. Try always to get at least 'inspect win' worth of data. In case there is more new data, take some of the old data as well to make sure there is always some overlap. This unifies IDS and IPS modes, the only difference left is the start of inspection. IDS waits until min_size is available, IPS starts right away. --- src/detect-engine-hcbd.c | 58 +++++++++++++++++++++++++++---------- src/detect-engine-hsbd.c | 62 ++++++++++++++++++++++++++-------------- 2 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index deaaa8a14a10..fddfaa56d06c 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -157,29 +157,57 @@ static const uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_i goto end; } - /* inspect the body if the transfer is complete or we have hit - * our body size limit */ - if ((htp_state->cfg->request.body_limit == 0 || - htud->request_body.content_len_so_far < htp_state->cfg->request.body_limit) && - htud->request_body.content_len_so_far < htp_state->cfg->request.inspect_min_size && - !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY) && - !(flags & STREAM_EOF)) { - SCLogDebug("we still haven't seen the entire request body. " - "Let's defer body inspection till we see the " - "entire body."); - goto end; + if (!htp_state->cfg->http_body_inline) { + /* inspect the body if the transfer is complete or we have hit + * our body size limit */ + if ((htp_state->cfg->request.body_limit == 0 || + htud->request_body.content_len_so_far < htp_state->cfg->request.body_limit) && + htud->request_body.content_len_so_far < htp_state->cfg->request.inspect_min_size && + !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY) && + !(flags & STREAM_EOF)) { + SCLogDebug("we still haven't seen the entire request body. " + "Let's defer body inspection till we see the " + "entire body."); + goto end; + } + } + + /* get the inspect buffer + * + * make sure that we have at least the configured inspect_win size. + * If we have more, take at least 1/4 of the inspect win size before + * the new data. + */ + uint64_t offset = 0; + if (htud->request_body.body_inspected > htp_state->cfg->request.inspect_min_size) { + BUG_ON(htud->request_body.content_len_so_far < htud->request_body.body_inspected); + uint64_t inspect_win = htud->request_body.content_len_so_far - htud->request_body.body_inspected; + SCLogDebug("inspect_win %u", (uint)inspect_win); + if (inspect_win < htp_state->cfg->request.inspect_window) { + uint64_t inspect_short = htp_state->cfg->request.inspect_window - inspect_win; + if (htud->request_body.body_inspected < inspect_short) + offset = 0; + else + offset = htud->request_body.body_inspected - inspect_short; + } else { + offset = htud->request_body.body_inspected - (htp_state->cfg->request.inspect_window / 4); + } } - StreamingBufferGetData(htud->request_body.sb, + StreamingBufferGetDataAtOffset(htud->request_body.sb, &det_ctx->hcbd[index].buffer, &det_ctx->hcbd[index].buffer_len, - &det_ctx->hcbd[index].offset); + offset); + det_ctx->hcbd[index].offset = offset; - /* update inspected tracker */ - htud->request_body.body_inspected = htud->request_body.last->sbseg.stream_offset + htud->request_body.last->sbseg.segment_len; + /* move inspected tracker to end of the data. HtpBodyPrune will consider + * the window sizes when freeing data */ + htud->request_body.body_inspected = htud->request_body.content_len_so_far; buffer = det_ctx->hcbd[index].buffer; *buffer_len = det_ctx->hcbd[index].buffer_len; *stream_start_offset = det_ctx->hcbd[index].offset; + + SCLogDebug("buffer_len %u (%u)", *buffer_len, (uint)htud->request_body.content_len_so_far); end: return buffer; } diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 8ef2c17a5aa7..bf980bd9bb65 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -178,23 +178,41 @@ static const uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_i } } - StreamingBufferGetData(htud->response_body.sb, + /* get the inspect buffer + * + * make sure that we have at least the configured inspect_win size. + * If we have more, take at least 1/4 of the inspect win size before + * the new data. + */ + uint64_t offset = 0; + if (htud->response_body.body_inspected > htp_state->cfg->response.inspect_min_size) { + BUG_ON(htud->response_body.content_len_so_far < htud->response_body.body_inspected); + uint64_t inspect_win = htud->response_body.content_len_so_far - htud->response_body.body_inspected; + SCLogDebug("inspect_win %u", (uint)inspect_win); + if (inspect_win < htp_state->cfg->response.inspect_window) { + uint64_t inspect_short = htp_state->cfg->response.inspect_window - inspect_win; + if (htud->response_body.body_inspected < inspect_short) + offset = 0; + else + offset = htud->response_body.body_inspected - inspect_short; + } else { + offset = htud->response_body.body_inspected - (htp_state->cfg->response.inspect_window / 4); + } + } + + StreamingBufferGetDataAtOffset(htud->response_body.sb, &det_ctx->hsbd[index].buffer, &det_ctx->hsbd[index].buffer_len, - &det_ctx->hsbd[index].offset); + offset); + det_ctx->hsbd[index].offset = offset; - /* update inspected tracker */ - if (!htp_state->cfg->http_body_inline) { - htud->response_body.body_inspected = htud->response_body.last->sbseg.stream_offset + - htud->response_body.last->sbseg.segment_len; - } else { - htud->response_body.body_inspected = htud->response_body.content_len_so_far; - } + /* move inspected tracker to end of the data. HtpBodyPrune will consider + * the window sizes when freeing data */ + htud->response_body.body_inspected = htud->response_body.content_len_so_far; SCLogDebug("htud->response_body.body_inspected now: %"PRIu64, htud->response_body.body_inspected); buffer = det_ctx->hsbd[index].buffer; *buffer_len = det_ctx->hsbd[index].buffer_len; *stream_start_offset = det_ctx->hsbd[index].offset; - end: return buffer; } @@ -4111,8 +4129,8 @@ libhtp:\n\ default-config:\n\ \n\ http-body-inline: yes\n\ - response-body-minimal-inspect-size: 6\n\ - response-body-inspect-window: 3\n\ + response-body-minimal-inspect-size: 9\n\ + response-body-inspect-window: 12\n\ "; struct TestSteps steps[] = { @@ -4153,8 +4171,8 @@ libhtp:\n\ default-config:\n\ \n\ http-body-inline: yes\n\ - response-body-minimal-inspect-size: 6\n\ - response-body-inspect-window: 3\n\ + response-body-minimal-inspect-size: 9\n\ + response-body-inspect-window: 12\n\ "; struct TestSteps steps[] = { @@ -4189,8 +4207,8 @@ libhtp:\n\ default-config:\n\ \n\ http-body-inline: yes\n\ - response-body-minimal-inspect-size: 6\n\ - response-body-inspect-window: 3\n\ + response-body-minimal-inspect-size: 9\n\ + response-body-inspect-window: 12\n\ "; struct TestSteps steps[] = { @@ -4225,8 +4243,8 @@ libhtp:\n\ default-config:\n\ \n\ http-body-inline: yes\n\ - response-body-minimal-inspect-size: 6\n\ - response-body-inspect-window: 3\n\ + response-body-minimal-inspect-size: 9\n\ + response-body-inspect-window: 12\n\ "; struct TestSteps steps[] = { @@ -4265,8 +4283,8 @@ libhtp:\n\ default-config:\n\ \n\ http-body-inline: yes\n\ - response-body-minimal-inspect-size: 6\n\ - response-body-inspect-window: 3\n\ + response-body-minimal-inspect-size: 8\n\ + response-body-inspect-window: 4\n\ "; struct TestSteps steps[] = { @@ -4305,8 +4323,8 @@ libhtp:\n\ default-config:\n\ \n\ http-body-inline: yes\n\ - response-body-minimal-inspect-size: 6\n\ - response-body-inspect-window: 3\n\ + response-body-minimal-inspect-size: 8\n\ + response-body-inspect-window: 4\n\ "; struct TestSteps steps[] = { From e43ce0a9ecc32fa1e574fc3c9e1bfc246a45bc01 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 Nov 2015 21:21:50 +0100 Subject: [PATCH 1411/2553] file: switch to streaming buffer API Make the file storage use the streaming buffer API. As the individual file chunks were not needed by themselves, this approach uses a chunkless implementation. --- src/app-layer-htp-file.c | 93 ++++-------- src/app-layer-smtp.c | 119 +++++++++------ src/app-layer-smtp.h | 3 + src/detect-engine-file.c | 6 +- src/detect-engine-filedata-smtp.c | 79 +++------- src/detect-engine.c | 5 - src/detect-filemagic.c | 87 +++-------- src/detect-filesize.c | 14 +- src/detect.h | 2 +- src/log-file.c | 2 +- src/log-filestore.c | 11 +- src/output-filedata.c | 94 +++++------- src/output-filedata.h | 2 +- src/output-json-file.c | 2 +- src/util-file.c | 238 +++++++----------------------- src/util-file.h | 33 ++--- src/util-lua-common.c | 2 +- 17 files changed, 279 insertions(+), 513 deletions(-) diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index 33b747f13e95..4dcddf686523 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -83,6 +83,7 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, uint8_t flags = 0; FileContainer *files = NULL; FileContainer *files_opposite = NULL; + const StreamingBufferConfig *sbcfg = NULL; SCLogDebug("data %p data_len %"PRIu32, data, data_len); @@ -120,6 +121,9 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TC)) { flags |= FILE_NOSTORE; } + + sbcfg = &s->cfg->response.sbcfg; + } else { if (s->files_ts == NULL) { s->files_ts = FileContainerAlloc(); @@ -149,6 +153,8 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TS)) { flags |= FILE_NOSTORE; } + + sbcfg = &s->cfg->request.sbcfg; } /* if the previous file is in the same txid, we reset the file part of the @@ -176,7 +182,7 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, } } - if (FileOpenFile(files, filename, filename_len, + if (FileOpenFile(files, sbcfg, filename, filename_len, data, data_len, flags) == NULL) { retval = -1; @@ -629,11 +635,12 @@ static int HTPFileParserTest03(void) goto end; } - if (http_state->files_ts->head->chunks_head == NULL || - http_state->files_ts->head->chunks_head->len != 11) + if (http_state->files_ts->head == NULL || + FileSize(http_state->files_ts->head) != 11) { - if (http_state->files_ts->head->chunks_head != NULL) - printf("filedata len not 11 but %u: ", http_state->files_ts->head->chunks_head->len); + if (http_state->files_ts->head != NULL) + printf("filedata len not 11 but %"PRIu64": ", + FileSize(http_state->files_ts->head)); goto end; } @@ -882,31 +889,18 @@ static int HTPFileParserTest05(void) if (http_state->files_ts->head->next != http_state->files_ts->tail) goto end; - if (http_state->files_ts->head->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->head->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len); - goto end; - } - - if (memcmp("filecontent", http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len) != 0) { + if (StreamingBufferCompareRawData(http_state->files_ts->head->sb, + (uint8_t *)"filecontent", 11) != 1) + { goto end; } - if (http_state->files_ts->tail->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->tail->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->tail->chunks_head->data, - http_state->files_ts->tail->chunks_head->len); + if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb, + (uint8_t *)"FILECONTENT", 11) != 1) + { goto end; } - if (memcmp("FILECONTENT", http_state->files_ts->tail->chunks_head->data, - http_state->files_ts->tail->chunks_head->len) != 0) { - goto end; - } result = 1; end: if (alp_tctx != NULL) @@ -1007,31 +1001,18 @@ static int HTPFileParserTest06(void) if (http_state->files_ts->head->next != http_state->files_ts->tail) goto end; - if (http_state->files_ts->head->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->head->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len); - goto end; - } - - if (memcmp("filecontent", http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len) != 0) { + if (StreamingBufferCompareRawData(http_state->files_ts->head->sb, + (uint8_t *)"filecontent", 11) != 1) + { goto end; } - if (http_state->files_ts->tail->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->tail->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->tail->chunks_head->data, - http_state->files_ts->tail->chunks_head->len); + if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb, + (uint8_t *)"FILECONTENT", 11) != 1) + { goto end; } - if (memcmp("FILECONTENT", http_state->files_ts->tail->chunks_head->data, - http_state->files_ts->tail->chunks_head->len) != 0) { - goto end; - } result = 1; end: if (alp_tctx != NULL) @@ -1116,16 +1097,9 @@ static int HTPFileParserTest07(void) goto end; } - if (http_state->files_ts->head->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->head->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len); - goto end; - } - - if (memcmp("FILECONTENT", http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len) != 0) { + if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb, + (uint8_t *)"FILECONTENT", 11) != 1) + { goto end; } @@ -1594,16 +1568,9 @@ static int HTPFileParserTest11(void) goto end; } - if (http_state->files_ts->head->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->head->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len); - goto end; - } - - if (memcmp("FILECONTENT", http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len) != 0) { + if (StreamingBufferCompareRawData(http_state->files_ts->head->sb, + (uint8_t *)"FILECONTENT", 11) != 1) + { goto end; } diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 5f89aea0344c..3f80d3e37a00 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -225,7 +225,7 @@ SCEnumCharMap smtp_reply_map[ ] = { }; /* Create SMTP config structure */ -SMTPConfig smtp_config = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 0}; +SMTPConfig smtp_config = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 0, STREAMING_BUFFER_CONFIG_INITIALIZER}; static SMTPString *SMTPStringAlloc(void); @@ -319,6 +319,8 @@ static void SMTPConfigure(void) { } } + smtp_config.sbcfg.buf_size = content_limit ? content_limit : 256; + SCReturn; } @@ -360,23 +362,21 @@ static void SMTPPruneFiles(FileContainer *files) File *file = files->head; while (file) { - SCLogDebug("file %p, file->chunks_head %p", file, file->chunks_head); - if (file->chunks_head) { - uint32_t window = smtp_config.content_inspect_window; - if (file->chunks_head->stream_offset == 0) - window = MAX(window, smtp_config.content_inspect_min_size); - - uint64_t file_size = file->content_len_so_far; - uint64_t data_size = file_size - file->chunks_head->stream_offset; - - SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64, - window, file_size, data_size); - - if (data_size > (window * 3)) { - uint64_t left_edge = file_size - window; - SCLogDebug("file->content_inspected now %"PRIu64, left_edge); - file->content_inspected = left_edge; - } + SCLogDebug("file %p", file); + uint32_t window = smtp_config.content_inspect_window; + if (file->sb->stream_offset == 0) + window = MAX(window, smtp_config.content_inspect_min_size); + + uint64_t file_size = FileSize(file); + uint64_t data_size = file_size - file->sb->stream_offset; + + SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64, + window, file_size, data_size); + + if (data_size > (window * 3)) { + uint64_t left_edge = left_edge = file_size - window; + SCLogDebug("file->content_inspected now %"PRIu64, left_edge); + file->content_inspected = left_edge; } file = file->next; @@ -451,7 +451,7 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, flags |= FILE_STORE; } - if (FileOpenFile(files, (uint8_t *) entity->filename, entity->filename_len, + if (FileOpenFile(files, &smtp_config.sbcfg, (uint8_t *) entity->filename, entity->filename_len, (uint8_t *) chunk, len, flags|FILE_USE_DETECT) == NULL) { ret = MIME_DEC_ERR_DATA; SCLogDebug("FileOpenFile() failed"); @@ -1681,10 +1681,21 @@ void RegisterSMTPParsers(void) #ifdef UNITTESTS +static void SMTPTestInitConfig(void) +{ + MimeDecSetConfig(&smtp_config.mime_config); + + smtp_config.content_limit = FILEDATA_CONTENT_LIMIT; + smtp_config.content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; + smtp_config.content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; + + smtp_config.sbcfg.buf_size = FILEDATA_CONTENT_INSPECT_WINDOW; +} + /* * \test Test STARTTLS. */ -int SMTPParserTest01(void) +static int SMTPParserTest01(void) { int result = 0; Flow f; @@ -1760,6 +1771,7 @@ int SMTPParserTest01(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, @@ -1873,7 +1885,7 @@ int SMTPParserTest01(void) /** * \test Test multiple DATA commands(full mail transactions). */ -int SMTPParserTest02(void) +static int SMTPParserTest02(void) { int result = 0; Flow f; @@ -2118,6 +2130,7 @@ int SMTPParserTest02(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, @@ -2657,7 +2670,7 @@ int SMTPParserTest02(void) /** * \test Testing parsing pipelined commands. */ -int SMTPParserTest03(void) +static int SMTPParserTest03(void) { int result = 0; Flow f; @@ -2752,6 +2765,7 @@ int SMTPParserTest03(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, @@ -2860,7 +2874,7 @@ int SMTPParserTest03(void) /* * \test Test smtp with just delimter instead of . */ -int SMTPParserTest04(void) +static int SMTPParserTest04(void) { int result = 0; Flow f; @@ -2899,6 +2913,7 @@ int SMTPParserTest04(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, @@ -2952,7 +2967,7 @@ int SMTPParserTest04(void) /* * \test Test STARTTLS fail. */ -int SMTPParserTest05(void) +static int SMTPParserTest05(void) { int result = 0; Flow f; @@ -3046,6 +3061,7 @@ int SMTPParserTest05(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, @@ -3193,7 +3209,7 @@ int SMTPParserTest05(void) /** * \test Test multiple DATA commands(full mail transactions). */ -int SMTPParserTest06(void) +static int SMTPParserTest06(void) { int result = 0; Flow f; @@ -3342,6 +3358,7 @@ int SMTPParserTest06(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, @@ -3542,7 +3559,7 @@ int SMTPParserTest06(void) /* * \test Test retrieving lines when frag'ed. */ -int SMTPParserTest07(void) +static int SMTPParserTest07(void) { int result = 0; Flow f; @@ -3580,6 +3597,7 @@ int SMTPParserTest07(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, @@ -3655,7 +3673,7 @@ int SMTPParserTest07(void) /* * \test Test retrieving lines when frag'ed. */ -int SMTPParserTest08(void) +static int SMTPParserTest08(void) { int result = 0; Flow f; @@ -3693,6 +3711,7 @@ int SMTPParserTest08(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, @@ -3768,7 +3787,7 @@ int SMTPParserTest08(void) /* * \test Test retrieving lines when frag'ed. */ -int SMTPParserTest09(void) +static int SMTPParserTest09(void) { int result = 0; Flow f; @@ -3806,6 +3825,7 @@ int SMTPParserTest09(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, @@ -3881,7 +3901,7 @@ int SMTPParserTest09(void) /* * \test Test retrieving lines when frag'ed. */ -int SMTPParserTest10(void) +static int SMTPParserTest10(void) { int result = 0; Flow f; @@ -3919,6 +3939,7 @@ int SMTPParserTest10(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, @@ -3994,7 +4015,7 @@ int SMTPParserTest10(void) /* * \test Test retrieving lines when frag'ed. */ -int SMTPParserTest11(void) +static int SMTPParserTest11(void) { int result = 0; Flow f; @@ -4026,6 +4047,7 @@ int SMTPParserTest11(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, @@ -4079,7 +4101,7 @@ int SMTPParserTest11(void) return result; } -int SMTPParserTest12(void) +static int SMTPParserTest12(void) { int result = 0; Signature *s = NULL; @@ -4124,6 +4146,7 @@ int SMTPParserTest12(void) f.alproto = ALPROTO_SMTP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) @@ -4200,7 +4223,7 @@ int SMTPParserTest12(void) return result; } -int SMTPParserTest13(void) +static int SMTPParserTest13(void) { int result = 0; Signature *s = NULL; @@ -4263,6 +4286,7 @@ int SMTPParserTest13(void) f.alproto = ALPROTO_SMTP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) @@ -4361,7 +4385,7 @@ int SMTPParserTest13(void) /** * \test Test DATA command w/MIME message. */ -int SMTPParserTest14(void) +static int SMTPParserTest14(void) { int result = 0; Flow f; @@ -4541,6 +4565,7 @@ int SMTPParserTest14(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); SCMutexLock(&f.m); /* Welcome reply */ @@ -4788,8 +4813,8 @@ int SMTPParserTest14(void) printf("smtp-mime file name is incorrect"); goto end; } - if(file->size != filesize){ - printf("smtp-mime file size %"PRIu64" is incorrect", file->size); + if (FileSize(file) != filesize){ + printf("smtp-mime file size %"PRIu64" is incorrect", FileSize(file)); goto end; } static uint8_t org_binary[] = { @@ -4810,12 +4835,12 @@ int SMTPParserTest14(void) 0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36, 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36, 0x5C, 0x7A, 0x00, 0x00, 0x38,}; - uint64_t z; - for (z=0; z < filesize; z++){ - if(org_binary[z] != file->chunks_head->data[z]){ - printf("smtp-mime file data incorrect\n"); - goto end; - } + + if (StreamingBufferCompareRawData(file->sb, + org_binary, sizeof(org_binary)) != 1) + { + printf("smtp-mime file data incorrect\n"); + goto end; } } @@ -4883,7 +4908,7 @@ int SMTPParserTest14(void) return result; } -int SMTPProcessDataChunkTest01(void){ +static int SMTPProcessDataChunkTest01(void){ Flow f; FLOW_INITIALIZE(&f); f.flags = FLOW_FILE_NO_STORE_TS; @@ -4895,7 +4920,7 @@ int SMTPProcessDataChunkTest01(void){ } -int SMTPProcessDataChunkTest02(void){ +static int SMTPProcessDataChunkTest02(void){ char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, @@ -4953,7 +4978,7 @@ int SMTPProcessDataChunkTest02(void){ -int SMTPProcessDataChunkTest03(void){ +static int SMTPProcessDataChunkTest03(void){ char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, }; char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, }; char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, }; @@ -5007,7 +5032,7 @@ int SMTPProcessDataChunkTest03(void){ } -int SMTPProcessDataChunkTest04(void){ +static int SMTPProcessDataChunkTest04(void){ char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, }; char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, }; char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, }; @@ -5047,7 +5072,7 @@ int SMTPProcessDataChunkTest04(void){ return ret == 0; } -int SMTPProcessDataChunkTest05(void){ +static int SMTPProcessDataChunkTest05(void){ char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, @@ -5075,7 +5100,7 @@ int SMTPProcessDataChunkTest05(void){ FAIL_IF(file == NULL); ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); FAIL_IF(ret != 0); - FAIL_IF(file->size != 106); + FAIL_IF((uint32_t)FileSize(file) != 106); SMTPStateFree(smtp_state); FLOW_DESTROY(&f); PASS; diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index f36029efe169..1f925c625ed3 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -27,6 +27,7 @@ #include "decode-events.h" #include "util-decode-mime.h" #include "queue.h" +#include "util-streaming-buffer.h" enum { SMTP_DECODER_EVENT_INVALID_REPLY, @@ -94,6 +95,8 @@ typedef struct SMTPConfig { uint32_t content_limit; uint32_t content_inspect_min_size; uint32_t content_inspect_window; + + StreamingBufferConfig sbcfg; } SMTPConfig; typedef struct SMTPState_ { diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index e50b4ce964dd..1afe967d6acd 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -88,6 +88,7 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, File *file = ffc->head; for (; file != NULL; file = file->next) { SCLogDebug("file"); + if (file->state == FILE_STATE_NONE) { SCLogDebug("file state FILE_STATE_NONE"); continue; @@ -109,13 +110,14 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, break; } - if ((s->file_flags & FILE_SIG_NEED_MAGIC) && file->chunks_head == NULL) { + uint64_t file_size = FileSize(file); + if ((s->file_flags & FILE_SIG_NEED_MAGIC) && file_size == 0) { SCLogDebug("sig needs file content, but we don't have any"); r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } - if ((s->file_flags & FILE_SIG_NEED_FILECONTENT) && file->chunks_head == NULL) { + if ((s->file_flags & FILE_SIG_NEED_FILECONTENT) && file_size == 0) { SCLogDebug("sig needs file content, but we don't have any"); r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 64c3ba661ba5..e8bcf7769d39 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -81,7 +81,7 @@ static inline int SMTPCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) return 0; } -static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, +static const uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, File *curr_file, @@ -91,10 +91,10 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, { SCEnter(); int index = 0; - uint8_t *buffer = NULL; + const uint8_t *buffer = NULL; *buffer_len = 0; *stream_start_offset = 0; - FileData *curr_chunk = NULL; + uint64_t file_size = FileSize(curr_file); if (det_ctx->smtp_buffers_list_len == 0) { if (SMTPCreateSpace(det_ctx, 1) < 0) @@ -129,23 +129,21 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, SCLogDebug("smtp_config.content_limit %u, smtp_config.content_inspect_min_size %u", smtp_config.content_limit, smtp_config.content_inspect_min_size); - SCLogDebug("file %p size %"PRIu64", state %d", curr_file, curr_file->content_len_so_far, curr_file->state); + SCLogDebug("file %p size %"PRIu64", state %d", curr_file, file_size, curr_file->state); /* no new data */ - if (curr_file->content_inspected == curr_file->content_len_so_far) { + if (curr_file->content_inspected == file_size) { SCLogDebug("no new data"); goto end; } - curr_chunk = curr_file->chunks_head; - if (curr_chunk == NULL) { - SCLogDebug("no data chunks to inspect for this transaction"); + if (file_size == 0) { + SCLogDebug("no data to inspect for this transaction"); goto end; } - if ((smtp_config.content_limit == 0 || - curr_file->content_len_so_far < smtp_config.content_limit) && - curr_file->content_len_so_far < smtp_config.content_inspect_min_size && + if ((smtp_config.content_limit == 0 || file_size < smtp_config.content_limit) && + file_size < smtp_config.content_inspect_min_size && !(flags & STREAM_EOF) && !(curr_file->state > FILE_STATE_OPENED)) { SCLogDebug("we still haven't seen the entire content. " "Let's defer content inspection till we see the " @@ -153,51 +151,16 @@ static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, goto end; } - int first = 1; - curr_chunk = curr_file->chunks_head; - while (curr_chunk != NULL) { - /* see if we can filter out chunks */ - if (curr_file->content_inspected > 0) { - if (curr_chunk->stream_offset < curr_file->content_inspected) { - if ((curr_file->content_inspected - curr_chunk->stream_offset) > smtp_config.content_inspect_window) { - curr_chunk = curr_chunk->next; - continue; - } else { - /* include this one */ - } - } else { - /* include this one */ - } - } - - if (first) { - det_ctx->smtp[index].offset = curr_chunk->stream_offset; - first = 0; - } + StreamingBufferGetDataAtOffset(curr_file->sb, + &det_ctx->smtp[index].buffer, &det_ctx->smtp[index].buffer_len, + curr_file->content_inspected); - /* see if we need to grow the buffer */ - if (det_ctx->smtp[index].buffer == NULL || (det_ctx->smtp[index].buffer_len + curr_chunk->len) > det_ctx->smtp[index].buffer_size) { - void *ptmp; - det_ctx->smtp[index].buffer_size += curr_chunk->len * 2; - - if ((ptmp = SCRealloc(det_ctx->smtp[index].buffer, det_ctx->smtp[index].buffer_size)) == NULL) { - SCFree(det_ctx->smtp[index].buffer); - det_ctx->smtp[index].buffer = NULL; - det_ctx->smtp[index].buffer_size = 0; - det_ctx->smtp[index].buffer_len = 0; - goto end; - } - det_ctx->smtp[index].buffer = ptmp; - } - memcpy(det_ctx->smtp[index].buffer + det_ctx->smtp[index].buffer_len, curr_chunk->data, curr_chunk->len); - det_ctx->smtp[index].buffer_len += curr_chunk->len; - - curr_chunk = curr_chunk->next; - } + det_ctx->smtp[index].offset = curr_file->content_inspected; /* updat inspected tracker */ - curr_file->content_inspected = curr_file->chunks_tail->stream_offset + curr_file->chunks_tail->len; - SCLogDebug("curr_file->content_inspected now %"PRIu64, curr_file->content_inspected); + curr_file->content_inspected = FileSize(curr_file); + + SCLogDebug("content_inspected %u, offset %u", (uint)curr_file->content_inspected, (uint)det_ctx->smtp[index].offset); buffer = det_ctx->smtp[index].buffer; *buffer_len = det_ctx->smtp[index].buffer_len; @@ -221,7 +184,7 @@ int DetectEngineInspectSMTPFiledata(ThreadVars *tv, int match = 0; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = 0; + const uint8_t *buffer = 0; if (ffc != NULL) { File *file = ffc->head; @@ -240,7 +203,7 @@ int DetectEngineInspectSMTPFiledata(ThreadVars *tv, det_ctx->inspection_recursion_counter = 0; match = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_FILEDATA], f, - buffer, + (uint8_t *)buffer, buffer_len, stream_start_offset, DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, NULL); @@ -309,7 +272,7 @@ int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, uint32_t cnt = 0; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = NULL; + const uint8_t *buffer = NULL; if (ffc != NULL) { File *file = ffc->head; @@ -323,7 +286,7 @@ int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, if (buffer_len == 0) goto end; - cnt += SMTPFiledataPatternSearch(det_ctx, buffer, buffer_len, flags); + cnt += SMTPFiledataPatternSearch(det_ctx, (uint8_t *)buffer, buffer_len, flags); } } end: @@ -410,7 +373,7 @@ static int DetectEngineSMTPFiledataTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, mimemsg, mimemsg_len); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, mimemsg, mimemsg_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %d", r); SCMutexUnlock(&f.m); diff --git a/src/detect-engine.c b/src/detect-engine.c index f591056848fa..a319a0ea329b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1699,11 +1699,6 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) /* SMTP */ if (det_ctx->smtp != NULL) { SCLogDebug("det_ctx smtp %u", det_ctx->smtp_buffers_size); - for (i = 0; i < det_ctx->smtp_buffers_size; i++) { - if (det_ctx->smtp[i].buffer != NULL) - SCFree(det_ctx->smtp[i].buffer); - SCLogDebug("det_ctx->smtp[i].buffer_size %u", det_ctx->smtp[i].buffer_size); - } SCFree(det_ctx->smtp); } diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 0ffabe741d8d..6ca7b6cd43ee 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -90,40 +90,21 @@ void DetectFilemagicRegister(void) */ int FilemagicGlobalLookup(File *file) { - if (file == NULL || file->chunks_head == NULL) { + if (file == NULL || FileSize(file) == 0) { SCReturnInt(-1); } - /* initial chunk already matching our requirement */ - if (file->chunks_head->len >= FILEMAGIC_MIN_SIZE) { - file->magic = MagicGlobalLookup(file->chunks_head->data, FILEMAGIC_MIN_SIZE); - } else { - uint8_t *buf = SCMalloc(FILEMAGIC_MIN_SIZE); - uint32_t size = 0; - - if (likely(buf != NULL)) { - FileData *ffd = file->chunks_head; - - for ( ; ffd != NULL; ffd = ffd->next) { - uint32_t copy_len = ffd->len; - if (size + ffd->len > FILEMAGIC_MIN_SIZE) - copy_len = FILEMAGIC_MIN_SIZE - size; - - memcpy(buf + size, ffd->data, copy_len); - size += copy_len; - - if (size >= FILEMAGIC_MIN_SIZE) { - file->magic = MagicGlobalLookup(buf, size); - break; - } - /* file is done but smaller than FILEMAGIC_MIN_SIZE */ - if (ffd->next == NULL && file->state >= FILE_STATE_CLOSED) { - file->magic = MagicGlobalLookup(buf, size); - break; - } - } - - SCFree(buf); + const uint8_t *data = NULL; + uint32_t data_len = 0; + uint64_t offset = 0; + + StreamingBufferGetData(file->sb, + &data, &data_len, &offset); + if (offset == 0) { + if (FileSize(file) >= FILEMAGIC_MIN_SIZE) { + file->magic = MagicGlobalLookup(data, data_len); + } else if (file->state >= FILE_STATE_CLOSED) { + file->magic = MagicGlobalLookup(data, data_len); } } @@ -140,43 +121,23 @@ int FilemagicGlobalLookup(File *file) */ int FilemagicThreadLookup(magic_t *ctx, File *file) { - if (ctx == NULL || file == NULL || file->chunks_head == NULL) { + if (ctx == NULL || file == NULL || FileSize(file) == 0) { SCReturnInt(-1); } - /* initial chunk already matching our requirement */ - if (file->chunks_head->len >= FILEMAGIC_MIN_SIZE) { - file->magic = MagicThreadLookup(ctx, file->chunks_head->data, FILEMAGIC_MIN_SIZE); - } else { - uint8_t *buf = SCMalloc(FILEMAGIC_MIN_SIZE); - uint32_t size = 0; - - if (likely(buf != NULL)) { - FileData *ffd = file->chunks_head; - - for ( ; ffd != NULL; ffd = ffd->next) { - uint32_t copy_len = ffd->len; - if (size + ffd->len > FILEMAGIC_MIN_SIZE) - copy_len = FILEMAGIC_MIN_SIZE - size; - - memcpy(buf + size, ffd->data, copy_len); - size += copy_len; - - if (size >= FILEMAGIC_MIN_SIZE) { - file->magic = MagicThreadLookup(ctx, buf, size); - break; - } - /* file is done but smaller than FILEMAGIC_MIN_SIZE */ - if (ffd->next == NULL && file->state >= FILE_STATE_CLOSED) { - file->magic = MagicThreadLookup(ctx, buf, size); - break; - } - } - - SCFree(buf); + const uint8_t *data = NULL; + uint32_t data_len = 0; + uint64_t offset = 0; + + StreamingBufferGetData(file->sb, + &data, &data_len, &offset); + if (offset == 0) { + if (FileSize(file) >= FILEMAGIC_MIN_SIZE) { + file->magic = MagicThreadLookup(ctx, data, data_len); + } else if (file->state >= FILE_STATE_CLOSED) { + file->magic = MagicThreadLookup(ctx, data, data_len); } } - SCReturnInt(0); } diff --git a/src/detect-filesize.c b/src/detect-filesize.c index b9a1177af431..92dcfebb9bae 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -94,30 +94,32 @@ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, F DetectFilesizeData *fsd = (DetectFilesizeData *)m->ctx; int ret = 0; - SCLogDebug("file size %"PRIu64", check %"PRIu64, file->size, fsd->size1); + uint64_t file_size = FileSize(file); + + SCLogDebug("file size %"PRIu64", check %"PRIu64, file_size, fsd->size1); if (file->state == FILE_STATE_CLOSED) { switch (fsd->mode) { case DETECT_FILESIZE_EQ: - if (file->size == fsd->size1) + if (file_size == fsd->size1) ret = 1; break; case DETECT_FILESIZE_LT: - if (file->size < fsd->size1) + if (file_size < fsd->size1) ret = 1; break; case DETECT_FILESIZE_GT: - if (file->size > fsd->size1) + if (file_size > fsd->size1) ret = 1; break; case DETECT_FILESIZE_RA: - if (file->size > fsd->size1 && file->size < fsd->size2) + if (file_size > fsd->size1 && file_size < fsd->size2) ret = 1; break; } /* truncated, error: only see if what we have meets the GT condition */ } else if (file->state > FILE_STATE_CLOSED) { - if (fsd->mode == DETECT_FILESIZE_GT && file->size > fsd->size1) + if (fsd->mode == DETECT_FILESIZE_GT && file_size > fsd->size1) ret = 1; } SCReturnInt(ret); diff --git a/src/detect.h b/src/detect.h index 8a57b0816165..4123922fac0b 100644 --- a/src/detect.h +++ b/src/detect.h @@ -704,7 +704,7 @@ typedef struct HttpReassembledBody_ { } HttpReassembledBody; typedef struct FiledataReassembledBody_ { - uint8_t *buffer; + const 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 */ diff --git a/src/log-file.c b/src/log-file.c index d95c4310acb7..402bf936a276 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -303,7 +303,7 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const break; } fprintf(fp, "\"stored\": %s, ", ff->flags & FILE_STORED ? "true" : "false"); - fprintf(fp, "\"size\": %"PRIu64" ", ff->size); + fprintf(fp, "\"size\": %"PRIu64" ", FileSize(ff)); fprintf(fp, "}\n"); fflush(fp); SCMutexUnlock(&aft->file_ctx->fp_mutex); diff --git a/src/log-filestore.c b/src/log-filestore.c index 61a9800f743b..15c7c9a58619 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -273,7 +273,7 @@ static void LogFilestoreLogCloseMetaFile(const File *ff) fprintf(fp, "STATE: UNKNOWN\n"); break; } - fprintf(fp, "SIZE: %"PRIu64"\n", ff->size); + fprintf(fp, "SIZE: %"PRIu64"\n", FileSize(ff)); fclose(fp); } else { @@ -281,7 +281,8 @@ static void LogFilestoreLogCloseMetaFile(const File *ff) } } -static int LogFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet *p, const File *ff, const FileData *ffd, uint8_t flags) +static int LogFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet *p, + const File *ff, const uint8_t *data, uint32_t data_len, uint8_t flags) { SCEnter(); LogFilestoreLogThread *aft = (LogFilestoreLogThread *)thread_data; @@ -302,7 +303,7 @@ static int LogFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet *p return 0; } - SCLogDebug("ff %p, ffd %p", ff, ffd); + SCLogDebug("ff %p, data %p, data_len %u", ff, data, data_len); snprintf(filename, sizeof(filename), "%s/file.%u", g_logfile_base_dir, ff->file_id); @@ -319,7 +320,7 @@ static int LogFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet *p return -1; } /* we can get called with a NULL ffd when we need to close */ - } else if (ffd != NULL) { + } else if (data != NULL) { file_fd = open(filename, O_APPEND | O_NOFOLLOW | O_WRONLY); if (file_fd == -1) { SCLogDebug("failed to open file %s: %s", filename, strerror(errno)); @@ -328,7 +329,7 @@ static int LogFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet *p } if (file_fd != -1) { - ssize_t r = write(file_fd, (const void *)ffd->data, (size_t)ffd->len); + ssize_t r = write(file_fd, (const void *)data, (size_t)data_len); if (r == -1) { SCLogDebug("write failed: %s", strerror(errno)); } diff --git a/src/output-filedata.c b/src/output-filedata.c index 1e19cc9f7ef7..d77e837fd16d 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -92,7 +92,8 @@ int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, Outpu SC_ATOMIC_DECLARE(unsigned int, file_id); static int CallLoggers(ThreadVars *tv, OutputLoggerThreadStore *store_list, - Packet *p, const File *ff, const FileData *ffd, uint8_t flags) + Packet *p, const File *ff, + const uint8_t *data, uint32_t data_len, uint8_t flags) { OutputFiledataLogger *logger = list; OutputLoggerThreadStore *store = store_list; @@ -103,7 +104,7 @@ static int CallLoggers(ThreadVars *tv, OutputLoggerThreadStore *store_list, SCLogDebug("logger %p", logger); PACKET_PROFILING_TMM_START(p, logger->module_id); - logger->LogFunc(tv, store->thread_data, (const Packet *)p, ff, ffd, flags); + logger->LogFunc(tv, store->thread_data, (const Packet *)p, ff, data, data_len, flags); PACKET_PROFILING_TMM_END(p, logger->module_id); file_logged = 1; @@ -172,73 +173,50 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P /* if we have no data chunks left to log, we should still * close the logger(s) */ - if (ff->chunks_head == NULL && (file_trunc || file_close)) { - CallLoggers(tv, store, p, ff, NULL, OUTPUT_FILEDATA_FLAG_CLOSE); + if (FileSize(ff) == ff->content_stored && + (file_trunc || file_close)) { + CallLoggers(tv, store, p, ff, NULL, 0, OUTPUT_FILEDATA_FLAG_CLOSE); ff->flags |= FILE_STORED; continue; } - FileData *ffd; - for (ffd = ff->chunks_head; ffd != NULL; ffd = ffd->next) { - uint8_t flags = 0; - int file_logged = 0; - FileData *write_ffd = ffd; + /* store */ - SCLogDebug("ffd %p", ffd); - - /* special case: on stream end we may inform the - * loggers that the file is truncated. In this - * case we already logged the current ffd, which - * is the last in our list. */ - if (ffd->stored == 1) { - if (!(file_close == 1 && ffd->next == NULL)) { - continue; - } - - // call writer with NULL ffd, so it can 'close' - // so really a 'close' msg - write_ffd = NULL; - flags |= OUTPUT_FILEDATA_FLAG_CLOSE; - SCLogDebug("OUTPUT_FILEDATA_FLAG_CLOSE set"); - } - - /* store */ + /* if file_id == 0, this is the first store of this file */ + if (ff->file_id == 0) { + /* new file */ + ff->file_id = SC_ATOMIC_ADD(file_id, 1); + flags |= OUTPUT_FILEDATA_FLAG_OPEN; + } else { + /* existing file */ + } - /* if file_id == 0, this is the first store of this file */ - if (ff->file_id == 0) { - /* new file */ - ff->file_id = SC_ATOMIC_ADD(file_id, 1); - flags |= OUTPUT_FILEDATA_FLAG_OPEN; - } else { - /* existing file */ - } + /* if file needs to be closed or truncated, inform + * loggers */ + if ((file_close || file_trunc) && ff->state < FILE_STATE_CLOSED) { + ff->state = FILE_STATE_TRUNCATED; + } - /* if file needs to be closed or truncated, inform - * loggers */ - if ((file_close || file_trunc) && ff->state < FILE_STATE_CLOSED) { - ff->state = FILE_STATE_TRUNCATED; - SCLogDebug("ff->state = FILE_STATE_TRUNCATED set"); - } + /* tell the logger we're closing up */ + if (ff->state >= FILE_STATE_CLOSED) + flags |= OUTPUT_FILEDATA_FLAG_CLOSE; - /* for the last data chunk we have, also tell the logger - * we're closing up */ - if (ffd->next == NULL && ff->state >= FILE_STATE_CLOSED) { - flags |= OUTPUT_FILEDATA_FLAG_CLOSE; - SCLogDebug("OUTPUT_FILEDATA_FLAG_CLOSE set"); - } + /* do the actual logging */ + const uint8_t *data = NULL; + uint32_t data_len = 0; - SCLogDebug("ff %p ffd %p flags %02x", ff, write_ffd, flags); - /* do the actual logging */ - file_logged = CallLoggers(tv, store, p, ff, write_ffd, flags); + StreamingBufferGetDataAtOffset(ff->sb, + &data, &data_len, + ff->content_stored); - if (file_logged) { - ffd->stored = 1; + int file_logged = CallLoggers(tv, store, p, ff, data, data_len, flags); + if (file_logged) { + ff->content_stored += data_len; - /* all done */ - if (flags & OUTPUT_FILEDATA_FLAG_CLOSE) { - ff->flags |= FILE_STORED; - break; - } + /* all done */ + if (flags & OUTPUT_FILEDATA_FLAG_CLOSE) { + ff->flags |= FILE_STORED; + break; } } } diff --git a/src/output-filedata.h b/src/output-filedata.h index 8900cd489df6..3a0a5d4341ed 100644 --- a/src/output-filedata.h +++ b/src/output-filedata.h @@ -34,7 +34,7 @@ /** filedata logger function pointer type */ typedef int (*FiledataLogger)(ThreadVars *, void *thread_data, const Packet *, - const File *, const FileData *, uint8_t); + const File *, const uint8_t *, uint32_t, uint8_t); /** packet logger condition function pointer type, * must return true for packets that should be logged diff --git a/src/output-json-file.c b/src/output-json-file.c index 964638ea6132..c4a7f5276bcb 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -151,7 +151,7 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F if (ff->flags & FILE_STORED) { json_object_set_new(fjs, "file_id", json_integer(ff->file_id)); } - json_object_set_new(fjs, "size", json_integer(ff->size)); + json_object_set_new(fjs, "size", json_integer(FileSize(ff))); json_object_set_new(fjs, "tx_id", json_integer(ff->txid)); /* originally just 'file', but due to bug 1127 naming it fileinfo */ diff --git a/src/util-file.c b/src/util-file.c index c9aab3e1266b..3fc7d5ff2309 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -58,7 +58,6 @@ static int g_file_force_tracking = 0; /* prototypes */ static void FileFree(File *); -static void FileDataFree(FileData *); void FileForceFilestoreEnable(void) { @@ -101,61 +100,27 @@ int FileMagicSize(void) return 512; } -static int FileAppendFileDataFilePtr(File *ff, FileData *ffd) -{ - SCEnter(); - - if (ff == NULL) { - SCReturnInt(-1); - } - - if (ff->chunks_tail == NULL) { - ff->chunks_head = ffd; - ff->chunks_tail = ffd; - ff->content_len_so_far = ffd->len; - } else { - ff->chunks_tail->next = ffd; - ff->chunks_tail = ffd; - ff->content_len_so_far += ffd->len; - } - -#ifdef DEBUG - ff->chunks_cnt++; - if (ff->chunks_cnt > ff->chunks_cnt_max) - ff->chunks_cnt_max = ff->chunks_cnt; -#endif - -#ifdef HAVE_NSS - if (ff->md5_ctx) - HASH_Update(ff->md5_ctx, ffd->data, ffd->len); -#endif - SCReturnInt(0); -} - -static int FileAppendFileData(FileContainer *ffc, FileData *ffd) +/** + * \brief get the size of the file + * + * This doesn't reflect how much of the file we have in memory, just the + * total size tracked so far. + */ +uint64_t FileSize(const File *file) { - SCEnter(); - - if (ffc == NULL) { - SCReturnInt(-1); - } - - if (FileAppendFileDataFilePtr(ffc->tail, ffd) == -1) - { - SCReturnInt(-1); + if (file != NULL && file->sb != NULL) { + SCLogDebug("returning %"PRIu64, + file->sb->stream_offset + file->sb->buf_offset); + return file->sb->stream_offset + file->sb->buf_offset; } - - SCReturnInt(0); + SCLogDebug("returning 0 (default)"); + return 0; } - - static int FilePruneFile(File *file) { SCEnter(); - SCLogDebug("file %p, file->chunks_cnt %"PRIu64, file, file->chunks_cnt); - if (!(file->flags & FILE_NOMAGIC)) { /* need magic but haven't set it yet, bail out */ if (file->magic == NULL) @@ -166,37 +131,20 @@ static int FilePruneFile(File *file) SCLogDebug("file->flags & FILE_NOMAGIC == true"); } - /* okay, we now know we can prune */ - FileData *fd = file->chunks_head; - - while (fd != NULL) { - SCLogDebug("fd %p", fd); - - if (file->flags & FILE_NOSTORE || fd->stored == 1) { - /* keep chunks in memory as long as we still need to - * inspect them or parts of them */ - if (file->flags & FILE_USE_DETECT) { - uint64_t right_edge = fd->stream_offset + fd->len; - if (file->content_inspected < right_edge) - break; - } - - file->chunks_head = fd->next; - if (file->chunks_tail == fd) - file->chunks_tail = fd->next; + uint64_t left_edge = file->content_stored; + if (file->flags & FILE_NOSTORE) { + left_edge = FileSize(file); + } + if (file->flags & FILE_USE_DETECT) { + left_edge = MIN(left_edge, file->content_inspected); + } - FileDataFree(fd); + if (left_edge) { + StreamingBufferSlideToOffset(file->sb, left_edge); + } - fd = file->chunks_head; -#ifdef DEBUG - file->chunks_cnt--; - SCLogDebug("file->chunks_cnt %"PRIu64, file->chunks_cnt); -#endif - } else if (fd->stored == 0) { - fd = NULL; - SCReturnInt(0); - break; - } + if (left_edge != FileSize(file)) { + SCReturnInt(0); } SCLogDebug("file->state %d. Is >= FILE_STATE_CLOSED: %s", file->state, (file->state >= FILE_STATE_CLOSED) ? "yes" : "no"); @@ -293,56 +241,6 @@ void FileContainerFree(FileContainer *ffc) SCFree(ffc); } -/** - * \internal - * - * \brief allocate a FileData chunk and set it up - * - * \param data data chunk to store in the FileData - * \param data_len lenght of the data - * - * \retval new FileData object - */ -static FileData *FileDataAlloc(const uint8_t *data, uint32_t data_len) -{ - FileData *new = SCMalloc(sizeof(FileData)); - if (unlikely(new == NULL)) { - return NULL; - } - memset(new, 0, sizeof(FileData)); - - new->data = SCMalloc(data_len); - if (new->data == NULL) { - SCFree(new); - return NULL; - } - - new->len = data_len; - memcpy(new->data, data, data_len); - - new->next = NULL; - return new; -} - -/** - * \internal - * - * \brief free a FileData object - * - * \param ffd the flow file data object to free - */ -static void FileDataFree(FileData *ffd) -{ - if (ffd == NULL) - return; - - if (ffd->data != NULL) { - SCFree(ffd->data); - } - - SCFree(ffd); -} - /** * \brief Alloc a new File * @@ -384,22 +282,14 @@ static void FileFree(File *ff) if (ff->magic != NULL) SCFree(ff->magic); - if (ff->chunks_head != NULL) { - FileData *ffd = ff->chunks_head; - - while (ffd != NULL) { - FileData *next_ffd = ffd->next; - FileDataFree(ffd); - ffd = next_ffd; - } + if (ff->sb != NULL) { + StreamingBufferFree(ff->sb); } #ifdef HAVE_NSS if (ff->md5_ctx) HASH_Destroy(ff->md5_ctx); #endif - SCLogDebug("ff chunks_cnt %"PRIu64", chunks_cnt_max %"PRIu64, - ff->chunks_cnt, ff->chunks_cnt_max); SCFree(ff); } @@ -456,7 +346,7 @@ static int FileStoreNoStoreCheck(File *ff) if (ff->flags & FILE_NOSTORE) { if (ff->state == FILE_STATE_OPENED && - ff->size >= (uint64_t)FileMagicSize()) + FileSize(ff) >= (uint64_t)FileMagicSize()) { SCReturnInt(1); } @@ -465,6 +355,18 @@ static int FileStoreNoStoreCheck(File *ff) SCReturnInt(0); } +static int AppendData(File *file, const uint8_t *data, uint32_t data_len) +{ + StreamingBufferAppendNoTrack(file->sb, data, data_len); + +#ifdef HAVE_NSS + if (file->md5_ctx) { + HASH_Update(file->md5_ctx, data, data_len); + } +#endif + SCReturnInt(0); +} + /** * \brief Store a chunk of file data in the flow. The open "flowfile" * will be used. @@ -492,9 +394,6 @@ int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) SCReturnInt(-1); } - ffc->tail->size += data_len; - SCLogDebug("file size is now %"PRIu64, ffc->tail->size); - if (FileStoreNoStoreCheck(ffc->tail) == 1) { #ifdef HAVE_NSS /* no storage but forced md5 */ @@ -515,23 +414,11 @@ int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) SCLogDebug("appending %"PRIu32" bytes", data_len); - FileData *ffd = FileDataAlloc(data, data_len); - if (ffd == NULL) { + if (AppendData(ffc->tail, data, data_len) != 0) { ffc->tail->state = FILE_STATE_ERROR; SCReturnInt(-1); } - if (ffc->tail->chunks_head == NULL) - ffd->stream_offset = 0; - else - ffd->stream_offset = ffc->tail->size; - - /* append the data */ - if (FileAppendFileData(ffc, ffd) < 0) { - ffc->tail->state = FILE_STATE_ERROR; - FileDataFree(ffd); - SCReturnInt(-1); - } SCReturnInt(0); } @@ -539,6 +426,7 @@ int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) * \brief Open a new File * * \param ffc flow container + * \param sbcfg buffer config * \param name filename character array * \param name_len filename len * \param data initial data @@ -549,7 +437,8 @@ int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) * * \note filename is not a string, so it's not nul terminated. */ -File *FileOpenFile(FileContainer *ffc, const uint8_t *name, uint16_t name_len, +File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, + const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, uint16_t flags) { SCEnter(); @@ -561,6 +450,13 @@ File *FileOpenFile(FileContainer *ffc, const uint8_t *name, uint16_t name_len, SCReturnPtr(NULL, "File"); } + ff->sb = StreamingBufferInit(sbcfg); + if (ff->sb == NULL) { + FileFree(ff); + SCReturnPtr(NULL, "File"); + } + SCLogDebug("ff->sb %p", ff->sb); + if (flags & FILE_STORE || g_file_force_filestore) { FileStore(ff); } else if (flags & FILE_NOSTORE) { @@ -595,22 +491,11 @@ File *FileOpenFile(FileContainer *ffc, const uint8_t *name, uint16_t name_len, FileContainerAdd(ffc, ff); if (data != NULL) { - //PrintRawDataFp(stdout, data, data_len); - ff->size += data_len; - SCLogDebug("file size is now %"PRIu64, ff->size); - - FileData *ffd = FileDataAlloc(data, data_len); - if (ffd == NULL) { - ff->state = FILE_STATE_ERROR; - SCReturnPtr(NULL, "File"); - } - - /* append the data */ - if (FileAppendFileData(ffc, ffd) < 0) { + if (AppendData(ff, data, data_len) != 0) { ff->state = FILE_STATE_ERROR; - FileDataFree(ffd); SCReturnPtr(NULL, "File"); } + SCLogDebug("file size is now %"PRIu64, FileSize(ff)); } SCReturnPtr(ff, "File"); @@ -629,12 +514,7 @@ static int FileCloseFilePtr(File *ff, const uint8_t *data, SCReturnInt(-1); } - ff->size += data_len; - SCLogDebug("file size is now %"PRIu64, ff->size); - if (data != NULL) { - //PrintRawDataFp(stdout, data, data_len); - if (ff->flags & FILE_NOSTORE) { #ifdef HAVE_NSS /* no storage but md5 */ @@ -642,16 +522,8 @@ static int FileCloseFilePtr(File *ff, const uint8_t *data, HASH_Update(ff->md5_ctx, data, data_len); #endif } else { - FileData *ffd = FileDataAlloc(data, data_len); - if (ffd == NULL) { - ff->state = FILE_STATE_ERROR; - SCReturnInt(-1); - } - - /* append the data */ - if (FileAppendFileDataFilePtr(ff, ffd) < 0) { + if (AppendData(ff, data, data_len) != 0) { ff->state = FILE_STATE_ERROR; - FileDataFree(ffd); SCReturnInt(-1); } } @@ -858,7 +730,7 @@ void FileDisableStoringForFile(File *ff) SCLogDebug("not storing this file"); ff->flags |= FILE_NOSTORE; - if (ff->state == FILE_STATE_OPENED && ff->size >= (uint64_t)FileMagicSize()) { + if (ff->state == FILE_STATE_OPENED && FileSize(ff) >= (uint64_t)FileMagicSize()) { if (g_file_force_md5 == 0 && g_file_force_tracking == 0) { (void)FileCloseFilePtr(ff, NULL, 0, (FILE_TRUNCATED|FILE_NOSTORE)); diff --git a/src/util-file.h b/src/util-file.h index 9d87b593df09..bdea4702f605 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -29,6 +29,8 @@ #include #endif +#include "util-streaming-buffer.h" + #define FILE_TRUNCATED 0x0001 #define FILE_NOMAGIC 0x0002 #define FILE_NOMD5 0x0004 @@ -51,38 +53,23 @@ typedef enum FileState_ { FILE_STATE_MAX } FileState; -typedef struct FileData_ { - uint8_t *data; - uint32_t len; - uint64_t stream_offset; - int stored; /* true if this chunk has been stored already - * false otherwise */ - struct FileData_ *next; -} FileData; - typedef struct File_ { uint16_t flags; uint16_t name_len; int16_t state; + StreamingBuffer *sb; uint64_t txid; /**< tx this file is part of */ uint32_t file_id; uint8_t *name; - uint64_t size; /**< size tracked so far */ char *magic; - FileData *chunks_head; - FileData *chunks_tail; struct File_ *next; #ifdef HAVE_NSS HASHContext *md5_ctx; uint8_t md5[MD5_LENGTH]; #endif -#ifdef DEBUG - uint64_t chunks_cnt; - uint64_t chunks_cnt_max; -#endif - uint64_t content_len_so_far; uint64_t content_inspected; /**< used in pruning if FILE_USE_DETECT * flag is set */ + uint64_t content_stored; } File; typedef struct FileContainer_ { @@ -101,6 +88,7 @@ void FileContainerAdd(FileContainer *, File *); * \brief Open a new File * * \param ffc flow container + * \param sbcfg buffer config * \param name filename character array * \param name_len filename len * \param data initial data @@ -110,9 +98,16 @@ void FileContainerAdd(FileContainer *, File *); * \retval ff flowfile object * * \note filename is not a string, so it's not nul terminated. + * + * If flags contains the FILE_USE_DETECT bit, the pruning code will + * consider not just the content_stored tracker, but also content_inspected. + * It's the responsibility of the API user to make sure this tracker is + * properly updated. */ -File *FileOpenFile(FileContainer *, const uint8_t *name, uint16_t name_len, +File *FileOpenFile(FileContainer *, const StreamingBufferConfig *, + const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, uint16_t flags); + /** * \brief Close a File * @@ -194,4 +189,6 @@ void FileStoreFileById(FileContainer *fc, uint32_t); void FileTruncateAllOpenFiles(FileContainer *); +uint64_t FileSize(const File *file); + #endif /* __UTIL_FILE_H__ */ diff --git a/src/util-lua-common.c b/src/util-lua-common.c index 0db230910246..d44d5a7c8211 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -624,7 +624,7 @@ static int LuaCallbackFileInfoPushToStackFromFile(lua_State *luastate, const Fil lua_pushnumber(luastate, file->file_id); lua_pushnumber(luastate, file->txid); lua_pushlstring(luastate, (char *)file->name, file->name_len); - lua_pushnumber(luastate, file->size); + lua_pushnumber(luastate, FileSize(file)); lua_pushstring (luastate, file->magic); lua_pushstring(luastate, md5ptr); return 6; From f77bc5195cb7c81214a57f3c0e06993923f82b3a Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Fri, 20 May 2016 13:31:05 +1000 Subject: [PATCH 1412/2553] spm: handle null ptrs in destroy funcs gracefully This will handle minimal DetectEngineCtx structures (used in delayed detect mode) safely, since they don't get SPM global contexts allocated. Also added BUG_ON checks for valid spm_table entries. --- src/util-spm.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/util-spm.c b/src/util-spm.c index 04e7676f5cde..d9cbf3f41bfe 100644 --- a/src/util-spm.c +++ b/src/util-spm.c @@ -108,38 +108,57 @@ void SpmTableSetup(void) SpmGlobalThreadCtx *SpmInitGlobalThreadCtx(uint16_t matcher) { + BUG_ON(spm_table[matcher].InitGlobalThreadCtx == NULL); return spm_table[matcher].InitGlobalThreadCtx(); } void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) { + if (global_thread_ctx == NULL) { + return; + } uint16_t matcher = global_thread_ctx->matcher; spm_table[matcher].DestroyGlobalThreadCtx(global_thread_ctx); } SpmThreadCtx *SpmMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) { + if (global_thread_ctx == NULL) { + return NULL; + } uint16_t matcher = global_thread_ctx->matcher; + BUG_ON(spm_table[matcher].MakeThreadCtx == NULL); return spm_table[matcher].MakeThreadCtx(global_thread_ctx); } void SpmDestroyThreadCtx(SpmThreadCtx *thread_ctx) { + if (thread_ctx == NULL) { + return; + } uint16_t matcher = thread_ctx->matcher; + BUG_ON(spm_table[matcher].DestroyThreadCtx == NULL); spm_table[matcher].DestroyThreadCtx(thread_ctx); } SpmCtx *SpmInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, SpmGlobalThreadCtx *global_thread_ctx) { + BUG_ON(global_thread_ctx == NULL); uint16_t matcher = global_thread_ctx->matcher; + BUG_ON(spm_table[matcher].InitCtx == NULL); return spm_table[matcher].InitCtx(needle, needle_len, nocase, global_thread_ctx); } void SpmDestroyCtx(SpmCtx *ctx) { - spm_table[ctx->matcher].DestroyCtx(ctx); + if (ctx == NULL) { + return; + } + uint16_t matcher = ctx->matcher; + BUG_ON(spm_table[matcher].DestroyCtx == NULL); + spm_table[matcher].DestroyCtx(ctx); } uint8_t *SpmScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, From 5f400785c850887b9e2856f2afbf89dfba7b53e2 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 3 Jan 2013 20:29:54 +0100 Subject: [PATCH 1413/2553] af-packet: avoid test for each packet --- src/source-af-packet.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 942391dd4f02..f9c368a40db2 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1128,9 +1128,16 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) TmSlot *s = (TmSlot *)slot; time_t last_dump = 0; struct timeval current_time; + int (*AFPReadFunc) (AFPThreadVars *); ptv->slot = s->slot_next; + if (ptv->flags & AFP_RING_MODE) { + AFPReadFunc = AFPReadFromRing; + } else { + AFPReadFunc = AFPRead; + } + if (ptv->afp_state == AFP_STATE_DOWN) { /* Wait for our turn, threads before us must have opened the socket */ while (AFPPeersListWaitTurn(ptv->mpeer)) { @@ -1211,12 +1218,7 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) continue; } } else if (r > 0) { - if (ptv->flags & AFP_RING_MODE) { - r = AFPReadFromRing(ptv); - } else { - /* AFPRead will call TmThreadsSlotProcessPkt on read packets */ - r = AFPRead(ptv); - } + r = AFPReadFunc(ptv); switch (r) { case AFP_READ_FAILURE: /* AFPRead in error: best to reset the socket */ From 27adbfa86828d21d06ff9fc3a999270da7bed00e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 1 Apr 2016 08:48:31 +0200 Subject: [PATCH 1414/2553] af-packet: micro optimization --- src/source-af-packet.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index f9c368a40db2..f5cecd48d29e 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1220,6 +1220,14 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) } else if (r > 0) { r = AFPReadFunc(ptv); switch (r) { + case AFP_READ_OK: + /* Trigger one dump of stats every second */ + TimeGet(¤t_time); + if (current_time.tv_sec != last_dump) { + AFPDumpCounters(ptv); + last_dump = current_time.tv_sec; + } + break; case AFP_READ_FAILURE: /* AFPRead in error: best to reset the socket */ SCLogError(SC_ERR_AFP_READ, @@ -1231,14 +1239,6 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) AFPSwitchState(ptv, AFP_STATE_DOWN); SCReturnInt(TM_ECODE_FAILED); break; - case AFP_READ_OK: - /* Trigger one dump of stats every second */ - TimeGet(¤t_time); - if (current_time.tv_sec != last_dump) { - AFPDumpCounters(ptv); - last_dump = current_time.tv_sec; - } - break; case AFP_KERNEL_DROP: AFPDumpCounters(ptv); break; From d094039600ac832325bacb014583cca6a6eaa2f4 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 1 Apr 2016 13:52:24 +0200 Subject: [PATCH 1415/2553] af-packet: remove useless code No need for cooked header in the case of mmap capture. --- src/source-af-packet.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index f5cecd48d29e..ea7f63e1cc2e 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -727,7 +727,6 @@ int AFPReadFromRing(AFPThreadVars *ptv) { Packet *p = NULL; union thdr h; - struct sockaddr_ll *from; uint8_t emergency_flush = 0; int read_pkts = 0; int loop_start = -1; @@ -789,20 +788,11 @@ int AFPReadFromRing(AFPThreadVars *ptv) * function. */ h.h2->tp_status |= TP_STATUS_USER_BUSY; - from = (void *)h.raw + TPACKET_ALIGN(ptv->tp_hdrlen); - ptv->pkts++; ptv->bytes += h.h2->tp_len; p->livedev = ptv->livedev; - - /* add forged header */ - if (ptv->cooked) { - SllHdr * hdrp = (SllHdr *)ptv->data; - /* XXX this is minimalist, but this seems enough */ - hdrp->sll_protocol = from->sll_protocol; - } - p->datalink = ptv->datalink; + if (h.h2->tp_len > h.h2->tp_snaplen) { SCLogDebug("Packet length (%d) > snaplen (%d), truncating", h.h2->tp_len, h.h2->tp_snaplen); From bae1b03cf5ccab79c0d8af896c7c2200688edc00 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 28 Oct 2013 17:19:31 +0100 Subject: [PATCH 1416/2553] af-packet: tpacket_v3 implementation This patch adds a basic implementation of AF_PACKET tpacket v3. It is basic in the way it is only working for 'workers' runnning mode. If not in 'workers' mode there is a fallback to tpacket_v2. Feature is activated via tpacket-v3 option in the af-packet section of Suricata YAML. --- src/runmode-af-packet.c | 12 ++ src/source-af-packet.c | 332 ++++++++++++++++++++++++++++++++++------ src/source-af-packet.h | 1 + suricata.yaml.in | 3 + 4 files changed, 301 insertions(+), 47 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 73bd263e1e35..0397401e37cd 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -222,6 +222,18 @@ void *ParseAFPConfig(const char *iface) aconf->iface); aconf->flags |= AFP_RING_MODE; } + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "tpacket-v3", (int *)&boolval); + if (boolval) { + if (strcasecmp(RunmodeGetActive(), "workers") == 0) { + SCLogInfo("Enabling tpacket v3 capture on iface %s", + aconf->iface); + aconf->flags |= AFP_TPACKET_V3|AFP_RING_MODE; + } else { + SCLogError(SC_ERR_RUNMODE, + "tpacket v3 is only implemented for 'workers' running mode." + " Switching to tpacket v2."); + } + } (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "use-emergency-flush", (int *)&boolval); if (boolval) { SCLogInfo("Enabling ring emergency flush on iface %s", diff --git a/src/source-af-packet.c b/src/source-af-packet.c index ea7f63e1cc2e..6aaf7f2211df 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2014 Open Information Security Foundation +/* Copyright (C) 2011-2016 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 @@ -179,6 +179,7 @@ enum { union thdr { struct tpacket2_hdr *h2; + struct tpacket3_hdr *h3; void *raw; }; @@ -236,10 +237,13 @@ typedef struct AFPThreadVars_ int copy_mode; struct tpacket_req req; + struct tpacket_req3 req3; unsigned int tp_hdrlen; unsigned int ring_buflen; char *ring_buf; char *frame_buf; + struct iovec *rd; + unsigned int frame_offset; int ring_size; @@ -708,6 +712,16 @@ void AFPReleaseDataFromRing(Packet *p) AFPV_CLEANUP(&p->afp_v); } +void AFPReleasePacketV3(Packet *p) +{ + /* Need to be in copy mode and need to detect early release + where Ethernet header could not be set (and pseudo packet) */ + if ((p->afp_v.copy_mode != AFP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) { + AFPWritePacket(p); + } + PacketFreeOrRelease(p); +} + void AFPReleasePacket(Packet *p) { AFPReleaseDataFromRing(p); @@ -882,6 +896,136 @@ int AFPReadFromRing(AFPThreadVars *ptv) SCReturnInt(AFP_READ_OK); } +static inline void AFPFlushBlock(struct tpacket_block_desc *pbd) +{ + pbd->hdr.bh1.block_status = TP_STATUS_KERNEL; +} + +static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc *pbd, struct tpacket3_hdr *ppd) +{ + Packet *p = PacketGetFromQueueOrAlloc(); + if (p == NULL) { + SCReturnInt(AFP_FAILURE); + } + PKT_SET_SRC(p, PKT_SRC_WIRE); + + ptv->pkts++; + ptv->bytes += ppd->tp_len; + p->livedev = ptv->livedev; + p->datalink = ptv->datalink; + + if (ptv->flags & AFP_ZERO_COPY) { + if (PacketSetData(p, (unsigned char*)ppd + ppd->tp_mac, ppd->tp_snaplen) == -1) { + TmqhOutputPacketpool(ptv->tv, p); + SCReturnInt(AFP_FAILURE); + } + p->afp_v.relptr = pbd; + p->ReleasePacket = AFPReleasePacketV3; + p->afp_v.mpeer = ptv->mpeer; + AFPRefSocket(ptv->mpeer); + + p->afp_v.copy_mode = ptv->copy_mode; + if (p->afp_v.copy_mode != AFP_COPY_MODE_NONE) { + p->afp_v.peer = ptv->mpeer->peer; + } else { + p->afp_v.peer = NULL; + } + } else { + if (PacketCopyData(p, (unsigned char*)ppd + ppd->tp_mac, ppd->tp_snaplen) == -1) { + TmqhOutputPacketpool(ptv->tv, p); + SCReturnInt(AFP_FAILURE); + } + } + /* Timestamp */ + p->ts.tv_sec = ppd->tp_sec; + p->ts.tv_usec = ppd->tp_nsec/1000; + SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", + GET_PKT_LEN(p), p, GET_PKT_DATA(p)); + + /* We only check for checksum disable */ + if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { + p->flags |= PKT_IGNORE_CHECKSUM; + } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { + if (ptv->livedev->ignore_checksum) { + p->flags |= PKT_IGNORE_CHECKSUM; + } else if (ChecksumAutoModeCheck(ptv->pkts, + SC_ATOMIC_GET(ptv->livedev->pkts), + SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { + ptv->livedev->ignore_checksum = 1; + p->flags |= PKT_IGNORE_CHECKSUM; + } + } else { + if (ppd->tp_status & TP_STATUS_CSUMNOTREADY) { + p->flags |= PKT_IGNORE_CHECKSUM; + } + } + + if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { + AFPFlushBlock(pbd); + TmqhOutputPacketpool(ptv->tv, p); + SCReturnInt(AFP_FAILURE); + } + + SCReturnInt(AFP_READ_OK); +} + +static inline int AFPWalkBlock(AFPThreadVars *ptv, struct tpacket_block_desc *pbd) +{ + int num_pkts = pbd->hdr.bh1.num_pkts, i; + uint8_t *ppd; + + ppd = (uint8_t *)pbd + pbd->hdr.bh1.offset_to_first_pkt; + for (i = 0; i < num_pkts; ++i) { + AFPParsePacketV3(ptv, pbd, (struct tpacket3_hdr *)ppd); + ppd = ppd + ((struct tpacket3_hdr *)ppd)->tp_next_offset; + } + + SCReturnInt(AFP_READ_OK); +} + +/** + * \brief AF packet read function for ring + * + * This function fills + * From here the packets are picked up by the DecodeAFP thread. + * + * \param user pointer to AFPThreadVars + * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success + */ +int AFPReadFromRingV3(AFPThreadVars *ptv) +{ + struct tpacket_block_desc *pbd; + + /* Loop till we have packets available */ + while (1) { + if (unlikely(suricata_ctl_flags != 0)) { + SCLogInfo("Exiting AFP V3 read loop"); + break; + } + + pbd = (struct tpacket_block_desc *) ptv->rd[ptv->frame_offset].iov_base; + + /* block is not ready to be read */ + if ((pbd->hdr.bh1.block_status & TP_STATUS_USER) == 0) { + SCReturnInt(AFP_READ_OK); + } + + if (unlikely(AFPWalkBlock(ptv, pbd) != AFP_READ_OK)) { + AFPFlushBlock(pbd); + SCReturnInt(AFP_READ_FAILURE); + } + + AFPFlushBlock(pbd); + ptv->frame_offset = (ptv->frame_offset + 1) % ptv->req3.tp_block_nr; + /* return to maintenance task after one loop on the ring */ + if (ptv->frame_offset == 0) { + SCReturnInt(AFP_READ_OK); + } + } + + SCReturnInt(AFP_READ_OK); +} + /** * \brief Reference socket * @@ -995,6 +1139,11 @@ static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv) return 1; } + /* Ignore system for tpacket_v3 */ + if (ptv->flags & AFP_TPACKET_V3) { + return 1; + } + /* Read packet from ring */ h.raw = (((union thdr **)ptv->frame_buf)[ptv->frame_offset]); if (h.raw == NULL) { @@ -1123,7 +1272,11 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) ptv->slot = s->slot_next; if (ptv->flags & AFP_RING_MODE) { - AFPReadFunc = AFPReadFromRing; + if (ptv->flags & AFP_TPACKET_V3) { + AFPReadFunc = AFPReadFromRingV3; + } else { + AFPReadFunc = AFPReadFromRing; + } } else { AFPReadFunc = AFPRead; } @@ -1153,7 +1306,9 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) } if (ptv->afp_state == AFP_STATE_UP) { SCLogDebug("Thread %s using socket %d", tv->name, ptv->socket); - AFPSynchronizeStart(ptv); + if ((ptv->flags & AFP_TPACKET_V3) != 0) { + AFPSynchronizeStart(ptv); + } } fds.fd = ptv->socket; @@ -1367,7 +1522,7 @@ frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + siz ptv->req.tp_block_size = getpagesize() << order; int frames_per_block = ptv->req.tp_block_size / ptv->req.tp_frame_size; if (frames_per_block == 0) { - SCLogInfo("frame size to big"); + SCLogError(SC_ERR_INVALID_VALUE, "Frame size bigger than block size"); return -1; } ptv->req.tp_frame_nr = ptv->ring_size; @@ -1380,6 +1535,45 @@ frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + siz return 1; } +static int AFPComputeRingParamsV3(AFPThreadVars *ptv) +{ + ptv->req3.tp_block_size = getpagesize(); + ptv->req3.tp_frame_size = 2048; + int frames_per_block = 0; + int tp_hdrlen = sizeof(struct tpacket3_hdr); + int snaplen = default_packet_size; + + if (snaplen == 0) { + snaplen = GetIfaceMaxPacketSize(ptv->iface); + if (snaplen <= 0) { + SCLogWarning(SC_ERR_INVALID_VALUE, + "Unable to get MTU, setting snaplen to sane default of 1514"); + snaplen = 1514; + } + } + + ptv->req.tp_frame_size = TPACKET_ALIGN(snaplen +TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); + frames_per_block = ptv->req3.tp_block_size / ptv->req3.tp_frame_size; + + if (frames_per_block == 0) { + SCLogError(SC_ERR_INVALID_VALUE, + "Block size is too small, it should be at least %d", + ptv->req3.tp_frame_size); + return -1; + } + ptv->req3.tp_block_nr = ptv->ring_size / frames_per_block + 1; + /* exact division */ + ptv->req3.tp_frame_nr = ptv->req3.tp_block_nr * frames_per_block; + ptv->req3.tp_retire_blk_tov = 10; /* 10 ms timeout on block */ + ptv->req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH; + SCLogInfo("AF_PACKET V3 RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d (mem: %d)", + ptv->req3.tp_block_size, ptv->req3.tp_block_nr, + ptv->req3.tp_frame_size, ptv->req3.tp_frame_nr, + ptv->req3.tp_block_size * ptv->req3.tp_block_nr + ); + return 1; +} + static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) { int r; @@ -1504,84 +1698,126 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) } if (ptv->flags & AFP_RING_MODE) { - int val = TPACKET_V2; + int val; unsigned int len = sizeof(val); + + if (ptv->flags & AFP_TPACKET_V3) { + val = TPACKET_V3; + } else { + val = TPACKET_V2; + } if (getsockopt(ptv->socket, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { if (errno == ENOPROTOOPT) { - SCLogError(SC_ERR_AFP_CREATE, - "Too old kernel giving up (need 2.6.27 at least)"); + if (ptv->flags & AFP_TPACKET_V3) { + SCLogError(SC_ERR_AFP_CREATE, + "Too old kernel giving up (need 3.2 for TPACKET_V3)"); + } else { + SCLogError(SC_ERR_AFP_CREATE, + "Too old kernel giving up (need 2.6.27 at least)"); + } } SCLogError(SC_ERR_AFP_CREATE, "Error when retrieving packet header len"); goto socket_err; } ptv->tp_hdrlen = val; - val = TPACKET_V2; + if (ptv->flags & AFP_TPACKET_V3) { + val = TPACKET_V3; + } else { + val = TPACKET_V2; + } if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)) < 0) { SCLogError(SC_ERR_AFP_CREATE, - "Can't activate TPACKET_V2 on packet socket: %s", + "Can't activate TPACKET_V2/TPACKET_V3 on packet socket: %s", strerror(errno)); goto socket_err; } /* Allocate RX ring */ -#define DEFAULT_ORDER 3 - for (order = DEFAULT_ORDER; order >= 0; order--) { - if (AFPComputeRingParams(ptv, order) != 1) { + if (ptv->flags & AFP_TPACKET_V3) { + if (AFPComputeRingParamsV3(ptv) != 1) { SCLogInfo("Ring parameter are incorrect. Please correct the devel"); + goto socket_err; } + r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, + (void *) &ptv->req3, sizeof(ptv->req3)); + } else { +#define DEFAULT_ORDER 3 + for (order = DEFAULT_ORDER; order >= 0; order--) { + if (AFPComputeRingParams(ptv, order) != 1) { + SCLogInfo("Ring parameter are incorrect. Please correct the devel"); + goto socket_err; + } - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, (void *) &ptv->req, sizeof(ptv->req)); - if (r < 0) { - if (errno == ENOMEM) { - SCLogInfo("Memory issue with ring parameters. Retrying."); - continue; + r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, + (void *) &ptv->req, sizeof(ptv->req)); + + if (r < 0) { + if (errno == ENOMEM) { + SCLogInfo("Memory issue with ring parameters. Retrying."); + continue; + } + SCLogError(SC_ERR_MEM_ALLOC, + "Unable to allocate RX Ring for iface %s: (%d) %s", + devname, + errno, + strerror(errno)); + goto socket_err; + } else { + break; } + } + if (order < 0) { SCLogError(SC_ERR_MEM_ALLOC, - "Unable to allocate RX Ring for iface %s: (%d) %s", - devname, - errno, - strerror(errno)); + "Unable to allocate RX Ring for iface %s (order 0 failed)", + devname); goto socket_err; - } else { - break; } } - if (order < 0) { - SCLogError(SC_ERR_MEM_ALLOC, - "Unable to allocate RX Ring for iface %s (order 0 failed)", - devname); - goto socket_err; - } - /* Allocate the Ring */ - ptv->ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; + if (ptv->flags & AFP_TPACKET_V3) { + ptv->ring_buflen = ptv->req3.tp_block_nr * ptv->req3.tp_block_size; + } else { + ptv->ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; + } ptv->ring_buf = mmap(0, ptv->ring_buflen, PROT_READ|PROT_WRITE, MAP_SHARED, ptv->socket, 0); if (ptv->ring_buf == MAP_FAILED) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); goto socket_err; } - /* allocate a ring for each frame header pointer*/ - ptv->frame_buf = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); - if (ptv->frame_buf == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); - goto mmap_err; - } - memset(ptv->frame_buf, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); - /* fill the header ring with proper frame ptr*/ - ptv->frame_offset = 0; - for (i = 0; i < ptv->req.tp_block_nr; ++i) { - void *base = &ptv->ring_buf[i * ptv->req.tp_block_size]; - unsigned int j; - for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { - (((union thdr **)ptv->frame_buf)[ptv->frame_offset]) = base; - base += ptv->req.tp_frame_size; + if (ptv->flags & AFP_TPACKET_V3) { + ptv->rd = SCMalloc(ptv->req3.tp_block_nr * sizeof(*ptv->rd)); + if (!ptv->rd) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to malloc ptv rd"); + goto mmap_err; + } + for (i = 0; i < ptv->req3.tp_block_nr; ++i) { + ptv->rd[i].iov_base = ptv->ring_buf + (i * ptv->req3.tp_block_size); + ptv->rd[i].iov_len = ptv->req3.tp_block_size; } + } else { + /* allocate a ring for each frame header pointer*/ + ptv->frame_buf = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); + if (ptv->frame_buf == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); + goto mmap_err; + } + memset(ptv->frame_buf, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); + /* fill the header ring with proper frame ptr*/ + ptv->frame_offset = 0; + for (i = 0; i < ptv->req.tp_block_nr; ++i) { + void *base = &ptv->ring_buf[i * ptv->req.tp_block_size]; + unsigned int j; + for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { + (((union thdr **)ptv->frame_buf)[ptv->frame_offset]) = base; + base += ptv->req.tp_frame_size; + } + } + ptv->frame_offset = 0; } - ptv->frame_offset = 0; } SCLogDebug("Using interface '%s' via socket %d", (char *)devname, ptv->socket); @@ -1608,6 +1844,8 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) frame_err: if (ptv->frame_buf) SCFree(ptv->frame_buf); + if (ptv->rd) + SCFree(ptv->rd); mmap_err: /* Packet mmap does the cleaning when socket is closed */ socket_err: diff --git a/src/source-af-packet.h b/src/source-af-packet.h index 86ad97bba6a7..f79d436adcb7 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -48,6 +48,7 @@ #define AFP_ZERO_COPY (1<<1) #define AFP_SOCK_PROTECT (1<<2) #define AFP_EMERGENCY_MODE (1<<3) +#define AFP_TPACKET_V3 (1<<4) #define AFP_COPY_MODE_NONE 0 #define AFP_COPY_MODE_TAP 1 diff --git a/suricata.yaml.in b/suricata.yaml.in index c93bfd613aba..b5e92fd75124 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -470,6 +470,8 @@ af-packet: #rollover: yes # To use the ring feature of AF_PACKET, set 'use-mmap' to yes use-mmap: yes + # Use tpacket_v3, capture mode, only active if user-mmap is true + #tpacket-v3: yes # Ring size will be computed with respect to max_pending_packets and number # of threads. You can set manually the ring size in number of packets by setting # the following value. If you are using flow cluster-type and have really network @@ -515,6 +517,7 @@ af-packet: #threads: auto #use-mmap: yes #rollover: yes + tpacket-v3: yes # Netmap support # From 9500d12c9f8be4edef896decab896b69be88a3ea Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 1 Apr 2016 19:46:41 +0200 Subject: [PATCH 1417/2553] af-packet: cleaning and hole hunting Reorder fields in AFPThreadVars and suppress some that were not used elsewhere than in the initialization. --- src/source-af-packet.c | 87 ++++++++++++++++++++++-------------------- src/source-af-packet.h | 3 +- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 6aaf7f2211df..bf6bffaf177b 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -188,64 +188,68 @@ union thdr { */ typedef struct AFPThreadVars_ { - /* thread specific socket */ - int socket; - /* handle state */ - unsigned char afp_state; - - /* data link type for the thread */ - int datalink; - int cooked; - /* counters */ uint64_t pkts; uint64_t bytes; - uint64_t errs; ThreadVars *tv; TmSlot *slot; + LiveDevice *livedev; + /* data link type for the thread */ + int datalink; + int flags; + + unsigned int frame_offset; + ChecksumValidationMode checksum_mode; + + uint16_t capture_kernel_packets; + uint16_t capture_kernel_drops; + + /* handle state */ + uint8_t afp_state; + uint8_t copy_mode; + + struct iovec *rd; + char *frame_buf; + + /* IPS peer */ + AFPPeer *mpeer; + + /* no mmap mode */ uint8_t *data; /** Per function and thread data */ int datalen; /** Length of per function and thread data */ + int cooked; - int vlan_disabled; - - char iface[AFP_IFACE_NAME_LENGTH]; - LiveDevice *livedev; - int down_count; + /* + * Init related members + */ + /* thread specific socket */ + int socket; /* Filter */ char *bpf_filter; /* socket buffer size */ int buffer_size; + + int ring_size; + int promisc; - ChecksumValidationMode checksum_mode; - /* IPS stuff */ - char out_iface[AFP_IFACE_NAME_LENGTH]; - AFPPeer *mpeer; + int down_count; - int flags; - uint16_t capture_kernel_packets; - uint16_t capture_kernel_drops; + char iface[AFP_IFACE_NAME_LENGTH]; + /* IPS output iface */ + char out_iface[AFP_IFACE_NAME_LENGTH]; int cluster_id; int cluster_type; int threads; - int copy_mode; struct tpacket_req req; struct tpacket_req3 req3; - unsigned int tp_hdrlen; - unsigned int ring_buflen; - char *ring_buf; - char *frame_buf; - struct iovec *rd; - - unsigned int frame_offset; - int ring_size; } AFPThreadVars; @@ -813,7 +817,7 @@ int AFPReadFromRing(AFPThreadVars *ptv) } /* get vlan id from header */ - if ((!ptv->vlan_disabled) && + if ((!(ptv->flags & AFP_VLAN_DISABLED)) && (h.h2->tp_status & TP_STATUS_VLAN_VALID || h.h2->tp_vlan_tci)) { p->vlan_id[0] = h.h2->tp_vlan_tci & 0x0fff; p->vlan_idx = 1; @@ -1583,6 +1587,8 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) int order; unsigned int i; int if_idx; + unsigned int ring_buflen; + uint8_t * ring_buf; /* open socket */ ptv->socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); @@ -1719,7 +1725,6 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) SCLogError(SC_ERR_AFP_CREATE, "Error when retrieving packet header len"); goto socket_err; } - ptv->tp_hdrlen = val; if (ptv->flags & AFP_TPACKET_V3) { val = TPACKET_V3; @@ -1778,13 +1783,13 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) /* Allocate the Ring */ if (ptv->flags & AFP_TPACKET_V3) { - ptv->ring_buflen = ptv->req3.tp_block_nr * ptv->req3.tp_block_size; + ring_buflen = ptv->req3.tp_block_nr * ptv->req3.tp_block_size; } else { - ptv->ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; + ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; } - ptv->ring_buf = mmap(0, ptv->ring_buflen, PROT_READ|PROT_WRITE, + ring_buf = mmap(0, ring_buflen, PROT_READ|PROT_WRITE, MAP_SHARED, ptv->socket, 0); - if (ptv->ring_buf == MAP_FAILED) { + if (ring_buf == MAP_FAILED) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); goto socket_err; } @@ -1795,7 +1800,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) goto mmap_err; } for (i = 0; i < ptv->req3.tp_block_nr; ++i) { - ptv->rd[i].iov_base = ptv->ring_buf + (i * ptv->req3.tp_block_size); + ptv->rd[i].iov_base = ring_buf + (i * ptv->req3.tp_block_size); ptv->rd[i].iov_len = ptv->req3.tp_block_size; } } else { @@ -1809,7 +1814,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) /* fill the header ring with proper frame ptr*/ ptv->frame_offset = 0; for (i = 0; i < ptv->req.tp_block_nr; ++i) { - void *base = &ptv->ring_buf[i * ptv->req.tp_block_size]; + void *base = &ring_buf[i * ptv->req.tp_block_size]; unsigned int j; for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { (((union thdr **)ptv->frame_buf)[ptv->frame_offset]) = base; @@ -2008,14 +2013,14 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) * the capture phase */ int vlanbool = 0; if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) { - ptv->vlan_disabled = 1; + ptv->flags |= AFP_VLAN_DISABLED; } /* If kernel is older than 3.0, VLAN is not stripped so we don't * get the info from packet extended header but we will use a standard * parsing of packet data (See Linux commit bcc6d47903612c3861201cc3a866fb604f26b8b2) */ if (! SCKernelVersionIsAtLeast(3, 0)) { - ptv->vlan_disabled = 1; + ptv->flags |= AFP_VLAN_DISABLED; } SCReturnInt(TM_ECODE_OK); diff --git a/src/source-af-packet.h b/src/source-af-packet.h index f79d436adcb7..89e82ec5d9eb 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -49,6 +49,7 @@ #define AFP_SOCK_PROTECT (1<<2) #define AFP_EMERGENCY_MODE (1<<3) #define AFP_TPACKET_V3 (1<<4) +#define AFP_VLAN_DISABLED (1<<5) #define AFP_COPY_MODE_NONE 0 #define AFP_COPY_MODE_TAP 1 @@ -108,12 +109,12 @@ typedef struct AFPPeer_ { typedef struct AFPPacketVars_ { void *relptr; - int copy_mode; AFPPeer *peer; /**< Sending peer for IPS/TAP mode */ /** Pointer to ::AFPPeer used for capture. Field is used to be able * to do reference counting. */ AFPPeer *mpeer; + uint8_t copy_mode; } AFPPacketVars; #define AFPV_CLEANUP(afpv) do { \ From b797fd926c0aa080c6ace55f25a7f0dff12b4bb7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 1 Apr 2016 22:33:22 +0200 Subject: [PATCH 1418/2553] af-packet: continuing cleaning and hole hunting Suppress useless fields in AFPThreadVars. This patch also get rid of bytes counter as it was only used to display a message at exit. Information on livedev and on packet counters are enough. --- src/source-af-packet.c | 78 ++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index bf6bffaf177b..df94a0d668ef 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -188,30 +188,32 @@ union thdr { */ typedef struct AFPThreadVars_ { + union { + char *ring_v2; + struct iovec *ring_v3; + }; + /* counters */ uint64_t pkts; - uint64_t bytes; ThreadVars *tv; TmSlot *slot; LiveDevice *livedev; /* data link type for the thread */ - int datalink; - int flags; + uint32_t datalink; unsigned int frame_offset; ChecksumValidationMode checksum_mode; + /* references to packet and drop counters */ uint16_t capture_kernel_packets; uint16_t capture_kernel_drops; /* handle state */ uint8_t afp_state; uint8_t copy_mode; - - struct iovec *rd; - char *frame_buf; + uint8_t flags; /* IPS peer */ AFPPeer *mpeer; @@ -227,29 +229,31 @@ typedef struct AFPThreadVars_ /* thread specific socket */ int socket; + + int ring_size; /* Filter */ char *bpf_filter; /* socket buffer size */ int buffer_size; - int ring_size; - int promisc; int down_count; - char iface[AFP_IFACE_NAME_LENGTH]; - /* IPS output iface */ - char out_iface[AFP_IFACE_NAME_LENGTH]; - int cluster_id; int cluster_type; int threads; - struct tpacket_req req; - struct tpacket_req3 req3; + union { + struct tpacket_req req; + struct tpacket_req3 req3; + }; + + char iface[AFP_IFACE_NAME_LENGTH]; + /* IPS output iface */ + char out_iface[AFP_IFACE_NAME_LENGTH]; } AFPThreadVars; @@ -591,7 +595,6 @@ int AFPRead(AFPThreadVars *ptv) } ptv->pkts++; - ptv->bytes += caplen + offset; p->livedev = ptv->livedev; /* add forged header */ @@ -757,7 +760,7 @@ int AFPReadFromRing(AFPThreadVars *ptv) } /* Read packet from ring */ - h.raw = (((union thdr **)ptv->frame_buf)[ptv->frame_offset]); + h.raw = (((union thdr **)ptv->ring_v2)[ptv->frame_offset]); if (h.raw == NULL) { SCReturnInt(AFP_FAILURE); } @@ -807,7 +810,6 @@ int AFPReadFromRing(AFPThreadVars *ptv) h.h2->tp_status |= TP_STATUS_USER_BUSY; ptv->pkts++; - ptv->bytes += h.h2->tp_len; p->livedev = ptv->livedev; p->datalink = ptv->datalink; @@ -914,7 +916,6 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc PKT_SET_SRC(p, PKT_SRC_WIRE); ptv->pkts++; - ptv->bytes += ppd->tp_len; p->livedev = ptv->livedev; p->datalink = ptv->datalink; @@ -1007,7 +1008,7 @@ int AFPReadFromRingV3(AFPThreadVars *ptv) break; } - pbd = (struct tpacket_block_desc *) ptv->rd[ptv->frame_offset].iov_base; + pbd = (struct tpacket_block_desc *) ptv->ring_v3[ptv->frame_offset].iov_base; /* block is not ready to be read */ if ((pbd->hdr.bh1.block_status & TP_STATUS_USER) == 0) { @@ -1074,10 +1075,10 @@ void AFPSwitchState(AFPThreadVars *ptv, int state) /* Do cleaning if switching to down state */ if (state == AFP_STATE_DOWN) { - if (ptv->frame_buf) { + if (ptv->ring_v2) { /* only used in reading phase, we can free it */ - SCFree(ptv->frame_buf); - ptv->frame_buf = NULL; + SCFree(ptv->ring_v2); + ptv->ring_v2 = NULL; } if (ptv->socket != -1) { /* we need to wait for all packets to return data */ @@ -1149,7 +1150,7 @@ static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv) } /* Read packet from ring */ - h.raw = (((union thdr **)ptv->frame_buf)[ptv->frame_offset]); + h.raw = (((union thdr **)ptv->ring_v2)[ptv->frame_offset]); if (h.raw == NULL) { return -1; } @@ -1794,30 +1795,30 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) goto socket_err; } if (ptv->flags & AFP_TPACKET_V3) { - ptv->rd = SCMalloc(ptv->req3.tp_block_nr * sizeof(*ptv->rd)); - if (!ptv->rd) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to malloc ptv rd"); + ptv->ring_v3 = SCMalloc(ptv->req3.tp_block_nr * sizeof(*ptv->ring_v3)); + if (!ptv->ring_v3) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to malloc ptv ring_v3"); goto mmap_err; } for (i = 0; i < ptv->req3.tp_block_nr; ++i) { - ptv->rd[i].iov_base = ring_buf + (i * ptv->req3.tp_block_size); - ptv->rd[i].iov_len = ptv->req3.tp_block_size; + ptv->ring_v3[i].iov_base = ring_buf + (i * ptv->req3.tp_block_size); + ptv->ring_v3[i].iov_len = ptv->req3.tp_block_size; } } else { /* allocate a ring for each frame header pointer*/ - ptv->frame_buf = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); - if (ptv->frame_buf == NULL) { + ptv->ring_v2 = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); + if (ptv->ring_v2 == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); goto mmap_err; } - memset(ptv->frame_buf, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); + memset(ptv->ring_v2, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); /* fill the header ring with proper frame ptr*/ ptv->frame_offset = 0; for (i = 0; i < ptv->req.tp_block_nr; ++i) { void *base = &ring_buf[i * ptv->req.tp_block_size]; unsigned int j; for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { - (((union thdr **)ptv->frame_buf)[ptv->frame_offset]) = base; + (((union thdr **)ptv->ring_v2)[ptv->frame_offset]) = base; base += ptv->req.tp_frame_size; } } @@ -1847,10 +1848,13 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) return 0; frame_err: - if (ptv->frame_buf) - SCFree(ptv->frame_buf); - if (ptv->rd) - SCFree(ptv->rd); + if (ptv->flags & AFP_TPACKET_V3) { + if (ptv->ring_v3) + SCFree(ptv->ring_v3); + } else { + if (ptv->ring_v2) + SCFree(ptv->ring_v2); + } mmap_err: /* Packet mmap does the cleaning when socket is closed */ socket_err: @@ -2044,7 +2048,7 @@ void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) StatsGetLocalCounterValue(tv, ptv->capture_kernel_drops)); #endif - SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); + SCLogInfo("(%s) Packets %" PRIu64, tv->name, ptv->pkts); } /** From 5f84b55d98ca36b199d1c6b84dc89a5461687df8 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 22 Apr 2016 22:15:53 +0200 Subject: [PATCH 1419/2553] af-packet: AFPWalkBlock error handling Error handling was not done. The implementation is making the choice to consider we must detroy the socket in case of parsing error. The same was done for tpacket_v2. --- src/source-af-packet.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index df94a0d668ef..971cba0e7bcd 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -966,7 +966,6 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc } if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { - AFPFlushBlock(pbd); TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(AFP_FAILURE); } @@ -981,7 +980,10 @@ static inline int AFPWalkBlock(AFPThreadVars *ptv, struct tpacket_block_desc *pb ppd = (uint8_t *)pbd + pbd->hdr.bh1.offset_to_first_pkt; for (i = 0; i < num_pkts; ++i) { - AFPParsePacketV3(ptv, pbd, (struct tpacket3_hdr *)ppd); + if (unlikely(AFPParsePacketV3(ptv, pbd, + (struct tpacket3_hdr *)ppd) == AFP_FAILURE)) { + SCReturnInt(AFP_READ_FAILURE); + } ppd = ppd + ((struct tpacket3_hdr *)ppd)->tp_next_offset; } @@ -1075,11 +1077,22 @@ void AFPSwitchState(AFPThreadVars *ptv, int state) /* Do cleaning if switching to down state */ if (state == AFP_STATE_DOWN) { - if (ptv->ring_v2) { - /* only used in reading phase, we can free it */ - SCFree(ptv->ring_v2); - ptv->ring_v2 = NULL; +#ifdef HAVE_TPACKET_V3 + if (ptv->flags & AFP_TPACKET_V3) { + if (!ptv->ring_v3) { + SCFree(ptv->ring_v3); + ptv->ring_v3 = NULL; + } + } else { +#endif + if (ptv->ring_v2) { + /* only used in reading phase, we can free it */ + SCFree(ptv->ring_v2); + ptv->ring_v2 = NULL; + } +#ifdef HAVE_TPACKET_V3 } +#endif if (ptv->socket != -1) { /* we need to wait for all packets to return data */ if (SC_ATOMIC_SUB(ptv->mpeer->sock_usage, 1) == 0) { From 7fa963718fa630320cb426702304c4bf8cdab5a8 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 1 Apr 2016 22:52:37 +0200 Subject: [PATCH 1420/2553] af-packet: pack AFPPeer structure --- src/source-af-packet.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/source-af-packet.h b/src/source-af-packet.h index 89e82ec5d9eb..75904f31868c 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -88,16 +88,16 @@ typedef struct AFPIfaceConfig_ */ typedef struct AFPPeer_ { - char iface[AFP_IFACE_NAME_LENGTH]; SC_ATOMIC_DECLARE(int, socket); SC_ATOMIC_DECLARE(int, sock_usage); SC_ATOMIC_DECLARE(int, if_idx); - SC_ATOMIC_DECLARE(uint8_t, state); - SCMutex sock_protect; int flags; + SCMutex sock_protect; int turn; /**< Field used to store initialisation order. */ + SC_ATOMIC_DECLARE(uint8_t, state); struct AFPPeer_ *peer; TAILQ_ENTRY(AFPPeer_) next; + char iface[AFP_IFACE_NAME_LENGTH]; } AFPPeer; /** From c7bde9dff66bd9722b7d4e8c80abd4b29fc5571b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 7 Apr 2016 21:58:48 +0200 Subject: [PATCH 1421/2553] af-packet: put ring setup in a separate function --- src/source-af-packet.c | 278 ++++++++++++++++++++++------------------- 1 file changed, 148 insertions(+), 130 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 971cba0e7bcd..95a85a9d25a5 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1592,17 +1592,153 @@ static int AFPComputeRingParamsV3(AFPThreadVars *ptv) return 1; } +static int AFPSetupRing(AFPThreadVars *ptv, char *devname) +{ + int val; + unsigned int len = sizeof(val), i; + unsigned int ring_buflen; + uint8_t * ring_buf; + int order; + int r; + + if (ptv->flags & AFP_TPACKET_V3) { + val = TPACKET_V3; + } else { + val = TPACKET_V2; + } + if (getsockopt(ptv->socket, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { + if (errno == ENOPROTOOPT) { + if (ptv->flags & AFP_TPACKET_V3) { + SCLogError(SC_ERR_AFP_CREATE, + "Too old kernel giving up (need 3.2 for TPACKET_V3)"); + } else { + SCLogError(SC_ERR_AFP_CREATE, + "Too old kernel giving up (need 2.6.27 at least)"); + } + } + SCLogError(SC_ERR_AFP_CREATE, "Error when retrieving packet header len"); + return AFP_FATAL_ERROR; + } + + if (ptv->flags & AFP_TPACKET_V3) { + val = TPACKET_V3; + } else { + val = TPACKET_V2; + } + if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, + sizeof(val)) < 0) { + SCLogError(SC_ERR_AFP_CREATE, + "Can't activate TPACKET_V2/TPACKET_V3 on packet socket: %s", + strerror(errno)); + return AFP_FATAL_ERROR; + } + + /* Allocate RX ring */ + if (ptv->flags & AFP_TPACKET_V3) { + if (AFPComputeRingParamsV3(ptv) != 1) { + return AFP_FATAL_ERROR; + } + r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, + (void *) &ptv->req3, sizeof(ptv->req3)); + if (r < 0) { + SCLogError(SC_ERR_MEM_ALLOC, + "Unable to allocate RX Ring for iface %s: (%d) %s", + devname, + errno, + strerror(errno)); + return AFP_FATAL_ERROR; + } + } else { +#define DEFAULT_ORDER 3 + for (order = DEFAULT_ORDER; order >= 0; order--) { + if (AFPComputeRingParams(ptv, order) != 1) { + SCLogInfo("Ring parameter are incorrect. Please correct the devel"); + return AFP_FATAL_ERROR; + } + + r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, + (void *) &ptv->req, sizeof(ptv->req)); + + if (r < 0) { + if (errno == ENOMEM) { + SCLogInfo("Memory issue with ring parameters. Retrying."); + continue; + } + SCLogError(SC_ERR_MEM_ALLOC, + "Unable to allocate RX Ring for iface %s: (%d) %s", + devname, + errno, + strerror(errno)); + return AFP_FATAL_ERROR; + } else { + break; + } + } + if (order < 0) { + SCLogError(SC_ERR_MEM_ALLOC, + "Unable to allocate RX Ring for iface %s (order 0 failed)", + devname); + return AFP_FATAL_ERROR; + } + } + + /* Allocate the Ring */ + if (ptv->flags & AFP_TPACKET_V3) { + ring_buflen = ptv->req3.tp_block_nr * ptv->req3.tp_block_size; + } else { + ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; + } + ring_buf = mmap(0, ring_buflen, PROT_READ|PROT_WRITE, + MAP_SHARED, ptv->socket, 0); + if (ring_buf == MAP_FAILED) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); + goto mmap_err; + } + if (ptv->flags & AFP_TPACKET_V3) { + ptv->ring_v3 = SCMalloc(ptv->req3.tp_block_nr * sizeof(*ptv->ring_v3)); + if (!ptv->ring_v3) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to malloc ptv ring_v3"); + goto mmap_err; + } + for (i = 0; i < ptv->req3.tp_block_nr; ++i) { + ptv->ring_v3[i].iov_base = ring_buf + (i * ptv->req3.tp_block_size); + ptv->ring_v3[i].iov_len = ptv->req3.tp_block_size; + } + } else { + /* allocate a ring for each frame header pointer*/ + ptv->ring_v2 = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); + if (ptv->ring_v2 == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); + goto mmap_err; + } + memset(ptv->ring_v2, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); + /* fill the header ring with proper frame ptr*/ + ptv->frame_offset = 0; + for (i = 0; i < ptv->req.tp_block_nr; ++i) { + void *base = &ring_buf[i * ptv->req.tp_block_size]; + unsigned int j; + for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { + (((union thdr **)ptv->ring_v2)[ptv->frame_offset]) = base; + base += ptv->req.tp_frame_size; + } + } + ptv->frame_offset = 0; + } + + return 0; + +mmap_err: + /* Packet mmap does the cleaning when socket is closed */ + return AFP_FATAL_ERROR; +} + static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) { int r; int ret = AFP_FATAL_ERROR; struct packet_mreq sock_params; struct sockaddr_ll bind_address; - int order; - unsigned int i; int if_idx; - unsigned int ring_buflen; - uint8_t * ring_buf; /* open socket */ ptv->socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); @@ -1633,7 +1769,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) SCLogError(SC_ERR_AFP_CREATE, "Couldn't switch iface %s to promiscuous, error %s", devname, strerror(errno)); - goto frame_err; + goto socket_err; } } @@ -1659,7 +1795,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) SCLogError(SC_ERR_AFP_CREATE, "Couldn't set buffer size to %d on iface %s, error %s", ptv->buffer_size, devname, strerror(errno)); - goto frame_err; + goto socket_err; } } @@ -1677,7 +1813,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) } } ret = AFP_RECOVERABLE_ERROR; - goto frame_err; + goto socket_err; } #ifdef HAVE_PACKET_FANOUT @@ -1692,7 +1828,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) SCLogError(SC_ERR_AFP_CREATE, "Coudn't set fanout mode, error %s", strerror(errno)); - goto frame_err; + goto socket_err; } } #endif @@ -1705,7 +1841,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) ptv->iface); } ret = AFP_RECOVERABLE_ERROR; - goto frame_err; + goto socket_err; } if ((if_flags & IFF_UP) == 0) { if (verbose) { @@ -1714,129 +1850,13 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) ptv->iface); } ret = AFP_RECOVERABLE_ERROR; - goto frame_err; + goto socket_err; } if (ptv->flags & AFP_RING_MODE) { - int val; - unsigned int len = sizeof(val); - - if (ptv->flags & AFP_TPACKET_V3) { - val = TPACKET_V3; - } else { - val = TPACKET_V2; - } - if (getsockopt(ptv->socket, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { - if (errno == ENOPROTOOPT) { - if (ptv->flags & AFP_TPACKET_V3) { - SCLogError(SC_ERR_AFP_CREATE, - "Too old kernel giving up (need 3.2 for TPACKET_V3)"); - } else { - SCLogError(SC_ERR_AFP_CREATE, - "Too old kernel giving up (need 2.6.27 at least)"); - } - } - SCLogError(SC_ERR_AFP_CREATE, "Error when retrieving packet header len"); - goto socket_err; - } - - if (ptv->flags & AFP_TPACKET_V3) { - val = TPACKET_V3; - } else { - val = TPACKET_V2; - } - if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, - sizeof(val)) < 0) { - SCLogError(SC_ERR_AFP_CREATE, - "Can't activate TPACKET_V2/TPACKET_V3 on packet socket: %s", - strerror(errno)); - goto socket_err; - } - - /* Allocate RX ring */ - if (ptv->flags & AFP_TPACKET_V3) { - if (AFPComputeRingParamsV3(ptv) != 1) { - SCLogInfo("Ring parameter are incorrect. Please correct the devel"); - goto socket_err; - } - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, - (void *) &ptv->req3, sizeof(ptv->req3)); - } else { -#define DEFAULT_ORDER 3 - for (order = DEFAULT_ORDER; order >= 0; order--) { - if (AFPComputeRingParams(ptv, order) != 1) { - SCLogInfo("Ring parameter are incorrect. Please correct the devel"); - goto socket_err; - } - - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, - (void *) &ptv->req, sizeof(ptv->req)); - - if (r < 0) { - if (errno == ENOMEM) { - SCLogInfo("Memory issue with ring parameters. Retrying."); - continue; - } - SCLogError(SC_ERR_MEM_ALLOC, - "Unable to allocate RX Ring for iface %s: (%d) %s", - devname, - errno, - strerror(errno)); - goto socket_err; - } else { - break; - } - } - if (order < 0) { - SCLogError(SC_ERR_MEM_ALLOC, - "Unable to allocate RX Ring for iface %s (order 0 failed)", - devname); - goto socket_err; - } - } - - /* Allocate the Ring */ - if (ptv->flags & AFP_TPACKET_V3) { - ring_buflen = ptv->req3.tp_block_nr * ptv->req3.tp_block_size; - } else { - ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; - } - ring_buf = mmap(0, ring_buflen, PROT_READ|PROT_WRITE, - MAP_SHARED, ptv->socket, 0); - if (ring_buf == MAP_FAILED) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); + ret = AFPSetupRing(ptv, devname); + if (ret != 0) goto socket_err; - } - if (ptv->flags & AFP_TPACKET_V3) { - ptv->ring_v3 = SCMalloc(ptv->req3.tp_block_nr * sizeof(*ptv->ring_v3)); - if (!ptv->ring_v3) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to malloc ptv ring_v3"); - goto mmap_err; - } - for (i = 0; i < ptv->req3.tp_block_nr; ++i) { - ptv->ring_v3[i].iov_base = ring_buf + (i * ptv->req3.tp_block_size); - ptv->ring_v3[i].iov_len = ptv->req3.tp_block_size; - } - } else { - /* allocate a ring for each frame header pointer*/ - ptv->ring_v2 = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); - if (ptv->ring_v2 == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); - goto mmap_err; - } - memset(ptv->ring_v2, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); - /* fill the header ring with proper frame ptr*/ - ptv->frame_offset = 0; - for (i = 0; i < ptv->req.tp_block_nr; ++i) { - void *base = &ring_buf[i * ptv->req.tp_block_size]; - unsigned int j; - for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { - (((union thdr **)ptv->ring_v2)[ptv->frame_offset]) = base; - base += ptv->req.tp_frame_size; - } - } - ptv->frame_offset = 0; - } } SCLogDebug("Using interface '%s' via socket %d", (char *)devname, ptv->socket); @@ -1868,8 +1888,6 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) if (ptv->ring_v2) SCFree(ptv->ring_v2); } -mmap_err: - /* Packet mmap does the cleaning when socket is closed */ socket_err: close(ptv->socket); ptv->socket = -1; From fa902abedf92e82768519c72ce3e180ace0784da Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 8 Apr 2016 10:03:52 +0200 Subject: [PATCH 1422/2553] af-packet: configurable tpacket_v3 block size It is used to set the block size in tpacket_v3. It will allow user to tune the capture depending on his bandwidth. Default block size value has been updated to a bigger value to allow more efficient wlak on block. --- src/runmode-af-packet.c | 15 +++++++++++++++ src/source-af-packet.c | 12 ++++++------ src/source-af-packet.h | 4 ++++ suricata.yaml.in | 4 ++++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 0397401e37cd..347373d3f225 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -361,6 +361,21 @@ void *ParseAFPConfig(const char *iface) aconf->ring_size = max_pending_packets * 2 / aconf->threads; } + aconf->block_size = getpagesize() << AFP_BLOCK_SIZE_DEFAULT_ORDER; + if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-size", &value)) == 1) { + if (value % getpagesize()) { + SCLogError(SC_ERR_INVALID_VALUE, "Block-size must be a multiple of pagesize."); + } else { + aconf->block_size = value; + } + } + + if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) { + aconf->block_timeout = value; + } else { + aconf->block_timeout = 10; + } + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); if (boolval) { SCLogInfo("Disabling promiscuous mode on iface %s", diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 95a85a9d25a5..3fdeb4f000d4 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -231,11 +231,11 @@ typedef struct AFPThreadVars_ int socket; int ring_size; - /* Filter */ - char *bpf_filter; - + int block_size; /* socket buffer size */ int buffer_size; + /* Filter */ + char *bpf_filter; int promisc; @@ -1555,7 +1555,7 @@ frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + siz static int AFPComputeRingParamsV3(AFPThreadVars *ptv) { - ptv->req3.tp_block_size = getpagesize(); + ptv->req3.tp_block_size = ptv->block_size; ptv->req3.tp_frame_size = 2048; int frames_per_block = 0; int tp_hdrlen = sizeof(struct tpacket3_hdr); @@ -1649,8 +1649,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) return AFP_FATAL_ERROR; } } else { -#define DEFAULT_ORDER 3 - for (order = DEFAULT_ORDER; order >= 0; order--) { + for (order = AFP_BLOCK_SIZE_DEFAULT_ORDER; order >= 0; order--) { if (AFPComputeRingParams(ptv, order) != 1) { SCLogInfo("Ring parameter are incorrect. Please correct the devel"); return AFP_FATAL_ERROR; @@ -1982,6 +1981,7 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->buffer_size = afpconfig->buffer_size; ptv->ring_size = afpconfig->ring_size; + ptv->block_size = afpconfig->block_size; ptv->promisc = afpconfig->promisc; ptv->checksum_mode = afpconfig->checksum_mode; diff --git a/src/source-af-packet.h b/src/source-af-packet.h index 75904f31868c..6560701ae4f5 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -58,6 +58,8 @@ #define AFP_FILE_MAX_PKTS 256 #define AFP_IFACE_NAME_LENGTH 48 +#define AFP_BLOCK_SIZE_DEFAULT_ORDER 3 + typedef struct AFPIfaceConfig_ { char iface[AFP_IFACE_NAME_LENGTH]; @@ -67,6 +69,8 @@ typedef struct AFPIfaceConfig_ int buffer_size; /* ring size in number of packets */ int ring_size; + /* block size for tpacket_v3 */ + int block_size; /* cluster param */ int cluster_id; int cluster_type; diff --git a/suricata.yaml.in b/suricata.yaml.in index b5e92fd75124..5c0dd8b4a0de 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -478,6 +478,10 @@ af-packet: # intensive single-flow you could want to set the ring-size independantly of the number # of threads: #ring-size: 2048 + # Block size is used by tpacket_v3 only. It should set to a value high enough to contain + # a decent number of packets. Size is in bytes so please consider your MTU. It should be + # a power of 2 and it must be multiple of page size (usually 4096). + #block-size: 32768 # On busy system, this could help to set it to yes to recover from a packet drop # phase. This will result in some packets (at max a ring flush) being non treated. #use-emergency-flush: yes From 234aefdff9c87623ac2f1a7f60436c79ac03561b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 8 Apr 2016 15:29:18 +0200 Subject: [PATCH 1423/2553] af-packet: configurable tpacket_v3 block timeout Block timeout defines the maximum filling duration of a block. --- src/runmode-af-packet.c | 5 +++++ src/source-af-packet.c | 3 ++- src/source-af-packet.h | 8 +++++++- suricata.yaml.in | 3 +++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 347373d3f225..0c457ee7ba63 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -370,6 +370,11 @@ void *ParseAFPConfig(const char *iface) } } + if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) { + aconf->block_timeout = value; + } else { + aconf->block_timeout = 10; + } if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) { aconf->block_timeout = value; } else { diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 3fdeb4f000d4..3f447b081530 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -232,6 +232,7 @@ typedef struct AFPThreadVars_ int ring_size; int block_size; + int block_timeout; /* socket buffer size */ int buffer_size; /* Filter */ @@ -1582,7 +1583,7 @@ static int AFPComputeRingParamsV3(AFPThreadVars *ptv) ptv->req3.tp_block_nr = ptv->ring_size / frames_per_block + 1; /* exact division */ ptv->req3.tp_frame_nr = ptv->req3.tp_block_nr * frames_per_block; - ptv->req3.tp_retire_blk_tov = 10; /* 10 ms timeout on block */ + ptv->req3.tp_retire_blk_tov = ptv->block_timeout; ptv->req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH; SCLogInfo("AF_PACKET V3 RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d (mem: %d)", ptv->req3.tp_block_size, ptv->req3.tp_block_nr, diff --git a/src/source-af-packet.h b/src/source-af-packet.h index 6560701ae4f5..7b3214c4df5e 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -58,6 +58,10 @@ #define AFP_FILE_MAX_PKTS 256 #define AFP_IFACE_NAME_LENGTH 48 +/* In kernel the allocated block size is allocated using the formula + * page_size << order. So default value is using the same formula with + * an order of 3 which guarantee we have some room in the block compared + * to standard frame size */ #define AFP_BLOCK_SIZE_DEFAULT_ORDER 3 typedef struct AFPIfaceConfig_ @@ -69,8 +73,10 @@ typedef struct AFPIfaceConfig_ int buffer_size; /* ring size in number of packets */ int ring_size; - /* block size for tpacket_v3 */ + /* block size for tpacket_v3 in */ int block_size; + /* block timeout for tpacket_v3 in milliseconds */ + int block_timeout; /* cluster param */ int cluster_id; int cluster_type; diff --git a/suricata.yaml.in b/suricata.yaml.in index 5c0dd8b4a0de..ea533081f47e 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -482,6 +482,9 @@ af-packet: # a decent number of packets. Size is in bytes so please consider your MTU. It should be # a power of 2 and it must be multiple of page size (usually 4096). #block-size: 32768 + # tpacket_v3 block timeout: an open block is passed to userspace if it is not + # filled after block-timeout milliseconds. + #block-timeout: 10 # On busy system, this could help to set it to yes to recover from a packet drop # phase. This will result in some packets (at max a ring flush) being non treated. #use-emergency-flush: yes From f5c20191672de24d55852eb48dcd6a33524de4b7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 8 Apr 2016 17:05:55 +0200 Subject: [PATCH 1424/2553] af-packet: add option to use memory locked mmap --- src/runmode-af-packet.c | 6 ++++++ src/source-af-packet.c | 7 +++++-- src/source-af-packet.h | 1 + suricata.yaml.in | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 0c457ee7ba63..15dc03baf498 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -222,6 +222,12 @@ void *ParseAFPConfig(const char *iface) aconf->iface); aconf->flags |= AFP_RING_MODE; } + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "mmap-locked", (int *)&boolval); + if (boolval) { + SCLogInfo("Enabling locked memory for mmap on iface %s", + aconf->iface); + aconf->flags |= AFP_MMAP_LOCKED; + } (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "tpacket-v3", (int *)&boolval); if (boolval) { if (strcasecmp(RunmodeGetActive(), "workers") == 0) { diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 3f447b081530..b149de8157b1 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1600,7 +1600,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) unsigned int ring_buflen; uint8_t * ring_buf; int order; - int r; + int r, mmap_flag; if (ptv->flags & AFP_TPACKET_V3) { val = TPACKET_V3; @@ -1688,8 +1688,11 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) } else { ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; } + mmap_flag = MAP_SHARED; + if (ptv->flags & AFP_MMAP_LOCKED) + mmap_flag |= MAP_LOCKED; ring_buf = mmap(0, ring_buflen, PROT_READ|PROT_WRITE, - MAP_SHARED, ptv->socket, 0); + mmap_flag, ptv->socket, 0); if (ring_buf == MAP_FAILED) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); goto mmap_err; diff --git a/src/source-af-packet.h b/src/source-af-packet.h index 7b3214c4df5e..2aa803a56b9c 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -50,6 +50,7 @@ #define AFP_EMERGENCY_MODE (1<<3) #define AFP_TPACKET_V3 (1<<4) #define AFP_VLAN_DISABLED (1<<5) +#define AFP_MMAP_LOCKED (1<<6) #define AFP_COPY_MODE_NONE 0 #define AFP_COPY_MODE_TAP 1 diff --git a/suricata.yaml.in b/suricata.yaml.in index ea533081f47e..c08165cc2d5e 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -470,6 +470,9 @@ af-packet: #rollover: yes # To use the ring feature of AF_PACKET, set 'use-mmap' to yes use-mmap: yes + # Lock memory map to avoid it goes to swap. Be careful that over suscribing could lock + # your system + #mmap-locked: yes # Use tpacket_v3, capture mode, only active if user-mmap is true #tpacket-v3: yes # Ring size will be computed with respect to max_pending_packets and number From c2d0d93806c6a684ced8492e86157a4f28e36bf4 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 9 Apr 2016 16:07:23 +0200 Subject: [PATCH 1425/2553] af-packet: detect availability of tpacket_v3 If TPACKET_V3 is not defined then it is not available and we should not build anything related to tpacket_v3. This will allow us to activate it dy default and fallback to v2 if not available. --- configure.ac | 5 +++++ src/runmode-af-packet.c | 6 ++++++ src/source-af-packet.c | 25 ++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d5719d7748ed..e7237651a2f4 100644 --- a/configure.ac +++ b/configure.ac @@ -1192,6 +1192,11 @@ AC_DEFINE([HAVE_PACKET_FANOUT],[1],[Recent packet fanout support is available]), [], [[#include ]]) + AC_CHECK_DECL([TPACKET_V3], + AC_DEFINE([HAVE_TPACKET_V3],[1],[AF_PACKET tpcket_v3 support is available]), + [], + [[#include + #include ]]) ]) # Netmap support diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 15dc03baf498..f1c3dba31641 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -231,13 +231,19 @@ void *ParseAFPConfig(const char *iface) (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "tpacket-v3", (int *)&boolval); if (boolval) { if (strcasecmp(RunmodeGetActive(), "workers") == 0) { +#ifdef HAVE_TPACKET_V3 SCLogInfo("Enabling tpacket v3 capture on iface %s", aconf->iface); aconf->flags |= AFP_TPACKET_V3|AFP_RING_MODE; +#else + SCLogNotice("System too old for tpacket v3 switching to v2"); + aconf->flags |= AFP_RING_MODE; +#endif } else { SCLogError(SC_ERR_RUNMODE, "tpacket v3 is only implemented for 'workers' running mode." " Switching to tpacket v2."); + aconf->flags |= AFP_RING_MODE; } } (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "use-emergency-flush", (int *)&boolval); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index b149de8157b1..a993fddd7055 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -179,7 +179,9 @@ enum { union thdr { struct tpacket2_hdr *h2; +#ifdef HAVE_TPACKET_V3 struct tpacket3_hdr *h3; +#endif void *raw; }; @@ -249,7 +251,9 @@ typedef struct AFPThreadVars_ union { struct tpacket_req req; +#ifdef HAVE_TPACKET_V3 struct tpacket_req3 req3; +#endif }; char iface[AFP_IFACE_NAME_LENGTH]; @@ -1002,6 +1006,7 @@ static inline int AFPWalkBlock(AFPThreadVars *ptv, struct tpacket_block_desc *pb */ int AFPReadFromRingV3(AFPThreadVars *ptv) { +#ifdef HAVE_TPACKET_V3 struct tpacket_block_desc *pbd; /* Loop till we have packets available */ @@ -1030,7 +1035,7 @@ int AFPReadFromRingV3(AFPThreadVars *ptv) SCReturnInt(AFP_READ_OK); } } - +#endif SCReturnInt(AFP_READ_OK); } @@ -1554,6 +1559,7 @@ frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + siz return 1; } +#ifdef HAVE_TPACKET_V3 static int AFPComputeRingParamsV3(AFPThreadVars *ptv) { ptv->req3.tp_block_size = ptv->block_size; @@ -1592,6 +1598,7 @@ static int AFPComputeRingParamsV3(AFPThreadVars *ptv) ); return 1; } +#endif static int AFPSetupRing(AFPThreadVars *ptv, char *devname) { @@ -1602,11 +1609,15 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) int order; int r, mmap_flag; +#ifdef HAVE_TPACKET_V3 if (ptv->flags & AFP_TPACKET_V3) { val = TPACKET_V3; } else { +#endif val = TPACKET_V2; +#ifdef HAVE_TPACKET_V3 } +#endif if (getsockopt(ptv->socket, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { if (errno == ENOPROTOOPT) { if (ptv->flags & AFP_TPACKET_V3) { @@ -1635,6 +1646,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) } /* Allocate RX ring */ +#ifdef HAVE_TPACKET_V3 if (ptv->flags & AFP_TPACKET_V3) { if (AFPComputeRingParamsV3(ptv) != 1) { return AFP_FATAL_ERROR; @@ -1650,6 +1662,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) return AFP_FATAL_ERROR; } } else { +#endif for (order = AFP_BLOCK_SIZE_DEFAULT_ORDER; order >= 0; order--) { if (AFPComputeRingParams(ptv, order) != 1) { SCLogInfo("Ring parameter are incorrect. Please correct the devel"); @@ -1680,14 +1693,20 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) devname); return AFP_FATAL_ERROR; } +#ifdef HAVE_TPACKET_V3 } +#endif /* Allocate the Ring */ +#ifdef HAVE_TPACKET_V3 if (ptv->flags & AFP_TPACKET_V3) { ring_buflen = ptv->req3.tp_block_nr * ptv->req3.tp_block_size; } else { +#endif ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; +#ifdef HAVE_TPACKET_V3 } +#endif mmap_flag = MAP_SHARED; if (ptv->flags & AFP_MMAP_LOCKED) mmap_flag |= MAP_LOCKED; @@ -1697,6 +1716,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); goto mmap_err; } +#ifdef HAVE_TPACKET_V3 if (ptv->flags & AFP_TPACKET_V3) { ptv->ring_v3 = SCMalloc(ptv->req3.tp_block_nr * sizeof(*ptv->ring_v3)); if (!ptv->ring_v3) { @@ -1708,6 +1728,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) ptv->ring_v3[i].iov_len = ptv->req3.tp_block_size; } } else { +#endif /* allocate a ring for each frame header pointer*/ ptv->ring_v2 = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); if (ptv->ring_v2 == NULL) { @@ -1726,7 +1747,9 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) } } ptv->frame_offset = 0; +#ifdef HAVE_TPACKET_V3 } +#endif return 0; From 876b356bbe335a50aec1c9e1222fa9584fba51b4 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 1 Apr 2016 14:01:09 +0200 Subject: [PATCH 1426/2553] af-packet: use mmap capture by default Update the code to use mmap capture by default even in unset in configuration file. mmap capture is now be turned off by using explicitely 'use-mmap: no' in configuration. --- src/runmode-af-packet.c | 13 +++++++++---- suricata.yaml.in | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index f1c3dba31641..3deae4e3f6f9 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -216,12 +216,17 @@ void *ParseAFPConfig(const char *iface) } } - (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "use-mmap", (int *)&boolval); - if (boolval) { - SCLogInfo("Enabling mmaped capture on iface %s", - aconf->iface); + if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-mmap", (int *)&boolval) == 1) { + if (boolval) { + aconf->flags |= AFP_RING_MODE; + } else { + SCLogInfo("Disabling mmaped capture on iface %s", + aconf->iface); + } + } else { aconf->flags |= AFP_RING_MODE; } + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "mmap-locked", (int *)&boolval); if (boolval) { SCLogInfo("Enabling locked memory for mmap on iface %s", diff --git a/suricata.yaml.in b/suricata.yaml.in index c08165cc2d5e..842aa45b3d1f 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -525,7 +525,7 @@ af-packet: # Put default values here - interface: default #threads: auto - #use-mmap: yes + #use-mmap: no #rollover: yes tpacket-v3: yes From 7fea0ec6f9c704a27db0c78c039bfd191f79d906 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 12 Apr 2016 11:46:43 +0200 Subject: [PATCH 1427/2553] af-packet: reset stats at start of capture We can loose packets during setup because we are reading nothing. So it is logical to discard the counter at start of capture to start from a clean state. This means we don't need to account the drop at start. But the stats call that will reset the drop counts will also return and reset the packets count. So we need to know how many packets we really have. This is in fact the number of packets coming from the stats call minus the number of discarded packets and the drop count. All the other packets will have to be read. --- src/source-af-packet.c | 70 ++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index a993fddd7055..7e1aa5444acc 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1113,7 +1113,8 @@ void AFPSwitchState(AFPThreadVars *ptv, int state) } } -static int AFPReadAndDiscard(AFPThreadVars *ptv, struct timeval *synctv) +static int AFPReadAndDiscard(AFPThreadVars *ptv, struct timeval *synctv, + uint64_t *discarded_pkts) { struct sockaddr_ll from; struct iovec iov; @@ -1155,7 +1156,8 @@ static int AFPReadAndDiscard(AFPThreadVars *ptv, struct timeval *synctv) return 0; } -static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv) +static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv, + uint64_t *discarded_pkts) { union thdr h; @@ -1163,26 +1165,30 @@ static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv) return 1; } - /* Ignore system for tpacket_v3 */ if (ptv->flags & AFP_TPACKET_V3) { + struct tpacket_block_desc *pbd; + pbd = (struct tpacket_block_desc *) ptv->ring_v3[ptv->frame_offset].iov_base; + *discarded_pkts += pbd->hdr.bh1.num_pkts; + AFPFlushBlock(pbd); + ptv->frame_offset = (ptv->frame_offset + 1) % ptv->req3.tp_block_nr; return 1; - } - - /* Read packet from ring */ - h.raw = (((union thdr **)ptv->ring_v2)[ptv->frame_offset]); - if (h.raw == NULL) { - return -1; - } - - if (((time_t)h.h2->tp_sec > synctv->tv_sec) || - ((time_t)h.h2->tp_sec == synctv->tv_sec && - (suseconds_t) (h.h2->tp_nsec / 1000) > synctv->tv_usec)) { - return 1; - } + } else { + /* Read packet from ring */ + h.raw = (((union thdr **)ptv->ring_v2)[ptv->frame_offset]); + if (h.raw == NULL) { + return -1; + } + (*discarded_pkts)++; + if (((time_t)h.h2->tp_sec > synctv->tv_sec) || + ((time_t)h.h2->tp_sec == synctv->tv_sec && + (suseconds_t) (h.h2->tp_nsec / 1000) > synctv->tv_usec)) { + return 1; + } - h.h2->tp_status = TP_STATUS_KERNEL; - if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { - ptv->frame_offset = 0; + h.h2->tp_status = TP_STATUS_KERNEL; + if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { + ptv->frame_offset = 0; + } } @@ -1198,7 +1204,7 @@ static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv) * * \retval r 1 = happy, otherwise unhappy */ -static int AFPSynchronizeStart(AFPThreadVars *ptv) +static int AFPSynchronizeStart(AFPThreadVars *ptv, uint64_t *discarded_pkts) { int r; struct timeval synctv; @@ -1223,9 +1229,9 @@ static int AFPSynchronizeStart(AFPThreadVars *ptv) gettimeofday(&synctv, NULL); } if (ptv->flags & AFP_RING_MODE) { - r = AFPReadAndDiscardFromRing(ptv, &synctv); + r = AFPReadAndDiscardFromRing(ptv, &synctv, discarded_pkts); } else { - r = AFPReadAndDiscard(ptv, &synctv); + r = AFPReadAndDiscard(ptv, &synctv, discarded_pkts); } SCLogDebug("Discarding on %s", ptv->tv->name); switch (r) { @@ -1292,6 +1298,7 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) time_t last_dump = 0; struct timeval current_time; int (*AFPReadFunc) (AFPThreadVars *); + uint64_t discarded_pkts = 0; ptv->slot = s->slot_next; @@ -1331,8 +1338,25 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) if (ptv->afp_state == AFP_STATE_UP) { SCLogDebug("Thread %s using socket %d", tv->name, ptv->socket); if ((ptv->flags & AFP_TPACKET_V3) != 0) { - AFPSynchronizeStart(ptv); + AFPSynchronizeStart(ptv, &discarded_pkts); } + /* let's reset counter as we will start the capture at the + * next function call */ +#ifdef PACKET_STATISTICS + struct tpacket_stats kstats; + socklen_t len = sizeof (struct tpacket_stats); + if (getsockopt(ptv->socket, SOL_PACKET, PACKET_STATISTICS, + &kstats, &len) > -1) { + uint64_t pkts = 0; + SCLogDebug("(%s) Kernel socket startup: Packets %" PRIu32 + ", dropped %" PRIu32 "", + ptv->tv->name, + kstats.tp_packets, kstats.tp_drops); + pkts = kstats.tp_packets - discarded_pkts - kstats.tp_drops; + StatsAddUI64(ptv->tv, ptv->capture_kernel_packets, pkts); + (void) SC_ATOMIC_ADD(ptv->livedev->pkts, pkts); + } +#endif } fds.fd = ptv->socket; From 8035d834678cfe82de597b9b0bc72a7f87b23df3 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 18 Apr 2016 14:24:08 +0200 Subject: [PATCH 1428/2553] af-packet: make mmap options parsing conditional Only parse them if mmap is activated. --- src/runmode-af-packet.c | 55 ++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 3deae4e3f6f9..5b48f7d56240 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -227,35 +227,40 @@ void *ParseAFPConfig(const char *iface) aconf->flags |= AFP_RING_MODE; } - (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "mmap-locked", (int *)&boolval); - if (boolval) { - SCLogInfo("Enabling locked memory for mmap on iface %s", - aconf->iface); - aconf->flags |= AFP_MMAP_LOCKED; - } - (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "tpacket-v3", (int *)&boolval); - if (boolval) { - if (strcasecmp(RunmodeGetActive(), "workers") == 0) { -#ifdef HAVE_TPACKET_V3 - SCLogInfo("Enabling tpacket v3 capture on iface %s", + if (aconf->flags & AFP_RING_MODE) { + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, + "mmap-locked", (int *)&boolval); + if (boolval) { + SCLogInfo("Enabling locked memory for mmap on iface %s", aconf->iface); - aconf->flags |= AFP_TPACKET_V3|AFP_RING_MODE; + aconf->flags |= AFP_MMAP_LOCKED; + } + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, + "tpacket-v3", (int *)&boolval); + if (boolval) { + if (strcasecmp(RunmodeGetActive(), "workers") == 0) { +#ifdef HAVE_TPACKET_V3 + SCLogInfo("Enabling tpacket v3 capture on iface %s", + aconf->iface); + aconf->flags |= AFP_TPACKET_V3|AFP_RING_MODE; #else - SCLogNotice("System too old for tpacket v3 switching to v2"); - aconf->flags |= AFP_RING_MODE; + SCLogNotice("System too old for tpacket v3 switching to v2"); + aconf->flags |= AFP_RING_MODE; #endif - } else { - SCLogError(SC_ERR_RUNMODE, - "tpacket v3 is only implemented for 'workers' running mode." - " Switching to tpacket v2."); - aconf->flags |= AFP_RING_MODE; + } else { + SCLogError(SC_ERR_RUNMODE, + "tpacket v3 is only implemented for 'workers' running mode." + " Switching to tpacket v2."); + aconf->flags |= AFP_RING_MODE; + } + } + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, + "use-emergency-flush", (int *)&boolval); + if (boolval) { + SCLogInfo("Enabling ring emergency flush on iface %s", + aconf->iface); + aconf->flags |= AFP_EMERGENCY_MODE; } - } - (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "use-emergency-flush", (int *)&boolval); - if (boolval) { - SCLogInfo("Enabling ring emergency flush on iface %s", - aconf->iface); - aconf->flags |= AFP_EMERGENCY_MODE; } From a40f08a21335e25d8b7aa1fe5182ec2687954b7d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 23 Apr 2016 00:30:39 +0200 Subject: [PATCH 1429/2553] af-packet: ask for hardware timestamp --- configure.ac | 4 ++++ src/source-af-packet.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/configure.ac b/configure.ac index e7237651a2f4..fc936abaec7d 100644 --- a/configure.ac +++ b/configure.ac @@ -1197,6 +1197,10 @@ [], [[#include #include ]]) + AC_CHECK_DECL([SOF_TIMESTAMPING_RAW_HARDWARE], + AC_DEFINE([HAVE_HW_TIMESTAMPING],[1],[Hardware timestamping support is available]), + [], + [[#include ]]) ]) # Netmap support diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 7e1aa5444acc..f6b6237f6830 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -94,6 +94,10 @@ #include #endif +#ifdef HAVE_HW_TIMESTAMPING +#include +#endif + #endif /* HAVE_AF_PACKET */ extern int max_pending_packets; @@ -1669,6 +1673,16 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) return AFP_FATAL_ERROR; } +#ifdef HAVE_HW_TIMESTAMPING + int req = SOF_TIMESTAMPING_RAW_HARDWARE; + if (setsockopt(ptv->socket, SOL_PACKET, PACKET_TIMESTAMP, (void *) &req, + sizeof(req)) < 0) { + SCLogWarning(SC_ERR_AFP_CREATE, + "Can't activate hardware timestamping on packet socket: %s", + strerror(errno)); + } +#endif + /* Allocate RX ring */ #ifdef HAVE_TPACKET_V3 if (ptv->flags & AFP_TPACKET_V3) { From ff05fb760b76d2ad3ea7b407af394ad6d13aa0dd Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 22 Apr 2016 19:50:10 +0200 Subject: [PATCH 1430/2553] af-packet: fix some typos in yaml --- suricata.yaml.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 842aa45b3d1f..4951c4dbe517 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -466,7 +466,7 @@ af-packet: defrag: yes # After Linux kernel 3.10 it is possible to activate the rollover option: if a socket is # full then kernel will send the packet on the next socket with room available. This option - # can minimize packet drop and increase the treated bandwith on single intensive flow. + # can minimize packet drop and increase the treated bandwidth on single intensive flow. #rollover: yes # To use the ring feature of AF_PACKET, set 'use-mmap' to yes use-mmap: yes @@ -478,7 +478,7 @@ af-packet: # Ring size will be computed with respect to max_pending_packets and number # of threads. You can set manually the ring size in number of packets by setting # the following value. If you are using flow cluster-type and have really network - # intensive single-flow you could want to set the ring-size independantly of the number + # intensive single-flow you could want to set the ring-size independently of the number # of threads: #ring-size: 2048 # Block size is used by tpacket_v3 only. It should set to a value high enough to contain @@ -508,7 +508,7 @@ af-packet: #checksum-checks: kernel # BPF filter to apply to this interface. The pcap filter syntax apply here. #bpf-filter: port 80 or udp - # You can use the following variables to activate AF_PACKET tap od IPS mode. + # You can use the following variables to activate AF_PACKET tap or IPS mode. # If copy-mode is set to ips or tap, the traffic coming to the current # interface will be copied to the copy-iface interface. If 'tap' is set, the # copy is complete. If 'ips' is set, the packet matching a 'drop' action From 88f5d7d16605d43afb44d134facf26239af48b45 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 26 Apr 2016 19:46:19 +0200 Subject: [PATCH 1431/2553] af-packet: print errno on mmap error --- src/source-af-packet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index f6b6237f6830..0581f00e72e4 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1751,7 +1751,8 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) ring_buf = mmap(0, ring_buflen, PROT_READ|PROT_WRITE, mmap_flag, ptv->socket, 0); if (ring_buf == MAP_FAILED) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); + SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap, error %s", + strerror(errno)); goto mmap_err; } #ifdef HAVE_TPACKET_V3 From 49612128f3b24b4224d58842cff1540fc9a42b08 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 26 Apr 2016 19:55:51 +0200 Subject: [PATCH 1432/2553] af-packet: use time() instead of GetTime() As we only use the second we don't need GetTime() which is slower and get us milliseconds. --- src/source-af-packet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 0581f00e72e4..8a429b78f1b5 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1300,7 +1300,7 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) int r; TmSlot *s = (TmSlot *)slot; time_t last_dump = 0; - struct timeval current_time; + time_t current_time; int (*AFPReadFunc) (AFPThreadVars *); uint64_t discarded_pkts = 0; @@ -1419,10 +1419,10 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) switch (r) { case AFP_READ_OK: /* Trigger one dump of stats every second */ - TimeGet(¤t_time); - if (current_time.tv_sec != last_dump) { + current_time = time(NULL); + if (current_time != last_dump) { AFPDumpCounters(ptv); - last_dump = current_time.tv_sec; + last_dump = current_time; } break; case AFP_READ_FAILURE: From f947539d7971d83f9b4cef0aeeb473ff3946a21d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 May 2016 10:41:45 +0200 Subject: [PATCH 1433/2553] af-packet: CentOS6 build fixes --- src/source-af-packet.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 8a429b78f1b5..29574f130832 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -911,6 +911,7 @@ int AFPReadFromRing(AFPThreadVars *ptv) SCReturnInt(AFP_READ_OK); } +#ifdef HAVE_TPACKET_V3 static inline void AFPFlushBlock(struct tpacket_block_desc *pbd) { pbd->hdr.bh1.block_status = TP_STATUS_KERNEL; @@ -998,6 +999,7 @@ static inline int AFPWalkBlock(AFPThreadVars *ptv, struct tpacket_block_desc *pb SCReturnInt(AFP_READ_OK); } +#endif /* HAVE_TPACKET_V3 */ /** * \brief AF packet read function for ring @@ -1169,6 +1171,7 @@ static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv, return 1; } +#ifdef HAVE_TPACKET_V3 if (ptv->flags & AFP_TPACKET_V3) { struct tpacket_block_desc *pbd; pbd = (struct tpacket_block_desc *) ptv->ring_v3[ptv->frame_offset].iov_base; @@ -1176,7 +1179,10 @@ static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv, AFPFlushBlock(pbd); ptv->frame_offset = (ptv->frame_offset + 1) % ptv->req3.tp_block_nr; return 1; - } else { + + } else +#endif + { /* Read packet from ring */ h.raw = (((union thdr **)ptv->ring_v2)[ptv->frame_offset]); if (h.raw == NULL) { @@ -1640,12 +1646,11 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) #ifdef HAVE_TPACKET_V3 if (ptv->flags & AFP_TPACKET_V3) { val = TPACKET_V3; - } else { + } else #endif + { val = TPACKET_V2; -#ifdef HAVE_TPACKET_V3 } -#endif if (getsockopt(ptv->socket, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { if (errno == ENOPROTOOPT) { if (ptv->flags & AFP_TPACKET_V3) { @@ -1660,11 +1665,12 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) return AFP_FATAL_ERROR; } + val = TPACKET_V2; +#ifdef HAVE_TPACKET_V3 if (ptv->flags & AFP_TPACKET_V3) { val = TPACKET_V3; - } else { - val = TPACKET_V2; } +#endif if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)) < 0) { SCLogError(SC_ERR_AFP_CREATE, From 3ffd19bdf51f14d99d7f988d327e20426dd6db8b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 May 2016 18:40:45 +0200 Subject: [PATCH 1434/2553] coverity CID 1362013: Control flow issues (NESTING_INDENT_MISMATCH) --- src/flow-worker.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flow-worker.c b/src/flow-worker.c index d6137944facb..778a4e10f6d8 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -115,9 +115,10 @@ static TmEcode FlowWorkerThreadDeinit(ThreadVars *tv, void *data) /* free DETECT */ void *detect_thread = SC_ATOMIC_GET(fw->detect_thread); - if (detect_thread != NULL) + if (detect_thread != NULL) { DetectEngineThreadCtxDeinit(tv, detect_thread); SC_ATOMIC_SET(fw->detect_thread, NULL); + } #if 0 // free OUTPUT #endif From 213f041c977c23710b986926433dfdf545e54814 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 May 2016 18:42:46 +0200 Subject: [PATCH 1435/2553] coverity: CID 1362012: Incorrect expression (EVALUATION_ORDER) --- src/app-layer-smtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 3f80d3e37a00..8bdb1f54ff44 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -374,7 +374,7 @@ static void SMTPPruneFiles(FileContainer *files) window, file_size, data_size); if (data_size > (window * 3)) { - uint64_t left_edge = left_edge = file_size - window; + uint64_t left_edge = file_size - window; SCLogDebug("file->content_inspected now %"PRIu64, left_edge); file->content_inspected = left_edge; } From 1df5acb001dfb85f61d7a530a748a641a4055903 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 20 May 2016 18:45:16 +0200 Subject: [PATCH 1436/2553] coverity: CID 1362011: Control flow issues (DEADCODE) --- src/app-layer-htp-body.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index b4ba2ffbeaf7..bfb9ba73af29 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -96,8 +96,9 @@ int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, if (body->first == NULL) { /* New chunk */ bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); - if (bd == NULL) - goto error; + if (bd == NULL) { + SCReturnInt(-1); + } StreamingBufferAppend(body->sb, &bd->sbseg, data, len); @@ -106,8 +107,9 @@ int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, body->content_len_so_far = len; } else { bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); - if (bd == NULL) - goto error; + if (bd == NULL) { + SCReturnInt(-1); + } StreamingBufferAppend(body->sb, &bd->sbseg, data, len); @@ -119,12 +121,6 @@ int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, SCLogDebug("body %p", body); SCReturnInt(0); - -error: - if (bd != NULL) { - HTPFree(bd, sizeof(HtpBodyChunk)); - } - SCReturnInt(-1); } /** From 133485937952d8ed106eae840f517edf53024e19 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 23 Sep 2015 16:34:40 +0200 Subject: [PATCH 1437/2553] dns: add support for sshfp records Update parser to process the records. Update json output to log it. --- src/app-layer-dns-common.c | 15 +++++++++++++++ src/app-layer-dns-common.h | 1 - src/output-json-dns.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 16a2252b4cb9..cfb441451bf3 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -1005,6 +1005,21 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ data += ntohs(head->len); break; } + case DNS_RECORD_TYPE_SSHFP: + { + /* data here should be: + * [1 byte algo][1 byte type][var bytes fingerprint] + * As we currently can't store each of those in the state, + * we just store the raw data an let the output/detect + * code figure out what to do with it. */ + + DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, + ntohs(head->type), ntohs(head->class), ntohl(head->ttl), + data, ntohs(head->len), ntohs(dns_header->tx_id)); + + data += ntohs(head->len); + break; + } default: /* unsupported record */ { DNSStoreAnswerInState(dns_state, list, NULL, 0, diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index a3bdd9351d8b..184fb26408d7 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -92,7 +92,6 @@ #define DNS_RECORD_TYPE_ANY 255 #define DNS_RECORD_TYPE_URI 256 - #define DNS_RCODE_NOERROR 0 #define DNS_RCODE_FORMERR 1 #define DNS_RCODE_SERVFAIL 2 diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 87b276521bfc..db8ae40f17d5 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -172,6 +172,34 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, } else { json_object_set_new(js, "rdata", json_string("")); } + } else if (entry->type == DNS_RECORD_TYPE_SSHFP) { + if (entry->data_len > 2) { + /* get algo and type */ + uint8_t algo = *ptr; + uint8_t fptype = *(ptr+1); + + /* turn fp raw buffer into a nice :-separate hex string */ + uint16_t fp_len = (entry->data_len - 2); + uint8_t *dptr = ptr+2; + uint32_t output_len = fp_len * 2 + 1; // create c-string, so add space for 0. + char hexstring[output_len], *p = hexstring; + memset(hexstring, 0x00, output_len); + + uint16_t x; + for (x = 0; x < fp_len; x++, p += 3) { + snprintf(p, 4, x == fp_len - 1 ? "%02x" : "%02x:", dptr[x]); + } + + /* wrap the whole thing in it's own structure */ + json_t *hjs = json_object(); + if (hjs != NULL) { + json_object_set_new(hjs, "fingerprint", json_string(hexstring)); + json_object_set_new(hjs, "algo", json_integer(algo)); + json_object_set_new(hjs, "type", json_integer(fptype)); + + json_object_set_new(js, "sshfp", hjs); + } + } } } From 6286e7055521875a150c7c7c5ff0a715ede27a36 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 22 Apr 2016 12:57:41 +0200 Subject: [PATCH 1438/2553] ac: allow use of 31bits of pid space instead of 16 --- src/util-mpm-ac.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 62100d41a737..095cde6d5a79 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -89,6 +89,10 @@ void SCACRegisterTests(void); #define STATE_QUEUE_CONTAINER_SIZE 65536 +#define AC_CASE_MASK 0x80000000 +#define AC_PID_MASK 0x7FFFFFFF +#define AC_CASE_BIT 31 + static int construct_both_16_and_32_state_tables = 0; /** @@ -674,8 +678,8 @@ static inline void SCACInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { - ctx->output_table[state].pids[k] &= 0x0000FFFF; - ctx->output_table[state].pids[k] |= 1 << 16; + ctx->output_table[state].pids[k] &= AC_PID_MASK; + ctx->output_table[state].pids[k] |= ((uint32_t)1 << AC_CASE_BIT); } } } @@ -1047,8 +1051,8 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; uint32_t k; for (k = 0; k < no_of_entries; k++) { - if (pids[k] & 0xFFFF0000) { - uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (pids[k] & AC_CASE_MASK) { + uint32_t lower_pid = pids[k] & AC_PID_MASK; if (SCMemcmp(pid_pat_list[lower_pid].cs, buf + i - pid_pat_list[lower_pid].patlen + 1, pid_pat_list[lower_pid].patlen) != 0) { @@ -1087,7 +1091,7 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; uint32_t k; for (k = 0; k < no_of_entries; k++) { - if (pids[k] & 0xFFFF0000) { + if (pids[k] & AC_CASE_MASK) { uint32_t lower_pid = pids[k] & 0x0000FFFF; if (SCMemcmp(pid_pat_list[lower_pid].cs, buf + i - pid_pat_list[lower_pid].patlen + 1, @@ -1587,7 +1591,7 @@ uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, * don't copy the pattern id into the pattern_id_array. That's * the only change */ for (k = 0; k < no_of_entries; k++) { - if (pids[k] & 0xFFFF0000) { + if (pids[k] & AC_CASE_MASK) { uint32_t lower_pid = pids[k] & 0x0000FFFF; if (SCMemcmp(pid_pat_list[lower_pid].cs, buf + offset - pid_pat_list[lower_pid].patlen + 1, From ea23b857765ffdf188a7bf097817f2fac7b7fc76 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 21 May 2016 14:22:13 +0200 Subject: [PATCH 1439/2553] flow worker: set up decoder thread vars --- src/flow-worker.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/flow-worker.c b/src/flow-worker.c index 778a4e10f6d8..8bb3043ac0b6 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -50,6 +50,8 @@ typedef DetectEngineThreadCtx *DetectEngineThreadCtxPtr; typedef struct FlowWorkerThreadData_ { + DecodeThreadVars *dtv; + union { StreamTcpThread *stream_thread; void *stream_thread_ptr; @@ -85,6 +87,13 @@ static TmEcode FlowWorkerThreadInit(ThreadVars *tv, void *initdata, void **data) SC_ATOMIC_INIT(fw->detect_thread); SC_ATOMIC_SET(fw->detect_thread, NULL); + fw->dtv = DecodeThreadVarsAlloc(tv); + if (fw->dtv == NULL) { + SC_ATOMIC_DESTROY(fw->detect_thread); + SCFree(fw); + return TM_ECODE_FAILED; + } + /* setup TCP */ BUG_ON(StreamTcpThreadInit(tv, NULL, &fw->stream_thread_ptr) != TM_ECODE_OK); @@ -110,6 +119,8 @@ static TmEcode FlowWorkerThreadDeinit(ThreadVars *tv, void *data) { FlowWorkerThreadData *fw = data; + DecodeThreadVarsFree(tv, fw->dtv); + /* free TCP */ StreamTcpThreadDeinit(tv, (void *)fw->stream_thread); @@ -147,7 +158,7 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac /* handle Flow */ if (p->flags & PKT_WANTS_FLOW) { - FlowHandlePacket(tv, NULL, p); //TODO what to do about decoder thread vars + FlowHandlePacket(tv, fw->dtv, p); if (likely(p->flow != NULL)) { DEBUG_ASSERT_FLOW_LOCKED(p->flow); FlowUpdate(tv, fw->stream_thread, p); From 221cb93024bd922084cec32b9be54f7ba120cdbb Mon Sep 17 00:00:00 2001 From: Arturo Borrero Gonzalez Date: Mon, 23 May 2016 12:32:34 +0200 Subject: [PATCH 1440/2553] src/: fix typo: receieved vs received Reported by Debian's lintian tool. Signed-off-by: Arturo Borrero Gonzalez --- src/detect-engine-address.c | 2 +- src/detect-engine-port.c | 2 +- src/suricata.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 5f601309d2f4..8c07d08fc855 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -807,7 +807,7 @@ int DetectAddressSetup(DetectAddressHead *gh, char *s) * that are negated. * \param s Pointer to the character string holding the address to be * parsed. - * \param negate Flag that indicates if the receieved address string is negated + * \param negate Flag that indicates if the received address string is negated * or not. 0 if it is not, 1 it it is. * * \retval 0 On successfully parsing. diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index d545dc16d377..f1b9d106b94a 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -952,7 +952,7 @@ static int DetectPortParseInsertString(DetectPort **head, char *s) * that are negated. * \param s Pointer to the character string holding the port to be * parsed. - * \param negate Flag that indicates if the receieved address string is negated + * \param negate Flag that indicates if the received address string is negated * or not. 0 if it is not, 1 it it is. * * \retval 0 On successfully parsing. diff --git a/src/suricata.c b/src/suricata.c index 71a742c421b8..ecb1690e1eaf 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1623,7 +1623,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) LiveRegisterDevice(optarg); #else SCLogError(SC_ERR_DAG_REQUIRED, "libdag and a DAG card are required" - " to receieve packets using --dag."); + " to receive packets using --dag."); return TM_ECODE_FAILED; #endif /* HAVE_DAG */ } From 5e7f617b7b453dce80e84059f97ba100a83baf1d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 24 May 2016 16:57:16 +0200 Subject: [PATCH 1441/2553] isdataat: remove unused code --- src/detect-isdataat.c | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 1329839ab8d0..0d81d70c5424 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -55,7 +55,6 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIsdataatMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); int DetectIsdataatSetup (DetectEngineCtx *, Signature *, char *); void DetectIsdataatRegisterTests(void); void DetectIsdataatFree(void *); @@ -68,7 +67,8 @@ void DetectIsdataatRegister(void) sigmatch_table[DETECT_ISDATAAT].name = "isdataat"; sigmatch_table[DETECT_ISDATAAT].desc = "check if there is still data at a specific part of the payload"; sigmatch_table[DETECT_ISDATAAT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Isadataat"; - sigmatch_table[DETECT_ISDATAAT].Match = DetectIsdataatMatch; + /* match is handled in DetectEngineContentInspection() */ + sigmatch_table[DETECT_ISDATAAT].Match = NULL; sigmatch_table[DETECT_ISDATAAT].Setup = DetectIsdataatSetup; sigmatch_table[DETECT_ISDATAAT].Free = DetectIsdataatFree; sigmatch_table[DETECT_ISDATAAT].RegisterTests = DetectIsdataatRegisterTests; @@ -78,37 +78,6 @@ void DetectIsdataatRegister(void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/** - * \brief This function is used to match isdataat on a packet - * \todo We need to add support for rawbytes - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectIsdataatData - * - * \retval 0 no match - * \retval 1 match - */ -int DetectIsdataatMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) -{ - const DetectIsdataatData *idad = (const DetectIsdataatData *)ctx; - - SCLogDebug("payload_len: %u , dataat? %u ; relative? %u...", p->payload_len,idad->dataat,idad->flags &ISDATAAT_RELATIVE); - - /* Relative to the last matched content is not performed here, returning match (content should take care of this)*/ - if (idad->flags & ISDATAAT_RELATIVE) - return 1; - - /* its not relative and we have more data in the packet than the offset of isdataat */ - if (p->payload_len >= idad->dataat) { - SCLogDebug("matched with payload_len: %u , dataat? %u ; relative? %u...", p->payload_len,idad->dataat,idad->flags &ISDATAAT_RELATIVE); - return 1; - } - - return 0; -} - /** * \brief This function is used to parse isdataat options passed via isdataat: keyword * From bfa90a64d565065d01d37438357f751c2998d252 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 27 May 2016 09:16:02 +0200 Subject: [PATCH 1442/2553] prscript: fix error handling Last result was used as global result. --- qa/prscript.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qa/prscript.py b/qa/prscript.py index 840d59526a00..21e989433131 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -343,14 +343,14 @@ def RmContainer(): else: sys.exit(0) -res = 0 +buildres = 0 if args.docker: while len(buildids): up_buildids = copy.copy(buildids) for build in buildids: ret = GetBuildStatus(build, buildids[build], builder_name = build) if ret == -1: - res = -1 + buildres = -1 up_buildids.pop(build, None) if len(up_buildids): remains = " (remaining builds: " + ', '.join(up_buildids.keys()) + ")" @@ -376,8 +376,10 @@ def RmContainer(): else: for build in buildids: res = WaitForBuildResult(build, buildids[build], builder_name = build) + if res == -1: + buildres = -1 -if res == 0: +if buildres == 0: if not args.norebase and not args.docker: print "You can copy/paste following lines into github PR" for build in buildids: From b23d74ac883293a65a78477becc070aa2c1baf0e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 26 May 2016 11:44:19 -0600 Subject: [PATCH 1443/2553] tls-json-log: register module as tls-json-log, not dns-json-log Fixes issue: https://redmine.openinfosecfoundation.org/issues/1792 where dns-json-log would not log any data. --- src/output-json-tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index adb0a4e1f603..a7512a097c23 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -318,7 +318,7 @@ void TmModuleJsonTlsLogRegister (void) tmm_modules[TMM_JSONTLSLOG].flags = TM_FLAG_LOGAPI_TM; /* register as separate module */ - OutputRegisterTxModuleWithProgress("JsonTlsLog", "dns-json-log", + OutputRegisterTxModuleWithProgress("JsonTlsLog", "tls-json-log", OutputTlsLogInit, ALPROTO_TLS, JsonTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE); From 2a5f487a16ac2390805459efad63bb556a8c0d84 Mon Sep 17 00:00:00 2001 From: Aleksey Katargin Date: Wed, 25 May 2016 09:45:07 +0500 Subject: [PATCH 1444/2553] netmap: close sw ring before hw rings Fix issue #1714 --- src/source-netmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index 75f8d5d81508..fdb4c707e7f9 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -474,7 +474,8 @@ static int NetmapClose(NetmapDevice *dev) pdev->ref--; if (!pdev->ref) { munmap(pdev->mem, pdev->memsize); - for (int i = 0; i <= pdev->rings_cnt; i++) { + // First close SW ring (https://github.com/luigirizzo/netmap/issues/144) + for (int i = pdev->rings_cnt; i >= 0; i--) { NetmapRing *pring = &pdev->rings[i]; close(pring->fd); SCSpinDestroy(&pring->tx_lock); From a765cfde191aaa37b797d8579d523a45a9fe5895 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Mon, 23 May 2016 14:06:00 +1000 Subject: [PATCH 1445/2553] mpm-hs,spm-hs: don't call hs_scan() for zero bytes --- src/util-mpm-hs.c | 4 ++++ src/util-spm-hs.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index 8b993ae16089..ae0de5e0a9f0 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -919,6 +919,10 @@ uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, SCHSThreadCtx *hs_thread_ctx = (SCHSThreadCtx *)(mpm_thread_ctx->ctx); const PatternDatabase *pd = ctx->pattern_db; + if (unlikely(buflen == 0)) { + return 0; + } + SCHSCallbackCtx cctx = {.ctx = ctx, .pmq = pmq, .match_count = 0}; /* scratch should have been cloned from g_scratch_proto at thread init. */ diff --git a/src/util-spm-hs.c b/src/util-spm-hs.c index 5ca0d333d0b9..898b6e9067a4 100644 --- a/src/util-spm-hs.c +++ b/src/util-spm-hs.c @@ -141,6 +141,10 @@ static uint8_t *HSScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, const SpmHsCtx *sctx = ctx->ctx; hs_scratch_t *scratch = thread_ctx->ctx; + if (unlikely(haystack_len == 0)) { + return NULL; + } + uint64_t match_offset = UINT64_MAX; hs_error_t err = hs_scan(sctx->db, (const char *)haystack, haystack_len, 0, scratch, MatchEvent, &match_offset); From 24a1488591e67c52db7ef0ebc2c0fd020bcf9db6 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Mon, 23 May 2016 13:57:50 +1000 Subject: [PATCH 1446/2553] mpm-hs: make errors from hs_scan() fatal Hyperscan will only return an error at scan time if the database or scratch region are corrupted, which should provoke a fatal error. --- src/util-mpm-hs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index ae0de5e0a9f0..61a6c4cf89cc 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -933,8 +933,11 @@ uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, hs_error_t err = hs_scan(pd->hs_db, (const char *)buf, buflen, 0, scratch, SCHSMatchEvent, &cctx); if (err != HS_SUCCESS) { - SCLogError(SC_ERR_FATAL, "Scanning with Hyperscan returned error %d", - err); + /* An error value (other than HS_SCAN_TERMINATED) from hs_scan() + * indicates that it was passed an invalid database or scratch region, + * which is not something we can recover from at scan time. */ + SCLogError(SC_ERR_FATAL, "Hyperscan returned error %d", err); + exit(EXIT_FAILURE); } else { ret = cctx.match_count; } From 68ddcdccde5d4d6435d405d6ebaa64041fe54583 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Mon, 23 May 2016 11:06:39 +1000 Subject: [PATCH 1447/2553] app-layer-smtp: init mpm thread ctx after prepare This allows the Hyperscan MPM to correctly allocate scratch. --- src/app-layer-smtp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 8bdb1f54ff44..98870a8e2447 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1437,13 +1437,6 @@ static void SMTPSetMpmState(void) memset(smtp_mpm_ctx, 0, sizeof(MpmCtx)); MpmInitCtx(smtp_mpm_ctx, SMTP_MPM); - smtp_mpm_thread_ctx = SCMalloc(sizeof(MpmThreadCtx)); - if (unlikely(smtp_mpm_thread_ctx == NULL)) { - exit(EXIT_FAILURE); - } - memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitThreadCtx(smtp_mpm_thread_ctx, SMTP_MPM); - uint32_t i = 0; for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) { SCEnumCharMap *map = &smtp_reply_map[i]; @@ -1454,6 +1447,13 @@ static void SMTPSetMpmState(void) } mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx); + + smtp_mpm_thread_ctx = SCMalloc(sizeof(MpmThreadCtx)); + if (unlikely(smtp_mpm_thread_ctx == NULL)) { + exit(EXIT_FAILURE); + } + memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitThreadCtx(smtp_mpm_thread_ctx, SMTP_MPM); } int SMTPStateGetEventInfo(const char *event_name, From 31d8d4b0a1cf686d1271c8781c160a7e69bb932e Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Mon, 23 May 2016 11:58:01 +1000 Subject: [PATCH 1448/2553] detect-engine: adjust unit tests for hs mpm The Hyperscan MPM does match deduplication internally (using HS_FLAG_SINGLEMATCH) and only returns the number of unique matches, unlike AC. --- src/detect-engine-hhd.c | 4 ++-- src/detect-engine-hrhd.c | 4 ++-- src/detect-engine-hrud.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 9419989938fd..d5863ecf4b84 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -2016,8 +2016,8 @@ static int DetectEngineHttpHeaderTest18(void) /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); uint32_t r = HttpHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); - if (r != 2) { - printf("expected result 2, got %"PRIu32": ", r); + if (r < 1) { + printf("expected result >= 1, got %"PRIu32": ", r); goto end; } diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 7395cbfa6177..e4d6c5e20a40 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -1888,8 +1888,8 @@ static int DetectEngineHttpRawHeaderTest18(void) /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); uint32_t r = HttpRawHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); - if (r != 2) { - printf("expected result 2, got %"PRIu32": ", r); + if (r < 1) { + printf("expected result >= 1, got %"PRIu32": ", r); goto end; } diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 38d7ea7867ec..352923593e09 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -2448,8 +2448,8 @@ static int DetectEngineHttpRawUriTest20(void) /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 2) { - printf("expected 2 result, got %"PRIu32": ", r); + if (r < 1) { + printf("expected result >= 1, got %"PRIu32": ", r); goto end; } From 88b50d2c34f49eb8bb21a7b4556808f52a8f2c97 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Mon, 23 May 2016 13:42:05 +1000 Subject: [PATCH 1449/2553] app-layer-detect-proto: pass mpm_ctx to DestroyCtx The MPM DestroyCtx function accepts the MpmCtx, not the ctx pointer inside it. --- src/app-layer-detect-proto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index aeed07259a60..c9b2a5e33eb9 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1558,7 +1558,7 @@ int AppLayerProtoDetectDeSetup(void) for (ipproto_map = 0; ipproto_map < FLOW_PROTO_DEFAULT; ipproto_map++) { for (dir = 0; dir < 2; dir++) { pm_ctx = &alpd_ctx.ctx_ipp[ipproto_map].ctx_pm[dir]; - mpm_table[pm_ctx->mpm_ctx.mpm_type].DestroyCtx(pm_ctx->mpm_ctx.ctx); + mpm_table[pm_ctx->mpm_ctx.mpm_type].DestroyCtx(&pm_ctx->mpm_ctx); for (id = 0; id < pm_ctx->max_sig_id; id++) { sig = pm_ctx->map[id]; AppLayerProtoDetectPMFreeSignature(sig); From 8c6deecc55117d5685e26283661640e02e7005fa Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Mon, 23 May 2016 13:46:24 +1000 Subject: [PATCH 1450/2553] app-layer-detect-proto: use mpm-algo Use the matcher configured by the user rather than hard-coding MPM_AC. --- src/app-layer-detect-proto.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index c9b2a5e33eb9..fb25b5b35209 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1528,6 +1528,8 @@ int AppLayerProtoDetectSetup(void) memset(&alpd_ctx, 0, sizeof(alpd_ctx)); uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + uint16_t mpm_matcher = PatternMatchDefaultMatcher(); + alpd_ctx.spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); if (alpd_ctx.spm_global_thread_ctx == NULL) { SCLogError(SC_ERR_FATAL, "Unable to alloc SpmGlobalThreadCtx."); @@ -1536,7 +1538,7 @@ int AppLayerProtoDetectSetup(void) for (i = 0; i < FLOW_PROTO_DEFAULT; i++) { for (j = 0; j < 2; j++) { - MpmInitCtx(&alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx, MPM_AC); + MpmInitCtx(&alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx, mpm_matcher); } } SCReturnInt(0); From c9d0d6f69855c3aba2ee148a092618e7d5453096 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Mon, 23 May 2016 10:46:53 +1000 Subject: [PATCH 1451/2553] mpm: add "auto" default for mpm-algo Setting mpm-algo to "auto" will use "hs" if Suricata was built against Hyperscan, and "ac" otherwise (or "ac-tile" on Tilera platforms). --- src/detect-engine-mpm.c | 3 +++ src/detect-engine.c | 2 +- src/util-mpm.h | 12 +++++++++--- suricata.yaml.in | 15 ++++++++++++--- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 04cca7844f7b..fe469b4a08a2 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -335,6 +335,9 @@ uint16_t PatternMatchDefaultMatcher(void) uint16_t u; if (mpm_algo != NULL) { + if (strcmp("auto", mpm_algo) == 0) { + goto done; + } for (u = 0; u < MPM_TABLE_SIZE; u++) { if (mpm_table[u].name == NULL) continue; diff --git a/src/detect-engine.c b/src/detect-engine.c index a319a0ea329b..dea169ed3ff4 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1041,7 +1041,7 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) if (sgh_mpm_context == NULL || strcmp(sgh_mpm_context, "auto") == 0) { /* for now, since we still haven't implemented any intelligence into * understanding the patterns and distributing mpm_ctx across sgh */ - if (de_ctx->mpm_matcher == DEFAULT_MPM || de_ctx->mpm_matcher == MPM_AC_TILE || + if (de_ctx->mpm_matcher == MPM_AC || de_ctx->mpm_matcher == MPM_AC_TILE || #ifdef BUILD_HYPERSCAN de_ctx->mpm_matcher == MPM_HS || #endif diff --git a/src/util-mpm.h b/src/util-mpm.h index 2c165bedab03..4930f0a6b62c 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -43,10 +43,16 @@ enum { MPM_TABLE_SIZE, }; -#ifdef __tile__ -#define DEFAULT_MPM MPM_AC_TILE +/* MPM matcher to use by default, i.e. when "mpm-algo" is set to "auto". + * If Hyperscan is available, use it. Otherwise, use AC. */ +#ifdef BUILD_HYPERSCAN +# define DEFAULT_MPM MPM_HS #else -#define DEFAULT_MPM MPM_AC +# ifdef __tile__ +# define DEFAULT_MPM MPM_AC_TILE +# else +# define DEFAULT_MPM MPM_AC +# endif #endif /* Internal Pattern Index: 0 to pattern_cnt-1 */ diff --git a/suricata.yaml.in b/suricata.yaml.in index 4951c4dbe517..74a3b95d9f40 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -722,8 +722,17 @@ cuda: cuda-streams: 2 # Select the multi pattern algorithm you want to run for scan/search the -# in the engine. The supported algorithms are b2g, b3g, wumanber, -# ac, ac-bs and ac-gfbs. +# in the engine. +# +# The supported algorithms are: +# "ac" - Aho-Corasick, default implementation +# "ac-bs" - Aho-Corasick, reduced memory implementation +# "ac-cuda" - Aho-Corasick, CUDA implementation +# "ac-tile" - Aho-Corasick, optimized for Tilera architecture +# "hs" - Hyperscan, available when built with Hyperscan support +# +# The default mpm-algo value of "auto" will use "hs" if Hyperscan is available, +# "ac-tile" on Tilera platforms, and "ac" otherwise. # # The mpm you choose also decides the distribution of mpm contexts for # signature groups, specified by the conf - "detect.sgh-mpm-context". @@ -736,7 +745,7 @@ cuda: # compiled with --enable-cuda: b2g_cuda. Make sure to update your # max-pending-packets setting above as well if you use b2g_cuda. -mpm-algo: ac +mpm-algo: auto # Select the matching algorithm you want to use for single-pattern searches. # From d807bf4e8a837db07830c6932d162f9758c5ad81 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Mon, 23 May 2016 14:22:30 +1000 Subject: [PATCH 1452/2553] detect-engine: log MPM/SPM matchers being used --- src/detect-engine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index dea169ed3ff4..3d6f51350516 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -839,7 +839,9 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) } de_ctx->mpm_matcher = PatternMatchDefaultMatcher(); + SCLogInfo("using MPM matcher: %s", mpm_table[de_ctx->mpm_matcher].name); de_ctx->spm_matcher = SinglePatternMatchDefaultMatcher(); + SCLogInfo("using SPM matcher: %s", spm_table[de_ctx->spm_matcher].name); de_ctx->spm_global_thread_ctx = SpmInitGlobalThreadCtx(de_ctx->spm_matcher); if (de_ctx->spm_global_thread_ctx == NULL) { From 7a0dbc6f9f39d4527f4f927347196c9a757917dc Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Wed, 25 May 2016 11:47:24 +1000 Subject: [PATCH 1453/2553] app-layer-smtp: free mpm contexts on shutdown Adds a cleanup function for the SMTP parser that destroys the MPM context and MPM thread context it uses. Also marks smtp_mpm_thread_ctx static. --- src/app-layer-parser.c | 2 ++ src/app-layer-smtp.c | 22 +++++++++++++++++++++- src/app-layer-smtp.h | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 018214cc0723..14942d167939 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -191,6 +191,8 @@ int AppLayerParserDeSetup(void) { SCEnter(); + SMTPParserCleanup(); + SCReturnInt(0); } diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 98870a8e2447..b68fa17fff44 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -155,7 +155,7 @@ SCEnumCharMap smtp_decoder_event_table[ ] = { #define SMTP_MPM DEFAULT_MPM static MpmCtx *smtp_mpm_ctx = NULL; -MpmThreadCtx *smtp_mpm_thread_ctx; +static MpmThreadCtx *smtp_mpm_thread_ctx = NULL; /* smtp reply codes. If an entry is made here, please make a simultaneous * entry in smtp_reply_map */ @@ -1456,6 +1456,18 @@ static void SMTPSetMpmState(void) MpmInitThreadCtx(smtp_mpm_thread_ctx, SMTP_MPM); } +static void SMTPFreeMpmState(void) +{ + if (smtp_mpm_thread_ctx != NULL) { + mpm_table[SMTP_MPM].DestroyThreadCtx(smtp_mpm_ctx, smtp_mpm_thread_ctx); + smtp_mpm_thread_ctx = NULL; + } + if (smtp_mpm_ctx != NULL) { + mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx); + smtp_mpm_ctx = NULL; + } +} + int SMTPStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type) { @@ -1677,6 +1689,14 @@ void RegisterSMTPParsers(void) return; } +/** + * \brief Free memory allocated for global SMTP parser state. + */ +void SMTPParserCleanup(void) +{ + SMTPFreeMpmState(); +} + /***************************************Unittests******************************/ #ifdef UNITTESTS diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 1f925c625ed3..9285f6217c58 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -169,6 +169,7 @@ extern SMTPConfig smtp_config; int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state); void *SMTPStateAlloc(void); void RegisterSMTPParsers(void); +void SMTPParserCleanup(void); void SMTPParserRegisterTests(void); #endif /* __APP_LAYER_SMTP_H__ */ From eec66c7b4f7d8d3272d8229c9164f0b4c4955426 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 May 2016 12:14:16 +0200 Subject: [PATCH 1454/2553] smtp: improve thread data use The SMTP app layer used a thread local data structure for the mpm in reply parsing, but it only used a pmq. The MpmThreadCtx was actually global. Until now this wasn't really noticed because non of the mpm's used the thread ctx. Hyperscan does use it however. This patch creates a new structure SMTPThreadCtx, which contains both the pmq and the mpm thread ctx. It's passed directly to the reply parsing function instead of storing a pointer to it in the SMTPState. Additionally fix a small memory leak warning wrt the smtp global mpm state. --- src/app-layer-smtp.c | 70 ++++++++++++++++++++++++++------------------ src/app-layer-smtp.h | 1 - 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index b68fa17fff44..6c2aede9b34e 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -152,10 +152,14 @@ SCEnumCharMap smtp_decoder_event_table[ ] = { { NULL, -1 }, }; +typedef struct SMTPThreadCtx_ { + MpmThreadCtx *smtp_mpm_thread_ctx; + PatternMatcherQueue *pmq; +} SMTPThreadCtx; + #define SMTP_MPM DEFAULT_MPM static MpmCtx *smtp_mpm_ctx = NULL; -static MpmThreadCtx *smtp_mpm_thread_ctx = NULL; /* smtp reply codes. If an entry is made here, please make a simultaneous * entry in smtp_reply_map */ @@ -887,12 +891,12 @@ static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f, } static int SMTPProcessReply(SMTPState *state, Flow *f, - AppLayerParserState *pstate) + AppLayerParserState *pstate, + SMTPThreadCtx *td) { SCEnter(); uint64_t reply_code = 0; - PatternMatcherQueue *pmq = state->thread_local_data; /* the reply code has to contain at least 3 bytes, to hold the 3 digit * reply code */ @@ -920,9 +924,9 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, /* I don't like this pmq reset here. We'll devise a method later, that * should make the use of the mpm very efficient */ - PmqReset(pmq); - int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, smtp_mpm_thread_ctx, - pmq, state->current_line, + PmqReset(td->pmq); + int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, td->smtp_mpm_thread_ctx, + td->pmq, state->current_line, 3); if (mpm_cnt == 0) { /* set decoder event - reply code invalid */ @@ -931,7 +935,7 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, state->current_line[0], state->current_line[1], state->current_line[2]); SCReturnInt(-1); } - reply_code = smtp_reply_map[pmq->rule_id_array[0]].enum_value; + reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value; if (state->cmds_idx == state->cmds_cnt) { if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { @@ -1240,7 +1244,7 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, static int SMTPParse(int direction, Flow *f, SMTPState *state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, - PatternMatcherQueue *local_data) + SMTPThreadCtx *thread_data) { SCEnter(); @@ -1253,7 +1257,6 @@ static int SMTPParse(int direction, Flow *f, SMTPState *state, state->input = input; state->input_len = input_len; state->direction = direction; - state->thread_local_data = local_data; /* toserver */ if (direction == 0) { @@ -1265,7 +1268,7 @@ static int SMTPParse(int direction, Flow *f, SMTPState *state, /* toclient */ } else { while (SMTPGetLine(state) >= 0) { - if (SMTPProcessReply(state, f, pstate) == -1) + if (SMTPProcessReply(state, f, pstate, thread_data) == -1) SCReturnInt(-1); } } @@ -1343,20 +1346,40 @@ static void SMTPStringFree(SMTPString *str) static void *SMTPLocalStorageAlloc(void) { /* needed by the mpm */ - PatternMatcherQueue *pmq = SCMalloc(sizeof(PatternMatcherQueue)); - if (unlikely(pmq == NULL)) { + SMTPThreadCtx *td = SCCalloc(1, sizeof(*td)); + if (td == NULL) { + exit(EXIT_FAILURE); + } + + td->pmq = SCCalloc(1, sizeof(*td->pmq)); + if (td->pmq == NULL) { exit(EXIT_FAILURE); } - PmqSetup(pmq); + PmqSetup(td->pmq); - return pmq; + td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx)); + if (unlikely(td->smtp_mpm_thread_ctx == NULL)) { + exit(EXIT_FAILURE); + } + MpmInitThreadCtx(td->smtp_mpm_thread_ctx, SMTP_MPM); + return td; } -static void SMTPLocalStorageFree(void *pmq) +static void SMTPLocalStorageFree(void *ptr) { - if (pmq != NULL) { - PmqFree(pmq); - SCFree(pmq); + SMTPThreadCtx *td = ptr; + if (td != NULL) { + if (td->pmq != NULL) { + PmqFree(td->pmq); + SCFree(td->pmq); + } + + if (td->smtp_mpm_thread_ctx != NULL) { + mpm_table[SMTP_MPM].DestroyThreadCtx(smtp_mpm_ctx, td->smtp_mpm_thread_ctx); + SCFree(td->smtp_mpm_thread_ctx); + } + + SCFree(td); } return; @@ -1448,22 +1471,13 @@ static void SMTPSetMpmState(void) mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx); - smtp_mpm_thread_ctx = SCMalloc(sizeof(MpmThreadCtx)); - if (unlikely(smtp_mpm_thread_ctx == NULL)) { - exit(EXIT_FAILURE); - } - memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitThreadCtx(smtp_mpm_thread_ctx, SMTP_MPM); } static void SMTPFreeMpmState(void) { - if (smtp_mpm_thread_ctx != NULL) { - mpm_table[SMTP_MPM].DestroyThreadCtx(smtp_mpm_ctx, smtp_mpm_thread_ctx); - smtp_mpm_thread_ctx = NULL; - } if (smtp_mpm_ctx != NULL) { mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx); + SCFree(smtp_mpm_ctx); smtp_mpm_ctx = NULL; } } diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 9285f6217c58..face8f93fa64 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -115,7 +115,6 @@ typedef struct SMTPState_ { /** length of the line in current_line. Doesn't include the delimiter */ int32_t current_line_len; uint8_t current_line_delimiter_len; - PatternMatcherQueue *thread_local_data; /** used to indicate if the current_line buffer is a malloced buffer. We * use a malloced buffer, if a line is fragmented */ From 333f2cb3107fc05859cafff7a3d1127795fbc541 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 May 2016 14:54:36 +0200 Subject: [PATCH 1455/2553] drmemory: broader suppressions for hyperscan --- qa/drmemory.suppress | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/qa/drmemory.suppress b/qa/drmemory.suppress index 30fa0d5d85e7..cfd3fad137e2 100644 --- a/qa/drmemory.suppress +++ b/qa/drmemory.suppress @@ -31,45 +31,13 @@ UNINITIALIZED READ name=Hyperscan false positives due to DrMemory limitations 1 ... libhs.so.*!hs_compile_ext_multi -suricata!SigGroupBuild -... -suricata!main +* UNINITIALIZED READ name=Hyperscan false positives due to DrMemory limitations 2 ... -libhs.so.*!hs_compile_ext_multi -suricata!SigGroupBuild -... -libc.so.6!__clone - -UNINITIALIZED READ -name=Hyperscan false positives due to DrMemory limitations 3 -... -libhs.so.*!hs_compile -suricata!SpmInitCtx -... -suricata!main - -UNINITIALIZED READ -name=Hyperscan false positives due to DrMemory limitations 4 -... libhs.so.*!hs_compile -suricata!SpmInitCtx -... -libc.so.6!__clone - -UNINITIALIZED READ -name=Hyperscan false positives due to DrMemory limitations 5 -... -libhs.so.*!hs_compile -suricata!HSBuildDatabase - -UNINITIALIZED READ -name=Hyperscan false positives due to DrMemory limitations 6 -... -libhs.so.*!hs_compile -suricata!HSBuildDatabase +* WARNING name=Prefetch warnings 1 From 8b06badbcfc3f3145f6d186b628010bbd7a42027 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 May 2016 16:02:06 +0200 Subject: [PATCH 1456/2553] stream-tcp: no longer register as a thread module Now that the FlowWorker handles the TCP Stream directly, having the TCP engine as a thread module is no longer needed. This patch removes the registration. --- src/runmode-unittests.c | 3 +++ src/stream-tcp.c | 29 ----------------------------- src/stream-tcp.h | 7 ++++--- src/suricata.c | 2 -- 4 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 6f572d3fce1b..74e194afc0ef 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -66,6 +66,8 @@ #include "ippair-bit.h" #include "unix-manager.h" +#include "stream-tcp.h" + #include "app-layer-detect-proto.h" #include "app-layer-parser.h" #include "app-layer.h" @@ -193,6 +195,7 @@ void RunUnittests(int list_unittests, char *regex_arg) UtInitialize(); UTHRegisterTests(); + StreamTcpRegisterTests(); SCReputationRegisterTests(); TmModuleRegisterTests(); SigTableRegisterTests(); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index d1d1470bf3b0..ac603e6ef75e 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -93,12 +93,7 @@ #define STREAMTCP_EMERG_EST_TIMEOUT 300 #define STREAMTCP_EMERG_CLOSED_TIMEOUT 20 -TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); -TmEcode StreamTcpThreadInit(ThreadVars *, void *, void **); -TmEcode StreamTcpThreadDeinit(ThreadVars *, void *); -void StreamTcpExitPrintStats(ThreadVars *, void *); static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *, TcpSession *, Packet *, PacketQueue *); -void StreamTcpRegisterTests (void); void StreamTcpReturnStreamSegments (TcpStream *); void StreamTcpInitConfig(char); int StreamTcpGetFlowState(void *); @@ -122,18 +117,6 @@ SC_ATOMIC_DECLARE(uint64_t, st_memuse); /* stream engine running in "inline" mode. */ int stream_inline = 0; -void TmModuleStreamTcpRegister (void) -{ - tmm_modules[TMM_STREAMTCP].name = "StreamTcp"; - tmm_modules[TMM_STREAMTCP].ThreadInit = StreamTcpThreadInit; - tmm_modules[TMM_STREAMTCP].Func = StreamTcp; - tmm_modules[TMM_STREAMTCP].ThreadExitPrintStats = StreamTcpExitPrintStats; - tmm_modules[TMM_STREAMTCP].ThreadDeinit = StreamTcpThreadDeinit; - tmm_modules[TMM_STREAMTCP].RegisterTests = StreamTcpRegisterTests; - tmm_modules[TMM_STREAMTCP].cap_flags = 0; - tmm_modules[TMM_STREAMTCP].flags = TM_FLAG_STREAM_TM; -} - void StreamTcpIncrMemuse(uint64_t size) { (void) SC_ATOMIC_ADD(st_memuse, size); @@ -4896,8 +4879,6 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe (void)StreamTcpPacket(tv, p, stt, pq); - stt->pkts++; - return TM_ECODE_OK; } @@ -4983,16 +4964,6 @@ TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data) SCReturnInt(TM_ECODE_OK); } -void StreamTcpExitPrintStats(ThreadVars *tv, void *data) -{ - StreamTcpThread *stt = (StreamTcpThread *)data; - if (stt == NULL) { - return; - } - - SCLogInfo("Stream TCP processed %" PRIu64 " TCP packets", stt->pkts); -} - /** * \brief Function to check the validity of the RST packets based on the * target OS of the given packet. diff --git a/src/stream-tcp.h b/src/stream-tcp.h index e23d9eab71e7..57e8abc41194 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -76,8 +76,6 @@ typedef struct TcpStreamCnf_ { typedef struct StreamTcpThread_ { int ssn_pool_id; - uint64_t pkts; - /** queue for pseudo packet(s) that were created in the stream * process and need further handling. Currently only used when * receiving (valid) RST packets */ @@ -108,7 +106,6 @@ typedef struct StreamTcpThread_ { } StreamTcpThread; TcpStreamCnf stream_config; -void TmModuleStreamTcpRegister (void); void StreamTcpInitConfig (char); void StreamTcpFreeConfig(char); void StreamTcpRegisterTests (void); @@ -217,8 +214,12 @@ static inline int StreamNeedsReassembly(TcpSession *ssn, int direction) } } +TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); +void StreamTcpExitPrintStats(ThreadVars *, void *); TmEcode StreamTcpThreadInit(ThreadVars *, void *, void **); TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data); +void StreamTcpRegisterTests (void); + int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueue *pq); /* clear ssn and return to pool */ diff --git a/src/suricata.c b/src/suricata.c index ecb1690e1eaf..b619233ca388 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -859,8 +859,6 @@ void RegisterAllModules() /* flow worker */ TmModuleFlowWorkerRegister(); - /* stream engine */ - TmModuleStreamTcpRegister(); /* detection */ TmModuleDetectRegister(); /* respond-reject */ From 4a96820320e5ba8ef183d65d2802040cb8dea1d9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 May 2016 16:10:59 +0200 Subject: [PATCH 1457/2553] stream-tcp: more cleanups --- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - src/tm-threads.c | 3 +-- src/util-profiling.c | 13 +------------ 4 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/tm-modules.c b/src/tm-modules.c index b798d1d4d836..0b835fa3453e 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -234,7 +234,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_PCAPLOG); CASE_CODE (TMM_FILELOG); CASE_CODE (TMM_FILESTORE); - CASE_CODE (TMM_STREAMTCP); CASE_CODE (TMM_DECODEIPFW); CASE_CODE (TMM_VERDICTIPFW); CASE_CODE (TMM_RECEIVEIPFW); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index dc70af9bc44e..ed442ba8e0ac 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -65,7 +65,6 @@ typedef enum { TMM_PCAPLOG, TMM_FILELOG, TMM_FILESTORE, - TMM_STREAMTCP, TMM_DECODEIPFW, TMM_VERDICTIPFW, TMM_RECEIVEIPFW, diff --git a/src/tm-threads.c b/src/tm-threads.c index 506430d3f817..8cfca0e7ac86 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -192,8 +192,7 @@ static int TmThreadTimeoutLoop(ThreadVars *tv, TmSlot *s) int r = TM_ECODE_OK; for (slot = s; slot != NULL; slot = slot->slot_next) { - if (slot->tm_id == TMM_FLOWWORKER || - slot->tm_id == TMM_STREAMTCP) + if (slot->tm_id == TMM_FLOWWORKER) { stream_slot = slot; break; diff --git a/src/util-profiling.c b/src/util-profiling.c index f63ee92987e4..2da2b232fb4e 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -217,7 +217,7 @@ SCProfilingInit(void) for (i = 0; i < ALPROTO_MAX; i++) { fprintf(packet_profile_csv_fp, "%s,", AppProtoToString(i)); } - fprintf(packet_profile_csv_fp, "STREAM (no app),proto detect,"); + fprintf(packet_profile_csv_fp, "proto detect,"); for (i = 0; i < PROF_DETECT_SIZE; i++) { fprintf(packet_profile_csv_fp, "%s,", PacketProfileDetectIdToString(i)); } @@ -450,7 +450,6 @@ void SCProfilingDumpPacketStats(void) TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); } } - fprintf(fp, "Note: TMM_STREAMTCP includes TCP app layer parsers, see below.\n"); fprintf(fp, "\nPer App layer parser stats:\n"); @@ -694,7 +693,6 @@ void SCProfilingPrintPacketProfile(Packet *p) int i; uint64_t tmm_total = 0; - uint64_t tmm_streamtcp_tcp = 0; for (i = 0; i < TMM_SIZE; i++) { PktProfilingTmmData *pdt = &p->profile->tmm[i]; @@ -702,10 +700,6 @@ void SCProfilingPrintPacketProfile(Packet *p) uint64_t tmm_delta = pdt->ticks_end - pdt->ticks_start; fprintf(packet_profile_csv_fp, "%"PRIu64",", tmm_delta); tmm_total += tmm_delta; - - if (p->proto == IPPROTO_TCP && i == TMM_STREAMTCP) { - tmm_streamtcp_tcp = tmm_delta; - } } fprintf(packet_profile_csv_fp, "%"PRIu64",", delta - tmm_total); @@ -721,11 +715,6 @@ void SCProfilingPrintPacketProfile(Packet *p) } } - uint64_t real_tcp = 0; - if (tmm_streamtcp_tcp > app_total) - real_tcp = tmm_streamtcp_tcp - app_total; - fprintf(packet_profile_csv_fp, "%"PRIu64",", real_tcp); - fprintf(packet_profile_csv_fp, "%"PRIu64",", p->profile->proto_detect); for (i = 0; i < PROF_DETECT_SIZE; i++) { From a8f257e05f1227771078ad797bc9b72313d70476 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 May 2016 16:39:14 +0200 Subject: [PATCH 1458/2553] detect: no longer a thread module Like stream, detect is now invoked directly by the FlowWorker. --- src/detect.c | 36 ------------------------------------ src/runmode-unittests.c | 1 + src/suricata.c | 2 -- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 5 files changed, 1 insertion(+), 40 deletions(-) diff --git a/src/detect.c b/src/detect.c index 860b330b3dce..9fb005fcf181 100644 --- a/src/detect.c +++ b/src/detect.c @@ -219,32 +219,6 @@ void DbgPrintSigs(DetectEngineCtx *, SigGroupHead *); void DbgPrintSigs2(DetectEngineCtx *, SigGroupHead *); static void PacketCreateMask(Packet *, SignatureMask *, uint16_t, int, StreamMsg *, int); -/* tm module api functions */ -TmEcode Detect(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); -TmEcode DetectThreadInit(ThreadVars *, void *, void **); -TmEcode DetectThreadDeinit(ThreadVars *, void *); - -void TmModuleDetectRegister (void) -{ - tmm_modules[TMM_DETECT].name = "Detect"; - tmm_modules[TMM_DETECT].ThreadInit = DetectThreadInit; - tmm_modules[TMM_DETECT].Func = Detect; - tmm_modules[TMM_DETECT].ThreadExitPrintStats = DetectExitPrintStats; - tmm_modules[TMM_DETECT].ThreadDeinit = DetectThreadDeinit; - tmm_modules[TMM_DETECT].RegisterTests = SigRegisterTests; - tmm_modules[TMM_DETECT].cap_flags = 0; - tmm_modules[TMM_DETECT].flags = TM_FLAG_DETECT_TM; - - PacketAlertTagInit(); -} - -void DetectExitPrintStats(ThreadVars *tv, void *data) -{ - DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; - if (det_ctx == NULL) - return; -} - /** * \brief Create the path if default-rule-path was specified * \param sig_file The name of the file @@ -2062,16 +2036,6 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue return TM_ECODE_FAILED; } -TmEcode DetectThreadInit(ThreadVars *t, void *initdata, void **data) -{ - return DetectEngineThreadCtxInit(t,initdata,data); -} - -TmEcode DetectThreadDeinit(ThreadVars *t, void *data) -{ - return DetectEngineThreadCtxDeinit(t,data); -} - void SigCleanSignatures(DetectEngineCtx *de_ctx) { Signature *s = NULL, *ns; diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 74e194afc0ef..b5d22bd3b19c 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -196,6 +196,7 @@ void RunUnittests(int list_unittests, char *regex_arg) UtInitialize(); UTHRegisterTests(); StreamTcpRegisterTests(); + SigRegisterTests(); SCReputationRegisterTests(); TmModuleRegisterTests(); SigTableRegisterTests(); diff --git a/src/suricata.c b/src/suricata.c index b619233ca388..4b77edf24099 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -859,8 +859,6 @@ void RegisterAllModules() /* flow worker */ TmModuleFlowWorkerRegister(); - /* detection */ - TmModuleDetectRegister(); /* respond-reject */ TmModuleRespondRejectRegister(); diff --git a/src/tm-modules.c b/src/tm-modules.c index 0b835fa3453e..6627a822a1c5 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -211,7 +211,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_DECODEPCAPFILE); CASE_CODE (TMM_RECEIVEPFRING); CASE_CODE (TMM_DECODEPFRING); - CASE_CODE (TMM_DETECT); CASE_CODE (TMM_ALERTFASTLOG); CASE_CODE (TMM_ALERTFASTLOG4); CASE_CODE (TMM_ALERTFASTLOG6); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index ed442ba8e0ac..af04988f5741 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -41,7 +41,6 @@ typedef enum { TMM_DECODEPCAPFILE, TMM_RECEIVEPFRING, TMM_DECODEPFRING, - TMM_DETECT, TMM_ALERTFASTLOG, TMM_ALERTFASTLOG4, TMM_ALERTFASTLOG6, From 7dfdcdc770e4a99fc953c990d6a54ea7ea2112ca Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 May 2016 16:46:03 +0200 Subject: [PATCH 1459/2553] thread modules: remove unused id's --- src/tm-modules.c | 8 -------- src/tm-threads-common.h | 8 -------- 2 files changed, 16 deletions(-) diff --git a/src/tm-modules.c b/src/tm-modules.c index 6627a822a1c5..924ff867c91a 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -212,23 +212,15 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_RECEIVEPFRING); CASE_CODE (TMM_DECODEPFRING); CASE_CODE (TMM_ALERTFASTLOG); - CASE_CODE (TMM_ALERTFASTLOG4); - CASE_CODE (TMM_ALERTFASTLOG6); CASE_CODE (TMM_ALERTUNIFIED2ALERT); CASE_CODE (TMM_ALERTPRELUDE); CASE_CODE (TMM_ALERTDEBUGLOG); CASE_CODE (TMM_ALERTSYSLOG); CASE_CODE (TMM_LOGDROPLOG); - CASE_CODE (TMM_ALERTSYSLOG4); - CASE_CODE (TMM_ALERTSYSLOG6); CASE_CODE (TMM_RESPONDREJECT); CASE_CODE (TMM_LOGDNSLOG); CASE_CODE (TMM_LOGHTTPLOG); - CASE_CODE (TMM_LOGHTTPLOG4); - CASE_CODE (TMM_LOGHTTPLOG6); CASE_CODE (TMM_LOGTLSLOG); - CASE_CODE (TMM_LOGTLSLOG4); - CASE_CODE (TMM_LOGTLSLOG6); CASE_CODE (TMM_LOGTCPDATALOG); CASE_CODE (TMM_PCAPLOG); CASE_CODE (TMM_FILELOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index af04988f5741..ee7e92205b78 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -42,23 +42,15 @@ typedef enum { TMM_RECEIVEPFRING, TMM_DECODEPFRING, TMM_ALERTFASTLOG, - TMM_ALERTFASTLOG4, - TMM_ALERTFASTLOG6, TMM_ALERTUNIFIED2ALERT, TMM_ALERTPRELUDE, TMM_ALERTDEBUGLOG, TMM_ALERTSYSLOG, TMM_LOGDROPLOG, - TMM_ALERTSYSLOG4, - TMM_ALERTSYSLOG6, TMM_RESPONDREJECT, TMM_LOGDNSLOG, TMM_LOGHTTPLOG, - TMM_LOGHTTPLOG4, - TMM_LOGHTTPLOG6, TMM_LOGTLSLOG, - TMM_LOGTLSLOG4, - TMM_LOGTLSLOG6, TMM_LOGTCPDATALOG, TMM_OUTPUTJSON, TMM_PCAPLOG, From 48771c1acf2f9c87507fd3ce5559b02b4573c025 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 28 May 2016 09:21:05 +0200 Subject: [PATCH 1460/2553] debug: fix compiler warnings --- src/app-layer-ssh.c | 2 +- src/util-decode-mime.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index b96f6c9cad9a..98b5c76a54b3 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -85,7 +85,7 @@ static int SSHParseBanner(SshState *state, SshHeader *header, const uint8_t *inp if ((banner_end - line_ptr) > 255) { SCLogDebug("Invalid version string, it should be less than 255 " "characters including , input value is %"PRIuMAX, - (banner_end - line_ptr)); + (uintmax_t)(banner_end - line_ptr)); SCReturnInt(-1); } diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 01cb28fb145e..54902551fae1 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -1150,7 +1150,8 @@ static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, if (tok + tokLen - (uint8_t *) chunk == (int)len) { PrintChars(SC_LOG_DEBUG, "LAST CHUNK LINE - CUTOFF", tok, tokLen); - SCLogDebug("\nCHUNK CUTOFF CHARS: %d delim %ld\n", tokLen, len - (tok + tokLen - (uint8_t *) chunk)); + SCLogDebug("\nCHUNK CUTOFF CHARS: %u delim %u\n", + tokLen, len - (uint32_t)(tok + tokLen - (uint8_t *) chunk)); } else { /* Search line for URL */ ret = FindUrlStrings(tok, tokLen, state); From e09643c396d6aa7ce35089ff45b5c4ce49c1d036 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 29 May 2016 10:40:46 +0200 Subject: [PATCH 1461/2553] flow worker: profiling Previously the detect and stream code lived in their own thread modules. This meant profiling showed their cost as part of the thread module profiling logic. Now that only the flow worker is a thread module this no longer works. This patch introduces profiling for the 3 current flow worker steps: flow, stream, detect. --- src/decode.h | 7 +++ src/flow-worker.c | 29 +++++++++++- src/flow-worker.h | 8 ++++ src/util-profiling.c | 109 +++++++++++++++++++++++++++++++++++++++++++ src/util-profiling.h | 17 +++++++ 5 files changed, 169 insertions(+), 1 deletion(-) diff --git a/src/decode.h b/src/decode.h index a8641a23a057..886ca2fa1ee8 100644 --- a/src/decode.h +++ b/src/decode.h @@ -30,6 +30,7 @@ #include "suricata-common.h" #include "threadvars.h" #include "decode-events.h" +#include "flow-worker.h" #ifdef __SC_CUDA_SUPPORT__ #include "util-cuda-buffer.h" @@ -325,6 +326,11 @@ typedef struct PktProfilingTmmData_ { #endif } PktProfilingTmmData; +typedef struct PktProfilingData_ { + uint64_t ticks_start; + uint64_t ticks_end; +} PktProfilingData; + typedef struct PktProfilingDetectData_ { uint64_t ticks_start; uint64_t ticks_end; @@ -341,6 +347,7 @@ typedef struct PktProfiling_ { uint64_t ticks_end; PktProfilingTmmData tmm[TMM_SIZE]; + PktProfilingData flowworker[PROFILE_FLOWWORKER_SIZE]; PktProfilingAppData app[ALPROTO_MAX]; PktProfilingDetectData detect[PROF_DETECT_SIZE]; uint64_t proto_detect; diff --git a/src/flow-worker.c b/src/flow-worker.c index 8bb3043ac0b6..21a210fee72b 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -158,6 +158,8 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac /* handle Flow */ if (p->flags & PKT_WANTS_FLOW) { + FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_FLOW); + FlowHandlePacket(tv, fw->dtv, p); if (likely(p->flow != NULL)) { DEBUG_ASSERT_FLOW_LOCKED(p->flow); @@ -165,6 +167,8 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac } /* Flow is now LOCKED */ + FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_FLOW); + /* if PKT_WANTS_FLOW is not set, but PKT_HAS_FLOW is, then this is a * pseudo packet created by the flow manager. */ } else if (p->flags & PKT_HAS_FLOW) { @@ -178,7 +182,9 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac SCLogDebug("packet %"PRIu64" is TCP", p->pcap_cnt); DEBUG_ASSERT_FLOW_LOCKED(p->flow); + FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_STREAM); StreamTcp(tv, p, fw->stream_thread, &fw->pq, NULL); + FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_STREAM); /* Packets here can safely access p->flow as it's locked */ SCLogDebug("packet %"PRIu64": extra packets %u", p->pcap_cnt, fw->pq.len); @@ -188,8 +194,11 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac // TODO do we need to call StreamTcp on these pseudo packets or not? //StreamTcp(tv, x, fw->stream_thread, &fw->pq, NULL); - if (detect_thread != NULL) + if (detect_thread != NULL) { + FLOWWORKER_PROFILING_START(x, PROFILE_FLOWWORKER_DETECT); Detect(tv, x, detect_thread, NULL, NULL); + FLOWWORKER_PROFILING_END(x, PROFILE_FLOWWORKER_DETECT); + } #if 0 // Outputs #endif @@ -204,7 +213,9 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac SCLogDebug("packet %"PRIu64" calling Detect", p->pcap_cnt); if (detect_thread != NULL) { + FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_DETECT); Detect(tv, p, detect_thread, NULL, NULL); + FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_DETECT); } #if 0 // Outputs @@ -234,6 +245,22 @@ void *FlowWorkerGetDetectCtxPtr(void *flow_worker) return SC_ATOMIC_GET(fw->detect_thread); } +const char *ProfileFlowWorkerIdToString(enum ProfileFlowWorkerId fwi) +{ + switch (fwi) { + case PROFILE_FLOWWORKER_FLOW: + return "flow"; + case PROFILE_FLOWWORKER_STREAM: + return "stream"; + case PROFILE_FLOWWORKER_DETECT: + return "detect"; + case PROFILE_FLOWWORKER_SIZE: + return "size"; + } + return "error"; +} + + void TmModuleFlowWorkerRegister (void) { tmm_modules[TMM_FLOWWORKER].name = "FlowWorker"; diff --git a/src/flow-worker.h b/src/flow-worker.h index a3528e628607..bda621063c66 100644 --- a/src/flow-worker.h +++ b/src/flow-worker.h @@ -18,6 +18,14 @@ #ifndef __FLOW_WORKER_H__ #define __FLOW_WORKER_H__ +enum ProfileFlowWorkerId { + PROFILE_FLOWWORKER_FLOW = 0, + PROFILE_FLOWWORKER_STREAM, + PROFILE_FLOWWORKER_DETECT, + PROFILE_FLOWWORKER_SIZE +}; +const char *ProfileFlowWorkerIdToString(enum ProfileFlowWorkerId fwi); + void FlowWorkerReplaceDetectCtx(void *flow_worker, void *detect_ctx); void *FlowWorkerGetDetectCtxPtr(void *flow_worker); diff --git a/src/util-profiling.c b/src/util-profiling.c index 2da2b232fb4e..6942d37fe763 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -30,6 +30,7 @@ #include "decode.h" #include "detect.h" #include "conf.h" +#include "flow-worker.h" #include "tm-threads.h" @@ -86,6 +87,13 @@ SCProfilePacketData packet_profile_app_pd_data6[257]; SCProfilePacketData packet_profile_detect_data4[PROF_DETECT_SIZE][257]; SCProfilePacketData packet_profile_detect_data6[PROF_DETECT_SIZE][257]; +struct ProfileProtoRecords { + SCProfilePacketData records4[257]; + SCProfilePacketData records6[257]; +}; + +struct ProfileProtoRecords packet_profile_flowworker_data[PROFILE_FLOWWORKER_SIZE]; + int profiling_packets_enabled = 0; int profiling_packets_csv_enabled = 0; @@ -159,6 +167,7 @@ SCProfilingInit(void) memset(&packet_profile_app_pd_data6, 0, sizeof(packet_profile_app_pd_data6)); memset(&packet_profile_detect_data4, 0, sizeof(packet_profile_detect_data4)); memset(&packet_profile_detect_data6, 0, sizeof(packet_profile_detect_data6)); + memset(&packet_profile_flowworker_data, 0, sizeof(packet_profile_flowworker_data)); const char *filename = ConfNodeLookupChildValue(conf, "filename"); if (filename != NULL) { @@ -302,6 +311,55 @@ SCProfilingDump(void) SCLogInfo("Done dumping profiling data."); } +static void DumpFlowWorkerIP(FILE *fp, int ipv, uint64_t total) +{ + char totalstr[256]; + + enum ProfileFlowWorkerId fwi; + for (fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { + struct ProfileProtoRecords *r = &packet_profile_flowworker_data[fwi]; + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = ipv == 4 ? &r->records4[p] : &r->records6[p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / + (long double)total * 100; + + fprintf(fp, "%-20s IPv%d %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n", + ProfileFlowWorkerIdToString(fwi), ipv, p, pd->cnt, + pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } +} + +static void DumpFlowWorker(FILE *fp) +{ + uint64_t total = 0; + + enum ProfileFlowWorkerId fwi; + for (fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { + struct ProfileProtoRecords *r = &packet_profile_flowworker_data[fwi]; + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &r->records4[p]; + total += pd->tot; + pd = &r->records6[p]; + total += pd->tot; + } + } + + fprintf(fp, "\n%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", + "Flow Worker", "IP ver", "Proto", "cnt", "min", "max", "avg"); + fprintf(fp, "%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", + "--------------------", "------", "-----", "----------", "------------", "------------", "-----------"); + DumpFlowWorkerIP(fp, 4, total); + DumpFlowWorkerIP(fp, 6, total); + fprintf(fp, "Note: %s includes app-layer for TCP\n", + ProfileFlowWorkerIdToString(PROFILE_FLOWWORKER_STREAM)); +} + void SCProfilingDumpPacketStats(void) { int i; @@ -451,6 +509,8 @@ void SCProfilingDumpPacketStats(void) } } + DumpFlowWorker(fp); + fprintf(fp, "\nPer App layer parser stats:\n"); fprintf(fp, "\n%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", @@ -881,6 +941,49 @@ void SCProfilingUpdatePacketTmmRecords(Packet *p) } } +static inline void SCProfilingUpdatePacketGenericRecord(PktProfilingData *pdt, + SCProfilePacketData *pd) +{ + if (pdt == NULL || pd == NULL) { + return; + } + + uint64_t delta = pdt->ticks_end - pdt->ticks_start; + if (pd->min == 0 || delta < pd->min) { + pd->min = delta; + } + if (pd->max < delta) { + pd->max = delta; + } + + pd->tot += delta; + pd->cnt ++; +} + +static void SCProfilingUpdatePacketGenericRecords(Packet *p, PktProfilingData *pd, + struct ProfileProtoRecords *store, int size) +{ + int i; + for (i = 0; i < size; i++) { + PktProfilingData *pdt = &pd[i]; + + if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) { + continue; + } + + struct ProfileProtoRecords *r = &store[i]; + SCProfilePacketData *store = NULL; + + if (PKT_IS_IPV4(p)) { + store = &(r->records4[p->proto]); + } else { + store = &(r->records6[p->proto]); + } + + SCProfilingUpdatePacketGenericRecord(pdt, store); + } +} + void SCProfilingAddPacket(Packet *p) { if (p == NULL || p->profile == NULL || @@ -922,6 +1025,9 @@ void SCProfilingAddPacket(Packet *p) pd->cnt ++; } + SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker, + packet_profile_flowworker_data, PROFILE_FLOWWORKER_SIZE); + SCProfilingUpdatePacketTmmRecords(p); SCProfilingUpdatePacketAppRecords(p); SCProfilingUpdatePacketDetectRecords(p); @@ -954,6 +1060,9 @@ void SCProfilingAddPacket(Packet *p) pd->cnt ++; } + SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker, + packet_profile_flowworker_data, PROFILE_FLOWWORKER_SIZE); + SCProfilingUpdatePacketTmmRecords(p); SCProfilingUpdatePacketAppRecords(p); SCProfilingUpdatePacketDetectRecords(p); diff --git a/src/util-profiling.h b/src/util-profiling.h index cc7ea0270071..c97f1b5c093c 100644 --- a/src/util-profiling.h +++ b/src/util-profiling.h @@ -157,6 +157,20 @@ PktProfiling *SCProfilePacketStart(void); } \ } +#define FLOWWORKER_PROFILING_START(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < PROFILE_FLOWWORKER_SIZE) { \ + (p)->profile->flowworker[(id)].ticks_start = UtilCpuGetTicks();\ + } \ + } + +#define FLOWWORKER_PROFILING_END(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < PROFILE_FLOWWORKER_SIZE) { \ + (p)->profile->flowworker[(id)].ticks_end = UtilCpuGetTicks(); \ + } \ + } + #define PACKET_PROFILING_RESET(p) \ if (profiling_packets_enabled && (p)->profile != NULL) { \ SCFree((p)->profile); \ @@ -292,6 +306,9 @@ void SCProfilingDump(void); #define SGH_PROFILING_RECORD(det_ctx, sgh) +#define FLOWWORKER_PROFILING_START(p, id) +#define FLOWWORKER_PROFILING_END(p, id) + #endif /* PROFILING */ #endif /* ! __UTIL_PROFILE_H__ */ From c1f679d3f3564fd3a2ab3b157880e22e1b936a7a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 29 May 2016 11:29:30 +0200 Subject: [PATCH 1462/2553] flow worker: move UDP app-layer into main function This way it's more clean what happens and we can profile it. --- src/flow-worker.c | 13 ++++++++----- src/flow-worker.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/flow-worker.c b/src/flow-worker.c index 21a210fee72b..4f96ac1f63e6 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -73,11 +73,6 @@ typedef struct FlowWorkerThreadData_ { static void FlowUpdate(ThreadVars *tv, StreamTcpThread *stt, Packet *p) { FlowHandlePacketUpdate(p->flow, p); - - /* handle the app layer part of the UDP packet payload */ - if (p->proto == IPPROTO_UDP) { - AppLayerHandleUdp(tv, stt->ra_ctx->app_tctx, p, p->flow); - } } static TmEcode FlowWorkerThreadInit(ThreadVars *tv, void *initdata, void **data) @@ -206,6 +201,12 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac * by the other thread modules before packet 'p'. */ PacketEnqueue(preq, x); } + + /* handle the app layer part of the UDP packet payload */ + } else if (p->flow && p->proto == IPPROTO_UDP) { + FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_APPLAYERUDP); + AppLayerHandleUdp(tv, fw->stream_thread->ra_ctx->app_tctx, p, p->flow); + FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_APPLAYERUDP); } /* handle Detect */ @@ -252,6 +253,8 @@ const char *ProfileFlowWorkerIdToString(enum ProfileFlowWorkerId fwi) return "flow"; case PROFILE_FLOWWORKER_STREAM: return "stream"; + case PROFILE_FLOWWORKER_APPLAYERUDP: + return "app-layer"; case PROFILE_FLOWWORKER_DETECT: return "detect"; case PROFILE_FLOWWORKER_SIZE: diff --git a/src/flow-worker.h b/src/flow-worker.h index bda621063c66..418ea05d6ca8 100644 --- a/src/flow-worker.h +++ b/src/flow-worker.h @@ -21,6 +21,7 @@ enum ProfileFlowWorkerId { PROFILE_FLOWWORKER_FLOW = 0, PROFILE_FLOWWORKER_STREAM, + PROFILE_FLOWWORKER_APPLAYERUDP, PROFILE_FLOWWORKER_DETECT, PROFILE_FLOWWORKER_SIZE }; From 093ecf4798b3fb93e75d81462cec1ec62487d9b2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 04:22:47 +0200 Subject: [PATCH 1463/2553] logging: clean up at shutdown --- src/suricata.c | 1 + src/util-debug.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index 4b77edf24099..f3b6d4f9858f 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2772,6 +2772,7 @@ int main(int argc, char **argv) #endif ConfDeInit(); + SCLogDeInitLogModule(); DetectParseFreeRegexes(); exit(engine_retval); } diff --git a/src/util-debug.c b/src/util-debug.c index 6e71102a9016..a55a559906b8 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -713,6 +713,7 @@ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, fclose(iface_ctx->file_d); iface_ctx->file_d = NULL; } + SCFree(iface_ctx); return NULL; } From a9cea53e62b1abf0fadbc04501710ba0213e0741 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 18:53:52 +0200 Subject: [PATCH 1464/2553] yaml: move vars to the top --- suricata.yaml.in | 87 ++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 74a3b95d9f40..6d80e603d1a1 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -5,6 +5,42 @@ # options in this file, full documentation can be found at: # https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricatayaml +## +## Step 1: inform Suricata about your network +## + +vars: + # more specifc is better for alert accuracy and performance + address-groups: + HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" + #HOME_NET: "[192.168.0.0/16]" + #HOME_NET: "[10.0.0.0/8]" + #HOME_NET: "[172.16.0.0/12]" + #HOME_NET: "any" + + EXTERNAL_NET: "!$HOME_NET" + #EXTERNAL_NET: "any" + + HTTP_SERVERS: "$HOME_NET" + SMTP_SERVERS: "$HOME_NET" + SQL_SERVERS: "$HOME_NET" + DNS_SERVERS: "$HOME_NET" + TELNET_SERVERS: "$HOME_NET" + AIM_SERVERS: "$EXTERNAL_NET" + DNP3_SERVER: "$HOME_NET" + DNP3_CLIENT: "$HOME_NET" + MODBUS_CLIENT: "$HOME_NET" + MODBUS_SERVER: "$HOME_NET" + ENIP_CLIENT: "$HOME_NET" + ENIP_SERVER: "$HOME_NET" + + port-groups: + HTTP_PORTS: "80" + SHELLCODE_PORTS: "!80" + ORACLE_PORTS: 1521 + SSH_PORTS: 22 + DNP3_PORTS: 20000 + MODBUS_PORTS: 502 # Number of packets preallocated per thread. The default is 1024. A higher number # will make sure each CPU will be more easily kept busy, but may negatively @@ -1196,57 +1232,6 @@ rule-files: classification-file: @e_sysconfdir@classification.config reference-config-file: @e_sysconfdir@reference.config -# Holds variables that would be used by the engine. -vars: - - # Holds the address group vars that would be passed in a Signature. - # These would be retrieved during the Signature address parsing stage. - address-groups: - - HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" - - EXTERNAL_NET: "!$HOME_NET" - - HTTP_SERVERS: "$HOME_NET" - - SMTP_SERVERS: "$HOME_NET" - - SQL_SERVERS: "$HOME_NET" - - DNS_SERVERS: "$HOME_NET" - - TELNET_SERVERS: "$HOME_NET" - - AIM_SERVERS: "$EXTERNAL_NET" - - DNP3_SERVER: "$HOME_NET" - - DNP3_CLIENT: "$HOME_NET" - - MODBUS_CLIENT: "$HOME_NET" - - MODBUS_SERVER: "$HOME_NET" - - ENIP_CLIENT: "$HOME_NET" - - ENIP_SERVER: "$HOME_NET" - - # Holds the port group vars that would be passed in a Signature. - # These would be retrieved during the Signature port parsing stage. - port-groups: - - HTTP_PORTS: "80" - - SHELLCODE_PORTS: "!80" - - ORACLE_PORTS: 1521 - - SSH_PORTS: 22 - - DNP3_PORTS: 20000 - - MODBUS_PORTS: 502 - # Set the order of alerts bassed on actions # The default order is pass, drop, reject, alert # action-order: From c949668863ebd9110c8ae977325d4a98f2df1f15 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 18:57:20 +0200 Subject: [PATCH 1465/2553] yaml: move rules up in the file Also disable decoder and stream events by default, as they are too noisy in a untuned environment. --- suricata.yaml.in | 124 +++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 6d80e603d1a1..c750d27df073 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -42,6 +42,68 @@ vars: DNP3_PORTS: 20000 MODBUS_PORTS: 502 +## +## Step 2: select the rules to enable or disable +## + +classification-file: @e_sysconfdir@classification.config +reference-config-file: @e_sysconfdir@reference.config +# threshold-file: @e_sysconfdir@threshold.config + +default-rule-path: @e_sysconfdir@rules +rule-files: + - botcc.rules + - ciarmy.rules + - compromised.rules + - drop.rules + - dshield.rules +# - emerging-activex.rules + - emerging-attack_response.rules + - emerging-chat.rules + - emerging-current_events.rules + - emerging-dns.rules + - emerging-dos.rules + - emerging-exploit.rules + - emerging-ftp.rules +# - emerging-games.rules +# - emerging-icmp_info.rules +# - emerging-icmp.rules + - emerging-imap.rules +# - emerging-inappropriate.rules + - emerging-malware.rules + - emerging-misc.rules + - emerging-mobile_malware.rules + - emerging-netbios.rules + - emerging-p2p.rules + - emerging-policy.rules + - emerging-pop3.rules + - emerging-rpc.rules + - emerging-scada.rules + - emerging-scan.rules +# - emerging-shellcode.rules + - emerging-smtp.rules + - emerging-snmp.rules + - emerging-sql.rules + - emerging-telnet.rules + - emerging-tftp.rules + - emerging-trojan.rules + - emerging-user_agents.rules + - emerging-voip.rules + - emerging-web_client.rules + - emerging-web_server.rules +# - emerging-web_specific_apps.rules + - emerging-worm.rules + - tor.rules +# - decoder-events.rules # available in suricata sources under rules dir +# - stream-events.rules # available in suricata sources under rules dir + - http-events.rules # available in suricata sources under rules dir + - smtp-events.rules # available in suricata sources under rules dir + - dns-events.rules # available in suricata sources under rules dir + - tls-events.rules # available in suricata sources under rules dir +# - modbus-events.rules # available in suricata sources under rules dir +# - app-layer-events.rules # available in suricata sources under rules dir + + # Number of packets preallocated per thread. The default is 1024. A higher number # will make sure each CPU will be more easily kept busy, but may negatively # impact caching. @@ -618,10 +680,6 @@ netmap: legacy: uricontent: enabled -# You can specify a threshold config file by setting "threshold-file" -# to the path of the threshold config file: -# threshold-file: /etc/suricata/threshold.config - # The detection engine builds internal groups of signatures. The engine # allow us to specify the profile to use for them, to manage memory on an # efficient way keeping a good performance. For the profile keyword you @@ -1174,64 +1232,6 @@ ipfw: # # ipfw-reinjection-rule-number: 5500 -# Set the default rule path here to search for the files. -# if not set, it will look at the current working dir -default-rule-path: @e_sysconfdir@rules -rule-files: - - botcc.rules - - ciarmy.rules - - compromised.rules - - drop.rules - - dshield.rules -# - emerging-activex.rules - - emerging-attack_response.rules - - emerging-chat.rules - - emerging-current_events.rules - - emerging-dns.rules - - emerging-dos.rules - - emerging-exploit.rules - - emerging-ftp.rules -# - emerging-games.rules -# - emerging-icmp_info.rules -# - emerging-icmp.rules - - emerging-imap.rules -# - emerging-inappropriate.rules - - emerging-malware.rules - - emerging-misc.rules - - emerging-mobile_malware.rules - - emerging-netbios.rules - - emerging-p2p.rules - - emerging-policy.rules - - emerging-pop3.rules - - emerging-rpc.rules - - emerging-scada.rules - - emerging-scan.rules -# - emerging-shellcode.rules - - emerging-smtp.rules - - emerging-snmp.rules - - emerging-sql.rules - - emerging-telnet.rules - - emerging-tftp.rules - - emerging-trojan.rules - - emerging-user_agents.rules - - emerging-voip.rules - - emerging-web_client.rules - - emerging-web_server.rules -# - emerging-web_specific_apps.rules - - emerging-worm.rules - - tor.rules - - decoder-events.rules # available in suricata sources under rules dir - - stream-events.rules # available in suricata sources under rules dir - - http-events.rules # available in suricata sources under rules dir - - smtp-events.rules # available in suricata sources under rules dir - - dns-events.rules # available in suricata sources under rules dir - - tls-events.rules # available in suricata sources under rules dir -# - modbus-events.rules # available in suricata sources under rules dir - - app-layer-events.rules # available in suricata sources under rules dir - -classification-file: @e_sysconfdir@classification.config -reference-config-file: @e_sysconfdir@reference.config - # Set the order of alerts bassed on actions # The default order is pass, drop, reject, alert # action-order: From d48098f1896e8d89b794fa1e6eef0d99dabcf6f8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 19:02:17 +0200 Subject: [PATCH 1466/2553] yaml: move logging up --- suricata.yaml.in | 84 +++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index c750d27df073..4d24174ad38b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -103,6 +103,50 @@ rule-files: # - modbus-events.rules # available in suricata sources under rules dir # - app-layer-events.rules # available in suricata sources under rules dir +## +## Step 3: select outputs to enable +## + +# Logging configuration. This is not about logging IDS alerts, but +# output about what Suricata is doing, like startup messages, errors, etc. +logging: + # The default log level, can be overridden in an output section. + # Note that debug level logging will only be emitted if Suricata was + # compiled with the --enable-debug configure option. + # + # This value is overriden by the SC_LOG_LEVEL env var. + default-log-level: notice + + # The default output format. Optional parameter, should default to + # something reasonable if not provided. Can be overriden in an + # output section. You can leave this out to get the default. + # + # This value is overriden by the SC_LOG_FORMAT env var. + #default-log-format: "[%i] %t - (%f:%l) <%d> (%n) -- " + + # A regex to filter output. Can be overridden in an output section. + # Defaults to empty (no filter). + # + # This value is overriden by the SC_LOG_OP_FILTER env var. + default-output-filter: + + # Define your logging outputs. If none are defined, or they are all + # disabled you will get the default - console output. + outputs: + - console: + enabled: yes + # type: json + - file: + enabled: yes + filename: @e_logdir@suricata.log + # type: json + - syslog: + enabled: no + facility: local5 + format: "[%i] <%d> -- " + # type: json + + # Number of packets preallocated per thread. The default is 1024. A higher number # will make sure each CPU will be more easily kept busy, but may negatively @@ -1061,46 +1105,6 @@ host: # prealloc: 1000 # memcap: 16777216 -# Logging configuration. This is not about logging IDS alerts, but -# IDS output about what its doing, errors, etc. -logging: - - # The default log level, can be overridden in an output section. - # Note that debug level logging will only be emitted if Suricata was - # compiled with the --enable-debug configure option. - # - # This value is overriden by the SC_LOG_LEVEL env var. - default-log-level: notice - - # The default output format. Optional parameter, should default to - # something reasonable if not provided. Can be overriden in an - # output section. You can leave this out to get the default. - # - # This value is overriden by the SC_LOG_FORMAT env var. - #default-log-format: "[%i] %t - (%f:%l) <%d> (%n) -- " - - # A regex to filter output. Can be overridden in an output section. - # Defaults to empty (no filter). - # - # This value is overriden by the SC_LOG_OP_FILTER env var. - default-output-filter: - - # Define your logging outputs. If none are defined, or they are all - # disabled you will get the default - console output. - outputs: - - console: - enabled: yes - # type: json - - file: - enabled: no - filename: @e_logdir@suricata.log - # type: json - - syslog: - enabled: no - facility: local5 - format: "[%i] <%d> -- " - # type: json - # Tilera mpipe configuration. for use on Tilera TILE-Gx. mpipe: From c160f7875874ae18303b3134ee1690f6c783d666 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 19:10:31 +0200 Subject: [PATCH 1467/2553] yaml: move afpacket, pcap, pcap-file up --- suricata.yaml.in | 261 +++++++++++++++++++++++------------------------ 1 file changed, 128 insertions(+), 133 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 4d24174ad38b..f2438e94b757 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -146,6 +146,134 @@ logging: format: "[%i] <%d> -- " # type: json +## +## Step 4: configure capture settings +## + +# af-packet support +af-packet: + - interface: eth0 + # Number of receive threads. "auto" uses the number of cores + #threads: auto + # Default clusterid. AF_PACKET will load balance packets based on flow. + cluster-id: 99 + # Default AF_PACKET cluster type. AF_PACKET can load balance per flow or per hash. + # This is only supported for Linux kernel > 3.1 + # possible value are: + # * cluster_round_robin: round robin load balancing + # * cluster_flow: all packets of a given flow are send to the same socket + # * cluster_cpu: all packets treated in kernel by a CPU are send to the same socket + # * cluster_qm: all packets linked by network card to a RSS queue are sent to the same + # socket. Requires at least Linux 3.14. + # * cluster_random: packets are sent randomly to sockets but with an equipartition. + # Requires at least Linux 3.14. + # * cluster_rollover: kernel rotates between sockets filling each socket before moving + # to the next. Requires at least Linux 3.10. + # Recommended modes are cluster_flow on most boxes and cluster_cpu or cluster_qm on system + # with capture card using RSS (require cpu affinity tuning and system irq tuning) + cluster-type: cluster_flow + # In some fragmentation case, the hash can not be computed. If "defrag" is set + # to yes, the kernel will do the needed defragmentation before sending the packets. + defrag: yes + # After Linux kernel 3.10 it is possible to activate the rollover option: if a socket is + # full then kernel will send the packet on the next socket with room available. This option + # can minimize packet drop and increase the treated bandwidth on single intensive flow. + #rollover: yes + # To use the ring feature of AF_PACKET, set 'use-mmap' to yes + #use-mmap: yes + # Lock memory map to avoid it goes to swap. Be careful that over suscribing could lock + # your system + #mmap-locked: yes + # Use tpacket_v3, capture mode, only active if user-mmap is true + tpacket-v3: yes + # Ring size will be computed with respect to max_pending_packets and number + # of threads. You can set manually the ring size in number of packets by setting + # the following value. If you are using flow cluster-type and have really network + # intensive single-flow you could want to set the ring-size independently of the number + # of threads: + #ring-size: 2048 + # Block size is used by tpacket_v3 only. It should set to a value high enough to contain + # a decent number of packets. Size is in bytes so please consider your MTU. It should be + # a power of 2 and it must be multiple of page size (usually 4096). + #block-size: 32768 + # tpacket_v3 block timeout: an open block is passed to userspace if it is not + # filled after block-timeout milliseconds. + #block-timeout: 10 + # On busy system, this could help to set it to yes to recover from a packet drop + # phase. This will result in some packets (at max a ring flush) being non treated. + #use-emergency-flush: yes + # recv buffer size, increase value could improve performance + # buffer-size: 32768 + # Set to yes to disable promiscuous mode + # disable-promisc: no + # Choose checksum verification mode for the interface. At the moment + # of the capture, some packets may be with an invalid checksum due to + # offloading to the network card of the checksum computation. + # Possible values are: + # - kernel: use indication sent by kernel for each packet (default) + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. + # Warning: 'checksum-validation' must be set to yes to have any validation + #checksum-checks: kernel + # BPF filter to apply to this interface. The pcap filter syntax apply here. + #bpf-filter: port 80 or udp + # You can use the following variables to activate AF_PACKET tap or IPS mode. + # If copy-mode is set to ips or tap, the traffic coming to the current + # interface will be copied to the copy-iface interface. If 'tap' is set, the + # copy is complete. If 'ips' is set, the packet matching a 'drop' action + # will not be copied. + #copy-mode: ips + #copy-iface: eth1 + + # Put default values here. These will be used for an interface that is not + # in the list above. + - interface: default + #threads: auto + #use-mmap: no + #rollover: yes + tpacket-v3: yes + +pcap: + - interface: eth0 + # On Linux, pcap will try to use mmaped capture and will use buffer-size + # as total of memory used by the ring. So set this to something bigger + # than 1% of your bandwidth. + #buffer-size: 16777216 + #bpf-filter: "tcp and port 25" + # Choose checksum verification mode for the interface. At the moment + # of the capture, some packets may be with an invalid checksum due to + # offloading to the network card of the checksum computation. + # Possible values are: + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. (default) + # Warning: 'checksum-validation' must be set to yes to have any validation + #checksum-checks: auto + # With some accelerator cards using a modified libpcap (like myricom), you + # may want to have the same number of capture threads as the number of capture + # rings. In this case, set up the threads variable to N to start N threads + # listening on the same interface. + #threads: 16 + # set to no to disable promiscuous mode: + #promisc: no + # set snaplen, if not set it defaults to MTU if MTU can be known + # via ioctl call and to full capture if not. + #snaplen: 1518 + # Put default values here + - interface: default + #checksum-checks: auto + +pcap-file: + # Possible values are: + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. (default) + # Warning: 'checksum-validation' must be set to yes to have checksum tested + checksum-checks: auto # Number of packets preallocated per thread. The default is 1024. A higher number @@ -578,99 +706,6 @@ nflog: # netlink max buffer size max-size: 20000 -# af-packet support -# Set threads to > 1 to use PACKET_FANOUT support -af-packet: - - interface: eth0 - # Number of receive threads. "auto" uses the number of cores - threads: auto - # Default clusterid. AF_PACKET will load balance packets based on flow. - # All threads/processes that will participate need to have the same - # clusterid. - cluster-id: 99 - # Default AF_PACKET cluster type. AF_PACKET can load balance per flow or per hash. - # This is only supported for Linux kernel > 3.1 - # possible value are: - # * cluster_round_robin: round robin load balancing - # * cluster_flow: all packets of a given flow are send to the same socket - # * cluster_cpu: all packets treated in kernel by a CPU are send to the same socket - # * cluster_qm: all packets linked by network card to a RSS queue are sent to the same - # socket. Requires at least Linux 3.14. - # * cluster_random: packets are sent randomly to sockets but with an equipartition. - # Requires at least Linux 3.14. - # * cluster_rollover: kernel rotates between sockets filling each socket before moving - # to the next. Requires at least Linux 3.10. - # Recommended modes are cluster_flow on most boxes and cluster_cpu or cluster_qm on system - # with capture card using RSS (require cpu affinity tuning and system irq tuning) - cluster-type: cluster_flow - # In some fragmentation case, the hash can not be computed. If "defrag" is set - # to yes, the kernel will do the needed defragmentation before sending the packets. - defrag: yes - # After Linux kernel 3.10 it is possible to activate the rollover option: if a socket is - # full then kernel will send the packet on the next socket with room available. This option - # can minimize packet drop and increase the treated bandwidth on single intensive flow. - #rollover: yes - # To use the ring feature of AF_PACKET, set 'use-mmap' to yes - use-mmap: yes - # Lock memory map to avoid it goes to swap. Be careful that over suscribing could lock - # your system - #mmap-locked: yes - # Use tpacket_v3, capture mode, only active if user-mmap is true - #tpacket-v3: yes - # Ring size will be computed with respect to max_pending_packets and number - # of threads. You can set manually the ring size in number of packets by setting - # the following value. If you are using flow cluster-type and have really network - # intensive single-flow you could want to set the ring-size independently of the number - # of threads: - #ring-size: 2048 - # Block size is used by tpacket_v3 only. It should set to a value high enough to contain - # a decent number of packets. Size is in bytes so please consider your MTU. It should be - # a power of 2 and it must be multiple of page size (usually 4096). - #block-size: 32768 - # tpacket_v3 block timeout: an open block is passed to userspace if it is not - # filled after block-timeout milliseconds. - #block-timeout: 10 - # On busy system, this could help to set it to yes to recover from a packet drop - # phase. This will result in some packets (at max a ring flush) being non treated. - #use-emergency-flush: yes - # recv buffer size, increase value could improve performance - # buffer-size: 32768 - # Set to yes to disable promiscuous mode - # disable-promisc: no - # Choose checksum verification mode for the interface. At the moment - # of the capture, some packets may be with an invalid checksum due to - # offloading to the network card of the checksum computation. - # Possible values are: - # - kernel: use indication sent by kernel for each packet (default) - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. - # Warning: 'checksum-validation' must be set to yes to have any validation - #checksum-checks: kernel - # BPF filter to apply to this interface. The pcap filter syntax apply here. - #bpf-filter: port 80 or udp - # You can use the following variables to activate AF_PACKET tap or IPS mode. - # If copy-mode is set to ips or tap, the traffic coming to the current - # interface will be copied to the copy-iface interface. If 'tap' is set, the - # copy is complete. If 'ips' is set, the packet matching a 'drop' action - # will not be copied. - #copy-mode: ips - #copy-iface: eth1 - - interface: eth1 - threads: auto - cluster-id: 98 - cluster-type: cluster_flow - defrag: yes - # buffer-size: 32768 - # disable-promisc: no - # Put default values here - - interface: default - #threads: auto - #use-mmap: no - #rollover: yes - tpacket-v3: yes - # Netmap support # # Netmap operates with NIC directly in driver, so you need FreeBSD wich have @@ -1170,46 +1205,6 @@ pfring: - interface: default #threads: 2 -pcap: - - interface: eth0 - # On Linux, pcap will try to use mmaped capture and will use buffer-size - # as total of memory used by the ring. So set this to something bigger - # than 1% of your bandwidth. - #buffer-size: 16777216 - #bpf-filter: "tcp and port 25" - # Choose checksum verification mode for the interface. At the moment - # of the capture, some packets may be with an invalid checksum due to - # offloading to the network card of the checksum computation. - # Possible values are: - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. (default) - # Warning: 'checksum-validation' must be set to yes to have any validation - #checksum-checks: auto - # With some accelerator cards using a modified libpcap (like myricom), you - # may want to have the same number of capture threads as the number of capture - # rings. In this case, set up the threads variable to N to start N threads - # listening on the same interface. - #threads: 16 - # set to no to disable promiscuous mode: - #promisc: no - # set snaplen, if not set it defaults to MTU if MTU can be known - # via ioctl call and to full capture if not. - #snaplen: 1518 - # Put default values here - - interface: default - #checksum-checks: auto - -pcap-file: - # Possible values are: - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. (default) - # Warning: 'checksum-validation' must be set to yes to have checksum tested - checksum-checks: auto - # For FreeBSD ipfw(8) divert(4) support. # Please make sure you have ipfw_load="YES" and ipdivert_load="YES" # in /etc/loader.conf or kldload'ing the appropriate kernel modules. From c5ca642a28659ba59de41b318f77ffdb2d61a277 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 19:15:41 +0200 Subject: [PATCH 1468/2553] yaml: move app layer up --- suricata.yaml.in | 407 +++++++++++++++++++++++------------------------ 1 file changed, 198 insertions(+), 209 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index f2438e94b757..25eef2c3964b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -275,6 +275,204 @@ pcap-file: # Warning: 'checksum-validation' must be set to yes to have checksum tested checksum-checks: auto +## +## Step 5: App Layer Protocol Configuration +## + +# Configure the app-layer parsers. The protocols section details each +# protocol. +# +# The option "enabled" takes 3 values - "yes", "no", "detection-only". +# "yes" enables both detection and the parser, "no" disables both, and +# "detection-only" enables protocol detection only (parser disabled). +app-layer: + protocols: + tls: + enabled: yes + detection-ports: + dp: 443 + + #no-reassemble: yes + dcerpc: + enabled: yes + ftp: + enabled: yes + ssh: + enabled: yes + smtp: + enabled: yes + # Configure SMTP-MIME Decoder + mime: + # Decode MIME messages from SMTP transactions + # (may be resource intensive) + # This field supercedes all others because it turns the entire + # process on or off + decode-mime: yes + + # Decode MIME entity bodies (ie. base64, quoted-printable, etc.) + decode-base64: yes + decode-quoted-printable: yes + + # Maximum bytes per header data value stored in the data structure + # (default is 2000) + header-value-depth: 2000 + + # Extract URLs and save in state data structure + extract-urls: yes + # Set to yes to compute the md5 of the mail body. You will then + # be able to journalize it. + body-md5: no + # Configure inspected-tracker for file_data keyword + inspected-tracker: + content-limit: 100000 + content-inspect-min-size: 32768 + content-inspect-window: 4096 + imap: + enabled: detection-only + msn: + enabled: detection-only + smb: + enabled: yes + detection-ports: + dp: 139 + # Note: Modbus probe parser is minimalist due to the poor significant field + # Only Modbus message length (greater than Modbus header length) + # And Protocol ID (equal to 0) are checked in probing parser + # It is important to enable detection port and define Modbus port + # to avoid false positive + modbus: + # How many unreplied Modbus requests are considered a flood. + # If the limit is reached, app-layer-event:modbus.flooded; will match. + #request-flood: 500 + + enabled: no + detection-ports: + dp: 502 + # According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it + # is recommended to keep the TCP connection opened with a remote device + # and not to open and close it for each MODBUS/TCP transaction. In that + # case, it is important to set the depth of the stream reassembling as + # unlimited (stream.reassembly.depth: 0) + # smb2 detection is disabled internally inside the engine. + #smb2: + # enabled: yes + dns: + # memcaps. Globally and per flow/state. + #global-memcap: 16mb + #state-memcap: 512kb + + # How many unreplied DNS requests are considered a flood. + # If the limit is reached, app-layer-event:dns.flooded; will match. + #request-flood: 500 + + tcp: + enabled: yes + detection-ports: + dp: 53 + udp: + enabled: yes + detection-ports: + dp: 53 + http: + enabled: yes + # memcap: 64mb + + # default-config: Used when no server-config matches + # personality: List of personalities used by default + # request-body-limit: Limit reassembly of request body for inspection + # by http_client_body & pcre /P option. + # response-body-limit: Limit reassembly of response body for inspection + # by file_data, http_server_body & pcre /Q option. + # double-decode-path: Double decode path section of the URI + # double-decode-query: Double decode query section of the URI + # + # server-config: List of server configurations to use if address matches + # address: List of ip addresses or networks for this block + # personalitiy: List of personalities used by this block + # request-body-limit: Limit reassembly of request body for inspection + # by http_client_body & pcre /P option. + # response-body-limit: Limit reassembly of response body for inspection + # by file_data, http_server_body & pcre /Q option. + # double-decode-path: Double decode path section of the URI + # double-decode-query: Double decode query section of the URI + # + # uri-include-all: Include all parts of the URI. By default the + # 'scheme', username/password, hostname and port + # are excluded. Setting this option to true adds + # all of them to the normalized uri as inspected + # by http_uri, urilen, pcre with /U and the other + # keywords that inspect the normalized uri. + # Note that this does not affect http_raw_uri. + # Also, note that including all was the default in + # 1.4 and 2.0beta1. + # + # meta-field-limit: Hard size limit for request and response size + # limits. Applies to request line and headers, + # response line and headers. Does not apply to + # request or response bodies. Default is 18k. + # If this limit is reached an event is raised. + # + # Currently Available Personalities: + # Minimal, Generic, IDS (default), IIS_4_0, IIS_5_0, IIS_5_1, IIS_6_0, + # IIS_7_0, IIS_7_5, Apache_2 + libhtp: + default-config: + personality: IDS + + # Can be specified in kb, mb, gb. Just a number indicates + # it's in bytes. + request-body-limit: 100kb + response-body-limit: 100kb + + # inspection limits + request-body-minimal-inspect-size: 32kb + request-body-inspect-window: 4kb + response-body-minimal-inspect-size: 40kb + response-body-inspect-window: 16kb + + # auto will use http-body-inline mode in IPS mode, yes or no set it statically + http-body-inline: auto + + # Take a random value for inspection sizes around the specified value. + # This lower the risk of some evasion technics but could lead + # detection change between runs. It is set to 'yes' by default. + #randomize-inspection-sizes: yes + # If randomize-inspection-sizes is active, the value of various + # inspection size will be choosen in the [1 - range%, 1 + range%] + # range + # Default value of randomize-inspection-range is 10. + #randomize-inspection-range: 10 + + # decoding + double-decode-path: no + double-decode-query: no + + server-config: + + #- apache: + # address: [192.168.1.0/24, 127.0.0.0/8, "::1"] + # personality: Apache_2 + # # Can be specified in kb, mb, gb. Just a number indicates + # # it's in bytes. + # request-body-limit: 4096 + # response-body-limit: 4096 + # double-decode-path: no + # double-decode-query: no + + #- iis7: + # address: + # - 192.168.0.0/24 + # - 192.168.10.0/24 + # personality: IIS_7_0 + # # Can be specified in kb, mb, gb. Just a number indicates + # # it's in bytes. + # request-body-limit: 4096 + # response-body-limit: 4096 + # double-decode-path: no + # double-decode-query: no + + + # Number of packets preallocated per thread. The default is 1024. A higher number # will make sure each CPU will be more easily kept busy, but may negatively @@ -1284,215 +1482,6 @@ pcre: match-limit: 3500 match-limit-recursion: 1500 -# Holds details on the app-layer. The protocols section details each protocol. -# Under each protocol, the default value for detection-enabled and " -# parsed-enabled is yes, unless specified otherwise. -# Each protocol covers enabling/disabling parsers for all ipprotos -# the app-layer protocol runs on. For example "dcerpc" refers to the tcp -# version of the protocol as well as the udp version of the protocol. -# The option "enabled" takes 3 values - "yes", "no", "detection-only". -# "yes" enables both detection and the parser, "no" disables both, and -# "detection-only" enables detection only(parser disabled). -app-layer: - protocols: - tls: - enabled: yes - detection-ports: - dp: 443 - - #no-reassemble: yes - dcerpc: - enabled: yes - ftp: - enabled: yes - ssh: - enabled: yes - smtp: - enabled: yes - # Configure SMTP-MIME Decoder - mime: - # Decode MIME messages from SMTP transactions - # (may be resource intensive) - # This field supercedes all others because it turns the entire - # process on or off - decode-mime: yes - - # Decode MIME entity bodies (ie. base64, quoted-printable, etc.) - decode-base64: yes - decode-quoted-printable: yes - - # Maximum bytes per header data value stored in the data structure - # (default is 2000) - header-value-depth: 2000 - - # Extract URLs and save in state data structure - extract-urls: yes - # Set to yes to compute the md5 of the mail body. You will then - # be able to journalize it. - body-md5: no - # Configure inspected-tracker for file_data keyword - inspected-tracker: - content-limit: 100000 - content-inspect-min-size: 32768 - content-inspect-window: 4096 - imap: - enabled: detection-only - msn: - enabled: detection-only - smb: - enabled: yes - detection-ports: - dp: 139 - # Note: Modbus probe parser is minimalist due to the poor significant field - # Only Modbus message length (greater than Modbus header length) - # And Protocol ID (equal to 0) are checked in probing parser - # It is important to enable detection port and define Modbus port - # to avoid false positive - modbus: - # How many unreplied Modbus requests are considered a flood. - # If the limit is reached, app-layer-event:modbus.flooded; will match. - #request-flood: 500 - - enabled: no - detection-ports: - dp: 502 - # According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it - # is recommended to keep the TCP connection opened with a remote device - # and not to open and close it for each MODBUS/TCP transaction. In that - # case, it is important to set the depth of the stream reassembling as - # unlimited (stream.reassembly.depth: 0) - # smb2 detection is disabled internally inside the engine. - #smb2: - # enabled: yes - dns: - # memcaps. Globally and per flow/state. - #global-memcap: 16mb - #state-memcap: 512kb - - # How many unreplied DNS requests are considered a flood. - # If the limit is reached, app-layer-event:dns.flooded; will match. - #request-flood: 500 - - tcp: - enabled: yes - detection-ports: - dp: 53 - udp: - enabled: yes - detection-ports: - dp: 53 - http: - enabled: yes - # memcap: 64mb - - ########################################################################### - # Configure libhtp. - # - # - # default-config: Used when no server-config matches - # personality: List of personalities used by default - # request-body-limit: Limit reassembly of request body for inspection - # by http_client_body & pcre /P option. - # response-body-limit: Limit reassembly of response body for inspection - # by file_data, http_server_body & pcre /Q option. - # double-decode-path: Double decode path section of the URI - # double-decode-query: Double decode query section of the URI - # - # server-config: List of server configurations to use if address matches - # address: List of ip addresses or networks for this block - # personalitiy: List of personalities used by this block - # request-body-limit: Limit reassembly of request body for inspection - # by http_client_body & pcre /P option. - # response-body-limit: Limit reassembly of response body for inspection - # by file_data, http_server_body & pcre /Q option. - # double-decode-path: Double decode path section of the URI - # double-decode-query: Double decode query section of the URI - # - # uri-include-all: Include all parts of the URI. By default the - # 'scheme', username/password, hostname and port - # are excluded. Setting this option to true adds - # all of them to the normalized uri as inspected - # by http_uri, urilen, pcre with /U and the other - # keywords that inspect the normalized uri. - # Note that this does not affect http_raw_uri. - # Also, note that including all was the default in - # 1.4 and 2.0beta1. - # - # meta-field-limit: Hard size limit for request and response size - # limits. Applies to request line and headers, - # response line and headers. Does not apply to - # request or response bodies. Default is 18k. - # If this limit is reached an event is raised. - # - # Currently Available Personalities: - # Minimal - # Generic - # IDS (default) - # IIS_4_0 - # IIS_5_0 - # IIS_5_1 - # IIS_6_0 - # IIS_7_0 - # IIS_7_5 - # Apache_2 - ########################################################################### - libhtp: - - default-config: - personality: IDS - - # Can be specified in kb, mb, gb. Just a number indicates - # it's in bytes. - request-body-limit: 100kb - response-body-limit: 100kb - - # inspection limits - request-body-minimal-inspect-size: 32kb - request-body-inspect-window: 4kb - response-body-minimal-inspect-size: 40kb - response-body-inspect-window: 16kb - - # auto will use http-body-inline mode in IPS mode, yes or no set it statically - http-body-inline: auto - - # Take a random value for inspection sizes around the specified value. - # This lower the risk of some evasion technics but could lead - # detection change between runs. It is set to 'yes' by default. - #randomize-inspection-sizes: yes - # If randomize-inspection-sizes is active, the value of various - # inspection size will be choosen in the [1 - range%, 1 + range%] - # range - # Default value of randomize-inspection-range is 10. - #randomize-inspection-range: 10 - - # decoding - double-decode-path: no - double-decode-query: no - - server-config: - - #- apache: - # address: [192.168.1.0/24, 127.0.0.0/8, "::1"] - # personality: Apache_2 - # # Can be specified in kb, mb, gb. Just a number indicates - # # it's in bytes. - # request-body-limit: 4096 - # response-body-limit: 4096 - # double-decode-path: no - # double-decode-query: no - - #- iis7: - # address: - # - 192.168.0.0/24 - # - 192.168.10.0/24 - # personality: IIS_7_0 - # # Can be specified in kb, mb, gb. Just a number indicates - # # it's in bytes. - # request-body-limit: 4096 - # response-body-limit: 4096 - # double-decode-path: no - # double-decode-query: no - # Profiling settings. Only effective if Suricata has been built with the # the --enable-profiling configure flag. # From 11e6809d554b01897e5f2498a623f3645bdcb6e7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 19:19:56 +0200 Subject: [PATCH 1469/2553] yaml: introduce 'advanced settings' --- suricata.yaml.in | 356 +++++++++++++++++++++++++---------------------- 1 file changed, 187 insertions(+), 169 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 25eef2c3964b..a74f22b20c60 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -472,6 +472,48 @@ app-layer: # double-decode-query: no +############################################################################## +## +## Advanced settings below +## +############################################################################## + +## +## Run Options +## + +# Run suricata as user and group. +#run-as: +# user: suri +# group: suri + +# Some logging module will use that name in event as identifier. The default +# value is the hostname +#sensor-name: suricata + +# Default pid file. +# Will use this file if no --pidfile in command options. +#pid-file: @e_rundir@suricata.pid + +# Daemon working directory +# Suricata will change directory to this one if provided +# Default: "/" +#daemon-directory: "/" + +# Suricata core dump configuration. Limits the size of the core dump file to +# approximately max-dump. The actual core dump size will be a multiple of the +# page size. Core dumps that would be larger than max-dump are truncated. On +# Linux, the actual core dump size may be a few pages larger than max-dump. +# Setting max-dump to 0 disables core dumping. +# Setting max-dump to 'unlimited' will give the full core dump file. +# On 32-bit Linux, a max-dump value >= ULONG_MAX may cause the core dump size +# to be 'unlimited'. + +coredump: + max-dump: unlimited + + + # Number of packets preallocated per thread. The default is 1024. A higher number @@ -507,24 +549,6 @@ app-layer: # This feature is currently only used by the reject* keywords. host-mode: auto -# Run suricata as user and group. -#run-as: -# user: suri -# group: suri - -# Some logging module will use that name in event as identifier. The default -# value is the hostname -#sensor-name: suricata - -# Default pid file. -# Will use this file if no --pidfile in command options. -#pid-file: @e_rundir@suricata.pid - -# Daemon working directory -# Suricata will change directory to this one if provided -# Default: "/" -#daemon-directory: "/" - # Preallocated size for packet. Default is 1514 which is the classical # size for pcap on ethernet. You should adjust this value to the highest # packet size (MTU + hardware header) on your system. @@ -904,56 +928,6 @@ nflog: # netlink max buffer size max-size: 20000 -# Netmap support -# -# Netmap operates with NIC directly in driver, so you need FreeBSD wich have -# built-in netmap support or compile and install netmap module and appropriate -# NIC driver on your Linux system. -# To reach maximum throughput disable all receive-, segmentation-, -# checksum- offloadings on NIC. -# Disabling Tx checksum offloading is *required* for connecting OS endpoint -# with NIC endpoint. -# You can find more information at https://github.com/luigirizzo/netmap -# -netmap: - # To specify OS endpoint add plus sign at the end (e.g. "eth0+") - - interface: eth2 - # Number of receive threads. "auto" uses number of RSS queues on interface. - threads: auto - # You can use the following variables to activate netmap tap or IPS mode. - # If copy-mode is set to ips or tap, the traffic coming to the current - # interface will be copied to the copy-iface interface. If 'tap' is set, the - # copy is complete. If 'ips' is set, the packet matching a 'drop' action - # will not be copied. - # To specify the OS as the copy-iface (so the OS can route packets, or forward - # to a service running on the same machine) add a plus sign at the end - # (e.g. "copy-iface: eth0+"). Don't forget to set up a symmetrical eth0+ -> eth0 - # for return packets. Hardware checksumming must be *off* on the interface if - # using an OS endpoint (e.g. 'ifconfig eth0 -rxcsum -txcsum -rxcsum6 -txcsum6' for FreeBSD - # or 'ethtool -K eth0 tx off rx off' for Linux). - #copy-mode: tap - #copy-iface: eth3 - # Set to yes to disable promiscuous mode - # disable-promisc: no - # Choose checksum verification mode for the interface. At the moment - # of the capture, some packets may be with an invalid checksum due to - # offloading to the network card of the checksum computation. - # Possible values are: - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. - # Warning: 'checksum-validation' must be set to yes to have any validation - #checksum-checks: auto - # BPF filter to apply to this interface. The pcap filter syntax apply here. - #bpf-filter: port 80 or udp - #- interface: eth3 - #threads: auto - #copy-mode: tap - #copy-iface: eth2 - # Put default values here - - interface: default - legacy: uricontent: enabled @@ -1338,97 +1312,6 @@ host: # prealloc: 1000 # memcap: 16777216 -# Tilera mpipe configuration. for use on Tilera TILE-Gx. -mpipe: - - # Load balancing modes: "static", "dynamic", "sticky", or "round-robin". - load-balance: dynamic - - # Number of Packets in each ingress packet queue. Must be 128, 512, 2028 or 65536 - iqueue-packets: 2048 - - # List of interfaces we will listen on. - inputs: - - interface: xgbe2 - - interface: xgbe3 - - interface: xgbe4 - - - # Relative weight of memory for packets of each mPipe buffer size. - stack: - size128: 0 - size256: 9 - size512: 0 - size1024: 0 - size1664: 7 - size4096: 0 - size10386: 0 - size16384: 0 - -# PF_RING configuration. for use with native PF_RING support -# for more info see http://www.ntop.org/products/pf_ring/ -pfring: - - interface: eth0 - # Number of receive threads (>1 will enable experimental flow pinned - # runmode) - threads: 1 - - # Default clusterid. PF_RING will load balance packets based on flow. - # All threads/processes that will participate need to have the same - # clusterid. - cluster-id: 99 - - # Default PF_RING cluster type. PF_RING can load balance per flow. - # Possible values are cluster_flow or cluster_round_robin. - cluster-type: cluster_flow - # bpf filter for this interface - #bpf-filter: tcp - # Choose checksum verification mode for the interface. At the moment - # of the capture, some packets may be with an invalid checksum due to - # offloading to the network card of the checksum computation. - # Possible values are: - # - rxonly: only compute checksum for packets received by network card. - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. (default) - # Warning: 'checksum-validation' must be set to yes to have any validation - #checksum-checks: auto - # Second interface - #- interface: eth1 - # threads: 3 - # cluster-id: 93 - # cluster-type: cluster_flow - # Put default values here - - interface: default - #threads: 2 - -# For FreeBSD ipfw(8) divert(4) support. -# Please make sure you have ipfw_load="YES" and ipdivert_load="YES" -# in /etc/loader.conf or kldload'ing the appropriate kernel modules. -# Additionally, you need to have an ipfw rule for the engine to see -# the packets from ipfw. For Example: -# -# ipfw add 100 divert 8000 ip from any to any -# -# The 8000 above should be the same number you passed on the command -# line, i.e. -d 8000 -# -ipfw: - - # Reinject packets at the specified ipfw rule number. This config - # option is the ipfw rule number AT WHICH rule processing continues - # in the ipfw processing system after the engine has finished - # inspecting the packet for acceptance. If no rule number is specified, - # accepted packets are reinjected at the divert rule which they entered - # and IPFW rule processing continues. No check is done to verify - # this will rule makes sense so care must be taken to avoid loops in ipfw. - # - ## The following example tells the engine to reinject packets - # back into the ipfw firewall AT rule number 5500: - # - # ipfw-reinjection-rule-number: 5500 - # Set the order of alerts bassed on actions # The default order is pass, drop, reject, alert # action-order: @@ -1550,17 +1433,124 @@ profiling: filename: pcaplog_stats.log append: yes -# Suricata core dump configuration. Limits the size of the core dump file to -# approximately max-dump. The actual core dump size will be a multiple of the -# page size. Core dumps that would be larger than max-dump are truncated. On -# Linux, the actual core dump size may be a few pages larger than max-dump. -# Setting max-dump to 0 disables core dumping. -# Setting max-dump to 'unlimited' will give the full core dump file. -# On 32-bit Linux, a max-dump value >= ULONG_MAX may cause the core dump size -# to be 'unlimited'. +## +## Advanced Capture Options +## + +# Netmap support +# +# Netmap operates with NIC directly in driver, so you need FreeBSD wich have +# built-in netmap support or compile and install netmap module and appropriate +# NIC driver on your Linux system. +# To reach maximum throughput disable all receive-, segmentation-, +# checksum- offloadings on NIC. +# Disabling Tx checksum offloading is *required* for connecting OS endpoint +# with NIC endpoint. +# You can find more information at https://github.com/luigirizzo/netmap +# +netmap: + # To specify OS endpoint add plus sign at the end (e.g. "eth0+") + - interface: eth2 + # Number of receive threads. "auto" uses number of RSS queues on interface. + threads: auto + # You can use the following variables to activate netmap tap or IPS mode. + # If copy-mode is set to ips or tap, the traffic coming to the current + # interface will be copied to the copy-iface interface. If 'tap' is set, the + # copy is complete. If 'ips' is set, the packet matching a 'drop' action + # will not be copied. + # To specify the OS as the copy-iface (so the OS can route packets, or forward + # to a service running on the same machine) add a plus sign at the end + # (e.g. "copy-iface: eth0+"). Don't forget to set up a symmetrical eth0+ -> eth0 + # for return packets. Hardware checksumming must be *off* on the interface if + # using an OS endpoint (e.g. 'ifconfig eth0 -rxcsum -txcsum -rxcsum6 -txcsum6' for FreeBSD + # or 'ethtool -K eth0 tx off rx off' for Linux). + #copy-mode: tap + #copy-iface: eth3 + # Set to yes to disable promiscuous mode + # disable-promisc: no + # Choose checksum verification mode for the interface. At the moment + # of the capture, some packets may be with an invalid checksum due to + # offloading to the network card of the checksum computation. + # Possible values are: + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. + # Warning: 'checksum-validation' must be set to yes to have any validation + #checksum-checks: auto + # BPF filter to apply to this interface. The pcap filter syntax apply here. + #bpf-filter: port 80 or udp + #- interface: eth3 + #threads: auto + #copy-mode: tap + #copy-iface: eth2 + # Put default values here + - interface: default + +# PF_RING configuration. for use with native PF_RING support +# for more info see http://www.ntop.org/products/pf_ring/ +pfring: + - interface: eth0 + # Number of receive threads (>1 will enable experimental flow pinned + # runmode) + threads: 1 + + # Default clusterid. PF_RING will load balance packets based on flow. + # All threads/processes that will participate need to have the same + # clusterid. + cluster-id: 99 + + # Default PF_RING cluster type. PF_RING can load balance per flow. + # Possible values are cluster_flow or cluster_round_robin. + cluster-type: cluster_flow + # bpf filter for this interface + #bpf-filter: tcp + # Choose checksum verification mode for the interface. At the moment + # of the capture, some packets may be with an invalid checksum due to + # offloading to the network card of the checksum computation. + # Possible values are: + # - rxonly: only compute checksum for packets received by network card. + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. (default) + # Warning: 'checksum-validation' must be set to yes to have any validation + #checksum-checks: auto + # Second interface + #- interface: eth1 + # threads: 3 + # cluster-id: 93 + # cluster-type: cluster_flow + # Put default values here + - interface: default + #threads: 2 + +# For FreeBSD ipfw(8) divert(4) support. +# Please make sure you have ipfw_load="YES" and ipdivert_load="YES" +# in /etc/loader.conf or kldload'ing the appropriate kernel modules. +# Additionally, you need to have an ipfw rule for the engine to see +# the packets from ipfw. For Example: +# +# ipfw add 100 divert 8000 ip from any to any +# +# The 8000 above should be the same number you passed on the command +# line, i.e. -d 8000 +# +ipfw: + + # Reinject packets at the specified ipfw rule number. This config + # option is the ipfw rule number AT WHICH rule processing continues + # in the ipfw processing system after the engine has finished + # inspecting the packet for acceptance. If no rule number is specified, + # accepted packets are reinjected at the divert rule which they entered + # and IPFW rule processing continues. No check is done to verify + # this will rule makes sense so care must be taken to avoid loops in ipfw. + # + ## The following example tells the engine to reinject packets + # back into the ipfw firewall AT rule number 5500: + # + # ipfw-reinjection-rule-number: 5500 -coredump: - max-dump: unlimited napatech: # The Host Buffer Allowance for all streams @@ -1575,6 +1565,34 @@ napatech: # The streams to listen on streams: [1, 2, 3] +# Tilera mpipe configuration. for use on Tilera TILE-Gx. +mpipe: + + # Load balancing modes: "static", "dynamic", "sticky", or "round-robin". + load-balance: dynamic + + # Number of Packets in each ingress packet queue. Must be 128, 512, 2028 or 65536 + iqueue-packets: 2048 + + # List of interfaces we will listen on. + inputs: + - interface: xgbe2 + - interface: xgbe3 + - interface: xgbe4 + + + # Relative weight of memory for packets of each mPipe buffer size. + stack: + size128: 0 + size256: 9 + size512: 0 + size1024: 0 + size1664: 7 + size4096: 0 + size10386: 0 + size16384: 0 + + # Includes. Files included here will be handled as if they were # inlined in this configuration file. #include: include1.yaml From 056f88b4582d16eabb49801580fc7400bebd6e34 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 19:28:34 +0200 Subject: [PATCH 1470/2553] yaml: move outputs to the logging step --- suricata.yaml.in | 1411 +++++++++++++++++++++++----------------------- 1 file changed, 705 insertions(+), 706 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index a74f22b20c60..c5cb292cd554 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -107,785 +107,784 @@ rule-files: ## Step 3: select outputs to enable ## -# Logging configuration. This is not about logging IDS alerts, but -# output about what Suricata is doing, like startup messages, errors, etc. -logging: - # The default log level, can be overridden in an output section. - # Note that debug level logging will only be emitted if Suricata was - # compiled with the --enable-debug configure option. - # - # This value is overriden by the SC_LOG_LEVEL env var. - default-log-level: notice - - # The default output format. Optional parameter, should default to - # something reasonable if not provided. Can be overriden in an - # output section. You can leave this out to get the default. - # - # This value is overriden by the SC_LOG_FORMAT env var. - #default-log-format: "[%i] %t - (%f:%l) <%d> (%n) -- " +# The default logging directory. Any log or output file will be +# placed here if its not specified with a full path name. This can be +# overridden with the -l command line parameter. +default-log-dir: @e_logdir@ - # A regex to filter output. Can be overridden in an output section. - # Defaults to empty (no filter). - # - # This value is overriden by the SC_LOG_OP_FILTER env var. - default-output-filter: +# global stats configuration +stats: + enabled: yes + # The interval field (in seconds) controls at what interval + # the loggers are invoked. + interval: 8 - # Define your logging outputs. If none are defined, or they are all - # disabled you will get the default - console output. - outputs: - - console: - enabled: yes - # type: json - - file: +# Configure the type of alert (and other) logging you would like. +outputs: + # a line based alerts log similar to Snort's fast.log + - fast: enabled: yes - filename: @e_logdir@suricata.log - # type: json - - syslog: - enabled: no - facility: local5 - format: "[%i] <%d> -- " - # type: json - -## -## Step 4: configure capture settings -## - -# af-packet support -af-packet: - - interface: eth0 - # Number of receive threads. "auto" uses the number of cores - #threads: auto - # Default clusterid. AF_PACKET will load balance packets based on flow. - cluster-id: 99 - # Default AF_PACKET cluster type. AF_PACKET can load balance per flow or per hash. - # This is only supported for Linux kernel > 3.1 - # possible value are: - # * cluster_round_robin: round robin load balancing - # * cluster_flow: all packets of a given flow are send to the same socket - # * cluster_cpu: all packets treated in kernel by a CPU are send to the same socket - # * cluster_qm: all packets linked by network card to a RSS queue are sent to the same - # socket. Requires at least Linux 3.14. - # * cluster_random: packets are sent randomly to sockets but with an equipartition. - # Requires at least Linux 3.14. - # * cluster_rollover: kernel rotates between sockets filling each socket before moving - # to the next. Requires at least Linux 3.10. - # Recommended modes are cluster_flow on most boxes and cluster_cpu or cluster_qm on system - # with capture card using RSS (require cpu affinity tuning and system irq tuning) - cluster-type: cluster_flow - # In some fragmentation case, the hash can not be computed. If "defrag" is set - # to yes, the kernel will do the needed defragmentation before sending the packets. - defrag: yes - # After Linux kernel 3.10 it is possible to activate the rollover option: if a socket is - # full then kernel will send the packet on the next socket with room available. This option - # can minimize packet drop and increase the treated bandwidth on single intensive flow. - #rollover: yes - # To use the ring feature of AF_PACKET, set 'use-mmap' to yes - #use-mmap: yes - # Lock memory map to avoid it goes to swap. Be careful that over suscribing could lock - # your system - #mmap-locked: yes - # Use tpacket_v3, capture mode, only active if user-mmap is true - tpacket-v3: yes - # Ring size will be computed with respect to max_pending_packets and number - # of threads. You can set manually the ring size in number of packets by setting - # the following value. If you are using flow cluster-type and have really network - # intensive single-flow you could want to set the ring-size independently of the number - # of threads: - #ring-size: 2048 - # Block size is used by tpacket_v3 only. It should set to a value high enough to contain - # a decent number of packets. Size is in bytes so please consider your MTU. It should be - # a power of 2 and it must be multiple of page size (usually 4096). - #block-size: 32768 - # tpacket_v3 block timeout: an open block is passed to userspace if it is not - # filled after block-timeout milliseconds. - #block-timeout: 10 - # On busy system, this could help to set it to yes to recover from a packet drop - # phase. This will result in some packets (at max a ring flush) being non treated. - #use-emergency-flush: yes - # recv buffer size, increase value could improve performance - # buffer-size: 32768 - # Set to yes to disable promiscuous mode - # disable-promisc: no - # Choose checksum verification mode for the interface. At the moment - # of the capture, some packets may be with an invalid checksum due to - # offloading to the network card of the checksum computation. - # Possible values are: - # - kernel: use indication sent by kernel for each packet (default) - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. - # Warning: 'checksum-validation' must be set to yes to have any validation - #checksum-checks: kernel - # BPF filter to apply to this interface. The pcap filter syntax apply here. - #bpf-filter: port 80 or udp - # You can use the following variables to activate AF_PACKET tap or IPS mode. - # If copy-mode is set to ips or tap, the traffic coming to the current - # interface will be copied to the copy-iface interface. If 'tap' is set, the - # copy is complete. If 'ips' is set, the packet matching a 'drop' action - # will not be copied. - #copy-mode: ips - #copy-iface: eth1 - - # Put default values here. These will be used for an interface that is not - # in the list above. - - interface: default - #threads: auto - #use-mmap: no - #rollover: yes - tpacket-v3: yes - -pcap: - - interface: eth0 - # On Linux, pcap will try to use mmaped capture and will use buffer-size - # as total of memory used by the ring. So set this to something bigger - # than 1% of your bandwidth. - #buffer-size: 16777216 - #bpf-filter: "tcp and port 25" - # Choose checksum verification mode for the interface. At the moment - # of the capture, some packets may be with an invalid checksum due to - # offloading to the network card of the checksum computation. - # Possible values are: - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. (default) - # Warning: 'checksum-validation' must be set to yes to have any validation - #checksum-checks: auto - # With some accelerator cards using a modified libpcap (like myricom), you - # may want to have the same number of capture threads as the number of capture - # rings. In this case, set up the threads variable to N to start N threads - # listening on the same interface. - #threads: 16 - # set to no to disable promiscuous mode: - #promisc: no - # set snaplen, if not set it defaults to MTU if MTU can be known - # via ioctl call and to full capture if not. - #snaplen: 1518 - # Put default values here - - interface: default - #checksum-checks: auto - -pcap-file: - # Possible values are: - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. (default) - # Warning: 'checksum-validation' must be set to yes to have checksum tested - checksum-checks: auto - -## -## Step 5: App Layer Protocol Configuration -## + filename: fast.log + append: yes + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' -# Configure the app-layer parsers. The protocols section details each -# protocol. -# -# The option "enabled" takes 3 values - "yes", "no", "detection-only". -# "yes" enables both detection and the parser, "no" disables both, and -# "detection-only" enables protocol detection only (parser disabled). -app-layer: - protocols: - tls: + # Extensible Event Format (nicknamed EVE) event log in JSON format + - eve-log: enabled: yes - detection-ports: - dp: 443 + filetype: regular #regular|syslog|unix_dgram|unix_stream|redis + filename: eve.json + #prefix: "@cee: " # prefix to prepend to each log entry + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + #redis: + # server: 127.0.0.1 + # port: 6379 + # mode: list ## possible values: list (default), channel + # key: suricata ## key or channel to use (default to suricata) + # Redis pipelining set up. This will enable to only do a query every + # 'batch-size' events. This should lower the latency induced by network + # connection at the cost of some memory. There is no flushing implemented + # so this setting as to be reserved to high traffic suricata. + # pipelining: + # enabled: yes ## set enable to yes to enable query pipelining + # batch-size: 10 ## number of entry to keep in buffer + types: + - alert: + # payload: yes # enable dumping payload in Base64 + # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log + # payload-printable: yes # enable dumping payload in printable (lossy) format + # packet: yes # enable dumping of packet (without stream segments) + # http: yes # enable dumping of http fields + # tls: yes # enable dumping of tls fields + # ssh: yes # enable dumping of ssh fields + # smtp: yes # enable dumping of smtp fields - #no-reassemble: yes - dcerpc: - enabled: yes - ftp: - enabled: yes - ssh: - enabled: yes - smtp: - enabled: yes - # Configure SMTP-MIME Decoder - mime: - # Decode MIME messages from SMTP transactions - # (may be resource intensive) - # This field supercedes all others because it turns the entire - # process on or off - decode-mime: yes + # HTTP X-Forwarded-For support by adding an extra field or overwriting + # the source or destination IP address (depending on flow direction) + # with the one reported in the X-Forwarded-For HTTP header. This is + # helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. + xff: + enabled: no + # Two operation modes are available, "extra-data" and "overwrite". + mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For + - http: + extended: yes # enable this for extended logging information + # custom allows additional http fields to be included in eve-log + # the example below adds three additional fields when uncommented + #custom: [Accept-Encoding, Accept-Language, Authorization] + - dns + - tls: + extended: yes # enable this for extended logging information + - files: + force-magic: no # force logging magic on all logged files + force-md5: no # force logging of md5 checksums + #- drop: + # alerts: no # log alerts that caused drops + - smtp: + #extended: yes # enable this for extended logging information + # this includes: bcc, message-id, subject, x_mailer, user-agent + # custom fields logging from the list: + # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, + # x-originating-ip, in-reply-to, references, importance, priority, + # sensitivity, organization, content-md5, date + #custom: [received, x-mailer, x-originating-ip, relays, reply-to, bcc] + # output md5 of fields: body, subject + # for the body you need to set app-layer.protocols.smtp.mime.body-md5 + # to yes + #md5: [body, subject] - # Decode MIME entity bodies (ie. base64, quoted-printable, etc.) - decode-base64: yes - decode-quoted-printable: yes + - ssh + - stats: + totals: yes # stats for all threads merged together + threads: no # per thread stats + deltas: no # include delta values + # bi-directional flows + #- flow + # uni-directional flows + #- netflow - # Maximum bytes per header data value stored in the data structure - # (default is 2000) - header-value-depth: 2000 + # alert output for use with Barnyard2 + - unified2-alert: + enabled: no + filename: unified2.alert - # Extract URLs and save in state data structure - extract-urls: yes - # Set to yes to compute the md5 of the mail body. You will then - # be able to journalize it. - body-md5: no - # Configure inspected-tracker for file_data keyword - inspected-tracker: - content-limit: 100000 - content-inspect-min-size: 32768 - content-inspect-window: 4096 - imap: - enabled: detection-only - msn: - enabled: detection-only - smb: - enabled: yes - detection-ports: - dp: 139 - # Note: Modbus probe parser is minimalist due to the poor significant field - # Only Modbus message length (greater than Modbus header length) - # And Protocol ID (equal to 0) are checked in probing parser - # It is important to enable detection port and define Modbus port - # to avoid false positive - modbus: - # How many unreplied Modbus requests are considered a flood. - # If the limit is reached, app-layer-event:modbus.flooded; will match. - #request-flood: 500 + # File size limit. Can be specified in kb, mb, gb. Just a number + # is parsed as bytes. + #limit: 32mb - enabled: no - detection-ports: - dp: 502 - # According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it - # is recommended to keep the TCP connection opened with a remote device - # and not to open and close it for each MODBUS/TCP transaction. In that - # case, it is important to set the depth of the stream reassembling as - # unlimited (stream.reassembly.depth: 0) - # smb2 detection is disabled internally inside the engine. - #smb2: - # enabled: yes - dns: - # memcaps. Globally and per flow/state. - #global-memcap: 16mb - #state-memcap: 512kb + # Sensor ID field of unified2 alerts. + #sensor-id: 0 - # How many unreplied DNS requests are considered a flood. - # If the limit is reached, app-layer-event:dns.flooded; will match. - #request-flood: 500 + # Include payload of packets related to alerts. Defaults to true, set to + # false if payload is not required. + #payload: yes - tcp: - enabled: yes - detection-ports: - dp: 53 - udp: - enabled: yes - detection-ports: - dp: 53 - http: + # HTTP X-Forwarded-For support by adding the unified2 extra header or + # overwriting the source or destination IP address (depending on flow + # direction) with the one reported in the X-Forwarded-For HTTP header. + # This is helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. + xff: + enabled: no + # Two operation modes are available, "extra-data" and "overwrite". Note + # that in the "overwrite" mode, if the reported IP address in the HTTP + # X-Forwarded-For header is of a different version of the packet + # received, it will fall-back to "extra-data" mode. + mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For + + # a line based log of HTTP requests (no alerts) + - http-log: enabled: yes - # memcap: 64mb + filename: http.log + append: yes + #extended: yes # enable this for extended logging information + #custom: yes # enabled the custom logging format (defined by customformat) + #customformat: "%{%D-%H:%M:%S}t.%z %{X-Forwarded-For}i %H %m %h %u %s %B %a:%p -> %A:%P" + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' - # default-config: Used when no server-config matches - # personality: List of personalities used by default - # request-body-limit: Limit reassembly of request body for inspection - # by http_client_body & pcre /P option. - # response-body-limit: Limit reassembly of response body for inspection - # by file_data, http_server_body & pcre /Q option. - # double-decode-path: Double decode path section of the URI - # double-decode-query: Double decode query section of the URI - # - # server-config: List of server configurations to use if address matches - # address: List of ip addresses or networks for this block - # personalitiy: List of personalities used by this block - # request-body-limit: Limit reassembly of request body for inspection - # by http_client_body & pcre /P option. - # response-body-limit: Limit reassembly of response body for inspection - # by file_data, http_server_body & pcre /Q option. - # double-decode-path: Double decode path section of the URI - # double-decode-query: Double decode query section of the URI - # - # uri-include-all: Include all parts of the URI. By default the - # 'scheme', username/password, hostname and port - # are excluded. Setting this option to true adds - # all of them to the normalized uri as inspected - # by http_uri, urilen, pcre with /U and the other - # keywords that inspect the normalized uri. - # Note that this does not affect http_raw_uri. - # Also, note that including all was the default in - # 1.4 and 2.0beta1. - # - # meta-field-limit: Hard size limit for request and response size - # limits. Applies to request line and headers, - # response line and headers. Does not apply to - # request or response bodies. Default is 18k. - # If this limit is reached an event is raised. - # - # Currently Available Personalities: - # Minimal, Generic, IDS (default), IIS_4_0, IIS_5_0, IIS_5_1, IIS_6_0, - # IIS_7_0, IIS_7_5, Apache_2 - libhtp: - default-config: - personality: IDS + # a line based log of TLS handshake parameters (no alerts) + - tls-log: + enabled: no # Log TLS connections. + filename: tls.log # File to store TLS logs. + append: yes + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + #extended: yes # Log extended information like fingerprint - # Can be specified in kb, mb, gb. Just a number indicates - # it's in bytes. - request-body-limit: 100kb - response-body-limit: 100kb + # output module to store certificates chain to disk + - tls-store: + enabled: no + #certs-log-dir: certs # directory to store the certificates files - # inspection limits - request-body-minimal-inspect-size: 32kb - request-body-inspect-window: 4kb - response-body-minimal-inspect-size: 40kb - response-body-inspect-window: 16kb + # a line based log of DNS requests and/or replies (no alerts) + - dns-log: + enabled: no + filename: dns.log + append: yes + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' - # auto will use http-body-inline mode in IPS mode, yes or no set it statically - http-body-inline: auto + # Packet log... log packets in pcap format. 3 modes of operation: "normal" + # "multi" and "sguil". + # + # In normal mode a pcap file "filename" is created in the default-log-dir, + # or are as specified by "dir". + # In multi mode, a file is created per thread. This will perform much + # better, but will create multiple files where 'normal' would create one. + # In multi mode the filename takes a few special variables: + # - %n -- thread number + # - %i -- thread id + # - %t -- timestamp (secs or secs.usecs based on 'ts-format' + # E.g. filename: pcap.%n.%t + # + # Note that it's possible to use directories, but the directories are not + # created by Suricata. E.g. filename: pcaps/%n/log.%s will log into the + # per thread directory. + # + # Also note that the limit and max-files settings are enforced per thread. + # So the size limit when using 8 threads with 1000mb files and 2000 files + # is: 8*1000*2000 ~ 16TiB. + # + # In Sguil mode "dir" indicates the base directory. In this base dir the + # pcaps are created in th directory structure Sguil expects: + # + # $sguil-base-dir/YYYY-MM-DD/$filename. + # + # By default all packets are logged except: + # - TCP streams beyond stream.reassembly.depth + # - encrypted streams after the key exchange + # + - pcap-log: + enabled: no + filename: log.pcap - # Take a random value for inspection sizes around the specified value. - # This lower the risk of some evasion technics but could lead - # detection change between runs. It is set to 'yes' by default. - #randomize-inspection-sizes: yes - # If randomize-inspection-sizes is active, the value of various - # inspection size will be choosen in the [1 - range%, 1 + range%] - # range - # Default value of randomize-inspection-range is 10. - #randomize-inspection-range: 10 + # File size limit. Can be specified in kb, mb, gb. Just a number + # is parsed as bytes. + limit: 1000mb - # decoding - double-decode-path: no - double-decode-query: no + # If set to a value will enable ring buffer mode. Will keep Maximum of "max-files" of size "limit" + max-files: 2000 - server-config: + mode: normal # normal, multi or sguil. + #sguil-base-dir: /nsm_data/ + #ts-format: usec # sec or usec second format (default) is filename.sec usec is filename.sec.usec + use-stream-depth: no #If set to "yes" packets seen after reaching stream inspection depth are ignored. "no" logs all packets + honor-pass-rules: no # If set to "yes", flows in which a pass rule matched will stopped being logged. - #- apache: - # address: [192.168.1.0/24, 127.0.0.0/8, "::1"] - # personality: Apache_2 - # # Can be specified in kb, mb, gb. Just a number indicates - # # it's in bytes. - # request-body-limit: 4096 - # response-body-limit: 4096 - # double-decode-path: no - # double-decode-query: no + # a full alerts log containing much information for signature writers + # or for investigating suspected false positives. + - alert-debug: + enabled: no + filename: alert-debug.log + append: yes + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' - #- iis7: - # address: - # - 192.168.0.0/24 - # - 192.168.10.0/24 - # personality: IIS_7_0 - # # Can be specified in kb, mb, gb. Just a number indicates - # # it's in bytes. - # request-body-limit: 4096 - # response-body-limit: 4096 - # double-decode-path: no - # double-decode-query: no + # alert output to prelude (http://www.prelude-technologies.com/) only + # available if Suricata has been compiled with --enable-prelude + - alert-prelude: + enabled: no + profile: suricata + log-packet-content: no + log-packet-header: yes + # Stats.log contains data from various counters of the suricata engine. + - stats: + enabled: yes + filename: stats.log + totals: yes # stats for all threads merged together + threads: no # per thread stats + #null-values: yes # print counters that have value 0 -############################################################################## -## -## Advanced settings below -## -############################################################################## + # a line based alerts log similar to fast.log into syslog + - syslog: + enabled: no + # reported identity to syslog. If ommited the program name (usually + # suricata) will be used. + #identity: "suricata" + facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug -## -## Run Options -## + # a line based information for dropped packets in IPS mode + - drop: + enabled: no + filename: drop.log + append: yes + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' -# Run suricata as user and group. -#run-as: -# user: suri -# group: suri + # output module to store extracted files to disk + # + # The files are stored to the log-dir in a format "file." where is + # an incrementing number starting at 1. For each file "file." a meta + # file "file..meta" is created. + # + # File extraction depends on a lot of things to be fully done: + # - stream reassembly depth. For optimal results, set this to 0 (unlimited) + # - http request / response body sizes. Again set to 0 for optimal results. + # - rules that contain the "filestore" keyword. + - file-store: + enabled: no # set to yes to enable + log-dir: files # directory to store the files + force-magic: no # force logging magic on all stored files + force-md5: no # force logging of md5 checksums + force-filestore: no # force storing of all files + #waldo: file.waldo # waldo file to store the file_id across runs -# Some logging module will use that name in event as identifier. The default -# value is the hostname -#sensor-name: suricata + # output module to log files tracked in a easily parsable json format + - file-log: + enabled: no + filename: files-json.log + append: yes + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' -# Default pid file. -# Will use this file if no --pidfile in command options. -#pid-file: @e_rundir@suricata.pid + force-magic: no # force logging magic on all logged files + force-md5: no # force logging of md5 checksums -# Daemon working directory -# Suricata will change directory to this one if provided -# Default: "/" -#daemon-directory: "/" + # Log TCP data after stream normalization + # 2 types: file or dir. File logs into a single logfile. Dir creates + # 2 files per TCP session and stores the raw TCP data into them. + # Using 'both' will enable both file and dir modes. + # + # Note: limited by stream.depth + - tcp-data: + enabled: no + type: file + filename: tcp-data.log + + # Log HTTP body data after normalization, dechunking and unzipping. + # 2 types: file or dir. File logs into a single logfile. Dir creates + # 2 files per HTTP session and stores the normalized data into them. + # Using 'both' will enable both file and dir modes. + # + # Note: limited by the body limit settings + - http-body-data: + enabled: no + type: file + filename: http-data.log -# Suricata core dump configuration. Limits the size of the core dump file to -# approximately max-dump. The actual core dump size will be a multiple of the -# page size. Core dumps that would be larger than max-dump are truncated. On -# Linux, the actual core dump size may be a few pages larger than max-dump. -# Setting max-dump to 0 disables core dumping. -# Setting max-dump to 'unlimited' will give the full core dump file. -# On 32-bit Linux, a max-dump value >= ULONG_MAX may cause the core dump size -# to be 'unlimited'. + # Lua Output Support - execute lua script to generate alert and event + # output. + # Documented at: + # https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Lua_Output + - lua: + enabled: no + #scripts-dir: /etc/suricata/lua-output/ + scripts: + # - script1.lua -coredump: - max-dump: unlimited +# Logging configuration. This is not about logging IDS alerts, but +# output about what Suricata is doing, like startup messages, errors, etc. +logging: + # The default log level, can be overridden in an output section. + # Note that debug level logging will only be emitted if Suricata was + # compiled with the --enable-debug configure option. + # + # This value is overriden by the SC_LOG_LEVEL env var. + default-log-level: notice + # The default output format. Optional parameter, should default to + # something reasonable if not provided. Can be overriden in an + # output section. You can leave this out to get the default. + # + # This value is overriden by the SC_LOG_FORMAT env var. + #default-log-format: "[%i] %t - (%f:%l) <%d> (%n) -- " + # A regex to filter output. Can be overridden in an output section. + # Defaults to empty (no filter). + # + # This value is overriden by the SC_LOG_OP_FILTER env var. + default-output-filter: + # Define your logging outputs. If none are defined, or they are all + # disabled you will get the default - console output. + outputs: + - console: + enabled: yes + # type: json + - file: + enabled: yes + filename: @e_logdir@suricata.log + # type: json + - syslog: + enabled: no + facility: local5 + format: "[%i] <%d> -- " + # type: json +## +## Step 4: configure capture settings +## -# Number of packets preallocated per thread. The default is 1024. A higher number -# will make sure each CPU will be more easily kept busy, but may negatively -# impact caching. -# -# If you are using the CUDA pattern matcher (mpm-algo: ac-cuda), different rules -# apply. In that case try something like 60000 or more. This is because the CUDA -# pattern matcher buffers and scans as many packets as possible in parallel. -#max-pending-packets: 1024 +# af-packet support +af-packet: + - interface: eth0 + # Number of receive threads. "auto" uses the number of cores + #threads: auto + # Default clusterid. AF_PACKET will load balance packets based on flow. + cluster-id: 99 + # Default AF_PACKET cluster type. AF_PACKET can load balance per flow or per hash. + # This is only supported for Linux kernel > 3.1 + # possible value are: + # * cluster_round_robin: round robin load balancing + # * cluster_flow: all packets of a given flow are send to the same socket + # * cluster_cpu: all packets treated in kernel by a CPU are send to the same socket + # * cluster_qm: all packets linked by network card to a RSS queue are sent to the same + # socket. Requires at least Linux 3.14. + # * cluster_random: packets are sent randomly to sockets but with an equipartition. + # Requires at least Linux 3.14. + # * cluster_rollover: kernel rotates between sockets filling each socket before moving + # to the next. Requires at least Linux 3.10. + # Recommended modes are cluster_flow on most boxes and cluster_cpu or cluster_qm on system + # with capture card using RSS (require cpu affinity tuning and system irq tuning) + cluster-type: cluster_flow + # In some fragmentation case, the hash can not be computed. If "defrag" is set + # to yes, the kernel will do the needed defragmentation before sending the packets. + defrag: yes + # After Linux kernel 3.10 it is possible to activate the rollover option: if a socket is + # full then kernel will send the packet on the next socket with room available. This option + # can minimize packet drop and increase the treated bandwidth on single intensive flow. + #rollover: yes + # To use the ring feature of AF_PACKET, set 'use-mmap' to yes + #use-mmap: yes + # Lock memory map to avoid it goes to swap. Be careful that over suscribing could lock + # your system + #mmap-locked: yes + # Use tpacket_v3, capture mode, only active if user-mmap is true + tpacket-v3: yes + # Ring size will be computed with respect to max_pending_packets and number + # of threads. You can set manually the ring size in number of packets by setting + # the following value. If you are using flow cluster-type and have really network + # intensive single-flow you could want to set the ring-size independently of the number + # of threads: + #ring-size: 2048 + # Block size is used by tpacket_v3 only. It should set to a value high enough to contain + # a decent number of packets. Size is in bytes so please consider your MTU. It should be + # a power of 2 and it must be multiple of page size (usually 4096). + #block-size: 32768 + # tpacket_v3 block timeout: an open block is passed to userspace if it is not + # filled after block-timeout milliseconds. + #block-timeout: 10 + # On busy system, this could help to set it to yes to recover from a packet drop + # phase. This will result in some packets (at max a ring flush) being non treated. + #use-emergency-flush: yes + # recv buffer size, increase value could improve performance + # buffer-size: 32768 + # Set to yes to disable promiscuous mode + # disable-promisc: no + # Choose checksum verification mode for the interface. At the moment + # of the capture, some packets may be with an invalid checksum due to + # offloading to the network card of the checksum computation. + # Possible values are: + # - kernel: use indication sent by kernel for each packet (default) + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. + # Warning: 'checksum-validation' must be set to yes to have any validation + #checksum-checks: kernel + # BPF filter to apply to this interface. The pcap filter syntax apply here. + #bpf-filter: port 80 or udp + # You can use the following variables to activate AF_PACKET tap or IPS mode. + # If copy-mode is set to ips or tap, the traffic coming to the current + # interface will be copied to the copy-iface interface. If 'tap' is set, the + # copy is complete. If 'ips' is set, the packet matching a 'drop' action + # will not be copied. + #copy-mode: ips + #copy-iface: eth1 -# Runmode the engine should use. Please check --list-runmodes to get the available -# runmodes for each packet acquisition method. Defaults to "autofp" (auto flow pinned -# load balancing). -#runmode: autofp + # Put default values here. These will be used for an interface that is not + # in the list above. + - interface: default + #threads: auto + #use-mmap: no + #rollover: yes + tpacket-v3: yes -# Specifies the kind of flow load balancer used by the flow pinned autofp mode. -# -# Supported schedulers are: -# -# round-robin - Flows assigned to threads in a round robin fashion. -# active-packets - Flows assigned to threads that have the lowest number of -# unprocessed packets (default). -# hash - Flow alloted usihng the address hash. More of a random -# technique. Was the default in Suricata 1.2.1 and older. -# -#autofp-scheduler: active-packets +pcap: + - interface: eth0 + # On Linux, pcap will try to use mmaped capture and will use buffer-size + # as total of memory used by the ring. So set this to something bigger + # than 1% of your bandwidth. + #buffer-size: 16777216 + #bpf-filter: "tcp and port 25" + # Choose checksum verification mode for the interface. At the moment + # of the capture, some packets may be with an invalid checksum due to + # offloading to the network card of the checksum computation. + # Possible values are: + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. (default) + # Warning: 'checksum-validation' must be set to yes to have any validation + #checksum-checks: auto + # With some accelerator cards using a modified libpcap (like myricom), you + # may want to have the same number of capture threads as the number of capture + # rings. In this case, set up the threads variable to N to start N threads + # listening on the same interface. + #threads: 16 + # set to no to disable promiscuous mode: + #promisc: no + # set snaplen, if not set it defaults to MTU if MTU can be known + # via ioctl call and to full capture if not. + #snaplen: 1518 + # Put default values here + - interface: default + #checksum-checks: auto -# If suricata box is a router for the sniffed networks, set it to 'router'. If -# it is a pure sniffing setup, set it to 'sniffer-only'. -# If set to auto, the variable is internally switch to 'router' in IPS mode -# and 'sniffer-only' in IDS mode. -# This feature is currently only used by the reject* keywords. -host-mode: auto +pcap-file: + # Possible values are: + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. (default) + # Warning: 'checksum-validation' must be set to yes to have checksum tested + checksum-checks: auto -# Preallocated size for packet. Default is 1514 which is the classical -# size for pcap on ethernet. You should adjust this value to the highest -# packet size (MTU + hardware header) on your system. -#default-packet-size: 1514 +## +## Step 5: App Layer Protocol Configuration +## -# The default logging directory. Any log or output file will be -# placed here if its not specified with a full path name. This can be -# overridden with the -l command line parameter. -default-log-dir: @e_logdir@ +# Configure the app-layer parsers. The protocols section details each +# protocol. +# +# The option "enabled" takes 3 values - "yes", "no", "detection-only". +# "yes" enables both detection and the parser, "no" disables both, and +# "detection-only" enables protocol detection only (parser disabled). +app-layer: + protocols: + tls: + enabled: yes + detection-ports: + dp: 443 -# Unix command socket can be used to pass commands to suricata. -# An external tool can then connect to get information from suricata -# or trigger some modifications of the engine. Set enabled to yes -# to activate the feature. You can use the filename variable to set -# the file name of the socket. -unix-command: - enabled: no - #filename: custom.socket + #no-reassemble: yes + dcerpc: + enabled: yes + ftp: + enabled: yes + ssh: + enabled: yes + smtp: + enabled: yes + # Configure SMTP-MIME Decoder + mime: + # Decode MIME messages from SMTP transactions + # (may be resource intensive) + # This field supercedes all others because it turns the entire + # process on or off + decode-mime: yes -# global stats configuration -stats: - enabled: yes - # The interval field (in seconds) controls at what interval - # the loggers are invoked. - interval: 8 + # Decode MIME entity bodies (ie. base64, quoted-printable, etc.) + decode-base64: yes + decode-quoted-printable: yes -# Configure the type of alert (and other) logging you would like. -outputs: + # Maximum bytes per header data value stored in the data structure + # (default is 2000) + header-value-depth: 2000 - # a line based alerts log similar to Snort's fast.log - - fast: + # Extract URLs and save in state data structure + extract-urls: yes + # Set to yes to compute the md5 of the mail body. You will then + # be able to journalize it. + body-md5: no + # Configure inspected-tracker for file_data keyword + inspected-tracker: + content-limit: 100000 + content-inspect-min-size: 32768 + content-inspect-window: 4096 + imap: + enabled: detection-only + msn: + enabled: detection-only + smb: enabled: yes - filename: fast.log - append: yes - #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + detection-ports: + dp: 139 + # Note: Modbus probe parser is minimalist due to the poor significant field + # Only Modbus message length (greater than Modbus header length) + # And Protocol ID (equal to 0) are checked in probing parser + # It is important to enable detection port and define Modbus port + # to avoid false positive + modbus: + # How many unreplied Modbus requests are considered a flood. + # If the limit is reached, app-layer-event:modbus.flooded; will match. + #request-flood: 500 - # Extensible Event Format (nicknamed EVE) event log in JSON format - - eve-log: - enabled: yes - filetype: regular #regular|syslog|unix_dgram|unix_stream|redis - filename: eve.json - #prefix: "@cee: " # prefix to prepend to each log entry - # the following are valid when type: syslog above - #identity: "suricata" - #facility: local5 - #level: Info ## possible levels: Emergency, Alert, Critical, - ## Error, Warning, Notice, Info, Debug - #redis: - # server: 127.0.0.1 - # port: 6379 - # mode: list ## possible values: list (default), channel - # key: suricata ## key or channel to use (default to suricata) - # Redis pipelining set up. This will enable to only do a query every - # 'batch-size' events. This should lower the latency induced by network - # connection at the cost of some memory. There is no flushing implemented - # so this setting as to be reserved to high traffic suricata. - # pipelining: - # enabled: yes ## set enable to yes to enable query pipelining - # batch-size: 10 ## number of entry to keep in buffer - types: - - alert: - # payload: yes # enable dumping payload in Base64 - # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log - # payload-printable: yes # enable dumping payload in printable (lossy) format - # packet: yes # enable dumping of packet (without stream segments) - # http: yes # enable dumping of http fields - # tls: yes # enable dumping of tls fields - # ssh: yes # enable dumping of ssh fields - # smtp: yes # enable dumping of smtp fields + enabled: no + detection-ports: + dp: 502 + # According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it + # is recommended to keep the TCP connection opened with a remote device + # and not to open and close it for each MODBUS/TCP transaction. In that + # case, it is important to set the depth of the stream reassembling as + # unlimited (stream.reassembly.depth: 0) + # smb2 detection is disabled internally inside the engine. + #smb2: + # enabled: yes + dns: + # memcaps. Globally and per flow/state. + #global-memcap: 16mb + #state-memcap: 512kb - # HTTP X-Forwarded-For support by adding an extra field or overwriting - # the source or destination IP address (depending on flow direction) - # with the one reported in the X-Forwarded-For HTTP header. This is - # helpful when reviewing alerts for traffic that is being reverse - # or forward proxied. - xff: - enabled: no - # Two operation modes are available, "extra-data" and "overwrite". - mode: extra-data - # Two proxy deployments are supported, "reverse" and "forward". In - # a "reverse" deployment the IP address used is the last one, in a - # "forward" deployment the first IP address is used. - deployment: reverse - # Header name where the actual IP address will be reported, if more - # than one IP address is present, the last IP address will be the - # one taken into consideration. - header: X-Forwarded-For - - http: - extended: yes # enable this for extended logging information - # custom allows additional http fields to be included in eve-log - # the example below adds three additional fields when uncommented - #custom: [Accept-Encoding, Accept-Language, Authorization] - - dns - - tls: - extended: yes # enable this for extended logging information - - files: - force-magic: no # force logging magic on all logged files - force-md5: no # force logging of md5 checksums - #- drop: - # alerts: no # log alerts that caused drops - - smtp: - #extended: yes # enable this for extended logging information - # this includes: bcc, message-id, subject, x_mailer, user-agent - # custom fields logging from the list: - # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, - # x-originating-ip, in-reply-to, references, importance, priority, - # sensitivity, organization, content-md5, date - #custom: [received, x-mailer, x-originating-ip, relays, reply-to, bcc] - # output md5 of fields: body, subject - # for the body you need to set app-layer.protocols.smtp.mime.body-md5 - # to yes - #md5: [body, subject] + # How many unreplied DNS requests are considered a flood. + # If the limit is reached, app-layer-event:dns.flooded; will match. + #request-flood: 500 - - ssh - - stats: - totals: yes # stats for all threads merged together - threads: no # per thread stats - deltas: no # include delta values - # bi-directional flows - #- flow - # uni-directional flows - #- netflow + tcp: + enabled: yes + detection-ports: + dp: 53 + udp: + enabled: yes + detection-ports: + dp: 53 + http: + enabled: yes + # memcap: 64mb - # alert output for use with Barnyard2 - - unified2-alert: - enabled: no - filename: unified2.alert + # default-config: Used when no server-config matches + # personality: List of personalities used by default + # request-body-limit: Limit reassembly of request body for inspection + # by http_client_body & pcre /P option. + # response-body-limit: Limit reassembly of response body for inspection + # by file_data, http_server_body & pcre /Q option. + # double-decode-path: Double decode path section of the URI + # double-decode-query: Double decode query section of the URI + # + # server-config: List of server configurations to use if address matches + # address: List of ip addresses or networks for this block + # personalitiy: List of personalities used by this block + # request-body-limit: Limit reassembly of request body for inspection + # by http_client_body & pcre /P option. + # response-body-limit: Limit reassembly of response body for inspection + # by file_data, http_server_body & pcre /Q option. + # double-decode-path: Double decode path section of the URI + # double-decode-query: Double decode query section of the URI + # + # uri-include-all: Include all parts of the URI. By default the + # 'scheme', username/password, hostname and port + # are excluded. Setting this option to true adds + # all of them to the normalized uri as inspected + # by http_uri, urilen, pcre with /U and the other + # keywords that inspect the normalized uri. + # Note that this does not affect http_raw_uri. + # Also, note that including all was the default in + # 1.4 and 2.0beta1. + # + # meta-field-limit: Hard size limit for request and response size + # limits. Applies to request line and headers, + # response line and headers. Does not apply to + # request or response bodies. Default is 18k. + # If this limit is reached an event is raised. + # + # Currently Available Personalities: + # Minimal, Generic, IDS (default), IIS_4_0, IIS_5_0, IIS_5_1, IIS_6_0, + # IIS_7_0, IIS_7_5, Apache_2 + libhtp: + default-config: + personality: IDS - # File size limit. Can be specified in kb, mb, gb. Just a number - # is parsed as bytes. - #limit: 32mb + # Can be specified in kb, mb, gb. Just a number indicates + # it's in bytes. + request-body-limit: 100kb + response-body-limit: 100kb - # Sensor ID field of unified2 alerts. - #sensor-id: 0 + # inspection limits + request-body-minimal-inspect-size: 32kb + request-body-inspect-window: 4kb + response-body-minimal-inspect-size: 40kb + response-body-inspect-window: 16kb - # Include payload of packets related to alerts. Defaults to true, set to - # false if payload is not required. - #payload: yes + # auto will use http-body-inline mode in IPS mode, yes or no set it statically + http-body-inline: auto - # HTTP X-Forwarded-For support by adding the unified2 extra header or - # overwriting the source or destination IP address (depending on flow - # direction) with the one reported in the X-Forwarded-For HTTP header. - # This is helpful when reviewing alerts for traffic that is being reverse - # or forward proxied. - xff: - enabled: no - # Two operation modes are available, "extra-data" and "overwrite". Note - # that in the "overwrite" mode, if the reported IP address in the HTTP - # X-Forwarded-For header is of a different version of the packet - # received, it will fall-back to "extra-data" mode. - mode: extra-data - # Two proxy deployments are supported, "reverse" and "forward". In - # a "reverse" deployment the IP address used is the last one, in a - # "forward" deployment the first IP address is used. - deployment: reverse - # Header name where the actual IP address will be reported, if more - # than one IP address is present, the last IP address will be the - # one taken into consideration. - header: X-Forwarded-For + # Take a random value for inspection sizes around the specified value. + # This lower the risk of some evasion technics but could lead + # detection change between runs. It is set to 'yes' by default. + #randomize-inspection-sizes: yes + # If randomize-inspection-sizes is active, the value of various + # inspection size will be choosen in the [1 - range%, 1 + range%] + # range + # Default value of randomize-inspection-range is 10. + #randomize-inspection-range: 10 + + # decoding + double-decode-path: no + double-decode-query: no - # a line based log of HTTP requests (no alerts) - - http-log: - enabled: yes - filename: http.log - append: yes - #extended: yes # enable this for extended logging information - #custom: yes # enabled the custom logging format (defined by customformat) - #customformat: "%{%D-%H:%M:%S}t.%z %{X-Forwarded-For}i %H %m %h %u %s %B %a:%p -> %A:%P" - #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + server-config: - # a line based log of TLS handshake parameters (no alerts) - - tls-log: - enabled: no # Log TLS connections. - filename: tls.log # File to store TLS logs. - append: yes - #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' - #extended: yes # Log extended information like fingerprint + #- apache: + # address: [192.168.1.0/24, 127.0.0.0/8, "::1"] + # personality: Apache_2 + # # Can be specified in kb, mb, gb. Just a number indicates + # # it's in bytes. + # request-body-limit: 4096 + # response-body-limit: 4096 + # double-decode-path: no + # double-decode-query: no - # output module to store certificates chain to disk - - tls-store: - enabled: no - #certs-log-dir: certs # directory to store the certificates files + #- iis7: + # address: + # - 192.168.0.0/24 + # - 192.168.10.0/24 + # personality: IIS_7_0 + # # Can be specified in kb, mb, gb. Just a number indicates + # # it's in bytes. + # request-body-limit: 4096 + # response-body-limit: 4096 + # double-decode-path: no + # double-decode-query: no - # a line based log of DNS requests and/or replies (no alerts) - - dns-log: - enabled: no - filename: dns.log - append: yes - #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' - # Packet log... log packets in pcap format. 3 modes of operation: "normal" - # "multi" and "sguil". - # - # In normal mode a pcap file "filename" is created in the default-log-dir, - # or are as specified by "dir". - # In multi mode, a file is created per thread. This will perform much - # better, but will create multiple files where 'normal' would create one. - # In multi mode the filename takes a few special variables: - # - %n -- thread number - # - %i -- thread id - # - %t -- timestamp (secs or secs.usecs based on 'ts-format' - # E.g. filename: pcap.%n.%t - # - # Note that it's possible to use directories, but the directories are not - # created by Suricata. E.g. filename: pcaps/%n/log.%s will log into the - # per thread directory. - # - # Also note that the limit and max-files settings are enforced per thread. - # So the size limit when using 8 threads with 1000mb files and 2000 files - # is: 8*1000*2000 ~ 16TiB. - # - # In Sguil mode "dir" indicates the base directory. In this base dir the - # pcaps are created in th directory structure Sguil expects: - # - # $sguil-base-dir/YYYY-MM-DD/$filename. - # - # By default all packets are logged except: - # - TCP streams beyond stream.reassembly.depth - # - encrypted streams after the key exchange - # - - pcap-log: - enabled: no - filename: log.pcap +############################################################################## +## +## Advanced settings below +## +############################################################################## - # File size limit. Can be specified in kb, mb, gb. Just a number - # is parsed as bytes. - limit: 1000mb +## +## Run Options +## - # If set to a value will enable ring buffer mode. Will keep Maximum of "max-files" of size "limit" - max-files: 2000 +# Run suricata as user and group. +#run-as: +# user: suri +# group: suri - mode: normal # normal, multi or sguil. - #sguil-base-dir: /nsm_data/ - #ts-format: usec # sec or usec second format (default) is filename.sec usec is filename.sec.usec - use-stream-depth: no #If set to "yes" packets seen after reaching stream inspection depth are ignored. "no" logs all packets - honor-pass-rules: no # If set to "yes", flows in which a pass rule matched will stopped being logged. +# Some logging module will use that name in event as identifier. The default +# value is the hostname +#sensor-name: suricata - # a full alerts log containing much information for signature writers - # or for investigating suspected false positives. - - alert-debug: - enabled: no - filename: alert-debug.log - append: yes - #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' +# Default pid file. +# Will use this file if no --pidfile in command options. +#pid-file: @e_rundir@suricata.pid - # alert output to prelude (http://www.prelude-technologies.com/) only - # available if Suricata has been compiled with --enable-prelude - - alert-prelude: - enabled: no - profile: suricata - log-packet-content: no - log-packet-header: yes +# Daemon working directory +# Suricata will change directory to this one if provided +# Default: "/" +#daemon-directory: "/" - # Stats.log contains data from various counters of the suricata engine. - - stats: - enabled: yes - filename: stats.log - totals: yes # stats for all threads merged together - threads: no # per thread stats - #null-values: yes # print counters that have value 0 +# Suricata core dump configuration. Limits the size of the core dump file to +# approximately max-dump. The actual core dump size will be a multiple of the +# page size. Core dumps that would be larger than max-dump are truncated. On +# Linux, the actual core dump size may be a few pages larger than max-dump. +# Setting max-dump to 0 disables core dumping. +# Setting max-dump to 'unlimited' will give the full core dump file. +# On 32-bit Linux, a max-dump value >= ULONG_MAX may cause the core dump size +# to be 'unlimited'. - # a line based alerts log similar to fast.log into syslog - - syslog: - enabled: no - # reported identity to syslog. If ommited the program name (usually - # suricata) will be used. - #identity: "suricata" - facility: local5 - #level: Info ## possible levels: Emergency, Alert, Critical, - ## Error, Warning, Notice, Info, Debug +coredump: + max-dump: unlimited - # a line based information for dropped packets in IPS mode - - drop: - enabled: no - filename: drop.log - append: yes - #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' - # output module to store extracted files to disk - # - # The files are stored to the log-dir in a format "file." where is - # an incrementing number starting at 1. For each file "file." a meta - # file "file..meta" is created. - # - # File extraction depends on a lot of things to be fully done: - # - stream reassembly depth. For optimal results, set this to 0 (unlimited) - # - http request / response body sizes. Again set to 0 for optimal results. - # - rules that contain the "filestore" keyword. - - file-store: - enabled: no # set to yes to enable - log-dir: files # directory to store the files - force-magic: no # force logging magic on all stored files - force-md5: no # force logging of md5 checksums - force-filestore: no # force storing of all files - #waldo: file.waldo # waldo file to store the file_id across runs - # output module to log files tracked in a easily parsable json format - - file-log: - enabled: no - filename: files-json.log - append: yes - #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' - force-magic: no # force logging magic on all logged files - force-md5: no # force logging of md5 checksums - # Log TCP data after stream normalization - # 2 types: file or dir. File logs into a single logfile. Dir creates - # 2 files per TCP session and stores the raw TCP data into them. - # Using 'both' will enable both file and dir modes. - # - # Note: limited by stream.depth - - tcp-data: - enabled: no - type: file - filename: tcp-data.log +# Number of packets preallocated per thread. The default is 1024. A higher number +# will make sure each CPU will be more easily kept busy, but may negatively +# impact caching. +# +# If you are using the CUDA pattern matcher (mpm-algo: ac-cuda), different rules +# apply. In that case try something like 60000 or more. This is because the CUDA +# pattern matcher buffers and scans as many packets as possible in parallel. +#max-pending-packets: 1024 - # Log HTTP body data after normalization, dechunking and unzipping. - # 2 types: file or dir. File logs into a single logfile. Dir creates - # 2 files per HTTP session and stores the normalized data into them. - # Using 'both' will enable both file and dir modes. - # - # Note: limited by the body limit settings - - http-body-data: - enabled: no - type: file - filename: http-data.log +# Runmode the engine should use. Please check --list-runmodes to get the available +# runmodes for each packet acquisition method. Defaults to "autofp" (auto flow pinned +# load balancing). +#runmode: autofp - # Lua Output Support - execute lua script to generate alert and event - # output. - # Documented at: - # https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Lua_Output - - lua: - enabled: no - #scripts-dir: /etc/suricata/lua-output/ - scripts: - # - script1.lua +# Specifies the kind of flow load balancer used by the flow pinned autofp mode. +# +# Supported schedulers are: +# +# round-robin - Flows assigned to threads in a round robin fashion. +# active-packets - Flows assigned to threads that have the lowest number of +# unprocessed packets (default). +# hash - Flow alloted usihng the address hash. More of a random +# technique. Was the default in Suricata 1.2.1 and older. +# +#autofp-scheduler: active-packets + +# If suricata box is a router for the sniffed networks, set it to 'router'. If +# it is a pure sniffing setup, set it to 'sniffer-only'. +# If set to auto, the variable is internally switch to 'router' in IPS mode +# and 'sniffer-only' in IDS mode. +# This feature is currently only used by the reject* keywords. +host-mode: auto + +# Preallocated size for packet. Default is 1514 which is the classical +# size for pcap on ethernet. You should adjust this value to the highest +# packet size (MTU + hardware header) on your system. +#default-packet-size: 1514 + +# Unix command socket can be used to pass commands to suricata. +# An external tool can then connect to get information from suricata +# or trigger some modifications of the engine. Set enabled to yes +# to activate the feature. You can use the filename variable to set +# the file name of the socket. +unix-command: + enabled: no + #filename: custom.socket # Magic file. The extension .mgc is added to the value here. #magic-file: /usr/share/file/magic From 8fae138d3b9cc36b26b32940825c1cf4ab267e26 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 19:30:33 +0200 Subject: [PATCH 1471/2553] yaml: add netfilter section --- suricata.yaml.in | 94 ++++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index c5cb292cd554..fb2adc1a0192 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -835,9 +835,12 @@ app-layer: coredump: max-dump: unlimited - - - +# If suricata box is a router for the sniffed networks, set it to 'router'. If +# it is a pure sniffing setup, set it to 'sniffer-only'. +# If set to auto, the variable is internally switch to 'router' in IPS mode +# and 'sniffer-only' in IDS mode. +# This feature is currently only used by the reject* keywords. +host-mode: auto # Number of packets preallocated per thread. The default is 1024. A higher number # will make sure each CPU will be more easily kept busy, but may negatively @@ -865,13 +868,6 @@ coredump: # #autofp-scheduler: active-packets -# If suricata box is a router for the sniffed networks, set it to 'router'. If -# it is a pure sniffing setup, set it to 'sniffer-only'. -# If set to auto, the variable is internally switch to 'router' in IPS mode -# and 'sniffer-only' in IDS mode. -# This feature is currently only used by the reject* keywords. -host-mode: auto - # Preallocated size for packet. Default is 1514 which is the classical # size for pcap on ethernet. You should adjust this value to the highest # packet size (MTU + hardware header) on your system. @@ -890,43 +886,6 @@ unix-command: #magic-file: /usr/share/file/magic @e_magic_file_comment@magic-file: @e_magic_file@ -# When running in NFQ inline mode, it is possible to use a simulated -# non-terminal NFQUEUE verdict. -# This permit to do send all needed packet to suricata via this a rule: -# iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE -# And below, you can have your standard filtering ruleset. To activate -# this mode, you need to set mode to 'repeat' -# If you want packet to be sent to another queue after an ACCEPT decision -# set mode to 'route' and set next-queue value. -# On linux >= 3.1, you can set batchcount to a value > 1 to improve performance -# by processing several packets before sending a verdict (worker runmode only). -# On linux >= 3.6, you can set the fail-open option to yes to have the kernel -# accept the packet if suricata is not able to keep pace. -nfq: -# mode: accept -# repeat-mark: 1 -# repeat-mask: 1 -# route-queue: 2 -# batchcount: 20 -# fail-open: yes - -#nflog support -nflog: - # netlink multicast group - # (the same as the iptables --nflog-group param) - # Group 0 is used by the kernel, so you can't use it - - group: 2 - # netlink buffer size - buffer-size: 18432 - # put default value here - - group: default - # set number of packet to queue inside kernel - qthreshold: 1 - # set the delay before flushing packet in the queue inside kernel - qtimeout: 100 - # netlink max buffer size - max-size: 20000 - legacy: uricontent: enabled @@ -1432,6 +1391,47 @@ profiling: filename: pcaplog_stats.log append: yes +## +## Netfilter integration +## + +# When running in NFQ inline mode, it is possible to use a simulated +# non-terminal NFQUEUE verdict. +# This permit to do send all needed packet to suricata via this a rule: +# iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE +# And below, you can have your standard filtering ruleset. To activate +# this mode, you need to set mode to 'repeat' +# If you want packet to be sent to another queue after an ACCEPT decision +# set mode to 'route' and set next-queue value. +# On linux >= 3.1, you can set batchcount to a value > 1 to improve performance +# by processing several packets before sending a verdict (worker runmode only). +# On linux >= 3.6, you can set the fail-open option to yes to have the kernel +# accept the packet if suricata is not able to keep pace. +nfq: +# mode: accept +# repeat-mark: 1 +# repeat-mask: 1 +# route-queue: 2 +# batchcount: 20 +# fail-open: yes + +#nflog support +nflog: + # netlink multicast group + # (the same as the iptables --nflog-group param) + # Group 0 is used by the kernel, so you can't use it + - group: 2 + # netlink buffer size + buffer-size: 18432 + # put default value here + - group: default + # set number of packet to queue inside kernel + qthreshold: 1 + # set the delay before flushing packet in the queue inside kernel + qtimeout: 100 + # netlink max buffer size + max-size: 20000 + ## ## Advanced Capture Options ## From d79c95ddedf670cf8bcf10c1a1a12e584b154253 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 19:33:00 +0200 Subject: [PATCH 1472/2553] yaml: add hw accel section, move cuda there --- suricata.yaml.in | 66 +++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index fb2adc1a0192..91b61f690ec5 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -993,37 +993,6 @@ threading: # detect-thread-ratio: 1.5 -# Cuda configuration. -cuda: - # The "mpm" profile. On not specifying any of these parameters, the engine's - # internal default values are used, which are same as the ones specified in - # in the default conf file. - mpm: - # The minimum length required to buffer data to the gpu. - # Anything below this is MPM'ed on the CPU. - # Can be specified in kb, mb, gb. Just a number indicates it's in bytes. - # A value of 0 indicates there's no limit. - data-buffer-size-min-limit: 0 - # The maximum length for data that we would buffer to the gpu. - # Anything over this is MPM'ed on the CPU. - # Can be specified in kb, mb, gb. Just a number indicates it's in bytes. - data-buffer-size-max-limit: 1500 - # The ring buffer size used by the CudaBuffer API to buffer data. - cudabuffer-buffer-size: 500mb - # The max chunk size that can be sent to the gpu in a single go. - gpu-transfer-size: 50mb - # The timeout limit for batching of packets in microseconds. - batching-timeout: 2000 - # The device to use for the mpm. Currently we don't support load balancing - # on multiple gpus. In case you have multiple devices on your system, you - # can specify the device to use, using this conf. By default we hold 0, to - # specify the first device cuda sees. To find out device-id associated with - # the card(s) on the system run "suricata --list-cuda-cards". - device-id: 0 - # No of Cuda streams used for asynchronous processing. All values > 0 are valid. - # For this option you need a device with Compute Capability > 1.0. - cuda-streams: 2 - # Select the multi pattern algorithm you want to run for scan/search the # in the engine. # @@ -1591,6 +1560,41 @@ mpipe: size10386: 0 size16384: 0 +## +## Hardware accelaration +## + +# Cuda configuration. +cuda: + # The "mpm" profile. On not specifying any of these parameters, the engine's + # internal default values are used, which are same as the ones specified in + # in the default conf file. + mpm: + # The minimum length required to buffer data to the gpu. + # Anything below this is MPM'ed on the CPU. + # Can be specified in kb, mb, gb. Just a number indicates it's in bytes. + # A value of 0 indicates there's no limit. + data-buffer-size-min-limit: 0 + # The maximum length for data that we would buffer to the gpu. + # Anything over this is MPM'ed on the CPU. + # Can be specified in kb, mb, gb. Just a number indicates it's in bytes. + data-buffer-size-max-limit: 1500 + # The ring buffer size used by the CudaBuffer API to buffer data. + cudabuffer-buffer-size: 500mb + # The max chunk size that can be sent to the gpu in a single go. + gpu-transfer-size: 50mb + # The timeout limit for batching of packets in microseconds. + batching-timeout: 2000 + # The device to use for the mpm. Currently we don't support load balancing + # on multiple gpus. In case you have multiple devices on your system, you + # can specify the device to use, using this conf. By default we hold 0, to + # specify the first device cuda sees. To find out device-id associated with + # the card(s) on the system run "suricata --list-cuda-cards". + device-id: 0 + # No of Cuda streams used for asynchronous processing. All values > 0 are valid. + # For this option you need a device with Compute Capability > 1.0. + cuda-streams: 2 + # Includes. Files included here will be handled as if they were # inlined in this configuration file. From a6a69f00993d157c73ff01708be753a752010570 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 19:38:46 +0200 Subject: [PATCH 1473/2553] yaml: create advancted sections Sections for advancted detection settings and traffic tracking and reconstruction. --- suricata.yaml.in | 106 +++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 46 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 91b61f690ec5..6fae0fcb77a1 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -889,6 +889,10 @@ unix-command: legacy: uricontent: enabled +## +## Detection settings +## + # The detection engine builds internal groups of signatures. The engine # allow us to specify the profile to use for them, to manage memory on an # efficient way keeping a good performance. For the profile keyword you @@ -938,6 +942,59 @@ detect: include-rules: false # very verbose include-mpm-stats: false +# Select the multi pattern algorithm you want to run for scan/search the +# in the engine. +# +# The supported algorithms are: +# "ac" - Aho-Corasick, default implementation +# "ac-bs" - Aho-Corasick, reduced memory implementation +# "ac-cuda" - Aho-Corasick, CUDA implementation +# "ac-tile" - Aho-Corasick, optimized for Tilera architecture +# "hs" - Hyperscan, available when built with Hyperscan support +# +# The default mpm-algo value of "auto" will use "hs" if Hyperscan is available, +# "ac-tile" on Tilera platforms, and "ac" otherwise. +# +# The mpm you choose also decides the distribution of mpm contexts for +# signature groups, specified by the conf - "detect.sgh-mpm-context". +# Selecting "ac" as the mpm would require "detect.sgh-mpm-context" +# to be set to "single", because of ac's memory requirements, unless the +# ruleset is small enough to fit in one's memory, in which case one can +# use "full" with "ac". Rest of the mpms can be run in "full" mode. +# +# There is also a CUDA pattern matcher (only available if Suricata was +# compiled with --enable-cuda: b2g_cuda. Make sure to update your +# max-pending-packets setting above as well if you use b2g_cuda. + +mpm-algo: auto + +# Select the matching algorithm you want to use for single-pattern searches. +# +# Supported algorithms are "bm" (Boyer-Moore) and "hs" (Hyperscan, only +# available if Suricata has been built with Hyperscan support). +# +# The default of "auto" will use "hs" if available, otherwise "bm". + +spm-algo: auto + +# Set the order of alerts bassed on actions +# The default order is pass, drop, reject, alert +# action-order: +# - pass +# - drop +# - reject +# - alert + +# IP Reputation +#reputation-categories-file: @e_sysconfdir@iprep/categories.txt +#default-reputation-path: @e_sysconfdir@iprep +#reputation-files: +# - reputation.list + +## +## Threading +## + # Suricata is multi-threaded. Here the threading can be influenced. threading: # On some cpu's/architectures it is beneficial to tie individual threads @@ -993,40 +1050,10 @@ threading: # detect-thread-ratio: 1.5 -# Select the multi pattern algorithm you want to run for scan/search the -# in the engine. -# -# The supported algorithms are: -# "ac" - Aho-Corasick, default implementation -# "ac-bs" - Aho-Corasick, reduced memory implementation -# "ac-cuda" - Aho-Corasick, CUDA implementation -# "ac-tile" - Aho-Corasick, optimized for Tilera architecture -# "hs" - Hyperscan, available when built with Hyperscan support -# -# The default mpm-algo value of "auto" will use "hs" if Hyperscan is available, -# "ac-tile" on Tilera platforms, and "ac" otherwise. -# -# The mpm you choose also decides the distribution of mpm contexts for -# signature groups, specified by the conf - "detect.sgh-mpm-context". -# Selecting "ac" as the mpm would require "detect.sgh-mpm-context" -# to be set to "single", because of ac's memory requirements, unless the -# ruleset is small enough to fit in one's memory, in which case one can -# use "full" with "ac". Rest of the mpms can be run in "full" mode. -# -# There is also a CUDA pattern matcher (only available if Suricata was -# compiled with --enable-cuda: b2g_cuda. Make sure to update your -# max-pending-packets setting above as well if you use b2g_cuda. -mpm-algo: auto - -# Select the matching algorithm you want to use for single-pattern searches. -# -# Supported algorithms are "bm" (Boyer-Moore) and "hs" (Hyperscan, only -# available if Suricata has been built with Hyperscan support). -# -# The default of "auto" will use "hs" if available, otherwise "bm". - -spm-algo: auto +## +## Advanced Traffic Tracking and Reconstruction Settings +## # Defrag settings: @@ -1239,19 +1266,6 @@ host: # prealloc: 1000 # memcap: 16777216 -# Set the order of alerts bassed on actions -# The default order is pass, drop, reject, alert -# action-order: -# - pass -# - drop -# - reject -# - alert - -# IP Reputation -#reputation-categories-file: @e_sysconfdir@iprep/categories.txt -#default-reputation-path: @e_sysconfdir@iprep -#reputation-files: -# - reputation.list # Host specific policies for defragmentation and TCP stream # reassembly. The host OS lookup is done using a radix tree, just From 6d7b4c81e3e2dd79bbb933f21c16b7f0d8a660c5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 21:10:44 +0200 Subject: [PATCH 1474/2553] yaml: more reshuffling --- suricata.yaml.in | 76 ++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 6fae0fcb77a1..737bebee8587 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -794,6 +794,9 @@ app-layer: # double-decode-path: no # double-decode-query: no +# Limit for the maximum number of asn1 frames to decode (default 256) +asn1-max-frames: 256 + ############################################################################## ## @@ -991,6 +994,22 @@ spm-algo: auto #reputation-files: # - reputation.list +# When run with the option --engine-analysis, the engine will read each of +# the parameters below, and print reports for each of the enabled sections +# and exit. The reports are printed to a file in the default log dir +# given by the parameter "default-log-dir", with engine reporting +# subsection below printing reports in its own report file. +engine-analysis: + # enables printing reports for fast-pattern for every rule. + rules-fast-pattern: yes + # enables printing reports for each rule + rules: yes + +#recursion and match limits for PCRE where supported +pcre: + match-limit: 3500 + match-limit-recursion: 1500 + ## ## Threading ## @@ -1055,6 +1074,25 @@ threading: ## Advanced Traffic Tracking and Reconstruction Settings ## +# Host specific policies for defragmentation and TCP stream +# reassembly. The host OS lookup is done using a radix tree, just +# like a routing table so the most specific entry matches. +host-os-policy: + # Make the default policy windows. + windows: [0.0.0.0/0] + bsd: [] + bsd-right: [] + old-linux: [] + linux: [10.0.0.0/8, 192.168.1.100, "8762:2352:6241:7245:E000:0000:0000:0000"] + old-solaris: [] + solaris: ["::1"] + hpux10: [] + hpux11: [] + irix: [] + macos: [] + vista: [] + windows2k3: [] + # Defrag settings: defrag: @@ -1267,44 +1305,6 @@ host: # memcap: 16777216 -# Host specific policies for defragmentation and TCP stream -# reassembly. The host OS lookup is done using a radix tree, just -# like a routing table so the most specific entry matches. -host-os-policy: - # Make the default policy windows. - windows: [0.0.0.0/0] - bsd: [] - bsd-right: [] - old-linux: [] - linux: [10.0.0.0/8, 192.168.1.100, "8762:2352:6241:7245:E000:0000:0000:0000"] - old-solaris: [] - solaris: ["::1"] - hpux10: [] - hpux11: [] - irix: [] - macos: [] - vista: [] - windows2k3: [] - - -# Limit for the maximum number of asn1 frames to decode (default 256) -asn1-max-frames: 256 - -# When run with the option --engine-analysis, the engine will read each of -# the parameters below, and print reports for each of the enabled sections -# and exit. The reports are printed to a file in the default log dir -# given by the parameter "default-log-dir", with engine reporting -# subsection below printing reports in its own report file. -engine-analysis: - # enables printing reports for fast-pattern for every rule. - rules-fast-pattern: yes - # enables printing reports for each rule - rules: yes - -#recursion and match limits for PCRE where supported -pcre: - match-limit: 3500 - match-limit-recursion: 1500 # Profiling settings. Only effective if Suricata has been built with the # the --enable-profiling configure flag. From ea7923cc8116b5993ce1c105f40b08a06d2f0211 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 21:21:20 +0200 Subject: [PATCH 1475/2553] yaml: add performance tuning section --- suricata.yaml.in | 289 ++++++++++++++++++++++++----------------------- 1 file changed, 145 insertions(+), 144 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 737bebee8587..52195f93b6b3 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -42,6 +42,7 @@ vars: DNP3_PORTS: 20000 MODBUS_PORTS: 502 + ## ## Step 2: select the rules to enable or disable ## @@ -103,6 +104,7 @@ rule-files: # - modbus-events.rules # available in suricata sources under rules dir # - app-layer-events.rules # available in suricata sources under rules dir + ## ## Step 3: select outputs to enable ## @@ -469,6 +471,7 @@ logging: format: "[%i] <%d> -- " # type: json + ## ## Step 4: configure capture settings ## @@ -598,6 +601,7 @@ pcap-file: # Warning: 'checksum-validation' must be set to yes to have checksum tested checksum-checks: auto + ## ## Step 5: App Layer Protocol Configuration ## @@ -896,90 +900,6 @@ legacy: ## Detection settings ## -# The detection engine builds internal groups of signatures. The engine -# allow us to specify the profile to use for them, to manage memory on an -# efficient way keeping a good performance. For the profile keyword you -# can use the words "low", "medium", "high" or "custom". If you use custom -# make sure to define the values at "- custom-values" as your convenience. -# Usually you would prefer medium/high/low. -# -# "sgh mpm-context", indicates how the staging should allot mpm contexts for -# the signature groups. "single" indicates the use of a single context for -# all the signature group heads. "full" indicates a mpm-context for each -# group head. "auto" lets the engine decide the distribution of contexts -# based on the information the engine gathers on the patterns from each -# group head. -# -# The option inspection-recursion-limit is used to limit the recursive calls -# in the content inspection code. For certain payload-sig combinations, we -# might end up taking too much time in the content inspection code. -# If the argument specified is 0, the engine uses an internally defined -# default limit. On not specifying a value, we use no limits on the recursion. -detect: - profile: medium - custom-values: - toclient-groups: 3 - toserver-groups: 25 - sgh-mpm-context: auto - inspection-recursion-limit: 3000 - # If set to yes, the loading of signatures will be made after the capture - # is started. This will limit the downtime in IPS mode. - #delayed-detect: yes - - # the grouping values above control how many groups are created per - # direction. Port whitelisting forces that port to get it's own group. - # Very common ports will benefit, as well as ports with many expensive - # rules. - grouping: - #tcp-whitelist: 53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080 - #udp-whitelist: 53, 135, 5060 - - profiling: - # Log the rules that made it past the prefilter stage, per packet - # default is off. The threshold setting determines how many rules - # must have made it past pre-filter for that rule to trigger the - # logging. - #inspect-logging-threshold: 200 - grouping: - dump-to-disk: false - include-rules: false # very verbose - include-mpm-stats: false - -# Select the multi pattern algorithm you want to run for scan/search the -# in the engine. -# -# The supported algorithms are: -# "ac" - Aho-Corasick, default implementation -# "ac-bs" - Aho-Corasick, reduced memory implementation -# "ac-cuda" - Aho-Corasick, CUDA implementation -# "ac-tile" - Aho-Corasick, optimized for Tilera architecture -# "hs" - Hyperscan, available when built with Hyperscan support -# -# The default mpm-algo value of "auto" will use "hs" if Hyperscan is available, -# "ac-tile" on Tilera platforms, and "ac" otherwise. -# -# The mpm you choose also decides the distribution of mpm contexts for -# signature groups, specified by the conf - "detect.sgh-mpm-context". -# Selecting "ac" as the mpm would require "detect.sgh-mpm-context" -# to be set to "single", because of ac's memory requirements, unless the -# ruleset is small enough to fit in one's memory, in which case one can -# use "full" with "ac". Rest of the mpms can be run in "full" mode. -# -# There is also a CUDA pattern matcher (only available if Suricata was -# compiled with --enable-cuda: b2g_cuda. Make sure to update your -# max-pending-packets setting above as well if you use b2g_cuda. - -mpm-algo: auto - -# Select the matching algorithm you want to use for single-pattern searches. -# -# Supported algorithms are "bm" (Boyer-Moore) and "hs" (Hyperscan, only -# available if Suricata has been built with Hyperscan support). -# -# The default of "auto" will use "hs" if available, otherwise "bm". - -spm-algo: auto - # Set the order of alerts bassed on actions # The default order is pass, drop, reject, alert # action-order: @@ -1010,66 +930,6 @@ pcre: match-limit: 3500 match-limit-recursion: 1500 -## -## Threading -## - -# Suricata is multi-threaded. Here the threading can be influenced. -threading: - # On some cpu's/architectures it is beneficial to tie individual threads - # to specific CPU's/CPU cores. In this case all threads are tied to CPU0, - # and each extra CPU/core has one "detect" thread. - # - # On Intel Core2 and Nehalem CPU's enabling this will degrade performance. - # - set-cpu-affinity: no - # Tune cpu affinity of suricata threads. Each family of threads can be bound - # on specific CPUs. - cpu-affinity: - - management-cpu-set: - cpu: [ 0 ] # include only these cpus in affinity settings - - receive-cpu-set: - cpu: [ 0 ] # include only these cpus in affinity settings - - decode-cpu-set: - cpu: [ 0, 1 ] - mode: "balanced" - - stream-cpu-set: - cpu: [ "0-1" ] - - detect-cpu-set: - cpu: [ "all" ] - mode: "exclusive" # run detect threads in these cpus - # Use explicitely 3 threads and don't compute number by using - # detect-thread-ratio variable: - # threads: 3 - prio: - low: [ 0 ] - medium: [ "1-2" ] - high: [ 3 ] - default: "medium" - - verdict-cpu-set: - cpu: [ 0 ] - prio: - default: "high" - - reject-cpu-set: - cpu: [ 0 ] - prio: - default: "low" - - output-cpu-set: - cpu: [ "all" ] - prio: - default: "medium" - # - # By default Suricata creates one "detect" thread per available CPU/CPU core. - # This setting allows controlling this behaviour. A ratio setting of 2 will - # create 2 detect threads for each CPU/CPU core. So for a dual core CPU this - # will result in 4 detect threads. If values below 1 are used, less threads - # are created. So on a dual core CPU a setting of 0.5 results in 1 detect - # thread being created. Regardless of the setting at a minimum 1 detect - # thread will always be created. - # - detect-thread-ratio: 1.5 - - ## ## Advanced Traffic Tracking and Reconstruction Settings ## @@ -1304,7 +1164,148 @@ host: # prealloc: 1000 # memcap: 16777216 +## +## Performance tuning and profiling +## + +# The detection engine builds internal groups of signatures. The engine +# allow us to specify the profile to use for them, to manage memory on an +# efficient way keeping a good performance. For the profile keyword you +# can use the words "low", "medium", "high" or "custom". If you use custom +# make sure to define the values at "- custom-values" as your convenience. +# Usually you would prefer medium/high/low. +# +# "sgh mpm-context", indicates how the staging should allot mpm contexts for +# the signature groups. "single" indicates the use of a single context for +# all the signature group heads. "full" indicates a mpm-context for each +# group head. "auto" lets the engine decide the distribution of contexts +# based on the information the engine gathers on the patterns from each +# group head. +# +# The option inspection-recursion-limit is used to limit the recursive calls +# in the content inspection code. For certain payload-sig combinations, we +# might end up taking too much time in the content inspection code. +# If the argument specified is 0, the engine uses an internally defined +# default limit. On not specifying a value, we use no limits on the recursion. +detect: + profile: medium + custom-values: + toclient-groups: 3 + toserver-groups: 25 + sgh-mpm-context: auto + inspection-recursion-limit: 3000 + # If set to yes, the loading of signatures will be made after the capture + # is started. This will limit the downtime in IPS mode. + #delayed-detect: yes + + # the grouping values above control how many groups are created per + # direction. Port whitelisting forces that port to get it's own group. + # Very common ports will benefit, as well as ports with many expensive + # rules. + grouping: + #tcp-whitelist: 53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080 + #udp-whitelist: 53, 135, 5060 + + profiling: + # Log the rules that made it past the prefilter stage, per packet + # default is off. The threshold setting determines how many rules + # must have made it past pre-filter for that rule to trigger the + # logging. + #inspect-logging-threshold: 200 + grouping: + dump-to-disk: false + include-rules: false # very verbose + include-mpm-stats: false +# Select the multi pattern algorithm you want to run for scan/search the +# in the engine. +# +# The supported algorithms are: +# "ac" - Aho-Corasick, default implementation +# "ac-bs" - Aho-Corasick, reduced memory implementation +# "ac-cuda" - Aho-Corasick, CUDA implementation +# "ac-tile" - Aho-Corasick, optimized for Tilera architecture +# "hs" - Hyperscan, available when built with Hyperscan support +# +# The default mpm-algo value of "auto" will use "hs" if Hyperscan is available, +# "ac-tile" on Tilera platforms, and "ac" otherwise. +# +# The mpm you choose also decides the distribution of mpm contexts for +# signature groups, specified by the conf - "detect.sgh-mpm-context". +# Selecting "ac" as the mpm would require "detect.sgh-mpm-context" +# to be set to "single", because of ac's memory requirements, unless the +# ruleset is small enough to fit in one's memory, in which case one can +# use "full" with "ac". Rest of the mpms can be run in "full" mode. +# +# There is also a CUDA pattern matcher (only available if Suricata was +# compiled with --enable-cuda: b2g_cuda. Make sure to update your +# max-pending-packets setting above as well if you use b2g_cuda. + +mpm-algo: auto + +# Select the matching algorithm you want to use for single-pattern searches. +# +# Supported algorithms are "bm" (Boyer-Moore) and "hs" (Hyperscan, only +# available if Suricata has been built with Hyperscan support). +# +# The default of "auto" will use "hs" if available, otherwise "bm". + +spm-algo: auto + +# Suricata is multi-threaded. Here the threading can be influenced. +threading: + # On some cpu's/architectures it is beneficial to tie individual threads + # to specific CPU's/CPU cores. In this case all threads are tied to CPU0, + # and each extra CPU/core has one "detect" thread. + # + # On Intel Core2 and Nehalem CPU's enabling this will degrade performance. + # + set-cpu-affinity: no + # Tune cpu affinity of suricata threads. Each family of threads can be bound + # on specific CPUs. + cpu-affinity: + - management-cpu-set: + cpu: [ 0 ] # include only these cpus in affinity settings + - receive-cpu-set: + cpu: [ 0 ] # include only these cpus in affinity settings + - decode-cpu-set: + cpu: [ 0, 1 ] + mode: "balanced" + - stream-cpu-set: + cpu: [ "0-1" ] + - detect-cpu-set: + cpu: [ "all" ] + mode: "exclusive" # run detect threads in these cpus + # Use explicitely 3 threads and don't compute number by using + # detect-thread-ratio variable: + # threads: 3 + prio: + low: [ 0 ] + medium: [ "1-2" ] + high: [ 3 ] + default: "medium" + - verdict-cpu-set: + cpu: [ 0 ] + prio: + default: "high" + - reject-cpu-set: + cpu: [ 0 ] + prio: + default: "low" + - output-cpu-set: + cpu: [ "all" ] + prio: + default: "medium" + # + # By default Suricata creates one "detect" thread per available CPU/CPU core. + # This setting allows controlling this behaviour. A ratio setting of 2 will + # create 2 detect threads for each CPU/CPU core. So for a dual core CPU this + # will result in 4 detect threads. If values below 1 are used, less threads + # are created. So on a dual core CPU a setting of 0.5 results in 1 detect + # thread being created. Regardless of the setting at a minimum 1 detect + # thread will always be created. + # + detect-thread-ratio: 1.5 # Profiling settings. Only effective if Suricata has been built with the # the --enable-profiling configure flag. From cb47c2f682e04611d526aea50704827be5d4111b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 21:30:25 +0200 Subject: [PATCH 1476/2553] yaml: improved defaults and misc cleanups --- suricata.yaml.in | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 52195f93b6b3..7aa7b47107e0 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -159,10 +159,10 @@ outputs: # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log # payload-printable: yes # enable dumping payload in printable (lossy) format # packet: yes # enable dumping of packet (without stream segments) - # http: yes # enable dumping of http fields - # tls: yes # enable dumping of tls fields - # ssh: yes # enable dumping of ssh fields - # smtp: yes # enable dumping of smtp fields + http: yes # enable dumping of http fields + tls: yes # enable dumping of tls fields + ssh: yes # enable dumping of ssh fields + smtp: yes # enable dumping of smtp fields # HTTP X-Forwarded-For support by adding an extra field or overwriting # the source or destination IP address (depending on flow direction) @@ -315,7 +315,7 @@ outputs: # - encrypted streams after the key exchange # - pcap-log: - enabled: no + enabled: no filename: log.pcap # File size limit. Can be specified in kb, mb, gb. Just a number @@ -432,7 +432,7 @@ outputs: scripts: # - script1.lua -# Logging configuration. This is not about logging IDS alerts, but +# Logging configuration. This is not about logging IDS alerts/events, but # output about what Suricata is doing, like startup messages, errors, etc. logging: # The default log level, can be overridden in an output section. @@ -481,7 +481,7 @@ af-packet: - interface: eth0 # Number of receive threads. "auto" uses the number of cores #threads: auto - # Default clusterid. AF_PACKET will load balance packets based on flow. + # Default clusterid. AF_PACKET will load balance packets based on flow. cluster-id: 99 # Default AF_PACKET cluster type. AF_PACKET can load balance per flow or per hash. # This is only supported for Linux kernel > 3.1 @@ -601,6 +601,9 @@ pcap-file: # Warning: 'checksum-validation' must be set to yes to have checksum tested checksum-checks: auto +# See "Advanced Capture Options" below for more options, including NETMAP +# and PF_RING. + ## ## Step 5: App Layer Protocol Configuration @@ -935,7 +938,7 @@ pcre: ## # Host specific policies for defragmentation and TCP stream -# reassembly. The host OS lookup is done using a radix tree, just +# reassembly. The host OS lookup is done using a radix tree, just # like a routing table so the most specific entry matches. host-os-policy: # Make the default policy windows. @@ -943,9 +946,9 @@ host-os-policy: bsd: [] bsd-right: [] old-linux: [] - linux: [10.0.0.0/8, 192.168.1.100, "8762:2352:6241:7245:E000:0000:0000:0000"] + linux: [] old-solaris: [] - solaris: ["::1"] + solaris: [] hpux10: [] hpux11: [] irix: [] @@ -998,7 +1001,7 @@ defrag: # in bytes. flow: - memcap: 64mb + memcap: 128mb hash-size: 65536 prealloc: 10000 emergency-recovery: 30 @@ -1039,11 +1042,11 @@ flow-timeouts: emergency-closed: 0 tcp: new: 60 - established: 3600 - closed: 120 - emergency-new: 10 - emergency-established: 300 - emergency-closed: 20 + established: 600 + closed: 60 + emergency-new: 5 + emergency-established: 100 + emergency-closed: 10 udp: new: 30 established: 300 @@ -1115,11 +1118,11 @@ flow-timeouts: # # on directly. # stream: - memcap: 32mb + memcap: 64mb checksum-validation: yes # reject wrong csums inline: auto # auto will use inline mode in IPS mode, yes or no set it statically reassembly: - memcap: 128mb + memcap: 256mb depth: 1mb # reassemble 1mb into a stream toserver-chunk-size: 2560 toclient-chunk-size: 2560 @@ -1153,7 +1156,7 @@ stream: host: hash-size: 4096 prealloc: 1000 - memcap: 16777216 + memcap: 32mb # IP Pair table: # @@ -1162,7 +1165,8 @@ host: #ippair: # hash-size: 4096 # prealloc: 1000 -# memcap: 16777216 +# memcap: 32mb + ## ## Performance tuning and profiling @@ -1610,6 +1614,9 @@ cuda: # For this option you need a device with Compute Capability > 1.0. cuda-streams: 2 +## +## Include other configs +## # Includes. Files included here will be handled as if they were # inlined in this configuration file. From 4d056912d3858fe919bc6e06f9c0ff01f8b8172b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 21:32:17 +0200 Subject: [PATCH 1477/2553] yaml: file logging at info level --- suricata.yaml.in | 1 + 1 file changed, 1 insertion(+) diff --git a/suricata.yaml.in b/suricata.yaml.in index 7aa7b47107e0..613d1ba6292b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -463,6 +463,7 @@ logging: # type: json - file: enabled: yes + level: info filename: @e_logdir@suricata.log # type: json - syslog: From 1b4e1ea389c3f96eb620d62227cb932edaf61dcf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 08:50:45 +0200 Subject: [PATCH 1478/2553] yaml: new defaults for outputs Enable eve.flow, disable plain http.log. --- suricata.yaml.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 613d1ba6292b..5ccb138dab68 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -213,7 +213,7 @@ outputs: threads: no # per thread stats deltas: no # include delta values # bi-directional flows - #- flow + - flow # uni-directional flows #- netflow @@ -256,7 +256,7 @@ outputs: # a line based log of HTTP requests (no alerts) - http-log: - enabled: yes + enabled: no filename: http.log append: yes #extended: yes # enable this for extended logging information From 766bc95e3cb16f1c776f9f099b882ddfbfe847fc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 08:51:15 +0200 Subject: [PATCH 1479/2553] yaml: move classification etc below the rules --- suricata.yaml.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 5ccb138dab68..bdd754135a70 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -47,10 +47,6 @@ vars: ## Step 2: select the rules to enable or disable ## -classification-file: @e_sysconfdir@classification.config -reference-config-file: @e_sysconfdir@reference.config -# threshold-file: @e_sysconfdir@threshold.config - default-rule-path: @e_sysconfdir@rules rule-files: - botcc.rules @@ -104,6 +100,10 @@ rule-files: # - modbus-events.rules # available in suricata sources under rules dir # - app-layer-events.rules # available in suricata sources under rules dir +classification-file: @e_sysconfdir@classification.config +reference-config-file: @e_sysconfdir@reference.config +# threshold-file: @e_sysconfdir@threshold.config + ## ## Step 3: select outputs to enable From df6f9269ec0b769e4b11649821e64f044f386726 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 08:51:57 +0200 Subject: [PATCH 1480/2553] yaml: improve capture comments --- suricata.yaml.in | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index bdd754135a70..b048a9ae8e56 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -474,10 +474,13 @@ logging: ## -## Step 4: configure capture settings +## Step 4: configure common capture settings +## +## See "Advanced Capture Options" below for more options, including NETMAP +## and PF_RING. ## -# af-packet support +# Linux high speed capture support af-packet: - interface: eth0 # Number of receive threads. "auto" uses the number of cores @@ -562,6 +565,7 @@ af-packet: #rollover: yes tpacket-v3: yes +# Cross platform libpcap capture support pcap: - interface: eth0 # On Linux, pcap will try to use mmaped capture and will use buffer-size @@ -593,6 +597,7 @@ pcap: - interface: default #checksum-checks: auto +# Settings for reading pcap files pcap-file: # Possible values are: # - yes: checksum validation is forced From f55dbca57beea9d2aa4dd423da458903ed186685 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 08:57:07 +0200 Subject: [PATCH 1481/2553] yaml: make eve log in yaml depend on libjansson --- configure.ac | 2 ++ suricata.yaml.in | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fc936abaec7d..71f402936a64 100644 --- a/configure.ac +++ b/configure.ac @@ -773,6 +773,7 @@ fi AS_IF([test "x$enable_unixsocket" = "xyes"], [AC_DEFINE([BUILD_UNIX_SOCKET], [1], [Unix socket support enabled])]) + e_enable_evelog=$enable_jansson AC_ARG_ENABLE(nflog, AS_HELP_STRING([--enable-nflog],[Enable libnetfilter_log support]), @@ -1944,6 +1945,7 @@ AC_SUBST(e_localstatedir) AC_DEFINE_UNQUOTED([CONFIG_DIR],["$e_sysconfdir"],[Our CONFIG_DIR]) AC_SUBST(e_magic_file) AC_SUBST(e_magic_file_comment) +AC_SUBST(e_enable_evelog) EXPAND_VARIABLE(prefix, CONFIGURE_PREFIX) EXPAND_VARIABLE(sysconfdir, CONFIGURE_SYSCONDIR) diff --git a/suricata.yaml.in b/suricata.yaml.in index b048a9ae8e56..f253c70da088 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -132,7 +132,7 @@ outputs: # Extensible Event Format (nicknamed EVE) event log in JSON format - eve-log: - enabled: yes + enabled: @e_enable_evelog@ filetype: regular #regular|syslog|unix_dgram|unix_stream|redis filename: eve.json #prefix: "@cee: " # prefix to prepend to each log entry From 9f7ba07153268fb72b99b219940859ba24bd770f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 13:44:16 +0200 Subject: [PATCH 1482/2553] af-packet: use better defaults if config is missing --- src/runmode-af-packet.c | 120 ++++++++++++++++++++-------------------- src/source-af-packet.c | 2 +- 2 files changed, 60 insertions(+), 62 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 5b48f7d56240..725fa8d4f6c4 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -115,7 +115,6 @@ void *ParseAFPConfig(const char *iface) ConfNode *if_root; ConfNode *if_default = NULL; ConfNode *af_packet_node; - AFPIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); char *tmpclusterid; char *tmpctype; char *copymodestr; @@ -124,29 +123,31 @@ void *ParseAFPConfig(const char *iface) char *bpf_filter = NULL; char *out_iface = NULL; - if (unlikely(aconf == NULL)) { + if (iface == NULL) { return NULL; } - if (iface == NULL) { - SCFree(aconf); + AFPIfaceConfig *aconf = SCCalloc(1, sizeof(*aconf)); + if (unlikely(aconf == NULL)) { return NULL; } strlcpy(aconf->iface, iface, sizeof(aconf->iface)); - aconf->threads = 1; + aconf->threads = 0; SC_ATOMIC_INIT(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, 1); aconf->buffer_size = 0; aconf->cluster_id = 1; - aconf->cluster_type = PACKET_FANOUT_HASH; + aconf->cluster_type = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; aconf->DerefFunc = AFPDerefConfig; - aconf->flags = 0; + aconf->flags = AFP_RING_MODE|AFP_TPACKET_V3; aconf->bpf_filter = NULL; aconf->out_iface = NULL; aconf->copy_mode = AFP_COPY_MODE_NONE; + aconf->block_timeout = 10; + aconf->block_size = getpagesize() << AFP_BLOCK_SIZE_DEFAULT_ORDER; if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { @@ -159,19 +160,18 @@ void *ParseAFPConfig(const char *iface) /* Find initial node */ af_packet_node = ConfGetNode("af-packet"); if (af_packet_node == NULL) { - SCLogInfo("Unable to find af-packet config using default value"); - return aconf; + SCLogInfo("unable to find af-packet config using default values"); + goto finalize; } if_root = ConfFindDeviceConfig(af_packet_node, iface); - if_default = ConfFindDeviceConfig(af_packet_node, "default"); if (if_root == NULL && if_default == NULL) { - SCLogInfo("Unable to find af-packet config for " - "interface \"%s\" or \"default\", using default value", + SCLogInfo("unable to find af-packet config for " + "interface \"%s\" or \"default\", using default values", iface); - return aconf; + goto finalize; } /* If there is no setting for current interface use default one as main iface */ @@ -191,24 +191,6 @@ void *ParseAFPConfig(const char *iface) } } } - if (aconf->threads == 0) { - int rss_queues; - aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); - /* Get the number of RSS queues and take the min */ - rss_queues = GetIfaceRSSQueuesNum(iface); - if (rss_queues > 0) { - if (rss_queues < aconf->threads) { - aconf->threads = rss_queues; - SCLogInfo("More cores than RSS queues, using %d threads for interface %s", - aconf->threads, iface); - } - } - if (aconf->threads) - SCLogInfo("Using %d AF_PACKET threads for interface %s", aconf->threads, iface); - } - if (aconf->threads <= 0) { - aconf->threads = 1; - } if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { if (strlen(out_iface) > 0) { @@ -222,6 +204,7 @@ void *ParseAFPConfig(const char *iface) } else { SCLogInfo("Disabling mmaped capture on iface %s", aconf->iface); + aconf->flags &= ~AFP_RING_MODE; } } else { aconf->flags |= AFP_RING_MODE; @@ -242,16 +225,16 @@ void *ParseAFPConfig(const char *iface) #ifdef HAVE_TPACKET_V3 SCLogInfo("Enabling tpacket v3 capture on iface %s", aconf->iface); - aconf->flags |= AFP_TPACKET_V3|AFP_RING_MODE; + aconf->flags |= AFP_TPACKET_V3; #else SCLogNotice("System too old for tpacket v3 switching to v2"); - aconf->flags |= AFP_RING_MODE; + aconf->flags &= ~AFP_TPACKET_V3; #endif } else { SCLogError(SC_ERR_RUNMODE, - "tpacket v3 is only implemented for 'workers' running mode." + "tpacket v3 is only implemented for 'workers' runmode." " Switching to tpacket v2."); - aconf->flags |= AFP_RING_MODE; + aconf->flags &= ~AFP_TPACKET_V3; } } (void)ConfGetChildValueBoolWithDefault(if_root, if_default, @@ -263,7 +246,6 @@ void *ParseAFPConfig(const char *iface) } } - aconf->copy_mode = AFP_COPY_MODE_NONE; if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { if (aconf->out_iface == NULL) { @@ -289,9 +271,6 @@ void *ParseAFPConfig(const char *iface) } } - SC_ATOMIC_RESET(aconf->ref); - (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); - if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) { aconf->cluster_id = (uint16_t)(cluster_id_auto++); } else { @@ -338,9 +317,7 @@ void *ParseAFPConfig(const char *iface) aconf->cluster_type = PACKET_FANOUT_ROLLOVER; } else { - SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); - SCFree(aconf); - return NULL; + SCLogWarning(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); } int conf_val = 0; @@ -369,21 +346,8 @@ void *ParseAFPConfig(const char *iface) } if ((ConfGetChildValueIntWithDefault(if_root, if_default, "ring-size", &value)) == 1) { aconf->ring_size = value; - if (value * aconf->threads < max_pending_packets) { - aconf->ring_size = max_pending_packets / aconf->threads + 1; - SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. " - "Resetting to decent value %d.", aconf->ring_size); - /* We want at least that max_pending_packets packets can be handled by the - * interface. This is generous if we have multiple interfaces listening. */ - } - } else { - /* We want that max_pending_packets packets can be handled by suricata - * for this interface. To take burst into account we multiply the obtained - * size by 2. */ - aconf->ring_size = max_pending_packets * 2 / aconf->threads; } - aconf->block_size = getpagesize() << AFP_BLOCK_SIZE_DEFAULT_ORDER; if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-size", &value)) == 1) { if (value % getpagesize()) { SCLogError(SC_ERR_INVALID_VALUE, "Block-size must be a multiple of pagesize."); @@ -392,11 +356,6 @@ void *ParseAFPConfig(const char *iface) } } - if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) { - aconf->block_timeout = value; - } else { - aconf->block_timeout = 10; - } if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) { aconf->block_timeout = value; } else { @@ -424,6 +383,43 @@ void *ParseAFPConfig(const char *iface) } } +finalize: + + if (aconf->threads == 0) { + int rss_queues; + aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); + /* Get the number of RSS queues and take the min */ + rss_queues = GetIfaceRSSQueuesNum(iface); + if (rss_queues > 0) { + if (rss_queues < aconf->threads) { + aconf->threads = rss_queues; + SCLogInfo("More cores than RSS queues, using %d threads for interface %s", + aconf->threads, iface); + } + } + if (aconf->threads) + SCLogInfo("Using %d AF_PACKET threads for interface %s", aconf->threads, iface); + } + if (aconf->threads <= 0) { + aconf->threads = 1; + } + SC_ATOMIC_RESET(aconf->ref); + (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); + + if (aconf->ring_size != 0) { + if (aconf->ring_size * aconf->threads < max_pending_packets) { + aconf->ring_size = max_pending_packets / aconf->threads + 1; + SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. " + "Resetting to decent value %d.", aconf->ring_size); + /* We want at least that max_pending_packets packets can be handled by the + * interface. This is generous if we have multiple interfaces listening. */ + } + } else { + /* We want that max_pending_packets packets can be handled by suricata + * for this interface. To take burst into account we multiply the obtained + * size by 2. */ + aconf->ring_size = max_pending_packets * 2 / aconf->threads; + } int ltype = AFPGetLinkType(iface); switch (ltype) { @@ -440,7 +436,6 @@ void *ParseAFPConfig(const char *iface) char *active_runmode = RunmodeGetActive(); if (active_runmode && !strcmp("workers", active_runmode)) { aconf->flags |= AFP_ZERO_COPY; - SCLogInfo("%s: enabling zero copy mode", iface); } else { /* If we are using copy mode we need a lock */ aconf->flags |= AFP_SOCK_PROTECT; @@ -450,6 +445,9 @@ void *ParseAFPConfig(const char *iface) * by using the data release mechanism */ if (aconf->flags & AFP_RING_MODE) { aconf->flags |= AFP_ZERO_COPY; + } + + if (aconf->flags & AFP_ZERO_COPY) { SCLogInfo("%s: enabling zero copy mode by using data release call", iface); } diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 29574f130832..8453c1d03431 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1246,7 +1246,7 @@ static int AFPSynchronizeStart(AFPThreadVars *ptv, uint64_t *discarded_pkts) SCLogDebug("Discarding on %s", ptv->tv->name); switch (r) { case 1: - SCLogInfo("Starting to read on %s", ptv->tv->name); + SCLogDebug("Starting to read on %s", ptv->tv->name); return 1; case -1: return r; From 291af719c60a198f6875a33bc993a8d8b63451f5 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 31 May 2016 11:21:31 +0200 Subject: [PATCH 1483/2553] coverity: fix CID 1362014 Error handling was not correct regarding ring buffer memory handling. --- src/source-af-packet.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 8453c1d03431..8b065f8c8514 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1766,7 +1766,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) ptv->ring_v3 = SCMalloc(ptv->req3.tp_block_nr * sizeof(*ptv->ring_v3)); if (!ptv->ring_v3) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to malloc ptv ring_v3"); - goto mmap_err; + goto postmmap_err; } for (i = 0; i < ptv->req3.tp_block_nr; ++i) { ptv->ring_v3[i].iov_base = ring_buf + (i * ptv->req3.tp_block_size); @@ -1778,7 +1778,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) ptv->ring_v2 = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); if (ptv->ring_v2 == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); - goto mmap_err; + goto postmmap_err; } memset(ptv->ring_v2, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); /* fill the header ring with proper frame ptr*/ @@ -1798,6 +1798,12 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) return 0; +postmmap_err: + munmap(ring_buf, ring_buflen); + if (ptv->ring_v2) + SCFree(ptv->ring_v2); + if (ptv->ring_v3) + SCFree(ptv->ring_v3); mmap_err: /* Packet mmap does the cleaning when socket is closed */ return AFP_FATAL_ERROR; From c9159892c72f5b4782862c3bfcc5deacccbbd0c6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 14:17:35 +0200 Subject: [PATCH 1484/2553] profiling: allow packet profiling to be reset --- src/util-profiling.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/util-profiling.h b/src/util-profiling.h index c97f1b5c093c..54521a422098 100644 --- a/src/util-profiling.h +++ b/src/util-profiling.h @@ -96,6 +96,12 @@ PktProfiling *SCProfilePacketStart(void); (p)->profile->ticks_start = UtilCpuGetTicks(); \ } +#define PACKET_PROFILING_RESTART(p) \ + if (profiling_packets_enabled) { \ + if ((p)->profile != NULL) \ + (p)->profile->ticks_start = UtilCpuGetTicks(); \ + } + #define PACKET_PROFILING_END(p) \ if (profiling_packets_enabled && (p)->profile != NULL) { \ (p)->profile->ticks_end = UtilCpuGetTicks(); \ @@ -286,6 +292,7 @@ void SCProfilingDump(void); #define KEYWORD_PROFILING_END(a,b,c) #define PACKET_PROFILING_START(p) +#define PACKET_PROFILING_RESTART(p) #define PACKET_PROFILING_END(p) #define PACKET_PROFILING_TMM_START(p, id) From 6f7740807dd6719c9b17403dd64db463a3bee26a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 14:18:04 +0200 Subject: [PATCH 1485/2553] pfring: improve profiling Reset packet profiling after pfring_recv. The packet was taken from the packet pool before this call. The packet will already have it's start ticks initialized. To avoid including ticks while pfring_recv waits for traffic, reset the ticks right after it. --- src/source-pfring.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/source-pfring.c b/src/source-pfring.c index 655031fb71f8..5cee51344ade 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -48,6 +48,7 @@ #include "util-device.h" #include "util-host-info.h" #include "runmodes.h" +#include "util-profiling.h" #ifdef __SC_CUDA_SUPPORT__ @@ -355,6 +356,10 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) } if (likely(r == 1)) { + /* profiling started before blocking pfring_recv call, so + * reset it here */ + PACKET_PROFILING_RESTART(p); + //printf("RecievePfring src %" PRIu32 " sport %" PRIu32 " dst %" PRIu32 " dstport %" PRIu32 "\n", // hdr.parsed_pkt.ipv4_src,hdr.parsed_pkt.l4_src_port, hdr.parsed_pkt.ipv4_dst,hdr.parsed_pkt.l4_dst_port); From 661d7c1d092df6fef31185ddfefe2d0f71080259 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 14:22:00 +0200 Subject: [PATCH 1486/2553] pfring: cleanup --- src/source-pfring.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index 5cee51344ade..4ce3c81e3446 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -344,22 +344,20 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) pkt_buffer = GET_PKT_DIRECT_DATA(p); } - /* Depending on what compile time options are used for pfring we either return 0 or -1 on error and always 1 for success */ int r = pfring_recv(ptv->pd, &pkt_buffer, buffer_size, &hdr, LIBPFRING_WAIT_FOR_INCOMING); - - /* Check for Zero-copy mode */ - if (ptv->flags & PFRING_FLAGS_ZERO_COPY) { - PacketSetData(p, pkt_buffer, hdr.caplen); - } - if (likely(r == 1)) { /* profiling started before blocking pfring_recv call, so * reset it here */ PACKET_PROFILING_RESTART(p); + /* Check for Zero-copy mode */ + if (ptv->flags & PFRING_FLAGS_ZERO_COPY) { + PacketSetData(p, pkt_buffer, hdr.caplen); + } + //printf("RecievePfring src %" PRIu32 " sport %" PRIu32 " dst %" PRIu32 " dstport %" PRIu32 "\n", // hdr.parsed_pkt.ipv4_src,hdr.parsed_pkt.l4_src_port, hdr.parsed_pkt.ipv4_dst,hdr.parsed_pkt.l4_dst_port); From 4b9a62d1fe571cf9a3b63382e5751b2e97f17b4c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 14:41:31 +0200 Subject: [PATCH 1487/2553] profiling: fix compilation if libjansson is missing --- src/detect-engine-profile.c | 2 ++ src/detect.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/detect-engine-profile.c b/src/detect-engine-profile.c index f5127657236d..c60241792984 100644 --- a/src/detect-engine-profile.c +++ b/src/detect-engine-profile.c @@ -32,6 +32,7 @@ #include "util-print.h" #ifdef PROFILING +#ifdef HAVE_LIBJANSSON static void DumpFp(const SigMatch *sm, char *pat_orig, uint32_t pat_orig_sz, char *pat_chop, uint32_t pat_chop_sz) { int fast_pattern_chop_set = 0; @@ -133,4 +134,5 @@ void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, const Packet *p) json_object_clear(js); json_decref(js); } +#endif /* HAVE_LIBJANSSON */ #endif /* PROFILING */ diff --git a/src/detect.c b/src/detect.c index 9fb005fcf181..f6296044e83d 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1516,8 +1516,10 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SGH_PROFILING_RECORD(det_ctx, det_ctx->sgh); #ifdef PROFILING +#ifdef HAVE_LIBJANSSON if (match_cnt >= de_ctx->profile_match_logging_threshold) RulesDumpMatchArray(det_ctx, p); +#endif #endif uint32_t sflags, next_sflags = 0; From 36535cbc6107f4b1393df8b6a06c71702028c7a6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 16:21:50 +0200 Subject: [PATCH 1488/2553] yaml: remove conf_filename global conf_filename was a global pointer to the filename of the yaml. Move into SCInstance. This reduces it's scope and cleans up the code. --- src/detect-engine.c | 12 +++++++----- src/detect-engine.h | 2 +- src/suricata.c | 30 +++++++++++++++--------------- src/suricata.h | 3 +-- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 3d6f51350516..24385e0e9fcd 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2534,7 +2534,7 @@ static int reloads = 0; * \retval -1 error * \retval 0 ok */ -int DetectEngineReload(const char *filename, SCInstance *suri) +int DetectEngineReload(SCInstance *suri) { DetectEngineCtx *new_de_ctx = NULL; DetectEngineCtx *old_de_ctx = NULL; @@ -2542,16 +2542,18 @@ int DetectEngineReload(const char *filename, SCInstance *suri) char prefix[128]; memset(prefix, 0, sizeof(prefix)); - if (filename != NULL) { + if (suri->conf_filename != NULL) { snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++); - if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename); + if (ConfYamlLoadFileWithPrefix(suri->conf_filename, prefix) != 0) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", + suri->conf_filename); return -1; } ConfNode *node = ConfGetNode(prefix); if (node == NULL) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename); + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", + suri->conf_filename); return -1; } #if 0 diff --git a/src/detect-engine.h b/src/detect-engine.h index 70b18133fcb3..64c241e16612 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -75,7 +75,7 @@ void DetectEnginePruneFreeList(void); int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx); DetectEngineCtx *DetectEngineReference(DetectEngineCtx *); void DetectEngineDeReference(DetectEngineCtx **de_ctx); -int DetectEngineReload(const char *filename, SCInstance *suri); +int DetectEngineReload(SCInstance *suri); int DetectEngineEnabled(void); int DetectEngineMTApply(void); int DetectEngineMultiTenantEnabled(void); diff --git a/src/suricata.c b/src/suricata.c index f3b6d4f9858f..cad97fcfe008 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -248,8 +248,6 @@ int g_detect_disabled = 0; /** set caps or not */ int sc_set_caps; -char *conf_filename = NULL; - int EngineModeIsIPS(void) { return (g_engine_mode == ENGINE_MODE_IPS); @@ -927,14 +925,14 @@ void RegisterAllModules() } -static TmEcode LoadYamlConfig(void) +static TmEcode LoadYamlConfig(SCInstance *suri) { SCEnter(); - if (conf_filename == NULL) - conf_filename = DEFAULT_CONF_FILE; + if (suri->conf_filename == NULL) + suri->conf_filename = DEFAULT_CONF_FILE; - if (ConfYamlLoadFile(conf_filename) != 0) { + if (ConfYamlLoadFile(suri->conf_filename) != 0) { /* Error already displayed. */ SCReturnInt(TM_ECODE_FAILED); } @@ -1684,7 +1682,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) } break; case 'c': - conf_filename = optarg; + suri->conf_filename = optarg; break; case 'T': SCLogInfo("Running suricata under test mode"); @@ -2168,7 +2166,7 @@ static int ConfigGetCaptureValue(SCInstance *suri) if (max_pending_packets >= 65535) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Maximum max-pending-packets setting is 65534. " - "Please check %s for errors", conf_filename); + "Please check %s for errors", suri->conf_filename); return TM_ECODE_FAILED; } @@ -2244,7 +2242,7 @@ static int PostConfLoadedSetup(SCInstance *suri) if (ConfigCheckLogDirectory(suri->log_dir) != TM_ECODE_OK) { SCLogError(SC_ERR_LOGDIR_CONFIG, "The logging directory \"%s\" " "supplied by %s (default-log-dir) doesn't exist. " - "Shutting down the engine", suri->log_dir, conf_filename); + "Shutting down the engine", suri->log_dir, suri->conf_filename); SCReturnInt(TM_ECODE_FAILED); } @@ -2326,12 +2324,14 @@ static int PostConfLoadedSetup(SCInstance *suri) if (DetectAddressTestConfVars() < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, - "basic address vars test failed. Please check %s for errors", conf_filename); + "basic address vars test failed. Please check %s for errors", + suri->conf_filename); SCReturnInt(TM_ECODE_FAILED); } if (DetectPortTestConfVars() < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, - "basic port vars test failed. Please check %s for errors", conf_filename); + "basic port vars test failed. Please check %s for errors", + suri->conf_filename); SCReturnInt(TM_ECODE_FAILED); } @@ -2446,7 +2446,7 @@ int main(int argc, char **argv) } /* Load yaml configuration file if provided. */ - if (LoadYamlConfig() != TM_ECODE_OK) { + if (LoadYamlConfig(&suri) != TM_ECODE_OK) { exit(EXIT_FAILURE); } @@ -2586,7 +2586,7 @@ int main(int argc, char **argv) if (suri.delayed_detect) { /* force 'reload', this will load the rules and swap engines */ - DetectEngineReload(NULL, &suri); + DetectEngineReload(&suri); SCLogNotice("Signature(s) loaded, Detect thread(s) activated."); } @@ -2626,7 +2626,7 @@ int main(int argc, char **argv) } else { if (!(DetectEngineReloadIsStart())) { DetectEngineReloadStart(); - DetectEngineReload(conf_filename, &suri); + DetectEngineReload(&suri); DetectEngineReloadSetDone(); sigusr2_count--; } @@ -2638,7 +2638,7 @@ int main(int argc, char **argv) "possible if -s or -S option used at runtime."); DetectEngineReloadSetDone(); } else { - DetectEngineReload(conf_filename, &suri); + DetectEngineReload(&suri); DetectEngineReloadSetDone(); } } diff --git a/src/suricata.h b/src/suricata.h index b361b3932993..1edd129d81e8 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -156,6 +156,7 @@ typedef struct SCInstance_ { char *log_dir; const char *progname; /**< pointer to argv[0] */ + const char *conf_filename; } SCInstance; @@ -167,8 +168,6 @@ extern volatile uint8_t suricata_ctl_flags; /* uppercase to lowercase conversion lookup table */ uint8_t g_u8_lowercasetable[256]; -extern char *conf_filename; - /* marco to do the actual lookup */ //#define u8_tolower(c) g_u8_lowercasetable[(c)] // these 2 are slower: From be9cd0fd843f1e412bceb3a86b0ad4e5cb7b0782 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 17:52:43 +0200 Subject: [PATCH 1489/2553] yaml: replace ac-tile by ac-ks --- suricata.yaml.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index f253c70da088..582592cb00ce 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1234,11 +1234,11 @@ detect: # "ac" - Aho-Corasick, default implementation # "ac-bs" - Aho-Corasick, reduced memory implementation # "ac-cuda" - Aho-Corasick, CUDA implementation -# "ac-tile" - Aho-Corasick, optimized for Tilera architecture +# "ac-ks" - Aho-Corasick, "Ken Steele" variant # "hs" - Hyperscan, available when built with Hyperscan support # -# The default mpm-algo value of "auto" will use "hs" if Hyperscan is available, -# "ac-tile" on Tilera platforms, and "ac" otherwise. +# The default mpm-algo value of "auto" will use "hs" if Hyperscan is +# available, "ac" otherwise. # # The mpm you choose also decides the distribution of mpm contexts for # signature groups, specified by the conf - "detect.sgh-mpm-context". From 72d3ea65525725a9f57c9d8a425a812eb24e9f5f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 17:55:27 +0200 Subject: [PATCH 1490/2553] detect: make pattern matcher messages less verbose --- src/detect-engine.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 24385e0e9fcd..cf917ad346a2 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -839,9 +839,10 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) } de_ctx->mpm_matcher = PatternMatchDefaultMatcher(); - SCLogInfo("using MPM matcher: %s", mpm_table[de_ctx->mpm_matcher].name); de_ctx->spm_matcher = SinglePatternMatchDefaultMatcher(); - SCLogInfo("using SPM matcher: %s", spm_table[de_ctx->spm_matcher].name); + SCLogInfo("pattern matchers: MPM: %s, SPM: %s", + mpm_table[de_ctx->mpm_matcher].name, + spm_table[de_ctx->spm_matcher].name); de_ctx->spm_global_thread_ctx = SpmInitGlobalThreadCtx(de_ctx->spm_matcher); if (de_ctx->spm_global_thread_ctx == NULL) { From 181f67ff97338c78a8bb19821d36859b60df8ff3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 18:01:02 +0200 Subject: [PATCH 1491/2553] flow-worker: small cleanups --- src/flow-worker.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/flow-worker.c b/src/flow-worker.c index 4f96ac1f63e6..154b3948f3a4 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -70,7 +70,7 @@ typedef struct FlowWorkerThreadData_ { * * Handle flow creation/lookup */ -static void FlowUpdate(ThreadVars *tv, StreamTcpThread *stt, Packet *p) +static inline void FlowUpdate(Packet *p) { FlowHandlePacketUpdate(p->flow, p); } @@ -148,8 +148,9 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac SCLogDebug("packet %"PRIu64, p->pcap_cnt); /* update time */ - if (!(PKT_IS_PSEUDOPKT(p))) + if (!(PKT_IS_PSEUDOPKT(p))) { TimeSetByThread(tv->id, &p->ts); + } /* handle Flow */ if (p->flags & PKT_WANTS_FLOW) { @@ -158,7 +159,7 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac FlowHandlePacket(tv, fw->dtv, p); if (likely(p->flow != NULL)) { DEBUG_ASSERT_FLOW_LOCKED(p->flow); - FlowUpdate(tv, fw->stream_thread, p); + FlowUpdate(p); } /* Flow is now LOCKED */ From 371113e21e808b74cfbb0878ed14e08a3b926d5c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 31 May 2016 16:58:29 +0200 Subject: [PATCH 1492/2553] ac-ks: don't allow use on big-endian --- src/detect-engine-mpm.c | 7 +++++++ src/util-mpm-ac-tile.c | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index fe469b4a08a2..dafa2b3a8bcd 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -335,6 +335,13 @@ uint16_t PatternMatchDefaultMatcher(void) uint16_t u; if (mpm_algo != NULL) { +#if __BYTE_ORDER == __BIG_ENDIAN + if (strcmp(mpm_algo, "ac-ks") == 0) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "ac-ks does " + "not work on big endian systems at this time."); + exit(EXIT_FAILURE); + } +#endif if (strcmp("auto", mpm_algo) == 0) { goto done; } diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 425d22376664..62fda87e106c 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -68,6 +68,8 @@ #include "suricata-common.h" #include "suricata.h" +#if __BYTE_ORDER == __LITTLE_ENDIAN + #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" @@ -2569,3 +2571,11 @@ void SCACTileRegisterTests(void) #endif } +#else /* we're big endian */ + +void MpmACTileRegister(void) +{ + /* no-op on big endian */ +} + +#endif /* little endian check */ From ed561c73a5a8d41f70be4af61adbd6de90a19b91 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 31 May 2016 23:18:06 +0200 Subject: [PATCH 1493/2553] suricata: fix double packet processing threads With the additional ParseInterfacesList the packet processing threads were doubled since the Interface was included twice unless the device was passed via the commandline with af-packet=IF. The additonal ParseInterfacesList isn't necessary so remove it again --- src/suricata.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index cad97fcfe008..f486300c907c 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2533,10 +2533,6 @@ int main(int argc, char **argv) StatsSetupPostConfig(); } - if (ParseInterfacesList(suri.run_mode, suri.pcap_dev) != TM_ECODE_OK) { - exit(EXIT_FAILURE); - } - if (suri.run_mode == RUNMODE_CONF_TEST){ SCLogNotice("Configuration provided was successfully loaded. Exiting."); MagicDeinit(); From 4defc5acc21e92b53d6993e6133871e3636a9193 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 31 May 2016 15:55:31 +0200 Subject: [PATCH 1494/2553] util-ioctcl: increase header size Headers can contain VLAN or Qing so we need to increase the value returned by GetIfaceMaxHWHeaderLength. --- src/util-ioctl.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index e0b5ef824b2d..93718460361c 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -61,13 +61,16 @@ int GetIfaceMaxHWHeaderLength(const char *pcap_dev) || (!strcmp("tap", pcap_dev)) || - (!strcmp("lo", pcap_dev))) - return ETHERNET_HEADER_LEN; + (!strcmp("lo", pcap_dev))) { + /* Add possible VLAN tag or Qing headers */ + return 8 + ETHERNET_HEADER_LEN; + } if (!strcmp("ppp", pcap_dev)) return SLL_HEADER_LEN; - /* SLL_HEADER_LEN is the biggest one */ - return SLL_HEADER_LEN; + /* SLL_HEADER_LEN is the biggest one and + add possible VLAN tag and Qing headers */ + return 8 + SLL_HEADER_LEN; } /** From 2412681eff5cde57e80f4d756430dc951f104869 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 1 Jun 2016 20:08:20 +0200 Subject: [PATCH 1495/2553] instance: memset to 0 before use --- src/suricata.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index f486300c907c..8b3abd84a701 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1035,6 +1035,8 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) static void SCInstanceInit(SCInstance *suri) { + memset(suri, 0x00, sizeof(*suri)); + suri->run_mode = RUNMODE_UNKNOWN; memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); From d39e5754e646111bc6d23a736e9e8dbaf87c7201 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 1 Jun 2016 20:08:47 +0200 Subject: [PATCH 1496/2553] instance: use enum for runmode --- src/runmodes.h | 2 +- src/suricata.c | 2 ++ src/suricata.h | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/runmodes.h b/src/runmodes.h index d935b9a3fef0..0f1884e990ad 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -24,7 +24,7 @@ #define __RUNMODES_H__ /* Run mode */ -enum { +enum RunModes { RUNMODE_UNKNOWN = 0, RUNMODE_PCAP_DEV, RUNMODE_PCAP_FILE, diff --git a/src/suricata.c b/src/suricata.c index 8b3abd84a701..e53d6ea0a081 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2110,6 +2110,8 @@ static int FinalizeRunMode(SCInstance *suri, char **argv) case RUNMODE_UNKNOWN: usage(argv[0]); return TM_ECODE_FAILED; + default: + break; } /* Set the global run mode */ run_mode = suri->run_mode; diff --git a/src/suricata.h b/src/suricata.h index 1edd129d81e8..337305361d84 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -119,6 +119,8 @@ enum { #define IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode) ((host_mode) == SURI_HOST_IS_SNIFFER_ONLY) #define IS_SURI_HOST_MODE_ROUTER(host_mode) ((host_mode) == SURI_HOST_IS_ROUTER) +#include "runmodes.h" + /* queue's between various other threads * XXX move to the TmQueue structure later */ @@ -127,7 +129,7 @@ PacketQueue trans_q[256]; SCDQDataQueue data_queues[256]; typedef struct SCInstance_ { - int run_mode; + enum RunModes run_mode; char pcap_dev[128]; char *sig_file; From f4465774126add54f42746a86fbdbe1b55e70847 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 2 Jun 2016 06:41:50 +0200 Subject: [PATCH 1497/2553] netmap: implement 'threads: auto' Add until function for retrieving RSS RX count from netmap. Use the RSS count to create the threads. --- src/runmode-netmap.c | 2 +- src/source-netmap.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/source-netmap.h | 2 ++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 5d76e417d2f7..f154e7cf1578 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -180,7 +180,7 @@ static void *ParseNetmapConfig(const char *iface_name) aconf->threads = 1; } else { if (strcmp(threadsstr, "auto") == 0) { - aconf->threads = GetIfaceRSSQueuesNum(aconf->iface); + aconf->threads = NetmapGetRSSCount(aconf->iface); } else { aconf->threads = (uint8_t)atoi(threadsstr); } diff --git a/src/source-netmap.c b/src/source-netmap.c index fdb4c707e7f9..fff2b26e27d5 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -277,6 +277,46 @@ static int NetmapSetIfaceFlags(int fd, const char *ifname, int flags) return 0; } +/** \brief get RSS RX-queue count + * \retval rx_rings RSS RX queue count or 1 on error + */ +int NetmapGetRSSCount(const char *ifname) +{ + struct nmreq nm_req; + int rx_rings = 1; + + SCMutexLock(&netmap_devlist_lock); + + /* open netmap */ + int fd = open("/dev/netmap", O_RDWR); + if (fd == -1) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't open netmap device, error %s", + strerror(errno)); + goto error_open; + } + + /* query netmap info */ + memset(&nm_req, 0, sizeof(nm_req)); + strlcpy(nm_req.nr_name, ifname, sizeof(nm_req.nr_name)); + nm_req.nr_version = NETMAP_API; + + if (ioctl(fd, NIOCGINFO, &nm_req) != 0) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't query netmap for %s, error %s", + ifname, strerror(errno)); + goto error_fd; + }; + + rx_rings = nm_req.nr_rx_rings; + +error_fd: + close(fd); +error_open: + SCMutexUnlock(&netmap_devlist_lock); + return rx_rings; +} + /** * \brief Open interface in netmap mode. * \param ifname Interface name. diff --git a/src/source-netmap.h b/src/source-netmap.h index c52b50507929..c6f7b6c23ff6 100644 --- a/src/source-netmap.h +++ b/src/source-netmap.h @@ -67,6 +67,8 @@ typedef struct NetmapPacketVars_ void *ntv; } NetmapPacketVars; +int NetmapGetRSSCount(const char *ifname); + void TmModuleReceiveNetmapRegister (void); void TmModuleDecodeNetmapRegister (void); From d58d02fed5e674011cca50d3e3ab203d9b93e335 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 2 Jun 2016 06:53:32 +0200 Subject: [PATCH 1498/2553] netmap: handle missing config with better defaults Default to 'threads: auto' which uses RSS RX count when no config has been created for a interface. --- src/runmode-netmap.c | 34 ++++++++++++++++++---------------- suricata.yaml.in | 2 +- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index f154e7cf1578..ccc25719c6cf 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -127,7 +127,7 @@ static void *ParseNetmapConfig(const char *iface_name) memset(aconf, 0, sizeof(*aconf)); aconf->DerefFunc = NetmapDerefConfig; - aconf->threads = 1; + aconf->threads = 0; aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; aconf->copy_mode = NETMAP_COPY_MODE_NONE; @@ -156,7 +156,7 @@ static void *ParseNetmapConfig(const char *iface_name) netmap_node = ConfGetNode("netmap"); if (netmap_node == NULL) { SCLogInfo("Unable to find netmap config using default value"); - return aconf; + goto finalize; } if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name); @@ -167,7 +167,7 @@ static void *ParseNetmapConfig(const char *iface_name) SCLogInfo("Unable to find netmap config for " "interface \"%s\" or \"default\", using default value", aconf->iface_name); - return aconf; + goto finalize; } /* If there is no setting for current interface use default one as main iface */ @@ -177,23 +177,15 @@ static void *ParseNetmapConfig(const char *iface_name) } if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { - aconf->threads = 1; + aconf->threads = 0; } else { if (strcmp(threadsstr, "auto") == 0) { - aconf->threads = NetmapGetRSSCount(aconf->iface); + aconf->threads = 0; } else { aconf->threads = (uint8_t)atoi(threadsstr); } } - if (aconf->threads <= 0) { - aconf->threads = 1; - } - if (aconf->threads) { - SCLogInfo("Using %d threads for interface %s", aconf->threads, - aconf->iface_name); - } - if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { if (strlen(out_iface) > 0) { aconf->out_iface_name = out_iface; @@ -231,9 +223,6 @@ static void *ParseNetmapConfig(const char *iface_name) } } - SC_ATOMIC_RESET(aconf->ref); - (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); - /* load netmap bpf filter */ /* command line value has precedence */ if (ConfGet("bpf-filter", &bpf_filter) != 1) { @@ -263,6 +252,19 @@ static void *ParseNetmapConfig(const char *iface_name) } } +finalize: + + if (aconf->threads == 0) { + aconf->threads = NetmapGetRSSCount(aconf->iface); + } + if (aconf->threads <= 0) { + aconf->threads = 1; + } + SC_ATOMIC_RESET(aconf->ref); + (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); + SCLogInfo("Using %d threads for interface %s", aconf->threads, + aconf->iface_name); + return aconf; } diff --git a/suricata.yaml.in b/suricata.yaml.in index 582592cb00ce..f830a1242176 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1445,7 +1445,7 @@ netmap: # To specify OS endpoint add plus sign at the end (e.g. "eth0+") - interface: eth2 # Number of receive threads. "auto" uses number of RSS queues on interface. - threads: auto + #threads: auto # You can use the following variables to activate netmap tap or IPS mode. # If copy-mode is set to ips or tap, the traffic coming to the current # interface will be copied to the copy-iface interface. If 'tap' is set, the From d861bf100bf8bd249f40c90d13781762ca214b91 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 2 Jun 2016 08:09:12 +0200 Subject: [PATCH 1499/2553] netmap: reduce verbosity at startup --- src/runmode-netmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index ccc25719c6cf..dc3833abe6c7 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -381,7 +381,7 @@ int RunModeIdsNetmapAutoFp(void) exit(EXIT_FAILURE); } - SCLogInfo("RunModeIdsNetmapAutoFp initialised"); + SCLogDebug("RunModeIdsNetmapAutoFp initialised"); #endif /* HAVE_NETMAP */ SCReturnInt(0); @@ -414,7 +414,7 @@ int RunModeIdsNetmapSingle(void) exit(EXIT_FAILURE); } - SCLogInfo("RunModeIdsNetmapSingle initialised"); + SCLogDebug("RunModeIdsNetmapSingle initialised"); #endif /* HAVE_NETMAP */ SCReturnInt(0); @@ -450,7 +450,7 @@ int RunModeIdsNetmapWorkers(void) exit(EXIT_FAILURE); } - SCLogInfo("RunModeIdsNetmapWorkers initialised"); + SCLogDebug("RunModeIdsNetmapWorkers initialised"); #endif /* HAVE_NETMAP */ SCReturnInt(0); From a8a918545bddf8bbdb449b99cedc73629bdb8294 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 2 Jun 2016 11:01:29 +0200 Subject: [PATCH 1500/2553] netmap: get correct RSS queues on Linux as well --- src/runmode-netmap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index dc3833abe6c7..fcd2a0bd7025 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -255,7 +255,12 @@ static void *ParseNetmapConfig(const char *iface_name) finalize: if (aconf->threads == 0) { - aconf->threads = NetmapGetRSSCount(aconf->iface); + /* As NetmapGetRSSCount is broken on Linux, first run + * GetIfaceRSSQueuesNum. If that fails, run NetmapGetRSSCount */ + aconf->threads = GetIfaceRSSQueuesNum(aconf->iface); + if (aconf->threads == 0) { + aconf->threads = NetmapGetRSSCount(aconf->iface); + } } if (aconf->threads <= 0) { aconf->threads = 1; From 4369161b9265ab3586a4cf762d46a1d7ecab9b6c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 2 Jun 2016 10:49:35 +0200 Subject: [PATCH 1501/2553] netmap: get offloading settings and warn if needed Add FreeBSD lookup function and use the existing code on Linux. --- src/source-netmap.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/source-netmap.c b/src/source-netmap.c index fff2b26e27d5..096e7594bbc1 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -247,6 +247,55 @@ static int NetmapGetIfaceFlags(int fd, const char *ifname) #endif } +#ifdef SIOCGIFCAP +static int NetmapGetIfaceCaps(int fd, const char *ifname) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Unable to get caps for iface \"%s\": %s", + ifname, strerror(errno)); + return -1; + } + + return ifr.ifr_curcap; +} +#endif + +static void NetmapCheckOffloading(int fd, const char *ifname) +{ +#ifdef SIOCGIFCAP + int if_caps = NetmapGetIfaceCaps(fd, ifname); + if (if_caps == -1) { + return; + } + SCLogDebug("if_caps %X", if_caps); + + if (if_caps & IFCAP_RXCSUM) { + SCLogWarning(SC_ERR_NETMAP_CREATE, + "Using NETMAP with RXCSUM activated can lead to capture " + "problems: ifconfig %s -rxcsum", ifname); + } + if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { + SCLogWarning(SC_ERR_NETMAP_CREATE, + "Using NETMAP with TSO, TOE or LRO activated can lead to " + "capture problems: ifconfig %s -tso -toe -lro", ifname); + } +#else + if (GetIfaceOffloading(ifname) == 1) { + SCLogWarning(SC_ERR_NETMAP_CREATE, + "Using NETMAP with GRO or LRO activated can lead to " + "capture problems: " + "ethtool -K %s rx off sg off gro off gso off tso off", + ifname); + } +#endif +} + /** * \brief Set interface flags. * \param fd Network susbystem file descritor. @@ -393,6 +442,8 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver if_flags |= IFF_PROMISC; NetmapSetIfaceFlags(if_fd, ifname, if_flags); } + + NetmapCheckOffloading(if_fd, ifname); close(if_fd); /* query netmap info */ From e11753e3f2e3a1260dda0eb9d538509d383e2d47 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 2 Jun 2016 08:06:07 +0200 Subject: [PATCH 1502/2553] profiling: fix minor compiler warning --- src/util-profiling-rulegroups.c | 2 ++ src/util-profiling-rules.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/util-profiling-rulegroups.c b/src/util-profiling-rulegroups.c index e4112ccc13b2..53b3624ce7b7 100644 --- a/src/util-profiling-rulegroups.c +++ b/src/util-profiling-rulegroups.c @@ -66,7 +66,9 @@ static int profiling_sghs_output_to_file = 0; int profiling_sghs_enabled = 0; static char *profiling_file_name = ""; static const char *profiling_file_mode = "a"; +#ifdef HAVE_LIBJANSSON static int profiling_rulegroup_json = 0; +#endif void SCProfilingSghsGlobalInit(void) { diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index 870f7b9705fe..520b1c0614c2 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -81,7 +81,9 @@ extern int profiling_output_to_file; int profiling_rules_enabled = 0; static char *profiling_file_name = ""; static const char *profiling_file_mode = "a"; +#ifdef HAVE_LIBJANSSON static int profiling_rule_json = 0; +#endif /** * Sort orders for dumping profiled rules. From 1c0f20f0e568ab0864f5b8184ab92e0c949cf27d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 2 Jun 2016 10:06:38 +0200 Subject: [PATCH 1503/2553] yaml: profiling 'json' depend on jansson availability --- suricata.yaml.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index f830a1242176..15bd7eeb0165 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1342,7 +1342,7 @@ profiling: limit: 100 # output to json - json: true + json: @e_enable_evelog@ # per keyword profiling keywords: From cc2ed783c5ccb1b84f6f99d46661fb4ac0f177e3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 11 Jul 2015 23:22:37 +0200 Subject: [PATCH 1504/2553] output: improve notice and warning/error color handling --- src/util-debug.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/util-debug.c b/src/util-debug.c index a55a559906b8..d8e607a2f46c 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -475,8 +475,12 @@ static SCError SCLogMessageGetBuffer( } } - char *xyellow = error_code > SC_OK ? yellow : ""; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", xyellow, message, reset); + char *hi = ""; + if (error_code > SC_OK) + hi = red; + else if (log_level <= SC_LOG_NOTICE) + hi = yellow; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", hi, message, reset); if (cw < 0) goto error; temp += cw; From b3bf7a57297a24be569f7d7bcff140ffbb908b91 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 11 Jul 2015 23:14:14 +0200 Subject: [PATCH 1505/2553] output: introduce config and perf output levels Goal is to reduce info output --- src/alert-fastlog.c | 2 +- src/alert-unified2-alert.c | 4 ++-- src/app-layer-dns-udp.c | 6 +++--- src/app-layer-htp.c | 6 +++--- src/app-layer-modbus.c | 6 +++--- src/defrag-hash.c | 6 +++--- src/detect-engine-mpm.c | 12 ++++++------ src/detect-engine.c | 10 +++++----- src/detect.c | 12 +++++++----- src/flow-manager.c | 8 ++++---- src/flow.c | 6 +++--- src/host.c | 10 +++++----- src/ippair.c | 10 +++++----- src/log-httplog.c | 2 +- src/reputation.c | 2 +- src/runmode-af-packet.c | 34 ++++++++++++++++----------------- src/runmodes.c | 2 +- src/source-af-packet.c | 10 ++++------ src/stream-tcp-reassemble.c | 14 +++++++------- src/stream-tcp.c | 24 +++++++++++------------ src/suricata.c | 2 +- src/tmqh-flow.c | 4 ++-- src/tmqh-packetpool.c | 4 ++-- src/util-debug.c | 2 ++ src/util-debug.h | 7 +++++++ src/util-profiling-keywords.c | 4 ++-- src/util-profiling-rulegroups.c | 4 ++-- src/util-profiling-rules.c | 6 +++--- src/util-profiling.c | 2 +- 29 files changed, 115 insertions(+), 106 deletions(-) diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 900fafb55a3f..cf7875bf642c 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -233,7 +233,7 @@ void AlertFastLogExitPrintStats(ThreadVars *tv, void *data) return; } - SCLogInfo("Fast log output wrote %" PRIu64 " alerts", aft->file_ctx->alerts); + //SCLogInfo("Fast log output wrote %" PRIu64 " alerts", aft->file_ctx->alerts); } /** diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 5450024680dc..557ec5d166b8 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -1211,8 +1211,8 @@ TmEcode Unified2AlertThreadDeinit(ThreadVars *t, void *data) } if (!(aun->unified2alert_ctx->file_ctx->flags & LOGFILE_ALERTS_PRINTED)) { - SCLogInfo("Alert unified2 module wrote %"PRIu64" alerts", - aun->unified2alert_ctx->file_ctx->alerts); + //SCLogInfo("Alert unified2 module wrote %"PRIu64" alerts", + // aun->unified2alert_ctx->file_ctx->alerts); /* Do not print it for each thread */ aun->unified2alert_ctx->file_ctx->flags |= LOGFILE_ALERTS_PRINTED; diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index 77a6cb3c7724..f2636df48ab6 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -336,7 +336,7 @@ static void DNSUDPConfigure(void) request_flood = value; } } - SCLogInfo("DNS request flood protection level: %u", request_flood); + SCLogConfig("DNS request flood protection level: %u", request_flood); DNSConfigSetRequestFlood(request_flood); p = ConfGetNode("app-layer.protocols.dns.state-memcap"); @@ -348,7 +348,7 @@ static void DNSUDPConfigure(void) state_memcap = value; } } - SCLogInfo("DNS per flow memcap (state-memcap): %u", state_memcap); + SCLogConfig("DNS per flow memcap (state-memcap): %u", state_memcap); DNSConfigSetStateMemcap(state_memcap); p = ConfGetNode("app-layer.protocols.dns.global-memcap"); @@ -360,7 +360,7 @@ static void DNSUDPConfigure(void) global_memcap = value; } } - SCLogInfo("DNS global memcap: %"PRIu64, global_memcap); + SCLogConfig("DNS global memcap: %"PRIu64, global_memcap); DNSConfigSetGlobalMemcap(global_memcap); } diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 63c244298830..950f472bf631 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2184,7 +2184,7 @@ static void HTPConfigSetDefaultsPhase2(char *name, HTPCfgRec *cfg_prec) cfg_prec->request.inspect_window += (int) (cfg_prec->request.inspect_window * (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100); - SCLogInfo("'%s' server has 'request-body-minimal-inspect-size' set to" + SCLogConfig("'%s' server has 'request-body-minimal-inspect-size' set to" " %d and 'request-body-inspect-window' set to %d after" " randomization.", name, @@ -2199,7 +2199,7 @@ static void HTPConfigSetDefaultsPhase2(char *name, HTPCfgRec *cfg_prec) (int) (cfg_prec->response.inspect_window * (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100); - SCLogInfo("'%s' server has 'response-body-minimal-inspect-size' set to" + SCLogConfig("'%s' server has 'response-body-minimal-inspect-size' set to" " %d and 'response-body-inspect-window' set to %d after" " randomization.", name, @@ -2546,7 +2546,7 @@ void AppLayerHtpPrintStats(void) { #ifdef DEBUG SCMutexLock(&htp_state_mem_lock); - SCLogInfo("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt); + SCLogPerf("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt); SCMutexUnlock(&htp_state_mem_lock); #endif } diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index c3502f2e59d4..f02c2124d894 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1472,10 +1472,10 @@ void RegisterModbusParsers(void) request_flood = value; } } - SCLogInfo("Modbus request flood protection level: %u", request_flood); + SCLogConfig("Modbus request flood protection level: %u", request_flood); } else { #ifndef AFLFUZZ_APPLAYER - SCLogInfo("Protocol detection and parser disabled for %s protocol.", proto_name); + SCLogConfig("Protocol detection and parser disabled for %s protocol.", proto_name); return; #endif } @@ -1507,7 +1507,7 @@ void RegisterModbusParsers(void) AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOSERVER); } else { - SCLogInfo("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); + SCLogConfig("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); } #ifdef UNITTESTS AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_MODBUS, ModbusParserRegisterTests); diff --git a/src/defrag-hash.c b/src/defrag-hash.c index 284b582f6e73..082eb4967380 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -204,7 +204,7 @@ void DefragInitConfig(char quiet) (void) SC_ATOMIC_ADD(defrag_memuse, (defrag_config.hash_size * sizeof(DefragTrackerHashRow))); if (quiet == FALSE) { - SCLogInfo("allocated %llu bytes of memory for the defrag hash... " + SCLogConfig("allocated %llu bytes of memory for the defrag hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(defrag_memuse), defrag_config.hash_size, (uintmax_t)sizeof(DefragTrackerHashRow)); @@ -231,14 +231,14 @@ void DefragInitConfig(char quiet) DefragTrackerEnqueue(&defragtracker_spare_q,h); } if (quiet == FALSE) { - SCLogInfo("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "", + SCLogConfig("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "", defragtracker_spare_q.len, (uintmax_t)sizeof(DefragTracker)); } } } if (quiet == FALSE) { - SCLogInfo("defrag memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("defrag memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(defrag_memuse), defrag_config.memcap); } diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index dafa2b3a8bcd..4c0d7dc91c56 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -130,12 +130,12 @@ void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) if (shared == 0) { if (!(de_ctx->flags & DE_QUIET)) { - SCLogInfo("using unique mpm ctx' for %s", am->name); + SCLogPerf("using unique mpm ctx' for %s", am->name); } am->sgh_mpm_context = MPM_CTX_FACTORY_UNIQUE_CONTEXT; } else { if (!(de_ctx->flags & DE_QUIET)) { - SCLogInfo("using shared mpm ctx' for %s", am->name); + SCLogPerf("using shared mpm ctx' for %s", am->name); } am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name); } @@ -184,10 +184,10 @@ static int32_t SetupBuiltinMpm(DetectEngineCtx *de_ctx, const char *name) int32_t ctx; if (shared == 0) { ctx = MPM_CTX_FACTORY_UNIQUE_CONTEXT; - SCLogInfo("using unique mpm ctx' for %s", name); + SCLogPerf("using unique mpm ctx' for %s", name); } else { ctx = MpmFactoryRegisterMpmCtxProfile(de_ctx, name); - SCLogInfo("using shared mpm ctx' for %s", name); + SCLogPerf("using shared mpm ctx' for %s", name); } return ctx; } @@ -839,14 +839,14 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx) if (!(de_ctx->flags & DE_QUIET)) { uint32_t x; for (x = 0; x < MPMB_MAX; x++) { - SCLogInfo("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]); + SCLogPerf("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]); } for (x = 0; x < APP_MPMS_MAX; x++) { if (appstats[x] == 0) continue; const char *name = app_mpms[x].name; char *direction = app_mpms[x].direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient"; - SCLogInfo("AppLayer MPM \"%s %s\": %u", direction, name, appstats[x]); + SCLogPerf("AppLayer MPM \"%s %s\": %u", direction, name, appstats[x]); } } } diff --git a/src/detect-engine.c b/src/detect-engine.c index cf917ad346a2..12dfb499733d 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -840,7 +840,7 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) de_ctx->mpm_matcher = PatternMatchDefaultMatcher(); de_ctx->spm_matcher = SinglePatternMatchDefaultMatcher(); - SCLogInfo("pattern matchers: MPM: %s, SPM: %s", + SCLogConfig("pattern matchers: MPM: %s, SPM: %s", mpm_table[de_ctx->mpm_matcher].name, spm_table[de_ctx->spm_matcher].name); @@ -1211,10 +1211,10 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) char *ports = NULL; (void)ConfGet("detect.grouping.tcp-whitelist", &ports); if (ports) { - SCLogInfo("grouping: tcp-whitelist %s", ports); + SCLogConfig("grouping: tcp-whitelist %s", ports); } else { ports = "53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080"; - SCLogInfo("grouping: tcp-whitelist (default) %s", ports); + SCLogConfig("grouping: tcp-whitelist (default) %s", ports); } if (DetectPortParse(de_ctx, &de_ctx->tcp_whitelist, ports) != 0) { @@ -1235,10 +1235,10 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) ports = NULL; (void)ConfGet("detect.grouping.udp-whitelist", &ports); if (ports) { - SCLogInfo("grouping: udp-whitelist %s", ports); + SCLogConfig("grouping: udp-whitelist %s", ports); } else { ports = "53, 135, 5060"; - SCLogInfo("grouping: udp-whitelist (default) %s", ports); + SCLogConfig("grouping: udp-whitelist (default) %s", ports); } if (DetectPortParse(de_ctx, &de_ctx->udp_whitelist, ports) != 0) { diff --git a/src/detect.c b/src/detect.c index f6296044e83d..bf95d784d1b0 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3236,7 +3236,8 @@ int RulesGroupByProto(DetectEngineCtx *de_ctx) ref++; } } - SCLogInfo("OTHER %s: %u proto groups, %u unique SGH's, %u copies", "toserver", cnt, own, ref); + SCLogPerf("OTHER %s: %u proto groups, %u unique SGH's, %u copies", + "toserver", cnt, own, ref); cnt = 0; own = 0; @@ -3272,7 +3273,8 @@ int RulesGroupByProto(DetectEngineCtx *de_ctx) ref++; } } - SCLogInfo("OTHER %s: %u proto groups, %u unique SGH's, %u copies", "toclient", cnt, own, ref); + SCLogPerf("OTHER %s: %u proto groups, %u unique SGH's, %u copies", + "toclient", cnt, own, ref); for (p = 0; p < 256; p++) { if (p == IPPROTO_TCP || p == IPPROTO_UDP) @@ -3486,7 +3488,7 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 iter->sh->init->whitelist); } #endif - SCLogInfo("%s %s: %u port groups, %u unique SGH's, %u copies", + SCLogPerf("%s %s: %u port groups, %u unique SGH's, %u copies", ipproto == 6 ? "TCP" : "UDP", direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", cnt, own, ref); @@ -3614,7 +3616,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) de_ctx->sig_cnt, cnt_iponly, cnt_payload, cnt_applayer, cnt_deonly); - SCLogInfo("building signature grouping structure, stage 1: " + SCLogConfig("building signature grouping structure, stage 1: " "preprocessing rules... complete"); } return 0; @@ -4002,7 +4004,7 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) sgh->id = idx; cnt++; } - SCLogInfo("Unique rule groups: %u", cnt); + SCLogPerf("Unique rule groups: %u", cnt); MpmStoreReportStats(de_ctx); diff --git a/src/flow-manager.c b/src/flow-manager.c index 31e907d3f92c..cd5e33dd3b2a 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -688,7 +688,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) StatsSyncCountersIfSignalled(th_v); } - SCLogInfo("%" PRIu32 " new flows, %" PRIu32 " established flows were " + SCLogPerf("%" PRIu32 " new flows, %" PRIu32 " established flows were " "timed out, %"PRIu32" flows in closed state", new_cnt, established_cnt, closing_cnt); @@ -717,7 +717,7 @@ void FlowManagerThreadSpawn() } flowmgr_number = (uint32_t)setting; - SCLogInfo("using %u flow manager threads", flowmgr_number); + SCLogConfig("using %u flow manager threads", flowmgr_number); SCCtrlCondInit(&flow_manager_ctrl_cond, NULL); SCCtrlMutexInit(&flow_manager_ctrl_mutex, NULL); @@ -850,7 +850,7 @@ static TmEcode FlowRecycler(ThreadVars *th_v, void *thread_data) StatsSyncCountersIfSignalled(th_v); } - SCLogInfo("%"PRIu64" flows processed", recycled_cnt); + SCLogPerf("%"PRIu64" flows processed", recycled_cnt); return TM_ECODE_OK; } @@ -881,7 +881,7 @@ void FlowRecyclerThreadSpawn() } flowrec_number = (uint32_t)setting; - SCLogInfo("using %u flow recycler threads", flowrec_number); + SCLogConfig("using %u flow recycler threads", flowrec_number); SCCtrlCondInit(&flow_recycler_ctrl_cond, NULL); SCCtrlMutexInit(&flow_recycler_ctrl_mutex, NULL); diff --git a/src/flow.c b/src/flow.c index 66e6b1d98234..0b847a0bb954 100644 --- a/src/flow.c +++ b/src/flow.c @@ -384,7 +384,7 @@ void FlowInitConfig(char quiet) (void) SC_ATOMIC_ADD(flow_memuse, (flow_config.hash_size * sizeof(FlowBucket))); if (quiet == FALSE) { - SCLogInfo("allocated %llu bytes of memory for the flow hash... " + SCLogConfig("allocated %llu bytes of memory for the flow hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(flow_memuse), flow_config.hash_size, (uintmax_t)sizeof(FlowBucket)); @@ -410,9 +410,9 @@ void FlowInitConfig(char quiet) } if (quiet == FALSE) { - SCLogInfo("preallocated %" PRIu32 " flows of size %" PRIuMAX "", + SCLogConfig("preallocated %" PRIu32 " flows of size %" PRIuMAX "", flow_spare_q.len, (uintmax_t)(sizeof(Flow) + + FlowStorageSize())); - SCLogInfo("flow memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("flow memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(flow_memuse), flow_config.memcap); } diff --git a/src/host.c b/src/host.c index 86092d9ef31d..d992b0a0c352 100644 --- a/src/host.c +++ b/src/host.c @@ -210,7 +210,7 @@ void HostInitConfig(char quiet) (void) SC_ATOMIC_ADD(host_memuse, (host_config.hash_size * sizeof(HostHashRow))); if (quiet == FALSE) { - SCLogInfo("allocated %llu bytes of memory for the host hash... " + SCLogConfig("allocated %llu bytes of memory for the host hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(host_memuse), host_config.hash_size, (uintmax_t)sizeof(HostHashRow)); @@ -235,9 +235,9 @@ void HostInitConfig(char quiet) } if (quiet == FALSE) { - SCLogInfo("preallocated %" PRIu32 " hosts of size %" PRIu16 "", + SCLogConfig("preallocated %" PRIu32 " hosts of size %" PRIu16 "", host_spare_q.len, g_host_size); - SCLogInfo("host memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("host memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(host_memuse), host_config.memcap); } @@ -249,10 +249,10 @@ void HostInitConfig(char quiet) void HostPrintStats (void) { #ifdef HOSTBITS_STATS - SCLogInfo("hostbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", + SCLogPerf("hostbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", hostbits_added, hostbits_removed, hostbits_memuse_max); #endif /* HOSTBITS_STATS */ - SCLogInfo("host memory usage: %llu bytes, maximum: %"PRIu64, + SCLogPerf("host memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(host_memuse), host_config.memcap); return; } diff --git a/src/ippair.c b/src/ippair.c index e86d67b5316e..c83aa2b5d898 100644 --- a/src/ippair.c +++ b/src/ippair.c @@ -206,7 +206,7 @@ void IPPairInitConfig(char quiet) (void) SC_ATOMIC_ADD(ippair_memuse, (ippair_config.hash_size * sizeof(IPPairHashRow))); if (quiet == FALSE) { - SCLogInfo("allocated %llu bytes of memory for the ippair hash... " + SCLogConfig("allocated %llu bytes of memory for the ippair hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(ippair_memuse), ippair_config.hash_size, (uintmax_t)sizeof(IPPairHashRow)); @@ -231,9 +231,9 @@ void IPPairInitConfig(char quiet) } if (quiet == FALSE) { - SCLogInfo("preallocated %" PRIu32 " ippairs of size %" PRIu16 "", + SCLogConfig("preallocated %" PRIu32 " ippairs of size %" PRIu16 "", ippair_spare_q.len, g_ippair_size); - SCLogInfo("ippair memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("ippair memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(ippair_memuse), ippair_config.memcap); } @@ -245,10 +245,10 @@ void IPPairInitConfig(char quiet) void IPPairPrintStats (void) { #ifdef IPPAIRBITS_STATS - SCLogInfo("ippairbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", + SCLogPerf("ippairbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", ippairbits_added, ippairbits_removed, ippairbits_memuse_max); #endif /* IPPAIRBITS_STATS */ - SCLogInfo("ippair memory usage: %llu bytes, maximum: %"PRIu64, + SCLogPerf("ippair memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(ippair_memuse), ippair_config.memcap); return; } diff --git a/src/log-httplog.c b/src/log-httplog.c index 10bc4160fe22..e77e79031be6 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -582,7 +582,7 @@ void LogHttpLogExitPrintStats(ThreadVars *tv, void *data) return; } - SCLogInfo("HTTP logger logged %" PRIu32 " requests", aft->uri_cnt); + //SCLogInfo("HTTP logger logged %" PRIu32 " requests", aft->uri_cnt); } /** \brief Create a new http log LogFileCtx. diff --git a/src/reputation.c b/src/reputation.c index b0aee7cbf541..6f03ce98c798 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -617,7 +617,7 @@ int SRepInit(DetectEngineCtx *de_ctx) (void)ConfGet("reputation-categories-file", &filename); files = ConfGetNode("reputation-files"); if (filename == NULL && files == NULL) { - SCLogInfo("IP reputation disabled"); + SCLogConfig("IP reputation disabled"); return 0; } diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 725fa8d4f6c4..34b1a3872b3a 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -152,7 +152,7 @@ void *ParseAFPConfig(const char *iface) if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; - SCLogInfo("Going to use command-line provided bpf filter '%s'", + SCLogConfig("Going to use command-line provided bpf filter '%s'", aconf->bpf_filter); } } @@ -202,7 +202,7 @@ void *ParseAFPConfig(const char *iface) if (boolval) { aconf->flags |= AFP_RING_MODE; } else { - SCLogInfo("Disabling mmaped capture on iface %s", + SCLogConfig("Disabling mmaped capture on iface %s", aconf->iface); aconf->flags &= ~AFP_RING_MODE; } @@ -214,7 +214,7 @@ void *ParseAFPConfig(const char *iface) (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "mmap-locked", (int *)&boolval); if (boolval) { - SCLogInfo("Enabling locked memory for mmap on iface %s", + SCLogConfig("Enabling locked memory for mmap on iface %s", aconf->iface); aconf->flags |= AFP_MMAP_LOCKED; } @@ -223,7 +223,7 @@ void *ParseAFPConfig(const char *iface) if (boolval) { if (strcasecmp(RunmodeGetActive(), "workers") == 0) { #ifdef HAVE_TPACKET_V3 - SCLogInfo("Enabling tpacket v3 capture on iface %s", + SCLogConfig("Enabling tpacket v3 capture on iface %s", aconf->iface); aconf->flags |= AFP_TPACKET_V3; #else @@ -240,7 +240,7 @@ void *ParseAFPConfig(const char *iface) (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "use-emergency-flush", (int *)&boolval); if (boolval) { - SCLogInfo("Enabling ring emergency flush on iface %s", + SCLogConfig("Enabling ring emergency flush on iface %s", aconf->iface); aconf->flags |= AFP_EMERGENCY_MODE; } @@ -282,7 +282,7 @@ void *ParseAFPConfig(const char *iface) /* default to our safest choice: flow hashing + defrag enabled */ aconf->cluster_type = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { - SCLogInfo("Using round-robin cluster mode for AF_PACKET (iface %s)", + SCLogConfig("Using round-robin cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_LB; } else if (strcmp(tmpctype, "cluster_flow") == 0) { @@ -290,29 +290,29 @@ void *ParseAFPConfig(const char *iface) * compute the hash */ uint16_t defrag = 0; int conf_val = 0; - SCLogInfo("Using flow cluster mode for AF_PACKET (iface %s)", + SCLogConfig("Using flow cluster mode for AF_PACKET (iface %s)", aconf->iface); ConfGetChildValueBoolWithDefault(if_root, if_default, "defrag", &conf_val); if (conf_val) { - SCLogInfo("Using defrag kernel functionality for AF_PACKET (iface %s)", + SCLogConfig("Using defrag kernel functionality for AF_PACKET (iface %s)", aconf->iface); defrag = PACKET_FANOUT_FLAG_DEFRAG; } aconf->cluster_type = PACKET_FANOUT_HASH | defrag; } else if (strcmp(tmpctype, "cluster_cpu") == 0) { - SCLogInfo("Using cpu cluster mode for AF_PACKET (iface %s)", + SCLogConfig("Using cpu cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_CPU; } else if (strcmp(tmpctype, "cluster_qm") == 0) { - SCLogInfo("Using queue based cluster mode for AF_PACKET (iface %s)", + SCLogConfig("Using queue based cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_QM; } else if (strcmp(tmpctype, "cluster_random") == 0) { - SCLogInfo("Using random based cluster mode for AF_PACKET (iface %s)", + SCLogConfig("Using random based cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_RND; } else if (strcmp(tmpctype, "cluster_rollover") == 0) { - SCLogInfo("Using rollover based cluster mode for AF_PACKET (iface %s)", + SCLogConfig("Using rollover based cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_ROLLOVER; @@ -323,7 +323,7 @@ void *ParseAFPConfig(const char *iface) int conf_val = 0; ConfGetChildValueBoolWithDefault(if_root, if_default, "rollover", &conf_val); if (conf_val) { - SCLogInfo("Using rollover kernel functionality for AF_PACKET (iface %s)", + SCLogConfig("Using rollover kernel functionality for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type |= PACKET_FANOUT_FLAG_ROLLOVER; } @@ -334,7 +334,7 @@ void *ParseAFPConfig(const char *iface) if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; - SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter); + SCLogConfig("Going to use bpf filter %s", aconf->bpf_filter); } } } @@ -364,7 +364,7 @@ void *ParseAFPConfig(const char *iface) (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); if (boolval) { - SCLogInfo("Disabling promiscuous mode on iface %s", + SCLogConfig("Disabling promiscuous mode on iface %s", aconf->iface); aconf->promisc = 0; } @@ -398,7 +398,7 @@ void *ParseAFPConfig(const char *iface) } } if (aconf->threads) - SCLogInfo("Using %d AF_PACKET threads for interface %s", aconf->threads, iface); + SCLogPerf("Using %d AF_PACKET threads for interface %s", aconf->threads, iface); } if (aconf->threads <= 0) { aconf->threads = 1; @@ -448,7 +448,7 @@ void *ParseAFPConfig(const char *iface) } if (aconf->flags & AFP_ZERO_COPY) { - SCLogInfo("%s: enabling zero copy mode by using data release call", iface); + SCLogConfig("%s: enabling zero copy mode by using data release call", iface); } return aconf; diff --git a/src/runmodes.c b/src/runmodes.c index fa920cec1ca5..9a9e5b53c08c 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -813,7 +813,7 @@ void RunModeInitializeOutputs(void) if (types != NULL) { ConfNode *type = NULL; TAILQ_FOREACH(type, &types->head, next) { - SCLogInfo("enabling 'eve-log' module '%s'", type->val); + SCLogConfig("enabling 'eve-log' module '%s'", type->val); char subname[256]; snprintf(subname, sizeof(subname), "%s.%s", output->val, type->val); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 8b065f8c8514..313278e3ccd6 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1587,7 +1587,7 @@ frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + siz ptv->req.tp_block_nr = ptv->req.tp_frame_nr / frames_per_block + 1; /* exact division */ ptv->req.tp_frame_nr = ptv->req.tp_block_nr * frames_per_block; - SCLogInfo("AF_PACKET RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d", + SCLogPerf("AF_PACKET RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d", ptv->req.tp_block_size, ptv->req.tp_block_nr, ptv->req.tp_frame_size, ptv->req.tp_frame_nr); return 1; @@ -1625,7 +1625,7 @@ static int AFPComputeRingParamsV3(AFPThreadVars *ptv) ptv->req3.tp_frame_nr = ptv->req3.tp_block_nr * frames_per_block; ptv->req3.tp_retire_blk_tov = ptv->block_timeout; ptv->req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH; - SCLogInfo("AF_PACKET V3 RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d (mem: %d)", + SCLogPerf("AF_PACKET V3 RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d (mem: %d)", ptv->req3.tp_block_size, ptv->req3.tp_block_nr, ptv->req3.tp_frame_size, ptv->req3.tp_frame_nr, ptv->req3.tp_block_size * ptv->req3.tp_block_nr @@ -1865,7 +1865,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) /* * Set the socket buffer size to the specified value. */ - SCLogInfo("Setting AF_PACKET socket buffer to %d", ptv->buffer_size); + SCLogPerf("Setting AF_PACKET socket buffer to %d", ptv->buffer_size); if (setsockopt(ptv->socket, SOL_SOCKET, SO_RCVBUF, &ptv->buffer_size, sizeof(ptv->buffer_size)) == -1) { @@ -2151,13 +2151,11 @@ void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) #ifdef PACKET_STATISTICS AFPDumpCounters(ptv); - SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", + SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, StatsGetLocalCounterValue(tv, ptv->capture_kernel_packets), StatsGetLocalCounterValue(tv, ptv->capture_kernel_drops)); #endif - - SCLogInfo("(%s) Packets %" PRIu64, tv->name, ptv->pkts); } /** diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 10276ddb4838..6fc622fb07ef 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -375,7 +375,7 @@ int StreamTcpReassemblyConfig(char quiet) sizes[npools].pktsize = 0xffff; sizes[npools].prealloc = 8; npools++; - SCLogInfo("appended a segment pool for pktsize 65536"); + SCLogConfig("appended a segment pool for pktsize 65536"); } } else if (npools == 0) { /* defaults */ @@ -447,7 +447,7 @@ int StreamTcpReassemblyConfig(char quiet) SCLogDebug("my_segment_pktsizes[i] %u, my_segment_poolsizes[i] %u", my_segment_pktsizes[i], my_segment_poolsizes[i]); if (!quiet) - SCLogInfo("segment pool: pktsize %u, prealloc %u", + SCLogConfig("segment pool: pktsize %u, prealloc %u", my_segment_pktsizes[i], my_segment_poolsizes[i]); } @@ -484,7 +484,7 @@ int StreamTcpReassemblyConfig(char quiet) stream_chunk_prealloc = prealloc; } if (!quiet) - SCLogInfo("stream.reassembly \"chunk-prealloc\": %u", stream_chunk_prealloc); + SCLogConfig("stream.reassembly \"chunk-prealloc\": %u", stream_chunk_prealloc); StreamMsgQueuesInit(stream_chunk_prealloc); intmax_t zero_copy_size = 128; @@ -497,7 +497,7 @@ int StreamTcpReassemblyConfig(char quiet) } stream_config.zero_copy_size = (uint16_t)zero_copy_size; if (!quiet) - SCLogInfo("stream.reassembly \"zero-copy-size\": %u", stream_config.zero_copy_size); + SCLogConfig("stream.reassembly \"zero-copy-size\": %u", stream_config.zero_copy_size); return 0; } @@ -539,7 +539,7 @@ void StreamTcpReassembleFree(char quiet) segment_pool[u16]->allocated); if (segment_pool[u16]->max_outstanding > segment_pool[u16]->allocated) { - SCLogInfo("TCP segment pool of size %u had a peak use of %u segments, " + SCLogPerf("TCP segment pool of size %u had a peak use of %u segments, " "more than the prealloc setting of %u", segment_pool_pktsizes[u16], segment_pool[u16]->max_outstanding, segment_pool[u16]->allocated); } @@ -564,8 +564,8 @@ void StreamTcpReassembleFree(char quiet) SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt); SCMutexDestroy(&segment_pool_memuse_mutex); SCMutexDestroy(&segment_pool_cnt_mutex); - SCLogInfo("dbg_app_layer_gap %u", dbg_app_layer_gap); - SCLogInfo("dbg_app_layer_gap_candidate %u", dbg_app_layer_gap_candidate); + SCLogPerf("dbg_app_layer_gap %u", dbg_app_layer_gap); + SCLogPerf("dbg_app_layer_gap_candidate %u", dbg_app_layer_gap_candidate); #endif } diff --git a/src/stream-tcp.c b/src/stream-tcp.c index ac603e6ef75e..c339a0b26491 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -335,7 +335,7 @@ void StreamTcpInitConfig(char quiet) } } if (!quiet) { - SCLogInfo("stream \"prealloc-sessions\": %"PRIu32" (per thread)", + SCLogConfig("stream \"prealloc-sessions\": %"PRIu32" (per thread)", stream_config.prealloc_sessions); } @@ -352,19 +352,19 @@ void StreamTcpInitConfig(char quiet) } if (!quiet) { - SCLogInfo("stream \"memcap\": %"PRIu64, stream_config.memcap); + SCLogConfig("stream \"memcap\": %"PRIu64, stream_config.memcap); } ConfGetBool("stream.midstream", &stream_config.midstream); if (!quiet) { - SCLogInfo("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled"); + SCLogConfig("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled"); } ConfGetBool("stream.async-oneside", &stream_config.async_oneside); if (!quiet) { - SCLogInfo("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled"); + SCLogConfig("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled"); } int csum = 0; @@ -379,7 +379,7 @@ void StreamTcpInitConfig(char quiet) } if (!quiet) { - SCLogInfo("stream \"checksum-validation\": %s", + SCLogConfig("stream \"checksum-validation\": %s", stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION ? "enabled" : "disabled"); } @@ -409,7 +409,7 @@ void StreamTcpInitConfig(char quiet) } if (!quiet) { - SCLogInfo("stream.\"inline\": %s", stream_inline ? "enabled" : "disabled"); + SCLogConfig("stream.\"inline\": %s", stream_inline ? "enabled" : "disabled"); } if ((ConfGetInt("stream.max-synack-queued", &value)) == 1) { @@ -422,7 +422,7 @@ void StreamTcpInitConfig(char quiet) stream_config.max_synack_queued = (uint8_t)STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED; } if (!quiet) { - SCLogInfo("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued); + SCLogConfig("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued); } char *temp_stream_reassembly_memcap_str; @@ -440,7 +440,7 @@ void StreamTcpInitConfig(char quiet) } if (!quiet) { - SCLogInfo("stream.reassembly \"memcap\": %"PRIu64"", stream_config.reassembly_memcap); + SCLogConfig("stream.reassembly \"memcap\": %"PRIu64"", stream_config.reassembly_memcap); } char *temp_stream_reassembly_depth_str; @@ -458,7 +458,7 @@ void StreamTcpInitConfig(char quiet) } if (!quiet) { - SCLogInfo("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth); + SCLogConfig("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth); } int randomize = 0; @@ -540,9 +540,9 @@ void StreamTcpInitConfig(char quiet) stream_config.reassembly_toclient_chunk_size); if (!quiet) { - SCLogInfo("stream.reassembly \"toserver-chunk-size\": %"PRIu16, + SCLogConfig("stream.reassembly \"toserver-chunk-size\": %"PRIu16, stream_config.reassembly_toserver_chunk_size); - SCLogInfo("stream.reassembly \"toclient-chunk-size\": %"PRIu16, + SCLogConfig("stream.reassembly \"toclient-chunk-size\": %"PRIu16, stream_config.reassembly_toclient_chunk_size); } @@ -556,7 +556,7 @@ void StreamTcpInitConfig(char quiet) enable_raw = 1; } if (!quiet) - SCLogInfo("stream.reassembly.raw: %s", enable_raw ? "enabled" : "disabled"); + SCLogConfig("stream.reassembly.raw: %s", enable_raw ? "enabled" : "disabled"); /* init the memcap/use tracking */ SC_ATOMIC_INIT(st_memuse); diff --git a/src/suricata.c b/src/suricata.c index e53d6ea0a081..c5c1c3a2f186 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2142,7 +2142,7 @@ static void SetupDelayedDetect(SCInstance *suri) } } - SCLogInfo("Delayed detect %s", suri->delayed_detect ? "enabled" : "disabled"); + SCLogConfig("Delayed detect %s", suri->delayed_detect ? "enabled" : "disabled"); if (suri->delayed_detect) { SCLogInfo("Packets will start being processed before signatures are active."); } diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index 480e909c32a0..cdcfd670a3e4 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -83,7 +83,7 @@ void TmqhFlowPrintAutofpHandler(void) { #define PRINT_IF_FUNC(f, msg) \ if (tmqh_table[TMQH_FLOW].OutHandler == (f)) \ - SCLogInfo("AutoFP mode using \"%s\" flow load balancer", (msg)) + SCLogConfig("AutoFP mode using \"%s\" flow load balancer", (msg)) PRINT_IF_FUNC(TmqhOutputFlowHash, "Hash"); PRINT_IF_FUNC(TmqhOutputFlowIPPair, "IPPair"); @@ -212,7 +212,7 @@ void TmqhOutputFlowFreeCtx(void *ctx) { TmqhFlowCtx *fctx = (TmqhFlowCtx *)ctx; - SCLogInfo("AutoFP - Total flow handler queues - %" PRIu16, + SCLogPerf("AutoFP - Total flow handler queues - %" PRIu16, fctx->size); SCFree(fctx->queues); SCFree(fctx); diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index c66025cf4dee..07e0bc9d3c6d 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -394,9 +394,9 @@ void PacketPoolInit(void) } PacketPoolStorePacket(p); } - SCLogInfo("preallocated %"PRIiMAX" packets. Total memory %"PRIuMAX"", - max_pending_packets, (uintmax_t)(max_pending_packets*SIZE_OF_PACKET)); + //SCLogInfo("preallocated %"PRIiMAX" packets. Total memory %"PRIuMAX"", + // max_pending_packets, (uintmax_t)(max_pending_packets*SIZE_OF_PACKET)); } void PacketPoolDestroy(void) diff --git a/src/util-debug.c b/src/util-debug.c index d8e607a2f46c..5e85e7744f83 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -55,6 +55,8 @@ SCEnumCharMap sc_log_level_map[ ] = { { "Warning", SC_LOG_WARNING }, { "Notice", SC_LOG_NOTICE }, { "Info", SC_LOG_INFO }, + { "Perf", SC_LOG_PERF }, + { "Config", SC_LOG_CONFIG }, { "Debug", SC_LOG_DEBUG }, { NULL, -1 } }; diff --git a/src/util-debug.h b/src/util-debug.h index 1f97d6565d81..48d9eee9568b 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -56,6 +56,8 @@ typedef enum { SC_LOG_WARNING, SC_LOG_NOTICE, SC_LOG_INFO, + SC_LOG_PERF, + SC_LOG_CONFIG, SC_LOG_DEBUG, SC_LOG_LEVEL_MAX, } SCLogLevel; @@ -242,6 +244,11 @@ extern int sc_log_module_cleaned; #define SCLogInfoRaw(file, func, line, ...) SCLog(SC_LOG_INFO, \ (file), (func), (line), __VA_ARGS__) +#define SCLogConfig(...) SCLog(SC_LOG_CONFIG, \ + __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) +#define SCLogPerf(...) SCLog(SC_LOG_PERF, \ + __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) + /** * \brief Macro used to log NOTICE messages. * diff --git a/src/util-profiling-keywords.c b/src/util-profiling-keywords.c index 444406c1275a..c512727d3b83 100644 --- a/src/util-profiling-keywords.c +++ b/src/util-profiling-keywords.c @@ -206,7 +206,7 @@ SCProfilingKeywordDump(DetectEngineCtx *de_ctx) if (fp != stdout) fclose(fp); - SCLogInfo("Done dumping keyword profiling data."); + SCLogPerf("Done dumping keyword profiling data."); } /** @@ -384,7 +384,7 @@ SCProfilingKeywordInitCounters(DetectEngineCtx *de_ctx) memset(de_ctx->profile_keyword_ctx_per_list[i]->data, 0x00, sizeof(SCProfileKeywordData) * DETECT_TBLSIZE); } - SCLogInfo("Registered %"PRIu32" keyword profiling counters.", DETECT_TBLSIZE); + SCLogPerf("Registered %"PRIu32" keyword profiling counters.", DETECT_TBLSIZE); } #endif /* PROFILING */ diff --git a/src/util-profiling-rulegroups.c b/src/util-profiling-rulegroups.c index 53b3624ce7b7..8f55e717fbf1 100644 --- a/src/util-profiling-rulegroups.c +++ b/src/util-profiling-rulegroups.c @@ -269,7 +269,7 @@ SCProfilingSghDump(DetectEngineCtx *de_ctx) if (fp != stdout) fclose(fp); - SCLogInfo("Done dumping rulegroup profiling data."); + SCLogPerf("Done dumping rulegroup profiling data."); } /** @@ -403,7 +403,7 @@ SCProfilingSghInitCounters(DetectEngineCtx *de_ctx) de_ctx->profile_sgh_ctx->cnt = de_ctx->sgh_array_cnt; - SCLogInfo("Registered %"PRIu32" rulegroup profiling counters.", de_ctx->sgh_array_cnt); + SCLogPerf("Registered %"PRIu32" rulegroup profiling counters.", de_ctx->sgh_array_cnt); } #endif /* PROFILING */ diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index 520b1c0614c2..fbfa491b7871 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -449,7 +449,7 @@ SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx) uint32_t count = rules_ctx->size; uint64_t total_ticks = 0; - SCLogInfo("Dumping profiling data for %u rules.", count); + SCLogPerf("Dumping profiling data for %u rules.", count); memset(summary, 0, summary_size); for (i = 0; i < count; i++) { @@ -522,7 +522,7 @@ SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx) if (fp != stdout) fclose(fp); SCFree(summary); - SCLogInfo("Done dumping profiling data."); + SCLogPerf("Done dumping profiling data."); } /** @@ -669,7 +669,7 @@ SCProfilingRuleInitCounters(DetectEngineCtx *de_ctx) } } - SCLogInfo("Registered %"PRIu32" rule profiling counters.", count); + SCLogPerf("Registered %"PRIu32" rule profiling counters.", count); } #endif /* PROFILING */ diff --git a/src/util-profiling.c b/src/util-profiling.c index 6942d37fe763..500a3ebc8e11 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -308,7 +308,7 @@ void SCProfilingDump(void) { SCProfilingDumpPacketStats(); - SCLogInfo("Done dumping profiling data."); + SCLogPerf("Done dumping profiling data."); } static void DumpFlowWorkerIP(FILE *fp, int ipv, uint64_t total) From 2beb39469b94ccf033e5e936ba6453fe4650c579 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 09:32:37 +0200 Subject: [PATCH 1506/2553] netmap: output cleanup --- src/runmode-netmap.c | 2 +- src/source-netmap.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index fcd2a0bd7025..d568b4585ccb 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -267,7 +267,7 @@ static void *ParseNetmapConfig(const char *iface_name) } SC_ATOMIC_RESET(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); - SCLogInfo("Using %d threads for interface %s", aconf->threads, + SCLogPerf("Using %d threads for interface %s", aconf->threads, aconf->iface_name); return aconf; diff --git a/src/source-netmap.c b/src/source-netmap.c index 096e7594bbc1..bf8eb212cae4 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -725,7 +725,7 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da if ((aconf->copy_mode != NETMAP_COPY_MODE_NONE) && active_runmode && !strcmp("workers", active_runmode)) { ntv->flags |= NETMAP_FLAG_ZERO_COPY; - SCLogInfo("Enabling zero copy mode for %s->%s", + SCLogPerf("Enabling zero copy mode for %s->%s", aconf->iface_name, aconf->out_iface_name); } else { uint16_t ring_size = ntv->ifsrc->rings[0].rx->num_slots; @@ -739,7 +739,7 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da } if (aconf->bpf_filter) { - SCLogInfo("Using BPF '%s' on iface '%s'", + SCLogConfig("Using BPF '%s' on iface '%s'", aconf->bpf_filter, ntv->ifsrc->ifname); if (pcap_compile_nopcap(default_packet_size, /* snaplen_arg */ LINKTYPE_ETHERNET, /* linktype_arg */ @@ -1054,7 +1054,7 @@ static void ReceiveNetmapThreadExitStats(ThreadVars *tv, void *data) NetmapThreadVars *ntv = (NetmapThreadVars *)data; NetmapDumpCounters(ntv); - SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 ", bytes %" PRIu64 "", + SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 ", bytes %" PRIu64 "", tv->name, StatsGetLocalCounterValue(tv, ntv->capture_kernel_packets), StatsGetLocalCounterValue(tv, ntv->capture_kernel_drops), From 4c663bb1432c50a0628ad72a976354fed6b346df Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 09:33:12 +0200 Subject: [PATCH 1507/2553] netmap: don't check for offloading twice --- src/source-netmap.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index bf8eb212cae4..d9223fe653e0 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -753,11 +753,6 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da } } - if (GetIfaceOffloading(aconf->iface) == 1) { - SCLogWarning(SC_ERR_NETMAP_CREATE, - "Using netmap mode with GRO or LRO activated can lead to capture problems"); - } - *data = (void *)ntv; aconf->DerefFunc(aconf); SCReturnInt(TM_ECODE_OK); From 2aac437927010dd5ccdd4a2f07ada0744c21a113 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 09:45:23 +0200 Subject: [PATCH 1508/2553] output: reduce verbosity on info level --- src/output-json-file.c | 6 +++--- src/util-coredump-config.c | 6 +++--- src/util-device.c | 2 +- src/util-magic.c | 16 ++++++++++------ src/util-mpm-hs.c | 4 ++-- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/output-json-file.c b/src/output-json-file.c index c4a7f5276bcb..a06628225a3f 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -261,20 +261,20 @@ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore"); if (force_filestore != NULL && ConfValIsTrue(force_filestore)) { FileForceFilestoreEnable(); - SCLogInfo("forcing filestore of all files"); + SCLogConfig("forcing filestore of all files"); } const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); - SCLogInfo("forcing magic lookup for logged files"); + SCLogConfig("forcing magic lookup for logged files"); } const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); if (force_md5 != NULL && ConfValIsTrue(force_md5)) { #ifdef HAVE_NSS FileForceMd5Enable(); - SCLogInfo("forcing md5 calculation for logged files"); + SCLogConfig("forcing md5 calculation for logged files"); #else SCLogInfo("md5 calculation requires linking against libnss"); #endif diff --git a/src/util-coredump-config.c b/src/util-coredump-config.c index 2115f930fbbe..9555e0fd7103 100644 --- a/src/util-coredump-config.c +++ b/src/util-coredump-config.c @@ -112,14 +112,14 @@ int32_t CoredumpLoadConfig (void) if (unlimited) { /* we want no limit on coredump size */ if (lim.rlim_max == RLIM_INFINITY && lim.rlim_cur == RLIM_INFINITY) { - SCLogInfo ("Core dump size is unlimited."); + SCLogConfig ("Core dump size is unlimited."); return 1; } else { new_lim.rlim_max = RLIM_INFINITY; new_lim.rlim_cur = RLIM_INFINITY; if (setrlimit (RLIMIT_CORE, &new_lim) == 0) { - SCLogInfo ("Core dump size set to unlimited."); + SCLogConfig ("Core dump size set to unlimited."); return 1; } if (errno == EPERM) { @@ -169,7 +169,7 @@ int32_t CoredumpLoadConfig (void) struct rlimit actual_lim; if (getrlimit (RLIMIT_CORE, &actual_lim) == 0) { if (actual_lim.rlim_cur == RLIM_INFINITY) { - SCLogInfo ("Core dump size set to unlimited."); + SCLogConfig ("Core dump size set to unlimited."); } #ifdef RLIM_SAVED_CUR else if (actual_lim.rlim_cur == RLIM_SAVED_CUR) { diff --git a/src/util-device.c b/src/util-device.c index a4e634ee0c66..409f8732cc62 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -214,7 +214,7 @@ int LiveBuildDeviceListCustom(const char *runmode, const char *itemname) if ((!strcmp(subchild->name, itemname))) { if (!strcmp(subchild->val, "default")) break; - SCLogInfo("Adding %s %s from config file", + SCLogConfig("Adding %s %s from config file", itemname, subchild->val); LiveRegisterDevice(subchild->val); i++; diff --git a/src/util-magic.c b/src/util-magic.c index 5d8615b182e4..679545751f3e 100644 --- a/src/util-magic.c +++ b/src/util-magic.c @@ -53,7 +53,8 @@ int MagicInit(void) g_magic_ctx = magic_open(0); if (g_magic_ctx == NULL) { - SCLogError(SC_ERR_MAGIC_OPEN, "magic_open failed: %s", magic_error(g_magic_ctx)); + SCLogError(SC_ERR_MAGIC_OPEN, "magic_open failed: %s", + magic_error(g_magic_ctx)); goto error; } @@ -62,15 +63,17 @@ int MagicInit(void) if (filename != NULL) { if (strlen(filename) == 0) { - /* set filename to NULL on *nix systems so magic_load uses system default path (see man libmagic) */ - SCLogInfo("using system default magic-file"); + /* set filename to NULL on *nix systems so magic_load uses system + * default path (see man libmagic) */ + SCLogConfig("using system default magic-file"); filename = NULL; } else { - SCLogInfo("using magic-file %s", filename); + SCLogConfig("using magic-file %s", filename); if ( (fd = fopen(filename, "r")) == NULL) { - SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); + SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", + filename, strerror(errno)); goto error; } fclose(fd); @@ -78,7 +81,8 @@ int MagicInit(void) } if (magic_load(g_magic_ctx, filename) != 0) { - SCLogError(SC_ERR_MAGIC_LOAD, "magic_load failed: %s", magic_error(g_magic_ctx)); + SCLogError(SC_ERR_MAGIC_LOAD, "magic_load failed: %s", + magic_error(g_magic_ctx)); goto error; } diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index 61a6c4cf89cc..43e74d3142a8 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -1063,7 +1063,7 @@ void MpmHSGlobalCleanup(void) { SCMutexLock(&g_scratch_proto_mutex); if (g_scratch_proto) { - SCLogInfo("Cleaning up Hyperscan global scratch"); + SCLogPerf("Cleaning up Hyperscan global scratch"); hs_free_scratch(g_scratch_proto); g_scratch_proto = NULL; } @@ -1071,7 +1071,7 @@ void MpmHSGlobalCleanup(void) SCMutexLock(&g_db_table_mutex); if (g_db_table != NULL) { - SCLogInfo("Clearing Hyperscan database cache"); + SCLogPerf("Clearing Hyperscan database cache"); HashTableFree(g_db_table); g_db_table = NULL; } From bdc2c6e9ce69a05e9ac517d732f4422cb2aed5dd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 09:55:44 +0200 Subject: [PATCH 1509/2553] affinity: type cleanup --- src/util-affinity.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/util-affinity.h b/src/util-affinity.h index 9ca30fcfe2d7..630f1b8edac3 100644 --- a/src/util-affinity.h +++ b/src/util-affinity.h @@ -65,20 +65,19 @@ enum { }; typedef struct ThreadsAffinityType_ { - char *name; -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ - cpu_set_t cpu_set; -#endif + const char *name; uint8_t mode_flag; int prio; int nb_threads; + SCMutex taf_mutex; + uint16_t lcpu; /* use by exclusive mode */ + #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ + cpu_set_t cpu_set; cpu_set_t lowprio_cpu; cpu_set_t medprio_cpu; cpu_set_t hiprio_cpu; #endif - SCMutex taf_mutex; - uint16_t lcpu; /* use by exclusive mode */ } ThreadsAffinityType; /** store thread affinity mode for all type of threads */ From 570b9d06e0ae34aa880beaf7013b4b23c9b05b19 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 10:01:28 +0200 Subject: [PATCH 1510/2553] affinity: remove unused settings These were never referenced to in the code so they can be removed. Add bypass to config parser in case the settings are still in old yamls. --- src/util-affinity.c | 31 +++++++------------------------ src/util-affinity.h | 4 ---- suricata.yaml.in | 13 ------------- 3 files changed, 7 insertions(+), 41 deletions(-) diff --git a/src/util-affinity.c b/src/util-affinity.c index 53ded80a0620..08b85f8e15cb 100644 --- a/src/util-affinity.c +++ b/src/util-affinity.c @@ -38,18 +38,6 @@ ThreadsAffinityType thread_affinity[MAX_CPU_SET] = { .prio = PRIO_MEDIUM, .lcpu = 0, }, - { - .name = "decode-cpu-set", - .mode_flag = BALANCED_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, - { - .name = "stream-cpu-set", - .mode_flag = BALANCED_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, { .name = "detect-cpu-set", .mode_flag = EXCLUSIVE_AFFINITY, @@ -62,18 +50,6 @@ ThreadsAffinityType thread_affinity[MAX_CPU_SET] = { .prio = PRIO_MEDIUM, .lcpu = 0, }, - { - .name = "reject-cpu-set", - .mode_flag = BALANCED_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, - { - .name = "output-cpu-set", - .mode_flag = BALANCED_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, { .name = "management-cpu-set", .mode_flag = BALANCED_AFFINITY, @@ -206,6 +182,13 @@ void AffinitySetupLoadFromConfig() } TAILQ_FOREACH(affinity, &root->head, next) { + if (strcmp(affinity->val, "decode-cpu-set") == 0 || + strcmp(affinity->val, "stream-cpu-set") == 0 || + strcmp(affinity->val, "reject-cpu-set") == 0 || + strcmp(affinity->val, "output-cpu-set") == 0) { + continue; + } + ThreadsAffinityType *taf = GetAffinityTypeFromName(affinity->val); ConfNode *node = NULL; ConfNode *nprio = NULL; diff --git a/src/util-affinity.h b/src/util-affinity.h index 630f1b8edac3..2c4e424b23e1 100644 --- a/src/util-affinity.h +++ b/src/util-affinity.h @@ -48,12 +48,8 @@ enum { RECEIVE_CPU_SET, - DECODE_CPU_SET, - STREAM_CPU_SET, DETECT_CPU_SET, VERDICT_CPU_SET, - REJECT_CPU_SET, - OUTPUT_CPU_SET, MANAGEMENT_CPU_SET, MAX_CPU_SET }; diff --git a/suricata.yaml.in b/suricata.yaml.in index 15bd7eeb0165..2ca70e218b6e 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1278,11 +1278,6 @@ threading: cpu: [ 0 ] # include only these cpus in affinity settings - receive-cpu-set: cpu: [ 0 ] # include only these cpus in affinity settings - - decode-cpu-set: - cpu: [ 0, 1 ] - mode: "balanced" - - stream-cpu-set: - cpu: [ "0-1" ] - detect-cpu-set: cpu: [ "all" ] mode: "exclusive" # run detect threads in these cpus @@ -1298,14 +1293,6 @@ threading: cpu: [ 0 ] prio: default: "high" - - reject-cpu-set: - cpu: [ 0 ] - prio: - default: "low" - - output-cpu-set: - cpu: [ "all" ] - prio: - default: "medium" # # By default Suricata creates one "detect" thread per available CPU/CPU core. # This setting allows controlling this behaviour. A ratio setting of 2 will From 45b72d61c98277196c4233e64dcaa1451bbcebf5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 10:24:03 +0200 Subject: [PATCH 1511/2553] affinity: improve suricata.yaml doc --- suricata.yaml.in | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 2ca70e218b6e..55da24cbe042 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1264,15 +1264,18 @@ spm-algo: auto # Suricata is multi-threaded. Here the threading can be influenced. threading: - # On some cpu's/architectures it is beneficial to tie individual threads - # to specific CPU's/CPU cores. In this case all threads are tied to CPU0, - # and each extra CPU/core has one "detect" thread. - # - # On Intel Core2 and Nehalem CPU's enabling this will degrade performance. - # set-cpu-affinity: no - # Tune cpu affinity of suricata threads. Each family of threads can be bound + # Tune cpu affinity of threads. Each family of threads can be bound # on specific CPUs. + # + # These 2 apply to the all runmodes: + # management-cpu-set is used for flow timeout handling, counters + # detect-cpu-set is used for 'worker' threads + # + # Additionally, for autofp these apply: + # receive-cpu-set is used for capture threads + # verdict-cpu-set is used for IPS verdict threads + # cpu-affinity: - management-cpu-set: cpu: [ 0 ] # include only these cpus in affinity settings From 723e90a174fd6f4df6677eff348fa46c25e36f65 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 10:32:43 +0200 Subject: [PATCH 1512/2553] affinity: rename detect-cpu-set to worker-cpu-set Add fallback for existing configs. --- src/util-affinity.c | 20 ++++++++++++-------- suricata.yaml.in | 6 +++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/util-affinity.c b/src/util-affinity.c index 08b85f8e15cb..9356f67c2c2b 100644 --- a/src/util-affinity.c +++ b/src/util-affinity.c @@ -39,7 +39,7 @@ ThreadsAffinityType thread_affinity[MAX_CPU_SET] = { .lcpu = 0, }, { - .name = "detect-cpu-set", + .name = "worker-cpu-set", .mode_flag = EXCLUSIVE_AFFINITY, .prio = PRIO_MEDIUM, .lcpu = 0, @@ -95,7 +95,7 @@ static void AffinitySetupInit() return; } -static void build_cpuset(char *name, ConfNode *node, cpu_set_t *cpu) +static void build_cpuset(const char *name, ConfNode *node, cpu_set_t *cpu) { ConfNode *lnode; TAILQ_FOREACH(lnode, &node->head, next) { @@ -189,7 +189,11 @@ void AffinitySetupLoadFromConfig() continue; } - ThreadsAffinityType *taf = GetAffinityTypeFromName(affinity->val); + const char *setname = affinity->val; + if (strcmp(affinity->val, "detect-cpu-set") == 0) + setname = "worker-cpu-set"; + + ThreadsAffinityType *taf = GetAffinityTypeFromName(setname); ConfNode *node = NULL; ConfNode *nprio = NULL; @@ -198,7 +202,7 @@ void AffinitySetupLoadFromConfig() exit(EXIT_FAILURE); } else { SCLogInfo("Found affinity definition for \"%s\"", - affinity->val); + setname); } CPU_ZERO(&taf->cpu_set); @@ -206,7 +210,7 @@ void AffinitySetupLoadFromConfig() if (node == NULL) { SCLogInfo("unable to find 'cpu'"); } else { - build_cpuset(affinity->val, node, &taf->cpu_set); + build_cpuset(setname, node, &taf->cpu_set); } CPU_ZERO(&taf->lowprio_cpu); @@ -218,21 +222,21 @@ void AffinitySetupLoadFromConfig() if (node == NULL) { SCLogDebug("unable to find 'low' prio using default value"); } else { - build_cpuset(affinity->val, node, &taf->lowprio_cpu); + build_cpuset(setname, node, &taf->lowprio_cpu); } node = ConfNodeLookupChild(nprio, "medium"); if (node == NULL) { SCLogDebug("unable to find 'medium' prio using default value"); } else { - build_cpuset(affinity->val, node, &taf->medprio_cpu); + build_cpuset(setname, node, &taf->medprio_cpu); } node = ConfNodeLookupChild(nprio, "high"); if (node == NULL) { SCLogDebug("unable to find 'high' prio using default value"); } else { - build_cpuset(affinity->val, node, &taf->hiprio_cpu); + build_cpuset(setname, node, &taf->hiprio_cpu); } node = ConfNodeLookupChild(nprio, "default"); if (node != NULL) { diff --git a/suricata.yaml.in b/suricata.yaml.in index 55da24cbe042..6caadc84b357 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1270,7 +1270,7 @@ threading: # # These 2 apply to the all runmodes: # management-cpu-set is used for flow timeout handling, counters - # detect-cpu-set is used for 'worker' threads + # worker-cpu-set is used for 'worker' threads # # Additionally, for autofp these apply: # receive-cpu-set is used for capture threads @@ -1281,9 +1281,9 @@ threading: cpu: [ 0 ] # include only these cpus in affinity settings - receive-cpu-set: cpu: [ 0 ] # include only these cpus in affinity settings - - detect-cpu-set: + - worker-cpu-set: cpu: [ "all" ] - mode: "exclusive" # run detect threads in these cpus + mode: "exclusive" # Use explicitely 3 threads and don't compute number by using # detect-thread-ratio variable: # threads: 3 From 5f9de1e7346d45567edfcb3b2e597a89f7c75fad Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 10:37:59 +0200 Subject: [PATCH 1513/2553] affinity: rename detect -> worker set internall --- src/runmode-erf-file.c | 2 +- src/runmode-pcap-file.c | 6 +++--- src/util-affinity.h | 2 +- src/util-runmodes.c | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index 5e0b097ab600..e4f3c3df9374 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -142,7 +142,7 @@ int RunModeErfFileAutoFp(void) cpu = 1; /* always create at least one thread */ - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); + int thread_max = TmThreadGetNbThreads(WORKER_CPU_SET); if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index c6fea2b2defb..9db65d485e30 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -109,7 +109,7 @@ int RunModeFilePcapSingle(void) SetupOutputs(tv); - TmThreadSetCPU(tv, DETECT_CPU_SET); + TmThreadSetCPU(tv, WORKER_CPU_SET); #ifndef AFLFUZZ_PCAP_RUNMODE if (TmThreadSpawn(tv) != TM_ECODE_OK) { @@ -177,7 +177,7 @@ int RunModeFilePcapAutoFp(void) cpu = 1; /* always create at least one thread */ - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); + int thread_max = TmThreadGetNbThreads(WORKER_CPU_SET); if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) @@ -253,7 +253,7 @@ int RunModeFilePcapAutoFp(void) /* add outputs as well */ SetupOutputs(tv_detect_ncpu); - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); + TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); diff --git a/src/util-affinity.h b/src/util-affinity.h index 2c4e424b23e1..db12276c943d 100644 --- a/src/util-affinity.h +++ b/src/util-affinity.h @@ -48,7 +48,7 @@ enum { RECEIVE_CPU_SET, - DETECT_CPU_SET, + WORKER_CPU_SET, VERDICT_CPU_SET, MANAGEMENT_CPU_SET, MAX_CPU_SET diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 375295b1044b..d2789f0f47e2 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -99,7 +99,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); int nlive = LiveGetDeviceCount(); - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); + int thread_max = TmThreadGetNbThreads(WORKER_CPU_SET); /* always create at least one thread */ if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; @@ -253,7 +253,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); + TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); TmThreadSetGroupName(tv_detect_ncpu, "Detect"); @@ -354,7 +354,7 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod SetupOutputs(tv); - TmThreadSetCPU(tv, DETECT_CPU_SET); + TmThreadSetCPU(tv, WORKER_CPU_SET); if (TmThreadSpawn(tv) != TM_ECODE_OK) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); @@ -455,7 +455,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); int nqueue = LiveGetDeviceCount(); - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); + int thread_max = TmThreadGetNbThreads(WORKER_CPU_SET); /* always create at least one thread */ if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; @@ -531,7 +531,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); + TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); SetupOutputs(tv_detect_ncpu); @@ -654,7 +654,7 @@ int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, SetupOutputs(tv); - TmThreadSetCPU(tv, DETECT_CPU_SET); + TmThreadSetCPU(tv, WORKER_CPU_SET); if (TmThreadSpawn(tv) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); From b5633b9bfdd87413dc22bd6ff97c631e3d08b4d4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 10:49:53 +0200 Subject: [PATCH 1514/2553] affinity: small cleanups to output & code --- src/tm-threads.c | 13 +++++++------ src/util-affinity.c | 24 ++++++++++++------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index 8cfca0e7ac86..8442a1e84559 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1026,8 +1026,9 @@ void TmThreadSetPrio(ThreadVars *tv) #else int ret = nice(tv->thread_priority); if (ret == -1) { - SCLogError(SC_ERR_THREAD_NICE_PRIO, "Error setting nice value " - "for thread %s: %s", tv->name, strerror(errno)); + SCLogError(SC_ERR_THREAD_NICE_PRIO, "Error setting nice value %d " + "for thread %s: %s", tv->thread_priority, tv->name, + strerror(errno)); } else { SCLogDebug("Nice value set to %"PRId32" for thread %s", tv->thread_priority, tv->name); @@ -1090,7 +1091,7 @@ int TmThreadGetNbThreads(uint8_t type) TmEcode TmThreadSetupOptions(ThreadVars *tv) { if (tv->thread_setup_flags & THREAD_SET_AFFINITY) { - SCLogInfo("Setting affinity for \"%s\" Module to cpu/core " + SCLogPerf("Setting affinity for thread \"%s\"to cpu/core " "%"PRIu16", thread id %lu", tv->name, tv->cpu_affinity, SCGetThreadIdLong()); SetCPUAffinity(tv->cpu_affinity); @@ -1114,14 +1115,14 @@ TmEcode TmThreadSetupOptions(ThreadVars *tv) } else { tv->thread_priority = taf->prio; } - SCLogInfo("Setting prio %d for \"%s\" Module to cpu/core " + SCLogPerf("Setting prio %d for thread \"%s\" to cpu/core " "%d, thread id %lu", tv->thread_priority, tv->name, cpu, SCGetThreadIdLong()); } else { SetCPUAffinitySet(&taf->cpu_set); tv->thread_priority = taf->prio; - SCLogInfo("Setting prio %d for \"%s\" thread " - ", thread id %lu", tv->thread_priority, + SCLogPerf("Setting prio %d for thread \"%s\", " + "thread id %lu", tv->thread_priority, tv->name, SCGetThreadIdLong()); } TmThreadSetPrio(tv); diff --git a/src/util-affinity.c b/src/util-affinity.c index 9356f67c2c2b..51925a9f3b48 100644 --- a/src/util-affinity.c +++ b/src/util-affinity.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Open Information Security Foundation +/* Copyright (C) 2010-2016 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 @@ -95,7 +95,7 @@ static void AffinitySetupInit() return; } -static void build_cpuset(const char *name, ConfNode *node, cpu_set_t *cpu) +static void BuildCpuset(const char *name, ConfNode *node, cpu_set_t *cpu) { ConfNode *lnode; TAILQ_FOREACH(lnode, &node->head, next) { @@ -201,8 +201,7 @@ void AffinitySetupLoadFromConfig() SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown cpu-affinity type"); exit(EXIT_FAILURE); } else { - SCLogInfo("Found affinity definition for \"%s\"", - setname); + SCLogConfig("Found affinity definition for \"%s\"", setname); } CPU_ZERO(&taf->cpu_set); @@ -210,7 +209,7 @@ void AffinitySetupLoadFromConfig() if (node == NULL) { SCLogInfo("unable to find 'cpu'"); } else { - build_cpuset(setname, node, &taf->cpu_set); + BuildCpuset(setname, node, &taf->cpu_set); } CPU_ZERO(&taf->lowprio_cpu); @@ -222,21 +221,21 @@ void AffinitySetupLoadFromConfig() if (node == NULL) { SCLogDebug("unable to find 'low' prio using default value"); } else { - build_cpuset(setname, node, &taf->lowprio_cpu); + BuildCpuset(setname, node, &taf->lowprio_cpu); } node = ConfNodeLookupChild(nprio, "medium"); if (node == NULL) { SCLogDebug("unable to find 'medium' prio using default value"); } else { - build_cpuset(setname, node, &taf->medprio_cpu); + BuildCpuset(setname, node, &taf->medprio_cpu); } node = ConfNodeLookupChild(nprio, "high"); if (node == NULL) { SCLogDebug("unable to find 'high' prio using default value"); } else { - build_cpuset(setname, node, &taf->hiprio_cpu); + BuildCpuset(setname, node, &taf->hiprio_cpu); } node = ConfNodeLookupChild(nprio, "default"); if (node != NULL) { @@ -250,7 +249,8 @@ void AffinitySetupLoadFromConfig() SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown cpu_affinity prio"); exit(EXIT_FAILURE); } - SCLogInfo("Using default prio '%s'", node->val); + SCLogConfig("Using default prio '%s' for set '%s'", + node->val, setname); } } @@ -285,7 +285,6 @@ void AffinitySetupLoadFromConfig() int AffinityGetNextCPU(ThreadsAffinityType *taf) { int ncpu = 0; - #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ int iter = 0; SCMutexLock(&taf->taf_mutex); @@ -298,13 +297,14 @@ int AffinityGetNextCPU(ThreadsAffinityType *taf) } } if (iter == 2) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "cpu_set does not contain available cpus, cpu affinity conf is invalid"); + SCLogError(SC_ERR_INVALID_ARGUMENT, "cpu_set does not contain " + "available cpus, cpu affinity conf is invalid"); } taf->lcpu = ncpu + 1; if (taf->lcpu >= UtilCpuGetNumProcessorsOnline()) taf->lcpu = 0; SCMutexUnlock(&taf->taf_mutex); - SCLogInfo("Setting affinity on CPU %d", ncpu); + SCLogDebug("Setting affinity on CPU %d", ncpu); #endif /* OS_WIN32 and __OpenBSD__ */ return ncpu; } From 0b6171854dcf6fc431860c80d2e99dd69f6df60c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 10:53:46 +0200 Subject: [PATCH 1515/2553] yaml: improve affinity defaults --- suricata.yaml.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 6caadc84b357..a1cacd48c879 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1292,10 +1292,10 @@ threading: medium: [ "1-2" ] high: [ 3 ] default: "medium" - - verdict-cpu-set: - cpu: [ 0 ] - prio: - default: "high" + #- verdict-cpu-set: + # cpu: [ 0 ] + # prio: + # default: "high" # # By default Suricata creates one "detect" thread per available CPU/CPU core. # This setting allows controlling this behaviour. A ratio setting of 2 will @@ -1305,7 +1305,7 @@ threading: # thread being created. Regardless of the setting at a minimum 1 detect # thread will always be created. # - detect-thread-ratio: 1.5 + detect-thread-ratio: 1.0 # Profiling settings. Only effective if Suricata has been built with the # the --enable-profiling configure flag. From ffba26d04a84c7342c0cbdbaee099136eb5990f6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 12:25:14 +0200 Subject: [PATCH 1516/2553] configure: don't set -march=native for powerpc --- configure.ac | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure.ac b/configure.ac index 71f402936a64..47ab3e164aaf 100644 --- a/configure.ac +++ b/configure.ac @@ -364,6 +364,10 @@ AC_ARG_ENABLE(gccmarch_native, AS_HELP_STRING([--enable-gccmarch-native], [Enable gcc march=native gcc 4.2 and later only]),,[enable_gccmarch_native=yes]) AS_IF([test "x$enable_gccmarch_native" = "xyes"], [ + case "$host" in + *powerpc*) + ;; + *) OFLAGS="$CFLAGS" CFLAGS="$CFLAGS -march=native" AC_MSG_CHECKING([checking if $CC supports -march=native]) @@ -379,6 +383,8 @@ enable_gccmarch_native=no ] ) + ;; + esac ]) # options From 86d44cea96826c07fdaa9c48027c8bf4835ab445 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 12:27:47 +0200 Subject: [PATCH 1517/2553] netmap: code cleanup --- src/runmode-netmap.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index d568b4585ccb..ff2e803ab8f6 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -109,19 +109,18 @@ static void *ParseNetmapConfig(const char *iface_name) ConfNode *if_root; ConfNode *if_default = NULL; ConfNode *netmap_node; - NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); char *tmpctype; char *copymodestr; int boolval; char *bpf_filter = NULL; char *out_iface = NULL; - if (unlikely(aconf == NULL)) { + if (iface_name == NULL) { return NULL; } - if (iface_name == NULL) { - SCFree(aconf); + NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); + if (unlikely(aconf == NULL)) { return NULL; } From 648a69759bdf0ce2ac9809a700ce74ab7935ca82 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 12:28:09 +0200 Subject: [PATCH 1518/2553] netmap: don't set more than 1 thread on sw ring --- src/runmode-netmap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index ff2e803ab8f6..8403d0843ebf 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -253,7 +253,10 @@ static void *ParseNetmapConfig(const char *iface_name) finalize: - if (aconf->threads == 0) { + if (aconf->iface_sw) { + /* just one thread per interface supported */ + aconf->threads = 1; + } else if (aconf->threads == 0) { /* As NetmapGetRSSCount is broken on Linux, first run * GetIfaceRSSQueuesNum. If that fails, run NetmapGetRSSCount */ aconf->threads = GetIfaceRSSQueuesNum(aconf->iface); From a3095987217356d3175874477c0c80c007c8fd4c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 3 Jun 2016 12:38:08 +0200 Subject: [PATCH 1519/2553] netmap: work around mtu error on iface+ settings --- src/suricata.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/suricata.c b/src/suricata.c index c5c1c3a2f186..5482002a5497 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2182,15 +2182,30 @@ static int ConfigGetCaptureValue(SCInstance *suri) if ((ConfGet("default-packet-size", &temp_default_packet_size)) != 1) { int lthread; int nlive; + int strip_trailing_plus = 0; switch (suri->run_mode) { case RUNMODE_PCAP_DEV: case RUNMODE_AFP_DEV: case RUNMODE_NETMAP: + /* in netmap igb0+ has a special meaning, however the + * interface really is igb0 */ + strip_trailing_plus = 1; + /* fall through */ case RUNMODE_PFRING: nlive = LiveGetDeviceCount(); for (lthread = 0; lthread < nlive; lthread++) { char *live_dev = LiveGetDeviceName(lthread); - unsigned int iface_max_packet_size = GetIfaceMaxPacketSize(live_dev); + char dev[32]; + (void)strlcpy(dev, live_dev, sizeof(dev)); + + if (strip_trailing_plus) { + size_t len = strlen(dev); + if (len && dev[len-1] == '+') { + dev[len-1] = '\0'; + } + } + + unsigned int iface_max_packet_size = GetIfaceMaxPacketSize(dev); if (iface_max_packet_size > default_packet_size) default_packet_size = iface_max_packet_size; } From 36e4126227f6ca0695ec8b9553961e536d1dc816 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 5 Jun 2016 00:48:38 +0200 Subject: [PATCH 1520/2553] detect-filemagic: fix heap-use-after-free This fixes the heap-use-after-free issue with sm being freed without being removed from the signature (s) list. Move the protocol check for rules with filemagic before the alloc and make the error log more precise. --- src/detect-filemagic.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 6ca7b6cd43ee..26fcd44390b6 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -338,6 +338,11 @@ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, char *st DetectFilemagicData *filemagic = NULL; SigMatch *sm = NULL; + if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rules with filemagic need to have protocol set to http or smtp."); + goto error; + } + filemagic = DetectFilemagicParse(str); if (filemagic == NULL) goto error; @@ -359,11 +364,6 @@ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, char *st SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - if (s->alproto == ALPROTO_HTTP) { AppLayerHtpNeedFileInspection(); } From 439b62fe69e3651083902151ccfc6a7b97acc4bc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 31 Mar 2016 21:12:57 +0200 Subject: [PATCH 1521/2553] configure: cleanup configure output Don't present missing spatch as a warning. Remove verbose libnet warnings as well. --- configure.ac | 54 ++++++++++------------------------------------------ 1 file changed, 10 insertions(+), 44 deletions(-) diff --git a/configure.ac b/configure.ac index 47ab3e164aaf..e85ddfa599bf 100644 --- a/configure.ac +++ b/configure.ac @@ -11,32 +11,6 @@ AC_PROG_LIBTOOL PKG_PROG_PKG_CONFIG(0.21) # 0.21 is the CentOS 5.11 version - AC_DEFUN([FAIL_MESSAGE],[ - echo - echo - echo "**********************************************" - echo " ERROR: unable to find" $1 - echo " checked in the following places" - for i in `echo $2`; do - echo " $i" - done - echo "**********************************************" - echo - exit 1 - ]) - - AC_DEFUN([LIBNET_FAIL_WARN],[ - echo - echo "*************************************************************************" - echo " Warning! libnet version 1.1.x could not be found in " $1 - echo " Reject keywords will not be supported." - echo " If you require reject support, please install libnet 1.1.x. " - echo " If libnet is not installed in a non-standard location please use the" - echo " --with-libnet-includes and --with-libnet-libraries configure options" - echo "*************************************************************************" - echo - ]) - dnl Taken from https://llvm.org/svn/llvm-project/llvm/trunk/autoconf/configure.ac dnl check if we compile using clang or gcc. On some systems the gcc binary is dnl is actually clang, so do a compile test. @@ -453,10 +427,6 @@ AS_IF([test "x$enable_coccinelle" = "xyes"], [ AC_PATH_PROG(HAVE_COCCINELLE_CONFIG, spatch, "no") if test "$HAVE_COCCINELLE_CONFIG" = "no"; then - echo " Warning! spatch not found, you will not be " - echo " able to run code checking with coccinelle " - echo " get it from http://coccinelle.lip6.fr " - echo " or install from your distribution " enable_coccinelle=no fi ]) @@ -999,14 +969,13 @@ fi done + enable_libnet="no" AC_MSG_CHECKING(for libnet.h version 1.1.x) if test "$LIBNET_INC_DIR" != ""; then LIBNET_VER=`grep LIBNET_VERSION $LIBNET_INC_DIR/libnet.h | grep '1.[[12]]' | sed 's/[[^"]]*"\([[^"]]*\).*/\1/'` if test -z "$LIBNET_VER" ; then AC_MSG_RESULT(no) - LIBNET_DETECT_FAIL="yes" - LIBNET_FAIL_WARN($libnet_dir) else AC_MSG_RESULT(yes) fi @@ -1023,12 +992,7 @@ AC_DEFINE([__BSD_SOURCE],[1],(bsd source)) AC_DEFINE([__FAVOR_BSD],[1],(favor bsd)) AC_DEFINE([HAVE_NET_ETHERNET_H],[1],(ethernet.h)) - else - #if we displayed a warning already no reason to do it again. - if test "$LIBNET_DETECT_FAIL" = "no"; then - LIBNET_DETECT_FAIL="yes" - LIBNET_FAIL_WARN($libnet_dir) - fi + enable_libnet="yes" fi # see if we have the patched libnet 1.1 @@ -1036,7 +1000,7 @@ # # To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work # see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful - if test "$LIBNET_DETECT_FAIL" = "no"; then + if test "$enable_libnet" = "yes"; then LLIBNET="" TMPLIBS="${LIBS}" AC_CHECK_LIB(net, libnet_build_icmpv6_unreach,, LLIBNET="no") @@ -1056,8 +1020,7 @@ [AC_DEFINE([HAVE_LIBNET_CAPABILITIES],[1], (libnet_have_capabilities_patch))]) fi else - LIBNET_DETECT_FAIL="yes" - LIBNET_FAIL_WARN($libnet_dir) + AC_MSG_RESULT(no) fi # libpcap @@ -1988,15 +1951,18 @@ SURICATA_BUILD_CONF="Suricata Configuration: Old barnyard2 support: ${enable_old_barnyard2} CUDA enabled: ${enable_cuda} Hyperscan support: ${enable_hyperscan} + Libnet support: ${enable_libnet} Suricatasc install: ${enable_python} - Unit tests enabled: ${enable_unittests} - Debug output enabled: ${enable_debug} - Debug validation enabled: ${enable_debug_validation} Profiling enabled: ${enable_profiling} Profiling locks enabled: ${enable_profiling_locks} + +Development settings: Coccinelle / spatch: ${enable_coccinelle} + Unit tests enabled: ${enable_unittests} + Debug output enabled: ${enable_debug} + Debug validation enabled: ${enable_debug_validation} Generic build parameters: Installation prefix: ${prefix} From b313f8ca7b98f8739f5f4f6113070a26a4406f1f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 26 Feb 2016 14:00:00 +0100 Subject: [PATCH 1522/2553] http: update compression mismatch test --- src/detect-engine-hsbd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index bf980bd9bb65..ab22826e6224 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -3339,7 +3339,7 @@ static int DetectEngineHttpServerBodyTest22(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { - printf("sid 1 matched but shouldn't have\n"); + printf("sid 1 matched but shouldn't have: "); goto end; } @@ -3353,8 +3353,8 @@ static int DetectEngineHttpServerBodyTest22(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 should have matched: "); goto end; } From ed7dc0c6b3eb2967ff46913f5662654adc2d3885 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Jul 2015 13:43:59 +0200 Subject: [PATCH 1523/2553] unittest: minor cleanup --- src/detect-engine-hsbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index ab22826e6224..18fba7010a9b 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -3345,7 +3345,7 @@ static int DetectEngineHttpServerBodyTest22(void) r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + printf("toserver chunk 2 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } From 5ec885e451860ed5cfeaa3a696cd8a26ba62e703 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Jul 2015 16:47:25 +0200 Subject: [PATCH 1524/2553] http: set of response body decompress limit This is a per personality setting. --- configure.ac | 5 ++++- src/app-layer-htp.c | 13 +++++++++++++ suricata.yaml.in | 6 ++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index e85ddfa599bf..f43316d57f9f 100644 --- a/configure.ac +++ b/configure.ac @@ -1240,6 +1240,7 @@ # check for htp_tx_get_response_headers_raw AC_CHECK_LIB([htp], [htp_tx_get_response_headers_raw],AC_DEFINE_UNQUOTED([HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW],[1],[Found htp_tx_get_response_headers_raw in libhtp]) ,,[-lhtp]) AC_CHECK_LIB([htp], [htp_decode_query_inplace],AC_DEFINE_UNQUOTED([HAVE_HTP_DECODE_QUERY_INPLACE],[1],[Found htp_decode_query_inplace function in libhtp]) ,,[-lhtp]) + AC_CHECK_LIB([htp], [htp_config_set_response_decompression_layer_limit],AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT],[1],[Found htp_config_set_response_decompression_layer_limit function in libhtp]) ,,[-lhtp]) AC_EGREP_HEADER(htp_config_set_path_decode_u_encoding, htp/htp.h, AC_DEFINE_UNQUOTED([HAVE_HTP_SET_PATH_DECODE_U_ENCODING],[1],[Found usable htp_config_set_path_decode_u_encoding function in libhtp]) ) ]) @@ -1259,10 +1260,12 @@ AC_DEFINE_UNQUOTED([HAVE_HTP_URI_NORMALIZE_HOOK],[1],[Assuming htp_config_register_request_uri_normalize function in bundled libhtp]) AC_DEFINE_UNQUOTED([HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW],[1],[Assuming htp_tx_get_response_headers_raw function in bundled libhtp]) AC_DEFINE_UNQUOTED([HAVE_HTP_DECODE_QUERY_INPLACE],[1],[Assuming htp_decode_query_inplace function in bundled libhtp]) + # enable when libhtp has been updated + AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT],[1],[Assuming htp_config_set_response_decompression_layer_limit function in bundled libhtp]) else echo echo " ERROR: Libhtp is not bundled. Get libhtp by doing:" - echo " git clone https://github.com/ironbee/libhtp" + echo " git clone https://github.com/OISF/libhtp" echo " Then re-run Suricata's autogen.sh and configure script." echo " Or, if libhtp is installed in a different location," echo " pass --enable-non-bundled-htp to Suricata's configure script." diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 950f472bf631..d87abd18fbaa 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2348,6 +2348,19 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, exit(EXIT_FAILURE); } + } else if (strcasecmp("response-body-decompress-layer-limit", p->name) == 0) { + uint32_t value = 2; + if (ParseSizeStringU32(p->val, &value) < 0) { + SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-inspect-window " + "from conf file - %s. Killing engine", p->val); + exit(EXIT_FAILURE); + } +#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT + htp_config_set_response_decompression_layer_limit(cfg_prec->cfg, value); +#else + SCLogWarning(SC_WARN_OUTDATED_LIBHTP, "can't set response-body-decompress-layer-limit " + "to %u, libhtp version too old", value); +#endif } else if (strcasecmp("path-convert-backslash-separators", p->name) == 0) { htp_config_set_backslash_convert_slashes(cfg_prec->cfg, HTP_DECODER_URL_PATH, diff --git a/suricata.yaml.in b/suricata.yaml.in index a1cacd48c879..c0912cddeebc 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -721,6 +721,9 @@ app-layer: # by file_data, http_server_body & pcre /Q option. # double-decode-path: Double decode path section of the URI # double-decode-query: Double decode query section of the URI + # response-body-decompress-layer-limit: + # Limit to how many layers of compression will be + # decompressed. Defaults to 2. # # server-config: List of server configurations to use if address matches # address: List of ip addresses or networks for this block @@ -766,6 +769,9 @@ app-layer: response-body-minimal-inspect-size: 40kb response-body-inspect-window: 16kb + # response body decompression (0 disables) + response-body-decompress-layer-limit: 2 + # auto will use http-body-inline mode in IPS mode, yes or no set it statically http-body-inline: auto From e76b334f8dc855c021ba0e567229adf242c615b6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 30 May 2016 14:55:34 +0200 Subject: [PATCH 1525/2553] http body: fix compression tests --- src/detect-engine-hsbd.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 18fba7010a9b..100134314e30 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -3087,10 +3087,9 @@ static int DetectEngineHttpServerBodyTest20(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } +#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT + FAIL_IF(!(PacketAlertCheck(p2, 1))); +#endif result = 1; @@ -3219,10 +3218,9 @@ static int DetectEngineHttpServerBodyTest21(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } +#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT + FAIL_IF(!(PacketAlertCheck(p2, 1))); +#endif result = 1; @@ -3353,10 +3351,9 @@ static int DetectEngineHttpServerBodyTest22(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!(PacketAlertCheck(p2, 1))) { - printf("sid 1 should have matched: "); - goto end; - } +#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT + FAIL_IF(!(PacketAlertCheck(p2, 1))); +#endif result = 1; From d4f84455640a3af9fd86c325627ad5aef305a269 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 7 Jun 2016 14:56:13 +0200 Subject: [PATCH 1526/2553] Update Changelog for 3.1RC1 --- ChangeLog | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/ChangeLog b/ChangeLog index 517d742370c2..6fefafa68e19 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +3.1RC1 -- 2016-06-07 + +Feature #681: Implement TPACKET_V3 support in AF_PACKET +Feature #1134: tls: server name rule keyword +Feature #1343: OOBE -1- increasing the default stream.memcap and stream.reassembly.memcap values +Feature #1344: OOBE -2- decreasing the default flow-timeouts (at least for TCP) +Feature #1563: dns: log sshfp records +Feature #1760: Unit tests: Don't register return value, use 1 for success, 0 for failure. +Feature #1761: Unit tests: Provide macros for clean test failures. +Feature #1762: default to AF_PACKET for -i if available +Feature #1785: hyperscan spm integration +Feature #1789: hyperscan mpm: enable by default +Feature #1797: netmap: implement 'threads: auto' +Feature #1798: netmap: warn about NIC offloading on FreeBSD +Feature #1800: update bundled libhtp to 0.5.20 +Feature #1801: reduce info level verbosity +Feature #1802: yaml: improve default layout +Feature #1803: reimplement rule grouping +Bug #1202: detect-engine profile medium consumes more memory than detect-engine profile high +Bug #1289: MPM b2gm matcher has questionable code +Bug #1487: Configuration parser depends on key ordering +Bug #1524: Potential Thread Name issues due to RHEL7 Interface Naming Contentions +Bug #1584: Rule keywords conflict will cause Suricata restart itself in loop +Bug #1665: Default maximum packet size is insufficient when VLAN tags are present (and not stripped) +Bug #1714: Kernel panic on application exit with netmap Suricata 3.0 stable +Bug #1746: deadlock with autofp and --disable-detection +Bug #1764: app-layer-modbus: AddressSanitizer error (segmentation fault) +Bug #1768: packet processing threads doubled +Bug #1773: smtp: not all attachments inspected in all cases +Bug #1786: spm crash on rule reload +Bug #1792: dns-json-log produces no output +Optimization #563: pmq optimization -- remove patter_id_array +Optimization #1037: Optimize TCP Option storage +Optimization #1418: lockless flow handling during capture (autofp) +Optimization #1784: reduce storage size of IPv4 options and IPv6 ext hdrs + 3.0.1 -- 2016-04-04 Feature #1704: hyperscan mpm integration From b673e1441110a4624c708cb40f94004f6071c0ae Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 7 Jun 2016 18:29:42 +0200 Subject: [PATCH 1527/2553] afl: fix various --afl-* options --- src/suricata.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index 5482002a5497..198420b3e602 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1384,26 +1384,41 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) } #ifdef AFLFUZZ_RULES } else if(strcmp((long_opts[option_index]).name, "afl-rules") == 0) { + MpmTableSetup(); + SpmTableSetup(); exit(RuleParseDataFromFile(optarg)); #endif #ifdef AFLFUZZ_APPLAYER } else if(strcmp((long_opts[option_index]).name, "afl-http-request") == 0) { //printf("arg: //%s\n", optarg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterHTPParsers(); exit(AppLayerParserRequestFromFile(ALPROTO_HTTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-http") == 0) { //printf("arg: //%s\n", optarg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterHTPParsers(); exit(AppLayerParserFromFile(ALPROTO_HTTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-tls-request") == 0) { //printf("arg: //%s\n", optarg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); RegisterSSLParsers(); exit(AppLayerParserRequestFromFile(ALPROTO_TLS, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-tls") == 0) { //printf("arg: //%s\n", optarg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSSLParsers(); exit(AppLayerParserFromFile(ALPROTO_TLS, optarg)); @@ -1420,20 +1435,33 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) } else if(strcmp((long_opts[option_index]).name, "afl-ssh-request") == 0) { //printf("arg: //%s\n", optarg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); RegisterSSHParsers(); exit(AppLayerParserRequestFromFile(ALPROTO_SSH, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-ssh") == 0) { //printf("arg: //%s\n", optarg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSSHParsers(); exit(AppLayerParserFromFile(ALPROTO_SSH, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-ftp-request") == 0) { //printf("arg: //%s\n", optarg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); RegisterFTPParsers(); exit(AppLayerParserRequestFromFile(ALPROTO_FTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-ftp") == 0) { //printf("arg: //%s\n", optarg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterFTPParsers(); exit(AppLayerParserFromFile(ALPROTO_FTP, optarg)); @@ -1441,22 +1469,32 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) } else if(strcmp((long_opts[option_index]).name, "afl-smtp-request") == 0) { //printf("arg: //%s\n", optarg); MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSMTPParsers(); exit(AppLayerParserRequestFromFile(ALPROTO_SMTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-smtp") == 0) { //printf("arg: //%s\n", optarg); MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSMTPParsers(); exit(AppLayerParserFromFile(ALPROTO_SMTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-smb-request") == 0) { //printf("arg: //%s\n", optarg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); RegisterSMBParsers(); exit(AppLayerParserRequestFromFile(ALPROTO_SMB, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-smb") == 0) { //printf("arg: //%s\n", optarg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSMBParsers(); exit(AppLayerParserFromFile(ALPROTO_SMB, optarg)); @@ -1481,6 +1519,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) } else if(strcmp((long_opts[option_index]).name, "afl-decoder-ppp") == 0) { StatsInit(); MpmTableSetup(); + SpmTableSetup(); AppLayerProtoDetectSetup(); DefragInit(); FlowInitConfig(FLOW_QUIET); From 5c974f92a8aafb2d4c447e54259c400c14bec037 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Jun 2016 08:17:13 +0200 Subject: [PATCH 1528/2553] livedev: shorten devname at registration --- src/respond-reject-libnet11.c | 8 ++++---- src/runmode-af-packet.c | 4 ++-- src/runmode-netmap.c | 4 ++-- src/source-mpipe.c | 4 ++-- src/suricata.c | 2 +- src/util-device.c | 26 +++++++++++++++++++++----- src/util-device.h | 9 ++++++--- src/util-runmodes.c | 24 +++++------------------- 8 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/respond-reject-libnet11.c b/src/respond-reject-libnet11.c index b27b74e9d98f..c52e340c5b65 100644 --- a/src/respond-reject-libnet11.c +++ b/src/respond-reject-libnet11.c @@ -79,7 +79,7 @@ int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir) libnet_t *c; /* libnet context */ char ebuf[LIBNET_ERRBUF_SIZE]; int result; - char *devname = NULL; + const char *devname = NULL; /* fill in struct defaults */ lpacket.ttl = 0; @@ -203,7 +203,7 @@ int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir) libnet_t *c; /* libnet context */ char ebuf[LIBNET_ERRBUF_SIZE]; int result; - char *devname = NULL; + const char *devname = NULL; /* fill in struct defaults */ lpacket.ttl = 0; @@ -291,7 +291,7 @@ int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir) libnet_t *c; /* libnet context */ char ebuf[LIBNET_ERRBUF_SIZE]; int result; - char *devname = NULL; + const char *devname = NULL; /* fill in struct defaults */ lpacket.ttl = 0; @@ -414,7 +414,7 @@ int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir) libnet_t *c; /* libnet context */ char ebuf[LIBNET_ERRBUF_SIZE]; int result; - char *devname = NULL; + const char *devname = NULL; /* fill in struct defaults */ lpacket.ttl = 0; diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 34b1a3872b3a..f485f5b23c2f 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -479,7 +479,7 @@ int AFPRunModeIsIPS() if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default"); for (ldev = 0; ldev < nlive; ldev++) { - char *live_dev = LiveGetDeviceName(ldev); + const char *live_dev = LiveGetDeviceName(ldev); if (live_dev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); return 0; @@ -509,7 +509,7 @@ int AFPRunModeIsIPS() if (has_ids && has_ips) { SCLogInfo("AF_PACKET mode using IPS and IDS mode"); for (ldev = 0; ldev < nlive; ldev++) { - char *live_dev = LiveGetDeviceName(ldev); + const char *live_dev = LiveGetDeviceName(ldev); if (live_dev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); return 0; diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 8403d0843ebf..e476dd04033e 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -300,7 +300,7 @@ int NetmapRunModeIsIPS() if_default = ConfNodeLookupKeyValue(netmap_node, "interface", "default"); for (ldev = 0; ldev < nlive; ldev++) { - char *live_dev = LiveGetDeviceName(ldev); + const char *live_dev = LiveGetDeviceName(ldev); if (live_dev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); return 0; @@ -330,7 +330,7 @@ int NetmapRunModeIsIPS() if (has_ids && has_ips) { SCLogInfo("Netmap mode using IPS and IDS mode"); for (ldev = 0; ldev < nlive; ldev++) { - char *live_dev = LiveGetDeviceName(ldev); + const char *live_dev = LiveGetDeviceName(ldev); if (live_dev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); return 0; diff --git a/src/source-mpipe.c b/src/source-mpipe.c index d304b4a8b108..0310115a0401 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -895,8 +895,8 @@ TmEcode ReceiveMpipeThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->tv = tv; int result; - char *link_name = (char *)initdata; - + const char *link_name = (char *)initdata; + MpipeRegisterPerfCounters(ptv, tv); *data = (void *)ptv; diff --git a/src/suricata.c b/src/suricata.c index 198420b3e602..a6e3e1f7b1a0 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2233,7 +2233,7 @@ static int ConfigGetCaptureValue(SCInstance *suri) case RUNMODE_PFRING: nlive = LiveGetDeviceCount(); for (lthread = 0; lthread < nlive; lthread++) { - char *live_dev = LiveGetDeviceName(lthread); + const char *live_dev = LiveGetDeviceName(lthread); char dev[32]; (void)strlcpy(dev, live_dev, sizeof(dev)); diff --git a/src/util-device.c b/src/util-device.c index 409f8732cc62..582746ac126f 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2012 Open Information Security Foundation +/* Copyright (C) 2011-2016 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 @@ -36,6 +36,9 @@ static TAILQ_HEAD(, LiveDevice_) live_devices = /** if set to 0 when we don't have real devices */ static int live_devices_stats = 1; +static int LiveSafeDeviceName(const char *devname, + char *newdevname, size_t destlen); + /** * \brief Add a pcap device for monitoring * @@ -56,6 +59,13 @@ int LiveRegisterDevice(const char *dev) SCFree(pd); return -1; } + /* create a short version to be used in thread names */ + if (strlen(pd->dev) > MAX_DEVNAME) { + LiveSafeDeviceName(pd->dev, pd->dev_short, sizeof(pd->dev_short)); + } else { + (void)strlcpy(pd->dev_short, pd->dev, sizeof(pd->dev_short)); + } + SC_ATOMIC_INIT(pd->pkts); SC_ATOMIC_INIT(pd->drop); SC_ATOMIC_INIT(pd->invalid_checksums); @@ -91,7 +101,7 @@ int LiveGetDeviceCount(void) * \retval ptr pointer to the string containing the device * \retval NULL on error */ -char *LiveGetDeviceName(int number) +const char *LiveGetDeviceName(int number) { int i = 0; LiveDevice *pd; @@ -107,14 +117,14 @@ char *LiveGetDeviceName(int number) return NULL; } -/** +/** \internal * \brief Shorten a device name that is to long * * \param device name from config and destination for modified * * \retval None, is added to destination char *newdevname */ -int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen) +static int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen) { size_t devnamelen = strlen(devname); @@ -192,7 +202,13 @@ LiveDevice *LiveGetDevice(const char *name) return NULL; } - +const char *LiveGetShortName(const char *dev) +{ + LiveDevice *live_dev = LiveGetDevice(dev); + if (live_dev == NULL) + return NULL; + return live_dev->dev_short; +} int LiveBuildDeviceList(const char *runmode) { diff --git a/src/util-device.h b/src/util-device.h index a6f78dd50b1a..ca3d91331a35 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2012 Open Information Security Foundation +/* Copyright (C) 2011-2016 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 @@ -21,9 +21,12 @@ #include "queue.h" #include "unix-manager.h" +#define MAX_DEVNAME 10 + /** storage for live device names */ typedef struct LiveDevice_ { char *dev; /**< the device (e.g. "eth0") */ + char dev_short[MAX_DEVNAME + 1]; int ignore_checksum; SC_ATOMIC_DECLARE(uint64_t, pkts); SC_ATOMIC_DECLARE(uint64_t, drop); @@ -34,9 +37,9 @@ typedef struct LiveDevice_ { int LiveRegisterDevice(const char *dev); int LiveGetDeviceCount(void); -char *LiveGetDeviceName(int number); -int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen); +const char *LiveGetDeviceName(int number); LiveDevice *LiveGetDevice(const char *dev); +const char *LiveGetShortName(const char *dev); int LiveBuildDeviceList(const char *base); void LiveDeviceHasNoStats(void); int LiveDeviceListClean(void); diff --git a/src/util-runmodes.c b/src/util-runmodes.c index d2789f0f47e2..8f01983ab41b 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -169,9 +169,8 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, int lthread; for (lthread = 0; lthread < nlive; lthread++) { - char *live_dev = LiveGetDeviceName(lthread); - char visual_devname[11] = ""; - int shortening_result; + const char *live_dev = LiveGetDeviceName(lthread); + const char *visual_devname = LiveGetShortName(live_dev); void *aconf; int threads_count; @@ -190,12 +189,6 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, threads_count = ModThreadsCount(aconf); for (thread = 0; thread < threads_count; thread++) { - shortening_result = LiveSafeDeviceName(live_dev, visual_devname, sizeof(visual_devname)); - if (shortening_result != 0) { - SCLogError(SC_ERR_INVALID_VALUE, "Could not shorten long devicename: %s", live_dev); - exit(EXIT_FAILURE); - } - snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, thread+1, visual_devname); @@ -298,16 +291,9 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod /* create the threads */ for (thread = 0; thread < threads_count; thread++) { char tname[TM_THREAD_NAME_MAX]; - char visual_devname[11] = ""; - int shortening_result; ThreadVars *tv = NULL; TmModule *tm_module = NULL; - - shortening_result = LiveSafeDeviceName(live_dev, visual_devname, sizeof(visual_devname)); - if (shortening_result != 0) { - SCLogError(SC_ERR_INVALID_VALUE, "Could not shorten long devicename: %s", live_dev); - exit(EXIT_FAILURE); - } + const char *visual_devname = LiveGetShortName(live_dev); if (single_mode) { snprintf(tname, sizeof(tname), "%s#01-%s", thread_name, visual_devname); @@ -447,7 +433,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, char tname[TM_THREAD_NAME_MAX]; char qname[TM_QUEUE_NAME_MAX]; TmModule *tm_module ; - char *cur_queue = NULL; + const char *cur_queue = NULL; char *queues = NULL; int thread; @@ -593,7 +579,7 @@ int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, char tname[TM_THREAD_NAME_MAX]; ThreadVars *tv = NULL; TmModule *tm_module = NULL; - char *cur_queue = NULL; + const char *cur_queue = NULL; int nqueue = LiveGetDeviceCount(); From a88359dcf099b16c2085f11c0159160c6835e88a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Jun 2016 08:57:29 +0200 Subject: [PATCH 1529/2553] detect: get proper legacy custom values. Issue #1804 --- src/detect-engine.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index 12dfb499733d..3d35fb08dece 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1105,10 +1105,18 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) if (de_ctx_custom != NULL) { TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { if (strcmp(opt->val, "custom-values") == 0) { + if (max_uniq_toclient_groups_str == NULL) { + max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue + (opt->head.tqh_first, "toclient-sp-groups"); + } if (max_uniq_toclient_groups_str == NULL) { max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue (opt->head.tqh_first, "toclient-groups"); } + if (max_uniq_toserver_groups_str == NULL) { + max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue + (opt->head.tqh_first, "toserver-dp-groups"); + } if (max_uniq_toserver_groups_str == NULL) { max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue (opt->head.tqh_first, "toserver-groups"); @@ -1131,6 +1139,8 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) } else { de_ctx->max_uniq_toclient_groups = 20; } + SCLogConfig("toclient-groups %u", de_ctx->max_uniq_toclient_groups); + if (max_uniq_toserver_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_groups, 10, strlen(max_uniq_toserver_groups_str), @@ -1146,6 +1156,7 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) } else { de_ctx->max_uniq_toserver_groups = 40; } + SCLogConfig("toserver-groups %u", de_ctx->max_uniq_toserver_groups); break; /* Default (or no config provided) is profile medium */ From 9119007d007de07a61075f4d466926b1698e25cf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Jun 2016 13:52:34 +0200 Subject: [PATCH 1530/2553] pfring: no longer link against rt and numa libs --- configure.ac | 2 -- 1 file changed, 2 deletions(-) diff --git a/configure.ac b/configure.ac index f43316d57f9f..91bb331aef52 100644 --- a/configure.ac +++ b/configure.ac @@ -1134,8 +1134,6 @@ echo exit 1 fi - else - LIBS="${LIBS} -lrt -lnuma" fi else if test "x$enable_pfring" = "xyes"; then From 66346e463211044d82bd80e943bd0cfc5b8c7bd2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Jun 2016 16:58:55 +0200 Subject: [PATCH 1531/2553] libnet: work around older libnet type difference Older libnet 1.1.x have a non-const type for libnet_init's dev argument. --- configure.ac | 28 ++++++++++++++++++++++++++++ src/respond-reject-libnet11.c | 14 ++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 91bb331aef52..d553ff3532e7 100644 --- a/configure.ac +++ b/configure.ac @@ -1018,6 +1018,34 @@ [], [AC_DEFINE([HAVE_LIBNET_CAPABILITIES],[1], (libnet_have_capabilities_patch))], [AC_DEFINE([HAVE_LIBNET_CAPABILITIES],[1], (libnet_have_capabilities_patch))]) + + + # check if the argument to libnet_init is char* or const char* + AC_MSG_CHECKING([libnet_init dev type]) + STORECFLAGS="${CFLAGS}" + if test `basename $CC` = "clang"; then + CFLAGS="${CFLAGS} -Werror=incompatible-pointer-types" + else + CFLAGS="${CFLAGS} -Werror" + fi + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [ + #include + #include + ], + [[ + const char dev[32] = ""; + char ebuf[LIBNET_ERRBUF_SIZE]; + (void)libnet_init(LIBNET_LINK, dev, ebuf); + ]])], + [libnet_init_const="yes"], + [libnet_init_const="no"]) + AC_MSG_RESULT($libnet_init_const) + if test "x$libnet_init_const" = "xyes"; then + AC_DEFINE([HAVE_LIBNET_INIT_CONST], [1], [libnet_init takes const argument]) + fi + CFLAGS="${STORECFLAGS}" fi else AC_MSG_RESULT(no) diff --git a/src/respond-reject-libnet11.c b/src/respond-reject-libnet11.c index c52e340c5b65..ae238db873dd 100644 --- a/src/respond-reject-libnet11.c +++ b/src/respond-reject-libnet11.c @@ -51,6 +51,12 @@ #ifdef HAVE_LIBNET11 +#ifndef HAVE_LIBNET_INIT_CONST +#define LIBNET_INIT_CAST (char *) +#else +#define LIBNET_INIT_CAST +#endif + /** set to true in main if we're setting caps. We need it here if we're using * reject rules as libnet 1.1 is not compatible with caps. */ extern int sc_set_caps; @@ -91,7 +97,7 @@ int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir) devname = p->livedev->dev; SCLogDebug("Will emit reject packet on dev %s", devname); } - if ((c = libnet_init(LIBNET_RAW4, devname, ebuf)) == NULL) { + if ((c = libnet_init(LIBNET_RAW4, LIBNET_INIT_CAST devname, ebuf)) == NULL) { SCLogError(SC_ERR_LIBNET_INIT,"libnet_init failed: %s", ebuf); return 1; } @@ -216,7 +222,7 @@ int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir) if (IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode) && (p->livedev)) { devname = p->livedev->dev; } - if ((c = libnet_init(LIBNET_RAW4, devname, ebuf)) == NULL) { + if ((c = libnet_init(LIBNET_RAW4, LIBNET_INIT_CAST devname, ebuf)) == NULL) { SCLogError(SC_ERR_LIBNET_INIT,"libnet_inint failed: %s", ebuf); return 1; } @@ -302,7 +308,7 @@ int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir) if (IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode) && (p->livedev)) { devname = p->livedev->dev; } - if ((c = libnet_init(LIBNET_RAW6, devname, ebuf)) == NULL) { + if ((c = libnet_init(LIBNET_RAW6, LIBNET_INIT_CAST devname, ebuf)) == NULL) { SCLogError(SC_ERR_LIBNET_INIT,"libnet_init failed: %s", ebuf); return 1; } @@ -428,7 +434,7 @@ int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir) if (IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode) && (p->livedev)) { devname = p->livedev->dev; } - if ((c = libnet_init(LIBNET_RAW6, devname, ebuf)) == NULL) { + if ((c = libnet_init(LIBNET_RAW6, LIBNET_INIT_CAST devname, ebuf)) == NULL) { SCLogError(SC_ERR_LIBNET_INIT,"libnet_inint failed: %s", ebuf); return 1; } From f7124b1149760c44673cf87e89c148ffccf8410b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Jun 2016 09:32:16 +0200 Subject: [PATCH 1532/2553] afpacket: disable tpacket-v3 by default It's still considered experimental at this point. --- src/runmode-af-packet.c | 40 +++++++++++++++++++++------------------- suricata.yaml.in | 6 +++--- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index f485f5b23c2f..1696834c12bc 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -142,7 +142,7 @@ void *ParseAFPConfig(const char *iface) aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; aconf->DerefFunc = AFPDerefConfig; - aconf->flags = AFP_RING_MODE|AFP_TPACKET_V3; + aconf->flags = AFP_RING_MODE; aconf->bpf_filter = NULL; aconf->out_iface = NULL; aconf->copy_mode = AFP_COPY_MODE_NONE; @@ -199,15 +199,11 @@ void *ParseAFPConfig(const char *iface) } if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-mmap", (int *)&boolval) == 1) { - if (boolval) { - aconf->flags |= AFP_RING_MODE; - } else { + if (!boolval) { SCLogConfig("Disabling mmaped capture on iface %s", aconf->iface); - aconf->flags &= ~AFP_RING_MODE; + aconf->flags &= ~(AFP_RING_MODE|AFP_TPACKET_V3); } - } else { - aconf->flags |= AFP_RING_MODE; } if (aconf->flags & AFP_RING_MODE) { @@ -218,25 +214,31 @@ void *ParseAFPConfig(const char *iface) aconf->iface); aconf->flags |= AFP_MMAP_LOCKED; } - (void)ConfGetChildValueBoolWithDefault(if_root, if_default, - "tpacket-v3", (int *)&boolval); - if (boolval) { - if (strcasecmp(RunmodeGetActive(), "workers") == 0) { + + if (ConfGetChildValueBoolWithDefault(if_root, if_default, + "tpacket-v3", (int *)&boolval) == 1) + { + if (boolval) { + if (strcasecmp(RunmodeGetActive(), "workers") == 0) { #ifdef HAVE_TPACKET_V3 - SCLogConfig("Enabling tpacket v3 capture on iface %s", - aconf->iface); - aconf->flags |= AFP_TPACKET_V3; + SCLogConfig("Enabling tpacket v3 capture on iface %s", + aconf->iface); + aconf->flags |= AFP_TPACKET_V3; #else - SCLogNotice("System too old for tpacket v3 switching to v2"); - aconf->flags &= ~AFP_TPACKET_V3; + SCLogNotice("System too old for tpacket v3 switching to v2"); + aconf->flags &= ~AFP_TPACKET_V3; #endif + } else { + SCLogWarning(SC_ERR_RUNMODE, + "tpacket v3 is only implemented for 'workers' runmode." + " Switching to tpacket v2."); + aconf->flags &= ~AFP_TPACKET_V3; + } } else { - SCLogError(SC_ERR_RUNMODE, - "tpacket v3 is only implemented for 'workers' runmode." - " Switching to tpacket v2."); aconf->flags &= ~AFP_TPACKET_V3; } } + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "use-emergency-flush", (int *)&boolval); if (boolval) { diff --git a/suricata.yaml.in b/suricata.yaml.in index c0912cddeebc..5d87be99026c 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -514,8 +514,8 @@ af-packet: # Lock memory map to avoid it goes to swap. Be careful that over suscribing could lock # your system #mmap-locked: yes - # Use tpacket_v3, capture mode, only active if user-mmap is true - tpacket-v3: yes + # Use experimental tpacket_v3 capture mode, only active if use-mmap is true + #tpacket-v3: yes # Ring size will be computed with respect to max_pending_packets and number # of threads. You can set manually the ring size in number of packets by setting # the following value. If you are using flow cluster-type and have really network @@ -563,7 +563,7 @@ af-packet: #threads: auto #use-mmap: no #rollover: yes - tpacket-v3: yes + #tpacket-v3: yes # Cross platform libpcap capture support pcap: From d0baa83d2b80127b314ca13b03ccd5222707afc1 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Wed, 15 Jun 2016 23:44:34 +0200 Subject: [PATCH 1533/2553] util-runmode: pass initdata to runmode workers for nfqueue The VerdictNFQ was missing the initdata which results in a segfault within CaptureStatsSetup. This commit adds the passing of the initdata. --- src/util-runmodes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 8f01983ab41b..b7e8f09ccad3 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -629,7 +629,7 @@ int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, exit(EXIT_FAILURE); } - TmSlotSetFuncAppend(tv, tm_module, NULL); + TmSlotSetFuncAppend(tv, tm_module, (void *) ConfigParser(i)); tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { From 0e9134930d4840de49295d65a5a2e7c81dd103ee Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Jun 2016 15:51:07 +0200 Subject: [PATCH 1534/2553] changelog: update for 3.1 and add missing 3.1rc1 tickets --- ChangeLog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6fefafa68e19..720abe0653b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +3.1 -- 2016-06-20 + +Bug #1589: Cannot run nfq in workers mode +Bug #1804: yaml: legacy detect-engine parsing custom values broken + 3.1RC1 -- 2016-06-07 Feature #681: Implement TPACKET_V3 support in AF_PACKET @@ -16,19 +21,23 @@ Feature #1800: update bundled libhtp to 0.5.20 Feature #1801: reduce info level verbosity Feature #1802: yaml: improve default layout Feature #1803: reimplement rule grouping +Bug #1078: 'Not" operator (!) in Variable causes extremely slow loading of Suricata Bug #1202: detect-engine profile medium consumes more memory than detect-engine profile high Bug #1289: MPM b2gm matcher has questionable code Bug #1487: Configuration parser depends on key ordering Bug #1524: Potential Thread Name issues due to RHEL7 Interface Naming Contentions Bug #1584: Rule keywords conflict will cause Suricata restart itself in loop +Bug #1606: [ERRCODE: SC_ERR_SYSCALL(50)] - Failure when trying to get MTU via ioctl: 6 Bug #1665: Default maximum packet size is insufficient when VLAN tags are present (and not stripped) Bug #1714: Kernel panic on application exit with netmap Suricata 3.0 stable Bug #1746: deadlock with autofp and --disable-detection Bug #1764: app-layer-modbus: AddressSanitizer error (segmentation fault) Bug #1768: packet processing threads doubled +Bug #1771: tls store memory leak Bug #1773: smtp: not all attachments inspected in all cases Bug #1786: spm crash on rule reload Bug #1792: dns-json-log produces no output +Bug #1795: Remove unused CPU affinity settings from suricata.yaml Optimization #563: pmq optimization -- remove patter_id_array Optimization #1037: Optimize TCP Option storage Optimization #1418: lockless flow handling during capture (autofp) From 6c7bf006b747bfc3edaedb489e65cdbf06e0b7e2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 11 Jun 2016 11:30:16 +0000 Subject: [PATCH 1535/2553] netmap: redo config parsing Normally we parse the config per interface only. But to properly setup the bridge, netmap also needs the config of it's peering interface. Instead of using a complicated peering scheme like in afpacket, simply parse the peers config too. --- src/runmode-netmap.c | 243 +++++++++++++++++++++---------------------- src/source-netmap.c | 51 ++++----- src/source-netmap.h | 27 +++-- 3 files changed, 163 insertions(+), 158 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index e476dd04033e..81c409c2835e 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -93,183 +93,178 @@ static void NetmapDerefConfig(void *conf) } } -/** -* \brief extract information from config file -* -* The returned structure will be freed by the thread init function. -* This is thus necessary to or copy the structure before giving it -* to thread or to reparse the file for each thread (and thus have -* new structure. -* -* \return a NetmapIfaceConfig corresponding to the interface name -*/ -static void *ParseNetmapConfig(const char *iface_name) +static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface, + ConfNode *if_root, ConfNode *if_default) { - char *threadsstr = NULL; - ConfNode *if_root; - ConfNode *if_default = NULL; - ConfNode *netmap_node; - char *tmpctype; - char *copymodestr; - int boolval; - char *bpf_filter = NULL; - char *out_iface = NULL; - - if (iface_name == NULL) { - return NULL; - } - - NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); - if (unlikely(aconf == NULL)) { - return NULL; - } - - memset(aconf, 0, sizeof(*aconf)); - aconf->DerefFunc = NetmapDerefConfig; - aconf->threads = 0; - aconf->promisc = 1; - aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; - aconf->copy_mode = NETMAP_COPY_MODE_NONE; - strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name)); - SC_ATOMIC_INIT(aconf->ref); - (void) SC_ATOMIC_ADD(aconf->ref, 1); - - strlcpy(aconf->iface, aconf->iface_name, sizeof(aconf->iface)); - if (aconf->iface[0]) { - size_t len = strlen(aconf->iface); - if (aconf->iface[len-1] == '+') { - aconf->iface[len-1] = '\0'; - aconf->iface_sw = 1; + ns->threads = 0; + ns->promisc = 1; + ns->checksum_mode = CHECKSUM_VALIDATION_AUTO; + ns->copy_mode = NETMAP_COPY_MODE_NONE; + + strlcpy(ns->iface, iface, sizeof(ns->iface)); + if (ns->iface[0]) { + size_t len = strlen(ns->iface); + if (ns->iface[len-1] == '+') { + ns->iface[len-1] = '\0'; + ns->sw_ring = 1; } } + char *bpf_filter = NULL; if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { - aconf->bpf_filter = bpf_filter; + ns->bpf_filter = bpf_filter; SCLogInfo("Going to use command-line provided bpf filter '%s'", - aconf->bpf_filter); + ns->bpf_filter); } } - /* Find initial node */ - netmap_node = ConfGetNode("netmap"); - if (netmap_node == NULL) { - SCLogInfo("Unable to find netmap config using default value"); - goto finalize; - } - - if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name); - - if_default = ConfFindDeviceConfig(netmap_node, "default"); - if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find netmap config for " - "interface \"%s\" or \"default\", using default value", - aconf->iface_name); + "interface \"%s\" or \"default\", using default values", + iface); goto finalize; - } /* If there is no setting for current interface use default one as main iface */ - if (if_root == NULL) { + } else if (if_root == NULL) { if_root = if_default; if_default = NULL; } + char *threadsstr = NULL; if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { - aconf->threads = 0; + ns->threads = 0; } else { if (strcmp(threadsstr, "auto") == 0) { - aconf->threads = 0; - } else { - aconf->threads = (uint8_t)atoi(threadsstr); - } - } - - if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { - if (strlen(out_iface) > 0) { - aconf->out_iface_name = out_iface; - } - } - - if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { - if (aconf->out_iface_name == NULL) { - SCLogInfo("Copy mode activated but no destination" - " iface. Disabling feature"); - } else if (strlen(copymodestr) <= 0) { - aconf->out_iface_name = NULL; - } else if (strcmp(copymodestr, "ips") == 0) { - SCLogInfo("Netmap IPS mode activated %s->%s", - aconf->iface_name, - aconf->out_iface_name); - aconf->copy_mode = NETMAP_COPY_MODE_IPS; - } else if (strcmp(copymodestr, "tap") == 0) { - SCLogInfo("Netmap TAP mode activated %s->%s", - aconf->iface_name, - aconf->out_iface_name); - aconf->copy_mode = NETMAP_COPY_MODE_TAP; + ns->threads = 0; } else { - SCLogInfo("Invalid mode (not in tap, ips)"); - } - } - - if (aconf->out_iface_name && aconf->out_iface_name[0]) { - strlcpy(aconf->out_iface, aconf->out_iface_name, - sizeof(aconf->out_iface)); - size_t len = strlen(aconf->out_iface); - if (aconf->out_iface[len-1] == '+') { - aconf->out_iface[len-1] = '\0'; - aconf->out_iface_sw = 1; + ns->threads = (uint8_t)atoi(threadsstr); } } /* load netmap bpf filter */ /* command line value has precedence */ - if (ConfGet("bpf-filter", &bpf_filter) != 1) { + if (ns->bpf_filter == NULL) { if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { - aconf->bpf_filter = bpf_filter; - SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter); + ns->bpf_filter = bpf_filter; + SCLogInfo("Going to use bpf filter %s", ns->bpf_filter); } } } + int boolval = 0; (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); if (boolval) { - SCLogInfo("Disabling promiscuous mode on iface %s", aconf->iface); - aconf->promisc = 0; + SCLogInfo("Disabling promiscuous mode on iface %s", ns->iface); + ns->promisc = 0; } - if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { + char *tmpctype; + if (ConfGetChildValueWithDefault(if_root, if_default, + "checksum-checks", &tmpctype) == 1) + { if (strcmp(tmpctype, "auto") == 0) { - aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; + ns->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (ConfValIsTrue(tmpctype)) { - aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; + ns->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (ConfValIsFalse(tmpctype)) { - aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; + ns->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { - SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface_name); + SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid value for " + "checksum-checks for %s", iface); + } + } + + char *copymodestr; + if (ConfGetChildValueWithDefault(if_root, if_default, + "copy-mode", ©modestr) == 1) + { + if (strcmp(copymodestr, "ips") == 0) { + ns->copy_mode = NETMAP_COPY_MODE_IPS; + } else if (strcmp(copymodestr, "tap") == 0) { + ns->copy_mode = NETMAP_COPY_MODE_TAP; + } else { + SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid copy-mode " + "(valid are tap, ips)"); } } finalize: - if (aconf->iface_sw) { + if (ns->sw_ring) { /* just one thread per interface supported */ - aconf->threads = 1; - } else if (aconf->threads == 0) { + ns->threads = 1; + } else if (ns->threads == 0) { /* As NetmapGetRSSCount is broken on Linux, first run * GetIfaceRSSQueuesNum. If that fails, run NetmapGetRSSCount */ - aconf->threads = GetIfaceRSSQueuesNum(aconf->iface); - if (aconf->threads == 0) { - aconf->threads = NetmapGetRSSCount(aconf->iface); + ns->threads = GetIfaceRSSQueuesNum(ns->iface); + if (ns->threads == 0) { + ns->threads = NetmapGetRSSCount(ns->iface); } } - if (aconf->threads <= 0) { - aconf->threads = 1; + if (ns->threads <= 0) { + ns->threads = 1; } + + return 0; +} + +/** +* \brief extract information from config file +* +* The returned structure will be freed by the thread init function. +* This is thus necessary to or copy the structure before giving it +* to thread or to reparse the file for each thread (and thus have +* new structure. +* +* \return a NetmapIfaceConfig corresponding to the interface name +*/ +static void *ParseNetmapConfig(const char *iface_name) +{ + ConfNode *if_root = NULL; + ConfNode *if_default = NULL; + ConfNode *netmap_node; + char *out_iface = NULL; + + if (iface_name == NULL) { + return NULL; + } + + NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); + if (unlikely(aconf == NULL)) { + return NULL; + } + + memset(aconf, 0, sizeof(*aconf)); + aconf->DerefFunc = NetmapDerefConfig; + strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name)); + SC_ATOMIC_INIT(aconf->ref); + (void) SC_ATOMIC_ADD(aconf->ref, 1); + + /* Find initial node */ + netmap_node = ConfGetNode("netmap"); + if (netmap_node == NULL) { + SCLogInfo("Unable to find netmap config using default value"); + } else { + if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name); + if_default = ConfFindDeviceConfig(netmap_node, "default"); + } + + /* parse settings for capture iface */ + ParseNetmapSettings(&aconf->in, aconf->iface_name, if_root, if_default); + + /* if we have a copy iface, parse that as well */ + if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { + if (strlen(out_iface) > 0) { + if_root = ConfFindDeviceConfig(netmap_node, out_iface); + ParseNetmapSettings(&aconf->out, out_iface, if_root, if_default); + } + } + SC_ATOMIC_RESET(aconf->ref); - (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); - SCLogPerf("Using %d threads for interface %s", aconf->threads, + (void) SC_ATOMIC_ADD(aconf->ref, aconf->in.threads); + SCLogPerf("Using %d threads for interface %s", aconf->in.threads, aconf->iface_name); return aconf; @@ -278,7 +273,7 @@ static void *ParseNetmapConfig(const char *iface_name) static int NetmapConfigGeThreadsCount(void *conf) { NetmapIfaceConfig *aconf = (NetmapIfaceConfig *)conf; - return aconf->threads; + return aconf->in.threads; } int NetmapRunModeIsIPS() diff --git a/src/source-netmap.c b/src/source-netmap.c index d9223fe653e0..b9ce7a843f94 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -622,8 +622,8 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da memset(ntv, 0, sizeof(*ntv)); ntv->tv = tv; - ntv->checksum_mode = aconf->checksum_mode; - ntv->copy_mode = aconf->copy_mode; + ntv->checksum_mode = aconf->in.checksum_mode; + ntv->copy_mode = aconf->in.copy_mode; ntv->livedev = LiveGetDevice(aconf->iface_name); if (ntv->livedev == NULL) { @@ -631,32 +631,32 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da goto error_ntv; } - if (NetmapOpen(aconf->iface, aconf->promisc, &ntv->ifsrc, 1) != 0) { + if (NetmapOpen(aconf->in.iface, aconf->in.promisc, &ntv->ifsrc, 1) != 0) { goto error_ntv; } - if (unlikely(!aconf->iface_sw && !ntv->ifsrc->rx_rings_cnt)) { + if (unlikely(!aconf->in.sw_ring && !ntv->ifsrc->rx_rings_cnt)) { SCLogError(SC_ERR_NETMAP_CREATE, "Input interface '%s' does not have Rx rings", aconf->iface_name); goto error_src; } - if (unlikely(aconf->iface_sw && aconf->threads > 1)) { + if (unlikely(aconf->in.sw_ring && aconf->in.threads > 1)) { SCLogError(SC_ERR_INVALID_VALUE, "Interface '%s+'. " "Thread count can't be greater than 1 for SW ring.", aconf->iface_name); goto error_src; - } else if (unlikely(aconf->threads > ntv->ifsrc->rx_rings_cnt)) { + } else if (unlikely(aconf->in.threads > ntv->ifsrc->rx_rings_cnt)) { SCLogError(SC_ERR_INVALID_VALUE, "Thread count can't be greater than Rx ring count. " "Configured %d threads for interface '%s' with %d Rx rings.", - aconf->threads, aconf->iface_name, ntv->ifsrc->rx_rings_cnt); + aconf->in.threads, aconf->iface_name, ntv->ifsrc->rx_rings_cnt); goto error_src; } - if (aconf->iface_sw) { + if (aconf->in.sw_ring) { ntv->thread_idx = 0; } else { do { @@ -665,35 +665,35 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da } /* calculate thread rings binding */ - if (aconf->iface_sw) { + if (aconf->in.sw_ring) { ntv->src_ring_from = ntv->src_ring_to = ntv->ifsrc->rings_cnt; } else { - int tmp = (ntv->ifsrc->rx_rings_cnt + 1) / aconf->threads; + int tmp = (ntv->ifsrc->rx_rings_cnt + 1) / aconf->in.threads; ntv->src_ring_from = ntv->thread_idx * tmp; ntv->src_ring_to = ntv->src_ring_from + tmp - 1; - if (ntv->thread_idx == (aconf->threads - 1)) { + if (ntv->thread_idx == (aconf->in.threads - 1)) { ntv->src_ring_to = ntv->ifsrc->rx_rings_cnt - 1; } } SCLogDebug("netmap: %s thread:%d rings:%d-%d", aconf->iface_name, ntv->thread_idx, ntv->src_ring_from, ntv->src_ring_to); - if (aconf->copy_mode != NETMAP_COPY_MODE_NONE) { - if (NetmapOpen(aconf->out_iface, 0, &ntv->ifdst, 1) != 0) { + if (aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) { + if (NetmapOpen(aconf->out.iface, aconf->out.promisc, &ntv->ifdst, 1) != 0) { goto error_src; } - if (unlikely(!aconf->out_iface_sw && !ntv->ifdst->tx_rings_cnt)) { + if (unlikely(!aconf->out.sw_ring && !ntv->ifdst->tx_rings_cnt)) { SCLogError(SC_ERR_NETMAP_CREATE, "Output interface '%s' does not have Tx rings", - aconf->out_iface_name); + aconf->out.iface); goto error_dst; } /* calculate dst rings bindings */ for (int i = ntv->src_ring_from; i <= ntv->src_ring_to; i++) { NetmapRing *ring = &ntv->ifsrc->rings[i]; - if (aconf->out_iface_sw) { + if (aconf->out.sw_ring) { ring->dst_ring_from = ring->dst_ring_to = ntv->ifdst->rings_cnt; } else if (ntv->ifdst->tx_rings_cnt > ntv->ifsrc->rx_rings_cnt) { int tmp = (ntv->ifdst->tx_rings_cnt + 1) / ntv->ifsrc->rx_rings_cnt; @@ -709,7 +709,7 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da ring->dst_next_ring = ring->dst_ring_from; SCLogDebug("netmap: %s(%d)->%s(%d-%d)", - aconf->iface_name, i, aconf->out_iface_name, + aconf->in.iface, i, aconf->out.iface, ring->dst_ring_from, ring->dst_ring_to); } } @@ -722,11 +722,11 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da /* enable zero-copy mode for workers runmode */ char const *active_runmode = RunmodeGetActive(); - if ((aconf->copy_mode != NETMAP_COPY_MODE_NONE) && active_runmode - && !strcmp("workers", active_runmode)) { + if ((aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) && active_runmode && + strcmp("workers", active_runmode) == 0) { ntv->flags |= NETMAP_FLAG_ZERO_COPY; SCLogPerf("Enabling zero copy mode for %s->%s", - aconf->iface_name, aconf->out_iface_name); + aconf->in.iface, aconf->out.iface); } else { uint16_t ring_size = ntv->ifsrc->rings[0].rx->num_slots; if (ring_size > max_pending_packets) { @@ -738,16 +738,17 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da } } - if (aconf->bpf_filter) { + if (aconf->in.bpf_filter) { SCLogConfig("Using BPF '%s' on iface '%s'", - aconf->bpf_filter, ntv->ifsrc->ifname); + aconf->in.bpf_filter, ntv->ifsrc->ifname); if (pcap_compile_nopcap(default_packet_size, /* snaplen_arg */ LINKTYPE_ETHERNET, /* linktype_arg */ &ntv->bpf_prog, /* program */ - aconf->bpf_filter, /* const char *buf */ + aconf->in.bpf_filter, /* const char *buf */ 1, /* optimize */ PCAP_NETMASK_UNKNOWN /* mask */ - ) == -1) { + ) == -1) + { SCLogError(SC_ERR_NETMAP_CREATE, "Filter compilation failed."); goto error_dst; } @@ -758,7 +759,7 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da SCReturnInt(TM_ECODE_OK); error_dst: - if (aconf->copy_mode != NETMAP_COPY_MODE_NONE) { + if (aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) { NetmapClose(ntv->ifdst); } error_src: diff --git a/src/source-netmap.h b/src/source-netmap.h index c6f7b6c23ff6..00b0b442743b 100644 --- a/src/source-netmap.h +++ b/src/source-netmap.h @@ -35,25 +35,34 @@ enum { #define NETMAP_IFACE_NAME_LENGTH 48 -typedef struct NetmapIfaceConfig_ +typedef struct NetmapIfaceSettings_ { - /* semantic interface name */ - char iface_name[NETMAP_IFACE_NAME_LENGTH]; /* real inner interface name */ char iface[NETMAP_IFACE_NAME_LENGTH]; - /* sw ring flag for iface */ - int iface_sw; + int threads; + /* sw ring flag for out_iface */ + int sw_ring; int promisc; int copy_mode; ChecksumValidationMode checksum_mode; char *bpf_filter; +} NetmapIfaceSettings; + +typedef struct NetmapIfaceConfig_ +{ + /* semantic interface name */ + char iface_name[NETMAP_IFACE_NAME_LENGTH]; + + /* settings for out capture device*/ + NetmapIfaceSettings in; + /* semantic interface name */ char *out_iface_name; - /* real inner interface name */ - char out_iface[NETMAP_IFACE_NAME_LENGTH]; - /* sw ring flag for out_iface */ - int out_iface_sw; + + /* settings for outgoing iface for IPS/TAP */ + NetmapIfaceSettings out; + SC_ATOMIC_DECLARE(unsigned int, ref); void (*DerefFunc)(void *); } NetmapIfaceConfig; From b1d191b478bf6d90ae4971fd30fbe14a63dd036a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 11 Jun 2016 16:12:26 +0200 Subject: [PATCH 1536/2553] netmap: fix enabling promisc mode on FreeBSD In FreeBSD setting the IFF_PROMISC flag has no effect. Instead we need to set the IFF_PPROMISC flag. --- src/source-netmap.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index b9ce7a843f94..738da5af13e3 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -133,6 +133,11 @@ TmEcode NoNetmapSupportExit(ThreadVars *tv, void *initdata, void **data) #if defined(__linux__) #define POLL_EVENTS (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL) + +#ifndef IFF_PPROMISC +#define IFF_PPROMISC IFF_PROMISC +#endif + #else #define POLL_EVENTS (POLLHUP|POLLERR|POLLNVAL) #endif @@ -438,8 +443,9 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver close(if_fd); goto error_fd; } - if (promisc) { - if_flags |= IFF_PROMISC; + /* if needed, try to set iface in promisc mode */ + if (promisc && (if_flags & (IFF_PROMISC|IFF_PPROMISC)) == 0) { + if_flags |= IFF_PPROMISC; NetmapSetIfaceFlags(if_fd, ifname, if_flags); } From 54bc4718108b85d8b06a95845f4590a883421849 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 12 Jun 2016 10:37:28 +0200 Subject: [PATCH 1537/2553] offloading: check for more offloading on Linux --- src/util-ioctl.c | 108 +++++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 93718460361c..9c92184fa278 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -137,75 +137,91 @@ int GetIfaceMaxPacketSize(const char *pcap_dev) return ll_header + mtu; } -/** - * \brief output offloading status of the link - * - * Test interface for GRO and LRO features. If one of them is - * activated then suricata mays received packets merge at reception. - * The result is oversized packets and this may cause some serious - * problem in some capture mode where the size of the packet is - * limited (AF_PACKET in V2 more for example). - * - * ETHTOOL_GGRO ETH_FLAG_LRO - * - * \param Name of link - * \retval -1 in case of error, 0 if none, 1 if some - */ -int GetIfaceOffloading(const char *pcap_dev) +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL +static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) { -#if defined (ETHTOOL_GGRO) && defined (ETHTOOL_GFLAGS) struct ifreq ifr; int fd; struct ethtool_value ethv; - int ret = 0; - char *lro = "unset", *gro = "unset"; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { return -1; } - (void)strlcpy(ifr.ifr_name, pcap_dev, sizeof(ifr.ifr_name)); + (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); - /* First get GRO */ - ethv.cmd = ETHTOOL_GGRO; + ethv.cmd = cmd; ifr.ifr_data = (void *) ðv; if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { SCLogWarning(SC_ERR_SYSCALL, "Failure when trying to get feature via ioctl for '%s': %s (%d)", - pcap_dev, strerror(errno), errno); + dev, strerror(errno), errno); close(fd); return -1; - } else { - if (ethv.data) { - gro = "SET"; - ret = 1; - } } - /* Then get LRO which is set in a flag */ - ethv.data = 0; - ethv.cmd = ETHTOOL_GFLAGS; - ifr.ifr_data = (void *) ðv; - if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { - SCLogWarning(SC_ERR_SYSCALL, - "Failure when trying to get feature via ioctl for '%s': %s (%d)", - pcap_dev, strerror(errno), errno); - close(fd); - return -1; - } else { - if (ethv.data & ETH_FLAG_LRO) { + *value = ethv.data; + close(fd); + return 0; +} +#endif + +/** + * \brief output offloading status of the link + * + * Test interface for offloading features. If one of them is + * activated then suricata mays received packets merge at reception. + * The result is oversized packets and this may cause some serious + * problem in some capture mode where the size of the packet is + * limited (AF_PACKET in V2 more for example). + * + * \param Name of link + * \retval -1 in case of error, 0 if none, 1 if some + */ +int GetIfaceOffloading(const char *dev) +{ + int ret = 0; + char *lro = "unset", *gro = "unset", *tso = "unset", *gso = "unset"; + char *sg = "unset"; +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + uint32_t value = 0; + +#ifdef ETHTOOL_GGRO + if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { + gro = "SET"; + ret = 1; + } +#endif +#ifdef ETHTOOL_GTSO + if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { + tso = "SET"; + ret = 1; + } +#endif +#ifdef ETHTOOL_GGSO + if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { + gso = "SET"; + ret = 1; + } +#endif +#ifdef ETHTOOL_GSG + if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { + sg = "SET"; + ret = 1; + } +#endif +#ifdef ETHTOOL_GFLAGS + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + if (value & ETH_FLAG_LRO) { lro = "SET"; ret = 1; } } - - close(fd); - SCLogInfo("NIC offloading on %s: GRO: %s, LRO: %s", pcap_dev, gro, lro); - return ret; -#else - /* ioctl is not defined, let's pretend returning 0 is ok */ - return 0; #endif +#endif + SCLogInfo("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " + "TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso); + return ret; } int GetIfaceRSSQueuesNum(const char *pcap_dev) From 33f876900124d45dd033f148ee0f013bd3467d00 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Jun 2016 08:59:26 +0200 Subject: [PATCH 1538/2553] offloading: move linux specific into their own func --- src/util-ioctl.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 9c92184fa278..436d39a49ba1 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -164,26 +164,12 @@ static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) close(fd); return 0; } -#endif -/** - * \brief output offloading status of the link - * - * Test interface for offloading features. If one of them is - * activated then suricata mays received packets merge at reception. - * The result is oversized packets and this may cause some serious - * problem in some capture mode where the size of the packet is - * limited (AF_PACKET in V2 more for example). - * - * \param Name of link - * \retval -1 in case of error, 0 if none, 1 if some - */ -int GetIfaceOffloading(const char *dev) +static int GetIfaceOffloadingLinux(const char *dev) { int ret = 0; char *lro = "unset", *gro = "unset", *tso = "unset", *gso = "unset"; char *sg = "unset"; -#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL uint32_t value = 0; #ifdef ETHTOOL_GGRO @@ -217,13 +203,34 @@ int GetIfaceOffloading(const char *dev) ret = 1; } } -#endif #endif SCLogInfo("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " "TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso); return ret; } +#endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */ + +/** + * \brief output offloading status of the link + * + * Test interface for offloading features. If one of them is + * activated then suricata mays received packets merge at reception. + * The result is oversized packets and this may cause some serious + * problem in some capture mode where the size of the packet is + * limited (AF_PACKET in V2 more for example). + * + * \param Name of link + * \retval -1 in case of error, 0 if none, 1 if some + */ +int GetIfaceOffloading(const char *dev) +{ +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + return GetIfaceOffloadingLinux(dev); +#endif + return 0; +} + int GetIfaceRSSQueuesNum(const char *pcap_dev) { #if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS From 45fa25eb0ca96612298389aa1041d58599bb5c86 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Jun 2016 10:16:33 +0200 Subject: [PATCH 1539/2553] offloading: improve checks on FreeBSD Move FreeBSD specific (but not netmap specific) checks from the netmap code to the general ioctl wrapper code. Warn from the check functions now, so callers no longer need to. --- src/source-netmap.c | 131 +++------------------------------------- src/source-pcap.c | 10 +--- src/util-error.c | 1 + src/util-error.h | 1 + src/util-ioctl.c | 143 +++++++++++++++++++++++++++++++++++++++++++- src/util-ioctl.h | 9 +++ 6 files changed, 159 insertions(+), 136 deletions(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index 738da5af13e3..21d21579bfa2 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -80,6 +80,8 @@ #endif /* HAVE_NETMAP */ +#include "util-ioctl.h" + extern intmax_t max_pending_packets; #ifndef HAVE_NETMAP @@ -224,113 +226,6 @@ typedef TAILQ_HEAD(NetmapDeviceList_, NetmapDevice_) NetmapDeviceList; static NetmapDeviceList netmap_devlist = TAILQ_HEAD_INITIALIZER(netmap_devlist); static SCMutex netmap_devlist_lock = SCMUTEX_INITIALIZER; -/** - * \brief Get interface flags. - * \param fd Network susbystem file descritor. - * \param ifname Inteface name. - * \return Interface flags or -1 on error - */ -static int NetmapGetIfaceFlags(int fd, const char *ifname) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - - if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { - SCLogError(SC_ERR_NETMAP_CREATE, - "Unable to get flags for iface \"%s\": %s", - ifname, strerror(errno)); - return -1; - } - -#ifdef OS_FREEBSD - int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); - return flags; -#else - return ifr.ifr_flags; -#endif -} - -#ifdef SIOCGIFCAP -static int NetmapGetIfaceCaps(int fd, const char *ifname) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - - if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) { - SCLogError(SC_ERR_NETMAP_CREATE, - "Unable to get caps for iface \"%s\": %s", - ifname, strerror(errno)); - return -1; - } - - return ifr.ifr_curcap; -} -#endif - -static void NetmapCheckOffloading(int fd, const char *ifname) -{ -#ifdef SIOCGIFCAP - int if_caps = NetmapGetIfaceCaps(fd, ifname); - if (if_caps == -1) { - return; - } - SCLogDebug("if_caps %X", if_caps); - - if (if_caps & IFCAP_RXCSUM) { - SCLogWarning(SC_ERR_NETMAP_CREATE, - "Using NETMAP with RXCSUM activated can lead to capture " - "problems: ifconfig %s -rxcsum", ifname); - } - if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { - SCLogWarning(SC_ERR_NETMAP_CREATE, - "Using NETMAP with TSO, TOE or LRO activated can lead to " - "capture problems: ifconfig %s -tso -toe -lro", ifname); - } -#else - if (GetIfaceOffloading(ifname) == 1) { - SCLogWarning(SC_ERR_NETMAP_CREATE, - "Using NETMAP with GRO or LRO activated can lead to " - "capture problems: " - "ethtool -K %s rx off sg off gro off gso off tso off", - ifname); - } -#endif -} - -/** - * \brief Set interface flags. - * \param fd Network susbystem file descritor. - * \param ifname Inteface name. - * \param flags Flags to set. - * \return Zero on success. - */ -static int NetmapSetIfaceFlags(int fd, const char *ifname, int flags) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); -#ifdef OS_FREEBSD - ifr.ifr_flags = flags & 0xffff; - ifr.ifr_flagshigh = flags >> 16; -#else - ifr.ifr_flags = flags; -#endif - - if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { - SCLogError(SC_ERR_NETMAP_CREATE, - "Unable to set flags for iface \"%s\": %s", - ifname, strerror(errno)); - return -1; - } - - return 0; -} - /** \brief get RSS RX-queue count * \retval rx_rings RSS RX queue count or 1 on error */ @@ -398,6 +293,8 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver } } + (void)GetIfaceOffloading(ifname); + /* not found, create new record */ pdev = SCMalloc(sizeof(*pdev)); if (unlikely(pdev == NULL)) { @@ -419,39 +316,25 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver } /* check interface is up */ - int if_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (if_fd < 0) { - SCLogError(SC_ERR_NETMAP_CREATE, - "Couldn't create control socket for '%s' interface", - ifname); - goto error_fd; - } - int if_flags = NetmapGetIfaceFlags(if_fd, ifname); + int if_flags = GetIfaceFlags(ifname); if (if_flags == -1) { if (verbose) { SCLogError(SC_ERR_NETMAP_CREATE, "Can not access to interface '%s'", ifname); } - close(if_fd); goto error_fd; } if ((if_flags & IFF_UP) == 0) { - if (verbose) { - SCLogError(SC_ERR_NETMAP_CREATE, "Interface '%s' is down", ifname); - } - close(if_fd); + SCLogWarning(SC_ERR_NETMAP_CREATE, "Interface '%s' is down", ifname); goto error_fd; } /* if needed, try to set iface in promisc mode */ if (promisc && (if_flags & (IFF_PROMISC|IFF_PPROMISC)) == 0) { if_flags |= IFF_PPROMISC; - NetmapSetIfaceFlags(if_fd, ifname, if_flags); + SetIfaceFlags(ifname, if_flags); } - NetmapCheckOffloading(if_fd, ifname); - close(if_fd); - /* query netmap info */ memset(&nm_req, 0, sizeof(nm_req)); strlcpy(nm_req.nr_name, ifname, sizeof(nm_req.nr_name)); diff --git a/src/source-pcap.c b/src/source-pcap.c index 7b9a6161d325..304e713304e4 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -510,15 +510,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) SCMutexUnlock(&pcap_bpf_compile_lock); } - /* Making it conditional to Linux even if GetIfaceOffloading return 0 - * for non Linux. */ -#ifdef HAVE_LINUX_ETHTOOL_H - if (GetIfaceOffloading(pcapconfig->iface) == 1) { - SCLogWarning(SC_ERR_PCAP_CREATE, - "Using Pcap capture with GRO or LRO activated can lead to " - "capture problems."); - } -#endif /* HAVE_LINUX_ETHTOOL_H */ + (void)GetIfaceOffloading(pcapconfig->iface); ptv->datalink = pcap_datalink(ptv->pcap_handle); diff --git a/src/util-error.c b/src/util-error.c index 2cd58e5c2ec1..672430adcaec 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -324,6 +324,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_NETFLOW_LOG_GENERIC); CASE_CODE (SC_ERR_SMTP_LOG_GENERIC); CASE_CODE (SC_ERR_SSH_LOG_GENERIC); + CASE_CODE (SC_ERR_NIC_OFFLOADING); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 1825b77005ea..99c8f1375d0f 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -314,6 +314,7 @@ typedef enum { SC_ERR_NETFLOW_LOG_GENERIC, SC_ERR_SMTP_LOG_GENERIC, SC_ERR_SSH_LOG_GENERIC, + SC_ERR_NIC_OFFLOADING, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 436d39a49ba1..4e949686b997 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -137,6 +137,106 @@ int GetIfaceMaxPacketSize(const char *pcap_dev) return ll_header + mtu; } +#ifdef SIOCGIFFLAGS +/** + * \brief Get interface flags. + * \param ifname Inteface name. + * \return Interface flags or -1 on error + */ +int GetIfaceFlags(const char *ifname) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to get flags for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); +#ifdef OS_FREEBSD + int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); + return flags; +#else + return ifr.ifr_flags; +#endif +} +#endif + +#ifdef SIOCSIFFLAGS +/** + * \brief Set interface flags. + * \param ifname Inteface name. + * \param flags Flags to set. + * \return Zero on success. + */ +int SetIfaceFlags(const char *ifname, int flags) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +#ifdef OS_FREEBSD + ifr.ifr_flags = flags & 0xffff; + ifr.ifr_flagshigh = flags >> 16; +#else + ifr.ifr_flags = flags; +#endif + + if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to set flags for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return 0; +} +#endif /* SIOCGIFFLAGS */ + +#ifdef SIOCGIFCAP +int GetIfaceCaps(const char *ifname) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to get caps for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return ifr.ifr_curcap; +} +#endif + #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) { @@ -204,13 +304,47 @@ static int GetIfaceOffloadingLinux(const char *dev) } } #endif - SCLogInfo("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " - "TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso); + if (ret == 0) { + SCLogInfo("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " + "TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso); + } else { + SCLogWarning(SC_ERR_NIC_OFFLOADING, "NIC offloading on %s: SG: %s, " + " GRO: %s, LRO: %s, TSO: %s, GSO: %s: " + "ethtool -K %s sg off gro off lro off tso off gso off", + dev, sg, gro, lro, tso, gso, dev); + } return ret; } #endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */ +#ifdef SIOCGIFCAP +static int GetIfaceOffloadingBSD(const char *ifname) +{ + int ret = 0; + int if_caps = GetIfaceCaps(ifname); + if (if_caps == -1) { + return -1; + } + SCLogDebug("if_caps %X", if_caps); + + if (if_caps & IFCAP_RXCSUM) { + SCLogWarning(SC_ERR_NIC_OFFLOADING, + "Using %s with RXCSUM activated can lead to capture " + "problems: ifconfig %s -rxcsum", ifname, ifname); + ret = 1; + } + if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { + SCLogWarning(SC_ERR_NIC_OFFLOADING, + "Using %s with TSO, TOE or LRO activated can lead to " + "capture problems: ifconfig %s -tso -toe -lro", + ifname, ifname); + ret = 1; + } + return ret; +} +#endif + /** * \brief output offloading status of the link * @@ -227,8 +361,11 @@ int GetIfaceOffloading(const char *dev) { #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL return GetIfaceOffloadingLinux(dev); -#endif +#elif defined SIOCGIFCAP + return GetIfaceOffloadingBSD(dev); +#else return 0; +#endif } int GetIfaceRSSQueuesNum(const char *pcap_dev) diff --git a/src/util-ioctl.h b/src/util-ioctl.h index 3931c1fe0919..76195ac76fdc 100644 --- a/src/util-ioctl.h +++ b/src/util-ioctl.h @@ -25,3 +25,12 @@ int GetIfaceMTU(const char *pcap_dev); int GetIfaceMaxPacketSize(const char *pcap_dev); int GetIfaceOffloading(const char *pcap_dev); int GetIfaceRSSQueuesNum(const char *pcap_dev); +#ifdef SIOCGIFFLAGS +int GetIfaceFlags(const char *ifname); +#endif +#ifdef SIOCSIFFLAGS +int SetIfaceFlags(const char *ifname, int flags); +#endif +#ifdef SIOCGIFCAP +int GetIfaceCaps(const char *ifname); +#endif From 507027845d6afac10236eb14b671ae189146e5c1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Jun 2016 12:33:51 +0200 Subject: [PATCH 1540/2553] afpacket: update offloading warning --- src/runmode-af-packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 1696834c12bc..3d9cacb5cb91 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -428,7 +428,7 @@ void *ParseAFPConfig(const char *iface) case LINKTYPE_ETHERNET: if (GetIfaceOffloading(iface) == 1) { SCLogWarning(SC_ERR_AFP_CREATE, - "Using AF_PACKET with GRO or LRO activated can lead to capture problems"); + "Using AF_PACKET with offloading activated leads to capture problems"); } case -1: default: From 03d46f13691d67494c6923bfd24a688ce1cc428d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Jun 2016 12:36:27 +0200 Subject: [PATCH 1541/2553] offloading: reduce verbosity --- src/util-ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 4e949686b997..54d262666160 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -305,7 +305,7 @@ static int GetIfaceOffloadingLinux(const char *dev) } #endif if (ret == 0) { - SCLogInfo("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " + SCLogPerf("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " "TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso); } else { SCLogWarning(SC_ERR_NIC_OFFLOADING, "NIC offloading on %s: SG: %s, " From 9b80c21d787b5e7b4c221c91b71619e6e8eb11f0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Jun 2016 12:55:29 +0200 Subject: [PATCH 1542/2553] offloading: distinguish between csum and the rest As AF_PACKET handles csum offloading don't check for this type of offloading. Other methods like pcap and netmap do require it to be turned off. Improve disable command suggestion wording. --- src/runmode-af-packet.c | 3 +- src/source-netmap.c | 3 +- src/source-pcap.c | 3 +- src/util-ioctl.c | 103 ++++++++++++++++++++++++++-------------- src/util-ioctl.h | 2 +- 5 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 3d9cacb5cb91..1e003f7c16fa 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -426,7 +426,8 @@ void *ParseAFPConfig(const char *iface) int ltype = AFPGetLinkType(iface); switch (ltype) { case LINKTYPE_ETHERNET: - if (GetIfaceOffloading(iface) == 1) { + /* af-packet can handle csum offloading */ + if (GetIfaceOffloading(iface, 0, 1) == 1) { SCLogWarning(SC_ERR_AFP_CREATE, "Using AF_PACKET with offloading activated leads to capture problems"); } diff --git a/src/source-netmap.c b/src/source-netmap.c index 21d21579bfa2..ec38c1f7a618 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -293,7 +293,8 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver } } - (void)GetIfaceOffloading(ifname); + /* netmap needs all offloading to be disabled */ + (void)GetIfaceOffloading(ifname, 1, 1); /* not found, create new record */ pdev = SCMalloc(sizeof(*pdev)); diff --git a/src/source-pcap.c b/src/source-pcap.c index 304e713304e4..97fcd72e6f93 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -510,7 +510,8 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) SCMutexUnlock(&pcap_bpf_compile_lock); } - (void)GetIfaceOffloading(pcapconfig->iface); + /* no offloading supported at all */ + (void)GetIfaceOffloading(pcapconfig->iface, 1, 1); ptv->datalink = pcap_datalink(ptv->pcap_handle); diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 54d262666160..866e6a0f61f0 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -265,53 +265,82 @@ static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) return 0; } -static int GetIfaceOffloadingLinux(const char *dev) +static int GetIfaceOffloadingLinux(const char *dev, int csum, int other) { int ret = 0; - char *lro = "unset", *gro = "unset", *tso = "unset", *gso = "unset"; - char *sg = "unset"; uint32_t value = 0; -#ifdef ETHTOOL_GGRO - if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { - gro = "SET"; - ret = 1; + if (csum) { + char *rx = "unset", *tx = "unset"; + int csum_ret = 0; +#ifdef ETHTOOL_GRXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { + rx = "SET"; + csum_ret = 1; + } +#endif +#ifdef ETHTOOL_GTXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { + tx = "SET"; + csum_ret = 1; + } +#endif + if (csum_ret == 0) + SCLogPerf("NIC offloading on %s: RX %s TX %s", dev, rx, tx); + else { + SCLogWarning(SC_ERR_NIC_OFFLOADING, + "NIC offloading on %s: RX %s TX %s. Run: " + "ethtool -K %s rx off tx off", dev, rx, tx, dev); + ret = 1; + } } + + if (other) { + char *lro = "unset", *gro = "unset", *tso = "unset", *gso = "unset"; + char *sg = "unset"; + int other_ret = 0; +#ifdef ETHTOOL_GGRO + if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { + gro = "SET"; + other_ret = 1; + } #endif #ifdef ETHTOOL_GTSO - if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { - tso = "SET"; - ret = 1; - } + if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { + tso = "SET"; + other_ret = 1; + } #endif #ifdef ETHTOOL_GGSO - if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { - gso = "SET"; - ret = 1; - } + if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { + gso = "SET"; + other_ret = 1; + } #endif #ifdef ETHTOOL_GSG - if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { - sg = "SET"; - ret = 1; - } + if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { + sg = "SET"; + other_ret = 1; + } #endif #ifdef ETHTOOL_GFLAGS - if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { - if (value & ETH_FLAG_LRO) { - lro = "SET"; - ret = 1; + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + if (value & ETH_FLAG_LRO) { + lro = "SET"; + other_ret = 1; + } } - } #endif - if (ret == 0) { - SCLogPerf("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " - "TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso); - } else { - SCLogWarning(SC_ERR_NIC_OFFLOADING, "NIC offloading on %s: SG: %s, " - " GRO: %s, LRO: %s, TSO: %s, GSO: %s: " - "ethtool -K %s sg off gro off lro off tso off gso off", - dev, sg, gro, lro, tso, gso, dev); + if (other_ret == 0) { + SCLogPerf("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " + "TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso); + } else { + SCLogWarning(SC_ERR_NIC_OFFLOADING, "NIC offloading on %s: SG: %s, " + " GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: " + "ethtool -K %s sg off gro off lro off tso off gso off", + dev, sg, gro, lro, tso, gso, dev); + ret = 1; + } } return ret; } @@ -331,13 +360,13 @@ static int GetIfaceOffloadingBSD(const char *ifname) if (if_caps & IFCAP_RXCSUM) { SCLogWarning(SC_ERR_NIC_OFFLOADING, "Using %s with RXCSUM activated can lead to capture " - "problems: ifconfig %s -rxcsum", ifname, ifname); + "problems. Run: ifconfig %s -rxcsum", ifname, ifname); ret = 1; } if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { SCLogWarning(SC_ERR_NIC_OFFLOADING, "Using %s with TSO, TOE or LRO activated can lead to " - "capture problems: ifconfig %s -tso -toe -lro", + "capture problems. Run: ifconfig %s -tso -toe -lro", ifname, ifname); ret = 1; } @@ -355,12 +384,14 @@ static int GetIfaceOffloadingBSD(const char *ifname) * limited (AF_PACKET in V2 more for example). * * \param Name of link + * \param csum check if checksums are offloaded + * \param other check if other things are offloaded: TSO, GRO, etc. * \retval -1 in case of error, 0 if none, 1 if some */ -int GetIfaceOffloading(const char *dev) +int GetIfaceOffloading(const char *dev, int csum, int other) { #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL - return GetIfaceOffloadingLinux(dev); + return GetIfaceOffloadingLinux(dev, csum, other); #elif defined SIOCGIFCAP return GetIfaceOffloadingBSD(dev); #else diff --git a/src/util-ioctl.h b/src/util-ioctl.h index 76195ac76fdc..79018754b0c4 100644 --- a/src/util-ioctl.h +++ b/src/util-ioctl.h @@ -23,7 +23,7 @@ int GetIfaceMTU(const char *pcap_dev); int GetIfaceMaxPacketSize(const char *pcap_dev); -int GetIfaceOffloading(const char *pcap_dev); +int GetIfaceOffloading(const char *dev, int csum, int other); int GetIfaceRSSQueuesNum(const char *pcap_dev); #ifdef SIOCGIFFLAGS int GetIfaceFlags(const char *ifname); From 18de4c9654aff7d48904511946d34964f74caab7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Jun 2016 13:32:28 +0200 Subject: [PATCH 1543/2553] offloading: work around missing TOE support --- src/util-ioctl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 866e6a0f61f0..cfca00b3a4b2 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -363,6 +363,7 @@ static int GetIfaceOffloadingBSD(const char *ifname) "problems. Run: ifconfig %s -rxcsum", ifname, ifname); ret = 1; } +#ifdef IFCAP_TOE if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { SCLogWarning(SC_ERR_NIC_OFFLOADING, "Using %s with TSO, TOE or LRO activated can lead to " @@ -370,6 +371,15 @@ static int GetIfaceOffloadingBSD(const char *ifname) ifname, ifname); ret = 1; } +#else + if (if_caps & (IFCAP_TSO|IFCAP_LRO)) { + SCLogWarning(SC_ERR_NIC_OFFLOADING, + "Using %s with TSO or LRO activated can lead to " + "capture problems. Run: ifconfig %s -tso -lro", + ifname, ifname); + ret = 1; + } +#endif return ret; } #endif From 46ac5ed7b74a971ced9efc7a41b09b2b1c6331b6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 10 Jun 2016 09:31:30 +0200 Subject: [PATCH 1544/2553] pfring: move output to 'Perf' level --- src/source-pfring.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index 4ce3c81e3446..4b4715d313f8 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -469,7 +469,7 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) /* enable zero-copy mode for workers runmode */ if (active_runmode && strcmp("workers", active_runmode) == 0) { ptv->flags |= PFRING_FLAGS_ZERO_COPY; - SCLogInfo("Enabling zero-copy for %s", ptv->interface); + SCLogPerf("Enabling zero-copy for %s", ptv->interface); } ptv->checksum_mode = pfconf->checksum_mode; @@ -532,11 +532,11 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) } if (ptv->threads > 1) { - SCLogInfo("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d", + SCLogPerf("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d", tv->name, (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8, version & 0x000000FF, ptv->interface, ptv->cluster_id); } else { - SCLogInfo("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d, single-pfring-thread", + SCLogPerf("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d, single-pfring-thread", tv->name, (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8, version & 0x000000FF, ptv->interface, ptv->cluster_id); } @@ -581,7 +581,7 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) * ZC interface, do nothing */ if (ptv->vlan_disabled && ptv->ctype == CLUSTER_FLOW && strncmp(ptv->interface, "zc", 2) != 0) { - SCLogInfo("VLAN disabled, setting cluster type to CLUSTER_FLOW_5_TUPLE"); + SCLogPerf("VLAN disabled, setting cluster type to CLUSTER_FLOW_5_TUPLE"); rc = pfring_set_cluster(ptv->pd, ptv->cluster_id, CLUSTER_FLOW_5_TUPLE); if (rc != 0) { @@ -608,11 +608,11 @@ void ReceivePfringThreadExitStats(ThreadVars *tv, void *data) PfringThreadVars *ptv = (PfringThreadVars *)data; PfringDumpCounters(ptv); - SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", + SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, StatsGetLocalCounterValue(tv, ptv->capture_kernel_packets), StatsGetLocalCounterValue(tv, ptv->capture_kernel_drops)); - SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); + SCLogPerf("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); } /** From 604542081221a95c8904dcdde9d599b30c87c55a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 10 Jun 2016 09:56:23 +0200 Subject: [PATCH 1545/2553] detect: reduce verbosity, don't warn on empty files --- src/detect.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/detect.c b/src/detect.c index bf95d784d1b0..141e81910527 100644 --- a/src/detect.c +++ b/src/detect.c @@ -389,7 +389,10 @@ static int ProcessSigFiles(DetectEngineCtx *de_ctx, char *pattern, for (size_t i = 0; i < (size_t)files.gl_pathc; i++) { char *fname = files.gl_pathv[i]; - SCLogInfo("Loading rule file: %s", fname); + if (strcmp("/dev/null", fname) == 0) + continue; + + SCLogConfig("Loading rule file: %s", fname); r = DetectLoadSigFile(de_ctx, fname, good_sigs, bad_sigs); if (r < 0) { ++(st->bad_files); @@ -397,11 +400,6 @@ static int ProcessSigFiles(DetectEngineCtx *de_ctx, char *pattern, ++(st->total_files); - if (*good_sigs == 0) { - SCLogWarning(SC_ERR_NO_RULES, - "No rules loaded from %s", fname); - } - st->good_sigs_total += *good_sigs; st->bad_sigs_total += *bad_sigs; } @@ -479,11 +477,7 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl } if (good_sigs == 0) { - SCLogError(SC_ERR_NO_RULES, "No rules loaded from %s", sig_file); - - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } + SCLogConfig("No rules loaded from %s", sig_file); } } From f0e22c91cb23415d3c095b016040d7bb7542c4a7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 13 Jun 2016 12:44:28 -0600 Subject: [PATCH 1546/2553] privs: add capability CAP_SYS_NICE. Allows the setting of thread priorities after dropping privileges. --- src/util-privs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util-privs.c b/src/util-privs.c index e6e3d6c591a8..9b2a0058f6f3 100644 --- a/src/util-privs.c +++ b/src/util-privs.c @@ -76,16 +76,18 @@ void SCDropMainThreadCaps(uint32_t userid, uint32_t groupid) case RUNMODE_AFP_DEV: capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_RAW, /* needed for pcap live mode */ + CAP_SYS_NICE, -1); break; case RUNMODE_PFRING: capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, - CAP_NET_ADMIN, CAP_NET_RAW, + CAP_NET_ADMIN, CAP_NET_RAW, CAP_SYS_NICE, -1); break; case RUNMODE_NFQ: capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_ADMIN, /* needed for nfqueue inline mode */ + CAP_SYS_NICE, -1); break; } From e9a2a341ceda1f1c23918949f483508144a22aea Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 14 Jun 2016 23:14:40 +0200 Subject: [PATCH 1547/2553] util-threshold-config: parse suppress rules with spaces in ip list This modified regex allows spaces witihn the ip list for supress rules like [10.0.0.1, 10.0.0.2] --- src/util-threshold-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index d7f24769e2b9..d45f7b7030a0 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -73,7 +73,7 @@ typedef enum ThresholdRuleType { * suppress gen_id 1, sig_id 2000328 * suppress gen_id 1, sig_id 2000328, track by_src, ip fe80::/10 */ -#define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src|by_either)\\s*,\\s*ip\\s*([\\[\\],\\$\\da-zA-Z.:/_]+)*\\s*$" +#define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src|by_either)\\s*,\\s*ip\\s*([\\[\\],\\$\\s\\da-zA-Z.:/_]+)*\\s*$" /* Default path for the threshold.config file */ #if defined OS_WIN32 || defined __CYGWIN__ From ab65b6f83b55e12fb05aafcaf51ad9b369b82de5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Jun 2016 13:21:54 +0200 Subject: [PATCH 1548/2553] netmap: fix coverity warning 1362789 ** CID 1362789: Null pointer dereferences (FORWARD_NULL) /src/runmode-netmap.c: 247 in ParseNetmapConfig() ________________________________________________________________________________________________________ *** CID 1362789: Null pointer dereferences (FORWARD_NULL) /src/runmode-netmap.c: 247 in ParseNetmapConfig() 241 strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name)); 242 SC_ATOMIC_INIT(aconf->ref); 243 (void) SC_ATOMIC_ADD(aconf->ref, 1); 244 245 /* Find initial node */ 246 netmap_node = ConfGetNode("netmap"); >>> CID 1362789: Null pointer dereferences (FORWARD_NULL) >>> Comparing "netmap_node" to null implies that "netmap_node" might be null. 247 if (netmap_node == NULL) { 248 SCLogInfo("Unable to find netmap config using default value"); 249 } else { 250 if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name); 251 if_default = ConfFindDeviceConfig(netmap_node, "default"); 252 } --- src/runmode-netmap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 81c409c2835e..1cf08bc82987 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -255,10 +255,12 @@ static void *ParseNetmapConfig(const char *iface_name) ParseNetmapSettings(&aconf->in, aconf->iface_name, if_root, if_default); /* if we have a copy iface, parse that as well */ - if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { - if (strlen(out_iface) > 0) { - if_root = ConfFindDeviceConfig(netmap_node, out_iface); - ParseNetmapSettings(&aconf->out, out_iface, if_root, if_default); + if (netmap_node != NULL) { + if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { + if (strlen(out_iface) > 0) { + if_root = ConfFindDeviceConfig(netmap_node, out_iface); + ParseNetmapSettings(&aconf->out, out_iface, if_root, if_default); + } } } From 402bdf9b2b76ac56f33d87e6f6a4d51a30ec57c7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Jun 2016 16:43:53 +0200 Subject: [PATCH 1549/2553] af-packet: test if fanout is supported before use Older system may pretend they can support FANOUT but then fail to work at runtime. CentOS6 is an example of this. It would fail to start up with the default configuration with errors like: [15770] 21/6/2016 -- 16:00:13 - (tm-threads.c:2168) (TmThreadWaitOnThreadInit) -- all 4 packet processing threads, 4 management threads initialized, engine started. [15785] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1907) (AFPCreateSocket) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Coudn't set fanout mode, error Protocol not available [15785] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1337) (ReceiveAFPLoop) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Couldn't init AF_PACKET socket, fatal error [15770] 21/6/2016 -- 16:00:13 - (suricata.c:2664) (main) -- Signal Received. Stopping engine. [15787] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1907) (AFPCreateSocket) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Coudn't set fanout mode, error Protocol not available [15788] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1907) (AFPCreateSocket) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Coudn't set fanout mode, error Protocol not available [15786] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1907) (AFPCreateSocket) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Coudn't set fanout mode, error Protocol not available [15789] 21/6/2016 -- 16:00:13 - (flow-manager.c:693) (FlowManager) -- 0 new flows, 0 established flows were timed out, 0 flows in closed state [15787] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1337) (ReceiveAFPLoop) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Couldn't init AF_PACKET socket, fatal error [15788] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1337) (ReceiveAFPLoop) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Couldn't init AF_PACKET socket, fatal error [15786] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1337) (ReceiveAFPLoop) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Couldn't init AF_PACKET socket, fatal error This patch adds a test that if run before the number of threads is determined. If the test fails, only 1 thread is created. --- src/runmode-af-packet.c | 13 +++++++++++++ src/source-af-packet.c | 24 ++++++++++++++++++++++++ src/source-af-packet.h | 2 ++ 3 files changed, 39 insertions(+) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 1e003f7c16fa..714589fc5539 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -387,6 +387,19 @@ void *ParseAFPConfig(const char *iface) finalize: + /* if the number of threads is not 1, we need to first check if fanout + * functions on this system. */ + if (aconf->threads != 1) { + if (AFPIsFanoutSupported() == 0) { + if (aconf->threads != 0) { + SCLogNotice("fanout not supported on this system, falling " + "back to 1 capture thread"); + } + aconf->threads = 1; + } + } + + /* try to automagically set the proper number of threads */ if (aconf->threads == 0) { int rss_queues; aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 313278e3ccd6..db6f5056bc65 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1809,6 +1809,30 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) return AFP_FATAL_ERROR; } +/** \brief test if we can use FANOUT. Older kernels like those in + * CentOS6 have HAVE_PACKET_FANOUT defined but fail to work + */ +int AFPIsFanoutSupported(void) +{ +#ifdef HAVE_PACKET_FANOUT + int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (fd != -1) { + uint16_t mode = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; + uint16_t id = 99; + uint32_t option = (mode << 16) | (id & 0xffff); + int r = setsockopt(fd, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); + close(fd); + + if (r < 0) { + SCLogPerf("fanout not supported by kernel: %s", strerror(errno)); + return 0; + } + return 1; + } +#endif + return 0; +} + static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) { int r; diff --git a/src/source-af-packet.h b/src/source-af-packet.h index 2aa803a56b9c..513fdc9b37ff 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -147,4 +147,6 @@ TmEcode AFPPeersListCheck(); void AFPPeersListClean(); int AFPGetLinkType(const char *ifname); +int AFPIsFanoutSupported(void); + #endif /* __SOURCE_AFP_H__ */ From 4111331ab067c8e6038cf131eb31b2c8350b3ead Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Jun 2016 17:07:15 +0200 Subject: [PATCH 1550/2553] af-packet: minor cleanups --- src/runmode-af-packet.c | 10 ++++++---- src/source-af-packet.c | 9 ++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 714589fc5539..d230eabbba8f 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -408,12 +408,14 @@ void *ParseAFPConfig(const char *iface) if (rss_queues > 0) { if (rss_queues < aconf->threads) { aconf->threads = rss_queues; - SCLogInfo("More cores than RSS queues, using %d threads for interface %s", - aconf->threads, iface); + SCLogInfo("More cores than RSS queues, using %d threads " + "for interface %s", aconf->threads, iface); } } - if (aconf->threads) - SCLogPerf("Using %d AF_PACKET threads for interface %s", aconf->threads, iface); + if (aconf->threads) { + SCLogPerf("Using %d AF_PACKET threads for interface %s", + aconf->threads, iface); + } } if (aconf->threads <= 0) { aconf->threads = 1; diff --git a/src/source-af-packet.c b/src/source-af-packet.c index db6f5056bc65..2721ed47f6b2 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1879,7 +1879,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) if (setsockopt(ptv->socket, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) == -1 && errno != ENOPROTOOPT) { SCLogWarning(SC_ERR_NO_AF_PACKET, - "'kernel' checksum mode not supported, failling back to full mode."); + "'kernel' checksum mode not supported, falling back to full mode."); ptv->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } } @@ -1920,14 +1920,13 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) #ifdef HAVE_PACKET_FANOUT /* add binded socket to fanout group */ if (ptv->threads > 1) { - uint32_t option = 0; uint16_t mode = ptv->cluster_type; uint16_t id = ptv->cluster_id; - option = (mode << 16) | (id & 0xffff); + uint32_t option = (mode << 16) | (id & 0xffff); r = setsockopt(ptv->socket, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); if (r < 0) { SCLogError(SC_ERR_AFP_CREATE, - "Coudn't set fanout mode, error %s", + "Couldn't set fanout mode, error %s", strerror(errno)); goto socket_err; } @@ -1938,7 +1937,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) if (if_flags == -1) { if (verbose) { SCLogError(SC_ERR_AFP_READ, - "Can not acces to interface '%s'", + "Couldn't get flags for interface '%s'", ptv->iface); } ret = AFP_RECOVERABLE_ERROR; From 3c59d60049aa7f9a6624d77870558ceed9b8df4e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 14 Jun 2016 14:08:34 +0200 Subject: [PATCH 1551/2553] cuda: make sure we don't use cuda in proto detect --- src/app-layer-detect-proto.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index fb25b5b35209..541fa24e9003 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1530,6 +1530,12 @@ int AppLayerProtoDetectSetup(void) uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); uint16_t mpm_matcher = PatternMatchDefaultMatcher(); +#ifdef __SC_CUDA_SUPPORT__ + /* CUDA won't work here, so fall back to AC */ + if (mpm_matcher == MPM_AC_CUDA) + mpm_matcher = DEFAULT_MPM; +#endif + alpd_ctx.spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); if (alpd_ctx.spm_global_thread_ctx == NULL) { SCLogError(SC_ERR_FATAL, "Unable to alloc SpmGlobalThreadCtx."); From 5e4d071b76f6b2d6397015dc091359ab105e04b9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 5 Jul 2016 16:00:31 +0200 Subject: [PATCH 1552/2553] lua-output: don't crash on script setup error --- src/output-lua.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/output-lua.c b/src/output-lua.c index c2aadbbbdf8c..eb32911337f2 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -816,12 +816,12 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) if (unlikely(output_ctx == NULL)) { return NULL; } + output_ctx->DeInit = LogLuaMasterFree; output_ctx->data = SCCalloc(1, sizeof(LogLuaMasterCtx)); if (unlikely(output_ctx->data == NULL)) { SCFree(output_ctx); return NULL; } - output_ctx->DeInit = LogLuaMasterFree; LogLuaMasterCtx *master_config = output_ctx->data; strlcpy(master_config->path, dir, sizeof(master_config->path)); TAILQ_INIT(&output_ctx->submodules); @@ -904,9 +904,8 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) return output_ctx; error: - if (output_ctx->DeInit && output_ctx->data) - output_ctx->DeInit(output_ctx->data); - SCFree(output_ctx); + if (output_ctx->DeInit) + output_ctx->DeInit(output_ctx); return NULL; } From ff3baeee90f7f2ea778d06be62bd236f85ed99eb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 5 Jul 2016 16:09:32 +0200 Subject: [PATCH 1553/2553] lua: support smtp tx logging --- src/output-lua.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/output-lua.c b/src/output-lua.c index eb32911337f2..77a7811f0df4 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -605,6 +605,8 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { options->alproto = ALPROTO_TLS; else if (strcmp(k,"protocol") == 0 && strcmp(v, "ssh") == 0) options->alproto = ALPROTO_SSH; + else if (strcmp(k,"protocol") == 0 && strcmp(v, "smtp") == 0) + options->alproto = ALPROTO_SMTP; else if (strcmp(k, "type") == 0 && strcmp(v, "packet") == 0) options->packet = 1; else if (strcmp(k, "filter") == 0 && strcmp(v, "alerts") == 0) @@ -877,6 +879,10 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) } else if (opts.alproto == ALPROTO_SSH) { om->PacketLogFunc = LuaPacketLoggerSsh; om->PacketConditionFunc = LuaPacketConditionSsh; + } else if (opts.alproto == ALPROTO_SMTP) { + om->TxLogFunc = LuaTxLogger; + om->alproto = ALPROTO_SMTP; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); } else if (opts.packet && opts.alerts) { om->PacketLogFunc = LuaPacketLoggerAlerts; om->PacketConditionFunc = LuaPacketConditionAlerts; From 7581f5129ffea93979fc9cd51c3ac2d07a41f285 Mon Sep 17 00:00:00 2001 From: tobiass1 <130472@hig.no> Date: Tue, 14 Jun 2016 22:28:50 -0400 Subject: [PATCH 1554/2553] Lua: SMTP support; Addresses feature ticket #1775; v5 --- src/Makefile.am | 1 + src/detect-lua-extensions.c | 2 + src/util-lua-smtp.c | 374 ++++++++++++++++++++++++++++++++++++ src/util-lua-smtp.h | 27 +++ 4 files changed, 404 insertions(+) create mode 100644 src/util-lua-smtp.c create mode 100644 src/util-lua-smtp.h diff --git a/src/Makefile.am b/src/Makefile.am index 65f175e8c512..be200cb6289a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -364,6 +364,7 @@ util-lua-dns.c util-lua-dns.h \ util-lua-http.c util-lua-http.h \ util-lua-tls.c util-lua-tls.h \ util-lua-ssh.c util-lua-ssh.h \ +util-lua-smtp.c util-lua-smtp.h \ util-magic.c util-magic.h \ util-memcmp.c util-memcmp.h \ util-memcpy.h \ diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index ae9b4e141272..44a8cfd216e1 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -68,6 +68,7 @@ #include "util-lua-dns.h" #include "util-lua-tls.h" #include "util-lua-ssh.h" +#include "util-lua-smtp.h" static const char luaext_key_ld[] = "suricata:luajitdata"; static const char luaext_key_det_ctx[] = "suricata:det_ctx"; @@ -621,6 +622,7 @@ int LuaRegisterExtensions(lua_State *lua_state) LuaRegisterDnsFunctions(lua_state); LuaRegisterTlsFunctions(lua_state); LuaRegisterSshFunctions(lua_state); + LuaRegisterSmtpFunctions(lua_state); return 0; } diff --git a/src/util-lua-smtp.c b/src/util-lua-smtp.c new file mode 100644 index 000000000000..1d0e4ed7e8cc --- /dev/null +++ b/src/util-lua-smtp.c @@ -0,0 +1,374 @@ +/* Copyright (C) 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 casec Bachelors group + * \author Lauritz Prag Sømme + * \author Levi Tobiassen + * \author Stian Hoel Bergseth + * \author Vinjar Hillestad + */ + +#include "suricata-common.h" + +#include "debug.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "output.h" + +#include "app-layer-smtp.h" + +#ifdef HAVE_LUA + +#include +#include + +#include "util-lua.h" +#include "util-lua-common.h" +#include "util-file.h" + +/* + * \brief internal function used by SMTPGetMimeField + * + * \param luastate luastate stack to use and push attributes to + * \param flow network flow of SMTP packets + * \param name name of the attribute to extract from MimeDecField + * + * \retval 1 if success mimefield found and pushed to stack. Returns error + * int and msg pushed to luastate stack if error occurs. + */ + +static int GetMimeDecField(lua_State *luastate, Flow *flow, const char *name) +{ + /* extract state from flow */ + SMTPState *state = (SMTPState *) FlowGetAppState(flow); + /* check that state exsists */ + if(state == NULL) { + return LuaCallbackError(luastate, "Internal error: no state in flow"); + } + /* pointer to current transaction in state */ + SMTPTransaction *smtp_tx = state->curr_tx; + if(smtp_tx == NULL) { + return LuaCallbackError(luastate, "Transaction ending or not found"); + } + /* pointer to tail of msg list of MimeDecEntitys in current transaction. */ + MimeDecEntity *mime = smtp_tx->msg_tail; + /* check if msg_tail was hit */ + if(mime == NULL){ + return LuaCallbackError(luastate, "Internal error: no fields in transaction"); + } + /* extract MIME field based on spesific field name. */ + MimeDecField *field = MimeDecFindField(mime, name); + /* check MIME field */ + if(field == NULL) { + return LuaCallbackError(luastate, "Error: mimefield not found"); + } + /* return extracted field. */ + if(field->value == NULL || field->value_len == 0){ + return LuaCallbackError(luastate, "Error, pointer error"); + } + + return LuaPushStringBuffer(luastate, field->value, field->value_len); +} + +/** + * \brief Function extracts specific MIME field based on argument from luastate + * stack then pushing the attribute onto the luastate stack. + * + * \param luastate luastate stack to pop and push attributes for I/O to lua + * + * \retval 1 if success mimefield found and pushed to stack. Returns error + * int and msg pushed to luastate stack if error occurs. + */ + +static int SMTPGetMimeField(lua_State *luastate) +{ + if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "error: protocol not SMTP"); + } + int lock_hint = 0; + Flow *flow = LuaStateGetFlow(luastate, &lock_hint); + /* check that flow exist */ + if(flow == NULL) { + return LuaCallbackError(luastate, "Error: no flow found"); + } + const char *name = LuaGetStringArgument(luastate, 1); + /* lock check */ + if(lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + FLOWLOCK_RDLOCK(flow); + /* get specific MIME field */ + GetMimeDecField(luastate, flow, name); + /* unlock flow mutex to allow for multithreading */ + FLOWLOCK_UNLOCK(flow); + /* return number of fields pushed to luastate */ + } else { /* if mutex already locked */ + GetMimeDecField(luastate, flow, name); + } + return 1; +} + +/** + * \brief Internal function used by SMTPGetMimeList + * + * \param luastate luastate stack to pop and push attributes for I/O to lua + * \param flow network flow of SMTP packets + * + * \retval 1 if the mimelist table is pushed to luastate stack. + * Returns error int and msg pushed to luastate stack if error occurs. +*/ + +static int GetMimeList(lua_State *luastate, Flow *flow) +{ + + SMTPState *state = (SMTPState *) FlowGetAppState(flow); + if(state == NULL) { + return LuaCallbackError(luastate, "Error: no SMTP state"); + } + /* Create a pointer to the current SMTPtransaction */ + SMTPTransaction *smtp_tx = state->curr_tx; + if(smtp_tx == NULL) { + return LuaCallbackError(luastate, "Error: no SMTP transaction found"); + } + /* Create a pointer to the tail of MimeDecEntity list */ + MimeDecEntity *mime = smtp_tx->msg_tail; + if(mime == NULL) { + return LuaCallbackError(luastate, "Error: no mime entity found"); + } + MimeDecField *field = mime->field_list; + if(field == NULL) { + return LuaCallbackError(luastate, "Error: no field_list found"); + } + if(field->name == NULL || field->name_len == 0) { + return LuaCallbackError(luastate, "Error: field has no name"); + } + /* Counter of MIME fields found */ + int num = 1; + /* loop trough the list of mimeFields, printing each name found */ + lua_newtable(luastate); + while (field != NULL) { + if(field->name != NULL && field->name_len != 0) { + lua_pushinteger(luastate,num++); + LuaPushStringBuffer(luastate, field->name, field->name_len); + lua_settable(luastate,-3); + } + field = field->next; + } + return 1; +} + +/** + * \brief Lists name and value to all MIME fields which + * is included in a SMTP transaction. + * + * \param luastate luastate stack to pop and push attributes for I/O to lua. + * + * \retval 1 if the table is pushed to lua. + * Returns error int and msg pushed to luastate stack if error occurs + * + */ + +static int SMTPGetMimeList(lua_State *luastate) +{ + /* Check if right protocol */ + if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "Error: protocol not SMTP"); + } + /* mutex lock indicator var */ + int lock_hint = 0; + /* Extract network flow */ + Flow *flow = LuaStateGetFlow(luastate, &lock_hint); + if(flow == NULL) { + return LuaCallbackError(luastate, "Error: no flow found"); + } + /* check if flow already locked */ + if(lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + /* mutexlock flow */ + FLOWLOCK_RDLOCK(flow); + GetMimeList(luastate, flow); + FLOWLOCK_UNLOCK(flow); + } else { + GetMimeList(luastate, flow); + } + return 1; +} + +/** + * \brief internal function used by SMTPGetMailFrom + * + * \param luastate luastate stack to pop and push attributes for I/O to lua. + * \param flow flow to get state for SMTP + * + * \retval 1 if mailfrom field found. + * Retruns error int and msg pushed to luastate stack if error occurs + */ + +static int GetMailFrom(lua_State *luastate, Flow *flow) +{ + /* Extract SMTPstate from current flow */ + SMTPState *state = (SMTPState *) FlowGetAppState(flow); + + if(state == NULL) { + return LuaCallbackError(luastate, "Internal Error: no state"); + } + SMTPTransaction *smtp_tx = state->curr_tx; + if(smtp_tx == NULL) { + return LuaCallbackError(luastate, "Internal Error: no SMTP transaction"); + } + if(smtp_tx->mail_from == NULL || smtp_tx->mail_from_len == 0) { + return LuaCallbackError(luastate, "MailFrom not found"); + } + return LuaPushStringBuffer(luastate, smtp_tx->mail_from, smtp_tx->mail_from_len); + /* Returns 1 because we never push more then 1 item to the lua stack */ +} + +/** + * \brief Extracts mail_from parameter from SMTPState. + * Attribute may also be available from mimefields, although there is no + * guarantee of it existing as mime. + * + * \param luastate luastate stack to pop and push attributes for I/O to lua. + * + * \retval 1 if mailfrom field found. + * Retruns error int and msg pushed to luastate stack if error occurs + */ + +static int SMTPGetMailFrom(lua_State *luastate) +{ + /* check protocol */ + if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "Error: protocol not SMTP"); + } + /* use lock_hint to check for mutexlock on flow */ + int lock_hint = 0; + /* Extract flow, with lockhint to check mutexlocking */ + Flow *flow = LuaStateGetFlow(luastate, &lock_hint); + if(flow == NULL) { + return LuaCallbackError(luastate, "Internal Error: no flow"); + } + /* check if already mutexlocked by parents */ + if(lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + /* mutexlock flow */ + FLOWLOCK_RDLOCK(flow); + GetMailFrom(luastate, flow); + FLOWLOCK_UNLOCK(flow); + } else { + GetMailFrom(luastate, flow); + } + return 1; +} + +/** + * \brief intern function used by SMTPGetRcpList + * + * \params luastate luastate stack for internal communication with Lua. + * Used to hand over data to the recieveing luascript. + * + * \retval 1 if the table is pushed to lua. + * Returns error int and msg pushed to luastate stack if error occurs + */ + +static int GetRcptList(lua_State *luastate, Flow *flow) +{ + + SMTPState *state = (SMTPState *) FlowGetAppState(flow); + if(state == NULL) { + return LuaCallbackError(luastate, "Internal error, no state"); + } + + SMTPTransaction *smtp_tx = state->curr_tx; + if(smtp_tx == NULL) { + return LuaCallbackError(luastate, "No more tx, or tx not found"); + } + + /* Create a new table in luastate for rcpt list */ + lua_newtable(luastate); + /* rcpt var for iterator */ + int u = 1; + SMTPString *rcpt; + + TAILQ_FOREACH(rcpt, &smtp_tx->rcpt_to_list, next) { + LuaPushStringBuffer(luastate, rcpt->str, rcpt->len); + lua_pushinteger(luastate, u++); + lua_settable(luastate, -3); + } + /* return 1 since we allways push one table to luastate */ + return 1; +} + +/** + * \brief function loops through rcpt-list located in + * flow->SMTPState->SMTPTransaction, adding all items to a table. + * Then pushing it to the luastate stack. + * + * \params luastate luastate stack for internal communication with Lua. + * Used to hand over data to the recieveing luascript. + * + * \retval 1 if the table is pushed to lua. + * Returns error int and msg pushed to luastate stack if error occurs + */ + +static int SMTPGetRcptList(lua_State *luastate) +{ + /* check protocol */ + if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "Error: protocol not SMTP"); + } + /* create lockhint var for flowlock check. */ + int lock_hint = 0; + /* Extract flow, with lockhint to check mutexlocking */ + Flow *flow = LuaStateGetFlow(luastate, &lock_hint); + if(flow == NULL) { + return LuaCallbackError(luastate, "Internal error: no flow"); + } + /* check if already mutexlocked by parents */ + if(lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { + /* lock flow */ + FLOWLOCK_RDLOCK(flow); + GetRcptList(luastate, flow); + /* open flow */ + FLOWLOCK_UNLOCK(flow); + } else { + GetRcptList(luastate, flow); + } + /* return 1 since we allways push one table to luastate */ + return 1; +} + +int LuaRegisterSmtpFunctions(lua_State *luastate) +{ + + lua_pushcfunction(luastate, SMTPGetMimeField); + lua_setglobal(luastate, "SMTPGetMimeField"); + + lua_pushcfunction(luastate, SMTPGetMimeList); + lua_setglobal(luastate, "SMTPGetMimeList"); + + lua_pushcfunction(luastate, SMTPGetMailFrom); + lua_setglobal(luastate, "SMTPGetMailFrom"); + + lua_pushcfunction(luastate, SMTPGetRcptList); + lua_setglobal(luastate, "SMTPGetRcptList"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-smtp.h b/src/util-lua-smtp.h new file mode 100644 index 000000000000..26750b8fbf22 --- /dev/null +++ b/src/util-lua-smtp.h @@ -0,0 +1,27 @@ +/* Copyright (C) 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. + */ + +#ifndef __UTIL_LUA_SMTP_H__ +#define __UTIL_LUA_SMTP_H__ + +#ifdef HAVE_LUA + +int LuaRegisterSmtpFunctions(lua_State *luastate); + +#endif /* HAVE_LUA */ + +#endif /* __UTIL_LUA_SMTP_H__ */ From 7501bf744f74ea3072f056d83872c0ca9e492d3c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 6 Jul 2016 12:57:22 +0200 Subject: [PATCH 1555/2553] lua: SMTPGetRcptList use position as key, not value --- src/util-lua-smtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-lua-smtp.c b/src/util-lua-smtp.c index 1d0e4ed7e8cc..f18bea1b3c78 100644 --- a/src/util-lua-smtp.c +++ b/src/util-lua-smtp.c @@ -306,8 +306,8 @@ static int GetRcptList(lua_State *luastate, Flow *flow) SMTPString *rcpt; TAILQ_FOREACH(rcpt, &smtp_tx->rcpt_to_list, next) { - LuaPushStringBuffer(luastate, rcpt->str, rcpt->len); lua_pushinteger(luastate, u++); + LuaPushStringBuffer(luastate, rcpt->str, rcpt->len); lua_settable(luastate, -3); } /* return 1 since we allways push one table to luastate */ From 928cb1eba9cd6ee2cef801d1c5c09e5a094e8305 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 6 Jul 2016 12:58:37 +0200 Subject: [PATCH 1556/2553] lua output: expose smtp functions to output scripts --- src/output-lua.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output-lua.c b/src/output-lua.c index 77a7811f0df4..e3d45566605b 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -61,6 +61,7 @@ #include "util-lua-dns.h" #include "util-lua-tls.h" #include "util-lua-ssh.h" +#include "util-lua-smtp.h" #define MODULE_NAME "LuaLog" @@ -710,6 +711,7 @@ static lua_State *LuaScriptSetup(const char *filename) LuaRegisterDnsFunctions(luastate); LuaRegisterTlsFunctions(luastate); LuaRegisterSshFunctions(luastate); + LuaRegisterSmtpFunctions(luastate); if (lua_pcall(luastate, 0, 0, 0) != 0) { SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'setup' function: %s", lua_tostring(luastate, -1)); From da8f9c1896adfd6146c5a20fb09a315c847e80df Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 6 Jul 2016 13:08:02 +0200 Subject: [PATCH 1557/2553] lua: add smtp for detection --- src/detect-lua.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/detect-lua.c b/src/detect-lua.c index a05583e00359..99cb13be3776 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -165,8 +165,8 @@ void DetectLuaRegister(void) #define DATATYPE_DNS_RESPONSE (1<<17) #define DATATYPE_TLS (1<<18) - #define DATATYPE_SSH (1<<19) +#define DATATYPE_SMTP (1<<20) #ifdef HAVE_LUAJIT static void *LuaStatePoolAlloc(void) @@ -1027,6 +1027,12 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) ld->flags |= DATATYPE_SSH; + } else if (strncmp(k, "smtp", 4) == 0 && strcmp(v, "true") == 0) { + + ld->alproto = ALPROTO_SMTP; + + ld->flags |= DATATYPE_SMTP; + } else { SCLogError(SC_ERR_LUA_ERROR, "unsupported data type %s", k); goto error; @@ -1126,6 +1132,8 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); } else if (luajit->alproto == ALPROTO_SSH) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + } else if (luajit->alproto == ALPROTO_SMTP) { + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); } else { SCLogError(SC_ERR_LUA_ERROR, "luajit can't be used with protocol %s", AppLayerGetProtoName(luajit->alproto)); From 3bb408940fc130caa36d79dd803320b30d439a0b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 1 Jul 2016 16:03:53 +0200 Subject: [PATCH 1558/2553] af-packet: improve threads selection logic Only use RSS queue count when cluster_qm is used. Only use core count when cluster_flow is used. Use a local variable to simplify the check so that we don't have to deal with the extra flags. --- src/runmode-af-packet.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index d230eabbba8f..0de06c12b986 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -122,6 +122,7 @@ void *ParseAFPConfig(const char *iface) int boolval; char *bpf_filter = NULL; char *out_iface = NULL; + int cluster_type = PACKET_FANOUT_HASH; if (iface == NULL) { return NULL; @@ -138,7 +139,7 @@ void *ParseAFPConfig(const char *iface) (void) SC_ATOMIC_ADD(aconf->ref, 1); aconf->buffer_size = 0; aconf->cluster_id = 1; - aconf->cluster_type = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; + aconf->cluster_type = cluster_type | PACKET_FANOUT_FLAG_DEFRAG; aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; aconf->DerefFunc = AFPDerefConfig; @@ -283,10 +284,12 @@ void *ParseAFPConfig(const char *iface) if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) { /* default to our safest choice: flow hashing + defrag enabled */ aconf->cluster_type = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; + cluster_type = PACKET_FANOUT_HASH; } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { SCLogConfig("Using round-robin cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_LB; + cluster_type = PACKET_FANOUT_LB; } else if (strcmp(tmpctype, "cluster_flow") == 0) { /* In hash mode, we also ask for defragmentation needed to * compute the hash */ @@ -301,22 +304,27 @@ void *ParseAFPConfig(const char *iface) defrag = PACKET_FANOUT_FLAG_DEFRAG; } aconf->cluster_type = PACKET_FANOUT_HASH | defrag; + cluster_type = PACKET_FANOUT_HASH; } else if (strcmp(tmpctype, "cluster_cpu") == 0) { SCLogConfig("Using cpu cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_CPU; + cluster_type = PACKET_FANOUT_CPU; } else if (strcmp(tmpctype, "cluster_qm") == 0) { SCLogConfig("Using queue based cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_QM; + cluster_type = PACKET_FANOUT_QM; } else if (strcmp(tmpctype, "cluster_random") == 0) { SCLogConfig("Using random based cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_RND; + cluster_type = PACKET_FANOUT_RND; } else if (strcmp(tmpctype, "cluster_rollover") == 0) { SCLogConfig("Using rollover based cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_ROLLOVER; + cluster_type = PACKET_FANOUT_ROLLOVER; } else { SCLogWarning(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); @@ -401,17 +409,20 @@ void *ParseAFPConfig(const char *iface) /* try to automagically set the proper number of threads */ if (aconf->threads == 0) { - int rss_queues; - aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); - /* Get the number of RSS queues and take the min */ - rss_queues = GetIfaceRSSQueuesNum(iface); - if (rss_queues > 0) { - if (rss_queues < aconf->threads) { + /* for cluster_flow use core count */ + if (cluster_type == PACKET_FANOUT_HASH) { + aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); + SCLogPerf("%u cores, so using %u threads", aconf->threads, aconf->threads); + + /* for cluster_qm use RSS queue count */ + } else if (cluster_type == PACKET_FANOUT_QM) { + int rss_queues = GetIfaceRSSQueuesNum(iface); + if (rss_queues > 0) { aconf->threads = rss_queues; - SCLogInfo("More cores than RSS queues, using %d threads " - "for interface %s", aconf->threads, iface); + SCLogPerf("%d RSS queues, so using %u threads", rss_queues, aconf->threads); } } + if (aconf->threads) { SCLogPerf("Using %d AF_PACKET threads for interface %s", aconf->threads, iface); From b73098e990ccc48e8473157ed65c9e1e03cd01f6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 6 Jul 2016 13:48:14 +0200 Subject: [PATCH 1559/2553] smb: style fix in log message --- src/app-layer-smb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 22a9439e0918..d79b5b959182 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -1546,7 +1546,7 @@ void RegisterSMBParsers(void) AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMB, STREAM_TOCLIENT, SMBParseResponse); AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMB, SMBStateAlloc, SMBStateFree); } else { - SCLogInfo("Parsed disabled for %s protocol. Protocol detection" + SCLogInfo("Parsed disabled for %s protocol. Protocol detection " "still on.", proto_name); } From f302a6cf8656cd889f6a8dbae342af27a1e9e8ce Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 6 Jul 2016 16:08:55 +0200 Subject: [PATCH 1560/2553] output: fix debug messages --- src/output-file.c | 2 +- src/output-filedata.c | 2 +- src/output-streaming.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/output-file.c b/src/output-file.c index bd266c77ac74..7defa39a0b0d 100644 --- a/src/output-file.c +++ b/src/output-file.c @@ -80,7 +80,7 @@ int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, OutputCtx *ou t->next = op; } - SCLogDebug("OutputRegisterTxLogger happy"); + SCLogDebug("OutputRegisterFileLogger happy"); return 0; } diff --git a/src/output-filedata.c b/src/output-filedata.c index d77e837fd16d..43f36c066456 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -85,7 +85,7 @@ int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, Outpu t->next = op; } - SCLogDebug("OutputRegisterTxLogger happy"); + SCLogDebug("OutputRegisterFiledataLogger happy"); return 0; } diff --git a/src/output-streaming.c b/src/output-streaming.c index 234fbee70ebd..295506620347 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -86,7 +86,7 @@ int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, t->next = op; } - SCLogDebug("OutputRegisterTxLogger happy"); + SCLogDebug("OutputRegisterStreamingLogger happy"); return 0; } From 01913f6a566f2b60d47f6cee59fa3b323f604a8a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 6 Jul 2016 16:21:33 +0200 Subject: [PATCH 1561/2553] app-layer: add AppLayerParserIsTxAware This function globally checks if the protocol is registered and enabled by testing for the per alproto callback: StateGetProgressCompletionStatus This check is to be used before enabling Tx-aware code, like loggers. --- src/app-layer-parser.c | 9 +++++++++ src/app-layer-parser.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 14942d167939..4c0e9b8ee79b 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -1076,6 +1076,15 @@ int AppLayerParserHasDecoderEvents(uint8_t ipproto, AppProto alproto, SCReturnInt(1); } +/** \brief simpler way to globally test if a alproto is registered + * and fully enabled in the configuration. + */ +int AppLayerParserIsTxAware(AppProto alproto) +{ + return (alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto] + .StateGetProgressCompletionStatus != NULL); +} + int AppLayerParserProtocolIsTxAware(uint8_t ipproto, AppProto alproto) { SCEnter(); diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index 7a319510c688..cad9ec31821e 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -197,6 +197,7 @@ int AppLayerParserParse(AppLayerParserThreadCtx *tctx, Flow *f, AppProto alproto void AppLayerParserSetEOF(AppLayerParserState *pstate); int AppLayerParserHasDecoderEvents(uint8_t ipproto, AppProto alproto, void *alstate, AppLayerParserState *pstate, uint8_t flags); +int AppLayerParserIsTxAware(AppProto alproto); int AppLayerParserProtocolIsTxAware(uint8_t ipproto, AppProto alproto); int AppLayerParserProtocolIsTxEventAware(uint8_t ipproto, AppProto alproto); int AppLayerParserProtocolSupportsTxs(uint8_t ipproto, AppProto alproto); From ed483b4e13c441abac7b1c1ad363e27bcaff3fa7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 6 Jul 2016 16:33:20 +0200 Subject: [PATCH 1562/2553] output: don't register loggers for disabled protocols --- src/output-tx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/output-tx.c b/src/output-tx.c index e94e418897f4..a2a6e284e597 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -67,6 +67,12 @@ int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, if (module_id < 0) return -1; + if (!(AppLayerParserIsTxAware(alproto))) { + SCLogNotice("%s logger not enabled: protocol %s is disabled", + name, AppProtoToString(alproto)); + return -1; + } + OutputTxLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; From 2b10b8374c970426dac6c9aaea37dd0bf3e92afd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 Jul 2016 11:24:27 +0200 Subject: [PATCH 1563/2553] cmdline: fix --list-keywords and --list-app-layer-protos Ticket #1840 --- src/util-running-modes.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util-running-modes.c b/src/util-running-modes.c index 8ad5a1eea862..30699c40c3c0 100644 --- a/src/util-running-modes.c +++ b/src/util-running-modes.c @@ -35,6 +35,7 @@ int ListKeywords(const char *keyword_info) if (ConfYamlLoadFile(DEFAULT_CONF_FILE) != -1) SCLogLoadConfig(0, 0); MpmTableSetup(); + SpmTableSetup(); AppLayerSetup(); SigTableSetup(); /* load the rule keywords */ SigTableList(keyword_info); @@ -46,6 +47,7 @@ int ListAppLayerProtocols() if (ConfYamlLoadFile(DEFAULT_CONF_FILE) != -1) SCLogLoadConfig(0, 0); MpmTableSetup(); + SpmTableSetup(); AppLayerSetup(); AppLayerListSupportedProtocols(); From 37b10c13c104d2b21d964378860d8c6ff299810d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 Jul 2016 11:26:24 +0200 Subject: [PATCH 1564/2553] configure: require libhtp 0.5.20 Ticket #1839 --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d553ff3532e7..462058477bcf 100644 --- a/configure.ac +++ b/configure.ac @@ -1251,12 +1251,12 @@ echo exit 1 fi - PKG_CHECK_MODULES(LIBHTPMINVERSION, [htp >= 0.5.5],[libhtp_minver_found="yes"],[libhtp_minver_found="no"]) + PKG_CHECK_MODULES(LIBHTPMINVERSION, [htp >= 0.5.20],[libhtp_minver_found="yes"],[libhtp_minver_found="no"]) if test "$libhtp_minver_found" = "no"; then PKG_CHECK_MODULES(LIBHTPDEVVERSION, [htp = 0.5.X],[libhtp_devver_found="yes"],[libhtp_devver_found="no"]) if test "$libhtp_devver_found" = "no"; then echo - echo " ERROR! libhtp was found but it is neither >= 0.5.5, nor the dev 0.5.X" + echo " ERROR! libhtp was found but it is neither >= 0.5.20, nor the dev 0.5.X" echo exit 1 fi From 9d01ef58fcb4519608a4533496a8478a1be15f7b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 11 Jul 2016 09:30:26 +0200 Subject: [PATCH 1565/2553] lua smtp: fix SMTPGetMimeField arg checking Properly check argument before passing it on: CID 1363385: (NULL_RETURNS) --- src/util-lua-smtp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util-lua-smtp.c b/src/util-lua-smtp.c index f18bea1b3c78..a64c7098323e 100644 --- a/src/util-lua-smtp.c +++ b/src/util-lua-smtp.c @@ -112,6 +112,9 @@ static int SMTPGetMimeField(lua_State *luastate) return LuaCallbackError(luastate, "Error: no flow found"); } const char *name = LuaGetStringArgument(luastate, 1); + if (name == NULL) + return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); + /* lock check */ if(lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { FLOWLOCK_RDLOCK(flow); From fcad270d9656c9b9d498f884989838faaed4ee79 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 11 Jul 2016 11:34:45 -0600 Subject: [PATCH 1566/2553] logging: setup all registered loggers for a name When setting up a configured logger, do so for all registered loggers of that name instead of just the first registered one. This allows a logger to register itself more than once, which can allow for independent logging of requests and replies without touching the core transaction handling logic. We do this so just having "dns" in the eve-log can configured multiple "dns" loggers instead of having something like "dns-tc" and "dns-ts" in the configuration file. --- src/output-tx.c | 12 +-- src/output.c | 11 ++- src/output.h | 3 + src/runmodes.c | 221 +++++++++++++++++++++++++++--------------------- 4 files changed, 139 insertions(+), 108 deletions(-) diff --git a/src/output-tx.c b/src/output-tx.c index a2a6e284e597..093e2e593180 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -85,20 +85,20 @@ int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, op->name = name; op->module_id = (TmmId) module_id; - if (tc_log_progress) { - op->tc_log_progress = tc_log_progress; - } else { + if (tc_log_progress < 0) { op->tc_log_progress = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT); + } else { + op->tc_log_progress = tc_log_progress; } - if (ts_log_progress) { - op->ts_log_progress = ts_log_progress; - } else { + if (ts_log_progress < 0) { op->ts_log_progress = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER); + } else { + op->ts_log_progress = ts_log_progress; } if (list == NULL) { diff --git a/src/output.c b/src/output.c index e0f86ae0fda5..64b6702be211 100644 --- a/src/output.c +++ b/src/output.c @@ -31,8 +31,7 @@ #include "util-debug.h" #include "output.h" -static TAILQ_HEAD(, OutputModule_) output_modules = - TAILQ_HEAD_INITIALIZER(output_modules); +OutputModuleList output_modules = TAILQ_HEAD_INITIALIZER(output_modules); /** * Registry of flags to be updated on file rotation notification. @@ -234,7 +233,7 @@ void OutputRegisterTxModuleWithCondition(const char *name, const char *conf_name TxLogger TxLogFunc, TxLoggerCondition TxLogCondition) { OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, - TxLogFunc, 0, 0, TxLogCondition); + TxLogFunc, -1, -1, TxLogCondition); } void OutputRegisterTxSubModuleWithCondition(const char *parent_name, @@ -243,7 +242,7 @@ void OutputRegisterTxSubModuleWithCondition(const char *parent_name, TxLoggerCondition TxLogCondition) { OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, InitFunc, - alproto, TxLogFunc, 0, 0, + alproto, TxLogFunc, -1, -1, TxLogCondition); } @@ -288,7 +287,7 @@ OutputRegisterTxModule(const char *name, const char *conf_name, TxLogger TxLogFunc) { OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, - TxLogFunc, 0, 0, NULL); + TxLogFunc, -1, -1, NULL); } void @@ -297,7 +296,7 @@ OutputRegisterTxSubModule(const char *parent_name, const char *name, AppProto alproto, TxLogger TxLogFunc) { OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, - InitFunc, alproto, TxLogFunc, 0, 0, NULL); + InitFunc, alproto, TxLogFunc, -1, -1, NULL); } /** diff --git a/src/output.h b/src/output.h index 91d8bd2708c1..00425bf94f93 100644 --- a/src/output.h +++ b/src/output.h @@ -62,6 +62,9 @@ typedef struct OutputModule_ { TAILQ_ENTRY(OutputModule_) entries; } OutputModule; +typedef TAILQ_HEAD(OutputModuleList_, OutputModule_) OutputModuleList; +extern OutputModuleList output_modules; + void OutputRegisterModule(const char *, const char *, OutputCtx *(*)(ConfNode *)); void OutputRegisterPacketModule(const char *name, const char *conf_name, diff --git a/src/runmodes.c b/src/runmodes.c index 9a9e5b53c08c..2ca3fd03a903 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -718,6 +718,96 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } +static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) { + ConfNode *types = ConfNodeLookupChild(conf, "types"); + SCLogDebug("types %p", types); + if (types != NULL) { + ConfNode *type = NULL; + TAILQ_FOREACH(type, &types->head, next) { + SCLogConfig("enabling 'eve-log' module '%s'", type->val); + + int sub_count = 0; + char subname[256]; + snprintf(subname, sizeof(subname), "eve-log.%s", type->val); + + /* Now setup all registers logger of this name. */ + OutputModule *sub_module; + TAILQ_FOREACH(sub_module, &output_modules, entries) { + if (strcmp(subname, sub_module->conf_name) == 0) { + sub_count++; + + if (sub_module->parent_name == NULL || + strcmp(sub_module->parent_name, "eve-log") != 0) { + FatalError(SC_ERR_INVALID_ARGUMENT, + "bad parent for %s", subname); + } + if (sub_module->InitSubFunc == NULL) { + FatalError(SC_ERR_INVALID_ARGUMENT, + "bad sub-module for %s", subname); + } + ConfNode *sub_output_config = + ConfNodeLookupChild(type, type->val); + // sub_output_config may be NULL if no config + + /* pass on parent output_ctx */ + OutputCtx *sub_output_ctx = + sub_module->InitSubFunc(sub_output_config, + parent_ctx); + if (sub_output_ctx == NULL) { + continue; + } + + AddOutputToFreeList(sub_module, sub_output_ctx); + SetupOutput(sub_module->name, sub_module, + sub_output_ctx); + } + } + + /* Error is no registered loggers with this name + * were found .*/ + if (!sub_count) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + "No output module named %s", subname); + continue; + } + } + } +} + +static void RunModeInitializeLuaOutput(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputModule *lua_module = OutputGetModuleByConfName("lua"); + BUG_ON(lua_module == NULL); + + ConfNode *scripts = ConfNodeLookupChild(conf, "scripts"); + BUG_ON(scripts == NULL); //TODO + + OutputModule *m; + TAILQ_FOREACH(m, &parent_ctx->submodules, entries) { + SCLogDebug("m %p %s:%s", m, m->name, m->conf_name); + + ConfNode *script = NULL; + TAILQ_FOREACH(script, &scripts->head, next) { + SCLogDebug("script %s", script->val); + if (strcmp(script->val, m->conf_name) == 0) { + break; + } + } + BUG_ON(script == NULL); + + /* pass on parent output_ctx */ + OutputCtx *sub_output_ctx = + m->InitSubFunc(script, parent_ctx); + if (sub_output_ctx == NULL) { + SCLogInfo("sub_output_ctx NULL, skipping"); + continue; + } + + AddOutputToFreeList(m, sub_output_ctx); + SetupOutput(m->name, m, sub_output_ctx); + } +} + /** * Initialize the output modules. */ @@ -787,112 +877,51 @@ void RunModeInitializeOutputs(void) tls_log_enabled = 1; } - OutputModule *module = OutputGetModuleByConfName(output->val); - if (module == NULL) { - FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, - "No output module named %s", output->val); - continue; - } - - OutputCtx *output_ctx = NULL; - if (module->InitFunc != NULL) { - output_ctx = module->InitFunc(output_config); - if (output_ctx == NULL) { - FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, "output module setup failed"); + OutputModule *module; + int count = 0; + TAILQ_FOREACH(module, &output_modules, entries) { + if (strcmp(module->conf_name, output->val) != 0) { continue; } - } else if (module->InitSubFunc != NULL) { - SCLogInfo("skipping submodule"); - continue; - } - - // TODO if module == parent, find it's children - if (strcmp(output->val, "eve-log") == 0) { - ConfNode *types = ConfNodeLookupChild(output_config, "types"); - SCLogDebug("types %p", types); - if (types != NULL) { - ConfNode *type = NULL; - TAILQ_FOREACH(type, &types->head, next) { - SCLogConfig("enabling 'eve-log' module '%s'", type->val); - - char subname[256]; - snprintf(subname, sizeof(subname), "%s.%s", output->val, type->val); - - OutputModule *sub_module = OutputGetModuleByConfName(subname); - if (sub_module == NULL) { - FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, - "No output module named %s", subname); - continue; - } - if (sub_module->parent_name == NULL || - strcmp(sub_module->parent_name,output->val) != 0) { - FatalError(SC_ERR_INVALID_ARGUMENT, - "bad parent for %s", subname); - } - if (sub_module->InitSubFunc == NULL) { - FatalError(SC_ERR_INVALID_ARGUMENT, - "bad sub-module for %s", subname); - } - ConfNode *sub_output_config = ConfNodeLookupChild(type, type->val); - // sub_output_config may be NULL if no config - /* pass on parent output_ctx */ - OutputCtx *sub_output_ctx = - sub_module->InitSubFunc(sub_output_config, output_ctx); - if (sub_output_ctx == NULL) { - continue; - } + count++; - AddOutputToFreeList(sub_module, sub_output_ctx); - SetupOutput(sub_module->name, sub_module, sub_output_ctx); + OutputCtx *output_ctx = NULL; + if (module->InitFunc != NULL) { + output_ctx = module->InitFunc(output_config); + if (output_ctx == NULL) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + "output module setup failed"); + continue; } - } - /* add 'eve-log' to free list as it's the owner of the - * main output ctx from which the sub-modules share the - * LogFileCtx */ - AddOutputToFreeList(module, output_ctx); - - } else if (strcmp(output->val, "lua") == 0) { - SCLogDebug("handle lua"); - - if (output_ctx == NULL) + } else if (module->InitSubFunc != NULL) { + SCLogInfo("skipping submodule"); continue; + } - OutputModule *lua_module = OutputGetModuleByConfName(output->val); - BUG_ON(lua_module == NULL); - AddOutputToFreeList(lua_module, output_ctx); - - ConfNode *scripts = ConfNodeLookupChild(output_config, "scripts"); - BUG_ON(scripts == NULL); //TODO - - OutputModule *m; - TAILQ_FOREACH(m, &output_ctx->submodules, entries) { - SCLogDebug("m %p %s:%s", m, m->name, m->conf_name); + // TODO if module == parent, find it's children + if (strcmp(output->val, "eve-log") == 0) { + RunModeInitializeEveOutput(output_config, output_ctx); - ConfNode *script = NULL; - TAILQ_FOREACH(script, &scripts->head, next) { - SCLogDebug("script %s", script->val); - if (strcmp(script->val, m->conf_name) == 0) { - break; - } - } - BUG_ON(script == NULL); - - /* pass on parent output_ctx */ - OutputCtx *sub_output_ctx = - m->InitSubFunc(script, output_ctx); - if (sub_output_ctx == NULL) { - SCLogInfo("sub_output_ctx NULL, skipping"); + /* add 'eve-log' to free list as it's the owner of the + * main output ctx from which the sub-modules share the + * LogFileCtx */ + AddOutputToFreeList(module, output_ctx); + } else if (strcmp(output->val, "lua") == 0) { + SCLogDebug("handle lua"); + if (output_ctx == NULL) continue; - } - - AddOutputToFreeList(m, sub_output_ctx); - SetupOutput(m->name, m, sub_output_ctx); + RunModeInitializeLuaOutput(output_config, output_ctx); + AddOutputToFreeList(module, output_ctx); + } else { + AddOutputToFreeList(module, output_ctx); + SetupOutput(module->name, module, output_ctx); } - - } else { - AddOutputToFreeList(module, output_ctx); - SetupOutput(module->name, module, output_ctx); + } + if (count == 0) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + "No output module named %s", output->val); + continue; } } From f397e7bfc23f632fde4c4ded5e0dfec5022bea5e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 11 Jul 2016 11:35:51 -0600 Subject: [PATCH 1567/2553] dns: directional logging Register loggers for to server and to client so requests and responses can be logged independently of each other. This results in the request log having the actual timestamp of the request instead of the reply. --- src/output-json-dns.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/output-json-dns.c b/src/output-json-dns.c index db8ae40f17d5..11173ccc0e54 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -274,7 +274,8 @@ static void LogAnswers(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uin } -static int JsonDnsLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id) +static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data, + const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id) { SCEnter(); @@ -293,6 +294,18 @@ static int JsonDnsLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flo json_decref(js); } + SCReturnInt(TM_ECODE_OK); +} + +static int JsonDnsLoggerToClient(ThreadVars *tv, void *thread_data, + const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id) +{ + SCEnter(); + + LogDnsLogThread *td = (LogDnsLogThread *)thread_data; + DNSTransaction *tx = txptr; + json_t *js; + js = CreateJSONHeader((Packet *)p, 0, "dns"); if (unlikely(js == NULL)) return TM_ECODE_OK; @@ -449,10 +462,21 @@ void TmModuleJsonDnsLogRegister (void) tmm_modules[TMM_JSONDNSLOG].cap_flags = 0; tmm_modules[TMM_JSONDNSLOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterTxModule(MODULE_NAME, "dns-json-log", JsonDnsLogInitCtx, - ALPROTO_DNS, JsonDnsLogger); - OutputRegisterTxSubModule("eve-log", MODULE_NAME, "eve-log.dns", JsonDnsLogInitCtxSub, - ALPROTO_DNS, JsonDnsLogger); + /* Logger for requests. */ + OutputRegisterTxModuleWithProgress(MODULE_NAME, "dns-json-log", + JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToServer, 0, 1); + + /* Logger for replies. */ + OutputRegisterTxModuleWithProgress(MODULE_NAME, "dns-json-log", + JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToClient, 1, 1); + + /* Sub-logger for requests. */ + OutputRegisterTxSubModuleWithProgress("eve-log", MODULE_NAME, "eve-log.dns", + JsonDnsLogInitCtxSub, ALPROTO_DNS, JsonDnsLoggerToServer, 0, 1); + + /* Sub-logger for replies. */ + OutputRegisterTxSubModuleWithProgress("eve-log", MODULE_NAME, "eve-log.dns", + JsonDnsLogInitCtxSub, ALPROTO_DNS, JsonDnsLoggerToClient, 1, 1); } #else From 7188c2630fc529e6bcd262b620b27b3bebe0e0f1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 12 Jul 2016 08:49:48 +0200 Subject: [PATCH 1568/2553] outputs: small code cleanup --- src/runmodes.c | 83 ++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/src/runmodes.c b/src/runmodes.c index 2ca3fd03a903..f9bc02938bb7 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -718,58 +718,61 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } -static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) { +static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) +{ ConfNode *types = ConfNodeLookupChild(conf, "types"); SCLogDebug("types %p", types); - if (types != NULL) { - ConfNode *type = NULL; - TAILQ_FOREACH(type, &types->head, next) { - SCLogConfig("enabling 'eve-log' module '%s'", type->val); - - int sub_count = 0; - char subname[256]; - snprintf(subname, sizeof(subname), "eve-log.%s", type->val); - - /* Now setup all registers logger of this name. */ - OutputModule *sub_module; - TAILQ_FOREACH(sub_module, &output_modules, entries) { - if (strcmp(subname, sub_module->conf_name) == 0) { - sub_count++; - - if (sub_module->parent_name == NULL || + if (types == NULL) { + return; + } + + ConfNode *type = NULL; + TAILQ_FOREACH(type, &types->head, next) { + SCLogConfig("enabling 'eve-log' module '%s'", type->val); + + int sub_count = 0; + char subname[256]; + snprintf(subname, sizeof(subname), "eve-log.%s", type->val); + + /* Now setup all registers logger of this name. */ + OutputModule *sub_module; + TAILQ_FOREACH(sub_module, &output_modules, entries) { + if (strcmp(subname, sub_module->conf_name) == 0) { + sub_count++; + + if (sub_module->parent_name == NULL || strcmp(sub_module->parent_name, "eve-log") != 0) { - FatalError(SC_ERR_INVALID_ARGUMENT, + FatalError(SC_ERR_INVALID_ARGUMENT, "bad parent for %s", subname); - } - if (sub_module->InitSubFunc == NULL) { - FatalError(SC_ERR_INVALID_ARGUMENT, + } + if (sub_module->InitSubFunc == NULL) { + FatalError(SC_ERR_INVALID_ARGUMENT, "bad sub-module for %s", subname); - } - ConfNode *sub_output_config = - ConfNodeLookupChild(type, type->val); - // sub_output_config may be NULL if no config + } + ConfNode *sub_output_config = + ConfNodeLookupChild(type, type->val); + // sub_output_config may be NULL if no config - /* pass on parent output_ctx */ - OutputCtx *sub_output_ctx = - sub_module->InitSubFunc(sub_output_config, + /* pass on parent output_ctx */ + OutputCtx *sub_output_ctx = + sub_module->InitSubFunc(sub_output_config, parent_ctx); - if (sub_output_ctx == NULL) { - continue; - } + if (sub_output_ctx == NULL) { + continue; + } - AddOutputToFreeList(sub_module, sub_output_ctx); - SetupOutput(sub_module->name, sub_module, + AddOutputToFreeList(sub_module, sub_output_ctx); + SetupOutput(sub_module->name, sub_module, sub_output_ctx); - } } + } - /* Error is no registered loggers with this name - * were found .*/ - if (!sub_count) { - FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + /* Error is no registered loggers with this name + * were found .*/ + if (!sub_count) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, "No output module named %s", subname); - continue; - } + continue; } } } From a26e59cb6d0e9052a7383efa47eb639ea9a36238 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 12 Jul 2016 17:07:10 +0200 Subject: [PATCH 1569/2553] output lua: set proper logging progress values --- src/output-lua.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/output-lua.c b/src/output-lua.c index e3d45566605b..d053487da901 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -867,6 +867,8 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) } else if (opts.alproto == ALPROTO_HTTP) { om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_HTTP; + om->ts_log_progress = -1; + om->tc_log_progress = -1; AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP); } else if (opts.alproto == ALPROTO_TLS) { om->TxLogFunc = LuaTxLogger; @@ -876,6 +878,8 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) } else if (opts.alproto == ALPROTO_DNS) { om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_DNS; + om->ts_log_progress = -1; + om->tc_log_progress = -1; AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNS); AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); } else if (opts.alproto == ALPROTO_SSH) { @@ -884,6 +888,8 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) } else if (opts.alproto == ALPROTO_SMTP) { om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_SMTP; + om->ts_log_progress = -1; + om->tc_log_progress = -1; AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); } else if (opts.packet && opts.alerts) { om->PacketLogFunc = LuaPacketLoggerAlerts; From 2856dfd1199cd1827f800f41e0e4a22723bf00ba Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 12 Jul 2016 17:07:25 +0200 Subject: [PATCH 1570/2553] output lua: improve debugging output --- src/output-tx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/output-tx.c b/src/output-tx.c index 093e2e593180..311cc70f43fc 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -171,13 +171,18 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ int tx_progress_tc = AppLayerParserGetStateProgress(p->proto, alproto, tx, FlowGetDisruptionFlags(f, STREAM_TOCLIENT)); + SCLogDebug("tx_progress_ts %d tx_progress_tc %d", + tx_progress_ts, tx_progress_tc); + // call each logger here (pseudo code) logger = list; store = op_thread_data->store; while (logger && store) { BUG_ON(logger->LogFunc == NULL); - SCLogDebug("logger %p", logger); + SCLogDebug("logger %p, LogCondition %p, ts_log_progress %d " + "tc_log_progress %d", logger, logger->LogCondition, + logger->ts_log_progress, logger->tc_log_progress); if (logger->alproto == alproto) { SCLogDebug("alproto match, logging tx_id %ju", tx_id); From ec602089a064d68d2ec97a23d269dff5b36e303b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 Jul 2016 09:48:54 +0200 Subject: [PATCH 1571/2553] Update Changelog for 3.1.1 --- ChangeLog | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ChangeLog b/ChangeLog index 720abe0653b4..3ce9497e945f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +3.1.1 -- 2016-07-13 + +Feature #1775: Lua: SMTP-support +Bug #1419: DNS transaction handling issues +Bug #1515: Problem with Threshold.config when using more than one IP +Bug #1664: Unreplied DNS queries not logged when flow is aged out +Bug #1808: Can't set thread priority after dropping privileges. +Bug #1821: Suricata 3.1 fails to start on CentOS6 +Bug #1839: suricata 3.1 configure.ac says >=libhtp-0.5.5, but >=libhtp-0.5.20 required +Bug #1840: --list-keywords and --list-app-layer-protos not working +Bug #1841: libhtp 0.5.21 +Bug #1844: netmap: IPS mode doesn't set 2nd iface in promisc mode +Bug #1845: Crash on disabling a app-layer protocol when it's logger is still enabled +Optimization #1846: af-packet: improve thread calculation logic +Optimization #1847: rules: don't warn on empty files + 3.1 -- 2016-06-20 Bug #1589: Cannot run nfq in workers mode From 2403af5177859241c62d77a2f9b3b351bb3bfe37 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 29 Jul 2016 10:47:23 -0600 Subject: [PATCH 1572/2553] pcap: don't fail with --pcap with no device present Issue: 1856. A device with the name of "" (empty string) was being added with LiveRegisterDevice which failed to initialize causing Suricata to fail. --- src/suricata.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/suricata.c b/src/suricata.c index a6e3e1f7b1a0..28e764f6668e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1167,7 +1167,9 @@ static int ParseCommandLinePcapLive(SCInstance *suri, const char *optarg) if (suri->run_mode == RUNMODE_UNKNOWN) { suri->run_mode = RUNMODE_PCAP_DEV; - LiveRegisterDevice(suri->pcap_dev); + if (optarg) { + LiveRegisterDevice(suri->pcap_dev); + } } else if (suri->run_mode == RUNMODE_PCAP_DEV) { #ifdef OS_WIN32 SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " From 79388df8878623f0a323fd5c825c39c9f99a1a13 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 15 Aug 2016 11:06:27 +0200 Subject: [PATCH 1573/2553] commandline: fix strlcpy usage --- src/suricata.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 28e764f6668e..7db868e42be1 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1116,9 +1116,7 @@ static int ParseCommandLineAfpacket(SCInstance *suri, const char *optarg) if (optarg) { LiveRegisterDevice(optarg); memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - strlcpy(suri->pcap_dev, optarg, - ((strlen(optarg) < sizeof(suri->pcap_dev)) ? - (strlen(optarg) + 1) : sizeof(suri->pcap_dev))); + strlcpy(suri->pcap_dev, optarg, sizeof(suri->pcap_dev)); } } else if (suri->run_mode == RUNMODE_AFP_DEV) { SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " @@ -1153,7 +1151,7 @@ static int ParseCommandLinePcapLive(SCInstance *suri, const char *optarg) if (strlen(optarg) > 9 && strncmp(optarg, "DeviceNPF", 9) == 0) { snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", optarg+9); } else { - strlcpy(suri->pcap_dev, optarg, ((strlen(optarg) < sizeof(suri->pcap_dev)) ? (strlen(optarg)+1) : (sizeof(suri->pcap_dev)))); + strlcpy(suri->pcap_dev, optarg, sizeof(suri->pcap_dev)); PcapTranslateIPToDevice(suri->pcap_dev, sizeof(suri->pcap_dev)); } From c9756caeefab7961c981201e540d9f38e9d15168 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Aug 2016 13:34:38 +0200 Subject: [PATCH 1574/2553] packet: make tcp/udp/icmp vars union non-anonymous Clean the whole thing after use. --- src/decode-icmpv4.h | 17 +++-------------- src/decode-icmpv6.h | 20 +++----------------- src/decode-tcp.h | 12 +++--------- src/decode.h | 10 +++++++++- 4 files changed, 18 insertions(+), 41 deletions(-) diff --git a/src/decode-icmpv4.h b/src/decode-icmpv4.h index 2f5862d38994..b28dd259a6cd 100644 --- a/src/decode-icmpv4.h +++ b/src/decode-icmpv4.h @@ -198,20 +198,9 @@ typedef struct ICMPV4Vars_ } ICMPV4Vars; #define CLEAR_ICMPV4_PACKET(p) do { \ - (p)->level4_comp_csum = -1; \ - (p)->icmpv4vars.id = 0; \ - (p)->icmpv4vars.seq = 0; \ - (p)->icmpv4vars.emb_ipv4h = NULL; \ - (p)->icmpv4vars.emb_tcph = NULL; \ - (p)->icmpv4vars.emb_udph = NULL; \ - (p)->icmpv4vars.emb_icmpv4h = NULL; \ - (p)->icmpv4vars.emb_ip4_src.s_addr = 0; \ - (p)->icmpv4vars.emb_ip4_dst.s_addr = 0; \ - (p)->icmpv4vars.emb_sport = 0; \ - (p)->icmpv4vars.emb_ip4_proto = 0; \ - (p)->icmpv4vars.emb_sport = 0; \ - (p)->icmpv4vars.emb_dport = 0; \ - (p)->icmpv4h = NULL; \ + (p)->level4_comp_csum = -1; \ + PACKET_CLEAR_L4VARS((p)); \ + (p)->icmpv4h = NULL; \ } while(0) #define ICMPV4_HEADER_PKT_OFFSET 8 diff --git a/src/decode-icmpv6.h b/src/decode-icmpv6.h index af97500607f8..a9a15ff72b1b 100644 --- a/src/decode-icmpv6.h +++ b/src/decode-icmpv6.h @@ -158,23 +158,9 @@ typedef struct ICMPV6Vars_ { #define CLEAR_ICMPV6_PACKET(p) do { \ - (p)->level4_comp_csum = -1; \ - (p)->icmpv6vars.id = 0; \ - (p)->icmpv6vars.seq = 0; \ - (p)->icmpv6vars.mtu = 0; \ - (p)->icmpv6vars.error_ptr = 0; \ - (p)->icmpv6vars.emb_ipv6h = NULL; \ - (p)->icmpv6vars.emb_tcph = NULL; \ - (p)->icmpv6vars.emb_udph = NULL; \ - (p)->icmpv6vars.emb_icmpv6h = NULL; \ - (p)->icmpv6vars.emb_ip6_src[0] = 0; \ - (p)->icmpv6vars.emb_ip6_src[1] = 0; \ - (p)->icmpv6vars.emb_ip6_src[2] = 0; \ - (p)->icmpv6vars.emb_ip6_src[3] = 0; \ - (p)->icmpv6vars.emb_ip6_proto_next = 0; \ - (p)->icmpv6vars.emb_sport = 0; \ - (p)->icmpv6vars.emb_dport = 0; \ - (p)->icmpv6h = NULL; \ + (p)->level4_comp_csum = -1; \ + PACKET_CLEAR_L4VARS((p)); \ + (p)->icmpv6h = NULL; \ } while(0) void DecodeICMPV6RegisterTests(void); diff --git a/src/decode-tcp.h b/src/decode-tcp.h index 72ed8179740b..f9611e723db4 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -151,16 +151,10 @@ typedef struct TCPVars_ TCPOpt mss; } TCPVars; -#define CLEAR_TCP_PACKET(p) { \ - (p)->tcph = NULL; \ +#define CLEAR_TCP_PACKET(p) { \ (p)->level4_comp_csum = -1; \ - (p)->tcpvars.ts_set = FALSE; \ - (p)->tcpvars.ts_val = 0; \ - (p)->tcpvars.ts_ecr = 0; \ - (p)->tcpvars.sack.type = 0; \ - (p)->tcpvars.sackok.type = 0; \ - (p)->tcpvars.ws.type = 0; \ - (p)->tcpvars.mss.type = 0; \ + PACKET_CLEAR_L4VARS((p)); \ + (p)->tcph = NULL; \ } void DecodeTCPRegisterTests(void); diff --git a/src/decode.h b/src/decode.h index 886ca2fa1ee8..ff221a6876e1 100644 --- a/src/decode.h +++ b/src/decode.h @@ -470,7 +470,11 @@ typedef struct Packet_ UDPVars udpvars; ICMPV4Vars icmpv4vars; ICMPV6Vars icmpv6vars; - }; + } l4vars; +#define tcpvars l4vars.tcpvars +#define udpvars l4vars.udpvars +#define icmpv4vars l4vars.icmpv4vars +#define icmpv6vars l4vars.icmpv6vars TCPHdr *tcph; @@ -659,6 +663,10 @@ typedef struct CaptureStats_ { void CaptureStatsUpdate(ThreadVars *tv, CaptureStats *s, const Packet *p); void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s); +#define PACKET_CLEAR_L4VARS(p) do { \ + memset(&(p)->l4vars, 0x00, sizeof((p)->l4vars)); \ + } while (0) + /** * \brief reset these to -1(indicates that the packet is fresh from the queue) */ From 884fddf035c3bbd509f532d158e1cf58b88e1d36 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Aug 2016 13:54:30 +0200 Subject: [PATCH 1575/2553] packet: remove empty and unused UDPVars struct --- src/decode-udp.h | 10 +++------- src/decode.h | 2 -- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/decode-udp.h b/src/decode-udp.h index 5636c32b0f42..7bc0ec080510 100644 --- a/src/decode-udp.h +++ b/src/decode-udp.h @@ -44,13 +44,9 @@ typedef struct UDPHdr_ uint16_t uh_sum; /* checksum */ } __attribute__((__packed__)) UDPHdr; -typedef struct UDPVars_ -{ -} UDPVars; - -#define CLEAR_UDP_PACKET(p) do { \ - (p)->udph = NULL; \ - (p)->level4_comp_csum = -1; \ +#define CLEAR_UDP_PACKET(p) do { \ + (p)->level4_comp_csum = -1; \ + (p)->udph = NULL; \ } while (0) void DecodeUDPV4RegisterTests(void); diff --git a/src/decode.h b/src/decode.h index ff221a6876e1..2c759c0122eb 100644 --- a/src/decode.h +++ b/src/decode.h @@ -467,12 +467,10 @@ typedef struct Packet_ /* Can only be one of TCP, UDP, ICMP at any given time */ union { TCPVars tcpvars; - UDPVars udpvars; ICMPV4Vars icmpv4vars; ICMPV6Vars icmpv6vars; } l4vars; #define tcpvars l4vars.tcpvars -#define udpvars l4vars.udpvars #define icmpv4vars l4vars.icmpv4vars #define icmpv6vars l4vars.icmpv6vars From 26e67400ba7bfac5b1e900979f0d12144302241b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 16 Aug 2016 15:54:43 +0200 Subject: [PATCH 1576/2553] dns: fix name parsing issue leading to events --- src/app-layer-dns-common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index cfb441451bf3..0f4595ac2c84 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -730,7 +730,11 @@ static uint16_t DNSResponseGetNameByOffset(const uint8_t * const input, const ui } qdata += length; - if ((uint64_t)((qdata + 1) - input) >= (uint64_t)input_len) { + /* if we're at the end of the input data, we're done */ + if ((uint64_t)((qdata + 1) - input) == (uint64_t)input_len) { + break; + } + else if ((uint64_t)((qdata + 1) - input) > (uint64_t)input_len) { SCLogDebug("input buffer too small"); goto insufficient_data; } From 7e6ce016004249bf048241bddb8cab5eea9c6368 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 16 Aug 2016 13:39:48 -0600 Subject: [PATCH 1577/2553] unified2: fix logging of tagged packets The structure for create the alert preceding each tagged packet was not being initialized, preventing tagged packets from being logged. Note: Snort unified2 does not precede tagged packets with an alert like is done here, so this just fixes what the code intended to do, it does not make it Snort unified2 compatible. Address issue: https://redmine.openinfosecfoundation.org/issues/1854 --- src/suricata.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/suricata.c b/src/suricata.c index 7db868e42be1..99611cb4de70 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2376,6 +2376,7 @@ static int PostConfLoadedSetup(SCInstance *suri) SCProtoNameInit(); TagInitCtx(); + PacketAlertTagInit(); ThresholdInit(); HostBitInitCtx(); IPPairBitInitCtx(); From 731d4a70492ae6ca37c9274f117905691c66aac9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Aug 2016 13:12:40 +0200 Subject: [PATCH 1578/2553] dns: fix OOB read on malformed TXT record --- src/app-layer-dns-common.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 0f4595ac2c84..8c5bc02affa0 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -983,6 +983,12 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ case DNS_RECORD_TYPE_TXT: { uint16_t datalen = ntohs(head->len); + + if (datalen == 0) { + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); + goto bad_data; + } + uint8_t txtlen = *data; const uint8_t *tdata = data + 1; From b3b78d4326ccb1eac84348290ec9ae1c62d3b4be Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 17 Aug 2016 16:31:05 +0200 Subject: [PATCH 1579/2553] detect: log earlier that rule reload is happening --- src/detect-engine.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 3d35fb08dece..9e54604149d9 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -665,8 +665,6 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) return 0; } - SCLogNotice("rule reload starting"); - /* prepare swap structures */ DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs]; DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs]; @@ -803,7 +801,6 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) SRepReloadComplete(); - SCLogNotice("rule reload complete"); return 1; error: @@ -2554,6 +2551,8 @@ int DetectEngineReload(SCInstance *suri) char prefix[128]; memset(prefix, 0, sizeof(prefix)); + SCLogNotice("rule reload starting"); + if (suri->conf_filename != NULL) { snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++); if (ConfYamlLoadFileWithPrefix(suri->conf_filename, prefix) != 0) { @@ -2612,6 +2611,8 @@ int DetectEngineReload(SCInstance *suri) DetectEnginePruneFreeList(); SCLogDebug("old_de_ctx should have been freed"); + + SCLogNotice("rule reload complete"); return 0; } From 73a04510702bfa4cec535cfe83a373d62fd7ec3e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 23 Aug 2016 10:00:54 -0600 Subject: [PATCH 1580/2553] output-json-dns: allocate correct size hexstring buffer The buffer allocated for the hexstring was not large enough for a ':' separated hex string. --- src/output-json-dns.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 11173ccc0e54..2eacb10d13aa 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -181,7 +181,8 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, /* turn fp raw buffer into a nice :-separate hex string */ uint16_t fp_len = (entry->data_len - 2); uint8_t *dptr = ptr+2; - uint32_t output_len = fp_len * 2 + 1; // create c-string, so add space for 0. + /* c-string for ':' separated hex and trailing \0. */ + uint32_t output_len = fp_len * 3 + 1; char hexstring[output_len], *p = hexstring; memset(hexstring, 0x00, output_len); From d3c0135eec796e1f934348dc96df3fe6c4d2f8ce Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 23 Aug 2016 10:53:49 -0600 Subject: [PATCH 1581/2553] app-layer-tls: accomodate trailing \0 in hash output --- src/app-layer-tls-handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-tls-handshake.c b/src/app-layer-tls-handshake.c index c95fd4373a05..bc99097b206c 100644 --- a/src/app-layer-tls-handshake.c +++ b/src/app-layer-tls-handshake.c @@ -181,7 +181,7 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, if (i == 0 && ssl_state->server_connp.cert0_fingerprint == NULL) { int msg_len = cur_cert_length; int hash_len = 20; - int out_len = 60; + int out_len = hash_len * 3 + 1; char out[out_len]; unsigned char *hash; hash = ComputeSHA1((unsigned char *) input, (int) msg_len); From a8da6bbd7137fb5a41cb20c1fc8a230c78b646e4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 24 Aug 2016 09:50:06 +0200 Subject: [PATCH 1582/2553] output: use safer logic for fingerprint printing --- src/app-layer-tls-handshake.c | 18 ++++++++++-------- src/output-json-dns.c | 9 ++++++--- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/app-layer-tls-handshake.c b/src/app-layer-tls-handshake.c index bc99097b206c..663471e83137 100644 --- a/src/app-layer-tls-handshake.c +++ b/src/app-layer-tls-handshake.c @@ -180,20 +180,22 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, if (i == 0 && ssl_state->server_connp.cert0_fingerprint == NULL) { int msg_len = cur_cert_length; - int hash_len = 20; - int out_len = hash_len * 3 + 1; - char out[out_len]; unsigned char *hash; hash = ComputeSHA1((unsigned char *) input, (int) msg_len); - char *p = out; - int j = 0; if (hash == NULL) { // TODO maybe an event here? } else { - for (j = 0; j < hash_len; j++, p += 3) { - snprintf(p, 4, j == hash_len - 1 ? "%02x" : "%02x:", - hash[j]); + int hash_len = 20; + int out_len = hash_len * 3 + 1; + char out[out_len]; + memset(out, 0x00, out_len); + + int j = 0; + for (j = 0; j < hash_len; j++) { + char one[4]; + snprintf(one, sizeof(one), j == hash_len - 1 ? "%02x" : "%02x:", hash[j]); + strlcat(out, one, out_len); } SCFree(hash); ssl_state->server_connp.cert0_fingerprint = SCStrdup(out); diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 2eacb10d13aa..5462b752dc85 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -181,14 +181,17 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, /* turn fp raw buffer into a nice :-separate hex string */ uint16_t fp_len = (entry->data_len - 2); uint8_t *dptr = ptr+2; + /* c-string for ':' separated hex and trailing \0. */ uint32_t output_len = fp_len * 3 + 1; - char hexstring[output_len], *p = hexstring; + char hexstring[output_len]; memset(hexstring, 0x00, output_len); uint16_t x; - for (x = 0; x < fp_len; x++, p += 3) { - snprintf(p, 4, x == fp_len - 1 ? "%02x" : "%02x:", dptr[x]); + for (x = 0; x < fp_len; x++) { + char one[4]; + snprintf(one, sizeof(one), x == fp_len - 1 ? "%02x" : "%02x:", dptr[x]); + strlcat(hexstring, one, output_len); } /* wrap the whole thing in it's own structure */ From 95015a3f6d0a4a21100e586a1fb19cb9f3206be7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Sun, 14 Aug 2016 12:44:51 -0600 Subject: [PATCH 1583/2553] decode: support Cisco Fabric Path / DCE Cisco Fabric Path is ethernet wrapped in an ethernet like header with 2 extra bytes. The ethernet type is in the same location so the ethernet decoder can be used with some validation for the extra length. --- rules/decoder-events.rules | 5 ++++- src/decode-ethernet.c | 8 ++++++++ src/decode-ethernet.h | 5 +++++ src/decode-events.c | 3 +++ src/decode-events.h | 3 +++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/rules/decoder-events.rules b/rules/decoder-events.rules index 4a20197fd5c3..7240ea06785b 100644 --- a/rules/decoder-events.rules +++ b/rules/decoder-events.rules @@ -137,5 +137,8 @@ alert pkthdr any any -> any any (msg:"SURICATA ERSPAN pkt too small"; decode-eve alert pkthdr any any -> any any (msg:"SURICATA ERSPAN unsupported version"; decode-event:erspan.unsupported_version; sid: 2200106; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ERSPAN too many vlan layers"; decode-event:erspan.too_many_vlan_layers; sid: 2200107; rev:1;) -# next sid is 2200110 +# Cisco Fabric Path/DCE +alert pkthdr any any -> any any (msg:"SURICATA DCE packet too small"; decode-event:dce.pkt_too_small; sid:2200110; rev:1;) + +# next sid is 2200111 diff --git a/src/decode-ethernet.c b/src/decode-ethernet.c index cd82886c6bb6..1c5e83e97a5e 100644 --- a/src/decode-ethernet.c +++ b/src/decode-ethernet.c @@ -85,6 +85,14 @@ int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, DecodeMPLS(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; + case ETHERNET_TYPE_DCE: + if (unlikely(len < ETHERNET_DCE_HEADER_LEN)) { + ENGINE_SET_INVALID_EVENT(p, DCE_PKT_TOO_SMALL); + } else { + DecodeEthernet(tv, dtv, p, pkt + ETHERNET_DCE_HEADER_LEN, + len - ETHERNET_DCE_HEADER_LEN, pq); + } + break; default: SCLogDebug("p %p pkt %p ether type %04x not supported", p, pkt, ntohs(p->ethh->eth_type)); diff --git a/src/decode-ethernet.h b/src/decode-ethernet.h index 094d2548e785..33f443da84a3 100644 --- a/src/decode-ethernet.h +++ b/src/decode-ethernet.h @@ -26,6 +26,9 @@ #define ETHERNET_HEADER_LEN 14 +/* Cisco Fabric Path / DCE header length. */ +#define ETHERNET_DCE_HEADER_LEN ETHERNET_HEADER_LEN + 2 + /* Ethernet types -- taken from Snort and Libdnet */ #define ETHERNET_TYPE_PUP 0x0200 /* PUP protocol */ #define ETHERNET_TYPE_IP 0x0800 @@ -42,6 +45,8 @@ #define ETHERNET_TYPE_LOOP 0x9000 #define ETHERNET_TYPE_8021QINQ 0x9100 #define ETHERNET_TYPE_ERSPAN 0x88BE +#define ETHERNET_TYPE_DCE 0x8903 /* Data center ethernet, + * Cisco Fabric Path */ typedef struct EthernetHdr_ { uint8_t eth_dst[6]; diff --git a/src/decode-events.c b/src/decode-events.c index f4a5bdd1ca81..d7e4ecc946c5 100644 --- a/src/decode-events.c +++ b/src/decode-events.c @@ -178,6 +178,9 @@ const struct DecodeEvents_ DEvents[] = { { "decoder.erspan.unsupported_version", ERSPAN_UNSUPPORTED_VERSION, }, { "decoder.erspan.too_many_vlan_layers", ERSPAN_TOO_MANY_VLAN_LAYERS, }, + /* Cisco Fabric Path/DCE events. */ + { "decoder.dce.pkt_too_small", DCE_PKT_TOO_SMALL, }, + /* STREAM EVENTS */ { "stream.3whs_ack_in_wrong_dir", STREAM_3WHS_ACK_IN_WRONG_DIR, }, { "stream.3whs_async_wrong_seq", STREAM_3WHS_ASYNC_WRONG_SEQ, }, diff --git a/src/decode-events.h b/src/decode-events.h index 8e7395254300..2d249aba1683 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -187,6 +187,9 @@ enum { ERSPAN_UNSUPPORTED_VERSION, ERSPAN_TOO_MANY_VLAN_LAYERS, + /* Cisco Fabric Path/DCE events. */ + DCE_PKT_TOO_SMALL, + /* END OF DECODE EVENTS ON SINGLE PACKET */ DECODE_EVENT_PACKET_MAX, From a975fdcfeb3816f5dccaea9a2cef212935cf6029 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 24 Aug 2016 10:06:26 -0600 Subject: [PATCH 1584/2553] app-layer-dcerpc-udp: fix missleading indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit app-layer-dcerpc-udp.c: In function ‘DCERPCUDPParserTest01’: app-layer-dcerpc-udp.c:1105:5: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation] if (alp_tctx != NULL) ^~ app-layer-dcerpc-udp.c:1107:2: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the ‘if’ StreamTcpFreeConfig(TRUE); ^~~~~~~~~~~~~~~~~~~ --- src/app-layer-dcerpc-udp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app-layer-dcerpc-udp.c b/src/app-layer-dcerpc-udp.c index 7ab5f83ab2e3..a373c8103e5e 100644 --- a/src/app-layer-dcerpc-udp.c +++ b/src/app-layer-dcerpc-udp.c @@ -1102,10 +1102,11 @@ int DCERPCUDPParserTest01(void) } end: - if (alp_tctx != NULL) + if (alp_tctx != NULL) { AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(TRUE); - return result; + } + StreamTcpFreeConfig(TRUE); + return result; } void DCERPCUDPParserRegisterTests(void) From e55334fb370629603c8c08a540e2f83e756fc863 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 24 Aug 2016 10:15:55 -0600 Subject: [PATCH 1585/2553] detect-flowbits: fix misleading indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit detect-flowbits.c: In function ‘FlowBitsTestSig02’: detect-flowbits.c:475:4: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation] if(error_count == 5) ^~ detect-flowbits.c:478:5: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the ‘if’ SigGroupBuild(de_ctx); ^~~~~~~~~~~~~ --- src/detect-flowbits.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 238eb91b4ccf..9752f03e8bd5 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -472,8 +472,8 @@ static int FlowBitsTestSig02(void) error_count++; } - if(error_count == 5) - goto end; + if(error_count == 5) + goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); From cf61472619044a0e961a517c37360d24c047a5e4 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 24 Aug 2016 10:14:11 -0600 Subject: [PATCH 1586/2553] app-layer-dcerpc-udp: style cleanups - consistent 4 space indent - cleanup file header --- src/app-layer-dcerpc-udp.c | 1788 ++++++++++++++++++------------------ 1 file changed, 901 insertions(+), 887 deletions(-) diff --git a/src/app-layer-dcerpc-udp.c b/src/app-layer-dcerpc-udp.c index a373c8103e5e..218f58e65e4e 100644 --- a/src/app-layer-dcerpc-udp.c +++ b/src/app-layer-dcerpc-udp.c @@ -1,5 +1,22 @@ /* * Copyright (c) 2009, 2010 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 Kirby Kuehl * @@ -36,23 +53,22 @@ #include "app-layer-dcerpc-udp.h" enum { - DCERPC_FIELD_NONE = 0, - DCERPC_PARSE_DCERPC_HEADER, - DCERPC_PARSE_DCERPC_BIND, - DCERPC_PARSE_DCERPC_BIND_ACK, - DCERPC_PARSE_DCERPC_REQUEST, - /* must be last */ - DCERPC_FIELD_MAX, + DCERPC_FIELD_NONE = 0, + DCERPC_PARSE_DCERPC_HEADER, + DCERPC_PARSE_DCERPC_BIND, + DCERPC_PARSE_DCERPC_BIND_ACK, + DCERPC_PARSE_DCERPC_REQUEST, + /* must be last */ + DCERPC_FIELD_MAX, }; /** \internal * \retval stub_len or 0 in case of error */ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, - AppLayerParserState *pstate, - uint8_t *input, uint32_t input_len) + AppLayerParserState *pstate, uint8_t *input, uint32_t input_len) { - SCEnter(); - DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpcudp_state; + SCEnter(); + DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpcudp_state; uint8_t **stub_data_buffer = NULL; uint32_t *stub_data_buffer_len = NULL; uint8_t *stub_data_fresh = NULL; @@ -100,8 +116,8 @@ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, /* length of the buffered stub */ *stub_data_buffer_len += stub_len; - sstate->dcerpc.fraglenleft -= stub_len; - sstate->dcerpc.bytesprocessed += stub_len; + sstate->dcerpc.fraglenleft -= stub_len; + sstate->dcerpc.bytesprocessed += stub_len; #ifdef DEBUG if (SCLogDebugEnabled()) { @@ -122,597 +138,595 @@ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, * fragmented packets. */ static int DCERPCUDPParseHeader(Flow *f, void *dcerpcudp_state, - AppLayerParserState *pstate, - uint8_t *input, uint32_t input_len) + AppLayerParserState *pstate, uint8_t *input, uint32_t input_len) { - SCEnter(); - uint8_t *p = input; - DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpcudp_state; - if (input_len) { - switch (sstate->bytesprocessed) { - case 0: - // fallthrough - /* above statement to prevent coverity FPs from the switch - * fall through */ - if (input_len >= DCERPC_UDP_HDR_LEN) { - sstate->dcerpc.dcerpchdrudp.rpc_vers = *p; - if (sstate->dcerpc.dcerpchdrudp.rpc_vers != 4) { - SCLogDebug("DCERPC UDP Header did not validate"); - SCReturnInt(-1); - } - sstate->dcerpc.dcerpchdrudp.type = *(p + 1); - sstate->dcerpc.dcerpchdrudp.flags1 = *(p + 2); - sstate->dcerpc.dcerpchdrudp.flags2 = *(p + 3); - sstate->dcerpc.dcerpchdrudp.drep[0] = *(p + 4); - sstate->dcerpc.dcerpchdrudp.drep[1] = *(p + 5); - sstate->dcerpc.dcerpchdrudp.drep[2] = *(p + 6); - sstate->dcerpc.dcerpchdrudp.serial_hi = *(p + 7); - sstate->dcerpc.dcerpchdrudp.objectuuid[3] = *(p + 8); - sstate->dcerpc.dcerpchdrudp.objectuuid[2] = *(p + 9); - sstate->dcerpc.dcerpchdrudp.objectuuid[1] = *(p + 10); - sstate->dcerpc.dcerpchdrudp.objectuuid[0] = *(p + 11); - sstate->dcerpc.dcerpchdrudp.objectuuid[5] = *(p + 12); - sstate->dcerpc.dcerpchdrudp.objectuuid[4] = *(p + 13); - sstate->dcerpc.dcerpchdrudp.objectuuid[7] = *(p + 14); - sstate->dcerpc.dcerpchdrudp.objectuuid[6] = *(p + 15); - sstate->dcerpc.dcerpchdrudp.objectuuid[8] = *(p + 16); - sstate->dcerpc.dcerpchdrudp.objectuuid[9] = *(p + 17); - sstate->dcerpc.dcerpchdrudp.objectuuid[10] = *(p + 18); - sstate->dcerpc.dcerpchdrudp.objectuuid[11] = *(p + 19); - sstate->dcerpc.dcerpchdrudp.objectuuid[12] = *(p + 20); - sstate->dcerpc.dcerpchdrudp.objectuuid[13] = *(p + 21); - sstate->dcerpc.dcerpchdrudp.objectuuid[14] = *(p + 22); - sstate->dcerpc.dcerpchdrudp.objectuuid[15] = *(p + 23); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[3] = *(p + 24); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[2] = *(p + 25); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[1] = *(p + 26); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[0] = *(p + 27); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[5] = *(p + 28); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[4] = *(p + 29); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[7] = *(p + 30); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[6] = *(p + 31); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[8] = *(p + 32); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[9] = *(p + 33); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[10] = *(p + 34); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[11] = *(p + 35); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[12] = *(p + 36); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[13] = *(p + 37); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[14] = *(p + 38); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[15] = *(p + 39); - sstate->dcerpc.dcerpchdrudp.activityuuid[3] = *(p + 40); - sstate->dcerpc.dcerpchdrudp.activityuuid[2] = *(p + 41); - sstate->dcerpc.dcerpchdrudp.activityuuid[1] = *(p + 42); - sstate->dcerpc.dcerpchdrudp.activityuuid[0] = *(p + 43); - sstate->dcerpc.dcerpchdrudp.activityuuid[5] = *(p + 44); - sstate->dcerpc.dcerpchdrudp.activityuuid[4] = *(p + 45); - sstate->dcerpc.dcerpchdrudp.activityuuid[7] = *(p + 46); - sstate->dcerpc.dcerpchdrudp.activityuuid[6] = *(p + 47); - sstate->dcerpc.dcerpchdrudp.activityuuid[8] = *(p + 48); - sstate->dcerpc.dcerpchdrudp.activityuuid[9] = *(p + 49); - sstate->dcerpc.dcerpchdrudp.activityuuid[10] = *(p + 50); - sstate->dcerpc.dcerpchdrudp.activityuuid[11] = *(p + 51); - sstate->dcerpc.dcerpchdrudp.activityuuid[12] = *(p + 52); - sstate->dcerpc.dcerpchdrudp.activityuuid[13] = *(p + 53); - sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p + 54); - sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p + 55); - if (sstate->dcerpc.dcerpchdrudp.drep[0] == 0x10) { - sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p + 56); - sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 57) << 8; - sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 58) << 16; - sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 59) << 24; - sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p + 60); - sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 61) << 8; - sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 62) << 16; - sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 63) << 24; - sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p + 64); - sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 65) << 8; - sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 66) << 16; - sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 67) << 24; - sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68); - sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 8; - sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70); - sstate->dcerpc.dcerpchdrudp.ihint |= *(p + 71) << 8; - sstate->dcerpc.dcerpchdrudp.ahint = *(p + 72); - sstate->dcerpc.dcerpchdrudp.ahint |= *(p + 73) << 8; - sstate->dcerpc.dcerpchdrudp.fraglen = *(p + 74); - sstate->dcerpc.dcerpchdrudp.fraglen |= *(p + 75) << 8; - sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76); - sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77) << 8; - } else { - sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p + 56) << 24; - sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 57) << 16; - sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 58) << 8; - sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 59); - sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p + 60) << 24; - sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 61) << 16; - sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 62) << 8; - sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 63); - sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p + 64) << 24; - sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 65) << 16; - sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 66) << 8; - sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 67); - sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68) << 24; - sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 16; - sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70) << 8; - sstate->dcerpc.dcerpchdrudp.ihint |= *(p + 71); - sstate->dcerpc.dcerpchdrudp.ahint = *(p + 72) << 8; - sstate->dcerpc.dcerpchdrudp.ahint |= *(p + 73); - sstate->dcerpc.dcerpchdrudp.fraglen = *(p + 74) << 8; - sstate->dcerpc.dcerpchdrudp.fraglen |= *(p + 75); - sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76) << 8; - sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77); - } - sstate->fraglenleft = sstate->dcerpc.dcerpchdrudp.fraglen; - sstate->dcerpc.dcerpchdrudp.auth_proto = *(p + 78); - sstate->dcerpc.dcerpchdrudp.serial_lo = *(p + 79); - sstate->bytesprocessed = DCERPC_UDP_HDR_LEN; - sstate->uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, - sizeof(DCERPCUuidEntry)); - if (sstate->uuid_entry == NULL) { - SCReturnUInt(-1); - } else { - memcpy(sstate->uuid_entry->uuid, - sstate->dcerpc.dcerpchdrudp.activityuuid, - sizeof(sstate->dcerpc.dcerpchdrudp.activityuuid)); - TAILQ_INSERT_HEAD(&sstate->uuid_list, sstate->uuid_entry, - next); + SCEnter(); + uint8_t *p = input; + DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpcudp_state; + if (input_len) { + switch (sstate->bytesprocessed) { + case 0: + // fallthrough + /* above statement to prevent coverity FPs from the switch + * fall through */ + if (input_len >= DCERPC_UDP_HDR_LEN) { + sstate->dcerpc.dcerpchdrudp.rpc_vers = *p; + if (sstate->dcerpc.dcerpchdrudp.rpc_vers != 4) { + SCLogDebug("DCERPC UDP Header did not validate"); + SCReturnInt(-1); + } + sstate->dcerpc.dcerpchdrudp.type = *(p + 1); + sstate->dcerpc.dcerpchdrudp.flags1 = *(p + 2); + sstate->dcerpc.dcerpchdrudp.flags2 = *(p + 3); + sstate->dcerpc.dcerpchdrudp.drep[0] = *(p + 4); + sstate->dcerpc.dcerpchdrudp.drep[1] = *(p + 5); + sstate->dcerpc.dcerpchdrudp.drep[2] = *(p + 6); + sstate->dcerpc.dcerpchdrudp.serial_hi = *(p + 7); + sstate->dcerpc.dcerpchdrudp.objectuuid[3] = *(p + 8); + sstate->dcerpc.dcerpchdrudp.objectuuid[2] = *(p + 9); + sstate->dcerpc.dcerpchdrudp.objectuuid[1] = *(p + 10); + sstate->dcerpc.dcerpchdrudp.objectuuid[0] = *(p + 11); + sstate->dcerpc.dcerpchdrudp.objectuuid[5] = *(p + 12); + sstate->dcerpc.dcerpchdrudp.objectuuid[4] = *(p + 13); + sstate->dcerpc.dcerpchdrudp.objectuuid[7] = *(p + 14); + sstate->dcerpc.dcerpchdrudp.objectuuid[6] = *(p + 15); + sstate->dcerpc.dcerpchdrudp.objectuuid[8] = *(p + 16); + sstate->dcerpc.dcerpchdrudp.objectuuid[9] = *(p + 17); + sstate->dcerpc.dcerpchdrudp.objectuuid[10] = *(p + 18); + sstate->dcerpc.dcerpchdrudp.objectuuid[11] = *(p + 19); + sstate->dcerpc.dcerpchdrudp.objectuuid[12] = *(p + 20); + sstate->dcerpc.dcerpchdrudp.objectuuid[13] = *(p + 21); + sstate->dcerpc.dcerpchdrudp.objectuuid[14] = *(p + 22); + sstate->dcerpc.dcerpchdrudp.objectuuid[15] = *(p + 23); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[3] = *(p + 24); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[2] = *(p + 25); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[1] = *(p + 26); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[0] = *(p + 27); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[5] = *(p + 28); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[4] = *(p + 29); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[7] = *(p + 30); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[6] = *(p + 31); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[8] = *(p + 32); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[9] = *(p + 33); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[10] = *(p + 34); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[11] = *(p + 35); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[12] = *(p + 36); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[13] = *(p + 37); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[14] = *(p + 38); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[15] = *(p + 39); + sstate->dcerpc.dcerpchdrudp.activityuuid[3] = *(p + 40); + sstate->dcerpc.dcerpchdrudp.activityuuid[2] = *(p + 41); + sstate->dcerpc.dcerpchdrudp.activityuuid[1] = *(p + 42); + sstate->dcerpc.dcerpchdrudp.activityuuid[0] = *(p + 43); + sstate->dcerpc.dcerpchdrudp.activityuuid[5] = *(p + 44); + sstate->dcerpc.dcerpchdrudp.activityuuid[4] = *(p + 45); + sstate->dcerpc.dcerpchdrudp.activityuuid[7] = *(p + 46); + sstate->dcerpc.dcerpchdrudp.activityuuid[6] = *(p + 47); + sstate->dcerpc.dcerpchdrudp.activityuuid[8] = *(p + 48); + sstate->dcerpc.dcerpchdrudp.activityuuid[9] = *(p + 49); + sstate->dcerpc.dcerpchdrudp.activityuuid[10] = *(p + 50); + sstate->dcerpc.dcerpchdrudp.activityuuid[11] = *(p + 51); + sstate->dcerpc.dcerpchdrudp.activityuuid[12] = *(p + 52); + sstate->dcerpc.dcerpchdrudp.activityuuid[13] = *(p + 53); + sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p + 54); + sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p + 55); + if (sstate->dcerpc.dcerpchdrudp.drep[0] == 0x10) { + sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p + 56); + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 57) << 8; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 58) << 16; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 59) << 24; + sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p + 60); + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 61) << 8; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 62) << 16; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 63) << 24; + sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p + 64); + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 65) << 8; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 66) << 16; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 67) << 24; + sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68); + sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 8; + sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70); + sstate->dcerpc.dcerpchdrudp.ihint |= *(p + 71) << 8; + sstate->dcerpc.dcerpchdrudp.ahint = *(p + 72); + sstate->dcerpc.dcerpchdrudp.ahint |= *(p + 73) << 8; + sstate->dcerpc.dcerpchdrudp.fraglen = *(p + 74); + sstate->dcerpc.dcerpchdrudp.fraglen |= *(p + 75) << 8; + sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76); + sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77) << 8; + } else { + sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p + 56) << 24; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 57) << 16; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 58) << 8; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 59); + sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p + 60) << 24; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 61) << 16; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 62) << 8; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 63); + sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p + 64) << 24; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 65) << 16; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 66) << 8; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 67); + sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68) << 24; + sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 16; + sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70) << 8; + sstate->dcerpc.dcerpchdrudp.ihint |= *(p + 71); + sstate->dcerpc.dcerpchdrudp.ahint = *(p + 72) << 8; + sstate->dcerpc.dcerpchdrudp.ahint |= *(p + 73); + sstate->dcerpc.dcerpchdrudp.fraglen = *(p + 74) << 8; + sstate->dcerpc.dcerpchdrudp.fraglen |= *(p + 75); + sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76) << 8; + sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77); + } + sstate->fraglenleft = sstate->dcerpc.dcerpchdrudp.fraglen; + sstate->dcerpc.dcerpchdrudp.auth_proto = *(p + 78); + sstate->dcerpc.dcerpchdrudp.serial_lo = *(p + 79); + sstate->bytesprocessed = DCERPC_UDP_HDR_LEN; + sstate->uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, + sizeof(DCERPCUuidEntry)); + if (sstate->uuid_entry == NULL) { + SCReturnUInt(-1); + } else { + memcpy(sstate->uuid_entry->uuid, + sstate->dcerpc.dcerpchdrudp.activityuuid, + sizeof(sstate->dcerpc.dcerpchdrudp.activityuuid)); + TAILQ_INSERT_HEAD(&sstate->uuid_list, sstate->uuid_entry, + next); #ifdef UNITTESTS - if (RunmodeIsUnittests()) { - printUUID("DCERPC UDP", sstate->uuid_entry); + if (RunmodeIsUnittests()) { + printUUID("DCERPC UDP", sstate->uuid_entry); - } + } #endif - } - SCReturnUInt(80); - break; - } else { - sstate->dcerpc.dcerpchdrudp.rpc_vers = *(p++); - if (sstate->dcerpc.dcerpchdrudp.rpc_vers != 4) { - SCLogDebug("DCERPC UDP Header did not validate"); - SCReturnInt(-1); - } - if (!(--input_len)) - break; - /* We fall through to the next case if we still have input. - * Same applies for other cases as well */ - } - /* fall through */ - case 1: - sstate->dcerpc.dcerpchdrudp.type = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 2: - sstate->dcerpc.dcerpchdrudp.flags1 = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 3: - sstate->dcerpc.dcerpchdrudp.flags2 = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 4: - sstate->dcerpc.dcerpchdrudp.drep[0] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 5: - sstate->dcerpc.dcerpchdrudp.drep[1] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 6: - sstate->dcerpc.dcerpchdrudp.drep[2] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 7: - sstate->dcerpc.dcerpchdrudp.serial_hi = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 8: - sstate->dcerpc.dcerpchdrudp.objectuuid[3] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 9: - sstate->dcerpc.dcerpchdrudp.objectuuid[2] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 10: - sstate->dcerpc.dcerpchdrudp.objectuuid[1] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 11: - sstate->dcerpc.dcerpchdrudp.objectuuid[0] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 12: - sstate->dcerpc.dcerpchdrudp.objectuuid[5] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 13: - sstate->dcerpc.dcerpchdrudp.objectuuid[4] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 14: - sstate->dcerpc.dcerpchdrudp.objectuuid[7] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 15: - sstate->dcerpc.dcerpchdrudp.objectuuid[6] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 16: - sstate->dcerpc.dcerpchdrudp.objectuuid[8] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 17: - sstate->dcerpc.dcerpchdrudp.objectuuid[9] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 18: - sstate->dcerpc.dcerpchdrudp.objectuuid[10] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 19: - sstate->dcerpc.dcerpchdrudp.objectuuid[11] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 20: - sstate->dcerpc.dcerpchdrudp.objectuuid[12] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 21: - sstate->dcerpc.dcerpchdrudp.objectuuid[13] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 22: - sstate->dcerpc.dcerpchdrudp.objectuuid[14] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 23: - sstate->dcerpc.dcerpchdrudp.objectuuid[15] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 24: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[3] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 25: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[2] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 26: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[1] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 27: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[0] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 28: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[5] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 29: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[4] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 30: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[7] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 31: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[6] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 32: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[8] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 33: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[9] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 34: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[10] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 35: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[11] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 36: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[12] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 37: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[13] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 38: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[14] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 39: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[15] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 40: - sstate->dcerpc.dcerpchdrudp.activityuuid[3] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 41: - sstate->dcerpc.dcerpchdrudp.activityuuid[2] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 42: - sstate->dcerpc.dcerpchdrudp.activityuuid[1] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 43: - sstate->dcerpc.dcerpchdrudp.activityuuid[0] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 44: - sstate->dcerpc.dcerpchdrudp.activityuuid[5] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 45: - sstate->dcerpc.dcerpchdrudp.activityuuid[4] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 46: - sstate->dcerpc.dcerpchdrudp.activityuuid[7] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 47: - sstate->dcerpc.dcerpchdrudp.activityuuid[6] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 48: - sstate->dcerpc.dcerpchdrudp.activityuuid[8] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 49: - sstate->dcerpc.dcerpchdrudp.activityuuid[9] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 50: - sstate->dcerpc.dcerpchdrudp.activityuuid[10] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 51: - sstate->dcerpc.dcerpchdrudp.activityuuid[11] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 52: - sstate->dcerpc.dcerpchdrudp.activityuuid[12] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 53: - sstate->dcerpc.dcerpchdrudp.activityuuid[13] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 54: - sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 55: - sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 56: - sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 57: - sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 58: - sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 16; - if (!(--input_len)) - break; - /* fall through */ - case 59: - sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 24; - if (!(--input_len)) - break; - /* fall through */ - case 60: - sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 61: - sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 62: - sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 16; - if (!(--input_len)) - break; - /* fall through */ - case 63: - sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 24; - if (!(--input_len)) - break; - /* fall through */ - case 64: - sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 65: - sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 66: - sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 16; - if (!(--input_len)) - break; - /* fall through */ - case 67: - sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 24; - if (!(--input_len)) - break; - /* fall through */ - case 68: - sstate->dcerpc.dcerpchdrudp.opnum = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 69: - sstate->dcerpc.dcerpchdrudp.opnum |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 70: - sstate->dcerpc.dcerpchdrudp.ihint = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 71: - sstate->dcerpc.dcerpchdrudp.ihint |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 72: - sstate->dcerpc.dcerpchdrudp.ahint = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 73: - sstate->dcerpc.dcerpchdrudp.ahint |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 74: - sstate->dcerpc.dcerpchdrudp.fraglen = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 75: - sstate->dcerpc.dcerpchdrudp.fraglen |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 76: - sstate->dcerpc.dcerpchdrudp.fragnum = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 77: - sstate->dcerpc.dcerpchdrudp.fragnum |= *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 78: - sstate->dcerpc.dcerpchdrudp.auth_proto = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 79: - sstate->dcerpc.dcerpchdrudp.serial_lo = *(p++); - if (sstate->dcerpc.dcerpchdrudp.drep[0] != 0x10) { - sstate->dcerpc.dcerpchdrudp.server_boot = SCByteSwap32(sstate->dcerpc.dcerpchdrudp.server_boot); - sstate->dcerpc.dcerpchdrudp.if_vers= SCByteSwap32(sstate->dcerpc.dcerpchdrudp.if_vers); - sstate->dcerpc.dcerpchdrudp.seqnum= SCByteSwap32(sstate->dcerpc.dcerpchdrudp.seqnum); - sstate->dcerpc.dcerpchdrudp.opnum = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.opnum); - sstate->dcerpc.dcerpchdrudp.ihint= SCByteSwap16(sstate->dcerpc.dcerpchdrudp.ihint); - sstate->dcerpc.dcerpchdrudp.ahint = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.ahint); - sstate->dcerpc.dcerpchdrudp.fraglen = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.fraglen); - sstate->dcerpc.dcerpchdrudp.fragnum = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.fragnum); - } - sstate->fraglenleft = sstate->dcerpc.dcerpchdrudp.fraglen; - sstate->uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, - sizeof(DCERPCUuidEntry)); - if (sstate->uuid_entry == NULL) { - SCReturnUInt(-1); - } else { - memcpy(sstate->uuid_entry->uuid, - sstate->dcerpc.dcerpchdrudp.activityuuid, - sizeof(sstate->dcerpc.dcerpchdrudp.activityuuid)); - TAILQ_INSERT_HEAD(&sstate->uuid_list, sstate->uuid_entry, - next); + } + SCReturnUInt(80); + break; + } else { + sstate->dcerpc.dcerpchdrudp.rpc_vers = *(p++); + if (sstate->dcerpc.dcerpchdrudp.rpc_vers != 4) { + SCLogDebug("DCERPC UDP Header did not validate"); + SCReturnInt(-1); + } + if (!(--input_len)) + break; + /* We fall through to the next case if we still have input. + * Same applies for other cases as well */ + } + /* fall through */ + case 1: + sstate->dcerpc.dcerpchdrudp.type = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 2: + sstate->dcerpc.dcerpchdrudp.flags1 = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 3: + sstate->dcerpc.dcerpchdrudp.flags2 = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 4: + sstate->dcerpc.dcerpchdrudp.drep[0] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 5: + sstate->dcerpc.dcerpchdrudp.drep[1] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 6: + sstate->dcerpc.dcerpchdrudp.drep[2] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 7: + sstate->dcerpc.dcerpchdrudp.serial_hi = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 8: + sstate->dcerpc.dcerpchdrudp.objectuuid[3] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 9: + sstate->dcerpc.dcerpchdrudp.objectuuid[2] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 10: + sstate->dcerpc.dcerpchdrudp.objectuuid[1] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 11: + sstate->dcerpc.dcerpchdrudp.objectuuid[0] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 12: + sstate->dcerpc.dcerpchdrudp.objectuuid[5] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 13: + sstate->dcerpc.dcerpchdrudp.objectuuid[4] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 14: + sstate->dcerpc.dcerpchdrudp.objectuuid[7] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 15: + sstate->dcerpc.dcerpchdrudp.objectuuid[6] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 16: + sstate->dcerpc.dcerpchdrudp.objectuuid[8] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 17: + sstate->dcerpc.dcerpchdrudp.objectuuid[9] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 18: + sstate->dcerpc.dcerpchdrudp.objectuuid[10] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 19: + sstate->dcerpc.dcerpchdrudp.objectuuid[11] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 20: + sstate->dcerpc.dcerpchdrudp.objectuuid[12] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 21: + sstate->dcerpc.dcerpchdrudp.objectuuid[13] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 22: + sstate->dcerpc.dcerpchdrudp.objectuuid[14] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 23: + sstate->dcerpc.dcerpchdrudp.objectuuid[15] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 24: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[3] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 25: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[2] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 26: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[1] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 27: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[0] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 28: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[5] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 29: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[4] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 30: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[7] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 31: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[6] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 32: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[8] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 33: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[9] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 34: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[10] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 35: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[11] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 36: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[12] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 37: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[13] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 38: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[14] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 39: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[15] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 40: + sstate->dcerpc.dcerpchdrudp.activityuuid[3] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 41: + sstate->dcerpc.dcerpchdrudp.activityuuid[2] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 42: + sstate->dcerpc.dcerpchdrudp.activityuuid[1] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 43: + sstate->dcerpc.dcerpchdrudp.activityuuid[0] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 44: + sstate->dcerpc.dcerpchdrudp.activityuuid[5] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 45: + sstate->dcerpc.dcerpchdrudp.activityuuid[4] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 46: + sstate->dcerpc.dcerpchdrudp.activityuuid[7] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 47: + sstate->dcerpc.dcerpchdrudp.activityuuid[6] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 48: + sstate->dcerpc.dcerpchdrudp.activityuuid[8] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 49: + sstate->dcerpc.dcerpchdrudp.activityuuid[9] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 50: + sstate->dcerpc.dcerpchdrudp.activityuuid[10] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 51: + sstate->dcerpc.dcerpchdrudp.activityuuid[11] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 52: + sstate->dcerpc.dcerpchdrudp.activityuuid[12] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 53: + sstate->dcerpc.dcerpchdrudp.activityuuid[13] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 54: + sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 55: + sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 56: + sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 57: + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 58: + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 16; + if (!(--input_len)) + break; + /* fall through */ + case 59: + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 24; + if (!(--input_len)) + break; + /* fall through */ + case 60: + sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 61: + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 62: + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 16; + if (!(--input_len)) + break; + /* fall through */ + case 63: + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 24; + if (!(--input_len)) + break; + /* fall through */ + case 64: + sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 65: + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 66: + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 16; + if (!(--input_len)) + break; + /* fall through */ + case 67: + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 24; + if (!(--input_len)) + break; + /* fall through */ + case 68: + sstate->dcerpc.dcerpchdrudp.opnum = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 69: + sstate->dcerpc.dcerpchdrudp.opnum |= *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 70: + sstate->dcerpc.dcerpchdrudp.ihint = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 71: + sstate->dcerpc.dcerpchdrudp.ihint |= *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 72: + sstate->dcerpc.dcerpchdrudp.ahint = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 73: + sstate->dcerpc.dcerpchdrudp.ahint |= *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 74: + sstate->dcerpc.dcerpchdrudp.fraglen = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 75: + sstate->dcerpc.dcerpchdrudp.fraglen |= *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 76: + sstate->dcerpc.dcerpchdrudp.fragnum = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 77: + sstate->dcerpc.dcerpchdrudp.fragnum |= *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 78: + sstate->dcerpc.dcerpchdrudp.auth_proto = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 79: + sstate->dcerpc.dcerpchdrudp.serial_lo = *(p++); + if (sstate->dcerpc.dcerpchdrudp.drep[0] != 0x10) { + sstate->dcerpc.dcerpchdrudp.server_boot = SCByteSwap32(sstate->dcerpc.dcerpchdrudp.server_boot); + sstate->dcerpc.dcerpchdrudp.if_vers= SCByteSwap32(sstate->dcerpc.dcerpchdrudp.if_vers); + sstate->dcerpc.dcerpchdrudp.seqnum= SCByteSwap32(sstate->dcerpc.dcerpchdrudp.seqnum); + sstate->dcerpc.dcerpchdrudp.opnum = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.opnum); + sstate->dcerpc.dcerpchdrudp.ihint= SCByteSwap16(sstate->dcerpc.dcerpchdrudp.ihint); + sstate->dcerpc.dcerpchdrudp.ahint = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.ahint); + sstate->dcerpc.dcerpchdrudp.fraglen = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.fraglen); + sstate->dcerpc.dcerpchdrudp.fragnum = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.fragnum); + } + sstate->fraglenleft = sstate->dcerpc.dcerpchdrudp.fraglen; + sstate->uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, + sizeof(DCERPCUuidEntry)); + if (sstate->uuid_entry == NULL) { + SCReturnUInt(-1); + } else { + memcpy(sstate->uuid_entry->uuid, + sstate->dcerpc.dcerpchdrudp.activityuuid, + sizeof(sstate->dcerpc.dcerpchdrudp.activityuuid)); + TAILQ_INSERT_HEAD(&sstate->uuid_list, sstate->uuid_entry, + next); #ifdef UNITTESTS - if (RunmodeIsUnittests()) { - printUUID("DCERPC UDP", sstate->uuid_entry); - } + if (RunmodeIsUnittests()) { + printUUID("DCERPC UDP", sstate->uuid_entry); + } #endif - } - --input_len; - break; - } - } - sstate->bytesprocessed += (p - input); - SCReturnInt((p - input)); + } + --input_len; + break; + } + } + sstate->bytesprocessed += (p - input); + SCReturnInt((p - input)); } static int DCERPCUDPParse(Flow *f, void *dcerpc_state, - AppLayerParserState *pstate, - uint8_t *input, uint32_t input_len, - void *local_data) + AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, + void *local_data) { - uint32_t retval = 0; - uint32_t parsed = 0; - int hdrretval = 0; - SCEnter(); + uint32_t retval = 0; + uint32_t parsed = 0; + int hdrretval = 0; + SCEnter(); if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { SCReturnInt(1); @@ -720,81 +734,81 @@ static int DCERPCUDPParse(Flow *f, void *dcerpc_state, SCReturnInt(-1); } - DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpc_state; - while (sstate->bytesprocessed < DCERPC_UDP_HDR_LEN && input_len) { - hdrretval = DCERPCUDPParseHeader(f, dcerpc_state, pstate, input, - input_len); - if (hdrretval == -1 || hdrretval > (int32_t)input_len) { - sstate->bytesprocessed = 0; - SCReturnInt(hdrretval); - } else { - parsed += hdrretval; - input_len -= hdrretval; - } - } + DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpc_state; + while (sstate->bytesprocessed < DCERPC_UDP_HDR_LEN && input_len) { + hdrretval = DCERPCUDPParseHeader(f, dcerpc_state, pstate, input, + input_len); + if (hdrretval == -1 || hdrretval > (int32_t)input_len) { + sstate->bytesprocessed = 0; + SCReturnInt(hdrretval); + } else { + parsed += hdrretval; + input_len -= hdrretval; + } + } #if 0 - printf("Done with DCERPCUDPParseHeader bytesprocessed %u/%u left %u\n", - sstate->bytesprocessed, sstate->dcerpc.dcerpchdrudp.fraglen, input_len); - printf("\nDCERPC Version:\t%u\n", sstate->dcerpc.dcerpchdrudp.rpc_vers); - printf("DCERPC Type:\t%u\n", sstate->dcerpc.dcerpchdrudp.ptype); - printf("DCERPC Flags1:\t0x%02x\n", sstate->dcerpc.dcerpchdrudp.flags1); - printf("DCERPC Flags2:\t0x%02x\n", sstate->dcerpc.dcerpchdrudp.flags2); - printf("DCERPC Packed Drep:\t%02x %02x %02x\n", - sstate->dcerpc.dcerpchdrudp.drep[0], sstate->dcerpc.dcerpchdrudp.drep[1], - sstate->dcerpc.dcerpchdrudp.drep[2]); - printf("DCERPC Frag Length:\t0x%04x %u\n", sstate->dcerpc.dcerpchdrudp.fraglen, - sstate->dcerpc.dcerpchdrudp.fraglen); - printf("DCERPC Frag Number:\t0x%04x\n", sstate->dcerpc.dcerpchdrudp.fragnum); - printf("DCERPC OpNum:\t0x%04x\n", sstate->dcerpc.dcerpchdrudp.opnum); + printf("Done with DCERPCUDPParseHeader bytesprocessed %u/%u left %u\n", + sstate->bytesprocessed, sstate->dcerpc.dcerpchdrudp.fraglen, input_len); + printf("\nDCERPC Version:\t%u\n", sstate->dcerpc.dcerpchdrudp.rpc_vers); + printf("DCERPC Type:\t%u\n", sstate->dcerpc.dcerpchdrudp.ptype); + printf("DCERPC Flags1:\t0x%02x\n", sstate->dcerpc.dcerpchdrudp.flags1); + printf("DCERPC Flags2:\t0x%02x\n", sstate->dcerpc.dcerpchdrudp.flags2); + printf("DCERPC Packed Drep:\t%02x %02x %02x\n", + sstate->dcerpc.dcerpchdrudp.drep[0], sstate->dcerpc.dcerpchdrudp.drep[1], + sstate->dcerpc.dcerpchdrudp.drep[2]); + printf("DCERPC Frag Length:\t0x%04x %u\n", sstate->dcerpc.dcerpchdrudp.fraglen, + sstate->dcerpc.dcerpchdrudp.fraglen); + printf("DCERPC Frag Number:\t0x%04x\n", sstate->dcerpc.dcerpchdrudp.fragnum); + printf("DCERPC OpNum:\t0x%04x\n", sstate->dcerpc.dcerpchdrudp.opnum); #endif - while (sstate->bytesprocessed >= DCERPC_UDP_HDR_LEN - && sstate->bytesprocessed < sstate->dcerpc.dcerpchdrudp.fraglen - && input_len) { - retval = FragmentDataParser(f, dcerpc_state, pstate, input + parsed, - input_len); - if (retval || retval > input_len) { - parsed += retval; - input_len -= retval; - } else if (input_len) { - SCLogDebug("Error parsing DCERPC UDP Fragment Data"); - parsed -= input_len; - input_len = 0; - sstate->bytesprocessed = 0; - } - } + while (sstate->bytesprocessed >= DCERPC_UDP_HDR_LEN + && sstate->bytesprocessed < sstate->dcerpc.dcerpchdrudp.fraglen + && input_len) { + retval = FragmentDataParser(f, dcerpc_state, pstate, input + parsed, + input_len); + if (retval || retval > input_len) { + parsed += retval; + input_len -= retval; + } else if (input_len) { + SCLogDebug("Error parsing DCERPC UDP Fragment Data"); + parsed -= input_len; + input_len = 0; + sstate->bytesprocessed = 0; + } + } - if (sstate->bytesprocessed == sstate->dcerpc.dcerpchdrudp.fraglen) { - sstate->bytesprocessed = 0; - } - if (pstate == NULL) - SCReturnInt(-1); + if (sstate->bytesprocessed == sstate->dcerpc.dcerpchdrudp.fraglen) { + sstate->bytesprocessed = 0; + } + if (pstate == NULL) + SCReturnInt(-1); - SCReturnInt(1); + SCReturnInt(1); } static void *DCERPCUDPStateAlloc(void) { - void *s = SCMalloc(sizeof(DCERPCUDPState)); - if (unlikely(s == NULL)) - return NULL; + void *s = SCMalloc(sizeof(DCERPCUDPState)); + if (unlikely(s == NULL)) + return NULL; - memset(s, 0, sizeof(DCERPCUDPState)); - return s; + memset(s, 0, sizeof(DCERPCUDPState)); + return s; } static void DCERPCUDPStateFree(void *s) { - DCERPCUDPState *sstate = (DCERPCUDPState *) s; + DCERPCUDPState *sstate = (DCERPCUDPState *) s; - DCERPCUuidEntry *item; + DCERPCUuidEntry *item; - while ((item = TAILQ_FIRST(&sstate->uuid_list))) { - //printUUID("Free", item); - TAILQ_REMOVE(&sstate->uuid_list, item, next); - SCFree(item); - } + while ((item = TAILQ_FIRST(&sstate->uuid_list))) { + //printUUID("Free", item); + TAILQ_REMOVE(&sstate->uuid_list, item, next); + SCFree(item); + } if (sstate->dcerpc.dcerpcrequest.stub_data_buffer != NULL) { SCFree(sstate->dcerpc.dcerpcrequest.stub_data_buffer); sstate->dcerpc.dcerpcrequest.stub_data_buffer = NULL; @@ -811,7 +825,7 @@ static void DCERPCUDPStateFree(void *s) static int DCERPCUDPRegisterPatternsForProtocolDetection(void) { if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_DCERPC, - "|04 00|", 2, 0, STREAM_TOSERVER) < 0) + "|04 00|", 2, 0, STREAM_TOSERVER) < 0) { return -1; } @@ -829,21 +843,21 @@ void RegisterDCERPCUDPParsers(void) return; } else { SCLogInfo("Protocol detection and parser disabled for %s protocol.", - "dcerpc"); + "dcerpc"); return; } if (AppLayerParserConfParserEnabled("udp", "dcerpc")) { AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_DCERPC, STREAM_TOSERVER, - DCERPCUDPParse); + DCERPCUDPParse); AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_DCERPC, STREAM_TOCLIENT, - DCERPCUDPParse); + DCERPCUDPParse); AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_DCERPC, DCERPCUDPStateAlloc, - DCERPCUDPStateFree); + DCERPCUDPStateFree); AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_UDP, ALPROTO_DCERPC, STREAM_TOSERVER); } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" - "still on.", "dcerpc"); + "still on.", "dcerpc"); } #ifdef UNITTESTS AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_DCERPC, DCERPCUDPParserRegisterTests); @@ -859,247 +873,247 @@ void RegisterDCERPCUDPParsers(void) int DCERPCUDPParserTest01(void) { - int result = 1; - Flow f; - uint8_t dcerpcrequest[] = { - 0x04, 0x00, 0x2c, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x3f, 0x98, 0xf0, 0x5c, 0xd9, 0x63, 0xcc, 0x46, - 0xc2, 0x74, 0x51, 0x6c, 0x8a, 0x53, 0x7d, 0x6f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x70, 0x05, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x32, 0x24, 0x58, 0xfd, - 0xcc, 0x45, 0x64, 0x49, 0xb0, 0x70, 0xdd, 0xae, - 0x74, 0x2c, 0x96, 0xd2, 0x60, 0x5e, 0x0d, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x70, 0x5e, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x7c, 0x5e, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x80, 0x96, 0xf1, 0xf1, - 0x2a, 0x4d, 0xce, 0x11, 0xa6, 0x6a, 0x00, 0x20, - 0xaf, 0x6e, 0x72, 0xf4, 0x0c, 0x00, 0x00, 0x00, - 0x4d, 0x41, 0x52, 0x42, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0xf4, 0x0b, 0x00, - 0x10, 0x09, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, - 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, - 0xa2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x38, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x00, 0x00, 0x00, 0x00, 0xe0, 0x08, 0x00, 0x00, - 0xd8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0xc8, 0x00, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, - 0xd8, 0x08, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc4, 0x28, 0xcd, 0x00, - 0x64, 0x29, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xb9, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xab, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xa5, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xa6, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xa4, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xad, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xaa, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0x07, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x90, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x28, 0x06, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x50, 0x00, 0x00, 0x00, 0x4f, 0xb6, 0x88, 0x20, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x66, 0x00, - 0x06, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x19, 0x0c, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x98, 0x93, - 0x98, 0x4f, 0xd2, 0x11, 0xa9, 0x3d, 0xbe, 0x57, - 0xb2, 0x00, 0x00, 0x00, 0x32, 0x00, 0x31, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x80, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, - 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x81, 0xc5, 0x17, 0x03, - 0x80, 0x0e, 0xe9, 0x4a, 0x99, 0x99, 0xf1, 0x8a, - 0x50, 0x6f, 0x7a, 0x85, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6e, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xd8, 0xda, 0x0d, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x2f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x46, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2e, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x68, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xff, 0xff, - 0x68, 0x8b, 0x0b, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfe, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfe, 0x02, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, - 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, - 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, - 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, - 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, - 0x31, 0x00, 0x31, 0x00, 0x9d, 0x13, 0x00, 0x01, - 0xcc, 0xe0, 0xfd, 0x7f, 0xcc, 0xe0, 0xfd, 0x7f, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - uint32_t requestlen = sizeof(dcerpcrequest); + int result = 1; + Flow f; + uint8_t dcerpcrequest[] = { + 0x04, 0x00, 0x2c, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x3f, 0x98, 0xf0, 0x5c, 0xd9, 0x63, 0xcc, 0x46, + 0xc2, 0x74, 0x51, 0x6c, 0x8a, 0x53, 0x7d, 0x6f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x70, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0x24, 0x58, 0xfd, + 0xcc, 0x45, 0x64, 0x49, 0xb0, 0x70, 0xdd, 0xae, + 0x74, 0x2c, 0x96, 0xd2, 0x60, 0x5e, 0x0d, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x5e, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x7c, 0x5e, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x80, 0x96, 0xf1, 0xf1, + 0x2a, 0x4d, 0xce, 0x11, 0xa6, 0x6a, 0x00, 0x20, + 0xaf, 0x6e, 0x72, 0xf4, 0x0c, 0x00, 0x00, 0x00, + 0x4d, 0x41, 0x52, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0xf4, 0x0b, 0x00, + 0x10, 0x09, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, + 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, + 0xa2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x38, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x08, 0x00, 0x00, + 0xd8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0xc8, 0x00, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, + 0xd8, 0x08, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc4, 0x28, 0xcd, 0x00, + 0x64, 0x29, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0xb9, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xab, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xa5, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xa6, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xa4, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xad, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xaa, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0x07, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x28, 0x06, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x50, 0x00, 0x00, 0x00, 0x4f, 0xb6, 0x88, 0x20, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x66, 0x00, + 0x06, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x19, 0x0c, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x98, 0x93, + 0x98, 0x4f, 0xd2, 0x11, 0xa9, 0x3d, 0xbe, 0x57, + 0xb2, 0x00, 0x00, 0x00, 0x32, 0x00, 0x31, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x80, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, + 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x81, 0xc5, 0x17, 0x03, + 0x80, 0x0e, 0xe9, 0x4a, 0x99, 0x99, 0xf1, 0x8a, + 0x50, 0x6f, 0x7a, 0x85, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd8, 0xda, 0x0d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x2f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x46, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x68, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xff, 0xff, + 0x68, 0x8b, 0x0b, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x02, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x9d, 0x13, 0x00, 0x01, + 0xcc, 0xe0, 0xfd, 0x7f, 0xcc, 0xe0, 0xfd, 0x7f, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + uint32_t requestlen = sizeof(dcerpcrequest); - TcpSession ssn; - DCERPCUuidEntry *uuid_entry; + TcpSession ssn; + DCERPCUuidEntry *uuid_entry; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; + f.protoctx = (void *)&ssn; f.proto = IPPROTO_UDP; f.protomap = FlowGetProtoMapping(f.proto); - StreamTcpInitConfig(TRUE); + StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); - if (r != 0) { - printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); + if (r != 0) { + printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); + result = 0; + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); - DCERPCUDPState *dcerpc_state = f.alstate; - if (dcerpc_state == NULL) { - printf("no dcerpc state: "); - result = 0; - goto end; - } + DCERPCUDPState *dcerpc_state = f.alstate; + if (dcerpc_state == NULL) { + printf("no dcerpc state: "); + result = 0; + goto end; + } - if (dcerpc_state->dcerpc.dcerpchdrudp.rpc_vers != 4) { - printf("expected dcerpc version 0x04, got 0x%02x : ", - dcerpc_state->dcerpc.dcerpchdrudp.rpc_vers); - result = 0; - goto end; - } + if (dcerpc_state->dcerpc.dcerpchdrudp.rpc_vers != 4) { + printf("expected dcerpc version 0x04, got 0x%02x : ", + dcerpc_state->dcerpc.dcerpchdrudp.rpc_vers); + result = 0; + goto end; + } - if (dcerpc_state->dcerpc.dcerpchdrudp.fraglen != 1392) { - printf("expected dcerpc fraglen 0x%02x , got 0x%02x : ", 1392, dcerpc_state->dcerpc.dcerpchdrudp.fraglen); - result = 0; - goto end; - } + if (dcerpc_state->dcerpc.dcerpchdrudp.fraglen != 1392) { + printf("expected dcerpc fraglen 0x%02x , got 0x%02x : ", 1392, dcerpc_state->dcerpc.dcerpchdrudp.fraglen); + result = 0; + goto end; + } - if (dcerpc_state->dcerpc.dcerpchdrudp.opnum != 4) { - printf("expected dcerpc opnum 0x%02x , got 0x%02x : ", 4, dcerpc_state->dcerpc.dcerpchdrudp.opnum); - result = 0; - goto end; - } + if (dcerpc_state->dcerpc.dcerpchdrudp.opnum != 4) { + printf("expected dcerpc opnum 0x%02x , got 0x%02x : ", 4, dcerpc_state->dcerpc.dcerpchdrudp.opnum); + result = 0; + goto end; + } - TAILQ_FOREACH(uuid_entry, &dcerpc_state->uuid_list, next) { - printUUID("REQUEST", uuid_entry); - } + TAILQ_FOREACH(uuid_entry, &dcerpc_state->uuid_list, next) { + printUUID("REQUEST", uuid_entry); + } end: if (alp_tctx != NULL) { @@ -1111,6 +1125,6 @@ int DCERPCUDPParserTest01(void) void DCERPCUDPParserRegisterTests(void) { - UtRegisterTest("DCERPCUDPParserTest01", DCERPCUDPParserTest01); + UtRegisterTest("DCERPCUDPParserTest01", DCERPCUDPParserTest01); } #endif From 199bb3bae3cc40ebb87fb0c8cc21bd7b951be678 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 6 May 2016 19:44:54 +0200 Subject: [PATCH 1587/2553] stream-tcp: fix ssn returning to wrong thread pool --- src/stream-tcp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index c339a0b26491..72fb4eda9bd0 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -228,7 +228,11 @@ void StreamTcpSessionClear(void *ssnptr) StreamTcpSessionCleanup(ssn); + /* HACK: don't loose track of thread id */ + PoolThreadReserved a = ssn->res; memset(ssn, 0, sizeof(TcpSession)); + ssn->res = a; + PoolThreadReturn(ssn_pool, ssn); #ifdef DEBUG SCMutexLock(&ssn_pool_mutex); From b79d9cda3a062cf2ac36e15435c0b03a7659ff69 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 18 Jul 2016 10:50:29 +0200 Subject: [PATCH 1588/2553] detect: minor cleanups --- src/detect.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/detect.c b/src/detect.c index 141e81910527..4abf58cd66e3 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3505,9 +3505,6 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) uint32_t cnt_applayer = 0; uint32_t cnt_deonly = 0; - //DetectAddressPrintMemory(); - //DetectPortPrintMemory(); - if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("building signature grouping structure, stage 1: " "preprocessing rules..."); @@ -3600,9 +3597,6 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) de_ctx->sig_cnt++; } - //DetectAddressPrintMemory(); - //DetectPortPrintMemory(); - if (!(de_ctx->flags & DE_QUIET)) { SCLogInfo("%" PRIu32 " signatures processed. %" PRIu32 " are IP-only " "rules, %" PRIu32 " are inspecting packet payload, %"PRIu32 @@ -4104,7 +4098,7 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); exit(EXIT_FAILURE); } -//exit(0); + if (SigAddressPrepareStage2(de_ctx) != 0) { SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); exit(EXIT_FAILURE); @@ -4119,8 +4113,8 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { #ifdef __SC_CUDA_SUPPORT__ + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) { /* setting it to default. You've gotta remove it once you fix the state table thing */ SCACConstructBoth16and32StateTables(); @@ -4137,8 +4131,7 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } } -#endif -#ifdef __SC_CUDA_SUPPORT__ + if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) { int r = SCCudaCtxPopCurrent(NULL); if (r < 0) { @@ -4150,14 +4143,12 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) /* too late to call this either ways. Should be called post ac goto. * \todo Support this. */ DetermineCudaStateTableSize(de_ctx); -#endif } +#endif + DetectMpmPrepareBuiltinMpms(de_ctx); DetectMpmPrepareAppMpms(de_ctx); -// DetectAddressPrintMemory(); -// DetectPortPrintMemory(); - if (SigMatchPrepare(de_ctx) != 0) { SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); exit(EXIT_FAILURE); From 0e2ea4e63ba4eb773fb94f16c13df69d2b8b983e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Aug 2016 09:39:48 +0200 Subject: [PATCH 1589/2553] detect: remove unused debug code --- src/detect-parse.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/detect-parse.c b/src/detect-parse.c index 4adef8f84ea4..01bf5fef30eb 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -76,9 +76,6 @@ static pcre *option_pcre = NULL; static pcre_extra *config_pcre_extra = NULL; static pcre_extra *option_pcre_extra = NULL; -static uint32_t dbg_srcportany_cnt = 0; -static uint32_t dbg_dstportany_cnt = 0; - /** * \brief We use this as data to the hash table DetectEngineCtx->dup_sig_hash_table. */ @@ -308,16 +305,6 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s return ret; } -uint32_t DbgGetSrcPortAnyCnt(void) -{ - return dbg_srcportany_cnt; -} - -uint32_t DbgGetDstPortAnyCnt(void) -{ - return dbg_dstportany_cnt; -} - SigMatch *SigMatchAlloc(void) { SigMatch *sm = SCMalloc(sizeof(SigMatch)); From 7d11af16ef4b007bbd440e8f8446d32dd8b0e988 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Aug 2016 12:58:33 +0200 Subject: [PATCH 1590/2553] detect: minor debug output cleanup --- src/detect-engine-iponly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index d39e6d501a05..b19d1cb6c56a 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -423,7 +423,7 @@ void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead) while (it != NULL) { i++; SCFree(it); - SCLogDebug("Item(%p) %"PRIu32" removed\n", it, i); + SCLogDebug("Item(%p) %"PRIu32" removed", it, i); it = next; if (next != NULL) From ec0217f52cb060b2b74725cd8fbb7aa03e84342f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Aug 2016 13:58:07 +0200 Subject: [PATCH 1591/2553] detect: minor style fixes --- src/detect-engine-mpm.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 4c0d7dc91c56..be02ed57d7a2 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1364,6 +1364,7 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) PatIntId max_id = 0; DetectFPAndItsId *struct_offset = (DetectFPAndItsId *)ahb; uint8_t *content_offset = ahb + struct_total_size; + for (s = de_ctx->sig_list; s != NULL; s = s->next) { if (s->mpm_sm != NULL) { int sm_list = SigMatchListSMBelongsTo(s, s->mpm_sm); @@ -1401,8 +1402,8 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) break; } if (dup != struct_offset) { - /* Exited for-loop before the end, so found an existing match. - * Use its ID. */ + /* Exited for-loop before the end, so found an existing match. + * Use its ID. */ cd->id = dup->id; continue; } @@ -1421,14 +1422,14 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) content_offset += content_len; if (flags & DETECT_CONTENT_NOCASE) { - /* Need to store case-insensitive patterns as lower case - * because SCMemcmpLowercase() above assumes that all - * patterns are stored lower case so that it doesn't - * need to relower its first argument. - */ - memcpy_tolower(struct_offset->content, content, content_len); + /* Need to store case-insensitive patterns as lower case + * because SCMemcmpLowercase() above assumes that all + * patterns are stored lower case so that it doesn't + * need to relower its first argument. + */ + memcpy_tolower(struct_offset->content, content, content_len); } else { - memcpy(struct_offset->content, content, content_len); + memcpy(struct_offset->content, content, content_len); } struct_offset++; From 305b1b90fd11b8684dbf85c44da5171abf6c3035 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 Jul 2016 12:11:02 +0200 Subject: [PATCH 1592/2553] detect: minor cleanup --- src/detect.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/detect.c b/src/detect.c index 4abf58cd66e3..a507e4716df7 100644 --- a/src/detect.c +++ b/src/detect.c @@ -695,18 +695,13 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) -// SigGroupHead *sgh) { SigIntId mpm, nonmpm; det_ctx->match_array_cnt = 0; SigIntId *mpm_ptr = det_ctx->pmq.rule_id_array; SigIntId *nonmpm_ptr = det_ctx->non_mpm_id_array; - //SigIntId *nonmpm_ptr = sgh->non_mpm_id_array; uint32_t m_cnt = det_ctx->pmq.rule_id_array_cnt; - //uint32_t n_cnt = sgh->non_mpm_id_cnt; uint32_t n_cnt = det_ctx->non_mpm_id_cnt; - SCLogDebug("PMQ rule id array count %d", det_ctx->pmq.rule_id_array_cnt); -// SCLogDebug("SGH non-MPM id count %d", sgh->non_mpm_id_cnt); SigIntId *final_ptr; uint32_t final_cnt; SigIntId id; @@ -715,6 +710,8 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, Signature **match_array = det_ctx->match_array; Signature *s; + SCLogDebug("PMQ rule id array count %d", det_ctx->pmq.rule_id_array_cnt); + /* Load first values. */ if (likely(m_cnt)) { mpm = *mpm_ptr; From 040660556eb1b4260c4998407baa48409e6f06df Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 1 Aug 2016 14:01:49 -0600 Subject: [PATCH 1593/2553] eve: log tag packets as packet events Create a new eve event type, "packet" for logging packets that are tagged as part of an event. The packet is still at the top level to keep it consistent with alert event types. In addition to the packet being logged, a packet_info object is created to hold the linktype and any future meta data we may want to add about the packet. --- src/output-json-alert.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 7476fbd2bd6c..03202983eb51 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -175,6 +175,23 @@ void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js) json_object_set_new(js, "alert", ajs); } +static void AlertJsonPacket(const Packet *p, json_t *js) +{ + unsigned long len = GET_PKT_LEN(p) * 2; + uint8_t encoded_packet[len]; + Base64Encode((unsigned char*) GET_PKT_DATA(p), GET_PKT_LEN(p), + encoded_packet, &len); + json_object_set_new(js, "packet", json_string((char *)encoded_packet)); + + /* Create packet info. */ + json_t *packetinfo_js = json_object(); + if (unlikely(packetinfo_js == NULL)) { + return; + } + json_object_set_new(packetinfo_js, "linktype", json_integer(p->datalink)); + json_object_set_new(js, "packet_info", packetinfo_js); +} + static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) { MemBuffer *payload = aft->payload_buffer; @@ -183,7 +200,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) int i; - if (p->alerts.cnt == 0) + if (p->alerts.cnt == 0 && !(p->flags & PKT_HAS_TAG)) return TM_ECODE_OK; json_t *js = CreateJSONHeader((Packet *)p, 0, "alert"); @@ -325,10 +342,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) /* base64-encoded full packet */ if (json_output_ctx->flags & LOG_JSON_PACKET) { - unsigned long len = GET_PKT_LEN(p) * 2; - uint8_t encoded_packet[len]; - Base64Encode((unsigned char*) GET_PKT_DATA(p), GET_PKT_LEN(p), encoded_packet, &len); - json_object_set_new(js, "packet", json_string((char *)encoded_packet)); + AlertJsonPacket(p, js); } HttpXFFCfg *xff_cfg = json_output_ctx->xff_cfg; @@ -368,6 +382,16 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) json_object_clear(js); json_decref(js); + if (p->flags & PKT_HAS_TAG) { + MemBufferReset(aft->json_buffer); + json_t *packetjs = CreateJSONHeader((Packet *)p, 0, "packet"); + if (unlikely(packetjs != NULL)) { + AlertJsonPacket(p, packetjs); + OutputJSONBuffer(packetjs, aft->file_ctx, &aft->json_buffer); + json_decref(packetjs); + } + } + return TM_ECODE_OK; } @@ -457,7 +481,10 @@ static int JsonAlertLogger(ThreadVars *tv, void *thread_data, const Packet *p) static int JsonAlertLogCondition(ThreadVars *tv, const Packet *p) { - return (p->alerts.cnt ? TRUE : FALSE); + if (p->alerts.cnt || (p->flags & PKT_HAS_TAG)) { + return TRUE; + } + return FALSE; } #define OUTPUT_BUFFER_SIZE 65535 From 1691c1068166ad351ebb8417bb6fb848ea63ba6d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 23 Aug 2016 11:37:42 -0600 Subject: [PATCH 1594/2553] eve: make logging of tagged packets optional But it is enabled in the default configuration. --- src/output-json-alert.c | 24 ++++++++++++++++-------- suricata.yaml.in | 4 ++++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 03202983eb51..e785337e9f9f 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -70,13 +70,14 @@ #ifdef HAVE_LIBJANSSON -#define LOG_JSON_PAYLOAD 1 -#define LOG_JSON_PACKET 2 -#define LOG_JSON_PAYLOAD_BASE64 4 -#define LOG_JSON_HTTP 8 -#define LOG_JSON_TLS 16 -#define LOG_JSON_SSH 32 -#define LOG_JSON_SMTP 64 +#define LOG_JSON_PAYLOAD 0x01 +#define LOG_JSON_PACKET 0x02 +#define LOG_JSON_PAYLOAD_BASE64 0x04 +#define LOG_JSON_HTTP 0x08 +#define LOG_JSON_TLS 0x10 +#define LOG_JSON_SSH 0x20 +#define LOG_JSON_SMTP 0x40 +#define LOG_JSON_TAGGED_PACKETS 0x80 #define JSON_STREAM_BUFFER_SIZE 4096 @@ -382,7 +383,8 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) json_object_clear(js); json_decref(js); - if (p->flags & PKT_HAS_TAG) { + if ((p->flags & PKT_HAS_TAG) && (json_output_ctx->flags & + LOG_JSON_TAGGED_PACKETS)) { MemBufferReset(aft->json_buffer); json_t *packetjs = CreateJSONHeader((Packet *)p, 0, "packet"); if (unlikely(packetjs != NULL)) { @@ -595,6 +597,7 @@ static void XffSetup(AlertJsonOutputCtx *json_output_ctx, ConfNode *conf) const char *tls = ConfNodeLookupChildValue(conf, "tls"); const char *ssh = ConfNodeLookupChildValue(conf, "ssh"); const char *smtp = ConfNodeLookupChildValue(conf, "smtp"); + const char *tagged_packets = ConfNodeLookupChildValue(conf, "tagged-packets"); if (ssh != NULL) { if (ConfValIsTrue(ssh)) { @@ -642,6 +645,11 @@ static void XffSetup(AlertJsonOutputCtx *json_output_ctx, ConfNode *conf) json_output_ctx->flags |= LOG_JSON_PACKET; } } + if (tagged_packets != NULL) { + if (ConfValIsTrue(tagged_packets)) { + json_output_ctx->flags |= LOG_JSON_TAGGED_PACKETS; + } + } json_output_ctx->payload_buffer_size = payload_buffer_size; HttpXFFGetCfg(conf, xff_cfg); diff --git a/suricata.yaml.in b/suricata.yaml.in index 5d87be99026c..18217d832059 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -164,6 +164,10 @@ outputs: ssh: yes # enable dumping of ssh fields smtp: yes # enable dumping of smtp fields + # Enable the logging of tagged packets for rules using the + # "tag" keyword. + tagged-packets: yes + # HTTP X-Forwarded-For support by adding an extra field or overwriting # the source or destination IP address (depending on flow direction) # with the one reported in the X-Forwarded-For HTTP header. This is From 0f6c8806a0800974a5680c891ea146fb8e1180d2 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Thu, 4 Feb 2016 12:19:14 -0800 Subject: [PATCH 1595/2553] output-json-dns: dns output filtering. --- src/output-json-dns.c | 414 ++++++++++++++++++++++++++++++++++++++++-- suricata.yaml.in | 9 +- 2 files changed, 404 insertions(+), 19 deletions(-) diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 5462b752dc85..ea218aac9b4c 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -56,9 +56,198 @@ * TX id handling doesn't expect it */ #define QUERY 0 +#define LOG_QUERIES (1L<<0) +#define LOG_ANSWERS (1L<<1) + +#define LOG_A (1L<<2) +#define LOG_NS (1L<<3) +#define LOG_MD (1L<<4) +#define LOG_MF (1L<<5) +#define LOG_CNAME (1L<<6) +#define LOG_SOA (1L<<7) +#define LOG_MB (1L<<8) +#define LOG_MG (1L<<9) +#define LOG_MR (1L<<10) +#define LOG_NULL (1L<<11) +#define LOG_WKS (1L<<12) +#define LOG_PTR (1L<<13) +#define LOG_HINFO (1L<<14) +#define LOG_MINFO (1L<<15) +#define LOG_MX (1L<<16) +#define LOG_TXT (1L<<17) +#define LOG_RP (1L<<18) +#define LOG_AFSDB (1L<<19) +#define LOG_X25 (1L<<20) +#define LOG_ISDN (1L<<21) +#define LOG_RT (1L<<22) +#define LOG_NSAP (1L<<23) +#define LOG_NSAPPTR (1L<<24) +#define LOG_SIG (1L<<25) +#define LOG_KEY (1L<<26) +#define LOG_PX (1L<<27) +#define LOG_GPOS (1L<<28) +#define LOG_AAAA (1L<<29) +#define LOG_LOC (1L<<30) +#define LOG_NXT (1L<<31) +#define LOG_SRV (1L<<32) +#define LOG_ATMA (1L<<33) +#define LOG_NAPTR (1L<<34) +#define LOG_KX (1L<<35) +#define LOG_CERT (1L<<36) +#define LOG_A6 (1L<<37) +#define LOG_DNAME (1L<<38) +#define LOG_OPT (1L<<39) +#define LOG_APL (1L<<40) +#define LOG_DS (1L<<41) +#define LOG_SSHFP (1L<<42) +#define LOG_IPSECKEY (1L<<43) +#define LOG_RRSIG (1L<<44) +#define LOG_NSEC (1L<<45) +#define LOG_DNSKEY (1L<<46) +#define LOG_DHCID (1L<<47) +#define LOG_NSEC3 (1L<<48) +#define LOG_NSEC3PARAM (1L<<49) +#define LOG_TLSA (1L<<50) +#define LOG_HIP (1L<<51) +#define LOG_CDS (1L<<52) +#define LOG_CDNSKEY (1L<<53) +#define LOG_SPF (1L<<54) +#define LOG_TKEY (1L<<55) +#define LOG_TSIG (1L<<56) +#define LOG_MAILA (1L<<57) +#define LOG_ANY (1L<<58) +#define LOG_URI (1L<<59) + +#define LOG_ALL_RRTYPES (~(uint64_t)(LOG_QUERIES|LOG_ANSWERS)) + +typedef enum { + DNS_RRTYPE_A = 0, + DNS_RRTYPE_NS, + DNS_RRTYPE_MD, + DNS_RRTYPE_MF, + DNS_RRTYPE_CNAME, + DNS_RRTYPE_SOA, + DNS_RRTYPE_MB, + DNS_RRTYPE_MG, + DNS_RRTYPE_MR, + DNS_RRTYPE_NULL, + DNS_RRTYPE_WKS, + DNS_RRTYPE_PTR, + DNS_RRTYPE_HINFO, + DNS_RRTYPE_MINFO, + DNS_RRTYPE_MX, + DNS_RRTYPE_TXT, + DNS_RRTYPE_RP, + DNS_RRTYPE_AFSDB, + DNS_RRTYPE_X25, + DNS_RRTYPE_ISDN, + DNS_RRTYPE_RT, + DNS_RRTYPE_NSAP, + DNS_RRTYPE_NSAPPTR, + DNS_RRTYPE_SIG, + DNS_RRTYPE_KEY, + DNS_RRTYPE_PX, + DNS_RRTYPE_GPOS, + DNS_RRTYPE_AAAA, + DNS_RRTYPE_LOC, + DNS_RRTYPE_NXT, + DNS_RRTYPE_SRV, + DNS_RRTYPE_ATMA, + DNS_RRTYPE_NAPTR, + DNS_RRTYPE_KX, + DNS_RRTYPE_CERT, + DNS_RRTYPE_A6, + DNS_RRTYPE_DNAME, + DNS_RRTYPE_OPT, + DNS_RRTYPE_APL, + DNS_RRTYPE_DS, + DNS_RRTYPE_SSHFP, + DNS_RRTYPE_IPSECKEY, + DNS_RRTYPE_RRSIG, + DNS_RRTYPE_NSEC, + DNS_RRTYPE_DNSKEY, + DNS_RRTYPE_DHCID, + DNS_RRTYPE_NSEC3, + DNS_RRTYPE_NSEC3PARAM, + DNS_RRTYPE_TLSA, + DNS_RRTYPE_HIP, + DNS_RRTYPE_CDS, + DNS_RRTYPE_CDNSKEY, + DNS_RRTYPE_SPF, + DNS_RRTYPE_TKEY, + DNS_RRTYPE_TSIG, + DNS_RRTYPE_MAILA, + DNS_RRTYPE_ANY, + DNS_RRTYPE_URI +} DnsRRTypes; + +static struct { + char *config_rrtype; + uint64_t flags; +} dns_rrtype_fields[] = { + { "a", LOG_A }, + { "ns", LOG_NS }, + { "md", LOG_MD }, + { "mf", LOG_MF }, + { "cname", LOG_CNAME }, + { "soa", LOG_SOA }, + { "mb", LOG_MB }, + { "mg", LOG_MG }, + { "mr", LOG_MR }, + { "null", LOG_NULL }, + { "wks", LOG_WKS }, + { "ptr", LOG_PTR }, + { "hinfo", LOG_HINFO }, + { "minfo", LOG_MINFO }, + { "mx", LOG_MX }, + { "txt", LOG_TXT }, + { "rp", LOG_RP }, + { "afsdb", LOG_AFSDB }, + { "x25", LOG_X25 }, + { "isdn", LOG_ISDN }, + { "rt", LOG_RT }, + { "nsap", LOG_NSAP }, + { "nsapptr", LOG_NSAPPTR }, + { "sig", LOG_SIG }, + { "key", LOG_KEY }, + { "px", LOG_PX }, + { "gpos", LOG_GPOS }, + { "aaaa", LOG_AAAA }, + { "loc", LOG_LOC }, + { "nxt", LOG_NXT }, + { "srv", LOG_SRV }, + { "atma", LOG_ATMA }, + { "naptr", LOG_NAPTR }, + { "kx", LOG_KX }, + { "cert", LOG_CERT }, + { "a6", LOG_A6 }, + { "dname", LOG_DNAME }, + { "opt", LOG_OPT }, + { "apl", LOG_APL }, + { "ds", LOG_DS }, + { "sshfp", LOG_SSHFP }, + { "ipseckey", LOG_IPSECKEY }, + { "rrsig", LOG_RRSIG }, + { "nsec", LOG_NSEC }, + { "dnskey", LOG_DNSKEY }, + { "dhcid", LOG_DHCID }, + { "nsec3", LOG_NSEC3 }, + { "nsec3param", LOG_NSEC3PARAM }, + { "tlsa", LOG_TLSA }, + { "hip", LOG_HIP }, + { "cds", LOG_CDS }, + { "cdnskey", LOG_CDNSKEY }, + { "spf", LOG_SPF }, + { "tkey", LOG_TKEY }, + { "tsig", LOG_TSIG }, + { "maila", LOG_MAILA }, + { "any", LOG_ANY }, + { "uri", LOG_URI } +}; + typedef struct LogDnsFileCtx_ { LogFileCtx *file_ctx; - uint32_t flags; /** Store mode */ + uint64_t flags; /** Store mode */ } LogDnsFileCtx; typedef struct LogDnsLogThread_ { @@ -69,6 +258,134 @@ typedef struct LogDnsLogThread_ { MemBuffer *buffer; } LogDnsLogThread; +static int DNSRRTypeEnabled(uint16_t type, uint64_t flags) +{ + if (likely(flags == ~0UL)) { + return 1; + } + + switch (type) { + case DNS_RECORD_TYPE_A: + return ((flags & LOG_A) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NS: + return ((flags & LOG_NS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MD: + return ((flags & LOG_MD) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MF: + return ((flags & LOG_MF) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CNAME: + return ((flags & LOG_CNAME) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SOA: + return ((flags & LOG_SOA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MB: + return ((flags & LOG_MB) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MG: + return ((flags & LOG_MG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MR: + return ((flags & LOG_MR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NULL: + return ((flags & LOG_NULL) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_WKS: + return ((flags & LOG_WKS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_PTR: + return ((flags & LOG_PTR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_HINFO: + return ((flags & LOG_HINFO) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MINFO: + return ((flags & LOG_MINFO) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MX: + return ((flags & LOG_MX) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TXT: + return ((flags & LOG_TXT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_RP: + return ((flags & LOG_RP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_AFSDB: + return ((flags & LOG_AFSDB) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_X25: + return ((flags & LOG_X25) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_ISDN: + return ((flags & LOG_ISDN) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_RT: + return ((flags & LOG_RT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSAP: + return ((flags & LOG_NSAP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSAPPTR: + return ((flags & LOG_NSAPPTR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SIG: + return ((flags & LOG_SIG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_KEY: + return ((flags & LOG_KEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_PX: + return ((flags & LOG_PX) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_GPOS: + return ((flags & LOG_GPOS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_AAAA: + return ((flags & LOG_AAAA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_LOC: + return ((flags & LOG_LOC) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NXT: + return ((flags & LOG_NXT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SRV: + return ((flags & LOG_SRV) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_ATMA: + return ((flags & LOG_ATMA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NAPTR: + return ((flags & LOG_NAPTR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_KX: + return ((flags & LOG_KX) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CERT: + return ((flags & LOG_CERT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_A6: + return ((flags & LOG_A6) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DNAME: + return ((flags & LOG_DNAME) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_OPT: + return ((flags & LOG_OPT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_APL: + return ((flags & LOG_APL) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DS: + return ((flags & LOG_DS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SSHFP: + return ((flags & LOG_SSHFP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_IPSECKEY: + return ((flags & LOG_IPSECKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_RRSIG: + return ((flags & LOG_RRSIG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSEC: + return ((flags & LOG_NSEC) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DNSKEY: + return ((flags & LOG_DNSKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DHCID: + return ((flags & LOG_DHCID) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSEC3: + return ((flags & LOG_NSEC3) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSEC3PARAM: + return ((flags & LOG_NSEC3PARAM) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TLSA: + return ((flags & LOG_TLSA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_HIP: + return ((flags & LOG_HIP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CDS: + return ((flags & LOG_CDS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CDNSKEY: + return ((flags & LOG_CDNSKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SPF: + return ((flags & LOG_SPF) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TKEY: + return ((flags & LOG_TKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TSIG: + return ((flags & LOG_TSIG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MAILA: + return ((flags & LOG_MAILA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_ANY: + return ((flags & LOG_ANY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_URI: + return ((flags & LOG_URI) != 0) ? 1 : 0; + default: + return 0; + } +} + static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uint64_t tx_id, DNSQueryEntry *entry) { @@ -106,7 +423,9 @@ static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, /* dns */ json_object_set_new(js, "dns", djs); - OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, &aft->buffer); + if (likely(DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags))) { + OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, &aft->buffer); + } json_object_del(js, "dns"); } @@ -210,7 +529,9 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, /* reset */ MemBufferReset(aft->buffer); json_object_set_new(djs, "dns", js); - OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); + if (likely(DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags))) { + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); + } json_object_del(djs, "dns"); return; @@ -244,7 +565,9 @@ static void OutputFailure(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, /* reset */ MemBufferReset(aft->buffer); json_object_set_new(djs, "dns", js); - OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); + if (likely(DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags))) { + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); + } json_object_del(djs, "dns"); return; @@ -284,18 +607,21 @@ static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data, SCEnter(); LogDnsLogThread *td = (LogDnsLogThread *)thread_data; + LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx; DNSTransaction *tx = txptr; json_t *js; - DNSQueryEntry *query = NULL; - TAILQ_FOREACH(query, &tx->query_list, next) { - js = CreateJSONHeader((Packet *)p, 1, "dns"); - if (unlikely(js == NULL)) - return TM_ECODE_OK; + if (likely(dnslog_ctx->flags & LOG_QUERIES) != 0) { + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &tx->query_list, next) { + js = CreateJSONHeader((Packet *)p, 1, "dns"); + if (unlikely(js == NULL)) + return TM_ECODE_OK; - LogQuery(td, js, tx, tx_id, query); + LogQuery(td, js, tx, tx_id, query); - json_decref(js); + json_decref(js); + } } SCReturnInt(TM_ECODE_OK); @@ -307,16 +633,19 @@ static int JsonDnsLoggerToClient(ThreadVars *tv, void *thread_data, SCEnter(); LogDnsLogThread *td = (LogDnsLogThread *)thread_data; + LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx; DNSTransaction *tx = txptr; json_t *js; - js = CreateJSONHeader((Packet *)p, 0, "dns"); - if (unlikely(js == NULL)) - return TM_ECODE_OK; + if (likely(dnslog_ctx->flags & LOG_ANSWERS) != 0) { + js = CreateJSONHeader((Packet *)p, 0, "dns"); + if (unlikely(js == NULL)) + return TM_ECODE_OK; - LogAnswers(td, js, tx, tx_id); + LogAnswers(td, js, tx, tx_id); - json_decref(js); + json_decref(js); + } SCReturnInt(TM_ECODE_OK); } @@ -380,9 +709,54 @@ static void LogDnsLogDeInitCtxSub(OutputCtx *output_ctx) SCFree(output_ctx); } +static void JsonDnsLogInitFilters(LogDnsFileCtx *dnslog_ctx, ConfNode *conf) +{ + dnslog_ctx->flags = ~0UL; + + if (conf) { + const char *query = ConfNodeLookupChildValue(conf, "query"); + if (query != NULL) { + if (ConfValIsTrue(query)) { + dnslog_ctx->flags |= LOG_QUERIES; + } else { + dnslog_ctx->flags &= ~LOG_QUERIES; + } + } + const char *response = ConfNodeLookupChildValue(conf, "answer"); + if (response != NULL) { + if (ConfValIsTrue(response)) { + dnslog_ctx->flags |= LOG_ANSWERS; + } else { + dnslog_ctx->flags &= ~LOG_ANSWERS; + } + } + ConfNode *custom; + if ((custom = ConfNodeLookupChild(conf, "custom")) != NULL) { + dnslog_ctx->flags &= ~LOG_ALL_RRTYPES; + ConfNode *field; + TAILQ_FOREACH(field, &custom->head, next) + { + if (field != NULL) + { + DnsRRTypes f; + for (f = DNS_RRTYPE_A; f < DNS_RRTYPE_TXT; f++) + { + if (strcasecmp(dns_rrtype_fields[f].config_rrtype, + field->val) == 0) + { + dnslog_ctx->flags |= dns_rrtype_fields[f].flags; + break; + } + } + } + } + } + } +} + static OutputCtx *JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; LogDnsFileCtx *dnslog_ctx = SCMalloc(sizeof(LogDnsFileCtx)); if (unlikely(dnslog_ctx == NULL)) { @@ -390,7 +764,7 @@ static OutputCtx *JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) } memset(dnslog_ctx, 0x00, sizeof(LogDnsFileCtx)); - dnslog_ctx->file_ctx = ajt->file_ctx; + dnslog_ctx->file_ctx = ojc->file_ctx; OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { @@ -401,6 +775,8 @@ static OutputCtx *JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) output_ctx->data = dnslog_ctx; output_ctx->DeInit = LogDnsLogDeInitCtxSub; + JsonDnsLogInitFilters(dnslog_ctx, conf); + SCLogDebug("DNS log sub-module initialized"); AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); @@ -447,6 +823,8 @@ static OutputCtx *JsonDnsLogInitCtx(ConfNode *conf) output_ctx->data = dnslog_ctx; output_ctx->DeInit = LogDnsLogDeInitCtx; + JsonDnsLogInitFilters(dnslog_ctx, conf); + SCLogDebug("DNS log output initialized"); AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); diff --git a/suricata.yaml.in b/suricata.yaml.in index 18217d832059..d2fb45f7583d 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -190,7 +190,14 @@ outputs: # custom allows additional http fields to be included in eve-log # the example below adds three additional fields when uncommented #custom: [Accept-Encoding, Accept-Language, Authorization] - - dns + - dns: + # control logging of queries and answers + # default yes, no to disable + query: yes # enable logging of DNS queries + answer: yes # enable logging of DNS answers + # control which RR types are logged + # all enabled if custom not specified + #custom: [a, aaaa, cname, mx, ns, ptr, txt] - tls: extended: yes # enable this for extended logging information - files: From 5c6ffe5653db6a6f423a29891c25fe65397fab24 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 29 Aug 2016 13:14:51 +0200 Subject: [PATCH 1596/2553] common: introduce macro for bit declarations --- src/suricata-common.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/suricata-common.h b/src/suricata-common.h index 141e8671d961..da44d33520fe 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -301,6 +301,9 @@ #define MAX(x, y) (((x)<(y))?(y):(x)) #endif +#define BIT_U32(n) (1UL << (n)) +#define BIT_U64(n) (1ULL << (n)) + typedef enum PacketProfileDetectId_ { PROF_DETECT_MPM, PROF_DETECT_MPM_PACKET, /* PKT MPM */ From 2eb941f9d9296c6812761c0645b4174a41e806d1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 29 Aug 2016 13:17:31 +0200 Subject: [PATCH 1597/2553] output dns: fix bit declarations --- src/output-json-dns.c | 122 +++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/src/output-json-dns.c b/src/output-json-dns.c index ea218aac9b4c..5b35949318bc 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -56,67 +56,67 @@ * TX id handling doesn't expect it */ #define QUERY 0 -#define LOG_QUERIES (1L<<0) -#define LOG_ANSWERS (1L<<1) - -#define LOG_A (1L<<2) -#define LOG_NS (1L<<3) -#define LOG_MD (1L<<4) -#define LOG_MF (1L<<5) -#define LOG_CNAME (1L<<6) -#define LOG_SOA (1L<<7) -#define LOG_MB (1L<<8) -#define LOG_MG (1L<<9) -#define LOG_MR (1L<<10) -#define LOG_NULL (1L<<11) -#define LOG_WKS (1L<<12) -#define LOG_PTR (1L<<13) -#define LOG_HINFO (1L<<14) -#define LOG_MINFO (1L<<15) -#define LOG_MX (1L<<16) -#define LOG_TXT (1L<<17) -#define LOG_RP (1L<<18) -#define LOG_AFSDB (1L<<19) -#define LOG_X25 (1L<<20) -#define LOG_ISDN (1L<<21) -#define LOG_RT (1L<<22) -#define LOG_NSAP (1L<<23) -#define LOG_NSAPPTR (1L<<24) -#define LOG_SIG (1L<<25) -#define LOG_KEY (1L<<26) -#define LOG_PX (1L<<27) -#define LOG_GPOS (1L<<28) -#define LOG_AAAA (1L<<29) -#define LOG_LOC (1L<<30) -#define LOG_NXT (1L<<31) -#define LOG_SRV (1L<<32) -#define LOG_ATMA (1L<<33) -#define LOG_NAPTR (1L<<34) -#define LOG_KX (1L<<35) -#define LOG_CERT (1L<<36) -#define LOG_A6 (1L<<37) -#define LOG_DNAME (1L<<38) -#define LOG_OPT (1L<<39) -#define LOG_APL (1L<<40) -#define LOG_DS (1L<<41) -#define LOG_SSHFP (1L<<42) -#define LOG_IPSECKEY (1L<<43) -#define LOG_RRSIG (1L<<44) -#define LOG_NSEC (1L<<45) -#define LOG_DNSKEY (1L<<46) -#define LOG_DHCID (1L<<47) -#define LOG_NSEC3 (1L<<48) -#define LOG_NSEC3PARAM (1L<<49) -#define LOG_TLSA (1L<<50) -#define LOG_HIP (1L<<51) -#define LOG_CDS (1L<<52) -#define LOG_CDNSKEY (1L<<53) -#define LOG_SPF (1L<<54) -#define LOG_TKEY (1L<<55) -#define LOG_TSIG (1L<<56) -#define LOG_MAILA (1L<<57) -#define LOG_ANY (1L<<58) -#define LOG_URI (1L<<59) +#define LOG_QUERIES BIT_U64(0) +#define LOG_ANSWERS BIT_U64(1) + +#define LOG_A BIT_U64(2) +#define LOG_NS BIT_U64(3) +#define LOG_MD BIT_U64(4) +#define LOG_MF BIT_U64(5) +#define LOG_CNAME BIT_U64(6) +#define LOG_SOA BIT_U64(7) +#define LOG_MB BIT_U64(8) +#define LOG_MG BIT_U64(9) +#define LOG_MR BIT_U64(10) +#define LOG_NULL BIT_U64(11) +#define LOG_WKS BIT_U64(12) +#define LOG_PTR BIT_U64(13) +#define LOG_HINFO BIT_U64(14) +#define LOG_MINFO BIT_U64(15) +#define LOG_MX BIT_U64(16) +#define LOG_TXT BIT_U64(17) +#define LOG_RP BIT_U64(18) +#define LOG_AFSDB BIT_U64(19) +#define LOG_X25 BIT_U64(20) +#define LOG_ISDN BIT_U64(21) +#define LOG_RT BIT_U64(22) +#define LOG_NSAP BIT_U64(23) +#define LOG_NSAPPTR BIT_U64(24) +#define LOG_SIG BIT_U64(25) +#define LOG_KEY BIT_U64(26) +#define LOG_PX BIT_U64(27) +#define LOG_GPOS BIT_U64(28) +#define LOG_AAAA BIT_U64(29) +#define LOG_LOC BIT_U64(30) +#define LOG_NXT BIT_U64(31) +#define LOG_SRV BIT_U64(32) +#define LOG_ATMA BIT_U64(33) +#define LOG_NAPTR BIT_U64(34) +#define LOG_KX BIT_U64(35) +#define LOG_CERT BIT_U64(36) +#define LOG_A6 BIT_U64(37) +#define LOG_DNAME BIT_U64(38) +#define LOG_OPT BIT_U64(39) +#define LOG_APL BIT_U64(40) +#define LOG_DS BIT_U64(41) +#define LOG_SSHFP BIT_U64(42) +#define LOG_IPSECKEY BIT_U64(43) +#define LOG_RRSIG BIT_U64(44) +#define LOG_NSEC BIT_U64(45) +#define LOG_DNSKEY BIT_U64(46) +#define LOG_DHCID BIT_U64(47) +#define LOG_NSEC3 BIT_U64(48) +#define LOG_NSEC3PARAM BIT_U64(49) +#define LOG_TLSA BIT_U64(50) +#define LOG_HIP BIT_U64(51) +#define LOG_CDS BIT_U64(52) +#define LOG_CDNSKEY BIT_U64(53) +#define LOG_SPF BIT_U64(54) +#define LOG_TKEY BIT_U64(55) +#define LOG_TSIG BIT_U64(56) +#define LOG_MAILA BIT_U64(57) +#define LOG_ANY BIT_U64(58) +#define LOG_URI BIT_U64(59) #define LOG_ALL_RRTYPES (~(uint64_t)(LOG_QUERIES|LOG_ANSWERS)) From 6b078e4f51800ac4cba3660dedfe210474491bc6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 30 Aug 2016 19:35:18 +0200 Subject: [PATCH 1598/2553] detect: fix ICMP error handling issue The first packet in both directions of a flow looks up the rule group (sgh) and stores it in the flow. This makes sure the lookup doesn't have to be performed for each packet. ICMPv4 error messages are connected to the TCP or UDP flow they apply to. In the case of such an ICMP error being the first packet in a flow's direction, this would lead to an issue. The packet would look up the rule group based on the ICMP protocol, not based on the embedded TCP/UDP. This makes sense, as the ICMP packet is inspected as ICMP packet. The consequence however, was that this rule group pointer (sgh) would be stored in the flow. This is wrong, as TCP/UDP packets that follow the ICMP packet would have no sgh or the wrong sgh. In normal traffic this shouldn't normally happen, but it could be used to evade Suricata's inspection. --- src/detect.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/detect.c b/src/detect.c index a507e4716df7..3ae6e0f8605f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1816,7 +1816,12 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } } - if (!(sms_runflags & SMS_USE_FLOW_SGH)) { + /* HACK: prevent the wrong sgh (or NULL) from being stored in the + * flow's sgh pointers */ + if (PKT_IS_ICMPV4(p) && ICMPV4_DEST_UNREACH_IS_VALID(p)) { + ; /* no-op */ + + } else if (!(sms_runflags & SMS_USE_FLOW_SGH)) { if ((p->flowflags & FLOW_PKT_TOSERVER) && !(pflow->flags & FLOW_SGH_TOSERVER)) { /* first time we see this toserver sgh, store it */ pflow->sgh_toserver = det_ctx->sgh; From ecf4a2862c474145d435018e1cd999d35ca1d43a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 30 Aug 2016 20:54:35 +0200 Subject: [PATCH 1599/2553] detect: cleanup --- src/detect-engine-state.h | 52 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 7b48f2c5b7cd..37ff65e5cc1d 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -63,32 +63,32 @@ #define DE_STATE_CHUNK_SIZE 15 /* per sig flags */ -#define DE_STATE_FLAG_URI_INSPECT (1) -#define DE_STATE_FLAG_HRUD_INSPECT (1 << 1) -#define DE_STATE_FLAG_HCBD_INSPECT (1 << 2) -#define DE_STATE_FLAG_HSBD_INSPECT (1 << 3) -#define DE_STATE_FLAG_HHD_INSPECT (1 << 4) -#define DE_STATE_FLAG_HRHD_INSPECT (1 << 5) -#define DE_STATE_FLAG_HHHD_INSPECT (1 << 6) -#define DE_STATE_FLAG_HRHHD_INSPECT (1 << 7) -#define DE_STATE_FLAG_HUAD_INSPECT (1 << 8) -#define DE_STATE_FLAG_HMD_INSPECT (1 << 9) -#define DE_STATE_FLAG_HCD_INSPECT (1 << 10) -#define DE_STATE_FLAG_HSMD_INSPECT (1 << 11) -#define DE_STATE_FLAG_HSCD_INSPECT (1 << 12) -#define DE_STATE_FLAG_FILE_TC_INSPECT (1 << 13) -#define DE_STATE_FLAG_FILE_TS_INSPECT (1 << 14) -#define DE_STATE_FLAG_FULL_INSPECT (1 << 15) -#define DE_STATE_FLAG_SIG_CANT_MATCH (1 << 16) -#define DE_STATE_FLAG_DNSQUERYNAME_INSPECT (1 << 17) -#define DE_STATE_FLAG_APP_EVENT_INSPECT (1 << 18) -#define DE_STATE_FLAG_MODBUS_INSPECT (1 << 19) -#define DE_STATE_FLAG_HRL_INSPECT (1 << 20) -#define DE_STATE_FLAG_FD_SMTP_INSPECT (1 << 21) -#define DE_STATE_FLAG_DNSREQUEST_INSPECT (1 << 22) -#define DE_STATE_FLAG_DNSRESPONSE_INSPECT (1 << 23) -#define DE_STATE_FLAG_TLSSNI_INSPECT (1 << 24) -#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT (1 << 25) +#define DE_STATE_FLAG_URI_INSPECT BIT_U32(0) +#define DE_STATE_FLAG_HRUD_INSPECT BIT_U32(1) +#define DE_STATE_FLAG_HCBD_INSPECT BIT_U32(2) +#define DE_STATE_FLAG_HSBD_INSPECT BIT_U32(3) +#define DE_STATE_FLAG_HHD_INSPECT BIT_U32(4) +#define DE_STATE_FLAG_HRHD_INSPECT BIT_U32(5) +#define DE_STATE_FLAG_HHHD_INSPECT BIT_U32(6) +#define DE_STATE_FLAG_HRHHD_INSPECT BIT_U32(7) +#define DE_STATE_FLAG_HUAD_INSPECT BIT_U32(8) +#define DE_STATE_FLAG_HMD_INSPECT BIT_U32(9) +#define DE_STATE_FLAG_HCD_INSPECT BIT_U32(10) +#define DE_STATE_FLAG_HSMD_INSPECT BIT_U32(11) +#define DE_STATE_FLAG_HSCD_INSPECT BIT_U32(12) +#define DE_STATE_FLAG_FILE_TC_INSPECT BIT_U32(13) +#define DE_STATE_FLAG_FILE_TS_INSPECT BIT_U32(14) +#define DE_STATE_FLAG_FULL_INSPECT BIT_U32(15) +#define DE_STATE_FLAG_SIG_CANT_MATCH BIT_U32(16) +#define DE_STATE_FLAG_DNSQUERYNAME_INSPECT BIT_U32(17) +#define DE_STATE_FLAG_APP_EVENT_INSPECT BIT_U32(18) +#define DE_STATE_FLAG_MODBUS_INSPECT BIT_U32(19) +#define DE_STATE_FLAG_HRL_INSPECT BIT_U32(20) +#define DE_STATE_FLAG_FD_SMTP_INSPECT BIT_U32(21) +#define DE_STATE_FLAG_DNSREQUEST_INSPECT BIT_U32(22) +#define DE_STATE_FLAG_DNSRESPONSE_INSPECT BIT_U32(23) +#define DE_STATE_FLAG_TLSSNI_INSPECT BIT_U32(24) +#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(25) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 From 666bba8121155292c5fcab97b0630af5d537c2c7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 30 Aug 2016 21:44:44 +0200 Subject: [PATCH 1600/2553] detect: implement continue detect for dcepayload Also fix a corner case in start detection. Bug 1853. --- src/detect-engine-state.c | 111 +++++++++++++++++++++++++++----------- src/detect-engine-state.h | 3 +- 2 files changed, 81 insertions(+), 33 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index e05d18dbbf4b..4fa24ea51a94 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -480,14 +480,15 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SigMatch *sm = NULL; uint16_t file_no_match = 0; uint32_t inspect_flags = 0; - uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; int alert_cnt = 0; - int check_before_add = 0; + int dmatch = 0; SCLogDebug("rule %u", s->id); /* TX based matches (inspect engines) */ if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { + uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; + int check_before_add = 0; uint64_t tx_id = 0; uint64_t total_txs = 0; @@ -631,28 +632,19 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (smb_state->dcerpc_present && DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, flags, &smb_state->dcerpc) == 1) { - if (!(s->flags & SIG_FLAG_NOALERT)) { - PacketAlertAppend(det_ctx, s, p, 0, - PACKET_ALERT_FLAG_STATE_MATCH); - } else { - DetectSignatureApplyActions(p, s); - } - alert_cnt = 1; + inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; + dmatch = 1; } } else { if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, flags, alstate) == 1) { - if (!(s->flags & SIG_FLAG_NOALERT)) { - PacketAlertAppend(det_ctx, s, p, 0, - PACKET_ALERT_FLAG_STATE_MATCH); - } else { - DetectSignatureApplyActions(p, s); - } - alert_cnt = 1; + inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; + dmatch = 1; } } } + int amatch = 0; /* flow based matches */ KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_AMATCH); sm = s->sm_lists[DETECT_SM_LIST_AMATCH]; @@ -662,10 +654,9 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, goto end; } - int match = 0; for ( ; sm != NULL; sm = sm->next) { if (sigmatch_table[sm->type].AppLayerMatch != NULL) { - match = 0; + int match = 0; if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { SMBState *smb_state = (SMBState *)alstate; if (smb_state->dcerpc_present) { @@ -681,17 +672,37 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, KEYWORD_PROFILING_END(det_ctx, sm->type, (match == 1)); } - if (match == 0) + if (match == 0) { break; - if (match == 2) { + } else if (match == 2) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; break; + } else if (match == 1 && sm->next == NULL) { + amatch = 1; } } } + } - if (sm == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) { - if (match == 1) { + /* if AMATCH and/or DMATCH are in use, see if we need to + * alert and store the state */ + if ((s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL || + s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL)) + { + /* if dmatch in use and match + amatch in use and match + or + if dmatch in use and match + amatch not in use + or + if dmatch not in use + amatch in use and match + or + sig can't match + */ + if (inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) { + inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; + } else { + if ((amatch || s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) && + (dmatch || s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL)) + { if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, 0, PACKET_ALERT_FLAG_STATE_MATCH); @@ -699,14 +710,14 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectSignatureApplyActions(p, s); } alert_cnt = 1; + + inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; } - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; } StoreState(det_ctx, f, flags, alversion, s, sm, inspect_flags, file_no_match); } - end: det_ctx->tx_id = 0; det_ctx->tx_id_set = 0; @@ -931,8 +942,9 @@ static int DoInspectFlowRule(ThreadVars *tv, } uint8_t alert = 0; - uint32_t inspect_flags = 0; + uint32_t inspect_flags = item->flags; int total_matches = 0; + int full_match = 0; SigMatch *sm = NULL; Signature *s = de_ctx->sig_array[item->sid]; @@ -974,16 +986,51 @@ static int DoInspectFlowRule(ThreadVars *tv, } } } + /* AMATCH part checked out, or isn't there at all */ + full_match = (sm == NULL); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - if (total_matches > 0 && (sm == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { - if (sm == NULL) - alert = 1; - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; + /* DCERPC matches */ + if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL && + (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || + alproto == ALPROTO_SMB2) && + !(item->flags & DE_STATE_FLAG_DCE_PAYLOAD_INSPECT)) + { + void *alstate = FlowGetAppState(f); + if (alstate != NULL) { + KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_DMATCH); + if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { + SMBState *smb_state = (SMBState *)alstate; + if (smb_state->dcerpc_present && + DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, + flags, &smb_state->dcerpc) == 1) + { + total_matches++; + inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; + } + } else { + if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, + flags, alstate) == 1) + { + total_matches++; + inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; + } + } } - /* prevent the rule loop from reinspecting this rule */ - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; } + /* update full_match with DMATCH result */ + if (full_match && s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { + full_match = ((inspect_flags & DE_STATE_FLAG_DCE_PAYLOAD_INSPECT) != 0); + } + + /* check the results */ + if (total_matches > 0 && (full_match || (inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH))) + { + if (full_match) + alert = 1; + inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; + } + /* prevent the rule loop from reinspecting this rule */ + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; RULE_PROFILING_END(det_ctx, s, (alert == 1), p); /* store the progress in the state */ diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 37ff65e5cc1d..dcbbc9c499ed 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -88,7 +88,8 @@ #define DE_STATE_FLAG_DNSREQUEST_INSPECT BIT_U32(22) #define DE_STATE_FLAG_DNSRESPONSE_INSPECT BIT_U32(23) #define DE_STATE_FLAG_TLSSNI_INSPECT BIT_U32(24) -#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(25) +#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(25) +#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(26) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 From 78b4db8a954f5937d07ec494e7113e292228e189 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 31 Aug 2016 15:04:58 +0200 Subject: [PATCH 1601/2553] flow: introduce function to generate flow id The flow id itself is not stored in the flow, but generated based on properties that do not change during the lifetime of the flow. As it's meant for use with the json output, it is limited to a signed 64 bit integer (int64_t) because that is the time json_integer_t uses. --- src/flow.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/flow.h b/src/flow.h index 0400250e2362..b5dbe5708599 100644 --- a/src/flow.h +++ b/src/flow.h @@ -536,6 +536,18 @@ static inline void FlowDeReference(Flow **d) } } +/** \brief create a flow id that is as unique as possible + * \retval flow_id signed 64bit id + * \note signed because of the signedness of json_integer_t in + * the json output + */ +static inline int64_t FlowGetId(const Flow *f) +{ + return (int64_t)f->flow_hash << 31 | + (int64_t)(f->startts.tv_sec & 0x0000FFFF) << 16 | + (int64_t)(f->startts.tv_usec & 0x0000FFFF); +} + int FlowClearMemory(Flow *,uint8_t ); AppProto FlowGetAppProtocol(const Flow *f); From 9ca34fa5c98b6028b0f05fe3f709cc36df7dca66 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 31 Aug 2016 15:08:58 +0200 Subject: [PATCH 1602/2553] eve: output more unique flow_id --- src/output-json.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/output-json.c b/src/output-json.c index 3d14d70a070a..cf19df8acf61 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -166,7 +166,8 @@ void CreateJSONFlowId(json_t *js, const Flow *f) { if (f == NULL) return; - json_object_set_new(js, "flow_id", json_integer(f->flow_hash)); + int64_t flow_id = FlowGetId(f); + json_object_set_new(js, "flow_id", json_integer(flow_id)); } json_t *CreateJSONHeader(const Packet *p, int direction_sensitive, From 5db322045e21e880efed96b07aaac4eb6e7abbe9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Sep 2016 11:13:48 +0200 Subject: [PATCH 1603/2553] configure: fix Ubuntu lua pkg suggestion --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 462058477bcf..8cabd35ce002 100644 --- a/configure.ac +++ b/configure.ac @@ -1662,7 +1662,7 @@ echo " ERROR! liblua library not found, go get it" echo " from http://lua.org/index.html or your distribution:" echo - echo " Ubuntu: apt-get install liblua-5.1-dev" + echo " Ubuntu: apt-get install liblua5.1-dev" echo " CentOS/Fedora: yum install lua-devel" echo echo " If you installed software in a non-standard prefix" @@ -1698,7 +1698,7 @@ echo " ERROR! liblua headers not found, go get them" echo " from http://lua.org/index.html or your distribution:" echo - echo " Ubuntu: apt-get install liblua-5.1-dev" + echo " Ubuntu: apt-get install liblua5.1-dev" echo " CentOS/Fedora: yum install lua-devel" echo echo " If you installed software in a non-standard prefix" From b81ea0d7dbcfd3c997b6d02806e79214fb45244d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Sep 2016 20:34:26 +0200 Subject: [PATCH 1604/2553] eve: reduce flow_id to 51 bits Evebox & ELK couldn't handle the large integers. It looks like (partly) a javascript limitation that doesn't treat 64bit ints as real ints. --- src/output-json.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/output-json.c b/src/output-json.c index cf19df8acf61..7fb06c535a82 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -167,6 +167,9 @@ void CreateJSONFlowId(json_t *js, const Flow *f) if (f == NULL) return; int64_t flow_id = FlowGetId(f); + /* reduce to 51 bits as Javascript and even JSON often seem to + * max out there. */ + flow_id &= 0x7ffffffffffffLL; json_object_set_new(js, "flow_id", json_integer(flow_id)); } From 8600872e02f3b160338e830a50ca96395dae2125 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Sep 2016 10:12:54 +0200 Subject: [PATCH 1605/2553] logfile: resolve name clash on SunOS --- src/util-logopenfile.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 63cc05acbb7c..120742a1f996 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -46,19 +46,19 @@ const char * redis_publish_cmd = "PUBLISH"; static FILE * SCLogOpenUnixSocketFp(const char *path, int sock_type, int log_err) { - struct sockaddr_un sun; + struct sockaddr_un saun; int s = -1; FILE * ret = NULL; - memset(&sun, 0x00, sizeof(sun)); + memset(&saun, 0x00, sizeof(saun)); s = socket(PF_UNIX, sock_type, 0); if (s < 0) goto err; - sun.sun_family = AF_UNIX; - strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); + saun.sun_family = AF_UNIX; + strlcpy(saun.sun_path, path, sizeof(saun.sun_path)); - if (connect(s, (const struct sockaddr *)&sun, sizeof(sun)) < 0) + if (connect(s, (const struct sockaddr *)&saun, sizeof(saun)) < 0) goto err; ret = fdopen(s, "w"); From ec871233396282c61beff7e0ccdba3c222450edc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Sep 2016 10:14:04 +0200 Subject: [PATCH 1606/2553] configure: check for strings.h: used by SunOS --- configure.ac | 2 +- src/suricata-common.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8cabd35ce002..55c02f7c21a9 100644 --- a/configure.ac +++ b/configure.ac @@ -126,7 +126,7 @@ AC_CHECK_HEADERS([arpa/inet.h assert.h ctype.h errno.h fcntl.h inttypes.h]) AC_CHECK_HEADERS([getopt.h]) AC_CHECK_HEADERS([limits.h netdb.h netinet/in.h poll.h sched.h signal.h]) - AC_CHECK_HEADERS([stdarg.h stdint.h stdio.h stdlib.h string.h sys/ioctl.h]) + AC_CHECK_HEADERS([stdarg.h stdint.h stdio.h stdlib.h string.h strings.h sys/ioctl.h]) AC_CHECK_HEADERS([syslog.h sys/prctl.h sys/socket.h sys/stat.h sys/syscall.h]) AC_CHECK_HEADERS([sys/time.h time.h unistd.h]) AC_CHECK_HEADERS([sys/ioctl.h linux/if_ether.h linux/if_packet.h linux/filter.h]) diff --git a/src/suricata-common.h b/src/suricata-common.h index da44d33520fe..0db433f9c47c 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -89,6 +89,10 @@ #include #endif +#if HAVE_STRINGS_H +#include +#endif + #if HAVE_FCNTL_H #include #endif From 6956c1c749fd97d48a989e3a98f3550b026ab0dc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Sep 2016 10:14:52 +0200 Subject: [PATCH 1607/2553] decode: fix int types --- src/source-pcap-file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 92fb6f6fa20a..6a587e2b22c7 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -61,7 +61,7 @@ extern int max_pending_packets; typedef struct PcapFileGlobalVars_ { pcap_t *pcap_handle; - int (*Decoder)(ThreadVars *, DecodeThreadVars *, Packet *, u_int8_t *, u_int16_t, PacketQueue *); + int (*Decoder)(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int datalink; struct bpf_program filter; uint64_t cnt; /** packet counter */ From 4271d571579725586a943ef78900750cbe688c94 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Sep 2016 10:15:23 +0200 Subject: [PATCH 1608/2553] decode: declare IPPROTO_IPIP if OS doesn't have it --- src/decode.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/decode.h b/src/decode.h index 2c759c0122eb..2a5d39d38eae 100644 --- a/src/decode.h +++ b/src/decode.h @@ -982,6 +982,10 @@ int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder); r; \ }) +#ifndef IPPROTO_IPIP +#define IPPROTO_IPIP 4 +#endif + /* older libcs don't contain a def for IPPROTO_DCCP * inside of * if it isn't defined let's define it here. From ef1acdfaeec1941f513d5f98fd54bda3c8388a7d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Sep 2016 10:15:52 +0200 Subject: [PATCH 1609/2553] threads: provide SCGetThreadIdLong for SunOS --- src/threads.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/threads.h b/src/threads.h index 0a843b7ff034..213b064243b3 100644 --- a/src/threads.h +++ b/src/threads.h @@ -243,6 +243,14 @@ enum { u_long tid = (u_long)tpid; \ tid; \ }) +#elif defined(sun) +#include +#define SCGetThreadIdLong(...) ({ \ + thread_t tmpthid = thr_self(); \ + u_long tid = (u_long)tmpthid; \ + tid; \ +}) + #else #define SCGetThreadIdLong(...) ({ \ pid_t tmpthid; \ From 7847c4f8eeee65b81ada71d7245005ac6319b157 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Sep 2016 10:16:30 +0200 Subject: [PATCH 1610/2553] configure: detect SunOS and link against required libs --- configure.ac | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure.ac b/configure.ac index 55c02f7c21a9..2437f58671da 100644 --- a/configure.ac +++ b/configure.ac @@ -227,6 +227,10 @@ LUA_LIB_NAME="lua" WINDOWS_PATH="yes" ;; + *-*-solaris*) + AC_MSG_WARN([support for Solaris/Illumos/SunOS is experimental]) + LDFLAGS="${LDFLAGS} -lsocket -lnsl" + ;; *) AC_MSG_WARN([unsupported OS this may or may not work]) ;; From a2c9b86cdfaa8b2fdf54bf828a0f959e120ba326 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Sep 2016 10:17:16 +0200 Subject: [PATCH 1611/2553] byteswap: fix compilation on SunOS --- src/util-byte.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-byte.h b/src/util-byte.h index 82c16a4d1c50..aca846ac2bfe 100644 --- a/src/util-byte.h +++ b/src/util-byte.h @@ -45,7 +45,7 @@ #define SCByteSwap16(x) OSSwapInt16(x) #define SCByteSwap32(x) OSSwapInt32(x) #define SCByteSwap64(x) OSSwapInt64(x) -#elif defined(__WIN32) || defined(_WIN32) +#elif defined(__WIN32) || defined(_WIN32) || defined(sun) /* Quick & dirty solution, nothing seems to exist for this in Win32 API */ #define SCByteSwap16(x) \ ((((x) & 0xff00) >> 8) \ From 120f59386b526a883a08c3ff5fe16bb7b7453092 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 5 Sep 2016 10:17:40 +0200 Subject: [PATCH 1612/2553] affinity: fix compilation on SunOS --- src/tm-threads.c | 6 +++--- src/util-affinity.c | 6 +++--- src/util-affinity.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index 8442a1e84559..08fb6429ee7c 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -929,7 +929,7 @@ TmSlot *TmSlotGetSlotForTM(int tm_id) return NULL; } -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun static int SetCPUAffinitySet(cpu_set_t *cs) { #if defined OS_FREEBSD @@ -963,7 +963,7 @@ static int SetCPUAffinitySet(cpu_set_t *cs) */ static int SetCPUAffinity(uint16_t cpuid) { -#if defined __OpenBSD__ +#if defined __OpenBSD__ || defined sun return 0; #else int cpu = (int)cpuid; @@ -1097,7 +1097,7 @@ TmEcode TmThreadSetupOptions(ThreadVars *tv) SetCPUAffinity(tv->cpu_affinity); } -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun if (tv->thread_setup_flags & THREAD_SET_PRIORITY) TmThreadSetPrio(tv); if (tv->thread_setup_flags & THREAD_SET_AFFTYPE) { diff --git a/src/util-affinity.c b/src/util-affinity.c index 51925a9f3b48..37539aef66b5 100644 --- a/src/util-affinity.c +++ b/src/util-affinity.c @@ -76,7 +76,7 @@ ThreadsAffinityType * GetAffinityTypeFromName(const char *name) return NULL; } -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun static void AffinitySetupInit() { int i, j; @@ -166,7 +166,7 @@ static void BuildCpuset(const char *name, ConfNode *node, cpu_set_t *cpu) void AffinitySetupLoadFromConfig() { -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun ConfNode *root = ConfGetNode("threading.cpu-affinity"); ConfNode *affinity; @@ -285,7 +285,7 @@ void AffinitySetupLoadFromConfig() int AffinityGetNextCPU(ThreadsAffinityType *taf) { int ncpu = 0; -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun int iter = 0; SCMutexLock(&taf->taf_mutex); ncpu = taf->lcpu; diff --git a/src/util-affinity.h b/src/util-affinity.h index db12276c943d..bd9e1626ea0b 100644 --- a/src/util-affinity.h +++ b/src/util-affinity.h @@ -68,7 +68,7 @@ typedef struct ThreadsAffinityType_ { SCMutex taf_mutex; uint16_t lcpu; /* use by exclusive mode */ -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun cpu_set_t cpu_set; cpu_set_t lowprio_cpu; cpu_set_t medprio_cpu; From af4085b77b56cbb41496956e5b23184b4528a094 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 5 Sep 2016 07:41:33 -0600 Subject: [PATCH 1613/2553] icmpv6: fix checksum verification if fcs present Calculate the length of the ICMPv6 packet from decoded information instead of off the wire length. This will provide the correct length if trailing data like an FCS is present. Fixes issue: https://redmine.openinfosecfoundation.org/issues/1849 --- src/decode-icmpv6.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ src/detect-csum.c | 7 ++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index 26a48b7439af..75da935bfac8 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -1603,6 +1603,61 @@ static int ICMPV6RedirectTestUnknownCode(void) return retval; } +/** + * \test Test for valid ICMPv6 checksum when the FCS is still attached. + * + * Tests that the packet is decoded with sufficient info to verify the + * checksum even if the packet has some trailing data like an ethernet + * FCS. + */ +static int ICMPV6CalculateValidChecksumWithFCS(void) +{ + /* IPV6/ICMPv6 packet with ethernet header. + * - IPv6 payload length: 36 + */ + uint8_t raw_ipv6[] = { + 0x33, 0x33, 0x00, 0x00, 0x00, 0x16, 0x00, 0x50, + 0x56, 0xa6, 0x6a, 0x7d, 0x86, 0xdd, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0xfe, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x09, + 0xad, 0x44, 0x49, 0x38, 0x5f, 0xa9, 0xff, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x3a, 0x00, + 0x05, 0x02, 0x00, 0x00, 0x01, 0x00, 0x8f, 0x00, + 0x24, 0xe0, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, /* Checksum: 0x24e0. */ + 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfb, 0x1f, 0x34, 0xf6, 0xa4 + }; + uint16_t csum = *(((uint16_t *)(raw_ipv6 + 64))); + + Packet *p = SCMalloc(SIZE_OF_PACKET); + FAIL_IF_NULL(p); + IPV6Hdr ip6h; + ThreadVars tv; + DecodeThreadVars dtv; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(p, 0, SIZE_OF_PACKET); + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&ip6h, 0, sizeof(IPV6Hdr)); + + FlowInitConfig(FLOW_QUIET); + DecodeIPV6(&tv, &dtv, p, raw_ipv6 + 14, sizeof(raw_ipv6) - 14, NULL); + FAIL_IF_NULL(p->icmpv6h); + + uint16_t icmpv6_len = IPV6_GET_RAW_PLEN(p->ip6h) - + ((uint8_t *)p->icmpv6h - (uint8_t *)p->ip6h - IPV6_HEADER_LEN); + FAIL_IF(icmpv6_len != 28); + FAIL_IF(ICMPV6CalculateChecksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->icmpv6h, icmpv6_len) != csum); + + PACKET_RECYCLE(p); + FlowShutdown(); + SCFree(p); + PASS; +} + #endif /* UNITTESTS */ /** * \brief Registers ICMPV6 unit tests @@ -1654,6 +1709,8 @@ void DecodeICMPV6RegisterTests(void) UtRegisterTest("ICMPV6RedirectTestKnownCode", ICMPV6RedirectTestKnownCode); UtRegisterTest("ICMPV6RedirectTestUnknownCode", ICMPV6RedirectTestUnknownCode); + UtRegisterTest("ICMPV6CalculateValidChecksumWithFCS", + ICMPV6CalculateValidChecksumWithFCS); #endif /* UNITTESTS */ } /** diff --git a/src/detect-csum.c b/src/detect-csum.c index 37d2b22163cc..4a338f5409b7 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -814,10 +814,13 @@ int DetectICMPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, return cd->valid; } - if (p->level4_comp_csum == -1) + if (p->level4_comp_csum == -1) { + uint16_t len = IPV6_GET_RAW_PLEN(p->ip6h) - + ((uint8_t *)p->icmpv6h - (uint8_t *)p->ip6h - IPV6_HEADER_LEN); p->level4_comp_csum = ICMPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->icmpv6h, - GET_PKT_LEN(p) - ((uint8_t *)p->icmpv6h - GET_PKT_DATA(p))); + len); + } if (p->level4_comp_csum == p->icmpv6h->csum && cd->valid == 1) return 1; From 2a42e8be0362d5aaab8f42e382ef678a54e74a33 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 5 Sep 2016 08:15:26 -0600 Subject: [PATCH 1614/2553] unittest: FAIL macro to unconditionally fail a test --- src/util-unittest.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/util-unittest.h b/src/util-unittest.h index cca59b869b56..7a0e110be9cb 100644 --- a/src/util-unittest.h +++ b/src/util-unittest.h @@ -54,6 +54,17 @@ void UtRunModeRegister(void); extern int unittests_fatal; +/** + * \breif Fail a test. + */ +#define FAIL do { \ + if (unittests_fatal) { \ + BUG_ON(1); \ + } else { \ + return 0; \ + } \ + } while (0) + /** * \brief Fail a test if expression evaluates to false. */ From 3cf8b4629f2cf523c3f82604d93b8fd4a0888109 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 5 Sep 2016 08:15:46 -0600 Subject: [PATCH 1615/2553] decode-icmpv6: use FAIL macros in tests --- src/decode-icmpv6.c | 442 ++++++++++---------------------------------- 1 file changed, 100 insertions(+), 342 deletions(-) diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index 75da935bfac8..fc82d5949353 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -393,8 +393,9 @@ static int ICMPV6CalculateValidChecksumtest01(void) csum = *( ((uint16_t *)(raw_ipv6 + 56))); - return (csum == ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + FAIL_IF(csum != ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 68)); + PASS; } static int ICMPV6CalculateInvalidChecksumtest02(void) @@ -421,18 +422,17 @@ static int ICMPV6CalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)(raw_ipv6 + 56))); - return (csum != ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + FAIL_IF(csum == ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 68)); + PASS; } - /** \test icmpv6 message type: parameter problem, valid packet * * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6ParamProbTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -448,8 +448,7 @@ static int ICMPV6ParamProbTest01(void) 0x80, 0x00, 0x08, 0xb5, 0x99, 0xc3, 0xde, 0x40 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -466,37 +465,23 @@ static int ICMPV6ParamProbTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6h == NULL); - if (ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0 || - ICMPV6_GET_EMB_PROTO(p) != IPPROTO_ICMPV6) { - SCLogDebug("ICMPv6 not processed at all"); - retval = 0; - goto end; - } + /* ICMPv6 not processed at all? */ + FAIL_IF(ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0 || + ICMPV6_GET_EMB_PROTO(p) != IPPROTO_ICMPV6); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { - if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { - SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " - "the src and dest ip addresses correctly"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: packet too big, valid packet @@ -505,7 +490,6 @@ static int ICMPV6ParamProbTest01(void) */ static int ICMPV6PktTooBigTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -520,8 +504,7 @@ static int ICMPV6PktTooBigTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -538,39 +521,26 @@ static int ICMPV6PktTooBigTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6h == NULL); - /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ - if (ICMPV6_GET_TYPE(p) != 2 || ICMPV6_GET_CODE(p) != 0 ) { - SCLogDebug("ICMPv6 Not processed at all"); - retval = 0; - goto end; - } + /* Note: it has an embedded ipv6 packet but no protocol after ipv6 + * (IPPROTO_NONE) */ + /* Check if ICMPv6 header was processed at all. */ + FAIL_IF(ICMPV6_GET_TYPE(p) != 2 || ICMPV6_GET_CODE(p) != 0 ); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { - if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { - SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " - "the src and dest ip addresses correctly"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } SCLogDebug("ICMPV6 IPV6 src and dst properly set"); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: time exceed, valid packet @@ -579,7 +549,6 @@ static int ICMPV6PktTooBigTest01(void) */ static int ICMPV6TimeExceedTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -594,8 +563,7 @@ static int ICMPV6TimeExceedTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -604,7 +572,6 @@ static int ICMPV6TimeExceedTest01(void) ipv6src = (uint32_t*) &raw_ipv6[8]; ipv6dst = (uint32_t*) &raw_ipv6[24]; - memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); memset(&dtv, 0, sizeof(DecodeThreadVars)); @@ -613,40 +580,26 @@ static int ICMPV6TimeExceedTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } + FAIL_IF_NULL(p->icmpv6h); /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ - if (ICMPV6_GET_TYPE(p) != 3 || ICMPV6_GET_CODE(p) != 0 || - ICMPV6_GET_EMB_IPV6(p)==NULL || ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE ) { - SCLogDebug("ICMPv6 Not processed at all"); - retval = 0; - goto end; - } + FAIL_IF(ICMPV6_GET_TYPE(p) != 3 || ICMPV6_GET_CODE(p) != 0 || + ICMPV6_GET_EMB_IPV6(p) == NULL || + ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { - if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { - SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " - "the src and dest ip addresses correctly"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } SCLogDebug("ICMPV6 IPV6 src and dst properly set"); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: destination unreach, valid packet @@ -655,7 +608,6 @@ static int ICMPV6TimeExceedTest01(void) */ static int ICMPV6DestUnreachTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -670,8 +622,7 @@ static int ICMPV6DestUnreachTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -680,7 +631,6 @@ static int ICMPV6DestUnreachTest01(void) ipv6src = (uint32_t*) &raw_ipv6[8]; ipv6dst = (uint32_t*) &raw_ipv6[24]; - memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); memset(&dtv, 0, sizeof(DecodeThreadVars)); @@ -689,38 +639,24 @@ static int ICMPV6DestUnreachTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } + FAIL_IF_NULL(p->icmpv6h); /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ - if (ICMPV6_GET_TYPE(p) != 1 || ICMPV6_GET_CODE(p) != 0 || - ICMPV6_GET_EMB_IPV6(p) == NULL || ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE ) { - SCLogDebug("ICMPv6 Not processed at all"); - retval = 0; - goto end; - } + FAIL_IF(ICMPV6_GET_TYPE(p) != 1 || ICMPV6_GET_CODE(p) != 0 || + ICMPV6_GET_EMB_IPV6(p) == NULL || + ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { - if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { - SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " - "the src and dest ip addresses correctly"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 message type: echo request, valid packet @@ -728,7 +664,6 @@ static int ICMPV6DestUnreachTest01(void) */ static int ICMPV6EchoReqTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -738,8 +673,7 @@ static int ICMPV6EchoReqTest01(void) 0x80, 0x00, 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -752,10 +686,7 @@ static int ICMPV6EchoReqTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - goto end; - } + FAIL_IF_NULL(p->icmpv6h); SCLogDebug("ID: %u seq: %u", ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); @@ -764,15 +695,13 @@ static int ICMPV6EchoReqTest01(void) printf("ICMPv6 Echo reply decode failed TYPE %u CODE %u ID %04x(%u) SEQ %04x(%u): ", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ntohs(ICMPV6_GET_ID(p)), ICMPV6_GET_SEQ(p), ntohs(ICMPV6_GET_SEQ(p))); - goto end; + FAIL; } - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 message type: echo reply, valid packet @@ -780,7 +709,6 @@ static int ICMPV6EchoReqTest01(void) */ static int ICMPV6EchoRepTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -791,8 +719,7 @@ static int ICMPV6EchoRepTest01(void) 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -805,10 +732,7 @@ static int ICMPV6EchoRepTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - goto end; - } + FAIL_IF_NULL(p->icmpv6h); SCLogDebug("type: %u code %u ID: %u seq: %u", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p),ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); @@ -818,15 +742,13 @@ static int ICMPV6EchoRepTest01(void) printf("ICMPv6 Echo reply decode failed TYPE %u CODE %u ID %04x(%u) SEQ %04x(%u): ", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ntohs(ICMPV6_GET_ID(p)), ICMPV6_GET_SEQ(p), ntohs(ICMPV6_GET_SEQ(p))); - goto end; + FAIL; } - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: parameter problem, invalid packet @@ -835,7 +757,6 @@ static int ICMPV6EchoRepTest01(void) */ static int ICMPV6ParamProbTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -851,8 +772,7 @@ static int ICMPV6ParamProbTest02(void) 0x80, 0x00, 0x08, 0xb5, 0x99, 0xc3, 0xde, 0x40 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -865,30 +785,14 @@ static int ICMPV6ParamProbTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } - - if (ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0) { - SCLogDebug("ICMPv6 Not processed at all"); - retval = 0; - goto end; - } - - if (!ENGINE_ISSET_EVENT(p, ICMPV6_IPV6_UNKNOWN_VER)) { - SCLogDebug("ICMPv6 Error: Unknown embedded ipv6 version event not set"); - retval = 0; - goto end; - } + FAIL_IF_NULL(p->icmpv6h); + FAIL_IF(ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0); + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_IPV6_UNKNOWN_VER)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: packet too big, invalid packet @@ -897,7 +801,6 @@ static int ICMPV6ParamProbTest02(void) */ static int ICMPV6PktTooBigTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -912,8 +815,7 @@ static int ICMPV6PktTooBigTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -926,24 +828,13 @@ static int ICMPV6PktTooBigTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } - - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event not set"); - retval = 0; - goto end; - } + FAIL_IF_NULL(p->icmpv6h); + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: time exceed, invalid packet @@ -952,7 +843,6 @@ static int ICMPV6PktTooBigTest02(void) */ static int ICMPV6TimeExceedTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -964,8 +854,7 @@ static int ICMPV6TimeExceedTest02(void) /* The icmpv6 header is broken in the checksum (so we dont have a complete header) */ Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -978,18 +867,12 @@ static int ICMPV6TimeExceedTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_PKT_TOO_SMALL)) { - SCLogDebug("ICMPv6 Error: event packet too small not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_PKT_TOO_SMALL)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 message type: destination unreach, invalid packet @@ -998,7 +881,6 @@ static int ICMPV6TimeExceedTest02(void) */ static int ICMPV6DestUnreachTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1013,8 +895,7 @@ static int ICMPV6DestUnreachTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1027,18 +908,12 @@ static int ICMPV6DestUnreachTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_IPV6_TRUNC_PKT)) { - SCLogDebug("ICMPv6 Error: embedded ipv6 truncated packet event not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_IPV6_TRUNC_PKT)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 message type: echo request, invalid packet @@ -1047,7 +922,6 @@ static int ICMPV6DestUnreachTest02(void) */ static int ICMPV6EchoReqTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1058,8 +932,7 @@ static int ICMPV6EchoReqTest02(void) 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1072,18 +945,12 @@ static int ICMPV6EchoReqTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 message type: echo reply, invalid packet @@ -1092,7 +959,6 @@ static int ICMPV6EchoReqTest02(void) */ static int ICMPV6EchoRepTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1103,8 +969,7 @@ static int ICMPV6EchoRepTest02(void) 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1117,18 +982,12 @@ static int ICMPV6EchoRepTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 packet decoding and setting up of payload_len and payload buufer @@ -1136,7 +995,6 @@ static int ICMPV6EchoRepTest02(void) */ static int ICMPV6PayloadTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1151,8 +1009,7 @@ static int ICMPV6PayloadTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1165,28 +1022,17 @@ static int ICMPV6PayloadTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->payload == NULL) { - printf("payload == NULL, expected non-NULL: "); - goto end; - } + FAIL_IF_NULL(p->payload); + FAIL_IF(p->payload_len != 37); - if (p->payload_len != 37) { - printf("payload_len %"PRIu16", expected 37: ", p->payload_len); - goto end; - } - - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RouterSolicitTestKnownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1197,8 +1043,7 @@ static int ICMPV6RouterSolicitTestKnownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1211,24 +1056,16 @@ static int ICMPV6RouterSolicitTestKnownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is set"); - retval = 0; - goto end; - } + FAIL_IF(ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RouterSolicitTestUnknownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1239,8 +1076,7 @@ static int ICMPV6RouterSolicitTestUnknownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1253,24 +1089,16 @@ static int ICMPV6RouterSolicitTestUnknownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RouterAdvertTestKnownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1281,8 +1109,7 @@ static int ICMPV6RouterAdvertTestKnownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1295,24 +1122,16 @@ static int ICMPV6RouterAdvertTestKnownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is set"); - retval = 0; - goto end; - } + FAIL_IF(ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RouterAdvertTestUnknownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1323,8 +1142,7 @@ static int ICMPV6RouterAdvertTestUnknownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1337,24 +1155,16 @@ static int ICMPV6RouterAdvertTestUnknownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6NeighbourSolicitTestKnownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1365,8 +1175,7 @@ static int ICMPV6NeighbourSolicitTestKnownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1379,24 +1188,16 @@ static int ICMPV6NeighbourSolicitTestKnownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is set"); - retval = 0; - goto end; - } + FAIL_IF(ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6NeighbourSolicitTestUnknownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1407,8 +1208,7 @@ static int ICMPV6NeighbourSolicitTestUnknownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1421,24 +1221,16 @@ static int ICMPV6NeighbourSolicitTestUnknownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6NeighbourAdvertTestKnownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1449,8 +1241,7 @@ static int ICMPV6NeighbourAdvertTestKnownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1463,24 +1254,16 @@ static int ICMPV6NeighbourAdvertTestKnownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is set"); - retval = 0; - goto end; - } + FAIL_IF(ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6NeighbourAdvertTestUnknownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1491,8 +1274,7 @@ static int ICMPV6NeighbourAdvertTestUnknownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1505,24 +1287,16 @@ static int ICMPV6NeighbourAdvertTestUnknownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RedirectTestKnownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1533,8 +1307,7 @@ static int ICMPV6RedirectTestKnownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1547,24 +1320,16 @@ static int ICMPV6RedirectTestKnownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is set"); - retval = 0; - goto end; - } + FAIL_IF(ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RedirectTestUnknownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1575,8 +1340,7 @@ static int ICMPV6RedirectTestUnknownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1589,18 +1353,12 @@ static int ICMPV6RedirectTestUnknownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** From e878dd2231f4d29f7e3792dc496eed0cf9209051 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 31 Aug 2016 08:24:08 -0600 Subject: [PATCH 1616/2553] app-layer templates: cleanups - cleanup file headers - add todo section - convert unit tests to new macros - add markers to remove disabled by default behaviour --- src/app-layer-template.c | 13 ++++++++-- src/app-layer-template.h | 6 +++++ src/detect-engine-template.c | 15 ++++++++++++ src/detect-engine-template.h | 6 +++++ src/detect-template-buffer.c | 47 ++++++++++++++++-------------------- src/detect-template-buffer.h | 6 +++++ src/output-json-template.c | 17 ++++++++++++- src/output-json-template.h | 6 +++++ 8 files changed, 87 insertions(+), 29 deletions(-) diff --git a/src/app-layer-template.c b/src/app-layer-template.c index 1a2cce0ec186..a454b119bf89 100644 --- a/src/app-layer-template.c +++ b/src/app-layer-template.c @@ -15,8 +15,18 @@ * 02110-1301, USA. */ +/* + * TODO: Update \author in this file and app-layer-template.h. + * TODO: Implement your app-layer logic with unit tests. + * TODO: Remove SCLogNotice statements or convert to debug. + */ + /** - * \file Template application layer detector and parser for learning and + * \file + * + * \author FirstName LastName + * + * Template application layer detector and parser for learning and * template pruposes. * * This template implements a simple application layer for something @@ -449,7 +459,6 @@ void RegisterTemplateParsers(void) return; } /* TEMPLATE_END_REMOVE */ - /* Check if Template TCP detection is enabled. If it does not exist in * the configuration file then it will be enabled by default. */ if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { diff --git a/src/app-layer-template.h b/src/app-layer-template.h index 191e0933b541..2dd944a01a8c 100644 --- a/src/app-layer-template.h +++ b/src/app-layer-template.h @@ -15,6 +15,12 @@ * 02110-1301, USA. */ +/** + * \file + * + * \author FirstName LastName + */ + #ifndef __APP_LAYER_TEMPLATE_H__ #define __APP_LAYER_TEMPLATE_H__ diff --git a/src/detect-engine-template.c b/src/detect-engine-template.c index 49c29c6a6ae0..1d70d11fedd5 100644 --- a/src/detect-engine-template.c +++ b/src/detect-engine-template.c @@ -15,6 +15,21 @@ * 02110-1301, USA. */ +/* + * TODO: Update your name below and in detect-engine-template.h. + * TODO: Update description in the \file section below. + * TODO: Remove SCLogNotice statements or convert to debug. + */ + +/** + * \file + * + * \author FirstName LastName + * + * Implement buffer inspection on the decoded application layer + * content buffers. + */ + #include "suricata-common.h" #include "stream.h" #include "detect-engine-content-inspection.h" diff --git a/src/detect-engine-template.h b/src/detect-engine-template.h index 61eb8d01035b..98a17bf63d3f 100644 --- a/src/detect-engine-template.h +++ b/src/detect-engine-template.h @@ -15,6 +15,12 @@ * 02110-1301, USA. */ +/** + * \file + * + * \author FirstName LastName + */ + #ifndef __DETECT_TEMPLATE_ENGINE_H__ #define __DETECT_TEMPLATE_ENGINE_H__ diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index 50521f937f94..01f676a41011 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -15,9 +15,19 @@ * 02110-1301, USA. */ +/* + * TODO: Update the \author in this file and detect-template-buffer.h. + * TODO: Update description in the \file section below. + * TODO: Remove SCLogNotice statements or convert to debug. + */ + /** - * \file Set up of the "template_buffer" keyword to allow content inspections - * on the decoded template application layer buffers. + * \file + * + * \author FirstName LastName + * + * Set up of the "template_buffer" keyword to allow content + * inspections on the decoded template application layer buffers. */ #include "suricata-common.h" @@ -30,10 +40,11 @@ static void DetectTemplateBufferRegisterTests(void); void DetectTemplateBufferRegister(void) { + /* TEMPLATE_START_REMOVE */ if (ConfGetNode("app-layer.protocols.template") == NULL) { return; } - + /* TEMPLATE_END_REMOVE */ sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].name = "template_buffer"; sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].desc = "Template content modififier to match on the template buffers"; @@ -77,8 +88,6 @@ static int DetectTemplateBufferTest(void) ThreadVars tv; Signature *s; - int result = 0; - uint8_t request[] = "Hello World!"; /* Setup flow. */ @@ -97,9 +106,7 @@ static int DetectTemplateBufferTest(void) StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); /* This rule should match. */ s = DetectEngineAppendSig(de_ctx, @@ -107,9 +114,7 @@ static int DetectTemplateBufferTest(void) "msg:\"TEMPLATE Test Rule\"; " "template_buffer; content:\"World!\"; " "sid:1; rev:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); /* This rule should not match. */ s = DetectEngineAppendSig(de_ctx, @@ -117,9 +122,7 @@ static int DetectTemplateBufferTest(void) "msg:\"TEMPLATE Test Rule\"; " "template_buffer; content:\"W0rld!\"; " "sid:2; rev:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); @@ -130,20 +133,12 @@ static int DetectTemplateBufferTest(void) SCMutexUnlock(&f.m); /* Check that we have app-layer state. */ - if (f.alstate == NULL) { - goto end; - } + FAIL_IF_NULL(f.alstate); SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - goto end; - } - if (PacketAlertCheck(p, 2)) { - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); - result = 1; -end: /* Cleanup. */ if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -157,7 +152,7 @@ static int DetectTemplateBufferTest(void) FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + PASS; } #endif diff --git a/src/detect-template-buffer.h b/src/detect-template-buffer.h index 8a2ab8bad176..4385e443082c 100644 --- a/src/detect-template-buffer.h +++ b/src/detect-template-buffer.h @@ -15,6 +15,12 @@ * 02110-1301, USA. */ +/** + * \file + * + * \author FirstName LastName + */ + #ifndef __DETECT_TEMPLATE_BUFFER_H__ #define __DETECT_TEMPLATE_BUFFER_H__ diff --git a/src/output-json-template.c b/src/output-json-template.c index eba2cebd68e4..d096d730041b 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -15,6 +15,20 @@ * 02110-1301, USA. */ +/* + * TODO: Update \author in this file and in output-json-template.h. + * TODO: Remove SCLogNotice statements, or convert to debug. + * TODO: Implement your app-layers logging. + */ + +/** + * \file + * + * \author FirstName LastName + * + * Implement JSON/eve logging app-layer Template. + */ + #include "suricata-common.h" #include "debug.h" #include "detect.h" @@ -178,10 +192,11 @@ static TmEcode JsonTemplateLogThreadDeinit(ThreadVars *t, void *data) void TmModuleJsonTemplateLogRegister(void) { + /* TEMPLATE_START_REMOVE */ if (ConfGetNode("app-layer.protocols.template") == NULL) { return; } - + /* TEMPLATE_END_REMOVE */ tmm_modules[TMM_JSONTEMPLATELOG].name = "JsonTemplateLog"; tmm_modules[TMM_JSONTEMPLATELOG].ThreadInit = JsonTemplateLogThreadInit; tmm_modules[TMM_JSONTEMPLATELOG].ThreadDeinit = JsonTemplateLogThreadDeinit; diff --git a/src/output-json-template.h b/src/output-json-template.h index d071e1828b59..4f1ac6b7afdd 100644 --- a/src/output-json-template.h +++ b/src/output-json-template.h @@ -15,6 +15,12 @@ * 02110-1301, USA. */ +/** + * \file + * + * \author FirstName LastName + */ + #ifndef __OUTPUT_JSON_TEMPLATE_H__ #define __OUTPUT_JSON_TEMPLATE_H__ From b4565004c7f7585e69e29d5e11b5d28bb66125fa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 2 Sep 2016 12:47:11 +0200 Subject: [PATCH 1617/2553] detect-template: modernize --- src/detect-template.c | 43 ++++++++++++++----------------------------- src/detect-template.h | 2 +- 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/src/detect-template.c b/src/detect-template.c index b415783a60f9..b3ffb08e7941 100644 --- a/src/detect-template.c +++ b/src/detect-template.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Open Information Security Foundation +/* Copyright (C) 2015-2016 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 @@ -229,40 +229,25 @@ static void DetectTemplateFree(void *ptr) { * \test description of the test */ -static int DetectTemplateParseTest01 (void) { - DetectTemplateData *templated = NULL; - uint8_t res = 0; - - templated = DetectTemplateParse("1,10"); - if (templated != NULL) { - if (templated->arg1 == 1 && templated->arg2 == 10) - res = 1; - - DetectTemplateFree(templated); - } - - return res; +static int DetectTemplateParseTest01 (void) +{ + DetectTemplateData *templated = DetectTemplateParse("1,10"); + FAIL_IF_NULL(templated); + FAIL_IF(!(templated->arg1 == 1 && templated->arg2 == 10)); + DetectTemplateFree(templated); + PASS; } -static int DetectTemplateSignatureTest01 (void) { - uint8_t res = 0; - +static int DetectTemplateSignatureTest01 (void) +{ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); Signature *sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (template:1,10; sid:1; rev:1;)"); - if (sig == NULL) { - printf("parsing signature failed: "); - goto end; - } + FAIL_IF_NULL(sig); - /* if we get here, all conditions pass */ - res = 1; -end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return res; + DetectEngineCtxFree(de_ctx); + PASS; } #endif /* UNITTESTS */ diff --git a/src/detect-template.h b/src/detect-template.h index d86c0083bb6e..6b2b4435ef80 100644 --- a/src/detect-template.h +++ b/src/detect-template.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Open Information Security Foundation +/* Copyright (C) 2015-2016 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 From bbcc22d2ad8e99e377a4d713de251d08a4cf15b2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 6 Sep 2016 10:20:38 +0200 Subject: [PATCH 1618/2553] dns: fix coverity warning ** CID 1372324: Null pointer dereferences (FORWARD_NULL) /src/output-json-dns.c: 532 in OutputAnswer() ________________________________________________________________________________________________________ *** CID 1372324: Null pointer dereferences (FORWARD_NULL) /src/output-json-dns.c: 532 in OutputAnswer() 526 } 527 } 528 529 /* reset */ 530 MemBufferReset(aft->buffer); 531 json_object_set_new(djs, "dns", js); >>> CID 1372324: Null pointer dereferences (FORWARD_NULL) >>> Dereferencing null pointer "entry". 532 if (likely(DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags))) { 533 OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); 534 } 535 json_object_del(djs, "dns"); 536 537 return; Move checks to the top of the functions. Should be more efficient too. --- src/output-json-dns.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 5b35949318bc..42fa975b3549 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -391,6 +391,11 @@ static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, { SCLogDebug("got a DNS request and now logging !!"); + if (entry != NULL && + !DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { + return; + } + json_t *djs = json_object(); if (djs == NULL) { return; @@ -423,14 +428,17 @@ static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, /* dns */ json_object_set_new(js, "dns", djs); - if (likely(DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags))) { - OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, &aft->buffer); - } + OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, &aft->buffer); json_object_del(js, "dns"); } static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, DNSAnswerEntry *entry) { + if (entry != NULL && + !DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { + return; + } + json_t *js = json_object(); if (js == NULL) return; @@ -529,9 +537,7 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, /* reset */ MemBufferReset(aft->buffer); json_object_set_new(djs, "dns", js); - if (likely(DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags))) { - OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); - } + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); json_object_del(djs, "dns"); return; @@ -539,6 +545,11 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, static void OutputFailure(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, DNSQueryEntry *entry) { + if (entry != NULL && + !DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { + return; + } + json_t *js = json_object(); if (js == NULL) return; @@ -565,9 +576,7 @@ static void OutputFailure(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, /* reset */ MemBufferReset(aft->buffer); json_object_set_new(djs, "dns", js); - if (likely(DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags))) { - OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); - } + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); json_object_del(djs, "dns"); return; From 1cc5f9825de1b866b3e153ac1cf8028308e8cdb0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 6 Sep 2016 10:29:57 +0200 Subject: [PATCH 1619/2553] dns: use nonnull attr for log functions --- src/output-json-dns.c | 161 ++++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 78 deletions(-) diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 42fa975b3549..daa545ee0114 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -386,13 +386,15 @@ static int DNSRRTypeEnabled(uint16_t type, uint64_t flags) } } +static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, + uint64_t tx_id, DNSQueryEntry *entry) __attribute__((nonnull)); + static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uint64_t tx_id, DNSQueryEntry *entry) { SCLogDebug("got a DNS request and now logging !!"); - if (entry != NULL && - !DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { + if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { return; } @@ -432,10 +434,13 @@ static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, json_object_del(js, "dns"); } -static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, DNSAnswerEntry *entry) +static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, + DNSTransaction *tx, DNSAnswerEntry *entry) __attribute__((nonnull)); + +static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, + DNSTransaction *tx, DNSAnswerEntry *entry) { - if (entry != NULL && - !DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { + if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { return; } @@ -454,82 +459,79 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode)); json_object_set_new(js, "rcode", json_string(rcode)); - /* we are logging an answer RR */ - if (entry != NULL) { - /* query */ - if (entry->fqdn_len > 0) { - char *c; - c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)), - entry->fqdn_len); - if (c != NULL) { - json_object_set_new(js, "rrname", json_string(c)); - SCFree(c); - } + /* query */ + if (entry->fqdn_len > 0) { + char *c; + c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)), + entry->fqdn_len); + if (c != NULL) { + json_object_set_new(js, "rrname", json_string(c)); + SCFree(c); } + } - /* name */ - char record[16] = ""; - DNSCreateTypeString(entry->type, record, sizeof(record)); - json_object_set_new(js, "rrtype", json_string(record)); - - /* ttl */ - json_object_set_new(js, "ttl", json_integer(entry->ttl)); - - uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len); - if (entry->type == DNS_RECORD_TYPE_A) { - char a[16] = ""; - PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); - json_object_set_new(js, "rdata", json_string(a)); - } else if (entry->type == DNS_RECORD_TYPE_AAAA) { - char a[46] = ""; - PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); - json_object_set_new(js, "rdata", json_string(a)); - } else if (entry->data_len == 0) { + /* name */ + char record[16] = ""; + DNSCreateTypeString(entry->type, record, sizeof(record)); + json_object_set_new(js, "rrtype", json_string(record)); + + /* ttl */ + json_object_set_new(js, "ttl", json_integer(entry->ttl)); + + uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len); + if (entry->type == DNS_RECORD_TYPE_A) { + char a[16] = ""; + PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); + json_object_set_new(js, "rdata", json_string(a)); + } else if (entry->type == DNS_RECORD_TYPE_AAAA) { + char a[46] = ""; + PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); + json_object_set_new(js, "rdata", json_string(a)); + } else if (entry->data_len == 0) { + json_object_set_new(js, "rdata", json_string("")); + } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME || + entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR || + entry->type == DNS_RECORD_TYPE_NS) { + if (entry->data_len != 0) { + char buffer[256] = ""; + uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ? + entry->data_len : sizeof(buffer) - 1; + memcpy(buffer, ptr, copy_len); + buffer[copy_len] = '\0'; + json_object_set_new(js, "rdata", json_string(buffer)); + } else { json_object_set_new(js, "rdata", json_string("")); - } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME || - entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR || - entry->type == DNS_RECORD_TYPE_NS) { - if (entry->data_len != 0) { - char buffer[256] = ""; - uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ? - entry->data_len : sizeof(buffer) - 1; - memcpy(buffer, ptr, copy_len); - buffer[copy_len] = '\0'; - json_object_set_new(js, "rdata", json_string(buffer)); - } else { - json_object_set_new(js, "rdata", json_string("")); + } + } else if (entry->type == DNS_RECORD_TYPE_SSHFP) { + if (entry->data_len > 2) { + /* get algo and type */ + uint8_t algo = *ptr; + uint8_t fptype = *(ptr+1); + + /* turn fp raw buffer into a nice :-separate hex string */ + uint16_t fp_len = (entry->data_len - 2); + uint8_t *dptr = ptr+2; + + /* c-string for ':' separated hex and trailing \0. */ + uint32_t output_len = fp_len * 3 + 1; + char hexstring[output_len]; + memset(hexstring, 0x00, output_len); + + uint16_t x; + for (x = 0; x < fp_len; x++) { + char one[4]; + snprintf(one, sizeof(one), x == fp_len - 1 ? "%02x" : "%02x:", dptr[x]); + strlcat(hexstring, one, output_len); } - } else if (entry->type == DNS_RECORD_TYPE_SSHFP) { - if (entry->data_len > 2) { - /* get algo and type */ - uint8_t algo = *ptr; - uint8_t fptype = *(ptr+1); - - /* turn fp raw buffer into a nice :-separate hex string */ - uint16_t fp_len = (entry->data_len - 2); - uint8_t *dptr = ptr+2; - - /* c-string for ':' separated hex and trailing \0. */ - uint32_t output_len = fp_len * 3 + 1; - char hexstring[output_len]; - memset(hexstring, 0x00, output_len); - - uint16_t x; - for (x = 0; x < fp_len; x++) { - char one[4]; - snprintf(one, sizeof(one), x == fp_len - 1 ? "%02x" : "%02x:", dptr[x]); - strlcat(hexstring, one, output_len); - } - /* wrap the whole thing in it's own structure */ - json_t *hjs = json_object(); - if (hjs != NULL) { - json_object_set_new(hjs, "fingerprint", json_string(hexstring)); - json_object_set_new(hjs, "algo", json_integer(algo)); - json_object_set_new(hjs, "type", json_integer(fptype)); + /* wrap the whole thing in it's own structure */ + json_t *hjs = json_object(); + if (hjs != NULL) { + json_object_set_new(hjs, "fingerprint", json_string(hexstring)); + json_object_set_new(hjs, "algo", json_integer(algo)); + json_object_set_new(hjs, "type", json_integer(fptype)); - json_object_set_new(js, "sshfp", hjs); - } + json_object_set_new(js, "sshfp", hjs); } } } @@ -543,10 +545,13 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, return; } -static void OutputFailure(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, DNSQueryEntry *entry) +static void OutputFailure(LogDnsLogThread *aft, json_t *djs, + DNSTransaction *tx, DNSQueryEntry *entry) __attribute__((nonnull)); + +static void OutputFailure(LogDnsLogThread *aft, json_t *djs, + DNSTransaction *tx, DNSQueryEntry *entry) { - if (entry != NULL && - !DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { + if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { return; } From 2997d086bea41349d05fcff176afd15ebd1d09ef Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 6 Sep 2016 11:29:09 +0200 Subject: [PATCH 1620/2553] eve-drop: allow logging all drops - drop: alerts: yes # log alerts that caused drops flows: all # start or all: 'start' logs only a single drop # per flow direction. All logs each dropped pkt. --- src/output-json-drop.c | 30 +++++++++++++++++++++++++++++- suricata.yaml.in | 4 +++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 5c866809b8b4..fd7f513ead0f 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -71,6 +71,9 @@ typedef struct JsonDropLogThread_ { MemBuffer *buffer; } JsonDropLogThread; +/* default to true as this has been the default behavior for a long time */ +static int g_droplog_flows_start = 1; + /** * \brief Log the dropped packets in netfilter format when engine is running * in inline mode @@ -282,6 +285,17 @@ static OutputCtx *JsonDropLogInitCtx(ConfNode *conf) drop_ctx->flags = LOG_DROP_ALERTS; } } + extended = ConfNodeLookupChildValue(conf, "flows"); + if (extended != NULL) { + if (strcasecmp(extended, "start") == 0) { + g_droplog_flows_start = 1; + } else if (strcasecmp(extended, "all") == 0) { + g_droplog_flows_start = 0; + } else { + SCLogWarning(SC_ERR_CONF_YAML_ERROR, "valid options for " + "'flow' are 'start' and 'all'"); + } + } } output_ctx->data = drop_ctx; @@ -316,6 +330,17 @@ static OutputCtx *JsonDropLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) drop_ctx->flags = LOG_DROP_ALERTS; } } + extended = ConfNodeLookupChildValue(conf, "flows"); + if (extended != NULL) { + if (strcasecmp(extended, "start") == 0) { + g_droplog_flows_start = 1; + } else if (strcasecmp(extended, "all") == 0) { + g_droplog_flows_start = 0; + } else { + SCLogWarning(SC_ERR_CONF_YAML_ERROR, "valid options for " + "'flow' are 'start' and 'all'"); + } + } } drop_ctx->file_ctx = ajt->file_ctx; @@ -341,6 +366,9 @@ static int JsonDropLogger(ThreadVars *tv, void *thread_data, const Packet *p) if (r < 0) return -1; + if (!g_droplog_flows_start) + return 0; + if (p->flow) { FLOWLOCK_RDLOCK(p->flow); if (p->flow->flags & FLOW_ACTION_DROP) { @@ -374,7 +402,7 @@ static int JsonDropLogCondition(ThreadVars *tv, const Packet *p) return FALSE; } - if (p->flow != NULL) { + if (g_droplog_flows_start && p->flow != NULL) { int ret = FALSE; /* for a flow that will be dropped fully, log just once per direction */ diff --git a/suricata.yaml.in b/suricata.yaml.in index d2fb45f7583d..351261962770 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -204,7 +204,9 @@ outputs: force-magic: no # force logging magic on all logged files force-md5: no # force logging of md5 checksums #- drop: - # alerts: no # log alerts that caused drops + # alerts: yes # log alerts that caused drops + # flows: all # start or all: 'start' logs only a single drop + # # per flow direction. All logs each dropped pkt. - smtp: #extended: yes # enable this for extended logging information # this includes: bcc, message-id, subject, x_mailer, user-agent From ae116871ad13bd132df9ff69a27a32b7484edae7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 6 Sep 2016 17:52:45 +0200 Subject: [PATCH 1621/2553] Update Changelog for 3.1.2 --- ChangeLog | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ChangeLog b/ChangeLog index 3ce9497e945f..aa5541095ae6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +3.1.2 -- 2016-09-06 + +Feature #1830: support 'tag' in eve log +Feature #1870: make logged flow_id more unique +Feature #1874: support Cisco Fabric Path / DCE +Feature #1885: eve: add option to log all dropped packets +Bug #1849: ICMPv6 incorrect checksum alert if Ethernet FCS is present +Bug #1853: suricata is matching everything on dce_stub_data buffer +Bug #1854: unified2: logging of tagged packets not working +Bug #1856: PCAP mode device not found +Bug #1858: Lots of TCP 'duplicated option/DNS malformed request data' after upgrading from 3.0.1 to 3.1.1 +Bug #1878: dns: crash while logging sshfp records +Bug #1880: icmpv4 error packets can lead to missed detection in tcp/udp +Bug #1884: libhtp 0.5.22 + 3.1.1 -- 2016-07-13 Feature #1775: Lua: SMTP-support From 65fd09a39939c303f0e6e3ae7f9f46857f555232 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Wed, 7 Sep 2016 22:17:01 +0200 Subject: [PATCH 1622/2553] rule-parsing: reject unescaped double quote within content section --- src/detect-content.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/detect-content.c b/src/detect-content.c index 1bbb6f7c18b9..18050bd34e2b 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -186,6 +186,9 @@ int DetectContentDataParse(const char *keyword, const char *contentstr, } escape = 0; converted = 1; + } else if (str[i] == '"') { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid unescaped double quote within content section"); + goto error; } else { str[x] = str[i]; x++; @@ -2309,6 +2312,27 @@ int DetectContentParseTest44(void) return result; } +/** + * \test Parsing test to check for unescaped quote within content section + */ +int DetectContentParseTest45(void) +{ + DetectEngineCtx *de_ctx = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"test\"; content:\"|ff|\" content:\"TEST\"; sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + static int SigTestNegativeTestContent(char *rule, uint8_t *buf) { uint16_t buflen = strlen((char *)buf); @@ -2877,6 +2901,7 @@ void DetectContentRegisterTests(void) UtRegisterTest("DetectContentParseTest42", DetectContentParseTest42); UtRegisterTest("DetectContentParseTest43", DetectContentParseTest43); UtRegisterTest("DetectContentParseTest44", DetectContentParseTest44); + UtRegisterTest("DetectContentParseTest45", DetectContentParseTest45); /* The reals */ UtRegisterTest("DetectContentLongPatternMatchTest01", From 1cdd062dc64768c3fec04a1c14837481813fde3b Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 14 Sep 2016 15:09:47 +0200 Subject: [PATCH 1623/2553] unix-manager: fix output of version command Make it consistent with the output of version command line flag. --- src/unix-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index 919651cce887..bb6eef6756b0 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -662,7 +662,7 @@ TmEcode UnixManagerVersionCommand(json_t *cmd, SCEnter(); json_object_set_new(server_msg, "message", json_string( #ifdef REVISION - PROG_VER xstr(REVISION) + PROG_VER " (rev " xstr(REVISION) ")" #elif defined RELEASE PROG_VER " RELEASE" #else From 24f2387b238e4d82ea0a9a1ec5eb12b8238b022e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 13 Sep 2016 10:57:09 -0600 Subject: [PATCH 1624/2553] flowbits: validate that there are no spaces in the name Fixes issue: https://redmine.openinfosecfoundation.org/issues/1889 To catch the issue where the ';' is missing we have to expand the regex to capture the whole name string, not just the leading valid stuff. Then verify that there are no spaces in the name (Snort has the same restriction) and fail if there is. --- src/detect-flowbits.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 9752f03e8bd5..5100f7f998a9 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -45,7 +45,7 @@ #include "util-unittest.h" #include "util-debug.h" -#define PARSE_REGEX "([a-z]+)(?:,\\s*([^\\s]*))?" +#define PARSE_REGEX "([a-z]+)(?:,\\s*(.*))?" static pcre *parse_regex; static pcre_extra *parse_regex_study; @@ -182,6 +182,20 @@ static int DetectFlowbitParse(char *str, char *cmd, int cmd_len, char *name, SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); return 0; } + + /* Trim trailing whitespace. */ + while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) { + name[strlen(name) - 1] = '\0'; + } + + /* Validate name, spaces are not allowed. */ + for (size_t i = 0; i < strlen(name); i++) { + if (isblank(name[i])) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "spaces not allowed in flowbit names"); + return 0; + } + } } return 1; @@ -324,6 +338,10 @@ static int FlowBitsTestParse01(void) FAIL_IF(strcmp(command, "set") != 0); FAIL_IF(strcmp(name, "flowbit") != 0); + /* Spaces are not allowed in the name. */ + FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command), + name, sizeof(name))); + PASS; } From c4945607e3de78a32c83b8a45cb2c10639d29754 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 13 Sep 2016 17:09:58 -0600 Subject: [PATCH 1625/2553] hostbits: fail parse on unexpected trailing data Address issue https://redmine.openinfosecfoundation.org/issues/1889 for hostbits. This involves updating the regular expresssion to capture any trailing data as the regex already keeps spaces out of the name. A unit test was converted to new macros to find out which line it was failing at after updating regex. --- src/detect-hostbits.c | 131 ++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 87 deletions(-) diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 2c325eb346f7..16394d8d35f6 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -61,7 +61,10 @@ hostbits:set,bitname,both,120; */ -#define PARSE_REGEX "([a-z]+)(?:\\s*,\\s*([^\\s,]+))?(?:\\s*,\\s*([^,\\s]+))?" +#define PARSE_REGEX "([a-z]+)" /* Action */ \ + "(?:\\s*,\\s*([^\\s,]+))?(?:\\s*)?" /* Name. */ \ + "(?:\\s*,\\s*([^,\\s]+))?(?:\\s*)?" /* Direction. */ \ + "(.+)?" /* Any remainding data. */ static pcre *parse_regex; static pcre_extra *parse_regex_study; @@ -453,126 +456,80 @@ static void HostBitsTestShutdown(void) static int HostBitsTestParse01(void) { - int ret = 0; char cmd[16] = "", name[256] = "", dir[16] = ""; /* No direction. */ - if (!DetectHostbitParse("isset,name", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))) { - goto end; - } - if (strcmp(cmd, "isset") != 0) { - goto end; - } - if (strcmp(name, "name") != 0) { - goto end; - } - if (strlen(dir)) { - goto end; - } + FAIL_IF(!DetectHostbitParse("isset,name", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + FAIL_IF(strlen(dir)); /* No direction, leading space. */ *cmd = '\0'; *name = '\0'; *dir = '\0'; - if (!DetectHostbitParse("isset, name", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))) { - goto end; - } - if (strcmp(cmd, "isset") != 0) { - goto end; - } - if (strcmp(name, "name") != 0) { - goto end; - } + FAIL_IF(!DetectHostbitParse("isset, name", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); /* No direction, trailing space. */ *cmd = '\0'; *name = '\0'; *dir = '\0'; - if (!DetectHostbitParse("isset,name ", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))) { - goto end; - } - if (strcmp(cmd, "isset") != 0) { - goto end; - } - if (strcmp(name, "name") != 0) { - goto end; - } + FAIL_IF(!DetectHostbitParse("isset,name ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); /* No direction, leading and trailing space. */ *cmd = '\0'; *name = '\0'; *dir = '\0'; - if (!DetectHostbitParse("isset, name ", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))) { - goto end; - } - if (strcmp(cmd, "isset") != 0) { - goto end; - } - if (strcmp(name, "name") != 0) { - goto end; - } + FAIL_IF(!DetectHostbitParse("isset, name ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); /* With direction. */ *cmd = '\0'; *name = '\0'; *dir = '\0'; - if (!DetectHostbitParse("isset,name,src", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))) { - goto end; - } - if (strcmp(cmd, "isset") != 0) { - goto end; - } - if (strcmp(name, "name") != 0) { - goto end; - } - if (strcmp(dir, "src") != 0) { - goto end; - } + FAIL_IF(!DetectHostbitParse("isset,name,src", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + FAIL_IF(strcmp(dir, "src") != 0); /* With direction - leading and trailing spaces on name. */ *cmd = '\0'; *name = '\0'; *dir = '\0'; - if (!DetectHostbitParse("isset, name ,src", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))) { - goto end; - } - if (strcmp(cmd, "isset") != 0) { - goto end; - } - if (strcmp(name, "name") != 0) { - goto end; - } - if (strcmp(dir, "src") != 0) { - goto end; - } + FAIL_IF(!DetectHostbitParse("isset, name ,src", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + FAIL_IF(strcmp(dir, "src") != 0); /* With direction - space around direction. */ *cmd = '\0'; *name = '\0'; *dir = '\0'; - if (!DetectHostbitParse("isset, name , src ", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))) { - goto end; - } - if (strcmp(cmd, "isset") != 0) { - goto end; - } - if (strcmp(name, "name") != 0) { - goto end; - } - if (strcmp(dir, "src") != 0) { - goto end; - } + FAIL_IF(!DetectHostbitParse("isset, name , src ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + FAIL_IF(strcmp(dir, "src") != 0); - ret = 1; -end: - return ret; + /* Name with space, no direction - should fail. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + FAIL_IF(DetectHostbitParse("isset, name withspace ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + + PASS; } /** From 3c5d8e65d4060494a3e74702e795b0301c0024c3 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 15 Sep 2016 10:40:22 -0600 Subject: [PATCH 1626/2553] hostbits: use new unittest macros --- src/detect-hostbits.c | 222 +++++++----------------------------------- 1 file changed, 34 insertions(+), 188 deletions(-) diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 16394d8d35f6..c12bc604ed29 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -553,7 +553,6 @@ static int HostBitsTestSig01(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); @@ -566,29 +565,18 @@ static int HostBitsTestSig01(void) HostBitsTestSetup(); de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - printf("bad de_ctx: "); - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (hostbits:set,abc; content:\"GET \"; sid:1;)"); - - if (s == NULL) { - printf("bad sig: "); - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - result = 1; - -end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -605,7 +593,7 @@ static int HostBitsTestSig01(void) HostBitsTestShutdown(); SCFree(p); - return result; + PASS; } /** @@ -620,65 +608,39 @@ static int HostBitsTestSig02(void) Signature *s = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; - int result = 0; - int error_count = 0; memset(&th_v, 0, sizeof(th_v)); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:isset,abc,src; content:\"GET \"; sid:1;)"); - if (s == NULL) { - error_count++; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:isnotset,abc,dst; content:\"GET \"; sid:2;)"); - if (s == NULL) { - error_count++; - } + FAIL_IF_NULL(s); + /* TODO reenable after both is supported s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:set,abc,both; content:\"GET \"; sid:3;)"); - if (s == NULL) { - error_count++; - } + FAIL_IF_NULL(s); */ s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:unset,abc,src; content:\"GET \"; sid:4;)"); - if (s == NULL) { - error_count++; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:toggle,abc,dst; content:\"GET \"; sid:5;)"); - if (s == NULL) { - error_count++; - } - - if (error_count != 0) - goto end; - - result = 1; + FAIL_IF_NULL(s); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - } - - return result; + PASS; } #if 0 @@ -782,7 +744,6 @@ static int HostBitsTestSig04(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; int idx = 0; memset(&th_v, 0, sizeof(th_v)); @@ -796,28 +757,21 @@ static int HostBitsTestSig04(void) HostBitsTestSetup(); de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; hostbits:isset,fbt; content:\"GET \"; sid:1;)"); + FAIL_IF_NULL(s); idx = VariableNameGetIdx(de_ctx, "fbt", VAR_TYPE_HOST_BIT); - - if (s == NULL || idx != 1) { - goto end; - } + FAIL_IF(idx != 1); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - result = 1; - SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -826,27 +780,7 @@ static int HostBitsTestSig04(void) HostBitsTestShutdown(); SCFree(p); - return result; - -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - HostBitsTestShutdown(); - - SCFree(p); - return result; + PASS; } /** @@ -870,7 +804,6 @@ static int HostBitsTestSig05(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); @@ -883,28 +816,21 @@ static int HostBitsTestSig05(void) HostBitsTestSetup(); de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (hostbits:noalert; content:\"GET \"; sid:1;)"); - - if (s == NULL || ((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT)) { - goto end; - } + FAIL_IF_NULL(s); + FAIL_IF((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - result = 1; - } + FAIL_IF(PacketAlertCheck(p, 1)); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -915,26 +841,7 @@ static int HostBitsTestSig05(void) HostBitsTestShutdown(); SCFree(p); - return result; -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - HostBitsTestShutdown(); - - SCFree(p); - return result; + PASS; } #if 0 @@ -1146,8 +1053,7 @@ static int HostBitsTestSig07(void) FLOW_DESTROY(&f); SCFree(p); - return result; -} + return result;} #endif /** @@ -1189,26 +1095,17 @@ static int HostBitsTestSig07(void) p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (hostbits:set,myflow2; sid:10;)"); - - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); s = s->next = SigInit(de_ctx, "alert ip any any -> any any (hostbits:isset,myflow2; sid:11;)"); - - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -1222,6 +1119,7 @@ static int HostBitsTestSig07(void) result = 1; } } + FAIL_IF_NOT(result); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -1233,27 +1131,7 @@ static int HostBitsTestSig07(void) HostBitsTestShutdown(); SCFree(p); - return result; -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - FLOW_DESTROY(&f); - - HostBitsTestShutdown(); - SCFree(p); - return result; + PASS; } /** @@ -1277,7 +1155,6 @@ static int HostBitsTestSig08(void) DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; Flow f; - int result = 0; memset(p, 0, SIZE_OF_PACKET); memset(&th_v, 0, sizeof(th_v)); @@ -1295,33 +1172,22 @@ static int HostBitsTestSig08(void) p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:set,myflow2; sid:10;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:toggle,myflow2; sid:11;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:toggle,myflow2; sid:12;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:isset,myflow2; sid:13;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); @@ -1346,7 +1212,8 @@ static int HostBitsTestSig08(void) } if (PacketAlertCheck(p, 13)) { SCLogInfo("sid 13 matched"); - result = 1; + } else { + FAIL; } } @@ -1361,28 +1228,7 @@ static int HostBitsTestSig08(void) HostBitsTestShutdown(); SCFree(p); - return result; -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - FLOW_DESTROY(&f); - - HostBitsTestShutdown(); - - SCFree(p); - return result; + PASS; } #endif /* UNITTESTS */ From 17e70483c568a4b5b14d17542b9a7f4ea07e7ddf Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 15 Sep 2016 11:19:12 -0600 Subject: [PATCH 1627/2553] detect-flowbits: more unittest macro usage Also cleanup some tests by removing extra code after a test was determined to fail. --- src/detect-flowbits.c | 449 ++++-------------------------------------- 1 file changed, 37 insertions(+), 412 deletions(-) diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 5100f7f998a9..80494b07fe48 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -354,70 +354,19 @@ static int FlowBitsTestParse01(void) static int FlowBitsTestSig01(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)"); + FAIL_IF_NOT_NULL(s); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - SCFree(p); - PASS_IF(result == 0); + PASS; } /** @@ -429,117 +378,35 @@ static int FlowBitsTestSig01(void) static int FlowBitsTestSig02(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; - int error_count = 0; memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)"); - - if (s == NULL) { - error_count++; - } + FAIL_IF_NOT_NULL(s); s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)"); - - if (s == NULL) { - error_count++; - } + FAIL_IF_NOT_NULL(s); s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)"); - - if (s == NULL) { - error_count++; - } + FAIL_IF_NOT_NULL(s); s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)"); - - if (s == NULL) { - error_count++; - } + FAIL_IF_NOT_NULL(s); s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)"); + FAIL_IF_NOT_NULL(s); - if (s == NULL) { - error_count++; - } - - if(error_count == 5) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - goto cleanup; - } - if (PacketAlertCheck(p, 2)) { - goto cleanup; - } - if (PacketAlertCheck(p, 3)) { - goto cleanup; - } - if (PacketAlertCheck(p, 4)) { - goto cleanup; - } - if (PacketAlertCheck(p, 5)) { - goto cleanup; - } - - result = 1; - -cleanup: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - SCFree(p); - PASS_IF(result == 0); + PASS; } /** @@ -551,73 +418,19 @@ static int FlowBitsTestSig02(void) static int FlowBitsTestSig03(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)"); + FAIL_IF_NOT_NULL(s); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - - SCFree(p); - PASS_IF(result == 0); + PASS; } /** @@ -629,77 +442,23 @@ static int FlowBitsTestSig03(void) static int FlowBitsTestSig04(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; int idx = 0; - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; - de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)"); + FAIL_IF_NULL(s); idx = VariableNameGetIdx(de_ctx, "fbt", VAR_TYPE_FLOW_BIT); + FAIL_IF(idx != 1); - if (s == NULL || idx != 1) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - SCFree(p); - PASS_IF(result); - -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - SCFree(p); - PASS_IF(result); + PASS; } /** @@ -711,74 +470,20 @@ static int FlowBitsTestSig04(void) static int FlowBitsTestSig05(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)"); + FAIL_IF_NULL(s); + FAIL_IF((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT); - if (s == NULL || ((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT)) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - - SCFree(p); - PASS_IF(result); -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - SCFree(p); - PASS_IF(result); + PASS; } /** @@ -796,8 +501,7 @@ static int FlowBitsTestSig06(void) "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -825,18 +529,12 @@ static int FlowBitsTestSig06(void) p->flowflags |= FLOW_PKT_TOSERVER; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)"); - - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -852,6 +550,7 @@ static int FlowBitsTestSig06(void) result = 1; } } + FAIL_IF_NOT(result); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -863,26 +562,7 @@ static int FlowBitsTestSig06(void) FLOW_DESTROY(&f); SCFree(p); - PASS_IF(result); -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - if(gv) GenericVarFree(gv); - FLOW_DESTROY(&f); - SCFree(p); - PASS_IF(result); + PASS; } /** @@ -900,8 +580,7 @@ static int FlowBitsTestSig07(void) "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -927,22 +606,15 @@ static int FlowBitsTestSig07(void) p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -958,6 +630,7 @@ static int FlowBitsTestSig07(void) result = 1; } } + FAIL_IF(result); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -969,27 +642,7 @@ static int FlowBitsTestSig07(void) FLOW_DESTROY(&f); SCFree(p); - PASS_IF(result == 0); -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - if(gv) GenericVarFree(gv); - FLOW_DESTROY(&f); - - SCFree(p); - PASS_IF(result == 0); + PASS; } /** @@ -1034,24 +687,15 @@ static int FlowBitsTestSig08(void) p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); - - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)"); - - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -1067,6 +711,7 @@ static int FlowBitsTestSig08(void) result = 1; } } + FAIL_IF(result); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -1078,27 +723,7 @@ static int FlowBitsTestSig08(void) FLOW_DESTROY(&f); SCFree(p); - PASS_IF(result == 0); -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - if(gv) GenericVarFree(gv); - FLOW_DESTROY(&f); - - SCFree(p); - PASS_IF(result == 0); + PASS; } #endif /* UNITTESTS */ From 4324805478dabb699a1650490c89023c0a695b70 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 16 Sep 2016 11:47:20 +0200 Subject: [PATCH 1628/2553] coccinelle: add siginit test Add a test that check an inversion during keyword setup where we add a sigmatch to a signature and then do error handling on it. This was causing a double free of some elements and ultimately a segfault. Proposed-by: Victor Julien --- qa/coccinelle/siginit.cocci | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 qa/coccinelle/siginit.cocci diff --git a/qa/coccinelle/siginit.cocci b/qa/coccinelle/siginit.cocci new file mode 100644 index 000000000000..9a2193be408d --- /dev/null +++ b/qa/coccinelle/siginit.cocci @@ -0,0 +1,26 @@ +@siginit@ +identifier func =~ "Detect.*Setup"; +expression E1; +position p1; +identifier de_ctx, s, str, error; +type DetectEngineCtx, Signature; +@@ + +func(DetectEngineCtx *de_ctx, Signature *s, char *str) { +... +SigMatchAppendSMToList(s, ...)@p1; +... +if (s->alproto != E1 && ...) { +... +goto error; +} +... +} + + +@script:python@ +p1 << siginit.p1; +@@ +print "SigMatch added at %s:%s but error handling can cause it to be freed later." % (p1[0].file, p1[0].line) +import sys +sys.exit(1) From ed90a16e8986d46686efbc608b2c9611db90034d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 16 Sep 2016 13:34:09 +0200 Subject: [PATCH 1629/2553] detect: fix setup for some keywords Fix problems found by siginit.cocci. --- src/detect-dce-iface.c | 4 ++-- src/detect-dce-opnum.c | 4 ++-- src/detect-fileext.c | 4 ++-- src/detect-filemd5.c | 4 ++-- src/detect-filename.c | 4 ++-- src/detect-filesize.c | 4 ++-- src/detect-ssl-version.c | 4 ++-- src/detect-tls-version.c | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 3e89feb5572d..06ae77c1f644 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -336,13 +336,13 @@ static int DetectDceIfaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->type = DETECT_DCE_IFACE; sm->ctx = (void *)did; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + s->alproto = ALPROTO_DCERPC; /* Flagged the signature as to inspect the app layer data */ s->flags |= SIG_FLAG_APPLAYER; diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index b650fe27ce4b..f25010893551 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -306,13 +306,13 @@ static int DetectDceOpnumSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->type = DETECT_DCE_OPNUM; sm->ctx = (void *)dod; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + s->alproto = ALPROTO_DCERPC; /* Flagged the signature as to inspect the app layer data */ s->flags |= SIG_FLAG_APPLAYER; diff --git a/src/detect-fileext.c b/src/detect-fileext.c index e4f146e29f53..484e6b8ab78a 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -209,13 +209,13 @@ static int DetectFileextSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) sm->type = DETECT_FILEEXT; sm->ctx = (void *)fileext; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + if (s->alproto == ALPROTO_HTTP) { AppLayerHtpNeedFileInspection(); } diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index faedb11c0b07..af149b4147d3 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -322,13 +322,13 @@ static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) sm->type = DETECT_FILEMD5; sm->ctx = (void *)filemd5; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + if (s->alproto == ALPROTO_HTTP) { AppLayerHtpNeedFileInspection(); } diff --git a/src/detect-filename.c b/src/detect-filename.c index 2bc9a09d4f38..780f073f9524 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -213,13 +213,13 @@ static int DetectFilenameSetup (DetectEngineCtx *de_ctx, Signature *s, char *str sm->type = DETECT_FILENAME; sm->ctx = (void *)filename; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + if (s->alproto == ALPROTO_HTTP) { AppLayerHtpNeedFileInspection(); } diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 92dcfebb9bae..6e9fe5fbb344 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -287,13 +287,13 @@ static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *str sm->type = DETECT_FILESIZE; sm->ctx = (SigMatchCtx *)fsd; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + if (s->alproto == ALPROTO_HTTP) { AppLayerHtpNeedFileInspection(); } diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index 5259187eb6e7..e5957c12118b 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -292,13 +292,13 @@ static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->type = DETECT_AL_SSL_VERSION; sm->ctx = (void *)ssl; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + s->alproto = ALPROTO_TLS; return 0; diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index 200ba959f898..745bedefca6b 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -228,13 +228,13 @@ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->type = DETECT_AL_TLS_VERSION; sm->ctx = (void *)tls; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + s->alproto = ALPROTO_TLS; return 0; From 519b2970ec5618ef7e86748a7f762e2a9669f2ab Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Sep 2016 15:06:11 +0200 Subject: [PATCH 1630/2553] detect: don't print (null) in --list-keywords=all --- src/detect.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index 3ae6e0f8605f..7a779f3ae4ae 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4256,8 +4256,10 @@ void SigTableList(const char *keyword) } } else if (!strcmp("all", keyword)) { for (i = 0; i < size; i++) { - printf("%s:\n", sigmatch_table[i].name); - SigMultilinePrint(i, "\t"); + if (sigmatch_table[i].name != NULL) { + printf("%s:\n", sigmatch_table[i].name); + SigMultilinePrint(i, "\t"); + } } } else { for (i = 0; i < size; i++) { From 71c8d1f46c6adeafa31f46f105f875a96e94b938 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 8 Sep 2016 10:39:51 +0200 Subject: [PATCH 1631/2553] bpf: fix file parsing memory handling Fix improper fread string handling. Improve error handling. Skip trailing spaces for slightly more pretty printing. Coverity CID 400763. Thanks to Steve Grubb for helping address this issue. --- src/suricata.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 99611cb4de70..708d1640c13a 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -484,11 +484,15 @@ static void SetBpfStringFromFile(char *filename) } memset(bpf_filter, 0x00, bpf_len); - nm = fread(bpf_filter, bpf_len - 1, 1, fp); - if((ferror(fp) != 0)||( nm != 1)) { - *bpf_filter='\0'; + nm = fread(bpf_filter, 1, bpf_len - 1, fp); + if ((ferror(fp) != 0) || (nm != (bpf_len - 1))) { + SCLogError(SC_ERR_BPF, "Failed to read complete BPF file %s", filename); + SCFree(bpf_filter); + fclose(fp); + exit(EXIT_FAILURE); } fclose(fp); + bpf_filter[nm] = '\0'; if(strlen(bpf_filter) > 0) { /*replace comments with space*/ @@ -508,10 +512,18 @@ static void SetBpfStringFromFile(char *filename) while((bpf_comment_tmp = strchr(bpf_filter, '\n')) != NULL) { *bpf_comment_tmp = ' '; } - if(ConfSetFinal("bpf-filter", bpf_filter) != 1) { - SCLogError(SC_ERR_FOPEN, "ERROR: Failed to set bpf filter!"); - SCFree(bpf_filter); - exit(EXIT_FAILURE); + /* cut trailing spaces */ + while (strlen(bpf_filter) > 0 && + bpf_filter[strlen(bpf_filter)-1] == ' ') + { + bpf_filter[strlen(bpf_filter)-1] = '\0'; + } + if (strlen(bpf_filter) > 0) { + if(ConfSetFinal("bpf-filter", bpf_filter) != 1) { + SCLogError(SC_ERR_FOPEN, "ERROR: Failed to set bpf filter!"); + SCFree(bpf_filter); + exit(EXIT_FAILURE); + } } } SCFree(bpf_filter); From 82282a9e6840a34b4aece83456a548fadbfad7c0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Sep 2016 18:10:51 +0200 Subject: [PATCH 1632/2553] mpls: add missing event type + rule --- rules/decoder-events.rules | 3 ++- src/decode-events.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rules/decoder-events.rules b/rules/decoder-events.rules index 7240ea06785b..95414b74c6dc 100644 --- a/rules/decoder-events.rules +++ b/rules/decoder-events.rules @@ -121,6 +121,7 @@ alert pkthdr any any -> any any (msg:"SURICATA IPv6-in-IPv6 packet too short"; d alert pkthdr any any -> any any (msg:"SURICATA IPv6-in-IPv6 invalid protocol"; decode-event:ipv6.ipv6_in_ipv6_wrong_version; sid:2200085; rev:1;) # MPLS rules +alert pkthdr any any -> any any (msg:"SURICATA MPLS header too small"; decode-event:mpls.header_too_small; sid:2200111; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA MPLS bad router alert label"; decode-event:mpls.bad_label_router_alert; sid: 2200098; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA MPLS bad implicit null label"; decode-event:mpls.bad_label_implicit_null; sid: 2200099; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA MPLS reserved label"; decode-event:mpls.bad_label_reserved; sid: 2200100; rev:1;) @@ -140,5 +141,5 @@ alert pkthdr any any -> any any (msg:"SURICATA ERSPAN too many vlan layers"; dec # Cisco Fabric Path/DCE alert pkthdr any any -> any any (msg:"SURICATA DCE packet too small"; decode-event:dce.pkt_too_small; sid:2200110; rev:1;) -# next sid is 2200111 +# next sid is 2200112 diff --git a/src/decode-events.c b/src/decode-events.c index d7e4ecc946c5..a07b44b1d444 100644 --- a/src/decode-events.c +++ b/src/decode-events.c @@ -168,6 +168,7 @@ const struct DecodeEvents_ DEvents[] = { { "decoder.ipv6.ipv6_in_ipv6_wrong_version", IPV6_IN_IPV6_WRONG_IP_VER, }, /* MPLS events */ + { "decoder.mpls.header_too_small", MPLS_HEADER_TOO_SMALL, }, { "decoder.mpls.bad_label_router_alert", MPLS_BAD_LABEL_ROUTER_ALERT, }, { "decoder.mpls.bad_label_implicit_null", MPLS_BAD_LABEL_IMPLICIT_NULL, }, { "decoder.mpls.bad_label_reserved", MPLS_BAD_LABEL_RESERVED, }, From 471b61a0e1f7f27977d16cdb6081e783c3a4a50c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Sep 2016 09:12:28 +0200 Subject: [PATCH 1633/2553] magic: fix broken tests after CentOS6 update --- src/util-magic.c | 50 ++++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/src/util-magic.c b/src/util-magic.c index 679545751f3e..5f0719787598 100644 --- a/src/util-magic.c +++ b/src/util-magic.c @@ -307,9 +307,6 @@ int MagicDetectTest02(void) /** \test magic lib calls -- lookup */ int MagicDetectTest03(void) { - magic_t magic_ctx; - char *result = NULL; - char buffer[] = { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x5e, 0xc6, @@ -335,29 +332,23 @@ int MagicDetectTest03(void) 0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b, }; size_t buffer_len = sizeof(buffer); - int retval = 0; - magic_ctx = magic_open(0); - if (magic_ctx == NULL) { - printf("failure retrieving magic_ctx\n"); - return 0; - } + magic_t magic_ctx = magic_open(0); + FAIL_IF_NULL(magic_ctx); - if (magic_load(magic_ctx, NULL) == -1) { - printf("magic_load failure\n"); - goto end; - } + FAIL_IF(magic_load(magic_ctx, NULL) == -1); - result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); - if (result == NULL || strcmp(result, "OpenDocument Text") != 0) { - printf("result %p:%s, not \"OpenDocument Text\": ", result,result?result:"(null)"); - goto end; + char *result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); + FAIL_IF_NULL(result); + + char *str = strstr(result, "OpenDocument Text"); + if (str == NULL) { + printf("result %s, not \"OpenDocument Text\": ", str); + FAIL; } - retval = 1; -end: magic_close(magic_ctx); - return retval; + PASS; } /** \test magic lib calls -- lookup */ @@ -517,23 +508,20 @@ int MagicDetectTest07(void) 0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b, }; size_t buffer_len = sizeof(buffer); - int retval = 0; - if (MagicInit() < 0) { - printf("MagicInit() failure\n"); - return 0; - } + FAIL_IF(MagicInit() < 0); result = MagicGlobalLookup(buffer, buffer_len); - if (result == NULL || strcmp(result, "OpenDocument Text") != 0) { - printf("result %p:%s, not \"OpenDocument Text\": ", result,result?result:"(null)"); - goto end; + FAIL_IF_NULL(result); + + char *str = strstr(result, "OpenDocument Text"); + if (str == NULL) { + printf("result %s, not \"OpenDocument Text\": ", str); + FAIL; } - retval = 1; -end: MagicDeinit(); - return retval; + PASS; } /** \test magic api calls -- lookup */ From 54503ef31012fe779b9abfd08911fa1b61d80234 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Sep 2016 12:37:12 +0200 Subject: [PATCH 1634/2553] Open Suricata 3.2 development branch --- configure.ac | 2 +- src/suricata.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 2437f58671da..d6837d4576f9 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ - AC_INIT(suricata, 3.1dev) + AC_INIT(suricata, 3.2dev) m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])AM_SILENT_RULES([yes]) m4_ifndef([AS_VERSION_COMPARE], [AC_DEFUN([AS_VERSION_COMPARE],[])]) AC_CONFIG_HEADERS([config.h]) diff --git a/src/suricata.h b/src/suricata.h index 337305361d84..b38e65274b49 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -71,7 +71,7 @@ /* the name of our binary */ #define PROG_NAME "Suricata" -#define PROG_VER "3.1dev" +#define PROG_VER "3.2dev" /* workaround SPlint error (don't know __gnuc_va_list) */ #ifdef S_SPLINT_S From fb655d5f152bcd04d049631a15831142fc478fb5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 13 Jul 2016 21:07:11 +0200 Subject: [PATCH 1635/2553] threading: remove thread restart logic Thread restarts never worked well and the rest of the engine was never really expecting errors to lead to thread restarts. Either and error is recoverable in the thread, or not at all. So this patch removes the functionality completely. --- src/threadvars.h | 15 ----------- src/tm-threads.c | 67 +++--------------------------------------------- src/tm-threads.h | 1 - 3 files changed, 3 insertions(+), 80 deletions(-) diff --git a/src/threadvars.h b/src/threadvars.h index c72dcc734ddb..389f22a14eaa 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -53,14 +53,6 @@ struct TmSlot_; * rule reloads even if no packets are read by the capture method. */ #define THV_CAPTURE_INJECT_PKT (1<<11) -/** Thread flags set and read by threads, to control the threads, when they - * encounter certain conditions like failure */ -#define THV_RESTART_THREAD 0x01 /** restart the thread */ -#define THV_ENGINE_EXIT 0x02 /** shut the engine down gracefully */ - -/** Maximum no of times a thread can be restarted */ -#define THV_MAX_RESTARTS 50 - /** \brief Per thread variable structure */ typedef struct ThreadVars_ { pthread_t t; @@ -69,13 +61,6 @@ typedef struct ThreadVars_ { SC_ATOMIC_DECLARE(unsigned int, flags); - /** aof(action on failure) determines what should be done with the thread - when it encounters certain conditions like failures */ - uint8_t aof; - - /** no of times the thread has been restarted on failure */ - uint8_t restarted; - /** TmModule::flags for each module part of this thread */ uint8_t tmm_flags; diff --git a/src/tm-threads.c b/src/tm-threads.c index 08fb6429ee7c..fa84364963cc 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -81,10 +81,6 @@ ThreadVars *tv_root[TVT_MAX] = { NULL }; /* lock to protect tv_root */ SCMutex tv_root_lock = SCMUTEX_INITIALIZER; -/* Action On Failure(AOF). Determines how the engine should behave when a - * thread encounters a failure. Defaults to restart the failed thread */ -uint8_t tv_aof = THV_RESTART_THREAD; - /** * \brief Check if a thread flag is set. * @@ -1171,8 +1167,6 @@ ThreadVars *TmThreadCreate(const char *name, char *inq_name, char *inqh_name, /* default state for every newly created thread */ TmThreadsSetFlag(tv, THV_PAUSE); TmThreadsSetFlag(tv, THV_USE); - /* default aof for every newly created thread */ - tv->aof = THV_RESTART_THREAD; /* set the incoming queue */ if (inq_name != NULL && strcmp(inq_name, "packetpool") != 0) { @@ -1879,19 +1873,6 @@ void TmThreadSetFlags(ThreadVars *tv, uint8_t flags) return; } #endif -/** - * \brief Sets the aof(Action on failure) for a thread instance(tv) - * - * \param tv Pointer to the thread instance for which the aof has to be set - * \param aof Holds the aof this thread instance has to be set to - */ -void TmThreadSetAOF(ThreadVars *tv, uint8_t aof) -{ - if (tv != NULL) - tv->aof = aof; - - return; -} /** * \brief Initializes the mutex and condition variables for this TV @@ -2046,38 +2027,7 @@ void TmThreadPauseThreads() } /** - * \brief Restarts the thread sent as the argument - * - * \param tv Pointer to the thread instance(tv) to be restarted - */ -static void TmThreadRestartThread(ThreadVars *tv) -{ - if (tv->restarted >= THV_MAX_RESTARTS) { - SCLogError(SC_ERR_TM_THREADS_ERROR,"thread restarts exceeded " - "threshold limit for thread \"%s\"", tv->name); - exit(EXIT_FAILURE); - } - - TmThreadsUnsetFlag(tv, THV_CLOSED); - TmThreadsUnsetFlag(tv, THV_FAILED); - - if (TmThreadSpawn(tv) != TM_ECODE_OK) { - SCLogError(SC_ERR_THREAD_SPAWN, "thread \"%s\" failed to spawn", tv->name); - exit(EXIT_FAILURE); - } - - tv->restarted++; - SCLogInfo("thread \"%s\" restarted", tv->name); - - return; -} - -/** - * \brief Used to check the thread for certain conditions of failure. If the - * thread has been specified to restart on failure, the thread is - * restarted. If the thread has been specified to gracefully shutdown - * the engine on failure, it does so. The global aof flag, tv_aof - * overrides the thread aof flag, if it holds a THV_ENGINE_EXIT; + * \brief Used to check the thread for certain conditions of failure. */ void TmThreadCheckThreadState(void) { @@ -2091,19 +2041,8 @@ void TmThreadCheckThreadState(void) while (tv) { if (TmThreadsCheckFlag(tv, THV_FAILED)) { TmThreadsSetFlag(tv, THV_DEINIT); - pthread_join(tv->t, NULL); - if ((tv_aof & THV_ENGINE_EXIT) || (tv->aof & THV_ENGINE_EXIT)) { - EngineKill(); - goto end; - } else { - /* if the engine kill-stop has been received by now, chuck - * restarting and return to kill the engine */ - if ((suricata_ctl_flags & SURICATA_KILL) || - (suricata_ctl_flags & SURICATA_STOP)) { - goto end; - } - TmThreadRestartThread(tv); - } + EngineKill(); + goto end; } tv = tv->next; } diff --git a/src/tm-threads.h b/src/tm-threads.h index 1942ae1ce54a..943b6236a9b8 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -95,7 +95,6 @@ ThreadVars *TmThreadCreateCmdThreadByName(const char *name, char *module, int mucond); TmEcode TmThreadSpawn(ThreadVars *); void TmThreadSetFlags(ThreadVars *, uint8_t); -void TmThreadSetAOF(ThreadVars *, uint8_t); void TmThreadKillThread(ThreadVars *); void TmThreadKillThreadsFamily(int family); void TmThreadKillThreads(void); From 045c10db43ca97fe0c2ebf70e8af6c874f3cad71 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 Jul 2016 09:49:21 +0200 Subject: [PATCH 1636/2553] threads: failed thread is a fatal error now --- src/tm-threads.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/tm-threads.c b/src/tm-threads.c index fa84364963cc..c5699e82ad4c 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -2040,14 +2040,11 @@ void TmThreadCheckThreadState(void) while (tv) { if (TmThreadsCheckFlag(tv, THV_FAILED)) { - TmThreadsSetFlag(tv, THV_DEINIT); - EngineKill(); - goto end; + FatalError(SC_ERR_FATAL, "thread %s failed", tv->name); } tv = tv->next; } } -end: SCMutexUnlock(&tv_root_lock); return; } From 85db260eed58c006ecac17277ccb016c5499f926 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 Jul 2016 10:36:54 +0200 Subject: [PATCH 1637/2553] threads: remove EngineKill & SURICATA_KILL EngineStop and EngineKill were effectively doing the same, so removed the kill variant. --- src/source-af-packet.c | 3 --- src/source-erf-dag.c | 2 +- src/source-erf-file.c | 2 +- src/source-napatech.c | 2 +- src/source-pcap-file.c | 10 +++++----- src/source-pcap.c | 2 +- src/source-pfring.c | 4 ++-- src/suricata.c | 17 +++++------------ src/suricata.h | 3 --- src/tm-threads.c | 26 ++++++++++---------------- src/unix-manager.c | 2 +- 11 files changed, 27 insertions(+), 46 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 2721ed47f6b2..1909cdcbf6df 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1335,9 +1335,6 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) switch (-r) { case AFP_FATAL_ERROR: SCLogError(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket, fatal error"); - /* fatal is fatal, we want suri to exit */ - EngineKill(); - //tv->aof = THV_ENGINE_EXIT; SCReturnInt(TM_ECODE_FAILED); case AFP_RECOVERABLE_ERROR: SCLogWarning(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket, retrying soon"); diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index 76f5fe3d83e2..db6b3d9f6459 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -342,7 +342,7 @@ ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) dtv->slot = s->slot_next; while (1) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } diff --git a/src/source-erf-file.c b/src/source-erf-file.c index 5d8af87f7563..29e59358c8d3 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -117,7 +117,7 @@ TmEcode ReceiveErfFileLoop(ThreadVars *tv, void *data, void *slot) etv->slot = ((TmSlot *)slot)->slot_next; while (1) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } diff --git a/src/source-napatech.c b/src/source-napatech.c index 5566e4022794..1348eaf99e16 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -206,7 +206,7 @@ TmEcode NapatechStreamLoop(ThreadVars *tv, void *data, void *slot) TmSlot *s = (TmSlot *)slot; ntv->slot = s->slot_next; - while (!(suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL))) { + while (!(suricata_ctl_flags & SURICATA_STOP)) { /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ PacketPoolWait(); diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 6a587e2b22c7..51515b7c8523 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -199,7 +199,7 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) ptv->cb_result = TM_ECODE_OK; while (1) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } @@ -213,10 +213,11 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) if (unlikely(r == -1)) { SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s", r, pcap_geterr(pcap_g.pcap_handle)); - if (! RunModeUnixSocketIsActive()) { - /* in the error state we just kill the engine */ - EngineKill(); + if (ptv->cb_result == TM_ECODE_FAILED) { SCReturnInt(TM_ECODE_FAILED); + } + if (! RunModeUnixSocketIsActive()) { + EngineStop(); } else { pcap_close(pcap_g.pcap_handle); pcap_g.pcap_handle = NULL; @@ -237,7 +238,6 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) } else if (ptv->cb_result == TM_ECODE_FAILED) { SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapFileCallbackLoop failed"); if (! RunModeUnixSocketIsActive()) { - EngineKill(); SCReturnInt(TM_ECODE_FAILED); } else { pcap_close(pcap_g.pcap_handle); diff --git a/src/source-pcap.c b/src/source-pcap.c index 97fcd72e6f93..ac7d3a35a89e 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -305,7 +305,7 @@ TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot) ptv->cb_result = TM_ECODE_OK; while (1) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } diff --git a/src/source-pfring.c b/src/source-pfring.c index 4b4715d313f8..d8583f5f18e6 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -318,7 +318,7 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) } while(1) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } @@ -374,7 +374,7 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) last_dump = p->ts.tv_sec; } } else if (unlikely(r == 0)) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } diff --git a/src/suricata.c b/src/suricata.c index 708d1640c13a..4c1c6a67594d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -367,19 +367,14 @@ void GlobalInits() CreateLowercaseTable(); } -/* XXX hack: make sure threads can stop the engine by calling this - function. Purpose: pcap file mode needs to be able to tell the - engine the file eof is reached. */ +/** \brief make sure threads can stop the engine by calling this + * function. Purpose: pcap file mode needs to be able to tell the + * engine the file eof is reached. */ void EngineStop(void) { suricata_ctl_flags |= SURICATA_STOP; } -void EngineKill(void) -{ - suricata_ctl_flags |= SURICATA_KILL; -} - /** * \brief Used to indicate that the current task is done. * @@ -2667,13 +2662,11 @@ int main(int argc, char **argv) int engine_retval = EXIT_SUCCESS; while(1) { - if (sigterm_count) { - suricata_ctl_flags |= SURICATA_KILL; - } else if (sigint_count) { + if (sigterm_count || sigint_count) { suricata_ctl_flags |= SURICATA_STOP; } - if (suricata_ctl_flags & (SURICATA_KILL | SURICATA_STOP)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCLogNotice("Signal Received. Stopping engine."); break; } diff --git a/src/suricata.h b/src/suricata.h index b38e65274b49..4273ecb6e96b 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -88,8 +88,6 @@ /* runtime engine control flags */ #define SURICATA_STOP (1 << 0) /**< gracefully stop the engine: process all outstanding packets first */ -#define SURICATA_KILL (1 << 1) /**< shut down asap, discarding outstanding - packets. */ #define SURICATA_DONE (1 << 2) /**< packets capture ended */ /* Engine stage/status*/ @@ -181,7 +179,6 @@ uint8_t g_u8_lowercasetable[256]; #define u8_tolower(c) tolower((uint8_t)(c)) void EngineStop(void); -void EngineKill(void); void EngineDone(void); int RunmodeIsUnittests(void); diff --git a/src/tm-threads.c b/src/tm-threads.c index c5699e82ad4c..9df10ff9370a 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -283,8 +283,6 @@ void *TmThreadsSlotPktAcqLoop(void *td) " PktAcqLoop=%p, tmqh_in=%p," " tmqh_out=%p", s, s ? s->PktAcqLoop : NULL, tv->tmqh_in, tv->tmqh_out); - EngineKill(); - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; @@ -300,7 +298,6 @@ void *TmThreadsSlotPktAcqLoop(void *td) TmThreadsSetFlag(tv, THV_CLOSED | THV_INIT_DONE | THV_RUNNING_DONE); goto error; } else { - EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); goto error; } @@ -336,8 +333,11 @@ void *TmThreadsSlotPktAcqLoop(void *td) r = s->PktAcqLoop(tv, SC_ATOMIC_GET(s->slot_data), s); - if (r == TM_ECODE_FAILED || TmThreadsCheckFlag(tv, THV_KILL_PKTACQ) - || suricata_ctl_flags) { + if (r == TM_ECODE_FAILED) { + TmThreadsSetFlag(tv, THV_FAILED); + run = 0; + } + if (TmThreadsCheckFlag(tv, THV_KILL_PKTACQ) || suricata_ctl_flags) { run = 0; } if (r == TM_ECODE_DONE) { @@ -408,8 +408,6 @@ void *TmThreadsSlotPktAcqLoopAFL(void *td) " PktAcqLoop=%p, tmqh_in=%p," " tmqh_out=%p", s, s ? s->PktAcqLoop : NULL, tv->tmqh_in, tv->tmqh_out); - EngineKill(); - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); return NULL; } @@ -424,7 +422,6 @@ void *TmThreadsSlotPktAcqLoopAFL(void *td) TmThreadsSetFlag(tv, THV_CLOSED | THV_INIT_DONE | THV_RUNNING_DONE); goto error; } else { - EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); goto error; } @@ -456,8 +453,11 @@ void *TmThreadsSlotPktAcqLoopAFL(void *td) r = s->PktAcqLoop(tv, SC_ATOMIC_GET(s->slot_data), s); - if (r == TM_ECODE_FAILED || TmThreadsCheckFlag(tv, THV_KILL_PKTACQ) - || suricata_ctl_flags) { + if (r == TM_ECODE_FAILED) { + TmThreadsSetFlag(tv, THV_FAILED); + run = 0; + } + if (TmThreadsCheckFlag(tv, THV_KILL_PKTACQ) || suricata_ctl_flags) { run = 0; } if (r == TM_ECODE_DONE) { @@ -530,8 +530,6 @@ void *TmThreadsSlotVar(void *td) /* check if we are setup properly */ if (s == NULL || tv->tmqh_in == NULL || tv->tmqh_out == NULL) { - EngineKill(); - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; @@ -542,8 +540,6 @@ void *TmThreadsSlotVar(void *td) void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { - EngineKill(); - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); goto error; } @@ -697,8 +693,6 @@ static void *TmThreadsManagement(void *td) void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { - EngineKill(); - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; diff --git a/src/unix-manager.c b/src/unix-manager.c index bb6eef6756b0..86f619676364 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -579,7 +579,7 @@ int UnixMain(UnixCommand * this) return 0; } - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) { UnixCommandClose(this, uclient->fd); } From bcfa484bce226cda03c88edaadd82752156b95ee Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Sep 2016 14:39:56 +0200 Subject: [PATCH 1638/2553] app-layer: add function to check if app-layer supports files --- src/app-layer-parser.c | 7 +++++++ src/app-layer-parser.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 4c0e9b8ee79b..4d95fe12b3ac 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -861,6 +861,13 @@ uint64_t AppLayerParserGetTransactionActive(uint8_t ipproto, AppProto alproto, SCReturnCT(active_id, "uint64_t"); } +int AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto) +{ + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetFiles != NULL) + return TRUE; + return FALSE; +} + int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto) { if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState != NULL) diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index cad9ec31821e..ae7f89b6be2b 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -185,6 +185,7 @@ uint64_t AppLayerParserGetTransactionActive(uint8_t ipproto, AppProto alproto, A uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto); +int AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto); int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto); int AppLayerParserHasTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate); DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx); From 621860f5b2d188a99ea2c04bdfa791f9892febc0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Sep 2016 14:40:35 +0200 Subject: [PATCH 1639/2553] detect file: enforce protocol in single place Instead of trying to enforce the app layer protocol in each file function, enforce it in the generic validation function. --- src/detect-fileext.c | 5 ----- src/detect-filemagic.c | 5 ----- src/detect-filemd5.c | 5 ----- src/detect-filename.c | 6 +----- src/detect-filesize.c | 5 ----- src/detect-filestore.c | 5 ----- src/detect-parse.c | 9 +++++++++ src/util-error.c | 1 + src/util-error.h | 1 + 9 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/detect-fileext.c b/src/detect-fileext.c index 484e6b8ab78a..973d5082117c 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -209,11 +209,6 @@ static int DetectFileextSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) sm->type = DETECT_FILEEXT; sm->ctx = (void *)fileext; - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); if (s->alproto == ALPROTO_HTTP) { diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 26fcd44390b6..950b0290f06d 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -338,11 +338,6 @@ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, char *st DetectFilemagicData *filemagic = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rules with filemagic need to have protocol set to http or smtp."); - goto error; - } - filemagic = DetectFilemagicParse(str); if (filemagic == NULL) goto error; diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index af149b4147d3..d8a187122609 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -322,11 +322,6 @@ static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) sm->type = DETECT_FILEMD5; sm->ctx = (void *)filemd5; - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); if (s->alproto == ALPROTO_HTTP) { diff --git a/src/detect-filename.c b/src/detect-filename.c index 780f073f9524..0fd55392ef5f 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -49,6 +49,7 @@ #include "stream-tcp.h" #include "detect-filename.h" +#include "app-layer-parser.h" static int DetectFilenameMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, Signature *, SigMatch *); @@ -213,11 +214,6 @@ static int DetectFilenameSetup (DetectEngineCtx *de_ctx, Signature *s, char *str sm->type = DETECT_FILENAME; sm->ctx = (void *)filename; - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); if (s->alproto == ALPROTO_HTTP) { diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 6e9fe5fbb344..9aeae0c6f499 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -287,11 +287,6 @@ static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *str sm->type = DETECT_FILESIZE; sm->ctx = (SigMatchCtx *)fsd; - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); if (s->alproto == ALPROTO_HTTP) { diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 8927ff5d1beb..38c7ce2bfecc 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -387,11 +387,6 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *st sm->ctx = (SigMatchCtx*)NULL; } - if (s->alproto != ALPROTO_HTTP && s->alproto != ALPROTO_SMTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - if (s->alproto == ALPROTO_HTTP) { AppLayerHtpNeedFileInspection(); } diff --git a/src/detect-parse.c b/src/detect-parse.c index 01bf5fef30eb..3f6a7a6a8a4c 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1421,6 +1421,15 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } #endif + if (((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0) && + s->alproto != ALPROTO_UNKNOWN && + !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto)) + { + SCLogError(SC_ERR_NO_FILES_FOR_PROTOCOL, "protocol %s doesn't " + "support file matching", AppProtoToString(s->alproto)); + SCReturnInt(0); + } + SCReturnInt(1); } diff --git a/src/util-error.c b/src/util-error.c index 672430adcaec..50d013c58c35 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -325,6 +325,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_SMTP_LOG_GENERIC); CASE_CODE (SC_ERR_SSH_LOG_GENERIC); CASE_CODE (SC_ERR_NIC_OFFLOADING); + CASE_CODE (SC_ERR_NO_FILES_FOR_PROTOCOL); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 99c8f1375d0f..28a50cff4edb 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -315,6 +315,7 @@ typedef enum { SC_ERR_SMTP_LOG_GENERIC, SC_ERR_SSH_LOG_GENERIC, SC_ERR_NIC_OFFLOADING, + SC_ERR_NO_FILES_FOR_PROTOCOL, } SCError; const char *SCErrorToString(SCError); From c957c62824bff022f4633fcf24345828c02b04ad Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Sep 2016 15:13:33 +0200 Subject: [PATCH 1640/2553] detect file: enable HTTP inspection from validate func --- src/detect-fileext.c | 4 ---- src/detect-filemagic.c | 4 ---- src/detect-filemd5.c | 4 ---- src/detect-filename.c | 4 ---- src/detect-filesize.c | 4 ---- src/detect-parse.c | 19 ++++++++++++------- 6 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/detect-fileext.c b/src/detect-fileext.c index 973d5082117c..73ce1d346e3e 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -211,10 +211,6 @@ static int DetectFileextSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto == ALPROTO_HTTP) { - AppLayerHtpNeedFileInspection(); - } - s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_FILENAME); return 0; diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 950b0290f06d..26a3b969ab91 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -359,10 +359,6 @@ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, char *st SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto == ALPROTO_HTTP) { - AppLayerHtpNeedFileInspection(); - } - s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MAGIC); return 0; diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index d8a187122609..2e1988a630ad 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -324,10 +324,6 @@ static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto == ALPROTO_HTTP) { - AppLayerHtpNeedFileInspection(); - } - s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MD5); return 0; diff --git a/src/detect-filename.c b/src/detect-filename.c index 0fd55392ef5f..956d7340c774 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -216,10 +216,6 @@ static int DetectFilenameSetup (DetectEngineCtx *de_ctx, Signature *s, char *str SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto == ALPROTO_HTTP) { - AppLayerHtpNeedFileInspection(); - } - s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_FILENAME); return 0; diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 9aeae0c6f499..3f21745a32c9 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -289,10 +289,6 @@ static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *str SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - if (s->alproto == ALPROTO_HTTP) { - AppLayerHtpNeedFileInspection(); - } - s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_SIZE); SCReturnInt(0); diff --git a/src/detect-parse.c b/src/detect-parse.c index 3f6a7a6a8a4c..f78b6033c78b 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1421,13 +1421,18 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } #endif - if (((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0) && - s->alproto != ALPROTO_UNKNOWN && - !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto)) - { - SCLogError(SC_ERR_NO_FILES_FOR_PROTOCOL, "protocol %s doesn't " - "support file matching", AppProtoToString(s->alproto)); - SCReturnInt(0); + if ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0) { + if (s->alproto != ALPROTO_UNKNOWN && + !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto)) + { + SCLogError(SC_ERR_NO_FILES_FOR_PROTOCOL, "protocol %s doesn't " + "support file matching", AppProtoToString(s->alproto)); + SCReturnInt(0); + } + + if (s->alproto == ALPROTO_HTTP) { + AppLayerHtpNeedFileInspection(); + } } SCReturnInt(1); From 9030e89c946819a4b4850bdb95ffab27d9279c8c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Sep 2016 18:24:29 +0200 Subject: [PATCH 1641/2553] detect: don't set alproto while registering keyword The field is not used except for some printing, and is wrong for many keywords. --- src/detect-dce-iface.c | 1 - src/detect-dce-opnum.c | 1 - src/detect-dce-stub-data.c | 1 - src/detect-dns-query.c | 1 - src/detect-file-data.c | 1 - src/detect-fileext.c | 1 - src/detect-filemagic.c | 1 - src/detect-filemd5.c | 2 -- src/detect-filename.c | 1 - src/detect-filesize.c | 1 - src/detect-filestore.c | 1 - src/detect-ftpbounce.c | 1 - src/detect-http-client-body.c | 1 - src/detect-http-cookie.c | 1 - src/detect-http-header.c | 1 - src/detect-http-hh.c | 1 - src/detect-http-hrh.c | 1 - src/detect-http-method.c | 1 - src/detect-http-raw-header.c | 1 - src/detect-http-raw-uri.c | 1 - src/detect-http-server-body.c | 1 - src/detect-http-stat-code.c | 1 - src/detect-http-stat-msg.c | 1 - src/detect-http-ua.c | 1 - src/detect-http-uri.c | 1 - src/detect-modbus.c | 1 - src/detect-pcre.c | 1 - src/detect-pkt-data.c | 1 - src/detect-ssh-proto-version.c | 1 - src/detect-ssh-software-version.c | 1 - src/detect-ssl-state.c | 1 - src/detect-ssl-version.c | 1 - src/detect-template-buffer.c | 1 - src/detect-tls-sni.c | 1 - src/detect-tls-version.c | 1 - src/detect-tls.c | 4 ---- src/detect-uricontent.c | 1 - src/detect-urilen.c | 1 - 38 files changed, 42 deletions(-) diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 06ae77c1f644..6a712041ba4c 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -63,7 +63,6 @@ void DetectDceIfaceFree(void *); void DetectDceIfaceRegister(void) { sigmatch_table[DETECT_DCE_IFACE].name = "dce_iface"; - sigmatch_table[DETECT_DCE_IFACE].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_IFACE].Match = NULL; sigmatch_table[DETECT_DCE_IFACE].AppLayerMatch = DetectDceIfaceMatch; sigmatch_table[DETECT_DCE_IFACE].Setup = DetectDceIfaceSetup; diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index f25010893551..50544fd14b60 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -63,7 +63,6 @@ void DetectDceOpnumFree(void *); void DetectDceOpnumRegister(void) { sigmatch_table[DETECT_DCE_OPNUM].name = "dce_opnum"; - sigmatch_table[DETECT_DCE_OPNUM].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_OPNUM].Match = NULL; sigmatch_table[DETECT_DCE_OPNUM].AppLayerMatch = DetectDceOpnumMatch; sigmatch_table[DETECT_DCE_OPNUM].Setup = DetectDceOpnumSetup; diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index b3b6da859815..987a9b9fa3d8 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -59,7 +59,6 @@ static int DetectDceStubDataSetup(DetectEngineCtx *, Signature *, char *); void DetectDceStubDataRegister(void) { sigmatch_table[DETECT_DCE_STUB_DATA].name = "dce_stub_data"; - sigmatch_table[DETECT_DCE_STUB_DATA].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_STUB_DATA].Match = NULL; sigmatch_table[DETECT_DCE_STUB_DATA].AppLayerMatch = NULL; sigmatch_table[DETECT_DCE_STUB_DATA].Setup = DetectDceStubDataSetup; diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 33ffa31a96b9..9df43871545b 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -69,7 +69,6 @@ void DetectDnsQueryRegister (void) sigmatch_table[DETECT_AL_DNS_QUERY].desc = "content modifier to match specifically and only on the DNS query-buffer"; sigmatch_table[DETECT_AL_DNS_QUERY].Match = NULL; sigmatch_table[DETECT_AL_DNS_QUERY].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_DNS_QUERY].alproto = ALPROTO_DNS; sigmatch_table[DETECT_AL_DNS_QUERY].Setup = DetectDnsQuerySetup; sigmatch_table[DETECT_AL_DNS_QUERY].Free = NULL; sigmatch_table[DETECT_AL_DNS_QUERY].RegisterTests = DetectDnsQueryRegisterTests; diff --git a/src/detect-file-data.c b/src/detect-file-data.c index a5cb650788f6..b3e18ec1452b 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -55,7 +55,6 @@ void DetectFiledataRegister(void) sigmatch_table[DETECT_FILE_DATA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#file_data"; sigmatch_table[DETECT_FILE_DATA].Match = NULL; sigmatch_table[DETECT_FILE_DATA].AppLayerMatch = NULL; - sigmatch_table[DETECT_FILE_DATA].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILE_DATA].Setup = DetectFiledataSetup; sigmatch_table[DETECT_FILE_DATA].Free = NULL; sigmatch_table[DETECT_FILE_DATA].RegisterTests = DetectFiledataRegisterTests; diff --git a/src/detect-fileext.c b/src/detect-fileext.c index 73ce1d346e3e..4416d3787318 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -66,7 +66,6 @@ void DetectFileextRegister(void) sigmatch_table[DETECT_FILEEXT].desc = "match on the extension of a file name"; sigmatch_table[DETECT_FILEEXT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#fileext"; sigmatch_table[DETECT_FILEEXT].FileMatch = DetectFileextMatch; - sigmatch_table[DETECT_FILEEXT].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEEXT].Setup = DetectFileextSetup; sigmatch_table[DETECT_FILEEXT].Free = DetectFileextFree; sigmatch_table[DETECT_FILEEXT].RegisterTests = DetectFileextRegisterTests; diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 26a3b969ab91..76b0e0ce797f 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -69,7 +69,6 @@ void DetectFilemagicRegister(void) sigmatch_table[DETECT_FILEMAGIC].desc = "match on the information libmagic returns about a file"; sigmatch_table[DETECT_FILEMAGIC].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemagic"; sigmatch_table[DETECT_FILEMAGIC].FileMatch = DetectFilemagicMatch; - sigmatch_table[DETECT_FILEMAGIC].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetup; sigmatch_table[DETECT_FILEMAGIC].Free = DetectFilemagicFree; sigmatch_table[DETECT_FILEMAGIC].RegisterTests = DetectFilemagicRegisterTests; diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index 2e1988a630ad..18c46616396e 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -69,7 +69,6 @@ void DetectFileMd5Register(void) { sigmatch_table[DETECT_FILEMD5].name = "filemd5"; sigmatch_table[DETECT_FILEMD5].FileMatch = NULL; - sigmatch_table[DETECT_FILEMD5].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEMD5].Setup = DetectFileMd5SetupNoSupport; sigmatch_table[DETECT_FILEMD5].Free = NULL; sigmatch_table[DETECT_FILEMD5].RegisterTests = NULL; @@ -96,7 +95,6 @@ void DetectFileMd5Register(void) sigmatch_table[DETECT_FILEMD5].desc = "match file MD5 against list of MD5 checksums"; sigmatch_table[DETECT_FILEMD5].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemd5"; sigmatch_table[DETECT_FILEMD5].FileMatch = DetectFileMd5Match; - sigmatch_table[DETECT_FILEMD5].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEMD5].Setup = DetectFileMd5Setup; sigmatch_table[DETECT_FILEMD5].Free = DetectFileMd5Free; sigmatch_table[DETECT_FILEMD5].RegisterTests = DetectFileMd5RegisterTests; diff --git a/src/detect-filename.c b/src/detect-filename.c index 956d7340c774..638bb7439fb3 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -66,7 +66,6 @@ void DetectFilenameRegister(void) sigmatch_table[DETECT_FILENAME].desc = "match on the file name"; sigmatch_table[DETECT_FILENAME].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filename"; sigmatch_table[DETECT_FILENAME].FileMatch = DetectFilenameMatch; - sigmatch_table[DETECT_FILENAME].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILENAME].Setup = DetectFilenameSetup; sigmatch_table[DETECT_FILENAME].Free = DetectFilenameFree; sigmatch_table[DETECT_FILENAME].RegisterTests = DetectFilenameRegisterTests; diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 3f21745a32c9..416cb467849d 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -63,7 +63,6 @@ void DetectFilesizeRegister(void) sigmatch_table[DETECT_FILESIZE].name = "filesize"; sigmatch_table[DETECT_FILESIZE].desc = "match on the size of the file as it is being transferred"; sigmatch_table[DETECT_FILESIZE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filesize"; - sigmatch_table[DETECT_FILESIZE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILESIZE].FileMatch = DetectFilesizeMatch; sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup; sigmatch_table[DETECT_FILESIZE].Free = DetectFilesizeFree; diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 38c7ce2bfecc..84c8acc60c11 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -73,7 +73,6 @@ void DetectFilestoreRegister(void) sigmatch_table[DETECT_FILESTORE].desc = "stores files to disk if the rule matched"; sigmatch_table[DETECT_FILESTORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filestore"; sigmatch_table[DETECT_FILESTORE].FileMatch = DetectFilestoreMatch; - sigmatch_table[DETECT_FILESTORE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILESTORE].Setup = DetectFilestoreSetup; sigmatch_table[DETECT_FILESTORE].Free = DetectFilestoreFree; sigmatch_table[DETECT_FILESTORE].RegisterTests = NULL; diff --git a/src/detect-ftpbounce.c b/src/detect-ftpbounce.c index f4102089b397..f293ca970dcb 100644 --- a/src/detect-ftpbounce.c +++ b/src/detect-ftpbounce.c @@ -67,7 +67,6 @@ void DetectFtpbounceRegister(void) sigmatch_table[DETECT_FTPBOUNCE].Setup = DetectFtpbounceSetup; sigmatch_table[DETECT_FTPBOUNCE].Match = NULL; sigmatch_table[DETECT_FTPBOUNCE].AppLayerMatch = DetectFtpbounceALMatch; - sigmatch_table[DETECT_FTPBOUNCE].alproto = ALPROTO_FTP; sigmatch_table[DETECT_FTPBOUNCE].Free = NULL; sigmatch_table[DETECT_FTPBOUNCE].RegisterTests = DetectFtpbounceRegisterTests; sigmatch_table[DETECT_FTPBOUNCE].flags = SIGMATCH_NOOPT; diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 2813d4ca995d..24eb5175c981 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -74,7 +74,6 @@ void DetectHttpClientBodyRegister(void) sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Setup = DetectHttpClientBodySetup; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Free = DetectHttpClientBodyFree; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].RegisterTests = DetectHttpClientBodyRegisterTests; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_PAYLOAD ; diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index be08b2dc1f2a..d43098889243 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -74,7 +74,6 @@ void DetectHttpCookieRegister(void) sigmatch_table[DETECT_AL_HTTP_COOKIE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_cookie"; sigmatch_table[DETECT_AL_HTTP_COOKIE].Match = NULL; sigmatch_table[DETECT_AL_HTTP_COOKIE].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_COOKIE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_COOKIE].Setup = DetectHttpCookieSetup; sigmatch_table[DETECT_AL_HTTP_COOKIE].Free = DetectHttpCookieFree; sigmatch_table[DETECT_AL_HTTP_COOKIE].RegisterTests = DetectHttpCookieRegisterTests; diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 7d3e1a2d23e4..39474ed9c98a 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -76,7 +76,6 @@ void DetectHttpHeaderRegister(void) sigmatch_table[DETECT_AL_HTTP_HEADER].Setup = DetectHttpHeaderSetup; sigmatch_table[DETECT_AL_HTTP_HEADER].Free = DetectHttpHeaderFree; sigmatch_table[DETECT_AL_HTTP_HEADER].RegisterTests = DetectHttpHeaderRegisterTests; - sigmatch_table[DETECT_AL_HTTP_HEADER].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_PAYLOAD ; diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 859782f9f57c..4de340a14aee 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -74,7 +74,6 @@ void DetectHttpHHRegister(void) sigmatch_table[DETECT_AL_HTTP_HOST].Setup = DetectHttpHHSetup; sigmatch_table[DETECT_AL_HTTP_HOST].Free = DetectHttpHHFree; sigmatch_table[DETECT_AL_HTTP_HOST].RegisterTests = DetectHttpHHRegisterTests; - sigmatch_table[DETECT_AL_HTTP_HOST].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_PAYLOAD ; diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index 2663b306b222..cb6ee2cf442e 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -74,7 +74,6 @@ void DetectHttpHRHRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Setup = DetectHttpHRHSetup; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Free = DetectHttpHRHFree; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].RegisterTests = DetectHttpHRHRegisterTests; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_PAYLOAD ; diff --git a/src/detect-http-method.c b/src/detect-http-method.c index ee5291016c92..8fcaaef57fa6 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -74,7 +74,6 @@ void DetectHttpMethodRegister(void) sigmatch_table[DETECT_AL_HTTP_METHOD].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_method"; sigmatch_table[DETECT_AL_HTTP_METHOD].Match = NULL; sigmatch_table[DETECT_AL_HTTP_METHOD].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_METHOD].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_METHOD].Setup = DetectHttpMethodSetup; sigmatch_table[DETECT_AL_HTTP_METHOD].Free = DetectHttpMethodFree; sigmatch_table[DETECT_AL_HTTP_METHOD].RegisterTests = DetectHttpMethodRegisterTests; diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index 67b1fa7c7ad4..ad7effc0497a 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -74,7 +74,6 @@ void DetectHttpRawHeaderRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetup; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Free = DetectHttpRawHeaderFree; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].RegisterTests = DetectHttpRawHeaderRegisterTests; - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_PAYLOAD; diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 8c4a95044061..70eabd6c8aa7 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -67,7 +67,6 @@ void DetectHttpRawUriRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_uri-and-http_raw_uri"; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Match = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Setup = DetectHttpRawUriSetup; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Free = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].RegisterTests = DetectHttpRawUriRegisterTests; diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index c2b7a078df99..0f1cb2bbaa17 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -76,7 +76,6 @@ void DetectHttpServerBodyRegister(void) sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Setup = DetectHttpServerBodySetup; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Free = DetectHttpServerBodyFree; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].RegisterTests = DetectHttpServerBodyRegisterTests; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_PAYLOAD ; diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index f5b1bb7e6c3e..e0f1cb0efe0c 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -79,7 +79,6 @@ void DetectHttpStatCodeRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_CODE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_stat_code"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Match = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetup; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Free = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].RegisterTests = DetectHttpStatCodeRegisterTests; diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index 235764528665..5e6e8f002ca5 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -79,7 +79,6 @@ void DetectHttpStatMsgRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_MSG].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_stat_msg"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Match = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetup; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Free = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].RegisterTests = DetectHttpStatMsgRegisterTests; diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index 237b8f26e60d..2a1ac7b906f9 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -75,7 +75,6 @@ void DetectHttpUARegister(void) sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Setup = DetectHttpUASetup; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Free = DetectHttpUAFree; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].RegisterTests = DetectHttpUARegisterTests; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_PAYLOAD ; diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 9d005a9ce794..028459380d9a 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -68,7 +68,6 @@ void DetectHttpUriRegister (void) sigmatch_table[DETECT_AL_HTTP_URI].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_uri-and-http_raw_uri"; sigmatch_table[DETECT_AL_HTTP_URI].Match = NULL; sigmatch_table[DETECT_AL_HTTP_URI].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_URI].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_URI].Setup = DetectHttpUriSetup; sigmatch_table[DETECT_AL_HTTP_URI].Free = NULL; sigmatch_table[DETECT_AL_HTTP_URI].RegisterTests = DetectHttpUriRegisterTests; diff --git a/src/detect-modbus.c b/src/detect-modbus.c index f0cf9c6c85b9..fe585f6d121c 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -404,7 +404,6 @@ void DetectModbusRegister(void) sigmatch_table[DETECT_AL_MODBUS].name = "modbus"; sigmatch_table[DETECT_AL_MODBUS].Match = NULL; sigmatch_table[DETECT_AL_MODBUS].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_MODBUS].alproto = ALPROTO_MODBUS; sigmatch_table[DETECT_AL_MODBUS].Setup = DetectModbusSetup; sigmatch_table[DETECT_AL_MODBUS].Free = DetectModbusFree; sigmatch_table[DETECT_AL_MODBUS].RegisterTests = DetectModbusRegisterTests; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 72692ee0734a..ed8eb2300f13 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -86,7 +86,6 @@ void DetectPcreRegister (void) sigmatch_table[DETECT_PCRE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#Pcre-Perl-Compatible-Regular-Expressions"; sigmatch_table[DETECT_PCRE].Match = NULL; sigmatch_table[DETECT_PCRE].AppLayerMatch = NULL; - sigmatch_table[DETECT_PCRE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_PCRE].Setup = DetectPcreSetup; sigmatch_table[DETECT_PCRE].Free = DetectPcreFree; sigmatch_table[DETECT_PCRE].RegisterTests = DetectPcreRegisterTests; diff --git a/src/detect-pkt-data.c b/src/detect-pkt-data.c index fc04d3b21f93..7b4934bcc42f 100644 --- a/src/detect-pkt-data.c +++ b/src/detect-pkt-data.c @@ -54,7 +54,6 @@ void DetectPktDataRegister(void) sigmatch_table[DETECT_PKT_DATA].name = "pkt_data"; sigmatch_table[DETECT_PKT_DATA].Match = NULL; sigmatch_table[DETECT_PKT_DATA].AppLayerMatch = NULL; - sigmatch_table[DETECT_PKT_DATA].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_PKT_DATA].Setup = DetectPktDataSetup; sigmatch_table[DETECT_PKT_DATA].Free = NULL; sigmatch_table[DETECT_PKT_DATA].RegisterTests = DetectPktDataTestRegister; diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index abf86fe6fa9e..dca2e3588d28 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -75,7 +75,6 @@ void DetectSshVersionRegister(void) sigmatch_table[DETECT_AL_SSH_PROTOVERSION].name = "ssh.protoversion"; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Match = NULL; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].AppLayerMatch = DetectSshVersionMatch; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].alproto = ALPROTO_SSH; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Setup = DetectSshVersionSetup; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Free = DetectSshVersionFree; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].RegisterTests = DetectSshVersionRegisterTests; diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index ff45a7f6ab06..8ab0dbed5671 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -80,7 +80,6 @@ void DetectSshSoftwareVersionRegister(void) sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].name = "ssh.softwareversion"; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Match = NULL; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].AppLayerMatch = DetectSshSoftwareVersionMatch; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].alproto = ALPROTO_SSH; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Setup = DetectSshSoftwareVersionSetup; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Free = DetectSshSoftwareVersionFree; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].RegisterTests = DetectSshSoftwareVersionRegisterTests; diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 2e837f208d3a..1662a3b7b5f7 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -73,7 +73,6 @@ void DetectSslStateRegister(void) sigmatch_table[DETECT_AL_SSL_STATE].name = "ssl_state"; sigmatch_table[DETECT_AL_SSL_STATE].Match = NULL; sigmatch_table[DETECT_AL_SSL_STATE].AppLayerMatch = DetectSslStateMatch; - sigmatch_table[DETECT_AL_SSL_STATE].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_SSL_STATE].Setup = DetectSslStateSetup; sigmatch_table[DETECT_AL_SSL_STATE].Free = DetectSslStateFree; sigmatch_table[DETECT_AL_SSL_STATE].RegisterTests = DetectSslStateRegisterTests; diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index e5957c12118b..0c377ac86f52 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -74,7 +74,6 @@ void DetectSslVersionRegister(void) sigmatch_table[DETECT_AL_SSL_VERSION].name = "ssl_version"; sigmatch_table[DETECT_AL_SSL_VERSION].Match = NULL; sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerMatch = DetectSslVersionMatch; - sigmatch_table[DETECT_AL_SSL_VERSION].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_SSL_VERSION].Setup = DetectSslVersionSetup; sigmatch_table[DETECT_AL_SSL_VERSION].Free = DetectSslVersionFree; sigmatch_table[DETECT_AL_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests; diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index 01f676a41011..ffc89cf07884 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -48,7 +48,6 @@ void DetectTemplateBufferRegister(void) sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].name = "template_buffer"; sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].desc = "Template content modififier to match on the template buffers"; - sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].alproto = ALPROTO_TEMPLATE; sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].Setup = DetectTemplateBufferSetup; sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].RegisterTests = DetectTemplateBufferRegisterTests; diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index 31c001c1f70b..46c43e53e6bf 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -64,7 +64,6 @@ void DetectTlsSniRegister(void) sigmatch_table[DETECT_AL_TLS_SNI].desc = "content modifier to match specifically and only on the TLS SNI buffer"; sigmatch_table[DETECT_AL_TLS_SNI].Match = NULL; sigmatch_table[DETECT_AL_TLS_SNI].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_TLS_SNI].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_SNI].Setup = DetectTlsSniSetup; sigmatch_table[DETECT_AL_TLS_SNI].Free = NULL; sigmatch_table[DETECT_AL_TLS_SNI].RegisterTests = DetectTlsSniRegisterTests; diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index 745bedefca6b..6e185ef40e38 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -74,7 +74,6 @@ void DetectTlsVersionRegister (void) sigmatch_table[DETECT_AL_TLS_VERSION].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsversion"; sigmatch_table[DETECT_AL_TLS_VERSION].Match = NULL; sigmatch_table[DETECT_AL_TLS_VERSION].AppLayerMatch = DetectTlsVersionMatch; - sigmatch_table[DETECT_AL_TLS_VERSION].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_VERSION].Setup = DetectTlsVersionSetup; sigmatch_table[DETECT_AL_TLS_VERSION].Free = DetectTlsVersionFree; sigmatch_table[DETECT_AL_TLS_VERSION].RegisterTests = DetectTlsVersionRegisterTests; diff --git a/src/detect-tls.c b/src/detect-tls.c index b2ff99b613d9..6a0830a3dea5 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -98,7 +98,6 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_SUBJECT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlssubject"; sigmatch_table[DETECT_AL_TLS_SUBJECT].Match = NULL; sigmatch_table[DETECT_AL_TLS_SUBJECT].AppLayerMatch = DetectTlsSubjectMatch; - sigmatch_table[DETECT_AL_TLS_SUBJECT].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_SUBJECT].Setup = DetectTlsSubjectSetup; sigmatch_table[DETECT_AL_TLS_SUBJECT].Free = DetectTlsSubjectFree; sigmatch_table[DETECT_AL_TLS_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; @@ -108,7 +107,6 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_ISSUERDN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsissuerdn"; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Match = NULL; sigmatch_table[DETECT_AL_TLS_ISSUERDN].AppLayerMatch = DetectTlsIssuerDNMatch; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Setup = DetectTlsIssuerDNSetup; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Free = DetectTlsIssuerDNFree; sigmatch_table[DETECT_AL_TLS_ISSUERDN].RegisterTests = DetectTlsIssuerDNRegisterTests; @@ -118,7 +116,6 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_FINGERPRINT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsfingerprint"; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Match = NULL; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].AppLayerMatch = DetectTlsFingerprintMatch; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free = DetectTlsFingerprintFree; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].RegisterTests = NULL; @@ -128,7 +125,6 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_STORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsstore"; sigmatch_table[DETECT_AL_TLS_STORE].Match = NULL; sigmatch_table[DETECT_AL_TLS_STORE].AppLayerMatch = DetectTlsStoreMatch; - sigmatch_table[DETECT_AL_TLS_STORE].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_STORE].Setup = DetectTlsStoreSetup; sigmatch_table[DETECT_AL_TLS_STORE].Free = NULL; sigmatch_table[DETECT_AL_TLS_STORE].RegisterTests = NULL; diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index 2955dab0ff07..1ee13c6c03fc 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -76,7 +76,6 @@ void DetectUricontentRegister (void) sigmatch_table[DETECT_URICONTENT].Setup = DetectUricontentSetup; sigmatch_table[DETECT_URICONTENT].Free = DetectUricontentFree; sigmatch_table[DETECT_URICONTENT].RegisterTests = HttpUriRegisterTests; - sigmatch_table[DETECT_URICONTENT].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_URICONTENT].flags |= SIGMATCH_PAYLOAD; } diff --git a/src/detect-urilen.c b/src/detect-urilen.c index 8d69e34f154c..fbb454b136f7 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -63,7 +63,6 @@ void DetectUrilenRegister(void) sigmatch_table[DETECT_AL_URILEN].desc = "match on the length of the HTTP uri"; sigmatch_table[DETECT_AL_URILEN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#Urilen"; sigmatch_table[DETECT_AL_URILEN].Match = NULL; - sigmatch_table[DETECT_AL_URILEN].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_URILEN].AppLayerMatch = NULL /**< We handle this at detect-engine-uri.c now */; sigmatch_table[DETECT_AL_URILEN].Setup = DetectUrilenSetup; sigmatch_table[DETECT_AL_URILEN].Free = DetectUrilenFree; From e173016ded711e0bc26dee0dd013c8cb8a447a9a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Sep 2016 18:27:47 +0200 Subject: [PATCH 1642/2553] gitignore: update to hide more local files --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index b7fb466ca4bf..8faa686c0ef9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,10 @@ *.lo *.in *.[ch]e +*.log +*.rule +*.rules +*.yaml Makefile .deps/ .libs/ @@ -31,6 +35,10 @@ libhtp/stamp-h1 libhtp/test/TAGS libtool ltmain.sh +src/*.diff +src/*.patch +src/*.rej +src/*.orig src/TAGS src/suricata stamp-h1 From 99dce740ef3ab5bdeb0d5fc1c2fa6499a230132b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Sep 2016 18:29:18 +0200 Subject: [PATCH 1643/2553] detect: mark alproto in keyword reg deprecated No existing code uses it, and it had been useless for some time. --- src/detect.c | 6 +----- src/detect.h | 7 ++++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/detect.c b/src/detect.c index 7a779f3ae4ae..b1d1c6d5a7bc 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4204,8 +4204,6 @@ static inline void SigMultilinePrint(int i, char *prefix) if (sigmatch_table[i].desc) { printf("%sDescription: %s\n", prefix, sigmatch_table[i].desc); } - printf("%sProtocol: %s\n", prefix, - AppLayerGetProtoName(sigmatch_table[i].alproto)); printf("%sFeatures: ", prefix); PrintFeatureList(sigmatch_table[i].flags, ','); if (sigmatch_table[i].url) { @@ -4218,7 +4216,6 @@ void SigTableList(const char *keyword) { size_t size = sizeof(sigmatch_table) / sizeof(SigTableElmt); size_t i; - char *proto_name; if (keyword == NULL) { printf("=====Supported keywords=====\n"); @@ -4243,8 +4240,7 @@ void SigTableList(const char *keyword) printf("%s", sigmatch_table[i].desc); } /* Build feature */ - proto_name = AppLayerGetProtoName(sigmatch_table[i].alproto); - printf(";%s;", proto_name ? proto_name : "Unset"); + printf(";Unset;"); // this used to be alproto PrintFeatureList(sigmatch_table[i].flags, ':'); printf(";"); if (sigmatch_table[i].url) { diff --git a/src/detect.h b/src/detect.h index 4123922fac0b..807dcafc2cf3 100644 --- a/src/detect.h +++ b/src/detect.h @@ -889,9 +889,6 @@ typedef struct SigTableElmt_ { 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 *); @@ -899,6 +896,10 @@ typedef struct SigTableElmt_ { void (*RegisterTests)(void); uint8_t flags; + + /** unused: warn user. Will be removed in the future. */ + AppProto alproto __attribute__((deprecated)); + char *name; /**< keyword name alias */ char *alias; /**< name alias */ char *desc; From 637aa346109eefdc96131585cdb0a986336ab870 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 25 May 2016 23:32:48 -0600 Subject: [PATCH 1644/2553] logging: convert dns log to a non-thread module --- src/log-dnslog.c | 11 +----- src/log-httplog.c | 2 +- src/output-json-http.c | 2 +- src/output-json-smtp.c | 5 +-- src/output-tx.c | 82 +++++++++++++++++++++++++++++++---------- src/output-tx.h | 5 ++- src/output.c | 20 +++++++--- src/output.h | 9 ++++- src/runmodes.c | 25 +++++++++++-- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 11 files changed, 118 insertions(+), 45 deletions(-) diff --git a/src/log-dnslog.c b/src/log-dnslog.c index cfb0afccb7a5..5267175d5dd9 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -346,16 +346,9 @@ static OutputCtx *LogDnsLogInitCtx(ConfNode *conf) void TmModuleLogDnsLogRegister (void) { - tmm_modules[TMM_LOGDNSLOG].name = MODULE_NAME; - tmm_modules[TMM_LOGDNSLOG].ThreadInit = LogDnsLogThreadInit; - tmm_modules[TMM_LOGDNSLOG].ThreadExitPrintStats = LogDnsLogExitPrintStats; - tmm_modules[TMM_LOGDNSLOG].ThreadDeinit = LogDnsLogThreadDeinit; - tmm_modules[TMM_LOGDNSLOG].RegisterTests = NULL; - tmm_modules[TMM_LOGDNSLOG].cap_flags = 0; - tmm_modules[TMM_LOGDNSLOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterTxModule(MODULE_NAME, "dns-log", LogDnsLogInitCtx, - ALPROTO_DNS, LogDnsLogger); + ALPROTO_DNS, LogDnsLogger, LogDnsLogThreadInit, LogDnsLogThreadDeinit, + LogDnsLogExitPrintStats); /* enable the logger for the app layer */ SCLogDebug("registered %s", MODULE_NAME); diff --git a/src/log-httplog.c b/src/log-httplog.c index e77e79031be6..04db70a43de1 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -74,7 +74,7 @@ void TmModuleLogHttpLogRegister (void) tmm_modules[TMM_LOGHTTPLOG].flags = TM_FLAG_LOGAPI_TM; OutputRegisterTxModule(MODULE_NAME, "http-log", LogHttpLogInitCtx, - ALPROTO_HTTP, LogHttpLogger); + ALPROTO_HTTP, LogHttpLogger, NULL, NULL, NULL); } #define LOG_HTTP_MAXN_NODES 64 diff --git a/src/output-json-http.c b/src/output-json-http.c index d41874909333..2a10c4fe934a 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -593,7 +593,7 @@ void TmModuleJsonHttpLogRegister (void) /* register as separate module */ OutputRegisterTxModule("JsonHttpLog", "http-json-log", OutputHttpLogInit, - ALPROTO_HTTP, JsonHttpLogger); + ALPROTO_HTTP, JsonHttpLogger, NULL, NULL, NULL); /* also register as child of eve-log */ OutputRegisterTxSubModule("eve-log", "JsonHttpLog", "eve-log.http", OutputHttpLogInitSub, diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index fd9683b920b9..37be7c1cd8c0 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -266,9 +266,8 @@ void TmModuleJsonSmtpLogRegister (void) { tmm_modules[TMM_JSONSMTPLOG].flags = TM_FLAG_LOGAPI_TM; /* register as separate module */ - OutputRegisterTxModule("JsonSmtpLog", "smtp-json-log", - OutputSmtpLogInit, ALPROTO_SMTP, - JsonSmtpLogger); + OutputRegisterTxModule("JsonSmtpLog", "smtp-json-log", OutputSmtpLogInit, + ALPROTO_SMTP, JsonSmtpLogger, NULL, NULL, NULL); /* also register as child of eve-log */ OutputRegisterTxSubModule("eve-log", "JsonSmtpLog", diff --git a/src/output-tx.c b/src/output-tx.c index 311cc70f43fc..6250a996ffe3 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -55,17 +55,25 @@ typedef struct OutputTxLogger_ { uint32_t id; int tc_log_progress; int ts_log_progress; + TmEcode (*ThreadInit)(ThreadVars *, void *, void **); + TmEcode (*ThreadDeinit)(ThreadVars *, void *); + void (*ThreadExitPrintStats)(ThreadVars *, void *); } OutputTxLogger; static OutputTxLogger *list = NULL; int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *output_ctx, int tc_log_progress, - int ts_log_progress, TxLoggerCondition LogCondition) + int ts_log_progress, TxLoggerCondition LogCondition, + TmEcode (*ThreadInit)(ThreadVars *, void *, void **), + TmEcode (*ThreadDeinit)(ThreadVars *, void *), + void (*ThreadExitPrintStats)(ThreadVars *, void *)) { +#if 0 int module_id = TmModuleGetIdByName(name); if (module_id < 0) return -1; +#endif if (!(AppLayerParserIsTxAware(alproto))) { SCLogNotice("%s logger not enabled: protocol %s is disabled", @@ -83,7 +91,12 @@ int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, op->LogCondition = LogCondition; op->output_ctx = output_ctx; op->name = name; +#if 0 op->module_id = (TmmId) module_id; +#endif + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; if (tc_log_progress < 0) { op->tc_log_progress = @@ -260,16 +273,29 @@ static TmEcode OutputTxLogThreadInit(ThreadVars *tv, void *initdata, void **data OutputTxLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, + + TmEcode (*ThreadInit)(ThreadVars *, void *, void **) = NULL; + + if (logger->ThreadInit) { + SCLogNotice("Logger %s has ThreadInit.", logger->name); + ThreadInit = logger->ThreadInit; + } else { + SCLogNotice("Logger %s DOES NOT have ThreadInit.", logger->name); + } + + if (ThreadInit == NULL) { + TmModule *tm_module = TmModuleGetByName((char *)logger->name); + if (tm_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); + } + ThreadInit = tm_module->ThreadInit; } - if (tm_module->ThreadInit) { + if (ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -303,15 +329,24 @@ static TmEcode OutputTxLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputTxLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, + TmEcode (*ThreadDeinit)(ThreadVars *, void *) = NULL; + + if (logger->ThreadDeinit) { + ThreadDeinit = logger->ThreadDeinit; + } + + if (ThreadDeinit == NULL) { + TmModule *tm_module = TmModuleGetByName((char *)logger->name); + if (tm_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); + } + ThreadDeinit = tm_module->ThreadDeinit; } - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (ThreadDeinit) { + ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -331,15 +366,24 @@ static void OutputTxLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputTxLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, + void (*ThreadExitPrintStats)(ThreadVars *, void *) = NULL; + + if (logger->ThreadExitPrintStats) { + ThreadExitPrintStats = logger->ThreadExitPrintStats; + } + + if (ThreadExitPrintStats == NULL) { + TmModule *tm_module = TmModuleGetByName((char *)logger->name); + if (tm_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); + } + ThreadExitPrintStats = tm_module->ThreadExitPrintStats; } - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (ThreadExitPrintStats) { + ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; diff --git a/src/output-tx.h b/src/output-tx.h index e73c305ce64b..ee2e8a77c83e 100644 --- a/src/output-tx.h +++ b/src/output-tx.h @@ -38,7 +38,10 @@ typedef int (*TxLoggerCondition)(ThreadVars *, const Packet *, void *state, void int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *, int tc_log_progress, int ts_log_progress, - TxLoggerCondition LogCondition); + TxLoggerCondition LogCondition, + TmEcode (*ThreadInit)(ThreadVars *, void *, void **), + TmEcode (*ThreadDeinit)(ThreadVars *, void *), + void (*ThreadExitPrintStats)(ThreadVars *, void *)); void TmModuleTxLoggerRegister (void); diff --git a/src/output.c b/src/output.c index 64b6702be211..c9bc2201095b 100644 --- a/src/output.c +++ b/src/output.c @@ -159,7 +159,10 @@ OutputRegisterPacketSubModule(const char *parent_name, const char *name, void OutputRegisterTxModuleWrapper(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, - TxLoggerCondition TxLogCondition) + TxLoggerCondition TxLogCondition, + TmEcode (*ThreadInit)(ThreadVars *t, void *, void **), + TmEcode (*ThreadDeinit)(ThreadVars *t, void *), + void (*ThreadExitPrintStats)(ThreadVars *, void *)) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -178,6 +181,9 @@ void OutputRegisterTxModuleWrapper(const char *name, const char *conf_name, module->alproto = alproto; module->tc_log_progress = tc_log_progress; module->ts_log_progress = ts_log_progress; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Tx logger \"%s\" registered.", name); @@ -233,7 +239,8 @@ void OutputRegisterTxModuleWithCondition(const char *name, const char *conf_name TxLogger TxLogFunc, TxLoggerCondition TxLogCondition) { OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, - TxLogFunc, -1, -1, TxLogCondition); + TxLogFunc, -1, -1, TxLogCondition, NULL, NULL, + NULL); } void OutputRegisterTxSubModuleWithCondition(const char *parent_name, @@ -260,7 +267,7 @@ void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, { OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, TxLogFunc, tc_log_progress, ts_log_progress, - NULL); + NULL, NULL, NULL, NULL); } void OutputRegisterTxSubModuleWithProgress(const char *parent_name, @@ -284,10 +291,13 @@ void OutputRegisterTxSubModuleWithProgress(const char *parent_name, void OutputRegisterTxModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc) + TxLogger TxLogFunc, TmEcode (*ThreadInit)(ThreadVars *, void *, void **), + TmEcode (*ThreadDeinit)(ThreadVars *, void *), + void (*ThreadExitPrintStats)(ThreadVars *, void *)) { OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, - TxLogFunc, -1, -1, NULL); + TxLogFunc, -1, -1, NULL, ThreadInit, + ThreadDeinit, ThreadExitPrintStats); } void diff --git a/src/output.h b/src/output.h index 00425bf94f93..33e92a04def6 100644 --- a/src/output.h +++ b/src/output.h @@ -45,6 +45,10 @@ typedef struct OutputModule_ { OutputCtx *(*InitFunc)(ConfNode *); OutputCtx *(*InitSubFunc)(ConfNode *, OutputCtx *parent_ctx); + TmEcode (*ThreadInit)(ThreadVars *, void *, void **); + TmEcode (*ThreadDeinit)(ThreadVars *, void *); + void (*ThreadExitPrintStats)(ThreadVars *, void *); + PacketLogger PacketLogFunc; PacketLogCondition PacketConditionFunc; TxLogger TxLogFunc; @@ -76,7 +80,10 @@ void OutputRegisterPacketSubModule(const char *parent_name, const char *name, void OutputRegisterTxModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc); + TxLogger TxLogFunc, TmEcode (*ThreadInit)(ThreadVars *t, void *, void **), + TmEcode (*ThreadDeinit)(ThreadVars *t, void *), + void (*ThreadExitPrintStats)(ThreadVars *, void *)); + void OutputRegisterTxSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc); diff --git a/src/runmodes.c b/src/runmodes.c index f9bc02938bb7..f761caab90b1 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -106,7 +106,10 @@ static char *active_runmode; /* free list for our outputs */ typedef struct OutputFreeList_ { +#if 0 TmModule *tm_module; +#endif + OutputModule *output_module; OutputCtx *output_ctx; TAILQ_ENTRY(OutputFreeList_) entries; @@ -466,7 +469,11 @@ void RunOutputFreeList(void) { OutputFreeList *output; while ((output = TAILQ_FIRST(&output_free_list))) { - SCLogDebug("output %s %p %p", output->tm_module->name, output, output->output_ctx); +#if 0 + SCLogNotice("output %s %p %p", output->tm_module->name, output, output->output_ctx); +#endif + SCLogDebug("output %s %p %p", output->output_module->name, output, + output->output_ctx); if (output->output_ctx != NULL && output->output_ctx->DeInit != NULL) output->output_ctx->DeInit(output->output_ctx); @@ -528,16 +535,21 @@ void RunModeShutDown(void) * the output ctx at shutdown and unix socket reload */ static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx) { +#if 0 TmModule *tm_module = TmModuleGetByName(module->name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "TmModuleGetByName for %s failed", module->name); exit(EXIT_FAILURE); } +#endif OutputFreeList *fl_output = SCCalloc(1, sizeof(OutputFreeList)); if (unlikely(fl_output == NULL)) return; +#if 0 fl_output->tm_module = tm_module; +#endif + fl_output->output_module = module; fl_output->output_ctx = output_ctx; TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries); } @@ -582,14 +594,17 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu return; } +#if 0 TmModule *tm_module = TmModuleGetByName(module->name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "TmModuleGetByName for %s failed", module->name); exit(EXIT_FAILURE); } - if (strcmp(tmm_modules[TMM_ALERTDEBUGLOG].name, tm_module->name) == 0) + /* XXX What to do here? */ + if (tm_module != NULL && strcmp(tmm_modules[TMM_ALERTDEBUGLOG].name, tm_module->name) == 0) debuglog_enabled = 1; +#endif if (module->PacketLogFunc) { SCLogDebug("%s is a packet logger", module->name); @@ -618,7 +633,9 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu SCLogDebug("%s is a tx logger", module->name); OutputRegisterTxLogger(module->name, module->alproto, module->TxLogFunc, output_ctx, module->tc_log_progress, - module->ts_log_progress, module->TxLogCondition); + module->ts_log_progress, module->TxLogCondition, + module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); /* need one instance of the tx logger module */ if (tx_logger_module == NULL) { @@ -712,7 +729,9 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu if (unlikely(runmode_output == NULL)) return; runmode_output->name = module->name; +#if 0 runmode_output->tm_module = tm_module; +#endif runmode_output->output_ctx = output_ctx; InsertInRunModeOutputs(runmode_output); } diff --git a/src/tm-modules.c b/src/tm-modules.c index 924ff867c91a..d104afba2de3 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -218,7 +218,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_ALERTSYSLOG); CASE_CODE (TMM_LOGDROPLOG); CASE_CODE (TMM_RESPONDREJECT); - CASE_CODE (TMM_LOGDNSLOG); CASE_CODE (TMM_LOGHTTPLOG); CASE_CODE (TMM_LOGTLSLOG); CASE_CODE (TMM_LOGTCPDATALOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index ee7e92205b78..8c9c98fe8eee 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -48,7 +48,6 @@ typedef enum { TMM_ALERTSYSLOG, TMM_LOGDROPLOG, TMM_RESPONDREJECT, - TMM_LOGDNSLOG, TMM_LOGHTTPLOG, TMM_LOGTLSLOG, TMM_LOGTCPDATALOG, From b1200dba54053cf9faccf080ff2f3e759acc9cc1 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 26 May 2016 10:45:55 -0600 Subject: [PATCH 1645/2553] logging: convert fast log to a non-thread module --- src/alert-debuglog.c | 2 +- src/alert-fastlog.c | 14 ++++------- src/alert-syslog.c | 2 +- src/alert-unified2-alert.c | 2 +- src/log-droplog.c | 2 +- src/output-json-alert.c | 2 +- src/output-json-drop.c | 2 +- src/output-json-ssh.c | 2 +- src/output-packet.c | 48 ++++++++++++++++---------------------- src/output-packet.h | 3 ++- src/output-tx.c | 4 ++-- src/output-tx.h | 3 +-- src/output.c | 7 +++++- src/output.h | 3 ++- src/runmodes.c | 5 ++-- src/tm-modules.c | 1 - src/tm-modules.h | 4 ++++ src/tm-threads-common.h | 1 - 18 files changed, 51 insertions(+), 56 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index e939df3ed013..212e90c16161 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -522,5 +522,5 @@ void TmModuleAlertDebugLogRegister (void) tmm_modules[TMM_ALERTDEBUGLOG].flags = TM_FLAG_LOGAPI_TM; OutputRegisterPacketModule(MODULE_NAME, "alert-debug", - AlertDebugLogInitCtx, AlertDebugLogLogger, AlertDebugLogCondition); + AlertDebugLogInitCtx, AlertDebugLogLogger, AlertDebugLogCondition, NULL, NULL, NULL); } diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index cf7875bf642c..59ff045e02af 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -78,16 +78,10 @@ int AlertFastLogger(ThreadVars *tv, void *data, const Packet *p); void TmModuleAlertFastLogRegister (void) { - tmm_modules[TMM_ALERTFASTLOG].name = MODULE_NAME; - tmm_modules[TMM_ALERTFASTLOG].ThreadInit = AlertFastLogThreadInit; - tmm_modules[TMM_ALERTFASTLOG].ThreadExitPrintStats = AlertFastLogExitPrintStats; - tmm_modules[TMM_ALERTFASTLOG].ThreadDeinit = AlertFastLogThreadDeinit; - tmm_modules[TMM_ALERTFASTLOG].RegisterTests = AlertFastLogRegisterTests; - tmm_modules[TMM_ALERTFASTLOG].cap_flags = 0; - tmm_modules[TMM_ALERTFASTLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule(MODULE_NAME, "fast", - AlertFastLogInitCtx, AlertFastLogger, AlertFastLogCondition); + OutputRegisterPacketModule(MODULE_NAME, "fast", AlertFastLogInitCtx, + AlertFastLogger, AlertFastLogCondition, AlertFastLogThreadInit, + AlertFastLogThreadDeinit, AlertFastLogExitPrintStats); + AlertFastLogRegisterTests(); } typedef struct AlertFastLogThread_ { diff --git a/src/alert-syslog.c b/src/alert-syslog.c index 13151dd99027..2dd541b66bb4 100644 --- a/src/alert-syslog.c +++ b/src/alert-syslog.c @@ -421,7 +421,7 @@ void TmModuleAlertSyslogRegister (void) tmm_modules[TMM_ALERTSYSLOG].flags = TM_FLAG_LOGAPI_TM; OutputRegisterPacketModule(MODULE_NAME, "syslog", - AlertSyslogInitCtx, AlertSyslogLogger, AlertSyslogCondition); + AlertSyslogInitCtx, AlertSyslogLogger, AlertSyslogCondition, NULL, NULL, NULL); #endif /* !OS_WIN32 */ } diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 557ec5d166b8..8619f5a2a50d 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -245,7 +245,7 @@ void TmModuleUnified2AlertRegister(void) //OutputRegisterModule(MODULE_NAME, "unified2-alert", Unified2AlertInitCtx); OutputRegisterPacketModule(MODULE_NAME, "unified2-alert", - Unified2AlertInitCtx, Unified2Logger, Unified2Condition); + Unified2AlertInitCtx, Unified2Logger, Unified2Condition, NULL, NULL, NULL); } /** diff --git a/src/log-droplog.c b/src/log-droplog.c index 724d65840ce1..0b466b6a48ed 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -506,5 +506,5 @@ void TmModuleLogDropLogRegister (void) tmm_modules[TMM_LOGDROPLOG].flags = TM_FLAG_LOGAPI_TM; OutputRegisterPacketModule(MODULE_NAME, "drop", LogDropLogInitCtx, - LogDropLogger, LogDropCondition); + LogDropLogger, LogDropCondition, NULL, NULL, NULL); } diff --git a/src/output-json-alert.c b/src/output-json-alert.c index e785337e9f9f..56567ce2066c 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -748,7 +748,7 @@ void TmModuleJsonAlertLogRegister (void) tmm_modules[TMM_JSONALERTLOG].flags = TM_FLAG_LOGAPI_TM; OutputRegisterPacketModule(MODULE_NAME, "alert-json-log", - JsonAlertLogInitCtx, JsonAlertLogger, JsonAlertLogCondition); + JsonAlertLogInitCtx, JsonAlertLogger, JsonAlertLogCondition, NULL, NULL, NULL); OutputRegisterPacketSubModule("eve-log", MODULE_NAME, "eve-log.alert", JsonAlertLogInitCtxSub, JsonAlertLogger, JsonAlertLogCondition); } diff --git a/src/output-json-drop.c b/src/output-json-drop.c index fd7f513ead0f..fee5845f72b0 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -436,7 +436,7 @@ void TmModuleJsonDropLogRegister (void) tmm_modules[TMM_JSONDROPLOG].flags = TM_FLAG_LOGAPI_TM; OutputRegisterPacketModule(MODULE_NAME, "drop-json-log", - JsonDropLogInitCtx, JsonDropLogger, JsonDropLogCondition); + JsonDropLogInitCtx, JsonDropLogger, JsonDropLogCondition, NULL, NULL, NULL); OutputRegisterPacketSubModule("eve-log", MODULE_NAME, "eve-log.drop", JsonDropLogInitCtxSub, JsonDropLogger, JsonDropLogCondition); } diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 94853c87b055..ff626666c237 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -325,7 +325,7 @@ void TmModuleJsonSshLogRegister (void) /* register as separate module */ OutputRegisterPacketModule("JsonSshLog", "ssh-json-log", OutputSshLogInit, - JsonSshLogger, JsonSshCondition); + JsonSshLogger, JsonSshCondition, NULL, NULL, NULL); /* also register as child of eve-log */ OutputRegisterPacketSubModule("eve-log", "JsonSshLog", "eve-log.ssh", OutputSshLogInitSub, diff --git a/src/output-packet.c b/src/output-packet.c index 7e2b550b1157..376b2cd51f36 100644 --- a/src/output-packet.c +++ b/src/output-packet.c @@ -49,15 +49,23 @@ typedef struct OutputPacketLogger_ { struct OutputPacketLogger_ *next; const char *name; TmmId module_id; + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; } OutputPacketLogger; static OutputPacketLogger *list = NULL; -int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, PacketLogCondition ConditionFunc, OutputCtx *output_ctx) +int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, + PacketLogCondition ConditionFunc, OutputCtx *output_ctx, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { +#if 0 int module_id = TmModuleGetIdByName(name); if (module_id < 0) return -1; +#endif OutputPacketLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) @@ -68,7 +76,12 @@ int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, PacketLog op->ConditionFunc = ConditionFunc; op->output_ctx = output_ctx; op->name = name; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; +#if 0 op->module_id = (TmmId) module_id; +#endif if (list == NULL) list = op; @@ -131,16 +144,9 @@ static TmEcode OutputPacketLogThreadInit(ThreadVars *tv, void *initdata, void ** OutputPacketLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -174,15 +180,8 @@ static TmEcode OutputPacketLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputPacketLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -203,15 +202,8 @@ static void OutputPacketLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputPacketLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; diff --git a/src/output-packet.h b/src/output-packet.h index 5ae1adf8e487..431c441b11c7 100644 --- a/src/output-packet.h +++ b/src/output-packet.h @@ -37,7 +37,8 @@ typedef int (*PacketLogger)(ThreadVars *, void *thread_data, const Packet *); typedef int (*PacketLogCondition)(ThreadVars *, const Packet *); int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, - PacketLogCondition ConditionFunc, OutputCtx *); + PacketLogCondition ConditionFunc, OutputCtx *, ThreadInitFunc, + ThreadDeinitFunc, ThreadExitPrintStatsFunc); void TmModulePacketLoggerRegister (void); diff --git a/src/output-tx.c b/src/output-tx.c index 6250a996ffe3..24a5cff94145 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -65,8 +65,8 @@ static OutputTxLogger *list = NULL; int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *output_ctx, int tc_log_progress, int ts_log_progress, TxLoggerCondition LogCondition, - TmEcode (*ThreadInit)(ThreadVars *, void *, void **), - TmEcode (*ThreadDeinit)(ThreadVars *, void *), + ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, void (*ThreadExitPrintStats)(ThreadVars *, void *)) { #if 0 diff --git a/src/output-tx.h b/src/output-tx.h index ee2e8a77c83e..53f563aca2a5 100644 --- a/src/output-tx.h +++ b/src/output-tx.h @@ -39,8 +39,7 @@ typedef int (*TxLoggerCondition)(ThreadVars *, const Packet *, void *state, void int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *, int tc_log_progress, int ts_log_progress, TxLoggerCondition LogCondition, - TmEcode (*ThreadInit)(ThreadVars *, void *, void **), - TmEcode (*ThreadDeinit)(ThreadVars *, void *), + ThreadInitFunc, ThreadDeinitFunc, void (*ThreadExitPrintStats)(ThreadVars *, void *)); void TmModuleTxLoggerRegister (void); diff --git a/src/output.c b/src/output.c index c9bc2201095b..b3d5c4487818 100644 --- a/src/output.c +++ b/src/output.c @@ -86,7 +86,9 @@ OutputRegisterModule(const char *name, const char *conf_name, void OutputRegisterPacketModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), - PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc) + PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(PacketLogFunc == NULL || PacketConditionFunc == NULL)) { goto error; @@ -102,6 +104,9 @@ OutputRegisterPacketModule(const char *name, const char *conf_name, module->InitFunc = InitFunc; module->PacketLogFunc = PacketLogFunc; module->PacketConditionFunc = PacketConditionFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Packet logger \"%s\" registered.", name); diff --git a/src/output.h b/src/output.h index 33e92a04def6..232db0edcf54 100644 --- a/src/output.h +++ b/src/output.h @@ -73,7 +73,8 @@ void OutputRegisterModule(const char *, const char *, OutputCtx *(*)(ConfNode *) void OutputRegisterPacketModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), - PacketLogger LogFunc, PacketLogCondition ConditionFunc); + PacketLogger LogFunc, PacketLogCondition ConditionFunc, + ThreadInitFunc, ThreadDeinitFunc, ThreadExitPrintStatsFunc); void OutputRegisterPacketSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), PacketLogger LogFunc, PacketLogCondition ConditionFunc); diff --git a/src/runmodes.c b/src/runmodes.c index f761caab90b1..78f73aa22b32 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -607,9 +607,10 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu #endif if (module->PacketLogFunc) { - SCLogDebug("%s is a packet logger", module->name); + SCLogNotice("%s is a packet logger", module->name); OutputRegisterPacketLogger(module->name, module->PacketLogFunc, - module->PacketConditionFunc, output_ctx); + module->PacketConditionFunc, output_ctx, module->ThreadInit, + module->ThreadDeinit, module->ThreadExitPrintStats); /* need one instance of the packet logger module */ if (pkt_logger_module == NULL) { diff --git a/src/tm-modules.c b/src/tm-modules.c index d104afba2de3..5879d3d44396 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -211,7 +211,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_DECODEPCAPFILE); CASE_CODE (TMM_RECEIVEPFRING); CASE_CODE (TMM_DECODEPFRING); - CASE_CODE (TMM_ALERTFASTLOG); CASE_CODE (TMM_ALERTUNIFIED2ALERT); CASE_CODE (TMM_ALERTPRELUDE); CASE_CODE (TMM_ALERTDEBUGLOG); diff --git a/src/tm-modules.h b/src/tm-modules.h index 3486ebf04af4..e85aa76908e2 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -36,6 +36,10 @@ #define TM_FLAG_MANAGEMENT_TM 0x20 #define TM_FLAG_COMMAND_TM 0x40 +typedef TmEcode (*ThreadInitFunc)(ThreadVars *, void *, void **); +typedef TmEcode (*ThreadDeinitFunc)(ThreadVars *, void *); +typedef void (*ThreadExitPrintStatsFunc)(ThreadVars *, void *); + typedef struct TmModule_ { char *name; diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 8c9c98fe8eee..d1bc75391d3d 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -41,7 +41,6 @@ typedef enum { TMM_DECODEPCAPFILE, TMM_RECEIVEPFRING, TMM_DECODEPFRING, - TMM_ALERTFASTLOG, TMM_ALERTUNIFIED2ALERT, TMM_ALERTPRELUDE, TMM_ALERTDEBUGLOG, From 687602c0ca2517f6e1c74f3d1b36aa494f085dce Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 26 May 2016 22:26:04 -0600 Subject: [PATCH 1646/2553] logging: convert eve dns logging to non-thread module --- src/log-tlslog.c | 3 +- src/output-json-dns.c | 28 ++++++------------ src/output-json-http.c | 4 +-- src/output-json-smtp.c | 6 ++-- src/output-json-template.c | 3 +- src/output-json-tls.c | 4 +-- src/output-tx.c | 58 ++------------------------------------ src/output.c | 47 +++++++++++++++++++----------- src/output.h | 23 ++++++++++----- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 11 files changed, 69 insertions(+), 109 deletions(-) diff --git a/src/log-tlslog.c b/src/log-tlslog.c index c5fb14642d8a..d0274f222a54 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -323,5 +323,6 @@ void TmModuleLogTlsLogRegister(void) tmm_modules[TMM_LOGTLSLOG].flags = TM_FLAG_LOGAPI_TM; OutputRegisterTxModuleWithProgress(MODULE_NAME, "tls-log", LogTlsLogInitCtx, - ALPROTO_TLS, LogTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE); + ALPROTO_TLS, LogTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, + NULL, NULL, NULL); } diff --git a/src/output-json-dns.c b/src/output-json-dns.c index daa545ee0114..228d575b5d95 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -851,42 +851,32 @@ static OutputCtx *JsonDnsLogInitCtx(ConfNode *conf) #define MODULE_NAME "JsonDnsLog" void TmModuleJsonDnsLogRegister (void) { - tmm_modules[TMM_JSONDNSLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONDNSLOG].ThreadInit = LogDnsLogThreadInit; - tmm_modules[TMM_JSONDNSLOG].ThreadDeinit = LogDnsLogThreadDeinit; - tmm_modules[TMM_JSONDNSLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONDNSLOG].cap_flags = 0; - tmm_modules[TMM_JSONDNSLOG].flags = TM_FLAG_LOGAPI_TM; - /* Logger for requests. */ OutputRegisterTxModuleWithProgress(MODULE_NAME, "dns-json-log", - JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToServer, 0, 1); + JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToServer, 0, 1, + LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); /* Logger for replies. */ OutputRegisterTxModuleWithProgress(MODULE_NAME, "dns-json-log", - JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToClient, 1, 1); + JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToClient, 1, 1, + LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); /* Sub-logger for requests. */ OutputRegisterTxSubModuleWithProgress("eve-log", MODULE_NAME, "eve-log.dns", - JsonDnsLogInitCtxSub, ALPROTO_DNS, JsonDnsLoggerToServer, 0, 1); + JsonDnsLogInitCtxSub, ALPROTO_DNS, JsonDnsLoggerToServer, 0, 1, + LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); /* Sub-logger for replies. */ OutputRegisterTxSubModuleWithProgress("eve-log", MODULE_NAME, "eve-log.dns", - JsonDnsLogInitCtxSub, ALPROTO_DNS, JsonDnsLoggerToClient, 1, 1); + JsonDnsLogInitCtxSub, ALPROTO_DNS, JsonDnsLoggerToClient, 1, 1, + LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonDnsLogRegister (void) { - tmm_modules[TMM_JSONDNSLOG].name = "JsonDnsLog"; - tmm_modules[TMM_JSONDNSLOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-http.c b/src/output-json-http.c index 2a10c4fe934a..1ded557892f2 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -596,8 +596,8 @@ void TmModuleJsonHttpLogRegister (void) ALPROTO_HTTP, JsonHttpLogger, NULL, NULL, NULL); /* also register as child of eve-log */ - OutputRegisterTxSubModule("eve-log", "JsonHttpLog", "eve-log.http", OutputHttpLogInitSub, - ALPROTO_HTTP, JsonHttpLogger); + OutputRegisterTxSubModule("eve-log", "JsonHttpLog", "eve-log.http", + OutputHttpLogInitSub, ALPROTO_HTTP, JsonHttpLogger, NULL, NULL, NULL); } #else diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 37be7c1cd8c0..1a9a46fbde83 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -270,10 +270,8 @@ void TmModuleJsonSmtpLogRegister (void) { ALPROTO_SMTP, JsonSmtpLogger, NULL, NULL, NULL); /* also register as child of eve-log */ - OutputRegisterTxSubModule("eve-log", "JsonSmtpLog", - "eve-log.smtp", - OutputSmtpLogInitSub, ALPROTO_SMTP, - JsonSmtpLogger); + OutputRegisterTxSubModule("eve-log", "JsonSmtpLog", "eve-log.smtp", + OutputSmtpLogInitSub, ALPROTO_SMTP, JsonSmtpLogger, NULL, NULL, NULL); } #else diff --git a/src/output-json-template.c b/src/output-json-template.c index d096d730041b..ca49f81ecdd6 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -206,7 +206,8 @@ void TmModuleJsonTemplateLogRegister(void) /* Register as an eve sub-module. */ OutputRegisterTxSubModule("eve-log", "JsonTemplateLog", "eve-log.template", - OutputTemplateLogInitSub, ALPROTO_TEMPLATE, JsonTemplateLogger); + OutputTemplateLogInitSub, ALPROTO_TEMPLATE, JsonTemplateLogger, NULL, + NULL, NULL); SCLogNotice("Template JSON logger registered."); } diff --git a/src/output-json-tls.c b/src/output-json-tls.c index a7512a097c23..4b0f2a0463f2 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -320,12 +320,12 @@ void TmModuleJsonTlsLogRegister (void) /* register as separate module */ OutputRegisterTxModuleWithProgress("JsonTlsLog", "tls-json-log", OutputTlsLogInit, ALPROTO_TLS, JsonTlsLogger, TLS_HANDSHAKE_DONE, - TLS_HANDSHAKE_DONE); + TLS_HANDSHAKE_DONE, NULL, NULL, NULL); /* also register as child of eve-log */ OutputRegisterTxSubModuleWithProgress("eve-log", "JsonTlsLog", "eve-log.tls", OutputTlsLogInitSub, ALPROTO_TLS, JsonTlsLogger, - TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE); + TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, NULL, NULL, NULL); } #else diff --git a/src/output-tx.c b/src/output-tx.c index 24a5cff94145..4a7934aad1ca 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -273,29 +273,9 @@ static TmEcode OutputTxLogThreadInit(ThreadVars *tv, void *initdata, void **data OutputTxLogger *logger = list; while (logger) { - - TmEcode (*ThreadInit)(ThreadVars *, void *, void **) = NULL; - if (logger->ThreadInit) { - SCLogNotice("Logger %s has ThreadInit.", logger->name); - ThreadInit = logger->ThreadInit; - } else { - SCLogNotice("Logger %s DOES NOT have ThreadInit.", logger->name); - } - - if (ThreadInit == NULL) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - ThreadInit = tm_module->ThreadInit; - } - - if (ThreadInit) { void *retptr = NULL; - if (ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -329,24 +309,8 @@ static TmEcode OutputTxLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputTxLogger *logger = list; while (logger && store) { - TmEcode (*ThreadDeinit)(ThreadVars *, void *) = NULL; - if (logger->ThreadDeinit) { - ThreadDeinit = logger->ThreadDeinit; - } - - if (ThreadDeinit == NULL) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - ThreadDeinit = tm_module->ThreadDeinit; - } - - if (ThreadDeinit) { - ThreadDeinit(tv, store->thread_data); + logger->ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -366,24 +330,8 @@ static void OutputTxLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputTxLogger *logger = list; while (logger && store) { - void (*ThreadExitPrintStats)(ThreadVars *, void *) = NULL; - if (logger->ThreadExitPrintStats) { - ThreadExitPrintStats = logger->ThreadExitPrintStats; - } - - if (ThreadExitPrintStats == NULL) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - ThreadExitPrintStats = tm_module->ThreadExitPrintStats; - } - - if (ThreadExitPrintStats) { - ThreadExitPrintStats(tv, store->thread_data); + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; diff --git a/src/output.c b/src/output.c index b3d5c4487818..4ffa6b081319 100644 --- a/src/output.c +++ b/src/output.c @@ -202,7 +202,10 @@ void OutputRegisterTxSubModuleWrapper(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, - TxLoggerCondition TxLogCondition) + TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -222,6 +225,9 @@ void OutputRegisterTxSubModuleWrapper(const char *parent_name, module->alproto = alproto; module->tc_log_progress = tc_log_progress; module->ts_log_progress = ts_log_progress; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Tx logger \"%s\" registered.", name); @@ -255,7 +261,7 @@ void OutputRegisterTxSubModuleWithCondition(const char *parent_name, { OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, InitFunc, alproto, TxLogFunc, -1, -1, - TxLogCondition); + TxLogCondition, NULL, NULL, NULL); } /** @@ -267,22 +273,27 @@ void OutputRegisterTxSubModuleWithCondition(const char *parent_name, * \retval Returns 0 on success, -1 on failure. */ void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress) + OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, - TxLogFunc, tc_log_progress, ts_log_progress, - NULL, NULL, NULL, NULL); + TxLogFunc, tc_log_progress, ts_log_progress, NULL, ThreadInit, + ThreadDeinit, ThreadExitPrintStats); } void OutputRegisterTxSubModuleWithProgress(const char *parent_name, - const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, - OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, - int tc_log_progress, int ts_log_progress) + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), + AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, + int ts_log_progress, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, InitFunc, - alproto, TxLogFunc, tc_log_progress, - ts_log_progress, NULL); + alproto, TxLogFunc, tc_log_progress, ts_log_progress, NULL, ThreadInit, + ThreadDeinit, ThreadExitPrintStats); } /** @@ -305,13 +316,17 @@ OutputRegisterTxModule(const char *name, const char *conf_name, ThreadDeinit, ThreadExitPrintStats); } -void -OutputRegisterTxSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - AppProto alproto, TxLogger TxLogFunc) +void OutputRegisterTxSubModule(const char *parent_name, const char *name, + const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), + AppProto alproto, TxLogger TxLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, - InitFunc, alproto, TxLogFunc, -1, -1, NULL); + InitFunc, alproto, TxLogFunc, -1, -1, NULL, + ThreadInit, ThreadDeinit, + ThreadExitPrintStats); } /** diff --git a/src/output.h b/src/output.h index 232db0edcf54..58f488c6c45a 100644 --- a/src/output.h +++ b/src/output.h @@ -86,8 +86,11 @@ void OutputRegisterTxModule(const char *name, const char *conf_name, void (*ThreadExitPrintStats)(ThreadVars *, void *)); void OutputRegisterTxSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - AppProto alproto, TxLogger TxLogFunc); + const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), + AppProto alproto, TxLogger TxLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterTxModuleWithCondition(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, @@ -98,11 +101,17 @@ void OutputRegisterTxSubModuleWithCondition(const char *parent_name, TxLoggerCondition TxLogCondition); void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress); -void OutputRegisterTxSubModuleWithProgress(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress); + OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc, + int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterTxSubModuleWithProgress(const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), + AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, + int ts_log_progress, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFileModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc); diff --git a/src/tm-modules.c b/src/tm-modules.c index 5879d3d44396..eb2ef2567cf4 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -245,7 +245,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_STREAMINGLOGGER); CASE_CODE (TMM_JSONALERTLOG); CASE_CODE (TMM_JSONDROPLOG); - CASE_CODE (TMM_JSONDNSLOG); CASE_CODE (TMM_JSONHTTPLOG); CASE_CODE (TMM_JSONFILELOG); CASE_CODE (TMM_JSONFLOWLOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index d1bc75391d3d..8ccfeeac5f9a 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -79,7 +79,6 @@ typedef enum { TMM_JSONALERTLOG, TMM_JSONDROPLOG, TMM_JSONHTTPLOG, - TMM_JSONDNSLOG, TMM_JSONSMTPLOG, TMM_JSONSSHLOG, TMM_JSONSTATSLOG, From dedda33f01a180214c2355a85f18e344c959a11f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 01:03:13 -0600 Subject: [PATCH 1647/2553] logging: convert eve http to non-thread module --- src/output-json-http.c | 22 +++++----------------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/output-json-http.c b/src/output-json-http.c index 1ded557892f2..fdf03a33f6f0 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -584,34 +584,22 @@ static TmEcode JsonHttpLogThreadDeinit(ThreadVars *t, void *data) void TmModuleJsonHttpLogRegister (void) { - tmm_modules[TMM_JSONHTTPLOG].name = "JsonHttpLog"; - tmm_modules[TMM_JSONHTTPLOG].ThreadInit = JsonHttpLogThreadInit; - tmm_modules[TMM_JSONHTTPLOG].ThreadDeinit = JsonHttpLogThreadDeinit; - tmm_modules[TMM_JSONHTTPLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONHTTPLOG].cap_flags = 0; - tmm_modules[TMM_JSONHTTPLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ OutputRegisterTxModule("JsonHttpLog", "http-json-log", OutputHttpLogInit, - ALPROTO_HTTP, JsonHttpLogger, NULL, NULL, NULL); + ALPROTO_HTTP, JsonHttpLogger, JsonHttpLogThreadInit, + JsonHttpLogThreadDeinit, NULL); /* also register as child of eve-log */ OutputRegisterTxSubModule("eve-log", "JsonHttpLog", "eve-log.http", - OutputHttpLogInitSub, ALPROTO_HTTP, JsonHttpLogger, NULL, NULL, NULL); + OutputHttpLogInitSub, ALPROTO_HTTP, JsonHttpLogger, + JsonHttpLogThreadInit, JsonHttpLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonHttpLogRegister (void) { - tmm_modules[TMM_JSONHTTPLOG].name = "JsonHttpLog"; - tmm_modules[TMM_JSONHTTPLOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/tm-modules.c b/src/tm-modules.c index eb2ef2567cf4..9e3a83604b87 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -245,7 +245,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_STREAMINGLOGGER); CASE_CODE (TMM_JSONALERTLOG); CASE_CODE (TMM_JSONDROPLOG); - CASE_CODE (TMM_JSONHTTPLOG); CASE_CODE (TMM_JSONFILELOG); CASE_CODE (TMM_JSONFLOWLOG); CASE_CODE (TMM_JSONNETFLOWLOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 8ccfeeac5f9a..c844f2c17e73 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -78,7 +78,6 @@ typedef enum { TMM_STREAMINGLOGGER, TMM_JSONALERTLOG, TMM_JSONDROPLOG, - TMM_JSONHTTPLOG, TMM_JSONSMTPLOG, TMM_JSONSSHLOG, TMM_JSONSTATSLOG, From 31663f1627e1e574b1c84c9a58ce048a657e9e24 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 01:07:10 -0600 Subject: [PATCH 1648/2553] logging: convert prelude output to non-thread module --- src/alert-prelude.c | 27 ++++----------------------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index 1a7b2681499c..b29e885fa9ce 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -62,22 +62,9 @@ /* Handle the case where no PRELUDE support is compiled in. */ -static TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogDebug("Can't init Prelude output thread - Prelude support was disabled during build."); - return TM_ECODE_FAILED; -} - -static TmEcode AlertPreludeThreadDeinit(ThreadVars *t, void *data) -{ - return TM_ECODE_FAILED; -} - void TmModuleAlertPreludeRegister (void) { - tmm_modules[TMM_ALERTPRELUDE].name = "AlertPrelude"; - tmm_modules[TMM_ALERTPRELUDE].ThreadInit = AlertPreludeThreadInit; - tmm_modules[TMM_ALERTPRELUDE].ThreadDeinit = AlertPreludeThreadDeinit; + SCLogDebug("Can't register Prelude output thread - Prelude support was disabled during build."); } #else /* implied we do have PRELUDE support */ @@ -929,15 +916,9 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p void TmModuleAlertPreludeRegister (void) { - tmm_modules[TMM_ALERTPRELUDE].name = "AlertPrelude"; - tmm_modules[TMM_ALERTPRELUDE].ThreadInit = AlertPreludeThreadInit; - tmm_modules[TMM_ALERTPRELUDE].Func = NULL; - tmm_modules[TMM_ALERTPRELUDE].ThreadDeinit = AlertPreludeThreadDeinit; - tmm_modules[TMM_ALERTPRELUDE].cap_flags = 0; - tmm_modules[TMM_ALERTPRELUDE].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule("AlertPrelude", "alert-prelude", AlertPreludeInitCtx, - AlertPreludeLogger, AlertPreludeCondition); + OutputRegisterPacketModule("AlertPrelude", "alert-prelude", + AlertPreludeInitCtx, AlertPreludeLogger, AlertPreludeCondition, + AlertPreludeThreadInit, AlertPreludeThreadDeinit, NULL); } #endif /* PRELUDE */ diff --git a/src/tm-modules.c b/src/tm-modules.c index 9e3a83604b87..d4d167158c92 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -212,7 +212,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_RECEIVEPFRING); CASE_CODE (TMM_DECODEPFRING); CASE_CODE (TMM_ALERTUNIFIED2ALERT); - CASE_CODE (TMM_ALERTPRELUDE); CASE_CODE (TMM_ALERTDEBUGLOG); CASE_CODE (TMM_ALERTSYSLOG); CASE_CODE (TMM_LOGDROPLOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index c844f2c17e73..7288b92ebdfe 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -42,7 +42,6 @@ typedef enum { TMM_RECEIVEPFRING, TMM_DECODEPFRING, TMM_ALERTUNIFIED2ALERT, - TMM_ALERTPRELUDE, TMM_ALERTDEBUGLOG, TMM_ALERTSYSLOG, TMM_LOGDROPLOG, From aaa65f3d16174bf149ccffa98f23569de6c91039 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 01:18:22 -0600 Subject: [PATCH 1649/2553] logging: convert json tls output to non-thread module --- src/output-json-tls.c | 25 ++++++------------------- src/output.h | 7 ++++--- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 4b0f2a0463f2..52237ba934be 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -310,36 +310,23 @@ OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) void TmModuleJsonTlsLogRegister (void) { - tmm_modules[TMM_JSONTLSLOG].name = "JsonTlsLog"; - tmm_modules[TMM_JSONTLSLOG].ThreadInit = JsonTlsLogThreadInit; - tmm_modules[TMM_JSONTLSLOG].ThreadDeinit = JsonTlsLogThreadDeinit; - tmm_modules[TMM_JSONTLSLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONTLSLOG].cap_flags = 0; - tmm_modules[TMM_JSONTLSLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ OutputRegisterTxModuleWithProgress("JsonTlsLog", "tls-json-log", - OutputTlsLogInit, ALPROTO_TLS, JsonTlsLogger, TLS_HANDSHAKE_DONE, - TLS_HANDSHAKE_DONE, NULL, NULL, NULL); + OutputTlsLogInit, ALPROTO_TLS, JsonTlsLogger, TLS_HANDSHAKE_DONE, + TLS_HANDSHAKE_DONE, JsonTlsLogThreadInit, JsonTlsLogThreadDeinit, NULL); /* also register as child of eve-log */ OutputRegisterTxSubModuleWithProgress("eve-log", "JsonTlsLog", - "eve-log.tls", OutputTlsLogInitSub, ALPROTO_TLS, JsonTlsLogger, - TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, NULL, NULL, NULL); + "eve-log.tls", OutputTlsLogInitSub, ALPROTO_TLS, JsonTlsLogger, + TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, JsonTlsLogThreadInit, + JsonTlsLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonTlsLogRegister (void) { - tmm_modules[TMM_JSONTLSLOG].name = "JsonTlsLog"; - tmm_modules[TMM_JSONTLSLOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output.h b/src/output.h index 58f488c6c45a..cfa01ae9a0b5 100644 --- a/src/output.h +++ b/src/output.h @@ -101,10 +101,11 @@ void OutputRegisterTxSubModuleWithCondition(const char *parent_name, TxLoggerCondition TxLogCondition); void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc, - int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, + OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); + void OutputRegisterTxSubModuleWithProgress(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), diff --git a/src/tm-modules.c b/src/tm-modules.c index d4d167158c92..834a46a2c2e7 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -250,7 +250,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_JSONSMTPLOG); CASE_CODE (TMM_JSONSSHLOG); CASE_CODE (TMM_JSONSTATSLOG); - CASE_CODE (TMM_JSONTLSLOG); CASE_CODE (TMM_OUTPUTJSON); CASE_CODE (TMM_FLOWMANAGER); CASE_CODE (TMM_FLOWRECYCLER); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 7288b92ebdfe..370c5a1cffa9 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -80,7 +80,6 @@ typedef enum { TMM_JSONSMTPLOG, TMM_JSONSSHLOG, TMM_JSONSTATSLOG, - TMM_JSONTLSLOG, TMM_JSONFILELOG, TMM_RECEIVENFLOG, TMM_DECODENFLOG, From ad15ac829761f0f1b429fd3f3c8f43dae18eaee9 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 01:33:10 -0600 Subject: [PATCH 1650/2553] logging: convert json alert output to non-thread module --- src/output-json-alert.c | 21 +++++---------------- src/output-json-drop.c | 2 +- src/output-json-ssh.c | 4 ++-- src/output.c | 7 ++++++- src/output.h | 4 +++- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 7 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 56567ce2066c..79c8ea0e291a 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -741,30 +741,19 @@ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) void TmModuleJsonAlertLogRegister (void) { - tmm_modules[TMM_JSONALERTLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONALERTLOG].ThreadInit = JsonAlertLogThreadInit; - tmm_modules[TMM_JSONALERTLOG].ThreadDeinit = JsonAlertLogThreadDeinit; - tmm_modules[TMM_JSONALERTLOG].cap_flags = 0; - tmm_modules[TMM_JSONALERTLOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterPacketModule(MODULE_NAME, "alert-json-log", - JsonAlertLogInitCtx, JsonAlertLogger, JsonAlertLogCondition, NULL, NULL, NULL); + JsonAlertLogInitCtx, JsonAlertLogger, JsonAlertLogCondition, + JsonAlertLogThreadInit, JsonAlertLogThreadDeinit, NULL); OutputRegisterPacketSubModule("eve-log", MODULE_NAME, "eve-log.alert", - JsonAlertLogInitCtxSub, JsonAlertLogger, JsonAlertLogCondition); + JsonAlertLogInitCtxSub, JsonAlertLogger, JsonAlertLogCondition, + JsonAlertLogThreadInit, JsonAlertLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonAlertLogRegister (void) { - tmm_modules[TMM_JSONALERTLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONALERTLOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-drop.c b/src/output-json-drop.c index fee5845f72b0..8a9a0610c6a8 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -438,7 +438,7 @@ void TmModuleJsonDropLogRegister (void) OutputRegisterPacketModule(MODULE_NAME, "drop-json-log", JsonDropLogInitCtx, JsonDropLogger, JsonDropLogCondition, NULL, NULL, NULL); OutputRegisterPacketSubModule("eve-log", MODULE_NAME, "eve-log.drop", - JsonDropLogInitCtxSub, JsonDropLogger, JsonDropLogCondition); + JsonDropLogInitCtxSub, JsonDropLogger, JsonDropLogCondition, NULL, NULL, NULL); } #else diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index ff626666c237..d99c6e88807b 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -328,8 +328,8 @@ void TmModuleJsonSshLogRegister (void) JsonSshLogger, JsonSshCondition, NULL, NULL, NULL); /* also register as child of eve-log */ - OutputRegisterPacketSubModule("eve-log", "JsonSshLog", "eve-log.ssh", OutputSshLogInitSub, - JsonSshLogger, JsonSshCondition); + OutputRegisterPacketSubModule("eve-log", "JsonSshLog", "eve-log.ssh", + OutputSshLogInitSub, JsonSshLogger, JsonSshCondition, NULL, NULL, NULL); } #else diff --git a/src/output.c b/src/output.c index 4ffa6b081319..f981fbdeb3cd 100644 --- a/src/output.c +++ b/src/output.c @@ -127,7 +127,9 @@ OutputRegisterPacketModule(const char *name, const char *conf_name, void OutputRegisterPacketSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc) + PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(PacketLogFunc == NULL || PacketConditionFunc == NULL)) { goto error; @@ -144,6 +146,9 @@ OutputRegisterPacketSubModule(const char *parent_name, const char *name, module->InitSubFunc = InitFunc; module->PacketLogFunc = PacketLogFunc; module->PacketConditionFunc = PacketConditionFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Packet logger \"%s\" registered.", name); diff --git a/src/output.h b/src/output.h index cfa01ae9a0b5..d7311c13de4f 100644 --- a/src/output.h +++ b/src/output.h @@ -77,7 +77,9 @@ void OutputRegisterPacketModule(const char *name, const char *conf_name, ThreadInitFunc, ThreadDeinitFunc, ThreadExitPrintStatsFunc); void OutputRegisterPacketSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - PacketLogger LogFunc, PacketLogCondition ConditionFunc); + PacketLogger LogFunc, PacketLogCondition ConditionFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterTxModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, diff --git a/src/tm-modules.c b/src/tm-modules.c index 834a46a2c2e7..5099a74b8201 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -242,7 +242,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_FILELOGGER); CASE_CODE (TMM_FILEDATALOGGER); CASE_CODE (TMM_STREAMINGLOGGER); - CASE_CODE (TMM_JSONALERTLOG); CASE_CODE (TMM_JSONDROPLOG); CASE_CODE (TMM_JSONFILELOG); CASE_CODE (TMM_JSONFLOWLOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 370c5a1cffa9..7e76782692e1 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -75,7 +75,6 @@ typedef enum { TMM_FILELOGGER, TMM_FILEDATALOGGER, TMM_STREAMINGLOGGER, - TMM_JSONALERTLOG, TMM_JSONDROPLOG, TMM_JSONSMTPLOG, TMM_JSONSSHLOG, From 983a619ff075888b645d3dba4c72a078960f0cf3 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 01:52:01 -0600 Subject: [PATCH 1651/2553] logging: convert json flow output to non-thread module --- src/output-flow.c | 54 +++++++++++++-------------------------- src/output-flow.h | 4 ++- src/output-json-flow.c | 22 ++++------------ src/output-json-netflow.c | 4 +-- src/output.c | 14 ++++++++-- src/output.h | 9 +++++-- src/runmodes.c | 4 ++- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 9 files changed, 50 insertions(+), 63 deletions(-) diff --git a/src/output-flow.c b/src/output-flow.c index 20d5d7d423bd..6113631d9f85 100644 --- a/src/output-flow.c +++ b/src/output-flow.c @@ -47,17 +47,18 @@ typedef struct OutputFlowLogger_ { OutputCtx *output_ctx; struct OutputFlowLogger_ *next; const char *name; - TmmId module_id; + TmEcode (*ThreadInit)(ThreadVars *, void *, void **); + TmEcode (*ThreadDeinit)(ThreadVars *, void *); + void (*ThreadExitPrintStats)(ThreadVars *, void *); } OutputFlowLogger; static OutputFlowLogger *list = NULL; -int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, OutputCtx *output_ctx) +int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; - OutputFlowLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -66,7 +67,9 @@ int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, OutputCtx *ou op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; - op->module_id = (TmmId) module_id; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; if (list == NULL) list = op; @@ -106,9 +109,9 @@ TmEcode OutputFlowLog(ThreadVars *tv, void *thread_data, Flow *f) BUG_ON(logger->LogFunc == NULL); SCLogDebug("logger %p", logger); - //PACKET_PROFILING_TMM_START(p, logger->module_id); + //PACKET_PROFILING_LOGGER_START(p, logger->module_id); logger->LogFunc(tv, store->thread_data, f); - //PACKET_PROFILING_TMM_END(p, logger->module_id); + //PACKET_PROFILING_LOGGER_END(p, logger->module_id); logger = logger->next; store = store->next; @@ -136,16 +139,9 @@ TmEcode OutputFlowLogThreadInit(ThreadVars *tv, void *initdata, void **data) OutputFlowLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -179,15 +175,8 @@ TmEcode OutputFlowLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputFlowLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -207,15 +196,8 @@ void OutputFlowLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputFlowLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; diff --git a/src/output-flow.h b/src/output-flow.h index af093e3eb0d9..26bfc32450b2 100644 --- a/src/output-flow.h +++ b/src/output-flow.h @@ -36,7 +36,9 @@ typedef int (*FlowLogger)(ThreadVars *, void *thread_data, Flow *f); */ //typedef int (*TxLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, OutputCtx *); +int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, + OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputFlowShutdown(void); diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 1ce4b6f2f73b..a55faa3115f1 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -450,34 +450,22 @@ static TmEcode JsonFlowLogThreadDeinit(ThreadVars *t, void *data) void TmModuleJsonFlowLogRegister (void) { - tmm_modules[TMM_JSONFLOWLOG].name = "JsonFlowLog"; - tmm_modules[TMM_JSONFLOWLOG].ThreadInit = JsonFlowLogThreadInit; - tmm_modules[TMM_JSONFLOWLOG].ThreadDeinit = JsonFlowLogThreadDeinit; - tmm_modules[TMM_JSONFLOWLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONFLOWLOG].cap_flags = 0; - tmm_modules[TMM_JSONFLOWLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ OutputRegisterFlowModule("JsonFlowLog", "flow-json-log", - OutputFlowLogInit, JsonFlowLogger); + OutputFlowLogInit, JsonFlowLogger, JsonFlowLogThreadInit, + JsonFlowLogThreadDeinit, NULL); /* also register as child of eve-log */ OutputRegisterFlowSubModule("eve-log", "JsonFlowLog", "eve-log.flow", - OutputFlowLogInitSub, JsonFlowLogger); + OutputFlowLogInitSub, JsonFlowLogger, JsonFlowLogThreadInit, + JsonFlowLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonFlowLogRegister (void) { - tmm_modules[TMM_JSONFLOWLOG].name = "JsonFlowLog"; - tmm_modules[TMM_JSONFLOWLOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 52ff013cada3..e131588bb6fa 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -441,11 +441,11 @@ void TmModuleJsonNetFlowLogRegister (void) /* register as separate module */ OutputRegisterFlowModule("JsonNetFlowLog", "netflow-json-log", - OutputNetFlowLogInit, JsonNetFlowLogger); + OutputNetFlowLogInit, JsonNetFlowLogger, NULL, NULL, NULL); /* also register as child of eve-log */ OutputRegisterFlowSubModule("eve-log", "JsonNetFlowLog", "eve-log.netflow", - OutputNetFlowLogInitSub, JsonNetFlowLogger); + OutputNetFlowLogInitSub, JsonNetFlowLogger, NULL, NULL, NULL); } #else diff --git a/src/output.c b/src/output.c index f981fbdeb3cd..5d121b32947b 100644 --- a/src/output.c +++ b/src/output.c @@ -484,7 +484,9 @@ OutputRegisterFiledataSubModule(const char *parent_name, const char *name, */ void OutputRegisterFlowModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FlowLogger FlowLogFunc) + OutputCtx *(*InitFunc)(ConfNode *), FlowLogger FlowLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FlowLogFunc == NULL)) { goto error; @@ -499,6 +501,9 @@ OutputRegisterFlowModule(const char *name, const char *conf_name, module->conf_name = conf_name; module->InitFunc = InitFunc; module->FlowLogFunc = FlowLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Flow logger \"%s\" registered.", name); @@ -519,7 +524,9 @@ OutputRegisterFlowModule(const char *name, const char *conf_name, void OutputRegisterFlowSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FlowLogger FlowLogFunc) + FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FlowLogFunc == NULL)) { goto error; @@ -535,6 +542,9 @@ OutputRegisterFlowSubModule(const char *parent_name, const char *name, module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->FlowLogFunc = FlowLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Flow logger \"%s\" registered.", name); diff --git a/src/output.h b/src/output.h index d7311c13de4f..9a6296ffc258 100644 --- a/src/output.h +++ b/src/output.h @@ -129,10 +129,15 @@ void OutputRegisterFiledataSubModule(const char *parent_name, const char *name, FiledataLogger FiledataLogFunc); void OutputRegisterFlowModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FlowLogger FlowLogFunc); + OutputCtx *(*InitFunc)(ConfNode *), FlowLogger FlowLogFunc, + ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFlowSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FlowLogger FlowLogFunc); + FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterStreamingModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), StreamingLogger StreamingLogFunc, diff --git a/src/runmodes.c b/src/runmodes.c index 78f73aa22b32..6c0d9918c8e3 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -585,7 +585,9 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu { /* flow logger doesn't run in the packet path */ if (module->FlowLogFunc) { - OutputRegisterFlowLogger(module->name, module->FlowLogFunc, output_ctx); + OutputRegisterFlowLogger(module->name, module->FlowLogFunc, + output_ctx, module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); return; } /* stats logger doesn't run in the packet path */ diff --git a/src/tm-modules.c b/src/tm-modules.c index 5099a74b8201..67a97767ac2a 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -244,7 +244,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_STREAMINGLOGGER); CASE_CODE (TMM_JSONDROPLOG); CASE_CODE (TMM_JSONFILELOG); - CASE_CODE (TMM_JSONFLOWLOG); CASE_CODE (TMM_JSONNETFLOWLOG); CASE_CODE (TMM_JSONSMTPLOG); CASE_CODE (TMM_JSONSSHLOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 7e76782692e1..9a980ed73677 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -82,7 +82,6 @@ typedef enum { TMM_JSONFILELOG, TMM_RECEIVENFLOG, TMM_DECODENFLOG, - TMM_JSONFLOWLOG, TMM_JSONNETFLOWLOG, TMM_LOGSTATSLOG, TMM_JSONTEMPLATELOG, From 01cc50825718171f2adf92d406d9d6d5482f55fb Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 01:54:36 -0600 Subject: [PATCH 1652/2553] logging: convert json netflow output to non-thread module --- src/output-json-netflow.c | 22 +++++----------------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index e131588bb6fa..2091be08d896 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -432,34 +432,22 @@ static TmEcode JsonNetFlowLogThreadDeinit(ThreadVars *t, void *data) void TmModuleJsonNetFlowLogRegister (void) { - tmm_modules[TMM_JSONNETFLOWLOG].name = "JsonNetFlowLog"; - tmm_modules[TMM_JSONNETFLOWLOG].ThreadInit = JsonNetFlowLogThreadInit; - tmm_modules[TMM_JSONNETFLOWLOG].ThreadDeinit = JsonNetFlowLogThreadDeinit; - tmm_modules[TMM_JSONNETFLOWLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONNETFLOWLOG].cap_flags = 0; - tmm_modules[TMM_JSONNETFLOWLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ OutputRegisterFlowModule("JsonNetFlowLog", "netflow-json-log", - OutputNetFlowLogInit, JsonNetFlowLogger, NULL, NULL, NULL); + OutputNetFlowLogInit, JsonNetFlowLogger, JsonNetFlowLogThreadInit, + JsonNetFlowLogThreadDeinit, NULL); /* also register as child of eve-log */ OutputRegisterFlowSubModule("eve-log", "JsonNetFlowLog", "eve-log.netflow", - OutputNetFlowLogInitSub, JsonNetFlowLogger, NULL, NULL, NULL); + OutputNetFlowLogInitSub, JsonNetFlowLogger, JsonNetFlowLogThreadInit, + JsonNetFlowLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonNetFlowLogRegister (void) { - tmm_modules[TMM_JSONNETFLOWLOG].name = "JsonNetFlowLog"; - tmm_modules[TMM_JSONNETFLOWLOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/tm-modules.c b/src/tm-modules.c index 67a97767ac2a..1d1040fcda20 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -244,7 +244,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_STREAMINGLOGGER); CASE_CODE (TMM_JSONDROPLOG); CASE_CODE (TMM_JSONFILELOG); - CASE_CODE (TMM_JSONNETFLOWLOG); CASE_CODE (TMM_JSONSMTPLOG); CASE_CODE (TMM_JSONSSHLOG); CASE_CODE (TMM_JSONSTATSLOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 9a980ed73677..7739146e669d 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -82,7 +82,6 @@ typedef enum { TMM_JSONFILELOG, TMM_RECEIVENFLOG, TMM_DECODENFLOG, - TMM_JSONNETFLOWLOG, TMM_LOGSTATSLOG, TMM_JSONTEMPLATELOG, From 3fea12d7b32e8c5ce4d8052d3886cd9ff6f6d676 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 02:00:24 -0600 Subject: [PATCH 1653/2553] logging: convert json ssh output to non-thread module --- src/output-json-ssh.c | 22 +++++----------------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index d99c6e88807b..313df7c824aa 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -316,34 +316,22 @@ static int JsonSshCondition(ThreadVars *tv, const Packet *p) void TmModuleJsonSshLogRegister (void) { - tmm_modules[TMM_JSONSSHLOG].name = "JsonSshLog"; - tmm_modules[TMM_JSONSSHLOG].ThreadInit = JsonSshLogThreadInit; - tmm_modules[TMM_JSONSSHLOG].ThreadDeinit = JsonSshLogThreadDeinit; - tmm_modules[TMM_JSONSSHLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONSSHLOG].cap_flags = 0; - tmm_modules[TMM_JSONSSHLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ OutputRegisterPacketModule("JsonSshLog", "ssh-json-log", OutputSshLogInit, - JsonSshLogger, JsonSshCondition, NULL, NULL, NULL); + JsonSshLogger, JsonSshCondition, JsonSshLogThreadInit, + JsonSshLogThreadDeinit, NULL); /* also register as child of eve-log */ OutputRegisterPacketSubModule("eve-log", "JsonSshLog", "eve-log.ssh", - OutputSshLogInitSub, JsonSshLogger, JsonSshCondition, NULL, NULL, NULL); + OutputSshLogInitSub, JsonSshLogger, JsonSshCondition, + JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonSshLogRegister (void) { - tmm_modules[TMM_JSONSSHLOG].name = "JsonSshLog"; - tmm_modules[TMM_JSONSSHLOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/tm-modules.c b/src/tm-modules.c index 1d1040fcda20..dc4605e45f56 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -245,7 +245,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_JSONDROPLOG); CASE_CODE (TMM_JSONFILELOG); CASE_CODE (TMM_JSONSMTPLOG); - CASE_CODE (TMM_JSONSSHLOG); CASE_CODE (TMM_JSONSTATSLOG); CASE_CODE (TMM_OUTPUTJSON); CASE_CODE (TMM_FLOWMANAGER); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 7739146e669d..17c531e085ee 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -77,7 +77,6 @@ typedef enum { TMM_STREAMINGLOGGER, TMM_JSONDROPLOG, TMM_JSONSMTPLOG, - TMM_JSONSSHLOG, TMM_JSONSTATSLOG, TMM_JSONFILELOG, TMM_RECEIVENFLOG, From 38354479b7b18ddde3d905c106eb33097aa841c0 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 02:01:52 -0600 Subject: [PATCH 1654/2553] logging: convert json smtp output to non-thread module --- src/output-json-smtp.c | 22 +++++----------------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 1a9a46fbde83..8bf94d260432 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -258,34 +258,22 @@ static TmEcode JsonSmtpLogThreadDeinit(ThreadVars *t, void *data) } void TmModuleJsonSmtpLogRegister (void) { - tmm_modules[TMM_JSONSMTPLOG].name = "JsonSmtpLog"; - tmm_modules[TMM_JSONSMTPLOG].ThreadInit = JsonSmtpLogThreadInit; - tmm_modules[TMM_JSONSMTPLOG].ThreadDeinit = JsonSmtpLogThreadDeinit; - tmm_modules[TMM_JSONSMTPLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONSMTPLOG].cap_flags = 0; - tmm_modules[TMM_JSONSMTPLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ OutputRegisterTxModule("JsonSmtpLog", "smtp-json-log", OutputSmtpLogInit, - ALPROTO_SMTP, JsonSmtpLogger, NULL, NULL, NULL); + ALPROTO_SMTP, JsonSmtpLogger, JsonSmtpLogThreadInit, + JsonSmtpLogThreadDeinit, NULL); /* also register as child of eve-log */ OutputRegisterTxSubModule("eve-log", "JsonSmtpLog", "eve-log.smtp", - OutputSmtpLogInitSub, ALPROTO_SMTP, JsonSmtpLogger, NULL, NULL, NULL); + OutputSmtpLogInitSub, ALPROTO_SMTP, JsonSmtpLogger, + JsonSmtpLogThreadInit, JsonSmtpLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonSmtpLogRegister (void) { - tmm_modules[TMM_JSONSMTPLOG].name = "JsonSmtpLog"; - tmm_modules[TMM_JSONSMTPLOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/tm-modules.c b/src/tm-modules.c index dc4605e45f56..dc5527cd5f39 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -244,7 +244,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_STREAMINGLOGGER); CASE_CODE (TMM_JSONDROPLOG); CASE_CODE (TMM_JSONFILELOG); - CASE_CODE (TMM_JSONSMTPLOG); CASE_CODE (TMM_JSONSTATSLOG); CASE_CODE (TMM_OUTPUTJSON); CASE_CODE (TMM_FLOWMANAGER); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 17c531e085ee..736eb9987138 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -76,7 +76,6 @@ typedef enum { TMM_FILEDATALOGGER, TMM_STREAMINGLOGGER, TMM_JSONDROPLOG, - TMM_JSONSMTPLOG, TMM_JSONSTATSLOG, TMM_JSONFILELOG, TMM_RECEIVENFLOG, From bac65f09e8aa810c9768e0f814e0e3d9c841b564 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 02:05:30 -0600 Subject: [PATCH 1655/2553] logging: convert json drop output to non-thread module --- src/output-json-drop.c | 21 +++++---------------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 8a9a0610c6a8..c7a8b18b85c9 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -429,30 +429,19 @@ static int JsonDropLogCondition(ThreadVars *tv, const Packet *p) void TmModuleJsonDropLogRegister (void) { - tmm_modules[TMM_JSONDROPLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONDROPLOG].ThreadInit = JsonDropLogThreadInit; - tmm_modules[TMM_JSONDROPLOG].ThreadDeinit = JsonDropLogThreadDeinit; - tmm_modules[TMM_JSONDROPLOG].cap_flags = 0; - tmm_modules[TMM_JSONDROPLOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterPacketModule(MODULE_NAME, "drop-json-log", - JsonDropLogInitCtx, JsonDropLogger, JsonDropLogCondition, NULL, NULL, NULL); + JsonDropLogInitCtx, JsonDropLogger, JsonDropLogCondition, + JsonDropLogThreadInit, JsonDropLogThreadDeinit, NULL); OutputRegisterPacketSubModule("eve-log", MODULE_NAME, "eve-log.drop", - JsonDropLogInitCtxSub, JsonDropLogger, JsonDropLogCondition, NULL, NULL, NULL); + JsonDropLogInitCtxSub, JsonDropLogger, JsonDropLogCondition, + JsonDropLogThreadInit, JsonDropLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonDropLogRegister (void) { - tmm_modules[TMM_JSONDROPLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONDROPLOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/tm-modules.c b/src/tm-modules.c index dc5527cd5f39..c8fbd57681e8 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -242,7 +242,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_FILELOGGER); CASE_CODE (TMM_FILEDATALOGGER); CASE_CODE (TMM_STREAMINGLOGGER); - CASE_CODE (TMM_JSONDROPLOG); CASE_CODE (TMM_JSONFILELOG); CASE_CODE (TMM_JSONSTATSLOG); CASE_CODE (TMM_OUTPUTJSON); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 736eb9987138..3323faab44e4 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -75,7 +75,6 @@ typedef enum { TMM_FILELOGGER, TMM_FILEDATALOGGER, TMM_STREAMINGLOGGER, - TMM_JSONDROPLOG, TMM_JSONSTATSLOG, TMM_JSONFILELOG, TMM_RECEIVENFLOG, From b605984f34aa3150afd4852bc9ff9f278a5a500a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 10:01:54 -0600 Subject: [PATCH 1656/2553] tests: setup unit test framework earlier Allows tests to be registered early, in support of moving outputs away from thread modules. --- src/runmode-unittests.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index b5d22bd3b19c..7326bcec3be9 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -177,6 +177,8 @@ void RunUnittests(int list_unittests, char *regex_arg) SCReferenceConfInit(); SCClassConfInit(); + UtInitialize(); + RegisterAllModules(); DetectEngineRegisterAppInspectionEngines(); @@ -193,7 +195,6 @@ void RunUnittests(int list_unittests, char *regex_arg) AppLayerHtpEnableRequestBodyCallback(); AppLayerHtpNeedFileInspection(); - UtInitialize(); UTHRegisterTests(); StreamTcpRegisterTests(); SigRegisterTests(); From 5bbb4fd1341e9b204786b262743c94bb85f14a59 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 10:05:44 -0600 Subject: [PATCH 1657/2553] logging: convert json template output to non-thread module --- src/output-json-template.c | 23 ++++------------------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/output-json-template.c b/src/output-json-template.c index ca49f81ecdd6..195f1786f349 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -197,35 +197,20 @@ void TmModuleJsonTemplateLogRegister(void) return; } /* TEMPLATE_END_REMOVE */ - tmm_modules[TMM_JSONTEMPLATELOG].name = "JsonTemplateLog"; - tmm_modules[TMM_JSONTEMPLATELOG].ThreadInit = JsonTemplateLogThreadInit; - tmm_modules[TMM_JSONTEMPLATELOG].ThreadDeinit = JsonTemplateLogThreadDeinit; - tmm_modules[TMM_JSONTEMPLATELOG].RegisterTests = NULL; - tmm_modules[TMM_JSONTEMPLATELOG].cap_flags = 0; - tmm_modules[TMM_JSONTEMPLATELOG].flags = TM_FLAG_LOGAPI_TM; - /* Register as an eve sub-module. */ OutputRegisterTxSubModule("eve-log", "JsonTemplateLog", "eve-log.template", - OutputTemplateLogInitSub, ALPROTO_TEMPLATE, JsonTemplateLogger, NULL, - NULL, NULL); + OutputTemplateLogInitSub, ALPROTO_TEMPLATE, JsonTemplateLogger, + JsonTemplateLogThreadInit, JsonTemplateLogThreadDeinit, NULL); SCLogNotice("Template JSON logger registered."); } #else /* No JSON support. */ -static TmEcode JsonTemplateLogThreadInit(ThreadVars *t, void *initdata, - void **data) -{ - SCLogInfo("Cannot initialize JSON output for template. " - "JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonTemplateLogRegister(void) { - tmm_modules[TMM_JSONTEMPLATELOG].name = "JsonTemplateLog"; - tmm_modules[TMM_JSONTEMPLATELOG].ThreadInit = JsonTemplateLogThreadInit; + SCLogInfo("Cannot register JSON output for template. " + "JSON support was disabled during build."); } #endif /* HAVE_LIBJANSSON */ diff --git a/src/tm-modules.c b/src/tm-modules.c index c8fbd57681e8..a707f69efbd2 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -251,7 +251,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_DETECTLOADER); CASE_CODE (TMM_LUALOG); CASE_CODE (TMM_LOGSTATSLOG); - CASE_CODE (TMM_JSONTEMPLATELOG); CASE_CODE (TMM_RECEIVENETMAP); CASE_CODE (TMM_DECODENETMAP); CASE_CODE (TMM_TLSSTORE); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 3323faab44e4..696f1f855ed9 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -80,7 +80,6 @@ typedef enum { TMM_RECEIVENFLOG, TMM_DECODENFLOG, TMM_LOGSTATSLOG, - TMM_JSONTEMPLATELOG, TMM_FLOWMANAGER, TMM_FLOWRECYCLER, From 869d2eb701daa6660692c0344eb0951a24d0db07 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 10:10:02 -0600 Subject: [PATCH 1658/2553] logging: convert drop output to non-thread module --- src/log-droplog.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/log-droplog.c b/src/log-droplog.c index 0b466b6a48ed..c680a4233733 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -494,17 +494,10 @@ static void LogDropLogRegisterTests(void) /** \brief function to register the drop log module */ void TmModuleLogDropLogRegister (void) { - - tmm_modules[TMM_LOGDROPLOG].name = MODULE_NAME; - tmm_modules[TMM_LOGDROPLOG].ThreadInit = LogDropLogThreadInit; - tmm_modules[TMM_LOGDROPLOG].ThreadExitPrintStats = LogDropLogExitPrintStats; - tmm_modules[TMM_LOGDROPLOG].ThreadDeinit = LogDropLogThreadDeinit; + OutputRegisterPacketModule(MODULE_NAME, "drop", LogDropLogInitCtx, + LogDropLogger, LogDropCondition, LogDropLogThreadInit, + LogDropLogThreadDeinit, LogDropLogExitPrintStats); #ifdef UNITTESTS - tmm_modules[TMM_LOGDROPLOG].RegisterTests = LogDropLogRegisterTests; + LogDropLogRegisterTests(); #endif - tmm_modules[TMM_LOGDROPLOG].cap_flags = 0; - tmm_modules[TMM_LOGDROPLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule(MODULE_NAME, "drop", LogDropLogInitCtx, - LogDropLogger, LogDropCondition, NULL, NULL, NULL); } From e00dcd52a0b3da1e39ba4d8d5d6043c0a97e03cc Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 10:17:21 -0600 Subject: [PATCH 1659/2553] logging: convert alert syslog to non-thread module --- src/alert-syslog.c | 14 +++----------- src/tm-modules.c | 2 -- src/tm-threads-common.h | 2 -- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/alert-syslog.c b/src/alert-syslog.c index 2dd541b66bb4..a48b99f7a23b 100644 --- a/src/alert-syslog.c +++ b/src/alert-syslog.c @@ -411,17 +411,9 @@ static int AlertSyslogLogger(ThreadVars *tv, void *thread_data, const Packet *p) void TmModuleAlertSyslogRegister (void) { #ifndef OS_WIN32 - tmm_modules[TMM_ALERTSYSLOG].name = MODULE_NAME; - tmm_modules[TMM_ALERTSYSLOG].ThreadInit = AlertSyslogThreadInit; - tmm_modules[TMM_ALERTSYSLOG].Func = NULL; - tmm_modules[TMM_ALERTSYSLOG].ThreadExitPrintStats = AlertSyslogExitPrintStats; - tmm_modules[TMM_ALERTSYSLOG].ThreadDeinit = AlertSyslogThreadDeinit; - tmm_modules[TMM_ALERTSYSLOG].RegisterTests = NULL; - tmm_modules[TMM_ALERTSYSLOG].cap_flags = 0; - tmm_modules[TMM_ALERTSYSLOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterPacketModule(MODULE_NAME, "syslog", - AlertSyslogInitCtx, AlertSyslogLogger, AlertSyslogCondition, NULL, NULL, NULL); - + AlertSyslogInitCtx, AlertSyslogLogger, AlertSyslogCondition, + AlertSyslogThreadInit, AlertSyslogThreadDeinit, + AlertSyslogExitPrintStats); #endif /* !OS_WIN32 */ } diff --git a/src/tm-modules.c b/src/tm-modules.c index a707f69efbd2..7b79668eeee1 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -213,8 +213,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_DECODEPFRING); CASE_CODE (TMM_ALERTUNIFIED2ALERT); CASE_CODE (TMM_ALERTDEBUGLOG); - CASE_CODE (TMM_ALERTSYSLOG); - CASE_CODE (TMM_LOGDROPLOG); CASE_CODE (TMM_RESPONDREJECT); CASE_CODE (TMM_LOGHTTPLOG); CASE_CODE (TMM_LOGTLSLOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 696f1f855ed9..1b2824a2a3bc 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -43,8 +43,6 @@ typedef enum { TMM_DECODEPFRING, TMM_ALERTUNIFIED2ALERT, TMM_ALERTDEBUGLOG, - TMM_ALERTSYSLOG, - TMM_LOGDROPLOG, TMM_RESPONDREJECT, TMM_LOGHTTPLOG, TMM_LOGTLSLOG, From 9475c8371380f37ee83aecf8e30f47e6dbe128aa Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 10:21:19 -0600 Subject: [PATCH 1660/2553] logging: convert http log to non-thread module --- src/log-httplog.c | 11 ++--------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/log-httplog.c b/src/log-httplog.c index 04db70a43de1..64b825f89134 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -65,16 +65,9 @@ int LogHttpLogger(ThreadVars *tv, void *thread_data, const Packet *, Flow *f, vo void TmModuleLogHttpLogRegister (void) { - tmm_modules[TMM_LOGHTTPLOG].name = MODULE_NAME; - tmm_modules[TMM_LOGHTTPLOG].ThreadInit = LogHttpLogThreadInit; - tmm_modules[TMM_LOGHTTPLOG].ThreadExitPrintStats = LogHttpLogExitPrintStats; - tmm_modules[TMM_LOGHTTPLOG].ThreadDeinit = LogHttpLogThreadDeinit; - tmm_modules[TMM_LOGHTTPLOG].RegisterTests = NULL; - tmm_modules[TMM_LOGHTTPLOG].cap_flags = 0; - tmm_modules[TMM_LOGHTTPLOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterTxModule(MODULE_NAME, "http-log", LogHttpLogInitCtx, - ALPROTO_HTTP, LogHttpLogger, NULL, NULL, NULL); + ALPROTO_HTTP, LogHttpLogger, LogHttpLogThreadInit, + LogHttpLogThreadDeinit, LogHttpLogExitPrintStats); } #define LOG_HTTP_MAXN_NODES 64 diff --git a/src/tm-modules.c b/src/tm-modules.c index 7b79668eeee1..df0b21ecc8f2 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -214,7 +214,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_ALERTUNIFIED2ALERT); CASE_CODE (TMM_ALERTDEBUGLOG); CASE_CODE (TMM_RESPONDREJECT); - CASE_CODE (TMM_LOGHTTPLOG); CASE_CODE (TMM_LOGTLSLOG); CASE_CODE (TMM_LOGTCPDATALOG); CASE_CODE (TMM_PCAPLOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 1b2824a2a3bc..861bd8e6f79f 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -44,7 +44,6 @@ typedef enum { TMM_ALERTUNIFIED2ALERT, TMM_ALERTDEBUGLOG, TMM_RESPONDREJECT, - TMM_LOGHTTPLOG, TMM_LOGTLSLOG, TMM_LOGTCPDATALOG, TMM_OUTPUTJSON, From b580016c805d05a0d57964d914504ed7a9105c9f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 10:39:50 -0600 Subject: [PATCH 1661/2553] logging: convert stats loggers to non-thread module --- src/log-stats.c | 12 +++------ src/output-json-stats.c | 22 ++++------------- src/output-stats.c | 54 +++++++++++++++-------------------------- src/output-stats.h | 4 ++- src/output.c | 14 +++++++++-- src/output.h | 8 ++++-- src/runmodes.c | 4 ++- src/tm-modules.c | 2 -- src/tm-threads-common.h | 2 -- 9 files changed, 52 insertions(+), 70 deletions(-) diff --git a/src/log-stats.c b/src/log-stats.c index a02e4a1225a3..51cb56c4817e 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -296,13 +296,7 @@ static void LogStatsLogDeInitCtx(OutputCtx *output_ctx) void TmModuleLogStatsLogRegister (void) { - tmm_modules[TMM_LOGSTATSLOG].name = MODULE_NAME; - tmm_modules[TMM_LOGSTATSLOG].ThreadInit = LogStatsLogThreadInit; - tmm_modules[TMM_LOGSTATSLOG].ThreadExitPrintStats = LogStatsLogExitPrintStats; - tmm_modules[TMM_LOGSTATSLOG].ThreadDeinit = LogStatsLogThreadDeinit; - tmm_modules[TMM_LOGSTATSLOG].RegisterTests = NULL; - tmm_modules[TMM_LOGSTATSLOG].cap_flags = 0; - tmm_modules[TMM_LOGSTATSLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterStatsModule(MODULE_NAME, "stats", LogStatsLogInitCtx, LogStatsLogger); + OutputRegisterStatsModule(MODULE_NAME, "stats", LogStatsLogInitCtx, + LogStatsLogger, LogStatsLogThreadInit, LogStatsLogThreadDeinit, + LogStatsLogExitPrintStats); } diff --git a/src/output-json-stats.c b/src/output-json-stats.c index 3f45732bb443..dbfba0c43cf7 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -372,34 +372,22 @@ OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) } void TmModuleJsonStatsLogRegister (void) { - tmm_modules[TMM_JSONSTATSLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONSTATSLOG].ThreadInit = JsonStatsLogThreadInit; - tmm_modules[TMM_JSONSTATSLOG].ThreadDeinit = JsonStatsLogThreadDeinit; - tmm_modules[TMM_JSONSTATSLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONSTATSLOG].cap_flags = 0; - tmm_modules[TMM_JSONSTATSLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ OutputRegisterStatsModule(MODULE_NAME, "stats-json", OutputStatsLogInit, - JsonStatsLogger); + JsonStatsLogger, JsonStatsLogThreadInit, JsonStatsLogThreadDeinit, + NULL); /* also register as child of eve-log */ OutputRegisterStatsSubModule("eve-log", MODULE_NAME, "eve-log.stats", - OutputStatsLogInitSub, JsonStatsLogger); + OutputStatsLogInitSub, JsonStatsLogger, JsonStatsLogThreadInit, + JsonStatsLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonStatsLogRegister (void) { - tmm_modules[TMM_JSONSTATSLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONSTATSLOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-stats.c b/src/output-stats.c index 8309755de62c..47fedf05c775 100644 --- a/src/output-stats.c +++ b/src/output-stats.c @@ -46,17 +46,18 @@ typedef struct OutputStatsLogger_ { OutputCtx *output_ctx; struct OutputStatsLogger_ *next; const char *name; - TmmId module_id; + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; } OutputStatsLogger; static OutputStatsLogger *list = NULL; -int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, OutputCtx *output_ctx) +int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; - OutputStatsLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -65,7 +66,9 @@ int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, OutputCtx * op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; - op->module_id = (TmmId) module_id; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; if (list == NULL) list = op; @@ -126,16 +129,9 @@ static TmEcode OutputStatsLogThreadInit(ThreadVars *tv, void *initdata, void **d OutputStatsLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -170,15 +166,12 @@ static TmEcode OutputStatsLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputStatsLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); + } else { + /* XXX Temporary. */ + SCLogNotice("Logger {%s} does not have ThreadDeinit.", + logger->name); } OutputLoggerThreadStore *next_store = store->next; @@ -198,15 +191,8 @@ static void OutputStatsLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputStatsLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; diff --git a/src/output-stats.h b/src/output-stats.h index 75017ca20c4e..eba72f36e410 100644 --- a/src/output-stats.h +++ b/src/output-stats.h @@ -46,7 +46,9 @@ TmEcode OutputStatsLog(ThreadVars *tv, void *thread_data, StatsTable *st); typedef int (*StatsLogger)(ThreadVars *, void *thread_data, const StatsTable *); -int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, OutputCtx *); +int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, + OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void TmModuleStatsLoggerRegister (void); diff --git a/src/output.c b/src/output.c index 5d121b32947b..84fe7fab2eed 100644 --- a/src/output.c +++ b/src/output.c @@ -637,7 +637,9 @@ OutputRegisterStreamingSubModule(const char *parent_name, const char *name, */ void OutputRegisterStatsModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), StatsLogger StatsLogFunc) + OutputCtx *(*InitFunc)(ConfNode *), StatsLogger StatsLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(StatsLogFunc == NULL)) { goto error; @@ -652,6 +654,9 @@ OutputRegisterStatsModule(const char *name, const char *conf_name, module->conf_name = conf_name; module->InitFunc = InitFunc; module->StatsLogFunc = StatsLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Stats logger \"%s\" registered.", name); @@ -672,7 +677,9 @@ OutputRegisterStatsModule(const char *name, const char *conf_name, void OutputRegisterStatsSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - StatsLogger StatsLogFunc) + StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(StatsLogFunc == NULL)) { goto error; @@ -688,6 +695,9 @@ OutputRegisterStatsSubModule(const char *parent_name, const char *name, module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->StatsLogFunc = StatsLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Stats logger \"%s\" registered.", name); diff --git a/src/output.h b/src/output.h index 9a6296ffc258..a895fdc310b2 100644 --- a/src/output.h +++ b/src/output.h @@ -147,10 +147,14 @@ void OutputRegisterStreamingSubModule(const char *parent_name, const char *name, StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type); void OutputRegisterStatsModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), StatsLogger StatsLogFunc); + OutputCtx *(*InitFunc)(ConfNode *), StatsLogger StatsLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterStatsSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - StatsLogger StatsLogFunc); + StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); OutputModule *OutputGetModuleByConfName(const char *name); void OutputDeregisterAll(void); diff --git a/src/runmodes.c b/src/runmodes.c index 6c0d9918c8e3..a22436a0969a 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -592,7 +592,9 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } /* stats logger doesn't run in the packet path */ if (module->StatsLogFunc) { - OutputRegisterStatsLogger(module->name, module->StatsLogFunc, output_ctx); + OutputRegisterStatsLogger(module->name, module->StatsLogFunc, + output_ctx,module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); return; } diff --git a/src/tm-modules.c b/src/tm-modules.c index df0b21ecc8f2..c333367e36b0 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -240,14 +240,12 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_FILEDATALOGGER); CASE_CODE (TMM_STREAMINGLOGGER); CASE_CODE (TMM_JSONFILELOG); - CASE_CODE (TMM_JSONSTATSLOG); CASE_CODE (TMM_OUTPUTJSON); CASE_CODE (TMM_FLOWMANAGER); CASE_CODE (TMM_FLOWRECYCLER); CASE_CODE (TMM_UNIXMANAGER); CASE_CODE (TMM_DETECTLOADER); CASE_CODE (TMM_LUALOG); - CASE_CODE (TMM_LOGSTATSLOG); CASE_CODE (TMM_RECEIVENETMAP); CASE_CODE (TMM_DECODENETMAP); CASE_CODE (TMM_TLSSTORE); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 861bd8e6f79f..75916590d730 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -72,11 +72,9 @@ typedef enum { TMM_FILELOGGER, TMM_FILEDATALOGGER, TMM_STREAMINGLOGGER, - TMM_JSONSTATSLOG, TMM_JSONFILELOG, TMM_RECEIVENFLOG, TMM_DECODENFLOG, - TMM_LOGSTATSLOG, TMM_FLOWMANAGER, TMM_FLOWRECYCLER, From 669827ae169c22ca5de14d8e19d8337f17402202 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 10:45:11 -0600 Subject: [PATCH 1662/2553] logging: convert unified2 to non-thread module --- src/alert-unified2-alert.c | 13 +++---------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 8619f5a2a50d..89b588d0e2d4 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -235,17 +235,10 @@ int Unified2Logger(ThreadVars *tv, void *data, const Packet *p); void TmModuleUnified2AlertRegister(void) { - tmm_modules[TMM_ALERTUNIFIED2ALERT].name = MODULE_NAME; - tmm_modules[TMM_ALERTUNIFIED2ALERT].ThreadInit = Unified2AlertThreadInit; -// tmm_modules[TMM_ALERTUNIFIED2ALERT].Func = Unified2Alert; - tmm_modules[TMM_ALERTUNIFIED2ALERT].ThreadDeinit = Unified2AlertThreadDeinit; - tmm_modules[TMM_ALERTUNIFIED2ALERT].RegisterTests = Unified2RegisterTests; - tmm_modules[TMM_ALERTUNIFIED2ALERT].cap_flags = 0; - tmm_modules[TMM_ALERTUNIFIED2ALERT].flags = TM_FLAG_LOGAPI_TM; - - //OutputRegisterModule(MODULE_NAME, "unified2-alert", Unified2AlertInitCtx); OutputRegisterPacketModule(MODULE_NAME, "unified2-alert", - Unified2AlertInitCtx, Unified2Logger, Unified2Condition, NULL, NULL, NULL); + Unified2AlertInitCtx, Unified2Logger, Unified2Condition, + Unified2AlertThreadInit, Unified2AlertThreadDeinit, NULL); + Unified2RegisterTests(); } /** diff --git a/src/tm-modules.c b/src/tm-modules.c index c333367e36b0..48b869bfca73 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -211,7 +211,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_DECODEPCAPFILE); CASE_CODE (TMM_RECEIVEPFRING); CASE_CODE (TMM_DECODEPFRING); - CASE_CODE (TMM_ALERTUNIFIED2ALERT); CASE_CODE (TMM_ALERTDEBUGLOG); CASE_CODE (TMM_RESPONDREJECT); CASE_CODE (TMM_LOGTLSLOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 75916590d730..0544350075f4 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -41,7 +41,6 @@ typedef enum { TMM_DECODEPCAPFILE, TMM_RECEIVEPFRING, TMM_DECODEPFRING, - TMM_ALERTUNIFIED2ALERT, TMM_ALERTDEBUGLOG, TMM_RESPONDREJECT, TMM_LOGTLSLOG, From f9bb9029c543d376a81ad59a824d470026caacba Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 11:59:13 -0600 Subject: [PATCH 1663/2553] logging: convert file logging to non-thread module --- src/log-file.c | 12 ++--------- src/output-file.c | 48 +++++++++++++++++------------------------ src/output-file.h | 4 +++- src/output-json-file.c | 17 +++------------ src/output.c | 14 ++++++++++-- src/output.h | 8 +++++-- src/runmodes.c | 4 +++- src/tm-modules.c | 2 -- src/tm-threads-common.h | 2 -- 9 files changed, 49 insertions(+), 62 deletions(-) diff --git a/src/log-file.c b/src/log-file.c index 402bf936a276..5a7e4b87a389 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -455,17 +455,9 @@ int LogFileLogOpenFileCtx(LogFileCtx *file_ctx, const char *filename, const void TmModuleLogFileLogRegister (void) { - tmm_modules[TMM_FILELOG].name = MODULE_NAME; - tmm_modules[TMM_FILELOG].ThreadInit = LogFileLogThreadInit; - tmm_modules[TMM_FILELOG].Func = NULL; - tmm_modules[TMM_FILELOG].ThreadExitPrintStats = LogFileLogExitPrintStats; - tmm_modules[TMM_FILELOG].ThreadDeinit = LogFileLogThreadDeinit; - tmm_modules[TMM_FILELOG].RegisterTests = NULL; - tmm_modules[TMM_FILELOG].cap_flags = 0; - tmm_modules[TMM_FILELOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterFileModule(MODULE_NAME, "file-log", LogFileLogInitCtx, - LogFileLogger); + LogFileLogger, LogFileLogThreadInit, LogFileLogThreadDeinit, + LogFileLogExitPrintStats); SCLogDebug("registered"); } diff --git a/src/output-file.c b/src/output-file.c index 7defa39a0b0d..50075c5b66e2 100644 --- a/src/output-file.c +++ b/src/output-file.c @@ -51,15 +51,23 @@ typedef struct OutputFileLogger_ { struct OutputFileLogger_ *next; const char *name; TmmId module_id; + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; } OutputFileLogger; static OutputFileLogger *list = NULL; -int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, OutputCtx *output_ctx) +int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { +#if 0 int module_id = TmModuleGetIdByName(name); if (module_id < 0) return -1; +#endif OutputFileLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) @@ -69,7 +77,12 @@ int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, OutputCtx *ou op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; +#if 0 op->module_id = (TmmId) module_id; +#endif + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; if (list == NULL) list = op; @@ -190,16 +203,9 @@ static TmEcode OutputFileLogThreadInit(ThreadVars *tv, void *initdata, void **da OutputFileLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -233,15 +239,8 @@ static TmEcode OutputFileLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputFileLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -261,15 +260,8 @@ static void OutputFileLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputFileLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; diff --git a/src/output-file.h b/src/output-file.h index 8b203e267c1d..75f3d8860bb5 100644 --- a/src/output-file.h +++ b/src/output-file.h @@ -37,7 +37,9 @@ typedef int (*FileLogger)(ThreadVars *, void *thread_data, const Packet *, const */ //typedef int (*TxLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, OutputCtx *); +int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, OutputCtx *, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void TmModuleFileLoggerRegister (void); diff --git a/src/output-json-file.c b/src/output-json-file.c index a06628225a3f..273750dc9399 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -290,28 +290,17 @@ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) void TmModuleJsonFileLogRegister (void) { - tmm_modules[TMM_JSONFILELOG].name = "JsonFileLog"; - tmm_modules[TMM_JSONFILELOG].ThreadInit = JsonFileLogThreadInit; - tmm_modules[TMM_JSONFILELOG].ThreadDeinit = JsonFileLogThreadDeinit; - tmm_modules[TMM_JSONFILELOG].flags = TM_FLAG_LOGAPI_TM; - /* register as child of eve-log */ OutputRegisterFileSubModule("eve-log", "JsonFileLog", "eve-log.files", - OutputFileLogInitSub, JsonFileLogger); + OutputFileLogInitSub, JsonFileLogger, JsonFileLogThreadInit, + JsonFileLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - void TmModuleJsonFileLogRegister (void) { - tmm_modules[TMM_JSONFILELOG].name = "JsonFileLog"; - tmm_modules[TMM_JSONFILELOG].ThreadInit = OutputJsonThreadInit; + SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output.c b/src/output.c index 84fe7fab2eed..b1262c06a458 100644 --- a/src/output.c +++ b/src/output.c @@ -344,7 +344,9 @@ void OutputRegisterTxSubModule(const char *parent_name, const char *name, */ void OutputRegisterFileModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc) + OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FileLogFunc == NULL)) { goto error; @@ -359,6 +361,9 @@ OutputRegisterFileModule(const char *name, const char *conf_name, module->conf_name = conf_name; module->InitFunc = InitFunc; module->FileLogFunc = FileLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("File logger \"%s\" registered.", name); @@ -379,7 +384,9 @@ OutputRegisterFileModule(const char *name, const char *conf_name, void OutputRegisterFileSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FileLogger FileLogFunc) + FileLogger FileLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FileLogFunc == NULL)) { goto error; @@ -395,6 +402,9 @@ OutputRegisterFileSubModule(const char *parent_name, const char *name, module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->FileLogFunc = FileLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("File logger \"%s\" registered.", name); diff --git a/src/output.h b/src/output.h index a895fdc310b2..72f89c89d746 100644 --- a/src/output.h +++ b/src/output.h @@ -117,10 +117,14 @@ void OutputRegisterTxSubModuleWithProgress(const char *parent_name, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFileModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc); + OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFileSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FileLogger FileLogFunc); + FileLogger FileLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFiledataModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), FiledataLogger FiledataLogFunc); diff --git a/src/runmodes.c b/src/runmodes.c index a22436a0969a..f55dea3ce368 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -684,7 +684,9 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } else if (module->FileLogFunc) { SCLogDebug("%s is a file logger", module->name); - OutputRegisterFileLogger(module->name, module->FileLogFunc, output_ctx); + OutputRegisterFileLogger(module->name, module->FileLogFunc, output_ctx, + module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); /* need one instance of the tx logger module */ if (file_logger_module == NULL) { diff --git a/src/tm-modules.c b/src/tm-modules.c index 48b869bfca73..8175a5e65160 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -216,7 +216,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_LOGTLSLOG); CASE_CODE (TMM_LOGTCPDATALOG); CASE_CODE (TMM_PCAPLOG); - CASE_CODE (TMM_FILELOG); CASE_CODE (TMM_FILESTORE); CASE_CODE (TMM_DECODEIPFW); CASE_CODE (TMM_VERDICTIPFW); @@ -238,7 +237,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_FILELOGGER); CASE_CODE (TMM_FILEDATALOGGER); CASE_CODE (TMM_STREAMINGLOGGER); - CASE_CODE (TMM_JSONFILELOG); CASE_CODE (TMM_OUTPUTJSON); CASE_CODE (TMM_FLOWMANAGER); CASE_CODE (TMM_FLOWRECYCLER); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 0544350075f4..76b357a5ea3e 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -47,7 +47,6 @@ typedef enum { TMM_LOGTCPDATALOG, TMM_OUTPUTJSON, TMM_PCAPLOG, - TMM_FILELOG, TMM_FILESTORE, TMM_DECODEIPFW, TMM_VERDICTIPFW, @@ -71,7 +70,6 @@ typedef enum { TMM_FILELOGGER, TMM_FILEDATALOGGER, TMM_STREAMINGLOGGER, - TMM_JSONFILELOG, TMM_RECEIVENFLOG, TMM_DECODENFLOG, From 60b6ccc3c40696cae23ae3a49bd2aa46b6ac565e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 12:55:50 -0600 Subject: [PATCH 1664/2553] logging: convert file data logging to non-thread module --- src/log-filestore.c | 18 +++++----------- src/output-filedata.c | 48 +++++++++++++++++------------------------ src/output-filedata.h | 4 +++- src/output.c | 14 ++++++++++-- src/output.h | 8 +++++-- src/runmodes.c | 4 +++- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 8 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/log-filestore.c b/src/log-filestore.c index 15c7c9a58619..80c32dfd0a9f 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -481,20 +481,12 @@ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) void TmModuleLogFilestoreRegister (void) { - tmm_modules[TMM_FILESTORE].name = MODULE_NAME; - tmm_modules[TMM_FILESTORE].ThreadInit = LogFilestoreLogThreadInit; - tmm_modules[TMM_FILESTORE].Func = NULL; - tmm_modules[TMM_FILESTORE].ThreadExitPrintStats = LogFilestoreLogExitPrintStats; - tmm_modules[TMM_FILESTORE].ThreadDeinit = LogFilestoreLogThreadDeinit; - tmm_modules[TMM_FILESTORE].RegisterTests = NULL; - tmm_modules[TMM_FILESTORE].cap_flags = 0; - tmm_modules[TMM_FILESTORE].flags = TM_FLAG_LOGAPI_TM; - tmm_modules[TMM_FILESTORE].priority = 10; - OutputRegisterFiledataModule(MODULE_NAME, "file", LogFilestoreLogInitCtx, - LogFilestoreLogger); - OutputRegisterFiledataModule(MODULE_NAME, "file-store", LogFilestoreLogInitCtx, - LogFilestoreLogger); + LogFilestoreLogger, LogFilestoreLogThreadInit, + LogFilestoreLogThreadDeinit, LogFilestoreLogExitPrintStats); + OutputRegisterFiledataModule(MODULE_NAME, "file-store", + LogFilestoreLogInitCtx, LogFilestoreLogger, LogFilestoreLogThreadInit, + LogFilestoreLogThreadDeinit, LogFilestoreLogExitPrintStats); SCLogDebug("registered"); } diff --git a/src/output-filedata.c b/src/output-filedata.c index 43f36c066456..828dac2384df 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -52,6 +52,9 @@ typedef struct OutputFiledataLogger_ { struct OutputFiledataLogger_ *next; const char *name; TmmId module_id; + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; } OutputFiledataLogger; static OutputFiledataLogger *list = NULL; @@ -60,11 +63,16 @@ static SCMutex g_waldo_mutex = SCMUTEX_INITIALIZER; static int g_waldo_init = 0; static int g_waldo_deinit = 0; -int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, OutputCtx *output_ctx) +int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { +#if 0 int module_id = TmModuleGetIdByName(name); if (module_id < 0) return -1; +#endif OutputFiledataLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) @@ -74,7 +82,12 @@ int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, Outpu op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; +#if 0 op->module_id = (TmmId) module_id; +#endif + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; if (list == NULL) list = op; @@ -299,16 +312,9 @@ static TmEcode OutputFiledataLogThreadInit(ThreadVars *tv, void *initdata, void OutputFiledataLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -391,15 +397,8 @@ static TmEcode OutputFiledataLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputFiledataLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -429,15 +428,8 @@ static void OutputFiledataLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputFiledataLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; diff --git a/src/output-filedata.h b/src/output-filedata.h index 3a0a5d4341ed..c9478990aa58 100644 --- a/src/output-filedata.h +++ b/src/output-filedata.h @@ -41,7 +41,9 @@ typedef int (*FiledataLogger)(ThreadVars *, void *thread_data, const Packet *, */ //typedef int (*TxLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, OutputCtx *); +int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, + OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void TmModuleFiledataLoggerRegister (void); diff --git a/src/output.c b/src/output.c index b1262c06a458..1650995d867a 100644 --- a/src/output.c +++ b/src/output.c @@ -424,7 +424,9 @@ OutputRegisterFileSubModule(const char *parent_name, const char *name, */ void OutputRegisterFiledataModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FiledataLogger FiledataLogFunc) + OutputCtx *(*InitFunc)(ConfNode *), FiledataLogger FiledataLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FiledataLogFunc == NULL)) { goto error; @@ -439,6 +441,9 @@ OutputRegisterFiledataModule(const char *name, const char *conf_name, module->conf_name = conf_name; module->InitFunc = InitFunc; module->FiledataLogFunc = FiledataLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Filedata logger \"%s\" registered.", name); @@ -459,7 +464,9 @@ OutputRegisterFiledataModule(const char *name, const char *conf_name, void OutputRegisterFiledataSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FiledataLogger FiledataLogFunc) + FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FiledataLogFunc == NULL)) { goto error; @@ -475,6 +482,9 @@ OutputRegisterFiledataSubModule(const char *parent_name, const char *name, module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->FiledataLogFunc = FiledataLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Filedata logger \"%s\" registered.", name); diff --git a/src/output.h b/src/output.h index 72f89c89d746..007031bc9100 100644 --- a/src/output.h +++ b/src/output.h @@ -127,10 +127,14 @@ void OutputRegisterFileSubModule(const char *parent_name, const char *name, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFiledataModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FiledataLogger FiledataLogFunc); + OutputCtx *(*InitFunc)(ConfNode *), FiledataLogger FiledataLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFiledataSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FiledataLogger FiledataLogFunc); + FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFlowModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), FlowLogger FlowLogFunc, diff --git a/src/runmodes.c b/src/runmodes.c index f55dea3ce368..903f9a99a311 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -662,7 +662,9 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } else if (module->FiledataLogFunc) { SCLogDebug("%s is a filedata logger", module->name); - OutputRegisterFiledataLogger(module->name, module->FiledataLogFunc, output_ctx); + OutputRegisterFiledataLogger(module->name, module->FiledataLogFunc, + output_ctx, module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); /* need one instance of the tx logger module */ if (filedata_logger_module == NULL) { diff --git a/src/tm-modules.c b/src/tm-modules.c index 8175a5e65160..341488b411d9 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -216,7 +216,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_LOGTLSLOG); CASE_CODE (TMM_LOGTCPDATALOG); CASE_CODE (TMM_PCAPLOG); - CASE_CODE (TMM_FILESTORE); CASE_CODE (TMM_DECODEIPFW); CASE_CODE (TMM_VERDICTIPFW); CASE_CODE (TMM_RECEIVEIPFW); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 76b357a5ea3e..58506737486f 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -47,7 +47,6 @@ typedef enum { TMM_LOGTCPDATALOG, TMM_OUTPUTJSON, TMM_PCAPLOG, - TMM_FILESTORE, TMM_DECODEIPFW, TMM_VERDICTIPFW, TMM_RECEIVEIPFW, From 4d8b8ca0461fe80fb7d4f370f9639b3cf9bd8e38 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 13:03:58 -0600 Subject: [PATCH 1665/2553] logging: convert tls store logging to non-thread module --- src/log-tlsstore.c | 15 +++------------ src/output.c | 22 ++++++++++++---------- src/output.h | 16 ++++++++++------ src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c index 317f80ffc4b7..d26d02e50531 100644 --- a/src/log-tlsstore.c +++ b/src/log-tlsstore.c @@ -408,19 +408,10 @@ static OutputCtx *LogTlsStoreLogInitCtx(ConfNode *conf) void TmModuleLogTlsStoreRegister (void) { - tmm_modules[TMM_TLSSTORE].name = MODULE_NAME; - tmm_modules[TMM_TLSSTORE].ThreadInit = LogTlsStoreLogThreadInit; - tmm_modules[TMM_TLSSTORE].Func = NULL; - tmm_modules[TMM_TLSSTORE].ThreadExitPrintStats = LogTlsStoreLogExitPrintStats; - tmm_modules[TMM_TLSSTORE].ThreadDeinit = LogTlsStoreLogThreadDeinit; - tmm_modules[TMM_TLSSTORE].RegisterTests = NULL; - tmm_modules[TMM_TLSSTORE].cap_flags = 0; - tmm_modules[TMM_TLSSTORE].flags = TM_FLAG_LOGAPI_TM; - tmm_modules[TMM_TLSSTORE].priority = 10; - OutputRegisterTxModuleWithCondition(MODULE_NAME, "tls-store", - LogTlsStoreLogInitCtx, ALPROTO_TLS, LogTlsStoreLogger, - LogTlsStoreCondition); + LogTlsStoreLogInitCtx, ALPROTO_TLS, LogTlsStoreLogger, + LogTlsStoreCondition, LogTlsStoreLogThreadInit, + LogTlsStoreLogThreadDeinit, LogTlsStoreLogExitPrintStats); SC_ATOMIC_INIT(cert_id); diff --git a/src/output.c b/src/output.c index 1650995d867a..85840cb18e1b 100644 --- a/src/output.c +++ b/src/output.c @@ -250,23 +250,25 @@ void OutputRegisterTxSubModuleWrapper(const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterTxModuleWithCondition(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc, TxLoggerCondition TxLogCondition) +void OutputRegisterTxModuleWithCondition(const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, - TxLogFunc, -1, -1, TxLogCondition, NULL, NULL, - NULL); + TxLogFunc, -1, -1, TxLogCondition, NULL, NULL, NULL); } void OutputRegisterTxSubModuleWithCondition(const char *parent_name, - const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, - OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, - TxLoggerCondition TxLogCondition) + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, + TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, InitFunc, - alproto, TxLogFunc, -1, -1, - TxLogCondition, NULL, NULL, NULL); + alproto, TxLogFunc, -1, -1, TxLogCondition, NULL, NULL, NULL); } /** diff --git a/src/output.h b/src/output.h index 007031bc9100..073f810cad22 100644 --- a/src/output.h +++ b/src/output.h @@ -94,13 +94,17 @@ void OutputRegisterTxSubModule(const char *parent_name, const char *name, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxModuleWithCondition(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc, TxLoggerCondition TxLogCondition); +void OutputRegisterTxModuleWithCondition(const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterTxSubModuleWithCondition(const char *parent_name, - const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, - OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, - TxLoggerCondition TxLogCondition); + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, + TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, diff --git a/src/tm-modules.c b/src/tm-modules.c index 341488b411d9..49d519e66f70 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -244,7 +244,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_LUALOG); CASE_CODE (TMM_RECEIVENETMAP); CASE_CODE (TMM_DECODENETMAP); - CASE_CODE (TMM_TLSSTORE); CASE_CODE (TMM_SIZE); } diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 58506737486f..dfebc45429a8 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -79,7 +79,6 @@ typedef enum { TMM_UNIXMANAGER, TMM_LUALOG, - TMM_TLSSTORE, TMM_SIZE, } TmmId; From 7a8e8343e52b2d6226c61447400727904a54604e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 13:12:06 -0600 Subject: [PATCH 1666/2553] logging: convert tcp data logging to non-thread module --- src/log-tcp-data.c | 17 ++++++--------- src/output-streaming.c | 47 +++++++++++++++++------------------------ src/output-streaming.h | 6 ++++-- src/output.c | 14 ++++++++++-- src/output.h | 8 +++++-- src/runmodes.c | 3 ++- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 8 files changed, 49 insertions(+), 48 deletions(-) diff --git a/src/log-tcp-data.c b/src/log-tcp-data.c index c3dadd4416b7..b1ebfca39761 100644 --- a/src/log-tcp-data.c +++ b/src/log-tcp-data.c @@ -61,18 +61,13 @@ static void LogTcpDataLogDeInitCtx(OutputCtx *); int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags); void TmModuleLogTcpDataLogRegister (void) { - tmm_modules[TMM_LOGTCPDATALOG].name = MODULE_NAME; - tmm_modules[TMM_LOGTCPDATALOG].ThreadInit = LogTcpDataLogThreadInit; - tmm_modules[TMM_LOGTCPDATALOG].ThreadExitPrintStats = LogTcpDataLogExitPrintStats; - tmm_modules[TMM_LOGTCPDATALOG].ThreadDeinit = LogTcpDataLogThreadDeinit; - tmm_modules[TMM_LOGTCPDATALOG].RegisterTests = NULL; - tmm_modules[TMM_LOGTCPDATALOG].cap_flags = 0; - tmm_modules[TMM_LOGTCPDATALOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterStreamingModule(MODULE_NAME, "tcp-data", LogTcpDataLogInitCtx, - LogTcpDataLogger, STREAMING_TCP_DATA); - OutputRegisterStreamingModule(MODULE_NAME, "http-body-data", LogTcpDataLogInitCtx, - LogTcpDataLogger, STREAMING_HTTP_BODIES); + LogTcpDataLogger, STREAMING_TCP_DATA, LogTcpDataLogThreadInit, + LogTcpDataLogThreadDeinit, LogTcpDataLogExitPrintStats); + OutputRegisterStreamingModule(MODULE_NAME, "http-body-data", + LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_HTTP_BODIES, + LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, + LogTcpDataLogExitPrintStats); } typedef struct LogTcpDataFileCtx_ { diff --git a/src/output-streaming.c b/src/output-streaming.c index 295506620347..b72a38a44f77 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -55,16 +55,23 @@ typedef struct OutputStreamingLogger_ { const char *name; TmmId module_id; enum OutputStreamingType type; + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; } OutputStreamingLogger; static OutputStreamingLogger *list = NULL; int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, - OutputCtx *output_ctx, enum OutputStreamingType type ) + OutputCtx *output_ctx, enum OutputStreamingType type, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { +#if 0 int module_id = TmModuleGetIdByName(name); if (module_id < 0) return -1; +#endif OutputStreamingLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) @@ -74,8 +81,13 @@ int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; +#if 0 op->module_id = (TmmId) module_id; +#endif op->type = type; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; if (list == NULL) list = op; @@ -368,16 +380,9 @@ static TmEcode OutputStreamingLogThreadInit(ThreadVars *tv, void *initdata, void OutputStreamingLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -412,15 +417,8 @@ static TmEcode OutputStreamingLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputStreamingLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } logger = logger->next; @@ -436,15 +434,8 @@ static void OutputStreamingLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputStreamingLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; diff --git a/src/output-streaming.h b/src/output-streaming.h index 8b3037422875..9508903a8a03 100644 --- a/src/output-streaming.h +++ b/src/output-streaming.h @@ -45,8 +45,10 @@ typedef int (*StreamingLogger)(ThreadVars *, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags); -int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, OutputCtx *, - enum OutputStreamingType); +int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, + OutputCtx *, enum OutputStreamingType, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void TmModuleStreamingLoggerRegister (void); diff --git a/src/output.c b/src/output.c index 85840cb18e1b..351cd294aec8 100644 --- a/src/output.c +++ b/src/output.c @@ -587,7 +587,9 @@ OutputRegisterFlowSubModule(const char *parent_name, const char *name, void OutputRegisterStreamingModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), StreamingLogger StreamingLogFunc, - enum OutputStreamingType stream_type) + enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(StreamingLogFunc == NULL)) { goto error; @@ -603,6 +605,9 @@ OutputRegisterStreamingModule(const char *name, const char *conf_name, module->InitFunc = InitFunc; module->StreamingLogFunc = StreamingLogFunc; module->stream_type = stream_type; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Streaming logger \"%s\" registered.", name); @@ -623,7 +628,9 @@ OutputRegisterStreamingModule(const char *name, const char *conf_name, void OutputRegisterStreamingSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type) + StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(StreamingLogFunc == NULL)) { goto error; @@ -640,6 +647,9 @@ OutputRegisterStreamingSubModule(const char *parent_name, const char *name, module->InitSubFunc = InitFunc; module->StreamingLogFunc = StreamingLogFunc; module->stream_type = stream_type; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Streaming logger \"%s\" registered.", name); diff --git a/src/output.h b/src/output.h index 073f810cad22..e34d34379d74 100644 --- a/src/output.h +++ b/src/output.h @@ -153,10 +153,14 @@ void OutputRegisterFlowSubModule(const char *parent_name, const char *name, void OutputRegisterStreamingModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), StreamingLogger StreamingLogFunc, - enum OutputStreamingType stream_type); + enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterStreamingSubModule(const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type); + StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterStatsModule(const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), StatsLogger StatsLogFunc, diff --git a/src/runmodes.c b/src/runmodes.c index 903f9a99a311..3f043b9409f6 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -711,7 +711,8 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } else if (module->StreamingLogFunc) { SCLogDebug("%s is a streaming logger", module->name); OutputRegisterStreamingLogger(module->name, module->StreamingLogFunc, - output_ctx, module->stream_type); + output_ctx, module->stream_type, module->ThreadInit, + module->ThreadDeinit, module->ThreadExitPrintStats); /* need one instance of the streaming logger module */ if (streaming_logger_module == NULL) { diff --git a/src/tm-modules.c b/src/tm-modules.c index 49d519e66f70..cab153838463 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -214,7 +214,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_ALERTDEBUGLOG); CASE_CODE (TMM_RESPONDREJECT); CASE_CODE (TMM_LOGTLSLOG); - CASE_CODE (TMM_LOGTCPDATALOG); CASE_CODE (TMM_PCAPLOG); CASE_CODE (TMM_DECODEIPFW); CASE_CODE (TMM_VERDICTIPFW); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index dfebc45429a8..b528053b1e67 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -44,7 +44,6 @@ typedef enum { TMM_ALERTDEBUGLOG, TMM_RESPONDREJECT, TMM_LOGTLSLOG, - TMM_LOGTCPDATALOG, TMM_OUTPUTJSON, TMM_PCAPLOG, TMM_DECODEIPFW, From 7cb16bc90d9fadc5ea821c1b426539944ac3e2fd Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 13:16:22 -0600 Subject: [PATCH 1667/2553] logging: convert alert debug log to non-thread module --- src/alert-debuglog.c | 13 +++---------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 212e90c16161..1c0b4640dcbb 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -512,15 +512,8 @@ static int AlertDebugLogLogger(ThreadVars *tv, void *thread_data, const Packet * void TmModuleAlertDebugLogRegister (void) { - tmm_modules[TMM_ALERTDEBUGLOG].name = MODULE_NAME; - tmm_modules[TMM_ALERTDEBUGLOG].ThreadInit = AlertDebugLogThreadInit; - tmm_modules[TMM_ALERTDEBUGLOG].Func = NULL; - tmm_modules[TMM_ALERTDEBUGLOG].ThreadExitPrintStats = AlertDebugLogExitPrintStats; - tmm_modules[TMM_ALERTDEBUGLOG].ThreadDeinit = AlertDebugLogThreadDeinit; - tmm_modules[TMM_ALERTDEBUGLOG].RegisterTests = NULL; - tmm_modules[TMM_ALERTDEBUGLOG].cap_flags = 0; - tmm_modules[TMM_ALERTDEBUGLOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterPacketModule(MODULE_NAME, "alert-debug", - AlertDebugLogInitCtx, AlertDebugLogLogger, AlertDebugLogCondition, NULL, NULL, NULL); + AlertDebugLogInitCtx, AlertDebugLogLogger, AlertDebugLogCondition, + AlertDebugLogThreadInit, AlertDebugLogThreadDeinit, + AlertDebugLogExitPrintStats); } diff --git a/src/tm-modules.c b/src/tm-modules.c index cab153838463..d12089d0aae5 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -211,7 +211,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_DECODEPCAPFILE); CASE_CODE (TMM_RECEIVEPFRING); CASE_CODE (TMM_DECODEPFRING); - CASE_CODE (TMM_ALERTDEBUGLOG); CASE_CODE (TMM_RESPONDREJECT); CASE_CODE (TMM_LOGTLSLOG); CASE_CODE (TMM_PCAPLOG); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index b528053b1e67..0938b2f611d5 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -41,7 +41,6 @@ typedef enum { TMM_DECODEPCAPFILE, TMM_RECEIVEPFRING, TMM_DECODEPFRING, - TMM_ALERTDEBUGLOG, TMM_RESPONDREJECT, TMM_LOGTLSLOG, TMM_OUTPUTJSON, From 7a0737b9a9ce074693f3452f8200d0708936f47c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 3 Jun 2016 10:48:10 -0600 Subject: [PATCH 1668/2553] logging: convert tls log to non-thread module --- src/log-tlslog.c | 10 +--------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/log-tlslog.c b/src/log-tlslog.c index d0274f222a54..0239606362ea 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -314,15 +314,7 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, void TmModuleLogTlsLogRegister(void) { - tmm_modules[TMM_LOGTLSLOG].name = MODULE_NAME; - tmm_modules[TMM_LOGTLSLOG].ThreadInit = LogTlsLogThreadInit; - tmm_modules[TMM_LOGTLSLOG].ThreadExitPrintStats = LogTlsLogExitPrintStats; - tmm_modules[TMM_LOGTLSLOG].ThreadDeinit = LogTlsLogThreadDeinit; - tmm_modules[TMM_LOGTLSLOG].RegisterTests = NULL; - tmm_modules[TMM_LOGTLSLOG].cap_flags = 0; - tmm_modules[TMM_LOGTLSLOG].flags = TM_FLAG_LOGAPI_TM; - OutputRegisterTxModuleWithProgress(MODULE_NAME, "tls-log", LogTlsLogInitCtx, ALPROTO_TLS, LogTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, - NULL, NULL, NULL); + LogTlsLogThreadInit, LogTlsLogThreadDeinit, LogTlsLogExitPrintStats); } diff --git a/src/tm-modules.c b/src/tm-modules.c index d12089d0aae5..d2c22aefefa0 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -212,7 +212,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_RECEIVEPFRING); CASE_CODE (TMM_DECODEPFRING); CASE_CODE (TMM_RESPONDREJECT); - CASE_CODE (TMM_LOGTLSLOG); CASE_CODE (TMM_PCAPLOG); CASE_CODE (TMM_DECODEIPFW); CASE_CODE (TMM_VERDICTIPFW); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 0938b2f611d5..eb455888d202 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -42,7 +42,6 @@ typedef enum { TMM_RECEIVEPFRING, TMM_DECODEPFRING, TMM_RESPONDREJECT, - TMM_LOGTLSLOG, TMM_OUTPUTJSON, TMM_PCAPLOG, TMM_DECODEIPFW, From 42b8f302727ee416e010273669f5da573017074a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 31 May 2016 10:23:34 -0600 Subject: [PATCH 1669/2553] logging: convert lua output to non-thread module --- src/output-lua.c | 12 +++++------- src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/output-lua.c b/src/output-lua.c index d053487da901..7d3ae065e502 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -84,6 +84,9 @@ typedef struct LogLuaThreadCtx_ { LogLuaCtx *lua_ctx; } LogLuaThreadCtx; +static TmEcode LuaLogThreadInit(ThreadVars *t, void *initdata, void **data); +static TmEcode LuaLogThreadDeinit(ThreadVars *t, void *data); + /** \internal * \brief TX logger for lua scripts * @@ -858,6 +861,8 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) om->name = MODULE_NAME; om->conf_name = script->val; om->InitSubFunc = OutputLuaLogInitSub; + om->ThreadInit = LuaLogThreadInit; + om->ThreadDeinit = LuaLogThreadDeinit; if (opts.alproto == ALPROTO_HTTP && opts.streaming) { om->StreamingLogFunc = LuaStreamingLogger; @@ -996,13 +1001,6 @@ static TmEcode LuaLogThreadDeinit(ThreadVars *t, void *data) } void TmModuleLuaLogRegister (void) { - tmm_modules[TMM_LUALOG].name = MODULE_NAME; - tmm_modules[TMM_LUALOG].ThreadInit = LuaLogThreadInit; - tmm_modules[TMM_LUALOG].ThreadDeinit = LuaLogThreadDeinit; - tmm_modules[TMM_LUALOG].RegisterTests = NULL; - tmm_modules[TMM_LUALOG].cap_flags = 0; - tmm_modules[TMM_LUALOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ OutputRegisterModule(MODULE_NAME, "lua", OutputLuaLogInit); } diff --git a/src/tm-modules.c b/src/tm-modules.c index d2c22aefefa0..d47637f29605 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -238,7 +238,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_FLOWRECYCLER); CASE_CODE (TMM_UNIXMANAGER); CASE_CODE (TMM_DETECTLOADER); - CASE_CODE (TMM_LUALOG); CASE_CODE (TMM_RECEIVENETMAP); CASE_CODE (TMM_DECODENETMAP); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index eb455888d202..c9a449bcde5f 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -75,7 +75,6 @@ typedef enum { TMM_UNIXMANAGER, - TMM_LUALOG, TMM_SIZE, } TmmId; From fa27a7646255ad684264b6d21e035344ff069d89 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 27 May 2016 18:57:06 -0600 Subject: [PATCH 1670/2553] logging: add profiling back for non-tmm loggers The loggers moved away from a TMM required a new profiling support. --- src/alert-debuglog.c | 2 +- src/alert-fastlog.c | 7 +- src/alert-prelude.c | 2 +- src/alert-syslog.c | 2 +- src/alert-unified2-alert.c | 2 +- src/decode.h | 7 ++ src/log-dnslog.c | 2 +- src/log-droplog.c | 6 +- src/log-file.c | 6 +- src/log-filestore.c | 6 +- src/log-httplog.c | 4 +- src/log-stats.c | 6 +- src/log-tcp-data.c | 9 +-- src/log-tlslog.c | 7 +- src/log-tlsstore.c | 4 +- src/output-file.c | 18 ++--- src/output-file.h | 4 +- src/output-filedata.c | 20 ++---- src/output-filedata.h | 5 +- src/output-json-alert.c | 9 +-- src/output-json-dns.c | 26 +++---- src/output-json-drop.c | 9 +-- src/output-json-file.c | 6 +- src/output-json-flow.c | 8 +-- src/output-json-http.c | 8 +-- src/output-json-netflow.c | 12 ++-- src/output-json-smtp.c | 8 +-- src/output-json-ssh.c | 8 +-- src/output-json-stats.c | 12 ++-- src/output-json-template.c | 7 +- src/output-json-tls.c | 15 ++-- src/output-packet.c | 24 +++---- src/output-packet.h | 7 +- src/output-streaming.c | 23 +++--- src/output-streaming.h | 6 +- src/output-tx.c | 13 ++-- src/output-tx.h | 3 +- src/output.c | 118 +++++++++++++++++++------------ src/output.h | 91 +++++++++++++----------- src/runmodes.c | 60 +++++----------- src/suricata-common.h | 31 ++++++++ src/util-profiling.c | 141 ++++++++++++++++++++++++++++++++++++- src/util-profiling.h | 22 ++++++ 43 files changed, 488 insertions(+), 298 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 1c0b4640dcbb..931fa70cba41 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -512,7 +512,7 @@ static int AlertDebugLogLogger(ThreadVars *tv, void *thread_data, const Packet * void TmModuleAlertDebugLogRegister (void) { - OutputRegisterPacketModule(MODULE_NAME, "alert-debug", + OutputRegisterPacketModule(LOGGER_ALERT_DEBUG, MODULE_NAME, "alert-debug", AlertDebugLogInitCtx, AlertDebugLogLogger, AlertDebugLogCondition, AlertDebugLogThreadInit, AlertDebugLogThreadDeinit, AlertDebugLogExitPrintStats); diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 59ff045e02af..42d601997c27 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -78,9 +78,10 @@ int AlertFastLogger(ThreadVars *tv, void *data, const Packet *p); void TmModuleAlertFastLogRegister (void) { - OutputRegisterPacketModule(MODULE_NAME, "fast", AlertFastLogInitCtx, - AlertFastLogger, AlertFastLogCondition, AlertFastLogThreadInit, - AlertFastLogThreadDeinit, AlertFastLogExitPrintStats); + OutputRegisterPacketModule(LOGGER_ALERT_FAST, MODULE_NAME, "fast", + AlertFastLogInitCtx, AlertFastLogger, AlertFastLogCondition, + AlertFastLogThreadInit, AlertFastLogThreadDeinit, + AlertFastLogExitPrintStats); AlertFastLogRegisterTests(); } diff --git a/src/alert-prelude.c b/src/alert-prelude.c index b29e885fa9ce..399641015581 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -916,7 +916,7 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p void TmModuleAlertPreludeRegister (void) { - OutputRegisterPacketModule("AlertPrelude", "alert-prelude", + OutputRegisterPacketModule(LOGGER_PRELUDE, "AlertPrelude", "alert-prelude", AlertPreludeInitCtx, AlertPreludeLogger, AlertPreludeCondition, AlertPreludeThreadInit, AlertPreludeThreadDeinit, NULL); } diff --git a/src/alert-syslog.c b/src/alert-syslog.c index a48b99f7a23b..3d312c9a01d2 100644 --- a/src/alert-syslog.c +++ b/src/alert-syslog.c @@ -411,7 +411,7 @@ static int AlertSyslogLogger(ThreadVars *tv, void *thread_data, const Packet *p) void TmModuleAlertSyslogRegister (void) { #ifndef OS_WIN32 - OutputRegisterPacketModule(MODULE_NAME, "syslog", + OutputRegisterPacketModule(LOGGER_ALERT_SYSLOG, MODULE_NAME, "syslog", AlertSyslogInitCtx, AlertSyslogLogger, AlertSyslogCondition, AlertSyslogThreadInit, AlertSyslogThreadDeinit, AlertSyslogExitPrintStats); diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 89b588d0e2d4..a39a328c5eff 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -235,7 +235,7 @@ int Unified2Logger(ThreadVars *tv, void *data, const Packet *p); void TmModuleUnified2AlertRegister(void) { - OutputRegisterPacketModule(MODULE_NAME, "unified2-alert", + OutputRegisterPacketModule(LOGGER_UNIFIED2, MODULE_NAME, "unified2-alert", Unified2AlertInitCtx, Unified2Logger, Unified2Condition, Unified2AlertThreadInit, Unified2AlertThreadDeinit, NULL); Unified2RegisterTests(); diff --git a/src/decode.h b/src/decode.h index 2a5d39d38eae..0a829ec2fa2d 100644 --- a/src/decode.h +++ b/src/decode.h @@ -341,6 +341,12 @@ typedef struct PktProfilingAppData_ { uint64_t ticks_spent; } PktProfilingAppData; +typedef struct PktProfilingLoggerData_ { + uint64_t ticks_start; + uint64_t ticks_end; + uint64_t ticks_spent; +} PktProfilingLoggerData; + /** \brief Per pkt stats storage */ typedef struct PktProfiling_ { uint64_t ticks_start; @@ -350,6 +356,7 @@ typedef struct PktProfiling_ { PktProfilingData flowworker[PROFILE_FLOWWORKER_SIZE]; PktProfilingAppData app[ALPROTO_MAX]; PktProfilingDetectData detect[PROF_DETECT_SIZE]; + PktProfilingLoggerData logger[LOGGER_SIZE]; uint64_t proto_detect; } PktProfiling; diff --git a/src/log-dnslog.c b/src/log-dnslog.c index 5267175d5dd9..418b2dd47926 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -346,7 +346,7 @@ static OutputCtx *LogDnsLogInitCtx(ConfNode *conf) void TmModuleLogDnsLogRegister (void) { - OutputRegisterTxModule(MODULE_NAME, "dns-log", LogDnsLogInitCtx, + OutputRegisterTxModule(LOGGER_DNS, MODULE_NAME, "dns-log", LogDnsLogInitCtx, ALPROTO_DNS, LogDnsLogger, LogDnsLogThreadInit, LogDnsLogThreadDeinit, LogDnsLogExitPrintStats); diff --git a/src/log-droplog.c b/src/log-droplog.c index c680a4233733..03c66c620f4c 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -494,9 +494,9 @@ static void LogDropLogRegisterTests(void) /** \brief function to register the drop log module */ void TmModuleLogDropLogRegister (void) { - OutputRegisterPacketModule(MODULE_NAME, "drop", LogDropLogInitCtx, - LogDropLogger, LogDropCondition, LogDropLogThreadInit, - LogDropLogThreadDeinit, LogDropLogExitPrintStats); + OutputRegisterPacketModule(LOGGER_DROP, MODULE_NAME, "drop", + LogDropLogInitCtx, LogDropLogger, LogDropCondition, + LogDropLogThreadInit, LogDropLogThreadDeinit, LogDropLogExitPrintStats); #ifdef UNITTESTS LogDropLogRegisterTests(); #endif diff --git a/src/log-file.c b/src/log-file.c index 5a7e4b87a389..71e683a42071 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -455,9 +455,9 @@ int LogFileLogOpenFileCtx(LogFileCtx *file_ctx, const char *filename, const void TmModuleLogFileLogRegister (void) { - OutputRegisterFileModule(MODULE_NAME, "file-log", LogFileLogInitCtx, - LogFileLogger, LogFileLogThreadInit, LogFileLogThreadDeinit, - LogFileLogExitPrintStats); + OutputRegisterFileModule(LOGGER_FILE, MODULE_NAME, "file-log", + LogFileLogInitCtx, LogFileLogger, LogFileLogThreadInit, + LogFileLogThreadDeinit, LogFileLogExitPrintStats); SCLogDebug("registered"); } diff --git a/src/log-filestore.c b/src/log-filestore.c index 80c32dfd0a9f..aacd219433c6 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -481,10 +481,10 @@ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) void TmModuleLogFilestoreRegister (void) { - OutputRegisterFiledataModule(MODULE_NAME, "file", LogFilestoreLogInitCtx, - LogFilestoreLogger, LogFilestoreLogThreadInit, + OutputRegisterFiledataModule(LOGGER_FILE_STORE, MODULE_NAME, "file", + LogFilestoreLogInitCtx, LogFilestoreLogger, LogFilestoreLogThreadInit, LogFilestoreLogThreadDeinit, LogFilestoreLogExitPrintStats); - OutputRegisterFiledataModule(MODULE_NAME, "file-store", + OutputRegisterFiledataModule(LOGGER_FILE_STORE, MODULE_NAME, "file-store", LogFilestoreLogInitCtx, LogFilestoreLogger, LogFilestoreLogThreadInit, LogFilestoreLogThreadDeinit, LogFilestoreLogExitPrintStats); diff --git a/src/log-httplog.c b/src/log-httplog.c index 64b825f89134..695b98e53897 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -65,8 +65,8 @@ int LogHttpLogger(ThreadVars *tv, void *thread_data, const Packet *, Flow *f, vo void TmModuleLogHttpLogRegister (void) { - OutputRegisterTxModule(MODULE_NAME, "http-log", LogHttpLogInitCtx, - ALPROTO_HTTP, LogHttpLogger, LogHttpLogThreadInit, + OutputRegisterTxModule(LOGGER_HTTP, MODULE_NAME, "http-log", + LogHttpLogInitCtx, ALPROTO_HTTP, LogHttpLogger, LogHttpLogThreadInit, LogHttpLogThreadDeinit, LogHttpLogExitPrintStats); } diff --git a/src/log-stats.c b/src/log-stats.c index 51cb56c4817e..343fce06ae6f 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -296,7 +296,7 @@ static void LogStatsLogDeInitCtx(OutputCtx *output_ctx) void TmModuleLogStatsLogRegister (void) { - OutputRegisterStatsModule(MODULE_NAME, "stats", LogStatsLogInitCtx, - LogStatsLogger, LogStatsLogThreadInit, LogStatsLogThreadDeinit, - LogStatsLogExitPrintStats); + OutputRegisterStatsModule(LOGGER_STATS, MODULE_NAME, "stats", + LogStatsLogInitCtx, LogStatsLogger, LogStatsLogThreadInit, + LogStatsLogThreadDeinit, LogStatsLogExitPrintStats); } diff --git a/src/log-tcp-data.c b/src/log-tcp-data.c index b1ebfca39761..d56a9fc5889d 100644 --- a/src/log-tcp-data.c +++ b/src/log-tcp-data.c @@ -61,10 +61,11 @@ static void LogTcpDataLogDeInitCtx(OutputCtx *); int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags); void TmModuleLogTcpDataLogRegister (void) { - OutputRegisterStreamingModule(MODULE_NAME, "tcp-data", LogTcpDataLogInitCtx, - LogTcpDataLogger, STREAMING_TCP_DATA, LogTcpDataLogThreadInit, - LogTcpDataLogThreadDeinit, LogTcpDataLogExitPrintStats); - OutputRegisterStreamingModule(MODULE_NAME, "http-body-data", + OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "tcp-data", + LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_TCP_DATA, + LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, + LogTcpDataLogExitPrintStats); + OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "http-body-data", LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_HTTP_BODIES, LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, LogTcpDataLogExitPrintStats); diff --git a/src/log-tlslog.c b/src/log-tlslog.c index 0239606362ea..aa04ad11054a 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -314,7 +314,8 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, void TmModuleLogTlsLogRegister(void) { - OutputRegisterTxModuleWithProgress(MODULE_NAME, "tls-log", LogTlsLogInitCtx, - ALPROTO_TLS, LogTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, - LogTlsLogThreadInit, LogTlsLogThreadDeinit, LogTlsLogExitPrintStats); + OutputRegisterTxModuleWithProgress(LOGGER_TLS, MODULE_NAME, "tls-log", + LogTlsLogInitCtx, ALPROTO_TLS, LogTlsLogger, TLS_HANDSHAKE_DONE, + TLS_HANDSHAKE_DONE, LogTlsLogThreadInit, LogTlsLogThreadDeinit, + LogTlsLogExitPrintStats); } diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c index d26d02e50531..13840af1ec30 100644 --- a/src/log-tlsstore.c +++ b/src/log-tlsstore.c @@ -408,8 +408,8 @@ static OutputCtx *LogTlsStoreLogInitCtx(ConfNode *conf) void TmModuleLogTlsStoreRegister (void) { - OutputRegisterTxModuleWithCondition(MODULE_NAME, "tls-store", - LogTlsStoreLogInitCtx, ALPROTO_TLS, LogTlsStoreLogger, + OutputRegisterTxModuleWithCondition(LOGGER_TLS_STORE, MODULE_NAME, + "tls-store", LogTlsStoreLogInitCtx, ALPROTO_TLS, LogTlsStoreLogger, LogTlsStoreCondition, LogTlsStoreLogThreadInit, LogTlsStoreLogThreadDeinit, LogTlsStoreLogExitPrintStats); diff --git a/src/output-file.c b/src/output-file.c index 50075c5b66e2..995e3200095b 100644 --- a/src/output-file.c +++ b/src/output-file.c @@ -50,7 +50,7 @@ typedef struct OutputFileLogger_ { OutputCtx *output_ctx; struct OutputFileLogger_ *next; const char *name; - TmmId module_id; + LoggerId logger_id; ThreadInitFunc ThreadInit; ThreadDeinitFunc ThreadDeinit; ThreadExitPrintStatsFunc ThreadExitPrintStats; @@ -58,17 +58,11 @@ typedef struct OutputFileLogger_ { static OutputFileLogger *list = NULL; -int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, +int OutputRegisterFileLogger(LoggerId id, const char *name, FileLogger LogFunc, OutputCtx *output_ctx, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { -#if 0 - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; -#endif - OutputFileLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -77,9 +71,7 @@ int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; -#if 0 - op->module_id = (TmmId) module_id; -#endif + op->logger_id = id; op->ThreadInit = ThreadInit; op->ThreadDeinit = ThreadDeinit; op->ThreadExitPrintStats = ThreadExitPrintStats; @@ -162,9 +154,9 @@ static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data, Packe BUG_ON(logger->LogFunc == NULL); SCLogDebug("logger %p", logger); - PACKET_PROFILING_TMM_START(p, logger->module_id); + PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, (const Packet *)p, (const File *)ff); - PACKET_PROFILING_TMM_END(p, logger->module_id); + PACKET_PROFILING_LOGGER_END(p, logger->logger_id); file_logged = 1; logger = logger->next; diff --git a/src/output-file.h b/src/output-file.h index 75f3d8860bb5..3f335447dafe 100644 --- a/src/output-file.h +++ b/src/output-file.h @@ -37,8 +37,8 @@ typedef int (*FileLogger)(ThreadVars *, void *thread_data, const Packet *, const */ //typedef int (*TxLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, OutputCtx *, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, +int OutputRegisterFileLogger(LoggerId id, const char *name, FileLogger LogFunc, + OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void TmModuleFileLoggerRegister (void); diff --git a/src/output-filedata.c b/src/output-filedata.c index 828dac2384df..75e3a83fc341 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -51,7 +51,7 @@ typedef struct OutputFiledataLogger_ { OutputCtx *output_ctx; struct OutputFiledataLogger_ *next; const char *name; - TmmId module_id; + LoggerId logger_id; ThreadInitFunc ThreadInit; ThreadDeinitFunc ThreadDeinit; ThreadExitPrintStatsFunc ThreadExitPrintStats; @@ -63,17 +63,11 @@ static SCMutex g_waldo_mutex = SCMUTEX_INITIALIZER; static int g_waldo_init = 0; static int g_waldo_deinit = 0; -int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, - OutputCtx *output_ctx, ThreadInitFunc ThreadInit, +int OutputRegisterFiledataLogger(LoggerId id, const char *name, + FiledataLogger LogFunc, OutputCtx *output_ctx, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { -#if 0 - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; -#endif - OutputFiledataLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -82,9 +76,7 @@ int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; -#if 0 - op->module_id = (TmmId) module_id; -#endif + op->logger_id = id; op->ThreadInit = ThreadInit; op->ThreadDeinit = ThreadDeinit; op->ThreadExitPrintStats = ThreadExitPrintStats; @@ -116,9 +108,9 @@ static int CallLoggers(ThreadVars *tv, OutputLoggerThreadStore *store_list, BUG_ON(logger->LogFunc == NULL); SCLogDebug("logger %p", logger); - PACKET_PROFILING_TMM_START(p, logger->module_id); + PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, (const Packet *)p, ff, data, data_len, flags); - PACKET_PROFILING_TMM_END(p, logger->module_id); + PACKET_PROFILING_LOGGER_END(p, logger->logger_id); file_logged = 1; diff --git a/src/output-filedata.h b/src/output-filedata.h index c9478990aa58..562eba6bb0fc 100644 --- a/src/output-filedata.h +++ b/src/output-filedata.h @@ -41,8 +41,9 @@ typedef int (*FiledataLogger)(ThreadVars *, void *thread_data, const Packet *, */ //typedef int (*TxLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, - OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, +int OutputRegisterFiledataLogger(LoggerId id, const char *name, + FiledataLogger LogFunc, OutputCtx *, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void TmModuleFiledataLoggerRegister (void); diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 79c8ea0e291a..ac28c6c9d695 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -741,12 +741,13 @@ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) void TmModuleJsonAlertLogRegister (void) { - OutputRegisterPacketModule(MODULE_NAME, "alert-json-log", + OutputRegisterPacketModule(LOGGER_JSON_ALERT, MODULE_NAME, "alert-json-log", JsonAlertLogInitCtx, JsonAlertLogger, JsonAlertLogCondition, JsonAlertLogThreadInit, JsonAlertLogThreadDeinit, NULL); - OutputRegisterPacketSubModule("eve-log", MODULE_NAME, "eve-log.alert", - JsonAlertLogInitCtxSub, JsonAlertLogger, JsonAlertLogCondition, - JsonAlertLogThreadInit, JsonAlertLogThreadDeinit, NULL); + OutputRegisterPacketSubModule(LOGGER_JSON_ALERT, "eve-log", MODULE_NAME, + "eve-log.alert", JsonAlertLogInitCtxSub, JsonAlertLogger, + JsonAlertLogCondition, JsonAlertLogThreadInit, JsonAlertLogThreadDeinit, + NULL); } #else diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 228d575b5d95..8d0e8e76eddc 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -852,24 +852,26 @@ static OutputCtx *JsonDnsLogInitCtx(ConfNode *conf) void TmModuleJsonDnsLogRegister (void) { /* Logger for requests. */ - OutputRegisterTxModuleWithProgress(MODULE_NAME, "dns-json-log", - JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToServer, 0, 1, - LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); + OutputRegisterTxModuleWithProgress(LOGGER_JSON_DNS, MODULE_NAME, + "dns-json-log", JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToServer, + 0, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); /* Logger for replies. */ - OutputRegisterTxModuleWithProgress(MODULE_NAME, "dns-json-log", - JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToClient, 1, 1, - LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); + OutputRegisterTxModuleWithProgress(LOGGER_JSON_DNS, MODULE_NAME, + "dns-json-log", JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToClient, + 1, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); /* Sub-logger for requests. */ - OutputRegisterTxSubModuleWithProgress("eve-log", MODULE_NAME, "eve-log.dns", - JsonDnsLogInitCtxSub, ALPROTO_DNS, JsonDnsLoggerToServer, 0, 1, - LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_DNS, "eve-log", + MODULE_NAME, "eve-log.dns", JsonDnsLogInitCtxSub, ALPROTO_DNS, + JsonDnsLoggerToServer, 0, 1, LogDnsLogThreadInit, + LogDnsLogThreadDeinit, NULL); /* Sub-logger for replies. */ - OutputRegisterTxSubModuleWithProgress("eve-log", MODULE_NAME, "eve-log.dns", - JsonDnsLogInitCtxSub, ALPROTO_DNS, JsonDnsLoggerToClient, 1, 1, - LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_DNS, "eve-log", + MODULE_NAME, "eve-log.dns", JsonDnsLogInitCtxSub, ALPROTO_DNS, + JsonDnsLoggerToClient, 1, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit, + NULL); } #else diff --git a/src/output-json-drop.c b/src/output-json-drop.c index c7a8b18b85c9..fa2c7de00836 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -429,12 +429,13 @@ static int JsonDropLogCondition(ThreadVars *tv, const Packet *p) void TmModuleJsonDropLogRegister (void) { - OutputRegisterPacketModule(MODULE_NAME, "drop-json-log", + OutputRegisterPacketModule(LOGGER_JSON_DROP, MODULE_NAME, "drop-json-log", JsonDropLogInitCtx, JsonDropLogger, JsonDropLogCondition, JsonDropLogThreadInit, JsonDropLogThreadDeinit, NULL); - OutputRegisterPacketSubModule("eve-log", MODULE_NAME, "eve-log.drop", - JsonDropLogInitCtxSub, JsonDropLogger, JsonDropLogCondition, - JsonDropLogThreadInit, JsonDropLogThreadDeinit, NULL); + OutputRegisterPacketSubModule(LOGGER_JSON_DROP, "eve-log", MODULE_NAME, + "eve-log.drop", JsonDropLogInitCtxSub, JsonDropLogger, + JsonDropLogCondition, JsonDropLogThreadInit, JsonDropLogThreadDeinit, + NULL); } #else diff --git a/src/output-json-file.c b/src/output-json-file.c index 273750dc9399..6e1ad571ff06 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -291,9 +291,9 @@ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) void TmModuleJsonFileLogRegister (void) { /* register as child of eve-log */ - OutputRegisterFileSubModule("eve-log", "JsonFileLog", "eve-log.files", - OutputFileLogInitSub, JsonFileLogger, JsonFileLogThreadInit, - JsonFileLogThreadDeinit, NULL); + OutputRegisterFileSubModule(LOGGER_JSON_FILE, "eve-log", "JsonFileLog", + "eve-log.files", OutputFileLogInitSub, JsonFileLogger, + JsonFileLogThreadInit, JsonFileLogThreadDeinit, NULL); } #else diff --git a/src/output-json-flow.c b/src/output-json-flow.c index a55faa3115f1..3a5902779305 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -451,14 +451,14 @@ static TmEcode JsonFlowLogThreadDeinit(ThreadVars *t, void *data) void TmModuleJsonFlowLogRegister (void) { /* register as separate module */ - OutputRegisterFlowModule("JsonFlowLog", "flow-json-log", + OutputRegisterFlowModule(LOGGER_JSON_FLOW, "JsonFlowLog", "flow-json-log", OutputFlowLogInit, JsonFlowLogger, JsonFlowLogThreadInit, JsonFlowLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterFlowSubModule("eve-log", "JsonFlowLog", "eve-log.flow", - OutputFlowLogInitSub, JsonFlowLogger, JsonFlowLogThreadInit, - JsonFlowLogThreadDeinit, NULL); + OutputRegisterFlowSubModule(LOGGER_JSON_FLOW, "eve-log", "JsonFlowLog", + "eve-log.flow", OutputFlowLogInitSub, JsonFlowLogger, + JsonFlowLogThreadInit, JsonFlowLogThreadDeinit, NULL); } #else diff --git a/src/output-json-http.c b/src/output-json-http.c index fdf03a33f6f0..9075e0cce335 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -585,13 +585,13 @@ static TmEcode JsonHttpLogThreadDeinit(ThreadVars *t, void *data) void TmModuleJsonHttpLogRegister (void) { /* register as separate module */ - OutputRegisterTxModule("JsonHttpLog", "http-json-log", OutputHttpLogInit, - ALPROTO_HTTP, JsonHttpLogger, JsonHttpLogThreadInit, + OutputRegisterTxModule(LOGGER_JSON_HTTP, "JsonHttpLog", "http-json-log", + OutputHttpLogInit, ALPROTO_HTTP, JsonHttpLogger, JsonHttpLogThreadInit, JsonHttpLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterTxSubModule("eve-log", "JsonHttpLog", "eve-log.http", - OutputHttpLogInitSub, ALPROTO_HTTP, JsonHttpLogger, + OutputRegisterTxSubModule(LOGGER_JSON_HTTP, "eve-log", "JsonHttpLog", + "eve-log.http", OutputHttpLogInitSub, ALPROTO_HTTP, JsonHttpLogger, JsonHttpLogThreadInit, JsonHttpLogThreadDeinit, NULL); } diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 2091be08d896..0ac1683a856c 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -433,14 +433,14 @@ static TmEcode JsonNetFlowLogThreadDeinit(ThreadVars *t, void *data) void TmModuleJsonNetFlowLogRegister (void) { /* register as separate module */ - OutputRegisterFlowModule("JsonNetFlowLog", "netflow-json-log", - OutputNetFlowLogInit, JsonNetFlowLogger, JsonNetFlowLogThreadInit, - JsonNetFlowLogThreadDeinit, NULL); + OutputRegisterFlowModule(LOGGER_JSON_NETFLOW, "JsonNetFlowLog", + "netflow-json-log", OutputNetFlowLogInit, JsonNetFlowLogger, + JsonNetFlowLogThreadInit, JsonNetFlowLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterFlowSubModule("eve-log", "JsonNetFlowLog", "eve-log.netflow", - OutputNetFlowLogInitSub, JsonNetFlowLogger, JsonNetFlowLogThreadInit, - JsonNetFlowLogThreadDeinit, NULL); + OutputRegisterFlowSubModule(LOGGER_JSON_NETFLOW, "eve-log", "JsonNetFlowLog", + "eve-log.netflow", OutputNetFlowLogInitSub, JsonNetFlowLogger, + JsonNetFlowLogThreadInit, JsonNetFlowLogThreadDeinit, NULL); } #else diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 8bf94d260432..456f2c6af066 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -259,13 +259,13 @@ static TmEcode JsonSmtpLogThreadDeinit(ThreadVars *t, void *data) void TmModuleJsonSmtpLogRegister (void) { /* register as separate module */ - OutputRegisterTxModule("JsonSmtpLog", "smtp-json-log", OutputSmtpLogInit, - ALPROTO_SMTP, JsonSmtpLogger, JsonSmtpLogThreadInit, + OutputRegisterTxModule(LOGGER_JSON_SMTP, "JsonSmtpLog", "smtp-json-log", + OutputSmtpLogInit, ALPROTO_SMTP, JsonSmtpLogger, JsonSmtpLogThreadInit, JsonSmtpLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterTxSubModule("eve-log", "JsonSmtpLog", "eve-log.smtp", - OutputSmtpLogInitSub, ALPROTO_SMTP, JsonSmtpLogger, + OutputRegisterTxSubModule(LOGGER_JSON_SMTP, "eve-log", "JsonSmtpLog", + "eve-log.smtp", OutputSmtpLogInitSub, ALPROTO_SMTP, JsonSmtpLogger, JsonSmtpLogThreadInit, JsonSmtpLogThreadDeinit, NULL); } diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 313df7c824aa..deec854acd0c 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -317,13 +317,13 @@ static int JsonSshCondition(ThreadVars *tv, const Packet *p) void TmModuleJsonSshLogRegister (void) { /* register as separate module */ - OutputRegisterPacketModule("JsonSshLog", "ssh-json-log", OutputSshLogInit, - JsonSshLogger, JsonSshCondition, JsonSshLogThreadInit, + OutputRegisterPacketModule(LOGGER_JSON_SSH, "JsonSshLog", "ssh-json-log", + OutputSshLogInit, JsonSshLogger, JsonSshCondition, JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterPacketSubModule("eve-log", "JsonSshLog", "eve-log.ssh", - OutputSshLogInitSub, JsonSshLogger, JsonSshCondition, + OutputRegisterPacketSubModule(LOGGER_JSON_SSH, "eve-log", "JsonSshLog", + "eve-log.ssh", OutputSshLogInitSub, JsonSshLogger, JsonSshCondition, JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL); } diff --git a/src/output-json-stats.c b/src/output-json-stats.c index dbfba0c43cf7..ec0fc4152dfe 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -373,14 +373,14 @@ OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) void TmModuleJsonStatsLogRegister (void) { /* register as separate module */ - OutputRegisterStatsModule(MODULE_NAME, "stats-json", OutputStatsLogInit, - JsonStatsLogger, JsonStatsLogThreadInit, JsonStatsLogThreadDeinit, - NULL); + OutputRegisterStatsModule(LOGGER_JSON_STATS, MODULE_NAME, "stats-json", + OutputStatsLogInit, JsonStatsLogger, JsonStatsLogThreadInit, + JsonStatsLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterStatsSubModule("eve-log", MODULE_NAME, "eve-log.stats", - OutputStatsLogInitSub, JsonStatsLogger, JsonStatsLogThreadInit, - JsonStatsLogThreadDeinit, NULL); + OutputRegisterStatsSubModule(LOGGER_JSON_STATS, "eve-log", MODULE_NAME, + "eve-log.stats", OutputStatsLogInitSub, JsonStatsLogger, + JsonStatsLogThreadInit, JsonStatsLogThreadDeinit, NULL); } #else diff --git a/src/output-json-template.c b/src/output-json-template.c index 195f1786f349..e877259de7ad 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -198,9 +198,10 @@ void TmModuleJsonTemplateLogRegister(void) } /* TEMPLATE_END_REMOVE */ /* Register as an eve sub-module. */ - OutputRegisterTxSubModule("eve-log", "JsonTemplateLog", "eve-log.template", - OutputTemplateLogInitSub, ALPROTO_TEMPLATE, JsonTemplateLogger, - JsonTemplateLogThreadInit, JsonTemplateLogThreadDeinit, NULL); + OutputRegisterTxSubModule(LOGGER_JSON_TEMPLATE, "eve-log", "JsonTemplateLog", + "eve-log.template", OutputTemplateLogInitSub, ALPROTO_TEMPLATE, + JsonTemplateLogger, JsonTemplateLogThreadInit, + JsonTemplateLogThreadDeinit, NULL); SCLogNotice("Template JSON logger registered."); } diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 52237ba934be..18ea2cab9443 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -311,15 +311,16 @@ OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) void TmModuleJsonTlsLogRegister (void) { /* register as separate module */ - OutputRegisterTxModuleWithProgress("JsonTlsLog", "tls-json-log", - OutputTlsLogInit, ALPROTO_TLS, JsonTlsLogger, TLS_HANDSHAKE_DONE, - TLS_HANDSHAKE_DONE, JsonTlsLogThreadInit, JsonTlsLogThreadDeinit, NULL); - - /* also register as child of eve-log */ - OutputRegisterTxSubModuleWithProgress("eve-log", "JsonTlsLog", - "eve-log.tls", OutputTlsLogInitSub, ALPROTO_TLS, JsonTlsLogger, + OutputRegisterTxModuleWithProgress(LOGGER_JSON_TLS, "JsonTlsLog", + "tls-json-log", OutputTlsLogInit, ALPROTO_TLS, JsonTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, JsonTlsLogThreadInit, JsonTlsLogThreadDeinit, NULL); + + /* also register as child of eve-log */ + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_TLS, "eve-log", + "JsonTlsLog", "eve-log.tls", OutputTlsLogInitSub, ALPROTO_TLS, + JsonTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, + JsonTlsLogThreadInit, JsonTlsLogThreadDeinit, NULL); } #else diff --git a/src/output-packet.c b/src/output-packet.c index 376b2cd51f36..94197fbc9dc0 100644 --- a/src/output-packet.c +++ b/src/output-packet.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "tm-modules.h" +#include "output.h" #include "output-packet.h" #include "util-profiling.h" @@ -48,7 +49,7 @@ typedef struct OutputPacketLogger_ { OutputCtx *output_ctx; struct OutputPacketLogger_ *next; const char *name; - TmmId module_id; + LoggerId logger_id; ThreadInitFunc ThreadInit; ThreadDeinitFunc ThreadDeinit; ThreadExitPrintStatsFunc ThreadExitPrintStats; @@ -56,17 +57,12 @@ typedef struct OutputPacketLogger_ { static OutputPacketLogger *list = NULL; -int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, - PacketLogCondition ConditionFunc, OutputCtx *output_ctx, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, +int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, + PacketLogger LogFunc, PacketLogCondition ConditionFunc, + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { -#if 0 - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; -#endif - OutputPacketLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -79,9 +75,7 @@ int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, op->ThreadInit = ThreadInit; op->ThreadDeinit = ThreadDeinit; op->ThreadExitPrintStats = ThreadExitPrintStats; -#if 0 - op->module_id = (TmmId) module_id; -#endif + op->logger_id = logger_id; if (list == NULL) list = op; @@ -113,9 +107,9 @@ static TmEcode OutputPacketLog(ThreadVars *tv, Packet *p, void *thread_data, Pac BUG_ON(logger->LogFunc == NULL || logger->ConditionFunc == NULL); if ((logger->ConditionFunc(tv, (const Packet *)p)) == TRUE) { - PACKET_PROFILING_TMM_START(p, logger->module_id); + PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, (const Packet *)p); - PACKET_PROFILING_TMM_END(p, logger->module_id); + PACKET_PROFILING_LOGGER_END(p, logger->logger_id); } logger = logger->next; diff --git a/src/output-packet.h b/src/output-packet.h index 431c441b11c7..408be05b273d 100644 --- a/src/output-packet.h +++ b/src/output-packet.h @@ -27,6 +27,7 @@ #define __OUTPUT_PACKET_H__ #include "decode.h" +#include "output.h" /** packet logger function pointer type */ typedef int (*PacketLogger)(ThreadVars *, void *thread_data, const Packet *); @@ -36,9 +37,9 @@ typedef int (*PacketLogger)(ThreadVars *, void *thread_data, const Packet *); */ typedef int (*PacketLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, - PacketLogCondition ConditionFunc, OutputCtx *, ThreadInitFunc, - ThreadDeinitFunc, ThreadExitPrintStatsFunc); +int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, + PacketLogger LogFunc, PacketLogCondition ConditionFunc, OutputCtx *, + ThreadInitFunc, ThreadDeinitFunc, ThreadExitPrintStatsFunc); void TmModulePacketLoggerRegister (void); diff --git a/src/output-streaming.c b/src/output-streaming.c index b72a38a44f77..9413721986cf 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -53,7 +53,7 @@ typedef struct OutputStreamingLogger_ { OutputCtx *output_ctx; struct OutputStreamingLogger_ *next; const char *name; - TmmId module_id; + LoggerId logger_id; enum OutputStreamingType type; ThreadInitFunc ThreadInit; ThreadDeinitFunc ThreadDeinit; @@ -62,17 +62,12 @@ typedef struct OutputStreamingLogger_ { static OutputStreamingLogger *list = NULL; -int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, - OutputCtx *output_ctx, enum OutputStreamingType type, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, +int OutputRegisterStreamingLogger(LoggerId id, const char *name, + StreamingLogger LogFunc, OutputCtx *output_ctx, + enum OutputStreamingType type, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { -#if 0 - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; -#endif - OutputStreamingLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -81,9 +76,7 @@ int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; -#if 0 - op->module_id = (TmmId) module_id; -#endif + op->logger_id = id; op->type = type; op->ThreadInit = ThreadInit; op->ThreadDeinit = ThreadDeinit; @@ -128,9 +121,9 @@ int Streamer(void *cbdata, Flow *f, const uint8_t *data, uint32_t data_len, uint if (logger->type == streamer_cbdata->type) { SCLogDebug("logger %p", logger); - PACKET_PROFILING_TMM_START(p, logger->module_id); + PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, (const Flow *)f, data, data_len, tx_id, flags); - PACKET_PROFILING_TMM_END(p, logger->module_id); + PACKET_PROFILING_LOGGER_END(p, logger->logger_id); } logger = logger->next; diff --git a/src/output-streaming.h b/src/output-streaming.h index 9508903a8a03..8db555f94c4c 100644 --- a/src/output-streaming.h +++ b/src/output-streaming.h @@ -45,9 +45,9 @@ typedef int (*StreamingLogger)(ThreadVars *, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags); -int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, - OutputCtx *, enum OutputStreamingType, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, +int OutputRegisterStreamingLogger(LoggerId id, const char *name, + StreamingLogger LogFunc, OutputCtx *, enum OutputStreamingType, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void TmModuleStreamingLoggerRegister (void); diff --git a/src/output-tx.c b/src/output-tx.c index 4a7934aad1ca..3d37e89e8ec3 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -51,7 +51,7 @@ typedef struct OutputTxLogger_ { OutputCtx *output_ctx; struct OutputTxLogger_ *next; const char *name; - TmmId module_id; + LoggerId logger_id; uint32_t id; int tc_log_progress; int ts_log_progress; @@ -62,7 +62,8 @@ typedef struct OutputTxLogger_ { static OutputTxLogger *list = NULL; -int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, +int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, + TxLogger LogFunc, OutputCtx *output_ctx, int tc_log_progress, int ts_log_progress, TxLoggerCondition LogCondition, ThreadInitFunc ThreadInit, @@ -91,9 +92,7 @@ int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, op->LogCondition = LogCondition; op->output_ctx = output_ctx; op->name = name; -#if 0 - op->module_id = (TmmId) module_id; -#endif + op->logger_id = id; op->ThreadInit = ThreadInit; op->ThreadDeinit = ThreadDeinit; op->ThreadExitPrintStats = ThreadExitPrintStats; @@ -230,9 +229,9 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ } } - PACKET_PROFILING_TMM_START(p, logger->module_id); + PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, p, f, alstate, tx, tx_id); - PACKET_PROFILING_TMM_END(p, logger->module_id); + PACKET_PROFILING_LOGGER_END(p, logger->logger_id); AppLayerParserSetTxLogged(p->proto, alproto, alstate, tx, logger->id); diff --git a/src/output-tx.h b/src/output-tx.h index 53f563aca2a5..e548cdd16092 100644 --- a/src/output-tx.h +++ b/src/output-tx.h @@ -36,7 +36,8 @@ typedef int (*TxLogger)(ThreadVars *, void *thread_data, const Packet *, Flow *f */ typedef int (*TxLoggerCondition)(ThreadVars *, const Packet *, void *state, void *tx, uint64_t tx_id); -int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, +int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, + TxLogger LogFunc, OutputCtx *, int tc_log_progress, int ts_log_progress, TxLoggerCondition LogCondition, ThreadInitFunc, ThreadDeinitFunc, diff --git a/src/output.c b/src/output.c index 351cd294aec8..5c7e71a25c04 100644 --- a/src/output.c +++ b/src/output.c @@ -84,7 +84,7 @@ OutputRegisterModule(const char *name, const char *conf_name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterPacketModule(const char *name, const char *conf_name, +OutputRegisterPacketModule(LoggerId id, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, @@ -99,6 +99,7 @@ OutputRegisterPacketModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; @@ -125,8 +126,9 @@ OutputRegisterPacketModule(const char *name, const char *conf_name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterPacketSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), +OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -140,6 +142,7 @@ OutputRegisterPacketSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; @@ -166,10 +169,10 @@ OutputRegisterPacketSubModule(const char *parent_name, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterTxModuleWrapper(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, - TxLoggerCondition TxLogCondition, +void OutputRegisterTxModuleWrapper(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, + int ts_log_progress, TxLoggerCondition TxLogCondition, TmEcode (*ThreadInit)(ThreadVars *t, void *, void **), TmEcode (*ThreadDeinit)(ThreadVars *t, void *), void (*ThreadExitPrintStats)(ThreadVars *, void *)) @@ -183,6 +186,7 @@ void OutputRegisterTxModuleWrapper(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; @@ -203,7 +207,7 @@ void OutputRegisterTxModuleWrapper(const char *name, const char *conf_name, exit(EXIT_FAILURE); } -void OutputRegisterTxSubModuleWrapper(const char *parent_name, +void OutputRegisterTxSubModuleWrapper(LoggerId id, const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, @@ -221,6 +225,7 @@ void OutputRegisterTxSubModuleWrapper(const char *parent_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; @@ -250,25 +255,27 @@ void OutputRegisterTxSubModuleWrapper(const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterTxModuleWithCondition(const char *name, +void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, - TxLogFunc, -1, -1, TxLogCondition, NULL, NULL, NULL); + OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, + TxLogFunc, -1, -1, TxLogCondition, ThreadInit, ThreadDeinit, + ThreadExitPrintStats); } -void OutputRegisterTxSubModuleWithCondition(const char *parent_name, +void OutputRegisterTxSubModuleWithCondition(LoggerId id, const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, InitFunc, - alproto, TxLogFunc, -1, -1, TxLogCondition, NULL, NULL, NULL); + OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, + alproto, TxLogFunc, -1, -1, TxLogCondition, ThreadInit, ThreadDeinit, + ThreadExitPrintStats); } /** @@ -279,18 +286,20 @@ void OutputRegisterTxSubModuleWithCondition(const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, +void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, + int ts_log_progress, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, - TxLogFunc, tc_log_progress, ts_log_progress, NULL, ThreadInit, - ThreadDeinit, ThreadExitPrintStats); + OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, + TxLogFunc, tc_log_progress, ts_log_progress, + NULL, ThreadInit, ThreadDeinit, + ThreadExitPrintStats); } -void OutputRegisterTxSubModuleWithProgress(const char *parent_name, +void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, @@ -298,7 +307,7 @@ void OutputRegisterTxSubModuleWithProgress(const char *parent_name, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, InitFunc, + OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, alproto, TxLogFunc, tc_log_progress, ts_log_progress, NULL, ThreadInit, ThreadDeinit, ThreadExitPrintStats); } @@ -312,25 +321,25 @@ void OutputRegisterTxSubModuleWithProgress(const char *parent_name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterTxModule(const char *name, const char *conf_name, +OutputRegisterTxModule(LoggerId id, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc, TmEcode (*ThreadInit)(ThreadVars *, void *, void **), TmEcode (*ThreadDeinit)(ThreadVars *, void *), void (*ThreadExitPrintStats)(ThreadVars *, void *)) { - OutputRegisterTxModuleWrapper(name, conf_name, InitFunc, alproto, + OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, TxLogFunc, -1, -1, NULL, ThreadInit, ThreadDeinit, ThreadExitPrintStats); } -void OutputRegisterTxSubModule(const char *parent_name, const char *name, - const char *conf_name, +void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxSubModuleWrapper(parent_name, name, conf_name, + OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, alproto, TxLogFunc, -1, -1, NULL, ThreadInit, ThreadDeinit, ThreadExitPrintStats); @@ -345,7 +354,7 @@ void OutputRegisterTxSubModule(const char *parent_name, const char *name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterFileModule(const char *name, const char *conf_name, +OutputRegisterFileModule(LoggerId id, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -359,6 +368,7 @@ OutputRegisterFileModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; @@ -384,8 +394,9 @@ OutputRegisterFileModule(const char *name, const char *conf_name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterFileSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +OutputRegisterFileSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), FileLogger FileLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -399,6 +410,7 @@ OutputRegisterFileSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; @@ -425,9 +437,10 @@ OutputRegisterFileSubModule(const char *parent_name, const char *name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterFiledataModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FiledataLogger FiledataLogFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, +OutputRegisterFiledataModule(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FiledataLogFunc == NULL)) { @@ -439,6 +452,7 @@ OutputRegisterFiledataModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; @@ -464,8 +478,9 @@ OutputRegisterFiledataModule(const char *name, const char *conf_name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterFiledataSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +OutputRegisterFiledataSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -479,6 +494,7 @@ OutputRegisterFiledataSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; @@ -505,7 +521,7 @@ OutputRegisterFiledataSubModule(const char *parent_name, const char *name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterFlowModule(const char *name, const char *conf_name, +OutputRegisterFlowModule(LoggerId id, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -519,6 +535,7 @@ OutputRegisterFlowModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; @@ -544,8 +561,9 @@ OutputRegisterFlowModule(const char *name, const char *conf_name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterFlowSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -559,6 +577,7 @@ OutputRegisterFlowSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; @@ -585,8 +604,9 @@ OutputRegisterFlowSubModule(const char *parent_name, const char *name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterStreamingModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), StreamingLogger StreamingLogFunc, +OutputRegisterStreamingModule(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -600,6 +620,7 @@ OutputRegisterStreamingModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; @@ -626,8 +647,9 @@ OutputRegisterStreamingModule(const char *name, const char *conf_name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterStreamingSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -641,6 +663,7 @@ OutputRegisterStreamingSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; @@ -668,7 +691,7 @@ OutputRegisterStreamingSubModule(const char *parent_name, const char *name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterStatsModule(const char *name, const char *conf_name, +OutputRegisterStatsModule(LoggerId id, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -682,6 +705,7 @@ OutputRegisterStatsModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; @@ -707,8 +731,9 @@ OutputRegisterStatsModule(const char *name, const char *conf_name, * \retval Returns 0 on success, -1 on failure. */ void -OutputRegisterStatsSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -722,6 +747,7 @@ OutputRegisterStatsSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; diff --git a/src/output.h b/src/output.h index e34d34379d74..ad787193689a 100644 --- a/src/output.h +++ b/src/output.h @@ -39,6 +39,7 @@ #include "output-stats.h" typedef struct OutputModule_ { + LoggerId logger_id; const char *name; const char *conf_name; const char *parent_name; @@ -71,48 +72,49 @@ extern OutputModuleList output_modules; void OutputRegisterModule(const char *, const char *, OutputCtx *(*)(ConfNode *)); -void OutputRegisterPacketModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), +void OutputRegisterPacketModule(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), PacketLogger LogFunc, PacketLogCondition ConditionFunc, ThreadInitFunc, ThreadDeinitFunc, ThreadExitPrintStatsFunc); -void OutputRegisterPacketSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +void OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), PacketLogger LogFunc, PacketLogCondition ConditionFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc, TmEcode (*ThreadInit)(ThreadVars *t, void *, void **), +void OutputRegisterTxModule(LoggerId id, const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc, + TmEcode (*ThreadInit)(ThreadVars *t, void *, void **), TmEcode (*ThreadDeinit)(ThreadVars *t, void *), void (*ThreadExitPrintStats)(ThreadVars *, void *)); -void OutputRegisterTxSubModule(const char *parent_name, const char *name, - const char *conf_name, +void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxModuleWithCondition(const char *name, +void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxSubModuleWithCondition(const char *parent_name, +void OutputRegisterTxSubModuleWithCondition(LoggerId id, const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxModuleWithProgress(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, +void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxSubModuleWithProgress(const char *parent_name, +void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, @@ -120,54 +122,61 @@ void OutputRegisterTxSubModuleWithProgress(const char *parent_name, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterFileModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterFileSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +void OutputRegisterFileModule(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); - -void OutputRegisterFiledataModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FiledataLogger FiledataLogFunc, +void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), FileLogger FileLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterFiledataSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), + +void OutputRegisterFiledataModule(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterFiledataSubModule(LoggerId, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterFlowModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FlowLogger FlowLogFunc, - ThreadInitFunc ThreadInit, +void OutputRegisterFlowModule(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterFlowSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +void OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterStreamingModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), StreamingLogger StreamingLogFunc, - enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, +void OutputRegisterStreamingModule(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterStreamingSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +void OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterStatsModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), StatsLogger StatsLogFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, +void OutputRegisterStatsModule(LoggerId id, const char *name, + const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterStatsSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +void OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); diff --git a/src/runmodes.c b/src/runmodes.c index 3f043b9409f6..b4f319d4081a 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -106,9 +106,6 @@ static char *active_runmode; /* free list for our outputs */ typedef struct OutputFreeList_ { -#if 0 - TmModule *tm_module; -#endif OutputModule *output_module; OutputCtx *output_ctx; @@ -469,9 +466,6 @@ void RunOutputFreeList(void) { OutputFreeList *output; while ((output = TAILQ_FIRST(&output_free_list))) { -#if 0 - SCLogNotice("output %s %p %p", output->tm_module->name, output, output->output_ctx); -#endif SCLogDebug("output %s %p %p", output->output_module->name, output, output->output_ctx); @@ -535,20 +529,9 @@ void RunModeShutDown(void) * the output ctx at shutdown and unix socket reload */ static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx) { -#if 0 - TmModule *tm_module = TmModuleGetByName(module->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", module->name); - exit(EXIT_FAILURE); - } -#endif OutputFreeList *fl_output = SCCalloc(1, sizeof(OutputFreeList)); if (unlikely(fl_output == NULL)) return; -#if 0 - fl_output->tm_module = tm_module; -#endif fl_output->output_module = module; fl_output->output_ctx = output_ctx; TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries); @@ -598,23 +581,16 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu return; } -#if 0 - TmModule *tm_module = TmModuleGetByName(module->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", module->name); - exit(EXIT_FAILURE); - } - /* XXX What to do here? */ - if (tm_module != NULL && strcmp(tmm_modules[TMM_ALERTDEBUGLOG].name, tm_module->name) == 0) + if (module->logger_id == LOGGER_ALERT_DEBUG) { debuglog_enabled = 1; -#endif + } if (module->PacketLogFunc) { SCLogNotice("%s is a packet logger", module->name); - OutputRegisterPacketLogger(module->name, module->PacketLogFunc, - module->PacketConditionFunc, output_ctx, module->ThreadInit, - module->ThreadDeinit, module->ThreadExitPrintStats); + OutputRegisterPacketLogger(module->logger_id, module->name, + module->PacketLogFunc, module->PacketConditionFunc, output_ctx, + module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); /* need one instance of the packet logger module */ if (pkt_logger_module == NULL) { @@ -636,7 +612,7 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } else if (module->TxLogFunc) { SCLogDebug("%s is a tx logger", module->name); - OutputRegisterTxLogger(module->name, module->alproto, + OutputRegisterTxLogger(module->logger_id, module->name, module->alproto, module->TxLogFunc, output_ctx, module->tc_log_progress, module->ts_log_progress, module->TxLogCondition, module->ThreadInit, module->ThreadDeinit, @@ -662,9 +638,9 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } else if (module->FiledataLogFunc) { SCLogDebug("%s is a filedata logger", module->name); - OutputRegisterFiledataLogger(module->name, module->FiledataLogFunc, - output_ctx, module->ThreadInit, module->ThreadDeinit, - module->ThreadExitPrintStats); + OutputRegisterFiledataLogger(module->logger_id, module->name, + module->FiledataLogFunc, output_ctx, module->ThreadInit, + module->ThreadDeinit, module->ThreadExitPrintStats); /* need one instance of the tx logger module */ if (filedata_logger_module == NULL) { @@ -686,9 +662,9 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } else if (module->FileLogFunc) { SCLogDebug("%s is a file logger", module->name); - OutputRegisterFileLogger(module->name, module->FileLogFunc, output_ctx, - module->ThreadInit, module->ThreadDeinit, - module->ThreadExitPrintStats); + OutputRegisterFileLogger(module->logger_id, module->name, + module->FileLogFunc, output_ctx, module->ThreadInit, + module->ThreadDeinit, module->ThreadExitPrintStats); /* need one instance of the tx logger module */ if (file_logger_module == NULL) { @@ -710,9 +686,10 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } else if (module->StreamingLogFunc) { SCLogDebug("%s is a streaming logger", module->name); - OutputRegisterStreamingLogger(module->name, module->StreamingLogFunc, - output_ctx, module->stream_type, module->ThreadInit, - module->ThreadDeinit, module->ThreadExitPrintStats); + OutputRegisterStreamingLogger(module->logger_id, module->name, + module->StreamingLogFunc, output_ctx, module->stream_type, + module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); /* need one instance of the streaming logger module */ if (streaming_logger_module == NULL) { @@ -739,9 +716,6 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu if (unlikely(runmode_output == NULL)) return; runmode_output->name = module->name; -#if 0 - runmode_output->tm_module = tm_module; -#endif runmode_output->output_ctx = output_ctx; InsertInRunModeOutputs(runmode_output); } diff --git a/src/suricata-common.h b/src/suricata-common.h index 0db433f9c47c..b837de26addb 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -341,6 +341,37 @@ typedef enum PacketProfileDetectId_ { PROF_DETECT_SIZE, } PacketProfileDetectId; +typedef enum { + LOGGER_UNDEFINED, + LOGGER_ALERT_DEBUG, + LOGGER_ALERT_FAST, + LOGGER_UNIFIED2, + LOGGER_ALERT_SYSLOG, + LOGGER_DROP, + LOGGER_JSON_ALERT, + LOGGER_JSON_DROP, + LOGGER_JSON_SSH, + LOGGER_DNS, + LOGGER_HTTP, + LOGGER_JSON_DNS, + LOGGER_JSON_HTTP, + LOGGER_JSON_SMTP, + LOGGER_JSON_TLS, + LOGGER_JSON_TEMPLATE, + LOGGER_TLS_STORE, + LOGGER_TLS, + LOGGER_FILE, + LOGGER_FILE_STORE, + LOGGER_JSON_FILE, + LOGGER_TCP_DATA, + LOGGER_JSON_FLOW, + LOGGER_JSON_NETFLOW, + LOGGER_STATS, + LOGGER_JSON_STATS, + LOGGER_PRELUDE, + LOGGER_SIZE, +} LoggerId; + #include #include "threads.h" #include "tm-threads-common.h" diff --git a/src/util-profiling.c b/src/util-profiling.c index 500a3ebc8e11..cbbef0c20a83 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -87,6 +87,9 @@ SCProfilePacketData packet_profile_app_pd_data6[257]; SCProfilePacketData packet_profile_detect_data4[PROF_DETECT_SIZE][257]; SCProfilePacketData packet_profile_detect_data6[PROF_DETECT_SIZE][257]; +SCProfilePacketData packet_profile_log_data4[LOGGER_SIZE][256]; +SCProfilePacketData packet_profile_log_data6[LOGGER_SIZE][256]; + struct ProfileProtoRecords { SCProfilePacketData records4[257]; SCProfilePacketData records6[257]; @@ -114,6 +117,7 @@ __thread int profiling_rules_entered = 0; void SCProfilingDumpPacketStats(void); const char * PacketProfileDetectIdToString(PacketProfileDetectId id); +const char * PacketProfileLoggertIdToString(LoggerId id); static void FormatNumber(uint64_t num, char *str, size_t size) { @@ -167,6 +171,8 @@ SCProfilingInit(void) memset(&packet_profile_app_pd_data6, 0, sizeof(packet_profile_app_pd_data6)); memset(&packet_profile_detect_data4, 0, sizeof(packet_profile_detect_data4)); memset(&packet_profile_detect_data6, 0, sizeof(packet_profile_detect_data6)); + memset(&packet_profile_log_data4, 0, sizeof(packet_profile_log_data4)); + memset(&packet_profile_log_data6, 0, sizeof(packet_profile_log_data6)); memset(&packet_profile_flowworker_data, 0, sizeof(packet_profile_flowworker_data)); const char *filename = ConfNodeLookupChildValue(conf, "filename"); @@ -685,6 +691,58 @@ void SCProfilingDumpPacketStats(void) } } + fprintf(fp, "\nLogger/output stats:\n"); + + total = 0; + for (m = 0; m < LOGGER_SIZE; m++) { + int p; + for (p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_log_data4[m][p]; + total += pd->tot; + pd = &packet_profile_log_data6[m][p]; + total += pd->tot; + } + } + + fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", + "Logger", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot"); + fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", + "------------------------", "------", "-----", "----------", "------------", "------------", "-----------", "-----------"); + for (m = 0; m < LOGGER_SIZE; m++) { + int p; + for (p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_log_data4[m][p]; + + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / + (long double)total * 100; + + fprintf(fp, "%-24s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n", + PacketProfileLoggertIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + for (m = 0; m < LOGGER_SIZE; m++) { + int p; + for (p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_log_data6[m][p]; + + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / + (long double)total * 100; + + fprintf(fp, "%-24s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n", + PacketProfileLoggertIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + fprintf(fp, "\nGeneral detection engine stats:\n"); total = 0; @@ -984,6 +1042,45 @@ static void SCProfilingUpdatePacketGenericRecords(Packet *p, PktProfilingData *p } } +static void SCProfilingUpdatePacketLogRecord(LoggerId id, + uint8_t ipproto, PktProfilingLoggerData *pdt, int ipver) +{ + if (pdt == NULL) { + return; + } + + SCProfilePacketData *pd; + if (ipver == 4) + pd = &packet_profile_log_data4[id][ipproto]; + else + pd = &packet_profile_log_data6[id][ipproto]; + + if (pd->min == 0 || pdt->ticks_spent < pd->min) { + pd->min = pdt->ticks_spent; + } + if (pd->max < pdt->ticks_spent) { + pd->max = pdt->ticks_spent; + } + + pd->tot += pdt->ticks_spent; + pd->cnt++; +} + +static void SCProfilingUpdatePacketLogRecords(Packet *p) +{ + for (LoggerId i = 0; i < LOGGER_SIZE; i++) { + PktProfilingLoggerData *pdt = &p->profile->logger[i]; + + if (pdt->ticks_spent > 0) { + if (PKT_IS_IPV4(p)) { + SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 4); + } else { + SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 6); + } + } + } +} + void SCProfilingAddPacket(Packet *p) { if (p == NULL || p->profile == NULL || @@ -1031,6 +1128,7 @@ void SCProfilingAddPacket(Packet *p) SCProfilingUpdatePacketTmmRecords(p); SCProfilingUpdatePacketAppRecords(p); SCProfilingUpdatePacketDetectRecords(p); + SCProfilingUpdatePacketLogRecords(p); } else if (PKT_IS_IPV6(p)) { SCProfilePacketData *pd = &packet_profile_data6[p->proto]; @@ -1066,6 +1164,7 @@ void SCProfilingAddPacket(Packet *p) SCProfilingUpdatePacketTmmRecords(p); SCProfilingUpdatePacketAppRecords(p); SCProfilingUpdatePacketDetectRecords(p); + SCProfilingUpdatePacketLogRecords(p); } } pthread_mutex_unlock(&packet_profile_lock); @@ -1142,7 +1241,47 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id) } } - +/** + * \brief Maps the LoggerId's to its string equivalent for profiling output. + * + * \param id LoggerId id + * + * \retval string equivalent for the LoggerId id + */ +const char * PacketProfileLoggertIdToString(LoggerId id) +{ + switch (id) { + CASE_CODE (LOGGER_UNDEFINED); + CASE_CODE (LOGGER_ALERT_DEBUG); + CASE_CODE (LOGGER_ALERT_FAST); + CASE_CODE (LOGGER_UNIFIED2); + CASE_CODE (LOGGER_ALERT_SYSLOG); + CASE_CODE (LOGGER_DROP); + CASE_CODE (LOGGER_JSON_ALERT); + CASE_CODE (LOGGER_JSON_DROP); + CASE_CODE (LOGGER_JSON_SSH); + CASE_CODE (LOGGER_DNS); + CASE_CODE (LOGGER_HTTP); + CASE_CODE (LOGGER_JSON_DNS); + CASE_CODE (LOGGER_JSON_HTTP); + CASE_CODE (LOGGER_JSON_SMTP); + CASE_CODE (LOGGER_JSON_TLS); + CASE_CODE (LOGGER_JSON_TEMPLATE); + CASE_CODE (LOGGER_TLS_STORE); + CASE_CODE (LOGGER_TLS); + CASE_CODE (LOGGER_FILE); + CASE_CODE (LOGGER_FILE_STORE); + CASE_CODE (LOGGER_JSON_FILE); + CASE_CODE (LOGGER_TCP_DATA); + CASE_CODE (LOGGER_JSON_FLOW); + CASE_CODE (LOGGER_JSON_NETFLOW); + CASE_CODE (LOGGER_STATS); + CASE_CODE (LOGGER_JSON_STATS); + CASE_CODE (LOGGER_PRELUDE); + default: + return "UNKNOWN"; + } +} #ifdef UNITTESTS diff --git a/src/util-profiling.h b/src/util-profiling.h index 54521a422098..990697ca1ec3 100644 --- a/src/util-profiling.h +++ b/src/util-profiling.h @@ -250,6 +250,25 @@ PktProfiling *SCProfilePacketStart(void); } \ } +#define PACKET_PROFILING_LOGGER_START(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < LOGGER_SIZE) { \ + (p)->profile->logger[(id)].ticks_start = UtilCpuGetTicks(); \ + } \ + } + +#define PACKET_PROFILING_LOGGER_END(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < LOGGER_SIZE) { \ + (p)->profile->logger[(id)].ticks_end = UtilCpuGetTicks();\ + if ((p)->profile->logger[(id)].ticks_start != 0 && \ + (p)->profile->logger[(id)].ticks_start < (p)->profile->logger[(id)].ticks_end) { \ + (p)->profile->logger[(id)].ticks_spent += \ + ((p)->profile->logger[(id)].ticks_end - (p)->profile->logger[(id)].ticks_start); \ + } \ + } \ + } + #define SGH_PROFILING_RECORD(det_ctx, sgh) \ if (profiling_sghs_enabled) { \ SCProfilingSghUpdateCounter((det_ctx), (sgh)); \ @@ -311,6 +330,9 @@ void SCProfilingDump(void); #define PACKET_PROFILING_DETECT_START(p, id) #define PACKET_PROFILING_DETECT_END(p, id) +#define PACKET_PROFILING_LOGGER_START(p, id) +#define PACKET_PROFILING_LOGGER_END(p, id) + #define SGH_PROFILING_RECORD(det_ctx, sgh) #define FLOWWORKER_PROFILING_START(p, id) From 8b38b9d728d9b909b8ed5e663823f8410b42364c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Sun, 29 May 2016 00:11:03 -0600 Subject: [PATCH 1671/2553] output.[ch]: consistent style - Clean up function declaration. - Consistenly use typedefs for function points. No functional changes. --- src/output.c | 152 +++++++++++++++++++++------------------------------ src/output.h | 78 +++++++++++++------------- 2 files changed, 98 insertions(+), 132 deletions(-) diff --git a/src/output.c b/src/output.c index 5c7e71a25c04..9466dbb23bd5 100644 --- a/src/output.c +++ b/src/output.c @@ -53,9 +53,8 @@ TAILQ_HEAD(, OutputFileRolloverFlag_) output_file_rotation_flags = * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *)) +void OutputRegisterModule(const char *name, const char *conf_name, + OutputInitFunc InitFunc) { OutputModule *module = SCCalloc(1, sizeof(*module)); if (unlikely(module == NULL)) @@ -83,9 +82,8 @@ OutputRegisterModule(const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterPacketModule(LoggerId id, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), +void OutputRegisterPacketModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -125,10 +123,8 @@ OutputRegisterPacketModule(LoggerId id, const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), +void OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -170,12 +166,11 @@ OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, * \retval Returns 0 on success, -1 on failure. */ void OutputRegisterTxModuleWrapper(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), - AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, - int ts_log_progress, TxLoggerCondition TxLogCondition, - TmEcode (*ThreadInit)(ThreadVars *t, void *, void **), - TmEcode (*ThreadDeinit)(ThreadVars *t, void *), - void (*ThreadExitPrintStats)(ThreadVars *, void *)) + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, + TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -208,13 +203,11 @@ void OutputRegisterTxModuleWrapper(LoggerId id, const char *name, } void OutputRegisterTxSubModuleWrapper(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, - OutputCtx *parent_ctx), AppProto alproto, TxLogger TxLogFunc, - int tc_log_progress, int ts_log_progress, - TxLoggerCondition TxLogCondition, - ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, + int ts_log_progress, TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -256,7 +249,7 @@ void OutputRegisterTxSubModuleWrapper(LoggerId id, const char *parent_name, * \retval Returns 0 on success, -1 on failure. */ void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -266,11 +259,11 @@ void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, ThreadExitPrintStats); } -void OutputRegisterTxSubModuleWithCondition(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, - TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, +void OutputRegisterTxSubModuleWithCondition(LoggerId id, + const char *parent_name, const char *name, const char *conf_name, + OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, @@ -287,21 +280,18 @@ void OutputRegisterTxSubModuleWithCondition(LoggerId id, const char *parent_name * \retval Returns 0 on success, -1 on failure. */ void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), - AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, - int ts_log_progress, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, - TxLogFunc, tc_log_progress, ts_log_progress, - NULL, ThreadInit, ThreadDeinit, - ThreadExitPrintStats); + TxLogFunc, tc_log_progress, ts_log_progress, NULL, ThreadInit, + ThreadDeinit, ThreadExitPrintStats); } void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, @@ -320,29 +310,26 @@ void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterTxModule(LoggerId id, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc, TmEcode (*ThreadInit)(ThreadVars *, void *, void **), - TmEcode (*ThreadDeinit)(ThreadVars *, void *), - void (*ThreadExitPrintStats)(ThreadVars *, void *)) +void OutputRegisterTxModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, - TxLogFunc, -1, -1, NULL, ThreadInit, - ThreadDeinit, ThreadExitPrintStats); + TxLogFunc, -1, -1, NULL, ThreadInit, ThreadDeinit, + ThreadExitPrintStats); } void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - AppProto alproto, TxLogger TxLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, + OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, - InitFunc, alproto, TxLogFunc, -1, -1, NULL, - ThreadInit, ThreadDeinit, - ThreadExitPrintStats); + InitFunc, alproto, TxLogFunc, -1, -1, NULL, ThreadInit, ThreadDeinit, + ThreadExitPrintStats); } /** @@ -353,9 +340,8 @@ void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFileModule(LoggerId id, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc, +void OutputRegisterFileModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, FileLogger FileLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { @@ -393,10 +379,8 @@ OutputRegisterFileModule(LoggerId id, const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFileSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, FileLogger FileLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -436,9 +420,8 @@ OutputRegisterFileSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFiledataModule(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), +void OutputRegisterFiledataModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -477,10 +460,8 @@ OutputRegisterFiledataModule(LoggerId id, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFiledataSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +void OutputRegisterFiledataSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -520,9 +501,8 @@ OutputRegisterFiledataSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFlowModule(LoggerId id, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FlowLogger FlowLogFunc, +void OutputRegisterFlowModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { @@ -560,10 +540,8 @@ OutputRegisterFlowModule(LoggerId id, const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +void OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -603,9 +581,8 @@ OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterStreamingModule(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), +void OutputRegisterStreamingModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, @@ -646,10 +623,8 @@ OutputRegisterStreamingModule(LoggerId id, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +void OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -690,9 +665,8 @@ OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterStatsModule(LoggerId id, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), StatsLogger StatsLogFunc, +void OutputRegisterStatsModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { @@ -730,10 +704,8 @@ OutputRegisterStatsModule(LoggerId id, const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), +void OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) @@ -771,8 +743,7 @@ OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, * \retval The OutputModule with the given name or NULL if no output module * with the given name is registered. */ -OutputModule * -OutputGetModuleByConfName(const char *conf_name) +OutputModule *OutputGetModuleByConfName(const char *conf_name) { OutputModule *module; @@ -787,8 +758,7 @@ OutputGetModuleByConfName(const char *conf_name) /** * \brief Deregister all modules. Useful for a memory clean exit. */ -void -OutputDeregisterAll(void) +void OutputDeregisterAll(void) { OutputModule *module; diff --git a/src/output.h b/src/output.h index ad787193689a..f6a8cc6dcc68 100644 --- a/src/output.h +++ b/src/output.h @@ -38,17 +38,20 @@ #include "output-streaming.h" #include "output-stats.h" +typedef OutputCtx *(*OutputInitFunc)(ConfNode *); +typedef OutputCtx *(*OutputInitSubFunc)(ConfNode *, OutputCtx *); + typedef struct OutputModule_ { LoggerId logger_id; const char *name; const char *conf_name; const char *parent_name; - OutputCtx *(*InitFunc)(ConfNode *); - OutputCtx *(*InitSubFunc)(ConfNode *, OutputCtx *parent_ctx); + OutputInitFunc InitFunc; + OutputInitSubFunc InitSubFunc; - TmEcode (*ThreadInit)(ThreadVars *, void *, void **); - TmEcode (*ThreadDeinit)(ThreadVars *, void *); - void (*ThreadExitPrintStats)(ThreadVars *, void *); + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; PacketLogger PacketLogFunc; PacketLogCondition PacketConditionFunc; @@ -70,113 +73,106 @@ typedef struct OutputModule_ { typedef TAILQ_HEAD(OutputModuleList_, OutputModule_) OutputModuleList; extern OutputModuleList output_modules; -void OutputRegisterModule(const char *, const char *, OutputCtx *(*)(ConfNode *)); +void OutputRegisterModule(const char *, const char *, OutputInitFunc); void OutputRegisterPacketModule(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), - PacketLogger LogFunc, PacketLogCondition ConditionFunc, - ThreadInitFunc, ThreadDeinitFunc, ThreadExitPrintStatsFunc); + const char *conf_name, OutputInitFunc InitFunc, PacketLogger LogFunc, + PacketLogCondition ConditionFunc, ThreadInitFunc, ThreadDeinitFunc, + ThreadExitPrintStatsFunc); void OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, PacketLogger LogFunc, PacketLogCondition ConditionFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxModule(LoggerId id, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, TxLogger TxLogFunc, - TmEcode (*ThreadInit)(ThreadVars *t, void *, void **), - TmEcode (*ThreadDeinit)(ThreadVars *t, void *), - void (*ThreadExitPrintStats)(ThreadVars *, void *)); - +void OutputRegisterTxModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - AppProto alproto, TxLogger TxLogFunc, + OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxSubModuleWithCondition(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), AppProto alproto, +void OutputRegisterTxSubModuleWithCondition(LoggerId id, + const char *parent_name, const char *name, const char *conf_name, + OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); - void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, - int ts_log_progress, ThreadInitFunc ThreadInit, + OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFileModule(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + const char *conf_name, OutputInitFunc InitFunc, FileLogger FileLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), FileLogger FileLogFunc, + OutputInitSubFunc InitFunc, FileLogger FileLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFiledataModule(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + const char *conf_name, OutputInitFunc InitFunc, FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFiledataSubModule(LoggerId, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFlowModule(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + const char *conf_name, OutputInitFunc InitFunc, FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterStreamingModule(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + const char *conf_name, OutputInitFunc InitFunc, StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, + OutputInitSubFunc InitFunc, StreamingLogger StreamingLogFunc, + enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterStatsModule(LoggerId id, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *), + const char *conf_name, OutputInitFunc InitFunc, StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), + OutputInitSubFunc InitFunc, StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); From 9489d5b9e36e4f0fbcffc157a330aad3e8a96563 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 3 Jun 2016 15:38:02 -0600 Subject: [PATCH 1672/2553] logging: remove dead code from output-json The "parent" json logger was setup like a real logger, but some of that code was never being called. --- src/output-json.c | 111 +--------------------------------------- src/output-json.h | 1 - src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - 4 files changed, 1 insertion(+), 113 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index 7fb06c535a82..6a91cbd0fb4a 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -65,45 +65,11 @@ * */ -TmEcode OutputJson (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); -TmEcode OutputJsonThreadInit(ThreadVars *, void *, void **); -TmEcode OutputJsonThreadDeinit(ThreadVars *, void *); int OutputJsonOpenFileCtx(LogFileCtx *, char *); -void OutputJsonRegisterTests(void); void TmModuleOutputJsonRegister (void) { - tmm_modules[TMM_OUTPUTJSON].name = "OutputJSON"; - tmm_modules[TMM_OUTPUTJSON].ThreadInit = OutputJsonThreadInit; - tmm_modules[TMM_OUTPUTJSON].Func = OutputJson; - tmm_modules[TMM_OUTPUTJSON].ThreadDeinit = OutputJsonThreadDeinit; - tmm_modules[TMM_OUTPUTJSON].RegisterTests = OutputJsonRegisterTests; -} - -OutputCtx *OutputJsonInitCtx(ConfNode *conf) -{ - SCLogDebug("Can't init JSON output - JSON support was disabled during build."); - return NULL; -} - -TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogDebug("Can't init JSON output thread - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -TmEcode OutputJson (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) -{ - return TM_ECODE_OK; -} - -TmEcode OutputJsonThreadDeinit(ThreadVars *t, void *data) -{ - return TM_ECODE_FAILED; -} - -void OutputJsonRegisterTests (void) -{ + SCLogDebug("Can't register JSON output - JSON support was disabled during build."); } #else /* implied we do have JSON support */ @@ -116,23 +82,10 @@ void OutputJsonRegisterTests (void) #define OUTPUT_BUFFER_SIZE 65536 -TmEcode OutputJson (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); -TmEcode OutputJsonThreadInit(ThreadVars *, void *, void **); -TmEcode OutputJsonThreadDeinit(ThreadVars *, void *); -void OutputJsonExitPrintStats(ThreadVars *, void *); -void OutputJsonRegisterTests(void); static void OutputJsonDeInitCtx(OutputCtx *); void TmModuleOutputJsonRegister (void) { - tmm_modules[TMM_OUTPUTJSON].name = MODULE_NAME; - tmm_modules[TMM_OUTPUTJSON].ThreadInit = OutputJsonThreadInit; - tmm_modules[TMM_OUTPUTJSON].Func = OutputJson; - tmm_modules[TMM_OUTPUTJSON].ThreadExitPrintStats = OutputJsonExitPrintStats; - tmm_modules[TMM_OUTPUTJSON].ThreadDeinit = OutputJsonThreadDeinit; - tmm_modules[TMM_OUTPUTJSON].RegisterTests = OutputJsonRegisterTests; - tmm_modules[TMM_OUTPUTJSON].cap_flags = 0; - OutputRegisterModule(MODULE_NAME, "eve-log", OutputJsonInitCtx); } @@ -372,51 +325,6 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer) return 0; } -TmEcode OutputJson (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) -{ - return TM_ECODE_OK; -} - -TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - AlertJsonThread *aft = SCMalloc(sizeof(AlertJsonThread)); - if (unlikely(aft == NULL)) - return TM_ECODE_FAILED; - memset(aft, 0, sizeof(AlertJsonThread)); - - if(initdata == NULL) - { - SCLogDebug("Error getting context for EveLog. \"initdata\" argument NULL"); - SCFree(aft); - return TM_ECODE_FAILED; - } - - *data = (void *)aft; - return TM_ECODE_OK; -} - -TmEcode OutputJsonThreadDeinit(ThreadVars *t, void *data) -{ - AlertJsonThread *aft = (AlertJsonThread *)data; - if (aft == NULL) { - return TM_ECODE_OK; - } - - SCFree(aft); - return TM_ECODE_OK; -} - -void OutputJsonExitPrintStats(ThreadVars *tv, void *data) -{ - AlertJsonThread *aft = (AlertJsonThread *)data; - if (aft == NULL) { - return; - } - - SCLogInfo("JSON output wrote %" PRIu64 " alerts", aft->file_ctx->alerts); - -} - /** * \brief Create a new LogFileCtx for "fast" output style. * \param conf The configuration node for this output. @@ -621,21 +529,4 @@ static void OutputJsonDeInitCtx(OutputCtx *output_ctx) SCFree(output_ctx); } -/*------------------------------Unittests-------------------------------------*/ - -#ifdef UNITTESTS - -#endif /* UNITTESTS */ - -/** - * \brief This function registers unit tests for AlertFastLog API. - */ -void OutputJsonRegisterTests(void) -{ - -#ifdef UNITTESTS - -#endif /* UNITTESTS */ - -} #endif diff --git a/src/output-json.h b/src/output-json.h index 467062db33db..7f43392664a4 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -43,7 +43,6 @@ void CreateJSONFlowId(json_t *js, const Flow *f); void JsonTcpFlags(uint8_t flags, json_t *js); json_t *CreateJSONHeader(const Packet *p, int direction_sensative, const char *event_type); json_t *CreateJSONHeaderWithTxId(const Packet *p, int direction_sensitive, const char *event_type, uint64_t tx_id); -TmEcode OutputJSON(json_t *js, void *data, uint64_t *count); int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer); OutputCtx *OutputJsonInitCtx(ConfNode *); diff --git a/src/tm-modules.c b/src/tm-modules.c index d47637f29605..97c4b5223f3f 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -233,7 +233,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_FILELOGGER); CASE_CODE (TMM_FILEDATALOGGER); CASE_CODE (TMM_STREAMINGLOGGER); - CASE_CODE (TMM_OUTPUTJSON); CASE_CODE (TMM_FLOWMANAGER); CASE_CODE (TMM_FLOWRECYCLER); CASE_CODE (TMM_UNIXMANAGER); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index c9a449bcde5f..30ca6740b39a 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -42,7 +42,6 @@ typedef enum { TMM_RECEIVEPFRING, TMM_DECODEPFRING, TMM_RESPONDREJECT, - TMM_OUTPUTJSON, TMM_PCAPLOG, TMM_DECODEIPFW, TMM_VERDICTIPFW, From d2c17ce9a04cf8ce445afbcaf8c801c627abc9cb Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 6 Jun 2016 14:38:56 -0600 Subject: [PATCH 1673/2553] logging: remove output priorities: not used --- src/runmodes.c | 23 +---------------------- src/tm-modules.h | 2 -- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/src/runmodes.c b/src/runmodes.c index b4f319d4081a..2d5bc32aa09c 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -537,30 +537,9 @@ static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx) TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries); } - -static int GetRunModeOutputPriority(RunModeOutput *module) -{ - TmModule *tm = TmModuleGetByName(module->name); - if (tm == NULL) - return 0; - - return tm->priority; -} - static void InsertInRunModeOutputs(RunModeOutput *runmode_output) { - RunModeOutput *r_output = NULL; - int output_priority = GetRunModeOutputPriority(runmode_output); - - TAILQ_FOREACH(r_output, &RunModeOutputs, entries) { - if (GetRunModeOutputPriority(r_output) < output_priority) - break; - } - if (r_output) { - TAILQ_INSERT_BEFORE(r_output, runmode_output, entries); - } else { - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); - } + TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); } /** \brief Turn output into thread module */ diff --git a/src/tm-modules.h b/src/tm-modules.h index e85aa76908e2..4e29aa35563b 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -68,8 +68,6 @@ typedef struct TmModule_ { the given TmModule */ /* Other flags used by the module */ uint8_t flags; - /* priority in the logging order, higher priority is runned first */ - uint8_t priority; } TmModule; TmModule tmm_modules[TMM_SIZE]; From fc35a78ba14c04c528adf198f8f10b97521e8012 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 6 Jun 2016 13:58:37 -0600 Subject: [PATCH 1674/2553] logging: use a single entry point for all loggers Introduces a new thread module, TMM_LOGGER, which is the root most logger. Only handles loggers in the packet path, stats and flow logging are not included. The loggers are made up of a hierarchy of loggers. At the top we have the root logger which is the main entry point to logging. Under the root there exists parent loggers that are the entry point for specific types of loggers such as packet logger, transaction loggers, etc. Each parent logger may have 0 or more loggers that actual handle the job of producing output to something like a file. --- src/output-file.c | 15 ++-- src/output-filedata.c | 17 ++-- src/output-flow.c | 1 - src/output-packet.c | 15 ++-- src/output-stats.c | 6 -- src/output-streaming.c | 16 ++-- src/output-tx.c | 16 +--- src/output.c | 141 +++++++++++++++++++++++++++++++- src/output.h | 9 +++ src/runmode-erf-file.c | 2 +- src/runmode-pcap-file.c | 2 +- src/runmodes.c | 174 ++++------------------------------------ src/runmodes.h | 1 - src/suricata.c | 1 + src/tm-modules.c | 6 +- src/tm-threads-common.h | 7 +- src/util-runmodes.c | 2 +- 17 files changed, 207 insertions(+), 224 deletions(-) diff --git a/src/output-file.c b/src/output-file.c index 995e3200095b..2e23b2a38753 100644 --- a/src/output-file.c +++ b/src/output-file.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "tm-modules.h" +#include "output.h" #include "output-file.h" #include "app-layer.h" #include "app-layer-parser.h" @@ -92,7 +93,11 @@ int OutputRegisterFileLogger(LoggerId id, const char *name, FileLogger LogFunc, static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) { BUG_ON(thread_data == NULL); - BUG_ON(list == NULL); + + if (list == NULL) { + /* No child loggers. */ + return TM_ECODE_OK; + } OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputFileLogger *logger = list; @@ -263,12 +268,8 @@ static void OutputFileLogExitPrintStats(ThreadVars *tv, void *thread_data) void TmModuleFileLoggerRegister (void) { - tmm_modules[TMM_FILELOGGER].name = "__file_logger__"; - tmm_modules[TMM_FILELOGGER].ThreadInit = OutputFileLogThreadInit; - tmm_modules[TMM_FILELOGGER].Func = OutputFileLog; - tmm_modules[TMM_FILELOGGER].ThreadExitPrintStats = OutputFileLogExitPrintStats; - tmm_modules[TMM_FILELOGGER].ThreadDeinit = OutputFileLogThreadDeinit; - tmm_modules[TMM_FILELOGGER].cap_flags = 0; + OutputRegisterRootLogger(OutputFileLogThreadInit, + OutputFileLogThreadDeinit, OutputFileLogExitPrintStats, OutputFileLog); } void OutputFileShutdown(void) diff --git a/src/output-filedata.c b/src/output-filedata.c index 75e3a83fc341..66a66208eca0 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "tm-modules.h" +#include "output.h" #include "output-filedata.h" #include "app-layer.h" #include "app-layer-parser.h" @@ -126,7 +127,11 @@ static int CallLoggers(ThreadVars *tv, OutputLoggerThreadStore *store_list, static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) { BUG_ON(thread_data == NULL); - BUG_ON(list == NULL); + + if (list == NULL) { + /* No child loggers. */ + return TM_ECODE_OK; + } OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputFiledataLogger *logger = list; @@ -431,13 +436,9 @@ static void OutputFiledataLogExitPrintStats(ThreadVars *tv, void *thread_data) void TmModuleFiledataLoggerRegister (void) { - tmm_modules[TMM_FILEDATALOGGER].name = "__filedata_logger__"; - tmm_modules[TMM_FILEDATALOGGER].ThreadInit = OutputFiledataLogThreadInit; - tmm_modules[TMM_FILEDATALOGGER].Func = OutputFiledataLog; - tmm_modules[TMM_FILEDATALOGGER].ThreadExitPrintStats = OutputFiledataLogExitPrintStats; - tmm_modules[TMM_FILEDATALOGGER].ThreadDeinit = OutputFiledataLogThreadDeinit; - tmm_modules[TMM_FILEDATALOGGER].cap_flags = 0; - + OutputRegisterRootLogger(OutputFiledataLogThreadInit, + OutputFiledataLogThreadDeinit, OutputFiledataLogExitPrintStats, + OutputFiledataLog); SC_ATOMIC_INIT(file_id); } diff --git a/src/output-flow.c b/src/output-flow.c index 6113631d9f85..235c6578e63e 100644 --- a/src/output-flow.c +++ b/src/output-flow.c @@ -93,7 +93,6 @@ TmEcode OutputFlowLog(ThreadVars *tv, void *thread_data, Flow *f) if (list == NULL) return TM_ECODE_OK; - //BUG_ON(list == NULL); OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputFlowLogger *logger = list; diff --git a/src/output-packet.c b/src/output-packet.c index 94197fbc9dc0..85385e437b3a 100644 --- a/src/output-packet.c +++ b/src/output-packet.c @@ -93,7 +93,11 @@ int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, static TmEcode OutputPacketLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) { BUG_ON(thread_data == NULL); - BUG_ON(list == NULL); + + if (list == NULL) { + /* No child loggers. */ + return TM_ECODE_OK; + } OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputPacketLogger *logger = list; @@ -207,12 +211,9 @@ static void OutputPacketLogExitPrintStats(ThreadVars *tv, void *thread_data) void TmModulePacketLoggerRegister (void) { - tmm_modules[TMM_PACKETLOGGER].name = "__packet_logger__"; - tmm_modules[TMM_PACKETLOGGER].ThreadInit = OutputPacketLogThreadInit; - tmm_modules[TMM_PACKETLOGGER].Func = OutputPacketLog; - tmm_modules[TMM_PACKETLOGGER].ThreadExitPrintStats = OutputPacketLogExitPrintStats; - tmm_modules[TMM_PACKETLOGGER].ThreadDeinit = OutputPacketLogThreadDeinit; - tmm_modules[TMM_PACKETLOGGER].cap_flags = 0; + OutputRegisterRootLogger(OutputPacketLogThreadInit, + OutputPacketLogThreadDeinit, OutputPacketLogExitPrintStats, + OutputPacketLog); } void OutputPacketShutdown(void) diff --git a/src/output-stats.c b/src/output-stats.c index 47fedf05c775..2eb9c9323fa9 100644 --- a/src/output-stats.c +++ b/src/output-stats.c @@ -168,12 +168,7 @@ static TmEcode OutputStatsLogThreadDeinit(ThreadVars *tv, void *thread_data) while (logger && store) { if (logger->ThreadDeinit) { logger->ThreadDeinit(tv, store->thread_data); - } else { - /* XXX Temporary. */ - SCLogNotice("Logger {%s} does not have ThreadDeinit.", - logger->name); } - OutputLoggerThreadStore *next_store = store->next; SCFree(store); store = next_store; @@ -204,7 +199,6 @@ void TmModuleStatsLoggerRegister (void) { tmm_modules[TMM_STATSLOGGER].name = "__stats_logger__"; tmm_modules[TMM_STATSLOGGER].ThreadInit = OutputStatsLogThreadInit; - //tmm_modules[TMM_STATSLOGGER].Func = OutputStatsLog; tmm_modules[TMM_STATSLOGGER].ThreadExitPrintStats = OutputStatsLogExitPrintStats; tmm_modules[TMM_STATSLOGGER].ThreadDeinit = OutputStatsLogThreadDeinit; tmm_modules[TMM_STATSLOGGER].cap_flags = 0; diff --git a/src/output-streaming.c b/src/output-streaming.c index 9413721986cf..744ead6f274e 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "tm-modules.h" +#include "output.h" #include "output-streaming.h" #include "app-layer.h" #include "app-layer-parser.h" @@ -300,7 +301,11 @@ int StreamIterator(Flow *f, TcpStream *stream, int close, void *cbdata, uint8_t static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) { BUG_ON(thread_data == NULL); - BUG_ON(list == NULL); + + if (list == NULL) { + /* No child loggers. */ + return TM_ECODE_OK; + } OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputStreamingLogger *logger = list; @@ -437,12 +442,9 @@ static void OutputStreamingLogExitPrintStats(ThreadVars *tv, void *thread_data) } void TmModuleStreamingLoggerRegister (void) { - tmm_modules[TMM_STREAMINGLOGGER].name = "__streaming_logger__"; - tmm_modules[TMM_STREAMINGLOGGER].ThreadInit = OutputStreamingLogThreadInit; - tmm_modules[TMM_STREAMINGLOGGER].Func = OutputStreamingLog; - tmm_modules[TMM_STREAMINGLOGGER].ThreadExitPrintStats = OutputStreamingLogExitPrintStats; - tmm_modules[TMM_STREAMINGLOGGER].ThreadDeinit = OutputStreamingLogThreadDeinit; - tmm_modules[TMM_STREAMINGLOGGER].cap_flags = 0; + OutputRegisterRootLogger(OutputStreamingLogThreadInit, + OutputStreamingLogThreadDeinit, OutputStreamingLogExitPrintStats, + OutputStreamingLog); } void OutputStreamingShutdown(void) diff --git a/src/output-tx.c b/src/output-tx.c index 3d37e89e8ec3..f68b1aa85e43 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "tm-modules.h" +#include "output.h" #include "output-tx.h" #include "app-layer.h" #include "app-layer-parser.h" @@ -70,12 +71,6 @@ int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, ThreadDeinitFunc ThreadDeinit, void (*ThreadExitPrintStats)(ThreadVars *, void *)) { -#if 0 - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; -#endif - if (!(AppLayerParserIsTxAware(alproto))) { SCLogNotice("%s logger not enabled: protocol %s is disabled", name, AppProtoToString(alproto)); @@ -267,7 +262,6 @@ static TmEcode OutputTxLogThreadInit(ThreadVars *tv, void *initdata, void **data memset(td, 0x00, sizeof(*td)); *data = (void *)td; - SCLogDebug("OutputTxLogThreadInit happy (*data %p)", *data); OutputTxLogger *logger = list; @@ -340,12 +334,8 @@ static void OutputTxLogExitPrintStats(ThreadVars *tv, void *thread_data) void TmModuleTxLoggerRegister (void) { - tmm_modules[TMM_TXLOGGER].name = "__tx_logger__"; - tmm_modules[TMM_TXLOGGER].ThreadInit = OutputTxLogThreadInit; - tmm_modules[TMM_TXLOGGER].Func = OutputTxLog; - tmm_modules[TMM_TXLOGGER].ThreadExitPrintStats = OutputTxLogExitPrintStats; - tmm_modules[TMM_TXLOGGER].ThreadDeinit = OutputTxLogThreadDeinit; - tmm_modules[TMM_TXLOGGER].cap_flags = 0; + OutputRegisterRootLogger(OutputTxLogThreadInit, OutputTxLogThreadDeinit, + OutputTxLogExitPrintStats, OutputTxLog); } void OutputTxShutdown(void) diff --git a/src/output.c b/src/output.c index 9466dbb23bd5..180f54fe95a1 100644 --- a/src/output.c +++ b/src/output.c @@ -18,9 +18,18 @@ /** * \file * + * \author OISF, Jason Ish * \author Endace Technology Limited, Jason Ish * - * Output registration functions + * The root logging output for all non-application logging. + * + * The loggers are made up of a hierarchy of loggers. At the top we + * have the root logger which is the main entry point to + * logging. Under the root there exists parent loggers that are the + * entry point for specific types of loggers such as packet logger, + * transaction loggers, etc. Each parent logger may have 0 or more + * loggers that actual handle the job of producing output to something + * like a file. */ #include "suricata-common.h" @@ -31,6 +40,25 @@ #include "util-debug.h" #include "output.h" +typedef struct RootLogger_ { + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; + OutputLogFunc LogFunc; + + TAILQ_ENTRY(RootLogger_) entries; +} RootLogger; + +static TAILQ_HEAD(, RootLogger_) RootLoggers = + TAILQ_HEAD_INITIALIZER(RootLoggers); + +typedef struct LoggerThreadStoreNode_ { + void *thread_data; + TAILQ_ENTRY(LoggerThreadStoreNode_) entries; +} LoggerThreadStoreNode; + +typedef TAILQ_HEAD(LoggerThreadStore_, LoggerThreadStoreNode_) LoggerThreadStore; + OutputModuleList output_modules = TAILQ_HEAD_INITIALIZER(output_modules); /** @@ -851,3 +879,114 @@ void OutputNotifyFileRotation(void) { *(flag->flag) = 1; } } + +static TmEcode OutputLoggerLog(ThreadVars *tv, Packet *p, void *thread_data, + PacketQueue *pq, PacketQueue *postpq) +{ + LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data; + RootLogger *logger = TAILQ_FIRST(&RootLoggers); + LoggerThreadStoreNode *thread_store_node = TAILQ_FIRST(thread_store); + while (logger && thread_store_node) { + if (logger->LogFunc != NULL) { + logger->LogFunc(tv, p, thread_store_node->thread_data, pq, postpq); + } + logger = TAILQ_NEXT(logger, entries); + thread_store_node = TAILQ_NEXT(thread_store_node, entries); + } + + return TM_ECODE_OK; +} + +static TmEcode OutputLoggerThreadInit(ThreadVars *tv, void *initdata, + void **data) +{ + LoggerThreadStore *thread_store = SCCalloc(1, sizeof(*thread_store)); + if (thread_store == NULL) { + return TM_ECODE_FAILED; + } + TAILQ_INIT(thread_store); + *data = (void *)thread_store; + + RootLogger *logger; + TAILQ_FOREACH(logger, &RootLoggers, entries) { + + void *child_thread_data = NULL; + if (logger->ThreadInit != NULL) { + if (logger->ThreadInit(tv, initdata, &child_thread_data) == TM_ECODE_OK) { + LoggerThreadStoreNode *thread_store_node = + SCCalloc(1, sizeof(*thread_store_node)); + BUG_ON(thread_store_node == NULL); + thread_store_node->thread_data = child_thread_data; + TAILQ_INSERT_TAIL(thread_store, thread_store_node, entries); + } + } + } + return TM_ECODE_OK; +} + +static TmEcode OutputLoggerThreadDeinit(ThreadVars *tv, void *thread_data) +{ + LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data; + RootLogger *logger = TAILQ_FIRST(&RootLoggers); + LoggerThreadStoreNode *thread_store_node = TAILQ_FIRST(thread_store); + while (logger && thread_store_node) { + if (logger->ThreadDeinit != NULL) { + logger->ThreadDeinit(tv, thread_store_node->thread_data); + } + logger = TAILQ_NEXT(logger, entries); + thread_store_node = TAILQ_NEXT(thread_store_node, entries); + } + + /* Free the thread store. */ + while ((thread_store_node = TAILQ_FIRST(thread_store)) != NULL) { + TAILQ_REMOVE(thread_store, thread_store_node, entries); + SCFree(thread_store_node); + } + SCFree(thread_store); + + return TM_ECODE_OK; +} + +static void OutputLoggerExitPrintStats(ThreadVars *tv, void *thread_data) +{ + LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data; + RootLogger *logger = TAILQ_FIRST(&RootLoggers); + LoggerThreadStoreNode *thread_store_node = TAILQ_FIRST(thread_store); + while (logger && thread_store_node) { + if (logger->ThreadExitPrintStats != NULL) { + logger->ThreadExitPrintStats(tv, thread_store_node->thread_data); + } + logger = TAILQ_NEXT(logger, entries); + thread_store_node = TAILQ_NEXT(thread_store_node, entries); + } +} + +void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats, + OutputLogFunc LogFunc) +{ + RootLogger *logger = SCCalloc(1, sizeof(*logger)); + if (logger == NULL) { + return; + } + logger->ThreadInit = ThreadInit; + logger->ThreadDeinit = ThreadDeinit; + logger->ThreadExitPrintStats = ThreadExitPrintStats; + logger->LogFunc = LogFunc; + TAILQ_INSERT_TAIL(&RootLoggers, logger, entries); +} + +void TmModuleLoggerRegister(void) +{ + tmm_modules[TMM_LOGGER].name = "__root_logger__"; + tmm_modules[TMM_LOGGER].ThreadInit = OutputLoggerThreadInit; + tmm_modules[TMM_LOGGER].ThreadDeinit = OutputLoggerThreadDeinit; + tmm_modules[TMM_LOGGER].ThreadExitPrintStats = OutputLoggerExitPrintStats; + tmm_modules[TMM_LOGGER].Func = OutputLoggerLog;; +} + +void SetupOutputs(ThreadVars *tv) +{ + TmSlotSetFuncAppend(tv, &tmm_modules[TMM_LOGGER], NULL); +} diff --git a/src/output.h b/src/output.h index f6a8cc6dcc68..009d4995be62 100644 --- a/src/output.h +++ b/src/output.h @@ -40,6 +40,8 @@ typedef OutputCtx *(*OutputInitFunc)(ConfNode *); typedef OutputCtx *(*OutputInitSubFunc)(ConfNode *, OutputCtx *); +typedef TmEcode (*OutputLogFunc)(ThreadVars *, Packet *, void *, PacketQueue *, + PacketQueue *); typedef struct OutputModule_ { LoggerId logger_id; @@ -190,4 +192,11 @@ void OutputRegisterFileRotationFlag(int *flag); void OutputUnregisterFileRotationFlag(int *flag); void OutputNotifyFileRotation(void); +void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats, + OutputLogFunc LogFunc); +void TmModuleLoggerRegister(void); +void SetupOutputs(ThreadVars *); + #endif /* ! __OUTPUT_H__ */ diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index e4f3c3df9374..714f2af156e9 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -231,7 +231,7 @@ int RunModeErfFileAutoFp(void) TmThreadSetGroupName(tv_detect_ncpu, "Detect"); - /* add outputs as well */ + /* Add logger. */ SetupOutputs(tv_detect_ncpu); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index 9db65d485e30..e671a4a7b665 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -250,7 +250,7 @@ int RunModeFilePcapAutoFp(void) TmThreadSetGroupName(tv_detect_ncpu, "Detect"); - /* add outputs as well */ + /* Add logger. */ SetupOutputs(tv_detect_ncpu); TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); diff --git a/src/runmodes.c b/src/runmodes.c index 2d5bc32aa09c..f98343c82e98 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -87,19 +87,6 @@ typedef struct RunModes_ { RunMode *runmodes; } RunModes; -/** - * A list of output modules that will be active for the run mode. - */ -typedef struct RunModeOutput_ { - const char *name; - TmModule *tm_module; - OutputCtx *output_ctx; - - TAILQ_ENTRY(RunModeOutput_) entries; -} RunModeOutput; -TAILQ_HEAD(, RunModeOutput_) RunModeOutputs = - TAILQ_HEAD_INITIALIZER(RunModeOutputs); - static RunModes runmodes[RUNMODE_USER_MAX]; static char *active_runmode; @@ -111,7 +98,7 @@ typedef struct OutputFreeList_ { TAILQ_ENTRY(OutputFreeList_) entries; } OutputFreeList; -TAILQ_HEAD(, OutputFreeList_) output_free_list = +static TAILQ_HEAD(, OutputFreeList_) output_free_list = TAILQ_HEAD_INITIALIZER(output_free_list); /** @@ -462,7 +449,7 @@ void RunModeRegisterNewRunMode(int runmode, const char *name, * \param tv The ThreadVars for the thread the outputs will be * appended to. */ -void RunOutputFreeList(void) +static void RunOutputFreeList(void) { OutputFreeList *output; while ((output = TAILQ_FIRST(&output_free_list))) { @@ -477,20 +464,17 @@ void RunOutputFreeList(void) } } -static TmModule *pkt_logger_module = NULL; -static TmModule *tx_logger_module = NULL; -static TmModule *file_logger_module = NULL; -static TmModule *filedata_logger_module = NULL; -static TmModule *streaming_logger_module = NULL; +static int file_logger_count = 0; +static int filedata_logger_count = 0; int RunModeOutputFileEnabled(void) { - return (file_logger_module != NULL); + return file_logger_count > 0; } int RunModeOutputFiledataEnabled(void) { - return (filedata_logger_module != NULL); + return filedata_logger_count > 0; } /** @@ -508,20 +492,9 @@ void RunModeShutDown(void) OutputStatsShutdown(); OutputFlowShutdown(); - /* Close any log files. */ - RunModeOutput *output; - while ((output = TAILQ_FIRST(&RunModeOutputs))) { - SCLogDebug("Shutting down output %s.", output->tm_module->name); - TAILQ_REMOVE(&RunModeOutputs, output, entries); - SCFree(output); - } - - /* reset logger pointers */ - pkt_logger_module = NULL; - tx_logger_module = NULL; - file_logger_module = NULL; - filedata_logger_module = NULL; - streaming_logger_module = NULL; + /* Reset logger counts. */ + file_logger_count = 0; + filedata_logger_count = 0; } /** \internal @@ -537,11 +510,6 @@ static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx) TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries); } -static void InsertInRunModeOutputs(RunModeOutput *runmode_output) -{ - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); -} - /** \brief Turn output into thread module */ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *output_ctx) { @@ -565,30 +533,11 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } if (module->PacketLogFunc) { - SCLogNotice("%s is a packet logger", module->name); + SCLogDebug("%s is a packet logger", module->name); OutputRegisterPacketLogger(module->logger_id, module->name, module->PacketLogFunc, module->PacketConditionFunc, output_ctx, module->ThreadInit, module->ThreadDeinit, module->ThreadExitPrintStats); - - /* need one instance of the packet logger module */ - if (pkt_logger_module == NULL) { - pkt_logger_module = TmModuleGetByName("__packet_logger__"); - if (pkt_logger_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __packet_logger__ failed"); - exit(EXIT_FAILURE); - } - - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->name = module->name; - runmode_output->tm_module = pkt_logger_module; - runmode_output->output_ctx = NULL; - InsertInRunModeOutputs(runmode_output); - SCLogDebug("__packet_logger__ added"); - } } else if (module->TxLogFunc) { SCLogDebug("%s is a tx logger", module->name); OutputRegisterTxLogger(module->logger_id, module->name, module->alproto, @@ -596,107 +545,27 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu module->ts_log_progress, module->TxLogCondition, module->ThreadInit, module->ThreadDeinit, module->ThreadExitPrintStats); - - /* need one instance of the tx logger module */ - if (tx_logger_module == NULL) { - tx_logger_module = TmModuleGetByName("__tx_logger__"); - if (tx_logger_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __tx_logger__ failed"); - exit(EXIT_FAILURE); - } - - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->name = module->name; - runmode_output->tm_module = tx_logger_module; - runmode_output->output_ctx = NULL; - InsertInRunModeOutputs(runmode_output); - SCLogDebug("__tx_logger__ added"); - } } else if (module->FiledataLogFunc) { SCLogDebug("%s is a filedata logger", module->name); OutputRegisterFiledataLogger(module->logger_id, module->name, module->FiledataLogFunc, output_ctx, module->ThreadInit, module->ThreadDeinit, module->ThreadExitPrintStats); - - /* need one instance of the tx logger module */ - if (filedata_logger_module == NULL) { - filedata_logger_module = TmModuleGetByName("__filedata_logger__"); - if (filedata_logger_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __filedata_logger__ failed"); - exit(EXIT_FAILURE); - } - - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->name = module->name; - runmode_output->tm_module = filedata_logger_module; - runmode_output->output_ctx = NULL; - InsertInRunModeOutputs(runmode_output); - SCLogDebug("__filedata_logger__ added"); - } + filedata_logger_count++; } else if (module->FileLogFunc) { SCLogDebug("%s is a file logger", module->name); OutputRegisterFileLogger(module->logger_id, module->name, module->FileLogFunc, output_ctx, module->ThreadInit, module->ThreadDeinit, module->ThreadExitPrintStats); - - /* need one instance of the tx logger module */ - if (file_logger_module == NULL) { - file_logger_module = TmModuleGetByName("__file_logger__"); - if (file_logger_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __file_logger__ failed"); - exit(EXIT_FAILURE); - } - - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->name = module->name; - runmode_output->tm_module = file_logger_module; - runmode_output->output_ctx = NULL; - InsertInRunModeOutputs(runmode_output); - SCLogDebug("__file_logger__ added"); - } + file_logger_count++; } else if (module->StreamingLogFunc) { SCLogDebug("%s is a streaming logger", module->name); OutputRegisterStreamingLogger(module->logger_id, module->name, module->StreamingLogFunc, output_ctx, module->stream_type, module->ThreadInit, module->ThreadDeinit, module->ThreadExitPrintStats); - - /* need one instance of the streaming logger module */ - if (streaming_logger_module == NULL) { - streaming_logger_module = TmModuleGetByName("__streaming_logger__"); - if (streaming_logger_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __streaming_logger__ failed"); - exit(EXIT_FAILURE); - } - - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->name = module->name; - runmode_output->tm_module = streaming_logger_module; - runmode_output->output_ctx = NULL; - InsertInRunModeOutputs(runmode_output); - SCLogDebug("__streaming_logger__ added"); - } } else { - SCLogDebug("%s is a regular logger", module->name); - - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->name = module->name; - runmode_output->output_ctx = output_ctx; - InsertInRunModeOutputs(runmode_output); + SCLogError(SC_ERR_INVALID_ARGUMENT, "Unknown logger type: name=%s", + module->name); } } @@ -945,21 +814,6 @@ void RunModeInitializeOutputs(void) } -/** - * Setup the outputs for this run mode. - * - * \param tv The ThreadVars for the thread the outputs will be - * appended to. - */ -void SetupOutputs(ThreadVars *tv) -{ - RunModeOutput *output; - TAILQ_FOREACH(output, &RunModeOutputs, entries) { - tv->cap_flags |= output->tm_module->cap_flags; - TmSlotSetFuncAppend(tv, output->tm_module, output->output_ctx); - } -} - float threading_detect_ratio = 1; /** diff --git a/src/runmodes.h b/src/runmodes.h index 0f1884e990ad..2a38fb50244e 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -82,7 +82,6 @@ void RunModeRegisterNewRunMode(int, const char *, const char *, int (*RunModeFunc)(void)); void RunModeInitialize(void); void RunModeInitializeOutputs(void); -void SetupOutputs(ThreadVars *); void RunModeShutDown(void); /* bool indicating if file logger is enabled */ diff --git a/src/suricata.c b/src/suricata.c index 4c1c6a67594d..dd45b1d36372 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -919,6 +919,7 @@ void RegisterAllModules() TmModuleJsonTemplateLogRegister(); /* log api */ + TmModuleLoggerRegister(); TmModulePacketLoggerRegister(); TmModuleTxLoggerRegister(); TmModuleFileLoggerRegister(); diff --git a/src/tm-modules.c b/src/tm-modules.c index 97c4b5223f3f..4a109fd6a2aa 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -227,18 +227,14 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_RECEIVEAFP); CASE_CODE (TMM_ALERTPCAPINFO); CASE_CODE (TMM_DECODEAFP); - CASE_CODE (TMM_PACKETLOGGER); - CASE_CODE (TMM_TXLOGGER); CASE_CODE (TMM_STATSLOGGER); - CASE_CODE (TMM_FILELOGGER); - CASE_CODE (TMM_FILEDATALOGGER); - CASE_CODE (TMM_STREAMINGLOGGER); CASE_CODE (TMM_FLOWMANAGER); CASE_CODE (TMM_FLOWRECYCLER); CASE_CODE (TMM_UNIXMANAGER); CASE_CODE (TMM_DETECTLOADER); CASE_CODE (TMM_RECEIVENETMAP); CASE_CODE (TMM_DECODENETMAP); + CASE_CODE (TMM_LOGGER); CASE_CODE (TMM_SIZE); } diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 30ca6740b39a..cdb384c55c77 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -59,12 +59,7 @@ typedef enum { TMM_DECODEMPIPE, TMM_RECEIVENAPATECH, TMM_DECODENAPATECH, - TMM_PACKETLOGGER, - TMM_TXLOGGER, TMM_STATSLOGGER, - TMM_FILELOGGER, - TMM_FILEDATALOGGER, - TMM_STREAMINGLOGGER, TMM_RECEIVENFLOG, TMM_DECODENFLOG, @@ -74,6 +69,8 @@ typedef enum { TMM_UNIXMANAGER, + TMM_LOGGER, + TMM_SIZE, } TmmId; diff --git a/src/util-runmodes.c b/src/util-runmodes.c index b7e8f09ccad3..26925c2ecaf1 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -257,7 +257,7 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - /* add outputs as well */ + /* Add logger. */ SetupOutputs(tv_detect_ncpu); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { From a093580527cf6cfa448be02f27681f561520492c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 7 Jun 2016 14:55:18 -0600 Subject: [PATCH 1675/2553] logging: just return if no tx loggers --- src/output-tx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/output-tx.c b/src/output-tx.c index f68b1aa85e43..b39967c89917 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -130,7 +130,10 @@ int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) { BUG_ON(thread_data == NULL); - BUG_ON(list == NULL); + if (list == NULL) { + /* No child loggers registered. */ + return TM_ECODE_OK; + } OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputTxLogger *logger = list; From 04a44a077d06567b68381ee8e62e45237b958fec Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 7 Jun 2016 14:56:17 -0600 Subject: [PATCH 1676/2553] logging: convert pcap log to non-thread module --- src/log-pcap.c | 32 ++++++++++++++++++++------------ src/suricata-common.h | 1 + src/tm-modules.c | 1 - src/tm-threads-common.h | 1 - src/util-profiling.c | 1 + 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/log-pcap.c b/src/log-pcap.c index 076c44269e3e..4ff1b4d5c94c 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -143,22 +143,19 @@ typedef struct PcapLogThreadData_ { static PcapLogData *g_pcap_data = NULL; static int PcapLogOpenFileCtx(PcapLogData *); -static TmEcode PcapLog(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); +static int PcapLog(ThreadVars *, void *, const Packet *); static TmEcode PcapLogDataInit(ThreadVars *, void *, void **); static TmEcode PcapLogDataDeinit(ThreadVars *, void *); static void PcapLogFileDeInitCtx(OutputCtx *); static OutputCtx *PcapLogInitCtx(ConfNode *); static void PcapLogProfilingDump(PcapLogData *); +static int PcapLogCondition(ThreadVars *, const Packet *); void TmModulePcapLogRegister(void) { - tmm_modules[TMM_PCAPLOG].name = MODULE_NAME; - tmm_modules[TMM_PCAPLOG].ThreadInit = PcapLogDataInit; - tmm_modules[TMM_PCAPLOG].Func = PcapLog; - tmm_modules[TMM_PCAPLOG].ThreadDeinit = PcapLogDataDeinit; - tmm_modules[TMM_PCAPLOG].RegisterTests = NULL; - - OutputRegisterModule(MODULE_NAME, "pcap-log", PcapLogInitCtx); + OutputRegisterPacketModule(LOGGER_PCAP, MODULE_NAME, "pcap-log", + PcapLogInitCtx, PcapLog, PcapLogCondition, PcapLogDataInit, + PcapLogDataDeinit, NULL); SC_ATOMIC_INIT(thread_cnt); return; @@ -171,6 +168,17 @@ void TmModulePcapLogRegister(void) (prof).total += (UtilCpuGetTicks() - pcaplog_profile_ticks); \ (prof).cnt++ +static int PcapLogCondition(ThreadVars *tv, const Packet *p) +{ + if (p->flags & PKT_PSEUDO_STREAM_END) { + return FALSE; + } + if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) { + return FALSE; + } + return TRUE; +} + /** * \brief Function to close pcaplog file * @@ -281,7 +289,7 @@ static int PcapLogRotateFile(ThreadVars *t, PcapLogData *pl) return 0; } -static int PcapLogOpenHandles(PcapLogData *pl, Packet *p) +static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p) { PCAPLOG_PROFILE_START; @@ -345,8 +353,7 @@ static void PcapLogUnlock(PcapLogData *pl) * \retval TM_ECODE_OK on succes * \retval TM_ECODE_FAILED on serious error */ -static TmEcode PcapLog (ThreadVars *t, Packet *p, void *thread_data, PacketQueue *pq, - PacketQueue *postpq) +static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) { size_t len; int rotate = 0; @@ -572,6 +579,7 @@ static TmEcode PcapLogDataDeinit(ThreadVars *t, void *thread_data) pl->reported = 1; } } + SCFree(td); return TM_ECODE_OK; } @@ -894,7 +902,7 @@ static void PcapLogFileDeInitCtx(OutputCtx *output_ctx) TAILQ_FOREACH(pf, &pl->pcap_file_list, next) { SCLogDebug("PCAP files left at exit: %s\n", pf->filename); } - + SCFree(output_ctx); return; } diff --git a/src/suricata-common.h b/src/suricata-common.h index b837de26addb..fedccf31ceb0 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -369,6 +369,7 @@ typedef enum { LOGGER_STATS, LOGGER_JSON_STATS, LOGGER_PRELUDE, + LOGGER_PCAP, LOGGER_SIZE, } LoggerId; diff --git a/src/tm-modules.c b/src/tm-modules.c index 4a109fd6a2aa..f0d8b89019f4 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -212,7 +212,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_RECEIVEPFRING); CASE_CODE (TMM_DECODEPFRING); CASE_CODE (TMM_RESPONDREJECT); - CASE_CODE (TMM_PCAPLOG); CASE_CODE (TMM_DECODEIPFW); CASE_CODE (TMM_VERDICTIPFW); CASE_CODE (TMM_RECEIVEIPFW); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index cdb384c55c77..a0ca3bcad848 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -42,7 +42,6 @@ typedef enum { TMM_RECEIVEPFRING, TMM_DECODEPFRING, TMM_RESPONDREJECT, - TMM_PCAPLOG, TMM_DECODEIPFW, TMM_VERDICTIPFW, TMM_RECEIVEIPFW, diff --git a/src/util-profiling.c b/src/util-profiling.c index cbbef0c20a83..5f6aa2066079 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1278,6 +1278,7 @@ const char * PacketProfileLoggertIdToString(LoggerId id) CASE_CODE (LOGGER_STATS); CASE_CODE (LOGGER_JSON_STATS); CASE_CODE (LOGGER_PRELUDE); + CASE_CODE (LOGGER_PCAP); default: return "UNKNOWN"; } From 1b4ba4496c9dc08b61e26d169c6a05dd0df47a0b Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 7 Jun 2016 17:20:23 -0600 Subject: [PATCH 1677/2553] logging: rename registration functions to not have tmm As the logging modules are no longer threading modules, rename them so they don't look like they are being registered as threading modules. Also, move the registration to the output.c which will handle registration of the loggers. --- src/alert-debuglog.c | 2 +- src/alert-debuglog.h | 2 +- src/alert-fastlog.c | 2 +- src/alert-fastlog.h | 2 +- src/alert-prelude.c | 4 +- src/alert-prelude.h | 2 +- src/alert-syslog.c | 2 +- src/alert-syslog.h | 2 +- src/alert-unified2-alert.c | 2 +- src/alert-unified2-alert.h | 2 +- src/log-dnslog.c | 2 +- src/log-dnslog.h | 2 +- src/log-droplog.c | 2 +- src/log-droplog.h | 2 +- src/log-file.c | 2 +- src/log-file.h | 2 +- src/log-filestore.c | 2 +- src/log-filestore.h | 2 +- src/log-httplog.c | 2 +- src/log-httplog.h | 2 +- src/log-pcap.c | 4 +- src/log-pcap.h | 2 +- src/log-stats.c | 2 +- src/log-stats.h | 2 +- src/log-tcp-data.c | 2 +- src/log-tcp-data.h | 2 +- src/log-tlslog.c | 2 +- src/log-tlslog.h | 2 +- src/log-tlsstore.c | 2 +- src/log-tlsstore.h | 2 +- src/output-file.c | 2 +- src/output-file.h | 2 +- src/output-filedata.c | 2 +- src/output-filedata.h | 2 +- src/output-json-alert.c | 4 +- src/output-json-alert.h | 2 +- src/output-json-dns.c | 4 +- src/output-json-dns.h | 2 +- src/output-json-drop.c | 4 +- src/output-json-drop.h | 2 +- src/output-json-file.c | 4 +- src/output-json-file.h | 2 +- src/output-json-flow.c | 4 +- src/output-json-flow.h | 2 +- src/output-json-http.c | 4 +- src/output-json-http.h | 2 +- src/output-json-netflow.c | 4 +- src/output-json-netflow.h | 2 +- src/output-json-smtp.c | 4 +- src/output-json-smtp.h | 2 +- src/output-json-ssh.c | 4 +- src/output-json-ssh.h | 2 +- src/output-json-stats.c | 4 +- src/output-json-stats.h | 2 +- src/output-json-template.c | 4 +- src/output-json-template.h | 2 +- src/output-json-tls.c | 4 +- src/output-json-tls.h | 2 +- src/output-json.c | 4 +- src/output-json.h | 2 +- src/output-lua.c | 4 +- src/output-lua.h | 2 +- src/output-packet.c | 2 +- src/output-packet.h | 2 +- src/output-streaming.c | 2 +- src/output-streaming.h | 2 +- src/output-tx.c | 2 +- src/output-tx.h | 2 +- src/output.c | 110 ++++++++++++++++++++++++++++++++++++- src/suricata.c | 97 +------------------------------- 70 files changed, 194 insertions(+), 181 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 931fa70cba41..1f2f5a4553e7 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -510,7 +510,7 @@ static int AlertDebugLogLogger(ThreadVars *tv, void *thread_data, const Packet * return TM_ECODE_OK; } -void TmModuleAlertDebugLogRegister (void) +void AlertDebugLogRegister(void) { OutputRegisterPacketModule(LOGGER_ALERT_DEBUG, MODULE_NAME, "alert-debug", AlertDebugLogInitCtx, AlertDebugLogLogger, AlertDebugLogCondition, diff --git a/src/alert-debuglog.h b/src/alert-debuglog.h index 8eb38d977c2a..f7c411c3ab3e 100644 --- a/src/alert-debuglog.h +++ b/src/alert-debuglog.h @@ -24,7 +24,7 @@ #ifndef __ALERT_DEBUGLOG_H__ #define __ALERT_DEBUGLOG_H__ -void TmModuleAlertDebugLogRegister (void); +void AlertDebugLogRegister(void); #endif /* __ALERT_DEBUGLOG_H__ */ diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 42d601997c27..3fac2f66dfcd 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -76,7 +76,7 @@ static void AlertFastLogDeInitCtx(OutputCtx *); int AlertFastLogCondition(ThreadVars *tv, const Packet *p); int AlertFastLogger(ThreadVars *tv, void *data, const Packet *p); -void TmModuleAlertFastLogRegister (void) +void AlertFastLogRegister(void) { OutputRegisterPacketModule(LOGGER_ALERT_FAST, MODULE_NAME, "fast", AlertFastLogInitCtx, AlertFastLogger, AlertFastLogCondition, diff --git a/src/alert-fastlog.h b/src/alert-fastlog.h index ac3c45a7cf9d..96bd0118abc9 100644 --- a/src/alert-fastlog.h +++ b/src/alert-fastlog.h @@ -24,7 +24,7 @@ #ifndef __ALERT_FASTLOG_H__ #define __ALERT_FASTLOG_H__ -void TmModuleAlertFastLogRegister(void); +void AlertFastLogRegister(void); void TmModuleAlertFastLogIPv4Register(void); void TmModuleAlertFastLogIPv6Register(void); OutputCtx *AlertFastLogInitCtx(ConfNode *); diff --git a/src/alert-prelude.c b/src/alert-prelude.c index 399641015581..8fd9b7ba64da 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -62,7 +62,7 @@ /* Handle the case where no PRELUDE support is compiled in. */ -void TmModuleAlertPreludeRegister (void) +void AlertPreludeRegister(void) { SCLogDebug("Can't register Prelude output thread - Prelude support was disabled during build."); } @@ -914,7 +914,7 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p SCReturnInt(TM_ECODE_FAILED); } -void TmModuleAlertPreludeRegister (void) +void AlertPreludeRegister (void) { OutputRegisterPacketModule(LOGGER_PRELUDE, "AlertPrelude", "alert-prelude", AlertPreludeInitCtx, AlertPreludeLogger, AlertPreludeCondition, diff --git a/src/alert-prelude.h b/src/alert-prelude.h index 7a30e847ea1f..0f15961f091f 100644 --- a/src/alert-prelude.h +++ b/src/alert-prelude.h @@ -26,6 +26,6 @@ #ifndef __ALERT_PRELUDE_H__ #define __ALERT_PRELUDE_H__ -void TmModuleAlertPreludeRegister (void); +void AlertPreludeRegister(void); #endif /* __ALERT_PRELUDE_H__ */ diff --git a/src/alert-syslog.c b/src/alert-syslog.c index 3d312c9a01d2..869e33acf361 100644 --- a/src/alert-syslog.c +++ b/src/alert-syslog.c @@ -408,7 +408,7 @@ static int AlertSyslogLogger(ThreadVars *tv, void *thread_data, const Packet *p) #endif /* !OS_WIN32 */ /** \brief Function to register the AlertSyslog module */ -void TmModuleAlertSyslogRegister (void) +void AlertSyslogRegister (void) { #ifndef OS_WIN32 OutputRegisterPacketModule(LOGGER_ALERT_SYSLOG, MODULE_NAME, "syslog", diff --git a/src/alert-syslog.h b/src/alert-syslog.h index 976a1122eff7..06890469fcfc 100644 --- a/src/alert-syslog.h +++ b/src/alert-syslog.h @@ -27,7 +27,7 @@ #ifndef __ALERT_SYSLOG_H__ #define __ALERT_SYSLOG_H__ -void TmModuleAlertSyslogRegister(void); +void AlertSyslogRegister(void); #endif /* __ALERT_SYSLOG_H__ */ diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index a39a328c5eff..be0998edfc5c 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -233,7 +233,7 @@ int Unified2Logger(ThreadVars *tv, void *data, const Packet *p); #define MODULE_NAME "Unified2Alert" -void TmModuleUnified2AlertRegister(void) +void Unified2AlertRegister(void) { OutputRegisterPacketModule(LOGGER_UNIFIED2, MODULE_NAME, "unified2-alert", Unified2AlertInitCtx, Unified2Logger, Unified2Condition, diff --git a/src/alert-unified2-alert.h b/src/alert-unified2-alert.h index d4d3b2ec1536..ae068a1d4e89 100644 --- a/src/alert-unified2-alert.h +++ b/src/alert-unified2-alert.h @@ -43,7 +43,7 @@ #define UNIFIED2_EXTRADATA_TYPE_BLOB 1 #define UNIFIED2_EXTRADATA_TYPE_EXTRA_DATA 4 -void TmModuleUnified2AlertRegister(void); +void Unified2AlertRegister(void); OutputCtx *Unified2AlertInitCtx(ConfNode *); #endif /* __ALERT_UNIFIED2_ALERT_H__ */ diff --git a/src/log-dnslog.c b/src/log-dnslog.c index 418b2dd47926..51d524a59fcb 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -344,7 +344,7 @@ static OutputCtx *LogDnsLogInitCtx(ConfNode *conf) return output_ctx; } -void TmModuleLogDnsLogRegister (void) +void LogDnsLogRegister (void) { OutputRegisterTxModule(LOGGER_DNS, MODULE_NAME, "dns-log", LogDnsLogInitCtx, ALPROTO_DNS, LogDnsLogger, LogDnsLogThreadInit, LogDnsLogThreadDeinit, diff --git a/src/log-dnslog.h b/src/log-dnslog.h index acd00bc40285..eefac42248f8 100644 --- a/src/log-dnslog.h +++ b/src/log-dnslog.h @@ -24,6 +24,6 @@ #ifndef __LOG_DNSLOG_H__ #define __LOG_DNSLOG_H__ -void TmModuleLogDnsLogRegister (void); +void LogDnsLogRegister(void); #endif /* __LOG_DNSLOG_H__ */ diff --git a/src/log-droplog.c b/src/log-droplog.c index 03c66c620f4c..ea0158388aa5 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -492,7 +492,7 @@ static void LogDropLogRegisterTests(void) #endif /** \brief function to register the drop log module */ -void TmModuleLogDropLogRegister (void) +void LogDropLogRegister (void) { OutputRegisterPacketModule(LOGGER_DROP, MODULE_NAME, "drop", LogDropLogInitCtx, LogDropLogger, LogDropCondition, diff --git a/src/log-droplog.h b/src/log-droplog.h index 2b266ad55c37..e37d8e73f989 100644 --- a/src/log-droplog.h +++ b/src/log-droplog.h @@ -26,6 +26,6 @@ #ifndef ALERT_DROPLOG_H #define ALERT_DROPLOG_H -void TmModuleLogDropLogRegister(void); +void LogDropLogRegister(void); #endif /* ALERT_DROPLOG_H */ diff --git a/src/log-file.c b/src/log-file.c index 71e683a42071..1b594c5909fe 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -453,7 +453,7 @@ int LogFileLogOpenFileCtx(LogFileCtx *file_ctx, const char *filename, const return 0; } -void TmModuleLogFileLogRegister (void) +void LogFileLogRegister (void) { OutputRegisterFileModule(LOGGER_FILE, MODULE_NAME, "file-log", LogFileLogInitCtx, LogFileLogger, LogFileLogThreadInit, diff --git a/src/log-file.h b/src/log-file.h index 08e0785b21e4..b856204bd688 100644 --- a/src/log-file.h +++ b/src/log-file.h @@ -24,6 +24,6 @@ #ifndef __LOG_FILELOG_H__ #define __LOG_FILELOG_H__ -void TmModuleLogFileLogRegister (void); +void LogFileLogRegister(void); #endif /* __LOG_FILELOG_H__ */ diff --git a/src/log-filestore.c b/src/log-filestore.c index aacd219433c6..99fa7e38d9b9 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -479,7 +479,7 @@ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) SCReturnPtr(output_ctx, "OutputCtx"); } -void TmModuleLogFilestoreRegister (void) +void LogFilestoreRegister (void) { OutputRegisterFiledataModule(LOGGER_FILE_STORE, MODULE_NAME, "file", LogFilestoreLogInitCtx, LogFilestoreLogger, LogFilestoreLogThreadInit, diff --git a/src/log-filestore.h b/src/log-filestore.h index bfbfd5fcfa85..d477506fc590 100644 --- a/src/log-filestore.h +++ b/src/log-filestore.h @@ -24,6 +24,6 @@ #ifndef __LOG_FILESTORE_H__ #define __LOG_FILESTORE_H__ -void TmModuleLogFilestoreRegister (void); +void LogFilestoreRegister(void); #endif /* __LOG_FILELOG_H__ */ diff --git a/src/log-httplog.c b/src/log-httplog.c index 695b98e53897..775fec636e92 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -63,7 +63,7 @@ static void LogHttpLogDeInitCtx(OutputCtx *); int LogHttpLogger(ThreadVars *tv, void *thread_data, const Packet *, Flow *f, void *state, void *tx, uint64_t tx_id); -void TmModuleLogHttpLogRegister (void) +void LogHttpLogRegister (void) { OutputRegisterTxModule(LOGGER_HTTP, MODULE_NAME, "http-log", LogHttpLogInitCtx, ALPROTO_HTTP, LogHttpLogger, LogHttpLogThreadInit, diff --git a/src/log-httplog.h b/src/log-httplog.h index c02d0d9d612b..e8fccb65dab4 100644 --- a/src/log-httplog.h +++ b/src/log-httplog.h @@ -24,7 +24,7 @@ #ifndef __LOG_HTTPLOG_H__ #define __LOG_HTTPLOG_H__ -void TmModuleLogHttpLogRegister (void); +void LogHttpLogRegister(void); void TmModuleLogHttpLogIPv4Register (void); void TmModuleLogHttpLogIPv6Register (void); OutputCtx *LogHttpLogInitCtx(ConfNode *); diff --git a/src/log-pcap.c b/src/log-pcap.c index 4ff1b4d5c94c..258e483ece23 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -151,12 +151,12 @@ static OutputCtx *PcapLogInitCtx(ConfNode *); static void PcapLogProfilingDump(PcapLogData *); static int PcapLogCondition(ThreadVars *, const Packet *); -void TmModulePcapLogRegister(void) +void PcapLogRegister(void) { OutputRegisterPacketModule(LOGGER_PCAP, MODULE_NAME, "pcap-log", PcapLogInitCtx, PcapLog, PcapLogCondition, PcapLogDataInit, PcapLogDataDeinit, NULL); - + PcapLogProfileSetup(); SC_ATOMIC_INIT(thread_cnt); return; } diff --git a/src/log-pcap.h b/src/log-pcap.h index 0c6e7011bade..8b68d4332929 100644 --- a/src/log-pcap.h +++ b/src/log-pcap.h @@ -28,7 +28,7 @@ #ifndef __LOG_PCAP_H__ #define __LOG_PCAP_H__ -void TmModulePcapLogRegister (void); +void PcapLogRegister(void); void PcapLogProfileSetup(void); #endif /* __LOG_PCAP_H__ */ diff --git a/src/log-stats.c b/src/log-stats.c index 343fce06ae6f..e82e1edb0ff5 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -294,7 +294,7 @@ static void LogStatsLogDeInitCtx(OutputCtx *output_ctx) SCFree(output_ctx); } -void TmModuleLogStatsLogRegister (void) +void LogStatsLogRegister (void) { OutputRegisterStatsModule(LOGGER_STATS, MODULE_NAME, "stats", LogStatsLogInitCtx, LogStatsLogger, LogStatsLogThreadInit, diff --git a/src/log-stats.h b/src/log-stats.h index 957104f3c7fc..f7f536c6ddb0 100644 --- a/src/log-stats.h +++ b/src/log-stats.h @@ -24,6 +24,6 @@ #ifndef __LOG_STATS_H__ #define __LOG_STATS_H__ -void TmModuleLogStatsLogRegister (void); +void LogStatsLogRegister(void); #endif /* __LOG_HTTPLOG_H__ */ diff --git a/src/log-tcp-data.c b/src/log-tcp-data.c index d56a9fc5889d..3a791a55dcef 100644 --- a/src/log-tcp-data.c +++ b/src/log-tcp-data.c @@ -60,7 +60,7 @@ static void LogTcpDataLogDeInitCtx(OutputCtx *); int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags); -void TmModuleLogTcpDataLogRegister (void) { +void LogTcpDataLogRegister (void) { OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "tcp-data", LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_TCP_DATA, LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, diff --git a/src/log-tcp-data.h b/src/log-tcp-data.h index 5123c3b2dda5..fcfe19442b59 100644 --- a/src/log-tcp-data.h +++ b/src/log-tcp-data.h @@ -24,7 +24,7 @@ #ifndef __LOG_TCPDATALOG_H__ #define __LOG_TCPDATALOG_H__ -void TmModuleLogTcpDataLogRegister (void); +void LogTcpDataLogRegister(void); OutputCtx *LogTcpDataLogInitCtx(ConfNode *); #endif /* __LOG_TCPDATALOG_H__ */ diff --git a/src/log-tlslog.c b/src/log-tlslog.c index aa04ad11054a..ff7935ae5d95 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -312,7 +312,7 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, return 0; } -void TmModuleLogTlsLogRegister(void) +void LogTlsLogRegister(void) { OutputRegisterTxModuleWithProgress(LOGGER_TLS, MODULE_NAME, "tls-log", LogTlsLogInitCtx, ALPROTO_TLS, LogTlsLogger, TLS_HANDSHAKE_DONE, diff --git a/src/log-tlslog.h b/src/log-tlslog.h index d3c9ce516b86..87c2fbcf5db7 100644 --- a/src/log-tlslog.h +++ b/src/log-tlslog.h @@ -25,7 +25,7 @@ #ifndef __LOG_TLSLOG_H__ #define __LOG_TLSLOG_H__ -void TmModuleLogTlsLogRegister (void); +void LogTlsLogRegister(void); int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len, Port* sp, char* dstip, size_t dstip_len, diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c index 13840af1ec30..ddabd41fa377 100644 --- a/src/log-tlsstore.c +++ b/src/log-tlsstore.c @@ -406,7 +406,7 @@ static OutputCtx *LogTlsStoreLogInitCtx(ConfNode *conf) SCReturnPtr(output_ctx, "OutputCtx"); } -void TmModuleLogTlsStoreRegister (void) +void LogTlsStoreRegister (void) { OutputRegisterTxModuleWithCondition(LOGGER_TLS_STORE, MODULE_NAME, "tls-store", LogTlsStoreLogInitCtx, ALPROTO_TLS, LogTlsStoreLogger, diff --git a/src/log-tlsstore.h b/src/log-tlsstore.h index 6cbacab64760..c80975bee132 100644 --- a/src/log-tlsstore.h +++ b/src/log-tlsstore.h @@ -24,6 +24,6 @@ #ifndef __LOG_TLSSTORE_H__ #define __LOG_TLSSTORE_H__ -void TmModuleLogTlsStoreRegister (void); +void LogTlsStoreRegister(void); #endif /* __LOG_TLSSTORE_H__ */ diff --git a/src/output-file.c b/src/output-file.c index 2e23b2a38753..78b9df38f2df 100644 --- a/src/output-file.c +++ b/src/output-file.c @@ -266,7 +266,7 @@ static void OutputFileLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModuleFileLoggerRegister (void) +void OutputFileLoggerRegister(void) { OutputRegisterRootLogger(OutputFileLogThreadInit, OutputFileLogThreadDeinit, OutputFileLogExitPrintStats, OutputFileLog); diff --git a/src/output-file.h b/src/output-file.h index 3f335447dafe..d27d26eec47f 100644 --- a/src/output-file.h +++ b/src/output-file.h @@ -41,7 +41,7 @@ int OutputRegisterFileLogger(LoggerId id, const char *name, FileLogger LogFunc, OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void TmModuleFileLoggerRegister (void); +void OutputFileLoggerRegister(void); void OutputFileShutdown(void); diff --git a/src/output-filedata.c b/src/output-filedata.c index 66a66208eca0..7b7ea20a237d 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -434,7 +434,7 @@ static void OutputFiledataLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModuleFiledataLoggerRegister (void) +void OutputFiledataLoggerRegister(void) { OutputRegisterRootLogger(OutputFiledataLogThreadInit, OutputFiledataLogThreadDeinit, OutputFiledataLogExitPrintStats, diff --git a/src/output-filedata.h b/src/output-filedata.h index 562eba6bb0fc..4c661b2de1cc 100644 --- a/src/output-filedata.h +++ b/src/output-filedata.h @@ -46,7 +46,7 @@ int OutputRegisterFiledataLogger(LoggerId id, const char *name, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void TmModuleFiledataLoggerRegister (void); +void OutputFiledataLoggerRegister(void); void OutputFiledataShutdown(void); diff --git a/src/output-json-alert.c b/src/output-json-alert.c index ac28c6c9d695..0de310b58e5e 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -739,7 +739,7 @@ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } -void TmModuleJsonAlertLogRegister (void) +void JsonAlertLogRegister (void) { OutputRegisterPacketModule(LOGGER_JSON_ALERT, MODULE_NAME, "alert-json-log", JsonAlertLogInitCtx, JsonAlertLogger, JsonAlertLogCondition, @@ -752,7 +752,7 @@ void TmModuleJsonAlertLogRegister (void) #else -void TmModuleJsonAlertLogRegister (void) +void JsonAlertLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-alert.h b/src/output-json-alert.h index a10a316d20b3..645b6f5c0270 100644 --- a/src/output-json-alert.h +++ b/src/output-json-alert.h @@ -27,7 +27,7 @@ #ifndef __OUTPUT_JSON_ALERT_H__ #define __OUTPUT_JSON_ALERT_H__ -void TmModuleJsonAlertLogRegister (void); +void JsonAlertLogRegister(void); #ifdef HAVE_LIBJANSSON void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js); #endif /* HAVE_LIBJANSSON */ diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 8d0e8e76eddc..f55d6d546173 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -849,7 +849,7 @@ static OutputCtx *JsonDnsLogInitCtx(ConfNode *conf) #define MODULE_NAME "JsonDnsLog" -void TmModuleJsonDnsLogRegister (void) +void JsonDnsLogRegister (void) { /* Logger for requests. */ OutputRegisterTxModuleWithProgress(LOGGER_JSON_DNS, MODULE_NAME, @@ -876,7 +876,7 @@ void TmModuleJsonDnsLogRegister (void) #else -void TmModuleJsonDnsLogRegister (void) +void JsonDnsLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-dns.h b/src/output-json-dns.h index f26227e37480..9c3e88011578 100644 --- a/src/output-json-dns.h +++ b/src/output-json-dns.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_JSON_DNS_H__ #define __OUTPUT_JSON_DNS_H__ -void TmModuleJsonDnsLogRegister (void); +void JsonDnsLogRegister(void); #endif /* __OUTPUT_JSON_DNS_H__ */ diff --git a/src/output-json-drop.c b/src/output-json-drop.c index fa2c7de00836..8ae8c4297ac0 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -427,7 +427,7 @@ static int JsonDropLogCondition(ThreadVars *tv, const Packet *p) return FALSE; } -void TmModuleJsonDropLogRegister (void) +void JsonDropLogRegister (void) { OutputRegisterPacketModule(LOGGER_JSON_DROP, MODULE_NAME, "drop-json-log", JsonDropLogInitCtx, JsonDropLogger, JsonDropLogCondition, @@ -440,7 +440,7 @@ void TmModuleJsonDropLogRegister (void) #else -void TmModuleJsonDropLogRegister (void) +void JsonDropLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-drop.h b/src/output-json-drop.h index c02057c14cbb..d4fc9a16283c 100644 --- a/src/output-json-drop.h +++ b/src/output-json-drop.h @@ -25,6 +25,6 @@ #ifndef __OUTPUT_JSON_DROP_H__ #define __OUTPUT_JSON_DROP_H__ -void TmModuleJsonDropLogRegister (void); +void JsonDropLogRegister(void); #endif /* __OUTPUT_DROPLOG_H__ */ diff --git a/src/output-json-file.c b/src/output-json-file.c index 6e1ad571ff06..dfc034bdc758 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -288,7 +288,7 @@ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return output_ctx; } -void TmModuleJsonFileLogRegister (void) +void JsonFileLogRegister (void) { /* register as child of eve-log */ OutputRegisterFileSubModule(LOGGER_JSON_FILE, "eve-log", "JsonFileLog", @@ -298,7 +298,7 @@ void TmModuleJsonFileLogRegister (void) #else -void TmModuleJsonFileLogRegister (void) +void JsonFileLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-file.h b/src/output-json-file.h index e101897f7bf2..680724f6cbb5 100644 --- a/src/output-json-file.h +++ b/src/output-json-file.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_JSON_FILE_H__ #define __OUTPUT_JSON_FILE_H__ -void TmModuleJsonFileLogRegister (void); +void JsonFileLogRegister(void); #endif /* __OUTPUT_JSON_FILE_H__ */ diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 3a5902779305..2d0f76acfe65 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -448,7 +448,7 @@ static TmEcode JsonFlowLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleJsonFlowLogRegister (void) +void JsonFlowLogRegister (void) { /* register as separate module */ OutputRegisterFlowModule(LOGGER_JSON_FLOW, "JsonFlowLog", "flow-json-log", @@ -463,7 +463,7 @@ void TmModuleJsonFlowLogRegister (void) #else -void TmModuleJsonFlowLogRegister (void) +void JsonFlowLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-flow.h b/src/output-json-flow.h index 1d32c9eb6812..439af9385704 100644 --- a/src/output-json-flow.h +++ b/src/output-json-flow.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_JSON_FLOW_H__ #define __OUTPUT_JSON_FLOW_H__ -void TmModuleJsonFlowLogRegister (void); +void JsonFlowLogRegister(void); #endif /* __OUTPUT_JSON_FLOW_H__ */ diff --git a/src/output-json-http.c b/src/output-json-http.c index 9075e0cce335..381ddeb4c4ab 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -582,7 +582,7 @@ static TmEcode JsonHttpLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleJsonHttpLogRegister (void) +void JsonHttpLogRegister (void) { /* register as separate module */ OutputRegisterTxModule(LOGGER_JSON_HTTP, "JsonHttpLog", "http-json-log", @@ -597,7 +597,7 @@ void TmModuleJsonHttpLogRegister (void) #else -void TmModuleJsonHttpLogRegister (void) +void JsonHttpLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-http.h b/src/output-json-http.h index 0c886f3dd56d..eda68c2acc75 100644 --- a/src/output-json-http.h +++ b/src/output-json-http.h @@ -24,7 +24,7 @@ #ifndef __OUTPUT_JSON_HTTP_H__ #define __OUTPUT_JSON_HTTP_H__ -void TmModuleJsonHttpLogRegister (void); +void JsonHttpLogRegister(void); #ifdef HAVE_LIBJANSSON void JsonHttpLogJSONBasic(json_t *js, htp_tx_t *tx); diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 0ac1683a856c..fb39d219e467 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -430,7 +430,7 @@ static TmEcode JsonNetFlowLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleJsonNetFlowLogRegister (void) +void JsonNetFlowLogRegister(void) { /* register as separate module */ OutputRegisterFlowModule(LOGGER_JSON_NETFLOW, "JsonNetFlowLog", @@ -445,7 +445,7 @@ void TmModuleJsonNetFlowLogRegister (void) #else -void TmModuleJsonNetFlowLogRegister (void) +void JsonNetFlowLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-netflow.h b/src/output-json-netflow.h index 361cc3a0f347..738c497fd830 100644 --- a/src/output-json-netflow.h +++ b/src/output-json-netflow.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_JSON_NETFLOW_H__ #define __OUTPUT_JSON_NETFLOW_H__ -void TmModuleJsonNetFlowLogRegister (void); +void JsonNetFlowLogRegister(void); #endif /* __OUTPUT_JSON_FLOW_H__ */ diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 456f2c6af066..368e917c280b 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -257,7 +257,7 @@ static TmEcode JsonSmtpLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleJsonSmtpLogRegister (void) { +void JsonSmtpLogRegister (void) { /* register as separate module */ OutputRegisterTxModule(LOGGER_JSON_SMTP, "JsonSmtpLog", "smtp-json-log", OutputSmtpLogInit, ALPROTO_SMTP, JsonSmtpLogger, JsonSmtpLogThreadInit, @@ -271,7 +271,7 @@ void TmModuleJsonSmtpLogRegister (void) { #else -void TmModuleJsonSmtpLogRegister (void) +void JsonSmtpLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-smtp.h b/src/output-json-smtp.h index 2f79d992011a..24d3f8c22de8 100644 --- a/src/output-json-smtp.h +++ b/src/output-json-smtp.h @@ -24,7 +24,7 @@ #ifndef __OUTPUT_JSON_SMTP_H__ #define __OUTPUT_JSON_SMTP_H__ -void TmModuleJsonSmtpLogRegister (void); +void JsonSmtpLogRegister(void); #ifdef HAVE_LIBJANSSON json_t *JsonSMTPAddMetadata(const Flow *f, uint64_t tx_id); #endif diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index deec854acd0c..e8178f3152d6 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -314,7 +314,7 @@ static int JsonSshCondition(ThreadVars *tv, const Packet *p) return FALSE; } -void TmModuleJsonSshLogRegister (void) +void JsonSshLogRegister (void) { /* register as separate module */ OutputRegisterPacketModule(LOGGER_JSON_SSH, "JsonSshLog", "ssh-json-log", @@ -329,7 +329,7 @@ void TmModuleJsonSshLogRegister (void) #else -void TmModuleJsonSshLogRegister (void) +void JsonSshLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-ssh.h b/src/output-json-ssh.h index 5d0752bf2a53..68a7f974c679 100644 --- a/src/output-json-ssh.h +++ b/src/output-json-ssh.h @@ -24,7 +24,7 @@ #ifndef __OUTPUT_JSON_SSH_H__ #define __OUTPUT_JSON_SSH_H__ -void TmModuleJsonSshLogRegister (void); +void JsonSshLogRegister(void); #ifdef HAVE_LIBJANSSON #include "app-layer-ssh.h" diff --git a/src/output-json-stats.c b/src/output-json-stats.c index ec0fc4152dfe..be1646a4456a 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -371,7 +371,7 @@ OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return output_ctx; } -void TmModuleJsonStatsLogRegister (void) { +void JsonStatsLogRegister(void) { /* register as separate module */ OutputRegisterStatsModule(LOGGER_JSON_STATS, MODULE_NAME, "stats-json", OutputStatsLogInit, JsonStatsLogger, JsonStatsLogThreadInit, @@ -385,7 +385,7 @@ void TmModuleJsonStatsLogRegister (void) { #else -void TmModuleJsonStatsLogRegister (void) +void JsonStatsLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-stats.h b/src/output-json-stats.h index ab1e6b55c014..94962a3c99bb 100644 --- a/src/output-json-stats.h +++ b/src/output-json-stats.h @@ -33,6 +33,6 @@ #ifdef HAVE_LIBJANSSON json_t *StatsToJSON(const StatsTable *st, uint8_t flags); #endif -void TmModuleJsonStatsLogRegister (void); +void JsonStatsLogRegister(void); #endif /* __OUTPUT_JSON_COUNTERS_H__ */ diff --git a/src/output-json-template.c b/src/output-json-template.c index e877259de7ad..88e8ee7981fc 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -190,7 +190,7 @@ static TmEcode JsonTemplateLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleJsonTemplateLogRegister(void) +void JsonTemplateLogRegister(void) { /* TEMPLATE_START_REMOVE */ if (ConfGetNode("app-layer.protocols.template") == NULL) { @@ -208,7 +208,7 @@ void TmModuleJsonTemplateLogRegister(void) #else /* No JSON support. */ -void TmModuleJsonTemplateLogRegister(void) +void JsonTemplateLogRegister(void) { SCLogInfo("Cannot register JSON output for template. " "JSON support was disabled during build."); diff --git a/src/output-json-template.h b/src/output-json-template.h index 4f1ac6b7afdd..874df6b3b4a7 100644 --- a/src/output-json-template.h +++ b/src/output-json-template.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_JSON_TEMPLATE_H__ #define __OUTPUT_JSON_TEMPLATE_H__ -void TmModuleJsonTemplateLogRegister(void); +void JsonTemplateLogRegister(void); #endif /* __OUTPUT_JSON_TEMPLATE_H__ */ diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 18ea2cab9443..c7135031795e 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -308,7 +308,7 @@ OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return output_ctx; } -void TmModuleJsonTlsLogRegister (void) +void JsonTlsLogRegister (void) { /* register as separate module */ OutputRegisterTxModuleWithProgress(LOGGER_JSON_TLS, "JsonTlsLog", @@ -325,7 +325,7 @@ void TmModuleJsonTlsLogRegister (void) #else -void TmModuleJsonTlsLogRegister (void) +void JsonTlsLogRegister (void) { SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } diff --git a/src/output-json-tls.h b/src/output-json-tls.h index f330ad898aad..06657c8e852c 100644 --- a/src/output-json-tls.h +++ b/src/output-json-tls.h @@ -24,7 +24,7 @@ #ifndef __OUTPUT_JSON_TLS_H__ #define __OUTPUT_JSON_TLS_H__ -void TmModuleJsonTlsLogRegister (void); +void JsonTlsLogRegister(void); #ifdef HAVE_LIBJANSSON #include "app-layer-ssl.h" diff --git a/src/output-json.c b/src/output-json.c index 6a91cbd0fb4a..ccf43b692359 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -67,7 +67,7 @@ int OutputJsonOpenFileCtx(LogFileCtx *, char *); -void TmModuleOutputJsonRegister (void) +void OutputJsonRegister (void) { SCLogDebug("Can't register JSON output - JSON support was disabled during build."); } @@ -84,7 +84,7 @@ void TmModuleOutputJsonRegister (void) static void OutputJsonDeInitCtx(OutputCtx *); -void TmModuleOutputJsonRegister (void) +void OutputJsonRegister (void) { OutputRegisterModule(MODULE_NAME, "eve-log", OutputJsonInitCtx); } diff --git a/src/output-json.h b/src/output-json.h index 7f43392664a4..bb7d94de9ee5 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -28,7 +28,7 @@ #include "util-buffer.h" #include "util-logopenfile.h" -void TmModuleOutputJsonRegister (void); +void OutputJsonRegister(void); #ifdef HAVE_LIBJANSSON /* helper struct for OutputJSONMemBufferCallback */ diff --git a/src/output-lua.c b/src/output-lua.c index 7d3ae065e502..deed5d5bc990 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -1000,14 +1000,14 @@ static TmEcode LuaLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleLuaLogRegister (void) { +void LuaLogRegister(void) { /* register as separate module */ OutputRegisterModule(MODULE_NAME, "lua", OutputLuaLogInit); } #else -void TmModuleLuaLogRegister (void) { +void LuaLogRegister (void) { /* no-op */ } diff --git a/src/output-lua.h b/src/output-lua.h index 627cdc37a25e..c8c5ebbf4565 100644 --- a/src/output-lua.h +++ b/src/output-lua.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_LUA_H__ #define __OUTPUT_LUA_H__ -void TmModuleLuaLogRegister (void); +void LuaLogRegister(void); #endif /* __OUTPUT_LUA_H__ */ diff --git a/src/output-packet.c b/src/output-packet.c index 85385e437b3a..3d18ad449cd6 100644 --- a/src/output-packet.c +++ b/src/output-packet.c @@ -209,7 +209,7 @@ static void OutputPacketLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModulePacketLoggerRegister (void) +void OutputPacketLoggerRegister(void) { OutputRegisterRootLogger(OutputPacketLogThreadInit, OutputPacketLogThreadDeinit, OutputPacketLogExitPrintStats, diff --git a/src/output-packet.h b/src/output-packet.h index 408be05b273d..da40ccde47c1 100644 --- a/src/output-packet.h +++ b/src/output-packet.h @@ -41,7 +41,7 @@ int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, PacketLogger LogFunc, PacketLogCondition ConditionFunc, OutputCtx *, ThreadInitFunc, ThreadDeinitFunc, ThreadExitPrintStatsFunc); -void TmModulePacketLoggerRegister (void); +void OutputPacketLoggerRegister(void); void OutputPacketShutdown(void); diff --git a/src/output-streaming.c b/src/output-streaming.c index 744ead6f274e..1b800abd5481 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -441,7 +441,7 @@ static void OutputStreamingLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModuleStreamingLoggerRegister (void) { +void OutputStreamingLoggerRegister(void) { OutputRegisterRootLogger(OutputStreamingLogThreadInit, OutputStreamingLogThreadDeinit, OutputStreamingLogExitPrintStats, OutputStreamingLog); diff --git a/src/output-streaming.h b/src/output-streaming.h index 8db555f94c4c..bc02fe543be5 100644 --- a/src/output-streaming.h +++ b/src/output-streaming.h @@ -50,7 +50,7 @@ int OutputRegisterStreamingLogger(LoggerId id, const char *name, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); -void TmModuleStreamingLoggerRegister (void); +void OutputStreamingLoggerRegister (void); void OutputStreamingShutdown(void); diff --git a/src/output-tx.c b/src/output-tx.c index b39967c89917..004a83adc610 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -335,7 +335,7 @@ static void OutputTxLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModuleTxLoggerRegister (void) +void OutputTxLoggerRegister (void) { OutputRegisterRootLogger(OutputTxLogThreadInit, OutputTxLogThreadDeinit, OutputTxLogExitPrintStats, OutputTxLog); diff --git a/src/output-tx.h b/src/output-tx.h index e548cdd16092..847d0b472b7f 100644 --- a/src/output-tx.h +++ b/src/output-tx.h @@ -43,7 +43,7 @@ int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, ThreadInitFunc, ThreadDeinitFunc, void (*ThreadExitPrintStats)(ThreadVars *, void *)); -void TmModuleTxLoggerRegister (void); +void OutputTxLoggerRegister (void); void OutputTxShutdown(void); diff --git a/src/output.c b/src/output.c index 180f54fe95a1..ed714e902347 100644 --- a/src/output.c +++ b/src/output.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -40,6 +40,36 @@ #include "util-debug.h" #include "output.h" +#include "alert-fastlog.h" +#include "alert-unified2-alert.h" +#include "alert-debuglog.h" +#include "alert-prelude.h" +#include "alert-syslog.h" +#include "output-json-alert.h" +#include "output-json-flow.h" +#include "output-json-netflow.h" +#include "log-droplog.h" +#include "output-json-drop.h" +#include "log-httplog.h" +#include "output-json-http.h" +#include "log-dnslog.h" +#include "output-json-dns.h" +#include "log-tlslog.h" +#include "log-tlsstore.h" +#include "output-json-tls.h" +#include "output-json-ssh.h" +#include "log-pcap.h" +#include "log-file.h" +#include "output-json-file.h" +#include "output-json-smtp.h" +#include "output-json-stats.h" +#include "log-filestore.h" +#include "log-tcp-data.h" +#include "log-stats.h" +#include "output-json.h" +#include "output-json-template.h" +#include "output-lua.h" + typedef struct RootLogger_ { ThreadInitFunc ThreadInit; ThreadDeinitFunc ThreadDeinit; @@ -59,6 +89,9 @@ typedef struct LoggerThreadStoreNode_ { typedef TAILQ_HEAD(LoggerThreadStore_, LoggerThreadStoreNode_) LoggerThreadStore; +/** + * The list of all registered (known) output modules. + */ OutputModuleList output_modules = TAILQ_HEAD_INITIALIZER(output_modules); /** @@ -73,6 +106,9 @@ typedef struct OutputFileRolloverFlag_ { TAILQ_HEAD(, OutputFileRolloverFlag_) output_file_rotation_flags = TAILQ_HEAD_INITIALIZER(output_file_rotation_flags); +void OutputRegisterRootLoggers(void); +void OutputRegisterLoggers(void); + /** * \brief Register an output module. * @@ -984,9 +1020,81 @@ void TmModuleLoggerRegister(void) tmm_modules[TMM_LOGGER].ThreadDeinit = OutputLoggerThreadDeinit; tmm_modules[TMM_LOGGER].ThreadExitPrintStats = OutputLoggerExitPrintStats; tmm_modules[TMM_LOGGER].Func = OutputLoggerLog;; + + OutputRegisterRootLoggers(); + OutputRegisterLoggers(); } void SetupOutputs(ThreadVars *tv) { TmSlotSetFuncAppend(tv, &tmm_modules[TMM_LOGGER], NULL); } + +/** + * \brief Register all root loggers. + */ +void OutputRegisterRootLoggers(void) +{ + OutputPacketLoggerRegister(); + OutputTxLoggerRegister(); + OutputFileLoggerRegister(); + OutputFiledataLoggerRegister(); + OutputStreamingLoggerRegister(); +} + +/** + * \brief Register all non-root logging modules. + */ +void OutputRegisterLoggers(void) +{ + LuaLogRegister(); + /* fast log */ + AlertFastLogRegister(); + /* debug log */ + AlertDebugLogRegister(); + /* prelue log */ + AlertPreludeRegister(); + /* syslog log */ + AlertSyslogRegister(); + /* unified2 log */ + Unified2AlertRegister(); + /* drop log */ + LogDropLogRegister(); + JsonDropLogRegister(); + /* json log */ + OutputJsonRegister(); + /* email logs */ + JsonSmtpLogRegister(); + /* http log */ + LogHttpLogRegister(); + JsonHttpLogRegister(); + /* tls log */ + LogTlsLogRegister(); + JsonTlsLogRegister(); + LogTlsStoreRegister(); + /* ssh */ + JsonSshLogRegister(); + /* pcap log */ + PcapLogRegister(); + /* file log */ + LogFileLogRegister(); + JsonFileLogRegister(); + LogFilestoreRegister(); + /* dns log */ + LogDnsLogRegister(); + JsonDnsLogRegister(); + /* tcp streaming data */ + LogTcpDataLogRegister(); + /* log stats */ + LogStatsLogRegister(); + + JsonAlertLogRegister(); + /* flow/netflow */ + JsonFlowLogRegister(); + JsonNetFlowLogRegister(); + /* json stats */ + JsonStatsLogRegister(); + + /* Template JSON logger. */ + JsonTemplateLogRegister(); +} diff --git a/src/suricata.c b/src/suricata.c index dd45b1d36372..2bbdb3bffbce 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -73,37 +73,6 @@ #include "conf.h" #include "conf-yaml-loader.h" -#include "alert-fastlog.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" -#include "alert-prelude.h" -#include "alert-syslog.h" -#include "output-json-alert.h" - -#include "output-json-flow.h" -#include "output-json-netflow.h" -#include "log-droplog.h" -#include "output-json-drop.h" -#include "log-httplog.h" -#include "output-json-http.h" -#include "log-dnslog.h" -#include "output-json-dns.h" -#include "log-tlslog.h" -#include "log-tlsstore.h" -#include "output-json-tls.h" -#include "output-json-ssh.h" -#include "log-pcap.h" -#include "log-file.h" -#include "output-json-file.h" -#include "output-json-smtp.h" -#include "output-json-stats.h" -#include "log-filestore.h" -#include "log-tcp-data.h" -#include "log-stats.h" - -#include "output-json.h" - -#include "output-json-template.h" #include "stream-tcp.h" @@ -186,13 +155,6 @@ #include "reputation.h" #include "output.h" -#include "output-lua.h" - -#include "output-packet.h" -#include "output-tx.h" -#include "output-file.h" -#include "output-filedata.h" -#include "output-streaming.h" #include "util-privs.h" @@ -867,65 +829,10 @@ void RegisterAllModules() /* respond-reject */ TmModuleRespondRejectRegister(); - TmModuleLuaLogRegister(); - /* fast log */ - TmModuleAlertFastLogRegister(); - /* debug log */ - TmModuleAlertDebugLogRegister(); - /* prelue log */ - TmModuleAlertPreludeRegister(); - /* syslog log */ - TmModuleAlertSyslogRegister(); - /* unified2 log */ - TmModuleUnified2AlertRegister(); - /* drop log */ - TmModuleLogDropLogRegister(); - TmModuleJsonDropLogRegister(); - /* json log */ - TmModuleOutputJsonRegister(); - /* email logs */ - TmModuleJsonSmtpLogRegister(); - /* http log */ - TmModuleLogHttpLogRegister(); - TmModuleJsonHttpLogRegister(); - /* tls log */ - TmModuleLogTlsLogRegister(); - TmModuleJsonTlsLogRegister(); - TmModuleLogTlsStoreRegister(); - /* ssh */ - TmModuleJsonSshLogRegister(); - /* pcap log */ - TmModulePcapLogRegister(); - /* file log */ - TmModuleLogFileLogRegister(); - TmModuleJsonFileLogRegister(); - TmModuleLogFilestoreRegister(); - /* dns log */ - TmModuleLogDnsLogRegister(); - TmModuleJsonDnsLogRegister(); - /* tcp streaming data */ - TmModuleLogTcpDataLogRegister(); - /* log stats */ - TmModuleLogStatsLogRegister(); - - TmModuleJsonAlertLogRegister(); - /* flow/netflow */ - TmModuleJsonFlowLogRegister(); - TmModuleJsonNetFlowLogRegister(); - /* json stats */ - TmModuleJsonStatsLogRegister(); - - /* Template JSON logger. */ - TmModuleJsonTemplateLogRegister(); - /* log api */ TmModuleLoggerRegister(); - TmModulePacketLoggerRegister(); - TmModuleTxLoggerRegister(); - TmModuleFileLoggerRegister(); - TmModuleFiledataLoggerRegister(); - TmModuleStreamingLoggerRegister(); TmModuleStatsLoggerRegister(); + TmModuleDebugList(); /* nflog */ TmModuleReceiveNFLOGRegister(); @@ -2412,8 +2319,6 @@ static int PostConfLoadedSetup(SCInstance *suri) TmModuleRunInit(); - PcapLogProfileSetup(); - if (MayDaemonize(suri) != TM_ECODE_OK) SCReturnInt(TM_ECODE_FAILED); From f8c2c3653bcfaecaaf0e9d7d20b0fd066ac3f9e4 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 8 Jun 2016 13:56:35 -0600 Subject: [PATCH 1678/2553] output-streaming: free thread store on deinit --- src/output-streaming.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/output-streaming.c b/src/output-streaming.c index 1b800abd5481..6c8e5a066f24 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -419,10 +419,13 @@ static TmEcode OutputStreamingLogThreadDeinit(ThreadVars *tv, void *thread_data) logger->ThreadDeinit(tv, store->thread_data); } + OutputLoggerThreadStore *next_store = store->next; + SCFree(store); logger = logger->next; - store = store->next; + store = next_store; } + SCFree(op_thread_data); return TM_ECODE_OK; } From 00b6e628d17f16789bfba1c4e8ca3029cef4f021 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 20 Jun 2016 09:52:28 -0600 Subject: [PATCH 1679/2553] logging: hook into flow worker thread --- src/alert-debuglog.c | 2 -- src/alert-unified2-alert.c | 6 ----- src/flow-worker.c | 47 +++++++++++++++++++++----------------- src/log-droplog.c | 4 ---- src/output-file.c | 2 -- src/output-filedata.c | 2 -- src/output-json-alert.c | 14 ------------ src/output-json-drop.c | 4 ---- src/output-json-ssh.c | 5 ---- src/output-lua.c | 5 ---- src/output-streaming.c | 3 --- src/output-tx.c | 2 -- src/output.c | 19 ++++----------- src/output.h | 8 +++++-- src/runmode-erf-file.c | 5 ---- src/runmode-pcap-file.c | 5 ---- src/tm-modules.c | 1 - src/tm-threads-common.h | 2 -- src/tmqh-packetpool.c | 9 -------- src/util-runmodes.c | 9 -------- 20 files changed, 36 insertions(+), 118 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 1f2f5a4553e7..267b8eb81119 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -216,7 +216,6 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da if (p->flow != NULL) { int applayer = 0; - FLOWLOCK_RDLOCK(p->flow); applayer = StreamTcpAppLayerIsDisabled(p->flow); CreateTimeString(&p->flow->startts, timebuf, sizeof(timebuf)); MemBufferWriteString(aft->buffer, "FLOW Start TS: %s\n", timebuf); @@ -239,7 +238,6 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da (p->flow->alproto != ALPROTO_UNKNOWN) ? "TRUE" : "FALSE", p->flow->alproto); AlertDebugLogFlowVars(aft, p); AlertDebugLogFlowBits(aft, (Packet *)p); /* < no const */ - FLOWLOCK_UNLOCK(p->flow); } AlertDebugLogPktVars(aft, p); diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index be0998edfc5c..b922fe8f5eea 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -331,11 +331,9 @@ int Unified2Logger(ThreadVars *t, void *data, const Packet *p) char buffer[XFF_MAXLEN]; int have_xff_ip = 0; - FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); } - FLOWLOCK_UNLOCK(p->flow); if (have_xff_ip) { /** Be sure that we have a nice zeroed buffer */ @@ -890,7 +888,6 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) char buffer[XFF_MAXLEN]; int have_xff_ip = 0; - FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { if (pa->flags & PACKET_ALERT_FLAG_TX) { have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN); @@ -898,7 +895,6 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); } } - FLOWLOCK_UNLOCK(p->flow); if (have_xff_ip) { memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); @@ -1067,7 +1063,6 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) char buffer[XFF_MAXLEN]; int have_xff_ip = 0; - FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { if (pa->flags & PACKET_ALERT_FLAG_TX) { have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN); @@ -1075,7 +1070,6 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); } } - FLOWLOCK_UNLOCK(p->flow); if (have_xff_ip) { memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); diff --git a/src/flow-worker.c b/src/flow-worker.c index 154b3948f3a4..2d981e4be702 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -29,12 +29,6 @@ * - Detection * * This all while holding the flow lock. - * - * TODO - * - once we have a single entry point into the outputs they - * will have to move into this as well. - * - once outputs are here we can also call StreamTcpPrune here - * instead of in the packet pool return code */ #include "suricata-common.h" @@ -44,6 +38,7 @@ #include "stream-tcp.h" #include "app-layer.h" #include "detect-engine.h" +#include "output.h" #include "util-validate.h" @@ -59,9 +54,8 @@ typedef struct FlowWorkerThreadData_ { SC_ATOMIC_DECLARE(DetectEngineThreadCtxPtr, detect_thread); -#if 0 - void *output_thread; // XXX multiple, not a single state -#endif + void *output_thread; /* Output thread data. */ + PacketQueue pq; } FlowWorkerThreadData; @@ -98,9 +92,9 @@ static TmEcode FlowWorkerThreadInit(ThreadVars *tv, void *initdata, void **data) BUG_ON(DetectEngineThreadCtxInit(tv, NULL, &detect_thread) != TM_ECODE_OK); SC_ATOMIC_SET(fw->detect_thread, detect_thread); } -#if 0 - // setup OUTPUTS -#endif + + /* Setup outputs for this thread. */ + OutputLoggerThreadInit(tv, initdata, &fw->output_thread); /* setup pq for stream end pkts */ memset(&fw->pq, 0, sizeof(PacketQueue)); @@ -125,9 +119,9 @@ static TmEcode FlowWorkerThreadDeinit(ThreadVars *tv, void *data) DetectEngineThreadCtxDeinit(tv, detect_thread); SC_ATOMIC_SET(fw->detect_thread, NULL); } -#if 0 - // free OUTPUT -#endif + + /* Free output. */ + OutputLoggerThreadDeinit(tv, fw->output_thread); /* free pq */ BUG_ON(fw->pq.len); @@ -195,9 +189,10 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac Detect(tv, x, detect_thread, NULL, NULL); FLOWWORKER_PROFILING_END(x, PROFILE_FLOWWORKER_DETECT); } -#if 0 + // Outputs -#endif + OutputLoggerLog(tv, x, fw->output_thread, preq, unused); + /* put these packets in the preq queue so that they are * by the other thread modules before packet 'p'. */ PacketEnqueue(preq, x); @@ -219,11 +214,15 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac Detect(tv, p, detect_thread, NULL, NULL); FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_DETECT); } -#if 0 - // Outputs - // StreamTcpPruneSession (from TmqhOutputPacketpool) -#endif + // Outputs. + OutputLoggerLog(tv, p, fw->output_thread, preq, unused); + + /* Release tcp segments. Done here after alerting can use them. */ + if (p->flow != NULL && p->proto == IPPROTO_TCP) { + StreamTcpPruneSession(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? + STREAM_TOSERVER : STREAM_TOCLIENT); + } if (p->flow) { DEBUG_ASSERT_FLOW_LOCKED(p->flow); @@ -264,6 +263,11 @@ const char *ProfileFlowWorkerIdToString(enum ProfileFlowWorkerId fwi) return "error"; } +static void FlowWorkerExitPrintStats(ThreadVars *tv, void *data) +{ + FlowWorkerThreadData *fw = data; + OutputLoggerExitPrintStats(tv, fw->output_thread); +} void TmModuleFlowWorkerRegister (void) { @@ -271,6 +275,7 @@ void TmModuleFlowWorkerRegister (void) tmm_modules[TMM_FLOWWORKER].ThreadInit = FlowWorkerThreadInit; tmm_modules[TMM_FLOWWORKER].Func = FlowWorker; tmm_modules[TMM_FLOWWORKER].ThreadDeinit = FlowWorkerThreadDeinit; + tmm_modules[TMM_FLOWWORKER].ThreadExitPrintStats = FlowWorkerExitPrintStats; tmm_modules[TMM_FLOWWORKER].cap_flags = 0; tmm_modules[TMM_FLOWWORKER].flags = TM_FLAG_STREAM_TM|TM_FLAG_DETECT_TM; } diff --git a/src/log-droplog.c b/src/log-droplog.c index ea0158388aa5..027425754d1b 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -292,14 +292,12 @@ static int LogDropCondition(ThreadVars *tv, const Packet *p) if (p->flow != NULL) { int ret = FALSE; - FLOWLOCK_RDLOCK(p->flow); if (p->flow->flags & FLOW_ACTION_DROP) { if (PKT_IS_TOSERVER(p) && !(p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) ret = TRUE; else if (PKT_IS_TOCLIENT(p) && !(p->flow->flags & FLOW_TOCLIENT_DROP_LOGGED)) ret = TRUE; } - FLOWLOCK_UNLOCK(p->flow); return ret; } else if (PACKET_TEST_ACTION(p, ACTION_DROP)) { return TRUE; @@ -325,14 +323,12 @@ static int LogDropLogger(ThreadVars *tv, void *thread_data, const Packet *p) return -1; if (p->flow) { - FLOWLOCK_RDLOCK(p->flow); if (p->flow->flags & FLOW_ACTION_DROP) { if (PKT_IS_TOSERVER(p) && !(p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) p->flow->flags |= FLOW_TOSERVER_DROP_LOGGED; else if (PKT_IS_TOCLIENT(p) && !(p->flow->flags & FLOW_TOCLIENT_DROP_LOGGED)) p->flow->flags |= FLOW_TOCLIENT_DROP_LOGGED; } - FLOWLOCK_UNLOCK(p->flow); } return 0; } diff --git a/src/output-file.c b/src/output-file.c index 78b9df38f2df..402b398ab005 100644 --- a/src/output-file.c +++ b/src/output-file.c @@ -123,7 +123,6 @@ static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data, Packe int file_close = (p->flags & PKT_PSEUDO_STREAM_END) ? 1 : 0; int file_trunc = 0; - FLOWLOCK_WRLOCK(f); // < need write lock for FilePrune below file_trunc = StreamTcpReassembleDepthReached(p); FileContainer *ffc = AppLayerParserGetFiles(p->proto, f->alproto, @@ -180,7 +179,6 @@ static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data, Packe FilePrune(ffc); } - FLOWLOCK_UNLOCK(f); return TM_ECODE_OK; } diff --git a/src/output-filedata.c b/src/output-filedata.c index 7b7ea20a237d..589bef6893e8 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -157,7 +157,6 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P int file_close = (p->flags & PKT_PSEUDO_STREAM_END) ? 1 : 0; int file_trunc = 0; - FLOWLOCK_WRLOCK(f); // < need write lock for FiledataPrune below file_trunc = StreamTcpReassembleDepthReached(p); FileContainer *ffc = AppLayerParserGetFiles(p->proto, f->alproto, @@ -234,7 +233,6 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P FilePrune(ffc); } - FLOWLOCK_UNLOCK(f); return TM_ECODE_OK; } diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 0de310b58e5e..682377448771 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -221,7 +221,6 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (json_output_ctx->flags & LOG_JSON_HTTP) { if (p->flow != NULL) { - FLOWLOCK_RDLOCK(p->flow); uint16_t proto = FlowGetAppProtocol(p->flow); /* http alert */ @@ -230,40 +229,31 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (hjs) json_object_set_new(js, "http", hjs); } - - FLOWLOCK_UNLOCK(p->flow); } } if (json_output_ctx->flags & LOG_JSON_TLS) { if (p->flow != NULL) { - FLOWLOCK_RDLOCK(p->flow); uint16_t proto = FlowGetAppProtocol(p->flow); /* http alert */ if (proto == ALPROTO_TLS) AlertJsonTls(p->flow, js); - - FLOWLOCK_UNLOCK(p->flow); } } if (json_output_ctx->flags & LOG_JSON_SSH) { if (p->flow != NULL) { - FLOWLOCK_RDLOCK(p->flow); uint16_t proto = FlowGetAppProtocol(p->flow); /* http alert */ if (proto == ALPROTO_SSH) AlertJsonSsh(p->flow, js); - - FLOWLOCK_UNLOCK(p->flow); } } if (json_output_ctx->flags & LOG_JSON_SMTP) { if (p->flow != NULL) { - FLOWLOCK_RDLOCK(p->flow); uint16_t proto = FlowGetAppProtocol(p->flow); /* http alert */ @@ -276,8 +266,6 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (hjs) json_object_set_new(js, "email", hjs); } - - FLOWLOCK_UNLOCK(p->flow); } } @@ -353,7 +341,6 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) int have_xff_ip = 0; char buffer[XFF_MAXLEN]; - FLOWLOCK_RDLOCK(p->flow); if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { if (pa->flags & PACKET_ALERT_FLAG_TX) { have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN); @@ -361,7 +348,6 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); } } - FLOWLOCK_UNLOCK(p->flow); if (have_xff_ip) { if (xff_cfg->flags & XFF_EXTRADATA) { diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 8ae8c4297ac0..66ab32aea9f5 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -370,14 +370,12 @@ static int JsonDropLogger(ThreadVars *tv, void *thread_data, const Packet *p) return 0; if (p->flow) { - FLOWLOCK_RDLOCK(p->flow); if (p->flow->flags & FLOW_ACTION_DROP) { if (PKT_IS_TOSERVER(p) && !(p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) p->flow->flags |= FLOW_TOSERVER_DROP_LOGGED; else if (PKT_IS_TOCLIENT(p) && !(p->flow->flags & FLOW_TOCLIENT_DROP_LOGGED)) p->flow->flags |= FLOW_TOCLIENT_DROP_LOGGED; } - FLOWLOCK_UNLOCK(p->flow); } return 0; } @@ -406,14 +404,12 @@ static int JsonDropLogCondition(ThreadVars *tv, const Packet *p) int ret = FALSE; /* for a flow that will be dropped fully, log just once per direction */ - FLOWLOCK_RDLOCK(p->flow); if (p->flow->flags & FLOW_ACTION_DROP) { if (PKT_IS_TOSERVER(p) && !(p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) ret = TRUE; else if (PKT_IS_TOCLIENT(p) && !(p->flow->flags & FLOW_TOCLIENT_DROP_LOGGED)) ret = TRUE; } - FLOWLOCK_UNLOCK(p->flow); /* if drop is caused by signature, log anyway */ if (p->alerts.drop.action != 0) diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index e8178f3152d6..2b0ac7f99c0c 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -99,7 +99,6 @@ static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) } /* check if we have SSH state or not */ - FLOWLOCK_WRLOCK(p->flow); uint16_t proto = FlowGetAppProtocol(p->flow); if (proto != ALPROTO_SSH) goto end; @@ -136,7 +135,6 @@ static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) /* we only log the state once */ ssh_state->cli_hdr.flags |= SSH_FLAG_STATE_LOGGED; end: - FLOWLOCK_UNLOCK(p->flow); return 0; } @@ -286,7 +284,6 @@ static int JsonSshCondition(ThreadVars *tv, const Packet *p) return FALSE; } - FLOWLOCK_RDLOCK(p->flow); uint16_t proto = FlowGetAppProtocol(p->flow); if (proto != ALPROTO_SSH) goto dontlog; @@ -307,10 +304,8 @@ static int JsonSshCondition(ThreadVars *tv, const Packet *p) /* todo: logic to log once */ - FLOWLOCK_UNLOCK(p->flow); return TRUE; dontlog: - FLOWLOCK_UNLOCK(p->flow); return FALSE; } diff --git a/src/output-lua.c b/src/output-lua.c index deed5d5bc990..1bd1aae695ee 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -266,13 +266,11 @@ static int LuaPacketLoggerSsh(ThreadVars *tv, void *thread_data, const Packet *p } SCMutexUnlock(&td->lua_ctx->m); - FLOWLOCK_WRLOCK(p->flow); SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); if (ssh_state != NULL) ssh_state->cli_hdr.flags |= SSH_FLAG_STATE_LOGGED_LUA; - FLOWLOCK_UNLOCK(p->flow); SCReturnInt(0); } @@ -290,7 +288,6 @@ static int LuaPacketConditionSsh(ThreadVars *tv, const Packet *p) return FALSE; } - FLOWLOCK_RDLOCK(p->flow); uint16_t proto = FlowGetAppProtocol(p->flow); if (proto != ALPROTO_SSH) goto dontlog; @@ -309,10 +306,8 @@ static int LuaPacketConditionSsh(ThreadVars *tv, const Packet *p) if (ssh_state->cli_hdr.flags & SSH_FLAG_STATE_LOGGED_LUA) goto dontlog; - FLOWLOCK_UNLOCK(p->flow); return TRUE; dontlog: - FLOWLOCK_UNLOCK(p->flow); return FALSE; } diff --git a/src/output-streaming.c b/src/output-streaming.c index 6c8e5a066f24..1300295700ae 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -330,8 +330,6 @@ static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data, else flags |= OUTPUT_STREAMING_FLAG_TOSERVER; - FLOWLOCK_WRLOCK(f); - if (op_thread_data->loggers & (1<protoctx; if (ssn) { @@ -359,7 +357,6 @@ static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data, } } - FLOWLOCK_UNLOCK(f); return TM_ECODE_OK; } diff --git a/src/output-tx.c b/src/output-tx.c index 004a83adc610..ad24e5cb0c0b 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -148,7 +148,6 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ Flow * const f = p->flow; - FLOWLOCK_WRLOCK(f); /* WRITE lock before we updated flow logged id */ AppProto alproto = f->alproto; if (AppLayerParserProtocolIsTxAware(p->proto, alproto) == 0) @@ -250,7 +249,6 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ } end: - FLOWLOCK_UNLOCK(f); return TM_ECODE_OK; } diff --git a/src/output.c b/src/output.c index ed714e902347..db742d4136eb 100644 --- a/src/output.c +++ b/src/output.c @@ -916,7 +916,7 @@ void OutputNotifyFileRotation(void) { } } -static TmEcode OutputLoggerLog(ThreadVars *tv, Packet *p, void *thread_data, +TmEcode OutputLoggerLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) { LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data; @@ -933,7 +933,7 @@ static TmEcode OutputLoggerLog(ThreadVars *tv, Packet *p, void *thread_data, return TM_ECODE_OK; } -static TmEcode OutputLoggerThreadInit(ThreadVars *tv, void *initdata, +TmEcode OutputLoggerThreadInit(ThreadVars *tv, void *initdata, void **data) { LoggerThreadStore *thread_store = SCCalloc(1, sizeof(*thread_store)); @@ -960,7 +960,7 @@ static TmEcode OutputLoggerThreadInit(ThreadVars *tv, void *initdata, return TM_ECODE_OK; } -static TmEcode OutputLoggerThreadDeinit(ThreadVars *tv, void *thread_data) +TmEcode OutputLoggerThreadDeinit(ThreadVars *tv, void *thread_data) { LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data; RootLogger *logger = TAILQ_FIRST(&RootLoggers); @@ -983,7 +983,7 @@ static TmEcode OutputLoggerThreadDeinit(ThreadVars *tv, void *thread_data) return TM_ECODE_OK; } -static void OutputLoggerExitPrintStats(ThreadVars *tv, void *thread_data) +void OutputLoggerExitPrintStats(ThreadVars *tv, void *thread_data) { LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data; RootLogger *logger = TAILQ_FIRST(&RootLoggers); @@ -1015,21 +1015,10 @@ void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, void TmModuleLoggerRegister(void) { - tmm_modules[TMM_LOGGER].name = "__root_logger__"; - tmm_modules[TMM_LOGGER].ThreadInit = OutputLoggerThreadInit; - tmm_modules[TMM_LOGGER].ThreadDeinit = OutputLoggerThreadDeinit; - tmm_modules[TMM_LOGGER].ThreadExitPrintStats = OutputLoggerExitPrintStats; - tmm_modules[TMM_LOGGER].Func = OutputLoggerLog;; - OutputRegisterRootLoggers(); OutputRegisterLoggers(); } -void SetupOutputs(ThreadVars *tv) -{ - TmSlotSetFuncAppend(tv, &tmm_modules[TMM_LOGGER], NULL); -} - /** * \brief Register all root loggers. */ diff --git a/src/output.h b/src/output.h index 009d4995be62..5d01c904ce37 100644 --- a/src/output.h +++ b/src/output.h @@ -42,7 +42,6 @@ typedef OutputCtx *(*OutputInitFunc)(ConfNode *); typedef OutputCtx *(*OutputInitSubFunc)(ConfNode *, OutputCtx *); typedef TmEcode (*OutputLogFunc)(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); - typedef struct OutputModule_ { LoggerId logger_id; const char *name; @@ -197,6 +196,11 @@ void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, ThreadExitPrintStatsFunc ThreadExitPrintStats, OutputLogFunc LogFunc); void TmModuleLoggerRegister(void); -void SetupOutputs(ThreadVars *); + +TmEcode OutputLoggerLog(ThreadVars *, Packet *, void *, PacketQueue *, + PacketQueue *); +TmEcode OutputLoggerThreadInit(ThreadVars *, void *, void **); +TmEcode OutputLoggerThreadDeinit(ThreadVars *, void *); +void OutputLoggerExitPrintStats(ThreadVars *, void *); #endif /* ! __OUTPUT_H__ */ diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index 714f2af156e9..76bc49214726 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -101,8 +101,6 @@ int RunModeErfFileSingle(void) } TmSlotSetFuncAppend(tv, tm_module, NULL); - SetupOutputs(tv); - if (TmThreadSpawn(tv) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); @@ -231,9 +229,6 @@ int RunModeErfFileAutoFp(void) TmThreadSetGroupName(tv_detect_ncpu, "Detect"); - /* Add logger. */ - SetupOutputs(tv_detect_ncpu); - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index e671a4a7b665..6bf44ae7d55b 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -107,8 +107,6 @@ int RunModeFilePcapSingle(void) } TmSlotSetFuncAppend(tv, tm_module, NULL); - SetupOutputs(tv); - TmThreadSetCPU(tv, WORKER_CPU_SET); #ifndef AFLFUZZ_PCAP_RUNMODE @@ -250,9 +248,6 @@ int RunModeFilePcapAutoFp(void) TmThreadSetGroupName(tv_detect_ncpu, "Detect"); - /* Add logger. */ - SetupOutputs(tv_detect_ncpu); - TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { diff --git a/src/tm-modules.c b/src/tm-modules.c index f0d8b89019f4..13fa409f196b 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -233,7 +233,6 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_DETECTLOADER); CASE_CODE (TMM_RECEIVENETMAP); CASE_CODE (TMM_DECODENETMAP); - CASE_CODE (TMM_LOGGER); CASE_CODE (TMM_SIZE); } diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index a0ca3bcad848..8325687a8322 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -68,8 +68,6 @@ typedef enum { TMM_UNIXMANAGER, - TMM_LOGGER, - TMM_SIZE, } TmmId; diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index 07e0bc9d3c6d..913cb3e78c93 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -448,15 +448,6 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p) SCEnter(); SCLogDebug("Packet %p, p->root %p, alloced %s", p, p->root, p->flags & PKT_ALLOC ? "true" : "false"); - /** \todo make this a callback - * Release tcp segments. Done here after alerting can use them. */ - if (p->flow != NULL && p->proto == IPPROTO_TCP) { - SCMutexLock(&p->flow->m); - StreamTcpPruneSession(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? - STREAM_TOSERVER : STREAM_TOCLIENT); - SCMutexUnlock(&p->flow->m); - } - if (IS_TUNNEL_PKT(p)) { SCLogDebug("Packet %p is a tunnel packet: %s", p,p->root ? "upper layer" : "tunnel root"); diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 26925c2ecaf1..6800eb5e75c6 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -257,9 +257,6 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - /* Add logger. */ - SetupOutputs(tv_detect_ncpu); - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); @@ -338,8 +335,6 @@ static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc Mod } TmSlotSetFuncAppend(tv, tm_module, NULL); - SetupOutputs(tv); - TmThreadSetCPU(tv, WORKER_CPU_SET); if (TmThreadSpawn(tv) != TM_ECODE_OK) { @@ -519,8 +514,6 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); - SetupOutputs(tv_detect_ncpu); - TmThreadSetGroupName(tv_detect_ncpu, "Detect"); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { @@ -638,8 +631,6 @@ int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, } TmSlotSetFuncAppend(tv, tm_module, NULL); - SetupOutputs(tv); - TmThreadSetCPU(tv, WORKER_CPU_SET); if (TmThreadSpawn(tv) != TM_ECODE_OK) { From 55f2704a25876a1a9886a72f3057f7b5cf3ab8d7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 13 Jul 2016 10:48:14 -0600 Subject: [PATCH 1680/2553] logging: remove the packetqueue's from the logging path They are not referenced by any loggers, and they probably shouldn't be either. --- src/flow-worker.c | 4 ++-- src/output-file.c | 2 +- src/output-filedata.c | 2 +- src/output-packet.c | 2 +- src/output-streaming.c | 2 +- src/output-tx.c | 2 +- src/output.c | 5 ++--- src/output.h | 7 +++---- 8 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/flow-worker.c b/src/flow-worker.c index 2d981e4be702..89894c7199b4 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -191,7 +191,7 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac } // Outputs - OutputLoggerLog(tv, x, fw->output_thread, preq, unused); + OutputLoggerLog(tv, x, fw->output_thread); /* put these packets in the preq queue so that they are * by the other thread modules before packet 'p'. */ @@ -216,7 +216,7 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac } // Outputs. - OutputLoggerLog(tv, p, fw->output_thread, preq, unused); + OutputLoggerLog(tv, p, fw->output_thread); /* Release tcp segments. Done here after alerting can use them. */ if (p->flow != NULL && p->proto == IPPROTO_TCP) { diff --git a/src/output-file.c b/src/output-file.c index 402b398ab005..f43d63970f02 100644 --- a/src/output-file.c +++ b/src/output-file.c @@ -90,7 +90,7 @@ int OutputRegisterFileLogger(LoggerId id, const char *name, FileLogger LogFunc, return 0; } -static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) +static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data) { BUG_ON(thread_data == NULL); diff --git a/src/output-filedata.c b/src/output-filedata.c index 589bef6893e8..50cff2816276 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -124,7 +124,7 @@ static int CallLoggers(ThreadVars *tv, OutputLoggerThreadStore *store_list, return file_logged; } -static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) +static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data) { BUG_ON(thread_data == NULL); diff --git a/src/output-packet.c b/src/output-packet.c index 3d18ad449cd6..fe4cc2fee825 100644 --- a/src/output-packet.c +++ b/src/output-packet.c @@ -90,7 +90,7 @@ int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, return 0; } -static TmEcode OutputPacketLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) +static TmEcode OutputPacketLog(ThreadVars *tv, Packet *p, void *thread_data) { BUG_ON(thread_data == NULL); diff --git a/src/output-streaming.c b/src/output-streaming.c index 1300295700ae..aae5ec550136 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -298,7 +298,7 @@ int StreamIterator(Flow *f, TcpStream *stream, int close, void *cbdata, uint8_t return 0; } -static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) +static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data) { BUG_ON(thread_data == NULL); diff --git a/src/output-tx.c b/src/output-tx.c index ad24e5cb0c0b..339cd3b4fab8 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -127,7 +127,7 @@ int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, return 0; } -static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) +static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) { BUG_ON(thread_data == NULL); if (list == NULL) { diff --git a/src/output.c b/src/output.c index db742d4136eb..6c6ee8f805dd 100644 --- a/src/output.c +++ b/src/output.c @@ -916,15 +916,14 @@ void OutputNotifyFileRotation(void) { } } -TmEcode OutputLoggerLog(ThreadVars *tv, Packet *p, void *thread_data, - PacketQueue *pq, PacketQueue *postpq) +TmEcode OutputLoggerLog(ThreadVars *tv, Packet *p, void *thread_data) { LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data; RootLogger *logger = TAILQ_FIRST(&RootLoggers); LoggerThreadStoreNode *thread_store_node = TAILQ_FIRST(thread_store); while (logger && thread_store_node) { if (logger->LogFunc != NULL) { - logger->LogFunc(tv, p, thread_store_node->thread_data, pq, postpq); + logger->LogFunc(tv, p, thread_store_node->thread_data); } logger = TAILQ_NEXT(logger, entries); thread_store_node = TAILQ_NEXT(thread_store_node, entries); diff --git a/src/output.h b/src/output.h index 5d01c904ce37..32004a69691d 100644 --- a/src/output.h +++ b/src/output.h @@ -40,8 +40,8 @@ typedef OutputCtx *(*OutputInitFunc)(ConfNode *); typedef OutputCtx *(*OutputInitSubFunc)(ConfNode *, OutputCtx *); -typedef TmEcode (*OutputLogFunc)(ThreadVars *, Packet *, void *, PacketQueue *, - PacketQueue *); +typedef TmEcode (*OutputLogFunc)(ThreadVars *, Packet *, void *); + typedef struct OutputModule_ { LoggerId logger_id; const char *name; @@ -197,8 +197,7 @@ void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, OutputLogFunc LogFunc); void TmModuleLoggerRegister(void); -TmEcode OutputLoggerLog(ThreadVars *, Packet *, void *, PacketQueue *, - PacketQueue *); +TmEcode OutputLoggerLog(ThreadVars *, Packet *, void *); TmEcode OutputLoggerThreadInit(ThreadVars *, void *, void **); TmEcode OutputLoggerThreadDeinit(ThreadVars *, void *); void OutputLoggerExitPrintStats(ThreadVars *, void *); From 688e8dbe7f4e085ae72cb140bb0192fd0742bd5c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 13 Jul 2016 17:07:45 -0600 Subject: [PATCH 1681/2553] stream: remove lock from StreamTcpSegmentForEach This is only entered from logging functions which are already called with a locked flow. --- src/stream-tcp.c | 6 ++---- src/stream.c | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 72fb4eda9bd0..a0517f3a4b32 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5723,6 +5723,8 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread * \note when stream engine is running in inline mode all segments are used, * in IDS/non-inline mode only ack'd segments are iterated. * + * \note Must be called under flow lock. + * * \return -1 in case of error, the number of segment in case of success * */ @@ -5736,11 +5738,9 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback if (p->flow == NULL) return 0; - FLOWLOCK_RDLOCK(p->flow); ssn = (TcpSession *)p->flow->protoctx; if (ssn == NULL) { - FLOWLOCK_UNLOCK(p->flow); return 0; } @@ -5758,13 +5758,11 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback ret = CallbackFunc(p, data, seg->payload, seg->payload_len); if (ret != 1) { SCLogDebug("Callback function has failed"); - FLOWLOCK_UNLOCK(p->flow); return -1; } seg = seg->next; cnt++; } - FLOWLOCK_UNLOCK(p->flow); return cnt; } diff --git a/src/stream.c b/src/stream.c index 8aabd6dcaea6..6415420981a5 100644 --- a/src/stream.c +++ b/src/stream.c @@ -268,6 +268,8 @@ void StreamMsgReturnListToPool(void *list) } /** \brief Run callback for all segments + * + * Must be called under flow lock. * * \return -1 in case of error, the number of segment in case of success */ From 8865009fcaf0dfeed3423d184482b1a94a4eee4f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 14 Jul 2016 09:53:59 -0600 Subject: [PATCH 1682/2553] lua: remove flow locking from the lua layer --- src/detect-lua-extensions.c | 65 +++++++------------------------------ src/detect-lua-extensions.h | 2 +- src/detect-lua.c | 16 ++------- src/output-lua.c | 14 ++++---- src/util-lua-common.c | 59 ++++++++------------------------- src/util-lua-smtp.c | 65 +++++++++---------------------------- src/util-lua-ssh.c | 48 +++++++-------------------- src/util-lua-tls.c | 36 +++++--------------- src/util-lua.c | 10 +++--- src/util-lua.h | 14 ++------ 10 files changed, 78 insertions(+), 251 deletions(-) diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index 44a8cfd216e1..6bd5c2453bce 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -80,7 +80,6 @@ static int LuaGetFlowvar(lua_State *luastate) Flow *f; FlowVar *fv; DetectLuaData *ld; - int flow_lock = 0; /* need luajit data for id -> idx conversion */ lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); @@ -94,7 +93,7 @@ static int LuaGetFlowvar(lua_State *luastate) } /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); + f = LuaStateGetFlow(luastate); if (f == NULL) { lua_pushnil(luastate); lua_pushstring(luastate, "no flow"); @@ -120,15 +119,8 @@ static int LuaGetFlowvar(lua_State *luastate) return 2; } - /* lookup var */ - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_RDLOCK(f); - fv = FlowVarGet(f, idx); if (fv == NULL) { - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); - lua_pushnil(luastate); lua_pushstring(luastate, "no flow var"); return 2; @@ -137,9 +129,6 @@ static int LuaGetFlowvar(lua_State *luastate) LuaPushStringBuffer(luastate, (const uint8_t *)fv->data.fv_str.value, (size_t)fv->data.fv_str.value_len); - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); - return 1; } @@ -154,7 +143,6 @@ int LuaSetFlowvar(lua_State *luastate) uint8_t *buffer; DetectEngineThreadCtx *det_ctx; DetectLuaData *ld; - int flow_lock = 0; /* need luajit data for id -> idx conversion */ lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); @@ -179,7 +167,7 @@ int LuaSetFlowvar(lua_State *luastate) } /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); + f = LuaStateGetFlow(luastate); if (f == NULL) { lua_pushnil(luastate); lua_pushstring(luastate, "no flow"); @@ -239,10 +227,7 @@ int LuaSetFlowvar(lua_State *luastate) memcpy(buffer, str, len); buffer[len] = '\0'; - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FlowVarAddStr(f, idx, buffer, len); - else - FlowVarAddStrNoLock(f, idx, buffer, len); + FlowVarAddStr(f, idx, buffer, len); //SCLogInfo("stored:"); //PrintRawDataFp(stdout,buffer,len); @@ -256,7 +241,6 @@ static int LuaGetFlowint(lua_State *luastate) Flow *f; FlowVar *fv; DetectLuaData *ld; - int flow_lock = 0; uint32_t number; /* need luajit data for id -> idx conversion */ @@ -271,7 +255,7 @@ static int LuaGetFlowint(lua_State *luastate) } /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); + f = LuaStateGetFlow(luastate); if (f == NULL) { lua_pushnil(luastate); lua_pushstring(luastate, "no flow"); @@ -301,24 +285,15 @@ static int LuaGetFlowint(lua_State *luastate) } /* lookup var */ - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_RDLOCK(f); - fv = FlowVarGet(f, idx); if (fv == NULL) { SCLogDebug("fv NULL"); - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); - lua_pushnil(luastate); lua_pushstring(luastate, "no flow var"); return 2; } number = fv->data.fv_int.value; - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); - /* return value through luastate, as a luanumber */ lua_pushnumber(luastate, (lua_Number)number); SCLogDebug("retrieved flow:%p idx:%u value:%u", f, idx, number); @@ -334,7 +309,6 @@ int LuaSetFlowint(lua_State *luastate) Flow *f; DetectEngineThreadCtx *det_ctx; DetectLuaData *ld; - int flow_lock = 0; uint32_t number; lua_Number luanumber; @@ -361,7 +335,7 @@ int LuaSetFlowint(lua_State *luastate) } /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); + f = LuaStateGetFlow(luastate); if (f == NULL) { lua_pushnil(luastate); lua_pushstring(luastate, "no flow"); @@ -401,10 +375,7 @@ int LuaSetFlowint(lua_State *luastate) return 2; } - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FlowVarAddInt(f, idx, number); - else - FlowVarAddIntNoLock(f, idx, number); + FlowVarAddInt(f, idx, number); SCLogDebug("stored flow:%p idx:%u value:%u", f, idx, number); return 0; @@ -417,7 +388,6 @@ static int LuaIncrFlowint(lua_State *luastate) Flow *f; FlowVar *fv; DetectLuaData *ld; - int flow_lock = 0; uint32_t number; /* need luajit data for id -> idx conversion */ @@ -432,7 +402,7 @@ static int LuaIncrFlowint(lua_State *luastate) } /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); + f = LuaStateGetFlow(luastate); if (f == NULL) { lua_pushnil(luastate); lua_pushstring(luastate, "no flow"); @@ -462,9 +432,6 @@ static int LuaIncrFlowint(lua_State *luastate) } /* lookup var */ - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_RDLOCK(f); - fv = FlowVarGet(f, idx); if (fv == NULL) { number = 1; @@ -475,9 +442,6 @@ static int LuaIncrFlowint(lua_State *luastate) } FlowVarAddIntNoLock(f, idx, number); - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); - /* return value through luastate, as a luanumber */ lua_pushnumber(luastate, (lua_Number)number); SCLogDebug("incremented flow:%p idx:%u value:%u", f, idx, number); @@ -493,7 +457,6 @@ static int LuaDecrFlowint(lua_State *luastate) Flow *f; FlowVar *fv; DetectLuaData *ld; - int flow_lock = 0; uint32_t number; /* need luajit data for id -> idx conversion */ @@ -508,7 +471,7 @@ static int LuaDecrFlowint(lua_State *luastate) } /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); + f = LuaStateGetFlow(luastate); if (f == NULL) { lua_pushnil(luastate); lua_pushstring(luastate, "no flow"); @@ -538,9 +501,6 @@ static int LuaDecrFlowint(lua_State *luastate) } /* lookup var */ - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_RDLOCK(f); - fv = FlowVarGet(f, idx); if (fv == NULL) { number = 0; @@ -551,9 +511,6 @@ static int LuaDecrFlowint(lua_State *luastate) } FlowVarAddIntNoLock(f, idx, number); - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); - /* return value through luastate, as a luanumber */ lua_pushnumber(luastate, (lua_Number)number); SCLogDebug("decremented flow:%p idx:%u value:%u", f, idx, number); @@ -563,7 +520,7 @@ static int LuaDecrFlowint(lua_State *luastate) } void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld, DetectEngineThreadCtx *det_ctx, - Flow *f, int flow_locked, Packet *p, uint8_t flags) + Flow *f, Packet *p, uint8_t flags) { SCLogDebug("det_ctx %p, f %p", det_ctx, f); @@ -577,9 +534,9 @@ void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld, DetectEngi lua_pushlightuserdata(lua_state, (void *)det_ctx); lua_settable(lua_state, LUA_REGISTRYINDEX); - LuaStateSetFlow(lua_state, f, flow_locked); + LuaStateSetFlow(lua_state, f); - if (det_ctx->tx_id_set && flow_locked == LUA_FLOW_LOCKED_BY_PARENT) { + if (det_ctx->tx_id_set) { if (f && f->alstate) { void *txptr = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, det_ctx->tx_id); if (txptr) { diff --git a/src/detect-lua-extensions.h b/src/detect-lua-extensions.h index b8aa27366ee9..54a465783e2d 100644 --- a/src/detect-lua-extensions.h +++ b/src/detect-lua-extensions.h @@ -29,7 +29,7 @@ int LuaRegisterExtensions(lua_State *); void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *, DetectEngineThreadCtx *det_ctx, - Flow *f, int flow_locked, Packet *p, uint8_t flags); + Flow *f, Packet *p, uint8_t flags); #endif /* HAVE_LUA */ #endif diff --git a/src/detect-lua.c b/src/detect-lua.c index 99cb13be3776..3343a6be762b 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -309,13 +309,8 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch if (tluajit == NULL) SCReturnInt(0); - /* setup extension data for use in lua c functions */ - int flow_lock = (f != NULL) ? /* if we have a flow, it's locked */ - LUA_FLOW_LOCKED_BY_PARENT : - LUA_FLOW_NOT_LOCKED_BY_PARENT; - LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, - f, flow_lock, /* no packet in the ctx */NULL, 0); + f, /* no packet in the ctx */NULL, 0); /* prepare data to pass to script */ lua_getglobal(tluajit->luastate, "match"); @@ -424,12 +419,8 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, LuaStateSetThreadVars(tluajit->luastate, tv); - int flow_lock = (p->flow != NULL) ? /* if we have a flow, it's locked */ - LUA_FLOW_LOCKED_BY_PARENT : - LUA_FLOW_NOT_LOCKED_BY_PARENT; - LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, - p->flow, flow_lock, p, flags); + p->flow, p, flags); if ((tluajit->flags & DATATYPE_PAYLOAD) && p->payload_len == 0) SCReturnInt(0); @@ -554,8 +545,7 @@ static int DetectLuaAppMatchCommon (ThreadVars *t, DetectEngineThreadCtx *det_ct /* setup extension data for use in lua c functions */ LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, - f, /* flow is locked */LUA_FLOW_LOCKED_BY_PARENT, - NULL, flags); + f, NULL, flags); if (tluajit->alproto != ALPROTO_UNKNOWN) { int alproto = f->alproto; diff --git a/src/output-lua.c b/src/output-lua.c index 1bd1aae695ee..b71b0e3736f1 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -106,7 +106,7 @@ static int LuaTxLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow LuaStateSetThreadVars(td->lua_ctx->luastate, tv); LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); LuaStateSetTX(td->lua_ctx->luastate, txptr); - LuaStateSetFlow(td->lua_ctx->luastate, f, /* locked */LUA_FLOW_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, f); /* prepare data to pass to script */ lua_getglobal(td->lua_ctx->luastate, "log"); @@ -150,7 +150,7 @@ static int LuaStreamingLogger(ThreadVars *tv, void *thread_data, const Flow *f, LuaStateSetThreadVars(td->lua_ctx->luastate, tv); if (flags & OUTPUT_STREAMING_FLAG_TRANSACTION) LuaStateSetTX(td->lua_ctx->luastate, txptr); - LuaStateSetFlow(td->lua_ctx->luastate, (Flow *)f, /* locked */LUA_FLOW_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, (Flow *)f); LuaStateSetStreamingBuffer(td->lua_ctx->luastate, &b); /* prepare data to pass to script */ @@ -213,7 +213,7 @@ static int LuaPacketLoggerAlerts(ThreadVars *tv, void *thread_data, const Packet LuaStateSetThreadVars(td->lua_ctx->luastate, tv); LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); - LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* unlocked */LUA_FLOW_NOT_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, p->flow); LuaStateSetPacketAlert(td->lua_ctx->luastate, (PacketAlert *)pa); /* prepare data to pass to script */ @@ -258,7 +258,7 @@ static int LuaPacketLoggerSsh(ThreadVars *tv, void *thread_data, const Packet *p LuaStateSetThreadVars(td->lua_ctx->luastate, tv); LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); - LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* unlocked */LUA_FLOW_NOT_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, p->flow); int retval = lua_pcall(td->lua_ctx->luastate, 0, 0, 0); if (retval != 0) { @@ -347,7 +347,7 @@ static int LuaPacketLogger(ThreadVars *tv, void *thread_data, const Packet *p) LuaStateSetThreadVars(td->lua_ctx->luastate, tv); LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); - LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* unlocked */LUA_FLOW_NOT_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, p->flow); /* prepare data to pass to script */ lua_newtable(td->lua_ctx->luastate); @@ -398,7 +398,7 @@ static int LuaFileLogger(ThreadVars *tv, void *thread_data, const Packet *p, con LuaStateSetThreadVars(td->lua_ctx->luastate, tv); LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); LuaStateSetTX(td->lua_ctx->luastate, txptr); - LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* locked */LUA_FLOW_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, p->flow); LuaStateSetFile(td->lua_ctx->luastate, (File *)ff); /* get the lua function to call */ @@ -429,7 +429,7 @@ static int LuaFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) SCMutexLock(&td->lua_ctx->m); LuaStateSetThreadVars(td->lua_ctx->luastate, tv); - LuaStateSetFlow(td->lua_ctx->luastate, f, /* locked */LUA_FLOW_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, f); /* get the lua function to call */ lua_getglobal(td->lua_ctx->luastate, "log"); diff --git a/src/util-lua-common.c b/src/util-lua-common.c index d44d5a7c8211..367374d76ca6 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -210,18 +210,12 @@ static int LuaCallbackTimeStringPushToStackFromFlow(lua_State *luastate, const F static int LuaCallbackFlowTimeString(lua_State *luastate) { int r = 0; - int locked = 0; - Flow *flow = LuaStateGetFlow(luastate, &locked); + Flow *flow = LuaStateGetFlow(luastate); if (flow == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (locked == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(flow); - r = LuaCallbackTimeStringPushToStackFromFlow(luastate, flow); - FLOWLOCK_UNLOCK(flow); - } else { - r = LuaCallbackTimeStringPushToStackFromFlow(luastate, flow); - } + r = LuaCallbackTimeStringPushToStackFromFlow(luastate, flow); + return r; } @@ -345,18 +339,12 @@ static int LuaCallbackTuplePushToStackFromFlow(lua_State *luastate, const Flow * static int LuaCallbackTupleFlow(lua_State *luastate) { int r = 0; - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = LuaCallbackTuplePushToStackFromFlow(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = LuaCallbackTuplePushToStackFromFlow(luastate, f); - } + r = LuaCallbackTuplePushToStackFromFlow(luastate, f); + return r; } @@ -384,18 +372,12 @@ static int LuaCallbackAppLayerProtoPushToStackFromFlow(lua_State *luastate, cons static int LuaCallbackAppLayerProtoFlow(lua_State *luastate) { int r = 0; - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f); - } + r = LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f); + return r; } @@ -423,18 +405,12 @@ static int LuaCallbackStatsPushToStackFromFlow(lua_State *luastate, const Flow * static int LuaCallbackStatsFlow(lua_State *luastate) { int r = 0; - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = LuaCallbackStatsPushToStackFromFlow(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = LuaCallbackStatsPushToStackFromFlow(luastate, f); - } + r = LuaCallbackStatsPushToStackFromFlow(luastate, f); + return r; } @@ -771,18 +747,11 @@ int LuaRegisterFunctions(lua_State *luastate) int LuaStateNeedProto(lua_State *luastate, AppProto alproto) { AppProto flow_alproto = 0; - int locked = 0; - Flow *flow = LuaStateGetFlow(luastate, &locked); + Flow *flow = LuaStateGetFlow(luastate); if (flow == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (locked == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(flow); - flow_alproto = flow->alproto; - FLOWLOCK_UNLOCK(flow); - } else { - flow_alproto = flow->alproto; - } + flow_alproto = flow->alproto; return (alproto == flow_alproto); diff --git a/src/util-lua-smtp.c b/src/util-lua-smtp.c index a64c7098323e..8fca9131a1bd 100644 --- a/src/util-lua-smtp.c +++ b/src/util-lua-smtp.c @@ -105,8 +105,7 @@ static int SMTPGetMimeField(lua_State *luastate) if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { return LuaCallbackError(luastate, "error: protocol not SMTP"); } - int lock_hint = 0; - Flow *flow = LuaStateGetFlow(luastate, &lock_hint); + Flow *flow = LuaStateGetFlow(luastate); /* check that flow exist */ if(flow == NULL) { return LuaCallbackError(luastate, "Error: no flow found"); @@ -115,17 +114,8 @@ static int SMTPGetMimeField(lua_State *luastate) if (name == NULL) return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - /* lock check */ - if(lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(flow); - /* get specific MIME field */ - GetMimeDecField(luastate, flow, name); - /* unlock flow mutex to allow for multithreading */ - FLOWLOCK_UNLOCK(flow); - /* return number of fields pushed to luastate */ - } else { /* if mutex already locked */ - GetMimeDecField(luastate, flow, name); - } + GetMimeDecField(luastate, flow, name); + return 1; } @@ -195,22 +185,14 @@ static int SMTPGetMimeList(lua_State *luastate) if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { return LuaCallbackError(luastate, "Error: protocol not SMTP"); } - /* mutex lock indicator var */ - int lock_hint = 0; /* Extract network flow */ - Flow *flow = LuaStateGetFlow(luastate, &lock_hint); + Flow *flow = LuaStateGetFlow(luastate); if(flow == NULL) { return LuaCallbackError(luastate, "Error: no flow found"); } - /* check if flow already locked */ - if(lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - /* mutexlock flow */ - FLOWLOCK_RDLOCK(flow); - GetMimeList(luastate, flow); - FLOWLOCK_UNLOCK(flow); - } else { - GetMimeList(luastate, flow); - } + + GetMimeList(luastate, flow); + return 1; } @@ -260,22 +242,14 @@ static int SMTPGetMailFrom(lua_State *luastate) if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { return LuaCallbackError(luastate, "Error: protocol not SMTP"); } - /* use lock_hint to check for mutexlock on flow */ - int lock_hint = 0; /* Extract flow, with lockhint to check mutexlocking */ - Flow *flow = LuaStateGetFlow(luastate, &lock_hint); + Flow *flow = LuaStateGetFlow(luastate); if(flow == NULL) { return LuaCallbackError(luastate, "Internal Error: no flow"); } - /* check if already mutexlocked by parents */ - if(lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - /* mutexlock flow */ - FLOWLOCK_RDLOCK(flow); - GetMailFrom(luastate, flow); - FLOWLOCK_UNLOCK(flow); - } else { - GetMailFrom(luastate, flow); - } + + GetMailFrom(luastate, flow); + return 1; } @@ -335,23 +309,14 @@ static int SMTPGetRcptList(lua_State *luastate) if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { return LuaCallbackError(luastate, "Error: protocol not SMTP"); } - /* create lockhint var for flowlock check. */ - int lock_hint = 0; /* Extract flow, with lockhint to check mutexlocking */ - Flow *flow = LuaStateGetFlow(luastate, &lock_hint); + Flow *flow = LuaStateGetFlow(luastate); if(flow == NULL) { return LuaCallbackError(luastate, "Internal error: no flow"); } - /* check if already mutexlocked by parents */ - if(lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - /* lock flow */ - FLOWLOCK_RDLOCK(flow); - GetRcptList(luastate, flow); - /* open flow */ - FLOWLOCK_UNLOCK(flow); - } else { - GetRcptList(luastate, flow); - } + + GetRcptList(luastate, flow); + /* return 1 since we allways push one table to luastate */ return 1; } diff --git a/src/util-lua-ssh.c b/src/util-lua-ssh.c index df232c811855..892190080fa2 100644 --- a/src/util-lua-ssh.c +++ b/src/util-lua-ssh.c @@ -79,18 +79,12 @@ static int SshGetServerProtoVersion(lua_State *luastate) if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) return LuaCallbackError(luastate, "error: protocol not ssh"); - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = GetServerProtoVersion(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = GetServerProtoVersion(luastate, f); - } + r = GetServerProtoVersion(luastate, f); + return r; } @@ -116,18 +110,12 @@ static int SshGetServerSoftwareVersion(lua_State *luastate) if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) return LuaCallbackError(luastate, "error: protocol not ssh"); - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = GetServerSoftwareVersion(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = GetServerSoftwareVersion(luastate, f); - } + r = GetServerSoftwareVersion(luastate, f); + return r; } @@ -153,18 +141,12 @@ static int SshGetClientProtoVersion(lua_State *luastate) if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) return LuaCallbackError(luastate, "error: protocol not ssh"); - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = GetClientProtoVersion(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = GetClientProtoVersion(luastate, f); - } + r = GetClientProtoVersion(luastate, f); + return r; } @@ -190,18 +172,12 @@ static int SshGetClientSoftwareVersion(lua_State *luastate) if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) return LuaCallbackError(luastate, "error: protocol not ssh"); - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = GetClientSoftwareVersion(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = GetClientSoftwareVersion(luastate, f); - } + r = GetClientSoftwareVersion(luastate, f); + return r; } diff --git a/src/util-lua-tls.c b/src/util-lua-tls.c index e17e512e41c8..5d0a7491eb6a 100644 --- a/src/util-lua-tls.c +++ b/src/util-lua-tls.c @@ -118,18 +118,12 @@ static int TlsGetCertInfo(lua_State *luastate) int direction = LuaStateGetDirection(luastate); - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = GetCertInfo(luastate, f, direction); - FLOWLOCK_UNLOCK(f); - } else { - r = GetCertInfo(luastate, f, direction); - } + r = GetCertInfo(luastate, f, direction); + return r; } @@ -155,18 +149,12 @@ static int TlsGetSNI(lua_State *luastate) if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) return LuaCallbackError(luastate, "error: protocol not tls"); - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = GetSNI(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = GetSNI(luastate, f); - } + r = GetSNI(luastate, f); + return r; } @@ -217,18 +205,12 @@ static int TlsGetCertChain(lua_State *luastate) int direction = LuaStateGetDirection(luastate); - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = GetCertChain(luastate, f, direction); - FLOWLOCK_UNLOCK(f); - } else { - r = GetCertChain(luastate, f, direction); - } + r = GetCertChain(luastate, f, direction); + return r; } diff --git a/src/util-lua.c b/src/util-lua.c index 32d206c35b8b..54524826bd3a 100644 --- a/src/util-lua.c +++ b/src/util-lua.c @@ -124,10 +124,9 @@ void LuaStateSetTX(lua_State *luastate, void *txptr) lua_settable(luastate, LUA_REGISTRYINDEX); } -Flow *LuaStateGetFlow(lua_State *luastate, int *lock_hint) +Flow *LuaStateGetFlow(lua_State *luastate) { Flow *f = NULL; - int need_flow_lock = 0; lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow); lua_gettable(luastate, LUA_REGISTRYINDEX); @@ -136,13 +135,11 @@ Flow *LuaStateGetFlow(lua_State *luastate, int *lock_hint) /* need flow lock hint */ lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow_lock_hint); lua_gettable(luastate, LUA_REGISTRYINDEX); - need_flow_lock = lua_toboolean(luastate, -1); - *lock_hint = need_flow_lock; return f; } -void LuaStateSetFlow(lua_State *luastate, Flow *f, int need_flow_lock) +void LuaStateSetFlow(lua_State *luastate, Flow *f) { /* flow */ lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow); @@ -151,7 +148,8 @@ void LuaStateSetFlow(lua_State *luastate, Flow *f, int need_flow_lock) /* flow lock status hint */ lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow_lock_hint); - lua_pushboolean(luastate, need_flow_lock); + /* locking is not required, set to 0 for backwards compatibility */ + lua_pushboolean(luastate, 0); lua_settable(luastate, LUA_REGISTRYINDEX); } diff --git a/src/util-lua.h b/src/util-lua.h index 4ea4c60513f4..492007a62af5 100644 --- a/src/util-lua.h +++ b/src/util-lua.h @@ -32,9 +32,6 @@ typedef struct LuaStreamingBuffer_ { uint8_t flags; } LuaStreamingBuffer; -#define LUA_FLOW_LOCKED_BY_PARENT 0 -#define LUA_FLOW_NOT_LOCKED_BY_PARENT 1 - /* gets */ /** \brief get tv pointer from the lua state */ @@ -44,14 +41,10 @@ Packet *LuaStateGetPacket(lua_State *luastate); void *LuaStateGetTX(lua_State *luastate); /** \brief get flow pointer from lua state - * - * \param locked_by_parent[out] bool indicating if flow is locked - * (LUA_FLOW_LOCKED_BY_PARENT) or unlocked - * (LUA_FLOW_NOT_LOCKED_BY_PARENT) * * \retval f flow poiner or NULL if it was not set */ -Flow *LuaStateGetFlow(lua_State *luastate, int *locked_by_parent); +Flow *LuaStateGetFlow(lua_State *luastate); PacketAlert *LuaStateGetPacketAlert(lua_State *luastate); @@ -70,11 +63,8 @@ void LuaStateSetTX(lua_State *luastate, void *tx); /** \brief set a flow pointer in the lua state * * \param f flow pointer - * \param locked_by_parent bool indicating if flow is locked - * (LUA_FLOW_LOCKED_BY_PARENT) or unlocked - * (LUA_FLOW_NOT_LOCKED_BY_PARENT) */ -void LuaStateSetFlow(lua_State *luastate, Flow *f, int locked_by_parent); +void LuaStateSetFlow(lua_State *luastate, Flow *f); void LuaStateSetPacketAlert(lua_State *luastate, PacketAlert *pa); From 5a783e6854caf308eed9adfa516135101a0539d6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 15 Jul 2016 08:13:16 -0600 Subject: [PATCH 1683/2553] flow-bits: remove flow locks Code is now entered under flow lock. --- src/detect-flowbits.c | 31 ++++++++++++------------------- src/flow-bit.c | 23 +---------------------- src/flow-bit.h | 3 --- 3 files changed, 13 insertions(+), 44 deletions(-) diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 80494b07fe48..6745bda54d8b 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -70,39 +70,33 @@ void DetectFlowbitsRegister (void) } -static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd, const int flow_locked) +static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; - if (flow_locked) - FlowBitToggleNoLock(p->flow,fd->idx); - else - FlowBitToggle(p->flow,fd->idx); + FlowBitToggle(p->flow,fd->idx); + return 1; } -static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd, const int flow_locked) +static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; - if (flow_locked) - FlowBitUnsetNoLock(p->flow,fd->idx); - else - FlowBitUnset(p->flow,fd->idx); + FlowBitUnset(p->flow,fd->idx); + return 1; } -static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd, const int flow_locked) +static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; - if (flow_locked) - FlowBitSetNoLock(p->flow,fd->idx); - else - FlowBitSet(p->flow,fd->idx); + FlowBitSet(p->flow,fd->idx); + return 1; } @@ -133,7 +127,6 @@ int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx; if (fd == NULL) return 0; - const int flow_locked = det_ctx->flow_locked; switch (fd->cmd) { case DETECT_FLOWBITS_CMD_ISSET: @@ -141,11 +134,11 @@ int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p case DETECT_FLOWBITS_CMD_ISNOTSET: return DetectFlowbitMatchIsnotset(p,fd); case DETECT_FLOWBITS_CMD_SET: - return DetectFlowbitMatchSet(p,fd,flow_locked); + return DetectFlowbitMatchSet(p,fd); case DETECT_FLOWBITS_CMD_UNSET: - return DetectFlowbitMatchUnset(p,fd,flow_locked); + return DetectFlowbitMatchUnset(p,fd); case DETECT_FLOWBITS_CMD_TOGGLE: - return DetectFlowbitMatchToggle(p,fd,flow_locked); + return DetectFlowbitMatchToggle(p,fd); default: SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd); return 0; diff --git a/src/flow-bit.c b/src/flow-bit.c index 02c7fc474158..533bef5cc9df 100644 --- a/src/flow-bit.c +++ b/src/flow-bit.c @@ -81,31 +81,17 @@ static void FlowBitRemove(Flow *f, uint16_t idx) FlowBitFree(fb); } -void FlowBitSetNoLock(Flow *f, uint16_t idx) -{ - FlowBitAdd(f, idx); -} - void FlowBitSet(Flow *f, uint16_t idx) { - FLOWLOCK_WRLOCK(f); FlowBitAdd(f, idx); - FLOWLOCK_UNLOCK(f); -} - -void FlowBitUnsetNoLock(Flow *f, uint16_t idx) -{ - FlowBitRemove(f, idx); } void FlowBitUnset(Flow *f, uint16_t idx) { - FLOWLOCK_WRLOCK(f); FlowBitRemove(f, idx); - FLOWLOCK_UNLOCK(f); } -void FlowBitToggleNoLock(Flow *f, uint16_t idx) +void FlowBitToggle(Flow *f, uint16_t idx) { FlowBit *fb = FlowBitGet(f, idx); if (fb != NULL) { @@ -115,13 +101,6 @@ void FlowBitToggleNoLock(Flow *f, uint16_t idx) } } -void FlowBitToggle(Flow *f, uint16_t idx) -{ - FLOWLOCK_WRLOCK(f); - FlowBitToggleNoLock(f, idx); - FLOWLOCK_UNLOCK(f); -} - int FlowBitIsset(Flow *f, uint16_t idx) { int r = 0; diff --git a/src/flow-bit.h b/src/flow-bit.h index 1b966a007198..633b5ee3d9a9 100644 --- a/src/flow-bit.h +++ b/src/flow-bit.h @@ -38,11 +38,8 @@ typedef struct FlowBit_ { void FlowBitFree(FlowBit *); void FlowBitRegisterTests(void); -void FlowBitSetNoLock(Flow *, uint16_t); void FlowBitSet(Flow *, uint16_t); -void FlowBitUnsetNoLock(Flow *, uint16_t); void FlowBitUnset(Flow *, uint16_t); -void FlowBitToggleNoLock(Flow *, uint16_t); void FlowBitToggle(Flow *, uint16_t); int FlowBitIsset(Flow *, uint16_t); int FlowBitIsnotset(Flow *, uint16_t); From a1de7e6dae450923eef68e23e61596eae3e6a795 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 15 Jul 2016 08:14:03 -0600 Subject: [PATCH 1684/2553] flow-vars: remove flow locks Code is now entered under flow lock. --- src/flow-var.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/flow-var.c b/src/flow-var.c index 5262b5a795be..96b3ad3a84ef 100644 --- a/src/flow-var.c +++ b/src/flow-var.c @@ -88,9 +88,7 @@ void FlowVarAddStrNoLock(Flow *f, uint16_t idx, uint8_t *value, uint16_t size) /* add a flowvar to the flow, or update it */ void FlowVarAddStr(Flow *f, uint16_t idx, uint8_t *value, uint16_t size) { - FLOWLOCK_WRLOCK(f); FlowVarAddStrNoLock(f, idx, value, size); - FLOWLOCK_UNLOCK(f); } /* add a flowvar to the flow, or update it */ @@ -117,9 +115,7 @@ void FlowVarAddIntNoLock(Flow *f, uint16_t idx, uint32_t value) /* add a flowvar to the flow, or update it */ void FlowVarAddInt(Flow *f, uint16_t idx, uint32_t value) { - FLOWLOCK_WRLOCK(f); FlowVarAddIntNoLock(f, idx, value); - FLOWLOCK_UNLOCK(f); } void FlowVarFree(FlowVar *fv) From 108d37a52defb8c1298f1bfdf8c3d2c4d8eeef2e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 24 Aug 2016 08:39:39 -0600 Subject: [PATCH 1685/2553] logging: proper failure on memory allocation error unwinds all previous logger allocations --- src/flow-worker.c | 4 +++- src/output.c | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/flow-worker.c b/src/flow-worker.c index 89894c7199b4..f9f7228ed7f9 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -94,7 +94,9 @@ static TmEcode FlowWorkerThreadInit(ThreadVars *tv, void *initdata, void **data) } /* Setup outputs for this thread. */ - OutputLoggerThreadInit(tv, initdata, &fw->output_thread); + if (OutputLoggerThreadInit(tv, initdata, &fw->output_thread) != TM_ECODE_OK) { + return TM_ECODE_FAILED; + } /* setup pq for stream end pkts */ memset(&fw->pq, 0, sizeof(PacketQueue)); diff --git a/src/output.c b/src/output.c index 6c6ee8f805dd..d4dbb7da3f84 100644 --- a/src/output.c +++ b/src/output.c @@ -932,8 +932,7 @@ TmEcode OutputLoggerLog(ThreadVars *tv, Packet *p, void *thread_data) return TM_ECODE_OK; } -TmEcode OutputLoggerThreadInit(ThreadVars *tv, void *initdata, - void **data) +TmEcode OutputLoggerThreadInit(ThreadVars *tv, void *initdata, void **data) { LoggerThreadStore *thread_store = SCCalloc(1, sizeof(*thread_store)); if (thread_store == NULL) { @@ -950,7 +949,12 @@ TmEcode OutputLoggerThreadInit(ThreadVars *tv, void *initdata, if (logger->ThreadInit(tv, initdata, &child_thread_data) == TM_ECODE_OK) { LoggerThreadStoreNode *thread_store_node = SCCalloc(1, sizeof(*thread_store_node)); - BUG_ON(thread_store_node == NULL); + if (thread_store_node == NULL) { + /* Undo everything, calling de-init will take care + * of that. */ + OutputLoggerThreadDeinit(tv, thread_store); + return TM_ECODE_FAILED; + } thread_store_node->thread_data = child_thread_data; TAILQ_INSERT_TAIL(thread_store, thread_store_node, entries); } From bbbc5ab1fcd7cb8b38a3ccb698c92f1439f8cbea Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 12 Sep 2016 10:39:14 -0600 Subject: [PATCH 1686/2553] setup-app-layer-logger.sh: update for logging changes --- scripts/setup-app-layer-logger.sh | 46 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/scripts/setup-app-layer-logger.sh b/scripts/setup-app-layer-logger.sh index 13342412ed94..51f8e6d105f1 100755 --- a/scripts/setup-app-layer-logger.sh +++ b/scripts/setup-app-layer-logger.sh @@ -69,40 +69,35 @@ w EOF } -function patch_suricata_c() { - filename="src/suricata.c" +patch_suricata_common_h() { + filename="src/suricata-common.h" echo "Patching ${filename}." ed -s ${filename} > /dev/null < /dev/null < /dev/null < Date: Mon, 12 Sep 2016 18:15:01 +0200 Subject: [PATCH 1687/2553] decoder-event: BUG_ON on table mismatches Abort when the event enum and the name<>event table are not matching. --- src/decode.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/decode.c b/src/decode.c index 345cb6cdae2e..95504d843db5 100644 --- a/src/decode.c +++ b/src/decode.c @@ -427,13 +427,14 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) StatsRegisterCounter("defrag.ipv6.timeouts", tv); dtv->counter_defrag_max_hit = StatsRegisterCounter("defrag.max_frag_hits", tv); - + int i = 0; for (i = 0; i < DECODE_EVENT_PACKET_MAX; i++) { + BUG_ON(i != (int)DEvents[i].code); dtv->counter_invalid_events[i] = StatsRegisterCounter( DEvents[i].event_name, tv); } - + return; } From b454aa46c6ecaddb382eae401e34c929f8f50887 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 19 Sep 2016 07:47:24 -0600 Subject: [PATCH 1688/2553] defrag: use frag_pkt_too_large instead of frag_too_large The rules were using the wrong decoder event type, which was only set in the unlikely event of a complete overlap, which really had nothing to do with being too large. Remove FRAG_TOO_LARGE as its no longer being used, an overlap event is already set in the case where this event would be set. --- rules/decoder-events.rules | 4 ++-- src/decode-events.c | 4 ++-- src/decode-events.h | 2 -- src/defrag.c | 7 ++----- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/rules/decoder-events.rules b/rules/decoder-events.rules index 95414b74c6dc..73728706055f 100644 --- a/rules/decoder-events.rules +++ b/rules/decoder-events.rules @@ -99,9 +99,9 @@ alert pkthdr any any -> any any (msg:"SURICATA VLAN unknown type"; decode-event: alert pkthdr any any -> any any (msg:"SURICATA VLAN too many layers"; decode-event:vlan.too_many_layers; sid:2200091; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IP raw invalid IP version "; decode-event:ipraw.invalid_ip_version; sid:2200068; rev:1;) -alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv4 Packet size too large"; decode-event:ipv4.frag_too_large; sid:2200069; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv4 Packet size too large"; decode-event:ipv4.frag_pkt_too_large; sid:2200069; rev:2;) alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv4 Fragmentation overlap"; decode-event:ipv4.frag_overlap; sid:2200070; rev:1;) -alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv6 Packet size too large"; decode-event:ipv6.frag_too_large; sid:2200071; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv6 Packet size too large"; decode-event:ipv6.frag_pkt_too_large; sid:2200071; rev:2;) alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv6 Fragmentation overlap"; decode-event:ipv6.frag_overlap; sid:2200072; rev:1;) # checksum rules diff --git a/src/decode-events.c b/src/decode-events.c index a07b44b1d444..e6b330a76cf7 100644 --- a/src/decode-events.c +++ b/src/decode-events.c @@ -152,8 +152,8 @@ const struct DecodeEvents_ DEvents[] = { { "decoder.sctp.pkt_too_small", SCTP_PKT_TOO_SMALL, }, /* Fragmentation reasembly events. */ - { "decoder.ipv4.frag_too_large", IPV4_FRAG_PKT_TOO_LARGE, }, - { "decoder.ipv6.frag_too_large", IPV6_FRAG_PKT_TOO_LARGE, }, + { "decoder.ipv4.frag_pkt_too_large", IPV4_FRAG_PKT_TOO_LARGE, }, + { "decoder.ipv6.frag_pkt_too_large", IPV6_FRAG_PKT_TOO_LARGE, }, { "decoder.ipv4.frag_overlap", IPV4_FRAG_OVERLAP, }, { "decoder.ipv6.frag_overlap", IPV6_FRAG_OVERLAP, }, /* Fragment ignored due to internal error */ diff --git a/src/decode-events.h b/src/decode-events.h index 2d249aba1683..048ac45571fb 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -160,8 +160,6 @@ enum { IPV6_FRAG_PKT_TOO_LARGE, IPV4_FRAG_OVERLAP, IPV6_FRAG_OVERLAP, - IPV4_FRAG_TOO_LARGE, - IPV6_FRAG_TOO_LARGE, /* Fragment ignored due to internal error */ IPV4_FRAG_IGNORED, diff --git a/src/defrag.c b/src/defrag.c index 7004918c77ae..68ac0886e935 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -705,11 +705,8 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, insert: if (data_len - ltrim <= 0) { - if (af == AF_INET) { - ENGINE_SET_EVENT(p, IPV4_FRAG_TOO_LARGE); - } else { - ENGINE_SET_EVENT(p, IPV6_FRAG_TOO_LARGE); - } + /* Full packet has been trimmed due to the overlap policy. Overlap + * already set. */ goto done; } From 7d54d8c590971a9b126d0baf2343f508b1ec09e6 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sat, 23 Jul 2016 21:59:12 +0200 Subject: [PATCH 1689/2553] rule-reload: remember pending USR2 signals We did ignore additional USR2 signals while a rule-reload was running. This changes the counter to be incremented with every additional USR2 signal so we don't ignore them anymore but it's still limited to prevent huge overload or even overflow. --- src/suricata.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/suricata.c b/src/suricata.c index 2bbdb3bffbce..f23820551a4e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -265,7 +265,11 @@ static void SignalHandlerSigterm(/*@unused@*/ int sig) */ static void SignalHandlerSigusr2(int sig) { - sigusr2_count = 1; + if (sigusr2_count < 16) { + sigusr2_count++; + } else { + SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Too many USR2 signals pending, ignoring new ones!"); + } } /** From 15766ce2c4e04b71511a47d8ef9c0368228bb1a8 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 12 Jun 2016 20:55:16 +0200 Subject: [PATCH 1690/2553] configure: set correct cppflags for enabled nfqueue This change sets the correct CPPFLAGS received by PKG_CHECK to resolve building issues with some systems like OpenSuse. --- configure.ac | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure.ac b/configure.ac index d6837d4576f9..39c178d60ca3 100644 --- a/configure.ac +++ b/configure.ac @@ -761,6 +761,10 @@ [ enable_nflog="no"]) AC_ARG_ENABLE(nfqueue, AS_HELP_STRING([--enable-nfqueue], [Enable NFQUEUE support for inline IDP]),[enable_nfqueue=yes],[enable_nfqueue=no]) + if test "$enable_nfqueue" != "no"; then + PKG_CHECK_MODULES([libnetfilter_queue], [libnetfilter_queue], [enable_nfqueue=yes], [enable_nfqueue=no]) + CPPFLAGS="${CPPFLAGS} ${libnetfilter_queue_CFLAGS}" + fi if test "x$enable_nflog" = "xyes" || test "x$enable_nfqueue" = "xyes"; then # libnfnetlink From f6c3845397df717ebf2d0adf6ab917119371b822 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 31 May 2016 14:47:58 +0200 Subject: [PATCH 1691/2553] util-time: new function to know if live or offline --- src/util-time.c | 5 +++++ src/util-time.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/util-time.c b/src/util-time.c index f768ac733db0..40de6b817359 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -90,6 +90,11 @@ void TimeModeSetOffline (void) SCLogDebug("offline time mode enabled"); } +int TimeModeIsLive(void) +{ + return live; +} + void TimeSetByThread(const int thread_id, const struct timeval *tv) { if (live == TRUE) diff --git a/src/util-time.h b/src/util-time.h index 350f8bf4407d..6efce2f7b2f4 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -48,6 +48,7 @@ void TimeSetIncrementTime(uint32_t); void TimeModeSetLive(void); void TimeModeSetOffline (void); +int TimeModeIsLive(void); struct tm *SCLocalTime(time_t timep, struct tm *result); void CreateTimeString (const struct timeval *ts, char *str, size_t size); From f2d1e93e653c9498d810b189d5c106f25f4e08c9 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 31 May 2016 15:02:12 +0200 Subject: [PATCH 1692/2553] unix-socket: add auto mode When running in live mode, the new default 'auto' value of unix-command.enabled causes unix-command to be activated. This will allow users of live capture to benefit from the feature and result in no side effect for user running in offline capture. --- src/counters.c | 5 +---- src/detect-engine.c | 3 +-- src/suricata.c | 4 +--- src/util-conf.c | 28 ++++++++++++++++++++++++++++ src/util-conf.h | 2 ++ suricata.yaml.in | 5 +++-- 6 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/counters.c b/src/counters.c index e40e225778d5..494f3a8f300b 100644 --- a/src/counters.c +++ b/src/counters.c @@ -244,10 +244,7 @@ static void StatsInitCtx(void) /* if the unix command socket is enabled we do the background * stats sync just in case someone runs 'dump-counters' */ - int unix_socket = 0; - if (ConfGetBool("unix-command.enabled", &unix_socket) != 1) - unix_socket = 0; - if (unix_socket == 0) { + if (!ConfUnixSocketIsEnable()) { SCLogWarning(SC_WARN_NO_STATS_LOGGERS, "stats are enabled but no loggers are active"); stats_enabled = FALSE; SCReturn; diff --git a/src/detect-engine.c b/src/detect-engine.c index 9e54604149d9..e108258d9c99 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2090,8 +2090,7 @@ int DetectEngineMultiTenantSetup(void) enum DetectEngineTenantSelectors tenant_selector = TENANT_SELECTOR_UNKNOWN; DetectEngineMasterCtx *master = &g_master_de_ctx; - int unix_socket = 0; - (void)ConfGetBool("unix-command.enabled", &unix_socket); + int unix_socket = ConfUnixSocketIsEnable(); int failure_fatal = 0; (void)ConfGetBool("engine.init-failure-fatal", &failure_fatal); diff --git a/src/suricata.c b/src/suricata.c index f23820551a4e..3853d5bee05d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2520,9 +2520,7 @@ int main(int argc, char **argv) /* In Unix socket runmode, Flow manager is started on demand */ if (suri.run_mode != RUNMODE_UNIX_SOCKET) { /* Spawn the unix socket manager thread */ - int unix_socket = 0; - if (ConfGetBool("unix-command.enabled", &unix_socket) != 1) - unix_socket = 0; + int unix_socket = ConfUnixSocketIsEnable(); if (unix_socket == 1) { UnixManagerThreadSpawn(0); #ifdef BUILD_UNIX_SOCKET diff --git a/src/util-conf.c b/src/util-conf.c index 17f5edfe32aa..0c81178ec5c8 100644 --- a/src/util-conf.c +++ b/src/util-conf.c @@ -91,3 +91,31 @@ ConfNode *ConfFindDeviceConfig(ConfNode *node, const char *iface) return NULL; } + +int ConfUnixSocketIsEnable(void) +{ + char *value; + + if (ConfGet("unix-command.enabled", &value) != 1) { + return 0; + } + + if (!strcmp(value, "auto")) { +#ifdef HAVE_LIBJANSSON +#ifdef OS_WIN32 + return 0; +#else + if (TimeModeIsLive()) { + SCLogInfo("Running in live mode, activating unix socket"); + return 1; + } else { + return 0; + } +#endif +#else + return 0; +#endif + } + + return ConfValIsTrue(value); +} diff --git a/src/util-conf.h b/src/util-conf.h index 4f6399af8e1b..08727567f507 100644 --- a/src/util-conf.h +++ b/src/util-conf.h @@ -33,4 +33,6 @@ TmEcode ConfigCheckLogDirectory(char *log_dir); ConfNode *ConfFindDeviceConfig(ConfNode *node, const char *iface); +int ConfUnixSocketIsEnable(void); + #endif /* __UTIL_UTIL_CONF_H__ */ diff --git a/suricata.yaml.in b/suricata.yaml.in index 351261962770..7f4d075c119e 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -911,10 +911,11 @@ host-mode: auto # Unix command socket can be used to pass commands to suricata. # An external tool can then connect to get information from suricata # or trigger some modifications of the engine. Set enabled to yes -# to activate the feature. You can use the filename variable to set +# to activate the feature. In auto mode, the feature will only be +# activated in live capture mode. You can use the filename variable to set # the file name of the socket. unix-command: - enabled: no + enabled: auto #filename: custom.socket # Magic file. The extension .mgc is added to the value here. From 04faf1a93a80248c6f58268428eb16797a0776e1 Mon Sep 17 00:00:00 2001 From: Tom DeCanio Date: Fri, 16 Sep 2016 05:24:50 -0700 Subject: [PATCH 1693/2553] util-decode-mime: remove quote from boundary= string. remove quote from the end of the boundary= string. This was throwing off the mime parser so that it wouldn't always catch mime boundaries causing things like missed attachments. --- src/util-decode-mime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index 54902551fae1..eb1dcab56659 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -62,7 +62,7 @@ #define CTNT_DISP_STR "content-disposition" #define CTNT_TRAN_STR "content-transfer-encoding" #define MSG_ID_STR "message-id" -#define BND_START_STR "boundary=\"" +#define BND_START_STR "boundary=" #define TOK_END_STR "\"" #define MSG_STR "message/" #define MULTIPART_STR "multipart/" From 215d0d54c7771fdc735bf05302716ebf041e678b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 10 Jun 2016 12:32:25 +0200 Subject: [PATCH 1694/2553] detect: optimize rule address parsing Many rules have the same address vars, so instead of parsing them each time use a hash to store the string and the parsed result. Rules now reference the stored result in the hash table. --- src/detect-engine-address.c | 123 +++++++++++++++++++++++++++++++++++- src/detect-engine-address.h | 7 +- src/detect-engine.c | 3 + src/detect-parse.c | 29 ++++----- src/detect.h | 5 +- src/util-var.c | 2 +- src/util-var.h | 2 +- 7 files changed, 150 insertions(+), 21 deletions(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 8c07d08fc855..60964cd9c837 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -815,7 +815,7 @@ int DetectAddressSetup(DetectAddressHead *gh, char *s) */ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, DetectAddressHead *gh, DetectAddressHead *ghn, - char *s, int negate, ResolvedVariablesList *var_list) + const char *s, int negate, ResolvedVariablesList *var_list) { size_t x = 0; size_t u = 0; @@ -1023,6 +1023,8 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, if (DetectAddressParse2(de_ctx, gh, ghn, temp_rule_var_address, (negate + n_set) % 2, var_list) < 0) { SCLogDebug("DetectAddressParse2 hates us"); + if (temp_rule_var_address != rule_var_address) + SCFree(temp_rule_var_address); goto error; } d_set = 0; @@ -1345,6 +1347,98 @@ int DetectAddressTestConfVars(void) return -1; } +#include "util-hash-lookup3.h" + +typedef struct DetectAddressMap_ { + char *string; + DetectAddressHead *address; +} DetectAddressMap; + +static uint32_t DetectAddressMapHashFunc(HashListTable *ht, void *data, uint16_t datalen) +{ + const DetectAddressMap *map = (DetectAddressMap *)data; + uint32_t hash = 0; + + hash = hashlittle_safe(map->string, strlen(map->string), 0); + hash %= ht->array_size; + + return hash; +} + +static char DetectAddressMapCompareFunc(void *data1, uint16_t len1, void *data2, + uint16_t len2) +{ + DetectAddressMap *map1 = (DetectAddressMap *)data1; + DetectAddressMap *map2 = (DetectAddressMap *)data2; + + + int r = (strcmp(map1->string, map2->string) == 0); + return r; +} + +static void DetectAddressMapFreeFunc(void *data) +{ + DetectAddressMap *map = (DetectAddressMap *)data; + if (map != NULL) { + DetectAddressHeadFree(map->address); + SCFree(map->string); + } + SCFree(map); +} + +int DetectAddressMapInit(DetectEngineCtx *de_ctx) +{ + de_ctx->address_table = HashListTableInit(4096, DetectAddressMapHashFunc, + DetectAddressMapCompareFunc, + DetectAddressMapFreeFunc); + if (de_ctx->address_table == NULL) + return -1; + + return 0; +} + +void DetectAddressMapFree(DetectEngineCtx *de_ctx) +{ + if (de_ctx->address_table == NULL) + return; + + HashListTableFree(de_ctx->address_table); + de_ctx->address_table = NULL; + return; +} + +int DetectAddressMapAdd(DetectEngineCtx *de_ctx, const char *string, + DetectAddressHead *address) +{ + DetectAddressMap *map = SCCalloc(1, sizeof(*map)); + if (map == NULL) + return -1; + + map->string = SCStrdup(string); + if (map->string == NULL) { + SCFree(map); + return -1; + } + map->address = address; + + BUG_ON(HashListTableAdd(de_ctx->address_table, (void *)map, 0) != 0); + return 0; +} + +const DetectAddressHead *DetectAddressMapLookup(DetectEngineCtx *de_ctx, + const char *string) +{ + DetectAddressMap map = { (char *)string, NULL }; + + const DetectAddressMap *res = HashListTableLookup(de_ctx->address_table, + &map, 0); + if (res == NULL) + return NULL; + else { + return (const DetectAddressHead *)res->address; + } +} + /** * \brief Parses an address group sent as a character string and updates the * DetectAddressHead sent as the argument with the relevant address @@ -1358,7 +1452,7 @@ int DetectAddressTestConfVars(void) * \retval -1 On failure. */ int DetectAddressParse(const DetectEngineCtx *de_ctx, - DetectAddressHead *gh, char *str) + DetectAddressHead *gh, const char *str) { int r; DetectAddressHead *ghn = NULL; @@ -1401,6 +1495,31 @@ int DetectAddressParse(const DetectEngineCtx *de_ctx, return -1; } +const DetectAddressHead *DetectParseAddress(DetectEngineCtx *de_ctx, + const char *string) +{ + const DetectAddressHead *h = DetectAddressMapLookup(de_ctx, string); + if (h != NULL) { + SCLogDebug("found: %s :: %p", string, h); + return h; + } + + SCLogDebug("%s not found", string); + + DetectAddressHead *head = DetectAddressHeadInit(); + if (head == NULL) + return NULL; + + if (DetectAddressParse(de_ctx, head, string) == -1) + { + DetectAddressHeadFree(head); + return NULL; + } + + DetectAddressMapAdd((DetectEngineCtx *)de_ctx, string, head); + return head; +} + /** * \brief Returns a new instance of DetectAddressHead. * diff --git a/src/detect-engine-address.h b/src/detect-engine-address.h index 3b84f2257703..dcbde2e4277b 100644 --- a/src/detect-engine-address.h +++ b/src/detect-engine-address.h @@ -32,7 +32,7 @@ void DetectAddressHeadFree(DetectAddressHead *); void DetectAddressHeadCleanup(DetectAddressHead *); int DetectAddressParseString(DetectAddress *, char *); -int DetectAddressParse(const DetectEngineCtx *, DetectAddressHead *, char *); +int DetectAddressParse(const DetectEngineCtx *, DetectAddressHead *, const char *); DetectAddress *DetectAddressInit(void); void DetectAddressFree(DetectAddress *); @@ -59,4 +59,9 @@ int DetectAddressTestConfVars(void); void DetectAddressTests(void); +int DetectAddressMapInit(DetectEngineCtx *de_ctx); +void DetectAddressMapFree(DetectEngineCtx *de_ctx); +const DetectAddressHead *DetectParseAddress(DetectEngineCtx *de_ctx, + const char *string); + #endif /* __DETECT_ADDRESS_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index e108258d9c99..d7aee2242a04 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -854,6 +854,7 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) ThresholdHashInit(de_ctx); VariableNameInitHash(de_ctx); DetectParseDupSigHashInit(de_ctx); + DetectAddressMapInit(de_ctx); /* init iprep... ignore errors for now */ (void)SRepInit(de_ctx); @@ -964,6 +965,8 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) DetectEngineCtxFreeThreadKeywordData(de_ctx); SRepDestroy(de_ctx); + DetectAddressMapFree(de_ctx); + /* if we have a config prefix, remove the config from the tree */ if (strlen(de_ctx->config_prefix) > 0) { /* remove config */ diff --git a/src/detect-parse.c b/src/detect-parse.c index f78b6033c78b..9e970e38963c 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -624,7 +624,7 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, * * \retval 0 ok, -1 error */ -int SigParseAddress(const DetectEngineCtx *de_ctx, +static int SigParseAddress(DetectEngineCtx *de_ctx, Signature *s, const char *addrstr, char flag) { SCLogDebug("Address Group \"%s\" to be parsed now", addrstr); @@ -634,13 +634,15 @@ int SigParseAddress(const DetectEngineCtx *de_ctx, if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_SRC_ANY; - if (DetectAddressParse(de_ctx, &s->src, (char *)addrstr) < 0) + s->src = DetectParseAddress(de_ctx, addrstr); + if (s->src == NULL) goto error; } else { if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_DST_ANY; - if (DetectAddressParse(de_ctx, &s->dst, (char *)addrstr) < 0) + s->dst = DetectParseAddress(de_ctx, addrstr); + if (s->dst == NULL) goto error; } @@ -808,7 +810,7 @@ int SigParseAction(Signature *s, const char *action) * \internal * \brief split a signature string into a few blocks for further parsing */ -static int SigParseBasics(const DetectEngineCtx *de_ctx, +static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr, SignatureParser *parser, uint8_t addrs_direction) { #define MAX_SUBSTRINGS 30 @@ -1018,9 +1020,6 @@ void SigFree(Signature *s) } SigMatchFreeArrays(s); - DetectAddressHeadCleanup(&s->src); - DetectAddressHeadCleanup(&s->dst); - if (s->sp != NULL) { DetectPortCleanupList(s->sp); } @@ -1060,7 +1059,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* source addresses */ uint16_t cnt = 0; uint16_t idx = 0; - DetectAddress *da = s->src.ipv4_head; + DetectAddress *da = s->src->ipv4_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1070,7 +1069,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->src.ipv4_head; da != NULL; da = da->next) { + for (da = s->src->ipv4_head; da != NULL; da = da->next) { s->addr_src_match4[idx].ip = ntohl(da->ip.addr_data32[0]); s->addr_src_match4[idx].ip2 = ntohl(da->ip2.addr_data32[0]); idx++; @@ -1081,7 +1080,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* destination addresses */ cnt = 0; idx = 0; - da = s->dst.ipv4_head; + da = s->dst->ipv4_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1091,7 +1090,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->dst.ipv4_head; da != NULL; da = da->next) { + for (da = s->dst->ipv4_head; da != NULL; da = da->next) { s->addr_dst_match4[idx].ip = ntohl(da->ip.addr_data32[0]); s->addr_dst_match4[idx].ip2 = ntohl(da->ip2.addr_data32[0]); idx++; @@ -1102,7 +1101,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* source addresses IPv6 */ cnt = 0; idx = 0; - da = s->src.ipv6_head; + da = s->src->ipv6_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1112,7 +1111,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->src.ipv6_head; da != NULL; da = da->next) { + for (da = s->src->ipv6_head; da != NULL; da = da->next) { s->addr_src_match6[idx].ip[0] = ntohl(da->ip.addr_data32[0]); s->addr_src_match6[idx].ip[1] = ntohl(da->ip.addr_data32[1]); s->addr_src_match6[idx].ip[2] = ntohl(da->ip.addr_data32[2]); @@ -1129,7 +1128,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* destination addresses IPv6 */ cnt = 0; idx = 0; - da = s->dst.ipv6_head; + da = s->dst->ipv6_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1139,7 +1138,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->dst.ipv6_head; da != NULL; da = da->next) { + for (da = s->dst->ipv6_head; da != NULL; da = da->next) { s->addr_dst_match6[idx].ip[0] = ntohl(da->ip.addr_data32[0]); s->addr_dst_match6[idx].ip[1] = ntohl(da->ip.addr_data32[1]); s->addr_dst_match6[idx].ip[2] = ntohl(da->ip.addr_data32[2]); diff --git a/src/detect.h b/src/detect.h index 807dcafc2cf3..e0f555674b68 100644 --- a/src/detect.h +++ b/src/detect.h @@ -425,7 +425,7 @@ typedef struct Signature_ { DetectReference *references; /** address settings for this signature */ - DetectAddressHead src, dst; + const DetectAddressHead *src, *dst; /* used at init to determine max dsize */ SigMatch *dsize_sm; @@ -677,6 +677,9 @@ typedef struct DetectEngineCtx_ { DetectPort *tcp_whitelist; DetectPort *udp_whitelist; + /** table for storing the string representation with the parsers result */ + HashListTable *address_table; + } DetectEngineCtx; /* Engine groups profiles (low, medium, high, custom) */ diff --git a/src/util-var.c b/src/util-var.c index 40d4f7f31e83..dd7bbc132d91 100644 --- a/src/util-var.c +++ b/src/util-var.c @@ -130,7 +130,7 @@ void GenericVarRemove(GenericVar **list, GenericVar *gv) } // Checks if a variable is already in a resolve list and if it's not, adds it. -int AddVariableToResolveList(ResolvedVariablesList *list, char *var) +int AddVariableToResolveList(ResolvedVariablesList *list, const char *var) { ResolvedVariable *p_item; diff --git a/src/util-var.h b/src/util-var.h index dc284725ffa2..b95b59fd2b25 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -70,7 +70,7 @@ void GenericVarFree(GenericVar *); void GenericVarAppend(GenericVar **, GenericVar *); void GenericVarRemove(GenericVar **, GenericVar *); -int AddVariableToResolveList(ResolvedVariablesList *list, char *var); +int AddVariableToResolveList(ResolvedVariablesList *list, const char *var); void CleanVariableResolveList(ResolvedVariablesList *var_list); #endif /* __UTIL_VAR_H__ */ From f1117ba2dcdf5ef4a8fcd6ec010b6ea1bb98622f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 10 Jun 2016 15:49:21 +0200 Subject: [PATCH 1695/2553] iponly: fix unittests --- src/detect-engine-iponly.c | 98 +++++++++++++------------------------- 1 file changed, 32 insertions(+), 66 deletions(-) diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index b19d1cb6c56a..11346a40f687 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -1561,25 +1561,17 @@ void IPOnlyAddSignature(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx, static int IPOnlyTestSig01(void) { - int result = 0; - DetectEngineCtx de_ctx; - - memset(&de_ctx, 0, sizeof(DetectEngineCtx)); - - de_ctx.flags |= DE_QUIET; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(&de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-01 sig is IPOnly \"; sid:400001; rev:1;)"); - if (s == NULL) { - goto end; - } - if(SignatureIsIPOnly(&de_ctx, s)) - result = 1; - else - printf("expected a IPOnly signature: "); + Signature *s = SigInit(de_ctx,"alert tcp any any -> any any (sid:400001; rev:1;)"); + FAIL_IF(s == NULL); + FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0); SigFree(s); -end: - return result; + DetectEngineCtxFree(de_ctx); + PASS; } /** @@ -1589,27 +1581,17 @@ static int IPOnlyTestSig01(void) static int IPOnlyTestSig02 (void) { - int result = 0; - DetectEngineCtx de_ctx; - memset (&de_ctx, 0, sizeof(DetectEngineCtx)); - - memset(&de_ctx, 0, sizeof(DetectEngineCtx)); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + de_ctx->flags |= DE_QUIET; - de_ctx.flags |= DE_QUIET; - - Signature *s = SigInit(&de_ctx,"alert tcp any any -> any 80 (msg:\"SigTest40-02 sig is not IPOnly \"; sid:400001; rev:1;)"); - if (s == NULL) { - goto end; - } - if ((SignatureIsIPOnly(&de_ctx, s))) - result = 1; - else - printf("got a non-IPOnly signature: "); + Signature *s = SigInit(de_ctx,"alert tcp any any -> any 80 (sid:400001; rev:1;)"); + FAIL_IF(s == NULL); + FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0); SigFree(s); - -end: - return result; + DetectEngineCtxFree(de_ctx); + PASS; } /** @@ -2119,52 +2101,36 @@ int IPOnlyTestSig12(void) static int IPOnlyTestSig13(void) { - int result = 0; - DetectEngineCtx de_ctx; - - memset(&de_ctx, 0, sizeof(DetectEngineCtx)); - - de_ctx.flags |= DE_QUIET; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(&de_ctx, + Signature *s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; " "flowbits:set,myflow1; sid:1; rev:1;)"); - if (s == NULL) { - goto end; - } - if (SignatureIsIPOnly(&de_ctx, s)) - result = 1; - else - printf("expected a IPOnly signature: "); + FAIL_IF(s == NULL); + FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0); SigFree(s); -end: - return result; + DetectEngineCtxFree(de_ctx); + PASS; } static int IPOnlyTestSig14(void) { - int result = 0; - DetectEngineCtx de_ctx; - - memset(&de_ctx, 0, sizeof(DetectEngineCtx)); - - de_ctx.flags |= DE_QUIET; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(&de_ctx, + Signature *s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; " "flowbits:set,myflow1; flowbits:isset,myflow2; sid:1; rev:1;)"); - if (s == NULL) { - goto end; - } - if (SignatureIsIPOnly(&de_ctx, s)) - printf("expected a IPOnly signature: "); - else - result = 1; + FAIL_IF(s == NULL); + FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 1); SigFree(s); -end: - return result; + DetectEngineCtxFree(de_ctx); + PASS; } int IPOnlyTestSig15(void) From 9b2717799cc4eaa86e1c8d81be451e009961d822 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 21 Jul 2016 09:24:40 +0200 Subject: [PATCH 1696/2553] tls: add (mpm) keyword tls_cert_issuer This keyword is a replacement for tls.issuerdn. --- src/Makefile.am | 1 + src/detect-engine-analyzer.c | 2 + src/detect-engine-content-inspection.h | 1 + src/detect-engine-mpm.c | 4 +- src/detect-engine-state.h | 5 +- src/detect-engine-tls.c | 99 ++++++++++++++++++++++++ src/detect-engine-tls.h | 5 ++ src/detect-engine.c | 9 +++ src/detect-fast-pattern.c | 9 ++- src/detect-parse.c | 4 + src/detect-tls-cert-issuer.c | 101 +++++++++++++++++++++++++ src/detect-tls-cert-issuer.h | 33 ++++++++ src/detect.c | 14 ++++ src/detect.h | 9 ++- src/suricata-common.h | 1 + src/util-profiling.c | 1 + 16 files changed, 290 insertions(+), 8 deletions(-) create mode 100644 src/detect-tls-cert-issuer.c create mode 100644 src/detect-tls-cert-issuer.h diff --git a/src/Makefile.am b/src/Makefile.am index be200cb6289a..37a134cd1f78 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -88,6 +88,7 @@ detect-detection-filter.c detect-detection-filter.h \ detect-distance.c detect-distance.h \ detect-dns-query.c detect-dns-query.h \ detect-tls-sni.c detect-tls-sni.h \ +detect-tls-cert-issuer.c detect-tls-cert-issuer.h \ detect-dsize.c detect-dsize.h \ detect-engine-address.c detect-engine-address.h \ detect-engine-address-ipv4.c detect-engine-address-ipv4.h \ diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index ade8ec0946ec..b6bbc86140c4 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -480,6 +480,8 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "dns query name content"); else if (list_type == DETECT_SM_LIST_TLSSNI_MATCH) fprintf(rule_engine_analysis_FD, "tls sni extension content"); + else if (list_type == DETECT_SM_LIST_TLSISSUER_MATCH) + fprintf(rule_engine_analysis_FD, "tls issuer content"); fprintf(rule_engine_analysis_FD, "\" buffer.\n"); diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 7636fdf2c0d5..9402a66fd86d 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -50,6 +50,7 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSNI, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSISSUER, DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, DETECT_ENGINE_CONTENT_INSPECTION_MODE_BASE64, DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index be02ed57d7a2..aadb35994109 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -107,6 +107,7 @@ AppLayerMpms app_mpms[] = { { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, SIG_GROUP_HEAD_MPM_DNSQUERY, 17}, { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, SIG_GROUP_HEAD_MPM_TLSSNI, 18}, + { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, SIG_GROUP_HEAD_MPM_TLSISSUER, 19}, { NULL, 0, 0, 0, 0, 0, } }; @@ -1220,8 +1221,9 @@ void MpmStoreFixup(SigGroupHead *sgh) SET_TS(sgh, sgh->mpm_dnsquery_ctx_ts); SET_TS(sgh, sgh->mpm_tlssni_ctx_ts); + SET_TC(sgh, sgh->mpm_tlsissuer_ctx_ts); - BUG_ON(APP_MPMS_MAX != 19 || i != 19); + BUG_ON(APP_MPMS_MAX != 20 || i != 20); #undef SET_TS #undef SET_TC diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index dcbbc9c499ed..903920b353ee 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -88,8 +88,9 @@ #define DE_STATE_FLAG_DNSREQUEST_INSPECT BIT_U32(22) #define DE_STATE_FLAG_DNSRESPONSE_INSPECT BIT_U32(23) #define DE_STATE_FLAG_TLSSNI_INSPECT BIT_U32(24) -#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(25) -#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(26) +#define DE_STATE_FLAG_TLSISSUER_INSPECT BIT_U32(25) +#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(26) +#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(27) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 2cac96a01ce7..91e3ed20046a 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -143,3 +143,102 @@ int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, return cnt; } + +/** + * \brief TLS issuer match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx + * \param hrh Buffer to inspect + * \param hrh_len Buffer length + * \param flags Flags + * + * \retval ret Number of matches + */ +static inline uint32_t TlsIssuerPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *buffer, + const uint32_t buffer_len, + const uint8_t flags) +{ + SCEnter(); + + uint32_t ret = 0; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOSERVER); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_tlsissuer_ctx_ts == NULL); + + if (buffer_len >= det_ctx->sgh->mpm_tlsissuer_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_tlsissuer_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_tlsissuer_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); + } + + SCReturnUInt(ret); +} + +/** + * \brief Run the pattern matcher against the TLS issuer buffer + * + * \param det_ctx Detection engine thread ctx + * \param f Locked flow + * \param dns_state Initialized dns state + * \param flags Flags + * + * \retval cnt Number of matches + */ +uint32_t DetectTlsIssuerInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, + SSLState *ssl_state, uint8_t flags) +{ + SCEnter(); + + uint8_t *buffer; + uint32_t buffer_len; + uint32_t cnt = 0; + + if (ssl_state->server_connp.cert0_issuerdn == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->server_connp.cert0_issuerdn; + buffer_len = strlen(ssl_state->server_connp.cert0_issuerdn); + + cnt = TlsIssuerPatternSearch(det_ctx, buffer, buffer_len, flags); + + SCReturnUInt(cnt); +} + +/** \brief Do the content inspection and validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags App layer flags + * \param state App layer state + * + * \retval 0 No match + * \retval 1 Match + */ +int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, + Flow *f, uint8_t flags, void *alstate, void *txv, + uint64_t tx_id) +{ + uint8_t *buffer; + uint16_t buffer_len; + int cnt = 0; + + SSLState *ssl_state = (SSLState *)alstate; + + if (ssl_state->server_connp.cert0_issuerdn == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->server_connp.cert0_issuerdn; + buffer_len = strlen(ssl_state->server_connp.cert0_issuerdn); + + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_TLSISSUER_MATCH], + f, buffer, buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSISSUER, NULL); + + return cnt; +} diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h index 3a9d530f0c9f..b10d2a400086 100644 --- a/src/detect-engine-tls.h +++ b/src/detect-engine-tls.h @@ -28,4 +28,9 @@ int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); +int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); + #endif /* __DETECT_ENGINE_TLS_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index d7aee2242a04..1b2cd0c9c0e6 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -364,6 +364,13 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_DNSRESPONSE_INSPECT, 1, DetectEngineInspectDnsResponse }, + /* TLS */ + { IPPROTO_TCP, + ALPROTO_TLS, + DETECT_SM_LIST_TLSISSUER_MATCH, + DE_STATE_FLAG_TLSISSUER_INSPECT, + 1, + DetectEngineInspectTlsIssuer }, /* specifically for UDP, register again * allows us to use the alproto w/o translation * in the detection engine */ @@ -2741,6 +2748,8 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_TLSSNI_MATCH: return "tls sni extension"; + case DETECT_SM_LIST_TLSISSUER_MATCH: + return "tls issuer"; case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index dc7d94c64e09..55ceb6fa0c4f 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -137,6 +137,7 @@ void SupportFastPatternForSigMatchTypes(void) SupportFastPatternForSigMatchList(DETECT_SM_LIST_DNSQUERYNAME_MATCH, 2); SupportFastPatternForSigMatchList(DETECT_SM_LIST_TLSSNI_MATCH, 2); + SupportFastPatternForSigMatchList(DETECT_SM_LIST_TLSISSUER_MATCH, 2); #if 0 SCFPSupportSMList *tmp = sm_fp_support_smlist_list; @@ -205,7 +206,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH] == NULL) { + s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH] == NULL && + s->sm_lists_tail[DETECT_SM_LIST_TLSISSUER_MATCH] == NULL) { SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " "rule, without a preceding content based keyword. " "Currently we provide fast_pattern support for content, " @@ -213,7 +215,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a "http_raw_header, http_method, http_cookie, " "http_raw_uri, http_stat_msg, http_stat_code, " "http_user_agent, http_host, http_raw_host, " - "dns_query or tls_sni option"); + "dns_query, tls_sni or tls_cert_issuer option"); return -1; } @@ -233,7 +235,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSISSUER_MATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " "the rule, without a content context. Please use a " diff --git a/src/detect-parse.c b/src/detect-parse.c index 9e970e38963c..8b8158b5c57e 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -165,6 +165,7 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_DNSRESPONSE_MATCH, "dns_response"); CASE_CODE_STRING(DETECT_SM_LIST_DNSQUERYNAME_MATCH, "dns_query"); CASE_CODE_STRING(DETECT_SM_LIST_TLSSNI_MATCH, "tls_sni"); + CASE_CODE_STRING(DETECT_SM_LIST_TLSISSUER_MATCH, "tls_cert_issuer"); CASE_CODE_STRING(DETECT_SM_LIST_MODBUS_MATCH, "modbus"); CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); @@ -206,6 +207,7 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_DNSRESPONSE_MATCH); CASE_CODE(DETECT_SM_LIST_DNSQUERYNAME_MATCH); CASE_CODE(DETECT_SM_LIST_TLSSNI_MATCH); + CASE_CODE(DETECT_SM_LIST_TLSISSUER_MATCH); CASE_CODE(DETECT_SM_LIST_MODBUS_MATCH); CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); CASE_CODE(DETECT_SM_LIST_POSTMATCH); @@ -1559,6 +1561,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, /* TLS */ if (sig->sm_lists[DETECT_SM_LIST_TLSSNI_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_TLSISSUER_MATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_MODBUS_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c new file mode 100644 index 000000000000..0a9702f31308 --- /dev/null +++ b/src/detect-tls-cert-issuer.c @@ -0,0 +1,101 @@ +/* Copyright (C) 2007-2016 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 Mats Klepsland + * + * Implements support for tls_cert_issuer keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-spm.h" +#include "util-print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-ssl.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static int DetectTlsIssuerSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTlsIssuerRegisterTests(void); + +/** + * \brief Registration function for keyword: tls_cert_issuer + */ +void DetectTlsIssuerRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].name = "tls_cert_issuer"; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].desc = "content modifier to match specifically and only on the TLS cert issuer buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Match = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Setup = DetectTlsIssuerSetup; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Free = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].RegisterTests = DetectTlsIssuerRegisterTests; + + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_PAYLOAD; +} + + +/** + * \brief this function setup the tls_cert_issuer modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectTlsIssuerSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + s->list = DETECT_SM_LIST_TLSISSUER_MATCH; + s->alproto = ALPROTO_TLS; + return 0; +} + +#ifdef UNITTESTS + /* TODO add unit tests */ +#endif + +static void DetectTlsIssuerRegisterTests(void) +{ +#ifdef UNITTESTS + /* TODO add unit tests */ +#endif +} diff --git a/src/detect-tls-cert-issuer.h b/src/detect-tls-cert-issuer.h new file mode 100644 index 000000000000..8febf749f14e --- /dev/null +++ b/src/detect-tls-cert-issuer.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2016 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 Mats Klepsland + */ + +#ifndef __DETECT_TLS_ISSUER_H__ +#define __DETECT_TLS_ISSUER_H__ + +#include "app-layer-ssl.h" + +void DetectTlsIssuerRegister(void); +uint32_t DetectTlsIssuerInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, + SSLState *ssl_state, uint8_t flags); + +#endif /* __DETECT_TLS_ISSUER_H__ */ diff --git a/src/detect.c b/src/detect.c index b1d1c6d5a7bc..1c0640dc7a67 100644 --- a/src/detect.c +++ b/src/detect.c @@ -49,6 +49,7 @@ #include "detect-engine-uri.h" #include "detect-dns-query.h" #include "detect-tls-sni.h" +#include "detect-tls-cert-issuer.h" #include "detect-engine-state.h" #include "detect-engine-analyzer.h" #include "detect-engine-filedata-smtp.h" @@ -1039,6 +1040,18 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectTlsSniInspectMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSNI); } + } else if (p->flowflags & FLOW_PKT_TOCLIENT) { + if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSISSUER) { + void *alstate = FlowGetAppState(p->flow); + if (alstate == NULL) { + SCLogDebug("no alstate"); + return; + } + + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSISSUER); + DetectTlsIssuerInspectMpm(det_ctx, p->flow, alstate, flags); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSISSUER); + } } } else if (alproto == ALPROTO_SMTP && has_state) { if (p->flowflags & FLOW_PKT_TOSERVER) { @@ -4374,6 +4387,7 @@ void SigTableSetup(void) DetectIPRepRegister(); DetectDnsQueryRegister(); DetectTlsSniRegister(); + DetectTlsIssuerRegister(); DetectModbusRegister(); DetectAppLayerProtocolRegister(); DetectBase64DecodeRegister(); diff --git a/src/detect.h b/src/detect.h index e0f555674b68..09d5bac6f135 100644 --- a/src/detect.h +++ b/src/detect.h @@ -125,6 +125,7 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_DNSQUERYNAME_MATCH, /**< per query in a tx list */ DETECT_SM_LIST_TLSSNI_MATCH, + DETECT_SM_LIST_TLSISSUER_MATCH, DETECT_SM_LIST_MODBUS_MATCH, @@ -936,9 +937,10 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_HAVEFILESIZE (1 << 22) #define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 23) #define SIG_GROUP_HEAD_MPM_TLSSNI (1 << 24) -#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 25) +#define SIG_GROUP_HEAD_MPM_TLSISSUER (1 << 25) +#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 26) -#define APP_MPMS_MAX 19 +#define APP_MPMS_MAX 20 enum MpmBuiltinBuffers { MPMB_TCP_PKT_TS, @@ -1017,6 +1019,7 @@ typedef struct SigGroupHead_ { const MpmCtx *mpm_hrhhd_ctx_ts; const MpmCtx *mpm_dnsquery_ctx_ts; const MpmCtx *mpm_tlssni_ctx_ts; + const MpmCtx *mpm_tlsissuer_ctx_ts; const MpmCtx *mpm_smtp_filedata_ctx_ts; }; struct { @@ -1218,6 +1221,8 @@ enum { DETECT_AL_DNS_QUERY, DETECT_AL_TLS_SNI, + DETECT_AL_TLS_CERT_ISSUER, + DETECT_AL_TLS_CERT_SUBJECT, DETECT_AL_MODBUS, DETECT_XBITS, diff --git a/src/suricata-common.h b/src/suricata-common.h index fedccf31ceb0..4b6ec9694be6 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -328,6 +328,7 @@ typedef enum PacketProfileDetectId_ { PROF_DETECT_MPM_HRHHD, PROF_DETECT_MPM_DNSQUERY, PROF_DETECT_MPM_TLSSNI, + PROF_DETECT_MPM_TLSISSUER, PROF_DETECT_IPONLY, PROF_DETECT_RULES, PROF_DETECT_STATEFUL, diff --git a/src/util-profiling.c b/src/util-profiling.c index 5f6aa2066079..ec09cbdc4827 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1226,6 +1226,7 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id) CASE_CODE (PROF_DETECT_MPM_HUAD); CASE_CODE (PROF_DETECT_MPM_DNSQUERY); CASE_CODE (PROF_DETECT_MPM_TLSSNI); + CASE_CODE (PROF_DETECT_MPM_TLSISSUER); CASE_CODE (PROF_DETECT_IPONLY); CASE_CODE (PROF_DETECT_RULES); CASE_CODE (PROF_DETECT_PREFILTER); From 4172c4c8acbb94a9f2e4ca6614cd03aef77a7b67 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 21 Jul 2016 10:28:33 +0200 Subject: [PATCH 1697/2553] tls: add (mpm) keyword tls_cert_subject This keyword is a replacement for tls.subject. --- src/Makefile.am | 1 + src/detect-engine-analyzer.c | 2 + src/detect-engine-content-inspection.h | 1 + src/detect-engine-mpm.c | 4 +- src/detect-engine-state.h | 5 +- src/detect-engine-tls.c | 99 ++++++++++++++++++++++++ src/detect-engine-tls.h | 5 ++ src/detect-engine.c | 8 ++ src/detect-fast-pattern.c | 11 ++- src/detect-parse.c | 4 + src/detect-tls-cert-subject.c | 100 +++++++++++++++++++++++++ src/detect-tls-cert-subject.h | 33 ++++++++ src/detect.c | 25 ++++--- src/detect.h | 7 +- src/suricata-common.h | 1 + src/util-profiling.c | 1 + 16 files changed, 286 insertions(+), 21 deletions(-) create mode 100644 src/detect-tls-cert-subject.c create mode 100644 src/detect-tls-cert-subject.h diff --git a/src/Makefile.am b/src/Makefile.am index 37a134cd1f78..b941a09e91ec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -89,6 +89,7 @@ detect-distance.c detect-distance.h \ detect-dns-query.c detect-dns-query.h \ detect-tls-sni.c detect-tls-sni.h \ detect-tls-cert-issuer.c detect-tls-cert-issuer.h \ +detect-tls-cert-subject.c detect-tls-cert-subject.h \ detect-dsize.c detect-dsize.h \ detect-engine-address.c detect-engine-address.h \ detect-engine-address-ipv4.c detect-engine-address-ipv4.h \ diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index b6bbc86140c4..2933c0a6d218 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -482,6 +482,8 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "tls sni extension content"); else if (list_type == DETECT_SM_LIST_TLSISSUER_MATCH) fprintf(rule_engine_analysis_FD, "tls issuer content"); + else if (list_type == DETECT_SM_LIST_TLSSUBJECT_MATCH) + fprintf(rule_engine_analysis_FD, "tls subject content"); fprintf(rule_engine_analysis_FD, "\" buffer.\n"); diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 9402a66fd86d..3fc4b451e9f3 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -51,6 +51,7 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSNI, DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSISSUER, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSUBJECT, DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, DETECT_ENGINE_CONTENT_INSPECTION_MODE_BASE64, DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index aadb35994109..f078d6d1e3f0 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -108,6 +108,7 @@ AppLayerMpms app_mpms[] = { { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, SIG_GROUP_HEAD_MPM_TLSSNI, 18}, { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, SIG_GROUP_HEAD_MPM_TLSISSUER, 19}, + { "tls_cert_subject", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSSUBJECT_MATCH, SIG_GROUP_HEAD_MPM_TLSSUBJECT, 20}, { NULL, 0, 0, 0, 0, 0, } }; @@ -1222,8 +1223,9 @@ void MpmStoreFixup(SigGroupHead *sgh) SET_TS(sgh, sgh->mpm_tlssni_ctx_ts); SET_TC(sgh, sgh->mpm_tlsissuer_ctx_ts); + SET_TC(sgh, sgh->mpm_tlssubject_ctx_ts); - BUG_ON(APP_MPMS_MAX != 20 || i != 20); + BUG_ON(APP_MPMS_MAX != 21 || i != 21); #undef SET_TS #undef SET_TC diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 903920b353ee..7757ce89538f 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -89,8 +89,9 @@ #define DE_STATE_FLAG_DNSRESPONSE_INSPECT BIT_U32(23) #define DE_STATE_FLAG_TLSSNI_INSPECT BIT_U32(24) #define DE_STATE_FLAG_TLSISSUER_INSPECT BIT_U32(25) -#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(26) -#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(27) +#define DE_STATE_FLAG_TLSSUBJECT_INSPECT BIT_U32(26) +#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(27) +#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(28) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 91e3ed20046a..1d3e8641b92e 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -242,3 +242,102 @@ int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, return cnt; } + +/** + * \brief TLS subject match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx + * \param hrh Buffer to inspect + * \param hrh_len Buffer length + * \param flags Flags + * + * \retval ret Number of matches + */ +static inline uint32_t TlsSubjectPatternSearch(DetectEngineThreadCtx *det_ctx, + const uint8_t *buffer, + const uint32_t buffer_len, + const uint8_t flags) +{ + SCEnter(); + + uint32_t ret = 0; + + DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOSERVER); + DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_tlssubject_ctx_ts == NULL); + + if (buffer_len >= det_ctx->sgh->mpm_tlssubject_ctx_ts->minlen) { + ret = mpm_table[det_ctx->sgh->mpm_tlssubject_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_tlssubject_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); + } + + SCReturnUInt(ret); +} + +/** + * \brief Run the pattern matcher against the TLS subject buffer + * + * \param det_ctx Detection engine thread ctx + * \param f Locked flow + * \param dns_state Initialized dns state + * \param flags Flags + * + * \retval cnt Number of matches + */ +uint32_t DetectTlsSubjectInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, + SSLState *ssl_state, uint8_t flags) +{ + SCEnter(); + + uint8_t *buffer; + uint32_t buffer_len; + uint32_t cnt = 0; + + if (ssl_state->server_connp.cert0_subject == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->server_connp.cert0_subject; + buffer_len = strlen(ssl_state->server_connp.cert0_subject); + + cnt = TlsSubjectPatternSearch(det_ctx, buffer, buffer_len, flags); + + SCReturnUInt(cnt); +} + +/** \brief Do the content inspection and validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags App layer flags + * \param state App layer state + * + * \retval 0 No match + * \retval 1 Match + */ +int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, + Flow *f, uint8_t flags, void *alstate, void *txv, + uint64_t tx_id) +{ + uint8_t *buffer; + uint16_t buffer_len; + int cnt = 0; + + SSLState *ssl_state = (SSLState *)alstate; + + if (ssl_state->server_connp.cert0_subject == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->server_connp.cert0_subject; + buffer_len = strlen(ssl_state->server_connp.cert0_subject); + + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_TLSSUBJECT_MATCH], + f, buffer, buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSUBJECT, NULL); + + return cnt; +} diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h index b10d2a400086..547b63761379 100644 --- a/src/detect-engine-tls.h +++ b/src/detect-engine-tls.h @@ -33,4 +33,9 @@ int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); +int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); + #endif /* __DETECT_ENGINE_TLS_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 1b2cd0c9c0e6..a6fefbd155d7 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -371,6 +371,12 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_TLSISSUER_INSPECT, 1, DetectEngineInspectTlsIssuer }, + { IPPROTO_TCP, + ALPROTO_TLS, + DETECT_SM_LIST_TLSSUBJECT_MATCH, + DE_STATE_FLAG_TLSSUBJECT_INSPECT, + 1, + DetectEngineInspectTlsSubject }, /* specifically for UDP, register again * allows us to use the alproto w/o translation * in the detection engine */ @@ -2750,6 +2756,8 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "tls sni extension"; case DETECT_SM_LIST_TLSISSUER_MATCH: return "tls issuer"; + case DETECT_SM_LIST_TLSSUBJECT_MATCH: + return "tls subject"; case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 55ceb6fa0c4f..b2e569416759 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -138,6 +138,7 @@ void SupportFastPatternForSigMatchTypes(void) SupportFastPatternForSigMatchList(DETECT_SM_LIST_TLSSNI_MATCH, 2); SupportFastPatternForSigMatchList(DETECT_SM_LIST_TLSISSUER_MATCH, 2); + SupportFastPatternForSigMatchList(DETECT_SM_LIST_TLSSUBJECT_MATCH, 2); #if 0 SCFPSupportSMList *tmp = sm_fp_support_smlist_list; @@ -207,15 +208,16 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_TLSISSUER_MATCH] == NULL) { + s->sm_lists_tail[DETECT_SM_LIST_TLSISSUER_MATCH] == NULL && + s->sm_lists_tail[DETECT_SM_LIST_TLSSUBJECT_MATCH] == NULL) { SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " "rule, without a preceding content based keyword. " "Currently we provide fast_pattern support for content, " "uricontent, http_client_body, http_server_body, http_header, " "http_raw_header, http_method, http_cookie, " "http_raw_uri, http_stat_msg, http_stat_code, " - "http_user_agent, http_host, http_raw_host, " - "dns_query, tls_sni or tls_cert_issuer option"); + "http_user_agent, http_host, http_raw_host, dns_query, " + "tls_sni, tls_cert_issuer or tls_cert_subject option"); return -1; } @@ -236,7 +238,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSISSUER_MATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSISSUER_MATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSSUBJECT_MATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " "the rule, without a content context. Please use a " diff --git a/src/detect-parse.c b/src/detect-parse.c index 8b8158b5c57e..1427565ecf80 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -166,6 +166,7 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_DNSQUERYNAME_MATCH, "dns_query"); CASE_CODE_STRING(DETECT_SM_LIST_TLSSNI_MATCH, "tls_sni"); CASE_CODE_STRING(DETECT_SM_LIST_TLSISSUER_MATCH, "tls_cert_issuer"); + CASE_CODE_STRING(DETECT_SM_LIST_TLSSUBJECT_MATCH, "tls_cert_subject"); CASE_CODE_STRING(DETECT_SM_LIST_MODBUS_MATCH, "modbus"); CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); @@ -208,6 +209,7 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_DNSQUERYNAME_MATCH); CASE_CODE(DETECT_SM_LIST_TLSSNI_MATCH); CASE_CODE(DETECT_SM_LIST_TLSISSUER_MATCH); + CASE_CODE(DETECT_SM_LIST_TLSSUBJECT_MATCH); CASE_CODE(DETECT_SM_LIST_MODBUS_MATCH); CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); CASE_CODE(DETECT_SM_LIST_POSTMATCH); @@ -1563,6 +1565,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_TLSISSUER_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_TLSSUBJECT_MATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_MODBUS_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c new file mode 100644 index 000000000000..63ad00d44fd6 --- /dev/null +++ b/src/detect-tls-cert-subject.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2007-2016 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 Mats Klepsland + * + * Implements support for tls_cert_subject keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-spm.h" +#include "util-print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-ssl.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static int DetectTlsSubjectSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTlsSubjectRegisterTests(void); + +/** + * \brief Registration function for keyword: tls_cert_issuer + */ +void DetectTlsSubjectRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].name = "tls_cert_subject"; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].desc = "content modifier to match specifically and only on the TLS cert subject buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Match = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Setup = DetectTlsSubjectSetup; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Free = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; + + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_PAYLOAD; +} + +/** + * \brief this function setup the tls_cert_subject modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectTlsSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + s->list = DETECT_SM_LIST_TLSSUBJECT_MATCH; + s->alproto = ALPROTO_TLS; + return 0; +} + +#ifdef UNITTESTS + /* TODO add unit tests */ +#endif + +static void DetectTlsSubjectRegisterTests(void) +{ +#ifdef UNITTESTS + /* TODO add unit tests */ +#endif +} diff --git a/src/detect-tls-cert-subject.h b/src/detect-tls-cert-subject.h new file mode 100644 index 000000000000..e8fd1d3f99e2 --- /dev/null +++ b/src/detect-tls-cert-subject.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2016 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 Mats Klepsland + */ + +#ifndef __DETECT_TLS_SUBJECT_H__ +#define __DETECT_TLS_SUBJECT_H__ + +#include "app-layer-ssl.h" + +void DetectTlsSubjectRegister(void); +uint32_t DetectTlsSubjectInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, + SSLState *ssl_state, uint8_t flags); + +#endif /* __DETECT_TLS_SUBJECT_H__ */ diff --git a/src/detect.c b/src/detect.c index 1c0640dc7a67..c2ad76245a7f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -50,6 +50,7 @@ #include "detect-dns-query.h" #include "detect-tls-sni.h" #include "detect-tls-cert-issuer.h" +#include "detect-tls-cert-subject.h" #include "detect-engine-state.h" #include "detect-engine-analyzer.h" #include "detect-engine-filedata-smtp.h" @@ -1028,30 +1029,29 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } } } else if (alproto == ALPROTO_TLS && has_state) { + void *alstate = FlowGetAppState(p->flow); + if (alstate == NULL) { + SCLogDebug("no alstate"); + return; + } + if (p->flowflags & FLOW_PKT_TOSERVER) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSSNI) { - void *alstate = FlowGetAppState(p->flow); - if (alstate == NULL) { - SCLogDebug("no alstate"); - return; - } - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSSNI); DetectTlsSniInspectMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSNI); } } else if (p->flowflags & FLOW_PKT_TOCLIENT) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSISSUER) { - void *alstate = FlowGetAppState(p->flow); - if (alstate == NULL) { - SCLogDebug("no alstate"); - return; - } - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSISSUER); DetectTlsIssuerInspectMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSISSUER); } + if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSSUBJECT) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSSUBJECT); + DetectTlsSubjectInspectMpm(det_ctx, p->flow, alstate, flags); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSUBJECT); + } } } else if (alproto == ALPROTO_SMTP && has_state) { if (p->flowflags & FLOW_PKT_TOSERVER) { @@ -4388,6 +4388,7 @@ void SigTableSetup(void) DetectDnsQueryRegister(); DetectTlsSniRegister(); DetectTlsIssuerRegister(); + DetectTlsSubjectRegister(); DetectModbusRegister(); DetectAppLayerProtocolRegister(); DetectBase64DecodeRegister(); diff --git a/src/detect.h b/src/detect.h index 09d5bac6f135..d5562ba5342f 100644 --- a/src/detect.h +++ b/src/detect.h @@ -126,6 +126,7 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_TLSSNI_MATCH, DETECT_SM_LIST_TLSISSUER_MATCH, + DETECT_SM_LIST_TLSSUBJECT_MATCH, DETECT_SM_LIST_MODBUS_MATCH, @@ -938,9 +939,10 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 23) #define SIG_GROUP_HEAD_MPM_TLSSNI (1 << 24) #define SIG_GROUP_HEAD_MPM_TLSISSUER (1 << 25) -#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 26) +#define SIG_GROUP_HEAD_MPM_TLSSUBJECT (1 << 26) +#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 27) -#define APP_MPMS_MAX 20 +#define APP_MPMS_MAX 21 enum MpmBuiltinBuffers { MPMB_TCP_PKT_TS, @@ -1020,6 +1022,7 @@ typedef struct SigGroupHead_ { const MpmCtx *mpm_dnsquery_ctx_ts; const MpmCtx *mpm_tlssni_ctx_ts; const MpmCtx *mpm_tlsissuer_ctx_ts; + const MpmCtx *mpm_tlssubject_ctx_ts; const MpmCtx *mpm_smtp_filedata_ctx_ts; }; struct { diff --git a/src/suricata-common.h b/src/suricata-common.h index 4b6ec9694be6..09887df58eec 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -329,6 +329,7 @@ typedef enum PacketProfileDetectId_ { PROF_DETECT_MPM_DNSQUERY, PROF_DETECT_MPM_TLSSNI, PROF_DETECT_MPM_TLSISSUER, + PROF_DETECT_MPM_TLSSUBJECT, PROF_DETECT_IPONLY, PROF_DETECT_RULES, PROF_DETECT_STATEFUL, diff --git a/src/util-profiling.c b/src/util-profiling.c index ec09cbdc4827..8ee1fcb1c480 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1227,6 +1227,7 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id) CASE_CODE (PROF_DETECT_MPM_DNSQUERY); CASE_CODE (PROF_DETECT_MPM_TLSSNI); CASE_CODE (PROF_DETECT_MPM_TLSISSUER); + CASE_CODE (PROF_DETECT_MPM_TLSSUBJECT); CASE_CODE (PROF_DETECT_IPONLY); CASE_CODE (PROF_DETECT_RULES); CASE_CODE (PROF_DETECT_PREFILTER); From 20b41567d99003a1c9b07c4d61dd6aec06270408 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 8 Aug 2016 09:52:51 +0200 Subject: [PATCH 1698/2553] tls: add unit tests for tls_cert_subject --- src/detect-tls-cert-subject.c | 358 +++++++++++++++++++++++++++++++++- 1 file changed, 356 insertions(+), 2 deletions(-) diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index 63ad00d44fd6..90e5caeea95a 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -89,12 +89,366 @@ static int DetectTlsSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, char *st } #ifdef UNITTESTS - /* TODO add unit tests */ + +/** + * \test Test that a signature containing a tls_cert_subject is correctly parsed + * and that the keyword is registered. + */ +static int DetectTlsSubjectTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + SigMatch *sm = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tls any any -> any any " + "(msg:\"Testing tls_cert_subject\"; " + "tls_cert_subject; content:\"test\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + /* sm should not be in the MATCH list */ + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; + FAIL_IF_NOT_NULL(sm); + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_TLSSUBJECT_MATCH]; + FAIL_IF_NULL(sm); + + FAIL_IF(sm->type != DETECT_CONTENT); + FAIL_IF_NOT_NULL(sm->next); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test Test matching for google in the subject of a certificate + * + */ +static int DetectTlsSubjectTest02(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, + 0x5b, 0x85, 0xd4, 0x40, 0xab, 0xbe, 0xc0, 0xbc, + 0x41, 0xf2, 0x26, 0xf0, 0xfe, 0x21, 0xee, 0x8b, + 0x4c, 0x7e, 0x07, 0xc8, 0xec, 0xd2, 0x00, 0x46, + 0x4c, 0xeb, 0xb7, 0x00, 0x00, 0x16, 0xc0, 0x2b, + 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, + 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, + 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0xff, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, + 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, + 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, + 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, + 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, + 0x14, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, + 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x04, 0x02, 0x02, 0x02 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, + 0xdb, 0xbb, 0x23, 0xcf, 0x0b, 0x43, 0x02, 0x1d, + 0x46, 0x11, 0x27, 0x5c, 0x98, 0xcf, 0x67, 0xe1, + 0x94, 0x3d, 0x62, 0x7d, 0x38, 0x48, 0x21, 0x23, + 0xa5, 0x62, 0x31, 0x00, 0xc0, 0x2f, 0x00, 0x00, + 0x1c, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, + 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, + 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x19, + 0xb7, 0xb1, 0x32, 0x3b, 0x1c, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, + 0x31, 0x33, 0x31, 0x33, 0x32, 0x34, 0x35, 0x32, + 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x30, + 0x35, 0x31, 0x33, 0x31, 0x36, 0x30, 0x30, 0x5a, + 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa5, 0x0a, 0xb9, 0xb1, 0xca, 0x36, 0xd1, 0xae, + 0x22, 0x38, 0x07, 0x06, 0xc9, 0x1a, 0x56, 0x4f, + 0xbb, 0xdf, 0xa8, 0x6d, 0xbd, 0xee, 0x76, 0x16, + 0xbc, 0x53, 0x3c, 0x03, 0x6a, 0x5c, 0x94, 0x50, + 0x87, 0x2f, 0x28, 0xb4, 0x4e, 0xd5, 0x9b, 0x8f, + 0xfe, 0x02, 0xde, 0x2a, 0x83, 0x01, 0xf9, 0x45, + 0x61, 0x0e, 0x66, 0x0e, 0x24, 0x22, 0xe2, 0x59, + 0x66, 0x0d, 0xd3, 0xe9, 0x77, 0x8a, 0x7e, 0x42, + 0xaa, 0x5a, 0xf9, 0x05, 0xbf, 0x30, 0xc7, 0x03, + 0x2b, 0xdc, 0xa6, 0x9c, 0xe0, 0x9f, 0x0d, 0xf1, + 0x28, 0x19, 0xf8, 0xf2, 0x02, 0xfa, 0xbd, 0x62, + 0xa0, 0xf3, 0x02, 0x2b, 0xcd, 0xf7, 0x09, 0x04, + 0x3b, 0x52, 0xd8, 0x65, 0x4b, 0x4a, 0x70, 0xe4, + 0x57, 0xc9, 0x2e, 0x2a, 0xf6, 0x9c, 0x6e, 0xd8, + 0xde, 0x01, 0x52, 0xc9, 0x6f, 0xe9, 0xef, 0x82, + 0xbc, 0x0b, 0x95, 0xb2, 0xef, 0xcb, 0x91, 0xa6, + 0x0b, 0x2d, 0x14, 0xc6, 0x00, 0xa9, 0x33, 0x86, + 0x64, 0x00, 0xd4, 0x92, 0x19, 0x53, 0x3d, 0xfd, + 0xcd, 0xc6, 0x1a, 0xf2, 0x0e, 0x67, 0xc2, 0x1d, + 0x2c, 0xe0, 0xe8, 0x29, 0x97, 0x1c, 0xb6, 0xc4, + 0xb2, 0x02, 0x0c, 0x83, 0xb8, 0x60, 0x61, 0xf5, + 0x61, 0x2d, 0x73, 0x5e, 0x85, 0x4d, 0xbd, 0x0d, + 0xe7, 0x1a, 0x37, 0x56, 0x8d, 0xe5, 0x50, 0x0c, + 0xc9, 0x64, 0x4c, 0x11, 0xea, 0xf3, 0xcb, 0x26, + 0x34, 0xbd, 0x02, 0xf5, 0xc1, 0xfb, 0xa2, 0xec, + 0x27, 0xbb, 0x60, 0xbe, 0x0b, 0xf6, 0xe7, 0x3c, + 0x2d, 0xc9, 0xe7, 0xb0, 0x30, 0x28, 0x17, 0x3d, + 0x90, 0xf1, 0x63, 0x8e, 0x49, 0xf7, 0x15, 0x78, + 0x21, 0xcc, 0x45, 0xe6, 0x86, 0xb2, 0xd8, 0xb0, + 0x2e, 0x5a, 0xb0, 0x58, 0xd3, 0xb6, 0x11, 0x40, + 0xae, 0x81, 0x1f, 0x6b, 0x7a, 0xaf, 0x40, 0x50, + 0xf9, 0x2e, 0x81, 0x8b, 0xec, 0x26, 0x11, 0x3f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x53, 0x30, 0x82, 0x01, 0x4f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, + 0x0b, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x6e, 0x6f, 0x82, 0x09, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xc6, 0x53, 0x87, 0x42, + 0x2d, 0xc8, 0xee, 0x7a, 0x62, 0x1e, 0x83, 0xdb, + 0x0d, 0xe2, 0x32, 0xeb, 0x8b, 0xaf, 0x69, 0x40, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, + 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, + 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, + 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, + 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, + 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, + 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x7b, 0x27, 0x00, 0x46, 0x8f, 0xfd, 0x5b, 0xff, + 0xcb, 0x05, 0x9b, 0xf7, 0xf1, 0x68, 0xf6, 0x9a, + 0x7b, 0xba, 0x53, 0xdf, 0x63, 0xed, 0x11, 0x94, + 0x39, 0xf2, 0xd0, 0x20, 0xcd, 0xa3, 0xc4, 0x98, + 0xa5, 0x10, 0x74, 0xe7, 0x10, 0x6d, 0x07, 0xf8, + 0x33, 0x87, 0x05, 0x43, 0x0e, 0x64, 0x77, 0x09, + 0x18, 0x4f, 0x38, 0x2e, 0x45, 0xae, 0xa8, 0x34, + 0x3a, 0xa8, 0x33, 0xac, 0x9d, 0xdd, 0x25, 0x91, + 0x59, 0x43, 0xbe, 0x0f, 0x87, 0x16, 0x2f, 0xb5, + 0x27, 0xfd, 0xce, 0x2f, 0x35, 0x5d, 0x12, 0xa1, + 0x66, 0xac, 0xf7, 0x95, 0x38, 0x0f, 0xe5, 0xb1, + 0x18, 0x18, 0xe6, 0x80, 0x52, 0x31, 0x8a, 0x66, + 0x02, 0x52, 0x1a, 0xa4, 0x32, 0x6a, 0x61, 0x05, + 0xcf, 0x1d, 0xf9, 0x90, 0x73, 0xf0, 0xeb, 0x20, + 0x31, 0x7b, 0x2e, 0xc0, 0xb0, 0xfb, 0x5c, 0xcc, + 0xdc, 0x76, 0x55, 0x72, 0xaf, 0xb1, 0x05, 0xf4, + 0xad, 0xf9, 0xd7, 0x73, 0x5c, 0x2c, 0xbf, 0x0d, + 0x84, 0x18, 0x01, 0x1d, 0x4d, 0x08, 0xa9, 0x4e, + 0x37, 0xb7, 0x58, 0xc4, 0x05, 0x0e, 0x65, 0x63, + 0xd2, 0x88, 0x02, 0xf5, 0x82, 0x17, 0x08, 0xd5, + 0x8f, 0x80, 0xc7, 0x82, 0x29, 0xbb, 0xe1, 0x04, + 0xbe, 0xf6, 0xe1, 0x8c, 0xbc, 0x3a, 0xf8, 0xf9, + 0x56, 0xda, 0xdc, 0x8e, 0xc6, 0xe6, 0x63, 0x98, + 0x12, 0x08, 0x41, 0x2c, 0x9d, 0x7c, 0x82, 0x0d, + 0x1e, 0xea, 0xba, 0xde, 0x32, 0x09, 0xda, 0x52, + 0x24, 0x4f, 0xcc, 0xb6, 0x09, 0x33, 0x8b, 0x00, + 0xf9, 0x83, 0xb3, 0xc6, 0xa4, 0x90, 0x49, 0x83, + 0x2d, 0x36, 0xd9, 0x11, 0x78, 0xd0, 0x62, 0x9f, + 0xc4, 0x8f, 0x84, 0xba, 0x7f, 0xaa, 0x04, 0xf1, + 0xd9, 0xa4, 0xad, 0x5d, 0x63, 0xee, 0x72, 0xc6, + 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, + 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_subject\"; " + "tls_cert_subject; content:\"google\"; nocase; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_hello, sizeof(client_hello)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + #endif static void DetectTlsSubjectRegisterTests(void) { #ifdef UNITTESTS - /* TODO add unit tests */ + UtRegisterTest("DetectTlsSubjectTest01", DetectTlsSubjectTest01); + UtRegisterTest("DetectTlsSubjectTest02", DetectTlsSubjectTest02); #endif } From f1b550d9732ee41fc81288cc2e89ca1ebda3a096 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 8 Aug 2016 10:04:17 +0200 Subject: [PATCH 1699/2553] tls: add unit tests for tls_cert_issuer --- src/detect-tls-cert-issuer.c | 358 ++++++++++++++++++++++++++++++++++- 1 file changed, 356 insertions(+), 2 deletions(-) diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index 0a9702f31308..154185c0782e 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -90,12 +90,366 @@ static int DetectTlsIssuerSetup(DetectEngineCtx *de_ctx, Signature *s, char *str } #ifdef UNITTESTS - /* TODO add unit tests */ + +/** + * \test Test that a signature containing a tls_cert_issuer is correctly parsed + * and that the keyword is registered. + */ +static int DetectTlsIssuerTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + SigMatch *sm = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tls any any -> any any " + "(msg:\"Testing tls_cert_issuer\"; " + "tls_cert_issuer; content:\"test\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + /* sm should not be in the MATCH list */ + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; + FAIL_IF_NOT_NULL(sm); + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_TLSISSUER_MATCH]; + FAIL_IF_NULL(sm); + + FAIL_IF(sm->type != DETECT_CONTENT); + FAIL_IF_NOT_NULL(sm->next); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test Test matching for google in the issuer of a certificate + * + */ +static int DetectTlsIssuerTest02(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, + 0x5b, 0x85, 0xd4, 0x40, 0xab, 0xbe, 0xc0, 0xbc, + 0x41, 0xf2, 0x26, 0xf0, 0xfe, 0x21, 0xee, 0x8b, + 0x4c, 0x7e, 0x07, 0xc8, 0xec, 0xd2, 0x00, 0x46, + 0x4c, 0xeb, 0xb7, 0x00, 0x00, 0x16, 0xc0, 0x2b, + 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, + 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, + 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0xff, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, + 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, + 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, + 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, + 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, + 0x14, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, + 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x04, 0x02, 0x02, 0x02 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, + 0xdb, 0xbb, 0x23, 0xcf, 0x0b, 0x43, 0x02, 0x1d, + 0x46, 0x11, 0x27, 0x5c, 0x98, 0xcf, 0x67, 0xe1, + 0x94, 0x3d, 0x62, 0x7d, 0x38, 0x48, 0x21, 0x23, + 0xa5, 0x62, 0x31, 0x00, 0xc0, 0x2f, 0x00, 0x00, + 0x1c, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, + 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, + 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x19, + 0xb7, 0xb1, 0x32, 0x3b, 0x1c, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, + 0x31, 0x33, 0x31, 0x33, 0x32, 0x34, 0x35, 0x32, + 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x30, + 0x35, 0x31, 0x33, 0x31, 0x36, 0x30, 0x30, 0x5a, + 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa5, 0x0a, 0xb9, 0xb1, 0xca, 0x36, 0xd1, 0xae, + 0x22, 0x38, 0x07, 0x06, 0xc9, 0x1a, 0x56, 0x4f, + 0xbb, 0xdf, 0xa8, 0x6d, 0xbd, 0xee, 0x76, 0x16, + 0xbc, 0x53, 0x3c, 0x03, 0x6a, 0x5c, 0x94, 0x50, + 0x87, 0x2f, 0x28, 0xb4, 0x4e, 0xd5, 0x9b, 0x8f, + 0xfe, 0x02, 0xde, 0x2a, 0x83, 0x01, 0xf9, 0x45, + 0x61, 0x0e, 0x66, 0x0e, 0x24, 0x22, 0xe2, 0x59, + 0x66, 0x0d, 0xd3, 0xe9, 0x77, 0x8a, 0x7e, 0x42, + 0xaa, 0x5a, 0xf9, 0x05, 0xbf, 0x30, 0xc7, 0x03, + 0x2b, 0xdc, 0xa6, 0x9c, 0xe0, 0x9f, 0x0d, 0xf1, + 0x28, 0x19, 0xf8, 0xf2, 0x02, 0xfa, 0xbd, 0x62, + 0xa0, 0xf3, 0x02, 0x2b, 0xcd, 0xf7, 0x09, 0x04, + 0x3b, 0x52, 0xd8, 0x65, 0x4b, 0x4a, 0x70, 0xe4, + 0x57, 0xc9, 0x2e, 0x2a, 0xf6, 0x9c, 0x6e, 0xd8, + 0xde, 0x01, 0x52, 0xc9, 0x6f, 0xe9, 0xef, 0x82, + 0xbc, 0x0b, 0x95, 0xb2, 0xef, 0xcb, 0x91, 0xa6, + 0x0b, 0x2d, 0x14, 0xc6, 0x00, 0xa9, 0x33, 0x86, + 0x64, 0x00, 0xd4, 0x92, 0x19, 0x53, 0x3d, 0xfd, + 0xcd, 0xc6, 0x1a, 0xf2, 0x0e, 0x67, 0xc2, 0x1d, + 0x2c, 0xe0, 0xe8, 0x29, 0x97, 0x1c, 0xb6, 0xc4, + 0xb2, 0x02, 0x0c, 0x83, 0xb8, 0x60, 0x61, 0xf5, + 0x61, 0x2d, 0x73, 0x5e, 0x85, 0x4d, 0xbd, 0x0d, + 0xe7, 0x1a, 0x37, 0x56, 0x8d, 0xe5, 0x50, 0x0c, + 0xc9, 0x64, 0x4c, 0x11, 0xea, 0xf3, 0xcb, 0x26, + 0x34, 0xbd, 0x02, 0xf5, 0xc1, 0xfb, 0xa2, 0xec, + 0x27, 0xbb, 0x60, 0xbe, 0x0b, 0xf6, 0xe7, 0x3c, + 0x2d, 0xc9, 0xe7, 0xb0, 0x30, 0x28, 0x17, 0x3d, + 0x90, 0xf1, 0x63, 0x8e, 0x49, 0xf7, 0x15, 0x78, + 0x21, 0xcc, 0x45, 0xe6, 0x86, 0xb2, 0xd8, 0xb0, + 0x2e, 0x5a, 0xb0, 0x58, 0xd3, 0xb6, 0x11, 0x40, + 0xae, 0x81, 0x1f, 0x6b, 0x7a, 0xaf, 0x40, 0x50, + 0xf9, 0x2e, 0x81, 0x8b, 0xec, 0x26, 0x11, 0x3f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x53, 0x30, 0x82, 0x01, 0x4f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, + 0x0b, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x6e, 0x6f, 0x82, 0x09, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xc6, 0x53, 0x87, 0x42, + 0x2d, 0xc8, 0xee, 0x7a, 0x62, 0x1e, 0x83, 0xdb, + 0x0d, 0xe2, 0x32, 0xeb, 0x8b, 0xaf, 0x69, 0x40, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, + 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, + 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, + 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, + 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, + 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, + 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x7b, 0x27, 0x00, 0x46, 0x8f, 0xfd, 0x5b, 0xff, + 0xcb, 0x05, 0x9b, 0xf7, 0xf1, 0x68, 0xf6, 0x9a, + 0x7b, 0xba, 0x53, 0xdf, 0x63, 0xed, 0x11, 0x94, + 0x39, 0xf2, 0xd0, 0x20, 0xcd, 0xa3, 0xc4, 0x98, + 0xa5, 0x10, 0x74, 0xe7, 0x10, 0x6d, 0x07, 0xf8, + 0x33, 0x87, 0x05, 0x43, 0x0e, 0x64, 0x77, 0x09, + 0x18, 0x4f, 0x38, 0x2e, 0x45, 0xae, 0xa8, 0x34, + 0x3a, 0xa8, 0x33, 0xac, 0x9d, 0xdd, 0x25, 0x91, + 0x59, 0x43, 0xbe, 0x0f, 0x87, 0x16, 0x2f, 0xb5, + 0x27, 0xfd, 0xce, 0x2f, 0x35, 0x5d, 0x12, 0xa1, + 0x66, 0xac, 0xf7, 0x95, 0x38, 0x0f, 0xe5, 0xb1, + 0x18, 0x18, 0xe6, 0x80, 0x52, 0x31, 0x8a, 0x66, + 0x02, 0x52, 0x1a, 0xa4, 0x32, 0x6a, 0x61, 0x05, + 0xcf, 0x1d, 0xf9, 0x90, 0x73, 0xf0, 0xeb, 0x20, + 0x31, 0x7b, 0x2e, 0xc0, 0xb0, 0xfb, 0x5c, 0xcc, + 0xdc, 0x76, 0x55, 0x72, 0xaf, 0xb1, 0x05, 0xf4, + 0xad, 0xf9, 0xd7, 0x73, 0x5c, 0x2c, 0xbf, 0x0d, + 0x84, 0x18, 0x01, 0x1d, 0x4d, 0x08, 0xa9, 0x4e, + 0x37, 0xb7, 0x58, 0xc4, 0x05, 0x0e, 0x65, 0x63, + 0xd2, 0x88, 0x02, 0xf5, 0x82, 0x17, 0x08, 0xd5, + 0x8f, 0x80, 0xc7, 0x82, 0x29, 0xbb, 0xe1, 0x04, + 0xbe, 0xf6, 0xe1, 0x8c, 0xbc, 0x3a, 0xf8, 0xf9, + 0x56, 0xda, 0xdc, 0x8e, 0xc6, 0xe6, 0x63, 0x98, + 0x12, 0x08, 0x41, 0x2c, 0x9d, 0x7c, 0x82, 0x0d, + 0x1e, 0xea, 0xba, 0xde, 0x32, 0x09, 0xda, 0x52, + 0x24, 0x4f, 0xcc, 0xb6, 0x09, 0x33, 0x8b, 0x00, + 0xf9, 0x83, 0xb3, 0xc6, 0xa4, 0x90, 0x49, 0x83, + 0x2d, 0x36, 0xd9, 0x11, 0x78, 0xd0, 0x62, 0x9f, + 0xc4, 0x8f, 0x84, 0xba, 0x7f, 0xaa, 0x04, 0xf1, + 0xd9, 0xa4, 0xad, 0x5d, 0x63, 0xee, 0x72, 0xc6, + 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, + 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_issuer\"; " + "tls_cert_issuer; content:\"google\"; nocase; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_hello, sizeof(client_hello)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + #endif static void DetectTlsIssuerRegisterTests(void) { #ifdef UNITTESTS - /* TODO add unit tests */ + UtRegisterTest("DetectTlsIssuerTest01", DetectTlsIssuerTest01); + UtRegisterTest("DetectTlsIssuerTest02", DetectTlsIssuerTest02); #endif } From 188b382c46a13f266843b9546c3b9daf03b9dc02 Mon Sep 17 00:00:00 2001 From: Duarte Silva Date: Fri, 29 Apr 2016 21:23:12 +0200 Subject: [PATCH 1700/2553] file-hashing: common code added Moved and adapted code from detect-filemd5 to util-detect-file-hash, generalised code to work with SHA-1 and SHA-256 and added necessary flags and other constants. --- src/Makefile.am | 1 + src/detect-filemd5.c | 283 ++------------------------- src/detect-filemd5.h | 7 - src/detect.h | 13 +- src/util-detect-file-hash.c | 368 ++++++++++++++++++++++++++++++++++++ src/util-detect-file-hash.h | 45 +++++ src/util-error.c | 1 + src/util-error.h | 1 + src/util-file.h | 20 +- 9 files changed, 452 insertions(+), 287 deletions(-) create mode 100644 src/util-detect-file-hash.c create mode 100644 src/util-detect-file-hash.h diff --git a/src/Makefile.am b/src/Makefile.am index b941a09e91ec..6c2744829dd4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -344,6 +344,7 @@ util-decode-asn1.c util-decode-asn1.h \ util-decode-der.c util-decode-der.h \ util-decode-der-get.c util-decode-der-get.h \ util-decode-mime.c util-decode-mime.h \ +util-detect-file-hash.c util-detect-file-hash.h \ util-device.c util-device.h \ util-enum.c util-enum.h \ util-error.c util-error.h \ diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index 18c46616396e..6d8be5394e5e 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -23,37 +23,14 @@ */ #include "suricata-common.h" -#include "threads.h" -#include "debug.h" -#include "decode.h" -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-print.h" +#include "util-detect-file-hash.h" #include "util-unittest.h" #include "util-unittest-helper.h" -#include "app-layer.h" - -#include "stream-tcp.h" - #include "detect-filemd5.h" -#include "queue.h" -#include "util-rohash.h" - #ifndef HAVE_NSS static int DetectFileMd5SetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) @@ -74,17 +51,14 @@ void DetectFileMd5Register(void) sigmatch_table[DETECT_FILEMD5].RegisterTests = NULL; sigmatch_table[DETECT_FILEMD5].flags = SIGMATCH_NOT_BUILT; - SCLogDebug("registering filemd5 rule option"); + SCLogDebug("registering filemd5 rule option"); return; } #else /* HAVE_NSS */ -static int DetectFileMd5Match (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, File *, Signature *, SigMatch *); static int DetectFileMd5Setup (DetectEngineCtx *, Signature *, char *); static void DetectFileMd5RegisterTests(void); -static void DetectFileMd5Free(void *); /** * \brief Registration function for keyword: filemd5 @@ -94,203 +68,15 @@ void DetectFileMd5Register(void) sigmatch_table[DETECT_FILEMD5].name = "filemd5"; sigmatch_table[DETECT_FILEMD5].desc = "match file MD5 against list of MD5 checksums"; sigmatch_table[DETECT_FILEMD5].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemd5"; - sigmatch_table[DETECT_FILEMD5].FileMatch = DetectFileMd5Match; + sigmatch_table[DETECT_FILEMD5].FileMatch = DetectFileHashMatch; sigmatch_table[DETECT_FILEMD5].Setup = DetectFileMd5Setup; - sigmatch_table[DETECT_FILEMD5].Free = DetectFileMd5Free; + sigmatch_table[DETECT_FILEMD5].Free = DetectFileHashFree; sigmatch_table[DETECT_FILEMD5].RegisterTests = DetectFileMd5RegisterTests; - SCLogDebug("registering filemd5 rule option"); + SCLogDebug("registering filemd5 rule option"); return; } -static int Md5ReadString(uint8_t *md5, char *str, char *filename, int line_no) -{ - if (strlen(str) != 32) { - SCLogError(SC_ERR_INVALID_MD5, "%s:%d md5 string not 32 bytes", - filename, line_no); - return -1; - } - - int i, x; - for (x = 0, i = 0; i < 32; i+=2, x++) { - char buf[3] = { 0, 0, 0}; - buf[0] = str[i]; - buf[1] = str[i+1]; - - long value = strtol(buf, NULL, 16); - if (value >= 0 && value <= 255) - md5[x] = (uint8_t)value; - else { - SCLogError(SC_ERR_INVALID_MD5, "%s:%d md5 byte out of range %ld", - filename, line_no, value); - return -1; - } - } - - return 1; -} - -static int MD5LoadHash(ROHashTable *hash, char *string, char *filename, int line_no) -{ - uint8_t md5[16]; - - if (Md5ReadString(md5, string, filename, line_no) == 1) { - if (ROHashInitQueueValue(hash, &md5, (uint16_t)sizeof(md5)) != 1) - return -1; - } - - return 1; -} - -static int MD5MatchLookupBuffer(ROHashTable *hash, uint8_t *buf, size_t buflen) -{ - void *ptr = ROHashLookup(hash, buf, (uint16_t)buflen); - if (ptr == NULL) - return 0; - else - return 1; -} - -/** - * \brief match the specified filemd5 - * - * \param t thread local vars - * \param det_ctx pattern matcher thread local data - * \param f *LOCKED* flow - * \param flags direction flags - * \param file file being inspected - * \param s signature being inspected - * \param m sigmatch that we will cast into DetectFileMd5Data - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectFileMd5Match (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) -{ - SCEnter(); - int ret = 0; - DetectFileMd5Data *filemd5 = (DetectFileMd5Data *)m->ctx; - - if (file->txid < det_ctx->tx_id) { - SCReturnInt(0); - } - - if (file->txid > det_ctx->tx_id) { - SCReturnInt(0); - } - - if (file->state != FILE_STATE_CLOSED) { - SCReturnInt(0); - } - - if (file->flags & FILE_MD5) { - if (MD5MatchLookupBuffer(filemd5->hash, file->md5, sizeof(file->md5)) == 1) { - if (filemd5->negated == 0) - ret = 1; - else - ret = 0; - } else { - if (filemd5->negated == 0) - ret = 0; - else - ret = 1; - } - } - - SCReturnInt(ret); -} - -/** - * \brief Parse the filemd5 keyword - * - * \param idstr Pointer to the user provided option - * - * \retval filemd5 pointer to DetectFileMd5Data on success - * \retval NULL on failure - */ -static DetectFileMd5Data *DetectFileMd5Parse (const DetectEngineCtx *de_ctx, char *str) -{ - DetectFileMd5Data *filemd5 = NULL; - FILE *fp = NULL; - char *filename = NULL; - - /* We have a correct filemd5 option */ - filemd5 = SCMalloc(sizeof(DetectFileMd5Data)); - if (unlikely(filemd5 == NULL)) - goto error; - - memset(filemd5, 0x00, sizeof(DetectFileMd5Data)); - - if (strlen(str) && str[0] == '!') { - filemd5->negated = 1; - str++; - } - - filemd5->hash = ROHashInit(18, 16); - if (filemd5->hash == NULL) { - goto error; - } - - /* get full filename */ - filename = DetectLoadCompleteSigPath(de_ctx, str); - if (filename == NULL) { - goto error; - } - - char line[8192] = ""; - fp = fopen(filename, "r"); - if (fp == NULL) { - SCLogError(SC_ERR_OPENING_RULE_FILE, "opening md5 file %s: %s", filename, strerror(errno)); - goto error; - } - - int line_no = 0; - while(fgets(line, (int)sizeof(line), fp) != NULL) { - size_t len = strlen(line); - line_no++; - - /* ignore comments and empty lines */ - if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') - continue; - - while (isspace(line[--len])); - - /* Check if we have a trailing newline, and remove it */ - len = strlen(line); - if (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) { - line[len - 1] = '\0'; - } - - /* cut off longer lines */ - if (strlen(line) > 32) - line[32] = 0x00; - - if (MD5LoadHash(filemd5->hash, line, filename, line_no) != 1) { - goto error; - } - } - fclose(fp); - fp = NULL; - - if (ROHashInitFinalize(filemd5->hash) != 1) { - goto error; - } - SCLogInfo("MD5 hash size %u bytes%s", ROHashMemorySize(filemd5->hash), filemd5->negated ? ", negated match" : ""); - - SCFree(filename); - return filemd5; - -error: - if (filemd5 != NULL) - DetectFileMd5Free(filemd5); - if (fp != NULL) - fclose(fp); - if (filename != NULL) - SCFree(filename); - return NULL; -} - /** * \brief this function is used to parse filemd5 options * \brief into the current signature @@ -304,55 +90,14 @@ static DetectFileMd5Data *DetectFileMd5Parse (const DetectEngineCtx *de_ctx, cha */ static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) { - DetectFileMd5Data *filemd5 = NULL; - SigMatch *sm = NULL; - - filemd5 = DetectFileMd5Parse(de_ctx, str); - if (filemd5 == NULL) - goto error; - - /* Okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - sm = SigMatchAlloc(); - if (sm == NULL) - goto error; - - sm->type = DETECT_FILEMD5; - sm->ctx = (void *)filemd5; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - - s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MD5); - return 0; - -error: - if (filemd5 != NULL) - DetectFileMd5Free(filemd5); - if (sm != NULL) - SCFree(sm); - return -1; -} - -/** - * \brief this function will free memory associated with DetectFileMd5Data - * - * \param filemd5 pointer to DetectFileMd5Data - */ -static void DetectFileMd5Free(void *ptr) -{ - if (ptr != NULL) { - DetectFileMd5Data *filemd5 = (DetectFileMd5Data *)ptr; - if (filemd5->hash != NULL) - ROHashFree(filemd5->hash); - SCFree(filemd5); - } + return DetectFileHashSetup(de_ctx, s, str, DETECT_FILEMD5); } #ifdef UNITTESTS static int MD5MatchLookupString(ROHashTable *hash, char *string) { uint8_t md5[16]; - if (Md5ReadString(md5, string, "file", 88) == 1) { + if (ReadHashString(md5, string, "file", 88, 32) == 1) { void *ptr = ROHashLookup(hash, &md5, (uint16_t)sizeof(md5)); if (ptr == NULL) return 0; @@ -368,17 +113,17 @@ static int MD5MatchTest01(void) if (hash == NULL) { return 0; } - if (MD5LoadHash(hash, "d80f93a93dc5f3ee945704754d6e0a36", "file", 1) != 1) + if (LoadHashTable(hash, "d80f93a93dc5f3ee945704754d6e0a36", "file", 1, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "92a49985b384f0d993a36e4c2d45e206", "file", 2) != 1) + if (LoadHashTable(hash, "92a49985b384f0d993a36e4c2d45e206", "file", 2, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "11adeaacc8c309815f7bc3e33888f281", "file", 3) != 1) + if (LoadHashTable(hash, "11adeaacc8c309815f7bc3e33888f281", "file", 3, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "22e10a8fe02344ade0bea8836a1714af", "file", 4) != 1) + if (LoadHashTable(hash, "22e10a8fe02344ade0bea8836a1714af", "file", 4, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "c3db2cbf02c68f073afcaee5634677bc", "file", 5) != 1) + if (LoadHashTable(hash, "c3db2cbf02c68f073afcaee5634677bc", "file", 5, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "7ed095da259638f42402fb9e74287a17", "file", 6) != 1) + if (LoadHashTable(hash, "7ed095da259638f42402fb9e74287a17", "file", 6, DETECT_FILEMD5) != 1) return 0; if (ROHashInitFinalize(hash) != 1) { @@ -397,7 +142,7 @@ static int MD5MatchTest01(void) return 0; if (MD5MatchLookupString(hash, "7ed095da259638f42402fb9e74287a17") != 1) return 0; - /* shouldnt match */ + /* shouldn't match */ if (MD5MatchLookupString(hash, "33333333333333333333333333333333") == 1) return 0; diff --git a/src/detect-filemd5.h b/src/detect-filemd5.h index 486812f7c625..0905fc4ce02b 100644 --- a/src/detect-filemd5.h +++ b/src/detect-filemd5.h @@ -24,13 +24,6 @@ #ifndef __DETECT_FILEMD5_H__ #define __DETECT_FILEMD5_H__ -#include "util-rohash.h" - -typedef struct DetectFileMd5Data { - ROHashTable *hash; - int negated; -} DetectFileMd5Data; - /* prototypes */ void DetectFileMd5Register (void); diff --git a/src/detect.h b/src/detect.h index d5562ba5342f..3031f4d4c675 100644 --- a/src/detect.h +++ b/src/detect.h @@ -305,11 +305,12 @@ typedef struct DetectPort_ { #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 +#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) */ @@ -1216,6 +1217,8 @@ enum { DETECT_FILESTORE, DETECT_FILEMAGIC, DETECT_FILEMD5, + DETECT_FILESHA1, + DETECT_FILESHA256, DETECT_FILESIZE, DETECT_L3PROTO, diff --git a/src/util-detect-file-hash.c b/src/util-detect-file-hash.c new file mode 100644 index 000000000000..49b93eb8f766 --- /dev/null +++ b/src/util-detect-file-hash.c @@ -0,0 +1,368 @@ +/* Copyright (C) 2007-2016 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 + * \author Duarte Silva + * + */ + +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "util-detect-file-hash.h" + +#include "app-layer-htp.h" + +#ifdef HAVE_NSS + +/** + * \brief Read the bytes of a hash from an hexadecimal string + * + * \param hash buffer to store the resulting bytes + * \param string hexadecimal string representing the hash + * \param filename file name from where the string was read + * \param line_no file line number from where the string was read + * \param expected_len the expected length of the string that was read + * + * \retval -1 the hexadecimal string is invalid + * \retval 1 the hexadecimal string was read successfully + */ +int ReadHashString(uint8_t *hash, char *string, char *filename, int line_no, + uint16_t expected_len) +{ + if (strlen(string) != expected_len) { + SCLogError(SC_ERR_INVALID_HASH, "%s:%d hash string not %d characters", + filename, line_no, expected_len); + return -1; + } + + int i, x; + for (x = 0, i = 0; i < expected_len; i+=2, x++) { + char buf[3] = { 0, 0, 0 }; + buf[0] = string[i]; + buf[1] = string[i+1]; + + long value = strtol(buf, NULL, 16); + if (value >= 0 && value <= 255) + hash[x] = (uint8_t)value; + else { + SCLogError(SC_ERR_INVALID_HASH, "%s:%d hash byte out of range %ld", + filename, line_no, value); + return -1; + } + } + + return 1; +} + +/** + * \brief Store a hash into the hash table + * + * \param hash_table hash table that will hold the hash + * \param string hexadecimal string representing the hash + * \param filename file name from where the string was read + * \param line_no file line number from where the string was read + * \param type the hash algorithm + * + * \retval -1 failed to load the hash into the hash table + * \retval 1 successfully loaded the has into the hash table + */ +int LoadHashTable(ROHashTable *hash_table, char *string, char *filename, + int line_no, uint32_t type) +{ + /* allocate the maximum size a hash can have (in this case is SHA256, 32 bytes) */ + uint8_t hash[32]; + /* specify the actual size that should be read depending on the hash algorithm */ + uint16_t size = 32; + + if (type == DETECT_FILEMD5) { + size = 16; + } + else if (type == DETECT_FILESHA1) { + size = 20; + } + + /* every byte represented with hexadecimal digits is two characters */ + uint16_t expected_len = (size * 2); + + if (ReadHashString(hash, string, filename, line_no, expected_len) == 1) { + if (ROHashInitQueueValue(hash_table, &hash, size) != 1) + return -1; + } + + return 1; +} + +/** + * \brief Match a hash stored in a hash table + * + * \param hash_table hash table that will hold the hash + * \param hash buffer containing the bytes of the has + * \param hash_len length of the hash buffer + * + * \retval 0 didn't find the specified hash + * \retval 1 the hash matched a stored value + */ +static int HashMatchHashTable(ROHashTable *hash_table, uint8_t *hash, + size_t hash_len) +{ + void *ptr = ROHashLookup(hash_table, hash, (uint16_t)hash_len); + if (ptr == NULL) + return 0; + else + return 1; +} + +/** + * \brief Match the specified file hash + * + * \param t thread local vars + * \param det_ctx pattern matcher thread local data + * \param f *LOCKED* flow + * \param flags direction flags + * \param file file being inspected + * \param s signature being inspected + * \param m sigmatch that we will cast into DetectFileHashData + * + * \retval 0 no match + * \retval 1 match + */ +int DetectFileHashMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) +{ + SCEnter(); + int ret = 0; + DetectFileHashData *filehash = (DetectFileHashData *)m->ctx; + + if (file->txid < det_ctx->tx_id) { + SCReturnInt(0); + } + + if (file->txid > det_ctx->tx_id) { + SCReturnInt(0); + } + + if (file->state != FILE_STATE_CLOSED) { + SCReturnInt(0); + } + + int match = -1; + + if (s->file_flags & FILE_SIG_NEED_MD5 && file->flags & FILE_MD5) { + match = HashMatchHashTable(filehash->hash, file->md5, sizeof(file->md5)); + } + else if (s->file_flags & FILE_SIG_NEED_SHA1 && file->flags & FILE_SHA1) { + match = HashMatchHashTable(filehash->hash, file->sha1, sizeof(file->sha1)); + } + else if (s->file_flags & FILE_SIG_NEED_SHA256 && file->flags & FILE_SHA256) { + match = HashMatchHashTable(filehash->hash, file->sha256, sizeof(file->sha256)); + } + + if (match == 1) { + if (filehash->negated == 0) + ret = 1; + else + ret = 0; + } + else if (match == 0) { + if (filehash->negated == 0) + ret = 0; + else + ret = 1; + } + + SCReturnInt(ret); +} + +/** + * \brief Parse the filemd5 keyword + * + * \param det_ctx pattern matcher thread local data + * \param str Pointer to the user provided option + * \param type the hash algorithm + * + * \retval filemd5 pointer to DetectFileHashData on success + * \retval NULL on failure + */ +static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, + char *str, uint32_t type) +{ + DetectFileHashData *filehash = NULL; + FILE *fp = NULL; + char *filename = NULL; + + /* We have a correct filemd5 option */ + filehash = SCMalloc(sizeof(DetectFileHashData)); + if (unlikely(filehash == NULL)) + goto error; + + memset(filehash, 0x00, sizeof(DetectFileHashData)); + + if (strlen(str) && str[0] == '!') { + filehash->negated = 1; + str++; + } + + if (type == DETECT_FILEMD5) { + filehash->hash = ROHashInit(18, 16); + } + else if (type == DETECT_FILESHA1) { + filehash->hash = ROHashInit(18, 20); + } + else if (type == DETECT_FILESHA256) { + filehash->hash = ROHashInit(18, 32); + } + + if (filehash->hash == NULL) { + goto error; + } + + /* get full filename */ + filename = DetectLoadCompleteSigPath(de_ctx, str); + if (filename == NULL) { + goto error; + } + + char line[8192] = ""; + fp = fopen(filename, "r"); + if (fp == NULL) { + SCLogError(SC_ERR_OPENING_RULE_FILE, "opening hash file %s: %s", filename, strerror(errno)); + goto error; + } + + int line_no = 0; + while(fgets(line, (int)sizeof(line), fp) != NULL) { + size_t len = strlen(line); + line_no++; + + /* ignore comments and empty lines */ + if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') + continue; + + while (isspace(line[--len])); + + /* Check if we have a trailing newline, and remove it */ + len = strlen(line); + if (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) { + line[len - 1] = '\0'; + } + + /* cut off longer lines than a SHA256 represented in hexadecimal */ + if (strlen(line) > 64) + line[64] = 0x00; + + if (LoadHashTable(filehash->hash, line, filename, line_no, type) != 1) { + goto error; + } + } + fclose(fp); + fp = NULL; + + if (ROHashInitFinalize(filehash->hash) != 1) { + goto error; + } + SCLogInfo("Hash hash table size %u bytes%s", ROHashMemorySize(filehash->hash), filehash->negated ? ", negated match" : ""); + + SCFree(filename); + return filehash; + +error: + if (filehash != NULL) + DetectFileHashFree(filehash); + if (fp != NULL) + fclose(fp); + if (filename != NULL) + SCFree(filename); + return NULL; +} + +/** + * \brief this function is used to parse filemd5, filesha1 and filesha256 options + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided "filemd5", "filesha1" or "filesha256" option + * \param type type of file hash to setup + * + * \retval 0 on Success + * \retval -1 on Failure + */ +int DetectFileHashSetup (DetectEngineCtx *de_ctx, Signature *s, char *str, + uint32_t type) +{ + DetectFileHashData *filehash = NULL; + SigMatch *sm = NULL; + + filehash = DetectFileHashParse(de_ctx, str, type); + if (filehash == NULL) + goto error; + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = type; + sm->ctx = (void *)filehash; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + + s->file_flags |= FILE_SIG_NEED_FILE; + + // Setup the file flags depending on the hashing algorithm + if (type == DETECT_FILEMD5) { + s->file_flags |= FILE_SIG_NEED_MD5; + } + if (type == DETECT_FILESHA1) { + s->file_flags |= FILE_SIG_NEED_SHA1; + } + if (type == DETECT_FILESHA256) { + s->file_flags |= FILE_SIG_NEED_SHA256; + } + return 0; + +error: + if (filehash != NULL) + DetectFileHashFree(filehash); + if (sm != NULL) + SCFree(sm); + return -1; +} + +/** + * \brief this function will free memory associated with DetectFileHashData + * + * \param filehash pointer to DetectFileHashData + */ +void DetectFileHashFree(void *ptr) +{ + if (ptr != NULL) { + DetectFileHashData *filehash = (DetectFileHashData *)ptr; + if (filehash->hash != NULL) + ROHashFree(filehash->hash); + SCFree(filehash); + } +} + +#endif /* HAVE_NSS */ diff --git a/src/util-detect-file-hash.h b/src/util-detect-file-hash.h new file mode 100644 index 000000000000..19d5418c3e5a --- /dev/null +++ b/src/util-detect-file-hash.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2007-2016 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 + * \author Duarte Silva + * + */ + +#ifndef __UTIL_DETECT_FILE_HASH_H__ +#define __UTIL_DETECT_FILE_HASH_H__ + +#include "util-rohash.h" + +typedef struct DetectFileHashData { + ROHashTable *hash; + int negated; +} DetectFileHashData; + +/* prototypes */ +int ReadHashString(uint8_t *, char *, char *, int, uint16_t); +int LoadHashTable(ROHashTable *, char *, char *, int, uint32_t); + +int DetectFileHashMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, + File *, Signature *, SigMatch *); +int DetectFileHashSetup(DetectEngineCtx *, Signature *, char *, uint32_t); +void DetectFileHashFree(void *); + +#endif /* __UTIL_DETECT_FILE_HASH_H__ */ diff --git a/src/util-error.c b/src/util-error.c index 50d013c58c35..94d3e02d05ac 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -326,6 +326,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_SSH_LOG_GENERIC); CASE_CODE (SC_ERR_NIC_OFFLOADING); CASE_CODE (SC_ERR_NO_FILES_FOR_PROTOCOL); + CASE_CODE (SC_ERR_INVALID_HASH); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 28a50cff4edb..63eee8ec3b37 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -316,6 +316,7 @@ typedef enum { SC_ERR_SSH_LOG_GENERIC, SC_ERR_NIC_OFFLOADING, SC_ERR_NO_FILES_FOR_PROTOCOL, + SC_ERR_INVALID_HASH, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-file.h b/src/util-file.h index bdea4702f605..96fee17a90f7 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -35,12 +35,16 @@ #define FILE_NOMAGIC 0x0002 #define FILE_NOMD5 0x0004 #define FILE_MD5 0x0008 -#define FILE_LOGGED 0x0010 -#define FILE_NOSTORE 0x0020 -#define FILE_STORE 0x0040 -#define FILE_STORED 0x0080 -#define FILE_NOTRACK 0x0100 /**< track size of file */ -#define FILE_USE_DETECT 0x0200 /**< use content_inspected tracker */ +#define FILE_NOSHA1 0x0010 +#define FILE_SHA1 0x0020 +#define FILE_NOSHA256 0x0040 +#define FILE_SHA256 0x0080 +#define FILE_LOGGED 0x0100 +#define FILE_NOSTORE 0x0200 +#define FILE_STORE 0x0400 +#define FILE_STORED 0x0800 +#define FILE_NOTRACK 0x1000 /**< track size of file */ +#define FILE_USE_DETECT 0x2000 /**< use content_inspected tracker */ typedef enum FileState_ { FILE_STATE_NONE = 0, /**< no state */ @@ -66,6 +70,10 @@ typedef struct File_ { #ifdef HAVE_NSS HASHContext *md5_ctx; uint8_t md5[MD5_LENGTH]; + HASHContext *sha1_ctx; + uint8_t sha1[SHA1_LENGTH]; + HASHContext *sha256_ctx; + uint8_t sha256[SHA256_LENGTH]; #endif uint64_t content_inspected; /**< used in pruning if FILE_USE_DETECT * flag is set */ From a6d928e269db561c223a31e5677f298708541009 Mon Sep 17 00:00:00 2001 From: Duarte Silva Date: Fri, 29 Apr 2016 21:51:12 +0200 Subject: [PATCH 1701/2553] file-hashing: added support for SHA-1 file hashing --- src/Makefile.am | 1 + src/app-layer-htp-file.c | 10 +++ src/app-layer-smtp.c | 4 + src/detect-engine-file.c | 6 ++ src/detect-engine-siggroup.c | 12 ++- src/detect-engine-siggroup.h | 2 +- src/detect-filesha1.c | 162 +++++++++++++++++++++++++++++++++++ src/detect-filesha1.h | 31 +++++++ src/detect.c | 39 ++++++++- src/detect.h | 13 +-- src/flow.h | 36 ++++---- src/log-file.c | 9 +- src/log-filestore.c | 8 ++ src/output-json-file.c | 9 ++ src/suricata.c | 2 +- src/util-error.c | 1 + src/util-error.h | 1 + src/util-file.c | 90 +++++++++++++++++-- src/util-file.h | 4 + src/util-lua-common.c | 12 +++ 20 files changed, 415 insertions(+), 37 deletions(-) create mode 100644 src/detect-filesha1.c create mode 100644 src/detect-filesha1.h diff --git a/src/Makefile.am b/src/Makefile.am index 6c2744829dd4..edc6d65d2eb1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -138,6 +138,7 @@ detect-file-data.c detect-file-data.h \ detect-fileext.c detect-fileext.h \ detect-filemagic.c detect-filemagic.h \ detect-filemd5.c detect-filemd5.h \ +detect-filesha1.c detect-filesha1.h \ detect-filename.c detect-filename.h \ detect-filesize.c detect-filesize.h \ detect-filestore.c detect-filestore.h \ diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index 4dcddf686523..18b193612bd4 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -118,6 +118,11 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, flags |= FILE_NOMD5; } + if (s->f->flags & FLOW_FILE_NO_SHA1_TC) { + SCLogDebug("no sha1 for this flow in toclient direction, so none for this file"); + flags |= FILE_NOSHA1; + } + if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TC)) { flags |= FILE_NOSTORE; } @@ -150,6 +155,11 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, flags |= FILE_NOMD5; } + if (s->f->flags & FLOW_FILE_NO_SHA1_TS) { + SCLogDebug("no sha1 for this flow in toserver direction, so none for this file"); + flags |= FILE_NOSHA1; + } + if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TS)) { flags |= FILE_NOSTORE; } diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 6c2aede9b34e..f8b25c9470e4 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -423,6 +423,10 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, flags |= FILE_NOMD5; } + if (flow->flags & FLOW_FILE_NO_SHA1_TS) { + flags |= FILE_NOSHA1; + } + /* Find file */ if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index 1afe967d6acd..5eb36e853d78 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -129,6 +129,12 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, break; } + if ((s->file_flags & FILE_SIG_NEED_SHA1) && (!(file->flags & FILE_SHA1))) { + SCLogDebug("sig needs file sha1, but we don't have any"); + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + break; + } + if ((s->file_flags & FILE_SIG_NEED_SIZE) && file->state < FILE_STATE_CLOSED) { SCLogDebug("sig needs filesize, but state < FILE_STATE_CLOSED"); r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index a55b53046863..58a3058ad27e 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -516,7 +516,7 @@ int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, } /** - * \brief Set the need md5 flag in the sgh. + * \brief Set the need magic flag in the sgh. * * \param de_ctx detection engine ctx for the signatures * \param sgh sig group head to set the flag in @@ -608,12 +608,12 @@ void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) } /** - * \brief Set the need magic flag in the sgh. + * \brief Set the need hash flag in the sgh. * * \param de_ctx detection engine ctx for the signatures * \param sgh sig group head to set the flag in */ -void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +void SigGroupHeadSetFileHashFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; uint32_t sig = 0; @@ -631,6 +631,12 @@ void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) SCLogDebug("sgh %p has filemd5", sgh); break; } + + if (SignatureIsFileSha1Inspecting(s)) { + sgh->flags |= SIG_GROUP_HEAD_HAVEFILESHA1; + SCLogDebug("sgh %p has filesha1", sgh); + break; + } } return; diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index 7b88bbc7c715..b8dd6b1c9fc3 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -67,7 +67,7 @@ void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh); void SigGroupHeadStore(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilestoreCount(DetectEngineCtx *, SigGroupHead *); -void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *, SigGroupHead *); +void SigGroupHeadSetFileHashFlag(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *, SigGroupHead *); uint16_t SigGroupHeadGetMinMpmSize(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int list); diff --git a/src/detect-filesha1.c b/src/detect-filesha1.c new file mode 100644 index 000000000000..ea4e469bfb91 --- /dev/null +++ b/src/detect-filesha1.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2007-2016 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 + * \author Duarte Silva + * + */ + +#include "suricata-common.h" + +#include "util-detect-file-hash.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +#include "detect-filesha1.h" + +#ifndef HAVE_NSS + +static int DetectFileSha1SetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) +{ + SCLogError(SC_ERR_NO_SHA1_SUPPORT, "no SHA-1 calculation support built in, needed for filesha1 keyword"); + return -1; +} + +/** + * \brief Registration function for keyword: filesha1 + */ +void DetectFileSha1Register(void) +{ + sigmatch_table[DETECT_FILESHA1].name = "filesha1"; + sigmatch_table[DETECT_FILESHA1].FileMatch = NULL; + sigmatch_table[DETECT_FILESHA1].Setup = DetectFileSha1SetupNoSupport; + sigmatch_table[DETECT_FILESHA1].Free = NULL; + sigmatch_table[DETECT_FILESHA1].RegisterTests = NULL; + sigmatch_table[DETECT_FILESHA1].flags = SIGMATCH_NOT_BUILT; + + SCLogDebug("registering filesha1 rule option"); + return; +} + +#else /* HAVE_NSS */ + +static int DetectFileSha1Setup (DetectEngineCtx *, Signature *, char *); +static void DetectFileSha1RegisterTests(void); + +/** + * \brief Registration function for keyword: filesha1 + */ +void DetectFileSha1Register(void) +{ + sigmatch_table[DETECT_FILESHA1].name = "filesha1"; + sigmatch_table[DETECT_FILESHA1].desc = "match file SHA-1 against list of SHA-1 checksums"; + sigmatch_table[DETECT_FILESHA1].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filesha1"; + sigmatch_table[DETECT_FILESHA1].FileMatch = DetectFileHashMatch; + sigmatch_table[DETECT_FILESHA1].Setup = DetectFileSha1Setup; + sigmatch_table[DETECT_FILESHA1].Free = DetectFileHashFree; + sigmatch_table[DETECT_FILESHA1].RegisterTests = DetectFileSha1RegisterTests; + + SCLogDebug("registering filesha1 rule option"); + return; +} + +/** + * \brief this function is used to parse filesha1 options + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided "filesha1" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectFileSha1Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA1); +} + +#ifdef UNITTESTS +static int SHA1MatchLookupString(ROHashTable *hash, char *string) +{ + uint8_t sha1[20]; + if (ReadHashString(sha1, string, "file", 88, 40) == 1) { + void *ptr = ROHashLookup(hash, &sha1, (uint16_t)sizeof(sha1)); + if (ptr == NULL) + return 0; + else + return 1; + } + return 0; +} + +static int SHA1MatchTest01(void) +{ + ROHashTable *hash = ROHashInit(4, 20); + if (hash == NULL) { + return 0; + } + if (LoadHashTable(hash, "447661c5de965bd4d837b50244467e37bddc184d", "file", 1, DETECT_FILESHA1) != 1) + return 0; + if (LoadHashTable(hash, "75a9af1e34dc0bb2f7fcde9d56b2503072ac35dd", "file", 2, DETECT_FILESHA1) != 1) + return 0; + if (LoadHashTable(hash, "53224a297bbb30631670fdcd2d295d87a1d328e9", "file", 3, DETECT_FILESHA1) != 1) + return 0; + if (LoadHashTable(hash, "3395856ce81f2b7382dee72602f798b642f14140", "file", 4, DETECT_FILESHA1) != 1) + return 0; + if (LoadHashTable(hash, "65559245709fe98052eb284577f1fd61c01ad20d", "file", 5, DETECT_FILESHA1) != 1) + return 0; + if (LoadHashTable(hash, "0931fd4e05e6ea81c75f8488ecc1db9e66f22cbb", "file", 6, DETECT_FILESHA1) != 1) + return 0; + + if (ROHashInitFinalize(hash) != 1) { + return 0; + } + + if (SHA1MatchLookupString(hash, "447661c5de965bd4d837b50244467e37bddc184d") != 1) + return 0; + if (SHA1MatchLookupString(hash, "75a9af1e34dc0bb2f7fcde9d56b2503072ac35dd") != 1) + return 0; + if (SHA1MatchLookupString(hash, "53224a297bbb30631670fdcd2d295d87a1d328e9") != 1) + return 0; + if (SHA1MatchLookupString(hash, "3395856ce81f2b7382dee72602f798b642f14140") != 1) + return 0; + if (SHA1MatchLookupString(hash, "65559245709fe98052eb284577f1fd61c01ad20d") != 1) + return 0; + if (SHA1MatchLookupString(hash, "0931fd4e05e6ea81c75f8488ecc1db9e66f22cbb") != 1) + return 0; + /* Shouldn't match */ + if (SHA1MatchLookupString(hash, "3333333333333333333333333333333333333333") == 1) + return 0; + + ROHashFree(hash); + return 1; +} +#endif + +void DetectFileSha1RegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SHA1MatchTest01", SHA1MatchTest01); +#endif +} + +#endif /* HAVE_NSS */ diff --git a/src/detect-filesha1.h b/src/detect-filesha1.h new file mode 100644 index 000000000000..d7504344c606 --- /dev/null +++ b/src/detect-filesha1.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2007-2016 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 + * \author Duarte Silva + */ + +#ifndef __DETECT_FILESHA1_H__ +#define __DETECT_FILESHA1_H__ + +/* prototypes */ +void DetectFileSha1Register (void); + +#endif /* __DETECT_FILESHA1_H__ */ diff --git a/src/detect.c b/src/detect.c index c2ad76245a7f..767329b26d12 100644 --- a/src/detect.c +++ b/src/detect.c @@ -108,6 +108,7 @@ #include "detect-filestore.h" #include "detect-filemagic.h" #include "detect-filemd5.h" +#include "detect-filesha1.h" #include "detect-filesize.h" #include "detect-dsize.h" #include "detect-flowvar.h" @@ -1861,6 +1862,14 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh FileDisableMd5(pflow, STREAM_TOSERVER); } + /* see if this sgh requires us to consider file sha1 */ + if (!FileForceSha1() && (pflow->sgh_toserver == NULL || + !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESHA1))) + { + SCLogDebug("disabling sha1 for flow"); + FileDisableSha1(pflow, STREAM_TOSERVER); + } + /* see if this sgh requires us to consider filesize */ if (pflow->sgh_toserver == NULL || !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) @@ -1892,6 +1901,14 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh FileDisableMd5(pflow, STREAM_TOCLIENT); } + /* check if this flow needs sha1, if not disable it */ + if (!FileForceSha1() && (pflow->sgh_toclient == NULL || + !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESHA1))) + { + SCLogDebug("disabling sha1 for flow"); + FileDisableSha1(pflow, STREAM_TOCLIENT); + } + /* see if this sgh requires us to consider filesize */ if (pflow->sgh_toclient == NULL || !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) @@ -2146,10 +2163,23 @@ int SignatureIsFilemagicInspecting(Signature *s) */ int SignatureIsFileMd5Inspecting(Signature *s) { - if (s == NULL) - return 0; + if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_MD5)) + return 1; + + return 0; +} - if (s->file_flags & FILE_SIG_NEED_MD5) +/** + * \brief Check if a signature contains the filesha1 keyword. + * + * \param s signature + * + * \retval 0 no + * \retval 1 yes + */ +int SignatureIsFileSha1Inspecting(Signature *s) +{ + if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_SHA1)) return 1; return 0; @@ -3996,7 +4026,7 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SCLogDebug("sgh %p", sgh); SigGroupHeadSetFilemagicFlag(de_ctx, sgh); - SigGroupHeadSetFileMd5Flag(de_ctx, sgh); + SigGroupHeadSetFileHashFlag(de_ctx, sgh); SigGroupHeadSetFilesizeFlag(de_ctx, sgh); SigGroupHeadSetFilestoreCount(de_ctx, sgh); SCLogDebug("filestore count %u", sgh->filestore_cnt); @@ -4378,6 +4408,7 @@ void SigTableSetup(void) DetectFilestoreRegister(); DetectFilemagicRegister(); DetectFileMd5Register(); + DetectFileSha1Register(); DetectFilesizeRegister(); DetectAppLayerEventRegister(); DetectHttpUARegister(); diff --git a/src/detect.h b/src/detect.h index 3031f4d4c675..b3b947f5edec 100644 --- a/src/detect.h +++ b/src/detect.h @@ -937,11 +937,13 @@ typedef struct SigTableElmt_ { #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) -#define SIG_GROUP_HEAD_MPM_TLSSNI (1 << 24) -#define SIG_GROUP_HEAD_MPM_TLSISSUER (1 << 25) -#define SIG_GROUP_HEAD_MPM_TLSSUBJECT (1 << 26) -#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 27) +#define SIG_GROUP_HEAD_HAVEFILESHA1 (1 << 23) + +#define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 24) +#define SIG_GROUP_HEAD_MPM_TLSSNI (1 << 25) +#define SIG_GROUP_HEAD_MPM_TLSISSUER (1 << 26) +#define SIG_GROUP_HEAD_MPM_TLSSUBJECT (1 << 27) +#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 28) #define APP_MPMS_MAX 21 @@ -1278,6 +1280,7 @@ Signature *DetectGetTagSignature(void); int SignatureIsFilestoring(Signature *); int SignatureIsFilemagicInspecting(Signature *); int SignatureIsFileMd5Inspecting(Signature *); +int SignatureIsFileSha1Inspecting(Signature *s); int SignatureIsFilesizeInspecting(Signature *); int DetectRegisterThreadCtxFuncs(DetectEngineCtx *, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int); diff --git a/src/flow.h b/src/flow.h index b5dbe5708599..182f547c9f25 100644 --- a/src/flow.h +++ b/src/flow.h @@ -66,40 +66,44 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_ACTION_DROP 0x00000200 /** Sgh for toserver direction set (even if it's NULL) */ -#define FLOW_SGH_TOSERVER 0x00000800 +#define FLOW_SGH_TOSERVER 0x00000400 /** Sgh for toclient direction set (even if it's NULL) */ -#define FLOW_SGH_TOCLIENT 0x00001000 +#define FLOW_SGH_TOCLIENT 0x00000800 /** packet to server direction has been logged in drop file (only in IPS mode) */ -#define FLOW_TOSERVER_DROP_LOGGED 0x00002000 +#define FLOW_TOSERVER_DROP_LOGGED 0x00001000 /** packet to client direction has been logged in drop file (only in IPS mode) */ -#define FLOW_TOCLIENT_DROP_LOGGED 0x00004000 +#define FLOW_TOCLIENT_DROP_LOGGED 0x00002000 /** alproto detect done. Right now we need it only for udp */ -#define FLOW_ALPROTO_DETECT_DONE 0x00008000 +#define FLOW_ALPROTO_DETECT_DONE 0x00004000 // vacany 1x /** Pattern matcher alproto detection done */ -#define FLOW_TS_PM_ALPROTO_DETECT_DONE 0x00020000 +#define FLOW_TS_PM_ALPROTO_DETECT_DONE 0x00008000 /** Probing parser alproto detection done */ -#define FLOW_TS_PP_ALPROTO_DETECT_DONE 0x00040000 +#define FLOW_TS_PP_ALPROTO_DETECT_DONE 0x00010000 /** Pattern matcher alproto detection done */ -#define FLOW_TC_PM_ALPROTO_DETECT_DONE 0x00100000 +#define FLOW_TC_PM_ALPROTO_DETECT_DONE 0x00020000 /** Probing parser alproto detection done */ -#define FLOW_TC_PP_ALPROTO_DETECT_DONE 0x00200000 -#define FLOW_TIMEOUT_REASSEMBLY_DONE 0x00800000 +#define FLOW_TC_PP_ALPROTO_DETECT_DONE 0x00040000 +#define FLOW_TIMEOUT_REASSEMBLY_DONE 0x00080000 /** even if the flow has files, don't store 'm */ -#define FLOW_FILE_NO_STORE_TS 0x01000000 -#define FLOW_FILE_NO_STORE_TC 0x02000000 +#define FLOW_FILE_NO_STORE_TS 0x00100000 +#define FLOW_FILE_NO_STORE_TC 0x00200000 /** flow is ipv4 */ -#define FLOW_IPV4 0x04000000 +#define FLOW_IPV4 0x00400000 /** flow is ipv6 */ -#define FLOW_IPV6 0x08000000 +#define FLOW_IPV6 0x00800000 /** no md5 on files in this flow */ -#define FLOW_FILE_NO_MD5_TS 0x10000000 -#define FLOW_FILE_NO_MD5_TC 0x20000000 +#define FLOW_FILE_NO_MD5_TS 0x01000000 +#define FLOW_FILE_NO_MD5_TC 0x02000000 + +/** no sha1 on files in this flow */ +#define FLOW_FILE_NO_SHA1_TS 0x04000000 +#define FLOW_FILE_NO_SHA1_TC 0x08000000 /** no size tracking of files in this flow */ #define FLOW_FILE_NO_SIZE_TS 0x40000000 diff --git a/src/log-file.c b/src/log-file.c index 1b594c5909fe..73cde22685e0 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -290,6 +290,14 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const } fprintf(fp, "\", "); } + if (ff->flags & FILE_SHA1) { + fprintf(fp, "\"sha1\": \""); + size_t x; + for (x = 0; x < sizeof(ff->sha1); x++) { + fprintf(fp, "%02x", ff->sha1[x]); + } + fprintf(fp, "\", "); + } #endif break; case FILE_STATE_TRUNCATED: @@ -437,7 +445,6 @@ static OutputCtx *LogFileLogInitCtx(ConfNode *conf) SCLogInfo("md5 calculation requires linking against libnss"); #endif } - FileForceTrackingEnable(); SCReturnPtr(output_ctx, "OutputCtx"); } diff --git a/src/log-filestore.c b/src/log-filestore.c index 99fa7e38d9b9..b87473ee0c68 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -261,6 +261,14 @@ static void LogFilestoreLogCloseMetaFile(const File *ff) } fprintf(fp, "\n"); } + if (ff->flags & FILE_SHA1) { + fprintf(fp, "SHA1: "); + size_t x; + for (x = 0; x < sizeof(ff->sha1); x++) { + fprintf(fp, "%02x", ff->sha1[x]); + } + fprintf(fp, "\n"); + } #endif break; case FILE_STATE_TRUNCATED: diff --git a/src/output-json-file.c b/src/output-json-file.c index dfc034bdc758..76ad4c3db594 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -134,6 +134,15 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F } json_object_set_new(fjs, "md5", json_string(s)); } + if (ff->flags & FILE_SHA1) { + size_t x; + int i; + char s[256]; + for (i = 0, x = 0; x < sizeof(ff->sha1); x++) { + i += snprintf(&s[i], 255-i, "%02x", ff->sha1[x]); + } + json_object_set_new(fjs, "sha1", json_string(s)); + } #endif break; case FILE_STATE_TRUNCATED: diff --git a/src/suricata.c b/src/suricata.c index 3853d5bee05d..66d94ff78bf1 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2332,7 +2332,7 @@ static int PostConfLoadedSetup(SCInstance *suri) #ifdef HAVE_NSS if (suri->run_mode != RUNMODE_CONF_TEST) { - /* init NSS for md5 */ + /* init NSS for hashing */ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); NSS_NoDB_Init(NULL); } diff --git a/src/util-error.c b/src/util-error.c index 94d3e02d05ac..8b6d48afe803 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -327,6 +327,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_NIC_OFFLOADING); CASE_CODE (SC_ERR_NO_FILES_FOR_PROTOCOL); CASE_CODE (SC_ERR_INVALID_HASH); + CASE_CODE (SC_ERR_NO_SHA1_SUPPORT); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 63eee8ec3b37..312ace1d7a80 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -317,6 +317,7 @@ typedef enum { SC_ERR_NIC_OFFLOADING, SC_ERR_NO_FILES_FOR_PROTOCOL, SC_ERR_INVALID_HASH, + SC_ERR_NO_SHA1_SUPPORT, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-file.c b/src/util-file.c index 3fc7d5ff2309..82efb90e67c5 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -51,6 +51,11 @@ static int g_file_force_magic = 0; */ static int g_file_force_md5 = 0; +/** \brief switch to force sha1 calculation on all files + * regardless of the rules. + */ +static int g_file_force_sha1 = 0; + /** \brief switch to force tracking off all files * regardless of the rules. */ @@ -74,6 +79,11 @@ void FileForceMd5Enable(void) g_file_force_md5 = 1; } +void FileForceSha1Enable(void) +{ + g_file_force_sha1 = 1; +} + int FileForceFilestore(void) { return g_file_force_filestore; @@ -89,6 +99,11 @@ int FileForceMd5(void) return g_file_force_md5; } +int FileForceSha1(void) +{ + return g_file_force_sha1; +} + void FileForceTrackingEnable(void) { g_file_force_tracking = 1; @@ -289,6 +304,8 @@ static void FileFree(File *ff) #ifdef HAVE_NSS if (ff->md5_ctx) HASH_Destroy(ff->md5_ctx); + if (ff->sha1_ctx) + HASH_Destroy(ff->sha1_ctx); #endif SCFree(ff); } @@ -363,6 +380,9 @@ static int AppendData(File *file, const uint8_t *data, uint32_t data_len) if (file->md5_ctx) { HASH_Update(file->md5_ctx, data, data_len); } + if (file->sha1_ctx) { + HASH_Update(file->sha1_ctx, data, data_len); + } #endif SCReturnInt(0); } @@ -396,11 +416,13 @@ int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) if (FileStoreNoStoreCheck(ffc->tail) == 1) { #ifdef HAVE_NSS - /* no storage but forced md5 */ + /* no storage but forced hashing */ if (ffc->tail->md5_ctx) { - if (ffc->tail->md5_ctx) - HASH_Update(ffc->tail->md5_ctx, data, data_len); - + HASH_Update(ffc->tail->md5_ctx, data, data_len); + SCReturnInt(0); + } + if (ffc->tail->sha1_ctx) { + HASH_Update(ffc->tail->sha1_ctx, data, data_len); SCReturnInt(0); } #endif @@ -471,6 +493,10 @@ File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, SCLogDebug("not doing md5 for this file"); ff->flags |= FILE_NOMD5; } + if (flags & FILE_NOSHA1) { + SCLogDebug("not doing sha1 for this file"); + ff->flags |= FILE_NOSHA1; + } if (flags & FILE_USE_DETECT) { SCLogDebug("considering content_inspect tracker when pruning"); ff->flags |= FILE_USE_DETECT; @@ -483,6 +509,12 @@ File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, HASH_Begin(ff->md5_ctx); } } + if (!(ff->flags & FILE_NOSHA1) || g_file_force_sha1) { + ff->sha1_ctx = HASH_Create(HASH_AlgSHA1); + if (ff->sha1_ctx != NULL) { + HASH_Begin(ff->sha1_ctx); + } + } #endif ff->state = FILE_STATE_OPENED; @@ -517,9 +549,11 @@ static int FileCloseFilePtr(File *ff, const uint8_t *data, if (data != NULL) { if (ff->flags & FILE_NOSTORE) { #ifdef HAVE_NSS - /* no storage but md5 */ + /* no storage but hashing */ if (ff->md5_ctx) HASH_Update(ff->md5_ctx, data, data_len); + if (ff->sha1_ctx) + HASH_Update(ff->sha1_ctx, data, data_len); #endif } else { if (AppendData(ff, data, data_len) != 0) { @@ -547,6 +581,11 @@ static int FileCloseFilePtr(File *ff, const uint8_t *data, HASH_End(ff->md5_ctx, ff->md5, &len, sizeof(ff->md5)); ff->flags |= FILE_MD5; } + if (ff->sha1_ctx) { + unsigned int len = 0; + HASH_End(ff->sha1_ctx, ff->sha1, &len, sizeof(ff->sha1)); + ff->flags |= FILE_SHA1; + } #endif } @@ -682,6 +721,45 @@ void FileDisableMd5(Flow *f, uint8_t direction) SCReturn; } +/** + * \brief disable file sha1 calc for this flow + * + * \param f *LOCKED* flow + * \param direction flow direction +*/ +void FileDisableSha1(Flow *f, uint8_t direction) +{ + File *ptr = NULL; + + SCEnter(); + + DEBUG_ASSERT_FLOW_LOCKED(f); + + if (direction == STREAM_TOSERVER) + f->flags |= FLOW_FILE_NO_SHA1_TS; + else + f->flags |= FLOW_FILE_NO_SHA1_TC; + + FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); + if (ffc != NULL) { + for (ptr = ffc->head; ptr != NULL; ptr = ptr->next) { + SCLogDebug("disabling sha1 for file %p from direction %s", + ptr, direction == STREAM_TOSERVER ? "toserver":"toclient"); + ptr->flags |= FILE_NOSHA1; + +#ifdef HAVE_NSS + /* destroy any ctx we may have so far */ + if (ptr->sha1_ctx != NULL) { + HASH_Destroy(ptr->sha1_ctx); + ptr->sha1_ctx = NULL; + } +#endif + } + } + + SCReturn; +} + /** * \brief disable file size tracking for this flow * @@ -731,7 +809,7 @@ void FileDisableStoringForFile(File *ff) ff->flags |= FILE_NOSTORE; if (ff->state == FILE_STATE_OPENED && FileSize(ff) >= (uint64_t)FileMagicSize()) { - if (g_file_force_md5 == 0 && g_file_force_tracking == 0) { + if (g_file_force_md5 == 0 && g_file_force_sha1 == 0 && g_file_force_tracking == 0) { (void)FileCloseFilePtr(ff, NULL, 0, (FILE_TRUNCATED|FILE_NOSTORE)); } diff --git a/src/util-file.h b/src/util-file.h index 96fee17a90f7..0c476bd9f429 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -189,6 +189,10 @@ void FileDisableMd5(Flow *f, uint8_t); void FileForceMd5Enable(void); int FileForceMd5(void); +void FileDisableSha1(Flow *f, uint8_t); +void FileForceSha1Enable(void); +int FileForceSha1(void); + void FileForceTrackingEnable(void); void FileStoreAllFiles(FileContainer *); diff --git a/src/util-lua-common.c b/src/util-lua-common.c index 367374d76ca6..4b712b9f627d 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -593,8 +593,19 @@ static int LuaCallbackFileInfoPushToStackFromFile(lua_State *luastate, const Fil strlcat(md5, one, sizeof(md5)); } } + char sha1[41] = ""; + char *sha1ptr = sha1; + if (file->flags & FILE_SHA1) { + size_t x; + for (x = 0; x < sizeof(file->sha1); x++) { + char one[3] = ""; + snprintf(one, sizeof(one), "%02x", file->sha1[x]); + strlcat(sha1, one, sizeof(sha1)); + } + } #else char *md5ptr = NULL; + char *sha1ptr = NULL; #endif lua_pushnumber(luastate, file->file_id); @@ -603,6 +614,7 @@ static int LuaCallbackFileInfoPushToStackFromFile(lua_State *luastate, const Fil lua_pushnumber(luastate, FileSize(file)); lua_pushstring (luastate, file->magic); lua_pushstring(luastate, md5ptr); + lua_pushstring(luastate, sha1ptr); return 6; } From 89eb935f733c6b7d1521d140226ae1b2c251853a Mon Sep 17 00:00:00 2001 From: Duarte Silva Date: Fri, 29 Apr 2016 22:23:55 +0200 Subject: [PATCH 1702/2553] file-hashing: added support for SHA-256 file hashing --- src/Makefile.am | 1 + src/app-layer-htp-file.c | 10 +++ src/app-layer-smtp.c | 4 + src/detect-engine-file.c | 6 ++ src/detect-engine-siggroup.c | 6 ++ src/detect-filemd5.c | 1 - src/detect-filesha1.c | 1 - src/detect-filesha256.c | 161 +++++++++++++++++++++++++++++++++++ src/detect-filesha256.h | 31 +++++++ src/detect.c | 34 ++++++++ src/detect.h | 12 +-- src/flow.h | 4 + src/log-file.c | 8 ++ src/log-filestore.c | 8 ++ src/output-json-file.c | 9 ++ src/util-error.c | 1 + src/util-error.h | 1 + src/util-file.c | 83 +++++++++++++++++- src/util-file.h | 4 + src/util-lua-common.c | 12 +++ 20 files changed, 389 insertions(+), 8 deletions(-) create mode 100644 src/detect-filesha256.c create mode 100644 src/detect-filesha256.h diff --git a/src/Makefile.am b/src/Makefile.am index edc6d65d2eb1..c19d33cf039a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -139,6 +139,7 @@ detect-fileext.c detect-fileext.h \ detect-filemagic.c detect-filemagic.h \ detect-filemd5.c detect-filemd5.h \ detect-filesha1.c detect-filesha1.h \ +detect-filesha256.c detect-filesha256.h \ detect-filename.c detect-filename.h \ detect-filesize.c detect-filesize.h \ detect-filestore.c detect-filestore.h \ diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index 18b193612bd4..fa3ac654f187 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -123,6 +123,11 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, flags |= FILE_NOSHA1; } + if (s->f->flags & FLOW_FILE_NO_SHA256_TC) { + SCLogDebug("no sha256 for this flow in toclient direction, so none for this file"); + flags |= FILE_NOSHA256; + } + if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TC)) { flags |= FILE_NOSTORE; } @@ -160,6 +165,11 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, flags |= FILE_NOSHA1; } + if (s->f->flags & FLOW_FILE_NO_SHA256_TS) { + SCLogDebug("no sha256 for this flow in toserver direction, so none for this file"); + flags |= FILE_NOSHA256; + } + if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TS)) { flags |= FILE_NOSTORE; } diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index f8b25c9470e4..2d584a7c4785 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -427,6 +427,10 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, flags |= FILE_NOSHA1; } + if (flow->flags & FLOW_FILE_NO_SHA256_TS) { + flags |= FILE_NOSHA256; + } + /* Find file */ if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index 5eb36e853d78..dafb28a880e5 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -135,6 +135,12 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, break; } + if ((s->file_flags & FILE_SIG_NEED_SHA256) && (!(file->flags & FILE_SHA256))) { + SCLogDebug("sig needs file sha256, but we don't have any"); + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + break; + } + if ((s->file_flags & FILE_SIG_NEED_SIZE) && file->state < FILE_STATE_CLOSED) { SCLogDebug("sig needs filesize, but state < FILE_STATE_CLOSED"); r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 58a3058ad27e..22019a3d3625 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -637,6 +637,12 @@ void SigGroupHeadSetFileHashFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) SCLogDebug("sgh %p has filesha1", sgh); break; } + + if (SignatureIsFileSha256Inspecting(s)) { + sgh->flags |= SIG_GROUP_HEAD_HAVEFILESHA256; + SCLogDebug("sgh %p has filesha256", sgh); + break; + } } return; diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index 6d8be5394e5e..c5cf4c192401 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -25,7 +25,6 @@ #include "suricata-common.h" #include "util-detect-file-hash.h" - #include "util-unittest.h" #include "util-unittest-helper.h" diff --git a/src/detect-filesha1.c b/src/detect-filesha1.c index ea4e469bfb91..ad1886648849 100644 --- a/src/detect-filesha1.c +++ b/src/detect-filesha1.c @@ -26,7 +26,6 @@ #include "suricata-common.h" #include "util-detect-file-hash.h" - #include "util-unittest.h" #include "util-unittest-helper.h" diff --git a/src/detect-filesha256.c b/src/detect-filesha256.c new file mode 100644 index 000000000000..4310445080c4 --- /dev/null +++ b/src/detect-filesha256.c @@ -0,0 +1,161 @@ +/* Copyright (C) 2007-2016 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 + * \author Duarte Silva + * + */ + +#include "suricata-common.h" + +#include "util-detect-file-hash.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +#include "detect-filesha256.h" + +#ifndef HAVE_NSS + +static int DetectFileSha256SetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) +{ + SCLogError(SC_ERR_NO_SHA256_SUPPORT, "no SHA-256 calculation support built in, needed for filesha256 keyword"); + return -1; +} + +/** + * \brief Registration function for keyword: filesha256 + */ +void DetectFileSha256Register(void) +{ + sigmatch_table[DETECT_FILESHA256].name = "filesha256"; + sigmatch_table[DETECT_FILESHA256].FileMatch = NULL; + sigmatch_table[DETECT_FILESHA256].Setup = DetectFileSha256SetupNoSupport; + sigmatch_table[DETECT_FILESHA256].Free = NULL; + sigmatch_table[DETECT_FILESHA256].RegisterTests = NULL; + sigmatch_table[DETECT_FILESHA256].flags = SIGMATCH_NOT_BUILT; + + SCLogDebug("registering filesha256 rule option"); + return; +} + +#else /* HAVE_NSS */ + +static int DetectFileSha256Setup (DetectEngineCtx *, Signature *, char *); +static void DetectFileSha256RegisterTests(void); + +/** + * \brief Registration function for keyword: filesha256 + */ +void DetectFileSha256Register(void) +{ + sigmatch_table[DETECT_FILESHA256].name = "filesha256"; + sigmatch_table[DETECT_FILESHA256].desc = "match file SHA-256 against list of SHA-256 checksums"; + sigmatch_table[DETECT_FILESHA256].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filesha256"; + sigmatch_table[DETECT_FILESHA256].FileMatch = DetectFileHashMatch; + sigmatch_table[DETECT_FILESHA256].Setup = DetectFileSha256Setup; + sigmatch_table[DETECT_FILESHA256].Free = DetectFileHashFree; + sigmatch_table[DETECT_FILESHA256].RegisterTests = DetectFileSha256RegisterTests; + + SCLogDebug("registering filesha256 rule option"); + return; +} + +/** + * \brief this function is used to parse filesha256 options + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided "filesha256" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectFileSha256Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA256); +} + +#ifdef UNITTESTS +static int SHA256MatchLookupString(ROHashTable *hash, char *string) +{ + uint8_t sha256[32]; + if (ReadHashString(sha256, string, "file", 88, 64) == 1) { + void *ptr = ROHashLookup(hash, &sha256, (uint16_t)sizeof(sha256)); + if (ptr == NULL) + return 0; + else + return 1; + } + return 0; +} + +static int SHA256MatchTest01(void) +{ + ROHashTable *hash = ROHashInit(4, 32); + if (hash == NULL) { + return 0; + } + if (LoadHashTable(hash, "9c891edb5da763398969b6aaa86a5d46971bd28a455b20c2067cb512c9f9a0f8", "file", 1, DETECT_FILESHA256) != 1) + return 0; + if (LoadHashTable(hash, "6eee51705f34b6cfc7f0c872a7949ec3e3172a908303baf5d67d03b98f70e7e3", "file", 2, DETECT_FILESHA256) != 1) + return 0; + if (LoadHashTable(hash, "b12c7d57507286bbbe36d7acf9b34c22c96606ffd904e3c23008399a4a50c047", "file", 3, DETECT_FILESHA256) != 1) + return 0; + if (LoadHashTable(hash, "ca496e1ddadc290050339dd75ce8830ad3028ce1556a5368874a4aec3aee114b", "file", 4, DETECT_FILESHA256) != 1) + return 0; + if (LoadHashTable(hash, "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f", "file", 5, DETECT_FILESHA256) != 1) + return 0; + if (LoadHashTable(hash, "d765e722e295969c0a5c2d90f549db8b89ab617900bf4698db41c7cdad993bb9", "file", 6, DETECT_FILESHA256) != 1) + return 0; + + if (ROHashInitFinalize(hash) != 1) { + return 0; + } + + if (SHA256MatchLookupString(hash, "9c891edb5da763398969b6aaa86a5d46971bd28a455b20c2067cb512c9f9a0f8") != 1) + return 0; + if (SHA256MatchLookupString(hash, "6eee51705f34b6cfc7f0c872a7949ec3e3172a908303baf5d67d03b98f70e7e3") != 1) + return 0; + if (SHA256MatchLookupString(hash, "b12c7d57507286bbbe36d7acf9b34c22c96606ffd904e3c23008399a4a50c047") != 1) + return 0; + if (SHA256MatchLookupString(hash, "ca496e1ddadc290050339dd75ce8830ad3028ce1556a5368874a4aec3aee114b") != 1) + return 0; + if (SHA256MatchLookupString(hash, "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f") != 1) + return 0; + if (SHA256MatchLookupString(hash, "d765e722e295969c0a5c2d90f549db8b89ab617900bf4698db41c7cdad993bb9") != 1) + return 0; + /* Shouldn't match */ + if (SHA256MatchLookupString(hash, "3333333333333333333333333333333333333333333333333333333333333333") == 1) + return 0; + + ROHashFree(hash); + return 1; +} +#endif + +void DetectFileSha256RegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SHA256MatchTest01", SHA256MatchTest01); +#endif +} + +#endif /* HAVE_NSS */ diff --git a/src/detect-filesha256.h b/src/detect-filesha256.h new file mode 100644 index 000000000000..a205b48699a0 --- /dev/null +++ b/src/detect-filesha256.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2007-2016 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 + * \author Duarte Silva + */ + +#ifndef __DETECT_FILESHA256_H__ +#define __DETECT_FILESHA256_H__ + +/* prototypes */ +void DetectFileSha256Register (void); + +#endif /* __DETECT_FILESHA256_H__ */ diff --git a/src/detect.c b/src/detect.c index 767329b26d12..aeb8123064b0 100644 --- a/src/detect.c +++ b/src/detect.c @@ -109,6 +109,7 @@ #include "detect-filemagic.h" #include "detect-filemd5.h" #include "detect-filesha1.h" +#include "detect-filesha256.h" #include "detect-filesize.h" #include "detect-dsize.h" #include "detect-flowvar.h" @@ -1870,6 +1871,14 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh FileDisableSha1(pflow, STREAM_TOSERVER); } + /* see if this sgh requires us to consider file sha256 */ + if (!FileForceSha256() && (pflow->sgh_toserver == NULL || + !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESHA256))) + { + SCLogDebug("disabling sha256 for flow"); + FileDisableSha256(pflow, STREAM_TOSERVER); + } + /* see if this sgh requires us to consider filesize */ if (pflow->sgh_toserver == NULL || !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) @@ -1909,6 +1918,14 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh FileDisableSha1(pflow, STREAM_TOCLIENT); } + /* check if this flow needs sha256, if not disable it */ + if (!FileForceSha256() && (pflow->sgh_toclient == NULL || + !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESHA256))) + { + SCLogDebug("disabling sha256 for flow"); + FileDisableSha256(pflow, STREAM_TOCLIENT); + } + /* see if this sgh requires us to consider filesize */ if (pflow->sgh_toclient == NULL || !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) @@ -2185,6 +2202,22 @@ int SignatureIsFileSha1Inspecting(Signature *s) return 0; } +/** + * \brief Check if a signature contains the filesha256 keyword. + * + * \param s signature + * + * \retval 0 no + * \retval 1 yes + */ +int SignatureIsFileSha256Inspecting(Signature *s) +{ + if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_SHA256)) + return 1; + + return 0; +} + /** * \brief Check if a signature contains the filesize keyword. * @@ -4409,6 +4442,7 @@ void SigTableSetup(void) DetectFilemagicRegister(); DetectFileMd5Register(); DetectFileSha1Register(); + DetectFileSha256Register(); DetectFilesizeRegister(); DetectAppLayerEventRegister(); DetectHttpUARegister(); diff --git a/src/detect.h b/src/detect.h index b3b947f5edec..260f23f7cb1b 100644 --- a/src/detect.h +++ b/src/detect.h @@ -938,12 +938,13 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_HAVEFILEMD5 (1 << 21) #define SIG_GROUP_HEAD_HAVEFILESIZE (1 << 22) #define SIG_GROUP_HEAD_HAVEFILESHA1 (1 << 23) +#define SIG_GROUP_HEAD_HAVEFILESHA256 (1 << 24) -#define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 24) -#define SIG_GROUP_HEAD_MPM_TLSSNI (1 << 25) -#define SIG_GROUP_HEAD_MPM_TLSISSUER (1 << 26) -#define SIG_GROUP_HEAD_MPM_TLSSUBJECT (1 << 27) -#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 28) +#define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 25) +#define SIG_GROUP_HEAD_MPM_TLSSNI (1 << 26) +#define SIG_GROUP_HEAD_MPM_TLSISSUER (1 << 27) +#define SIG_GROUP_HEAD_MPM_TLSSUBJECT (1 << 28) +#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 29) #define APP_MPMS_MAX 21 @@ -1281,6 +1282,7 @@ int SignatureIsFilestoring(Signature *); int SignatureIsFilemagicInspecting(Signature *); int SignatureIsFileMd5Inspecting(Signature *); int SignatureIsFileSha1Inspecting(Signature *s); +int SignatureIsFileSha256Inspecting(Signature *s); int SignatureIsFilesizeInspecting(Signature *); int DetectRegisterThreadCtxFuncs(DetectEngineCtx *, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int); diff --git a/src/flow.h b/src/flow.h index 182f547c9f25..199b17ee94af 100644 --- a/src/flow.h +++ b/src/flow.h @@ -105,6 +105,10 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_FILE_NO_SHA1_TS 0x04000000 #define FLOW_FILE_NO_SHA1_TC 0x08000000 +/** no sha256 on files in this flow */ +#define FLOW_FILE_NO_SHA256_TS 0x10000000 +#define FLOW_FILE_NO_SHA256_TC 0x20000000 + /** no size tracking of files in this flow */ #define FLOW_FILE_NO_SIZE_TS 0x40000000 #define FLOW_FILE_NO_SIZE_TC 0x80000000 diff --git a/src/log-file.c b/src/log-file.c index 73cde22685e0..bd5a5855eb87 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -298,6 +298,14 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const } fprintf(fp, "\", "); } + if (ff->flags & FILE_SHA256) { + fprintf(fp, "\"sha256\": \""); + size_t x; + for (x = 0; x < sizeof(ff->sha256); x++) { + fprintf(fp, "%02x", ff->sha256[x]); + } + fprintf(fp, "\", "); + } #endif break; case FILE_STATE_TRUNCATED: diff --git a/src/log-filestore.c b/src/log-filestore.c index b87473ee0c68..d6be8f5f80fa 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -269,6 +269,14 @@ static void LogFilestoreLogCloseMetaFile(const File *ff) } fprintf(fp, "\n"); } + if (ff->flags & FILE_SHA256) { + fprintf(fp, "SHA256: "); + size_t x; + for (x = 0; x < sizeof(ff->sha256); x++) { + fprintf(fp, "%02x", ff->sha256[x]); + } + fprintf(fp, "\n"); + } #endif break; case FILE_STATE_TRUNCATED: diff --git a/src/output-json-file.c b/src/output-json-file.c index 76ad4c3db594..fb39bef7204d 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -143,6 +143,15 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F } json_object_set_new(fjs, "sha1", json_string(s)); } + if (ff->flags & FILE_SHA256) { + size_t x; + int i; + char s[256]; + for (i = 0, x = 0; x < sizeof(ff->sha256); x++) { + i += snprintf(&s[i], 255-i, "%02x", ff->sha256[x]); + } + json_object_set_new(fjs, "sha256", json_string(s)); + } #endif break; case FILE_STATE_TRUNCATED: diff --git a/src/util-error.c b/src/util-error.c index 8b6d48afe803..7e13f67d8a6e 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -328,6 +328,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_NO_FILES_FOR_PROTOCOL); CASE_CODE (SC_ERR_INVALID_HASH); CASE_CODE (SC_ERR_NO_SHA1_SUPPORT); + CASE_CODE (SC_ERR_NO_SHA256_SUPPORT); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 312ace1d7a80..6aef68cbb9bc 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -318,6 +318,7 @@ typedef enum { SC_ERR_NO_FILES_FOR_PROTOCOL, SC_ERR_INVALID_HASH, SC_ERR_NO_SHA1_SUPPORT, + SC_ERR_NO_SHA256_SUPPORT, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-file.c b/src/util-file.c index 82efb90e67c5..f44549c6aa69 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -56,6 +56,11 @@ static int g_file_force_md5 = 0; */ static int g_file_force_sha1 = 0; +/** \brief switch to force sha256 calculation on all files + * regardless of the rules. + */ +static int g_file_force_sha256 = 0; + /** \brief switch to force tracking off all files * regardless of the rules. */ @@ -84,6 +89,11 @@ void FileForceSha1Enable(void) g_file_force_sha1 = 1; } +void FileForceSha256Enable(void) +{ + g_file_force_sha256 = 1; +} + int FileForceFilestore(void) { return g_file_force_filestore; @@ -104,6 +114,11 @@ int FileForceSha1(void) return g_file_force_sha1; } +int FileForceSha256(void) +{ + return g_file_force_sha256; +} + void FileForceTrackingEnable(void) { g_file_force_tracking = 1; @@ -306,6 +321,8 @@ static void FileFree(File *ff) HASH_Destroy(ff->md5_ctx); if (ff->sha1_ctx) HASH_Destroy(ff->sha1_ctx); + if (ff->sha256_ctx) + HASH_Destroy(ff->sha256_ctx); #endif SCFree(ff); } @@ -383,6 +400,9 @@ static int AppendData(File *file, const uint8_t *data, uint32_t data_len) if (file->sha1_ctx) { HASH_Update(file->sha1_ctx, data, data_len); } + if (file->sha256_ctx) { + HASH_Update(file->sha256_ctx, data, data_len); + } #endif SCReturnInt(0); } @@ -425,6 +445,10 @@ int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) HASH_Update(ffc->tail->sha1_ctx, data, data_len); SCReturnInt(0); } + if (ffc->tail->sha256_ctx) { + HASH_Update(ffc->tail->sha256_ctx, data, data_len); + SCReturnInt(0); + } #endif if (g_file_force_tracking || (!(ffc->tail->flags & FILE_NOTRACK))) SCReturnInt(0); @@ -497,6 +521,10 @@ File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, SCLogDebug("not doing sha1 for this file"); ff->flags |= FILE_NOSHA1; } + if (flags & FILE_NOSHA256) { + SCLogDebug("not doing sha256 for this file"); + ff->flags |= FILE_NOSHA256; + } if (flags & FILE_USE_DETECT) { SCLogDebug("considering content_inspect tracker when pruning"); ff->flags |= FILE_USE_DETECT; @@ -515,6 +543,12 @@ File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, HASH_Begin(ff->sha1_ctx); } } + if (!(ff->flags & FILE_NOSHA256) || g_file_force_sha256) { + ff->sha256_ctx = HASH_Create(HASH_AlgSHA256); + if (ff->sha256_ctx != NULL) { + HASH_Begin(ff->sha256_ctx); + } + } #endif ff->state = FILE_STATE_OPENED; @@ -554,6 +588,8 @@ static int FileCloseFilePtr(File *ff, const uint8_t *data, HASH_Update(ff->md5_ctx, data, data_len); if (ff->sha1_ctx) HASH_Update(ff->sha1_ctx, data, data_len); + if (ff->sha256_ctx) + HASH_Update(ff->sha256_ctx, data, data_len); #endif } else { if (AppendData(ff, data, data_len) != 0) { @@ -586,6 +622,11 @@ static int FileCloseFilePtr(File *ff, const uint8_t *data, HASH_End(ff->sha1_ctx, ff->sha1, &len, sizeof(ff->sha1)); ff->flags |= FILE_SHA1; } + if (ff->sha256_ctx) { + unsigned int len = 0; + HASH_End(ff->sha256_ctx, ff->sha256, &len, sizeof(ff->sha256)); + ff->flags |= FILE_SHA256; + } #endif } @@ -760,6 +801,45 @@ void FileDisableSha1(Flow *f, uint8_t direction) SCReturn; } +/** + * \brief disable file sha256 calc for this flow + * + * \param f *LOCKED* flow + * \param direction flow direction + */ +void FileDisableSha256(Flow *f, uint8_t direction) +{ + File *ptr = NULL; + + SCEnter(); + + DEBUG_ASSERT_FLOW_LOCKED(f); + + if (direction == STREAM_TOSERVER) + f->flags |= FLOW_FILE_NO_SHA256_TS; + else + f->flags |= FLOW_FILE_NO_SHA256_TC; + + FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); + if (ffc != NULL) { + for (ptr = ffc->head; ptr != NULL; ptr = ptr->next) { + SCLogDebug("disabling sha256 for file %p from direction %s", + ptr, direction == STREAM_TOSERVER ? "toserver":"toclient"); + ptr->flags |= FILE_NOSHA256; + +#ifdef HAVE_NSS + /* destroy any ctx we may have so far */ + if (ptr->sha256_ctx != NULL) { + HASH_Destroy(ptr->sha256_ctx); + ptr->sha256_ctx = NULL; + } +#endif + } + } + + SCReturn; +} + /** * \brief disable file size tracking for this flow * @@ -809,7 +889,8 @@ void FileDisableStoringForFile(File *ff) ff->flags |= FILE_NOSTORE; if (ff->state == FILE_STATE_OPENED && FileSize(ff) >= (uint64_t)FileMagicSize()) { - if (g_file_force_md5 == 0 && g_file_force_sha1 == 0 && g_file_force_tracking == 0) { + if (g_file_force_md5 == 0 && g_file_force_sha1 == 0 && g_file_force_sha256 == 0 + && g_file_force_tracking == 0) { (void)FileCloseFilePtr(ff, NULL, 0, (FILE_TRUNCATED|FILE_NOSTORE)); } diff --git a/src/util-file.h b/src/util-file.h index 0c476bd9f429..fa9d75276bc5 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -193,6 +193,10 @@ void FileDisableSha1(Flow *f, uint8_t); void FileForceSha1Enable(void); int FileForceSha1(void); +void FileDisableSha256(Flow *f, uint8_t); +void FileForceSha256Enable(void); +int FileForceSha256(void); + void FileForceTrackingEnable(void); void FileStoreAllFiles(FileContainer *); diff --git a/src/util-lua-common.c b/src/util-lua-common.c index 4b712b9f627d..3c9e7718d9a8 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -603,9 +603,20 @@ static int LuaCallbackFileInfoPushToStackFromFile(lua_State *luastate, const Fil strlcat(sha1, one, sizeof(sha1)); } } + char sha256[65] = ""; + char *sha256ptr = sha256; + if (file->flags & FILE_SHA256) { + size_t x; + for (x = 0; x < sizeof(file->sha256); x++) { + char one[3] = ""; + snprintf(one, sizeof(one), "%02x", file->sha256[x]); + strlcat(sha256, one, sizeof(sha256)); + } + } #else char *md5ptr = NULL; char *sha1ptr = NULL; + char *sha256ptr = NULL; #endif lua_pushnumber(luastate, file->file_id); @@ -615,6 +626,7 @@ static int LuaCallbackFileInfoPushToStackFromFile(lua_State *luastate, const Fil lua_pushstring (luastate, file->magic); lua_pushstring(luastate, md5ptr); lua_pushstring(luastate, sha1ptr); + lua_pushstring(luastate, sha256ptr); return 6; } From 53ebe4c5380781c740106e445e7782e3cbfee0a5 Mon Sep 17 00:00:00 2001 From: Duarte Silva Date: Tue, 24 May 2016 19:58:13 +0200 Subject: [PATCH 1703/2553] file-hashing: added configuration options and common parsing code --- src/log-file.c | 10 +------- src/log-filestore.c | 10 +------- src/output-json-file.c | 10 +------- src/util-detect-file-hash.c | 6 ++--- src/util-detect-file-hash.h | 2 +- src/util-file.c | 51 +++++++++++++++++++++++++++++++++++++ src/util-file.h | 4 +++ suricata.yaml.in | 12 ++++++--- 8 files changed, 71 insertions(+), 34 deletions(-) diff --git a/src/log-file.c b/src/log-file.c index bd5a5855eb87..19821a22f885 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -444,15 +444,7 @@ static OutputCtx *LogFileLogInitCtx(ConfNode *conf) SCLogInfo("forcing magic lookup for logged files"); } - const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); - if (force_md5 != NULL && ConfValIsTrue(force_md5)) { -#ifdef HAVE_NSS - FileForceMd5Enable(); - SCLogInfo("forcing md5 calculation for logged files"); -#else - SCLogInfo("md5 calculation requires linking against libnss"); -#endif - } + FileForceHashParseCfg(conf); FileForceTrackingEnable(); SCReturnPtr(output_ctx, "OutputCtx"); } diff --git a/src/log-filestore.c b/src/log-filestore.c index d6be8f5f80fa..d793d341e28c 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -481,15 +481,7 @@ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) SCLogInfo("forcing magic lookup for stored files"); } - const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); - if (force_md5 != NULL && ConfValIsTrue(force_md5)) { -#ifdef HAVE_NSS - FileForceMd5Enable(); - SCLogInfo("forcing md5 calculation for stored files"); -#else - SCLogInfo("md5 calculation requires linking against libnss"); -#endif - } + FileForceHashParseCfg(conf); SCLogInfo("storing files in %s", g_logfile_base_dir); SCReturnPtr(output_ctx, "OutputCtx"); diff --git a/src/output-json-file.c b/src/output-json-file.c index fb39bef7204d..4fb08b5ea190 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -288,15 +288,7 @@ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) SCLogConfig("forcing magic lookup for logged files"); } - const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); - if (force_md5 != NULL && ConfValIsTrue(force_md5)) { -#ifdef HAVE_NSS - FileForceMd5Enable(); - SCLogConfig("forcing md5 calculation for logged files"); -#else - SCLogInfo("md5 calculation requires linking against libnss"); -#endif - } + FileForceHashParseCfg(conf); } output_ctx->data = output_file_ctx; diff --git a/src/util-detect-file-hash.c b/src/util-detect-file-hash.c index 49b93eb8f766..2cd884975f1d 100644 --- a/src/util-detect-file-hash.c +++ b/src/util-detect-file-hash.c @@ -194,13 +194,13 @@ int DetectFileHashMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, } /** - * \brief Parse the filemd5 keyword + * \brief Parse the filemd5, filesha1 or filesha256 keyword * * \param det_ctx pattern matcher thread local data * \param str Pointer to the user provided option * \param type the hash algorithm * - * \retval filemd5 pointer to DetectFileHashData on success + * \retval hash pointer to DetectFileHashData on success * \retval NULL on failure */ static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, @@ -210,7 +210,7 @@ static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, FILE *fp = NULL; char *filename = NULL; - /* We have a correct filemd5 option */ + /* We have a correct hash algorithm option */ filehash = SCMalloc(sizeof(DetectFileHashData)); if (unlikely(filehash == NULL)) goto error; diff --git a/src/util-detect-file-hash.h b/src/util-detect-file-hash.h index 19d5418c3e5a..0e9835bb4d78 100644 --- a/src/util-detect-file-hash.h +++ b/src/util-detect-file-hash.h @@ -28,7 +28,7 @@ #include "util-rohash.h" -typedef struct DetectFileHashData { +typedef struct DetectFileHashData_ { ROHashTable *hash; int negated; } DetectFileHashData; diff --git a/src/util-file.c b/src/util-file.c index f44549c6aa69..ff35508161a7 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -124,6 +124,57 @@ void FileForceTrackingEnable(void) g_file_force_tracking = 1; } + +/** + * \brief Function to parse forced file hashing configuration. + */ +void FileForceHashParseCfg(ConfNode *conf) +{ + BUG_ON(conf == NULL); + + ConfNode *forcehash_node = NULL; + + if (conf != NULL) + forcehash_node = ConfNodeLookupChild(conf, "force-hash"); + + if (forcehash_node != NULL) { + ConfNode *field = NULL; + + TAILQ_FOREACH(field, &forcehash_node->head, next) { + if (field == NULL) { + break; + } + + if (strcasecmp("md5", field->val) == 0) { +#ifdef HAVE_NSS + FileForceMd5Enable(); + SCLogConfig("forcing md5 calculation for logged or stored files"); +#else + SCLogInfo("md5 calculation requires linking against libnss"); +#endif + } + + if (strcasecmp("sha1", field->val) == 0) { +#ifdef HAVE_NSS + FileForceSha1Enable(); + SCLogConfig("forcing sha1 calculation for logged or stored files"); +#else + SCLogInfo("sha1 calculation requires linking against libnss"); +#endif + } + + if (strcasecmp("sha256", field->val) == 0) { +#ifdef HAVE_NSS + FileForceSha256Enable(); + SCLogConfig("forcing sha256 calculation for logged or stored files"); +#else + SCLogInfo("sha256 calculation requires linking against libnss"); +#endif + } + } + } +} + int FileMagicSize(void) { /** \todo make this size configurable */ diff --git a/src/util-file.h b/src/util-file.h index fa9d75276bc5..9f55d8304c9c 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -29,6 +29,8 @@ #include #endif +#include "conf.h" + #include "util-streaming-buffer.h" #define FILE_TRUNCATED 0x0001 @@ -197,6 +199,8 @@ void FileDisableSha256(Flow *f, uint8_t); void FileForceSha256Enable(void); int FileForceSha256(void); +void FileForceHashParseCfg(ConfNode *); + void FileForceTrackingEnable(void); void FileStoreAllFiles(FileContainer *); diff --git a/suricata.yaml.in b/suricata.yaml.in index 7f4d075c119e..f8be4b3d2747 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -202,7 +202,9 @@ outputs: extended: yes # enable this for extended logging information - files: force-magic: no # force logging magic on all logged files - force-md5: no # force logging of md5 checksums + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] #- drop: # alerts: yes # log alerts that caused drops # flows: all # start or all: 'start' logs only a single drop @@ -399,7 +401,9 @@ outputs: enabled: no # set to yes to enable log-dir: files # directory to store the files force-magic: no # force logging magic on all stored files - force-md5: no # force logging of md5 checksums + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] force-filestore: no # force storing of all files #waldo: file.waldo # waldo file to store the file_id across runs @@ -411,7 +415,9 @@ outputs: #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' force-magic: no # force logging magic on all logged files - force-md5: no # force logging of md5 checksums + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] # Log TCP data after stream normalization # 2 types: file or dir. File logs into a single logfile. Dir creates From 2f5663dfe9bb9e8f6c85869b0aa1e76f0efede72 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 10:26:12 +0200 Subject: [PATCH 1704/2553] common: introduce BIT_U16 --- src/suricata-common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/suricata-common.h b/src/suricata-common.h index 09887df58eec..cb2c214837a5 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -305,6 +305,7 @@ #define MAX(x, y) (((x)<(y))?(y):(x)) #endif +#define BIT_U16(n) ((uint16_t)(1 << (n))) #define BIT_U32(n) (1UL << (n)) #define BIT_U64(n) (1ULL << (n)) From 4426f3ff5522c60a32dc1e900b0a478ef70f5146 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 10:26:56 +0200 Subject: [PATCH 1705/2553] file: introduce common flags handling function --- src/app-layer-htp-file.c | 54 ++++++---------------------------------- src/app-layer-smtp.c | 26 +++---------------- src/util-file.c | 48 +++++++++++++++++++++++++++++++++++ src/util-file.h | 30 +++++++++++----------- 4 files changed, 76 insertions(+), 82 deletions(-) diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index fa3ac654f187..0045bbaad7c1 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -80,7 +80,7 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, uint64_t txid, uint8_t direction) { int retval = 0; - uint8_t flags = 0; + uint16_t flags = 0; FileContainer *files = NULL; FileContainer *files_opposite = NULL; const StreamingBufferConfig *sbcfg = NULL; @@ -103,32 +103,13 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, files = s->files_tc; files_opposite = s->files_ts; + flags = FileFlowToFlags(s->f, STREAM_TOCLIENT); + if ((s->flags & HTP_FLAG_STORE_FILES_TS) || ((s->flags & HTP_FLAG_STORE_FILES_TX_TS) && txid == s->store_tx_id)) { flags |= FILE_STORE; - } - - if (s->f->flags & FLOW_FILE_NO_MAGIC_TC) { - SCLogDebug("no magic for this flow in toclient direction, so none for this file"); - flags |= FILE_NOMAGIC; - } - - if (s->f->flags & FLOW_FILE_NO_MD5_TC) { - SCLogDebug("no md5 for this flow in toclient direction, so none for this file"); - flags |= FILE_NOMD5; - } - - if (s->f->flags & FLOW_FILE_NO_SHA1_TC) { - SCLogDebug("no sha1 for this flow in toclient direction, so none for this file"); - flags |= FILE_NOSHA1; - } - - if (s->f->flags & FLOW_FILE_NO_SHA256_TC) { - SCLogDebug("no sha256 for this flow in toclient direction, so none for this file"); - flags |= FILE_NOSHA256; - } - - if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TC)) { + flags &= ~FILE_NOSTORE; + } else if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TC)) { flags |= FILE_NOSTORE; } @@ -146,31 +127,12 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, files = s->files_ts; files_opposite = s->files_tc; + flags = FileFlowToFlags(s->f, STREAM_TOSERVER); if ((s->flags & HTP_FLAG_STORE_FILES_TC) || ((s->flags & HTP_FLAG_STORE_FILES_TX_TC) && txid == s->store_tx_id)) { flags |= FILE_STORE; - } - if (s->f->flags & FLOW_FILE_NO_MAGIC_TS) { - SCLogDebug("no magic for this flow in toserver direction, so none for this file"); - flags |= FILE_NOMAGIC; - } - - if (s->f->flags & FLOW_FILE_NO_MD5_TS) { - SCLogDebug("no md5 for this flow in toserver direction, so none for this file"); - flags |= FILE_NOMD5; - } - - if (s->f->flags & FLOW_FILE_NO_SHA1_TS) { - SCLogDebug("no sha1 for this flow in toserver direction, so none for this file"); - flags |= FILE_NOSHA1; - } - - if (s->f->flags & FLOW_FILE_NO_SHA256_TS) { - SCLogDebug("no sha256 for this flow in toserver direction, so none for this file"); - flags |= FILE_NOSHA256; - } - - if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TS)) { + flags &= ~FILE_NOSTORE; + } else if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TS)) { flags |= FILE_NOSTORE; } diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 2d584a7c4785..a28e299fb331 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -408,28 +408,10 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, SMTPState *smtp_state = (SMTPState *) flow->alstate; MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; FileContainer *files = NULL; - uint16_t flags = 0; - /* Set flags */ - if (flow->flags & FLOW_FILE_NO_STORE_TS) { - flags |= FILE_NOSTORE; - } - - if (flow->flags & FLOW_FILE_NO_MAGIC_TS) { - flags |= FILE_NOMAGIC; - } - - if (flow->flags & FLOW_FILE_NO_MD5_TS) { - flags |= FILE_NOMD5; - } - - if (flow->flags & FLOW_FILE_NO_SHA1_TS) { - flags |= FILE_NOSHA1; - } - - if (flow->flags & FLOW_FILE_NO_SHA256_TS) { - flags |= FILE_NOSHA256; - } + uint16_t flags = FileFlowToFlags(flow, STREAM_TOSERVER); + /* we depend on detection engine for file pruning */ + flags |= FILE_USE_DETECT; /* Find file */ if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { @@ -464,7 +446,7 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, } if (FileOpenFile(files, &smtp_config.sbcfg, (uint8_t *) entity->filename, entity->filename_len, - (uint8_t *) chunk, len, flags|FILE_USE_DETECT) == NULL) { + (uint8_t *) chunk, len, flags) == NULL) { ret = MIME_DEC_ERR_DATA; SCLogDebug("FileOpenFile() failed"); } diff --git a/src/util-file.c b/src/util-file.c index ff35508161a7..b2f6b47a5e7c 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -175,6 +175,54 @@ void FileForceHashParseCfg(ConfNode *conf) } } +uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction) +{ + uint16_t flags = 0; + + if (direction == STREAM_TOSERVER) { + if (flow->flags & FLOW_FILE_NO_STORE_TS) { + flags |= FILE_NOSTORE; + } + + if (flow->flags & FLOW_FILE_NO_MAGIC_TS) { + flags |= FILE_NOMAGIC; + } + + if (flow->flags & FLOW_FILE_NO_MD5_TS) { + flags |= FILE_NOMD5; + } + + if (flow->flags & FLOW_FILE_NO_SHA1_TS) { + flags |= FILE_NOSHA1; + } + + if (flow->flags & FLOW_FILE_NO_SHA256_TS) { + flags |= FILE_NOSHA256; + } + } else { + if (flow->flags & FLOW_FILE_NO_STORE_TC) { + flags |= FILE_NOSTORE; + } + + if (flow->flags & FLOW_FILE_NO_MAGIC_TC) { + flags |= FILE_NOMAGIC; + } + + if (flow->flags & FLOW_FILE_NO_MD5_TC) { + flags |= FILE_NOMD5; + } + + if (flow->flags & FLOW_FILE_NO_SHA1_TC) { + flags |= FILE_NOSHA1; + } + + if (flow->flags & FLOW_FILE_NO_SHA256_TC) { + flags |= FILE_NOSHA256; + } + } + return flags; +} + int FileMagicSize(void) { /** \todo make this size configurable */ diff --git a/src/util-file.h b/src/util-file.h index 9f55d8304c9c..3b9ee9daee46 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -33,20 +33,20 @@ #include "util-streaming-buffer.h" -#define FILE_TRUNCATED 0x0001 -#define FILE_NOMAGIC 0x0002 -#define FILE_NOMD5 0x0004 -#define FILE_MD5 0x0008 -#define FILE_NOSHA1 0x0010 -#define FILE_SHA1 0x0020 -#define FILE_NOSHA256 0x0040 -#define FILE_SHA256 0x0080 -#define FILE_LOGGED 0x0100 -#define FILE_NOSTORE 0x0200 -#define FILE_STORE 0x0400 -#define FILE_STORED 0x0800 -#define FILE_NOTRACK 0x1000 /**< track size of file */ -#define FILE_USE_DETECT 0x2000 /**< use content_inspected tracker */ +#define FILE_TRUNCATED BIT_U16(0) +#define FILE_NOMAGIC BIT_U16(1) +#define FILE_NOMD5 BIT_U16(2) +#define FILE_MD5 BIT_U16(3) +#define FILE_NOSHA1 BIT_U16(4) +#define FILE_SHA1 BIT_U16(5) +#define FILE_NOSHA256 BIT_U16(6) +#define FILE_SHA256 BIT_U16(7) +#define FILE_LOGGED BIT_U16(8) +#define FILE_NOSTORE BIT_U16(9) +#define FILE_STORE BIT_U16(10) +#define FILE_STORED BIT_U16(11) +#define FILE_NOTRACK BIT_U16(12) /**< track size of file */ +#define FILE_USE_DETECT BIT_U16(13) /**< use content_inspected tracker */ typedef enum FileState_ { FILE_STATE_NONE = 0, /**< no state */ @@ -211,4 +211,6 @@ void FileTruncateAllOpenFiles(FileContainer *); uint64_t FileSize(const File *file); +uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction); + #endif /* __UTIL_FILE_H__ */ From f7481c407820430669d89e2b7a36b96e08d796a2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 10:45:29 +0200 Subject: [PATCH 1706/2553] file-hashing: restore 'force-md5' We don't want to break existing setups. Do issue a warning that a new option is available. --- src/util-file.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/util-file.c b/src/util-file.c index b2f6b47a5e7c..502fcf059b15 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -134,6 +134,22 @@ void FileForceHashParseCfg(ConfNode *conf) ConfNode *forcehash_node = NULL; + /* legacy option */ + const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); + if (force_md5 != NULL) { + SCLogWarning(SC_ERR_DEPRECATED_CONF, "deprecated 'force-md5' option " + "found. Please use 'force-hash: [md5]' instead"); + + if (ConfValIsTrue(force_md5)) { +#ifdef HAVE_NSS + FileForceMd5Enable(); + SCLogInfo("forcing md5 calculation for logged files"); +#else + SCLogInfo("md5 calculation requires linking against libnss"); +#endif + } + } + if (conf != NULL) forcehash_node = ConfNodeLookupChild(conf, "force-hash"); From 4cdcada397aa4fe2d3d3a37f1268c409205b2134 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 19 Sep 2016 10:45:05 -0600 Subject: [PATCH 1707/2553] pcre: fix missing quote in pcre unit test --- src/detect-pcre.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index ed8eb2300f13..7b28f6185357 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -1721,7 +1721,7 @@ static int DetectPcreTestSig01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/^gEt/i\"; pcre:\"/\\/two\\//U; pcre:\"/GET \\/two\\//\"; pcre:\"/\\s+HTTP/R\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/^gEt/i\"; pcre:\"/\\/two\\//U\"; pcre:\"/GET \\/two\\//\"; pcre:\"/\\s+HTTP/R\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; From 7ce196e3bfd74898353d598b9b968ffdd844cc6a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 21 Sep 2016 09:43:42 -0600 Subject: [PATCH 1708/2553] detect-pcre: use new unit test macros --- src/detect-pcre.c | 1376 ++++++++++----------------------------------- 1 file changed, 300 insertions(+), 1076 deletions(-) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 7b28f6185357..e1b0f09428e3 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -805,15 +805,10 @@ static int DetectPcreParseTest01 (void) char *teststring = "/blah/7"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd != NULL) { - printf("expected NULL: got %p", pd); - result = 0; - DetectPcreFree(pd); - } + FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); return result; @@ -829,15 +824,11 @@ static int DetectPcreParseTest02 (void) char *teststring = "/blah/Ui$"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd != NULL) { - printf("expected NULL: got %p", pd); - result = 0; - DetectPcreFree(pd); - } + FAIL_IF_NOT_NULL(pd); + DetectEngineCtxFree(de_ctx); return result; } @@ -852,15 +843,11 @@ static int DetectPcreParseTest03 (void) char *teststring = "/blah/UNi"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd != NULL) { - printf("expected NULL: got %p", pd); - result = 0; - DetectPcreFree(pd); - } + FAIL_IF_NOT_NULL(pd); + DetectEngineCtxFree(de_ctx); return result; } @@ -875,14 +862,10 @@ static int DetectPcreParseTest04 (void) char *teststring = "/b\\\"lah/i"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); @@ -899,14 +882,10 @@ static int DetectPcreParseTest05 (void) char *teststring = "/b(l|a)h/"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); @@ -923,14 +902,10 @@ static int DetectPcreParseTest06 (void) char *teststring = "/b(l|a)h/smi"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); @@ -947,14 +922,10 @@ static int DetectPcreParseTest07 (void) char *teststring = "/blah/Ui"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); @@ -971,14 +942,10 @@ static int DetectPcreParseTest08 (void) char *teststring = "/b(l|a)h/O"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); @@ -991,23 +958,18 @@ static int DetectPcreParseTest08 (void) */ static int DetectPcreParseTest09 (void) { - int result = 1; DetectPcreData *pd = NULL; char *teststring = "/lala\\\\/"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1016,30 +978,27 @@ static int DetectPcreParseTest09 (void) int DetectPcreParseTest10(void) { Signature *s = SigAlloc(); - int result = 1; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - result = 0; - goto end; - } + FAIL_IF_NULL(de_ctx); s->alproto = ALPROTO_DCERPC; - result &= (DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + FAIL_IF_NOT(DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); + FAIL_IF_NOT(s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); s = SigAlloc(); + FAIL_IF_NULL(s); + /* failure since we have no preceding content/pcre/bytejump */ - result &= (DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + FAIL_IF_NOT(DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); + FAIL_IF_NOT(s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); - end: SigFree(s); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1048,13 +1007,11 @@ int DetectPcreParseTest10(void) int DetectPcreParseTest11(void) { DetectEngineCtx *de_ctx = NULL; - int result = 1; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1062,86 +1019,52 @@ int DetectPcreParseTest11(void) "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/R; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } + FAIL_IF(de_ctx == NULL); s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { - result = 0; - goto end; - } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); + FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL); + FAIL_IF_NOT(s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; - if (data->flags & DETECT_PCRE_RAWBYTES || - !(data->flags & DETECT_PCRE_RELATIVE)) { - result = 0; - goto end; - } + FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || + !(data->flags & DETECT_PCRE_RELATIVE)); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/R; sid:1;)"); - if (s->next == NULL) { - result = 0; - goto end; - } + FAIL_IF_NULL(s->next); s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { - result = 0; - goto end; - } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); + FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL); + FAIL_IF_NOT(s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; - if (data->flags & DETECT_PCRE_RAWBYTES || - !(data->flags & DETECT_PCRE_RELATIVE)) { - result = 0; - goto end; - } + FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || + !(data->flags & DETECT_PCRE_RELATIVE)); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/RB; sid:1;)"); - if (s->next == NULL) { - result = 0; - goto end; - } + FAIL_IF(s->next == NULL); s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { - result = 0; - goto end; - } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); + FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL); + FAIL_IF_NOT(s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; - if (!(data->flags & DETECT_PCRE_RAWBYTES) || - !(data->flags & DETECT_PCRE_RELATIVE)) { - result = 0; - goto end; - } + FAIL_IF(!(data->flags & DETECT_PCRE_RAWBYTES) || + !(data->flags & DETECT_PCRE_RELATIVE)); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; pcre:/bamboo/; sid:1;)"); - if (s->next == NULL) { - result = 0; - goto end; - } + FAIL_IF(s->next == NULL); s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { - result = 0; - goto end; - } + FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL); - end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1151,47 +1074,31 @@ int DetectPcreParseTest11(void) static int DetectPcreParseTest12(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; pcre:/abc/R; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF (de_ctx->sig_list == NULL); s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("empty server body list: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL); - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE) { - printf("last sm not pcre: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; - if (data->flags & DETECT_PCRE_RAWBYTES || - !(data->flags & DETECT_PCRE_RELATIVE)) { - printf("flags not right: "); - goto end; - } + FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || + !(data->flags & DETECT_PCRE_RELATIVE)); - result = 1; - end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1200,47 +1107,31 @@ static int DetectPcreParseTest12(void) static int DetectPcreParseTest13(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"abc\"; pcre:/def/R; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("empty server body list: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL); - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE) { - printf("last sm not pcre: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; - if (data->flags & DETECT_PCRE_RAWBYTES || - !(data->flags & DETECT_PCRE_RELATIVE)) { - printf("flags not right: "); - goto end; - } + FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || + !(data->flags & DETECT_PCRE_RELATIVE)); - result = 1; - end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1249,57 +1140,39 @@ static int DetectPcreParseTest13(void) static int DetectPcreParseTest14(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; pcre:/def/; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("empty server body list: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL); - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE) { - printf("last sm not pcre: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; - if (data->flags & DETECT_PCRE_RAWBYTES || - data->flags & DETECT_PCRE_RELATIVE) { - printf("flags not right: "); - goto end; - } + FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || + data->flags & DETECT_PCRE_RELATIVE); - result = 1; - end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative method */ int DetectPcreParseTest15(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1307,19 +1180,13 @@ int DetectPcreParseTest15(void) "(msg:\"Testing pcre relative http_method\"; " "content:\"GET\"; " "http_method; pcre:\"/abc/RM\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } @@ -1327,10 +1194,8 @@ int DetectPcreParseTest15(void) int DetectPcreParseTest16(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1338,29 +1203,21 @@ int DetectPcreParseTest16(void) "(msg:\"Testing pcre relative http_cookie\"; " "content:\"test\"; " "http_cookie; pcre:\"/abc/RC\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative raw header */ int DetectPcreParseTest17(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1368,29 +1225,21 @@ int DetectPcreParseTest17(void) "(msg:\"Testing pcre relative http_raw_header\"; " "flow:to_server; content:\"test\"; " "http_raw_header; pcre:\"/abc/RD\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative header */ int DetectPcreParseTest18(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1398,29 +1247,21 @@ int DetectPcreParseTest18(void) "(msg:\"Testing pcre relative http_header\"; " "content:\"test\"; " "http_header; pcre:\"/abc/RH\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative client-body */ int DetectPcreParseTest19(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1428,29 +1269,21 @@ int DetectPcreParseTest19(void) "(msg:\"Testing pcre relativie http_client_body\"; " "content:\"test\"; " "http_client_body; pcre:\"/abc/RP\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative raw uri */ int DetectPcreParseTest20(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1458,29 +1291,21 @@ int DetectPcreParseTest20(void) "(msg:\"Testing http_raw_uri\"; " "content:\"test\"; " "http_raw_uri; pcre:\"/abc/RI\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative uricontent */ int DetectPcreParseTest21(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1488,29 +1313,21 @@ int DetectPcreParseTest21(void) "(msg:\"Testing pcre relative uricontent\"; " "uricontent:\"test\"; " "pcre:\"/abc/RU\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative http_uri */ int DetectPcreParseTest22(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1518,29 +1335,21 @@ int DetectPcreParseTest22(void) "(msg:\"Testing pcre relative http_uri\"; " "content:\"test\"; " "http_uri; pcre:\"/abc/RU\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with inconsistent pcre relative */ int DetectPcreParseTest23(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1548,134 +1357,96 @@ int DetectPcreParseTest23(void) "(msg:\"Testing inconsistent pcre relative\"; " "content:\"GET\"; " "http_cookie; pcre:\"/abc/RM\"; sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); - if (de_ctx->sig_list == NULL) { - result = 1; - } else { - printf("sig parse shouldn't have failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with inconsistent pcre modifiers */ int DetectPcreParseTest24(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/UI\"; sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); - if (de_ctx->sig_list == NULL) { - result = 1; - } else { - printf("sig parse should have failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with inconsistent pcre modifiers */ int DetectPcreParseTest25(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/DH\"; sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); - if (de_ctx->sig_list == NULL) { - result = 1; - } else { - printf("sig parse should have failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with inconsistent pcre modifiers */ static int DetectPcreParseTest26(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/F\"; sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); - if (de_ctx->sig_list == NULL) { - result = 1; - } else { - printf("sig parse should have failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Bug 1098 */ static int DetectPcreParseTest27(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any 80 " "(content:\"baduricontent\"; http_raw_uri; " "pcre:\"/^[a-z]{5}\\.html/R\"; sid:2; rev:2;)"); + FAIL_IF_NOT(de_ctx->sig_list == NULL); - if (de_ctx->sig_list == NULL) { - result = 1; - } else { - printf("sig parse should have failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } static int DetectPcreTestSig01(void) @@ -1692,7 +1463,6 @@ static int DetectPcreTestSig01(void) Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; Flow f; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1715,36 +1485,23 @@ static int DetectPcreTestSig01(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/^gEt/i\"; pcre:\"/\\/two\\//U\"; pcre:\"/GET \\/two\\//\"; pcre:\"/\\s+HTTP/R\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, buf, buflen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) == 1) { - result = 1; - } + FAIL_IF_NOT(PacketAlertCheck(p, 1) == 1); -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); @@ -1758,7 +1515,7 @@ static int DetectPcreTestSig01(void) FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; } static int DetectPcreTestSig02(void) @@ -1775,7 +1532,6 @@ static int DetectPcreTestSig02(void) Flow f; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); @@ -1790,25 +1546,18 @@ static int DetectPcreTestSig02(void) pcre_match_limit_recursion = 100; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/two/O\"; sid:2;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 2) == 1) { - result = 1; - } + FAIL_IF_NOT(PacketAlertCheck(p, 2) == 1); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -1816,9 +1565,9 @@ static int DetectPcreTestSig02(void) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FLOW_DESTROY(&f); -end: + UTHFreePackets(&p, 1); - return result; + PASS; } /** @@ -1837,42 +1586,32 @@ static int DetectPcreTestSig03(void) Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 1; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - result = 0; - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"GET\"; pcre:!\"/two/\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)){ - printf("sid 1 matched even though it shouldn't have:"); - result = 0; - } + FAIL_IF(PacketAlertCheck(p, 1)); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: + UTHFreePackets(&p, 1); - return result; + PASS; } /** @@ -1880,7 +1619,6 @@ static int DetectPcreTestSig03(void) */ static int DetectPcreModifPTest04(void) { - int result = 0; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" @@ -1936,59 +1674,36 @@ static int DetectPcreModifPTest04(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"Pcre modifier P\"; pcre:\"/DOCTYPE/P\"; " "sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF(s == NULL); s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"" "Pcre modifier P (no match)\"; pcre:\"/blah/P\"; sid:2;)"); - if (s->next == NULL) { - goto end; - } + FAIL_IF(s->next == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); HtpState *http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - if (PacketAlertCheck(p, 2)) { - printf("sid 2 matched but shouldn't: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 1))); + FAIL_IF(PacketAlertCheck(p, 2)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); @@ -1998,7 +1713,7 @@ static int DetectPcreModifPTest04(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; } /** @@ -2007,7 +1722,6 @@ static int DetectPcreModifPTest04(void) */ static int DetectPcreModifPTest05(void) { - int result = 0; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" @@ -2071,85 +1785,49 @@ static int DetectPcreModifPTest05(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"Pcre modifier P\"; pcre:\"/DOC/P\"; " "sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF(s == NULL); s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"" "Pcre modifier P (no match)\"; pcre:\"/DOCTYPE/P\"; sid:2;)"); - if (s->next == NULL) { - goto end; - } + FAIL_IF(s->next == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); HtpState *http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF(http_state == NULL); - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 didn't match on p1 but should have: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p1, 1)); - if (PacketAlertCheck(p1, 2)) { - printf("sid 2 did match on p1 but shouldn't have: "); - /* It's a partial match over 2 chunks*/ - goto end; - } + FAIL_IF(PacketAlertCheck(p1, 2)); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect for p2 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!(PacketAlertCheck(p2, 1))) { - printf("sid 1 did match on p2 but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p2, 1))); - if (!(PacketAlertCheck(p2, 2))) { - printf("sid 2 didn't match on p2 but should have: "); - /* It's a partial match over 2 chunks*/ - goto end; - } + FAIL_IF(!(PacketAlertCheck(p2, 2))); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); @@ -2160,7 +1838,7 @@ static int DetectPcreModifPTest05(void) FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); - return result; + PASS; } int DetectPcreTestSig06() @@ -2190,18 +1868,13 @@ int DetectPcreTestSig07() "lalala\n"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); - int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/^(la)+$/\"; sid:1;)"; - if (UTHPacketMatchSig(p, sig) == 0) { - result = 0; - goto end; - } - result = 1; -end: + FAIL_IF(UTHPacketMatchSig(p, sig) == 0); + if (p != NULL) UTHFreePacket(p); - return result; + PASS; } /** \test anchored pcre */ @@ -2212,18 +1885,13 @@ int DetectPcreTestSig08() "lalala"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); - int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/^(la)+$/\"; sid:1;)"; - if (UTHPacketMatchSig(p, sig) == 0) { - result = 0; - goto end; - } - result = 1; -end: + FAIL_IF(UTHPacketMatchSig(p, sig) == 0); + if (p != NULL) UTHFreePacket(p); - return result; + PASS; } /** \test Check the signature working to alert when cookie modifier is @@ -2231,7 +1899,6 @@ int DetectPcreTestSig08() */ static int DetectPcreTestSig09(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; @@ -2265,48 +1932,31 @@ static int DetectPcreTestSig09(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; pcre:\"/dummy/C\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 failed to match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2319,7 +1969,7 @@ static int DetectPcreTestSig09(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when cookie modifier is @@ -2327,7 +1977,6 @@ static int DetectPcreTestSig09(void) */ static int DetectPcreTestSig10(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; @@ -2361,48 +2010,31 @@ static int DetectPcreTestSig10(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; pcre:!\"/dummy/C\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 should match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2415,7 +2047,7 @@ static int DetectPcreTestSig10(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when method modifier is @@ -2423,7 +2055,6 @@ static int DetectPcreTestSig10(void) */ static int DetectPcreTestSig11(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; @@ -2457,48 +2088,31 @@ static int DetectPcreTestSig11(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP method\"; pcre:\"/POST/M\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 failed to match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2511,7 +2125,7 @@ static int DetectPcreTestSig11(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when method modifier is @@ -2519,7 +2133,6 @@ static int DetectPcreTestSig11(void) */ static int DetectPcreTestSig12(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; @@ -2553,48 +2166,31 @@ static int DetectPcreTestSig12(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP method\"; pcre:!\"/POST/M\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 should match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2607,7 +2203,7 @@ static int DetectPcreTestSig12(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when header modifier is @@ -2615,7 +2211,6 @@ static int DetectPcreTestSig12(void) */ static int DetectPcreTestSig13(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; @@ -2649,48 +2244,31 @@ static int DetectPcreTestSig13(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP header\"; pcre:\"/User[-_]Agent[:]?\\sMozilla/H\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 failed to match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2703,7 +2281,7 @@ static int DetectPcreTestSig13(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when header modifier is @@ -2711,7 +2289,6 @@ static int DetectPcreTestSig13(void) */ static int DetectPcreTestSig14(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: IEXPLORER/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; @@ -2745,48 +2322,31 @@ static int DetectPcreTestSig14(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP header\"; pcre:!\"/User-Agent[:]?\\s+Mozilla/H\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 should match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2799,7 +2359,7 @@ static int DetectPcreTestSig14(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when cookie and relative modifiers are @@ -2807,7 +2367,6 @@ static int DetectPcreTestSig14(void) */ static int DetectPcreTestSig15(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy 1234\r\n\r\n"; @@ -2841,9 +2400,7 @@ static int DetectPcreTestSig15(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; @@ -2851,39 +2408,24 @@ static int DetectPcreTestSig15(void) "\"pcre relative HTTP cookie\"; content:\"dummy\";" " http_cookie; pcre:\"/1234/RC\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 failed to match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2896,7 +2438,7 @@ static int DetectPcreTestSig15(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when method and relative modifiers are @@ -2904,7 +2446,6 @@ static int DetectPcreTestSig15(void) */ static int DetectPcreTestSig16(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy 1234\r\n\r\n"; @@ -2938,9 +2479,7 @@ static int DetectPcreTestSig16(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; @@ -2948,39 +2487,24 @@ static int DetectPcreTestSig16(void) "\"pcre relative HTTP method\"; content:\"PO\";" " http_method; pcre:\"/ST/RM\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 failed to match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2993,14 +2517,13 @@ static int DetectPcreTestSig16(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Test tracking of body chunks per transactions (on requests) */ static int DetectPcreTxBodyChunksTest01(void) { - int result = 0; Flow f; TcpSession ssn; Packet *p = NULL; @@ -3042,113 +2565,65 @@ static int DetectPcreTxBodyChunksTest01(void) SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); - if (r != 0) { - printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); - if (r != 0) { - printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); - if (r != 0) { - printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - goto end; - } + FAIL_IF(r != 0); /* Now we should have 2 transactions, each with it's own list * of request body chunks (let's test it) */ HtpState *htp_state = f.alstate; - if (htp_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF(htp_state == NULL); /* hardcoded check of the transactions and it's client body chunks */ - if (AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2) { - printf("The http app layer doesn't have 2 transactions, but it should: "); - goto end; - } + FAIL_IF(AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2); htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 0); htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 1); HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); - if (htud == NULL) { - printf("No body data in t1 (it should be removed only when the tx is destroyed): "); - goto end; - } + FAIL_IF(htud == NULL); HtpBodyChunk *cur = htud->request_body.first; - if (htud->request_body.first == NULL) { - SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); - goto end; - } + FAIL_IF(htud->request_body.first == NULL); - if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1) { - SCLogDebug("Body data in t1 is not correctly set: "); - goto end; - } + FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1); htud = (HtpTxUserData *) htp_tx_get_user_data(t2); cur = htud->request_body.first; - if (htud->request_body.first == NULL) { - SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); - goto end; - } - - if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1) { - SCLogDebug("Body data in t1 is not correctly set: "); - goto end; - } + FAIL_IF(htud->request_body.first == NULL); + FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); SCMutexUnlock(&f.m); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + PASS; } /** \test test pcre P modifier with multiple pipelined http transactions */ static int DetectPcreTxBodyChunksTest02(void) { - int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; @@ -3191,160 +2666,95 @@ static int DetectPcreTxBodyChunksTest02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); - if (s == NULL) { - printf("sig2 parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (2): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("signature matched, but shouldn't have: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 1))); p->alerts.cnt = 0; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); - if (r != 0) { - printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (5): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); - if (r != 0) { - printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { - printf("sig 1 alerted (request 2, chunk 6): "); - goto end; - } + FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))); p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); - if (r != 0) { - printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 2))) { - printf("signature 2 didn't match, but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 2))); p->alerts.cnt = 0; HtpState *htp_state = f.alstate; - if (htp_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF(htp_state == NULL); /* hardcoded check of the transactions and it's client body chunks */ - if (AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2) { - printf("The http app layer doesn't have 2 transactions, but it should: "); - goto end; - } + FAIL_IF(AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2); htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 0); htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 1); @@ -3352,31 +2762,17 @@ static int DetectPcreTxBodyChunksTest02(void) HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); HtpBodyChunk *cur = htud->request_body.first; - if (htud->request_body.first == NULL) { - SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); - goto end; - } + FAIL_IF(htud->request_body.first == NULL); - if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1) { - SCLogDebug("Body data in t1 is not correctly set: "); - goto end; - } + FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1); htud = (HtpTxUserData *) htp_tx_get_user_data(t2); cur = htud->request_body.first; - if (htud->request_body.first == NULL) { - SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); - goto end; - } + FAIL_IF(htud->request_body.first == NULL); - if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1) { - SCLogDebug("Body data in t1 is not correctly set: "); - goto end; - } + FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -3390,13 +2786,12 @@ static int DetectPcreTxBodyChunksTest02(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + PASS; } /** \test multiple http transactions and body chunks of request handling */ static int DetectPcreTxBodyChunksTest03(void) { - int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; @@ -3439,162 +2834,95 @@ static int DetectPcreTxBodyChunksTest03(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); - if (s == NULL) { - printf("sig2 parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (2): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("signature matched, but shouldn't have: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 1))); p->alerts.cnt = 0; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); - if (r != 0) { - printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (5): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); - if (r != 0) { - printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { - printf("sig 1 alerted (request 2, chunk 6): "); - goto end; - } + FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))); p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); - if (r != 0) { - printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 2))) { - printf("signature 2 didn't match, but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 2))); p->alerts.cnt = 0; HtpState *htp_state = f.alstate; - if (htp_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF(htp_state == NULL); - if (AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2) { - printf("The http app layer doesn't have 2 transactions, but it should: "); - goto end; - } + FAIL_IF(AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -3608,7 +2936,7 @@ static int DetectPcreTxBodyChunksTest03(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + PASS; } /** @@ -3616,7 +2944,6 @@ static int DetectPcreTxBodyChunksTest03(void) */ static int DetectPcreFlowvarCapture01(void) { - int result = 0; uint8_t uabuf1[] = "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13"; uint32_t ualen1 = sizeof(uabuf1) - 1; /* minus the \0 */ @@ -3661,22 +2988,15 @@ static int DetectPcreFlowvarCapture01(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || + FAIL_IF(s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { - goto end; - } + s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE); DetectPcreData *pd = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; SigGroupBuild(de_ctx); @@ -3684,48 +3004,30 @@ static int DetectPcreFlowvarCapture01(void) SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); HtpState *http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match on p1 but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p1, 1))); FlowVar *fv = FlowVarGet(&f, pd->capidx); - if (fv == NULL) { - printf("no flowvar: "); - goto end; - } + FAIL_IF(fv == NULL); - if (fv->data.fv_str.value_len != ualen1) { - printf("%u != %u: ", fv->data.fv_str.value_len, ualen1); - goto end; - } + FAIL_IF(fv->data.fv_str.value_len != ualen1); if (memcmp(fv->data.fv_str.value, uabuf1, ualen1) != 0) { PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len); PrintRawDataFp(stdout, uabuf1, ualen1); printf("buffer mismatch: "); - goto end; + FAIL; } - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -3734,7 +3036,7 @@ static int DetectPcreFlowvarCapture01(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); - return result; + PASS; } /** @@ -3742,7 +3044,6 @@ static int DetectPcreFlowvarCapture01(void) */ static int DetectPcreFlowvarCapture02(void) { - int result = 0; uint8_t uabuf1[] = "Apache"; uint32_t ualen1 = sizeof(uabuf1) - 1; /* minus the \0 */ @@ -3787,41 +3088,26 @@ static int DetectPcreFlowvarCapture02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:1; sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || + FAIL_IF(s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { - goto end; - } + s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE); DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:3; sid:2;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || + FAIL_IF(s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { - goto end; - } + s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE); DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; - if (pd1->capidx != pd2->capidx) { - printf("capidx mismatch, %u != %u: ", pd1->capidx, pd2->capidx); - goto end; - } + FAIL_IF(pd1->capidx != pd2->capidx); SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); @@ -3831,38 +3117,25 @@ static int DetectPcreFlowvarCapture02(void) SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); HtpState *http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match on p1 but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p1, 1))); FlowVar *fv = FlowVarGet(&f, pd1->capidx); - if (fv == NULL) { - printf("no flowvar: "); - goto end; - } + FAIL_IF(fv == NULL); if (fv->data.fv_str.value_len != ualen1) { PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len); PrintRawDataFp(stdout, uabuf1, ualen1); printf("%u != %u: ", fv->data.fv_str.value_len, ualen1); - goto end; + FAIL; } if (memcmp(fv->data.fv_str.value, uabuf1, ualen1) != 0) { @@ -3870,11 +3143,9 @@ static int DetectPcreFlowvarCapture02(void) PrintRawDataFp(stdout, uabuf1, ualen1); printf("buffer mismatch: "); - goto end; + FAIL; } - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -3883,7 +3154,7 @@ static int DetectPcreFlowvarCapture02(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); - return result; + PASS; } /** @@ -3891,7 +3162,6 @@ static int DetectPcreFlowvarCapture02(void) */ static int DetectPcreFlowvarCapture03(void) { - int result = 0; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" @@ -3933,76 +3203,46 @@ static int DetectPcreFlowvarCapture03(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:1; sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || + FAIL_IF(s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { - goto end; - } + s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE); DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:3; sid:2;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || + FAIL_IF(s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { - goto end; - } + s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE); DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; - if (pd1->capidx != pd2->capidx) { - printf("capidx mismatch, %u != %u: ", pd1->capidx, pd2->capidx); - goto end; - } + FAIL_IF(pd1->capidx != pd2->capidx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); HtpState *http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched on p1 but shouldn't have: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p1, 1)); FlowVar *fv = FlowVarGet(&f, pd1->capidx); - if (fv != NULL) { - printf("flowvar, shouldn't have one: "); - goto end; - } + FAIL_IF(fv != NULL); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -4011,7 +3251,7 @@ static int DetectPcreFlowvarCapture03(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); - return result; + PASS; } /** @@ -4019,50 +3259,34 @@ static int DetectPcreFlowvarCapture03(void) */ static int DetectPcreParseHttpHost(void) { - int result = 0; DetectPcreData *pd = NULL; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - return 0; - } + FAIL_IF(de_ctx == NULL); pd = DetectPcreParse(de_ctx, "/domain\\.com/W", &list); - if (pd == NULL) { - goto end; - } + FAIL_IF(pd == NULL); DetectPcreFree(pd); list = DETECT_SM_LIST_NOTSET; pd = DetectPcreParse(de_ctx, "/dOmain\\.com/W", &list); - if (pd != NULL) { - DetectPcreFree(pd); - goto end; - } + FAIL_IF(pd != NULL); /* Uppercase meta characters are valid. */ list = DETECT_SM_LIST_NOTSET; pd = DetectPcreParse(de_ctx, "/domain\\D+\\.com/W", &list); - if (pd == NULL) { - goto end; - } + FAIL_IF(pd == NULL); DetectPcreFree(pd); /* This should not parse as the first \ escapes the second \, then * we have a D. */ list = DETECT_SM_LIST_NOTSET; pd = DetectPcreParse(de_ctx, "/\\\\Ddomain\\.com/W", &list); - if (pd != NULL) { - DetectPcreFree(pd); - goto end; - } - - result = 1; + FAIL_IF(pd != NULL); -end: DetectEngineCtxFree(de_ctx); - return result; + PASS; } #endif /* UNITTESTS */ From afc796a0998e3e8b14d89cc2bd108d651fe1b818 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 1 Oct 2014 23:27:39 -0600 Subject: [PATCH 1709/2553] ssl: store current state separately from cumulative state The ssl_state keyword needs the current state, not the cumulative state in order be compatible with Snort's implementation. --- src/app-layer-ssl.c | 40 ++++++++++++++++++++++++---------------- src/app-layer-ssl.h | 2 ++ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 288370737307..1107fb2f8a4d 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -244,7 +244,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, switch (ssl_state->curr_connp->handshake_type) { case SSLV3_HS_CLIENT_HELLO: - ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_HELLO; + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO; /* skip version */ input += SSLV3_CLIENT_HELLO_VERSION_LEN; @@ -371,15 +371,15 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, break; case SSLV3_HS_SERVER_HELLO: - ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_HELLO; + ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_HELLO; break; case SSLV3_HS_SERVER_KEY_EXCHANGE: - ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_KEYX; + ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_KEYX; break; case SSLV3_HS_CLIENT_KEY_EXCHANGE: - ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_KEYX; + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_KEYX; break; case SSLV3_HS_CERTIFICATE: @@ -480,6 +480,8 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, return -1; } + ssl_state->flags |= ssl_state->current_flags; + uint32_t write_len = 0; if ((ssl_state->curr_connp->bytes_processed + input_len) >= ssl_state->curr_connp->record_length + (SSLV3_RECORD_HDR_LEN)) { @@ -907,8 +909,8 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, break; case SSLV2_MT_CLIENT_HELLO: - ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_HELLO; - ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_HS; + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_CLIENT_HS; if (ssl_state->curr_connp->record_lengths_length == 3) { switch (ssl_state->curr_connp->bytes_processed) { @@ -920,7 +922,7 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, input_len -= 6; ssl_state->curr_connp->bytes_processed += 6; if (ssl_state->curr_connp->session_id_length == 0) { - ssl_state->flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; } break; @@ -979,7 +981,7 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, input_len -= 6; ssl_state->curr_connp->bytes_processed += 6; if (ssl_state->curr_connp->session_id_length == 0) { - ssl_state->flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; } break; @@ -1029,8 +1031,7 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, SCLogDebug("Client hello is not seen before master key " "message!"); } - - ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY; + ssl_state->current_flags = SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY; break; @@ -1039,7 +1040,7 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, SCLogDebug("Incorrect SSL Record type sent in the toclient " "direction!"); } else { - ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_KEYX; + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_KEYX; } /* fall through */ @@ -1061,14 +1062,14 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, if (direction == 0) { if (ssl_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) { - ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; SCLogDebug("SSLv2 client side has started the encryption"); } else if (ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY) { - ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; + ssl_state->current_flags = SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; SCLogDebug("SSLv2 client side has started the encryption"); } } else { - ssl_state->flags |= SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED; + ssl_state->current_flags = SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED; SCLogDebug("SSLv2 Server side has started the encryption"); } @@ -1086,12 +1087,14 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, break; case SSLV2_MT_SERVER_HELLO: - ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_HELLO; - ssl_state->flags |= SSL_AL_FLAG_SSL_SERVER_HS; + ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_HELLO; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_SERVER_HS; break; } + ssl_state->flags |= ssl_state->current_flags; + if (input_len + ssl_state->curr_connp->bytes_processed >= (ssl_state->curr_connp->record_length + ssl_state->curr_connp->record_lengths_length)) { @@ -1316,6 +1319,11 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt else ssl_state->curr_connp = &ssl_state->server_connp; + /* If entering on a new record, reset the current flags. */ + if (ssl_state->curr_connp->bytes_processed == 0) { + ssl_state->current_flags = 0; + } + /* if we have more than one record */ while (input_len > 0) { if (counter++ == 30) { diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 991b4c2bdd71..30fa476c4aba 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -184,6 +184,8 @@ typedef struct SSLState_ { uint16_t events; + uint32_t current_flags; + SSLStateConnp *curr_connp; SSLStateConnp client_connp; From 487cdda93d1836acc33323c3b57135c1844a8f41 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 30 Sep 2014 16:20:56 -0600 Subject: [PATCH 1710/2553] ssl: issue 1231 - support ssl state negation Snort compatible SSL state negation. Adds "," as a state separator, but keeps "|" for compatibility with existing Suricata rules. --- src/detect-ssl-state.c | 153 ++++++++++++++++++++++++++++++----------- src/detect-ssl-state.h | 1 + 2 files changed, 113 insertions(+), 41 deletions(-) diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 1662a3b7b5f7..579971bf2937 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -51,11 +51,11 @@ #include "stream-tcp.h" #include "app-layer-ssl.h" -#define PARSE_REGEX1 "^\\s*([_a-zA-Z0-9]+)(.*)$" +#define PARSE_REGEX1 "^\\s*(!?)([_a-zA-Z0-9]+)(.*)$" static pcre *parse_regex1; static pcre_extra *parse_regex1_study; -#define PARSE_REGEX2 "^(?:\\s*[|]\\s*([_a-zA-Z0-9]+))(.*)$" +#define PARSE_REGEX2 "^(?:\\s*[|,]\\s*(!?)([_a-zA-Z0-9]+))(.*)$" static pcre *parse_regex2; static pcre_extra *parse_regex2_study; @@ -99,7 +99,6 @@ int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *alstate, Signature *s, SigMatch *m) { - int result = 1; DetectSslStateData *ssd = (DetectSslStateData *)m->ctx; SSLState *ssl_state = (SSLState *)alstate; if (ssl_state == NULL) { @@ -107,29 +106,13 @@ int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, return 0; } - if ((ssd->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - !(ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO)) { - result = 0; - goto end; - } - if ((ssd->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && - !(ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO)) { - result = 0; - goto end; - } - if ((ssd->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) && - !(ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX)) { - result = 0; - goto end; - } - if ((ssd->flags & SSL_AL_FLAG_STATE_SERVER_KEYX) && - !(ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_KEYX)) { - result = 0; - goto end; + uint32_t ssl_flags = ssl_state->current_flags; + + if ((ssd->flags & ssl_flags) ^ ssd->mask) { + return 1; } - end: - return result; + return 0; } /** @@ -149,7 +132,8 @@ DetectSslStateData *DetectSslStateParse(char *arg) int ov2[MAX_SUBSTRINGS]; const char *str1; const char *str2; - uint32_t flags = 0; + int negate = 0; + uint32_t flags = 0, mask = 0; DetectSslStateData *ssd = NULL; ret = pcre_exec(parse_regex1, parse_regex1_study, arg, strlen(arg), 0, 0, @@ -159,22 +143,41 @@ DetectSslStateData *DetectSslStateParse(char *arg) "ssl_state keyword.", arg); goto error; } + res = pcre_get_substring((char *)arg, ov1, MAX_SUBSTRINGS, 1, &str1); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } + negate = !strcmp("!", str1); + pcre_free_substring(str1); + + res = pcre_get_substring((char *)arg, ov1, MAX_SUBSTRINGS, 2, &str1); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } if (strcmp("client_hello", str1) == 0) { flags |= DETECT_SSL_STATE_CLIENT_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_HELLO; } else if (strcmp("server_hello", str1) == 0) { flags |= DETECT_SSL_STATE_SERVER_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_HELLO; } else if (strcmp("client_keyx", str1) == 0) { flags |= DETECT_SSL_STATE_CLIENT_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_KEYX; } else if (strcmp("server_keyx", str1) == 0) { flags |= DETECT_SSL_STATE_SERVER_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_KEYX; } else if (strcmp("unknown", str1) == 0) { flags |= DETECT_SSL_STATE_UNKNOWN; + if (negate) + mask |= DETECT_SSL_STATE_UNKNOWN; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "Found invalid option \"%s\" " "in ssl_state keyword.", str1); @@ -183,7 +186,7 @@ DetectSslStateData *DetectSslStateParse(char *arg) pcre_free_substring(str1); - res = pcre_get_substring((char *)arg, ov1, MAX_SUBSTRINGS, 2, &str1); + res = pcre_get_substring((char *)arg, ov1, MAX_SUBSTRINGS, 3, &str1); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; @@ -196,28 +199,47 @@ DetectSslStateData *DetectSslStateParse(char *arg) "ssl_state keyword.", arg); goto error; } + res = pcre_get_substring((char *)str1, ov2, MAX_SUBSTRINGS, 1, &str2); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + negate = !strcmp("!", str2); + pcre_free_substring(str2); + + res = pcre_get_substring((char *)str1, ov2, MAX_SUBSTRINGS, 2, &str2); if (res <= 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (strcmp("client_hello", str2) == 0) { flags |= DETECT_SSL_STATE_CLIENT_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_HELLO; } else if (strcmp("server_hello", str2) == 0) { flags |= DETECT_SSL_STATE_SERVER_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_HELLO; } else if (strcmp("client_keyx", str2) == 0) { flags |= DETECT_SSL_STATE_CLIENT_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_KEYX; } else if (strcmp("server_keyx", str2) == 0) { flags |= DETECT_SSL_STATE_SERVER_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_KEYX; } else if (strcmp("unknown", str2) == 0) { flags |= DETECT_SSL_STATE_UNKNOWN; + if (negate) + mask |= DETECT_SSL_STATE_UNKNOWN; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "Found invalid option \"%s\" " "in ssl_state keyword.", str2); goto error; } - res = pcre_get_substring((char *)str1, ov2, MAX_SUBSTRINGS, 2, &str2); + res = pcre_get_substring((char *)str1, ov2, MAX_SUBSTRINGS, 3, &str2); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; @@ -232,6 +254,7 @@ DetectSslStateData *DetectSslStateParse(char *arg) goto error; } ssd->flags = flags; + ssd->mask = mask; return ssd; @@ -322,7 +345,7 @@ int DetectSslStateTest01(void) int DetectSslStateTest02(void) { - DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_hello"); + DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_hello"); if (ssd == NULL) { printf("ssd == NULL\n"); return 0; @@ -338,7 +361,7 @@ int DetectSslStateTest02(void) int DetectSslStateTest03(void) { - DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_keyx | " + DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " "client_hello"); if (ssd == NULL) { printf("ssd == NULL\n"); @@ -356,8 +379,8 @@ int DetectSslStateTest03(void) int DetectSslStateTest04(void) { - DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_keyx | " - "client_hello | server_keyx | " + DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " + "client_hello , server_keyx , " "unknown"); if (ssd == NULL) { printf("ssd == NULL\n"); @@ -377,8 +400,8 @@ int DetectSslStateTest04(void) int DetectSslStateTest05(void) { - DetectSslStateData *ssd = DetectSslStateParse("| server_hello | client_keyx | " - "client_hello | server_keyx | " + DetectSslStateData *ssd = DetectSslStateParse(", server_hello , client_keyx , " + "client_hello , server_keyx , " "unknown"); if (ssd != NULL) { @@ -392,9 +415,9 @@ int DetectSslStateTest05(void) int DetectSslStateTest06(void) { - DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_keyx | " - "client_hello | server_keyx | " - "unknown | "); + DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " + "client_hello , server_keyx , " + "unknown , "); if (ssd != NULL) { printf("ssd != NULL - failure\n"); SCFree(ssd); @@ -698,22 +721,29 @@ static int DetectSslStateTest07(void) s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " - "ssl_state:client_hello | server_hello; " + "ssl_state:server_hello; " "sid:2;)"); if (s == NULL) goto end; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " - "ssl_state:client_hello | server_hello | " - "client_keyx; sid:3;)"); + "ssl_state:client_keyx; " + "sid:3;)"); + if (s == NULL) + goto end; + + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(msg:\"ssl state\"; " + "ssl_state:server_keyx; " + "sid:4;)"); if (s == NULL) goto end; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " - "ssl_state:client_hello | server_hello | " - "client_keyx | server_keyx; sid:4;)"); + "ssl_state:!client_hello; " + "sid:5;)"); if (s == NULL) goto end; @@ -748,6 +778,8 @@ static int DetectSslStateTest07(void) goto end; if (PacketAlertCheck(p, 4)) goto end; + if (PacketAlertCheck(p, 5)) + goto end; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, @@ -771,6 +803,8 @@ static int DetectSslStateTest07(void) goto end; if (PacketAlertCheck(p, 4)) goto end; + if (!PacketAlertCheck(p, 5)) + goto end; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, @@ -861,6 +895,40 @@ static int DetectSslStateTest07(void) return result; } +/** + * \brief Test that the "|" character still works as a separate for + * compatibility with older Suricata rules. + */ +int DetectSslStateTest08(void) +{ + DetectSslStateData *ssd = DetectSslStateParse("server_hello|client_hello"); + FAIL_IF_NULL(ssd); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | + DETECT_SSL_STATE_CLIENT_HELLO)); + SCFree(ssd); + PASS; +} + +/** + * \test Test parsing of negated states. + */ +int DetectSslStateTestParseNegate(void) +{ + DetectSslStateData *ssd = DetectSslStateParse("!client_hello"); + FAIL_IF_NULL(ssd); + uint32_t expected = DETECT_SSL_STATE_CLIENT_HELLO; + FAIL_IF(ssd->flags != expected || ssd->mask != expected); + SCFree(ssd); + + ssd = DetectSslStateParse("!client_hello,!server_hello"); + FAIL_IF_NULL(ssd); + expected = DETECT_SSL_STATE_CLIENT_HELLO | DETECT_SSL_STATE_SERVER_HELLO; + FAIL_IF(ssd->flags != expected || ssd->mask != expected); + SCFree(ssd); + + PASS; +} + #endif /* UNITTESTS */ void DetectSslStateRegisterTests(void) @@ -873,6 +941,9 @@ void DetectSslStateRegisterTests(void) UtRegisterTest("DetectSslStateTest05", DetectSslStateTest05); UtRegisterTest("DetectSslStateTest06", DetectSslStateTest06); UtRegisterTest("DetectSslStateTest07", DetectSslStateTest07); + UtRegisterTest("DetectSslStateTest08", DetectSslStateTest08); + UtRegisterTest("DetectSslStateTestParseNegate", + DetectSslStateTestParseNegate); #endif return; diff --git a/src/detect-ssl-state.h b/src/detect-ssl-state.h index a9c69a158b56..9246d8f34767 100644 --- a/src/detect-ssl-state.h +++ b/src/detect-ssl-state.h @@ -35,6 +35,7 @@ typedef struct DetectSslStateData_ { uint32_t flags; + uint32_t mask; } DetectSslStateData; void DetectSslStateRegister(void); From 30c853a3040966f3541017e0451480879eeec3b4 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 21 Sep 2016 14:19:55 -0600 Subject: [PATCH 1711/2553] detect-ssl-state: use new unit test macros --- src/detect-ssl-state.c | 212 ++++++++++++----------------------------- 1 file changed, 62 insertions(+), 150 deletions(-) diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 579971bf2937..674dcdcc67dd 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -331,50 +331,32 @@ void DetectSslStateFree(void *ptr) int DetectSslStateTest01(void) { DetectSslStateData *ssd = DetectSslStateParse("client_hello"); - if (ssd == NULL) { - printf("ssd == NULL\n"); - return 0; - } - if (ssd->flags == DETECT_SSL_STATE_CLIENT_HELLO) { - SCFree(ssd); - return 1; - } - - return 0; + FAIL_IF_NULL(ssd); + FAIL_IF_NOT(ssd->flags == DETECT_SSL_STATE_CLIENT_HELLO); + SCFree(ssd); + PASS; } int DetectSslStateTest02(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_hello"); - if (ssd == NULL) { - printf("ssd == NULL\n"); - return 0; - } - if (ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | - DETECT_SSL_STATE_CLIENT_HELLO)) { - SCFree(ssd); - return 1; - } - - return 0; + FAIL_IF_NULL(ssd); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | + DETECT_SSL_STATE_CLIENT_HELLO)); + SCFree(ssd); + PASS; } int DetectSslStateTest03(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " "client_hello"); - if (ssd == NULL) { - printf("ssd == NULL\n"); - return 0; - } - if (ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | + FAIL_IF_NULL(ssd); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_KEYX | - DETECT_SSL_STATE_CLIENT_HELLO)) { - SCFree(ssd); - return 1; - } - - return 0; + DETECT_SSL_STATE_CLIENT_HELLO)); + SCFree(ssd); + PASS; } int DetectSslStateTest04(void) @@ -382,20 +364,14 @@ int DetectSslStateTest04(void) DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " "client_hello , server_keyx , " "unknown"); - if (ssd == NULL) { - printf("ssd == NULL\n"); - return 0; - } - if (ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | + FAIL_IF_NULL(ssd); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_KEYX | DETECT_SSL_STATE_CLIENT_HELLO | DETECT_SSL_STATE_SERVER_KEYX | - DETECT_SSL_STATE_UNKNOWN)) { - SCFree(ssd); - return 1; - } - - return 0; + DETECT_SSL_STATE_UNKNOWN)); + SCFree(ssd); + PASS; } int DetectSslStateTest05(void) @@ -404,13 +380,8 @@ int DetectSslStateTest05(void) "client_hello , server_keyx , " "unknown"); - if (ssd != NULL) { - printf("ssd != NULL - failure\n"); - SCFree(ssd); - return 0; - } - - return 1; + FAIL_IF_NOT_NULL(ssd); + PASS; } int DetectSslStateTest06(void) @@ -418,13 +389,8 @@ int DetectSslStateTest06(void) DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " "client_hello , server_keyx , " "unknown , "); - if (ssd != NULL) { - printf("ssd != NULL - failure\n"); - SCFree(ssd); - return 0; - } - - return 1; + FAIL_IF_NOT_NULL(ssd); + PASS; } /** @@ -677,7 +643,6 @@ static int DetectSslStateTest07(void) }; uint32_t toserver_app_data_buf_len = sizeof(toserver_app_data_buf); - int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; @@ -708,44 +673,38 @@ static int DetectSslStateTest07(void) StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; ssl_state:client_hello; " "sid:1;)"); - if (s == NULL) - goto end; + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " "ssl_state:server_hello; " "sid:2;)"); - if (s == NULL) - goto end; + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " "ssl_state:client_keyx; " "sid:3;)"); - if (s == NULL) - goto end; + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " "ssl_state:server_keyx; " "sid:4;)"); - if (s == NULL) - goto end; + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " "ssl_state:!client_hello; " "sid:5;)"); - if (s == NULL) - goto end; + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -753,134 +712,87 @@ static int DetectSslStateTest07(void) SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_START, chello_buf, chello_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF(ssl_state == NULL); /* do detect */ p->alerts.cnt = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) - goto end; - if (PacketAlertCheck(p, 2)) - goto end; - if (PacketAlertCheck(p, 3)) - goto end; - if (PacketAlertCheck(p, 4)) - goto end; - if (PacketAlertCheck(p, 5)) - goto end; + FAIL_IF(!PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + FAIL_IF(PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); + FAIL_IF(PacketAlertCheck(p, 5)); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, shello_buf_len); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ p->alerts.cnt = 0; + p->flowflags = (FLOW_PKT_TOCLIENT | FLOW_PKT_ESTABLISHED); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - goto end; - if (!PacketAlertCheck(p, 2)) - goto end; - if (PacketAlertCheck(p, 3)) - goto end; - if (PacketAlertCheck(p, 4)) - goto end; - if (!PacketAlertCheck(p, 5)) - goto end; + FAIL_IF(PacketAlertCheck(p, 1)); + FAIL_IF(!PacketAlertCheck(p, 2)); + FAIL_IF(PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); + FAIL_IF(!PacketAlertCheck(p, 5)); + + PASS; SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, client_change_cipher_spec_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ p->alerts.cnt = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - goto end; - if (PacketAlertCheck(p, 2)) - goto end; - if (!PacketAlertCheck(p, 3)) - goto end; - if (PacketAlertCheck(p, 4)) - goto end; + FAIL_IF(PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + FAIL_IF(!PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_change_cipher_spec_buf, server_change_cipher_spec_buf_len); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ p->alerts.cnt = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - goto end; - if (PacketAlertCheck(p, 2)) - goto end; - if (PacketAlertCheck(p, 3)) - goto end; - if (PacketAlertCheck(p, 4)) - goto end; + FAIL_IF(PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + FAIL_IF(PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); SCMutexLock(&f.m); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, toserver_app_data_buf, toserver_app_data_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } + FAIL_IF(r != 0); SCMutexUnlock(&f.m); /* do detect */ p->alerts.cnt = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - goto end; - if (PacketAlertCheck(p, 2)) - goto end; - if (PacketAlertCheck(p, 3)) - goto end; - if (PacketAlertCheck(p, 4)) - goto end; - - result = 1; + FAIL_IF(PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + FAIL_IF(PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); - end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); @@ -892,7 +804,7 @@ static int DetectSslStateTest07(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; } /** From 7004987670f1e810fcb4558db7d581c106b7d533 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Jun 2016 20:11:55 +0200 Subject: [PATCH 1712/2553] offloading: preparation for disabling offload on BSD Add functions for setting IFCAP flags. --- src/util-ioctl.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util-ioctl.h | 1 + 2 files changed, 72 insertions(+) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index cfca00b3a4b2..5eb7b408c1f8 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -236,6 +236,33 @@ int GetIfaceCaps(const char *ifname) return ifr.ifr_curcap; } #endif +#ifdef SIOCSIFCAP +int SetIfaceCaps(const char *ifname, int caps) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + ifr.ifr_reqcap = caps; + + if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to set caps for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return 0; +} +#endif + #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) @@ -384,6 +411,40 @@ static int GetIfaceOffloadingBSD(const char *ifname) } #endif +#ifdef SIOCSIFCAP +static int DisableIfaceOffloadingBSD(const char *ifname) +{ + int ret = 0; + int if_caps = GetIfaceCaps(ifname); + int set_caps = if_caps; + if (if_caps == -1) { + return -1; + } + SCLogDebug("if_caps %X", if_caps); + + if (if_caps & IFCAP_RXCSUM) { + SCLogInfo("%s: disabling rxcsum offloading", ifname); + set_caps &= ~IFCAP_RXCSUM; + } + +#ifdef IFCAP_TOE + if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { + SCLogInfo("%s: disabling tso|toe|lro offloading", ifname); + set_caps &= ~(IFCAP_TSO|IFCAP_LRO); + } +#else + if (if_caps & (IFCAP_TSO|IFCAP_LRO)) { + SCLogInfo("%s: disabling tso|lro offloading", ifname); + set_caps &= ~(IFCAP_TSO|IFCAP_LRO); + } +#endif + if (set_caps != if_caps) { + SetIfaceCaps(ifname, set_caps); + } + return ret; +} +#endif + /** * \brief output offloading status of the link * @@ -409,6 +470,16 @@ int GetIfaceOffloading(const char *dev, int csum, int other) #endif } +int DisableIfaceOffloading(const char *dev, int csum, int other) +{ +#if defined SIOCSIFCAP + return DisableIfaceOffloadingBSD(dev); +#else + return 0; +#endif + +} + int GetIfaceRSSQueuesNum(const char *pcap_dev) { #if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS diff --git a/src/util-ioctl.h b/src/util-ioctl.h index 79018754b0c4..da3bd616911d 100644 --- a/src/util-ioctl.h +++ b/src/util-ioctl.h @@ -34,3 +34,4 @@ int SetIfaceFlags(const char *ifname, int flags); #ifdef SIOCGIFCAP int GetIfaceCaps(const char *ifname); #endif +int DisableIfaceOffloading(const char *dev, int csum, int other); From 2780fba1d120a69ecc7286441f79a6dc65d3c60e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Jun 2016 20:15:37 +0200 Subject: [PATCH 1713/2553] device: add global flag for disabling offloading Add global flag to disable offloading or just warn on it. --- src/util-device.c | 17 +++++++++++++++++ src/util-device.h | 3 +++ 2 files changed, 20 insertions(+) diff --git a/src/util-device.c b/src/util-device.c index 582746ac126f..2a37bffc5a04 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -39,6 +39,23 @@ static int live_devices_stats = 1; static int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen); +static int g_live_devices_disable_offloading = 1; + +void LiveSetOffloadDisable(void) +{ + g_live_devices_disable_offloading = 1; +} + +void LiveSetOffloadWarn(void) +{ + g_live_devices_disable_offloading = 0; +} + +int LiveGetOffload(void) +{ + return g_live_devices_disable_offloading; +} + /** * \brief Add a pcap device for monitoring * diff --git a/src/util-device.h b/src/util-device.h index ca3d91331a35..307e4634ec45 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -34,6 +34,9 @@ typedef struct LiveDevice_ { TAILQ_ENTRY(LiveDevice_) next; } LiveDevice; +void LiveSetOffloadDisable(void); +void LiveSetOffloadWarn(void); +int LiveGetOffload(void); int LiveRegisterDevice(const char *dev); int LiveGetDeviceCount(void); From 723a14c0fe4b1cb33c970988acef174d4d8d0492 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Jun 2016 20:17:30 +0200 Subject: [PATCH 1714/2553] netmap: optionally disable offloading --- src/source-netmap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/source-netmap.c b/src/source-netmap.c index ec38c1f7a618..48c16fe55d06 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -294,7 +294,11 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver } /* netmap needs all offloading to be disabled */ - (void)GetIfaceOffloading(ifname, 1, 1); + if (LiveGetOffload() == 0) { + (void)GetIfaceOffloading(ifname, 1, 1); + } else { + DisableIfaceOffloading(ifname, 1, 1); + } /* not found, create new record */ pdev = SCMalloc(sizeof(*pdev)); From bc370606fc031743d42455b0be28547138ee2115 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Jun 2016 20:18:43 +0200 Subject: [PATCH 1715/2553] pcap: optionally disable offloading --- src/source-pcap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/source-pcap.c b/src/source-pcap.c index ac7d3a35a89e..4385231b0be8 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -395,6 +395,12 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) SCLogInfo("using interface %s", (char *)pcapconfig->iface); + if (LiveGetOffload() == 0) { + (void)GetIfaceOffloading((char *)pcapconfig->iface, 1, 1); + } else { + DisableIfaceOffloading((char *)pcapconfig->iface, 1, 1); + } + ptv->checksum_mode = pcapconfig->checksum_mode; if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { SCLogInfo("Running in 'auto' checksum mode. Detection of interface state will require " From 98092f63b531bae3f585016a700c92cb0c56eac7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Jun 2016 23:00:38 +0200 Subject: [PATCH 1716/2553] offloading: Linux ethtool offloading support --- src/util-ioctl.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 5eb7b408c1f8..ae1bded7e58f 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -19,6 +19,7 @@ * \file * * \author Eric Leblond + * \author Victor Julien */ #include "suricata-common.h" @@ -292,6 +293,33 @@ static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) return 0; } +static int SetEthtoolValue(const char *dev, int cmd, uint32_t value) +{ + struct ifreq ifr; + int fd; + struct ethtool_value ethv; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + return -1; + } + (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + + ethv.cmd = cmd; + ethv.data = value; + ifr.ifr_data = (void *) ðv; + if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { + SCLogWarning(SC_ERR_SYSCALL, + "Failure when trying to get feature via ioctl for '%s': %s (%d)", + dev, strerror(errno), errno); + close(fd); + return -1; + } + + close(fd); + return 0; +} + static int GetIfaceOffloadingLinux(const char *dev, int csum, int other) { int ret = 0; @@ -372,6 +400,62 @@ static int GetIfaceOffloadingLinux(const char *dev, int csum, int other) return ret; } +static int DisableIfaceOffloadingLinux(const char *dev, int csum, int other) +{ + int ret = 0; + uint32_t value = 0; + + if (csum) { +#ifdef ETHTOOL_GRXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { + SCLogInfo("%s: disabling rxcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0); + } +#endif +#ifdef ETHTOOL_GTXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { + SCLogInfo("%s: disabling txcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0); + } +#endif + } + if (other) { +#ifdef ETHTOOL_GGRO + if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { + SCLogInfo("%s: disabling gro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGRO, 0); + } +#endif +#ifdef ETHTOOL_GTSO + if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { + SCLogInfo("%s: disabling tso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STSO, 0); + } +#endif +#ifdef ETHTOOL_GGSO + if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { + SCLogInfo("%s: disabling gso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGSO, 0); + } +#endif +#ifdef ETHTOOL_GSG + if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { + SCLogInfo("%s: disabling sg offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SSG, 0); + } +#endif +#ifdef ETHTOOL_GFLAGS + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + if (value & ETH_FLAG_LRO) { + SCLogInfo("%s: disabling lro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO); + } + } +#endif + } + return ret; +} + #endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */ #ifdef SIOCGIFCAP @@ -472,7 +556,9 @@ int GetIfaceOffloading(const char *dev, int csum, int other) int DisableIfaceOffloading(const char *dev, int csum, int other) { -#if defined SIOCSIFCAP +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + return DisableIfaceOffloadingLinux(dev, csum, other); +#elif defined SIOCSIFCAP return DisableIfaceOffloadingBSD(dev); #else return 0; From 9d48720f9a2590ce2d51d37433358bfda21c8579 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 20 Jun 2016 23:02:02 +0200 Subject: [PATCH 1717/2553] af-packet: optionally disable offloading --- src/runmode-af-packet.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 0de06c12b986..65ba213b3b7c 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -453,10 +453,15 @@ void *ParseAFPConfig(const char *iface) switch (ltype) { case LINKTYPE_ETHERNET: /* af-packet can handle csum offloading */ - if (GetIfaceOffloading(iface, 0, 1) == 1) { - SCLogWarning(SC_ERR_AFP_CREATE, - "Using AF_PACKET with offloading activated leads to capture problems"); + if (LiveGetOffload() == 0) { + if (GetIfaceOffloading(iface, 0, 1) == 1) { + SCLogWarning(SC_ERR_AFP_CREATE, + "Using AF_PACKET with offloading activated leads to capture problems"); + } + } else { + DisableIfaceOffloading(iface, 0, 1); } + break; case -1: default: break; From 499e27de14c2d960eae60c1fc7f050c4422ca712 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Jun 2016 09:35:33 +0200 Subject: [PATCH 1718/2553] offloading: restore settings on exit --- src/runmode-af-packet.c | 2 +- src/runmode-netmap.c | 7 ++++ src/source-netmap.c | 7 ---- src/source-pcap.c | 2 +- src/util-device.c | 6 ++- src/util-device.h | 19 ++++++++-- src/util-ioctl.c | 81 ++++++++++++++++++++++++++++++++++++++++- src/util-ioctl.h | 5 ++- 8 files changed, 112 insertions(+), 17 deletions(-) diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 65ba213b3b7c..959617889b91 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -459,7 +459,7 @@ void *ParseAFPConfig(const char *iface) "Using AF_PACKET with offloading activated leads to capture problems"); } } else { - DisableIfaceOffloading(iface, 0, 1); + DisableIfaceOffloading(LiveGetDevice(iface), 0, 1); } break; case -1: diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 1cf08bc82987..88d2de3f60fa 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -269,6 +269,13 @@ static void *ParseNetmapConfig(const char *iface_name) SCLogPerf("Using %d threads for interface %s", aconf->in.threads, aconf->iface_name); + /* netmap needs all offloading to be disabled */ + if (LiveGetOffload() == 0) { + (void)GetIfaceOffloading(aconf->in.iface, 1, 1); + } else { + DisableIfaceOffloading(LiveGetDevice(aconf->in.iface), 1, 1); + } + return aconf; } diff --git a/src/source-netmap.c b/src/source-netmap.c index 48c16fe55d06..5f81f1a69453 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -293,13 +293,6 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver } } - /* netmap needs all offloading to be disabled */ - if (LiveGetOffload() == 0) { - (void)GetIfaceOffloading(ifname, 1, 1); - } else { - DisableIfaceOffloading(ifname, 1, 1); - } - /* not found, create new record */ pdev = SCMalloc(sizeof(*pdev)); if (unlikely(pdev == NULL)) { diff --git a/src/source-pcap.c b/src/source-pcap.c index 4385231b0be8..33d8c72529a8 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -398,7 +398,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) if (LiveGetOffload() == 0) { (void)GetIfaceOffloading((char *)pcapconfig->iface, 1, 1); } else { - DisableIfaceOffloading((char *)pcapconfig->iface, 1, 1); + DisableIfaceOffloading(ptv->livedev, 1, 1); } ptv->checksum_mode = pcapconfig->checksum_mode; diff --git a/src/util-device.c b/src/util-device.c index 2a37bffc5a04..f8afbc239cd0 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -18,6 +18,7 @@ #include "suricata-common.h" #include "conf.h" #include "util-device.h" +#include "util-ioctl.h" #define MAX_DEVNAME 10 @@ -66,7 +67,7 @@ int LiveGetOffload(void) */ int LiveRegisterDevice(const char *dev) { - LiveDevice *pd = SCMalloc(sizeof(LiveDevice)); + LiveDevice *pd = SCCalloc(1, sizeof(LiveDevice)); if (unlikely(pd == NULL)) { return -1; } @@ -281,6 +282,9 @@ int LiveDeviceListClean() 100 * (SC_ATOMIC_GET(pd->drop) * 1.0) / SC_ATOMIC_GET(pd->pkts), SC_ATOMIC_GET(pd->invalid_checksums)); } + + RestoreIfaceOffloading(pd); + if (pd->dev) SCFree(pd->dev); SC_ATOMIC_DESTROY(pd->pkts); diff --git a/src/util-device.h b/src/util-device.h index 307e4634ec45..5c4e76c09f37 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -21,6 +21,19 @@ #include "queue.h" #include "unix-manager.h" +#define OFFLOAD_FLAG_SG (1<<0) +#define OFFLOAD_FLAG_TSO (1<<1) +#define OFFLOAD_FLAG_GSO (1<<2) +#define OFFLOAD_FLAG_GRO (1<<3) +#define OFFLOAD_FLAG_LRO (1<<4) +#define OFFLOAD_FLAG_RXCSUM (1<<5) +#define OFFLOAD_FLAG_TXCSUM (1<<6) +#define OFFLOAD_FLAG_TOE (1<<7) + +void LiveSetOffloadDisable(void); +void LiveSetOffloadWarn(void); +int LiveGetOffload(void); + #define MAX_DEVNAME 10 /** storage for live device names */ @@ -32,11 +45,9 @@ typedef struct LiveDevice_ { SC_ATOMIC_DECLARE(uint64_t, drop); SC_ATOMIC_DECLARE(uint64_t, invalid_checksums); TAILQ_ENTRY(LiveDevice_) next; -} LiveDevice; -void LiveSetOffloadDisable(void); -void LiveSetOffloadWarn(void); -int LiveGetOffload(void); + uint32_t offload_orig; /**< original offload settings to restore @exit */ +} LiveDevice; int LiveRegisterDevice(const char *dev); int LiveGetDeviceCount(void); diff --git a/src/util-ioctl.c b/src/util-ioctl.c index ae1bded7e58f..ff6646adc518 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -24,6 +24,7 @@ #include "suricata-common.h" #include "conf.h" +#include "util-device.h" #ifdef HAVE_SYS_IOCTL_H #include @@ -400,22 +401,29 @@ static int GetIfaceOffloadingLinux(const char *dev, int csum, int other) return ret; } -static int DisableIfaceOffloadingLinux(const char *dev, int csum, int other) +static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other) { int ret = 0; uint32_t value = 0; + if (ldev == NULL) + return -1; + + const char *dev = ldev->dev; + if (csum) { #ifdef ETHTOOL_GRXCSUM if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { SCLogInfo("%s: disabling rxcsum offloading", dev); SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0); + ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; } #endif #ifdef ETHTOOL_GTXCSUM if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { SCLogInfo("%s: disabling txcsum offloading", dev); SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0); + ldev->offload_orig |= OFFLOAD_FLAG_TXCSUM; } #endif } @@ -424,24 +432,28 @@ static int DisableIfaceOffloadingLinux(const char *dev, int csum, int other) if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { SCLogInfo("%s: disabling gro offloading", dev); SetEthtoolValue(dev, ETHTOOL_SGRO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_GRO; } #endif #ifdef ETHTOOL_GTSO if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { SCLogInfo("%s: disabling tso offloading", dev); SetEthtoolValue(dev, ETHTOOL_STSO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_TSO; } #endif #ifdef ETHTOOL_GGSO if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { SCLogInfo("%s: disabling gso offloading", dev); SetEthtoolValue(dev, ETHTOOL_SGSO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_GSO; } #endif #ifdef ETHTOOL_GSG if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { SCLogInfo("%s: disabling sg offloading", dev); SetEthtoolValue(dev, ETHTOOL_SSG, 0); + ldev->offload_orig |= OFFLOAD_FLAG_SG; } #endif #ifdef ETHTOOL_GFLAGS @@ -449,6 +461,7 @@ static int DisableIfaceOffloadingLinux(const char *dev, int csum, int other) if (value & ETH_FLAG_LRO) { SCLogInfo("%s: disabling lro offloading", dev); SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO); + ldev->offload_orig |= OFFLOAD_FLAG_LRO; } } #endif @@ -456,6 +469,61 @@ static int DisableIfaceOffloadingLinux(const char *dev, int csum, int other) return ret; } +static int RestoreIfaceOffloadingLinux(LiveDevice *ldev) +{ + if (ldev == NULL) + return -1; + + const char *dev = ldev->dev; + +#ifdef ETHTOOL_GRXCSUM + if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { + SCLogInfo("%s: restoring rxcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1); + } +#endif +#ifdef ETHTOOL_GTXCSUM + if (ldev->offload_orig & OFFLOAD_FLAG_TXCSUM) { + SCLogInfo("%s: restoring txcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1); + } +#endif +#ifdef ETHTOOL_GGRO + if (ldev->offload_orig & OFFLOAD_FLAG_GRO) { + SCLogInfo("%s: restoring gro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGRO, 1); + } +#endif +#ifdef ETHTOOL_GTSO + if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { + SCLogInfo("%s: restoring tso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STSO, 1); + } +#endif +#ifdef ETHTOOL_GGSO + if (ldev->offload_orig & OFFLOAD_FLAG_GSO) { + SCLogInfo("%s: restoring gso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGSO, 1); + } +#endif +#ifdef ETHTOOL_GSG + if (ldev->offload_orig & OFFLOAD_FLAG_SG) { + SCLogInfo("%s: restoring sg offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SSG, 1); + } +#endif +#ifdef ETHTOOL_GFLAGS + if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { + uint32_t value = 0; + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + SCLogInfo("%s: restoring lro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO); + } + } +#endif + return 0; +} + #endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */ #ifdef SIOCGIFCAP @@ -554,7 +622,7 @@ int GetIfaceOffloading(const char *dev, int csum, int other) #endif } -int DisableIfaceOffloading(const char *dev, int csum, int other) +int DisableIfaceOffloading(LiveDevice *dev, int csum, int other) { #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL return DisableIfaceOffloadingLinux(dev, csum, other); @@ -566,6 +634,15 @@ int DisableIfaceOffloading(const char *dev, int csum, int other) } +void RestoreIfaceOffloading(LiveDevice *dev) +{ + if (dev->offload_orig != 0) { +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + RestoreIfaceOffloadingLinux(dev); +#endif + } +} + int GetIfaceRSSQueuesNum(const char *pcap_dev) { #if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS diff --git a/src/util-ioctl.h b/src/util-ioctl.h index da3bd616911d..54020e4c7cf8 100644 --- a/src/util-ioctl.h +++ b/src/util-ioctl.h @@ -21,6 +21,8 @@ * \author Eric Leblond */ +#include "util-device.h" + int GetIfaceMTU(const char *pcap_dev); int GetIfaceMaxPacketSize(const char *pcap_dev); int GetIfaceOffloading(const char *dev, int csum, int other); @@ -34,4 +36,5 @@ int SetIfaceFlags(const char *ifname, int flags); #ifdef SIOCGIFCAP int GetIfaceCaps(const char *ifname); #endif -int DisableIfaceOffloading(const char *dev, int csum, int other); +int DisableIfaceOffloading(LiveDevice *dev, int csum, int other); +void RestoreIfaceOffloading(LiveDevice *dev); From 2b2984dae9d418d869952dde01642e56bf617f1e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Jun 2016 07:59:51 +0200 Subject: [PATCH 1719/2553] offloading: implement restoring settings for BSD --- src/runmode-netmap.c | 14 +++++------ src/util-ioctl.c | 60 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 88d2de3f60fa..3ea6c7a55cd7 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -207,6 +207,13 @@ static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface, ns->threads = 1; } + /* netmap needs all offloading to be disabled */ + if (LiveGetOffload() == 0) { + (void)GetIfaceOffloading(ns->iface, 1, 1); + } else { + DisableIfaceOffloading(LiveGetDevice(ns->iface), 1, 1); + } + return 0; } @@ -269,13 +276,6 @@ static void *ParseNetmapConfig(const char *iface_name) SCLogPerf("Using %d threads for interface %s", aconf->in.threads, aconf->iface_name); - /* netmap needs all offloading to be disabled */ - if (LiveGetOffload() == 0) { - (void)GetIfaceOffloading(aconf->in.iface, 1, 1); - } else { - DisableIfaceOffloading(LiveGetDevice(aconf->in.iface), 1, 1); - } - return aconf; } diff --git a/src/util-ioctl.c b/src/util-ioctl.c index ff6646adc518..6a84816055bf 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -564,9 +564,14 @@ static int GetIfaceOffloadingBSD(const char *ifname) #endif #ifdef SIOCSIFCAP -static int DisableIfaceOffloadingBSD(const char *ifname) +static int DisableIfaceOffloadingBSD(LiveDevice *ldev) { int ret = 0; + + if (ldev == NULL) + return -1; + + const char *ifname = ldev->dev; int if_caps = GetIfaceCaps(ifname); int set_caps = if_caps; if (if_caps == -1) { @@ -590,6 +595,57 @@ static int DisableIfaceOffloadingBSD(const char *ifname) set_caps &= ~(IFCAP_TSO|IFCAP_LRO); } #endif + if (set_caps != if_caps) { + if (if_caps & IFCAP_RXCSUM) + ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; + if (if_caps & IFCAP_TSO) + ldev->offload_orig |= OFFLOAD_FLAG_TSO; +#ifdef IFCAP_TOE + if (if_caps & IFCAP_TOE) + ldev->offload_orig |= OFFLOAD_FLAG_TOE; +#endif + if (if_caps & IFCAP_LRO) + ldev->offload_orig |= OFFLOAD_FLAG_LRO; + + SetIfaceCaps(ifname, set_caps); + } + return ret; +} + +static int RestoreIfaceOffloadingBSD(LiveDevice *ldev) +{ + int ret = 0; + + if (ldev == NULL) + return -1; + + const char *ifname = ldev->dev; + int if_caps = GetIfaceCaps(ifname); + int set_caps = if_caps; + if (if_caps == -1) { + return -1; + } + SCLogDebug("if_caps %X", if_caps); + + if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { + SCLogInfo("%s: restoring rxcsum offloading", ifname); + set_caps |= IFCAP_RXCSUM; + } + if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { + SCLogInfo("%s: restoring tso offloading", ifname); + set_caps |= IFCAP_TSO; + } +#ifdef IFCAP_TOE + if (ldev->offload_orig & OFFLOAD_FLAG_TOE) { + SCLogInfo("%s: restoring toe offloading", ifname); + set_caps |= IFCAP_TOE; + } +#endif + if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { + SCLogInfo("%s: restoring lro offloading", ifname); + set_caps |= IFCAP_LRO; + } + if (set_caps != if_caps) { SetIfaceCaps(ifname, set_caps); } @@ -639,6 +695,8 @@ void RestoreIfaceOffloading(LiveDevice *dev) if (dev->offload_orig != 0) { #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL RestoreIfaceOffloadingLinux(dev); +#elif defined SIOCSIFCAP + RestoreIfaceOffloadingBSD(dev); #endif } } From 5e3b61cc65b688a31b2bb25cbf674b77f4e92085 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Jun 2016 10:05:40 +0200 Subject: [PATCH 1720/2553] offloading: reduce verbosity to 'perf' --- src/util-ioctl.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 6a84816055bf..1ec0700c8691 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -414,14 +414,14 @@ static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other) if (csum) { #ifdef ETHTOOL_GRXCSUM if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { - SCLogInfo("%s: disabling rxcsum offloading", dev); + SCLogPerf("%s: disabling rxcsum offloading", dev); SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0); ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; } #endif #ifdef ETHTOOL_GTXCSUM if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { - SCLogInfo("%s: disabling txcsum offloading", dev); + SCLogPerf("%s: disabling txcsum offloading", dev); SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0); ldev->offload_orig |= OFFLOAD_FLAG_TXCSUM; } @@ -430,28 +430,28 @@ static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other) if (other) { #ifdef ETHTOOL_GGRO if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { - SCLogInfo("%s: disabling gro offloading", dev); + SCLogPerf("%s: disabling gro offloading", dev); SetEthtoolValue(dev, ETHTOOL_SGRO, 0); ldev->offload_orig |= OFFLOAD_FLAG_GRO; } #endif #ifdef ETHTOOL_GTSO if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { - SCLogInfo("%s: disabling tso offloading", dev); + SCLogPerf("%s: disabling tso offloading", dev); SetEthtoolValue(dev, ETHTOOL_STSO, 0); ldev->offload_orig |= OFFLOAD_FLAG_TSO; } #endif #ifdef ETHTOOL_GGSO if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { - SCLogInfo("%s: disabling gso offloading", dev); + SCLogPerf("%s: disabling gso offloading", dev); SetEthtoolValue(dev, ETHTOOL_SGSO, 0); ldev->offload_orig |= OFFLOAD_FLAG_GSO; } #endif #ifdef ETHTOOL_GSG if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { - SCLogInfo("%s: disabling sg offloading", dev); + SCLogPerf("%s: disabling sg offloading", dev); SetEthtoolValue(dev, ETHTOOL_SSG, 0); ldev->offload_orig |= OFFLOAD_FLAG_SG; } @@ -459,7 +459,7 @@ static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other) #ifdef ETHTOOL_GFLAGS if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { if (value & ETH_FLAG_LRO) { - SCLogInfo("%s: disabling lro offloading", dev); + SCLogPerf("%s: disabling lro offloading", dev); SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO); ldev->offload_orig |= OFFLOAD_FLAG_LRO; } @@ -478,37 +478,37 @@ static int RestoreIfaceOffloadingLinux(LiveDevice *ldev) #ifdef ETHTOOL_GRXCSUM if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { - SCLogInfo("%s: restoring rxcsum offloading", dev); + SCLogPerf("%s: restoring rxcsum offloading", dev); SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1); } #endif #ifdef ETHTOOL_GTXCSUM if (ldev->offload_orig & OFFLOAD_FLAG_TXCSUM) { - SCLogInfo("%s: restoring txcsum offloading", dev); + SCLogPerf("%s: restoring txcsum offloading", dev); SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1); } #endif #ifdef ETHTOOL_GGRO if (ldev->offload_orig & OFFLOAD_FLAG_GRO) { - SCLogInfo("%s: restoring gro offloading", dev); + SCLogPerf("%s: restoring gro offloading", dev); SetEthtoolValue(dev, ETHTOOL_SGRO, 1); } #endif #ifdef ETHTOOL_GTSO if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { - SCLogInfo("%s: restoring tso offloading", dev); + SCLogPerf("%s: restoring tso offloading", dev); SetEthtoolValue(dev, ETHTOOL_STSO, 1); } #endif #ifdef ETHTOOL_GGSO if (ldev->offload_orig & OFFLOAD_FLAG_GSO) { - SCLogInfo("%s: restoring gso offloading", dev); + SCLogPerf("%s: restoring gso offloading", dev); SetEthtoolValue(dev, ETHTOOL_SGSO, 1); } #endif #ifdef ETHTOOL_GSG if (ldev->offload_orig & OFFLOAD_FLAG_SG) { - SCLogInfo("%s: restoring sg offloading", dev); + SCLogPerf("%s: restoring sg offloading", dev); SetEthtoolValue(dev, ETHTOOL_SSG, 1); } #endif @@ -516,7 +516,7 @@ static int RestoreIfaceOffloadingLinux(LiveDevice *ldev) if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { uint32_t value = 0; if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { - SCLogInfo("%s: restoring lro offloading", dev); + SCLogPerf("%s: restoring lro offloading", dev); SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO); } } @@ -580,18 +580,18 @@ static int DisableIfaceOffloadingBSD(LiveDevice *ldev) SCLogDebug("if_caps %X", if_caps); if (if_caps & IFCAP_RXCSUM) { - SCLogInfo("%s: disabling rxcsum offloading", ifname); + SCLogPerf("%s: disabling rxcsum offloading", ifname); set_caps &= ~IFCAP_RXCSUM; } #ifdef IFCAP_TOE if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { - SCLogInfo("%s: disabling tso|toe|lro offloading", ifname); + SCLogPerf("%s: disabling tso|toe|lro offloading", ifname); set_caps &= ~(IFCAP_TSO|IFCAP_LRO); } #else if (if_caps & (IFCAP_TSO|IFCAP_LRO)) { - SCLogInfo("%s: disabling tso|lro offloading", ifname); + SCLogPerf("%s: disabling tso|lro offloading", ifname); set_caps &= ~(IFCAP_TSO|IFCAP_LRO); } #endif @@ -628,21 +628,21 @@ static int RestoreIfaceOffloadingBSD(LiveDevice *ldev) SCLogDebug("if_caps %X", if_caps); if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { - SCLogInfo("%s: restoring rxcsum offloading", ifname); + SCLogPerf("%s: restoring rxcsum offloading", ifname); set_caps |= IFCAP_RXCSUM; } if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { - SCLogInfo("%s: restoring tso offloading", ifname); + SCLogPerf("%s: restoring tso offloading", ifname); set_caps |= IFCAP_TSO; } #ifdef IFCAP_TOE if (ldev->offload_orig & OFFLOAD_FLAG_TOE) { - SCLogInfo("%s: restoring toe offloading", ifname); + SCLogPerf("%s: restoring toe offloading", ifname); set_caps |= IFCAP_TOE; } #endif if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { - SCLogInfo("%s: restoring lro offloading", ifname); + SCLogPerf("%s: restoring lro offloading", ifname); set_caps |= IFCAP_LRO; } From da8f3c987b0071555e5df79397985f87b52d7b87 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 12:38:54 +0200 Subject: [PATCH 1721/2553] offloading: make disabling offloading configurable Add a generic 'capture' section to the YAML: # general settings affecting packet capture capture: # disable NIC offloading. It's restored when Suricata exists. # Enabled by default #disable-offloading: false # # disable checksum validation. Same as setting '-k none' on the # commandline #checksum-validation: none --- src/suricata.c | 19 +++++++++++++++++++ suricata.yaml.in | 10 ++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index 66d94ff78bf1..1a395ce3b3d3 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2201,6 +2201,25 @@ static int PostConfLoadedSetup(SCInstance *suri) #endif SpmTableSetup(); + int disable_offloading; + if (ConfGetBool("capture.disable-offloading", &disable_offloading) == 0) + disable_offloading = 1; + if (disable_offloading) { + LiveSetOffloadDisable(); + } else { + LiveSetOffloadWarn(); + } + + if (suri->checksum_validation == -1) { + char *cv = NULL; + if (ConfGet("capture.checksum-validation", &cv) == 1) { + if (strcmp(cv, "none") == 0) { + suri->checksum_validation = 0; + } else if (strcmp(cv, "all") == 0) { + suri->checksum_validation = 1; + } + } + } switch (suri->checksum_validation) { case 0: ConfSet("stream.checksum-validation", "0"); diff --git a/suricata.yaml.in b/suricata.yaml.in index f8be4b3d2747..9faf1f623a50 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1446,6 +1446,16 @@ nflog: ## Advanced Capture Options ## +# general settings affecting packet capture +capture: + # disable NIC offloading. It's restored when Suricata exists. + # Enabled by default + #disable-offloading: false + # + # disable checksum validation. Same as setting '-k none' on the + # commandline + #checksum-validation: none + # Netmap support # # Netmap operates with NIC directly in driver, so you need FreeBSD wich have From 96427cf371da885fe2cec0106d77853025947a0d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 May 2016 22:13:59 +0200 Subject: [PATCH 1722/2553] flow: remove dead code --- src/flow.c | 49 ------------------------------------------------- 1 file changed, 49 deletions(-) diff --git a/src/flow.c b/src/flow.c index 0b847a0bb954..eda2117c446d 100644 --- a/src/flow.c +++ b/src/flow.c @@ -84,8 +84,6 @@ SC_ATOMIC_DECLARE(unsigned int, flow_flags); void FlowRegisterTests(void); void FlowInitFlowProto(); -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 *)); /* Run mode selected at suricata.c */ @@ -758,53 +756,6 @@ int FlowSetProtoFreeFunc (uint8_t proto, void (*Free)(void *)) return 1; } -/** - * \brief Function to set the timeout values for the specified protocol. - * - * \param proto protocol of which timeout value is needed to be set. - * \param new_timeout timeout value for the new flows. - * \param est_timeout timeout value for the established flows. - * \param closed_timeout timeout value for the closed flows. - */ - -int FlowSetProtoTimeout(uint8_t proto, uint32_t new_timeout, - uint32_t est_timeout, uint32_t closed_timeout) -{ - uint8_t proto_map; - proto_map = FlowGetProtoMapping(proto); - - flow_proto[proto_map].new_timeout = new_timeout; - flow_proto[proto_map].est_timeout = est_timeout; - flow_proto[proto_map].closed_timeout = closed_timeout; - - return 1; -} - -/** - * \brief Function to set the emergency timeout values for the specified - * protocol. - * - * \param proto protocol of which timeout value is needed to be set. - * \param emerg_new_timeout timeout value for the new flows. - * \param emerg_est_timeout timeout value for the established flows. - * \param emerg_closed_timeout timeout value for the closed flows. - */ - -int FlowSetProtoEmergencyTimeout(uint8_t proto, uint32_t emerg_new_timeout, - uint32_t emerg_est_timeout, - uint32_t emerg_closed_timeout) -{ - - uint8_t proto_map; - proto_map = FlowGetProtoMapping(proto); - - flow_proto[proto_map].emerg_new_timeout = emerg_new_timeout; - flow_proto[proto_map].emerg_est_timeout = emerg_est_timeout; - flow_proto[proto_map].emerg_closed_timeout = emerg_closed_timeout; - - return 1; -} - AppProto FlowGetAppProtocol(const Flow *f) { return f->alproto; From aee1f0bb99b82bb2cfc6553ecae602ea81acaa05 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 13 May 2016 23:04:30 +0200 Subject: [PATCH 1723/2553] flow: simplify timeout logic Instead of a single big FlowProto array containing timeouts separately for normal and emergency cases, plus the 'Free' pointer for the protoctx, split up these arrays. An array made of FlowProtoTimeout for just the normal timeouts and an mirror of that for emergency timeouts are used through a pointer that will be set at init and by swapped by the emergency logic. It's swapped back when the emergency is over. The free funcs are moved to their own array. This simplifies the timeout lookup code and shrinks the data that is commonly used. --- src/flow-hash.c | 2 + src/flow-manager.c | 76 +++++++++--------- src/flow-manager.h | 4 + src/flow-private.h | 7 +- src/flow.c | 190 +++++++++++++++++++-------------------------- src/flow.h | 10 +-- 6 files changed, 135 insertions(+), 154 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index 466b246cc59b..be4940d7d609 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -367,6 +367,8 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) if (!(SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)) { SC_ATOMIC_OR(flow_flags, FLOW_EMERGENCY); + FlowTimeoutsEmergency(); + /* under high load, waking up the flow mgr each time leads * to high cpu usage. Flows are not timed out much faster if * we check a 1000 times a second. */ diff --git a/src/flow-manager.c b/src/flow-manager.c index cd5e33dd3b2a..be58914a53c0 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -82,6 +82,20 @@ SC_ATOMIC_DECLARE(uint32_t, flowrec_cnt); SC_ATOMIC_EXTERN(unsigned int, flow_flags); + +typedef FlowProtoTimeout *FlowProtoTimeoutPtr; +SC_ATOMIC_DECLARE(FlowProtoTimeoutPtr, flow_timeouts); + +void FlowTimeoutsInit(void) +{ + SC_ATOMIC_SET(flow_timeouts, flow_timeouts_normal); +} + +void FlowTimeoutsEmergency(void) +{ + SC_ATOMIC_SET(flow_timeouts, flow_timeouts_emerg); +} + /* 1 seconds */ #define FLOW_NORMAL_MODE_UPDATE_DELAY_SEC 1 #define FLOW_NORMAL_MODE_UPDATE_DELAY_NSEC 0 @@ -164,42 +178,25 @@ void FlowDisableFlowManagerThread(void) * * \param f flow * \param state flow state - * \param emergency bool indicating emergency mode 1 yes, 0 no * * \retval timeout timeout in seconds */ -static inline uint32_t FlowGetFlowTimeout(const Flow *f, int state, int emergency) +static inline uint32_t FlowGetFlowTimeout(const Flow *f, int state) { uint32_t timeout; - - if (emergency) { - switch(state) { - default: - case FLOW_STATE_NEW: - timeout = flow_proto[f->protomap].emerg_new_timeout; - break; - case FLOW_STATE_ESTABLISHED: - timeout = flow_proto[f->protomap].emerg_est_timeout; - break; - case FLOW_STATE_CLOSED: - timeout = flow_proto[f->protomap].emerg_closed_timeout; - break; - } - } else { /* implies no emergency */ - switch(state) { - default: - case FLOW_STATE_NEW: - timeout = flow_proto[f->protomap].new_timeout; - break; - case FLOW_STATE_ESTABLISHED: - timeout = flow_proto[f->protomap].est_timeout; - break; - case FLOW_STATE_CLOSED: - timeout = flow_proto[f->protomap].closed_timeout; - break; - } + FlowProtoTimeoutPtr flow_timeouts = SC_ATOMIC_GET(flow_timeouts); + switch(state) { + default: + case FLOW_STATE_NEW: + timeout = flow_timeouts[f->protomap].new_timeout; + break; + case FLOW_STATE_ESTABLISHED: + timeout = flow_timeouts[f->protomap].est_timeout; + break; + case FLOW_STATE_CLOSED: + timeout = flow_timeouts[f->protomap].closed_timeout; + break; } - return timeout; } @@ -208,16 +205,15 @@ static inline uint32_t FlowGetFlowTimeout(const Flow *f, int state, int emergenc * * \param f flow * \param ts timestamp - * \param emergency bool indicating emergency mode * * \retval 0 not timed out * \retval 1 timed out */ -static int FlowManagerFlowTimeout(const Flow *f, int state, struct timeval *ts, int emergency) +static int FlowManagerFlowTimeout(const Flow *f, int state, struct timeval *ts) { /* set the timeout value according to the flow operating mode, * flow's state and protocol.*/ - uint32_t timeout = FlowGetFlowTimeout(f, state, emergency); + uint32_t timeout = FlowGetFlowTimeout(f, state); /* do the timeout check */ if ((int32_t)(f->lastts.tv_sec + timeout) >= ts->tv_sec) { @@ -233,7 +229,6 @@ static int FlowManagerFlowTimeout(const Flow *f, int state, struct timeval *ts, * * \param f flow * \param ts timestamp - * \param emergency bool indicating emergency mode * * \retval 0 not timed out just yet * \retval 1 fully timed out, lets kill it @@ -286,7 +281,7 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, int state = SC_ATOMIC_GET(f->flow_state); /* timeout logic goes here */ - if (FlowManagerFlowTimeout(f, state, ts, emergency) == 0) { + if (FlowManagerFlowTimeout(f, state, ts) == 0) { f = f->hprev; continue; } @@ -653,6 +648,8 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) if (len * 100 / flow_config.prealloc > flow_config.emergency_recovery) { SC_ATOMIC_AND(flow_flags, ~FLOW_EMERGENCY); + FlowTimeoutsReset(); + emerg = FALSE; prev_emerg = FALSE; @@ -997,6 +994,7 @@ void TmModuleFlowManagerRegister (void) SCLogDebug("%s registered", tmm_modules[TMM_FLOWMANAGER].name); SC_ATOMIC_INIT(flowmgr_cnt); + SC_ATOMIC_INIT(flow_timeouts); } void TmModuleFlowRecyclerRegister (void) @@ -1049,7 +1047,7 @@ static int FlowMgrTest01 (void) f.proto = IPPROTO_TCP; int state = SC_ATOMIC_GET(f.flow_state); - if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + if (FlowManagerFlowTimeout(&f, state, &ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1108,7 +1106,7 @@ static int FlowMgrTest02 (void) f.proto = IPPROTO_TCP; int state = SC_ATOMIC_GET(f.flow_state); - if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + if (FlowManagerFlowTimeout(&f, state, &ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1155,7 +1153,7 @@ static int FlowMgrTest03 (void) f.flags |= FLOW_EMERGENCY; int state = SC_ATOMIC_GET(f.flow_state); - if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + if (FlowManagerFlowTimeout(&f, state, &ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1215,7 +1213,7 @@ static int FlowMgrTest04 (void) f.flags |= FLOW_EMERGENCY; int state = SC_ATOMIC_GET(f.flow_state); - if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + if (FlowManagerFlowTimeout(&f, state, &ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); diff --git a/src/flow-manager.h b/src/flow-manager.h index 32ae2b2641dd..117c98df6d0c 100644 --- a/src/flow-manager.h +++ b/src/flow-manager.h @@ -24,6 +24,10 @@ #ifndef __FLOW_MANAGER_H__ #define __FLOW_MANAGER_H__ +#define FlowTimeoutsReset() FlowTimeoutsInit() +void FlowTimeoutsInit(void); +void FlowTimeoutsEmergency(void); + /** flow manager scheduling condition */ SCCtrlCondT flow_manager_ctrl_cond; SCCtrlMutex flow_manager_ctrl_mutex; diff --git a/src/flow-private.h b/src/flow-private.h index 507b1aad7dd6..c1323db3b0d8 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -73,7 +73,10 @@ enum { */ /** FlowProto specific timeouts and free/state functions */ -FlowProto flow_proto[FLOW_PROTO_MAX]; + +FlowProtoTimeout flow_timeouts_normal[FLOW_PROTO_MAX]; +FlowProtoTimeout flow_timeouts_emerg[FLOW_PROTO_MAX]; +FlowProtoFreeFunc flow_freefuncs[FLOW_PROTO_MAX]; /** spare/unused/prealloced flows live here */ FlowQueue flow_spare_q; diff --git a/src/flow.c b/src/flow.c index eda2117c446d..ddd6428e63ef 100644 --- a/src/flow.c +++ b/src/flow.c @@ -481,51 +481,41 @@ void FlowShutdown(void) void FlowInitFlowProto(void) { - /*Default*/ - flow_proto[FLOW_PROTO_DEFAULT].new_timeout = FLOW_DEFAULT_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].est_timeout = FLOW_DEFAULT_EST_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].closed_timeout = - FLOW_DEFAULT_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].emerg_new_timeout = - FLOW_DEFAULT_EMERG_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].emerg_est_timeout = - FLOW_DEFAULT_EMERG_EST_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].emerg_closed_timeout = - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].Freefunc = NULL; - /*TCP*/ - flow_proto[FLOW_PROTO_TCP].new_timeout = FLOW_IPPROTO_TCP_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].est_timeout = FLOW_IPPROTO_TCP_EST_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].emerg_new_timeout = - FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].emerg_est_timeout = - FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].emerg_closed_timeout = - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].Freefunc = NULL; - /*UDP*/ - flow_proto[FLOW_PROTO_UDP].new_timeout = FLOW_IPPROTO_UDP_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].est_timeout = FLOW_IPPROTO_UDP_EST_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].emerg_new_timeout = - FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].emerg_est_timeout = - FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].emerg_closed_timeout = - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].Freefunc = NULL; - /*ICMP*/ - flow_proto[FLOW_PROTO_ICMP].new_timeout = FLOW_IPPROTO_ICMP_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].est_timeout = FLOW_IPPROTO_ICMP_EST_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].emerg_new_timeout = - FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].emerg_est_timeout = - FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].emerg_closed_timeout = - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].Freefunc = NULL; + FlowTimeoutsInit(); + +#define SET_DEFAULTS(p, n, e, c, ne, ee, ce) \ + flow_timeouts_normal[(p)].new_timeout = (n); \ + flow_timeouts_normal[(p)].est_timeout = (e); \ + flow_timeouts_normal[(p)].closed_timeout = (c); \ + flow_timeouts_emerg[(p)].new_timeout = (ne); \ + flow_timeouts_emerg[(p)].est_timeout = (ee); \ + flow_timeouts_emerg[(p)].closed_timeout = (ce); + + SET_DEFAULTS(FLOW_PROTO_DEFAULT, + FLOW_DEFAULT_NEW_TIMEOUT, FLOW_DEFAULT_EST_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, + FLOW_DEFAULT_EMERG_NEW_TIMEOUT, FLOW_DEFAULT_EMERG_EST_TIMEOUT, + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT); + SET_DEFAULTS(FLOW_PROTO_TCP, + FLOW_IPPROTO_TCP_NEW_TIMEOUT, FLOW_IPPROTO_TCP_EST_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, + FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT, + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT); + SET_DEFAULTS(FLOW_PROTO_UDP, + FLOW_IPPROTO_UDP_NEW_TIMEOUT, FLOW_IPPROTO_UDP_EST_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, + FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT, + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT); + SET_DEFAULTS(FLOW_PROTO_ICMP, + FLOW_IPPROTO_ICMP_NEW_TIMEOUT, FLOW_IPPROTO_ICMP_EST_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, + FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT, + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT); + + flow_freefuncs[FLOW_PROTO_DEFAULT].Freefunc = NULL; + flow_freefuncs[FLOW_PROTO_TCP].Freefunc = NULL; + flow_freefuncs[FLOW_PROTO_UDP].Freefunc = NULL; + flow_freefuncs[FLOW_PROTO_ICMP].Freefunc = NULL; /* Let's see if we have custom timeouts defined from config */ const char *new = NULL; @@ -555,39 +545,39 @@ void FlowInitFlowProto(void) if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].new_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_DEFAULT].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].est_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_DEFAULT].est_timeout = configval; } if (closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(closed), closed) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].closed_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_DEFAULT].closed_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].emerg_new_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_DEFAULT].new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].emerg_est_timeout= configval; + flow_timeouts_emerg[FLOW_PROTO_DEFAULT].est_timeout= configval; } if (emergency_closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_closed), emergency_closed) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].emerg_closed_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_DEFAULT].closed_timeout = configval; } } @@ -606,39 +596,39 @@ void FlowInitFlowProto(void) if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { - flow_proto[FLOW_PROTO_TCP].new_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_TCP].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { - flow_proto[FLOW_PROTO_TCP].est_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_TCP].est_timeout = configval; } if (closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(closed), closed) > 0) { - flow_proto[FLOW_PROTO_TCP].closed_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_TCP].closed_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { - flow_proto[FLOW_PROTO_TCP].emerg_new_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_TCP].new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { - flow_proto[FLOW_PROTO_TCP].emerg_est_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_TCP].est_timeout = configval; } if (emergency_closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_closed), emergency_closed) > 0) { - flow_proto[FLOW_PROTO_TCP].emerg_closed_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_TCP].closed_timeout = configval; } } @@ -653,26 +643,26 @@ void FlowInitFlowProto(void) if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { - flow_proto[FLOW_PROTO_UDP].new_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_UDP].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { - flow_proto[FLOW_PROTO_UDP].est_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_UDP].est_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { - flow_proto[FLOW_PROTO_UDP].emerg_new_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_UDP].new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { - flow_proto[FLOW_PROTO_UDP].emerg_est_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_UDP].est_timeout = configval; } } @@ -688,26 +678,26 @@ void FlowInitFlowProto(void) if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { - flow_proto[FLOW_PROTO_ICMP].new_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_ICMP].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { - flow_proto[FLOW_PROTO_ICMP].est_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_ICMP].est_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { - flow_proto[FLOW_PROTO_ICMP].emerg_new_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_ICMP].new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { - flow_proto[FLOW_PROTO_ICMP].emerg_est_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_ICMP].est_timeout = configval; } } } @@ -728,8 +718,8 @@ int FlowClearMemory(Flow* f, uint8_t proto_map) SCEnter(); /* call the protocol specific free function if we have one */ - if (flow_proto[proto_map].Freefunc != NULL) { - flow_proto[proto_map].Freefunc(f->protoctx); + if (flow_freefuncs[proto_map].Freefunc != NULL) { + flow_freefuncs[proto_map].Freefunc(f->protoctx); } FlowFreeStorage(f); @@ -752,7 +742,7 @@ int FlowSetProtoFreeFunc (uint8_t proto, void (*Free)(void *)) uint8_t proto_map; proto_map = FlowGetProtoMapping(proto); - flow_proto[proto_map].Freefunc = Free; + flow_freefuncs[proto_map].Freefunc = Free; return 1; } @@ -814,40 +804,35 @@ static int FlowTest01 (void) FlowInitFlowProto(); proto_map = FlowGetProtoMapping(IPPROTO_TCP); - - if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_TCP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_TCP_EST_TIMEOUT) - && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT)){ - printf ("failed in setting TCP flow timeout"); - return 0; - } + FAIL_IF(flow_timeouts_normal[proto_map].new_timeout != FLOW_IPPROTO_TCP_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_normal[proto_map].est_timeout != FLOW_IPPROTO_TCP_EST_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].new_timeout != FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].est_timeout != FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT); proto_map = FlowGetProtoMapping(IPPROTO_UDP); - if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_UDP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_UDP_EST_TIMEOUT) - && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT)){ - printf ("failed in setting UDP flow timeout"); - return 0; - } + FAIL_IF(flow_timeouts_normal[proto_map].new_timeout != FLOW_IPPROTO_UDP_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_normal[proto_map].est_timeout != FLOW_IPPROTO_UDP_EST_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].new_timeout != FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].est_timeout != FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT); proto_map = FlowGetProtoMapping(IPPROTO_ICMP); - if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_ICMP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_ICMP_EST_TIMEOUT) - && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT)){ - printf ("failed in setting ICMP flow timeout"); - return 0; - } + FAIL_IF(flow_timeouts_normal[proto_map].new_timeout != FLOW_IPPROTO_ICMP_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_normal[proto_map].est_timeout != FLOW_IPPROTO_ICMP_EST_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].new_timeout != FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].est_timeout != FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT); proto_map = FlowGetProtoMapping(IPPROTO_DCCP); - if ((flow_proto[proto_map].new_timeout != FLOW_DEFAULT_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_DEFAULT_EST_TIMEOUT) - && (flow_proto[proto_map].emerg_new_timeout != FLOW_DEFAULT_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_DEFAULT_EMERG_EST_TIMEOUT)){ - printf ("failed in setting default flow timeout"); - return 0; - } + FAIL_IF(flow_timeouts_normal[proto_map].new_timeout != FLOW_DEFAULT_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_normal[proto_map].est_timeout != FLOW_DEFAULT_EST_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].new_timeout != FLOW_DEFAULT_EMERG_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].est_timeout != FLOW_DEFAULT_EMERG_EST_TIMEOUT); - return 1; + PASS; } /*Test function for the unit test FlowTest02*/ -void test(void *f) {} +static void test(void *f) {} /** * \test Test the setting of the per protocol free function to free the @@ -863,23 +848,12 @@ static int FlowTest02 (void) FlowSetProtoFreeFunc(IPPROTO_UDP, test); FlowSetProtoFreeFunc(IPPROTO_ICMP, test); - if (flow_proto[FLOW_PROTO_DEFAULT].Freefunc != test) { - printf("Failed in setting default free function\n"); - return 0; - } - if (flow_proto[FLOW_PROTO_TCP].Freefunc != test) { - printf("Failed in setting TCP free function\n"); - return 0; - } - if (flow_proto[FLOW_PROTO_UDP].Freefunc != test) { - printf("Failed in setting UDP free function\n"); - return 0; - } - if (flow_proto[FLOW_PROTO_ICMP].Freefunc != test) { - printf("Failed in setting ICMP free function\n"); - return 0; - } - return 1; + FAIL_IF(flow_freefuncs[FLOW_PROTO_DEFAULT].Freefunc != test); + FAIL_IF(flow_freefuncs[FLOW_PROTO_TCP].Freefunc != test); + FAIL_IF(flow_freefuncs[FLOW_PROTO_UDP].Freefunc != test); + FAIL_IF(flow_freefuncs[FLOW_PROTO_ICMP].Freefunc != test); + + PASS; } /** diff --git a/src/flow.h b/src/flow.h index 199b17ee94af..def9c515efbd 100644 --- a/src/flow.h +++ b/src/flow.h @@ -427,15 +427,15 @@ enum { FLOW_STATE_CLOSED, }; -typedef struct FlowProto_ { +typedef struct FlowProtoTimeout_ { 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; +} FlowProtoTimeout; + +typedef struct FlowProtoFreeFunc_ { void (*Freefunc)(void *); -} FlowProto; +} FlowProtoFreeFunc; /** \brief prepare packet for a life with flow * Set PKT_WANTS_FLOW flag to incidate workers should do a flow lookup From 70c16f50e733f6f7cc40c1bc3465eb966e3be517 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 14 May 2016 08:56:49 +0200 Subject: [PATCH 1724/2553] flow-manager: optimize hash walking Until now the flow manager would walk the entire flow hash table on an interval. It would thus touch all flows, leading to a lot of memory and cache pressure. In scenario's where the number of tracked flows run into the hundreds on thousands, and the memory used can run into many hundreds of megabytes or even gigabytes, this would lead to serious performance degradation. This patch introduces a new approach. A timestamp per flow bucket (hash row) is maintained by the flow manager. It holds the timestamp of the earliest possible timeout of a flow in the list. The hash walk skips rows with timestamps beyond the current time. As the timestamp depends on the flows in the hash row's list, and on the 'state' of each flow in the list, any addition of a flow or changing of a flow's state invalidates the timestamp. The flow manager then has to walk the list again to set a new timestamp. A utility function FlowUpdateState is introduced to change Flow states, taking care of the bucket timestamp invalidation while at it. Empty flow buckets use a special value so that we don't have to take the flow bucket lock to find out the bucket is empty. This patch also adds more performance counters: flow_mgr.flows_checked | Total | 929 flow_mgr.flows_notimeout | Total | 391 flow_mgr.flows_timeout | Total | 538 flow_mgr.flows_removed | Total | 277 flow_mgr.flows_timeout_inuse | Total | 261 flow_mgr.rows_checked | Total | 1000000 flow_mgr.rows_skipped | Total | 998835 flow_mgr.rows_empty | Total | 290 flow_mgr.rows_maxlen | Total | 2 flow_mgr.flows_checked: number of flows checked for timeout in the last pass flow_mgr.flows_notimeout: number of flows out of flow_mgr.flows_checked that didn't time out flow_mgr.flows_timeout: number of out of flow_mgr.flows_checked that did reach the time out flow_mgr.flows_removed: number of flows out of flow_mgr.flows_timeout that were really removed flow_mgr.flows_timeout_inuse: number of flows out of flow_mgr.flows_timeout that were still in use or needed work flow_mgr.rows_checked: hash table rows checked flow_mgr.rows_skipped: hash table rows skipped because non of the flows would time out anyway The counters below are only relating to rows that were not skipped. flow_mgr.rows_empty: empty hash rows flow_mgr.rows_maxlen: max number of flows per hash row. Best to keep low, so increase hash-size if needed. flow_mgr.rows_busy: row skipped because it was locked by another thread --- src/flow-hash.c | 5 ++ src/flow-hash.h | 6 +++ src/flow-manager.c | 118 +++++++++++++++++++++++++++++++++++++++------ src/flow.c | 16 +++++- src/flow.h | 6 ++- src/stream-tcp.c | 4 +- 6 files changed, 136 insertions(+), 19 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index be4940d7d609..a330101b991d 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -487,6 +487,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p FlowInit(f, p); f->flow_hash = hash; f->fb = fb; + FlowUpdateState(f, FLOW_STATE_NEW); /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); @@ -523,6 +524,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p FlowInit(f, p); f->flow_hash = hash; f->fb = fb; + FlowUpdateState(f, FLOW_STATE_NEW); /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts,&f->lastts); @@ -649,6 +651,7 @@ static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv) f->hnext = NULL; f->hprev = NULL; f->fb = NULL; + SC_ATOMIC_SET(fb->next_ts, 0); FBLOCK_UNLOCK(fb); int state = SC_ATOMIC_GET(f->flow_state); @@ -670,6 +673,8 @@ static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv) FlowClearMemory(f, f->protomap); + FlowUpdateState(f, FLOW_STATE_NEW); + FLOWLOCK_UNLOCK(f); (void) SC_ATOMIC_ADD(flow_prune_idx, (flow_config.hash_size - cnt)); diff --git a/src/flow-hash.h b/src/flow-hash.h index e570b055513c..18a8c324b5a0 100644 --- a/src/flow-hash.h +++ b/src/flow-hash.h @@ -48,6 +48,12 @@ typedef struct FlowBucket_ { #else #error Enable FBLOCK_SPIN or FBLOCK_MUTEX #endif + /** timestamp in seconds of the earliest possible moment a flow + * will time out in this row. Set by the flow manager. Cleared + * to 0 by workers, either when new flows are added or when a + * flow state changes. The flow manager sets this to INT_MAX for + * empty buckets. */ + SC_ATOMIC_DECLARE(int32_t, next_ts); } __attribute__((aligned(CLS))) FlowBucket; #ifdef FBLOCK_SPIN diff --git a/src/flow-manager.c b/src/flow-manager.c index be58914a53c0..0deb0bc571ca 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -109,6 +109,18 @@ typedef struct FlowTimeoutCounters_ { uint32_t est; uint32_t clo; uint32_t tcp_reuse; + + uint32_t flows_checked; + uint32_t flows_notimeout; + uint32_t flows_timeout; + uint32_t flows_timeout_inuse; + uint32_t flows_removed; + + uint32_t rows_checked; + uint32_t rows_skipped; + uint32_t rows_empty; + uint32_t rows_busy; + uint32_t rows_maxlen; } FlowTimeoutCounters; /** @@ -181,7 +193,7 @@ void FlowDisableFlowManagerThread(void) * * \retval timeout timeout in seconds */ -static inline uint32_t FlowGetFlowTimeout(const Flow *f, int state) +static inline uint32_t FlowGetFlowTimeout(const Flow *f, enum FlowState state) { uint32_t timeout; FlowProtoTimeoutPtr flow_timeouts = SC_ATOMIC_GET(flow_timeouts); @@ -209,14 +221,18 @@ static inline uint32_t FlowGetFlowTimeout(const Flow *f, int state) * \retval 0 not timed out * \retval 1 timed out */ -static int FlowManagerFlowTimeout(const Flow *f, int state, struct timeval *ts) +static int FlowManagerFlowTimeout(const Flow *f, enum FlowState state, struct timeval *ts, int32_t *next_ts) { /* set the timeout value according to the flow operating mode, * flow's state and protocol.*/ uint32_t timeout = FlowGetFlowTimeout(f, state); + int32_t flow_times_out_at = (int32_t)(f->lastts.tv_sec + timeout); + if (*next_ts == 0 || flow_times_out_at < *next_ts) + *next_ts = flow_times_out_at; + /* do the timeout check */ - if ((int32_t)(f->lastts.tv_sec + timeout) >= ts->tv_sec) { + if (flow_times_out_at >= ts->tv_sec) { return 0; } @@ -268,20 +284,26 @@ static int FlowManagerFlowTimedOut(Flow *f, struct timeval *ts) * \retval cnt timed out flows */ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, - int emergency, FlowTimeoutCounters *counters) + int emergency, FlowTimeoutCounters *counters, int32_t *next_ts) { uint32_t cnt = 0; + uint32_t checked = 0; do { + checked++; + /* check flow timeout based on lastts and state. Both can be * accessed w/o Flow lock as we do have the hash row lock (so flow * can't disappear) and flow_state is atomic. lastts can only * be modified when we have both the flow and hash row lock */ - int state = SC_ATOMIC_GET(f->flow_state); + enum FlowState state = SC_ATOMIC_GET(f->flow_state); /* timeout logic goes here */ - if (FlowManagerFlowTimeout(f, state, ts) == 0) { + if (FlowManagerFlowTimeout(f, state, ts, next_ts) == 0) { + + counters->flows_notimeout++; + f = f->hprev; continue; } @@ -294,6 +316,8 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, Flow *next_flow = f->hprev; + counters->flows_timeout++; + /* check if the flow is fully timed out and * ready to be discarded. */ if (FlowManagerFlowTimedOut(f, ts) == 1) { @@ -347,13 +371,19 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, counters->clo++; break; } + counters->flows_removed++; } else { + counters->flows_timeout_inuse++; FLOWLOCK_UNLOCK(f); } f = next_flow; } while (f != NULL); + counters->flows_checked += checked; + if (checked > counters->rows_maxlen) + counters->rows_maxlen = checked; + return cnt; } @@ -382,20 +412,37 @@ static uint32_t FlowTimeoutHash(struct timeval *ts, uint32_t try_cnt, for (idx = hash_min; idx < hash_max; idx++) { FlowBucket *fb = &flow_hash[idx]; + counters->rows_checked++; + + int32_t check_ts = SC_ATOMIC_GET(fb->next_ts); + if (check_ts > (int32_t)ts->tv_sec) { + counters->rows_skipped++; + continue; + } + /* before grabbing the row lock, make sure we have at least * 9 packets in the pool */ PacketPoolWaitForN(9); - if (FBLOCK_TRYLOCK(fb) != 0) + if (FBLOCK_TRYLOCK(fb) != 0) { + counters->rows_busy++; continue; + } /* flow hash bucket is now locked */ - if (fb->tail == NULL) + if (fb->tail == NULL) { + SC_ATOMIC_SET(fb->next_ts, INT_MAX); + counters->rows_empty++; goto next; + } + + int32_t next_ts = 0; /* we have a flow, or more than one */ - cnt += FlowManagerHashRowTimeout(fb->tail, ts, emergency, counters); + cnt += FlowManagerHashRowTimeout(fb->tail, ts, emergency, counters, &next_ts); + + SC_ATOMIC_SET(fb->next_ts, next_ts); next: FBLOCK_UNLOCK(fb); @@ -502,6 +549,19 @@ typedef struct FlowManagerThreadData_ { uint16_t flow_emerg_mode_enter; uint16_t flow_emerg_mode_over; uint16_t flow_tcp_reuse; + + uint16_t flow_mgr_flows_checked; + uint16_t flow_mgr_flows_notimeout; + uint16_t flow_mgr_flows_timeout; + uint16_t flow_mgr_flows_timeout_inuse; + uint16_t flow_mgr_flows_removed; + + uint16_t flow_mgr_rows_checked; + uint16_t flow_mgr_rows_skipped; + uint16_t flow_mgr_rows_empty; + uint16_t flow_mgr_rows_busy; + uint16_t flow_mgr_rows_maxlen; + } FlowManagerThreadData; static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) @@ -540,6 +600,18 @@ static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) ftd->flow_emerg_mode_over = StatsRegisterCounter("flow.emerg_mode_over", t); ftd->flow_tcp_reuse = StatsRegisterCounter("flow.tcp_reuse", t); + ftd->flow_mgr_flows_checked = StatsRegisterCounter("flow_mgr.flows_checked", t); + ftd->flow_mgr_flows_notimeout = StatsRegisterCounter("flow_mgr.flows_notimeout", t); + ftd->flow_mgr_flows_timeout = StatsRegisterCounter("flow_mgr.flows_timeout", t); + ftd->flow_mgr_flows_timeout_inuse = StatsRegisterCounter("flow_mgr.flows_timeout_inuse", t); + ftd->flow_mgr_flows_removed = StatsRegisterCounter("flow_mgr.flows_removed", t); + + ftd->flow_mgr_rows_checked = StatsRegisterCounter("flow_mgr.rows_checked", t); + ftd->flow_mgr_rows_skipped = StatsRegisterCounter("flow_mgr.rows_skipped", t); + ftd->flow_mgr_rows_empty = StatsRegisterCounter("flow_mgr.rows_empty", t); + ftd->flow_mgr_rows_busy = StatsRegisterCounter("flow_mgr.rows_busy", t); + ftd->flow_mgr_rows_maxlen = StatsRegisterCounter("flow_mgr.rows_maxlen", t); + PacketPoolInit(); return TM_ECODE_OK; } @@ -609,7 +681,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) FlowUpdateSpareFlows(); /* try to time out flows */ - FlowTimeoutCounters counters = { 0, 0, 0, 0, }; + FlowTimeoutCounters counters = { 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,}; FlowTimeoutHash(&ts, 0 /* check all */, ftd->min, ftd->max, &counters); @@ -631,6 +703,18 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) StatsAddUI64(th_v, ftd->flow_mgr_cnt_est, (uint64_t)counters.est); StatsAddUI64(th_v, ftd->flow_tcp_reuse, (uint64_t)counters.tcp_reuse); + StatsSetUI64(th_v, ftd->flow_mgr_flows_checked, (uint64_t)counters.flows_checked); + StatsSetUI64(th_v, ftd->flow_mgr_flows_notimeout, (uint64_t)counters.flows_notimeout); + StatsSetUI64(th_v, ftd->flow_mgr_flows_timeout, (uint64_t)counters.flows_timeout); + StatsSetUI64(th_v, ftd->flow_mgr_flows_removed, (uint64_t)counters.flows_removed); + StatsSetUI64(th_v, ftd->flow_mgr_flows_timeout_inuse, (uint64_t)counters.flows_timeout_inuse); + + StatsSetUI64(th_v, ftd->flow_mgr_rows_checked, (uint64_t)counters.rows_checked); + StatsSetUI64(th_v, ftd->flow_mgr_rows_skipped, (uint64_t)counters.rows_skipped); + StatsSetUI64(th_v, ftd->flow_mgr_rows_maxlen, (uint64_t)counters.rows_maxlen); + StatsSetUI64(th_v, ftd->flow_mgr_rows_busy, (uint64_t)counters.rows_busy); + StatsSetUI64(th_v, ftd->flow_mgr_rows_empty, (uint64_t)counters.rows_empty); + uint32_t len = 0; FQLOCK_LOCK(&flow_spare_q); len = flow_spare_q.len; @@ -1046,8 +1130,9 @@ static int FlowMgrTest01 (void) f.proto = IPPROTO_TCP; + int32_t next_ts = 0; int state = SC_ATOMIC_GET(f.flow_state); - if (FlowManagerFlowTimeout(&f, state, &ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + if (FlowManagerFlowTimeout(&f, state, &ts, &next_ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1105,8 +1190,9 @@ static int FlowMgrTest02 (void) f.fb = &fb; f.proto = IPPROTO_TCP; + int32_t next_ts = 0; int state = SC_ATOMIC_GET(f.flow_state); - if (FlowManagerFlowTimeout(&f, state, &ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + if (FlowManagerFlowTimeout(&f, state, &ts, &next_ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1152,8 +1238,9 @@ static int FlowMgrTest03 (void) f.proto = IPPROTO_TCP; f.flags |= FLOW_EMERGENCY; + int next_ts = 0; int state = SC_ATOMIC_GET(f.flow_state); - if (FlowManagerFlowTimeout(&f, state, &ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + if (FlowManagerFlowTimeout(&f, state, &ts, &next_ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1212,8 +1299,9 @@ static int FlowMgrTest04 (void) f.proto = IPPROTO_TCP; f.flags |= FLOW_EMERGENCY; + int next_ts = 0; int state = SC_ATOMIC_GET(f.flow_state); - if (FlowManagerFlowTimeout(&f, state, &ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + if (FlowManagerFlowTimeout(&f, state, &ts, &next_ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1265,7 +1353,7 @@ static int FlowMgrTest05 (void) struct timeval ts; TimeGet(&ts); /* try to time out flows */ - FlowTimeoutCounters counters = { 0, 0, 0, 0, }; + FlowTimeoutCounters counters = { 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,}; FlowTimeoutHash(&ts, 0 /* check all */, 0, flow_config.hash_size, &counters); if (flow_recycle_q.len > 0) { diff --git a/src/flow.c b/src/flow.c index ddd6428e63ef..e7671c59f89e 100644 --- a/src/flow.c +++ b/src/flow.c @@ -251,7 +251,7 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p) p->flowflags |= FLOW_PKT_ESTABLISHED; if (f->proto != IPPROTO_TCP) { - SC_ATOMIC_SET(f->flow_state, FLOW_STATE_ESTABLISHED); + FlowUpdateState(f, FLOW_STATE_ESTABLISHED); } } @@ -378,6 +378,7 @@ void FlowInitConfig(char quiet) uint32_t i = 0; for (i = 0; i < flow_config.hash_size; i++) { FBLOCK_INIT(&flow_hash[i]); + SC_ATOMIC_INIT(flow_hash[i].next_ts); } (void) SC_ATOMIC_ADD(flow_memuse, (flow_config.hash_size * sizeof(FlowBucket))); @@ -460,6 +461,7 @@ void FlowShutdown(void) } FBLOCK_DESTROY(&flow_hash[u]); + SC_ATOMIC_DESTROY(flow_hash[u].next_ts); } SCFreeAligned(flow_hash); flow_hash = NULL; @@ -787,6 +789,18 @@ uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags) return newflags; } +void FlowUpdateState(Flow *f, enum FlowState s) +{ + /* set the state */ + SC_ATOMIC_SET(f->flow_state, s); + + if (f->fb) { + /* and reset the flow buckup next_ts value so that the flow manager + * has to revisit this row */ + SC_ATOMIC_SET(f->fb->next_ts, 0); + } +} + /************************************Unittests*******************************/ #ifdef UNITTESTS diff --git a/src/flow.h b/src/flow.h index def9c515efbd..df5d9a4ac4d7 100644 --- a/src/flow.h +++ b/src/flow.h @@ -421,7 +421,7 @@ typedef struct Flow_ uint64_t tosrcbytecnt; } Flow; -enum { +enum FlowState { FLOW_STATE_NEW = 0, FLOW_STATE_ESTABLISHED, FLOW_STATE_CLOSED, @@ -465,6 +465,10 @@ int FlowGetPacketDirection(const Flow *, const Packet *); void FlowCleanupAppLayer(Flow *); +void FlowUpdateState(Flow *f, enum FlowState s); + +/** ----- Inline functions ----- */ + /** \brief Set the No Packet Inspection Flag without locking the flow. * * \param f Flow to set the flag in diff --git a/src/stream-tcp.c b/src/stream-tcp.c index a0517f3a4b32..470d4208f112 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -662,12 +662,12 @@ static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn, case TCP_FIN_WAIT2: case TCP_CLOSING: case TCP_CLOSE_WAIT: - SC_ATOMIC_SET(p->flow->flow_state, FLOW_STATE_ESTABLISHED); + FlowUpdateState(p->flow, FLOW_STATE_ESTABLISHED); break; case TCP_LAST_ACK: case TCP_TIME_WAIT: case TCP_CLOSED: - SC_ATOMIC_SET(p->flow->flow_state, FLOW_STATE_CLOSED); + FlowUpdateState(p->flow, FLOW_STATE_CLOSED); break; } } From 682459d640318f4d3f991e52a04cab5c71140c39 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 13:15:48 +0200 Subject: [PATCH 1725/2553] file: remove dead code --- src/util-file.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/util-file.c b/src/util-file.c index 502fcf059b15..5089210216b8 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -157,10 +157,6 @@ void FileForceHashParseCfg(ConfNode *conf) ConfNode *field = NULL; TAILQ_FOREACH(field, &forcehash_node->head, next) { - if (field == NULL) { - break; - } - if (strcasecmp("md5", field->val) == 0) { #ifdef HAVE_NSS FileForceMd5Enable(); From 6530c3d0d820d3aea02360dbd31f7c90c3881efe Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Sep 2016 08:40:33 +0200 Subject: [PATCH 1726/2553] unittests: replace SCMutex* calls by FLOWLOCK_* --- src/app-layer-dcerpc-udp.c | 6 +- src/app-layer-dcerpc.c | 234 ++++++------- src/app-layer-detect-proto.c | 30 +- src/app-layer-ftp.c | 48 +-- src/app-layer-htp-file.c | 252 +++++++------- src/app-layer-htp.c | 250 +++++++------- src/app-layer-modbus.c | 160 ++++----- src/app-layer-parser.c | 12 +- src/app-layer-smb.c | 96 +++--- src/app-layer-smb2.c | 6 +- src/app-layer-smtp.c | 550 +++++++++++++++--------------- src/app-layer-ssh.c | 384 ++++++++++----------- src/app-layer-ssl.c | 282 +++++++-------- src/detect-dce-iface.c | 78 ++--- src/detect-dce-opnum.c | 24 +- src/detect-dce-stub-data.c | 108 +++--- src/detect-dns-query.c | 90 ++--- src/detect-engine-dcepayload.c | 66 ++-- src/detect-engine-filedata-smtp.c | 14 +- src/detect-engine-hcbd.c | 6 +- src/detect-engine-hcd.c | 102 +++--- src/detect-engine-hhd.c | 258 +++++++------- src/detect-engine-hhhd.c | 150 ++++---- src/detect-engine-hmd.c | 102 +++--- src/detect-engine-hrhd.c | 240 ++++++------- src/detect-engine-hrhhd.c | 150 ++++---- src/detect-engine-hrl.c | 324 +++++++++--------- src/detect-engine-hrud.c | 294 ++++++++-------- src/detect-engine-hsbd.c | 264 +++++++------- src/detect-engine-hscd.c | 186 +++++----- src/detect-engine-hsmd.c | 186 +++++----- src/detect-engine-hua.c | 102 +++--- src/detect-engine-modbus.c | 54 +-- src/detect-engine-state.c | 132 +++---- src/detect-engine-uri.c | 324 +++++++++--------- src/detect-ftpbounce.c | 24 +- src/detect-http-client-body.c | 158 ++++----- src/detect-http-cookie.c | 66 ++-- src/detect-http-header.c | 90 ++--- src/detect-http-hh.c | 108 +++--- src/detect-http-hrh.c | 120 +++---- src/detect-http-method.c | 24 +- src/detect-http-raw-header.c | 72 ++-- src/detect-http-server-body.c | 312 ++++++++--------- src/detect-http-stat-code.c | 32 +- src/detect-http-stat-msg.c | 24 +- src/detect-http-ua.c | 108 +++--- src/detect-lua.c | 48 +-- src/detect-pcre.c | 120 +++---- src/detect-ssh-proto-version.c | 34 +- src/detect-ssh-software-version.c | 36 +- src/detect-ssl-state.c | 20 +- src/detect-ssl-version.c | 36 +- src/detect-template-buffer.c | 4 +- src/detect-tls-cert-issuer.c | 12 +- src/detect-tls-cert-subject.c | 12 +- src/detect-tls-sni.c | 12 +- src/detect-tls-version.c | 36 +- src/detect-uricontent.c | 52 +-- src/detect-urilen.c | 6 +- src/detect.c | 66 ++-- src/stream-tcp-reassemble.c | 78 ++--- src/stream-tcp.c | 116 +++---- 63 files changed, 3695 insertions(+), 3695 deletions(-) diff --git a/src/app-layer-dcerpc-udp.c b/src/app-layer-dcerpc-udp.c index 218f58e65e4e..56ed637f8611 100644 --- a/src/app-layer-dcerpc-udp.c +++ b/src/app-layer-dcerpc-udp.c @@ -1075,15 +1075,15 @@ int DCERPCUDPParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCUDPState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index ece676e7f143..6efe6d029ee4 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -2421,15 +2421,15 @@ int DCERPCParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcbind, bindlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -2457,15 +2457,15 @@ int DCERPCParserTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpcbindack, bindacklen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (dcerpc_state->dcerpc.dcerpchdr.type != BIND_ACK) { printf("expected dcerpc type 0x%02x , got 0x%02x : ", BIND_ACK, dcerpc_state->dcerpc.dcerpchdr.type); result = 0; @@ -2481,15 +2481,15 @@ int DCERPCParserTest01(void) printUUID("BIND_ACK", uuid_entry); } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_EOF, dcerpcrequest, requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (dcerpc_state->dcerpc.dcerpchdr.type != REQUEST) { printf("expected dcerpc type 0x%02x , got 0x%02x : ", REQUEST, dcerpc_state->dcerpc.dcerpchdr.type); result = 0; @@ -2653,15 +2653,15 @@ int DCERPCParserTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -2853,15 +2853,15 @@ int DCERPCParserTest03(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4302,16 +4302,16 @@ int DCERPCParserTest05(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4328,16 +4328,16 @@ int DCERPCParserTest05(void) m++; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); item = NULL; m = 0; @@ -4477,16 +4477,16 @@ int DCERPCParserTest06(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4500,16 +4500,16 @@ int DCERPCParserTest06(void) result &= (dcerpc_state->dcerpc.dcerpcbindbindack.numctxitems == 16); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.numctxitemsleft == 8); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.ctxbytesprocessed == 0); @@ -4563,16 +4563,16 @@ int DCERPCParserTest07(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4586,32 +4586,32 @@ int DCERPCParserTest07(void) dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 12); result &= (dcerpc_state->dcerpc.pdu_fragged = 1); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 38); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 14); result &= (dcerpc_state->dcerpc.pdu_fragged = 1); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && @@ -4655,16 +4655,16 @@ int DCERPCParserTest08(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, request, request_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4715,16 +4715,16 @@ int DCERPCParserTest09(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, request, request_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4789,16 +4789,16 @@ int DCERPCParserTest10(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, fault, fault_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4807,31 +4807,31 @@ int DCERPCParserTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 2); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer == NULL); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && @@ -4890,16 +4890,16 @@ int DCERPCParserTest11(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4913,30 +4913,30 @@ int DCERPCParserTest11(void) dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 12); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 2); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && @@ -4989,16 +4989,16 @@ int DCERPCParserTest12(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack1, bind_ack1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5010,16 +5010,16 @@ int DCERPCParserTest12(void) result &= (dcerpc_state->dcerpc.bytesprocessed == 24); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack2, bind_ack2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); @@ -5067,16 +5067,16 @@ int DCERPCParserTest13(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5158,16 +5158,16 @@ int DCERPCParserTest14(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5220,16 +5220,16 @@ int DCERPCParserTest15(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5682,16 +5682,16 @@ int DCERPCParserTest16(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5700,16 +5700,16 @@ int DCERPCParserTest16(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack1, bind_ack1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5732,16 +5732,16 @@ int DCERPCParserTest16(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5752,16 +5752,16 @@ int DCERPCParserTest16(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack2, bind_ack2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5784,16 +5784,16 @@ int DCERPCParserTest16(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind3, bind3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5804,16 +5804,16 @@ int DCERPCParserTest16(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack3, bind_ack3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5928,16 +5928,16 @@ int DCERPCParserTest17(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5946,16 +5946,16 @@ int DCERPCParserTest17(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5978,16 +5978,16 @@ int DCERPCParserTest17(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, alter_context, alter_context_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5998,16 +5998,16 @@ int DCERPCParserTest17(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, alter_context_resp, alter_context_resp_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -6073,16 +6073,16 @@ int DCERPCParserTest18(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -6095,16 +6095,16 @@ int DCERPCParserTest18(void) result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer == NULL); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && @@ -6339,14 +6339,14 @@ int DCERPCParserTest19(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpcbind, bindlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -6359,14 +6359,14 @@ int DCERPCParserTest19(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpcbindack, bindacklen); if (r == 0) { printf("dce parser didn't return fail\n"); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result = 1; end: diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 541fa24e9003..e9b2480e7fe0 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -3341,14 +3341,14 @@ static int AppLayerProtoDetectTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -3434,14 +3434,14 @@ static int AppLayerProtoDetectTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -3529,14 +3529,14 @@ static int AppLayerProtoDetectTest18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -3620,14 +3620,14 @@ static int AppLayerProtoDetectTest19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_FTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); @@ -3722,14 +3722,14 @@ static int AppLayerProtoDetectTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index 985a75e02e06..6e90a4a00ea3 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -392,15 +392,15 @@ int FTPParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf, ftplen); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -444,35 +444,35 @@ int FTPParserTest03(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf3, ftplen3); if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -513,15 +513,15 @@ int FTPParserTest06(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -565,25 +565,25 @@ int FTPParserTest07(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -635,15 +635,15 @@ int FTPParserTest10(void) else if (u == (ftplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, flags, &ftpbuf1[u], 1); if (r != 0) { SCLogDebug("toserver chunk %" PRIu32 " returned %" PRId32 ", expected 0: ", u, r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); } FtpState *ftp_state = f.alstate; diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index 0045bbaad7c1..a3505f3110a1 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -313,26 +313,26 @@ static int HTPFileParserTest01(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -405,48 +405,48 @@ static int HTPFileParserTest02(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -529,70 +529,70 @@ static int HTPFileParserTest03(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -684,70 +684,70 @@ static int HTPFileParserTest04(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -821,26 +821,26 @@ static int HTPFileParserTest05(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -933,26 +933,26 @@ static int HTPFileParserTest06(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1034,26 +1034,26 @@ static int HTPFileParserTest07(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1128,26 +1128,26 @@ static int HTPFileParserTest08(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1156,14 +1156,14 @@ static int HTPFileParserTest08(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events == NULL) { printf("no app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); if (decoder_events->cnt != 2) { printf("expected 2 events: "); @@ -1224,48 +1224,48 @@ static int HTPFileParserTest09(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1274,14 +1274,14 @@ static int HTPFileParserTest09(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events == NULL) { printf("no app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); if (decoder_events->cnt != 1) { printf("expected 1 event: "); @@ -1340,48 +1340,48 @@ static int HTPFileParserTest10(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1390,14 +1390,14 @@ static int HTPFileParserTest10(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events != NULL) { printf("app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); result = 1; end: @@ -1479,44 +1479,44 @@ static int HTPFileParserTest11(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1524,14 +1524,14 @@ static int HTPFileParserTest11(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events != NULL) { printf("app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0); if (tx == NULL) { diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index d87abd18fbaa..93925d4ed218 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2848,15 +2848,15 @@ int HTPParserTest01(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -2925,15 +2925,15 @@ static int HTPParserTest01a(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -2987,15 +2987,15 @@ int HTPParserTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -3052,15 +3052,15 @@ int HTPParserTest03(void) else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { @@ -3113,14 +3113,14 @@ int HTPParserTest04(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); htp_state = f->alstate; if (htp_state == NULL) { @@ -3182,12 +3182,12 @@ int HTPParserTest05(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } @@ -3195,21 +3195,21 @@ int HTPParserTest05(void) httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } @@ -3217,7 +3217,7 @@ int HTPParserTest05(void) httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } @@ -3225,10 +3225,10 @@ int HTPParserTest05(void) httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -3327,12 +3327,12 @@ int HTPParserTest06(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } @@ -3340,10 +3340,10 @@ int HTPParserTest06(void) httplen2); if (r != 0) { printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -3416,15 +3416,15 @@ int HTPParserTest07(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -3515,16 +3515,16 @@ libhtp:\n\ uint8_t flags = 0; flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk returned %" PRId32 ", expected" " 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); htp_state = f->alstate; if (htp_state == NULL) { @@ -3602,15 +3602,15 @@ libhtp:\n\ uint8_t flags = 0; flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk returned %" PRId32 ", expected" " 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); htp_state = f->alstate; if (htp_state == NULL) { @@ -3678,15 +3678,15 @@ int HTPParserTest10(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -3770,15 +3770,15 @@ static int HTPParserTest11(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -3855,15 +3855,15 @@ static int HTPParserTest12(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -3943,15 +3943,15 @@ int HTPParserTest13(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -4354,16 +4354,16 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -4537,15 +4537,15 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -4706,15 +4706,15 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -4873,15 +4873,15 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -5010,15 +5010,15 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -5120,15 +5120,15 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -5230,15 +5230,15 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -5341,15 +5341,15 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -5449,15 +5449,15 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -5558,15 +5558,15 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -5713,23 +5713,23 @@ libhtp:\n\ StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 1 again <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -5737,14 +5737,14 @@ libhtp:\n\ goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetDecoderEvents(f->alparser); if (decoder_events != NULL) { printf("app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); result = 1; end: if (alp_tctx != NULL) @@ -5831,28 +5831,28 @@ libhtp:\n\ else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)&httpbuf[u], 1); if (u < 18294) { /* first 18294 bytes should result in 0 */ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } } else if (u == 18294UL) { /* byte 18294 should result in error */ if (r != -1) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " -1: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } /* break out, htp state is in error state now */ - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); break; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { @@ -5869,14 +5869,14 @@ libhtp:\n\ goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events == NULL) { printf("no app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); if (decoder_events->events[0] != HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG) { printf("HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG not set: "); @@ -5973,15 +5973,15 @@ libhtp:\n\ else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)&httpbuf[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { @@ -5998,14 +5998,14 @@ libhtp:\n\ goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events != NULL) { printf("app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); result = 1; end: @@ -6056,14 +6056,14 @@ int HTPParserTest16(void) uint8_t flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)httpbuf, len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); htp_state = f->alstate; if (htp_state == NULL) { @@ -6080,14 +6080,14 @@ int HTPParserTest16(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events == NULL) { printf("no app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); if (decoder_events->events[0] != HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT) { printf("HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT not set: "); @@ -6139,12 +6139,12 @@ int HTPParserTest17(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } @@ -6152,14 +6152,14 @@ int HTPParserTest17(void) httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } @@ -6167,11 +6167,11 @@ int HTPParserTest17(void) httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -6262,12 +6262,12 @@ int HTPParserTest18(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } @@ -6275,21 +6275,21 @@ int HTPParserTest18(void) httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } @@ -6298,11 +6298,11 @@ int HTPParserTest18(void) httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -6389,12 +6389,12 @@ int HTPParserTest19(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } @@ -6402,18 +6402,18 @@ int HTPParserTest19(void) httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index f02c2124d894..14dff540ccbf 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1723,15 +1723,15 @@ static int ModbusParserTest01(void) { StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readCoilsReq, sizeof(readCoilsReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -1748,15 +1748,15 @@ static int ModbusParserTest01(void) { goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, readCoilsRsp, sizeof(readCoilsRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); @@ -1788,15 +1788,15 @@ static int ModbusParserTest02(void) { StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -1817,15 +1817,15 @@ static int ModbusParserTest02(void) { goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); @@ -1887,15 +1887,15 @@ static int ModbusParserTest03(void) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readWriteMultipleRegistersReq, sizeof(readWriteMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -1920,15 +1920,15 @@ static int ModbusParserTest03(void) { goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, readWriteMultipleRegistersRsp, sizeof(readWriteMultipleRegistersRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); @@ -1975,15 +1975,15 @@ static int ModbusParserTest04(void) { StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, forceListenOnlyMode, sizeof(forceListenOnlyMode)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2054,15 +2054,15 @@ static int ModbusParserTest05(void) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, invalidProtocolIdReq, sizeof(invalidProtocolIdReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2140,15 +2140,15 @@ static int ModbusParserTest06(void) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, readCoilsRsp, sizeof(readCoilsRsp)); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2226,16 +2226,16 @@ static int ModbusParserTest07(void) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, invalidLengthWriteMultipleRegistersReq, sizeof(invalidLengthWriteMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2313,15 +2313,15 @@ static int ModbusParserTest08(void) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readCoilsReq, sizeof(readCoilsReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2338,15 +2338,15 @@ static int ModbusParserTest08(void) { goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, readCoilsErrorRsp, sizeof(readCoilsErrorRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); @@ -2396,12 +2396,12 @@ static int ModbusParserTest09(void) { StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len - part2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -2409,10 +2409,10 @@ static int ModbusParserTest09(void) { input, input_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2433,12 +2433,12 @@ static int ModbusParserTest09(void) { part2_len = 10; input = readCoilsRsp; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len - part2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -2446,10 +2446,10 @@ static int ModbusParserTest09(void) { input, input_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); @@ -2491,15 +2491,15 @@ static int ModbusParserTest10(void) { StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2535,15 +2535,15 @@ static int ModbusParserTest10(void) { memcpy(input, readCoilsRsp, sizeof(readCoilsRsp)); memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp)); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, sizeof(input_len)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result = 1; end: @@ -2602,16 +2602,16 @@ static int ModbusParserTest11(void) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, exceededLengthWriteMultipleRegistersReq, sizeof(exceededLengthWriteMultipleRegistersReq) + 65523 /* header.length - 7 */ * sizeof(uint8_t)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2689,16 +2689,16 @@ static int ModbusParserTest12(void) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, invalidLengthPDUWriteMultipleRegistersReq, sizeof(invalidLengthPDUWriteMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2746,15 +2746,15 @@ static int ModbusParserTest13(void) { StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, maskWriteRegisterReq, sizeof(maskWriteRegisterReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2771,15 +2771,15 @@ static int ModbusParserTest13(void) { goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, maskWriteRegisterRsp, sizeof(maskWriteRegisterRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); @@ -2811,15 +2811,15 @@ static int ModbusParserTest14(void) { StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, writeSingleRegisterReq, sizeof(writeSingleRegisterReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2836,15 +2836,15 @@ static int ModbusParserTest14(void) { goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, writeSingleRegisterRsp, sizeof(writeSingleRegisterRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); @@ -2906,16 +2906,16 @@ static int ModbusParserTest15(void) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, invalidMaskWriteRegisterReq, sizeof(invalidMaskWriteRegisterReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -2938,15 +2938,15 @@ static int ModbusParserTest15(void) { goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, maskWriteRegisterRsp, sizeof(maskWriteRegisterRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); @@ -3015,15 +3015,15 @@ static int ModbusParserTest16(void) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, invalidWriteSingleRegisterReq, sizeof(invalidWriteSingleRegisterReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -3047,15 +3047,15 @@ static int ModbusParserTest16(void) { goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, writeSingleRegisterRsp, sizeof(writeSingleRegisterRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 4d95fe12b3ac..be47acf542b3 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -1511,15 +1511,15 @@ static int AppLayerParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, testbuf, testlen); if (r != -1) { printf("returned %" PRId32 ", expected -1: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); if (!(ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) { printf("flag should have been set, but is not: "); @@ -1564,16 +1564,16 @@ static int AppLayerParserTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, testbuf, testlen); if (r != -1) { printf("returned %" PRId32 ", expected -1: \n", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); end: AppLayerParserRestoreParserTable(); diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index d79b5b959182..2e007a095960 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -1590,14 +1590,14 @@ int SMBParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_EOF, smbbuf, smblen); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -1667,14 +1667,14 @@ int SMBParserTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_EOF, smbbuf, smblen); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -1963,14 +1963,14 @@ int SMBParserTest03(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -1983,22 +1983,22 @@ int SMBParserTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf3, smblen3); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); printUUID("BIND", smb_state->dcerpc.dcerpcbindbindack.uuid_entry); result = 1; end: @@ -2080,14 +2080,14 @@ int SMBParserTest04(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -2100,30 +2100,30 @@ int SMBParserTest04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf3, smblen3); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf4, smblen4); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result = 1; end: @@ -2335,14 +2335,14 @@ int SMBParserTest07(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -2409,14 +2409,14 @@ int SMBParserTest08(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -2440,14 +2440,14 @@ int SMBParserTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT, smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smb_state->smb.command != SMB_COM_NEGOTIATE) { printf("we should expect SMB command 0x%02x , got 0x%02x : ", @@ -2523,14 +2523,14 @@ int SMBParserTest09(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -2554,14 +2554,14 @@ int SMBParserTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smb_state->smb.command != SMB_COM_NEGOTIATE) { printf("we should expect SMB command 0x%02x , got 0x%02x : ", @@ -2645,14 +2645,14 @@ int SMBParserTest10(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -2665,14 +2665,14 @@ int SMBParserTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT, smbbuf2, smblen2); if (r == 0) { printf("smb parser didn't return fail\n"); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result = 1; end: diff --git a/src/app-layer-smb2.c b/src/app-layer-smb2.c index 7f5ea2051be1..90a369889879 100644 --- a/src/app-layer-smb2.c +++ b/src/app-layer-smb2.c @@ -640,15 +640,15 @@ int SMB2ParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB2, STREAM_TOSERVER|STREAM_EOF, smb2buf, smb2len); if (r != 0) { printf("smb2 header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMB2State *smb2_state = f.alstate; if (smb2_state == NULL) { diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index a28e299fb331..739511a134d3 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1797,15 +1797,15 @@ static int SMTPParserTest01(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -1819,15 +1819,15 @@ static int SMTPParserTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1837,15 +1837,15 @@ static int SMTPParserTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1854,15 +1854,15 @@ static int SMTPParserTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1872,15 +1872,15 @@ static int SMTPParserTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2156,15 +2156,15 @@ static int SMTPParserTest02(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -2178,15 +2178,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2196,15 +2196,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2213,15 +2213,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2231,15 +2231,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2248,15 +2248,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2266,15 +2266,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2283,15 +2283,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2301,15 +2301,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply4, reply4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2319,15 +2319,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_1, request5_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2338,15 +2338,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_2, request5_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2357,15 +2357,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_3, request5_3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2376,15 +2376,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_4, request5_4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2395,15 +2395,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_5, request5_5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2413,15 +2413,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply5, reply5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2430,15 +2430,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request6, request6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2448,15 +2448,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply6, reply6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2465,15 +2465,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request7, request7_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2483,15 +2483,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply7, reply7_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2500,15 +2500,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request8, request8_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2518,15 +2518,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply8, reply8_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2536,15 +2536,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_1, request9_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2555,15 +2555,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_2, request9_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2574,15 +2574,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_3, request9_3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2593,15 +2593,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_4, request9_4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2612,15 +2612,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_5, request9_5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2630,15 +2630,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply9, reply9_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2647,15 +2647,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request10, request10_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2665,15 +2665,15 @@ static int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply10, reply10_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2791,15 +2791,15 @@ static int SMTPParserTest03(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -2813,15 +2813,15 @@ static int SMTPParserTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2831,15 +2831,15 @@ static int SMTPParserTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2848,15 +2848,15 @@ static int SMTPParserTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 3 || smtp_state->cmds_idx != 0 || @@ -2868,15 +2868,15 @@ static int SMTPParserTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2939,15 +2939,15 @@ static int SMTPParserTest04(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -2961,15 +2961,15 @@ static int SMTPParserTest04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -3087,15 +3087,15 @@ static int SMTPParserTest05(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -3109,15 +3109,15 @@ static int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -3127,15 +3127,15 @@ static int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -3144,15 +3144,15 @@ static int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -3162,15 +3162,15 @@ static int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -3186,15 +3186,15 @@ static int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -3204,15 +3204,15 @@ static int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -3384,15 +3384,15 @@ static int SMTPParserTest06(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -3406,15 +3406,15 @@ static int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -3424,15 +3424,15 @@ static int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -3441,15 +3441,15 @@ static int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -3459,15 +3459,15 @@ static int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -3476,15 +3476,15 @@ static int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -3494,15 +3494,15 @@ static int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -3511,15 +3511,15 @@ static int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -3532,15 +3532,15 @@ static int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5, request5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -3552,15 +3552,15 @@ static int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request6, request6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -3623,15 +3623,15 @@ static int SMTPParserTest07(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -3647,15 +3647,15 @@ static int SMTPParserTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || @@ -3666,15 +3666,15 @@ static int SMTPParserTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || @@ -3737,15 +3737,15 @@ static int SMTPParserTest08(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -3761,15 +3761,15 @@ static int SMTPParserTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || @@ -3780,15 +3780,15 @@ static int SMTPParserTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || @@ -3851,15 +3851,15 @@ static int SMTPParserTest09(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -3875,15 +3875,15 @@ static int SMTPParserTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || @@ -3894,15 +3894,15 @@ static int SMTPParserTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || @@ -3965,15 +3965,15 @@ static int SMTPParserTest10(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -3989,15 +3989,15 @@ static int SMTPParserTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || @@ -4008,15 +4008,15 @@ static int SMTPParserTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || @@ -4073,15 +4073,15 @@ static int SMTPParserTest11(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -4097,15 +4097,15 @@ static int SMTPParserTest11(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || @@ -4188,15 +4188,15 @@ static int SMTPParserTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START, request1, request1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); smtp_state = f.alstate; if (smtp_state == NULL) { @@ -4212,15 +4212,15 @@ static int SMTPParserTest12(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT | STREAM_TOCLIENT, reply1, reply1_len); if (r == 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -4329,15 +4329,15 @@ static int SMTPParserTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START, request1, request1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); smtp_state = f.alstate; if (smtp_state == NULL) { @@ -4353,15 +4353,15 @@ static int SMTPParserTest13(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -4371,15 +4371,15 @@ static int SMTPParserTest13(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -4591,16 +4591,16 @@ static int SMTPParserTest14(void) StreamTcpInitConfig(TRUE); SMTPTestInitConfig(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* Welcome reply */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -4614,15 +4614,15 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -4632,23 +4632,23 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* EHLO Reply */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) { printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -4657,16 +4657,16 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* MAIL FROM Request */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -4676,13 +4676,13 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* MAIL FROM Reply */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -4691,11 +4691,11 @@ static int SMTPParserTest14(void) printf("incorrect parsing of MAIL FROM field '%s' (%d)\n", smtp_state->curr_tx->mail_from, smtp_state->curr_tx->mail_from_len); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -4704,16 +4704,16 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* RCPT TO Request */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -4723,16 +4723,16 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* RCPT TO Reply */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -4747,16 +4747,16 @@ static int SMTPParserTest14(void) smtp_config.mime_config.decode_quoted_printable = 1; MimeDecSetConfig(&smtp_config.mime_config); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* DATA request */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || @@ -4767,16 +4767,16 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* Data reply */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply4, reply4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -4786,16 +4786,16 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* DATA message */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4_msg, request4_msg_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || @@ -4807,16 +4807,16 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* DATA . request */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4_end, request4_end_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || @@ -4868,16 +4868,16 @@ static int SMTPParserTest14(void) } } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* DATA . reply */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply4_end, reply4_end_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -4886,16 +4886,16 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* QUIT Request */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5, request5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -4905,16 +4905,16 @@ static int SMTPParserTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* QUIT Reply */ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply5, reply5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index 98b5c76a54b3..823c3080a23a 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -561,14 +561,14 @@ static int SSHParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -627,14 +627,14 @@ static int SSHParserTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -693,14 +693,14 @@ static int SSHParserTest03(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -745,14 +745,14 @@ static int SSHParserTest04(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -811,14 +811,14 @@ static int SSHParserTest05(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -876,14 +876,14 @@ static int SSHParserTest06(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* Ok, it returned an error. Let's make sure we didn't parse the string at all */ SshState *ssh_state = f.alstate; @@ -930,23 +930,23 @@ static int SSHParserTest07(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1008,32 +1008,32 @@ static int SSHParserTest08(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1091,23 +1091,23 @@ static int SSHParserTest09(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1169,32 +1169,32 @@ static int SSHParserTest10(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1253,23 +1253,23 @@ static int SSHParserTest11(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1335,32 +1335,32 @@ static int SSHParserTest12(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1427,33 +1427,33 @@ static int SSHParserTest13(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); for (u = 0; u < sshlen2; u++) { - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, &sshbuf2[u], 1); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); } for (u = 0; u < sshlen3; u++) { - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, &sshbuf3[u], 1); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1526,46 +1526,46 @@ static int SSHParserTest14(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf5, sshlen5); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1638,46 +1638,46 @@ static int SSHParserTest15(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf5, sshlen5); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1743,32 +1743,32 @@ static int SSHParserTest16(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1836,41 +1836,41 @@ static int SSHParserTest17(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1946,50 +1946,50 @@ static int SSHParserTest18(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, server1, serverlen1); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, server2, serverlen2); if (r != 0) { printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2052,41 +2052,41 @@ static int SSHParserTest19(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2172,42 +2172,42 @@ static int SSHParserTest20(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCLogDebug("chunk 4:"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2279,42 +2279,42 @@ static int SSHParserTest21(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCLogDebug("chunk 4:"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2414,42 +2414,42 @@ static int SSHParserTest22(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); #if 0 SCLogDebug("chunk 4:"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); #endif SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2506,14 +2506,14 @@ static int SSHParserTest23(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toclient chunk 1 returned 0 expected non null: "); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result = 1; end: @@ -2539,14 +2539,14 @@ static int SSHParserTest24(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 1107fb2f8a4d..347097773778 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -1816,15 +1816,15 @@ static int SSLParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_EOF, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -1872,25 +1872,25 @@ static int SSLParserTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -1940,35 +1940,35 @@ static int SSLParserTest03(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -2020,45 +2020,45 @@ static int SSLParserTest04(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -2364,15 +2364,15 @@ static int SSLParserMultimsgTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -2445,15 +2445,15 @@ static int SSLParserMultimsgTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -2515,15 +2515,15 @@ static int SSLParserTest07(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -2701,25 +2701,25 @@ static int SSLParserTest09(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -2789,25 +2789,25 @@ static int SSLParserTest10(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -2876,25 +2876,25 @@ static int SSLParserTest11(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -2968,35 +2968,35 @@ static int SSLParserTest12(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf3, buf3_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -3075,45 +3075,45 @@ static int SSLParserTest13(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf3, buf3_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf4, buf4_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -3171,25 +3171,25 @@ static int SSLParserTest14(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -3228,15 +3228,15 @@ static int SSLParserTest15(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); end: if (alp_tctx != NULL) @@ -3268,15 +3268,15 @@ static int SSLParserTest16(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); end: if (alp_tctx != NULL) @@ -3308,15 +3308,15 @@ static int SSLParserTest17(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); end: if (alp_tctx != NULL) @@ -3354,25 +3354,25 @@ static int SSLParserTest18(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -3412,15 +3412,15 @@ static int SSLParserTest19(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -3460,15 +3460,15 @@ static int SSLParserTest20(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); end: if (alp_tctx != NULL) @@ -3502,15 +3502,15 @@ static int SSLParserTest21(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_EOF, buf, buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; if (app_state == NULL) { @@ -3569,16 +3569,16 @@ static int SSLParserTest22(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT | STREAM_EOF, buf, buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; if (app_state == NULL) { @@ -3874,16 +3874,16 @@ static int SSLParserTest23(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_START, chello_buf, chello_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; if (app_state == NULL) { @@ -3915,16 +3915,16 @@ static int SSLParserTest23(void) } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, shello_buf_len); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", @@ -3949,16 +3949,16 @@ static int SSLParserTest23(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, client_change_cipher_spec_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* with multiple records the client content type hold the type from the last * record */ @@ -3988,16 +3988,16 @@ static int SSLParserTest23(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_change_cipher_spec_buf, server_change_cipher_spec_buf_len); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* with multiple records the serve content type hold the type from the last * record */ @@ -4029,16 +4029,16 @@ static int SSLParserTest23(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, toserver_app_data_buf, toserver_app_data_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (app_state->client_connp.content_type != SSLV3_APPLICATION_PROTOCOL) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", @@ -4122,25 +4122,25 @@ static int SSLParserTest24(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -4501,14 +4501,14 @@ static int SSLParserTest25(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, client_hello_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -4523,16 +4523,16 @@ static int SSLParserTest25(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello_certificate_done, server_hello_certificate_done_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (ssl_state->client_connp.bytes_processed != 0 || ssl_state->client_connp.hs_bytes_processed != 0) @@ -4541,16 +4541,16 @@ static int SSLParserTest25(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_key_exchange_cipher_enc_hs, client_key_exchange_cipher_enc_hs_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* The reason hs_bytes_processed is 2 is because, the record * immediately after the client key exchange is 2 bytes long, diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 6a712041ba4c..10cf7f5e6b70 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -894,15 +894,15 @@ static int DetectDceIfaceTestParse12(void) SCLogDebug("handling to_server chunk"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -920,15 +920,15 @@ static int DetectDceIfaceTestParse12(void) SCLogDebug("handling to_client chunk"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -938,15 +938,15 @@ static int DetectDceIfaceTestParse12(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1400,15 +1400,15 @@ static int DetectDceIfaceTestParse14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1422,15 +1422,15 @@ static int DetectDceIfaceTestParse14(void) if (PacketAlertCheck(p, 1)) goto end; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1440,15 +1440,15 @@ static int DetectDceIfaceTestParse14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1610,15 +1610,15 @@ static int DetectDceIfaceTestParse15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1634,15 +1634,15 @@ static int DetectDceIfaceTestParse15(void) if (PacketAlertCheck(p, 2)) goto end; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1656,15 +1656,15 @@ static int DetectDceIfaceTestParse15(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_alter_context, dcerpc_alter_context_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1678,15 +1678,15 @@ static int DetectDceIfaceTestParse15(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_alter_context_resp, dcerpc_alter_context_resp_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1700,15 +1700,15 @@ static int DetectDceIfaceTestParse15(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1722,15 +1722,15 @@ static int DetectDceIfaceTestParse15(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1744,15 +1744,15 @@ static int DetectDceIfaceTestParse15(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 50544fd14b60..f5d3f1d55ee6 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -1160,15 +1160,15 @@ static int DetectDceOpnumTestParse08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1176,25 +1176,25 @@ static int DetectDceOpnumTestParse08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_EOF, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1699,15 +1699,15 @@ static int DetectDceOpnumTestParse09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index 987a9b9fa3d8..d39ed2778696 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -620,15 +620,15 @@ static int DetectDceStubDataTestParse02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -646,15 +646,15 @@ static int DetectDceStubDataTestParse02(void) goto end; /* do detect */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -665,15 +665,15 @@ static int DetectDceStubDataTestParse02(void) if (PacketAlertCheck(p, 1)) goto end; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_EOF, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1175,15 +1175,15 @@ static int DetectDceStubDataTestParse03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1381,15 +1381,15 @@ static int DetectDceStubDataTestParse04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1400,29 +1400,29 @@ static int DetectDceStubDataTestParse04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* request1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1433,15 +1433,15 @@ static int DetectDceStubDataTestParse04(void) goto end; /* response1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1452,15 +1452,15 @@ static int DetectDceStubDataTestParse04(void) goto end; /* request2 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1471,15 +1471,15 @@ static int DetectDceStubDataTestParse04(void) goto end; /* response2 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1490,15 +1490,15 @@ static int DetectDceStubDataTestParse04(void) goto end; /* request3 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1509,15 +1509,15 @@ static int DetectDceStubDataTestParse04(void) goto end; /* response3 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1692,15 +1692,15 @@ static int DetectDceStubDataTestParse05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1717,15 +1717,15 @@ static int DetectDceStubDataTestParse05(void) goto end; /* response1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1736,15 +1736,15 @@ static int DetectDceStubDataTestParse05(void) goto end; /* request2 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1755,15 +1755,15 @@ static int DetectDceStubDataTestParse05(void) goto end; /* response2 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1774,15 +1774,15 @@ static int DetectDceStubDataTestParse05(void) goto end; /* request3 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1793,15 +1793,15 @@ static int DetectDceStubDataTestParse05(void) goto end; /* response3 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 9df43871545b..2463fd2e94b7 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -149,14 +149,14 @@ static int DetectDnsQueryTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -287,14 +287,14 @@ static int DetectDnsQueryTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -314,14 +314,14 @@ static int DetectDnsQueryTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf2, sizeof(buf2)); if (r != 0) { printf("toserver client 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -335,14 +335,14 @@ static int DetectDnsQueryTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf3, sizeof(buf3)); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p3); @@ -433,14 +433,14 @@ static int DetectDnsQueryTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -539,14 +539,14 @@ static int DetectDnsQueryTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -562,14 +562,14 @@ static int DetectDnsQueryTest04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf2, sizeof(buf2)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -709,14 +709,14 @@ static int DetectDnsQueryTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -736,14 +736,14 @@ static int DetectDnsQueryTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf2, sizeof(buf2)); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -757,14 +757,14 @@ static int DetectDnsQueryTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf3, sizeof(buf3)); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p3); @@ -778,14 +778,14 @@ static int DetectDnsQueryTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf4, sizeof(buf4)); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p4); @@ -881,14 +881,14 @@ static int DetectDnsQueryTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -1030,14 +1030,14 @@ static int DetectDnsQueryTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -1057,14 +1057,14 @@ static int DetectDnsQueryTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf2, sizeof(buf2)); if (r != -1) { printf("toserver client 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -1082,14 +1082,14 @@ static int DetectDnsQueryTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf3, sizeof(buf3)); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p3); diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index c28f05752a3a..79182f41ca74 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -6538,15 +6538,15 @@ int DcePayloadTest15(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -6654,15 +6654,15 @@ int DcePayloadTest16(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -6770,15 +6770,15 @@ int DcePayloadTest17(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -6886,15 +6886,15 @@ int DcePayloadTest18(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -7002,15 +7002,15 @@ int DcePayloadTest19(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -7118,15 +7118,15 @@ int DcePayloadTest20(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -7223,15 +7223,15 @@ int DcePayloadTest21(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -7324,15 +7324,15 @@ int DcePayloadTest22(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -7426,15 +7426,15 @@ int DcePayloadTest23(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -9642,15 +9642,15 @@ int DcePayloadTest42(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -9744,15 +9744,15 @@ int DcePayloadTest43(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if ( !(PacketAlertCheck(p, 1))) { diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index e8bcf7769d39..45b2e80a6066 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -372,14 +372,14 @@ static int DetectEngineSMTPFiledataTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, mimemsg, mimemsg_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %d", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); smtp_state = f.alstate; if (smtp_state == NULL) { @@ -504,21 +504,21 @@ static int DetectEngineSMTPFiledataTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = 0; r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, mimemsg1, mimemsg1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %d", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, mimemsg2, mimemsg2_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %d", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); smtp_state = f.alstate; if (smtp_state == NULL) { diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index fddfaa56d06c..1e25976158d1 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -385,17 +385,17 @@ static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, b->direction, (uint8_t *)b->input, b->input_size ? b->input_size : strlen((const char *)b->input)); if (r != 0) { printf("toserver chunk %d returned %" PRId32 ", expected 0: ", i+1, r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index f7ec7fca1a53..6217a3bff82c 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -249,15 +249,15 @@ static int DetectEngineHttpCookieTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -347,15 +347,15 @@ static int DetectEngineHttpCookieTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -445,15 +445,15 @@ static int DetectEngineHttpCookieTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -543,15 +543,15 @@ static int DetectEngineHttpCookieTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -641,15 +641,15 @@ static int DetectEngineHttpCookieTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -739,15 +739,15 @@ static int DetectEngineHttpCookieTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -837,15 +837,15 @@ static int DetectEngineHttpCookieTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -935,15 +935,15 @@ static int DetectEngineHttpCookieTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1033,15 +1033,15 @@ static int DetectEngineHttpCookieTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1132,15 +1132,15 @@ static int DetectEngineHttpCookieTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1231,15 +1231,15 @@ static int DetectEngineHttpCookieTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1330,15 +1330,15 @@ static int DetectEngineHttpCookieTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1429,15 +1429,15 @@ static int DetectEngineHttpCookieTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1528,15 +1528,15 @@ static int DetectEngineHttpCookieTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1627,15 +1627,15 @@ static int DetectEngineHttpCookieTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1726,15 +1726,15 @@ static int DetectEngineHttpCookieTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1825,15 +1825,15 @@ static int DetectEngineHttpCookieTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index d5863ecf4b84..6d05b2837caa 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -384,15 +384,15 @@ static int DetectEngineHttpHeaderTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -480,15 +480,15 @@ static int DetectEngineHttpHeaderTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -576,15 +576,15 @@ static int DetectEngineHttpHeaderTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -672,15 +672,15 @@ static int DetectEngineHttpHeaderTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -768,15 +768,15 @@ static int DetectEngineHttpHeaderTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -864,15 +864,15 @@ static int DetectEngineHttpHeaderTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -960,15 +960,15 @@ static int DetectEngineHttpHeaderTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1056,15 +1056,15 @@ static int DetectEngineHttpHeaderTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1152,15 +1152,15 @@ static int DetectEngineHttpHeaderTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1248,15 +1248,15 @@ static int DetectEngineHttpHeaderTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1344,15 +1344,15 @@ static int DetectEngineHttpHeaderTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1440,15 +1440,15 @@ static int DetectEngineHttpHeaderTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1536,15 +1536,15 @@ static int DetectEngineHttpHeaderTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1632,15 +1632,15 @@ static int DetectEngineHttpHeaderTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1728,15 +1728,15 @@ static int DetectEngineHttpHeaderTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1824,15 +1824,15 @@ static int DetectEngineHttpHeaderTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1920,15 +1920,15 @@ static int DetectEngineHttpHeaderTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2174,15 +2174,15 @@ static int DetectEngineHttpHeaderTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2199,15 +2199,15 @@ static int DetectEngineHttpHeaderTest20(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2298,15 +2298,15 @@ static int DetectEngineHttpHeaderTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2323,15 +2323,15 @@ static int DetectEngineHttpHeaderTest21(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2422,15 +2422,15 @@ static int DetectEngineHttpHeaderTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2447,15 +2447,15 @@ static int DetectEngineHttpHeaderTest22(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2546,15 +2546,15 @@ static int DetectEngineHttpHeaderTest23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2571,15 +2571,15 @@ static int DetectEngineHttpHeaderTest23(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2670,15 +2670,15 @@ static int DetectEngineHttpHeaderTest24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2695,15 +2695,15 @@ static int DetectEngineHttpHeaderTest24(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2794,15 +2794,15 @@ static int DetectEngineHttpHeaderTest25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2819,15 +2819,15 @@ static int DetectEngineHttpHeaderTest25(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2918,15 +2918,15 @@ static int DetectEngineHttpHeaderTest26(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2943,15 +2943,15 @@ static int DetectEngineHttpHeaderTest26(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3042,15 +3042,15 @@ static int DetectEngineHttpHeaderTest27(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3067,15 +3067,15 @@ static int DetectEngineHttpHeaderTest27(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3170,16 +3170,16 @@ static int DetectEngineHttpHeaderTest28(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3196,15 +3196,15 @@ static int DetectEngineHttpHeaderTest28(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3299,16 +3299,16 @@ static int DetectEngineHttpHeaderTest29(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3325,15 +3325,15 @@ static int DetectEngineHttpHeaderTest29(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3461,16 +3461,16 @@ static int DetectEngineHttpHeaderTest30(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3487,15 +3487,15 @@ static int DetectEngineHttpHeaderTest30(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3583,15 +3583,15 @@ static int DetectEngineHttpHeaderTest31(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3686,15 +3686,15 @@ static int DetectEngineHttpHeaderTest32(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3797,15 +3797,15 @@ static int DetectEngineHttpHeaderTest33(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3822,15 +3822,15 @@ static int DetectEngineHttpHeaderTest33(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index e0d8ac9e9604..b3ab4aa893c7 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -214,15 +214,15 @@ static int DetectEngineHttpHHTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -312,15 +312,15 @@ static int DetectEngineHttpHHTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -410,15 +410,15 @@ static int DetectEngineHttpHHTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -508,15 +508,15 @@ static int DetectEngineHttpHHTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -606,15 +606,15 @@ static int DetectEngineHttpHHTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -704,15 +704,15 @@ static int DetectEngineHttpHHTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -802,15 +802,15 @@ static int DetectEngineHttpHHTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -900,15 +900,15 @@ static int DetectEngineHttpHHTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -998,15 +998,15 @@ static int DetectEngineHttpHHTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1097,15 +1097,15 @@ static int DetectEngineHttpHHTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1196,15 +1196,15 @@ static int DetectEngineHttpHHTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1295,15 +1295,15 @@ static int DetectEngineHttpHHTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1394,15 +1394,15 @@ static int DetectEngineHttpHHTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1493,15 +1493,15 @@ static int DetectEngineHttpHHTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1592,15 +1592,15 @@ static int DetectEngineHttpHHTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1691,15 +1691,15 @@ static int DetectEngineHttpHHTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1790,15 +1790,15 @@ static int DetectEngineHttpHHTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1884,15 +1884,15 @@ static int DetectEngineHttpHHTest18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1978,15 +1978,15 @@ static int DetectEngineHttpHHTest19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2072,15 +2072,15 @@ static int DetectEngineHttpHHTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2165,15 +2165,15 @@ static int DetectEngineHttpHHTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2258,15 +2258,15 @@ static int DetectEngineHttpHHTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2351,15 +2351,15 @@ static int DetectEngineHttpHHTest23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2445,15 +2445,15 @@ static int DetectEngineHttpHHTest24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2539,15 +2539,15 @@ static int DetectEngineHttpHHTest25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 00c7dc9904e2..924db480fea9 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -205,15 +205,15 @@ static int DetectEngineHttpMethodTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -302,15 +302,15 @@ static int DetectEngineHttpMethodTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -399,15 +399,15 @@ static int DetectEngineHttpMethodTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -496,15 +496,15 @@ static int DetectEngineHttpMethodTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -593,15 +593,15 @@ static int DetectEngineHttpMethodTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -690,15 +690,15 @@ static int DetectEngineHttpMethodTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -787,15 +787,15 @@ static int DetectEngineHttpMethodTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -884,15 +884,15 @@ static int DetectEngineHttpMethodTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -981,15 +981,15 @@ static int DetectEngineHttpMethodTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1079,15 +1079,15 @@ static int DetectEngineHttpMethodTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1177,15 +1177,15 @@ static int DetectEngineHttpMethodTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1275,15 +1275,15 @@ static int DetectEngineHttpMethodTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1373,15 +1373,15 @@ static int DetectEngineHttpMethodTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1471,15 +1471,15 @@ static int DetectEngineHttpMethodTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1569,15 +1569,15 @@ static int DetectEngineHttpMethodTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1667,15 +1667,15 @@ static int DetectEngineHttpMethodTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1765,15 +1765,15 @@ static int DetectEngineHttpMethodTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index e4d6c5e20a40..9c757a9dd25c 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -256,15 +256,15 @@ static int DetectEngineHttpRawHeaderTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -352,15 +352,15 @@ static int DetectEngineHttpRawHeaderTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -448,15 +448,15 @@ static int DetectEngineHttpRawHeaderTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -544,15 +544,15 @@ static int DetectEngineHttpRawHeaderTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -640,15 +640,15 @@ static int DetectEngineHttpRawHeaderTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -736,15 +736,15 @@ static int DetectEngineHttpRawHeaderTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -832,15 +832,15 @@ static int DetectEngineHttpRawHeaderTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -928,15 +928,15 @@ static int DetectEngineHttpRawHeaderTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1024,15 +1024,15 @@ static int DetectEngineHttpRawHeaderTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1120,15 +1120,15 @@ static int DetectEngineHttpRawHeaderTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1216,15 +1216,15 @@ static int DetectEngineHttpRawHeaderTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1312,15 +1312,15 @@ static int DetectEngineHttpRawHeaderTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1408,15 +1408,15 @@ static int DetectEngineHttpRawHeaderTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1504,15 +1504,15 @@ static int DetectEngineHttpRawHeaderTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1600,15 +1600,15 @@ static int DetectEngineHttpRawHeaderTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1696,15 +1696,15 @@ static int DetectEngineHttpRawHeaderTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1792,15 +1792,15 @@ static int DetectEngineHttpRawHeaderTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2046,15 +2046,15 @@ static int DetectEngineHttpRawHeaderTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2071,15 +2071,15 @@ static int DetectEngineHttpRawHeaderTest20(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2170,15 +2170,15 @@ static int DetectEngineHttpRawHeaderTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2195,15 +2195,15 @@ static int DetectEngineHttpRawHeaderTest21(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2294,15 +2294,15 @@ static int DetectEngineHttpRawHeaderTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2319,15 +2319,15 @@ static int DetectEngineHttpRawHeaderTest22(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2418,15 +2418,15 @@ static int DetectEngineHttpRawHeaderTest23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2443,15 +2443,15 @@ static int DetectEngineHttpRawHeaderTest23(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2542,15 +2542,15 @@ static int DetectEngineHttpRawHeaderTest24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2567,15 +2567,15 @@ static int DetectEngineHttpRawHeaderTest24(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2666,15 +2666,15 @@ static int DetectEngineHttpRawHeaderTest25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2691,15 +2691,15 @@ static int DetectEngineHttpRawHeaderTest25(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2790,15 +2790,15 @@ static int DetectEngineHttpRawHeaderTest26(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2815,15 +2815,15 @@ static int DetectEngineHttpRawHeaderTest26(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2912,15 +2912,15 @@ static int DetectEngineHttpRawHeaderTest27(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2937,15 +2937,15 @@ static int DetectEngineHttpRawHeaderTest27(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3040,16 +3040,16 @@ static int DetectEngineHttpRawHeaderTest28(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3066,15 +3066,15 @@ static int DetectEngineHttpRawHeaderTest28(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3169,16 +3169,16 @@ static int DetectEngineHttpRawHeaderTest29(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3195,15 +3195,15 @@ static int DetectEngineHttpRawHeaderTest29(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3325,15 +3325,15 @@ static int DetectEngineHttpRawHeaderTest31(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3437,15 +3437,15 @@ static int DetectEngineHttpRawHeaderTest32(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3462,15 +3462,15 @@ static int DetectEngineHttpRawHeaderTest32(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index b3c894dd4efc..c5a51d63510f 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -242,15 +242,15 @@ static int DetectEngineHttpHRHTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -340,15 +340,15 @@ static int DetectEngineHttpHRHTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -438,15 +438,15 @@ static int DetectEngineHttpHRHTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -536,15 +536,15 @@ static int DetectEngineHttpHRHTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -634,15 +634,15 @@ static int DetectEngineHttpHRHTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -732,15 +732,15 @@ static int DetectEngineHttpHRHTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -830,15 +830,15 @@ static int DetectEngineHttpHRHTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -928,15 +928,15 @@ static int DetectEngineHttpHRHTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1026,15 +1026,15 @@ static int DetectEngineHttpHRHTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1125,15 +1125,15 @@ static int DetectEngineHttpHRHTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1224,15 +1224,15 @@ static int DetectEngineHttpHRHTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1323,15 +1323,15 @@ static int DetectEngineHttpHRHTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1422,15 +1422,15 @@ static int DetectEngineHttpHRHTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1521,15 +1521,15 @@ static int DetectEngineHttpHRHTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1620,15 +1620,15 @@ static int DetectEngineHttpHRHTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1719,15 +1719,15 @@ static int DetectEngineHttpHRHTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1818,15 +1818,15 @@ static int DetectEngineHttpHRHTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1912,15 +1912,15 @@ static int DetectEngineHttpHRHTest18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2006,15 +2006,15 @@ static int DetectEngineHttpHRHTest19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2100,15 +2100,15 @@ static int DetectEngineHttpHRHTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2193,15 +2193,15 @@ static int DetectEngineHttpHRHTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2286,15 +2286,15 @@ static int DetectEngineHttpHRHTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2379,15 +2379,15 @@ static int DetectEngineHttpHRHTest23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2473,15 +2473,15 @@ static int DetectEngineHttpHRHTest24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2567,15 +2567,15 @@ static int DetectEngineHttpHRHTest25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-engine-hrl.c b/src/detect-engine-hrl.c index da1c14c577e8..09b3fa98227c 100644 --- a/src/detect-engine-hrl.c +++ b/src/detect-engine-hrl.c @@ -161,14 +161,14 @@ static int UriTestSig01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -186,14 +186,14 @@ static int UriTestSig01(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -283,14 +283,14 @@ static int UriTestSig02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -308,14 +308,14 @@ static int UriTestSig02(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -405,14 +405,14 @@ static int UriTestSig03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -430,14 +430,14 @@ static int UriTestSig03(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -527,14 +527,14 @@ static int UriTestSig04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -552,14 +552,14 @@ static int UriTestSig04(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -649,14 +649,14 @@ static int UriTestSig05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -674,14 +674,14 @@ static int UriTestSig05(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -771,14 +771,14 @@ static int UriTestSig06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -796,14 +796,14 @@ static int UriTestSig06(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -893,14 +893,14 @@ static int UriTestSig07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -918,14 +918,14 @@ static int UriTestSig07(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1015,14 +1015,14 @@ static int UriTestSig08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1040,14 +1040,14 @@ static int UriTestSig08(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1137,14 +1137,14 @@ static int UriTestSig09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1162,14 +1162,14 @@ static int UriTestSig09(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1259,14 +1259,14 @@ static int UriTestSig10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1284,14 +1284,14 @@ static int UriTestSig10(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1382,14 +1382,14 @@ static int UriTestSig11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1407,14 +1407,14 @@ static int UriTestSig11(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1505,14 +1505,14 @@ static int UriTestSig12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1530,14 +1530,14 @@ static int UriTestSig12(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1627,14 +1627,14 @@ static int UriTestSig13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1652,14 +1652,14 @@ static int UriTestSig13(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1750,14 +1750,14 @@ static int UriTestSig14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1775,14 +1775,14 @@ static int UriTestSig14(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1873,14 +1873,14 @@ static int UriTestSig15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1898,14 +1898,14 @@ static int UriTestSig15(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1994,14 +1994,14 @@ static int UriTestSig16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2022,14 +2022,14 @@ static int UriTestSig16(void) p->payload = http_buf2; p->payload_len = http_buf2_len; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2117,14 +2117,14 @@ static int UriTestSig17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2212,14 +2212,14 @@ static int UriTestSig18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2308,14 +2308,14 @@ static int UriTestSig19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2403,14 +2403,14 @@ static int UriTestSig20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2497,14 +2497,14 @@ static int UriTestSig21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2591,14 +2591,14 @@ static int UriTestSig22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2684,14 +2684,14 @@ static int UriTestSig23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2777,14 +2777,14 @@ static int UriTestSig24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2870,14 +2870,14 @@ static int UriTestSig25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2963,14 +2963,14 @@ static int UriTestSig26(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3056,14 +3056,14 @@ static int UriTestSig27(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3183,14 +3183,14 @@ static int UriTestSig28(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3275,14 +3275,14 @@ static int UriTestSig29(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3367,14 +3367,14 @@ static int UriTestSig30(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3459,14 +3459,14 @@ static int UriTestSig31(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3551,14 +3551,14 @@ static int UriTestSig32(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3641,14 +3641,14 @@ static int UriTestSig33(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3731,14 +3731,14 @@ static int UriTestSig34(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3821,14 +3821,14 @@ static int UriTestSig35(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3911,14 +3911,14 @@ static int UriTestSig36(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -4001,14 +4001,14 @@ static int UriTestSig37(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -4091,14 +4091,14 @@ static int UriTestSig38(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 352923593e09..5f83b3508275 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -225,15 +225,15 @@ static int DetectEngineHttpRawUriTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -250,15 +250,15 @@ static int DetectEngineHttpRawUriTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -349,15 +349,15 @@ static int DetectEngineHttpRawUriTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -459,15 +459,15 @@ static int DetectEngineHttpRawUriTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -484,15 +484,15 @@ static int DetectEngineHttpRawUriTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -587,15 +587,15 @@ static int DetectEngineHttpRawUriTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -612,15 +612,15 @@ static int DetectEngineHttpRawUriTest04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -714,15 +714,15 @@ static int DetectEngineHttpRawUriTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -739,15 +739,15 @@ static int DetectEngineHttpRawUriTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -841,15 +841,15 @@ static int DetectEngineHttpRawUriTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -866,15 +866,15 @@ static int DetectEngineHttpRawUriTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -968,15 +968,15 @@ static int DetectEngineHttpRawUriTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -993,15 +993,15 @@ static int DetectEngineHttpRawUriTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1095,15 +1095,15 @@ static int DetectEngineHttpRawUriTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1120,15 +1120,15 @@ static int DetectEngineHttpRawUriTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1223,15 +1223,15 @@ static int DetectEngineHttpRawUriTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1248,15 +1248,15 @@ static int DetectEngineHttpRawUriTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1351,15 +1351,15 @@ static int DetectEngineHttpRawUriTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1376,15 +1376,15 @@ static int DetectEngineHttpRawUriTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1479,15 +1479,15 @@ static int DetectEngineHttpRawUriTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1504,15 +1504,15 @@ static int DetectEngineHttpRawUriTest11(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1607,15 +1607,15 @@ static int DetectEngineHttpRawUriTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1632,15 +1632,15 @@ static int DetectEngineHttpRawUriTest12(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1735,15 +1735,15 @@ static int DetectEngineHttpRawUriTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1760,15 +1760,15 @@ static int DetectEngineHttpRawUriTest13(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1863,15 +1863,15 @@ static int DetectEngineHttpRawUriTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1888,15 +1888,15 @@ static int DetectEngineHttpRawUriTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1991,15 +1991,15 @@ static int DetectEngineHttpRawUriTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2016,15 +2016,15 @@ static int DetectEngineHttpRawUriTest15(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2119,15 +2119,15 @@ static int DetectEngineHttpRawUriTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2144,15 +2144,15 @@ static int DetectEngineHttpRawUriTest16(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2535,15 +2535,15 @@ static int DetectEngineHttpRawUriTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2560,15 +2560,15 @@ static int DetectEngineHttpRawUriTest21(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2663,15 +2663,15 @@ static int DetectEngineHttpRawUriTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2688,15 +2688,15 @@ static int DetectEngineHttpRawUriTest22(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2791,15 +2791,15 @@ static int DetectEngineHttpRawUriTest23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2816,15 +2816,15 @@ static int DetectEngineHttpRawUriTest23(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2919,15 +2919,15 @@ static int DetectEngineHttpRawUriTest24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2944,15 +2944,15 @@ static int DetectEngineHttpRawUriTest24(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3047,15 +3047,15 @@ static int DetectEngineHttpRawUriTest25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3072,15 +3072,15 @@ static int DetectEngineHttpRawUriTest25(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3175,15 +3175,15 @@ static int DetectEngineHttpRawUriTest26(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3200,15 +3200,15 @@ static int DetectEngineHttpRawUriTest26(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3303,15 +3303,15 @@ static int DetectEngineHttpRawUriTest27(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3328,15 +3328,15 @@ static int DetectEngineHttpRawUriTest27(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3431,15 +3431,15 @@ static int DetectEngineHttpRawUriTest28(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3456,15 +3456,15 @@ static int DetectEngineHttpRawUriTest28(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3546,14 +3546,14 @@ static int DetectEngineHttpRawUriTest29(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3639,14 +3639,14 @@ static int DetectEngineHttpRawUriTest30(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 100134314e30..298f5947757a 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -392,17 +392,17 @@ static int RunTest(struct TestSteps *steps, const char *sig, const char *yaml) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, b->direction, (uint8_t *)b->input, b->input_size ? b->input_size : strlen((const char *)b->input)); if (r != 0) { printf("toserver chunk %d returned %" PRId32 ", expected 0: ", i+1, r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -508,15 +508,15 @@ static int DetectEngineHttpServerBodyTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -533,15 +533,15 @@ static int DetectEngineHttpServerBodyTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -630,25 +630,25 @@ static int DetectEngineHttpServerBodyTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -752,15 +752,15 @@ static int DetectEngineHttpServerBodyTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -777,25 +777,25 @@ static int DetectEngineHttpServerBodyTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -890,15 +890,15 @@ static int DetectEngineHttpServerBodyTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -915,15 +915,15 @@ static int DetectEngineHttpServerBodyTest04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1018,15 +1018,15 @@ static int DetectEngineHttpServerBodyTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1043,15 +1043,15 @@ static int DetectEngineHttpServerBodyTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1146,15 +1146,15 @@ static int DetectEngineHttpServerBodyTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1171,15 +1171,15 @@ static int DetectEngineHttpServerBodyTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1274,15 +1274,15 @@ static int DetectEngineHttpServerBodyTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1299,15 +1299,15 @@ static int DetectEngineHttpServerBodyTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1402,15 +1402,15 @@ static int DetectEngineHttpServerBodyTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1427,15 +1427,15 @@ static int DetectEngineHttpServerBodyTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1531,15 +1531,15 @@ static int DetectEngineHttpServerBodyTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1556,15 +1556,15 @@ static int DetectEngineHttpServerBodyTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1660,15 +1660,15 @@ static int DetectEngineHttpServerBodyTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1685,15 +1685,15 @@ static int DetectEngineHttpServerBodyTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1789,15 +1789,15 @@ static int DetectEngineHttpServerBodyTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1814,15 +1814,15 @@ static int DetectEngineHttpServerBodyTest11(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1918,15 +1918,15 @@ static int DetectEngineHttpServerBodyTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1943,15 +1943,15 @@ static int DetectEngineHttpServerBodyTest12(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2047,15 +2047,15 @@ static int DetectEngineHttpServerBodyTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2072,15 +2072,15 @@ static int DetectEngineHttpServerBodyTest13(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2176,15 +2176,15 @@ static int DetectEngineHttpServerBodyTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2201,15 +2201,15 @@ static int DetectEngineHttpServerBodyTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2305,15 +2305,15 @@ static int DetectEngineHttpServerBodyTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2330,15 +2330,15 @@ static int DetectEngineHttpServerBodyTest15(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2459,15 +2459,15 @@ libhtp:\n\ SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2484,15 +2484,15 @@ libhtp:\n\ goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2502,15 +2502,15 @@ libhtp:\n\ goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2635,15 +2635,15 @@ libhtp:\n\ SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2660,15 +2660,15 @@ libhtp:\n\ goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2678,15 +2678,15 @@ libhtp:\n\ goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3441,15 +3441,15 @@ static int DetectEngineHttpServerBodyFileDataTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3466,15 +3466,15 @@ static int DetectEngineHttpServerBodyFileDataTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3570,15 +3570,15 @@ static int DetectEngineHttpServerBodyFileDataTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3595,15 +3595,15 @@ static int DetectEngineHttpServerBodyFileDataTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3703,15 +3703,15 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3728,15 +3728,15 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 7159835ab236..0d846ddd451b 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -221,15 +221,15 @@ static int DetectEngineHttpStatCodeTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -246,15 +246,15 @@ static int DetectEngineHttpStatCodeTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -343,25 +343,25 @@ static int DetectEngineHttpStatCodeTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -465,15 +465,15 @@ static int DetectEngineHttpStatCodeTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -490,25 +490,25 @@ static int DetectEngineHttpStatCodeTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -603,15 +603,15 @@ static int DetectEngineHttpStatCodeTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -628,15 +628,15 @@ static int DetectEngineHttpStatCodeTest04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -731,15 +731,15 @@ static int DetectEngineHttpStatCodeTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -756,15 +756,15 @@ static int DetectEngineHttpStatCodeTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -859,15 +859,15 @@ static int DetectEngineHttpStatCodeTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -884,15 +884,15 @@ static int DetectEngineHttpStatCodeTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -987,15 +987,15 @@ static int DetectEngineHttpStatCodeTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1012,15 +1012,15 @@ static int DetectEngineHttpStatCodeTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1115,15 +1115,15 @@ static int DetectEngineHttpStatCodeTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1140,15 +1140,15 @@ static int DetectEngineHttpStatCodeTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1244,15 +1244,15 @@ static int DetectEngineHttpStatCodeTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1269,15 +1269,15 @@ static int DetectEngineHttpStatCodeTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1373,15 +1373,15 @@ static int DetectEngineHttpStatCodeTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1398,15 +1398,15 @@ static int DetectEngineHttpStatCodeTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1502,15 +1502,15 @@ static int DetectEngineHttpStatCodeTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1527,15 +1527,15 @@ static int DetectEngineHttpStatCodeTest11(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1631,15 +1631,15 @@ static int DetectEngineHttpStatCodeTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1656,15 +1656,15 @@ static int DetectEngineHttpStatCodeTest12(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1760,15 +1760,15 @@ static int DetectEngineHttpStatCodeTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1785,15 +1785,15 @@ static int DetectEngineHttpStatCodeTest13(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1889,15 +1889,15 @@ static int DetectEngineHttpStatCodeTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1914,15 +1914,15 @@ static int DetectEngineHttpStatCodeTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2018,15 +2018,15 @@ static int DetectEngineHttpStatCodeTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2043,15 +2043,15 @@ static int DetectEngineHttpStatCodeTest15(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 3d662c54afd8..e978c246b1c7 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -221,15 +221,15 @@ static int DetectEngineHttpStatMsgTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -246,15 +246,15 @@ static int DetectEngineHttpStatMsgTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -343,25 +343,25 @@ static int DetectEngineHttpStatMsgTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -465,15 +465,15 @@ static int DetectEngineHttpStatMsgTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -490,25 +490,25 @@ static int DetectEngineHttpStatMsgTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -603,15 +603,15 @@ static int DetectEngineHttpStatMsgTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -628,15 +628,15 @@ static int DetectEngineHttpStatMsgTest04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -731,15 +731,15 @@ static int DetectEngineHttpStatMsgTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -756,15 +756,15 @@ static int DetectEngineHttpStatMsgTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -859,15 +859,15 @@ static int DetectEngineHttpStatMsgTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -884,15 +884,15 @@ static int DetectEngineHttpStatMsgTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -987,15 +987,15 @@ static int DetectEngineHttpStatMsgTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1012,15 +1012,15 @@ static int DetectEngineHttpStatMsgTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1115,15 +1115,15 @@ static int DetectEngineHttpStatMsgTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1140,15 +1140,15 @@ static int DetectEngineHttpStatMsgTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1244,15 +1244,15 @@ static int DetectEngineHttpStatMsgTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1269,15 +1269,15 @@ static int DetectEngineHttpStatMsgTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1373,15 +1373,15 @@ static int DetectEngineHttpStatMsgTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1398,15 +1398,15 @@ static int DetectEngineHttpStatMsgTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1502,15 +1502,15 @@ static int DetectEngineHttpStatMsgTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1527,15 +1527,15 @@ static int DetectEngineHttpStatMsgTest11(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1631,15 +1631,15 @@ static int DetectEngineHttpStatMsgTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1656,15 +1656,15 @@ static int DetectEngineHttpStatMsgTest12(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1760,15 +1760,15 @@ static int DetectEngineHttpStatMsgTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1785,15 +1785,15 @@ static int DetectEngineHttpStatMsgTest13(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1889,15 +1889,15 @@ static int DetectEngineHttpStatMsgTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1914,15 +1914,15 @@ static int DetectEngineHttpStatMsgTest14(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2018,15 +2018,15 @@ static int DetectEngineHttpStatMsgTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2043,15 +2043,15 @@ static int DetectEngineHttpStatMsgTest15(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index acd00a2fedd3..b05e843f0b9b 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -216,15 +216,15 @@ static int DetectEngineHttpUATest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -314,15 +314,15 @@ static int DetectEngineHttpUATest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -412,15 +412,15 @@ static int DetectEngineHttpUATest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -510,15 +510,15 @@ static int DetectEngineHttpUATest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -608,15 +608,15 @@ static int DetectEngineHttpUATest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -706,15 +706,15 @@ static int DetectEngineHttpUATest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -804,15 +804,15 @@ static int DetectEngineHttpUATest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -902,15 +902,15 @@ static int DetectEngineHttpUATest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1000,15 +1000,15 @@ static int DetectEngineHttpUATest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1099,15 +1099,15 @@ static int DetectEngineHttpUATest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1198,15 +1198,15 @@ static int DetectEngineHttpUATest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1297,15 +1297,15 @@ static int DetectEngineHttpUATest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1396,15 +1396,15 @@ static int DetectEngineHttpUATest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1495,15 +1495,15 @@ static int DetectEngineHttpUATest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1594,15 +1594,15 @@ static int DetectEngineHttpUATest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1693,15 +1693,15 @@ static int DetectEngineHttpUATest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1792,15 +1792,15 @@ static int DetectEngineHttpUATest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-engine-modbus.c b/src/detect-engine-modbus.c index d1811d461694..8d53bf39366c 100644 --- a/src/detect-engine-modbus.c +++ b/src/detect-engine-modbus.c @@ -380,15 +380,15 @@ static int DetectEngineInspectModbusTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readWriteMultipleRegistersReq, sizeof(readWriteMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -470,14 +470,14 @@ static int DetectEngineInspectModbusTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, forceListenOnlyMode, sizeof(forceListenOnlyMode)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -559,15 +559,15 @@ static int DetectEngineInspectModbusTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, encapsulatedInterfaceTransport, sizeof(encapsulatedInterfaceTransport)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -649,14 +649,14 @@ static int DetectEngineInspectModbusTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, unassigned, sizeof(unassigned)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -738,15 +738,15 @@ static int DetectEngineInspectModbusTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readCoilsReq, sizeof(readCoilsReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -828,15 +828,15 @@ static int DetectEngineInspectModbusTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readInputsRegistersReq, sizeof(readInputsRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -918,14 +918,14 @@ static int DetectEngineInspectModbusTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readCoilsReq, sizeof(readCoilsReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -1055,15 +1055,15 @@ static int DetectEngineInspectModbusTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readInputsRegistersReq, sizeof(readInputsRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { @@ -1240,15 +1240,15 @@ static int DetectEngineInspectModbusTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readWriteMultipleRegistersReq, sizeof(readWriteMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ModbusState *modbus_state = f.alstate; if (modbus_state == NULL) { diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 4fa24ea51a94..1f38a5c928ee 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -1442,14 +1442,14 @@ static int DeStateSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1458,14 +1458,14 @@ static int DeStateSigTest01(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1474,14 +1474,14 @@ static int DeStateSigTest01(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -1490,15 +1490,15 @@ static int DeStateSigTest01(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1594,14 +1594,14 @@ static int DeStateSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1610,14 +1610,14 @@ static int DeStateSigTest02(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1626,14 +1626,14 @@ static int DeStateSigTest02(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1654,15 +1654,15 @@ static int DeStateSigTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -1671,14 +1671,14 @@ static int DeStateSigTest02(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1687,14 +1687,14 @@ static int DeStateSigTest02(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { @@ -1705,14 +1705,14 @@ static int DeStateSigTest02(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 2))) { @@ -1799,15 +1799,15 @@ static int DeStateSigTest03(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1828,15 +1828,15 @@ static int DeStateSigTest03(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); File *file = files->head; if (file == NULL) { @@ -1926,15 +1926,15 @@ static int DeStateSigTest04(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1955,15 +1955,15 @@ static int DeStateSigTest04(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); File *file = files->head; if (file == NULL) { @@ -2053,15 +2053,15 @@ static int DeStateSigTest05(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -2082,15 +2082,15 @@ static int DeStateSigTest05(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); File *file = files->head; if (file == NULL) { @@ -2180,15 +2180,15 @@ static int DeStateSigTest06(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -2209,15 +2209,15 @@ static int DeStateSigTest06(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); File *file = files->head; if (file == NULL) { @@ -2310,15 +2310,15 @@ static int DeStateSigTest07(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -2328,15 +2328,15 @@ static int DeStateSigTest07(void) } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -2356,15 +2356,15 @@ static int DeStateSigTest07(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); File *file = files->head; if (file == NULL) { diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index 81504bcb669b..09bd2b9927f2 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -226,14 +226,14 @@ static int UriTestSig01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -251,14 +251,14 @@ static int UriTestSig01(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -348,14 +348,14 @@ static int UriTestSig02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -373,14 +373,14 @@ static int UriTestSig02(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -470,14 +470,14 @@ static int UriTestSig03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -495,14 +495,14 @@ static int UriTestSig03(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -592,14 +592,14 @@ static int UriTestSig04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -617,14 +617,14 @@ static int UriTestSig04(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -714,14 +714,14 @@ static int UriTestSig05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -739,14 +739,14 @@ static int UriTestSig05(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -836,14 +836,14 @@ static int UriTestSig06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -861,14 +861,14 @@ static int UriTestSig06(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -958,14 +958,14 @@ static int UriTestSig07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -983,14 +983,14 @@ static int UriTestSig07(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1080,14 +1080,14 @@ static int UriTestSig08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1105,14 +1105,14 @@ static int UriTestSig08(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1202,14 +1202,14 @@ static int UriTestSig09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1227,14 +1227,14 @@ static int UriTestSig09(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1324,14 +1324,14 @@ static int UriTestSig10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1349,14 +1349,14 @@ static int UriTestSig10(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1447,14 +1447,14 @@ static int UriTestSig11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1472,14 +1472,14 @@ static int UriTestSig11(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1570,14 +1570,14 @@ static int UriTestSig12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1595,14 +1595,14 @@ static int UriTestSig12(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1692,14 +1692,14 @@ static int UriTestSig13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1717,14 +1717,14 @@ static int UriTestSig13(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1815,14 +1815,14 @@ static int UriTestSig14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1840,14 +1840,14 @@ static int UriTestSig14(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1938,14 +1938,14 @@ static int UriTestSig15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1963,14 +1963,14 @@ static int UriTestSig15(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2059,14 +2059,14 @@ static int UriTestSig16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2087,14 +2087,14 @@ static int UriTestSig16(void) p->payload = http_buf2; p->payload_len = http_buf2_len; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2182,14 +2182,14 @@ static int UriTestSig17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2277,14 +2277,14 @@ static int UriTestSig18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2373,14 +2373,14 @@ static int UriTestSig19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2468,14 +2468,14 @@ static int UriTestSig20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2562,14 +2562,14 @@ static int UriTestSig21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2656,14 +2656,14 @@ static int UriTestSig22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2749,14 +2749,14 @@ static int UriTestSig23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2842,14 +2842,14 @@ static int UriTestSig24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2935,14 +2935,14 @@ static int UriTestSig25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3028,14 +3028,14 @@ static int UriTestSig26(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3121,14 +3121,14 @@ static int UriTestSig27(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3248,14 +3248,14 @@ static int UriTestSig28(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3340,14 +3340,14 @@ static int UriTestSig29(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3432,14 +3432,14 @@ static int UriTestSig30(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3524,14 +3524,14 @@ static int UriTestSig31(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3616,14 +3616,14 @@ static int UriTestSig32(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3706,14 +3706,14 @@ static int UriTestSig33(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3796,14 +3796,14 @@ static int UriTestSig34(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3886,14 +3886,14 @@ static int UriTestSig35(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3976,14 +3976,14 @@ static int UriTestSig36(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -4066,14 +4066,14 @@ static int UriTestSig37(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -4156,14 +4156,14 @@ static int UriTestSig38(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-ftpbounce.c b/src/detect-ftpbounce.c index f293ca970dcb..c4dea5cb212a 100644 --- a/src/detect-ftpbounce.c +++ b/src/detect-ftpbounce.c @@ -329,12 +329,12 @@ static int DetectFtpbounceTestALMatch02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *)de_ctx,(void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -342,7 +342,7 @@ static int DetectFtpbounceTestALMatch02(void) if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -350,7 +350,7 @@ static int DetectFtpbounceTestALMatch02(void) if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -358,11 +358,11 @@ static int DetectFtpbounceTestALMatch02(void) if (r != 0) { SCLogDebug("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -470,12 +470,12 @@ static int DetectFtpbounceTestALMatch03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *)de_ctx,(void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -483,7 +483,7 @@ static int DetectFtpbounceTestALMatch03(void) if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -491,7 +491,7 @@ static int DetectFtpbounceTestALMatch03(void) if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -499,10 +499,10 @@ static int DetectFtpbounceTestALMatch03(void) if (r != 0) { SCLogDebug("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 24eb5175c981..600d74cfcac1 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -344,15 +344,15 @@ static int DetectHttpClientBodyTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -455,15 +455,15 @@ static int DetectHttpClientBodyTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -479,14 +479,14 @@ static int DetectHttpClientBodyTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -582,15 +582,15 @@ static int DetectHttpClientBodyTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -607,15 +607,15 @@ static int DetectHttpClientBodyTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -712,15 +712,15 @@ static int DetectHttpClientBodyTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -737,15 +737,15 @@ static int DetectHttpClientBodyTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -842,15 +842,15 @@ static int DetectHttpClientBodyTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -867,15 +867,15 @@ static int DetectHttpClientBodyTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -963,15 +963,15 @@ static int DetectHttpClientBodyTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1065,15 +1065,15 @@ static int DetectHttpClientBodyTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1167,15 +1167,15 @@ static int DetectHttpClientBodyTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1275,14 +1275,14 @@ static int DetectHttpClientBodyTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1292,32 +1292,32 @@ static int DetectHttpClientBodyTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1327,15 +1327,15 @@ static int DetectHttpClientBodyTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1345,14 +1345,14 @@ static int DetectHttpClientBodyTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1362,14 +1362,14 @@ static int DetectHttpClientBodyTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1381,14 +1381,14 @@ static int DetectHttpClientBodyTest14(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1494,14 +1494,14 @@ static int DetectHttpClientBodyTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1511,14 +1511,14 @@ static int DetectHttpClientBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1528,14 +1528,14 @@ static int DetectHttpClientBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1545,15 +1545,15 @@ static int DetectHttpClientBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1563,14 +1563,14 @@ static int DetectHttpClientBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1580,14 +1580,14 @@ static int DetectHttpClientBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1599,14 +1599,14 @@ static int DetectHttpClientBodyTest15(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index d43098889243..635d78fccb22 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -370,15 +370,15 @@ static int DetectHttpCookieSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -469,15 +469,15 @@ static int DetectHttpCookieSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -562,15 +562,15 @@ static int DetectHttpCookieSigTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -656,15 +656,15 @@ static int DetectHttpCookieSigTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -750,15 +750,15 @@ static int DetectHttpCookieSigTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -845,14 +845,14 @@ static int DetectHttpCookieSigTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -937,15 +937,15 @@ static int DetectHttpCookieSigTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1048,16 +1048,16 @@ static int DetectHttpCookieSigTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf_request, httpbuf_request_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1072,16 +1072,16 @@ static int DetectHttpCookieSigTest08(void) } /* response */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf_response, httpbuf_response_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1185,16 +1185,16 @@ static int DetectHttpCookieSigTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf_request, httpbuf_request_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1209,16 +1209,16 @@ static int DetectHttpCookieSigTest09(void) } /* response */ - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf_response, httpbuf_response_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 39474ed9c98a..8459d5ab1eec 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -351,15 +351,15 @@ static int DetectHttpHeaderTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -460,15 +460,15 @@ static int DetectHttpHeaderTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -485,15 +485,15 @@ static int DetectHttpHeaderTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -587,15 +587,15 @@ static int DetectHttpHeaderTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -612,15 +612,15 @@ static int DetectHttpHeaderTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -716,15 +716,15 @@ static int DetectHttpHeaderTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -741,15 +741,15 @@ static int DetectHttpHeaderTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -844,15 +844,15 @@ static int DetectHttpHeaderTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -869,15 +869,15 @@ static int DetectHttpHeaderTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -964,15 +964,15 @@ static int DetectHttpHeaderTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1065,15 +1065,15 @@ static int DetectHttpHeaderTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1167,15 +1167,15 @@ static int DetectHttpHeaderTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1574,15 +1574,15 @@ static int DetectHttpHeaderTest28(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1661,15 +1661,15 @@ static int DetectHttpHeaderTest29(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1748,15 +1748,15 @@ static int DetectHttpHeaderTest30(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 4de340a14aee..6345241826e1 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -329,15 +329,15 @@ static int DetectHttpHHTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -436,15 +436,15 @@ static int DetectHttpHHTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -460,14 +460,14 @@ static int DetectHttpHHTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -559,15 +559,15 @@ static int DetectHttpHHTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -584,15 +584,15 @@ static int DetectHttpHHTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -689,15 +689,15 @@ static int DetectHttpHHTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -714,15 +714,15 @@ static int DetectHttpHHTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -819,15 +819,15 @@ static int DetectHttpHHTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -844,15 +844,15 @@ static int DetectHttpHHTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ @@ -939,15 +939,15 @@ static int DetectHttpHHTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1038,15 +1038,15 @@ static int DetectHttpHHTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1138,15 +1138,15 @@ static int DetectHttpHHTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1246,14 +1246,14 @@ static int DetectHttpHHTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1263,14 +1263,14 @@ static int DetectHttpHHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1280,14 +1280,14 @@ static int DetectHttpHHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1297,14 +1297,14 @@ static int DetectHttpHHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1314,14 +1314,14 @@ static int DetectHttpHHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1333,14 +1333,14 @@ static int DetectHttpHHTest14(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index cb6ee2cf442e..efe1cddbdd09 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -329,15 +329,15 @@ static int DetectHttpHRHTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -436,15 +436,15 @@ static int DetectHttpHRHTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -460,14 +460,14 @@ static int DetectHttpHRHTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -559,15 +559,15 @@ static int DetectHttpHRHTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -584,15 +584,15 @@ static int DetectHttpHRHTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -689,15 +689,15 @@ static int DetectHttpHRHTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -714,15 +714,15 @@ static int DetectHttpHRHTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -819,15 +819,15 @@ static int DetectHttpHRHTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -844,15 +844,15 @@ static int DetectHttpHRHTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -938,15 +938,15 @@ static int DetectHttpHRHTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1037,15 +1037,15 @@ static int DetectHttpHRHTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1137,15 +1137,15 @@ static int DetectHttpHRHTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1245,14 +1245,14 @@ static int DetectHttpHRHTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1262,14 +1262,14 @@ static int DetectHttpHRHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1279,14 +1279,14 @@ static int DetectHttpHRHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1296,14 +1296,14 @@ static int DetectHttpHRHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1313,14 +1313,14 @@ static int DetectHttpHRHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1332,14 +1332,14 @@ static int DetectHttpHRHTest14(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -2126,15 +2126,15 @@ static int DetectHttpHRHTest37(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2151,15 +2151,15 @@ static int DetectHttpHRHTest37(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 8fcaaef57fa6..132b76795780 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -496,14 +496,14 @@ static int DetectHttpMethodSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -599,14 +599,14 @@ static int DetectHttpMethodSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -693,14 +693,14 @@ static int DetectHttpMethodSigTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -789,14 +789,14 @@ static int DetectHttpMethodSigTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index ad7effc0497a..5d761ecb3a1f 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -350,15 +350,15 @@ static int DetectHttpRawHeaderTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -459,15 +459,15 @@ static int DetectHttpRawHeaderTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -484,15 +484,15 @@ static int DetectHttpRawHeaderTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -586,15 +586,15 @@ static int DetectHttpRawHeaderTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -611,15 +611,15 @@ static int DetectHttpRawHeaderTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -714,15 +714,15 @@ static int DetectHttpRawHeaderTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -739,15 +739,15 @@ static int DetectHttpRawHeaderTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -842,15 +842,15 @@ static int DetectHttpRawHeaderTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -867,15 +867,15 @@ static int DetectHttpRawHeaderTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -962,15 +962,15 @@ static int DetectHttpRawHeaderTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1063,15 +1063,15 @@ static int DetectHttpRawHeaderTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1165,15 +1165,15 @@ static int DetectHttpRawHeaderTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index 0f1cb2bbaa17..b4af9a402d78 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -365,22 +365,22 @@ static int DetectHttpServerBodyTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -488,21 +488,21 @@ static int DetectHttpServerBodyTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -518,14 +518,14 @@ static int DetectHttpServerBodyTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -625,15 +625,15 @@ static int DetectHttpServerBodyTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -642,15 +642,15 @@ static int DetectHttpServerBodyTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -660,15 +660,15 @@ static int DetectHttpServerBodyTest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -772,15 +772,15 @@ static int DetectHttpServerBodyTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -789,15 +789,15 @@ static int DetectHttpServerBodyTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -807,12 +807,12 @@ static int DetectHttpServerBodyTest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -820,10 +820,10 @@ static int DetectHttpServerBodyTest09(void) if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -927,15 +927,15 @@ static int DetectHttpServerBodyTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -944,15 +944,15 @@ static int DetectHttpServerBodyTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -962,12 +962,12 @@ static int DetectHttpServerBodyTest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -975,10 +975,10 @@ static int DetectHttpServerBodyTest10(void) if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1078,15 +1078,15 @@ static int DetectHttpServerBodyTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1095,15 +1095,15 @@ static int DetectHttpServerBodyTest11(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -1113,15 +1113,15 @@ static int DetectHttpServerBodyTest11(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1221,15 +1221,15 @@ static int DetectHttpServerBodyTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1238,15 +1238,15 @@ static int DetectHttpServerBodyTest12(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -1256,15 +1256,15 @@ static int DetectHttpServerBodyTest12(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1352,22 +1352,22 @@ static int DetectHttpServerBodyTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1479,11 +1479,11 @@ static int DetectHttpServerBodyTest14(void) SCLogDebug("add chunk 1"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -1492,10 +1492,10 @@ static int DetectHttpServerBodyTest14(void) r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCLogDebug("inspect chunk 1"); @@ -1509,11 +1509,11 @@ static int DetectHttpServerBodyTest14(void) SCLogDebug("add chunk 3"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -1522,10 +1522,10 @@ static int DetectHttpServerBodyTest14(void) r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCLogDebug("inspect chunk 4"); @@ -1645,21 +1645,21 @@ static int DetectHttpServerBodyTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1673,21 +1673,21 @@ static int DetectHttpServerBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -2465,22 +2465,22 @@ static int DetectHttpServerBodyFileDataTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2588,12 +2588,12 @@ static int DetectHttpServerBodyFileDataTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -2601,10 +2601,10 @@ static int DetectHttpServerBodyFileDataTest02(void) if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2620,14 +2620,14 @@ static int DetectHttpServerBodyFileDataTest02(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2727,15 +2727,15 @@ static int DetectHttpServerBodyFileDataTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2744,15 +2744,15 @@ static int DetectHttpServerBodyFileDataTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -2762,15 +2762,15 @@ static int DetectHttpServerBodyFileDataTest03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ @@ -2875,15 +2875,15 @@ static int DetectHttpServerBodyFileDataTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2892,15 +2892,15 @@ static int DetectHttpServerBodyFileDataTest04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -2910,12 +2910,12 @@ static int DetectHttpServerBodyFileDataTest04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -2923,10 +2923,10 @@ static int DetectHttpServerBodyFileDataTest04(void) if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3030,15 +3030,15 @@ static int DetectHttpServerBodyFileDataTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3047,15 +3047,15 @@ static int DetectHttpServerBodyFileDataTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -3065,12 +3065,12 @@ static int DetectHttpServerBodyFileDataTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -3078,10 +3078,10 @@ static int DetectHttpServerBodyFileDataTest05(void) if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3181,15 +3181,15 @@ static int DetectHttpServerBodyFileDataTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3198,15 +3198,15 @@ static int DetectHttpServerBodyFileDataTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -3216,15 +3216,15 @@ static int DetectHttpServerBodyFileDataTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3324,15 +3324,15 @@ static int DetectHttpServerBodyFileDataTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3341,15 +3341,15 @@ static int DetectHttpServerBodyFileDataTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -3359,15 +3359,15 @@ static int DetectHttpServerBodyFileDataTest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3455,22 +3455,22 @@ static int DetectHttpServerBodyFileDataTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3580,21 +3580,21 @@ static int DetectHttpServerBodyFileDataTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3604,21 +3604,21 @@ static int DetectHttpServerBodyFileDataTest09(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3736,21 +3736,21 @@ static int DetectHttpServerBodyFileDataTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3760,21 +3760,21 @@ static int DetectHttpServerBodyFileDataTest10(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index e0f1cb0efe0c..f2878743d860 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -268,21 +268,21 @@ static int DetectHttpStatCodeSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -376,12 +376,12 @@ static int DetectHttpStatCodeSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -389,10 +389,10 @@ static int DetectHttpStatCodeSigTest02(void) if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -492,12 +492,12 @@ static int DetectHttpStatCodeSigTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -505,10 +505,10 @@ static int DetectHttpStatCodeSigTest03(void) if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -608,12 +608,12 @@ static int DetectHttpStatCodeSigTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -621,10 +621,10 @@ static int DetectHttpStatCodeSigTest04(void) if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index 5e6e8f002ca5..4472f6144bed 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -266,12 +266,12 @@ static int DetectHttpStatMsgSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -279,10 +279,10 @@ static int DetectHttpStatMsgSigTest01(void) if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -374,12 +374,12 @@ static int DetectHttpStatMsgSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -387,10 +387,10 @@ static int DetectHttpStatMsgSigTest02(void) if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -486,12 +486,12 @@ static int DetectHttpStatMsgSigTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } @@ -499,10 +499,10 @@ static int DetectHttpStatMsgSigTest03(void) if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index 2a1ac7b906f9..5e9d69d13c0b 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -330,15 +330,15 @@ static int DetectHttpUATest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -437,15 +437,15 @@ static int DetectHttpUATest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -461,14 +461,14 @@ static int DetectHttpUATest07(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -560,15 +560,15 @@ static int DetectHttpUATest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -585,15 +585,15 @@ static int DetectHttpUATest08(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -690,15 +690,15 @@ static int DetectHttpUATest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -715,15 +715,15 @@ static int DetectHttpUATest09(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -820,15 +820,15 @@ static int DetectHttpUATest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -845,15 +845,15 @@ static int DetectHttpUATest10(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -939,15 +939,15 @@ static int DetectHttpUATest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1038,15 +1038,15 @@ static int DetectHttpUATest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1138,15 +1138,15 @@ static int DetectHttpUATest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1246,14 +1246,14 @@ static int DetectHttpUATest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1263,14 +1263,14 @@ static int DetectHttpUATest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1280,14 +1280,14 @@ static int DetectHttpUATest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1297,14 +1297,14 @@ static int DetectHttpUATest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1314,14 +1314,14 @@ static int DetectHttpUATest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1333,14 +1333,14 @@ static int DetectHttpUATest14(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); diff --git a/src/detect-lua.c b/src/detect-lua.c index 3343a6be762b..02450e61cd80 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1274,14 +1274,14 @@ static int LuaMatchTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); @@ -1297,14 +1297,14 @@ static int LuaMatchTest01(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SCLogDebug("inspecting p2"); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1708,14 +1708,14 @@ static int LuaMatchTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); @@ -1731,14 +1731,14 @@ static int LuaMatchTest04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SCLogInfo("p2"); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1856,14 +1856,14 @@ static int LuaMatchTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); @@ -1879,14 +1879,14 @@ static int LuaMatchTest05(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SCLogInfo("p2"); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2009,14 +2009,14 @@ static int LuaMatchTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); @@ -2032,14 +2032,14 @@ static int LuaMatchTest06(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SCLogInfo("p2"); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); diff --git a/src/detect-pcre.c b/src/detect-pcre.c index e1b0f09428e3..58b83e769ff2 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -1495,10 +1495,10 @@ static int DetectPcreTestSig01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, buf, buflen); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF_NOT(PacketAlertCheck(p, 1) == 1); @@ -1690,10 +1690,10 @@ static int DetectPcreModifPTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -1801,10 +1801,10 @@ static int DetectPcreModifPTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -1816,10 +1816,10 @@ static int DetectPcreModifPTest05(void) FAIL_IF(PacketAlertCheck(p1, 2)); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1944,10 +1944,10 @@ static int DetectPcreTestSig09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -2022,10 +2022,10 @@ static int DetectPcreTestSig10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -2100,10 +2100,10 @@ static int DetectPcreTestSig11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -2178,10 +2178,10 @@ static int DetectPcreTestSig12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -2256,10 +2256,10 @@ static int DetectPcreTestSig13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -2334,10 +2334,10 @@ static int DetectPcreTestSig14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -2413,10 +2413,10 @@ static int DetectPcreTestSig15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -2492,10 +2492,10 @@ static int DetectPcreTestSig16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -2563,7 +2563,7 @@ static int DetectPcreTxBodyChunksTest01(void) AppLayerHtpEnableRequestBodyCallback(); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); FAIL_IF(r != 0); @@ -2614,7 +2614,7 @@ static int DetectPcreTxBodyChunksTest01(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); @@ -2678,60 +2678,60 @@ static int DetectPcreTxBodyChunksTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!(PacketAlertCheck(p, 1))); p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -2740,10 +2740,10 @@ static int DetectPcreTxBodyChunksTest02(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -2846,60 +2846,60 @@ static int DetectPcreTxBodyChunksTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!(PacketAlertCheck(p, 1))); p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -2908,10 +2908,10 @@ static int DetectPcreTxBodyChunksTest03(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3002,10 +3002,10 @@ static int DetectPcreFlowvarCapture01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -3115,10 +3115,10 @@ static int DetectPcreFlowvarCapture02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; FAIL_IF(http_state == NULL); @@ -3227,10 +3227,10 @@ static int DetectPcreFlowvarCapture03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; FAIL_IF(http_state == NULL); diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index dca2e3588d28..39b4a891b1ee 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -374,35 +374,35 @@ static int DetectSshVersionTestDetect01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -487,7 +487,7 @@ static int DetectSshVersionTestDetect02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); @@ -497,24 +497,24 @@ static int DetectSshVersionTestDetect02(void) r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -598,35 +598,35 @@ static int DetectSshVersionTestDetect03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index 8ab0dbed5671..bc1967f77101 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -346,35 +346,35 @@ static int DetectSshSoftwareVersionTestDetect01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -459,35 +459,35 @@ static int DetectSshSoftwareVersionTestDetect02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -571,35 +571,35 @@ static int DetectSshSoftwareVersionTestDetect03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 674dcdcc67dd..742c925142ea 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -709,11 +709,11 @@ static int DetectSslStateTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_START, chello_buf, chello_buf_len); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ssl_state = f.alstate; FAIL_IF(ssl_state == NULL); @@ -728,11 +728,11 @@ static int DetectSslStateTest07(void) FAIL_IF(PacketAlertCheck(p, 4)); FAIL_IF(PacketAlertCheck(p, 5)); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, shello_buf_len); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ p->alerts.cnt = 0; @@ -748,11 +748,11 @@ static int DetectSslStateTest07(void) PASS; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, client_change_cipher_spec_buf_len); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ p->alerts.cnt = 0; @@ -763,11 +763,11 @@ static int DetectSslStateTest07(void) FAIL_IF(!PacketAlertCheck(p, 3)); FAIL_IF(PacketAlertCheck(p, 4)); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_change_cipher_spec_buf, server_change_cipher_spec_buf_len); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ p->alerts.cnt = 0; @@ -778,11 +778,11 @@ static int DetectSslStateTest07(void) FAIL_IF(PacketAlertCheck(p, 3)); FAIL_IF(PacketAlertCheck(p, 4)); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, toserver_app_data_buf, toserver_app_data_buf_len); FAIL_IF(r != 0); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ p->alerts.cnt = 0; diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index 0c377ac86f52..e56df42e7789 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -431,35 +431,35 @@ static int DetectSslVersionTestDetect01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; if (app_state == NULL) { @@ -556,35 +556,35 @@ static int DetectSslVersionTestDetect02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; if (app_state == NULL) { @@ -690,35 +690,35 @@ static int DetectSslVersionTestDetect03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; if (app_state == NULL) { diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index ffc89cf07884..574743c8625d 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -126,10 +126,10 @@ static int DetectTemplateBufferTest(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); AppLayerParserParse(alp_tctx, &f, ALPROTO_TEMPLATE, STREAM_TOSERVER, request, sizeof(request)); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* Check that we have app-layer state. */ FAIL_IF_NULL(f.alstate); diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index 154185c0782e..f6dc4ad128bc 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -390,10 +390,10 @@ static int DetectTlsIssuerTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -404,10 +404,10 @@ static int DetectTlsIssuerTest02(void) FAIL_IF(PacketAlertCheck(p1, 1)); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -415,10 +415,10 @@ static int DetectTlsIssuerTest02(void) FAIL_IF(PacketAlertCheck(p2, 1)); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index 90e5caeea95a..f3bea21e0c4f 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -389,10 +389,10 @@ static int DetectTlsSubjectTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -403,10 +403,10 @@ static int DetectTlsSubjectTest02(void) FAIL_IF(PacketAlertCheck(p1, 1)); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -414,10 +414,10 @@ static int DetectTlsSubjectTest02(void) FAIL_IF(PacketAlertCheck(p2, 1)); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index 46c43e53e6bf..141d9127c401 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -162,14 +162,14 @@ static int DetectTlsSniTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ssl_state = f.alstate; if (ssl_state == NULL) { @@ -283,14 +283,14 @@ static int DetectTlsSniTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); ssl_state = f.alstate; if (ssl_state == NULL) { diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index 6e185ef40e38..dd1f40c0583a 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -344,35 +344,35 @@ static int DetectTlsVersionTestDetect01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -472,35 +472,35 @@ static int DetectTlsVersionTestDetect02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { @@ -610,35 +610,35 @@ static int DetectTlsVersionTestDetect03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index 1ee13c6c03fc..42e83f19bd32 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -218,7 +218,7 @@ static int HTTPUriTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { @@ -257,7 +257,7 @@ static int HTTPUriTest01(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); return result; } @@ -286,7 +286,7 @@ static int HTTPUriTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { @@ -327,7 +327,7 @@ static int HTTPUriTest02(void) StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); return result; } @@ -356,7 +356,7 @@ static int HTTPUriTest03(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { @@ -397,7 +397,7 @@ static int HTTPUriTest03(void) StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); return result; } @@ -427,7 +427,7 @@ static int HTTPUriTest04(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { @@ -468,7 +468,7 @@ static int HTTPUriTest04(void) StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); return result; } @@ -585,14 +585,14 @@ static int DetectUriSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -700,14 +700,14 @@ static int DetectUriSigTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -724,14 +724,14 @@ static int DetectUriSigTest03(void) } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1052,14 +1052,14 @@ static int DetectUriSigTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1192,14 +1192,14 @@ static int DetectUriSigTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1314,14 +1314,14 @@ static int DetectUriSigTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); diff --git a/src/detect-urilen.c b/src/detect-urilen.c index fbb454b136f7..2dbf56a12638 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -610,14 +610,14 @@ static int DetectUrilenSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *htp_state = f.alstate; if (htp_state == NULL) { diff --git a/src/detect.c b/src/detect.c index aeb8123064b0..f527d051f907 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4820,15 +4820,15 @@ static int SigTest06 (void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) @@ -4909,15 +4909,15 @@ static int SigTest07 (void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) @@ -4998,15 +4998,15 @@ static int SigTest08 (void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) @@ -5089,15 +5089,15 @@ static int SigTest09 (void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) @@ -5172,15 +5172,15 @@ static int SigTest10 (void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) @@ -9341,14 +9341,14 @@ static int SigTestDropFlow01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -9443,14 +9443,14 @@ static int SigTestDropFlow02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -9573,14 +9573,14 @@ static int SigTestDropFlow03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -9618,14 +9618,14 @@ static int SigTestDropFlow03(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -9744,14 +9744,14 @@ static int SigTestDropFlow04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -9799,14 +9799,14 @@ static int SigTestDropFlow04(void) goto end; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 6fc622fb07ef..30b725a18df4 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -5086,14 +5086,14 @@ static int StreamTcpTestMissedPacket (TcpReassemblyThreadCtx *ra_ctx, s = &ssn->client; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, ssn, s, p, &pq) == -1) { - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); return -1; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); return 0; } @@ -6169,7 +6169,7 @@ static int StreamTcpReassembleTest38 (void) TcpStream *s = NULL; s = &ssn.server; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; @@ -6203,7 +6203,7 @@ static int StreamTcpReassembleTest38 (void) end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); return ret; } @@ -6238,7 +6238,7 @@ static int StreamTcpReassembleTest39 (void) p->flow = &f; p->tcph = &tcph; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int ret = 0; StreamTcpInitConfig(TRUE); @@ -6808,7 +6808,7 @@ static int StreamTcpReassembleTest39 (void) StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); return ret; } @@ -6880,7 +6880,7 @@ static int StreamTcpReassembleTest40 (void) TcpStream *s = NULL; s = &ssn.client; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; @@ -7010,7 +7010,7 @@ static int StreamTcpReassembleTest40 (void) StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -7085,7 +7085,7 @@ static int StreamTcpReassembleTest43 (void) TcpStream *s = NULL; s = &ssn.server; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; @@ -7181,7 +7181,7 @@ static int StreamTcpReassembleTest43 (void) StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -7289,7 +7289,7 @@ static int StreamTcpReassembleTest45 (void) TcpStream *s = NULL; s = &ssn.server; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toclient packet: "); goto end; @@ -7341,7 +7341,7 @@ static int StreamTcpReassembleTest45 (void) StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -7408,7 +7408,7 @@ static int StreamTcpReassembleTest46 (void) TcpStream *s = NULL; s = &ssn.server; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toclient packet\n"); goto end; @@ -7465,7 +7465,7 @@ static int StreamTcpReassembleTest46 (void) StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -7522,7 +7522,7 @@ static int StreamTcpReassembleTest47 (void) TcpStream *s = NULL; uint8_t cnt = 0; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); for (cnt=0; cnt < httplen1; cnt++) { tcph.th_seq = htonl(ssn.client.isn + 1 + cnt); tcph.th_ack = htonl(572799782UL); @@ -7565,7 +7565,7 @@ static int StreamTcpReassembleTest47 (void) StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -7597,7 +7597,7 @@ static int StreamTcpReassembleInlineTest01(void) p->tcph->th_seq = htonl(12); p->flow = &f; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -7629,7 +7629,7 @@ static int StreamTcpReassembleInlineTest01(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -7667,7 +7667,7 @@ static int StreamTcpReassembleInlineTest02(void) p->tcph->th_seq = htonl(12); p->flow = &f; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -7720,7 +7720,7 @@ static int StreamTcpReassembleInlineTest02(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -7762,7 +7762,7 @@ static int StreamTcpReassembleInlineTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -7817,7 +7817,7 @@ static int StreamTcpReassembleInlineTest03(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -7859,7 +7859,7 @@ static int StreamTcpReassembleInlineTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -7914,7 +7914,7 @@ static int StreamTcpReassembleInlineTest04(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -7950,7 +7950,7 @@ static int StreamTcpReassembleInlineTest05(void) p->tcph->th_seq = htonl(12); p->flow = &f; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -7989,7 +7989,7 @@ static int StreamTcpReassembleInlineTest05(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8026,7 +8026,7 @@ static int StreamTcpReassembleInlineTest06(void) p->tcph->th_seq = htonl(12); p->flow = &f; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8088,7 +8088,7 @@ static int StreamTcpReassembleInlineTest06(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8129,7 +8129,7 @@ static int StreamTcpReassembleInlineTest07(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8191,7 +8191,7 @@ static int StreamTcpReassembleInlineTest07(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8235,7 +8235,7 @@ static int StreamTcpReassembleInlineTest08(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8305,7 +8305,7 @@ static int StreamTcpReassembleInlineTest08(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8350,7 +8350,7 @@ static int StreamTcpReassembleInlineTest09(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8425,7 +8425,7 @@ static int StreamTcpReassembleInlineTest09(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8473,7 +8473,7 @@ static int StreamTcpReassembleInlineTest10(void) p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 2, stream_payload1, 2) == -1) { printf("failed to add segment 1: "); goto end; @@ -8518,7 +8518,7 @@ static int StreamTcpReassembleInlineTest10(void) UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -8550,7 +8550,7 @@ static int StreamTcpReassembleInsertTest01(void) p->tcph->th_seq = htonl(12); p->flow = &f; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8594,7 +8594,7 @@ static int StreamTcpReassembleInsertTest01(void) } ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 470d4208f112..d56bd5048c34 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5853,7 +5853,7 @@ static int StreamTcpTest02 (void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { goto end; } @@ -5910,7 +5910,7 @@ static int StreamTcpTest02 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -5952,7 +5952,7 @@ static int StreamTcpTest03 (void) p->tcph = &tcph; int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -5988,7 +5988,7 @@ static int StreamTcpTest03 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -6031,7 +6031,7 @@ static int StreamTcpTest04 (void) int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6059,7 +6059,7 @@ static int StreamTcpTest04 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -6110,7 +6110,7 @@ static int StreamTcpTest05 (void) p->payload = payload; p->payload_len = 3; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6166,7 +6166,7 @@ static int StreamTcpTest05 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -6207,7 +6207,7 @@ static int StreamTcpTest06 (void) tcph.th_flags = TH_FIN; p->tcph = &tcph; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* StreamTcpPacket returns -1 on unsolicited FIN */ if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) { printf("StreamTcpPacket failed: "); @@ -6234,7 +6234,7 @@ static int StreamTcpTest06 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -6288,7 +6288,7 @@ static int StreamTcpTest07 (void) p->payload = payload; p->payload_len = 1; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1); p->tcph->th_seq = htonl(11); @@ -6304,7 +6304,7 @@ static int StreamTcpTest07 (void) StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); PASS; @@ -6358,7 +6358,7 @@ static int StreamTcpTest08 (void) p->payload = payload; p->payload_len = 1; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1); p->tcph->th_seq = htonl(11); @@ -6375,7 +6375,7 @@ static int StreamTcpTest08 (void) StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); PASS; @@ -6428,7 +6428,7 @@ static int StreamTcpTest09 (void) p->payload = payload; p->payload_len = 1; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6456,7 +6456,7 @@ static int StreamTcpTest09 (void) StreamTcpSessionClear(p->flow->protoctx); end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -6498,7 +6498,7 @@ static int StreamTcpTest10 (void) p->tcph = &tcph; int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6560,7 +6560,7 @@ static int StreamTcpTest10 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -6602,7 +6602,7 @@ static int StreamTcpTest11 (void) p->tcph = &tcph; int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6665,7 +6665,7 @@ static int StreamTcpTest11 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -6707,7 +6707,7 @@ static int StreamTcpTest12 (void) p->tcph = &tcph; int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6762,7 +6762,7 @@ static int StreamTcpTest12 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -6805,7 +6805,7 @@ static int StreamTcpTest13 (void) p->tcph = &tcph; int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6872,7 +6872,7 @@ static int StreamTcpTest13 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -7038,7 +7038,7 @@ static int StreamTcpTest14 (void) p->payload = payload; p->payload_len = 3; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7139,7 +7139,7 @@ static int StreamTcpTest14 (void) StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -7180,7 +7180,7 @@ static int StreamTcp4WHSTest01 (void) tcph.th_flags = TH_SYN; p->tcph = &tcph; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7222,7 +7222,7 @@ static int StreamTcp4WHSTest01 (void) end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -7264,7 +7264,7 @@ static int StreamTcp4WHSTest02 (void) tcph.th_flags = TH_SYN; p->tcph = &tcph; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7295,7 +7295,7 @@ static int StreamTcp4WHSTest02 (void) end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -7337,7 +7337,7 @@ static int StreamTcp4WHSTest03 (void) tcph.th_flags = TH_SYN; p->tcph = &tcph; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7379,7 +7379,7 @@ static int StreamTcp4WHSTest03 (void) end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -7452,7 +7452,7 @@ static int StreamTcpTest15 (void) p->payload = payload; p->payload_len = 3; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7553,7 +7553,7 @@ static int StreamTcpTest15 (void) StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -7626,7 +7626,7 @@ static int StreamTcpTest16 (void) p->payload = payload; p->payload_len = 3; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7727,7 +7727,7 @@ static int StreamTcpTest16 (void) StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -7801,7 +7801,7 @@ static int StreamTcpTest17 (void) p->payload = payload; p->payload_len = 3; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7902,7 +7902,7 @@ static int StreamTcpTest17 (void) StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -8386,7 +8386,7 @@ static int StreamTcpTest25(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -8442,7 +8442,7 @@ static int StreamTcpTest25(void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -8484,7 +8484,7 @@ static int StreamTcpTest26(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -8540,7 +8540,7 @@ static int StreamTcpTest26(void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -8582,7 +8582,7 @@ static int StreamTcpTest27(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -8638,7 +8638,7 @@ static int StreamTcpTest27(void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -9588,7 +9588,7 @@ static int StreamTcpTest37(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet\n"); goto end; @@ -9669,7 +9669,7 @@ static int StreamTcpTest37(void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -9713,7 +9713,7 @@ static int StreamTcpTest38 (void) stt.ra_ctx = ra_ctx; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; @@ -9829,7 +9829,7 @@ static int StreamTcpTest38 (void) end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); if (stt.ra_ctx != NULL) @@ -9876,7 +9876,7 @@ static int StreamTcpTest39 (void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; @@ -9970,7 +9970,7 @@ static int StreamTcpTest39 (void) end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); if (stt.ra_ctx != NULL) @@ -10136,7 +10136,7 @@ static int StreamTcpTest42 (void) tcph.th_seq = htonl(100); p->flowflags = FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -10190,7 +10190,7 @@ static int StreamTcpTest42 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -10230,7 +10230,7 @@ static int StreamTcpTest43 (void) tcph.th_seq = htonl(100); p->flowflags = FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -10284,7 +10284,7 @@ static int StreamTcpTest43 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -10324,7 +10324,7 @@ static int StreamTcpTest44 (void) tcph.th_seq = htonl(100); p->flowflags = FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -10373,7 +10373,7 @@ static int StreamTcpTest44 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); FLOW_DESTROY(&f); return ret; @@ -10414,7 +10414,7 @@ static int StreamTcpTest45 (void) tcph.th_seq = htonl(100); p->flowflags = FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -10486,7 +10486,7 @@ static int StreamTcpTest45 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); return ret; } From 48b3cb04924f7d5e9d456c4e6a8151f3267e4577 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Sep 2016 09:22:39 +0200 Subject: [PATCH 1727/2553] unittests: fix tests --- src/app-layer-ftp.c | 2 ++ src/app-layer-modbus.c | 7 ++++++ src/app-layer-smb.c | 19 ++++++++++++++++ src/app-layer-ssh.c | 49 ++++++++++++++++++++++++++++++++++++++++++ src/app-layer-ssl.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+) diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index 6e90a4a00ea3..ea323b853f51 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -439,6 +439,8 @@ int FTPParserTest03(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 14dff540ccbf..cd44fb2c3a18 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1718,6 +1718,7 @@ static int ModbusParserTest01(void) { memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -1783,6 +1784,7 @@ static int ModbusParserTest02(void) { memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -1970,6 +1972,7 @@ static int ModbusParserTest04(void) { memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2391,6 +2394,7 @@ static int ModbusParserTest09(void) { memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2486,6 +2490,7 @@ static int ModbusParserTest10(void) { memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2741,6 +2746,7 @@ static int ModbusParserTest13(void) { memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2806,6 +2812,7 @@ static int ModbusParserTest14(void) { memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 2e007a095960..9ebc4a669a47 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -1558,6 +1558,7 @@ void RegisterSMBParsers(void) /* UNITTESTS */ #ifdef UNITTESTS +#include "flow-util.h" /** * \test SMBParserTest01 tests the NBSS and SMB header decoding @@ -1585,6 +1586,7 @@ int SMBParserTest01(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -1625,6 +1627,7 @@ int SMBParserTest01(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1662,6 +1665,7 @@ int SMBParserTest02(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -1703,6 +1707,7 @@ int SMBParserTest02(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1958,6 +1963,7 @@ int SMBParserTest03(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2005,6 +2011,7 @@ int SMBParserTest03(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2075,6 +2082,7 @@ int SMBParserTest04(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2130,6 +2138,7 @@ int SMBParserTest04(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2230,6 +2239,7 @@ int SMBParserTest05(void) AppLayerProtoDetectUnittestCtxRestore(); if (alpd_tctx != NULL) AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + FLOW_DESTROY(&f); return result; } @@ -2313,6 +2323,7 @@ int SMBParserTest06(void) AppLayerProtoDetectUnittestCtxRestore(); if (alpd_tctx != NULL) AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + FLOW_DESTROY(&f); return result; } @@ -2330,6 +2341,7 @@ int SMBParserTest07(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2371,6 +2383,7 @@ int SMBParserTest07(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2404,6 +2417,7 @@ int SMBParserTest08(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2471,6 +2485,7 @@ int SMBParserTest08(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2518,6 +2533,7 @@ int SMBParserTest09(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2585,6 +2601,7 @@ int SMBParserTest09(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2640,6 +2657,7 @@ int SMBParserTest10(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2679,6 +2697,7 @@ int SMBParserTest10(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index 823c3080a23a..9d8dff1b7592 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -544,6 +544,7 @@ void RegisterSSHParsers(void) /* UNITTESTS */ #ifdef UNITTESTS +#include "flow-util.h" /** \test Send a version string in one chunk (client version str). */ static int SSHParserTest01(void) @@ -557,6 +558,7 @@ static int SSHParserTest01(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -606,6 +608,7 @@ static int SSHParserTest01(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -623,6 +626,7 @@ static int SSHParserTest02(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -672,6 +676,7 @@ static int SSHParserTest02(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -689,6 +694,7 @@ static int SSHParserTest03(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -726,6 +732,7 @@ static int SSHParserTest03(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -741,6 +748,7 @@ static int SSHParserTest04(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -791,6 +799,7 @@ static int SSHParserTest04(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -807,6 +816,7 @@ static int SSHParserTest05(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -856,6 +866,7 @@ static int SSHParserTest05(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -872,6 +883,7 @@ static int SSHParserTest06(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -910,6 +922,7 @@ static int SSHParserTest06(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -926,6 +939,7 @@ static int SSHParserTest07(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -985,6 +999,7 @@ static int SSHParserTest07(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1004,6 +1019,7 @@ static int SSHParserTest08(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -1071,6 +1087,7 @@ static int SSHParserTest08(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1087,6 +1104,7 @@ static int SSHParserTest09(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -1146,6 +1164,7 @@ static int SSHParserTest09(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1165,6 +1184,7 @@ static int SSHParserTest10(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -1232,6 +1252,7 @@ static int SSHParserTest10(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1249,6 +1270,7 @@ static int SSHParserTest11(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -1312,6 +1334,7 @@ static int SSHParserTest11(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1331,6 +1354,7 @@ static int SSHParserTest12(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -1403,6 +1427,7 @@ static int SSHParserTest12(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1423,6 +1448,7 @@ static int SSHParserTest13(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -1496,6 +1522,7 @@ static int SSHParserTest13(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1522,6 +1549,7 @@ static int SSHParserTest14(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -1608,6 +1636,7 @@ static int SSHParserTest14(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1634,6 +1663,7 @@ static int SSHParserTest15(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -1720,6 +1750,7 @@ static int SSHParserTest15(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1739,6 +1770,7 @@ static int SSHParserTest16(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -1811,6 +1843,7 @@ static int SSHParserTest16(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1832,6 +1865,7 @@ static int SSHParserTest17(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -1913,6 +1947,7 @@ static int SSHParserTest17(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1942,6 +1977,7 @@ static int SSHParserTest18(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -2017,6 +2053,7 @@ static int SSHParserTest18(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2048,6 +2085,7 @@ static int SSHParserTest19(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -2135,6 +2173,7 @@ static int SSHParserTest19(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2168,6 +2207,7 @@ static int SSHParserTest20(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -2244,6 +2284,7 @@ static int SSHParserTest20(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2275,6 +2316,7 @@ static int SSHParserTest21(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -2352,6 +2394,7 @@ static int SSHParserTest21(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2410,6 +2453,7 @@ static int SSHParserTest22(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -2487,6 +2531,7 @@ static int SSHParserTest22(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2502,6 +2547,7 @@ static int SSHParserTest23(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -2520,6 +2566,7 @@ static int SSHParserTest23(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2535,6 +2582,7 @@ static int SSHParserTest24(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); @@ -2569,6 +2617,7 @@ static int SSHParserTest24(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 347097773778..4342ecb0ebcd 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -1811,6 +1811,8 @@ static int SSLParserTest01(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -1850,6 +1852,7 @@ static int SSLParserTest01(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1867,6 +1870,7 @@ static int SSLParserTest02(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -1916,6 +1920,7 @@ static int SSLParserTest02(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1935,6 +1940,7 @@ static int SSLParserTest03(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -1994,6 +2000,7 @@ static int SSLParserTest03(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2015,6 +2022,7 @@ static int SSLParserTest04(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2084,6 +2092,7 @@ static int SSLParserTest04(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2101,6 +2110,7 @@ static int SSLParserTest05(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2191,6 +2201,7 @@ static int SSLParserTest05(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } #endif @@ -2210,6 +2221,7 @@ static int SSLParserTest06(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2316,6 +2328,7 @@ static int SSLParserTest06(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } #endif @@ -2359,6 +2372,7 @@ static int SSLParserMultimsgTest01(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2398,6 +2412,7 @@ static int SSLParserMultimsgTest01(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2440,6 +2455,7 @@ static int SSLParserMultimsgTest02(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2479,6 +2495,7 @@ static int SSLParserMultimsgTest02(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2510,6 +2527,7 @@ static int SSLParserTest07(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2550,6 +2568,7 @@ static int SSLParserTest07(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2567,6 +2586,7 @@ static int SSLParserTest08(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2656,6 +2676,7 @@ static int SSLParserTest08(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2696,6 +2717,7 @@ static int SSLParserTest09(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2746,6 +2768,7 @@ static int SSLParserTest09(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2784,6 +2807,7 @@ static int SSLParserTest10(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2834,6 +2858,7 @@ static int SSLParserTest10(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2871,6 +2896,7 @@ static int SSLParserTest11(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2921,6 +2947,7 @@ static int SSLParserTest11(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2963,6 +2990,7 @@ static int SSLParserTest12(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -3023,6 +3051,7 @@ static int SSLParserTest12(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -3070,6 +3099,7 @@ static int SSLParserTest13(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -3140,6 +3170,7 @@ static int SSLParserTest13(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -3166,6 +3197,7 @@ static int SSLParserTest14(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -3202,6 +3234,7 @@ static int SSLParserTest14(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -3223,6 +3256,7 @@ static int SSLParserTest15(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -3242,6 +3276,7 @@ static int SSLParserTest15(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -3263,6 +3298,7 @@ static int SSLParserTest16(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -3282,6 +3318,7 @@ static int SSLParserTest16(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -3303,6 +3340,7 @@ static int SSLParserTest17(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -3322,6 +3360,7 @@ static int SSLParserTest17(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -3349,6 +3388,7 @@ static int SSLParserTest18(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -3385,6 +3425,7 @@ static int SSLParserTest18(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -3407,6 +3448,7 @@ static int SSLParserTest19(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -3433,6 +3475,7 @@ static int SSLParserTest19(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -3455,6 +3498,7 @@ static int SSLParserTest20(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -3474,6 +3518,7 @@ static int SSLParserTest20(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -4117,6 +4162,7 @@ static int SSLParserTest24(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -4167,6 +4213,7 @@ static int SSLParserTest24(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -4496,6 +4543,7 @@ static int SSLParserTest25(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -4571,6 +4619,7 @@ static int SSLParserTest25(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } From 04da43d65d4ba812a0595f6018d48344d1f155ef Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 19 Sep 2016 10:43:00 -0600 Subject: [PATCH 1728/2553] rule parsing: check for balanced double quotes If a rule option value starts with a double quote, ensure it ends with a double quote, exclusive of white space which gets trimmed anyways. Catches errors like 'filemagic:"picture" sid:5555555;' reporting that a missing semicolon may be the error. --- src/detect-parse.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/detect-parse.c b/src/detect-parse.c index 1427565ecf80..c9373c21d60e 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -608,6 +608,26 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, } } + /* Validate double quoting, trimming trailing white space along the way. */ + if (strlen(optvalue) > 0) { + size_t ovlen = strlen(optvalue); + if (ovlen && optvalue[0] == '"') { + for (; ovlen > 0; ovlen--) { + if (isblank(optvalue[ovlen - 1])) { + optvalue[ovlen - 1] = '\0'; + } else { + break; + } + } + if (ovlen && optvalue[ovlen - 1] != '"') { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "bad option value formatting (possible missing semicolon) " + "for keyword %s: \'%s\'", optname, optvalue); + goto error; + } + } + } + /* setup may or may not add a new SigMatch to the list */ if (st->Setup(de_ctx, s, strlen(optvalue) ? optvalue : NULL) < 0) { SCLogDebug("\"%s\" failed to setup", st->name); @@ -3585,6 +3605,21 @@ static int SigParseTestAppLayerTLS03(void) return result; } +static int SigParseTestUnblanacedQuotes01(void) +{ + DetectEngineCtx *de_ctx; + Signature *s; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + s = SigInit(de_ctx, "alert http any any -> any any (msg:\"SigParseTestUnblanacedQuotes01\"; pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)"); + FAIL_IF_NOT_NULL(s); + + PASS; +} + #endif /* UNITTESTS */ void SigParseRegisterTests(void) @@ -3639,5 +3674,7 @@ void SigParseRegisterTests(void) UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01); UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02); UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03); + UtRegisterTest("SigParseTestUnblanacedQuotes01", + SigParseTestUnblanacedQuotes01); #endif /* UNITTESTS */ } From 12da0e8681fea7b3ac781c9cfff403d9373a1461 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 18 May 2016 15:12:48 +0200 Subject: [PATCH 1729/2553] tls: add function for decoding client_hello Add function TLSDecodeHandshakeHello() to enable using the same code for decoding both client_hello and server_hello. --- src/app-layer-ssl.c | 211 ++++++++++++++++++++++++-------------------- 1 file changed, 114 insertions(+), 97 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 4342ecb0ebcd..cce52bc733f8 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -230,144 +230,161 @@ int SSLGetAlstateProgress(void *tx, uint8_t direction) return TLS_STATE_IN_PROGRESS; } -static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, +static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, uint32_t input_len) { - void *ptmp; uint8_t *initial_input = input; - uint32_t parsed = 0; - int rc; - if (input_len == 0) { + /* only parse the message if it is complete */ + if (input_len < ssl_state->curr_connp->message_length || input_len < 40) return 0; - } - switch (ssl_state->curr_connp->handshake_type) { - case SSLV3_HS_CLIENT_HELLO: - ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO; + /* skip version */ + input += SSLV3_CLIENT_HELLO_VERSION_LEN; - /* skip version */ - input += SSLV3_CLIENT_HELLO_VERSION_LEN; + /* skip random */ + input += SSLV3_CLIENT_HELLO_RANDOM_LEN; - /* skip random */ - input += SSLV3_CLIENT_HELLO_RANDOM_LEN; + if (!(HAS_SPACE(1))) + goto end; + + /* skip session id */ + uint8_t session_id_length = *(input++); + + input += session_id_length; + + if (!(HAS_SPACE(2))) + goto end; - if (!(HAS_SPACE(1))) - goto end; + /* skip cipher suites */ + uint16_t cipher_suites_length = input[0] << 8 | input[1]; + input += 2; - /* skip session id */ - uint8_t session_id_length = *(input++); + input += cipher_suites_length; - input += session_id_length; + if (!(HAS_SPACE(1))) + goto end; - if (!(HAS_SPACE(2))) - goto end; + /* skip compression methods */ + uint8_t compression_methods_length = *(input++); - /* skip cipher suites */ - uint16_t cipher_suites_length = input[0] << 8 | input[1]; - input += 2; + input += compression_methods_length; - input += cipher_suites_length; + if (!(HAS_SPACE(2))) + goto end; - if (!(HAS_SPACE(1))) - goto end; + uint16_t extensions_len = input[0] << 8 | input[1]; + input += 2; - /* skip compression methods */ - uint8_t compression_methods_length = *(input++); + uint16_t processed_len = 0; + while (processed_len < extensions_len) + { + if (!(HAS_SPACE(2))) + goto end; - input += compression_methods_length; + uint16_t ext_type = input[0] << 8 | input[1]; + input += 2; - if (!(HAS_SPACE(2))) - goto end; + if (!(HAS_SPACE(2))) + goto end; - uint16_t extensions_len = input[0] << 8 | input[1]; - input += 2; + uint16_t ext_len = input[0] << 8 | input[1]; + input += 2; - uint16_t processed_len = 0; - while (processed_len < extensions_len) + switch (ext_type) { + case SSL_EXTENSION_SNI: { - if (!(HAS_SPACE(2))) - goto end; + /* there must not be more than one extension of the same + type (RFC5246 section 7.4.1.4) */ + if (ssl_state->curr_connp->sni) { + SCLogDebug("Multiple SNI extensions"); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS); + return -1; + } - uint16_t ext_type = input[0] << 8 | input[1]; + /* skip sni_list_length */ input += 2; + if (!(HAS_SPACE(1))) + goto end; + + uint8_t sni_type = *(input++); + + /* currently the only type allowed is host_name + (RFC6066 section 3) */ + if (sni_type != SSL_SNI_TYPE_HOST_NAME) { + SCLogDebug("Unknown SNI type"); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_SNI_TYPE); + return -1; + } + if (!(HAS_SPACE(2))) goto end; - uint16_t ext_len = input[0] << 8 | input[1]; + uint16_t sni_len = input[0] << 8 | input[1]; input += 2; - switch (ext_type) { - case SSL_EXTENSION_SNI: - { - /* there must not be more than one extension of the same - type (RFC5246 section 7.4.1.4) */ - if (ssl_state->curr_connp->sni) { - SCLogDebug("Multiple SNI extensions"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS); - return -1; - } + if (!(HAS_SPACE(sni_len))) + goto end; - /* skip sni_list_length */ - input += 2; + /* host_name contains the fully qualified domain name, + and should therefore be limited by the maximum domain + name length */ + if (sni_len > 255) { + SCLogDebug("SNI length >255"); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_SNI_LENGTH); + return -1; + } - if (!(HAS_SPACE(1))) - goto end; + size_t sni_strlen = sni_len + 1; + ssl_state->curr_connp->sni = SCMalloc(sni_strlen); - uint8_t sni_type = *(input++); + if (unlikely(ssl_state->curr_connp->sni == NULL)) + goto end; - /* currently the only type allowed is host_name - (RFC6066 section 3) */ - if (sni_type != SSL_SNI_TYPE_HOST_NAME) { - SCLogDebug("Unknown SNI type"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_INVALID_SNI_TYPE); - return -1; - } + memcpy(ssl_state->curr_connp->sni, input, sni_strlen - 1); + ssl_state->curr_connp->sni[sni_strlen-1] = 0; - if (!(HAS_SPACE(2))) - goto end; + input += sni_len; + break; + } + default: + { + input += ext_len; + break; + } + } + processed_len += ext_len + 4; + } - uint16_t sni_len = input[0] << 8 | input[1]; - input += 2; +end: + return 0; +} - if (!(HAS_SPACE(sni_len))) - goto end; +static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, + uint32_t input_len) +{ + void *ptmp; + uint8_t *initial_input = input; + uint32_t parsed = 0; + int rc; - /* host_name contains the fully qualified domain name, - and should therefore be limited by the maximum domain - name length */ - if (sni_len > 255) { - SCLogDebug("SNI length >255"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_INVALID_SNI_LENGTH); - return -1; - } + if (input_len == 0) { + return 0; + } - size_t sni_strlen = sni_len + 1; - ssl_state->curr_connp->sni = SCMalloc(sni_strlen); + switch (ssl_state->curr_connp->handshake_type) { + case SSLV3_HS_CLIENT_HELLO: + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO; - if (unlikely(ssl_state->curr_connp->sni == NULL)) - goto end; + rc = TLSDecodeHandshakeHello(ssl_state, input, input_len); - memcpy(ssl_state->curr_connp->sni, input, - sni_strlen - 1); - ssl_state->curr_connp->sni[sni_strlen-1] = 0; + if (rc < 0) + return rc; - input += sni_len; - break; - } - default: - { - input += ext_len; - break; - } - } - processed_len += ext_len + 4; - } -end: break; case SSLV3_HS_SERVER_HELLO: From 1f7b813080b8595435bf4b8b97a9c0df49a67f05 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 23 May 2016 13:38:01 +0200 Subject: [PATCH 1730/2553] app-layer-tls: add name to authors --- src/app-layer-ssl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index cce52bc733f8..bdf0fbe2a386 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -20,6 +20,7 @@ * * \author Anoop Saldanha * \author Pierre Chifflier + * \author Mats Klepsland * */ From c36595eb35a8fddfde037c42df638fdf09777d07 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 18 May 2016 15:30:49 +0200 Subject: [PATCH 1731/2553] tls: set event if input buffer overflows Set HANDSHAKE_INVALID_LENGTH event if input buffer overflows while decoding client_hello/server_hello. --- src/app-layer-ssl.c | 25 ++++++++++++++++--------- src/app-layer-ssl.h | 1 + 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index bdf0fbe2a386..f9e1a1770baa 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -63,6 +63,7 @@ SCEnumCharMap tls_decoder_event_table[ ] = { { "INVALID_HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_INVALID_HEARTBEAT }, { "OVERFLOW_HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT }, { "DATALEAK_HEARTBEAT_MISMATCH", TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH }, + { "HANDSHAKE_INVALID_LENGTH", TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH }, { "MULTIPLE_SNI_EXTENSIONS", TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS }, { "INVALID_SNI_TYPE", TLS_DECODER_EVENT_INVALID_SNI_TYPE }, { "INVALID_SNI_LENGTH", TLS_DECODER_EVENT_INVALID_SNI_LENGTH }, @@ -247,7 +248,7 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, input += SSLV3_CLIENT_HELLO_RANDOM_LEN; if (!(HAS_SPACE(1))) - goto end; + goto invalid_length; /* skip session id */ uint8_t session_id_length = *(input++); @@ -255,7 +256,7 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, input += session_id_length; if (!(HAS_SPACE(2))) - goto end; + goto invalid_length; /* skip cipher suites */ uint16_t cipher_suites_length = input[0] << 8 | input[1]; @@ -264,7 +265,7 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, input += cipher_suites_length; if (!(HAS_SPACE(1))) - goto end; + goto invalid_length; /* skip compression methods */ uint8_t compression_methods_length = *(input++); @@ -272,7 +273,7 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, input += compression_methods_length; if (!(HAS_SPACE(2))) - goto end; + goto invalid_length; uint16_t extensions_len = input[0] << 8 | input[1]; input += 2; @@ -281,13 +282,13 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, while (processed_len < extensions_len) { if (!(HAS_SPACE(2))) - goto end; + goto invalid_length; uint16_t ext_type = input[0] << 8 | input[1]; input += 2; if (!(HAS_SPACE(2))) - goto end; + goto invalid_length; uint16_t ext_len = input[0] << 8 | input[1]; input += 2; @@ -308,7 +309,7 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, input += 2; if (!(HAS_SPACE(1))) - goto end; + goto invalid_length; uint8_t sni_type = *(input++); @@ -322,13 +323,13 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, } if (!(HAS_SPACE(2))) - goto end; + goto invalid_length; uint16_t sni_len = input[0] << 8 | input[1]; input += 2; if (!(HAS_SPACE(sni_len))) - goto end; + goto invalid_length; /* host_name contains the fully qualified domain name, and should therefore be limited by the maximum domain @@ -363,6 +364,12 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, end: return 0; + +invalid_length: + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + return 0; } static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 30fa476c4aba..3253ce46d56e 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -42,6 +42,7 @@ enum { TLS_DECODER_EVENT_INVALID_HEARTBEAT, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT, TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH, + TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH, TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS, TLS_DECODER_EVENT_INVALID_SNI_TYPE, TLS_DECODER_EVENT_INVALID_SNI_LENGTH, From 7c36b11a8405f912456bcbef84d93cdc4e3cbf76 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 18 May 2016 15:34:32 +0200 Subject: [PATCH 1732/2553] rules: add rule for HANDSHAKE_INVALID_LENGTH event --- rules/tls-events.rules | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rules/tls-events.rules b/rules/tls-events.rules index eccaaf568277..f22b1fed93a4 100644 --- a/rules/tls-events.rules +++ b/rules/tls-events.rules @@ -25,5 +25,6 @@ alert tls any any -> any any (msg:"SURICATA TLS invalid encrypted heartbeat enco alert tls any any -> any any (msg:"SURICATA TLS multiple SNI extensions"; flow:established,to_server; app-layer-event:tls.multiple_sni_extensions; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230016; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS invalid SNI type"; flow:established,to_server; app-layer-event:tls.invalid_sni_type; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230017; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS invalid SNI length"; flow:established,to_server; app-layer-event:tls.invalid_sni_length; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230018; rev:1;) +alert tls any any -> any any (msg:"SURICATA TLS handshake invalid length"; flow:established; app-layer-event:tls.handshake_invalid_length; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230019; rev:1;) -#next sid is 2230019 +#next sid is 2230020 From b74f3fd9786cbaf9287c50f46a50583c2af64924 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 18 May 2016 15:36:25 +0200 Subject: [PATCH 1733/2553] coverty: fix CID 1361873 --- src/app-layer-ssl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index f9e1a1770baa..d1801be6697b 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -278,6 +278,9 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, uint16_t extensions_len = input[0] << 8 | input[1]; input += 2; + if (!(HAS_SPACE(extensions_len))) + goto invalid_length; + uint16_t processed_len = 0; while (processed_len < extensions_len) { From 9d23ad9d2512ffd9b6c59dea93a1102c57782591 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 23 May 2016 13:34:43 +0200 Subject: [PATCH 1734/2553] tls: fix faulty unittests --- src/app-layer-ssl.c | 164 +++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 94 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index d1801be6697b..40954dfdfdb5 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -2534,21 +2534,17 @@ static int SSLParserTest07(void) { int result = 1; Flow f; - uint8_t tlsbuf[] = { 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, - 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 }; + uint8_t tlsbuf[] = { 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, + 0x00, 0x00, 0x48, 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t tlslen = sizeof(tlsbuf); TcpSession ssn; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2718,26 +2714,22 @@ static int SSLParserTest09(void) int result = 1; Flow f; uint8_t buf1[] = { - 0x16, + 0x16, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { - 0x03, 0x00, 0x00, 0x6f, 0x01, - 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 + 0x03, 0x00, 0x00, 0x4c, 0x01, + 0x00, 0x00, 0x48, 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; @@ -2813,21 +2805,17 @@ static int SSLParserTest10(void) uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { - 0x00, 0x00, 0x6f, 0x01, - 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 + 0x00, 0x00, 0x4c, 0x01, + 0x00, 0x00, 0x48, 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; @@ -2898,25 +2886,21 @@ static int SSLParserTest11(void) int result = 1; Flow f; uint8_t buf1[] = { - 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, + 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { - 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 + 0x00, 0x00, 0x48, 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; @@ -2987,30 +2971,26 @@ static int SSLParserTest12(void) int result = 1; Flow f; uint8_t buf1[] = { - 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, + 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { - 0x00, 0x00, 0x6b, + 0x00, 0x00, 0x48, }; uint32_t buf2_len = sizeof(buf2); uint8_t buf3[] = { - 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 + 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t buf3_len = sizeof(buf2); TcpSession ssn; @@ -3091,35 +3071,31 @@ static int SSLParserTest13(void) int result = 1; Flow f; uint8_t buf1[] = { - 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, + 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { - 0x00, 0x00, 0x6b, + 0x00, 0x00, 0x48, }; uint32_t buf2_len = sizeof(buf2); uint8_t buf3[] = { - 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, + 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, }; uint32_t buf3_len = sizeof(buf3); uint8_t buf4[] = { - 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 + 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t buf4_len = sizeof(buf4); TcpSession ssn; From 8e77d0c312bc66d8125aa8476dc88836bf15736d Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 23 May 2016 14:32:41 +0200 Subject: [PATCH 1735/2553] detect: fix faulty tls_sni unittests --- src/detect-tls-sni.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index 141d9127c401..5bf72bf0dcf3 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -97,7 +97,7 @@ static int DetectTlsSniSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) static int DetectTlsSniTest01(void) { /* client hello */ - uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0xAE, 0x01, 0x00, 0x00, 0xAA, + uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0x82, 0x01, 0x00, 0x00, 0x7E, 0x03, 0x03, 0x57, 0x04, 0x9F, 0x5D, 0xC9, 0x5C, 0x87, 0xAE, 0xF2, 0xA7, 0x4A, 0xFC, 0x59, 0x78, 0x23, 0x31, 0x61, 0x2D, 0x29, 0x92, 0xB6, 0x70, 0xA5, 0xA1, 0xFC, @@ -209,7 +209,7 @@ static int DetectTlsSniTest01(void) static int DetectTlsSniTest02(void) { /* client hello */ - uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0xAE, 0x01, 0x00, 0x00, 0xAA, + uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0x82, 0x01, 0x00, 0x00, 0x7E, 0x03, 0x03, 0x57, 0x04, 0x9F, 0x5D, 0xC9, 0x5C, 0x87, 0xAE, 0xF2, 0xA7, 0x4A, 0xFC, 0x59, 0x78, 0x23, 0x31, 0x61, 0x2D, 0x29, 0x92, 0xB6, 0x70, 0xA5, 0xA1, 0xFC, From d9e2cde585d623cc47dc7fa98c1ccc3280a98282 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 23 Sep 2016 12:13:29 +0200 Subject: [PATCH 1736/2553] detect-tls-sni: use new unit test macros --- src/detect-tls-sni.c | 96 +++++++++++--------------------------------- 1 file changed, 24 insertions(+), 72 deletions(-) diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index 5bf72bf0dcf3..42fe329c9c35 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -114,7 +114,6 @@ static int DetectTlsSniTest01(void) 0x0A, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x63, 0x6F, 0x6D, }; - int result = 0; Flow f; SSLState *ssl_state = NULL; Packet *p = NULL; @@ -146,61 +145,41 @@ static int DetectTlsSniTest01(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); + de_ctx->mpm_matcher = DEFAULT_MPM; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " "(msg:\"Test tls_sni option\"; " "tls_sni; content:\"google.com\"; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf, sizeof(buf)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF_NULL(ssl_state); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert, but it should have: "); - goto end; - } - - result = 1; + FAIL_IF_NOT(PacketAlertCheck(p, 1)); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + + PASS; } /** @@ -226,7 +205,6 @@ static int DetectTlsSniTest02(void) 0x0A, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x63, 0x6F, 0x6D, }; - int result = 0; Flow f; SSLState *ssl_state = NULL; Packet *p = NULL; @@ -258,9 +236,8 @@ static int DetectTlsSniTest02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); + de_ctx->mpm_matcher = DEFAULT_MPM; de_ctx->flags |= DE_QUIET; @@ -268,65 +245,40 @@ static int DetectTlsSniTest02(void) "(msg:\"Test tls_sni option\"; " "tls_sni; content:\"google\"; nocase; " "pcre:\"/google\\.com$/i\"; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " "(msg:\"Test tls_sni option\"; " "tls_sni; content:\"google\"; nocase; " "pcre:\"/^\\.[a-z]{2,3}$/iR\"; sid:2;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf, sizeof(buf)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF_NULL(ssl_state); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert, but it should have: "); - goto end; - } + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + FAIL_IF_NOT(PacketAlertCheck(p, 2)); - if (!(PacketAlertCheck(p, 2))) { - printf("sig 2 didn't alert, but it should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + + PASS; } #endif From 1503ac97a6234aa455a935039fa8c214f42ac8d6 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 23 Sep 2016 12:33:59 +0200 Subject: [PATCH 1737/2553] detect-tls-version: use new unit test macros --- src/detect-tls-version.c | 220 +++++++++------------------------------ 1 file changed, 49 insertions(+), 171 deletions(-) diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index dd1f40c0583a..bff7ba95cc8f 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -265,12 +265,10 @@ int DetectTlsVersionTestParse01 (void) { DetectTlsVersionData *tls = NULL; tls = DetectTlsVersionParse("1.0"); - if (tls != NULL && tls->ver == TLS_VERSION_10) { - DetectTlsVersionFree(tls); - return 1; - } - - return 0; + FAIL_IF_NULL(tls); + FAIL_IF_NOT(tls->ver == TLS_VERSION_10); + DetectTlsVersionFree(tls); + PASS; } /** @@ -282,12 +280,9 @@ int DetectTlsVersionTestParse02 (void) { DetectTlsVersionData *tls = NULL; tls = DetectTlsVersionParse("2.5"); - if (tls == NULL) { - DetectTlsVersionFree(tls); - return 1; - } - - return 0; + FAIL_IF_NOT_NULL(tls); + DetectTlsVersionFree(tls); + PASS; } #include "stream-tcp-reassemble.h" @@ -295,7 +290,6 @@ int DetectTlsVersionTestParse02 (void) /** \test Send a get request in three chunks + more data. */ static int DetectTlsVersionTestDetect01(void) { - int result = 0; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -330,67 +324,36 @@ static int DetectTlsVersionTestDetect01(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; tls.version:1.0; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - 0x16, ssl_state->client_connp.content_type); - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - goto end; - } + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); SCLogDebug("ssl_state is at %p, ssl_state->server_version 0x%02X " "ssl_state->client_version 0x%02X", @@ -400,14 +363,9 @@ static int DetectTlsVersionTestDetect01(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - goto end; - } + FAIL_IF_NOT(PacketAlertCheck(p, 1)); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -418,12 +376,12 @@ static int DetectTlsVersionTestDetect01(void) FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } static int DetectTlsVersionTestDetect02(void) { - int result = 0; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -458,80 +416,43 @@ static int DetectTlsVersionTestDetect02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; tls.version:1.0; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - 0x16, ssl_state->client_connp.content_type); - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - goto end; - } + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("signature 1 didn't match while it should have: "); - goto end; - } + FAIL_IF_NOT(PacketAlertCheck(p, 1)); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -542,13 +463,13 @@ static int DetectTlsVersionTestDetect02(void) FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } static int DetectTlsVersionTestDetect03(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -584,10 +505,7 @@ static int DetectTlsVersionTestDetect03(void) StreamTcpInitConfig(TRUE); StreamMsg *stream_msg = StreamMsgGetFromPool(); - if (stream_msg == NULL) { - printf("no stream_msg: "); - goto end; - } + FAIL_IF_NULL(stream_msg); memcpy(stream_msg->data, tlsbuf4, tlslen4); stream_msg->data_len = tlslen4; @@ -596,91 +514,51 @@ static int DetectTlsVersionTestDetect03(void) ssn.toserver_smsg_tail = stream_msg; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"TLS\"; tls.version:1.0; content:\"|01 00 00 AD|\"; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - 0x16, ssl_state->client_connp.content_type); - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - goto end; - } + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("signature 1 didn't match while it should have: "); - goto end; - } + FAIL_IF_NOT(PacketAlertCheck(p, 1)); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } #endif /* UNITTESTS */ From 12356d1fca6d0cea345c614b5f918c840292e0a3 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 23 Sep 2016 12:55:26 +0200 Subject: [PATCH 1738/2553] detect-ssl-version: use new unit test macros --- src/detect-ssl-version.c | 239 +++++++++------------------------------ 1 file changed, 56 insertions(+), 183 deletions(-) diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index e56df42e7789..7e133630e382 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -332,12 +332,10 @@ int DetectSslVersionTestParse01(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("SSlv3"); - if (ssl != NULL && ssl->data[SSLv3].ver == SSL_VERSION_3) { - DetectSslVersionFree(ssl); - return 1; - } - - return 0; + FAIL_IF_NULL(ssl); + FAIL_IF_NOT(ssl->data[SSLv3].ver == SSL_VERSION_3); + DetectSslVersionFree(ssl); + PASS; } /** @@ -349,12 +347,9 @@ int DetectSslVersionTestParse02(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("2.5"); - if (ssl == NULL) { - DetectSslVersionFree(ssl); - return 1; - } - - return 0; + FAIL_IF_NOT_NULL(ssl); + DetectSslVersionFree(ssl); + PASS; } /** @@ -365,16 +360,13 @@ int DetectSslVersionTestParse03(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("SSlv3,tls1.0, !tls1.2"); - if (ssl != NULL && ssl->data[SSLv3].ver == SSL_VERSION_3 && - ssl->data[TLS10].ver == TLS_VERSION_10 && - ssl->data[TLS12].ver == TLS_VERSION_12 && - ssl->data[TLS12].flags & DETECT_SSL_VERSION_NEGATED) - { - DetectSslVersionFree(ssl); - return 1; - } - - return 0; + FAIL_IF_NULL(ssl); + FAIL_IF_NOT(ssl->data[SSLv3].ver == SSL_VERSION_3); + FAIL_IF_NOT(ssl->data[TLS10].ver == TLS_VERSION_10); + FAIL_IF_NOT(ssl->data[TLS12].ver == TLS_VERSION_12); + FAIL_IF_NOT(ssl->data[TLS12].flags & DETECT_SSL_VERSION_NEGATED); + DetectSslVersionFree(ssl); + PASS; } #include "stream-tcp-reassemble.h" @@ -382,7 +374,6 @@ int DetectSslVersionTestParse03(void) /** \test Send a get request in three chunks + more data. */ static int DetectSslVersionTestDetect01(void) { - int result = 0; Flow f; uint8_t sslbuf1[] = { 0x16 }; uint32_t ssllen1 = sizeof(sslbuf1); @@ -417,65 +408,36 @@ static int DetectSslVersionTestDetect01(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_connp.content_type); - goto end; - } + FAIL_IF(app_state->client_connp.content_type != 0x16); - if (app_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_connp.version); - goto end; - } + FAIL_IF(app_state->client_connp.version != TLS_VERSION_10); SCLogDebug("app_state is at %p, app_state->server_connp.version 0x%02X app_state->client_connp.version 0x%02X", app_state, app_state->server_connp.version, app_state->client_connp.version); @@ -483,18 +445,9 @@ static int DetectSslVersionTestDetect01(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + AppLayerParserThreadCtxFree(alp_tctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); @@ -502,12 +455,12 @@ static int DetectSslVersionTestDetect01(void) FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } static int DetectSslVersionTestDetect02(void) { - int result = 0; Flow f; uint8_t sslbuf1[] = { 0x16 }; uint32_t ssllen1 = sizeof(sslbuf1); @@ -542,93 +495,55 @@ static int DetectSslVersionTestDetect02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_connp.content_type); - goto end; - } + FAIL_IF(app_state->client_connp.content_type != 0x16); - if (app_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_connp.version); - goto end; - } + FAIL_IF(app_state->client_connp.version != TLS_VERSION_10); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("signature 1 didn't match while it should have: "); - goto end; - } - - result = 1; + FAIL_IF_NOT(PacketAlertCheck(p, 1)); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + AppLayerParserThreadCtxFree(alp_tctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } static int DetectSslVersionTestDetect03(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; Flow f; uint8_t sslbuf1[] = { 0x16 }; uint32_t ssllen1 = sizeof(sslbuf1); @@ -664,10 +579,7 @@ static int DetectSslVersionTestDetect03(void) StreamTcpInitConfig(TRUE); StreamMsg *stream_msg = StreamMsgGetFromPool(); - if (stream_msg == NULL) { - printf("no stream_msg: "); - goto end; - } + FAIL_IF_NULL(stream_msg); memcpy(stream_msg->data, sslbuf4, ssllen4); stream_msg->data_len = ssllen4; @@ -676,90 +588,51 @@ static int DetectSslVersionTestDetect03(void) ssn.toserver_smsg_tail = stream_msg; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; content:\"|01 00 00 AD|\"; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_connp.content_type); - goto end; - } + FAIL_IF(app_state->client_connp.content_type != 0x16); - if (app_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_connp.version); - goto end; - } + FAIL_IF(app_state->client_connp.version != TLS_VERSION_10); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("signature 1 didn't match while it should have: "); - goto end; - } - - result = 1; + FAIL_IF_NOT(PacketAlertCheck(p, 1)); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } #endif /* UNITTESTS */ From b91486169221fdc2dfdeb3933bcd57de4b9a023f Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 23 Sep 2016 13:52:28 +0200 Subject: [PATCH 1739/2553] app-layer-ssl: use new unit test macros --- src/app-layer-ssl.c | 1036 ++++++++++--------------------------------- 1 file changed, 224 insertions(+), 812 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 40954dfdfdb5..3b75427c9086 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -1830,7 +1830,6 @@ void RegisterSSLParsers(void) */ static int SSLParserTest01(void) { - int result = 1; Flow f; uint8_t tlsbuf[] = { 0x16, 0x03, 0x01 }; uint32_t tlslen = sizeof(tlsbuf); @@ -1848,46 +1847,26 @@ static int SSLParserTest01(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_EOF, tlsbuf, tlslen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** \test Send a get request in two chunks. */ static int SSLParserTest02(void) { - int result = 1; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -1906,56 +1885,31 @@ static int SSLParserTest02(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** \test Send a get request in three chunks. */ static int SSLParserTest03(void) { - int result = 1; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -1976,66 +1930,36 @@ static int SSLParserTest03(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** \test Send a get request in three chunks + more data. */ static int SSLParserTest04(void) { - int result = 1; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -2058,70 +1982,36 @@ static int SSLParserTest04(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } #if 0 @@ -2364,7 +2254,6 @@ static int SSLParserTest06(void) /** \test multimsg test */ static int SSLParserMultimsgTest01(void) { - int result = 1; Flow f; /* 3 msgs */ uint8_t tlsbuf1[] = { @@ -2408,46 +2297,26 @@ static int SSLParserMultimsgTest01(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** \test multimsg test server */ static int SSLParserMultimsgTest02(void) { - int result = 1; Flow f; /* 3 msgs */ uint8_t tlsbuf1[] = { @@ -2491,40 +2360,21 @@ static int SSLParserMultimsgTest02(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->server_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->server_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->server_connp.content_type != 0x16); - if (ssl_state->server_connp.version != 0x0301) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", 0x0301, - ssl_state->server_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->server_connp.version != 0x0301); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -2532,7 +2382,6 @@ static int SSLParserMultimsgTest02(void) */ static int SSLParserTest07(void) { - int result = 1; Flow f; uint8_t tlsbuf[] = { 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x48, 0x03, 0x00, 0x57, 0x04, 0x9f, @@ -2559,41 +2408,21 @@ static int SSLParserTest07(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } #if 0 @@ -2711,7 +2540,6 @@ static int SSLParserTest08(void) */ static int SSLParserTest09(void) { - int result = 1; Flow f; uint8_t buf1[] = { 0x16, @@ -2745,51 +2573,26 @@ static int SSLParserTest09(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -2797,7 +2600,6 @@ static int SSLParserTest09(void) */ static int SSLParserTest10(void) { - int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, @@ -2831,51 +2633,26 @@ static int SSLParserTest10(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -2883,7 +2660,6 @@ static int SSLParserTest10(void) */ static int SSLParserTest11(void) { - int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, @@ -2916,51 +2692,26 @@ static int SSLParserTest11(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -2968,7 +2719,6 @@ static int SSLParserTest11(void) */ static int SSLParserTest12(void) { - int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, @@ -3006,61 +2756,31 @@ static int SSLParserTest12(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf3, buf3_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3068,7 +2788,6 @@ static int SSLParserTest12(void) */ static int SSLParserTest13(void) { - int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, @@ -3111,71 +2830,36 @@ static int SSLParserTest13(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf3, buf3_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf4, buf4_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3183,7 +2867,6 @@ static int SSLParserTest13(void) */ static int SSLParserTest14(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -3209,37 +2892,22 @@ static int SSLParserTest14(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3247,7 +2915,6 @@ static int SSLParserTest14(void) */ static int SSLParserTest15(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -3268,20 +2935,14 @@ static int SSLParserTest15(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r == 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r == 0); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3289,7 +2950,6 @@ static int SSLParserTest15(void) */ static int SSLParserTest16(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -3310,20 +2970,14 @@ static int SSLParserTest16(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r == 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r == 0); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3331,7 +2985,6 @@ static int SSLParserTest16(void) */ static int SSLParserTest17(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -3352,20 +3005,14 @@ static int SSLParserTest17(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r == 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r == 0); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3373,7 +3020,6 @@ static int SSLParserTest17(void) */ static int SSLParserTest18(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -3400,37 +3046,22 @@ static int SSLParserTest18(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3438,7 +3069,6 @@ static int SSLParserTest18(void) */ static int SSLParserTest19(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -3460,27 +3090,17 @@ static int SSLParserTest19(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3488,7 +3108,6 @@ static int SSLParserTest19(void) */ static int SSLParserTest20(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -3510,20 +3129,14 @@ static int SSLParserTest20(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r == 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r == 0); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3531,7 +3144,6 @@ static int SSLParserTest20(void) */ static int SSLParserTest21(void) { - int result = 0; Flow f; uint8_t buf[] = { 0x80, 0x31, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -3554,38 +3166,21 @@ static int SSLParserTest21(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_EOF, buf, buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->client_connp.content_type != SSLV2_MT_CLIENT_HELLO) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV2_MT_SERVER_HELLO, app_state->client_connp.content_type); - goto end; - } + FAIL_IF(app_state->client_connp.content_type != SSLV2_MT_CLIENT_HELLO); - if (app_state->client_connp.version != SSL_VERSION_2) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_2, app_state->client_connp.version); - goto end; - } + FAIL_IF(app_state->client_connp.version != SSL_VERSION_2); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3593,7 +3188,6 @@ static int SSLParserTest21(void) */ static int SSLParserTest22(void) { - int result = 1; Flow f; uint8_t buf[] = { 0x80, 0x31, 0x04, 0x00, 0x01, 0x00, @@ -3621,40 +3215,21 @@ static int SSLParserTest22(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT | STREAM_EOF, buf, buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->server_connp.content_type != SSLV2_MT_SERVER_HELLO) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV2_MT_SERVER_HELLO, app_state->server_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(app_state->server_connp.content_type != SSLV2_MT_SERVER_HELLO); - if (app_state->server_connp.version != SSL_VERSION_2) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_2, app_state->server_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(app_state->server_connp.version != SSL_VERSION_2); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3662,7 +3237,6 @@ static int SSLParserTest22(void) */ static int SSLParserTest23(void) { - int result = 1; Flow f; uint8_t chello_buf[] = { 0x80, 0x67, 0x01, 0x03, 0x00, 0x00, 0x4e, 0x00, @@ -3926,209 +3500,103 @@ static int SSLParserTest23(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_START, chello_buf, chello_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - result = 0; - goto end; - } - - if (app_state->client_connp.content_type != SSLV2_MT_CLIENT_HELLO) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV2_MT_CLIENT_HELLO, app_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->client_connp.version != SSL_VERSION_2) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_2, app_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.content_type != SSLV2_MT_CLIENT_HELLO); - if ((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0 || - (app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0 || - (app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0) { - printf("flags not set\n"); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.version != SSL_VERSION_2); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, shello_buf_len); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - if (app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV3_HANDSHAKE_PROTOCOL, app_state->server_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL); - if (app_state->server_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, app_state->server_connp.version); - result = 0; - goto end; - } + FAIL_IF(app_state->server_connp.version != SSL_VERSION_3); - if ((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0 || - (app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0 || - (app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0 || - (app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0) { - printf("flags not set\n"); - result = 0; - goto end; - } + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, client_change_cipher_spec_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); /* with multiple records the client content type hold the type from the last * record */ - if (app_state->client_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV3_HANDSHAKE_PROTOCOL, app_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL); - if (app_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, app_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.version != SSL_VERSION_3); - if ((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0 || - (app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0 || - (app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0 || - (app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0 || - (app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0 || - (app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0 || - (app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0) { - printf("flags not set\n"); - result = 0; - goto end; - } + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_change_cipher_spec_buf, server_change_cipher_spec_buf_len); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); /* with multiple records the serve content type hold the type from the last * record */ - if (app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV3_HANDSHAKE_PROTOCOL, app_state->server_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL); - if (app_state->server_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, app_state->server_connp.version); - result = 0; - goto end; - } + FAIL_IF(app_state->server_connp.version != SSL_VERSION_3); - if ((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0 || - (app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0 || - (app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0 || - (app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0 || - (app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0 || - (app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0 || - (app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0 || - (app_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC) == 0 || - (app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0) { - printf("flags not set\n"); - result = 0; - goto end; - } + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, toserver_app_data_buf, toserver_app_data_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - if (app_state->client_connp.content_type != SSLV3_APPLICATION_PROTOCOL) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV3_APPLICATION_PROTOCOL, app_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.content_type != SSLV3_APPLICATION_PROTOCOL); - if (app_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, app_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.version != SSL_VERSION_3); - if ((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0 || - (app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0 || - (app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0 || - (app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0 || - (app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0 || - (app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0 || - (app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0 || - (app_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC) == 0 || - (app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0) { - printf("flags not set\n"); - result = 0; - goto end; - } + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0); - if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION)) { - printf("The flags should be set\n"); - result = 0; - goto end; - } + FAIL_IF_NOT(f.flags & FLOW_NOPAYLOAD_INSPECTION); -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -4136,7 +3604,6 @@ static int SSLParserTest23(void) */ static int SSLParserTest24(void) { - int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, @@ -4174,51 +3641,26 @@ static int SSLParserTest24(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -4227,7 +3669,6 @@ static int SSLParserTest24(void) */ static int SSLParserTest25(void) { - int result = 0; Flow f; uint8_t client_hello[] = { 0x16, 0x03, 0x01, 0x00, 0xd3, 0x01, 0x00, 0x00, @@ -4555,54 +3996,31 @@ static int SSLParserTest25(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, client_hello_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.bytes_processed != 0 || - ssl_state->client_connp.hs_bytes_processed != 0) - { - printf("client_hello error\n"); - goto end; - } + FAIL_IF(ssl_state->client_connp.bytes_processed != 0); + FAIL_IF(ssl_state->client_connp.hs_bytes_processed != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello_certificate_done, server_hello_certificate_done_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - if (ssl_state->client_connp.bytes_processed != 0 || - ssl_state->client_connp.hs_bytes_processed != 0) - { - printf("server_hello_certificate_done error\n"); - goto end; - } + FAIL_IF(ssl_state->client_connp.bytes_processed != 0); + FAIL_IF(ssl_state->client_connp.hs_bytes_processed != 0); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_key_exchange_cipher_enc_hs, client_key_exchange_cipher_enc_hs_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); /* The reason hs_bytes_processed is 2 is because, the record * immediately after the client key exchange is 2 bytes long, @@ -4611,20 +4029,14 @@ static int SSLParserTest25(void) * handshake, we immediately break and don't parse the pdu from * where we left off, and leave the hs_bytes_processed var * isn't reset. */ - if (ssl_state->client_connp.bytes_processed != 0 || - ssl_state->client_connp.hs_bytes_processed != 2) - { - printf("client_key_exchange_cipher_enc_hs error\n"); - goto end; - } + FAIL_IF(ssl_state->client_connp.bytes_processed != 0); + FAIL_IF(ssl_state->client_connp.hs_bytes_processed != 2); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } #endif /* UNITTESTS */ From 03cda74b953258e10d0f2780e8f2d2d45d2f7f90 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 19 Oct 2015 10:19:20 +0200 Subject: [PATCH 1740/2553] util-decode-der: decode GeneralizedTime Decode ASN.1 element type GeneralizedTime in DER-encoded structures. --- src/util-decode-der.c | 20 ++++++++++++++++++++ src/util-decode-der.h | 29 +++++++++++++++-------------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/util-decode-der.c b/src/util-decode-der.c index 00c1bccaef07..d3fb3237f364 100644 --- a/src/util-decode-der.c +++ b/src/util-decode-der.c @@ -88,6 +88,9 @@ static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerGeneralizedTime(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); static Asn1Generic * Asn1GenericNew(void) { @@ -220,6 +223,9 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, case ASN1_UTCTIME: child = DecodeAsn1DerUTCTime(d_ptr, el_max_size, depth+1, errcode); break; + case ASN1_GENERALIZEDTIME: + child = DecodeAsn1DerGeneralizedTime(d_ptr, el_max_size, depth+1, errcode); + break; default: /* unknown ASN.1 type */ child = NULL; @@ -862,6 +868,20 @@ static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, return a; } +static Asn1Generic * DecodeAsn1DerGeneralizedTime(const unsigned char *buffer, + uint32_t max_size, + uint8_t depth, + uint32_t *errcode) +{ + Asn1Generic *a; + + a = DecodeAsn1DerIA5String(buffer, max_size, depth, errcode); + if (a != NULL) + a->type = ASN1_GENERALIZEDTIME; + + return a; +} + Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *errcode) { diff --git a/src/util-decode-der.h b/src/util-decode-der.h index b923c12d40cd..5383b4f1d1db 100644 --- a/src/util-decode-der.h +++ b/src/util-decode-der.h @@ -40,20 +40,21 @@ #define ASN1_CLASS_CONTEXTSPEC 2 #define ASN1_CLASS_PRIVATE 3 -#define ASN1_UNKNOWN 0 -#define ASN1_BOOLEAN 0x01 -#define ASN1_INTEGER 0x02 -#define ASN1_BITSTRING 0x03 -#define ASN1_OCTETSTRING 0x04 -#define ASN1_NULL 0x05 -#define ASN1_OID 0x06 -#define ASN1_UTF8STRING 0x0c -#define ASN1_SEQUENCE 0x10 -#define ASN1_SET 0x11 -#define ASN1_PRINTSTRING 0x13 -#define ASN1_T61STRING 0x14 -#define ASN1_IA5STRING 0x16 -#define ASN1_UTCTIME 0x17 +#define ASN1_UNKNOWN 0 +#define ASN1_BOOLEAN 0x01 +#define ASN1_INTEGER 0x02 +#define ASN1_BITSTRING 0x03 +#define ASN1_OCTETSTRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_OID 0x06 +#define ASN1_UTF8STRING 0x0c +#define ASN1_SEQUENCE 0x10 +#define ASN1_SET 0x11 +#define ASN1_PRINTSTRING 0x13 +#define ASN1_T61STRING 0x14 +#define ASN1_IA5STRING 0x16 +#define ASN1_UTCTIME 0x17 +#define ASN1_GENERALIZEDTIME 0x18 typedef struct Asn1ElementType_ { uint8_t cls:2; From 6c1c53b5a115ccd2859691a29dade9c6b8d981bc Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 30 Oct 2015 09:14:54 +0100 Subject: [PATCH 1741/2553] util-time: add function to convert tm to time_t Add function SCMkTimeUtc to convert broken-down time to Unix epoch in UTC. --- src/util-time.c | 38 ++++++++++++++++++++++++++++++++++++++ src/util-time.h | 1 + 2 files changed, 39 insertions(+) diff --git a/src/util-time.c b/src/util-time.c index 40de6b817359..352c041fad7a 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -354,3 +354,41 @@ void CreateTimeString (const struct timeval *ts, char *str, size_t size) } #endif /* defined(__OpenBSD__) */ + +/** + * \brief Convert broken-down time to seconds since Unix epoch. + * + * This function is based on: http://www.catb.org/esr/time-programming + * (released to the public domain). + * + * \param tp Pointer to broken-down time. + * + * \retval Seconds since Unix epoch. + */ +time_t SCMkTimeUtc (struct tm *tp) +{ + time_t result; + long year; +#define MONTHSPERYEAR 12 + static const int mdays[MONTHSPERYEAR] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + year = 1900 + tp->tm_year + tp->tm_mon / MONTHSPERYEAR; + result = (year - 1970) * 365 + mdays[tp->tm_mon % MONTHSPERYEAR]; + result += (year - 1968) / 4; + result -= (year - 1900) / 100; + result += (year - 1600) / 400; + if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) && + (tp->tm_mon % MONTHSPERYEAR) < 2) + result--; + result += tp->tm_mday - 1; + result *= 24; + result += tp->tm_hour; + result *= 60; + result += tp->tm_min; + result *= 60; + result += tp->tm_sec; + if (tp->tm_gmtoff) + result -= tp->tm_gmtoff; + return result; +} diff --git a/src/util-time.h b/src/util-time.h index 6efce2f7b2f4..2b4944528ab4 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -53,6 +53,7 @@ int TimeModeIsLive(void); struct tm *SCLocalTime(time_t timep, struct tm *result); void CreateTimeString (const struct timeval *ts, char *str, size_t size); void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size); +time_t SCMkTimeUtc (struct tm *tp); #endif /* __UTIL_TIME_H__ */ From bfd16dc74eecb52ce3eb2bb13348a2861e77c21d Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 19 Oct 2015 10:54:40 +0200 Subject: [PATCH 1742/2553] app-layer-ssl: add validity dates from certificate Parsing of certificate validity dates to get notBefore and notAfter fields. --- src/app-layer-ssl.h | 2 + src/app-layer-tls-handshake.c | 11 ++++ src/util-decode-der-get.c | 114 ++++++++++++++++++++++++++++++++++ src/util-decode-der-get.h | 1 + 4 files changed, 128 insertions(+) diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 3253ce46d56e..31ca913e7467 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -147,6 +147,8 @@ typedef struct SSLStateConnp_ { char *cert0_subject; char *cert0_issuerdn; + time_t cert0_not_before; + time_t cert0_not_after; char *cert0_fingerprint; /* ssl server name indication extension */ diff --git a/src/app-layer-tls-handshake.c b/src/app-layer-tls-handshake.c index 663471e83137..9ae3a1080164 100644 --- a/src/app-layer-tls-handshake.c +++ b/src/app-layer-tls-handshake.c @@ -87,6 +87,7 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, int i; Asn1Generic *cert; char buffer[256]; + time_t not_before, not_after; int rc; int parsed; uint8_t *start_data; @@ -176,6 +177,16 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, } } + rc = Asn1DerGetValidity(cert, ¬_before, ¬_after, &errcode); + if (rc != 0) { + TLSCertificateErrCodeToWarning(ssl_state, errcode); + } else { + if (i == 0) { + ssl_state->server_connp.cert0_not_before = not_before; + ssl_state->server_connp.cert0_not_after = not_after; + } + } + DerFree(cert); if (i == 0 && ssl_state->server_connp.cert0_fingerprint == NULL) { diff --git a/src/util-decode-der-get.c b/src/util-decode-der-get.c index 1c556c837d4f..413c43158140 100644 --- a/src/util-decode-der-get.c +++ b/src/util-decode-der-get.c @@ -38,6 +38,7 @@ #include "util-decode-der-get.h" static const uint8_t SEQ_IDX_ISSUER[] = { 0, 2 }; +static const uint8_t SEQ_IDX_VALIDITY[] = { 0, 3 }; static const uint8_t SEQ_IDX_SUBJECT[] = { 0, 4 }; static const char *Oid2ShortStr(const char *oid) @@ -72,6 +73,68 @@ static const char *Oid2ShortStr(const char *oid) return "unknown"; } +static time_t GentimeToTime(char *gentime) +{ + time_t time; + struct tm tm; + + /* GeneralizedTime values MUST be expressed in Greenwich Mean Time + * (Zulu) and MUST include seconds (rfc5280 4.1.2.5.2). It MUST NOT + * include fractional seconds. It should therefore be on the format + * YYYYmmddHHMMSSZ. */ + if (strlen(gentime) != 15) + goto error; + + tm.tm_gmtoff = 0; + strptime(gentime, "%Y%m%d%H%M%SZ", &tm); + time = SCMkTimeUtc(&tm); + + if (time < 0) + goto error; + + return time; + +error: + return -1; +} + +static time_t UtctimeToTime(char *utctime) +{ + time_t time; + unsigned int year; + char yy[2]; + char buf[20]; + + /* UTCTime values MUST be expressed in Greenwich Mean Time (Zulu) + * and MUST include seconds (rfc5280 4.1.2.5.1). It should + * therefore be on the format YYmmddHHMMSSZ. */ + if (strlen(utctime) != 13) + goto error; + + /* UTCTime use two digits to represent the year. The year field (YY) + * should be interpreted as 19YY when it is greater than or equal to + * 50. If it is less than 50 it should be interpreted as 20YY. + * Because of this, GeneralizedTime must be used for dates in the + * year 2050 or later. */ + strlcpy(yy, utctime, sizeof(yy)); + year = strtol(yy, NULL, 10); + if (year >= 50) + snprintf(buf, sizeof(buf), "%i%s", 19, utctime); + else if (year < 50) + snprintf(buf, sizeof(buf), "%i%s", 20, utctime); + else + goto error; + + time = GentimeToTime(buf); + if (time == -1) + goto error; + + return time; + +error: + return -1; +} + /** * \brief Iterate through an ASN.1 structure, following the index sequence. * Context specific elements are skipped. @@ -129,6 +192,57 @@ const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, return node; } +int Asn1DerGetValidity(const Asn1Generic *cert, time_t *not_before, + time_t *not_after, uint32_t *errcode) +{ + const Asn1Generic *node, *it; + int rc = -1; + + if (errcode) + *errcode = ERR_DER_MISSING_ELEMENT; + + node = Asn1DerGet(cert, SEQ_IDX_VALIDITY, sizeof(SEQ_IDX_VALIDITY), errcode); + if ((node == NULL) || node->type != ASN1_SEQUENCE) + goto validity_error; + + it = node->data; + if (it == NULL || it->str == NULL) + goto validity_error; + + if (it->type == ASN1_UTCTIME) + *not_before = UtctimeToTime(it->str); + else if (it->type == ASN1_GENERALIZEDTIME) + *not_before = GentimeToTime(it->str); + else + goto validity_error; + + if (*not_before == -1) + goto validity_error; + + if (node->next == NULL) + goto validity_error; + + it = node->next->data; + + if (it == NULL || it->str == NULL) + goto validity_error; + + if (it->type == ASN1_UTCTIME) + *not_after = UtctimeToTime(it->str); + else if (it->type == ASN1_GENERALIZEDTIME) + *not_after = GentimeToTime(it->str); + else + goto validity_error; + + if (*not_after == -1) + goto validity_error; + + rc = 0; + +validity_error: + return rc; +} + int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode) { diff --git a/src/util-decode-der-get.h b/src/util-decode-der-get.h index 79ecd7879c84..2d2168aeb3f3 100644 --- a/src/util-decode-der-get.h +++ b/src/util-decode-der-get.h @@ -38,6 +38,7 @@ const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, const uint32_t seqsz, uint32_t *errcode); int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode); +int Asn1DerGetValidity(const Asn1Generic *cert, time_t *not_before, time_t *not_after, uint32_t *errcode); int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode); #endif /* __UTIL_DECODE_DER_GET_H__ */ From c49cb053992f5a4675782c81e585bdcea773427e Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 23 Oct 2015 12:55:34 +0200 Subject: [PATCH 1743/2553] util-time: add function to parse a date string based on patterns Add function SCStringPatternToTime to parse a date string based on an array of pattern strings. --- src/util-time.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ src/util-time.h | 2 ++ 2 files changed, 56 insertions(+) diff --git a/src/util-time.c b/src/util-time.c index 352c041fad7a..992650e317d6 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -392,3 +392,57 @@ time_t SCMkTimeUtc (struct tm *tp) result -= tp->tm_gmtoff; return result; } + +/** + * \brief Parse a date string based on specified patterns. + * + * This function is based on GNU C library getdate. + * + * \param string Date string to parse. + * \param patterns String array containing patterns. + * \param num_patterns Number of patterns to check. + * \param tp Pointer to broken-down time. + * + * \retval 0 on success. + * \retval 1 on failure. + */ +int SCStringPatternToTime (char *string, char **patterns, int num_patterns, + struct tm *tp) +{ + char *result = NULL; + int i = 0; + + /* Do the pattern matching */ + for (i = 0; i < num_patterns; i++) + { + if (patterns[i] == NULL) + continue; + + tp->tm_hour = tp->tm_min = tp->tm_sec = 0; + tp->tm_year = tp->tm_mon = tp->tm_mday = tp->tm_wday = INT_MIN; + tp->tm_isdst = -1; + tp->tm_gmtoff = 0; + tp->tm_zone = NULL; + result = strptime(string, patterns[i], tp); + + if (result && *result == '\0') + break; + } + + /* Return if no patterns matched */ + if (result == NULL || *result != '\0') + return 1; + + /* Return if no date is given */ + if (tp->tm_year == INT_MIN && tp->tm_mon == INT_MIN && + tp->tm_mday == INT_MIN) + return 1; + + /* The first of the month is assumed, if only year and + month is given */ + if (tp->tm_year != INT_MIN && tp->tm_mon != INT_MIN && + tp->tm_mday <= 0) + tp->tm_mday = 1; + + return 0; +} diff --git a/src/util-time.h b/src/util-time.h index 2b4944528ab4..c2cbd5a22beb 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -54,6 +54,8 @@ struct tm *SCLocalTime(time_t timep, struct tm *result); void CreateTimeString (const struct timeval *ts, char *str, size_t size); void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size); time_t SCMkTimeUtc (struct tm *tp); +int SCStringPatternToTime (char *string, char **patterns, + int num_patterns, struct tm *time); #endif /* __UTIL_TIME_H__ */ From ea5696812fd392af1ed680b9c9f16c890491e877 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 20 Oct 2015 14:16:13 +0200 Subject: [PATCH 1744/2553] detect: add tls_cert_notbefore and tls_cert_notafter keywords Detection plugin for TLS certificate fields notBefore and notAfter. Supports equal to, less than, greater than, and range operations for both keywords. Dates can be represented as either ISO 8601 or epoch (Unix time). Examples: alert tls [...] tls_cert_notafter:1445852105; [...] alert tls [...] tls_cert_notbefore:<2015-10-22T23:59:59; [...] alert tls [...] tls_cert_notbefore:>2015-10-22; [...] alert tls [...] tls_cert_notafter:2000-10-22<>2020-05-15; [...] --- src/Makefile.am | 1 + src/detect-tls-cert-validity.c | 1204 ++++++++++++++++++++++++++++++++ src/detect-tls-cert-validity.h | 45 ++ src/detect.c | 2 + src/detect.h | 2 + 5 files changed, 1254 insertions(+) create mode 100644 src/detect-tls-cert-validity.c create mode 100644 src/detect-tls-cert-validity.h diff --git a/src/Makefile.am b/src/Makefile.am index c19d33cf039a..97a7749bdea7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -208,6 +208,7 @@ detect-template.c detect-template.h \ detect-template-buffer.c detect-template-buffer.h \ detect-threshold.c detect-threshold.h \ detect-tls.c detect-tls.h \ +detect-tls-cert-validity.c detect-tls-cert-validity.h \ detect-tls-version.c detect-tls-version.h \ detect-tos.c detect-tos.h \ detect-ttl.c detect-ttl.h \ diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c new file mode 100644 index 000000000000..15d612fb5d02 --- /dev/null +++ b/src/detect-tls-cert-validity.c @@ -0,0 +1,1204 @@ +/* Copyright (C) 2015 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 Mats Klepsland + * + * Implements tls certificate validity keywords + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-tls-cert-validity.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-ssl.h" + +#include "util-time.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +/** + * [tls_notbefore|tls_notafter]:[<|>][<>]; + */ +#define PARSE_REGEX "^\\s*(<|>)?\\s*([ -:TW0-9]+)\\s*(?:(<>)\\s*([ -:TW0-9]+))?\\s*$" +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +static int DetectTlsValidityMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t, void *, Signature *, SigMatch *); +static time_t DateStringToEpoch (char *); +static DetectTlsValidityData *DetectTlsValidityParse (char *); +static int DetectTlsNotBeforeSetup (DetectEngineCtx *, Signature *s, char *str); +static int DetectTlsNotAfterSetup (DetectEngineCtx *, Signature *s, char *str); +static int DetectTlsValiditySetup (DetectEngineCtx *, Signature *s, char *str, uint8_t); +void TlsNotBeforeRegisterTests(void); +void TlsNotAfterRegisterTests(void); +static void DetectTlsValidityFree(void *); + +/** + * \brief Registration function for tls validity keywords. + */ +void DetectTlsValidityRegister (void) +{ + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].name = "tls_cert_notbefore"; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].desc = "match TLS certificate notBefore field"; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsnotbefore"; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Match = NULL; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].AppLayerMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Setup = DetectTlsNotBeforeSetup; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Free = DetectTlsValidityFree; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].RegisterTests = TlsNotBeforeRegisterTests; + + sigmatch_table[DETECT_AL_TLS_NOTAFTER].name = "tls_cert_notafter"; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].desc = "match TLS certificate notAfter field"; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsnotafter"; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].Match = NULL; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].AppLayerMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].Setup = DetectTlsNotAfterSetup; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].Free = DetectTlsValidityFree; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].RegisterTests = TlsNotAfterRegisterTests; + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} + +/** + * \internal + * \brief Function to match validity field in a tls certificate. + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectTlsValidityData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectTlsValidityMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +{ + SCEnter(); + + SSLState *ssl_state = (SSLState *)state; + if (ssl_state == NULL) { + SCLogDebug("no tls state, no match"); + SCReturnInt(0); + } + + int ret = 0; + + SSLStateConnp *connp = NULL; + if (flags & STREAM_TOSERVER) + connp = &ssl_state->client_connp; + else + connp = &ssl_state->server_connp; + + const DetectTlsValidityData *dd = (const DetectTlsValidityData *)m->ctx; + + time_t cert_epoch = 0; + if (dd->type == DETECT_TLS_TYPE_NOTBEFORE) + cert_epoch = connp->cert0_not_before; + else if (dd->type == DETECT_TLS_TYPE_NOTAFTER) + cert_epoch = connp->cert0_not_after; + + if (cert_epoch == 0) + SCReturnInt(0); + + if (dd->mode == DETECT_TLS_VALIDITY_EQ && cert_epoch == dd->epoch) + ret = 1; + else if (dd->mode == DETECT_TLS_VALIDITY_LT && cert_epoch <= dd->epoch) + ret = 1; + else if (dd->mode == DETECT_TLS_VALIDITY_GT && cert_epoch >= dd->epoch) + ret = 1; + else if (dd->mode == DETECT_TLS_VALIDITY_RA && + cert_epoch >= dd->epoch && cert_epoch <= dd->epoch2) + ret = 1; + + SCReturnInt(ret); +} + +/** + * \internal + * \brief Function to check if string is epoch. + * + * \param string Date string. + * + * \retval epoch time on success. + * \retval 0 on failure. + */ +static time_t StringIsEpoch (char *string) +{ + if (strlen(string) == 0) + return -1; + + /* We assume that the date string is epoch if it consists of only + digits. */ + char *sp = string; + while (*sp) { + if (isdigit(*sp++) == 0) + return -1; + } + + return strtol(string, NULL, 10); +} + +/** + * \internal + * \brief Function to convert date string to epoch. + * + * \param string Date string. + * + * \retval epoch on success. + * \retval 0 on failure. + */ +static time_t DateStringToEpoch (char *string) +{ + int r = 0; + struct tm tm; + char *patterns[] = { + /* ISO 8601 */ + "%Y-%m", + "%Y-%m-%d", + "%Y-%m-%d %H", + "%Y-%m-%d %H:%M", + "%Y-%m-%d %H:%M:%S", + "%Y-%m-%dT%H", + "%Y-%m-%dT%H:%M", + "%Y-%m-%dT%H:%M:%S", + "%H:%M", + "%H:%M:%S", + }; + + /* Skip leading whitespace. */ + while (isspace(*string)) + string++; + + size_t inlen, oldlen; + + oldlen = inlen = strlen(string); + + /* Skip trailing whitespace */ + while (inlen > 0 && isspace(string[inlen - 1])) + inlen--; + + char tmp[inlen + 1]; + + if (inlen < oldlen) { + strlcpy(tmp, string, inlen + 1); + string = tmp; + } + + time_t epoch = StringIsEpoch(string); + if (epoch != -1) { + return epoch;; + } + + r = SCStringPatternToTime(string, patterns, 10, &tm); + + if (r != 0) + return -1; + + return SCMkTimeUtc(&tm); +} + +/** + * \internal + * \brief Function to parse options passed via tls validity keywords. + * + * \param rawstr Pointer to the user provided options. + * + * \retval dd pointer to DetectTlsValidityData on success. + * \retval NULL on failure. + */ +static DetectTlsValidityData *DetectTlsValidityParse (char *rawstr) +{ + DetectTlsValidityData *dd = NULL; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + char mode[2] = ""; + char value1[20] = ""; + char value2[20] = ""; + char range[3] = ""; + + ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, + 0, ov, MAX_SUBSTRINGS); + if (ret < 3 || ret > 5) { + SCLogError(SC_ERR_PCRE_MATCH, "Parse error %s", rawstr); + goto error; + } + + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, mode, + sizeof(mode)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("mode \"%s\"", mode); + + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, value1, + sizeof(value1)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("value1 \"%s\"", value1); + + if (ret > 3) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, + range, sizeof(range)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("range \"%s\"", range); + + if (ret > 4) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, + value2, sizeof(value2)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, + "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("value2 \"%s\"", value2); + } + } + + dd = SCMalloc(sizeof(DetectTlsValidityData)); + if (unlikely(dd == NULL)) + goto error; + + dd->epoch = 0; + dd->epoch2 = 0; + dd->mode = DETECT_TLS_VALIDITY_EQ; + + if (strlen(mode) > 0) { + if (mode[0] == '<') + dd->mode = DETECT_TLS_VALIDITY_LT; + else if (mode[0] == '>') + dd->mode = DETECT_TLS_VALIDITY_GT; + else + dd->mode = DETECT_TLS_VALIDITY_EQ; + } + + if (strlen(range) > 0) { + if (strcmp("<>", range) == 0) + dd->mode = DETECT_TLS_VALIDITY_RA; + } + + if (strlen(range) != 0 && strlen(mode) != 0) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Range specified but mode also set"); + goto error; + } + + /* set the first value */ + dd->epoch = DateStringToEpoch(value1); + if (dd->epoch == -1) + goto error; + + /* set the second value if specified */ + if (strlen(value2) > 0) { + if (dd->mode != DETECT_TLS_VALIDITY_RA) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Multiple tls validity values specified but mode is not range"); + goto error; + } + + dd->epoch2 = DateStringToEpoch(value2); + if (dd->epoch2 == -1) + goto error; + + if (dd->epoch2 <= dd->epoch) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Second value in range must not be smaller than the first"); + goto error; + } + } + return dd; + +error: + if (dd) + SCFree(dd); + return NULL; +} + +/** + * \brief Function to add the parsed tls_notbefore into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsNotBeforeSetup (DetectEngineCtx *de_ctx, Signature *s, + char *rawstr) +{ + uint8_t type = DETECT_TLS_TYPE_NOTBEFORE; + int r = DetectTlsValiditySetup(de_ctx, s, rawstr, type); + + SCReturnInt(r); +} + +/** + * \brief Function to add the parsed tls_notafter into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsNotAfterSetup (DetectEngineCtx *de_ctx, Signature *s, + char *rawstr) +{ + uint8_t type = DETECT_TLS_TYPE_NOTAFTER; + int r = DetectTlsValiditySetup(de_ctx, s, rawstr, type); + + SCReturnInt(r); +} + +/** + * \brief Function to add the parsed tls validity field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsValiditySetup (DetectEngineCtx *de_ctx, Signature *s, + char *rawstr, uint8_t type) +{ + DetectTlsValidityData *dd = NULL; + SigMatch *sm = NULL; + + SCLogDebug("\'%s\'", rawstr); + + dd = DetectTlsValidityParse(rawstr); + if (dd == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT,"Parsing \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "rule contains conflicting keywords."); + goto error; + } + + if (type == DETECT_TLS_TYPE_NOTBEFORE) { + dd->type = DETECT_TLS_TYPE_NOTBEFORE; + sm->type = DETECT_AL_TLS_NOTBEFORE; + } + else if (type == DETECT_TLS_TYPE_NOTAFTER) { + dd->type = DETECT_TLS_TYPE_NOTAFTER; + sm->type = DETECT_AL_TLS_NOTAFTER; + } + else { + goto error; + } + + sm->ctx = (void *)dd; + + s->flags |= SIG_FLAG_APPLAYER; + s->alproto = ALPROTO_TLS; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + + return 0; + +error: + DetectTlsValidityFree(dd); + if (sm) + SCFree(sm); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectTlsValidityData. + * + * \param de_ptr Pointer to DetectTlsValidityData. + */ +void DetectTlsValidityFree(void *de_ptr) +{ + DetectTlsValidityData *dd = (DetectTlsValidityData *)de_ptr; + if (dd) + SCFree(dd); +} + +#ifdef UNITTESTS + +/** + * \test This is a test for a valid value 1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse01 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("1430000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value >1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse02 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(">1430000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->mode == DETECT_TLS_VALIDITY_GT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value <1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse03 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("<1430000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->mode == DETECT_TLS_VALIDITY_LT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 1430000000<>1470000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse04 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("1430000000<>1470000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->epoch2 == 1470000000 && + dd->mode == DETECT_TLS_VALIDITY_RA); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a invalid value A. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse05 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("A"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value >1430000000<>1470000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse06 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(">1430000000<>1470000000"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value 1430000000<>. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse07 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("1430000000<>"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value <>1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse08 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("<>1430000000"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value "". + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse09 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(""); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value " ". + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse10 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(" "); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value 1490000000<>1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse11 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("1490000000<>1430000000"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a valid value 1430000000 <> 1490000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse12 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("1430000000 <> 1490000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->epoch2 == 1490000000 && + dd->mode == DETECT_TLS_VALIDITY_RA); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value > 1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse13 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("> 1430000000 "); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->mode == DETECT_TLS_VALIDITY_GT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value < 1490000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse14 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("< 1490000000 "); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1490000000 && dd->mode == DETECT_TLS_VALIDITY_LT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 1490000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse15 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(" 1490000000 "); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1490000000 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse16 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1443657600 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value >2015-10-22. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse17 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(">2015-10-22"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445472000 && dd->mode == DETECT_TLS_VALIDITY_GT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value <2015-10-22 23. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse18 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("<2015-10-22 23"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445554800 && dd->mode == DETECT_TLS_VALIDITY_LT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10-22 23:59. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse19 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10-22 23:59"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445558340 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10-22 23:59:59. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse20 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10-22 23:59:59"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445558399 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10-22T23. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse21 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10-22T23"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445554800 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10-22T23:59. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse22 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10-22T23:59"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445558340 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10-22T23:59:59. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse23 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10-22T23:59:59"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445558399 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test Test matching on validity dates in a certificate. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestDetect01(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, + 0x5b, 0x85, 0xd4, 0x40, 0xab, 0xbe, 0xc0, 0xbc, + 0x41, 0xf2, 0x26, 0xf0, 0xfe, 0x21, 0xee, 0x8b, + 0x4c, 0x7e, 0x07, 0xc8, 0xec, 0xd2, 0x00, 0x46, + 0x4c, 0xeb, 0xb7, 0x00, 0x00, 0x16, 0xc0, 0x2b, + 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, + 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, + 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0xff, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, + 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, + 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, + 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, + 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, + 0x14, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, + 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x04, 0x02, 0x02, 0x02 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, + 0xdb, 0xbb, 0x23, 0xcf, 0x0b, 0x43, 0x02, 0x1d, + 0x46, 0x11, 0x27, 0x5c, 0x98, 0xcf, 0x67, 0xe1, + 0x94, 0x3d, 0x62, 0x7d, 0x38, 0x48, 0x21, 0x23, + 0xa5, 0x62, 0x31, 0x00, 0xc0, 0x2f, 0x00, 0x00, + 0x1c, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, + 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, + 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x19, + 0xb7, 0xb1, 0x32, 0x3b, 0x1c, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, + 0x31, 0x33, 0x31, 0x33, 0x32, 0x34, 0x35, 0x32, + 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x30, + 0x35, 0x31, 0x33, 0x31, 0x36, 0x30, 0x30, 0x5a, + 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa5, 0x0a, 0xb9, 0xb1, 0xca, 0x36, 0xd1, 0xae, + 0x22, 0x38, 0x07, 0x06, 0xc9, 0x1a, 0x56, 0x4f, + 0xbb, 0xdf, 0xa8, 0x6d, 0xbd, 0xee, 0x76, 0x16, + 0xbc, 0x53, 0x3c, 0x03, 0x6a, 0x5c, 0x94, 0x50, + 0x87, 0x2f, 0x28, 0xb4, 0x4e, 0xd5, 0x9b, 0x8f, + 0xfe, 0x02, 0xde, 0x2a, 0x83, 0x01, 0xf9, 0x45, + 0x61, 0x0e, 0x66, 0x0e, 0x24, 0x22, 0xe2, 0x59, + 0x66, 0x0d, 0xd3, 0xe9, 0x77, 0x8a, 0x7e, 0x42, + 0xaa, 0x5a, 0xf9, 0x05, 0xbf, 0x30, 0xc7, 0x03, + 0x2b, 0xdc, 0xa6, 0x9c, 0xe0, 0x9f, 0x0d, 0xf1, + 0x28, 0x19, 0xf8, 0xf2, 0x02, 0xfa, 0xbd, 0x62, + 0xa0, 0xf3, 0x02, 0x2b, 0xcd, 0xf7, 0x09, 0x04, + 0x3b, 0x52, 0xd8, 0x65, 0x4b, 0x4a, 0x70, 0xe4, + 0x57, 0xc9, 0x2e, 0x2a, 0xf6, 0x9c, 0x6e, 0xd8, + 0xde, 0x01, 0x52, 0xc9, 0x6f, 0xe9, 0xef, 0x82, + 0xbc, 0x0b, 0x95, 0xb2, 0xef, 0xcb, 0x91, 0xa6, + 0x0b, 0x2d, 0x14, 0xc6, 0x00, 0xa9, 0x33, 0x86, + 0x64, 0x00, 0xd4, 0x92, 0x19, 0x53, 0x3d, 0xfd, + 0xcd, 0xc6, 0x1a, 0xf2, 0x0e, 0x67, 0xc2, 0x1d, + 0x2c, 0xe0, 0xe8, 0x29, 0x97, 0x1c, 0xb6, 0xc4, + 0xb2, 0x02, 0x0c, 0x83, 0xb8, 0x60, 0x61, 0xf5, + 0x61, 0x2d, 0x73, 0x5e, 0x85, 0x4d, 0xbd, 0x0d, + 0xe7, 0x1a, 0x37, 0x56, 0x8d, 0xe5, 0x50, 0x0c, + 0xc9, 0x64, 0x4c, 0x11, 0xea, 0xf3, 0xcb, 0x26, + 0x34, 0xbd, 0x02, 0xf5, 0xc1, 0xfb, 0xa2, 0xec, + 0x27, 0xbb, 0x60, 0xbe, 0x0b, 0xf6, 0xe7, 0x3c, + 0x2d, 0xc9, 0xe7, 0xb0, 0x30, 0x28, 0x17, 0x3d, + 0x90, 0xf1, 0x63, 0x8e, 0x49, 0xf7, 0x15, 0x78, + 0x21, 0xcc, 0x45, 0xe6, 0x86, 0xb2, 0xd8, 0xb0, + 0x2e, 0x5a, 0xb0, 0x58, 0xd3, 0xb6, 0x11, 0x40, + 0xae, 0x81, 0x1f, 0x6b, 0x7a, 0xaf, 0x40, 0x50, + 0xf9, 0x2e, 0x81, 0x8b, 0xec, 0x26, 0x11, 0x3f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x53, 0x30, 0x82, 0x01, 0x4f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, + 0x0b, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x6e, 0x6f, 0x82, 0x09, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xc6, 0x53, 0x87, 0x42, + 0x2d, 0xc8, 0xee, 0x7a, 0x62, 0x1e, 0x83, 0xdb, + 0x0d, 0xe2, 0x32, 0xeb, 0x8b, 0xaf, 0x69, 0x40, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, + 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, + 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, + 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, + 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, + 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, + 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x7b, 0x27, 0x00, 0x46, 0x8f, 0xfd, 0x5b, 0xff, + 0xcb, 0x05, 0x9b, 0xf7, 0xf1, 0x68, 0xf6, 0x9a, + 0x7b, 0xba, 0x53, 0xdf, 0x63, 0xed, 0x11, 0x94, + 0x39, 0xf2, 0xd0, 0x20, 0xcd, 0xa3, 0xc4, 0x98, + 0xa5, 0x10, 0x74, 0xe7, 0x10, 0x6d, 0x07, 0xf8, + 0x33, 0x87, 0x05, 0x43, 0x0e, 0x64, 0x77, 0x09, + 0x18, 0x4f, 0x38, 0x2e, 0x45, 0xae, 0xa8, 0x34, + 0x3a, 0xa8, 0x33, 0xac, 0x9d, 0xdd, 0x25, 0x91, + 0x59, 0x43, 0xbe, 0x0f, 0x87, 0x16, 0x2f, 0xb5, + 0x27, 0xfd, 0xce, 0x2f, 0x35, 0x5d, 0x12, 0xa1, + 0x66, 0xac, 0xf7, 0x95, 0x38, 0x0f, 0xe5, 0xb1, + 0x18, 0x18, 0xe6, 0x80, 0x52, 0x31, 0x8a, 0x66, + 0x02, 0x52, 0x1a, 0xa4, 0x32, 0x6a, 0x61, 0x05, + 0xcf, 0x1d, 0xf9, 0x90, 0x73, 0xf0, 0xeb, 0x20, + 0x31, 0x7b, 0x2e, 0xc0, 0xb0, 0xfb, 0x5c, 0xcc, + 0xdc, 0x76, 0x55, 0x72, 0xaf, 0xb1, 0x05, 0xf4, + 0xad, 0xf9, 0xd7, 0x73, 0x5c, 0x2c, 0xbf, 0x0d, + 0x84, 0x18, 0x01, 0x1d, 0x4d, 0x08, 0xa9, 0x4e, + 0x37, 0xb7, 0x58, 0xc4, 0x05, 0x0e, 0x65, 0x63, + 0xd2, 0x88, 0x02, 0xf5, 0x82, 0x17, 0x08, 0xd5, + 0x8f, 0x80, 0xc7, 0x82, 0x29, 0xbb, 0xe1, 0x04, + 0xbe, 0xf6, 0xe1, 0x8c, 0xbc, 0x3a, 0xf8, 0xf9, + 0x56, 0xda, 0xdc, 0x8e, 0xc6, 0xe6, 0x63, 0x98, + 0x12, 0x08, 0x41, 0x2c, 0x9d, 0x7c, 0x82, 0x0d, + 0x1e, 0xea, 0xba, 0xde, 0x32, 0x09, 0xda, 0x52, + 0x24, 0x4f, 0xcc, 0xb6, 0x09, 0x33, 0x8b, 0x00, + 0xf9, 0x83, 0xb3, 0xc6, 0xa4, 0x90, 0x49, 0x83, + 0x2d, 0x36, 0xd9, 0x11, 0x78, 0xd0, 0x62, 0x9f, + 0xc4, 0x8f, 0x84, 0xba, 0x7f, 0xaa, 0x04, 0xf1, + 0xd9, 0xa4, 0xad, 0x5d, 0x63, 0xee, 0x72, 0xc6, + 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, + 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_notbefore\"; " + "tls_cert_notbefore:<2016-07-20; sid:1;)"); + FAIL_IF_NULL(s); + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_notafter\"; " + "tls_cert_notafter:>2016-09-01; sid:2;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_hello, sizeof(client_hello)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + FAIL_IF(PacketAlertCheck(p1, 2)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + FAIL_IF(PacketAlertCheck(p2, 2)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + FAIL_IF_NOT(PacketAlertCheck(p3, 2)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief Register unit tests for tls_notbefore. + */ +void TlsNotBeforeRegisterTests(void) +{ +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("ValidityTestParse01", ValidityTestParse01); + UtRegisterTest("ValidityTestParse03", ValidityTestParse03); + UtRegisterTest("ValidityTestParse05", ValidityTestParse05); + UtRegisterTest("ValidityTestParse07", ValidityTestParse07); + UtRegisterTest("ValidityTestParse09", ValidityTestParse09); + UtRegisterTest("ValidityTestParse11", ValidityTestParse11); + UtRegisterTest("ValidityTestParse13", ValidityTestParse13); + UtRegisterTest("ValidityTestParse15", ValidityTestParse15); + UtRegisterTest("ValidityTestParse17", ValidityTestParse17); + UtRegisterTest("ValidityTestParse19", ValidityTestParse19); + UtRegisterTest("ValidityTestParse21", ValidityTestParse21); + UtRegisterTest("ValidityTestParse23", ValidityTestParse23); + UtRegisterTest("ValidityTestDetect01", ValidityTestDetect01); +#endif /* UNITTESTS */ +} + +/** + * \brief Register unit tests for tls_notafter. + */ +void TlsNotAfterRegisterTests(void) +{ +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("ValidityTestParse02", ValidityTestParse02); + UtRegisterTest("ValidityTestParse04", ValidityTestParse04); + UtRegisterTest("ValidityTestParse06", ValidityTestParse06); + UtRegisterTest("ValidityTestParse08", ValidityTestParse08); + UtRegisterTest("ValidityTestParse10", ValidityTestParse10); + UtRegisterTest("ValidityTestParse12", ValidityTestParse12); + UtRegisterTest("ValidityTestParse14", ValidityTestParse14); + UtRegisterTest("ValidityTestParse16", ValidityTestParse16); + UtRegisterTest("ValidityTestParse18", ValidityTestParse18); + UtRegisterTest("ValidityTestParse20", ValidityTestParse20); + UtRegisterTest("ValidityTestParse22", ValidityTestParse22); +#endif /* UNITTESTS */ +} diff --git a/src/detect-tls-cert-validity.h b/src/detect-tls-cert-validity.h new file mode 100644 index 000000000000..1589821ab4bb --- /dev/null +++ b/src/detect-tls-cert-validity.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2015 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 Mats Klepsland + */ + +#ifndef __DETECT_TLS_VALIDITY_H__ +#define __DETECT_TLS_VALIDITY_H__ + +#define DETECT_TLS_VALIDITY_LT 0 +#define DETECT_TLS_VALIDITY_EQ 1 +#define DETECT_TLS_VALIDITY_GT 2 +#define DETECT_TLS_VALIDITY_RA 3 + +#define DETECT_TLS_TYPE_NOTBEFORE 0 +#define DETECT_TLS_TYPE_NOTAFTER 1 + +typedef struct DetectTlsValidityData_ { + time_t epoch; + time_t epoch2; + uint8_t mode; + uint8_t type; +} DetectTlsValidityData; + +/* prototypes */ +void DetectTlsValidityRegister (void); + +#endif /* __DETECT_TLS_VALIDITY_H__ */ diff --git a/src/detect.c b/src/detect.c index f527d051f907..e933a23e0aa3 100644 --- a/src/detect.c +++ b/src/detect.c @@ -173,6 +173,7 @@ #include "app-layer-smtp.h" #include "app-layer-template.h" #include "detect-tls.h" +#include "detect-tls-cert-validity.h" #include "detect-tls-version.h" #include "detect-ssh-proto-version.h" #include "detect-ssh-software-version.h" @@ -4418,6 +4419,7 @@ void SigTableSetup(void) DetectHttpMethodRegister(); DetectHttpStatMsgRegister(); DetectTlsRegister(); + DetectTlsValidityRegister(); DetectTlsVersionRegister(); DetectUrilenRegister(); DetectDetectionFilterRegister(); diff --git a/src/detect.h b/src/detect.h index 260f23f7cb1b..05870f364243 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1179,6 +1179,8 @@ enum { DETECT_AL_TLS_VERSION, DETECT_AL_TLS_SUBJECT, DETECT_AL_TLS_ISSUERDN, + DETECT_AL_TLS_NOTBEFORE, + DETECT_AL_TLS_NOTAFTER, DETECT_AL_TLS_FINGERPRINT, DETECT_AL_TLS_STORE, From ac4e308140468fe2ee2ae32aa79392645fdbf7db Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 14 Mar 2016 10:31:16 +0100 Subject: [PATCH 1745/2553] util-time: add function to create a UTC time string Add function CreateUtcIsoTimeString to create a UTC time string. --- src/util-time.c | 21 +++++++++++++++++++++ src/util-time.h | 1 + 2 files changed, 22 insertions(+) diff --git a/src/util-time.c b/src/util-time.c index 992650e317d6..6670a0157add 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -64,6 +64,7 @@ static SCSpinlock current_time_spinlock; static char live = TRUE; struct tm *SCLocalTime(time_t timep, struct tm *result); +struct tm *SCUtcTime(time_t timep, struct tm *result); void TimeInit(void) { @@ -190,6 +191,26 @@ void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size) } } +void CreateUtcIsoTimeString (const struct timeval *ts, char *str, size_t size) +{ + time_t time = ts->tv_sec; + struct tm local_tm; + struct tm *t = (struct tm*)SCUtcTime(time, &local_tm); + char time_fmt[64] = { 0 }; + + if (likely(t != NULL)) { + strftime(time_fmt, sizeof(time_fmt), "%Y-%m-%dT%H:%M:%S", t); + snprintf(str, size, time_fmt, ts->tv_usec); + } else { + snprintf(str, size, "ts-error"); + } +} + +struct tm *SCUtcTime(time_t timep, struct tm *result) +{ + return gmtime_r(&timep, result); +} + /* * Time Caching code */ diff --git a/src/util-time.h b/src/util-time.h index c2cbd5a22beb..fa71cf565b4b 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -53,6 +53,7 @@ int TimeModeIsLive(void); struct tm *SCLocalTime(time_t timep, struct tm *result); void CreateTimeString (const struct timeval *ts, char *str, size_t size); void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size); +void CreateUtcIsoTimeString (const struct timeval *ts, char *str, size_t size); time_t SCMkTimeUtc (struct tm *tp); int SCStringPatternToTime (char *string, char **patterns, int num_patterns, struct tm *time); From 5b230bbce50e5c979221969bfdae3d42f8e558b8 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 20 Oct 2015 14:58:05 +0200 Subject: [PATCH 1746/2553] output-json-tls: add notBefore and notAfter fields to extended output Add notBefore and notAfter fields from TLS certificate to extended JSON output. --- src/output-json-tls.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index c7135031795e..34a12158e8f8 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -123,6 +123,26 @@ void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) break; } json_object_set_new(tjs, "version", json_string(ssl_version)); + + /* tls.notbefore */ + if (state->server_connp.cert0_not_before != 0) { + char timebuf[64]; + struct timeval tv; + tv.tv_sec = state->server_connp.cert0_not_before; + tv.tv_usec = 0; + CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); + json_object_set_new(tjs, "notbefore", json_string(timebuf)); + } + + /* tls.notafter */ + if (state->server_connp.cert0_not_after != 0) { + char timebuf[64]; + struct timeval tv; + tv.tv_sec = state->server_connp.cert0_not_after; + tv.tv_usec = 0; + CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); + json_object_set_new(tjs, "notafter", json_string(timebuf)); + } } static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, From ee2494906528e29ebbc4afc9fd4f23b155c92ba4 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 20 Oct 2015 15:08:31 +0200 Subject: [PATCH 1747/2553] log-tls: add notBefore and notAfter fields to extended output Add notBefore and NotAfter fields from TLS certificate to extended tls log output. --- src/log-tlslog.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/log-tlslog.c b/src/log-tlslog.c index ff7935ae5d95..113a2ccd3bcc 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -110,6 +110,22 @@ static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state) state->server_connp.version); break; } + if (state->server_connp.cert0_not_before != 0) { + char timebuf[64]; + struct timeval tv; + tv.tv_sec = state->server_connp.cert0_not_before; + tv.tv_usec = 0; + CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); + MemBufferWriteString(aft->buffer, " NOTBEFORE='%s'", timebuf); + } + if (state->server_connp.cert0_not_after != 0) { + char timebuf[64]; + struct timeval tv; + tv.tv_sec = state->server_connp.cert0_not_after; + tv.tv_usec = 0; + CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); + MemBufferWriteString(aft->buffer, " NOTAFTER='%s'", timebuf); + } MemBufferWriteString(aft->buffer, "\n"); } From 67ea82152179c604daf2ac9dae0d09dc16e961e1 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 20 Oct 2015 15:59:48 +0200 Subject: [PATCH 1748/2553] util-lua: add (wrapper) function to push integer to lua scripts --- src/util-lua.c | 6 ++++++ src/util-lua.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/util-lua.c b/src/util-lua.c index 54524826bd3a..7f1d44348c47 100644 --- a/src/util-lua.c +++ b/src/util-lua.c @@ -271,4 +271,10 @@ int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_ return 1; } +int LuaPushInteger(lua_State *luastate, lua_Integer n) +{ + lua_pushinteger(luastate, n); + return 1; +} + #endif /* HAVE_LUA */ diff --git a/src/util-lua.h b/src/util-lua.h index 492007a62af5..30431e74e8c2 100644 --- a/src/util-lua.h +++ b/src/util-lua.h @@ -80,6 +80,8 @@ void LuaPrintStack(lua_State *state); int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len); +int LuaPushInteger(lua_State *luastate, lua_Integer n); + #endif /* HAVE_LUA */ #endif /* __UTIL_LUA_H__ */ From cad638697d5ba22b5a5903c8dcf22b8f35a1409c Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 20 Oct 2015 16:03:04 +0200 Subject: [PATCH 1749/2553] lua: add lua functions for certificate validity dates Add functions TlsGetCertNotBefore and TLSGetCertNotAfter to get notBefore and notAfter fields from TLS certificate in lua scripts. --- src/util-lua-tls.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/util-lua-tls.c b/src/util-lua-tls.c index 5d0a7491eb6a..648eb423124e 100644 --- a/src/util-lua-tls.c +++ b/src/util-lua-tls.c @@ -57,6 +57,88 @@ #include "util-lua.h" #include "util-lua-common.h" +static int GetCertNotBefore(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_not_before == 0) + return LuaCallbackError(luastate, "error: no certificate NotBefore"); + + int r = LuaPushInteger(luastate, connp->cert0_not_before); + + return r; +} + +static int TlsGetCertNotBefore(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertNotBefore(luastate, f, direction); + + return r; +} + +static int GetCertNotAfter(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_not_after == 0) + return LuaCallbackError(luastate, "error: no certificate NotAfter"); + + int r = LuaPushInteger(luastate, connp->cert0_not_after); + + return r; +} + +static int TlsGetCertNotAfter(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertNotAfter(luastate, f, direction); + + return r; +} + static int GetCertInfo(lua_State *luastate, const Flow *f, int direction) { void *state = FlowGetAppState(f); @@ -218,6 +300,12 @@ static int TlsGetCertChain(lua_State *luastate) int LuaRegisterTlsFunctions(lua_State *luastate) { /* registration of the callbacks */ + lua_pushcfunction(luastate, TlsGetCertNotBefore); + lua_setglobal(luastate, "TlsGetCertNotBefore"); + + lua_pushcfunction(luastate, TlsGetCertNotAfter); + lua_setglobal(luastate, "TlsGetCertNotAfter"); + lua_pushcfunction(luastate, TlsGetCertInfo); lua_setglobal(luastate, "TlsGetCertInfo"); From d91664d67aea0b0d63939e6af319e3dac1d81592 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 22 Sep 2016 12:19:41 +0200 Subject: [PATCH 1750/2553] detect-dns: move DetectEngineInspectGenericList to detect-engine.c Move DetectEngineInspectGenericList from detect-engine-dns.c to detect-engine.c to enable it to be used other places as well. --- src/detect-engine-dns.c | 46 ------------------------------------- src/detect-engine.c | 50 +++++++++++++++++++++++++++++++++++++++++ src/detect-engine.h | 5 +++++ 3 files changed, 55 insertions(+), 46 deletions(-) diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index 915533f150d3..e68c1093b0c8 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -159,52 +159,6 @@ uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, SCReturnUInt(cnt); } -/** \brief Do the content inspection & validation for a signature - * - * \param de_ctx Detection engine context - * \param det_ctx Detection engine thread context - * \param s Signature to inspect - * \param sm SigMatch to inspect - * \param f Flow - * \param flags app layer flags - * \param state App layer state - * - * \retval 0 no match - * \retval 1 match - */ -int DetectEngineInspectGenericList(ThreadVars *tv, - const DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, const uint8_t flags, - void *alstate, void *txv, uint64_t tx_id, const int list) -{ - KEYWORD_PROFILING_SET_LIST(det_ctx, list); - - SigMatchData *smd = s->sm_arrays[list]; - SCLogDebug("running match functions, sm %p", smd); - if (smd != NULL) { - while (1) { - int match = 0; - KEYWORD_PROFILING_START; - match = sigmatch_table[smd->type]. - AppLayerTxMatch(tv, det_ctx, f, flags, alstate, txv, s, smd->ctx); - KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); - - if (match == 0) - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; - if (match == 2) { - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } - - if (smd->is_last) - break; - smd++; - } - } - - return DETECT_ENGINE_INSPECT_SIG_MATCH; -} - int DetectEngineInspectDnsRequest(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine.c b/src/detect-engine.c index a6fefbd155d7..5ba049f89f12 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -563,6 +563,56 @@ int DetectEngineReloadIsDone(void) return r; } +/** \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags app layer flags + * \param state App layer state + * + * \retval 0 no match + * \retval 1 match + */ +int DetectEngineInspectGenericList(ThreadVars *tv, + const DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + const Signature *s, Flow *f, const uint8_t flags, + void *alstate, void *txv, uint64_t tx_id, const int list) +{ +#ifdef PROFILING + KEYWORD_PROFILING_SET_LIST(det_ctx, list); +#endif + SigMatchData *smd = s->sm_arrays[list]; + SCLogDebug("running match functions, sm %p", smd); + if (smd != NULL) { + while (1) { + int match = 0; +#ifdef PROFILING + KEYWORD_PROFILING_START; +#endif + match = sigmatch_table[smd->type]. + AppLayerTxMatch(tv, det_ctx, f, flags, alstate, txv, s, smd->ctx); +#ifdef PROFILING + KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); +#endif + if (match == 0) + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + if (match == 2) { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + + if (smd->is_last) + break; + smd++; + } + } + + return DETECT_ENGINE_INSPECT_SIG_MATCH; +} + /* nudge capture loops to wake up */ static void BreakCapture(void) { diff --git a/src/detect-engine.h b/src/detect-engine.h index 64c241e16612..3211c601d9f2 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -94,6 +94,11 @@ int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id); int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id); int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id); +int DetectEngineInspectGenericList(ThreadVars *, const DetectEngineCtx *, + DetectEngineThreadCtx *, const Signature *, + Flow *, const uint8_t, void *, void *, + uint64_t, const int); + /** * \brief Registers an app inspection engine. * From dc8e0b3cf2a3b8ffc20f8c40832e31219d9fd4da Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 21 Sep 2016 12:40:12 +0200 Subject: [PATCH 1751/2553] detect: add detect engine for tls validity keywords Add detect engine for tls validity keywords (tls_cert_notbefore and tls_cert_notafter). --- src/detect-engine-state.h | 5 +++-- src/detect-engine-tls.c | 10 ++++++++++ src/detect-engine-tls.h | 5 +++++ src/detect-engine.c | 8 ++++++++ src/detect-parse.c | 4 ++++ src/detect-tls-cert-validity.c | 16 ++++++++++------ src/detect.h | 1 + 7 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 7757ce89538f..e079bedbca3c 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -90,8 +90,9 @@ #define DE_STATE_FLAG_TLSSNI_INSPECT BIT_U32(24) #define DE_STATE_FLAG_TLSISSUER_INSPECT BIT_U32(25) #define DE_STATE_FLAG_TLSSUBJECT_INSPECT BIT_U32(26) -#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(27) -#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(28) +#define DE_STATE_FLAG_TLSVALIDITY_INSPECT BIT_U32(27) +#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(28) +#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(29) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 1d3e8641b92e..25891671d0c2 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -341,3 +341,13 @@ int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, return cnt; } + +int DetectEngineInspectTlsValidity(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, + alstate, txv, tx_id, + DETECT_SM_LIST_TLSVALIDITY_MATCH); +} diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h index 547b63761379..efcc111f7bf5 100644 --- a/src/detect-engine-tls.h +++ b/src/detect-engine-tls.h @@ -38,4 +38,9 @@ int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); +int DetectEngineInspectTlsValidity(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); + #endif /* __DETECT_ENGINE_TLS_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 5ba049f89f12..638ebf070277 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -377,6 +377,12 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_TLSSUBJECT_INSPECT, 1, DetectEngineInspectTlsSubject }, + { IPPROTO_TCP, + ALPROTO_TLS, + DETECT_SM_LIST_TLSVALIDITY_MATCH, + DE_STATE_FLAG_TLSVALIDITY_INSPECT, + 1, + DetectEngineInspectTlsValidity }, /* specifically for UDP, register again * allows us to use the alproto w/o translation * in the detection engine */ @@ -2808,6 +2814,8 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "tls issuer"; case DETECT_SM_LIST_TLSSUBJECT_MATCH: return "tls subject"; + case DETECT_SM_LIST_TLSVALIDITY_MATCH: + return "tls validity"; case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; diff --git a/src/detect-parse.c b/src/detect-parse.c index c9373c21d60e..ca1a238afba8 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -167,6 +167,7 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_TLSSNI_MATCH, "tls_sni"); CASE_CODE_STRING(DETECT_SM_LIST_TLSISSUER_MATCH, "tls_cert_issuer"); CASE_CODE_STRING(DETECT_SM_LIST_TLSSUBJECT_MATCH, "tls_cert_subject"); + CASE_CODE_STRING(DETECT_SM_LIST_TLSVALIDITY_MATCH, "tls_cert_validity"); CASE_CODE_STRING(DETECT_SM_LIST_MODBUS_MATCH, "modbus"); CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); @@ -210,6 +211,7 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_TLSSNI_MATCH); CASE_CODE(DETECT_SM_LIST_TLSISSUER_MATCH); CASE_CODE(DETECT_SM_LIST_TLSSUBJECT_MATCH); + CASE_CODE(DETECT_SM_LIST_TLSVALIDITY_MATCH); CASE_CODE(DETECT_SM_LIST_MODBUS_MATCH); CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); CASE_CODE(DETECT_SM_LIST_POSTMATCH); @@ -1587,6 +1589,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_TLSSUBJECT_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_TLSVALIDITY_MATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_MODBUS_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index 15d612fb5d02..702f53f09c42 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -57,7 +57,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectTlsValidityMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, Signature *, SigMatch *); + uint8_t, void *, void *, const Signature *, + const SigMatchCtx *); + static time_t DateStringToEpoch (char *); static DetectTlsValidityData *DetectTlsValidityParse (char *); static int DetectTlsNotBeforeSetup (DetectEngineCtx *, Signature *s, char *str); @@ -76,7 +78,7 @@ void DetectTlsValidityRegister (void) sigmatch_table[DETECT_AL_TLS_NOTBEFORE].desc = "match TLS certificate notBefore field"; sigmatch_table[DETECT_AL_TLS_NOTBEFORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsnotbefore"; sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Match = NULL; - sigmatch_table[DETECT_AL_TLS_NOTBEFORE].AppLayerMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].AppLayerTxMatch = DetectTlsValidityMatch; sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Setup = DetectTlsNotBeforeSetup; sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Free = DetectTlsValidityFree; sigmatch_table[DETECT_AL_TLS_NOTBEFORE].RegisterTests = TlsNotBeforeRegisterTests; @@ -85,7 +87,7 @@ void DetectTlsValidityRegister (void) sigmatch_table[DETECT_AL_TLS_NOTAFTER].desc = "match TLS certificate notAfter field"; sigmatch_table[DETECT_AL_TLS_NOTAFTER].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsnotafter"; sigmatch_table[DETECT_AL_TLS_NOTAFTER].Match = NULL; - sigmatch_table[DETECT_AL_TLS_NOTAFTER].AppLayerMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].AppLayerTxMatch = DetectTlsValidityMatch; sigmatch_table[DETECT_AL_TLS_NOTAFTER].Setup = DetectTlsNotAfterSetup; sigmatch_table[DETECT_AL_TLS_NOTAFTER].Free = DetectTlsValidityFree; sigmatch_table[DETECT_AL_TLS_NOTAFTER].RegisterTests = TlsNotAfterRegisterTests; @@ -110,7 +112,9 @@ void DetectTlsValidityRegister (void) * \retval 1 match. */ static int DetectTlsValidityMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) + Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, + const SigMatchCtx *ctx) { SCEnter(); @@ -128,7 +132,7 @@ static int DetectTlsValidityMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx else connp = &ssl_state->server_connp; - const DetectTlsValidityData *dd = (const DetectTlsValidityData *)m->ctx; + const DetectTlsValidityData *dd = (const DetectTlsValidityData *)ctx; time_t cert_epoch = 0; if (dd->type == DETECT_TLS_TYPE_NOTBEFORE) @@ -451,7 +455,7 @@ static int DetectTlsValiditySetup (DetectEngineCtx *de_ctx, Signature *s, s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TLSVALIDITY_MATCH); return 0; diff --git a/src/detect.h b/src/detect.h index 05870f364243..f9754ff94e4a 100644 --- a/src/detect.h +++ b/src/detect.h @@ -127,6 +127,7 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_TLSSNI_MATCH, DETECT_SM_LIST_TLSISSUER_MATCH, DETECT_SM_LIST_TLSSUBJECT_MATCH, + DETECT_SM_LIST_TLSVALIDITY_MATCH, DETECT_SM_LIST_MODBUS_MATCH, From 398489e6df179e621563ac966e47a6a376c4e3de Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 2 Feb 2016 23:44:24 +0100 Subject: [PATCH 1752/2553] stream: fix depth reached detection When a segment only partially fit in streaming depth, the stream depth reached flag was not set resulting in a continuous inspection of the rest of the session. By setting the stream depth reached flag when the segment partially fit we avoid to reenter the code and we don't take anymore a code path resulting in the flag not to be set. --- src/stream-tcp-reassemble.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 30b725a18df4..28bf4b537ce7 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -1805,6 +1805,7 @@ static uint32_t StreamTcpReassembleCheckDepth(TcpStream *stream, /* complete fit */ SCReturnUInt(size); } else { + stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED; /* partial fit, return only what fits */ uint32_t part = (stream->isn + stream_config.reassembly_depth) - seq; #if DEBUG From 5908dd080475bccd689bf2d5309b92530f33801c Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Tue, 26 Apr 2016 14:58:59 +0200 Subject: [PATCH 1753/2553] app-layer: add flow counters This adds per flow counters for all supported protocols. This results in new data in stats output that looks like: ``` "app-layer": { "flow": { "http": 9310, "ftp": 0, "smtp": 0, "tls": 71, "ssh": 0, "imap": 0, "msn": 0, "smb": 170, "dcerpc_udp": 0, "dns_udp": 870, "dcerpc_tcp": 2, "dns_tcp": 0 }, }, ``` --- src/app-layer-parser.c | 7 +++ src/app-layer-parser.h | 1 + src/app-layer.c | 116 +++++++++++++++++++++++++++++++++++++++++ src/app-layer.h | 5 ++ src/flow-worker.c | 2 + 5 files changed, 131 insertions(+) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index be47acf542b3..92413ed2c9f0 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -149,6 +149,13 @@ struct AppLayerParserState_ { * Post 2.0 let's look at changing this to move it out to app-layer.c. */ static AppLayerParserCtx alp_ctx; +int AppLayerParserProtoIsRegistered(uint8_t ipproto, AppProto alproto) +{ + uint8_t ipproto_map = FlowGetProtoMapping(ipproto); + + return (alp_ctx.ctxs[ipproto_map][alproto].StateAlloc != NULL) ? 1 : 0; +} + AppLayerParserState *AppLayerParserStateAlloc(void) { SCEnter(); diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index ae7f89b6be2b..ac04464e62c1 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -34,6 +34,7 @@ #define APP_LAYER_PARSER_NO_REASSEMBLY 0x04 #define APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD 0x08 +int AppLayerParserProtoIsRegistered(uint8_t ipproto, AppProto alproto); /***** transaction handling *****/ diff --git a/src/app-layer.c b/src/app-layer.c index db4fa3abed95..ef4038b28eef 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -35,6 +35,7 @@ #include "stream-tcp-inline.h" #include "flow.h" #include "flow-util.h" +#include "flow-private.h" #include "util-debug.h" #include "util-print.h" @@ -66,6 +67,16 @@ struct AppLayerThreadCtx_ { #endif }; +typedef struct AppLayerCounters_ { + char *name; + uint16_t counter_id; +} AppLayerCounters; + +AppLayerCounters applayer_counters[FLOW_PROTO_MAX][ALPROTO_MAX]; + +void AppLayerSetupCounters(); +void AppLayerDeSetupCounters(); + /***** L7 layer dispatchers *****/ static void DisableAppLayer(Flow *f) @@ -80,6 +91,13 @@ static inline int ProtoDetectDone(const Flow *f, const TcpSession *ssn, uint8_t (FLOW_IS_PM_DONE(f, direction) && FLOW_IS_PP_DONE(f, direction))); } +static void AppLayerIncFlowCounter(ThreadVars *tv, Flow *f) +{ + if (likely(tv)) { + StatsIncr(tv, applayer_counters[f->protomap][f->alproto].counter_id); + } +} + int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet *p, Flow *f, TcpSession *ssn, TcpStream *stream, @@ -164,6 +182,11 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, f->alproto = *alproto; StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); + /* account flow if we have both side */ + if (*alproto_otherdir != ALPROTO_UNKNOWN) { + AppLayerIncFlowCounter(tv, f); + } + /* if we have seen data from the other direction first, send * data for that direction first to the parser. This shouldn't * be an issue, since each stream processing happens @@ -497,6 +520,7 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * if (f->alproto != ALPROTO_UNKNOWN) { f->flags |= FLOW_ALPROTO_DETECT_DONE; + AppLayerIncFlowCounter(tv, f); PACKET_PROFILING_APP_START(tctx, f->alproto); r = AppLayerParserParse(tctx->alp_tctx, @@ -576,6 +600,8 @@ int AppLayerSetup(void) AppLayerParserRegisterProtocolParsers(); AppLayerProtoDetectPrepareState(); + AppLayerSetupCounters(); + SCReturnInt(0); } @@ -586,6 +612,8 @@ int AppLayerDeSetup(void) AppLayerProtoDetectDeSetup(); AppLayerParserDeSetup(); + AppLayerDeSetupCounters(); + SCReturnInt(0); } @@ -648,6 +676,94 @@ void AppLayerRegisterGlobalCounters(void) StatsRegisterGlobalCounter("http.memcap", HTPMemcapGlobalCounter); } +#define IPPROTOS_MAX 2 +void AppLayerSetupCounters() +{ + uint8_t ipprotos[] = { IPPROTO_TCP, IPPROTO_UDP }; + uint8_t ipproto; + AppProto alproto; + AppProto alprotos[ALPROTO_MAX]; + + AppLayerProtoDetectSupportedAppProtocols(alprotos); + + for (ipproto = 0; ipproto < IPPROTOS_MAX; ipproto++) { + uint8_t other_ipproto = (ipprotos[ipproto] == IPPROTO_TCP) ? IPPROTO_UDP : IPPROTO_TCP; + const char *ipproto_suffix = (ipprotos[ipproto] == IPPROTO_TCP) ? "_tcp" : "_udp"; + + for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { + if (alprotos[alproto] == 1) { + char *str = "app_layer.flow."; + char *alproto_str = AppLayerGetProtoName(alproto); + int alproto_len = strlen(alproto_str) + 1; + uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); + + if (AppLayerParserProtoIsRegistered(ipprotos[ipproto], alproto) && + AppLayerParserProtoIsRegistered(other_ipproto, alproto)) + { + applayer_counters[ipproto_map][alproto].name = + SCMalloc(strlen(str) + alproto_len + strlen(ipproto_suffix)); + if (applayer_counters[ipproto_map][alproto].name == NULL) { + return; + } + + snprintf(applayer_counters[ipproto_map][alproto].name, + strlen(str) + alproto_len + strlen(ipproto_suffix), + "%s%s%s", str, alproto_str, ipproto_suffix); + } else { + applayer_counters[ipproto_map][alproto].name = + SCMalloc(strlen(str) + alproto_len); + if (applayer_counters[ipproto_map][alproto].name == NULL) { + return; + } + snprintf(applayer_counters[ipproto_map][alproto].name, + strlen(str) + alproto_len, + "%s%s", str, alproto_str); + } + } + } + } +} + +void AppLayerRegisterThreadCounters(ThreadVars *tv) +{ + uint8_t ipprotos[] = { IPPROTO_TCP, IPPROTO_UDP }; + uint8_t ipproto; + AppProto alproto; + AppProto alprotos[ALPROTO_MAX]; + + AppLayerProtoDetectSupportedAppProtocols(alprotos); + + for (ipproto = 0; ipproto < IPPROTOS_MAX; ipproto++) { + for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { + if (alprotos[alproto] == 1) { + uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); + applayer_counters[ipproto_map][alproto].counter_id = + StatsRegisterCounter(applayer_counters[ipproto_map][alproto].name, tv); + } + } + } +} + +void AppLayerDeSetupCounters() +{ + uint8_t ipprotos[] = { IPPROTO_TCP, IPPROTO_UDP }; + uint8_t ipproto; + AppProto alproto; + AppProto alprotos[ALPROTO_MAX]; + + AppLayerProtoDetectSupportedAppProtocols(alprotos); + + for (ipproto = 0; ipproto < IPPROTOS_MAX; ipproto++) { + for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { + if (alprotos[alproto] == 1) { + if (applayer_counters[FlowGetProtoMapping(ipprotos[ipproto])][alproto].name) { + SCFree(applayer_counters[FlowGetProtoMapping(ipprotos[ipproto])][alproto].name); + applayer_counters[FlowGetProtoMapping(ipprotos[ipproto])][alproto].name = NULL; + } + } + } + } +} /***** Unittests *****/ #ifdef UNITTESTS diff --git a/src/app-layer.h b/src/app-layer.h index f45afe6798c7..d138cd24f066 100644 --- a/src/app-layer.h +++ b/src/app-layer.h @@ -109,6 +109,11 @@ AppLayerThreadCtx *AppLayerGetCtxThread(ThreadVars *tv); */ void AppLayerDestroyCtxThread(AppLayerThreadCtx *tctx); +/** + * \brief Registers per flow counters for all protocols + * + */ +void AppLayerRegisterThreadCounters(ThreadVars *tv); /***** Profiling *****/ diff --git a/src/flow-worker.c b/src/flow-worker.c index f9f7228ed7f9..c3b95d6bf479 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -97,6 +97,8 @@ static TmEcode FlowWorkerThreadInit(ThreadVars *tv, void *initdata, void **data) if (OutputLoggerThreadInit(tv, initdata, &fw->output_thread) != TM_ECODE_OK) { return TM_ECODE_FAILED; } + + AppLayerRegisterThreadCounters(tv); /* setup pq for stream end pkts */ memset(&fw->pq, 0, sizeof(PacketQueue)); From 675fa564972b5a5336a31fe36f7ff1313ec4c7f3 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 26 Sep 2016 14:55:16 +0200 Subject: [PATCH 1754/2553] app-layer: add ThreadVars to AppLayerParserParse To be able to add a transaction counter we will need a ThreadVars in the AppLayerParserParse function. This function is massively used in unittests and this result in an long commit. --- src/app-layer-dcerpc-udp.c | 5 +- src/app-layer-dcerpc.c | 160 +++++++------ src/app-layer-detect-proto.c | 15 +- src/app-layer-ftp.c | 28 ++- src/app-layer-htp-file.c | 125 ++++++---- src/app-layer-htp.c | 166 +++++++++----- src/app-layer-modbus.c | 143 +++++++----- src/app-layer-parser.c | 18 +- src/app-layer-parser.h | 2 +- src/app-layer-smb.c | 48 ++-- src/app-layer-smb2.c | 4 +- src/app-layer-smtp.c | 367 +++++++++++++++--------------- src/app-layer-ssh.c | 189 ++++++++++----- src/app-layer-ssl.c | 144 +++++++----- src/app-layer.c | 23 +- src/detect-dce-iface.c | 45 ++-- src/detect-dce-opnum.c | 20 +- src/detect-dce-stub-data.c | 76 ++++--- src/detect-dns-query.c | 45 ++-- src/detect-engine-dcepayload.c | 33 ++- src/detect-engine-filedata-smtp.c | 11 +- src/detect-engine-hcbd.c | 6 +- src/detect-engine-hcd.c | 51 +++-- src/detect-engine-hhd.c | 132 +++++++---- src/detect-engine-hhhd.c | 75 ++++-- src/detect-engine-hmd.c | 51 +++-- src/detect-engine-hrhd.c | 122 ++++++---- src/detect-engine-hrhhd.c | 75 ++++-- src/detect-engine-hrl.c | 162 ++++++++----- src/detect-engine-hrud.c | 147 ++++++++---- src/detect-engine-hsbd.c | 165 +++++++++----- src/detect-engine-hscd.c | 93 +++++--- src/detect-engine-hsmd.c | 93 +++++--- src/detect-engine-hua.c | 51 +++-- src/detect-engine-modbus.c | 45 ++-- src/detect-engine-state.c | 60 +++-- src/detect-engine-uri.c | 162 ++++++++----- src/detect-ftpbounce.c | 24 +- src/detect-http-client-body.c | 78 ++++--- src/detect-http-cookie.c | 41 ++-- src/detect-http-header.c | 45 ++-- src/detect-http-hh.c | 54 +++-- src/detect-http-hrh.c | 60 +++-- src/detect-http-method.c | 12 +- src/detect-http-raw-header.c | 36 ++- src/detect-http-server-body.c | 254 +++++++++++++++------ src/detect-http-stat-code.c | 24 +- src/detect-http-stat-msg.c | 18 +- src/detect-http-ua.c | 54 +++-- src/detect-lua.c | 24 +- src/detect-pcre.c | 109 ++++++--- src/detect-ssh-proto-version.c | 36 ++- src/detect-ssh-software-version.c | 36 ++- src/detect-ssl-state.c | 17 +- src/detect-ssl-version.c | 36 ++- src/detect-template-buffer.c | 4 +- src/detect-tls-cert-issuer.c | 9 +- src/detect-tls-cert-subject.c | 9 +- src/detect-tls-cert-validity.c | 9 +- src/detect-tls-sni.c | 6 +- src/detect-tls-version.c | 36 ++- src/detect-uricontent.c | 42 ++-- src/detect-urilen.c | 3 +- src/detect.c | 33 ++- 64 files changed, 2754 insertions(+), 1512 deletions(-) diff --git a/src/app-layer-dcerpc-udp.c b/src/app-layer-dcerpc-udp.c index 56ed637f8611..7852a4b0bae1 100644 --- a/src/app-layer-dcerpc-udp.c +++ b/src/app-layer-dcerpc-udp.c @@ -1076,7 +1076,10 @@ int DCERPCUDPParserTest01(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, + dcerpcrequest, + requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 6efe6d029ee4..da547716160f 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -2422,7 +2422,9 @@ int DCERPCParserTest01(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcbind, bindlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpcbind, + bindlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2458,7 +2460,8 @@ int DCERPCParserTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpcbindack, bindacklen); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpcbindack, bindacklen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2482,7 +2485,9 @@ int DCERPCParserTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_EOF, dcerpcrequest, requestlen); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_EOF, dcerpcrequest, + requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2654,7 +2659,10 @@ int DCERPCParserTest02(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, + dcerpcrequest, + requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2854,7 +2862,10 @@ int DCERPCParserTest03(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, + dcerpcrequest, + requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4303,8 +4314,8 @@ int DCERPCParserTest05(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - bind1, bind1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4329,8 +4340,8 @@ int DCERPCParserTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind2, bind2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4478,8 +4489,8 @@ int DCERPCParserTest06(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, - bind1, bind1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4501,8 +4512,8 @@ int DCERPCParserTest06(void) result &= (dcerpc_state->dcerpc.dcerpcbindbindack.numctxitemsleft == 8); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind2, bind2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4564,8 +4575,9 @@ int DCERPCParserTest07(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, request1, + request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4587,8 +4599,8 @@ int DCERPCParserTest07(void) result &= (dcerpc_state->dcerpc.pdu_fragged = 1); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4603,8 +4615,8 @@ int DCERPCParserTest07(void) result &= (dcerpc_state->dcerpc.pdu_fragged = 1); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request3, request3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4656,8 +4668,9 @@ int DCERPCParserTest08(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - request, request_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, request, + request_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4716,8 +4729,9 @@ int DCERPCParserTest09(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - request, request_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, request, + request_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4790,8 +4804,8 @@ int DCERPCParserTest10(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, - fault, fault_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, fault, fault_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4808,8 +4822,8 @@ int DCERPCParserTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4823,8 +4837,8 @@ int DCERPCParserTest10(void) result &= (dcerpc_state->dcerpc.pdu_fragged == 1); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4891,8 +4905,8 @@ int DCERPCParserTest11(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4914,8 +4928,8 @@ int DCERPCParserTest11(void) result &= (dcerpc_state->dcerpc.pdu_fragged == 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4928,8 +4942,8 @@ int DCERPCParserTest11(void) result &= (dcerpc_state->dcerpc.pdu_fragged == 1); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request3, request3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4990,8 +5004,8 @@ int DCERPCParserTest12(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack1, bind_ack1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack1, bind_ack1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5011,8 +5025,8 @@ int DCERPCParserTest12(void) result &= (dcerpc_state->dcerpc.pdu_fragged == 1); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack2, bind_ack2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack2, bind_ack2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5068,8 +5082,8 @@ int DCERPCParserTest13(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind, bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5159,8 +5173,8 @@ int DCERPCParserTest14(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind, bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5221,8 +5235,8 @@ int DCERPCParserTest15(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack, bind_ack_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5683,8 +5697,8 @@ int DCERPCParserTest16(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind1, bind1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5701,8 +5715,8 @@ int DCERPCParserTest16(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack1, bind_ack1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack1, bind_ack1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5733,8 +5747,8 @@ int DCERPCParserTest16(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind2, bind2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5753,8 +5767,8 @@ int DCERPCParserTest16(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack2, bind_ack2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack2, bind_ack2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5785,8 +5799,8 @@ int DCERPCParserTest16(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind3, bind3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind3, bind3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5805,8 +5819,8 @@ int DCERPCParserTest16(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack3, bind_ack3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack3, bind_ack3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5929,8 +5943,8 @@ int DCERPCParserTest17(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind, bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5947,8 +5961,8 @@ int DCERPCParserTest17(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack, bind_ack_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5979,8 +5993,8 @@ int DCERPCParserTest17(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - alter_context, alter_context_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, alter_context, alter_context_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5999,8 +6013,9 @@ int DCERPCParserTest17(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - alter_context_resp, alter_context_resp_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, alter_context_resp, + alter_context_resp_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -6074,8 +6089,8 @@ int DCERPCParserTest18(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -6096,8 +6111,8 @@ int DCERPCParserTest18(void) result &= (dcerpc_state->dcerpc.pdu_fragged == 1); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -6340,7 +6355,9 @@ int DCERPCParserTest19(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpcbind, bindlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpcbind, + bindlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -6360,7 +6377,8 @@ int DCERPCParserTest19(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpcbindack, bindacklen); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpcbindack, bindacklen); if (r == 0) { printf("dce parser didn't return fail\n"); FLOWLOCK_UNLOCK(&f); diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index e9b2480e7fe0..68690441d82e 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -3342,7 +3342,8 @@ static int AppLayerProtoDetectTest16(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -3435,7 +3436,8 @@ static int AppLayerProtoDetectTest17(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -3530,7 +3532,8 @@ static int AppLayerProtoDetectTest18(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -3621,7 +3624,8 @@ static int AppLayerProtoDetectTest19(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_FTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_FTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -3723,7 +3727,8 @@ static int AppLayerProtoDetectTest20(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index ea323b853f51..974ec2e561bb 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -393,7 +393,8 @@ int FTPParserTest01(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf, ftplen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_EOF, ftpbuf, ftplen); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -447,7 +448,9 @@ int FTPParserTest03(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START, ftpbuf1, ftplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_START, ftpbuf1, + ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -457,7 +460,8 @@ int FTPParserTest03(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, ftplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -467,7 +471,8 @@ int FTPParserTest03(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf3, ftplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_EOF, ftpbuf3, ftplen3); if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -516,7 +521,10 @@ int FTPParserTest06(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, ftpbuf1, ftplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + ftpbuf1, + ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -568,7 +576,9 @@ int FTPParserTest07(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START, ftpbuf1, ftplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_START, ftpbuf1, + ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -578,7 +588,8 @@ int FTPParserTest07(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf2, ftplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_EOF, ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -638,7 +649,8 @@ int FTPParserTest10(void) else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, flags, &ftpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, flags, + &ftpbuf1[u], 1); if (r != 0) { SCLogDebug("toserver chunk %" PRIu32 " returned %" PRId32 ", expected 0: ", u, r); result = 0; diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index a3505f3110a1..ab0121d69b82 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -314,7 +314,9 @@ static int HTPFileParserTest01(void) SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -325,7 +327,8 @@ static int HTPFileParserTest01(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -406,7 +409,9 @@ static int HTPFileParserTest02(void) SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -417,7 +422,8 @@ static int HTPFileParserTest02(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -428,7 +434,8 @@ static int HTPFileParserTest02(void) SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -439,7 +446,8 @@ static int HTPFileParserTest02(void) SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -530,7 +538,9 @@ static int HTPFileParserTest03(void) SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -541,7 +551,8 @@ static int HTPFileParserTest03(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -552,7 +563,8 @@ static int HTPFileParserTest03(void) SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -563,7 +575,8 @@ static int HTPFileParserTest03(void) SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -574,7 +587,8 @@ static int HTPFileParserTest03(void) SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -585,7 +599,8 @@ static int HTPFileParserTest03(void) SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -685,7 +700,9 @@ static int HTPFileParserTest04(void) SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -696,7 +713,8 @@ static int HTPFileParserTest04(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -707,7 +725,8 @@ static int HTPFileParserTest04(void) SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -718,7 +737,8 @@ static int HTPFileParserTest04(void) SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -729,7 +749,8 @@ static int HTPFileParserTest04(void) SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -740,7 +761,8 @@ static int HTPFileParserTest04(void) SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -822,7 +844,9 @@ static int HTPFileParserTest05(void) SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -833,7 +857,8 @@ static int HTPFileParserTest05(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -934,7 +959,9 @@ static int HTPFileParserTest06(void) SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -945,7 +972,8 @@ static int HTPFileParserTest06(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1035,7 +1063,9 @@ static int HTPFileParserTest07(void) SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1046,7 +1076,8 @@ static int HTPFileParserTest07(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1129,7 +1160,9 @@ static int HTPFileParserTest08(void) SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1140,7 +1173,8 @@ static int HTPFileParserTest08(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1225,7 +1259,9 @@ static int HTPFileParserTest09(void) SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1236,7 +1272,8 @@ static int HTPFileParserTest09(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1247,7 +1284,8 @@ static int HTPFileParserTest09(void) SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1258,7 +1296,8 @@ static int HTPFileParserTest09(void) SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1341,7 +1380,9 @@ static int HTPFileParserTest10(void) SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1352,7 +1393,8 @@ static int HTPFileParserTest10(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1363,7 +1405,8 @@ static int HTPFileParserTest10(void) SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1374,7 +1417,8 @@ static int HTPFileParserTest10(void) SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1480,7 +1524,9 @@ static int HTPFileParserTest11(void) SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -1490,7 +1536,8 @@ static int HTPFileParserTest11(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -1500,7 +1547,8 @@ static int HTPFileParserTest11(void) SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -1510,7 +1558,8 @@ static int HTPFileParserTest11(void) SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 93925d4ed218..d4c15359dafe 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2849,7 +2849,8 @@ int HTPParserTest01(void) flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -2926,7 +2927,8 @@ static int HTPParserTest01a(void) flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -2988,8 +2990,10 @@ int HTPParserTest02(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -3053,7 +3057,8 @@ int HTPParserTest03(void) else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -3114,8 +3119,10 @@ int HTPParserTest04(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { FLOWLOCK_UNLOCK(f); goto end; @@ -3183,15 +3190,17 @@ int HTPParserTest05(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, - httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf4, + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); @@ -3199,30 +3208,32 @@ int HTPParserTest05(void) goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, + httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, - httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf6, - httplen6); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -3328,15 +3339,17 @@ int HTPParserTest06(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, - httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2, + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r); @@ -3417,7 +3430,8 @@ int HTPParserTest07(void) flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -3516,7 +3530,8 @@ libhtp:\n\ flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, httplen1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk returned %" PRId32 ", expected" " 0: ", r); @@ -3603,7 +3618,8 @@ libhtp:\n\ flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, httplen1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk returned %" PRId32 ", expected" " 0: ", r); @@ -3679,7 +3695,8 @@ int HTPParserTest10(void) flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -3771,7 +3788,8 @@ static int HTPParserTest11(void) flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -3856,7 +3874,8 @@ static int HTPParserTest12(void) flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -3944,7 +3963,8 @@ int HTPParserTest13(void) flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -4355,7 +4375,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -4538,7 +4559,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -4707,7 +4729,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -4874,7 +4897,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -5011,7 +5035,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -5121,7 +5146,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -5231,7 +5257,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -5342,7 +5369,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -5450,7 +5478,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -5559,7 +5588,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -5714,7 +5744,9 @@ libhtp:\n\ SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -5723,7 +5755,8 @@ libhtp:\n\ FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 1 again <<<<\n"); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -5832,7 +5865,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)&httpbuf[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + (uint8_t *)&httpbuf[u], 1); if (u < 18294) { /* first 18294 bytes should result in 0 */ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" @@ -5974,7 +6008,8 @@ libhtp:\n\ else flags = STREAM_TOSERVER; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)&httpbuf[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + (uint8_t *)&httpbuf[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); @@ -6057,7 +6092,8 @@ int HTPParserTest16(void) uint8_t flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)httpbuf, len); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + (uint8_t *)httpbuf, len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -6140,31 +6176,33 @@ int HTPParserTest17(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, - httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2, + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, - httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf4, - httplen4); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, + httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -6263,30 +6301,32 @@ int HTPParserTest18(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, - httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2, + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, - httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, - httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -6294,8 +6334,8 @@ int HTPParserTest18(void) } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5, - httplen5); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, + httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); @@ -6390,23 +6430,25 @@ int HTPParserTest19(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, - httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2, + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, - httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(f); diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index cd44fb2c3a18..cffb61cef63d 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1725,8 +1725,9 @@ static int ModbusParserTest01(void) { StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - readCoilsReq, sizeof(readCoilsReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1750,8 +1751,9 @@ static int ModbusParserTest01(void) { } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - readCoilsRsp, sizeof(readCoilsRsp)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, readCoilsRsp, + sizeof(readCoilsRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1791,8 +1793,9 @@ static int ModbusParserTest02(void) { StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, writeMultipleRegistersReq, + sizeof(writeMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1820,8 +1823,9 @@ static int ModbusParserTest02(void) { } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, writeMultipleRegistersRsp, + sizeof(writeMultipleRegistersRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1890,8 +1894,10 @@ static int ModbusParserTest03(void) { DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - readWriteMultipleRegistersReq, sizeof(readWriteMultipleRegistersReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + readWriteMultipleRegistersReq, + sizeof(readWriteMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1923,8 +1929,9 @@ static int ModbusParserTest03(void) { } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - readWriteMultipleRegistersRsp, sizeof(readWriteMultipleRegistersRsp)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, readWriteMultipleRegistersRsp, + sizeof(readWriteMultipleRegistersRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1979,8 +1986,9 @@ static int ModbusParserTest04(void) { StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - forceListenOnlyMode, sizeof(forceListenOnlyMode)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, forceListenOnlyMode, + sizeof(forceListenOnlyMode)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2058,8 +2066,9 @@ static int ModbusParserTest05(void) { DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - invalidProtocolIdReq, sizeof(invalidProtocolIdReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, invalidProtocolIdReq, + sizeof(invalidProtocolIdReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2144,8 +2153,9 @@ static int ModbusParserTest06(void) { DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - readCoilsRsp, sizeof(readCoilsRsp)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, readCoilsRsp, + sizeof(readCoilsRsp)); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2230,9 +2240,10 @@ static int ModbusParserTest07(void) { DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - invalidLengthWriteMultipleRegistersReq, - sizeof(invalidLengthWriteMultipleRegistersReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + invalidLengthWriteMultipleRegistersReq, + sizeof(invalidLengthWriteMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2317,8 +2328,9 @@ static int ModbusParserTest08(void) { DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - readCoilsReq, sizeof(readCoilsReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2342,8 +2354,9 @@ static int ModbusParserTest08(void) { } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - readCoilsErrorRsp, sizeof(readCoilsErrorRsp)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, readCoilsErrorRsp, + sizeof(readCoilsErrorRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2401,16 +2414,16 @@ static int ModbusParserTest09(void) { StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - input, input_len - part2_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, input, input_len - part2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - input, input_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, input, input_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2438,16 +2451,16 @@ static int ModbusParserTest09(void) { input = readCoilsRsp; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - input, input_len - part2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, input, input_len - part2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - input, input_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, input, input_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2497,8 +2510,8 @@ static int ModbusParserTest10(void) { StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - input, input_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, input, input_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2541,8 +2554,8 @@ static int ModbusParserTest10(void) { memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp)); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - input, sizeof(input_len)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, input, sizeof(input_len)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2608,9 +2621,10 @@ static int ModbusParserTest11(void) { DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - exceededLengthWriteMultipleRegistersReq, - sizeof(exceededLengthWriteMultipleRegistersReq) + 65523 /* header.length - 7 */ * sizeof(uint8_t)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + exceededLengthWriteMultipleRegistersReq, + sizeof(exceededLengthWriteMultipleRegistersReq) + 65523 * sizeof(uint8_t)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2695,9 +2709,10 @@ static int ModbusParserTest12(void) { DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - invalidLengthPDUWriteMultipleRegistersReq, - sizeof(invalidLengthPDUWriteMultipleRegistersReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + invalidLengthPDUWriteMultipleRegistersReq, + sizeof(invalidLengthPDUWriteMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2753,8 +2768,9 @@ static int ModbusParserTest13(void) { StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - maskWriteRegisterReq, sizeof(maskWriteRegisterReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, maskWriteRegisterReq, + sizeof(maskWriteRegisterReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2778,8 +2794,9 @@ static int ModbusParserTest13(void) { } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - maskWriteRegisterRsp, sizeof(maskWriteRegisterRsp)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, maskWriteRegisterRsp, + sizeof(maskWriteRegisterRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2819,8 +2836,9 @@ static int ModbusParserTest14(void) { StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - writeSingleRegisterReq, sizeof(writeSingleRegisterReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, writeSingleRegisterReq, + sizeof(writeSingleRegisterReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2844,8 +2862,9 @@ static int ModbusParserTest14(void) { } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - writeSingleRegisterRsp, sizeof(writeSingleRegisterRsp)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, writeSingleRegisterRsp, + sizeof(writeSingleRegisterRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2914,9 +2933,9 @@ static int ModbusParserTest15(void) { DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - invalidMaskWriteRegisterReq, - sizeof(invalidMaskWriteRegisterReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, invalidMaskWriteRegisterReq, + sizeof(invalidMaskWriteRegisterReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2946,8 +2965,9 @@ static int ModbusParserTest15(void) { } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - maskWriteRegisterRsp, sizeof(maskWriteRegisterRsp)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, maskWriteRegisterRsp, + sizeof(maskWriteRegisterRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3023,8 +3043,10 @@ static int ModbusParserTest16(void) { DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - invalidWriteSingleRegisterReq, sizeof(invalidWriteSingleRegisterReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + invalidWriteSingleRegisterReq, + sizeof(invalidWriteSingleRegisterReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3055,8 +3077,9 @@ static int ModbusParserTest16(void) { } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - writeSingleRegisterRsp, sizeof(writeSingleRegisterRsp)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, writeSingleRegisterRsp, + sizeof(writeSingleRegisterRsp)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 92413ed2c9f0..bd1962045b46 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -913,7 +913,7 @@ int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, /***** General *****/ -int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, +int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, uint8_t *input, uint32_t input_len) { SCEnter(); @@ -1314,7 +1314,8 @@ int AppLayerParserRequestFromFile(AppProto alproto, char *filename) } //PrintRawDataFp(stdout, buffer, result); - (void)AppLayerParserParse(alp_tctx, f, alproto, flags, buffer, result); + (void)AppLayerParserParse(NULL, alp_tctx, f, alproto, flags, + buffer, result); if (done) break; } @@ -1397,7 +1398,8 @@ int AppLayerParserFromFile(AppProto alproto, char *filename) } //PrintRawDataFp(stdout, buffer, result); - (void)AppLayerParserParse(alp_tctx, f, alproto, flags, buffer, result); + (void)AppLayerParserParse(NULL, alp_tctx, f, alproto, flags, + buffer, result); if (done) break; } @@ -1519,8 +1521,9 @@ static int AppLayerParserTest01(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, - testbuf, testlen); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_TEST, + STREAM_TOSERVER | STREAM_EOF, testbuf, + testlen); if (r != -1) { printf("returned %" PRId32 ", expected -1: ", r); FLOWLOCK_UNLOCK(f); @@ -1572,8 +1575,9 @@ static int AppLayerParserTest02(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, testbuf, - testlen); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_TEST, + STREAM_TOSERVER | STREAM_EOF, testbuf, + testlen); if (r != -1) { printf("returned %" PRId32 ", expected -1: \n", r); result = 0; diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index ac04464e62c1..368c7938a330 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -194,7 +194,7 @@ int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *alst /***** General *****/ -int AppLayerParserParse(AppLayerParserThreadCtx *tctx, Flow *f, AppProto alproto, +int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *tctx, Flow *f, AppProto alproto, uint8_t flags, uint8_t *input, uint32_t input_len); void AppLayerParserSetEOF(AppLayerParserState *pstate); int AppLayerParserHasDecoderEvents(uint8_t ipproto, AppProto alproto, void *alstate, AppLayerParserState *pstate, diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 9ebc4a669a47..bbf66dc2b44c 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -1593,7 +1593,8 @@ int SMBParserTest01(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_EOF, smbbuf, smblen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_EOF, smbbuf, smblen); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1672,7 +1673,8 @@ int SMBParserTest02(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_EOF, smbbuf, smblen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_EOF, smbbuf, smblen); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1970,7 +1972,8 @@ int SMBParserTest03(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_START, smbbuf1, smblen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1990,7 +1993,8 @@ int SMBParserTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1998,7 +2002,8 @@ int SMBParserTest03(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf3, smblen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf3, smblen3); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2089,7 +2094,8 @@ int SMBParserTest04(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_START, smbbuf1, smblen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2109,7 +2115,8 @@ int SMBParserTest04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2117,7 +2124,8 @@ int SMBParserTest04(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf3, smblen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf3, smblen3); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2125,7 +2133,8 @@ int SMBParserTest04(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf4, smblen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf4, smblen4); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2348,7 +2357,8 @@ int SMBParserTest07(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2424,7 +2434,8 @@ int SMBParserTest08(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2455,7 +2466,8 @@ int SMBParserTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT, smbbuf2, smblen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT, + smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2540,7 +2552,8 @@ int SMBParserTest09(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2571,7 +2584,8 @@ int SMBParserTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2664,7 +2678,8 @@ int SMBParserTest10(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2684,7 +2699,8 @@ int SMBParserTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT, smbbuf2, smblen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT, + smbbuf2, smblen2); if (r == 0) { printf("smb parser didn't return fail\n"); FLOWLOCK_UNLOCK(&f); diff --git a/src/app-layer-smb2.c b/src/app-layer-smb2.c index 90a369889879..58821cb13d24 100644 --- a/src/app-layer-smb2.c +++ b/src/app-layer-smb2.c @@ -641,7 +641,9 @@ int SMB2ParserTest01(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB2, STREAM_TOSERVER|STREAM_EOF, smb2buf, smb2len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB2, + STREAM_TOSERVER | STREAM_EOF, smb2buf, + smb2len); if (r != 0) { printf("smb2 header check returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 739511a134d3..1224b54adefc 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1798,8 +1798,8 @@ static int SMTPParserTest01(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1820,8 +1820,8 @@ static int SMTPParserTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1838,8 +1838,8 @@ static int SMTPParserTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1855,8 +1855,8 @@ static int SMTPParserTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1873,8 +1873,8 @@ static int SMTPParserTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2157,8 +2157,8 @@ static int SMTPParserTest02(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2179,8 +2179,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2197,8 +2197,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2214,8 +2214,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2232,8 +2232,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2249,8 +2249,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request3, request3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2267,8 +2267,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply3, reply3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2284,8 +2284,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request4, request4_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2302,8 +2302,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply4, reply4_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply4, reply4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2320,8 +2320,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5_1, request5_1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5_1, request5_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2339,8 +2339,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5_2, request5_2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5_2, request5_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2358,8 +2358,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5_3, request5_3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5_3, request5_3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2377,8 +2377,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5_4, request5_4_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5_4, request5_4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2396,8 +2396,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5_5, request5_5_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5_5, request5_5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2414,8 +2414,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply5, reply5_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply5, reply5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2431,8 +2431,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request6, request6_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request6, request6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2449,8 +2449,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply6, reply6_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply6, reply6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2466,8 +2466,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request7, request7_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request7, request7_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2484,8 +2484,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply7, reply7_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply7, reply7_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2501,8 +2501,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request8, request8_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request8, request8_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2519,8 +2519,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply8, reply8_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply8, reply8_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2537,8 +2537,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request9_1, request9_1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request9_1, request9_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2556,8 +2556,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request9_2, request9_2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request9_2, request9_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2575,8 +2575,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request9_3, request9_3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request9_3, request9_3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2594,8 +2594,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request9_4, request9_4_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request9_4, request9_4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2613,8 +2613,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request9_5, request9_5_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request9_5, request9_5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2631,8 +2631,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply9, reply9_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply9, reply9_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2648,8 +2648,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request10, request10_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request10, request10_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2666,8 +2666,8 @@ static int SMTPParserTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply10, reply10_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply10, reply10_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2792,8 +2792,8 @@ static int SMTPParserTest03(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2814,8 +2814,8 @@ static int SMTPParserTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2832,8 +2832,8 @@ static int SMTPParserTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2849,8 +2849,8 @@ static int SMTPParserTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2869,8 +2869,8 @@ static int SMTPParserTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2940,8 +2940,8 @@ static int SMTPParserTest04(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2962,8 +2962,8 @@ static int SMTPParserTest04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3088,8 +3088,8 @@ static int SMTPParserTest05(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3110,8 +3110,8 @@ static int SMTPParserTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3128,8 +3128,8 @@ static int SMTPParserTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3145,8 +3145,8 @@ static int SMTPParserTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3163,8 +3163,8 @@ static int SMTPParserTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3187,8 +3187,8 @@ static int SMTPParserTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request3, request3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3205,8 +3205,8 @@ static int SMTPParserTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply3, reply3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3385,8 +3385,8 @@ static int SMTPParserTest06(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3407,8 +3407,8 @@ static int SMTPParserTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3425,8 +3425,8 @@ static int SMTPParserTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3442,8 +3442,8 @@ static int SMTPParserTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3460,8 +3460,8 @@ static int SMTPParserTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3477,8 +3477,8 @@ static int SMTPParserTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request3, request3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3495,8 +3495,8 @@ static int SMTPParserTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply3, reply3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3512,8 +3512,8 @@ static int SMTPParserTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request4, request4_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3533,8 +3533,8 @@ static int SMTPParserTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5, request5_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5, request5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3553,8 +3553,8 @@ static int SMTPParserTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request6, request6_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request6, request6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3624,8 +3624,8 @@ static int SMTPParserTest07(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_1, request1_1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3648,8 +3648,8 @@ static int SMTPParserTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_2, request1_2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3667,8 +3667,8 @@ static int SMTPParserTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3738,8 +3738,8 @@ static int SMTPParserTest08(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_1, request1_1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3762,8 +3762,8 @@ static int SMTPParserTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_2, request1_2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3781,8 +3781,8 @@ static int SMTPParserTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3852,8 +3852,8 @@ static int SMTPParserTest09(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_1, request1_1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3876,8 +3876,8 @@ static int SMTPParserTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_2, request1_2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3895,8 +3895,8 @@ static int SMTPParserTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3966,8 +3966,8 @@ static int SMTPParserTest10(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_1, request1_1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3990,8 +3990,8 @@ static int SMTPParserTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_2, request1_2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4009,8 +4009,8 @@ static int SMTPParserTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4074,8 +4074,8 @@ static int SMTPParserTest11(void) SMTPTestInitConfig(); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4098,8 +4098,8 @@ static int SMTPParserTest11(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4189,8 +4189,9 @@ static int SMTPParserTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER | STREAM_START, request1, + request1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -4213,8 +4214,9 @@ static int SMTPParserTest12(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT | STREAM_TOCLIENT, - reply1, reply1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT | STREAM_TOCLIENT, reply1, + reply1_len); if (r == 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -4330,8 +4332,9 @@ static int SMTPParserTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER | STREAM_START, request1, + request1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -4354,8 +4357,8 @@ static int SMTPParserTest13(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -4372,8 +4375,8 @@ static int SMTPParserTest13(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -4593,8 +4596,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* Welcome reply */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4615,8 +4618,8 @@ static int SMTPParserTest14(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4634,8 +4637,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* EHLO Reply */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4659,8 +4662,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* MAIL FROM Request */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4678,8 +4681,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* MAIL FROM Reply */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4706,8 +4709,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* RCPT TO Request */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request3, request3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4725,8 +4728,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* RCPT TO Reply */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply3, reply3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4749,8 +4752,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* DATA request */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request4, request4_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4769,8 +4772,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* Data reply */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply4, reply4_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply4, reply4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4788,8 +4791,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* DATA message */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request4_msg, request4_msg_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request4_msg, request4_msg_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4809,8 +4812,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* DATA . request */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request4_end, request4_end_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request4_end, request4_end_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4870,8 +4873,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* DATA . reply */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply4_end, reply4_end_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply4_end, reply4_end_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4888,8 +4891,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* QUIT Request */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5, request5_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5, request5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4907,8 +4910,8 @@ static int SMTPParserTest14(void) FLOWLOCK_WRLOCK(&f); /* QUIT Reply */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply5, reply5_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply5, reply5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index 9d8dff1b7592..7eb529407d7f 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -564,7 +564,8 @@ static int SSHParserTest01(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -632,7 +633,8 @@ static int SSHParserTest02(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -700,7 +702,8 @@ static int SSHParserTest03(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -754,7 +757,8 @@ static int SSHParserTest04(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -822,7 +826,8 @@ static int SSHParserTest05(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -889,7 +894,8 @@ static int SSHParserTest06(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -945,7 +951,8 @@ static int SSHParserTest07(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -954,7 +961,8 @@ static int SSHParserTest07(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1025,7 +1033,8 @@ static int SSHParserTest08(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1034,7 +1043,8 @@ static int SSHParserTest08(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1043,7 +1053,8 @@ static int SSHParserTest08(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1110,7 +1121,8 @@ static int SSHParserTest09(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1119,7 +1131,8 @@ static int SSHParserTest09(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1190,7 +1203,8 @@ static int SSHParserTest10(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1199,7 +1213,8 @@ static int SSHParserTest10(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1208,7 +1223,8 @@ static int SSHParserTest10(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1276,7 +1292,8 @@ static int SSHParserTest11(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1285,7 +1302,8 @@ static int SSHParserTest11(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1360,7 +1378,8 @@ static int SSHParserTest12(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1369,7 +1388,8 @@ static int SSHParserTest12(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1378,7 +1398,8 @@ static int SSHParserTest12(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1454,7 +1475,8 @@ static int SSHParserTest13(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1463,7 +1485,8 @@ static int SSHParserTest13(void) FLOWLOCK_UNLOCK(&f); for (u = 0; u < sshlen2; u++) { FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, &sshbuf2[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, &sshbuf2[u], 1); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1473,7 +1496,8 @@ static int SSHParserTest13(void) } for (u = 0; u < sshlen3; u++) { FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, &sshbuf3[u], 1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, &sshbuf3[u], 1); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1555,7 +1579,8 @@ static int SSHParserTest14(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1563,7 +1588,8 @@ static int SSHParserTest14(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1571,7 +1597,8 @@ static int SSHParserTest14(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1579,7 +1606,8 @@ static int SSHParserTest14(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1587,7 +1615,8 @@ static int SSHParserTest14(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf5, sshlen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf5, sshlen5); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1669,7 +1698,8 @@ static int SSHParserTest15(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1677,7 +1707,8 @@ static int SSHParserTest15(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1685,7 +1716,8 @@ static int SSHParserTest15(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1693,7 +1725,8 @@ static int SSHParserTest15(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1701,7 +1734,8 @@ static int SSHParserTest15(void) } FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf5, sshlen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf5, sshlen5); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1776,7 +1810,8 @@ static int SSHParserTest16(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1785,7 +1820,8 @@ static int SSHParserTest16(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1794,7 +1830,8 @@ static int SSHParserTest16(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1871,7 +1908,8 @@ static int SSHParserTest17(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1880,7 +1918,8 @@ static int SSHParserTest17(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1889,7 +1928,8 @@ static int SSHParserTest17(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1898,7 +1938,8 @@ static int SSHParserTest17(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1983,7 +2024,8 @@ static int SSHParserTest18(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, server1, serverlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, server1, serverlen1); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1992,7 +2034,8 @@ static int SSHParserTest18(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2001,7 +2044,8 @@ static int SSHParserTest18(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2010,7 +2054,8 @@ static int SSHParserTest18(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, server2, serverlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + server2, serverlen2); if (r != 0) { printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2019,7 +2064,8 @@ static int SSHParserTest18(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2091,7 +2137,8 @@ static int SSHParserTest19(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2100,7 +2147,8 @@ static int SSHParserTest19(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2109,7 +2157,8 @@ static int SSHParserTest19(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2118,7 +2167,8 @@ static int SSHParserTest19(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2213,7 +2263,8 @@ static int SSHParserTest20(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2222,7 +2273,8 @@ static int SSHParserTest20(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2231,7 +2283,8 @@ static int SSHParserTest20(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2241,7 +2294,8 @@ static int SSHParserTest20(void) SCLogDebug("chunk 4:"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2322,7 +2376,8 @@ static int SSHParserTest21(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2331,7 +2386,8 @@ static int SSHParserTest21(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2340,7 +2396,8 @@ static int SSHParserTest21(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2350,7 +2407,8 @@ static int SSHParserTest21(void) SCLogDebug("chunk 4:"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2459,7 +2517,8 @@ static int SSHParserTest22(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2468,7 +2527,8 @@ static int SSHParserTest22(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2477,7 +2537,8 @@ static int SSHParserTest22(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2553,7 +2614,8 @@ static int SSHParserTest23(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toclient chunk 1 returned 0 expected non null: "); FLOWLOCK_UNLOCK(&f); @@ -2588,7 +2650,8 @@ static int SSHParserTest24(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 3b75427c9086..79b0368d3e53 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -1846,7 +1846,8 @@ static int SSLParserTest01(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_EOF, tlsbuf, tlslen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER | STREAM_EOF, tlsbuf, tlslen); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -1884,12 +1885,14 @@ static int SSLParserTest02(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -1929,17 +1932,20 @@ static int SSLParserTest03(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf3, tlslen3); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -1981,22 +1987,26 @@ static int SSLParserTest04(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf3, tlslen3); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf4, tlslen4); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -2296,7 +2306,8 @@ static int SSLParserMultimsgTest01(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -2359,7 +2370,8 @@ static int SSLParserMultimsgTest02(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf1, tlslen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOCLIENT, tlsbuf1, tlslen1); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -2407,7 +2419,8 @@ static int SSLParserTest07(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf, tlslen); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -2572,12 +2585,14 @@ static int SSLParserTest09(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -2632,12 +2647,14 @@ static int SSLParserTest10(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -2691,12 +2708,14 @@ static int SSLParserTest11(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -2755,17 +2774,20 @@ static int SSLParserTest12(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf3, buf3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf3, buf3_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -2829,22 +2851,26 @@ static int SSLParserTest13(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf3, buf3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf3, buf3_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf4, buf4_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf4, buf4_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -2891,12 +2917,14 @@ static int SSLParserTest14(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -2934,7 +2962,8 @@ static int SSLParserTest15(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r == 0); @@ -2969,7 +2998,8 @@ static int SSLParserTest16(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r == 0); @@ -3004,7 +3034,8 @@ static int SSLParserTest17(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r == 0); @@ -3045,12 +3076,14 @@ static int SSLParserTest18(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -3089,7 +3122,8 @@ static int SSLParserTest19(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -3128,7 +3162,8 @@ static int SSLParserTest20(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r == 0); @@ -3164,8 +3199,8 @@ static int SSLParserTest21(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_EOF, buf, - buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER | STREAM_EOF, buf, buf_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -3213,8 +3248,8 @@ static int SSLParserTest22(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT | STREAM_EOF, buf, - buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOCLIENT | STREAM_EOF, buf, buf_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -3498,7 +3533,8 @@ static int SSLParserTest23(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_START, chello_buf, + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER | STREAM_START, chello_buf, chello_buf_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -3515,8 +3551,8 @@ static int SSLParserTest23(void) FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, - shello_buf_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + shello_buf, shello_buf_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -3530,7 +3566,8 @@ static int SSLParserTest23(void) FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_change_cipher_spec_buf, client_change_cipher_spec_buf_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -3550,7 +3587,8 @@ static int SSLParserTest23(void) FAIL_IF((app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_change_cipher_spec_buf, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_change_cipher_spec_buf, server_change_cipher_spec_buf_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -3571,8 +3609,8 @@ static int SSLParserTest23(void) FAIL_IF((app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, toserver_app_data_buf, - toserver_app_data_buf_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + toserver_app_data_buf, toserver_app_data_buf_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -3640,12 +3678,14 @@ static int SSLParserTest24(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -3995,7 +4035,9 @@ static int SSLParserTest25(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, client_hello_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, client_hello, + client_hello_len); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -4006,7 +4048,7 @@ static int SSLParserTest25(void) FAIL_IF(ssl_state->client_connp.hs_bytes_processed != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello_certificate_done, server_hello_certificate_done_len); FLOWLOCK_UNLOCK(&f); @@ -4016,7 +4058,7 @@ static int SSLParserTest25(void) FAIL_IF(ssl_state->client_connp.hs_bytes_processed != 0); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_key_exchange_cipher_enc_hs, client_key_exchange_cipher_enc_hs_len); FLOWLOCK_UNLOCK(&f); diff --git a/src/app-layer.c b/src/app-layer.c index ef4038b28eef..f88e095fff04 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -297,7 +297,9 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; PACKET_PROFILING_APP_START(app_tctx, *alproto); - r = AppLayerParserParse(app_tctx->alp_tctx, f, *alproto, flags, data + data_al_so_far, data_len - data_al_so_far); + r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, *alproto, + flags, data + data_al_so_far, + data_len - data_al_so_far); PACKET_PROFILING_APP_END(app_tctx, *alproto); f->data_al_so_far[dir] = 0; } else { @@ -354,8 +356,10 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; PACKET_PROFILING_APP_START(app_tctx, *alproto_otherdir); - r = AppLayerParserParse(app_tctx->alp_tctx, f, *alproto_otherdir, flags, - data + data_al_so_far, data_len - data_al_so_far); + r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, + *alproto_otherdir, flags, + data + data_al_so_far, + data_len - data_al_so_far); PACKET_PROFILING_APP_END(app_tctx, *alproto_otherdir); if (FLOW_IS_PM_DONE(f, flags) && FLOW_IS_PP_DONE(f, flags)) { AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, @@ -464,7 +468,8 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, * a start msg should have gotten us one */ if (f->alproto != ALPROTO_UNKNOWN) { PACKET_PROFILING_APP_START(app_tctx, f->alproto); - r = AppLayerParserParse(app_tctx->alp_tctx, f, f->alproto, flags, data, data_len); + r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, f->alproto, + flags, data, data_len); PACKET_PROFILING_APP_END(app_tctx, f->alproto); } else { SCLogDebug(" smsg not start, but no l7 data? Weird"); @@ -523,9 +528,8 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * AppLayerIncFlowCounter(tv, f); PACKET_PROFILING_APP_START(tctx, f->alproto); - r = AppLayerParserParse(tctx->alp_tctx, - f, f->alproto, flags, - p->payload, p->payload_len); + r = AppLayerParserParse(tv, tctx->alp_tctx, f, f->alproto, + flags, p->payload, p->payload_len); PACKET_PROFILING_APP_END(tctx, f->alproto); } else { f->flags |= FLOW_ALPROTO_DETECT_DONE; @@ -539,9 +543,8 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * * a start msg should have gotten us one */ if (f->alproto != ALPROTO_UNKNOWN) { PACKET_PROFILING_APP_START(tctx, f->alproto); - r = AppLayerParserParse(tctx->alp_tctx, - f, f->alproto, flags, - p->payload, p->payload_len); + r = AppLayerParserParse(tv, tctx->alp_tctx, f, f->alproto, + flags, p->payload, p->payload_len); PACKET_PROFILING_APP_END(tctx, f->alproto); } else { SCLogDebug("udp session has started, but failed to detect alproto " diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 10cf7f5e6b70..10e79d399f64 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -895,8 +895,9 @@ static int DetectDceIfaceTestParse12(void) SCLogDebug("handling to_server chunk"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -921,7 +922,8 @@ static int DetectDceIfaceTestParse12(void) SCLogDebug("handling to_client chunk"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -939,7 +941,8 @@ static int DetectDceIfaceTestParse12(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_request, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1401,8 +1404,9 @@ static int DetectDceIfaceTestParse14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1423,7 +1427,8 @@ static int DetectDceIfaceTestParse14(void) goto end; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1441,7 +1446,8 @@ static int DetectDceIfaceTestParse14(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_request, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1611,8 +1617,9 @@ static int DetectDceIfaceTestParse15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1635,7 +1642,8 @@ static int DetectDceIfaceTestParse15(void) goto end; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1657,7 +1665,8 @@ static int DetectDceIfaceTestParse15(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_alter_context, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_alter_context, dcerpc_alter_context_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1679,7 +1688,8 @@ static int DetectDceIfaceTestParse15(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_alter_context_resp, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_alter_context_resp, dcerpc_alter_context_resp_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1701,7 +1711,8 @@ static int DetectDceIfaceTestParse15(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1723,7 +1734,8 @@ static int DetectDceIfaceTestParse15(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1745,7 +1757,8 @@ static int DetectDceIfaceTestParse15(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index f5d3f1d55ee6..023e643b9f0b 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -1161,8 +1161,9 @@ static int DetectDceOpnumTestParse08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1177,8 +1178,9 @@ static int DetectDceOpnumTestParse08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - dcerpc_bindack, dcerpc_bindack_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, + dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1187,8 +1189,9 @@ static int DetectDceOpnumTestParse08(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_EOF, - dcerpc_request, dcerpc_request_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_EOF, dcerpc_request, + dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1700,8 +1703,9 @@ static int DetectDceOpnumTestParse09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_request, dcerpc_request_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_request, + dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index d39ed2778696..ea47be1efca9 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -621,8 +621,9 @@ static int DetectDceStubDataTestParse02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -647,7 +648,8 @@ static int DetectDceStubDataTestParse02(void) /* do detect */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -666,8 +668,9 @@ static int DetectDceStubDataTestParse02(void) goto end; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_EOF, - dcerpc_request, dcerpc_request_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_EOF, dcerpc_request, + dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1176,8 +1179,9 @@ static int DetectDceStubDataTestParse03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_request, dcerpc_request_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_request, + dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1382,8 +1386,9 @@ static int DetectDceStubDataTestParse04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1401,7 +1406,8 @@ static int DetectDceStubDataTestParse04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1415,7 +1421,8 @@ static int DetectDceStubDataTestParse04(void) /* request1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1434,7 +1441,8 @@ static int DetectDceStubDataTestParse04(void) /* response1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1453,7 +1461,8 @@ static int DetectDceStubDataTestParse04(void) /* request2 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1472,7 +1481,8 @@ static int DetectDceStubDataTestParse04(void) /* response2 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_response2, dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1491,7 +1501,8 @@ static int DetectDceStubDataTestParse04(void) /* request3 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request3, dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); @@ -1510,8 +1521,9 @@ static int DetectDceStubDataTestParse04(void) /* response3 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, - dcerpc_response3, dcerpc_response3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, + dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1693,8 +1705,9 @@ static int DetectDceStubDataTestParse05(void) /* request1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_request1, dcerpc_request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_request1, + dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1718,8 +1731,9 @@ static int DetectDceStubDataTestParse05(void) /* response1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - dcerpc_response1, dcerpc_response1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_response1, + dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1737,8 +1751,9 @@ static int DetectDceStubDataTestParse05(void) /* request2 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - dcerpc_request2, dcerpc_request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request2, + dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1756,8 +1771,9 @@ static int DetectDceStubDataTestParse05(void) /* response2 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - dcerpc_response2, dcerpc_response2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_response2, + dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1775,8 +1791,9 @@ static int DetectDceStubDataTestParse05(void) /* request3 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - dcerpc_request3, dcerpc_request3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request3, + dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); @@ -1794,8 +1811,9 @@ static int DetectDceStubDataTestParse05(void) /* response3 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, - dcerpc_response3, dcerpc_response3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, + dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 2463fd2e94b7..ee49592872e1 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -150,7 +150,8 @@ static int DetectDnsQueryTest01(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -288,7 +289,8 @@ static int DetectDnsQueryTest02(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -315,7 +317,8 @@ static int DetectDnsQueryTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf2, sizeof(buf2)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, + buf2, sizeof(buf2)); if (r != 0) { printf("toserver client 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -336,7 +339,8 @@ static int DetectDnsQueryTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf3, sizeof(buf3)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, + buf3, sizeof(buf3)); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -434,7 +438,8 @@ static int DetectDnsQueryTest03(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -540,7 +545,8 @@ static int DetectDnsQueryTest04(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -563,7 +569,8 @@ static int DetectDnsQueryTest04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf2, sizeof(buf2)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, + buf2, sizeof(buf2)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -710,7 +717,8 @@ static int DetectDnsQueryTest05(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -737,7 +745,8 @@ static int DetectDnsQueryTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf2, sizeof(buf2)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, + buf2, sizeof(buf2)); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -758,7 +767,8 @@ static int DetectDnsQueryTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf3, sizeof(buf3)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, + buf3, sizeof(buf3)); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -779,7 +789,8 @@ static int DetectDnsQueryTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf4, sizeof(buf4)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, + buf4, sizeof(buf4)); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -882,7 +893,8 @@ static int DetectDnsQueryTest06(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1031,7 +1043,8 @@ static int DetectDnsQueryTest07(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1058,7 +1071,8 @@ static int DetectDnsQueryTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf2, sizeof(buf2)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, + buf2, sizeof(buf2)); if (r != -1) { printf("toserver client 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1083,7 +1097,8 @@ static int DetectDnsQueryTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf3, sizeof(buf3)); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, + buf3, sizeof(buf3)); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index 79182f41ca74..44fc98d94209 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -6539,7 +6539,8 @@ int DcePayloadTest15(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -6655,7 +6656,8 @@ int DcePayloadTest16(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -6771,7 +6773,8 @@ int DcePayloadTest17(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -6887,7 +6890,8 @@ int DcePayloadTest18(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -7003,7 +7007,8 @@ int DcePayloadTest19(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -7119,7 +7124,8 @@ int DcePayloadTest20(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -7224,7 +7230,8 @@ int DcePayloadTest21(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -7325,7 +7332,8 @@ int DcePayloadTest22(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -7427,7 +7435,8 @@ int DcePayloadTest23(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -9643,7 +9652,8 @@ int DcePayloadTest42(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -9745,7 +9755,8 @@ int DcePayloadTest43(void) /* request 1 */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 45b2e80a6066..4e65b8ce43d1 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -373,7 +373,10 @@ static int DetectEngineSMTPFiledataTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, mimemsg, mimemsg_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + mimemsg, + mimemsg_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %d", r); FLOWLOCK_UNLOCK(&f); @@ -506,13 +509,15 @@ static int DetectEngineSMTPFiledataTest03(void) FLOWLOCK_WRLOCK(&f); int r = 0; - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, mimemsg1, mimemsg1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, mimemsg1, mimemsg1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %d", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, mimemsg2, mimemsg2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, mimemsg2, mimemsg2_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %d", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 1e25976158d1..c0016f9b18b6 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -386,9 +386,9 @@ static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml) p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, b->direction, - (uint8_t *)b->input, - b->input_size ? b->input_size : strlen((const char *)b->input)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + b->direction, (uint8_t *)b->input, + b->input_size ? b->input_size : strlen((const char *)b->input)); if (r != 0) { printf("toserver chunk %d returned %" PRId32 ", expected 0: ", i+1, r); result = 0; diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index 6217a3bff82c..f783af0d25bf 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -250,7 +250,8 @@ static int DetectEngineHttpCookieTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -348,7 +349,8 @@ static int DetectEngineHttpCookieTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -446,7 +448,8 @@ static int DetectEngineHttpCookieTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -544,7 +547,8 @@ static int DetectEngineHttpCookieTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -642,7 +646,8 @@ static int DetectEngineHttpCookieTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -740,7 +745,8 @@ static int DetectEngineHttpCookieTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -838,7 +844,8 @@ static int DetectEngineHttpCookieTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -936,7 +943,8 @@ static int DetectEngineHttpCookieTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1034,7 +1042,8 @@ static int DetectEngineHttpCookieTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1133,7 +1142,8 @@ static int DetectEngineHttpCookieTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1232,7 +1242,8 @@ static int DetectEngineHttpCookieTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1331,7 +1342,8 @@ static int DetectEngineHttpCookieTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1430,7 +1442,8 @@ static int DetectEngineHttpCookieTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1529,7 +1542,8 @@ static int DetectEngineHttpCookieTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1628,7 +1642,8 @@ static int DetectEngineHttpCookieTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1727,7 +1742,8 @@ static int DetectEngineHttpCookieTest16(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1826,7 +1842,8 @@ static int DetectEngineHttpCookieTest17(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 6d05b2837caa..228189135657 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -385,7 +385,8 @@ static int DetectEngineHttpHeaderTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -481,7 +482,8 @@ static int DetectEngineHttpHeaderTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -577,7 +579,8 @@ static int DetectEngineHttpHeaderTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -673,7 +676,8 @@ static int DetectEngineHttpHeaderTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -769,7 +773,8 @@ static int DetectEngineHttpHeaderTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -865,7 +870,8 @@ static int DetectEngineHttpHeaderTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -961,7 +967,8 @@ static int DetectEngineHttpHeaderTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1057,7 +1064,8 @@ static int DetectEngineHttpHeaderTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1153,7 +1161,8 @@ static int DetectEngineHttpHeaderTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1249,7 +1258,8 @@ static int DetectEngineHttpHeaderTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1345,7 +1355,8 @@ static int DetectEngineHttpHeaderTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1441,7 +1452,8 @@ static int DetectEngineHttpHeaderTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1537,7 +1549,8 @@ static int DetectEngineHttpHeaderTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1633,7 +1646,8 @@ static int DetectEngineHttpHeaderTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1729,7 +1743,8 @@ static int DetectEngineHttpHeaderTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1825,7 +1840,8 @@ static int DetectEngineHttpHeaderTest16(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1921,7 +1937,8 @@ static int DetectEngineHttpHeaderTest17(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2175,7 +2192,8 @@ static int DetectEngineHttpHeaderTest20(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2200,7 +2218,8 @@ static int DetectEngineHttpHeaderTest20(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2299,7 +2318,8 @@ static int DetectEngineHttpHeaderTest21(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2324,7 +2344,8 @@ static int DetectEngineHttpHeaderTest21(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2423,7 +2444,8 @@ static int DetectEngineHttpHeaderTest22(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2448,7 +2470,8 @@ static int DetectEngineHttpHeaderTest22(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2547,7 +2570,8 @@ static int DetectEngineHttpHeaderTest23(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2572,7 +2596,8 @@ static int DetectEngineHttpHeaderTest23(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2671,7 +2696,8 @@ static int DetectEngineHttpHeaderTest24(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2696,7 +2722,8 @@ static int DetectEngineHttpHeaderTest24(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2795,7 +2822,8 @@ static int DetectEngineHttpHeaderTest25(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2820,7 +2848,8 @@ static int DetectEngineHttpHeaderTest25(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2919,7 +2948,8 @@ static int DetectEngineHttpHeaderTest26(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2944,7 +2974,8 @@ static int DetectEngineHttpHeaderTest26(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3043,7 +3074,8 @@ static int DetectEngineHttpHeaderTest27(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3068,7 +3100,8 @@ static int DetectEngineHttpHeaderTest27(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3171,8 +3204,8 @@ static int DetectEngineHttpHeaderTest28(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, - http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3197,7 +3230,8 @@ static int DetectEngineHttpHeaderTest28(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3300,8 +3334,8 @@ static int DetectEngineHttpHeaderTest29(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, - http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3326,7 +3360,8 @@ static int DetectEngineHttpHeaderTest29(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3462,8 +3497,8 @@ static int DetectEngineHttpHeaderTest30(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, - http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3488,7 +3523,8 @@ static int DetectEngineHttpHeaderTest30(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3584,7 +3620,8 @@ static int DetectEngineHttpHeaderTest31(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3687,7 +3724,8 @@ static int DetectEngineHttpHeaderTest32(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3798,7 +3836,8 @@ static int DetectEngineHttpHeaderTest33(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3823,7 +3862,8 @@ static int DetectEngineHttpHeaderTest33(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index b3ab4aa893c7..43af0b9e9a29 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -215,7 +215,8 @@ static int DetectEngineHttpHHTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -313,7 +314,8 @@ static int DetectEngineHttpHHTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -411,7 +413,8 @@ static int DetectEngineHttpHHTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -509,7 +512,8 @@ static int DetectEngineHttpHHTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -607,7 +611,8 @@ static int DetectEngineHttpHHTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -705,7 +710,8 @@ static int DetectEngineHttpHHTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -803,7 +809,8 @@ static int DetectEngineHttpHHTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -901,7 +908,8 @@ static int DetectEngineHttpHHTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -999,7 +1007,8 @@ static int DetectEngineHttpHHTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1098,7 +1107,8 @@ static int DetectEngineHttpHHTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1197,7 +1207,8 @@ static int DetectEngineHttpHHTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1296,7 +1307,8 @@ static int DetectEngineHttpHHTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1395,7 +1407,8 @@ static int DetectEngineHttpHHTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1494,7 +1507,8 @@ static int DetectEngineHttpHHTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1593,7 +1607,8 @@ static int DetectEngineHttpHHTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1692,7 +1707,8 @@ static int DetectEngineHttpHHTest16(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1791,7 +1807,8 @@ static int DetectEngineHttpHHTest17(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1885,7 +1902,8 @@ static int DetectEngineHttpHHTest18(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1979,7 +1997,8 @@ static int DetectEngineHttpHHTest19(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2073,7 +2092,8 @@ static int DetectEngineHttpHHTest20(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2166,7 +2186,8 @@ static int DetectEngineHttpHHTest21(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2259,7 +2280,8 @@ static int DetectEngineHttpHHTest22(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2352,7 +2374,8 @@ static int DetectEngineHttpHHTest23(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2446,7 +2469,8 @@ static int DetectEngineHttpHHTest24(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2540,7 +2564,8 @@ static int DetectEngineHttpHHTest25(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 924db480fea9..64d63cae4e2c 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -206,7 +206,8 @@ static int DetectEngineHttpMethodTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -303,7 +304,8 @@ static int DetectEngineHttpMethodTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -400,7 +402,8 @@ static int DetectEngineHttpMethodTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -497,7 +500,8 @@ static int DetectEngineHttpMethodTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -594,7 +598,8 @@ static int DetectEngineHttpMethodTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -691,7 +696,8 @@ static int DetectEngineHttpMethodTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -788,7 +794,8 @@ static int DetectEngineHttpMethodTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -885,7 +892,8 @@ static int DetectEngineHttpMethodTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -982,7 +990,8 @@ static int DetectEngineHttpMethodTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1080,7 +1089,8 @@ static int DetectEngineHttpMethodTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1178,7 +1188,8 @@ static int DetectEngineHttpMethodTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1276,7 +1287,8 @@ static int DetectEngineHttpMethodTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1374,7 +1386,8 @@ static int DetectEngineHttpMethodTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1472,7 +1485,8 @@ static int DetectEngineHttpMethodTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1570,7 +1584,8 @@ static int DetectEngineHttpMethodTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1668,7 +1683,8 @@ static int DetectEngineHttpMethodTest16(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1766,7 +1782,8 @@ static int DetectEngineHttpMethodTest17(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 9c757a9dd25c..496f9b5b4f48 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -257,7 +257,8 @@ static int DetectEngineHttpRawHeaderTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -353,7 +354,8 @@ static int DetectEngineHttpRawHeaderTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -449,7 +451,8 @@ static int DetectEngineHttpRawHeaderTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -545,7 +548,8 @@ static int DetectEngineHttpRawHeaderTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -641,7 +645,8 @@ static int DetectEngineHttpRawHeaderTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -737,7 +742,8 @@ static int DetectEngineHttpRawHeaderTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -833,7 +839,8 @@ static int DetectEngineHttpRawHeaderTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -929,7 +936,8 @@ static int DetectEngineHttpRawHeaderTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1025,7 +1033,8 @@ static int DetectEngineHttpRawHeaderTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1121,7 +1130,8 @@ static int DetectEngineHttpRawHeaderTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1217,7 +1227,8 @@ static int DetectEngineHttpRawHeaderTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1313,7 +1324,8 @@ static int DetectEngineHttpRawHeaderTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1409,7 +1421,8 @@ static int DetectEngineHttpRawHeaderTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1505,7 +1518,8 @@ static int DetectEngineHttpRawHeaderTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1601,7 +1615,8 @@ static int DetectEngineHttpRawHeaderTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1697,7 +1712,8 @@ static int DetectEngineHttpRawHeaderTest16(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1793,7 +1809,8 @@ static int DetectEngineHttpRawHeaderTest17(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2047,7 +2064,8 @@ static int DetectEngineHttpRawHeaderTest20(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2072,7 +2090,8 @@ static int DetectEngineHttpRawHeaderTest20(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2171,7 +2190,8 @@ static int DetectEngineHttpRawHeaderTest21(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2196,7 +2216,8 @@ static int DetectEngineHttpRawHeaderTest21(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2295,7 +2316,8 @@ static int DetectEngineHttpRawHeaderTest22(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2320,7 +2342,8 @@ static int DetectEngineHttpRawHeaderTest22(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2419,7 +2442,8 @@ static int DetectEngineHttpRawHeaderTest23(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2444,7 +2468,8 @@ static int DetectEngineHttpRawHeaderTest23(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2543,7 +2568,8 @@ static int DetectEngineHttpRawHeaderTest24(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2568,7 +2594,8 @@ static int DetectEngineHttpRawHeaderTest24(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2667,7 +2694,8 @@ static int DetectEngineHttpRawHeaderTest25(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2692,7 +2720,8 @@ static int DetectEngineHttpRawHeaderTest25(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2791,7 +2820,8 @@ static int DetectEngineHttpRawHeaderTest26(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2816,7 +2846,8 @@ static int DetectEngineHttpRawHeaderTest26(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2913,7 +2944,8 @@ static int DetectEngineHttpRawHeaderTest27(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2938,7 +2970,8 @@ static int DetectEngineHttpRawHeaderTest27(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3041,8 +3074,8 @@ static int DetectEngineHttpRawHeaderTest28(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, - http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3067,7 +3100,8 @@ static int DetectEngineHttpRawHeaderTest28(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3170,8 +3204,8 @@ static int DetectEngineHttpRawHeaderTest29(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, - http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3196,7 +3230,8 @@ static int DetectEngineHttpRawHeaderTest29(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3326,7 +3361,8 @@ static int DetectEngineHttpRawHeaderTest31(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3438,7 +3474,8 @@ static int DetectEngineHttpRawHeaderTest32(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3463,7 +3500,8 @@ static int DetectEngineHttpRawHeaderTest32(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index c5a51d63510f..b0a9f1134adc 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -243,7 +243,8 @@ static int DetectEngineHttpHRHTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -341,7 +342,8 @@ static int DetectEngineHttpHRHTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -439,7 +441,8 @@ static int DetectEngineHttpHRHTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -537,7 +540,8 @@ static int DetectEngineHttpHRHTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -635,7 +639,8 @@ static int DetectEngineHttpHRHTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -733,7 +738,8 @@ static int DetectEngineHttpHRHTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -831,7 +837,8 @@ static int DetectEngineHttpHRHTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -929,7 +936,8 @@ static int DetectEngineHttpHRHTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1027,7 +1035,8 @@ static int DetectEngineHttpHRHTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1126,7 +1135,8 @@ static int DetectEngineHttpHRHTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1225,7 +1235,8 @@ static int DetectEngineHttpHRHTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1324,7 +1335,8 @@ static int DetectEngineHttpHRHTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1423,7 +1435,8 @@ static int DetectEngineHttpHRHTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1522,7 +1535,8 @@ static int DetectEngineHttpHRHTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1621,7 +1635,8 @@ static int DetectEngineHttpHRHTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1720,7 +1735,8 @@ static int DetectEngineHttpHRHTest16(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1819,7 +1835,8 @@ static int DetectEngineHttpHRHTest17(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1913,7 +1930,8 @@ static int DetectEngineHttpHRHTest18(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2007,7 +2025,8 @@ static int DetectEngineHttpHRHTest19(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2101,7 +2120,8 @@ static int DetectEngineHttpHRHTest20(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2194,7 +2214,8 @@ static int DetectEngineHttpHRHTest21(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2287,7 +2308,8 @@ static int DetectEngineHttpHRHTest22(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2380,7 +2402,8 @@ static int DetectEngineHttpHRHTest23(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2474,7 +2497,8 @@ static int DetectEngineHttpHRHTest24(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2568,7 +2592,8 @@ static int DetectEngineHttpHRHTest25(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-engine-hrl.c b/src/detect-engine-hrl.c index 09b3fa98227c..30dd06441f6b 100644 --- a/src/detect-engine-hrl.c +++ b/src/detect-engine-hrl.c @@ -162,7 +162,8 @@ static int UriTestSig01(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -187,7 +188,8 @@ static int UriTestSig01(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -284,7 +286,8 @@ static int UriTestSig02(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -309,7 +312,8 @@ static int UriTestSig02(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -406,7 +410,8 @@ static int UriTestSig03(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -431,7 +436,8 @@ static int UriTestSig03(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -528,7 +534,8 @@ static int UriTestSig04(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -553,7 +560,8 @@ static int UriTestSig04(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -650,7 +658,8 @@ static int UriTestSig05(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -675,7 +684,8 @@ static int UriTestSig05(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -772,7 +782,8 @@ static int UriTestSig06(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -797,7 +808,8 @@ static int UriTestSig06(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -894,7 +906,8 @@ static int UriTestSig07(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -919,7 +932,8 @@ static int UriTestSig07(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1016,7 +1030,8 @@ static int UriTestSig08(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1041,7 +1056,8 @@ static int UriTestSig08(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1138,7 +1154,8 @@ static int UriTestSig09(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1163,7 +1180,8 @@ static int UriTestSig09(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1260,7 +1278,8 @@ static int UriTestSig10(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1285,7 +1304,8 @@ static int UriTestSig10(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1383,7 +1403,8 @@ static int UriTestSig11(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1408,7 +1429,8 @@ static int UriTestSig11(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1506,7 +1528,8 @@ static int UriTestSig12(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1531,7 +1554,8 @@ static int UriTestSig12(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1628,7 +1652,8 @@ static int UriTestSig13(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1653,7 +1678,8 @@ static int UriTestSig13(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1751,7 +1777,8 @@ static int UriTestSig14(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1776,7 +1803,8 @@ static int UriTestSig14(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1874,7 +1902,8 @@ static int UriTestSig15(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1899,7 +1928,8 @@ static int UriTestSig15(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1995,7 +2025,8 @@ static int UriTestSig16(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2023,7 +2054,8 @@ static int UriTestSig16(void) p->payload_len = http_buf2_len; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2118,7 +2150,8 @@ static int UriTestSig17(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2213,7 +2246,8 @@ static int UriTestSig18(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2309,7 +2343,8 @@ static int UriTestSig19(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2404,7 +2439,8 @@ static int UriTestSig20(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2498,7 +2534,8 @@ static int UriTestSig21(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2592,7 +2629,8 @@ static int UriTestSig22(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2685,7 +2723,8 @@ static int UriTestSig23(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2778,7 +2817,8 @@ static int UriTestSig24(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2871,7 +2911,8 @@ static int UriTestSig25(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2964,7 +3005,8 @@ static int UriTestSig26(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3057,7 +3099,8 @@ static int UriTestSig27(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3184,7 +3227,8 @@ static int UriTestSig28(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3276,7 +3320,8 @@ static int UriTestSig29(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3368,7 +3413,8 @@ static int UriTestSig30(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3460,7 +3506,8 @@ static int UriTestSig31(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3552,7 +3599,8 @@ static int UriTestSig32(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3642,7 +3690,8 @@ static int UriTestSig33(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3732,7 +3781,8 @@ static int UriTestSig34(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3822,7 +3872,8 @@ static int UriTestSig35(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3912,7 +3963,8 @@ static int UriTestSig36(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4002,7 +4054,8 @@ static int UriTestSig37(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4092,7 +4145,8 @@ static int UriTestSig38(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 5f83b3508275..383669301c9d 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -226,7 +226,8 @@ static int DetectEngineHttpRawUriTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -251,7 +252,8 @@ static int DetectEngineHttpRawUriTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -350,7 +352,8 @@ static int DetectEngineHttpRawUriTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -460,7 +463,8 @@ static int DetectEngineHttpRawUriTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -485,7 +489,8 @@ static int DetectEngineHttpRawUriTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -588,7 +593,8 @@ static int DetectEngineHttpRawUriTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -613,7 +619,8 @@ static int DetectEngineHttpRawUriTest04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -715,7 +722,8 @@ static int DetectEngineHttpRawUriTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -740,7 +748,8 @@ static int DetectEngineHttpRawUriTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -842,7 +851,8 @@ static int DetectEngineHttpRawUriTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -867,7 +877,8 @@ static int DetectEngineHttpRawUriTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -969,7 +980,8 @@ static int DetectEngineHttpRawUriTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -994,7 +1006,8 @@ static int DetectEngineHttpRawUriTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1096,7 +1109,8 @@ static int DetectEngineHttpRawUriTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1121,7 +1135,8 @@ static int DetectEngineHttpRawUriTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1224,7 +1239,8 @@ static int DetectEngineHttpRawUriTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1249,7 +1265,8 @@ static int DetectEngineHttpRawUriTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1352,7 +1369,8 @@ static int DetectEngineHttpRawUriTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1377,7 +1395,8 @@ static int DetectEngineHttpRawUriTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1480,7 +1499,8 @@ static int DetectEngineHttpRawUriTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1505,7 +1525,8 @@ static int DetectEngineHttpRawUriTest11(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1608,7 +1629,8 @@ static int DetectEngineHttpRawUriTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1633,7 +1655,8 @@ static int DetectEngineHttpRawUriTest12(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1736,7 +1759,8 @@ static int DetectEngineHttpRawUriTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1761,7 +1785,8 @@ static int DetectEngineHttpRawUriTest13(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1864,7 +1889,8 @@ static int DetectEngineHttpRawUriTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1889,7 +1915,8 @@ static int DetectEngineHttpRawUriTest14(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1992,7 +2019,8 @@ static int DetectEngineHttpRawUriTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2017,7 +2045,8 @@ static int DetectEngineHttpRawUriTest15(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2120,7 +2149,8 @@ static int DetectEngineHttpRawUriTest16(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2145,7 +2175,8 @@ static int DetectEngineHttpRawUriTest16(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2536,7 +2567,8 @@ static int DetectEngineHttpRawUriTest21(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2561,7 +2593,8 @@ static int DetectEngineHttpRawUriTest21(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2664,7 +2697,8 @@ static int DetectEngineHttpRawUriTest22(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2689,7 +2723,8 @@ static int DetectEngineHttpRawUriTest22(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2792,7 +2827,8 @@ static int DetectEngineHttpRawUriTest23(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2817,7 +2853,8 @@ static int DetectEngineHttpRawUriTest23(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2920,7 +2957,8 @@ static int DetectEngineHttpRawUriTest24(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2945,7 +2983,8 @@ static int DetectEngineHttpRawUriTest24(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3048,7 +3087,8 @@ static int DetectEngineHttpRawUriTest25(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3073,7 +3113,8 @@ static int DetectEngineHttpRawUriTest25(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3176,7 +3217,8 @@ static int DetectEngineHttpRawUriTest26(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3201,7 +3243,8 @@ static int DetectEngineHttpRawUriTest26(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3304,7 +3347,8 @@ static int DetectEngineHttpRawUriTest27(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3329,7 +3373,8 @@ static int DetectEngineHttpRawUriTest27(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3432,7 +3477,8 @@ static int DetectEngineHttpRawUriTest28(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3457,7 +3503,8 @@ static int DetectEngineHttpRawUriTest28(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3547,7 +3594,8 @@ static int DetectEngineHttpRawUriTest29(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3640,7 +3688,8 @@ static int DetectEngineHttpRawUriTest30(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 298f5947757a..694fabe5ef9f 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -393,9 +393,9 @@ static int RunTest(struct TestSteps *steps, const char *sig, const char *yaml) p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, b->direction, - (uint8_t *)b->input, - b->input_size ? b->input_size : strlen((const char *)b->input)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + b->direction, (uint8_t *)b->input, + b->input_size ? b->input_size : strlen((const char *)b->input)); if (r != 0) { printf("toserver chunk %d returned %" PRId32 ", expected 0: ", i+1, r); result = 0; @@ -509,7 +509,8 @@ static int DetectEngineHttpServerBodyTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -534,7 +535,8 @@ static int DetectEngineHttpServerBodyTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -631,7 +633,8 @@ static int DetectEngineHttpServerBodyTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -641,7 +644,8 @@ static int DetectEngineHttpServerBodyTest02(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -753,7 +757,8 @@ static int DetectEngineHttpServerBodyTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -778,7 +783,8 @@ static int DetectEngineHttpServerBodyTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -788,7 +794,8 @@ static int DetectEngineHttpServerBodyTest03(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -891,7 +898,8 @@ static int DetectEngineHttpServerBodyTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -916,7 +924,8 @@ static int DetectEngineHttpServerBodyTest04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1019,7 +1028,8 @@ static int DetectEngineHttpServerBodyTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1044,7 +1054,8 @@ static int DetectEngineHttpServerBodyTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1147,7 +1158,8 @@ static int DetectEngineHttpServerBodyTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1172,7 +1184,8 @@ static int DetectEngineHttpServerBodyTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1275,7 +1288,8 @@ static int DetectEngineHttpServerBodyTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1300,7 +1314,8 @@ static int DetectEngineHttpServerBodyTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1403,7 +1418,8 @@ static int DetectEngineHttpServerBodyTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1428,7 +1444,8 @@ static int DetectEngineHttpServerBodyTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1532,7 +1549,8 @@ static int DetectEngineHttpServerBodyTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1557,7 +1575,8 @@ static int DetectEngineHttpServerBodyTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1661,7 +1680,8 @@ static int DetectEngineHttpServerBodyTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1686,7 +1706,8 @@ static int DetectEngineHttpServerBodyTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1790,7 +1811,8 @@ static int DetectEngineHttpServerBodyTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1815,7 +1837,8 @@ static int DetectEngineHttpServerBodyTest11(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1919,7 +1942,8 @@ static int DetectEngineHttpServerBodyTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1944,7 +1968,8 @@ static int DetectEngineHttpServerBodyTest12(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2048,7 +2073,8 @@ static int DetectEngineHttpServerBodyTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2073,7 +2099,8 @@ static int DetectEngineHttpServerBodyTest13(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2177,7 +2204,8 @@ static int DetectEngineHttpServerBodyTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2202,7 +2230,8 @@ static int DetectEngineHttpServerBodyTest14(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2306,7 +2335,8 @@ static int DetectEngineHttpServerBodyTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2331,7 +2361,8 @@ static int DetectEngineHttpServerBodyTest15(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2460,7 +2491,8 @@ libhtp:\n\ DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2485,7 +2517,8 @@ libhtp:\n\ } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2503,7 +2536,8 @@ libhtp:\n\ } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2636,7 +2670,8 @@ libhtp:\n\ DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2661,7 +2696,8 @@ libhtp:\n\ } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2679,7 +2715,8 @@ libhtp:\n\ } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2795,7 +2832,8 @@ static int DetectEngineHttpServerBodyTest18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2817,7 +2855,8 @@ static int DetectEngineHttpServerBodyTest18(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2925,7 +2964,8 @@ static int DetectEngineHttpServerBodyTest19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2947,7 +2987,8 @@ static int DetectEngineHttpServerBodyTest19(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3055,7 +3096,8 @@ static int DetectEngineHttpServerBodyTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3077,7 +3119,8 @@ static int DetectEngineHttpServerBodyTest20(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3186,7 +3229,8 @@ static int DetectEngineHttpServerBodyTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3208,7 +3252,8 @@ static int DetectEngineHttpServerBodyTest21(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3319,7 +3364,8 @@ static int DetectEngineHttpServerBodyTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3341,7 +3387,8 @@ static int DetectEngineHttpServerBodyTest22(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3442,7 +3489,8 @@ static int DetectEngineHttpServerBodyFileDataTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3467,7 +3515,8 @@ static int DetectEngineHttpServerBodyFileDataTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3571,7 +3620,8 @@ static int DetectEngineHttpServerBodyFileDataTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3596,7 +3646,8 @@ static int DetectEngineHttpServerBodyFileDataTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3704,7 +3755,8 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3729,7 +3781,8 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 0d846ddd451b..1c55e17637d6 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -222,7 +222,8 @@ static int DetectEngineHttpStatCodeTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -247,7 +248,8 @@ static int DetectEngineHttpStatCodeTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -344,7 +346,8 @@ static int DetectEngineHttpStatCodeTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -354,7 +357,8 @@ static int DetectEngineHttpStatCodeTest02(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -466,7 +470,8 @@ static int DetectEngineHttpStatCodeTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -491,7 +496,8 @@ static int DetectEngineHttpStatCodeTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -501,7 +507,8 @@ static int DetectEngineHttpStatCodeTest03(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -604,7 +611,8 @@ static int DetectEngineHttpStatCodeTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -629,7 +637,8 @@ static int DetectEngineHttpStatCodeTest04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -732,7 +741,8 @@ static int DetectEngineHttpStatCodeTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -757,7 +767,8 @@ static int DetectEngineHttpStatCodeTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -860,7 +871,8 @@ static int DetectEngineHttpStatCodeTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -885,7 +897,8 @@ static int DetectEngineHttpStatCodeTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -988,7 +1001,8 @@ static int DetectEngineHttpStatCodeTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1013,7 +1027,8 @@ static int DetectEngineHttpStatCodeTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1116,7 +1131,8 @@ static int DetectEngineHttpStatCodeTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1141,7 +1157,8 @@ static int DetectEngineHttpStatCodeTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1245,7 +1262,8 @@ static int DetectEngineHttpStatCodeTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1270,7 +1288,8 @@ static int DetectEngineHttpStatCodeTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1374,7 +1393,8 @@ static int DetectEngineHttpStatCodeTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1399,7 +1419,8 @@ static int DetectEngineHttpStatCodeTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1503,7 +1524,8 @@ static int DetectEngineHttpStatCodeTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1528,7 +1550,8 @@ static int DetectEngineHttpStatCodeTest11(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1632,7 +1655,8 @@ static int DetectEngineHttpStatCodeTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1657,7 +1681,8 @@ static int DetectEngineHttpStatCodeTest12(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1761,7 +1786,8 @@ static int DetectEngineHttpStatCodeTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1786,7 +1812,8 @@ static int DetectEngineHttpStatCodeTest13(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1890,7 +1917,8 @@ static int DetectEngineHttpStatCodeTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1915,7 +1943,8 @@ static int DetectEngineHttpStatCodeTest14(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2019,7 +2048,8 @@ static int DetectEngineHttpStatCodeTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2044,7 +2074,8 @@ static int DetectEngineHttpStatCodeTest15(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index e978c246b1c7..cacee62fefc4 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -222,7 +222,8 @@ static int DetectEngineHttpStatMsgTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -247,7 +248,8 @@ static int DetectEngineHttpStatMsgTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -344,7 +346,8 @@ static int DetectEngineHttpStatMsgTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -354,7 +357,8 @@ static int DetectEngineHttpStatMsgTest02(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -466,7 +470,8 @@ static int DetectEngineHttpStatMsgTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -491,7 +496,8 @@ static int DetectEngineHttpStatMsgTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -501,7 +507,8 @@ static int DetectEngineHttpStatMsgTest03(void) FLOWLOCK_UNLOCK(&f); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -604,7 +611,8 @@ static int DetectEngineHttpStatMsgTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -629,7 +637,8 @@ static int DetectEngineHttpStatMsgTest04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -732,7 +741,8 @@ static int DetectEngineHttpStatMsgTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -757,7 +767,8 @@ static int DetectEngineHttpStatMsgTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -860,7 +871,8 @@ static int DetectEngineHttpStatMsgTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -885,7 +897,8 @@ static int DetectEngineHttpStatMsgTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -988,7 +1001,8 @@ static int DetectEngineHttpStatMsgTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1013,7 +1027,8 @@ static int DetectEngineHttpStatMsgTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1116,7 +1131,8 @@ static int DetectEngineHttpStatMsgTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1141,7 +1157,8 @@ static int DetectEngineHttpStatMsgTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1245,7 +1262,8 @@ static int DetectEngineHttpStatMsgTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1270,7 +1288,8 @@ static int DetectEngineHttpStatMsgTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1374,7 +1393,8 @@ static int DetectEngineHttpStatMsgTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1399,7 +1419,8 @@ static int DetectEngineHttpStatMsgTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1503,7 +1524,8 @@ static int DetectEngineHttpStatMsgTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1528,7 +1550,8 @@ static int DetectEngineHttpStatMsgTest11(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1632,7 +1655,8 @@ static int DetectEngineHttpStatMsgTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1657,7 +1681,8 @@ static int DetectEngineHttpStatMsgTest12(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1761,7 +1786,8 @@ static int DetectEngineHttpStatMsgTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1786,7 +1812,8 @@ static int DetectEngineHttpStatMsgTest13(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -1890,7 +1917,8 @@ static int DetectEngineHttpStatMsgTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1915,7 +1943,8 @@ static int DetectEngineHttpStatMsgTest14(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2019,7 +2048,8 @@ static int DetectEngineHttpStatMsgTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2044,7 +2074,8 @@ static int DetectEngineHttpStatMsgTest15(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index b05e843f0b9b..41842f8fbbb3 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -217,7 +217,8 @@ static int DetectEngineHttpUATest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -315,7 +316,8 @@ static int DetectEngineHttpUATest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -413,7 +415,8 @@ static int DetectEngineHttpUATest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -511,7 +514,8 @@ static int DetectEngineHttpUATest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -609,7 +613,8 @@ static int DetectEngineHttpUATest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -707,7 +712,8 @@ static int DetectEngineHttpUATest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -805,7 +811,8 @@ static int DetectEngineHttpUATest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -903,7 +910,8 @@ static int DetectEngineHttpUATest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1001,7 +1009,8 @@ static int DetectEngineHttpUATest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1100,7 +1109,8 @@ static int DetectEngineHttpUATest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1199,7 +1209,8 @@ static int DetectEngineHttpUATest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1298,7 +1309,8 @@ static int DetectEngineHttpUATest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1397,7 +1409,8 @@ static int DetectEngineHttpUATest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1496,7 +1509,8 @@ static int DetectEngineHttpUATest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1595,7 +1609,8 @@ static int DetectEngineHttpUATest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1694,7 +1709,8 @@ static int DetectEngineHttpUATest16(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1793,7 +1809,8 @@ static int DetectEngineHttpUATest17(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-engine-modbus.c b/src/detect-engine-modbus.c index 8d53bf39366c..976e7d901f27 100644 --- a/src/detect-engine-modbus.c +++ b/src/detect-engine-modbus.c @@ -381,8 +381,10 @@ static int DetectEngineInspectModbusTest01(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - readWriteMultipleRegistersReq, sizeof(readWriteMultipleRegistersReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + readWriteMultipleRegistersReq, + sizeof(readWriteMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -471,7 +473,9 @@ static int DetectEngineInspectModbusTest02(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, forceListenOnlyMode, sizeof(forceListenOnlyMode)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, forceListenOnlyMode, + sizeof(forceListenOnlyMode)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -560,8 +564,10 @@ static int DetectEngineInspectModbusTest03(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - encapsulatedInterfaceTransport, sizeof(encapsulatedInterfaceTransport)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + encapsulatedInterfaceTransport, + sizeof(encapsulatedInterfaceTransport)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -650,7 +656,9 @@ static int DetectEngineInspectModbusTest04(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, unassigned, sizeof(unassigned)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, unassigned, + sizeof(unassigned)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -739,8 +747,9 @@ static int DetectEngineInspectModbusTest05(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - readCoilsReq, sizeof(readCoilsReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -829,8 +838,9 @@ static int DetectEngineInspectModbusTest06(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - readInputsRegistersReq, sizeof(readInputsRegistersReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readInputsRegistersReq, + sizeof(readInputsRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -919,7 +929,9 @@ static int DetectEngineInspectModbusTest07(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readCoilsReq, sizeof(readCoilsReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1056,8 +1068,9 @@ static int DetectEngineInspectModbusTest08(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - readInputsRegistersReq, sizeof(readInputsRegistersReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readInputsRegistersReq, + sizeof(readInputsRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1241,8 +1254,10 @@ static int DetectEngineInspectModbusTest09(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - readWriteMultipleRegistersReq, sizeof(readWriteMultipleRegistersReq)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + readWriteMultipleRegistersReq, + sizeof(readWriteMultipleRegistersReq)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 1f38a5c928ee..6120e1dda84a 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -1443,7 +1443,8 @@ static int DeStateSigTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1459,7 +1460,8 @@ static int DeStateSigTest01(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1475,7 +1477,8 @@ static int DeStateSigTest01(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1491,7 +1494,8 @@ static int DeStateSigTest01(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1595,7 +1599,8 @@ static int DeStateSigTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1611,7 +1616,8 @@ static int DeStateSigTest02(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1627,7 +1633,8 @@ static int DeStateSigTest02(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1655,7 +1662,8 @@ static int DeStateSigTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1672,7 +1680,8 @@ static int DeStateSigTest02(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1688,7 +1697,8 @@ static int DeStateSigTest02(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1706,7 +1716,8 @@ static int DeStateSigTest02(void) SCLogDebug("sending data chunk 7"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1800,7 +1811,10 @@ static int DeStateSigTest03(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1927,7 +1941,10 @@ static int DeStateSigTest04(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2054,7 +2071,10 @@ static int DeStateSigTest05(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2181,7 +2201,10 @@ static int DeStateSigTest06(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2311,7 +2334,9 @@ static int DeStateSigTest07(void) SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); FLOWLOCK_WRLOCK(f); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2329,7 +2354,8 @@ static int DeStateSigTest07(void) SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); FLOWLOCK_WRLOCK(f); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index 09bd2b9927f2..fd7e558ff1a6 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -227,7 +227,8 @@ static int UriTestSig01(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -252,7 +253,8 @@ static int UriTestSig01(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -349,7 +351,8 @@ static int UriTestSig02(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -374,7 +377,8 @@ static int UriTestSig02(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -471,7 +475,8 @@ static int UriTestSig03(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -496,7 +501,8 @@ static int UriTestSig03(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -593,7 +599,8 @@ static int UriTestSig04(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -618,7 +625,8 @@ static int UriTestSig04(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -715,7 +723,8 @@ static int UriTestSig05(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -740,7 +749,8 @@ static int UriTestSig05(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -837,7 +847,8 @@ static int UriTestSig06(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -862,7 +873,8 @@ static int UriTestSig06(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -959,7 +971,8 @@ static int UriTestSig07(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -984,7 +997,8 @@ static int UriTestSig07(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1081,7 +1095,8 @@ static int UriTestSig08(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1106,7 +1121,8 @@ static int UriTestSig08(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1203,7 +1219,8 @@ static int UriTestSig09(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1228,7 +1245,8 @@ static int UriTestSig09(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1325,7 +1343,8 @@ static int UriTestSig10(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1350,7 +1369,8 @@ static int UriTestSig10(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1448,7 +1468,8 @@ static int UriTestSig11(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1473,7 +1494,8 @@ static int UriTestSig11(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1571,7 +1593,8 @@ static int UriTestSig12(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1596,7 +1619,8 @@ static int UriTestSig12(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1693,7 +1717,8 @@ static int UriTestSig13(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1718,7 +1743,8 @@ static int UriTestSig13(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1816,7 +1842,8 @@ static int UriTestSig14(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1841,7 +1868,8 @@ static int UriTestSig14(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1939,7 +1967,8 @@ static int UriTestSig15(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1964,7 +1993,8 @@ static int UriTestSig15(void) DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2060,7 +2090,8 @@ static int UriTestSig16(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2088,7 +2119,8 @@ static int UriTestSig16(void) p->payload_len = http_buf2_len; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2183,7 +2215,8 @@ static int UriTestSig17(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2278,7 +2311,8 @@ static int UriTestSig18(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2374,7 +2408,8 @@ static int UriTestSig19(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2469,7 +2504,8 @@ static int UriTestSig20(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2563,7 +2599,8 @@ static int UriTestSig21(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2657,7 +2694,8 @@ static int UriTestSig22(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2750,7 +2788,8 @@ static int UriTestSig23(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2843,7 +2882,8 @@ static int UriTestSig24(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2936,7 +2976,8 @@ static int UriTestSig25(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3029,7 +3070,8 @@ static int UriTestSig26(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3122,7 +3164,8 @@ static int UriTestSig27(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3249,7 +3292,8 @@ static int UriTestSig28(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3341,7 +3385,8 @@ static int UriTestSig29(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3433,7 +3478,8 @@ static int UriTestSig30(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3525,7 +3571,8 @@ static int UriTestSig31(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3617,7 +3664,8 @@ static int UriTestSig32(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3707,7 +3755,8 @@ static int UriTestSig33(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3797,7 +3846,8 @@ static int UriTestSig34(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3887,7 +3937,8 @@ static int UriTestSig35(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3977,7 +4028,8 @@ static int UriTestSig36(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4067,7 +4119,8 @@ static int UriTestSig37(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -4157,7 +4210,8 @@ static int UriTestSig38(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-ftpbounce.c b/src/detect-ftpbounce.c index c4dea5cb212a..e6015a16c012 100644 --- a/src/detect-ftpbounce.c +++ b/src/detect-ftpbounce.c @@ -330,7 +330,8 @@ static int DetectFtpbounceTestALMatch02(void) DetectEngineThreadCtxInit(&th_v,(void *)de_ctx,(void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf1, ftplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -338,7 +339,8 @@ static int DetectFtpbounceTestALMatch02(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, ftplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -346,7 +348,8 @@ static int DetectFtpbounceTestALMatch02(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf3, ftplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf3, ftplen3); if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -354,7 +357,8 @@ static int DetectFtpbounceTestALMatch02(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf4, ftplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf4, ftplen4); if (r != 0) { SCLogDebug("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -471,7 +475,8 @@ static int DetectFtpbounceTestALMatch03(void) DetectEngineThreadCtxInit(&th_v,(void *)de_ctx,(void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf1, ftplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -479,7 +484,8 @@ static int DetectFtpbounceTestALMatch03(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, ftplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -487,7 +493,8 @@ static int DetectFtpbounceTestALMatch03(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf3, ftplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf3, ftplen3); if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -495,7 +502,8 @@ static int DetectFtpbounceTestALMatch03(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf4, ftplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf4, ftplen4); if (r != 0) { SCLogDebug("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 600d74cfcac1..4497836ffa78 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -345,7 +345,8 @@ static int DetectHttpClientBodyTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -456,7 +457,8 @@ static int DetectHttpClientBodyTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -480,7 +482,8 @@ static int DetectHttpClientBodyTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -583,7 +586,8 @@ static int DetectHttpClientBodyTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -608,7 +612,8 @@ static int DetectHttpClientBodyTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -713,7 +718,8 @@ static int DetectHttpClientBodyTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -738,7 +744,8 @@ static int DetectHttpClientBodyTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -843,7 +850,8 @@ static int DetectHttpClientBodyTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -868,7 +876,8 @@ static int DetectHttpClientBodyTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -964,7 +973,8 @@ static int DetectHttpClientBodyTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1066,7 +1076,8 @@ static int DetectHttpClientBodyTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1168,7 +1179,8 @@ static int DetectHttpClientBodyTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1276,7 +1288,8 @@ static int DetectHttpClientBodyTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1293,7 +1306,8 @@ static int DetectHttpClientBodyTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1311,7 +1325,8 @@ static int DetectHttpClientBodyTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1328,7 +1343,8 @@ static int DetectHttpClientBodyTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1346,7 +1362,8 @@ static int DetectHttpClientBodyTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1363,7 +1380,8 @@ static int DetectHttpClientBodyTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1382,7 +1400,8 @@ static int DetectHttpClientBodyTest14(void) SCLogDebug("sending data chunk 7"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1495,7 +1514,8 @@ static int DetectHttpClientBodyTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1512,7 +1532,8 @@ static int DetectHttpClientBodyTest15(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1529,7 +1550,8 @@ static int DetectHttpClientBodyTest15(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1546,7 +1568,8 @@ static int DetectHttpClientBodyTest15(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1564,7 +1587,8 @@ static int DetectHttpClientBodyTest15(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1581,7 +1605,8 @@ static int DetectHttpClientBodyTest15(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1600,7 +1625,8 @@ static int DetectHttpClientBodyTest15(void) SCLogDebug("sending data chunk 7"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 635d78fccb22..5d17c89ea48d 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -371,7 +371,8 @@ static int DetectHttpCookieSigTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -470,7 +471,8 @@ static int DetectHttpCookieSigTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -563,7 +565,8 @@ static int DetectHttpCookieSigTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -657,7 +660,8 @@ static int DetectHttpCookieSigTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -751,7 +755,8 @@ static int DetectHttpCookieSigTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -846,7 +851,8 @@ static int DetectHttpCookieSigTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -938,7 +944,8 @@ static int DetectHttpCookieSigTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1049,8 +1056,9 @@ static int DetectHttpCookieSigTest08(void) /* request */ FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, - httpbuf_request, httpbuf_request_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf_request, + httpbuf_request_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1073,8 +1081,9 @@ static int DetectHttpCookieSigTest08(void) /* response */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, - httpbuf_response, httpbuf_response_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf_response, + httpbuf_response_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1186,8 +1195,9 @@ static int DetectHttpCookieSigTest09(void) /* request */ FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, - httpbuf_request, httpbuf_request_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf_request, + httpbuf_request_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1210,8 +1220,9 @@ static int DetectHttpCookieSigTest09(void) /* response */ FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, - httpbuf_response, httpbuf_response_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf_response, + httpbuf_response_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 8459d5ab1eec..6a75e8199146 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -352,7 +352,8 @@ static int DetectHttpHeaderTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -461,7 +462,8 @@ static int DetectHttpHeaderTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -486,7 +488,8 @@ static int DetectHttpHeaderTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -588,7 +591,8 @@ static int DetectHttpHeaderTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -613,7 +617,8 @@ static int DetectHttpHeaderTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -717,7 +722,8 @@ static int DetectHttpHeaderTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -742,7 +748,8 @@ static int DetectHttpHeaderTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -845,7 +852,8 @@ static int DetectHttpHeaderTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -870,7 +878,8 @@ static int DetectHttpHeaderTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -965,7 +974,8 @@ static int DetectHttpHeaderTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1066,7 +1076,8 @@ static int DetectHttpHeaderTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1168,7 +1179,8 @@ static int DetectHttpHeaderTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1575,7 +1587,8 @@ static int DetectHttpHeaderTest28(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1662,7 +1675,8 @@ static int DetectHttpHeaderTest29(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1749,7 +1763,8 @@ static int DetectHttpHeaderTest30(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 6345241826e1..f8c33879747b 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -330,7 +330,8 @@ static int DetectHttpHHTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -437,7 +438,8 @@ static int DetectHttpHHTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -461,7 +463,8 @@ static int DetectHttpHHTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -560,7 +563,8 @@ static int DetectHttpHHTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -585,7 +589,8 @@ static int DetectHttpHHTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -690,7 +695,8 @@ static int DetectHttpHHTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -715,7 +721,8 @@ static int DetectHttpHHTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -820,7 +827,8 @@ static int DetectHttpHHTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -845,7 +853,8 @@ static int DetectHttpHHTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -940,7 +949,8 @@ static int DetectHttpHHTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1039,7 +1049,8 @@ static int DetectHttpHHTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1139,7 +1150,8 @@ static int DetectHttpHHTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1247,7 +1259,8 @@ static int DetectHttpHHTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1264,7 +1277,8 @@ static int DetectHttpHHTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1281,7 +1295,8 @@ static int DetectHttpHHTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1298,7 +1313,8 @@ static int DetectHttpHHTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1315,7 +1331,8 @@ static int DetectHttpHHTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1334,7 +1351,8 @@ static int DetectHttpHHTest14(void) SCLogDebug("sending data chunk 7"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index efe1cddbdd09..0243885d0595 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -330,7 +330,8 @@ static int DetectHttpHRHTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -437,7 +438,8 @@ static int DetectHttpHRHTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -461,7 +463,8 @@ static int DetectHttpHRHTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -560,7 +563,8 @@ static int DetectHttpHRHTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -585,7 +589,8 @@ static int DetectHttpHRHTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -690,7 +695,8 @@ static int DetectHttpHRHTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -715,7 +721,8 @@ static int DetectHttpHRHTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -820,7 +827,8 @@ static int DetectHttpHRHTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -845,7 +853,8 @@ static int DetectHttpHRHTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -939,7 +948,8 @@ static int DetectHttpHRHTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1038,7 +1048,8 @@ static int DetectHttpHRHTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1138,7 +1149,8 @@ static int DetectHttpHRHTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1246,7 +1258,8 @@ static int DetectHttpHRHTest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1263,7 +1276,8 @@ static int DetectHttpHRHTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1280,7 +1294,8 @@ static int DetectHttpHRHTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1297,7 +1312,8 @@ static int DetectHttpHRHTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1314,7 +1330,8 @@ static int DetectHttpHRHTest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1333,7 +1350,8 @@ static int DetectHttpHRHTest14(void) SCLogDebug("sending data chunk 7"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2127,7 +2145,8 @@ static int DetectHttpHRHTest37(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2152,7 +2171,8 @@ static int DetectHttpHRHTest37(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 132b76795780..5167bad16221 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -497,7 +497,8 @@ static int DetectHttpMethodSigTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -600,7 +601,8 @@ static int DetectHttpMethodSigTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -694,7 +696,8 @@ static int DetectHttpMethodSigTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -790,7 +793,8 @@ static int DetectHttpMethodSigTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index 5d761ecb3a1f..7397948387e7 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -351,7 +351,8 @@ static int DetectHttpRawHeaderTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -460,7 +461,8 @@ static int DetectHttpRawHeaderTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -485,7 +487,8 @@ static int DetectHttpRawHeaderTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -587,7 +590,8 @@ static int DetectHttpRawHeaderTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -612,7 +616,8 @@ static int DetectHttpRawHeaderTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -715,7 +720,8 @@ static int DetectHttpRawHeaderTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -740,7 +746,8 @@ static int DetectHttpRawHeaderTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -843,7 +850,8 @@ static int DetectHttpRawHeaderTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -868,7 +876,8 @@ static int DetectHttpRawHeaderTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -963,7 +972,8 @@ static int DetectHttpRawHeaderTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1064,7 +1074,8 @@ static int DetectHttpRawHeaderTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1166,7 +1177,8 @@ static int DetectHttpRawHeaderTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index b4af9a402d78..1f2b3113edea 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -366,14 +366,20 @@ static int DetectHttpServerBodyTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf, + http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START | STREAM_EOF, + http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -489,14 +495,19 @@ static int DetectHttpServerBodyTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -519,7 +530,9 @@ static int DetectHttpServerBodyTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -626,7 +639,9 @@ static int DetectHttpServerBodyTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -643,7 +658,9 @@ static int DetectHttpServerBodyTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -661,7 +678,9 @@ static int DetectHttpServerBodyTest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -773,7 +792,9 @@ static int DetectHttpServerBodyTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -790,7 +811,9 @@ static int DetectHttpServerBodyTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -808,7 +831,9 @@ static int DetectHttpServerBodyTest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -816,7 +841,9 @@ static int DetectHttpServerBodyTest09(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf4, + http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -928,7 +955,9 @@ static int DetectHttpServerBodyTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -945,7 +974,9 @@ static int DetectHttpServerBodyTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -963,7 +994,9 @@ static int DetectHttpServerBodyTest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -971,7 +1004,9 @@ static int DetectHttpServerBodyTest10(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf4, + http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1079,7 +1114,9 @@ static int DetectHttpServerBodyTest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1096,7 +1133,9 @@ static int DetectHttpServerBodyTest11(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1114,7 +1153,9 @@ static int DetectHttpServerBodyTest11(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1222,7 +1263,9 @@ static int DetectHttpServerBodyTest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1239,7 +1282,9 @@ static int DetectHttpServerBodyTest12(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1257,7 +1302,9 @@ static int DetectHttpServerBodyTest12(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1353,14 +1400,20 @@ static int DetectHttpServerBodyTest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf, + http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START | STREAM_EOF, + http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1480,7 +1533,9 @@ static int DetectHttpServerBodyTest14(void) SCLogDebug("add chunk 1"); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1489,7 +1544,8 @@ static int DetectHttpServerBodyTest14(void) SCLogDebug("add chunk 2"); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1510,7 +1566,8 @@ static int DetectHttpServerBodyTest14(void) SCLogDebug("add chunk 3"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1519,7 +1576,8 @@ static int DetectHttpServerBodyTest14(void) SCLogDebug("add chunk 4"); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1646,14 +1704,17 @@ static int DetectHttpServerBodyTest15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1674,14 +1735,16 @@ static int DetectHttpServerBodyTest15(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2466,14 +2529,20 @@ static int DetectHttpServerBodyFileDataTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf, + http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START | STREAM_EOF, + http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2589,7 +2658,10 @@ static int DetectHttpServerBodyFileDataTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2597,7 +2669,9 @@ static int DetectHttpServerBodyFileDataTest02(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2621,7 +2695,9 @@ static int DetectHttpServerBodyFileDataTest02(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2728,7 +2804,9 @@ static int DetectHttpServerBodyFileDataTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2745,7 +2823,9 @@ static int DetectHttpServerBodyFileDataTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2763,7 +2843,9 @@ static int DetectHttpServerBodyFileDataTest03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2876,7 +2958,9 @@ static int DetectHttpServerBodyFileDataTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2893,7 +2977,9 @@ static int DetectHttpServerBodyFileDataTest04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2911,7 +2997,9 @@ static int DetectHttpServerBodyFileDataTest04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2919,7 +3007,9 @@ static int DetectHttpServerBodyFileDataTest04(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf4, + http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3031,7 +3121,9 @@ static int DetectHttpServerBodyFileDataTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3048,7 +3140,9 @@ static int DetectHttpServerBodyFileDataTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3066,7 +3160,9 @@ static int DetectHttpServerBodyFileDataTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3074,7 +3170,9 @@ static int DetectHttpServerBodyFileDataTest05(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf4, + http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3182,7 +3280,9 @@ static int DetectHttpServerBodyFileDataTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3199,7 +3299,9 @@ static int DetectHttpServerBodyFileDataTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3217,7 +3319,9 @@ static int DetectHttpServerBodyFileDataTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3325,7 +3429,9 @@ static int DetectHttpServerBodyFileDataTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3342,7 +3448,9 @@ static int DetectHttpServerBodyFileDataTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3360,7 +3468,9 @@ static int DetectHttpServerBodyFileDataTest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3456,14 +3566,20 @@ static int DetectHttpServerBodyFileDataTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf, + http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START | STREAM_EOF, + http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3581,14 +3697,17 @@ static int DetectHttpServerBodyFileDataTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3605,14 +3724,16 @@ static int DetectHttpServerBodyFileDataTest09(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3737,14 +3858,17 @@ static int DetectHttpServerBodyFileDataTest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -3761,14 +3885,16 @@ static int DetectHttpServerBodyFileDataTest10(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index f2878743d860..2248694d1ed3 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -269,14 +269,16 @@ static int DetectHttpStatCodeSigTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -377,7 +379,8 @@ static int DetectHttpStatCodeSigTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -385,7 +388,8 @@ static int DetectHttpStatCodeSigTest02(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -493,7 +497,8 @@ static int DetectHttpStatCodeSigTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -501,7 +506,8 @@ static int DetectHttpStatCodeSigTest03(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -609,7 +615,8 @@ static int DetectHttpStatCodeSigTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -617,7 +624,8 @@ static int DetectHttpStatCodeSigTest04(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index 4472f6144bed..0c3151a3313c 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -267,7 +267,8 @@ static int DetectHttpStatMsgSigTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -275,7 +276,8 @@ static int DetectHttpStatMsgSigTest01(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -375,7 +377,8 @@ static int DetectHttpStatMsgSigTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -383,7 +386,8 @@ static int DetectHttpStatMsgSigTest02(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -487,7 +491,8 @@ static int DetectHttpStatMsgSigTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -495,7 +500,8 @@ static int DetectHttpStatMsgSigTest03(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index 5e9d69d13c0b..b923c43fda8e 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -331,7 +331,8 @@ static int DetectHttpUATest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -438,7 +439,8 @@ static int DetectHttpUATest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -462,7 +464,8 @@ static int DetectHttpUATest07(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -561,7 +564,8 @@ static int DetectHttpUATest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -586,7 +590,8 @@ static int DetectHttpUATest08(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -691,7 +696,8 @@ static int DetectHttpUATest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -716,7 +722,8 @@ static int DetectHttpUATest09(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -821,7 +828,8 @@ static int DetectHttpUATest10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -846,7 +854,8 @@ static int DetectHttpUATest10(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -940,7 +949,8 @@ static int DetectHttpUATest11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1039,7 +1049,8 @@ static int DetectHttpUATest12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1139,7 +1150,8 @@ static int DetectHttpUATest13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -1247,7 +1259,8 @@ static int DetectHttpUATest14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1264,7 +1277,8 @@ static int DetectHttpUATest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1281,7 +1295,8 @@ static int DetectHttpUATest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1298,7 +1313,8 @@ static int DetectHttpUATest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1315,7 +1331,8 @@ static int DetectHttpUATest14(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1334,7 +1351,8 @@ static int DetectHttpUATest14(void) SCLogDebug("sending data chunk 7"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-lua.c b/src/detect-lua.c index 02450e61cd80..a4716d44eeaa 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1275,7 +1275,8 @@ static int LuaMatchTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1298,7 +1299,8 @@ static int LuaMatchTest01(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1709,7 +1711,8 @@ static int LuaMatchTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1732,7 +1735,8 @@ static int LuaMatchTest04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1857,7 +1861,8 @@ static int LuaMatchTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1880,7 +1885,8 @@ static int LuaMatchTest05(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2010,7 +2016,8 @@ static int LuaMatchTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -2033,7 +2040,8 @@ static int LuaMatchTest06(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 58b83e769ff2..ed66a9f1e6f6 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -1496,7 +1496,8 @@ static int DetectPcreTestSig01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, buf, buflen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, buf, buflen); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1691,7 +1692,8 @@ static int DetectPcreModifPTest04(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -1802,7 +1804,8 @@ static int DetectPcreModifPTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -1817,7 +1820,8 @@ static int DetectPcreModifPTest05(void) FAIL_IF(PacketAlertCheck(p1, 2)); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -1945,7 +1949,8 @@ static int DetectPcreTestSig09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2023,7 +2028,8 @@ static int DetectPcreTestSig10(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2101,7 +2107,8 @@ static int DetectPcreTestSig11(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2179,7 +2186,8 @@ static int DetectPcreTestSig12(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2257,7 +2265,8 @@ static int DetectPcreTestSig13(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2335,7 +2344,8 @@ static int DetectPcreTestSig14(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2414,7 +2424,8 @@ static int DetectPcreTestSig15(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2493,7 +2504,8 @@ static int DetectPcreTestSig16(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2564,25 +2576,33 @@ static int DetectPcreTxBodyChunksTest01(void) AppLayerHtpEnableRequestBodyCallback(); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); FAIL_IF(r != 0); /* Now we should have 2 transactions, each with it's own list @@ -2679,7 +2699,8 @@ static int DetectPcreTxBodyChunksTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2689,7 +2710,8 @@ static int DetectPcreTxBodyChunksTest02(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2699,7 +2721,8 @@ static int DetectPcreTxBodyChunksTest02(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2709,7 +2732,8 @@ static int DetectPcreTxBodyChunksTest02(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2719,7 +2743,8 @@ static int DetectPcreTxBodyChunksTest02(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2729,7 +2754,8 @@ static int DetectPcreTxBodyChunksTest02(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2741,7 +2767,8 @@ static int DetectPcreTxBodyChunksTest02(void) SCLogDebug("sending data chunk 7"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2847,7 +2874,8 @@ static int DetectPcreTxBodyChunksTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2857,7 +2885,8 @@ static int DetectPcreTxBodyChunksTest03(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2867,7 +2896,8 @@ static int DetectPcreTxBodyChunksTest03(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2877,7 +2907,8 @@ static int DetectPcreTxBodyChunksTest03(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2887,7 +2918,8 @@ static int DetectPcreTxBodyChunksTest03(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2897,7 +2929,8 @@ static int DetectPcreTxBodyChunksTest03(void) p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -2909,7 +2942,8 @@ static int DetectPcreTxBodyChunksTest03(void) SCLogDebug("sending data chunk 7"); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -3003,7 +3037,8 @@ static int DetectPcreFlowvarCapture01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -3116,7 +3151,8 @@ static int DetectPcreFlowvarCapture02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -3228,7 +3264,8 @@ static int DetectPcreFlowvarCapture03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index 39b4a891b1ee..3df3dfe0b48d 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -375,28 +375,32 @@ static int DetectSshVersionTestDetect01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -488,27 +492,31 @@ static int DetectSshVersionTestDetect02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -599,28 +607,32 @@ static int DetectSshVersionTestDetect03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index bc1967f77101..1284bbc37e6e 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -347,28 +347,32 @@ static int DetectSshSoftwareVersionTestDetect01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -460,28 +464,32 @@ static int DetectSshSoftwareVersionTestDetect02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -572,28 +580,32 @@ static int DetectSshSoftwareVersionTestDetect03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 742c925142ea..855e76542234 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -710,7 +710,8 @@ static int DetectSslStateTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_START, chello_buf, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER | STREAM_START, chello_buf, chello_buf_len); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -729,8 +730,8 @@ static int DetectSslStateTest07(void) FAIL_IF(PacketAlertCheck(p, 5)); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, - shello_buf_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + shello_buf, shello_buf_len); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -749,7 +750,8 @@ static int DetectSslStateTest07(void) PASS; FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_change_cipher_spec_buf, client_change_cipher_spec_buf_len); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -764,7 +766,8 @@ static int DetectSslStateTest07(void) FAIL_IF(PacketAlertCheck(p, 4)); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_change_cipher_spec_buf, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_change_cipher_spec_buf, server_change_cipher_spec_buf_len); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -779,8 +782,8 @@ static int DetectSslStateTest07(void) FAIL_IF(PacketAlertCheck(p, 4)); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, toserver_app_data_buf, - toserver_app_data_buf_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + toserver_app_data_buf, toserver_app_data_buf_len); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index 7e133630e382..52a5d4b72aff 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -419,16 +419,20 @@ static int DetectSslVersionTestDetect01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, sslbuf1, ssllen1); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf2, ssllen2); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf3, ssllen3); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf4, ssllen4); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -506,16 +510,20 @@ static int DetectSslVersionTestDetect02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, sslbuf1, ssllen1); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf2, ssllen2); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf3, ssllen3); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf4, ssllen4); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -599,16 +607,20 @@ static int DetectSslVersionTestDetect03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, sslbuf1, ssllen1); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf2, ssllen2); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf3, ssllen3); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf4, ssllen4); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index 574743c8625d..65debf5ecba9 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -127,8 +127,8 @@ static int DetectTemplateBufferTest(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - AppLayerParserParse(alp_tctx, &f, ALPROTO_TEMPLATE, STREAM_TOSERVER, - request, sizeof(request)); + AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TEMPLATE, + STREAM_TOSERVER, request, sizeof(request)); FLOWLOCK_UNLOCK(&f); /* Check that we have app-layer state. */ diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index f6dc4ad128bc..bbdb419607f6 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -391,8 +391,9 @@ static int DetectTlsIssuerTest02(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, - client_hello, sizeof(client_hello)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, client_hello, + sizeof(client_hello)); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -405,7 +406,7 @@ static int DetectTlsIssuerTest02(void) FAIL_IF(PacketAlertCheck(p1, 1)); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); FLOWLOCK_UNLOCK(&f); @@ -416,7 +417,7 @@ static int DetectTlsIssuerTest02(void) FAIL_IF(PacketAlertCheck(p2, 1)); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index f3bea21e0c4f..48c30c030d40 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -390,8 +390,9 @@ static int DetectTlsSubjectTest02(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, - client_hello, sizeof(client_hello)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, client_hello, + sizeof(client_hello)); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -404,7 +405,7 @@ static int DetectTlsSubjectTest02(void) FAIL_IF(PacketAlertCheck(p1, 1)); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); FLOWLOCK_UNLOCK(&f); @@ -415,7 +416,7 @@ static int DetectTlsSubjectTest02(void) FAIL_IF(PacketAlertCheck(p2, 1)); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index 702f53f09c42..47f009cce16d 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -1107,8 +1107,9 @@ int ValidityTestDetect01(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, - client_hello, sizeof(client_hello)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, client_hello, + sizeof(client_hello)); SCMutexUnlock(&f.m); FAIL_IF(r != 0); @@ -1122,7 +1123,7 @@ int ValidityTestDetect01(void) FAIL_IF(PacketAlertCheck(p1, 2)); SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); SCMutexUnlock(&f.m); @@ -1134,7 +1135,7 @@ int ValidityTestDetect01(void) FAIL_IF(PacketAlertCheck(p2, 2)); SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); SCMutexUnlock(&f.m); diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index 42fe329c9c35..77774cc918b2 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -159,7 +159,8 @@ static int DetectTlsSniTest01(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf, sizeof(buf)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf, sizeof(buf)); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); @@ -257,7 +258,8 @@ static int DetectTlsSniTest02(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf, sizeof(buf)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf, sizeof(buf)); FLOWLOCK_UNLOCK(&f); FAIL_IF(r != 0); diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index bff7ba95cc8f..eb78cfb3bb4f 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -335,16 +335,20 @@ static int DetectTlsVersionTestDetect01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf3, tlslen3); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf4, tlslen4); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -427,16 +431,20 @@ static int DetectTlsVersionTestDetect02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf3, tlslen3); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf4, tlslen4); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); @@ -525,16 +533,20 @@ static int DetectTlsVersionTestDetect03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf3, tlslen3); FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf4, tlslen4); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index 42e83f19bd32..a8a1f0d9a3c2 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -219,8 +219,10 @@ static int HTTPUriTest01(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; @@ -287,8 +289,10 @@ static int HTTPUriTest02(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; @@ -357,8 +361,10 @@ static int HTTPUriTest03(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; @@ -428,8 +434,10 @@ static int HTTPUriTest04(void) StreamTcpInitConfig(TRUE); FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; @@ -586,7 +594,8 @@ static int DetectUriSigTest02(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -701,7 +710,8 @@ static int DetectUriSigTest03(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -725,7 +735,8 @@ static int DetectUriSigTest03(void) FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1053,7 +1064,8 @@ static int DetectUriSigTest05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1193,7 +1205,8 @@ static int DetectUriSigTest06(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -1315,7 +1328,8 @@ static int DetectUriSigTest07(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect-urilen.c b/src/detect-urilen.c index 2dbf56a12638..898fa9497a3d 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -611,7 +611,8 @@ static int DetectUrilenSigTest01(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); diff --git a/src/detect.c b/src/detect.c index e933a23e0aa3..2fb7243f1fac 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4823,7 +4823,8 @@ static int SigTest06 (void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -4912,7 +4913,8 @@ static int SigTest07 (void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5001,7 +5003,8 @@ static int SigTest08 (void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5092,7 +5095,8 @@ static int SigTest09 (void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5175,7 +5179,8 @@ static int SigTest10 (void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -9344,7 +9349,8 @@ static int SigTestDropFlow01(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -9446,7 +9452,8 @@ static int SigTestDropFlow02(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -9576,7 +9583,8 @@ static int SigTestDropFlow03(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -9621,7 +9629,8 @@ static int SigTestDropFlow03(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -9747,7 +9756,8 @@ static int SigTestDropFlow04(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); @@ -9802,7 +9812,8 @@ static int SigTestDropFlow04(void) } FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); FLOWLOCK_UNLOCK(&f); From a194dfbd5b1ac6b2b2db594267cf3caac7686618 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 26 May 2016 23:11:34 +0200 Subject: [PATCH 1755/2553] app-layer: tx counter implementation This patch adds a transaction counter for application layers supporting it. Analysis is done after the parsing by the different application layers. This result in new data in the stats output, that looks like: ``` "app-layer": { "tx": { "dns_udp": 21433, "http": 12766, "smtp": 0, "dns_tcp": 0 } }, ``` --- src/app-layer-parser.c | 13 ++++++++++ src/app-layer.c | 56 ++++++++++++++++++++++++++++++++++-------- src/app-layer.h | 2 ++ 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index bd1962045b46..36a2792f5b2b 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -923,6 +923,7 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow AppLayerParserState *pstate = NULL; AppLayerParserProtoCtx *p = &alp_ctx.ctxs[f->protomap][alproto]; void *alstate = NULL; + uint64_t p_tx_cnt = 0; /* we don't have the parser registered for this protocol */ if (p->StateAlloc == NULL) @@ -964,6 +965,10 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow alstate, AppLayerGetProtoName(f->alproto)); } + if (AppLayerParserProtocolIsTxAware(f->proto, alproto)) { + p_tx_cnt = AppLayerParserGetTxCnt(f->proto, alproto, f->alstate); + } + /* invoke the recursive parser, but only on data. We may get empty msgs on EOF */ if (input_len > 0 || (flags & STREAM_EOF)) { /* invoke the parser */ @@ -1011,6 +1016,14 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow } } + if (AppLayerParserProtocolIsTxAware(f->proto, alproto)) { + if (likely(tv)) { + uint64_t cur_tx_cnt = AppLayerParserGetTxCnt(f->proto, alproto, f->alstate); + if (cur_tx_cnt > p_tx_cnt) { + AppLayerIncTxCounter(tv, f, cur_tx_cnt - p_tx_cnt); + } + } + } /* next, see if we can get rid of transactions now */ AppLayerParserTransactionsCleanup(f); diff --git a/src/app-layer.c b/src/app-layer.c index f88e095fff04..8e1855d48ec6 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -69,7 +69,9 @@ struct AppLayerThreadCtx_ { typedef struct AppLayerCounters_ { char *name; + char *tx_name; uint16_t counter_id; + uint16_t counter_tx_id; } AppLayerCounters; AppLayerCounters applayer_counters[FLOW_PROTO_MAX][ALPROTO_MAX]; @@ -98,6 +100,13 @@ static void AppLayerIncFlowCounter(ThreadVars *tv, Flow *f) } } +void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step) +{ + if (likely(tv)) { + StatsAddUI64(tv, applayer_counters[f->protomap][f->alproto].counter_tx_id, step); + } +} + int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet *p, Flow *f, TcpSession *ssn, TcpStream *stream, @@ -696,31 +705,49 @@ void AppLayerSetupCounters() for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { if (alprotos[alproto] == 1) { char *str = "app_layer.flow."; + char *tx_str = "app_layer.tx."; char *alproto_str = AppLayerGetProtoName(alproto); int alproto_len = strlen(alproto_str) + 1; uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); + size_t size; if (AppLayerParserProtoIsRegistered(ipprotos[ipproto], alproto) && AppLayerParserProtoIsRegistered(other_ipproto, alproto)) { - applayer_counters[ipproto_map][alproto].name = - SCMalloc(strlen(str) + alproto_len + strlen(ipproto_suffix)); + size = strlen(str) + alproto_len + strlen(ipproto_suffix); + applayer_counters[ipproto_map][alproto].name = SCMalloc(size); if (applayer_counters[ipproto_map][alproto].name == NULL) { return; } - snprintf(applayer_counters[ipproto_map][alproto].name, - strlen(str) + alproto_len + strlen(ipproto_suffix), - "%s%s%s", str, alproto_str, ipproto_suffix); + snprintf(applayer_counters[ipproto_map][alproto].name, size, + "%s%s%s", str, alproto_str, ipproto_suffix); + if (AppLayerParserProtocolIsTxAware(ipprotos[ipproto], alproto)) { + size = strlen(tx_str) + alproto_len + strlen(ipproto_suffix); + applayer_counters[ipproto_map][alproto].tx_name = SCMalloc(size); + if (applayer_counters[ipproto_map][alproto].tx_name == NULL) { + return; + } + snprintf(applayer_counters[ipproto_map][alproto].tx_name, size, + "%s%s%s", tx_str, alproto_str, ipproto_suffix); + } } else { - applayer_counters[ipproto_map][alproto].name = - SCMalloc(strlen(str) + alproto_len); + size = strlen(str) + alproto_len; + applayer_counters[ipproto_map][alproto].name = SCMalloc(size); if (applayer_counters[ipproto_map][alproto].name == NULL) { return; } - snprintf(applayer_counters[ipproto_map][alproto].name, - strlen(str) + alproto_len, - "%s%s", str, alproto_str); + snprintf(applayer_counters[ipproto_map][alproto].name, size, + "%s%s", str, alproto_str); + if (AppLayerParserProtocolIsTxAware(ipprotos[ipproto], alproto)) { + size = strlen(tx_str) + alproto_len; + applayer_counters[ipproto_map][alproto].tx_name = SCMalloc(size); + if (applayer_counters[ipproto_map][alproto].tx_name == NULL) { + return; + } + snprintf(applayer_counters[ipproto_map][alproto].tx_name, size, + "%s%s", tx_str, alproto_str); + } } } } @@ -742,6 +769,11 @@ void AppLayerRegisterThreadCounters(ThreadVars *tv) uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); applayer_counters[ipproto_map][alproto].counter_id = StatsRegisterCounter(applayer_counters[ipproto_map][alproto].name, tv); + + if (AppLayerParserProtocolIsTxAware(ipprotos[ipproto], alproto)) { + applayer_counters[ipproto_map][alproto].counter_tx_id = + StatsRegisterCounter(applayer_counters[ipproto_map][alproto].tx_name, tv); + } } } } @@ -764,6 +796,10 @@ void AppLayerDeSetupCounters() applayer_counters[FlowGetProtoMapping(ipprotos[ipproto])][alproto].name = NULL; } } + if (applayer_counters[FlowGetProtoMapping(ipproto)][alproto].tx_name) { + SCFree(applayer_counters[FlowGetProtoMapping(ipproto)][alproto].tx_name); + applayer_counters[FlowGetProtoMapping(ipproto)][alproto].tx_name = NULL; + } } } } diff --git a/src/app-layer.h b/src/app-layer.h index d138cd24f066..e7e83c629230 100644 --- a/src/app-layer.h +++ b/src/app-layer.h @@ -143,4 +143,6 @@ void AppLayerRegisterGlobalCounters(void); void AppLayerUnittestsRegister(void); #endif +void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step); + #endif From d6f051cdf94a060139580377074982e85506aba3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Sep 2016 17:10:16 +0200 Subject: [PATCH 1756/2553] http: removed unused flags --- src/app-layer-htp.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 859979fbeb54..a2ad92b9c06d 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -133,13 +133,6 @@ enum { HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER, }; -#define HTP_PCRE_NONE 0x00 /**< No pcre executed yet */ -#define HTP_PCRE_DONE 0x01 /**< Flag to indicate that pcre has - done some inspection in the - chunks */ -#define HTP_PCRE_HAS_MATCH 0x02 /**< Flag to indicate that the chunks - matched on some rule */ - typedef struct HTPCfgDir_ { uint32_t body_limit; uint32_t inspect_min_size; @@ -192,16 +185,6 @@ typedef struct HtpBody_ { #define HTP_FILENAME_SET 0x08 /**< filename is registered in the flow */ #define HTP_DONTSTORE 0x10 /**< not storing this file */ -#define HTP_TX_HAS_FILE 0x01 -#define HTP_TX_HAS_FILENAME 0x02 /**< filename is known at this time */ -#define HTP_TX_HAS_TYPE 0x04 -#define HTP_TX_HAS_FILECONTENT 0x08 /**< file has content so we can do type detect */ - -#define HTP_RULE_NEED_FILE HTP_TX_HAS_FILE -#define HTP_RULE_NEED_FILENAME HTP_TX_HAS_FILENAME -#define HTP_RULE_NEED_TYPE HTP_TX_HAS_TYPE -#define HTP_RULE_NEED_FILECONTENT HTP_TX_HAS_FILECONTENT - /** Now the Body Chunks will be stored per transaction, at * the tx user data */ typedef struct HtpTxUserData_ { From c0f93503b76b4b567b64fe7c8d7220a85a0f1770 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 26 Sep 2016 15:53:48 +0200 Subject: [PATCH 1757/2553] util-decode-der-get: fix coverity warning *** CID 1373380: Control flow issues (DEADCODE) /src/util-decode-der-get.c: 126 in UtctimeToTime() 120 year = strtol(yy, NULL, 10); 121 if (year >= 50) 122 snprintf(buf, sizeof(buf), "%i%s", 19, utctime); 123 else if (year < 50) 124 snprintf(buf, sizeof(buf), "%i%s", 20, utctime); 125 else >>> CID 1373380: Control flow issues (DEADCODE) >>> Execution cannot reach this statement: "goto error;". 126 goto error; 127 128 time = GentimeToTime(buf); 129 if (time == -1) 130 goto error; 131 --- src/util-decode-der-get.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/util-decode-der-get.c b/src/util-decode-der-get.c index 413c43158140..747bf4b4226b 100644 --- a/src/util-decode-der-get.c +++ b/src/util-decode-der-get.c @@ -120,10 +120,8 @@ static time_t UtctimeToTime(char *utctime) year = strtol(yy, NULL, 10); if (year >= 50) snprintf(buf, sizeof(buf), "%i%s", 19, utctime); - else if (year < 50) - snprintf(buf, sizeof(buf), "%i%s", 20, utctime); else - goto error; + snprintf(buf, sizeof(buf), "%i%s", 20, utctime); time = GentimeToTime(buf); if (time == -1) From 44c846f2f8558094344344142d04e71d72b7466c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 27 Sep 2016 09:07:10 -0600 Subject: [PATCH 1758/2553] tls-json: make tls events direction sensitive Previously the src/dest ips in TLS events would differ between IDS and IPS modes. Make the header creation direction sensitive so they are identical in both modes. --- src/output-json-tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 34a12158e8f8..f1accdde3281 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -160,7 +160,7 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, ssl_state->server_connp.cert0_subject == NULL) return 0; - json_t *js = CreateJSONHeader((Packet *)p, 0, "tls"); + json_t *js = CreateJSONHeader((Packet *)p, 1, "tls"); if (unlikely(js == NULL)) return 0; From 1f4725fcaba4ecd2e68f032a5056377d538a0519 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 27 Sep 2016 09:38:42 -0600 Subject: [PATCH 1759/2553] detect-tls: make check on fingerprint directional --- src/detect-tls.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/detect-tls.c b/src/detect-tls.c index 6a0830a3dea5..f61265957ab2 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -653,13 +653,20 @@ static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ int ret = 0; - if (ssl_state->server_connp.cert0_fingerprint != NULL) { + SSLStateConnp *connp = NULL; + if (flags & STREAM_TOSERVER) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_fingerprint != NULL) { SCLogDebug("TLS: Fingerprint is [%s], looking for [%s]\n", - ssl_state->server_connp.cert0_fingerprint, + connp->cert0_fingerprint, tls_data->fingerprint); if (tls_data->fingerprint && - (strstr(ssl_state->server_connp.cert0_fingerprint, + (strstr(connp->cert0_fingerprint, tls_data->fingerprint) != NULL)) { if (tls_data->flags & DETECT_CONTENT_NEGATED) { ret = 0; From 6d7c0e827441ea1bb18c4b7d25fa8a3881d61a17 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 6 Nov 2015 19:01:15 +0100 Subject: [PATCH 1760/2553] docs: sample of sphinx docs --- doc/sphinx/.gitignore | 2 + doc/sphinx/Makefile | 192 +++++++++ doc/sphinx/_static/.gitignore | 0 doc/sphinx/conf.py | 285 ++++++++++++++ doc/sphinx/fast-pattern.rst | 4 + doc/sphinx/http-keywords.rst | 363 ++++++++++++++++++ doc/sphinx/http-keywords/Legenda_rules.png | Bin 0 -> 13544 bytes doc/sphinx/http-keywords/client_body.png | Bin 0 -> 18115 bytes doc/sphinx/http-keywords/client_body1.png | Bin 0 -> 39183 bytes doc/sphinx/http-keywords/cookie.png | Bin 0 -> 40424 bytes doc/sphinx/http-keywords/cookie1.png | Bin 0 -> 48347 bytes doc/sphinx/http-keywords/fast_pattern.png | Bin 0 -> 11808 bytes doc/sphinx/http-keywords/file_data.png | Bin 0 -> 11858 bytes doc/sphinx/http-keywords/header.png | Bin 0 -> 16340 bytes doc/sphinx/http-keywords/header1.png | Bin 0 -> 38150 bytes doc/sphinx/http-keywords/http_server_body.png | Bin 0 -> 9187 bytes doc/sphinx/http-keywords/http_uri.png | Bin 0 -> 54871 bytes doc/sphinx/http-keywords/method.png | Bin 0 -> 15701 bytes doc/sphinx/http-keywords/method1.png | Bin 0 -> 24326 bytes doc/sphinx/http-keywords/method2.png | Bin 0 -> 18669 bytes doc/sphinx/http-keywords/request.png | Bin 0 -> 70462 bytes doc/sphinx/http-keywords/request2.png | Bin 0 -> 49677 bytes doc/sphinx/http-keywords/response1.png | Bin 0 -> 80433 bytes doc/sphinx/http-keywords/stat-code1.png | Bin 0 -> 25336 bytes doc/sphinx/http-keywords/stat_code.png | Bin 0 -> 2295 bytes doc/sphinx/http-keywords/stat_msg.png | Bin 0 -> 2009 bytes doc/sphinx/http-keywords/stat_msg_1.png | Bin 0 -> 25055 bytes doc/sphinx/http-keywords/uri.png | Bin 0 -> 23158 bytes doc/sphinx/http-keywords/uri1.png | Bin 0 -> 5020 bytes doc/sphinx/http-keywords/uricontent.png | Bin 0 -> 53276 bytes doc/sphinx/http-keywords/uricontent1.png | Bin 0 -> 6263 bytes doc/sphinx/http-keywords/urilen.png | Bin 0 -> 26395 bytes doc/sphinx/http-keywords/urilen1.png | Bin 0 -> 49672 bytes doc/sphinx/http-keywords/user_agent.png | Bin 0 -> 30094 bytes doc/sphinx/http-keywords/user_agent_match.png | Bin 0 -> 270675 bytes doc/sphinx/index.rst | 20 + doc/sphinx/meta.rst | 168 ++++++++ doc/sphinx/payload-keywords.rst | 7 + doc/sphinx/rules.rst | 10 + doc/sphinx/what-is-suricata.rst | 68 ++++ 40 files changed, 1119 insertions(+) create mode 100644 doc/sphinx/.gitignore create mode 100644 doc/sphinx/Makefile create mode 100644 doc/sphinx/_static/.gitignore create mode 100644 doc/sphinx/conf.py create mode 100644 doc/sphinx/fast-pattern.rst create mode 100644 doc/sphinx/http-keywords.rst create mode 100644 doc/sphinx/http-keywords/Legenda_rules.png create mode 100644 doc/sphinx/http-keywords/client_body.png create mode 100644 doc/sphinx/http-keywords/client_body1.png create mode 100644 doc/sphinx/http-keywords/cookie.png create mode 100644 doc/sphinx/http-keywords/cookie1.png create mode 100644 doc/sphinx/http-keywords/fast_pattern.png create mode 100644 doc/sphinx/http-keywords/file_data.png create mode 100644 doc/sphinx/http-keywords/header.png create mode 100644 doc/sphinx/http-keywords/header1.png create mode 100644 doc/sphinx/http-keywords/http_server_body.png create mode 100644 doc/sphinx/http-keywords/http_uri.png create mode 100644 doc/sphinx/http-keywords/method.png create mode 100644 doc/sphinx/http-keywords/method1.png create mode 100644 doc/sphinx/http-keywords/method2.png create mode 100644 doc/sphinx/http-keywords/request.png create mode 100644 doc/sphinx/http-keywords/request2.png create mode 100644 doc/sphinx/http-keywords/response1.png create mode 100644 doc/sphinx/http-keywords/stat-code1.png create mode 100644 doc/sphinx/http-keywords/stat_code.png create mode 100644 doc/sphinx/http-keywords/stat_msg.png create mode 100644 doc/sphinx/http-keywords/stat_msg_1.png create mode 100644 doc/sphinx/http-keywords/uri.png create mode 100644 doc/sphinx/http-keywords/uri1.png create mode 100644 doc/sphinx/http-keywords/uricontent.png create mode 100644 doc/sphinx/http-keywords/uricontent1.png create mode 100644 doc/sphinx/http-keywords/urilen.png create mode 100644 doc/sphinx/http-keywords/urilen1.png create mode 100644 doc/sphinx/http-keywords/user_agent.png create mode 100644 doc/sphinx/http-keywords/user_agent_match.png create mode 100644 doc/sphinx/index.rst create mode 100644 doc/sphinx/meta.rst create mode 100644 doc/sphinx/payload-keywords.rst create mode 100644 doc/sphinx/rules.rst create mode 100644 doc/sphinx/what-is-suricata.rst diff --git a/doc/sphinx/.gitignore b/doc/sphinx/.gitignore new file mode 100644 index 000000000000..8b77e79c6645 --- /dev/null +++ b/doc/sphinx/.gitignore @@ -0,0 +1,2 @@ +!Makefile +_build diff --git a/doc/sphinx/Makefile b/doc/sphinx/Makefile new file mode 100644 index 000000000000..12d28b7a11a4 --- /dev/null +++ b/doc/sphinx/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Suricata.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Suricata.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Suricata" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Suricata" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/doc/sphinx/_static/.gitignore b/doc/sphinx/_static/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py new file mode 100644 index 000000000000..a5af0169ea2c --- /dev/null +++ b/doc/sphinx/conf.py @@ -0,0 +1,285 @@ +# -*- coding: utf-8 -*- +# +# Suricata documentation build configuration file, created by +# sphinx-quickstart on Fri Nov 6 10:12:25 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Suricata' +copyright = u'2015, OISF' +author = u'OISF' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2.1dev' +# The full version, including alpha/beta/rc tags. +release = '3.0dev' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +#html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Suricatadoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Suricata.tex', u'Suricata Documentation', + u'OISF', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'suricata', u'Suricata Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Suricata', u'Suricata Documentation', + author, 'Suricata', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/doc/sphinx/fast-pattern.rst b/doc/sphinx/fast-pattern.rst new file mode 100644 index 000000000000..17be89987977 --- /dev/null +++ b/doc/sphinx/fast-pattern.rst @@ -0,0 +1,4 @@ +Fast Pattern +============ + +Just a place holder now to demontrate linking. diff --git a/doc/sphinx/http-keywords.rst b/doc/sphinx/http-keywords.rst new file mode 100644 index 000000000000..e4363c79ce4c --- /dev/null +++ b/doc/sphinx/http-keywords.rst @@ -0,0 +1,363 @@ +:tocdepth: 2 + +HTTP Keywords +============= + +There are additional content modifiers that can provide +protocol-specific capabilities at the application layer (if you are +unfamiliar with content modifiers, please visit the page [[Payload +keywords]]). These keywords make sure the signature checks only +specific parts of the network traffic. For instance, to check +specifically on the request URI, cookies, or the HTTP request or +response body, etc. + + +Use ``http_method`` to match on the HTTP request method, ``http_uri`` +or ``http_raw_uri`` to match on the request URI, ``http_stat_code`` to +match on the response status code and ``http_stat_msg`` to match on the +response status message. + +It is important to understand the structure of HTTP requests and +responses. A simple example of a HTTP request and response follows: + +HTTP request +------------ + +:: + + GET /index.html HTTP/1.0\r\n + +GET is a request **method**. Examples of methods are: GET, POST, PUT, +HEAD, etc. The URI path is ``/index.html`` and the HTTP version is +``HTTP/1.0``. Several HTTP versions have been used over the years; of +the versions 0.9, 1.0 and 1.1, 1.0 and 1.1 are the most commonly used +today. + +HTTP response +------------- + +:: + + HTTP/1.0 200 OK\r\n + + some page + + +In this example, HTTP/1.0 is the HTTP version, 200 the response status +code and OK the response status message. + +Another more detailed example: + +Request: + +.. image:: http-keywords/request.png + +Response: + +.. image:: http-keywords/response1.png + +Request: + +.. image:: http-keywords/request2.png + +Although cookies are sent in an HTTP header, you can not match on them +with the ``http_header`` keyword. Cookies are matched with their own +keyword, namely ``http_cookie``. + +Each part of the table belongs to a so-called *buffer*. The HTTP +method belongs to the method buffer, HTTP headers to the header buffer +etc. A buffer is a specific portion of the request or response that +Suricata extracts in memory for inspection. + +All previous described keywords can be used in combination with a +buffer in a signature. The keywords ``distance`` and ``within`` are +relative modifiers, so they may only be used within the same +buffer. You can not relate content matches against different buffers +with relative modifiers. + +http_method +----------- + +With the ``http_method`` content modifier, it is possible to match +specifically and only on the HTTP method buffer. The keyword can be +used in combination with all previously mentioned content modifiers +such as: ``depth``, ``distance``, ``offset``, ``nocase`` and ``within``. + +Methods are: **GET**, **POST**, **PUT**, **HEAD**, **DELETE**, **TRACE**, +**OPTIONS**, **CONNECT** and **PATCH**. + +Example of a method in a HTTP request: + +.. image:: http-keywords/method2.png + +Example of the purpose of method: + +.. image:: http-keywords/method.png + +.. image:: http-keywords/Legenda_rules.png + +.. image:: http-keywords/method1.png + + +http_uri and http_raw_uri +------------------------- + +With the ``http_uri`` and the ``http_raw_uri`` content modifiers, it +is possible to match specifically and only on the request URI +buffer. The keyword can be used in combination with all previously +mentioned content modifiers like ``depth``, ``distance``, ``offset``, +``nocase`` and ``within``. + +To learn more about the difference between ``http_uri`` and +``http_raw_uri``, please read the information about [[HTTP-uri +normalization]]. + +Example of the URI in a HTTP request: + +.. image:: http-keywords/uri1.png + +Example of the purpose of ``http_uri``: + +.. image:: http-keywords/uri.png + +Example of the purpose of ``http_raw_uri``: + +#.. image:: http-keywords/raw_uri.png + +uricontent +---------- + +The ``uricontent`` keyword has the exact same effect as the +``http_uri`` content modifier. ``uricontent`` is a deprecated +(although still supported) way to match specifically and only on the +request URI buffer. + +Example of ``uricontent``: + +.. image:: http-keywords/uricontent.png + +The difference between ``http_uri`` and ``uricontent`` is the syntax: + +.. image:: http-keywords/uricontent1.png + +.. image:: http-keywords/http_uri.png + +When authoring new rules, it is recommended that the ``http_uri`` +content modifier be used rather than the deprecated ``uricontent`` +keyword. + +http_header and http_raw_header +------------------------------- + +With the ``http_header`` content modifier, it is possible to match +specifically and only on the HTTP header buffer. This contains all of +the extracted headers in a single buffer, except for those indicated +in the documentation that are not able to match by this buffer and +have their own content modifier (e.g. ``http_cookie``). The modifier +can be used in combination with all previously mentioned content +modifiers, like ``depth``, ``distance``, ``offset``, ``nocase`` and +``within``. + + **Note**: the header buffer is *normalized*. Any trailing + whitespace and tab characters are removed. See: + http://lists.openinfosecfoundation.org/pipermail/oisf-users/2011-October/000935.html. Match + on the ``http_raw_header`` buffer if you require the raw + (non-normalized) headers. + +Example of a header in a HTTP request: + +.. image:: http-keywords/header.png + +Example of the purpose of ``http_header``: + +.. image:: http-keywords/header1.png + +http_cookie +----------- + +With the ``http_cookie`` content modifier, it is possible to match +specifically and only on the cookie buffer. The keyword can be used in +combination with all previously mentioned content modifiers like +``depth``, ``distance``, ``offset``, ``nocase`` and ``within``. + +Note that cookies are passed in HTTP headers, but are extracted to a +dedicated buffer and matched using their own specific content +modifier. + +Example of a cookie in a HTTP request: + +.. image:: http-keywords/cookie.png + +Example of the purpose of ``http_cookie``: + +.. image:: http-keywords/cookie1.png + +http_user_agent +--------------- + +The ``http_user_agent`` content modifier is part of the HTTP request +header. It makes it possible to match specifically on the value of the +User-Agent header. It is normalized in the sense that it does not +include the _"User-Agent: "_ header name and separator, nor does it +contain the trailing carriage return and line feed (CRLF). The keyword +can be used in combination with all previously mentioned content +modifiers like ``depth``, ``distance``, ``offset``, ``nocase`` and +``within``. Note that the ``pcre`` keyword can also inspect this +buffer when using the ``/V`` modifier. + +An analysis into the performance of ``http_user_agent`` +vs. ``http_header`` is found at: +http://blog.inliniac.net/2012/07/09/suricata-http_user_agent-vs-http_header/ + +Normalization: leading spaces **are not** part of this buffer. So +"User-Agent: \r\n" will result in an empty ``http_user_agent`` buffer. + +Example of the User-Agent header in a HTTP request: + +.. image:: http-keywords/user_agent.png + +Example of the purpose of ``http_user_agent``: + +.. image:: http-keywords/user_agent_match.png + +http_client_body +---------------- + +With the ``http_client_body`` content modifier, it is possible to +match specifically and only on the HTTP request body. The keyword can +be used in combination with all previously mentioned content modifiers +like ``distance``, ``offset``, ``nocase``, ``within``, etc. + +Example of ``http_client_body`` in a HTTP request: + +.. image:: http-keywords/client_body.png + +Example of the purpose of ``http_client_body``: + +.. image:: http-keywords/client_body1.png + +Note: how much of the request/client body is inspected is controlled +in the [[suricata.yaml#Configure-Libhtp]], in the "libhtp" section, +via the ``request-body-limit`` setting. + +http_stat_code +-------------- + +With the ``http_stat_code`` content modifier, it is possible to match +specifically and only on the HTTP status code buffer. The keyword can +be used in combination with all previously mentioned content modifiers +like ``distance``, ``offset``, ``nocase``, ``within``, etc. + +Example of ``http_stat_code`` in a HTTP response: + +.. image:: http-keywords/stat_code.png + +Example of the purpose of ``http_stat_code``: + +.. image:: http-keywords/stat-code1.png + +http_stat_msg +------------- + +With the ``http_stat_msg`` content modifier, it is possible to match +specifically and only on the HTTP status message buffer. The keyword +can be used in combination with all previously mentioned content +modifiers like ``depth``, ``distance``, ``offset``, ``nocase`` and +``within``. + +Example of ``http_stat_msg`` in a HTTP response: + +.. image:: http-keywords/stat_msg.png + +Example of the purpose of ``http_stat_msg``: + +.. image:: http-keywords/stat_msg_1.png + +http_server_body +---------------- + +With the ``http_server_body`` content modifier, it is possible to +match specifically and only on the HTTP response body. The keyword can +be used in combination with all previously mentioned content modifiers +like ``distance``, ``offset``, ``nocase``, ``within``, etc. If the +response body is *gzip* encoded, it is first uncompressed for +inspection. + +Note: how much of the response/server body is inspected is controlled +in your [[suricata.yaml#Configure-Libhtp]], in the "libhtp" section, +via the ``response-body-limit`` setting. + +file_data +--------- + +With ``file_data``, the HTTP response body is inspected, just like +with ``http_server_body``. The ``file_data`` keyword works a bit +differently from the normal content modifiers; when used in a rule, +all content matches following it in the rule are affected (modified) +by it. + +Example:: + + alert http any any -> any any (file_data; content:"abc"; content:"xyz";) + +.. image:: http-keywords/file_data.png + +The ``file_data`` keyword affects all following content matches, until +the ``pkt_data`` keyword is encountered or it reaches the end of the +rule. This makes it a useful shortcut for applying many content +matches to the HTTP response body, eliminating the need to modify each +content match individually. If the response body is *gzip* encoded, it +is first uncompressed for inspection. + +Note: how much of the response/server body is inspected is controlled +in your [[suricata.yaml#Configure-Libhtp]], in the "libhtp" section +via the ``response-body-limit`` setting. + +**NOTE:** In 2.0.x, ``file_data`` is only supported for HTTP server +bodies (specified as flow direction **to_client**). Starting with +2.1-dev and above, ``file_data`` is handled more intelligently +per-protocol, supported with **to_server** for SMTP and **to_client** +for HTTP. + +urilen +------ + +The ``urilen`` keyword is used to match on the length of the request +URI. It is possible to use the ``<`` and ``>`` operators, which +indicate respectively *smaller than* and *larger than*. + +The format of ``urilen`` is:: + + urilen:3; + +Other possibilities are:: + + urilen:1; + urilen:>1; + urilen:<10; + urilen:10<>20; (bigger than 10, smaller than 20) + +Example: + +.. image:: http-keywords/urilen.png + +Example of ``urilen`` in a signature: + +.. image:: http-keywords/urilen1.png + +You can specify whether the inspected URI buffer is either the +normalized or the raw buffer by appending ``norm`` or ``raw``:: + + urilen:<5,raw; + +pcre +---- + +For information about the ``pcre`` keyword, check the [[pcre (Perl +Compatible Regular Expressions)]] page. + +fast_pattern +------------ + +For information about the ``fast_pattern`` keyword, check the +:doc:`fast-pattern` page. diff --git a/doc/sphinx/http-keywords/Legenda_rules.png b/doc/sphinx/http-keywords/Legenda_rules.png new file mode 100644 index 0000000000000000000000000000000000000000..c3e913340f7164fcdabf9db6754df8ebd2379aae GIT binary patch literal 13544 zcmZvD1ymd{*zMx3rD*YD#i3ZYxVsd0itFMOws=dSxVyW%dvSM%#i6jUxZ9(@JvndA znM@`*nIt2*_q*RWAu3AJSm>na0000>Rz^Y%0D$v)%~znpzow0(s&cOfI2Sc(F+j!m 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 EFR($N(EtDd literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/client_body.png b/doc/sphinx/http-keywords/client_body.png new file mode 100644 index 0000000000000000000000000000000000000000..d4ea6dba4756e7f83d7676ce297cd10dbcf3da2c GIT binary patch literal 18115 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

gpaI=ESU8>i|`zs`-aAfg)i; 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 N;@fwSvezbo{{v3_7(4&~ literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/cookie.png b/doc/sphinx/http-keywords/cookie.png new file mode 100644 index 0000000000000000000000000000000000000000..8e5c26262e4e76af3b0d62190a5b3e169949ed2b GIT binary patch literal 40424 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/cookie1.png b/doc/sphinx/http-keywords/cookie1.png new file mode 100644 index 0000000000000000000000000000000000000000..12293c3f41df7b2d870d370468b1d78ab54adde4 GIT binary patch literal 48347 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%0A((uqj#^~axOu=9dAy!W4US)>t}Gr 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 T{@OWrz{@2qt^leKH46AYN5n`f literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/fast_pattern.png b/doc/sphinx/http-keywords/fast_pattern.png new file mode 100644 index 0000000000000000000000000000000000000000..97163a50ab0ccce1ef7f13b5df6dddb1c52d7f43 GIT binary patch literal 11808 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 I0e%hnA1V0!c>n+a literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/header.png b/doc/sphinx/http-keywords/header.png new file mode 100644 index 0000000000000000000000000000000000000000..d78714c27672a30a34cfce230e12e4473dc1f071 GIT binary patch literal 16340 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 B0^I-r literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/header1.png b/doc/sphinx/http-keywords/header1.png new file mode 100644 index 0000000000000000000000000000000000000000..a255a0e61c0f421c079cd939326bb6f977db3520 GIT binary patch literal 38150 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�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

9$WDG%*(=Y19s4-+XP?Ll4#o2Ec?jwzqRm$;b9 z4il{GA%8GQr_cFiSCVw*ow-4-69&H9Kd<*uDoTyl?WL6V+^M=tH9yvFRgOYn=EFx_ zZDcF;7;s(2LUakUfS_bgzf$gOP1l+I)=j_9E!w-wR~+FNDvgx8&59<99&UiE^HSu4 zXYYz^OWU`+ibuPNc)JQiMO@LZ_`c5~C+Gh4sP_Gd>S#FUenoJ95p!p{*uM-zN(m`h zH+=~hrGel?q7(=buaiwe^={3MaS0Xp)e7}5gT>KgKYk|0vykvfVH&;W&j>G9SI4%(_;UCp-az{0%ne2sG&5e79+5ZXk2e?lW#GQN#2uW>ODRd$MTy%c zOf()_n{w$EgI{w_c->pdDIf9M6QIT(?y{>anIe>ucS-j#lm&jN@d=1X>(p4bJwLg zk}G@;CXrI2#?plo=4?1%%kkiAleFwK-qURmzLHR|F(j%3zG$0!$uhLqrU9guVkt*B zU|_FXFxUnhtcgT)r3w5uc^+V(WJV|$lqdu+4TR-s5Zq^*z8*(KC97dK!rzVh3F|Y8 zbMzF~Ctjw962Q)S3dIqCcf?*K2L(BtZwB=&wv$8;2$FHBMJ8V;i>y&r2)cf4Q7Ya_ z3Uzxhj1!!SR1m%y>p`G18A$FY6%KJ&A-_4m1{iR>vIY&2EH6S@;(l?3J9r~g5xO@I zAVHv6h_rTIi~HSQ#!0!c;);u+W-M>I*xO>}{Y5tv>-l-;5ybC%`uTR%`E+w~_i(S;3S$5K{mYre9<-OsAim{&R20X* z(C8dCHjgt$qGq@_!+-R$4vk2(R^S-q`z=oj3T%H(z|Z8$%_l4tf2HUyo`+5Q^ynn9E{M&rQPDDJ0&}k5+m-w%@yS#qyjm5HDj(8m2 zYK_oAQ-jD%aL8imk_fW-)hw!-^t{p_vuk7elv02P}lJRL1&!r z9095GTUUv#SGEfR|GQh!tE`@W)(PL|b)R^gpJ!qQm#f~qIL8rVBc-v!*%HHt%PfJx zj`7Eu{Bvps*OS6Ts;zhz(G}n4nK9A2oW|IsK(G7JtYe-B%3*2lTK$vcoGjc`Z(v3i z^z}q93yXc;ABa$g9L32=GcuR}9PiPxQ=TGKOn0jZ1`=a4J*He*WHbH=0Li$CnQu33 zTz8Iy_snE=TQ=ICpM&lx(LspUr!13`?L2tfRx^w&dFy`wwG-Dvpw)3%kb&7HQ9lv! z4bi(7c@aFzox~>YlsAk(djgoRImZ#9p+AZl6N|uHwlT~LxQ$1e;SO&%RmNnX=N+av zg&PygoxMCW4HL`E@#tfV*o@^jh^_}h$|-Yy^E@N7Y29&u2Hoswz!g=7yWZrt&X(NC z`(&@v+%A4T?nm6G7LJ8eY7SQX4?Gr@BSg!2yORiBv#t8;oy(w7&!8EjKx8XoxvyS3At=3iTk&R17k4>t#s zUA~`pD6%gLK!^2gb8e*e^|zOodZH2jx1guHXgCh`6R)r+F29L0S#2bq^C^nE=e|dz zL%ZqicjId9*6y331Bxg)MRJs&z8+CEJI;XeXcLE0}lm!`b8)MDcKPbj_X-kV&^ql5<-H1M(()<69@ zwXMMW1@|LAD==io=hv&mFuSEfWz&NUWWKSp%_|rnHzVY&bbA3EFbWFTh-`Bte3#oL z1#q;ad$_RjdlCWo*Zh5T{i#@g*!+U@e^NI-O?p0L1FUqR&Dk0#`>6lgf}^rfL<4}= zj!61>5H0l92KjMng}t6XE$j8iss|v_$&XCbz8tnjx1n%`eEcxG{1XiH8U7@?LsR;Z zbay?@-t~6fe!2O0z|}zfa!}yW(Y{~7nXTJs`cA%92m^(E7*C0 zn1zKMI@a(<(|`f!5hDU%C2$?+T1B^Bq7SrUveeKe z{+HB{`DcNv*X=Vau;tvdJZmzQTNMF37h&K0_NA$>?ftAvas310^RN5f&(E8Jb3DOf zdt5&n{}Y@$qkD@ChQg@9FT(gf2EIX{BcHE!m|Cj^C>^`~^Rc}Qp4yj+U_1$WTM;d_ zx6vTI@0M<*I5w3QC&#A$1teR|=HXQO8&bvvpq=F&y>78BIDGADnPPLDUsO>NKoE;P zNmnA~!n|tiMM{WLq8E3;M2t!pLN`DhB*1k!EIIo7SfO)SRzrtx`f%-3LNlr&P`{XT zPqZUe${=b`>pKi2&3x+8W`@GTo876djTul{cCvw6zuQQnsTI`3eP21301Lg#j={GC-ih1I#xh zSXqBj`F7N`?5@&P8$xmN`^{?5G3^_n0c8RFYFLV6*vNDChvr z@w>ElD2z3;`d4C#axvE(qks@}y=p3ddgfWqq&o>;Z@1v&pOh*Z@lz$f6WjblrXuG1 zZH~`pWAZ-r#aGw$NR{H8&N^b{GvhSZQSgs3fe7KqW@G^Vgpm6y{nK~ddOr!3iX^xY zK};J(uz_BZfYEq(uH1X5@>)v;d?=T5Jnl6GJ{lFOt(K2wIu5NE1-+!h+jiWtGCQb_ zq{3^?P%cQFSrfx2rGElGs$|c6RWdx#2K5w8c71Bft0n zyi67tKzGD=MH-eTR=cF%i?8Y^-W?qd>{uTR(7_vb(S7ZMjo$=dT|gL!{m0MYjmggF z58xx36t-a)NE;>e1ouw{QsFejG1Ha{SF_R(s^0WyHa}DN?c3Zy>7yK!>N5`SRxe92-t%_ppg7%JWMe z04Tm*v79bm0P%%3-xgMx&mgXpC%2kk{qG=L(b>s`bqZ*=_GO1|AvLlOrcQ-H-9v1adX5@eGt zGN*$)R@W16CNFrcoYpDnEvw!e-sTlFChrQiJ|Bd&vnYV7uXZAVUZEasyT4usK*bpt z*XZ5cEe69mU&k=x{x-uKq$UrMaEu>Z&hVcyH{t*bNO$N=HL(GPiB{6Z~$jeu20=!2z(4v*H3(yB3&4ji{5Sa; zo0tjD#s^ZSI2ics#8vWAfRp$#7C&F%h_>~(8rR^gbo2p>iwM9UdxPTV_6rk7tncGl zo0sh-o-_wa5P)SV|1;cm9Z;Y3nctyQ_ z-VR@A#v_Oq&Sy<*L|z=w1LAR4k9R({mwww@#C+lpZGMrNUM>qC@}@vW-}mP|>AVwu zllxhIqKDV!jrN}qu$S-eIYcR0ovuAT8*Tiy+BKXOwi+Celc6>G`*t2DgM$*X+II|! z1mFgV<+z9x04+kc?ZgYp4q@yyfm1r1gSHv5j3QxJ#eFuMKxs%+;bcT_A)7)I^8i!| zqn}v!??Q?-|JLPRifdi?+o-S#sGKXPfOaQ9Zoge?*XIuR@snLDekY;nN`;>zH#)OBLR@}?7r)6oYWK) z%5|WVlALd9yQ-obYcWCr)zJz`stLBaou|)BZ>jM(Dip$Bkk9?fwu;>Hg!EkVCW~sU zeWX--j88zBhF65tYf40!i9w+gWRBFk7r#S!{t?Pwl4zW7G+658l4UBvDu*gGK)aiN zEIy6OpVqK0Vkur9+&H(Ma0dVJUjxJhU-a3~(0@|KW*Zb!WD!1In#W7Z zo+~+8oLI0SCpCSKm*jj8VzX%f`vd~4ktc;i8FF|{qiYsafl_M1o-(nO}YSV?Bi*<&+JZS{&)>{Cup)6Y+<+HWVwC44yLS1tZq zO(j3nbLHz{U+pKqX1#S|D*GN+{-sTzEP6ry+7fj<(W3|K*_E^7`u0vjpJ*z*`&DF< ziZQnMSM@fHrg|onO6u_Cn;)T`6C3G&44rr73!V(9|4%RL-@fDjSbK?IFvaRhhlxA^ zXAW zPc}h(($M7sZL?L_KYwpuOH>t=a9aU!-A0?H^H(!tjs%mG+!}(THp-<-zcr4ozr)z`96B#lM1b8@m6_9{`*90fr z(dwTEIMY4k=!&flr-51?DLRi+Te?O*8X9Vrv0h6FdPnQrBBeVo)rszQ=aJpGLsjeL z?umPTNsIge*Zt%L$c_HnSz8c6D9c0yiuBUeX@_UK@JlI!hO z126%umDb}gX+c_zwhxE>K=UaMfD-3XpCg(g+jn6IQIj`zXB;1mmlz7eJJ2ctd;UxE z?Sa`-!!n4Q_3`KlM(G4Nt@*Wc9p^ceeFM0>-1^E$iK5lDN^O^u^WAN)_0?5dHu?bO z23&VN?kaN#JnhN)QE~JPyfbJ@-1U~RLxzX9=b1wJkd%@6?2q>C1cCo;>i%tpZN%%oD6{tyK5KP&)5A6)}Z_oHg<`T#ORIW9b4 z!1k(rdy`RHlgDH>?g|VLy(r6lwDI+K8?8r|*1Cneo?nW<(Jw9nA&@~*x|}K*0liaz zjQaa%C$_z?aK(_XW75@3=B~=2-Na%0Q-AWC$9UCrjgAFl>fLrY!0{8`DPo3pyUWnQ zAl`MG^x=pi6@n*wh6Fl8GuD4xf0D|iK(}C|;3G(DQ1t#W$=#>*)4?O2Zwl6Pzgs?Z z0eSyD=?TPRdBmm2A|=b4vV0MXliS{m_1LAgmoS;eQ)25lj7bP`nRVTy6qqh6G3WOJ zVGwIy2J?(O`PnT2js~z7)uIrn!wqI zTXlW?-naRqUY$KUL|ng_&$KO{yZwz)2_MhHrpn(lM^Jm)kh=WZ?B5&cjxpT5@~qY4tHj*g)m6Rrd1B^JXFb!X1G zOOwYGcDIpR&bWHH$p7Gaql@Uj|2Qb#W9jr=rAkF))^=*Bz%*xKFHcs+D} zX1$?eB;?=@_A!}ntz*>mwt1i%d;lHs+jeA3%?3dk6 z{dhC>`M{>{59i@?)%Y4odhX;9yL{;WzT zc3s3Vt|scyj^Qb6htieah?u{9ayDOI@8bsKB$ETyH9Fhts*qbI-!4m zx7RiKYGtsY>i?z&^iWrkkS;n%;#VAJ2(tv%gAmZK^zdK*yp%N#K$<*@zBK-Rp7?b7 zcS@2q8EKv1c85zO(s|wMb3d%Xi$jH6%L~2tIOe>#?lM=?mGo$U^;fQT=WjIhP@_Ar z1ZEoX!`=MctN+H1@wgB%otH-`%`qGCAm}`Ny^+NwRdV@OYFc)@-~-0w=(?WGg1I8x zB(npYGa>hQEaYmZ^kYTaYBfS@d$CYP-}_r*?kKtA`Hfv8&d^XrRW`FvEa{<^X3ts; zo-W%|;{JNZd~>&YWuc+=Obw=!?tl6fqPCay&K8U>ImjPQw=V)dGC2{A$aT0Kc{;XO z<$@K4;H$hAoK+_)MX^u58FjoYZ-shO&!4u{8n|qZSMe%V?k7kYEl(Dowk94Lxlqup z{gBG<|H+S=uE4aF!z=$<^ z9gaL^e>f8L+g>q&ulIaT|L#(LQLZGD-azm)2iM=_owCrn`o1mHbg`kW(juJIUpkf-J@IOURCP(1c+JS$YP0bS|7?Q1N0n*3lUBR;#NO;Y3`faM}$ z`upP>hbPxUSI1gV`C@4kStM`;g5+*w*2&#~eScaJGPCK`Pmy_%MDolJWp!~Z@s0Yb z?gz^?xVYe*l8~*@4k7{u`bsbZNHOt_0>m{IUR~GMj({cWCherl1)ZLT?|LchwgDfky|#T=!tkYg&^u2q@)Bx%Vw#YcqV`L~i+JR09!4!GiC#PW7Dy z0MISnk9RR^*pgdfeCYA)(V^!ss~MpJewAtRS0PdAIYr?q&Vqp*9D;IeiJjs1qt5ql8U=J5P^ZQB8 z!^1;hW4%&sqCTt9==XP_cb(cR+%H4D#n)ejXM1I2By0VcEAFrL(!cgE>a0$1u zft_%CX5jU?S!2v6NeUF97P)j;mC_aM;XiaFa5Q!C>bl>eaw@Aji-mY#TT3{nPSC;m ztcT&6v}<#6HCn9DxGd5a(~G~6I;u+cWZEDon}oXKR#r9MYJiR`BeK+%Ogns@sjza{{|gf zG8XvM1X0^D;alsn`4PzwVT|G%xV8EE_eAsxa+^n#$s!!%s39kFsfs>m4x6FfD?SIr zAp1i*1&zwSwkVKyn3|XiEy5jPZkTr@nunC~03aHP0TlxG!rewdh_{ibdg2p z^vCt&aW4s%zv)9D%boO@d@gkt#E+K&ciTak|O(H?gD`Tk_N zg01L*wboz6srQ~PIK@pHh53~#dWVm`?iJ7W6QwRhuQY3O)-GnT6|87ARW&}x7X-05 z9RCVu#nphu`9bNPo-ETi*)?b=DS_wj9iTCvu8*VudR$)T(B}^^IBVITDL+>5r|(Mm z7(c_?`1l;%N>lY|M-123fRziQ7jn43=H2BQaAI+%r5uL!kTMG)>$wN^kBMM^*Mp*a z4248-LA-jWYu{U9f6t8VIww|DFH&T5zTJRGIoY$BJ5xr|)2+m7KW0z7a&gG0v66IW zds?YE7(idBEL;zH=D9h#zr17*r{=#n|E!fH`XGs4(^80^h58Nx)GnV=`HcjcE3pH` z3LTQahiu@GSDOAFvukvD@_cg}xj&`1Cbf+AbQ9<%R2UcRVz2qNfy|LUR_A=9O7Cqx zv6K$@f(N;WOYfMh#)>)4H#xokGCA)poC>cTYD^WDhzKI5d%1dNO^F8;mYUb3#8ebN zHI#BjJs&Rn1>7;bcnbyma(l;neRTbM-UdFKzujg@Ew7L1LXOwr56;5#>7>lrN;*aQ zsxCt?<%x6KMhm!lk|Vm`C&|GA zG7ZbKTgz&=kw+MUo4+opMbzQxQ2Kv?|Ewx*eK1U|1qJYRJyEW@e-oW~vhJF1H!6V>1wWptlDV{Y*WN%v zF;UA?{z>yhW2qQ_s548Gr+p5uDle9Xm6!WjuX!qo5o?^l3PZy$R;PYG{R>OwXyNfx zPd{+k_?qln&2qc#7+%s-f%4X}ea}?XyFZHD|LGGt{Ym+1$%@Ox1SF|VHpq?QS0WX& z^O=0v%4yOVIOjLf-*J^=tB!X220N__^dZuoHoev@LIy1~glfB+=<%D|Z{c}U6X=v+ z%1I7Hh_m3IreGf)p!Mh?*A2_;YK7TFAn{p$cVInxU!Z;2em0xdG=1lLlPtlb~BCf z1q>4;K!{jS02W4apOOsNNI_gApkXImEt2eAN&S}M^HqF!vkn)GxsoL>%D{=-qnvi} z2BGxW_k2PgM)^OA|H!LX-lYF6{-gT8^#4(P`hV*Gr>g(A{(q|a-}e8XRsVm}v=8#G zuA!9Ze5H=GRD18uFdwwuYThptJ+^F%#81>wE>pXyb9Na`Q#iBcJg!Xz}_#JS%fyL2Acu!eeYO7=R8)ciL-U6~;P_ zWmb0Pz!4+e#<4JPqLJ4++x7qUITSu7#0E`VPHi!^Bt0l`aF*=CiH5Ba-JBJ>&Nl2` z->`%DB{{;b&daqFz5e{ZL;jsZ?&^G)5Py%-KVn*1NV@pY-L6Y|e!-rAK`4r~7&6~^ zuGdlk*HG>!o2wgBqK^5Zxh2*H>P}c^1-#QpODjYuMcA&@D<^o)aH+ za!-5T;^wTf{;+;*F4p|g({Du7^D(Uuo3xw!U!rl#y;hz^0SB`u@!rWN8i?~%dRv!I z;Uw>{;U9liLEU-IqvZzup0o^hT>??(zvp)i%iRLvs6P*98vVZbY8=avM4NHiq*kxz z7yxnH)~8ypx5pROA(f}tVjy5PuEwPMmmbbyNc-Qkj{t_19Xzv!*8?BU)3A*eA*TYX<;}0&!dO4~uiLN0n9HWV@u#_~XOFZ5l}t5y;+=8rCGA-V;;N3`iuQ z@N|HYbUN%0%p+mm$?Gi_g-y@Ki&G;0kig~cRQS+TOxiiX^`Ki@JYVU+s#3r^jM96~ zZ(#XSui*bpi4+4_g%_T7aDUtg#@GLc2`6zCw>_VbgnY$BS({HHx^%pDATMe8Bp(6ZyWjCwS&P7}}zf z{D9kJIpqk1W-DC%a42{$J;y9K@iNQ&^>THEMxv3g&a!+f%4k=_x328{;#3_Bo^?fN>itddXI2suD!%zO*ko(qMh`U8v8CIT*-q4q|h6_G(Dm zM6mtmTL0e2M&lZU0olQ0an5Rea^JSaM^`DItX6BI5O>m1StK-MZA<#}_!=pbP;3cKQ zql}Wfq}+dRc8GYa7e z(tF>_P`O;57L@xs{xc_|q5eh{W;B}*b=+MJn(&lb{m6(E@)O}H@oL?>kx|cmi4tK0 z6;q`6Kxi^~fy0@wW%jkHNoo94&uhwUhSG+a7-mPCw|#p#8nh&P7k9YiLb`PPmU^VT zr5ZaE^B~q?tK)TNA*hK2fX-nX7w;8h>D)iCOK)U*%N#Np>A#J?@jOh>T_1s)+E2ANN_hs(DrR2TqCDPg)hf;NL|=~|Pgoc~U-fm*!d(-*OE@AHbs z=hgkWuBXVzuVG2yV=5rc&LszBp9To$(bj0N2ycAFj&N(JEPF=b`3ec^j)G{0`@v{t zzae@fQC*Ps)A3E(U0oZDx@C&TP=_XlfaywtfRfiw=BwC}T1AB%BxXvLe`=Y$!*2;^AU_T8lKzjy;lC?{L5l%i@NRIK@Bdo< zU*-R<`ft6LO1>Bv8U$a%Y>yAjFt8GusgX4J!T0+^kq(-|Rr?;t4z(}t-{nk`AEJ0~ zuPt%jeyRlqKv->?d>lITNN|fUaFC7g$-pA+B6?fg-}$EO<6f^;{_AQNRC(N2(J@Bd zpZ9<3mlPsuER!BU4#`E1s@@cZu+cc(*3@bXJ9FvGtNy7#p=CfQx5I1cM{6vsffGQEg zgbKyI-F53^f!r7pH1v=Y$jhQ%2!2w!M-Gp^47Zoz&Eq`Nm-nEiP-mHtF@*P5un^Jq z28*#I_O7H4L@kFWll-*;Sq;#tu;ig~EHT_ip{6=N~5!#laRk)hNA z`1m4`A^e;w^nCd5w>T=j&)*_Zc|7gCm&-U$jOt)>;85HvPmiM265GgO<}%v5cmG-_ zh|5ZDEYL_fp<1sSKdnFnsmX<*^(+6}kE%P*PwyO6fbvQDzVpRQwu5jhk|8T8kx+z1 zldfm8O=_8S{-ufNhPUT_Pv7vR^q+urkVgS9v)z7Odg~KnPds8BM~Kq%<#Yxcm%O9a$3A zj&QI$zV7D64%f=c(bao8i?Bul2M7*D6e=3J4xg%Ad+hy~8!@m-x zGDE%aiu;ix9-&D=B0l+?M0jO=OD=EIaaFN# z5UH`vjN_1i9!1*)ny}6Y2hjzgry31*xB2f9EGkw+%H6Ws#WW9?7>bUqT?d&l;AVHi zhLNv8Oo9I}@AvePC@}e5QV$<^p^j-?@(5ui&H0p83F*9b`0c6e$`Uf}N~M(;v-11F zK}8#%zRJ+Ayo_!fQBi=h(_GAU>vap#joNVMz>jUuvC{dJD+$QDIRdELh4lgkV=dUy znHm~&YJN1YHatrC!7Y>2QP_d9<^f>MsTV@~Sy^iY5Oihrx3DNgl^}R`PuI;Fy?7=# zyQc*z#p@z+a$l`EJs=cb+jbr>~5{$-C=oqEKx+Pz(=zAz(?JN5Ub&jQ#yT=x3=y?L- zl?`PUZXRBDRU`aH+fec8!7#aFi{m}(xNHDECX>~jc^#&!M7o>0t8KC=(mZP2N&&xk zQ`Y=35X#1DMqoOpJzKMS^Qz7~7hZChHd(~DQr4hBWlurK@6~hs@MY!-rRsR|_&ovO z%TTb+mp5m1D(*5xKu#Xx=!>ut{%xVPWq!2YeBb*WM+H$vI$MWPh$^PA?n36Y^L5ffQL@YD@|z7!8| z{JQ>b0&a$#zbS`Wgci4}B@I2A(Mu>@CbOvJhiSJXeC9=ipC^{O{q3Wx&3SV@NQeOD zS@>*IU2PEVayxrdOR2MPy7mSVNa!|tud&2YeL7_J=6E6xrQ}J$7#o$Df=xQ(X0GUn$e9Cj9q?6>;de2s4IWk?#L0i*?BNTbm+{Xw&1!9{EQ$~8i z&x({M!U*k&W|f;_e3UB9m2bLc+lyBnvfd`DRsXzJ;0Y6Rom3?pk5<<>e`k@fTR;V@=~F@ zq{_IWHQM5=e^^gAk12nyb1oAud{^ZqXKX?zT! z=DZ))Mj8oZ^vdxXG?6nb{%kTnp^>HgV*Rfro_4gTihUuchp_AJa8Va`rqpbF(&)Dm z+1&9o&+Z6p4iNKvy~u}lK69+b4#-z|XYKQr*m;~Ucuo33_DLj?$tw;+FkmP{!@JZ^ zWA|0G!c=AfvWq3!rU7#kSxPccftXH+dt@0-a0L|cQm&)MWcyxx|BUqImfEbWAECGS z086an^6J_^v+SM%=Zu8=e0ru~o5QLV&bRh-p;fIf&E1oGD`1tvq|4(uoviKlBiU5r zz1$u+0`GD2jHHKDqsuj5ZB>cx=I3_P_|oNcrTF@qfc<3WQl^@B+8uLDHJ2qGxkO94 zcN%|L-}JFK)5;>>#?BGvdi62c)wO@*dimky!(8m^;+@2P_4*n?jLDoY^v%DUnL*5_ zzZr@aJ%bqWax>fgfLew2sP7a0rI255tefRx0Brn5$K9AK4IgW_z;|ob{(jJC|l$8#0q#vDFv$evbxx4sOXm%Fk`9kOLDe=Gh zji%iaXqMuGfP>?R8;PYfQ#eHjrIj(gAO9x{U>}K+#wH=)jUH?L)XCYbG#nEe)q*<* zlE2MSsbtJ7jw8$vgACpueon>k3RY8LsVdTUr)@{RHH50KW zn2sl4N4ZS5Y0T_Vkcv@&p0>pKZZj^I)1AXoWmqnu6<)GPXR(&U@GX)yQ}&CR&a;71 zB4N=sl2kgx(W!TT;kI`PqcW_U)^#FoO%7E!@|(Bz-ke8GQ&D*N^gTQA*0-@vPkIqy zU;4BAtkkWAEF=1+>%$kahIbds%k<6j5G=Onx@4L%Kf9i@#Yq`LgY31|(rQ~IfyfZxZU z2Q^kbeyt5`M+p?yc3Iw=k!TMibI;qf7K1KZQl0Jg$aPZyH%c4j;J(mft=3_3?pA4rX^LtcT@C^T7O{Lo z0ee~F*6zXgu;}ENczonRT)Bu6(xY~_VL-#*<~oniS!awBM2_^fa9$p3?rJk99%d$b+c|(ooe?z2*0D2I<{r3-+IkRE&wHAno9MP(}+1zKVRN1N@@TcPy4c7@^puVA$ zE&p0gB}-t{2>}G19wO`@n&H}_@5ZdTqC_qsZZx}aFf*WP?2ffGel>s`$Pr3XR)M7i zC?REqQarE#r1>f#hreh+F?amsWpNG7eOG32E_>JaQOZJ(AWUPb=3dx39iqmN9$9aM;BvrA<3AxSyKQ?-Qe}G2}=Qk<>jW0Ue zER!Tswtq3U7F*gPNS%dGyjU%;Vr)iF6P$dV$@adODx6xrO1#Y+o+hj=3dladGH43_ z%?B-Zo;VCs&7RKSX-2;K4Yf9td?;S z+zLfzPvkGW4@&RDdW9e6Bp^qyn4)3bybJe;KUTR@{Y**zcdjM8t-;r>^5ev>JXx*e zx*}9;{bah#4U!4bwwKkxc-mQWHbvNjRl?)?4(g^1qzKb8M3DehftuubsuZnxWP3c0 zDCZL*A}C@}WdJx-Uy_#`3}f0!wh4P!f&+#MorxawFn>9F_2Mb>{wd|#RS&cV8XB+;;=Bj~A$-Rlky*c*DCC-hLO z5ToZ(GF5oDs#tb<%<_y~EZ=}Q45z0NsUa#q7aXA=X^Mkm*5j|`)^)l+^lVHJQ9y>p?&ArpO zuUegqh~g6sb- ziyeQWK~r&r?3a*et(u}+IQo65<;3_H?|Rsie>om5!F8a7$z} zl_I-$4ofnL+NF1H6&lMAX%{hf$e6zLS*AWZEI( z{*)^V27v|yRFG?3(vL=u=>b!uWJL0`Yx^5pSoE}y_g^?z4;AdHh&75zsi;v_2^)#I z&we-VZd!@Aa1%aj@ojF??V1!GKOZ#_Jv(D_rXolT7+8h05uUhdXcTVXoc6WvnSnvb zhg?%VrtJH>9_++=RYMKmi>?{nUBK8_(MvEnDp=!bD7?<{4soX(msTvb+r=1hUqU6) zbe!McqE*QnmOc*v{JYESI`U;jnl9&1g26GNNRq=+BkD9ptO;|=eX{3j)6KTQrc9fd zJG7^glhXG5IjXm+|6+`wFlh!C?qp;|4?xiF^^{o!N|R5zJzF zBwfDTI){PJ-WZz^1cBt+E&56D+@7z~=sF+LamV1DQ(hJIe5#+h8$OO&HVM3o1LcDx z!t9E!SEuie3u}8yUz;yOzis#bXCq*g;VWAppMZ&ow`>ynglGN!PQS2Ii^gm3Z^w5K z)3>B5zhJrVE()K&i}R0741mXsmh(2*#I=dq8X? z8oQ?>G0t0#qYPR~X1pZ~He^GHp}GFHS&4cOG59p%mw9{i!%HC>SV_>SH1dNcBzuks|ti#i}8296p!}CSxOXldLGF=P9@1!y_ z5b*hK1y`<7YPjL){L&Zc&-2P-S}9we~GxwzOjP&@82kkvX}Tj-n$H_SH=(%8$=l2f!T`3OTTM2Dzl-L^KdD)yx`G)>!~ohwBDmefBxjD&>?Nk$-%Rz zHgAm|XSwz&M%<7^Z?X2;Si5~JPcuNgzb$nE`5Ot-F&qYqOM7zJ`E;>ZOeqXGxxaB< z%voI<>M1oDrL~vCXg?{pSUpPF`lpw9T0x%{sU#SvRIBITzsb{>*|N_}@2k*a!hUF-)iK~ek3mBAES8k){7xz2D)WFce<+Z1a zy57E+!cLOLiYn(;TkhpDZ#mH4l4Wl4+TiNlKbcG4m4XR=2foArl#v1 zyKxJ_f+aghJRCTcyZ+b{b8wr(ZQ+(29fGNFSo}&IIy?wVpaMN zFZX3@S!M6diB*eKM=ll8=d6>dAiw^s>%N#>B+Fu)ijen=c}=?9Ma9=5o8Jx+J_?40 zg_SKDeZ{`Z*V8-6(0~m6nG+u2x<3px}nx~tS zE)$#t5G4FhigyJGjyNVH-FVlJym@$do9%FM8TX2kAE~k5JnLx5PVb;4$%lQg!5c{g#sKN+&CnWFEe7${<`^FIY@v8^%2v~}<*Zuz5CA_rj5>u*n zV5s=D`-l!GWfCZg^xb<=C5+0A^)vJ+cjl3uNBwl|8SF5%{stZ4Fcj&X6=z zxRud?9Bi;l^=Tv zJpLsq8>u^uM-a1CE-dr$KeHRaSw0 zr1O(uCcZ#vj-B$;a!i{T{#^Q%NbEeZ9G7hLC$m@V(*lM!Qr1c38PDc=^#C9_#5pzE zj8%N>IcToBh2|OOmHRh!A75P^#L7<6J~P1Y9b{SMO0@bbWOn(C!5`7&7RGe{%^__|5PX$S=W zvhU&hYAnTj&krbL8Nb7U>Z7=s=R_p&J4V^J@RV; zsv`wfyiY??2a?vu+fr&m!wDpp!zUkd2{J@K8X*N`!URfkkCINvQ;wf~0`2X)*N;wP zuTORvsCrx$KsKTZlIg8_O#JAkOy$za+m`@f<_~s{l3sCOSzl{4+}maGbh5gM8YR-++1Ns5HsVM!xiw&*{;cG zWuQ`ZJrbQ&_BoC6iIA;Sm4U36<40AOiLN8kAy5Hk*(=oJI4E0}QKy6g6)WvzQ~49~ z%lylFnad7W)Y8FE7XH6VnXHZDdY;SL(0$88{Tad)&>-YDeW2coV4q??bfZPNo7rI~^~NI&L5-P0m|ac9U`aKf`@rr7zv?{kdzd9nm@yz%(?}jy?NyCJU|{)tjs! z$Z*v5Ax@91DDfo*`L9N0=K8wJD8I+ZF&|6%x#G9K`Ux$u4DXG>&`69^i-VA%Y%&KJ&$s2R|x!6mXBQK=NCxM&2iYXAgjy_G?T6s4>mux?>9I) zOfOvQ6pWt*DahP!^3T`ZWTs&xbZ0F%xEjr!RlmITVD!Bn%Hw87P(C~m<7j7cOTsW9 zD=pCRQ7N%ZEU-kiHnsaAPtyBE$oBhw)KhuFh{Le#SsP9H+{#EoSRqra;oH1W5UttS z*X6C2L5xr=b#B7{fx~hUJuyA@XR`YnbwccH)%hz&BsFBjB>-V#-s!d&CoeB)e6?M_ zB<838G9UNDHdz>iyqJB9b-aVrI)itCE+R*#P;jlO&D=$_iGffv*R;!)#sys{?^ouz z75Bw+{f*5yT!+i5pPrNTq69)Izj@8_m`l?L@wfSV4*aH8@6}H*6HZUtf|oY)rESzRv^Q-^}DL`7Gnv*vxbf8~`npL(W}>6eh+HnPsuw4aywrm*U3Tf+dr zS>!qM)%(6^{L6f0P08Nh=#E^0)r+-l9F5FmJq9BoX)w+$1 zAnS(U@h^A(~(D_7>WOg3{jMJh|H*Uh8>>C;tpcN1Qyq1 z1|A9&%-mVAa7OGRxBL@3+38MvRBW|>M`TdUk)E)gjcyhvVl|iVU}7c5LlI&O#ii^+ z?MisbT^)-UMlE${MWLjXZt(ebd8ZQVN`7dx$HGCXl%MM; z<{Rz5b!`Wp`IMPGGh9&g2}njcQ~a+0+|4(2>l8sT#ehaK1+54E#XaUhD?H194hOn> z90Uk;Gl8Jgo2SqwGJmpAj)T{TvL~S3AYR@P2hC>fYy6vgI^CrJ9cDyVh2)8eOi;S; zq$uJ4D~0eMwC%s(!hecAvMpW4Nm0ou!WQ>bc(?@QfzL^#@-4BaZo}&jP3Tm1cq+4% zB?R+aS9hW@f3F>>w~S8EvRBGqyd_&GmK&`j!@{-*OkOJYP!KT412@uK|L*KLpOls& zcKcbTcF|hSt#~Y`jQsDI;(sy3SJ*`2vK0Q;HxG@&xYgq*p$wsJq%UJ;foZSa6y$$)Q+9?%~e%b$I2~3hv ztJZpYIOsBH198g4**fNB$9~YnZMC;IkrEPT(sds=^gE zQH>SBV&TF%#3uj&2v9LoRj)Pw=0WEG2xC`NM{gOsAmT)j zl&L6uVlMmJ*FGX5QHtY&Uun2J)p6Y!nuby!HmOwMZczVSDca!KGk94tQ3ciz1Paj# z*)0Uo$0DHDEZp4m%P}0KBwb`ttw%Jp{c{~|kxa!R!BLMh5@s;m0b$_jKq!$T6gROe z4sEG&JlDRU74N;@&!cZHE}NH`Ek#34uHCW<^N7iUZvyYFHDTJSd=1+x^b10WNzii; z82)TjR@%~X=j(m;4%UoEQMotD7n4T)hnPq9PB1z~-z@?E>)pB6>&_21YE{%nN|T=X zc&WjJe+NM(HcnX&?fZp?>&u*0PZDzA6vW7YjRe?hCVhFbc~BhkzG6-zH2^&!F#XH$ z?>_l3fP)A|Q1IPq+dClJ_Yc;md*3!tzHryYbo6QQ#iH~6xo$Him+PSgMKj~4#EEnk z)3JQR^cny$3fGc1-8;r{=6As|B)TRr4a@=z+~u9B9Z}h^N`(S`2*X5-EC$xBmgpE8 znwGh?v|icT#@K262=kTe6UWarBS6m6SijuJ3bKrQw5s<%F?(bzXVjqPq?me`(q<5_ zaHTKgQ@jn2@BG(sXBYY6M|RsO=8qpidN?MCI2j>`-cdbQcjL>4jFFjZclX##O{?#F zRz4iVNy5|M`ljWtY9?RS=-S_~!K0vhrM)@wi5at}p4baw=@cvwFjRfG@|2e6GI$%# z+4Q$E(~ZHx(nIYfa*c-z4eQ_eNe%@}2ls|UC8+lUoxRPLQkc#Y9CX%c$pVSgFzv znt~|Wki8dUA&0-_WtMNgRwKT}yBTx@+gN{fB=X5|SyfZ({eV$WX*#8E$bnIkDx%fk zZZu0P?r-za$!8}KMO2hKS+m~sd10BCsNW}jrSN%XRrGq9dK+Fw`-m&Wf! zVE8S?BN!5EGMq-jt1q;&lgb&~|@6CIhI*8Ex*N=oK)a45OzgSgtQ(TN7x*4)u`^9&mF6=0c~^=#Zfl~m430rnj8#= zrZ8CU`>f>~S~I&sfo3{FRq!1oSb;|U;Zs^U9u@}^Ie&}1EY$68qcThx91wwPn~6dv z8NnA2>)lNIvP`8o3uM67r&a#0-z861DhR4a?K@SOdXk?oMh)lzGhzV0sL|Ws@F?nJHvvu9O4H!`bYFxt^LZ?pc+>20r43UpF^j^p z^JUG{4BCR%>Q>w?txQB9RAaxhN-J;L>F>b`6`T3sU6lJkSMzy9w}rYDb+fcOvcWr` ziOxwIy6OlSvt!s^c^LQRaZ664gkm~}{8_xL!;G7zli1JxRv;bj!U` z?;E1^qdtYs*7sS6wF$ycOIzog4t79$R0Q&4#!kwcBr8@uN`3k|eO${4$r12xHHsqN zdAJ-Y(EqvleN&FOULFA;q&M0wZjU>YdN)h@;xxQ!hZNzcOjDr8pc@e_Md^Vw16zE! z+Q+wbJ~HdF`~3Zt3};h3NiHG9@5bnG*-wu&jYQ{_2?6<5Z}2qDRg$po9cYnyr8m6f z+0j>J{(Ej)hF{(+bBI|7(gOW}Pat(byTf3V%C+5iGH(RlWS^z>?JN?l5^nD;Yp1`* zSI>e-?#~;K(e`EfXF5tsfh9RgWnb1-C4E8QsrBBc%8|dCU|-106R7T^#3cUDuWLp(Q zi#X+{kQ!T=dL8uEsu59g<5a=k+ZZl|uUoxl(R4f#|L*?AXu8cVUH{BXiK5?>bF~Ve z<4(^SuetNv@4f2zEHlC(mF}kx&r%GWi3=GFKfgW|C3}AUuQ4=28nXSrw2)SOkf^t@ z&X%-}))QH8Qr^sk7jB5(M|lwxNk}ZpU?m2o=KDME|C)cywN?m{Nno>D74(v9-b}As z=+YOg;GrKay}X}4jR;EEC}V|v9FFrG^>+5!+M>j;n%_a~>~O=Cd290sjya!*_OUI+ zWqbFSMv~`}+QSb>2z8k>#M>KB|KzepK{PFPX;NdOj#3i$aS)6%%J=cfNm75eS>??J z-P=?oq@4KmF{jfs+SU&w5r+_sd!ieESpwta4DKLqRmEQ&t4Id(K>Vc^8sHD_{d_jcLrObF|=QVQ83VBI8Tl6_PY8&W-VU^8jA3*VOUC2 zO<#G=P~P3s+&)oTyii9x!RD0X3o)%A*G{=smlM(6S9CU{!ydvA4OWV4nQrQO%(vJR3$})lo{KE{eWf|8LfnqyRCm_%LH*Jz>kS~ zqkF*yYq)t!;BX?B-O&{7bXnx__OFDR`oHa0r56pa%}Fvyaen@xR<@Z54XLPnfZyn5 zx+#F-J{QFNZD{>mJTH4b9dMhdb-J%@umqW$HjTaTxeb*iMLds3WZF-@Y%~;$SeT6c zJAka-dSj`a`#hKa@|&&de6X9*<9bi!cD{mWV^#4-6=YqTPAMM%BCif`viq&v76_XZ zVHfN0dyo_wD~TCKC!aTj(tZum;Cw@2PUpWJ#8Gtpdmj9t)BdErp-qz0swBdn=~ommQxL^`u~b-nMi+9`hvLZunI@sy-w*EBL1WT-v8tRjgJI> z()sbl6tqGG5E4cD7nz7KszLnA!6{c<<*p=AUg|kXpr3(F90B3PV?OV1GLWK|<2L`S zEjRi=xLlEs_F)Dle&McVfaPqMuWvD67B^2xH}A25ds|ARz78aI9qFM$^9>4mjiFg3 z+!L-(>}T#T@9-{ZC|*_;k1K}nDA1`J&M%KTiF1I^r4JR4BZAi+6ImnNj4vzq=~k~& zS`;@^Kf=j;HnfmJeZ)@K!5N=om1Cj_K;_cvmaMp@?w|Qi77kl( zqjLk$sQ2lX&0#6#2QQUC*vaGIEvLa8p26(X44UDGPEnl?z+%K)`Ixm zwhM(ElzM##_z+wFVXwWEQ^Oqp8e5!Le0F9G(x?(Dv-`9KM%D$A z*Z<|+@Hm4;d(|_sBlT5EMZFpW(rt-kG_|%8^Ci65P1)tVOWeY`_GA z+V@KMz$oAKT(|1^bhe z%&gRen4h$U-}Tj-%Se6z3Y4o6qeFGs-~PTwzHwB2gA%2qqQ^(-eDkkRkT0AkdDjA; zMs@-dkWsLhU*!c|0=_%sj}WRU-n{JuuUcEE>W|7s$&85hqT`Wl=7#>GPtS8ep0CnY z@)xdeUbjiTna{0~?Ec?+JMVWk+;@-1o~>Dz$%5^yy}bX*UIN0@{mwDkr20X^B8uN$aHab$}{B{{Phpi#v4P3KlgQN zlFbx@rH3|O+rjTZnjY|uZXmJtj2*9SzO#d~LYMDzvy3E=b7Wue;zSLUpF-+HOjrGR-V64_VWdp(QD%9X@=bOQ1yE0O;lR5$Ps!fO`5GF)AM@+57NgGEOYfctI)O6<)O0yvryRQ{fKbNh|=S}q> z;pe;|vgurm?s7Vh!$5EDjbN4}$v<8Pa7=V!NaNf&u3Oc+9bs|ob{Lm^G8CvNwCH_E z>n?n@zN0^h3>}q|;q|+DrfR3h!0^KBbjm!JdjvfVP%heLa#mjoA&u%H9%`g29e2$`iUS91oO>JEa zTV|P^q?cxF>~sqzZh3&kqb@^Pc1~3uK)8Fln3*~xWNY4a@fNiZY-`X|?VVD7{(4y4 zCc(f9d3)#V0ONP&x5Y8GKNo8WW2p1}>lg`IJt_$!GPc5o3Z&cqgn^R0%dQbwp-c<__L4BLUE7WPXc4=yjE1$9>WqP5J*C3we?VC5hKND?{ zZ7>z^pXR?ueh%9t$l}XXaZFU}WQ`AK^_|@AfISkT~F)5Y&Sf%>V6` z&9M9OU;>_Fl3bo`oG9FjIj3Y*&(5IA3{v{Sd^lg85TvHo#H9S8f|<#9e@hqd%FmmP zA&v3p#;AfM4mfyuvHAe}#UC=XruOv8O?M0PF&neJRES&w-aC@EhvUN$dy=F=LYQ`` z=bl4{#v9ht;*|PY`VS*=v1$OWdVMuD6lG?5EHga5MmoXh7R6RJRP@m!NlHi+v8l#nrBFzUg?ah*@~S8UA{n^&HHbQHKA_F#BMGevyV266&PX* zMSzgvqw$_5-~E8S!nROyUf%wYw0Ytc++8){g>j5$!?ddJunGP#2~BvIR+@O0g`>Jj zh$mq`JoalMz8sU758UJ)7U+(%@2}gnx=9(1%;8Q0DIXqe+yl28rd@UDf;JUnD>e)K zfs6UzNrx*DMJvL_SHgg^y7JyLGMMq4bEB^how=^sBAT8>$+>1a>0;e#{?hi~reUTL zAVhJU8HQMU?|1tJ!z1mP+-Sdfxpp05!i!AF;|(hWsk3<^0-Y{&{eqQxr=zaU54YzR zQbkF^y4Lf8TPYX=R!B7O368AjjR?4|&Ijpuy&5}ocObu66PNaVeMuqRSy{;lpr;C; z6vSVa@f9M{`mq9mAP*eEm+vw{v5rKUG36!j?@C^{CR2|Pqi8X82T%NLeHX?+q$Gp< zqdE^CIaN9Dns7Qs7C;`HQ};uCpht9xH9|@%A>%eK0dH;4Zr~e`RYLE)XmePzDU1Qp zF@oHwHPA#HfZJ2a!JA2J@xw#Qeg14Q5u-JkPEikLdAx7WTfEFSRR}7cLagn=neRc3 zSXmR3oj-X@o(v4+_q=u8dEv*?h}EzXBy=qM=>1yqAOO?u#FAzDt$ z=Q_<-5KqTNpfMBa4>hAQW}QgWhv0fI{T=-@X&dDf1qvd0`EM3u9+9qICM-lANm-=? zbccRxp_df>tI+zD^;|I~2%yE#&}h~*sk248 z9fwHvLm0VlQJYJBjiA}eWS3y77Atg-=hx+Kd2S}&G?|p)iJbdgbG0wYb z5B1;Q)l9zU2`2REOZpehbv0%I}+ zHAPbeIzwY+W6}E*1y6sI$=Xp-`7u}nRqgY|#hI{tCIVqT|iP05!yD}4R$4hj0 z{wYmabdvHX7Q*_qk1sl+CQ=VwOZG)4s;UErKf@iyz zjc#IqvUs!x%xoleP?akz3`7|y7_WnoZ}FG)AyFCn5+}iEWt(H8c6hw+ax8j0ueBo3 zi1y$8{kY+&$;C`OE_cdya*lBMuLDTEHDhYn@VKhEfX~PRJoH+I zD-gn!-zx^a#ZrP{tX@L8nAvwnkLFAm4`jKc)bPhcPwrMjj#H-O#?cWFv|1zBZW8A! zoOOSG#L=BrZr^T(>?mevI8)`r&56-Sh*wJL2P4z%#jsL z94zS-s22<4%3Yt1qLqqE#$;7&w;v)8-VIN$_ac4uc0C9w6)LKU;Q+h0tDAI51#Z$> z@P|eY&*M`HYK_^W$^|Bfram?j+`aSFY*fus=T4(R7VsQz0lpOp>bS>wE?c|! z&7(`+a;syVcl0WdT~(ma#pMvDS|xSOc+`?$jQYhEF{pQK*vdxo+K>v!ZGE_?5dbnl zBOKqk7{%`S9{^qoS5=50;Ue$edTgot3nV%W8X&^DvU+Rlm{t`d|Lz|j>tFqPV|B*K z`urs9iCbu0Fhyu^D0%daaoWOx z{s+(>b0`|+1!2+Xj%4fptb4R2e*_v=o+sW7O|VbFJCi8bipgTxWufmhKaq=NPCB}a zHdEB`C_sbTgzd|<18C`pqJ|kW*z!qNd%X27Mqt%X0rWeT3T{jj5DpyepNnTk0vSNC zNtLa<=p)SAI>cClNG}qw#8PeFIz}RtwHzD!;g_4w&qfz#TMLatC2Qbc;py?#*&5Sw zvB4?r)mKNbEmrBif;Ta|5?HsUpo2n)_{Td4wzFRb1;7nLhLSP^=UoJdNs^v| z535D0%ieFD$ttNso!piG?DJz-qvHYqvNF>48yi*Qw?52Ng5wubCBgEdkO+X~gY#2% zig%}x^By$%=W0mPcJEWYDZ{qru~PD*ceVVFWm`H$u*i!@lu5kbOFC7h)*0*cpKRYi3pnKV;z%;8(4$f(}q0MHql&^s^gJ^LN-J;(c-Z_;5 zgndXbZEB_8z8-#L#fV{3;ovXGCQ9|rl}*-%OT`PtCrE;)5pgC&q<{WgXdb2)C*Tw5 zm($;=787zt^Y?R;~_i;5j92$jfda-B63H_G~ApaZ)2z7 zAmcoL%Ok#NZ?dt&sVmEefEY&>UhTfJ4aqna?rFKwTM%ZPmJuz!yzu+k57W3m%6(cQ zT!m$5j{5|YG%s!Z!yUmUjyEk@$RzDRL|G;^`FziYz1Q6@Elw)IhOXE1qq2_+q6Qq% zmb%nG)^aD}O0mZFgqzCKCH$3z1%1{8v7+l@F{y1^n3^F$r61N@iDB5 z9`L5NFPu<<<(jPXLm{-OCFT-iKHM)5?~Ch5BF5oGers806Rtb^E&Wv^$?A6gU^f68 z)A!?Q?Nw~$o)lUqmTn^dvs~@?pOIQr|qs03%waVOXW{e z=bW+I<3U9Uq`22U?Rw%00;P;q{Y%!>k*f-Uy|+UDss-9N?v-fPr|&Vah299Qr`yZr zlPm5rmIxWn+ld^vLtB?UT9@5x=iFsDA4@k-|DU@4@!u-v?f*fS-RqYB7yQ@x|G|G< f^dCg-gs62D6?cJYtIz8emz*4dk+qUx+&}VJl_aAu6soW&c zl&-9zsHo`YqZJCdGxMeLZ@x!NSaQwF z#fk}*5mN&cihh*O_1Ip1cE(hm?X@uWK}^+lEPA^5r+axoHgos>^P5-Ale>$mpO4e% z$`pgknS;NZ_Qbe&BRV>?P+He-zD`CT-OR8iWHOQ5q?ml)$4Zz z%`iTzN|yZn&OTCCm%c6wl!mW%W!rAjprB>%vP?+r#kGBq?mX#8Bw%^l{lO%$uK4=$ zdw>USA9qG==0Za^iXoCcRo;yrgP`b7ztLIX?;2t*tG+O#nzaSJ`mMB{&W;-oW27_6 zHC_(sVvxty@j2z+q*&x6c_^Vez!dUuJ|uuKU%spLz6dSw@haw~#DjPuU$o(If1o9w zIWVk@K)fBjrDoNjzlyH@xrUSD?j06oJ{QfzWWd&77I!pX-VG(MpsEbQw@o*74JFx@ zBsmJQaUafd0_agIK`$(fJ35Qdi)l(}9M0R}Jb(zO`tHWH} zF&H_@?yILqTJGi4wIk%?lAC=#d(RO+4g&v(9sSKBTTdQY?>{U$^>L9B9CrQ`Rgk15 z`P*@IN7`ghza|IdICM&PH;j@WbbI0{@CV9a)SqT(so=U*Hjtyr5}ll+!>!W6s?Wi* zE47^7WjVg(W?WhEwA)1(nHnyeB!7y_@X<)neQ&l~#hM^I+WXQ@j9* zv@`d=IigzVi>{Ox^WPiHSE=|FVkYu5NC0rjA41OcUC}vZ-Qrd6ze%1q!iyaCOgiDa z=o8fwqvqgFuZm7O`&2iYCt&{yVjGud6uwDD5n^SUtmZMJ6ScK*7MqmryFBv4%gb-#a!+;O3GF+4{rK&%H~|GVh^mjff6+kKn3n6#05cn;@e{F83q}|XKUYuQ zXd|1@(a<%iRkszmSmZUo7lvPYY>6ar5c@o!S#Q%V^}Gf*<}D5ETio~R@*uG0t*;m@ zWF~@?tEQt)R4wewQ5$E`QyJuX~PVN z5;*+N?d($tkz9(OOfhqKpwXWC`Bb<-`&gTEf$Q0p`}Qo#s8u(BTt z)_7HSJ>WsSs=Du@xSWOIhK%HScHcDxHf3eo-9zWr% zJ-UIn;=PXw_;!=2hoC&tn}uZ$9gJ&4!gQth*;?Cv^%ZSS~S} zt~sWY2?w8XYGvR}eJo7Yj=5o(tk?EBjy z-7;Dj)D(8Ps`!;bcz9+JS`S7GGX+6=VqxQ%5fjkYbMJqcF%jdNb+kH-(oo&Jjy55k zXgm%)%dK7^MYMjYjQ;CWC^B_a982$i`Je zK)g^p35WCX_7KHI#cGb)~fcWC9HC0UYc#ur!EoL$@FsNe6 zYg|9zxfi1QOkE2IG z)zR%bLV+IiNa@wjQMPrNi?A$){9^-s$kW%Qy@zzd(cm1h(&38cmW^ZITY0#F{5i&} zFz|%)o*_X4{ddu;spb!8`q&dPA`fZh(NWqaU|W^sSZrwkQ%{P$t!-%e^6ty$f;P@# zKF$>BgzU6xcx9AeMP8q$_}Vx~JD)h&8ux{rs5t93^}{4_LBRQ(`?IDd#5}y%20cW{ zv>-1JI3wMx_IeKEysuWocS10=pvhh51I@|DqJs3Bf25$VdfBk$o6KGCe7>L|o_lvt z-M!AsSbcgvwLt}~nlV4h$HtliL_PnVB&p*|s=Di)XA|c$bt`V^B3Lr;r>On&Ia&$e zLAC?|O*jLycUl*m^n1*=?tr+t?-(aF;STuY-c)9Y&vXYy4*}|TEVSnj-Hx0BC6AH@ zWmtmW0VGTuHfwobm_@xx3B*xaGO&#{q|a!71JIMo$&YlZ^v!mMSvi6UOXY_FBUMF3Z7D>63pg6dD5q!TY1GBQwSR((rrA25bxV@6Y zIukI6sWLSy;-L3y>Lt5_>QK| zj)RZ?MAR)j=t@bM!UbFCeM3{QW9>rRA~1SZj8AdKKcM*dpeQWw@q#)j2@j#(+IhnW z{l{0vw@ekq;^n<4GZ8#ZCOIcQ8MKRr~0{zEyn5~9bMS@ zqX3}S<#coXd+QIDSrFj-jb6Liu};waekXQvHZA&zf3Tu?xoM3eL$N8S?P`s;J@G5e zYZO*V7Y|pjQ$@2&zF^O|hL<`yNNMTdm?_o}UbouM9^-pu47`T15fQh|S|e}HZ8@P4 zf9GNUmdZx3ILdXw{qbcmDG8I4mcz*G8)3x?za(-RvF18c@cNUUy1MydQ|k#kLO@i) z35&B9A|Kc9e#G{F*M{q!8$N(Dv9m8d;TPy7P}B7QI%-4|?6P&$5neXHi1?wlINYEq zwD9+5=WB~IK3uL;79f(QZq=`a?zm~ZGDMebNMfQQUv5P|yf_{4hAwAO84L5~w?=9Q z!%QZ*#|X}q%NMZRc*>Q}!(Z(0(hBz6A4IM%K{jj_EiA0q@2{=MG?$KSLKr8UTXj9s zWv$Cw;Zp1gl_6v%xLHq7`%&y3JN9;uqr22_P^+Vuy318`M*dV_=W(RynD&tDfJ^DO zHSinF(-pmXcaxXuA50wXf7iKsgBLT8D%fgbddcJN_C60>Qh|MZA#l;-Hrr%QI(7~; zj&P%&9)cc*W8=whh{fLX)M;cxe+T-L5Y7Q7D zXSOR0fHZ2BOldb19SHI%yxBPu1|Bq9I<4uzAtrZl%KF*U)!+Z4*B`Qhya2hf3FFuL zytMm=sF%5$0xlqyg_D4;Ib`F}9&5^1Qt=0gcUa1YbtAk0I15K1LyZONy;<+!M3N8Y z%ln5|F$fP==Wr=MpIux<&fLp-&PD)*hp8m1EZ(TKb~$vf>#;8Y4(DYP&7M#s`q=1pD9^>g$c!1pm}-(=kth$5XpN=n;pcR3l?%U~<|kLuDndPHFM?iyMDU1udyw*E-@ z;o}&smIyUPB~oL{sbGhv64e3K*Dna9tGJTLddGvKlyHVG7bj`NRpr<&S`{0?9S}^! zH$9yC=p*KgA|x1_)6UuyrcGz}FkK1NUmPls+@4 zCYOgQDZO+F*W8?@m~t*&_q}#K>|tE4uYa1@C`9vK_>jBN;WrdFXD~^wAF!2%=!FJv z%HOcBF)oauGt}^|uJct+`Wu0`o@{JM(k5I7djXr+r_a$JbB*t>&%An_XRnOsK2{66 z261zlc6WXrk0Y%5Sgy71gZH}>lzn5SGHwGdhiFvUO>$g6%Jc{U#tRj$oxnznqvN`l zFV^uy-RCEXrGQK6S!@f6FK(A5;b&unDvs%slTgB=`@hP!J+oJVUpZCFSv`JHf48A}fmz zLQH?KusQA?D}1Rbg+O-=>a3F6=ADl1`|g#1j_u=*`yT1-tyvet@uZVopvS34Y_;by zlUpX|Zn{SYJ6S>;o~!#-Yw1=VYW#c8lj31Qsndl^Y7xAOE6RsIJq#+kP``oAmhz=>pZmu$@ zn~fb%Upnjt8D`mns$$d3=7c}UJ+0<8z)lGVMATcX(JC4KqU;NZ zcN@1CPx)>DoX8dx2l>yZ)KqOwS`W!9a2})uhQW4H272wPct?5;KI_{%=S@_g+s((G z-MV12>6e4r-|I=m3Gw%PZCRIi+Cgc<3xVrcA#d$|-TlytZ}e1Uic&r*vGty`*%*OS z5K<2C-nE`gI-@?>W@*dx>ei%~`+T>3R(Egbl(C#8_XYalRlmi&PfE(~K6@JbY|)no zLbS+eIiJIt!A`OwvFw&}L8aCy*j3(x7**|lID{2dM1!vA`|_9fOoY!*oUx4d8QT3U z_wr+UxLmk#bH%bQ85OTJGM3!4k?(NsowF)6&WW`sDEKjdrtG3S*!M3;%?cci?Pn!Q z<Bb(IwY3&QU&xCVo8Qc*Ce<+#xo52ktXMQ6u*EJmz*=XWZx%?KI{)i@mJ#)^&6f zYgF*&-Ih`xOi=3y@>OoT{!_HplgGIkVE)yr>v^refxWUF*ti%i`n2_2&e)KrrA5k! zb+X}opqVtsXm&@B(fxdi)Z!(pLp~Js)@^45r*#sKVU>K!MRRT*cX4(Iy#0?B#7cp? zFW3B&ORr+)vzw-q3fS>Hvz{&%3Vt1vZ6bvjc z-+5C{B-B~`dUl*1bN;^8j1uI#c5}bIE}A?sS!W_VU(h*q={4ZB6|a|E$AXpB?y=OF z^u^2D=WXGs>|LBYqheZK$6Z_uCu;uYi1Fikr8&^3JURYLGZ^8mq}MHNrdn{%Rq@6T zv^>i}Qbg>ipOzJn^?N}C)a<8O=#3Ys(ds~H`LH%z<0{B?pwElnXLJ?1R;MGJDIhs2 zlvp6bVi=IqD)lI4VtqQC+`a01baxma6f$yHH+k~CaJig2HU)PX61kDz6gafpl<&Y| z_Ndl#5_!zWZ?f*Tdsj3w)XY$lV-Ym9{X1|Ky-2%td^b2Unjp#Cpc#2A^7b^VYa z%TL}V#>hj^^AhKK88h(Dms_#Q@ojDIPCn)egkO2=?3Z*>SaA#IqLGlrRkQt(fq5zW zRo-&ri#>(7@28|i_DddI*RMDqps*8JSmE{H!Cae8bag#RX{-kAb-D@l?-7wDDG(O>yD?RzK3Ur`|y@a4p_k~Cdk~(7eN>><}S4(c3wtWkJX6Ge~i0oS+HZ}&B z{wywr_w~hz#i2|*uo)brVfgMRAWXs2t`^9;*n!R|9Dl_nZ@cI_82R}eTY4fUWvyLT z*~boj{v;w#DtuBK7*hAKgF&1l8iG`U`|ceRhpegTPtCb!gQ|Dko!3wbBF@2JG4Wce zP;+T{nvyNNlzs8;@DWnnMxl)L5BzD79LB&Ie!HmjQ1QNZy?q1kLcaH6pk53m=*g4D z9@t3BO489f*?ViIZBe_|yE0y3MabhYgqHT@&=0nm%B7-pxY-284!}mGcf1&}Uodp< z5JSRmhyy?h=O^tvILbHOPCXM(#SgXnl@*?`9+i>XRzumag~DbS(#(pZj{21bxauglHIP)5_yhHO{i#uGMfVar3_#&@qz3U=E>Qk`J*TlB z20}EB+>7mlRuZCzILmb6cgb+U#cM0X@y#r)u{S%1*db=;bOWY5V(UDUw z2Rt$V42UGVqfO z4b4F)h0I6sFsTfk!?`Q&4k#T~5*6|30=Frtq5$KD^N z%lHhN877q({x^dWXg<%^-&>VM!jfOZ^B#e=(wRgO8ZiktymK3fy}eqj*`eW*5m*u= zKAcv+WTv5@wXNMD-Sc;R&b>pJ-}J@Rr?{r#3N5qcy8-eRs0Rs>_!HJ8%E@i=$^}u@ z#$g&NVHv2TMNz!=wc2Bnl2aAZyE3R+rPs;XF%mt0wFf`a<#zPKhq2`54+pD=^p z^>@zqe(0SoPocZ)*nFcMqRZw)vpF^CK}zQJ;Db zCF*-5`-9ZWN%4(nsjSTfi6Yt9=z}H8%Z1L5E@!BVPyXci_}rlfARr(>(BnW{o!}5f zdc?`STAL|NC1VuOWnA#}>$Y3_(J5`3B0W8Qn&LYaR_Gjfu?^0axDNyMHnfL;4k6RN z^`}%wXn1INDl7wRN>Oj5GA86z`v#+NC|vy?XUqo9gc@8aHIla!;aJ$-gEnQPhGw6N za;W&=fwo1ca;b0`7eI|j8un9#!C!Lky%cjO$R;oK^z@L!i=3=Wnd1K4V#1Iu8=bo) z+_)w$ZEbBSz()3rQD$M`;Rpx_Rj+|IAA|15P_Ss50B&fK&Cs;44-z{L6V0DOV#8yj zv%*uOBcsDY3yA69f0vN^T}fCFdz>b2VihiLBsv?RO{>w-zgY_2ydt$AESyE{!pDMB zBvV9YK~^L~|K6T+vrH57tZpIhMH|Ob^rcAWqwsqyZtC#5U<1mEA@kAE(FXmRh2sK( z-Lo@lDk@b!1l-1z^z-coGpTF0WU5U5-$o2dDk`2PWjVG&amAfoUG#Kx(#6@a8LB8= z4*i_=uE+cw`(ea5r4ohcZZKOb=M92!NNRL`_&O3jwn51~g&i|I4=RSV1128cR2MP) z04@oZqxcGFs8Gt4L-8`TAaRBB-jU<@F@oW+so6_{r&w`9P%0!ns4#4#;qE3b5l~p|HHyu)rUa8 zZ7x!d7-asQ-vTaL(CXi->LWKsEvT|r6Kj7%&h&+WcTT0x&E1`yNQwJ-0s_GZ8MnfZl{Pao6BQLLWyPTdg^yV%z8izkrfFA2 z(-064e9OqV6jqz@;9l@*T_4@OsIPxtrm-{_?9M^47@23_!bOcmXebeLw4{okFr{=Dje!aN3`18jcv^Mb` zbMkWh;}1}4L}Vm0LEPT)o|W07RjzPSJaKAHbfaQs9x!IBCPWtNCozG!yiYHB4%G=` z#Gr=HW2k!nXzy{zdYB@<2eM{%-#Jv9W|3Mw^&mgQAH@vnGLja2v;`G50RjtW4#`&2 zZF6~*-s0tq4_|gFmZ4)~XN-HYD5G6M2ZVTVZsN=;BZv2ya(z-^>rG0TL$AIbyV;Tf|^v_&wm#HRUUlb1# z>f5In)Q5q<(amz%LQcU58ZLOsk}YcZ0&$Pi$I)|;IOML$nu@l#Pw<#ajd?|k(PR!6`Du;`@|$9^50`|X+c6ZKn8;j0tI%T?abdcY|P9b$P&Y7+T5G} zCJFwH%PuG=(5`xySJNj`+}5@zbzV8%LxB|y*~N<=g6TtFUmxZGj#>-t&WY1W{-CtO zvSwGcrupj&5n7gFnH#pjYMd2U)+(Khy5=PzMbdVHY{_q%UlSAGZT0C=e`vA<2M6B{ z1yLpe00=t&!~*PufY9^zArMGaWo5NCE7&zZhFE3B*w|QjQiuYpYK|pUzFFT92uz6x zFb%b^@MdP!Hr@Mmv^xd#I9(0M`t>!UxU^KdZUH90?C)#0f+ET@cK#L8bg)T-jn?kx z!vtjE*vnr=CbG}8e&vLUg%}W5Y{5mUGNW2PbLi0l{sQX;2M1Rgp%!smTke{rTyFoB zlkr^GL|a>1PtW$JzHh!YN!0hl^tfyg0;p^p0#T~b_V@SSklkjG!1-n6uBDYWWZtmk zKmk5y_r-=S9*v4`W+WMqT@OLueB$^a#j@$i$+O8yZrHJVtriivxVhO+fB|_U5GCEw z0D~{5rn>r<4bSq4*Da<&D~YczvRz{|Hzqw^Y^g?tA%_l28duga5mvQNeye^BU(PtJ zs{)qEx1FySRGjfgVPK7rW!uu3dF~eoi~Oz#cj~;)L>WTc^XY(ponj zsm$JoH25^MBPG;GJ`kKrz(3VX4^yls}^xK zB2d{(&6m?YhJp87S;}P^wm+9a&?FR?74znEgLqMhYl*B+VZUv7 zNHDFMmPDw>@)|#2Zg=A!sSY|3dzLUMzQv0j`m-D`Q)75K>TTYz2$NS4(1wSs*bsKs zaxAsfU|u%CUE6gd#YBd!%%A#e)AK&$+25Jt+>(2I^7oxjb@Eo}{%V`u@^lP;P*eY= z%a%TB;nr?gqs^M8$ff^QQkJIo8MO$uEeqy3CAv?dcFli2@t|BSS?I7e4QIDs021sH zG28;6`eLUOov?)nyGAWw|2hqXtV~5%q>0V$-Ks^*ztpKKiN@ zudUKjJ4ID3MbXw;5w%7(*<`)j%=@32dv9)JBMFkcIls7>Im`Eb=llNWo9}#ca(y_k ze@}ZGFB?LLeXrQ=gYi2b|9V@q_*Bh}UXEYt8L=a05#n%+{$oCF>flY=-ssh@hw8e* z*2#&~bB@?fNJG-Ad)J|J8KPLA`zxc@>(NUtvIgp^2IvZri>!e$rjC>B$h6F;K@fAVa*48(5y63~?C)bzB27#49wgAPDHgF!-QX481}ftt_jU zhKPg2QDyZkrCy>9HqvPE;t^Sz#*`~uDJ-8+Rk4{$H%~y4+5mBZ2)sTu;nMBY9KM=V zV8~6odNDp*S1~<-f;;zaU7>?v#+2cmaO9RzkE5)f7$mp_>vsOwW&?LcK+h6 zLPj(?U7|wfjf>asW*SI&lPMu!wN=m+dGCh-A((1hD#w+p(#kV^MiAeg+^unC&H?}~ zhWuOeJGGeg=`k(CRes*4k)V-uV0ruS*n?@B3du3({ous5vtECq~D`kyRSBDBgdS^w@8KJuNdd0Z(&Oxk)fzolm$Xxsabc;)rUaougrHPy|qy5>e7 zIV^mSWns+EcIrM5vc8@?FP>Kb zx<#TFF_R``F`RIUqE=j4(x*u`n_1 zj~>MgL2oSerBG0{Ks1NIF*BB|o)>G+SLifK;rb|5)dF!*c!lEL;g3c|2Ro=3M(xpV z_`D;@j6xy7oDmE;hgVH+=kKgiDwI|Zq1|8n;^Z9z%hD(}^TO=jHcaa!nK>61kBxG- zL6x;%+Y#%2MQFf56(=V6Gfw?35&b7qJECpGA=E2K)|F4^3=j3NVL7F(Yv7=`jfq-; zrKZO-Uy-+C5TkG$y7vVh9Iv1&%p(QySO3h{YITO3%csug(C{3wMed>HFGmKrsW_Hn zZ35a3TD~WN$DGaMS%r#8+!!~|-;rZDwRfw*pPs%iEe;U@=%+cgVQ$w@PirNsbO{<7 zw>BXk*aPj%gR6IYv>WKh6l{8To9&>fO<+ug_KUuLoZ4Z``qYv_ipB=AIF+^T=<%k04C*P=f-z9JgCi~pB{$396okGz+HaIr$Qjepd*uj30PJC=(lhSz5NXN)7``of7@`Jx7>A@X;QSF4oG zUi^tdTA@h)syn0foU-!h=Wq0|Q!oLqoKxifJien96Zmc_mYi8{<#KxLMtp@()rt!{xpQ=U3tPh2hxZvb`>na-dPl+!ktWm5J`eqf7^$s zn#Kfpxp=o3F=^VwVcq@h(cN>wDd@z2c?&}3H`N~Vjc$zbp3yUZP1PC- zlg^wtb1xq=N&4mZ>DvX63DYY0dRS9OckhW`CYKOWkM`5cLJ8Y+Scfo|`e8#RPM!38 zY>*RBqn>d*SID@rbID(Pot1l&upm=X87Q{(Qu-T z$NdO>;Wm4FPeN>hnhyvIXwrAc(3xxEh5JWGw}lGkC-Vj<20b+&u_O_*6ie>q%{}lHUJYKoT4)fmF3%lGu@dp# zNn^7h{PH>wX*X=~WzA)&7wK?h(# zcX&7ms(qt3UxjUG(cS%NWB_`+n^dR+px4gAnhD!|AAPCq47?`s!pS2?e@?isc}UYb zoj60<55N`sV+7bF?;I1`wflg#sEATY{x%929k$?FHjJg+|BfGIuH8Sl&yhe3PjeZk?L{&tMxsO!c?LAW~KhOm8J`%)AT zD>-T9U)(_<;I-Z6E{W@hL&%{1pTG~455Wo{j+x}`?F0HYfql1LEs$8~?;d{A5U+Be zf_)65`*q*ZTUjJ@`n)JxQ4t2-z4zaa9XhytR;)8A*#7bN#M-&**a=<;SYQi-!8R}| zrfX|*_p5C;b@VG<1RWvm7EEbHs1^-Kd4$9O;)dL$yBdU`0x2j&2cp+%@&%$RxVdx9 zS<-3r^daG>6bsva&g&7jire3=z95M7Xe}Gsc1V}TN*)L{7&x_~XNWbqb0gg#5KVzb z4<@{(pn#x_NA$~iHjRw#*e<}CdnhKv(;7X|3;iIdcwxW*y;GMJUwpH5^ZPV}(B@}n zXJ>L@9lS~Mz0BNv>AUq1HaJb0I?SIl&MIKo=rCKg?)taKGB8H7XVo4pXVu}wNnRi; zs-^v_8;&2?IzGym6*=-Wu_JP%2^#QZ-9p+#cZv#fQ$8dloh}Luf!!ue9Tlpk4<7c0_mQ+5@x}Y5+1K=nHX;X`lkD9hZ77zEaQtwNMJE4v3rBRx|{h7x5ZCzBwTo z3HvVOkZK4ds505`$e8wxt+7f)DV|VtLT4ith3TRyzw@u%O@|VnYXN5r9Ej#%9K$k*gypf08v!eoC>~!`Y}=Q z#bgr-Zk$OWjMbsJ6UR9!rFLwvvTtj6ec_dhsU*xp>d&fO8zM9?Qo!a45j?M>Kz%4X zA)*)vf^aC}okXFmPdFgLsO;=h_r;B!yKeu*96~n%=nWE94XJyQlz`AI*xea7h_0y| zs)kKnls~2>UB6F=OX|sZ4dI*uX?S8(i^|R`va6TKl~OBK9#u#WZzt&4l(bYSDX1{( zVzkP>0mQkGKnEqYA}j$Zto?!=$nVJ`lB>A19PUg0%UC^B-e{Eev=!D-C9$m-2Gv>MQ`c5{CA@jfE zp8o>qC@N}erBY&#sS~2Kg%a=(q0b~;j+SSL%38DlRSR9;=8;8L=Bh`#z?`MAm7^dK zrHzW3!aQ7|Qo;r49(k2iC?>-y#V?^PVo~9cDs`w9h$~%e)rh?Br6a7c5z!45A@d}u z$==I>(cjNWr)dbdI|=3b?7RY?(aT9eO^+gdmOB@t))mfh)9Hg||MtZ@o+bNZUq*^1 zRX$a-8B3BWzlJ4wTmSjl1wDyc^urHvp~lXJJNrPf7|YxOtris`BYfni~$(A;w;fe z`Yq}~uPOEWkj1tNs8w6D=sK%LO(3?-8hbi&pkcwSn3;w1xV(mO;=q$uzaWPn?S_84_=Obe27>{9%#d<1jiP78p@ zyL9GCI^A178Z@Yq;pOp(HAhDoQ^}8%1IDPlKhxpYRM7)~Zz=>uiyUxwIGhcu&f)0CPhcSyy*-j_fQdq zG$yPcRmg`)i1(6kMIfUpHFsq3WIb~}a`}W}+guDnr&M%p;VDHK7 z95-i%belKT)sVe^{i4$uco9NV{_%&u+_LSq_24;u-NhiaA_ATv-o#@l@^gJWJ!U36r)$>+e%%>eVM*qW- zwb!zBj1vG5S!Nn35BOb1V8|=cjb_>m1vsORI*+irch!;n2-2aOSfv#|^Y0 zHe-H&fDI!p*!bt~?~BCvb2D}$w}iBN?wy^{7(?uQeSKpWUlNYYwfUY9>Hi4O+*&*? zf--gsiSE{|mA?yk+xw3^m}O+GJ&cqk+hOt!krbuRXP%$gS54HTf6LJdeBR-euTrn7 z^lBav{r3YHmi5n;c$cUcyXn4|D5OKmEMitqf8pQZ4V=I?uw&oeokEq2vgeBP``$w; zg7}AbTX-_#P@D&`i=GtI!pg?C{d2uKHuFX-W$iIwuPCIXz{{%!+JgjV+o)MHZ-jls zsmqj)Z|6xWd5AyN(Av&;8Ndu)bFUO34Z^9VAxM#~*neFs4TVp>@?m`kq6+^9GXHql zuqY-N+@R4GL*71{sN)|T?MuTal}CN=P78h(v?(jcIT80k)9^;jwo#W}v2FaYMPyw3 zM;^(eiiOPO7VVwmpT{7eR0Ir~G-Kw=BSRauob^r*JQW&^`d&)x=I!kb9rTGiP)JQI zmb-^Xwm~X+-jmCbbMxoV$1JN-@OFT#zIUq{} za|qs1qejPu+B1Bimbdk2GHB9UtNs<&+S3}zL5A05WTb07A_wf= z?%F*n%#-EyoLxY>){c5s?cx<2-KSssAn*45hjne?=d9H0h?RR_t09vYtXcb3xQ!S+ zAa2S}xti(TA-YG$mi6(%n9dGdGBXUGk%RiQcHoo^LxMdV7&~`255E@Od&LB~vJa9| z_=aI!dh~APt&~QTsS`ZUd7kr(9NjHMWo5(i23zll8B4xeJUqzVx1~LgjkZgRp1nd0 ziFX`3&j0t4(an`fiK)ajsLSA&S8n()+DU+Wz*7TBK##T~$Hg|WSE;RS9Q;~6_tIPM ze=vKnhk~XD#Q?3C2$)tu`t7s7T=3}s#?UYuV76E@VYCnKTsMUD=^Y(_*TraKSXP&H zE1d}m@75?;qXCL!-BH^J?6_SD$Eqq8_yKlw_gXXmaxBAeAS+Qpzr%g9y*bQ#jKNyU-BCBH|$uCD(qg(@5m zI?FUFP03LR!bE-UZfkcQiM4eGZ zf`Vugqln_H5UWXArGq4GTT}@8yp+|i22a}(dm?^ql($8)P?D*9fMYU1fM_O@TEPVG z%V_+D0*{SPlK_%gsd~&+kEVA@>Tyd^BI0pJ7Vj?t8EPw8OKa$?OEj7dN#Arx<0NEJ zTISv+&6@jAakfG%$E)_DZ?~7iI4^T zQq^M7Zpj&OIY+L1Fn+UYY7`{}R_DsrQ%_9S4)saqX9UGw!M)9EKG=Rbo0THTlJpI_dNB+CH8I$7ZItZwOlo9^ zKNGb-K2y=j8J+SIa(JvNFk)bgKHSBcGviwl6#JzI57N`Ka*9QwmXqMMd?wy`)WlL< zv3O0KTTPJ(z7gjLOa&UJAwrESK(%qhBkpR7WE6w!M+sDrB*EVm)wsD??1XBZ(rdp! zKnKSG-^|vnoR1IJtQqs&ceq6*o!i4Hk!L$!y6O;SpolqwB4GepDX5oP%l~cKe+ta%Bnujc z7Zk7~N3y$iVS<8-3m+UzUva{m`S}9itI;rdd9(>G{_0g4kc+l2rVS9m&;9#&7zjBz z#2JTEYIBjm4JBwa3M^)^2=?}TVj{7@-|RlsB162&>elJF!Gp=^(?Vz{g{E4~SXsdz z6U5#=K0;8C(5jWf*B5Lg$7~SyqUCYLApp4fS{I9&ViNU#v z@+SUd+Wy~ymg?4`m;`5z9iw!8eFZPCQmu$Dr7#CA{JM4g`0>zt?FMllab)*H4Iy#4TJMlbp=H_##japI5t4E`pnS z?(}qa?p!t|hF!lN&YP~@`t^l{3x&;_ky$DkycMbC$zRE__>7e5R9L5T^!udPQ{S?1Tx--n|G{XtG6wKEHgq z(4~vetQmd8*8tB~Od%4ovGByr1M|lpBrT0uw~qb%bNWsfuX1qWMyo~6lwYtw=-!=v zU&FJDyo*UL-pCLysgrVQ_8gf0Wi_4!pdJysw2K#+k3M2Q`2=@xjT9ehHUH|XfQ!(x zrz8#RL@%C|gBRB!-8qPb!47igPJ-0uXP=SGOdLkQAxpu@32(cwP|2`iJb(^ipRLT2 zti?ZNxEI&QQ@Arjr=Wm2f1X*kjNP<}`bB)%DEvJ@ZJdJichgV7 zvNDTe8jvCZ5l=u2J8m3v{5b7^02diXxOQL~kvcMu>(&X~y3qt23TniG^t!qV2ukdv zRRnOSrm{Fmxp^~l;R2HSR2UBr0k3u9LoXMd=ilzFcs;=3I50+BD zp04^h$dt<006aIMTM;YFo;~c+rR3^W8rr6%A=s7jFcJam?fBWVNux%zGhQFs+9I|= zHX5Jhb9lJ5un=d(=tD#L6dw`HzI}K(MUs;(I}3JpcvVR=fcEy(wfF4FfA}GyEcB^G z=icQ&#nPtF?wY1r=$jOZ9)#&Tb|5eyDJje^zre>6{Am#iK!yldgD+7f6xj_M5^ryu z10j}&WW=RHJ6jgfPvZ$d>ws6_`0ici-aUfw`u=@dD{ThEAvE~LRx&V9z#nqBxPUm2 zEi|EDw@yn9+g3_KmH#P2ynOvU-Bu}PFgbO2S-d+$Dg&p|nX_k^FTW(e|89&7Eaakb zGq8wJg@v@I^x6d-Kn=+oKo&nZ7X`8#kC+x2PvRdKAuH`rFZpC!+a2Vc48i!z=NU^oWb3jUNNDIgfP5tDF%>3vuWcHTAzs@oCd>Pn8jvCWm

>_ib^z z4&eW(-P)^r*P&G+BoD5f24uKbPH*z4TB89O;urgGQ=yVH+fX8(STo@gZ1_d=@>=@?$x7z_pLGG G-~AtH0_su# literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/method.png b/doc/sphinx/http-keywords/method.png new file mode 100644 index 0000000000000000000000000000000000000000..b718c8b7c2ec48c1e55a8bb0280c4116fb7434cc GIT binary patch literal 15701 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/method2.png b/doc/sphinx/http-keywords/method2.png new file mode 100644 index 0000000000000000000000000000000000000000..1084618167f59cc264ced8e9cb9db1e109e80d5b GIT binary patch literal 18669 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/request.png b/doc/sphinx/http-keywords/request.png new file mode 100644 index 0000000000000000000000000000000000000000..7298234e9359d417c6ce47e05002ebfbc64a52d1 GIT binary patch literal 70462 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%0DJ-dJwa_;Xv5 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/request2.png b/doc/sphinx/http-keywords/request2.png new file mode 100644 index 0000000000000000000000000000000000000000..b59b00c249492f8d74fd59dcb65432f49ce9904f GIT binary patch literal 49677 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 n+_<=9}nY zqn#G#Ns+b83d=0yCJ<%jm2G4K60JVst2=P_z+~Xd!_2<`3hxggZ4-B&@(RaimNRB7 z&UT#3qRZEun@G|?TI~bDyE2z&Qq97#9BUHB-LNvCuvqvKbHD^fJeT(?M-LXLUV4G|`7 zPP@RQt$DZRQ=%-Cok=x(cw@ztgRA{CB%=e6Sil&aM&5)~6 zG);k)y%dN#=t~qT|JHZXOO?n(zJ-+MymCl6pAvf1VPrdMTw-m$pB`k8P%PKbk$|LuU!p25Y5CE69rqf%+`|`(WR1r5i-r(xKyL+D!cxaBnL_ zHZ}J6tU5Ov&faKuFdo*Qt>}@*Q^KlLedg%Uabq`AI&|opDIGU%GiCTiDn_aDaO!^u z<>!bOe69Twzr+aW(D94nmk>8rj!#ES@d+mLGeBm~L>_DOKbAOF#4Mt(fe_d=I(RSmRs0+6kcBF~xmVh zeOpz2sfwIeeq8u}f3=EqQKRFJt=$L~Oy<>E>XGWvDg3Lc`uCb?hy*4F0hla^1a7ma z=i<2uyg8UHoj?H({~5*p+tmxTFN|kl9q+f%A9M*a(7% zrifuY+7B@jq7V~lR+qvVTpmNT!aZG464==vse-KW@aCN?Y@=?PZtX_aZD7DNlX{Wl zCeS6+XKfpqKMXm6BZCRjcn0q+4Za>vmnRLvP3&9MnMCo?!qpL;rVaRYzb#e+8k5KN4n z_=ccB1h+}dJVJbH5JX0jpT&RT0H{q=F%RsacT14L#N&U?pn`X$P@>K(C#gjVDCH?t~ahk7HX70)m+pMC1oNo=MJ3G7e(-08=c_Rlf$^ zKma5TqVaro7kd+rPbcFrwhxFuMe!6>vIxQHA>6eT=>taeWl~L$$ezsB9oQDIJDN+w z0CrEKR~{krskV$y?_qQ`Fq1u!f3GBbF)cfJEi&(q=YE+Q3yArK_2U^524*gg=C##? zE~Y^T-FBlx7dMc82B{uF63yGPY!B|Hgb6w{A|;LQF4C$2DD>&bKR46969$-kGfVeC z1{XtUVsm97TYEMVD}D zc8!0ZKoK0iKv5A}9C&12&ty=IYwDhWIjbn}cy}|M+R{9mCr{yavF`-wHil{!RVJ>Z zLCUaHsB#Sch)Akq|QZ3N=kU8^?l`)GVNHI34S- z_BDrkY|dt244L)Wlgc;wJkfwxLdZIYWMbP;j9`)J z_N}+72EpW(YO79g(9NJI-gJWCxw&4qe;;@XtKPgwi*RM~YdTMfVtbHsP@i;9-fvh)81Hl)#(C zv^Ue(N@5WhSa^{?)#5@E7JtR@n!MDO>}Z}|hERBF4}eL+<70EV>{6*xWve&N%uc(H zAIxjOGkY-zOcG852qevx93Je=qxhG0!GS%E;BUM%t8%(Sg=){+scG|Z$|)l}Dh;Cy z4Xs?rBg0L!#*(*`52p+e{62OcCVKbwL}@wAx-)Yf`ev$ZX}!0DKXsyJF6lB~B{QxC zT?^Ui0*QqOc(ogsQUPAy#|s@Xq>!tC#D*mLH)W)S?@BnAL*p3cgs`9(1e-6h`4a2X z{p=M7Q<0(>6%H<>U^>Ec+1JVgXt?y19v7ucIdNPXIxz`@Ygnk7gk72b$bZRc}` zGody+)3DW{qZynGY^~dFbm-a*0QQT-4CCt!AR*ETtH-t@YTiR>H0sRLp8{l@rDtEB zT&8V&a!HCNx{Rh=%61D~OOY!HG^>g5vK3xRla+iwl7&V*GE-J?Nx^LJX8=iR*+wIg z8U@K>A;MTuY`(Ogad(o{i1P(Jyo)6bRej2+=~H1AYz8Q%`6^c4&6j4Z5>IZXNCF5l zc*i2tLXZ)P>9Ce{_p(&t(q&qH0)qOVvTg`P12IaxvYEN*Ah>rwhiBmSF!ul$uu33k zx|kJr;OdRp$k#{sJOd#ZwU2$%kv%Ltq~+A1;}3(XNeoUf`|ziYK0yM?*~t}{%4kGt zllD|V#-J}3+?QW&*7hCc#Asixv#dI!QELfEdUk6Lv?Pt&U71L2@Ts(%&s~{vZLCCO zH~H5h`H;@b+AP50&j|Nu#BQ_C-YsCx-#T;>gO01skSj96tyTP8fqz_K!C0zz$`@w; z(#(~%ca}iq`^p!~HI!_u)CNn{l}c6Tv|O>4%5Ap#>yD;t%c(=hAJlfELx&C>y13Dy zL&t9yrYmo^{D?@upj}h>p9LuwYBacODqQ#nP5*I)=+L2SHx<^E*~s7f;GTt;#nu7T zw_JCOaH|>Pbv|M;VWCn*3XWMMgxt`6OWG9}6Ji$44A(@7Xx)hPc*HDL^}yzn9@hXd zi*Yu6I_c1Hz2ZiIg`#){DAb;h^e&5?q)ugW#P!7pe{USEuQNvYpGGh^I6#X^G$+3S zbd9T(86aH{+mIatw6Dr(FuC z;znZ41TG$?_cktjz{uPm7_}2Q2tYEiXgKmr&fiT_lX~6u&;)La;=?-;(^=R7-28nk zldT*`U||dh2x7}<{PA1)q&0u(k35s@1HF>&rsfn)C*@8;!w@s5TbGl!(Y!wSV>Oo%5*x-M&*X`E z>f!gH1Rkj6SDUkdTR*2zfQdUdQKJb)0fP01X}nx_C80ydkKIi5H8J{#pVemR5f*2F zfeX_R#|c|Vx9yycr-o}FZqNV#AOJ~3K~#3hWz8Ktx)Q^D8sE%IO?hTHZs*;$jsn?XP%NBh!s39+l$HUd0cJkP`fB&JdQOSOXs$1wV9!WQ$? z5W0nef%yl0NaTP-Y8IP|)O$3C1~7jcvH?u2OVv#_I&}Ovaihfu&-4U{5#FEc z${691fntQm_{Rv}?_f}*8c6e^MuzrOiV;2_ipJFtH+xg!Y#>pf1^jh;DlXdbT}Y^j z0?QM5?QDQ{4~QbB7NVUurEM@s6l(!3-EOta9^vfIQ@eIF9c~U#+KF;5xX_}s{-V|4Bc9&j+Pom#ab2ri3wSw-V-sZDKvQS6B3tD)cm2Y2_x zB1mz8P@AMcNm&bZqp=Ph*P-1=*mG#Ig7>=NyagcbG82~bWd=wz_?Go|^R|Rh;=%7Z z4%&50jgK0HuVHtHD5!nGl~C;gMz#JdwAShJA4qJ!K-?`j zrea&-Cv+n$SR{~HIgHm=@cbq3n0&sGKDQzs0LaXx*C&)pU_~UTSys*j`12B8F4pIj z4jq9+%hh9qyn$2xTU=ETh}MRXQ{qH9Vwx_m>W z2%kT(w5twXRXGV15%k(~R!$5^puhHkaq^?=?2=Pypd3XT3dR5F>l)!-SDn}s9q@U~S_<6J& z!SXJAn9aXiuyp&iMaaI!l=5_$FQ@V7JWd(>Ua&3?D>gIyxc^(%d_9r8#nrNbB=OyD zY7;0hdBD#4=9B{IV*Y{B9f}Xpyz(REe+upRPgJV?syV@<;8ZHsVwbf`NIr>yb9($6 z>C?@~2rdpGWQnGxT_HNV4jn&LyD`xtga=p9tPM>JUfsK8V=hkR!f3i_F__Ge>>EeH zMDDNWoyxBaqI3oa@4za9pmqy9LmAqh;_0N^MQtOvd3!uVOeD|ZztsYX5y}6fFz{v$ zb!S31?9(|k1WWm(4`JgNiYN1&7TX&G?+nHgv6<6G{C* z!ZD3V6YIy|n!^7z)Oz9J;eN=|S<;afaa;*C*k>uS&P$;GG zND?Sa>OxjL8TW8Yh`wrc+*olVm~cB64pZdd+Z^JXsqgR}E!p3L)}L_mI(AH^l@V+> z?%{!z)cu?({dqnPWcJJ?{0y}gG5sW^(*PVEjCF~+M2!!5ID_;N0CSdOfSc#@RBpxk zJ!Kbg%0Fd-{a`G_Ii}=jO`JQTwgwhGTzmb?FG-=1mZU84|P$!j|AJKIy$Kz>a z0UN1`W-0#|#^jo6;>xbHUBYd<*)v&lKNd-kBI`MiW&xk#c~VpWtcA8Q(3KmF$uHbp_QwX1#&qLnz7TmQ55DQ~hIv;H5GA z!%FO8nt#ux2@DU@7mkh_DsEn>!-S(??KrI03JATzoZZ|=bEA?ZB-&@KvZKFW(}0d^D9Hd5^7 zPzq@#?hjWJ=d9qoosv>Myuf%(X_~r@VmHUqIA`R+2vu6WkV2uGm)1iJZ8cqH%J&qz zIg!pO0}n;2IsbK*A~$brf|_)+0_;y?Wg&$Qrmdn`8}-?TS8>ixNeS~(xTmpN_0dZ# zFQC9d{0bVk@kZdng>4>dbCHaEf05>qAX6eE1f_0}cp#cC+bAfd;4&|sV`8js)6sFG zY&U|Sdeks7wIk!e1w=6>iZ2Sd*}^=HU7cPCf_~8)Ij-(^3hWdJhK52U;vsK&qoUaW z6yp@C$tD9DS=sGWGem~+Wp8AG;$X-|fNwW(XR^<#)>zt}60dy+0}^zN;CQ;)0K1Fx zPMSyK^dUp-cW_$-N;t_WYGPJV0C98HqgJ7mk-{b7Bwj006MsnIfofMWTb%KL859l+ zdWZ2=3BVzZzk1Tn1kG%G(xcj;4lDEy<71#m6S!_Np|O=RUqi>WoQFL031co$tVK_E za}k2@r%uGN%n+Y~{E@qfjW;BEy+DP|TcA?LiqNvR$|` zuzu+mggdes*f5qUG!oH}?Q_!PaPeLe3P?ho=LSiOPKVcQ6cEQsxj)3~u@ph68>`W~ zV47J;adOr{E$zl|Xi$Kcv#4M(6=XrQ37h~i)vhv*A!Tw|qJhMhniGr&Z9&JFNhwjg z6RH+TeFLjYAsB2J%64E9k&xk1f0j@v6B-RnY$^py#W75G(F81-He@t-?Y`wz*EEyr zP;I?tZ3GMkgwKd3+)j%O!oLF}u}!(Ji+|r_fUx%|_Gp7_3KUaNhmPysObIY>yOjqL z`T877&#^Rxgx&ORLzu!>$&Bg>c2LNi!+qf_*h_2|A_UlZZzP+#vimHS7)Df6UyNHu z5oJ&%TjwBf(efsOU2L_3KtMHt!_LwamZk9ZdF}P<@!@|v{dr0LSbBtNEoor}2lw~q z;&9S(Ac(0^D*ftK3omB!^>G@sCsKfeN7__DANQBJJF>XzCUAm{kL#<+b))GR8sM1b z**I`PFm2(30(B%8bp|&$xif~t5b zyTJQ->KJwk0vBJso`mVaH%T!|@cdCP-EN3^Im%L-( z0f%NFd!;j&z>N?XO{(GSJp4CSbrk#G!Az*5Z>DtIAnoSPei-t|@Ns$Ny1-V2SKBas zC;jhGH%f~S@opg$@TWxbX94U_<+eSb5VxA|N3z&Jh?&=Sk|&4+a(QGB%Oj~_X6gz& zMsV|57CUFNWE10k9EJv47;-D(R=-x=^bRH?;aYnoEy%Bu$=E$4PX{=YLAP%~Q2QG; zkKiS+nRsRcdrRRg|2$3JeK_1ayB8W`#;?Hgw{@5qs{}@#*utK>@U-G|9wT|z)BavA zj-lQLjKO#k2wh0C#jG2OqZd{)8&B}`B|Siyjvs?SjBr<=u(svFzh#YhZSiq!<0^+!L`i$GmRTr#mGgjJV{BSrZ;MZ*R;@ahCNoTd8X#$#g0k&^ zMb%l?A>(Me8wO`HQQ+4@|;?^4Go71Tk?)FJ9Z?nt4ofYDp`zysd zBV5OoP$eTgU==k4>n=6oaZY(XEpHTqakWQ87zjgvqg(|A5QD-FS_yZtt6wTzB z{HvDF8gR2Uf#>Vpz|9r!-H8}?<9OZ@7OCpfS;4}45D7Fh_$8(!P&nzD&vXS%S|dh* zLgqAvL_saYj4O6Q;Y>We!o2^^>5X$_rDJ#jX4Z^C%;5bt`Wds1Ka{uuw}LDxrTj#- z!WSVV)L^ZdM{3*{&80^NKJ9cx`KDlpagDs}?bTD7r%K%(5N?F&Gs|dkH zW)5n%eyi2vt(F=s+rRyJ@w~SY>3xD?`L2sDadiBV#LX2JcI_G*8B5U=zU<BPdjINmcrA@R4c_XMveGNY^CMc%ceDV@xia8`|ElBQn0dk4kw zZ0@I?TgSHKVqflPPu^6H4I@ILX*kl^Tkuf;%uvmjwJ(7~CY#oTCiLjb2 z$VsGFPPw1z?LiP4Xfb?D+Iq#Ef%8T2&`KV`WU#~mPe z>Q3INMu*R6vxZgU7#{&3%M574XY1&`r?T$E?3R3x#Ojl@Y(SJoRys9<+(hbqM!l}w zQ4K|a!ikyWBvEfMujb(x4+;(swVPs0q5j9bJSM{l!d6Mt0#aU@#IE(6(-* zWFi~3QGW?fr&BUnCD6ZkGk-au-lKWqc9M3p+8IDpB{XE!3C(0vNDA~1*Jq{2sbPWg|t4;6CTrMFeizkmW=_U{;3TgSQDI&L$X(OsRot(_ggaTg9Wl;wJ zo0VoTKABu6udL>R0?_pq;xc&ZIQb=fvyajU`j|iv=MqF&^_i*TcZezv z!X>GK6#^m1xqWA?||E)*t1*9W+xY#*f`_B7{<9F-1;$v(iQC~f{#aXr5{ow;0ctM7S?s?H>|^?Bd|*%CmS3ryTyi@$ABiA6iI7|@>)HrB~r zSLG;}%>Zdm@=g=IT3ehlSg2pE$~Av=1tS$VvZ1fduOCq4YD z1t=i%#H}PWsHjtHJHwLGEIG{?CnI}fPUEHHEI!5JQ+$4c`%duk07@KSWS|w?G>9Y4 z46x!DQO)RFX2=L;%iUN+Rl6C&jcQQMrqzk9ng;R4asG2FKln$RdT|#Wx`GTY26V<$ z#O@OQJ)FWLJa!yBS3j_K%jyWca2rU-9^P)oQ)vK2r;y&l_%_m8gsenlBfSe|ZmLVK zaDWvXsD2YI&0uFvPqI@vsh>>g_@ihy5;^A?`UCHbV1)%>;~5&P1v3XP;BJSQLynsW znUS9&OSJ!#wL@`q!)WHfS^B4eggKy9RpyO29$DohwMphMKz10MQrW9Kv?;P@rl zt=7HC==go&iZQ}nS{x!@60ochsf|7{!pn%=zBxVW?X`-i9D7@+{Osz%T+UV3=cxql z|C%)gfwJNj zOqC_Bz86O#51k>l5zQoa=2uh=0yMy&6{r;=s3K^$HBcLTY2}7W>}^}sx?tr{;=Utb zsd`9#8()DzZqcWtjz6I7<`+Wexoohqpf3}{30pv+P94&r$lTiz39Rl>iKi|A{(U>H1U3)E5KzVm zTErnHYo=>~Ef|qNw9y;hGbe%3;k-JO#qF-)!ja5B2eJHSo%yNb*C}oU-%sYXmFz6} z1;mYgIyM0Y#(l%HXRb~6xdtc#7ffs6C51;t(h4v4JvSc91**-*G?&*3IUi3QMSals zyd``-mJht2_p>YNi}vXhBw?P%$=aOn;onY~k0#MQAKN^h%Emr5kj5c#{2bUA5~LBT@x7AsW8R=da&0{phv!U3W&P<5wwe1X2XI2l3h^_279(Yc5XW;9%-%8EVCF zWE^>udAp6O0(^THcU9xV;S^5d;Rcw4*gKAkqllG25EDni?cCOy%Tq`iN)2s|nXD`u zLH=Ymml3H2=~FOEcyks73qd7;5@qBcC-DemShAgFUvN3lnY3HRt$06*|Ijt6i>H{s zq~Q@f{54H>`3aQ&XYZ`zqdL|%{++WLhlGR>oZ#+I+$j`y3KT80RG>b$w zgGd}i{}3<1xp|{4$s>5H5)PkIe%y(a;hgMFX#tYB(UcGX#mXT^5ut)4B8*%8KF(j%!>6ln|iaKRLM_A~iu8`_NQRduOJi7Zkkl+mdNMsa@r;>PhMLR3%%g4DyN}bE+{$9WQp(k!hyw7*QEs@n6-N@x-A$UCGjW(LkgcB*d>c!e zi}}0IBWPp=o$zmX{Sv7v$1h{GVS{8RK$0VW#~!nmTUi{w!Ue?}S{qP#u_8UU5O;^0 z@r*gh$c6xpEFRrm$UMbnX8I`}ssobf5@aQD)09iHMdz|XCvFV#Ai z%)+ISs8h}gW@`Jh^;Z5#<;eBib`h6`CMjbEjgH|=I82g*eJ7cl4iFJRH3vP9aLd7& zSbowO8^-6i84wO`I+feZb*OjYMc_#CIDHFGOYrScW(|TZ3~a==JM-+V z%gE%ZjXbrHQblN5mZkj|zmzX;=1o8#zRVv&+ZP!+cM@0<2ZCPTAxBaAN3MAp$DtAA zGeL{Cd$jNQXB$e4A$?cs>M63MUJkn{!e31e}uD8wO2;!flr) z@oULcl|=ZFoqO>}Q)_}3+X$PIp@?IA(GuDPB8GQ+5J0Kt9N;2Oa=ebjc zaMZw`KsSKdy9S&HMXlad5;vH*s8KEuk~{<60?uEv&T98WcFT^0o#durRfbv+Ux5Xa zjWHE}?&<)@CcRQ-c4X!Tw{t_?Z#bIeeaq=pP)WY)s zk4@u;!@OIPP8IUg4PZCnxO?*ZE@KJtHiZi}dCs^wnMP!QSCb*=Z0F_pyE?+(InN^v z=vjrQW`Jb+9x|KaH1X|WZ;-s7a}JYqNiCo$l1E%!%`G zhnR4xg^_X_)dVgku3@5y1|?W~A7>MpnP3<=2L9;DR5Fw|dl=+UGUIE211!i#xYxob zhw0eV6PJ2WD@Y_x{Z-6X&kk;)s}kU5XBGlf)#GV?r4xWl^$Z5Lnt!v&+f_Y*C7Z(Z zl-#clrStDvo|Wv8EqJyfNEC&}#qQ#0Ff;WS|8CF8%X!E)xHMY_(=5mnk~|=kA!Rsz z{a5&Iv^-YHfs=%mrLqD}`nJT9&J{Psig0fPKw@IN z-Kd?Z4*d96FO{3&VYk=3|N95~O;y2yt} z(0Fkjhq`cQIKlI{prSrX)7ki0uqmDtek{(7rj!U^!69NaiYgvCXy+xY>4vi&s)ehu zG~2RFjKKf^AOJ~3K~xJ0!NKh7gK26WZ?WC%dD`zeLtt~>-|Z=(%>r=gB;$fvK8Rx3 zhxIu5a5pbq0r0cn??cP-kvy%n=pX|Rd7t@$J85*@&xtWu;ARq4zDEJew*<+d-ZYxa!OT3&bv}Ur8=0wI?HJtDDQo7ZG|!(lGk)G_qwq0H zO#)1G-O9dBJl&RrRHk2`k_oaXzlQAt_|!#FKi=KO5eF!Ibd#l(n0Or&cEs{ZGdj)y z$%}{CJ%k_?-OPoXym@`Sb981w(=QrxV%tw_8xz|$Cw89L#>5j_lVoDswr$(i&HLT& ztn;0-*1dcGRkeS+t5)}3y}P=qt2UTyf4noG7sI4%$Ks0*yUez~jq(Lv5H+!Qe zbmm{2 z3|X0(yAWU>EjB4p!0_J7vfwOTaqi4NlIuA>S%H3C?m#$Wm?qw3$m{Wmw4&-oc*nmi zgTaa$DY^01jF_?L*qGNfME!FGL%SvT;hj+Xb&9A1L?j&|t}!}HEYF%s~tXuDGDo%9V|_H?Pdb)X7aACJj! zTaYge)rK$#|HK)wC5lL#g*kYL2a`0ymvPj>@QnP``v6zp&?_7whT>yo>ompfwC2O{U94(;N}`CpmJTdvPE8E`?E^Zg1R+P(*SrAr z{G4u41M<`VAWOw$V&1hZGIxPD4S)6Oa7hHjrQ zqS{n^v+tSm$Ghzb)VVxi*Jv#L?PdCh*mAd+1M_A_81xtxYWB%7wXyDt&v&$nOw~S? zgP&u_=Mz&49G7t44mkiEBBBWykgmhW8zIpEc;O4nGBjT)6>)cdRtLECn@-1og8S*T zf_7@gsKap}bfMx4iUc*dSO@&8C?MMr*0<3mlFduq-GXXkPl(Ipzc^-h=omrX)I*L9{?ak~bsTqq&fN^93V@~yDg(8ow)cw)9O|>LIf`^W zjWeMMilO?&dlzquhsdQ0ghyhOu4C0KN@MPvH?1ykkh2emy`(yPwM=6|mx)(G-_}UD zr4a)nL%h}u!G4qF5%VjJ34I63w=`^B4<%b6+~yX=!=mr8?vhw10K!%fn75E4T@yl~ z_KWWpf7!2eIiY&De!7`)a~tv#KF zos{%3**x$)C|M_mSZYgt87tdn;9qr#)IFg}-a3O8Ab;Q4ep8D0 z?Fqdm_Vq`i4jY98kG@CYRzf&6AIUB(fX5>#x+Aw6SosbGsn!LWN~+8|Ml%@QOM!o> zxPSw83IfJI_c{4pC@4rH&hCz`D&Hz9O9ZR=Hupx?<_l~wN7oJDxSTofl!-yI6wao7 z1-3R>UJC=hm|I^w+LyAINzN~1o9__~(O7w%ZK*QW(5R`jGgBGR;rB!YtDP*7174bG zf_Xb&VfLqmCZCE+C;A{8No_919!O*>z;Qot>*@uLbD0~#b=JI0(~w-vtk6;8k|KBa ziRB*(lYn&w4k#Q?yQ4yYq(^Km!N&q^rZ(sqL423|g5|js_z!ISOZwQ!wTot+V4^nE zlRC^ta~%dGGXo8)H2w&Uis6}_^UG~5BU+7^g@@|kL@to^T&52ArArGF=&IYFCAJv9 z5qEb%0Dm4ey(2>?Hkw)d7d<1}%i8))s=&Zd%Jw$+le@V4Ew(_H-)EaQFQU4Z@Y#`UBv)J|6 zB`OSuRh9p7R5DkuIcUupjwkPgUl8lG$04_5IJ@Eku6EeO0@jzNlgKcJ7N;8C;bn8PLF~ zV4HX0Deh(@@8O^Dd44{ka;BLgyVja%J#qZtvf8`W;lYc#J*`xp`{Vi6XITk1z%y z|E#tM_d|Wgj=n?t&I1EkmtbUqwO(6h!kh{$QRJ+M%dp!C^DxG#$>N6^s%2Ls+JNL` zM4b10*i)4A6F zYgu=g62;$(!b#9-hZjVPHC8|{^^It%BX3JWe=^(qQ~>d2NO61|?DclzdTH2I;o-J6l{?+^edz2_VZ6^>ZuL>(|&hq&q^~DhFDh5LLZJQrrs{;-H+SR!1`e8dBQPdpp@!=h5_g>_IOSWs(n-Ti3I zJ}?4V(!q1ofjVfEf-mtO?Mh6knZmYET%HNL%Qe&|?eU=TBdiyIuYgRCqMLHq1&7v= z!M{%9uK+<8F_fys(?_uH=NI*;7^Ulnvn44A{`F5f#v~EOo^#jCANdj{zgOLXcX}O7 zoJKcK@4P)0R5~D6Hu4Ej3X?l+yqiQYHa+bc0i-HY$=iok6jQFS5%pQ{zV~JQv-;;> zkz)*2o_h=-P)8+^w?*zWKW@?}3H7^v#a@};Vgl^*)X@#EiSW$>df!NoMtQ)S|8XuVNl% z=WX!k1|~9EAC%xF3Y8H?dNhNZE2?GNjQvH;b$-XKt5oDkg>PaGQCtGE8%+@oe+MW# zfK)_*>UJOm+{1!$?i9uC)$~AO6-Wo+sX}QO*P%!*b^EosnsAzo0Smb`Ax#xc$aKQu z;-yrPb1wE%(OeKscYMRG(?nlx9`q4qr2AD`A)APZotTGSl}vd`Z?S$c9+DHK3^J$V z*@3a2(hH|=b3p$r#Sb%wg7z9`b54YU2_81^7Ta0dsJ{xupK|3Cme>9Q*|xvwryJ@| zJkwkOe;`TlXG{O|SGo29yA`(k`)_0H{_Nk0LZ230d(VO+xheAbP-PvRYmaba^3UH# zzeo4HjyF+30g!%ZLgNT-$HO)2N#o1Cu@ucLNi=xNt04;H)L?>?7k(gEKYu%${)j-_ zMMZWmd<1p>TVlk{p&>FJDr;q9ykvOTQX};`-beknEtrhIWd*xUP-2q#mJ(*ze$2E> zLl%N6w0yaH3kIkWtaCd`MxY<#o+n)FqqdEibG*HxWZ+Yv{$_5(cr8FlU{KmLN9k$P zxYqlf^mANbMk;&cw%C6dza>TbN3~bZwe8@ z4t&9D(^g4(WQf;+^D_gwY3fz4#t?Jvv;_2c_PFTy){S*^R+V|?WD z)bJZ1N@`QyR=6p_&>>NfHR>VK#rj?(X}OT$EW-KFt!mcS93$PDWNcw?T|NmN%))@V zOs8!op0N7@1Ho+RFgo;i!n6}+kzOoRC2mKU>TB3oy)4Bnt_%mo112RlQZK)77Pw`hRx9d3d%SKruR-+JM z-SjcB&MI2Fz!eYxpab9ej-j(eXadqRQcBd-BoB6fA#T99E$+P(^>guk=v&oiMCAt* znt-db?;gupiK7BTBG2M@C?#qDzvVgPyFV!Ya%8c(?Q>t*Tt5G41oxs&6z3>4{g(p7h8vi$!jYQZIqao4Jfh)eFeKbMTPxdb!0v8!pXYqv~0y zn_q?k18e4kv8K5c0=rT?=PeX;!cVMHp^Ungv`P<8@5=(yUHnG_dxOs{JPq@XUh91% zhfDN8eh()h!@?9bxCSbVIqw)eMNA!x=OZOU{tx?9jx^kxtk5 zWlfV@l8n$@G)oimO55TG%bJj;N`Ow7D)&?uqS_#4tIn1?>g{Azyxg)Jfw(nm%6(Wx zr4;ellUutlpne6gA~CbLmICnVc$KLfkn?jmPTAPetP?49!xu0$k)Uzpw=Dm=@vM0l zoTi|n;}I@UCj42fj37xqGcl6gUK2?ZMa_{+;MV!qtl9m?d#ons$|ssucVUVu!cUn4 zQ8zB0tO=f=$Xad!h`K6|$N7O0<;^WtZGo1{5#bbc&Y3O_99TX@c-Cfe`H(+u;_7A# zs8cSbBWz5<#QrN55;hkO^QQ9Ugc!T(Be{xh>mWT#OMIDWsp61={%jH?3y$3>GjvkM zTGnOu5b%=H5JA#G(ri%MW#U()HuA-mD2vZ`nzsI=h@%po(kw5vln@h8&>ufvXcjGA zP4c~^NawWTz~J;2w_9VSSmAGgdTl)yLOfc_xpleBCRqLvPU@slcbeG#hlNHEnQXC54+M;A9VZfFerPkn1NY9D+WEvAI<)E04Xq~o$qfL2kgR7iz$QgsrD zS$6wHAne_)MQ`bW_*i>|#~p=2ryw|g%d4BH8_U}c(R3adKA69m z99u&jeGKr=jr?z3?qIAw>NjeQ4(?8_V2XynjaA4?%ZG{HOUcK)(~lDXg8&i^2`#(u|)3zf=N;F7re&=T!WD zntQo9a!1r?wIu{0}}wgo)3&aCF#t9DB6cp|kXn;N zgvVq0)fVReiP4vBcTYRvGowp5xkrJp6%+79uoV+A>HJGAS?QqkUyYNX-lW%}_1n0) zDL7#9a9=JdEqmy**jo27+rSk-I02dvqv7B|G&9B!Ul@@4p29a1JY??KeUyCQXP(tk{h;~XxKyo@sz&m{>Sa#@GH5l3m|Oow(c=O%Q3$@vrB#T;Bj51=MVF^!{&qNGNev9~RrtBI?%hwjoE|q*T;1f)W*3fTI3 z06uC7UUcaGJ@Fxbz_CfNnwI|@I^&UdwtcMGgR z|A4N^*7zTG0bX=Y_}@1jul5I~ShIZ2VCL!bnuaq4QvGP+)t|#IrHIO#Um9g+U1f3K zwLrYCw#-Mk@wssmt^R92VKJsq+~-iEcVJK5zZQL$X0_4ItZ zH6*fvo#>`1L2!!);iZu#*}_?1Eb*!b`k5h0IP5B+YOH+r&nCE#+F-JA@>m_p%-v{d z(b`ze%jv}=y+<|@hQjg|U&>$oi@+i#lYWg`yHSMsWLlu2)5~N5%ekzioAp{ac}rl40RN- zA0~nEFepeyOnq4RL~gp^&rTCxo?wRtK`S^Cv5{7((xR8C^$ooosVMH8o*Qg;Nc+$oEqy z^Wk4$QlxCN9PFgiBy-RHd1f1hx;|DGP{pHDRI@}AG> zj8-*!Pz>Wep6psszIZh6&E1~=N*|2(QmNe!o18*~`WD0PcsexZBDE_zsN>lf+};3c zWIe!JC01$3Iax6hN3dtTUHYDl(w`!U9ifyx2+gjVRASDUvJIb0ji*q_5Bzw%IS0$? zW}CrW-DI3*GL=gIM?Mv2jA+($8J}(f>6~OTL^5#&Ru%rl#8HEoEH#svb4#f)r4=a5 zqKmmOZGNM35o;e-?J2`0Dl)~T`R@>4y1c|KWsQ85x`;s~CROmmqKKRG) z&r}K+dmpAeY(*|K#@|`$Vt3PE0M^Le;~4*BNeaoS^^9os)|B}%YVdQlOc)-8w4&MG zd7(bJ7v&mX7~wOhfAIn16nGV9ev1+JFboI(;ytqu#8IWo35uuf$gD3BYecF$fIN5@asrw#GBUN(yo!i5vgPuGKJ`=zdlu8~_vdPXUUx z)Y5Pe;QkM@hLWGYm^%-fBoMt|4fi>0Iz|I!^KUNcdW;_xPLPKknhL4|JOkn_QwTdH zjh$Nps?byVhq7lh0A6z(0@fdGX*o-Lg9hIcNeI)JA+oS0WWmap!c#!ZJwM}g^SW~~ z2YAoJ|9hJWe&ka3Q#t_dQMa`PufCnZBG28MdPP!=+PXl27IO)#*(J*ydfL>kaPK@3 zswukLHNe6x@pyZ$C)@fbhWyd8O0h1-l9P=rNThJ9cpPx_WnN#mH%80vLAvr;pB3+!-Oyg7?&oyp-IPiy%pIju^c9|QnroT zbJu{a9dYo}y$E~5&4EAJU(r*1rh>F&m27(xHFcuhC*a{}whleEe)nz^e~M-t)OPpa z&gMiqmTEO+?;Pe+Z4obU@^B{}m{PqK$PsvC#Zr%29(HR3(*bmTgF2&VTb-s048v2Q z3&H`a1Y55MQkKopk;jfSI&*T8zT|Q|pS94&gl~DEO{I6)n1mS(}7z*vee9jKZHUC&6ls=4UVmFeU zJ7ClrXU?B6PgPfFsN*}#M(_GXoaeoNd3AmX<{5LNw*uYG69E~BiMI>Vxh`7={-bPQ zF1f`Iv`UYfX%Jo8SEi(6o>pv&#Y;nXdBa1KRu|M?op@)iZ4ez znI%ZYq9RAS*Sn*6?V~wESkilB5^1}3tc(R!6Pzr0aV-UCw@t74s9-5y#xTm&4K6is z867FX0`qQIE!(cUqbFE)kJ93^{4!@~ttm|t?*WctDIi38OR11Nv5dtCyss${N7RHi zLh6~m&{a%4DgTiZe-aE!Q2(wq!1Zw;AI^>~sHQon5Mge+;xDwPB3Gs@^cu1%Ex zb|+v*I{fFSJw&PUZ7DMu{>Kdk^`rIMH{cH%WcUBa`Cj_{Uzq>N>CVObZs&hmt1nlC)_4x<1|58O|C8j8|s}BwM5-cR|j#Lq2Js#}V z^9ihGu~38HoQ_^VWu+yvtg|HlJLqg`(kt{aaKNBB{1i01!PfSE-RJNnT!I z-pIg1QMH3By1z-vH84>)8tU@j^?0gR98HG>%P`<%u8*{Jq%9j^NgUgrv&4qwr9o5X z65EnA!I0(G!O9!DuhiHAR+7G)Cj!b$?w(#Ghc33U3f`os%qnPYC~tUelAde85UalY3K%RHWJ%j?O9Or9ni3um7NMMW6Nf zNQ8b9WHO1(c`s-d*Vleo4Y0M=doIV3Y8>{I8}!8|z@U@cZ9Bp+{a>*F=c84$E_k*x zejb0znjW*;2vrM&5ny5BF<8A;G-O12KlC2UHVA!2`mb7vL{MO9dFZ%Vc6zW{EePIt z>efF70zd9q6Sqybs4P$bbw3NdF6i{LDC z-rdRNBweWEl$isPTmiP0%9p+OZxY`j1|-v2Ko}~WkIs?|pk2wwxg5H=qqlbX*eB8E zQpIrF&sV|r>uR-+hgiXj?pX{3&nI*B zW{vgoeT?2vJKM8h!yx6j@y?#BRqUE_jmWZr(S{^7Mg~`hjsE_e$poM}mwSc+ECN{_ zj{#bpmjT+G7mSTEogoAnb({k|U|vxVSYQ!B`VVv6Zd^U?uY4()P|flOzk*O=wPpt( zLWjouyIzZvB#G!_UGG14!c=oSk=*iMcGNvKXun`sTXjqaE4LaS6mvKqLotM5>@M6b zX6ib^#@A5^_qjTa#qM)wMhQw!L~0Bn?N)TFDQVJ9M1LW>>W=8N&DC(hW*cN`>1 zba@3nYwwN(Fy~S>5zk;TtmFl6gn0BYMMQRF>+|B+GW8}xvyfd6Y zg&fBzXG)9XDU%@$F}~r^gNYk4%cIS|g4VS+;4;)U*L9LxaUUm^~qQOW)km z85>3TvZ;N|7%%=V25$Yg^8E2>c_wf@n~?%QyF!6t-Zo&xp~Wnv%b>u?u?9&~mhP7X zlbADLK4L8^6c`jm?2?2A=ft-DAFou7;!B=W_`ezO=uj@Y?D!rmM7VuHvDbr&}uF%~j@Qin~6T4}r$hc!^ zL*=q;0h16n@KjVSvP`5)r_D0Z`v%&l|-+=XR zkBpQAR!PZVnzUP|{Vu%kcH~;?PLzg9?RdIO>EhRfcm*!06n}^JSY~Wp=5epO*LIsL z-cqE&rq97lSX9{xWmsS)=jSE^8L#iX*=+EM z{Vu?6NJ0mb9{qD*v;pVnvAEtyK5h(Y-bTfRZfCSPwRM- zFt<(kxD~yXx9{TmF4`Gcq&2JA6~y|)t$}8&oHuq6Uy%}NtT<=&`Gs}K*ghk$KquO# zOT?w{s4Y55MH~^2)vHO2!mp_&Bl+3vs;jdY*mVmHB%Ev}AlkUt092HZd%3aU-Vt7` zeoU}~wggkx*E^SI`;iJzGgo^rc~N#AR!QcCr?MwLRqBwTCsMQvXM}BrQ{fV`R@r$1 z-y867gelHAZ4AK}6m07#_DWG=ffD)4{i8z#1)&$EI&IH-VMWwFFJu)#Z3@;Kc}An9 z7&=`aTzz@F26+cRiBjO?-rsvZ`#O1!ONdc`9MJ~NUGCQdFZ2RDIxKPHtXqDcgI+%7 zm$7VlMVHykmlsNN>iXjvz0)A^%?BST=J&^_?Uv5#$5Vewa&&7S%c&Vu9KH)rk;54_ zT6lBj%HG4*Jd{0uv@FVv%#20J+NfO_(2ij+=UC65UT0q1ZHBO$wN^LLhBy8Hgg}l2iZ5ua7^y4yJdv*1J;!}NG6CX0U zPcK4WhxLkmc73T0IoqwbwMIgEb0}Eo4{6y;@qL)MmNKazQDT+=B4jzQCxxWXj2Yyx zpAEpuwLQSoqUhC|Cb{HEt-Kgq`8-UweRS&EOzbaq;+!;MBFW`cNG%F(dMgxw(w9N$ z1Vs|@nd5Ok1-tCo3pn@j)!%g^GNhmbbS5}Z@HX*EN-Ws@JbwO)gN#Vh43fzd#9=+H z2sy_0tXdd+vGx4%_w!?HYRTKpxe6CF5|{I-W-@-JZ8RC_({Z)1l`*pvKSZ{x{l2c0 zJ)^5a6Rg5bW`B4fZ|FPmg`1@da~rRD(8d;nEPf8B!0$;UUw##Co zmDvrANApB75Khh?b<6}H^r1kqcT91Piw{r3t9iNIdpw5GhbVuP@?+@0o2rq|k_!&Kz$Pmr&ZW$#* zH0pj`|G<}mwvL~yn$taf58?OlfXiIhX-2GDe1gw=z(U%kR$)z(SUSS{o>rlr9iVnq zW~bfs&!<*}jvD8W(!89@n>r_-mqHApc6Rg8{W)iVc`y>e+bHowJj+$yZ`GplYn($^ zBvbCT7p>st1{Q__xvGlyM^cJEYg*}RdQSjb=J>*&~$b_x^!#mv9Y@;BMg(7%b zO)v1!&8oF@bQ>Bd_%40hO(<4@bJU1m#cuY8!K4tz=G(P?DsCKm3oqbB&wVk(y%^dz zZnsG%9FJ3}}C%LQ|lgs`KvV1pYF+nD4bIEcA)?MQ{3KZMd+xs=k%Nmg~ ziZd6C6XlSBq$gh4Ji7aIL4KdO%s8kHikoL@K;XIuSgDc}yfo(Hmhs%KBDUZv}Dfbac`O^}zQa zESiwL*Pfh3{YTIJeS!tu{jW6Ckrait@iLbZgVp;P3Y|5Q3o-|f5~=3Xgw&sfI%CtI4fUGOjqb228t+iOWHhV|<*$@gc}!+8m6v?68()ntaQi zuhQNh(gRafy2@ooFoH2{1DpbnQYlGRiC%7HRhH|^t*Yu5y8S*MZvRxl%At$4Iupb@ z!iJ{&_B<+1WTT?xnn(C&25QULmYt3K_WqbvU2(6Nu4lAiO{!?~c^YrDyiP6gzpNy_ zNT;SsIZjhARy(t&fYa|K+}CN)g|0;utuAlpTKdn+p)90-4bZBHJXot2NAezC53J_B z?aH`TAxEdf0m^fLbFDc!;Zus>tZWyzfe1PDBfilqW67h{xn^Hd-?9c9%UqL7yHY&9C`I&CG$1h|P;yZ5If#I@Asi7N>=gG!mSggnzr zFYCRX^Bxkgv0$z&V%J1JuJCgTstvi9##r@VVIzTi@A+a^2;b9F=dG9%QRvbVf1T0Y zfw<3LScrIG#x-AmpAm9`_(y*~qm5T#n+ zy|w&mfV!OG66uFVMX)*@2@(GdPi}6#R?D~B-+S-|%kL+<_x(B;ufDUbDs^pMldLQR zZePR-aFOh~DV%k9)A>{@W@C@IFsAC#?SPQ0>U(%t4Y=rqf8%WB^g`0eFjayBu8xQA zNJopu%r&NI39S>-gG61^D5?chK0iaZ@{7q(!YBMN*;;i<>bDm%kO+FxBy#`8pE?ui+)bZJCGt4}`c2j{7Ys7i z(&uX>;6d*)=|vF3!!E334maC$&IjW(*=j_2SJ*hZh3xzWKugLwJ&jHHywg zDI(Rk1pRW`mRp@YK@l(FL6rG_;mb<7!6!KAoBFeWO4(c=pu!M)<$BsC_9g=D1EPpSCys8FfMYOS_}MN zgzgI$S8ekv?;}Lgfs#>-u{@4B)Z@aU6ClkN}jcABUh;+5mTO1wt_6|-1!dw382xGvX{bCeGMH8yIr z(ePDYl@s=Wy^O}gbS^ZeEwu*n+3}Giu+~O~K*^Ny*4|tBY*j8ICEnd~?uDscR?m5+ zh%brFkdjQ+>u8ZK|3>x>AW(ZF5EozO;n%OX!E-l5B2^}ki zOvOM?OT)IHS7$LG4ROH>*{X)2LI<8wgsk!$<1C>U{ZJ$o;dVPI{)<+6mJmIbc6r^M zn;VC0;aMvmE`&mTROuzIU6B%0hg+;)hHOu$Nuw#I%b=O?EIM{cxHaOE zW#_%A;Dg4cp&3-kV;}8=R=n7ptFUrQ_i2Brsx#~gEFAsOe@&wE9K-qKPjOjmvA+JR zgK;25nGN;$CxBky0g(qZ&xqya+)Qst8PO*W_dLb%A$@#|6;S6Vu1(j9soT1d1z)!} zr>3WY7lV)1WUHe3kv^N%@y|-2%jl2*qkg|{YXZ^sH5^ryVm`Uk?8rlJZa!F!({7_o zy{J|yTZgN1BgV9;vaB-NbmRQ$sPE1^ub;9=s;W!X8EvESti`NKhQxL0BFn%V&3DT> z>GUG@{m5_O}=Cfv>SDtzxUMnXR4+)7=rBSU8K57eWBiY^I ziTlJ=FWpLms?BY*&Gqd8mFDDV@m#lM-IRgpk8Mx-*y__sgkUH4wj1Wa8bUomj`RL9 zed$@+633KxS;|@_(kT3kX@8i>j37YNr&_u=fQ;9YNtrUR zQiiG6Sjo;-ItjQzrKXT}&mpPmXnUG_JCe6~QBe*;VN~diN#ap97i12!=3_n%0WvV) z3SNzHIOm*rGMBH!DKv#HD_tPq)>kwio?ud%tjlE^9In4^w_AAW)gfHIKbIWVF6Qy4%RaVVub;7ej%01>Tuztt zHg!?*1Lo_zoZFOsPAU*oI}PZI38$b+g%A?e+iTd3+!0`Qa@Wi^vuEjufpL2$ZRoH2 z#3s?9H-%+{a39{ajNx4%x7GJ1`_ElqdZv4)IQoTz43x9(pse#_~)k~MA8 zz!Yy$XUynWCnvv+MG=s)hxAE-zm-!k?P-Tlp1N9`e#j}efBdj|J3W;ief5als&n*O z{ZJ{^S|?_wHj}@isbAao&d5Na+5wjqD`s>rlhOW@twKZ3%HFzWePrto(WyCbCy zNKHvWT7UIX)z$E{_j#9nmaXh||FI`g&Or0@S*Cqc?o4RiV78GaP>?POghC}LWj4>J z%{sP9Cg(EtYjxQDt9YB1*E&x@OcvH?r{cEqroyJPAe>Vrzwv(F4m+_#x6ZQNp{9;O z(xWQSTbzV*lgaLdN*+l(6}D zv;`#}ldJ1waj8uZQ`L;C2AZt?yWy&a)}DYnC{W%GCU%QF)+|ls2P}>SCc~%Q*xwNY z%aDv*7K^a+uLj`NjFKu4zuOOZIeuv_B?1N;%n1{YA|_0``Ue|M+cHk#ATN{3L0V~E zyx*ie|9&1?Q3-yTiiS!OLY~hbAAH}?9hU-w4mubF7mRr)9zrC0%p7R$`(bjod_D;k z7ySC{`?)$Xx!H2JY=61l0bG2l+~z2|!q}C;tsay8#6#EA?xRg``*fBx-7O1fa=X(> z0Bg)Tlc0x0j4fSjA53Y!oZorf#2F(K5k2p!S=>{}XwUNb;GdwwP@F$N>_N=VUr}t` z3VH=UeUtgP%U$Il1kRZH85HUfxxcbyqINbpZZv23!-s@w;308y;@EFECrovP+nXHQA$M%F0Gw;K5+16>^sBSYV!0-|*=SG%_Z7XS zJZG^wZpxF3ExC%=W3L2$lp@9RdUI_5=w}4gWs(L`E1Mf&sI+Yk;DX*#SCi9X_CK z)@fuKS`1=II+$y0+u4(jJ<-AR~wKpb7!=`!~3Y+fkMYx5zJ1g-HqgM z>>x;YD!PE=80!=)<609Na5J?lJ#p38`yqAgSknwDv@RqwfM6#CTH)eZV?|losM=Nc zARRue&iN5#Yt(69uKm|k>XE5+e3ccxmbX-`>4g%(5xhd=uklcO&x%$UIPRO;+aEPg z9~JSF?!g9)N3n84dk?GIiUlZm>OTVWb=#^3MSq6&KYYg`OvLh}AJ2VUb`r0u+yA}7 zI^Om{CK8!LU#>pi9k) zr}r%p@0zEx`bNC~_?u8fZLaSZC_UXGOi3#Z#23O-)3hX&*->dM5tVI4`wNw3u&iaI zX>7H_7o@@_Dye6$=;dg0S5LLo`ehSTc}qD^BPR|WV5HJJDmBdkQt1eCg!x267Y*AM zV=f04pC6@(At6Q`5;2~KMZ02sU9Ka0Q|oiCr;)W7d$QjdLW$g_0xMeXpi-AQ&PV0S zsRYS*5fnU~!9` z*UauKZAC?;N$`F)vnoYE@qqc^yEbhtEhYVn@on$@EI+TRT=15Ifq|pLmC@F@&eBmE z|C8*SPn0Vyi56>@tV^`AeoluiPt3`{oTpOyZTl=q@GSJ5aPCFLV&1OH z4f6=2B|Lm#*)cr~ff0zktRU#x&os=oGS44McpKW#%Ja`6v*QsAh|R!vB;+46k1L6ULhO)PT4CCc*&E8#{0hyFYufdv{HKwr z$5h}L6h-}OpqW|CtI!^S;^>Sr#9~Fhle{Z;gf_c8w#7J$+*PUaGUJ+I46^br|FhNh2$fnh;2AX zZ0#}vF_JD_VtvaC3)B&Xf%o(K<1+;;EE1=F{|>x-MTRk6BKcl0x>_x01!^dR(zMz=V> z8E8Lp{gDcRH}8C&*~^|dk!pnaT_%gzE>|tB*lw`|s&2A)q?g(IG}XsB%-rtdcR|AI z{oJeys(cDc+U0XRD^eHx%}3XI1(GKTbt#sP52M*HPC0k_ieD4K7z#i5*O<-Dqi z73t5d<%4T`9u}Womefrb6ZV33i*$W5#pgT%u64ZDhoh9CHft`XyMY&F==pciD2bP= z_v>*BjGq^ef`S(nl`LrxD(m^{;gOzgg-|^mCr2S)-hfDwE4@&jwzwpA+g}s8pHCf9lMKES;4769-ikqe^=qb4 zC8Q(QkNlNb(!K1(Em{XcSGM%4*v)A zKh*yT{U0*^8~Uxm|B~_F(Elyt|5Kgql<k(Ieur18BB3U{Qx_l+)^pfu0wJl2 zDkW~q5I!Oc6A~4lEN>RO7Mls&4{Dw5jC`ylf5HUUec*%dvKr`B}6E<#v47@!%J~i9tJwFa+(|QST zo2-UJ3COfJb(5j3VNMUNz z=|L}cKX)KOG+cWVf2zbtBX;}6L9R~4?S{_@qRCGf5zPt#!+Fob=beE;6v^|bTSJ@P z+j>x`%)B;9g+Sqm>q{BJWzk#+ga z+Y5hgdntU{iwcO862DAS<6Y1wr@vIe08gh zVL1_$d!@XXIT|*kyDk5BBl?%RO;tz)Vzk&w(PEF;UTaquU|e%zx|^(eG0*&x9%VvT`}?Vb6pQcb&o-t%nF zPV%;rN5J;`l4XORlN>liS!18xamk+%03fv%Ew(Wij+V=2#}L$fh3f}^#*cHkWYKxC zb&MQ}AH}ge`7C->Xz%?3+;?yvMby(s=x(t3q_jJ522t1K%i-Lg4;?u?Uvjk0@9_*( zD-r&%bPmS(`&iE?MA-6_1`LxEwe@O-#MtqFyq1^U=3NFm00@+}K``6RFJ{kieh?D@!Nr9Ryv!uee40(8IM}E_qE(HVDzw$&-j>C`D zec!;W8`35c2jhGL5UOt`asjOi5e)wrL2u0F%@2ZB}Eeb~tTvCa1W690-Z%a2p6 zk76M}14Q>Fyuy)cqNxJ!E;UfUlEMS1?r<;(!Po;4A=0l9cVI4|f9(jSL)KFRZyl{5 zK`R%^pa!aC5T6b#$n{MiBi?$6VlB~7c4!wSmB9L<1~QzNImh`_VAa}BuVCwAwOHuk z3yt^0+dsDtt=you_wv~sO0}4<#9x%rgL>PPBR+b?#f4iOSUbToLwHmrj*z8rFM((qY!@+b z1=HVx#&Xw)G2DG2>XZ}}r@NTVko(&;o`BBrNpnj6Pj>gtgk#?+Es_jDX{XM61r7?} zk+ZZxD+b!#V+;=AI*)03a&`oB5r4r4X{`>MV3V)S@pe@!Bu~w6{R=n-yG+-wqnSG())91{YF=QATmLxL4~XdeptUZ~0%MuYMzMKM_WnJ<2^r zKZ`A#$kKH`au zbV-^6sJ2w2<3GJ~7L=8Zq=bsUpN>s6#aT(;t_oSEL?RxKAezEh?a;hj{Q^}lhFyQx zf0+NwGDRZ!EL1aC5Q~;wpr{Z;G|2N@zhL#qn`_z&gx1#P=o$?bKi%XiD=zue#WjLo z2Fu^)I>qz%nmp4ZbiQ6zq&Ymrwx4C|<|`n?!yx2m1W|8OS$6NW-g-4T%i_PuxHg$= zRCvTebat-Pwc267pHy!IU&35h7eQ95w}=eRmcTsQjVHg-t&nTm`wj;y{&cGDq|C3m zRjz~b@ndaSZ!s8fvdxOz)S@*Cv1y<2Qj+Q9uZ!3qW3C;DcpL%^Hj?@H9cpsf4GtiC=sozJ@2{o{%;occ5 zDaH~!AMzn$#3V)|j>elCsR`oq9+FT=CYaO~f6KVKcp7X6`DqIhd((vmEO%b72x$6@ z6EnJUy&Zt+u&}B|)T#c69;3$xUDXYPbqi_o;=JfKIC+G3RB68-!`eJuh50E8sE&dX zF479MlLI8X^Xkl7D!Wet&u_MDHGPjHE3L9ui_$4w>S1U>diBXckm#o)MN)LFjbIss!T5xSwM#y z;#YV*jBSR7i+TbWa8?BOBPm;yX_TDD@TBUJbvBa}V#7D>iY!31<1lq(KN*-@1yZjw zEZV5oQ&IU|?WT}Qv;}~aYRdUo%y8{b=h&pG`=BYktcGkD;Hf&g%@mgrIt_sG_9EYY zl^R8T-j9txDABj!yb$$^z+z3n{UgmEo0v)yNT`O^2!s_0*qi5x$M}sv?Xraj+}<^t zU*5XbZ1z2Ip6n@LUE8pvU7RD${=QcSEQw;(~PKkr2qCfNpSBRj2(WqOsO zbAM)vGiiQO^Lr#CRYmB+dYe&^q?6CnuDYDvFQ>is7m7x=?fgwnf4c>?UeKoufl*1^ zlXlM43(qd+fVgC?lgV)$F(oi{+yC7(dxH#A{AhtyaYcfo%Myj7H9V=!$))Eq^z69{ z#lpil-f>u?P+tu+)8^ zs^>NPo6)vW|NF1s#%-rZ2+HxBJC3f?{XO>An7R~1UIq&a&N40HX5T3zy^{i;XGR90 z8MEWB=@>}3_0<9mYc002Q$i04;KN}8Nv2m!R11sD7vlZ%E{!v1Rh6GkI{k^tV|k%~yt?F67xcw7g*@J;D!moAvgs696(bfNm3+<21?v#BRRwa?RPUR4Iz8^;pq0 z4z$)XW=r;mS{G%cR(6{+RD|dS)j{h_EA)|9pKrhrqH@;}KQzz`*z~Ar1tw@yrJL|n zHBbf6?HKW!=%~*2gF>XZ6oZcLG1VSaC)wpehAj_80_Kmq_q3i{W+My3q3IcWDcxpr z_Cq*`5>ov1jO99m@AG)~z7dt1L)a7l%0ds#bClwrFXNMf8hfybB$xP3(qHFwE-TOB z??YP~e8eP!XaOh7utdg<(CF89zzp44-4%M5tF=sTTD907cJdD}A+icH9}SeV&c0ru z(e7DiQ$P9OOfF|mEMf~ofM1z~R{IFyp#L8zm+fRS8VHH}5ui0k%V@VukOYtxE`p$m zfbr*bv0r=C!Z3<*Vf>)EQ6>~}YK<1-ppZ|msMroVVDgk0*J#(pAee^8_)WvuCH?uV zRGrprY~eUiQ!mMg$T9V!Nf=9E-hA10`Cu-f28;-9y7qfvaDv0Thp@in%C}|4qUHvt zo2xm-%7c=fgP&)b7-%bO1{^sXM=fZmez%DP5JixU0lbZ<%FzibQt%E*x&Y-X?+P$7 zbSaXg{Id|cC#W&K>D4L(e4lfY_VpD8$Oolr@UA}vQtm$)LWIQYf*_hf)jv%k<-e*F2?BK3{jY z%S-SAFV{XVb<$aU9YQh(ov-ziJNM4Db$YX3-#6(UEm2eE*ElRUqSi$j*kj+I9O}9J zW8rq^uOoWx9rh)9GAxfqu_|5L9}CX;KeoXaIEXooe(Qg=ug^1En{NleQwjWMEa+O8 z`v@Kf+Wil*@ug`}n5=!PpkUhGzBF8WU&;anZnzf9{c8>v=}=IPHz~iI?-r-Gs8^Mt zyFcJLgh7yHo*fk6I+fve&Sq+jpd4;zgG}Dd(!~E&gOSk}Fsc=A6J;jzGRy;JIuxTn z-n4_1xZA&SZ`i39R>1V@Y7~?doGu_B?^cKY04@j+zUwiB;qlg zUini+u6{Zy(<|S337>;SOC$8eO21ruOm^KIm0Jy}j81nQ-5DI0h#9_e{8_bjzWAfE z%yH)>a-qtL#q)-T%JuWyY5;4XvbQB|f%6F9<1>;S8Ml(-zlviNkGpPkxO`#TzVzni zB5xl)yo1}%Awlst&|B88oUzIg2SnG>Q>{o4{d{qdmM!4YQH*$XJUDmh&vA~ z9NnbMDBIlEe0N8k@b~)ZcfMbX+DgiIF7Yz;+(Z)N#E3}(?kj?+F-F>W>wn6|vd+c! z9^^E9XOAE#aTnfJ8}f6CI;TNR{aKVQ77X1i_srbt)1^4b>FJ@J_XP|VE?moB$8qv3 z@5(MI>*a9TB`^>u)stiXVZ(0SGJ-0e9GNdH7pW-INgfELO=1zW3Z@o(uj=4VXaM}r%E zyOt$hL6I`q@Z*5Y77`I?s5;)!1Dp^hdzHF2TO(P|Muv`n(bB4K{vi%#9+Q{A$%#{% zFj#OzZ1)4%42h9y22zri6PE141du&vWZLSESQ;&i8oYMPr74o2w25?r>L)jc;u7yi zdQ+DWWbBr;qNSui+#m)S#9Q2_&uM#Dy`@9oko(mgo;KTB;8oK*%_R|o;k7>II$+8L z?YPXGi0=SKe@^Us(V{QkEvzb~miP0()RwlmmHKeHeg~l^6G}YX_Z*Xc9+sMy;ru>C zNTuF&B~}2|yB#>*JvU!dGqbvhZHITkNh`l5%4DUrtQI@7xl`}!sqOJS=2Bk54OFzrJo?(9 z<+t7dLiDw6_hEF!>p`9XYR_4m2KVCn+DT;@_{yw#jg5xA1^Nl*r0P)&Ao!ZVY2pcv zqt)T|;)R8q{;cI71`Nsh>LlJ`$;(at#-Wq^yV-MKYiX%Hh~x^xTi&+Y&b}*aZ196u zbwb5vx}n}d0N+B!d%ypgrq;UqHPwFSmnyCC^hYu`ET*T-LW{<-!NWC*hCR+b3#4ye zsEW6~+Sz>u3CGgEumnNESM=?$y{hb|cDcSWpYG#bN8)wwxgYQ4bYdQIv$J9>*IKk# zl3*6DbNtnxM>KNoXBXFDJ8W$6RS8iT-|StwQq~e28!zyBo}0^txQd_orQNF#9^$3) ztY?9xLPS=;jm1^NnEI_3HH7EI<=P<*~M{fflr_UYiQF0y*ppIWif+3!Hs77VOWM^ zCQo&g`JtswU|R(%^c!V4{`_S#`R9$y%Rs{EMb?&oQ)6_}^SuQBVI7_P(d&7t#Du?% zQhWWo|9t43;p?QxNJ(sm{_VCEE^^rB2UkggMwk3+brO=pDbSJ2Jj6z5W^04he8xv4 zom{t8#@+2gW5HW4v(q&Exc3pprVWLwA^rTN8_WzgQUpYh!pR!tRdl!=aHv~CFkLhgzQZCTq+<8Z>D5&^c zfaglZM1Pb~y2)@g*)J4=$#ZjdhJ490(?NhHka`2#;&o~ErwBDC zgS~|_w8}f(34xXS5o5w&-H>Z`Y0u+PD&-mGxd=|D?RzV3>uZ7RZ{fcov}YVttH$(! z=n5%Odf%;9?Zc0t1?_+!_oBr2h#E`!61C^H2MGoZVaO)3+&c7v*3lVGp~TRj#-mUP z6>{Ba-h%(80#-YM?#BzEgR_tt=M@^@Lfg*uB@*vL3$^ zxD!NyDhI{8Xu;P@NKK`qL}`Dr1|E$9-!0TG>;z#1gdFdr5$)PW1N-%9J?t=w7PT>U zmIBy{q5;#8%pC9xrlh9NqvX7Guy$@=FK17I23tC>TIsdK=EB!3>S;Ga3K(FZ%- zI#(NlBRCs&y*~nr=PjU?KRTO?zZB4SGA_?>a8z%R^@9w4WXaeCJ1m67asyYDsyr99OrZ5bWV8Hf69Ca z6nwl-_eZ`qkBS9JNdKIDt86b#aT{P!J9w(0E{W!3hxrltdW_YyPtpm%JV zZ5}V$uQ=lI*O8C;m`}H<#ou&MTJ3gdrefPR+W93vkK#NSNtJ)B##`>MXxjK!`dP{* zp46NZRU>}5U$(+V&7Y+6w`!8v3Q~h?rsaHSn9RH#e!?Sl95UmdIbJ+iRBiW(KUjpp zMn99d&qCQzRxaJ5z4b;mQRj6xpE#AR7Qd$PPz(?c$m=k3SsR?LS$u*aH@+-oHAB5L zZm!tLgwVR!juN#)FQThsi(r`J)K1kcHdb5=l&bvO+HaQ4J?wXm(?Tv&n;azHyGPj- z5ZMeqXWFNDpv5$+Fv!`XA~5en@>pxT-}h3V)DpG}hqRM>sW{stHkQ%8n|bXu#B4U} z{#eCVhT)-3)^shq_Kg&Hk&w<-L%Z*N;;uKk-u*3$DW7yhg_`49d! z-j8p286z(6FCi9*?G}gO>dt(CwxDV5!}nq{3>DXsD_1v!tW&$4*}L;_YIyV zd;j|nF$dW1PP}E5uITgH8&IBasf|4qrz1N~?U$uP>DBJ@k zA8hu5A7Y8EHs-W=-Iu|>4Q@Mi96zk?t{|FA#UG} zKw4|psdot!1$YC)d)b_CgO1*zgGk<7PJ5)<2TzzkWd`rH6Bb`Zm9?9^Ra><_`BY8A zjpY7*4L13^Q7q_NE+?B19A2*nPs{^2;Gy418<+MWF)hhjrf?}*VeNziN}9mX((eC{6VAkP z@wHZQiRPXh%O)Q#+B>JY9cPMGrU>wKR4!YMSD@!1v?~#?oJ97DZemHgl*D^}c-M)X zr%QbrtbG*J;N!RBXQCFuXE$^_FUymqQ)Z(Y*mzj~>`Ac##KgslO;8=MC}-7FYjWWI z-AB@BQ7-AzK~|Hw#MIV+8*_~js!ef&j5)frgNo-n z84Kgkhb~#l^{DbeaKe@wr1&ddx7>sR%=h%XFeS;TX(=cK_HWQI|9v}7i6$J#nG4iT z(*!ydi zdJ{i(@{DN-Q=<RqM-NS5rFXzrc)~aNmq4LFJF)%Pf3D)#~leR2`B<*yPV!{bN^}E1iYYrMuYk zW9^eR3#aeBJbXXCf<~!0o`hz!zE$H-xNB{-Y$R6L4KzqyTV(Rs%g0|~gK>0f7=LRv$WyI1!a!)cvT~tasYexff;6W-af= zPHL|W*nVzu^O^tQb}`oycsz$jj+MyUn{C&hcD&X)@am;|Zq5;Z{ob+975gl-Mw>>r zcTHOEfz{py34Y#(F~Sg_z~=2cy{g0D6|*-~)SF2-J>@vvACpo57;)oQ2AjY-`y>`O zNhJER(*rD{Zc8hEC2=$#ZGdvg=VB8o^Wx?B#I;Rc;hxV$m6i6F!cOO2a410!x22rv zn|}hb&Q;#9_UB3+yx03R`5BZ)ovey)8Jsw0H5)9r?h=xJ0)3r*X8-Le0 z(#G9U!&K+wHOd8je9f1D?~m=E$H&&r&D+MsYh~;^*XaJsiL2VpTY*T|i~jY?T-yzU zWp4qA`U?($ukUDB6brtU{)5C)B&$cZD z3(4jXU?6`QGTl(Kw)6S7*c2VnLYZ!qMaOIKv8;8q?b~VGk(*3sl_>QQO{jnu;Ua*; zlWHL5A3E$pYIYiZ^uY!I^!TnhXwxlQepBLfms;5U!=V9fok*7GQ7739b4I#_I!M|TtN-YkJimI1U*8t-0iCiSm$U# zV227eZxGsj2VFdyfqxM>JqyN|u^m5^x7!z04eYa2L;L>7T@=n9n$Czg(jdt2fT>x! zxkYg8qK>?2V*CTDowaz#ei+1u*^3=5dW`cwq6^6ocTDS~7K_m6h~GaIXb>AQYfy%w z9AOyUDRe{xieQ+G8B_!<I@bZUYr^#)zbi@9W%|63GXT@g8h;ZQJaHvjjY^N z9OwAkF++zJHFpP9z00NuCXZGZM=ryc)t5RS&u=$dX-MN=J7kjLS36{}`)}j2itLl# z=|a-6{MFT#Y$c#90+-I9EBFyaFHhn8RCRLD|vLp@ASac0^;17SXQQae%o;bqK;13a>qR+r7nR?zGBk4wVY^)uP zp791i$^8q;T1D2FBGx%XfYDGz*-mND*IBn^ti5(PQT)N@0_YJo(j!cVe9^$JEEe*l zmrYV|CSy=#M7(JTm}210)mQrXBchsrUuA1@tkBS zs`4P7WK8^#kMAb9S{hSby;l6AU|Lknogk&e?sN@h`9Os-VOSN81PjJ)Bv9ja9}M(V zj-+xrPGZk$@)>)Rcm!2_d!Yqg>LF+9a0+;%VDSc4*Lt~x-NR)#NTCu)?Txi#V*ZHu zmpdE$^6qTWD-m3k4x%UscBgs5-^|HERFL9}Rn%hntn5m8c2pv;5BWXC#3Vocb-?d@-i?C#L`$rvmsM}v@F=li#7(@J zFkAM+deQ#ETNQ4NQAY_@^+0eoI#ZrR@HayhNvTmaKwtg0)Bj9i2XRwG35B#Ul%w2| zfCKetIC(Cln2$5(IZ08%-I%UQWWQU6hAXw&(icCx0c&G)9dIQX`C_w-FAEzdJ>jF;ZL%XX8%-q<{#Zq7|-DNc&57SCu zQ5Ba0iRMa+UI^3u-7L z3=w+J67z~3_ybD^Ss=E2W%#YB3wRh3>Hv#e1%d37A-AYf0s&`jftVOJm=Z}$7tQ^X z(Wm}ATi7V#Nr9W1b)_w*g5`m3aHXjddfQT2STZ&d?^4cB$hSaJJsd;0@1|O4CH%SQ ztuV{E=BaLM_=O^0#H*rqcmq%PtfDz5zbKE6Le=q!KKxKK>>lzwh05~e+C zKO2&&`@P{;pD;z2l0Fn*@M3}Q^wLUH7S5nZTk$2}VSlCxkADDI-7 z+IDOYFZBVZghF8~4HNq13mn$Ah!~QvGZx(ZwauDt}_Q)wEXF z%YJqdf&DC|jv)&ZXX=IW0TyBQ+C*|vju_5S967%xsVS1}{|U|@rwootDd2)vtIqJjP4*G3y|V zRFU9Ga~q7LB-qBL5B}gQLoOl!dGCmZrbogD7t5tz_#H#42Y;3Fxcm7cn_Ux1oJa)} zLuM7Xt7kIgEGX>W;6_*r6H^&!s^ado;1NbmFnG5Tru?n7v6RyZl&uW%H)V~3XKh6- zdE1*lA6iRr(p5UJ?*T_0;}8AX}L{F>P~Bzm5=QE@vRTB+*YO zMIf~FyXE{f90;PMG;J#2Ck<;d79cn>hS|>qQx#Ch5d-jcLi8F6>UoDHA02q2$I`g$ znBO0jAPzD82hhWQK^yTZCqr-~GITVur~1W6^(Q=5%!E+O%9^PnM^ZzO{+6e<;ms2p zwJt9Zu|rEQ4ifGZze42Sk~oqC7h|*seM3Z_l!1FQN3qYvUc&56|xBmcY>prJUp}QBTSMI38 zGBSLxYtDtYTE$43Hg>^9RIk;+gx+=&BZP*0HMu@5k1#(HKBeiK)All7$)w_8tTqv^ z)5R)GC%YEAFpVR()|-6-Qy+FK4)VaxM4JZ(k(nL)%YLcchGI~D263czl+Kbs!KB@E zx|K1P3IzkJU%qttXpHU zTfOYBRX!C_QiP-xXh6Mb1+5eWCXyWMuP|28%oef@y*FX16pG6CIbWcHE}Q<4n7~v; z<>!%(g^r0hd9K7nw1Fz7(n@`pPNWL*1>GGLrUf|z4y4vh7kSCrM3m5@5GZck zkkCcc()WdC@9$KlFDXd)Zx6`&a%49P8&y~j0vVCBz?f2w#1dPGg{R7;p4vBGs>;%r zyJtVc15E7R3>=g=vTm|&^zEAzPsCC&(T`#dzz)cFI_{IX=K#WXZ*4Q?cxkoR#dp1WKx{6uL8ARZx=Jqx{ z$`0*j#pB&)%!=1N;jiJf{9#Y2C{#7I_}JQzurn3jh8edCIsLg~DPsTvj%uE~;Q{&m z9wY9=;RJDrAOyrKm>3ss#ULA6`L$7aph!ZR)D#$arLSjYYKAVAW*n@7cnlrvuVDkx z`T6GG^tbI-g%JkcDzImqQ!hS@!raeQg*TIBjgC*b`M^{+XC(jMCk3Hp${hoOMkNbm?um|X8 z+2Axbvc(f$+WqLEogBO|+obm%V(Erfa2VX3huX=&+9RjWh)vt&zeBr9d$5 zd2EFK6?cI>Pk*W>99fZXK^MnD4l%>S z_1ep+fU&&wkp0?X6dC>}CTBbw3Hc}f{#W1r)0zB-P5+-o&2S(D>c9NYco!c8kTN8I z`zI2|4oR7}l_&QPx365OT@Bk#7+y6zLq1K17Tji`hQ-(PoTgd6Lzm#0+Xdw38-G9 zE;2xPH)taNizyv+l!N>}Q~v%lYAy_&DbgU7VB3`l_Hp!Z?pmrlTooB`E+=KYKX$Em zza{DH^Lg~5ysZM>VkmN=+%+a;zS-w-H?&M)gNY?FhB+SjJ22pLGx1_0zr*wWy?LCF z%M<3`16=82M)s%T?T$O~;Cyh$1%Op&(icbK;ipQeaH5FP_sCT>EH|5(%!v#WRd)^? zWnoT81xDl47F)vLPUC9q4QWk4H&9e%(nF5(hZaZLw~M4kWSsernyBwI!3`T76b!L& zKLjLpxbvb9S1cNl`@r`lJaLqCF`pt-8`<4(e{`WMo;r03+))Tugz^}#WcC4&M#~`@ zM2r7$#r{(=Nry3yGV^Z)y%*;#{9l{IzpUBqUxR9}L6WSSEWk9nhqD^_DuX~z0PkpM zxj)0LL5;@Nu zxv3!T*vlp>=)a=e#^lW%AxhO@Hrd~(%~?U9zz=GTLJs9H!6xX)nZso*t(eWN(H> zzJ2H6s|05ADm5&`4EP-&C#ikC74k`sO&bUq`K|}U`DJX^zdB|B>0b|Y zZo9gtT^>>iT3ACYznp}U??ME#!)0znKycrgRPB_YNtH-fU!z#E@S(hQFzmRIsRK(1 z+bz3Ndo>p;`Kh~Eh}{T=S1ZR~eK}$hR_G+(tOttg!pe9zl`?o}Ah5Oq_#zRGtF|92 zf&AaujNAfBISNjjbDHm;m#S}OE~F@tNu{8wuRW1cE<=lP#sU+E%v?U8)nPsdL5Fks zBEko}4B5H{ZnuE2Nw^!^nOP)r4D|3gW39(k=Vy`@%(NNeQ zd?eB0d^4wurl|OdOl{@D zmOwzOyETKctauj+J^z-va4uK}hbW2<-8xfqEJDD6&9D{8#s0dpxM(14OIdM8@p*CD zVduw|-LP~8-L2`DjXmB@<#qd&qH~4`lC;%^l0SMy^SajOL364($mLAOV82_!+Nv*6 zRL;z^p&lhpF#c(Jz1`P-;n}3VW>09T7(0BGaSNk@(Bx&g)=S+CYph0(ai*xT1;pUl z2ddADVYw=>H|$(1LYKJ)bHjA4J-Vgwpoojv?ZooJ)ouaEKPieQ75$Z3*k8RmcDl4! zJvxI2;@%ol>`h;^;^>AUOc&U{+lMLKh}i;C=~#?`$!P~`9mW4JhB%+>d{7{lUm@q{c9JASnz;xa3sbe`64@w}Aw#hXJ#_ zr?`WG%;H?P)@nZF71!DUghpqXxrqrBmzK4?3ncMjEVWv9?<*V*pJ9Dj1h`SP2aA=}-I|~U z#`&9=uO1M1Hne1n;jq*%zBSV-T-t%U1_qA4l6X3EKm5LM3QVEg@LzIEQXH|@ z*p#qN%oP#cy4`w_YLu1o)BN`rNTo$#CheLj0~Vl0WNz3G!_Z;6v2J{^D4g9G8th%T zx>hE+!RY$>Y?kHq69s9pv4Fr_rfd#k-sF$u{()G5gf)TPxtJJYbN);8x*N0v5-5D?CTyzJges^;qbZ`k-yXWd%~8wVXcnG^^t z4P*i}M4Tz?*mg};=O&7jE{$g>{VEb?iit}QXV^129h*E6p;d4ED5Q88NjnG=^u>n@ zN4}}x{`NLQk7Tx-fXqqzNk~PtAVUdq9q6^Bejj$lRkvS(5Q06XXW-hQ$?lcK5!^Th z5~Mqapq?_~e-)mCNSVS6x)O6mveL1Ia9dOB%8^x{%^|?It9^;3!z%2)`^5B&8Mb?$ zd7m1`Rh-KLuRO@sJCht`qq6n;OKhdB)d+cTz^oD75jwCXTRSYVu;4+-U2>#1S?bi@Z$YC~AWD7DvV%bGQI)^YcKoPD5hQ8yeXh2AU> zB0DxRQW6n+#ul`{HAyVYU!YQ0mr;|8js5l$GWCMwjWIpldzL08mP->iusE6$f`2Eo zp+?h3Uk9o1FMcfL-DEAiS$LnyEkubPOGb_>`tdKp7UI3vh`#)RtIKhq&=n8n7MSV+ zFWwJ?pn;+bt(^$2i-<9ccXanrmIF>bfX2x~b27q$4DJXosU`rDy%W^0GH;xwBk;MN zDHiFsCI5S^#js;YbUgg+Ew}DI@t;!|agH_Y#D0qbXr_84k@I1q^rSl#h%t+m`+4I$ zSwL_mi6zlQy38A*JpkdC+;D*W->cr5KHv}XaNFaS-qss?ykr| z{`Z%C0YG=#`y|8I0wk5v^fEGhs(1x=h$T%Zcn9`gNf2j4y-d+xg_oWpwPlUoG19=u4FZB`eu4M@ZBSK#3j6W`LUP(XA^nSAzU?@kQ}c8|^}Yfsa0+WV zkQnp8{?d*pocfdIafwWdta>ENcsUFnxHC@@G^|A!0Y@YZfLW-zpH)JfwCd{#2f2EU zrGu@IlfV%`Z(z?oUcy2fnCJjnSiUzkvE@3%?oOJF@MdK&t-%4?n6JQ?3d!nD2wee9 zSF91Yd%2X6&hA-wf$ zHz6}oXLeTGZEtIGJVmv}%q{AJRyTJiS(g^0@sS4)nM@H?6r^ZEL=r88#!gHHVbOKC zDUg?;=I(YhKlB-tkxk%FWyOR~5rSxViM4^{*%^6aj1}OABson9;*2&S0u2-e6y9W&NMwYw<}0$YPFP-h0=sZ!_Y~)y4 zAUqJGcfuv}=XPmKk_i*vytOmO1Z)xVzm*Z04i={xQ-L=zCEgcU6<;5@SJ#;0+NzK> zEgg^Km)^oNpEvWsab!7nR{|FusGVFDZ1EtI3-#1j#IQU9J=_0?xVylET@ zPU9+`fDFwI>O`JXcXadxi+@e>Ol45{>z~D9l6he8+ECLN`4W!Al@zmPD)yj{Dh)!S zfW#l0OfrT$dIHfw=Co@;@14w-X``}+`TLK3idyvh#~^MCp*b>BUiBPdb3m*E%xv%c`UqZO=2S;HlwG*Gxta{BaPwCLpSyD0q=p@L!B-?-y98B+eS zHzrQUZEuI3h=0bJ?4W8~v8r7r#!OB1rUsQh8Hq407Q4QNXbx&C`*pj`(~XpEGv zH!ebEj%;NJp}C_yt1)!`HIe*p37o?4Pa__cc^`|RXbHV3FdL?^%$6pXx6sLJrHMg5m6=WS&a$g9`VFiR(T65r*}$Kg?pPNM2S)df+8(LL#VR zjL5q%4Y5I3lDb!vln&vTr=UFjUsX$CW0vBjbt{;nR@r)+yo%2Xs|9Z2-gWdca!pkq zX*~sjgeK~s`#emt{ag*6j+PJ`pO z9^0jFRYG@^)n=l-O^mnT?t*C$+#I-)VJh8yZZt_9r}5ERs7=-O<{^|jFn*XZ<_>wv z6AjwXiGZaeb;3;IrlJC+q|TyBb)c1TngC3>`BQPaEq@=bjov-Y|NCEn+b&xL)E7AI>lrUi-+Hf238!P^ zEC*`0&8)4+E#>>a9+fWP^t?W;hj&ywU+n01{|k&jbHA*wg%A1>cAhL_2^A~yO7SkX zl-wvou?m#ITl>eJyZNt0uH#P=j@^duDkk75}r@BjNIdp0`5R<{atv z0J4(Z%z2p`Gk7JK7s42^7fW@-EZUjMkg1P_N|v(g8Y8h!@?trj3uDAS{Awd+7UL6^ z4m+!7P~TDNGDL&7h04G9%$dZC2l*+z46SS3nvEU*q=DjpyAdDYK?QTshciYn%v=4s zB+bF!QMLhV@qR#-fdPw8*_W{zg1w6^4Xj+4Lq$6XLaGuw{Fiq30~#boBh|ehOjaId zs(LPFaL7KS=0Z#x4TvSTn`g<{r* zjzghCL-q}3QJX?yZl}6z7|4d6)N-dpR*r`#8f<5GJm*rFvW|D6=oG9receU`{nn_%;SLVb>5|Yv4pNchJ8vTL-bW8$tP6-hV_%wPr`0G)AR>+->BmlZs z=GaIMU1ZuZ-Wkle@_cg!3%q%Nby*nA3~xq*yS#M`3}j6vJ(ib_;#HHRM_mR`o{g+x zVrmq`ih(3WGwl#Vy75gtfL>KOK9XhUNVd^AgzBDT31-z(2SMv9)b}A%X8&{sDZF}| zZCT_@#Sap0vM-gBG5qB`AtB_BXXi!Uh~Vv^{JY9St#Jf{TGG?OtEcJHfz@?66G0v< zKEWqRymkiQh5bZWsS&_?k3cNbex_Y0+nSV?>$X9B7s1*jPEG~|1k?Mmr2!wE;OpDm zoJuSpKlKI;SV!X&4qn>j~e3WgGd>Tbq4|N#St4YR4Hb(O1c|IM+>%kzf8+fDv zk9+XOg%bB~H;?1kH9ow=52I=3!@tfT!(aEa^EO}HBq4+6PJl$Os>F=p>l6IHGi(}5 zd+!o;=+LG#%jV6iU?OK65!d+JNt!ohPgkyGGP1sURPEzXy41o`2El6$Ih|SZ^!Dbh zVBS83p&A#vfI|DG#Ps9abG&<*??*E`00dqEBn{*H2wpwI(|vfSHYkkm%-W{>;~1Ac z*w9eT@cBnsS)F%|^KCLIGpKI@iFUR5ycKVrz4u19vB=;s7(fu^aCK!FRKus!x5T6% zdvP|M4<}#(o8bRy&~-WCdF+fKy*a@qfS44XjR1*phq=@QBKe{&4Zr3_9^B;h>O9+& zpNrcVBbYn#R1IR$KG~u9pH-%{E(@t ze@W)`2-3U5QIMF@o}EWQV%%zCQ@|7HHXnyl*Mn2p#96WAaODnPJj%K-)=_M7+f3wW<0g2{wq~-?f2$j)rM<$Chv|xg3-N5yTH;YkePFh6D`5c zKf1GM59@D$pwTAM2JrfF913{w+;Q%fOl$mj1M9Lu;c6!u`LZSrAUv5A16Q-jvvNT@ zUG>^V4rc+ZOJjC5j=DR?peP6n&xL~oGBs9m^A1K2UJmDSQ#imeBYi#CEzwir!z`Mc zIBcVtAI~I}SVLiC+zF8Q`6q0Tz#cyAz%!fK5(|QEW_I@CvvuTUQFR5ecQIL*d6msI z`0GWcH{;E%987>XnlxrI7|gt11>-^-Kn$xIGQB!4C4$5&+c_ICc_-ptDFtr*E zL3$S7#Q}IgcCpo9V?WZ;wVDbJD+~@&)lIlY_OaUwd5?wtr(OQ=Xa$aG2mi?-8ru0d zUAbUz@141>eKaz1@YA@|2Xb9fWn3eoKVt(~<=|-_d@q8LUd>qEobY5a9Rz_4C_ev$I=cKl ziOB&wQ#$ZQ9hc$SH;|*67CRTOn$n@3RPM^KE&#HOY|$+2T(U)JTSy0-t|hRP>QDMv z8>r`Undno(HGm*8)MLyjyxp6Tft*dpU_r41ydTM58*nU+tT;Zn#?tEaizhgX$h;Cy zYzl3Z+jBt%nc7C)?9VF#z+@yq0f8d%&7-t3aw!`xU*y{=#r!jkVtzD+$-bD(AhA6Gj0}|9@Q(;%t}-cZ-pRz0%ouvCaX(9E0_x? zk@gZaoPq?^myoSpUxtCkwP;@fJEY!a#SQLAyjg|Ww+hRx6+(kt(rtJK2Amt0mrmgW#G33f5&5{@u@$3hwTO zd#svDTIpJsggYg6=llx{uFmkLd~*!IXaI$583Y~MQ{IUM)vra%7oP53b7UrQh`I$cZfVM9>BL4O~Ugp|Sbvbj23#6OqYX6PLd;32cJx87jY~}T)n_xAC?T}dlNuj9{=9SKd*ye$O+C)j2cJ53i zPSDUu`{n8oDHtb4S*^Y`mOXwvry#|FiL?yDZP+FfC3EoaV)H*}zC9>L+Jf1u+zS~b~eJ(#v{SBO{gP2adVA(mS zjAY_RGDiHDPIn8m!-GdH!XjrNGIA>uALT$Vx`pwr#CV1LYqqvp z8EGN>Zi#{_%us8N!N`*6t z>y*O#=u~p5bDpKJklmImw6kH(bUUjn!B+-@RzstDceGj`=Nx3MVg;2fPCj<9{Bcq* z^IW*oD?%f<7h$5~#Jw&eC8PG+tR<5)o^AoPSAJMlQf^5M1^wbY5)}2DiJ_3h{Ki0< zr7-M>Yah8ajf%6|DPeRu6Tu6HtK!rD2g&n|b#d`OY&1R~ow2wH0Qk1f_7hoikKiFJo}HHdeS^Ct%gewQKi16j02CmMvN{ zg_9V|Y~7Up7efg=W@E|kI=^E4r8RO(>UB&1buP|OY7Rzs`4q2=^Y_7guhQK%xp+bU zJAsl-?!@BUe3Lc-iV56ea5D;Q4jjeV?In#Ie^oOP4?1ozHRF8MNs;egWezCws>E4?Ewt;j%O_P3g5r29?>DJ9dF{U3rflCkXK$8A<$Ewl2va~TilxOPV zp|I;J&z~;4Ub2?mJz;b8l>iR@)sM%63d3$lAW6KlnWdQzRLVu1j`xH7n@=^j;;2wM zrSgrL4}ep2csy%D}8(OW*x1z z4(7CBO%&c9)b%Nv@{t~V(BQs^QPq73GU;Pd$N!GHk@#{P{;|~D#D-fONnp}i-iqRp z5cMq9Gws;YpGBcq?CO)RdQ#2E3mw_sm&qYuW5y$lw(!MZX8WnT*Kc=bb6=jyCz~of z(~hA*jBUk^{`|E8IC!KZub1N=y?L{e%X0U|9Zn>1CXr-8N(LtqIg`esUWMV}4M7~} zjoF8NJ@E2oO@G$)pq5lUx4QjHnAB#dkP`3$7>+)E0 zzG?!V?CpukgEjs5wlhXM^=hzX0Pi&`%13{-H`6NWgHy-Du5M%lGrZ{==5!v!#4Eda zFA5-R3L{Lsf0lCwa;Ia=|ISzAr;%Kb;)OH3KbT1s*bs>)EIh`>EDUDsGe}M3gGi?J zVRaKwXkL*e1Mo}c+2f4v&Vm}8zK9Gf&#*M@9?Mj_orbk|K2V+i|JRYcWUMB7)Mra4 z-a5*Ucep-T4YT*u05;TT@j13;kUWEiCIGYS(riWH?aKhK9V0`bZ+k9u<@*b)jN{Zq z9`zw2hIUPOIsoA07!IA_!Zl*^*msqWVnCv2Esoz(mrE5Z@LG8mMAE1!M_Y0;il`h8 zUgv`wAk(uR>)Z2>qr?PocRVlp@WN3Z>%fby%EfHZms2_(dUc~Q!mk%+giBPdL3amT z_p$Fb3y+XwW}=V!){-#R-zMTVYvSlqmBds8oJ-`Eov8!39nSla?297wJ4SWI7f?8O znMF6bki=`}7|@WkbaLQg64&zX<+%_HILN>HAp>@vsKh&0)xSKqle1~8JVUC9iQdRY zKCemT4eYqdsuL_rU{-CAd2tI%lUy=9nFwD1Ht8^_5EH+vR0E}(R! ziiwyY>g2K~9m)e-w5!KPPeD&V{*!@#tCQ65rscf37++f4@qEP^DD&-5toe5=SrBO; zNKa*SG{-yP@r4!@%SmHT3#R@p)gH{%sPH*CU~qGS^o9a5ibD%kERpU|!;Kb7+n|q3 z9S^;_0lR}#iB~K0v=cMCN<|vjxa+{nNiS415T%rEg#g6c*t(O)qn)1KYsac(HHLVh zNZ9XkGQ)kEk283;3gIny=U}0UW>&+FQw~m8RV@>;q-bpB(km^X>o;7?(_Ya+Tz^!X zgBiS6lX*8>-UzIY*KHD=4<8r#;Z7{~_f&_DhuU|O&&-}Zh({|RDc~T;m%~HpSApa4 z7|T=Nphn^A1piJbP1kqonr~KtIW1joU=ndH(HzUay|*w#-=<@&g9#JOgP1+dWh*9 zy+ivz=4=89+36KY!XSfSO*-o*bLb?UPq@)C2H9zaAwfDZ1}fa(npK04((u$laZ2>P8QsHf^KW+ypbCtnA(O^Gqn`z zt)O-_J`X`!0tQ;1;MyoG-?1r`Mg8c1p4&B9wnpWuNm3ydUahCZ))bcZqHhhF9&-7M zGig5mw?S4NQX3``v5VPJ`uNoGP@!ZJLjmtoc4cNeTtididOWY-NLv9jTXyA}${J-{ zav}=nFLRuU!o^V#Wn5c&oSDMQ>)Dp?D+xr5Kw6+Ba6T^Ra3Ts9Cvz9H%kGrM;lxUp zooa{^FT9|!&JmZLQz{xcSU9!UnS$(a&Bvg%Q6jVnBU5=P{=aG{>0#}3l-ar|G$-6m zd&%7!ZmHqUub0BcrUcR|rIlhd(7iP+?CeT+wS(Le$BQ?_?5`QS(eb~dZvMo$J{?;EKHs`tS@_VLR53Aey{>C?=<4Rr zVYF9YR7}OBA}xA|E|Jj>`RUNr&7XHF>hn{Fj)y_rD7@O8yjb47_S?+r(k~wrJl>o! z-i$t6cn)YxZ=OhCLKb1IaR`;nlAsQ$l_#bb-m6PIVpGnWMt&~ODg@B%z4`Z+D8b^nY-(TH0 z7}}JPAzX>)^>Fo>)lRQQJXwWPH+lDxx;;Ft4ZX_|pTWz=$dy20Y8%pS(Xc+sE#8e{ zaAQVQAuoqdjuT;3_n7Clqe}qCZ}9#Fyvy-J7i3Sq?aBCkMWc5^X@`LAIUL9Zfk!PA zBgbwRZVX8fmBfLPqO~{}(10Bg98Ceifc->=GVZE=vR8+W-xhApuD&spPinB?8iBP) z8myi`85zps7FI?l2~(%_;&akKydLIb4~+@U_NTh+*qFbk?3UbfN1{Of~H;^ z%0yAP63zdGgJ6CwPM>7cH88UEI(O}K=|Ky_jJ8vOoP;(Eb?_jlYED=EZv{(gy z(Poo?4t01+3ji$1e0PC#rBL0hJ<6a_h*_ivL>d(i-&e>{9XfP8$iY~58IkNwW7QyftVNbI=d;3bE4QEIbOK(!gg6+U zOm;jUHsJ1)97-g#65pQynOk?L97N3xT#`JB5n7we-z&v0Bkn?zJ>F)!nKb} zEM#p>CYRdimv?aUF_N2e16p}9W)%*hFQ#5?WMtNsFm0t9nG`b}LS_ zX+;ajtvIDD$Oo0^tUh!U=q)YAu*0qDbA?08N-m~L9L4-T#bd}6hvGze*Dsg(_0SpN zI?8I@sEVM7%eDy7nPRiFfI@93H6KcdF?>H%3PV}`bU)inx|Y$QbtdXO{*?=tN)n`sd2nzO#%{S5f6wmsLbl63j zL!IrO-u$CIUv}mZe-Jcn#`_^mYRliNy6OeNn&Dgwr^R-@z0Ue;gf8a1;1OT7%;(y& zv^#%k;6wp;Fsu<@cjNum1d5`$)vv;5?Lg2g1fx*H^*+~{#oc(Kin>Q$D}*mwm)(Za zp+mra1^aEHv@cJ5+~`KQG+GnR;g(HT!UA3a|pH1kG4Tsk-H z?lKkt11oSTMpFuTL_$x0qD&|@tQx2Mkd;3EyqXAtbE7$Mh9B>^91$L01xp@RCgiX1 z0P0&fsxvHg==g6^Hv%LodXbn79^Age8;5w~8sah7Pd0q=0}GsK)|SGbo$4|-7zc!1 z<&~>oVoCr@vkG&rR~1JRX?Faa7D|3#7dVtcP8JYoz%EpS=(9t7+MS^n_%W+6L5hui zVGOwHRBaEP@uWk?f0yq@LN<^vfw4gvrAW}P2HXW$AItbqFoBthAq=ak&U8;e@ZC{5 zZludbUWtSpCSByKQPj4m`Bd=d(jc09vHS{^8{;ED!K)%wVQDHUSzxA(NiDIz2cPFh zAGfg}f)4xnVHg%CAMiFCs6GGyAOJ~3K~#s~^zVkj3}&PNo@xvNgG_)4o!PBJ$A8UY zO0na;p17fWXCyk4nm$++daeQw-q_6(6UnL0iCnt))8`w2Eg38t!PE#k9CD#htq7y0 zCy`HJkpOHqo>|Y2X^_nPhNMklcM5%~Fh7h$1LV@=0B5FhForhONV?9dB&ehsEJx4t za!n#1rOr+@`^Z!5XoP(_dz0uMEj=v+!$%49uQ84jz1|%V1zqwMawR3VAWYt zg!V1DJ22>+PwAOBCziB-!s$w_{NHl1Cpe`qpsMTmL!dLlb(Gb*DV)IWwNtVAER{UN zrIJI?8SW#o#{+4E zdJx8%$Nb~$NCSxub$GKOLc0SrDvb}0amfzwY*z-l5(q>t{dN%;$m-56P8r`^I_`2G z;6*mFwI3t4k*TN|N)mP(CzJT*JeTsyc(O)-iM4(3PowW)cke3rm*>;g1RGf!&esKD z!mada!qat$Nnq}=lJ~i+3~0(zb%>7Vnd9oksqQnxP0>CfS!A?m<=@qfeKRm4TPr(kqCSXIU0|FA)i9R^hY84BX|KQm|nNo=#MIlR~e} zcm?o%SC_+_etC4*sr%z~JUDgJzABl=_&5~_{C(ImnzwfG+I1@U(AJ9)NAZx5BLkBK_v zxHy@$XBc&)Y}VM{htndC8CTs;ycTsh(}$_MNtanZh_*X;DjEdu4q?2B+2b~ts5n@&_wbSHXdRACFT#N)fS$KEma~G!Uto{aTCG4e+aMbRX-kpBoHztBYmnc zVh=*wrj+gaaY`KzRNVkk32cc|ccX9l5Eja7mjSZ#*nLBr^HEfVbgV2 zbszyKf*+$?$EXC>Vnr5Om+;JH4xML)C2GxwzX^IksDUf;1 z8DEXCSTMTJ5E3mXcN5l!{=F8KYr`z%MHsS?WZgU_FqnQ?~IhTUL#EtT7 ztIg|I2=S(0J8H#oMPd6$UR%%m$;b{`tl?ZT1{2qV*jt;wTm=updeL$bKK_Mkx|O?G znSat!;DBB=siu7-9Cm)Zp{{U;*DCzhWM{A~Szk}-c%bTL_T$XfexHw_z2<85_U5JL z$P)g(v^3!V1sU4N+i{Tor`PjD3`j?;3p&q@}b;PF!J6x#0H1vY)jJBjgAMZ zZWgR(ZoxK(N&Nri|{QJ&{IEV_jBg zyOQ`)s_9@Sq957=Y+p?Ve4o=RXGzaHS(fXuQH7r!~C*v;Z z9^~cFZ!O9+d=GIZ9s;#wHX@*rCy9bUlhz^u5~ps1PvK71MX2k^HG`WB2le4aFQf%v zq-H~+S^!k_Bl9kIJh0_3Xbs8?0uBI$u|O>{*{-Y07l-rc9Sn;=rejwQ_<}@C2KGGF z#g>(cSpYmcj8U1$Uw}+#CyoR`WuC3fSqqVEkPToWVho{c$&p;#U-Ndj`fg+ZMWNqT z-FKtow^TP46PQc;h&gPuI7avrSiZ(8G~FUxuSu6mEVK7=H}2jdi>bm44LshC86E^2 zBFjMV5;se&18IzI!nQL2wS%diM_78{-#?4w@9pu3AXfqtPu1d!NZx#$n&;?#5}sqV5vw`*m4JJ6#r-on?YjROyajNB^-MPT6uCh7mrFbgpH}Z_oSN) z8+mc`x@wUAxs#=)+sF^%;B#pjSK6+7u=*NrWyYwWQpN?L*~%K%Eo!YRk=Lcvz@l!k$N~ z<)j-+co)WRCt)nf4Y?@j>_^9?E{%zgV0j~Qrn4)au2tD`f-j8B{gL!hh)|O3l#`ge zN}cnMpXKNz;<5{8Y}^+@XX7zdq^0- z#%KoBBy>9``?I7eQx7w4B4Q?SHYy0}EdzLN4=ID#e1rZq=(3%|{aN0ENfD}5;%zE4 z{azZui?IY8EVa}1DWc=Sp%^1vlswQxvF8O(LFrWlNB#TDp_Jusqad~Dp1mMN-nXaE|W^=+|mbwJNfI3a2;i|Zb}(gQpryq$j4Fo zbzfDf>={bGD63zSO!}qoN@bCJDGk48hPrK|<2Qru_tT+6hpujP=+Nj z;jS_Qa-D8mFUZrV9_ItdKMX0k3M9W)W_OxAzXIlB1r<-9pYuIMWYtP9$jS~5%^6(0 z=Ea36xo$x!#rjKVj1!~I%+&EaS~trcN6bac<>$Vx90dm#o~ z89DgRXv93~mcm+a(4#Tdx$JMR?W`*_u1&%$#9YK2*0xsXt(b?Hi!v8wE{TJ|0SfhM za9d0HLtAwce%J>w7cmdV44w*6Cz8dN%hM5a-2@$O-VpH&&-kgOcWpuXY{Wd$C(KGoGTSrSw}NK>|mhL*GLPIKIRC_U5m63X(8*a z2!Uc}KzFCOE;0iG$a9@^MbN4fi>mWwJobV_-kk5l>@`TA;qe_KLaAm1FR&vmK>iH* zGb(Nc19)<|KhLd0`V7-b9&1A#6ZP8iTnIj2AT6NtNj`rBZ1@C{JC>Kju-V;67NpORmeRHvJ^k^l#+S`$vKVOr zBhPbe1UN8Si0Q|aHAtT!EunrR`UHZFu<6{oKpfgBNbZQF4Gz9K&x~e#wNYIky}qBw-VnvRPx3+(hW&;1yaCKc?SBP8o}IfM zG&OS02GFrR$Is9<6d=HtQB|~%Qu*K4JeEfhca;W-{Cx-or{@hey8Xz(bTE;Z1yEk* zmIvf%3R6~1eS?Fp8~7;=OxUxr3(6Zf9YLiCvLrBZBo^8u32fQ;euig-V%slv7LH`W z9vb#lThX;17p`$77Zmm$Wv>h}Gj|Y`3}$e!FNRKjAhY%WAEyx3#zmx49%YFc>H8A< zK#~d1rFS6TrvlV(NNyC?IshJKCf3H`BqG_);;UrD5fskIj)e;@Nul#b4kdyK@<_|2 zf{CFGh>zro4b1F}z}TL8aK%ccl_X?=39`A9ho2D)j9Eo|CQtV+tof|o965s307e$< z(gw19SZv++z-*#pMHh|i>0rqfQq#fU(oI6)P`v8WvXrNW2S24#JBLaYzyVqXx_fgamxL^2 zGvjK}p*Bgk*^&%0@wr8J(1-f7yMS7fOFC3BlVH_njgAMRZY1n>W*l^r$^%lgMTcEc z$7O6PvE2J~#<62mn}*L(GA(p86PBXB5tGQ|L^pG<6km0ns$3mJw3xHOR~y zK+NM9)}a6bqX*$*`St+oGfOya3*(C5sftKZyZ}H(7E=$DWd$s# zP>#eAj9NvUow&m!&g84MEK6W!8?wNnwaZ{;L@jFgaXqHQx_QGbn~U$>sJm};Jix`2 zB-1p|<+CX(oJ%4Rs+&2K3*ccyDbpI>!9gpJ`64>?eTxu+UK6$xL+)B~~Wcz}y3lZo|xT-1%9LY0;5Oru8) z{&NuowW@L_v(P(pKlFm32Z?J>QV4^>3O8tLhp@Q=xz3BJZ0c=v$A}O#ug}k+n7+WS z?RJ;O zdGy(!Rl>@Kr`WlXg?BM|QN1nG%d1vCobR<$fQ6<#)3qU zg=_~h_*n>&$jW2)Ap$4S*Pj!4L=NQr?d0lA8Y1D?q14 zJQ>4#F@?#j4wr2dAlISJkR^AB*{_-#xut&cHw>qf7eXK^lH8n#s|>vk4)#teO!My_ zdF=vK)7dzP=H7gN4$mWCpk_sIu;jvjcE#dbG>QQODCCy1=`47!57R572n3`~ zBq4^$#6K?nTl#gY4@%%e zi~C4PsVsI%uKYaXzstih$xFRLE6{D)p;eQU z;axzLF6qK!yT;6Mrc)O%yo)f%bDh}UCBXq!Cjxg76wtw?2gGbH&KJ)ub~8LqA`&In zzX-3rfVZ9h+@n}CZAHHqk{MCFh~jj4lRM$$7JFh=j|&t{Y*6VDIyGF!Z=i1M+@6Eu zG*yok&Z6?=NgB>KKk`H(2(WN?EFF9SJ`Cgeiy&k2=GYKg`T;CH%=B|b{jasFvZga_ z0@Me4uF`i0iU}l+&!a6=Tuf2{^UxFVBxi5Xa(l^s1P7l#%2QPsu!QY)H}m;FLl|9! zyLNnyTuI`QAGr0ajY9DZ4Hk3R0SeukvcEIURuGZrrt}g0S!+Vt;yyAu9*CKR50WyN zyNA_@;E9+?z(UfUuFLSMO;$fwMVf?R4a2&zz>g4T5y^;oE-9CuVCr$#ItWtc667k? zm)7uJDv8ff!L_D$FXOkHBUAYPC*HfE`*d_XKy@Q{XE+g=)N;KoVdo(B=8~svpllpV z#9=x{fH$dA*m#Tm8LWDYvu9{^8dEvK`(Zqb9k8mFj#n_(2Jy-s+Fk?&lRsbe!!{nn zYLLhg9M0vba{Mzv-4+?$f=nBErN-nuJ&VJ{pikU%q1OdyjTg;Wp`(1V2Oytp3>*cC0HLjLtMnu!$h1-Bg_@Tow; zXd1)pZP+D8((c5K4QdNS+FaUH+XcO&o* z;s06qN37Gg(7~i`q?~7uO-*AkFvP<1SHTQcR>m=_4g@mXhbgB(!j?wE|6rGqOo+Ku zHG#sqp6oitTUWpY7Hqjp-hjud!Z|$u0RQNXEL00?RwLG2!~h7|*JNy6mw#1EU|`TU zymQ&9C4zG05Oa}~|Igle$46DA|NnjO)bx;$5E24`KsM&V5dqdp`3# z&pFR|0AhXkIUZD<2qvu{auq1Fs$5iBh{~%2xY7|EVCS>P+0+^|!b16FENK%ElX*U> zaBWx-RH?+l4z&7$!#2=(aVQr$IMY#Sh^e&pb6HB(=vs&LDP&C~e>|hg7WUfL1ST-E z>bl!cK(pGUPDD&)Sxe{FW!8y%ZK)ov8xdr^HJT zE1Qi%jliBjf;aWN`85|MjCNVPok@KkfF_k_>28mljptfE@p(=~z=^bUI{tuAKw-!x zZgpW>MLs#l!CRb40~2U8uS8>avORp6SC-R%62p&hAeb=<$`0`6L_hw#gn5bJgBZ=% zpK;j%5E9DvZgl;MT{-%=&DqMEyCE8o3T;dQbtCBQvV&&lRg#?Aqt&0&edzfW8?)pLl6Vlh z5j@kAl^eNWC(K2)`LR2Lm$^A3RfF3kPq5)-BFKyqO4fElH{cyc)*x2RA|5u!>l4yT zCCjGIna7*+Wkdb;8lQ4X)y2McomZpibDWnNGvhF3Fa6#bTbbdB9E)GEJJ@tx|0wYy z%4fXQl4lyzC>TQyZI-hmgZH<18V?h7mm|7x!OSCHgOTdx3Cw0Q)D8tWD0tkTcT&iM zon5$)$Ji>Y|5dj&ZY6Wt%mhDXW$|W5rmx4QxY>OTzNJGY#{1%JMs*IK22<-|2UWqS z;cG4&){(oxqT6xds_xPXt-#zGRGsU73aY}wA)Ma93r@$125lmU)-W1*tUg_{u^t64 zfN{HBzDfsMNASaTzD+D7DFMx5C~q$mel>xle4U$)4`%XGR%goTBk>?~BM1!UgD|RW zqq0BYX3Q4Cz3JH$?E*Ul75ylq65vCGm76vI)w%Jsx;NL;Ny&#SKDiDSvXj^hFNZSe zR$&dPc~tg=R8aY9H(zZB1G#a9`P+b*8~Jz?hQo}CV!#F}H_)$_^TXeLBV2q2S&lpH zz7=5O#cjN(K|WKvvb_(==Y$30=PvDPIyo97uwA2e0$Z{`#or7TmUq@?qCJT)i|$K_ z`GPY>vPSV@B5z&OolS#xvZo8PmhrSdVMUJD@Fr^nn~(9I3uqQMgSPJ)Qk_jbJB5@K zKFk1TFt!`FDxB!a(50MncdJEL#*)hs#npk%pcv8xn&8-JltYCSlOzh))J8o@s|<`s z-Mq*u%-zhp86L*--yO*YfAvoLo+TvisNGboz@;3v_XaSVDI+)<#Qc21L)ae);Ah3q zmguv@?#2dTDi`gb(bb=2=SWBZ9|Ba;0EKYa=z40pfrSZt6wCC>h0YWV#a3*x`89_D zu|!0@x4d*gp#U0Mk&LzXI zGInM&umhE@@=Y+a>+s}pu4h9Y^}hxq2rNeO9H2PUrsq*@E!TRocL6`;g2J&gSX&Sj zigJTQ_hqs^waB|lk8Pk576K(`YR7V@9$K7f^g-A%n%z5Ca?9OZQaFE!=%28SrQLb9 zW`lwWrfue|qtKKqK1%*!%#WtRyt`i8R`~N;7OPzA%XhO&P3tZpaR<6lIDD9>!}_}x z?f5c-DhEL2Pr7G?S4R@Qf$_IMFyb;7`cP&iVO8iJMBF*B^PdEEbfxiTn#NE)pSM!L z$g8oudw@*AyFV~!ENMe&wVI1I%9mk9Ptr3ut+_n$DihAIw>i^RyG$yTDNC5*X#)6~ z$W&3m%Y?5&t_`D=m+SDi0|2p=NrzV%*oB#>1O$YY;VuOD4o< z=AU6#Jg2=`)_`FruvkeMMy<~|;ld;Fm+7^ijgJxd8EFdkJU+pB%s^J==;qb!_8&XW$N(}Y z@XLAX%;S~bTpxvbG5LavqX1NmotFriOQKeE8W%`-rxFeeiDL_|8x$gDAcP)>pLC5E z6G`ljWzC&WF*k)^fv*O*U0i*XK0C3&KL+p*+$!>(iB_P~DSWz(9^+UYOOJ!nq>{K> zlo}CUO5W&uN}hcmxwLU{4U~R}mncp1FRi*ecKL4dd3(ye{mNi^9H;5gQd5;HcWQYl z3C>F?e8=4CcO&*LlfD;w5@bZU#QkeGcNI*0e`W6Jt_P2ezQ6eCd&=jnfS_U+%RAA? z8{^SC$-Jk2-F@)-1BSWZ@uLUK<1QiTM&e=NW-^cez}0jdawst4yqu6r;slzNh-goK2|{n3rWp=pSz_}n%J^4T?wC(FpOl8}&ixO4;Aur-zK zv4zVM*|+0>^S~hoO+rHAA<+%+_6lk=q`9~If~cLfQ`uBc4w{67#QngttJq7W)qW24 z!t^zT8)ywYw+d3^ph-wbJUs0N_+>x)EW8xua!KK6JV)gwE(r;Vhf6mYX!bp?bR|Lt z#Yjj<{CDXFNaxLKtZYusZG%eObwV`>2?>dNpc{pkRuE91o(1^;H2T)3Z;%``2?>dZ zL^rByG>m~>dz}Ak42@-2h#WKt35olGhr>gg&C*qyg1;w@pd8Vu=ab#EOOS&mAtCWl z=%$qDXTjl%Y|oaVz!DM?4~1?@fkH}- z&h|c_aECKJxod86J2*;CYM$$2R~Gc{0aZNBnWEF^;+glDSiK-wWs#)mw@aGj?}fx4 zR=ctD?Qp(n{80DiIQVlLGULdbf|$mo!NitKH)db{98+rTM!p$}8>e?s_opLy@-~O9lsCo=qz~BQ;HAjQ| z5(M6slV56xxuA0s-i;u97M7VPGkEzr`^P$kXif=sU10U{46ab}40JHBC($V=(@|!U z8p+mXU?6!g8@8d$K$%bPraT&0l(4d4>OzzmDATFAhM3x%>8xi2)-|tum+>ibQ4}Sw z$C@$B2W2|S3^w|3wG#+F>`%~Dl<6q*7~F;-0pQ@p{tPy90B2HmKx6Mv^3I}6N0~)P z4W`$W8!sh(zjPxoc(Z&cIg=1^yj&F=jPF490Nvsk*OBCbU_eZvLkuTJW1GUN)|dp? zSu~7AjldT%h3<_JQ&1hn1Zp67r86Q9+Z0aqCR{;P=~{s>velYN#S|O&O#c{eXQ6|bobNCS&R^ig%60{G6PY*C~4_H8D&I!UoKrmoEf4u}| z$mM!A5ndi{^(si1Z6P6r_6rD$rnNt4)T_w3apcF5GMq>J^#Sw_VDBiz6w-&$+^6X2 z@dqx_bv;AxT%JQD z@jLe2DC{4>p7nU00V6jiax{rKKhb?G?^fmY4CY3oegam2FUwPY0XR54iO0{f;5u10 zaOeul6a{4lSU6Zr;K@k-;e+xas65)7j~g-cD9_h-n_9ja8?W%`G2R`>g}yxXD<{%8 zlLlrGsDVt5LirdRJlBhrO{lk(p=FuoPpcnG@b9SXznuizz~39PU?~XJIJ4X;zEt;S zd-9zREkBV>?=oz6aHt#2=d(AH=xUtphcXY$Tp!Bo%V-u)SPiZZ$7dGVF87|f!5Qbf znXOs06-@X;vP~~=ER$D5L2xdy*w2B&mdm$IM@ClW&x_?+p~UZ$ZUh!94F!)SQ!xkx z>yzkLp5-a@TY>0L4I9rcM>z8_4&J5vZda!4sr$c#$MYB1D zAAjaY6%;zGF4j5&Bx9MyUt9A|Yoh$|QW*FhOOw!2sK1OR6{zGxzDDgb09F-)a;HRV z0#v>kNb+&sN-WG_;^RZwaHcHfY`#lqSP3)vrXbwRpl0M=;=GZHL1ZS9Y@xe_9bWj` zdG8jOxp5BV1eje6MuW2r3V-WLY&uaF_57B3POeR~;bpo*7ZejeKgRl9e4Q@oM&fs? z-587jn|eFl9fG4K5Rl5-H+jmJUbhP8bG&ng+{mZ5wWt#zNt7rs`2uCX<%dpu>W{A= zW+7+nlykRY6j7M5=0L zAm%Hw1PBZ&4gm`FYw~9^latunnr6-!7-Qs|1E8jrLs_0@h)02{fz%XQegh6V#j<@M zkt;YqR8Iw206z`mJO;&*dY*OZ`hxM#r=bloMy7RT*B0VV0gS2Y$y@4CJyAF@hHuvM z%B4cC@eLqx0F~!(QPazRvXM_VIB!>q$}|U4$;zr^s-=@>r@}fgIJ>6d?Te~nC{Snw z<$bx8McJ7y<1JV@67#Rr_{G@<2e&k$yt$eI8m)uaR*FGqhF7DQou;>Am+q-4uJ3=FqBDc`L!bm zFc4rNKL=YjKA+=1zwo6j#9<(;3~T$-%ohbz11~*7zKw%+_GC~e0>CSXN#!y4>-I>9 zRp*6XP54J8cZEyiqaGaG$19gn73Y2zl?y}Zxrj@`?V`TH$En9D3M!~79qW=ih__a8 z!N!k!5S1Al22dd!`#3Civa>j4U`s<(XxfPQL8zKjnh`YmHm1f+y8fzHrvfTZo@aYE ztPmW@pDXd+&!F6nTGMM+0F9r9@b5J&NpWedT$z&iouF9KUI8jEwc~{tta&`PifOFt-YqY+>jrm%B9LCsN+|ZtYp(c5orjnZee= z^6vBvWXd!}9|eG+~y7mr_{_WIw3nj@3;O58KuP;yFa*UZoc#1mAS!)48-7!Kp{O#&P)l3 z{|&l<9XI5Ut%QWcgVRkxFqF}K%UnSKl({tP-7S3icHDDGfy)JPRR(a~)mE@C*-%2@ z_3h|wij~PNChB&3G*5w4YN>s>7oP=r`Znvkf(_I=?M0N3_+Nx48gS62I$|nIsuc!9 zh6Z!$Np1};Ef~5=G-4W){PamUrL`XSyrDg+C^|)>%X9Wg#57Vy(B4*kOL3heeT z$0GqCzz;DEYyREc=HU6hEUY3QJPE1Y0D?Ac`K%19a>;Sd#*ioyI`Za8Mg*7qD=paB znk$e82x?d6!^$Whfyx&nSQ5>kb51TW0&MTai{CLno|?5eJ`m+I6eBl!GWcu0y-B+k zENV*ipIqc?w5ZFbRt#IgSC;^4MYFpHUimzG0U#6Xq10D7ISkOG z1-r{(TnYx~7CyC@>S1(7avNM~cepfO1v|qV<9~?FNw-_))c#DR8kj17ilE*KFo5kL zsaFybzhCX<`X#EZAlW4{K*_{9hiw@y^GGmbA{lL*3W$UE`trpV4mtF2_!Z0%@ou|oQ0W-b^rwwJMLKGs-{on`(NpU<; zlV3-YH-&wj@z(U)-+dG@1rf)FwiuytJ3g+!YhC%dr5@nkwiX$a5mR`lItVJ2rEU4b zSG)35vVy?B93jcvR0s@2OhMJ;6DaXV)@~HeUM3k|$fzTd$)0Sc|la3ZB}3;$*ZLqo9C=FB-3_GCmPmv7K^Etm2O zcd`TqVs!9o0u*c=)BtibTpP|;r#aLa_JVoM{Ov6boIr5}8;?nyqo$jGg%h+y|l{&^V!Kw+W}ejj5AC3he%o}fn~MtHeN zUidSgT%ub=HeCgk%q#}1N0W|ri9a;m+$9uF#&fb@mTR2sLW4yv!c=_WQhuQwq=7-< z$}O${3f?M-F238#dDO5_*_#@%w4KGsd`3RX#eOJ@3+cey~L5@tQ-f z0&wFR+x-~k%a^%)(VAX!c&kQ17Xw&oldV8)w;h-VTSu95_RVYc!0cf|Wh# zJP`qxF@niZ$jcKCfQ7s)Fc7XV^G9ZSa@_Q&$=6Fk!ER^SCAqFA@rO62?hS%>2l3rz z&TDv?F)DbQP#^(nSPLsLfX&5lNU{;(vV>H}oA@l^^T;~SEx^LUO=Jhs)LO_6skvYw zz*%XNPf=!|EC6HSoV6NwV;3*A!^@BQdHkZ?4~-@`c`(&RhzT@W)+TireM7JdP&{w< z&2W=})kGPy+smqgHzTafOO;QZgw$^CooEXF_V*&9JtGSoEDCK0(r`Op+@wb}-uW3I zFbu^;woACf+8cb{3>>;Ar3*B=Nz!qA8aTJx17gzEC{@sR8zUP&jAn4xat_J3B{dvyUje-8Pg|7^p zzvvwDQqR+okoaS0H_nr##O?o`uOe4kR%c`=C`2#9Iv49)te>z^W5Qy_o#6AGv}s5L zVBm6hUR#MBYE>exA_x*rvcbZF2H;>+3sN%p1+JV$1Tr}U9K72XLp(>^SC_kfOWWpb zYJsYOM)NA959Rb}a$F{@NatU;tx(Y3O6Po zCNRo}QC$!d`KdmybwNyILrWqf5R=Fr0fPR``DYd9^m3jHV=-U^6mH%mas``4kT;BH zm-9*@K%08Zs0kVvd2|7Jl@XH|AP8Oz3PQuOfFYd_lc;kO%PRNQDI_Ih{ha;Y+F6%SG=57d_7aS!%x9nN z)9`cv#oa_XtDqG-eG2!Bu19bxo-7EVAEQ|`z*=~cT%-VnZsWqLRrgOzlJDH~d|(u@ z3tUJ||IPxC0zz1_T zkSCu335nkV-8eWto~e-!Z@t#Rl_@-3@i(&oY(Y#V$RQsC35owJV@iNSUv|mJcP6NI zxu}Oz7aTofbVfNEon>wp05q4gX;d%}`4O1)i)0#vvy2 zZBr*332Ic}{CGqhnWN}aR-aBHj+T`;HVP5PtCi{7kSpVGJV7UaUG^)FAmR{{S=RwZH&l{sSEw!=D^os|(5n8Y@$IA9mh&Z;i=c#ra?&!|2Cg$|THW@LAKUel(@r`VX zh(k=`?V2b8G@4iC=0rpsw;rdBA87PwMRFGw_ak#6=lc*8!1l+`;+S9mw`4*}Nc>i` z8TqmG1sj&d~a-s*lzF<`HYBJmHTr9Zcj-gfxU;^#FX&qbvoLpPpoygMNo-REtll>s3F~kA$8m%UIEyTgOoL zQYMn*zHB?{R@cT6r0v4A6pUP*$gQO;a7pP~uR610^y7QtCvo%!U&8K=)SbuC9O~5J z$N-etWaQvqi^o0z1GgrS)E#9ZC}d4$<_Y%MBi+p-fY2F@IexoNV~w{JP>rM zP5xC@Wq_IF1TLtI_G4x?z?fga2uWzL{2G`znNE0BfFtKoQ7`Cu%*3iSdReiAICT;sh|nz~kEpuLgWmkIU*_~sgYDzYH4u zU|?)Fl8$rK24;?)B(*(#yh(vuN%{uogMzEu!3Z|a2qL`P<2WTGq%mbQB5-E8R>`*k zL|M6(Q}|PV8rt~lBnT>SPHR*Sfh(@vMnL6-B-&k6 zDz%Vtwq_Aq7Lou=Cd?WKGI%o3S-?m&IFuzHCkctW*KQQ@ZKNr@7YPm;HKLXY6m}d& zE6#-QwIR z_r_}MbFikdzWlUjIL}9dgQ>0P7X%9PcG9*bsskW#6y5#!dIx?nwDAQ8T^r(^&eCl8 zI7vv{i!p^p*g~4ML`>qbEOun#qk;|JFL=BYViJpL5VTOg�g(g?v#UOI7vr!=L$v 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 Z2zeGwvNBcD&i=nQ(h>^d6{1E#{{z}==g|NF literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/stat-code1.png b/doc/sphinx/http-keywords/stat-code1.png new file mode 100644 index 0000000000000000000000000000000000000000..77758ee6c91c639d26a88c713cc7249cb25a02d0 GIT binary patch literal 25336 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 ME215t+MFEoAC=;`CIA2c literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/stat_msg_1.png b/doc/sphinx/http-keywords/stat_msg_1.png new file mode 100644 index 0000000000000000000000000000000000000000..f26a075b657942d1023bc4de500f228686a260e0 GIT binary patch literal 25055 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 Tp|lU(7Xa!i+RBwmHevq@K9vW& literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/uri.png b/doc/sphinx/http-keywords/uri.png new file mode 100644 index 0000000000000000000000000000000000000000..e43b4f792bb255f11127962dc4008a783d12ee8d GIT binary patch literal 23158 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 N4HaGGN+p{Q{{aF};`0Ci literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/uricontent.png b/doc/sphinx/http-keywords/uricontent.png new file mode 100644 index 0000000000000000000000000000000000000000..b9e8aad2740e6dd7632b9ef943e71adef236ed98 GIT binary patch literal 53276 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/uricontent1.png b/doc/sphinx/http-keywords/uricontent1.png new file mode 100644 index 0000000000000000000000000000000000000000..fa0cfac20074ce12a8f240d9f2635a11400160e3 GIT binary patch literal 6263 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 Ueij?Q`!oP3D`>zf<==$-4{=&%t^fc4 literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/urilen.png b/doc/sphinx/http-keywords/urilen.png new file mode 100644 index 0000000000000000000000000000000000000000..1697db1ca8af8b623fe4d0f8fd21982ee5fe807b GIT binary patch literal 26395 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 BvwHvl literal 0 HcmV?d00001 diff --git a/doc/sphinx/http-keywords/user_agent_match.png b/doc/sphinx/http-keywords/user_agent_match.png new file mode 100644 index 0000000000000000000000000000000000000000..d99d85be0b3ec6f9d2d0b762278e5d22575b3ecd GIT binary patch literal 270675 zcmeEP1$-1a7thRkw{Enh4h7m$CQN59i1F>4H9|+i98=(jN145J%OJAiF?E$@Sj6K zL(${=w)XNY|3^#yIdKED9*0MaUcTv%66NA^2yh7ezzA4aqN}@q{rkm@N+~bQ{ef}g zipC+pA@GM05P%K_=01PieNK1t$Ek5CI0QHZI0Qb404Huf2@UsvLx4lz??vDXx|_c@ zGmctGAuy)fyl8GOKuMwht%IRyS*1e7Xtlm!r-hz#*VVfD<=*C^*j# zhrpXAHs`s$0N-h~a-!!utr(6i4uKyJ0Z!cfcy-E^h(q8zMSv4G-)Y5gY;g$ucnEOf z=Etj3u0$LH-zfr|xcN>i<}b1ZXIlsok$l~UhYbnn4!q!FFYpK)_~66%^=D!5sTei{ zQy}%Jia5e_2t@Mm2jaYMm<`i`~RjSN8jjW6p2@wl;L5q{B#0kAx_|LpmAWm%uAhdV8d0T|{rg{9H<#k! zOXYcd)#Xi#>x|!F0pk&&kx&RSsK|k^BIVHs$2Cnw)%$FHGIHOwxdEo@93MGd3>#9CQ=}>sX1)qu1CXnK5RE~Qre}T4$PlH@$lnM+ja zzhE!GsF|x~aq{P%XaL^{O@dO%RdNI$g~qIIV58SJ?jRoG%O1tNlvEu)3*B0sA%_7D zZQFEOInmYI*PfC*BJS{nO#5L~syY`d96-E0Juq7mFu8g6F0>LU3y@jGZtX@+d9ri1 zf{*86JXP%D>v=UsPBMCV>@66K)KQ@+upo()GQ=|}+vMkCW~qlm?`G&GVBZN`92@^Q z0-U({$00894Df`CL*5}%e8 zUz|NhY6m<9R0u+&k$5(%lkw;%GxIZe#Cd;o1UPZ?BiFDxCov;FDk~xKUFe4MXK&Q) z(3T+S7x!*dsoey0FVzBrpB+Cyfj$pJfN4Pe)>V)GG_YL1bvBYus#yqHCYK|TnXy*b zFyPV1*jS2Gc`{OfUY_4op+SEQg*@u?jte=ges6B3gPKMHNhy`4@MBq|i@|;WmXsJf#>Kw*+1)_|;-hS< zUN?^1t5DO20{Qa^R461du@vSdBqE2>+E_GAs#7y^MdfWJs@T)7GNh)vyGMeu8qp&8 zyT?!R{5(xQBu1kAgoj2Z!zo6Q{ozyY_m7JJCvJY+x<#}_wO$RH)S>hfBNE-aaMruu zw)zb`*`6M;W6aZ#vt_%rgTW4>GmdFz*<{n0bQ3}PC1HL~p7w0P$8E;lO+ zp18H0msZpO+e4a1*OyVc`Nf1ULl#egrsi^Y>%Q zQREQd5GWP_PTUj=3m3>Cz#;JWBfyE9zaLYMB8LEnK(PpL;-*+wxIhj84uQWP0Z!cf z{g`qTIRrQaiba4EH^sv8X9H9HeeQ940sbs{T)O`f0-WgiFV!|zRt|v@MSv4GB?>>6 zIfuZ12?0*r{FiE*D=UXUi6X#>n-Ybe%bY{tzk~oMZvIQP&6SlyphOYi#7&99&t=Xb z@LxiJ6F2{*+Wx1?>TI&Zo7)TUPoevR(&a?Y4_dKYu{Z?2KLmapaicfxqxXD&XmcEK z2>hoJC?Sh~VD}4*cT*Y)Z0LdsFoGcA;xudk4*qD3inSS6R51ikK+q~|bN78m@P+#8 zN5D{S@{ynmx9PsiPU~aRv<5Qa@ddhcG^JJ{5~!)EA~V0*hXh|h!_yBPLGpPNT!x}^ zz$?k)X-)GYFmR_N`2v=A;2em2eCG)h8EMoif)v2@b2>`gH;2G~3xSdlH;k+)cy(z1 ziseGFkxcIl8BuA}uJBbo;hq6REAz54jVFVxgdY-Tc$3u@+w|e#}r`+%(HOs^Ox18e; z_%9-$>(k$|>;$1oxxIJ!x~7XmosG2?{}V5cIk{j$_n(%+zyxj0TSuX|oZ}Gq?;=nF;)Wnm`qMa*=1oC{z%T@BcG(Zq0*n(N zjHDke@BEUl?VL2vG|p@(UOYiQx+?9a* zfuiFMiPbAu0A++NIJ4_4giy3e$2Dh+;i4p%U5z{N-t0<^bNG-~x^qPLPqOD?jAb?<&zCKCkLs|6c zi0?n4Y0F+KkK>7;)?t~JAF|k_)f8^!Nrwsd%^~mw1d7+4d?C?adkj-4$GShKzt|lf zkC&nG>i5Zh3)&!MZVt&WQ@1wyM>WTWMJ82=3aXx%kHrarZZ7YesnFyXs)(IK5=FeS zJ=XcS7Va7u+oo(lB2}QouG|y>u{q$oe5sF;5w3Rc!bNlH`Nr_@|+G(&Yj4il`M&9CKe3 z$3UVL@vILlHkYD!oR34`zkxsr=x+Xfz=9eEaMF#giu_O#eK-g$@WX$IZ0OfVFeFkU z30dC$edu!>e?JJQw$I&yP;q+!{y2{%Gt&9ve3obmm?QOUgJsI}`N*px>d_i=v-L3A zxe;AEkM%g)kDw{TQA#p`G1{)9sDBqEmm&9ZXu(p{tsR0n*VyT(b`8`q7$;n_6P-DZ z&K$wvn+~AGGf_+wUh>~}91ZD%va?W`@@VlA)VUqfXwZZisDcmb-vK9Fv=-gIj*cI| z;cI_KTi2k+_hIsej-En82BGv6rr1(oPaEUnt0D(WP$6;p+-x|Zr@QsI8%!Ivitb-F)*C+emd;R`i;ZHLKdRzo5 z6!`yb+{3%5Z+j#Z;=Tj5*@k9$r@ZcoGUp5bUpstasW0W z)P^P~U_nPI)1B!4GApoZ{$P5o%x|{YE-wcUUjA;UQOduWz(jym{2M%m;v9!S$stfO z;^tH3#obSncWZ6m-4mLeTE9q1!UzTrVH63MPtIw*cXIHp^B3U-AN^~+mpQz%;~PIn zpzqHPxD=XZKu~jYT7#FFc<4hZ(|@1XG6Qz#099Gko=Hvi|1^Z{aml+|ANXZCp5`Dr zd~x9I7x(r}?Z*(IQ}?ysH)|0)c6za_S?H@mJB>l(8xw)jbFMfI9;c<#ooz1ctS#x6S-%_Z_TG2>NNL&P4bE( zdmecVJI+^-%@$tvb3pb1J>49o2B`5WHg$e+_6f{9)Tw89b`B38WJA}MM{XdTM$2-e z)KFqteeZ4top}mYyTLfulXztnuPVyI7(9TX(Y-sVDEl;fUhB!b0$+Ctk{Y3g4d{gR zr}u`mpK~IxZIuISkE>|hcZsaSd*}bsaMIzDX!R>EHpu zCnwe^R8nNdu49{z2hTj&ynCaAt9C?D zymwo+jU47PaC^@g({Ih`oTp&~8_c}klVS#dab6CAZ-qdKi5vO5E9(bT-#iF^HVvr$ zMr{m5mL)yPw<;e{!wHP@S^9J{N{flj1Ji#BN-fV;2!&!vx!$MRboNC&+|^0Y+akiT z@z65PM*8jv;U-l^%fdIn>>=sQHs9`()6Q&%xmwh*TNS&u@-{7uN(X{@+58ILR`N7B z8mf9j@f^j7?`^J*NQ3!YK_*?MQYlRuXm~Ym)wI0?dh3nLsAH>_zwfo`u|Xu32uyqe zJVb1c5nI=q1aC0`OJD+Fz_^L|*B8+!Ej1^*ar0Vyfly%8u#~Y;R8n5l-u-5sS4)i~ zJc&o$iZ+HFpXBF6ypCzwuDMVw5;+7q+grU(NYc-GNPhmixafeU4f%YbP19w)ejdl? z6~w=es2kiCLP*o9Ze`qKUPpu6RFl=6Ty3D#HWsDrTlF#)@(AQ-Dn#UoH+3*lnN20fOOJW*_rC>^G`RrQO%>XV#al7ge1AYoD<8yPVpMn)jrFr2_U?52jq@QPVA zAN@2J{r&nVV2pDd0$+tdiHRQIuBgxHynL~ZN|B5E28=lY={=2F zk#u3ykvYq|Oc?~pi$siJNgnxeeOw``u)=0r?V4ys^|OCx_vQ`UsQjz{LhkqK<1nLs&(YD-h0sVNzokC)Ox z3gkt-L&#IlGR3naH3c14JeD#_7TCZ{!zwwLE`;O&1K(aK%vY;Gh+_GLCxWE4NLZ*+ z&;%a~k-UOJa}&lgk0Bl(Lz9(_$7?)J+~|SlJSBiYiA}7ED=RIr^A#q%2#Z#LMfHML z$MY;4J*`oG^tJ=@e}Q#gp+qDxHljd}3I_`)Rkj?jHK#r}mXIQUpBmxbvF)RM%Z>a- zK<}&&ROR;Jjzam12NAS~B_f1wDCfkBOumaL(^E-%kvi&LxWdBFHMHn~eT<`Me>enA+yxKGA@rxWo3_+}jU3=v|z2wuf zB7}=Q2c(9E`8RaLgDFx_t*k6ZG=9jb=}oqc4OZ5g*Qtv? zj7(ZCK5zVd(e`0A53bx6wBWW>#1mAQQMaD)_94{|uiPBerydAF$Wg5<#0njnZaC+x zW5JP~!)k3A)zN3remhGek|%q1dZi3jxG1{O&qwXEwrv{VclwIF$I@T<8oJ)pVGFx)mc5I6rE;t64$)Khb-7H8>(-@)mUA3O7ax1s0y4ZY<$~Wu zg=N?*3em=ASO6Z_L5>zuOc$2SFhTG@A^UeiyAN{*8UPl~{Y3=+^bX?^(A{XeGVaH0 zH^sdj_X+HDLF`ZFmp;BOhBlQp2@_Knq>X~VaJYdWU_^qJx;|?*Et9y|M_PXT{E5A1 z31QCFpMsy4ZzLw--oDJ~vZ?~^-gprUmfUexNX$f+fxeqj%|Zz5j}hZ1gpp0iIEmoPnM^z-O9{Uqf9wqns=-htuQuEwWQ9I9f&3 z2qtZWbkhd7?{C!F%*oa3sBIgRn}e#=L~|D6 za}ul&|C1d3xBx~pFhgOT-p_VpHW>W6=eT?8{rbp|R_`x1 zAtZtENO1|HCQg5hkajP?pCzKr9g=HDbR_~Pm+23Jz@MI2m5|yPrUjs$fTPrK_7L{o z;q_p)7k;z)z}Z38ctr3u4q~w%=&nV6EFkb{O_m574%GA!4E^sV)DdB`{vaW%^VJh6 zN(cuX2spM0+iCze9Q?Hjflnq!_|G{Gfs#X@WW)`06Los%zDZ3s_VwM^-*5A<2B+7r zhk^e;?m&mC&O5ej4fH>nlK^tqk{9ho*CFKzKrU-n4F8*P8;GIn8yx9HogsS6Dc$c*S>kb-O#?5(+k8E^k z)4vT!A|7j2K?6z;_yuDHLL@;-88a9GIi&!*F*GS4Kv2LqfCt(MhzVQZV0j4ir$TJJ z0Wl%)O2=a;9>EMia6;HM$5V$FWakSdNFfuC+WSaZ0PJ9EqBssrXw(SruY(Xi5&&bc z;YWb!tFfAvCdCBo8&s;8Wh1s&unxq`vmhe@sE}1irN&S3=z~O*3Tc2EBaDEkz#tHQ z3MGU}fya07T%!PujR9F)Y&@1RR%GX@TF*IdB7hx%M9AW9uQMnc zQ&m=$JZR1dGbw-1D1SFs*DP^mP2#0YgK9e#JOLB)ANnYfvb$dpjl_k zrP|5@QFwHsf8~)k9Sm?H;Zl^fWTn)<%+^nAUL0aYtKe z5z&wN=0Z3Gz99l7BW_afJu#`j7zQb9Pk^ZiAutxg8HSvwlSjh4{1$2oLxa5Nt&@i3 zbZTG*R4~AQG($-fkd5fsprDYK*LGY>ejx;?K?Xj*>JSYicoVf zzb8-HF`>IG=xV|7-ZJ~)eMh%}k;ch!4PWO^t=qQl!OevY`c9@aa@MMO=CN)$M(uh{ z8w8`H^z(gA&RN!T_IMKXIIJpW1n&=ZFSAQ?7XPj6SX%9zS!>=zf6< z?pT_L3U2)GwW?m<1tVe5lXK&LN0x5yJ#B#O)`aMS8vPdj4+3*et z9+q`!Lh;eF@UU9_=P4eqdJt{Xf9WQuSJ|_bzyG?l|KeHXdlyOQX>cA6fp3jK35Xjg zB3%E%gINkp0t_AO8p(VvvbDG1gUL;rG;y@nWW7s6-o|iwm1#Lw9u2b?z62&Va+r!B zT4*1{+_^#+JJ@K#-l+4kX(1VVZaoMf$U#ag-(;Zl8?POP1cA{`n92nI8UiCJ1=z)b zi3*ORbuVtm+xO}TGbUiivQB^c%nF3Y<7c*Q@a`3YHg>e7AH?DLirA#+eg<7~u%>Z% zLTmqNH|;DWK=s9y=Ths^k4~(I=Ok^8-ksFY176}lYi%GhCK67mHA6s+LoVMR4Fes${pA}iI|svuRAFjKNF$%>;f1TW)=-kIrpzbpahnxpl3MMo0jr? zR}|P~V3v2m*w*un!TXo&l$w{5Wo4;g@fVyTCzUpHbNpIZ`O*qXMWL}u4+SpK)>Uwr7L4MU;23dGjK{sdYb76ElIaztz$#>+I8AnyJlI?n#&IKz3$nTmmZpw zWZc-P6b%=2>g0-dV3j@F$3Dtx6MuVO#d^MPPHc{-<5N!eRL1~q(`uY*Ouqzvizc=r z*q~$D=ogm@jSnx3bF1L?E_AP?&Z4G4b>A0{x}@AUhrl;Spk%fjSaaAD=QASF&FlL?Kj&1`Jo(k565PJ0(?-ZDx+t%FYTpI4ygdk!57%U@c3EP)J-Y z%-LBNt}7;*v6a0gjF}Xvk$IH0wY?RI6gkQ7lnSND+{whugdGi$gi;%5=4fJW3L~1s zlWNtUc1e&QuTm2x_8uZoZn2X^Oc=|Zg49@9pIX=#LwQ>pCu zmlB(DA|XD{o*f@SOG{grW7}Sk7fEVzliw<2a)GIxnUy8Bz4f7x!WnRmL*P#%@Ta#K zmyEdi)8+hL5`rycq1Kq+pJNH;We3L9sXsl$*1Xth(x0RHn5mld0nP|Cfc?ym$~exg&_`zrZ)qAv;+V<_tDS{{oReob*xODK9z?$2%lB$06{| z5#YqlpMkvE`WYt4Z;x-j`DYTBT$-vIW_cai5Z-+_4_ip(9EZTSMt~DHe+F@^90sH5 zz5(BKWb$V?eJ_pN!p0~w1*@+(_kANUEqsyJXZ8Yo-^_m{cO|oAn)PzqjRSj%@+Rn) zoBKVE$p1>FzZfk)Y~F=+liB@rUyS_u2rzjP;$6m{oQgbHKlc2}1^B3jmJm&9US3>1 z@@*E_#QG|yiQ95|$62tzb#wEG%v?G3Zs+N3Cq5$}h>Vlx4`1h#Z!WDIaekHdbM3}M zL+vo=j|DuAgPHzzi?Cz7S38%7<2yI@0;M{T(K_m z`M&E%_q<22Fy`c{xy_-Xnre-!Nnfvq|y2aQ%<0n8#_+$8(ix zU1KHQ?U|bT>XA(OwFe7Go4S?i_yEE5*f1sRA(XvIjQymEK4^C_Cl6YbElm`}#7F1* zwjJfydN_P4`FI#2!4nau#@EO<@%L-lJz`78`(e@V^=A-9DDKFTjWt`hH}UOlmV5N( zg?m^e5k$7!E#^U}{oKxn$OG|jqt~?UjR1ORx{$O(`jy4XHy0`VH=m4vJxsT=_Shc-u zlcA2*>ANQOhApP@#N)eW&nnk+gnw}Nr*O^cGq?(k#)t4G)JYXp@oUxj^_KQG9_8rY zB%jLS>%-Gy9v8rlP@RJlzbVlV@rF&l`rsJv71I2^ZE(d>;0Uc_+hpZxnNG<%LxvZ=X2|2c)q)QDvQ5 z`?EU#-i5VOkoMM2EvL|7)LD1(#bpBebbYaY0j!C`14u&fRCl*eys&Y0t{PolGoHQU zfv1YS^ZV2bYp1?`orz=7>Wgc~(Y(CSt>Z3inw^3NTe9=3#_~}3`Bh_p$m_l1L+-?X zgbD2z=zisFB)g;y+};XHvXwCQJ)!>!Q0&#U7gmqFwr4e1{RH=X$K>;?M>3yLm)4BT z$yZY8q2afm>xHkLKIEuM3%j}Tf9Katefc~N@5P3K@KHoegqw@2rXWFW)HxYF;|!gxuaTFnBjoGS*89vQanSC!%5f+U{&KFhY<&sGwApuOR^jmZax zy-igTsh6*uiD)@&EP_MtJfsr)b)UV8Wbb+)Q2y%}-wEgad|mY%5`606`u?%;ES&n_ zPkIVtFP;B=6I^@o1*c4ZcJ(X`(PVLF)-OS-xNGZ1UfRA4>JCs!zB={Z%{Q0=fl_Zw zzkB0tcKG@m`**`RdH}fK^`5KS*BQ#z!q`)HtbpX&AF2xl@xEc=ZP9OYE;+8y++GL7yUfoKtCP3dsOH>*bT0C zxGs6>xI4d3gGLw=lflSiTJdtlm2=VQ_qLs1IpX%oIWJvY4{qwF4J9G9G>?jGH zSuavvzIvx|HuT+{GbZx!z7tKt^Bd>apQ#cw03U=ha8SR|JEmH*_5#K3>o?Avz4Uz|ivWZKJz7*6CZVRoC$4P3}j+Sqd^K^4_t9tGrrI z@^9>aZVDWh5Y-6uLA-LcyHAEp1jd$PaWQ?xxY7KA%j01)5ws7u`?t`%zfe1oBknG0 z8y0I+t;2XPFXR1Vn#xtQd&}Ye9mc|^Ms3G8PZLEV0bTGa;dL>?8NNJZ=ft7T4Tt)- z?)&=pUSZGQ!7z|dzsbm~WMRSAM~5j zoT_7qDbt^%Cgx}gQ*({&992*6?wWGz=ynq)dtk$&TD!ui?E)igO(gP4q;=h$be{LYia)|$%)hBpwuN^;33Bb4r9Q84E_Nj^6E`{p#sDFRc z?_b2Mh}3uN`@Y1Dx-eZMkeWDo*tmMu9Ctl1u#6%t>}7#{``*oMT-`m}&F9D6PQvm9 z1P)zg+-z&7vWBBfc)QWc%)76}4I4QSe6u

Px5MK-y^JacLT9<7Rcu9lh<F2I0 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

I6Ut}cnv;M0OH2W4}Kuk?IRhWRwIxaPI(ZbBi6 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 $EXTERNAL_NET any (**msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)";** flow:established,to_server; content:"NICK "; depth:5; content:"USA"; within:10; reference:url,doc.emergingthreats.net/2008124; classtype:trojan-activity; sid:2008124; rev:5;) + +In this example the red, bold-faced part is the msg. + +Sid (signature id) +------------------ + +The keyword sid gives every signature its own id. This id is stated +with a number. + +The format of sid is:: + + sid:123; + +Example of sid in a signature: + + alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)"; flow:established,to_server; content:"NICK "; depth:5; content:"USA"; within:10; reference:url,doc.emergingthreats.net/2008124; classtype:trojan-activity; **sid:2008124;** rev:5;) + +Rev (Revision) +-------------- + +The sid keyword is almost every time accompanied by rev. Rev +represents the version of the signature. If a signature is modified, +the number of rev will be incremented by the signature writers. + +The format of rev is:: + + rev:123; + +*It is a convention that sid comes before rev, and both are the last of +all keywords.* + +Example of rev in a signature: + + alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)"; flow:established,to_server; content:"NICK "; depth:5; content:"USA"; within:10; reference:url,doc.emergingthreats.net/2008124; classtype:trojan-activity; sid:2008124; **rev:5;**) + +Gid (group id) +-------------- + +The gid keyword can be used to give different groups of signatures +another id value (like in sid). Suricata uses by default gid 1. It is +possible to modify this. It is not usual that it will be changed, and +changing it has no technical implications. You can only notice it in +the alert. + + 10/01/2014-05:14:43.926704 [**] [**1**:2016903:5] ET USER_AGENTS Suspicious User-Agent (DownloadMR) [**] [Classification: A Network Trojan was detected] [Priority: 1] {TCP} 192.168.81.10:1032 -> 95.211.39.161:80 + +This is an example from the fast.log. In the part [1:2008124:2], 1 is +the gid (2008124 is the the sid and 2 the rev). + +Classtype +--------- + +The classtype keyword gives information about the classification of +rules and alerts. It consists of a short name, a long name and a +priority. It can tell for example whether a rule is just informational +or is about a hack etcetera. For each classtype, the +classification.config has a priority which will be used in the rule. + +*It is a convention that classtype comes before sid and rev and after +the rest of the keywords.* + +Example classtype:: + + config classification: web-application-attack,Web Application Attack,1 + config classification: not-suspicious,Not Suspicious Traffic,3 + +============== =================================== ====================== +Signature classification.config Alert +============== =================================== ====================== +web-attack web-attack, Web Application Attack, Web Application Attack + priority:1 +not-suspicious not-suspicious, Not Suspiscious Not Suspicious Traffic + Traffic, priority:3 +============== =================================== ====================== + +In the above table you see how classtype appears in signatures, the +classification.config and the alert. + +Another example of classtype in a signature: + + alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)" flow:established,to_server; content:"NICK "; depth:5; content:"USA"; within:10; reference:url,doc.emergingthreats.net/2008124; **classtype:trojan-activity;** sid:2008124; rev:5;) + +Reference +--------- + +The reference keywords direct to places where information about the +signature and about the problem the signature tries to address, can be +found. The reference keyword can appear multiple times in a signature. +This keyword is meant for signature-writers and analysts who +investigate why a signature has matched. It has the following format:: + + reference: url, www.info.nl + +In this example url is the type of reference. After that comes the +actual reference (notice here you can not use http before the url). + +There are different types of references: + +========= =============================================== +system URL Prefix +========= =============================================== +bugtraq ``http://www.securityfocus.com/bid`` +cve ``http://cve.mitre.org/cgi-bin/cvename.cgi?name=`` +nessus ``http://cgi.nessus.org/plugins/dump.php3?id=`` +arachnids ``http://www.whitehats.com/info/IDS`` +mcafee ``http://vil.nai.com/vil/dispVirus.asp?virus_k=`` +url ``http://`` +========= =============================================== + +*Note that ararchnids is no longer available but may still be +encountered in signatures.* + +For example bugtraq will be replaced by the full url:: + + reference: bugtraq, 123; http://www.securityfocus.com/bid + +Example of reference in a signature: + + alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)" flow:established,to_server; content:"NICK "; depth:5; content:"USA"; within:10; **reference:url,doc.emergingthreats.net/2008124;** classtype:trojan-activity; sid:2008124; rev:5;) + +Priority +-------- + +The priority keyword comes with a mandatory numeric value which can +range from 1 till 255. The numbers 1 to 4 are most often used. +Signatures with a higher priority will be examined first. The highest +priority is 1. Normally signatures have already a priority through +class type. This can be overruled with the keyword priority. The +format of priority is:: + + priority:1; + +Metadata +-------- + +Suricata ignores the words behind meta data. +Suricata supports this keyword because it is part of the signature language. +The format is:: + + metadata:...; diff --git a/doc/sphinx/payload-keywords.rst b/doc/sphinx/payload-keywords.rst new file mode 100644 index 000000000000..6481766d6cb6 --- /dev/null +++ b/doc/sphinx/payload-keywords.rst @@ -0,0 +1,7 @@ +Payload Keywords +================ + +.. toctree:: + :maxdepth: 2 + + fast-pattern diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst new file mode 100644 index 000000000000..59d2a432ae2d --- /dev/null +++ b/doc/sphinx/rules.rst @@ -0,0 +1,10 @@ +Rules +===== + + +.. toctree:: + :maxdepth: 2 + + meta + http-keywords + payload-keywords diff --git a/doc/sphinx/what-is-suricata.rst b/doc/sphinx/what-is-suricata.rst new file mode 100644 index 000000000000..6ae7ba1fd818 --- /dev/null +++ b/doc/sphinx/what-is-suricata.rst @@ -0,0 +1,68 @@ +What is Suricata +================ + +The Suricata Engine is an Open Source Next Generation Intrusion +Detection and Prevention Engine. This engine is not intended to just +replace or emulate the existing tools in the industry, but will bring +new ideas and technologies to the field. The Suricata Engine and the +HTP Library are available to use under the GPLv2. + + +IDS/IPS +------- + +Suricata is a rule-based ID/PS engine that utilises externally +developed rule sets to monitor network traffic and provide alerts to +the system administrator when suspicious events occur. Designed to be +compatible with existing network security components, Suricata +features unified output functionality and pluggable library options to +accept calls from other applications. The initial release of Suricata +runs on a Linux 2.6 platform that supports inline and passive traffic +monitoring configuration capable of handling multiple gigabit traffic +levels. Linux 2.4 is supported with reduced configuration +functionality, such as no inline option. Available under Version 2 of +the General Public License, Suricata eliminates the ID/PS engine cost +concerns while providing a scalable option for the most complex +network security architectures. + + +Multi-threading +--------------- + +As a multi-threaded engine, Suricata offers increased speed and +efficiency in network traffic analysis. In addition to hardware +acceleration (with hardware and network card limitations), the engine +is build to utilise the increased processing power offered by the +latest multi-core CPU chip sets. Suricata is developed for ease of +implementation and accompanied by a step-by-step getting started +documentation and user manual. + +Development and features +------------------------ + +The goal of the Suricata Project Phase 1 was to have a distributable +and functional ID/PS engine. The initial beta release was made +available for download on January 1, 2010. The engine supports or +provides the following functionality: the latest Snort VRT, Snort +logging, rule language options, multi-threading, hardware acceleration +(with hardware and network card dependencies/limitations), unified +output enabling interaction with external log management systems, +IPv6, rule-based IP reputation, library plug-ability for interaction +with other applications, performance statistics output, and a simple +and effective getting started user manual. + +By engaging the open source community and the leading ID/PS rule set +resources available, OISF has built the Suricata engine to simplify +the process of maintaining optimum security levels. Through strategic +partnerships, OISF is leveraging the expertise of Emerging Threats +(www.emergingthreats.net) and other prominent resources in the +industry to provide the most current and comprehensive rule sets +available. + +The HTP Library is an HTTP normaliser and parser written by Ivan +Ristic of Mod Security fame for the OISF. This integrates and provides +very advanced processing of HTTP streams for Suricata. The HTP library +is required by the engine, but may also be used independently in a +range of applications and tools. + +[[Major Features|Next]] From a4645732307177970ceea6380fa87d2e2d3f01f5 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 2 Dec 2015 06:34:18 -0600 Subject: [PATCH 1761/2553] doc: payload-keywords --- doc/sphinx/payload-keywords.rst | 295 ++++++++++++++++++ doc/sphinx/payload-keywords/Legenda_rules.png | Bin 0 -> 13544 bytes doc/sphinx/payload-keywords/content.png | Bin 0 -> 41151 bytes doc/sphinx/payload-keywords/content2.png | Bin 0 -> 16267 bytes doc/sphinx/payload-keywords/content3.png | Bin 0 -> 17931 bytes doc/sphinx/payload-keywords/content4.png | Bin 0 -> 20218 bytes doc/sphinx/payload-keywords/content5.png | Bin 0 -> 17117 bytes doc/sphinx/payload-keywords/content6.png | Bin 0 -> 28424 bytes doc/sphinx/payload-keywords/distance.png | Bin 0 -> 17835 bytes doc/sphinx/payload-keywords/distance1.png | Bin 0 -> 22147 bytes doc/sphinx/payload-keywords/distance3.png | Bin 0 -> 11561 bytes doc/sphinx/payload-keywords/distance4.png | Bin 0 -> 28159 bytes doc/sphinx/payload-keywords/distance5.png | Bin 0 -> 18506 bytes doc/sphinx/payload-keywords/dsize.png | Bin 0 -> 31300 bytes doc/sphinx/payload-keywords/isdataat1.png | Bin 0 -> 18472 bytes doc/sphinx/payload-keywords/replace.png | Bin 0 -> 5595 bytes doc/sphinx/payload-keywords/replace1.png | Bin 0 -> 7628 bytes doc/sphinx/payload-keywords/rpc.png | Bin 0 -> 24363 bytes doc/sphinx/payload-keywords/within1.png | Bin 0 -> 18170 bytes doc/sphinx/payload-keywords/within2.png | Bin 0 -> 25136 bytes .../payload-keywords/within_distance.png | Bin 0 -> 14888 bytes .../payload-keywords/within_distance2.png | Bin 0 -> 13234 bytes 22 files changed, 295 insertions(+) create mode 100644 doc/sphinx/payload-keywords/Legenda_rules.png create mode 100644 doc/sphinx/payload-keywords/content.png create mode 100644 doc/sphinx/payload-keywords/content2.png create mode 100644 doc/sphinx/payload-keywords/content3.png create mode 100644 doc/sphinx/payload-keywords/content4.png create mode 100644 doc/sphinx/payload-keywords/content5.png create mode 100644 doc/sphinx/payload-keywords/content6.png create mode 100644 doc/sphinx/payload-keywords/distance.png create mode 100644 doc/sphinx/payload-keywords/distance1.png create mode 100644 doc/sphinx/payload-keywords/distance3.png create mode 100644 doc/sphinx/payload-keywords/distance4.png create mode 100644 doc/sphinx/payload-keywords/distance5.png create mode 100644 doc/sphinx/payload-keywords/dsize.png create mode 100644 doc/sphinx/payload-keywords/isdataat1.png create mode 100644 doc/sphinx/payload-keywords/replace.png create mode 100644 doc/sphinx/payload-keywords/replace1.png create mode 100644 doc/sphinx/payload-keywords/rpc.png create mode 100644 doc/sphinx/payload-keywords/within1.png create mode 100644 doc/sphinx/payload-keywords/within2.png create mode 100644 doc/sphinx/payload-keywords/within_distance.png create mode 100644 doc/sphinx/payload-keywords/within_distance2.png diff --git a/doc/sphinx/payload-keywords.rst b/doc/sphinx/payload-keywords.rst index 6481766d6cb6..f9c34b1eeb4d 100644 --- a/doc/sphinx/payload-keywords.rst +++ b/doc/sphinx/payload-keywords.rst @@ -5,3 +5,298 @@ Payload Keywords :maxdepth: 2 fast-pattern + +Payload keywords inspect the content of the payload of a packet or +stream. + +Content +------- + +The content keyword is very important in signatures. Between the +quotation marks you can write on what you would like the signature to +match. The most simple format of content is:: + + content: ”............”; + +It is possible to use several contents in a signature. + +Contents match on bytes. There are 256 different values of a byte +(0-255). You can match on all characters; from a till z, upper case +and lower case and also on all special signs. But not all of the bytes +are printable characters. For these bytes heximal notations are +used. Many programming languages use 0x00 as a notation, where 0x +means it concerns a binary value, however the rule language uses +``|00|`` as a notation. This kind of notation can also be used for +printable characters. + +Example:: + + |61| is a + |61 61| is aa + |41| is A + |21| is ! + |0D| is carriage return + |0A| is line feed + +There are characters you can not use in the content because they are +already important in the signature. For matching on these characters +you should use the heximal notation. These are:: + + “ |22| + ; |3B| + : |3A| + | |7C| + +It is a convention to write the heximal notation in upper case characters. + +To write for instance ``http://`` in the content of a signature, you +should write it like this: ``content: “http|3A|//”;`` If you use a +heximal notation in a signature, make sure you always place it between +pipes. Otherwise the notation will be taken literally as part of the +content. + +A few examples:: + + content:“a|0D|bc”; + content:”|61 0D 62 63|"; + content:”a|0D|b|63|”; + +It is possible to let a signature check the whole payload for a match with the content or to let it check specific parts of the payload. We come to that later. +If you add nothing special to the signature, it will try to find a match in all the bytes of the payload. + +Example: + +.. image:: payload-keywords/content.png + +In this example, the red, bold-faced part is the content. + + +By default the pattern-matching is case sensitive. The content has to +be accurate, otherwise there will not be a match. + +.. image:: payload-keywords/content2.png + +Legend: + +.. image:: payload-keywords/Legenda_rules.png + +It is possible to use the ! for exceptions in contents as well. + +For example:: + + alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"Outdated Firefox on + Windows"; content:"User-Agent|3A| Mozilla/5.0 |28|Windows|3B| "; + content:"Firefox/3."; distance:0; content:!"Firefox/3.6.13"; + distance:-10; sid:9000000; rev:1;) + +You see ``content:!”Firefox/3.6.13”;``. This means an alert will be +generated if the the used version of Firefox is not 3.6.13. + +Nocase +------ + +If you do not want to make a distinction between uppercase and +lowercase characters, you can use nocase. The keyword nocase is a +content modifier. + +The format of this keyword is:: + + nocase; + +You have to place it behind the content you want to modify, like:: + + content: “abc”; nocase; + +Example nocase: + +.. image:: payload-keywords/content3.png + +It has no influence on other contents in the signature. + +Depth +----- + +The depth keyword is a absolute content modifier. It comes after the +content. The depth content modifier comes with a mandatory numeric +value, like:: + + depth:12; + +The number after depth designates how many bytes from the beginning of +the payload will be checked. + +Example: + +.. image:: payload-keywords/content4.png + +Offset +------ + +The offset keyword designates from which byte in the payload will be +checked to find a match. For instance offset:3; checks the fourth +byte and further. + +.. image:: payload-keywords/content5.png + +The keywords offset and depth can be combined and are often used together. + +For example:: + + content; “def”; offset:3; depth:3; + +If this was used in a signature, it would check the payload from the +third byte till the sixth byte. + +.. image:: payload-keywords/content6.png + + +Distance +-------- + +The keyword distance is a relative content modifier. This means it +indicates a relation between this content keyword and the content +preceding it. Distance has its influence after the preceding match. +The keyword distance comes with a mandatory numeric value. The value +you give distance, determines the byte in the payload from which will +be checked for a match relative to the previous match. Distance only +determines where Suricata will start looking for a pattern. So, +distance:5; means the pattern can be anywhere after the previous +match + 5 bytes. For limiting how far after the last match Suricata +needs to look, use 'within'. + +Examples of distance: + +.. image:: payload-keywords/distance5.png + +.. image:: payload-keywords/distance4.png + +.. image:: payload-keywords/distance.png + +.. image:: payload-keywords/distance1.png + +Distance can also be a negative number. It can be used to check for +matches with partly the same content (see example) or for a content +even completely before it. This is not very often used though. It is +possible to attain the same results with other keywords. + +.. image:: payload-keywords/distance3.png + +Within +------ + +The keyword within is relative to the preceding match. The keyword +within comes with a mandatory numeric value. Using within makes sure +there will only be a match if the content matches with the payload +within the set amount of bytes. Within can not be 0 (zero) + +Example: + +.. image:: payload-keywords/within2.png + +Example of matching with within: + +.. image:: payload-keywords/within1.png + +The second content has to fall/come 'within 3 ' from the first content. + +As mentioned before, distance and within can be very well combined in +a signature. If you want Suricata to check a specific part of the +payload for a match, use within. + +.. image:: payload-keywords/within_distance.png + +.. image:: payload-keywords/within_distance2.png + +Isdataat +-------- + +The purpose of the isdataat keyword is to look if there is still data +at a specific part of the payload. The keyword starts with a number +(the position) and then optional followed by 'relative' separated by a +comma and the option rawbytes. You use the word 'relative' to know if +there is still data at a specific part of the payload relative to the +last match. + +So you can use both examples:: + + isdataat:512; + + isdataat:50, relative; + +The first example illustrates a signature which searches for byte 512 +of the payload. The second example illustrates a signature searching +for byte 50 after the last match. + +You can also use the negation (!) before isdataat. Suricata does not +support using it yet, but will support it in future versions of the +engine. For more information see **fixme: what is this supposed to link to**. + +.. image:: payload-keywords/isdataat1.png + +Dsize +----- + +With the dsize keyword, you can match on the size of the packet +payload. You can use the keyword for example to look for abnormal +sizes of payloads. This may be convenient in detecting buffer +overflows. + +Format:: + + dsize:; + +example of dsize in a rule: + +.. image:: payload-keywords/dsize.png + +rpc +---- + +The rpc keyword can be used to match in the SUNRPC CALL on the RPC +procedure numbers and the RPC version. + +You can modify the keyword by using a wild-card, defined with * With +this wild-card you can match on all version and/or procedure numbers. + +RPC (Remote Procedure Call) is an application that allows a computer +program to execute a procedure on another computer (or address +space). It is used for inter-process communication. See +http://en.wikipedia.org/wiki/Inter-process_communication + +Format:: + + rpc:, [|*], [|*]>; + +Example of the rpc keyword in a rule: + +.. image:: payload-keywords/rpc.png + +Replace +------- + +The replace content modifier can only be used in ips. It adjusts +network traffic. It changes the content it follows ('abc') into +another ('def'), see example: + +.. image:: payload-keywords/replace.png + +.. image:: payload-keywords/replace1.png + +The replace modifier has to contain as many characters as the content +it replaces. It can only be used with individual packets. It will not +work for [[Normalized Buffers]] like HTTP uri or a content match in +the reassembled stream. + +The checksums will be recalculated by Suricata and changed after the +replace keyword is being used. + +pcre +---- + +For information about pcre check the [[pcre (Perl Compatible Regular +Expressions)]] page. + +fast_pattern +------------ + +For information about fast_pattern check the :doc:`fast-pattern` page. diff --git a/doc/sphinx/payload-keywords/Legenda_rules.png b/doc/sphinx/payload-keywords/Legenda_rules.png new file mode 100644 index 0000000000000000000000000000000000000000..c3e913340f7164fcdabf9db6754df8ebd2379aae GIT binary patch literal 13544 zcmZvD1ymd{*zMx3rD*YD#i3ZYxVsd0itFMOws=dSxVyW%dvSM%#i6jUxZ9(@JvndA znM@`*nIt2*_q*RWAu3AJSm>na0000>Rz^Y%0D$v)%~znpzow0(s&cOfI2Sc(F+j!m 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 EFR($N(EtDd literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/content.png b/doc/sphinx/payload-keywords/content.png new file mode 100644 index 0000000000000000000000000000000000000000..267f9ee511127d0f79d58cc62e3ff2253e270653 GIT binary patch literal 41151 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 M07*qoM6N<$g2KjT(*OVf literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/content2.png b/doc/sphinx/payload-keywords/content2.png new file mode 100644 index 0000000000000000000000000000000000000000..cdfe61cbe7719a1bd8151c04910b25af214fb6fb GIT binary patch literal 16267 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/content3.png b/doc/sphinx/payload-keywords/content3.png new file mode 100644 index 0000000000000000000000000000000000000000..a92acd6251ef0fba2efc81a41b91bcbb104bf82d GIT binary patch literal 17931 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/content4.png b/doc/sphinx/payload-keywords/content4.png new file mode 100644 index 0000000000000000000000000000000000000000..943b6fdf40484a6eb14a44b06df5580c517c3a69 GIT binary patch literal 20218 zcmbq*1yEeix8~pj1Q^_%puuH=dvFWxArJ`e?k)*#!8N!OTm!*^yA1B`Fu)+o@74ad z-rId!`(ABL-I_any3d^IuG@Xi_kA;ws>(7LXe4L=002WyR_Y@F0O$33g#zJUTYQkK z(O=)-oIlD)0IJ5w4qiVXe^!u@0=)e5%Izpld~HE>kkxet05JdjbHOFEV3NKzqPWN@ zNuw;i!N(*c85!033II?6O)rJu>uj6Gv1KUCG%+qDpu}Z$ZG)_?t)9Ey-6FdK zs@xJ3(M@DZnA0QOO|;c)^4)Qnqn~I1!}R-B7-zp@FOex3_&a9|Y5)H+zPBU#KaKwk z_-Ew5H~!=8-$wp><3Ha1ar+;P|9sUyBmceeKg97be5;A6wf`be?yo9Gfmhf@x>KxoZ5;7Va!WM}JW*bxE1qV-Is+N2H%Y?8G+ zpZmRlRA^P?nj;jSlC4$nK`Dk5pc+#1@NkceoUlC_T#Mf7Y{`+vx`}4M`TRfQ|5u2H zwLEO_{Z+zK98S(xb@lbbLX<>AC5%y^)MCoCt*~0_Xn@nzWeS@i2?>D~b8zAJ@88LI zt?=ew-4K4yBVAlv{4$pNmWGm&(oT`HpUs6_X5EQ5eJrdkiugZSl4jt4zEH;r>()h8 z%2J4V_Y%0pD0LtJ_8UT%;Hat;YO$|cC1`~x6ku#B4UrJ@4uc}HQc=$NvH{dsN76ygtZb+&;aM(PQU*!*OQYTh8-n34!-I|br z=Q*i)zS$1{a`Wa=Iy@jL`y3fz$7k*~U8ITR33Y{2*Y5-_&IT;cs!@TcXHn_il8sS?#bXojT83 z4YrE6&dE>9&0d_Nm&UyIuT!#`}KJhY|!c{i`%rJwNpo8oJ!H8w7iiY*{s5yUw9Q{v+97DTyMx`<+DXt7YB?(S}_4 zJ~2&Av5zFTg~`+YM*RK-{-K?cD2yNw0M+EfLwc+ee5*@|qmA`QZRUv2i~RFjb*Z}$ z-hF=+q?i1~BXul)F3ah&YVxw_X3wj`Oz`~D?q6w#2Iyw)R~s!FDvmNumjGJc#Zwn? zG1t?z4t|zja3QKLq>DVi`BN66s$DSweXMtAv78<>82w46eomjR*p`Ac&ij|;bvVOpu68E!fZ*_ z-j5{tUf)H&myW129m@7&%njwqxiol7yE8F%gZLYv!s&Hl1^prb2?45cU0V>1JFUu< zehq7%m56rJuBQV|{M+&n9@6Q2@z9Ycblgp@Pk6^KU*eUO^kYcMBkSiG5d)6ZGv@Oz z5GvDuya|qiIU@~jiH%~%N)ticY*jRPfB^W$EYU)F1+$aeT|Mx8Wt_jy3Vkdx^*-6g z0jD(Y5h%OE-#&2rFU9~yTaSQ42n`hgjyj^w?Rdem{)5zm{%Bkytzc}4d6&Fev^ch= zU}N`W-vC!G5RNAJF~3Mi`?v4rIDXf5&fR(U*!5CVhY{_%eSa-smE=%lz69iJA|^92 zvIH>bkP=^OF|+n4Km#t03O2bCj+dyiv#Ta$GTSD#wUCgH{~l6I&9!b^T{S3@eYE>) zqm$I_ZG354qyJMK4FJexlNRo$;@C`j+uS!UGwrNG|CZuo?^&fD_BmC>^C!_9{&4Lx z>-T(UbYf;Yf-Y$e(@~-Jl|m*udaHB%0zCyeA|)DjCt;bTc9*5c_S6Ej=!hYo=indX z{ih@+sJ=h`*-nH>y*}79aA1kUwf!@0*hHCdw4Eg!R#pM>&mX~>!bYi}_1)L~av>QP z+%gbr_qcl=W{+uq_b`|vx;LnIQuH*{;_ZyYD7%`JtfA^Tp+gBD&|Nm_+aq!8E&A6n z5I`-4lgDabttL2Pawl_>Q;3?$Z3BQG5l36b3@^^~!-tQjUZMB_j|T_1olzn#wuuk! zzn235zuW8*V(%`%Od4@5?CG%qPG3li0QLR4y$z&p(!Tx}_Sqay;`MG`_PhoY7>x9V z_J+q?_XC}?pR>i`15}k#0HZIeRz60mCjk3(p!HWBRSz30txw5Rfn5hI)MB+W-++$v zlo3CxZbHk=1h7%5SBCC~_&ZlJ(on-t4>ClZ)8RMQEbkkQn&H#mc5i#X=cfmk7)|I3 zWQXKaL)T5vP6!4admVeL-i1MI8NTMbU;*)<*$Dphx)31|n;DFcIDovb*$B>^&pxJ~ zN3tIp+PqX6;NqLCi7$m(BLN@FHEkh`c2DiNTMx4rxCv3F@IBujPn>bDtldtuw7qf% zyKe0j>l!m1w|%icDgE6qC%Q9H$2mYk?Z zR!aH;i2^?I#~_x6P_0X>%56e2iq(V0GI_t{Q$vBVGpc%3eEgr!s2cYE7I7*)MNLMd z?4qzX)2Ls0;D^|3>n&iyf!Rs_cHxj)8QB(P@BJZDphshssX37X%U z_Xp9w&1Ed(Ej-x*E4TJ(C(!L%q9l@yt^e(%?P=g*0nOc4)wrrqE_(=BDcbfOn|?f5 ztZj?RF!ST}!fdzqx{-(5F+3Tn^4eV9(=`xc?|OI$3_53%WQg0g-!L}Azz*3(knY)H zo9+__^_al{DJ%|5m84WdhR{6LZ$Tjd@dh!?TtPVk!wgskz#GvPwb&KYR;S`v%kfXL_OD#`UpeN#veW-w z0!m1*R(^*=!=;$Iftdjh%HQ|vw+o_C_CG=X1X7e{R}f?8goE>%G~dh;LotgyKs`^& zUS$*x94qkQj>#B~=ZyhP9z~*jcM7v=X-+Vt`R!fclt^5kEi)qL^FUDuCr2beLJnDP z(2kEsrk>y-Dd^vr5cj#@)WFxGTn6Lb!oT)9Mw)Q_P7=#E=>av&j6w;h0SaAmG@ksP z&yk$|)cE<4yhIPf+5ERjINkS*2xO(ZVGA;FYLXrHQ;|~D{lMi+NsI(Zs?(%ySm<*4 zkli$^h-yIQJGws-BynPwOkZss9)Xum)B#cPp}2nr#JI($KM^?yfV|<^7+kPECggpf zWr9Pk1;nMIW5~)$Ns#g26R=!51zNrLLkz=YGGP}}Ca4gpc{u0mes9M{ZpoE%JmJ10 zsKB%L)>fVgUbg8befi7ubk2@o0R8C2rFRWsx6KC+q-_M}U1~veI&2b5tcg|xqckkT z@Ere*F2dEI734%>6KqBRMRxRv3ovkkV;immIoFfa!{Gcv(g6tcI6>In6W81z4A4h5 z9jPP&M}h(Uj?QvSt#(dg&W1hGtt%dv;h|*hl^8hVJ10qGC1x{HXZGF2EB$AN=sp4f06u$*X z1gf@&YCQYwuceZ_`d$U*m7LP%D6O>a{V02c;JWc(xUYp?6l^ee4ahR~Bz7LoHyMq& zk-T_O(}ff*nre^f3Pa;fiL0iqt@k}1s4Jd!+C{2pJ~nmMTz=yySxfC87c|ezP zFqwAiaM7s~z{1e0gtgE}6r9~=lNTySv$5a2Lzet6eqEd{K9|IPclTtPZ+a1__aQ?44owk_L8+teZg^_8C7}aZLjg%r z0aQUrptph|Ax$}b5M$c0mi*%RM5?!gR1!m>xbdpI-}2F@E6U)LD(H}q^5vY%^dy0J zV^TdFxjz61Q@Ku9A*gWDEPDBHOyfrHEOaf_2eXk6t{ZhNsGt56ecJ6N;{f)KoweWrDD8%m$I9?mn=GJaTWLsD{rOg8Gf@_WtxV z)Odem44*b)k`<=7(0OtO^@NLm9g5QPOeiv9GUff)uhxdx3BybC-;NeGD&-i=*EUvD z!_g3RFVBaJ5VaGnMUK2HE4{suITt3VI(^{^!qI1Soh6kw? z8XkhPkKfnKi?*IhGH#x4vX$Q|d#p!8Ha4T9w|2d%mk00Gc5NO_3{N=EZmo184VYk^ z*$wwA;qb<~IF|gTP1>`|4deD44QG7Lo&o9J+ptB5$d62KNUY&fXrd4~h6MK59lKTs z|G?7C!A4UPej@^eP^jH0+j_a4yAo?WXclEF)r$p_#`$F2nR0mY&^7B`vN?yMYcp+) z0P?BIz>Pdqm3J=>dbautTzjzK?mbtsu4vHqyrr#OO!p@Hp*g4JE?*@s2D!<1>-jG4 zDKfAl$B&g}MsER~4iRs?RM+vLc1`8Dn)ji@NU7}o=T!UqZKPs*)et#Wc4i*+IYR4{ z8C&k1VO8U&nWYv%zaLea&jr>;-Tp48F;pb=JuI@`$Jb9y;$6#K)8^_7^*v+g*f`RKuGKmoZh~k@r7?)k2lt||9{=uGHEeHxQfYF_)agYD3l9MV6{OFWokK26TNbC- zHJGB185=9Zx8AwhS(Oq|0cG#zh$hc!zt%5OTP!1q`rqBb1(+x(3(`M6%-SAHQo#Q% zK;b1`vKtRivv@~DTq}doG?Y)q|2Sa0TJMY~jmVT1S=yr3z>+;5_^uZrPgbqq%e+_E zHy}Kn)vt)98ow*useXA$^z}B79EKr{Ey1Wd z=5-z>C1yrM*Z#yJ1uP}8AsgW}u)nH#GdYuY~cy|HmdMZI(6h$gfF3{=A z{>}_lNSW1?Vd+}2=o}XzxgCzGCXrjS(4OP32%!1sy-RskHDv`|>AsaR5!=8TCDC5R zKb4)yX1^!ZMqI&AC41wUAYGjsf~e>>$c7MvS4l$6smYd6l^PK{KEIe;(-+wW{0wj`i)ST!jq9&oxd76CLn~V*%wGI>{utJi5Nk} zcr@tP*%^q+Q?f*uXDjjWCj z-AzAE_3Eo&)TIa{e$ck!rJN8tNkxKTVrLizk~9*Bn3Vet0d`t=y&pl!YOiF=MkFZr5X>0Wt@)5odu<@3)? zfl8l}grK3ag!m8blYEYU`?Y1xVk`2Sr<|OXD$l$+63!=<2|=J{8C%$&?`7ce5Az#M zH^f!zljBk3TMTSlvU;yV zWpk_LzhnrSy|-m+Yq9zMp6t9~F2>G*>!2yQK0Ne8h{q-Oq03oD=C6;FK4XgS560XV z6*8G6TZgmDo1>kUw9Gt?`PqucM%iLW-A>y%XDJ%iQ|2-@F)4p`BfBoSp7Z7z1@m24 z>Zt}KN4bBYIk-5uw1a;$5z(e%YaE|ktnqcJ?c>fT%Ow6v9bmu+zW!=`#YVtrtxQau zN`qCU7m}{Yd$P|j6goaG4PkJ7Cv=u2_-&%j>gA}8ZF~z~WN#XuBpwwFA5{33v&=?g4cDw==Wj<&sfnwDqbWW8;W|Aa?v9NLM?+h4R7sf`5MtC=9x>DH6}(rB z7Iez!e8}NAfHi=@5|1G@MeAebV)L<_7C1$T5mL-4v-C}mTN|5c*on@BWY3; zVUEDe!`@n$+a8JzH)Vp?Rr(`GlzzF@bj4eDI0KW!*|ZSxz-7JOH4K}0k*Zm-R}CnR z>{9TRLIS`cWHI*ZTz!z+=+ek3PnVk9&92&Uxn>&1X?9_F8Umt1J=5*kF_uD%Q)~B* zavp_V+fauDm`fB>M3e-aH73W9$#%>fW_BPHZRcNLDF;!*i@zb$9$Iko*b)8)oJ zEmCx`(ykaD-R|%rd?F(3H2AVaDe5l(W}+8v_I8~O_)SXsie`nZ)r1jai6f;vIv%Lw z(;ajUHH2ecb=6-@u0W14RUBrNMg?O^)r<41jFXNSLP13n53Z!kGx`36y^??SfUn4$ z!obAEK`Ia}+FG?c!Il5Z_mX{K~Ehp%pXM&y#>06hZN%T8-_G z`rR6wN*2#S^ZP8Y&fiL&!OpM>05G66Ko1F;BARs=?TDOyp&{y=harG4L!1;LX7 zt`B1eD0?Ai8?fr!vJxX)_A$vo4Cpf23PNvpDodWF$EIKAdo;;>b@vfZ3iggbO;G^+ zGu+)B>D}Gszm;E_%lmk1w&$tCruzvmgXn;$gpPek;j9ev%v6xoEOJ1~NnFYsnqObh z5lW^3hThbIxEuJYd0YnF6O-?M5z@1?UI(CmohPngv$BBs8#E{xkla2zybAdn9JXTtUy*Zl#pnl#IVhknltB@^X#`c}&pMS1bjoB)% zuj$1AI1a(2>Zu83|H2Chu|^G=@m0;twv(9Do85ZZ>=NaPK=5UOJ?d*wFXwIpc*P$s zxG6FzhQxrf-MU`cU+fSn5WEf!hDYKY$#cF1{MWcC!#%b=={FK;`1nFgk8dAL)H=Rk zY9g%hJ(9dsHT1yJ9hdQ(_zh*6UUsc<=oAbJm~xL=P0leY+1rzv|4Jb!AFrBmQpWX* zR?OnyDJ2SE9l9j{iO&B?M`o?Zn!be$h}b_UrYP1O*8v&V2^TZ|4U~l8CMHDq`?LQ# z&fFDyIo^WcWUk3^Jx$vys`IW)cmj*d5qYaLnclrK_{(zShn~t{7Xp&H9;sNg==^0h zTV~kiW@y>xf)Np2S!)sdb)rTbcI*2_atFSp|0-;d<2#EjS=8{{4*`8~4^nk9FkxmA zGWHuulCZJL*`we1?{_gM(?0(Pe$Q>Eb@Np7_+;%P-q>&Sr`~)<0G>2sl>DDQZ($l5 zrM3!-TO&1#W>9?95h^OGP~0O@lWY0SZU)PEb{41O=j;LJ-%<14$_RvKvpC@R_;{`I z8>bUvZLO0JKohRC!H~?T{1ADei+QHIbFVA_gY{B5+yP-Cl>2%=#WGDYO z8u7onfd4mar^;n}OkQEUsf~S|2wqv=TrVZ-Tgoe0H)Wu2e=zsdQ0@K%YvvbTLiLmp zxxdfaIHC6&l^%BN)gdm6tJSi$ zQOC}%j7a?NMHLL<%j3PSp&n1mkFmba{gu687#&~!j_^8SQX{^1cyG6Gquzi$0rk1p zITPF^8zk7km-yJkPU1IjkRf+LACv9s@X-D2oN~e&ssX$yj?Ni7<~t45X#xS_vlG*9 z=Qm4Di+$~`FfeLAU0KAsP{KauOL;)V4fW^WrsAx)tG4y?A_DUCvIHqe_^h0b91>fT z(Kf+~lpb4uHO}v@3ENixR{3_lC`(LupBWw;F-4LQ!|cu$bN4!O=maApN~lauPlA`+ z_RlvrZ4YKhE)1PGOMg@I0cgJCFQR$D5R#@?ZqIP;YVU-15Z1*hRA|kG7MTH=Z zO2fq>t7f3ArP>)MN@DbBVX;5r8!-=dvHOgIy+eyBBD>hO+}bR+3Rm%P+w9Z6;jhc$4hpnPuBL3@o z*Bs}+v;fYu@NpE2HSUQ$+Cb3n4n3H!E8Xyh_#z*UoNlROXnv?u>OcHZw_+-6kRAKE z(LO}ht3Lk^Hk0O!NK)&xCGqn}IP_O}k%D~}R|rUgk$~kpJb><7@Hc=Mr={5h{}cwI zgFA*hemy!P2gscJv>8FdpwZuSVAJQp}wulS904;LbK+R@?24PV;>(+7(`AlHctE`07#TRbp+|~M08fS zL>jObPxflcnnL{=KwN|MA}+UuHtCCDYU4RTqMqRK;<0I6^wa<*^`-6?Gr3z|$QM&H>+VgrFF;5}K+bKH`?w&IA6)MmK zYe3>VUWSLo<%LKRlPJ^O5?$-Jzrb6@$LZZk~n_iQ!Jws zNr;YRpPc;`isft?RqJ%5{F5TvarKO!MXygiH9M+4>~({D(O^gzgU{e;?iq__>Sxo0 zl{drn{e!5_(~6A7{%5D^|L<1)zw{_$=z;Ao_%D(97A5=lM_nR@IEv)uvVf7lkNjyUbSZ=a)G4y-HVL?1cfFYOJjjbZ_u9zaZjGjf4g0 z#v}gr1%I!7S^5F5(PRZykOs6emw33-a`B|nEF)Z3Ho-C2fCP;K8N zfL}#2hJX5#j$$j5KVu=&Gfakw76ybD#?b{l601bwi~bbi%)msV?r*(j95;DX&~%l#Nkc}w7Ha!G^+5-^KEqy$vr=OrY{!WRpgSu`1|3)4R@P};TBc$ z)Sl$$U3KuEHurlxOWpP>wBTu zbpK77yXbDY6%KueCpv9wTHM1;J*m@j(r}_5mx%Dd?HZq3T57h>p+@T~;UgRN^fYhm z#$5JvXRqQ@OS|0EelnAl;dz%Nlj@I)Bi0iPwSBw@(PA>7)%KDYDK#*3-_82YAAfQm zepJ5KPZr(Ka{W^0j&D|+r6}u2C^Dt4Odc!8_CEIUXN95hHHqJN)JpNEsbkCV-4*cH zDVX4kxRFt*WkDkRH~#&La5*)NA2!?+Tm$6b!VR8y=l$s2IMpYwrRw)~f0G|a)=ABM z>-z6hxE=kTMrPu{qw<2>;mgI!Uov`pS&MNnHLKL5pH#lpzNI)1`E@F?JuE{4wh_AT z7ZHI=`S3Kbs#>2g>vS-z^y2$_S`u058!Ws*c#7PZ^>I+`%f9!E{_}kgd#BOEtZ=X% z`Gd#9Wui7LjP6rFi1Nu25rJq>p4sjldhAdL*+GntNBTrwyqpnu58oKUajU~5g6ECl zysII&knYkA86-ycWdps{WN^BJ{^Pu>=MQUoo zH8`T=e0KU9Ra{>BI}xo!@i-|eE*Haj40y5AYjT#|DwSVWRcm`)wE_hta?}{5M<2mv z{FHHpYS(3jI9a5~sEi;Aun^J#OH72^Nl-o1ei?7U{u9y}3a^V{>X$>yP{X&YSgP%M z7XB?W5?s?Id^y1>KV7D@yU>9n`*0xp5%X2vT+J zVX%Av!(M7Ad(7!don^0HwBE0_lSwf2i&sbhsHU&N_jGmgB;N}BRj12voHWO{Mrarb zFsQTAq0}2Ly7v6MwI$GCy;`Uidr zZs&FNJhR@G?O$b^%h9vs_qZVpM+F!f4%4pEdD-b``H7$i41DbE8f$gefY7^=f~)2& zu6@@|6*YO(mKB3f_6O?EPG=iUg2QeKAW)CtW;ipuC*vl1a#2X@bEH0u$5yr4 zB+ zvM;Yx$%hr>6=(TykRHUuJ;sJ2C_h74PA(u%PZ6LB@`jz8vqIjiY_%R9@<~W&u49{v zR(=K{YQ*)a9yeIAK%*Jt5Syzr3f84X&9vE>BEKHJP#odm-|Q!x5Vv?n!cy0kI>f_k z&mfV5wXPq-_iua8R>(5aQxjV^f=fr!8?vAKa-^gVtnKzEt0bF5RNfh+W~FB2{Mrem zV1-1d`*Dp+hKZl{LK|Z{&u;9UE>EOl&M3QDdM)Vmbjf|c`I9;YHu2amtW)yE%JGhY<5ozV*|(Rw%DuhL z7o`-VRTTafKga7hB*WsqV-?53Vlto2Kq$%Do$^yDYAGhod>--is{Q-z@v~b9x3d%U z@mcAL8r@4-L7q=meo7sDP15;wB!izH(_Z+SEJ1QKUH-B!dXC>_XhUR7ox;e1h>7Z+ zaz_{&1V1$^?efSQ>V7h6f>n%*t+uOQAlPssdb;O}>dBubGdFTXia+b$4^x&j zw|TKs-P1B`b@#sO&^*x9WpHOFpRHBe+fc_W@^$NrGp=R)ahDcWgTCj|zUYk_4Dwn@o!HBK7+ zl6vx2_vW$W?j{BETN~RgR&5RFUw&JQzuK$VNAA%6+3M`>18#PniIcP6A@olQz7pWG zA8+B|o%P84yymEA@j6mcT`ACD9svxFvw( z<*kG05mJ?u-Ui>|FF6|R9tgUGecVJ;_cW&e-_xHq`&#DEWO$N zpeL9D9*_rN(ok5%J3G!7Z#Be_Sv|x$L$#9NNf)ZS)$ckMxc|C_y!qY8vEg)|es}Y- zHX{F$sY%SIyeX5{UEFIbUiysvagAG@xvR0p9b@MmZ4CYO(9(}KZ&%V{W29D1=kt!R(Il^TNqwUQzkQerP~GV}fimT3wD8 zy#%fquy=kwPdE6oj+O1;*(A+rn3cZQrX&o&G%vGjaN}5@6RgPQ9XP=Fn1VEzM(WNi z-0Tz~%}bg+0#DU^eyyC>c16ynP?Do}7<0GBMwO`9gd)`NMd^$?D#~TRb8Ool(-a%2A)sQk~)ckl)-WVWwUzs=G8g` z=wco+@C)}lR>e?R&^y*6DOuvH0Y3c;Qf{~Qg`)fOO3yGHm*@qm!KaBKO}{5CXYZUO+RT!O5}GLj#}eLt*B z+#Fd0)A+7*d{CbXPE*5u&!P)PU8)+oULRGRZH(hQv(KrPVeDshK?zHop4!5)y}v83 zMq|dL)WFSRz^XP=dEBoALn#zwRTP$CM~@b(kL9y>oHq?!(WD7deEP~povh6!I~6OwTYtzI3-~Sf9WQCSNJC zQ{!2j;udCmvR5|5Z9%aZZ->Nb?adzxr(~v+`Mb=cu#c!rBP>CW zERaKJcRC19z0WsNw}i9@Ec;ihrHO(JFjXY-b#DrZfiQECP%TWN85VGR9aT`?w;Zj6 z73$^7hnBC0%=U_?G!cH#PQQ2NQ<*RZKN1S6tQNNyb9*12N}7PO-c|qVPlvwFr|In@ zYeDV5k|Iv0jnbze5K!IXC3zK2Tgb-Xa1&vcoK~r(E%ZoqgtX%!Ra=`q{o)XE*$LTI z%(!#>8ekNcW*6yqQjkg#$}}-_@@og8VDL_iB7=49;9_iUsX2`IC^pL-gT(PAbu9*S zaH-wXuyOHAYJi^G5f3lvdl$dmx*^IcqP8&`dVM?9aI8~)56D0QfVHBx-D1a5lJolZ6 zG{|T6yTR~@GX-ob&thd2_xVw;qji0hSe??xd^G?On>&oj z{pGfQMf69|U|L2tCEv-@{F25Midp5LSgOTSZ*Q2Q$5o|CteWohar0%eb_y+soMAVLy!e{^IljvNIj zYKt!r<)2#^@Z!a3{Dd&H{#>fUcyqutypD8b3tlD4E&01E8lBaqL@p??KR*Og+&t_$ zZge=$9x>H#B2(lFpFdbGO;a&x$PNKb)Vtd(Xa10x&2WvbB38XaH@Ife^|%WtxwEK0 z|FZqua@a)Xd{ZT?j{*e9iu|(No7BjW$MF7TU6{$4*i-JWAW9qJ=dr~eURQbI?OuIc zkYcn}7fnHpXrO!1b>h zGzhpw-Qr49;z&@z(tf*Rz3dL}&Xv>JAr?BY(2=(!p7QuViEcfkz#IDwl>((5(KA+7 zOY4O^87Gwag;7E)9@OHI@orj6Rt?Z)uEyV!7Th^5a+8dmwMS3kCSPS=Wkw1e35|RG z-CUg8Fs=~0V1DQ0w%e*Pu*Oz9@^MVdg&5LxwAQ*&9{!h!)3aZW>t#dmoe`XzR8pJO zcCN)#b;`*kRWFAN6Zw>b{ZbPDm#DpcxNvcb-ng(NJKB?4Vt$cxMm+(sFxUhC*>3uN zfk1(@@nf@%!pq~*^G^omJ>flmT*o=jl$S8)iry|AxHD$D>Q?tQ|M{4W6sHH2F~%(C zPMv%b*ALOn=Njo#Iro$|^_jYV`_`z@HZ8^;Z;P68fCHM`fJ}fKT+qZ)BWn5!^K8`@ zWDPE0fYii7hGLIO_cj(4{cdZE<^}KMkI#GWIb35J=ekTq8(xmSbj=Y9S1SDZ`GChb zDb+#p5cO8Pn~G5iK+KjP5*3L^Os5HqRW`3r;rgUHIL>k$uy%X1J7-v(*!`;BnZNDy zPkXQ%RLzYGk>ORegHxKsFO5^BBBvXX(2PA9vI3oa9F4ae_&#wsFEc)RGf6qd_Nnd0 zm^ZnqoF)jKS?Hmp8&UHIA^?LK5%r@l9vu9v{X6>%5*^_`z{vKPzhTy|7~jNSC6j_# z?{s)skLsW+qaX=sZCPTevX#mVxX}tD@ZzXr@4`+5odCHoVVQpPKYSS4MaO^Z$6={R zo@W{#q(Y(ZXhE_B!t9QtD_mKxVD7LKAOS#rE=z+D#sNT;eD4aBZM{YQy54MZ>@;H& zAr=6iml2^6BqRG)W(czPeAIxzJy+~U8{&0h$T-$C|M{O@AyhQr!HNX<4V>(b#iN&z z2Wq9r1{7G-V~)2rnd`}{-77fUW;0?3SHFX&b zMr8Z;>LDZA?d{&xQ`{aLa$s&Mb2~0d=Wm6{(_3(q&QVD6BUU-@2@XNEs&-@p zV$JEM1}~E;fv=2Uju8dsX%D`Z6US+lr|HeAr@4BfMMA+F-J;HVXEwygTRPFHB(|m} zGO7Webp{lDB?gX3X{clm?Miic`p%nwTJdES46klUC{qN{J`Z^`Y}f7Z7vij+9SsgA zn&$v0k3<(7BFS!jQccj_T&uAyjA_T2az7%#E0*15d`ScaEi1Q8@5CcYbHg4Utp3ir zhbz&Le@u+3l3=Nr2N6q1Xlqbk;z5cpVi}ks(@my^woG|78@120VU4ms1JlrC3JB&6 zf}>&;lbe344}HCZ&K}@!zvHCDk?PMe9*3>1DlTm9b#R>pJY{k(-D5CobdUM}a)7>^ zz7iQVs0^2%i+_Emc2o+M#$wwqut^bny>Q(M%~o7BpIjjAO(KggHIAQA ziZ+{;n^!`99dbI%a9?%)bwbddJ)?n>=qcLW`N&nWzxyXHNJDd0-H;)bPK2`h&yT_( z6IS3HO}O4^N5|Yc9SjY%fkrOw9B?i&``mCw(e=`_!`zBScd(6JVVpf+}h=kZ;ha5VN@Zmr{AB)=oUHs7wCE+cEN{e-|b}f1R)9FhT`hWe&v=sy6Zf&8iUdc zYD_^L6336S>iKZ$Xey)BzV*BBXp1TYfZE$~m#lxP4_+aI%JzQ=M=%n4-iPlOKCIY5Em6 z6d7aE5|DDtJgdS;w<{X(A$p>n+(;KLB0rcS0Hg!M6yTL9C?a~HyM*(&tyr4f*s!qv z!Tr1}vDJ^Ifh6@jnFft*J2};55YAV00>Y(vdOTNn+mY~o-V~0lUd<`aI#s-kNlt4! zEZDQ76t!AjxES}pD~P57Q2%)tkP&)(mKSzCD(9w;B^CBLET}$Kas$xVzZ?qMx5AoZ zZ-*h%11s0EHk1A44b9JYcWIGZVJj}v+wLj0;3)H)XV^&KlMFk*9fFYeEj_j+Hh!fP z2(i1^sJHvE&;TI-bh^ThN%sD7Mafb70h0;PZ3cqF5dh$*=05$X`&w+BQ5~Q#opA>x z(t9E>)Rv=;){t~1?cw-D&}`nOUVYh24KMW^$=i$k{l#fmuD+`)+w=S=we+`P!SoMHwd-8XDT8#DOrdEuVR;IFf(+OqF!T0Kwxa9Sx24 zQZ_>v&wFHoyU6R3MR}{2-y=}sx~a&b=Ks36rn#gi_%Ylieq+30+jA5_Ai*qP)Qy^Es>4B(pqsXoa7_4H2FU1i}CA{ z3Q%lp+cXux%GH-i9|CN#0%Pi}@6!8Yg&{whL-11H8TxJC?^eYq!4w~!zJ|FsxWDtQ z(jE@W3U5zQkdo3DOBt-b76Ri|FmZONQtg~*kFNmH| zEah(vf}J8FlojpfHj|V6J=b;?Z*(-aiX?OHgdlC7Pm{FmY_WX@utKYM-%^MYB<{Rx zn3C!8hu-gHxBC0!P|#8=`7y7x)rAS~{HevYWqzM{O{jTQil+3DJi_4p+5M3oFw4GLfOSqrJH zEEO}ZwMivV^Zm1bN&t}Bjo3{*rQFqNvT5t}PDobk>KkmF^=;4Mm^3`$>qI)KUs zyfI`bB)>nB&2%38-d3*nN`JYoEN#SuFOigz#{7{4Y^P95p6zS*!kh_+HDze~9FA7g zh!Ow?OvnGDn)Cc-gJI)vY+5U7RBehopF(~nqljGYae$FT^ZJR zDqu0WDDTGQ&b+@TvoSZ-9uB*k^|0Sw=-W?TM(V$)qoM@nfNyz0n3z5_a+2;pHTn^CoxBV4y9NolF(%C{~|y{x)vB(>ivaLH^dW}p4EFHI(?0tYFHA*x!{kF+!^1WWX`fw=YD)xN}uMOeO^NK?%; z@uDY??pw?Y%jCw*2!ba|7C6w}=GskO;_MN-;!UpgN!L$+&wM2Fo8@L1hFA0NffXTd zn3!JGZ}{b45ssB>i=sj@q9`Lb7llrrqq95mjR$oc_td;Iz)WxtGngwZCci=7HLvDe zfIKzd!wOb;HZZrY&D=Tk*cD37z>x3iWnPj@3Wp@@$CREEI}D^Sa-0%+4lY&rCJ+zu;=a)@}zU1fqXEzZPS#lKGqawdHTZnR zNbSOa_*A+V>X%|<7`E)V1MGWNyqV6G52ALqVk_Km;<@n&_vLstar{#3Y}+d?hcctP z*i2YsWIu(ZZHtL1+1dNFYoQb<`{5j+UExw-s>Rh--pXDD_x#KH(=w#6owKA_nbqBD zaj|)57Rv`HFJ(pLo+Lal+?Tw9;0?J6=WOw%rA+vI8)xfE&S~s&4cRC41frNrxeH-A*_<>~W=$f^yA?p>O(3f{FtuPlC5rt1O8T?yL{JvKPN^a(GxS3YZtc z4!Q5+o<7#x^qdi-Rgc{I?QPZ47;3oZe-OlOMd(-x%t)6+?Y*XhyboDX#t5qyQO@r{ z_Ex$RUxJ>slJXUpEKH&l?w!36QSo~k)49|;VSr~DQ|@2x@VGo1h+AYnQO_QJer(95 zwUkAkY6Z43Tae__saUZp%A>zuB|WrgmKiu(-osL7By*FAW}EO zch6>Y^wJzXQLlL*&M^IB3s)y*vL3I=;ddEvdyn=l*<jEv(?+C z+i%0yhU^;9weMy=5~&qZK-B>|&rBBs3Ff#BXFD~0>2R5bSUb$jq$#US^tx9JPx^2c zIP`nN;D|iC3>h=Nlj=*zPL3P4Iq0b8j`a`yml;zex7+-%sSyb$z`GTBTjS*CI}%p= zyVc@4kSz8WiXT&;?WD0>p&dnKj5Dm2GFC3lo=1fV*@6uwf0cBW^Be zZjcWHX608>Ro8IqW-jNOkkFxU-;5CdVMXKAcT*CfYsG@{aD~ypm*}b--N1C%JIezk zLUItbs21oVc|yvDK}bK*lqi|Jvq%$Qed!TD7X;1mV0S-7-p5!Daqle+-w;H1YQW-Wif4vGpE@0eR8AS_wY#8x*fR6hPRbFj9cF-IMIh(< zvj@$~BuM+mgIWxshx>^5_;88D6zwNAX7(G`^2f&O9Qrx#mb0aMsBg&)@x*r2)%#Hl z-8goz3znI=+MN50#?{Z4ZF-gODvZb$uN|^hK?eIuS7Yct3FWo1J8;bV7KAPi? zU9Uo@RUn@2+z+h?HX&82fZP1}VW>>*hq;y%S%5nq5^VG_s{+&h`efrp zVoD_4Zh?5+L=T=9m7VXAM=HV`BfDQ;ad{&8mKp8}&@Aq#JmD3Zi>z1eI1)WLu|d6%0{os-B-HOlKozF-!8Au~F!F;OY4qM3<1jbtMv^nZMjmKL2l zW*dvm=fu^`gHOlx)GU5X39l)6*?7TTpG38IvWz*!YHI6#IKdc=gr6%bzS!t>WK#mJ zSCRG;&vR9{xUIm?V4JNfR7o~hv~L_wy}O^Z#Uv&eMeWLA5hA+Y|GlxcD>8*Becw`5 z89%Z!ETqSnZ9(1(+jx8Z8aYJ5+!A@TJF6%$WE!mp>r3W-U~#&+qH!?7rgq2)ez6t* zhWIo(Rhin3HhJ|q{|84c9nYQx5CzPiEIRP_b^RhdFeQUjQ2rkOXb&-HGa>e9X_t1h zHKs+&2Q=p>x!X{=b#2ZY4&MikDzG41VYu=%ZDWv8lSgx3ieCVdAQWE>AuW`YF0Q5p;%SXTO|0y;gQ1K~XsGMtUWpXCi>qSN`BNpXKETosZBoNN zKj@l0MLa5ajlNvnWUZ{8wlJQppUkOq^2CpuSiZ-n>^fhd6|Tnh*mN|`;_~j7^vUcE zj|t|QzFU7He-Pho1yNCdQI(4P4zAX*2RNly`*}0F^}WiPy5~p9~X_?Bw3B5+=+wP*K`_?+#^s) z7G01mvgN&e;m3_^33)-e!~1gJrCWDEB2Aa#gU^sN&@YFe_cGo)DM(86!s8(6OO2wn z6S%Er2BT=U&+~C3-O`Oq=yvT(ndxnO(adn<03w_q+FyDaYaY+R@0`iP0|c(Tin%VU zs`{Is&N2R>7^uo0;_ssaO1S@*dRzGZ(BJAG`nURr{;mF@-&6mg{v+dW^&c63tN+XR ge_H3zW=~w2F|I?2Mcv|eF&*HcnyzZCvTekF0EJ!H)c^nh literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/content5.png b/doc/sphinx/payload-keywords/content5.png new file mode 100644 index 0000000000000000000000000000000000000000..41352ac448d46314a7b77927bafc202fb021284f GIT binary patch literal 17117 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/distance.png b/doc/sphinx/payload-keywords/distance.png new file mode 100644 index 0000000000000000000000000000000000000000..e6154dabfd016ea0e7ac18fd2ad6c59a4f6a0c6c GIT binary patch literal 17835 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 FCIDxx+4%qf literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/distance1.png b/doc/sphinx/payload-keywords/distance1.png new file mode 100644 index 0000000000000000000000000000000000000000..096c036fc364c958a2d5dc5c6e10a91244883f16 GIT binary patch literal 22147 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/distance3.png b/doc/sphinx/payload-keywords/distance3.png new file mode 100644 index 0000000000000000000000000000000000000000..4ec2b60c48bd68c63c177efa398920e3ad56d3ad GIT binary patch literal 11561 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/distance5.png b/doc/sphinx/payload-keywords/distance5.png new file mode 100644 index 0000000000000000000000000000000000000000..0481179aa6687620d0de675e098a7239ec6ce7d1 GIT binary patch literal 18506 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 z zG1|GD?Ev|8ix9m*Ke@_IlZF?M#aiPZIPPYh7!c9E!44{vlvi&Z>f&qEb~~C;wfeO2F|!dwp~}|I{2Q+&p5jLDF4H+ zHq%(Glc=p^5S4$11yDK2|LVT%O;PjzUfewjZv~%9PC1DFTC+ z=fcN@cC5#xh~NE!H~hENR6o#T^TPiQsb%<&wCO~?cbaunKD--9^{>um#99cc6uj^H zwpHnn7d&wAceHJHg<8B6s_an-eE|5c{oC=_v9>K2)Z1l>di}i2aHYLc$Bpmfn0~Kk z{oNHhcQo7ppdMf2*V8XgaX;VI@Gw?3`qG$O^Z{xnb&!&j^$28J3~4a@3lfGSF~)=K zq%tMaBsVf8%JH;cz1v>8D!Z}yx=kUK<9Gd?1y20(ExqhLkxADj3|!k9s}qt48BjFu zPSk;Ut?&)b?J;0H++N&z_GH-{%^qWi$X%44j`Q+qpYxCV8l##Dl&Ey~%-5dZv+3{v zkHT9vwC~gSdbRO@2nB4wAXlB8IBCn5)#0S)y{C6l&X9O2j~3LQe!Bt>+9N7&GEUc* z6A&W{5t?hFmJxsq*BZ{n2t9I5+aw|g@VMseiPIPdM}lXH>mI&l(3N!%8N}ZW`pzu~ zE0zB&uvU9h!2;rd-;|vtCT4KENL_;3DJ0u3h&2H|!-GT``7StdIX}s4o>zw*SMh%6 zRD1h)R2X@K#gm^cc<9BUb`<$1QgIPvvw{G9oe81Zwd%AA8(?Gi>Q@T#6TX4KL$EBU z>Bou|o8xuq_E(}#D!tN%2!l077dibv+WQhEBjI6889hr=YdiQ6mB$BdC@gJj&BYKA z-?M>{(zJM}w9Op_Sg$#b{*^{wn3yOPyjC7*eF1L+A)oFrty2${WrAnDhmy1>lomWQ zA)eyi6KW0bb=YrExJe2o`0u;%bt(qnJ1JbRdYaAtd$fAR_EFJfK zWQj8OK>}rKZ7zlB_tj%Uw|cCeb{&By1Ca@$lCKL@l_HzeAQ(4?KjrJ&d-cvSSsL$x z)5lYVLqcaAdmAV5S6iV?-v;vW_7P;+McukD6gBjR@Uu=xbENp{a@yWovt#|Td>9OD zZ3jkv)_-;6*5N=@=$LGYeVWS4JDlP3u=w$&u}*E z^k(+1iLz2V?@$%{b9l|RQVYtCf9{Y#hIb6@a+Iqb-fl}j&#}3^PDE=w5Q0fe)`Mgw zjcOh5dc6hAG%q65;}=RCjT5Xsof}Ba!s9d;k9i1_*A{pCN_DE^aFxsIcPQHPejB;> z%|tXvBn_$V9L+%c$2O?XE7)H^^uFnUwDiX(NZ-wTSLuIy$uLG|PD(ZwC zTB{|2{F|PfmeqGRgljP+*i*ZO;r?kkpPyC}e-YU+(!K94EsKma9`f2|)hsurrBMp4 z=+#bN@4H=|*1G>oRE(14K;k^I*hiCdqG%|*(yWhsZ^_p=`cCqGSE|qEc3H|%7j|>+ z`Ep3-Ugz8pv$Wnk5IQd6QRqal|ND7hd$Fs1Km)H&D4o?_U{jT?|Ht|D_EHOz26Ae% zoNA9)B0+-nMz!m`BCMF;kpJeI&Be~$xJIolfr3-)%8%@}Z~jepijE`mY=sb4x9u%| zubj+UW87~?1UNVcj8yBS~^rkGeCoT4(UqxiI*X4*VgSDvc;MoG3tW@G$b5y6WgJ^5i{ za??ecZC2A=m$6XdCNPZ`>kcgFXgtw%-qrg-zOgQ?E3XBe-YKCGO$=?_T|!2;QD*#W z0@k+@l_o|DWeEwvI!E&zO|@+*h6_Hc2#7ZQ?ZoS0DS1v&RCuJy7s3@Ql zo*^K?jZA%NRlcn-qwaWo=KY8n~K1cflhnKUM2o zWXIZiHuinNec~UQTdn@_she>iXNNTJ<`A8!v&Kq%)OT`l)_J~1el<|aya5is9u@8D z)9}D@*?JXP%PA^0m-T|Zz08O+d(FXmqI*7X+jZdb!B-NoHM!qZ2ynn|2FA_18r`}$lbi+UQ! z<$GtvaoKXJn4j|40@5K3Ifz!tYpl71R*yv~@7&D7HD1sOQc^W?&zN1#x{^5pr)wkd z^8?ZC$wkk$r=d|8PK2(Hs6g>4-n)rq_D$$-NO%|taRf^&;wisdEbec|*m|zn^oP)v zp?E&*pYzRaS}OgBI1sT_nTuls06<}0OBki;!T?qbh=U~{qa2|L&C~}S>**=w>8Ys? zkAR`QP3(NycepTjr`gqG+>Y7B8;`<}UCW0(gB^Jg_4YON?5G5VPAR({qot;n>cS1V zn!;iTKF18y24Y_yp2(rJs2wO3KV#`kGd{<7)H|ybS_cid67LW7gN*y~h0h_gcTlv^ z*-9|q%dNq7;Ex2PM0|nqta|<1djAH?s@sdyL~IGL~Xha-Gm) z`@NG4(E7(s0k!|#3$V{DX}{;%qE(j=@=mFS>?-&k!-}iMIn^u}(s*-GP=Q!@bK0Eo z4^k&~&3jIP)?Ojwq{$}UHHqn<3VlR2D6?1hruwD&4`-RMv5i@AtJc%l58iMw708;m z28>??@tWy0!RY`o=dN$l+7w9&L@3fMG-Rv$%f>!@lMRpRJcDNsnFI<2@ob9!pOw#Z zoaT8`n82sLWO9}YqdeKs31M3_0D?N9z$e_P)yR=P`YUb&mz`#XP=%jc5>&t6DpOUq zx<1(NwAVGs>$S;U8}{Rf)iP%k-K^mwDcwXVm#+6@wM*w7>}|SZ$2^jyVt+#Z^;2Dj z!|u4`b*=R`8}mXLX^r5h&j5%$^3hOZXoHTaZ$*~)e(}nwVMOZdEK^3%r0ci8jrdPJ zU?*x%;W4MKfy3hJyO+boEIe)?AVBQ4(YNz{7g<`7xtp<5ttT zKHd6nS^vy3mDSOgv*KlGm@xmB`74{`)hl~9b1FW6@A}%WH2vNO>HmMus?N(-{NptaesC#&@B5?oe4CxJ zBR)L(?6Ud4MTF>r+fz)B|L);>TXFwrn@zRU^^6m<*q$X#D2!_RTcC4%lMXvW!WD%B zewG$1rlzldU#|0aWp#gMoo=7`7V-U+!mlr<_6aI5Bu0KaJSq2tArEk3?BVmcRLA}a zVgC-B|GD-4a7Ra~uw_5b<%`OUVx*?m{l7#L&@Z;(0A(Ym*f zfA*c9p~{c{ls~&`R?a0=TTv!{Th`q$ zEzqpspBuwwxrJ?qcU8{5`elQF$NZyD+I4RSu6+`4XqlUW#=iXf+rIv|dOWHxCjS4m z1Iu!)ci)t@sg`(pr@FL&_p;FH_nuj-w>K}Iy{+K=$5?L0O{e(xOCL8_qqlp(`<|!I ztNOoYmL1)^?B#9o{JFDyw+MW+@6jy1e(r_unTY{QR(>(f zRn^1y`5!aE2JUsCr6)ge>aR1owY!jW{f2+X^7iU3QI31syj@eFpu4T*e#d!tx0431 z%6y$Ado#|R>|T3@@sZ#D2QkyGvS>u5O=eJv+?wKb<3wv+x_QK^M^o73_UB1(C0T4p z3)p@#Hvi36!*JCjUaYUpd<0))ov5o2Gvqm}$ked0Hre~*KR(^4FHtq0F3iefR@-Wk zbNzzPkNw}?#hZ3%a6S02vwTg^jqH5gm&u6>mpZES-soD8psaKwqC;OHDLYv?DL-93 z;wfVd>+6OI)qO|Lq?J!jSUB}lZD_=^_j7OFPb-^z^JnPN?N85bi01!xZ_%Px7TL3= z&GroITXSvsy=n86qvroQ)^o8ce%iF;HOqQe*qod7>q=BgU)0$h6K8K+Q(V_~^qbK0 ze5uZu+%ua#rIt>OyjqnXI8*fEvX$;D04twlRBO(cQbe&eb(F&E?Cz?QAJq zMVH6TpB}p9o|5)8U#zTQesR(owp`mcy3hFc zZ@adyP|fA)i5TDgIj?HuQr7l6yw+V6b>zgH_VRh9DYKW!ZI$~8+*Uq0^T+by!~fsB z`0(}K;=}s!_hZ)-|BKwEbn8c5^7nV2&);7cpY`zPo4wLME^9x%b+h)*qiYxEw&x$) zsrvKhR7AnN;SR$IUIlZ8 uB4#)R6aw+U6j(tKGhE$JRsQFg{;eG6nSXxl=L8<~!{F)a=d#Wzp$Py#te_GA literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/dsize.png b/doc/sphinx/payload-keywords/dsize.png new file mode 100644 index 0000000000000000000000000000000000000000..5973f9d2a8f509b148cb06c55146a6a3f9d1d8d6 GIT binary patch literal 31300 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/isdataat1.png b/doc/sphinx/payload-keywords/isdataat1.png new file mode 100644 index 0000000000000000000000000000000000000000..61606f0a4776eb979577537706f3021728ef2d91 GIT binary patch literal 18472 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

~f5eV=*-(8pfBYXLU`CrB$#B!IY)@umT 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/replace1.png b/doc/sphinx/payload-keywords/replace1.png new file mode 100644 index 0000000000000000000000000000000000000000..69da275fa526450313fa996f0e503806a6efc711 GIT binary patch literal 7628 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 Zth(mmIA49rKPG#Cw77y;g^1zL{{u1m-@*U@ literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/within1.png b/doc/sphinx/payload-keywords/within1.png new file mode 100644 index 0000000000000000000000000000000000000000..0c816f9675836f204138aeeb5e6ceeb69f1600d8 GIT binary patch literal 18170 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/within2.png b/doc/sphinx/payload-keywords/within2.png new file mode 100644 index 0000000000000000000000000000000000000000..c60857daf018e435ac5891c86aaf99152f864c5d GIT binary patch literal 25136 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords/within_distance.png b/doc/sphinx/payload-keywords/within_distance.png new file mode 100644 index 0000000000000000000000000000000000000000..7d74b25872861c07aa974b58dc6cd2a0e243b3f0 GIT binary patch literal 14888 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õYIXTpi(S7SNY)v{)>!JlY`SwW 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 Date: Wed, 2 Dec 2015 07:12:02 -0600 Subject: [PATCH 1762/2553] doc: fast-pattern --- doc/sphinx/fast-pattern-explained.rst | 186 +++++++++++++++++++++++ doc/sphinx/fast-pattern.rst | 61 +++++++- doc/sphinx/fast-pattern/fast_pattern.png | Bin 0 -> 11808 bytes 3 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 doc/sphinx/fast-pattern-explained.rst create mode 100644 doc/sphinx/fast-pattern/fast_pattern.png diff --git a/doc/sphinx/fast-pattern-explained.rst b/doc/sphinx/fast-pattern-explained.rst new file mode 100644 index 000000000000..86654e59542a --- /dev/null +++ b/doc/sphinx/fast-pattern-explained.rst @@ -0,0 +1,186 @@ +Suricata Fast Pattern Determination Explained +============================================= + +If the 'fast_pattern' keyword is explicitly set in a rule, Suricata +will use that as the fast pattern match. The 'fast_pattern' keyword +can only be set once per rule. If 'fast_pattern' is not set, Suricata +automatically determines the content to use as the fast pattern match. + +The following explains the logic Suricata uses to automatically +determine the fast pattern match to use. + +Be aware that if there are positive (i.e. non-negated) content +matches, then negated content matches are ignored for fast pattern +determination. Otherwise, negated content matches are considered. + +Suricata 1.1.x - 1.4.x +---------------------- + +#. The longest (in terms of character/byte length) content match is + used as the fast pattern match. + +#. If multiple content matches qualify for the longest length, the one + with the highest character/byte diversity score ("Pattern + Strength") is used as the fast pattern match. See :ref:`Appendix C + ` for details on the algorithm + used to determine Pattern Strength. + +#. If multiple content matches qualify for the longest length and have + the same highest Pattern Strength, the buffer that has the *lower + "list_id"* is used as the fast pattern match. See :ref:`Appendix A + ` for the list_id of each + buffers/list. + +#. If multiple content matches qualify for the longest length and have + the same highest Pattern Strength, and have the same list_id + (i.e. are looking in the same buffer), then the one that comes + first (from left-to-right) in the rule is used as the fast pattern + match. + +It is worth noting that for content matches that have the same length +and Pattern Strength, regular 'content' matches take precedence over +matches that use the 'http_*' buffers. + +Suricata 2.0.x +-------------- + +#. Suricata first identifies all content matches that have the highest + "priority" that are used in the signature. The priority is based + off of the buffer being matched on and generally 'http_*' buffers + have a higher priority (lower number is higher priority). See + :ref:`Appendix B ` for details + on which buffers have what priority. +#. Within the content matches identified in step 1 (the highest + priority content matches), the longest (in terms of character/byte + length) content match is used as the fast pattern match. +#. If multiple content matches have the same highest priority and + qualify for the longest length, the one with the highest + character/byte diversity score ("Pattern Strength") is used as the + fast pattern match. See :ref:`Appendix C + ` for details on the algorithm + used to determine Pattern Strength. +#. If multiple content matches have the same highest priority, qualify + for the longest length, and the same highest Pattern Strength, the + buffer ("list_id") that was *registered last* is used as the fast + pattern match. See :ref:`Appendix B + ` for the registration order of + the different buffers/lists. +#. If multiple content matches have the same highest priority, qualify + for the longest length, the same highest Pattern Strength, and have + the same list_id (i.e. are looking in the same buffer), then the + one that comes first (from left-to-right) in the rule is used as + the fast pattern match. + +It is worth noting that for content matches that have the same +priority, length, and Pattern Strength, 'http_stat_msg', +'http_stat_code', and 'http_method' take precedence over regular +'content' matches. + +Appendices +---------- + +.. _fast-pattern-explained-appendix-a: + +Appendix A - Buffers, list_id values, and Registration Order for Suricata 1.3.4 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This should be pretty much the same for Suricata 1.1.x - 1.4.x. + +======= ============================== ======================== ================== +list_id Content Modifier Keyword Buffer Name Registration Order +======= ============================== ======================== ================== +1 (regular content match) DETECT_SM_LIST_PMATCH 1 (first) +2 http_uri DETECT_SM_LIST_UMATCH 2 +6 http_client_body DETECT_SM_LIST_HCBDMATCH 3 +7 http_server_body DETECT_SM_LIST_HSBDMATCH 4 +8 http_header DETECT_SM_LIST_HHDMATCH 5 +9 http_raw_header DETECT_SM_LIST_HRHDMATCH 6 +10 http_method DETECT_SM_LIST_HMDMATCH 7 +11 http_cookie DETECT_SM_LIST_HCDMATCH 8 +12 http_raw_uri DETECT_SM_LIST_HRUDMATCH 9 +13 http_stat_msg DETECT_SM_LIST_HSMDMATCH 10 +14 http_stat_code DETECT_SM_LIST_HSCDMATCH 11 +15 http_user_agent DETECT_SM_LIST_HUADMATCH 12 (last) +======= ============================== ======================== ================== + +Note: registration order doesn't matter when it comes to determining the fast pattern match for Suricata 1.3.4 but list_id value does. + +.. _fast-pattern-explained-appendix-b: + +Appendix B - Buffers, list_id values, Priorities, and Registration Order for Suricata 2.0.7 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This should be pretty much the same for Suricata 2.0.x. + +========================================== ================== ============================== ============================= ======= +Priority (lower number is higher priority) Registration Order Content Modifier Keyword Buffer Name list_id +========================================== ================== ============================== ============================= ======= +3 11 (regular content match) DETECT_SM_LIST_PMATCH 1 +3 12 http_method DETECT_SM_LIST_HMDMATCH 12 +3 13 http_stat_code DETECT_SM_LIST_HSCDMATCH 9 +3 14 http_stat_msg DETECT_SM_LIST_HSMDMATCH 8 +2 1 (first) http_client_body DETECT_SM_LIST_HCBDMATCH 4 +2 2 http_server_body DETECT_SM_LIST_HSBDMATCH 5 +2 3 http_header DETECT_SM_LIST_HHDMATCH 6 +2 4 http_raw_header DETECT_SM_LIST_HRHDMATCH 7 +2 5 http_uri DETECT_SM_LIST_UMATCH 2 +2 6 http_raw_uri DETECT_SM_LIST_HRUDMATCH 3 +2 7 http_host DETECT_SM_LIST_HHHDMATCH 10 +2 8 http_raw_host DETECT_SM_LIST_HRHHDMATCH 11 +2 9 http_cookie DETECT_SM_LIST_HCDMATCH 13 +2 10 http_user_agent DETECT_SM_LIST_HUADMATCH 14 +2 15 (last) dns_query DETECT_SM_LIST_DNSQUERY_MATCH 20 +========================================== ================== ============================== ============================= ======= + +Note: list_id value doesn't matter when it comes to determining the +fast pattern match for Suricata 2.0.7 but registration order does. + +.. _fast-pattern-explained-appendix-c: + +Appendix C - Pattern Strength Algorithm +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +From detect-engine-mpm.c. Basically the Pattern Strength "score" +starts at zero and looks at each character/byte in the passed in byte +array from left to right. If the character/byte has not been seen +before in the array, it adds 3 to the score if it is an alpha +character; else it adds 4 to the score if it is a printable character, +0x00, 0x01, or 0xFF; else it adds 6 to the score. If the +character/byte has been seen before it adds 1 to the score. The final +score is returned. + +.. code-block:: c + + /** \brief Predict a strength value for patterns + * + * Patterns with high character diversity score higher. + * Alpha chars score not so high + * Other printable + a few common codes a little higher + * Everything else highest. + * Longer patterns score better than short patters. + * + * \param pat pattern + * \param patlen length of the patternn + * + * \retval s pattern score + */ + uint32_t PatternStrength(uint8_t *pat, uint16_t patlen) { + uint8_t a[256]; + memset(&a, 0 ,sizeof(a)); + uint32_t s = 0; + uint16_t u = 0; + for (u = 0; u < patlen; u++) { + if (a[pat[u]] == 0) { + if (isalpha(pat[u])) + s += 3; + else if (isprint(pat[u]) || pat[u] == 0x00 || pat[u] == 0x01 || pat[u] == 0xFF) + s += 4; + else + s += 6; + a[pat[u]] = 1; + } else { + s++; + } + } + return s; + } diff --git a/doc/sphinx/fast-pattern.rst b/doc/sphinx/fast-pattern.rst index 17be89987977..c32b79844fd0 100644 --- a/doc/sphinx/fast-pattern.rst +++ b/doc/sphinx/fast-pattern.rst @@ -1,4 +1,63 @@ Fast Pattern ============ -Just a place holder now to demontrate linking. +.. toctree:: + + fast-pattern-explained + +Only one content of a signature will be used in the Multi Pattern +Matcher (MPM). If there are multiple contents, then Suricata uses the +'strongest' content. This means a combination of length, how varied a +content is, and what buffer it is looking in. Generally, the longer +and more varied the better. For full details on how Suricata +determines the fast pattern match, see :doc:`fast-pattern-explained`. + +Sometimes a signature writer concludes he wants Suricata to use +another content than it does by default. + +For instance:: + + User-agent: Mozilla/5.0 Badness; + + content:”User-Agent|3A|”; + content:”Badness”; distance:0; + +In this example you see the first content is longer and more varied +than the second one, so you know Suricata will use this content for +the MPM. Because 'User-Agent:' will be a match very often, and +'Badness' appears less often in network traffic, you can make Suricata +use the second content by using 'fast_pattern'. + +:: + + content:”User-Agent|3A|”; + content:”Badness”; distance:0; fast_pattern; + +The keyword fast_pattern modifies the content previous to it. + +.. image:: fast-pattern/fast_pattern.png + +Fast-pattern can also be combined with all previous mentioned +keywords, and all mentioned HTTP-modifiers. + +fast_pattern:only +----------------- + +Sometimes a signature contains only one content. In that case it is +not necessary Suricata will check it any further after a match has +been found in MPM. If there is only one content, the whole signature +matches. Suricata notices this automatically. In some signatures this +is still indicated with 'fast_pattern:only;'. Although Suricata does +not need fast_pattern:only, it does support it. + +Fast_pattern: 'chop' +-------------------- + +If you do not want the MPM to use the whole content, you can use +fast_pattern 'chop'. + +For example:: + + content: “aaaaaaaaabc”; fast_pattern:8,4; + +This way, MPM uses only the last four characters. diff --git a/doc/sphinx/fast-pattern/fast_pattern.png b/doc/sphinx/fast-pattern/fast_pattern.png new file mode 100644 index 0000000000000000000000000000000000000000..97163a50ab0ccce1ef7f13b5df6dddb1c52d7f43 GIT binary patch literal 11808 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 Date: Wed, 2 Dec 2015 07:22:20 -0600 Subject: [PATCH 1763/2553] doc: header-keywords --- doc/sphinx/header-keywords.rst | 388 ++++++++++++++++++ doc/sphinx/header-keywords/ICMP_type_code.png | Bin 0 -> 138533 bytes doc/sphinx/header-keywords/ICMP_types.png | Bin 0 -> 47309 bytes doc/sphinx/header-keywords/Window.png | Bin 0 -> 26681 bytes doc/sphinx/header-keywords/Wireshark_ack.png | Bin 0 -> 134829 bytes doc/sphinx/header-keywords/Wireshark_seq.png | Bin 0 -> 134801 bytes doc/sphinx/header-keywords/ack.png | Bin 0 -> 25305 bytes doc/sphinx/header-keywords/fragbits.png | Bin 0 -> 42764 bytes doc/sphinx/header-keywords/fragoffset.png | Bin 0 -> 45033 bytes doc/sphinx/header-keywords/icmp_id.png | Bin 0 -> 19474 bytes doc/sphinx/header-keywords/icmp_seq.png | Bin 0 -> 21191 bytes doc/sphinx/header-keywords/icmp_type.png | Bin 0 -> 19622 bytes doc/sphinx/header-keywords/icode.png | Bin 0 -> 16627 bytes doc/sphinx/header-keywords/id.png | Bin 0 -> 55094 bytes doc/sphinx/header-keywords/ip_proto.png | Bin 0 -> 21788 bytes doc/sphinx/header-keywords/ipopts.png | Bin 0 -> 33790 bytes doc/sphinx/header-keywords/ipopts_rule.png | Bin 0 -> 18357 bytes doc/sphinx/header-keywords/sameip.png | Bin 0 -> 27181 bytes doc/sphinx/header-keywords/seq.png | Bin 0 -> 23340 bytes doc/sphinx/header-keywords/ttl.png | Bin 0 -> 26909 bytes doc/sphinx/rules.rst | 1 + 21 files changed, 389 insertions(+) create mode 100644 doc/sphinx/header-keywords.rst create mode 100644 doc/sphinx/header-keywords/ICMP_type_code.png create mode 100644 doc/sphinx/header-keywords/ICMP_types.png create mode 100644 doc/sphinx/header-keywords/Window.png create mode 100644 doc/sphinx/header-keywords/Wireshark_ack.png create mode 100644 doc/sphinx/header-keywords/Wireshark_seq.png create mode 100644 doc/sphinx/header-keywords/ack.png create mode 100644 doc/sphinx/header-keywords/fragbits.png create mode 100644 doc/sphinx/header-keywords/fragoffset.png create mode 100644 doc/sphinx/header-keywords/icmp_id.png create mode 100644 doc/sphinx/header-keywords/icmp_seq.png create mode 100644 doc/sphinx/header-keywords/icmp_type.png create mode 100644 doc/sphinx/header-keywords/icode.png create mode 100644 doc/sphinx/header-keywords/id.png create mode 100644 doc/sphinx/header-keywords/ip_proto.png create mode 100644 doc/sphinx/header-keywords/ipopts.png create mode 100644 doc/sphinx/header-keywords/ipopts_rule.png create mode 100644 doc/sphinx/header-keywords/sameip.png create mode 100644 doc/sphinx/header-keywords/seq.png create mode 100644 doc/sphinx/header-keywords/ttl.png diff --git a/doc/sphinx/header-keywords.rst b/doc/sphinx/header-keywords.rst new file mode 100644 index 000000000000..a4bc69d3051c --- /dev/null +++ b/doc/sphinx/header-keywords.rst @@ -0,0 +1,388 @@ +Header Keywords +=============== + +IP-keywords +----------- + +ttl +--- + +The ttl keyword is used to check for a specific IP time-to-live value +in the header of a packet. The format is:: + + ttl: + +For example:: + + ttl:10; + +At the end of the ttl keyword you can enter the value on which you +want to match. The Time-to-live value determines the maximal amount +of time a packet can be in the Internet-system. If this field is set +to 0, then the packet has to be destroyed. The time-to-live is based +on hop count. Each hop/router the packet passes subtracts one of the +packet TTL counter. The purpose of this mechanism is to limit the +existence of packets so that packets can not end up in infinite +routing loops. + +Example of the ttl keyword in a rule: + +.. image:: header-keywords/ttl.png + +Ipopts +------ + +With the ipopts keyword you can check if a specific ip option is +set. Ipopts has to be used at the beginning of a rule. You can only +match on one option per rule. There are several options on which can +be matched. These are: + +.. image:: header-keywords/ipopts.png + +Format of the ipopts keyword:: + + ipopts: + +For example:: + + ipopts: lsrr; + +Example of ipopts in a rule: + +.. image:: header-keywords/ipopts_rule.png + +sameip +------ + +Every packet has a source IP-address and a destination IP-address. It +can be that the source IP is the same as the destination IP. With the +sameip keyword you can check if the IP address of the source is the +same as the IP address of the destination. The format of the sameip +keyword is:: + + sameip; + +Example of sameip in a rule: + +.. image:: header-keywords/sameip.png + +ip_proto +-------- + +With the ip_proto keyword you can match on the IP protocol in the +packet-header. You can use the name or the number of the protocol. +You can match for example on the following protocols:: + + 1 ICMP Internet Control Message + 6 TCP Transmission Control Protocol + 17 UDP User Datagram + 47 GRE General Routing Encapsulation + 50 ESP Encap Security Payload for IPv6 + 51 AH Authentication Header for Ipv6 + 58 IPv6-ICMP ICMP for Ipv6 + +For the complete list of protocols and their numbers see +http://en.wikipedia.org/wiki/List_of_IP_protocol_numbers + +Example of ip_proto in a rule: + +.. image:: header-keywords/ip_proto.png + +An example of the text based version of the protocol, say IPv6 whose +code is 41 would be:: + + ip_proto:IPv6 + +No quotes are needed around the name. + +Id +-- + +With the id keyword, you can match on a specific IP ID value. The ID +identifies each packet sent by a host and increments usually with one +with each packet that is being send. The IP ID is uses as a fragment +identification number. Each packet has an IP ID, and when the packet +becomes fragmented, all fragments of this packet have the same ID. In +this way, the receiver of the packet knows which fragments belong to +the same packet. (IP ID does not take care of the order, in that case +offset is used. It clarifies the order of the fragments.) + +Format of id:: + + id:; + +Example of id in a rule: + +.. image:: header-keywords/id.png + +Geoip +----- + +The geoip keyword enables (you) to match on the source, destination or +source and destination IP addresses of network traffic, and to see to +which country it belongs. To be able to do this, Suricata uses GeoIP +API of Maxmind. + +The syntax of geoip:: + + geoip: src, RU; + geoip: both, CN, RU; + geoip: dst, CN, RU, IR; + geoip: both, US, CA, UK; + geoip: any, CN, IR; + +So, you can see you can use the following to make clear on which +direction you would like to match:: + + both: both directions have to match with the given geoip (geopip’s) + any: one of the directions have to match with the given geoip (’s). + dest: if the destination matches with the given geoip. + src: the source matches with the given geoip. + +Fragbits +-------- + +With the fragbits keyword, you can check if the fragmentation and +reserved bits are set in the IP header. The fragbits keyword should be +placed at the beginning of a rule. Fragbits is used to modify the +fragmentation mechanism. During routing of messages from one Internet +module to the other, it can occur that a packet is bigger than the +maximal packet size a network can process. In that case, a packet can +be send in fragments. This maximum of the packet size is called +Maximal Transmit Unit (MTU). + +You can match on the following bits:: + + M - More Fragments + D - Do not Fragment + R - Reserved Bit + +Matching on this bits can be more specified with the following +modifiers:: + + + match on the specified bits, plus any others + * match if any of the specified bits are set + ! match if the specified bits are not set + +Format:: + + fragbits:[*+!]<[MDR]>; + +Example of fragbits in a rule: + +.. image:: header-keywords/fragbits.png + +Fragoffset +---------- + +With the fragoffset keyword you can match on specific decimal values +of the IP fragment offset field. If you would like to check the first +fragments of a session, you have to combine fragoffset 0 with the More +Fragment option. The fragmentation offset field is convenient for +reassembly. The id is used to determine which fragments belong to +which packet and the fragmentation offset field clarifies the order of +the fragments. + +You can use the following modifiers:: + + < match if the value is smaller than the specified value + > match if the value is greater than the specified value + ! match if the specified value is not present + +Format of fragoffset:: + + fragoffset:[!|<|>]; + +Example of fragoffset in a rule: + +.. image:: header-keywords/fragoffset.png + +TCP keywords +------------ + +seq +--- + +The seq keyword can be used in a signature to check for a specific TCP +sequence number. A sequence number is a number that is generated +practically at random by both endpoints of a TCP-connection. The +client and the server both create a sequence number, which increases +with one with every byte that they send. So this sequence number is +different for both sides. This sequence number has to be acknowledged +by both sides of the connection. Through sequence numbers, TCP +handles acknowledgement, order and retransmission. Its number +increases with every data-byte the sender has send. The seq helps +keeping track of to what place in a data-stream a byte belongs. If the +SYN flag is set at 1, than the sequence number of the first byte of +the data is this number plus 1 (so, 2). + +Example:: + + seq:0; + +Example of seq in a signature: + +.. image:: header-keywords/seq.png + +Example of seq in a packet (Wireshark): + +.. image:: header-keywords/Wireshark_seq.png + + +ack +--- + +The ack is the acknowledgement of the receipt of all previous +(data)-bytes send by the other side of the TCP-connection. In most +occasions every packet of a TCP connection has an ACK flag after the +first SYN and a ack-number which increases with the receipt of every +new data-byte. The ack-keyword can be used in a signature to check +for a specific TCP acknowledgement number. + +Format of ack:: + + ack:1; + +Example of ack in a signature: + +.. image:: header-keywords/ack.png + +Example of ack in a packet (Wireshark): + +.. image:: header-keywords/Wireshark_ack.png + +Window +------ + +The window keyword is used to check for a specific TCP window size. +The TCP window size is a mechanism that has control of the +data-flow. The window is set by the receiver (receiver advertised +window size) and indicates the amount of bytes that can be +received. This amount of data has to be acknowledged by the receiver +first, before the sender can send the same amount of new data. This +mechanism is used to prevent the receiver from being overflowed by +data. The value of the window size is limited and can be 2 to 65.535 +bytes. To make more use of your bandwidth you can use a bigger +TCP-window. + +The format of the window keyword:: + + window:[!]; + +Example of window in a rule: + +.. image:: header-keywords/Window.png + +ICMP keywords +------------- + +ICMP (Internet Control Message Protocol) is a part of IP. IP at itself +is not reliable when it comes to delivering data (datagram). ICMP +gives feedback in case problems occur. It does not prevent problems +from happening, but helps in understanding what went wrong and +where. If reliability is necessary, protocols that use IP have to take +care of reliability themselves. In different situations ICMP messages +will be send. For instance when the destination is unreachable, if +there is not enough buffer-capacity to forward the data, or when a +datagram is send fragmented when it should not be, etcetera. More can +be found in the list with message-types. + +There are four important contents of a ICMP message on which can be +matched with corresponding ICMP-keywords. These are: the type, the +code, the id and the sequence of a message. + +itype +------ + +The itype keyword is for matching on a specific ICMP type (number). +ICMP has several kinds of messages and uses codes to clarify those +messages. The different messages are distinct by different names, but +more important by numeric values. For more information see the table +with message-types and codes. + +The format of the itype keyword:: + + itype:min<>max; + itype:[<|>]; + +Example +This example looks for an ICMP type greater than 10:: + + itype:>10; + +Example of the itype keyword in a signature: + +.. image:: header-keywords/icmp_type.png + +icode +------ + +With the icode keyword you can match on a specific ICMP code. The +code of a ICMP message clarifies the message. Together with the +ICMP-type it indicates with what kind of problem you are dealing with. +A code has a different purpose with every ICMP-type. + +The format of the icode keyword:: + + icode:min<>max; + icode:[<|>]; + +Example: +This example looks for an ICMP code greater than 5:: + + icode:>5; + +Example of the icode keyword in a rule: + +.. image:: header-keywords/icode.png + +icmp_id +-------- + +With the icmp_id keyword you can match on specific ICMP id-values. +Every ICMP-packet gets an id when it is being send. At the moment the +receiver has received the packet, it will send a reply using the same +id so the sender will recognize it and connects it with the correct +ICMP-request. + +Format of the icmp_id keyword:: + + icmp_id:; + +Example: +This example looks for an ICMP ID of 0:: + + icmp_id:0; + +Example of the icmp_id keyword in a rule: + +.. image:: header-keywords/icmp_id.png + +icmp_seq +--------- + +You can use the icmp_seq keyword to check for a ICMP sequence number. +ICMP messages all have sequence numbers. This can be useful (together +with the id) for checking which reply message belongs to which request +message. + +Format of the icmp_seq keyword:: + + icmp_seq:; + +Example: +This example looks for an ICMP Sequence of 0:: + + icmp_seq:0; + +Example of icmp_seq in a rule: + +.. image:: header-keywords/icmp_seq.png + +Message types and numbers: + +.. image:: header-keywords/ICMP_types.png + +Meaning of type-numbers en codes combined: + +.. image:: header-keywords/ICMP_type_code.png diff --git a/doc/sphinx/header-keywords/ICMP_type_code.png b/doc/sphinx/header-keywords/ICMP_type_code.png new file mode 100644 index 0000000000000000000000000000000000000000..e14239e84e3e3f1968a91c7c3ef83421177c13b8 GIT binary patch literal 138533 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


Hrh^XqR{=G?)ymLb#g}OC{Z*JD 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�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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/header-keywords/ICMP_types.png b/doc/sphinx/header-keywords/ICMP_types.png new file mode 100644 index 0000000000000000000000000000000000000000..a1589d8d89ef6bfde5e519b80efd4b5a24e975df GIT binary patch literal 47309 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 E14Tth-~a#s literal 0 HcmV?d00001 diff --git a/doc/sphinx/header-keywords/Wireshark_ack.png b/doc/sphinx/header-keywords/Wireshark_ack.png new file mode 100644 index 0000000000000000000000000000000000000000..d90156b29f2e65ebf6d5f080e8cd9b02807a21da GIT binary patch literal 134829 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 z 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%0DUAmQf&6{aNP+_rD0DyI7VfQTQ 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

JreA3 zPcsenjKVYV?+z!05%ATMEPxVGpiR8b8A(?ydI_2E3MPT~Cpo;RC=mJG^RpqAsr(Q{ z02M}HYVlJc7NiH>U*FR2y%65vykJameeo6TGB=;j3;A8nk`26CRt<3w5-c|ZP2m0C zoB3ocx|Ki!8SdKBKhqa&)Quxq2Sja36iG4zdiEpFNQe2_kMwgFoaWvyuOJF8QP%Cr zv*Pu~Z4PJ7S!mh_4vM_H zh0wzEG_5GU`B>?q3Qcf-a6%R1v3p6(*_!80*cTg73iRAKPlKDCMs4l`p>Kq%b$oh( zt8QO(IE{+muX^-!x$L*xIVbE_s~r3=X@7P4nptM_=rII~xaz&7T=Ue+P}{9;o4s8U(IB3F0$b&1WQ*Hf zl{ppG+MCG<_*67ZskrO;Rc0i zZ~xvN6cJGwLQD4HrzhG_vx`h^(ZP3Bfmiu{GoessR+X^l*>Ji?8~T?iya(>Z$92^O zmgbho2p2QD@w8Qb%G#ZQFF0odre|9%Pc`HAqO0bd$NsD?=Jqbn2>*0EWsWbr;cZj& ztD#JWZp!UlYrX$dv`k^dQo*|iIO~pV7#F*G z8Z=7))ce)@gCIQgT5Gp#Dgr_;&C~8H&sSNd@kM3o(a-GB-aPQbE znJ%Xh_-V&;^ndhOe_tih7b0Vs;@5|l79$i_&F9Foj z(m)k%MpPI-y6}CGjCs_SMzKOZ1{>R=xQr@x8tX|q`keL_8(lv^PfoH^K{&Z(^`FM4 zUtRK;hsvyN!v&2R!7HXoT?0$ybBNO#yQB89E1Ke$$yIxX_lT zyVwF7%bjm9Ia}>O9#TP2{}(}b<2}a?=|Xu6J|z^4MM7}($CTecEp2)bt=2cRB2wqX zA}UH_<)cLi!J3ILUom^TDC?Q?xKuQin`J*LX^Icb!5u)wu~ye)`962%L^VE+esX+c zEB7m*h@7?4R$V){>rN_B^#|fc0jV?FL1BgzEq&9+Nll<5P#U!Gn$uH;hwIi;$17Mt z%jabpFI*~L+9`jA!RX^|dN+ziFvtSBApFMTIGL2i&{q7jys=E>wZ`Xula#z6U1FX# ze528EA+{tMNlPQ%ot^p5&?d3(x+cv6yjA8TR}!eV-tC?dhjtXgW+VYf2n#5WDd1oj zR)nh8$;xb|TS=jS$7p53vb=J&#mw)^HFa}dPope##e#SktUbIbxvo{|Ws9*VBFh&m zP0D9W8LTrnoX2jFPYzUQT!^*Y6Q!-1dXjRJNvClQf!Y=GXn_ni;6p9oonz27KP`Ot z36UO;^TGYT5itFp7Q0M%tCoFEd>)~>{BZ5`6i?zr<$LDxOKPP8%`WorpwTzl&bFka zfKFW+aml4C)!aBl3Q2kab0yWU-YT@uWtK9>Fwseb&0?s+XSGAKc9sTLGVuN#nJZ1X z2o+2(3a6$8VnxCG`vd!M#Bz57(9uiQHqGLdb-_s=6HBq)oa|BC2Wo3Stf)|i)56!d znWG4P4cga@*(zeQ=Vfm_`MuQd=knxqpEv>(KFm+jHENH*qUtf1!D38b1B5aTvw#^R z_DCx}r`H*)W_o%p1M%$1G!fwwcJAax7Jo3$Oj-I`k zI*CQb$>sJK5kUYTcOT({WMCb7F=b)Q>usfp%Yepkpo6$I@(`oXVtm#EY`o+N&j)!tq zI9lH`OIWkBGspBSXrifgNOn zwT!zMLM+ZC;7;&{*L@vqhRePK$_!(&!FZQtBwICYQaT$)U&XTF0>O68edt}6?t)LS zFT7SB?f4DRjHz~uxm}pwGu&rs(UNhwa#%^vm(I)@_2x=hEBJme>>xN^QV^q^HWsN^-PkH@H@7ZFv0wx~l!+A){bS(?T#!#K0*`+p zi6|fqF17n>E2NX;cr2R3knj8&rurEZW+i^MpeDjp16Sny^_m==i#ga3exlCt?ARa& z8pm?!C|dnNr_RFrkJP;osLJ-LBmFpiaM+!#(oQ$=Xz{&rq>Z@tK>jr-5RO3(Ssr6^ z!H1V{ycl5P`}b?XNB(l&fb_rTX?F6rjP(qa^)}jb`l3q_MOBsSdZ};7!RX%~y3U<5 zQjOJlz6yP^-2=A=z-IjZ2}5q>;5hi(7Xd_Z!dSA;!+TZ5{HDnhvhm1DLnt7Dm%hR_ z6fV4J91sv1=Rn|scsfDCiW5u*aCkA8zML8+GS{#jy-0Z9PNcHqQf>Cq=J+Of&UthY zo3kM%dn@UkIqfQ8(Lc(nLM4SX{e@1V@ZK7(%*oBOcSporN^ztOoPNj}3~c`5AL~Hy zGBpA>s7lxD-1dZ_c*T>)ONmeu(*Er9*wC3MxUhwf z{x&b6A z;6wq(f_(q+)bJ%kgcT+NW)$Q=0a9XRyE0L9&}jZ^Qre{ zsFZv~-HdRm;87v9wW4`FPC1;&)iF{?jjJ+ve+FocHkYn;M6{_At24VSSsCwV3^rSw zxa$pu)vA(#dTSrIZg&Wm|25de<-( zfu*n^x%d0sa&^f0kI3}F0ekHt%iU{ZW(#+UXp?JTZet}e#Y@CH5edBMw*SZzUPj@q zj#8Q%Z48g6J4TWUT|yXE2kL)QSnlxO6eeDn8Rc(~_qeM_r*gQN@~a_20TP>{OigUY z*sFhvTHfjj2Udf}=Euwb`mEIvczTLiX(cyCOL@Skv%=Hx!HJC9-(`@uTAqm^Js52N zI-l;YIm|G(2Sm!bIvO6)OH|)h>|NI5X}B~`RVCg@otEti`l-|IFW&4Kvlm)fo5zV4 zAg6nzM)qdW6^l~WC~b^D%)1oyYWL@qtv9GMaLZk-fx+J?<$OLnR9ZfYxVkwvNvIfV zQ8pJcVkZ|v#g#K|kzbzxIkb{8SXK^yYs7zB?#`SHk46;9t(SfR!02WrD=4ncuq!$f zvzpFSMXAM=Koin_(^H1}ouJ)`&+H(J;uz5syq&s zBiPQ{SQV(LsjjcDXJa$O(b9~ib~S*ODGG|>Ey#GT5U5a$;B=TBfJUS&?;zE=yZN1P z%r#ziTr_p%ey`*eaSM8+23i}yR~BpRSKk}{I+{E?w#eCnBSPMt(}rN zcc50+3i2xvLcj2ip#kJg2d4nwLk0ABWgFTZs5ukGblRieLzmUnZeb2_y>qt5G&%g= z8!Su$&p6#t@81rqIYyqS0a&^@nXrRGLZbY!Ziw~s#QV}U>C7F2r&F`+Abam}E3vZ>yfx#Kb6|AT+;|7kXfyfBBNZ>$qU-^rpgW{o?k6 zpZC6qq5$K$NEHNj5Up0^m5P` z-fZhlenql>dL)3Mv%?KrtOT06cNw8g_++G_2a!bn(639e@Dp?P_DC9OvdjPO)~qij&XqDgEl&@BU*KF&=JBj<~nQ zaoj&XHw&gLt4XP}l@4W8cRx8B+$*MrK%jj0vnXo1ed3b}(tmB-S8`>2w4cPVe_73o zFD^Jpke9Dvx{;DM+wb(xW-PTNuzY4INJv_tJuw(Hy=#23uCla1+xc58$>nop5H{oK zIG6t^SnahB5k=}r)1ZCC&an@N7)gyUg1gpHt}QuHKu5tp%hhm^H|c*};U*D=huy<{j^+ik|itfHw9;UDBK5jpkP1r9cqaFz%KFpXESqU+XNqP2oCb*&vsQ?H?H?ilL~Eg z&8j0pzpqcv->&mv)25x6%9p=S4 zErQlBh&B}y_1e8wO%;dFDvH**G&X5JETlq?vXl)c&YK<^X`ae<kXMa@B2~v;7)8ekWzK?Yh`|Q|MM~QzTC)*F!JkzW%6l61$RAvSI zeWCT)%NYBTVSPQMb5H-?@zX~@v_ikBaUT1HaxMs!q z-q0y2%Dy0{qOywt%}TW#BI*O-WjIz=QM3aT-mceH%tTn8m+LY`zJnxJTXryPE!Dt+ zp8*c%99AXtHFRezS`WyXoA}c3Wz2==<4Pf};%kjhvIVT(9}VxlMG>bbcUs@3X(moP z*}YEoNLa02kCo6{8S&X2VsTB3`VaVHZx5rybHq8F?^CyQf2-cw3-x*99;0H`_od7{ zGlV~X{x~%(`!x(K?0P||qH z;pm5RdwACSYIy_gSMx7$d|5W9mx-n&!b|gOAEXm_4$^5VU@Mdm{SNd(U-oP*(c@cb z%0^TFbz7dd9@cN&K^Y6|21hkKfBI@L)slJ~X7vg1Tcy-T8KF1|=_5)rr;kKgf8$4P zixxn*u%%Y7s9vyXQbkT_I7dq!X%ntp4zC2%k+7MJY6&$*QFa{Xcf~<1v$W3_rXU&^ z|3l+>sceBEGv8E6MDP#ucwuJKQg$dYn01wOLSf#Q>*};&0S;LBR7h2wsHxn6*22lW*VL8No{m;?E}Y= zOx1Y)$go`NH2RI@){S`LP}U~>amSx9wk%}!=fGjX$>-%-?20H$LXGteIH|rLvfCh? zhm(l!1*NWwk|g>G;5E7587PvT*_p~{Q=VtgjlI|NmiI=0%RES2V(U_AM5 z??%k3s`i>|V^o6vFfu7d7nU)UWC|ep^JeoDYTsvtQK&}-G~9m4xL*0U8S^<+Uk*=^ z9%^L3+WHs`0aCadug z<>$C`LDKkP42org(Hd0caF!u>0n|!a+Y%=nw&9Q<#mEG_sG`gRW;S^)~3 z@ye1CrhA-AM!Ii+rHCP=g9mz@_Q#lAH(UIr{iX0u(5vhC%AbJ6XGu&=Gbe=Khtl^K zSp7Ye6?_g`Q!Od~dUIWa9Z7JIi?xHt(yth?DYA3Ue4xc7lqn+vt1E^y(Ewe2)BX{F zV4!z}Ja|Hm4U<>5i7ux&w^SsTmAWWQUPF`KVs1v9E+a*fH1?;*RC+((`-W@vx4kbb z+@i)2D{j{ql@kHldm1V-CLvMnZO)KPi=g{Xg3j4@ft)lv1+?GQ_UNOx@mRA#oKvCf zuH*&r#4clwf1v>KacVKw?iOiz`l4yo@u%BSxV4``5v)JQ{}Suh@|iJzj$48Ykt-VY z4pu7|KHt;-Y75~qGZ!~#%V?x6%EYH1?O?}1Vg^{a+0+1-Zfr=^G=-NFV1V3% zQ1D?;^#;+Qih=S>@{Y2Zk84#R`c8oJp=_J`-)9%{?}C3K14s^if7WMP6Vth?(93#z z(De8AFZa)r?_879PLwFBKjUmYHQw_nJVw7428jO?N^RV~TAEvudA+;sKp-?F!sRoH9?<%I z|1i+MaD;Mf-9O6GI1a116gWEjwod12tkMruk+Hh~J2f=UeuPUp+_F9mi@PXPAFreR zh3-Q5j>~qm;;J7bE#D%n6c>_`<{iPr4xbo`R|_9t!lX2|OvvPt598XUh4%^2MT;}( zEnGKl#7fmQx~RHn2)eL)qCTEQF<3D$?oc(v;S6%oE|FeYqZUNX*UL7M_4tB{RrdC7 zQnC>swyF84Qlmr_@d*mE2WL6$38X!xm??I~7boz{QY}Iy`OE!i)-xV2TrpaAkDV@ z-Y)^IGg^==Z#{nzgswTILKXKpQb1-LwGa&eq0G8`Bz-%C2;p7R_Vo$J>q-1U?xBE) z6=$y~e!l;hBUO(1b7i18KPX4l?82N`8K5Qzfl*86pnlF;D0OnT+E`T&`seuF-~07q z{Ykb1yFRy;D2@Mp-O5AI-HK09gO{Oi4=d!c_G=)m1b)R9?hbfIm81o*4z`KY)W zW%_#vT6KU{aWYdv;Z%<;CgN|1+O}cd zo0q+C%}`lRDz#e^F<$n(rDu zV^`F|M7x+=%>=l~!EG{>1$=l0)_5BnM^xkiSDh^$onS2in;3MM_BRV%%$%h6rSYd- z4GIeadP7=_zh7h$Ze)f@m>)6~c1FJ|{)!2QZ-zfe+ES!}EYsc09{6pnVIH&ep#PQz zUtXj=Y6GfCZjPDpS#DGS?2<7@(jYI+OUcra6^(Jem;kW~4L*H3evO+fS9+E#y2+7C z2{`z^CCNs*zp0(T=MehbZ6U~C_w(#?bbUqWI?lKY9(P|D2CGE@-9`8M<5-535YBTE z0?0ZnbcNbXzVdweN;MD(o*3MqNvE2HZ(hI_WDZhS7)hq z`D;^nU`_6RqwV+R?CK7QYZ@Uo6%{)EVCW1{RgJgRAzP-#!lzlQPny2!R#cuw%)jMP z9v;YhzX-?xB96X4r~BGph;+I73AXsiyK`_;cqeqG!s^k2R9;0 zQ{(-paS6P7`76QG;^>e#`bftXsEV~ z(NCmk`kXz7lP5#YfPQP=3>c6_c_sD;D-ss8NEfyiu#4h#Ks57rVb2i~9zvI0g*03F zXi-cZD=Ygb8+^QM#bjIiEvA#PSY89SfO&xn0Z9J)w@_jDM1fDK`vamr;R)0Czfc23 zNw*!-z9S%~Nyx3Yo^lq5{Uv;Rki&~?%kiU&D_w8A))OpBayrHnCSw9x2)}=@F&&}2 zE53HC4$#TTjCFN5)S7mOlfVe*p%p0l<<2GCIp@ zE|*hn%-DX%yF94+X!MWwrg7+0lKrJLy=&R^cT4ll97k*9*ij?5OXar{aus+EPE4Bv zBvA7EYRRX1oeZUubAAjbz*1CNAGIV>Wn$NLrsOiyY#lF~j6M|G16c2hzV>4$Vh;XD zasSW>@4m});&%Ml%UAnSePU~GpUv51F&_T9T`@a=&5D=M(Z7*_%>R;mx!+w(E+GR0 z(ynD?&Lgqf*~TQR@BTbPF;LNxq31^CxRt?^BRj$EbaY;*al1<5*n?_AvS*({r8ou+9SsKMw}LL75valuI!TZM@!CM~T~@iZB!NP*;?5 z)w?ebe+Q|qx9RID|IfVOBTvG~>@=vHj5f(ok?*%rTUAmrPK}&!5_~Os-nwsYCMXF@ zb9*02T#i>|s|R)mTJ4=+Gqffv$j4+oP)(3&ySVQ~Se2OIHb#M36<*Zlb$Zz(Wo_=x zRnY8UKfsIMQP&1rjbtg`{Zt`@h36LU@<=+mF}2ony!(oOcc8;Z4dQ`fc>nZjv4VYRe$zwm@@5_1Y9XdZu zq}$wLYMZR34fxB>v1K1TCakQW{{fC8_Ec|N=bCj|B5*pXOQ3@Yyf|nRG(!Q_K!?XC zE2dM!b@Oh@%fl@0AcTd3{ScSP1gE0E@$!$A7eJ;G%`AR3>3ClWX$2Tr*&pk zEj&j_noRZDA4$qy9`C$GS{V)wei^j!b~^ecHdsD7fz$A-F#N_&sS7^x^76{f;J}Sj zN~1QHvDEYKTMH5{HUUAtSAy!O8>@v%0F24k6dX8!EKO5J4|+JhB(T>E1?610L{b)g z+grv5pQZp4BW(N)&h=tOW8aaPZetdt;9)#u)!9rty)H^0zY2rX-5}Xd}|(X zK>e8`fVQ%^cg+@vBJOni&=1>A&{(lOHSB!5?ArHtL<=nn~&|w^W#U zzY$s1U5xbAz0tg;7U`C zXrOFMovADIsP6aJe-vc+s=Z_L$>OYCi90Ykyr{JvzJ}v{vFlt8Y^xZ36&iUpuBF&C zs~Yv1%4TL2%T*qXwuXunGoSu$@L<(HO^s`y2O!zv2H~Py{v{$z*Vc&JHoMbo^&!nz z%isb3&;xr}UJ^DOE+gpuSvK=Fd$5f%+#(GHa(a?KbbcmXN?o3zZuU7f8iG#zU1hAw)Q<|@#ao2H>USS?UjWZ?DD_GY3$u2kTLpMCm4h%PIFN6ol&oBFPd7Tbi%Ev4G@d90bxW&_*wyKZ`zM}TV@ zR~No0gfrE#Fy}uL;ezMvbvymF_@8Xvw7K(_eJ>tUp4{%p5^Db#tcrCaY`$InTioA` z33N1wd3lk$Jm_%E?Y0ELCBG+DFlr+T<20Cm0;Z-k@KLO_a2p*fb33#jU%rDwRAF^E-K6X|VGIoLTK#GprSFnSL@`{B8g#IE zTkpSYVPPg^Pi6U3I#dAO``zu;Ho=xP!{ILFx7A z^Y<2u@Q8LMQ(PH}dgH^-Uu$IgCI~lNkMQoj#gr%s0bMoh0)T8K8Zwi#LGD1VH}{e2 z3!T-hdC}aoW+eRSX>hHaULz|A3lL~4{Fyp52x27|2p7cM6EXkk>hhCfKY#8H!fn|) zJe`IPiNcZ0O^JVB8{>o;gh1ky@KA$apaA|PeD5bxQXP6#cUkZOiFI#uy*7=FyMyDT z)QGc7$m#VamQ-I1g$H65q)L@(ozM{gIFV29iBbPVvbJirm4`zdnLJ*QAYi>qK33q~ zqJYLDYv-%_>1fnCQRX_K(${yz%#U*UqeC%lJs!`p?EKyCH#Jr%Q9?#$s`f#S3cIa)!@J({SWim&1yd%O;s-Qdl8R^As!FV0?S-GD>Fe4qw&DSOzrdA55u=N zj{Lsco)@*Ol{-RF<_iiR9~N@{lVk96rm9EfqX;etT%LNq=fsfyXKT8d&d=)Dva|q! zGr2eR*cU}~`F+7Z-Ry}XnH^4dWqC^@|{9LeCuxQtApvjH1>RKuBXJe#hJ-AYF z0n@C2!*O)+!V7b$pBNzT_GYi)VxS2utZX+BR^s?x^e;UF;&1)6+DlL6LI#zWRj3^& zzZ7WPS-bz?Z7hFWo{h6R9R_Ryqt8{a&6L%V?F~tzb)J^lv; z=`HwX6OXbP6OT&dX7z0uWx4!!$SOta+IZf2QUDpDk*hMsU-Pg9hDp3>5O-$fxt1=31iH0~j@NrRPln#SD|AGJDVBYLm|7QLr%lr$V&VNZI_D=H;MIg!H$)&?rG!j_2r+vyINbw2wUqi7r z%Q@j9Qks7Db8JViod6Cq4z;(mGFfd8{*pEDXa}fpxqmcs<9jk9 zq`>z){OCgWO!52~Ui~?byh7}}u&d6a5+j%B(XL5yMk?6gv8}_$qcRN+ejjHp>t?@x zA;)d$5`Z9jvOV$VrSOOSoHM_tQhSGM;O_eHht3RQUiNg3H?O$na&Mp5z*kvG+kn{C zN|BSE8~EkLK^l&|3UG`DG}I}Y$?RLm@Pv9I?>|HVP;-yfd<4--eBk`;=R$ z&_bRgx-Q>1NF@2n2=3=_#bUJj!e%rqT=3;lfwvt@ydz>`lIVh%{p1*ur3U z!->3)PikNOY&w%p2@b_n?+?1XO_quXlI@nbwI0WYhwM=DRwkSQUhV0z)6{jNp0#o$ z(?Sw@wx^OOmv&$6sl`z!k)NYcL@w@};E<0^DpVeVBPT7oQc-B%5a@R+B?>Al-|!Y#98+ArGFp3M06#wqKL7 zfQtcE^O|uEVvJT8p8%+|z_GFRJlHfiKI^X!mkv4E|AO?0Z(J)WwmaYhH0 z(JMTZqz3BS7&gBCq>Mjg=gai*an>z~Y^8#QMra-wUJZw%8Tr3`vxjl#Oc6mV%S-T_}G!bsyGz^5xaPq=`Y_Oy|MZEk|qY0M)CW9Ro~s&nk31{5qYLB_}RR5{N*}2 z&$VyGTQ8h?{c1=ttB}J3Uj0XWcXhwMeX%yUHtiVGx@lKJ!t1pr2K{>A^5&>?YmkMi zFle${;qMhEk58*t>^sO9_gUV51IJ?E7o0kRh~2_;A)&Wd*6#JPKE=m zFBK9z?l+t>K3rpL(e%xk`}?z_>uh$grH8LHX}3zSs^rW#&$z6pHE87&>E>IN(n1WZq8&fk zmCJf$uYLY&{iS4+8e42}#bGwh(?JTq=ibV5`@4+&yR<>ghRy{%n zJN1gjX3H&wYr;6!cx;j~di-MBiQDVBh56(zT##L&l=ALa@0PT_Ucs$@w<>dddN`jW z$#3!Q9~BWd$_%E3oVc|_j0L!#orS?kcdg<@zjwC^zE=Lb`ggZou#0HZKmUhXOJ7}P z(2iLhxN6IXld8bQ`1MEIEnPS+Uzgrn@-Xt&Zs+{A{P=gQQ!H0+TiSR)=t}m!wV#2z zo){U#zppWwzo#Ry&$vtMe$BBux%l0Gc2xe(7Pqtgw?y9bY2wj8f+nRKuD|P^ex|vg zGk=BZ-3`k^AHTJIX}eq{e1g*5ImdEtGcxQbG-$HQYc=Hct7-VRdP}eNVYAlx)^8k` z7#c36e_XvTP+$I6C(~{wMc~qh^MAwEw>r9Iy_$8xEv(OMnZ$wU9j3lXy;Jv2)_m>U z-nC$&v(aXACFP>T;Mm0z^3t;N59U2L?DJc^;%R5$%#Ng#rwOS}52W&PdtG>QtaeDe zynZb7bc@VJsp(rb=*ZfM=7^eIRa{nfETy6t=oSv&+|=f+-IssQSS0fKRm+O*#gbh9 zKEPEM|Ft)q0!~cjQp za@WeqIXQD@_Ut_;R8d|U9fbr1005xNe3MWH0O0ok0JtF_JnRa4$InC93!I~}v>2d# zl7OUsc@}kJDYfR3(@0Dv}*XZ%0g3_yT!ie~+j7Q7YrNXjJ+GCnfAEKZ#oS zhbZG=sVXWeew9?hmi&tKdzA{3vbtotbYQmoVk91s#M1TTvnrkW!T9oj=4&K;Z_kSg_$4YjhD!clOYiv10w{t)%^*?#vvMt`|JkdZ7%;(P zVed)>1n^VNidO_cu;8-*@ydumDp8;kO1!ct9wQ|L;0I3$fMCNT`eDI`_Ze~}b4dB> z)?tZZq0p~~DdG7O_x`vRNihL_Vt0s#GE1_UvR&CgnGuP44NK>~{cj5NNML4QD{Zlb zMRA!{{?ds-U|`@t6#14roDo1YUKvoSRi>^x!%I)!zju``m<-m?fN)3x5hwwc-TNCD zp)YZ{=qxo2m4_=d54OKBQBkc_ohd;Fa-a0(RQ-A6N}#1k0F-I#D*oYXL2=wUqd~X-TNfHEGz|*&Kgxk7@;ts?2pLbRwSrqF8{BU0*Nn=g2pO z>G-*U(=>rA%CSH!1LzQ1rclDe;|eB50ugcEob3NrB0?h*TVOG#>zck`O$z}4x`9Ss z+vioStzHq>RJGueT9=b0WfGn)KtDegR=w>@ApBRqoQUJi*8}-dfMON^7#iZ~VrJW( zmHfRx_QT!QZdtZ9D+H^dg^zyLc?vyXXy{|T^~z!S%rW1`&dm2eL3m*5zt+aIN(Sg; z)G2v5kp|=#0`Dcj_%h1CcM-(7aJb+&uoxUsB5!3#Rh^s1tT@3?M3N6oj$i@v%Frcs zNkzTO3M+*|3?blu{4_n9&UtGNgy#AiFqg3w;?#uIFcxm zOsd&s;=lF~kS!UTcYCsA@crGdIUX^lJ|d%t#o9rZ3P!?r6V`l%`GqL0qCn*GB@Q%G zO?p<=o#zKKq^@D|bOMF1O^R_Wwhw`!os&^SeC;NH6+gAcw=I*mP} z9B4{26h5nlTqJMS`B@O!wb$)oAul8Sho84CsGmA`N8-E&?!Ow~>ObyoVjAhEJeeLb zid)>;Rj}RHPOZm8FE5Y$%enGwclX@E9MrY5z}0)bZ=9pZ6nN@d6=8pQmRMIEq+8}02?t!hna9jQ zBk#7Ke9H7@?oEZCtR-}Iw?9#wk+xwBNH;~lT+T~NC$e~DUsbd$OyiX~1yHKu?LIBm zgTM`mR1nn!EEK=azto~3YR4rT!L%l|L&qip4CW_s%HN4EW~7B z4n9h!j|vP33h(!~KMAvfoVt!LjA{^%!rRV5PlS#K6aQ_R72+W`8~@KUo1FGBqt2^K z$@uLZ*WdF#M4OFwB0+0ff@FXRbxVR>XgW&v(2IRlR;yvRj`AbF@6ss>Rj97PH zSe`ZF<;lPSDn;FL7a`~|l;M4)j6=Z`74F9O;(>j1+6{J}NJw23z5@Pw-`j79i`$;6 zwAe{&MW4nX-?t2!0VV+e#w4!b_7|PKwx#M)Jk8I&2mrr=M*KjM$kO#c*^)$9y~+F| zC+`6{o6@`Ou14@`@+=fL{lY)|aD0=O<{tXrr=6ls@l`q6w#$5vZ`aZY$pZI4D$(Y1 zwBhGJkO)ZqTJCAWVScl?Y2Z|7tt&cQZr8Ls!4Q79E+$bSQr@kZ2%4Dkzj0dU*2)*LigFlPuR_ zu~?-rfF4tB3QrOr5g7pVV;oMS|4>TLBiQQreV$O$>`dMeyXOI~PAL?}G8%2bfld9p zgUmrHDxr7nE^f^r88-GpBko5rqG5(;(?Z=PlOFZ8#Lr(EiavLggc(u;!>Wub*mjd> z!&T!l^@ps`=>RCNajrip2u1eGJt>YCV^801&?tZKS0CncVxp1qdY$V1zyeT?*JqSl zCoJY1Pv0I29X%tHli}~(sZEKX7C~FZt9#;GWCX_-8Ft*R8tySHV~$3;!VAUus0SU#1sEpLeTwdXR2 zqvvghJ8M7n4uHK|?ptP~Zz-myd=K}TqDl1hw1B*#@z1S-(OCp(E4Ak0y=A(SE?%`x zMp3<7K!8SKQ!jzD(^S;4>dhX7JeMfOsfb0z7kWpmf8qMIaTm zZ%`8F7VXKkVgi(1ZRh)8Nr_r)_4}u{+*W%;9sS=_c-e+9r>6_;n{L9^LthE?k;Hi) zOkR3D{tv17B01L+fM>2-$Nw*rrXJ!a{>u7PK6d2()@G6=kaqZg1F;f+vTYUmr&OqA z+qNV1@*U^@M(Cgdu0P48o)}=PR7gty*Y+~MI)cLsEPQ;kJ_lDoL=*A9V%>ayqY%TA zP>O%Gdy@i#y@h@EJ&G(Kdk?-f<*&T2G$Y%a>@!~Noo_=G|C!1ILotDvIc4YE%h*)} z>*=CX9OxvsAHyJp@PNV)cz$!n;6lN3&D@fg+)^Kz%M2IrP6>xPL)5RLBU&qVN7S#O zzu|D+|H-xaC#aZq5Ka#Z@gmIYH&cG>a;YCwiqq^_Apwhu7Hd7g)gq{1N@&aWjbY8;Ull}FQC(REz)q{u>4)=Br#qmTtOCKYjnwHcYVKi_<0kH2Cb;PtWoSEtZ! zvT{B&3c?2@FGc&Xcr5MBU{5HbQR0dLsk&-zcp@uV#F^+Il`JJt<{l2Y6O6)wr0i&n zqlCkF_&R;x=h0t+F|gn0BYIbnYyFdDJIz&ytJSwacGrr}r_o-$U5ZH(=%39ahnf-A z!;wU}XT&bp>h=ha4hN4Y8c>WvANsplam1_K(z0oN<)VaM&|8li2^|>*@jHJ+U`_Hw z!vBD9N@4u@$U^ZkY>0!%sFcySajQi*9H4j}RU$<(AZa3eSCP$0P`>*w@l)cNkMZpF znVx$=Zv_|HEDw$s8|4-Px1Ip+TWAj*w97auS_0SvmZO1CLx3p0UPHJgddVAeod&4U zs1-=Rfm9?^KtF?|bp_xqICt<{<8Hs%>FHQd(|6@a{hz)(&b!FiZ~)jcIQyiMumMdP zn8XFAu1YA*$)V_jGMp(;%OW;AQd3^4_}|Ul&o9HmDt=@BQA>%dRAu zZDzFumKfxXSP=%dg)Ov^2Vb^BO@;{~o3e!fSYeB`5r}|(9L~M6z6$h{DOIwLy(c{pz6dZWSQ~`W)WO^kLu9BvYVT0R1{W z8@e(c(ZfH;B1K|5zsckD=kRDe5JXgY?fsgM*+n=erfN!tR0;F)<^I%i#V|vMpv__$ z-Fw-tN$=}P6IngqQ@C6fMySO!Dz|!T!~IOCt78fppue&HtgXR#G19`OqT_6$gcV?a zw>74>)q8U0VZAWf$1Qz5!xQg5JfAQ7C!!-?rA??bn&S*&HlzkC>Yuh6w?~clB||8O9&=k~tlEOR zL9sN4)cqD$gch@x;(?b>Rwo{2-$tE0)xxHnYg)`9&azm?zK${ zfdZNl=#nw+h8Bd3v63)eC$*D`8ZILCv5afM-?c zXh){PyRD*_9|A31jPO*pnO+CA5Zn@~4M%jD^Zm%6jXH@c6ndEs4z})DA}N8K%TN5U z5-NIeZbM@}ouq4(xiGMu0`b?jDNgfjUU_)?bdfFH9ANA?7Am|oLHn+sl(R#XzVg-| z<15v2sw?v56o-L2eYa~uaWk}B7X@EE2ssjIZ_c-6ri6vFTDhu8XG2t79-H>`QX1O) zIEm!QkN~+0|2TDy%F77GlIz!p5jaoYV|+Ss`?)#QckyBuW%2VyIq!qD&McLZfbVGu zLx$HyVX41RYR87mW@EYW;gmv|@F`J-h3#SJf~K@Ur2At*260NK3V_;U?|VAW)36Y< z!EM)3LFl&o^7PXR1o+Mmw&3sDulPUu4GpPsre4w~I_QP3UT3|+es8j+TyDxb`u;QJ z59sUsMr+!gUM8F-U^LV^Q-_UE!I_zUJ}sO1VIx(TH3mlv_zo1Bmm;m;aTwkdm*H(S zuwoQ6Yl7+=k$gTr$)wO$dHh!hbJeu=3ofX`&EoRkiWqFyRQ#0lug{N}D*ioSuPo7& zf!A72E00sTOgs#RyD)E}4CD+hz^U|dDeWsukH0j0-^m|g^(5Ii9B$}SIa&JQh~c!X zJS+BY6tgRckP6xV>*Pl+6r2e5^qjp`i0ZVWS=z{&{=uRUeOU82vuDP(Br5)a@%PV} zmFOt)oBequA?;wR>HELS?gJvpPus_1XKowsti}Ps^R;X?!bu{Ivn?VRUYm4r1&7{= zQBkA5+;VCA>|pP!9d&q9w~m3|*H23!HG1jh$Y?&5sX<{11lSST#WF1#uQ!B8l0n!n z?GP)i4=)Zzbptx!qZVWS-x5m7sqw<97v;}#`-^(>Y62u zHKW3h8VaXN>8 zV5POQ!GMy!;F8eM<;!UGVS%XENeKNtRyP@2mCyWR!Ms zdgrPr4+v$T01^Zu0H7_Gs8X9LcCv%nz2;)}8y&8*xJRz)epjE%UwUvc{huG!-I!%_ z^2{TM0e&}`3-L3~-MKWkZ_hKMHMI9vJK@d9@*V0c*C=&sv-1T!5mAJr00p;^?L^ntX(WyPfdvgn$~g zPOsu_eYGfcBs39{t3Bu8)xQ>nC$h?iP(2i~edV#@zQ=a$?C{YgVbuYg>h%T|Io4T7 zL&9C6emLK)uxu;v9zZESSx6joNT68M*4p}77~S&W*i7#VAMk_P>v5)CJ2(m?RDIQw z&X9e8-x+&sbM%Q2z7zc}S`x{#LPDjaCHQ7iQO1Sy*_J&|IJ2VqaeB48WlJNa&{Yct z_nIvqYV?ZAp*R{C0JJU#c*Z`KgcrhRt=k}8&r3Hk+8|!O&$x)FRz(yJrG zG(9}Yw12=WgjD&T2)+zS-!zf1>F=urhYBr^Rqi4DG#pY!y3)@m37K)6zEoEXJ zR*ppG15avpBZOZjFa7!{L8_X_t3{Ds5B1wFr3IkQzhQd=yk}K0#Ajn9LKphOZjBK~ z%(2T4?VXGGX9+;j&`_J4A?H7If=3QSd_L=1v<29hwZnv;-*|En#Ql~;@w@rU|ztzBs$Y`6X5gt zj&yK1ZRB6X0k|IJ95{ef7M0Z!!8Ol5Veo%&BXmdMHxepcmpaRBMtPWzQ`XIkI$>1$ zc{f6g&grQFfv+=^NdUPjzvFgR5JeQB(Cpv+cDS0+YTBP(YLlh+S{(9d&x!1=9nXhH z3DOG=@6Cv1fFmH=&$=7c$ch`5jlixBk=@&+TNaK2N5;26!Aa z9Sgb$auK+|ys^a6R?qvII|hN!0_!)+@CHUJn;+ZD57BO;XUQ)cO$Emfz-fv<>}}rj zz3<9&po&jZW@jU7irglnq%6VJ?W;(B|B!_WM-R*r!U$MBGAVcFbo1@nZcI<3z^HsL zKdXm3R<+C#@;#c+unDh9&ga?JOrm^@zNTroT;F_}LnQHJTq+S3nsV4}eJItax1aS_Zn{7_b9xErv1=RZwkY&{c^v*Z@w{;Rr*NeB^TkWf zNa~rp#m0{)5Zx1&xwg8GkoRW963X4EmU9|B$0#3r`+emwq{dfkM{<*0#JKHtmsHYo zuDl%p=wvdRJGSHYUWKpGd0lL2`QYniPn2t|+XO3VE`%HB{fj;O{OfS_e1vB6j$ch5 z2wOgeZA#xM_@4CaXlJChbPj&go@HB62Gsx4Hf#I*{i6WiQF(K4dl>t905|k6-tm$jsPCxmp;M3AVTj@HC}H06Nc}Y8c^Pd(?MDzBpV0 z89ZGE4qZDwyTW~0oib|ZB?=PZWnC^h)p+|Q-NFA|T6(X8^u>Dl4Z!6f@7p@OY@%KF zcA|~V6Y0M|mg(@4HJ`?-E&uXoyMq%ta;&|*C-Oz1g5wQ8Fv%wBC0<}ZNevj0zD*x8X6)znQt)P1YYF$?>j zh&8&V)sASx>LK+%LS+9r{b6PHKeUshW=O%qi_ce}XpMS2c0ZqIQlH_k^^;h=3PzL> zU+Vtv8jU^XJO{}Yxw!~g6mMBDa$S%yKOtc!@ZEz&8JA{a87`Y#I=-mIIgMswO-+<* zM{`3#@#npko9Bj1uKDML0_DX ztvQGSf=P12Nf30sWU{-eJ`s);@sY?4U{L%sUy%aOs1YZpbpg@eDg0eGa1oID{?*6U zP`O$U5w`TmqC|b)mm4wp(ag28`E2n9+m%;RE=erJnuX_2G7&H|@$>@0$%zRpmtKK!U7eon7Yn2GbxUC8U$@< zU>x!&;C3Aei;5!W^Dr|%ULSyj-rjsKH-?6F?7O&*doVHIDC7{RBs#Wr3N@iS3ws#~ z^78bM={uUPa^sEe26-|OB!E$Wl#%A{ipelZWK~wy`e8;JNH#1TJBGC5soeF<>Xk!R zWv2dQQ6cqlsM4T^1ijs2sz4^La9TtwHZS1)?b3qhAjx(cr z?mR4MsB>SvJZo5nyOsrfsS1VT8N&#|={Tvn%z3hYzt2?yIbL1n36v9eNA!}C7Pi%U0h3kwU+ zOTQC9k(=^Yz{FUE{2rStJDDz?qJx8xP`c$wkEhKUU9QW?nVD<*HI{9!t*B;aAATyN z^4aL63LTB<-){s{*tMM8qBcDsJl+{`AOXNMP$|ZI=IlLL%R(U`kJIHQ&%4tT*f!Pmc~MGac-@Ss6PIx<8rNHBgoHKZ z7#>+$huNchMR97eBX_@tkFqxlDHm5BY^v@I5}$czi%s<{if7FkY^+t=*LirkpINF^ z@IBd(FO@+qMOEZ%p~Ls>7s7iC@-KML+yVlgFOTf0VO22Kv}@W)9Mx^^9~e+b;=lO2 zA&xG>%FL{Wm#-v;Wqc9q8bvOkrrtw~Y$W(|`>(=mX?YET&0C#zgDnfGrNPnqF9Zu2 zWFU(J?kQJ|Ec{h;Fc$+PyxQQi{Re*x1M}70!XVnJfsTtgH-}B0Ou6 zrosnQIw%MaIOON&J2*J_bg(;-goTIu-aB0FD@F4hi>p`Yaoex^5wL3U*iDMN>KCoV zoZNn-9kd`B@3%0%Xhy)#Esu=EX!+M@#X(elxJXkp1Mu784>AzUSnSX-sgX~Ayq+5S z;$%)iNZ4Sv_Db}}sy8IKV%dKO{r-hb9qskgKh^lj!yy!qj70oVbq}f1&g9sh#>fl- zO@QAdcc%KW_EEDLA0N-$Sp3*x?05$QH3=QWlEfT>122)ALa*8sn6@>d%4(v|iWZ&E z*soN19D2>9|D3-j_lMQeV0X zhR=8`*)$mbvtDV=udcqVy4Vu`XHP;Mw%O`_rQKk`{X^9EE7oke_8!m?jr{QkH(gzy zp=OH<>wp7n7ehls0g6gW8$X)>om&_DWEe8BfbwI-vI^hTCF)6n4GwkB`)-hag7i76 zWx}WP71uRfF%%S(L{{&@;>wtq7|dug{6Dvn;eR>8V+L8T@Ko=aEgvoyI}3-`J~$j@ zg@lB}ZsrsmN}rUkl@I?bB^4&SxXr%fB7zfLI$yb90sulnUoVb6%M~Z4x47Om6)04E zXe)Jjs=^&;ac+Z_M?kLvxz`MhA~k;N)_oM*ZDy!o6c=n2bTyK<{B9h-V!#cPG6(%! z((%>KSTdYEp)3D>jf$w&nWyajY(hdKQnWLl;9+H9Db?$}_iCR{N-8i+6Y^ARI2GdJ z=B}x(uD4rqu^1Bz9oPyD4@X^L$`JCrg{`qpg9RxdJ11vz1Di(pb)N?C8(%YV2g~T> z*UM9G8itu_?by}^+B`9_oNO4z2SFlLQV3R}N$Oz`o@8+mqa8MdEMsU`7!IPrS%y$~ zQj$k@t_8_}LpJYJrdi~?BMOfUc7rS7pLFKT54(}goJBcbWO$Oa_jC8MPuW< z1#43cB+&v@6jRy(2iV^Xq>@w;+upv|8u;{f9k*cUV|Gxjl>4D7X(Wfy=XzqmpSJvA zdy3SSXgc3zplLet$47O8hwa9>PLjMm;N;h{+7v5k8c0EKNvT-v$L0 z6^@dMii$tXtNC_nqo;hnTSrap_JAQ%`0e?Mvx-x6qxsjI&0_7r%H1mICl_n(;P;^7 zhI#@&E!JJwzCwI^w8iicM?0w?mQZGzT-|J3%Iyp;61Q>H9GoDN82WkZ#^)KQeVo0=G7%g3uNe>C_M+Mdso1XK5O- zkOGT%YS>`-Eoa%pQM1xY2#b_laZ0(nqKXFKB2z3{5kuaFaF8T zNHR`%?j+^M^Bzp!rxRCwyLtOJ?>pXsZ`{6J-99gm=*0~Ef?6?PrSxb&r3O^55* z;zG@?cCY@xwr}Dzt}o#qH<#@AzNdaRJMP_+LkjBCm@yYsMfvER%4bXDsPZ0g?$K6N zRVDXsfJo%&I*wiFVL!)Jgoo5RURlhdO#j*GAxFDH9+pG)Oj1bmA$v!MsY*N~{Mx6| z)g=@Y_g@Yqcd(L)KYZ}nJwCW^bc<9@H1RiOC}x&sdKftq8p`a*0?rdBxJVLHmn^2) zjY-avH{tuUghAKe17@wcQ@+cmI*&G(>9-Z4_v{n=@hz~-j_>d7MI+*%oY(TV8Qic} z1YwdbvocxQGmqnuw>W!kM7cRHT05~?`8 z9cI@a&G_8#P?%XTmel;VZksiYjqQ^BK@;r%Vxc^&3i&;7(ogi{{h?tA9WV+k99zmW zq5k;sBQLLHeD8WDT7Y)LAis~`N9u0kV;&vO@{c3>V6c+Jdw?P;Do@!dbFv5b*@Thw zclx*j3pr=FS5ZF`%^&eAh3yqT3B!Lzl!CrqxHem}4-mzok#83$0Pzqvrs^{Ldi$pv zt*B{oXT7R-%LPuC8!tR%V%mhGXAE^~cH^cKS;;Y^RXF3PK^D3^U8?N+&K-9flU8Sy8R#w(`enUe;uw)6}NvQ92L8v-BP%qMONBB!3!5 z>o>MJ-7mtXMoD4BmVA*VC}?)TqcZj``km7sOo6m{;e$#A!9s_#TyKJp#{q<4F@OAM zRisJ+&Ft-!fMCrqX6G54W6`yoUa=R*rE2LYR~rqCk_))x6%@FfO?aO)JC8U-XT_hc zzAR0;CVmid`L2Wqu;d}K>o}P$%<$Q5_dIJmo&tkMhKEzXI9s~AKisX^S*|oY8ya@6 zcQuS9an^V?*p6s2$zKdSRf>2 zq@-Z?t?@a*6|Xp3tSgzZv^k~S*bKMQ-dwBh@GlA)Gl$9j9B2VmpxU(7W!R2|=P2r` zkdJ<|JkV2Euyu9eW9;8wjfS{3mpwFnWz?;_h+na0EyW<>Xv=kU^U`VV3mMz_W5cg} zg#CNiz~d?SxX{if{I%gMcIx3HG!W~uJNCvJA^dL7^A8Qgqqn;-Rk*x}Wlz#qWr7@r zD$GU|`gY!h<(wO?$Jq&E!M83^e2WS%Ek>_IlXYMee>|SkLuD&KYk%2=LN9&1%b8eN zS86R(3@o~yGTY>M%&{|Za@0;%+em3BVO>Rkf(2-RR5JBrh98> z%s(tIm%XEiXl##;zLNm~0Oe=P2O6X71Qvd@GF|tieb#(t^+STm=_XvnvY;>{9nLAU ze}Dh}D=I3@il1$^dVfnnBvx%sqFJ3^WRp{~$WAzOFLfLB9wodUFDUtQYNrEQR4rda zV1w0Md3AMlR@RTdzp2zpZrCfZ()k^{<}0(~6-7mVAu$+i$eRHJrs(QFDy0)AnE;4~6T%8Ql2b)VaLiMHg^TOu-FHZF^e z5PT>A$75{&nDK*FmS&9C0a?w>%|(@24_0nxKJ6i2$J_L!g85`L&BB=i_3u8+47Ha< zL~32F3|YEHvV>=YWu2UAhj+AICWfNQv`+<{cH^SeT5o&3Ei5dEjDifr8u+m}AFNj@ z_k=?xT6Mjaf87OW@CFW+Xvg zAEwFjOtkB<+Pe9F1xerD>o^^V=xf;WR04jc^*C=l2ij8EWSnlMNJ|S9Ko7V76#O92 zE=x@J^u>P`%w3-kDXNhS3^*h5S}>NBkl^p>fx+0CgMmz@e9jGd1rthcrWisQZ`3x$aA+ZFd#HK0hDVcC;6D6{;GRerw)-Uy_ zCfvWguIrqGT#w9C=x5^32Yh~*EUej^guw%9&)pjrbM+#;pg7)3alULJqLk|wZd_A~ z`FSjlx8tR!#A=eL9P{?i-J$lTKcsXTmY0`*?5&!2V~Np7N6j}nY>jC*B(d&RUse-@ zvJMRm1E~brm)%~_8&+JbLVEX9!$Ot#Fe~og9pq~(AJg9k=!Z`k9pj0{hvwk4430mS z?yt1C+9%$gP0y(vl))lcVtkT@h?u9~>LC=m%d#XBi+Ap>8HLU^Q^leJ)&p%A@)p86 zno%y~l5pBSL^C211r=N2Ts$aFaV^t#AL%Xd$HiXbMqPIPfx5aamzq?vuEZDTW@7deZf7&5#$QL9V~ zVNYJYb(7;jRFzS`%l^2*$)dAe$BUZDf6Wm}He8J@zxV6q{iHZyTt5?Vz=e&RM0fRaF z1ze8rcT>@ke0?M&By4P0`{#|h0$uI~58SjTC8bxEH%H2L$|PEftgAbp?A~|;`YHa-)E6+5oNM7n5YkF@ObpX8j(*DZ6td56Qc}jX4_aVuBjLt5^@k>oVjx7yi&?0+rO$Tb28S z0b>rA?_UZwH)FpBAdx@syl-mmxBStjz^9LyO@=v*?G8nvz5My!h?TRV_c|uevBu813 zzWVqFYY65zG%U<--ux@#lM1LfwC+xpv}5a^KpE}=P6J-hqjLyFkwpq6(7?dpRkRbE zV0N19^mfTk9nX30R5w2Vl*IM?1y&%n-^^;WaeuuSj^Q)PSGOd$s!!Db5KXSs?fEm9 zJN)3dmd7+{84~s`uvxmTXy>~+s_58o|B8hO`leWkEwk!3hfcT}XA%BVjg znbWag;zw)!Se$RHjuJoyUa5fj zf^3y(*HjYrWmHGL;aT_)#V}xY{Evu=WKwbbpA%Me`xDA{(&0V^lKomBAQc{!a^W{d zEHP{A_*v$5mjsiWDl8V#0_+6PQn88ZYfp_MsYs9`XL(Gk*WUp9dkFbwpM7gvmjO158D`UvWW|)Z zUZ2*W+tA3hHx9S+bpqtUHJ^rJ7^VTi1$U*Gh3zo1GBF{4KG>j@ftEr!QzIa;0QPFK z;YyYm+6c~fB#V_Wh}QSBbkG=vz;PuxmkmU`cdfN7Q*w&@U^Ud302;g17d4ZJ2(*or zq%KvZVp^zw=6UPx-Pg|OXSi+55WRe*8GlX}ezLCu?s;@oo|}JJ%?KIz%Ma6BRK{!g z>FK4Wcq#^_;w_QOy~w|KF$xQ}*Ou~VWO0@!sVpqO;_4sAa3swMyoAce@(hS}W2%6J z5(;E;y}%DkLQ3ijS(K>gKTJHHW!w)=4xsPfc}OA|6f#11y-efaNRVB4&1%@XwEN20|1t}R>tf`l)9V!zQYOXR{(O~$wJ6` z?gJ=#-oQN%gK4E|r4}b;7AL8^537%X6K!$1p@yr(cpm~Klc8Gc!|FEjMyJa!#5Ka^ zv+%h79{QgE=DzCMXp#4m@M7O-*@Sh!F;YqNBsKB7y>ELuvS$4{GdWIr2dmr3xK00s z;xed}Y1LWHu|;Ab`f&!NY{aI<#Bd(Q#E`Z>-0rbz^T-)#&Ys;75)iO?9i4FIN-tQ~ zkHc>kklNwByEsB8o%Ou|kAIR^inm#62o^}cLu*PkS-|Sz?2i`Vdu_X0({D2!f!$pG zqzRfqnpcAiNV!#ZnO4L>O{HF6fps!A6ZTzq{Z?OIb~4fp7S8zWI1EZynBE0G_~(&{ zIM?b9B*m(C8%%V!Ck?WG!#eO1!U0h0h=vN)utd6CBR3Z&p6TMF_AI6qd|}wdoR3nUh-y zrJM~i-6^6#Z~$6cDjIxhbBJ%>W|XP$S#_TZR8Qh0WWc;xwT+W21uF`#~K*1LGXl-a=WC;po6gfTe!-F&rwE_GTZ!o{5=@?T3AGKQeY(> zIl6diNLZLGb((zUS};~O8paoV{o*po1jZRJkS5%O1T;hfho?)y4Gs|-nR=J*-*8wk zA2W&n6h8oH`@3GN0u-h<#FaK^Zm2nX;<992|6k~qdik3`(&5$rooRSeQ4wQNj=y$6 zPj`1>>(%J6N&!Tp##L*cOF>lWpji2}o~@&Uy(F(vD=eBr11)=Y*dLeIwM_c_fembg zwsrMjtf`jpvHr&mEPBF9T__YOm_P|{AcFkvaru)}6wyS7Z-=68;UL)uY_P88XeFAW zBAA!z^A4t!3st&SHyOrLW**hqT}w%cMpS;hGK3~Khn+idK5cRVrKYZVM{e$S8jIpI zL~R3!Sr&{lM_;`l%Y%oA9E$QyorAa6w8g#_Pdy=jc|300gi2H9Zv-Euq(h00YKy6K zfFFD|*0kk!K`9`WPKRex*Q*(ZQAEH~;P{!@Kz3FW9X}h=r>>1~#J;u1o1^fsFhfH_ z7`BuO3Br;Zv2_yixHg|FCm*{C%b`X@>p6x&(1$Qg81t_0_Sys^aK{ff618nl=PD`~ z!*06fyexFztzn~JlQGkvnUME_aLl7K+v5*&y3r&Ys#O<2DKF58AD zXB`s}Pj2HK6M-4?9?G!M%D?5}&^Y}qW#tOSPn*=%J0^YKH6jXT>Mm6z>k7jx6T(+_ zSOTEK!$xH3&T{7px>Sep@j5$LJd)WdrJz=(Ap%m01MF=lb!qug-oEN#b+6xviC^qH z{rXwrK-Jv-4g9M9L})&CbuuxrxH(Yo>fuD9{;+^@ZdO?M_!>}dw^kn0UVWCX&YB@Y z>?jqq#bL$B%!-Cpw$>RnZ_Zs*|4lYNR?Kw7$7Xq+v#SSKHZYF4MZp)=md9Sm!-gN(4)fA|QN$40w*#GyPwqrK98J z_BGKY=<{RT4cWs)=oSTYeW#uJ8BO7pt z_=Tmct^H9(*&cye?C(@>*@{2q_f*aR#WE-~3_d~fpkFe7m zDLhPE)HxIDOcT2(cEy3*M4B!e(ShFF`NY{81!A<>8J2K^dx*NDJcm;BgUc5S}=5wlA4*FMl54F zO-UI(j0k$Ur*oEy%^M2iirP|@ltjZ_qu!`i=}Z#%z@%SsALT`?=85Bm&0{F>_l!Yn zu4OA&Wa7K4);J@O8i&qW%|8z>2R7SWsyshz>BU`gl+WTc38&2Mx&U6S4{i%)RSDm zsd1Zf{BiO0XH$gK7M)t{k4G4y7ynqv7od!Uc8m#t#43#0uC|?}mnXYQ_R=H3cWI|r zvBbjoMpLu16|_R7)=a;3l@8{ZS#mpZzyWns3gZ5F$efu;@bf z5W24DnBL`1bXK!ut4{G`?2VY#tesVeoRo1ovtPn1u-V4IRCtzQ%M|*LC}URyC4qOB z1_tVtx@s_e`P`@?m8k;Vwi6)s6&wTlT}mm_7weA)zSxlJ$@uIj6-x^$h9x?!GO66E zQP~(Qxe|d5{luNa!^71%ovHo(jKma=`@aT|-vySq4D!dYCI{1_*{ePF@uJ;7FECZ5 zipR!^lQc=mdsAddeFI;$FyZM!;-r7;lmm4bz|Ru#F`|b*K729|mGIc5Woxsk|IhVb z7#c&}J@3#Dg=H~}{bonGG+O_5KNxzOqSu_ks z2URpARNNx!2Xr}^Z0;bjlz9Cgj!F+AAS>mUhBCq zTG_wN5Rr)`@+T$K+~)(cyS9_E)!3>{lpX?y=R+A=k?pT&MBNy>&?+pkSHVguNNjo{ znJY2u^piiMg`25JHc#VKQ*G^aY?*i*z1-vdR|D8Si^G-_j5F|O{5m2~o4;xu zKpbSE5y2_dsC{RP)>Eq6V7mj2{@``~D~kLJ5BL*XP#LN`@z9T5Sl!4?5(!hMb#EpH zdV(-^wNh<7I(wr0I94_4bedF06XoXk~mZ57@eVCN50QyK2vOJ+2{ zJK{h|T7EiBBMz9~?GO?ymfmVL2)KnQ(-7Q+g`KXn%$42o{+(YJNGX6(mO1VPpApGu zR+ik~q!z0mv8Z}~L<$bAj#C*IwLS|b?hqjrhb`7!fxCtruUZK^Jar-j>(#l2B~jPD z@uae>c<|1Rhm3D$BT!^Kxr=gJg}{mKfvjF~sF8gDLy9AoSeYGfKHjjSUf?>kLq`?) zgRi+O@mTnJIy+Id+HR6+s%1ra&DD7tINL@8Lu$Uy4!IM$&NJYWPhRm0RQUz7goM~? zr?(_T)*RIdAM|f8bg1oF_{cv0G(JkqBt;iCx!ji4Ct30RQJ6ENl^Tj`lJIAH9_VQi zxz}(aZG-eaJPb&cD;;UcbI&`c6X(qQQBY7vNfi*rsRo`g=K)o#s+>pxVGTxwQw!5J zfS0E`5zo`o5laLB7!1qj_CoIfmdmzT>vs=RQ&XfXlA#>7P8qbr)yFR4CJ+$S&j0TP zAl6nw1s;y-&++6bN^#6s@hTVZ>$6Mx_QzymH3gyRSgo zwA-f_-DW47A$m@aX~rAxoB1lE=tv3*a(u9|vLRacnuaF931rZ^}(%n zJh$DEk^{<}CI_pJOEoLxGdZsYC_Z75aZo}y(Wvl<$wxT8mlg7T&fn=Ufi!5LBf&(d zDmgnh+gfNZ8nNz)6S%@19mukcLpOl(bT+qP}n$;8IQ&cse8w$rg~O>EnCzJ9-Z@9BTt=c(?hQ@x+P z*IsK?4u34PYm*i3Zzi-))jN^ctOO%zSu6R$;$W1&ZtcEnO?GrTO+U2X=(%t)0Y3a& zAb8Aedcz$>n5n!SH6AKR1qTDS~9=tw4_wGw2;#8>$4Pyo)4Lg?4mRgZwWtpu+pnd{wm5jFcXA{VCX}2J{6(kO(bCS7v>UQJm?!Ay?(QD84F>M$ z-aYa%HSsn~PGp%UAWe1UC*ae!u{m~rKG87EdpB{H7OiXQF~1Y^eM=_|gDyj(T=!sa zQi?ix9TEDu#V+BC#@v*aZXZTI&HVK($i! z<)xt~F3V*&g-Uzs++gU#Pcpgz7}9GyH8LvTaz8aW9+#hAP@z_llbn8&XOi3PGi0_2 z3myCD)+9GFV;C&MsTnp@WWVP6A=T56SR!Ag)BL%{}z#$+6 z3V}Z1G!lq3OOwdXUX+(ZZ}Q#B^RIdL`Epm*ydt3p(-RY>S}BN`S}n>!XkxSb8%!y* z`ij-Mt%xfVcXvRo6)ok6!ja^(e9E9%ODhoAXGD}N{Z(IJzMuXGRoEdthYa8V7RJY^ zu_;8wO~Bt!Yk(L+2Q;Y)+58Wi_yfeV6I3&WO)YJUeMa4+;u!rj|~s< zQ*&jTr8%emBv^I-MxZocQJs0mW5eej80*cc1 z`kzsyh1r+{Vx(q(fVc|1ErN>FhhO!I)TYeolB6gTbX%O%aN|!lbRaqwhr@=Kjmcmn zdWA*>6aa+N`PgS8IzF5NkJFlYj4D7ab9{Wy?{jfsdaHFN6k(g}zITtwGc$_0efJmy z#PpYZb!pGN?&ju)62)Pkx7X3p(cMPdZ0WKDj$p-<(zF=GPFXMuJD0TXO3p9-JJ|@di%s zg1`tw0zS~>;JrN`9_Qw*s;>CW*!Q7lXO@Z%GMK0YQXe@f z%Ij%sI&jeC&@CfdJoCrU0@DJp{SQYt{+z+ymNJ@CB47p$9xY_TT+Xejy+p%SHmNEb zpK9J6c0L6WPyZTD4Ex?I)Cey-D@1~jkkFE@&qG5{a68dZjQG36aBz#q)CBVTs`{-L ze`sz!?Xw6aATVOoR8~%oN~J4MlNed1@Wjfhg^-*6_Y)q1SQrFSbnUF=$kdpNlNH1M_l1fB(ZI={$(Vv;B^RR+?&-iW}*uZ(=^#{-_OnH#A^`N(usE|YI`scs?-U+<=DQ&AO0NoB*9!QTRb)-uEBnsg zKTL%m_hRzTgI6C8q%xo(k)G2Qg`uSs6cnVTo7{gr6MI1kQJJvh3iOsS}(q_wSWwRAze;709N zZFV-__@@GDSH`(*ne6G#Wh|1{%WZNp@BuS@Y=@JchNZ#h#p%a5ED07E*zYe_v;pru zCp^si+vJiGirl2jDze*L&MYq)dJt2JiD|a$U|cLT%-b_nnKFqGn(nuM#91l>tKDpI zshohSe>II7OITQxVyrGS;M+-TkCGs=U~09i)vDh!;8gq zPP@0qb$1ur{b}=@bm~`xuuCA`Y12xdY z_TK?=&@)^;pBsQ&BoHMYBbeJ-2KM8OvB+6i;7Dv4kL@nbLryWCF?Ud*Zs>r|-tCqb z_DZRg2P#9R>{j(`MbfE@*1#>vm#qtfU?i4dqiB_XbG)4$oUw1~IXW&=`Ka1jIwsMe z3@lqu_XkuzCKWYcGCK9Wm!^&Gzy ziEU>pX;bP>tYmfEHK)Y~03O5!9fyf=)7HPq>jXyqrImo#WrVeg|C@TxVyvSqSCCsAMv1#oI0=V zp_5(x!l($}ErQ4HoDnk%an5J5-jDSex81ALJ_rO_j%{oz{MB?BwM4Kmq zQvuw95056_|hk$KK96SlR33jW7{> z3Isdiys!F%Ry;ZSzBF)3YHEh>kV^lpB^fYf7lKw)QtB&~54Rmjm@*$k4Ks=uLuWz? zWa=Zmo2%zqIv(n`c$3M0vfs$IY_i{IFffy7bl(e|Q4R8+&TUPUS#OuCKBs2TjiJKQ zf$aKL6>`XiOb7`9=!GgkhE24L5+#nz2b27*K%-c50gpy5UGv%hDua|y>EUK?BYSc= ziQnLM<-hE#*nV7a_Q)qyXzC{5cA_z;mho}>`uNX1rt)HhNhCVH`4O+%zKNQn)Zn|+ zVU(S>g1KWkSiw-4D-n;|PuU|?zR;M4rGbrDRaNH_)_6oW0{$8`kB7^($w}}W{57v# zF>11An>Cw&n$FVaB%2!_2Ql^^U8TkM*Jf)3@&=593G7m&CZ>gE z2eO%o+b(-477UZw058`IBcm67YIg6KNp}Im47TX$=9xtSl$CnGQ=i;fd^D~)=SBXU zH=AJwAft{T=znWh6+)06va!*88vh1v~MY-gVy{tx94PHnE5fd{}X5tU*&PuFq=a7Potmoh1vv;o#8JxSw86Y5emrU~)(1 z$N-Qb4TU`gVg{#*eXN1|{%6mnANHuH$gl#CscYTmPOgI}C~tN%IQ zyhLoJ8Hbel(2{BK#03Qk8NBBpXS3}o>=RY*I1Ro%E|p-p?xW`hU-5G^hKF?_)NFXz zlMQ#Hy8N3W*4~mm(>n|p;lU=G)k?9N47r_G(rQgt0TF|Qf!lT?#%VZ@#p8wx_Kadu z)qO5=RWaAa!J$fC0Z%JCz7a0c-MM1yQqzNN|ddFndlOXqvgEl$P#9jMI$Hr0y|Ki zq5e|gm_#!YLz@IrMZV@a7EJ0i&9QC(WiSEToCuVW#jv}?yTV5<(TpP-UiWA8Bx&d} zKeFo5b3G>c+R4>_44LzbFd5TQx9;Ng843rW5Cs>mrbW-EWok?UwzXF46C?_7n`6&K z#)bq~sa1eRV=*LeoLZfsG09jEP~w?@rdV3$bZj22DLFb-3bYs)WG$}nNuxBR@?Y{{ z&A@B8d)OrETd&Y?W39xg0iuju_W~FIQE}EaErj>c7)|JHnJ(1*thWN6(wZje84^GY zTJguYV|X!4ap^7vX|UnMhG)7Z{ms2{2K|MSOZ^uk`cR`}C}T_evTg@z>@TfIbQ9qL zY6|+DCYW_kZ}q*5siPngTTvsqk5eRLH1lvsNXV|*MeqgM@Xp#g7fVenI+Dk4a zY%~@O4e0^N)p%w!f$tVdzkWm;-D1B6lnTI1eny!`|&Xx8WUJ*$I zBahessa1EgU881V;s+0p&L%p@_z5a>`tHfg2!UMCIcvp`J*ZdoK!O0)^#+9L_`p~u$G33Z=X5F0ff@!y01q|raU_;!!SaUa+as`wPvTaz(>N> zHvHx}o`@+q+u88?hxZ5v|5W`iwA-Rs7p%-(Ghr6HN=1WwtW+JPQmSDv{EO#{b^`Wf zn+Ho8gzX~EAK#Fn!%oZ`toz9i_>R+E$va7I8r+7^d@`+WRLCZnO}nWMkI4?TeP%SXY5{Ym`L3+%VQfgM;hvI7$-*3DNX zEnP3UZ4RCeOGAs5;P%$=|W$~cnSzgxE#3PiCaZHIo+tGfo+Yq%!elDh_l!2 zy8P?g0LE-fT-d|KK5hFCSpCt(CX-sZjFvk*$ji;;u=$Rkhj74$r>viqE8zdRDCjv@ z|1%hXl;F^KzP^07{d!=7z;C}*O>f73w?qaB0R|(@>&OyncCR6y!!##5Qq>S=@=#Oo zjCs}QH0;^n&CA>6Iv6S7mfKY|s7|)>XPij3*|9(Or$M*rNjc5*T%C>g`~67Zw{h?v zDYW0jC_FlYYnPXf8!UXro@;;f*XC2x;fM!|5rVHCkK1Tew`8Bq738rH8A|(i*=$78 z9TC3)E5c=M7hucv++AM8J- zt_V?MMl8z=j0jQj0wr1u6|_M|JYh-V`0HGzA>+DbOI8%&LS-u9@O;X6$@}-0yJ9(< zun@>4hk4Obo8SKNXBzbCHx>5m>5*9jFjQT!P?UcIimf7z2Z@7c5-Ak2v-R%1_=rSl zF)$JJ`>{MLq<@&rVnAL#m>&Y*zELYB0v*m6lX- z%_t4iA(4)=F_%JO&YV<^cU!9~<Z_>heHo9W40JzUAh*@~%trg1V7AC?e6s z_gW32YG8(UWsN~n9yt(HA&yVu z*nws$hWr$(3dyI;$cK@W>>Z%|?apjsB)n^4(&0NMS%^}lK8`CB$*|+uAi>y_e0ELn z*_z;A>VIR7{+F^yxL1c`3--mpW$B7Sv+4F2u$jU%&5PhQt zo9RG0a*LYrVs)Vne|y4G%LZM|BttwAQ;(#>&n7uJ~K&QV-c1Qy``V9nLq8b=`D z=1fC`62X7Ax#ex1IEqFtWdWrf` z{@+IZ@A_mHW7!CiGJ+8lLP!k6fBw4n${y>xJxijZ=A9pJZ)7yOXPdPGGN(tQ$lm8h zlhce#S7Ds)phm<*{(7Q)sc|_SsohQ}8iT$S72M__JYG@RicAIrIO@8%1jod5>gF*X zKR|U(P4&j-n$gc_gK!mH`Y-E@B;7oupVLc_B!#MF!IB2Ku|hR()_l9(SU)2~ztl_2 zv4nDYuJ#ENW5V7K5M8K zM>Tv0wgz=HORJ~tO!f_YGy{2&k)C5iR|e+BU;&`MAV_m{wp1}(UnxrLDPjXgh*eOd zM$At#!J`ai_LI}2Tdz3<#VGVON`p%%c)R8)ygSP8&b>V97u6^>!c;7p;PNDDUcI(m z`I^7!QR6-Iz z+9r)cq#s-H`DzP?-afyRr9?WR4(O4=&9GK2ok3h~fuh0_IQV;ohW{FF^YRa+&xtw~ z+#k8CEzxvlv01>wn|nvSE|+bEKxFdZv|Bb%XJ}kLDrPJt>A|i1Mn%Hi-9kET=$T@u zHw}%?SkG(ZHrZPX4!z*lPxky0=|6i{OLvin_%8nP8HLW&QY55x^s`MSJnl3%VX^s& zr%f?oL(^C!;I*~RjugSXsspw z@+xY%*CyB$b^m|rJR_#{Loqn$u%`J-jtdJ_;LM!shmokIP{=a-#7kv2i5mp02$C&8)e&&mw3kW4=n_V z`C!0aubqisrz`R3>E!b=jrpCyptt@WOJi+j$)uKTRBnM-yE zQb+GRaVOe(j+T>S-b|jGb`;TNh_5Xa-O>1Gt44isR?QAN+-koj-h5vJRUwo))w0+f z3GqFRHiz!G6(8QrB6A^_NWt;+P987>r2hYqosF8QhN9d`#KgX?#~J7Al&DY>M#7C#q@U zKJVh>m|k3}9!1*bZ}t;OJI$7Qef(?%g8@XGeEWx4YTp@S^eURLmr9guvmSj0R@*m$ zAnz>iubI#Su=o^xHVMS5Y77`=P|(38;Onx$)0kLPW<((ROU+hUvUI+ZnezS!0U$D; z3@y9E{d~3f#`AAV>n@Ro)+M3gt36Qy4UE)t5P%j1;Q*M!;rn1&czcD&9V| z+qD*_b6|LW|I`-9g7@*|({OwXgN}uaFTL*Z@z$W+{Fn}dK39T5Pt)(kJlT(~%ZRK- z5L8tH4)0g9YBSv@mA^+GGt-{ZW^5|U?saz4(JVMGZYP}Y7z}scz61eOPuYD{`Pl3t zv;CP}#`+GNoOjpFhR0<;tEfuE!Ceo&ACl8oUbCyCDkL~x z?0|0>4Z`9}pt}%h7=08!kdX+>5l@a29MTyN?Cok@UHXSL0@76fyG)jZL}|L1rTF za)JjFLi#-NMLV&ej;T2e0*Iik8uDdfxG<+WA%_+;#C%hy1051W_yP?PhFN2pQQtY@oKK} z8zoAnOf}bD<+C&+hSJd{m4lH?{7ez_2KB$8-BkRIocyP4A`2FROq_u=HKvY$HQ=UB zNv2a0F;BxyH2@I2&zRxWa;BjYi}LLpDC1@^1P|#u1@a2v^`^N)4?!bGTV)VIR-%n1 z@is*IXW^BMM?Y38XOj&q_R728hQ!lQw9LRj`(zFbivFWj=~70olT1oY#YM%ZN~O`& z-H2S%W)y}7PznOl_QG{0r#yD<(Z-?D)E0lSeGeI^e|&9Ma^XNG4f%ee`ZLGv+hT0) zD$w20QLFuMdU{5C#zsRT7zQaCi8vqtDHw?;07;NNGN>51{!u1tEw`4ZE5hrosJ#<24wO~i-v_;~x+bT1MkWPFU?;!3h&Qm& z`>==C*FSl9J+8)WP|IkF8|jb>DCp#A!&4!_*}UuV!v;zz#SxAa&YIdhWQ3K(ajV%& zqZS7i@ETlb71S4uj*LZYmic7s=h&lS;@jvKWey}ICdJd4nWY(q<*|U=KSsvR=ik_a*uI82n$H_&zFzS z=VD<)Qkjp0ER{ox_-Q3h?8%x+4GR!qW2%nx4U29w>?tWZwNFjk@a4HBk6mzXo$Ha6 zJByM`qQPJ*`N9o9^Me88;ec!D_PH+E;~O2R*aeipK>YH>k~%_BP$fSpgapb*Z|-V- zBZ)&xi5hEgJcZ9}b2MT^GZD<^=KoQp?!_AhQ!My1$$odg0w;PfbrAb@iKUFt_)cp*v($gcoALKZYvGuTLBEEU*vNTOJC zG8By3d2h?AS|FT7x+xj?BvwT+WOv&%lRbKxHYZ@FDAa!0hk9Hvx%!`58YT@k(@W2) zS%bn!CW5Bws`|j{#|-K5^a_i@*!)jFrpj+!yIj#WlTswq5Ob1+%ma?lD$EhjI`Zv8(7*5` zpov(kl4i43CU|(5&_)W02OI&a=vC(JuT^o8)t9O~&5yoSD}C*1 z9B~FSffGiH_Rgf`i#jodaK@s`44{RZO2aY^J30+hi;NTKvirx1B&#QSc^fxqArXUO zHo2J(4cZt+G;}ZY$_me|4s1Pzb$!E0pP3kIKUygonwSc!1KJMBiLr11Qe<(I^4=$W zeLeHV`FRvnEa*ct0V@4pRvG4uy?`Er>^Knx#$rmpHt^sgKyK8EZGCOy;#p&jO$T8o z6Br<}xU4Ts=Q(-TzvOs{WN!E2YeN7om`NoK@VnURFC}4NX=EgI3;;m%O|AC{Au^vb zvcoSMHKUkG_}xubQb~fQT-?v%)E8Z62Ae9fxa(xWm5U1pBo+(d z2Q^{*RtSE>(6{|cmk{^R8Si$23*QT-G6DO21se(e7aAZiLXy^T5fcTIZ*_Qv9u7qq zNV2YB2bMcOw$l;ZeoLT&j4XsDg4B--hiyz*E*+`C zM&Tjhlk=ebuW+)W8vR-<`sPVYc5yDT?`dYnrVcqJGnJA^3xo=Jxte4*$pSJ={{- zCbv9+vt{2OX1n&rkt1lN%h`xrZ?~rto{s*geO`S8hc2W~kvn;HT7ckkgcexw=_Kxw zuSSNA3PDvHgVkb3)#(*?K32Uj0&n!&44T#XA7L%jTr_U@8|F_TQdXNMq zc?Pij>*0w#Hkn)P-i_lxi~&yrXyKl#b;j{)`Q6a_il49J^@rUZq1M~)@tr%1xMS$i z2tKBcW`%C0PT>Z*;J@RU-jChQk{82KA?Uk^;7?Q(ZBZ2H{nsaR=?$W@A1pw%bSXVXa}i;w2zXU z>Ww=m;g`%32fkR(#<%*r+lzJr(+$lW!}-h4BDMC>rBnn5?yn~SE|crum>9Tj0%v8b zXh_-j`}=*3I6Cf^UEZE+`7S1}mt@@^O@}Av?2&RjvCwt^K*0VLzRK=XJ51&gn{J~K z0n+{Zb4yOPu7&+F6u_dHwvv5!?ht(qfj&LaByz)he`u9YD3L~h-;WFcfM&8Vv%sWV zV6$3zQ;?^t9jLIzFR-VjyEIPkFZ%>=6u}^2>hHn+pe`| z`ARr+s%P>1P3LIG=6om}1)hiN{JvX3*B*%Bo{-(`L`U=PQWD$6a9M@3-Yr(x>tkY{ z48w!4zPaK!)3SAs1yJ;JD^EuPgm-oo9$mYQx|1Vf&9Kcv7I*xy5|Mtwo8zY(hcsN} zZ1)R$%yDl1xz9M;vC7ltKPsU`Ddu|XBC~`Xbts;5`Oji|#Mb$7bw|Gf zoCQ<%ddufl+G#m``*f}O3f4uA2gS;q#$B)3)BAdE2mg?M-Gtm>9)@Y4DqXeiEL=#6 z8d$zKZxx1I5M@8`3;*mH_O3;=8)gt=eB0^ziL z4@Vbn3c^m1iB=`tyP+;eB`=GrTk&ef3tfe^#!5G?rwMluH-s~~N3P5=ICPJeG;pSw%U@B_gR;6!~-q$*}13wz<*Jfg#9*u;>Cf?kN z=T1)hNK)tRQpUwvs&3mADUs>J{A#Ac&#$U5=eL{8Xh?c{J6_}2@(CXZ08)~-m)4&A zg^Yc>3u5@m>%^F|Mf25MgSucSqZ8`$&u1L%D9QYU$W0O-7po_kmt;=Q`#-DwFDIFN zum@cu$!p!*ubHK~7lrf3jq@|oZ0GLyt=4vAjBV9E!J*fbt*}#8Y{+cGX>qoSEprE$bbNNhA?>C zDk@c-OZ)Ryk71B0uymzrsb&Hu5|vvM&|GwPS*M#W>tEG5Vs`RS;nB)zv`$n$rG(0@ z2mnBDKUDizh6eyljvX*-{r)-G)@-e6|9Ay~kqo& ztzh9|y=0_5vl%0^&k7jRWa|)bM1~0P?vLP6zoP$lwLTkEqE~kR(A{{&dND+R+HPm? zj!Wbc^_$22(rY`lo0?UJqOOL^Z1kh5g56%Tju{cm@ZxiaJ~hbrIaS^(+~~0!a5P}| z@Y+`Yga8bNt0_CyS<%zmzt$r7WUFF(7@njV zSihrqxNNcG#y^C+8f|piYS_o&uhg{`xI15cFTi}?>aH!XSm?C`mY&l6dV zq68#$IeAQKvH*HM5~Kc|*>7^108+E#;HeatD;prxgVQe*odBthlbgd2x3g7E2Q<72 zOLfMh|L#;U8St0tbub50k)Y7T8Y;u{u~W=`|HDHZp}J7fCQTSYla2)M4n#WO+bC9mDn7BEZ$aW@S`WQ}EudtLnjP3HT_zBLMdDHnn z-ot_cj8_FJf^3d9GE+Y5{3P3dkX&*fK2ARrbujG?E-dUUEZS%Aa8r<{0FaD-+3@<` zY=`2q<4Hg|p+t*dK;HlA^q`{Mx!km}TF^LOcd?v~Og}LvT*h*Kn*SSusPVylH@Qk& zSK?=6O}_;^FxQjdN+W3|Xle9VYxsS6glGWoQIU3g>dhW)U9faV*WYM;Ft(^tZEMgl zJt$1=c2VcBA!L{H6JV*f0RJ7F&+gQLH;J{#!Y(o%i0k-kY0CR@v|?Az^gggXXtgP` zf#YQPwig991HOg%P2yV^41g5!a)klA+jA{B`m9?5w>K?w`=kH;;hzMpLH!c#vN7c6 zTkV${7*>d`)KMQ#s1CTG%)UBpwhAS@R)}!C0{Z)qbW)NgWKT_4excKNUvgY<@gViL zWW8DvvIH$=S_s1XrKi6#oT)d|_LF0909!MNr|oluu(m{<6v^xkd!2SJcrePk^#n86 zbHnJ$+g^zFs93xEyBBdW1-Jt}K1Kz$XK`#EGC<2)+=ZRH_uy~1ml!WVfTVSAxahaI zfCp{Y?L%){!NbBeFb1#Kl_XEc`Ks><<&6&Sv+8?{cK#FI=A!p7?!*mq?y^Y#wofm< z>#lxI?m0#1rY0=Li%8`SFXeU>Dc54dG{y%+D#0%s%u`doXUy}M)n4S+`Xa6^4yd(UWt0@hP5i?6`reTFkxLt!ON zdZcQlEoUXil|iC>KLSB%7Sd(EIOa|_JoO-fqh6zxzOCE5r%Q2$)S2HHl^mn@LBOyX z`K|O}2O}wwj9O!3{DHx_oyhmS+7(r{QaCYfHz;o)>}g^Ox@M!YJ2|Jn$<&z|iIelJO9!56kg*vR2Q@`zyS}QBJ#YB3iE8mI54Lr*12&%uU{- zsj7IQEDd}fyg!XC=q%|JIk7;T<8CTVPwr2uYbd)&824(du`OcZVM|z9Sfn6VvzcYM zo1Ij4vsR#ZTPD@|!YFF6nnrQ^X{L(Z1a+$_#rRS_M zdUqYIj9%XA^%`N!a3~3q)67XXrOEbPt#PG50-{}&W@p9vfgSVL11|724eOh1?>VJ+ zGhROd1GaOs$~qdk82Qm9TEwZa>ROARBpWS|@g}YSfN^vb0vj@bzX*R98Uz***?DC3 zRyQ{2EUYdh?1_9z>o8JCbTf9Kev3_6_0*Dni&^EgJ6$yD3@u37Q2ugsHn+Dsq=E{7 z!>n;n^Z7M44M#h`YH)skJdBh5TfoHpS|(^EDLGwv>`v7!b}y#XX{_sb}tMZs`Jk)h)!h+b$|(+i2{1%Tz^npf&16mz7Q9 zv6>OcmZe{ltizdHqe^q~NkwwV@YELo1JKke-TUVXd2n=eVpV2>o=K~gER^$SjC0ZS z0;f2PV%~0+Y)|b^O(&>98L|I(d601`Qhn$b!D;vYj}+1o8q8*)DTA7qH*ilDsxuY| zpuO?c-1!({QZy&0L8t5CGom0ThPIr1?)K7?hooAZQlM$86E%C3!IilAS0$WZMqCNM zJW4?irpPkBU3#_hsod&c(-*T}#AGJID78#`>TG%z7Y_|zv!Sf&`Olw#b;f+ zwow7f@IVQPe5zDs73mKEqw(w;y49IiqB%a^%1gT(UGS;ICDB zuc6>G{xGUE*{oQ}adbF~)A0rscO+P>NE%WCLG#w-Fjs^B+FXyEF6W_XlWu9 zMnkn$mSrw^Ma{zoVeQ?jYR9AH>n^yp3B-BIwxy^$WAj@)kN4}&p1@ykF1W7U8tel) zn_OJxefWkcoaaWDev%C5Wb1fukI=`EpSv_%pD%V@)^4I>@>j2SInn_Lhia)*%=a-O z7bUzUYIuC$0fO$%4>@}b^6+PC&ASVKmX92TuR3DGmV00*=u5F7A=UdHvrO9#JAM+12Xgig5Dr*Cs zcR3}ZQ;8|nx-3BREg>LBZihS%{6zQXS*bzWcPDCq<-hXTDJoY#J=SSSCICRx-P#(c zlLzz7f%)VErk@%L3wKe&zg(e4r^sG_{A<129bRkFk<4_RZme$38B$AuMXH0r?l6hydl<42m1{bfAL|&5#81q%a3{rS}VES#`Mn*q_aLK-XFMA4Gri(hJ9OZ`zCmh5k$IAa8Mhl>NC1Raoi_bNfIq$PrmbE@e9WJw4p8}+ zJ&@ZGlnR~Lz^X0w-1_u$Ub^B)-@}N#eY+Fhb}+HFZ}F&-F32m!kAaHCji*xX7$zh| z$mJ=%&6i=P^O0t~GjD7LI?7QNV@QHO_km3SCK#*pK|MyJTI@yeXu@*l2CfZ>%yzEW(ZirW7>oi zjrbcKCw`lYc7JkMoTuuk)}{K=r!Tb)?`tZmIvR|RJK8=G><>{vm>X>n-J{F@4?hWW zkh2;oou<3TYvUGKAd|4*w$7|1IE~sP?TCozKWLL!7Tg%9hEZGAQ@f}mB9#C14F2Fu zMfh9KGLgOYYqjWsV<2E~D__ut>I!agQP>VdFM0R>tJ|-B6s!%pdC}u#HxZbUDik=K z@*mF(#6Ita66^V>c{DPg%rIldQBj6g{EFVgU`i_@ z&2B8kry#^oqz`zMBAzA!(uZ+rFcMuRk*#Wp!?GK zJjgh9CQ&d2mYu(Dw$DReeVJ`m)|Pfe`l$^jas5&_im|9hQIkUaUU3}uM!(r6q~*1$ zBbjKB-R|1bjn*t(i`45GC~{k(X^2*wc;Jc%FCafnwBZUlxwSJV$sPKO)n@z*qJ+FdjUc2y9QE}l%@}(EF zf8%E4BFfGO=i;=!Dw7$!0sUo{{>?=KwdX5W=Cb9uajA+Wr|J)!ZO1jbfgSq4to7Ar ziciks)UIvHO{u^IYfnycgmB$!qW;0%Xv3@uyE&^`Cag5up6szu z^F>WB9vx_VFP3Tcv6}2SK`?E;H&|uJ$?g3cteApAPx^aJN-pQo#D3CKJxTr}K$&9- z_foGp^LfRAXBz4kl$_}@5HiG|eNnFxJ0bP`^l`yC_93j6HQ<9t#`ABq-mQ6ni=T%6P|Q^IS64jZwHTvC-#0i3 z7$zIzf?Ns<^KLCY(M*h+?Wu2K7sz(ntno9t))PTAsRXQcY=s?RI`Z?ac{EdM_pZ8M z!)W-62Hn3V^IY(quZMCuwt5R||I|zeb5#@m^7T7~L*{L}<-C5gF))T(I#sK{Z_nC3 zIvNI_>fo^MKd7bl13oatIqBQ2c35k5(3?CZth_l0DENEcnp>BxF1$BQ+jS!i*xRw@>9W*gQijT*jQ-3z4pe#B+!1^Gu^gC7Z8gv)>Mo|vi0Cjy|6=;_FQ z1B6~?S69z2A^?)4!k>GE}Y*#4nKlP_jJ(DKCU+* zA;}#iAIM}Pg0xZYCpPJG#UqELpb*7oA_@jsShEuwFIo(W@Z;e_KyL1(uh4G|UPl^LJ>4w$goD=-ip7RTl^ zo{EzXhmn?zh=@U8Hv}KZibq4iexP0&0o$2N>{H$|5FZrJWSl)33gKIEdD#Spr%{rI z^ZmYx_1CvSZhiXsSy2;baAvLVx#G});*>z|<(92hBs@+~L33r^UDm{?&W7tweW0}| zPh@OK&3x__!&Kqp)2`YW?wd2tnM`@KqeM>6?`4?#>T-#$aw7jgGmp*P(p%6H%)$SP>x_kfC#Xp_>2oZ}KtPXlaBWlEas(=Ymy?#i@REGIiA&(~6KgZF*0 zNgXyh8wkvvn~hoE^R=Q}t2Yh-6IuJ--2x9-Mq+hYKFCW+>*|>)X2q+Yu&JppY zVL#E7DrUpNmtLyT0ES9LBrr3<4K441mAb-zv1hjrY^{C+^bE=qEb@my0RE&}E_6w$ zFsUih+u#CMhkB)}|5VUgsaxCG^-I%LRoQ954oLHas1mEKXz7$w0t8PgLYKmsjRA%O z(lRnM;`SzXW|ILgJF8w6;3Otj^y#gS&_qK#h?mwtm^BMFx!DZnpegmvY-DgOLy9_+^60AY_LUuN z2k5@){8Mf&_AN5;(kQO@{j9Rb*v=O0iz5^U6p?T_ni$#by^iCj`VUVT0gCc!60GIQ zr|tK_7DXvPFN+49zPoE^DAp`|{2vzp>Zn?;1*p*t!(a5S<8n@u|JU&wr_cGsct*EQ z1SQ~)c1x=#NBJRrguK)$&s~Wv#G;t3cGpKC(MN~xLS)I(56&CPPiImzvSz9s^*#{Q zP$fX*$xYMy*4m}#)X!gcPxA5c!5KN=akR7nQDi`wMy5#C-l(FfzOd)rSmdJMDG2pv zRd%Bb12K}j`P^~(9=x%qi|%SBgD?I4YAkK%&1E%zCVkjRLk_~1tDn<+Yrn?s@9ndS zc7v$d{Ph`RR1C{HzoXsiX%#1ML^m#%GcLfBr4`U>Efz(ZAT!It=zddim@>vxsM3cYp=-uYBFU^C;X^E`+us5Kt0nN%eK z2)MiK9C0eM9woHPm$hE!tx&1%W0SBLSsL6A*Rfmic)V?kP+CD=nh`VU^ z?>B(-{#>(yf|!w+*Al^My<12=Dn<8lb5O?r1K2<(zf#4+9)QF>-mq)$2DegWXmh?6 z6c5)lKJ`LFbGZNjv`zayqb%Rk?!?Y6wnz3XybwXVIatuFRIRoZ%PiGuTb80EDm#@- zCR5p4TUk;R0Htcud%B&70svN`w6?Ss$!*kX8_YVFE8&>FqL4{bXlWX9h%j2J{MmsCl*DC6*d+M zg+ytuwzi@vT4`l3V_7R}2ZdB()NAadN#kcN#$s`n4gml*#2h$xd&c;73&p#tpbUpEC$#Q7q(RG} z`ZLqB-wf>|mRVV;gny7=d2TZHmXk-U}8;WLHbgcL4-u1ND0PnujRGRbGgA$)#-4v87 zc^dKv0DzYC@6xwqN&jj-j#g?1iAZXxcC=DTDGHP-JGr=^mCzCummT^dGNrn=7s`9S z<6=Zqz|Q;8neneq0xhcK+t{O=f6cOf5s7&R&)?BzJvnpr3KzO5E{~HsS83tv)u?It zw4_*()Y95QE?3#8t*vQ6^a*@_L!+;7jr_DnOXkfOJmav7;*HCRExnSXBr9euxwyWS zyCn+%$ZRwdS|S!v0AlNMeFyyB)~nO*`}gXr>=HE&f6N-ce&!WNB?ADjPW@q3X&ehc zEK2EeLk7+|lyJ6{y`#cHX6ss^j)k?g9h;S&nV5q0OJ{eC2zi#cbBX`hDMA;12c~+b z`C}VZrT_@ROIM$2HvLWm>*QV?eoASvQDic zK?Jajuw$E!K3qO~wTcD+DB(A3sNaw&BU&YPT5HSXR2_a_nXvXofD-@!t*GQ*|J`_} zC@~d`Em#*_QbD|H!^iB#Y(VV<+#hlQIB+vkshzvzl{zS1+G6am(CRPAZ0QS=&}j_G-Jh zf?5m!KugQ|H)RV?C$Vs==kN0WN`a;rMLAoPot+En0%IpFD?e`D25U=Z9{>QjR2?z2 zyT4j(%hHsh=Fp8-o;ajh460zurg}S7aB{MB@ha&Slw+=|{}BXpNn2kXKHbnQhMU%8ZT_v`fE3(H`pXpvkZDSk5YzPTHfPoK3* z{O;Y@F=a*anlUxy)|Dns-KiAO0FZLMJx$Rx!_pLuF$T(}$JlMP?8N{8IO_^4q5)`@ zAqB|`C?d=a2?(~9zX_M}=k)HCyZoYwz8960Ui=qJ=VsZ*CSAI+@$55k4J#S|o*f-G za_%-l0BP=Q-m?78tpkfT+;w&JE>*5^$eO;luPlGbRrFQSK=8iX8BLqk1OQ6aNF9IV z=;edUx4x?G?pC8_-ACIdy?D4Simg%BtHFW=Cl~x5d*2-w)zQ6wZr!`PEWH;+q$w7P z#)1tMv0-o6(AcBV7>z9&H6|K+jlEawy`m^K1O-u4dXe7C_T5|N_Xn5&`kLhXdy|+q z`+WF=ySL3fXXeZ^=ggd0b*Y_a%VA@`F;JHGVbVDC#lG3$(f4kiS@}kXHESrleQsZL zb7Cjbz%31dSi{t_X&|MS2VdoKe3u<6TIu5A?zj$0BB0%<6fl|=fuBC zN%|kFQF=vwOzb^%Rm!s$FIe2@^X1dbZEBrX6~S_4p&a^j=Z*$>G{36 z$k+rce4U$d^4#<4-kdRS8uKJNueb!5244*l9}GJXA9Hfwo*f_Cs}UDT#5B@Xo;eqe z0L&T%Eg&_elQwbr8H^T(?u6?_;&cyyIXEV$Gra}Yl-UV^B2XH zYJ}LT@)5a{O^}4F#bBTEy%*2NJvwya%&B@$7}~?**tTT} zFK_+4dP&85S(PbE-&gU^a*K-u19vgte{VSSr{~5MG})P{)uvl!-q702r1p42Ri0H; zsghYbTbUREfTl9HR4aD0u>hng%F9yeSz2miXKhVlg1jW7M4_{=ZEPwP1LAV?i|p)c zMy^_UL4HXoW8!3MVTu7)UYK5~)|=b9nZ0vOmlR}3tr|%TYlv#ZE>z_wkyf5k8V7{b zRk=lF6&NjZaC9a(WkG(nmd7mZ-HjQN)0F4t=aN!8dmAeP10-m&b4nZy@iAX06=VUcAANk zrwGRYfY-|l)ug?t1OpIwO+jwDmd8!Z8(5e~OY@VJ93hk9ViRYEugWXP2TFzn%)zMv z34D3>Ytq`oSS;f8^1MnVQk98}9c?Y@XD-rK6;u(H)<#tIJmB)YRGFOzMPPsgc}aSS zLT7H%*i1_0XC`V80sul}-N3;X2ev3X!?b}%bySGeR%91x8#S=QG0-Wpa*O2vK#MJ$ z>>d7>Di^1zc$=RC06>~JH)u#;sJtkxLa7y-I9kyaO5D!ONQ`(*ex=TWRG0H+cINMv z&LE*QCkad&SQ;B4gwz$;MHN+yv4fqZIrjV35b4!L6@saak%-fj=ag{`?PZ0z8Crp| zcXDG0OkI^*P$oAup>UC-nUNUry1blJ9cJv@paG6_1-WS&4rFFdR;I@K%4|7dV`cn4 zc}42V?7|AAk&#%y%xo-7s*2MqG)N>OtZW-o7%0ng%C(e}oh^m|t0~Vf$mKBF%C?cQ zm{u0NAuK(`6!DJR7339{;L?T-tVOw5Db?{S6B{=(Qkz$p%ksFDy{oZUByg(y+zg#S zm|8Y8#!K{+y;@#oDw7oH#SSv8tRSOGqi1CHc2*|kMY$HX4Fz>>C2MA3VuTP^kdv$t zB+d;R8RFvx{G%AjZ|BA}Wb`+{00Rs#zyJgO8LXvdqKT0akd#4U1{h#~0R|Xgz~2Lv z;b-#TLZV;0J1{mcI8?!^~)Q>xM0I-XKu}4EXEt=dXO`D-SN88C}ko7HPj+wZD_=ud{L0r3q7KE;h52 zvPLbotXxp1D16z@?`FNI9MVk)#IT{I^YSrYnNeyQl`EJ~;bzhv%(kLsGooDPG z*Cb`}vVCeKNIafXshjWCcb2usxr-( z@Ad_nKUuu$q#pRx=m+23NNHzQ`$pkW*u0%5&N)v$v!ai0W!8hw=d5X9FU9OSuUj;Y z_}k=#6t54@TfH|f*Y1A!NfA_TT{t0;HJ2Bu=B(dmUU+TUwi6^$iQR{9STMeBTM~|L z{37h)o&Ja3OlnB!%MzB(n^VSEIr>jr9O56j_48xNBCIOkFLcY)K)2erDU#04TE35w z;Ejf^pVQN$whGEJ9(=dFCXk~S?&#)XRPXLbN5)t7+0)0IG}tNw4EURTErjW~?+g?-Hppvd#^aQ;pfu{CwJuX7PB^= z+q3=n%03n+Pd_v$8vuZ`nzi}d?(N4{_Axzm_MxKiUX;VMox8(=BoR-Q!oDMSLVrBG ze&zDL3x6oDy9Tr{{b^;;n$>IfI;o%LumC`GA2e^twqyH2?p}jj#ZkRn{<4-4bpUeW+0gDc8Ubn^0 zWB7(GhvtrGS-VT-E5cKayKdih=;y5mU9Ba17KfbA)geGjMg`r<=Ujt++_rSs|5p}1 z#KrF2JfwfK8`oX~;?7R=>Nm1q@4lT6#gzzL!PI^&KOgSjbI7=qGHt#4svb`2HK_NA zyXn=3nGbdi?%5)sXW+B^s?yjKL;JMs)X8`It(RP7?5KWyauqQndikt69xrH1#td&i z>g!EP1b~n#`}X)??=IcipL|(@_|iFp{pODA+`enCm&Mxm>Xga6)kjuO=&)ecTAiTV zG^b~$PR)i*`?gfgo!a>M+)bC34{6nX{92X3MeiElrHfb3AtR%6RR+^#fB}CMYXQ*Y zK4{+DX7ZzEQ-}D~{#|0__2l|PMO9klo%r~Y`c_|=a;{kmyICm%hj;T-W=2do>lxI- z=@*Z|gaM6%f4sSS&5-JKeR;9BGrDcIHzFJ?qz@yW>q{QyCdK5u+uZ2#6^>qb;cm%&}C|4+IerVm*B(ftL%*vcjR z%spkro2QTBUYB#9h|ma=##q6dBCYnyrI*|Cyu1jAmSvc$m&32=Z@w;y@G#<;lhY9qs-LYXOkHV%;^P{xhdm zK0aPele&-DaPi2tjl)AqS;Ud98;(CXHP8IS_4)%ClMZ{1&FlS6ftqhOJy>_>vTD`roc~Ri?{8l_ zwq@y<>7^X-xZUEt5vQi$5s%({u(all+~}f6Ek{lJ@j^tz^Y7a}e3V)^Z1(rdT!r&*2hNnn5k{p~FiD*e8m?_0gJp1Tm4 z^yLq&KfaN#YrDy-tInRi`qHgkYh&h9nSF&xTC80?_r~%4jzQhbibMdw%3n?UK61hL zYd)R~h$KWEzuM5Ti+PJ3UE&Ke&&*l9_u?x_%C7I0{~WeycI_)^9GQ3o&GuryyFpX+ zQ*GdOgU&{F%2~U7QQD{gHxb00S$e6Y{rZVE|A@rx7;duZOngp8;{9V|50i&O{exw@ zf0W0&wCo!EU)kM$$G64Wcb89nFOk3+xm3l#9X(1(W+^I!zbj3%T zhk`SAw>P4zE#sqOOZO&9`}j2|D=lUJvqK9Z;cb=3&)$TQSy`)7lzPONm`X_;%q47v z{y#W|^eiUE^(nKz{=u(HppaZ?)T}N$=gKzE7>u_WZKqDsYwiB1G-N+6_@`Sc#kW5h z%(Vf318WiVWv^3;?QG3BUawRt>z%b}+Sy5$x$2T~v;_eGxi7+_imV3*wgi1qVtS>u zm6T^$m0Htd%852AR-3YQ@fEXPjqn$-@wQHOJjYd)l_3DGJo;9W(E)1`01zVF+xGD& zdwi-vCszsgBy8z%b>G!N%{6MROv)Ja4T3J}#CIoj{Z{vArcrB+?7O6GxM|UK)U}`U zLOv&uob>4&T=L=s6)@RagoB`c6t>&G*Mvr9QmwjDK!D@8pi{_ox>xaOmiE>uv9V@N zT9E)CD8s`}`VF68PC!}Oop}p4|FHRh40ODJ#hqPtq%z>A(Z1CxV2i_(Fs}vXHJqp@ z`Qfc(W@Kn*+9 z-LJ(wk+*DC$QoOVbR`uUzzG}&wY(evK&ZSBb|YZK2ooFvysfV$6!&PSQh4;Y7vmu4 zqQZ7q22OCZlF3U_OLS5x60{1rPT(^mw{3ZdeZM$ZsZg29q}ZoQTvYOk@^UGLlO|H# z%cL?V2d73(7BMO{~Db4!R@XByZq0sul}R*;jg(z;5Rx=|_2)VwP8 zQF5N2C1S-^@h{VYrXC75P2RZSA^-qJh@rAdrL#7s@mf?7!*D-m^ei^fySUA;-Dh)E(>l)Fm`kYi4wf zDL4OS{TXWl03iRxoii_+4GwGxT-pBRWA3CBy9a!=W3Inggo$OKRXEt%m>QF8)Uo*o zA`^_9yB|7uP=rI$&9fFAr&NE5t|(?k=+t7V-@(HtWNgmnwMUWwdYzx&ZqT|NOGX;> z4f>qT>y9P^^g1`M{owW6za9F0yFEjD_2@O{pbHI^S=Yu-{}EjJT{!uZaYeXrf=PRl zTKuR!J|OLQ<>s1=D-XT_=zVdqZ|{}+e+W%DzNclt(qCvuaq^>MmraKUw;}-U9txem zD;nTdW%dtSCUjgpHXsc(TDIl1#otL#OTOJ}oMII<^Ba%}(FF<;FnzgR|i>Sv70fx+M6-y$m?!r&x7m@$hfE%o*6ZYu3~a z*P2>+ZrV9-=pV;Ez zJ>1PoR+al?+VuIwdegDr?rlb^zW!lXd}(FB$lXQ_Cx@R~CjNw23vOX%RQ(@iY_n}q z?`;5-nbW0nr%tb*aP>v5bNh+=M|%PgzP&?!jEI@#YzhGB;a`qeati@W%z1ly+lv3g zTNA>ghb{TR)?D1NZRbhHW5xrO{bXzK(c;}VADL4n#&-0cNv%??MuqKe3jijLJ*^`A z{m=N{y|Q*+u;=f!4*{q`$w)4#Q=d$hgXyv47LFus2GO||Cg-HF`YJoxpOgUAdpzyJgOR$zc(fQ0{_yCj(jH~^m>uRgH& zpC|$*Ayovx7iRvB@?!w#e?jU03t#bHfY53vczOQ@sa>{gnO>*U#fH=B%0ICzl)ZS& zR3Y&(s-68B7g2#T#a()VCQB%-_jZN~nk5bhCS+PJJEx|sooCTDh|ep)+k7tWF^qJ! z;ZqX;0qzqb?mLpOAi1n`%)SlNZ<@%j760}H(&{mXE|Q^BNINl?mSU(7HSMEeFY%zy zalVi*E&+_9x_>DS=#A;K`H~9UEr{tmfo|f;r920|ZY!cJM7^eoI(On8bHq|q=ZWIL z!Gui5z0Lk~#D%*DF?}Y`o~~TVa}W^Nwvvqak}%bAnb|;^(!q0>4gpY}EL7EBABTGn z7xx`SSkYW&8s-`#9WPqH89|84xtzkkQC!rJ)#CPnv~M8o z8%RiUx$H8k^B3a4ez>TT&s8v^eh{?@Bpcdr>90ZfZ<}eO29i+==~jWHjTx8r25&J; z+btazD zt_|6=f?vPge#|->} zZsEnfj-h%_hx}M1NJSy@P<9L=OsTeClXxm$sRRHjxriuL3f3~#-3FM(%#g2W-}X?I zAXIAqSYbSanU20((ktA(C)4+Hx>++mBOb9lNE=4kZ!-V@ta^xAn)A8&SkpfG44I}<#SZt2ZuzCb#*`o~IpFSEv8EUOoZ7#zb8LV_UhJSXr1 z&vO!~kx2B{WWvCW=s}YS`vzFu{1cd6Ace=PPwyrCCPV!d5CZ?^vgXV-!Fe+6W(xpd z>`j?i6PA_$fQp`KFK%K>OeMj7fIBkYmYT4&yvYdC)*QpN?7iKZ+fm|ygMhLZj~Jmn z_YrcTgLzK{3^1Zfe{;L`Rhe`|;Cr{ReClmX zW{(jV08aE=jaNRjZ+f7ZUKkcM;v%t#b8RCi$mZ#kOwbi|wX zCo39s~smG|DLM8PJc5_S#%0Ae3eQ!{ngM!w-Uq{H8t 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

W@Uj^kKY!HM}rubDm-E;i(7A%`;*P1`+ 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 mH|7P8;O_0000YRLmvXQF2*y!STnMP1 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 Date: Wed, 2 Dec 2015 15:23:52 -0600 Subject: [PATCH 1764/2553] doc: helper tool to convert from wiki to sphinx --- doc/sphinx/convert.py | 71 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100755 doc/sphinx/convert.py diff --git a/doc/sphinx/convert.py b/doc/sphinx/convert.py new file mode 100755 index 000000000000..c5e3c193d05d --- /dev/null +++ b/doc/sphinx/convert.py @@ -0,0 +1,71 @@ +#! /usr/bin/env python + +import sys +import re +import urlparse +import os.path +import urllib2 +from StringIO import StringIO + +import requests + +def fetch_images(url, dest): + + print("Parsing image URLs from %s." % (url)) + urlparts = urlparse.urlparse(url) + r = requests.get(url) + for m in re.finditer(r"(/attachments/[^\s]+\.png)\"", r.text): + filename = os.path.basename(m.group(1)) + image_url = "%s://%s%s" % ( + urlparts.scheme, urlparts.netloc, m.group(1)) + + if not os.path.exists(dest): + os.makedirs(dest) + + if os.path.exists("%s/%s" % (dest, filename)): + print("Image %s already exists." % (filename)) + continue + + print("Fetching image %s." % (image_url)) + + open(os.path.join(dest, filename), "w").write( + urllib2.urlopen(image_url).read()) + +def main(): + + url = sys.argv[1] + output = sys.argv[2] + + fetch_images(url, output) + + print("Fetching %s." % (url)) + r = requests.get("%s.json" % url) + text = r.json()["wiki_page"]["text"] + text = text.replace("\r", "") + + with open("%s.rst" % output, "w") as fileobj: + for line in StringIO(text): + + # Images. + line = re.sub( + r"!([^\s]+)!", r"\n.. image:: %s/\1" % output, line) + + # h1. + if line.startswith("h1."): + line = re.sub("^h1\.\s+", "", line) + line += "=" * (len(line) - 1) + "\n" + + # h2. + if line.startswith("h2."): + line = re.sub("^h2\.\s+", "", line) + line += "-" * (len(line) - 1) + "\n" + + # h3. + if line.startswith("h3."): + line = re.sub("^h3\.\s+", "", line) + line += "~" * (len(line) - 1) + "\n" + + fileobj.write(line.encode("utf-8")) + +if __name__ == "__main__": + sys.exit(main()) From 0c602c5f19d69b3a9e14557b0a0d0878d49c2b35 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 2 Dec 2015 15:24:12 -0600 Subject: [PATCH 1765/2553] doc: pcre --- doc/sphinx/http-keywords.rst | 1 - doc/sphinx/payload-keywords.rst | 1 + doc/sphinx/pcre.rst | 139 ++++++++++++++++++++++++++++++++ doc/sphinx/pcre/pcre.png | Bin 0 -> 41419 bytes doc/sphinx/pcre/pcre3.png | Bin 0 -> 21204 bytes doc/sphinx/pcre/pcre4.png | Bin 0 -> 22114 bytes doc/sphinx/pcre/pcre5.png | Bin 0 -> 20860 bytes doc/sphinx/pcre/pcre6.png | Bin 0 -> 22648 bytes 8 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 doc/sphinx/pcre.rst create mode 100644 doc/sphinx/pcre/pcre.png create mode 100644 doc/sphinx/pcre/pcre3.png create mode 100644 doc/sphinx/pcre/pcre4.png create mode 100644 doc/sphinx/pcre/pcre5.png create mode 100644 doc/sphinx/pcre/pcre6.png diff --git a/doc/sphinx/http-keywords.rst b/doc/sphinx/http-keywords.rst index e4363c79ce4c..63a52d56b587 100644 --- a/doc/sphinx/http-keywords.rst +++ b/doc/sphinx/http-keywords.rst @@ -11,7 +11,6 @@ specific parts of the network traffic. For instance, to check specifically on the request URI, cookies, or the HTTP request or response body, etc. - Use ``http_method`` to match on the HTTP request method, ``http_uri`` or ``http_raw_uri`` to match on the request URI, ``http_stat_code`` to match on the response status code and ``http_stat_msg`` to match on the diff --git a/doc/sphinx/payload-keywords.rst b/doc/sphinx/payload-keywords.rst index f9c34b1eeb4d..c6889cddd894 100644 --- a/doc/sphinx/payload-keywords.rst +++ b/doc/sphinx/payload-keywords.rst @@ -4,6 +4,7 @@ Payload Keywords .. toctree:: :maxdepth: 2 + pcre fast-pattern Payload keywords inspect the content of the payload of a packet or diff --git a/doc/sphinx/pcre.rst b/doc/sphinx/pcre.rst new file mode 100644 index 000000000000..74f8024d91a3 --- /dev/null +++ b/doc/sphinx/pcre.rst @@ -0,0 +1,139 @@ +pcre (Perl Compatible Regular Expressions) +========================================== + +The keyword pcre matches specific on regular expressions. More +information about regular expressions can be found here +http://en.wikipedia.org/wiki/Regular_expression. + +The complexity of pcre comes with a high price though: it has a +negative influence on performance. So, to mitigate Suricata from +having to check pcre often, pcre is mostly combined with 'content'. In +that case, the content has to match first, before pcre will be +checked. + +Format of pcre:: + + “//opts”; + +Example of pcre:: + + pcre:”/[0-9]{6}/”; + +In this example there will be a match if the payload contains six +numbers following. + +Example of pcre in a signature: + +.. image:: pcre/pcre.png + +There are a few qualities of pcre which can be modified: + +* By default pcre is case-sensitive. +* The . (dot) is a part of regex. It matches on every byte except for + newline characters. +* By default the payload will be inspected as one line. + +These qualities can be modified with the following characters:: + + i pcre is case insensitive + s pcre does check newline characters + m can make one line (of the payload) count as two lines + +These options are perl compatible modifiers. To use these modifiers, +you should add them to pcre, behind regex. Like this:: + + pcre: “//i”; + +*Pcre compatible modifiers* + +There are a few pcre compatible modifiers which can change the +qualities of pcre as well. These are: + +* ``A``: A pattern has to match at the beginning of a buffer. (In pcre + ^ is similar to A.) +* ``E``: Ignores newline characters at the end of the buffer/payload. +* ``G``: Inverts the greediness. + +Suricata's modifiers +~~~~~~~~~~~~~~~~~~~~ + +Suricata has its own specific pcre modifiers. These are: + +* ``R``: Match relative to the last pattern match. It is similar to distance:0; +* ``U``: Makes pcre match on the normalized uri. It matches on the + uri_buffer just like uricontent and content combined with http_uri.U + can be combined with /R. Note that R is relative to the previous + match so both matches have to be in the HTTP-uri buffer. Read more + about [[HTTP-uri normalization]]. + +.. image:: pcre/pcre3.png + +.. image:: pcre/pcre4.png + +.. image:: pcre/pcre5.png + +.. image:: pcre/pcre6.png + +* ``I``: Makes pcre match on the HTTP-raw-uri. It matches on the same + buffer as http_raw_uri. I can be combined with /R. Note that R is + relative to the previous match so both matches have to be in the + HTTP-raw-uri buffer. Read more about [[HTTP-uri normalization]]. + +.. image:: pcre/pcre7.png + +.. image:: pcre/pcre8.png + +* ``P``: Makes pcre match on the HTTP- request-body. So, it matches on + the same buffer as http_client_body. P can be combined with /R. Note + that R is relative to the previous match so both matches have to be + in the HTTP-request body. + +* ``Q``: Makes pcre match on the HTTP- response-body. So, it matches + on the same buffer as http_server_body. Q can be combined with + /R. Note that R is relative to the previous match so both matches + have to be in the HTTP-response body. + +* ``H``: Makes pcre match on the HTTP-header. H can be combined with + /R. Note that R is relative to the previous match so both matches have + to be in the HTTP-header body. + +* ``D``: Makes pcre match on the unnormalized header. So, it matches + on the same buffer as http_raw_header. D can be combined with + /R. Note that R is relative to the previous match so both matches + have to be in the HTTP-raw-header. + +* ``M``: Makes pcre match on the request-method. So, it matches on the + same buffer as http_method. M can be combined with /R. Note that R + is relative to the previous match so both matches have to be in the + HTTP-method buffer. + +* ``C``: Makes pcre match on the HTTP-cookie. So, it matches on the + same buffer as http_cookie. C can be combined with /R. Note that R + is relative to the previous match so both matches have to be in the + HTTP-cookie buffer. + +* ``S``: Makes pcre match on the HTTP-stat-code. So, it matches on the + same buffer as http_stat_code. S can be combined with /R. Note that + R is relative to the previous match so both matches have to be in + the HTTP-stat-code buffer. + +* ``Y``: Makes pcre match on the HTTP-stat-msg. So, it matches on the + same buffer as http_stat_msg. Y can be combined with /R. Note that + R is relative to the previous match so both matches have to be in + the HTTP-stat-msg buffer. + +* ``B``: You can encounter B in signatures but this is just for + compatibility. So, Suricata does not use B but supports it so it + does not cause errors. + +* ``O``: Overrides the configures pcre match limit. + +* ``V``: Makes pcre match on the HTTP-User-Agent. So, it matches on + the same buffer as http_user_agent. V can be combined with /R. Note + that R is relative to the previous match so both matches have to be + in the HTTP-User-Agent buffer. + +* ``W``: Makes pcre match on the HTTP-Host. So, it matches on the same + buffer as http_host. W can be combined with /R. Note that R is + relative to the previous match so both matches have to be in the + HTTP-Host buffer. diff --git a/doc/sphinx/pcre/pcre.png b/doc/sphinx/pcre/pcre.png new file mode 100644 index 0000000000000000000000000000000000000000..83c3185671af4f9e19fcc4a1eb479b97c8c414e4 GIT binary patch literal 41419 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 _~k=MC`WZ-AF^IV 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 literal 0 HcmV?d00001 From 5f9d265fdf509ee339dac37170d4dc7bbb5bd37c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 2 Dec 2015 15:55:17 -0600 Subject: [PATCH 1766/2553] doc: flow-keywords --- doc/sphinx/convert.py | 19 +++++ doc/sphinx/flow-keywords.rst | 104 +++++++++++++++++++++++++ doc/sphinx/flow-keywords/Flow1.png | Bin 0 -> 24838 bytes doc/sphinx/flow-keywords/Flow2.png | Bin 0 -> 26325 bytes doc/sphinx/flow-keywords/Flowbit_3.png | Bin 0 -> 44901 bytes doc/sphinx/index.rst | 2 +- doc/sphinx/rules.rst | 3 +- 7 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 doc/sphinx/flow-keywords.rst create mode 100644 doc/sphinx/flow-keywords/Flow1.png create mode 100644 doc/sphinx/flow-keywords/Flow2.png create mode 100644 doc/sphinx/flow-keywords/Flowbit_3.png diff --git a/doc/sphinx/convert.py b/doc/sphinx/convert.py index c5e3c193d05d..b750ec6f2170 100755 --- a/doc/sphinx/convert.py +++ b/doc/sphinx/convert.py @@ -43,9 +43,22 @@ def main(): text = r.json()["wiki_page"]["text"] text = text.replace("\r", "") + inpre = False + with open("%s.rst" % output, "w") as fileobj: for line in StringIO(text): + if line.startswith("
"):
+                inpre = True
+                line = "\n::\n\n"
+
+            if line.startswith("
"): + inpre = False + line = "" + + if inpre and line: + line = " %s" % line + # Images. line = re.sub( r"!([^\s]+)!", r"\n.. image:: %s/\1" % output, line) @@ -65,6 +78,12 @@ def main(): line = re.sub("^h3\.\s+", "", line) line += "~" * (len(line) - 1) + "\n" + # *bold* -> **bold** + line = re.sub(r"(^|\s)\*([\w:]+)\*", r"\1**\2**", line) + + # _italic_ -> *italic* + line = re.sub(r"\s_(\w+)_\s", r" *\1* ", line) + fileobj.write(line.encode("utf-8")) if __name__ == "__main__": diff --git a/doc/sphinx/flow-keywords.rst b/doc/sphinx/flow-keywords.rst new file mode 100644 index 000000000000..f314f5978f1c --- /dev/null +++ b/doc/sphinx/flow-keywords.rst @@ -0,0 +1,104 @@ +Flow-keywords +============= + +Flowbits +~~~~~~~~ + +Flowbits consists of two parts. The first part describes the action it is going to perform, the second part is the name of the flowbit. + +There are multiple packets that belong to one flow. Suricata keeps those flows in memory. For more information see [[suricata.yaml#Flow]]. +Flowbits can make sure an alert will be generated when for example two different packets match. An alert will only be generated when both packets match. So, when the second packet matches, Suricata has to know if the first packet was a match too. Flowbits marks the flow if a packet matches so Suricata 'knows' it should generate an alert when the second packet matches as well. + +Flowbits have different actions. These are: + + +:: + + flowbits: set, name Will set the condition/'name', if present, in the flow. + flowbits: isset, name Can be used in the rule to make sure it generates an alert + when the rule matches and the condition is set in the flow. + flowbits: toggle, name Reverses the present setting. So for example if a condition is set, + it will be unset and vice-versa. + flowbits: unset, name Can be used to unset the condition in the flow. + flowbits: isnotset, name Can be used in the rule to make sure it generates an alert + when it matches and the condition is not set in the flow. + flowbits: noalert Does not generate an alert for this rule. + + +Example: + +.. image:: flow-keywords/Flowbit_3.png + + + +When you take a look at the first rule you will notice it would generate an alert if it would match, if it were not for the 'flowbits: noalert' at the end of that rule. The purpose of this rule is to check for a match on 'userlogin' and mark that in the flow. So, there is no need for generating an alert. +The second rule has no effect without the first rule. If the first rule matches, the flowbits sets that specific condition to be present in the flow. Now with the second rule there can be checked whether or not the previous packet fulfills the first condition. If at that point the second rule matches, an alert will be generated. + +It is possible to use flowbits several times in a rule and combine the different functions. + +Flow +~~~~ + +The flow keyword can be used to match on direction of the flow, so to/from client or to/from server. The to_client is equal to from_server, same goes for from_client and to_server - there's no difference, both names are supported due to historical reasons. It can also match if the flow is established or not. The flow keyword can also be use to say the signature has to match on stream only (only_stream) or on packet only (no_stream). + +So with the flow keyword you can match on: + + +:: + + to_client established only_stream + from_client stateless no_stream + to_server + from_server + +**NOTE:** *from_server* and *to_client* are the same, and so are *to_server* and _from_client_. This comes from the original Snort language and we support it for compatibility reasons. + +These options from the different columns can be combined. You can use up to three options. For example: + + +:: + + flow:to_client, established; + flow:from_client, established, only_stream; + + +There are different ways in which can be checked whether the connection is established or not. With tcp-traffic a connection starts with the three-way-handshake. In the flow is a part in which the state is set. There will be checked in which state the connection is. +In other cases there will be just checked if traffic comes from two sides. + + +Example: + +.. image:: flow-keywords/Flow1.png + +.. image:: flow-keywords/Flow2.png + +Flowint +~~~~~~~ + +For information, read the information on the [[flowint]] page. + + +stream_size +~~~~~~~~~~~ + +The stream size option matches on traffic according to the registered amount of bytes by the sequence numbers. +There are several modifiers to this keyword: + + +:: + + > greater than + < less than + = equal + != not equal + >= greater than or equal + <= less than or equal + + +Format + +:: + + stream_size:, , ; + +Example of the stream-size keyword in a rule: \ No newline at end of file diff --git a/doc/sphinx/flow-keywords/Flow1.png b/doc/sphinx/flow-keywords/Flow1.png new file mode 100644 index 0000000000000000000000000000000000000000..8479a91395259e1065049f0c56872149b0199274 GIT binary patch literal 24838 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 bk@s|?$M;#@t8m0WHGtwrHQ7q(&p-YT&UZ!0 literal 0 HcmV?d00001 diff --git a/doc/sphinx/flow-keywords/Flow2.png b/doc/sphinx/flow-keywords/Flow2.png new file mode 100644 index 0000000000000000000000000000000000000000..b1cd6ae272b07f2ea622f7e726d95dc0ced0a244 GIT binary patch literal 26325 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/flow-keywords/Flowbit_3.png b/doc/sphinx/flow-keywords/Flowbit_3.png new file mode 100644 index 0000000000000000000000000000000000000000..ad846241301ceb55a542928918d17b0576bab9a6 GIT binary patch literal 44901 zcma&N1ymi&x-HyTAm~B@!GZ?}?iSpFTW}BV?ykWhxJz&k?hqV;yDi*x;VzH8@45S) z^S?XB|JE2?U8}yT8dcpjs^!%PB>zgbf{77g@%{fR`P=l5{V$XM|84(|rvKRgv+3Xc|KCmjs?;dFEruZI zOpYLw;D3k!y@FM>mQH368XAi5MT|0}MZp3@+T9%lim0-W$0va$ZD%{oSRLCvL=hwI zB?)PfvpNb&^e+D<#>XV|E|3`~_T}Y4fg>Z$X8-yYwvEddSq|iqwJ4zPEqU#y{6Ub4 zp~)^3H5(MR<{J+N^(+^#L&K^*S0xIODZvVYN&g;?gf_u7+Cro>J1N43@nxZ_r)O7{ zL4WzI&=r2U%2Ku<3`7xi5JeEg0X3Rn&>vN<+c9e0P`YZ$nkt#_2@VeK2N(ovr{tj+ zQY|)lcojz`1;T`W(DnqL9l;yMa}{HUrEes+t<>M z|Ms9m!pJy;GGs$~UoKLOzQ}R5Ti7*y5DdYOfF=o~Lg(i=R15o-K;`oXl1cs55;sM) z(w$c-K9`=8^V27W{Xhbc#rXcfy$fYX(Y(V{T(wYcDRf7bav;m$AKZn?;ONThf)W%& zEDbVlI)B|8CP$Ip6KN7POcyT}gFOZslgIk=$W@irv!$>(G|!g|z0A|bisIY z6D^rYstXpbQfTsz6xDOp7|J)Bx8aq$PaOVqPkX^PE5gFXg&j@Um=ti5TaQf#+e-aY zKeTtVKZ}$8;V!9;rNtT`^r26VwH6o2d*9+!gAWuiiLpbTW-$UbCNO|E)hlw}q=5nE zEfeyka_4fc`8@+ijSEY5##Ap@{~F?%g7?zxe8Ad(T#c0X$AHAvt5wR6LRDLN+3Y=f z)4pr7tzSo>k&OurM!~g)qEHz=jS37jvQf-Rv|MmpT++K1sFyedfxI2R{f%{h#I27H zYP1c)0z$SQSu~wB^!0Pf&`#f;D;yET_>uAR^Tgo_NqPy>kfHPSKg^B^UUVqttl%CU_xtTm?8L?YB! zMW~4`qmoZ{K9~$OfHFJViLuR)6{c^u+I|BF*uph#ysONd9ZYGlx$AMjQG65@I*-LH zy-e5P=XO~>hXl)dsagcCt{ylH&z@H`@G}x0sWVQGn|RkWSIN4A&V4eLvSY6{m$Xr= z8k`R`l{pb#w5BO}&*KDzAKTNI=;5J}H8L|&6@2!7-lKdnB2a5OEUmlG{&amQRiN?2 z!^d5HI>}+7qHX%#ey!Shz}IhP8b#9mbBEbvJHPBhkmwF&#*GE%)S>L$vDj)yX3 z-G!o=+u*@|xv%&)69bhxdsvHBn&0`9M`?XHM-~--IC5t?ZhIORCh8DWn8y6Nqn_S z;dVXT(V-4_QGSg^RN50IZKwnzbiRYLt zvKsq!?`0suh&!;A<~s|W?_H9Q`h~dP_J$$@B4U2x9)vi5E>Tw zv2x4#pHMb_2$OK2bvGf$>-(i6A3g3<^ z?OhnRoQ7^=s{CgB+5chA2GU`47){i!QtX}f$q8Sz97Dx+zu*6}_(uDP*?>Z#rSnMd zZS5yztlsHnNvse8IbVUUVx&c1+nP#0hw(sm1Qsc3T=hqLvD+u7iH`&WKk?Zg4j;a; zy^Fe+RL*?|7YGwU0wtRU2Qu`EX%@_RjuuWBMI+QadyZBYr^K1;=eonb5RW? zcl_uNHTS*@Ps-j|HcE~d9#|vxt=*|l#3#w~b$?oUod5k!6@66cUK}L!gM6prki;Mi zT2UlG#ph%tRn09)u5|E6d#d&WsxsoDsU?&2H(zMjZH{-c762?x`<1)2c2b%>iT4Y~ zQb7m$jEDXZH?-mE0QZO^2E1?4VkF!1%+bC{&}dKNoF0~c7Z<7U*U~{Mrp|YiyTnpd zfFLksF6BYEEKKmTELi~P4ASlXf!1?5Ao1DBeRrdcCQc)Al@@UHR!BHtGxCQKXfQjL z>4eJ8izBkpw$@sy6E*ae{ubLqK6t?{*ZIyt-f=cG7nP0?H;9*I2v3I#>(iW-zTBeY zb#|Ld+o$IQ%|VI7Xaf2og_{qslc|VMq|lOGKfYrCs%2bmA!Wq-kocai-+RF_AF>v2 z_R-%i;YfJTIHp1`bZD45wv8vdGfQ%pCnhnm!>%inS#p`Nm&O?C-6bhqq>~8xdHXF! zNa4mp8PesYbANPIH_F?v&5v=Q4-~knt5}ofts5Kd>N;>b;&yYZW9-gfZBVWt)QL%f z;Hy(MnzzLi{c#SDF^c343BuEh*zsRpsl%slE$zwtvK|H+^=%v_ISjT;PEc%f9!}70 z2z2pb*Fv(l6!$sAmw2|~z8%D~l7W$HHb=72rbB==lj$8Wu6>^Q+2!+cygaoYy`2tD zR^JS7wHl93VWqtk47e6?tTVOv3^ zqmT{28^obU-gsUtx9(c7StnmUBt?CC%JqLb(hh#+@|cY3`mT1LLs0sT;til>*SsY_ zr4w)(27+#UTI(X2HFkhlXeKxa0P$Pk?(hb>nrX9TbVT}eUi{UgoJ>JB_udmo{nb;_ zx5KY;+^r<4C*YU-P>iWGWUdan426!V@%hvQ*qN{)OtbsTeGVgG9_Qoh;uWn~Jnbh6 zsNcr~BkOio`5VQd--fP2&CM@SN_>3y2by9NQq}j{3pJfB``>k@%&r<<72E3?O4sUX zkU6|Bb*xa~(cpxW=`2BLij*h*c?{D&TKcx|1=Z@#(9yAxo{_#Q=Ws7{C8?XQROr%`M?&}XiUKqDKrV$e)V`zgR8lO7R7>f($6K{imLP>=^<1z z*0QMqLDOAn_TXL-wVJ6XgVg(n)Grp#CIt2A7e1Ed8u?*AsSaj7NhsDBk08GhR)AeD zgSFq-+W&DAJ(K1?!Mi|!o&pP|4s0>aJqeefYUCb7Oo0s{c2x-PB^QD1r4IA?SXT@h zjC8+&ii1L*76G7M_gUdS00awPfgk`tNedYQ(2a^%XeB0X{2uHG1X!X#_v2L7%ek;I zqo5aJD&E0|+>As7Mgkv;aUd1kgg47MrUKIf&dD>O`@$?uyErZs%%&jsa*{ArcIqzL$Ej=zQ%5+a1YWA5d-w!k2c zHZFnPTd6S8kwmQlz$0mAuko2-ZuV|=xMimz5m7fnWs)rWRz>A)t=YRqaWt$N)7K8 z1jgl8V=Va5B{BshONhkhmCW)<0mB#2nzh}Rt+0s!KPJtO*uF@iNnQ*6u?cB`icNc= za(E+eSXSd*F1I1-VE=iU@XISM-ky&WLbY2`$pNj4U)!F;yu##oIcqXNAt~;i<23_N zbhd0>k<*`xLCzu4w8c&Zd;2k+qkt08SMtGo8haj&bRUIHgq)*i1nrY3e8Tgif<5}r(<~x*;6bh;q5^Hxk#K2`_85}vKjx}JSrQweXKCkUIy_{uZnZ7LiAd20^Peg?u zOebk{u^YC_NeFt9GK`dz<1&KNL+v#WO5_|3pMM4dzV{Z`zPs2Yz@T;cdSpVC4;#5CuT2P~RIJn%r0l&?(eow|+hY+8lG$@w8@WeEd=a z)m%*Nos)BDt&B_hmoS}dz?X)-)pEu+(y^!be#DkOkI+q+I%`@<|-iv(+CSEZLWw=07xK{9+&dvG;tK6834jls1W!Bp3x z6tyr?cTE?VT}(cA8TkOE>F?0F|FnyRmaW5(zFN^RUaV-FAL4 z^w%$;n!C|B{J!K}6qBCF0T}`N>IuDHq9SXA3jX8!jw_H_7^;TdEuBIw5v(7vq@<*b zBv7PegYRK2m)>}LkJle(xO;Caww#%w%!Iyl$~*HQk`SOW!$ARh4FSvE@L9S|1Cf-K zIk3A#$lF&8g5b090jz&xeE*_-f04nIS7QDb|Nc+@{QpM1cj~+Pzgr5t_SOJfp7?hL zR`8#`|6-dBZ(S}+7rt130xl~QghXQn6#k~X6!x2rv42s||ESzUNX{XIFxDZe>;B{s zfR8Tk&hpaj_t?QM7%vqV{|=dhfaGVg%S)ZdixoKr2Ygd{eRzlvm074nkZd6yqV!~N zp!j=Mz?Xv*10kxXl)5wLheo7hc@siO9?4IOgrD2f9U}IR@3d`QeRaZJE**oH&|%lY zSSY9mPrgnc>dfMGlL{M=SnHjxwJVvnLA_piSq|AI@?E>lUJik+G3cl2&X_!m+?aRtsDfMS*$97}E4qBmqE{Q= zM81X`_32AwF*{Ei6|R&Cp48@>;PkK`)$5&**C0dls=d!*u{GE^!vH}G zZeE4u1asW4ekB4(#KFTxnAcF2H4ISSI((T99q*{Wo)ZB>46oOeQtTFl>Yx|Wp@2l3 zF8dvHK+AbJb2~gffKWbsl-L?kMi6sFl0$-rB~0h5VU_x|F)s2$&nggZ8E5XnQ^q_aN(js{F{MquE|! z0PBviJEPQRUB_{6I6I#{^pNFsz1_9e{3n4$kj|r(-zh!T-THV1vk5L#*Hiap#xG;$ z=nV*upS|46bpD94Jr~tI2%9h%E(Q2O94O#5JU%)h^~?#+dqAMha}ku!uNqyN=)SI% zzoLX4VFeFp?nY)_cu7+DNRORmwQWzii)x!ZwB*7U)VVpG6b;0Cm1eqHxw%GiOHj&9 z``iYlS~OG?5&Xo2_J;zW=j%2*m5o~u3%dp=$b9K{8r@Y{GL0Rd0BN7R?gn@desGEP?#@g-Wv!c& zo{5VP9c;FZ>3hHyBMosSA43QQBm%o8E|(`(9}PQj@2=YyAI(u;X>4ztwZC$A#w&MZ z88(~O5Hp-unt*N8fHUpV7S2?oV*DzKa%2c14M(+L z!*2LZpAFONhI&{0eGG?Q+kpt-sirdO{F<;K^b<x5f=2hlI%+YVZ&KxFmPTwCq9aPY@spq`qx$NW4Ug zft|0(+~**!T71IH@?!dW=xXwaKq8VkL&8+vBap3E-Df%Lt37ZXanr$l@I6SC1(9^P z{Wl#pK7TC)tu0R_)$7xDc!4S)N3UsQEo=i*hi!3d3p!vC?KV%B2b8_l%MU)D_?0Qg zf8(kdz~=SX_;!G}H0IEYt;B`RJ@*Yzoz1v=P+_29p<^#O`aVk_aztN=Aj+%br9>1J zNF8X@%gqtt&S#gae?d!T$aG|FRE1F#sZQn*5 zRb~#JM`~Ukgvk4r-Li%UAoGm(_99d1?i?lyY5zPe6O{#an-K)}6xw|Wih=+PJyUuAeaS19`-<7K6G zD$$%f(w4hPka7mX-YR8#o;SyD=Ue@Fp+X$GM3KGSuoayf1?c>;~CkmE+LMp z`^6b0h?JCb^aH>9!Ss)Kuz#Mz?lYe|CtpiUZ2|O#BR3&xWd}O&dzErBJMReWb^f@Y zJA~~`ZMIO{MtK-D^O?}#(@;d5q;HtWa+WUSBAUSFWlW0a8JersT&TRh4b zYo1Ez5B^{5cKa)|h)CqDT1_W!0*rK~sSqf31>7vU**YY?5yyP!NWh$}spgOAsaL+cNX^*Uh-9Nea1=MNA0(jI;Da&&TKMG@Xy={wrn+< zF?JbvqAYrLbsM#6F@_Ut5v5yZY(A@XhnGP;zcj7_;#+CnhT4l?_f28Z z2Xmg@bS#m|0YLWXo>GTGcg#=99y0&&d)Rtwki+wIRXpv|lW^w2*A8&aD0dI}S#_l)LWAnq9A88(KwZ=9~)2&c`WOfjTKN0lzMYnpU)mHK2fC&!X~@Nxe3 z^yfJwwGU+zv0Bld72T;6wxqW$o@POCrbL4|HZC^quV1X9f9VVY`~LGL0+$E&`+)g* zo|%0$@0tfu+zYRu!tW6jrF6Xnbg($TlP#=HQ-3R4zKJ|s3$H)PTtXc3m`=$2V z&_5i9g!{h2Vn6J0{a8gcaE<@Uk85|}z5mT)JBE+12ejRUs@5_yj!}G9hPB(Mg^VarMKShzYmVh|JrlH_J1l}`d-8ihb`qJ8dt8S+@d@eoG1 zf!Uq!&jSV>8>wESvOtgmxpH=EGct$U-Bokuc^FjXNPJjK^;{S8jWoJFO*XvzV?QBc zHPkCS1!G*g|0_ct`oF=~e~BeMYC&NSN>@+M3NA@mTQ1aTsdVZ-K&wilv-k=}5exhKcZ z1%gr)RE8?A!kvoLNhtNy&X~tbluwx-=-c^W&7--?q;1M)$ho)v^G&WUxY3@PcY0%I zD3W$)=EO|1MutPye6xU&fz9CNT_gSn3*tZ@dDD^lr&{jNX4FrKkH{92)Y;!P;=h9d z-!(*40o&>lcPMDp+vSTD4-#0_bgi5;*|t`>Nlk(SWsFxL$U$5n^iuoe*}}+wI)&8Q zy;jgzY-gra6$ugX>;4ZTE^h8r!#(;RsY2ltT-4MY3}d;>GbPG#rZp+>U$NJSw90N-IqL zhUzL`?angu*l#8{XO1sAfP9Fk19Ih?te z*IdpA=>J>G`kO}l!zKQm)P$r#FVjo^%MMl_|7`HLV)&12_&?m|e`LjiSEWlnJqq7v zz73>h$88o2Io@2Ie8$kSqe8@)Qxmk~<}8!|lXGzJzZaa}=DgicQ-$-_NYK>5{hc2(HHB``-1@c$` zH*_zPS_}thKJL6KypifyreEeC7B2H@h2)QZjEJ*CmJ+x~ZZ0|aD>cgjbN_?d_ncfk zL{?lT4Q1e!YT5gfRRXkjMr;8fo4hk9;{xsZJgr9_XQugz%)m<~mTvR1Qc7pgIXM9D zvkIN9Y9{2D#>6kXiADGV85To`CX0<(Kw>$4CZ|?R0>;G7-45XrB7g-rb_j|>JMEP6 ztgbc~M30nMF&|~%RV94Y76hPXDy|&1qZ$b}e^w(_Z{DE4N$2NzRv=r)n@462M zoEuEWm|L?gEiAo+iAS_-h60>)3ue$~V4U1IY3&E;`_{3*8|G^UZYNr~Kg(^~PdE6y zd<~Gi?K)_T1|QCf@wb3MxK?G=JF0APUooex~+Cf9#9+gm^x(Yt`N5^^Nf-eHR)|TU044Wa#L4#TiaUE-3r7Di81vz!pj<^IfQ2*a z#lTn3dYCyIvg7?&0bwp0lS5jqWls7I8}L|DDwkgClvb_(`%<|eZ^Q#FYgY0%IoJMl zMPIbnxJg&~qi~JS3!Qju4A{M4&RV26D!h+_3euIeuZr1NW!}-iK3Bf!;JnOSJnPkN zTuwpBQE+1`vk{tpL<_4=cWHAjFPEXRc{0W`=JVp@+F%Fe{V_h`>btaU`tyXjlq6@I zQimBC$<}~Q++mO=C(hax6@uXo|t(nSvt!#e>b;aDEf|IYYp>8ZH!XfzVuMzMu<5xBk_PL(fbqp zcV=z&VlkSKgVC=GZH^yUY(pKE(sdI*2gK6R6;20OH@cR^D!tE z#?WF}E))P9-+I@yDY;4516FL&b$=v@Xs+EjM>{pKDABKbqgdZMjcEL%97xiGf)+ou zG$TePD!ao3eJwe}(p zSwzT74G%6Bf(45omQ0=@)Gbw2k|(UUB3 zgh8s&Ww+z5atv)%iiWi(!xLoS%*@-T#||Zw;hAF`BU2POQ#jGdYNZDbNYxT^&FD+K zl{psvpGFWdERNp!#1=)q8l71&JV!dO*KB6Wf#ZA;SI$wvR}k(`ZazNOn@1AyksnST zQHTh9#lB$2o?0*6(ZzGGuoxMp8#xr=bn-Uy zWm(uVcjlE^ckL$J{QNdcM@h~;h5Foac?QIyjHgMFt^d34M$=Y5=xo0Tt(sRl6o za~9CbnuOMg0U2+-A()_-XhCXNwe#5e5xj|FVV<;+f=}3_d{38CIXO8i+Axi_P~W~; zU)Ur1JSWU;-nW&^BtRS`NMPe8O#S^oGu}ek{@QsP6fhft_a^Z(>cC|?v6LPI&;k?j z{M*VGPrgjA0nyL&6w20rhBQXs?E|G6-M;2()_Ad-OzB9DyDox4u2^Je0KBe49U)J4 zHgJEPe^l_uvjud$g*zdQpjdKZT15J-vu00fVD2TZ=CGVWY=}V2iDd{yOiT=586p9O z$U#b2#x02=!N0SK*LSUu3RSGZIgH*miEI_#GgK#7a0?;G3XLivu&}?jin6F%iUq2J zL%`JM4j_P5y~6W52`6nAR7eDr>o*wCj1icm4+K@_1`YfmG2(D>GC{03yVR*{Wfkn5uU)Q~n#x0iWaV*;beXQ!KX@@D6qQ*Zr|deSQ`f%`)36TfZ> zS(SPirC}e)bZG#`dvp*9+6mbn%aSaL%SLx zl4`j|FT}VPeLPP=cnseIax`tc(a0o0O`Un!x9;d&=j~-}ec~fe97A3~^{(?F(n7Ur zf$-8fCyjxlns%;SY3U(tczAexjd+wx{VvJ}QVAlZrDdfp+gskn4yPdfEL}J=-YaI~ zMQ{H0&&(e~UAavkoXl*H|2JT7IkZ9Sueh(j=6;JtRp}ClL}IAUo+2#?N42O-KrRvc z3L;JW-%ss3evAuk#`wUwYg}_zaiW^23(-K(uTm?z(fNsQ!-^MvwTr&~=vJh1Jj$aU z-YWzHM^S;G>{ChI$^U{}Tzon%9KZZ%F;tR-&1UUFSMm!(L}66ZdxTS7CX+ZsllXrE zpTOJlG8wNDl=Y8U`Hb+tGH@aB%daS3rWD>UG{FX`o9eMVjb+>|Fm(l+kfAx0|)_DRT@D2jz0 zi}DIpHxhqyE%^Sw4(xvmp8IFu|1qb3P_Qr0W8GgXTS0%^ywjZGuNhY3|9|9xCLTM^ zfj57R^L5JP94;6xmwNx^$^Q$J|1*idNfY>;J(qb#=q0)>X|c^CEi*%4 zqOcmRaoS`IJ4~f@)~sYG#3G}E%A57HQtpGrT=9!^27%OOV>uin-PpIE z64syrbU}oukhKNEM%20C~IKp_NBhz<>@|C&*HK{ImVeW%mu-eSFl(i&ed ze*HyVz0XjOC>H4K+2&tY6(UFlBliTpvn zvqxX8ky*{zPD%-DFi^d!>5lUYn@f;NaB_g!Jl%xHE+@RijMSeja^Ly19ytq{k z$s`N?6n8FvKB*>h(s&zVM()V@4#>F)$GzI>zPF%StfMDsNceh)1e-K2ScL?pK*$`4 zpSA*^NIBLaGMe7Qv|B=YZS2}S^=0MjXBR8CUB=U{c_B;ZhrFCkX{&>Gr8l2hEe*E? zGC%}=FTXZ&r$gwEy`sJDyF~-AQ^;95Gt!YNdRUJhZ5xu|Y-p?A*Jf@B&R>+?xUP5h z-PaM(hc$35ACQr5q+YhZtN^(m`7b7MvV7i6{q%{Rol#~QXtw`$T=iJ!QEyA=wX@Ha zWnHoCEgx;H{MD{HkMPBHdu81~{C;4L1;@bEeC$T^Cd0#a;B-$f;GokW4Vy6h=-D)U zkNHt2e`P$ePo3sE^%8?LPWySI;CJH>GI-OR+SoAW<0EG%pa>6sWx^}zkIav04`u`s z(AoG&q*KXFDdsjMthnJyIMUc^2*T;IM;y%eF;gP^9VR31#RUeAEVupQiV_Pg8PM;r zx4DaLE$y;_-p{w8ZAqRJ^YE=+s_}M3nS!nEYb}(k(+UxGN;uzW%TdZPYz3!g&yKz`Qbexs@ z0f|;Lsu_#!IdTmYj!=D<3_khcYJY@0(dlk{ zDBQ*8@=vKxUY!y+k+g;+8132)Z$Lg#MWX6CXVU_9ZA`n{6~`ETiYnQFcw@t+<{*OJ zgZ`6h-ACzHCMyXAih6W%&>?I;9%I0ftKKT`Y+I-4KVcbB^}#ZX0hk!JH+J|HvrZO- z+WcL7E*63zid_sov-t~OQ4oPzV_mfl=b`T0tkW4Sh88Ga8p`YPN6V@GuHVtRgyaIm zYrVSc5YzF~3G9jdrwX<=rb1g#PeO(glKc-trHAz1&waLOBP559EfuD8+oO(T8KXa5K-k@G~dWwC%NrqB=QEv zV>`7?CaK=*Tq%o^M+637mM}&JKqQ6qEamG+612%MM4^~5=IuPs@TG-->F)M$Vx5B@gGT#*0Ge!9irZ-BC$ZP5;%P4By*Njh?`KKw$s62U|#B!GRF-%VuG% za3!>2E>Co7(PG7Yzk9^TeQ2WLV%2l~cO2rzAXcXb|ECV0)pD}v1A{@3RxJnKs}yglt<`%FHAyiU>g0fNVI%T0*_0so%LZE)tiqd4F)>>*-cnb z?FKkNb6JhI)$s&JkoGf}>rhh$3zm+kgq zH4cx%2KQK%ai@yO1S)%N?a*d;(VMwY^pIVFOS~^K%M=Ou-uW54oTLas|9y9Mgf_)m z=GcZA1j^33-N(^BNXBkwuJ!5YpL?|LOTa1awS&s(WD1h-Skb&_!%S9zS=SbiJYItK zg^7E7jOazxMG%OO@RQo*Z?XR~uNussxnw;#&i=#vEN?IVS71MbeI9D8Nf%>NVh{sis zqtu{z7u%zb*m0j%7j({AZ~q%>UWU{MZx6nf9d`&!0{g%y2eWBt7~<7sc< zHg$OH|Y)&c`qwJs6sMt4Esq{&9<{lA`Y(o#FnFMx7a`Y zTFWp=)2V4bDCv5yd%qSZ^j*+4+-8{9@9{~SGFvRWZ;roKw_#SnuRt>3#LMXTXGH61 zlGu#q;|!5k0WxS%{Mu+u{K_Jp%E$dr^P7&f`*L?$%bCs7XkG8t%b;k!vJR^!X(E?s zbsUYuDHqCCKA(v}8neOzSxMaSh6^t`Ph3ui3cl$l?*$`G3MKP;lZPd4kPw2wGJK)4 z*7LN=sxJRYIPvecDQ2>vl&ou!)e}56xp$w#=fLd_`XGQfeX(V?KOPe`irK+ZhqX}l zWw+$bpOhv*==N5{t6i@9uCil#KYU?j?k-2>V$sDz5^20{6*FAC!-c6(HzMm2LYhHi zr`><4zT~l<*f#aSZ2#_g^?td0_ntaj)i$SQ2@!cF?T}9Qr~}!n)PJqnZ!>tdg5a%h zn@8Y_*U84yF;N?{i^ijcFb&Im$3eIXT89AuqOvBZZrR*=0|iA}+^<9Ukm%Fqao86~ zPPw&Tl3PevJx{B${?NVjJn5HVRfG%gp?QyW4pa*wkUL_BD*T z_8VOlppRHO0t5ntND~K>l^WUA6B*6SBQSEU^FsJpZVIE#qp$8J`?e(a(ToHA&NJ+VnyiG?nxhP!qEVSV* z-KbbL9ho~UEiLA9@b2(j592ji0((?;^!>2FEGohYQ0Qkx0GJJgs7C!Ymb30Wwpx*m z1Rlq9zb%s_z>tG7`RvYH7&_ugS#Y6CBD{E!mgD5J;)SaLjJr`$$-(d62&hFNk(eS6S1t!qb zyOH3+=)UYtHRrUK_%+2mf+zE4_EE%g2Q%;PFB{-Twb=7ywBmVy0{dZp@LxTywB02Rby{$3`YNsLFgi8=fAXPK_0@ z%L}ik{8zrL&*}%~_x`&)!0!_po@gv5)Ii$7QE>WO9<*x~*K(r;&BQiX*Jze^nn0Ul zvEj#JHHR6B^sc_9(IUE%Gm3QH6V?1gl}ceNfq=wiqT`3<)GK^VrwQUXFHf0gdMJkj za6y1Yt{q&ns-S8ilxU~iuB=MrhYA=}U$B1h%=Ui6%Kf#7vaocVcl+9D=48%9 z8cO?fFn-ap>p1M3mycnaoy~C8haqsjSPZgQTXe_sn+7si;vFr%Hph#~O0O%;{x80d z@wy%A4&`pNJ0Xpzi&8W{zAGRS%b8EDR{1?L%U1))!plV zgI_{%hnm@7$4;4rMrUfwQU~VcGlug%Ii;a$UVFBztSbE~U+8Gr+*E0e|Q zKB8HeKXpR&1E=0?!}rA-Ypvokcjq5dkso#WeO@N@70VSi>mz?ct(Er(V`BTTG-|hP zAeo9uCr?{+c{rI|$Gr!BL$YjsC4V|A>#4yNLMT&dxsRslz?(V=+IVx#e8t9056dXR zntCs=7Z@6zbvE+|@y4MgTkn}9+~s?6)}$jl9UfY>S^3IJtZbQz0KEr)dGPR92q8o+ zh0nQBMw>#KW0SXgSNLeof$$rN7W5t+8IW9Ah(_y6OOCKE-G78JC=IkusZr6sPoq#W zDgXSo7qKqemLAtJ6ADu80u3O@(nq`r$kPw&jxv@|P8bqz$aDdS^9UAF@TYV9wBn(U z)h~8>MEUn%0u0;U0#SsVrq=U{JAdkA3nVvnGDzv8aPP!o36*EZ(yE`#XNoI%Va*R= zy7)=!qpo`JiJmV7vI(`g{VfW|}4SjdE^J2OsfVH31f`s~+qTswn+ z^e{{XM1(g0XT5`wkc!{hT(c>1G&1CD1i$hF$LxV34WJcZNgN1L%;(_O;Wimf$DPVV zW29pFK-9P^v>sxHG*|xgO|2pLq=~L*k^QVPGB-0r1<+_Ce}L<>DRnU`Rh^K;NUT^U zX6(_$X^SUdG2B_x(2MeVD6g`S%S^QF=<`i((ZJY(I2^0<`y)+Qj^763YU*k}dxWlb zAA)&kKk7eTMjsbJ{jvnN*YvVntY$qt!xMQj+N?ZWtfr(o9P~d)IEx5K7|a?}NuOmE z@Hye#SRdcASw!U@q}*mboj87~o-JD3pBs@e ztwBI-bUUZzmc{EQr{Yg}$h$3-X!z$~oQq~>#A_x=WWSVEbxybOadkAb<@J6RhV4Lx zyJl3i8+;V^&|*A7TbqDA>h5625A0@(fsb3y~XI#Hsr@bj6ZsLvlQkliyZ7J)r+ zxeph&aV!>iY(O?gnvaKtNRo@un6o3_`b8pb7zz`Th+%B=x3kfBgc7ZC;hH^a7@{y# zfhPA|)MHI+kB0^L0#;UBa&VqGJKa3-}Mwnh%rdGFdVQW3a^jc@ua7=c#U8te+ug?b_i7G+o%rF5|lw;(HNq zP=o1J>qk4@taPXPG1X^j=J$>##qSrZkP44YF9Nk^xu-^t$12+F1SoF${O(i< z)#NVr>jNN;lX{&A?b_U>LENI759|Fy2g>IcqXb_czTjmDq6m?|zG>xlxLl*${W>G@ zvggugm@BKR{aZjPP(Y0xiPb#e!;o&a1i7&KPcF@7J%_1estqpw<}GGRu9#PDdK zIlA(S5KIMFe^231(@|OuDm71t`w?qlcl%xBc2C`XQu!2RW`UW);g=v86e%ZStWphD zjDL666*JI4QD6uU|J~H^4bY`8Av-d8_Xh4B@9R6;MI^WPKf;=1%F<3vK zH#H+Ya~BiCXwA(`{cb0wD6kx};AO%3sciJEYK`NL?;5~@FqTe50=%;j+{jnT-FLtKr!KRHzJ9Zsqf9fG_fAUI zI1>X8Z$LgHvM8^h;EPxXF~5VLteADXGM3G5fUr<)HLMUP;cTs?l$t3B`w)2bab+at zO-s}7lXV3oJeI|4X{yDLuuWlOGuN9F54p z{0RM#q0zc;UqbkmD#r# z>=V*_Xpe~Fxo8GkrcUs1&rZ&;QQ}LMho)dMi_foj~O={kKpE^)xv2)>@yfI;LO3 z8{j2-hm2k-GVIFp3Fe!~THWR(`Ci^5i;B6dTCRCX`L$>r^Q}#O-wp+hp`cTc77Zl& zBFvQ(>D2I%0pp2oOiW4dlB7Obba!_drnof?@;GN(y2PV?WN7ju6W8krscu8gEQJaL zGe@Jir@$tBXQXJpSmxDU=~ z%{*@$x_?ucd~mi>>ObVmnB+Nol&}7x_{ic;s5lrvQ_Lnr%=rwi+5GlR$J=&X#8=nn zj)IE>iV%(@GWfH-ZXS26`u+5&hBK|xbbb^@$XN!Q7PDb6y;*!|VQqkB@LbJLSvqWc1*eyDS z2IJX&(T&EiNeC6pHyeavF9(UA7)o75ST`qEWZ-EXlDrhj<}WL)i(6P~(i8`KWMrd0 zm;Y=jw~c;kb{+(L9V)*xE_mF4Dc9PA_OiylYWpK~ejZ|a^Kc^^_pzeAah6A~L_vg##XLWG}Y;|UqVgWK*A=?JG3f%3N%I1LGoi5?; zJwM3QNL#2Kvg_5}z#|Zcofy(c-qS2ny`v$@phm1dr_v=s>}*o?FMlpwfr=0!CRMVT zGahDRsQi4bP7#*KNJ{Kl!^Y1%wCwnz2=idFrd9qeBI|KaMKgENV` zH2%h#*w)0F*qC@?+qP|+6I&C$!NkVIwrwYGY;3-&-L0*y>OZ>b)VY1TtE+GIxxe!~ z?Ag)3DMmj*_2eC(*KX9YA{2tCdn{ef?Ud{!&w5*po&7=Gn7(!8EkPa|8!3VA$)Ewj zLchbdt)cF#jB0jvv#{ZT0M~pa&0t%1VtnemJ?j z{T3bew((Ezd^n2Oua>H=%vR^ERGb?S{T9=O->e{+U)Q?*BJ%vI zVg?=iV|=+0ZIfl4EQD^8iCA|HX#Lpb`+9$|RtgG^pL}&H6+<0f9@xTq^fRMiQ7bI` zMv_pwrOx-fGZ>ufO@eYgIuZ*ZF30a`GZ!38b!e!lO*;Cw_|e&@zmbS`UsVSkkl=Ta zJy8&F1UoNt$J74Zn)$YbM@_4Q8>zJ6=Z+__p;Kby$~9{HU=ZYzh&eXiC#CXG}e z(v9E7+tsa?!A~%p80)7Cdd!ahsCT(2ukV-_b!8`~$wl(a72RXM215mWygZ;FpnG=< zoa`M%%Xu5R=@}|+X=Ct{j-vFg0&b; zjZdN%D`}_$5B#Fw0n7BQ&m6ohmoUOY)Weh14Ri{pi?)Hq^1;zYzFzUNKi;o6`vyB^ z&v$BX4}H1(H`g;my9J)ELTp6u{FIOjw{=vF6+$DN@0YYXOS*oPX)2bV5wGu#p6iIY zdxO=i+gulh-X2b5@%z4gG0UBQJvaf>4?*Ju){z?OkKX`D(sF(U8*^N+V5EtNLF`fv zje`Pp21I9p5<#{7@3R$=QG{7%7SfntP~bi1rMZo;Z~3VfyaJ`dF`<>4Bm(Y=H`umMd$>*svhCz@WpvLkrPl0ydw z=3!4#3M_e{30GSG(2%35PlBmE2b9EczITrl8<9e?@YTMO>$wX}Wp-`LKe3dbwye59+} zW$^KFdxEEYyiFzEY^wkTh`V@m`bguIDPX4(P`o|J@IIRKW?h!(axqvthXUFTej0;X zAqrbE^P1b2cH%bw#ThY`MMS}tl`VUN7#{SDexkS6x*Nw*;CX{||8hbiMBQ!fyj)Cz z;(6nWaFg`ky1oo2j~Ua=dWQiy#neN^?IylVo0rE6^}iuJ0c$pT>FiyfKXwTedsaef1j9 zTRauIB~bf5Z2Hx(!LJG;8P~r20A`tzA_cvhlkC;)+7Pu(=6HU z02zUPAS?yrnj@yR0)M)r3l@M1J-#x#?@W*fmH+E0XKxKzKk+QzsHo=`x!1m~9`9$h zRbQPaivUX0`WCZ5Wv`0hMOTt$&LNWB%Ztp_q$KE}2^E`IJip;IrZtI98+PAvCQGd* zY8bH9gdIzaxHEr1Nxa;}%*K*(sC|da zIZzY#MLQNeiTWAs1v$qHt}NbVvAd>=4sb7A)hSsK;6q6Q?5fipl;+*~{!Atd_@k15 z|N6Xh=_}c|_G}ZkeThGw(}K*Gj9RWUJ$g;{DKH&KM5mf}uO}JZkF57QUw5Ccmwpwb z9K(l-#lzGvmA#6Y*0~S)`5q49I%iVm<8$9nyDh-OXgJ|)azEn{ecoxu%@Rkv@O(MG z4*6y})`cDpsiMj19i!71o6%@+-Mih8pugDBuqFtEz{fP)TYw?AZ*4qbl4<93n7qaW zF1Bdg3SC?F-Yv{wSGlJge6%@_RV`ghUcYJNII5MZdDw7K zRIewLm;xnpdCwf&pZQDi3W5aIW=L-@8%y&-&41Cho_C#-03R@zZdtA7Mj^fZ28I;qM)`W8*XIAXgSjI)A8O2JH&c*!PxVSP0H!= z77lGc^P)Jq=9$6R3rI;y#(2AwiKH3AaX-B*k0Xf$?Ik4{=jxx%lvp19>L%OGq8pN1 zhciZ8SxMOAikqX^hfiG?J%Go$-q>K+II>~Ig$~b*fzy36yJ$&HPrf_+r>alfO$TaR zU)zxF;0X`&je5T_nw@6!(+#6CwZ2srY_MHDUBbSOgu8Axd#GG&kyjxa6je&CA$n&eq$eae92{{M zsp|+QGvN}jS&ihj{P`0R&I#`0GwCZDv!Yh62Fx)R*+oxcYwNX3N#q32WXEatczsRp z=L;Q_M3G%TY4YnN789kQ^wHvLxxL!%jJWQ^_vU}gjwB%SyS!YWWuyE&xeVN@>WYhy zkCUyr*mxdH8m>IAG-hpc%V{J=<&;0+GM`H6@9%$Y$7Z{_;rD7DUKbSDoHLy7jah&D z;-LOa)r3L2uDdhgp_1Fb&HHRKir&{bb`COaqGzS!d_1MF|kmR zGBdZR-)@snp*C6(0_V!v>7yfvt3Tb&7p>9T$Pc$b)AZX`$H1p4d-HEs_#NA9Mk-s2 z0=$fy(o#}h&YtRHi#dX&8|s&>?PMfecUh7+C?Mj z%FD<^`8zj?NN;gQww6ugvQs~qCkvStu8kv=HkFAj7r>AtP9SL&`bYQ0;2xZX4Zgo=kkPBQO~mA6(lXIiI{L$SU|qdvS2$HQ3B&8xqUsB%CP`g_Oh`AKTiS>o-n>fGy1PRNI)cBz`;DT3wv&trKS8I@7FE8*N3ZvHD-CpV6>C3gU5UUx>+5^KW zH}~?bh3~AAsHmZ8w{f^z>quTa?lMpvq*p{a>Hox$3-}?IBS)}h^Q(N8HDxo!)DbRk zf1A(CqKb}mM~LL(tz2d(b3vEFrT|LI{A_olx4t5DytmuB>d&wSma<6hpZN3n-hZ0~ z&sP+>l}=Hi-Y8L{p3c_G`Cxrvh=gn|!f_(}AUrq9$7g5Gi&wuEeLJtV)FQ(1SrL6l zKu=x2|8xSD>IMNJVY_=x;vEf9z|I_o>@7}|FcR?j@%%u0NXQ*hczdS=Vs%wEi@o|x zrFJlA!P^YEoY?i!sH4B!8Hn}Z_RzSBXkk#&f=h@D$)=?@RIRIPLr(})tE)q&@{K4m zH3Cl_UrhaNuG8Vzypm3QK9Jng+iI=e-OkGiF#%w}U2ac_Ego;PvX$`WVOJ+jkp$pm zXb3~_sM_=NbW?^8V@G;GLXx2x|6ss6UW8MCu0lyky2?1{8DDiBm?Y1&t7}HC7Vg=% zQ}qlf1bRLy=i~=P<}@nGyLg?^zbm*xC-gXor@$tZCcX( zp1o)|ON|ZlO3A?M&82?yo|lJ-5GlPhYR-y6!e z4=PvirD2OzOjb4VXFuV@j0)08^P?xyd<5!^jw$&4xDtaKrE;?iSoWBcKi&+qC!kyF zT~sZ~o2$Eg=J1?tIV@bPsUA&XVE}ky zekqx_Jzx`QR~CAStlVS(4K*t^^Mg1|EmbWoucw^8q@kF#yR+7?Hely#O(o%Su_EHq zxC>M~iX4n9IP_GGpQGU?7FD$laLzfan1+Kp^|uCVSgj%ecC|sKF?mSA3tjfUB#vHN zCksJB z)_?Pd)iTL;xFK(4X zX{87wC2oOsfd!ivKqA_cuKCMJHVvH=ydc9bfuKOLoU6Y(`sEP+FMgPKa77b_GX~a7 zKDg~6+iR(B{ZD+q&*p1oiD&js8@ibTTCVriU(u64?oVGup3tsMvgNAh!LI;9SqY_$ zSkf2cWmHnde%~~SXK{!S1AMx^tLGLG=c-lBR=B{%5HfY2{0XL8YtMASrP`r!%@&Y@ zofR}+c}m)1o=w?lFgCov_z)QRK_mQgbBKzjgQ&@9+od{|=klYfh==N6|3kHCsH*L6 zIn@NJ_=>Mqh^7n*cg4G7RE6sS9;jwPQ>u$KTkbjC-q`{IV*XAX<(_Q}8h`1uJ@UMawO-Iv zNUD9uZ>D7&eKJ-j2So62@9NpKHM_s&PpbA^@{KD)96P0cJcv>np=e5*$B(ZaZCV77 zIhZcRYMqE|VwtQ(9c~}&*`@5Uu8FKya)OT`#0;Z+U^_)}vLAMhbk;Q?r3#R{)o%@)*@uc0l;Sgk)@ewU z@gnB<-o8x^`Icd%HhPQzq2Y{+8BHhGrix?=#a&i;k1vU#F>1E!*ayNjZo2({ul)oh zZMK3jS*2+0> z_`IP;1!M!+E3BwyE#_4_e9-)IUFqNeBo}=b55ejHSeXkbuk+w>RZ4k*cj_<6u-2NX z&G+S^xM(3OOVhq??vB=C3Z~4H*Z1QtvT}M>i3QWs4lN`yg4)`f zWH{Z|^<>RD-Aqkqjz4MMApuw~BjcCiqY|X7{a`7Jg zg-4SZ2Fc1TorBKpB;j&{;d_jhj-{W2Kll%?hp3f$N|#k*V^wB@nT|uKNgU`Jqo^Hi zZAmx)%HZtiC`urlsFmS>Ikhpgp>Tw1Xjqo|#M<30Pkf(rFBo-r32&2a-5&Yk*~;;5 zWj-T+<#!dLTExx2XhI#PpKT}g>i4bgI4P}{4B;{Ge?uW_V;f`028^c49?(;P>8^q? zr(`f-rE1G6mJL>*8g{YmT9bblaMI!5I{TU{|N3q0qW1ag`0QSf3dp`u-5L00%#{>> z)sp4ulPo;|J?JBq^!;J-+2(e}zbsJ)$F&7~Uyga>syPR^4C0mBG zE+Fh7ptOp6o2>R0c$;`5Nwf^i7|?@@$I=UO9_7y+R%d(r{HI$AGW*tsx~|t5Ftjr< z`yW}!GR9>rbVOeK^$9jxLJ@2fyID-{a%(T1#$NhQ_MopJlgG=i+hj$))J#7-mHl!2 zrED0d_9&}Y_YA23?6#(+3~WEdMtgg;=>G`quXSEO?C7pNYWrHApJLv4j=elyQc+qJ z0H;n3n5O;yHgG7#*8OcboU=Gvo*pySf3)js2Cb&P->n}?I;>eVZu zrlTep7#g5TeQQIDRRC6AcP#?Wk5i}3TQZ5o$8`qQzUnkVE*Fn;W|f+(KV0IYwN2fT z)l(tzLpc_)*uZk9g(;a`deNmAObdIH$jMM{F6XOFnK852wff%(r8GVkQfZJ-(e-l? z3D~4#BM3^>$~96K)_$u8U6@l}3sm7>^Ks6c+_>@(HUx}rDe%L7`a}}t}Chva* z=cnWnQleN7SQQo=A}K)&sQM?nS?&}@gDzQ(n$k)l+tK+UFwg?byo7cv2TERq?7O?=Ccw2S=B!=lqt3uyQEKtmbJ$mCE<-ur);I zE$87wg{x+8@oFojif2#moDEcIi^a#B2%LCgg$w3SEiG|=|7J)RC0$5R2HvUcHCTP! zpAmQ5f|Uv$gSpi-N>goVaMM5S7h3N?mQ%4Ve+m(AC(3nwRqGi54PghP%I z*>XTNOU=s#y7k(m0~gBZR1r1&$DM=lbiP=v*weRi{;Wx!jKDHwT2*@O2+p`Y7oJ$D zDzQ0Ir-)H=bgGYhVe;0GtSj|1J6JH$p*Apqpy09i5c=c233OO^w2(QUz<;kHS5I$2 z!{lL11~Mi^4f5(k^lbumyOJ4{ZezuFC%o1WWE0rarXgo|NW~Zo7^y7SQHPPD9YF~M zB&(0C5)&s}Zc?uJR$G(dfj{Re`}4;pHh*}RxlTVJv0vosZyua%t;rcUFdQL-40Z;Q zK>{qprmnvEQU3X%g^-96RRWp3S(SM8>?0Dxg+>&wPfsv>MLdBH9w1uCgshk!4;iRn zaTi^5=eUAFj=?NmY66g=rlzRSs6jG$@)_*+R0XxmF#DhybM4K6lNQOgIlLX_c6PfF zH?AlO$4L2#wBlqAl_K;STXqGA17Nx9KMaz`o~kFD1at&aHm77A;TxlmSee-qB3t~_vEsiUZ-vYsgIr8q z(+YsVsUvKea8wq)qVxiLdmIiDGKCO@Z(Hg10cIW;D8h<8r?3TLWQij>F6RDv&Ky!K zb{_HT=|}eSu@7$b;6eof$RQ*<*9bbSmQe-NKPaiDi5r!OI&aPdwXPl`@?L-XkPtKfKDdcTU*e^3o|M9WQrku=$TwJB@jkAwLK;=qI?blkNx6QgqhSglJ> zRX1=%NkntfULH26FcEwr8^a}3ul;9jo(>UJDj?BD{FBdZyex)!S;M0mD_T*K=!y07 zY3nNF?fd3#8bVN2oN6vf(7{NzT;Tjk+lRZcHah~n9}U*Il=F~8zh}S9y}Dbr(hA?w zwJkNI!J`1Wz-h!BVLx5tZn5j}=cHmv-j0AypUFPUE!+Sax~8Xi#G00Hk8)fU_^D3+ z2Sl-;g>E}`ABI$T=pRcFaSR*FNY+%wS16Hy?63mN(M}1AJ)I!0A)Y0mr=k6Xm zc;!^on}f!;seo=Cv#8@f)##k+u4+A}K!cHt!qpyh#M%LZAzbw14@Ch3G_PQ>g{MCl z-8q7-IUlvOGcP6>FU^kn>Z)4thD!5=eeZ!$^N_VD|Dc@N2V2nN=yr!8#41QI2WHee z>J0cXrjbTK!+B!siIRq$ZgRwD@mJl@f9PdC$+@>c6wY9ohw+<{hP4MSQw&d?|#fk=`b{8Ql)%7 z)<)SWkVtf>k?{zL-4A$@`Ow(Ctoa&d|E)EOy-fEE-@HP}kwiT5*QkkLl&Fr^kz&20 zetO-XWn82f_YM*@ieohj7(ZPnvz90*cpWpy3;BZMI)#*ba zespX!s`<#lVFej3twGPq}bN$on39#t&kcRUbcF+HX%0_ic`$O-<%v=TZYp5V^@75qc>cGA`I*1i4 z&yHpzhcysW;!qFM4dQ;`7@}+>8TMw@#sf#UF_y|){eyk}D|{Qo0Ljz2XM~3tF>_sE zvwypalL{!gx@-qz;L|>lIgPj&Rix!| zX%Y0{pA9Y|TpPI=?{VMjV5pFB@qAKB5GkbhX%eF;zgZmY?JZTG#j(cI(0b>acVb_! zgeZ(qVX2pcUTGPl3x~s%tvlC{=1_=8QJ!~Qwvei_IIKG#mVHwb%6RedAJ>wuu6o*r zm`TG+W4Ta-N0Pibflb?OzsXe8&ZB8W+FqYtpc_E7AT6A5NJVTXBj+@?D(&YdxerHo z4v9|gR=>IE5N*MDV&A7+3eCpiLa(^)G*KwRmo}#hHvKgrg}rtJ=PR|b@^o9( z!BpXXqtL=GHw}c+l+VpK*Z0V)ciItH0c4r7b8oy8+=8{{^@>?~*9bn_H)!OCu_qg& zr78Zexvw=HCV?o^IxCp#y}(}vQ_SXeIyV*%gc6Ep<}SzhZwU(XMY^3sjDn5^1IZ7z zTJGn(*CJt=g~QjiwyQE*6X49>B}RT_aOKa@k!4OdPpoe!ew$KI=u-{0Zb? zJ>Q%^9f38*t3%ZyN5!V=$j1V^zP(f+@mRZlG-1iBGA!&G{an^M_W=1@RA?|6pkQqy^Y*UgOTYnd-6zACiN& zLt><@9*}rvSu|+T+fWPf_2&3#k^F(A;t1KUe&@We@;tjTW@?YeTmLiN+h(9=k2EnN z6LAj4CA0JD_yReiO&`mRxZwk;La+JOmc_L1emZsgs%9sEfXX?3%4TpaBKnP&W43+l>5+z; zHuiA6F3{J%B`9KKN1muVcCQ7T3On`ShiSTdeZsIt6|Mh4L!5}ePY|~}Z_^DwAzp4$ zQr69GgFUdx9xVlAUjyQD6C|q;B)YPkEAYKy7wtC}WIyAO#jFKdZKSp{2~3WU#*U!Zp z?f=@T>fqJ=O#iy(`^U8yQ+MFCmFT!8ul>!6guRoKQ&R6F)C=^$$hGsZ-Bd0Eu8$udZhWgc9-CFywTYye8P=)5qcyt2`vFyBn5k-OJTc#}Ixe5% z13g~H!BH{=-(gfZTI?o-Q5~(V8VbWHk2?bGmm6}ss_r}zG!M&>^yOn^43t* zfu1J4(mX$l)n$;ID4WHte%DMa@%(e&tAmiLWJHJl=SvS6nq&9mL=^+QiCr$kI$@2k z%pPus6;2pR)DZS8MnUL(r9xs&S+ICxI_E+hZwPKoru&wwg?bHl}|>YdY-Jaa!~Q50Z&++!0td_e-If zuY4fvccpL+S!?a#Ka5q-^V1~~CgynPCO016NMpX<9!Mo7keQk=B!D5}#r3fauvb&YcKt9W3UHCSn#DW(PIkUfijn-o6JG2e!EJqR zN9^tCj96j{Da_BL(}ld84MetytBJQP4-G9XzyuWlyf%FbMap1vc};t~^scn#G^Jt_ zNj}W!`s+*LUzL>?Sv({fpRasGt694l4+j_*{k>1$nj?RKy#}&)QI)D(tk9)cn^?Pa zyorgAyMMCOSKo&NocOk@jFlga)= zRZb~am;1Lti5Q@VBd614IQ4I^uOn>)iHlyR_0|b`cU5N-=eh1-0w@j9-a0imdTA=x zhxSXOv$V)+(fvyz*fn`Pk;PM|cyz8HWC&+o>d;8hsamU8ZRHo#%cZ9gY9CXaf9F}= zKP;0>rf;yR+-Bp$>bD+fVWmqYEKO$L*(IoKb`8Xix_#3eS;*S^ZZ4nQA9elcx(P9r z{k@2{-B7zCBu-p8(X?4P z7mDkyaa55~|0a$9TPZH_Yg2b6OS&8tV2b%xp$+>&iQGN5@B21p%WTKVFVADolOF&vZG7s(w1y-y^N0y0a>mXvJ3S$o;2F+Vpn}S zqf|?!)ak&+0Y7N86$iqG>PiOVz)$+Fq9@c9318w)rm={W||KZ#Zi08Un?kvrlnTOrFE;vO0`|YpP(F- z@^M9AAR3sEp9{yCB?DlzBtCq5bb=1#X%Nc zpG3fI7E=0ZcTlbcPd@H&tC9{MhwCx}AXbZ<4ZG(v1SH#9@q{eRU7}bonWb($x9qqu zSrj=!10v4Zbbrv@qD=Wo2GpOkdW`FH1-3$vTWRDqJDz=HPJG)5!k9T<@!S4#kXd^j zs+KT;QgdFcdvO(K)?%bNd0%@Xm>%}uX#G&bkdV9#`p|XH?ZU<;{ydQtjZ6KFGU~pc z;C*(e=X=e}Ea0^@3lgtvf$TAFNJsg+)D>ndb8@fL@c5{j{O-$hv8zLKa1hx~AU2-0 zCXx3&;yIb@Qm?xj0@US`mw@ugcTO&E7HY6r+&tA=oJD4gzAMoA;iplGUZD6AU^B7>GDE-}G@=4cO){lO9g=U2aK(3IGXh zNnk(DUU;3&>6PCqJrcGjC;WD?UV5=$ZPseSqQ?_XwiN#}9OsFRo0F5#;e6IK#r-Fu zQnkl`pn|;?p114ed~Sb#-&(@`d#k5=_4m5kro}_5?#PJPI1h}Da}?8m(Z3>=oG`>- zBW&6mD&KF%%MJ5(1tj>07900ofFnX#W~!LeRtH&+#OSj(3b}ReV~Y)ZglLcf$Nl|n z>=)73cTP`v=A5tqgOhD)%pU-fAN7uPtVe)BhP9J{&U8LQpR1;?8cTFNj=c**7(fpT5~j86v7+_+I?e53PTpTTd0Aco^53n?(qJC-hcV;c zzHS#I<{@)@U9Q~png|AsMpK8!*6pRTSsd;g1LfMt98T=+6-&20qofk*6S;h*gW7s? z6ZPO=A@xT{^4?B9?-^;3D}TMQ^QfE*Trk1Vei;1=7;Gyy76)+=bDNo%(;$Dh13SZd z+-&yxms~#Q7JlVMxcR;K@5L~2_>$UG4xi!8IcBvkwu`MAF5nN=!-HDbZSL^+;>_Sz zH%OzQepLrd5~YmB$5=gucf4vdCeNZ}vt!feA+GV!S2v>TAsPZH7yy9|#v6eYa7EG7 zgoXB=;6WxWq3sNa@OQdB-$=`zfsX+Qt?+Oocwhi(|2j3)V*t2p1iaF{J$-if%ft14 zLv&v{r_90{oDeO~6M4A;!2sKveQQ#D9lovrK+fMLb7yz!WE^Gb~0^zzclyM1rX>d*i^y{n2kDC=fsJ0zGlI2mUJTTKW0D_oYnA)0I^FjYqPsm3_jbF2j{-D%AC#mfx`n}5@cNU0}FuVcxa|tp(DyPv%V(%2 zeRUB`;rQHS>W7zV=6xk@C!^iR&UUcI^r4=>vvycEg(RSbDqi2M>;(LYO8O$DuX~YY zpw`B4bvKAuCo*PGrxtR^l#_9BA&tpTmdZj+-0I~PJb=YI5BB@aqndy|hyGuj_ z&i#3_S(2M?E4t{okE_E=#h%S|zJ>9VuVI9zBSL|tfkR@c6kHXj9^D0_xl^;`n9^!W z4odUBZ1oeYtUXyVqdo|V5chhu(^bC43TfD|mgQu+i9w~N`jd|LAxBDW z;pgC+eK|wJjeKoJ3b3W(cQ4GhTmh@G$cIa#5dU^<$C31Me{7#DuH=|+3gsV*=Yz*q zZ^SM!oc&6tD!3WkJV>Ev8RI&T#aPwN4UmbjGKCbM;e~~=m`|`3+571_dWf87pK#ya z)>aU2(`qnCAS)|B4qp{C7mhwznHn8gcLel>iYy!YKb2Y%Xu>f^&#i~0DrUwCvNwbZ z-Wv$&Kbcb1;|9S?l=(OvxZjcjX(fJgCyQ_=*Jn9VhdWW5a~>!l{pUC@As8(n7+sP5 zztM0fH|75u{TlT@xgy-{G+(*@8&#OJ`%muwM*rX7{~aaxust74Z@qkENi~`|93W=? znAd096z;33p-#{|m!Bh=`9o!_PvJ%H_w!R@Mm>!^W_Cz@|5p#$?MqR_2PKW+C;iN| zyTq$2aMyZ7llGyOOYg5J#Jl7*onr*0_2K6)rZ?W1vn=r2JRjVj9PI3324+-AKG&U+ zF%)MpxK?naWs`E_y9DR-mK8sW&3^u;?wn5z-=zYWY$1aswUIJnK?pGld2mw;2~bPP zqB%ORWQaLfcbZdbFp{>0>n3q!Ov_0uP_VWXH!wDrMHhwKUyf-|F&MY8{R1nM0Qi}s zm64fBQQw?)RW_ciLNS)XC`8uaP?wq&OWnLH!EZ2JeW0Cq%5Ua`zoh?&Ff0X*|B z&llW4Y5t;!I@-Ic2B-*eQH3(ce@7IKpk?JwN?ML+uw0S)F+v6pYea{i0hm={)!dhv zv9vQK$DBPWFUM=z<|!Cw_}Y>tA_K2LM`yXnA+!*_gZk;}iEAnKx4DrL5|)fC>vwj4 zvr{b^3Q2^JMl2tLvf-J*>w$eRN}=MxpFh@LlnlzZJ0+8nGRRalv=WszUdi(01{tL2 z>1ZmJ=K9|s@sgZdVH@d-+UzTO5tOc?d2X9~jFT68QDVwL*p^ZOfYwIml>7@WP}JdI zYTI8`21?V;wpLYIdK01$RXe?=qNCn&BuHU*Xl=J#wZ5NPgC2Kpa6&}Pru*5Dy`OJ9 zv$OwJ7g#MWkmr6AU*I~Ed`@0I4~DzRp5Hg!mgK!Ik%yS{cYGNtd5Zc#i_K{@%9$K+ zm|gxxLd;fejqGc4A7QKUJ{29zD2hw82I^cT{I^NWy(WsM9ix zE+0B-q{FmjHtc?J*I@D3dnSHaoFo5kGPh3{mlPjc)@R@0bN49xLoxGK8=Xve+vx_KUUr&4{~Ro)8^P@@>^cL z`Avb3dZ<`Q$LsAShVUo+f13Pjg9WR%`>&H~j`MwP>{v~-n4|_KQ zDE`iBsK?G(qrJt=6zKx*u@e~RUnO!n6$Uh(T24w`O-4|hy|pRtFt(YS*rR2t@CsU& zZ$YURZLFW*Hz`Htdf|Qw*iiF)=GTIhhu(XF< zGQ4&X$qE^Lb$F+U{X0`?W=Y9PmAeJI3j@`+fh{(sYC7@xsBbQNg^OnddrupjilI?&ot$q|tVB&3@j|7F>?a+E zPv@OlE9OaQS$5ScH;R}(O@#M*ngKT>yLify%}#&elSU$ zF&~Y5P;OrIDc>Y2*Whp1ZP!JY6#tQvxm-72QQXVRh_qkjuyWK^?Lb${;ch8@tZsfD zq(gm-Z@Rj`C=eR&n%iWZ?iRbD!K~f-IDI{nDta zoN@{bQ5wTNV#il+)yBwesNdD|6|{G(6PHO|sjHYsW6C8}^|P6^ANYgSi+;_Rbh_U? zJR+snNn*eHyCBz2ykxRsR&6}@O@R62cIZ#OWAqU+a!Zq)9c@;Z)2IjTVb|;_OIKcM zgH8P1dO$|=ncK~vP+`%m4<3iEX3sly^8EY0oAAX@fw>b>O!3b*MW`>f%NW;nj%96%>0G1ZAZEH( zDmU@;Qqbh&4s6A~rXkZ4G!!?!hokzomUh{BIAuv^i_x-uQ;&d&1KE=|^qk|I>CC}Z zwhw?ZOTE8vE`2z&IGU-mezcQ4ZIupfIKh%(ZIH{#OPxZE`pZ*&wtk@trc_7_hL)MU ze8QFBg`~%MKCs&;k>+MNX|}-MUBpj@W^{~piS z$_h3PXL{IT7Bn@Vhvjm+ZbnlWEoq(M&aoM;AJjd!Dd70k=g@#J^ zma7u&mX(){kx8);XmEV|k$21kjAOVV2Rt*yc_ZrjKMdwbE$-Xv)doLvprMmOsyt`N zdXKM8FW>_vneaPLmHMZGX>ryFbeSidj}Lb~hyV_|Lzgg2f_ZorATng*U`GAx1}NRZ z!1|gnCatyVHr0X%Nop}WtEm$hYu=H%8V0-i%jVk7_tgoV+UJLCinXS;f3Nw6dq-~# zRfbR_4A$zbvgaWbuh}6e-qz1O6lZIB+V9G%P#$dwEzR{Twf%Ch-QfAU5ANzT-}mJn@kJjQqqoiy*A_2_>sCS zIR6IflGYfe|IHer6x*BuLTH$H#boZPFI_~-5CfL^)Y^=un2}*v1I`tz)_n2S2lPxX z6MUvBK%MLyDr$Fo97V`X1a)>Ax7CZD-Q z=)2_ccA8ygif!)k*Y#npDAQq!Zuh*g7QS8{%_IUOx7(HncAIPfux*3|LD^hNk#|FQ zu~ba6iEJB&9n!+3Z3=ZNB*IRGPMa}5W|Gt@Ul9^A=Q`ifhCQfomfU`~!*fkHBO%DJ zAx^osyUmm@TSj^F00M)?OskEf2j6w?*Q!Tn-g&lv$nJ;RG?pocZfLX?vk|}A zlRkoJwZ+u*!po)IUyud1_fH2xYMvd!*Th?*$DZ*>t8o8s*lZ! zme`!lI4&_OC%}3N!-CaNi&<@sDJ9h3gDa&@*Jpoz{fFzf$5NZ?rAD!H7Tw`f4J}vm zxPcbl$q|lh)_yb&(Pn*7OI4H+M%HOqRa#E;Fo17)a1#-;{`gu9KloOE)C3_1mO$|^ z0Jj_|)a<(MqGby_Su;&-x^tWTbQWaWf*8`ovZ7MXmR!Ujvho@F-q0# z79(fzEGn4Ua*1X*ZFMuGO@`06>B>TN2#G-wBGOZr%)5qfNQp%ulW~g?Lbqa=v`aaS zX6Abkbmlf|^UX!^?Md7KG{An@2f|~c7j_+=$G}G4*h5wLz}kaXCTd(UaOu_skP;{x zQRT_TjN_8p=(D*XeVME~|ELWSV2RA(q-_5$kg$MMj{q{v~BQ%F4!T+j5 zu61u+>YE|J=gwOE-EwDLeaKj=9>6^cn$#3qJdiGkEy-0aDUGZ=qa{ZQrL55Ag8TTZ zDRW$BAq9lnJ9^4~9TB~HHg@5JwG2^jtQad-hGC>p?Wx#r2w3=fHnn(Z6%3Goo@wxM z(cDBEW;4;EgP~k;Dwj$|0cQs1x1A<{LMr^{7UKp0MY#Hd&C*(?b7JdpA3=0#A2ly( z`)3iD;sC8GP)iymzwI>wfZ$!lLF@s(nI@}-VJt*#u40+Gnm{gGdwnOWNFN>=M*p7i zM=u%))0WZ4|0yluLd380&B#C%MYW9IW7@!&_{Mu^iyS;bT=u+K$EWllpzs?O6v=n? zhhJ5zx&fy5>($-{3J<4lO;3z=EmHRvHFt%W7|RHq{G_`|vy>V8Kd)$3Ofj{c_&aSov)oCf~Yq$MYK$Hj4dBQ5g9SD`s@ zWr!k-VoS@>@vyy9G$c=+dx2JQGfBJ}k{}oJKPl-Zu}ymj%5SVT>r>|Ebr8?;(gU#~o%4QBFb~PFuVoUY zie;&|XeQG(T!>HL^M1?nnp;5`RIQ|pj^+bc~XbiSpBhmGyo3JlR^w>#+L z{q+$PPN0kK?X4|SZP>j3jw(TkG!mgoR|9%t7M^5fo_ja+D*v(>G}0!{dy$Jna*=x~ zB>_(l5~d%nFg!U#j4RWTmmlSjHRv9s>yXe zNK3Xm+5|p|ZT;Ho&fV9ZK|F+-twlGB zPPE~@={d5AMf8w)&efOT(MZ*ZE#G?K)cxi05lv9)jz|9O{q8MLtcD4*QeAF@2bzhH z>EA4BDKP{XTQjiRK;fR5uEuMExQdfmVqLJE?efRlKz6Ra;`(3aPjvrdLCJNOKp?yE-yXb}%1}QI;fo?>=` zq`u6mwueWcl@2#-kGn;agHH6bb6Pf6+aNeRb1+E`5ufGVys6njR@OmiHFwhe95ZLp zJZagEwtT})?^%moQ~pS-Hfo2)a4n$c^zYddMQo1rEi0{o2qYJRM2(|Bxc}RMsR6>x ztIHC;l(Y+VL*=lUM9tPsG%q&p?@Nv5--lN-##^zcL6p_vI$(0+mAdaXWNE~Tb}MHe zrpV#l$kYG+{o4|1`?;U5l=RRW6Cq((%TLKfJYOIte&_sOb)8jEoKe@M8xjZ*tbyR# zxCajw+}+*XgFA#^jl0uGpmEpW1b26Lx8Tn3{WDebUCivuw^r>s_1>I1=dAs#q>073 z$O`pBPY#P*x!%X`#OewnXOzby5@Y&vL*3CP9F9_+j5-`ZAOK{!GI4ksfv~Kt@2bm) z%o|8YPBmZRdezLA{*#HGPHty^+lnbktvXM@FVeAe+3!c}a$Y})E}u>WCUeII&-gir z-+SAv`%GmI%|=eK5=aWptZy0bjGi@ULwLjba;{tY(5j|$#B(__bV3LbyLvnmXH-;I z&P;2u@Wr78X*SOgPIl<&JNcML>+b0uhY|^Vnsxq&8Zb@OXTgbbkxV*3=e3}zVWnLP z0_6AhYh2nMQG9_?7odmyU>N@LlPBA1wY@2)$1Mhc?<$`qzVt_5jr1eTs2Urt(gEdzO!AyX23D3Fw*(j+f>Ias!z#c<{R%0I}QMr78gd zFK~!YNg-0Kchfof&T^|@l4hFK$*R2Xo0ob&_xsGMOjDYE zd4CTlafm~F{DX&M!b49tKD2jZp*VFr+NfKz+78fMSqOSx`t60wHv@Yy4d)~&Ejcc<%>D`8R zkTmKXY0n6`+)>a7{mT}fkl>A<%QXe4ziDW!DD_^jPSZm@hYl)#P>QR%{O~7q===8t z@&gYItNTm8FC@i?rm3M~8f@0g8W*l>mCs-%=#`SjXtPzj$Q+Y*{y1%KBfL(n|}-eXW{`g5gH6G8axjCen z&DODfqw2`mqSjCjcPcES57Dc=FW*8LI(o;`bmK^gwhE7HVs>bVD1ZsWshAD&=acZy zah_@Z)v&_L4&m|(7Ngh`a1;kECYDrgu35D;@3q)X?I)tb1poo~4ybeqiOf08^K_}4T znDA$nW?rwp{RtF->`A8r{fjc;CDZQKEJNW+=7}~JuOvYf7#da5peM>A63> zxarNID!F*R7E|g|9nlmA*U#WGKT)s$8`t=PDJZ%#a~UY1pmtrvnBM`19h-A>U8$ja zq}p`7JStsZ;)C4exb3N0f24-19GT#QNr$eg|J|Ei{!n*N$u`l+8I(=b@>*5nEvK?; zU^P{DcJ?q099*LNLWJzZQQGXe)oG!BGsO8U@b?Ls_yc@ZG0Q_Uoy(hIgps7}M@mZC<~;MG>4k zv9Gn}a8xJB1~^D9liQI!Mq_YMT+=dO9C6u~FW*|t9VQ0r;-%}9dV4h~A=lHjgcl#z zqga*JI~eZ~bW#8Ncbvh+!^H#JOyyhfn4HFK_A>KZ#6`;E>H$g~maF+JxY61IuQLBY zMOH*Fe5|?7w`Ic(rt2y`kJ%hdfydJ5{0&BM0rJ^9CQ}7-dLHW-NyZh@IfWUO$Wqhw zOjR;1;il`AX}?6p3vyXL3v9wCz27}^(eUT}ae1VYM~3fu^!bTX-=mbqY^yg^W2h4e z`Q2kr5pzs@za4EtVvNyEVvxpPw4JHfSfzRzCuPuwDiFHb_QbmTxge(GIdrD008C!yEsrck_z zV2N`}a;>b@V?)VxJ2*Qb$<$9AuMvNFWzX{#z=Q)zGC~Xr_C8fAIr6fQ&S$tI8;Z zBrWZtQpM#N8cHjSAb1kkrb8?lon-@)-b(MD-tz=B_l3+}Y5|uu3IS2v}$+WT!*8FZKtKF`6Y7)KUx&*WFC&$mlK9@YqIep#I zhmJ-pv|LMvLKL_vAHLNvj(+9K3NuCl0ujZ0{fHj7L|PXb;tl8(zJt(z4};si-ngqP z)*8fiWi+~Y8?HoA5hqugoVY`44_4YYXCuhuwCfvUF9b6@_xoO4DAhWe48HKP^plCj z4N!9#h+A-7-(n*K^{(t9h+RGKk#<@+F|T_r7T8^V!jXqsjc9*taK`#o{Ac*tz$~Oxk1LZ$E#grap~$bFDr2D&m@(pYxlIu6dunX@lYvHHU{HM2*=YQH&^vV4B&j zPmm`U`^`u~37V3f-RaaqEA!}4c+>+Ualz67M0xX2Z&t26mjoYPHUBqf414Sr)Q8<2 z_~~#7E$f59Qbg&znDSI~H6_KKJSWD6v!zB8XKGLRDe|Tpu)Q2G0FZKdFO-|xwEr{A zt*-!}m<~+p^K|(-{x3$>(SFTQPyvm-o}cr;D!ODjXLHv|Nj7kde~G*G(G(Hvn}_O+ zO2p2{)c({vQ^_pm`^TRzH^?~QK2UJ(DpW!Fa^ys}4gR|J3n>60*qAM>=qn@Vqo-1> zyl;!|#>`wTq*f-&;)!WgN4lJ5z!xJ<$oFei{p^dk##Pud?)a_ST%sfe0I(CQxT9ri zs2w*|9K8Rtf>FjfetU}EC*&F%Ww}d^S@Q+li^0Mdf$BpGZ9&6d zn@NXVj&`>AwxAuMdxebLE2i9a!? zedO>mLbdtG&*2n<7akXyh2;+Sgp%`S_YawyeO&9V*ULvV@L%ariI*B(ZyE?Wi2ilI zA|A^VF19F0*o@igdGIr3z`p!7W78mdPd5E`*}tt*XwR>JF!;ISVsggJNFkx}%;0VD zwfxhV1Wf1lIuitKtc;NQ1K?-5%<+f*TNih`KW{x};+5qyqNG8;VHGOVTMh-chELYp z*SO8+_MGrtdTA31N1A=8K_^Ro9a=K#=PhCYnxQI_Uw4!AFkxutwu^P<%UL3nW_3bw zJg3|L*4M)1Jqc@mOfBT#D2M-gdfFe?^k?9wf9V;kw-OtAq^?B0TAjYSNrqjlrw-v_D`K__w9Il^WfwVW(E!+l58%` z#X6fsUx>-z;W%nVTCLUb68&Fg4`&Anr4pN^g27ViNWq@n)vLJ^-^5I}r{}+i*%itM zvc9}Re$p3b+bP+6$hwb%MZ>h(<&%!bS^ici4aW^k*f11p51SdCF6cjyJZVRrdd1+< zrJ-2pNF91lg9VuLY_(JEi=6J4%~u$5ebKAD;c9}N9#(H_cHXE%H-H@OI%oIm2&A|L zhUb103x|(AA78)OcMgD&0E>ZYI;b==IrIt11TIizJo=n2W}>$TrSAYNQUA7G4}jQ0 zpbWL2=U)MG#(z6wy;qHy+cZaaD4FGXyfMR_4PLuR<|zsrZ~CrQ1Pjo{|B>>^fI`Q~MK ze!g7?wp87b#hWwfUYto!8fbEz^4{t3;czOkHK<%m*@^%HIXv@1P@5r&N^Hg>x7^#< z_5u&mf1#yjo^UQtAJ`HKB7fO^0~*@2Z7}aW^}iMD=@4%{=Kt z+VWiL)k}U5_T$&5puG=TE%aLq6mjsP!ij%p`;wb%5yC%Ggj{=hl{@L}C(+g3)JlM}QBg>3iRA&B?n>%8IfnAIM3QLeACY)m^B4ZRH%&hLKY2bFwI=tntf z{%5N_+VClJb+**uEi9o>Hl5uuNFh6B&tG4j9JKe`Ua~&Zjcn}X6EvdOboKZbLT)gG z&cQn`ODM31z1eQ2 zE*^JuKa(^+%8sNESjtU;zmrhm0f9I8Nppha#+Omh58wHR51smMPSc7x_;aTg{+Noo z1#7fS*iO%C@Oz~iiauLG&Ku}s1__JYi=?$qp04tW z;6_iRW5@}uvCW!7{+87ja+89~%1(&N*Kh-HCN1}timQnLuwox!!#VNw?=a_G+p99K z24dQn*WQ!Eg|h>?CC~_Fs@pPHdD#t0S{!d9)@ewwlG5^I#$(aWh7M1kuH#g1ZA(;V zgAgcH)X(sED;b!{ch4L;PS)!-R9j-kNpu{H>@skg{HOlvI)ARNs8ift#Gq+W_~f?k za~@=U^tUW%SwsRAZo@hx&dqjZk|F|IQ|Fhy$wWy#e5qTO`G0JVCtJ2xOQs*SdFvNl z4O6(M#9aq>D{m{8-ET$;24_#}>kHf%Qq}$f17hh!L(#NQ0Y4`fIf*D>0D@QW>Zzq= zY|eD-wOFtifDO%$hFT5H$+^|R6>_U(3^0KAG8Q?u$KUfe7O)wWma`tJ`1WeF$))V_yQAwlLpI^ zB2IpIIeh*yk^Wo2%+9WgKsMK-@~6tMZGoesLt0p0MOCZd*Q1I$9R_81vv$7hxDN>5 zP|>xp1uwA2OAiszXw+>B*51`YRR% z46WsFhj$G8`2OsRUbSd&sy#|s-atIwG3v!MS;0gTgs!vnWhD{34v-S+tN`{d(G`E_csvTDz|1OgP zRlq$@QT?Oo?mZtIIj13CnIbu&a-O-C+6gNdLn%Yxb6z-6YM=cX-^mmapfS!GP-63o zYSg&Rznl(&5e^|}T7U(x>vz~aO(2$TStz)@TcRj8b~5%Vaa*oh-KpI_+mu4cTWTb& zx!vg`I{kaIwQX_&z@66DjNx6IeU3WlpIO2C4?)BsLT%?_6_VKLhdhH($g~OV)NIc)@ zVO+$WdxC+8nuCil3Q7B|hB?)!^WzIrHNqA9psmudRwCxC)aGDk~zdJD!EGM#m( z?d|bi>!byGLHz9MI#cNq&d)bM)7{UZ))>B z>QlKZfgaR}+nLhPv;7-p@N7i;^lgEoiXEp<{L?Y+w9dTo*~pxGj2&VjA0IyN`$Wsf z#8jP(jAG^Y_d>;CC?)04W3pz#(S+;eZ;W)zaQf{&^f5)%qUyuBdPsTw7l_}BeH=7R z65#J~Dof(6T{(%H>Q%Zo-Du@#AE0bD)zC|YJHnsI09k3aR0V4I(O%o_TRN=IG29h? zMjNJfv-^mwm`KV+jt>JsR**)@#P@&==J-yWd3eZTsm4RD!v8Q{T;tb*xjk1WcAmQ} zueYiJ#4J$WTWNEhAL@M{z}S2Tn$D84v557d9$TcOA=>@Ve^@CK9F_`F%VG%t#G1+M zvJyq9#pSH8{H?Bmb#VCM7UFigHe4~vd$x-HF}L2tTNypRFk^9u5Wu00(w!#kS&Ls^ zA&p`?fv-u5>v*-{uED^!>_a;0GjyB%Z6bs{jb+tg`Ij1=h+?|k@<>*>A!6q#v&OUS z{@n{wCD-bQKFR%jzUvH@X$sQ<2EALNl@2Snx2On<>$6qphE!d_AUKy1qFL(5xz3o@ zPTCx%WkqXZW54?m5Jkms>hE|T-#g5gp{XPcNfYhFbA8$KbF;dQm%943%#F0QjVZ9= zQI{gI{LszkUXGWt(2^&vuQ@isV zwhP|3^w-;+G@UuWJYOD^EMLpVGSrCY)1CsGqFFp#zy@xhy1~PcW0_FthbnvaJpYWm z;eIN#6XoQT?sS8+K|qb?q$s6%B6|L zxH0xSeb%MNiLr4mB7RYVIxi73p*o?`Qo1^?udZ(wM+C{!%w-3ke)5!uhzKUnS)u?8 zd0lpgF48{ZjGV9L{+q5sk8vz*;jG5V$q#1Ojh->jjmYa%-YOVJ@w9$UDgBV6S~`2A ztTJb}#-xlBM1iCLFZXN9+4>zDfdyvN;jz*1ZFYGG8Kvxhp7Omtfh?t&Tx*vLnc9E3 zIPE*HXguGr&yL5PH@%mrkUtYx)$%wxx?w8M*lY8V_P%~6_SJM>zNGAzrQV+0?IrgG z6&6psXPv+@VMm`zP7a#MsE=y3K5vw0C7=e&TfSlct$cna<-#E(I*zP=DBj|dy8rgp z?JU9E(E|dNBYyszQfw(YQ(~G+#!?{Fc=>!ikO-QlIICR%x4d=;faS`Pg|G|0Hy!)$ zd+PV*IlP3F-y;IAvike-rPmoIw=b2m;NamtsbLUalPW_kfGh$xgL-f4%A~2wFU|o8xDatV7 zL5zWQPkL$O7z_k*CvT%GsbK+q-o{p+!n9cb!`1*owWMI&Ujn;KlGs7NE8cT>Pdw#% zjq8Wdl`?Q~h;V-h&`^MCHMLyf&vvJA{olNqciEl#{uE6V-DANkG0G9K8+zIA=Gxvy z6ct%ef;IIoDE71}4zH!Hq%CEei(_%ny8SvZY3NHeIbA#Z&M$3}4Kn|MXui^X{hy-Q z5%Oy9a#5F?Oo&Zo4-t{qASQNUrr|>cszHPA-mU9~ojcUPn0V6yww-*wNZEl(X9Kn_ z|4e@#Bw(DH#HY{_l*oqGucTXIH%U@qG1qq;Pv6S_Ecq+mgC2!UL4jZ}oI;+kNjzS( zh&BNxab})jmH_e%8UiB=oUew(rx0pbyq9dkZo!$uma8giZ6^ z-{=VZ`|5ty$0t?EbmwXN=MBwW-?W6EHw znoqf#K1zt}h&o8~){E0mbn;I;k7R$(_Z($@d6tJK1s$1uCw`QYHOB+33DmFc=LJKN z=knAmD?KV+;oH5m^;2Het+S6YEjsjR=31(W9l!QFs@498XL$78hw-(%Q7a9_1dex2Mbn?Fq^P0|b>>zAOQq>*b_3FkxL)qVX zHNIKfQ}A!zopoz-=_?zjdu<+hZo8IkGYKoO;?DqW9xWY1Ep8dG-|EG9gAT$`{j1s7 zrI>bH>_SHFeGWx8d5=^;Afu=b-ESV7=BbjRBkA5Gi%mm+m1Sw-{oY3URNR9wSfq6| zPWVgQbc9*Eg+m~u<0v1Vl<>^EsrnELo1>Q_ zDt%C+#Pbv>3I+@uqrdV10H`feqC%Qu2=Y{lj6J zq>N&5YHJ~{&xpHW%33VICXsnz__0cKVE+& z6|?r`3;4Ja7L+RBLe5^T{#q#YlG&8N}Oq6guzrNrI146*m+w( zd+uydYzmrv2oy)XvO^G{=lQxNm0-W0$dvx=Dh~TBQ>W!o61iBH*>nn<&b>@8RyU_) z$m_PmI0!)Fm%Y;{Uy@(ifDX8MES`p)QfVB`*v;0Klst8iay>;L19&Q&Gx58%)Hq*P zeCPJhMtjhIFygEA{zj3iLR0^ zsC;6oKqJw_$}BFL6x#-zGO&RI^PQ$*DhGwqR!3g zj^?0_lJtjouyDXYlJxsg(}`RHJ6dtLS-vRU zG)of5X(@+E4L^4B3l0wLkSd^as(HCX+-!Ges2+aWiv5cjWiREfHN@)PWF|SKB(hFk zOI1}>I~N8ZUK$<_9vWh%sZ=C043@Pv)ujJ4FJHdQ;pTj_w%9#~Y#Au8;2bH$m?WK~ zosdF=;-$B%t)0x2H2l77I(|K~3cPZ8g;=G5d}U9(_x-xXHiVMNIe)cs!{=e#scmJz@-XItLF?y+t26B9{ZNT(*EAnvqIoS`ByF_i)`%};W$edxN z5J%_GOzZ{cRFA6y=YUm%aWxfM`vcqN3dLSRp2X6Oe#Fgu^IarX+WLMd_1zok*il zX^vTMWsX}dqSSJy{5vXXlRE;Vgsd(uJ}~ailQ~xXa&d$UK|^1kq#MWb!co9r zE%)d<0#+)6!6O+q2~SV^=kJKXYLN3pY)m#*?O=!P;bF^6-H+YPK}!AY`6G0+#~W^p z%s{a0RDE=L3*<(DeIVW&RjWu`bah)upWp568W}j5%Ig-ZVO)_uX@jw~RhrWAgD|wr zdew9t&R|7UR6Rjp#X=cARKVx^^4)Y>LC@JdXADupHD6#Vw%Z?Xv~x>tkg@qhamDl) z$f*S<>S-Rw9le_2d{MA+a}x>%KWvF0KP2#z0$#Q3?L# zx^_MJe1570EHk$rQz^IO$NYva0ocHQ^Q#HI=GlS_*}RUDy5eF+M{S;0ZmFo?wmQcl zjXNMPqTOM(eLVO=R&<8{F?YUG36HW5pL)j<^62Oz9Gp9cQZgXto0%w7OQm3USw#F{ z+j-Z2uY7Ow0Sz@u-&s3&J16gaL$BrT)by$^^2PLYED!L*`Gub#hKeQNPP9`?hewlk z*m=ikA6^%Z^Dg5+2~v{+x?UwQ@seL;f)V_g<-D(zWl%b`-$(g3+06}1bCLST>i`i& z$NNZVWuyB{4uBqHKIgWFAEGw_pl3B#A4d0NrAHvrO6dBY4>)9v#I0xd&V zc{An@&MtCF=PTCvZQKCCZh5(DAS2H+K$ zDX9LUD6aqq5S%N&sY+sV;his2o+=Yh)|n}5DbB@qi-K=(h66}tganDDa{|KY+O!d1 z!^~1DAU0li=#vFf$4s+-#dA*q^Wm~-6*iddHr-cf1hTVfw;ZFTuuihWlNo;YGgfc& zTyyK+$2o|6{*7PFaT-WGHWVb(F)lQoa$;)X+fNOutXxI zsKig==Z)y3t_(T4Gg!Z}9-M6Kz|X534XpY7=KY%mCTz1fpXT~ssRlVpNLjb&i* z$v*=Gd$1j>$wm)ot&ZGNb_?=5$L!KSjFR;OH83o2F+pjRH zp%5a-^TIc;9E5L=`?b_30{YiNAf*Nx|hOKbk9*QcYaEON|mCzc+B>kRg0V6+I z>-MlR49DjVCnr6TeD=&t&w#X=EY1`4$20;LQ1I8DuWz0_A3XmSHiTmElEH|Y(m`Vf zs$}bZ4YlBbk!F+(TCNzVvV=~0rhF3>anT1nrl_AXfeN!GyK3~V?*I6%}dMf6`3#_ ze~v`ZxkHSAow^Ku$%)#EG=<=QQ|%C|UTKwcc>Q`D>B}t=QU1|E+1I@RG`s%MI7Px? zR^(ydiIGz+K@TB6ed+t&X)b;1T7zV|S-`;8lhSY&j}3 z4MfMQSDz@CaJO+L0~F5U^7GtO0Vg{$S1k58rt?@knS>~a9&a7CB|#t)B)XvE#xh$| zN=KXJdJW#ffs3l0>*wz($>VryS+IsyAEfbbk9JT2geLjL@cOGduD3s!nFa zv0A0?{#xQZ_4Y--?H+GWKtL5hq_)jmsRfrzSdO(4`zG=ci2{)`0Xwv5w3Hx!NUHT! zXJ;d>eNQ-cz2jn(ZSB{mQEai+kR~8MAlF4Sr zV4B58)##fe3LCpJ2}3PC*%#K~^xmqGlC{J5p*nPAq z|4svK;Hq7QeZ8+a&UzhjCZpzaiLf!KHThvQk&~AEHl;orl7r9Ao{Yome#w8a7!Gfq zFD^T#!9$-w1vWu$>OC@-BRmEp9+~%)>ZrRmH{nZ7SQoaGuTpm|)mGOx%#CEXHab#hpVK zG%z$t8^=#s?piil)(I59lf{%$hAA4NVeci(#I_$C*ty;+nK5PttF@cL-gw>!_7GlG zfn(iQ2DbL^7ss#FiqDiAo12@XC}?PC4*&V&;o;o Date: Wed, 2 Dec 2015 15:59:28 -0600 Subject: [PATCH 1767/2553] doc: flowint --- doc/sphinx/flowint.rst | 144 +++++++++++++++++++++++++++++++++++++++++ doc/sphinx/rules.rst | 1 + 2 files changed, 145 insertions(+) create mode 100644 doc/sphinx/flowint.rst diff --git a/doc/sphinx/flowint.rst b/doc/sphinx/flowint.rst new file mode 100644 index 000000000000..dc8aa6676d71 --- /dev/null +++ b/doc/sphinx/flowint.rst @@ -0,0 +1,144 @@ +Flowint +======= + +Flowint is a precursor to the Global Variables task we will be adding +to the engine very soon, which will allow the capture, storage and +comparison of data in a variable. It will be as the name implies +Global. So you can compare data from packets in unrelated streams. + +Flowint allows storage and mathematical operations using variables. It +operates much like flowbits but with the addition of mathematical +capabilities and the fact that an integer can be stored and +manipulated, not just a flag set. We can use this for a number of very +useful things, such as counting occurrences, adding or subtracting +occurrences, or doing thresholding within a stream in relation to +multiple factors. This will be expanded to a global context very soon, +so users can perform these operations between streams. + +The syntax is as follows: + +flowint: , ; + +Define a var (not required), or check that one is set or not set. + +flowint: , , ; + +flowint: , < +,-,=,>,<,>=,<=,==, != >, ; + +Compare or alter a var. Add, subtract, compare greater than or less +than, greater than or equal to, and less than or equal to are +available. The item to compare with can be an integer or another +variable. + +________________________________________ + +For example, if you want to count how many times a username is seen in +a particular stream and alert if it is over 5. + +:: + + alert tcp any any -> any any (msg:"Counting Usernames"; content:"jonkman"; \ + flowint: usernamecount, +, 1; noalert;) + +This will count each occurrence and increment the var usernamecount +and not generate an alert for each. + +Now say we want to generate an alert if there are more than five hits +in the stream. + +:: + + alert tcp any any -> any any (msg:"More than Five Usernames!"; content:"jonkman"; \ + flowint: usernamecount, +, 1; flowint:usernamecount, >, 5;) + +So we'll get an alert ONLY if usernamecount is over five. + +So now let’s say we want to get an alert as above but NOT if there +have been more occurrences of that username logging out. Assuming this +particular protocol indicates a log out with "jonkman logout", let’s +try: + +:: + + alert tcp any any -> any any (msg:"Username Logged out"; content:"logout jonkman"; \ + flowint: usernamecount, -, 1; flowint:usernamecount, >, 5;) + +So now we'll get an alert ONLY if there are more than five active +logins for this particular username. + +This is a rather simplistic example, but I believe it shows the power +of what such a simple function can do for rule writing. I see a lot of +applications in things like login tracking, IRC state machines, +malware tracking, and brute force login detection. + +Let’s say we're tracking a protocol that normally allows five login +fails per connection, but we have vulnerability where an attacker can +continue to login after that five attempts and we need to know about +it. + +:: + + alert tcp any any -> any any (msg:"Start a login count"; content:"login failed"; \ + flowint:loginfail, notset; flowint:loginfail, =, 1; noalert;) + +So we detect the initial fail if the variable is not yet set and set +it to 1 if so. Our first hit. + +:: + + alert tcp any any -> any any (msg:"Counting Logins"; content:"login failed"; \ + flowint:loginfail, isset; flowint:loginfail, +, 1; noalert;) + +We are now incrementing the counter if it's set. + +:: + + alert tcp any any -> any any (msg:"More than Five login fails in a Stream"; content:"login failed"; \ + flowint:loginfail, isset; flowint:loginfail, >, 5;) + + +Now we'll generate an alert if we cross five login fails in the same +stream. + +But let's also say we also need alert if there are two successful +logins and a failed login after that. + +:: + + alert tcp any any -> any any (msg:"Counting Good Logins"; content:"login successful"; \ + flowint:loginsuccess, +, 1; noalert;) + +Here we're counting good logins, so now we'll count good logins +relevant to fails: + +:: + + alert tcp any any -> any any (msg:"Login fail after two successes"; content:"login failed"; \ + flowint:loginsuccess, isset; flowint:loginsuccess, =, 2;) + +Here are some other general examples: + +:: + + alert tcp any any -> any any (msg:"Setting a flowint counter"; content:"GET"; \ + flowint:myvar, notset; flowint:maxvar,notset; flowint:myvar,=,1; flowint: maxvar,=,6;) + +:: + + alert tcp any any -> any any (msg:"Adding to flowint counter"; content:"Unauthorized"; \ + flowint:myvar,isset; flowint: myvar,+,2;) + +:: + + alert tcp any any -> any any (msg:"if the flowint counter is 3 create a new counter"; content:"Unauthorized"; \ + flowint:myvar, isset; flowint:myvar,==,3; flowint:cntpackets,notset; flowint:cntpackets, =, 0;) + +:: + + alert tcp any any -> any any (msg:"and count the rest of the packets received without generating alerts!!!"; \ + flowint:cntpackets,isset; flowint:cntpackets, +, 1; noalert;) + +:: + + alert tcp any any -> any any (msg:" and fire this when it reach 6"; flowint: cntpackets, isset; \ + flowint: maxvar,isset; flowint: cntpackets, ==, maxvar;) diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 3a500c440717..1303fcfa4d68 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -10,3 +10,4 @@ Rules payload-keywords http-keywords flow-keywords + flowint From b3b5e333e4a1c206242c9bb130d0f3a1e43ff243 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 09:01:18 -0600 Subject: [PATCH 1768/2553] doc: file-keywords --- doc/sphinx/file-keywords.rst | 138 +++++++++++++++++++++++++++++++++++ doc/sphinx/rules.rst | 1 + 2 files changed, 139 insertions(+) create mode 100644 doc/sphinx/file-keywords.rst diff --git a/doc/sphinx/file-keywords.rst b/doc/sphinx/file-keywords.rst new file mode 100644 index 000000000000..f35e3fee0ad4 --- /dev/null +++ b/doc/sphinx/file-keywords.rst @@ -0,0 +1,138 @@ +File-keywords +============= + +Suricata comes with several rule keywords to match on various file +properties. They depend on properly configured [[File Extraction]]. + +filename +-------- + +Matches on the file name. + +Syntax:: + + filename:; + +Example:: + + filename:"secret"; + +fileext +------- + +Matches on the extension of a file name. + +Syntax:: + + fileext:; + +Example:: + + fileext:"jpg"; + +filemagic +--------- + +Matches on the information libmagic returns about a file. + +Syntax:: + + filemagic:; + +Example:: + + filemagic:"executable for MS Windows"; + +Note: as libmagic versions differ between installations, the returned +information may also slightly change. See also #437. + +filestore +--------- + +Stores files to disk if the signature matched. + +Syntax:: + + filestore:,; + +direction can be: + +* request/to_server: store a file in the request / to_server direction +* response/to_client: store a file in the response / to_client direction +* both: store both directions + +scope can be: + +* file: only store the matching file (for filename,fileext,filemagic matches) +* tx: store all files from the matching HTTP transaction +* ssn/flow: store all files from the TCP session/flow. + +If direction and scope are omitted, the direction will be the same as +the rule and the scope will be per file. + +filemd5 +------- + +Match file [[MD5]] against list of MD5 checksums. + +Syntax:: + + filemd5:[!]filename; + +The filename is expanded to include the rule dir. In the default case +it will become /etc/suricata/rules/filename. Use the exclamation mark +to get a negated match. This allows for white listing. + +Examples:: + + filemd5:md5-blacklist; + filemd5:!md5-whitelist; + +*File format* + +The file format is simple. It's a text file with a single md5 per +line, at the start of the line, in hex notation. If there is extra +info on the line it is ignored. + +Output from md5sum is fine:: + + 2f8d0355f0032c3e6311c6408d7c2dc2 util-path.c + b9cf5cf347a70e02fde975fc4e117760 util-pidfile.c + 02aaa6c3f4dbae65f5889eeb8f2bbb8d util-pool.c + dd5fc1ee7f2f96b5f12d1a854007a818 util-print.c + +Just MD5's are good as well:: + + 2f8d0355f0032c3e6311c6408d7c2dc2 + b9cf5cf347a70e02fde975fc4e117760 + 02aaa6c3f4dbae65f5889eeb8f2bbb8d + dd5fc1ee7f2f96b5f12d1a854007a818 + +*Memory requirements* + +Each MD5 uses 16 bytes of memory. 20 Million MD5's use about 310 MiB of memory. + +See also: http://blog.inliniac.net/2012/06/09/suricata-md5-blacklisting/ + +filesize +-------- + +Match on the size of the file as it is being transferred. + +Syntax:: + + filesize:; + +Examples:: + + filesize:100; # exactly 100 bytes + filesize:100<>200; # greater than 100 and smaller than 200 + filesize:>100; # greater than 100 + filesize:<100; # smaller than 100 + +**Note**: For files that are not completely tracked because of packet +loss or stream.depth being reached on the "greater than" is +checked. This is because Suricata can know a file is bigger than a +value (it has seen some of it already), but it can't know if the final +size would have been within a range, an exact value or smaller than a +value. diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 1303fcfa4d68..1b035908a71b 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -11,3 +11,4 @@ Rules http-keywords flow-keywords flowint + file-keywords From 62e0f6a3e3864cc0ec89dbbc37e2fc83f71e22fd Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 09:07:37 -0600 Subject: [PATCH 1769/2553] doc: thresholding --- doc/sphinx/rules.rst | 1 + doc/sphinx/thresholding.rst | 118 ++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 doc/sphinx/thresholding.rst diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 1b035908a71b..0e95d52f0934 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -12,3 +12,4 @@ Rules flow-keywords flowint file-keywords + thresholding diff --git a/doc/sphinx/thresholding.rst b/doc/sphinx/thresholding.rst new file mode 100644 index 000000000000..a92d3fb57dca --- /dev/null +++ b/doc/sphinx/thresholding.rst @@ -0,0 +1,118 @@ +Rule Thresholding +================= + +Thresholding can be configured per rule and also globally, see +[[Global-Thresholds]]. + +*Note: mixing rule and global thresholds is not supported in 1.3 and +before. See bug #425.* For the state of the support in 1.4 see +[[Global-Thresholds#Global-thresholds-vs-rule-thresholds]]. + +threshold +--------- + +The threshold keyword can be used to control the rule's alert +frequency. It has 3 modes: threshold, limit and both. + +Syntax:: + + threshold: type , track , count , seconds + +type "threshold" +~~~~~~~~~~~~~~~~ + +This type can be used to set a minimum threshold for a rule before it +generates alerts. A threshold setting of N means on the Nth time the +rule matches an alert is generated. + +Example:: + + alert tcp !$HOME_NET any -> $HOME_NET 25 (msg:"ET POLICY Inbound Frequent Emails - Possible Spambot Inbound"; \ + flow:established; content:"mail from|3a|"; nocase; \ + threshold: type threshold, track by_src, count 10, seconds 60; \ + reference:url,doc.emergingthreats.net/2002087; classtype:misc-activity; sid:2002087; rev:10;) + +This signature only generates an alert if we get 10 inbound emails or +more from the same server in a time period of one minute. + +If a signature sets a flowbit, flowint, etc. those actions are still +performed for each of the matches. + + *Rule actions drop (IPS mode) and reject are applied to each packet + (not only the one that meets the threshold condition).* + +type "limit" +~~~~~~~~~~~~ + +This type can be used to make sure you're not getting flooded with +alerts. If set to limit N, it alerts at most N times. + +Example:: + + alert http $HOME_NET any -> any $HTTP_PORTS (msg:"ET USER_AGENTS Internet Explorer 6 in use - Significant Security Risk"; \ + flow:to_server,established; content:"|0d 0a|User-Agent|3a| Mozilla/4.0 (compatible|3b| MSIE 6.0|3b|"; \ + threshold: type limit, track by_src, seconds 180, count 1; \ + reference:url,doc.emergingthreats.net/2010706; classtype:policy-violation; sid:2010706; rev:7;) + +In this example at most 1 alert is generated per host within a period +of 3 minutes if MSIE 6.0 is detected. + +If a signature sets a flowbit, flowint, etc. those actions are still +performed for each of the matches. + + *Rule actions drop (IPS mode) and reject are applied to each packet + (not only the one that meets the limit condition).* + +type "both" +~~~~~~~~~~~ + +This type is a combination of the "threshold" and "limit" types. It +applies both thresholding and limiting. + +Example:: + + alert tcp $HOME_NET 5060 -> $EXTERNAL_NET any (msg:"ET VOIP Multiple Unauthorized SIP Responses TCP"; \ + flow:established,from_server; content:"SIP/2.0 401 Unauthorized"; depth:24; \ + threshold: type both, track by_src, count 5, seconds 360; \ + reference:url,doc.emergingthreats.net/2003194; classtype:attempted-dos; sid:2003194; rev:6;) + +This alert will only generate an alert if within 6 minutes there have +been 5 or more "SIP/2.0 401 Unauthorized" responses, and it will alert +only once in that 6 minutes. + +If a signature sets a flowbit, flowint, etc. those actions are still +performed for each of the matches. + + *Rule actions drop (IPS mode) and reject are applied to each packet.* + +detection_filter +---------------- + +The detection_filter keyword can be used to alert on every match after +a threshold has been reached. It differs from the threshold with type +threshold in that it generates an alert for each rule match after the +initial threshold has been reached, where the latter will reset it's +internal counter and alert again when the threshold has been reached +again. + +Syntax:: + + detection_filter: track , count , seconds + +Example:: + + alert http $EXTERNAL_NET any -> $HOME_NET any \ + (msg:"ET WEB_SERVER WebResource.axd access without t (time) parameter - possible ASP padding-oracle exploit"; \ + flow:established,to_server; content:"GET"; http_method; content:"WebResource.axd"; http_uri; nocase; \ + content:!"&t="; http_uri; nocase; content:!"&|3b|t="; http_uri; nocase; \ + detection_filter:track by_src,count 15,seconds 2; \ + reference:url,netifera.com/research/; reference:url,www.microsoft.com/technet/security/advisory/2416728.mspx; \ + classtype:web-application-attack; sid:2011807; rev:5;) + +Alerts each time after 15 or more matches have occurred within 2 seconds. + +If a signature sets a flowbit, flowint, etc. those actions are still +performed for each of the matches. + + *Rule actions drop (IPS mode) and reject are applied to each packet + that generate an alert* From 1e6df87ecb92d068ae72d28950ac0f2191f159cc Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 09:11:52 -0600 Subject: [PATCH 1770/2553] doc: rule lua scripting --- doc/sphinx/rule-lua-scripting.rst | 90 +++++++++++++++++++++++++++++++ doc/sphinx/rules.rst | 1 + 2 files changed, 91 insertions(+) create mode 100644 doc/sphinx/rule-lua-scripting.rst diff --git a/doc/sphinx/rule-lua-scripting.rst b/doc/sphinx/rule-lua-scripting.rst new file mode 100644 index 000000000000..9e0f6feff87e --- /dev/null +++ b/doc/sphinx/rule-lua-scripting.rst @@ -0,0 +1,90 @@ +Lua scripting +============= + +In order to enable Lua scripting, please reference this page before +continuing [[Installation from GIT with luajit]]. + +Syntax: + +:: + + luajit:[!]; + +The script filename will be appended to your default rules location. + +The script has 2 parts, an init function and a match function. First, the init. + +Init function +------------- + + +.. code-block:: lua + + function init (args) + local needs = {} + needs["http.request_line"] = tostring(true) + return needs + end + +The init function registers the buffer(s) that need +inspection. Currently the following are available: + +* packet -- entire packet, including headers +* payload -- packet payload (not stream) +* http.uri +* http.uri.raw +* http.request_line +* http.request_headers +* http.request_headers.raw +* http.request_cookie +* http.request_user_agent +* http.request_body +* http.response_headers +* http.response_headers.raw +* http.response_body +* http.response_cookie + +All the HTTP buffers have a limitation: only one can be inspected by a +script at a time. + +Match function +-------------- + +.. code-block:: lua + + function match(args) + a = tostring(args["http.request_line"]) + if #a > 0 then + if a:find("^POST%s+/.*%.php%s+HTTP/1.0$") then + return 1 + end + end + + return 0 + end + +The script can return 1 or 0. It should return 1 if the condition(s) +it checks for match, 0 if not. + +Entire script: + +.. code-block:: lua + + function init (args) + local needs = {} + needs["http.request_line"] = tostring(true) + return needs + end + + function match(args) + a = tostring(args["http.request_line"]) + if #a > 0 then + if a:find("^POST%s+/.*%.php%s+HTTP/1.0$") then + return 1 + end + end + + return 0 + end + + return 0 diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 0e95d52f0934..67dcabd6c16f 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -13,3 +13,4 @@ Rules flowint file-keywords thresholding + rule-lua-scripting From 3366571eebc70183325f173c324ad24872c0b173 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 09:22:52 -0600 Subject: [PATCH 1771/2553] doc: rule lua scripting --- doc/sphinx/rule-lua-scripting.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx/rule-lua-scripting.rst b/doc/sphinx/rule-lua-scripting.rst index 9e0f6feff87e..9eff413a3c07 100644 --- a/doc/sphinx/rule-lua-scripting.rst +++ b/doc/sphinx/rule-lua-scripting.rst @@ -1,4 +1,4 @@ -Lua scripting +Lua Scripting ============= In order to enable Lua scripting, please reference this page before From 107c12afd6ed180e529f8be5c164559d4f5fcf2d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 09:38:16 -0600 Subject: [PATCH 1772/2553] doc: adding your own rules --- doc/sphinx/adding-your-own-rules.rst | 60 ++++++++++++++++++++++++++++ doc/sphinx/rules.rst | 1 + 2 files changed, 61 insertions(+) create mode 100644 doc/sphinx/adding-your-own-rules.rst diff --git a/doc/sphinx/adding-your-own-rules.rst b/doc/sphinx/adding-your-own-rules.rst new file mode 100644 index 000000000000..303566fadc31 --- /dev/null +++ b/doc/sphinx/adding-your-own-rules.rst @@ -0,0 +1,60 @@ +Adding Your Own Rules +===================== + +If you would like to create a rule yourself and use it with Suricata, +this guide might be helpful. + +Start creating a file for your rule. Type for example the following in +your console: + +:: + + sudo nano local.rules + +Write your rule, see [[Suricata Rules]] and save it. + +Open yaml + +:: + + sudo nano /etc/suricata/suricata.yaml + +and make sure your local.rules file is added to the list of rules. + +Now, run Suricata and see if your rule is being loaded. + +:: + + suricata -c /etc/suricata/suricata.yaml -i wlan0 + +If your rule failed to load, check if you have made a mistake anywhere +in the rule. Mind the details; look for mistakes in special +characters, spaces, capital characters etc. + +Next, check if your log-files are enabled in suricata.yaml. + +If you had to correct your rule and/or modify yaml, you have to +restart Suricata. + +If you see your rule is successfully loaded, you can double check your +rule by doing something that should trigger it. + +Enter: + +:: + + tail -f /var/log/suricata/fast.log + +If you would make a rule like this: + +:: + + alert http any any -> any any (msg:"Do not read gossip during work"; + content:"Scarlett"; nocase; classtype:policy-violation; sid:1; rev:1;) + +Your alert should look like this: + +:: + + 09/15/2011-16:50:27.725288 [**] [1:1:1] Do not read gossip during work [**] + [Classification: Potential Corporate Privacy Violation] [Priority: 1] {TCP} 192.168.0.32:55604 -> 68.67.185.210:80 diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 67dcabd6c16f..e0083392fcbc 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -14,3 +14,4 @@ Rules file-keywords thresholding rule-lua-scripting + adding-your-own-rules From 58691fbb48774aff719a781228948347d1f68457 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 09:40:47 -0600 Subject: [PATCH 1773/2553] doc: live rule swap --- doc/sphinx/live-rule-swap.rst | 64 +++++++++++++++++++++++++++++++++++ doc/sphinx/rules.rst | 1 + 2 files changed, 65 insertions(+) create mode 100644 doc/sphinx/live-rule-swap.rst diff --git a/doc/sphinx/live-rule-swap.rst b/doc/sphinx/live-rule-swap.rst new file mode 100644 index 000000000000..fdc79b00bb0d --- /dev/null +++ b/doc/sphinx/live-rule-swap.rst @@ -0,0 +1,64 @@ +Live Rule Reloads +================= + +As of revision - Suricata version 1.3dev (rev 7109a05), Suricata +supports live rule swap. In other words if you decide to +change/update/remove/add rules you can do it on the fly without +stopping Suricata. This is how you can do it. + +The live rule reload is available by default without any additional +config changes needed. Lets say you have started Suricata the regular +way with about 11000 rules: + +:: + + root@LTS-64-1:~ # suricata -c /etc/suricata/suricata.yaml -v --af-packet + .... + [9907] 13/7/2015 -- 14:53:03 - (detect.c:520) (SigLoadSignatures) -- 50 rule files processed. 16659 rules successfully loaded, 0 rules failed + [9907] 13/7/2015 -- 14:53:04 - (detect.c:2912) (SigAddressPrepareStage1) -- 16667 signatures processed. 989 are IP-only rules, 6019 are inspecting packet payload, 12447 inspect application layer, 72 are decoder event only + [9907] 13/7/2015 -- 14:53:04 - (detect.c:2915) (SigAddressPrepareStage1) -- building signature grouping structure, stage 1: preprocessing rules... complete + [9907] 13/7/2015 -- 14:53:04 - (detect.c:3548) (SigAddressPrepareStage2) -- building signature grouping structure, stage 2: building source address list... complete + [9907] 13/7/2015 -- 14:53:05 - (detect.c:4194) (SigAddressPrepareStage3) -- building signature grouping structure, stage 3: building destination address lists... complete + [9907] 13/7/2015 -- 14:53:06 - (util-threshold-config.c:1176) (SCThresholdConfParseFile) -- Threshold config parsed: 0 rule(s) found + [9907] 13/7/2015 -- 14:53:06 - (util-coredump-config.c:122) (CoredumpLoadConfig) -- Core dump size set to unlimited. + [9907] 13/7/2015 -- 14:53:06 - (util-logopenfile.c:227) (SCConfLogOpenGeneric) -- fast output device (regular) initialized: fast.log + [9907] 13/7/2015 -- 14:53:06 - (util-logopenfile.c:227) (SCConfLogOpenGeneric) -- eve-log output device (regular) initialized: eve.json + [9907] 13/7/2015 -- 14:53:06 - (runmodes.c:774) (RunModeInitializeOutputs) -- enabling 'eve-log' module 'alert' + [9907] 13/7/2015 -- 14:53:06 - (runmodes.c:774) (RunModeInitializeOutputs) -- enabling 'eve-log' module 'http' + [9907] 13/7/2015 -- 14:53:06 - (runmodes.c:774) (RunModeInitializeOutputs) -- enabling 'eve-log' module 'dns' + [9907] 13/7/2015 -- 14:53:06 - (runmodes.c:774) (RunModeInitializeOutputs) -- enabling 'eve-log' module 'tls' + [9907] 13/7/2015 -- 14:53:06 - (runmodes.c:774) (RunModeInitializeOutputs) -- enabling 'eve-log' module 'files' + .... + ... + +But there is a new ruleset update and you have made some changes to +some rules and/or added new ones and you would like to do a live swap. + +Find what is the PID of Suricata: + +:: + + root@LTS-64-1:~ # ps aux |grep suricata + root 9907 56.9 15.9 840624 410544 pts/0 Sl+ 14:52 0:06 suricata -c /etc/suricata/suricata.yaml -v --af-packet + root@LTS-64-1:~ # + +Send the signal: + +:: + + root@LTS-64-1:~ # kill -USR2 9907 + +Suricata will now reload the rules: + +:: + + [9907] 13/7/2015 -- 14:57:11 - (detect.c:520) (SigLoadSignatures) -- 50 rule files processed. 16659 rules successfully loaded, 0 rules failed + [9907] 13/7/2015 -- 14:57:11 - (detect.c:2912) (SigAddressPrepareStage1) -- 16667 signatures processed. 989 are IP-only rules, 6019 are inspecting packet payload, 12447 inspect application layer, 72 are decoder event only + [9907] 13/7/2015 -- 14:57:11 - (detect.c:2915) (SigAddressPrepareStage1) -- building signature grouping structure, stage 1: preprocessing rules... complete + [9907] 13/7/2015 -- 14:57:12 - (detect.c:3548) (SigAddressPrepareStage2) -- building signature grouping structure, stage 2: building source address list... complete + [9907] 13/7/2015 -- 14:57:13 - (detect.c:4194) (SigAddressPrepareStage3) -- building signature grouping structure, stage 3: building destination address lists... complete + [9907] 13/7/2015 -- 14:57:14 - (util-threshold-config.c:1176) (SCThresholdConfParseFile) -- Threshold config parsed: 0 rule(s) found + [9907] 13/7/2015 -- 14:57:14 - (detect-engine.c:543) (DetectEngineReloadThreads) -- rule reload starting + [9907] 13/7/2015 -- 14:57:14 - (detect-engine.c:622) (DetectEngineReloadThreads) -- Live rule swap has swapped 2 old det_ctx's with new ones, along with the new de_ctx + [9907] 13/7/2015 -- 14:58:31 - (detect-engine.c:694) (DetectEngineReloadThreads) -- rule reload complete + [9907] 13/7/2015 -- 14:58:31 - (detect.c:4226) (SigAddressCleanupStage1) -- cleaning up signature grouping structure... complete diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index e0083392fcbc..42b7a7fe388f 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -15,3 +15,4 @@ Rules thresholding rule-lua-scripting adding-your-own-rules + live-rule-swap From 75662a16da053cbcf89774812728c33eb3eeaac8 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 09:52:02 -0600 Subject: [PATCH 1774/2553] doc: tls keywords --- doc/sphinx/convert.py | 6 +++- doc/sphinx/rules.rst | 1 + doc/sphinx/tls-keywords.rst | 70 +++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 doc/sphinx/tls-keywords.rst diff --git a/doc/sphinx/convert.py b/doc/sphinx/convert.py index b750ec6f2170..680d5f4e36ef 100755 --- a/doc/sphinx/convert.py +++ b/doc/sphinx/convert.py @@ -50,7 +50,11 @@ def main(): if line.startswith("
"):
                 inpre = True
-                line = "\n::\n\n"
+                line = line.replace("
", "\n::\n\n  ")
+                if line.find("
") > -1: + print("Removing
from end of line.") + line = line.replace("", "") + inpre = False if line.startswith(""): inpre = False diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 42b7a7fe388f..88c3773741b1 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -16,3 +16,4 @@ Rules rule-lua-scripting adding-your-own-rules live-rule-swap + tls-keywords diff --git a/doc/sphinx/tls-keywords.rst b/doc/sphinx/tls-keywords.rst new file mode 100644 index 000000000000..57a5a805847e --- /dev/null +++ b/doc/sphinx/tls-keywords.rst @@ -0,0 +1,70 @@ +TLS-keywords +============ + +Suricata comes with several rule keywords to match on various properties of TLS/SSL handshake. Matches are string inclusion matches. + +tls.version +----------- + +Match on negotiated TLS/SSL version. + +Example values: "1.0", "1.1", "1.2" + +Support added in Suricata version 1.3. + +tls.subject +----------- + +Match TLS/SSL certificate Subject field. + +example: + + +:: + + tls.subject:"CN=*.googleusercontent.com" + +Support added in Suricata version 1.3. + +Case sensitve, can't use 'nocase'. + +tls.issuerdn +------------ + +match TLS/SSL certificate IssuerDN field + +example: + + +:: + + tls.issuerdn:!"CN=Google-Internet-Authority" + +Support added in Suricata version 1.3. + +Case sensitve, can't use 'nocase'. + +tls.fingerprint +--------------- + +match TLS/SSL certificate SHA1 fingerprint + +example: + + +:: + + tls.fingerprint:!"f3:40:21:48:70:2c:31:bc:b5:aa:22:ad:63:d6:bc:2e:b3:46:e2:5a" + +Support added in Suricata version 1.4. + +Case sensitive, can't use 'nocase'. + +The tls.fingerprint buffer is lower case so you must use lower case letters for this to match. + +tls.store +--------- + +store TLS/SSL certificate on disk + +Support added in Suricata version 1.4. From 30f3ecf22309df76efaecbb07aad31563ba151e0 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 09:53:19 -0600 Subject: [PATCH 1775/2553] doc: normalized buffers --- doc/sphinx/normalized-buffers.rst | 15 +++++++++++++++ .../normalized-buffers/normalization1.png | Bin 0 -> 24182 bytes doc/sphinx/rules.rst | 1 + 3 files changed, 16 insertions(+) create mode 100644 doc/sphinx/normalized-buffers.rst create mode 100644 doc/sphinx/normalized-buffers/normalization1.png diff --git a/doc/sphinx/normalized-buffers.rst b/doc/sphinx/normalized-buffers.rst new file mode 100644 index 000000000000..111bb9716377 --- /dev/null +++ b/doc/sphinx/normalized-buffers.rst @@ -0,0 +1,15 @@ +Normalized Buffers +================== + + +A packet consists of raw data. HTTP and reassembly make a copy of +those kinds of packets data. They erase anomalous content, combine +packets etcetera. What remains is a called the 'normalized buffer'. + +Example: + +.. image:: normalized-buffers/normalization1.png + +Because the data is being normalized, it is not what it used to be; it +is an interpretation. Normalized buffers are: all HTTP-keywords, +reassembled streams, TLS-, SSL-, SSH-, FTP- and dcerpc-buffers. diff --git a/doc/sphinx/normalized-buffers/normalization1.png b/doc/sphinx/normalized-buffers/normalization1.png new file mode 100644 index 0000000000000000000000000000000000000000..a99820cc144d0096d32d13ecc64266bbbdcd99a2 GIT binary patch literal 24182 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 Imu7+g13_wz>;M1& literal 0 HcmV?d00001 diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 88c3773741b1..5a8ec3036c79 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -17,3 +17,4 @@ Rules adding-your-own-rules live-rule-swap tls-keywords + normalized-buffers From 082758deae945b296e7dc1faeb718bdeb703de10 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 09:55:09 -0600 Subject: [PATCH 1776/2553] doc: rule profiling --- doc/sphinx/rule-profiling.rst | 33 +++++++++++++++++++++++++++++++++ doc/sphinx/rules.rst | 1 + 2 files changed, 34 insertions(+) create mode 100644 doc/sphinx/rule-profiling.rst diff --git a/doc/sphinx/rule-profiling.rst b/doc/sphinx/rule-profiling.rst new file mode 100644 index 000000000000..099cdb8d612a --- /dev/null +++ b/doc/sphinx/rule-profiling.rst @@ -0,0 +1,33 @@ +Rule Profiling +============== + +:: + + -------------------------------------------------------------------------- + Date: 9/5/2013 -- 14:59:58 + -------------------------------------------------------------------------- + Num Rule Gid Rev Ticks % Checks Matches Max Ticks Avg Ticks Avg Match Avg No Match + -------- ------------ -------- -------- ------------ ------ -------- -------- ----------- ----------- ----------- -------------- + 1 2210021 1 3 12037 4.96 1 1 12037 12037.00 12037.00 0.00 + 2 2210054 1 1 107479 44.26 12 0 35805 8956.58 0.00 8956.58 + 3 2210053 1 1 4513 1.86 1 0 4513 4513.00 0.00 4513.00 + 4 2210023 1 1 3077 1.27 1 0 3077 3077.00 0.00 3077.00 + 5 2210008 1 1 3028 1.25 1 0 3028 3028.00 0.00 3028.00 + 6 2210009 1 1 2945 1.21 1 0 2945 2945.00 0.00 2945.00 + 7 2210055 1 1 2945 1.21 1 0 2945 2945.00 0.00 2945.00 + 8 2210007 1 1 2871 1.18 1 0 2871 2871.00 0.00 2871.00 + 9 2210005 1 1 2871 1.18 1 0 2871 2871.00 0.00 2871.00 + 10 2210024 1 1 2846 1.17 1 0 2846 2846.00 0.00 2846.00 + +The meaning of the individual fields: + +* Ticks -- total ticks spent on this rule, so a sum of all inspections +* % -- share of this single sig in the total cost of inspection +* Checks -- number of times a signature was inspected +* Matches -- number of times it matched. This may not have resulted in an alert due to suppression and thresholding. +* Max ticks -- single most expensive inspection +* Avg ticks -- per inspection average, so "ticks" / "checks". +* Avg match -- avg ticks spent resulting in match +* Avg No Match -- avg ticks spent resulting in no match. + +The "ticks" are CPU clock ticks: http://en.wikipedia.org/wiki/CPU_time diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 5a8ec3036c79..4d5fd074a404 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -18,3 +18,4 @@ Rules live-rule-swap tls-keywords normalized-buffers + rule-profiling From 9dea001c7da76813d9090288437ebbd520dcda8e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 09:58:11 -0600 Subject: [PATCH 1777/2553] doc: modbus keyword --- doc/sphinx/modbus-keyword.rst | 87 +++++++++++++++++++++++++++++++++++ doc/sphinx/rules.rst | 1 + 2 files changed, 88 insertions(+) create mode 100644 doc/sphinx/modbus-keyword.rst diff --git a/doc/sphinx/modbus-keyword.rst b/doc/sphinx/modbus-keyword.rst new file mode 100644 index 000000000000..3aa3bcb91f6d --- /dev/null +++ b/doc/sphinx/modbus-keyword.rst @@ -0,0 +1,87 @@ +Modbus Keyword +============== + +The modbus keyword can be used for matching on various properties of +Modbus requests. + +There are two ways of using this keyword: + +* matching on functions properties with the setting "function"; +* matching on directly on data access with the setting "access". + +With the setting **function**, you can match on: + +* an action based on a function code field and a sub-function code when applicable; +* one of three categories of Modbus functions; +* public functions that are publicly defined (setting "public") +* user-defined functions (setting "user") +* reserved functions that are dedicated to proprietary extensions of Modbus (keyword "reserved") +* one of the two sub-groups of public functions: + + * assigned functions whose definition is already given in the Modbus specification (keyword "assigned"); + * unassigned functions, which are reserved for future use (keyword "unassigned"). + +Syntax:: + + modbus: function + modbus: function , subfunction + modbus: function [!] + +Sign '!' is negation + +Examples:: + + modbus: function 21 # Write File record function + modbus: function 4, subfunction 4 # Force Listen Only Mode (Diagnostics) function + modbus: function assigned # defined by Modbus Application Protocol Specification V1.1b3 + modbus: function public # validated by the Modbus.org community + modbus: function user # internal use and not supported by the specification + modbus: function reserved # used by some companies for legacy products and not available for public use + modbus: function !reserved # every function but reserved function + +With the **access** setting, you can match on: + +* a type of data access (read or write); +* one of primary tables access (Discretes Input, Coils, Input Registers and Holding Registers); +* a range of addresses access; +* a written value. + +Syntax:: + + modbus: access + modbus: access + modbus: access , address + modbus: access , address , value + +With __ setting matches on the address or value as it is being +accessed or written as follows:: + + address 100 # exactly address 100 + address 100<>200 # greater than address 100 and smaller than address 200 + address >100 # greater than address 100 + address <100 # smaller than address 100 + +Examples:: + + modbus: access read # Read access + modbus: access write # Write access + modbus: access read input # Read access to Discretes Input table + modbus: access write coils # Write access to Coils table + modbus: access read discretes, address <100 # Read access at address smaller than 100 of Discretes Input table + modbus: access write holding, address 500, value >200 # Write value greather than 200 at address 500 of Holding Registers table + +(cf. http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf) + +**Note:** Address of read and write are starting at 1. So if your system +is using a start at 0, you need to add 1 the address values. + +**Note:** According to MODBUS Messaging on TCP/IP Implementation Guide +V1.0b, it is recommended to keep the TCP connection opened with a +remote device and not to open and close it for each MODBUS/TCP +transaction. In that case, it is important to set the depth of the +stream reassembling as unlimited (stream.reassembly.depth: 0) + +(cf. http://www.modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf) + +Paper and presentation (in french) on Modbus support are available : +http://www.ssi.gouv.fr/fr/anssi/publications/publications-scientifiques/articles-de-conferences/detection-d-intrusion-dans-les-systemes-industriels-suricata-et-le-cas-modbus.html diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 4d5fd074a404..2bff9ed05f56 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -19,3 +19,4 @@ Rules tls-keywords normalized-buffers rule-profiling + modbus-keyword From 98f56f991673196340ffbd66dce9f5e7a5c6868b Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 10:01:32 -0600 Subject: [PATCH 1778/2553] doc: dnp3 keywords --- doc/sphinx/dnp3-keywords.rst | 149 +++++++++++++++++++++++++++++++++++ doc/sphinx/rules.rst | 1 + 2 files changed, 150 insertions(+) create mode 100644 doc/sphinx/dnp3-keywords.rst diff --git a/doc/sphinx/dnp3-keywords.rst b/doc/sphinx/dnp3-keywords.rst new file mode 100644 index 000000000000..3e2748fd5d7d --- /dev/null +++ b/doc/sphinx/dnp3-keywords.rst @@ -0,0 +1,149 @@ +DNP3 keyword (Currently in development, not available yet) +========================================================== + +The DNP3 keywords can be used to match on fields in decoded DNP3 +messages. The keywords are based on Snort's DNP3 keywords and aim to +be 100% compatible. + +dnp3_func +--------- + +This keyword will match on the application function code found in DNP3 +request and responses. It can be specified as the integer value or +the symbolic name of the function code. + +Syntax +~~~~~~ + +:: + + dnp3_func:; + +Where value is one of: + +* An integer value between 0 and 255 inclusive. +* Function code name: + + * confirm + * read + * write + * select + * operate + * direct_operate + * direct_operate_nr + * immed_freeze + * immed_freeze_nr + * freeze_clear + * freeze_clear_nr + * freeze_at_time + * freeze_at_time_nr + * cold_restart + * warm_restart + * initialize_data + * initialize_appl + * start_appl + * stop_appl + * save_config + * enable_unsolicited + * disable_unsolicited + * assign_class + * delay_measure + * record_current_time + * open_file + * close_file + * delete_file + * get_file_info + * authenticate_file + * abort_file + * activate_config + * authenticate_req + * authenticate_err + * response + * unsolicited_response + * authenticate_resp + +dnp3_ind +-------- + +This keyword matches on the DNP3 internal indicator flags in the +response application header. + +Syntax +~~~~~~ + +:: + + dnp3_ind:{,...} + + +Where flag is the name of the internal indicator: + +* all_stations +* class_1_events +* class_2_events +* class_3_events +* need_time +* local_control +* device_trouble +* device_restart +* no_func_code_support +* object_unknown +* parameter_error +* event_buffer_overflow +* already_executing +* config_corrupt +* reserved_2 +* reserved_1 + +This keyword will match of any of the flags listed are set. To match +on multiple flags (AND type match), use dnp3_ind for each flag that +must be set. + +Examples +~~~~~~~~ + +:: + + dnp3_ind:all_stations; + +:: + + dnp3_ind:class_1_events,class_2_events; + +dnp3_obj +-------- + +This keyword matches on the DNP3 application data objects. + +Syntax +~~~~~~ + +:: + + + dnp3_obj:, + +Where and are integer values between 0 and 255 inclusive. + +dnp3_data +--------- + +This keyword will cause the following content options to match on the +re-assembled application buffer. The reassembled application buffer is +a DNP3 fragment with CRCs removed (which occur every 16 bytes), and +will be the complete fragment, possibly reassembled from multiple DNP3 +link layer frames. + +Syntax +~~~~~~ + +:: + + dnp3_data; + +Example +~~~~~~~ + +:: + + dnp3_data; content:|c3 06|; diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 2bff9ed05f56..c3e706696b63 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -20,3 +20,4 @@ Rules normalized-buffers rule-profiling modbus-keyword + dnp3-keywords From b1bc0038aeecce4184e6c1ad7e51dfee43d1698d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 10:26:53 -0600 Subject: [PATCH 1779/2553] doc: finish off the rules section --- doc/sphinx/README.md | 20 +++ doc/sphinx/adding-your-own-rules.rst | 2 +- doc/sphinx/conf.py | 6 +- doc/sphinx/dnp3-keywords.rst | 6 +- doc/sphinx/dns-keywords.rst | 25 ++++ doc/sphinx/dns-keywords/dns_query.png | Bin 0 -> 7022 bytes doc/sphinx/file-keywords.rst | 6 +- doc/sphinx/flow-keywords.rst | 73 ++++++---- doc/sphinx/http-keywords.rst | 19 ++- doc/sphinx/index.rst | 15 +- doc/sphinx/meta.rst | 111 ++++++++------- doc/sphinx/meta/classification.png | Bin 0 -> 41206 bytes doc/sphinx/meta/classtype.png | Bin 0 -> 42404 bytes doc/sphinx/meta/gid.png | Bin 0 -> 30298 bytes doc/sphinx/meta/msg.png | Bin 0 -> 38884 bytes doc/sphinx/meta/reference.png | Bin 0 -> 37896 bytes doc/sphinx/meta/rev.png | Bin 0 -> 39811 bytes doc/sphinx/meta/sid.png | Bin 0 -> 41173 bytes doc/sphinx/payload-keywords.rst | 5 +- doc/sphinx/pcre.rst | 4 +- doc/sphinx/rule-lua-scripting.rst | 2 +- doc/sphinx/rules.rst | 189 +++++++++++++++++++++++++- doc/sphinx/rules/Dest_port.png | Bin 0 -> 41492 bytes doc/sphinx/rules/Direction.png | Bin 0 -> 41001 bytes doc/sphinx/rules/Source-port.png | Bin 0 -> 40112 bytes doc/sphinx/rules/Source.png | Bin 0 -> 40040 bytes doc/sphinx/rules/TCP-session.png | Bin 0 -> 37144 bytes doc/sphinx/rules/action.png | Bin 0 -> 40842 bytes doc/sphinx/rules/destination.png | Bin 0 -> 42050 bytes doc/sphinx/rules/intro_sig.png | Bin 0 -> 43552 bytes doc/sphinx/rules/protocol.png | Bin 0 -> 38983 bytes doc/sphinx/thresholding.rst | 6 +- doc/sphinx/tls-keywords.rst | 2 +- doc/sphinx/what-is-suricata.rst | 2 +- 34 files changed, 374 insertions(+), 119 deletions(-) create mode 100644 doc/sphinx/README.md create mode 100644 doc/sphinx/dns-keywords.rst create mode 100644 doc/sphinx/dns-keywords/dns_query.png create mode 100644 doc/sphinx/meta/classification.png create mode 100644 doc/sphinx/meta/classtype.png create mode 100644 doc/sphinx/meta/gid.png create mode 100644 doc/sphinx/meta/msg.png create mode 100644 doc/sphinx/meta/reference.png create mode 100644 doc/sphinx/meta/rev.png create mode 100644 doc/sphinx/meta/sid.png create mode 100644 doc/sphinx/rules/Dest_port.png create mode 100644 doc/sphinx/rules/Direction.png create mode 100644 doc/sphinx/rules/Source-port.png create mode 100644 doc/sphinx/rules/Source.png create mode 100644 doc/sphinx/rules/TCP-session.png create mode 100644 doc/sphinx/rules/action.png create mode 100644 doc/sphinx/rules/destination.png create mode 100644 doc/sphinx/rules/intro_sig.png create mode 100644 doc/sphinx/rules/protocol.png diff --git a/doc/sphinx/README.md b/doc/sphinx/README.md new file mode 100644 index 000000000000..fe06acda5e22 --- /dev/null +++ b/doc/sphinx/README.md @@ -0,0 +1,20 @@ +# Suricata User Guide + +This directory contains the Suricata Guide. The +[Sphinx Document Generate](http://sphinx-doc.org) is used to build the +documentation. For a primer os reStructuredText see the +[reStructuredText Primer](http://sphinx-doc.org/rest.html). + +## Development Server + +To help with writing documentation there is a development web server +with live reload. To get run the live server you will first need npm +installed then run the following: + + npm install + gulp serve + +Then point your browser at http://localhost:8000/_build/html/index.html + +Any edits to .rst files should trigger a "make html" and cause your +browser to refresh. diff --git a/doc/sphinx/adding-your-own-rules.rst b/doc/sphinx/adding-your-own-rules.rst index 303566fadc31..cbf99b6d80fc 100644 --- a/doc/sphinx/adding-your-own-rules.rst +++ b/doc/sphinx/adding-your-own-rules.rst @@ -11,7 +11,7 @@ your console: sudo nano local.rules -Write your rule, see [[Suricata Rules]] and save it. +Write your rule, see :doc:`rules` and save it. Open yaml diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py index a5af0169ea2c..6cd7f0cf4d96 100644 --- a/doc/sphinx/conf.py +++ b/doc/sphinx/conf.py @@ -55,9 +55,9 @@ # built documents. # # The short X.Y version. -version = '2.1dev' +version = '3.0dev' # The full version, including alpha/beta/rc tags. -release = '3.0dev' +release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -201,7 +201,7 @@ #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'Suricatadoc' +htmlhelp_basename = 'suricatadoc' # -- Options for LaTeX output --------------------------------------------- diff --git a/doc/sphinx/dnp3-keywords.rst b/doc/sphinx/dnp3-keywords.rst index 3e2748fd5d7d..7fe34f75de57 100644 --- a/doc/sphinx/dnp3-keywords.rst +++ b/doc/sphinx/dnp3-keywords.rst @@ -1,5 +1,7 @@ -DNP3 keyword (Currently in development, not available yet) -========================================================== +DNP3 Keywords +============= + +**NOTE: DNP3 is currently in development and is not yet available.** The DNP3 keywords can be used to match on fields in decoded DNP3 messages. The keywords are based on Snort's DNP3 keywords and aim to diff --git a/doc/sphinx/dns-keywords.rst b/doc/sphinx/dns-keywords.rst new file mode 100644 index 000000000000..a437553c81df --- /dev/null +++ b/doc/sphinx/dns-keywords.rst @@ -0,0 +1,25 @@ +DNS Keywords +============ + +(from v2.0) + +There are some more content modifiers (If you are unfamiliar with +content modifiers, please visit the page :doc:`payload-keywords` These +ones make sure the signature checks a specific part of the +network-traffic. + + +dns_query +--------- + +With **dns_query** the DNS response body is inspected. The dns_query +keyword works a bit different from the normal content modifiers. When +used in a rule all contents following it are affected by it. Example: + + alert dns any any -> any any (msg:"Test dns_query option"; + dns_query; content:"google"; nocase; sid:1;) + +.. image:: dns-keywords/dns_query.png + +The dns_query keyword affects all following contents, until pkt_data +is used or it reaches the end of the rule. diff --git a/doc/sphinx/dns-keywords/dns_query.png b/doc/sphinx/dns-keywords/dns_query.png new file mode 100644 index 0000000000000000000000000000000000000000..35d16ca23e0dfd1bb6df0086465c31d06fd07d8f GIT binary patch literal 7022 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/file-keywords.rst b/doc/sphinx/file-keywords.rst index f35e3fee0ad4..4f13cceb3cfa 100644 --- a/doc/sphinx/file-keywords.rst +++ b/doc/sphinx/file-keywords.rst @@ -1,8 +1,8 @@ -File-keywords +File Keywords ============= Suricata comes with several rule keywords to match on various file -properties. They depend on properly configured [[File Extraction]]. +properties. They depend on properly configured [[**FIXME** File Extraction]]. filename -------- @@ -73,7 +73,7 @@ the rule and the scope will be per file. filemd5 ------- -Match file [[MD5]] against list of MD5 checksums. +Match file [[**FIXME** MD5]] against list of MD5 checksums. Syntax:: diff --git a/doc/sphinx/flow-keywords.rst b/doc/sphinx/flow-keywords.rst index f314f5978f1c..06658eebcc4c 100644 --- a/doc/sphinx/flow-keywords.rst +++ b/doc/sphinx/flow-keywords.rst @@ -1,17 +1,23 @@ -Flow-keywords +Flow Keywords ============= Flowbits ~~~~~~~~ -Flowbits consists of two parts. The first part describes the action it is going to perform, the second part is the name of the flowbit. +Flowbits consists of two parts. The first part describes the action it +is going to perform, the second part is the name of the flowbit. -There are multiple packets that belong to one flow. Suricata keeps those flows in memory. For more information see [[suricata.yaml#Flow]]. -Flowbits can make sure an alert will be generated when for example two different packets match. An alert will only be generated when both packets match. So, when the second packet matches, Suricata has to know if the first packet was a match too. Flowbits marks the flow if a packet matches so Suricata 'knows' it should generate an alert when the second packet matches as well. +There are multiple packets that belong to one flow. Suricata keeps +those flows in memory. For more information see +[[**FIXME** suricata.yaml#Flow]]. Flowbits can make sure an alert will be +generated when for example two different packets match. An alert will +only be generated when both packets match. So, when the second packet +matches, Suricata has to know if the first packet was a match +too. Flowbits marks the flow if a packet matches so Suricata 'knows' +it should generate an alert when the second packet matches as well. Flowbits have different actions. These are: - :: flowbits: set, name Will set the condition/'name', if present, in the flow. @@ -24,26 +30,37 @@ Flowbits have different actions. These are: when it matches and the condition is not set in the flow. flowbits: noalert Does not generate an alert for this rule. - Example: .. image:: flow-keywords/Flowbit_3.png +When you take a look at the first rule you will notice it would +generate an alert if it would match, if it were not for the 'flowbits: +noalert' at the end of that rule. The purpose of this rule is to check +for a match on 'userlogin' and mark that in the flow. So, there is no +need for generating an alert. The second rule has no effect without +the first rule. If the first rule matches, the flowbits sets that +specific condition to be present in the flow. Now with the second rule +there can be checked whether or not the previous packet fulfills the +first condition. If at that point the second rule matches, an alert +will be generated. - -When you take a look at the first rule you will notice it would generate an alert if it would match, if it were not for the 'flowbits: noalert' at the end of that rule. The purpose of this rule is to check for a match on 'userlogin' and mark that in the flow. So, there is no need for generating an alert. -The second rule has no effect without the first rule. If the first rule matches, the flowbits sets that specific condition to be present in the flow. Now with the second rule there can be checked whether or not the previous packet fulfills the first condition. If at that point the second rule matches, an alert will be generated. - -It is possible to use flowbits several times in a rule and combine the different functions. +It is possible to use flowbits several times in a rule and combine the +different functions. Flow ~~~~ -The flow keyword can be used to match on direction of the flow, so to/from client or to/from server. The to_client is equal to from_server, same goes for from_client and to_server - there's no difference, both names are supported due to historical reasons. It can also match if the flow is established or not. The flow keyword can also be use to say the signature has to match on stream only (only_stream) or on packet only (no_stream). +The flow keyword can be used to match on direction of the flow, so +to/from client or to/from server. The to_client is equal to +from_server, same goes for from_client and to_server - there's no +difference, both names are supported due to historical reasons. It can +also match if the flow is established or not. The flow keyword can +also be use to say the signature has to match on stream only +(only_stream) or on packet only (no_stream). So with the flow keyword you can match on: - :: to_client established only_stream @@ -51,20 +68,24 @@ So with the flow keyword you can match on: to_server from_server -**NOTE:** *from_server* and *to_client* are the same, and so are *to_server* and _from_client_. This comes from the original Snort language and we support it for compatibility reasons. - -These options from the different columns can be combined. You can use up to three options. For example: +**NOTE:** *from_server* and *to_client* are the same, and so are + *to_server* and _from_client_. This comes from the original Snort + language and we support it for compatibility reasons. +These options from the different columns can be combined. You can use +up to three options. For example: :: flow:to_client, established; flow:from_client, established, only_stream; - -There are different ways in which can be checked whether the connection is established or not. With tcp-traffic a connection starts with the three-way-handshake. In the flow is a part in which the state is set. There will be checked in which state the connection is. -In other cases there will be just checked if traffic comes from two sides. - +There are different ways in which can be checked whether the +connection is established or not. With tcp-traffic a connection starts +with the three-way-handshake. In the flow is a part in which the state +is set. There will be checked in which state the connection is. In +other cases there will be just checked if traffic comes from two +sides. Example: @@ -75,15 +96,14 @@ Example: Flowint ~~~~~~~ -For information, read the information on the [[flowint]] page. - +For information, read the information on the :doc:`flowint` page. stream_size ~~~~~~~~~~~ -The stream size option matches on traffic according to the registered amount of bytes by the sequence numbers. -There are several modifiers to this keyword: - +The stream size option matches on traffic according to the registered +amount of bytes by the sequence numbers. There are several modifiers +to this keyword: :: @@ -94,11 +114,10 @@ There are several modifiers to this keyword: >= greater than or equal <= less than or equal - Format :: stream_size:, , ; -Example of the stream-size keyword in a rule: \ No newline at end of file +Example of the stream-size keyword in a rule: diff --git a/doc/sphinx/http-keywords.rst b/doc/sphinx/http-keywords.rst index 63a52d56b587..623a301a8a7f 100644 --- a/doc/sphinx/http-keywords.rst +++ b/doc/sphinx/http-keywords.rst @@ -5,9 +5,9 @@ HTTP Keywords There are additional content modifiers that can provide protocol-specific capabilities at the application layer (if you are -unfamiliar with content modifiers, please visit the page [[Payload -keywords]]). These keywords make sure the signature checks only -specific parts of the network traffic. For instance, to check +unfamiliar with content modifiers, please visit the page +:doc:`payload-keywords` These keywords make sure the signature checks +only specific parts of the network traffic. For instance, to check specifically on the request URI, cookies, or the HTTP request or response body, etc. @@ -108,8 +108,8 @@ mentioned content modifiers like ``depth``, ``distance``, ``offset``, ``nocase`` and ``within``. To learn more about the difference between ``http_uri`` and -``http_raw_uri``, please read the information about [[HTTP-uri -normalization]]. +``http_raw_uri``, please read the information about [[**FIXME** +HTTP-uri normalization]]. Example of the URI in a HTTP request: @@ -236,7 +236,7 @@ Example of the purpose of ``http_client_body``: .. image:: http-keywords/client_body1.png Note: how much of the request/client body is inspected is controlled -in the [[suricata.yaml#Configure-Libhtp]], in the "libhtp" section, +in the [[**FIXME** suricata.yaml#Configure-Libhtp]], in the "libhtp" section, via the ``request-body-limit`` setting. http_stat_code @@ -283,7 +283,7 @@ response body is *gzip* encoded, it is first uncompressed for inspection. Note: how much of the response/server body is inspected is controlled -in your [[suricata.yaml#Configure-Libhtp]], in the "libhtp" section, +in your [[**FIXME** suricata.yaml#Configure-Libhtp]], in the "libhtp" section, via the ``response-body-limit`` setting. file_data @@ -309,7 +309,7 @@ content match individually. If the response body is *gzip* encoded, it is first uncompressed for inspection. Note: how much of the response/server body is inspected is controlled -in your [[suricata.yaml#Configure-Libhtp]], in the "libhtp" section +in your [[**FIXME** suricata.yaml#Configure-Libhtp]], in the "libhtp" section via the ``response-body-limit`` setting. **NOTE:** In 2.0.x, ``file_data`` is only supported for HTTP server @@ -352,8 +352,7 @@ normalized or the raw buffer by appending ``norm`` or ``raw``:: pcre ---- -For information about the ``pcre`` keyword, check the [[pcre (Perl -Compatible Regular Expressions)]] page. +For information about the ``pcre`` keyword, check the :doc:`pcre` page. fast_pattern ------------ diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index af8d429c5ba4..40581d2bce35 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -1,20 +1,9 @@ -.. Suricata documentation master file, created by - sphinx-quickstart on Fri Nov 6 10:12:25 2015. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - Suricata User Guide =================== .. toctree:: - :maxdepth: 2 + :numbered: + :titlesonly: what-is-suricata rules - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/doc/sphinx/meta.rst b/doc/sphinx/meta.rst index 6b5fbf5a71c0..4fb169f467f9 100644 --- a/doc/sphinx/meta.rst +++ b/doc/sphinx/meta.rst @@ -12,20 +12,27 @@ possible alert. The first part shows the filename of the signature. It is a convention that part is written in uppercase characters. -The format of msg is:: +The format of msg is: - msg: “...”; +:: -Example:: + + msg: “..........”; + +Example: + +:: msg:"ATTACK-RESPONSES 403 Forbidden"; msg:"ET EXPLOIT SMB-DS DCERPC PnP bind attempt"; -*It is a convention that msg is always the first keyword of a signature.* +:: + + It is a convention that msg is always the first keyword of a signature. Another example of msg in a signature: - alert tcp $HOME_NET any -> $EXTERNAL_NET any (**msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)";** flow:established,to_server; content:"NICK "; depth:5; content:"USA"; within:10; reference:url,doc.emergingthreats.net/2008124; classtype:trojan-activity; sid:2008124; rev:5;) +.. image:: meta/msg.png In this example the red, bold-faced part is the msg. @@ -35,31 +42,38 @@ Sid (signature id) The keyword sid gives every signature its own id. This id is stated with a number. -The format of sid is:: +The format of sid is: + +:: sid:123; Example of sid in a signature: - alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)"; flow:established,to_server; content:"NICK "; depth:5; content:"USA"; within:10; reference:url,doc.emergingthreats.net/2008124; classtype:trojan-activity; **sid:2008124;** rev:5;) +.. image:: meta/sid.png + +In this example the red, bold-faced part is the sid. Rev (Revision) -------------- The sid keyword is almost every time accompanied by rev. Rev represents the version of the signature. If a signature is modified, -the number of rev will be incremented by the signature writers. +the number of rev will be incremented by the signature writers. The +format of rev is: -The format of rev is:: +:: - rev:123; + rev:123; -*It is a convention that sid comes before rev, and both are the last of -all keywords.* +*It is a convention that sid comes before rev, and both are the last +of all keywords.* Example of rev in a signature: - alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)"; flow:established,to_server; content:"NICK "; depth:5; content:"USA"; within:10; reference:url,doc.emergingthreats.net/2008124; classtype:trojan-activity; sid:2008124; **rev:5;**) +.. image:: meta/rev.png + +In this example the red, bold-faced part is the rev. Gid (group id) -------------- @@ -70,10 +84,12 @@ possible to modify this. It is not usual that it will be changed, and changing it has no technical implications. You can only notice it in the alert. - 10/01/2014-05:14:43.926704 [**] [**1**:2016903:5] ET USER_AGENTS Suspicious User-Agent (DownloadMR) [**] [Classification: A Network Trojan was detected] [Priority: 1] {TCP} 192.168.81.10:1032 -> 95.211.39.161:80 +Example of gid in a signature: + +.. image:: meta/gid.png -This is an example from the fast.log. In the part [1:2008124:2], 1 is -the gid (2008124 is the the sid and 2 the rev). +This is an example from the fast.log. +In the part [1:2008124:2], 1 is the gid (2008124 is the the sid and 2 the rev). Classtype --------- @@ -92,21 +108,16 @@ Example classtype:: config classification: web-application-attack,Web Application Attack,1 config classification: not-suspicious,Not Suspicious Traffic,3 -============== =================================== ====================== -Signature classification.config Alert -============== =================================== ====================== -web-attack web-attack, Web Application Attack, Web Application Attack - priority:1 -not-suspicious not-suspicious, Not Suspiscious Not Suspicious Traffic - Traffic, priority:3 -============== =================================== ====================== +.. image:: meta/classification.png -In the above table you see how classtype appears in signatures, the +In this example you see how classtype appears in signatures, the classification.config and the alert. Another example of classtype in a signature: - alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)" flow:established,to_server; content:"NICK "; depth:5; content:"USA"; within:10; reference:url,doc.emergingthreats.net/2008124; **classtype:trojan-activity;** sid:2008124; rev:5;) +.. image:: meta/classtype.png + +In this example the red, bold-faced part is the classtype. Reference --------- @@ -115,7 +126,9 @@ The reference keywords direct to places where information about the signature and about the problem the signature tries to address, can be found. The reference keyword can appear multiple times in a signature. This keyword is meant for signature-writers and analysts who -investigate why a signature has matched. It has the following format:: +investigate why a signature has matched. It has the following format: + +:: reference: url, www.info.nl @@ -124,27 +137,30 @@ actual reference (notice here you can not use http before the url). There are different types of references: -========= =============================================== -system URL Prefix -========= =============================================== -bugtraq ``http://www.securityfocus.com/bid`` -cve ``http://cve.mitre.org/cgi-bin/cvename.cgi?name=`` -nessus ``http://cgi.nessus.org/plugins/dump.php3?id=`` -arachnids ``http://www.whitehats.com/info/IDS`` -mcafee ``http://vil.nai.com/vil/dispVirus.asp?virus_k=`` -url ``http://`` -========= =============================================== +type: + +:: + + system URL Prefix + bugtraq http://www.securityfocus.com/bid + cve http://cve.mitre.org/cgi-bin/cvename.cgi?name= + nessus http://cgi.nessus.org/plugins/dump.php3?id= + arachnids (No longer available but you might still encounter this in signatures.) + http://www.whitehats.com/info/IDS + mcafee http://vil.nai.com/vil/dispVirus.asp?virus_k= + url http:// -*Note that ararchnids is no longer available but may still be -encountered in signatures.* +For example bugtraq will be replaced by the full url: -For example bugtraq will be replaced by the full url:: +:: reference: bugtraq, 123; http://www.securityfocus.com/bid Example of reference in a signature: - alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)" flow:established,to_server; content:"NICK "; depth:5; content:"USA"; within:10; **reference:url,doc.emergingthreats.net/2008124;** classtype:trojan-activity; sid:2008124; rev:5;) +.. image:: meta/reference.png + +In this example the red, bold-faced part is the action. Priority -------- @@ -154,15 +170,18 @@ range from 1 till 255. The numbers 1 to 4 are most often used. Signatures with a higher priority will be examined first. The highest priority is 1. Normally signatures have already a priority through class type. This can be overruled with the keyword priority. The -format of priority is:: +format of priority is: + +:: priority:1; Metadata -------- -Suricata ignores the words behind meta data. -Suricata supports this keyword because it is part of the signature language. -The format is:: +Suricata ignores the words behind meta data. Suricata supports this +keyword because it is part of the signature language. The format is: + +:: - metadata:...; + metadata:......; diff --git a/doc/sphinx/meta/classification.png b/doc/sphinx/meta/classification.png new file mode 100644 index 0000000000000000000000000000000000000000..456b1ee30a071656e2d10765ee4605f1c12a2802 GIT binary patch literal 41206 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/meta/classtype.png b/doc/sphinx/meta/classtype.png new file mode 100644 index 0000000000000000000000000000000000000000..3d891943d2e95604a7dc1e9b78846fef2017baef GIT binary patch literal 42404 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/meta/gid.png b/doc/sphinx/meta/gid.png new file mode 100644 index 0000000000000000000000000000000000000000..051eecbf5db7b8c6f847ab7c6fd2953f25cd1a6c GIT binary patch literal 30298 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/meta/msg.png b/doc/sphinx/meta/msg.png new file mode 100644 index 0000000000000000000000000000000000000000..8d1e1beeb9938f7cf541f9b1cd4770b89a4d6736 GIT binary patch literal 38884 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%0Di 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/meta/sid.png b/doc/sphinx/meta/sid.png new file mode 100644 index 0000000000000000000000000000000000000000..7952641d64a82f1de897e41daf0ab33bb6dae9be GIT binary patch literal 41173 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 VMTb-9+g~REvQkQ*N(p2C{{oETSo;6~ literal 0 HcmV?d00001 diff --git a/doc/sphinx/payload-keywords.rst b/doc/sphinx/payload-keywords.rst index c6889cddd894..7af5fc21c9b4 100644 --- a/doc/sphinx/payload-keywords.rst +++ b/doc/sphinx/payload-keywords.rst @@ -285,7 +285,7 @@ another ('def'), see example: The replace modifier has to contain as many characters as the content it replaces. It can only be used with individual packets. It will not -work for [[Normalized Buffers]] like HTTP uri or a content match in +work for [[**FIXME** Normalized Buffers]] like HTTP uri or a content match in the reassembled stream. The checksums will be recalculated by Suricata and changed after the @@ -294,8 +294,7 @@ replace keyword is being used. pcre ---- -For information about pcre check the [[pcre (Perl Compatible Regular -Expressions)]] page. +For information about pcre check the :doc:`pcre` page. fast_pattern ------------ diff --git a/doc/sphinx/pcre.rst b/doc/sphinx/pcre.rst index 74f8024d91a3..eeeb314caf2c 100644 --- a/doc/sphinx/pcre.rst +++ b/doc/sphinx/pcre.rst @@ -64,7 +64,7 @@ Suricata has its own specific pcre modifiers. These are: uri_buffer just like uricontent and content combined with http_uri.U can be combined with /R. Note that R is relative to the previous match so both matches have to be in the HTTP-uri buffer. Read more - about [[HTTP-uri normalization]]. + about [[**FIXME** HTTP-uri normalization]]. .. image:: pcre/pcre3.png @@ -77,7 +77,7 @@ Suricata has its own specific pcre modifiers. These are: * ``I``: Makes pcre match on the HTTP-raw-uri. It matches on the same buffer as http_raw_uri. I can be combined with /R. Note that R is relative to the previous match so both matches have to be in the - HTTP-raw-uri buffer. Read more about [[HTTP-uri normalization]]. + HTTP-raw-uri buffer. Read more about [[**FIXME** HTTP-uri normalization]]. .. image:: pcre/pcre7.png diff --git a/doc/sphinx/rule-lua-scripting.rst b/doc/sphinx/rule-lua-scripting.rst index 9eff413a3c07..c142eeca5083 100644 --- a/doc/sphinx/rule-lua-scripting.rst +++ b/doc/sphinx/rule-lua-scripting.rst @@ -2,7 +2,7 @@ Lua Scripting ============= In order to enable Lua scripting, please reference this page before -continuing [[Installation from GIT with luajit]]. +continuing [[**FIXME** Installation from GIT with luajit]]. Syntax: diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index c3e706696b63..76279c032a69 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -1,9 +1,9 @@ -Rules -===== +Suricata Rules +============== .. toctree:: - :maxdepth: 2 + :maxdepth: 1 meta header-keywords @@ -16,8 +16,191 @@ Rules rule-lua-scripting adding-your-own-rules live-rule-swap + dns-keywords tls-keywords normalized-buffers rule-profiling modbus-keyword dnp3-keywords + +Introduction +~~~~~~~~~~~~ + +Signatures play a very important role in Suricata. In most occasions +people are using existing rulesets. The most used are `Emerging +Threats `_, `Emerging Threats +Pro `_ and Sourcefire's +`VRT `_. A way to install rules is described +in [[**FIXME** Rule Management with Oinkmaster]]. This Suricata Rules document +explains all about signatures; how to read-, adjust-and create them. + +A rule/signature consists of the following: + + The action, header and rule-options. + +Example of a signature: + +.. image:: rules/intro_sig.png + +Action +~~~~~~ + +For more information read 'Action Order' in the +[[**FIXME** suricata.yaml#Action-order]] wiki. + +Example: + +.. image:: rules/action.png + +In this example the red, bold-faced part is the action. + +Protocol +~~~~~~~~ + +This keyword in a signature tells Suricata which protocol it +concerns. You can choose between four settings. tcp (for +tcp-traffic), udp, icmp and ip. ip stands for 'all' or 'any'. +Suricata adds a few protocols : http, ftp, tls (this includes ssl), +smb and dns (from v2.0). These are the so-called application layer +protocols or layer 7 protocols. If you have a signature with for +instance a http-protocol, Suricata makes sure the signature can only +match if it concerns http-traffic. + +Example: + +.. image:: rules/protocol.png + +In this example the red, bold-faced part is the protocol. + +Source and destination +~~~~~~~~~~~~~~~~~~~~~~ + +In source you can assign IP-addresses; IPv4 and IPv6 combined as well +as separated. You can also set variables such as HOME_NET. (For more +information see 'Rule-vars' at [[**FIXME** Suricata.yaml#Rule-vars]] in the user +guide.) In the Yaml-file you can set IP-addresses for variables such +as EXTERNAL_NET and HOME_NET. These settings will be used when you use +these variables in a rule. In source and destination you can make use +of signs like ! And [ ]. + +For example:: + + ! 1.1.1.1 (Every IP address but 1.1.1.1) + ![1.1.1.1, 1.1.1.2] (Every IP address but 1.1.1.1 and 1.1.1.2) + $HOME_NET (Your setting of HOME_NET in yaml) + [$EXTERNAL_NET, !$HOME_NET] (EXTERNAL_NET and not HOME_NET) + [10.0.0.0/24, !10.0.0.5] (10.0.0.0/24 except for 10.0.0.5) + […..,[....]] + […. ,![.....]] + + +Pay attention to the following: + +If your settings in Yaml are:: + + HOME_NET: any + EXTERNAL_NET: ! $HOME_NET + +You can not write a signature using EXTERNAL_NET because it stands for +'not any'. This is a invalid setting. + +Example of source and destination in a signature: + +.. image:: rules/Source.png + +The red, bold-faced part is the source. + +.. image:: rules/destination.png + +The red, bold-faced part is the destination. + +Ports (source-and destination-port) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Traffic comes in and goes out through ports. Different ports have +different port-numbers. The HTTP-port for example is 80 while 443 is +the port for HTTPS and MSN makes use of port 1863. Commonly the Source +port will be set as 'any'. This will be influenced by the +protocol. The source port is designated at random by the operating +system. Sometimes it is possible to filter/screen on the source In +setting ports you can make use of special signs as well, like +described above at 'source'. Signs like:: + + ! exception/negation + : range + [] signs to make clear which parts belong together + , separation + +Example:: + + [80, 81, 82] (port 80, 81 and 82) + [80: 82] (Range from 80 till 82) + [1024: ] (From 1024 till the highest port-number) + !80 (Every port but 80) + [80:100,!99] (Range from 80 till 100 but 99 excluded) + [1:80,![2,4]] + [….[.....]] + +Example of ports in a signature: + +.. image:: rules/Source-port.png + + +.. image:: rules/Dest_port.png + +In this example, the red, bold-faced part is the port. + +Direction +~~~~~~~~~ + +The direction tells in which way the signature has to match. Nearly +every signature has an arrow to the right. This means that only +packets with the same direction can match. + +:: + + source -> destination + source <> destination (both directions) + +Example:: + + alert tcp 1.2.3.4 1024 - > 5.6.7.8 80 + +Example 1 tcp-session + +.. image:: rules/TCP-session.png + +In this example there will only be a match if the signature has the +same order/direction as the payload. + +Example of direction in a signature: + +.. image:: rules/Direction.png + +In this example the red, bold-faced part is the direction. + +Rule options +------------ + +Keywords have a set format:: + + name: settings; + +Sometimes it is just the name of the setting followed by ; . Like nocase; + +There are specific settings for: + +* meta-information. +* headers +* payloads +* flows + +For more information about these settings, you can click on the +following headlines: + +* :doc:`meta` +* :doc:`payload-keywords` +* :doc:`http-keywords` +* :doc:`dns-keywords` +* :doc:`flow-keywords` +* **FIXME** [[IPReputationRules|IP Reputation keyword]] diff --git a/doc/sphinx/rules/Dest_port.png b/doc/sphinx/rules/Dest_port.png new file mode 100644 index 0000000000000000000000000000000000000000..43e04147b886994a78bdad446704cff64cc6d42c GIT binary patch literal 41492 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

@>Vxhmc#Nwm6_o_faG)|Rje&%&yj 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/rules/action.png b/doc/sphinx/rules/action.png new file mode 100644 index 0000000000000000000000000000000000000000..4d67d152b0b6cb7857dc1d8883d4001578d523d9 GIT binary patch literal 40842 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 z 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/thresholding.rst b/doc/sphinx/thresholding.rst index a92d3fb57dca..2782087db9ae 100644 --- a/doc/sphinx/thresholding.rst +++ b/doc/sphinx/thresholding.rst @@ -2,11 +2,11 @@ Rule Thresholding ================= Thresholding can be configured per rule and also globally, see -[[Global-Thresholds]]. +[[**FIXME** Global-Thresholds]]. *Note: mixing rule and global thresholds is not supported in 1.3 and before. See bug #425.* For the state of the support in 1.4 see -[[Global-Thresholds#Global-thresholds-vs-rule-thresholds]]. +[[**FIXME** Global-Thresholds#Global-thresholds-vs-rule-thresholds]]. threshold --------- @@ -61,7 +61,7 @@ If a signature sets a flowbit, flowint, etc. those actions are still performed for each of the matches. *Rule actions drop (IPS mode) and reject are applied to each packet - (not only the one that meets the limit condition).* + (not only the one that meets the limit condition).* type "both" ~~~~~~~~~~~ diff --git a/doc/sphinx/tls-keywords.rst b/doc/sphinx/tls-keywords.rst index 57a5a805847e..5e891a68f64c 100644 --- a/doc/sphinx/tls-keywords.rst +++ b/doc/sphinx/tls-keywords.rst @@ -1,4 +1,4 @@ -TLS-keywords +TLS Keywords ============ Suricata comes with several rule keywords to match on various properties of TLS/SSL handshake. Matches are string inclusion matches. diff --git a/doc/sphinx/what-is-suricata.rst b/doc/sphinx/what-is-suricata.rst index 6ae7ba1fd818..920f081a7d01 100644 --- a/doc/sphinx/what-is-suricata.rst +++ b/doc/sphinx/what-is-suricata.rst @@ -65,4 +65,4 @@ very advanced processing of HTTP streams for Suricata. The HTP library is required by the engine, but may also be used independently in a range of applications and tools. -[[Major Features|Next]] +[[**FIXME** Major Features|Next]] From 7c9475e94debffc0d1da3327887c21be40e57c35 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 11:45:41 -0600 Subject: [PATCH 1780/2553] doc: add fixme to broken images --- doc/sphinx/pcre.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/sphinx/pcre.rst b/doc/sphinx/pcre.rst index eeeb314caf2c..a0df46fc3b39 100644 --- a/doc/sphinx/pcre.rst +++ b/doc/sphinx/pcre.rst @@ -79,9 +79,9 @@ Suricata has its own specific pcre modifiers. These are: relative to the previous match so both matches have to be in the HTTP-raw-uri buffer. Read more about [[**FIXME** HTTP-uri normalization]]. -.. image:: pcre/pcre7.png +** FIXME - image is missing on wiki: .. image:: pcre/pcre7.png -.. image:: pcre/pcre8.png +** FIXME - image is missing on wiki: .. image:: pcre/pcre8.png * ``P``: Makes pcre match on the HTTP- request-body. So, it matches on the same buffer as http_client_body. P can be combined with /R. Note From b0c2d6c8ee0e693157652fefc1131e54d4c37f9e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 11:50:35 -0600 Subject: [PATCH 1781/2553] doc: restructure the rules section a little --- doc/sphinx/rules-intro.rst | 183 ++++++++++++++++++++++++++++++++++++ doc/sphinx/rules.rst | 184 +------------------------------------ 2 files changed, 184 insertions(+), 183 deletions(-) create mode 100644 doc/sphinx/rules-intro.rst diff --git a/doc/sphinx/rules-intro.rst b/doc/sphinx/rules-intro.rst new file mode 100644 index 000000000000..960da6994a89 --- /dev/null +++ b/doc/sphinx/rules-intro.rst @@ -0,0 +1,183 @@ +Rules Introduction +================== + +.. contents:: + +Signatures play a very important role in Suricata. In most occasions +people are using existing rulesets. The most used are `Emerging +Threats `_, `Emerging Threats +Pro `_ and Sourcefire's +`VRT `_. A way to install rules is described +in [[**FIXME** Rule Management with Oinkmaster]]. This Suricata Rules document +explains all about signatures; how to read-, adjust-and create them. + +A rule/signature consists of the following: + + The action, header and rule-options. + +Example of a signature: + +.. image:: rules/intro_sig.png + +Action +------ + +For more information read 'Action Order' in the +[[**FIXME** suricata.yaml#Action-order]] wiki. + +Example: + +.. image:: rules/action.png + +In this example the red, bold-faced part is the action. + +Protocol +-------- + +This keyword in a signature tells Suricata which protocol it +concerns. You can choose between four settings. tcp (for +tcp-traffic), udp, icmp and ip. ip stands for 'all' or 'any'. +Suricata adds a few protocols : http, ftp, tls (this includes ssl), +smb and dns (from v2.0). These are the so-called application layer +protocols or layer 7 protocols. If you have a signature with for +instance a http-protocol, Suricata makes sure the signature can only +match if it concerns http-traffic. + +Example: + +.. image:: rules/protocol.png + +In this example the red, bold-faced part is the protocol. + +Source and destination +---------------------- + +In source you can assign IP-addresses; IPv4 and IPv6 combined as well +as separated. You can also set variables such as HOME_NET. (For more +information see 'Rule-vars' at [[**FIXME** Suricata.yaml#Rule-vars]] in the user +guide.) In the Yaml-file you can set IP-addresses for variables such +as EXTERNAL_NET and HOME_NET. These settings will be used when you use +these variables in a rule. In source and destination you can make use +of signs like ! And [ ]. + +For example:: + + ! 1.1.1.1 (Every IP address but 1.1.1.1) + ![1.1.1.1, 1.1.1.2] (Every IP address but 1.1.1.1 and 1.1.1.2) + $HOME_NET (Your setting of HOME_NET in yaml) + [$EXTERNAL_NET, !$HOME_NET] (EXTERNAL_NET and not HOME_NET) + [10.0.0.0/24, !10.0.0.5] (10.0.0.0/24 except for 10.0.0.5) + […..,[....]] + […. ,![.....]] + + +Pay attention to the following: + +If your settings in Yaml are:: + + HOME_NET: any + EXTERNAL_NET: ! $HOME_NET + +You can not write a signature using EXTERNAL_NET because it stands for +'not any'. This is a invalid setting. + +Example of source and destination in a signature: + +.. image:: rules/Source.png + +The red, bold-faced part is the source. + +.. image:: rules/destination.png + +The red, bold-faced part is the destination. + +Ports (source-and destination-port) +----------------------------------- + +Traffic comes in and goes out through ports. Different ports have +different port-numbers. The HTTP-port for example is 80 while 443 is +the port for HTTPS and MSN makes use of port 1863. Commonly the Source +port will be set as 'any'. This will be influenced by the +protocol. The source port is designated at random by the operating +system. Sometimes it is possible to filter/screen on the source In +setting ports you can make use of special signs as well, like +described above at 'source'. Signs like:: + + ! exception/negation + : range + [] signs to make clear which parts belong together + , separation + +Example:: + + [80, 81, 82] (port 80, 81 and 82) + [80: 82] (Range from 80 till 82) + [1024: ] (From 1024 till the highest port-number) + !80 (Every port but 80) + [80:100,!99] (Range from 80 till 100 but 99 excluded) + [1:80,![2,4]] + [….[.....]] + +Example of ports in a signature: + +.. image:: rules/Source-port.png + + +.. image:: rules/Dest_port.png + +In this example, the red, bold-faced part is the port. + +Direction +--------- + +The direction tells in which way the signature has to match. Nearly +every signature has an arrow to the right. This means that only +packets with the same direction can match. + +:: + + source -> destination + source <> destination (both directions) + +Example:: + + alert tcp 1.2.3.4 1024 - > 5.6.7.8 80 + +Example 1 tcp-session + +.. image:: rules/TCP-session.png + +In this example there will only be a match if the signature has the +same order/direction as the payload. + +Example of direction in a signature: + +.. image:: rules/Direction.png + +In this example the red, bold-faced part is the direction. + +Rule options +------------ + +Keywords have a set format:: + + name: settings; + +Sometimes it is just the name of the setting followed by ; . Like nocase; + +There are specific settings for: + +* meta-information. +* headers +* payloads +* flows + +For more information about these settings, you can click on the +following headlines: + +* :doc:`meta` +* :doc:`payload-keywords` +* :doc:`http-keywords` +* :doc:`dns-keywords` +* :doc:`flow-keywords` +* **FIXME** [[IPReputationRules|IP Reputation keyword]] diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules.rst index 76279c032a69..8b5f5e95eee3 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules.rst @@ -1,10 +1,9 @@ Suricata Rules ============== - .. toctree:: - :maxdepth: 1 + rules-intro meta header-keywords payload-keywords @@ -23,184 +22,3 @@ Suricata Rules modbus-keyword dnp3-keywords -Introduction -~~~~~~~~~~~~ - -Signatures play a very important role in Suricata. In most occasions -people are using existing rulesets. The most used are `Emerging -Threats `_, `Emerging Threats -Pro `_ and Sourcefire's -`VRT `_. A way to install rules is described -in [[**FIXME** Rule Management with Oinkmaster]]. This Suricata Rules document -explains all about signatures; how to read-, adjust-and create them. - -A rule/signature consists of the following: - - The action, header and rule-options. - -Example of a signature: - -.. image:: rules/intro_sig.png - -Action -~~~~~~ - -For more information read 'Action Order' in the -[[**FIXME** suricata.yaml#Action-order]] wiki. - -Example: - -.. image:: rules/action.png - -In this example the red, bold-faced part is the action. - -Protocol -~~~~~~~~ - -This keyword in a signature tells Suricata which protocol it -concerns. You can choose between four settings. tcp (for -tcp-traffic), udp, icmp and ip. ip stands for 'all' or 'any'. -Suricata adds a few protocols : http, ftp, tls (this includes ssl), -smb and dns (from v2.0). These are the so-called application layer -protocols or layer 7 protocols. If you have a signature with for -instance a http-protocol, Suricata makes sure the signature can only -match if it concerns http-traffic. - -Example: - -.. image:: rules/protocol.png - -In this example the red, bold-faced part is the protocol. - -Source and destination -~~~~~~~~~~~~~~~~~~~~~~ - -In source you can assign IP-addresses; IPv4 and IPv6 combined as well -as separated. You can also set variables such as HOME_NET. (For more -information see 'Rule-vars' at [[**FIXME** Suricata.yaml#Rule-vars]] in the user -guide.) In the Yaml-file you can set IP-addresses for variables such -as EXTERNAL_NET and HOME_NET. These settings will be used when you use -these variables in a rule. In source and destination you can make use -of signs like ! And [ ]. - -For example:: - - ! 1.1.1.1 (Every IP address but 1.1.1.1) - ![1.1.1.1, 1.1.1.2] (Every IP address but 1.1.1.1 and 1.1.1.2) - $HOME_NET (Your setting of HOME_NET in yaml) - [$EXTERNAL_NET, !$HOME_NET] (EXTERNAL_NET and not HOME_NET) - [10.0.0.0/24, !10.0.0.5] (10.0.0.0/24 except for 10.0.0.5) - […..,[....]] - […. ,![.....]] - - -Pay attention to the following: - -If your settings in Yaml are:: - - HOME_NET: any - EXTERNAL_NET: ! $HOME_NET - -You can not write a signature using EXTERNAL_NET because it stands for -'not any'. This is a invalid setting. - -Example of source and destination in a signature: - -.. image:: rules/Source.png - -The red, bold-faced part is the source. - -.. image:: rules/destination.png - -The red, bold-faced part is the destination. - -Ports (source-and destination-port) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Traffic comes in and goes out through ports. Different ports have -different port-numbers. The HTTP-port for example is 80 while 443 is -the port for HTTPS and MSN makes use of port 1863. Commonly the Source -port will be set as 'any'. This will be influenced by the -protocol. The source port is designated at random by the operating -system. Sometimes it is possible to filter/screen on the source In -setting ports you can make use of special signs as well, like -described above at 'source'. Signs like:: - - ! exception/negation - : range - [] signs to make clear which parts belong together - , separation - -Example:: - - [80, 81, 82] (port 80, 81 and 82) - [80: 82] (Range from 80 till 82) - [1024: ] (From 1024 till the highest port-number) - !80 (Every port but 80) - [80:100,!99] (Range from 80 till 100 but 99 excluded) - [1:80,![2,4]] - [….[.....]] - -Example of ports in a signature: - -.. image:: rules/Source-port.png - - -.. image:: rules/Dest_port.png - -In this example, the red, bold-faced part is the port. - -Direction -~~~~~~~~~ - -The direction tells in which way the signature has to match. Nearly -every signature has an arrow to the right. This means that only -packets with the same direction can match. - -:: - - source -> destination - source <> destination (both directions) - -Example:: - - alert tcp 1.2.3.4 1024 - > 5.6.7.8 80 - -Example 1 tcp-session - -.. image:: rules/TCP-session.png - -In this example there will only be a match if the signature has the -same order/direction as the payload. - -Example of direction in a signature: - -.. image:: rules/Direction.png - -In this example the red, bold-faced part is the direction. - -Rule options ------------- - -Keywords have a set format:: - - name: settings; - -Sometimes it is just the name of the setting followed by ; . Like nocase; - -There are specific settings for: - -* meta-information. -* headers -* payloads -* flows - -For more information about these settings, you can click on the -following headlines: - -* :doc:`meta` -* :doc:`payload-keywords` -* :doc:`http-keywords` -* :doc:`dns-keywords` -* :doc:`flow-keywords` -* **FIXME** [[IPReputationRules|IP Reputation keyword]] From 80e6830dece8b76cde55cfc84f34b8a1ab3c90d1 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 4 Dec 2015 12:04:46 -0600 Subject: [PATCH 1782/2553] doc: restructure directory layout --- doc/sphinx/index.rst | 2 +- .../{ => rules}/adding-your-own-rules.rst | 0 doc/sphinx/{ => rules}/dnp3-keywords.rst | 0 doc/sphinx/{ => rules}/dns-keywords.rst | 0 .../{ => rules}/dns-keywords/dns_query.png | Bin .../{ => rules}/fast-pattern-explained.rst | 0 doc/sphinx/{ => rules}/fast-pattern.rst | 0 .../{ => rules}/fast-pattern/fast_pattern.png | Bin doc/sphinx/{ => rules}/file-keywords.rst | 0 doc/sphinx/{ => rules}/flow-keywords.rst | 0 .../{ => rules}/flow-keywords/Flow1.png | Bin .../{ => rules}/flow-keywords/Flow2.png | Bin .../{ => rules}/flow-keywords/Flowbit_3.png | Bin doc/sphinx/{ => rules}/flowint.rst | 0 doc/sphinx/{ => rules}/header-keywords.rst | 0 .../header-keywords/ICMP_type_code.png | Bin .../header-keywords/ICMP_types.png | Bin .../{ => rules}/header-keywords/Window.png | Bin .../header-keywords/Wireshark_ack.png | Bin .../header-keywords/Wireshark_seq.png | Bin .../{ => rules}/header-keywords/ack.png | Bin .../{ => rules}/header-keywords/fragbits.png | Bin .../header-keywords/fragoffset.png | Bin .../{ => rules}/header-keywords/icmp_id.png | Bin .../{ => rules}/header-keywords/icmp_seq.png | Bin .../{ => rules}/header-keywords/icmp_type.png | Bin .../{ => rules}/header-keywords/icode.png | Bin doc/sphinx/{ => rules}/header-keywords/id.png | Bin .../{ => rules}/header-keywords/ip_proto.png | Bin .../{ => rules}/header-keywords/ipopts.png | Bin .../header-keywords/ipopts_rule.png | Bin .../{ => rules}/header-keywords/sameip.png | Bin .../{ => rules}/header-keywords/seq.png | Bin .../{ => rules}/header-keywords/ttl.png | Bin doc/sphinx/{ => rules}/http-keywords.rst | 0 .../http-keywords/Legenda_rules.png | Bin .../{ => rules}/http-keywords/client_body.png | Bin .../http-keywords/client_body1.png | Bin .../{ => rules}/http-keywords/cookie.png | Bin .../{ => rules}/http-keywords/cookie1.png | Bin .../http-keywords/fast_pattern.png | Bin .../{ => rules}/http-keywords/file_data.png | Bin .../{ => rules}/http-keywords/header.png | Bin .../{ => rules}/http-keywords/header1.png | Bin .../http-keywords/http_server_body.png | Bin .../{ => rules}/http-keywords/http_uri.png | Bin .../{ => rules}/http-keywords/method.png | Bin .../{ => rules}/http-keywords/method1.png | Bin .../{ => rules}/http-keywords/method2.png | Bin .../{ => rules}/http-keywords/request.png | Bin .../{ => rules}/http-keywords/request2.png | Bin .../{ => rules}/http-keywords/response1.png | Bin .../{ => rules}/http-keywords/stat-code1.png | Bin .../{ => rules}/http-keywords/stat_code.png | Bin .../{ => rules}/http-keywords/stat_msg.png | Bin .../{ => rules}/http-keywords/stat_msg_1.png | Bin doc/sphinx/{ => rules}/http-keywords/uri.png | Bin doc/sphinx/{ => rules}/http-keywords/uri1.png | Bin .../{ => rules}/http-keywords/uricontent.png | Bin .../{ => rules}/http-keywords/uricontent1.png | Bin .../{ => rules}/http-keywords/urilen.png | Bin .../{ => rules}/http-keywords/urilen1.png | Bin .../{ => rules}/http-keywords/user_agent.png | Bin .../http-keywords/user_agent_match.png | Bin doc/sphinx/{rules.rst => rules/index.rst} | 3 +-- .../{rules-intro.rst => rules/intro.rst} | 18 +++++++++--------- doc/sphinx/rules/{ => intro}/Dest_port.png | Bin doc/sphinx/rules/{ => intro}/Direction.png | Bin doc/sphinx/rules/{ => intro}/Source-port.png | Bin doc/sphinx/rules/{ => intro}/Source.png | Bin doc/sphinx/rules/{ => intro}/TCP-session.png | Bin doc/sphinx/rules/{ => intro}/action.png | Bin doc/sphinx/rules/{ => intro}/destination.png | Bin doc/sphinx/rules/{ => intro}/intro_sig.png | Bin doc/sphinx/rules/{ => intro}/protocol.png | Bin doc/sphinx/{ => rules}/live-rule-swap.rst | 0 doc/sphinx/{ => rules}/meta.rst | 0 .../{ => rules}/meta/classification.png | Bin doc/sphinx/{ => rules}/meta/classtype.png | Bin doc/sphinx/{ => rules}/meta/gid.png | Bin doc/sphinx/{ => rules}/meta/msg.png | Bin doc/sphinx/{ => rules}/meta/reference.png | Bin doc/sphinx/{ => rules}/meta/rev.png | Bin doc/sphinx/{ => rules}/meta/sid.png | Bin doc/sphinx/{ => rules}/modbus-keyword.rst | 0 doc/sphinx/{ => rules}/normalized-buffers.rst | 0 .../normalized-buffers/normalization1.png | Bin doc/sphinx/{ => rules}/payload-keywords.rst | 0 .../payload-keywords/Legenda_rules.png | Bin .../{ => rules}/payload-keywords/content.png | Bin .../{ => rules}/payload-keywords/content2.png | Bin .../{ => rules}/payload-keywords/content3.png | Bin .../{ => rules}/payload-keywords/content4.png | Bin .../{ => rules}/payload-keywords/content5.png | Bin .../{ => rules}/payload-keywords/content6.png | Bin .../{ => rules}/payload-keywords/distance.png | Bin .../payload-keywords/distance1.png | Bin .../payload-keywords/distance3.png | Bin .../payload-keywords/distance4.png | Bin .../payload-keywords/distance5.png | Bin .../{ => rules}/payload-keywords/dsize.png | Bin .../payload-keywords/isdataat1.png | Bin .../{ => rules}/payload-keywords/replace.png | Bin .../{ => rules}/payload-keywords/replace1.png | Bin .../{ => rules}/payload-keywords/rpc.png | Bin .../{ => rules}/payload-keywords/within1.png | Bin .../{ => rules}/payload-keywords/within2.png | Bin .../payload-keywords/within_distance.png | Bin .../payload-keywords/within_distance2.png | Bin doc/sphinx/{ => rules}/pcre.rst | 0 doc/sphinx/{ => rules}/pcre/pcre.png | Bin doc/sphinx/{ => rules}/pcre/pcre3.png | Bin doc/sphinx/{ => rules}/pcre/pcre4.png | Bin doc/sphinx/{ => rules}/pcre/pcre5.png | Bin doc/sphinx/{ => rules}/pcre/pcre6.png | Bin doc/sphinx/{ => rules}/rule-lua-scripting.rst | 0 doc/sphinx/{ => rules}/rule-profiling.rst | 0 doc/sphinx/{ => rules}/thresholding.rst | 0 doc/sphinx/{ => rules}/tls-keywords.rst | 0 119 files changed, 11 insertions(+), 12 deletions(-) rename doc/sphinx/{ => rules}/adding-your-own-rules.rst (100%) rename doc/sphinx/{ => rules}/dnp3-keywords.rst (100%) rename doc/sphinx/{ => rules}/dns-keywords.rst (100%) rename doc/sphinx/{ => rules}/dns-keywords/dns_query.png (100%) rename doc/sphinx/{ => rules}/fast-pattern-explained.rst (100%) rename doc/sphinx/{ => rules}/fast-pattern.rst (100%) rename doc/sphinx/{ => rules}/fast-pattern/fast_pattern.png (100%) rename doc/sphinx/{ => rules}/file-keywords.rst (100%) rename doc/sphinx/{ => rules}/flow-keywords.rst (100%) rename doc/sphinx/{ => rules}/flow-keywords/Flow1.png (100%) rename doc/sphinx/{ => rules}/flow-keywords/Flow2.png (100%) rename doc/sphinx/{ => rules}/flow-keywords/Flowbit_3.png (100%) rename doc/sphinx/{ => rules}/flowint.rst (100%) rename doc/sphinx/{ => rules}/header-keywords.rst (100%) rename doc/sphinx/{ => rules}/header-keywords/ICMP_type_code.png (100%) rename doc/sphinx/{ => rules}/header-keywords/ICMP_types.png (100%) rename doc/sphinx/{ => rules}/header-keywords/Window.png (100%) rename doc/sphinx/{ => rules}/header-keywords/Wireshark_ack.png (100%) rename doc/sphinx/{ => rules}/header-keywords/Wireshark_seq.png (100%) rename doc/sphinx/{ => rules}/header-keywords/ack.png (100%) rename doc/sphinx/{ => rules}/header-keywords/fragbits.png (100%) rename doc/sphinx/{ => rules}/header-keywords/fragoffset.png (100%) rename doc/sphinx/{ => rules}/header-keywords/icmp_id.png (100%) rename doc/sphinx/{ => rules}/header-keywords/icmp_seq.png (100%) rename doc/sphinx/{ => rules}/header-keywords/icmp_type.png (100%) rename doc/sphinx/{ => rules}/header-keywords/icode.png (100%) rename doc/sphinx/{ => rules}/header-keywords/id.png (100%) rename doc/sphinx/{ => rules}/header-keywords/ip_proto.png (100%) rename doc/sphinx/{ => rules}/header-keywords/ipopts.png (100%) rename doc/sphinx/{ => rules}/header-keywords/ipopts_rule.png (100%) rename doc/sphinx/{ => rules}/header-keywords/sameip.png (100%) rename doc/sphinx/{ => rules}/header-keywords/seq.png (100%) rename doc/sphinx/{ => rules}/header-keywords/ttl.png (100%) rename doc/sphinx/{ => rules}/http-keywords.rst (100%) rename doc/sphinx/{ => rules}/http-keywords/Legenda_rules.png (100%) rename doc/sphinx/{ => rules}/http-keywords/client_body.png (100%) rename doc/sphinx/{ => rules}/http-keywords/client_body1.png (100%) rename doc/sphinx/{ => rules}/http-keywords/cookie.png (100%) rename doc/sphinx/{ => rules}/http-keywords/cookie1.png (100%) rename doc/sphinx/{ => rules}/http-keywords/fast_pattern.png (100%) rename doc/sphinx/{ => rules}/http-keywords/file_data.png (100%) rename doc/sphinx/{ => rules}/http-keywords/header.png (100%) rename doc/sphinx/{ => rules}/http-keywords/header1.png (100%) rename doc/sphinx/{ => rules}/http-keywords/http_server_body.png (100%) rename doc/sphinx/{ => rules}/http-keywords/http_uri.png (100%) rename doc/sphinx/{ => rules}/http-keywords/method.png (100%) rename doc/sphinx/{ => rules}/http-keywords/method1.png (100%) rename doc/sphinx/{ => rules}/http-keywords/method2.png (100%) rename doc/sphinx/{ => rules}/http-keywords/request.png (100%) rename doc/sphinx/{ => rules}/http-keywords/request2.png (100%) rename doc/sphinx/{ => rules}/http-keywords/response1.png (100%) rename doc/sphinx/{ => rules}/http-keywords/stat-code1.png (100%) rename doc/sphinx/{ => rules}/http-keywords/stat_code.png (100%) rename doc/sphinx/{ => rules}/http-keywords/stat_msg.png (100%) rename doc/sphinx/{ => rules}/http-keywords/stat_msg_1.png (100%) rename doc/sphinx/{ => rules}/http-keywords/uri.png (100%) rename doc/sphinx/{ => rules}/http-keywords/uri1.png (100%) rename doc/sphinx/{ => rules}/http-keywords/uricontent.png (100%) rename doc/sphinx/{ => rules}/http-keywords/uricontent1.png (100%) rename doc/sphinx/{ => rules}/http-keywords/urilen.png (100%) rename doc/sphinx/{ => rules}/http-keywords/urilen1.png (100%) rename doc/sphinx/{ => rules}/http-keywords/user_agent.png (100%) rename doc/sphinx/{ => rules}/http-keywords/user_agent_match.png (100%) rename doc/sphinx/{rules.rst => rules/index.rst} (95%) rename doc/sphinx/{rules-intro.rst => rules/intro.rst} (94%) rename doc/sphinx/rules/{ => intro}/Dest_port.png (100%) rename doc/sphinx/rules/{ => intro}/Direction.png (100%) rename doc/sphinx/rules/{ => intro}/Source-port.png (100%) rename doc/sphinx/rules/{ => intro}/Source.png (100%) rename doc/sphinx/rules/{ => intro}/TCP-session.png (100%) rename doc/sphinx/rules/{ => intro}/action.png (100%) rename doc/sphinx/rules/{ => intro}/destination.png (100%) rename doc/sphinx/rules/{ => intro}/intro_sig.png (100%) rename doc/sphinx/rules/{ => intro}/protocol.png (100%) rename doc/sphinx/{ => rules}/live-rule-swap.rst (100%) rename doc/sphinx/{ => rules}/meta.rst (100%) rename doc/sphinx/{ => rules}/meta/classification.png (100%) rename doc/sphinx/{ => rules}/meta/classtype.png (100%) rename doc/sphinx/{ => rules}/meta/gid.png (100%) rename doc/sphinx/{ => rules}/meta/msg.png (100%) rename doc/sphinx/{ => rules}/meta/reference.png (100%) rename doc/sphinx/{ => rules}/meta/rev.png (100%) rename doc/sphinx/{ => rules}/meta/sid.png (100%) rename doc/sphinx/{ => rules}/modbus-keyword.rst (100%) rename doc/sphinx/{ => rules}/normalized-buffers.rst (100%) rename doc/sphinx/{ => rules}/normalized-buffers/normalization1.png (100%) rename doc/sphinx/{ => rules}/payload-keywords.rst (100%) rename doc/sphinx/{ => rules}/payload-keywords/Legenda_rules.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/content.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/content2.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/content3.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/content4.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/content5.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/content6.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/distance.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/distance1.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/distance3.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/distance4.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/distance5.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/dsize.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/isdataat1.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/replace.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/replace1.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/rpc.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/within1.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/within2.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/within_distance.png (100%) rename doc/sphinx/{ => rules}/payload-keywords/within_distance2.png (100%) rename doc/sphinx/{ => rules}/pcre.rst (100%) rename doc/sphinx/{ => rules}/pcre/pcre.png (100%) rename doc/sphinx/{ => rules}/pcre/pcre3.png (100%) rename doc/sphinx/{ => rules}/pcre/pcre4.png (100%) rename doc/sphinx/{ => rules}/pcre/pcre5.png (100%) rename doc/sphinx/{ => rules}/pcre/pcre6.png (100%) rename doc/sphinx/{ => rules}/rule-lua-scripting.rst (100%) rename doc/sphinx/{ => rules}/rule-profiling.rst (100%) rename doc/sphinx/{ => rules}/thresholding.rst (100%) rename doc/sphinx/{ => rules}/tls-keywords.rst (100%) diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 40581d2bce35..9c75ba65217a 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -6,4 +6,4 @@ Suricata User Guide :titlesonly: what-is-suricata - rules + rules/index.rst diff --git a/doc/sphinx/adding-your-own-rules.rst b/doc/sphinx/rules/adding-your-own-rules.rst similarity index 100% rename from doc/sphinx/adding-your-own-rules.rst rename to doc/sphinx/rules/adding-your-own-rules.rst diff --git a/doc/sphinx/dnp3-keywords.rst b/doc/sphinx/rules/dnp3-keywords.rst similarity index 100% rename from doc/sphinx/dnp3-keywords.rst rename to doc/sphinx/rules/dnp3-keywords.rst diff --git a/doc/sphinx/dns-keywords.rst b/doc/sphinx/rules/dns-keywords.rst similarity index 100% rename from doc/sphinx/dns-keywords.rst rename to doc/sphinx/rules/dns-keywords.rst diff --git a/doc/sphinx/dns-keywords/dns_query.png b/doc/sphinx/rules/dns-keywords/dns_query.png similarity index 100% rename from doc/sphinx/dns-keywords/dns_query.png rename to doc/sphinx/rules/dns-keywords/dns_query.png diff --git a/doc/sphinx/fast-pattern-explained.rst b/doc/sphinx/rules/fast-pattern-explained.rst similarity index 100% rename from doc/sphinx/fast-pattern-explained.rst rename to doc/sphinx/rules/fast-pattern-explained.rst diff --git a/doc/sphinx/fast-pattern.rst b/doc/sphinx/rules/fast-pattern.rst similarity index 100% rename from doc/sphinx/fast-pattern.rst rename to doc/sphinx/rules/fast-pattern.rst diff --git a/doc/sphinx/fast-pattern/fast_pattern.png b/doc/sphinx/rules/fast-pattern/fast_pattern.png similarity index 100% rename from doc/sphinx/fast-pattern/fast_pattern.png rename to doc/sphinx/rules/fast-pattern/fast_pattern.png diff --git a/doc/sphinx/file-keywords.rst b/doc/sphinx/rules/file-keywords.rst similarity index 100% rename from doc/sphinx/file-keywords.rst rename to doc/sphinx/rules/file-keywords.rst diff --git a/doc/sphinx/flow-keywords.rst b/doc/sphinx/rules/flow-keywords.rst similarity index 100% rename from doc/sphinx/flow-keywords.rst rename to doc/sphinx/rules/flow-keywords.rst diff --git a/doc/sphinx/flow-keywords/Flow1.png b/doc/sphinx/rules/flow-keywords/Flow1.png similarity index 100% rename from doc/sphinx/flow-keywords/Flow1.png rename to doc/sphinx/rules/flow-keywords/Flow1.png diff --git a/doc/sphinx/flow-keywords/Flow2.png b/doc/sphinx/rules/flow-keywords/Flow2.png similarity index 100% rename from doc/sphinx/flow-keywords/Flow2.png rename to doc/sphinx/rules/flow-keywords/Flow2.png diff --git a/doc/sphinx/flow-keywords/Flowbit_3.png b/doc/sphinx/rules/flow-keywords/Flowbit_3.png similarity index 100% rename from doc/sphinx/flow-keywords/Flowbit_3.png rename to doc/sphinx/rules/flow-keywords/Flowbit_3.png diff --git a/doc/sphinx/flowint.rst b/doc/sphinx/rules/flowint.rst similarity index 100% rename from doc/sphinx/flowint.rst rename to doc/sphinx/rules/flowint.rst diff --git a/doc/sphinx/header-keywords.rst b/doc/sphinx/rules/header-keywords.rst similarity index 100% rename from doc/sphinx/header-keywords.rst rename to doc/sphinx/rules/header-keywords.rst diff --git a/doc/sphinx/header-keywords/ICMP_type_code.png b/doc/sphinx/rules/header-keywords/ICMP_type_code.png similarity index 100% rename from doc/sphinx/header-keywords/ICMP_type_code.png rename to doc/sphinx/rules/header-keywords/ICMP_type_code.png diff --git a/doc/sphinx/header-keywords/ICMP_types.png b/doc/sphinx/rules/header-keywords/ICMP_types.png similarity index 100% rename from doc/sphinx/header-keywords/ICMP_types.png rename to doc/sphinx/rules/header-keywords/ICMP_types.png diff --git a/doc/sphinx/header-keywords/Window.png b/doc/sphinx/rules/header-keywords/Window.png similarity index 100% rename from doc/sphinx/header-keywords/Window.png rename to doc/sphinx/rules/header-keywords/Window.png diff --git a/doc/sphinx/header-keywords/Wireshark_ack.png b/doc/sphinx/rules/header-keywords/Wireshark_ack.png similarity index 100% rename from doc/sphinx/header-keywords/Wireshark_ack.png rename to doc/sphinx/rules/header-keywords/Wireshark_ack.png diff --git a/doc/sphinx/header-keywords/Wireshark_seq.png b/doc/sphinx/rules/header-keywords/Wireshark_seq.png similarity index 100% rename from doc/sphinx/header-keywords/Wireshark_seq.png rename to doc/sphinx/rules/header-keywords/Wireshark_seq.png diff --git a/doc/sphinx/header-keywords/ack.png b/doc/sphinx/rules/header-keywords/ack.png similarity index 100% rename from doc/sphinx/header-keywords/ack.png rename to doc/sphinx/rules/header-keywords/ack.png diff --git a/doc/sphinx/header-keywords/fragbits.png b/doc/sphinx/rules/header-keywords/fragbits.png similarity index 100% rename from doc/sphinx/header-keywords/fragbits.png rename to doc/sphinx/rules/header-keywords/fragbits.png diff --git a/doc/sphinx/header-keywords/fragoffset.png b/doc/sphinx/rules/header-keywords/fragoffset.png similarity index 100% rename from doc/sphinx/header-keywords/fragoffset.png rename to doc/sphinx/rules/header-keywords/fragoffset.png diff --git a/doc/sphinx/header-keywords/icmp_id.png b/doc/sphinx/rules/header-keywords/icmp_id.png similarity index 100% rename from doc/sphinx/header-keywords/icmp_id.png rename to doc/sphinx/rules/header-keywords/icmp_id.png diff --git a/doc/sphinx/header-keywords/icmp_seq.png b/doc/sphinx/rules/header-keywords/icmp_seq.png similarity index 100% rename from doc/sphinx/header-keywords/icmp_seq.png rename to doc/sphinx/rules/header-keywords/icmp_seq.png diff --git a/doc/sphinx/header-keywords/icmp_type.png b/doc/sphinx/rules/header-keywords/icmp_type.png similarity index 100% rename from doc/sphinx/header-keywords/icmp_type.png rename to doc/sphinx/rules/header-keywords/icmp_type.png diff --git a/doc/sphinx/header-keywords/icode.png b/doc/sphinx/rules/header-keywords/icode.png similarity index 100% rename from doc/sphinx/header-keywords/icode.png rename to doc/sphinx/rules/header-keywords/icode.png diff --git a/doc/sphinx/header-keywords/id.png b/doc/sphinx/rules/header-keywords/id.png similarity index 100% rename from doc/sphinx/header-keywords/id.png rename to doc/sphinx/rules/header-keywords/id.png diff --git a/doc/sphinx/header-keywords/ip_proto.png b/doc/sphinx/rules/header-keywords/ip_proto.png similarity index 100% rename from doc/sphinx/header-keywords/ip_proto.png rename to doc/sphinx/rules/header-keywords/ip_proto.png diff --git a/doc/sphinx/header-keywords/ipopts.png b/doc/sphinx/rules/header-keywords/ipopts.png similarity index 100% rename from doc/sphinx/header-keywords/ipopts.png rename to doc/sphinx/rules/header-keywords/ipopts.png diff --git a/doc/sphinx/header-keywords/ipopts_rule.png b/doc/sphinx/rules/header-keywords/ipopts_rule.png similarity index 100% rename from doc/sphinx/header-keywords/ipopts_rule.png rename to doc/sphinx/rules/header-keywords/ipopts_rule.png diff --git a/doc/sphinx/header-keywords/sameip.png b/doc/sphinx/rules/header-keywords/sameip.png similarity index 100% rename from doc/sphinx/header-keywords/sameip.png rename to doc/sphinx/rules/header-keywords/sameip.png diff --git a/doc/sphinx/header-keywords/seq.png b/doc/sphinx/rules/header-keywords/seq.png similarity index 100% rename from doc/sphinx/header-keywords/seq.png rename to doc/sphinx/rules/header-keywords/seq.png diff --git a/doc/sphinx/header-keywords/ttl.png b/doc/sphinx/rules/header-keywords/ttl.png similarity index 100% rename from doc/sphinx/header-keywords/ttl.png rename to doc/sphinx/rules/header-keywords/ttl.png diff --git a/doc/sphinx/http-keywords.rst b/doc/sphinx/rules/http-keywords.rst similarity index 100% rename from doc/sphinx/http-keywords.rst rename to doc/sphinx/rules/http-keywords.rst diff --git a/doc/sphinx/http-keywords/Legenda_rules.png b/doc/sphinx/rules/http-keywords/Legenda_rules.png similarity index 100% rename from doc/sphinx/http-keywords/Legenda_rules.png rename to doc/sphinx/rules/http-keywords/Legenda_rules.png diff --git a/doc/sphinx/http-keywords/client_body.png b/doc/sphinx/rules/http-keywords/client_body.png similarity index 100% rename from doc/sphinx/http-keywords/client_body.png rename to doc/sphinx/rules/http-keywords/client_body.png diff --git a/doc/sphinx/http-keywords/client_body1.png b/doc/sphinx/rules/http-keywords/client_body1.png similarity index 100% rename from doc/sphinx/http-keywords/client_body1.png rename to doc/sphinx/rules/http-keywords/client_body1.png diff --git a/doc/sphinx/http-keywords/cookie.png b/doc/sphinx/rules/http-keywords/cookie.png similarity index 100% rename from doc/sphinx/http-keywords/cookie.png rename to doc/sphinx/rules/http-keywords/cookie.png diff --git a/doc/sphinx/http-keywords/cookie1.png b/doc/sphinx/rules/http-keywords/cookie1.png similarity index 100% rename from doc/sphinx/http-keywords/cookie1.png rename to doc/sphinx/rules/http-keywords/cookie1.png diff --git a/doc/sphinx/http-keywords/fast_pattern.png b/doc/sphinx/rules/http-keywords/fast_pattern.png similarity index 100% rename from doc/sphinx/http-keywords/fast_pattern.png rename to doc/sphinx/rules/http-keywords/fast_pattern.png diff --git a/doc/sphinx/http-keywords/file_data.png b/doc/sphinx/rules/http-keywords/file_data.png similarity index 100% rename from doc/sphinx/http-keywords/file_data.png rename to doc/sphinx/rules/http-keywords/file_data.png diff --git a/doc/sphinx/http-keywords/header.png b/doc/sphinx/rules/http-keywords/header.png similarity index 100% rename from doc/sphinx/http-keywords/header.png rename to doc/sphinx/rules/http-keywords/header.png diff --git a/doc/sphinx/http-keywords/header1.png b/doc/sphinx/rules/http-keywords/header1.png similarity index 100% rename from doc/sphinx/http-keywords/header1.png rename to doc/sphinx/rules/http-keywords/header1.png diff --git a/doc/sphinx/http-keywords/http_server_body.png b/doc/sphinx/rules/http-keywords/http_server_body.png similarity index 100% rename from doc/sphinx/http-keywords/http_server_body.png rename to doc/sphinx/rules/http-keywords/http_server_body.png diff --git a/doc/sphinx/http-keywords/http_uri.png b/doc/sphinx/rules/http-keywords/http_uri.png similarity index 100% rename from doc/sphinx/http-keywords/http_uri.png rename to doc/sphinx/rules/http-keywords/http_uri.png diff --git a/doc/sphinx/http-keywords/method.png b/doc/sphinx/rules/http-keywords/method.png similarity index 100% rename from doc/sphinx/http-keywords/method.png rename to doc/sphinx/rules/http-keywords/method.png diff --git a/doc/sphinx/http-keywords/method1.png b/doc/sphinx/rules/http-keywords/method1.png similarity index 100% rename from doc/sphinx/http-keywords/method1.png rename to doc/sphinx/rules/http-keywords/method1.png diff --git a/doc/sphinx/http-keywords/method2.png b/doc/sphinx/rules/http-keywords/method2.png similarity index 100% rename from doc/sphinx/http-keywords/method2.png rename to doc/sphinx/rules/http-keywords/method2.png diff --git a/doc/sphinx/http-keywords/request.png b/doc/sphinx/rules/http-keywords/request.png similarity index 100% rename from doc/sphinx/http-keywords/request.png rename to doc/sphinx/rules/http-keywords/request.png diff --git a/doc/sphinx/http-keywords/request2.png b/doc/sphinx/rules/http-keywords/request2.png similarity index 100% rename from doc/sphinx/http-keywords/request2.png rename to doc/sphinx/rules/http-keywords/request2.png diff --git a/doc/sphinx/http-keywords/response1.png b/doc/sphinx/rules/http-keywords/response1.png similarity index 100% rename from doc/sphinx/http-keywords/response1.png rename to doc/sphinx/rules/http-keywords/response1.png diff --git a/doc/sphinx/http-keywords/stat-code1.png b/doc/sphinx/rules/http-keywords/stat-code1.png similarity index 100% rename from doc/sphinx/http-keywords/stat-code1.png rename to doc/sphinx/rules/http-keywords/stat-code1.png diff --git a/doc/sphinx/http-keywords/stat_code.png b/doc/sphinx/rules/http-keywords/stat_code.png similarity index 100% rename from doc/sphinx/http-keywords/stat_code.png rename to doc/sphinx/rules/http-keywords/stat_code.png diff --git a/doc/sphinx/http-keywords/stat_msg.png b/doc/sphinx/rules/http-keywords/stat_msg.png similarity index 100% rename from doc/sphinx/http-keywords/stat_msg.png rename to doc/sphinx/rules/http-keywords/stat_msg.png diff --git a/doc/sphinx/http-keywords/stat_msg_1.png b/doc/sphinx/rules/http-keywords/stat_msg_1.png similarity index 100% rename from doc/sphinx/http-keywords/stat_msg_1.png rename to doc/sphinx/rules/http-keywords/stat_msg_1.png diff --git a/doc/sphinx/http-keywords/uri.png b/doc/sphinx/rules/http-keywords/uri.png similarity index 100% rename from doc/sphinx/http-keywords/uri.png rename to doc/sphinx/rules/http-keywords/uri.png diff --git a/doc/sphinx/http-keywords/uri1.png b/doc/sphinx/rules/http-keywords/uri1.png similarity index 100% rename from doc/sphinx/http-keywords/uri1.png rename to doc/sphinx/rules/http-keywords/uri1.png diff --git a/doc/sphinx/http-keywords/uricontent.png b/doc/sphinx/rules/http-keywords/uricontent.png similarity index 100% rename from doc/sphinx/http-keywords/uricontent.png rename to doc/sphinx/rules/http-keywords/uricontent.png diff --git a/doc/sphinx/http-keywords/uricontent1.png b/doc/sphinx/rules/http-keywords/uricontent1.png similarity index 100% rename from doc/sphinx/http-keywords/uricontent1.png rename to doc/sphinx/rules/http-keywords/uricontent1.png diff --git a/doc/sphinx/http-keywords/urilen.png b/doc/sphinx/rules/http-keywords/urilen.png similarity index 100% rename from doc/sphinx/http-keywords/urilen.png rename to doc/sphinx/rules/http-keywords/urilen.png diff --git a/doc/sphinx/http-keywords/urilen1.png b/doc/sphinx/rules/http-keywords/urilen1.png similarity index 100% rename from doc/sphinx/http-keywords/urilen1.png rename to doc/sphinx/rules/http-keywords/urilen1.png diff --git a/doc/sphinx/http-keywords/user_agent.png b/doc/sphinx/rules/http-keywords/user_agent.png similarity index 100% rename from doc/sphinx/http-keywords/user_agent.png rename to doc/sphinx/rules/http-keywords/user_agent.png diff --git a/doc/sphinx/http-keywords/user_agent_match.png b/doc/sphinx/rules/http-keywords/user_agent_match.png similarity index 100% rename from doc/sphinx/http-keywords/user_agent_match.png rename to doc/sphinx/rules/http-keywords/user_agent_match.png diff --git a/doc/sphinx/rules.rst b/doc/sphinx/rules/index.rst similarity index 95% rename from doc/sphinx/rules.rst rename to doc/sphinx/rules/index.rst index 8b5f5e95eee3..6f73db0cf62f 100644 --- a/doc/sphinx/rules.rst +++ b/doc/sphinx/rules/index.rst @@ -3,7 +3,7 @@ Suricata Rules .. toctree:: - rules-intro + intro meta header-keywords payload-keywords @@ -21,4 +21,3 @@ Suricata Rules rule-profiling modbus-keyword dnp3-keywords - diff --git a/doc/sphinx/rules-intro.rst b/doc/sphinx/rules/intro.rst similarity index 94% rename from doc/sphinx/rules-intro.rst rename to doc/sphinx/rules/intro.rst index 960da6994a89..e834c31e5901 100644 --- a/doc/sphinx/rules-intro.rst +++ b/doc/sphinx/rules/intro.rst @@ -17,7 +17,7 @@ A rule/signature consists of the following: Example of a signature: -.. image:: rules/intro_sig.png +.. image:: intro/intro_sig.png Action ------ @@ -27,7 +27,7 @@ For more information read 'Action Order' in the Example: -.. image:: rules/action.png +.. image:: intro/action.png In this example the red, bold-faced part is the action. @@ -45,7 +45,7 @@ match if it concerns http-traffic. Example: -.. image:: rules/protocol.png +.. image:: intro/protocol.png In this example the red, bold-faced part is the protocol. @@ -83,11 +83,11 @@ You can not write a signature using EXTERNAL_NET because it stands for Example of source and destination in a signature: -.. image:: rules/Source.png +.. image:: intro/Source.png The red, bold-faced part is the source. -.. image:: rules/destination.png +.. image:: intro/destination.png The red, bold-faced part is the destination. @@ -120,10 +120,10 @@ Example:: Example of ports in a signature: -.. image:: rules/Source-port.png +.. image:: intro/Source-port.png -.. image:: rules/Dest_port.png +.. image:: intro/Dest_port.png In this example, the red, bold-faced part is the port. @@ -145,14 +145,14 @@ Example:: Example 1 tcp-session -.. image:: rules/TCP-session.png +.. image:: intro/TCP-session.png In this example there will only be a match if the signature has the same order/direction as the payload. Example of direction in a signature: -.. image:: rules/Direction.png +.. image:: intro/Direction.png In this example the red, bold-faced part is the direction. diff --git a/doc/sphinx/rules/Dest_port.png b/doc/sphinx/rules/intro/Dest_port.png similarity index 100% rename from doc/sphinx/rules/Dest_port.png rename to doc/sphinx/rules/intro/Dest_port.png diff --git a/doc/sphinx/rules/Direction.png b/doc/sphinx/rules/intro/Direction.png similarity index 100% rename from doc/sphinx/rules/Direction.png rename to doc/sphinx/rules/intro/Direction.png diff --git a/doc/sphinx/rules/Source-port.png b/doc/sphinx/rules/intro/Source-port.png similarity index 100% rename from doc/sphinx/rules/Source-port.png rename to doc/sphinx/rules/intro/Source-port.png diff --git a/doc/sphinx/rules/Source.png b/doc/sphinx/rules/intro/Source.png similarity index 100% rename from doc/sphinx/rules/Source.png rename to doc/sphinx/rules/intro/Source.png diff --git a/doc/sphinx/rules/TCP-session.png b/doc/sphinx/rules/intro/TCP-session.png similarity index 100% rename from doc/sphinx/rules/TCP-session.png rename to doc/sphinx/rules/intro/TCP-session.png diff --git a/doc/sphinx/rules/action.png b/doc/sphinx/rules/intro/action.png similarity index 100% rename from doc/sphinx/rules/action.png rename to doc/sphinx/rules/intro/action.png diff --git a/doc/sphinx/rules/destination.png b/doc/sphinx/rules/intro/destination.png similarity index 100% rename from doc/sphinx/rules/destination.png rename to doc/sphinx/rules/intro/destination.png diff --git a/doc/sphinx/rules/intro_sig.png b/doc/sphinx/rules/intro/intro_sig.png similarity index 100% rename from doc/sphinx/rules/intro_sig.png rename to doc/sphinx/rules/intro/intro_sig.png diff --git a/doc/sphinx/rules/protocol.png b/doc/sphinx/rules/intro/protocol.png similarity index 100% rename from doc/sphinx/rules/protocol.png rename to doc/sphinx/rules/intro/protocol.png diff --git a/doc/sphinx/live-rule-swap.rst b/doc/sphinx/rules/live-rule-swap.rst similarity index 100% rename from doc/sphinx/live-rule-swap.rst rename to doc/sphinx/rules/live-rule-swap.rst diff --git a/doc/sphinx/meta.rst b/doc/sphinx/rules/meta.rst similarity index 100% rename from doc/sphinx/meta.rst rename to doc/sphinx/rules/meta.rst diff --git a/doc/sphinx/meta/classification.png b/doc/sphinx/rules/meta/classification.png similarity index 100% rename from doc/sphinx/meta/classification.png rename to doc/sphinx/rules/meta/classification.png diff --git a/doc/sphinx/meta/classtype.png b/doc/sphinx/rules/meta/classtype.png similarity index 100% rename from doc/sphinx/meta/classtype.png rename to doc/sphinx/rules/meta/classtype.png diff --git a/doc/sphinx/meta/gid.png b/doc/sphinx/rules/meta/gid.png similarity index 100% rename from doc/sphinx/meta/gid.png rename to doc/sphinx/rules/meta/gid.png diff --git a/doc/sphinx/meta/msg.png b/doc/sphinx/rules/meta/msg.png similarity index 100% rename from doc/sphinx/meta/msg.png rename to doc/sphinx/rules/meta/msg.png diff --git a/doc/sphinx/meta/reference.png b/doc/sphinx/rules/meta/reference.png similarity index 100% rename from doc/sphinx/meta/reference.png rename to doc/sphinx/rules/meta/reference.png diff --git a/doc/sphinx/meta/rev.png b/doc/sphinx/rules/meta/rev.png similarity index 100% rename from doc/sphinx/meta/rev.png rename to doc/sphinx/rules/meta/rev.png diff --git a/doc/sphinx/meta/sid.png b/doc/sphinx/rules/meta/sid.png similarity index 100% rename from doc/sphinx/meta/sid.png rename to doc/sphinx/rules/meta/sid.png diff --git a/doc/sphinx/modbus-keyword.rst b/doc/sphinx/rules/modbus-keyword.rst similarity index 100% rename from doc/sphinx/modbus-keyword.rst rename to doc/sphinx/rules/modbus-keyword.rst diff --git a/doc/sphinx/normalized-buffers.rst b/doc/sphinx/rules/normalized-buffers.rst similarity index 100% rename from doc/sphinx/normalized-buffers.rst rename to doc/sphinx/rules/normalized-buffers.rst diff --git a/doc/sphinx/normalized-buffers/normalization1.png b/doc/sphinx/rules/normalized-buffers/normalization1.png similarity index 100% rename from doc/sphinx/normalized-buffers/normalization1.png rename to doc/sphinx/rules/normalized-buffers/normalization1.png diff --git a/doc/sphinx/payload-keywords.rst b/doc/sphinx/rules/payload-keywords.rst similarity index 100% rename from doc/sphinx/payload-keywords.rst rename to doc/sphinx/rules/payload-keywords.rst diff --git a/doc/sphinx/payload-keywords/Legenda_rules.png b/doc/sphinx/rules/payload-keywords/Legenda_rules.png similarity index 100% rename from doc/sphinx/payload-keywords/Legenda_rules.png rename to doc/sphinx/rules/payload-keywords/Legenda_rules.png diff --git a/doc/sphinx/payload-keywords/content.png b/doc/sphinx/rules/payload-keywords/content.png similarity index 100% rename from doc/sphinx/payload-keywords/content.png rename to doc/sphinx/rules/payload-keywords/content.png diff --git a/doc/sphinx/payload-keywords/content2.png b/doc/sphinx/rules/payload-keywords/content2.png similarity index 100% rename from doc/sphinx/payload-keywords/content2.png rename to doc/sphinx/rules/payload-keywords/content2.png diff --git a/doc/sphinx/payload-keywords/content3.png b/doc/sphinx/rules/payload-keywords/content3.png similarity index 100% rename from doc/sphinx/payload-keywords/content3.png rename to doc/sphinx/rules/payload-keywords/content3.png diff --git a/doc/sphinx/payload-keywords/content4.png b/doc/sphinx/rules/payload-keywords/content4.png similarity index 100% rename from doc/sphinx/payload-keywords/content4.png rename to doc/sphinx/rules/payload-keywords/content4.png diff --git a/doc/sphinx/payload-keywords/content5.png b/doc/sphinx/rules/payload-keywords/content5.png similarity index 100% rename from doc/sphinx/payload-keywords/content5.png rename to doc/sphinx/rules/payload-keywords/content5.png diff --git a/doc/sphinx/payload-keywords/content6.png b/doc/sphinx/rules/payload-keywords/content6.png similarity index 100% rename from doc/sphinx/payload-keywords/content6.png rename to doc/sphinx/rules/payload-keywords/content6.png diff --git a/doc/sphinx/payload-keywords/distance.png b/doc/sphinx/rules/payload-keywords/distance.png similarity index 100% rename from doc/sphinx/payload-keywords/distance.png rename to doc/sphinx/rules/payload-keywords/distance.png diff --git a/doc/sphinx/payload-keywords/distance1.png b/doc/sphinx/rules/payload-keywords/distance1.png similarity index 100% rename from doc/sphinx/payload-keywords/distance1.png rename to doc/sphinx/rules/payload-keywords/distance1.png diff --git a/doc/sphinx/payload-keywords/distance3.png b/doc/sphinx/rules/payload-keywords/distance3.png similarity index 100% rename from doc/sphinx/payload-keywords/distance3.png rename to doc/sphinx/rules/payload-keywords/distance3.png diff --git a/doc/sphinx/payload-keywords/distance4.png b/doc/sphinx/rules/payload-keywords/distance4.png similarity index 100% rename from doc/sphinx/payload-keywords/distance4.png rename to doc/sphinx/rules/payload-keywords/distance4.png diff --git a/doc/sphinx/payload-keywords/distance5.png b/doc/sphinx/rules/payload-keywords/distance5.png similarity index 100% rename from doc/sphinx/payload-keywords/distance5.png rename to doc/sphinx/rules/payload-keywords/distance5.png diff --git a/doc/sphinx/payload-keywords/dsize.png b/doc/sphinx/rules/payload-keywords/dsize.png similarity index 100% rename from doc/sphinx/payload-keywords/dsize.png rename to doc/sphinx/rules/payload-keywords/dsize.png diff --git a/doc/sphinx/payload-keywords/isdataat1.png b/doc/sphinx/rules/payload-keywords/isdataat1.png similarity index 100% rename from doc/sphinx/payload-keywords/isdataat1.png rename to doc/sphinx/rules/payload-keywords/isdataat1.png diff --git a/doc/sphinx/payload-keywords/replace.png b/doc/sphinx/rules/payload-keywords/replace.png similarity index 100% rename from doc/sphinx/payload-keywords/replace.png rename to doc/sphinx/rules/payload-keywords/replace.png diff --git a/doc/sphinx/payload-keywords/replace1.png b/doc/sphinx/rules/payload-keywords/replace1.png similarity index 100% rename from doc/sphinx/payload-keywords/replace1.png rename to doc/sphinx/rules/payload-keywords/replace1.png diff --git a/doc/sphinx/payload-keywords/rpc.png b/doc/sphinx/rules/payload-keywords/rpc.png similarity index 100% rename from doc/sphinx/payload-keywords/rpc.png rename to doc/sphinx/rules/payload-keywords/rpc.png diff --git a/doc/sphinx/payload-keywords/within1.png b/doc/sphinx/rules/payload-keywords/within1.png similarity index 100% rename from doc/sphinx/payload-keywords/within1.png rename to doc/sphinx/rules/payload-keywords/within1.png diff --git a/doc/sphinx/payload-keywords/within2.png b/doc/sphinx/rules/payload-keywords/within2.png similarity index 100% rename from doc/sphinx/payload-keywords/within2.png rename to doc/sphinx/rules/payload-keywords/within2.png diff --git a/doc/sphinx/payload-keywords/within_distance.png b/doc/sphinx/rules/payload-keywords/within_distance.png similarity index 100% rename from doc/sphinx/payload-keywords/within_distance.png rename to doc/sphinx/rules/payload-keywords/within_distance.png diff --git a/doc/sphinx/payload-keywords/within_distance2.png b/doc/sphinx/rules/payload-keywords/within_distance2.png similarity index 100% rename from doc/sphinx/payload-keywords/within_distance2.png rename to doc/sphinx/rules/payload-keywords/within_distance2.png diff --git a/doc/sphinx/pcre.rst b/doc/sphinx/rules/pcre.rst similarity index 100% rename from doc/sphinx/pcre.rst rename to doc/sphinx/rules/pcre.rst diff --git a/doc/sphinx/pcre/pcre.png b/doc/sphinx/rules/pcre/pcre.png similarity index 100% rename from doc/sphinx/pcre/pcre.png rename to doc/sphinx/rules/pcre/pcre.png diff --git a/doc/sphinx/pcre/pcre3.png b/doc/sphinx/rules/pcre/pcre3.png similarity index 100% rename from doc/sphinx/pcre/pcre3.png rename to doc/sphinx/rules/pcre/pcre3.png diff --git a/doc/sphinx/pcre/pcre4.png b/doc/sphinx/rules/pcre/pcre4.png similarity index 100% rename from doc/sphinx/pcre/pcre4.png rename to doc/sphinx/rules/pcre/pcre4.png diff --git a/doc/sphinx/pcre/pcre5.png b/doc/sphinx/rules/pcre/pcre5.png similarity index 100% rename from doc/sphinx/pcre/pcre5.png rename to doc/sphinx/rules/pcre/pcre5.png diff --git a/doc/sphinx/pcre/pcre6.png b/doc/sphinx/rules/pcre/pcre6.png similarity index 100% rename from doc/sphinx/pcre/pcre6.png rename to doc/sphinx/rules/pcre/pcre6.png diff --git a/doc/sphinx/rule-lua-scripting.rst b/doc/sphinx/rules/rule-lua-scripting.rst similarity index 100% rename from doc/sphinx/rule-lua-scripting.rst rename to doc/sphinx/rules/rule-lua-scripting.rst diff --git a/doc/sphinx/rule-profiling.rst b/doc/sphinx/rules/rule-profiling.rst similarity index 100% rename from doc/sphinx/rule-profiling.rst rename to doc/sphinx/rules/rule-profiling.rst diff --git a/doc/sphinx/thresholding.rst b/doc/sphinx/rules/thresholding.rst similarity index 100% rename from doc/sphinx/thresholding.rst rename to doc/sphinx/rules/thresholding.rst diff --git a/doc/sphinx/tls-keywords.rst b/doc/sphinx/rules/tls-keywords.rst similarity index 100% rename from doc/sphinx/tls-keywords.rst rename to doc/sphinx/rules/tls-keywords.rst From 4f9f9c09ec96fb9d295aeabe7726431385fd1d44 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Sat, 5 Dec 2015 09:09:52 -0600 Subject: [PATCH 1783/2553] doc: command line options --- doc/sphinx/command-line-options.rst | 78 +++++++++++++++++++++++++++++ doc/sphinx/dropping-privileges.rst | 69 +++++++++++++++++++++++++ doc/sphinx/index.rst | 1 + 3 files changed, 148 insertions(+) create mode 100644 doc/sphinx/command-line-options.rst create mode 100644 doc/sphinx/dropping-privileges.rst diff --git a/doc/sphinx/command-line-options.rst b/doc/sphinx/command-line-options.rst new file mode 100644 index 000000000000..2857d5032ad3 --- /dev/null +++ b/doc/sphinx/command-line-options.rst @@ -0,0 +1,78 @@ +Command Line Options +==================== + +.. toctree:: + + dropping-privileges + +You can use command line options in two ways. Using only one line +followed by one character or using two lines followed by a word, like +this: + +:: + + -a + --long-option + +:: + + + -c The -c option the most important option. After -c you can enter the path to the location of + suricata.yaml. + + -i After the -i option you can enter the interface card you would like to use to sniff packets from. + It concerns sniffing packets with libpcap in the pcap live mode. + + -r After the -r option you can enter the path to the pcap-file in which packets are recorded. That way + you can inspect the packets in that file in the pcap/offline mode. + + -s With the -s option you can set a file with signatures, which will be loaded together with the rules + set in yaml. + + -l With the -l option you can set the default log directory. If you already have the default-log-dir set + in yaml, it will not be used by Suricata if you use the -l option. It will use the log dir that is set + with the -l + option. If you do not set a directory with the -l option, Suricata will use the directory that is set + in yaml. + + + -D Normally if you run Suricata on your console, it keeps your console occupied. You + can not use it for other purposes, and when you close the window, Suricata stops running. + If you run Suricata as deamon (using the -D option), it runs at the background and you will be able + to use the console for other tasks without disturbing the engine running. + + --list-app-layer-protos : list supported app layer protocols + + --list-keywords[=all|csv|] : list keywords implemented by the engine + + + --list-runmodes The option --list-runmodes lists all possible runmodes. + + --runmode (in combination with the command line opion -i or -r) + With the --runmode option you can + set the runmode that you would like to use. This command line option can override the + yaml runmode option. For more information about runmodes see: [[Runmodes]]. + + +Unit Tests +~~~~~~~~~~ + +:: + + -u With the -u option you can run unit tests to test Suricata's code. + + -U With the -U option you can select which of the unit tests you want to run. This option uses REGEX. + Example of use: + suricata -u -U http + + --list-unittests The --list-unittests option shows a list with all possible unit tests. + + --fatal-unittests With the --fatal-unittests option you can run unit tests but it will stop immediately after one test fails + so you can see directly where it went wrong. + +PF_RING options +~~~~~~~~~~~~~~~ + +In order to use PF_RING-enabled libpcap, you must start suricata with +the --pfring-int= switch or it will not invoke the PF_RING +enhancements in libpcap. diff --git a/doc/sphinx/dropping-privileges.rst b/doc/sphinx/dropping-privileges.rst new file mode 100644 index 000000000000..6edfa36a1168 --- /dev/null +++ b/doc/sphinx/dropping-privileges.rst @@ -0,0 +1,69 @@ +Dropping Privileges After Startup +================================= + +Currently, libcap-ng is needed for dropping privileges on Suricata +after startup. For libcap, see status of feature request number #276 +-- Libcap support for dropping privileges. + +Download the current version of libcap-ng from upstream, see also +http://people.redhat.com/sgrubb/libcap-ng/ChangeLog + +:: + + wget http://people.redhat.com/sgrubb/libcap-ng/libcap-ng-0.7.4.tar.gz + tar -xzvf libcap-ng-0.7.4.tar.gz + cd libcap-ng-0.7.4 + ./configure + make + make install + +Download, configure, compile, and install Suricata for your particular +setup. See [[**FIXME** Suricata Installation]] Depending on your environment, +you may need to add the --with-libpcap_ng-libraries and +--with-libpcap_ng-includes options during the configure step. e.g: + +:: + + ./configure --with-libcap_ng-libraries=/usr/local/lib \ + --with-libcap_ng-includes=/usr/local/include + +Now, when you run Suricata, tell it what user and/or group you want it +to run as after startup with the --user and --group options. +e.g. (this assumes a 'suri' user and group): + +:: + + /usr/local/bin/suricata -c /etc/suricata/suricata.yaml \ + -D -i eth0 --user=suri --group=suri + +You will also want to make sure your user/group permissions are set so +suricata can still write to its log files which are usually located in +/var/log/suricata. + +:: + + mkdir -p /var/log/suricata + chown -R root:suri /var/log/suricata + chmod -R 775 /var/log/suricata + +If you rely on the pid files be aware that as of version 1.4.x +Suricata writes the pid file before it switches uids. This means that +the pid file will be owned by root and will not be readable by the +alternative uid. If this is an issue for you then a work around is to +set the sgid bit on the directory that the pid file will be created +in. This will cause all files in this directory to inherit the gid +from the parent directory rather than the creating process. + +:: + + chmod g+s ~sensors/sensor1/run + + ls -ld ~sensors/sensor1/run + drwxr-sr-x 2 sensors sensors 4096 Aug 9 09:20 ~sensors/sensor1/run + +and so after running suricata we get + +:: + + ls -ld ~sensors/sensor1/run/suricata.pid + -rw-r----- 1 root sensors 6 Aug 9 09:20 ~sensors/sensor1/run/suricata.pid diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 9c75ba65217a..bbfbfb7d418d 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -6,4 +6,5 @@ Suricata User Guide :titlesonly: what-is-suricata + command-line-options rules/index.rst From 5e0c39be57fc4e69c6e25d3a54cd1657fde86bbf Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Sat, 5 Dec 2015 11:38:56 -0600 Subject: [PATCH 1784/2553] doc: snort compatibility --- doc/sphinx/conf.py | 10 +++- doc/sphinx/index.rst | 1 + doc/sphinx/rules/adding-your-own-rules.rst | 2 +- doc/sphinx/snort-compatibility.rst | 66 ++++++++++++++++++++++ 4 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 doc/sphinx/snort-compatibility.rst diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py index 6cd7f0cf4d96..6224fe72c14f 100644 --- a/doc/sphinx/conf.py +++ b/doc/sphinx/conf.py @@ -16,6 +16,8 @@ import os import shlex +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. @@ -108,8 +110,12 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -#html_theme = 'alabaster' -html_theme = 'sphinx_rtd_theme' +if not on_rtd: + #html_theme = 'alabaster' + html_theme = 'sphinx_rtd_theme' + #html_theme = 'classic' + #html_theme = 'default' + #html_theme = 'nature' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index bbfbfb7d418d..9519597007bf 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -7,4 +7,5 @@ Suricata User Guide what-is-suricata command-line-options + snort-compatibility rules/index.rst diff --git a/doc/sphinx/rules/adding-your-own-rules.rst b/doc/sphinx/rules/adding-your-own-rules.rst index cbf99b6d80fc..2b2aa5ce2101 100644 --- a/doc/sphinx/rules/adding-your-own-rules.rst +++ b/doc/sphinx/rules/adding-your-own-rules.rst @@ -11,7 +11,7 @@ your console: sudo nano local.rules -Write your rule, see :doc:`rules` and save it. +Write your rule, see :doc:`intro` and save it. Open yaml diff --git a/doc/sphinx/snort-compatibility.rst b/doc/sphinx/snort-compatibility.rst new file mode 100644 index 000000000000..cc9e4e2bb969 --- /dev/null +++ b/doc/sphinx/snort-compatibility.rst @@ -0,0 +1,66 @@ +Snort Compatibility +=================== + +.. contents:: + +Keyword: content +---------------- + +*Versions affected: All versions prior to 3.0.* + +Prior to Suricata 3.0, the argument provided to the content keyword +cannot be longer than 255 characters like it can in Snort. + +Suricata 3.0 and newer can accept content arguments longer than 255 +characters. + +See: + +* https://redmine.openinfosecfoundation.org/issues/1281 +* https://github.com/inliniac/suricata/pull/1475 + +Keyword: urilen +--------------- + +*Versions affected: all* + +In Snort the urilen range is inclusive, in Suricata it is not. + +Example:: + + urilen:5<>10 + +In Snort the above will match URIs that are greater than and equal to +5 and less than and equal to 10. *Note that this is not what is +documented in the Snort manual.* + +In Suricata the above will match URIs that are greater than 5 and less +than 10, so it will only mathch URIs that are 6, 7, 8, and 9 bytes +long. + +See: + +* https://redmine.openinfosecfoundation.org/issues/1416 + +Keyword: isdataat +----------------- + +*Versions affected: all* + +``isdataat`` is off by one from Snort. In Snort the offset starts at 0 +where Suricata starts at 1. + +Keyword: flowbits +----------------- + +*Versions affected: all prior to 2.0.9* + +Versions of Suricata prior to 2.0.9 treated leading and trailing +whitespace in flowbit names as part of the flowbit name where Snort +does not. + +This was fixed in Suricata 2.0.9. + +See: + +* https://redmine.openinfosecfoundation.org/issues/1481 From 6136ec583f105fc95913b443a5ef2d8001acaba6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 17 Dec 2015 10:38:48 -0600 Subject: [PATCH 1785/2553] doc: oinkmaster --- doc/sphinx/index.rst | 1 + doc/sphinx/oinkmaster.rst | 187 +++++++++++++++++++++++ doc/sphinx/oinkmaster/oinkmasterconf.png | Bin 0 -> 154852 bytes doc/sphinx/oinkmaster/suricata_yaml.png | Bin 0 -> 90428 bytes 4 files changed, 188 insertions(+) create mode 100644 doc/sphinx/oinkmaster.rst create mode 100644 doc/sphinx/oinkmaster/oinkmasterconf.png create mode 100644 doc/sphinx/oinkmaster/suricata_yaml.png diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 9519597007bf..9c46f0ee1e8e 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -9,3 +9,4 @@ Suricata User Guide command-line-options snort-compatibility rules/index.rst + oinkmaster diff --git a/doc/sphinx/oinkmaster.rst b/doc/sphinx/oinkmaster.rst new file mode 100644 index 000000000000..55e8a85f57bd --- /dev/null +++ b/doc/sphinx/oinkmaster.rst @@ -0,0 +1,187 @@ +Rule Management with Oinkmaster +=============================== + + +It is possible to download and install rules manually, but there is a +much easier and quicker way to do so. There are special programs which +you can use for downloading and installing rules. There is for example +`Pulled Pork `_ and +`Oinkmaster `_. In this documentation +the use of Oinkmaster will be described. + +To install Oinkmaster, enter: + +:: + + sudo apt-get install oinkmaster + +There are several rulesets. There is for example Emerging Threats (ET) +Emerging Threats Pro and VRT. In this example we are using Emerging +Threats. + +Oinkmaster has to know where the rules an be found. These rules can be found at: + +:: + + http://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz + +open oinkmaster.conf to add this link by entering: + +:: + + sudo nano /etc/oinkmaster.conf + +Place a # in front of the url that is already there and add the new url like this: + +.. image:: oinkmaster/oinkmasterconf.png + +(Close oinkmaster.conf by pressing ctrl x, followed by y and enter. ) + +The next step is to create a directory for the new rules. Enter: + +:: + + sudo mkdir /etc/suricata/rules + + +Next enter: + +:: + + cd /etc + sudo oinkmaster -C /etc/oinkmaster.conf -o /etc/suricata/rules + +In the new rules directory a classification.config and a +reference.config can be found. The directories of both have to be +added in the suricata.yaml file. Do so by entering: + +:: + + sudo nano /etc/suricata/suricata.yaml + +And add the new file locations instead of the file locations already +present, like this: + +.. image:: oinkmaster/suricata_yaml.png + +To see if everything works as pleased, run Suricata: + +:: + + suricata -c /etc/suricata/suricata.yaml -i wlan0 (or eth0) + +You will notice there are several rule-files Suricata tries to load, +but are not available. It is possible to disable those rule-sets in +suricata.yaml by deleting them or by putting a # in front of them. To +stop Suricata from running, press ctrl c. + +Emerging Threats contains more rules than loaded in Suricata. To see +which rules are available in your rules directory, enter: + +:: + + ls /etc/suricata/rules/*.rules + +Find those that are not yet present in suricata.yaml and add them in +yaml if desired. + +You can do so by entering : + +:: + + sudo nano /etc/suricata/suricata.yaml + +If you disable a rule in your rule file by putting a # in front of it, +it will be enabled again the next time you run Oinkmaster. You can +disable it through Oinkmaster instead, by entering the following: + +:: + + cd /etc/suricata/rules + +and find the sid of the rule(s) you want to disable. + +Subsequently enter: + +:: + + sudo nano /etc/oinkmaster.conf + +and go all the way to the end of the file. +Type there: + +:: + + disablesid 2010495 + +Instead of 2010495, type the sid of the rule you would like to +disable. It is also possible to disable multiple rules, by entering +their sids separated by a comma. + +If you run Oinkmaster again, you can see the amount of rules you have +disabled. You can also enable rules that are disabled by default. Do +so by entering: + +:: + + ls /etc/suricata/rules + +In this directory you can see several rule-sets +Enter for example: + +:: + + sudo nano /etc/suricata/rules/emerging-malware.rules + +In this file you can see which rules are enabled en which are not. +You can not enable them for the long-term just by simply removing +the #. Because each time you will run Oinkmaster, the rule will be +disabled again. Instead, look up the sid of the rule you want to +enable. Place the sid in the correct place of oinkmaster.config: + +:: + + sudo nano /etc/oinkmaster.conf + +do so by typing: + +:: + + enablesid: 2010495 + +Instead of 2010495, type the sid of the rule you would like to to +enable. It is also possible to enable multiple rules, by entering +their sids separated by a comma. + +In oinkmaster.conf you can modify rules. For example, if you use +Suricata as inline/IPS and you want to modify a rule that sends an +alert when it matches and you would like the rule to drop the packet +instead, you can do so by entering the following: + +:: + + sudo nano oinkmaster.conf + +At the part where you can modify rules, type: + +:: + + modifysid 2010495 “alert” | “drop” + +The sid 2010495 is an example. Type the sid of the rule you desire to +change, instead. + +Rerun Oinkmaster to notice the change. + +Updating your rules +~~~~~~~~~~~~~~~~~~~ + +If you have already downloaded a ruleset (in the way described in this +file), and you would like to update the rules, enter: + +:: + + sudo oinkmaster -C /etc/oinkmaster.conf -o /etc/suricata/rules + +It is recommended to update your rules frequently. Emerging Threats is +modified daily, VRT is updated weekly or multiple times a week. diff --git a/doc/sphinx/oinkmaster/oinkmasterconf.png b/doc/sphinx/oinkmaster/oinkmasterconf.png new file mode 100644 index 0000000000000000000000000000000000000000..6f8545519c68a88e0da1d14a3455960b3a6293d8 GIT binary patch literal 154852 zcmZU4WmFw8xAwt`YoS~3b00020l%%K<007Me06?iDKz~SP)E)&t5-58m2@ycm zPNK$kFMG&dxeZYD(k%Z@+xEf6h?n_On?o$s2PU`e#&QvSZ)>!xaUayknD}2ov z?ry^5ei#9yuw)3r2yYC&fldFL6~Wk1`j1Ei*q(r&oBZxj}Uf#ett$q z#)16*enpp#J3~LL?2~JcP_l?968_u&$yskl%o9kxe+=k!<^PRe7it~naFJ-Qqj(R_ zI!bO^eTQR1CzC=Dx!i;u+nCyDRY~=tA9Q}(ZOfKZJTz`XDy8YvG9|T(*_hFSJ?#KV1y$HBXosnm$fSe0Ys!h zbC|yNs*zHEcQ_K|NMGd1q0Kyq?S5ckTl{HQQQRzuEwTXSlpz5m$?#1gY6Uw7@fIHw zLkbeois;7@iys9lPiBQBjpZhPYSH~;56~&^NG@f6+2>_U4g!Rgk=~Cxh9FSv)c60n zn?Q@aM3PS#pD7KMwJN=q?PPkx$`!DDzcI{>e5xrK5s3Tu7;G*sx&u z`~1+&BYeFSoOa+TD+zW0Gq!{LQxNNm4{1_`$LRm&g#dAt<_fEj$pWyS6YcJEu>>H` z3kLNRzpC+3pqAJ9DlF1$quQ!k84aZOW?i~#>y5FCv~Z5s`CVRnt}MPp%0_I7V!RG2 z#eJyE7<`)%K3CYD!I&Fvr4^|N`NX8nYGBy5a)BS@QSqPO>tqz8B;$A7$|GEgYT$K1 z97(wUoW8N@@SVEc+sk4BcbF)tx<>BKP7*s!v-Z56 z5f{B^Enq}p2%Jq|x7~Qflsm~@nR-E|`$jLMseN)y_Y0)Lcrlel0`PI0CuV0ZM8)qm z+*pqI#S!4iGU;;qfu9r&D-ex=>JGwW`zvVU+WV(td2Amx7gDNATf;?$!eGyrgG zJ}_YbXqS*d-;+rE3&Dqnmt{t~^DZCNqznYeY36D`#%P-l5RKDUV)nlbS!B|A?3Z89 z4I0#{P_(UO0dCc-VpH0S8Zz(u>z}!53bt%L_OcagN=hRs$Pw~#)}J~SpO?Ix1jEVU(Psf(a#69n!|iNHbRa$ xmeBThV8#&9!rVSEwP58BV%xW*7_RfE>Zzdo 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 literal 0 HcmV?d00001 From ab69c93a28968d9e322d209090cf8cf9fc31d363 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 17 Dec 2015 10:53:59 -0600 Subject: [PATCH 1786/2553] doc: making sense of alerts --- doc/sphinx/index.rst | 1 + doc/sphinx/make-sense-alerts.rst | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 doc/sphinx/make-sense-alerts.rst diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 9c46f0ee1e8e..20d2000910e7 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -10,3 +10,4 @@ Suricata User Guide snort-compatibility rules/index.rst oinkmaster + make-sense-alerts diff --git a/doc/sphinx/make-sense-alerts.rst b/doc/sphinx/make-sense-alerts.rst new file mode 100644 index 000000000000..735b1f9aa911 --- /dev/null +++ b/doc/sphinx/make-sense-alerts.rst @@ -0,0 +1,77 @@ +Making sense out of Alerts +========================== + +When alert happens it's important to figure out what it means. Is it +serious? Relevant? A false positive? + +To find out more about the rule that fired, it's always a good idea to +look at the actual rule. + +The first thing to look at in a rule is the description that follows +the "msg" keyword. Lets consider an example: + +:: + + msg:"ET SCAN sipscan probe"; + +The "ET" indicates the rule came from the Emerging Threats +project. "SCAN" indicates the purpose of the rule is to match on some +form of scanning. Following that a more or less detailed description +is given. + +Most rules contain some pointers to more information in the form of +the "reference" keyword. + +Consider the following example rule: + +:: + + + alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS \ + (msg:"ET CURRENT_EVENTS Adobe 0day Shovelware"; \ + flow:established,to_server; content:"GET "; nocase; depth:4; \ + content:!"|0d 0a|Referer\:"; nocase; \ + uricontent:"/ppp/listdir.php?dir="; \ + pcre:"/\/[a-z]{2}\/[a-z]{4}01\/ppp\/listdir\.php\?dir=/U"; \ + classtype:trojan-activity; \ + reference:url,isc.sans.org/diary.html?storyid=7747; \ + reference:url,doc.emergingthreats.net/2010496; \ + reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/CURRENT_EVENTS/CURRENT_Adobe; \ + sid:2010496; rev:2;) + +In this rule the reference keyword indicates 3 url's to visit for more +information: + +:: + + isc.sans.org/diary.html?storyid=7747 + doc.emergingthreats.net/2010496 + www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/CURRENT_EVENTS/CURRENT_Adobe + +Some rules contain a reference like: "reference:cve,2009-3958;" should +allow you to find info about the specific CVE using your favourite +search engine. + +It's not always straight forward and sometimes not all of that +information is available publicly. Usually asking about it on the +signature support lists helps a lot then. + +For the Emerging Threats list this is: +http://lists.emergingthreats.net/mailman/listinfo/emerging-sigs + +For the VRT ruleset: +https://lists.sourceforge.net/lists/listinfo/snort-sigs + +In many cases, looking at just the alert and the packet that triggered +it won't be enough to be conclusive. When running an IDS engine like +Suricata, it's always recommended to combine it with full packet +capturing. Using tools like Sguil or Snorby, the full TCP session or +UDP flow can be inspected. + +For example, if a rule fired that indicates your web application is +attacked, looking at the full TCP session might reveal that the web +application replied with 404 not found. This will usually mean the +attack failed. Usually, not always. + +Obviously there is a lot more to Incidence Response, but this should +get you started. From 235498717127c369d349c8d2303cee1c53f8c3a9 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 17 Dec 2015 11:05:57 -0600 Subject: [PATCH 1787/2553] doc: high performance config --- doc/sphinx/index.rst | 1 + .../performance/high-performance-config.rst | 72 +++++++++++++++++++ doc/sphinx/performance/index.rst | 6 ++ 3 files changed, 79 insertions(+) create mode 100644 doc/sphinx/performance/high-performance-config.rst create mode 100644 doc/sphinx/performance/index.rst diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 20d2000910e7..19bc27e067a6 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -11,3 +11,4 @@ Suricata User Guide rules/index.rst oinkmaster make-sense-alerts + performance/index.rst diff --git a/doc/sphinx/performance/high-performance-config.rst b/doc/sphinx/performance/high-performance-config.rst new file mode 100644 index 000000000000..c67361fcbaf1 --- /dev/null +++ b/doc/sphinx/performance/high-performance-config.rst @@ -0,0 +1,72 @@ +High Performance Configuration +============================== + +If you have enough RAM, consider the following options in +suricata.yaml to off-load as much work from the CPU's as possible: + +:: + + detect-engine: + - profile: medium + - custom-values: + toclient-src-groups: 200 + toclient-dst-groups: 200 + toclient-sp-groups: 200 + toclient-dp-groups: 300 + toserver-src-groups: 200 + toserver-dst-groups: 400 + toserver-sp-groups: 200 + toserver-dp-groups: 200 + - sgh-mpm-context: auto + - inspection-recursion-limit: 3000 + +Be advised, however, that this will require >= 32 GB of RAM for even +modestly sized rule sets. Also be aware that having additional CPU's +available provides a greater performance boost than having more RAM +available. That is, it would be better to spend money on CPU's +instead of RAM when configuring a system. + +As a rough benchmark, in an HTTP-rich traffic stream, the full +Emerging Threats rule set will require roughly one CPU per 50 Mb/sec +of traffic when using "low" memory settings and using PF_RING to +ensure there are no traffic drops. + +Here are the build in values for LOW/MEDIUM/HIGH profiles: + +:: + + + ENGINE_PROFILE_LOW: + toclient-src-groups: 2 + toclient-dst-groups: 2 + toclient-sp-groups: 2 + toclient-dp-groups: 3 + toserver-src-groups: 2 + toserver-dst-groups: 4 + toserver-sp-groups: 2 + toserver-dp-groups: 25 + + ENGINE_PROFILE_HIGH: + toclient-src-groups: 15 + toclient-dst-groups: 15 + toclient-sp-groups: 15 + toclient-dp-groups: 20 + toserver-src-groups: 15 + toserver-dst-groups: 15 + toserver-sp-groups: 15 + toserver-dp-groups: 40 + +If not provided: + +:: + + + default and MEDIUM profiles: + toclient-src-groups: 4 + toclient-dst-groups: 4 + toclient-sp-groups: 4 + toclient-dp-groups: 6 + toserver-src-groups: 4 + toserver-dst-groups: 8 + toserver-sp-groups: 4 + toserver-dp-groups: 30 diff --git a/doc/sphinx/performance/index.rst b/doc/sphinx/performance/index.rst new file mode 100644 index 000000000000..d59442f1c6f4 --- /dev/null +++ b/doc/sphinx/performance/index.rst @@ -0,0 +1,6 @@ +Performance +=========== + +.. toctree:: + + high-performance-config From 2574415a2d39aff73827d6f1f1d308c8f9f73dc3 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 17 Dec 2015 11:07:21 -0600 Subject: [PATCH 1788/2553] doc: tuning considerations --- doc/sphinx/performance/index.rst | 1 + .../performance/tuning-considerations.rst | 55 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 doc/sphinx/performance/tuning-considerations.rst diff --git a/doc/sphinx/performance/index.rst b/doc/sphinx/performance/index.rst index d59442f1c6f4..252652f9eda4 100644 --- a/doc/sphinx/performance/index.rst +++ b/doc/sphinx/performance/index.rst @@ -4,3 +4,4 @@ Performance .. toctree:: high-performance-config + tuning-considerations diff --git a/doc/sphinx/performance/tuning-considerations.rst b/doc/sphinx/performance/tuning-considerations.rst new file mode 100644 index 000000000000..b94e92ff8bc6 --- /dev/null +++ b/doc/sphinx/performance/tuning-considerations.rst @@ -0,0 +1,55 @@ +Tuning Considerations +===================== + +Settings to check for optimal performance. + +max-pending-packets: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This setting controls the number simultaneous packets that the engine +can handle. Setting this higher generally keeps the threads more busy, +but setting it too high will lead to degradation. + +Suggested setting: 1000 or higher. Max is ~65000. + +mpm-algo: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Controls the pattern matcher algorithm. AC is the default and best +choice for most if not all cases. + +detect-engine.profile: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The detection engine tries to split out separate signatures into +groups so that a packet is only inspected against signatures that can +actually match. As in large rule set this would result in way too many +groups and memory usage similar groups are merged together. The +profile setting controls how aggressive this merging is done. Higher +is better but results in (much) higher memory usage. + +The "custom" setting allows modification of the group sizes: + +:: + + - custom-values: + toclient-src-groups: 2 + toclient-dst-groups: 2 + toclient-sp-groups: 2 + toclient-dp-groups: 3 + toserver-src-groups: 2 + toserver-dst-groups: 4 + toserver-sp-groups: 2 + toserver-dp-groups: 25 + +In general, increasing will improve performance, but will lead to +higher memory usage. + +detect-engine.sgh-mpm-context: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The multi pattern matcher can have it's context per signature group +(full) or globally (single). Auto selects between single and full +based on the **mpm-algo** selected. ac, ac-gfbs and ac-bs use +"single". All others "full". Setting this to "full" with AC requires a +lot of memory: 32GB+ for a reasonable rule set. From 7b8aa62463b4694d259bae8947ec3f55c20fdbd5 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 17 Dec 2015 11:10:16 -0600 Subject: [PATCH 1789/2553] doc: statistics --- doc/sphinx/performance/index.rst | 1 + doc/sphinx/performance/statistics.rst | 161 ++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 doc/sphinx/performance/statistics.rst diff --git a/doc/sphinx/performance/index.rst b/doc/sphinx/performance/index.rst index 252652f9eda4..532b61ad20ec 100644 --- a/doc/sphinx/performance/index.rst +++ b/doc/sphinx/performance/index.rst @@ -5,3 +5,4 @@ Performance high-performance-config tuning-considerations + statistics diff --git a/doc/sphinx/performance/statistics.rst b/doc/sphinx/performance/statistics.rst new file mode 100644 index 000000000000..c2f3a2570f73 --- /dev/null +++ b/doc/sphinx/performance/statistics.rst @@ -0,0 +1,161 @@ +Statistics +========== + +The stats.log produces statistics records on a fixed interval, by +default every 8 seconds. + +stats.log file +-------------- + +:: + + ------------------------------------------------------------------- + Counter | TM Name | Value + ------------------------------------------------------------------- + flow_mgr.closed_pruned | FlowManagerThread | 154033 + flow_mgr.new_pruned | FlowManagerThread | 67800 + flow_mgr.est_pruned | FlowManagerThread | 100921 + flow.memuse | FlowManagerThread | 6557568 + flow.spare | FlowManagerThread | 10002 + flow.emerg_mode_entered | FlowManagerThread | 0 + flow.emerg_mode_over | FlowManagerThread | 0 + decoder.pkts | RxPcapem21 | 450001754 + decoder.bytes | RxPcapem21 | 409520714250 + decoder.ipv4 | RxPcapem21 | 449584047 + decoder.ipv6 | RxPcapem21 | 9212 + decoder.ethernet | RxPcapem21 | 450001754 + decoder.raw | RxPcapem21 | 0 + decoder.sll | RxPcapem21 | 0 + decoder.tcp | RxPcapem21 | 448124337 + decoder.udp | RxPcapem21 | 542040 + decoder.sctp | RxPcapem21 | 0 + decoder.icmpv4 | RxPcapem21 | 82292 + decoder.icmpv6 | RxPcapem21 | 9164 + decoder.ppp | RxPcapem21 | 0 + decoder.pppoe | RxPcapem21 | 0 + decoder.gre | RxPcapem21 | 0 + decoder.vlan | RxPcapem21 | 0 + decoder.avg_pkt_size | RxPcapem21 | 910 + decoder.max_pkt_size | RxPcapem21 | 1514 + defrag.ipv4.fragments | RxPcapem21 | 4 + defrag.ipv4.reassembled | RxPcapem21 | 1 + defrag.ipv4.timeouts | RxPcapem21 | 0 + defrag.ipv6.fragments | RxPcapem21 | 0 + defrag.ipv6.reassembled | RxPcapem21 | 0 + defrag.ipv6.timeouts | RxPcapem21 | 0 + tcp.sessions | Detect | 41184 + tcp.ssn_memcap_drop | Detect | 0 + tcp.pseudo | Detect | 2087 + tcp.invalid_checksum | Detect | 8358 + tcp.no_flow | Detect | 0 + tcp.reused_ssn | Detect | 11 + tcp.memuse | Detect | 36175872 + tcp.syn | Detect | 85902 + tcp.synack | Detect | 83385 + tcp.rst | Detect | 84326 + tcp.segment_memcap_drop | Detect | 0 + tcp.stream_depth_reached | Detect | 109 + tcp.reassembly_memuse | Detect | 67755264 + tcp.reassembly_gap | Detect | 789 + detect.alert | Detect | 14721 + +Detecting packet loss +~~~~~~~~~~~~~~~~~~~~~ + +At shut down, Suricata reports the packet loss statistics it gets from +pcap, pfring or afpacket + +:: + + [18088] 30/5/2012 -- 07:39:18 - (RxPcapem21) Packets 451595939, bytes 410869083410 + [18088] 30/5/2012 -- 07:39:18 - (RxPcapem21) Pcap Total:451674222 Recv:451596129 Drop:78093 (0.0%). + +Usually, this is not the complete story though. These are kernel drop +stats, but the NIC may also have dropped packets. Use ethtool to get +to those: + +:: + + # ethtool -S em2 + NIC statistics: + rx_packets: 35430208463 + tx_packets: 216072 + rx_bytes: 32454370137414 + tx_bytes: 53624450 + rx_broadcast: 17424355 + tx_broadcast: 133508 + rx_multicast: 5332175 + tx_multicast: 82564 + rx_errors: 47 + tx_errors: 0 + tx_dropped: 0 + multicast: 5332175 + collisions: 0 + rx_length_errors: 0 + rx_over_errors: 0 + rx_crc_errors: 51 + rx_frame_errors: 0 + rx_no_buffer_count: 0 + rx_missed_errors: 0 + tx_aborted_errors: 0 + tx_carrier_errors: 0 + tx_fifo_errors: 0 + tx_heartbeat_errors: 0 + tx_window_errors: 0 + tx_abort_late_coll: 0 + tx_deferred_ok: 0 + tx_single_coll_ok: 0 + tx_multi_coll_ok: 0 + tx_timeout_count: 0 + tx_restart_queue: 0 + rx_long_length_errors: 0 + rx_short_length_errors: 0 + rx_align_errors: 0 + tx_tcp_seg_good: 0 + tx_tcp_seg_failed: 0 + rx_flow_control_xon: 0 + rx_flow_control_xoff: 0 + tx_flow_control_xon: 0 + tx_flow_control_xoff: 0 + rx_long_byte_count: 32454370137414 + rx_csum_offload_good: 35270755306 + rx_csum_offload_errors: 65076 + alloc_rx_buff_failed: 0 + tx_smbus: 0 + rx_smbus: 0 + dropped_smbus: 0 + +Kernel drops +------------ + +stats.log contains interesting information in the +capture.kernel_packets and capture.kernel_drops. The meaning of them +is different following the capture mode. + +In AF_PACKET mode: + +* kernel_packets is the number of packets correctly sent to userspace +* kernel_drops is the number of packets that have been discarded instead of being sent to userspace + +In PF_RING mode: + +* kernel_packets is the total number of packets seen by pf_ring +* kernel_drops is the number of packets that have been discarded instead of being sent to userspace + +In the Suricata stats.log the TCP data gap counter is also an +indicator, as it accounts missing data packets in TCP streams: + +:: + + tcp.reassembly_gap | Detect | 789 + +Ideally, this number is 0. Not only pkt loss affects it though, also +bad checksums and stream engine running out of memory. + +Tools to plot graphs +-------------------- + +Some people made nice tools to plot graphs of the statistics file. + +* `ipython and matplotlib script `_ +* `Monitoring with Zabbix or other `_ and `Code on Github `_ From fc9d6219219fd0af89dbc71e666078cb1d139957 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 17 Dec 2015 11:12:00 -0600 Subject: [PATCH 1790/2553] doc: packet profiling --- doc/sphinx/performance/index.rst | 1 + doc/sphinx/performance/packet-profiling.rst | 58 +++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 doc/sphinx/performance/packet-profiling.rst diff --git a/doc/sphinx/performance/index.rst b/doc/sphinx/performance/index.rst index 532b61ad20ec..23bd8fc5f68f 100644 --- a/doc/sphinx/performance/index.rst +++ b/doc/sphinx/performance/index.rst @@ -6,3 +6,4 @@ Performance high-performance-config tuning-considerations statistics + packet-profiling diff --git a/doc/sphinx/performance/packet-profiling.rst b/doc/sphinx/performance/packet-profiling.rst new file mode 100644 index 000000000000..f93deb6c04bb --- /dev/null +++ b/doc/sphinx/performance/packet-profiling.rst @@ -0,0 +1,58 @@ +Packet Profiling +================ + +In this guide will be explained how to enable packet profiling and use +it with the most recent code of Suricata on Ubuntu. It is based on the +assumption that you have already installed Suricata once from the GIT +repository. + +Packet profiling is convenient in case you would like to know how long +packets take to be processed. It is a way to figure out why certain +packets are being processed quicker than others, and this way a good +tool for developing Suricata. + +Update Suricata by following the steps from [[Installation from +Git]]. Start at the end at + +:: + + cd suricata/oisf + git pull + +And follow the described next steps. To enable packet profiling, make +sure you enter the following during the configuring stage: + +:: + + ./configure --enable-profiling + +Find a folder in which you have pcaps. If you do not have pcaps yet, +you can get these with Wireshark. See [[Sniffing Packets with +Wireshark]]. + +Go to the directory of your pcaps. For example: + +:: + + cd ~/Desktop + +With the ls command you can see the content of the folder. Choose a +folder and a pcap file + +for example: + +:: + + cd ~/Desktop/2011-05-05 + +Run Suricata with that pcap: + +:: + + suricata -c /etc/suricata/suricata.yaml -r log.pcap.(followed by the number/name of your pcap) + +for example: + +:: + + suricata -c /etc/suricata/suricata.yaml -r log.pcap.1304589204 From 38bf0df6f0c40c7e2d5529656ff23a0123a3c8ae Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 17 Dec 2015 11:14:15 -0600 Subject: [PATCH 1791/2553] doc: rule profiling --- doc/sphinx/performance/index.rst | 1 + doc/sphinx/performance/rule-profiling.rst | 33 +++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 doc/sphinx/performance/rule-profiling.rst diff --git a/doc/sphinx/performance/index.rst b/doc/sphinx/performance/index.rst index 23bd8fc5f68f..bfdf391048be 100644 --- a/doc/sphinx/performance/index.rst +++ b/doc/sphinx/performance/index.rst @@ -7,3 +7,4 @@ Performance tuning-considerations statistics packet-profiling + rule-profiling diff --git a/doc/sphinx/performance/rule-profiling.rst b/doc/sphinx/performance/rule-profiling.rst new file mode 100644 index 000000000000..f05e8fb4e482 --- /dev/null +++ b/doc/sphinx/performance/rule-profiling.rst @@ -0,0 +1,33 @@ +Rule Profiling +============== + +:: + + -------------------------------------------------------------------------- + Date: 9/5/2013 -- 14:59:58 + -------------------------------------------------------------------------- + Num Rule Gid Rev Ticks % Checks Matches Max Ticks Avg Ticks Avg Match Avg No Match + -------- ------------ -------- -------- ------------ ------ -------- -------- ----------- ----------- ----------- -------------- + 1 2210021 1 3 12037 4.96 1 1 12037 12037.00 12037.00 0.00 + 2 2210054 1 1 107479 44.26 12 0 35805 8956.58 0.00 8956.58 + 3 2210053 1 1 4513 1.86 1 0 4513 4513.00 0.00 4513.00 + 4 2210023 1 1 3077 1.27 1 0 3077 3077.00 0.00 3077.00 + 5 2210008 1 1 3028 1.25 1 0 3028 3028.00 0.00 3028.00 + 6 2210009 1 1 2945 1.21 1 0 2945 2945.00 0.00 2945.00 + 7 2210055 1 1 2945 1.21 1 0 2945 2945.00 0.00 2945.00 + 8 2210007 1 1 2871 1.18 1 0 2871 2871.00 0.00 2871.00 + 9 2210005 1 1 2871 1.18 1 0 2871 2871.00 0.00 2871.00 + 10 2210024 1 1 2846 1.17 1 0 2846 2846.00 0.00 2846.00 + +The meaning of the individual fields: + +* Ticks -- total ticks spent on this rule, so a sum of all inspections +* % -- share of this single sig in the total cost of inspection +* Checks -- number of times a signature was inspected +* Matches -- number of times it matched. This may not have resulted in an alert due to suppression and thresholding. +* Max ticks -- single most expensive inspection +* Avg ticks -- per inspection average, so "ticks" / "checks". +* Avg match -- avg ticks spent resulting in match +* Avg No Match -- avg ticks spent resulting in no match. + +The "ticks" are CPU clock ticks: http://en.wikipedia.org/wiki/CPU_time From f97c045bf11d4c579e44eed2a36bf533fc57c86a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 17 Dec 2015 11:18:04 -0600 Subject: [PATCH 1792/2553] doc: runmodes --- doc/sphinx/performance/index.rst | 1 + doc/sphinx/performance/runmodes.rst | 35 ++++++++++++++++++ .../performance/runmodes/Runmode_autofp.png | Bin 0 -> 51070 bytes .../performance/runmodes/threading1.png | Bin 0 -> 17080 bytes 4 files changed, 36 insertions(+) create mode 100644 doc/sphinx/performance/runmodes.rst create mode 100644 doc/sphinx/performance/runmodes/Runmode_autofp.png create mode 100644 doc/sphinx/performance/runmodes/threading1.png diff --git a/doc/sphinx/performance/index.rst b/doc/sphinx/performance/index.rst index bfdf391048be..d76b8082ccb3 100644 --- a/doc/sphinx/performance/index.rst +++ b/doc/sphinx/performance/index.rst @@ -8,3 +8,4 @@ Performance statistics packet-profiling rule-profiling + runmodes diff --git a/doc/sphinx/performance/runmodes.rst b/doc/sphinx/performance/runmodes.rst new file mode 100644 index 000000000000..0927501e12c3 --- /dev/null +++ b/doc/sphinx/performance/runmodes.rst @@ -0,0 +1,35 @@ +Runmodes +======== + +Suricata consists of several 'building blocks' called threads, +thread-modules and queues. A thread is like a process that runs on a +computer. Suricata is multi-threaded, so multiple threads are active +at once. A thread-module is a part of a functionality. One module is +for example for decoding a packet, another is the detect-module and +another one the output-module. A packet can be processed by more than +one thread. The packet will be passed on to the next thread through a +queue. Packets will be processed by one thread at a time, but there +can be multiple packets being processed at a time by the engine. (see +[[**FIXME** suricata.yaml#max-pending-packets]]) A thread can have one or more +thread-modules. If they have more modules, they can only be active on +a a time. The way threads, modules and queues are arranged together +is called the Runmode. + +Different runmodes +~~~~~~~~~~~~~~~~~~ + +You can choose a runmode out of several predefined runmodes. The +command line option --list-runmodes shows all available runmodes. All +runmodes have a name: auto, single, autofp. The heaviest task is the +detection; a packet will be checked against thousands of signatures. + +Example of the default runmode: + +.. image:: runmodes/threading1.png + +In the pfring mode, every flow follows its own fixed route in the runmode. + +.. image:: runmodes/Runmode_autofp.png + +For more information about the command line options concerning the +runmode, see :doc:`../command-line-options`. diff --git a/doc/sphinx/performance/runmodes/Runmode_autofp.png b/doc/sphinx/performance/runmodes/Runmode_autofp.png new file mode 100644 index 0000000000000000000000000000000000000000..42db21d731d500228dcf2ab80d0600fa08c3284d GIT binary patch literal 51070 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 B9f$w` literal 0 HcmV?d00001 diff --git a/doc/sphinx/performance/runmodes/threading1.png b/doc/sphinx/performance/runmodes/threading1.png new file mode 100644 index 0000000000000000000000000000000000000000..399bf67fcacad176dd27f775f280a7ad4592b9f8 GIT binary patch literal 17080 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 MxPn-fh+)uw0}i$;HUIzs literal 0 HcmV?d00001 From f27e85e346dfa2c8a2c7b46f872827b282672bb7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 17 Dec 2015 11:19:34 -0600 Subject: [PATCH 1793/2553] doc: tcmalloc --- doc/sphinx/performance/index.rst | 1 + doc/sphinx/performance/tcmalloc.rst | 39 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 doc/sphinx/performance/tcmalloc.rst diff --git a/doc/sphinx/performance/index.rst b/doc/sphinx/performance/index.rst index d76b8082ccb3..9fc1cd4af9ab 100644 --- a/doc/sphinx/performance/index.rst +++ b/doc/sphinx/performance/index.rst @@ -9,3 +9,4 @@ Performance packet-profiling rule-profiling runmodes + tcmalloc diff --git a/doc/sphinx/performance/tcmalloc.rst b/doc/sphinx/performance/tcmalloc.rst new file mode 100644 index 000000000000..3f3ea815d7be --- /dev/null +++ b/doc/sphinx/performance/tcmalloc.rst @@ -0,0 +1,39 @@ +Tcmalloc +======== + +‘tcmalloc’ is a library Google created as part of the google-perftools +suite for improving memory handling in a threaded program. It’s very +simple to use and does work fine with Suricata. It leads to minor +speed ups and also reduces memory usage quite a bit. + +Installation +~~~~~~~~~~~~ + +On Ubuntu, install the libtcmalloc-minimal0 package: + +:: + + apt-get install libtcmalloc-minimal0 + +On Fedora, install the gperftools-libs package: + +:: + + yum install gperftools-libs + +Usage +~~~~~ + +Use the tcmalloc by preloading it: + +Ubuntu: + +:: + + LD_PRELOAD=”/usr/lib/libtcmalloc_minimal.so.0" suricata -c suricata.yaml -i eth0 + +Fedora: + +:: + + LD_PRELOAD="/usr/lib64/libtcmalloc_minimal.so.4" suricata -c suricata.yaml -i eth0 From aa6a975f1c2f5ff5006e071f13f8ac5c1172df4e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 17 Dec 2015 11:25:08 -0600 Subject: [PATCH 1794/2553] doc: ignoring traffic --- doc/sphinx/performance/ignoring-traffic.rst | 46 +++++++++++++++++++++ doc/sphinx/performance/index.rst | 1 + 2 files changed, 47 insertions(+) create mode 100644 doc/sphinx/performance/ignoring-traffic.rst diff --git a/doc/sphinx/performance/ignoring-traffic.rst b/doc/sphinx/performance/ignoring-traffic.rst new file mode 100644 index 000000000000..6e6f0db9f501 --- /dev/null +++ b/doc/sphinx/performance/ignoring-traffic.rst @@ -0,0 +1,46 @@ +Ignoring Traffic +================ + +In some cases there are reasons to ignore certain traffic. Maybe a +trusted host or network, or a site. This document lists some +strategies for ignoring traffic. + +capture filters (BPF) +--------------------- + +Through BPFs the capture methods pcap, af-packet and pf_ring can be +told what to send to Suricata, and what not. For example a simple +filter 'tcp' will only send tcp packets. + +If some hosts and or nets need to be ignored, use something like "not +(host IP1 or IP2 or IP3 or net NET/24)". + +pass rules +---------- + +Pass rules are Suricata rules that if matching, pass the packet and in +case of TCP the rest of the flow. They look like normal rules, except +that instead of 'alert' or 'drop' they start with 'pass'. + +Example: + +:: + + pass ip 1.2.3.4 any <> any any (msg:"pass all traffic from/to 1.2.3.4"; sid:1;) + +A big difference with capture filters is that logs such as http.log +are still generated for this traffic. + +suppress +-------- + +Suppress rules can be used to make sure no alerts are generated for a +host. This is not efficient however, as the suppression is only +considered post-matching. In other words, Suricata first inspects a +rule, and only then will it consider per-host suppressions. + +Example: + +:: + + suppress gen_id 0, sig_id 0, track by_src, ip 1.2.3.4 diff --git a/doc/sphinx/performance/index.rst b/doc/sphinx/performance/index.rst index 9fc1cd4af9ab..b06bee6f5862 100644 --- a/doc/sphinx/performance/index.rst +++ b/doc/sphinx/performance/index.rst @@ -10,3 +10,4 @@ Performance rule-profiling runmodes tcmalloc + ignoring-traffic From 733f1a5842aa2f3244f7c54319e72c10d99a8539 Mon Sep 17 00:00:00 2001 From: Andi Date: Thu, 31 Dec 2015 21:58:22 +0100 Subject: [PATCH 1795/2553] doc: Document http_host and http_raw_host Added doc for http_host and http_raw_host as mentioned in https://redmine.openinfosecfoundation.org/issues/756 --- doc/sphinx/rules/http-keywords.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/sphinx/rules/http-keywords.rst b/doc/sphinx/rules/http-keywords.rst index 623a301a8a7f..afa72218c010 100644 --- a/doc/sphinx/rules/http-keywords.rst +++ b/doc/sphinx/rules/http-keywords.rst @@ -286,6 +286,19 @@ Note: how much of the response/server body is inspected is controlled in your [[**FIXME** suricata.yaml#Configure-Libhtp]], in the "libhtp" section, via the ``response-body-limit`` setting. +http_host and http_raw_host +---------------- + +With the ``http_host`` content modifier, it is possible to +match specifically and only the normalized hostname. +The ``http_raw_host`` inspects the raw hostname. + +The keyword can be used in combination with most of the content modifiers +like ``distance``, ``offset``, ``within``, etc. + +The ``nocase`` keyword ist not allowed anymore. Keep in mind that you need +to specify a lowercase pattern. + file_data --------- From 07dac046d9578c0664ce6b8ea019e1a382dd570f Mon Sep 17 00:00:00 2001 From: Andi Date: Thu, 31 Dec 2015 22:12:42 +0100 Subject: [PATCH 1796/2553] doc: Add ssl_state doc See https://redmine.openinfosecfoundation.org/issues/589 --- doc/sphinx/rules/tls-keywords.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/sphinx/rules/tls-keywords.rst b/doc/sphinx/rules/tls-keywords.rst index 5e891a68f64c..5ff137de4365 100644 --- a/doc/sphinx/rules/tls-keywords.rst +++ b/doc/sphinx/rules/tls-keywords.rst @@ -1,4 +1,4 @@ -TLS Keywords +SSL/TLS Keywords ============ Suricata comes with several rule keywords to match on various properties of TLS/SSL handshake. Matches are string inclusion matches. @@ -68,3 +68,12 @@ tls.store store TLS/SSL certificate on disk Support added in Suricata version 1.4. + +ssl_state +--------- + +The ``ssl_state`` keyword matches the state of the SSL connection. The possible states +are ``client_hello``, ``server_hello``, ``client_keyx``, ``server_keyx`` and ``unknown``. +You can specify several states with ``|`` (OR) to check for any of the specified states. + +Negation support is not available yet, see https://redmine.openinfosecfoundation.org/issues/1231 From ba27602babb9ffbf1e305789ee48eb37e8967fd6 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 00:46:13 +0100 Subject: [PATCH 1797/2553] doc: fixed underline too short error --- doc/sphinx/rules/http-keywords.rst | 2 +- doc/sphinx/rules/tls-keywords.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/sphinx/rules/http-keywords.rst b/doc/sphinx/rules/http-keywords.rst index afa72218c010..53aa36c11163 100644 --- a/doc/sphinx/rules/http-keywords.rst +++ b/doc/sphinx/rules/http-keywords.rst @@ -287,7 +287,7 @@ in your [[**FIXME** suricata.yaml#Configure-Libhtp]], in the "libhtp" section, via the ``response-body-limit`` setting. http_host and http_raw_host ----------------- +--------------------------- With the ``http_host`` content modifier, it is possible to match specifically and only the normalized hostname. diff --git a/doc/sphinx/rules/tls-keywords.rst b/doc/sphinx/rules/tls-keywords.rst index 5ff137de4365..3700c21395a6 100644 --- a/doc/sphinx/rules/tls-keywords.rst +++ b/doc/sphinx/rules/tls-keywords.rst @@ -1,5 +1,5 @@ SSL/TLS Keywords -============ +================ Suricata comes with several rule keywords to match on various properties of TLS/SSL handshake. Matches are string inclusion matches. From 630f3d3bc8c5dab83a83d6a94c5032114435c893 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 01:04:11 +0100 Subject: [PATCH 1798/2553] doc: added ip reputation --- .../ipreputation/ip-reputation-config.rst | 71 +++++++++++++++++++ .../ipreputation/ip-reputation-format.rst | 52 ++++++++++++++ .../ipreputation/ip-reputation-rules.rst | 43 +++++++++++ .../reputation/ipreputation/ip-reputation.rst | 15 ++++ 4 files changed, 181 insertions(+) create mode 100644 doc/sphinx/reputation/ipreputation/ip-reputation-config.rst create mode 100644 doc/sphinx/reputation/ipreputation/ip-reputation-format.rst create mode 100644 doc/sphinx/reputation/ipreputation/ip-reputation-rules.rst create mode 100644 doc/sphinx/reputation/ipreputation/ip-reputation.rst diff --git a/doc/sphinx/reputation/ipreputation/ip-reputation-config.rst b/doc/sphinx/reputation/ipreputation/ip-reputation-config.rst new file mode 100644 index 000000000000..9a4cde88fecf --- /dev/null +++ b/doc/sphinx/reputation/ipreputation/ip-reputation-config.rst @@ -0,0 +1,71 @@ +IP Reputation Config +==================== + +IP reputation has a few configuration directives, all disabled by default. + + +:: + + + # IP Reputation + #reputation-categories-file: /etc/suricata/iprep/categories.txt + #default-reputation-path: /etc/suricata/iprep + #reputation-files: + # - reputation.list + +reputation-categories-file +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The categories file mapping numbered category values to short names. + + +:: + + + reputation-categories-file: /etc/suricata/iprep/categories.txt + +default-reputation-path +~~~~~~~~~~~~~~~~~~~~~~~ + +Path where reputation files from the "reputation-files" directive are loaded from by default. + + +:: + + + default-reputation-path: /etc/suricata/iprep + +reputation-files +~~~~~~~~~~~~~~~~ + +YAML list of file names to load. In case of a absolute path the file is loaded directly, otherwise the path from "default-reputation-path" is pre-pended to form the final path. + + +:: + + + reputation-files: + - badhosts.list + - knowngood.list + - sharedhosting.list + +Hosts +~~~~~ + +IP reputation information is stored in the host table, so the settings of the host table affect it. + +Depending on the number of hosts reputation information is available for, the memcap and hash size may have to be increased. + +Reloads +~~~~~~~ + +If the "rule-reloads" option is enabled, sending Suricata a USR2 signal will reload the IP reputation data, along with the normal rules reload. + +During the reload the host table will be updated to contain the new data. The iprep information is versioned. When the reload is complete, Suricata will automatically clean up the old iprep information. + +Only the reputation files will be reloaded, the categories file won't be. If categories change, Suricata should be restarted. + +File format +~~~~~~~~~~~ + +The format of the reputation files is described in the :doc:`ip-reputation-format` page. diff --git a/doc/sphinx/reputation/ipreputation/ip-reputation-format.rst b/doc/sphinx/reputation/ipreputation/ip-reputation-format.rst new file mode 100644 index 000000000000..679d51189eb2 --- /dev/null +++ b/doc/sphinx/reputation/ipreputation/ip-reputation-format.rst @@ -0,0 +1,52 @@ +IP Reputation Format +==================== + +Description of IP Reputation file formats. For the configuration see :doc:`ip-reputation-config` and :doc:`ip-reputation-rules` for the rule format. + +Categories file +~~~~~~~~~~~~~~~ + +The categories file provides a mapping between a category number, short name and long description. It's a simple CSV file: + +:: + + + ,, + +Example: + +:: + + + 1,BadHosts,Known bad hosts + 2,Google,Known google host + +The maximum value for the category id is hard coded at 60 currently. + +Reputation file +~~~~~~~~~~~~~~~ + +The reputation file lists a reputation score for hosts in the categories. It's a simple CSV file: +> ,, + +The IP is an IPv4 address in the quad-dotted notation. The category is the number as defined in the categories file and the value is a number between 1 and 127. 0 means no data. + +Example: + +:: + + + 1.2.3.4,1,101 + 1.1.1.1,6,88 + +If an IP address has a score in multiple categories it should be listed in the file multiple times. + +Example: + +:: + + + 1.1.1.1,1,10 + 1.1.1.1,2,10 + +This lists 1.1.1.1 in categories 1 and 2, each with a score of 10. diff --git a/doc/sphinx/reputation/ipreputation/ip-reputation-rules.rst b/doc/sphinx/reputation/ipreputation/ip-reputation-rules.rst new file mode 100644 index 000000000000..1fcdfc5ee074 --- /dev/null +++ b/doc/sphinx/reputation/ipreputation/ip-reputation-rules.rst @@ -0,0 +1,43 @@ +IP Reputation Rules +=================== + +IP Reputation can be used in rules through a new rule directive "iprep". + +iprep +~~~~~ + +The iprep directive matches on the IP reputation information for a host. + +:: + + iprep:,,, + + +side to check: + +cat: the category short name + +operator: <, >, = + +value: 1-127 + +Example: + +:: + + + alert ip $HOME_NET any -> any any (msg:"IPREP internal host talking to CnC server"; flow:to_server; iprep:dst,CnC,>,30; sid:1; rev:1;) + +IP-only +~~~~~~~ + +The "iprep" keyword is compatible to "IP-only" rules. This means that a rule like: + +:: + + + alert ip any any -> any any (msg:"IPREP High Value CnC"; iprep:src,CnC,>,100; sid:1; rev:1;) + +will only be checked once per flow-direction. + +For more information about IP Reputation see :doc:`ip-reputation-config` and :doc:`ip-reputation-format`. diff --git a/doc/sphinx/reputation/ipreputation/ip-reputation.rst b/doc/sphinx/reputation/ipreputation/ip-reputation.rst new file mode 100644 index 000000000000..edfc69a65a69 --- /dev/null +++ b/doc/sphinx/reputation/ipreputation/ip-reputation.rst @@ -0,0 +1,15 @@ +IP Reputation +============= + +.. toctree:: + + ip-reputation-config + ip-reputation-rules + ip-reputation-format + +The purpose of the IP reputation component is the ranking of IP Addresses within the Suricata Engine. It will collect, store, update and distribute reputation intelligence on IP Addresses. The hub and spoke architecture will allows the central database (The Hub) to collect, store and compile updated IP reputation details that are then distributed to user-side sensor databases (Spokes) for inclusion in user security systems. The reputation data update frequency and security action taken, is defined in the user security configuration. + +The intent of IP Reputation is to allow sharing of intelligence regarding a vast number of IP addresses. This can be positive or negative intelligence classified into a number of categories. The technical implementation requires three major efforts; engine integration, the hub that redistributes reputation, and the communication protocol between hubs and sensors. The hub will have a number of responsibilities. This will be a separate module running on a separate system as any sensor. Most often it would run on a central database that all sensors already have communication with. It will be able to subscribe to one or more external feeds. The local admin should be able to define the feeds to be subscribed to, provide authentication credentials if required, and give a weight to that feed. The weight can be an overall number or a by category weight. This will allow the admin to minimize the influence a feed has on their overall reputation if they distrust a particular category or feed, or trust another implicitly. Feeds can be configured to accept feedback or not and will report so on connect. The admin can override and choose not to give any feedback, but the sensor should report these to the Hub upstream on connect. The hub will take all of these feeds and aggregate them into an average single score for each IP or IP Block, and then redistribute this data to all local sensors as configured. It should receive connections from sensors. The sensor will have to provide authentication and will provide feedback. The hub should redistribute that feedback from sensors to all other sensors as well as up to any feeds that accept feedback. The hub should also have an API to allow outside statistical analysis to be done to the database and fed back in to the stream. For instance a local site may choose to change the reputation on all Russian IP blocks, etc. + + +For more information about IP Reputation see :doc:`ip-reputation-config`, :doc:`ip-reputation-rules` and :doc:`ip-reputation-format`. From c04a60aaa0db8343e8bb863e1c9c2d47609c3d97 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 01:04:29 +0100 Subject: [PATCH 1799/2553] doc: added ip reputation --- doc/sphinx/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 19bc27e067a6..f48624b1b181 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -12,3 +12,4 @@ Suricata User Guide oinkmaster make-sense-alerts performance/index.rst + reputation/ipreputation/ip-reputation.rst From ae6c0af4921aeac953bd7cee165eb12c226ef266 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 01:05:13 +0100 Subject: [PATCH 1800/2553] doc: added initscripts --- doc/sphinx/index.rst | 1 + doc/sphinx/initscripts.rst | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 doc/sphinx/initscripts.rst diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index f48624b1b181..8105af199bea 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -13,3 +13,4 @@ Suricata User Guide make-sense-alerts performance/index.rst reputation/ipreputation/ip-reputation.rst + initscripts diff --git a/doc/sphinx/initscripts.rst b/doc/sphinx/initscripts.rst new file mode 100644 index 000000000000..a479df239247 --- /dev/null +++ b/doc/sphinx/initscripts.rst @@ -0,0 +1,15 @@ +Init Scripts +============ + +For Ubuntu with Upstart, the following can be used in /etc/init/suricata.conf: + + +:: + + + # suricata + description "Intruder Detection System Daemon" + start on runlevel [2345] + stop on runlevel [!2345] + expect fork + exec suricata -D --pidfile /var/run/suricata.pid -c /etc/suricata/suricata.yaml -i eth1 From d881f000f963904bd28a6590c7994cc6ed1c1138 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 01:22:42 +0100 Subject: [PATCH 1801/2553] doc: add index for reputation to match wiki --- doc/sphinx/index.rst | 2 +- doc/sphinx/reputation/index.rst | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 doc/sphinx/reputation/index.rst diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 8105af199bea..9b8194d7838e 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -12,5 +12,5 @@ Suricata User Guide oinkmaster make-sense-alerts performance/index.rst - reputation/ipreputation/ip-reputation.rst + reputation/index.rst initscripts diff --git a/doc/sphinx/reputation/index.rst b/doc/sphinx/reputation/index.rst new file mode 100644 index 000000000000..0166a2ae0c29 --- /dev/null +++ b/doc/sphinx/reputation/index.rst @@ -0,0 +1,6 @@ +Reputation +========== + +.. toctree:: + + ipreputation/ip-reputation.rst From c8e5271c29d2d8c7e8bf367c857da6808c2d9ca2 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 22:48:16 +0100 Subject: [PATCH 1802/2553] doc: added setting up ips inline --- doc/sphinx/index.rst | 1 + doc/sphinx/setting-up-ipsinline-for-linux.rst | 123 ++++++++++++++++++ .../IPtables.png | Bin 0 -> 12286 bytes .../IPtables3.png | Bin 0 -> 11204 bytes .../iptables1.png | Bin 0 -> 13223 bytes .../iptables2.png | Bin 0 -> 15267 bytes .../iptables4.png | Bin 0 -> 22821 bytes .../iptables_vnL.png | Bin 0 -> 50980 bytes 8 files changed, 124 insertions(+) create mode 100644 doc/sphinx/setting-up-ipsinline-for-linux.rst create mode 100644 doc/sphinx/setting-up-ipsinline-for-linux/IPtables.png create mode 100644 doc/sphinx/setting-up-ipsinline-for-linux/IPtables3.png create mode 100644 doc/sphinx/setting-up-ipsinline-for-linux/iptables1.png create mode 100644 doc/sphinx/setting-up-ipsinline-for-linux/iptables2.png create mode 100644 doc/sphinx/setting-up-ipsinline-for-linux/iptables4.png create mode 100644 doc/sphinx/setting-up-ipsinline-for-linux/iptables_vnL.png diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 9b8194d7838e..ad43700d89e1 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -14,3 +14,4 @@ Suricata User Guide performance/index.rst reputation/index.rst initscripts + setting-up-ipsinline-for-linux diff --git a/doc/sphinx/setting-up-ipsinline-for-linux.rst b/doc/sphinx/setting-up-ipsinline-for-linux.rst new file mode 100644 index 000000000000..0a4b956c87c9 --- /dev/null +++ b/doc/sphinx/setting-up-ipsinline-for-linux.rst @@ -0,0 +1,123 @@ +Setting up IPS/inline for Linux +================================ + +In this guide will be explained how to work with Suricata in layer3 inline mode and how to set iptables for that purpose. + +First start with compiling Suricata with NFQ support. For instructions see [[**FIXME** Ubuntu Installation]]. +For more information about NFQ and iptables, see [[**FIXME** suricata.yaml#NFQ]]. + +To check if you have NFQ enabled in your Suricata, enter the following command: + + +:: + + + suricata --build-info + +and examine if you have NFQ between the features. + +To run suricata with the NFQ mode, you have to make use of the -q option. This option tells Suricata which of the queue numbers it should use. + + +:: + + + sudo suricata -c /etc/suricata/suricata.yaml -q 0 + + +Iptables configuration +~~~~~~~~~~~~~~~~~~~~~~ + +First of all it is important to know which traffic you would like to send to Suricata. Traffic that passes your computer or traffic that is generated by your computer. + + +.. image:: setting-up-ipsinline-for-linux/IPtables.png + +.. image:: setting-up-ipsinline-for-linux/iptables1.png + +If Suricata is running on a gateway and is meant to protect the computers behind that gateway you are dealing with the first scenario: *forward_ing* . +If Suricata has to protect the computer it is running on, you are dealing with the second scenario: *host* (see drawing 2). +These two ways of using Suricata can also be combined. + +The easiest rule in case of the gateway-scenario to send traffic to Suricata is: + + +:: + + + sudo iptables -I FORWARD -j NFQUEUE + +In this case, all forwarded traffic goes to Suricata. + + +In case of the host situation, these are the two most simple iptable rules; + + +:: + + + sudo iptables -I INPUT -j NFQUEUE + sudo iptables -I OUTPUT -j NFQUEUE + +It is possible to set a queue number. If you do not, the queue number will be 0 by default. + +Imagine you want Suricata to check for example just TCP-traffic, or all incoming traffic on port 80, or all traffic on destination-port 80, you can do so like this: + + +:: + + + sudo iptables -I INPUT -p tcp -j NFQUEUE + sudo iptables -I OUTPUT -p tcp -j NFQUEUE + +In this case, Suricata checks just TCP traffic. + + +:: + + + sudo iptables -I INPUT -p tcp --sport 80 -j NFQUEUE + sudo iptables -I OUTPUT -p tcp --dport 80 -j NFQUEUE + +In this example, Suricata checks all input and output on port 80. + +.. image:: setting-up-ipsinline-for-linux/iptables2.png + +.. image:: setting-up-ipsinline-for-linux/IPtables3.png + +To see if you have set your iptables rules correct make sure Suricata is running and enter: + +:: + + + sudo iptables -vnL + +In the example you can see if packets are being logged. + +.. image:: setting-up-ipsinline-for-linux/iptables_vnL.png + +This description of the use of iptables is the way to use it with IPv4. To use it with IPv6 all previous mentioned commands have to start with 'ip6tables'. It is also possible to let Suricata check both kinds of traffic. + +There is also a way to use iptables with multiple networks (and interface cards). Example: + + +.. image:: setting-up-ipsinline-for-linux/iptables4.png + + +:: + + + sudo iptables -I FORWARD -i eth0 -o eth1 -j NFQUEUE + sudo iptables -I FORWARD -i eth1 -o eth0 -j NFQUEUE + +The options -i (input) -o (output) can be combined with all previous mentioned options + +If you would stop Suricata and use internet, the traffic will not come through. To make internet work correctly, you have to erase all iptable rules. + +To erase all iptable rules, enter: + + +:: + + + sudo iptables -F diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/IPtables.png b/doc/sphinx/setting-up-ipsinline-for-linux/IPtables.png new file mode 100644 index 0000000000000000000000000000000000000000..3798db3dcbebf8324d3d61ed1edc94f3c79e980b GIT binary patch literal 12286 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 TZ%we`e1NQ!qGW~mmw^8RVU6#6 literal 0 HcmV?d00001 diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/IPtables3.png b/doc/sphinx/setting-up-ipsinline-for-linux/IPtables3.png new file mode 100644 index 0000000000000000000000000000000000000000..1102fc99033dce6f35c2fcace4c2aaafb396f988 GIT binary patch literal 11204 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/iptables1.png b/doc/sphinx/setting-up-ipsinline-for-linux/iptables1.png new file mode 100644 index 0000000000000000000000000000000000000000..125387f8b923ccf622828cf76becfcf22397e727 GIT binary patch literal 13223 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 z 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 Gh5jFM6XenW literal 0 HcmV?d00001 diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/iptables2.png b/doc/sphinx/setting-up-ipsinline-for-linux/iptables2.png new file mode 100644 index 0000000000000000000000000000000000000000..02d0df04aa81620979dc3de4a303c48e64335df2 GIT binary patch literal 15267 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/iptables4.png b/doc/sphinx/setting-up-ipsinline-for-linux/iptables4.png new file mode 100644 index 0000000000000000000000000000000000000000..174ed967367a0e7906465b914b8351bc6bdea0d2 GIT binary patch literal 22821 zcmZ_0Wmp_d(+0Zu;)@g90t9z=m*7rtcM0z9?he5rxVr~;cMI+w9L_%Pcb#A7I<-2p zy)(UC)zwvZ-Lnyj@{-61cnAOh09jf}Oc?-x@C3h~1ww+KM4Q~ z@CK}rtfUy=^S|4#uF@p%9(V^SEhhi~<Wbf^ORlX)kkW$>9a0+bt!-Oy%Y3Ud!-Lgr>V3;;ivN)y zm>Cul5;8CfHIfYiEcy80EfG#=umsxy!LkVgOFJnESe!+LgoKVm{lPMW{Qukb{~G^) z+Xe*eScHYvqCzzk;VqVyMJN`DNiIdoXC7wR4VRT{fs9(7HF3{4!#PXzYF4ehZUB4Xcx zd;G3jR|ys}aCey$(~Do1uTtqY<26{_Px-Zde$|waBZzDbU5PqwMkxsXUbH&c6IarC zdMH5lNEs**G(d_;E}Gx}-Bo^gJS2_*7s7YH17%M3?Y|+>Ku$3zudlBk-KVaxtgN(V z$)E?$;x)0burV=HPL!$r860vzD1LlOOiWZrwNa&%lbMjZX@!toSq>EeGSg{RRTtuS zzg+B3IFg4Q9N;i$r(y6pOQ?D`?!Zc)j!^<3D*W5W+B3Ukk2Zg9Ugv8CJAwya$2J!y zSn(!ePj>mjtRMCV^b#Y}cWa;#Hv&KmqOwHY`bSVE`UdjwoaoBBeFqjuOkr?z% z2N`=Mh8sUHA_{g_a^+aj`IZ%OgmJ@Wkoyi$ly=tF)@(Q`C=4SDa6@M;n_vsk03K?n zrSs1prBQ!YMt5%`uU?%)7r??e5F+g}*NqSE0PrYl?`aREaHSRh-2FTIO zLgQhVlI zy;&!-3hiH_wghWY#r%60G%My#uxM=a>?(;(0+?ZiUj5v8We(DL-RwL)dH(OX5VHo} zB#$$k6|OI+nb>&={T&dp=DZwzWNW^cs^`0CYJIKIYf5HzTNg| zCQ?Wjefh^ytSXJ^o~uU9oC+P+VX*jGBlxH&WB~Gb0BgZlt!wDS`OW&n=wgSPM-Zx; zrtpLJWd00z+&grUdw)CVU=VCP z1v~(SSYTsrP6YEmL&Ax0EP~jAOr$WB{za{=x9od7LrRAA-^tS@$n95bn_ZLOBi{To zKQFiN0*4QnIqQ+20BmwNn3#Z!f_9qTc*@pBU0IZ$71XqwUQg~hG4;33LCBDmludb` z{!K-EC>0fL(GgLp1LfdJMPRi9&4Fe$deUnCxjFRe6$Eu!j%qF~Q{IRCW zGXQYbG>GPgS$p0ahDZhgg^ylfvnCIZjwGQ&XOM+IAMnz~AGWCU3->c3b`uKx(EtYF zGGAnr7J8jy=h$dyxr~5uN9$i&)<+$)JGVQ89mIpE%hJ&AdS3c4Sh-2)>d6yo3Dhf= ze#$%uIjI>$qro(pil>BdFK@cq&$;wemDwgDQ^)Ql%Y04129M9XhAlR|wh0OmK3djJ zhi3lkP;VV=mNo5I91*V1UY8wJ@ZjLy45@mQbYf9-G!jX*(SKjM)V3@2F^`~UAyw)G zAr^|YY?`)=ZKBCSUj58o;$#N+Q@DF>>mST}lordn@BrvqFXXMW=GP7zGogi#JKsE7 z;9;7ZOX@f`hieG{;e6k_&t~5Wlp{q3!ceJLM2|y%eXi75E1a%qLHa>7;zovy#n>~x zuLsf7V*?zTQ;sU%gyI3Sz104@03{*XUk(T61(3Md0An#XJ0_u7fa-7pCNi#ZCX6}+ z8{#X@M|JUP1hqkHtoH~|dRV=)&F2OV2EUudZ`&zKZV)wbGe&smg5S-(F$*C1PLQV9!znQj1>Vw z_mCpyEv&1{Z*6@#%JZZA-(d9waSsC8{Za5LpO835x<;%@$bFZrpJA_E@dTpwjOM@KPR%W zqfu!6h%3+NON720g2Kn9C-S+Pw<+BcW>%G(8Vi(@b)$RdGo7=MY1P!jimns6paO`h zs0s@Ui;Kf(je+BpU-}?E2Vo5&GKnmg_ZYae&MS!6l9Q5tzO`eGdJiqNs)3OVTX`i8 zg@qS`v=dFAE>Z^439XizW_kvpBZ)qE*slh~vt>Uyo4ppa3x^mL6NMa_FJDe4?|Jo> zok%_8lzu~mkjtNq01BCa(LJNESlJvF**)qq z8tX2p-ELfCXk0P94{bFy(>l%Y*Z-z=UIIIHA)On>qz>*Ql?Yow{D|mA4C8B4wSAM+ z2f3eh<2hfwlj!VkPS=n61f`Qjndv&Y9%?8I8I;RdJOQmUdusZT7-H4{b}`9UUN^ee ze=F@FcA{3{v9NzeP7x-{-&E}I1i5|2aXtsWhy4_F(wY1qjcy4K5qx}*MiYU&O5Jc30s_|7*X1ZN>Po9EK=z+s{R!Oe`Xuirl~_dz3wVs)UOrL! zR&~ba1AHa;4R+|+&G0!w#bE!fBI<9f3 zcpLt5=@7K62^R%8G8C4QELMJhU-fv&M1J+vn^E+D1mI%NA}Ka%z_occww<5~_&6_T z{x0B)6mT2YoNWHhFFQa^wx8|$^JAvBSBQ*5gKZ@8T6P09#flz%v#+k4AjX>EQ}5$c{#Pq&(9Y# z1INYpJ;X#~<5gxV81s_GNRB6~fSsQ!9xW;t=AD@nzzlW@_+ex`6(6!`K?*#V3KSYz zVa$+N;uWAvTV^ZQwti4hkn|Y7(RZ|aV(=8rwqX-9AE6~R4GR}3o_&E+#&mh`xIq&c zno$fJ+^_%9?u0B(n)^tw)!J&ejuRm*-5nPPij0byKXLxQ&S1E96plr!;pu9GopE>7 zYS4*6!0I~f?Oq5npMNXp!)-t?Va;;&esEK5;N>R|I(nY}lUyJXgC`zn2iBnj(Hb&r zQdqG0P?H!Eeqn1CgxzdN+~Q1Opfhb z4mc0%<8H*yBFqnXKmdv022BZ$m^o_wz~5|cZvJh|9>y^gdYmMQf&<-`rouFoNMUMf z8bd6Y>wpXnY3>4*%Q3|bfAORQ-a1libTcxxs~+zSDghPNYD_W3yPQ z)Dlw#k9l^DRv$}pDxo`jG3Xj)e#aq)1VRLXOU1eVeC7*>&C2;|1B8DW2RNpgTCP;2 zX=M_Obo0VZB_!FD*2CYmpbqf=Az^72boO=9J3Yg+f{U;qWgcylv>33n75u)=ljnXLQ}X9e3k?%nC_Lno6?FLD%CJJ~sAJu^h0vzb}-nuegcM zq}}gz@rY%mzBBKLQ$3BAJzR|>5?1KvHdH7~WcPVEl#1?g;!5X z>N@CgyTf`}ert21_F@2|$`-p}bRzWaP~q-9TH>UB3^DdsS2-mO_gOX_6aX^>T5n{# zy`JAq>u`rIZg>xW1c#Vd0U4%~{8EXqoPz|W&&f#*m=JuzCf)-xCW-SW#9 z-PX{8GI$J15WbbazwbrUvJ|b3z%ObVZf>o7#cVzgWfYN{dCOCUeFM2*0j5e~8o-dy zERd-mcih|v!4MAuCgLpZ7OzXP^vYUt7}rZDwjWvlu<9M%>1C%(EL42wfE79%G7?fu zbaB-9?C3Mbav}zC){-rgK`VxzXqvud1D%jiZtGR(i^}N4f+>u>YSyCFX1j~EhezA| z$$jf494eu7*0ag?L(Np<*V`c`@xsn3LAc@K&_T*?-zh_i>95`O-iC^WL*V2$_!zJ9 zHGak22>dJwAG+Q9D%g{fn60DnLswaA9A*ecy!Zu1l4jAD@5;52lUEAtSvpL!nI72~i_y2-c zzoCVjfkZGxaAjSy7I&Rx5`zKXQe>*sWm)N9;~V^3A*SyvEiIi6CzL7{_gyf+z0koO zc2m&OTBY@S=S9I6*!?HT4dWwG3J=?hDTPEm`R|WQ)SS9^Nd<%HIkq-Bnm;{-)n1RU zjWi+6EK>I2)X9aeBTeI54h~${EI}!kC|Y=fKwxLm(X(_CrCcVPw5tZ%A~@#gGnEnI z=H?dsY`hh^-2D|D@y*zb+698GRPlEs+c*g{x_|z;`~77T{22}$&f!z;rLsdCSWavG!Ye`1Z%C~lNXk&)-1pIqIPzBJIxvsAw;jn-r728-Y6%*6d+Wt z3JVLnqsO29=#jO6E1%D(fW-7-1PANzdZDV81+6mMK>WDRzRG_4lfsum}d(e0~Vx zosHJUljxV$4DV&IS577?y|E{R`QEw8lY9j%ZPNaw+LycF}@jkjeuoAwmkB-*e8@A765#O3$+VZU* zWxe=F3pvE7ei4~99rS;nvsV;HD#5L$x(hRlFE94k{LCdxz{^*q>39P}T1S&vM^{&< zfJ6%TK$6IU&Hzw>Wo7|&s3C6Xjg_ca&3{OKI1So*pXB_Y zRC(O{0SP7eu}3T(2^ozh!Y1dDjS^`HBdiK50T-PBT+M(B4fKD!md`3@GZ(!G zz#0fc>Nh8g8cm{dt0_LSwnF=|icp2R9QFrR{Od8)n~63EhN-2ILp7(7T`i&n&s?RhClUc3 z8Rt)RKqyh1`P21ogZVV&KQyqns>pUUkrS)ee5#}q7Z=CDAH$JPIo*>asylVY?cKYH zCKeRn=Jq(5D^{<-f--e$&(dDAL7{@BKnRqnQl?#r{{?^tM^A*F8LDp()l*)8wrqo1E>R3c>utMCvBx3vP#L$f~rYV|5jJGJi$Vn1naM= zsztjRX(_4W%CPZz8*guKb#?4v$A^apqBuCu@XUmxEHGwiHkrw8x6v9O4!(EYLjY;Ci3y|QC?o2k&%HH6IzP|))T}KyKGuNxT70w*GGb)&W&l1V`F33K98F_ zP;h3|dU7rd5LbWytn&Wc|M0r%`mF9if)!QpBa==X-gD$4z{0{B2t~eAa{|tS?(t1N zZV~n~FV=U7KmFOQcl{V<_-cWMpUcX#>g`qQD{{?ym2SueTs z<>tcTM;0W@6ptThce;bk{+39hHPnA*vR6q04bU5k9G{13JmkEOAOQr`YtmJySJkiD z5RAtXvQip7US5g?@@x*NaN1B)(@#!LK2XYD25dMeSpWJDBu4^Vz#6;nA%o%Nbq^)La0N zmhNPPk&23nukXiBUy#=e@oG953CY@IueuXpXOeT)>&g&-V*LL8Xx#G3#t&nR%Z_k3 z#lHt5l9~BNhaK&xr>Cco9SA~)4zS<^1NpFg0`Hi5K8qDqy_cJ{4u(|IPoO^?SCBrT zneHF9w%Q$pfYZ~{%&aW0f-KgO4+?N4fi+%H9k!+iC2*%={Fj2jH(u}7qM{EF0ZBB`rg#&C|F2Z+wrUYk(V$V2Qvtyc5W08*6Uu+}5PyB&lYSDOEc*ASo4;dY z+1c4Dlqt&aU|%Qr!@N%Dh|XO}Y4*#fFsAt2#Q#Qv3APIR!v{)683q!kl;qTw=pc+l?9 z?RUReYbr&N{|?>NJr2Va7nVp74H8#UQ&XFv-%`lUAd40SN6r8MX?S$7b@h#!1EyWe z*hvxf?}7pmJ#YyLM1-=&x)6_GXVnjc@TZW*jw)V17!~9C?^iM6!kSG0LT_lekfvW- zTA=*L4`{x9JK_3X3YAkmUXCt;*P;6lTQ+fl|0T3?f&yGkao`z>gUee}K!~Gi>?R_o zkXH8a@R0n&G#nr?|FCIH_sr!yVdk_9MU7zmJ^FtYlN=x-RGyd?Ztt{_Av6R44-Zd= z0S6Y))b3?dC#5tJCS$Yt^LNruhX0B|-u}$gDIg4|F-XWAKB5ds?H@nnC{@D5F^RVq z(+jBeFG^m=zM&sV{+BAS$p8Q&BU~57GKrnUqzfx6EA!=*B#p4p?pWEEdWQC2zW+}X zKptk35lglJ=1Ynwl{-0egq4OE}Jg~t#ivj>YUGG(3u|-%S6fxB_G?wd@ zcaMK6J1K&mRIQIM%fTzd+7N6Cqh1~+#Y zJW!uJ1ieJ4npNGy03jdE^egta_xFx@WJ~S;3Ql_BFi?PnWiPjIOw$W&AtYPd9ap#2 zWjxT%tJ*w03J8E3YSKUnUT9+l!e3v`Qcm;ZV@mkFI(aEVZ;qX3p1BCUm9$POHUa*+ zRn69H-QD=b3KsP^f709Q_up93ybs50EmoUWm)7R&>RK``4i?!_!hTdKQ~VLfZ=@;I zJF`dfw{tODU)Pqy&Kf=ZU2Sb)%Q}xlh<;2=h*qLjM=BhUEdsBhW4U%{wk>TJU^>Y| zc-oIMIOyOxQ>#|$^jmf2i`IZ+wn+XloEwG?4Hx0Rp%SwSm9olmYdiK?w#Zmu6cBNV zCZl$SiL2{{7top=TXKjUCi%M(d@8#^+*eEX8^>ALn7Loect{^Tf%~i)49h^G$7Nad z#$Q6LHOX8#dCW=3$~SfzA9d=ZO2vf)hLtDP>vm>XGSBW#UT1S^_}YEju-duG&tEWB zgxCSq^(!1HizisW9EiW)4?CG{M}u6xGRLkWQL0Fe1Asg^-vo&0u(fu0oKrEV+H*~q zR(vX{f)zP6z%?9j(0sG#=}@{2XY6f7bJoZR{Z7m~{an#fy!=sLU6#-?2TP^?{AI6I zh&{C^aSdBTsY#f$>^#d{;R|6}{DLC`c3RC_+s1cZ+(J16Fw~gh$09!8gtFczS{1!e zAo>rm!Q%BoVQg?Mp5lF2Z*|tW5rofaYgaFARtofoY;+D*VzvAmJRuz9BdHy%Xe$0p zd*zqJe*`bsl(*{~XC~x;3y>-}20g=lzFpouekbH}eoCd!>fUz!Ig{*lFVp0Q1Jx%; z!bJuPfZkHEvhqEw`SjgWh$~+>r44nwz3ue<0=@Hvb?C1vYtCfx{7LUcXlEybm@+Xo zB@+^PB!DE+NJK=0a};*#qSListXM`@srDn+y!%Jp`JRwq(;K-6u(!eEfzeFZ z=y)4xpL=9JmCbE7flGIbT@ho1$y23$+lpeNd%Iho=(goMtJLtGDoD4{=u1j_6D?A# zPLrMb;`edD$ounFOZR2%fq?>x_W$JqAaaWky_4ZJtab`s9Y@A^5uTRqVjPvZARxFz z!xaG4sG?%8bknfP(^-9f8tF7D7uRb~Om~0u{o-aUQ_ZH%mP@pRO*tS2vJvxW8fJKZ z-l3x=I-?kxrPP{^_HV~VWeT_?Dm)#j33L8b7)rbzP1{zF%70nO4=^Ovgp}qR1m41m zLlyjLsw?h#Q^d8(^qj0^TsoxG@oFIu`1ud}4{jRaCLCr`GW%b;nxn>!0uTVx{&V+{ z)9mZlQk~1h^(~YJv%YFwy+VuaTzu8PatRVX}^*tiuJlHPBR&o zD#@bCb??_7r+<6u8c-kIbL+5=S$pmQ?Z3?JR_mep;Auc@6WUqMCXeFg)=lKc+5iZg)B@H1LG|;!4H?qh@ zGgJyg_{|<;uk^QzuO?3mQw!%(GWLFSCWqvGw)VnLSJ?gJC~0J|yW3dqMnvhuFO$H|&;8FQ^A`@$d{jKUBO9r>ZQi3weG> zR4iJ>NNBb;(Z28`yy2<+To)l7`d-K zX%M$fUZ4es7NqVtetNzSu4U(?+VND!;qtgGQ6Ni}jC#>N>mn6=dOtblvQm2gIUfl| zlIDT}rzNTWj|Q=(#w?QfpR8&}+IQSt>Dz0@ z&RAPpW03ewe%O!RJYd(blC9? zGY@9Gzb2=2?$k$LRKXSk01Ti;2n{#!Q3PBKby*6BZDw=Z@m$Ip@jOcvYbV(&*{n2P zyo@gAIEFse@8AU+OyXV35!|d8i?26(nAZda24S%w>-(-AEQpGRu>=BgEJc%&k|6T? z$wNk#u9wq3=-jiFy+ngXeshN!aaCzs_N^2~cDNl<^S7#?8)@Tb0o$AtyaOH^o13yO zE_J<}4^Ji;N@Sv~u^?v%Y^U{bIH{wpbOgSMV238vQbc4bop^ za8V;oq3x_(uj4>T>U*TRJxF{*V|RHl?&*pOG1ueV&DYl#JRzJXFm5i1HQsdg6q^yO z0v08aJ2+J)J&7@lLD1Bd6>HsOf|~Rp-*T#&u#|70f{5Ll-q@)aCL8e;I zH=<)o9TZ}UME9>O8I~7FVyLTkuu(v%IzotVZtQg!X#xA_piC|>0fDEJ}f%-;*d(u z5ALMMP$ItrxLW4N(|*@2Rw{tPqF;^5;W0Kmo&f8Jy&+*Q~Kr*!me z&OW^de(qWP{>|pM-faxegI9}c34va@nDt0NYwLP#XL;}Hhvc zy+_6WOByLowT#CX-CG;cI5>W4IzE*j!uY!NeDUybPB$tL0~Rh=;z2nPqLy0Zw$|F~ z1mk*6=kt%+wb0O0mY?SR^gB1VedmX#h|yd~qW4SFvL0{Vp)1$9KD}ODhcK`Ai@l}9 zNmhOD<43!V3L8Eq7BPBGz0WgMeqA|2O8a9b(HqUT4%4f!c{^g33y3fptDF93QI^C9 zUu|xmtKzRYDx6H_D2**{8?}0^o%Ob2%jkS8<|+@wfSkvBzaf6(;5m^>ThN zMrK}(?{OJ*BU`>g;2;hc|PebHOyQ2%S{s6~#qe>j3KS6;%frmF7L158Js zu2a@#zuW8I##4BUM(UWQr6ISE+$5BMvWgn&poHWI#_<<2hK|LHMws9bcrwh3&G?h6 z)}y5py79i^YGp+&m893v(sQq?fKEsZe# zgcy{q-jLyw zmWv2A=kD1kaqfCGGZ#NMxr{SqirdLl@e>}sn~#T;1;|YIn-XV;oBt*|uy9h@&4iCD z-ZBqi#+=GTk|oVsU`L`7D>dP4_}w)nBpl)6%_+3^;kL9icfVdR_6;0Svuo3h!lNn* zuD#b2&bM#pwiS1KY!~>wKeWmE4va6`@R%WT;0Ai%t7;qJj+(PWiG-(896Q6iQLg}{ zOC`C9b`RvYu8TXwn(y39k&hJ4x?BA${9XQLfZ8fm&TX zGtAzzt0`iEJz?&DK0?w0L+OU;uHxszdAy6a@#oUPzG0gQxj^~`9 z&55IEciELMn)ST@TlceFH0y)ZY(gkVs;Lh(#XY>67L=9R`Wi_lHxI@IeTGgJZ5YBd z^qtSkI9w10gsy@Ht62!CsC{Sp4y*;9c7ouDy%m@Fqt;=T?fC383MHcqgv=*6Bq-dO zR1_6!trlsNF#Tdm;@b}QrQHuwDpWK3%vv%g&7ua4STfqv?mG!;J&r#97%oTl15)4O z4XBixT3Q&j8_S5V%BG!FG&D+)qC-ABMyj!op@Jq*IOXQSIsJb)YS*_;XV+=|O+*@< zuf6`D0v<;#8JuPrtDEl!?XbXo!;~9DQQ+d@qU~B^c@2mCb`yTCdGcDo1UtBP3?U3U zxIo6|(9yY&Sh5BMeqr6|g&=7ab6ByhTndN17K#EvB84jf0OCrok5~2<7RN~#rB|#f z=tMiK6ktLCDy9M87s$%OUeNRYc#xe{3@z6a!S{LaksTnN_gK;MeCZMcm+cxPsGbZ z*|F7U^)5R6#~gM4t+A?U(3b{}NuH68pv8WBxKMIHJhER1_;F9={(3R*DxZtQ*agji zx*HfZ#&U~@C0gF%mCONp}+jO z!fCVJaORGP!@+e{tqI2)bb?76*Ni^{ulgv8IEbjF|g znE1tvLMsTsgDq-}F^Q^BF6#-)`l~n_X-L#0d&lGXrjp_^3ErG}S8|bme^%Zn zW;0D^GPf2Q*XxxS{q1%i!v0pSZ}2Wl8aLH!Cp{(PXQx16Tl$HNy&psvfa~jBiyNbc z!FubX>U8{2kY20%02jdf_Bqh(ok?^k`g;?C?2e;|&Y?wCIs7%?0B>urIa8azlLILy zlkP&Le6fL$2H5|0rBT6ZcZ(V$EJfsqHl#@ml2L+6u%kw3VqZujTzzL6nA)rhK!c8w zUp8Zd1PnXg{&4KreBZ~5R*(~^(t=7z&~2lngauP=lxPG$&soFfrD>{kI;%sN^}6g- z3Vp?-ys=9aJzc&;mOKRP9)0g~Q@dppAIO~k6xeN+q~yD9*?hh0JW!j~^lq|uCeK3Z zv02$D`u>25aQe+@5|AWP-h98(w`rY+5QqP`K@j-}5Xzce`FoVc>`V=~=Ia6DjG|#E z58Iw1Kme4U&&T6XEX?HWD)|yVw&X$Sn5ELfP3(7vMq|F&P zHP`T37@pn7bf*>Bl&zC9I0bc;)DZwQDKtDhFWx7xr29Wt)Gz5}2~&MOn3KUYGpG{d zr{Qpj%uALyFgF#`>4jjWtr~$u{|?C*qYyf@t5-!F*I3ai*RGQ2buI@8fHLskDJfa^ zd)jUPYh>>7@VCkOk(iss=IPp3TfvN#@0nu5LG*E<|EYO>X06G^^;H8LZm+C_$G?3- zto@E;<9Fn zHd%0MJ1(w$DYNpp`N#%rt9n?+>E8VbFHi#kB~l4l<@ek^DeEhAA3_iU5|3k?`0_k> zCWW5w)RaDUGC}ukR`9uqhR1Vm0Cjp~e2)&BE^>xnNYpo#L4g8a5e4pTj~Mg?{_~x2 zVaYY6Qt$(fURPUF>1OaK?+0C~K*kvKyP_@KMU|Opqp}CYTE?N`hlaw(+vsck{_@3- z>=tuW9{bV9m8=%Vr>yyJ*%FDsSxmq4Va{$JqcNPgjoRHPRGqhw2q`h(Gn}Lqa=_1h zP7xr~AEZ31I?dbLTQQ|`pCbLZ>c908UYaE@B2~{N+#yYWEqqMHoxSNqlC$;Jb#mzmtzFG4 zc2+8IRLYn!)I*zkcFiJ+sssQDHcf=o%y;|Pzj0dhc2%Jr{=aKRYSRnKr3Q}*q5b_c zURT_QQ=2`eC71g^)%G+l9FfY?%@L3Udq~< zU>skr8x5;N-%v(T!@<$RiWMR>!-ydDA8ie>vpwAW^6pM(Y6cSDbnS>WYx$K)N;#=| zx@RJlkWo5VaVipM%otR9?{+ork61T-^;(CY7jTjsA8b~KlO(#B%Ic@0*$B2?Uayf@ zw03O=sd}-2{6zbpGDKXhAPe!e)^E=h*x}#7HShVp&W8%D7e({I7twV$md16_Zywec z5%22|zZ@mp{Y1OhApetZ%?uk`=vT)TD%_w^=c0)-Q(agOVAYQR%F4H9>xT9 zC`h63{M~EDim)jUMSG^^B@JCo+75n(O;g~x{9f6(t1v|89m<9y+(bG=5@lcX7l&cO z>pvLR=MC2jDh}(m4)bzMmgpM}P#Z29aXLT&s3>&f`^@47fQn7suu0w9&$RlOHIQjIg)j;Ec03@0AqvP+U#UjL) zzcjr}?Gld5k@9MrfDYx|ckUy$qX1wefJa zMcKQumfh#vf-X0xvt3HcJR*!1i*8suTVCEVzo4v^#>fQL&*t^kCCHdtW*-lw`o=-K zr7eM7qUCaPMBX!7WbC+ac>&uGdF9kbgPN>zr`p!`pRBVwZ_Jl(TA~mvD4$#%voG-i z6wEBPNMAGhHd{XgYoa~9h24KCCo_>yv~K=lagdU?N6-{u8_thP%}6^)4y1taAKqJS zvDde;v9ZU@CW-?t8QcU?KE%5#+@5R9-Y|}j;e!g8QiT$ku+eaM+=p~z&;de*Y&6*= zhe=tAYjjJdRst`GSsWRnkg0%Ke`>sVATD`m(j>Z*N)>azqN@S^OnvxX=wEV#I zoGnoh#mi?`S)7dYY^ra!vd3v_eOWTge)l*t;vtkp>b9POf;9lcxN*B-T-nZX(-z}C zJI<{03)?Mie@vL>Lz<33vTfj%1t+I!d$t{d@O!gc%SWpYNDM(5{GqHh`H(|#M_ogG zXfna7C@TO*sxHZ0VNQ-wg$gG*b%`9oFj}}DH>x)jsqKV82AxSHyGQt>nLTd>Sl+<3 zwU*tJD%YVG@FYK43Wxxt8({*K03&lcN5s{PytP(aZ z$Eu^MRZPK%Rl}M17f7Z3Q=yrEL&Jmpb)#^^Q8KX6sV{W8XbhiRd>seUGi_nGJ-*`O zT%#ogHYSeT0sQNVkn!1Gx*yZmu!eue0z}ZSet+ZU_&c>s^|?FwEv`F-pX_BPl^$um zaAhQJh-T^}8|)USiD-tmsr{^RSuQJHuk;1X<$cvtRm#OmJAS^b@Bs`BFQx_k?l;|f z^4Lx)V(>X@vKM{!1q432J?_xCP)fcB@OK1UOlN-E+L|Iam6{t_IcLTo zdL|)dp40Iuv)D!f)N*2BU96L4{N(WYFmt@ro7GbB`3qeUOdh4r-|Tmnkn%~xt+#7M zztXYa)s6v&!r;->)}7y6FILOhs#~&grN^JzQ0RQ*Ch2NlNbM|sC+B&%^Dn96%fJ5G z5{g?*bdLZcmu*=!UTm&Sk&#-<6`j$Ofj`a0G05r?`H*0;$!PoaQ?IUUcMKi}`=4;P zYP}RLqXGt3;E$HQ&k5^->eotA_o@^=JttV!>2N2Fu1O(y0?LalDVYH1Nu^O{Q&_N96+|;4GDatw_G8 z9I-z(nUYJmSe^Nl#8|48gJKmo7ab2v&&`IBkc+})K?><~2Po*&z|G>+7~BNED%zy& zhZgb`W%|!AX*~Y6CX3Rj7y{N;J3OYz-}im9;RP0<^Dx69rm=O)X(u9o0R)LaRZwltb$UniM_vVc;v3A_fFM;Q$03SJN=NAIK7$ zHw%rMd&9&EvKY9OW#tjr;``QL9!!{BwuFD!*i3D@`S}eX!=;P`hK4pDnr&VDoBT;a z%cWBCJ%imkbJ7$!9tF2m>S5O?GZz?52Sj#%KJ$QYKfw;W`lcOZW#NJ+X$Ui%T z#cg?2vCzLbky4kc+^Pu=)jHTZB>K6_XgZs0)^({0sjnT+;;Qzcd8(-VFge79x5lUs z17BUHbqlc|T}ah}eerYFu+Y9cOCsGY*_U({Q+%GS0x=eqm~Bc=qY^Q;^cx_0f%HUr zU^x9Z!nrH6&!I})DEy35K2SY?!|#z6k( z6u(|XirN2H;ZI)iAc|aL(Qd;`h=41l!aum=2oOVF>hueEK}n%{g-g#lRsD=Zc7*Lt zOYyx)lBtYSHSyXL;#p{e01;f$07Ht%$nwhX{Jwnc^~&Z=GHg}OJXm&|U#0y)usd2y zWQzeV36kk)QC>BCPS%^@{rFFAO>PulsF^Px-Ea!^;{1KyO2wk@iBbNjiXgU8} zHD5=D$oKKVN~Bh%8=&dk($wg@3F<%XEpLgTzXpXH zHETaTZ2?QGzyIDBTlk*hNdS{VPJJ&>XG^euN_eeNzes!t&v#aeJI<${&AHLPb!4H; zd<&VgdfdSI2zX5oj4a4Mx3C*He8fmpK5%Wl8NzR_JhFVHzA$rh(Nqtg_yt>_ zCd;+uG-PZF@3KD+zD#M)0F7ghn1>z=4cQYC8mV8j=*Z+M2vLg17nS1iNl}Ma+3`?^ z+prKK3aF)(+jMd!9kuuF_=rIuCda>j8XMV)mEi?Hqlvwc)YNiHwX7MoeLBnR&TZXZ z#Dj-TV@7CK;MmBo<>e#Xe*|@qC-14=hv{1cH@O#wd5mbaUx}rZS#A-sKF{tJCUN%o zppszAqR&*8wiRt*IZux>vJtFk>eQte_RZHk!AmDL+i&aX=tP6GyS>};^75{-PJR1w zX-sC>HaBe}Kt}1TnC&LGLtbdXGuhlub{!WSfTz7Kr>$3`a_*PRr+dt}hCGyIFh(0P z|1sq@&27K3*Pmfr)6&#}L%gM>?`iV~xnYB0BP;B-l>k|iQ``hOktZcZPd=E{yp0-A zL`l{4c~rLi`5<4xVS5~$#S`V;r-pGqdlM?g6e`g$KZ6K988Wo4galO z4?UR`_L8VsMD;Wr$CCZzFv>d5WV8@4%9{HWmNyiWg8j&nOy)oirb@3Lp-5xmRQt05t`D+XyUI_0P1oX98Q4=3hL`n#WJP?_S4pM z&aJFys;a7LXqdBPfTs_E)2a%DVB1ZXYm!7EJP;_Qppe!<01IgN;&YGId9R$-ah%5- z!VDX1fxUm=f*Z603lCM{9~-WY6bPV$Bf^ouOys17tG6FEN}4Nc3N72G6H~%9 zPEoI6h1HcCm*P1uq#wr!i+yAb&3>0VxYD%dy%*K-4&=;DKYGq!H6KI7dnw;^U-vos zXKNiBHBaoWyp!KnGG}I$U@qx0v{O-8jVB_NuN+2YmP)Xe!0|KDostR#7Vz~I3Y+W; ztN53$f(Yi=s3;Yh6flh#EC4Wt3taQ0p`{%k8v`SRU3)?}a=8U%@$vB^BO_o25|}qx zwKV*im4_N9h{Efdy;~IpsrX)w1`9w(CHiReVD9sIDFV-4+N#a~@oO#xe!(j~xx7a% zlNd-IXQXZoD{n!&R}G?nXd) zwQMD#-pxf4q#rr+9C%VPq(vQhc$C@*xQ78-){y~3abY;nxrUe4_I`i=z#n6eQz_W6 zZ!)P7tav#2!N43PF?JKNoW)^+E4)^MpB93C#GLbsRL`1wM>r`gMHZjAMTW*->&|M} zf=q#JHh z1tf;<7^GVqx`h!CP>?Pu0f+7y8WE80hCzpV&$Hg=Pk64M&RJ`pb=I}6z4ktPpZ)oM zMLV?lYKqWnXY~+x2~y`A)u7vs)Fs@(+EZlRRtRfH`pvE9!58|9Zx9sTiv|&YKaD&ej7MQggk;#8V6PrcJbbp(n=K5fg9HjD=WMQ6dEcZV(hJYJ*Sr zrP|{-Jr;90F!u)a=g1T`Reyh++^T{kMv1zt2VUeqYJb!c&6n%ONsvN_iIkN$Dyj=O zDFuo-d!Q*Z8zW}tw60t_0s>CHANl77-0jXb1{W3(qWmeMIKDK!5dHTg5+}@vg)F(rv7y1XDZJ6%p5n@1vcj&~DJ>=CA@j;2ZP0ej zz4B)e8n2SF84_Xcz9G}$G4T7>#nk)I#hbe}x?;ZPrX>cYc9z9g{tA>asd79z42Vb%OHwceFIxL1~~-!>3)3od)IPHWmPLr9uE-UILlwFKT-jY%EWvRq62H z0qXD5nMqtbyOTkV8V^>&ZzdjZL5C!l5#I*Tmv%OX5n3Wt-5a(P_ik%1hn$Q`MHmA! z?A?^X4YM?%Ew-b&NO*a2>&Zl?>($Mzu9!;D>8>ib=&`T@7ml=HWJNK4>3mU~K!s2bBF&Uo0{Mhxi zycGTVx;1q_IW7J}cv?_=E!rXIq?1S@alif2oBYSy8f3vqm{75;5gKhSBV-&|I4Q`Y zo+??vk*|^rQK#tzARMhv;-?~95}vs6Dqxbm(@Bt?IpXS2NebR^B%`Otaz9x$E0_B8 zcB-?;E#?(7)uU-+*;#UMM=81@PtaH5(LUy>o`5_wp{P!{8fzktCQ~x(cJtrKUVMLh zz1uohVfJ5Ox20*!&_|CI&8zskzZvgQZ_c$BN#UHdjJ&1G$ouTWfgcM=cfkw%t^WG| zIp5&O7ulvXEZ|L`B3R8Uf4RC&Mm;CzEK{KQKAR39($^PEp(})_ue~eKjA#EJ_AM$Z z3OLq%pC7U*-4Z*`g&@iNr3!CP@rIVbVB$=bmn9^*Pyh0b@~Wq*6t%1;O0BJ}b--g1 zw^^kaI7uQRR~r|tcJu`3HlkAgcqyn8yDXEnw9Lbl$W;>sH*)8{VNw=Q{4#>W8v&Bs z<Z1J0IOX%tkUqUrS9BFDzM}>A|e%<1h$Um!UYwMh~R-edevc0MD@>C~T2ULjx7^m;;fZ zDR5sS$ntJvMvT~3G_&M$?V9OFLA`WIFGe3rQ#SR<=~Bb~L?&)ks;g4Zv4?PKhJ5+T zzr9RyiUkI%;pn4SMdP#t&n5+q(!j`5P?(*WoE&O;dKzk2tVc8RR_PsbGuvK1(Z0d- zPi0fU4QZH0@Ps#%xGCci?Cs3?Zshtss$H1EZNK^W?@_Dg84g4~g6QRmY>!f%j*5`7 z>Q|mYKL|I*)XQ*Kr{9m_mE)So)OW+CH2*c7RLA|7wMJ6fFs^^e8=mU}DF*|M->!eE zA=3S0v%nD`aB}nM^5P-0Zj{3wu6Eh;?Ax1YR-Crr>yW=kcOln{D|yn5V+;3bF6XEh zqPvcX%0pujYhGzk%0$Nfo$P%3)MOSXGs(VF9;pM0FFOlnmZM35plzE?frRhyFdfWM|ibPfL<>qS5E2UxZ!ddy0hWBJ5 zQ_CYTw|q}nAr(QY?=J*ma>u19R1Mu;scI2~sjO#WTe<6$EAFEEvJ;M>UinwfWN&_* ze>28S&tgMnD${V75i0I=@zG{^j@i6nB* zyXJpc?tV&qP2WsY>`|MBB0d&}qWU-@0X=B}l+C@?0L223TEMg`aA8G73?F$TC8I2Y zI%^-5yZPtLUY~5ch+b!);{VZ zI<|@BAH_6ym?7qZ*IODkeHhV%Md*cq*O}JC%-G?}8AYvdm7<4XoE;mn1Ji&lV?hZz)u_u&3~-OhWM zTD`2+^q{mPZ)jxXi=$);R5Y9KYii0neHzQ)UB~V1>cBvAw$9a_Y_&Pn1T^K|ck>rL zAAWcZHfmgIdY;=$A-wAQx3rx^=qrtfJzrZd?(>Rr=F5=Y{q5gCnoyEGvBOZ;hp5@y zs4FPMWhOX@TL|790J*(lckYTmLDXVmr-Azl?ZZ_Fqcs0nX}3*%W&OF@EyMv zUOpyIj*=e3g^)Jn3017@qQfJ}yWP0jlvtamIF+uR+c(Q(YCR7T$_ZRNGhe4sr4-?I zc5dT+kbiskM%NNqj)KqcC&u8Onoj#RG}P}#p+9vJ|8k_cD0~|lNUf~@$vA6+dadE) z;wN0M<(9urG0g3<<(f-L z!^OdBBH21oRSD`SS``cmj)Cxrjb9 z2ZePNuGJ0wGcuZSB!o?qLnEP;b!EStv<_w>c{pe?GmU6Ae|LKjetE?EF@KQg>R|rY z-131Z1}mNSCzk(F0)AW7SX}=aI@X~ zX)|(j!s_33Mi2y1Wo#Go_@(JFf>*_6<><3Egzd*Byih{;ZJjma$K4B>KN~TxM25Aw zNsBormID0HWeJ1xI8n*e9eH9F4Fl~@c4zrRDD0XRccngkAZOhql-z#)|^scO@!r9Uoom zD5@-EHqIZAk;#L7BOK~;kc(sZK@`QmwzTTjR?-=?CXNf97|Sf(Y#lSd`41Nnp&~tI z(|Rw=udJc2$&3_<7Zjxr?JO7gxeYc7sf3dxFxzNN)m$Egw+-bi5?obTlH-Ep#RY!1UBL@7lO8Xb zFeUY`&O<4>(=#%(4+Rk;FWvhbL;$wU^ZxEOAt9lTXG$bD-?inWb?zweh6q+}l==L( zC!LKM!m~}F0Z zNKQ3BAUXAKYiz{uwP?{r+UFA>#Uj18FGVaT55fQio4DjV~X*h*qPVrnNz!jM$K9!La66&gRDRVe* zyV(&csWkoh>`@;zt?Ua^Fl&_IRhluw9~aqYEqoMyL28?POA*%8~!NI}NQJ;pu#^>jz z(`HeqrRfV@#453$q?630nXy82r)_Q*^UNmo^~P{u1HCq5XWm^Wcnx1uwg}B&Fp@G6 zOGAvGo7EuTHvZj; zHQp0om|R^e2W<_+;#N|Z0x@tQJNP$A@%m=(ca^);5k{lk+vmA*p?4>%-Lm>dElWun9@spkz_R6B;Of|mew?yi)q{vs z;1jZ2j(@5kW6~v!@HoFw)~5mDyZbq&{-+x=I6SakJoV;uJT1I9+f@8>v9``OaU!DcHG`#YZLaF35O zjIKGwS$uEIO-%ahsQFBHPW^#)E{kUEJHw5_k8npsK(#_f7GSwijtr9i&9EnEU_^IXQmM9gnlj>PH>C{QT9` z)w-IRt&jO`rWvLH!Zh&WFSG>ya&mjDG8p3SM$iFb1vIYcesew{!1)4F#zO`EJ;5+b zy_{J0p_RQburS-q0)v+5ILvB}=c<1_(bYf*K8)?8n-bv#cb%Nn>=pd3f(a-Nta?;f zv`ezFvDH2mDXX_eH1R}@9F8UZ2-T1IF-4Sd~r3q+l)~VNSZt8&07=ydZ`Frc`iS#$MZBGB3F4cO` z21YhK%(!YeQ62V+_iy4c0yLQYVPomj3dZ}hv;MQ1U5D;JDJzd?H=c(~%_WUe^>%hD zT(Te*6GH2F;tHFA(IjAioY?j3j%!l|_z`oA3f-M#57Q5Pg`8setPSM#m+o~t%B0*5 zcF#%C)yEY9nmZ+NAhN6qrV;HTm&Q3`PTOmzS?zQcEzn#Jb7mc9T zGY1*mCRL`jYds&RIdne7zI;~4!yy{^O|hfSMMr0Btv9a!_{S$if&1BU8=gfqe6i6r z6%xMCrIpTbsV^!f77A3hAe*_c`a>r%yOGH+u##~ol~3WUl>tOu|BI=(z?v`ijSQlx zeLlripx7$@8jH=2AmTES)(}46)wMvK`wI4%FeF_D-N78+E;kS50a<=Hlb4B!iHPE< zPwP@0PdN_0?@*DOp#UA3W)@#%SsB(#>A(ak=A_Fc;k5yfv9+e@cBWza;*2EG5vdT( z)E)scZGE0$Ctpd02@t}7M#Nm=_3pv$9Bmcno1Yf>g@#{jTal~s@cpml{jw9$KU~cg zY#x84R8%SQ1m65%pnT<+nVy~m(0p)6FLq2&u@RsHdaQer+BeicH#1cGN_-Q-_cSl+{!9!TOzg=(u)W9m8q5r7&M|M(k(=vU|c?+g`BHPw6Y#1{l8mvjvFN%FwtKxCb4_7|RswW8SNM?HlW^@7n|Cale=_aps63g; zI!QK%1t5#vwv8g%6lDeJol9C{26>56B9$DtiEMVqYMz7 z_I7sdms_C?eh+A>=S|yo#!W5opn&)R7+Rsy0A#rhh8@|a`z5{Y+TOUw!eml>&MK}- zzP^`iNz%A5NA$u%S%KAadxlcptA9b)n8W?OJwQc)y(xbdRu4qq!(acF?TN^XO{%LZ z-c*Z~D5>d-JYb0eS;qt7JJ4E>KQ|?<*W<_KoPJ-5&H5zuK8V`FV1QN=bWoTI*7!TV z2na$&MM^RUymVw`@0rW?KF8?z=ZVpgJx_C7?TQA7V7hf+T9C;_Twudfiby7XtZQ$y zZMo;f{L6p_56zQPH5{=dHgZ+j;d7_pZlrS}u;cQE|8T-jj2ym>Z#z3XxB4CCEFO}- z?+%w|d74z7Sq(c9A}gBOeW}mG#bw^;@&xp`z5TYELe8i4lg!eRJW|71yKQ*{EUAX} z;(@5*>Z3@b3B3>fA{_wtc1tG!simgp=C;4>CXDM9s{HRdZ+LXRH3On9BW^TvUArwJ zNCps|EZ{xs8f@q6>@48AP=umkdLic?u{Ovmr`RkrGCgN3!o5WS2c&0diE= z2vSc4G&6uE6R@9RgjcN~(Bj7eKC)kx0#`7y%_^ zjm*s?S?sscQfMvM!({k9<(V`p=-(OOOuM_*-MgRqvnk`^9`joOiU3VbVl*V|iLngV zqDJxldEn^7h2lSpc~g+3BzVCsVw7Ovx%Ql!z}VlE z;3zp-&Pf7%-0*=1z%hF%u~33vx`FX=Qy6f=%6Q|w2JtDqZz;u literal 0 HcmV?d00001 diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/iptables_vnL.png b/doc/sphinx/setting-up-ipsinline-for-linux/iptables_vnL.png new file mode 100644 index 0000000000000000000000000000000000000000..672c3d99deac431a3d6bcf30b90f5e409b62e1ba GIT binary patch literal 50980 zcmV)?K!U%CP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipV) z4+|+S1J3yX03ZNKL_t(|+U#9rU{y!cp4}tY;|{?!xVyVs@#0#nxD;Ai94bJI7mB+S zcb8xR5+IO}1Pu}5H&>4Cem`!YNuX2+?fbp&ogWawIeT_zcjuXzotZ^3G0~Z3b4p6$ z_;#ap1|9t85LJDe4fv_}sZKw}@f>>pvyzn=ar@k{Rt;h;6#cWkq=teE4$t4%rT4>B zK=2<&lu}9w!?56_-yv01DWxCY4k3i+c_%;LL!xNod7YCFPWnsqA1%BPLKp!6g+C$x z5oZ3CK7!@hw8ozT{g34#VC-Dye*ol;KN0#MH3K;r{ReyojRpt-gq+N9(tig^AtwI# z+IB}7E%(QppEoEgDpzK-TKtdi0E7@w3INWn_y2Vdu&g9W_`@)UzP4MDQwBT9NqI^i zOZ%h11XieAy?z;9r3GtLtx~6=2m6=(DwyFkm`I`|%ZlS&qAG+^$g*6hD$9~6DJlg( ztX88+vLq>g<|C9+Utd>3{*I%EQVMQ`iWD^d(aRKAUAgi;pptjCB1Nfarj~~jTcK(YAA+Xt;hLn^3Lr{tm zLz#waCl`74@TGzv?(V$`Lq|7ulm2QmL{x{A*rE@dKVUDmGdaG`K>SHF42>Rn~sdew% zsU#@xKq<=TSKZkVC|KTw@7`ZbY$1w{w~%B`y!Xg|#Nhf8`TNr04=2o}{p2GXYNG#D zoXQge2q8oWQ53}~R-ELdkAqT#7%H@y^wWZ`z8~ewQdxxBV<)v9KV|Nck^UemGT(l1 z-*#Wl{$_SJlPXe5T`RYmzV?SPL+dg`&83&-`(()c`9qL*y|D}XyQ`99vq>`f?Y~*~ zfeYt;y>OTx6%>inUD);zd!Q!PokX5a;^mx8Y)2n+|TYM@WNo=nj8#lFYGGv9YXIo25$eYuK zwn1CW(-dJZtMROj8MXJq%lfU#PhTA|^~Cv~7j(_vxX8iTla{Uz+dO2%p#Hze29H6V zh--sMCnJuwtKcbWi?uBMDpGLIxOPct(96J5NzhDqakq0dZc z{dt3`=FjGlhcbNG@Or2xRQYsa*oXN6asGq6)JmF5tr z1qaPt&@^`Lh`9~s%r8j=pU=0o)SUiu++wRj-;Us*gs6(5sw%=rjSuhEr-5Xby}Hl# zU^6rx`TBm_b!)%j=FZ<1cH{q-#cJN3B&n+E1ghV4La^XujFbL8N+CoN?`KXweRj{U zU*PgJT#%}!CZBzxCf|F^lq|~t2)C|WNz*+z8fgp+FqY}%U9sKvsB80v7HeA8-)>bJ z?hg%4died6;)qg4t2Y_7SZ8u|HRjUK70;Rj>bguhbmG??!;OX7nKW;S3{HD(+j1+f zee?)-J;IER&wp$A=+-rdb=&?efgUMH=i*}I zF7>G01Orj!cZQ841XNWC1uEH7(r$P4>0qZIt6BqA^;#Ns#vS0 z$GQ9S64vt=0RRF-R05PzMR*~Rw768+%4T2>lNc9|e8R?8KIGT6=NHj}41lPRo&khn zj*nkIVjFOD>#>yvtt=>727a9|&^NkyINxzxRsHzhpZ%%hcWnUt#YkBnylK=TC^6G%f8SM8iwt&qBI%m3+lm0eJfhs(HMgxilHtjG%XJ7yT zVT`i0LjnLOOO#{G@|FkN3vF6GR$7$eUlZTjeKa(lRkA|K5JEr!vQnKKD2Hy}%a}U3 zYxLHex36Dce$aFN?7j!?b4}ZLd^dDig6!WQD6r&+ipt$xj*nuD00GCO#J+HGe>f$5 z_?Dgh#K^}#BZf_neLA>*-RNH*Jc*27HtWWBbH_>-^gcH>J~qExvoc}gglj(Xr?5FJnhnWPe?MuYB>O486d!O*e$5`&?>xJfS>9gaPOF$Jp!4kw9uG2wUaKq z#G0fRX^4{_o=d1xt$1Mh#z5|IiHF0PZIz1^Xg0Wv9E{1U(@eKDy>8LEOBx;TI*UWu z0Gd*bhnH_be@5pKSS&F4WdfDORwKvU_cRy0z43NBkMzpJWbbyLR6Ta@MZ}Z14AJ0U zywqp28;S{G00`<29@{V6W$fS!lUwl&rq*!R8WU?(i;BD#v19eQ1DE&2kJ%d3zVZ2q zGp)nFYG}Up1Zz`bQwh!`77 zqY+p(`P#|53FLoG$mT7sI8n+;PRcX==C|4tZAa-m{rvr06~V%=G~s!gF`vIJF+pVv zeqN9eXY=rLOHE7#t*58Xnvy241~(rcSF8%j@kxT5Q>amjwFXa4e3hAHVNk^T1o~;z z)Yuo9z;Isq{Io2!rY5Il2&~b~*V|}LlQ?WnNfkK{AET6n5; zlmg3p`g#u>Q16#zN0QSsv-g}*${5^zy-k?PNwEo{N)fB`5A+f(cAgUx;xZY%tFMpA zW>v77mXa#+E*?H!M%kS5D%lD-IiT_I_IA^$DrGoGiH@yv@N%K=I~{w@r^d$FWC}nT zgS(%v3)quh##yx$t$RPW{M z;i6H6%*6OKq<8c6als%b#U_dheOoY6N)aLmu>e2__AcaSc@ZZNig}&4UQJ9Bc{g8d zO_q3*zmE$-00@hTFOsbPb13!UDO0)F&T*VmzT_f8YzR4xDJT7Hl=@GrkOV+gnfg{5 zII5iwO;|R2y;aS#WD81Zl`4gAUVn@^{0|6YqM|nE?)XoxwC*0*_>y^FdbCH>`@J;yRMLG=n{oVt^sFHpBM6M-6b z2{MYJplEa&lyqt9_9(>WfK^d2PQ18(Tc=LR!tZ+05GB~9;+zfBY880ezR7fq5CEl= zU3c=E@hxY`dj2no5mjNU59ne(bvQEKihwE_?-t!!_!`9Ey@#K?vVvQ&_Fe1h)#Q^~ zkEq9*G^u%nZSAGYtyBvL4y_Zt6#Sr6BKQgPVLGBY9Aasd@CmX&j8=MK%8R# z%J)y!tXupiqUYZ=Yf7;?jWe&EO(g7J7qiqt$3IRBDOTh(-7ZPyPRiB7aD z$g^4RR(@LZi7kgy1wx6YVV^EOG;aUqb25V%y-({;TjG~@4*VJlJe%#bkQhrgJvJb- z(S#747QeH%1*tr0P0r}`>3;H&@q5 zX)EV8xN-EdYvX2aND(tLF|XC@wHPR+l;JfxgI=p;fl>-c=i#ws%;R9U)Qb-hO1mh#AQ?0u)%Cj@N2+ zdJO_fDMgso8uVH%2Y^WC{Vxan5HG1&#nyn)8#NPqeyixYEMQ5@YITTsn5~#+6W&(xA`hf7=6&?7A~~|4*Kxl)ZoSHzvHEGESp6 z>P;rjQHg^B=5;!qUdvzvM3pi{0AMs)1_7num|u>?6hNcpYWD0~(!}fZj-m`mqu1&5 zIu`v=sX9uD!uFpybMTDr9HQ<8{M9F+Hy-j!j(&?p)bqgJmd1M*!%dr(cM>v$QePix zZh8{y-C@tnl9E~IvU-=-!;7wcfB3$iS1xF!M6n2$FAO=kM2D9=S_=;_z@A>O&Z^q+XANsVO z0T3=+tk}$7H@Fi5K)oCFK6h(zrHa+(A6c!VIcg3egzRxopCnk6)aQ?%Wg?6-tuM=e zGssI4Ui<89v5%ka8}}tDT#jZ-j71owJc){lcr4q}qr#(}ys)60C`CbS(XRN}mA5GZ z*~SdHb$x2TI(0_PS~aB9mta1~)S1+8313m9AKR+u50{RR#b775O&! zaQ9D|^qn!-pTNM&m)aDilyzAfzPUIf-LrmB@=W{mG4! zr>{j8sng1^wD&JZ9^5^&CnQy2Fk^|me<%1>Nbr3t#eh)8tN5r(M~}bssNippei;2C zMYbe7i;0M_OXSVKC}NQ1#)2<5KfHE+!EReXpgRRHG#IvE?Uz*oL_$H4Nk+uorw_vu z69hG<^iu@f`|9b&*j*WNnJRp`9^*w+nPw^_1#zELKDWy|<^8Vgh`U#_eV6~%zQE2mHCQm=cj z9%Wedy;6p#P~*pKQQLk74FiDUuAV<|_)^H3bMbC=Q{b%*>(PqxsgT+0Wieu-0-%d*u zd;58-T6>Xz(m?^<#=r{Y%9iybq8vD6<=0>JXfkBNj-OkB)mnGPx?z2rHW@suWdQ;J zj8?g~FQR?{2m$wBPUop=|fS9a)#30a_TEP#+YGQpa9miZx?R) zZsx(#T^n(na%S^EnPu*rORLbVDkW<8_3O`*B>LJ1pSt(k^Cu3TzM(6i&8;pWgb;H4 z1waApN#C5W-nE6N<0;jUzirZ>@1c0)6%Oo-2<3P%X||pF5fq?-@$rAd*+foShd``bTh^5IOm`R297RxdD7Z-`#tZ`D>R0Ib z^_PfaFvDN~D%*+;*|0zCXmg{ZHRqv`BjC^4JkGDsQzM5pJj*Et~h)yiUFc(%kA9XV{)}&@fNYukPc6F zokiFdhl}+qsXV%I^F^XL>dLk2H(mn9rULoW5?@81-Mi+N#QuIzB&DiLP?P@gvp1Yc z0ji2J0aYq7eDk5uor!za+Oe|pQ1alV6S|BU@8RX`?d|4+(@M@iwsl6a6zp&G$760=aj+L4z8~68e9Q#&% z32IMQ5Q6{^en-kqE`bAK)20>f+*4Ko02nzVA|!0bpfdQt?ttB>zVKA%VF~ZW>dHV8o^3@-_`se$c zmdQQ}S#qoJNy9ZMkH^+6UZYP9HSL)$zztM~gAv~Dt`8iXy31ZOEhrKo@qmCjgON#*_;|475^&i=-Tb6C0tO??`Ayj zSG!-GrcZ+gw{aJ8`&TIi3W&&dYLH2>WoH*XIC5y;!3d6L0cmJPs-o3khGkg{0F0N% zp>y^rBTE7yCIg(_y#L_VgR|OpTo%J;Km5TwA2GY#(FonBEk`yF@qK-X%Db2;+Y2?H zP-)WE$H^8WoJ;}wuLd?mv@ofutnyQO93^}hKLmItN zetK-nzN0&~cJZtg4Xy`9bbYEVG4Jw?Ic+qKDjry8u-J1SOMN82oYUQxog~T011Eg| zN--$&$4M6keKW+v)xF-JP9`en@U9vB#3%P3#EE^rsG$lfrE;bxkz&G$|2KuSJQ+dtZSspBf$hEWP8HI*OejNQ-uDKB`SV-nC#*$p8WvUYuV& zWJ2ta-Njusr_Vi`_{(rty|zl{4h69c2n!ObP>i!$C8Ci0ZQ7+@`*qR6-9dE&5TQh& z)fTPoP$xgh`F+G0?k{gwFQ9VOph>Bzmj*1qU$t4Yvc-IT%QvfA0i`I6wp8s>zI>6c z)4Z?jjuKPX?PuCFD;3nXBm3)$4D;O!@g>=rO!u?* zQ+0aj^vvDgZRvPn)lq~fAS8&SLJ8h#6|v>T^jBVLnvZ1qKteHVUC-*PbgX)5ngaYM+3D(-aEt)rt_6tldFz4JuGm`!>VYRTnD zQE7>(-%n|vdF(l2>7u$wNDsRhMp(_k9h>i7xu;_K@On66Fdzhok<)HZSZ|wuaCOD- z8N1HEU=RSPcdkE1EP5wQUH$n)zKMe!(5IMfLi34pKh^YT`U}!qW)E2W*^c#X>_1PM zeG4I^<(@2_6}qm7iYE}>+_Vl$E zhRD_Fc8YRHVN|H0fAH>uL{XUZ;NziIy=ouSV65MeIg3^d*D5wh3Ts;JyOwj8%$VHD zu7EB2PEyds1)Ghok3y>ag$utkJKJ{NM22?*5{l{4jz^M6>l>Bkne z^2tcoYvH^F^E>bQwEasfJu+e3G55a9_s+dCVZ?PQcY-95WJ}e-i$)dbUVjy%T$#5# zaqIbQF4r#IiAVwjU$h>j>pO4xwn-*pK~m=RYjIlc)zV&H5A0Vqa{08$r}BTde|`5_ zZfPn8%pd(}MUn4z9NgCv?2KAFD0id`0!maxrS?}h zFNDh!S-`FTx8KeEw#UZ4BVIDBLc9k4^wYrFDSgN8*ST=P!&*S6X`eT@wHtbcb7eLR z9M<@UWi2u{4w?5TR}~FaNIN`ZclQmOON4xRHY$U`ocZBCZPb<{;S>QvjOP5>6#;WL z9XimTm4*H7>zeD2{(1NO!q%rEP~NN3_lLIibvrR==3@XPp~CGtlDn_$_@6Rz997bt zvc?%b;iSLmkjRaWxFVyX8Y%#@xtfYli3x?T&-sP{pN)nIwwM}Bg%enlM_iQ zH*8ko&UtZ3XvFPv$67Ur%_P}h%mnh>k5H? ze`Mtc9^TU$6Y@ukQC3v)ddeuySL6KY&PY)H;xeX0un$OmkYg#VX|5>ZoWnrX_s7L}})jMNOPU8WRN!S-9Tlv+~~`>fqoAtOF5LwpyC z+oM;Hyl^)a0RSadi_MmiVa~ASEodpC-JF(@X%Q&^Rpm^(0syLDkyR?0lU$nq(5-|% zIn9=*-=v}?)0~!JwK+nYiQQ~Ar&}kV*m}_QQhS_XWDFDsd4w+^fp&(n+q_T5HwJDmM zW+jw@DyBcWHe~o&;28iaXJ%L}R&$zJR472sO-H0ewc^?2m05e4f=v*1&6t^y<$k7; zHB%8YY<7iGQ0-QW)t+s4ILS$W9i>DIH|^!KHJ49Zh&j}{2;%?=3QUuqjxC#3(^z%F zl^dUxZt~g1r&sC)nPkR$%IOQ2lkV@@IQE_Cw_O%*y^$31dGmlww)%0)Q4>pSYN4&R zTke4!FFs#mU~3$WfAGbyA{5wWGk>~}6n^r`lKdv5FrE`np1YiMfA_XYxdItf#$)Bf z>z!(rUh?wc^$R`KG+Tw~8!pD(xfs2taY0Nd@#sAM{_)Q?J-B-2`~pn4fm;vXi9Pl8 zp1b{8A`lwsBfShHN;r?3-GXu3or(e-3Ap^G5HZq~iQdH&3rP9CP#g zY0XuYC^oe0`k~LZ9=?hB5nKc z)?G*nKX_t}r`8e2lV=85u27MG(}q&yLhUDCPQ1HvRvTFbAZnRj6Hms6T@2q^Jpfb8 z^<1^%a`N31*H`;-wpycB9N*Kj%hGk%A8qkskiF=Tn<=-p?`s2+s>-Ns$kQzc)|^kc zIkCBqXp<_<*mxoC_Jv0~8|DYWtJ8&Ns|;+7BXQx=h83ZVX2tnSXG52}I|@E?UK37U z2u_b#_froB(ejJ;Ts|=G=<~1@Gn(evx^U8eDY3urrU2Dq`LS1z2W;cxr)HfCnm{C} z!lZTOE=-wlAezB9TQ(McnMH;VT+bk6s@%LgT2k5nu-47=&ad2DJAKeOc7McohkRQv z-a4nGub!6g2eI>C}yFsOP46FZXV&y*Hd|Fz+^0S_|hO91dYU-g_k=1i~Bu3RtN>6NM?Z|po$8GjkC+OuyGnH(Qg-bnpv&E3(#;__A1k( z-kopjkG_|$&X~as3M@SKjAvOzQ9ck<-adk&loCSn_Wr6rPj*yt#`g_-Rj9A;`pqvL zh`?4I-U3<{sH(cQSi5@A%~1yiRtRb8(Vg@0z^XoR?Zi*+&KVrAXUYC>9wXh8jZJGs zT-X!{00=;~D3@2y+!*G2_UI=ok1V~vbaeAsnM#R1m)G|UZn~vyxmPDcdv-59T3}cN zFur+{A=`IT005;#+kTbz52@4WL9caZYq;!5u`4g{Y#z{U)(=O1@RCntFdA?kTRZ8m zq7(oqc6+*@s`jVp#$p;46wm6t%LTtkMzR77j}Qg`zz8D**09qHLMAUh+!IHiobu&P zk}Jm-L;RB@V$(fQ^X2p5?r&VRsIA|z5+#>UUqG=IV@Jgb1XR@)uI*BjOkPwEQz`WL zW${7u{A*JdAMVCJJu~@>ZEE&r5qe!@2qT0PiR->@OWBN&=VC#skHkO`gEE89+X=!{ z<_lDcc(4m&DdK#rFDM@QOB<^Xn^+%!+9E<#M~NbY97D-FE0ux7uosBIiRo&&04CUs zl&6s~7Qi~9Xncz3VpGkE-TL&ETR#I28ID3wICmi^N>mr$z}q(xfT8jCBbxg1PcbBh zJ_iOTrb*@VF;}ArLVz$v%w9L zwyWpT70fd#Aug`gCs7vA=oLv4^o6RK8Wx^Z%7%y(zTccz@jVD3LI}e!4vQ*lfd8U7 zaMqk< zpE`upjARQa?yAleB);p)t)!&q;7&|yY!)XDC zN*Ep^N`bLIzN}5)R?R-d=?pv-H7q{8=&POanIq1fb7!_EtGTPK6M_v|AQF|0WjfW* z=wEaW*KkaqCfw_-;n-wYdKMDYDv)k{P_9XS8qOv?k8l?buUZqMF&e=xGYEk~3_45* zp?MdHNMu@|QF*-QTHyfQsW^hN&O87BkS!tF8tCoDrMnmNNxf&45#kBK8WvGPX!c@; z2(uXp&#Ki6M8T=~D+NUcOQ6yMjVm%cFBQsfy7W>7K!hNJ7EueOxo=RRL{$j|N>oA! zg8>krJoP>yz-m&sSMi!0K|ZzXq{ZE!DyQ*sr7{~3M8mLV#k*@`{9k=+O( zNs=5PaBoZvM;h##2eM~wIo{5Mmf6`~AQF zrm2t;9ghQfOiV?5fW*@0SIj8^>*xKXuo}Gv7zCl4m!A7Bqt5ob<%+I2cP|a8veq$W z405a<0HUfYFl?4n6d^>ZY%1HKR!YB8^E6Gz_ijJ|01=fkJO)ZAMF5WFr>ZK!OiDt0 zje7a;_0;@j3P0GcV&tqo>!c4pmjVD;VES!88hrB8Z`*w>P^2*$cw!q_f5B&ae#8o8 zp6`9+)8}l=g}S9pOuq6fg3n*Gh84NBCjBjan>BFN2hF>5fAg=sCqAQEuq7=Bsc4J1 zh&2cSV$(x^K3(`=?7gW&i%apRS0~py_2Smakj*uVxnjSv%P*h5X1g17Z*}V1wYU+x zZ+po67vaHYdhp5D7yp9yhM%9-rv_ux0svxpgBAk-0!B_ae!{2!?bt(Q6A}sLq7JP& zQhw&?7dH={{h^>9Q%3XT^4?ERoel||m1pNt00>LS)b9B6J1*x|UKh0hpw(*~GEl>( zF6uIG?zJnY4)mVhVu1}aOlIVd`#kr>J(xc!=eZPOVuSabsj=uv`n{f}9hc$-4$G>x z<*{dXeXsv~P0%8SKehML%$Trimj^)hb16y%!E@o`hZ`s5o4E7%=I!GVAf1kPTuH)n zdEQ!he}URhJlPnYLcdOFbe4KV*(n_P#Y=8ZeQCG_l<{pxahUZdPuus&f= z%=NSP4|H!<5O|kqza9xr4;!uBa4RwsVODyuxx}=US08TjVo;sA%g+Zd=gNP1G2?7K zgN-$4SPTHjVA5zUH-Fr!*>~^kq;6FhgBF0Y>7i>*7dr6b?$p5rS@%kNUW5&9UuoCl z;Aved+&{4KYRgqOt&xqa>u;DTr`78?006CChrnq|IqAK!^!M_mBr7{MBgEtsW zY?iY^XEZo07=y|27Sb3^ujL|ZaB=y)hB%YUn`3>+rkN0Rv*^Y?3nMZA=4GAH^co)- zjn1Tb1D5#rn*{*Ctj6S~dHtf^lwC@58snRD~E`h}Ro={c9hd&0{EuauL_VPiD5Z|>+9a4EWw&1LL>(ypd7zJ zIsTbdMu}3ujM3G_A^jc37N^teSmrfvIfD!PTO$l-(&tz-`fQ6TN9Xg1KHO|_aOs^< z7yuv$0?+dpV}y__D-JwD*?1+(@|&B2vwqKTCRd)mu1T=8oe#0WH zH*ndxXLS6YF}X1B*mODfve7Na3g-<*#fEiS762HXL7yd6^iC=4q`zrP0Z>&@F~j6_ z5G_?@g<^(f{yF`LQpX7m#hAhWR1FNOss!cz*Zyj=j_9&Hzd7ko(m#;R>Zqs)C`VDK zzg>|iuWYF|wfkgQMhFO@f3=jKq9`oO5~8Xq1)vyXMNzU_V{Z(m-zyIJ2I?T&_4e8A zFplFKe$;=g%%HROgp=~rmIB1EEC8`*+Blf z6+x0Y9ur$uHYo50J&1P7>v;x5o1M|=K(M|}G(nW zf{a*Rt9v`^fU2V1E-0)<`&+Y=3U*1W*C0v+n_ZTBOAv0JPZF*<`5WpOJ@hd>C4Hmjln!)r8}x3dMPWVg!- z<@Gx5EzOb=Rj>&ZFhgXH;Mm1uf&CZ6=K@D+K8$)oxb|65OwUpD3f9{Rrvgt@HosCbytWP*}RCPFSzjL zt-Hd5Z$7Jvavp{fS*@}^@~#klS9rXpv!7j(ed-N6pYiBc?7_wX4*!j+4Xk%dxKoL> zP>KTDjXj(3IP}H-A||2k#5MD3@}eZwo4#rN=fxHIx8rREyKgkdOzl@fX59CfFP2kN zYORjAD@2FcV?yFicym(G4xe8WVlD;G_5-`7P~W{@H?jz#p~=d5L#i2ScD*aagxR9+ z3gO)ga6=BCnOa7ms`Sl;lZ`lA!z1_Z3ejQq=)1zn!m8~9J5AJk-dWrYOa!0R8jRkwx78# zMNJ)0?#(-h(eJ;t*l4wbvE;^Qk#`afmT_nQWX&H3LO6mpe-EOvuLJQly?H%{xAX7M zl4>m0=!7}u`u!FDSjnpAk6vG%jhI@~SB2W6w=VC%Q$lk%EvZc0#+|+%YQNL7em*tl zYNb>)6smV9CGzUM75Q1^4UvZ_`cZhQ9qGG~qQDOGzJ@YzR6>XQb2k#1xfBC*W zN9A7Y_s^*;tFnE}zT>S7VvTKAUJJByg%r0v!h@m)MRKWfL)h<FJTEGLxQu%rN)gaaJ2)=+>U~P7WuD9o)8_eC( z&$Mm$vS=npWExd%$qkydkOd-(5(NZO+E?`&)y-F>Nzf;;*1|KUSML~5ssH9e^S*CK zD3KL{04Pxul>lPIgF|ZjRIVRT``1_rDUzcSgCfa%y;^frYeMy>a}im0J%jEQrOARAi4TwCaFy zLz{T^{(4&7lKPJoNJY7}(`R%b|X)y()bDr01A{K{YMY8LL zZC&t1rE1;gr)=KYnaL4FN_mg6v+6vkWeD1+nbNGHyR0a``8+AqnEO+OvqS3zc5E|m zikl#1XSHnC4cPkaoLaTJ&5GZ!qf=J1jDFE1w0!Ob&b9P64WsM3m0!zFZdc2X(Er?< zr6^JO;(hiW9~M})(~heLn^blqM4^F=7N7Wa!`@kbI$WsFnE6wNuDiIeXT!kURa+>* zhQf1>?%sa(mzIG@v}^k>T|9Q%_KllIyGfaBk>2}Gj?7o0-S(@8T2%LNFoES5L@5H& zX!;bdRqboKS3(`f7FVSfn|In5cWGQ{?3bHI>g~C1HKy_4HTUxZs;o$o0sy=%xRY1e z2KlP?pM9`k&5pyBRkhs8A9EkyAkZMovZIr#EU5q#*h8b6*3Vb9en9&uq?d{4@N`H- z20$p`X{-EI>*uS|yW`@V7)5k}73PfWH0#)*A7-~@LG^DxXhu61A_<+QPWQ$9w4c8C zcK@2T9Y$^3I!r5O>n#PzZXCUQTYdLX^lhi-g<*s(K@m^MW5aKBn8!-Nzps>r}~=fuvo_ zuXgCurGMYD2WM}W6sgtp;o(EZBufBPtgqIk4;8_kku%RMo%Z*E339>^0^j z`MU*5ud`{`iY=SB{G?su#s!&zjSVmFrHIPoL&r>|s*|@C7Rq0$@>y8yz^=}3zBg}3Y-E-vh3rm`}u2cOhS&P{^Uwzq)4sFz^`iM#I=*UjlaI-!U&%H!Tl4eV7FOqf|#X{Dt4RQYLk^e>KkTKq95TxE~!z` ziB|Nn3>$==+=|qebc+uO&y?XG$P1!WDObMGh0Wph8hG8mC)W0*B%AD1HNI^sWWGQ} zi!rgOWjgq2DF8^4q^c^Vg!xrOo&2HuSl7%Tn8q z5&#)|r><{w=-6FW>(#E3^_fzzq&7Y!sGXly{S!v!J1{BN>CqdX+j}EQK9m$=$y&bg z)}pm_QK53x_8KM!Gqw3@MeV;)q)D}~P3OuN^Osc$0II4ILMTA}s%}?LCN-$aMO*V% z@yJnKS}_){n=ip!poa0;U9oa|9YcZ0`ob;L4a>spJReZ|>5-5EjjG+>c&=>m0EJM5 zz-IeT%#uQwl_Gv_TJ!s;n_F6!YH<8U8n~7`95Qj&u-@Y)?cy-f`WCHN)7GTg#$`;hn%hTEuzIr=pR{S+xiY8bUblpI zYtp4ni>~cz*36gdzZk7+gU_nYtzP$1vB@QUw7hR%315~{;#aJg2BGrxi){Pp%8YSI z2l#e9Oa1mq3ZS@D2;!b9P@ud-EIe0YtU-$g0GRB!fIf$OhlXjz0AR+DmI*ON+j zgvhC-5>u!K0H`W8=-h1Y@bx063*NZWd*!8Y`C7%)o4IZs!YmFS-@Qk}PrA0AK5o-U zy+DiCsge|VFFKj8)u5>2-?NQh#P(+z1|f_PYj7`=ynk@R4#VcC-CG2SDqpVr)09$e z>iMYea9AN`?}}S}mvwxt82Ubi->z5iaAEqc$gN{CW9Q|^5`I@A{Zd5?VWGr|xcL|@)HwQ^15!C!Vi zH_IQzmO=nji9EA=%bHu8HXKW_lYb(4l~R^v1kU@@-qjSlPMCO}e zMgeP$Ry%6k?-Q+T)$mMK(Ov2QDPS=nUM2cM*u-Q?=zTI?+mFJoN^pq$@>*}UsSdFWPE6;*k@zVOeUtN4;Nq-U^ zYgHKy8@+A6-VJU)rp*fH*h!d0PY)a$zjfWj{^cLU6NJDX`S7O2@apg$64V&5#??*l zXja2vK$sw2_)rPCn*&r;>{%TFJKMf;bpXaLHA%$KOsyKSH-W6fL9KOA{Ee@14l zI{6*SDMr@Eq2W>Y9wwyi?HG`?v3h--{y%e;9KSQB+DP0+JFd7(HDSl}L7xAcPr~Wst%d zJs7L}UhffN@%3J{>iSpeJLxV3V2#|a`jzVXS6aC@{=I4`LYUYyWXths5vi&*#ZEtp z5{nR0C6&FmXRb&T!7Bd~iZW(iCZq=yi0jpTt!Gj9yYU18Ak1(a1C)Y2CBo*Dv}xkB z4T=83!xTHB6c~gB-B!C7 z_r4oPs9ne^3SmWLPWCdPqF6B50WHFlI(~bS5?&!WAcCO zU1wlaMc1C0+jmn)LJ0vvPeQMPbd)L}ARrb#0R=$>M2hq-AP6F&Gz9@cdPjQiz4zXc zn!dZY&7AMYO_t3jgaA=_bF)19so3jxxtz!PygTcJ6cl$x zr^uQUf-xdQyL+l|8T+UfpBg30UH>zdBM1TJc^)Ic2wi!Ia?`!=WSa;Df-0Gjp zf(deSiF<*!)$7@O+p-;$K_}!nzT<^5McRL9gH9#e<8Nf3@+quHmO^+4ueG z#Fa*A6{9F*w&-(WAxPA?bHQfD6Q1HzrwTkRI{Gkm^R_! z$g$lLO4MK0?R^cfp~@p;jvlUBW%ZdD_5SYb)#i^HRkD0r)VI=g9s%|%vG-QLI^sJC z0e;IyEqwpiU)$A)@!z-b43lL9n@bYt!dw#9Xh64Ol0kq-TqIdM)P)c ze{S7Q!vcqq{&3Ib*XE5J9aW|c9#Z{^MUTaCh_P3d8tML##L$rqTUB-0=AIDg zS=WDY{f#l<2tvS22G&3cLI7GKZg+I=z9vy{X5nR5ZFGT=GnfpnBB}I^vHeJ%zM%J5|NdX~2 z5U{m7C}ZF~)t;Aiu|hLewC>nsFwa@#*C{V+sR`_4OnDVi%F0%?R9uo0d!nX__5Z2k zxjx-ist6ck-UVvO`x-Gub%$-#wu!?VbwtEcHRy@vq)F?BOP*UdrLSA5TC1AT6blTj zPZ3NhU_uB6MuBjIQ3}XC)r1sovUYWomc`q~8P8B?gd@r77ZZ-dILXV)m=b!1d0LGH4{*#vQlL`!QlLMgSRhvcu z$CD2xzY58TscuFBi{B+l9VESK5e>LM!crbWlkSL-^#jHT7;@*8VT=%%YJ8_E9|ddH zcfgW!6g&su{@wj($y75>UVQO0KSED7Gxit*AR-0WFfd91|HbEN0A!lz#fn_L7!cgi zexB#8KU!ry7-RJJwoppB8j;0m@nktZ`3~Jnm8EzmwYFT+>(=^7N@Qn@n$|*r9o^dA zzrwIprG!%~jb}oXd(tSSsVi##c4t7WHUXFi337_hxpfO50IUSqlkg*nNX1)o zdaXClmr}0k6b3hA@MMU|_JN1CWAyBzrqz#F;e+%QTC%RT#_pMGfxXvE5)87G4+7SB ztT!aR>sjmVFSMn6@)u!;78lR^2mB2@7%$8{VTH&kr997B;N&KSqm&AQz!>}A{Q{mw zxB%exr)I*HEo6E%+R4ATn5HR;qUTw}P0^I*X(k={ALX7fT@H=2*~N@}iQtTPC;@&x zzV}QN-ZusR$jMC#4E)=U(a%X%@uX^xF~As-iFp8H;*Po`b4V; z1^hi3(ns!tzen!blT-t{OGJ6H4Dg}ux@?f%e z+fvq=F${wc!f_-i)|J-Uu!1N)@yT-3bRc~--Yf6;L#ZN?@yk}<|~-PCp6{rFy2cy$x}eBwhXpZtT8@zcC#hunWJ zY{S!HbuaJ0^x`gbH+%fg*bkTxY|*z{y)M08R#o42^ob9pe3F(ql|kK&{~HHgLWn0f zgqJn>GLwK)*$`Ha-+#ow(?5c z*e{A=nuz#sUv(Ig>TgnPjC}$K8LG>X z;LtqitbpoHmkIw8Ws!FF1TgA!7*?~pze}Hj>2m6sG_O>1(&ujpkWO3o^xyE3`r1m% z{%^q*fCc=XfAeKe_~d0#3II4!QtUQa;`Kz*<>-+dHu9831=QvGa_ORAO4DC<0DuKq zu`7z*rq~sN0AV8A6h#p+03agUZHiryWdQ*aZ3<4VEs+!{`3*7#003T+tc&m*282YL zqS$ScB&2CA003vtvv^8V)tO$o5C-((0cDO{ht97+LYp>NOK z_+yiIoAmm*XAsq>u4#^hxR?ZkA%u|TNQjG$O-OKA9LO$BoAmK#v4kLun64!_)P$JW zM2F_R2`SCdW%=Yuof^L1q;ac;LCpEu*9(XAY1w7Y+%c`QJHySv$vNaVGFZx^B3>r%_fXLePG}l2ILMzumdt(ltGi=0D}?&d*vm z`fARi{*A&?pU}b3@_syS&ab-#g#)08iH^kBxP%1N>fEI}65^s`oh}0qS=src7A>ae z?h6>s$D1cMYrDrPegObAAt5e0&fzo=(-RY1)>Ap+9jUYvMFl_GaD8v{98QFgDn$Ko zXkD9+8g=;gtHQ{oXQ?%7$INCe-|jK3cTj?>#kK>TIyG@_@Q=$gwJ9}}k;3;|7u zNw6A#I%DD}HKLs%%WqEOWA7z8OhAb0YJ5y=e7rSy(4C2KF|i5pP5?wC@yx`5U$iT$ zYVbVp0TwG=nmCbJwhmZa{s5^Bxc^{u3L#|iKw^vm(92b$`Q$&3Qq&axZ|SH--M^SK zea@g3L!)^KNkL!EnzQ5H-cGNJRAa5DFJ5|Z_3|UXRR}}C$wPmez4_eSAjS}|&?cQv z@BDWBn&r#Z595)SZbHD!V{4Yo82|J1adU2>l3iN|j2t#&Sf^iK8#>sJqjBet&6zlD z)bx90D(Bj_KS2=kEHf@g@*>fpWC%mgmCN#{@CXUS#Wq_2ZY%U36e(!5|Fw+~4fmy6nW3 z-xqcl2_if%@SGcIpk%LwC-?pFdo=_I0Tr{Bn7n(<^22{j{;{cPufO8Jc$0!dtg-y$ zG_N2AP*QO~s~;z9Y|^~~MyztbUcn37{rKa&aqS14W&ZEZAG>exXS05pH>Aa&`@F(b zW7W?yejPt;_LNOJ#w_mk@|g>VHu@sCZu7gV=gyfp`{eDIr9aP^^V5*XET=7rw_5 zU4a!lE;+q%@!>UJloidVo0tG*j^eeY>0gfhX6T6dwi@{Zy$o$I^jZU_E<3jUhu&44 zG<-RnDQGt}6uJm56bvmpW7i}<6!GJ>4MV#}A<7yKo3QN2`jy9)RxT(rK5*cMH7gFU zo3rZM009ujTI^L@i~q}q)r>=wyFG4dO__;B&G@Ny1@^S1;J;Gmi{0t?7$ehUKAr26 z7e^@&0&5mB?_7@)cwVwA7=S~r8DDgMyXC@nhcprdw6NPJ?HjaiGa&K(4wZqbV?OP$ zbWfbM=)j~2=N9y9+G6R|;(1g1Y=C|+`H!>uwbOTp+U#Ljwc8949DDnbm`@f^Xzfof zm{;f5Kh(GXx|^G>60 z-4Yap5aD=Yy6%!9`GZpJ`78xWE0^M&Rs|5nxBuwV{FBeVy4|8dv3#}O%Q>~}2Nmni zy;{9`2NIK{d+!te9KidM@s4)jPzJK zy>FlP%}3XtIX0Vu*Y|7xX~VYfcRts4U_AuVpxy;KmTS_!Uh7r6ZxaMSrSI2{`J-{2 zy*Cq^5AOc3XNz`qn{99u|1ghZQio1UH=mo-qD{LFD}m<h5eI0mAF#_2H&qxK6jS#mGdm^eEIhA z?v4A#8W;LEdVlP+3uZv=w*!xT@aFp;H2m$|j!hsitYP4qHdWvKyw#9+10jUL)GnjK z#dBoL5sMHZgy(re$Unu2!1FxEae^RNR>l8x-;?LIFOz4$XG!_wJHjWb+&8j&fC+(9lBd-XBpIrIL-&=9*lOUUW-iJZX4 z-n^MV8)tPDOY>;Un3$)S{cfC#U`z-hlCX8tiGi)McdqB0HRGyR+uDFaQHA6jV^<8$ z9~KcJ^G;2-2MBHma~N1sJcvgPvvY+?)pM1vTWzY&am<$UgU+o>8*4s(e^j~^CDzV8ORy)m=EJo@Q@8lTE17OW~JPSR{;A9_pdxc0>Vk%CQ+fr zgtCey{eaON!C7#zH)}Sm7q@%mo_N9YJ0uc+yl<8Fnp8jzjJ&SMR?`Z*LdHi^u=eQ)W{MTDl zo)2gkhAe|Gd%`C#j#4~}oj&VM?Uq#qUdR!dPekmA3j+YMRkB^%GHce_xNLzOV*pH7 zRmzy|(u|~@jOpEmnuf0FhC%V8lSiF}^XIUKRjC$qWkaHl5Tm*)c5KHrjrwbLyjgSJDzyV4>;Gyzf5OuVrCO76yQXV(zIgctHwsOf)V z@%i{vd2BJ)j=Ks3+LJU|w%S#5%P4u1(quUR2K0xoO5P>i^9e{9V?Vtn|%g-2XUN+U;)s90xy;}5#N z|8c*e$D0?iuUm2S^}!tiWg$zRT>jvgHS6k|?cNf3K6~MO5_lwZV1f}Mjyu1NpT2DV z)_VznpUzE+F*$JfPL2O7dG-=17Vg~th{Gx8od{B~LRoDEN)(7c@<=I{j~)GW#;W_W z#50CbY;=waRl+6A+p`4P0AqZ4UWd27d42ZsYzlws;)7D54|e^r<@A|r4-*-}*km|c z7Od+g0xSp8`NIc)@zuQ6-AiMWF^Y55d#6ZvpqKLxWB&2AL*+lIe)rV93h$RYa3g_F zsrs4D3fCw@q%6hl_fOr!%yH&%>GxZ|A#J#a2u6re%KJ+kH5oQ9ueSx+k8RkzYx~K& z(GFhVqxUZ#)cnKQiPdrii3kDar9$ZP=|3SODl(l)UU%Rm)79tGqF?F1;os-+OR^d< zPLpNdCq8)&l)^kY)34F_h;BRoJThs>8^oZPSk4_nI8J=9cqeLd?9UyQG^fF1DMzJk z`mIkIRoLRXIJ{*s9WcQd0ZRUew{CT>PDzd#*RNHO8-`RRlMM421ga|)v_WABVx5S41hl^(> z_Ad5*vzb)(=C>B`{a?SkTex6|1-5q%7^5zq|EbB5*()#H**s@K_@D!Er^;UW?noRZ zn7@5^4H>lR=*{oM1o&v@p@SQ`1l65()VZsKou2--tKab8B z*N8JHmiS2r_wBrMc%->k+16!1)q!T*#(9UM4*t3S?X0rS^9Y+?emLW^?fduMSzD#B9T4UO(cg8b=O=4t zeN%nQfSwyl4Br!ddhYc0G6O`!4RcoYxP1BKh3+iQm9tULt&gs3{{8K?ZFXUiFv`^& zI}U0#i*iO2#YJ~(i9%ZASVE@1^2{b`#L^ym+Y z5k{DE-5C5`;;Ojob0?JN^^*fI7t=|)qs-)V(Kap zB(Fwr%ur1vipg#yU{rHyfH_H#2%@S+Wm!ZB=`NL*CEaC6Hj%oVSW=j#@v@9D0&1!T z=8=I!Ss(~ZT{AIeCIi46FG)fg8UYxwg%9bNukV=cN>JqN;Zcn~S*X|~NfIyy>oJKS zi2`T2zciOh5m9Usb-Aq6IY3ypDHwsNX(nYvkR*ZVLcZyjXO1pf z24<={R%DJDx~7|maIzv{giKvC3~J3SbvcuA_b`!dlHt+>B?ayo*5s$Lr@>TJgCbs% zgp^S$!$sO2*?*vZsgn;tQe+Mzs;jyQ7y}`aDDeoWuIdbsAj>=fmr5m>H#CC#P#39r~Bj1W*$Rdv9E%_cBI({ze3krbI=q{|UIZuI^zwDm(s-IN`uuImORf+UJw zQv_7i41|GFUX}$8Q%b(twejvJHRfMUYSztkO*1IwB}wAIG&IdX7z>ib5u~dcWxxrd zDDt4|k)Kag)($*=M@@Y!a(8ItI4*tc`Rh8qKdobZn$AY|fd2+lIz!JboO< z5kjmEzyG5h<$dzcikAt3c}eD_WOKw?PdMp+UP@uGD0Z9Y>CigU@?siiTO!C}iW4;_ zKlv;t%Sq81QIQcsvQ0z?@rn&0#3^#JVZkdLLWoNqr6}_Vp>(;vF`>>|y+>bDWFDw` z@p`Ocx5*Mo{g~G2SF$B-9$ryWP6`%eSwIK@=vu&_ol{PI+U!~aN!{E|NZx*!@YcYI zAS%L>N9RR}PyUTpY@T-!75QmbOZ{NHtng_+F?x9FguzLQEy={me&7=D< z5yFZ>06>y$A^^simn7NFGsYNWfDq<**_Nc`i6AK+lP$W=R+L)#XHnA9c9;_-MNHfA z#mO>B_6?gl*K*a$94iNXbC#EqpPqPp7W0C_Ke?;qF(FtK&;9f{5f!)T?pD44NsZ4l zf<0Ef?O%~kkwM$YDy6c1b~g|7NQ%qk%yqA;rAn6vgz$59VRjD^rA+0w(kUsW?x(Zj zg1&AZK6!at>fd?H$-MUGkWRPkSLQ*zh6fn4RL7C0YE?H&5M#`fCe=&3d1_M6zo(vR zK@cn?uq>OTeoGmfOiOE`r#tH`f1PzscjxlCJ$TPl@c>}4_+A60lX&NEK zns$q-)ig~(5Om$ZIMcWXJ#kUfG)a;Gir@`W001BWNklt_RKbR;_x1K&dsZSw*a#!uqwG2*W%u^Lc^Wnk4`8NYG5`e3G)!xoP{RaZ2}~u;q`kYK&o6m!qa(m_`zg0%Im+NuNbYS7p>> z3=jfFt0?n6>Cs0+{$IJR)W>7g;DDM6$}^u`uN`Om2m1w z(`BlTyLX+KV1xiM1_0LV@jOouqNYicbwGkr<$yNZW*P_)1V9;$`STugf0@jTk25V) z1xiioxjTH~ljlb%-O0Dxux;eV4cm@RE5NC46_cy|l(DuS&t3(PcNF=(T+{i6dQaucjv=Xv!{IOm61XD;GZuaX;v}n$A?!A?`=in zoDuE6*?9Blx;@|J#yS85)^5Fc^c&Mo9oVp8D5j`t-=7X%U;SbK`Hib&Hw;v^`w!b5 zoSHcFEd=zlx$CA5f4%piy~i$mBRGuA(N+MFUyhtRalpD8hq^Y6Faf9w_xp83gYTE_ zi8<7?1mOcq%sPK?)4@r(iQ&xBaM#`WGL%{yePvw#BB>ar_%}z)+!b?lBQVud>o z{r!i2Yi}I>^4%gj@tbhsQ2PeO#@)Sersdnsvu6Pqt|$K+*-D*%i{*ITi@LLOoUm-=JpXOgZfkyRIud1LtYom-Cl;xA$&u-NE5yLR8) z)a3Q73~{FZyaB@X-Fth0g-ZDzS;Wli3VwF* z=K7D`D~u>(Ca$qy)97D**n4kR(@1|^(<3{K-gxuK+U;Y)kmkzPV(-nL6;yG)=eN#4f6M%uKht})TugKQEL$@Uy7*#TA?BNyT$_AC(ek#tdY@&VPED)%3}ZB*EUZOgA#2oIKQRhm|RFgx+ug0dkWK8W2?-IizY#0x@j z`JpxM*YnHQZCbEbW!QJ zao(I}by^KLw`fbdfJe(KWNGrywdYMG*B8Uiqzo$2Y!%+=7q+TaNY!gqMwZDcA~7Iq z==nNX%LIPZw+MUud1T2S7VhsHl($%k$=EMNQW+Ng*7SP4<&Q2un{_ZJ`D%pyRK8f} zJ++%P2!DYitfdn<&LeLd7$pUUx6j%lXNAcLpLT9lgmFTkjRyc;2@nKnQMaazTCMs1 zjhaPrwRcJ>s;8c53b+-$+kVLnTcmHxwrzxRK0-mY4=Mjwa9hAbR@uuGFSi+yzTj_F_U%|THIt4VoA z>?rwyr?a;Tz|;Uf23rRNyeLkF)O+^c-04fhx^nNITz9#E}y?x@B+ zANHN_At+hLv~|=G3w_vOwu{(yjsLi6y~V$M+_Fe$(}xt4OFxw=)JFD~5Fi9d@Xr>z z?T5;xy7!;)uArmG`+t8cXR&7eZ~wNqk?r36vRPX_h}}}d9zJB^WlYu9MI(RSZzBjH zMDx^Z+ub&|MsQ_k;g?Y|Pncte-n@FV7na zkJNx_zf5nrZNW}eln^KR`->be`UUv&9ClndaxkRZ>~#~XMUXVYL>xZ6{e*V^(lM@F zR2bVgaqj z8-A)8nd-8bDE@vT&nbZces&QU%TfOQHMdW!S@fBay&#VOb6nhpsrPizh>wvX>Kt0R z$EiPFGW#aMMxG*7bALK<*P~N|I+ZFC#tX7dk$K6_&);9k!~g{mxofMo%K_Zko3wgf z3<#qudzKzakU3|xnX5{!%crg;{JD4My~z3j5@!#vVa(YB{1ur?X@#0O@)zAWZL3P- z_bfg9TDSx}cYWm+$)7uWO{Ur7ECOs+qO*nYy4z}Goe8(Ob z057U`Igji{Kn#UezQ1?R1H;@mb$PC+2sb5?b$vm$*=@XNxBCTn&uuyufIGsU+N$Gu z9%GVtWc$fNgML{)wsanh2w$_LzH!AFGw$jsC|o?q^sX}_MBOs=d<=)xIMWCSrzaO5 zjL{PA-MDfmxLCtHt%mK2J~wq#r2-+6HTYL8iek-%JDV{z__--9JVH>OA4e=(=_q#i zMyzpQ?O{&9D1U>pHEOTCactf44;0Pcbj7W`Uv<&GnXRhY4HGy~@v{knV)GBM6O0ij zrq~x8yL|SpNE2K^xn)E{E4Es5`}pd4pBUK+azya+Puk0}#376nKYz&@6f^S_F0^*a zHio13t~>vFZVq_v*0uvSn;z}51#muN$|vbbdZ}N$A_^E$ztCWKY%-*%M_Lx^{p0D$ z=ZiHur`s?P1k~zK!8@;ZjI0u9vv*oNJ8)ZzSZ`Yj+k+HFgdAdgj8k}cc0<{3T1mGO z`kp0N!U$o67yuwlj0YFak6!-an1eQ+0w>xDbShFMz-Ie&(Y)YoO&_OP%orh{3=z<5 zWd`;Sdq1*LOvDF!=j5oEr6c$g>z5sbtvHVnWXT)Mt-cJp_>Q+P&!$Pz!MUVT4*ziQJq zS2|H=$C+4+F@P1dOJhS|oOD0cR=!`atnWotj*DuuYr22(AX!q|8l2)x>4=Xnn471E zG&x)7-57>3AYZ1RPhK9SOg^yxq!D_~h&_EeJ1LeFL5siJy5q4~3;VWg`~%$Hszr|P zF*IoP)Tws@Dvayf^kD*@H{npCx7IxvO*XQG^iYMZ0YIrg;74vbe^-{8X@k9A)ms;^{wrlUDuy zU5j%6m7_sO+y|D=&ibdGrNyMrvto>fh5gnkx|g8j9I<2zTs=TNfTJg9PPTCaK2X8)e= zB6BXDa)C&(Kdv1%sBh$*VB&ut1Hv3{S2!yLk_g7s>33#qpK|Jke({ePi?%F`8#ZNX z&5MRDaKo^{+pfgQ8P4oT$MpF}sDLb>5=GISR_^u-O6svmvz=cK=|Usx^3qi)VfFIc z@6DP&=7AaTVDIlgFSs;#Nvr(IrOVOZB*#rI7gJvaMX&E9^al29

c9nYDeNPBi=tPTG$UB<$RRe>jaw3PFSPtso7Ppg;G9sHMv*UhP3^}Z8J zHkrdncd3FRW1y8R_{491CyBw}V5s%9k793aojrU4#64VOztM6~!3RGo4hVT{N&5t)Wc zIYlB#Dca0Ph*Mwt`B3=6ChL#JGhNekYOz8PjDb{8}v7l2{|Cw+Rd+o$v6 z1xXeK4k6H7x}-?St~{!`G(beQ$(ApN>Z+zwPLw6lt6&&RRn<+#36dz1BE2Vcxzy+5 zIkAFlT^0c~RhPzyXt#L$N&qnEby4>x~7}fdXq%KZREWSR(aMW{Uc%+ zhG$_D#+V?cssDSGHk*R2<`>EQ2$++TqVZTz+I9Vxhl446%O+*lFPxu?EE#s1x#Y}xvPLOPZXT{5W<9)?Y!srCwZ(BOnAlf)g$=oNwUrJ*pT#2tk^_^5cb-1DfhDCXZL(bkd@vq=qHPL)%h=du~%p7=+EQtGBEK*>pcUflw9U3VAidJ*tEFSF6pSo^FB zSx=O*2q|7nGS1-lw^&pd5CX>B0RK;mk9)!=nP*EOgyn#MzXBJPELr|;D8^Xv5BQte zpHiOZGtY2QZ1(2{=~tA9+A~8Tbr)R=QM^nXH?B}hpGM%6&N46zGtGB;X>d2|&x?HT z$;D*5yGRG&9`WD)6ldHby9XI?jYF_>|47rhG8>zOTS{rjKlVebWmg1%PZe zpVQAL&n>)f3VibSOIpRJPx8?X!${MhvFesFLhjnz47S;|;#dS@&&ub&qI*;7b`>vt zsmvOf_0U!ly}^nn5kh#5dtPWsvtPTrKq?b$Df&EVD(+U3Ziq@AAtnUBOe(ymxZR2k_iQSd z!BH88;kNKRXwDHr$Z9~GxyJ%u_JmJ-DCLt^QC^+w2}^^!A?mr1=DB(&rZOd&S6+jK zd6}CpZlx+bmxbrUY6GLLSt$M zTMP3tQTbXyvgft%th9Bjr6B`ADakdgj1RABu;)cAH%;Oza$xd_Pcj#!K#h-Q>Fx?O zG4WM%BDfsRXXq4!sIJDx#5q*s$sd^+AFur@4|y4^>IG9xNHG4=88A&Vb!(E0>vYdg zQO%X8u?&7Nm7-69SWHb+b+6(a4CBMf2uPm-d)QWpSxHg1%q{<1~DLi(Wt^j@=62& zqnuyXLdByB7S72ru;tDlQ9LT5L{wy{0s^Ih1tTI#L`4)W7$_kzET4N4B8%nYJX8<> zU|!A@5fNFUaMnNp0D^MojVKWnQ6j2v@d65B42fZp5fQ};1&H`*kDUR9211R#C-yWU zPtiMoP|kw61x8;?wb^pz&zap10LdXa3zsMwQ8d5IS!vP0D9RBP87Lq|Sx})O5haR5 zmM$71G5}`FmMgMUk?@>;z*2U50#>N&xV2q^DShgLTX<*jPHYn!82eOKn9$tPbmh_E<`KC#qElG z;;4L{kz`U*h)@2rD8)=v@Z;YX^~x3)(y0HZL7;013A*ZXI$V}EFg2Gm(cyCGR!XqJ z*bg7JiQx#sh?#~i?3c24Z~Hg-Ke^uygej1XSp}$ z{#q|6FxcOg230{wyGi<<8CW0~f#z~)PN&nUF+d1_>Y6jrp{fR8{`%$_Z&w)}&61CG z%uKj;uv(3INKQIznwsiNbhuOl0d+Z4D@jUoIK5y15K=>%%-%k?*K3l&fC|}vIy*mEJM9(boL*8qcb4+4-YbB#Qe)?S+BiHUTS(Td0iZ&?SxZV62+Uir-HIdQ zg6+28ELo~eSz71yT)|lbQ*@6*G-sIxAGau%y-2NJ56%ykuxJm+nk^(aFu3ouKE%l? zOjtJX<0vt#(z3N3d6(`rCA!n8yIe_=fWS~)Nt2Lt&@fyMr_-S_KwxT#i3UPQb6HbIfT>QS_xurAV;(tOCPIi&!|%^piPO=*}D>xpK|U#8^>&6+iPut*ps`Dd*CIt#CK+PJkrQQk{; zGhKD4hRfm9bcz5pr;7qYV6~EAE{E%jUq|GKdFWD2#;ox>oetGn##Gl0RkNNNWBhR1 z=YI7+HdCE!GN^dnIqsR_5w(I_Pkn<0Q~;Lm^qDs`P17@{pHga?Cctx#mN91GlNXR% ze@|{_owXu}2ke?2~Xr$enSrJF|+9NMts%E3jZuXwO^7mePv`|x#D3MdG%*A8vldi31^>%WOyd5|TQ zVFDmTPj1_8{}V$?Y3I7Ff=$3F+1dfi?YreW+UP7nlJ4}MdjG_qGk%sU);K%jlSPN< zz?Jg??p_ZomuEzSHWweIa32{V6$cD@|Gk>0D@Dyf3U3I7$E_ZwU%9B*?+$3QdUDKy zp@pj7FpI8oeA^{g!v_ZEaZ_Bb%RBqN9`fd(`d`;w9QsDX$kiR%Pdy-rn-Is>8r9kL z?R!i9xC<+HU|z0<$%Wk;)-I1lShUMFpys)Qhxg7s+oa!~zz5y8A2(PRQ1&8Dc@y<#GIuI&iJU!k=uOJiL>7dxpg;@tr|S?6hZ(@ zDEa=BVMT|u92i}??T>>h+`g&hb?x}H$FBBc+Jy&&wHY@&`tHW5(@s|UYEp}$aj`)F>K6FBerz^ghPlOoib&wGl9=}r{{)75}1Iqef!?S5#uifS+i*i zs#vS)%>%2qMN^?fqv%zOH}BcEx7*2aO{%QBv^ND^x}oLybnJ*S&ceALcW6GQ_sN6z zTUDBWMIL!-+wO+VvUTiUD0|pPc`V&m*DO? z?SU(Met9yM=Y{AS&fKrtjl+iM;UCMWV~QmgZ#|dlcjxa}c9KW%?AdpB7b6>nk!BYw z3oxt}S)QI!%OHD!5;4XAA$VFRdn<)9BXK?}dx9~a)6XX_ic(ArsF25)emjxpB&2Y9 zA|ht|k9~&U&evx9g!Mf(~|xBd{Alqpq&dROvqZfV$!LcLEO%%lLsEV z|I_NcGPsMhJl%oV#FDjc@uL-}Jel zR7>fy;5dR2CWIqt_*i(kRM4Y8?j=DWy?J2Nz#pACA1#>DW^vbR5eKI>@4q2Ov)P^A zEIMZ4Nl!yeh&eKGwBDplafA^tC_HRx^!!go&AE;YlMwp-=zHZ01)KTnic`AXa}kdB zfJMxGRMj=T>Sm$a+Cu*G#N351Zdghrf#)%R8I>>i!n~UtCt_Y=6d}XaZsDO;I+9)M z-pJk?VUi;}&+C<%lzO=DK>~2rBqTjyisLip1&ISx@PpQQ4z-EZ2_XRdJJUKJ9bHr6 z*y;~I`uWI_L-vFpnl(+7B|fEdlioS|&7hxRgRibw_QlK{BYqt?B3rP;RTKKCf z`pDlFk7+Emss)r{N!b4NSI%=+Kc2ndC;vKK=WfhauWOmv=j(qJ6>uPsF~ob^2#BN} z8b6}Tv3Gu0(kx7y@YU|AUEW&I_guvJxqYuE$|EM0tW$RJ(9st~KbKOW$LHaF8})VQ z`F~hHSop17*(l??ecLJ1001BWNklN>+185DR?qXnjH_#vkskAV@6_g5aH}Zb!q?}0GmK$zdglMy9ux@dt|ZjvtwEfUvyd|V6nDA#)2y*a9na6O^Z{3 z!#MFzq6Bh*VfXGk1&OD3E(HeK7()o7G}~AMkg%x0=sOR2jtH{I3F6Hq<34(?K=sN+ zMvgj?ii^$C^;VZae0+WnoU&KZKh@d8H>VpI$%xKArn zwX{Ft_)sz7vC0zyQ{L%#z@d0*Bch1&JAD!LZkyju>}p@mawvfnFG*!dsULmXCj9*= zJGXyatXZ#b>nkA0b2_|HE2?4pStCNSl%CS5@YkDm5Ba=Ir=2^?=7Mvp*50^$VQ`l@ zQ6IGw>4mmU$0%Wb^M-G6ForR>bKVTo0K}rtKgNROh>OV+!l~;=KP=G5_FA{C^Y(F1 zdS4>bG)YK4oA!t!#81A_r+y#G!+^GvYIf_n;?jn5O$K)PPiGXk5-%vs$Q#baAf&Hf3Cam=i?h%Xn1ye&JsoK56>Gc)yJaGZ(g~8%62`DK4X0wu3dLSisl!r?P4olvT|;*aLf1DwWH>r2a3F1BZ!EV zJ2ts|+H^0o0{Zpg3FJ zfK}s0eKq6yn~lOTLR7<*dv?#~$9cteFt1E*UA=y(di5Lqetz}D0h{#FRZC?Hlml}W z%Ic5EqXSjL$}}iiWz6)G)9cqi7M-n3rNVvzS>A3}94nRvd=A*Z5W0XvvK?M zENY3=pRoR<>$=w!o`I3cl!ho}W?*XG3IIe%dT8oS+tYPj*L7>;lv0aVDV=BJI8GD= zl;I))UtzINUJ9i!&s`h$?s{mv;mY>@?-yW{sj;yD2vaRKRu`j}t-N3D=$*}Z&R&U8 z4Jmu2EsopoRg2t^cz)=+MO~^I?_?NZ-4XAVc*SwXyt;4Y?mcJ8g0}5zji-SL-@Mho z|JE(@Mn$x%G2XxgV`Rj|m{!OhXk47e@dRUxFn@XF^xw00-*k6Z_`y+!6B&mQP$MQ* z$7w+##`>Ir`${&iWZggZ^!?h4cF$~kzkk;ika&8?nk;J{9cpEMw_x*44ioI$zlCpn z^!AE83a&hI+KG$vTzS4a2`B4kQ4?2nn{}b=##{Tp{y4%g7&06awgo*pv!3U%=Y5$$ zN_48f=g?U&sO#dgfXc=3#a*@E**c2$dwVJL;)(uj}NO>fchMuscS0dm}ypVr`?zR11ood!2+joNy3#}`fW8zw@`96ey`kn7iX zuYC(ttzhGBo9-MRTlx4GLoNcsrfIL+p{2qRZ~GKuW*VBR>CS|>m_!qBSnW1*PwZZ_ zyvN|WeI6;YuIieqJK|y!otj|?O~(GZ=IrKXY<}B5M*vX0!IL+fSRhV(XZH3uj8iCX zFddh-Ys+sQ=2m}mR1*j%?cZ~-ls5ayJ&F+qfUyJD_PcW9@V0j({BT6$?p@Yy+kIwU z_54WS`6^vU?|yu&vpM0HCHFBP1LqHiE2pXGxuyU>lAc{e>_sH#`F;zZJQyXOt;DU5 zXOKVFeJr#*ex9+hG~Ie>wm<{`(=>HmPs-Q>usR@n(qW`I5O<|l#z*Tmr+ng*=M}Gx z@-m~8F+iB(cmk%0ISwN*DdKnn)MN}1f&dXh5H*t{z#LByP{92ExA&caQB>dCx6JI$ z))Ybr9TFh)CS8z@2q+>bDkvb>X<}~_L8|RX2Ne_rMFdglO?pv!@1cbjAZ6>6d(Zn} zb~n455URfDf1WR}*_}Ig?#!I$o^#KA4#k{lnB)=41YjBigor>1#sHjY3?WPfLH{Aw zR7{27PDT&}k{c0cj00do^>+t=Glp`15Oo%nJ~!lrZ-z})HRmVGKYF8WUm{XUDMkZAs7K@ zj0c)x`lV5fF>uBhN0?B7f~GM5{VakY01I4lSZgYx0*TVELkQ`O=&N`FB^Y!4zTn_> zXbd4tD2-UF1CYIz5$mUX)T%qjKm{|#z%-^WdjO`Cgx?5?fHRJ%K!7ohh(Hn37ytxE z41jaSxIRL`@ge$hnm4KIvL6a{X+DWx$D!6#MPo=1FlV}KUEo3j7tS<9D8Y!S8Xy$9 zM@-WIkZ3Yficw^hcVG-r0Rz`Bn=`fDm~Sio^un0!3Jr`33-wmNOhA|rVls=MF%F>L z6vQF!@nLN;zL>i%E6+0v1?17`ln}o56Cx)RMjp4CQlT$U6@2QvY@z=$d|OyZx-j%H zDrq8I2LuN_rdwI5%02I`9EC78D#{zUWkkiPF`+_ehawI{u>=3&u&)q8f=D8wJNoRB z3i-~Us3?SeB9X@;B8Z`PTL@p*!k9!d62|1Zp>>R@iGMldf1+d}NZq!4i(nEl)!ztA zC?yfo$=sH4^j9b}2$~|a`*hfW*L$wKWX_w!l-m`I1%V=jFd;(N{5pIzanywfVxHE- z{O8Lga@@nut6zth|7trG*p9_(i69WdgVTw~?27PXG1dErg9VpDKL$PM6V{EW9$C-N zYEuW<9Omn<&k%t^es>|_nW2#xYg7;bkWNv-0){x`#ZZC?(G`YJ)mPrBmA!EIUn;?Y z&PI%U*kx*}hOtg<1OPC>*XF$aJ(WyCzTSC6rH|;ZB1uTk)ecXKxK#-#T?R1Z$J`=u z1hzxvyHuvhi+f#oxVBoI!QkEM;ByQ)~4Ao&X9_#-P0073gCq!Fh5ktCxd7pr+2|G)NVuLnUBIOkEKJTA3$}n5yHg>e zDDQ+Z26|Rxfz3u8mA7hF)L`lZ7aXgb?Q-51I5c|K3wVZedH8`|uh(L+7;mM4Tf$B1 z_yJec9wXm&s9Nr$$ow9+oPVlZL|BY8`26d}Wyp1Z2bwF(b9;LN{Vul_42<0gG})tY zxbt@Iz)ESZ%-b9U+2htA|3LsvE&A+)mbK&fO*b8yXafKtKnS@#j>&xh6tBu|M`FBy zH4l9*AFB6pOUpl@#`VLabct@hdz8{(2kwZX@^yeHr8hYzys113&JbuOjA<$&M&*RNUdjg@@$~9sH#pm&9 z91t+SR}QE-czwXNYqb8K$}Hl_QB;l)a8>bnyner`|K@tlA^^WD`@PkRYUErF2qLJm z&*Sw4bQTb3s!!Hrug~XG0D-2+UXM>z{2Jp30aIk3$1BSkAf&jjRekZ>j)hT&&O!UeqCn)0C6?gtjZ98 z?7H^C4-4!0uX?=sO#GRqT;4SAc)C}&#Ij#jd_JE~0Vv4iDFG{nL*cH1t4QSDGK7FL zT^5h4e#SxbW+gm4_1Wri*`8aFNrW5o4XA#f-|JIU1^}ue%U-Y78T#pm;ReEO3h`#jm1Sw6oKF8OmaAukjrwRcC+42&tI`o60ha!o`E zNmw*8+_?-Cl#1#t*Sv0zVk%s@VjM=8GtKAm`h2;{Ec!9RLOSB0D!pW zxs*2NhoeZq2!ZDF`F(!bFKZlfU%Eg$TBguoC;UL%IjRO2Az4=bT=<(W&`r=}zbg9_ zl>>ym9V#=duz}lTDa9iW*n4>5woN-u&8uk-YU%*4`1ViJhd|~{eEtijdGuyIR4z`*fLMO3M9U|`meja$ES>F zOEItf_WxGS8M7|)$gmgcsl-0@ytZM}kt?%ovUanwLkRI;mBMi6DcB`YnDdq2H|&+uzW=P7#z7+` zM{eJ>-@m(a-6FCNcmDHuld@DxsJAQaU9+NCtG3$oU6=8D_wGoW=QLqlyy1-FhxYk) zKHZ`?16ud>@w?R1zy8!uV6uLSTcWGG5|Yi=Ys|x27=TBO5(LxS5ki{A^wm4gdDLDaKG`zGngss$90)@b2ogejl!NZTq-trE%LAj;-OWx@KRt zqjuZ=#lEablb?U<=lmwy!kOPkH>%X<#l@eLy}DxhnzCgRq?neERr_m1&dDEY7Jc?| z)~d$VT5HLl1;^03(*vuuHG(FY3os zTbJ}&gG95&DEBXK5nIXMwqGrL^`&xE$N#wXWoOBnl_z0)#8Lq^*%!TDzthNbp@fu} zGV1Uu6`%aRO2_tPuV)x^DLKw_3%mlx1Y=zVJIZ`x1YD@}MjKC)n96T$edv{*H5dd1 zus8=|n%nP@_D?VVtZCCqg?o6+!p)B@fJ5q#jXnQ*a`~k0fhGR0`T0-!^i{tTB%__KHsfOwHbe1 z7BnV9>box`x0H(4ZNGlt|9XRz@L~ItwQ#Yv?LN)|+uE_+>$muE#xtEN#kJ31U^zOz zW`*uba8?719{KU3y5)MkH1P?Ep;PldZfGmhq}#Sh^E%ru&8bPhP55=VfI(^y+$QXv4VF!`0rdX~RsT{%fn7II9=x(k)h2kU>)hZjYrjm+OoR zsi*d56s{wQNRDefVqn!%`%fxFKtwQ00wIDVNt9sE{!I&&-ZNLte6~YMJ}V>?9o~6D z%}hUtDy9@AJEqR))vR!f_SL?7b19>OSu$Zv%@#=@%u>EhiH@)SxP95gG4;4t^Bmf` zz}w@SRWo~aEFUcvfw3r=1&T$BB$)-K;aWXE_-W_TZ>ROtVvAD*SRmPJe#+DY&F3+v zG~T`bfXZEK7o5RJOG>F*?D=u?b}Z}nR4I!U3!+IBiC~r_NxX{*9z-N(|JWs3=*f$$ zeklS7^OHL^q{$*tJfvvN__VYOzH0||Uo3II-Gt4O31ecmNG35_rM^(fa_fKDt6~3v zHG8TTHv`4z*6b84H0`|HpcE0!W`PpXBALxXetj^T1RSzh?gK}!5mUyotCGzI*EgCb zlgVTfa|`1Jzu}xkxf*~tE^^grGMflBn{H`r^@O*m zzk~}MWNrL?rG4PnOTX&UqBO!n-4y@kb!WksaYQRoA&z1F?4iph*t>S_Sr5gkmoaCe zd}!TCA6MO1E?tdDZBhK`_vde4HRio)1UN!S-~6g;$o@kfReom)iH_^OQQi_+;Vx!4 zP`(Rvg{zcS_hq=X1MBxA5tHPWRT?+{ZrjqiKXkr!G>7@FeY3mj+>JlJ`*M8|0})JS z6Q!a_vY0W(hzODt+DrzR^7E&zQsz?}i2_6SJvaEL9ZSBM(w)T=$AC>{5o2nWBvBv; zBhf4g`a{IEq*A5VF4&*r^&Z@EtX44!6kpnL$YfGos$?SuM;Ryx1*LuoR>@%^#9BH* zOII}{xwk*l_Ov)NA~s_LLHfZ|KDR65=cV0-Z?u>YLfDGXm`5H1pW0{9lK9!3 zuH;>W2TU*^1ggE(t3Aa&l^&OC_WWa7Y;e6qZNrbFQ3B|9tYR zzh;R95XJ(*m?MJk@~gr%RJ3+UG2LbhF(8Ab?LFyq&E^&%^3l`ypzN${QWs~DS6 zP*yi0jMb$9EH(K%u z7bgv$}+JiMmzHJtHRz0^O}?7M~$5R3p2Ac*V> z!TOVcF$Rzw_r3Hq>Qk+&T)X$G@n*&u*NdrOy|>{{70tPJwMwcLHfk{?OPspOF$QCc zuYtS3QW~-i`fg@YQOCSq&-ggDIIPH@+2hflfBtp!V@-$Pvx~2$%$_>G{fwH>p8NGkqi=s-*YlX$wU?L<{x;+6>}j+6bIdcxJ<)Gp zw(0DSmBW9Y`RLIZfhry*K&$GvS)(XSXao`|Gs1eKg3}`pW12QXoqeU!1-= zSvxRia*i1buxZVK37dXCzh`cr9t&|u#STDGV*1VhU!7{j;%UO&NPlQcK!0m zf(cEJZ+`WOaejg3tFE1wDMJPK5JDm4Z=IzO0&A_dlg9PrM9kbe*C)W#-s7gvS@D2J zJ28If36qpHe8%({GnyXEA+Z-Q0H&hTCg>>{MC49Vb827=PRr7WZm^{Cm znQPvu&-dSO%0=@bh`%}FhY$)&qt7Rm{5p=*%|p`mj~jF1v!5nsnNm&Camlyw%T15W z-~6+x!seNyr_DPxe9puYPD0hSZ=|^}5&Vbe*O@T#n*O&6OkDV{90K-{q1uusWOqW*(P^aU@!;7IW05bWn0~R7^FE zS)5K2MU0ExSFKYA-9K-CV0Nu~U0y#Etq!Y1nC$m>WFXY)unCxZTpq^sX2rbkDOY8; z%g3oDHrC919*<8GOoFCSM~noD->r#GE7hG0iE8IAx!TR!@0|SL%6%Tq>-G9oOhud1 zN-+kmxwG92n_^-RTW{A*>0CG0$)zH%qSt6 zDA`4V0hsLddsP+}=ft-;mJm`83T&TZs@vt|fJ|1K#VjD;-W-?8kz}`~{I7Ko~MR941g@ zx7!DZNH&{E#6Fi>Wt^HUHk%nE1i-!7Ek*;J853I8m%Zk<&-_*Y zw*g&uFcLJBqSX--l%S(#i_;t;OJa|SDRAw_?2I=DdMnwSQutXVXXvb09Jp|G#|AOG zro7p2w+m4!T5U05qIZ}Gj=0#n9LS-9$t*eJVuDs4hbRgmgo)^gi;0Y{+GDKO89MNt$5 zjI9=js3?l2su*LzViN-X5W)mgViIG`qAcGw1B4=exl(mhbc8=|m{?P9#gLjRr=ZYl1Td zAp}62F&0%-so5GMMcmlXy9@x%xY)pMVuTPvCY!@-r<@BIBf)Cd?@9PeVZgwx`BDgh z;_(Sq3%Sd24^Z45CQ25w@Q+<204P46#(_A-> zmW7l|fiu8_63hbyY=Vqu%9+{2hz}BE|aK8di4^ z^wG@IEO5pF6M``UO;vL%oZjnW#5ESEM|wL0Y;vX)Cnry4MQ4Q+&@4cpq%x(H5QKty z&|zB4xs7O?3Iax4V?YJMwczeULIsL-m2gZbp#+!)M4%XPO+(QJjWU%{LBI%fv&mI8 z6oRpf%M#`M3Yk9&m5DgZ9ubI2c= zyS{j@A<-CDwGy4*TY6^CFF(CSaY5N~noJ)W|HB{Wb}szwy%?qdS1UX^X!WICi?qSQ~xxM%QZAS`RHh z`PcgN9h)*Xbt)lt{c6@ryPAdR^6@7-pe7sNEil8Q&b+-8xj6 zwE2AQ=FDw9S{IKNe*!=>@v|LU*X){BB(I(W@T8W{t-7{%*7%2stmb(*NvltO*pl_< za}Sk-K>1C;M4Yx{sNL)5IAPphTh{FPs;G$gziYi8xT$cp*(Y}{S@EGwQSzv`;PSnO zZphjDzxNsvE!uTfd_wo{7jL@sN2_YFfFibbVc=qXd}X2ydg>Jb1ugR82JV$gTZe^Zkp?{Zxd2&)Me7-`>R_j9j&4UHXo7 z={vsppuI<-O@>Tge{JWeK@AC49~m=sP!*MH{%0r8Y-&|%eld4*`u26{JO0f2t(4}R zcyw7QtESqk{Bm@v!_E5sxo=(ij&Y4F$ z`C2{uehW8ijp|aP`QQ}^3uZT0hyJakMOA-?XLwf8lPsW~CD zXP4%su*GhrEVcKi@3uJp>ZIc|Y%dWY?1&W}?$B0Nz!4uK05{pp;~svbUFBw-8a#X6 zl{j?5Qv<3s9eJe9r=yx7A~~%h03gwBl>}_I+c&@QV7aCbm20~wU9rc+SSTO_)|eO( zAya(Py#5_KRBqO$)U#)a<#r!>*0^WiKF`+e_`%ylM|7bI15GZ`xZ|7S-tW=1I{2XW z%l#jD<>fa%>=DnEzsK1CrU)%w8`QRb$(DUy>Da0`#`(*yg|>|9K|jVAzqwjzI z``bGg&VLN6TIAFyHgFe>|%E!U^j|d-8-ArLILE*j9g1+xy~qK(Q9xgE|wynOLmFdm|nzU%T~NpA4>^ zVgt^!*vh?!y*KdPr(;Ew*tC83PHp;+ey?%m_~=|?U?7!zVZ`9aA53K&m?AcRuGhnF zy!qN|?IhVtlbXLbvP(+!mT!MDq*evHUe`L13oTtmE2}CEru|lI z+3SzAn=oNcAHf%?BZEa^uliBQ(oY@7c4tB?#R#wvliL9EpvbaH<9|A~W7+EANhVI=@}}iGv$L{KUdT~p zpH#d_+U(!FG3LdeuD-8AkqWh|ZQNLF*5PfV-f4kRL8`5UYG-#Ju{h&W%f;i?7=v&&(IV921|I5T6)F^9~_^6cZnpm=K?6 zyX{vBW4dPY=*i#iTloIq*9Uy3i5M!pGTJX^aI$J2_)aWBf+*c_OkMi#FEoST^2sZ0)v;K)6*9BIVzJ=Ltu0&O;?z3-+ZD zLJ0d;FFo0yTUE=U)d$jC`TyoF^RHI7LF$T8zr@%tZ`=t@5;+gMhfFN;R110AL63ZB ztLuShl1wa&Ryj{-BJ5sw!4|uG^uluW>xc6jfL6O+<&`5BI2~6uY*m^h0!N^+n3ulm zvEbM3qEz_lR_c~L+1l}KIgPs)Gyj`dO0iaKUGBmGxAo-W6+)Zt77~8dOe)d%#H?R^ zvF6{$uDY*M36)1k1-5IIw0z3iLPFYpxkBAo1p$OIEmceELzOP=%eI_dwhFg?)=B|@ zS&B7C`t|em*G#5jP0r0-^ z>nG0~KF8H*!ng<6`Q`5pn0N8yy1_5J`RBnLjJQV1uDr6Ku-^{|AKti|R`aC~BdS!Ef|OdlK2>G(c*()gm8&H6u)lB>7|2&s;mbz_bl;c@$BFR``ka_1qx z>#`KJiAy^-Y@OWj`7hP4zVAc<5U67D=0gk39{trR!5*KPMf!d@#^JeYvry4qs)}jB zqh;%?CSBSj5?(NQ5}{OTYK3xzu3h#4BE)1XS2ZQ2xPv2#5XQE`<*TKZE^NXWGbXm^ zT})1@Rl%y}+s^E-4iETW^T11oNwEs$Q>#@^ zHATvAZ6dKuh19AQQ&SVk9ZdX8R+~i<%yzrOVL=?%8Pa>jsF4@4a#l^5pGidS^R3)> z&9iG=TCJW5QbA|oDz7tR_1ZH#rjMwK0W`Pv*z(;g)BftyF{$9*0mpXf>L(-i|Gs2j ze3BLAdO4xoZmcVqMg{%!T|0!}n_?LtHuv@kAFloR&m2dL>7R+tm?e|TlstJ#S2f!c z?}%8Z!=fZ{Pl;Z`Kj>A;!!72>qFuyM*psb1Hf3fRlUp#G0iv7Dp`|8H?WShC3poe^ zh-=jT(Os|aNoPouEZkG88d;IF$ivHP$!BIyBuItpFO zBK^J|>+oK++r+4c$|7)9`hl-LYvJ{QS z?RKj`?D3gd_@(LNVtiL^RzYvo@4r{ah?wjSGZ9R7r(L8drc#ZfzYqLn^QCh;)*s1H zsbo6(<<};gf9r9veVGUnU~$zREwy{iu8YfOEg%9$2+0R_t+;GH@$EOX{-cPP><)=g zlig_-1%eQ!aJGBx7q6Mk2qDawlvp~sTE!TfKnby8zqLt^i67STD1u#z?w}y24f!Ot zVf`Y3sVcFhRI8X;tzx`Gq&7#k4=~1>-xX_%U?PkV0v=zge1)p16)Po?yi;4jQodSh zYPHHGi#wvtHYV4;n|cAmj-}~E9OlSFFeEICP%1#UyuW#Rg%kG>_OP8(KZQ1|lJ44rQsV#3D{NqY(UFj8Hb^R(0 z<;?he_WYfT(i@F!UinAL7rrv;%hVAw7xaDj@tJuG$@@0UTs34v2TP8wpT1|+>XpY_ z6l2YHgvK^eRE84E^PEda^8;rZV=AMX$}l0?*)2=w{VABKAW+6R)-=ut0+3a1CiKXr z70Z|9AVkDF$esu+^8~f;{BCYCiyQz{4Pg-zN-*NYWTRTaP7xN!&X+qpBp|M-fDp9_ zzjbW5gd$B*3L+7V3FQ}$oD(uf?9003(-i zo8-$l$M`?86PD1+S6uhUpJ?5B%b?#nAH2vgA}FX)i~L!qm4vgO_k5An-#6e?mJb01 zOb7zN2=hw^W6Rt(rFEnDN5Au2T}1VC078IsL`cS!?3RgV+P3ikrZ2JD^j%VmHCm18(0FaZOK@NrfSt+V0&-i#nY4XaMS^Bc&fT_iolH<)y_JG8WQ%p4KrUC|G2KYnmz6 z4jSVEM}#7dt??$#G?Uq!9VyfdOjR)rPmmHV0;r5R944e8UGD{WP{;!#&@#?l`)aTZJG~J^WoxJ#+pNGw<+@g7# z@=f^uS2{QP=$kHoelr`gcG|o4e)PfSuZ?Q7|L7TtKrD7&vvw_-J=C;JtgwFV$yQ_E zs`t>-^$MTf=QSY&DRr7OZQH#0Lk*n*yAxyTI-l15iTjEbjl~#tzdO9)J7XHvsrJn9 zKJiS(W>f!{+qEC~f_cFw88Ru52oPwB;#V|H*9t;hRTRI%`HcmUFs1D3F+WF`1QrB1 z=af>SYt@Bw&7E*D6+D;IIQ&EPTQR2V=dG+g>B}}xzS*wi(amlFBVP9LH@5A4Mbwx8 z8J`b7_~JXgo_@FA@e!jlKxCTObLaknUCT3s1<&TgMIIjX)I;OHy#J4Rt0_jRn)LJ4 zmBlp`Az|~vl{F@Q^j6}Hd`OtkYyx-@^w+Ez+8hwe2 z{~}*X;>TwE;D7z4c5i(8>|aAa^#fLX(mSX3KUgV-BkH@bmOuGk?=D@(jZXPvN1A{E z+p283IwRKWM;QI^#p>1*zi8g`y|QUbcBv9Vyza2CR{j1sMM&Z&zx>uU=#>rw$M)JW zWSoz&4lj0G@YF~zA{?-Cd7Z!G>wUU*88^24+HJ=Lf&q}#itbtcbAIJ8E?&EI>0%a1 z$Ud-rQ{|BZp1Z$c=dRV`L?(MvUL1K}lTHsNpI>xN2%j#CuDxHcE!Ln`@#dW#1O^Bp zNUrta^Nn7d+%Nr?ZxKTL>QP>_c9}B8tr7*`oRnE|d2V69j4=Ik+lj}get2K2Cm*aU zZ%kLFezfKB(eJi-@l7`G%VSK+JMF~ksf@BIg*6o+gb5*(5K1vIo!#+!%Gh!3+duyH zn@I}~yLWFp+Vqq68?=40dBx1#ZUF-?RjWzUw#}QjYgCwA_;mw*^0{^ozx)(i^HUb1 z$Q;|aZS$sWTQsPjns*&Jw{RQ67j~aY>iT#>a?55d3ZdNMHPPk+VA4UUO02+8n(uiEnAFIj4;YNcJzV=7b#aZ z-bSvZrCo8U_EO0uVoV4lOxT%yM|}LY_r(Jurc$ZNHsU_K?;Jf0?_R!<*F^8@)i%{ySs0jOS;;|{Ct-ZRVH;3!eHcwzJ9<0r0pGz=idB$O%) zCyrl57y-}{mC9R@_r#$yy7X*ZN_l$a^p$J{W1zP94WDOCcq)SY`G#azz%#9pej{cPGLsYr>UR{2y~M)7jRE*?9l zVST8PEvaOQ`kkkZF86TtzBvjhoLsh$Q@D0I?Q)i4D^a>+oCRTo2|u^*kQ>>{R4irU z{xe6?d>TotR8iMO(7ZV(Po(F%gaE{BD-p|2UGP{E%hH^4ZW$$(FBd0x+#a}c?m|-8 zLh0v~QibFTP{f{f`id`nQ~-%RN@zwndy25%66?6H0N z=hXL_J_Gche%ZJz$JT7*JF-LJ=s)(J|Cd?nR*{{VeNa2i!nTZ1fmWB2{|2H0O;(7> zME(KEZ2-}=skJpw6-_XS#(eND;%{352JX#q zDU3Md9dcH-%#bxM#&j>)Nxxr}q=;!UM(FZ|OKr zpDE~Pz(D?wJI0Elgv*-zyFdi-rcDVU9Yzs^5D#R>`dRf=C2bj zD%kGt)XL^Qy>ih`euHTbXny}|1KW=Ic&Q`a5~&A+MYAd7c2I%-`waw=B;j9`k@o)q z;iaS^$_d`{2ro)`kM|q^tk!#U%ann8dX^An(g-Dl>eB=df)Xm#5T^C*_RvRH&3Jb2S7-maN8^ETHA0AlwSx%;06;jfFC7!2w~UcFwbhb& zPwZPbFRN0w!4KFp&XQa8tQl{{6a#10_Md9S|S`Wo>~CK%g+t>nCXa0j2$dP}(;sWbKJr+b zXF64A{nVpRH+-kUiyu8w2{-OnyIjrsH7X}mY~HkG%gUfxU;nJe+V%1)Z+1=Fe?>8s z>-_|t^8LD5!)BCv{S6!8OcgqQ{dL1~P7Vl|;>yf&x&0hKmeqv&J9Izu_N4wVv}rNK z&;H{#7yvP5Jm>k$>vgk^^C%nY9*Ir>;jT$|?cnRhwSwMEbh%wZNL1Z-5(YsK@}4fZ zx0>YbxlXRS(mX`SXMkQPGQ_giBWArn=sHy{3+`>+LD17jLkH@lm3NddMzU-;QU>mT zr7*=OrhT??Z~BQHyDIhS91E&;_1cVC%VvJDw%XGz1q9mR^;2i9{Osey)mv1ymVYvK z&$_*7>09P)dAxb5U*QQ2TQ=*^x>^N0LdbP!=f=&4y$3d}{B@g;Mr@4rn`^%FdYR3C zojkPskN936#+tdRs0bs(RYl_nA<)RqC11|}Y3Y<1r%I=Iuco}zQe6ARcl+&D@x<1R zyAEU=T(xG!iUT0oO52MRR<;fvwc*=sA3DX@cy_hn>^)<;#bugG=v6^9S!Ns%R~-%e zE;zhp-jdHcKGy!-SDRekzxQhU4kJN8}{t|!Xs7sPb@X6>(6QOf4E4ifqczwRC%OO@=`?}v?WL$e@gUcr|(ms_o@VlX)GTP%(}hQv3BT zHmZexd%A>yd(@Xgf~9<-d-ET=Vk+HlwG{ZO5Yc_$msW4}O17bx2w!vywdy4zKs009s!I)9*Dj1L#acey+ypMgQpDzVJcA9y_ZrZZDB?U$UL$r0?5#rdSO9Z+jXTBf-d=D8N4e zKp2ansM}eS$rKf2%ePwbZToPhAVj^+u@F&QXg&&^x+i>#B+iYH+{$AFeFz_#6DS>D7Z8`DHwVU7Q?AX2~ z4Fr5?|9*`l?9VuGAOjJ8>hNid5z0wRJL^`j?&&q`&<9I@{omNmT$M2b9D05cLI|rl zSB_o^ZqmkN$$O*J0Y5I7`-lm|Q`y!554 z5D(EHqS_DtHpF3}W`iGdeJo@DgMqv7j)w2*m8??4BwU{&1#|{cC=U9DX9b@hDyil)wny{+lrbLiE)XouV*?kTVe?fIDpehO-C#?BQ1aW;_oZHU-T05s&hL z!l_8VWc|;C(A=mXLWpxrZ+UlM)M6C?P^u4X{)1q6RtD~rrS3&vPY^Bkzhy7CK6j3= zER-UI)}7m)`@#!!{NPWFr{uo}N~s>o3))$XF@higFvj#mhFjvQd^sks9S`?HLcFNE zO8PR@4OgdhC+Q~pcD;-{{cycPydE#PRVCu626bl(075ZReHkp=k2h4h4EzUK>Ys$& zX@8`8tEfL(Y}SAEMH$%>*R!yq)6nR0>Uih<^cYV-#J9$G;dgZ%+3#jO|GM2tlzhWN(S5&Ise^I@UyJ-8BeUXz6 z-4J(T&d~TMZBV1h%qlIoB=f`yyNUXV3N0F{RbW{@i6-p${I|Me zQBkDg46)VSau;Vu$Z*Nd&QF`LEK~6iH*i(o|Gj!iBBwHWN?$%}uB!_3`_V5N$;X>> zC2mW=QJeMRkv&g1nc2K0PbByC8g^{k@bFQol`CVzya~&0-xmmcy7lgL@mht4ei8fZ z`@FXCJbBEzC?#M6Q*a3TmrbXyFN~A=dVGaUZ_Q=x65GDn@$Zs)5@j^(7KfiYxBYB1 zuZom`0ITw%)D2hupL}kY)10M|zdJ#wt4R5i?DLr3$FsTTwnl%e*?vc?pl{E@J$uxz z{+4|DMP$$4Z)r^ZiJon&A2aTm@oqCp*f6EB=8V+RV+K!>(+}@mI(y+X4bgooJ$vlYGnE;0X~>>BvR zLYhHIWy5ug{5b*&8)q1ulCsw`S|EX3uUF!2$MG+Q8$0K2Pn0|?E_2qiH+;C#}(`m(vGuj((w+Mdxy+2{%;=QYDDz#s| zcRXAhEdRgstWpbWV?m#(@Ai2XUF(|K=D93WS8xq7O$IK zG$+5_;`zcCF#&57YhG$QN$9wQ%qc!rp>Z<$|D@stQ&=)}Uai{ruCR4!#R3CKdm$wu zjyZ-Rhg}xVSh((yq}}eNAt%0H10D;Y#vs_VIc>9HGT5s&eIm!YuCE3jn!k)8xpFVZ z!UN|-8J>JsZea=)HPIDNykh_BFXKiAPp&uR7c zgy810Y*nWv_{>gAIREP9c&`gQ+wUkx;e7pq{TiVLZoh`24i0MWN2O1bbdDH-f z(YzF>03-rq91H?!0g7NS5;Vc4B^-b;HcSB;2vUr}h&TnZ3n&F+=%j*e=aIl*OoKX% g2gZQ8@H^i>c{LX%%e8V2n;C$>)78&qol`;+0Ku! Date: Sun, 3 Jan 2016 22:48:50 +0100 Subject: [PATCH 1803/2553] doc: update gitignore to ignore node_modules --- doc/sphinx/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/sphinx/.gitignore b/doc/sphinx/.gitignore index 8b77e79c6645..bc1208ccebf8 100644 --- a/doc/sphinx/.gitignore +++ b/doc/sphinx/.gitignore @@ -1,2 +1,3 @@ !Makefile _build +node_modules From 8618d824082d6579075d3b728948aace64f8e9a2 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 22:51:06 +0100 Subject: [PATCH 1804/2553] doc: added public data sets --- doc/sphinx/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index ad43700d89e1..78f3495e1d0c 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -15,3 +15,4 @@ Suricata User Guide reputation/index.rst initscripts setting-up-ipsinline-for-linux + public-data-sets From a65b585cd53797fff0840bbdc639a1084c2435d5 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 23:01:39 +0100 Subject: [PATCH 1805/2553] doc: added capture hardware except for napatech --- doc/sphinx/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 78f3495e1d0c..e625551e1ae1 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -16,3 +16,4 @@ Suricata User Guide initscripts setting-up-ipsinline-for-linux public-data-sets + capture-hardware/index.rst From 7f1e0d82fc1c3195501a0eb7653d8723c80833ca Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 23:02:26 +0100 Subject: [PATCH 1806/2553] doc: added public data sets with file --- doc/sphinx/public-data-sets.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 doc/sphinx/public-data-sets.rst diff --git a/doc/sphinx/public-data-sets.rst b/doc/sphinx/public-data-sets.rst new file mode 100644 index 000000000000..d994cccad48b --- /dev/null +++ b/doc/sphinx/public-data-sets.rst @@ -0,0 +1,16 @@ +Public Data Sets +================ + +Collections of pcaps for testing, profiling. + +DARPA sets: http://www.ll.mit.edu/mission/communications/cyber/CSTcorpora/ideval/data/ + +MAWI sets (pkt headers only, no payloads): http://mawi.wide.ad.jp/mawi/samplepoint-F/2012/ + +MACCDC: http://www.netresec.com/?page=MACCDC + +Netresec: http://www.netresec.com/?page=PcapFiles + +Wireshark: https://wiki.wireshark.org/SampleCaptures + +Security Onion collection: https://github.com/security-onion-solutions/security-onion/wiki/Pcaps From 1089ec1cd891067d3bda0646dfd50f0d28c95887 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 23:02:33 +0100 Subject: [PATCH 1807/2553] doc: added capture hardware except for napatech with file --- doc/sphinx/capture-hardware/endace-dag.rst | 46 ++++++++++ doc/sphinx/capture-hardware/index.rst | 7 ++ doc/sphinx/capture-hardware/myricom.rst | 98 ++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 doc/sphinx/capture-hardware/endace-dag.rst create mode 100644 doc/sphinx/capture-hardware/index.rst create mode 100644 doc/sphinx/capture-hardware/myricom.rst diff --git a/doc/sphinx/capture-hardware/endace-dag.rst b/doc/sphinx/capture-hardware/endace-dag.rst new file mode 100644 index 000000000000..72eb78f8f39a --- /dev/null +++ b/doc/sphinx/capture-hardware/endace-dag.rst @@ -0,0 +1,46 @@ +Endace DAG +========== + +Suricata comes with native Endace DAG card support. This means Suricata can use the *libdag* interface directly, instead of a libpcap wrapper (which should also work). + +Steps: + +Configure with DAG support: + + +:: + + + ./configure --enable-dag --prefix=/usr --sysconfdir=/etc --localstatedir=/var + make + sudo make install + +Results in: + +:: + + + Suricata Configuration: + AF_PACKET support: no + PF_RING support: no + NFQueue support: no + IPFW support: no + DAG enabled: yes + Napatech enabled: no + +Start with: + + +:: + + + suricata -c suricata.yaml --dag 0:0 + +Started up! + + +:: + + + [5570] 10/7/2012 -- 13:52:30 - (source-erf-dag.c:262) (ReceiveErfDagThreadInit) -- Attached and started stream: 0 on DAG: /dev/dag0 + [5570] 10/7/2012 -- 13:52:30 - (source-erf-dag.c:288) (ReceiveErfDagThreadInit) -- Starting processing packets from stream: 0 on DAG: /dev/dag0 diff --git a/doc/sphinx/capture-hardware/index.rst b/doc/sphinx/capture-hardware/index.rst new file mode 100644 index 000000000000..071ed7fab85d --- /dev/null +++ b/doc/sphinx/capture-hardware/index.rst @@ -0,0 +1,7 @@ +Using Capture Hardware +====================== + +.. toctree:: + + endace-dag + myricom diff --git a/doc/sphinx/capture-hardware/myricom.rst b/doc/sphinx/capture-hardware/myricom.rst new file mode 100644 index 000000000000..680e2fb85ca2 --- /dev/null +++ b/doc/sphinx/capture-hardware/myricom.rst @@ -0,0 +1,98 @@ +Myricom +======= + +From: http://blog.inliniac.net/2012/07/10/suricata-on-myricom-capture-cards/ + +In this guide I’ll describe using the Myricom libpcap support. I’m going to assume you installed the card properly, installed the Sniffer driver and made sure that all works. Make sure that in your dmesg you see that the card is in sniffer mode: + +:: + + + [ 2102.860241] myri_snf INFO: eth4: Link0 is UP + [ 2101.341965] myri_snf INFO: eth5: Link0 is UP + +I have installed the Myricom runtime and libraries in /opt/snf + +Compile Suricata against Myricom’s libpcap: + + +:: + + + ./configure --with-libpcap-includes=/opt/snf/include/ --with-libpcap-libraries=/opt/snf/lib/ --prefix=/usr --sysconfdir=/etc --localstatedir=/var + make + sudo make install + +Next, configure the amount of ringbuffers. I’m going to work with 8 here, as my quad core + hyper threading has 8 logical CPU’s. *See below* for additional information about the buffer-size parameter. + + +:: + + + pcap: + - interface: eth5 + threads: 8 + buffer-size: 512kb + checksum-checks: no + +The 8 threads setting makes Suricata create 8 reader threads for eth5. The Myricom driver makes sure each of those is attached to it’s own ringbuffer. + +Then start Suricata as follows: + +:: + + + SNF_NUM_RINGS=8 SNF_FLAGS=0x1 suricata -c suricata.yaml -i eth5 --runmode=workers + +If you want 16 ringbuffers, update the “threads” variable in your yaml to 16 and start Suricata: + +:: + + + SNF_NUM_RINGS=16 SNF_FLAGS=0x1 suricata -c suricata.yaml -i eth5 --runmode=workers + +Note that the pcap.buffer-size yaml setting shown above is currently ignored when using Myricom cards. The value is passed through to the pcap_set_buffer_size libpcap API within the Suricata source code. From Myricom support: + +:: + + + “The libpcap interface to Sniffer10G ignores the pcap_set_buffer_size() value. The call to snf_open() uses zero as the dataring_size which informs the Sniffer library to use a default value or the value from the SNF_DATARING_SIZE environment variable." + +The following pull request opened by Myricom in the libpcap project indicates that a future SNF software release could provide support for setting the SNF_DATARING_SIZE via the pcap.buffer-size yaml setting: + +* https://github.com/the-tcpdump-group/libpcap/pull/435 + +Until then, the data ring and descriptor ring values can be explicitly set using the SNF_DATARING_SIZE and SNF_DESCRING_SIZE environment variables, respectively. + +The SNF_DATARING_SIZE is the total amount of memory to be used for storing incoming packet data. This size is shared across all rings. +The SNF_DESCRING_SIZE is the total amount of memory to be used for storing meta information about the packets (packet lengths, offsets, timestamps). This size is also shared across all rings. + +Myricom recommends that the descriptor ring be 1/4 the size of the data ring, but the ratio can be modified based on your traffic profile. +If not set explicitly, Myricom uses the following default values: SNF_DATARING_SIZE = 256MB, and SNF_DESCRING_SIZE = 64MB + +Expanding on the 16 thread example above, you can start Suricata with a 16GB Data Ring and a 4GB Descriptor Ring using the following command: + +:: + + + SNF_NUM_RINGS=16 SNF_DATARING_SIZE=17179869184 SNF_DESCRING_SIZE=4294967296 SNF_FLAGS=0x1 suricata -c suricata.yaml -i eth5 --runmode=workers + +Debug Info +~~~~~~~~~~ + +Myricom also provides a means for obtaining debug information. This can be useful for verifying your configuration and gathering additional information. +Setting SNF_DEBUG_MASK=3 enables debug information, and optionally setting the SNF_DEBUG_FILENAME allows you to specify the location of the output file. + +Following through with the example: + +:: + + + SNF_NUM_RINGS=16 SNF_DATARING_SIZE=17179869184 SNF_DESCRING_SIZE=4294967296 SNF_FLAGS=0x1 SNF_DEBUG_MASK=3 SNF_DEBUG_FILENAME="/tmp/snf.out" suricata -c suricata.yaml -i eth5 --runmode=workers + +Additional Info +~~~~~~~~~~~~~~~ + +* http://www.40gbe.net/index_files/be59da7f2ab5bf0a299ab99ef441bb2e-28.html + +* http://o-www.emulex.com/blogs/implementers/2012/07/23/black-hat-usa-2012-emulex-faststack-sniffer10g-product-demo-emulex-booth/ From 253886b99f096d27d076e66598736807611ecc52 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Sun, 3 Jan 2016 23:38:20 +0100 Subject: [PATCH 1808/2553] doc: added file-extraction --- .../file-extraction/file-extraction.rst | 147 ++++++++++ ...filemd5-and-whiteblacklisting-with-md5.rst | 254 ++++++++++++++++ doc/sphinx/file-extraction/md5.rst | 271 ++++++++++++++++++ .../public-sha1-md5-data-sets.rst | 7 + doc/sphinx/index.rst | 1 + 5 files changed, 680 insertions(+) create mode 100644 doc/sphinx/file-extraction/file-extraction.rst create mode 100644 doc/sphinx/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst create mode 100644 doc/sphinx/file-extraction/md5.rst create mode 100644 doc/sphinx/file-extraction/public-sha1-md5-data-sets.rst diff --git a/doc/sphinx/file-extraction/file-extraction.rst b/doc/sphinx/file-extraction/file-extraction.rst new file mode 100644 index 000000000000..853cb12ce3d7 --- /dev/null +++ b/doc/sphinx/file-extraction/file-extraction.rst @@ -0,0 +1,147 @@ +File Extraction +=============== + +.. toctree:: + + md5 + filemd5-and-whiteblacklisting-with-md5 + public-sha1-md5-data-sets + +Starting with Suricata version 1.2 it's possible to extract files from HTTP sessions as well as match on file name, extension and "magic". + + +Architecture +~~~~~~~~~~~~ + +The file extraction code works on top of the HTTP parser which itself is largely a wrapper for libhtp. The HTTP parser takes care of dechunking and unzipping the request and/or response data if necessary. The HTTP parser runs on top of the stream reassembly engine. + +This means that settings in the stream engine, reassembly engine and the HTTP parser all affect the workings of the file extraction. + +What files are actually extracted and stored to disk is controlled by the rule language. + + +Settings +~~~~~~~~ + +*stream.checksum_validation* controls whether or not the stream engine rejects packets with invalid checksums. A good idea normally, but the network interface performs checksum offloading a lot of packets may seem to be broken. This setting is enabled by default, and can be disabled by setting to "no". Note that the checksum handling can be controlled per interface, see "checksum_checks" in example configuration. + +*stream.reassembly.depth* controls how far into a stream reassembly is done. Beyond this value no reassembly will be done. This means that after this value the HTTP session will no longer be tracked. By default a settings of 1 Megabyte is used. 0 sets it to unlimited. + +*libhtp.default-config.request-body-limit* / *libhtp.server-config..request-body-limit* controls how much of the HTTP request body is tracked for inspection by the http_client_body keyword, but also used to limit file inspection. A value of 0 means unlimited. + +*libhtp.default-config.response-body-limit* / *libhtp.server-config..response-body-limit* is like the request body limit, only it applies to the HTTP response body. + +NIC offloading +~~~~~~~~~~~~~~ + +NIC offloading should be disabled: + +:: + + + apt-get install ethtool + + +:: + + + ethtool -k eth3 + + Offload parameters for eth3: + rx-checksumming: off + tx-checksumming: off + scatter-gather: off + tcp-segmentation-offload: off + udp-fragmentation-offload: off + generic-segmentation-offload: off + generic-receive-offload: off + large-receive-offload: off + rx-vlan-offload: off + tx-vlan-offload: off + +Everything should be OFF. If it is not here is how you can disable it: + + +:: + + + ethtool -K eth3 tso off + ethtool -K eth3 gro off + ethtool -K eth3 lro off + ethtool -K eth3 gso off + ethtool -K eth3 rx off + ethtool -K eth3 tx off + ethtool -K eth3 sg off + ethtool -K eth3 rxvlan off + ethtool -K eth3 txvlan off + +NOTICE the difference between small k and a BIG K !! +Please make sure you choose the appropriate interface name (eth0,eth1,eth5...) + + +Output +~~~~~~ + +For file extraction two separate output modules were created: "file-log" and "file-store". They need to be enabled in the [[suricata.yaml]]. For "file-store", the "files" drop dir must be configured. + + +:: + + + - file-store: + enabled: yes # set to yes to enable + log-dir: files # directory to store the files + force-magic: no # force logging magic on all stored files + force-md5: no # force logging of md5 checksums + waldo: file.waldo # waldo file to store the file_id across runs + +Each file that is stored with have a name "file.". The id will be reset and files will be overwritten unless the waldo option is used. + + +:: + + + - file-log: + enabled: yes + filename: files-json.log + append: yes + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + force-magic: no # force logging magic on all logged files + force-md5: no # force logging of md5 checksums + + +Rules +~~~~~ + +Without rules in place no extraction will happen. The simplest rule would be: + + +:: + + + alert http any any -> any any (msg:"FILE store all"; filestore; sid:1; rev:1;) + +This will simply store all files to disk. + +Want to store all files with a pdf extension? + + +:: + + + alert http any any -> any any (msg:"FILE PDF file claimed"; fileext:"pdf"; filestore; sid:2; rev:1;) + +Or rather all actual pdf files? + + +:: + + + alert http any any -> any any (msg:"FILE pdf detected"; filemagic:"PDF document"; filestore; sid:3; rev:1;) + +Bundled with the Suricata download is a file with more example rules. In the archive, go to the rules/ directory and check the files.rules file. + +MD5 +~~~ + +Suricata can calculate MD5 checksums of files on the fly and log them. See :doc:`md5` for an explanation on how to enable this. diff --git a/doc/sphinx/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst b/doc/sphinx/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst new file mode 100644 index 000000000000..d4e6ef4fc52a --- /dev/null +++ b/doc/sphinx/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst @@ -0,0 +1,254 @@ +Filemd5 and white or black listing with MD5 hashes +================================================== + + + +This guide will show you how to set up a white/black MD5 listing using latest Suricata on Ubuntu LTS 12.04 64 bit +and a file containing 87 million MD5s - white list. + + +In this set up we had/did the following : + +1. A Suricata installation with :doc:`md5` enabled. +2. We start Suricata with about 4.5K rules and the MD5 white list file containing 87 million MD5 entries. +3. We have a 9.5Gb of traffic. +4. We have the following set up: + + +:: + + + CPU: One Intel(R) Xeon(R) CPU E5-2680 0 @ 2.70GHz (16 cores counting Hyperthreading) + Memory: 32Gb + capture NIC: Intel 82599EB 10-Gigabit SFI/SFP+ + + + +You need to get the white list file containing MD5s from here - http://www.nsrl.nist.gov/Downloads.htm +This is an official database containing SHA-1 and MD5s for files that are " traceable ". +For example after you download and unzip (I used the Combo DVD link) you would get a file like so: + + +:: + + + + "SHA-1","MD5","CRC32","FileName","FileSize","ProductCode","OpSystemCode","SpecialCode" + "000000206738748EDD92C4E3D2E823896700F849","392126E756571EBF112CB1C1CDEDF926","EBD105A0","I05002T2.PFB",98865,3095,"WIN","" + "0000004DA6391F7F5D2F7FCCF36CEBDA60C6EA02","0E53C14A3E48D94FF596A2824307B492","AA6A7B16","00br2026.gif",2226,228,"WIN","" + "000000A9E47BD385A0A3685AA12C2DB6FD727A20","176308F27DD52890F013A3FD80F92E51","D749B562","femvo523.wav",42748,4887,"MacOSX","" + "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,16848,"358","" + "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,18266,"358","" + "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,20316,"358","" + "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,20401,"358","" + "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,2322,"WIN","" + "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,23822,"358","" + + +The file contains 87 million entries/lines, each line having +"SHA-1","MD5","CRC32","FileName","FileSize","ProductCode","OpSystemCode","SpecialCode" +of a traceable file. + +You can use the Linux "cut" utility to make this file into only a MD5 file - have only the MD5 check sums (second row) - which is what we need. +Here is what you can do: + +Download the ComboDVD - http://www.nsrl.nist.gov/RDS/rds_2.47/RDS_247.iso + +unzip/tar, then + +:: + + + cat NSRFile.txt | more + +would be able to see the beginning of the file and get an idea of what does it contain.(shown above) +**NOTE – this is a 10GB file, make sure you have the space!** + +the MD5 column ... should start with "MD5" + + +:: + + + sudo cut -d'"' -f4 NSRFile.txt >> MD5.txt + +and you have only MD5s ...but still with "MD5" on top + + +:: + + + sed -i '1d' MD5.txt + +wait for a while +check the file + + +:: + + + wc -l MD5.txt + +wait for about 2-3 min + +should be about 87Mil something md5s , one per line +**NOTE:** +You can also import the file into a MySQL database, if you would like: + + +:: + + + mysql> create user 'filejson'@'localhost' IDENTIFIED BY 'PASSWORD123'; + Query OK, 0 rows affected (0.00 sec) + + mysql>create database filejsondb; + mysql> grant all privileges on filejsondb.* to 'filejson'@'localhost' with grant option; + mysql> flush privileges; + mysql> use filejsondb; + +Then: + +:: + + + CREATE TABLE MD5(md5_whitelist VARCHAR(32)); + +The trick here for the import is that **the table name and the file name MUST be the same** - aka MySQL table "MD5" and the file is called MD5.txt! + +:: + + + sudo mysqlimport -u root -p --local filejsondb MD5.txt + +Where "filejsondb" is the name of the database. + + + +So , here is how we did it .... + + + +:: + + + pevman@suricata:~$ ls -lh /etc/suricata/et-config/MD5_NSRFile.txt + -rw-r--r-- 1 root root 2.7G Aug 29 00:35 /etc/suricata/et-config/MD5_NSRFile.txt + + pevman@suricata:~$ wc -l /etc/suricata/et-config/MD5_NSRFile.txt + 87345542 /etc/suricata/et-config/MD5_NSRFile.txt + pevman@suricata:~$ + + + + + + +:: + + + pevman@suricata:~$ sudo tcpstat -i eth3 + Time:1346241952 n=6664547 avg=898.01 stddev=757.68 bps=9575769952.00 + Time:1346241957 n=6670750 avg=897.22 stddev=754.07 bps=9576254160.00 + Time:1346241962 n=6626520 avg=903.62 stddev=747.26 bps=9580577822.40 + Time:1346241967 n=6685956 avg=895.15 stddev=749.34 bps=9575883715.20 + Time:1346241972 n=6712481 avg=891.53 stddev=747.34 bps=9575027134.40 + Time:1346241977 n=6696189 avg=893.82 stddev=746.62 bps=9576294273.60 + Time:1346241982 n=6681826 avg=895.75 stddev=749.67 bps=9576376033.60 + + + + + +:: + + + pevman@suricata:~$ suricata --build-info + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:539) (SCPrintBuildInfo) -- This is Suricata version 1.4dev (rev 75af345) + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:612) (SCPrintBuildInfo) -- Features: PCAP_SET_BUFF LIBPCAP_VERSION_MAJOR=1 AF_PACKET HAVE_PACKET_FANOUT LIBCAP_NG LIBNET1.1 HAVE_HTP_URI_NORMALIZE_HOOK HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW HAVE_NSS + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:626) (SCPrintBuildInfo) -- 64-bits, Little-endian architecture + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:628) (SCPrintBuildInfo) -- GCC version 4.6.3, C version 199901 + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:634) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:637) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:640) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:643) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:646) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:650) (SCPrintBuildInfo) -- compiled with -fstack-protector + [2746] 29/8/2012 -- 15:07:25 - (suricata.c:656) (SCPrintBuildInfo) -- compiled with _FORTIFY_SOURCE=2 + +During Suricata start up : +... + +:: + + + [3071] 29/8/2012 -- 15:23:45 - (detect.c:670) (SigLoadSignatures) -- Loading rule file: /var/data/peter/md5test.rules + [3071] 29/8/2012 -- 15:23:45 - (detect-filemd5.c:105) (Md5ReadString) -- [ERRCODE: SC_ERR_INVALID_MD5(214)] - md5 string not 32 bytes + [3071] 29/8/2012 -- 15:24:25 - (detect-filemd5.c:277) (DetectFileMd5Parse) -- MD5 hash size 1399625840 bytes, negated match + [3071] 29/8/2012 -- 15:24:25 - (detect.c:701) (SigLoadSignatures) -- 5 rule files processed. 4641 rules succesfully loaded, 0 rules failed + + +You will get the + +:: + + [ERRCODE: SC_ERR_INVALID_MD5(214)] - md5 string not 32 bytes + +if a line of the file is not containing a proper MD5 hash. + +For example above we get the err message (which is more of a warning) because in the file , the first line was containing: +"SHA-1","MD5","CRC32","FileName","FileSize","ProductCode","OpSystemCode","SpecialCode" + +However , nonetheless Suricata will continue loading the rest of the MD5 hashes from the file. REMEMBER - you would need put only the MD5 hashes in the file. + + +Then we just created the following test rules: + +:: + + + root@suricata:/etc/suricata/peter-yaml# cat /var/data/peter/md5test.rules + alert http any any -> any any (msg:"FILE MD5 Check PDF against a white list"; filemagic:"pdf"; filemd5:!MD5_NSRFile.txt; sid:9966699; rev:1;) + alert http any any -> any any (msg:"FILE MD5 Check EXE against a white list"; filemagic:"exe"; filemd5:!MD5_NSRFile.txt; sid:9977799; rev:2;) + +Make sure the **MD5_NSRFile.txt** file (containing the MD5 hashes) is in your "rules directory" (where you load the rules from). + + +Basically the two rules above are telling Suricata to do the following: +1. If you see a PDF document that has a MD5 hash NOT in the MD5_NSRFile.txt - generate an alert +2. If you see an EXE file that has a MD5 hash NOT in the MD5_NSRFile.txt - generate an alert + +all that on the fly, while inspecting traffic. + + +Then all that is left is to start Suricata: + +:: + + + sudo /usr/local/bin/suricata -c /etc/suricata/peter-yaml/suricata-af-packet-mmap.yaml -s /var/data/peter/md5test.rules --af-packet=eth3 + +and we get the alerts: + + +:: + + + 08/29/2012-15:38:43.165038 [**] [1:9977799:2] FILE MD5 Check EXE against a white list [**] [Classification: (null)] [Priority: 3] {TCP} y.y.y.y:80 -> x.x.x.x:23836 + 08/29/2012-15:39:32.551950 [**] [1:9977799:2] FILE MD5 Check EXE against a white list [**] [Classification: (null)] [Priority: 3] {TCP} y.y.y.y:2091 -> x.x.x.x:80 + + + +That's it. + +You can reverse and use the above rules with a "blacklisting" of MD5 hashes, for example: + + +:: + + + alert http any any -> any any (msg:"FILE MD5 Check PDF against a black list"; filemagic:"pdf"; filemd5:BlackMD5s.txt; sid:9966699; rev:1;) + +You can also use the filestore keyword to store the file on disk and do further analysis on the particular file - or blend it in with other :doc:`../rules/file-keywords`. + +Peter Manev diff --git a/doc/sphinx/file-extraction/md5.rst b/doc/sphinx/file-extraction/md5.rst new file mode 100644 index 000000000000..1e38313738a1 --- /dev/null +++ b/doc/sphinx/file-extraction/md5.rst @@ -0,0 +1,271 @@ +Storing MD5s checksums +====================== + +In this particular example we are using: Ubuntu 14.04 LTS + +Also - we are using the latest git master (git installation) + +Make sure you have libnss and libnspr installed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +:: + + + root@LTS-64-1:~/Work/tmp/oisf# dpkg -l |grep libnss + ii libnss-mdns:amd64 0.10-6 amd64 NSS module for Multicast DNS name resolution + ii libnss3:amd64 2:3.17.4-0ubuntu0.14.04.1 amd64 Network Security Service libraries + ii libnss3-1d:amd64 2:3.17.4-0ubuntu0.14.04.1 amd64 Network Security Service libraries - transitional package + ii libnss3-dev:amd64 2:3.17.4-0ubuntu0.14.04.1 amd64 Development files for the Network Security Service libraries + ii libnss3-nssdb 2:3.17.4-0ubuntu0.14.04.1 all Network Security Security libraries - shared databases + ii libnss3-tools 2:3.17.4-0ubuntu0.14.04.1 amd64 Network Security Service tools + + + +:: + + + root@LTS-64-1:~/Work/tmp/oisf# dpkg -l |grep libnspr + ii libnspr4:amd64 2:4.10.7-0ubuntu0.14.04.1 amd64 NetScape Portable Runtime Library + ii libnspr4-dev 2:4.10.7-0ubuntu0.14.04.1 amd64 Development files for the NetScape Portable Runtime library + +If not install them: + +:: + + + apt-get install libnss3-dev libnspr4-dev + +**Note:** Fedora users need to install the following: + +:: + + + nss-util + nss-util-devel + nss-devel + nspr-devel + nspr + +Get the Suricata code +~~~~~~~~~~~~~~~~~~~~~ + +Execute: + +:: + + + git clone git://phalanx.openinfosecfoundation.org/oisf.git && cd oisf + git clone https://github.com/OISF/libhtp.git -b 0.5.x + +Building Suricata +~~~~~~~~~~~~~~~~~~ + +You have to compile/install suri like this in order to enable MD5s: + +:: + + + ./autogen.sh + ./configure --with-libnss-libraries=/usr/lib --with-libnss-includes=/usr/include/nss/ --with-libnspr-libraries=/usr/lib --with-libnspr-includes=/usr/include/nspr + make clean + make + sudo make install + +For Fedora 64-bit users, the configure line will look like + + +:: + + + ./configure --with-libnss-libraries=/usr/lib64 --with-libnss-includes=/usr/include/nss3 --with-libnspr-libraries=/usr/lib64 --with-libnspr-includes=/usr/include/nspr4 + +Output of configure: + + +:: + + + Suricata Configuration: +   AF_PACKET support:                       yes +   PF_RING support:                         no +   NFQueue support:                         no +   IPFW support:                            no +   DAG enabled:                             no +   Napatech enabled:                        no + +   libnss support:                          yes +   libnspr support:                         yes +   Prelude support:                         no +   PCRE jit:                                no + +This is what is important to have: + +:: + + + libnss support:                          yes + libnspr support:                         yes + +Confirm everything is built correctly: + + +:: + + + # suricata --build-info + [10010] 1/5/2012 -- 11:16:23 - (suricata.c:502) (SCPrintBuildInfo) -- This is Suricata version 1.3dev (rev e6dea5c) + [10010] 1/5/2012 -- 11:16:23 - (suricata.c:575) (SCPrintBuildInfo) -- Features: PCAP_SET_BUFF LIBPCAP_VERSION_MAJOR=1 AF_PACKET HAVE_PACKET_FANOUT LIBCAP_NG LIBNET1.1 HAVE_HTP_URI_NORMALIZE_HOOK HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW HAVE_NSS + [10010] 1/5/2012 -- 11:16:23 - (suricata.c:589) (SCPrintBuildInfo) -- 32-bits, Little-endian architecture + [10010] 1/5/2012 -- 11:16:23 - (suricata.c:591) (SCPrintBuildInfo) -- GCC version 4.4.5, C version 199901 + [10010] 1/5/2012 -- 11:16:23 - (suricata.c:597) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 + [10010] 1/5/2012 -- 11:16:23 - (suricata.c:600) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 + [10010] 1/5/2012 -- 11:16:23 - (suricata.c:603) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + [10010] 1/5/2012 -- 11:16:23 - (suricata.c:606) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 + [10010] 1/5/2012 -- 11:16:23 - (suricata.c:613) (SCPrintBuildInfo) -- compiled with -fstack-protector + [10010] 1/5/2012 -- 11:16:23 - (suricata.c:619) (SCPrintBuildInfo) -- compiled with _FORTIFY_SOURCE=2 + +Make sure we have **HAVE_NSS** in the **Features** line. + +Configuration +~~~~~~~~~~~~~ + +In the suricata yaml: + + +:: + + +  - file-store: +       enabled: yes       # set to yes to enable +       log-dir: files    # directory to store the files +       force-magic: yes   # force logging magic on all stored files +       force-md5: yes     # force logging of md5 checksums +       #waldo: file.waldo # waldo file to store the file_id across runs + +Optionally, for JSON output: + + +:: + + + - file-log: + enabled: yes + filename: files-json.log + append: no + +Other settings affecting :doc:`file-extraction` + + +:: + + + stream: + memcap: 64mb + checksum-validation: yes # reject wrong csums + inline: no # no inline mode + reassembly: + memcap: 32mb + depth: 0 # reassemble all of a stream + toserver-chunk-size: 2560 + toclient-chunk-size: 2560 + +Make sure we have *depth: 0* so all files can be tracked fully. + + +:: + + + libhtp: + default-config: + personality: IDS + # Can be specified in kb, mb, gb. Just a number indicates + # it's in bytes. + request-body-limit: 0 + response-body-limit: 0 + +Make sure we have *request-body-limit: 0* and *response-body-limit: 0* + +Testing +~~~~~~~ + +For the purpose of testing we use this rule only in a file.rules (a test/example file): + + +:: + + + alert http any any -> any any (msg:"FILE store all"; filestore; sid:1; rev:1;) + +This rule above will save all the file data for files that are opened/downloaded through HTTP + +Start Suricta (-S option loads ONLY the specified rule file, with disregard if any other rules that are enabled in suricata.yaml): + + +:: + + + suricata -c /etc/suricata/suricata.yaml -S file.rules -i eth0 + + +I tried that link (Cisco Prod Brochure PDF, just googled "Cisco PDF"): + +* http://www.cisco.com/c/en/us/products/routers/3800-series-integrated-services-routers-isr/index.html + +and in file directory (/var/log/suricata/files) I got the meta data: + + + +:: + + + TIME:              05/01/2012-11:09:52.425751 + SRC IP:            2.23.144.170 + DST IP:            192.168.1.91 + PROTO:             6 + SRC PORT:          80 + DST PORT:          51598 + HTTP URI:          /en/US/prod/collateral/routers/ps5855/prod_brochure0900aecd8019dc1f.pdf + HTTP HOST:         www.cisco.com + HTTP REFERER:      http://www.cisco.com/c/en/us/products/routers/3800-series-integrated-services-routers-isr/index.html + FILENAME:          /en/US/prod/collateral/routers/ps5855/prod_brochure0900aecd8019dc1f.pdf + MAGIC:             PDF document, version 1.6 + STATE:             CLOSED + MD5:               59eba188e52467adc11bf2442ee5bf57 + SIZE:              9485123 + +and in files-json.log (or eve.json) : + + +:: + + + { "id": 1, "timestamp": "05\/01\/2012-11:10:27.693583", "ipver": 4, "srcip": "2.23.144.170", "dstip": "192.168.1.91", "protocol": 6, "sp": 80, "dp": 51598, "http_uri": "\/en\/US\/prod\/collateral\/routers\/ps5855\/prod_brochure0900aecd8019dc1f.pdf", "http_host": "www.cisco.com", "http_referer": "http:\/\/www.google.com\/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDAQFjAA&url=http%3A%2F%2Fwww.cisco.com%2Fen%2FUS%2Fprod%2Fcollateral%2Frouters%2Fps5855%2Fprod_brochure0900aecd8019dc1f.pdf&ei=OqyfT9eoJubi4QTyiamhAw&usg=AFQjCNGdjDBpBDfQv2r3VogSH41V6T5x9Q", "filename": "\/en\/US\/prod\/collateral\/routers\/ps5855\/prod_brochure0900aecd8019dc1f.pdf", "magic": "PDF document, version 1.6", "state": "CLOSED", "md5": "59eba188e52467adc11bf2442ee5bf57", "stored": true, "size": 9485123 } + { "id": 12, "timestamp": "05\/01\/2012-11:12:57.421420", "ipver": 4, "srcip": "2.23.144.170", "dstip": "192.168.1.91", "protocol": 6, "sp": 80, "dp": 51598, "http_uri": "\/en\/US\/prod\/collateral\/routers\/ps5855\/prod_brochure0900aecd8019dc1f.pdf", "http_host": "www.cisco.com", "http_referer": "http:\/\/www.google.com\/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDAQFjAA&url=http%3A%2F%2Fwww.cisco.com%2Fen%2FUS%2Fprod%2Fcollateral%2Frouters%2Fps5855%2Fprod_brochure0900aecd8019dc1f.pdf&ei=OqyfT9eoJubi4QTyiamhAw&usg=AFQjCNGdjDBpBDfQv2r3VogSH41V6T5x9Q", "filename": "\/en\/US\/prod\/collateral\/routers\/ps5855\/prod_brochure0900aecd8019dc1f.pdf", "magic": "PDF document, version 1.6", "state": "CLOSED", "md5": "59eba188e52467adc11bf2442ee5bf57", "stored": true, "size": 9485123 } + + +Log all MD5s without any rules +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you would like to log MD5s for everything and anything that passes through the traffic that you are inspecting with Suricata, but not log the files themselves, all you have to do is disable file-store and enable only the JSON output with forced MD5s - in suricata.yaml like so: + + +:: + + + - file-store: + enabled: no # set to yes to enable + log-dir: files # directory to store the files + force-magic: yes # force logging magic on all stored files + force-md5: yes # force logging of md5 checksums + #waldo: file.waldo # waldo file to store the file_id across runs + + - file-log: + enabled: yes + filename: files-json.log + append: no + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + force-magic: yes # force logging magic on all logged files + force-md5: yes # force logging of md5 checksums + +This is in short what is needed to have MD5s logged. diff --git a/doc/sphinx/file-extraction/public-sha1-md5-data-sets.rst b/doc/sphinx/file-extraction/public-sha1-md5-data-sets.rst new file mode 100644 index 000000000000..373a52ecc4e2 --- /dev/null +++ b/doc/sphinx/file-extraction/public-sha1-md5-data-sets.rst @@ -0,0 +1,7 @@ +Public SHA1 MD5 data sets +========================= + + + + +National Software Reference Library - http://www.nsrl.nist.gov/Downloads.htm diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index e625551e1ae1..566d048fa3bc 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -15,5 +15,6 @@ Suricata User Guide reputation/index.rst initscripts setting-up-ipsinline-for-linux + file-extraction/file-extraction.rst public-data-sets capture-hardware/index.rst From b252b0d84c95d884bdcba27a794f31f8085e65ad Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 4 Jan 2016 11:10:12 -0600 Subject: [PATCH 1809/2553] doc: add configuration --- .../configuration/global-thresholds.rst | 119 + doc/sphinx/configuration/index.rst | 11 + doc/sphinx/configuration/log-rotation.rst | 31 + doc/sphinx/configuration/lua-output.rst | 656 ++++++ doc/sphinx/configuration/multi-tenant.rst | 167 ++ .../configuration/snort-to-suricata.rst | 276 +++ doc/sphinx/configuration/suricata-yaml.rst | 1992 +++++++++++++++++ .../suricata-yaml/IDS_chunk_size.png | Bin 0 -> 23331 bytes .../Inline_reassembly_unackd_data.png | Bin 0 -> 21776 bytes .../configuration/suricata-yaml/MPM2.png | Bin 0 -> 8647 bytes .../configuration/suricata-yaml/NFQ.png | Bin 0 -> 34533 bytes .../configuration/suricata-yaml/NFQ1.png | Bin 0 -> 19438 bytes .../configuration/suricata-yaml/NFQ2.png | Bin 0 -> 20707 bytes .../suricata-yaml/Normal_ids_ack_d.png | Bin 0 -> 23053 bytes .../configuration/suricata-yaml/Tuple1.png | Bin 0 -> 11151 bytes .../suricata-yaml/balancing_workload.png | Bin 0 -> 29055 bytes .../configuration/suricata-yaml/flow.png | Bin 0 -> 15914 bytes .../suricata-yaml/grouping_tree.png | Bin 0 -> 26129 bytes .../suricata-yaml/grouping_tree_detail.png | Bin 0 -> 62604 bytes .../suricata-yaml/inline_mode.png | Bin 0 -> 15054 bytes .../suricata-yaml/ipfw_reinjection.png | Bin 0 -> 27813 bytes .../suricata-yaml/normal_ids.png | Bin 0 -> 8447 bytes .../configuration/suricata-yaml/overlap.png | Bin 0 -> 27430 bytes .../suricata-yaml/reassembly1.png | Bin 0 -> 23072 bytes .../configuration/suricata-yaml/threading.png | Bin 0 -> 17401 bytes doc/sphinx/index.rst | 1 + 26 files changed, 3253 insertions(+) create mode 100644 doc/sphinx/configuration/global-thresholds.rst create mode 100644 doc/sphinx/configuration/index.rst create mode 100644 doc/sphinx/configuration/log-rotation.rst create mode 100644 doc/sphinx/configuration/lua-output.rst create mode 100644 doc/sphinx/configuration/multi-tenant.rst create mode 100644 doc/sphinx/configuration/snort-to-suricata.rst create mode 100644 doc/sphinx/configuration/suricata-yaml.rst create mode 100644 doc/sphinx/configuration/suricata-yaml/IDS_chunk_size.png create mode 100644 doc/sphinx/configuration/suricata-yaml/Inline_reassembly_unackd_data.png create mode 100644 doc/sphinx/configuration/suricata-yaml/MPM2.png create mode 100644 doc/sphinx/configuration/suricata-yaml/NFQ.png create mode 100644 doc/sphinx/configuration/suricata-yaml/NFQ1.png create mode 100644 doc/sphinx/configuration/suricata-yaml/NFQ2.png create mode 100644 doc/sphinx/configuration/suricata-yaml/Normal_ids_ack_d.png create mode 100644 doc/sphinx/configuration/suricata-yaml/Tuple1.png create mode 100644 doc/sphinx/configuration/suricata-yaml/balancing_workload.png create mode 100644 doc/sphinx/configuration/suricata-yaml/flow.png create mode 100644 doc/sphinx/configuration/suricata-yaml/grouping_tree.png create mode 100644 doc/sphinx/configuration/suricata-yaml/grouping_tree_detail.png create mode 100644 doc/sphinx/configuration/suricata-yaml/inline_mode.png create mode 100644 doc/sphinx/configuration/suricata-yaml/ipfw_reinjection.png create mode 100644 doc/sphinx/configuration/suricata-yaml/normal_ids.png create mode 100644 doc/sphinx/configuration/suricata-yaml/overlap.png create mode 100644 doc/sphinx/configuration/suricata-yaml/reassembly1.png create mode 100644 doc/sphinx/configuration/suricata-yaml/threading.png diff --git a/doc/sphinx/configuration/global-thresholds.rst b/doc/sphinx/configuration/global-thresholds.rst new file mode 100644 index 000000000000..183e2c4cddc6 --- /dev/null +++ b/doc/sphinx/configuration/global-thresholds.rst @@ -0,0 +1,119 @@ +Global-Thresholds +================= + +Thresholds can be configured in the rules themselves, see +:doc:`../rules/thresholding`. They are often set by rule writers based on +their intel for creating a rule combined with a judgement on how often +a rule will alert. + +Next to these settings, thresholding can be configured on the sensor +using the threshold.config. + +threshold/event_filter +~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: + +:: + + threshold gen_id , sig_id , type , track , count , seconds + +rate_filter +~~~~~~~~~~~ + +TODO + +suppress +~~~~~~~~ + +Suppressions can be used to suppress alerts for a rule or a +host/network. Actions performed when a rule matches, such as setting a +flowbit, are still performed. + +Syntax: + +:: + + suppress gen_id , sig_id + suppress gen_id , sig_id , track , ip + +Example: + +:: + + suppress gen_id 1, sig_id 2002087, track by_src, ip 209.132.180.67 + +This will make sure the signature 2002087 will never match for src +host 209.132.180.67. + +.. _global-thresholds-vs-rule-thresholds: + +Global thresholds vs rule thresholds +------------------------------------ + +**Note: this section applies to 1.4+ In 1.3 and before mixing rule and +global thresholds is not supported.** + +When a rule has a threshold/detection_filter set a rule can still be +affected by the global threshold file. + +The rule below will only fire if 10 or more emails are being +delivered/sent from a host within 60 seconds. + +:: + + alert tcp any any -> any 25 (msg:"ET POLICY Inbound Frequent Emails - Possible Spambot Inbound"; \ + flow:established; content:"mail from|3a|"; nocase; \ + threshold: type threshold, track by_src, count 10, seconds 60; \ + reference:url,doc.emergingthreats.net/2002087; classtype:misc-activity; sid:2002087; rev:10;) + +Next, we'll see how global settings affect this rule. + +Suppress +~~~~~~~~ + +Suppressions can be combined with rules with +thresholds/detection_filters with no exceptions. + +:: + + suppress gen_id 1, sig_id 2002087, track by_src, ip 209.132.180.67 + suppress gen_id 0, sig_id 0, track by_src, ip 209.132.180.67 + suppress gen_id 1, sig_id 0, track by_src, ip 209.132.180.67 + +Each of the rules above will make sure 2002087 doesn't alert when the +source of the emails is 209.132.180.67. It **will** alert for all other +hosts. + +:: + + suppress gen_id 1, sig_id 2002087 + +This suppression will simply convert the rule to "noalert", meaning it +will never alert in any case. If the rule sets a flowbit, that will +still happen. + +Threshold/event_filter +~~~~~~~~~~~~~~~~~~~~~~ + +When applied to a specific signature, thresholds and event_filters +(threshold from now on) will override the signature setting. This can +be useful for when the default in a signature doesn't suit your +evironment. + +:: + + threshold gen_id 1, sig_id 2002087, type both, track by_src, count 3, seconds 5 + threshold gen_id 1, sig_id 2002087, type threshold, track by_src, count 10, seconds 60 + threshold gen_id 1, sig_id 2002087, type limit, track by_src, count 1, seconds 15 + +Each of these will replace the threshold setting for 2002087 by the +new threshold setting. + +**Note:** overriding all gids or sids (by using gen_id 0 or sig_id 0) +is not supported. Bug #425. + +Rate_filter +~~~~~~~~~~~ + +TODO diff --git a/doc/sphinx/configuration/index.rst b/doc/sphinx/configuration/index.rst new file mode 100644 index 000000000000..d620646ffaae --- /dev/null +++ b/doc/sphinx/configuration/index.rst @@ -0,0 +1,11 @@ +Configuration +============= + +.. toctree:: + + suricata-yaml + global-thresholds + snort-to-suricata + log-rotation + lua-output + multi-tenant diff --git a/doc/sphinx/configuration/log-rotation.rst b/doc/sphinx/configuration/log-rotation.rst new file mode 100644 index 000000000000..63ee24e5b3d3 --- /dev/null +++ b/doc/sphinx/configuration/log-rotation.rst @@ -0,0 +1,31 @@ +Log Rotation +============ + +Starting with Suricata version 2.0.2 (#1200), log rotation is made a +lot easier. A HUP signal sent to Suricata will force it to reopen the +logfiles. + +Example logrotate file: + +:: + + /var/log/suricata/*.log /var/log/suricata/*.json + { + rotate 3 + missingok + nocompress + create + sharedscripts + postrotate + /bin/kill -HUP $(cat /var/run/suricata.pid) + endscript + } + +newsyslog based log rotation (e.g. on OpenBSD) /etc/newsyslog.conf: + +:: + + /var/log/suricata/eve.json root:wheel 640 1 * 24 B /var/run/suricata.pid SIGHUP + +The above rotates every 24h; the 'B' prevents a rotation logmessage in +eve.json. Fieldseperator is a TAB. diff --git a/doc/sphinx/configuration/lua-output.rst b/doc/sphinx/configuration/lua-output.rst new file mode 100644 index 000000000000..5c0f554c7b8a --- /dev/null +++ b/doc/sphinx/configuration/lua-output.rst @@ -0,0 +1,656 @@ +Lua Output +========== + +Note: this page new Lua scripting available for outputs. It will be +available in 2.1. + +Script structure +---------------- + +A script defines 4 functions: init, setup, log, deinit + +* init -- registers where the script hooks into the output engine +* setup -- does per output thread setup +* log -- logging function +* deinit -- clean up function + +Example: + +:: + + function init (args) + local needs = {} + needs["protocol"] = "http" + return needs + end + + function setup (args) + filename = SCLogPath() .. "/" .. name + file = assert(io.open(filename, "a")) + SCLogInfo("HTTP Log Filename " .. filename) + http = 0 + end + + function log(args) + http_uri = HttpGetRequestUriRaw() + if http_uri == nil then + http_uri = "" + end + http_uri = string.gsub(http_uri, "%c", ".") + + http_host = HttpGetRequestHost() + if http_host == nil then + http_host = "" + end + http_host = string.gsub(http_host, "%c", ".") + + http_ua = HttpGetRequestHeader("User-Agent") + if http_ua == nil then + http_ua = "" + end + http_ua = string.gsub(http_ua, "%g", ".") + + ts = SCPacketTimeString() + ipver, srcip, dstip, proto, sp, dp = SCFlowTuple() + + file:write (ts .. " " .. http_host .. " [**] " .. http_uri .. " [**] " .. + http_ua .. " [**] " .. srcip .. ":" .. sp .. " -> " .. + dstip .. ":" .. dp .. "\n") + file:flush() + + http = http + 1 + end + + function deinit (args) + SCLogInfo ("HTTP transactions logged: " .. http); + file:close(file) + end + +YAML +---- + +To enable the lua output, add the 'lua' output and add one or more +scripts like so: + +:: + + outputs: + - lua: + enabled: yes + scripts-dir: /etc/suricata/lua-output/ + scripts: + - tcp-data.lua + - flow.lua + +The scripts-dir option is optional. It makes Suricata load the scripts +from this directory. Otherwise scripts will be loaded from the current +workdir. + +packet +------ + +Initialize with: + +:: + + function init (args) + local needs = {} + needs["type"] = "packet" + return needs + end + +SCPacketTimeString +~~~~~~~~~~~~~~~~~~ + +Add SCPacketTimeString to get the packets time string in the format: +11/24/2009-18:57:25.179869 + +:: + + function log(args) + ts = SCPacketTimeString() + +SCPacketTuple +~~~~~~~~~~~~~ + +:: + + ipver, srcip, dstip, proto, sp, dp = SCPacketTuple() + +SCPacketPayload +~~~~~~~~~~~~~~~ + +:: + + p = SCPacketPayload() + +flow +---- + +:: + + function init (args) + local needs = {} + needs["type"] = "flow" + return needs + end + +SCFlowTimeString +~~~~~~~~~~~~~~~~ + +:: + + startts = SCFlowTimeString() + +SCFlowTuple +~~~~~~~~~~~ + +:: + + ipver, srcip, dstip, proto, sp, dp = SCFlowTuple() + +SCFlowAppLayerProto +~~~~~~~~~~~~~~~~~~~ + +Get alproto as string from the flow. If alproto is not (yet) known, it +returns "unknown". + +Example: + +:: + + function log(args) + alproto = SCFlowAppLayerProto() + if alproto ~= nil then + print (alproto) + end + end + +SCFlowStats +~~~~~~~~~~~ + +Gets the packet and byte counts per flow. + +:: + + tscnt, tsbytes, tccnt, tcbytes = SCFlowStats() + +http +---- + +Init with: + +:: + + function init (args) + local needs = {} + needs["protocol"] = "http" + return needs + end + +HttpGetRequestBody and HttpGetResponseBody. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Make normalized body data available to the script through +HttpGetRequestBody and HttpGetResponseBody. + +There no guarantees that all of the body will be availble. + +Example: + +:: + + function log(args) + a, o, e = HttpGetResponseBody(); + --print("offset " .. o .. " end " .. e) + for n, v in ipairs(a) do + print(v) + end + end + +HttpGetRequestHost +~~~~~~~~~~~~~~~~~~ + +Get the host from libhtp's tx->request_hostname, which can either be +the host portion of the url or the host portion of the Host header. + +Example: + +:: + + http_host = HttpGetRequestHost() + if http_host == nil then + http_host = "" + end + +HttpGetRequestHeader +~~~~~~~~~~~~~~~~~~~~ + +:: + + http_ua = HttpGetRequestHeader("User-Agent") + if http_ua == nil then + http_ua = "" + end + +HttpGetResponseHeader +~~~~~~~~~~~~~~~~~~~~~ + +:: + + server = HttpGetResponseHeader("Server"); + print ("Server: " .. server); + +HttpGetRequestLine +~~~~~~~~~~~~~~~~~~ + +:: + + rl = HttpGetRequestLine(); + print ("Request Line: " .. rl); + +HttpGetResponseLine +~~~~~~~~~~~~~~~~~~~ + +:: + + rsl = HttpGetResponseLine(); + print ("Response Line: " .. rsl); + +HttpGetRawRequestHeaders +~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + rh = HttpGetRawRequestHeaders(); + print ("Raw Request Headers: " .. rh); + +HttpGetRawResponseHeaders +~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + rh = HttpGetRawResponseHeaders(); + print ("Raw Response Headers: " .. rh); + +HttpGetRequestUriRaw +~~~~~~~~~~~~~~~~~~~~ + +:: + + http_uri = HttpGetRequestUriRaw() + if http_uri == nil then + http_uri = "" + end + +HttpGetRequestUriNormalized +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + http_uri = HttpGetRequestUriNormalized() + if http_uri == nil then + http_uri = "" + end + +HttpGetRequestHeaders +~~~~~~~~~~~~~~~~~~~~~ + +:: + + a = HttpGetRequestHeaders(); + for n, v in pairs(a) do + print(n,v) + end + +HttpGetResponseHeaders +~~~~~~~~~~~~~~~~~~~~~~ + +:: + + a = HttpGetResponseHeaders(); + for n, v in pairs(a) do + print(n,v) + end + +DNS +--- + +DnsGetQueries +~~~~~~~~~~~~~ + +:: + + dns_query = DnsGetQueries(); + if dns_query ~= nil then + for n, t in pairs(dns_query) do + rrname = t["rrname"] + rrtype = t["type"] + + print ("QUERY: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " .. + "TODO" .. " [**] " .. srcip .. ":" .. sp .. " -> " .. + dstip .. ":" .. dp) + end + end + +returns a table of tables + +DnsGetAnswers +~~~~~~~~~~~~~ + +:: + + dns_answers = DnsGetAnswers(); + if dns_answers ~= nil then + for n, t in pairs(dns_answers) do + rrname = t["rrname"] + rrtype = t["type"] + ttl = t["ttl"] + + print ("ANSWER: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " .. + ttl .. " [**] " .. srcip .. ":" .. sp .. " -> " .. + dstip .. ":" .. dp) + end + end + +returns a table of tables + +DnsGetAuthorities +~~~~~~~~~~~~~~~~~ + +:: + + dns_auth = DnsGetAuthorities(); + if dns_auth ~= nil then + for n, t in pairs(dns_auth) do + rrname = t["rrname"] + rrtype = t["type"] + ttl = t["ttl"] + + print ("AUTHORITY: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " .. + ttl .. " [**] " .. srcip .. ":" .. sp .. " -> " .. + dstip .. ":" .. dp) + end + end + +returns a table of tables + +DnsGetRcode +~~~~~~~~~~~ + +:: + + rcode = DnsGetRcode(); + if rcode == nil then + return 0 + end + print (rcode) + +returns a lua string with the error message, or nil + +DnsGetRecursionDesired +~~~~~~~~~~~~~~~~~~~~~~ + +:: + + if DnsGetRecursionDesired() == true then + print ("RECURSION DESIRED") + end + +returns a bool + +TLS +--- + +Initialize with: + +:: + + function init (args) + local needs = {} + needs["protocol"] = "tls" + return needs + end + +TlsGetCertInfo +~~~~~~~~~~~~~~ + +Make certificate information available to the script through TlsGetCertInfo. + +Example: + +:: + + function log (args) + version, subject, issuer, fingerprint = TlsGetCertInfo() + if version == nil then + return 0 + end + end + + +SSH +--- + +Initialize with: + +:: + + + function init (args) + local needs = {} + needs["protocol"] = "ssh" + return needs + end + +SshGetServerProtoVersion +~~~~~~~~~~~~~~~~~~~~~~~~ + +Get SSH protocol version used by the server through SshGetServerProtoVersion. + +Example: + +:: + + function log (args) + version = SshGetServerProtoVersion() + if version == nil then + return 0 + end + end + +SshGetServerSoftwareVersion +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Get SSH software used by the server through SshGetServerSoftwareVersion. + +Example: + +:: + + + function log (args) + software = SshGetServerSoftwareVersion() + if software == nil then + return 0 + end + end + +SshGetClientProtoVersion +~~~~~~~~~~~~~~~~~~~~~~~~ + +Get SSH protocol version used by the client through SshGetClientProtoVersion. + +Example: + +:: + + function log (args) + version = SshGetClientProtoVersion() + if version == nil then + return 0 + end + end + +SshGetClientSoftwareVersion +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Get SSH software used by the client through SshGetClientSoftwareVersion. + +Example: + +:: + + function log (args) + software = SshGetClientSoftwareVersion() + if software == nil then + return 0 + end + end + +Files +----- + +To use the file logging API, the script's init() function needs to look like: + +:: + + function init (args) + local needs = {} + needs['type'] = 'file' + return needs + end + +SCFileInfo +~~~~~~~~~~ + +:: + + + fileid, txid, name, size, magic, md5 = SCFileInfo() + +returns fileid (number), txid (number), name (string), size (number), +magic (string), md5 in hex (string) + +SCFileState +~~~~~~~~~~~ + +:: + + state, stored = SCFileState() + +returns state (string), stored (bool) + +Alerts +------ + +Alerts are a subset of the 'packet' logger: + +:: + + function init (args) + local needs = {} + needs["type"] = "packet" + needs["filter"] = "alerts" + return needs + end + +SCRuleIds +~~~~~~~~~ + +:: + + sid, rev, gid = SCRuleIds() + +SCRuleMsg +~~~~~~~~~ + +:: + + msg = SCRuleMsg() + +SCRuleClass +~~~~~~~~~~~ + +:: + + + class, prio = SCRuleClass() + +Streaming Data +-------------- + +Streaming data can currently log out reassembled TCP data and +normalized HTTP data. The script will be invoked for each consecutive +data chunk. + +In case of TCP reassembled data, all possible overlaps are removed +according to the host OS settings. + +:: + + function init (args) + local needs = {} + needs["type"] = "streaming" + needs["filter"] = "tcp" + return needs + end + +In case of HTTP body data, the bodies are unzipped and dechunked if applicable. + +:: + + function init (args) + local needs = {} + needs["type"] = "streaming" + needs["protocol"] = "http" + return needs + end + +SCStreamingBuffer +~~~~~~~~~~~~~~~~~ + +:: + + function log(args) + data = SCStreamingBuffer() + hex_dump(data) + end + +Misc +---- + +SCThreadInfo +~~~~~~~~~~~~ + +:: + + tid, tname, tgroup = SCThreadInfo() + +It gives: tid (integer), tname (string), tgroup (string) + +SCLogError, SCLogWarning, SCLogNotice, SCLogInfo, SCLogDebug +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Print a message. It will go into the outputs defined in the +yaml. Whether it will be printed depends on the log level. + +Example: + +:: + + SCLogError("some error message") + +SCLogPath +~~~~~~~~~ + +Expose the log path. + +:: + + + name = "fast_lua.log" + function setup (args) + filename = SCLogPath() .. "/" .. name + file = assert(io.open(filename, "a")) + end diff --git a/doc/sphinx/configuration/multi-tenant.rst b/doc/sphinx/configuration/multi-tenant.rst new file mode 100644 index 000000000000..f7142313aca1 --- /dev/null +++ b/doc/sphinx/configuration/multi-tenant.rst @@ -0,0 +1,167 @@ +Multi Tenancy +============= + +**Work In Progress** + +This is part of Suricata 3.0RC1. + +Introduction +------------ + +Multi tenancy support allows for different rule sets with different +rule vars. + +YAML +---- + +In the main ("master") YAML, the suricata.yaml, a new section called +"multi-detect" should be added. + +Settings: + +* enabled: yes/no -> is multi-tenancy support enable +* default: yes/no -> is the normal detect config a default 'fall back' tenant? +* selector: direct (for unix socket pcap processing, see below) or vlan +* loaders: number of 'loader' threads, for parallel tenant loading at startup +* tenants: list of tenants + + * id: tenant id + * yaml: separate yaml file with the tenant specific settings + +* mappings: + + * vlan id + * tenant id: tenant to associate with the vlan id + +:: + + multi-detect: + enabled: yes + #selector: direct # direct or vlan + selector: vlan + loaders: 3 + + tenants: + - id: 1 + yaml: tenant-1.yaml + - id: 2 + yaml: tenant-2.yaml + - id: 3 + yaml: tenant-3.yaml + + mappings: + - vlan-id: 1000 + tenant-id: 1 + - vlan-id: 2000 + tenant-id: 2 + - vlan-id: 1112 + tenant-id: 3 + +The tenant-1.yaml, tenant-2.yaml, tenant-3.yaml each contain a partial +configuration: + +:: + + # Set the default rule path here to search for the files. + # if not set, it will look at the current working dir + default-rule-path: /etc/suricata/rules + rule-files: + - rules1 + + # You can specify a threshold config file by setting "threshold-file" + # to the path of the threshold config file: + # threshold-file: /etc/suricata/threshold.config + + classification-file: /etc/suricata/classification.config + reference-config-file: /etc/suricata/reference.config + + # Holds variables that would be used by the engine. + vars: + + # Holds the address group vars that would be passed in a Signature. + # These would be retrieved during the Signature address parsing stage. + address-groups: + + HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" + + EXTERNAL_NET: "!$HOME_NET" + + ... + + port-groups: + + HTTP_PORTS: "80" + + SHELLCODE_PORTS: "!80" + + ... + +Unix Socket +----------- + +Registration +~~~~~~~~~~~~ + +register-tenant + +Examples: + +:: + + register-tenant 1 tenant-1.yaml + register-tenant 2 tenant-2.yaml + register-tenant 3 tenant-3.yaml + register-tenant 5 tenant-5.yaml + register-tenant 7 tenant-7.yaml + +unregister-tenant + +:: + + unregister-tenant 2 + unregister-tenant 1 + +Unix socket runmode (pcap processing) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Unix Socket "pcap-file" command can be used to select the tenant +to inspect the pcap against: + +:: + + pcap-file traffic1.pcap /logs1/ 1 + pcap-file traffic2.pcap /logs2/ 2 + pcap-file traffic3.pcap /logs3/ 3 + pcap-file traffic4.pcap /logs5/ 5 + pcap-file traffic5.pcap /logs7/ 7 + +This runs the traffic1.pcap against tenant 1 and it logs into /logs1/, +traffic2.pcap against tenant 2 and logs to /logs2/ and so on. + +Live traffic mode +~~~~~~~~~~~~~~~~~ + +For live traffic currently only a vlan based multi-tenancy is supported. + +The master yaml needs to have the selector set to "vlan". + +Registration +~~~~~~~~~~~~ + +Tenants can be mapped to vlan id's. + +register-tenant-handler vlan + +:: + + register-tenant-handler 1 vlan 1000 + +unregister-tenant-handler vlan + +:: + + unregister-tenant-handler 4 vlan 1111 + unregister-tenant-handler 1 vlan 1000 + +The registration of tenant and tenant handlers can be done on a +running engine. diff --git a/doc/sphinx/configuration/snort-to-suricata.rst b/doc/sphinx/configuration/snort-to-suricata.rst new file mode 100644 index 000000000000..ec9ec0f0db26 --- /dev/null +++ b/doc/sphinx/configuration/snort-to-suricata.rst @@ -0,0 +1,276 @@ +Snort.conf to Suricata.yaml +=========================== + +This guide is meant for those who are familiar with Snort and the +snort.conf configuration format. This guide will provide a 1:1 mapping +between Snort and Suricata configuration wherever possible. + +Variables +--------- + +snort.conf + +:: + + ipvar HOME_NET any + ipvar EXTERNAL_NET any + ... + + portvar HTTP_PORTS [80,81,311,591,593,901,1220,1414,1741,1830,2301,2381,2809,3128,3702,4343,4848,5250,7001,7145,7510,7777,7779,8000,8008,8014,8028,8080,8088,8090,8118,8123,8180,8181,8243,8280,8800,8888,8899,9000,9080,9090,9091,9443,9999,11371,55555] + portvar SHELLCODE_PORTS !80 + ... + +suricata.yaml + +:: + + + vars: + address-groups: + + HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" + EXTERNAL_NET: "!$HOME_NET" + + port-groups: + HTTP_PORTS: "80" + SHELLCODE_PORTS: "!80" + +Note that Suricata can automatically detect HTTP traffic regardless of +the port it uses. So the HTTP_PORTS variable is not nearly as +important as it is with Snort, **if** you use a Suricata enabled +ruleset. + +Decoder alerts +-------------- + +snort.conf + +:: + + # Stop generic decode events: + config disable_decode_alerts + + # Stop Alerts on experimental TCP options + config disable_tcpopt_experimental_alerts + + # Stop Alerts on obsolete TCP options + config disable_tcpopt_obsolete_alerts + + # Stop Alerts on T/TCP alerts + config disable_tcpopt_ttcp_alerts + + # Stop Alerts on all other TCPOption type events: + config disable_tcpopt_alerts + + # Stop Alerts on invalid ip options + config disable_ipopt_alerts + +suricata.yaml + +Suricata has no specific decoder options. All decoder related alerts +are controlled by rules. See #Rules below. + +Checksum handling +----------------- + +snort.conf + +:: + + config checksum_mode: all + +suricata.yaml + +Suricata's checksum handling works _on-demand_. The stream engine +checks TCP and IP checksum by default: + +:: + + stream: + checksum-validation: yes # reject wrong csums + +Alerting on bad checksums can be done with normal rules. See #Rules, +decoder-events.rules specifically. + +Various configs +--------------- + +Active response +~~~~~~~~~~~~~~~ + +snort.conf + +:: + + # Configure active response for non inline operation. For more information, see REAMDE.active + # config response: eth0 attempts 2 + +suricata.yaml + +Active responses are handled automatically w/o config if rules with +the "reject" action are used. + +Dropping privileges +~~~~~~~~~~~~~~~~~~~ + +snort.conf + +:: + + + # Configure specific UID and GID to run snort as after dropping privs. For more information see snort -h command line options + # + # config set_gid: + # config set_uid: + +Suricata + +To set the user and group use the --user and --group + commandline options. + +Snaplen +~~~~~~~ + +snort.conf + +:: + + # Configure default snaplen. Snort defaults to MTU of in use interface. For more information see README + # + # config snaplen: + # + +Suricata always works at full snap length to provide full traffic visibility. + +Bpf +~~~ + +snort.conf + +:: + + # Configure default bpf_file to use for filtering what traffic reaches snort. For more information see snort -h command line options (-F) + # + # config bpf_file: + # + +suricata.yaml + +BPF filters can be set per packet acquisition method, with the "bpf-filter: " yaml option and in a file using the -F command line option. + +For example: + +:: + + pcap: + - interface: eth0 + #buffer-size: 16777216 + #bpf-filter: "tcp and port 25" + #checksum-checks: auto + #threads: 16 + #promisc: no + #snaplen: 1518 + +Log directory +------------- + +snort.conf + +:: + + # Configure default log directory for snort to log to. For more information see snort -h command line options (-l) + # + # config logdir: + +suricata.yaml + +:: + + default-log-dir: /var/log/suricata/ + +This value is overridden by the -l commandline option. + +Packet acquisition +------------------ + +snort.conf + +:: + + # Configure DAQ related options for inline operation. For more information, see README.daq + # + # config daq: + # config daq_dir:

+ # config daq_mode: + # config daq_var: + # + # ::= pcap | afpacket | dump | nfq | ipq | ipfw + # ::= read-file | passive | inline + # ::= arbitrary = ::= path as to where to look for DAQ module so's + +suricata.yaml + +Suricata has all packet acquisition support built-in. It's +configuration format is very verbose. + +:: + + pcap: + - interface: eth0 + #buffer-size: 16777216 + #bpf-filter: "tcp and port 25" + #checksum-checks: auto + #threads: 16 + #promisc: no + #snaplen: 1518 + pfring: + afpacket: + nfq: + ipfw: + +Passive vs inline vs reading files is determined by how Suricata is +invoked on the command line. + +Rules +----- + +snort.conf: + +In snort.conf a RULE_PATH variable is set, as well as variables for +shared object (SO) rules and preprocessor rules. + +:: + + var RULE_PATH ../rules + var SO_RULE_PATH ../so_rules + var PREPROC_RULE_PATH ../preproc_rules + + include $RULE_PATH/local.rules + include $RULE_PATH/emerging-activex.rules + ... + +suricata.yaml: + +In the suricata.yaml the default rule path is set followed by a list +of rule files. Suricata does not have a concept of shared object rules +or preprocessor rules. Instead of preprocessor rules, Suricata has +several rule files for events set by the decoders, stream engine, http +parser etc. + +:: + + default-rule-path: /etc/suricata/rules + rule-files: + - local.rules + - emerging-activex.rules + +The equivalent of preprocessor rules are loaded like normal rule files: + +:: + + rule-files: + - decoder-events.rules + - stream-events.rules + - http-events.rules + - smtp-events.rules diff --git a/doc/sphinx/configuration/suricata-yaml.rst b/doc/sphinx/configuration/suricata-yaml.rst new file mode 100644 index 000000000000..8f78cff227e9 --- /dev/null +++ b/doc/sphinx/configuration/suricata-yaml.rst @@ -0,0 +1,1992 @@ +Suricata.yaml +============= + +Suricata uses the Yaml format for configuration. The Suricata.yaml +file included in the source code, is the example configuration of +Suricata. This document will explain each option. + +At the top of the YAML-file you will find % YAML 1.1. Suricata reads +the file and identifies the file as YAML. + +Max-pending-packets +------------------- + +With the max-pending-packets setting you can set the number of packets +you allow Suricata to process simultaneously. This can range from one +packet to tens of thousands/hundreds of thousands of packets. It is a +trade of higher performance and the use of more memory (RAM), or lower +performance and less use of memory. A high number of packets being +processed results in a higher performance and the use of more +memory. A low number of packets, results in lower performance and less +use of memory. Choosing a low number of packets being processed while +having many CPU's/CPU cores, can result in not making use of the whole +computer-capacity. (For instance: using one core while having three +waiting for processing packets.) + +:: + + max-pending-packets: 1024 + +Runmodes +-------- + +By default the runmode option is disabled With the runmodes setting +you can set the runmode you would like to use. For all runmodes +available, enter **--list-runmodes** in your command line. For more +information, see :doc:`../performance/runmodes`. + +:: + + runmode: autofp + +Default-packet-size +------------------- + +For the max-pending-packets option, Suricata has to keep packets in +memory. With the default-packet-size option, you can set the size of +the packets on your network. It is possible that bigger packets have +to be processed sometimes. The engine can still process these bigger +packets, but processing it will lower the performance. + +:: + + default-packet-size: 1514 + +User and group +-------------- + +It is possible to set the user and group to run Suricata as: + +:: + + run-as: + user: suri + group: suri + + +Action-order +------------ + +All signatures have different properties. One of those is the Action +property. This one determines what will happen when a signature +matches. There are four types of Action. A summary of what will +happen when a signature matches and contains one of those Actions: + +1) Pass + +If a signature matches and contains pass, Suricata stops scanning the +packet and skips to the end of all rules (only for the current +packet). + +2) Drop + +This only concerns the IPS/inline mode. If the program finds a +signature that matches, containing drop, it stops immediately. The +packet will not be sent any further. Drawback: The receiver does not +receive a message of what is going on, resulting in a time-out +(certainly with TCP). Suricata generates an alert for this packet. + +3) Reject + +This is an active rejection of the packet. Both receiver and sender +receive a reject packet. There are two types of reject packets that +will be automatically selected. If the offending packet concerns TCP, +it will be a Reset-packet. For all other protocols it will be an +ICMP-error packet. Suricata also generates an alert. When in +Inline/IPS mode, the offending packet will also be dropped like with +the 'drop' action. + +4) Alert + +If a signature matches and contains alert, the packet will be treated +like any other non-threatening packet, except for this one an alert +will be generated by Suricata. Only the system administrator can +notice this alert. + +Inline/IPS can block network traffic in two ways. One way is by drop +and the other by reject. + +Rules will be loaded in the order of which they appear in files. But +they will be processed in a different order. Signatures have different +priorities. The most important signatures will be scanned first. There +is a possibility to change the order of priority. The default order +is: pass, drop, reject, alert. + +:: + + action-order: + - pass + - drop + - reject + - alert + +This means a pass rule is considered before a drop rule, a drop rule +before a reject rule and so on. + +Splitting configuration in multiple files +----------------------------------------- + +Some users might have a need or a wish to split their suricata.yaml +file in to seperate files, this is available vis the 'include' and +'!include' keyword. The first example is of taking the contents of the +outputs section and storing them in outputs.yaml + +:: + + # outputs.yaml + - fast + enabled: yes + filename: fast.log + append: yes + + - unified2-alert: + enabled: yes + + ... + +:: + + # suricata.yaml + ... + + outputs: !include outputs.yaml + + ... + +The second scenario is where multiple sections are migrated to a +different YAML file. + +:: + + # host_1.yaml + + max-pending-packets: 2048 + + outputs: + - fast + enabled: yes + filename: fast.log + append: yes + + - unified2-alert: + enabled: yes + +:: + + # suricata.yaml + + include: host_1.yaml + + ... + +If the same section, say outputs is later redefined after the include +statement it will overwrite the included file. Therefor any include +statement at the end of the document will overwrite the already +configured sections. + +Event output +------------ + +Default logging directory +~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the /var/log/suricata directory, all of Suricata's output (alerts +and events) will be stored. + +:: + + default-log-dir: /var/log/suricata + +This directory can be overridden by entering the -l command line +parameter or by changing the directory directly in Yaml. To change it +with the -l command line parameter, enter the following: + +:: + + suricata -c suricata.yaml -i eth0 -l /var/log/suricata-logs/ + +Outputs +~~~~~~~ + +There are several types of output. The general structure is: + +:: + + outputs: + -fast: + enabled: yes + filename: fast.log + append: yes/no + +Enabling all of the logs, will result in a much lower performance and +the use of more disc space, so enable only the outputs you need. + +Line based alerts log (fast.log) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This log contains alerts consisting of a single line. Example of the +appearance of a single fast.log-file line: + +:: + + 10/05/10-10:08:59.667372  [**] [1:2009187:4] ET WEB_CLIENT ACTIVEX iDefense + COMRaider ActiveX Control Arbitrary File Deletion [**] [Classification: Web + Application Attack] [Priority: 3] {TCP} xx.xx.232.144:80 -> 192.168.1.4:56068 + +:: + + -fast: #The log-name. + enabled:yes #This log is enabled. Set to 'no' to disable. + filename: fast.log #The name of the file in the default logging directory. + append: yes/no #If this option is set to yes, the last filled fast.log-file will not be + #overwritten while restarting Suricata. + +Eve (Extensible Event Format) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is an JSON output for alerts and events. It allows for easy +integration with tools like logstash. + +:: + + # Extensible Event Format (nicknamed EVE) event log in JSON format + - eve-log: + enabled: yes + type: file #file|syslog|unix_dgram|unix_stream + filename: eve.json + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + types: + - alert + - http: + extended: yes # enable this for extended logging information + - dns + - tls: + extended: yes # enable this for extended logging information + - files: + force-magic: no # force logging magic on all logged files + force-md5: no # force logging of md5 checksums + #- drop + - ssh + +For more advanced configuration options, see [[**FIXME** EveJSONOutput]]. + +The format is documented in [[**FIXME **EveJSONFormat]] + +Log output for use with Barnyard (unified.log) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This log only supports IPv4. Its information will be stored in the +default logging directory. This log is designed to be stored in a +binary format on the hard disc, where it will be further processed by +Barnyard. Barnyard can store the output in a database, so Suricata can +work on other important tasks. Barnyard can add the files in the +Mysql-database, send them to Sguil or several other output options. + +There is a size-limit to the log-file: If Suricata generates an alert, +it stores this alert in a unified-file. Suricata keeps continuing +doing that, until the file has reached its limit. Which in the default +case is at 32 MB. At that point Suricata generates a new file and the +process starts all over again. Barnyard keeps on processing these +files. To prevent Suricata from filling up the hard disc, a size limit +is enforced. When the limit is reached, the file will 'role-over', +creating a new file. Barnyard removes old files. To every file, +Suricata adds a time stamp, so it is easy to see which one came first +and which one is the latter. + +:: + + -Unified-log: #The log-name. + enabled: no #This log is not enabled. Set 'yes' to enable. + filename: unified.log #The name of the file in the default logging directory. + limit: 32 #The file size limit in megabytes. + +This output option has been removed in Suricata 1.1rc1 (see ticket +#353). + +Alert output for use with Barnyard (unified.alert) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This log only supports IPv4. Its information will be stored in the +default logging directory. For further information read the above +information about ( 2) unified.log) + +:: + + -Unified-alert: #The log-name. + enabled: no #This log is not enabled. Set 'yes' to enable. + filename: unified.alert #The name of the file in the default logging directory. + limit: 32 #The file size limit in megabytes. + +This output option has been removed in Suricata 1.1rc1 (see ticket #353). + +Alert output for use with Barnyard2 (unified2.alert) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This log also supports IPv6 in addition to IPv4. It's information will +be stored in the default logging directory. For further information +read the above information about 2. unified.log. + +:: + + - unified2-alert: #The log-name. + enabled: yes #This log is enabled. Set 'no' to disable. + filename: unified2.alert #The name of the file in the default logging directory. + limit: 32 #The file size limit in megabytes. + +This alert output needs Barnyard2. + +A line based log of HTTP requests (http.log) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This log keeps track of all HTTP-traffic events. It contains the HTTP +request, hostname, URI and the User-Agent. This information will be +stored in the http.log (default name, in the suricata log +directory). This logging can also be performed through the use of the +[[**FIXME** EveJSONFormat|Eve-log capability]]. + +Example of a HTTP-log line with non-extended logging: + +:: + + 07/01/2014-04:20:14.338309 vg.no [**] / [**] Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) + AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36 [**] + 192.168.1.6:64685 -> 195.88.54.16:80 + +Example of a HTTP-log line with extended logging: + +:: + + 07/01/2014-04:21:06.994705 vg.no [**] / [**] Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) + AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36 [**] [**] + GET [**] HTTP/1.1 [**] 301 => http://www.vg.no/ [**] 239 bytes [**] 192.168.1.6:64726 -> 195.88.54.16:80 + +:: + + - http-log: #The log-name. + enabled: yes #This log is enabled. Set 'no' to disable. + filename: http.log #The name of the file in the default logging directory. + append: yes/no #If this option is set to yes, the last filled http.log-file will not be + # overwritten while restarting Suricata. + extended: yes # If set to yes more information is written about the event. + +A line based log of DNS queries and replies (dns.log) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This log keeps track of all DNS events (queries and replies). It +contains the type of DNS activity that has been performed, the +requested / replied domain name and relevant data suck as client, +server, ttl, resource record data. This logging can also be performed +through the use of the [[EveJSONFormat|Eve-log capability]] which +offers easier parsing. + +Example of the apperance of a DNS log of a query with a preceding reply: + +:: + + 07/01/2014-04:07:08.768100 [**] Query TX 14bf [**] zeustracker.abuse.ch [**] A [**] 192.168.1.6:37681 -> 192.168.1.1:53 + 07/01/2014-04:07:08.768100 [**] Response TX 14bf [**] zeustracker.abuse.ch [**] A [**] TTL 60 [**] 205.188.95.206 [**] 192.168.1.1:53 -> 192.168.1.6:37681 + +Non-existant domains and other DNS errors are recorded by the text +representation of the rcode field in the reply (see RFC1035 and +RFC2136 for a list). In the example below a non-existent domain is +resolved and the NXDOMAIN error logged: + +:: + + 02/25/2015-22:58:40.499385 [**] Query TX a3ce [**] nosuchdomainwfqwdqwdqw.com [**] A [**] 192.168.40.10:48361 -> 192.168.40.2:53 + 02/25/2015-22:58:40.499385 [**] Response TX a3ce [**] NXDOMAIN [**] 192.168.40.2:53 -> 192.168.40.10:48361 + 02/25/2015-22:58:40.499385 [**] Response TX a3ce [**] NXDOMAIN [**] 192.168.40.2:53 -> 192.168.40.10:48361 + +Configuration options: + +:: + + - dns-log: # The log-name + enabled: yes # If this log is enabled. Set 'no' to disable + filename: dns.log # Name of this file this log is written to in the default logging directory + append: yes # If this option is set to yes, the (if any exists) dns.log file wil not be overwritten while restarting Suricata. + filetype: regular / unix_stream / unix_dgram + +Packet log (pcap-log) +~~~~~~~~~~~~~~~~~~~~~ + +With the pcap-log option you can save all packets, that are registered +by Suricata, in a log file named _log.pcap_. This way, you can take a +look at all packets whenever you want. In the normal mode a pcap file +is created in the default-log-dir. It can also be created elsewhere if +a absolute path is set in the yaml-file. + +The file that is saved in example the default -log-dir +/var/log/suricata, can be be opened with every program which supports +the pcap file format. This can be Wireshark, TCPdump, Suricata, Snort +and many others. + +The pcap-log option can be enabled and disabled. + +There is a size limit for the pcap-log file that can be set. The +default limit is 32 MB. If the log-file reaches this limit, the file +will be rotated and a new one will be created. The pcap-log option +has an extra functionality for "Sguil":http://sguil.sourceforge.net/ +that can be enabled in the 'mode' option. In the sguil mode the +"sguil_base_dir" indicates the base directory. In this base dir the +pcaps are created in a Sguil-specific directory structure that is +based on the day: + +:: + + $sguil_base_dir/YYYY-MM-DD/$filename. + +If you would like to use Suricata with Sguil, do not forget to enable +(and if necessary modify) the base dir in the suricata.yaml file. +Remember that in the 'normal' mode, the file will be saved in +default-log-dir or in the absolute path (if set). + +By default all packets are logged except: + +- TCP streams beyond stream.reassembly.depth +- encrypted streams after the key exchange + +:: + + - pcap-log: + enabled: yes + filename: log.pcap + + # Limit in MB. + limit: 32 + + mode: sguil # "normal" (default) or sguil. + sguil_base_dir: /nsm_data/ + +Verbose Alerts Log (alert-debug.log) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is a log type that gives supplementary information about an +alert. It is particularly convenient for people who investigate false +positives and who write signatures. However, it lowers the performance +because of the amount of information it has to store. + +:: + + - alert-debug: #The log-name. + enabled: no #This log is not enabled. Set 'yes' to enable. + filename: alert-debug.log #The name of the file in the default logging directory. + append: yes/no #If this option is set to yes, the last filled fast.log-file will not be + # overwritten while restarting Suricata. + +Alert output to prelude (alert-prelude) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To be able to use this type, you have to connect with the prelude +manager first. + +Prelude alerts contain a lot of information and fields, including the +IPfields in of the packet which triggered the alert. This information +can be divided in three parts: + +- The alert description (sensor name, date, ID (sid) of the rule, + etc). This is always included +- The packets headers (almost all IP fields, TCP UDP etc. if relevant) +- A binary form of the entire packet. + +Since the last two parts can be very big (especially since they are +stored in the Prelude SQL database), they are optional and controlled +by the two options 'log_packet_header' and 'log_packet_content'. The +default setting is to log the headers, but not the content. + +The profile name is the name of the Prelude profile used to connect to +the prelude manager. This profile must be registered using an external +command (prelude-admin), and must match the uid/gid of the user that +will run Suricata. The complete procedure is detailed in the `Prelude +Handbook +`_. + +:: + + - alert-prelude: #The log-name. + enabled: no #This log is not enabled. Set 'yes' to enable. + profile: suricata #The profile-name used to connect to the prelude manager. + log_packet_content: no #The log_packet_content is disabled by default. + log_packet_header: yes #The log _packet_header is enabled by default. + +Stats +~~~~~ + +In stats you can set the options for stats.log. When enabling +stats.log you can set the amount of time in seconds after which you +want the output-data to be written to the log file. + +:: + + - stats: + enabled: yes #By default, the stats-option is enabled + filename: stats.log #The log-name. Combined with the default logging directory + #(default-log-dir) it will result in /var/log/suricata/stats.log. + #This directory can be overruled with a absolute path. (A + #directory starting with / ). + interval: 8 #The default amount of time after which the file will be + #refreshed. + append: yes/no #If this option is set to yes, the last filled fast.log-file will not be + #overwritten while restarting Suricata. + +Syslog +~~~~~~ + +With this option it is possible to send all alert and event output to syslog. + +:: + + - syslog: #This is a output-module to direct log-output to several directions. + enabled: no #The use of this output-module is not enabled. + facility: local5 #In this option you can set a syslog facility. + level: Info #In this option you can set the level of output. The possible levels are: + #Emergency, Alert, Critical, Error, Warning, Notice, Info and Debug. + +Drop.log, a line based information for dropped packets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If Suricata works in IPS mode, it can drop packets based on +rules. Packets that are being dropped are saved in the drop.log file, +a Netfilter log format. + +:: + + - drop: + enabled: yes #The option is enabled. + filename: drop.log #The log-name of the file for dropped packets. + append: yes #If this option is set to yes, the last filled drop.log-file will not be + #overwritten while restarting Suricata. If set to 'no' the last filled drop.log file will be overwritten. + +Detection engine +---------------- + +Inspection configuration +~~~~~~~~~~~~~~~~~~~~~~~~ + +The detection-engine builds internal groups of signatures. Suricata +loads signatures, with which the network traffic will be compared. The +fact is, that many rules certainly will not be necessary. (For +instance: if there appears a packet with the UDP-protocol, all +signatures for the TCP-protocol won't be needed.) For that reason, +all signatures will be divided in groups. However, a distribution +containing many groups will make use of a lot of memory. Not every +type of signature gets its own group. There is a possibility that +different signatures with several properties in common, will be placed +together in a group. The quantity of groups will determine the +balance between memory and performance. A small amount of groups will +lower the performance yet uses little memory. The opposite counts for +a higher amount of groups. The engine allows you to manage the balance +between memory and performance. To manage this, (by determining the +amount of groups) there are several general options:high for good +performance and more use of memory, low for low performance and little +use of memory. The option medium is the balance between performance +and memory usage. This is the default setting.The option custom is for +advanced users. This option has eight values which can be managed by +the user. + +:: + + detect-engine: + -profile: medium #The balance between performance and memory usage. This is the default setting. + - custom-values: + toclient_src_groups: 2 + toclient_dst_groups: 2 + toclient_sp_groups: 2 + toclient_dp_groups: 3 + toserver_src_groups: 2 + toserver_dst_groups: 4 + toserver_sp_groups: 2 + toserver_dp_groups: 25 + - sgh-mpm-context: auto + - inspection-recursion-limit: 3000 + + +At all of these options, you can add (or change) a value. Most +signatures have the adjustment to focus on one direction, meaning +focusing exclusively on the server, or exclusively on the client. + +If you take a look at example 4, _the Detection-engine grouping tree_, +you see it has many branches. At the end of each branch, there is +actually a 'sig group head'. Within that sig group head there is a +container which contains a list with signatures that are significant +for that specific group/that specific end of the branch. Also within +the sig group head the settings for Multi-Pattern-Matcher (MPM) can be +found: the MPM-context. + +As will be described again at the part 'Pattern matching settings', +there are several MPM-algorithms of which can be chosen from. Because +every sig group head has its own MPM-context, some algorithms use a +lot of memory. For that reason there is the option sgh-mpm-context to +set whether the groups share one MPM-context, or to set that every +group has its own MPM-context. + +For setting the option sgh-mpm-context, you can choose from auto, full +or single. The default setting is 'auto', meaning Suricata selects +full or single based on the algorithm you use. 'Full' means that every +group has its own MPM-context, and 'single' that all groups share one +MPM-context. The two algorithms ac and ac-gfbs are new in 1.03. These +algorithms use a single MPM-context if the Sgh-MPM-context setting is +'auto'. The rest of the algorithms use full in that case. + +The inspection-recursion-limit option has to mitigate that possible +bugs in Suricata cause big problems. Often Suricata has to deal with +complicated issues. It could end up in an 'endless loop' due to a bug, +meaning it will repeat its actions over and over again. With the +option inspection-recursion-limit you can limit this action. + +*Example 4 Detection-engine grouping tree* + +.. image:: suricata-yaml/grouping_tree.png + +:: + + src Stands for source IP-address. + dst Stands for destination IP-address. + sp Stands for source port. + dp Stands for destination port. + +*Example 5 Detail grouping tree* + +.. image:: suricata-yaml/grouping_tree_detail.png + +CUDA (Compute United Device Architecture) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Suricata utilizes CUDA for offloading CPU intensive tasks to the +(NVIDIA) GPU (graphics processing unit). Suricata supports an +experimental multi-pattern-matcher using CUDA. Only if you have +compiled Suricata with CUDA (by entering --enable-cuda in the +configure stage) you can make use of these features. There are +several options for CUDA. The option 'packet_buffer_limit' designates +how many packets will be send to the GPU at the same time. Suricata +sends packets in 'batches', meaning it sends multiple packets at +once. As soon as Suricata has collected the amount of packets set in +the 'packet_buffer_limit' option, it sends them to the GPU. The +default amount of packets is 2400. + +The option 'packet_size_limit' makes sure that packets with payloads +bigger than a certain amount of bytes will not be send to the +GPU. Other packets will be send to the GPU. The default setting is +1500 bytes. + +The option 'packet_buffers' designates the amount of buffers that will +be filled with packets and will be processed. Buffers contain the +batches of packets. During the time these filled buffers are being +processed, new buffers will be filled. + +The option 'batching_timeout' can have all values higher than 0. If a +buffers is not fully filled after a period of time (set in this option +'batching_timeout'), the buffer will be send to the GPU anyway. + +The option 'page_locked' designates whether the page locked memory +will or will not be used. The advantage of page locked memory is that +it can not be swapped out to disk. You would not want your computer to +use your hard disk for Suricata, because it lowers the performance a +lot. In this option you can set whether you still want this for CUDA +or not. + +The option 'device_id' is an option within CUDA to determine which GPU +should be turned to account.(If there is only one GPU present at your +computer, there is no benefit making use of the 'device-id' option.) +To detect the id of your GPU's, enter the following in your command +line: + +:: + + suricata --list-cuda-cards + +With the option 'cuda_streams' you can determine how many cuda-streams +should be used for asynchronous processing. All values > 0 are +valid. For this option you need a device with Compute Capability > 1.0 +and page_locked enabled to have any effect. + +:: + + cuda: + -mpm: + packet_buffer_limit: 2400 + packet_size_limit: 1500 + packet_buffers: 10 + batching_timeout: 1 + page_locked: enabled + device_id: 0 + cuda_streams: 2 + +Pattern matcher settings +~~~~~~~~~~~~~~~~~~~~~~~~ + +The multi-pattern-matcher (MPM) is a part of the detection engine +within Suricata that searches for multiple patterns at +once. Generally, signatures have one ore more patterns. Of each +signature, one pattern is used by the multi-pattern-matcher. That way +Suricata can exclude many signatures from being examined, because a +signature can only match when all its patterns match. + +These are the proceedings: + +1)A packet comes in. + +2)The packed will be analysed by the Multi-pattern-matcher in search + of patterns that match. + +3)All patterns that match, will be further processed by Suricata (signatures). + +*Example 8 Multi-pattern-matcher* + +.. image:: suricata-yaml/MPM2.png + +Suricata offers various implementations of different +multi-pattern-matcher algorithm's. These can be found below. + +To set the multi-pattern-matcher algorithm: + +:: + + mpm-algo: b2gc + +After 'mpm-algo', you can enter one of the following algorithms: b2g, +b2gc, b2gm, b3g, wumanber, ac and ac-gfbs (These last two are new in +1.0.3). For more information about these last two, please read again +the the end of the part 'Detection engine'. These algorithms have no +options, so the fact that below there is no option being mentioned is +no omission. + +Subsequently, you can set the options for the mpm-algorithm's. + +The hash_size option determines the size of the hash-table that is +internal used by the pattern matcher. A low hash-size (small table) +causes lower memory usage, but decreases the performance. The opposite +counts for a high hash-size: higher memory usage, but (generally) +higher performance. The memory settings for hash size of the +algorithms can vary from lowest (2048) - low (4096) - medium (8192) - +high (16384) - higher (32768) – max (65536). (Higher is 'highest' in +YAML 1.0 -1.0.2) + +The bf_size option determines the size of the bloom filter, that is +used with the final step of the pattern matcher, namely the validation +of the pattern. For this option the same counts as for the hash-size +option: setting it to low will cause lower memory usage, but lowers +the performance. The opposite counts for a high setting of the +bf_size: higher memory usage, but (generally) higher performance. The +bloom-filter sizes can vary from low (512) - medium (1024) - high +(2048). + +:: + + pattern-matcher: + - b2gc: + search_algo: B2gSearchBNDMq + hash_size: low #Determines the size of the hash-table. + bf_size: medium #Determines the size of the bloom- filter. + - b3g: + search_algo: B3gSearchBNDMq + hash_size: low #See hash-size -b2gc. + bf_size: medium #See bf-size -b2gc. + - wumanber: + hash_size: low #See hash-size -b2gc. + bf_size: medium #See bf-size -b2gc. + +Threading +--------- + +Suricata is multi-threaded. Suricata uses multiple CPU' s/CPU cores so +it can process a lot of network packets simultaneously. (In a +single-core engine, the packets will be processed one at a time.) + +There are four thread-modules: Packet acquisition, decode and stream +application layer, detection, and outputs. + +# The packet acquisition module reads packets from the network. + +# The decode module decodes the packets and the stream application +layer performs its job here. The stream application layer has three +tasks: + +:: + + First: it performs stream-tracking, meaning it is making sure all steps will be taken to make a correct network-connection. + Second: TCP-network traffic comes in as packets. The Stream-Assembly engine reconstructs the original stream. + Finally: the application layer will be inspected. HTTP and DCERPC will be analyzed. + +# The detection threads will compare signatures. There can be several detection threads so they can operate simultaneously. + +# In Outputs all alerts and events will be processed. + +*Example 6 Threading* + +.. image:: suricata-yaml/threading.png + +:: + + Packet acquisition: Reads packets from the network + Decode: Decodes packets. + Stream app. Layer: Performs stream-tracking and reassembly. + Detect: Compares signatures. + Outputs: Processes all events and alerts. + +Most computers have multiple CPU's/ CPU cores. By default the +operating system determines which core works on which thread. When a +core is already occupied, another one will be designated to work on +the thread. So, which core works on which thread, can differ from time +to time. + +There is an option within threading: + +:: + + set-cpu-affinity: no + +With this option you can cause Suricata setting fixed cores for every +thread. In that case 1, 2 and 4 are at core 0 (zero). Each core has +its own detect thread. The detect thread running on core 0 has a lower +priority than the other threads running on core 0. If these other +cores are to occupied, the detect thread on core 0 has not much +packets to process. De detect threads running on other cores will +process more packets. This is only the case after setting the option +at 'yes'. + +*Example 7 Balancing workload* + +.. image:: suricata-yaml/balancing_workload.png + +You can set the detect-thread-ratio: + +:: + + detect-thread-ratio: 1.5 + +The detect thread-ratio will determine the amount of detect +threads. By default it will be 1.5 x the amount of CPU's/CPU cores +present at your computer. This will result in having more detection +threads then CPU's/ CPU cores. Meaning you are oversubscribing the +amount of cores. This may be convenient at times when there have to be +waited for a detection thread. The remaining detection thread can +become active. + + +In the option 'cpu affinity' you can set which CPU's/cores work on +which thread. In this option there are several sets of threads. The +management-, receive-, decode-, stream-, detect-, verdict-, reject- +and outputs-set. These are fixed names and can not be changed. For +each set there are several options: cpu, mode, and prio. In the +option 'cpu' you can set the numbers of the CPU's/cores which will run +the threads from that set. You can set this option to 'all', use a +range (0-3) or a comma separated list (0,1). The option 'mode' can be +set to 'balanced' or 'exclusive'. When set to 'balanced', the +individual threads can be processed by all cores set in the option +'cpu'. If the option 'mode' is set to 'exclusive', there will be fixed +cores for each thread. As mentioned before, threads can have +different priority's. In the option 'prio' you can set a priority for +each thread. This priority can be low, medium, high or you can set the +priority to 'default'. If you do not set a priority for a CPU, than +the settings in 'default' will count. By default Suricata creates one +'detect' thread per available CPU/CPU core. + +:: + + cpu-affinity: + - management-cpu-set: + cpu: [ 0 ] # include only these cpus in affinity settings + - receive-cpu-set: + cpu: [ 0 ] # include only these cpus in affinity settings + - decode-cpu-set: + cpu: [ 0, 1 ] + mode: "balanced" + - stream-cpu-set: + cpu: [ "0-1" ] + - detect-cpu-set: + cpu: [ "all" ] + mode: "exclusive" # run detect threads in these cpus + # Use explicitely 3 threads and don't compute number by using + # detect-thread-ratio variable: + # threads: 3 + prio: + low: [ 0 ] + medium: [ "1-2" ] + high: [ 3 ] + default: "medium" + - verdict-cpu-set: + cpu: [ 0 ] + prio: + default: "high" + - reject-cpu-set: + cpu: [ 0 ] + prio: + default: "low" + - output-cpu-set: + cpu: [ "all" ] + prio: + default: "medium" + +IP Defrag +--------- + +Occasionally network packets appear fragmented. On some networks it +occurs more often than on others. Fragmented packets exist of many +parts. Before Suricata is able to inspect these kind of packets +accurately, the packets have to be reconstructed. This will be done by +a component of Suricata; the defragment-engine. After a fragmented +packet is reconstructed by the defragment-engine, the engine sends on +the reassembled packet to rest of Suricata. + +There are three options within defrag: max-frags, prealloc and +timeout. At the moment Suricata receives a fragment of a packet, it +keeps in memory that other fragments of that packet will appear soon +to complete the packet. However, there is a possibility that one of +the fragments does not appear. To prevent Suricata for keeping waiting +for that packet (thereby using memory) there is a timespan after which +Suricata discards the fragments. This occurs by default after 60 +seconds. + +:: + + defrag: + max-frags: 65535 + prealloc: yes + timeout: 60 + +Flow and Stream handling +------------------------ + +Flow Settings +~~~~~~~~~~~~~ + +Within Suricata, Flows are very important. They play a big part in the +way Suricata organizes data internally. A flow is a bit similar to a +connection, except a flow is more general.All packets having the same +Tuple (protocol, source IP, destination IP, source-port, +destination-port), belong to the same flow. Packets belonging to a +flow are connected to it internally. + +*Example 9 Flow* + +.. image:: suricata-yaml/flow.png + +*Example 10 Tuple* + +.. image:: suricata-yaml/Tuple1.png + +Keeping track of all these flows, uses memory. The more flows, the +more memory it will cost. + +To keep control over memory usage, there are several options: + +The option memcap for setting the maximum amount of bytes the +flow-engine will use, hash-size for setting the size of the hash-table +and prealloc for the following: + + For packets not yet belonging to a flow, Suricata creates a + new flow. This is a relative expensive action. The risk coming + with it, is that attackers /hackers can a attack the engine + system at this part. When they make sure a computer gets a lot + of packets with different tuples, the engine has to make a lot + of new flows. This way, an attacker could flood the system. To + mitigate the engine from being overloaded, this option + instructs Suricata to keep a number of flows ready in + memory. This way Suricata is less vulnerable to these kind of + attacks. + +The flow-engine has a management thread that operates independent from +the packet processing. This thread is called the flow-manager. This +thread ensures that wherever possible and within the memcap. there +will be 10000 flows prepared. + +:: + + flow: + memcap: 33554432 #The maximum amount of bytes the flow-engine will make use of. + hash_size: 65536 #Flows will be organized in a hash-table. With this option you can set the + #size of the hash-table. + Prealloc: 10000 #The amount of flows Suricata has to keep ready in memory. + +At the point the memcap will still be reached, despite prealloc, the +flow-engine goes into the emergency-mode. In this mode, the engine +will make use of shorter time-outs. It lets flows expire in a more +aggressive manner so there will be more space for new Flows. + +There are two options: emergency_recovery and prune_flows. The +emergency recovery is set on 30. This is the percentage of prealloc'd +flows after which the flow-engine will be back to normal (when 30 +percent of the 10000 flows is completed). + + If during the emergency-mode, the aggressive time-outs do not + have the desired result, this option is the final resort. It + ends some flows even if they have not reached their time-outs + yet. The prune-flows option shows how many flows there will be + terminated at each time a new flow is set up. + +:: + + emergency_recovery: 30 #Percentage of 1000 prealloc'd flows. + prune_flows: 5 #Amount of flows being terminated during the emergency mode. + +Flow Time-Outs +~~~~~~~~~~~~~~ + +The amount of time Suricata keeps a flow in memory is determined by +the Flow time-out. + +There are different states in which a flow can be. Suricata +distinguishes three flow-states for TCP and two for UDP. For TCP, +these are: New, Established and Closed,for UDP only new and +established. For each of these states Suricata can employ different +timeouts. + +The state new in a TCP-flow, means the period during the three way +handshake. The state established is the state when the three way +handshake is completed. The state closed in the TCP-flow: there a +several ways to end a flow. This is by means of Reset or the Four-way +FIN handshake. + +New in a UDP-flow: the state in which packets are send from only one +direction. + +Established in a UDP-flow: packets are send from both directions. + +In the example configuration the are settings for each protocol. TCP, +UDP, ICMP and default (all other protocols). + +:: + + flow-timeouts: + + default: + new: 30 #Time-out in seconds after the last activity in this flow in a New state. + established: 300 #Time-out in seconds after the last activity in this flow in a Established + #state. + emergency_new: 10 #Time-out in seconds after the last activity in this flow in a New state + #during the emergency mode. + emergency_established: 100 #Time-out in seconds after the last activity in this flow in a Established + #state in the emergency mode. + tcp: + new: 60 + established: 3600 + closed: 120 + emergency_new: 10 + emergency_established: 300 + emergency_closed: 20 + udp: + new: 30 + established: 300 + emergency_new: 10 + emergency_established: 100 + icmp: + new: 30 + established: 300 + emergency_new: 10 + emergency_established: 100 + +Stream-engine +~~~~~~~~~~~~~ + +The Stream-engine keeps track of the TCP-connections. The engine +exists of two parts: The stream tracking- and the reassembly-engine. + +The stream-tracking engine monitors the state of a connection. The +reassembly-engine reconstructs the flow as it used to be, so it will +be recognised by Suricata. + +The stream-engine has two memcaps that can be set. One for the +stream-tracking-engine and one for the reassembly-engine. + +The stream-tracking-engine keeps information of the flow in +memory. Information about the state, TCP-sequence-numbers and the TCP +window. For keeping this information, it can make use of the capacity +the memcap allows. + +TCP packets have a so-called checksum. This is an internal code which +makes it possible to see if a packet has arrived in a good state. The +stream-engine will not process packets with a wrong checksum. This +option can be set off by entering 'no' instead of 'yes'. + +:: + + stream: + memcap: 33554432 #Amount of flow-information (in bytes) to keep in memory. + checksum_validation: yes #Validate packet checksum, reject packets with invalid checksums. + +The option 'max_sessions' is the limit for concurrent sessions. It +prevents Suricata from using all memory for sessions. + +To mitigate Suricata from being overloaded by fast session creation, +the option prealloc_sessions instructs Suricata to keep a number of +sessions ready in memory. + +A TCP-session starts with the three-way-handshake. After that, data +can be send en received. A session can last a long time. It can happen +that Suricata will be running after a few sessions have already been +started. This way, Suricata misses the original setup of those +sessions. This setup always includes a lot of information. If you want +Suricata to check the stream from that time on, you can do so by +setting the option 'midstream' to 'true'. The default setting is +'false'. Normally Suricata is able to see all packets of a +connection. Some networks make it more complicated though. Some of the +network-traffic follows a different route than the other part, in +other words: the traffic goes asynchronous. To make sure Suricata will +check the one part it does see, instead of getting confused, the +option 'async-oneside' is brought to life. By default the option is +set to 'false'. + +Suricata inspects content in the normal/IDS mode in chunks. In the +inline/IPS mode it does that on the sliding window way (see example +..) In the case Suricata is set in inline mode, it has to inspect +packets immediately before sending it to the receiver. This way +Suricata is able to drop a packet directly if needed.(see example …) +It is important for Suricata to note which operating system it is +dealing with, because operating systems differ in the way they process +anomalies in streams. See :ref:`host-os-policy`. + +:: + + max_sessions: 262144 # 256k concurrent sessions + prealloc_sessions: 32768 # 32k sessions prealloc'd + midstream: false # do not allow midstream session pickups + async_oneside: false # do not enable async stream handling + inline: no # stream inline mode + +**Example 11 Normal/IDS mode** + +Suricata inspects traffic in chunks. + +.. image:: suricata-yaml/normal_ids.png + +**Example 12 Inline/IPS Sliding Window** + +Suricata inspects traffic in a sliding window manner. + +.. image:: suricata-yaml/inline_mode.png + +**Example 13 Normal/IDS (reasembly on ACK'D data)** + +.. image:: suricata-yaml/Normal_ids_ack_d.png + +**Example 14 Inline/IPS (reassembly on UNACK'D data)** + +.. image:: suricata-yaml/Inline_reassembly_unackd_data.png + +The reassembly-engine has to keep packets in memory to be able to make +a reassembled stream. It can make use of the amount of bytes set +below. Reassembling a stream is an expensive operation. In the option +depth you can set the depth (in a stream) of the reassembling. By +default this is 1MB. + +:: + + reassembly: + memcap: 67108864 #Amount of packets (in bytes) to keep in memory. + depth: 1048576 #The depth of the reassembling. + toserver_chunk_size: 2560 # inspect raw stream in chunks of at least this size + toclient_chunk_size: 2560 # inspect raw stream in chunks of at least + +*Example 15 Stream reassembly* + +.. image:: suricata-yaml/reassembly1.png + +.. image:: suricata-yaml/IDS_chunk_size.png + +Application Layer Parsers +------------------------- + +Asn1_max_frames (new in 1.0.3 and 1.1) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Asn1 (`Abstract Syntax One +`_) is a +standard notation to structure and describe data. + +Within Asn1_max_frames there are several frames. To protect itself, +Suricata will inspect a maximum of 256. You can set this amount +differently if wanted. + +Application layer protocols such as X.400 electronic mail, X.500 and +LDAP directory services, H.323 (VoIP), BACnet and SNMP, use ASN.1 to +describe the protocol data units (PDUs) they exchange. It is also +extensively used in the Access and Non-Access Strata of UMTS. + +Limit for the maximum number of asn1 frames to decode (default 256): + +:: + + asn1_max_frames: 256 + +Configure HTTP (libhtp) +~~~~~~~~~~~~~~~~~~~~~~~ + +The library Libhtp is being used by Suricata to parse HTTP-sessions. + +While processing HTTP-traffic, Suricata has to deal with different +kind of servers which each process anomalies in HTTP-traffic +differently. The most common web-server is Apache. This is a open +source web -server program. + +Beside Apache, IIS (Internet Information Services/Server)a web-server +program of Microsoft is also well-known. + +Like with host-os-policy, it is important for Suricata to which +IP-address/network-address is used by which server. In Libhtp this +assigning of web-servers to IP-and network addresses is called +personality. + +Currently Available Personalities: + +* Minimal +* Generic +* IDS (default) +* IIS_4_0 +* IIS_5_0 +* IIS_5_1 +* IIS_6_0 +* IIS_7_0 +* IIS_7_5 +* Apache +* Apache_2_2 + +You can assign names to each block of settings. Which in this case +is -apache and -iis7. Under these names you can set IP-addresses, +network-addresses the personality and the request-body-limit. + +The version-specific personalities know exactly how web servers +behave, and emulate that. The IDS personality (will be GENERIC in the +future) would try to implement a best-effort approach that would work +reasonably well in the cases where you do not know the specifics. + +The default configuration also applies to every IP-address for which +no specific setting is available. + +HTTP request body's are often big, so they take a lot of time to +process which has a significant impact on the performance. With the +option 'request-body-limit' you can set the limit (in bytes) of the +client-body that will be inspected. Setting it to 0 will inspect all +of the body. + +HTTP response body's are often big, so they take a lot of time to +process which has a significant impact on the performance. With the +option 'response-body-limit' you can set the limit (in bytes) of the +server-body that will be inspected. Setting it to 0 will inspect all +of the body. + +:: + + libhtp: + + default-config: + personality: IDS + request-body-limit: 3072 + response-body-limit: 3072 + + server-config: + - apache: + address: [192.168.1.0/24, 127.0.0.0/8, "::1"] + personality: Apache_2_2 + request-body-limit: 0 + response-body-limit: 0 + + - iis7: + address: + - 192.168.0.0/24 + - 192.168.10.0/24 + personality: IIS_7_0 + request-body-limit: 4096 + response-body-limit: 8192 + +As of 1.4, Suricata makes available the whole set of libhtp +customisations for its users. + +You can now use these parameters in the conf to customise suricata's +use of libhtp. + +:: + + # Configures whether backslash characters are treated as path segment + # separators. They are not on Unix systems, but are on Windows systems. + # If this setting is enabled, a path such as "/one\two/three" will be + # converted to "/one/two/three". Accepted values - yes, no. + #path-backslash-separators: yes + + # Configures whether consecutive path segment separators will be + # compressed. When enabled, a path such as "/one//two" will be normalized + # to "/one/two". The backslash_separators and decode_separators + # parameters are used before compression takes place. For example, if + # backslash_separators and decode_separators are both enabled, the path + # "/one\\/two\/%5cthree/%2f//four" will be converted to + # "/one/two/three/four". Accepted values - yes, no. + #path-compress-separators: yes + + # This parameter is used to predict how a server will react when control + # characters are present in a request path, but does not affect path + # normalization. Accepted values - none or status_400 */ + #path-control-char-handling: none + + # Controls the UTF-8 treatment of request paths. One option is to only + # validate path as UTF-8. In this case, the UTF-8 flags will be raised + # as appropriate, and the path will remain in UTF-8 (if it was UTF-8 in + # the first place). The other option is to convert a UTF-8 path into a + # single byte stream using best-fit mapping. Accepted values - yes, no. + #path-convert-utf8: yes + + # Configures whether encoded path segment separators will be decoded. + # Apache does not do this, but IIS does. If enabled, a path such as + # "/one%2ftwo" will be normalized to "/one/two". If the + # backslash_separators option is also enabled, encoded backslash + # characters will be converted too (and subseqently normalized to + # forward slashes). Accepted values - yes, no. + #path-decode-separators: yes + + # Configures whether %u-encoded sequences in path will be decoded. Such + # sequences will be treated as invalid URL encoding if decoding is not + # desireable. Accepted values - yes, no. + #path-decode-u-encoding: yes + + # Configures how server reacts to invalid encoding in path. Accepted + # values - preserve_percent, remove_percent, decode_invalid, status_400 + #path-invalid-encoding-handling: preserve_percent + + # Configures how server reacts to invalid UTF-8 characters in path. + # This setting will not affect path normalization; it only controls what + # response status we expect for a request that contains invalid UTF-8 + # characters. Accepted values - none, status_400. + #path-invalid-utf8-handling: none + + # Configures how server reacts to encoded NUL bytes. Some servers will + # terminate path at NUL, while some will respond with 400 or 404. When + # the termination option is not used, the NUL byte will remain in the + # path. Accepted values - none, terminate, status_400, status_404. + # path-nul-encoded-handling: none + + # Configures how server reacts to raw NUL bytes. Some servers will + # terminate path at NUL, while some will respond with 400 or 404. When + # the termination option is not used, the NUL byte will remain in the + # path. Accepted values - none, terminate, status_400, status_404. + path-nul-raw-handling: none + + # Sets the replacement characater that will be used to in the lossy + # best-fit mapping from Unicode characters into single-byte streams. + # The question mark is the default replacement character. + #set-path-replacement-char: ? + + # Controls what the library does when it encounters an Unicode character + # where only a single-byte would do (e.g., the %u-encoded characters). + # Conversion always takes place; this parameter is used to correctly + # predict the status code used in response. In the future there will + # probably be an option to convert such characters to UCS-2 or UTF-8. + # Accepted values - bestfit, status_400 and status_404. + #set-path-unicode-mapping: bestfit + +Engine output +------------- + +Logging configuration +~~~~~~~~~~~~~~~~~~~~~ + +The logging subsystem can display all output except alerts and +events. It gives information at runtime about what the engine is +doing. This information can be displayed during the engine startup, at +runtime and while shutting the engine down. For informational +messages, errors, debugging, etc. + +The log-subsystem has several log levels: + +Error, warning, informational and debug. Note that debug level logging +will only be emitted if Suricata was compiled with the --enable-debug +configure option. + +The first option within the logging configuration is the +default-log-level. This option determines the severity/importance +level of information that will be displayed. Messages of lower levels +than the one set here, will not be shown. The default setting is +Info. This means that error, warning and info will be shown and the +other levels won't be. + +There are more levels: emergency, alert, critical and notice, but +those are not used by Suricata yet. This option can be changed in the +configuration, but can also be overridden in the command line by the +environment variable: SC_LOG_LEVEL . + +:: + + logging: + default-log-level: info + +Default log format +~~~~~~~~~~~~~~~~~~ + +A logging line exists of two parts. First it displays meta information +(thread id, date etc.), and finally the actual log message. Example: + +:: + + [27708] 15/10/2010 -- 11:40:07 - (suricata.c:425) (main) – This is Suricata version 1.0.2 + +(Here the part until the – is the meta info, “This is Suricata 1.0.2” +is the actual message.) + +It is possible to determine which information will be displayed in +this line and (the manner how it will be displayed) in which format it +will be displayed. This option is the so called format string:: + + default-log-format: "[%i] %t - (%f:%l) <%d> (%n) -- " + +The % followed by a character, has a special meaning. There are eight +specified signs: + +:: + + t: Time, timestamp, time and date + example: 15/10/2010 - -11:40:07 + p: Process ID. Suricata's whole processing consists of multiple threads. + i: Thread ID. ID of individual threads. + m: Thread module name. (Outputs, Detect etc.) + d: Log-level of specific log-event. (Error, info, debug etc.) + f: Filename. Name of C-file (source code) where log-event is generated. + l: Line-number within the filename, where the log-event is generated in the source-code. + n: Function-name in the C-code (source code). + +The last three, f, l and n are mainly convenient for developers. + +The log-format can be overridden in the command line by the +environment variable: SC_LOG_FORMAT + +Output-filter +~~~~~~~~~~~~~ + +Within logging you can set an output-filter. With this output-filter +you can set which part of the event-logs should be displayed. You can +supply a regular expression (Regex). A line will be shown if the regex +matches. + +:: + + default-output-filter: #In this option the regular expression can be entered. + +This value is overridden by the environment var: SC_LOG_OP_FILTER + +Outputs +~~~~~~~ + +There are different ways of displaying output. The output can appear +directly on your screen, it can be placed in a file or via syslog. The +last mentioned is an advanced tool for log-management. The tool can be +used to direct log-output to different locations (files, other +computers etc.) + +:: + + outputs: + - console: #Output on your screen. + enabled: yes #This option is enabled. + - file: #Output stored in a file. + enabled: no #This option is not enabled. + filename: /var/log/suricata.log #Filename and location on disc. + - syslog: #This is a program to direct log-output to several directions. + enabled: no #The use of this program is not enabled. + facility: local5 #In this option you can set a syslog facility. + format: "[%i] <%d> -- " #The option to set your own format. + +Packet Acquisition +------------------ + +Pf-ring +~~~~~~~ + +The Pf_ring is a library that aims to improve packet capture +performance over libcap. It performs packet acquisition. There are +three options within Pf_ring: interface, cluster-id and cluster-type. + +:: + + pfring: + interface: eth0 # In this option you can set the network-interface + # on which you want the packets of the network to be read. + +Pf_ring will load balance packets based on flow. All packet +acquisition threads that will participate in the load balancing need +to have the same cluster-id. It is important to make sure this ID is +unique for this cluster of threads, so that no other engine / program +is making use of clusters with the same id. + +:: + + cluster-id: 99 + +Pf_ring can load balance traffic using pf_ring-clusters. All traffic +for pf_ring can be load balanced in one of two ways, in a round robin +manner or a per flow manner that are part of the same cluster. All +traffic for pf_ring will be load balanced across acquisition threads +of the same cluster id. + +The cluster_round_robin manner is a way of distributing packets one at +a time to each thread (like distributing playing cards to fellow +players). The cluster_flow manner is a way of distributing all packets +of the same flow to the same thread. The flows itself will be +distributed to the threads in a round-robin manner. + +:: + + cluster-type: cluster_round_robin + +.. _suricata-yaml-nfq: + +NFQ +~~~ + +Using NFQUEUE in iptables rules, will send packets to Suricata. If the +mode is set to 'accept', the packet that has been send to Suricata by +a rule using NFQ, will by default not be inspected by the rest of the +iptables rules after being processed by Suricata. There are a few more +options to NFQ to change this if desired. + +If the mode is set to 'repeat', the packets will be marked by Suricata +and be re-injected at the first rule of iptables. To mitigate the +packet from being going round in circles, the rule using NFQ will be +skipped because of the mark. + +If the mode is set to 'route', you can make sure the packet will be +send to another tool after being processed by Suricata. It is possible +to assign this tool at the mandatory option 'route_queue'. Every +engine/tool is linked to a queue-number. This number you can add to +the NFQ rule and to the route_queue option. + +Add the numbers of the options repeat_mark and route_queue to the NFQ-rule:: + + iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE + +:: + + nfq: + mode: accept #By default the packet will be accepted or dropped by Suricata + repeat_mark: 1 #If the mode is set to 'repeat', the packets will be marked after being + #processed by Suricata. + repeat_mask: 1 + route_queue: 2 #Here you can assign the queue-number of the tool that Suricata has to + #send the packets to after processing them. + +*Example 1 NFQ * + +mode: accept + +.. image:: suricata-yaml/NFQ.png + +*Example 2 NFQ* + +mode: repeat + +.. image:: suricata-yaml/NFQ1.png + +*Example 3 NFQ* + +mode: route + +.. image:: suricata-yaml/NFQ2.png + +Ipfw +~~~~ + +Suricata does not only support Linux, it supports the FreeBSD +operating system (this is an open source Unix operating system) and +Mac OS X as well. The in-line mode on FreeBSD uses ipfw (IP-firewall). + +Certain rules in ipfw send network-traffic to Suricata. Rules have +numbers. In this option you can set the rule to which the +network-traffic will be placed back. Make sure this rule comes after +the one that sends the traffic to Suricata, otherwise it will go +around in circles. + +The following tells the engine to re-inject packets back into the ipfw +firewall at rule number 5500: + +:: + + ipfw: + ipfw-reinjection-rule-number: 5500 + +*Example 16 Ipfw-reinjection.* + +.. image:: suricata-yaml/ipfw_reinjection.png + +Rules +----- + +Rule-files +~~~~~~~~~~ + +For different categories of risk there are different rule-files +available containing one or more rules. There is a possibility to +instruct Suricata where to find these rules and which rules you want +to be load for use. You can set the directory where the files can be +found. + +:: + + default-rule-path: /etc/suricata/rules/ + rule-files: + - backdoor.rules + - bad-traffic.rules + - chat.rules + - ddos.rules + - .... + +The above mentioned is an example of rule-files of which can be chosen +from. There are much more rule-files available. + +If wanted, you can set a full path for a specific rule or +rule-file. In that case, the above directory (/etc/suricata/rules/) +will be ignored for that specific file. This is convenient in case you +write your own rules and want to store them separate from other rules +like that of VRT, ET or ET pro. + +If you set a file-name that appears to be not existing, Suricata will +ignore that entry and display a error-message during the engine +startup. It will continue with the startup as usual. + +Threshold-file +~~~~~~~~~~~~~~ + +Within this option, you can state the directory in which the +threshold-file will be stored. The default directory is: +/etc/suricata/threshold.config + +Classifications +~~~~~~~~~~~~~~~ + +The Classification-file is a file which makes the purpose of rules +clear. + +Some rules are just for providing information. Some of them are to +warn you for serious risks like when you are being hacked etc. + +In this classification-file, there is a part submitted to the rule to +make it possible for the system-administrator to distinguish events. + +A rule in this file exists of three parts: the short name, a +description and the priority of the rule (in which 1 has the highest +priority and 4 the lowest). + +You can notice these descriptions returning in the rule and events / alerts. + +:: + + Example: + + configuration classification: misc-activity,Misc activity,3 + + Rule: + + alert tcp $HOME_NET 21 -> $EXTERNAL_NET any (msg:"ET POLICY FTP Login Successful (non-anonymous)"; + flow:from_server,established;flowbits:isset,ET.ftp.user.login; flowbits:isnotset,ftp.user.logged_in; + flowbits:set,ftp.user.logged_in; content:"230 ";pcre:!"/^230(\s+USER)?\s+(anonymous|ftp)/smi"; + classtype:misc-activity; reference:urldoc.emergingthreats.net/2003410,; + reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/POLICY/POLICY_FTP_Login; sid:2003410; rev:7;) + + Event/Alert: + + 10/26/10-10:13:42.904785 [**] [1:2003410:7] ET POLICY FTP Login Successful (non-anonymous) [**] + [Classification: Misc activity[Priority: 3] {TCP} 192.168.0.109:21 -> x.x.x.x:34117 + +You can set the direction of the classification configuration. + +:: + + classification-file: /etc/suricata/classification.config + +Rule-vars +~~~~~~~~~ + +There are variables which can be used in rules. + +Within rules, there is a possibility to set for which IP-address the +rule should be checked and for which IP-address it should not. + +This way, only relevant rules will be used. To prevent you from having +to set this rule by rule, there is an option in which you can set the +relevant IP-address for several rules. This option contains the +address group vars that will be passed in a rule. So, after HOME_NET +you can enter your home IP-address. + +:: + + vars: + address-groups: + HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" #By using [], it is possible to set + #complicated variables. + EXTERNAL_NET: any + HTTP_SERVERS: "$HOME_NET" #The $-sign tells that what follows is + #a variable. + SMTP_SERVERS: "$HOME_NET" + SQL_SERVERS: "$HOME_NET" + DNS_SERVERS: "$HOME_NET" + TELNET_SERVERS: "$HOME_NET" + AIM_SERVERS: any + +It is a convention to use upper-case characters. + +There are two kinds of variables: Address groups and Port-groups. They +both have the same function: change the rule so it will be relevant to +your needs. + +In a rule there is a part assigned to the address and one to the +port. Both have their variable. + +All options have to be set. If it is not necessary to set a specific +address, you should enter 'any'. + +:: + + port-groups: + HTTP_PORTS: "80" + SHELLCODE_PORTS: "!80" + ORACLE_PORTS: 1521 + SSH_PORTS: 22 + +.. _host-os-policy: + +Host-os-policy +~~~~~~~~~~~~~~ + +Operating systems differ in the way they process fragmented packets +and streams. Suricata performs differently with anomalies for +different operating systems. It is important to set of which operating +system your IP-address makes use of, so Suricata knows how to process +fragmented packets and streams. For example in stream-reassembly there +can be packets with overlapping payloads. + +*Example 17 Overlapping payloads* + +.. image:: suricata-yaml/overlap.png + +In the configuration-file, the operating-systems are listed. You can +add your IP-address behind the name of the operating system you make +use of. + +:: + + host-os-policy: + windows: [0.0.0.0/0] + bsd: [] + bsd_right: [] + old_linux: [] + linux: [10.0.0.0/8, 192.168.1.100, "8762:2352:6241:7245:E000:0000:0000:0000"] + old_solaris: [] + solaris: ["::1"] + hpux10: [] + hpux11: [] + irix: [] + macos: [] + vista: [] + windows2k3: [] + +Engine analysis and profiling +----------------------------- + +Suricata offers several ways of analyzing performance of rules and the +engine itself. + +Engine-analysis +~~~~~~~~~~~~~~~ + +The option engine-analysis provides information for signature writers +about how Suricata organises signatures internally. + +Like mentioned before, signatures have zero or more patterns on which +they can match. Only one of these patterns will be used by the multi +pattern matcher (MPM). Suricata determines which patterns will be used +unless the fast-pattern rule option is used. + +The option engine-analysis creates a new log file in the default log +dir. In this file all information about signatures and patterns can be +found so signature writers are able to see which pattern is used and +change it if desired. + +To create this log file, you have to run Suricata with +./src/suricata -c suricata.yaml --engine-analysis. + +:: + + engine-analysis: + rules-fast-pattern: yes + +Example: + +:: + + [10703] 26/11/2010 -- 11:41:15 - (detect.c:560) (SigLoadSignatures) + -- Engine-Analyis for fast_pattern printed to file - /var/log/suricata/rules_fast_pattern.txt + + == Sid: 1292 == + Fast pattern matcher: content + Fast pattern set: no + Fast pattern only set: no + Fast pattern chop set: no + Content negated: no + Original content: Volume Serial Number + Final content: Volume Serial Number + + --- + + alert tcp any any -> any any (content:"abc"; content:"defghi"; sid:1;) + + == Sid: 1 == + Fast pattern matcher: content + Fast pattern set: no + Fast pattern only set: no + Fast pattern chop set: no + Content negated: no + Original content: defghi + Final content: defghi + + --- + + alert tcp any any -> any any (content:"abc"; fast_pattern:only; content:"defghi"; sid:1;) + + == Sid: 1 == + Fast pattern matcher: content + Fast pattern set: yes + Fast pattern only set: yes + Fast pattern chop set: no + Content negated: no + Original content: abc + Final content: abc + + --- + + alert tcp any any -> any any (content:"abc"; fast_pattern; content:"defghi"; sid:1;) + + == Sid: 1 == + Fast pattern matcher: content + Fast pattern set: yes + Fast pattern only set: no + Fast pattern chop set: no + Content negated: no + Original content: abc + Final content: abc + + --- + + alert tcp any any -> any any (content:"abc"; fast_pattern:1,2; content:"defghi"; sid:1;) + + == Sid: 1 == + Fast pattern matcher: content + Fast pattern set: yes + Fast pattern only set: no + Fast pattern chop set: yes + Fast pattern offset, length: 1, 2 + Content negated: no + Original content: abc + Final content: bc + +Rule and Packet Profiling settings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Rule profiling is a part of Suricata to determine how expensive rules +are. Some rules are very expensive while inspecting traffic. Rule +profiling is convenient for people trying to track performance +problems and resolving them. Also for people writing signatures. + +Compiling Suricata with rule-profiling will have an impact on +performance, even if the option is disabled in the configuration file. + +To observe the rule-performance, there are several options. + +:: + + profiling: + rules: + enabled: yes + +This engine is not used by default. It can only be used if Suricata is +compiled with: + +:: + + -- enable-profiling + +At the end of each session, Suricata will display the profiling +statistics. The list will be displayed sorted. + +This order can be changed as pleased. The choice is between ticks, +avgticks, checks, maxticks and matches. The setting of your choice +will be displayed from high to low. + +The amount of time it takes to check the signatures, will be +administrated by Suricata. This will be counted in ticks. One tick is +one CPU computation. 3 GHz will be 3 billion ticks. + +Beside the amount of checks, ticks and matches it will also display +the average and the maximum of a rule per session at the end of the +line. + +The option Limit determines the amount of signatures of which the +statistics will be shown, based on the sorting. + +:: + + sort: avgticks + limit: 100 + +Example of how the rule statistics can look like; + +:: + + Rule Ticks % Checks Matches Max Tick Avg + Ticks + + 7560 107766621 0.02 138 37 105155334 780917.54 + 11963 1605394413 0.29 2623 1 144418923 612045.14 + 7040 1431034011 0.26 2500 0 106018209 572413.60 + 5726 1437574662 0.26 2623 1 115632900 548065.06 + 7037 1355312799 0.24 2562 0 116048286 529005.78 + 11964 1276449255 0.23 2623 1 96412347 486637.15 + 7042 1272562974 0.23 2623 1 96405993 485155.54 + 5719 1233969192 0.22 2562 0 106439661 481642.93 + 5720 1204053246 0.21 2562 0 125155431 469966.14 + +Packet Profiling +~~~~~~~~~~~~~~~~ + +:: + + packets: + + # Profiling can be disabled here, but it will still have a + # performance impact if compiled in. + + + enabled: yes #this option is enabled by default + filename: packet_stats.log #name of the file in which packet profiling information will be + #stored. + append: yes #If set to yes, new packet profiling information will be added to the + #information that was saved last in the file. + + # per packet csv output + csv: + + # Output can be disabled here, but it will still have a + # performance impact if compiled in. + + enabled: no #the sending of packet output to a csv-file is by default disabled. + filename: packet_stats.csv #name of the file in which csv packet profiling information will be + #stored + +Packet profiling is enabled by default in suricata.yaml but it will +only do its job if you compiled Suricata with --enable profiling. + +The filename in which packet profiling information will be stored, is +packet-stats.log. Information in this file can be added to the last +information that was saved there, or if the append option is set to +no, the existing file will be overwritten. + +Per packet, you can send the output to a csv-file. This file contains +one line for each packet with all profiling information of that +packet. This option can be used only if Suricata is build +with --enable-profiling and if the packet profiling option is enabled +in yaml. + +It is best to use runmode 'single' if you would like to profile the +speed of the code. When using a single thread, there is no situation +in which two threads have to wait for each other . When using two +threads, the time threads might have to wait for each other will be +taken in account when/during profiling packets. For more information +see :doc:`../performance/packet-profiling`. diff --git a/doc/sphinx/configuration/suricata-yaml/IDS_chunk_size.png b/doc/sphinx/configuration/suricata-yaml/IDS_chunk_size.png new file mode 100644 index 0000000000000000000000000000000000000000..61dcb207d64268ced4d703ec1a9e30f6bf653031 GIT binary patch literal 23331 zcmb@uWmp_d*Dgv70wfUJAq?)p9YPo!hTsmtT?Z#X5`w$i01xi&?hbI^Y{BAo(Y5G zIT6KKMnM8)@ii_6Ci?G}1E@$yACY8$Vyf;7hs$oxxN0QGrwHiCah|xv&vEO5%zPzm z&yyE9vM6G2_RvCp(Mx=O17u*7@Qh__b&JB7{PMOiC#uQC>=@A>@Zk%+Pe29g*ok|@ zr@??xK~6*?0=i7p$4~cMZ7TIYuaS^`#64U8S@s1IlJeghV|asvB+c-Akc0dD^EWB# z`9A+m`uC!bxzA^Rlm3T%|0eyv^8wcHS8aUOFxQ@D5A?6b&Y!NcS8OJ(+ZP^bL;JwH zV)i;HE7kEeoyL*ve}vC`5&9WE7ruhK?#Fy@Da~_mjR#*Hz)CkXL_cf9o zbnA%h!=IBAim$89dFIOjev+eA4p+C~$j0)%?k0Ob%Jr))WSusXP}@_|@7OUh*$$^i z#>x$;$^~i#uP8302Z>6Njq@T&xC@SS*gig6vbtLDs>b%D9_zEv`=}uOsSo-vSq3^$ zDAyA24%buJIq~i!AWA-|xBRp0xi3p1bVX>)>}c>n%zaOMd-uHYmKe-bo29b)MFJm- z5ks0?qP6?i5KK9b(Zr(%pUGG78|BJ0u+(e!SqoUtSbzK0uOr^-oKz&~LW0R%XO_GN z$LrJRZm9^!P`?c%j zn=-OY@?-UtxDN0oWhYCg%un_>ob|F5UC6GyVh0Zt$%UP-?xRys`@MW!eg$m>ZRlsu z@DK_=ovu+yMUe8ltS!`?c#;}$Z6&5U(Q?Z_c+qm3#Hi=v8EkY=8C{OuaPl7a3O!}> z?SzGizB^W#o>9V;ShS@#$T)`sA)i{($D zF?TmG#)?OPK_&|=+rOEGE`%YPa|U3M)#!@D-CS=JP}xJx%%kmrno$@M1Dtk{R(!!x zw`%QlTW!-Xl?{iAduz=t+w*1`etuQNyS~UB%s~Yu+7Rnkf5TI((Ol*hskjZyDZaX2mGD5^lp)1mA=}mFcB=R7tb2%_TWUP_rLR!7IKBG7Fp!0g)G@-0By8r2M zC-K$dTPx^pLSfN;O()ACcV*#5n_7Nw5Cg;Fw&L4U_*K!yjO921VjZt9D2V1agyKdY zovmCz;guA`Ckm2j5ea(IY_{_ArbMGc6R5278V=CcUnyN7@t_e(X1}_=)Xu=bN#3f^ z2p90m%HVlR%P4f5$`-)QEDH&OG+h?NIi1z;?~vYB%|~7Bbh+HQmgXL7d8gw1^P^rAja7Od6<(0c(*zX^d`u-*)BDaK&;~u!VyPJK8=VGqT3TJbMZ)3$^;t_+vOzmWA8uhMZ?c1TQdP*5G*m<-o zmOFd=t`FRONoy0O41R)lx3||f^$(`Arbc1xJXP^0c;QR4UL+_H zjKx#{#u=wg7>xlM#Q2kc+>pANpTxngG$e9Q^iKvL4V1y}aewWT4<7DkTagJPI%Yk& zI6Dt6#z+$ee=k@(t)__F8j^5_>RO~a?n6HJ(zP)dM5~8Dd|fwf%_1UQ$s zHu&6LyF`0olz`n#nh8MHHt_KGcM<7)-c1I3`L@Od&t$VK5R&!=33 zfaCT^@B`D8kEnAe>|jryOt20-+eI}ya;zR7x7eD3;HpmrAI_b{Ht(dRESN7H^8s!R zk1&}#?ItpDM7h|~%XkOH?S+|7)Ykh^A5yr`c173n`9P3QNnd1J4P#n2VlfI$XYZp0 zyN2E!7)0RQZ6iwM=w4%Mu%Ml&bDq@tehJzgvkbk!yswK$RsX>CVk6;+C%gJ~v$u1x zjl7w~XKSbz0}_OdI246>tdn{v#ZYGs$5nPE$L5Fk5VA|ke|W7V?`Bd>>K2EdMSC<> zkID9QTXQ=oZ2&mOfK=L_Ot!ej^qQO&XdBqSok+czQ6s^zx{fS})u58;)$ysaoX95z z@81VgZh!ff!GM!+Qfe^yQ+ip*R%{|teTH%UV{nN@TASM8?^lT@AEN0$L6dsumu=|1 z1PpuUVDo-3lKaFPqsCOQoSrkWjLE3T zZO>lDffRNS7V1lO+Mt*?*9u2aSfz(?zeo6OSy&(Jpf8v-P5H?t_--flO?z`9!VR!q z#)7FQ0Lx73!P9cF-#;P;ZyTWv8k(OVBS^;s*_C#_y03MambQj!8Wg*HFvr{_UEWNk zc~$%=EA?PDFdp$x=WQtyGmv@T!`7VfpJHlw}>(u+QYGs_pH%5wNbkMRx?b{p713lRUu**1M zH-(HTfApFBhw^bIgMBQfCU^C6d0@|Lx$6}~9>t!Jqn0Hds3+))u{bmLHT7>@xc!mjzq!6T0X53C+)#C24Cfw+G zL{(r;DtF&M#I|IDm52d70bbnK-9N?sm0PtvH@6_13C@o{KUD7fT^*Eq6OfZ+#9@;v zY@Wp=gjQ~5NFlVzv|W~=_M~st`ST2hL8Ii_=E&w@vHvirXKv?Y_?)?}L*`1wt!YPZ z6%O=S+q0pUyFcqbV*!SfKi1l0)1i=qi`28NtPtC0XXLS%Z!R-*7|OXTy2WEj?LY?( zwD1m9+^WB4RL!^6RJ<*|O6%FmP+ zt?D46uAtbcit8z*;;|mJLRI-AJDBh#tGr2a# zWVh&RYx}@*;@^)RSypSm`Z%a6Yb0CMI`O4xWYwR(2>AqtL!!>s&F_7=F`X8FXB(8V zGWy<+A!j;u+T=FCJ|)4^75jJL_MO4#o%eWG_Oi7A&P2Sur_Tov@K-3A1o37~goSo! zHtkaCg~Xo%#r_%lhI}6%z$AO@&Bn~)!p>m4S9tS`Mg38}%wD|%C@k6c`ddTc!|if* z5suRH;5;e?r30X(S;VMFDemP<{k~3}xeY^q+6v5oUXdPeNm2_~H=fjlbM7yg24xXQ z;A)X8?$2E+H)f*DVq$qfQ#{v1jPW1FOI-tAMJi3#?1|PqZl4DIcnNg&nvn8_eu(~) zl^rNK494o(J%bP8cqyje&!pGgY2)GtImh(gKiV(e;(NNtJN5G2CW>FNZr#BJrGN~E zN~r5akD0Rx%=gdE@=T7&&D8*D5OClho+f5LzAblHo7RAZZ=|??z(T!>`NpFa#HZ!Q zc*O07)-IYe-Z$~8ZSm?r6Hql90@}K-W4WW<=rkRwQQVB{S1WdL@|+}L)E=7uKst=d z;7`=fE6YxjA?!hf<*4#o|726CGZ_phyLT3mWcm-8jfP98)^^>eTA|w+%%m7UzUiSq;tX81DsC z>+J;Gj6x+p0%r0hC&p7LkpX>t#+82FR%|U&VM!tep-SG(<@y3vM+FfC0A?V__8~2j zbvc&UGY2C49r{m;#RR!Ikfg6hRORf#R`gwT&`yJ;N^i{IPpO2{ei_h=6<&pY)YHR= zw_r3*ur0}UYr~Q5zWcOOb$H_HnF&DIW3O{`Av}e@%X%TohZc}!#9eF^S=M&H*&!$5 zz0T;Hm#Ki@6{~mbUvu$g)@pG-Tkj1OwbmS;XFIKbld-rhAS$_3FqZS}Nl2M#nm(h6 z!F}sYN*l^wT^=P$vD`q|M`+%o;k}f-a|ox#W;Z;SB9k1u7Fn&`>Yn}mK`CvYhU!>E z+B3%U46B}kdH_brly9z~!2!tHk1sY5tovCa$DR#>C^9VNkOI(*3+u7dBWBJUQ+5>6 zW-`q>^>lb$?bJNi%L8GgB@ZhN8R*={Fz{w8@)jiWWJNm*A+IPH;(lI)kpXQw*WW;h zELUwWg0dws_D=^tb6067xSd@`aJ!M}oWP0ugV1($>maL5yNSCZuaNmI(|=!XRC5v> z)5u^Xccz45nBTS5Oy!0{uXtb*|Wm`w&(eL{*iQarWh<=faVGVXZbAZzNB(qw} zB5+9vYs=hOR#`kruz-WLIQ(_;B^eBIJH}GV$sapsQR;ov><>7j`8wJtP*YYdUzwg?B_F66Q)acF4_Q}?eZU7 zzVrRsAy#w6%#~7;i>r%GxB*~iFz0U46L4p~cIsWqa`jkewZmkXs?mS6E^Zgqx9r+P zkihSZI=b5z`TGqFd_S4Mu3U43zQ^#=Y(Ma{?)~tgBRRUX=DVgEvn6Z7*oW1zN4B(C z9{h~BaQ(ik@&giryFS6$o^&ub!Z{rykF!ooXF zrl`dr1D~5M9a3yU6?s$Z*}|{m4922*<8SItBO=`i(|Vf1AZx1y@u?p!=Dr!^Cup1? zwCO9OBNcub~`@X|Kyu<-wxb5cSi&`KH@!6oe5rOZq5^ zJjJ5I9|)Ejq7)=^COJ`S$1;{r5zgWN;LRdC$*)>+thLk&nzTwgZ`MH28>Zfk81ZZ~ zDA%dSR}mEtdW83pLF6Yesn)Gsh`DR5r<&fxqhQ@Kx_sAu-KGJQ4hxZE)ynUlHNb#j zMH_MK%gz?71n@Df7G!&m+*k}|8zn2BAZ&9b0|O-Ja7#!(c|B6Qkx_vn-Y{+_z8j=1 zlqEa)qNpsL5k=3}*tE;Fph_J6&0x4WfQOEYfVQYAr=gShLf1OI(j@{=c@Y z@YysD9zgn)lnCKW$k0lwn|_AyMO-qpb)(<)$dxY*16&MUH)g0ej8k;wnUA3-SBr*`+dX7 zHq2!fO9O7Eo^Pi|AlTXVwYMqaOzJq;C!OY?=6G+-#`6PlrU3q)sGXJ6*h>hwPxru! zKrTp*Ub9UyJ_~A@&0EGa*Jw^RyfHu>3VUi*q(z`t3>LdbLnU zsSxmikc&zZ{pD$REN5AV5+ki(IrG(fS4Y#~4cF&aDrk4l3{Frk=}q@7((?N6^g)R%Zn z0oCY#{OP1Um6WE-DcB_=A})IgxLldp1GeCbBy~1=8@xuZS+wI!8R8!cU$EV<5N<$> z?c1{w__v}-=!sj*)C+3=X9 z(*%_2?WS{3L1p=GhGEMY5ATq@s)?F!Oq*#K23PR410jRZZy&I+cb}vg26^o6);ED5 z&|KvF=<-8yJ3b>&U!TjCc%~paW&YIlFAp~9Ht%(n!w)X_nmL`1rbP#F;75CA%T9T? zZDp66Rc_9SW(6oS{<_?rXlJ^DGU2pU0vSW-fUil(ep`7odJ()tiaRYTN)omS&|_@sPdilB9ZO)hDz&OJJ| z+Z`<^G-GT#vYb{0BoR`jE96pP1EYzIeDyD5k2LJ>j=e=$^wmp%$xqF8TCAIoX^K*j zZ{NQCoSJ?&x4V$4Q&VE5jp1xY&0tJb zlc+N}dAND~ldrxs^n^X_u+$h6ZjJMi|YgQ&k-x6u8t8 zj#bE3kPd$o3E{s(KRz-QT&H=i-yj;qZszd=$ zHtGFmmL#n2lH_7*I1sxPqk7)v6XCl(a=8IQu#1a?seUkyqAVyPG*qsALR)~;UAoXM zs5nER0lAm9FtqXGH_+pg(CMe|W84lH|C{;!Pcrzwm|vtP5bJddE}fCK*E(9VLSaVK zA4sSGZLZg2Tv3#b&n+q%G&q>rvcye*PK~m+E7)lv>Fu6l3{ zM)ExrpQ_Nx%wXMwqa`#$Yz@L0olDLF)TNx4U%Dlvfzk-l7MSql3)a2PtEH;`35HU8 z8F6SapIn-|<Fg*&{n4>wxlGu%yJE3cmgCkTT3wi| z$>-5u*Rx+t1vsL!1N!EA{U4zE4O!7#Koj;HKHRfQ3+_VKRz{c<)mz!?WIWE3bitT{ z`VRybiRA{l57$;Ra)YvE0{n#ahmRF!ekOj@!Me4YCJH~%M938aJz!Mht$|=_E?;8nY@)73M{Epa~=kQhDk;hK!uCk)|5MX*rEqE(f zfAy&l2lZoO4sI;{;fT==amGZN2j!Zd9R7!rS8tSx!KJWlM1y09>@R6I9tDA#v+j^u z1pgkj8R{x`ri5}QOrc#wqoqJHelO$wMt^z^K4VFqodj;y4bZN7nP&=dSvrbNG?8NwIq44M%Yof;SadLt;DfE^~b*jLM&_|8W7 zph`y!5Z@KSCQ|WTHN;fxqV7Fkbb(70SBiOrj97Lh*aX-kQv;64ar4ydNE$c0!b;<@ zRQo0#jYWsebwykXPgfjqaNF4C7uBHfEwPfID~tJPQR{j|C@ID&%K(bOzC@J$Spa)V zK341>`x~2TzoEA*EwW-Kk>2Xz$19!JUUuoDX98U*?*>b-FK{gPjg1GJ$WpGi*xYI9 zYDhY%gSSMst0rtdO3(lbZ4MY%Z**O4Z!7GM$cV|K+=~Q@x0lbQanp&JAW6sh9|75bk#)|ANw_ezATo zTo<$avPTVv5hO3pJ9fmNYf4*~Q_Nmh@W*@YdyJbJol%&ybX%+G**^+Ed3Nd; zmAwGtS!)R+6PXZpKG@Z_%fk;p+i{HF^d)^W7!OXRpi9y+#I8LYX-LVR!c$}6Gx<~B zEfF82G*XC1V857anowu5VU=#G1}75`CZwSj1I!WdaNgteDd`Fx#`W2sZCyn^mAPYzAI+{b-o6HAW$jT# z2IaCY4#E8xwCrgoR`j2r_J}vWZi!aVq@-e4tjt)cv5m@f=`J*8urQH-}l|+i;Bv&{+n4)a;;t6#b#Wgl#vtH!-&%S-$KaL(US}Y8M zxyTeH4t8AztC0sHTV5zHV)LU&R6>GQ^&6!f9h=%r#%rgS*3E|J-9a8D1{$NZ!dh&P z1ee5rd@XxdL^0Iwvs507@W^%bGhh2KO~%gjgfYlO;@-V%()GUgZoZHXGbQ6{1+zu|kno7-vn3C)1E0*@-II1!4i&{}SveMcbaM-Ce z*>k2`<_O6!RCoSJ@DJkCP?Nx-e!n49OLx7QOnoJ>4=YhmvSN))ow3<*n|ew29s0I- zj1tU`Xu{o)9oqUQX#b>qR~Yg6gdfFojDOtxu`>i(A92`_xMr~fK?n5y-jhHo)WCPwssn2HG6Y;Te}G_7x`mlcg7-dqS*6Drq!^@~gp2q;}{ zu_5XIisrPa84{fLPXz2GuKc!mg(HGXNC%+(dYwsAw85zmsFT*QF5zI6Q&)o#zhXW6@EEbzwx&2gNIIw^kqV&_<3-nt42&`ycaO0EDNK8gK}z57w)dizg;dIX>{&v&)&*t9d#OsDZQmwB zR$``3)ybv{;TpD3r1C{r2U7^Fzxfm!hdawhdGb}a-F`3Dj1sHG1JTK0YZWZQCaa)d_RQ- zopV1Fm`sg;$jpSfgLD~TZ|{X{n~es;(eIN~TURgNE#j)|+ZUZ0y_bTHUAmyrwMUC$ z69>{Ah&CE~j6pMU1s|ooo$zvv5@mondBt&hl;yPDEkQxUMq4jL+lO;Ea!Ti1zepUc zZcR^>H$0*APG!_E@~cwJve09-uGv-pXIOo;?B4(X)&e|F$^Jiw z=A%gFj)f=QC`~VzKK^!-v8J7b1sZ%tx#ar9b>8RTi4G;1q4*62PVjhecG~7}CT@1`1wNeHu6liv|B!5?JVSb#6e3H$#XFjW^W6%(fUl;uvA!N8 z{h`N;mz7!qxfNvQ0Oi&eoHx2Xv1bqwSjzW&!?i12Xk+_}Eln`qaO0W!%g)LQq6Yx% zot&I*&bO*>^a_iL=H#gWA?wGsshl?V2j%V1bm3t_^!F}2siUStaf6T8TS2aM5~27k zI&~uzjvIa9y!I>d=%sQ3Duv3q=bM8U#G>UEurMWe4~fASm`HY$9nF^A@AvAHYUKSH$tJ zVxvV(8N;(2Kh!^{A)JM>x{Zm%kc*gqhsT9z9=0+jM;~Hjt&zD|qUoM2>@|H*?^&x|kU;NSpzNBM@b7*vFY$LIjHH3X!CS%=TFr6O%gfzK|ejmB=RQmSSJ zJe1Sn4OdOce)tWL2-ytcxZ6?2_R4i+?*(e;xeK@{#{vWhc+? z%ir4m3$*+{a+SYHAM<0rz8rAE7yo{p{Tcw}$BO>AcTV60o<@TNwLU7c(;@rQ#WSm^ zeuvjPL4(;PAvnf+b=byn*c4=`QC%|5PAo~Qy%At2;qV@wI*SZu_l7dlNYY0uU36Th zy4XiOf76GD@i`-!5X;wB0yK5%bJ}}cl~{%{X2~U9DbfxDDp^s*qcDYx4>)8Q=bIhW zO4bG)qoevczG}R7VXYK2iL859#B3htei_0Xrp8VdCh`jgM8**GW13KFBH~E-3c5S= zkHfzq1~Blny?+R9JfY+K2V$)5X(4d^(K!R~@)p(6*E=^o6_lo(h=8a3S|hs!-GKcU zt94FF$)@h^a3cI=o07V-R4nG)ti3!4hTq_Ud>V2U5c3|(p$D%4y`;ogy{3VK2Uj%= zH20xsQe>qoYpG;`uK4u?20M%G$3$~p@IK`+JIIw!zPQr%FAvhv_cG+=9W=(x^ES&7 z59}^o>#us3mV(%4k_d0<#hCE4Dy@wf@_ijmiW1G#@A>X;Cn&he9Zj6L8^sUC)Q@f^ zXqLD8-6Ak{8Fu!^F(BzV$Py3wwb5725YVT2*mw|NIOeUGMbo&| z;jz)I?rj%2XSUoR-X?o6`*d&8LeAM{yu&VfvdUF94>ldXAE34)d&u#5#cp(Y|838b zjIbStq+CE$u*`{N)nO_iz_JiAbyu3zeuIhy2Q;w0u@C8uf$_{Cto3-VCxw%PqPGx4 zRIl#$xvgP6%|457n(f&ofy`USZJB8#H{2Gx8w98D_4YXP#e{L3c25u3s-x5xVRMDC z_rr3txM-`m`z+6qPt!w9FfJLI{c}V#SIzJ6O%A@v)cmeS*eI%??sm+NA@il ze|{_)&3CS@to(qi$(2kA?{fm%pN6(*%Y5JCgBtjKR?Pi~r>*BoWIjL8>S?5hRlr!z zPZU~pW~~3Lj`z3E{0h&XGRHS|_P)4WSUCbo4unlS;#KSLT8&q!p|{`K?$|dE5poK( z%+(#yQR~}IRgLC3TwR*(0oX35?c1f|h-X`v^J?|$#*nIDeqgzS8EXpDZAdYUg}@Ac zamW!5E^8NQm)Jmvm+DZ}!OHi&M54js7K_><)tCWJP>;z{B++);dZU{Mm-z2Zyrp%^4SwGS*t0li8MCy!eRjEivcxZve@DnnuhdF-oo@$HTy#6qtn@w;ll=Yy z(Z-{o!?N_GcwFG%G+@@Qtzbuzu6_+W9~07v`~$i8vzp57eiGmUp3MC547_`s>|_qL z+E;RF6Zv*@!)+G_%m>%Jg!ZLfPVgx`wSxHkISA{srB36vSikX_U+{&N^h$i11Zh6ESImm zCrhq6;vpAzfq8YdcS>kGkc*^?(1(2g`g)i`r1TTxPNj2y zpD9CP_3TfwdieR{SA93%;z*#;0`ii&n=VP89wP-;i}R?I>qoR>=}!F;3KJ8CYOK}m zXCt_$cVBS~0*e@Gi*IcVR-79Z7ct*~u6m2=cmL>##1+cUvnqcR-?85OOvGd&iL=J$3)z;s5H z$L|bIEV5hE*gVJnbaGg7PuB_DPSmY?tYsr{gc)aJOii;cX>U6D;=*in%)Uj?X?OPu zg^g5O2-asVCqd~ld3i!6swkMsWu}jW6@Qu0BK%|UwkPP?BwJN~nwEz8VsoRPd28sZ zj2>&J#AIqJpO`&bEAcf=|NXMzKufaq)ipj&@Mf(+Ijg{?)R+(uxT)GKHqSw)NP420 z+c?OKa*}Xt1lY3zzrt)E`)pnt~npkRDW^3s5kYKg2kPfe@10>dLgDMHz6n8OBybG;rA z{~I0s{%S-qO_hs?w0P62*XCy$qLaxNJnvw6)N^$tc`V2!YEV{C(Z_1~bvO?|Wi-=mX^(YI`=OW70t9&S+)=I=uHE8qE-e{t*4fC_`6`Dk`&H62UlirXvFId$gD9k;t>4^6_V^3hU#)>oSS=aH-IHXT{A(d@*95Rw`pJ#?tL;;Q#MmP_ zaD?xvyD*}ar-WEHIcOx3)qbTdF$i*WG+MRd8I@a}YJ=6Jpyj&OOqq>Os?WpmLz;QL zhY3@wwnjYpoz%A6tz(Y9pihKvTLEc+Qh5^RXVgFMxlufatIcVs09(=eDn&+E2MMVM z`F$x8Wkq(q!b$V)?3?VyJ(`n&B5M7IsDPg)ww-OI#oo6Eo^MOCgn1?C$JBgRli(c%=)w&QkIymTJ}apG%y&+=LnBpCVzQ zy+b*9J>APw$Anx(SprS!4&#$I#h64?eIv0cvt$kTuYVRyL@|}!&irqb_{U!7jzY%LPs!czmZXIo@QT&(16?6uk3KGcTlb4Zh(N zwYeS~fZDoFTOstyk8Brttx3i^=+4*I+NsXjM5q0O3Zn9xA0U*%$g>A`@E&zL7;Pu3 zZ!N=-un5V*l{sRv?2?|Eqwpe5BECo0M-ua9ynb+QkU~O#T3G0@Vj%~a8+3AW9LurF zrpu9M_-D6FP^i@<+IKaAt&OLGoQA?XhVPB}ScbOmpIs_4x0}02ip5VAI#XuwhX)+{ zbfJsSDed*bRDfAonxk&fU7nueMRNm`1X){Wmw3^WBS8=8(0CfAO-}#U64aL&O-0TT zC8@(dGSjL0T|O+-z89#>wy00e;n!JQm2pax zUn^OaU`DmFFu#Fd9CKVxL`DN{qr*I-9cT}MuZY%2#=KLi-uIpb`ENYdiBUK4KVz!T znD4((@BapVr*&)M?k6_Uw%=#7E%>pHqh4z%s(C#9d__vCr|<29Z9eZr!l|a#7j`?) z-Ay%%d*k@Mt6;*IloVo7mT#mQ!fDCpw$w$?bVx1)3IH94BdNxofM)ISq;=m z27{F2ty=FFxdgO@jpZXz!6p|ZzH)SRPd?{8l|LjEZ0am#%k{SGW~|{vPead>Y8aG! z-fI#Qe=5~mF7k_CTiV^!y_P}dvOCtub!TdFkNb@=I)@Ki%gw_J9&PkPlK%~S^(7-b zoKIw{f*sPXN7;ojLNFS8`9tn+y9q%+)U~G`Nr_KimZOwU%j#bDcx)zAJ}cb$YaTxt zTcEE4J}pyO*Npv~&tY)kJa-g^th~RI0Mq zIq`sHf1rod*fs3w;s9I^Z^I+4db&3TCbH?J^V+9p z(OZ&S?2N6p`#vp2DZRY&T7_n%XY9b8s=_FUrYy^gmvsn+h_FhXdb`nNPC9R9M<~iW!YEN+AFhvt za-FI6pOg2NV${f&y<{be#%p(uR?W0mCcUCf<(`=$S%Ha(iNURb_uP z%cMnymy3CO>bX2jKM^XY!~b-?N-a%gKeza$Tcug}(!;vOA*dNUhQ2*qMwE8gDS%2v zDQ;jux`slUVIU%)gVbdURHeG475*OGETUG%_mcq68~?$s2qY{_or~m&>`*yn>F=tV zwa8nn_N#fj6&*KtF2>kzO4F=%gf$~jBSP_oA9N!g9tnbZlz8P4l(`?9rEy(sknwD= zd=a~Tawy`*OKdx!eoTFQ_9=)NYlJN)63Jopn%kVgcQn1x-KK8+}YIF9Rj2i5cGhA#K2d~_GHgf`JWPgx%F(MCZ69oGwuOHk!hw6pD2BmdDXC5MX&kJCOw`x-fzrr zPTmoWk&g-oPsMJ>uuE>voS>-E7CT53d^*(tC{Hy#g)v~P*h+cfAS<)wY1g<&l?@Tz z_&3#3h*4(?5z0LW{QvD!{<5$?;(kFGW8uo02X}p;Vc6}U8NU65SKr{TTlNBe1Zy|7 zBl@lL6_ZRlYrm+pm%VcNawUWUPqVZl!U@BK+F!4Ujf>|E8w~kM+dgTB1amTUk4A{Mx_41>axgEP(D1$}eWvJIa@p8KYz7kKCRtVV5K+_Vof7Gg8t7jE9rCa|W4?Bs9iK2h%& zA-Z)FEF!6BgRc47iV24dmHj3W>r!0Fmwh+V4DNve%J__nrUTive%VIhS-@Y?@(Mzn z&AlruC=xI9=1TTZgRUgxns)f_cF>ZOKE`~ECUvu$s_+yWd}lqQugsgssDPGoOeXA< z4x|mDmSw(qOu!Qt=q;j8vF&tWaL-nF;Z}Grw$Zoqn6iGN+C}H9kJjkaSvK^CRgahn ze+ivi?h};jJ+1B1g<9fFwg!ILArGN@Qc!-``>v+Jk=Cu6RbCKT<@ZGE zGg-B;%pGG2l2p+0c1Wbm$J{^5R^n=m6YzTSQi{}fo=~l21mrMHFUg-OyQ-{5H##j< zVZl;9tXk8=C=15W4h40qMG&{Q*k!3~9j_k4=!Dfx;$N4h$-M~g;gkA1On_?NgayU+ zb*gRrxjj@LsKVw10K)aid7JaIHM^Wwtw~dWS!v=cfaEwF8{}t<`5y}kf6R9An`2wL z6jDg8L4bmj7H5Wq%q$$yed*6q9L0y}$iAPz7j6h2m*pA^Saw_x*eJ*4W8YWa9NZSU zq=7Csw>!%Pa#{{h&q$`Px2EZAoyxBu^l2>(6B^U4e~Ng^`Z@Z7*}IqF?eEbV;2+mE~zvrPQ;7%+i8wwH!W)asSLhF?K+lhJU z%NRAc665)ET?VK^!h({!Ty3>08g8av*?Ek=@HU;NPRr(eZle;UDRuU~(kIEq)L}W# zezBXhz;=zWw_SCVd$qc*+k4@)BAr^?UT=7DpKF_cV~# zCAtLtS_$X*-mFKF1}BNR`-RpS?$M!ClRT$V>s&%aKMZTMo^r*?KcZ8%a;jeZNH)gd$a9%n!;ot7dRex|8f zv_yZ~aM_@wGOke=Zg1w^NGyOV_C+YYzNF(hS>sibOh(h(Z^5{O%5!9`0h>O+^OUaT z6=C&be}lXkzl$D)aTs5+O3)*FdafxT3E_Uy>1krn|LOtFASXRHd?4mlBO$FF?fe778~bcGMQ6l%rFT0>u^lpI!&6+8vL+~Qr|0DC*y`eX66zB{ zA5>IykEo~C88M5c!zZD}!A7;C`++7M zPomBD!l;zv#zrWsjC8dZ4}7bDua&@(u+yh__&B5D%X+P>wkhu$6(u2M=JbU$k;Q^5 zN;#@D1lM)3@>oMHddf2-hT3kW<)+gw>YajENX}SxbcltKfzWFst!gJdagkCThL9LR zS}@-ZPJfuq>N&BoVz~$nbx*l&BS*JeNEV?PUE+8TC8LS{_mKvspqy zLL4@ZY}zB=xN=4D_;)0hLW_!0gfspbQlMC|fNV4_u58;aj(-!=hD2y}pM5tNBkWM<7TL|gjNp(~>~ z@k2dgX%&u_n-QyvU!jfEGFsT5{L%1+6eOS-qQ0L$|M>W}4o9`92>JEvIrn8^UORbU z4D|zoN(Hxez6?fwE;JM!acAWd7Fh z-jw2C%yHhw26T2Lq?Xz^qcCQCV$t*jR+`rI^!BEpXW8iw`B$6a<>~JCNs?jza9e-1 z{^2$(xN?X4dgzkK;MeIDQ+82}GXs40XPhh@V+cM=7Mb8~m%n`5LJ85)^4$pOpT#bI zVITRbFq8`u6CM>KKze;z@TQ69F=+F1QOGM=Ff9&I__H#&#!kV`PP%aCWrruN?*sS4 zC60uY%0mA`3U9u!m&4^tq|bew<~+#jvH7p$)8#WWV7eS2kGNbtV& z*RS0*@pD8!^cl*f$`rnHjK|l0KIDmeju;}b{h)Ju-u<7;)c-5U_n+|Z&oWKs^8$A^ z0#Dbc!a&q9w|y4Zt)}|I2*D`8a}01LPe)LFWXVh8PFJ3WV0Yy`13cj05PbP5-|nsG z#Nb$DZbMm+VmNjI=5w8Yjy(3j{(L*{6v;eeD?DE!{Sm#qRQkpHZuYq>eR819*l)XR z*HxJCY_THa_yP3MarcnwZ#A^f^16z8Umy5yqjE9F6?eK9|KSz9&vQ;ZkTD1ei8%D{{{s9^Yw!OpAbxYxL_+B+$}<4`!IC2AW~Zr1 zxc@iuSs|faim$jW@pqa3f1Abrcli9D@`C?z=_xe!>vI!IoH~Gac6NqU4h#$&%$7?@ zN^FFFOnj%%4CWj|KF=jxQLIAj!J!9pJA1(>=%Vk3C|YeJ?mIoy%2Sejox=x z^lzV^Ku2B9=y|Q}B7XJPdE|dH_C8C$=jXAMoSdq%v#HQxgik#fkbcZ&P3;A|Cvjct zdIQAmdu};(12#PNi*+oYK7Gjj8xo(xhw>ZCCzvYXa(*8m_-j}lwratvzYXihTc(L; zAN{XM{(pDR->d#@UjIW_xkAFd4fivCgXdAe$3L_=NQ(S|&A4pakE{03(72b^iLi z&?}TbmSf>n`*9uns7Oc^djCmo{GT@d50B6W^Y5a7CtgsP46(AQvTBuxR1i4EIqpiH z5*l2bGXzN&G7kbnfwUn#gpQ!1FGXEM#$)YYU_HBe zi07CJ?I$HbUl5L?zpDT9%xzYJELuLKONGL(hd)>zTc$4O5ui(}w$_sbx0S=j!qSlb zzgoG@peCDk?Q2IqqzZzF53l6Reb zH4n_mHS0XjSWu`wuUp6cgVkH|8MJ`6TIhEK6?W@y1Uh{z`qKx+wQIh{#c&lbVM3XF(G6 z$5qd%WWIC-_N7cj{zGOXJ?AwdqR;#-<<0KM-011_(Rzja%WX#v?72?js)$S;K73LO(&Dg zviQO4h@aEZbSr|T=N^@;Vrv9`XKB^6OyV9n$F;L|M=+a!QHbY*&5PSB|6~6L21f!z zk`BB~iGD6K3^|zu$#ZmMQyyqI{U8j{<8P;bZG?fC@o(at4;>TZ`5<0dIe|(#CaxZs zJRIJtz1)x<-t|c|xi=mekHUiPEaqiDDt#Kl?99>BkCoW z%W%XUfI>CCN=D_EUegOCDEYGb>iYn{u^DCJvLvz2aA%*`m;{i)pT3a?3>82cG5QQy zece?ld>^?U+aioBlu}ZiQPSn0+A}(BFRiK+^VJ{Go;^82YMy$nck~pBP67W`TmS7Y zKZs(H`=*h`@s0DWSl#){hL?rEsUwl5R{?(D$0qkLivq|$r_Zpb0op^(pHF%vbvd2S zQ{q-sTZ??c7sTl2Yh}}1!YsvD)kV&9($H|qh?seWebg;qX`LKhKCGn(mACN9ywKJjn8VL|<*g-w0L58P7|CNa!7DJH-Sbnz7wk=tyG@^Lp4vjT8THME`1 z;RjO`%%Bk*cO#ZdIM}P5fy?e?FAIwOWrtSm!W>lTt~YLUS(^EzAQWQ0wq$Nqfz}sM zQHa_P_ifEBCgGOhKi(7a>_96UyG#C@@_co@Nl6<2%wb{LPG*WB?>xV4JzR> zR1H@JO*AIJB9|LnT)Mr=hckaO>#U?YD273Cn-D%NHg>gPMHvejS&!KE%*87*xO&fP z5)~;2sCjyAM)>oQn=8a*har| z&vroqIU&QSl6^dA@5kq}sch1$fLd594IWc!DR~#4^a2EL0~+|}6pQ|{#b={;D=sIS zKn4!)o^T5Y16owPK8MF$+0*j<%GkfmEu_E@iWh&Ui(GcEW^7t*LPrH%2H4YB)0M~_0FI2!P-XJ;_)r^=MBUf_FE?;`~ zx_p4!^h3&}TD_p-J9rufVaJWS?VKrDByOIDDJUoRaHWuG9__4DkTg4IIz-ZMl9!fe zGm&=tb-j9wl|`m$!|<^s>HI5W288)h#%;=hJqe4!6LF~C6_uJ_XyMcm{>NRd(C?$U zFs*dYA(>@&%=4NnHL|Irkup?wt7<@u{ZXuLv1vG;t3P}2imzFN_^l?&x|*MnFM}r0IB7@9pct% zn7?VBptZ13Nu_s68ofCkq74%@R&9zSvsOi54>KQBy@sSY%RmxL>+Yi6Di8{B&SF*9 z>;+>wgY0(*-_s4R#TfTIsh~_qx#UXc8hYbStO>DoH-VnCOPV25v)}J!SUj0mE?9Hu zhl7qeN{2bcBM}00Gj`dt0zaycn~qkcEvddUl=`Rv`UAAKPSLdQ&0pD~4~r(#yagdv zu9yF+C=$mf64%pQrBhu^C%ct}6j^knSFS?(95zhu-Gj!0h3pcW@AeLBaG*ZVo7%Zt zSx+mvV@eN=6H0!?MZq>dC=-`WFJecPRCP5xBan2fH?ZuS1{%+x$jYMo9zj~WeFS_I zUQVJi#WD)$x$`0QvHoA5PLFFVZ%@KkMM~p~P#-uHS2CNLZokfpQ=D$`5!9{bYLp>% zns0f&bi!mPQ^ec@49cOywl|eco8Foc^Fqwns?Bn5j#}OO_3*th8!<%v@#azVlWVD_ ztxIhGms`(&Vb@TnCgQzMoVU-@gs%KBXE=&&yUuekuw{RWC`75wB}|o#0-YKmO4CN=DwfqEp0052KZgk3>n}Y# znwUe22n2v;;_gmt#;dr)Q48n1!Ve5=tc>#%g1(Sdut-sfKU-^Nr3|~D5Lx43gY#!X z#p_ZDUzh~vNjGn7?KY^s_})1-mZp*IF|aS1j5?4c@s%s;B(OQ|DpJ2(u*E*v|c z+V+-`HtL&e|Eh9kvKF=ER_v%sRd)8s(Pm>3w8kp<26!i%g7-fLp4tC0Vd_n({RkbH zxKXDiA+fsp*#B0~fq-mNEGI0bY)|3N)7($OToHTX7uT(BKKOIXs8#Va>(;Y5BQrf8 z4xUB2 zV+RVKd1)~A?+qTu{2aGy8c12nr3;rDIsnXe($crEBs)p+-;m3S6)qyx zJ=xlWMcQf(xLszQ$CBY;l=}PY-C(?NR<~Z`I9(fw$Qw&BLBuJn<~KLT$NyAIcd| zOqAqm1LjCPM!DG-#nsT!U>Q#CqWb~6>8W=#?TWa$!k%w6p88Cb6YEtl7~D-LANP#w z_e|O0Ve*c=avy<8cdUhBD^&RpcC!?tLQj6f9v`ffh@QTGnRPSZmj_idx2=P?7Syoo zbq(l4P``L4R8OEd69A~;u42nPi$UUt;j0mEPO}>s)v8(wNKEW&-r;6jBG?@-{odir zLgp($d-N{VhO7^EJ%IPeOP$kh-0**L7hcl!wKt{IY-IopMrpS{dA9W=PWSY?#Xls! z%j4B@8#Y@Ig`M~IjaJdtV~?1vd=nCGd6FXbC1(D`n<7M&5<@eF0j)~$*bM!>sJrJNV zCa!Z%F&pz9YVNo56z^VijZm)ieHXIWJwBN!#lH>-O!eno)A=a2tby1D54&#ISMByU zhHGcKV^*6JO?d62X)Ie zer~F3wJx;|hNE#Nm0cGB9MPDw%G*prfP=HumwiZ@U=22=wWJB7hfvQOxIe^4V5`Tp$z>bUbP^BCKPo=*)ocPGku*%nS-HjLFLwjzallW$!V z9-%yR4@xS9@y8wvq!YPeL!am;RK*h8YsrDaCl?RQ1Mh8r3X+55w5m2$CG0VsISw*Q z2$0k$oZ_)5OYF7el&R-Cpb~&;u<7)gz18APN23%Hkes_2Z#((nypmFI`=dIRKE*n<0<+k1g{jHgce{T49bw zran1GcfC@ybd~I@5lsQoCvi}AyvNTrU8Wlo&8vvc=j*i*VjhRInbVYJD+3uy8z98n zrZu>SaB^g(dVM0&d6FbHULyD5Ng(_R(~!Wlm-ox75D1gpj6hG#%+U9Qpe5T-<%>>r z&&D21^lxlP7w0yX!Z%Da$MF(`2z135^E&65eM(6N@RMEPZ#A<=zx0HV@mn9~(}GOu zVW8*BZ?&Z_$wh{dbj`?nm2iVR{sk`suvSRB?PRAqj;0Ro2Hwx1C4o76e?0__$g8Ml zhP-JLJk6+)9q7a{vzxr!(#G#yAx%~&qTebfa>`(+?UWPJNrm1QshhQ?UXtmzYi3*E z^^Y7Yo#UA=3$mAq6JtK3!n7j)?wWc2BB(n-uFGmw=pSJ&u-s(oxuMMKI}M2YmdWd5 zI7DhBM2MC84e0TCkzshYIB}8kj-5$IYa*u_+w6za2ic`Zj$6{^YqP-Szn-Za>+?>& zUwntnWqw~E!O6st>0u%9A;9Br#V(e67`U?03KJ(JIF9qFHsr~ldwU1VPb;1 zRx`MltwDn?>@T6lT`uk3bq9zkyz?O!^wm)7^4LTg5wGuunsywsoji-7W1+G<0=iij z*sI;P^bv=VE%8MhsjoVcQibfB(?_C_(+_u+&gER%uNAlOmxc-9S`Z6K4^pVgLWWW@ zDzP~y?yF74=ux88kZEjIT-l@G@+s0lIjfo)ctP^;J#-9>Nyieop!+o2H_pm@VLZTK zlHww2koy=qyH9TwA)elvpe%fB&P5x~az|g-Oxf#)PV@)IKe!LLa)$0)pV83r)T6O) z$>F#dz9X%g`><;HRqDlFUltZA;RS^)3NBsRh-4Fw%;}%Vp6#^PQOg&G>Fc2-~;&> zN5o}PTQ3nlIJYAX8Xb*8a%#E_^@~&<6ES5Py-48XR5B^|ht-@uzCCigF6c84Ru_NI zBmGJwRw$@zAS>Kb!nf^pSn){Oyw4pTQC5a91>&g|)c0+76PJ46zWggIQCeSUsUpTM zh>sAS8il>$HXGpM#;+Vf-kEV!HZ=%$>(}QbG?{OlxDNaEYkVfXxV6m`Z*YAs@W~gS z(GaHHo%AaYqSOw<_tP*I_VLJF#8)4ZI4(JSl}mE*imG13TJ~3cy%d63D`}_KP%2}U zx6#|yvCw#ywCdh5h6`|l`95$f7U)#)_?h=0H0#W#@jC*`Z-R#J^)BC0^HKC8{IICd zCw@k;mF~h8&~S&lh>;eFD@#>ae;3jx$M~j)jcYGrdxgF4(^!C{PhCFs;Aah%w zAUP+_T%u=KqZxRb8&u!2ohl_w%i!(DzQR22+!sU|Mu`3$Cb+C<6@8_5fIr(^_D7}x!!`4T5$)52 zj%9n~Kwf%{-wq}PdnXfTK=2S=ozg$@{=?&3A%kXX^F2CTkak587=N9+N^fgmFW1y0 zXCu15)<)?x0_`-ee4AZEAP4-JYJF&vbu!B9xV6&{2p{002Ojla+)304y&6zz`$BLM0~g zo6*oW7$=B~I8ZxIdH}sZFp-y$1m6C8=697PK_$pvWwo6E0OQwxFPIcY3=*gi(OFJW z3UL_@4+Dq09kZ<)04M-CNij9|rQ;koEj&%au!)?%eSOnnV#;cG^~NPA3=E6-UShN5 z4QX11bkK{r7ylac;*)b26MJ zgnE|0gerq!#IWGRz%*!?z<(c7#GwtA8VK6JsiXWSQ7-wvB>#Wtj-RN2B>V1%!rql$ z_s5RpB>3i%XDs+}A&s%-ytaA^AF}KZri|>-^e~pZF=xd&g{>gY;1~^i`<#fZE`4mH z?ot59lu^>cK$5w^0)CV6M2~!RNu1_@p-!j*BY_mecRNvxaD_o-EG&_|BH!iE7wrBrtGrm zsX((iFZ}lH&EWn?Cc}V(va;k|$Far&IiX;~29tN5AASnKY{_h_E zmwORGxRi&N zz)`k7SY7Yel_p53S!(%_BN2w*f!NM#bzhv@H$9#h8i+xXcbB*!C zLy8^+%a~4UMf#~#j(}II-L%VFbAcFoiYNvDt{ z{*KBc@zvYntnZeg40aFJMonYPSkkI4nKfE>>%Y74xEXRZOV+=%57eA2LCX${UD;%@4mC|JwpuZV7Sp4#Y8~3 zuI0ZP%I24J|5j+8W`)4rp&2^QPA!uZ~cr^gQw1vlJY#0@~OK z0Q6f?kg!6cRfxWqOozGD(pDKxTptIO;aN)>F3#FNFInFRR%I3E3OUVn-yM!^6Jz`L zUpyJpBRL8rp zd0m*5PcDKwunXhQ=*;a06?h+h9DdcXDo+duY)dFC&Oo9MFAkhuq|i`N+m6kZE3lA;rCwhwAY)hZsUVr`|N&|K&Ovxw^B)F zM+b>}lUF=F1Pr?So|d-v=yh>@Ku0){dy%}h#5GVf)_bl71}O^l{D{@8v#>g_K*?BQ zFq#z(fK;}fXto~wGfRLle92ai8?>|eaS~OMhe~;CxxEy_N@uRW+NjFdmBr(iLp7Of z!AMZ!Sv!9+^fukHmOq)6Jbkj>V##Tr$8xi_*(O{wNTb|-`b41L{S-D`%x-rS^RS(0 zf7BV!EyfwQ|ElEWSYKc(vjJ)NKHc|4%2rP zW$e20_jDTi1#RFRqKcE(J~cnY#b3404!zl(U)m5>5zO)O%w3^*R~9BiDt+e1`kjtu z@E*T5H){5nf$Ls`$BX*Ihq%B}><8D`OEFJflcjl9tG`lDK9Um9msl-i&R%pBlzRL~ z9kSEqddgy__H;dH-u&f5c~mJ(eW%06yLb*cvrZaswbimYlVJXr$XjRNyQ!UR-_zB< z+?3N51bMu_6Grb~ndZx<^KNbR+Vc|h`QG*Uh0G5E*2J`1vz~TEFG-$mL>2J3(XM#P zs-#+aYO~`fkproVJlBZzQ$`%@Dewl!f=U`*I!PS-im@N=$8(!wB~{=+f>Nt#RP1*w zC#(2_s#qR#|AKT`b$R$^TRD_m}vJQWXf&g9i zojxhRzf6>f=kamgxJN|4!6_>!5JEACxz1i^pXB{^s1D;_|NRe{RhAna@`o`vZ2!nW zfC7|(3Zn%QB5A)X$wthVb0D)_!&@?&^(3JV6`$J-S|(j;J=yR0M7BXIyJbN8j^^3t zvH5AKrTtcNj7N36W!Tc-yu#_R^|Otz!wCf@iYUe9dKSC-a!QBi4FfPl6UmUdv(2iS zW1SU21rLS?c)Vm1At=F?>uc|My@P$ShJyr;!4rqbfdBro#T}U19fc~*Q`mV%aalvg za~Y=OCiBjCg8WT&PiJZZ8A&H#MZj-;w4tyFmL5J{ZPn#~3h0%fsNT6r5s|U?y?V-J zc6CGn!tPd^D>vi6?k(vCz#5}}ATBvxF2Px*hlc^+D65`I&-OSt@(-8i_r=0Mwxpl8sPpu?6DgDdDwjhp7nO-G z?d?wsD=?@^w7%TV;a>VSV^My0x!o9moON@w`hF1Wg^l_b7c(zQj5Sh?L!K5`x>6#6+1^?E&D_S*l$2yx54ZUVhiDhkbxQqC zW(D*gsz=mFK=JPi^X6nU(OYxX=;xER_j}RkF(0-$6BE^q+)cMXWB$E1cTiA&`h{2E zFU&BTV+N7n_DF&jOTqpkaxLi#goX(R6rW#KB3SHa8 zwWnHrHkt^L0pjCJ6XY+yGJ726bmLMLTdV730>LmS4GaNZzIMCEhzGR;Z2#=4B`HNX zVJU&&0}gj0O1R*3(VpIz)3u_^PrknI8n}*k&Dr4c)l4jfzaAvSlHr5k3nLEas!cnc zu2f!@mote4J>2in0Dv&%PdbU5b8e{xrOCPX#h+HX>XHTmQ6)h1Ls4p{P`&M~N+Bn< zjhXe}JCQtpYN>->Ejb(pT(FRc{YZt zPL}K3Rz00$?FfLic*1r&p3>hHhqB-RKv^6pr-yx)Z*C_MdmQ;%^R_rOlSQUy1jQ~8 z78mR9Za3GYWkF4e_TQA4-``%rVw#W3x|s}8LKfTxw~*lge}Rf=^mSb|_8CF143xPT z7gQe*KC-dDbqz`MdSkI%k3Y{0>CrQu8ft!L3C-V|vaW4?RDrCb$o9#$!A0MmQ_RaI zRy!OhhAi1$K=t$zYdOG#JvVXK&k+`Iz;vbr&Z$lU?2B^RIJEK6f#5?uc|4FYz=adG zI@lUEar8R2|2Iv-V#J?cXT&UW-YYG7;y`Cfu!iXB=vP~e$)qwEW**o~MiaQ}ElY zkn&U?cFCmd7)DqC0gRkSGzbIqcBn^b-~biLv-YQQdBQJO8Yoy4pu3kN-j!#1Y$WA~ zJ`IrFa-r{rG)=-&35ob&>)T^t%&saqw}nbm$s22-4R@iqF+>w1q2{d+RBo zRdV=E9>rr38&4WX7$mkw1jQ7Ky|5{N^2JCTUe{I?@233$xz5eKB})r;Vyt`|2@?3_ z%R##uv{zntX(TM1^Ax}73JFBR(!FlK;eF()T2%^BBz%u%ny@`B_Ng~rE~|v`$x4g2 zY{kvz96R~%5j52>@z?CgiuV;Cu!jS|fDu3XUDV?Fh$%Nf89_)e=X`Lkl@|65o^R+Q zlVOs($?xAJXMouUMDDH*XHNys-3Z(;OhMO=JVJgf>OGDsV11bn-M%M(N}R`&_qP4` zJ#3aG3B@n|8Wh7_mwbwm9@%Rv9{m2stM7Y1&$w8kWZP+deLRQx`;L6Fah;Vii--AG z@Rg(otN+pp`5XFD9GWA0P?>k8js%SVAK&z+M!&MDp4{84jRl{9=rR!u>&}X7>buhr z%cBPOAVe4xgt_I}#2EYePK}M=530-N4BIhX>v0C&sRiDZ32ZfOXSSh_(fS;%xTrG9eRO{+i^DK!v-{F2!oR=m-D#TVk*h{-SUzg?Nbon)p8Jv|I3^#GQ?Wx8Sj0jbYJd8i_Xog6U z$DZ8Cb5`sHvVkD2w^IEcKZ%T@+NX;BMrTtASUfbFmdar?yOmC*I4jC^o(bEpXjwg{ zQ^gtRhoM^OY{;F{AB~(BLh&#C>YEp_=B%s)$NFcgNxM38n1lFT%Z-b|lQdR4>m81S ztGXW(*4eiAd@ZEW&aXIlHGf+sC(YM=MQ|UrnYAVZ&=}lL)A6w;9YkxA{My{ImN%!< zF%+Lkk4L0Jy2=j)hRR}T;n~V(zef)Io?jai7+n;qNrB(V>@9*0h(^^6pa6q}aZedS zatCUEmHZ+#X37QH^TOir`1?Vp5R-NB{tUnGuHD4MMC_JODm;dH|7$aGVv^I~`q4t| zT&=z?OPT}(B8ITzAu9(e$IhSf*U?u#C@aR>(I?fMTs^pC-MEy*=E^Lr@|*zX0jB%T zn;u`E#fEp4nuEPBQj{S5G)BfxC_Sw|YnA;Ads$~Q(vt~P&ykTokLQMb8Jmm{Nu12{ zt>pLZ?A*wmB*ere{HWWEQmVw<=j42hgov?|01Zst-}jcQY@EjWfS~cohs#5M3V-Q$ z<&d+Jp;G({Ld5H^B4n60QqP+}c+}n{eqBuxT9p4nm^+P>Y5mdfC+ovlg`ZK^+gqEPn<Ad)l~|aeODG(rf{PM7d>g$s1}s8bfonHx8-_a9;~F z%$4e7u3Gg}!CKMF3Bx46^-u##;Js4sIi30V5y87uY7``=)QX3DUtX`I*pU}O9866V zvoqb%pM*c($;(d>6OVxFEO21W_A2-HTgmGnn0;%HF?#m~4HQ5nUX8Jp6HRW=GRYwR z0my#cYcl^#4_7{kLj!SUI~h-ji5Ss5%>sLBt)DPb{BNg#(mOYvm^WJ=kP03=Gt!wC zZhNnjSE|y!zzwgMZe}#&SL@4f4n`k=!rqIeXkLdSUQF%9MtASG_an`jkYhjC37~UmI2<_YiZgg8h+n04ZB%G80b?F--v}_m-rN*~ea*URfvAVt`&* z?47yGR@_46Rk(l1nH*tW9y=2SpIzU^=nJC87b7CQ^hd*&81t#scnG3~`~N*Q9*OAP zCrutmCyrG-)Z02nP`-(Fwej=i;c9PB784E4+0|A02?$6|PQE!>SkC*DkwF(}()eYp zv$Jzj@NuQv=V`&v?;oc~H5x_Iuyh<5bAr(aCcK1%geU^$t?TX}hRCgrpFuS)hI!&( zSBYEGXL6e%FDy8foEL$0NCg)=J2rFDlof1@bddv<3LX?zPqDR;%E`*h<6h@7;laUp zWrxV%4Ky`zy|8_ZEYzry8cBw{?Rj*^zs6Dfl9Q#fe~0>GJi`B(4*%Ob|1Velza;5560SA<;g5D|JiMOU?aVuhHDjbIK<=u1paO7(;49Mqf&1qU})L zQ~z2=$`PqC>EX_8J|4(klSP(*2EegUCH^|dY=a>H21)t2X5b)$K^H+BH`vw_U!jC)(o3tnG)Fv`ja9 z%C9BAysM&GXw>0>iw zUFvfDdo6=`8ux*>U_T@hY-W{4c+=*=+w2>s601?FmV@Mo-zL%+TFIh(*>OaRld-mDe~eWacKcjjr^u}SY0oVw6ki3qkRY4H7U`27wgJE- zuV%%3Q>H^n<+Pv@Os|kZo=%&E2Yk2=yYTTBFodHX1=mYcRrMV>Ah~vun!8G^6$G$x zoYIa|F#gbVY@Rsw6VQSMkSYh!{xRodseL!+?6YG~R@V4dwQmA~poo%ok$l8->G3{n z_KQLZ4k;fTOhMn3qsb)v3|XEKa5e69$Q^)3TX_~JhV&k0q8~*jFQTiwu-kZu_rQFa zo)9UL^Pt!4=&#xKL+QpP0ydJU$=6uU)C5k4(XBPgA|a1-TORNuhlN939`3_Uk!AO% zu6o{)zb4zWO%;*fN!v>d=Uw6aIt2sl2V%cS+I(pL9+gel+FV0I4>)2eGBV^vqtNB8`=>bNnI9zRc{+X92h*n~6>MWL8 z5B6H1Ym;AIYlbQWXLD7FvesKDti4v;Aci#4`OUcVyQ#-NJCt63hC>5eXC_l4WBsm{ z>gpzd<4mHeRR8z5aJzAZ^S~uGwG4iVvI=l%@^qhNj1a&mUQ;GbAH4M*J^AU1GkzF3j-)|+3|m4R>rb~!8H$Iaz+Uj7Wmp( zc?OX#zDwoqc^s`bks#k(Jz3bqe&vi^)*(*e*?WW2RzVSTu+>w_Ao_r;9AG||ph;!@ zqLyEB5f8@}5NG&Lnn*a8U z8hoUc=5>FMy^x=YSJ;xbSoqC^wK&C%v*Om~A2BlTo1)cP&CEi;|H%aqMMmrF{E z!ozXWxTNS^RL6v5Xt(Bbp&`*S>(&?!*T-t7y5#CspL!l>zmF)1?t+wl2%KezF_@{w z;mG>B;wH0%Is!(JypYqjuRRdE!F>S>xJG}nnJ?_;4R+FPdcw|&Y$XYoP8kWt89#n3 zM$>(osw|MoYrw2~ed)&(8O`LbDi4mtG1|}ZYOQjAvt%xyQp79{Bp^o9gA;{sptxhw zyHEiSRW(|SRxKnUaXHGY7rl9zuGhB(@H`Kk*l;6~TQ26CG@zH`wSuiw*I-LhQ~%Lp zfk9YQs%9}>PFC&em^8a9hufG6jR?OR34whtOFUOtA+FX^C{#_ zLB^ZA3UyIwr#Jii<7qFKv8WNShnHM(V;cD*pw^H8~!}tMF!!sYy zm9-Uy@&+0%3~+M9Rnu1S?NNz}y@l0ldLnaM1&+kujrIF z&zPS;0ZgG4QH~^bpV}gc5+Q4rDBk7fz`>9vf9A388kKvh*Qs|azq-6+htvpBr}Q3e zYl!64nU5%=@NmE63p&}acP#*p%n4|{JQi=QR2Gf@W;TWho=OT=l9WWdNr!6**v zrPyK11X*-{vrq5p=-RjNXA>;u6^2l(sWdD8nw4d`hVa9`bI2p*seZ}{hA}E8O~boB zVj=MVoxQ~7;wt&Q<$J_2b&h5KZoJvmBlmNMkF@;lfpwv}MMVNV#G-YVHF-DS!%_&@ zCp8*zDZsLmj%Vu6R7~jvYM=oHtzITeMsetylgXUC5H+WZ*Jx7tON;^jw|_d^ zwV|-#I1E6fC6HPNq2$Df{FTnEC#DM6J#(Tvm>L)1(f(QT^}SPixu6i1E{?A>X^LRb zfn@cn0jPwAj2^$sWFzkBcIEm8+Z>Mv6c@-zlmV42yl=w6?Y`UkhGOpFpL~9Q5B)gO z|KxR2mH$x~PsQ^Av z77v8LA0k~!A^NGC$(uYCU_DP}k3aDJ-j`+9l{N4VH8_Ph)!}ZW;Sz-aK(aB@Z)TCV zEX^W*kMH^`Da8?cFK;&e6a^6F!|l*OE5Sq3?e0cT!XwDgDM>x1Ugi(RYD;J+s4&OY z7!9t{oCxJTp3T87R};JETBT4HOM}B>SSX)>8$-98d%SNblA0-+j-+Dyehsk98N3vI z#*EPui%4d#UiG@spv43zxWBWU?N?fuQ6+s3K`Ta!h(X>K8eCLC$j)+gzjxaYL3Q|) zyCD555+QR7t$3gY0tw;9l2ufKMMVV%WZn^Vw<2Oq3LCWeZdNJaf^uGt9{=U0F{oWJ z|2ts$`o1<9CZ?y^ho$I{q4vi%}*5&>1%%!hLcyc0a$1xsYHqXH$Rf14C%dD;_FK3R&w`9`Z zvSN|o2Q%suN;9^cI&W3W;tGC`3=bO|D0|G%*4gb@nHz)&VCj2GQzu{n;`p^WF}@_& zjQ;SzQ1Wy%OXld$5q@*yrpU&$VZgs0VFx$vr?0Q1wGqVN{nb8?oiQo^YeUksjSUlD zPG0-sX|{WgK+RqEZ~d%iR2<@8PHk-RLZ<;x0r>AFj-vNInmJ~a&*NFCW`C)TdYc$X z73L_7jduUq;cMg;5q(UKJ?Z}Un`*c6phoqn&S_XzEqWJAHeW3l&+9MVL9IVA=n$&@ z0u5%A;G{O655x$7?aEJl(-yPSkBzmP#FK`_Z?v9Bo4PoET$*`d*ttQ@j!$Y?r7=42 z3@MQ`r^aS_7qOi9POI_he2cP+j20~Q5ZGWW6dim^_58W7dAq(e=Ua;z#3xfJjmB-2<2rL`H(x)MC{r4lB)xL_JWX7m2>czGlbhYI)K@rW953h=>a63F z1j=Xsu7GcDzu^=B$>P)fnhaNmDQJxkFMGP@GBCwo)=)gD4()2EM1ha3ODe_|NJ;Ah z*a0<%YMh(vBp@0Y!k7lvo8&jI7j#g^=Pp$YTVfaGFjh?)DRB_YhFZR2331Bd%+BYH zvA?)*4am2K6sdXh^|0d z8m~ln@O~t#P<$nKUMU9-akrmeNhui`qW5&OJ3iM3_JygrBJVkVithuRK+O*uN?LHw z@J#RsC+2H|G;^Q=jN`lT?v{h0cI6;zm*NcOPZqQVf ze1sZHqz)BK1Z<+c9mWj!hnf=AQ=nnH6cP-UfxXiAQi!DGzW_Ez>I~Ro zNBx%_gIv^zXmF9BZb|ImRli6SN<3(||D{KwZOJuMfh_UfBeaG-A#*V^v&YAqRc4G* zH0BVIICwR(2$JYm%(7lDah<@-N0$Y{OznQzinX0jT}|0n3yxF_TjpfF9V2=Fz@u&t z#{q9ySeIwOoux`dEXPUKNLkI~rI-xz?|d7!2Loh6zIx+rcE45Cr+<9(YT}?ukofar z+7OyLj*pkOVuK_xU5ln8uy^NlrE{Eqlafl9@oNOJto6|eJn>G%Wrd@Atl0*eqI;FS zX@1)c&Y#WJc7I>TuSRPeIvaCO$U1yZ^}zc-tzwjFbT9YldnV(nMyu8}(T-{Yl6%sg zdxvpf?~WFiv8|=SR7#_ZuQ3+;fj=otvyQcIljz5^QKvPz&Yh=!Gmdq5<6~oASS{zH zBltR8TCeAZ%xtSkenH}Zrx6lxb$=lKT?*O76E-$)SA2X!!Ice=|M9-mwR(#wTvW?6 zbn_Fl?2hQxtDDF(?Hp2~iQa+E@f9Q)T>Xy!b1|X#+X}mFhUiWpMW#lj;qacogsWXZ zktltgl2;qMhwzygJ^An2>{jfV;re@jhTnudk?*vk53LX;-xJGYT{rTxU6`J@@ zmegr8E&D0dGM00>kUER83j5ZtWuk(q|E=v*cCzwQ?1bkTf`7i;zYswog&i(FjIvH0 z+MO0`iM*2~s|8!WkpNMo&gJj+OE?V1e7V%}%fes6#X@$4y0iMhGxiSmp$Ocqttzuf z2Jt@}pMQ6w6M^cWZr1ksQjq^+aPOY>_Gf?DBafxfwI4gH<)AW^2<=t{xD5H`%DP$u zpFtb-LW)D3VG3xd#${JYLtRjf(rISaK&M$}T?@s=Q1+M@S3q%R`V({7*tm(d>16LS8sd!83_<9DshDrx4^=DPH3ze7yu;2vIw5e+Utn-$%m|JI_w0$WT*te zDKZR3c{Jaet_eoEk{c-AMSb?MfY?nYfO4cF(yv*5R*c1!A|w`meXn6mgS>7ee2{La zXc`;z#{4K&zT`J~P64LeUD@hd9-OmpS}rV99L+&g8nX#c=xA1|8O~ZxhM_pW9Z*NT z(}xR}G$wvwDR^t2!NK@pai>)gESt=XaHlWe+PJ<`^4l7#uQhwoWy)c#pM8dZGdvRRkryHUXMh&P$gB?i(I|R8d>8 z{XB=ESzN($@6$zb4ukefk7|o)*BJ_A%Vsv)Z5IR7!gOEe!q9fbjsazVI$lW(I2fRO z!s~ZOD3Pi&#H$FM{_dJ%- zpNLES?CV;msuSyF1Mtd`U@;5R?X|)*8be#NQgr?Axfoz6;oxF#w4NvBf!L9Qq-3p| zzurNbs`~3q1JNWD0IiTV0X@7})@!wy$_fFil~zqCdl?KYYf(RSr7NmJggh*e#BZmd z;eZ*1t6%v^&*xi!xs4?0y2IHk^>G$f35$XPQQX?Tb4PdMF* zC0-6>8yK{6CgKnnO-sqM@RNP+4JgjjwO$MgBeB`J-n&P?lLqyJvg1q z^fO7S2Ko=@>$EIziKL*x ztT*2k5`d5|3Xx*kvp~$F6|%@!Hg^F5bNr0eBN2E2lg{W$EkU$``GLVPr!#6%z1+l1 zi%s0wvMfASzRq$UMsWofL{;FA*jP77Ra4Y-Id?A_CmXYaQT&NwQFU-O`YMsDr_aRc zs(bDPw~zvT2`V8ADZ5EPJ|UaSozmC3@WF>u zqKEs+wL0C$tjhMsp?{DetsqfQitKPVw@8@~|6hiD{K0P?<09DNaANl-t?SaUq*mtU zAyN_0G`8$}vtJ8_+Gk6&DPO#9hNg;SR8>`-+-^jC&6wTj&?Lssba}rFz|;^^nC3gI z|H+8_(P2N9xpyjMesr(GkThJ6r2?(405#Ike#9i@qLP1J$}NR))NA$H8cYW{(1NNy*0VzM@QL#J9BT|& zuYQ?NbFc43P~0;d=dZSVt+-KxgqB*ZzgT}MO`^}VOJkB$advh-UT$@GT!_D@03FLi z6Z$(K6>XiQSC*Jj=0}v7H7dI#M`#g$|Z5SoV5O9@x)qI_yh&a+A z?(KioB$tN(ez}mOUzzwmQk^>M;U52&<4>W+C_~x{KQC`@Z}08~S@8ZFHA9xUD$UPe zFazB%H4U@k_EKHa>or7AZ>7WS?0eV03}{+mxy5dEW#xQT_P>mk_f(V3LhYx|3sstR zq##0813}Mg%ThcQFfESU)9uO8TvZrO2z1cf0Tn#X8@ao|e6b)~TU!9}@qa2^ zz|h+&WPh5PoyAiO_>ZXo3CvF>CLxI<6CyTb`(KhRno98y6p1hlDOGRZ6e>8Rt5?kk ztUfGpqS9oao#gm9pWJ9z=vCq%^?q=`v}F=$$s2NAZv34{Rv%lw7imc{AEcoZJ`AfA zXv7MoRn~clNv=c`;3ke~Y;;mq#scts+u)4-lcyGxy^G)cs=;%vmCrpXs@FY%GJrvM zG*(4=kySz_UXK;{EbiHWYy=FK%h=-i+lp)L6dm~WmK~(pZ2dhsZErzwywff;p4Xvp zmY5qxRxbL<34HeXArcRTqb)$Ah$Z*T63c(K_|r$jySRx;rw;!YKZSW-NgW-X>*ZFy zKbe4>T=a{(j0uuNg_bva!1NNgKF7zosKB)@&v9M;uoN?&>Fn(v<>lqoNxp^r=@}%9 z2`I3J3dR`ufh7$TNF`MCPY(~~hpLpcm8M6jelNLWZ|V%{3JMC?T_O?2L<|H~ZwnRb z+aiSIAQZ;u%MtNrot%*g*@~xPMwq?}y;!moNveyxJ2y8sR=tCrsl=u4=1%VJ?x1El z1G+!ATNWyKLV|)zEp|_o!r3zY+XGSOBD}A|^$PF5(g0Y&**LT*;GUOT-3qlwP@pIo zf&v(7OMfwwrH$W*7y7>2R%5AN5?f@adt@qw|4(VV@%&D6FTbe9Q z5}hJL^c&%DC*A~VTU|wy^ky81%}^ulz&G!V22AhBfo6{{`5HFvVn#3zX9zp)0ekRz zFM8mpIwtt(xWk76WT?5vkeEM2qX4 z?hL4LuL4C#C6U;PdCX(1hq3)jU^|mTw9Zsa0bp~B= z!#_txj;IOgggnfA4=Zk={O&?PT3WihTTzWcy+Ped1+S~COGG%&dakmqqrJe4eK+`i`x>SRWo8=@Q$3`q@sFTi=4;hxT~mJ6_xLX^J7)K)VVfVXmViV|kE>pAdf^y{i-By4e>Jz4n9- zDp9Y}IGHXPA=K)vGwjiBvDJ?KXU(kJQmxy{;_0^*Lki1EO{H0_Rp7uCyB&&2UaQ71 zB@Cri-83lYgFv8123jQX(>oMj%J9PY?CjC2&h9Tg?iaA?l>l4-bak2J&7?qLXJ>~x zOvtl0_7x-;i?sItTkYTfE(HAlR2umIb9eDE#JZb)f`go*JQzz{)>lNHFnM}~@Qrew zLV?95*`sxQ#uDu*q#X;&Jn-@SGWL3~(V&Vhp)|namT4+V z(N^zT_g_WN)AfNWv3xkz)^f2nZP^kX9bIAX5zbsCULDKKnpZV_V2VVH>6=~wmyoCY zKZLlmR{_`J@3tM>l*Qg2SuLx9I}lKbN&6I6=IoZwZYc;#>Wju+grpgwJN&&F2h|1|vv=k{NZ$H`U9mWb5 z1qOdd6HPbUEKDym6MZ^A!aE8*LB!bRI%xfEV`;2&SB*!cLHL7`R;BSOjonpRd_6a3 zx!Fc@H>bmC!l<$RLzdf7?%FIUdy2lKI=CL9kBhjq_RGPL?Yols2zi-eOJn2Ue?LcI zI46ym&wD6h4Au8kk9KQHA_37rq9EQAELK(8Nnm0q zaXqZ5g1aiq%Ub+JgZ^9l?YR00yx2WX_EX)5te2{3+J64B zl4ATd%U~=OS>B}^T$xlfTfBYUj=*NV!3!c*XuT+dZjuIFl91o6S|@qC?=D3}b^WR^ z7&MZ&txFK1a3)CqqqSi=JoQq18d-hhOLr@4-e2yjyDs^UG}D+3p>Xp`2M?C(opp~l z1nUAD>Y@3`w+D0E_q8rPzW)d=?g@-#H!*48d{JEGI~y!E{C$aQ2&mzqHu4WU6UN^- zoxJR`_Vdd^R9LHAY#hsIA&l5YTFePeMEiV+gl;H^nsbfch8_)lB3DpLhM>jKv3_*p zg<3N>V5rQ^_rvV3{x z9w1yDLwofcT5EPn#k`Jm_s%k=>`}t+Pjq_XA=6`H`(a~a!x+UXxHO(F>@pW!FcQ`h z8RMxPKSkuYANTO~EZps|H~$+(rh+st8a-_O(~M zJ3Y?jJg<6ve<5grA?|8faiXhMY3X-z8FFqa|Jhc%@`!b}9$~`D55wA$)Tzd)3`2)G zje7Qr7E=_&E=C;EYQI|bMk>HocGrySg}h_TrS8~A^LCk1a<03wig!{@~KQJ3@Mw&6LHxceCGWFqfaK51R@23#5$4fQumPn~$(Kw+>2$drA9(DpL^^p^DIk1&-R2LCey&Z{ zQ)&z;yH;Eo3cvSbKBBO3DP&G16tvv{gDk?G!!}tJ2DPV`;lG4)C<<>JOvJa#FudNF&E>W_Ckfu z&EeSx->DDwMn=j#zAyg%{?lZJ&I^9KqZy2vwU%6&(A`dD41-Y5h1+`Ws+pq)B_=N~ zufuw`&s?Q?4}F=4iXUT(Ux))!}+H~liv(`VL%wp^yB+iP83%S%gzl2GiR zwq`7jHxM5me}4Y8MgtW<>+j?>*mq^);v(g?P8KhqCkZL*0HuJNZU1t_NK=PXftt9r zQfrh8`ut(uX{Ek67S@a}BU8%B$uVkFPg*wzQm~;F=^hyp5jwiKprfHNjlM!rdIUoW zIcr~EACLWtRytwzf%L;tlhyX_u7(Ec<)0KrL`$bT+uWXadk)kQ==&?r|f zsQyj3>LVp31zp-%85kIPmScx-)!qZ27Mj^jf@3+?%s1?Ugc)7bsS7|qX zfp!xi^icZ$_swLM_E1gUpBu+WCkgQ5iXYBZEkO5BtOZa$=Ae+*?MjcI$RJaWeUci( z4HT<7IrXoJVvIl+>r<%C11a{iq%^tBIJ75ng+6@vFlG7QLcLxTEnV~%3Q@9n9XND< zB|}Oed}c#fxVTBI%-u9JG}Q)OI(LWSt7s@dGOMBQMsL8SI8*gKhsVR^KRk|W=vf1J z?*E+&0G*bcGH=ep+dDh6MKW=$)`u8SONxw#Zqv?|TR-3VSC*Aoh>G?Sk{CKCu|W4j za6qW>QmeyyzSujoX858hOAInW_oI2{P-CJ{WGG$H#YO6WAY|FGT7_C=j)2?a!vo)^ zPu{~9Qf_BZ?elrv+Cp{H-HY+hk7sEhiZD;eYrezH;aL1X<57VpX43Sr$yXE}GKptb zh?JK2-zN!xko2^p{@-Ze|M}4Wix}=b#URy4(5c!r;ch|mGAJlQ()7v%&V_R0Ox%^7ih-HxgOVw?3+oNkDekaws#UvIHTDjI zv}WyDL5!L)6R{=2?Y{2kx&MUcdVY9a=ZDXAo%8wOT<7z{=Y8J9Su(fBo>i{wGX`T; z9*Oln5oOd3)x43GSr6eW`e$#V^#B*H>vXT$6w;d`*6f=7N*Wq6XlaTJ^s9Vdovowq z!PO+5xjy*JHl_^}edp1i$wvq(&TcQ?m@C=`tL`Uop^%(S6dT(vjN67S<+mg?arGP7 z%kLC4Z~`ZmTYD*}!L*&W1V1_uK53h90QwtrQj*ma4(A)Sc6&%_^eb(7b<+FT`-1^X zb_wCsPN|_eH`7Di%<<{ojhE)1BX`p%1Y|^Z-sHFZenS$};9RMBOHD56BU`Qo!#y09 zSJm{Y!lgpkkEA-pZhs#^Q1H&$Di1yuqpdN;J<*CAt)AR0#lOl1-O+BQr1*r++S+D; z9t}(;e>W6fLV1VKNj1p17~|-uSXRwk?=2?6L~CzvwK?`z*DbLPW=@4D4+PKnSXZ%r zbgU%H3_FA1y9{zIC>oif^myZm%*%DLt=cO$;*Cos%0WmWL1>aI@8b}r}aZY(0w~;GhV|lb@|AgO?R`bgFyoVj~ zz<0Jk$}wGRS%^l8rAQb@fDOBw1$C0>9+(3h4u&uPmIoFLy_(SEMz{O92)%J?7+Peq z*2-T!rQyN(~(;g${Ox);JI1+96fCucJt{-L0T9R61<=k(0bICCyDqBaw01V zwm)bMnR;j?aplt;oDz$(E?tCvN`$mm%`03eZNi?Papdh^_BbVfSRdaWPD3{xMU+dt z`^W;c&b3GWJD%;t_#2dnJfrj2gR?4%jgic`=uOgD$(-=0bf>ZBHYlZu_Ta68@ zlmCDd`1pA5TZahw5MnP;1K zkntot#K}F6wFCXH*zW5ILoc47JG40YXLZ{0+ zZ_@VtVQQBQ(!_@4tPuS|HD)yFI&_<(r6f@tll%iIP|n!X=G2?MAbD?eawrg!5BAE}EY~ z9mGo^EzravXAwch;k1B#?`KDXrf{}PRW&-LcCOLnfsd zT>`9kIBe)g(jxun!h4p=W=Nwm_~d%JZ|s?4;`|3coGrXvPhd;$92|?WYT> zGuk&SouOcOlF8ViK$pf`>ZEYGBP`*%i1=;e{O_6%m#a>X7@!Y>9|YDs`=$ZV(cWY+ zxmvIc0p!1ZbHdS3#Krl`9r;w^^ga!%351d1^1~9&e2Xh=zVcm!0TklhO?2u5*()E) z@fuQdnVFNveK0&VQy87q_p2FFt1j%eV8l2>&SXS4UULK5BED&j>Kb|3^Qkckd+kC^F)@|=DlwxS5y2!4@v~Ed)K>k zW&~qF<^~ELK7n(RGK)BcFuw#yl1LCac1EMbZ?z)iHO3`vC(x`a$f=xL2&$cEPYaPD z9}95pd48{rCHrsd^`LNOXDSZWe>+6xo9nnJs{}hHzC9CU?}nm({YZL9;J#;oy*Jrh zD7VJTXC{uWj@j`!h7561Q5ux18A)ma3QE-n=4RB4Z ziRnZ(FuYK?cYh`w#$s6P8R)!IK_8uNh6f!ot=*mEVl{aV@pUIwBI;|+H{*;aqEZ4X z^4(L?I9xeRp7d%h0Po5AJ3Sv@joP(hV+byJ$L`Wqlm~% zs;{rFrMb+_{`b6aHdN&VjV8PV0EG-vpz$m){*+!F95?J*)^m{2`1_AGk^x&~>GRcO z+sx5?lUV3bd2a|%$l)s?aRn$~MKbGp4a{8^wayPbd~WWMwj+nl%tdJ2>jTm+e(kXwbL&ef0zXm<@Aeht)N-A@6SItoes}17 zcJ}_-Ei3urongG<*Y7)*p@S66qxCEg-{2*FR=LOiWCdhNFt5?ZPQ^^SjoBbW^a|6e z8Sk)Ak8BKGsF*%>ygl}VcuJwe`W8kC?bh8XXOjf6d-3Er+)Z-hCfI6S8`P9101t4w z6C&%qE5JR#Cy(FG*JzoYm1peLaGcEpluZ?@OUH$fm)(7^43mDtv`=_4hZ@>gu86MTx^O9X>w;6VcUn$ryn-Oi~bZWRR!U6|mYWqRZ zOi@3YHq0?T9*B`qzwa^q!mZM4-&EQZqB2|Ix{}GsYU6hkkA&vhS6N=n9dr(vvHV%p z?%Ocqh3a)qjZkL7mA;*}VI77_#)DZ9iA!#d7AMppRxnY(nJ2qLGvQCaJ90xD_^0*;i!hTAi8Cwv zjYPwb*UoHh<6rw1uJp(gE+DOf2722~( zVzxs=aZiC{v?QaFs_@^|$H>l?^f4Wd)dAn5z~JJiyJLpIhnvvq zB_)AdDGP11lfeh?bM0Q=4({LX`{gk^ot%<_UM|2_8x{l?kL7z%4#D?SoLb)=1`wti z;G;{wl$d*i_B|}wEptijKlF)9n*%d-UWB%C_+czVL`_R>j4gWg{fQb{=|1)6`es$t z0)qH^#)ga9>L`Fw@ZAPmG?4?mY-j6~Y^Qh1bBm?DH@vXG>P*;PyEU;XJB5Nm3EZ6Z z9?Hi{f4i0c^dTj_L~Lj0u&Fte^rV3n?nT%jp_F1AH^x0D)3bN?v|x5)1F#U{>`8c} z1M}8wFrgCXb@nG6SGDU4YiaSFJgr|*8!Z{f@XVF2?&GQ~Hh<%q9XBG-bhFA{Yn07T zG>=?%KV?gPzPYE(0%?xAfEj#(>cE4I_Ea+WjCF5+-HZy-6`>6$jU&VB#zx`eW3%kK zU}dX?EsfntlR5AoD3^w!M_=M20(_F%CRdHnxZ6CrdcOXcK`k^lTx7ebZx8zesQmOK zl*`pD+SdaxRw%w=WCPv3j4mwt8eZg5Wi1qHMXRM%Ifo6TPFE)BALPCybJIJWny0`S;8aH#MFQuI&)_{oS zK3#DE)+VP$C(o+dlk0(GvfZo(f|S(T$&#t&_Pn@O@~Mx0*d4GrC=JHjNLtHx^IMTt zh1^J)I>_p>YhJ#J84ub_kU`mze{Le#B@&5K*^h&_xZ&FEFU9DnJ}%Ny(_u@`_CRn6 z_3Mv67JW0gBHD#c8ns8MUT4%55P*gS?ZdwLTYo#Vfx|J>EwwI@ee7V#nU8M9Z_dHN z<2kwNYQ-N*IMG1?SkmbUzKt+Q9_{H86(L`0DFS`lXAzZdxa0UMW770m&#UTynQSY} z%H23u_}Yl2ZQu*?7=S%nk!|Fz*xB*;89DhwyU0;O$W5~g!`YN-KP8h)3a`6>J5T|{ zR6EvWTXgos&j$S~$}ynpiC93I!!qVHxSEh2rCz)!8(iA4=F(AIZuKLfBwL<50^6_g zcZZ+@#L|o)2~*DJ&&R9TCT3XZ=W1u4>0`@;gjYH1%j2_C*U>G*)RJKvz3h{S_u$hV z4Gmk;+&vk_I4Ek>atr}BKT~;erL@4dA$OyEgOmNQ)p{{=+Z2oYR+|conHI1zVf^?= zQJLh{lp5h;S3Bqb6_V*oHNt0(6-Q<0g2vukC3LI>gaB~x`AfzEz4c_QOq)^cXd48`{2?5Q^y?3MVf&*VWxBK z*zJPG%o%LbFV8>lB<*_}MIJ&VV`mm`(36UTn|)3*u#O%Ik@_U(Rip$d+E`YJx;G%!5-Rl0AhKq zwh;3uuCA@0J2vbFv+CpVq5J%Njt2%}sa0~~B{9d~j}i(qv^wNM*9E3k>5|3= zV)nHL>N;fG>zt?Lc{Q@Ax20DTeQO*eOKgF=EBZbp%PffN!uCZwC^dZLNg zr?H-9&cuhS?{9uDQDHDa4Cfeca(&Xib2HYnW-B4nyMD(&AM9edke&ij2>#ih?%d7R z-5qa({-Hqg_e2k%OQ3o4&-@Fx78@%qjWWXYKaKzYwCTyGmz-?T`RRxK+UItqH2OM5 K+GU#0-u?@rBi8f) literal 0 HcmV?d00001 diff --git a/doc/sphinx/configuration/suricata-yaml/MPM2.png b/doc/sphinx/configuration/suricata-yaml/MPM2.png new file mode 100644 index 0000000000000000000000000000000000000000..27cd87caa66c59ef5157464fc9cb069af5fc402c GIT binary patch literal 8647 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�w6~n-QoSZHW7A8k{*T@~B8?|~=y-HbVuTRZDr+Yzg6h8Iz@rR% z^=ou=)@U?w+GFAPaN_xX^8SE!8ARA?3w2y&bD!ByHGB4IZDo&q`Ag;GDZwG?3TCpu zIsWu2jUoe_?G*eHu^PGj#-#{}cN<;wi6)oMGLwJoXq zz~_Q8#NEM_4_@7ayf&W^)l16kVe;EwTW%>%NPkYly0w2!=;I}dqm1%k(Glnn7HzvJ zPkgONT+{3xgmPwPsR@ZE5WGB5&ZFC*nhmj;!1vtJIBO50(RMc~G4KlL<;C*P`)Zn1 zI^HE`-4Z^(O@T3$=;^lUjp}8_=YTv8-B{)N?1ibd0hgR`ir8aX}TQP@qYG?N8Brr9pKgAN7p~0T%SJFQ1*m5Rk z>P718Wv1g!w^%u8?$<@oaZkK=87LDIuFxu+LUw#GttmU(D82zZ3C{~;y1n{P#mU@x zgYAHb4=j{)Y4TUkEHLNUR6WVbG$U%Z#a3j)EQxT){vW7LWK zP)F5nfxeSiea=KL#Mg;>DLoC46U|Beum@<^VTM#u)l#U!{{vSrf$)jB*<;bMIY*a( zmuWzRr1j2T-2A*#^-OW^ld~8bV&0wfJZySa?x35v%JVEEVARyxt)I=8(sZSO%6Ze*>sPrsP%C9YmLbP| z5f>-F&vf!D>Y~MlWb~YV0;K;;j%TWg9DgJTLfkj?y2fE$J?9u!8wJI3jYXW8O>dUP zp`~I7Dwt3;K2lVlY2%zcTHtmIJsf=bI{Dz;VML`-h?<5iHH-f$HE+e@Q>9!p9$H5Y zTw&N+8TFy!q$*|8NtQZ-Z%ivn*p2bI2E8B?Y2?Vtd9nue?B`R|UCJ8g!>#prdB6Q? zAx(ZXYJwcz@@57+wEKPsn5F^N=t~w`-d!0YHj*RWk>l`yortFk23wK>_tfTF9syEIp#%8Y5Omh@^W0$0rBzfU~c9eU;g zd3^$Hf8@S!^#F7b)Rmu?_b@S-FbuISK*N!Il!;iogpV!UGBA7MK3X%$#@5z*WiT|0 zswC>uaE5kEz>!v_EF~e(zWu=sOLBM#M4ndAmR9O%RIF}B$tIzcUOOSe-DXSqs*f#_ zEsPlrbQ|^04%nX@9hn3%=<`g!9CN71b zwnJVc$hBmPo=1a{fu;&iL%Ce)pM$ z$ElLeED{cFF$63*gcCbiTVZTE9D%@{ryEADv6%`c}jv_esW9-RQjLTb@p)O*X=x z#YO8C9Y#w{$*hTeBo*AHo$n25Fnb4a@YYLk>GQ)}IO#Qn*a%WpCAf96|7o)hmv&#m zdr;84Fg3?%li)YN@;~2J zb#ykye|de;ak$_Kh@n2{?3m%3mtwu+BUW*{cL&B{=0fo1fW8!oJm2%zris=PWYWxW zv{b=R6h}5Wd0NTuxi!Hss&5};UouQYd|M%s3AP$Lx2-6J$RN$$J$<)?-XQ2ROsy!_!STQs^3Ajfb z7n77s1XFzxm_0KwAoDZsTvYAE0$%h_DO1c;Wb^7su|7)|T(lZb<^h7}^?D6XB*0Wj z%UeES)U4034u(+|j_Rj3XxL@$@$ek$4V9swpMADwTf@7HfOl+#pQg=-%Dz-oK@;NajDS`H$-_?7Ne zp`KN85a$9qn(x?YGuz}}tU8FX6$*`}W_obv;Kxs`xH~OVl;S7$?M&pU?3_2}_0xOQ zqpHqtav5Sm2z^}26ogyxbjOxuT6ECZ^ow%Op-khqZeR6%^7x~ z5@mh^axyJ4GIGipAKl=!)}N`U_*j2+sU~u=)~RwcJxQ@P$gEk8yf_|!H43v=@1Q&z z()v?|&x1iA)auCo(}DhR8ZQNDvZlOufBpDYu!u)>$So8={Jc4%woRcd5Y* zlf9Xuh)b6*>(S3d^O1*D8K{2$=;;%$5T!4MN$=jh%gE5#>|7%Tr}KIP9>HNe<)r&ob-k>K<$Hw>~)DU)SXR zf>u?r`1|!GC@}1OXkmd2w}G0X8h=*S6G=EQG|##xvGXl^4%_Ekg9HJ?fZZ3LkQA?8 zUkIqxR3#^818xicp!k!_{Ubl4E*x~T19YotIOHC=Ox6AT`64R&4ujzHfYrkMQ)@?K zGCOQ!Tw$T2q;z5Nr;3vkvBr6lT%SxPeIJmMxJt8IKKtvFwpHWgIj%D){o9QK0H;XN zdCEUI@~nslmJ6eQ)5n2_v*DC9Y*}od>(*-~FYNy5c2_ukx}Vy%iB>8Q(R7Xfa@L_B ztj5XDPv(i?UpVWlFYCZM)q~d_Xo89+y!_wr>J`;^OW)b;GX|4dFcO=xBvf3 zYXA3a>_4OWQ2o{1v@Zj$5?(P=c-R-gbU-h^C?%$oR zuBo|otEZ={r_Z^4Plu~0NuweWA^`w^Dk~$Q1^`fq@0A+_{cd@sxsZRqLAk0)ivi{1 z#E0(>@TT(862RMkl&rRbxOWSplZ=il0HF2$M}+*?#r!ThTbAaXD)9$p77!q~-hgvXy2)&|+D261Ir0C^m5ynOEX5F_i z$}nRn)#7Q@zn-!(=oCRAH|yuWj|Hxu&Cc)c)UdzKksbKoikFX$jh+c@q<9T~`bL{a zE*27o+quOArV!it4#J@1kq84fQHX^MqGC{<89Q7^G0D*Z_fN{Ku9x}ja;J*CX%i2L zA=KyQi!3>Pezwj;O$#p(8y%lS2?khnpGoYUktJ8zC(G7F%Rh;Q`HZz$w-LYL++zVh z!8t%-nT>sds$8~YTZo#SBX-u9Ezt}v3{$cfjMS-+^SzLuDz^eoI=sXg;Nsc3UM$P zfUBvhs?V0)J=!h)4PEJ;FejB*dsPeeaK3j^9i*j>r;Lp4GoL(0rKw4wj*peuMaq-P z?SB!M1ieDQG&%M%4pFiosK9K_=WltACEKK4ms3N`?ET#AOK%rq5f2k!=&TS*yXQa_ zISjGR*NDz(jn~tohH;Gn|Bff;P_bz{Mkx^WTkCG_SjVTT-3y6|J=}nj@;deC=&zld==-cog1(RbN8=H%EkVa*N zb{7<0ID^1j5b7matLRrv@3$T-m{o%li^rU>BpneD=u2TqdEqpM+@m`p`45@2)Y@GO z3-4}OqPisLcEU;)jjuE!X}$l}DSQN@A&ZGr9$nIReH2@t83d?dPkHI<2~&qhMs6(Y zA1k2&O@l8w1Z;DTYt0N#V^)GVVauOsBdV%ebHr>bU5*Eui-(K(*|&mz1XqRPj2>$j zAMBiu8@PDQKYG4BLmU^1dvczl2{$63%qQpbKV<0o@2I@|!AlZ)4n&d&-9F!fXMtwl zxN|kq=`UQ}#e@w6pmM}WpeTY!zY6ZIHlreb>yH9mI6;X)!GI)(m}6FbzMJ5~^Q7fJ z6tnhYhQqG>_~P(TA3;~ma;T?szVel_5e>qzlB%yV+vOoJqr!nR$VS{yZ!9W9nXsiP zZ4;8m-qcVaJ^%Rac^oChPuUZ&=|EwOmBIIc!3@_Z|Gj#j`S`l>RY=hyCDZT1&^N{W z?6;>h+5rjaKX?GJyR3`1H!5GM-h@e6bzf4yCzk^%3*BCJJ?NEEY4ai#Fu=rH$A>@J zTuN;*rWfKr7$^-gEG$WoLILyEoTO(CHd;KeA{cce*?htRR1}b_+hCWLUwq^VvR&Fq ziOIiW(;e+?Wko>u0tTO*O~tzFx{-hoR$SU+koMZ#Z0`si!L8IVGCR-owcIcJCt&h3 z4h>Cjfqql|$H_=~k24*Y^1mPQ4ChjKxxsRXo?NqwzY@Pb+8ELSwC0$zcVD9_Yxn>8 z{O~kwH*BD5tIW`|6+NcM=Q_|uQw~uBrrqu?l%*?XC%zsvNz*NjvMm%dWh;Znrn2P~xijKdT+Sx&2HD~j}S8!9bYRJrR9_9~nRjveMWFW)e7 z6eZMJ2oo|(YJ0W8$M$V|N%4%)cxquFC0UVPJDb81W`Z(pcCi^)Vc^-1*GwzZD4K?q zywR;ad2K{v4x|MJcZz$djuYFi-BZRX)tf`yj^DPn;9zpabU_5)n@`Z!jl3QdTnyr5 zi=7UMvF^Kb;QT0|K~RxQ2pzs}ap(T!Q%Bk#oSpB}IiLIRtYS<-lG?@`x!B-*E;@Nb zuX_#M@-E|k_NEf6f3ML}rI%sa9iqeI@T74E%N|D&a#K(Q?b&V*9 zI#5D1wp)DelRow&F8VT=RtBC5=$_R^?^IZEWpP12Vt>r|Cy%_oT(T*vy*At#YuA?uY1`5h{uZwv9q-X^n>_sQkt;g1sF6v9{H7wEUuiG@+@3J7 z2=YJ$;u;D-Ryoe+2gUH1^x95;j9nL?+BbTf^(?FxLm2~=-93L=UPE_B~M_Ji&3Da5X? z*`PezFEIeJmLFpjabr^N*X+Ae1s%fX*j1&-qEh9w7i`2~`&}{PeypCPWIdUT(sr@Z zZRl}}KLm=_0*c5*S?K=hqrdq6i}%yXcN}GLi{XY1|0LB?>Ett=w{?LuG)l$6Rjm!9 zx)Z*nBl%3b+_wetjuB5G>v=-HrD0BDA7y&`PZ@P-Y_zwcJKK? z2Y~hK!`}+S0K3yzqv(&HSp5bMVjmZxjizIW0*o3f;7e)jx2RXC9EKQJVvg3JfSg<( zx}_&&NlMSKN^TXKUw+dgVScZ?b6$`1Z5Cv$#{M|DCLYz9)cz2lRie$ zUH}CwMTl=pOgPb3n%4p0)-OV;&TlEt|8j6P{96Ui(o0~p5%-X>N7B*F%#fagg`DD%{4j58H|t)XW)ueWc@ zE6SNk{!RlEq0|<2b#s!BO-o*VF6U_6&%gS}Z;uE<5Um*C0iFcCtTdXMs#I`yTDV9_ zNrk-{!%~HiZwzJ{*N}~k0@LJ?;=(BWC-18`tt(-{+OxSHJ#n+Ao3OBhWd<7Vd>;e} zMChQAU~u>{S0HD)fEOzRPepTneRb)@Q5`X|Xsd>5B5mv1EaoT+9R|hfF^$2O(0MEK zQasQJVpqFAJ7RN+Oe$pCGE(?;Wt~g@$IZsFI-N5FQ4$3Ucdflfo&l>~;V|b)<+$W$ zDK3?m%L=0s-MM=KT!JOCYIDn`fjy9%(Qr(`ac}@)qF(#b>V;kgj5xA-ky4DzIxPgl9!r& z)wZr^9O`+pYHRRFs#!lbrpECf9sFR-U5Ro5!wdMtDZwGhoZj!09_}+&Xg@>tD<;m$ ze{nYG=rEO8`(k&Fjd3vkT}uhR8U8LM>={~S5s4CYi%aS5{y9_FXWhC_G<%Z}G0fre zP1%7Q_O_0XS`(DGm`Fe0Y^!q%KHl7x0EdizuXb!WEAN7^v^AR>Yh>x?$B#^|Psg3? zdY2Rbrd6D~(jYJ|V9S@d{G zgse!STy5BvV-Z~ic|wVyncevogm^bY`su6v6-QM(rV?-+ffR}Bg4M&BhYfevbbkBM z-^YJ!{kCzDR&_J&0Tobtghf5V^D(}Sc^)@BB*m517D=YGeXTGmTlD&TJ4*GfftcS` z#Q$D_7{TcW{K5;&sYWzT2M3QFayh9$3KX!aYrfF$?yi<}=I71(U3(mTa#3Y!5+5IT zs?92-BqBngAFzmU9l_}Cbej1dUzJ$4QoBH^V5Jx?oZ?aEy(n0vCdKMz*5MG#=I{PP z>%4=xK~yu=XLGJ;B6E~3PMZk5Jiup@h=>u;ru1}oMLwNYJf*Z^!j(h3Fhm0YR|`pM zwMGri6LgUIV32}oV=Lk ziMQGKF-a->R#9GIo{+8IzHV`}n1Kk=89DSCd{?S}@iZ@=EDECd^%W(P`{SP>gS+__ zM1tEGMk6j-88J!A7yIk)f}Ak4)T?4-0N6NOwqbXhC+#SMWNGbuvERZr2K$cSbueW8 z6iQnJg;H@2)%_NgnclNP#PL3YPfJa$+8`GiB`RwF-Vf3uAl|%p z9^mNhwca}9Hy!P;(t5mbci+KQ?<0*O0%c}bvw}j%Cv>;7D{i~D*{?-|exhyUa$7P- zh65YpU0@~sS5*T2)bn3Nn|g-3-qYv@E`0yjvxptawPe0;YjbL%lMLh^?rrfx6l4nm zgjTKQS?A3e-%Q z#nc)-dOUK)a@CGR!HLvPY^IR}dXY@$KGMv{Mutvjms%rqdp(YHCUhnu;DW&x=|*LI z_rV%@!-}`_;oNg!56gi`t34%T_aw`Y8AF3~HQEYxB1u7Aat!kLk-g#D^<9j5^(UGJ z#JyQ98G8TLnyk*pPrGsiyq#ilwqKRkiJHw`QztrBf0y0=x#^5d!kxJFGyy8ht9kh@ zN5eTjZqJn7E8;J6iKIJ09)iC8P|g&p^Vz=>!-Nd(1RZvyE6a@Eoi7U0D_{xwuSZgx zvX7HI`afp`OYJTaOtkZR%4HQG0jxb=5!_GaN`5rNv)g1s+W5bz`s@^(x3APcA1wXt zY>(4y+fcHZV`@#j~uaZl$oI}0F9` zjROm4YHbygfT*IXy@xI`aOpB zagrEtrNrJ^k#u80!1Do=U(SnQ0$|LY@{M0=;O_90!hIU&L`oL`5~MHw1+lfSljf(c z`U%vZu6y#f{H>BdDg3xM3YyJ>c#e4<-L?6+-$*l2rb@1s7H;@P@{?&xBieGNR!Y#v z4Mn2%u}q{d;S24rpj%p(jM&t|7pY-k|Jx3`;NZ#s*!R(B%pLhKU}Ml4nAF0f$v4+H zkolp6VUSCSJsa-}aSKu+#1g1XZ&;mAY$|GQ509l2T;qBPv?tS~qX@L4XD?%Bm?9ii zYZ@MyP^J*=_QT*xuvnIYk&NtLTNw~XW%5u2@<3*+wl(GE=6i`vkMPp>C%eb=3}Z?^ zJAUskP&cd7CYBvAihP|KPCBwDl7ja7mh_xm%rDzT4OSUxps0_!+Yac7fbt9rKAtN@wllAU9meX&?HGW0VJ#lGglLqG1E zfL^-p3f$gofEZsz6YW7jQai<0+W6n!n~%JC#A{qU9=!=TM|e0BU;YiUldw4HG8J&$d?h(=!_qoUW#~mtVnb-K`d614 zgJ0t#^aV^*WxBJl#8}iX@6o%Up7OoQ$k!pPH?af+E@5;TzW!ugg3Yd&ZhZEb>$ zdx^dY4-L4E#ro-alC_I;%k^iz&i=qeN`|hp#|zFMV@P_7x3F9A8QvM9!VU(D?)%1%shmf7Qrp^`?K<3*&P8B*o}F)#!~N^>v>3c`pPFERE7z z)f3-z+Mq^^zqP$t+~0~2sJ4FGe?I3y`Tdm%klCSUVPOgFZLdjFvr#@2e=N3k^#pKA zPfkY!q3}+>>-rdqm|S7BWU4*X<$f8k(ieV!@HQHsf57CwhuwY1B)FX;64Gzqe8viK z-Q#6P2yaYlqHuFcEBjDt5E2k5JzegO3yktH0)X+t^0(QNl};IS7_yk3upQDM!1=QB zq`RC(_DB|Qp!=y{vq$&dTt&nh@Ds>dsfe6Bh+c@r(L!0D>KC<6=lWtDvgh@ z-Yv^t4wAvzC6Zd7efc12Qc6YL0&WLci@*MnN2v`f^H_?Td7128ZsSF{oG%7_Ypz4r z9Hs`*QVg0-?^)&>MJjXBy=;F+1EHg-$mHo$ij^#>WO&|=hHey(4nv&3wbUXzFVHrA z$!Tvc9j8UUQ%~AkYy5gA!SxlLn6pstYnDE z7o5gjUj28%w03C}K$mduXI470@cet({d}p#4B*kHIT3LCr@t(&%w%3cB3F#=?RMnE z_dUP5ltswfwM(9CXO_qYxx!(i^-$YIwqTGpKp77{_vfDwPeX%R-?8~&DZi@`K3bX4z2CP{o@#l7I)z{`|HYi%z2KGI zcWUdWLBm$bFnLNj#(vl5j@0`T25FXkPVRXt!zcH-0wWxPzifV{ob0fml%p$QqxOf# zg@vT!vByKa_O;eqUDVU1wzM?4@`^!-`C|!#rUPT))P6z6liOM%=6qd%0#7I`k0zcS z#QYH1F(B1I%}D)Mv&md)1P|e|XE@503zSIOhL_E{)xNh0&Ay%z|*d zj)BkZ(fA)DzNaQ-BE|XQtyvNu7U}zFROBmg)MroT1ACFAmYtO6v$VIO6ipVwW&8fL zG={rSy3$GG>$GX-z|Oj>5->GE*+5U&fOh(B3CLPuY| z!`mxLUZQ8V63^I9?zc=3mc^_6_TQYW&U3VX;m5Hh_Sd{fXbA=G%WeX>Pg zR<5dLRDT*{QI8- zt#<>+sNUka^?L(z6P}>c_Df&1I_}rTv)lF8?`2E=wbk{a1#^~v*7#^>o`S3r_vdtJ z^HzlYm>dQ>g~Z8T_^3NnOUmfR3_9ElCrGO@A#PK4c8r6vY4@FrUh?x=)@cfs$eYjf zTjM?UAFV~hQqvR+W5!7`JdQM!>fivvk`eabGXiVRUs<{JXaPV<#hL2(ByTjV>e}!R z|KjJ|_a(14GWp?PXHzFh8E>9*KEX2ml__t(w_sn9^dQ?=wPbZbu*O9$vSX;*W!Oej zPRtvl^ZZ(ZZ)_ z?}sHXbZJ;GTm4yP2gppnCwFqJXaNF1D^$5Tc^g}knZcLS(%&b!O~CrNj&MfC)oDJ* zv&P%DuVDGyIIyos@UK{-kSilDL;K~R@@^?lSKe%FXdBNv#`j?8ht%WO#%62I*l%R| z_0}$;{h{%tpUS-q{AO z`(Ok@i(L(#r6-dh_PNvWh+E1wU1bmTbdvU=g8EQTTBt6;7iOQdVcaTOeR|3TkRYmSKIOxCG+Wg`Ac$%Sg?XHzb_uCYaYnlrpGIZ>r&9(I?9EH)wg2+2G{g) z;^zn$HOP9{j>M;ez_Wuy&|_?07p|7In8>@D zvp`rV!DO+68Gx71U9e7wx5av=Id=$3qDA1qPjPO6I5O$sAJFe=xxVK@C=-h2=vV3y zg0dH@S`e*8?8kV*bn4Y;LZhE4gR-)a5)VAB9-QnWE?+#E1E*X~;s& zj@H4r%VCDvIKoUc61J&1%Gb~q2SNem7Eab#84WR;H1K>?kK3wk?| z`osS;N#eJn&sx?yrk0C;s{Oi+`RQyX?`glTrZ4B?aZDb^|7jCe1nb}SUa?%8Q#jc4 zI;e8*RX4?jZyjth6-CVR~l#+r>L}+3)p2P}I_%%+@#&!bq(78Vduvl$bJ)#xL`5G$$pkc9jE{G*BfuM#3i^v3Z;y>Zhm1dbwP z@ygTZ?ttJh6pd7{crL^P34I4M2t14_1_}+VbokaR{g?FFvM1=l+y0x9UYf_{P~L`t|Vf z(Xnj_z0&EUP1hEWa=~iW`$mS#^h7}2VM$Mifh7L5p@+@&`VhX&6p5kx zeCM$7M}wflL<8}$vE<&d4O zOYy4mot-LI%Y-z!B>%IAONhaWWT=nu<#KhaR+4}F$r8!BA-j1|VKMrt>v_+%8Es)^ zz+q@k9+|y9e?Ux!u-VjS4X%EL^jjwdTA36?^oeH8i_Lr-?D91`oEiSFD4hYZY9>j|4hx92i+D)V-b>TWHx-vi@f0=fox;Jb6)&gG|iaH^bu! zrYm-dbozxEDIFHWm?;eF@#!NK>m;qlUlaAzh6+FV+>zm~EEO~sj*jt&P?^z+ffieD z9%lBpkQt6Y$Tf^lwY`(r3(b+nIT?qiKJ^X@cqw$kg^m(G#NI>lcx}ZZt2_JWLu-GF zwg@YgjYh;8vZI#c4#$%g%l3e$)*l~xS@COec%sP!GQ4slS+6F;GVUWu_Rc9kh8Rbt z4cDN*c|Ym;6U5T4NcTq)aP{gj?V5_-%!L*xWhiuL8h^li`-S#xOG+a2(TStGel9{t z$atyccl>SMtjzLfDxaL=Qo?g%dBmczEx^(od^ zJXn-KFBolKgYqSYmVA>GB*YVQ5oy}>@s1-th|DuBUF)3J0T(vKyAwlQKGe^BRH_~x zRvPW1^xs#yPa;dPj}poJGOXgue3op7?osfR=0)m=5~tfpoB}=uy#{Uhm{WV5CL2(n z-2_j)`3@I&bgAQNV`$ z5bXS)F8^D{10i%+jQ-{MB=gBm=e;R83_vpMsvt%not8zcwek2Tc+0ay6MTb4imJ#v|X`;ini1&}M@uLcpB3C+k;ZO|?Y0l;cE{ z5QAT}c@cO8=^ORO1@R>d9PC#=?h?X0f0(|D%EGU+m958{y@RuFL#XwN=&pEN7}pZf zJ5;Ob7%vmBacW-I)W!4tfF|bI*nVmC8=3+ZL~)j2Z_?kkZ@73%&G zlf!^MBLn_Hmg%A1wGzq>K7PTt_JUb~fb%r1bu2WTbj08kDd28HLTrHPHa1Ue-{KCT z1WOWUhX_kV4@<6gJ@se8E75`|J|TzMmr8Iyehg8mMC7!9qqYx?ZKKVOR|^J1i-cA8 zGJgRO5#cY&=W5N_8##8_;d;+EITl@x_+QzEMAx_vyfU4SHU_+eBTn)BUD>qsJ#t@~&L>Y(Q9p*RAHf4cPDF-4Mb0o3K*Ls0DF zNvr`8x1E+0I%sOJGe^+VX?wvZZbj1V#zi$Ht(d#Q$ZN|*C&qtm7c}iJ(CoauhjfBN zuou%A@9w-`93|b_-3{}JGwcZ6{@Lw%{9&95p_xJ>J+u1DcK<`^Q$|~h3UA>g`3Ycxv)=Ub%LhJVxM z`qFb>zP-1*lSCzt7*|XCtIhtVyosQ<53SQkLU zwgv?hB1SFsamS5T!IE_pp!29^3;lf6wYIe#1JI7U>)lL$4&bwe21Fhgru~=OwoRp= z0Due6NVvs)peuM79toKJzp=i`HPl-NLN zitK>@;**&n79LpB`D))!_*6JM7Z$i#E;hQe7xsMonF0W9u_=|d1LM8Ny8w{Y^7Uyy zT^OQfQVINe+KSMtKWo#}g#knq!}rnOF4i*S0KmGGLD1u2z$n^?Q@a$H)J|)0U5V}; zCDQjHNK%GWS`2WJKmnEWhWvg`_Yku>DJ&rQ7FGJ*QP_if3IqU6DYC+6i_UZ<57EC7 zgPNtz)ktLUA)YJQfrVp6%jdtQth2Ope#yp)TQ!EZLEXVCt5R>IG|M$)@Zq6s*;5%cbKF$r0gy?Q6qRwf7=<(t zQb!m`6Rtp$B!>|=WL~KqrjVCtk|m-bMI~P;R@4bn9Zp4o?|cswqM;aZw zElA8|1gV>stMUHR;qpX+XR_44%T-b>DQa>bBI$VQeNLY6EeXkur==b;P-6X!2)e6E zSQ*Jl?`1o{tVI1H!$p%M4Ly`+ombnUL7b1EzHtczEJZ*;k4s5FfmO2pebVGShJs6b z>tCnb)x)S=j70Sn1!H?W*>W^4>Ef;OY~E7N=D0h#9iXM~H$KbJ8iy3y7SoNa`}ug% zN@{PNo=Sq6qHf2@#@-k6wk#lwdS^BTIj#Qe4jsu%=i0#1^!H%#Pe(>?OG^cX%oWXq zK0pt{J~BDpa({26+uI}aQ<$syi#QNp=%5Ghj)O~ZBSoM^h2Ra z8q~l{Ida&7hYQEXFNz2EyydXVE~{|<8MO3#z8bd`k>TurL&i6KL!fAEX>{gzI%jg} zacH*9$L6o>fbJ;%Vy%R4!Nr7mX2 zP3gQ0cD9-z4Z&BW0VZwg{w%4{Ck*dirFnYF=vJu!a1!!0EWYh`X(xoXSrtCwl2xCv z*uN~Fe984D7XvC~&@epNS>bDz{=_GLz4({?^u!+m9;r4oG|ZKX`aNX+Hj_G>Q}MRB zeb20k(BAk}^`6zp?=-6JocV2Q8{HRrJ|@goq<1BvGzuXdEv%(3DZrwBVg!OlF{Da;P8_Qs>eqX1yR zbo=>nqtx(m`*7z>JxQ3IH*mRuDja;tvITF|y&I*!Jp7{GLAqXLYt+_jbri6!b8}!V z2O_syP;`iVD%Y6ShuWev;HCOQEafMa}We2i#Af~JB*v(tdH>Z=rf&xzkd5u`Wau|!^e~Vs8Huy2( zKX~fs_jf=sooI-#L9f*r-T&28Onc50jpa54;Tqg%x;cli7158$E6J5{SAr!6*mJ1lR!iAh<=u1p^Ty;LrHl-AS-1;-$Gp6%&|fso77)69s#OXn{om$bS1v~ zl9t-_PX=uyd{KJ~RU0`Q*(fx#_hv4nG;O3jazn{szdv>V-HD{P$EvQ&NQigKLwwh) z=~T4&a|tpu42sc`n>!RM$;&d87w(ofRP*xC(UtYfu!@D@|8(J);c>ga%4=0t7j3 zy$ul~!2N~wIlN5Nd4*~tvGTp?Bd9As@yL%?cc*{n#AF0iCIM|`rdq!4z{ZVPEsNNV zK)XJhP3NFN(|e{@{Wf||IXdl5-_)M~nspwpjdg!rdcSQA00Naxo}VCy+Z%6?4*+1_ z{4i79$QDB)KbH3%A}+9`v3Z}Ilz@ON+SkQD1abRqmBWExa&7^WfyJq~b^+gUIjGLY z*BQy4?+QX{CQyL2g5U1pp*oqNzPSaIsD;UsI{JFeO-&g;E-)E;S~3tr@b(CS1pr!q z$D!3r^$dkFHt1hORzk$QFF|b`25>;&(}dP1HoMMv&UdGgrkj^Pbgo7Zm70!H!0rNi z6cL}pX*3lhG_ZZ2+4iaRP4HQM3;>>N8I02Ty!y9}Z}~-Jw9?;JbIovD>*`4Xz<=p- zskdrd^Gpa`N$*B-HTDUfhav>U&p6>tWRw+9!t%3DI-5Mn6|SdbIP>~Zaxd6ng&zI-zgc}0Q zf&kE{5a2DDd6};S0RKoZ+sq$7mac9nQse>a+0Mt@ei*n*FfhR2fbff$b>@Kg(>q_m z&aT027tk$0nJR=5IVF8K@*(==(})Zw!fJg&Wh;&V?|$sXVCjhwfTg>1fB!6>zpSH8wY(3S81nRj8C5D7Y|Z{j%GoG z+L>)vKmIp~0t&2jKO!z*JfH=OfiVkJlys=OE=c-O5-oUquX}ds4=?CuZktweP>I}?)y=5-7fq`gTUvy#M>%Zjp1Aj;HbzD|KO(fshW0FZBi;=t zpB5lehS-O*V@Pr*^0vGA{|NnzbPN^3T1Vv8mA`h~J%(6Ssm8p)a!=MB{hNDCPh~b% zN>zJY3Aup(F^cKsGa%-HR5!I?rr7M^ZG5d zZsVxMk_kDo78=Hx0WQ5*H26)o313uo-;k%nx`5xywXDa|d890&w{hFu8RNf2t#1rG z55$Fcx%7ej>mam5Fw^CGJhxg&paJ{7{Zyz!4<{EZI1vWIcr&jh{4o;xxhf$K4o;F< zx2&gvT235DO9mC{I{h#VR2U+Z?dSUcsdcsZu1K5XiMgG4|~8n zB)a3mIVjH*)XE{d?z~xF<9~R5lt%M5o({Xi@#@IKj);86Cj<2*m$1TDvvuF?y5s{9 zh^u{Dv~gWSlG!2kx&X!-vjZR|5>CVW6!gy;NX?9OViT&PWjWR6_jb8l@ryTBexjo% zezW9t|n1@Zb$Z#y|0BWW}civ?DMnEF%)@mCgYKmZ2VwBrZp z9j2*!6SF%ti_DBLvwNA7K(tkeY`oP(i^ouU%1t@(YR`Pm-Sh8sSns$#Sj3L{asE^b z3JAF>{fEW5sOPBpdsUE-_?}$bY`p4r=#tM6!+Db}7p7YvKI4)1@dhz*@x09*RK3qv z9Rb^&tcu|M0Lw9m`|AUKl3rw5AnP~nwWx=4p`y}?-bFSR3Lgoqr;+;he~Fg#NMKwN zLl?o*oh7&SG=YFsv)CdrAG8k1S40zq;RshuW@^nNCVl46t6+xkA}t~m%MjKo{BnyA zc@}%R82$Kjnz$c7Qm@mNh~rZjA2YaMVb0jrdW(QmZB-p~yLTgLI`OG;%ekqT4&^+c z?io`Fhq18Y*8ai2j)QW_?Z49} zcGXz9KYuh-Vq`4YD{m-e6@aLjCNL!h3%%*;y6D!g4?_dC(?*KQt*PqPk|47}W)=mx z);~t70eHJ=|D^C-)i0ys|0tOicoK0kmo6Mci<2G++2|`yn;66mW%PuqIn)hCLD#Pu z#)JQ&oh>wNfQv#@kdj5?E8jIXD}yi~7?p0_vJkKXuc_kl&(gm%xpVF9(A~N^iFG5# zMs;BO42D#qXSL znaSj*qZjFX!6z3Cc|i2D>eCFmvUa-%QIh=TLb@$YbY>$&gz_C$eIK4Uu*m+TX_~>3 zdszt+x=e^aZ`HiV^d_$XnS@+BqRdHRl1eW*P3S_e)6#X`SkQ%y{?=Q9_x|nIwC}Hc zUe=OECH2gjg$A-ZAeTfj$|;Y(nUcg5*Sk}&a9NBN0s(+zt;yr+0g>#y9ptIZ4EHP- z8!LmdtD{xt&P6WD9y;3aOeJo~baNAL<;(G9A#odtnmjPoRvIm!e$l#E@b+@iZzCY! zrNh~W`?YvXx4~y_T8b)BPH_og{qb^4wq^ZK>v<0xoL3$uHGNy-m-C-REgQ{_3ngYT zzW0h|2JYjR=R|~#AME`LSUX@Bk4DlmmM@?Fu2n=WHTfEz)qS$6J7<~U`6?)uqcLIl zq%&J-HlSo6Gg5fO`%+c#J?4N2r@v2q&0GX0Q{JSz2bsTLXf`jM5D+v~YKT8w>y~pPK*0QN*y4&;rnJ zVO?aUOJVVl_g@li?R@RZpy8ri6$Ki2?A39ULa{wL8{1VoXx>?ysI&YGe1qy_$h!8) z3@Erc&awmo(b_!6_sX|}1*BnszzvRyR?h&K(=BF%&QsG&$l;HoSU~}3KxNEqB7pa6 zaUKT%eEo6fd)$LsI=Wy$R{#i^P_@6BxH?JjFei2IELFG@=wclX?5cs%p0AE%6@Rj7 zaRG&b!AWIH!JMa@*uWIU{Wv85n)WS>REg*0eN&27<%28gIh%KP#fG0h?Uy8Jm1M`> zK(yBZpHNsTAbeUeDDO|DsT7U6EtoviM`fulGdJH62@Q3|a7?w3Q;lmjO;P&+~$~o7b$Ox*%Pgv?%?AI7FoF; zKh}j$vQ0R+$J#s&Wn_NvVKTllKy&?Zp}Tl4N6aqlTlfFrfW(t#(;J(K8aP7gw9P0HeYv@oNR129^VI|9yeGGmWPD`i> zL!FBw8@zhLy6IeD8*d-%$m%z56w`Ng|HqDwj6`bH;t%Ym-Sm;LQqJ%Sc|)=Y_49|? zc`f}Kx?%!%Flnb36CFNG#n%YNj`PipC$<5eyBAH9iE3h`(tE} zNcdcDb#Hyf2hDj?PMxe{!8mk><@kRUh{y>>OZOIWwiAOOt@+8Y1bwKd|sm$xL$#zMw-3%w$kIA$UZyUADiRTEA#K)?!TVhu=J(GyS(@k%F zgJs&A4wr=~wnEd7g`4b0JXlRp3QZfCu< zlN8PF4iFigeLO2y^L#^VZjD%AA!Z(7K_`BS%*-6-C=^#$3|cKwcJg8A4z8;jHlBm6 zkC}({@Koor%zQnRa)F+6JL9u3X<;__b=E((y;8$spdl$luvA6y>|$u#fX}+K5Al%O z-6-h!*LWnqGNVjfIQ8sKCREA(N<8IuWs4W~#~Y0uZYPhLJHh;W-MKMaS`))(TI{N- zD)y8U4>xBF&(Q-1>X@iZak zSlu%Ch$ZuW_B^pMm70(|SXR@@zCsR}c)214F*<6^QJFFkf)X4km5?F{u`4xn*0FK0uco%nAMr;?SMK?dizkH4;#+~Rd|MIQI`7nk(8Yx&^m*nSZmwdFV!yo4Jy>0O{ zvLtc14mZe4j6_R9J{Vf8b5HwC9f2j$g3G}Hra*!FkjPN~?y{z);O=Nnk203rs^I3F z+a^N0^L;NP_ycCB23&kK4KV&9LT8faQWvRa!?n`7St{9`-VR{XBIDvxg|O!I2FFSi z{erfz$5rfR#|&kFwy6X9U5dn%=-@sim0;^{Gt%zZz~#kPlB-&GI&417aG}Yrlnn2! z7k0P@XOp|-Tu2K*)gJ0q@fpHNg(fO7NEgbd4X0&IrI8})t`pdxvpx7xPccW76^~CY z{uOq5Sa7yaIr}dy!1Pc0A6-uY?PVyYYQJZ4miyep!Vy8oPvd)^*`)pbJRrV~j^}B! zg2Yu-|6Y)|8WdgJw%07Xl`(_`_#=PbrP>K$8xG-yXfKWao_$QxC%(v3j?rxD`mybt zUWIEg!dO#i+U#x)A(YQ8Q?nUTQj!@PzCOek_{0qj+S~$xvwok1)C`5TeOEXk{$N|m zBph(2kT6eq0-vXme;0WwOg_5-L&a)idwpGQWi(+snTA20(DJ_k6hZ60PsdK3I)sP0 zC>XA-hRVEi=PxRPh7Ru&1cD>bOchDHPvmy*H!8ZlhsD&Cdg(-FUOgkh&O2>y3^>HArYMnI-*pn9$Nh7$)9$;ynOY49)B>RW4MdP z?GL9ZfpxIuE60TCP*9x42WP{MeHh_qZd*-un|Ny}UL6y(Elf^e0Q}464g0Zlz;&*n z`0CpC-pX(vxNr4K@Yk%V?8A%c+|N5!e!bT%V$}LgpY{q=^Uo>!!rmqSJ@Dq2qdEu4 zYRhv!d1tBCrE`xi?f57pN{GrkB)n_S@Boj-^6YOnetG1=RkgRTt4fZ5G&R&z>hQp^ zQx`n_u!j@?pejFk<%*ZQ$7~+bJ4hyR*yZ#$4!-j04~svFif->=Hq`(0%}0AKqqw;4 zQo-C{wSs|h@7uqp4CuvU+h6~gwF5(Z27j*<=@;F;Rgj*&aHUs zL(dMqB0_{?GXa@<`>5U>g1lQASU9dS4AZ__bl-8~i1p9B+k^$9o^U=JT@4vJ>A~yi zQD6UZxr6KFF+=-wi|+YnEaXrduWzy>YWs)i=BoXxY`EYE1}EA*TQ{9b$dC={{g?I! z0RUhZjYqrC@W#5d)t`O0{=KKw_LCc<@2vrmT09LUw;4qBr=t+f3T;!qS*yu znOk5`fJP++0F1EG#c$v}LszVL(gisgJsF8qN&yh4H6B5Mfogg4(a^=sCoqtzY~hb+kSpd zs_5LMi)apkw$2#fZXpKih5g?i`7N(qkYAmY`5Sseh}DAKXV1HDKz|_)^GT8qr3np z1=8B+NGTUIYJYu$!e~&Le z`!u`0^)ZzKNM*9t*qXEHXo@Cu(5(AovCYtEH}xRpxQSDPJ!FXo*O_iQ4KM}7NTkx% z6nlCrQ#%Ea%M@)~%J1D+hLK3+AQS$t_@DllD-a_^LS0rWM}^rL-!Gl5tWFOJ^sB9{ z7g^EDyut5Cqm=0DioRI4Ni}fBtSND8E`INbY59w{z#~ctgXg@ovl2FcBau3GvJ%25B4gtEM+M*fKrLmg7fZYE*b z(!6Zh*<+LtzE6ab|0T@}rBvhL)xJkxvw>oa6dLs7n*WmGd6O&I4f*Of-P55FP7vaISgxz3%In8Xiv-*8sw_tH=;NehyWl}spN8NlhtehnUj&L zEm1=f36$lf{kWsRF>O*}mAc)p=`x@tH`=TROBrkGZ^yHfB?7s(x&%c=#tsVbP_}g+ zIlFd(oc$8KdIj)0ns(6#@>C5xvkfpy3U zl6ZLgwd}RMo|cmUF`8xf&3a+N(9TGZ;DM2;0s=J9w(U=$P)xq>zGnAQB9-a&`rGz+ zV2lzn3+pP&%5#!a4{n$^dXR^wm)UIQFQ2Qqrl#i04I8R-X2z|H$PEBNhKSSqw&&@X zq{H7OAG9*WTv(vBpyapScr&c$m}h2BR5JADL(~OcR`h$h6q*YNmAiz@fBxy`UjAtN z;j@F~PG1tlc=-f&j_BB2K)Q7DcUL8+rB_*yuhh0pA5n|0iPg9$n(_;(s%u=jjto&k zF%g)|1yavAf51{uyZc0RY%gzBKSnl+G0p1%jHuvH21)??282X(>xz6j4Nw-a{Y(k`Mw3ke=MOZRYpK?%uoiCc%LE zdja)OioXx@pI%^6LI{@hcDFASIe+{9;)-K5NLWm+u0G8&h&Nze(W)!i! z_6$I({zn7=$B)*rNDfQFh6anxy|U(0i?$RdfDClr7TmOic9P(XjZFcBiK1YP{a}Is zAxelMOB}~v%DXDInc)o3b>N7c{s0I7Gpwup)V`m~P}be|jAbd{bIYQPFjmS-i%L&a zr*`WVXXB_Ml$REk)#9vJv#xINlkeTuEertS z+Gk{>CH}Bw=?|MPzrKH_x~Ns=um5PthT!-f{X2#0+bj$KR8fFaF+50PZmW20se0Z#7BjkbiKwHlrV=|a#*7}sb}ovB zbIFX!liv7t@}8p)c8LJ7YRShBPF`i3x9p3-*(vV&6VE+3x{Mq0$6JT>>uTZZqM^ijE8aETNE6h*43uChDbD!_|AiYTS(vKRd1Ywt4eO!?-eyBALD zGO$M$cGvFOxm&V?1%yR%H6+5o*@0{Ak3sZ?IwSBTHgp*Q;NhG%-8g%C!I6`xB18^zqy=SM};S z@T!zZOUZ#C#w+@))$NLzp;I`jALa-;Aby}R&KI#G0_ zxS~GyvOZxfqM+GfF}3II%Byyf_MQ49MsZGiO@7{?u(*u0q-d7W{PsPmq%^fR- zaL>-IyYh}Id`Rc+z54X-9qvB#;6wjT82;jaCytZAS|X!$Lx>*MhzsdD=*%@WBZO>d(JdS32B}B z_P?x0w@$$vs8RRzl_w4zE^&*p-;0(Ml-xeMLvjp*Tl-EGMX9T+lO*X+v=hp*yk^as zqM{;}WhF_<$;lZuY*1hz`f5 ztEgUp1RpE|PkcInpX)mDxOq1564!MG{~dx4)f}q`NsVKOrlzA7@r+wxs@4n=lz3iH zlX}#B-dVAy&dI;}uQ*mx6lLDLd4~=i3JVMC*RS7z0RvPGgb>nl{Kh3A8^0UBVFXh^ z=M=N9BN2MXi4g3Tw%f%%i8)u#6p(Xs3OPiWQj5l9SGY+Xf zxhworS2X#%Nf)|Q7|#>UJ=NLP4Q>0}#9P6G|6{(si+2ZVe%7O*Gjx*n&NtdK-c+R}hkzbZP^~(D~U?i(KI}uB8+LUEqWdSw!qb6ONdn!Nx z1eCJ!lTtv&UH6R%VW~m^fH15rN?&+Q@i6Jqk_`{aHz-17-SLp@KDXXF+Ujr7P)`EP zS7*{iPQLm6)Lgg#R21t@9*<6rwE_r&Ta;9w3re)5#hAg+B$F-y*#HeA07;@$SyEen zc-#HAjqKOA*MK1--}++7X&1ss4gN>SG~t?bsmX?lr{ET<_Y_tZm!Ii5^1i7bfAZ+4 zoJCV#eRRU><)9~tF_#UKE;(JC0z$xB18;ib*_^>QbkAr900ReJ5y3cKn!Ebj#n(RY zkM8G|>Y%mp;y&4>H76x7CXO;V@PZdXQ1_Vfc+cxG;yx~f#uj)0x4qs};JNML2!465 z^@3n1?DMZ$EA_y{Hi2ZJI$$L7>#s2rw>j&y*>!^gAWBGJXzJK|@9mz^j#3RkX~fmn z*%+bpbiV8vCan+(0B>ll7slC;uv^VW@68^r{nSUXZ)R~F!3`lwk@hduDxqp>F+E?o zj~z{WR7=Z7kv~U-DD~y2`{(*`M@T#V1WJAD)N1u|_xSqy_7|FRr__@y+xw77ZExK` z0Dv&ADJ?u& ztQV(2U4wi%`b4NxO0==tlp_L4Jk9Yv{P*P!23!c_1p@Ut0XOL{YF&RlwX`kLvV_xC z#(K7qMyt~o1@woS%{E;&08nGehG*YgJ>ks{M)XKlzu4CG8(or|kZ~CU=j@C|h^#2U zFd7_(qR5m2W*7tjgeZhiKq>?iA&R09%rFc>6o3*%Arxb*PPs%;6bdY(Hi0OLf)Lj7 zO%g>>2*QjSM@1BwP{3H_NEKNofEflO07{5Li0YdSKnWp=LNUWI2q=J}$bL$TFe8vMRs_QDj09VpQ%x6p0{=J=_%!KOl-iC`DMkqC`;$AcPSH+<$Al^W}=D|`N_2P>G~pM3Fh7{K}!Gd`TQ=(5|Nop}3Ih}gF*f9JW+i(Y*Dm7!fT zkka_+s}C&Q%uW4qRwsb6ymc?VIhBbW{Na=*13@m_zUZ+R=H33-Gh?p3oI~yfA3yi$ z;*#eVEgl}rLF2xO6W%ydpEPyO+es|0Jf8Rb(-Yz@AN%w}w}-HJ?Ke~2pT73GM_zm6 zhTaHHy#4&k8w%mAFFxuP$ro>W_l_5~Pk8&a8!zhwwC=OXPb~PM{^PAna{*2r+5X1l zH{Id=-+KMg$N)>l;UC65_|diZJ@L?(YZ!3N`|qS_^Y%TpWaae<7H}M$^4cpKk4L}z z-&Z<>2RBw0KmYiHDC7E9UwtGDVC{mBr_T6((D;`p+}yuS`M;{$y8xcuyL2w8DiYjo zHQ|!W=@i`VKPn#xfKZm>2qAd8_5fp6waYp?}0FmTg88r^FhSHu3%cPXB!R zCoewmhFu747vJl;haY|H&OodOrM5yF*FQ843W-QaNU(7j001$;VbSri7OOe|Gi+3J zEMYW=jsROod|X0AZ~y=R!d6>ELcBeY=Ty}wG$J-WfmO4$v6jH-n0O{CRDF=Q2FEAF z1=|8teLN^EDj~rgsK$9?J}N4%XxzhN5)uPd?hI#X7Zc|W2~!s)mb1kt#D@k4swIQNq7oA0ZEDsI z#Dz!3#0im{x->9+R7^aI4Ar;?g~i9khX-5rO=z1D41^Fuw~oG{Tc-{fW6(nwH~se8 zo;`aQ#Qf1E2~nirztElAMSEu_rlqGl9FFtGo$!elH^y8egcM1rsjhYivMo3?A|jMA z6g`K}NU5yIvP@W>V=<w)aSTS35LuQ8#T?J7db2D` z2s13hAOwmm%L>6P%Q6h2M3Q7ef#X<&5GArG6P9IJj46O3i?RZo#lj#UM3H3~0J9vc z?$ab$#th49+$C9|EYGtTQA!j^QYhkh4gsQ6QDm7ShGPxf8J1(2KRwOqA5}A&`_OCF zuHCe06USZ{VLytZc!DMWXuLS`qM#u{DdsHgV&mHxCKE8^gKJ&NT}lBMR(qN18)rG5 z1uaw=Va!`B`W0Y?wXm$GBxZT5_d(3^JgbK|BaC^*;#GJV*23tu0OD4r!HWbux@a(}Gm)Jj;2iL@aO7yF@W& zFwZpQPDmT_PcsIl`{hFQ6I2bs`l)k=}eV@kxs2|QG z^1lhtVm3~{1aN*VjE4ufNu|b5Zb&wVkg7);>S+ots8)#)oUKl8#|>4UjXOd}g<@$d z`bM*TH^xi;F0f+rn6Uqg?wt)v=3LMIP_qyQ=)9sy{T@IqVJWnTy3iCh0k!bkzodWE zxVO?Khy=|RMbI+1;P2OYp4{8eT->zp>f$K~g4^xpIPNT(0>(HnAb>PU#D*}EWJSfL z{{QceEXz)(({R#s&gUB@nRK=hmXwr~m6dfCq-u<@+vUnTSjh4=N_}iliXz6xM5d>w z5ki0WOzcl5Ns_oa;c-zgRwbUYl0|ElthzahTWka=8d6Jvy30$bpqGyISU6LCrKTW;mlKL2=2Dnq= z$p>_vn(<$%owq_ZbaRxJ;ha)g5?yXLFnoa3!eHzRi)qrOE+^;y;HloY?c}8~@(A|H0Q@ygN)=I!xg(>D&loR8UZ` z>W3c`LO?&O9z1w(e0+S{TsoTi;UY?@;&y#M`;*fl-9CQr)wD1k;Ewo!$3FaS$>tkx z9?>}v%zc$f=d~3(b?Q|9!F-PmSC-}6+}!y1__o>Jrhd495VAKEuGw5Z=wDBzg=sz% zH$3oi&b5^hF$}adUuu&sG+o8ufzVq0z75ERrfMM9@%63AH7spF4aKOYD(OEc^}&K~0tWBT(RkbQ+qVa_nI`%D>&x9+gCF)hZQ5Uh z+28b0Xsfc}`7(SU&jf~!x@~O7a7>5-5b^Y*cd(MHVEaniS}294SPBSyu1zcj6HB2@ zlb;P&`-DL$$yUq+g#-ftLYM;BBHOVnxD-(a;99q*YJ#QU6_!?FDR_|$nqnzHvsemn zRxAbol1;D_kPk${d0{C~0DKW)DVXbqK{^nn6hacZ=R~-+?#%Oyv)vmvxnziq?#%h@ z6Iw;GEV%_i@mlUgK@_zsN+eMbM9uk(D6$|3lB|WmE3zaAqW&P2B|#8W4`)QEA_{^i z=?@Y`5CmCPu}MLZMYka6DYJ8rnBw1F+qoPQHAjmR72mldDQrkuWfU39j zjgKUWf*=xYC=*c>L`l}SiHab&C0S9`O~t3bL=r_&l(dZ#A(Cilwk*2^x1){x|zZW+0G_FI!aT~=Os=I41+CVu{1M9QF>|K8&qPB68J(Y0jylL-}c0w`vNgb?~=<;+|DKJwiKzXC#tI<~ENZP>_h zKOZOogb-=`{PlZATzg*uLI}ah{GT7V`yUTK`=JXVgp?yY7LL4j^w+C5%M>BxUi8U? z;X`g(cSc4CA;XBcRhDfAqYWb*@1^|yYAKhe$z-0La=V(M>kw|!)M>`280lt zeCNf7Zn)*4{WSstQu5oBK|{xUyIo~iKW*~;L$AE$073|%GetX|{^uixevJDpy0$|vIqyITU;uo*}YRtU%10$ll4;wq~;qeI; zN}B=xYe6(L2|}R}?NZazLU;@SfSHh}gtTN!0LK9UX1KV-RGy7i0|J6VB9c?n+J)Hw z01yrgjY&%tgRJTq3yz3MOiSa`3(gXhn4H2yMX8Oj1cs)irG^Iws^|%!5pn4m#HOMr zU~6oAvJe`}Apii5wf1US($b?sg4O9iEFv~NBQ03t&bNz6N+A(E!vFwg z__(BW937$dH#jURB{elFBv5&3>nNp<3kW*Qf5oTBhtLP01Av#AQ%Zds@ zg%Kh|kyWrPi~*>kD1@lk4SLHEVptWQL6K$R;jZ^r{D_N)m(+r!F>LECnw|MgwEhiZZGIX;=!Zfjd&`^k69% zTZS>q>l_FGqxDzEQs6j`%@$(@V*{1~qax7(B^U6KYLgU@XY0oWq*OIM`_q>WguyrV zALu!PDg1w7DPU+3O97n&mIC@8Vkw}ugr#sE%LSz#|7`@6D2mkl4uU9@5ORU!H)5L; zY=2AwU2!-^Fa;A!;oP`ikPC+@7;eG6dd-hAWrBhNiwp9tK@pVr>#-ciH#o&3$I39n zF)VMhpwN(z3rjXkGU=R&!Awzee(_f!C2u~_dJJLbCF@E@nWB#9!+`ohT)umqy*>wZ`>_2Hfw z(TT|^ilVgfuHlx<4riGsOxPZi{MHR!LeQvDqn;Z#^85E5sybc4a>!$@4URw?&e$}{ z001BWNklis7q@|cJ$t0rz!D!9v+ppiO z^t6Ybo|Jpjv(fPx2qDgbX1)3}b0%-l6_?Ah?B^$K6p1!vj_}8BQ#)C6c*{5Ic5$55 zV~oa_WjUr@a>t=p^yaY%Q)LpgwBw+ZVvH+Jls-J+rSz-DMaHM?`e7zlb1*kI*P~#l z>x`l({rdGwO-)r4g%FaMm>3xu*>;9j^RiLCWx<4xmRkdC+NlO>W$h<^+_Zb}-IG6k zvi#*Qrw`4Hr0S`riNRx1>x87VwDi00 zzN@IH@PLJSZmGby!-fsJ?6S*vo^RrN@;@frY?r9&(4@ixR~Eec-}!^bJvt;al2T$K zx0%#>@t~BZq@;`_Xt|Zz2B=cY_mNv?*1BS zOR??hjH#u?^B)3Mt9A6~(S7^&1pq=wLPEl*QKQn+(@_iCc+UXw4Y&81#EpOV>4F|6 z)?BqnLkvLP?3OJN+q_(8q-_6T=}EBN+dr4V80mP1t&|Jh#ncef?d_CtiPAyak;izU zqgI1A!=R!68oax&Z?E?8L5;_521`K;?o~_raMbEEa5S_9e6yy3w@F~AlL7)C?%sW~ zZ+|Ij+Fzt4a`+3Aet8(Ef$m_OO_~{Y-t3Nk!^{8UHQ97fLj7E9jUL=L-gsk7bo9yc z@++^rGA1U*J0UdNYdy@q#ZGxpI+}Wdp5+J|0ri~SojqAXvph8fw^IeHe%u(}>E`xP zK^S>nS8G4t*|8MhBE?cLaBoXk3L10@l4>h9?c5(6m)WaJn!b=B1aQ1y_r8Ng4w*?v z%k15wiv@c<>z#F{ckkX^QCZIgMRn=kt9^VJrPNVhnZI|>@zb@6KFl!7W#;zm+9A1M z*OuZFCmY-f0$})n^p0I~vs0K;`xb5}0E9T+Y6}k8x%IaOrvNzM%4>(k*#fCT%JVj# z3P_hK_Lo&Q5DI{pnAEJET{{O`FrgG9ba?CfLlw1dQ33!!IILY__uf6DgLpMDD#(uf zeftg zVg!g%A_#&)05jNwdjNnL1_4k>5JXAF41*9NiY&MVU>KddAc!*7lO_wITUIEeK1LO{ zOQ3)li~&HFM8V6QN}?djp8it7?Uo5uW13X%RBOv$W&Kl8j@55>;Mc`ZO?YvC71MXv z?fTWlwsyQXyIk|jG%;UWDxs+wiZ$%9i~fBDz^Qw&lL@7c8U+qD5{ z{j=h16^FJ?`C`6P2FdMgXlQ7tuWxj?BI1)%V#8;>^2E|3LTmu7t*b9D&i{7#DjeOR zy{&HDwnGh#_NwxtWna%fjiYR|vASN!?4A>DwaD_xk0!nEj*a{F>$wfU6St$b>g1XQ zv$qyIa(i?Qu`mEI`^87s9d`wB(9qCOS5>ib-FLs`S9a~zDJ0N>8jnwX`;B?uZjczO zy{h#4#q)QZkT36@!%`)0{mPHNny=WxWw)cT`s9jP)AyZW1`NpMTN9#3n-Zav64`BE z{NXdb28>#_{TQW`Dnz@}dLo2SN~zTPdv3jM{NwLBD5X?7v~}LFAtPq4+#o8HQs=x69=&|Pb*n2xN-1sJ^YnfHxZ&0( zj!QD7bu0 zqn2#Rr<78q_T!iC8qjCdK1wO26^FMza@Y0aAAhUL;i80;7pxpUXxNAIR>_o7>YV$* zQA9MGFcMhJcb-UfQmF3glcx1?^2TxLZe8+dUJ^sqx;!~n1ct}zRrS3OxAM($c zJ0(#N1i@Zg@x|n)#y$CFS+zqH1VIpMEAqw;88~xC1ErE%5EMnBl%Cl!_s-{*6l_~D z_K8W`%Nk`#bh{dl?A`XSkpm}9TcdX4%{#7rXTh(MC<=lgiS8ZCXJ0#H*!)dLDJ9ci zykpSFyVn<+ky8z^7+#rc~LqaN76>o;+|ylqFGgJBxSC8{DJc++Ft8 zyl&k5<`h67lnss;GIC^cO0ufV!8y)p9xR23==khT*%1~MOM#7yNzH7ZV&ho=zzm<9 zmYJTGpa#u`ghzGA%8HFtK?#_k@Pv-p8KD8{u@M`cn4X=LuA&)O0z%U=GSiY{)ecx~ zky%-pQDMRA<|ZO0IlE(KsEVF|1C!D+I%Fj4SPFq@?XweNA{hh#C^RCrLv~h7xSEfh zi%U$)?2sDBVgRs&#CFQ=5N=a*a52$|=^Z<@S1(wrEhQ~8EjdnIC^&0qW_DIgM5wyC zh=@tb?vx$Q=|~Pq>6sbHRt5tA!&#CuGE)*X?1<2an9QuK*a(~NvDlxig{#PRfRL;4 z%$A*HxBhcn*J!$9*Ukn40I+!O+~mvezI{k;aDc@UV2kT9dcs407f)0I&@)GWSh`)l zW9-uvX3(fhp}5gO5oTDHVL9Gn%jnwspHGcHykX_xYEU=P z48yP-$MZbPSu#_Sqd3t4$dSM7%Qa^vO!;(BWHCgQ_czD2k#e5v@{L6hv8;2_cja zS(Zdml-0G4D3Tyq+MJy{e^$r^Gs1iBPBKW z4e9yux>MRbN+=;zQDjMyh%9b=@1bk&eWBE$FKUDkqDYcVDJ|K$^0ud5KTuZFgs1z> z+lM^(^#N_b$j%j?y?WdIlZsAj`HSsm^6wgY`K(<|s<(|Qr=NNHwK_`o{xE0klP~Wo zcTuXoa&n?@+XHvs_G|tbO6i+-T=&89Z5k7yVd=*chu!*2NtO8HM-vB)e?=PxglL_v zJb1^|-5;M>eq_z;dmnzLuwHN7nGM6bcAvWTwEA|=KBn0gr+kE1EiB6e&v~AwqdH!J zX0Fho1~jvY26O;GDPV@dIwS%h;|l-B*hqOQDa)A45ugdrC`7)pcEm@ve;-L zz}SZ)Z{Vl_CTJyD-mt8C5E3W_gfWMWbuySYaQEr2fjgxLVtP4LQpVk4b*BQKoKCUYAJzX zLB;ED9X^j@73-7+1jj%9!bi7W+kv&(PVZQ`5caqwQhTy+?fP9K{`pKol(m`BK@h@F zvv-{(wR0$d;+@7dI}5{d9HxTo1^^o?e>v&CFP>K@01%mkW=?+RozzHfV_ki_$OJ>O zRs;x8c#tJH*i}}{qy*HRJi2oJtQZ?Z-BrtG%?=)L^Bu#YLB|9*i@w3OWb*U1Tb=jE zL8!$m|B9Q2f48dEW-QpPucx&oTU{mm75)7KS~${8&H(mJU#xBHHNNhJ6&92Lczw^aZD8xVTm^KXqD)Q#1UYEaXc_3MU$F8%H^9vx_cLxCuw zTgCwv8vrkAI-En|qJpaJ*1bl7tMc(DzgBvIUzDW?nY_*~cE8`26$FJu~64yGI_|v8S}weZ$z>53iaw zcYOf>!U(Dg*34YA_ljF?v;jnRzxJBW^oviYS2zd)1R$-LGq>CwJ)m!jB#MLr&oRv| zRzgFy;c#6)j`AMnXlHK-;Kbqm5Zf^^j8i=d2*Lpt4gi2S*3A0ggIPcI8}aw#VC^BI zC?59*Bol12ltYMgag}-eUErV22KtcI9XiQ$>4WB>h*@a|i0KKDRc`-}jk@kr5$lq+uk z_t-&Hkuk&aJZD_lT92~Utmt_1Pxv6V0hlpO7Z`cIm*A+YtPx_8VpvK5Fak=cQdeE& zWnB(H%Q=j*SXofXbq~ zuC~S{%ARSM0t5zyMTQ60pQ(@oBBDa9e%>f*V-#7aK2seK85?ZD0MJlZ%h*B#IfN(` z+^*W%T2WS12Lh`tG%O^@!eZ4Ir}p$|WD5-L;0YHupo@E=xiuIUUHDR&1J3WKCPKQH{&kUyi=`*l@<*FfDq_GLCw@^uqIGl)%JL# z=}uzcaZ~f#Ej5iXJb&3x-y0eHvqM#PoW?qGr5i^@U4sknZbARZEls^cDOP-urhO z&Iziv<#j`M?sYYu+49TJn|JIzRc#N6PVC-yz@RGzMh9UH^3;?LlP-3`e)6u)EJSv% zoBQ6&Q>NPklZFf*5~Y+)eeH$+Ok3gBQ|9UOk4Yw7wA8$hy0f8T$%6GgMm{-t!fgxy zj2dMXZl1OL%PnJW92|$t%v&a1dh3R+_YfjBI+V!BNZovmqoacq(cWP9*$SFu(xtL) zc(fl|aKiN?dn{PB=!cF8y)vT94{liUqp%A=!YM^d-sha zA%EtzkA0_@yvI2P7V3Wnjy{t!@+;}X5xjs6$WT;oHW;v8 zyod}wb!zw`KK=FMu7lb%(_d}%Gk2+Nc~6COJ5_9Eio34*a8Wq`s7WFZ?%3gyQDj&u z2i_yfR+1>V8XN7R1{F+2!D)9mWkLXe62;}TJDhISO+gX`yS>pZ%IbiTMYrAVkn{%y zm!r|{Bme-2D6-RTce+$uZc1d)Znq1Pq_J>28yh_j$}Xqf?r^DF7ox~chutLz>h?tv z-S);tx1?YU0L1Nd+U-u6QUFRM!QN;WB?I?Hhk_6Q5F)!Ac8AMNHM5>%w>N4K7#erG zq&b@^ZkNOEa1nJ!MHHvQ?sN&N7lb6bwf>qTv5oJk^uR*usy+U~9YgyMx#^3=>y8{L zTrvGW!>+t+#LbW7H^{Az`PYj%=709mm3;;;JfdSMygP2#jSuZ8uAr1UYmPmB*EP3} zpQOfCu3I{71ny`!(c<#7*|!nhlUJnzL)cxU*KVN;i@SPIAAcxK%28^-Ba3UBrq@b@K~ z^C_j2)O_^P*#5o$zE{Ii*z)k$>&HF*R;7le@a^zH!#@04!%~>@!BYc!4_RL3#ZtKT z*2fEL>ItRwXO2E}>(GZ^m|CM@DZGEpkRfmXrC16koiDNeMk|DX5ET(Drn zqED85;S7q1894Hu8^?_46wGM*pjI4l==&PnE9q#oVuQ6YgE_tfleJscY5LO^i)?9M`Pk{TJy2Sj$s&54f= z*Uo|x(z|shkt#nXFfl#5i!D5WWdVR;t?fJJpo9eVy@$6;%<0-Sv0aE~6KWnDwN)Fg z?oUMkFn}V*BVO13smC z<5N*ZQM}yM{&Fm%Wnhst?g*(M6;$u9LKH$M#+YFkb1b&?^9}GgE+fsq5sdlOy=NP( zo8f$2ADehu`lz4A8tGXvcYU5~;$7)i&sm%zThFn@F8yAet?#etyxG>*4euw^KbOyE zGryrpm$Yn{WRgiHmV!wpos(=BoI9HOahPP%rM#!|Ng&}3CM02Eha?XjZ;hfg%7XLd|YjtdF2s2C5(1XD2S5+K%Z zD}@ju1b`}sxBc*+cc$i7LsC>g$D^$`rK4|X;sS7T`;Q0e_}lNfqjPFp zSZG*!w;_*@yWzyn207ywlBCVE zN%e5_WoLv!pn4TPO{0|hbEnOMF*L{B3%y{vwzc7PLp972ihwA#qg=>SR?0fF|40Rpm#7COFm3lJP z`97wjAp0e__j2^&mKb2Sn-OwjolS2VxoaNG&Gy%qyB;qNU|Pl7uxx19*MOXj#}~}| zvFq?rJ#)INw^nc1C~{Gq`sBblTB#`2BF^Xh%;`lb)ovmLlu&&;sG>Cx>fwkGrG!$f7o~)Pr!7YA00bx?jJ<+N zsiE0~QsgO0fg&x3o>8cpaMxxf(*W4EhOzqhnzSY4~l)yuS-{~FNjV~3=6c%uG*E0 zW^X@O*`Z4&kKjn&)@94TuYu5vgh)iilKnrsS$M+3v++C?x}-u>%}MJs*_?bxlIl|kakZz5_V*SG?rQ)0pps#~{m`Pxkf;xe;Bd0bWW^XFgx zVvC874G%`(+PG%Xij_MO`}GJxsG;)McPkd}KU$lfk<2r=vGU-InM<9lEjd0KBYEeB z?-non#n!QVOaOzV%AbE&`qQ@J#LP4s&$%0`RxF%#=%hQfLn@Eaq1_vnE??EaMWx4u zBLuAtuQKU>pl@iW-6SA5`Ja#fOF6Ro{;{{*ar?~^-~Kvz=)Eu9H(X0(0*1}V*;Wko zLrZx(exCmM^!yqD06=ye_-)y&Z&sGq*#SUy*R5JMd(pC=-2ecn_~5RuXU*KOuNVLT ziN_EA^ySP&#iwck0I0C-=S4GSEU5$lfV$I1mo1#TeARCf0zjndMBdC9bM_XN5()tF z{w?2s^~Kzyb_D=Hs93Y&n|X^?HBbrwj=Iy!=g(NTWv@s90FLBso;7pU)6f3)I|Bd!_UaSgEuFV~)kdczBLt0Ag|nv5 z+Oq#B0RWKpZC&%_XEO>K6#xLSYSY?9a~H0vaSH$-I%~dLIP?3Tw+aXV;K=^1b7s!m zly}_tzD#N()aDIc;qU9QC|JK3-H%R9w~m zvi?cI994v}qx(y$n4GSiB7y>B(Q#n!E*A>#**k{^diq51k>V2($=RJ!V}Qt&<%jZ$ z9368z$A$+ZA|B1(RaT9A4C)&S;H*1!;Ls6dZP&efHbY56P1)YO(&WtSl-OvD<KC@QVX9&mX=AOmt^L4JOv)6%tPmtc;QgvPu*yHQYl=Pn&A zh*p#yIZ{#)o!&V+Im!&GY}2yg$@6DSmIFH08X**640`sR)@Y8@7az1~A|GfW+}1yO z+vmE;O~0H%EywWsZ3O*N8G=t}yOu=~{5UN?+`-ZwSW zxxy&;Kkjkf^-I1+fr4+gO|P4;Z&BYdYDj6->KE|}qfCS6R#Hosozo`DF# ziGsY-V9V){%3+Eq079}XR-G!{v15-CoI0>)c4$Zl$EYZ}pn@%!;$hN7x^5Wk`ik?+ zTTeb(lsI_G)8oS|m?EUOYFEwq_??+Q*rF16p`xfVaKhVD?i`wnJzl4#V3>4qt{a-4 zI;lBvbjPked3(03-crzY-1XXlIF%1>TJrW+Ypx#u%>6eFODI)R000IxNklvn&neDwN6CzQLWmy0K zjDR9Q7LJjLD0pH~P0=vvVwDZm($u`YiNTmfvLef>5CNh52PQE94`@vEbobhZ&{yn?SH2~ESs;J;ISVX`M@0N8K|b6)UGnWO_{6mvOPU70 z3t2WOLcBGqV{CZYu@iOGE^V%JR~8;Snb@r_ujwiN`i3C}f*MvP_%Q z1#hsS$8ANsQ0Hr;0hI)5`$Zz@e6+RCcP*qIl?oy6lb({)gX@62!A71djiK6Ugj5R;q~ z7HE~6H7gg*-j-jPnUl#QII@51(q$`aAT%Q(3V~R%f9;%QTf*WKB13GLx;L(xxAMn) z6-%M^WWlm!OAj1t$jVl+6!y%S_Zsb?o86QdqaOI5{&dP{mSMF!NBkJGDb9 zk5Iwx4NI2&P|rrC$D3FR7s|Tfg}g-^Z?SN!_Q^1pJ>h2!e9nUJD^x56p<(s1Ig3}U*RT`{ zcFmtVXVbnC001hM9sK#LSxbse)lvYU;*Rx;XU$xyLL1bdDPF#K-nXm0SPHXeeZBAS zaTQA;Z|e`!zxw*9od5s`r`CSEVE&@j8kR!+=@koS{k(ObiluNgZ}aTgbG8@gSPE;u zoil%hhNV!tY1&uc96C`2008c7>z94?#W$w_0Ki^-^84lUSFF~s6zo-nvuDoUc0j{Y z*uQnn^l7sSH7ted-_|bvdhzNi4NIZ+`^B?=_-U&E002kww$7P7dvku7I+d7$(WaqN65n&+dYfa>Cj=Wao76(!s(aBWRg#9rB5iBPFF( z>AfyX2x5sMmKW!j*5Hm^vLkF(S#%!E+biJkuH8HGK+lvPD=I0EOzM!C98HN_Q*k)I z#F5pdV{}*$B4Sa&zKR;$bzsk60B8M~g2EzXjqH+}$x@}Uwmk3PiNuT!Nik6v%O{TJ z7oT)y_3ayD#URz?9Vm220Xe;MYyfUo!@;~fYgBUkv?LzWQ)NZPrIoQ69n<5&0i1;g z3aT2RbNAd(o^ezk-g&6DL+4Hjks(0E;)1*rr=_lgE(-;4*=q_53ket5xpM}OvD2y=Yppg)W*{3K#6U0ZpI}{O=mfE-jV$>#!7{ zMKlBdac^QNnDnQ~hDj!wy0}RunPkd_NhX=HVUkIvY?x${DH|r4WXgs~CYiEfl1Zj) xm}HVE8zz}#%7#fMnX+M$Nv3R=WRgh$@PBWqu0Wz-LZZ#? zeTxPFVn9MzK*@FaRNKh|V*uOR!K;}Z+ZXN}Yx}&6$*`q!bnUNi!wnoRjw``7y*_C7OT%wo zitcqBN&A0J9)!J$Em!$kmu}i=#y7wWuY@#p+98qpotj>sc0~$%%}Ty64fd@g`Pfry z6}u%DGVWxnb~H+e)cZ=;;NYN~!i~&J2dq>b{EJ=A_Wjm<=lLspLfen%xyVuHzbZt> zzjHfU?dFx1n=A>>vt2tOPR zMj@On+L)B{0p$Mlj1(c57-W1CAEkc$1k=1SC-S)V9Y**-hu7_4l`nE{&N7u1so0Q~ zerdq~F+`d-ROKxATeoB>F92$0v_zRb zI_sKJwk#=E+u^Du9XEr?%^t?zZ8$ZSk|(9bF4AA?#__(A2TO;At+7mxbmqIw*Y#TU zLzc_a>5NnUZ=0o@Y$zjL#+Z9CHx4F^^qK3gjh=kLv$QgZ+V+uHv>D%x;%U^c9odmD z)GU^pUbCHcTyanZ4^)we+TVf#Wqqqwr+C_o~?W3S-(#VDr+yxd+x8Jmn|PmQWc$JZD{Yn+aFO zm4zESW8k(dDYQrLa69!$L!lUY?9K@A&UJdRhq0K$1;UvrxuZK@&&bd=A>8|2A|{~o zQRcycF$@oWdUj(;&3xC>L#K~aslB3)48J(sGPoBNFbpqrv^hIF!(_7!)JZ~L8eQn0 zzqUgLAk4&v^nZtl^=<$|^*Jw7)NnJK}$ilc+wM5H9KsbiC==59%=baS`lrdjU zHz#ur`eH<~YIIjPTN`m(Sl<(k(%U_tAQ?e8%r5&Z*LQdDC-vmIc>4z@=gesa4CBrF z2WObGW}+QMvLoNt*VlQRd8zUXGRhsD?6_TNFbzF^zoD{Yx2`qLFd8#}m`Pu?IY*5z zS{k2S*y)K-RN3zZZ5^D`9LPTzrrp29xx;*D%$g%%B>l zYxk?X+2li5ktdzs0KY{Ypr>aJec|?Zb`%3g zRN^$^LZFcPPQ720_p!DPr;F6%=MMtc-QzxDA2_SeV%`43SXh<1?Z)^}+n*yW=B6@2CLkD? zoR0J827JT7NBo)+~8vpe&AU2ws%Xffm&ZM{0mrt39j6`D{XR54i zVtK08h_M`kgv0%;bdOEBr;JDiG&9w#57*iCpn;>pG=5_IqCg2nQEQ zV+;PPOs~CLtWfTJW#vyj&~QN9jL%o%D}s=p;KnSVFKv zo3UdeCXv3X77|hH3q&ag_LwCpm3I|gd!=~u_NXYOVD=wUfxfkE{400`fVfKU(8Fri zo2-3#*jkj4UCq;JJ$PLTk#zIl1oj7#HS~>L5r6A}B#0#w>O> zJj)w9XPr)U@3fX#^B4NsUL&GMOjI};6lC^vm$zfqPp&w2Gg@%74(@efYR+ApC&!;6 z@={I!Vuam|-X~G;U$@(tgA_sZe}={+J`HoB-p`G}_tW9lx3lMIA`nqniP{f_lE06{ zDmp~|Xzy*7@j2jvHijCiGR8`=6$X5~uLiwd!y$n~(V%7M7ZxZ~$?#?KgTtnmgdj{m zfe86rE(5Fal`kz1wdlca3JwW4mek*EYWNDO)`DEYBC{>{;8mp`f{6za6R+av$Ry#k zSm7sqZ9ko-HO5M_i{G2!>xo;lnZW zK=~PND@@NQIFBE;?Bg=ozbj`{vP@Dt<5bmD2D`pEOvEq>cFA#oRahjz$lBbs@a zx^60?%l9pLzuxaZPDh^|qwI;pi@9IX&%EJ4WUdbw` z!%4mIKH*R|Hz~*AoTkj4t*_LLj*dPI$diGrV^m5kG;@~JSS!Yg>?`uj0D!rrX~iA( zVgx$e$p};Bn6bU(uj&0^1G?(DH~#&f=d{5o*w_G%fDOa%*qSjya3!qxOY1{8lLHm= zB+woRt*@n`o2QNX>+3sjt8cqbFR9oQ)bo|FA%$NqOM)U9p^3x1Hv(n)6LG{T9!u92 zv#dAfr+LU)8dc5Avegv28)ke1X&FF3QFi^M%<6ZOfmfRG^-J3frH!kr7~iw~Vpd>q zaMoihXsGihWsauLYp7dOro&62whHTTvq_bnaQs7@c{UZI#X+`V6qwS2VlrYwmPL##z^M>(ii-kuTZSy2LL-( zV&jM>7fNotU;RHdt9DSB@xba0u}<#485l~{ z+W&lI9)i80u5vu}I0}ES(urI0rF`s-bV4XU@1D4k4{csZKzoFSR}@R}klDnkbS$@`pAu9$2?mm>=wDtsoi> z{_)!Bi9MaH;!pO0g$rfdzCY)qE>OqzD!FlTRQmJ%3z1Iy9ZPPum>d+%XP|F`)16Xi znY%AcHK*u_Tyo|JeDK4`TW2oO6%FK5G>acgr#2Q=bQMt}&;*v(n1NMH1W1D( z?#*maUou-;Uf$7OHqIh?Hbjhn_u+(yr+-0B5B2dmRDy;Mz=wv0*7d;;yseIDSrX&A zjgS60^#td|ZA~0NXnAyabaaHhjEt!(2?Qj2We{d$WOU@x?Z{?Yi^1K(xm;8|eR%>G z9@`bae(LttEEEi(-@HC*8^vGF(Ite)mGbJtzI^oHyE%;1r9$4@uIB z6sV3Qw)>*#hO;<$waQx>@I3Y@5vr%}4T9^Wt_z-R$fHuIOjc2GWUNdQ+}vc)C?IEM z4*GLaUU~I$;;_bdda>XwXK@X2l|6`BNUpq5;p6&t|fil9Csey(6Y=q~=IsqBe%7{kH z<>v18KLg*Wd)}D|Fe?v0H@QOJyqEu;kBgjG08W9T7Q~$UezDg2vNWdSa%|GuB@Z z+Ajb@05J>k5~cY~2A$Eh$B$!&=Bmhyr$=RDOwYx9^nCTDl3A9Z*PZss;iyT#D!+ss z4FWA0anLg5{mQ|eu>9I`*=_a`j>OE7Zxmy=v)7+Cz5ONCoZ-zxN3k;s%hD2gR8FXk z=jD&}K;81n%8K`m5sYD3$Ii*ln)OiniwX0D^xfUn;v3ah!(aVBZmw6=va1gG-%nrXdq9Cz22C9~a)#0+x3`HE60EholELi1 z$GpDe)TRz(%`rZ9w*6!tm>DtY#Sb?#;xb{kvFVI8`-7YNyfiU0u%H{v=npPN^Ic!h z08>-HFJ%fsu4)TiQH3*F?_W%LY{h%X&kudJ9!I{9t+(X))cn&r!YhIiWVwjxcZF_} zXP0@D!Y$%RsK;OTZ4V0zF=?&XR`$(#05T|B_2qY|s(h717h)+%5I zl^j-WZuThleJQ3QBSXtlz=a|kQ<@t9LHjgmPJBYFv=X=7QlUw>EDm_~A%Ngl>#nse z!jQ-GM#Rt6EfUg>!h+({R}{ZY5G+;<8SpNgo?}J3`sDZEZn9vt=Dv5%{8iebo)cop ziN6T~=t>+vHRrur)B-LzYHcnpkoGXsr_qQ3ew@(LY!HsmfEZxVC#0rb7E5a>cv;dc z%2r<(hJ*P_dqtASNC_O~xH8zqQsV+!Vp?QhoXmU0kxSdhuLos8^6$Ie=4450m>c8W z90LYq7Gb%NPW~Qv)Lg{z{A7bXOJ+EwEA#yuZMZEIkR?BnoYE2MyCH_E%hkvFAUsy z?N-dI6oc9C#qeY^@R`R$ieu%zY${XvQujR?s^;b?a>g)fu)y)nH6Vmw+(LLJ00=nc z1B(E$*g}<9q##>nQ=Z_X@RAT)CEIY8HA{>P5492ExQIwGUG0AH*i0komCCucR4lKR4`V5cpiFZX@uGc|PRqaStcx_%+ zR6@}-w@>*J%4FdXf3=OBirCHX*L^m3U<|Tla(}7JIhBp?>LUVkTw|X(9W91J{^5_7 zS(&SP5I!>qMbBAZwP<`mk9i#j2TLev%Q_nD*`ue!=B{*yI^I|364@rwC+tP34-9PT z(T3ZLe4_z#89wyo&aNKUrTZ##v?3F_AR1h5+g=i0z3^^_Wr)WipTS9>S>!e-z8{5% zcWh`Z8GKLj8HKw3{JRF>iu*%bySFrpQb#(g{q7JfSkU)!tF;W2fC+&r>L&&s0+exI zHWp!p_H9QX^M{nF?5|8Ha3#y-sIFL8j2Dk2MYH90shq;S&Y50C9N&@kW&Zu^*h)uU zb(KDtFk?alse$R7#}_kOoloj*M{p_nsT>^a=Q!EEj>WY&2^|mtKDY4x~c^~o!Yx#o2aU) zVp9eSAl%LTEDX#HOI6%qMqy?IL1{iWH@C9e|5J(?nj(VUSiGogvXkQ`mC?7GlEdpi z|M6qOyQGijQ%uh1PRj41bL(TeM-1B!%N0b2l9JvDJmvoL#q}7vR9K%~ai9vE@V?R} zgrEUEjv0~>52VGy!a))CCSl&tp^c#iXJv<_C_F25Y)d7k&qPcGcY^}70qLUgJXw-3y~4w z=Wi1Dzw`f}4KFEt!0z6jnTig@o!*-e?JhUL<8QPnqt9P@FS8r@s~a)gRF9J1-kYq@ zy}?AEMxi^Of))73f|^8MG@Nw|4=Uj+C?JI+?;AK`#*40Ubqx>OE{=Y7=ZBJ!DhX-f5Z3PyCoIUmrn) z0dVo~OC2yV{Og--pZ2bwU~q^lXQG^16T}+q?7d@3=NJK>vg4mOL_F=P;$(=ISC=sf z=<}w^s}jmzVkK$ak3x9-!m+50tVlOL!FrL4zzxT=OXTTY+2eDvUZbMlP~p2U@)?4V${C z0t=wxu%2+;-m`%^5#P`;=k^$2IxEl}9cA#U+2ME*vuF7?*tTvqPH5P###D2l739B5 zdPjFo#k)86z@HW)bzzT4n&0AN3(YKqXvi>CnQJ$H!Mx?ZeLY~GT)-_1f}wD7v_-L% z?XaT>w$S}FfN$LS)BER8j;BNE0^>rUGaZRa6cIBK)Wc0$(#?|sV+0JzX0a~#LGSXt z$O^*DmJdEkt|nh~&Bz=P2pOo9n|T}^>b7Lj={q1gR&lBQwlR+R_0QcTj6Q$Vmv%$X zPz<23y`}zyquyB>SXm}|Io2?tO5d1F)D1-{C5Q64t(H)nZ-L-XO^L@UYg@E76Fw?< zn2~PC_RZh>(zU2m^2H8?k-4f6EF9Lbpcsm}HtQcDMY)){|^8cH(U{>P0gL7t7HMW2=o(&T_PWo`Z+%c9aO}g`?b!;DI3FCCms(;5mscmuWPB~Vk_I3@ z)qw*ABh_jBs+okzNb{469Hpx%sk_=~7^~V->N^n>P^l5+7D#zONa^fUMVA~KYv$CN zlqjkP{hrooy>Itm8()$tb+^GxWg-g3GlT*bu$-JLi$zY!f3k0@MwbM;zJ4d)6$ zv>Mh@qi(ftU^qTBQK2pb0K!OD)w2;7&NMa+MUpINel>c^i|BrXRg!p6w)^783_z+lmJ=BhyTQf*|A3F8oy6}<80JK5|Z2Bvpufr7joX)< zi<>F`HN2%(*A~Sidc*ChDmVO=*#jtm!7)SOQQMLK_u0h&16wFj-}M`m+xoNk=kDMQ zrQNTeBz$$yrXzJI(0c(Y-KfmY9&dolsBEMK`}&vOZ!^V8JQwf3h5u!h4z8%%|8FYM z?*jX`_6uz9yOI3qaQq0|tKM2sa4>8YO?UwQUI3<@o!!6jacxc~jRwo5Mz;$e2tFQ3 z{oQ>PJ~?ghryh$lvY2&>D7)M?Tf?h7iB=hHqQ<@TQh(--C3mDe7->!sm12u~sJVD? zNZFh_)btW9MC?R*v1jNY=?yQ3U#&}E+4H=Dg7tRygOQF9{i@hl^y15jEzvi&s`nY^ zC;QOV)zy#?WXFC`>iJ%=JtHt%=hS9DXug_brF$pBh>f!TNVz;c9W(n_Xb(l!N1$C_ zBEK7zLaJc1VcN7$ADfUao8_pMKA@h!N$W^Z`x4eEpZ@r7fb2Tq(?e3rX2Y4q z#u~x>LIpcUah;8CTpWhf3AJjB(a1REB*x1IyXCuWmf1HR9v+d%-QC?vM(eCN?0foj zKJdV_wy1)T!qEl{Sr7`sA!|2B6Ip(508S=EpkTG-5>t@=)xef76s$^#($UC2eB0mM zyRQcqDy6FNB+75)RfY!@(N^i+NQ@IQo&!5jcD0X)!~w2<=fLRbYEnv@+v7QO&AW`IGd5Y`BIR1qk$ve-LK5{5;k`eiF}6Fw zxcq$v;7i|j%EqGEpIKzM-JjXv;E7|095Gm*5*aVPphp~kiiUq&ekicuiIXXuk$)nS zGfkHfV}AO%rlgOis3xq)nJ%NMCOowofGe$dfzHU1KXcT?!Z3g2h|wSD-T%uj`d`is zX-kuMA$B$HeCdvE+Yh50pURb8ZhEfEF`-P5chPExgXc6eA=4Ro;MXh$7v$Lb> zQ{=`LmLkuhTF+}smAIOfkuj_NY8(|72RRGM)+lJUUUid?6BI4ycm!ioMT>v?m4u3e zqvpzXR7!0xT=?`84;=9AoBdX25u*bFf~3(n1u;WiRTTq<{l;RQpomm_06G}y$B!Qo z6k6-M1(-i*>sLLw{|4sgYkk|FMKp9kpcxIU7868}l2SCJd&(0wHaAn3?<)v_#!A52 zFAyygH`O!H*C*K*ZVOFFn1=thn%ZxVfPnCQ!7wWn3yZosnb(c%qn_+DlItddP(Pct zq7I4=bRV5<%gGn??vB+^)4-8x;>Jr=sj5=~M|b?dO8CY!RM?=Z`=4#NUGEpq9lsEr zot|DTG#mL;YbB_&Q@w354S6kIqmRj`7FPM;Way50 z9NrzQ+miUCG^)WzuchKmXnywPiuyj`u$13U|D3YAdO9k7*iG@8cOK>H3DYAYX$z)+ z+dd4WtA|A=zmAPp;-6FXK$v)~fhFeeD2*}t{#k7&O3GiCWlP9ue(P?=v6Rc13LpQ= z(sF<@)S9EKqi&^u08sz9n?25xODvYDlXsB_H17v_Q9{B5@TYSZ2|YiXaRyf)6u=IB zW`-MXmFc%OSm9}3xMH4gg+X#odn_&a#qZpJ7UyoQ7mmtP7<=LCy3|%)m@>=qyRZ34x=Jj5tF&#mh8XGe{%J>mR6oN!-UdRs90+UUX`4v&I-*y9^u zU{&A5pTPY-^*G*|)bZ^myTc7*FieXKb~i=xxuTKV3~uW|vYzOIMPgybBm$mP^CjNx zblg9FulYL$pbDD0HnKr_X|kp?38 z2f}P%t6RShalzGjz|$v0-Ktc~bRBk%NGhjOuRiVRO@1Uh*TD zxU|a0kn>Eg66ay%Y^pYsiwg&!=2{RDESL48s^odyn7FzwR{TVAUuspp-t5xRX!v2n z9uOQ<)|}WADtd3e(ATKQmbx_yr7s}Rnd#LP>P56Rw^3+CN;BMnvrMkHUEsiXPW&T4 zwQ$}FoM}sE-_Pf%vVMAb?Qjr2My0_0}=X;J~O$El^in;$909RE&D7Q5p>AI6&$54_JV0kq(nqg z{8Sf588fNuBo4t{`n8B?qTF$I?yvb!&)*r!7VKNvrP>!tQwlDj&6qWgL0>Bj5ji5A z(>L0+h5nic$vA?YCW#QP_vC{*A7FJ}ic^58VlTP$W2m=n?(C;c+e!j`?bP|+Gmo|h z#HuZVqyT^X`Smxmc}ES{pSP>a{bI0mS`VfUC;0b=!-TJAo~b5jmX8HJEnQiX$u8K0 zOLpaReVvZXhIm!HE>%35dtOlx$ofj8sckZUVgqKwiX>($SS3oVj{ZKn&) z92)DA8Wej*csTRj(-{j1O7Y@G7qP+E^bW|4qepA9lf_r>KP>Apqz|64J#TNki6=QF zuA39LZBAR7T}I2t>Sh=7j7Qvbc<=HDxCFw@)(CyeHJITRiN&}xo|aRrDwu6XA{c(& zg2Vqx|MDN6FV~R9(X%Ao1COPZmc}w2itdYYcL_q_54n9*VXJU07ATJ1W1ubH1u+0miyCUN z8G`B$nvjR6#&W&u-T(-g%djDMyIP_tr%s%gEX7vlc>vArG(_+|Z&s_sOPQHTZM>J# z%J5(EN)ta0?xt(rgWY@>FGXPNQ^zB;Mr+o2>2Tl}C-J1;C?J(wOFn~zAtm$m0VrbV zVO7;>hoV*o&o79}jcHY_*M11RtgQWYNdw-{yzvsW{qB>a01-PyxKV zglSyVs^q^y7v|tU$Km0^KelMvJctu@qk$m+$`0i@I4dhXOY)d2o3<=8T_7zCZK@cq zBi9ZJC->XgfXpIa?{!HTDGK9onN}i+`>`6>XJNJCc$?N=us=$br>>Ljgqm2du9@?- zjy!iHp9+R~(zMH$J+_B!t)b`m27YXRAQgRs$pyNskTWUd)Gse{pclL$2fBG^^E=XtY+c&xU zZf0|sT-f3HdR4!Ia@+pt0}vxH`iGB0vdB`0Cwj2a zDNi()(~CDf91nU=s}SConc%@5o`3J48Syz;O_CxYnP(;(WH96VEx9@G z+y3YJVLm@>sM#`9No6*lN`!)5CGO?PdN#lC_2-18(M@0xH4A%lfp~aCXv9_E)=|{F@85aXFgxO=ABDh!CT~YkZInO(!-mpaM$S z400&(CDyyY@HAW^x5^Xw-*?5eOzoN9FASJVh+I2<(}j_%F$8KbT&UPWfttc`$ZDBT{SZ}+NFEe=DwL84f4fmy#OPOQ?8I{Tu-1q871Fr{cHd@?f608CM-5`7% zL*eh=!jt#e&m(P1D-$U&I>CjPBC0&FWm?RAl%44$0sAQC?N@;VrHVTcdUKWOsu>=_ zCq+GDVN=ww70v9U8zENPk@V-9jfNZXsntv7%Y8X1s9Q$1V|;{>P51 zj;0No-K}VUS}PSxm+aVWw9$ZFUiG6HGgj%NP?5&Mx?97{7g~PQ$gj&ps5s&>cuy{?T{t9lP6n9>@8rsgUPe5!i+%S;aEqGfz0ad)ffz-a1Ao&;OA&DwvMqNnPZJ1rK|IP|6cEl zb7#wokWU{RjuHg_hkj;IT!pj_P1aP;w6DKRn7cYV8eFw>O?@49vyo&o%KMF(g@uU< zO*@jFk%?*Bp&1JYPcj81<5Y7Y?R#DigPNs|s1yhf(^OfvG={cxPScaweLq}&rO`&S z*7p0&B+UP#aV zRP>jg0-Rrxt^#myHoM%Gwzxu5+J>z&F-j zJ5C}X&EonFnj}q(f#$M1b7(m>-f37C__k@IC-no^| zClv~3{tD-O<#JwJTB^6%$dKF4ZT6i^4J$Ry7+!X;8)&>xWB`>W{xh9+duoG1i(O`+ z`=&gj?4`-p6h-@w)_fTX$QLE5z_OXSR(I zvzqC_9AqxO?e^>K;Ne1ekBN>3FX(!|hJDwr)4x{XCr-$ct_?EbYhf^2b}Uy(<;x)r zFfcT%EeLPC&P-+#WF%Q0${zM+|kVI z2$x^F%D(%reA1%+mjCe07XpGJ9&;om9^&L&R~FvJ{Bz&}5d%zsfearTL+$fqjmYO@ z6WhVU#qFj+KEUTFsDhUy(;zI-@ZZ9C(wr;Kb$4(cnJ?FDv|j7D2oUdT^>)2Z`1;(rv^eE; zMcpd-a8Nx`y_tJM?1iLD#O&cb0nh)3>r?h(E!X?s5krNG3a^lprhAyKuAMLj*Ne739-8ZHKVoHWDG9M0pUcr&z+ff9gg)b*ZgY8xDXX@X_l_%4!+H zbdFgx0AVwLcZ96aP~6t9W_m2iUl4F@r)Dq^szfRb=1_w65%`+2_J^YV>9CHGTBMu7 z_7oG>(cmoqAyPpcShxw(V%ok<>PP3fuRL02&I$dysUE5_I>Ym?@C2G2+pgB8t-F*h z&3cAwv^UqOaS+5xJFPolt3Re>mZ+<+y0AeGsV@Vx;_T(U zZ*uL~im3euorzP6r32w%v@P^%Roi!gxlCoHxveZEYdi9_sV=LZ+TlBsP5C>dRgw%31YxDtQ0+Fq<@ zES7pymwE9&$14sf#~uzq3w-MQ27%Za;3Z&rGyz2gX*N=#>w3VCg zBf>jFQafdN607Py9^GvoU6bK+8XOWx-z?Qi9af8Z@_7-C9hh!d`Sw4z)@v=EJm;^6 z#2wOm*pGe0#2+gXA*5%x*CQ87y-Lian*=V0Xn(M<+|XF9iNG-;UbA9wr^}dFS-qMi zlW5X^hU1-CcSUi7%Y}Q}c_^~mxt#rXVhFD#%jo~7e0^a)be2%St+C%pH8*2l{6x8! zxSxQXA$gsYc(tqR_nJh1#Z2Oam1Z=-oG|}s1Y|w}#?WW+)xmO9#*jyu|71lRLuTUS ziJhwpvlIR6Q+tJfr4+9n`>-g98-BKhug|)j>IUsAlX2EX|K?e7c+d)xta|P_I`*)~ z`}Xm2Av(R|5Nz}N{$eVj9nCDp!$VVZ@qVe%nYftO&weZ-<|jkn^@I!S#Kne8Nn{rH z3cgzW$J61*_8=+S7qUJ|Co#G4X5YJiNH*)&CJB@P;JCl6$bnfJ;2p#vBaa~>uhuCk zD36g#RBswOjfr+->iM9SQsCGkNSaQ!(H{Gqv?oqRZ0eD;Mb57*WdCq{5<`SBP-NC! z7(oRofV&kYjzVtLQJ^OugAyIYC_g4+hmEdpHIirdhbQOkd z873m7lrGNBa2}wBindh3e{`=VRz@NNDxxi%j~l;LuUYBa3A8v7U(zwxR`^!e#xA(= z!70O+4)zE(Tq(>Ibh1}BHylyjSUTAI`&%a)shGuv2k!1}R$jeG*)LiT%S8|G~M zEZ4(VNa(+`U%vwwLNDh1o5-mqn~egBkUwtms}UsV%hPiR^*y`@w-5C$#ih;0=Z^93 z=pUdyB0E3~_DYK`Udz#uzT;a^K*S0aX7vlQ%9zeT_0LLM!Ot32*yC<@kXU_M4Mf1E z*U{oBe%(Pw5WA2ej#Y--Lm zS8!++_kLgjCO|`irOHt)WK(-s$~vt(x8w|j0v!RKT`Utpl`E)l86PfNr(7c-@Ft%D61Xw; ztS#8WCoHJ#of;%O^Gk6Y(?Mo-%GPH0Iz;5OB104b|aQrIRt67IP96B4B$YwF`=#m!H9&S0q#L^U*Kr6Lc zV7#SoVW^-sm9&l~@TOg}gjh&uiT9=E@|a_ z<6OI43JMD2(q=`ZnrTIJbXKi86w&y&q@?6h<4XJ5=`ZN9-{~xa*%%q8NVy_Y1qUT$ zfBo8rB+}DXFvuZJpMi239?k0`ujgG9vp2~3(1NwAr^m;|e-UZ_yq@c24Bl*y3>)Y+5jOUwO&0oiaBDdTC8sAOsXbWYK`-Ap4u{Wv?e@kuDtnEu z`CTgg8Ek>x4E~k)q_F)UCg(K}LE6`agZkryhy>*&UkVE9zrLnjNSy^Ecwt?(7N>_* zU;NeXBf+dv;jo~_^STaBUw$8;2*Ca5)`9hr6$?TeLhE`w}UZ;3aN*wpfqzCE=k^bh-Wtp!Gcv|%`-S7U$wls@P$ zY?-OY#U%&{a=kj|#&Ephj%*=AUxWtKSZlR=oz#P4n06gm8=-w+mZ~sIP_RLu;%IV#Dkc`m+>B!wUT>DccIP`5T$|&9J;2f0^qwBX2uhlV{>ka? z>TDu1oWxO4QGu^hyf`w?OZd;Zob@9W(YZJ|Yj`k6W8PZK^)=|5exs3G-rC+|xV_X? zVX6171tF#MRpXBT+_SV`x7@S)b*b&gXSH0%#7Zri&s3zrRVQLgVc6Y?`}0RxS=(zn z{%qx6RG-PkmX>sfogmD7NT5j1Y;S94rb^$67jko?taPb~gQbBf0q~LdBxNE?pBm&8 z0OvzlU!k(m+uu>sj0WH&t1WW6FR~TU2ms=i+V%eugB@6Dn1LufWmCNiMA9> zCl|_SU7IXPs@mT9u?R>NYLFK>y0uaZ!o-9@;js|FBbIn2n56vb? zCZ%Z1l|_{965_XLaTe}mn$g49gPsz&wUI(>FNxUcBK0T={F7l|96 z3w#Ie-~RWI@n%L0UMg%E@cAGEB8ZMHN~Zf`KN8)+>LypS>R)fq)+j}X^L@qSAp6z{ z*Z)<&yU%l<=iG6g``10sIrsd|we(Daq#%13OzSA@FboEyua{QP zM)xjjyf#A{mImaI>P02Z(Y-GFs5$x=$ou)EHxs44cj7sR(m74&WB3dPgI(8UgXuMs z&gd*b6vaP%O9n=*TzGFG3k{c68Qok&(jn+!pQ36D`*ll`=L+RcDBaz!D zwfEU$AZTQ{0=di6HP9zqy?2HL4CPKumc%rdm>c>F zxvCKY{w~W-uw66@3E#mzxp@#iJAaCUM+YmE1MtTQ!tT%O>T{o~WZWTt=Wl$-HFssm z?z9xapY7oGq^7{d$y%Xu<=CRq(Q4aG%MOL~>`itL8O8H%L*DsK0!QBfD?f&NO+SEgZUnK%lBIQo^Tg|9X#c z2vM?iyssl{Br&j3q!#Pd*%Xn}7PKHwJKc?BBsgdy`P4bacScAFd39be8Rui8g)B0n z03X!IQ#rLdj&+g|)|+byQ;NCD!qC~Ep9eMBRYEf$A|s_`U1tmhD>yirjC(ZjQ0y^{ zX{qFbFaHN_PWI8>_`QOLfW5KI)uN4{hE7A6)mLNSe4 zZPg+RyICTf?aTefXPLp|mzBLm@g}g+IKey#w1|j`sk=jG3%0;Rhprs&59K%#kyE0E{>!TqjJBbQrPEO;=H0v7yJI@?#9`iU$3QRyC5RXdzsfuo3 z7*;wl4e`jCjfv%ZeuLavez>W14wntROhj}kCD5Y$kwL+zFP_5xt9JzA5+Qz;&d`MX z&>v2xxJ$g8=ci{_zY$R*T>G0BP3dB9Oa|%B_Kq@T(#m4Uod;@;<)$@1$9^3tc)2xX zH@nz~P;RoXDy6#3@uuX|Z>le+BuJ(l)r0=Q#KBm+nktWMSG0ICbD9^N|E~eyfELtY zrs}Ty{OGq^Vqft}G_P2>uPndgP}GjQs-nxAonzPW$L_)q(um@G`cY$}rv+57$S!YC z#=-=+C!NMhG<%%uA@&n4-NylKD}8UkWSf!#jdHRN zbh34f{R$QqH8m)pRQRH-$67ra`&RJA^&SiB^IuaOC81T@JG(Y)$RX%&FRq1!VZK-o zSzYD7351oL;I8=MeXlilz`L$^X@lUV#w0=z>JC}%JrbinEOS9+?fd(${X=E77JRI@ zptABW4?gyyy`ZxE+~>fb2?Qc12Y*EWcA)=tFVc0fNAakQMjZw@P zoVl{O*|MBSab)TC0|OI>Yp@|L-=_!szIgy|{>nc<0}loCurnH>3%ereY<VE8+@xx#FO zdnAvD!lG6(_|Rjn)sK8?H-4g8NXN4?E02yirW2N;p?ZxIs&|7005Uds10ESdDfxg@ zYt!0>hT2k?)l^OpoLn_!DDJGl#dk%A)glVb1Vn-aMI>i}@~)wE@VB;IVvyy|(QG-I zztZwgS54nXNiI3%(=*-&vG+z^qnH;9`BI%{6ER`-+$B6}c{xyR!!4}Qx5D>A!U~#R zX;dGSkV6XI#0L~@3cf{cG08Z&?2>r0$-b^#6;x|0n4w3W_)Tq~iui+rne;Z2;??B> z?Sr8kEpSPuQ41rp-2}K45fazw)b;3%)Gdmm1FN%44YX$TNL z|BT2f<;^YD)a;d+olUgd3f=Js(@s{)7g~%om&Tz`YNWBoJ)Am0C6pY3;hP`_pSuya z06dle#tx>2yL{K6p+q+?(hnl{@8W z>eh5z|EFnpCMx{oY*QHwel)_f#oI!r=qp?=drjZlc6Gkm@r{fmg|6} z%&7b7)hI|kwC|~aCK}wTmt!X5QFI)$qK!4KH|u{4N{;LZnuTH4wXAGH4#Z8wC&f5Y zyQ8WD)d+uKE%^mazN{Bxa9RixV-?VKl23q=j`Sy#*C@8w1Sy-X(Q(*UyvSl=oa$ex zk8fI^O|5%H3R4u7n@Oxoxox4`{LV$bx}&;rISq49*I_uW1pG8BS*6XcbX+XvbrEzm zxysejCP=JicVAS~x|1VHh khiM-Cd)t46^UAxA5h)GAu~eay&$y^`HJ@lyLF^;{1)ex0ZvX%Q literal 0 HcmV?d00001 diff --git a/doc/sphinx/configuration/suricata-yaml/NFQ2.png b/doc/sphinx/configuration/suricata-yaml/NFQ2.png new file mode 100644 index 0000000000000000000000000000000000000000..de0b25d383937ca6ac30a706fe0f08ca44073d92 GIT binary patch literal 20707 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 kJ-7ZHdT#v_x^4c8cMt=8d!eLXrMN5 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 I%BzU~0BLZWQ2+n{ literal 0 HcmV?d00001 diff --git a/doc/sphinx/configuration/suricata-yaml/Tuple1.png b/doc/sphinx/configuration/suricata-yaml/Tuple1.png new file mode 100644 index 0000000000000000000000000000000000000000..4bcddb81e6a032500e45d2c760824f561abe7ee6 GIT binary patch literal 11151 zcmdUV2T)U8+ij57h6vJCng$R;mllww0s=uwLJ>k!l->lSmmo+Nkd9OVLx)HUQX>M= z1f+KmLJtsnC;Z3nzW>ZS-`tsh?l*Ji&dp3FaCWlyKIc5=dDdFb3e(b1zD{wQ0t5nG zS5;9&fIt_ZAP^b$$_3yErH1e=;DgKsq5K$B+QYH}{B!lSih&CVMAh==O_sn%#S9$0 z{6>GJqBT53s&yY0FaAkZC>Papb)vu|5O(F)~_*CEWD&X?w6)k;AK zYDF5IFBccIip<~zNK9cuVZQEaBusYmQ)s{y(qB4v%pg4R%#Uu6wZ5ivws&*4$e3Yg z7B>4U+O9m#XIkjQMnCb@&d)WU#j%g+x=33x(4Bj?D9J$nFf!0XGzg>voDuIu&?n%8 zv>+f*KK;LsfD$hJ`^cX!1Hbvl$e(Hc%=V9wKMMe}{d45c0>Etl82RVYe~N^|6WYLob0hfJobu~bPJ&FD3u7Hcz0-EmlUho%TVq$`N?Jn22 zEdBWYzSGyGV8j&Fpq-~NRH(}V2i-t-eA}3+gE~w~I!u10K*?-Kw-G;DW)v7y+zY$l zpa0W1o;Jp!JEdW7*syHV!$_~dxXx{FZEOH*Kgv{QmobI7@b67oG3iEj{Vd2f&6uJtAL3 zJS>*EkDtTSX$Z>Q?IF_8lyCum$lYz4PloVffGb{gisEsB{QkU_O;e5YQL@1In=bwu zf3If#K}#uDJ18jV?ZZ2Aav3nPG6nA3;o{W9AA9e~&^ms8atRlBpDk2MP!16Gc(}0U z2G|@W591pf#+hA5+z7~>a80Xbrlf|I0ctrU)~{>-^uwTif4Ob+bl_#Tf!PnCh}<&I zrc`DZ%7jUW(VCKo0dy;5@|@_Y){xt8Eh|Wv_;OhJNI-A4sd~oLjCTq@dG~spFQstd z1>TE_1zKjwB7{aYqMxtvSqH{eBe>p7x z@k0|1mUq<)LU?t^E@^lzMI1_^))S}h$?vQhIyQH8_VXhX8%geP5zoZ|Z1PEyvteu$=b+4%`7oew=olVRcAEbkVHGaEMx(+j3;B zt3!{CPPfn?7sw~OB}DLxM2*M$nw8&$u}@R2Y_E>85^s6x{Tha;&IdZ{>{U1rO`7|s zZw)L>IGIS7POE>E<2tTlk{`*X?X%eUQ8UqCVbg%hh~qJvsuRjnIQn_r~txs-0|>MB6097-gy#s>Uut z-yHBR6m_;$mAb*F#x}y0A7N&9?x6~%oW34MYU6gev#)Cp^6C9&T9Q0!XG8N_4Wn*y%XCyqIFsCYo{zej4Fq3BDpqQ+A2DH6 zNZ(f`^n@l?4_DE7+(G;_2~vJvX4|)GG9C3vIIXlii!;4~#1bjai@X8w)MOq(@>ThC4g|4@>QpEn)FQ(|858=&?@qtpu{&Fe>+&_JvrfGh5H$?W zNX)T4W|`>;(zGbqD|($nh8GBV@)kyRSn@HpwEC$;Jm);_pnnci-`3;)3+9>T=lqTe+}BD}3j;u)1k3Jm$im@-c~l$qDHI(6|P zR`h>P{HZi)yx~b^DeFSI*G{PIhVRz%nDB$KbKj)`QbWi*a@7i6firTQE~_?#z-=ZY zr>aVnIO#_gvneq=G+fywU4}ZQTZC-DLU+9z8UY_nUA+t1jbFFD`*ZSjVR-T8TQ8MQOmFges2v_SEb8R z1o?S+VKyVBWmIh5SDbrBO`1->KZpAj4L79S$Yc-T4LMLFLo>o`RmV=d<+x~hd9MUl zJ?K!gN7_ldZlwrSGGZ_uwK9MA)^b9lB);VPhdBK@_?ZbaET#m zyMwz}7IeeDNUx;O6epK(Y+i5T7{MqI8ylOeuC`N@m^@&498mcr$(^87)eocIT4y8|b?D?76x>?ygb`JhjBbPIc4mOqp4 zf`Q8XKB!_So*=Os(<4th#Mji+0B8fIs+y$>(z;Z^*gRV2PNdV6f$Qs!mYa96J0bRp6T<3bwV?Mp&(CBD(IUf&67QwwNo06_`m4v#P zp}IFK{aQS`%Q?~GSmS%WZ;OkI83m9YG8;D;C$PA~xd^QN1fn3^dA>bH)_cFwVJany zC%Pn|ZHIJ1bYC02&q7s4h_NkU5-c4+;Mm%fZ7GzDIM_6>==>Xv?6%u4uG`;EuC9d47~zz?6=zf*pH z6Mi@3x$$ezV#C4oM5Q$Vk|yqHW*Dv3a3Ki*4Dpu9aG&;6W^E3?2r?H50x-?;uPgvQ zMWvakqr*d^>R+5|_W`wZk6&D+8B&y)*|0e(7h3AAYSx ziMuAa`31DmY5pCV`yRwF(Y)r&Kfg}zZc^zc()K`3m+ur5&V5Pwvt@4vVYq}Y=7H<# z+GLHWoSX>=q>HfYMuROM2%0t;DIzPaV$#!DnV8xhU-0MU!!9BKRBH6)`CCM%SocuT zGZ!oyNH{4x!5|(lX+MFj;#ae6c-|Dy($Yd9xzHzupF3UH>?&U*(+xp%3U|JIX$Ywn z$QU&Umv&nl#i4Malx#8{-~7qY)Ak3@8I7;&n1UhOCoAx^Be#QGTgUtF^M~NKx>t4U z4mPAcr!U-JSnkWo!8F`QdzIw3D7-r8VSN^b)6ITHgN{909EjG;MZm?Zetl|Zik96U z)ogHIt6N(e)H@RiF`n(8-9KKyw{e#%@zl5@GDH_CJT=YMgf3h%QrzCzuD7-q!PIt_ zq&jETpDeE@I5R|s!K_QDSszro67-sdfk!w6>gX3MZ8)nXxjZ~OjI5N_RJm?A9O-^) ze9QbqLu9YJCw*i_qJRba68YI8*0JC8d@hlU`cfdOW{LPBY$K18r}^-h(15DNzqLx^ zPLEC7{WS%x;~p_He8J>s$l{dN>6!2~IX@m@v(%Fgo|Dw*aNh>Iy$i^~>@%30=7m&h zCkh!<>Vg-xAJ@L{(tC>QQX)6e(t7>*+lpT+Yad(Y`(^$M(IYz>+NjyEKo|l-;|T;2 zhpEmWI(t)ezb@fLieSV0MiIqZg5Jx)FOqW&<;i-4l^}tZ*E^pZhsU(t_ujXoQGNRK zsk(Z}WEcXSp3-E10%d2>+8LUeYXW!I9*oe^`n~7H=aL=oQ)k)x{+1}rM6lvf;3dmU zUkOca5KigEi{IVQ8Gg^mY9IvE1Z&>G5@s2Vj(i$nxO*2Vt^s*wwl=z@l%?(pdc%5q zTZH%W1QrN|7Y2GAFx`L|zF=N-Rq5>!1;lsdUR}j(DmF2FkzLRNXNT1Y)|Iehgg;8_iP`r}SwA=$$Uo=Gl&qmrVgwbK1#fRFf@_bT)lvK&9s;UIsEs3WsQ7Sm(EDNNiR5dD3+w5T0 z&}0aJY)PFvW5gBM|{fZG0aX8el;p-S5Eo2zE#SXmijb>W5j+BMUg-YZgxIjuS& ziL#rU_SDxs-P9}&4nyjOjt$wvIwg1Ag}MoWg`G}6+T`(7#3+dWWn>mDbwNi-vkHmiZ`UW|8U!{Nf2 zW!2MPJufhj=EY@Fw`Q_h`cCICE<$DbHx_3yeoo9>@X$vWOV|hkGqpKqzr|NZ~mt6j3_MMP+tdgfUb_L;1I6o_L?6QsOeH(S4Y+FLPuocR{NaHfFHl~of zQCz*#R6tEB>Am4>n(t9N|Bj+|dJESRiOW>x8n%0w4ah#}0dB>)?rRN;lks!%<7Ni5 z<2Wbnb_|>B`eKMugv9&5L{9?0oZr@bOs7mpdoI~Q_^DTuOw2*~Jm(3~x^Kr(U+Zo2+^?r6H zDp)Wyuerl!ngKQUB*oV_c9uq0NQB2|RjYMxzR$DZjqXR+x~ zdBaj>KlAM}6H_s24u4(hl5z&fzeeYlM3)$OrbfChKGt>CUq9yFGx<7YOJeRw2Fqsk z)xb<&$AK?zF>)W{q+a{aP&%CajxiszrpqhW&3((L=qX`Mx<&@friW75IVQFBeeb#eE8bjq=ZJ46*cDoGCRfZ0( zXaUGVTS&zDOzQY*O50+E9vLWsmky?w_A)P1^x_47{bun#vVT_{|4*gAujyTKa1&dp za^i%qG>*q9VmM0MLjGY`C~ZlO_$2A@IsENh1>tS-#8;J`rnT4!Mw)fWsQB3*--JI? zLiOZddHDu;N`WKubuJQKKlwo%=igZ~@HkB*zf4tnYG;0nbcHKB=jf@`RB@KMfgPQH zGJ;#czTKc(H_X1PZ*sD#==_rj+C$?G%`!0bm$naoed*4V8C z*f4ETiy5Cr2t&0shL>a@kb*?{!@V_c*jiYTdMb1&e(K2pz=Rks=2Qm)YGj__{%j37 zZ;-PATqZ-A-M4aH;OOWmT4p=cI%OlJwbp!medmY`b-G38;Iq>Wt+t<7%sr~czouuz z(JUR#jyU=o9rU9os*@=tlhtarJ#7sVi!v#(6H!SZUBx>$LRXKj^kqywi;9C7nHJ=# zr$*hp4=z+27wgUs{;ZMyz>dmaA1J`-00K~QotWD>dYq-T+laEU;Y}#?Fu?%JVP$f7 zZNP;79foLmKX=*Z(8kWy={Cm{i()&&%0w0ZXcRo*_5NRe=y&hlx%5c22^;xXi2`KE znEDSa>`oDPA(l4aCA)!Bui1%!aM5vhvY+!rGOPLc=yowAe8(8O%47hluPD_*f#2Ej z9%00ir7$~MJ`n;0cCBk1>P$^Uq);Q@%vL#BGywGbm0oE))}BkwWV|{_Q(mC4uNy;N zXDzs}<)PvG1m=d7IVnCoD=q??jqm$2@Xf!y%zN-1=+EtS;_6?8qmHGYP36bxYvOUMgQ`y=V^bZ% z?Vj>2VEgFE@tE@RaWFS7T$r5Qy#u^dNpz&%2@jOV*@Ys*$(7Q(9D8F@m&Ows~g*ckb6L3=l($o0syA z$R4hoEQ{NAYHN0E&g$OPC__L>_I`d8RcdicBO|}`^;jSqbVFbumm$+%u+3x)Z``n; z0NMLSPOaD&HBSM0{e7eU%?iTxo+fwCT|PJP-tRzaKy8OBdL3-A4rx+d1XYK>Dkx;T zUhoCL@9rCup1raMp`kNG)ACng5pr2nAgvBQT`jE-F)=hpitkT0>Y{hF&vFwa~FdT>zcNmrIp6tc{id z(tD@SvEIjz9}`IL!<5(srpxWUcl~51u<|6US*aze@cx>ZM0-xa@?@v$bt=6@@Wr)40-c3OY-{E!l zYOPaHEYNW=^>MASMMObCLCo|k3yZ{B{{#d;`=mWKKj9@~bYHCWqgfxk(XX&j=b{?w z!kpEubGZiv!s{3HllU&NydPIO9ritb)TUb`A}VV9fP|^v>63a%bhG30l7Bn|w?|UT z(g!JhqI@~!t!XN??Tjmu%UeVnT=RqOvrUBSDb+@8G>nwxREZ@Z#Sd!WNldjH3TXv{ zy@0L)hz;|=qt_U6GU?K*RN7PHFjWg&!(zkg9>Shpr&cQ$=dgTj&^SU8+}6j# z+7kr~k9Sv^Pdv#$3-E$W$hI}>%E}73+}9o&2JAcD-+BWPHr;J+nfB1U$a&2%*1=WN=>LiM-j+6)fU~i6P4}Ozu)}v zBa#`$X7z?858(19n4~61NVmD432A$wODzi9yF};lt+Hy?*@4 za0xSqHUl4nQwLX)kRiIyZX_4UH`enARP5)iN|hp7k7-(CXZ20tz6Atg{WfoGf1Q~7)Fb!L4|kpF0*&bv1J z7!D=>=NAzP<@^!X7RfYCw3Z6m_PALSCeJ z!AXa_<6x}^8X7-dWBbg{uhEbV_2~`{HIuQydM>upzHQmaj%stl+KnOHQq|V?PMU$5 z$cBP9_4Rc3xQ`@5L-|g72WFychL5{S4A*15ZE*I#8ca+jS)%41WTGmkKDms!!3%gF z*`6igCf&YAIs*MdKt4 zXJEL$_z6+=HQ{tCGSS>1(flS0RWYdP`G+Q^Z`g7jB+hj~V zD%QQ&ovQ4b4v1fcOVWpDeiBAHg%s-=78VwO*7voweyzNVw+T6){p)t{eY;WNA1pX) zfkGb$56P@GT;JQOc=@@2*-v;C--4uwH7uGT5Uh#(P+d6M6pWo5Z_L$}Ne4L2; z#sT!$hu;_=HVYbrIkmurg$}H}bC&=R=n(g7mll@cS1%d-02O{n5pNB8=3i`-;LI}i z75?LWjJU0aTXky$8Yw=k57O<*RuXyr-26Dm$iv8{i}4n8gC1zg78dlU6K1hB@xwsj zF49wVD7Bm7b)SZ?`|2FaPE;q=5fiOUxrv)BWHt}*=a0tDFhD#|xf#>URq@4VVD>O)%m{BTX^ z6~jd>v~DTWnVGHNo+0M5h}paMH}8VC$8F19`3SrqtpXAJ&Qa%DY&?f@I3mGr{2EB7 z@PcJNFFi$2=ju)khZ7hM`t4liY*Yx~FK}#pJpH`ySCGGc(O@VIha#uE{CRr}hY$UA z&>bwV_~vLTnu%Zk8$&1=s7$wDKtoz!yVZ5XxD7!DYSBX@5QrZ6a~~QAFE6seOI+xf z3}lv%KoV|=THFl23(irF)`QXTf*uy@z#s{Lte%k}2xf*l_^cM>Nj|s;3N7K|^gUWg z0@7x#HK10$Xb!&qG!Gz%t%*R0j$sABKxOUi>f+D=Oa*4`fYK>qGsr{JhXk6?-m8NJ z{G7nOEqiP$>wCO=|K*QR6(0Ip(lOzW2w#mmvj;%k&mv$p-7oE9zCsPV{eZwuQ)50> zZhkQ3ZVII95sYc?g+F{}D~mP;D7W;CjQfNU;z^s$O@3ieKEmv{!V5n)$0%gN56(o9 zJoWVS26EL6p8wg6ErJVdTnh;2=xb`%K!vwW6v+SG9`U!O;ve>i|2A9v!yfT>iu$KL z;%`gEKkO0zZK?RbYMl5_H}(HyyS$<$s5gO8{hG(RDBVu-0e*2H%nLbT1$);>Lm1umJYr1VcO%hvbwMw<;=+{k{E?dC@f?_X`Aqv_N5!n0k?eR>CY4$Rj9AY|W{t)!=yh*&rd&@=NH zuN@+?2xx@TS~qTNR?EgIK|I$}qVmM82Mg7UoC%?{aqKdUv2ai0QcUMO06IqWQ zEKR{91v3S~Bb7jc_03@xw|RqX4hBfr*>mq6YB0LQ$rveaGkT{%b>K(j>dfA-9=e?# z#LLiKGYE8N0B}f0M>kRJC=V#M&dEsYm_B#8A%!!HQ)KP>16SrZ3*8aJ>jz#9FvWcf z# zuK<(GQV2QrX=Ic2GVVbeo2<@v z>4jIE?**V+cl9lAN)13qsj*O0>r0n_x1?&hwLT=@(2LVui-Qqkm){H38ot9#``m%$G*GAwAn2NZYr)xi}HTC+CbZfJbvqNgzb*DI1m%6ap5 z6TnrDfZ`C3Fi$Dk=3Z-t(AG5J~%N-rJsB-jgd^J0iUqXEx zJ1>r!>Up}AF1!WLuHsQpLb$KdZ%z>26i19D1qk|#S4c>xJj}G(A)OHXd>WuLi`^$@ zMAUgZNA#o@p~Up0gkf0S!}CHpc+}Sqt7bOl^`v3X=a&C+&htOLlI`%_hi2E5Ti$g2Zx5vievdnh$^en1Vs7z z<_qJZ{jDUbvnghSI_YTAj*>OfmMg>*wUXmj<&g_|ZI7-Tj=QIRe29-e^F!H@Vu7x% zAU{8U1E&emIxk(~#rJnx_%<~I+^&0Ti|v!i)4D8yX?p`{)v+dwe3}eOeJ;BuJSX z=he#aOeJi9r*n5XUT#UV_uTY*B**0g>Y&HjGIFL37gLAb)rOp#Tydz=k63{esbKfb z1{a~*U)=0wB6`lYNj3!?Z9fL%kOETMT9naHaV`TzouX8E59c;C(;I5TsA{i@1Njq9 z5ryNvZDDO~?d!TS(Y34lOBt(MC&L06yDhqgr~Bed@*98_sU8Rtr7gU z(NXR?5HxFB-?%U(`g8n~gylp=II^qk@+a{56Gg=z;-Vsq51@JMCpD`ls;^$zYk{Ni zRsu1P`XA?jzPbrAoP>vmBdZ;NrjjP0HAsnz>t?$kObaTW(!e`~yJMkjCv`8YdCiko zL(Ug3yPq|6cM3_a%<;8PorQ?f-u|JGDq8_GkE(x<`kR?0|n3q^hK$So-*Rz<&Wr CzddXK literal 0 HcmV?d00001 diff --git a/doc/sphinx/configuration/suricata-yaml/balancing_workload.png b/doc/sphinx/configuration/suricata-yaml/balancing_workload.png new file mode 100644 index 0000000000000000000000000000000000000000..37dce79bec5aadc6fbd0db371941e018577e99b8 GIT binary patch literal 29055 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%0A2z+AIrYFL`~J4qHD$jPn7W-G`T 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/configuration/suricata-yaml/flow.png b/doc/sphinx/configuration/suricata-yaml/flow.png new file mode 100644 index 0000000000000000000000000000000000000000..9e05e921ecb0b984c09a1f62f56723eba790f305 GIT binary patch literal 15914 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 G(EkCV<@vn; literal 0 HcmV?d00001 diff --git a/doc/sphinx/configuration/suricata-yaml/grouping_tree.png b/doc/sphinx/configuration/suricata-yaml/grouping_tree.png new file mode 100644 index 0000000000000000000000000000000000000000..a88d9a207db7f7a0f3380945d8f9961bbc1988b5 GIT binary patch literal 26129 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%0DheV&W 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 bz2H_nl7VuShv6I*0$%bm%F<<0MzH?^N&#y9 literal 0 HcmV?d00001 diff --git a/doc/sphinx/configuration/suricata-yaml/inline_mode.png b/doc/sphinx/configuration/suricata-yaml/inline_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..aadbdf2e3d5e3b2b6cd7607e386c73765ec5dca9 GIT binary patch literal 15054 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/configuration/suricata-yaml/normal_ids.png b/doc/sphinx/configuration/suricata-yaml/normal_ids.png new file mode 100644 index 0000000000000000000000000000000000000000..4f3b70bd1452cf342855c86989a4d47b0d22f6c5 GIT binary patch literal 8447 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

jOY#tdD;VIs8ekON!*^_Gzn_+aS!@2tPd$b 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 YGwRFhl#(>n_fQ`NIaS$;mv4gp3okn2I{*Lx literal 0 HcmV?d00001 diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash3.png b/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash3.png new file mode 100644 index 0000000000000000000000000000000000000000..2c396df51d43211cc06e3aa59aa593cee1b5ada8 GIT binary patch literal 29420 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash4.png b/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash4.png new file mode 100644 index 0000000000000000000000000000000000000000..b5cfc148f48bcb634641ca247e45295e05e8a6c5 GIT binary patch literal 125520 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/output/files-json-log-output/mongodb.rst b/doc/sphinx/output/files-json-log-output/mongodb.rst new file mode 100644 index 000000000000..0143ab6dff93 --- /dev/null +++ b/doc/sphinx/output/files-json-log-output/mongodb.rst @@ -0,0 +1,97 @@ +MongoDB +======= + +If you do not have it installed, follow the istructions here: +http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/ + +Basically you do: + + +:: + + + sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10 + deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen + sudo apt-get update && sudo apt-get install mongodb-10gen + + +The bigest benefit of MongoDB is that it can natively import json.log files: +if you have MongoDB installed - all you have to do is: + + +:: + + + mongoimport --db filejsondb --collection filejson --file files-json.log + +here: + +* --db filejsondb is the database, +* --collections filejson is the equivalent of SQL "table" +* --file files-json.log - is the json log created and logged into from Suricata. + +last but not least - it would automatically create the db and tables for you. + +this would import a 5 Gb (15 million entries) json log file in about 5-10 minutes - default configuration, without tuning MongoDB for high performance. (your set up and HW will definitely have effect on the import time ) + + + +MongoDB Example queries (once you have imported the files-json.log - described above - just go ahead with these queries): + + +:: + + + db.files.group( { cond : {"magic":/.*PDF*./ }, key: {"srcip":true,"http_host":true,"magic":true} ,initial: {count: 0},reduce: function(value, total) {total+=value.count;} } ); + + +:: + + + db.filejson.find({magic:/.*PDF.*/},{srcip:1,http_host:1,magic:1}).sort({srcip:1,http_host:1,magic:1}).limit(20) + + +Get a sorted table biggest to smallest number hosts of file downloads: + + +:: + + + > map = function () { emit({srcip:this.srcip,http_host:this.http_host,magic:this.magic}, {count:1}); } + function () { + emit({srcip:this.srcip, http_host:this.http_host, magic:this.magic}, {count:1}); + } + > reduce = function(k, values) {var result = {count: 0}; values.forEach(function(value) { result.count += value.count; }); return result; } + function (k, values) { + var result = {count:0}; + values.forEach(function (value) {result.count += value.count;}); + return result; + } + > db.filejson.mapReduce(map,reduce,{out: "myoutput" }); + { + "result" : "myoutput", + "timeMillis" : 578806, + "counts" : { + "input" : 3110871, + "emit" : 3110871, + "reduce" : 673186, + "output" : 219840 + }, + "ok" : 1, + } + > db.myoutput.find().sort({'value.count':-1}).limit(10) + { "_id" : { "srcip" : "184.107.x.x", "http_host" : "arexx.x", "magic" : "very short file (no magic)" }, "value" : { "count" : 42560 } } + { "_id" : { "srcip" : "66.135.210.182", "http_host" : "www.ebay.co.uk", "magic" : "XML document text" }, "value" : { "count" : 30896 } } + { "_id" : { "srcip" : "66.135.210.62", "http_host" : "www.ebay.co.uk", "magic" : "XML document text" }, "value" : { "count" : 27812 } } + { "_id" : { "srcip" : "213.91.x.x", "http_host" : "www.focxxxx.x", "magic" : "HTML document, ISO-8859 text" }, "value" : { "count" : 26301 } } + { "_id" : { "srcip" : "195.168.x.x", "http_host" : "search.etaxxx.x", "magic" : "JPEG image data, JFIF standard 1.01, comment: \"CREATOR: gd-jpeg v1.0 (using IJG JPEG v80), quality = 100\"" }, "value" : { "count" : 16131 } } + { "_id" : { "srcip" : "184.107.x.x", "http_host" : "p2p.arxx.x:2710", "magic" : "ASCII text, with no line terminators" }, "value" : { "count" : 15829 } } + { "_id" : { "srcip" : "213.91.x.x", "http_host" : "www.focxx.x", "magic" : "HTML document, ISO-8859 text" }, "value" : { "count" : 14472 } } + { "_id" : { "srcip" : "64.111.199.222", "http_host" : "syndication.exoclick.com", "magic" : "HTML document, ASCII text, with very long lines, with no line terminators" }, "value" : { "count" : 14009 } } + { "_id" : { "srcip" : "69.171.242.70", "http_host" : "www.facebook.com", "magic" : "ASCII text, with no line terminators" }, "value" : { "count" : 13098 } } + { "_id" : { "srcip" : "69.171.242.74", "http_host" : "www.facebook.com", "magic" : "ASCII text, with no line terminators" }, "value" : { "count" : 12801 } } + > + + + +Peter Manev diff --git a/doc/sphinx/output/files-json-log-output/mysql.rst b/doc/sphinx/output/files-json-log-output/mysql.rst new file mode 100644 index 000000000000..41533f21d7a0 --- /dev/null +++ b/doc/sphinx/output/files-json-log-output/mysql.rst @@ -0,0 +1,36 @@ +MySQL +===== + +If you do not have MySQL installed - go ahead and do so: + +:: + + + sudo apt-get update && sudo apt-get upgrade + sudo apt-get install mysql-server mysql-client + + +For MySQL make sure you create a db and a table: + + +:: + + + mysql>create database filejsondb; + mysql> create user 'filejson'@'localhost' IDENTIFIED BY 'PASSWORD123'; + Query OK, 0 rows affected (0.00 sec) + mysql> grant all privileges on filejsondb.* to 'filejson'@'localhost' with grant option; + mysql> flush privileges; + mysql> use filejsondb; + + mysql> CREATE TABLE filejson( time_received VARCHAR(64), ipver VARCHAR(4), srcip VARCHAR(40), dstip VARCHAR(40), protocol SMALLINT UNSIGNED, sp SMALLINT UNSIGNED, dp SMALLINT UNSIGNED, http_uri TEXT, http_host TEXT, http_referer TEXT, filename TEXT, magic TEXT, state VARCHAR(32), md5 VARCHAR(32), stored VARCHAR(32), size BIGINT UNSIGNED); + + mysql> show columns from filejson; + + + +OPTIONALLY - if you would like you can add in the MD5 whitelist table and import the data as described here ( [[Filemd5 and white/black listing with MD5]] ) + +now you can go ahead and execute the script - [[Script FollowJSON]] + +Peter Manev diff --git a/doc/sphinx/output/files-json-log-output/postgresql.rst b/doc/sphinx/output/files-json-log-output/postgresql.rst new file mode 100644 index 000000000000..3fdb1f2cff5c --- /dev/null +++ b/doc/sphinx/output/files-json-log-output/postgresql.rst @@ -0,0 +1,80 @@ +PostgreSQL +========== + +If you do not have PostgreSQL installed: + + +:: + + + sudo apt-get update && sudo apt-get upgrade + sudo apt-get install postgresql + + + +:: + + + sudo vim /etc/postgresql/9.1/main/pg_hba.conf + +change the line: + + +:: + + + local all all trust + +to + + +:: + + + local all all md5 + + +login and change passwords + +:: + + + sudo -u postgres psql postgres + \password postgres + + +Then - + + + +:: + + + create database filejsondb; + \c filejsondb; + create user filejson with password 'PASSWORD123'; + CREATE TABLE filejson( time_received VARCHAR(64), ipver VARCHAR(4), srcip VARCHAR(40), dstip VARCHAR(40), protocol INTEGER, sp INTEGER, dp INTEGER, http_uri TEXT, http_host TEXT, http_referer TEXT, filename TEXT, magic TEXT, state VARCHAR(32), md5 VARCHAR(32), stored VARCHAR(32), size BIGINT); + grant all privileges on database filejsondb to filejson; + +Log out and log in again (with the "filejson" user) to test if everything is ok: + + +:: + + + psql -d filejson -U filejson + + + + +Optionally you could create and import the MD5 white list data if you wish - generally the same guidance as described in: +[[Filemd5 and white/black listing with MD5]] + +Some more general info and basic commands/queries: +http://jazstudios.blogspot.se/2010/06/postgresql-login-commands.html +http://www.thegeekstuff.com/2009/05/15-advanced-postgresql-commands-with-examples/ + + +now you can go ahead and execute the script - [[Script FollowJSON]] + +Peter Manev diff --git a/doc/sphinx/output/files-json-log-output/script-follow-json.rst b/doc/sphinx/output/files-json-log-output/script-follow-json.rst new file mode 100644 index 000000000000..3c88021c2174 --- /dev/null +++ b/doc/sphinx/output/files-json-log-output/script-follow-json.rst @@ -0,0 +1,98 @@ +Script FollowJSON +================= + +BEFORE you run the script - make sure you have set up suricata.yaml and your database correctly !! + +Suricata.yaml: + +1. make sure json-log is enabled +2. and append is set to yes +3. optionally - you have compilled in Suricata with MD5's enabled + +MD5's are enabled and forced in the suricata yaml config ( :ref:`MD5 ` ) +bottom of the page "Log all MD5s without any rules" . + + +:: + + + - file-log: + enabled: yes + filename: files-json.log + append: yes + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + force-magic: yes # force logging magic on all logged files + force-md5: yes # force logging of md5 checksums + + +**Append is set to yes** - this is very important if you "follow" , json.log - if you use the tool to constantly parse and insert logs from files-json.log as they are being written onto the log file. + + +There is a python script (in BETA now and) available here: + +* https://redmine.openinfosecfoundation.org/attachments/download/843/FollowJSON.tar.gz + +that you can use for helping out in importing files-json.log entries into a MSQL or PostgreSQL database. + +The script would allow you to do the following: + + +* it contains 2 files +* one python executable +* one yaml config file +* one LICENSE (GPLv2) + +This is what the script does: + +1. Multi-threaded - spawns multiple processes if itself +2. uses yaml as configuration +3. Can: + + 3.1. Read files-json.log file + + 3.1.1. - Continuously - as logs are being written in the log file + 3.1.2. - mass import a stand alone files-json.log into a database + + 3.2. Into (your choice) + + 3.2.1. MySQL DB (locally/remotely,ip) + 3.2.2. PostgreSQL DB (locally/remotely,ip) + +4. Customizable number of processes (default is number of cores - if you have more then 16 - suggested value is NumCores/2) +5. Customizable "chunk" lines to read at once by every process - suggested (default) value is 10 (16 cores = 16 processes * 10 = 160 entries per second) + +**Please look into the configurational yaml file** for more information. + +The script is in BETA state - it has been tested , it works - but still, you should test it and adjust the configuration accordingly and run it on your test environment first before you put it in production. + +After you have made: + +#. your choices of database type (MySQL or PostgreSQL and installed/configured tables for it), +#. created the appropriate database structure and tables (explained in the next tutorial(s) ), +#. adjusted the yaml configuration accordingly, +#. started Suricata, + +you would need: + +:: + + + sudo apt-get install python-yaml python-mysqldb python-psycopg2 + +Then you just run the script, after you have started Suricata: + + +:: + + + sudo python Follow_JSON_Multi.py + +if you would like to execute the script in the background: + + +:: + + + sudo python Follow_JSON_Multi.py & + +Peter Manev diff --git a/doc/sphinx/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst b/doc/sphinx/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst new file mode 100644 index 000000000000..d3d81ec13a36 --- /dev/null +++ b/doc/sphinx/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst @@ -0,0 +1,138 @@ +Useful queries - for MySQL and PostgreSQL +========================================= + + +General Purpose and Useful Queries (MySQL - 99% the same for PostgreSQL) for the files-json.log databases and tables: + + +:: + + + mysql>select srcip,http_host,count(*) as total from filejson where magic like "%PDF document%" group by srcip,http_host order by total DESC limit 10; + +above top 10 source ip from which PDF's where downloaded +change srcip with dstip to get top 10 IPs downloading PDFs + + +:: + + + mysql>select srcip,http_host,count(*) as total from filejson where magic like "%executable%" group by srcip,http_host order by total DESC limit 10; + +above top 10 source ip from which executables where downloaded from, +change srcip with dstip to get top 10 IPs downloading executables + + + +:: + + + mysql> SELECT srcip,http_host,count(*) AS Total , (COUNT(*) / (SELECT COUNT(*) FROM filejson where magic like "%executable%")) * 100 AS 'Percentage to all items' FROM filejson WHERE magic like "%executable%" GROUP BY srcip,http_host order by total DESC limit 10; + +:: + + + +----------------+----------------------+-------+-------------------------+ + | srcip | http_host | Total | Percentage to all items | + +----------------+----------------------+-------+-------------------------+ + | 149.5.130.7 | ws.livepcsupport.com | 225 | 9.1167 | + .............................. + ............................. + +This would give you a sorted table depicting source ip and host name, number of executable downloads from that host/source ip and what percentage is that of the total executable downloads. +Note: the term executable means - dll, exe, com, msi, java ... and so on , NOT just .exe files + + + +:: + + + mysql>select count(magic) as totalPDF from filejson where magic like "%PDF%" + +This will give you the total number of PDFs out of all files + + +:: + + + mysql>SELECT ( select count(magic) from filejson where magic like "%PDF%" ) as "PDF Total" , (select count(magic) from filejson where magic like "%executable%") as "Executables Total" , (select count(magic) from filejson where filename like "%.xls") as "Excel Total"; + +This will give you: + +:: + + + +-----------+-------------------+-------------+ + | PDF Total | Executables Total | Excel Total | + +-----------+-------------------+-------------+ + | 391 | 2468 | 7 | + +-----------+-------------------+-------------+ + + +:: + + + mysql> SELECT ( select count(magic) from filejson where magic like "%PDF%" ) as "PDF Total" , (select count(magic) from filejson where magic like "%executable%") as "Executables Total" , (select count(magic) from filejson where filename like "%.xls") as "Excel Total", (select count(magic) from filejson) as "TOTAL NUMER OF FILES"; + +:: + + + +-----------+-------------------+-------------+----------------------+ + | PDF Total | Executables Total | Excel Total | TOTAL NUMER OF FILES | + +-----------+-------------------+-------------+----------------------+ + | 391 | 2468 | 7 | 3743925 | + +-----------+-------------------+-------------+----------------------+ + +the above query - a breakdown for PDF, executables and files hat have extension .xls + + + +:: + + + mysql>select srcip,filename,http_host,count(*) as total from filejson where filename like "%.xls" group by srcip,filename,http_host order by total DESC limit 10; + +the above will select top 10 source ip and document NAMES where excel files (files with extension .xls) were downloaded form + + +:: + + + mysql>select srcip,http_host,count(*) as total from filejson where filename like "%.exe" group by srcip,http_host order by total DESC limit 10; + +the above will select the top 10 source ips from where ".exe" files where downloaded from + + +:: + + + mysql>select srcip,http_host,count(*) as total from filejson where filename like "%.doc" group by srcip,http_host order by total DESC limit 10; + +the above for ".doc" files + + +:: + + + mysql>select magic,http_host,count(*) as count from filejson group by magic,http_host order by count DESC limit 20; + +select top 20 hosts grouped and ordered by count + + +:: + + + mysql>select dstip,size,count(*) as total from filejson group by dstip,size order by total DESC limit 10; + +the above query will show you he top 10 downloading ips by size of downloads + + +:: + + + mysql>select dstip,http_host,count(*) as total from filejson where filename like "%.exe" group by dstip order by total DESC limit 5; + +the above query will show you the top 5 downloading ips (and the hosts they downloaded from) that downloaded files with .exe extensions. + + +Peter Manev diff --git a/doc/sphinx/output/index.rst b/doc/sphinx/output/index.rst new file mode 100644 index 000000000000..94c9e2bde3ae --- /dev/null +++ b/doc/sphinx/output/index.rst @@ -0,0 +1,11 @@ +Output +====== + +.. toctree:: + + eve/index.rst + ../configuration/lua-output + syslog-alerting-comp + custom-http-logging + ../configuration/log-rotation + files-json-log-output/files-json-log-output.rst diff --git a/doc/sphinx/output/syslog-alerting-comp.rst b/doc/sphinx/output/syslog-alerting-comp.rst new file mode 100644 index 000000000000..26472433ca6d --- /dev/null +++ b/doc/sphinx/output/syslog-alerting-comp.rst @@ -0,0 +1,63 @@ +Syslog Alerting Compatibility +============================= + +Suricata can alert via sylog which is a very handy feature for central log collection, compliance, and reporting to a SIEM. Instructions on setting this up can be found in the .yaml file in the section where you can configure what type of alert (and other) logging you would like. + +However, there are different syslog daemons and there can be parsing issues with the syslog format a SIEM expects and what syslog format Suricata sends. The syslog format from Suricata is dependent on the syslog daemon running on the Suricata sensor but often the format it sends is not the format the SIEM expects and cannot parse it properly. + +Popular syslog daemons +---------------------- + +* **syslogd** - logs system messages +* **syslog-ng** - logs system messages but also suports TCP, TLS, and other enhanced enterprise features +* **rsyslogd** - logs system messages but also support TCP, TLS, multi-threading, and other enhanced features +* **klogd** - logs kernel messages +* **sysklogd** - basically a bundle of syslogd and klogd + +If the syslog format the Suricata sensor is sending is not compatible with what your SIEM or syslog collector expects, you will need to fix this. You can do this on your SIEM if it is capable of being able to be configured to interpret the message, or by configuring the syslog daemon on the Suricata sensor itself to send in a format you SIEM can parse. The latter can be done by applying a template to your syslog config file. + +Finding what syslog daemon you are using +---------------------------------------- + +There are many ways to find out what syslog daemon you are using but here is one way: + +:: + + + cd /etc/init.d + ls | grep syslog + +You should see a file with the word syslog in it, e.g. "syslog", "rsyslogd", etc. Obviously if the name is "rsyslogd" you can be fairly confident you are running rsyslogd. If unsure or the filename is just "syslog", take a look at that file. For example, if it was "rsyslogd", run: + +:: + + + less rsyslogd + +At the top you should see a comment line that looks something like this: + +:: + + + # rsyslog Starts rsyslogd/rklogd. + +Locate those files and look at them to give you clues as to what syslog daemon you are running. Also look in the *start()* section of the file you ran "less" on and see what binaries get started because that can give you clues as well. + +Example +------- + +Here is an example where the Suricata sensor is sending syslog messages in rsyslogd format but the SIEM is expecting and parsing them in a sysklogd format. In the syslog configuration file (ususally in /etc with a filename like rsyslog.conf or syslog.conf), first add the template: + +:: + + + $template sysklogd, "<%PRI%>%syslogtag:1:32%%msg:::sp-if-no-1st-sp%%msg%" + +Then send it to the syslog server with the template applied: + +:: + + + user.alert @10.8.75.24:514;sysklogd + +Of course this is just one example and it will probably be different in your environment depending on what syslog daemons and SIEM you use but hopefully this will point you in the right direction. From 5a542a9934b0923140471a6b3d34fdef4ca3409c Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 5 Jan 2016 03:23:54 +0100 Subject: [PATCH 1813/2553] doc: minor fixes in configuration causing errors/warnings --- doc/sphinx/configuration/snort-to-suricata.rst | 2 +- doc/sphinx/configuration/suricata-yaml.rst | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/sphinx/configuration/snort-to-suricata.rst b/doc/sphinx/configuration/snort-to-suricata.rst index ec9ec0f0db26..f9ea3b36e049 100644 --- a/doc/sphinx/configuration/snort-to-suricata.rst +++ b/doc/sphinx/configuration/snort-to-suricata.rst @@ -81,7 +81,7 @@ snort.conf suricata.yaml -Suricata's checksum handling works _on-demand_. The stream engine +Suricata's checksum handling works *on-demand*. The stream engine checks TCP and IP checksum by default: :: diff --git a/doc/sphinx/configuration/suricata-yaml.rst b/doc/sphinx/configuration/suricata-yaml.rst index 7dd34ca81c38..6a2867fe2829 100644 --- a/doc/sphinx/configuration/suricata-yaml.rst +++ b/doc/sphinx/configuration/suricata-yaml.rst @@ -277,8 +277,8 @@ integration with tools like logstash. - ssh For more advanced configuration options, see [[**FIXME** EveJSONOutput]]. - -The format is documented in [[**FIXME **EveJSONFormat]] +.. FIXME jsonformat ref +The format is documented in :ref:`Eve JSON Format ` Log output for use with Barnyard (unified.log) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -613,7 +613,7 @@ At all of these options, you can add (or change) a value. Most signatures have the adjustment to focus on one direction, meaning focusing exclusively on the server, or exclusively on the client. -If you take a look at example 4, _the Detection-engine grouping tree_, +If you take a look at example 4, *the Detection-engine grouping tree*, you see it has many branches. At the end of each branch, there is actually a 'sig group head'. Within that sig group head there is a container which contains a list with signatures that are significant @@ -1572,7 +1572,7 @@ Add the numbers of the options repeat_mark and route_queue to the NFQ-rule:: route_queue: 2 #Here you can assign the queue-number of the tool that Suricata has to #send the packets to after processing them. -*Example 1 NFQ * +*Example 1 NFQ1* mode: accept From 715485a42ba8ad07782f72ed34d792de584ffad4 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 5 Jan 2016 20:19:10 +0100 Subject: [PATCH 1814/2553] doc: finished remaining conversion for output --- ...filemd5-and-whiteblacklisting-with-md5.rst | 2 ++ ...gstash-kibana-and-suricata-json-output.rst | 33 ++++++++++--------- .../output/files-json-log-output/mysql.rst | 4 +-- .../files-json-log-output/postgresql.rst | 6 ++-- .../script-follow-json.rst | 2 ++ 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/doc/sphinx/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst b/doc/sphinx/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst index d4e6ef4fc52a..1e24c2a59189 100644 --- a/doc/sphinx/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst +++ b/doc/sphinx/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst @@ -1,3 +1,5 @@ +.. _filemd5-listing: + Filemd5 and white or black listing with MD5 hashes ================================================== diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst b/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst index ebc2aef759ab..10e5d87f25cb 100644 --- a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst +++ b/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst @@ -2,14 +2,17 @@ Logstash Kibana and Suricata JSON output ======================================== With the release of Suricata 2.0rc1 , Suricata introduces all JSON output capability. -What is JSON - http://en.wikipedia.org/wiki/JSON +What is JSON - http://en.wikipedia.org/wiki/JSON One way to handle easily Suricata's JSON log outputs is through Kibana - http://kibana.org/ : -> Kibana is a highly scalable interface for Logstash (http://logstash.net/) and ElasticSearch (http://www.elasticsearch.org/) that allows you to efficiently search, graph, analyze and otherwise make sense of a mountain of logs. -> + +:: + + Kibana is a highly scalable interface for Logstash (http://logstash.net/) and ElasticSearch (http://www.elasticsearch.org/) that allows you to efficiently search, graph, analyze and otherwise make sense of a mountain of logs. The installation is very simple/basic start up with minor specifics for ubuntu. You can be up and running, looking through the logs in under 5 min. + The downloads can be found here - http://www.elasticsearch.org/overview/elkdownloads/ This is what yo need to do. @@ -38,7 +41,7 @@ Make sure your Suricata is compiled/installed with libjansson support enabled: CUDA enabled: no ... -If it isn't check out the [[Suricata_installation]] page to install or compile Suricata for your distribution. +If it isn't check out the [[**FIXME** Suricata_installation]] page to install or compile Suricata for your distribution. **NOTE:** you will need these packages installed -> **libjansson4** and *libjansson-dev* before compilation. Configure suricata @@ -78,14 +81,12 @@ Install ELK (elasticsearch, logstash, kibana) --------------------------------------------- First install the dependencies -( -**NOTE:** -ELK recommends running with Oracle Java - how to -> -http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup-service.html#_installing_the_oracle_jdk -) -Otherwise you can install the openjdk: +**NOTE:** ELK recommends running with Oracle Java - how to: + +* http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup-service.html#_installing_the_oracle_jdk +Otherwise you can install the openjdk: :: @@ -95,7 +96,9 @@ Otherwise you can install the openjdk: Then download and install the software. Make sure you download the latest versions - -http://www.elasticsearch.org/overview/elkdownloads/ + +* http://www.elasticsearch.org/overview/elkdownloads/ + The installation process is simple (for example): :: @@ -112,7 +115,7 @@ The installation process is simple (for example): Logstash configuration ---------------------- -Create and save a *logstash.conf* file with the following content in the /etc/logstash/conf.d/ directory : +Create and save a **logstash.conf** file with the following content in the /etc/logstash/conf.d/ directory : :: @@ -197,7 +200,7 @@ Configure the start-up services Enjoy ----- -That's all. Now make sure Suricata is running and you have logs written in your JSON log files and you point your browser towards -> +That's all. Now make sure Suricata is running and you have logs written in your JSON log files and you point your browser towards :: @@ -210,9 +213,9 @@ Some ready to use templates can be found here: * https://github.com/pevma/Suricata-Logstash-Templates From here on if you would like to customize and familiarize yourself more with the interface you should read the documentation about Kibana and Logstash. -Please have in mind that this is a very quick(under 5 min) tutorial. You should customize and review the proper way for you of using it as a service and/or consider using *httpS web interface and reversy proxy with some authentication*. +Please have in mind that this is a very quick(under 5 min) tutorial. You should customize and review the proper way for you of using it as a service and/or consider using **httpS web interface and reversy proxy with some authentication**. -Some possible customization of the output of Logstash and Kibana - > +Some possible customization of the output of Logstash and Kibana diff --git a/doc/sphinx/output/files-json-log-output/mysql.rst b/doc/sphinx/output/files-json-log-output/mysql.rst index 41533f21d7a0..0e0c32867014 100644 --- a/doc/sphinx/output/files-json-log-output/mysql.rst +++ b/doc/sphinx/output/files-json-log-output/mysql.rst @@ -29,8 +29,8 @@ For MySQL make sure you create a db and a table: -OPTIONALLY - if you would like you can add in the MD5 whitelist table and import the data as described here ( [[Filemd5 and white/black listing with MD5]] ) +OPTIONALLY - if you would like you can add in the MD5 whitelist table and import the data as described here :ref:`FileMD5 and white/black listing with md5 ` -now you can go ahead and execute the script - [[Script FollowJSON]] +now you can go ahead and execute the script - :ref:`Script FollowJSON ` Peter Manev diff --git a/doc/sphinx/output/files-json-log-output/postgresql.rst b/doc/sphinx/output/files-json-log-output/postgresql.rst index 3fdb1f2cff5c..7f0cb1b732f3 100644 --- a/doc/sphinx/output/files-json-log-output/postgresql.rst +++ b/doc/sphinx/output/files-json-log-output/postgresql.rst @@ -67,14 +67,14 @@ Log out and log in again (with the "filejson" user) to test if everything is ok: -Optionally you could create and import the MD5 white list data if you wish - generally the same guidance as described in: -[[Filemd5 and white/black listing with MD5]] +Optionally you could create and import the MD5 white list data if you wish - generally the same guidance as described in :ref:`FileMD5 and white/black listing with md5 ` Some more general info and basic commands/queries: http://jazstudios.blogspot.se/2010/06/postgresql-login-commands.html http://www.thegeekstuff.com/2009/05/15-advanced-postgresql-commands-with-examples/ -now you can go ahead and execute the script - [[Script FollowJSON]] +now you can go ahead and execute the script - :ref:`Script FollowJSON ` Peter Manev + diff --git a/doc/sphinx/output/files-json-log-output/script-follow-json.rst b/doc/sphinx/output/files-json-log-output/script-follow-json.rst index 3c88021c2174..a914fa4082bc 100644 --- a/doc/sphinx/output/files-json-log-output/script-follow-json.rst +++ b/doc/sphinx/output/files-json-log-output/script-follow-json.rst @@ -1,3 +1,5 @@ +.. _script-follow-json: + Script FollowJSON ================= From 347e3b49726e0ad6e32c96f9779438855dc4900c Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 5 Jan 2016 20:47:50 +0100 Subject: [PATCH 1815/2553] doc: fixed remaining FIXME --- doc/sphinx/configuration/suricata-yaml.rst | 10 +++++----- doc/sphinx/output/.custom-http-logging.rst.swp | Bin 12288 -> 0 bytes doc/sphinx/output/.index.rst.swp | Bin 12288 -> 0 bytes doc/sphinx/output/.mongodb.rst.swp | Bin 16384 -> 0 bytes doc/sphinx/output/.syslog-alerting-comp.rst.swp | Bin 12288 -> 0 bytes doc/sphinx/output/eve/eve-json-format.rst | 2 ++ doc/sphinx/output/eve/eve-json-output.rst | 2 ++ .../.files-json-log-output.rst.swp | Bin 12288 -> 0 bytes ...logstash-kibana-and-suricata-json-output.rst | 2 +- doc/sphinx/rules/payload-keywords.rst | 4 +--- doc/sphinx/rules/pcre.rst | 4 ---- 11 files changed, 11 insertions(+), 13 deletions(-) delete mode 100644 doc/sphinx/output/.custom-http-logging.rst.swp delete mode 100644 doc/sphinx/output/.index.rst.swp delete mode 100644 doc/sphinx/output/.mongodb.rst.swp delete mode 100644 doc/sphinx/output/.syslog-alerting-comp.rst.swp delete mode 100644 doc/sphinx/output/files-json-log-output/.files-json-log-output.rst.swp diff --git a/doc/sphinx/configuration/suricata-yaml.rst b/doc/sphinx/configuration/suricata-yaml.rst index 6a2867fe2829..f318e1c5ed63 100644 --- a/doc/sphinx/configuration/suricata-yaml.rst +++ b/doc/sphinx/configuration/suricata-yaml.rst @@ -276,9 +276,9 @@ integration with tools like logstash. #- drop - ssh -For more advanced configuration options, see [[**FIXME** EveJSONOutput]]. -.. FIXME jsonformat ref -The format is documented in :ref:`Eve JSON Format ` +For more advanced configuration options, see :ref:`Eve JSON Output `. + +The format is documented in :ref:`Eve JSON Format `. Log output for use with Barnyard (unified.log) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -350,7 +350,7 @@ This log keeps track of all HTTP-traffic events. It contains the HTTP request, hostname, URI and the User-Agent. This information will be stored in the http.log (default name, in the suricata log directory). This logging can also be performed through the use of the -[[**FIXME** EveJSONFormat|Eve-log capability]]. +:ref:`Eve-log capability `. Example of a HTTP-log line with non-extended logging: @@ -384,7 +384,7 @@ This log keeps track of all DNS events (queries and replies). It contains the type of DNS activity that has been performed, the requested / replied domain name and relevant data suck as client, server, ttl, resource record data. This logging can also be performed -through the use of the [[EveJSONFormat|Eve-log capability]] which +through the use of the :ref:`Eve-log capability ` which offers easier parsing. Example of the apperance of a DNS log of a query with a preceding reply: diff --git a/doc/sphinx/output/.custom-http-logging.rst.swp b/doc/sphinx/output/.custom-http-logging.rst.swp deleted file mode 100644 index 8f40092872278afb4d7fa267bba193d607c7a372..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeHNO^+N$8LmLWcleYD7o-K?&(?YWVTI$mIQm3WTVBg!%7%gHQhDS757wi zs;YNp)-n75IBynA>=uSC}vuFo^}&zFAmZvEwy{o`fExXPt}{j7_dtXSA*^ zJ>UfRE^zBJjC}`q8#n@9{WN1=2cG{FV;=?n_({h80Q>}a4|o&!0`U7!F!np30RH}Q z#{LHU7|4LH0>Akf>I?t@ya^0}uK+Ir-p8MNKf9}Apkv@e!N9&+k+T09CwD*C zrbQu)ppz4lmRuoxU&?eYt}^yA^^U1eR+v+)R%zo%)$@rkzGeSW%i%HcJckL^H&kfI zN(pl=4&jel9v^as2Dp$(E8(h>b8q$j{{OGu*y88izP0@5+}6rYQS+HatS&J-lpu9b_aRG6|^^OmrcR#wnKGm88uKg%~U5c&vh zR-QGg^crm)Om<%x@A;0l>F8>sU?X?6ZL}ECVQ?Vhm>Uc43=%>y9qvQOJp@7%A&r~0 zDZR%Ngvov3+9ieq)cugB@T7l3n*}$y$o+2*WlEv!E(E|MX*Ry{#=Dll3qym`fg#$G zaNM*p$l)%62G*k7Z@Ib}R=$G{eLe$ye$gX+h5+XAZZx2+lO(xLcP6!R^>unns(MLs zG#*_ibDAbeG`LDPMRs4u!$C5@PeM1O5mUX4ePa`<4>os7K6|I$uOXVvjcQcjH=)Mh zJGb5fhgn(Ys68a~H7li73g)Ky=`8`t&+Bkm}}&;!Z&zXT@3?gTF*)mWqQuoZAiS7 zXoo^tFW^qf*r6j^=(|3nWbEN zb7&@<*R?dH7b+O!7nRdy#)Y&6IgQ{J!EC95%Lx4Kwg;?I!n>tuu5&qEHF5IT;=V0x zID*q50eQoFYf-`CGDrMlX2M}IufRFN>4}sPg;a$d{LiVI8XptjbitdG~H2u2VUIl<={^cYK( zi)FN&mxPQ#O=6;CZx|(`ag;=RNqTKJ8H}m_ns39~Q8e7$jgoOXMi{106Fr_rhp>B) zjFP?oDklqV%6yZNf-AUt-}dioBY5AfszPhkpXidGaC$@UnZfN4=Y#T6DSBg^r5!&8cv)?)cH)j z^3k0lK+j)=cnV!py3~8nd!yewNP9YY99@WH#yW5Fj$q){Y6q+uL~I68Yg z^&eHQ;hQV%9bdYzTySK=349?o)#K;Z2ZLy9eNy8S@v+Fq;nZH9VxL=6T5s2RQ{X7j zhL`=Ohp$af@ze<4-wxZ|ey1&Mk5+tMVn-2FO~zRlv?E!C4-=oqM2>vJJ@sA!7JI(m qd|j+3p(NTt?0d~*T&;JDubuF7p8Kk+CYtg0^ph8RJ@B$Qfc*<}VB@y{ diff --git a/doc/sphinx/output/.index.rst.swp b/doc/sphinx/output/.index.rst.swp deleted file mode 100644 index cfd31020081d4caf33d3442d3e210222119ebdb8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI&v2N2q7zgk#tW^QEV;4iEZ08GYB~VZwphLw(_RGbwFHL-w?+jrnOSe8k=RN^T z_r3ue5)+DW3llddX_R$j@G)zTH2$>-8mzNox3`6!vkrSt8Z zq5=XCXcwsbSiD%L-JNH>P`v&0Nwm4~x_uogAOHafKmY;|fB*y_0D*fW;EN8u=eK## zywO^7?fh|VhPXfg0uX=z1Rwwb2tWV=5P$##AaDl-)QIToL!#azet7==zx@CIlgB?e z-#OQuE6zvG2hJJigrhlOU6-@P`NsQv;e6s;az1m=AOHafKmY;|fB*y_009U<00RF> zAc~@?O`TUR6GvvKawYhn`OWN2r@noAv@90Ov*=>tY%Uh3&{s--ceyt<)5I+b`FERQ z`On$<2s mtO)ae?^mhjLBj3iO|p7~K8_=AwJ(#T-zVCy8@;Me+S4z*8lPtX diff --git a/doc/sphinx/output/.mongodb.rst.swp b/doc/sphinx/output/.mongodb.rst.swp deleted file mode 100644 index e07477ba338a00305b275652c1c539017f66a284..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 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 diff --git a/doc/sphinx/output/.syslog-alerting-comp.rst.swp b/doc/sphinx/output/.syslog-alerting-comp.rst.swp deleted file mode 100644 index 24ad1a76e335428e22c0bdf8674420fac7e0e2ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeHN&5smC6faa%RMd!)Xhe&}O<*%0EFVG!{2&AZ2?%kK#G5tU)iVV>U7f1xT_!Pl zQcS#X)c6O8R})Q4JZR912NO+9JaaVh5Ab6Ay;t3{1M=Zj(i7g!Y)$q1_`TnIuQt?h z_xY2j<$>Nlf!C8lJiqPZ^Pe3Wh!2*8P(^BJ`ED=elJT0q+b$vABZd9a*$X-ezV9n% z5*1WGwMpNXV^dt}+bWb*==-V9?Wn7A?Sd&r-Na7Hp7Y`EHrgF60xbf!K%fd)_uyu+ zchB-}`gX^{cDd!Lw{EeqU1||%5oi%;5oi%;5oi%;5oi%;5x7?o2;~OxK7zZi4)C@5 zeZx)f^{?$)i$IG&i$IG&i$IG&i$IG&i$IG&i$IG&i$IIO{}2I{3h@*E_`iNXoX7wF zH-G@(kqn2ZZY~`5p4R;%%^gwWooiaJ6!~6 z3OR)msf$(PY%!s=RF@hTdWsQr$+fWxGG5z}snQc$cvib|^4Mv5R90|cSOqz@rOv7x z2H2fw(;DcbU9c0zS~@ct!+>$PC}eEWLvJ7juE#fm1r{u8t=)s3RqYUM81r(_06_)7P?ovT>42=gG+S+ycjUt1 z#j|goTzqvgDhg^eSRU-%v$#0%qrqU{%dW|~h3zi;(DfxRFD}gabOKls{;HTEzc!{d z3VEfz4Mk3S>u4XjPw>`$Pqg=Hq>;ixy116g%(@AXCuCU*!Hq}trIMh-!<5@nIZvOl zV?s|WQpt$b&-bJ}8IiATCAP@SsB((nmze=cc2>UfiV_D6eI1gBpyF=}HPJFR7m>QC zp+_1d;+Xq&R|k7>i%Y6By#aY3-iFL=o=;6-R=H|LyIX&U2>sjs`hdzg9?zZ&uU3 zg9?`;tj?_J%yAanFP&5ry@foD)$uq-MV=GTQitsXbz}fYkF`>W< zJt$MgVJ{OhrM5$fn9JnMY2t7us{+>wH4%?eO3pUwx$CX_6%@#-A_16B_(9uy@;Dx@ zJ7b4@q|OLlt-IGD7Dd#&d{>T~E^7<`T#|Be^i5$x@1~9f$H?=EDyC35Wv*rhG{UvV zJCU~H>gDcPw-D;y(6C-Ob^YA_O&o_I%KIIPgY5_b7zw;Ot#yZ?l{@q(Axc(GIsFxSDD|FsK;#qf7 z!mOKjK^1(P?c({PsG<6*EUgRj+|jcgdG6FoM^36dm~I$5t%!deHg5qTohHVrNRW|C ztAMigvI&K5{}!YFW)J54oIPsGH>pS4pllnOB(w-GIn|7J=X?`f3HdTjk%O(qqo6bF2qiSrd*@0zdF zlnRLGcB7)q*~xlEqk7_bj#_L@@f#d&CTH{IyahV1PMyT)NFj{J~e@w`kJwhuU16K_lWIz@4G?R?^Xe9yvRDxFNw8=F& zBNN2sRE~Z>YI+Y&HXUwQxgi!tVxpIWPh9yH#X}y_U@3fX6(0(?_jn!R9_mF^*;H_5 zQEOEC6kKnrCOMaAv(g+Z;-Qba0>v_GOtCYEX~_*NhPZRa=3V6ah#aE_*Lc*^2nRH; X-03A&;&eVz-=&vF>lSTt6Q<%HmaB5g diff --git a/doc/sphinx/output/eve/eve-json-format.rst b/doc/sphinx/output/eve/eve-json-format.rst index a3d68ef67f46..61a4f33433b5 100644 --- a/doc/sphinx/output/eve/eve-json-format.rst +++ b/doc/sphinx/output/eve/eve-json-format.rst @@ -1,3 +1,5 @@ +.. _eve-json-format: + Eve JSON Format =============== diff --git a/doc/sphinx/output/eve/eve-json-output.rst b/doc/sphinx/output/eve/eve-json-output.rst index 2606f6c92909..8d42930d8657 100644 --- a/doc/sphinx/output/eve/eve-json-output.rst +++ b/doc/sphinx/output/eve/eve-json-output.rst @@ -1,3 +1,5 @@ +.. _eve-json-output: + Eve JSON Output =============== diff --git a/doc/sphinx/output/files-json-log-output/.files-json-log-output.rst.swp b/doc/sphinx/output/files-json-log-output/.files-json-log-output.rst.swp deleted file mode 100644 index b00f05e585001fc0774948dc0065008081b07522..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeHN&u<$=6rLg#QD}j-f-8fOs#dCZy|&{dM*K>`A*i9P+?I-qKOz3+W9t0*t- zT-n^B%R!&u^E4r+PJMRe=8Hq}eMkr^Q(?RB^^Yb6q9 zSeVKr)YVj!yP>R2Rhw`ka<1FkT9)lxX6^s#4U{(b-rCRb3_RQn)MnCNIYxTjsAGwE zq4hjHdE)ZJ&54iRGvFEU40r}S1D*lTfM>un@Q^WJszc;`#Qex2?w1$OL;rd%n*QM# z@ChOqAN#LAtRQ$c93?T^CgodXqeBwaEk0SEiv< z7}W;rF%s_4@BBplWu^l{>=ehN?G=WmLZMtUpYKcD>5>_74FNQK%Sl7ItJ*vhkQ%O{ zFR8VW1x?_!&DKH=GhwFGkxQ}Doh0lTI~~{gjvaz?MwGRz^%-OVTs5T0$%HEegYmk8 zoUqZJ4nRd4LLgIPs$m$;X0yPSkOop^p-m(>vUy?1OiCwwc2GuF zBS;G*o~4a9NCJY*A@~e}&A=ut1TtvFi12x7-0_6Mwm~`Kn{mDqG^FhlEBu6{=8$1t zP3qk00b*!kLpB3qec^73Rilj?Ww?!`6D74q65TPi{NlJ*SVHJ~gtoMJhqs2byV@N@ z)V2+xP0=%9xeWtdMY@D`E9T2-yu?>ozaI@)KkD| zKX-og`bN`PuuLSj^R?0X<|Z|K*PNwJP0r;UcM657xnA^^(ls$r6#{~lN;^Yb<31aQ z-5`pB&NxiD-Z8QohrM8F9J+ju!ve=ONOZHHW#fGt_mJIu98MG~_)MxDJq}~0P^f%g z_8MzbTt3#EjZ`E-948`3WKi$G#b$=$&^cFjlGF1z96Lp0DrOer(9X08D&fw-o`LqX z!cecfy3%ckwat}|`;EKP$VBGo8MuyA8)3&=(JIIptOR{LR+k(0wMv@7l}^y@tp?p_ zIf#~{W>8c}0ao^%9U}_d&#Y){f#OaCx;s&~9Sw#{-Qkj3J%|Qw@w+&&L)?mMOydQS z+k3{ID16xgN3f{`rzi?{+H~pP(|;~@tXhR0lD)SEoidFsoXS|_0tXl83vs9Q;*7f+ z%hj0&Fi9KhR@KyQfgtp>y(3~)vNldjd#_@>sZ4KX+qt+4aHYidCyp)7R(tWvY~x6^ zi@Cm*Jaqd2!zz4U)R Gl79e$FZbsF diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst b/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst index 10e5d87f25cb..adbb73aa6681 100644 --- a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst +++ b/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst @@ -41,7 +41,7 @@ Make sure your Suricata is compiled/installed with libjansson support enabled: CUDA enabled: no ... -If it isn't check out the [[**FIXME** Suricata_installation]] page to install or compile Suricata for your distribution. +If it isn't check out the `Suricata Installation `_ page to install or compile Suricata for your distribution. **NOTE:** you will need these packages installed -> **libjansson4** and *libjansson-dev* before compilation. Configure suricata diff --git a/doc/sphinx/rules/payload-keywords.rst b/doc/sphinx/rules/payload-keywords.rst index b5f400ac4514..6104c5ba7973 100644 --- a/doc/sphinx/rules/payload-keywords.rst +++ b/doc/sphinx/rules/payload-keywords.rst @@ -228,9 +228,7 @@ The first example illustrates a signature which searches for byte 512 of the payload. The second example illustrates a signature searching for byte 50 after the last match. -You can also use the negation (!) before isdataat. Suricata does not -support using it yet, but will support it in future versions of the -engine. For more information see **fixme: what is this supposed to link to**. +You can also use the negation (!) before isdataat. .. image:: payload-keywords/isdataat1.png diff --git a/doc/sphinx/rules/pcre.rst b/doc/sphinx/rules/pcre.rst index 9af548421403..784b56681c97 100644 --- a/doc/sphinx/rules/pcre.rst +++ b/doc/sphinx/rules/pcre.rst @@ -79,10 +79,6 @@ Suricata has its own specific pcre modifiers. These are: relative to the previous match so both matches have to be in the HTTP-raw-uri buffer. Read more about :doc:`http-uri-normalization`. -** FIXME - image is missing on wiki: .. image:: pcre/pcre7.png - -** FIXME - image is missing on wiki: .. image:: pcre/pcre8.png - * ``P``: Makes pcre match on the HTTP- request-body. So, it matches on the same buffer as http_client_body. P can be combined with /R. Note that R is relative to the previous match so both matches have to be From c0aacec9b77bdd59f0d928ca84abf4e3e081d44e Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 5 Jan 2016 20:55:12 +0100 Subject: [PATCH 1816/2553] doc: reorder duplicates --- doc/sphinx/configuration/index.rst | 1 - doc/sphinx/output/index.rst | 3 +- .../{configuration => output}/lua-output.rst | 0 doc/sphinx/rules/index.rst | 2 +- doc/sphinx/rules/rule-profiling.rst | 33 ------------------- 5 files changed, 2 insertions(+), 37 deletions(-) rename doc/sphinx/{configuration => output}/lua-output.rst (100%) delete mode 100644 doc/sphinx/rules/rule-profiling.rst diff --git a/doc/sphinx/configuration/index.rst b/doc/sphinx/configuration/index.rst index d620646ffaae..6327c7274cdc 100644 --- a/doc/sphinx/configuration/index.rst +++ b/doc/sphinx/configuration/index.rst @@ -7,5 +7,4 @@ Configuration global-thresholds snort-to-suricata log-rotation - lua-output multi-tenant diff --git a/doc/sphinx/output/index.rst b/doc/sphinx/output/index.rst index 94c9e2bde3ae..40aec04dc047 100644 --- a/doc/sphinx/output/index.rst +++ b/doc/sphinx/output/index.rst @@ -4,8 +4,7 @@ Output .. toctree:: eve/index.rst - ../configuration/lua-output + lua-output syslog-alerting-comp custom-http-logging - ../configuration/log-rotation files-json-log-output/files-json-log-output.rst diff --git a/doc/sphinx/configuration/lua-output.rst b/doc/sphinx/output/lua-output.rst similarity index 100% rename from doc/sphinx/configuration/lua-output.rst rename to doc/sphinx/output/lua-output.rst diff --git a/doc/sphinx/rules/index.rst b/doc/sphinx/rules/index.rst index 6f73db0cf62f..f4b5446aef19 100644 --- a/doc/sphinx/rules/index.rst +++ b/doc/sphinx/rules/index.rst @@ -18,6 +18,6 @@ Suricata Rules dns-keywords tls-keywords normalized-buffers - rule-profiling modbus-keyword dnp3-keywords + diff --git a/doc/sphinx/rules/rule-profiling.rst b/doc/sphinx/rules/rule-profiling.rst deleted file mode 100644 index 099cdb8d612a..000000000000 --- a/doc/sphinx/rules/rule-profiling.rst +++ /dev/null @@ -1,33 +0,0 @@ -Rule Profiling -============== - -:: - - -------------------------------------------------------------------------- - Date: 9/5/2013 -- 14:59:58 - -------------------------------------------------------------------------- - Num Rule Gid Rev Ticks % Checks Matches Max Ticks Avg Ticks Avg Match Avg No Match - -------- ------------ -------- -------- ------------ ------ -------- -------- ----------- ----------- ----------- -------------- - 1 2210021 1 3 12037 4.96 1 1 12037 12037.00 12037.00 0.00 - 2 2210054 1 1 107479 44.26 12 0 35805 8956.58 0.00 8956.58 - 3 2210053 1 1 4513 1.86 1 0 4513 4513.00 0.00 4513.00 - 4 2210023 1 1 3077 1.27 1 0 3077 3077.00 0.00 3077.00 - 5 2210008 1 1 3028 1.25 1 0 3028 3028.00 0.00 3028.00 - 6 2210009 1 1 2945 1.21 1 0 2945 2945.00 0.00 2945.00 - 7 2210055 1 1 2945 1.21 1 0 2945 2945.00 0.00 2945.00 - 8 2210007 1 1 2871 1.18 1 0 2871 2871.00 0.00 2871.00 - 9 2210005 1 1 2871 1.18 1 0 2871 2871.00 0.00 2871.00 - 10 2210024 1 1 2846 1.17 1 0 2846 2846.00 0.00 2846.00 - -The meaning of the individual fields: - -* Ticks -- total ticks spent on this rule, so a sum of all inspections -* % -- share of this single sig in the total cost of inspection -* Checks -- number of times a signature was inspected -* Matches -- number of times it matched. This may not have resulted in an alert due to suppression and thresholding. -* Max ticks -- single most expensive inspection -* Avg ticks -- per inspection average, so "ticks" / "checks". -* Avg match -- avg ticks spent resulting in match -* Avg No Match -- avg ticks spent resulting in no match. - -The "ticks" are CPU clock ticks: http://en.wikipedia.org/wiki/CPU_time From 11eb8640ddb32e44019089559c00851f0d07fc0d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 27 Jan 2016 14:50:37 -0600 Subject: [PATCH 1817/2553] doc: acknowledge doc/wiki authors --- doc/sphinx/acknowledgements.rst | 38 +++++++++++++++++++++++++++++++++ doc/sphinx/index.rst | 1 + 2 files changed, 39 insertions(+) create mode 100644 doc/sphinx/acknowledgements.rst diff --git a/doc/sphinx/acknowledgements.rst b/doc/sphinx/acknowledgements.rst new file mode 100644 index 000000000000..add6bb565adc --- /dev/null +++ b/doc/sphinx/acknowledgements.rst @@ -0,0 +1,38 @@ +Acknowledgements +================ + +Thank you to the following for their Wiki and documentation +contributions that have made this user guide possible: + +- Andreas Herz +- Andreas Moe +- Anne-Fleur Koolstra +- Christophe Vandeplas +- Darren Spruell +- David Cannings +- David Diallo +- David Wharton +- Eric Leblond +- god lol +- Haris Haq +- Ignacio Sanchez +- Jason Ish +- Jason Taylor +- Josh Smith +- Ken Steele +- Les Syv +- Mark Solaris +- Martin Holste +- Mats Klepsland +- Matt Jonkman +- Michael Bentley +- Michael Hrishenko +- Nathan Jimerson +- Nicolas Merle +- Peter Manev +- Philipp Buehler +- Rob MacGregor +- Russel Fulton +- Victor Julien +- Vincent Fang +- Zach Rasmor diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 02b03ffd64c3..248613d8612b 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -20,3 +20,4 @@ Suricata User Guide file-extraction/file-extraction.rst public-data-sets capture-hardware/index.rst + acknowledgements From 8d47c13d2a7d3f6d1d26062132a43ad650a201e7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 4 Feb 2016 10:18:20 -0600 Subject: [PATCH 1818/2553] doc: new global threshold examples from Peter Manev. --- doc/sphinx/configuration/global-thresholds.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/sphinx/configuration/global-thresholds.rst b/doc/sphinx/configuration/global-thresholds.rst index 183e2c4cddc6..a5acbe406873 100644 --- a/doc/sphinx/configuration/global-thresholds.rst +++ b/doc/sphinx/configuration/global-thresholds.rst @@ -37,7 +37,7 @@ Syntax: suppress gen_id , sig_id suppress gen_id , sig_id , track , ip -Example: +Examples: :: @@ -46,6 +46,12 @@ Example: This will make sure the signature 2002087 will never match for src host 209.132.180.67. +Other possibilities/examples:: + + suppress gen_id 1, sig_id 2003614, track by_src, ip 217.110.97.128/25 + suppress gen_id 1, sig_id 2003614, track by_src, ip [192.168.0.0/16,10.0.0.0/8,172.16.0.0/12] + suppress gen_id 1, sig_id 2003614, track by_src, ip $HOME_NET + .. _global-thresholds-vs-rule-thresholds: Global thresholds vs rule thresholds From 16f6fab502a7d177dbdbfc516d9a744275a803f6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Sep 2016 15:57:31 -0600 Subject: [PATCH 1819/2553] doc: user .. option:: for command line option formatting --- doc/sphinx/command-line-options.rst | 92 ++++++++++++++++++----------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/doc/sphinx/command-line-options.rst b/doc/sphinx/command-line-options.rst index 80542da49c82..29d32e9600bf 100644 --- a/doc/sphinx/command-line-options.rst +++ b/doc/sphinx/command-line-options.rst @@ -14,62 +14,88 @@ this: -a --long-option -:: +.. option:: -c + + The -c option the most important option. After -c you can enter the + path to the location of suricata.yaml. + +.. option:: -i + + After the -i option you can enter the interface card you would like + to use to sniff packets from. It concerns sniffing packets with + libpcap in the pcap live mode. + +.. option:: -r + + After the -r option you can enter the path to the pcap-file in + which packets are recorded. That way you can inspect the packets in + that file in the pcap/offline mode. +.. option:: -s - -c The -c option the most important option. After -c you can enter the path to the location of - suricata.yaml. + With the -s option you can set a file with signatures, which will + be loaded together with the rules set in yaml. - -i After the -i option you can enter the interface card you would like to use to sniff packets from. - It concerns sniffing packets with libpcap in the pcap live mode. +.. option:: -l - -r After the -r option you can enter the path to the pcap-file in which packets are recorded. That way - you can inspect the packets in that file in the pcap/offline mode. + With the -l option you can set the default log directory. If you + already have the default-log-dir set in yaml, it will not be used + by Suricata if you use the -l option. It will use the log dir that + is set with the -l option. If you do not set a directory with + the -l option, Suricata will use the directory that is set in yaml. - -s With the -s option you can set a file with signatures, which will be loaded together with the rules - set in yaml. +.. option:: -D - -l With the -l option you can set the default log directory. If you already have the default-log-dir set - in yaml, it will not be used by Suricata if you use the -l option. It will use the log dir that is set - with the -l - option. If you do not set a directory with the -l option, Suricata will use the directory that is set - in yaml. + Normally if you run Suricata on your console, it keeps your console + occupied. You can not use it for other purposes, and when you close + the window, Suricata stops running. If you run Suricata as deamon + (using the -D option), it runs at the background and you will be + able to use the console for other tasks without disturbing the + engine running. +.. option:: --list-app-layer-protos - -D Normally if you run Suricata on your console, it keeps your console occupied. You - can not use it for other purposes, and when you close the window, Suricata stops running. - If you run Suricata as deamon (using the -D option), it runs at the background and you will be able - to use the console for other tasks without disturbing the engine running. + List supported app layer protocols. - --list-app-layer-protos : list supported app layer protocols +.. option:: --list-keywords[=all|csv|] - --list-keywords[=all|csv|] : list keywords implemented by the engine + List keywords implemented by the engine +.. option:: --list-runmodes - --list-runmodes The option --list-runmodes lists all possible runmodes. + The option --list-runmodes lists all possible runmodes. - --runmode (in combination with the command line opion -i or -r) - With the --runmode option you can - set the runmode that you would like to use. This command line option can override the - yaml runmode option. +.. option:: --runmode + + (in combination with the command line opion -i or -r) With + the --runmode option you can set the runmode that you would like to + use. This command line option can override the yaml runmode option. For more information about runmodes see: :doc:`performance/runmodes` Unit Tests ~~~~~~~~~~ -:: +.. option:: -u + + With the -u option you can run unit tests to test Suricata's code. + +.. option:: -U + + With the -U option you can select which of the unit tests you want + to run. This option uses REGEX. Example of use: suricata -u -U + http - -u With the -u option you can run unit tests to test Suricata's code. +.. option:: --list-unittests - -U With the -U option you can select which of the unit tests you want to run. This option uses REGEX. - Example of use: - suricata -u -U http + The --list-unittests option shows a list with all possible unit + tests. - --list-unittests The --list-unittests option shows a list with all possible unit tests. +.. option:: --fatal-unittests - --fatal-unittests With the --fatal-unittests option you can run unit tests but it will stop immediately after one test fails - so you can see directly where it went wrong. + With the --fatal-unittests option you can run unit tests but it + will stop immediately after one test fails so you can see directly + where it went wrong. PF_RING options ~~~~~~~~~~~~~~~ From 2751baae4641b4d3c9b0d53b7de40a8cbcea923a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 18 Feb 2016 14:46:21 -0600 Subject: [PATCH 1820/2553] doc: rename from "sphinx" to "userguide" --- doc/sphinx/.gitignore | 3 --- doc/{sphinx => userguide}/Makefile | 0 doc/{sphinx => userguide}/README.md | 0 doc/{sphinx => userguide}/_static/.gitignore | 0 doc/{sphinx => userguide}/acknowledgements.rst | 0 .../capture-hardware/endace-dag.rst | 0 .../capture-hardware/index.rst | 0 .../capture-hardware/myricom.rst | 0 doc/{sphinx => userguide}/command-line-options.rst | 0 doc/{sphinx => userguide}/conf.py | 0 .../configuration/global-thresholds.rst | 0 doc/{sphinx => userguide}/configuration/index.rst | 0 .../configuration/log-rotation.rst | 0 .../configuration/multi-tenant.rst | 0 .../configuration/snort-to-suricata.rst | 0 .../configuration/suricata-yaml.rst | 0 .../configuration/suricata-yaml/IDS_chunk_size.png | Bin .../suricata-yaml/Inline_reassembly_unackd_data.png | Bin .../configuration/suricata-yaml/MPM2.png | Bin .../configuration/suricata-yaml/NFQ.png | Bin .../configuration/suricata-yaml/NFQ1.png | Bin .../configuration/suricata-yaml/NFQ2.png | Bin .../suricata-yaml/Normal_ids_ack_d.png | Bin .../configuration/suricata-yaml/Tuple1.png | Bin .../suricata-yaml/balancing_workload.png | Bin .../configuration/suricata-yaml/flow.png | Bin .../configuration/suricata-yaml/grouping_tree.png | Bin .../suricata-yaml/grouping_tree_detail.png | Bin .../configuration/suricata-yaml/inline_mode.png | Bin .../suricata-yaml/ipfw_reinjection.png | Bin .../configuration/suricata-yaml/normal_ids.png | Bin .../configuration/suricata-yaml/overlap.png | Bin .../configuration/suricata-yaml/reassembly1.png | Bin .../configuration/suricata-yaml/threading.png | Bin doc/{sphinx => userguide}/convert.py | 0 doc/{sphinx => userguide}/dropping-privileges.rst | 0 .../file-extraction/file-extraction.rst | 0 .../filemd5-and-whiteblacklisting-with-md5.rst | 0 doc/{sphinx => userguide}/file-extraction/md5.rst | 0 .../file-extraction/public-sha1-md5-data-sets.rst | 0 doc/{sphinx => userguide}/index.rst | 0 doc/{sphinx => userguide}/initscripts.rst | 0 doc/{sphinx => userguide}/make-sense-alerts.rst | 0 doc/{sphinx => userguide}/oinkmaster.rst | 0 .../oinkmaster/oinkmasterconf.png | Bin .../oinkmaster/suricata_yaml.png | Bin .../output/custom-http-logging.rst | 0 .../output/eve/eve-json-examplesjq.rst | 0 .../output/eve/eve-json-format.rst | 0 .../output/eve/eve-json-output.rst | 0 doc/{sphinx => userguide}/output/eve/index.rst | 0 .../files-json-log-output/files-json-log-output.rst | 0 .../logstash-kibana-and-suricata-json-output.rst | 0 .../Logstash1.png | Bin .../Logstash2.png | Bin .../Logstash3.png | Bin .../Logstash4.png | Bin .../Logstash5.png | Bin .../Logstash6.png | Bin .../output/files-json-log-output/mongodb.rst | 0 .../output/files-json-log-output/mysql.rst | 0 .../output/files-json-log-output/postgresql.rst | 1 - .../files-json-log-output/script-follow-json.rst | 0 .../useful-queries-for-mysql-and-postgresql.rst | 0 doc/{sphinx => userguide}/output/index.rst | 0 doc/{sphinx => userguide}/output/lua-output.rst | 0 .../output/syslog-alerting-comp.rst | 0 .../performance/high-performance-config.rst | 0 .../performance/ignoring-traffic.rst | 0 doc/{sphinx => userguide}/performance/index.rst | 0 .../performance/packet-profiling.rst | 0 .../performance/rule-profiling.rst | 0 doc/{sphinx => userguide}/performance/runmodes.rst | 0 .../performance/runmodes/Runmode_autofp.png | Bin .../performance/runmodes/threading1.png | Bin .../performance/statistics.rst | 0 doc/{sphinx => userguide}/performance/tcmalloc.rst | 0 .../performance/tuning-considerations.rst | 0 doc/{sphinx => userguide}/public-data-sets.rst | 0 doc/{sphinx => userguide}/reputation/index.rst | 0 .../ipreputation/ip-reputation-config.rst | 0 .../ipreputation/ip-reputation-format.rst | 0 .../reputation/ipreputation/ip-reputation-rules.rst | 0 .../reputation/ipreputation/ip-reputation.rst | 0 .../rules/adding-your-own-rules.rst | 0 doc/{sphinx => userguide}/rules/dnp3-keywords.rst | 0 doc/{sphinx => userguide}/rules/dns-keywords.rst | 0 .../rules/dns-keywords/dns_query.png | Bin .../rules/fast-pattern-explained.rst | 0 doc/{sphinx => userguide}/rules/fast-pattern.rst | 0 .../rules/fast-pattern/fast_pattern.png | Bin doc/{sphinx => userguide}/rules/file-keywords.rst | 0 doc/{sphinx => userguide}/rules/flow-keywords.rst | 0 .../rules/flow-keywords/Flow1.png | Bin .../rules/flow-keywords/Flow2.png | Bin .../rules/flow-keywords/Flowbit_3.png | Bin doc/{sphinx => userguide}/rules/flowint.rst | 0 doc/{sphinx => userguide}/rules/header-keywords.rst | 0 .../rules/header-keywords/ICMP_type_code.png | Bin .../rules/header-keywords/ICMP_types.png | Bin .../rules/header-keywords/Window.png | Bin .../rules/header-keywords/Wireshark_ack.png | Bin .../rules/header-keywords/Wireshark_seq.png | Bin .../rules/header-keywords/ack.png | Bin .../rules/header-keywords/fragbits.png | Bin .../rules/header-keywords/fragoffset.png | Bin .../rules/header-keywords/icmp_id.png | Bin .../rules/header-keywords/icmp_seq.png | Bin .../rules/header-keywords/icmp_type.png | Bin .../rules/header-keywords/icode.png | Bin .../rules/header-keywords/id.png | Bin .../rules/header-keywords/ip_proto.png | Bin .../rules/header-keywords/ipopts.png | Bin .../rules/header-keywords/ipopts_rule.png | Bin .../rules/header-keywords/sameip.png | Bin .../rules/header-keywords/seq.png | Bin .../rules/header-keywords/ttl.png | Bin doc/{sphinx => userguide}/rules/http-keywords.rst | 0 .../rules/http-keywords/Legenda_rules.png | Bin .../rules/http-keywords/client_body.png | Bin .../rules/http-keywords/client_body1.png | Bin .../rules/http-keywords/cookie.png | Bin .../rules/http-keywords/cookie1.png | Bin .../rules/http-keywords/fast_pattern.png | Bin .../rules/http-keywords/file_data.png | Bin .../rules/http-keywords/header.png | Bin .../rules/http-keywords/header1.png | Bin .../rules/http-keywords/http_server_body.png | Bin .../rules/http-keywords/http_uri.png | Bin .../rules/http-keywords/method.png | Bin .../rules/http-keywords/method1.png | Bin .../rules/http-keywords/method2.png | Bin .../rules/http-keywords/request.png | Bin .../rules/http-keywords/request2.png | Bin .../rules/http-keywords/response1.png | Bin .../rules/http-keywords/stat-code1.png | Bin .../rules/http-keywords/stat_code.png | Bin .../rules/http-keywords/stat_msg.png | Bin .../rules/http-keywords/stat_msg_1.png | Bin .../rules/http-keywords/uri.png | Bin .../rules/http-keywords/uri1.png | Bin .../rules/http-keywords/uricontent.png | Bin .../rules/http-keywords/uricontent1.png | Bin .../rules/http-keywords/urilen.png | Bin .../rules/http-keywords/urilen1.png | Bin .../rules/http-keywords/user_agent.png | Bin .../rules/http-keywords/user_agent_match.png | Bin .../rules/http-uri-normalization.rst | 0 doc/{sphinx => userguide}/rules/index.rst | 1 - doc/{sphinx => userguide}/rules/intro.rst | 0 doc/{sphinx => userguide}/rules/intro/Dest_port.png | Bin doc/{sphinx => userguide}/rules/intro/Direction.png | Bin .../rules/intro/Source-port.png | Bin doc/{sphinx => userguide}/rules/intro/Source.png | Bin .../rules/intro/TCP-session.png | Bin doc/{sphinx => userguide}/rules/intro/action.png | Bin .../rules/intro/destination.png | Bin doc/{sphinx => userguide}/rules/intro/intro_sig.png | Bin doc/{sphinx => userguide}/rules/intro/protocol.png | Bin doc/{sphinx => userguide}/rules/live-rule-swap.rst | 0 doc/{sphinx => userguide}/rules/meta.rst | 0 .../rules/meta/classification.png | Bin doc/{sphinx => userguide}/rules/meta/classtype.png | Bin doc/{sphinx => userguide}/rules/meta/gid.png | Bin doc/{sphinx => userguide}/rules/meta/msg.png | Bin doc/{sphinx => userguide}/rules/meta/reference.png | Bin doc/{sphinx => userguide}/rules/meta/rev.png | Bin doc/{sphinx => userguide}/rules/meta/sid.png | Bin doc/{sphinx => userguide}/rules/modbus-keyword.rst | 0 .../rules/normalized-buffers.rst | 0 .../rules/normalized-buffers/normalization1.png | Bin .../rules/payload-keywords.rst | 0 .../rules/payload-keywords/Legenda_rules.png | Bin .../rules/payload-keywords/content.png | Bin .../rules/payload-keywords/content2.png | Bin .../rules/payload-keywords/content3.png | Bin .../rules/payload-keywords/content4.png | Bin .../rules/payload-keywords/content5.png | Bin .../rules/payload-keywords/content6.png | Bin .../rules/payload-keywords/distance.png | Bin .../rules/payload-keywords/distance1.png | Bin .../rules/payload-keywords/distance3.png | Bin .../rules/payload-keywords/distance4.png | Bin .../rules/payload-keywords/distance5.png | Bin .../rules/payload-keywords/dsize.png | Bin .../rules/payload-keywords/isdataat1.png | Bin .../rules/payload-keywords/replace.png | Bin .../rules/payload-keywords/replace1.png | Bin .../rules/payload-keywords/rpc.png | Bin .../rules/payload-keywords/within1.png | Bin .../rules/payload-keywords/within2.png | Bin .../rules/payload-keywords/within_distance.png | Bin .../rules/payload-keywords/within_distance2.png | Bin doc/{sphinx => userguide}/rules/pcre.rst | 0 doc/{sphinx => userguide}/rules/pcre/pcre.png | Bin doc/{sphinx => userguide}/rules/pcre/pcre3.png | Bin doc/{sphinx => userguide}/rules/pcre/pcre4.png | Bin doc/{sphinx => userguide}/rules/pcre/pcre5.png | Bin doc/{sphinx => userguide}/rules/pcre/pcre6.png | Bin .../rules/rule-lua-scripting.rst | 0 doc/{sphinx => userguide}/rules/thresholding.rst | 0 doc/{sphinx => userguide}/rules/tls-keywords.rst | 0 .../setting-up-ipsinline-for-linux.rst | 0 .../setting-up-ipsinline-for-linux/IPtables.png | Bin .../setting-up-ipsinline-for-linux/IPtables3.png | Bin .../setting-up-ipsinline-for-linux/iptables1.png | Bin .../setting-up-ipsinline-for-linux/iptables2.png | Bin .../setting-up-ipsinline-for-linux/iptables4.png | Bin .../setting-up-ipsinline-for-linux/iptables_vnL.png | Bin doc/{sphinx => userguide}/snort-compatibility.rst | 0 doc/{sphinx => userguide}/what-is-suricata.rst | 0 211 files changed, 5 deletions(-) delete mode 100644 doc/sphinx/.gitignore rename doc/{sphinx => userguide}/Makefile (100%) rename doc/{sphinx => userguide}/README.md (100%) rename doc/{sphinx => userguide}/_static/.gitignore (100%) rename doc/{sphinx => userguide}/acknowledgements.rst (100%) rename doc/{sphinx => userguide}/capture-hardware/endace-dag.rst (100%) rename doc/{sphinx => userguide}/capture-hardware/index.rst (100%) rename doc/{sphinx => userguide}/capture-hardware/myricom.rst (100%) rename doc/{sphinx => userguide}/command-line-options.rst (100%) rename doc/{sphinx => userguide}/conf.py (100%) rename doc/{sphinx => userguide}/configuration/global-thresholds.rst (100%) rename doc/{sphinx => userguide}/configuration/index.rst (100%) rename doc/{sphinx => userguide}/configuration/log-rotation.rst (100%) rename doc/{sphinx => userguide}/configuration/multi-tenant.rst (100%) rename doc/{sphinx => userguide}/configuration/snort-to-suricata.rst (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml.rst (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/IDS_chunk_size.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/Inline_reassembly_unackd_data.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/MPM2.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/NFQ.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/NFQ1.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/NFQ2.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/Normal_ids_ack_d.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/Tuple1.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/balancing_workload.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/flow.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/grouping_tree.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/grouping_tree_detail.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/inline_mode.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/ipfw_reinjection.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/normal_ids.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/overlap.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/reassembly1.png (100%) rename doc/{sphinx => userguide}/configuration/suricata-yaml/threading.png (100%) rename doc/{sphinx => userguide}/convert.py (100%) rename doc/{sphinx => userguide}/dropping-privileges.rst (100%) rename doc/{sphinx => userguide}/file-extraction/file-extraction.rst (100%) rename doc/{sphinx => userguide}/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst (100%) rename doc/{sphinx => userguide}/file-extraction/md5.rst (100%) rename doc/{sphinx => userguide}/file-extraction/public-sha1-md5-data-sets.rst (100%) rename doc/{sphinx => userguide}/index.rst (100%) rename doc/{sphinx => userguide}/initscripts.rst (100%) rename doc/{sphinx => userguide}/make-sense-alerts.rst (100%) rename doc/{sphinx => userguide}/oinkmaster.rst (100%) rename doc/{sphinx => userguide}/oinkmaster/oinkmasterconf.png (100%) rename doc/{sphinx => userguide}/oinkmaster/suricata_yaml.png (100%) rename doc/{sphinx => userguide}/output/custom-http-logging.rst (100%) rename doc/{sphinx => userguide}/output/eve/eve-json-examplesjq.rst (100%) rename doc/{sphinx => userguide}/output/eve/eve-json-format.rst (100%) rename doc/{sphinx => userguide}/output/eve/eve-json-output.rst (100%) rename doc/{sphinx => userguide}/output/eve/index.rst (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/files-json-log-output.rst (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash1.png (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash2.png (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash3.png (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash4.png (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash5.png (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash6.png (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/mongodb.rst (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/mysql.rst (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/postgresql.rst (99%) rename doc/{sphinx => userguide}/output/files-json-log-output/script-follow-json.rst (100%) rename doc/{sphinx => userguide}/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst (100%) rename doc/{sphinx => userguide}/output/index.rst (100%) rename doc/{sphinx => userguide}/output/lua-output.rst (100%) rename doc/{sphinx => userguide}/output/syslog-alerting-comp.rst (100%) rename doc/{sphinx => userguide}/performance/high-performance-config.rst (100%) rename doc/{sphinx => userguide}/performance/ignoring-traffic.rst (100%) rename doc/{sphinx => userguide}/performance/index.rst (100%) rename doc/{sphinx => userguide}/performance/packet-profiling.rst (100%) rename doc/{sphinx => userguide}/performance/rule-profiling.rst (100%) rename doc/{sphinx => userguide}/performance/runmodes.rst (100%) rename doc/{sphinx => userguide}/performance/runmodes/Runmode_autofp.png (100%) rename doc/{sphinx => userguide}/performance/runmodes/threading1.png (100%) rename doc/{sphinx => userguide}/performance/statistics.rst (100%) rename doc/{sphinx => userguide}/performance/tcmalloc.rst (100%) rename doc/{sphinx => userguide}/performance/tuning-considerations.rst (100%) rename doc/{sphinx => userguide}/public-data-sets.rst (100%) rename doc/{sphinx => userguide}/reputation/index.rst (100%) rename doc/{sphinx => userguide}/reputation/ipreputation/ip-reputation-config.rst (100%) rename doc/{sphinx => userguide}/reputation/ipreputation/ip-reputation-format.rst (100%) rename doc/{sphinx => userguide}/reputation/ipreputation/ip-reputation-rules.rst (100%) rename doc/{sphinx => userguide}/reputation/ipreputation/ip-reputation.rst (100%) rename doc/{sphinx => userguide}/rules/adding-your-own-rules.rst (100%) rename doc/{sphinx => userguide}/rules/dnp3-keywords.rst (100%) rename doc/{sphinx => userguide}/rules/dns-keywords.rst (100%) rename doc/{sphinx => userguide}/rules/dns-keywords/dns_query.png (100%) rename doc/{sphinx => userguide}/rules/fast-pattern-explained.rst (100%) rename doc/{sphinx => userguide}/rules/fast-pattern.rst (100%) rename doc/{sphinx => userguide}/rules/fast-pattern/fast_pattern.png (100%) rename doc/{sphinx => userguide}/rules/file-keywords.rst (100%) rename doc/{sphinx => userguide}/rules/flow-keywords.rst (100%) rename doc/{sphinx => userguide}/rules/flow-keywords/Flow1.png (100%) rename doc/{sphinx => userguide}/rules/flow-keywords/Flow2.png (100%) rename doc/{sphinx => userguide}/rules/flow-keywords/Flowbit_3.png (100%) rename doc/{sphinx => userguide}/rules/flowint.rst (100%) rename doc/{sphinx => userguide}/rules/header-keywords.rst (100%) rename doc/{sphinx => userguide}/rules/header-keywords/ICMP_type_code.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/ICMP_types.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/Window.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/Wireshark_ack.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/Wireshark_seq.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/ack.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/fragbits.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/fragoffset.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/icmp_id.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/icmp_seq.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/icmp_type.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/icode.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/id.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/ip_proto.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/ipopts.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/ipopts_rule.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/sameip.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/seq.png (100%) rename doc/{sphinx => userguide}/rules/header-keywords/ttl.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords.rst (100%) rename doc/{sphinx => userguide}/rules/http-keywords/Legenda_rules.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/client_body.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/client_body1.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/cookie.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/cookie1.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/fast_pattern.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/file_data.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/header.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/header1.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/http_server_body.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/http_uri.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/method.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/method1.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/method2.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/request.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/request2.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/response1.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/stat-code1.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/stat_code.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/stat_msg.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/stat_msg_1.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/uri.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/uri1.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/uricontent.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/uricontent1.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/urilen.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/urilen1.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/user_agent.png (100%) rename doc/{sphinx => userguide}/rules/http-keywords/user_agent_match.png (100%) rename doc/{sphinx => userguide}/rules/http-uri-normalization.rst (100%) rename doc/{sphinx => userguide}/rules/index.rst (99%) rename doc/{sphinx => userguide}/rules/intro.rst (100%) rename doc/{sphinx => userguide}/rules/intro/Dest_port.png (100%) rename doc/{sphinx => userguide}/rules/intro/Direction.png (100%) rename doc/{sphinx => userguide}/rules/intro/Source-port.png (100%) rename doc/{sphinx => userguide}/rules/intro/Source.png (100%) rename doc/{sphinx => userguide}/rules/intro/TCP-session.png (100%) rename doc/{sphinx => userguide}/rules/intro/action.png (100%) rename doc/{sphinx => userguide}/rules/intro/destination.png (100%) rename doc/{sphinx => userguide}/rules/intro/intro_sig.png (100%) rename doc/{sphinx => userguide}/rules/intro/protocol.png (100%) rename doc/{sphinx => userguide}/rules/live-rule-swap.rst (100%) rename doc/{sphinx => userguide}/rules/meta.rst (100%) rename doc/{sphinx => userguide}/rules/meta/classification.png (100%) rename doc/{sphinx => userguide}/rules/meta/classtype.png (100%) rename doc/{sphinx => userguide}/rules/meta/gid.png (100%) rename doc/{sphinx => userguide}/rules/meta/msg.png (100%) rename doc/{sphinx => userguide}/rules/meta/reference.png (100%) rename doc/{sphinx => userguide}/rules/meta/rev.png (100%) rename doc/{sphinx => userguide}/rules/meta/sid.png (100%) rename doc/{sphinx => userguide}/rules/modbus-keyword.rst (100%) rename doc/{sphinx => userguide}/rules/normalized-buffers.rst (100%) rename doc/{sphinx => userguide}/rules/normalized-buffers/normalization1.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords.rst (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/Legenda_rules.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/content.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/content2.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/content3.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/content4.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/content5.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/content6.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/distance.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/distance1.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/distance3.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/distance4.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/distance5.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/dsize.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/isdataat1.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/replace.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/replace1.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/rpc.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/within1.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/within2.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/within_distance.png (100%) rename doc/{sphinx => userguide}/rules/payload-keywords/within_distance2.png (100%) rename doc/{sphinx => userguide}/rules/pcre.rst (100%) rename doc/{sphinx => userguide}/rules/pcre/pcre.png (100%) rename doc/{sphinx => userguide}/rules/pcre/pcre3.png (100%) rename doc/{sphinx => userguide}/rules/pcre/pcre4.png (100%) rename doc/{sphinx => userguide}/rules/pcre/pcre5.png (100%) rename doc/{sphinx => userguide}/rules/pcre/pcre6.png (100%) rename doc/{sphinx => userguide}/rules/rule-lua-scripting.rst (100%) rename doc/{sphinx => userguide}/rules/thresholding.rst (100%) rename doc/{sphinx => userguide}/rules/tls-keywords.rst (100%) rename doc/{sphinx => userguide}/setting-up-ipsinline-for-linux.rst (100%) rename doc/{sphinx => userguide}/setting-up-ipsinline-for-linux/IPtables.png (100%) rename doc/{sphinx => userguide}/setting-up-ipsinline-for-linux/IPtables3.png (100%) rename doc/{sphinx => userguide}/setting-up-ipsinline-for-linux/iptables1.png (100%) rename doc/{sphinx => userguide}/setting-up-ipsinline-for-linux/iptables2.png (100%) rename doc/{sphinx => userguide}/setting-up-ipsinline-for-linux/iptables4.png (100%) rename doc/{sphinx => userguide}/setting-up-ipsinline-for-linux/iptables_vnL.png (100%) rename doc/{sphinx => userguide}/snort-compatibility.rst (100%) rename doc/{sphinx => userguide}/what-is-suricata.rst (100%) diff --git a/doc/sphinx/.gitignore b/doc/sphinx/.gitignore deleted file mode 100644 index bc1208ccebf8..000000000000 --- a/doc/sphinx/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -!Makefile -_build -node_modules diff --git a/doc/sphinx/Makefile b/doc/userguide/Makefile similarity index 100% rename from doc/sphinx/Makefile rename to doc/userguide/Makefile diff --git a/doc/sphinx/README.md b/doc/userguide/README.md similarity index 100% rename from doc/sphinx/README.md rename to doc/userguide/README.md diff --git a/doc/sphinx/_static/.gitignore b/doc/userguide/_static/.gitignore similarity index 100% rename from doc/sphinx/_static/.gitignore rename to doc/userguide/_static/.gitignore diff --git a/doc/sphinx/acknowledgements.rst b/doc/userguide/acknowledgements.rst similarity index 100% rename from doc/sphinx/acknowledgements.rst rename to doc/userguide/acknowledgements.rst diff --git a/doc/sphinx/capture-hardware/endace-dag.rst b/doc/userguide/capture-hardware/endace-dag.rst similarity index 100% rename from doc/sphinx/capture-hardware/endace-dag.rst rename to doc/userguide/capture-hardware/endace-dag.rst diff --git a/doc/sphinx/capture-hardware/index.rst b/doc/userguide/capture-hardware/index.rst similarity index 100% rename from doc/sphinx/capture-hardware/index.rst rename to doc/userguide/capture-hardware/index.rst diff --git a/doc/sphinx/capture-hardware/myricom.rst b/doc/userguide/capture-hardware/myricom.rst similarity index 100% rename from doc/sphinx/capture-hardware/myricom.rst rename to doc/userguide/capture-hardware/myricom.rst diff --git a/doc/sphinx/command-line-options.rst b/doc/userguide/command-line-options.rst similarity index 100% rename from doc/sphinx/command-line-options.rst rename to doc/userguide/command-line-options.rst diff --git a/doc/sphinx/conf.py b/doc/userguide/conf.py similarity index 100% rename from doc/sphinx/conf.py rename to doc/userguide/conf.py diff --git a/doc/sphinx/configuration/global-thresholds.rst b/doc/userguide/configuration/global-thresholds.rst similarity index 100% rename from doc/sphinx/configuration/global-thresholds.rst rename to doc/userguide/configuration/global-thresholds.rst diff --git a/doc/sphinx/configuration/index.rst b/doc/userguide/configuration/index.rst similarity index 100% rename from doc/sphinx/configuration/index.rst rename to doc/userguide/configuration/index.rst diff --git a/doc/sphinx/configuration/log-rotation.rst b/doc/userguide/configuration/log-rotation.rst similarity index 100% rename from doc/sphinx/configuration/log-rotation.rst rename to doc/userguide/configuration/log-rotation.rst diff --git a/doc/sphinx/configuration/multi-tenant.rst b/doc/userguide/configuration/multi-tenant.rst similarity index 100% rename from doc/sphinx/configuration/multi-tenant.rst rename to doc/userguide/configuration/multi-tenant.rst diff --git a/doc/sphinx/configuration/snort-to-suricata.rst b/doc/userguide/configuration/snort-to-suricata.rst similarity index 100% rename from doc/sphinx/configuration/snort-to-suricata.rst rename to doc/userguide/configuration/snort-to-suricata.rst diff --git a/doc/sphinx/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst similarity index 100% rename from doc/sphinx/configuration/suricata-yaml.rst rename to doc/userguide/configuration/suricata-yaml.rst diff --git a/doc/sphinx/configuration/suricata-yaml/IDS_chunk_size.png b/doc/userguide/configuration/suricata-yaml/IDS_chunk_size.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/IDS_chunk_size.png rename to doc/userguide/configuration/suricata-yaml/IDS_chunk_size.png diff --git a/doc/sphinx/configuration/suricata-yaml/Inline_reassembly_unackd_data.png b/doc/userguide/configuration/suricata-yaml/Inline_reassembly_unackd_data.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/Inline_reassembly_unackd_data.png rename to doc/userguide/configuration/suricata-yaml/Inline_reassembly_unackd_data.png diff --git a/doc/sphinx/configuration/suricata-yaml/MPM2.png b/doc/userguide/configuration/suricata-yaml/MPM2.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/MPM2.png rename to doc/userguide/configuration/suricata-yaml/MPM2.png diff --git a/doc/sphinx/configuration/suricata-yaml/NFQ.png b/doc/userguide/configuration/suricata-yaml/NFQ.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/NFQ.png rename to doc/userguide/configuration/suricata-yaml/NFQ.png diff --git a/doc/sphinx/configuration/suricata-yaml/NFQ1.png b/doc/userguide/configuration/suricata-yaml/NFQ1.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/NFQ1.png rename to doc/userguide/configuration/suricata-yaml/NFQ1.png diff --git a/doc/sphinx/configuration/suricata-yaml/NFQ2.png b/doc/userguide/configuration/suricata-yaml/NFQ2.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/NFQ2.png rename to doc/userguide/configuration/suricata-yaml/NFQ2.png diff --git a/doc/sphinx/configuration/suricata-yaml/Normal_ids_ack_d.png b/doc/userguide/configuration/suricata-yaml/Normal_ids_ack_d.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/Normal_ids_ack_d.png rename to doc/userguide/configuration/suricata-yaml/Normal_ids_ack_d.png diff --git a/doc/sphinx/configuration/suricata-yaml/Tuple1.png b/doc/userguide/configuration/suricata-yaml/Tuple1.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/Tuple1.png rename to doc/userguide/configuration/suricata-yaml/Tuple1.png diff --git a/doc/sphinx/configuration/suricata-yaml/balancing_workload.png b/doc/userguide/configuration/suricata-yaml/balancing_workload.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/balancing_workload.png rename to doc/userguide/configuration/suricata-yaml/balancing_workload.png diff --git a/doc/sphinx/configuration/suricata-yaml/flow.png b/doc/userguide/configuration/suricata-yaml/flow.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/flow.png rename to doc/userguide/configuration/suricata-yaml/flow.png diff --git a/doc/sphinx/configuration/suricata-yaml/grouping_tree.png b/doc/userguide/configuration/suricata-yaml/grouping_tree.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/grouping_tree.png rename to doc/userguide/configuration/suricata-yaml/grouping_tree.png diff --git a/doc/sphinx/configuration/suricata-yaml/grouping_tree_detail.png b/doc/userguide/configuration/suricata-yaml/grouping_tree_detail.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/grouping_tree_detail.png rename to doc/userguide/configuration/suricata-yaml/grouping_tree_detail.png diff --git a/doc/sphinx/configuration/suricata-yaml/inline_mode.png b/doc/userguide/configuration/suricata-yaml/inline_mode.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/inline_mode.png rename to doc/userguide/configuration/suricata-yaml/inline_mode.png diff --git a/doc/sphinx/configuration/suricata-yaml/ipfw_reinjection.png b/doc/userguide/configuration/suricata-yaml/ipfw_reinjection.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/ipfw_reinjection.png rename to doc/userguide/configuration/suricata-yaml/ipfw_reinjection.png diff --git a/doc/sphinx/configuration/suricata-yaml/normal_ids.png b/doc/userguide/configuration/suricata-yaml/normal_ids.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/normal_ids.png rename to doc/userguide/configuration/suricata-yaml/normal_ids.png diff --git a/doc/sphinx/configuration/suricata-yaml/overlap.png b/doc/userguide/configuration/suricata-yaml/overlap.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/overlap.png rename to doc/userguide/configuration/suricata-yaml/overlap.png diff --git a/doc/sphinx/configuration/suricata-yaml/reassembly1.png b/doc/userguide/configuration/suricata-yaml/reassembly1.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/reassembly1.png rename to doc/userguide/configuration/suricata-yaml/reassembly1.png diff --git a/doc/sphinx/configuration/suricata-yaml/threading.png b/doc/userguide/configuration/suricata-yaml/threading.png similarity index 100% rename from doc/sphinx/configuration/suricata-yaml/threading.png rename to doc/userguide/configuration/suricata-yaml/threading.png diff --git a/doc/sphinx/convert.py b/doc/userguide/convert.py similarity index 100% rename from doc/sphinx/convert.py rename to doc/userguide/convert.py diff --git a/doc/sphinx/dropping-privileges.rst b/doc/userguide/dropping-privileges.rst similarity index 100% rename from doc/sphinx/dropping-privileges.rst rename to doc/userguide/dropping-privileges.rst diff --git a/doc/sphinx/file-extraction/file-extraction.rst b/doc/userguide/file-extraction/file-extraction.rst similarity index 100% rename from doc/sphinx/file-extraction/file-extraction.rst rename to doc/userguide/file-extraction/file-extraction.rst diff --git a/doc/sphinx/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst b/doc/userguide/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst similarity index 100% rename from doc/sphinx/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst rename to doc/userguide/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst diff --git a/doc/sphinx/file-extraction/md5.rst b/doc/userguide/file-extraction/md5.rst similarity index 100% rename from doc/sphinx/file-extraction/md5.rst rename to doc/userguide/file-extraction/md5.rst diff --git a/doc/sphinx/file-extraction/public-sha1-md5-data-sets.rst b/doc/userguide/file-extraction/public-sha1-md5-data-sets.rst similarity index 100% rename from doc/sphinx/file-extraction/public-sha1-md5-data-sets.rst rename to doc/userguide/file-extraction/public-sha1-md5-data-sets.rst diff --git a/doc/sphinx/index.rst b/doc/userguide/index.rst similarity index 100% rename from doc/sphinx/index.rst rename to doc/userguide/index.rst diff --git a/doc/sphinx/initscripts.rst b/doc/userguide/initscripts.rst similarity index 100% rename from doc/sphinx/initscripts.rst rename to doc/userguide/initscripts.rst diff --git a/doc/sphinx/make-sense-alerts.rst b/doc/userguide/make-sense-alerts.rst similarity index 100% rename from doc/sphinx/make-sense-alerts.rst rename to doc/userguide/make-sense-alerts.rst diff --git a/doc/sphinx/oinkmaster.rst b/doc/userguide/oinkmaster.rst similarity index 100% rename from doc/sphinx/oinkmaster.rst rename to doc/userguide/oinkmaster.rst diff --git a/doc/sphinx/oinkmaster/oinkmasterconf.png b/doc/userguide/oinkmaster/oinkmasterconf.png similarity index 100% rename from doc/sphinx/oinkmaster/oinkmasterconf.png rename to doc/userguide/oinkmaster/oinkmasterconf.png diff --git a/doc/sphinx/oinkmaster/suricata_yaml.png b/doc/userguide/oinkmaster/suricata_yaml.png similarity index 100% rename from doc/sphinx/oinkmaster/suricata_yaml.png rename to doc/userguide/oinkmaster/suricata_yaml.png diff --git a/doc/sphinx/output/custom-http-logging.rst b/doc/userguide/output/custom-http-logging.rst similarity index 100% rename from doc/sphinx/output/custom-http-logging.rst rename to doc/userguide/output/custom-http-logging.rst diff --git a/doc/sphinx/output/eve/eve-json-examplesjq.rst b/doc/userguide/output/eve/eve-json-examplesjq.rst similarity index 100% rename from doc/sphinx/output/eve/eve-json-examplesjq.rst rename to doc/userguide/output/eve/eve-json-examplesjq.rst diff --git a/doc/sphinx/output/eve/eve-json-format.rst b/doc/userguide/output/eve/eve-json-format.rst similarity index 100% rename from doc/sphinx/output/eve/eve-json-format.rst rename to doc/userguide/output/eve/eve-json-format.rst diff --git a/doc/sphinx/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst similarity index 100% rename from doc/sphinx/output/eve/eve-json-output.rst rename to doc/userguide/output/eve/eve-json-output.rst diff --git a/doc/sphinx/output/eve/index.rst b/doc/userguide/output/eve/index.rst similarity index 100% rename from doc/sphinx/output/eve/index.rst rename to doc/userguide/output/eve/index.rst diff --git a/doc/sphinx/output/files-json-log-output/files-json-log-output.rst b/doc/userguide/output/files-json-log-output/files-json-log-output.rst similarity index 100% rename from doc/sphinx/output/files-json-log-output/files-json-log-output.rst rename to doc/userguide/output/files-json-log-output/files-json-log-output.rst diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst b/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst similarity index 100% rename from doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst rename to doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash1.png b/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash1.png similarity index 100% rename from doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash1.png rename to doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash1.png diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash2.png b/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash2.png similarity index 100% rename from doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash2.png rename to doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash2.png diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash3.png b/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash3.png similarity index 100% rename from doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash3.png rename to doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash3.png diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash4.png b/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash4.png similarity index 100% rename from doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash4.png rename to doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash4.png diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash5.png b/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash5.png similarity index 100% rename from doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash5.png rename to doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash5.png diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash6.png b/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash6.png similarity index 100% rename from doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash6.png rename to doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash6.png diff --git a/doc/sphinx/output/files-json-log-output/mongodb.rst b/doc/userguide/output/files-json-log-output/mongodb.rst similarity index 100% rename from doc/sphinx/output/files-json-log-output/mongodb.rst rename to doc/userguide/output/files-json-log-output/mongodb.rst diff --git a/doc/sphinx/output/files-json-log-output/mysql.rst b/doc/userguide/output/files-json-log-output/mysql.rst similarity index 100% rename from doc/sphinx/output/files-json-log-output/mysql.rst rename to doc/userguide/output/files-json-log-output/mysql.rst diff --git a/doc/sphinx/output/files-json-log-output/postgresql.rst b/doc/userguide/output/files-json-log-output/postgresql.rst similarity index 99% rename from doc/sphinx/output/files-json-log-output/postgresql.rst rename to doc/userguide/output/files-json-log-output/postgresql.rst index 7f0cb1b732f3..256fea4d4dab 100644 --- a/doc/sphinx/output/files-json-log-output/postgresql.rst +++ b/doc/userguide/output/files-json-log-output/postgresql.rst @@ -77,4 +77,3 @@ http://www.thegeekstuff.com/2009/05/15-advanced-postgresql-commands-with-example now you can go ahead and execute the script - :ref:`Script FollowJSON ` Peter Manev - diff --git a/doc/sphinx/output/files-json-log-output/script-follow-json.rst b/doc/userguide/output/files-json-log-output/script-follow-json.rst similarity index 100% rename from doc/sphinx/output/files-json-log-output/script-follow-json.rst rename to doc/userguide/output/files-json-log-output/script-follow-json.rst diff --git a/doc/sphinx/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst b/doc/userguide/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst similarity index 100% rename from doc/sphinx/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst rename to doc/userguide/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst diff --git a/doc/sphinx/output/index.rst b/doc/userguide/output/index.rst similarity index 100% rename from doc/sphinx/output/index.rst rename to doc/userguide/output/index.rst diff --git a/doc/sphinx/output/lua-output.rst b/doc/userguide/output/lua-output.rst similarity index 100% rename from doc/sphinx/output/lua-output.rst rename to doc/userguide/output/lua-output.rst diff --git a/doc/sphinx/output/syslog-alerting-comp.rst b/doc/userguide/output/syslog-alerting-comp.rst similarity index 100% rename from doc/sphinx/output/syslog-alerting-comp.rst rename to doc/userguide/output/syslog-alerting-comp.rst diff --git a/doc/sphinx/performance/high-performance-config.rst b/doc/userguide/performance/high-performance-config.rst similarity index 100% rename from doc/sphinx/performance/high-performance-config.rst rename to doc/userguide/performance/high-performance-config.rst diff --git a/doc/sphinx/performance/ignoring-traffic.rst b/doc/userguide/performance/ignoring-traffic.rst similarity index 100% rename from doc/sphinx/performance/ignoring-traffic.rst rename to doc/userguide/performance/ignoring-traffic.rst diff --git a/doc/sphinx/performance/index.rst b/doc/userguide/performance/index.rst similarity index 100% rename from doc/sphinx/performance/index.rst rename to doc/userguide/performance/index.rst diff --git a/doc/sphinx/performance/packet-profiling.rst b/doc/userguide/performance/packet-profiling.rst similarity index 100% rename from doc/sphinx/performance/packet-profiling.rst rename to doc/userguide/performance/packet-profiling.rst diff --git a/doc/sphinx/performance/rule-profiling.rst b/doc/userguide/performance/rule-profiling.rst similarity index 100% rename from doc/sphinx/performance/rule-profiling.rst rename to doc/userguide/performance/rule-profiling.rst diff --git a/doc/sphinx/performance/runmodes.rst b/doc/userguide/performance/runmodes.rst similarity index 100% rename from doc/sphinx/performance/runmodes.rst rename to doc/userguide/performance/runmodes.rst diff --git a/doc/sphinx/performance/runmodes/Runmode_autofp.png b/doc/userguide/performance/runmodes/Runmode_autofp.png similarity index 100% rename from doc/sphinx/performance/runmodes/Runmode_autofp.png rename to doc/userguide/performance/runmodes/Runmode_autofp.png diff --git a/doc/sphinx/performance/runmodes/threading1.png b/doc/userguide/performance/runmodes/threading1.png similarity index 100% rename from doc/sphinx/performance/runmodes/threading1.png rename to doc/userguide/performance/runmodes/threading1.png diff --git a/doc/sphinx/performance/statistics.rst b/doc/userguide/performance/statistics.rst similarity index 100% rename from doc/sphinx/performance/statistics.rst rename to doc/userguide/performance/statistics.rst diff --git a/doc/sphinx/performance/tcmalloc.rst b/doc/userguide/performance/tcmalloc.rst similarity index 100% rename from doc/sphinx/performance/tcmalloc.rst rename to doc/userguide/performance/tcmalloc.rst diff --git a/doc/sphinx/performance/tuning-considerations.rst b/doc/userguide/performance/tuning-considerations.rst similarity index 100% rename from doc/sphinx/performance/tuning-considerations.rst rename to doc/userguide/performance/tuning-considerations.rst diff --git a/doc/sphinx/public-data-sets.rst b/doc/userguide/public-data-sets.rst similarity index 100% rename from doc/sphinx/public-data-sets.rst rename to doc/userguide/public-data-sets.rst diff --git a/doc/sphinx/reputation/index.rst b/doc/userguide/reputation/index.rst similarity index 100% rename from doc/sphinx/reputation/index.rst rename to doc/userguide/reputation/index.rst diff --git a/doc/sphinx/reputation/ipreputation/ip-reputation-config.rst b/doc/userguide/reputation/ipreputation/ip-reputation-config.rst similarity index 100% rename from doc/sphinx/reputation/ipreputation/ip-reputation-config.rst rename to doc/userguide/reputation/ipreputation/ip-reputation-config.rst diff --git a/doc/sphinx/reputation/ipreputation/ip-reputation-format.rst b/doc/userguide/reputation/ipreputation/ip-reputation-format.rst similarity index 100% rename from doc/sphinx/reputation/ipreputation/ip-reputation-format.rst rename to doc/userguide/reputation/ipreputation/ip-reputation-format.rst diff --git a/doc/sphinx/reputation/ipreputation/ip-reputation-rules.rst b/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst similarity index 100% rename from doc/sphinx/reputation/ipreputation/ip-reputation-rules.rst rename to doc/userguide/reputation/ipreputation/ip-reputation-rules.rst diff --git a/doc/sphinx/reputation/ipreputation/ip-reputation.rst b/doc/userguide/reputation/ipreputation/ip-reputation.rst similarity index 100% rename from doc/sphinx/reputation/ipreputation/ip-reputation.rst rename to doc/userguide/reputation/ipreputation/ip-reputation.rst diff --git a/doc/sphinx/rules/adding-your-own-rules.rst b/doc/userguide/rules/adding-your-own-rules.rst similarity index 100% rename from doc/sphinx/rules/adding-your-own-rules.rst rename to doc/userguide/rules/adding-your-own-rules.rst diff --git a/doc/sphinx/rules/dnp3-keywords.rst b/doc/userguide/rules/dnp3-keywords.rst similarity index 100% rename from doc/sphinx/rules/dnp3-keywords.rst rename to doc/userguide/rules/dnp3-keywords.rst diff --git a/doc/sphinx/rules/dns-keywords.rst b/doc/userguide/rules/dns-keywords.rst similarity index 100% rename from doc/sphinx/rules/dns-keywords.rst rename to doc/userguide/rules/dns-keywords.rst diff --git a/doc/sphinx/rules/dns-keywords/dns_query.png b/doc/userguide/rules/dns-keywords/dns_query.png similarity index 100% rename from doc/sphinx/rules/dns-keywords/dns_query.png rename to doc/userguide/rules/dns-keywords/dns_query.png diff --git a/doc/sphinx/rules/fast-pattern-explained.rst b/doc/userguide/rules/fast-pattern-explained.rst similarity index 100% rename from doc/sphinx/rules/fast-pattern-explained.rst rename to doc/userguide/rules/fast-pattern-explained.rst diff --git a/doc/sphinx/rules/fast-pattern.rst b/doc/userguide/rules/fast-pattern.rst similarity index 100% rename from doc/sphinx/rules/fast-pattern.rst rename to doc/userguide/rules/fast-pattern.rst diff --git a/doc/sphinx/rules/fast-pattern/fast_pattern.png b/doc/userguide/rules/fast-pattern/fast_pattern.png similarity index 100% rename from doc/sphinx/rules/fast-pattern/fast_pattern.png rename to doc/userguide/rules/fast-pattern/fast_pattern.png diff --git a/doc/sphinx/rules/file-keywords.rst b/doc/userguide/rules/file-keywords.rst similarity index 100% rename from doc/sphinx/rules/file-keywords.rst rename to doc/userguide/rules/file-keywords.rst diff --git a/doc/sphinx/rules/flow-keywords.rst b/doc/userguide/rules/flow-keywords.rst similarity index 100% rename from doc/sphinx/rules/flow-keywords.rst rename to doc/userguide/rules/flow-keywords.rst diff --git a/doc/sphinx/rules/flow-keywords/Flow1.png b/doc/userguide/rules/flow-keywords/Flow1.png similarity index 100% rename from doc/sphinx/rules/flow-keywords/Flow1.png rename to doc/userguide/rules/flow-keywords/Flow1.png diff --git a/doc/sphinx/rules/flow-keywords/Flow2.png b/doc/userguide/rules/flow-keywords/Flow2.png similarity index 100% rename from doc/sphinx/rules/flow-keywords/Flow2.png rename to doc/userguide/rules/flow-keywords/Flow2.png diff --git a/doc/sphinx/rules/flow-keywords/Flowbit_3.png b/doc/userguide/rules/flow-keywords/Flowbit_3.png similarity index 100% rename from doc/sphinx/rules/flow-keywords/Flowbit_3.png rename to doc/userguide/rules/flow-keywords/Flowbit_3.png diff --git a/doc/sphinx/rules/flowint.rst b/doc/userguide/rules/flowint.rst similarity index 100% rename from doc/sphinx/rules/flowint.rst rename to doc/userguide/rules/flowint.rst diff --git a/doc/sphinx/rules/header-keywords.rst b/doc/userguide/rules/header-keywords.rst similarity index 100% rename from doc/sphinx/rules/header-keywords.rst rename to doc/userguide/rules/header-keywords.rst diff --git a/doc/sphinx/rules/header-keywords/ICMP_type_code.png b/doc/userguide/rules/header-keywords/ICMP_type_code.png similarity index 100% rename from doc/sphinx/rules/header-keywords/ICMP_type_code.png rename to doc/userguide/rules/header-keywords/ICMP_type_code.png diff --git a/doc/sphinx/rules/header-keywords/ICMP_types.png b/doc/userguide/rules/header-keywords/ICMP_types.png similarity index 100% rename from doc/sphinx/rules/header-keywords/ICMP_types.png rename to doc/userguide/rules/header-keywords/ICMP_types.png diff --git a/doc/sphinx/rules/header-keywords/Window.png b/doc/userguide/rules/header-keywords/Window.png similarity index 100% rename from doc/sphinx/rules/header-keywords/Window.png rename to doc/userguide/rules/header-keywords/Window.png diff --git a/doc/sphinx/rules/header-keywords/Wireshark_ack.png b/doc/userguide/rules/header-keywords/Wireshark_ack.png similarity index 100% rename from doc/sphinx/rules/header-keywords/Wireshark_ack.png rename to doc/userguide/rules/header-keywords/Wireshark_ack.png diff --git a/doc/sphinx/rules/header-keywords/Wireshark_seq.png b/doc/userguide/rules/header-keywords/Wireshark_seq.png similarity index 100% rename from doc/sphinx/rules/header-keywords/Wireshark_seq.png rename to doc/userguide/rules/header-keywords/Wireshark_seq.png diff --git a/doc/sphinx/rules/header-keywords/ack.png b/doc/userguide/rules/header-keywords/ack.png similarity index 100% rename from doc/sphinx/rules/header-keywords/ack.png rename to doc/userguide/rules/header-keywords/ack.png diff --git a/doc/sphinx/rules/header-keywords/fragbits.png b/doc/userguide/rules/header-keywords/fragbits.png similarity index 100% rename from doc/sphinx/rules/header-keywords/fragbits.png rename to doc/userguide/rules/header-keywords/fragbits.png diff --git a/doc/sphinx/rules/header-keywords/fragoffset.png b/doc/userguide/rules/header-keywords/fragoffset.png similarity index 100% rename from doc/sphinx/rules/header-keywords/fragoffset.png rename to doc/userguide/rules/header-keywords/fragoffset.png diff --git a/doc/sphinx/rules/header-keywords/icmp_id.png b/doc/userguide/rules/header-keywords/icmp_id.png similarity index 100% rename from doc/sphinx/rules/header-keywords/icmp_id.png rename to doc/userguide/rules/header-keywords/icmp_id.png diff --git a/doc/sphinx/rules/header-keywords/icmp_seq.png b/doc/userguide/rules/header-keywords/icmp_seq.png similarity index 100% rename from doc/sphinx/rules/header-keywords/icmp_seq.png rename to doc/userguide/rules/header-keywords/icmp_seq.png diff --git a/doc/sphinx/rules/header-keywords/icmp_type.png b/doc/userguide/rules/header-keywords/icmp_type.png similarity index 100% rename from doc/sphinx/rules/header-keywords/icmp_type.png rename to doc/userguide/rules/header-keywords/icmp_type.png diff --git a/doc/sphinx/rules/header-keywords/icode.png b/doc/userguide/rules/header-keywords/icode.png similarity index 100% rename from doc/sphinx/rules/header-keywords/icode.png rename to doc/userguide/rules/header-keywords/icode.png diff --git a/doc/sphinx/rules/header-keywords/id.png b/doc/userguide/rules/header-keywords/id.png similarity index 100% rename from doc/sphinx/rules/header-keywords/id.png rename to doc/userguide/rules/header-keywords/id.png diff --git a/doc/sphinx/rules/header-keywords/ip_proto.png b/doc/userguide/rules/header-keywords/ip_proto.png similarity index 100% rename from doc/sphinx/rules/header-keywords/ip_proto.png rename to doc/userguide/rules/header-keywords/ip_proto.png diff --git a/doc/sphinx/rules/header-keywords/ipopts.png b/doc/userguide/rules/header-keywords/ipopts.png similarity index 100% rename from doc/sphinx/rules/header-keywords/ipopts.png rename to doc/userguide/rules/header-keywords/ipopts.png diff --git a/doc/sphinx/rules/header-keywords/ipopts_rule.png b/doc/userguide/rules/header-keywords/ipopts_rule.png similarity index 100% rename from doc/sphinx/rules/header-keywords/ipopts_rule.png rename to doc/userguide/rules/header-keywords/ipopts_rule.png diff --git a/doc/sphinx/rules/header-keywords/sameip.png b/doc/userguide/rules/header-keywords/sameip.png similarity index 100% rename from doc/sphinx/rules/header-keywords/sameip.png rename to doc/userguide/rules/header-keywords/sameip.png diff --git a/doc/sphinx/rules/header-keywords/seq.png b/doc/userguide/rules/header-keywords/seq.png similarity index 100% rename from doc/sphinx/rules/header-keywords/seq.png rename to doc/userguide/rules/header-keywords/seq.png diff --git a/doc/sphinx/rules/header-keywords/ttl.png b/doc/userguide/rules/header-keywords/ttl.png similarity index 100% rename from doc/sphinx/rules/header-keywords/ttl.png rename to doc/userguide/rules/header-keywords/ttl.png diff --git a/doc/sphinx/rules/http-keywords.rst b/doc/userguide/rules/http-keywords.rst similarity index 100% rename from doc/sphinx/rules/http-keywords.rst rename to doc/userguide/rules/http-keywords.rst diff --git a/doc/sphinx/rules/http-keywords/Legenda_rules.png b/doc/userguide/rules/http-keywords/Legenda_rules.png similarity index 100% rename from doc/sphinx/rules/http-keywords/Legenda_rules.png rename to doc/userguide/rules/http-keywords/Legenda_rules.png diff --git a/doc/sphinx/rules/http-keywords/client_body.png b/doc/userguide/rules/http-keywords/client_body.png similarity index 100% rename from doc/sphinx/rules/http-keywords/client_body.png rename to doc/userguide/rules/http-keywords/client_body.png diff --git a/doc/sphinx/rules/http-keywords/client_body1.png b/doc/userguide/rules/http-keywords/client_body1.png similarity index 100% rename from doc/sphinx/rules/http-keywords/client_body1.png rename to doc/userguide/rules/http-keywords/client_body1.png diff --git a/doc/sphinx/rules/http-keywords/cookie.png b/doc/userguide/rules/http-keywords/cookie.png similarity index 100% rename from doc/sphinx/rules/http-keywords/cookie.png rename to doc/userguide/rules/http-keywords/cookie.png diff --git a/doc/sphinx/rules/http-keywords/cookie1.png b/doc/userguide/rules/http-keywords/cookie1.png similarity index 100% rename from doc/sphinx/rules/http-keywords/cookie1.png rename to doc/userguide/rules/http-keywords/cookie1.png diff --git a/doc/sphinx/rules/http-keywords/fast_pattern.png b/doc/userguide/rules/http-keywords/fast_pattern.png similarity index 100% rename from doc/sphinx/rules/http-keywords/fast_pattern.png rename to doc/userguide/rules/http-keywords/fast_pattern.png diff --git a/doc/sphinx/rules/http-keywords/file_data.png b/doc/userguide/rules/http-keywords/file_data.png similarity index 100% rename from doc/sphinx/rules/http-keywords/file_data.png rename to doc/userguide/rules/http-keywords/file_data.png diff --git a/doc/sphinx/rules/http-keywords/header.png b/doc/userguide/rules/http-keywords/header.png similarity index 100% rename from doc/sphinx/rules/http-keywords/header.png rename to doc/userguide/rules/http-keywords/header.png diff --git a/doc/sphinx/rules/http-keywords/header1.png b/doc/userguide/rules/http-keywords/header1.png similarity index 100% rename from doc/sphinx/rules/http-keywords/header1.png rename to doc/userguide/rules/http-keywords/header1.png diff --git a/doc/sphinx/rules/http-keywords/http_server_body.png b/doc/userguide/rules/http-keywords/http_server_body.png similarity index 100% rename from doc/sphinx/rules/http-keywords/http_server_body.png rename to doc/userguide/rules/http-keywords/http_server_body.png diff --git a/doc/sphinx/rules/http-keywords/http_uri.png b/doc/userguide/rules/http-keywords/http_uri.png similarity index 100% rename from doc/sphinx/rules/http-keywords/http_uri.png rename to doc/userguide/rules/http-keywords/http_uri.png diff --git a/doc/sphinx/rules/http-keywords/method.png b/doc/userguide/rules/http-keywords/method.png similarity index 100% rename from doc/sphinx/rules/http-keywords/method.png rename to doc/userguide/rules/http-keywords/method.png diff --git a/doc/sphinx/rules/http-keywords/method1.png b/doc/userguide/rules/http-keywords/method1.png similarity index 100% rename from doc/sphinx/rules/http-keywords/method1.png rename to doc/userguide/rules/http-keywords/method1.png diff --git a/doc/sphinx/rules/http-keywords/method2.png b/doc/userguide/rules/http-keywords/method2.png similarity index 100% rename from doc/sphinx/rules/http-keywords/method2.png rename to doc/userguide/rules/http-keywords/method2.png diff --git a/doc/sphinx/rules/http-keywords/request.png b/doc/userguide/rules/http-keywords/request.png similarity index 100% rename from doc/sphinx/rules/http-keywords/request.png rename to doc/userguide/rules/http-keywords/request.png diff --git a/doc/sphinx/rules/http-keywords/request2.png b/doc/userguide/rules/http-keywords/request2.png similarity index 100% rename from doc/sphinx/rules/http-keywords/request2.png rename to doc/userguide/rules/http-keywords/request2.png diff --git a/doc/sphinx/rules/http-keywords/response1.png b/doc/userguide/rules/http-keywords/response1.png similarity index 100% rename from doc/sphinx/rules/http-keywords/response1.png rename to doc/userguide/rules/http-keywords/response1.png diff --git a/doc/sphinx/rules/http-keywords/stat-code1.png b/doc/userguide/rules/http-keywords/stat-code1.png similarity index 100% rename from doc/sphinx/rules/http-keywords/stat-code1.png rename to doc/userguide/rules/http-keywords/stat-code1.png diff --git a/doc/sphinx/rules/http-keywords/stat_code.png b/doc/userguide/rules/http-keywords/stat_code.png similarity index 100% rename from doc/sphinx/rules/http-keywords/stat_code.png rename to doc/userguide/rules/http-keywords/stat_code.png diff --git a/doc/sphinx/rules/http-keywords/stat_msg.png b/doc/userguide/rules/http-keywords/stat_msg.png similarity index 100% rename from doc/sphinx/rules/http-keywords/stat_msg.png rename to doc/userguide/rules/http-keywords/stat_msg.png diff --git a/doc/sphinx/rules/http-keywords/stat_msg_1.png b/doc/userguide/rules/http-keywords/stat_msg_1.png similarity index 100% rename from doc/sphinx/rules/http-keywords/stat_msg_1.png rename to doc/userguide/rules/http-keywords/stat_msg_1.png diff --git a/doc/sphinx/rules/http-keywords/uri.png b/doc/userguide/rules/http-keywords/uri.png similarity index 100% rename from doc/sphinx/rules/http-keywords/uri.png rename to doc/userguide/rules/http-keywords/uri.png diff --git a/doc/sphinx/rules/http-keywords/uri1.png b/doc/userguide/rules/http-keywords/uri1.png similarity index 100% rename from doc/sphinx/rules/http-keywords/uri1.png rename to doc/userguide/rules/http-keywords/uri1.png diff --git a/doc/sphinx/rules/http-keywords/uricontent.png b/doc/userguide/rules/http-keywords/uricontent.png similarity index 100% rename from doc/sphinx/rules/http-keywords/uricontent.png rename to doc/userguide/rules/http-keywords/uricontent.png diff --git a/doc/sphinx/rules/http-keywords/uricontent1.png b/doc/userguide/rules/http-keywords/uricontent1.png similarity index 100% rename from doc/sphinx/rules/http-keywords/uricontent1.png rename to doc/userguide/rules/http-keywords/uricontent1.png diff --git a/doc/sphinx/rules/http-keywords/urilen.png b/doc/userguide/rules/http-keywords/urilen.png similarity index 100% rename from doc/sphinx/rules/http-keywords/urilen.png rename to doc/userguide/rules/http-keywords/urilen.png diff --git a/doc/sphinx/rules/http-keywords/urilen1.png b/doc/userguide/rules/http-keywords/urilen1.png similarity index 100% rename from doc/sphinx/rules/http-keywords/urilen1.png rename to doc/userguide/rules/http-keywords/urilen1.png diff --git a/doc/sphinx/rules/http-keywords/user_agent.png b/doc/userguide/rules/http-keywords/user_agent.png similarity index 100% rename from doc/sphinx/rules/http-keywords/user_agent.png rename to doc/userguide/rules/http-keywords/user_agent.png diff --git a/doc/sphinx/rules/http-keywords/user_agent_match.png b/doc/userguide/rules/http-keywords/user_agent_match.png similarity index 100% rename from doc/sphinx/rules/http-keywords/user_agent_match.png rename to doc/userguide/rules/http-keywords/user_agent_match.png diff --git a/doc/sphinx/rules/http-uri-normalization.rst b/doc/userguide/rules/http-uri-normalization.rst similarity index 100% rename from doc/sphinx/rules/http-uri-normalization.rst rename to doc/userguide/rules/http-uri-normalization.rst diff --git a/doc/sphinx/rules/index.rst b/doc/userguide/rules/index.rst similarity index 99% rename from doc/sphinx/rules/index.rst rename to doc/userguide/rules/index.rst index f4b5446aef19..9cf0058edb1a 100644 --- a/doc/sphinx/rules/index.rst +++ b/doc/userguide/rules/index.rst @@ -20,4 +20,3 @@ Suricata Rules normalized-buffers modbus-keyword dnp3-keywords - diff --git a/doc/sphinx/rules/intro.rst b/doc/userguide/rules/intro.rst similarity index 100% rename from doc/sphinx/rules/intro.rst rename to doc/userguide/rules/intro.rst diff --git a/doc/sphinx/rules/intro/Dest_port.png b/doc/userguide/rules/intro/Dest_port.png similarity index 100% rename from doc/sphinx/rules/intro/Dest_port.png rename to doc/userguide/rules/intro/Dest_port.png diff --git a/doc/sphinx/rules/intro/Direction.png b/doc/userguide/rules/intro/Direction.png similarity index 100% rename from doc/sphinx/rules/intro/Direction.png rename to doc/userguide/rules/intro/Direction.png diff --git a/doc/sphinx/rules/intro/Source-port.png b/doc/userguide/rules/intro/Source-port.png similarity index 100% rename from doc/sphinx/rules/intro/Source-port.png rename to doc/userguide/rules/intro/Source-port.png diff --git a/doc/sphinx/rules/intro/Source.png b/doc/userguide/rules/intro/Source.png similarity index 100% rename from doc/sphinx/rules/intro/Source.png rename to doc/userguide/rules/intro/Source.png diff --git a/doc/sphinx/rules/intro/TCP-session.png b/doc/userguide/rules/intro/TCP-session.png similarity index 100% rename from doc/sphinx/rules/intro/TCP-session.png rename to doc/userguide/rules/intro/TCP-session.png diff --git a/doc/sphinx/rules/intro/action.png b/doc/userguide/rules/intro/action.png similarity index 100% rename from doc/sphinx/rules/intro/action.png rename to doc/userguide/rules/intro/action.png diff --git a/doc/sphinx/rules/intro/destination.png b/doc/userguide/rules/intro/destination.png similarity index 100% rename from doc/sphinx/rules/intro/destination.png rename to doc/userguide/rules/intro/destination.png diff --git a/doc/sphinx/rules/intro/intro_sig.png b/doc/userguide/rules/intro/intro_sig.png similarity index 100% rename from doc/sphinx/rules/intro/intro_sig.png rename to doc/userguide/rules/intro/intro_sig.png diff --git a/doc/sphinx/rules/intro/protocol.png b/doc/userguide/rules/intro/protocol.png similarity index 100% rename from doc/sphinx/rules/intro/protocol.png rename to doc/userguide/rules/intro/protocol.png diff --git a/doc/sphinx/rules/live-rule-swap.rst b/doc/userguide/rules/live-rule-swap.rst similarity index 100% rename from doc/sphinx/rules/live-rule-swap.rst rename to doc/userguide/rules/live-rule-swap.rst diff --git a/doc/sphinx/rules/meta.rst b/doc/userguide/rules/meta.rst similarity index 100% rename from doc/sphinx/rules/meta.rst rename to doc/userguide/rules/meta.rst diff --git a/doc/sphinx/rules/meta/classification.png b/doc/userguide/rules/meta/classification.png similarity index 100% rename from doc/sphinx/rules/meta/classification.png rename to doc/userguide/rules/meta/classification.png diff --git a/doc/sphinx/rules/meta/classtype.png b/doc/userguide/rules/meta/classtype.png similarity index 100% rename from doc/sphinx/rules/meta/classtype.png rename to doc/userguide/rules/meta/classtype.png diff --git a/doc/sphinx/rules/meta/gid.png b/doc/userguide/rules/meta/gid.png similarity index 100% rename from doc/sphinx/rules/meta/gid.png rename to doc/userguide/rules/meta/gid.png diff --git a/doc/sphinx/rules/meta/msg.png b/doc/userguide/rules/meta/msg.png similarity index 100% rename from doc/sphinx/rules/meta/msg.png rename to doc/userguide/rules/meta/msg.png diff --git a/doc/sphinx/rules/meta/reference.png b/doc/userguide/rules/meta/reference.png similarity index 100% rename from doc/sphinx/rules/meta/reference.png rename to doc/userguide/rules/meta/reference.png diff --git a/doc/sphinx/rules/meta/rev.png b/doc/userguide/rules/meta/rev.png similarity index 100% rename from doc/sphinx/rules/meta/rev.png rename to doc/userguide/rules/meta/rev.png diff --git a/doc/sphinx/rules/meta/sid.png b/doc/userguide/rules/meta/sid.png similarity index 100% rename from doc/sphinx/rules/meta/sid.png rename to doc/userguide/rules/meta/sid.png diff --git a/doc/sphinx/rules/modbus-keyword.rst b/doc/userguide/rules/modbus-keyword.rst similarity index 100% rename from doc/sphinx/rules/modbus-keyword.rst rename to doc/userguide/rules/modbus-keyword.rst diff --git a/doc/sphinx/rules/normalized-buffers.rst b/doc/userguide/rules/normalized-buffers.rst similarity index 100% rename from doc/sphinx/rules/normalized-buffers.rst rename to doc/userguide/rules/normalized-buffers.rst diff --git a/doc/sphinx/rules/normalized-buffers/normalization1.png b/doc/userguide/rules/normalized-buffers/normalization1.png similarity index 100% rename from doc/sphinx/rules/normalized-buffers/normalization1.png rename to doc/userguide/rules/normalized-buffers/normalization1.png diff --git a/doc/sphinx/rules/payload-keywords.rst b/doc/userguide/rules/payload-keywords.rst similarity index 100% rename from doc/sphinx/rules/payload-keywords.rst rename to doc/userguide/rules/payload-keywords.rst diff --git a/doc/sphinx/rules/payload-keywords/Legenda_rules.png b/doc/userguide/rules/payload-keywords/Legenda_rules.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/Legenda_rules.png rename to doc/userguide/rules/payload-keywords/Legenda_rules.png diff --git a/doc/sphinx/rules/payload-keywords/content.png b/doc/userguide/rules/payload-keywords/content.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/content.png rename to doc/userguide/rules/payload-keywords/content.png diff --git a/doc/sphinx/rules/payload-keywords/content2.png b/doc/userguide/rules/payload-keywords/content2.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/content2.png rename to doc/userguide/rules/payload-keywords/content2.png diff --git a/doc/sphinx/rules/payload-keywords/content3.png b/doc/userguide/rules/payload-keywords/content3.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/content3.png rename to doc/userguide/rules/payload-keywords/content3.png diff --git a/doc/sphinx/rules/payload-keywords/content4.png b/doc/userguide/rules/payload-keywords/content4.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/content4.png rename to doc/userguide/rules/payload-keywords/content4.png diff --git a/doc/sphinx/rules/payload-keywords/content5.png b/doc/userguide/rules/payload-keywords/content5.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/content5.png rename to doc/userguide/rules/payload-keywords/content5.png diff --git a/doc/sphinx/rules/payload-keywords/content6.png b/doc/userguide/rules/payload-keywords/content6.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/content6.png rename to doc/userguide/rules/payload-keywords/content6.png diff --git a/doc/sphinx/rules/payload-keywords/distance.png b/doc/userguide/rules/payload-keywords/distance.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/distance.png rename to doc/userguide/rules/payload-keywords/distance.png diff --git a/doc/sphinx/rules/payload-keywords/distance1.png b/doc/userguide/rules/payload-keywords/distance1.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/distance1.png rename to doc/userguide/rules/payload-keywords/distance1.png diff --git a/doc/sphinx/rules/payload-keywords/distance3.png b/doc/userguide/rules/payload-keywords/distance3.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/distance3.png rename to doc/userguide/rules/payload-keywords/distance3.png diff --git a/doc/sphinx/rules/payload-keywords/distance4.png b/doc/userguide/rules/payload-keywords/distance4.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/distance4.png rename to doc/userguide/rules/payload-keywords/distance4.png diff --git a/doc/sphinx/rules/payload-keywords/distance5.png b/doc/userguide/rules/payload-keywords/distance5.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/distance5.png rename to doc/userguide/rules/payload-keywords/distance5.png diff --git a/doc/sphinx/rules/payload-keywords/dsize.png b/doc/userguide/rules/payload-keywords/dsize.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/dsize.png rename to doc/userguide/rules/payload-keywords/dsize.png diff --git a/doc/sphinx/rules/payload-keywords/isdataat1.png b/doc/userguide/rules/payload-keywords/isdataat1.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/isdataat1.png rename to doc/userguide/rules/payload-keywords/isdataat1.png diff --git a/doc/sphinx/rules/payload-keywords/replace.png b/doc/userguide/rules/payload-keywords/replace.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/replace.png rename to doc/userguide/rules/payload-keywords/replace.png diff --git a/doc/sphinx/rules/payload-keywords/replace1.png b/doc/userguide/rules/payload-keywords/replace1.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/replace1.png rename to doc/userguide/rules/payload-keywords/replace1.png diff --git a/doc/sphinx/rules/payload-keywords/rpc.png b/doc/userguide/rules/payload-keywords/rpc.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/rpc.png rename to doc/userguide/rules/payload-keywords/rpc.png diff --git a/doc/sphinx/rules/payload-keywords/within1.png b/doc/userguide/rules/payload-keywords/within1.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/within1.png rename to doc/userguide/rules/payload-keywords/within1.png diff --git a/doc/sphinx/rules/payload-keywords/within2.png b/doc/userguide/rules/payload-keywords/within2.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/within2.png rename to doc/userguide/rules/payload-keywords/within2.png diff --git a/doc/sphinx/rules/payload-keywords/within_distance.png b/doc/userguide/rules/payload-keywords/within_distance.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/within_distance.png rename to doc/userguide/rules/payload-keywords/within_distance.png diff --git a/doc/sphinx/rules/payload-keywords/within_distance2.png b/doc/userguide/rules/payload-keywords/within_distance2.png similarity index 100% rename from doc/sphinx/rules/payload-keywords/within_distance2.png rename to doc/userguide/rules/payload-keywords/within_distance2.png diff --git a/doc/sphinx/rules/pcre.rst b/doc/userguide/rules/pcre.rst similarity index 100% rename from doc/sphinx/rules/pcre.rst rename to doc/userguide/rules/pcre.rst diff --git a/doc/sphinx/rules/pcre/pcre.png b/doc/userguide/rules/pcre/pcre.png similarity index 100% rename from doc/sphinx/rules/pcre/pcre.png rename to doc/userguide/rules/pcre/pcre.png diff --git a/doc/sphinx/rules/pcre/pcre3.png b/doc/userguide/rules/pcre/pcre3.png similarity index 100% rename from doc/sphinx/rules/pcre/pcre3.png rename to doc/userguide/rules/pcre/pcre3.png diff --git a/doc/sphinx/rules/pcre/pcre4.png b/doc/userguide/rules/pcre/pcre4.png similarity index 100% rename from doc/sphinx/rules/pcre/pcre4.png rename to doc/userguide/rules/pcre/pcre4.png diff --git a/doc/sphinx/rules/pcre/pcre5.png b/doc/userguide/rules/pcre/pcre5.png similarity index 100% rename from doc/sphinx/rules/pcre/pcre5.png rename to doc/userguide/rules/pcre/pcre5.png diff --git a/doc/sphinx/rules/pcre/pcre6.png b/doc/userguide/rules/pcre/pcre6.png similarity index 100% rename from doc/sphinx/rules/pcre/pcre6.png rename to doc/userguide/rules/pcre/pcre6.png diff --git a/doc/sphinx/rules/rule-lua-scripting.rst b/doc/userguide/rules/rule-lua-scripting.rst similarity index 100% rename from doc/sphinx/rules/rule-lua-scripting.rst rename to doc/userguide/rules/rule-lua-scripting.rst diff --git a/doc/sphinx/rules/thresholding.rst b/doc/userguide/rules/thresholding.rst similarity index 100% rename from doc/sphinx/rules/thresholding.rst rename to doc/userguide/rules/thresholding.rst diff --git a/doc/sphinx/rules/tls-keywords.rst b/doc/userguide/rules/tls-keywords.rst similarity index 100% rename from doc/sphinx/rules/tls-keywords.rst rename to doc/userguide/rules/tls-keywords.rst diff --git a/doc/sphinx/setting-up-ipsinline-for-linux.rst b/doc/userguide/setting-up-ipsinline-for-linux.rst similarity index 100% rename from doc/sphinx/setting-up-ipsinline-for-linux.rst rename to doc/userguide/setting-up-ipsinline-for-linux.rst diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/IPtables.png b/doc/userguide/setting-up-ipsinline-for-linux/IPtables.png similarity index 100% rename from doc/sphinx/setting-up-ipsinline-for-linux/IPtables.png rename to doc/userguide/setting-up-ipsinline-for-linux/IPtables.png diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/IPtables3.png b/doc/userguide/setting-up-ipsinline-for-linux/IPtables3.png similarity index 100% rename from doc/sphinx/setting-up-ipsinline-for-linux/IPtables3.png rename to doc/userguide/setting-up-ipsinline-for-linux/IPtables3.png diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/iptables1.png b/doc/userguide/setting-up-ipsinline-for-linux/iptables1.png similarity index 100% rename from doc/sphinx/setting-up-ipsinline-for-linux/iptables1.png rename to doc/userguide/setting-up-ipsinline-for-linux/iptables1.png diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/iptables2.png b/doc/userguide/setting-up-ipsinline-for-linux/iptables2.png similarity index 100% rename from doc/sphinx/setting-up-ipsinline-for-linux/iptables2.png rename to doc/userguide/setting-up-ipsinline-for-linux/iptables2.png diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/iptables4.png b/doc/userguide/setting-up-ipsinline-for-linux/iptables4.png similarity index 100% rename from doc/sphinx/setting-up-ipsinline-for-linux/iptables4.png rename to doc/userguide/setting-up-ipsinline-for-linux/iptables4.png diff --git a/doc/sphinx/setting-up-ipsinline-for-linux/iptables_vnL.png b/doc/userguide/setting-up-ipsinline-for-linux/iptables_vnL.png similarity index 100% rename from doc/sphinx/setting-up-ipsinline-for-linux/iptables_vnL.png rename to doc/userguide/setting-up-ipsinline-for-linux/iptables_vnL.png diff --git a/doc/sphinx/snort-compatibility.rst b/doc/userguide/snort-compatibility.rst similarity index 100% rename from doc/sphinx/snort-compatibility.rst rename to doc/userguide/snort-compatibility.rst diff --git a/doc/sphinx/what-is-suricata.rst b/doc/userguide/what-is-suricata.rst similarity index 100% rename from doc/sphinx/what-is-suricata.rst rename to doc/userguide/what-is-suricata.rst From a96225527a461b0809a68cbb94bac4bc08a6c89c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 22 Feb 2016 11:53:48 -0600 Subject: [PATCH 1821/2553] doc: update url to modbus paper as advised by David Diallo. --- doc/userguide/rules/modbus-keyword.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide/rules/modbus-keyword.rst b/doc/userguide/rules/modbus-keyword.rst index 3aa3bcb91f6d..407c3e38e8fc 100644 --- a/doc/userguide/rules/modbus-keyword.rst +++ b/doc/userguide/rules/modbus-keyword.rst @@ -84,4 +84,4 @@ stream reassembling as unlimited (stream.reassembly.depth: 0) (cf. http://www.modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf) Paper and presentation (in french) on Modbus support are available : -http://www.ssi.gouv.fr/fr/anssi/publications/publications-scientifiques/articles-de-conferences/detection-d-intrusion-dans-les-systemes-industriels-suricata-et-le-cas-modbus.html +http://www.ssi.gouv.fr/agence/publication/detection-dintrusion-dans-les-systemes-industriels-suricata-et-le-cas-modbus/ From 8e655cf107db515d6bcc601ccf9c45481cc56a09 Mon Sep 17 00:00:00 2001 From: Andi Date: Fri, 26 Feb 2016 23:56:30 +0100 Subject: [PATCH 1822/2553] eve-json-format: add newest version from the wiki This was added by pevma in the wiki, so should go into the sphinx doc as well. --- doc/userguide/output/eve/eve-json-format.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide/output/eve/eve-json-format.rst b/doc/userguide/output/eve/eve-json-format.rst index 61a4f33433b5..db3d7c96a012 100644 --- a/doc/userguide/output/eve/eve-json-format.rst +++ b/doc/userguide/output/eve/eve-json-format.rst @@ -115,7 +115,7 @@ In addition to the extended logging fields one can also choose to enable/add fro content-type, date, etags, last-modified, link, location, proxy-authenticate, referrer, refresh, retry-after, server, set-cookie, trailer, transfer-encoding, upgrade, vary, warning, - www-authenticate] + www-authenticate, x-flash-version, x-authenticated-user] The benefits here of using the extended logging is to see if this action for example was a POST or perhaps if a download of an executable actually returned any bytes. From 7e3591e3ce1e3a59cd90882a3593f6a42e13528c Mon Sep 17 00:00:00 2001 From: brandonlattin Date: Wed, 24 Feb 2016 11:55:46 -0600 Subject: [PATCH 1823/2553] doc: performance: Replace 'medium' with 'custom' I assume the intent was to use the custom-values that are being defined. --- doc/userguide/performance/high-performance-config.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide/performance/high-performance-config.rst b/doc/userguide/performance/high-performance-config.rst index c67361fcbaf1..fa1a3cde1732 100644 --- a/doc/userguide/performance/high-performance-config.rst +++ b/doc/userguide/performance/high-performance-config.rst @@ -7,7 +7,7 @@ suricata.yaml to off-load as much work from the CPU's as possible: :: detect-engine: - - profile: medium + - profile: custom - custom-values: toclient-src-groups: 200 toclient-dst-groups: 200 From 0e63c9ca41ea13d12d630687dc8eb28326227b13 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 30 Mar 2016 10:52:19 -0600 Subject: [PATCH 1824/2553] doc: add GPL and CC licenses --- doc/userguide/index.rst | 1 + doc/userguide/licenses/cc-nc-4.0.rst | 169 ++++++++++++ doc/userguide/licenses/gnu-gpl-v2.0.rst | 340 ++++++++++++++++++++++++ doc/userguide/licenses/index.rst | 20 ++ doc/userguide/what-is-suricata.rst | 11 +- 5 files changed, 538 insertions(+), 3 deletions(-) create mode 100644 doc/userguide/licenses/cc-nc-4.0.rst create mode 100644 doc/userguide/licenses/gnu-gpl-v2.0.rst create mode 100644 doc/userguide/licenses/index.rst diff --git a/doc/userguide/index.rst b/doc/userguide/index.rst index 248613d8612b..63055a0675fd 100644 --- a/doc/userguide/index.rst +++ b/doc/userguide/index.rst @@ -21,3 +21,4 @@ Suricata User Guide public-data-sets capture-hardware/index.rst acknowledgements + licenses/index.rst diff --git a/doc/userguide/licenses/cc-nc-4.0.rst b/doc/userguide/licenses/cc-nc-4.0.rst new file mode 100644 index 000000000000..2bbdf632630e --- /dev/null +++ b/doc/userguide/licenses/cc-nc-4.0.rst @@ -0,0 +1,169 @@ +Creative Commons Attribution-NonCommercial 4.0 International Public License +=========================================================================== + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. +------------------------ + +a. **Adapted Material** means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. **Adapter's License** means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. **Copyright and Similar Rights** means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +d. **Effective Technological Measures** means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +e. **Exceptions and Limitations** means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +f. **Licensed Material** means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +g. **Licensed Rights** means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +h. **Licensor** means the individual(s) or entity(ies) granting rights under this Public License. + +i. **NonCommercial** means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +j. **Share** means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +k. **Sui Generis Database Rights** means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +l. **You** means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. +------------------ + +a. **License grant.** + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. **Exceptions and Limitations.** For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. **Term.** The term of this Public License is specified in Section 6(a). + + 4. **Media and formats; technical modifications allowed.** The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. **Downstream recipients.** + + A. **Offer from the Licensor – Licensed Material.** Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + B. **No downstream restrictions.** You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. **No endorsement.** Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. **Other rights.** + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. +------------------------------- + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. **Attribution.** + + 1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. + +Section 4 – Sui Generis Database Rights. +---------------------------------------- + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. +----------------------------------------------------------------- + +a. **Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.** + +b. **To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.** + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. +--------------------------------- + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. +--------------------------------------- + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. +--------------------------- + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. + +**Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” Except for the limited purpose of +indicating that material is shared under a Creative Commons public +license or as otherwise permitted by the Creative Commons policies +published at creativecommons.org/policies, Creative Commons does not +authorize the use of the trademark “Creative Commons” or any other +trademark or logo of Creative Commons without its prior written +consent including, without limitation, in connection with any +unauthorized modifications to any of its public licenses or any other +arrangements, understandings, or agreements concerning use of licensed +material. For the avoidance of doubt, this paragraph does not form +part of the public licenses.** + +**Creative Commons may be contacted at creativecommons.org.** diff --git a/doc/userguide/licenses/gnu-gpl-v2.0.rst b/doc/userguide/licenses/gnu-gpl-v2.0.rst new file mode 100644 index 000000000000..8bcc1b6b261d --- /dev/null +++ b/doc/userguide/licenses/gnu-gpl-v2.0.rst @@ -0,0 +1,340 @@ +GNU General Public License +========================== + +*Version 2, June 1991* +*Copyright © 1989, 1991 Free Software Foundation, Inc.* +*51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA* + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble +~~~~~~~~ + +The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +We protect your rights with two steps: **(1)** copyright the software, and +**(2)** offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and +modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**0.** This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +**1.** You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +**2.** You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +* **a)** You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. +* **b)** You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. +* **c)** If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +**3.** You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +* **a)** Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, +* **b)** Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, +* **c)** Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +**4.** You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +**5.** You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +**6.** Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +**7.** If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +**8.** If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +**9.** The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + +**10.** If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + +NO WARRANTY +~~~~~~~~~~~ + +**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +*END OF TERMS AND CONDITIONS* + +How to Apply These Terms to Your New Programs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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 along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type \`show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type \`show c' for details. + +The hypothetical commands \`show w` and \`show c` should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than \`show w' and \`show c`; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + \`Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/doc/userguide/licenses/index.rst b/doc/userguide/licenses/index.rst new file mode 100644 index 000000000000..1326930d943a --- /dev/null +++ b/doc/userguide/licenses/index.rst @@ -0,0 +1,20 @@ +Licenses +======== + +.. toctree:: + :titlesonly: + + gnu-gpl-v2.0 + cc-nc-4.0 + +Suricata Source Code +-------------------- + +The Suricata source code is licensed under version 2 of the +:doc:`gnu-gpl-v2.0`. + +Suricata Documentation +---------------------- + +The Suricata documentation (this documentation) is licensed under the +:doc:`cc-nc-4.0`. diff --git a/doc/userguide/what-is-suricata.rst b/doc/userguide/what-is-suricata.rst index 60c1b46efe86..ef585b67ae10 100644 --- a/doc/userguide/what-is-suricata.rst +++ b/doc/userguide/what-is-suricata.rst @@ -7,7 +7,6 @@ replace or emulate the existing tools in the industry, but will bring new ideas and technologies to the field. The Suricata Engine and the HTP Library are available to use under the GPLv2. - IDS/IPS ------- @@ -25,7 +24,6 @@ the General Public License, Suricata eliminates the ID/PS engine cost concerns while providing a scalable option for the most complex network security architectures. - Multi-threading --------------- @@ -37,7 +35,7 @@ latest multi-core CPU chip sets. Suricata is developed for ease of implementation and accompanied by a step-by-step getting started documentation and user manual. -Development and features +Development and Features ------------------------ The goal of the Suricata Project Phase 1 was to have a distributable @@ -64,3 +62,10 @@ Ristic of Mod Security fame for the OISF. This integrates and provides very advanced processing of HTTP streams for Suricata. The HTP library is required by the engine, but may also be used independently in a range of applications and tools. + +License +------- + +The Suricata source code is licensed under version 2 of the +:doc:`licenses/gnu-gpl-v2.0`. This documentation is licensed under the +:doc:`licenses/cc-nc-4.0`. From 7806ae8f57155b94c95065b2002c3e7b21eecdd4 Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Wed, 13 Jul 2016 22:51:05 +0200 Subject: [PATCH 1825/2553] docs: sync up to recent redmine --- doc/userguide/configuration/log-rotation.rst | 8 - doc/userguide/configuration/suricata-yaml.rst | 38 ++++- doc/userguide/dropping-privileges.rst | 21 --- doc/userguide/file-extraction/md5.rst | 7 - doc/userguide/output/custom-http-logging.rst | 2 - doc/userguide/performance/hyperscan.rst | 138 ++++++++++++++++++ doc/userguide/performance/packet_capture.rst | 80 ++++++++++ doc/userguide/rules/flow-keywords.rst | 15 +- doc/userguide/rules/header-keywords.rst | 7 +- doc/userguide/rules/http-keywords.rst | 36 ++--- doc/userguide/rules/rule-lua-scripting.rst | 4 - 11 files changed, 273 insertions(+), 83 deletions(-) create mode 100644 doc/userguide/performance/hyperscan.rst create mode 100644 doc/userguide/performance/packet_capture.rst diff --git a/doc/userguide/configuration/log-rotation.rst b/doc/userguide/configuration/log-rotation.rst index 63ee24e5b3d3..4bf507189e01 100644 --- a/doc/userguide/configuration/log-rotation.rst +++ b/doc/userguide/configuration/log-rotation.rst @@ -21,11 +21,3 @@ Example logrotate file: endscript } -newsyslog based log rotation (e.g. on OpenBSD) /etc/newsyslog.conf: - -:: - - /var/log/suricata/eve.json root:wheel 640 1 * 24 B /var/run/suricata.pid SIGHUP - -The above rotates every 24h; the 'B' prevents a rotation logmessage in -eve.json. Fieldseperator is a TAB. diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index f318e1c5ed63..7a574d1745aa 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -807,8 +807,7 @@ application layer, detection, and outputs. # The packet acquisition module reads packets from the network. # The decode module decodes the packets and the stream application -layer performs its job here. The stream application layer has three -tasks: +application layer has three tasks: :: @@ -926,6 +925,41 @@ the settings in 'default' will count. By default Suricata creates one prio: default: "medium" +Relevant cpu-affinity settings for IDS/IPS modes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +IDS mode +~~~~~~~~ + +Runmode AutoFp:: + + management-cpu-set - used for management (example - flow.managers, flow.recyclers) + recive-cpu-set - used for receive and decode + detect-cpu-set - used for streamtcp,detect,output(logging),reject + +Rumode Workers:: + + management-cpu-set - used for management (example - flow.managers, flow.recyclers) + detect-cpu-set - used for receive,streamtcp,decode,detect,output(logging),respond/reject + + +IPS mode +~~~~~~~~ + +Runmode AutoFp:: + + management-cpu-set - used for management (example - flow.managers, flow.recyclers) + recive-cpu-set - used for receive and decode + detect-cpu-set - used for streamtcp,detect,output(logging) + verdict-cpu-set - used for verdict and respond/reject + +Runmode Workers:: + + management-cpu-set - used for management (example - flow.managers, flow.recyclers) + detect-cpu-set - used for receive,streamtcp,decode,detect,output(logging),respond/reject, verdict + + + IP Defrag --------- diff --git a/doc/userguide/dropping-privileges.rst b/doc/userguide/dropping-privileges.rst index bdcd930d631a..ade11c1b4970 100644 --- a/doc/userguide/dropping-privileges.rst +++ b/doc/userguide/dropping-privileges.rst @@ -48,24 +48,3 @@ suricata can still write to its log files which are usually located in chown -R root:suri /var/log/suricata chmod -R 775 /var/log/suricata -If you rely on the pid files be aware that as of version 1.4.x -Suricata writes the pid file before it switches uids. This means that -the pid file will be owned by root and will not be readable by the -alternative uid. If this is an issue for you then a work around is to -set the sgid bit on the directory that the pid file will be created -in. This will cause all files in this directory to inherit the gid -from the parent directory rather than the creating process. - -:: - - chmod g+s ~sensors/sensor1/run - - ls -ld ~sensors/sensor1/run - drwxr-sr-x 2 sensors sensors 4096 Aug 9 09:20 ~sensors/sensor1/run - -and so after running suricata we get - -:: - - ls -ld ~sensors/sensor1/run/suricata.pid - -rw-r----- 1 root sensors 6 Aug 9 09:20 ~sensors/sensor1/run/suricata.pid diff --git a/doc/userguide/file-extraction/md5.rst b/doc/userguide/file-extraction/md5.rst index 419a3970b06f..3cc94cad1873 100644 --- a/doc/userguide/file-extraction/md5.rst +++ b/doc/userguide/file-extraction/md5.rst @@ -74,13 +74,6 @@ You have to compile/install suri like this in order to enable MD5s: make sudo make install -For Fedora 64-bit users, the configure line will look like - - -:: - - - ./configure --with-libnss-libraries=/usr/lib64 --with-libnss-includes=/usr/include/nss3 --with-libnspr-libraries=/usr/lib64 --with-libnspr-includes=/usr/include/nspr4 Output of configure: diff --git a/doc/userguide/output/custom-http-logging.rst b/doc/userguide/output/custom-http-logging.rst index 9ddb5ba80a84..f7d21adac5d8 100644 --- a/doc/userguide/output/custom-http-logging.rst +++ b/doc/userguide/output/custom-http-logging.rst @@ -28,8 +28,6 @@ And in your http.log file you would get the following, for example: 08/28/12-22:14:30.693856 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:11.0) Gecko/20100101 Firefox/11.0 HTTP/1.1 GET us.cnn.com /video/data/3.0/video/showbiz/2012/08/28/conan-reports-from-rnc-convention.teamcoco/index.xml 200 15789 192.168.1.91:45108 -> 157.166.255.18:80 -It should be noted that each line represents the http request and response all in one, depending on how you specified your custom format. HTTP responses do not get their own line and if you wish to see that information, you will need to modify the custom format to include it using %{header_field}o for example. - The list of supported format strings is the following: * %h - Host HTTP Header (remote host name). ie: google.com diff --git a/doc/userguide/performance/hyperscan.rst b/doc/userguide/performance/hyperscan.rst new file mode 100644 index 000000000000..64c23a7cc32b --- /dev/null +++ b/doc/userguide/performance/hyperscan.rst @@ -0,0 +1,138 @@ +Hyperscan guide for Ubuntu +========================== + +Introduction +============ + +"Hyperscan is a high-performance multiple regex matching library." https://01.org/hyperscan + +In Suricata it can be used to perform multi pattern matching (mpm). Support was implemented by Justin Viiret and Jim Xu from Intel: https://github.com/inliniac/suricata/pull/1965, https://redmine.openinfosecfoundation.org/issues/1704 + + +Installation +============ + +To use Suricata with Hyperscan support, install dependencies: + + +:: + + + apt-get install cmake ragel + +libboost headers +---------------- + +Hyperscan needs the libboost headers from 1.58+. + +On Ubuntu 15.10 or 16.04+, simply do: + + +:: + + + apt-get install libboost-dev + + +Trusty +~~~~~~ + +Trusty has 1.57, so it's too old. We can grab a newer libboost version, but we *don't* install it system wide. It's only the headers we care about during compilation of Hyperscan. + + +:: + + + sudo apt-get python-dev libbz2-dev + wget http://downloads.sourceforge.net/project/boost/boost/1.60.0/boost_1_60_0.tar.gz + tar xvzf boost_1_60_0.tar.gz + cd boost_1_60_0 + ./bootstrap.sh --prefix=~/tmp/boost-1.60 + ./b2 install + +Hyperscan +--------- + +We'll install version 4.2.0. + + +:: + + + git clone https://github.com/01org/hyperscan + cd hyperscan + mkdir build + cd build + cmake -DBUILD_STATIC_AND_SHARED=1 ../ + +If you have your own libboost headers, use this cmake line instead: + +:: + + + cmake -DBUILD_STATIC_AND_SHARED=1 -DBOOST_ROOT=~/tmp/boost-1.60 ../ + +Finally, make and make install: + +:: + + + make + sudo make install + +Compilation can take a long time, but it should in the end look something like this: + + +:: + + + Install the project... + -- Install configuration: "RELWITHDEBINFO" + -- Installing: /usr/local/lib/pkgconfig/libhs.pc + -- Up-to-date: /usr/local/include/hs/hs.h + -- Up-to-date: /usr/local/include/hs/hs_common.h + -- Up-to-date: /usr/local/include/hs/hs_compile.h + -- Up-to-date: /usr/local/include/hs/hs_runtime.h + -- Installing: /usr/local/lib/libhs_runtime.a + -- Installing: /usr/local/lib/libhs_runtime.so.4.2.0 + -- Installing: /usr/local/lib/libhs_runtime.so.4.2 + -- Installing: /usr/local/lib/libhs_runtime.so + -- Installing: /usr/local/lib/libhs.a + -- Installing: /usr/local/lib/libhs.so.4.2.0 + -- Installing: /usr/local/lib/libhs.so.4.2 + -- Installing: /usr/local/lib/libhs.so + +Note that you may have to add /usr/local/lib to your ld search path + + +:: + + + echo "/usr/local/lib" | sudo tee --append /etc/ld.so.conf.d/usrlocal.conf + sudo ldconfig + +Suricata +-------- + +Compilation +~~~~~~~~~~~ + +Suricata's installation is now quite standard. + +It's possible to pass --with-libhs-includes=/usr/local/include/hs/ --with-libhs-libraries=/usr/local/lib/, although by default this shouldn't be necessary. Suricata should pick up Hyperscan's pkg-config file automagically. + +When Suricata's compilation succeeded, you should have: + +:: + + + suricata --build-info|grep Hyperscan + Hyperscan support: yes + + +Using Hyperscan +~~~~~~~~~~~~~~~ + +To use the hyperscan support edit your suricata.yaml and change the mpm-algo value to 'hs'. + +Alternatively, use this commandline option: --set mpm-algo=hs diff --git a/doc/userguide/performance/packet_capture.rst b/doc/userguide/performance/packet_capture.rst new file mode 100644 index 000000000000..148c0b416f03 --- /dev/null +++ b/doc/userguide/performance/packet_capture.rst @@ -0,0 +1,80 @@ +Packet Capture +============== + +Load balancing +-------------- + +To get the best performance, Suricata will need to run in 'workers' mode. This effectively means that there are multiple threads, each running a full packet pipeline and each receiving packets from the capture method. This means that we rely on the capture method to distribute the packets over the various threads. One critical aspect of this is that Suricata needs to get both sides of a flow in the same thread, in the correct order. + +The AF_PACKET and PF_RING capture methods both have options to select the 'cluster-type'. These default to 'cluster_flow' which instructs the capture method to hash by flow (5 tuple). This hash is symmetric. Netmap does not have a cluster_flow mode built-in. It can be added separately by using the "'lb' tool":https://github.com/luigirizzo/netmap/tree/master/apps/lb + +> **WARNING** Recent AF_PACKET changes have "broken":https://redmine.openinfosecfoundation.org/issues/1777 this symmetry. Work is under way to "address this":https://redmine.openinfosecfoundation.org/issues/1777#note-7, but for now stay on kernel <=4.2. + +On multi-queue NICs, which is almost any modern NIC, RSS settings need to be considered. + + +RSS +--- + +Receive Side Scaling is a technique used by network cards to distribute incoming traffic over various queues on the NIC. This is meant to improve performance but it is important to realize that it was designed for normal traffic, not for the IDS packet capture scenario. RSS using a hash algorithm to distribute the incoming traffic over the various queues. This hash is normally *not* symmetrical. This means that when receiving both sides of a flow, each side may end up in a different queue. Sadly, when deploying Suricata, this is the common scenario when using span ports or taps. + +The problem here is that by having both sides of the traffic in different queues, the order of processing of packets becomes unpredictable. Timing differences on the NIC, the driver, the kernel and in Suricata will lead to a high chance of packets coming in at a different order than on the wire. This is specifically about a mismatch between the two traffic directions. For example, Suricata tracks the TCP 3-way handshake. Due to this timing issue, the SYN/ACK may only be received by Suricata long after the client to server side has already started sending data. Suricata would see this traffic as invalid. + +None of the supported capture methods like AF_PACKET, PF_RING or NETMAP can fix this problem for us. It would require buffering and packet reordering which is expensive. + +To see how many queues are configured: + +:: + + + $ ethtool -l ens2f1 + Channel parameters for ens2f1: + Pre-set maximums: + RX: 0 + TX: 0 + Other: 1 + Combined: 64 + Current hardware settings: + RX: 0 + TX: 0 + Other: 1 + Combined: 8 + +Some NIC's allow you to set it into a symmetric mode. The Intel X(L)710 card can do this in theory, but the drivers aren't capable of enabling this yet (work is underway to try to address this). Another way to address is by setting a special "Random Secret Key" that will make the RSS symmetrical. See http://www.ndsl.kaist.edu/~kyoungsoo/papers/TR-symRSS.pdf (PDF). + +In most scenario's however, the optimal solution is to reduce the number of RSS queues to 1: + +Example: + +:: + + + # Intel X710 with i40e driver: + ethtool -L $DEV combined 1 + +Some drivers do not support setting the number of queues through ethtool. In some cases there is a module load time option. Read the driver docs for the specifics. + + +Offloading +---------- + +Network cards, drivers and the kernel itself have various techniques to speed up packet handling. Generally these will all have to be disabled. + +LRO/GRO lead to merging various smaller packets into big 'super packets'. These will need to be disabled as they break the dsize keyword as well as TCP state tracking. + +Checksum offloading can be left enabled on AF_PACKET and PF_RING, but needs to be disabled on PCAP, NETMAP and others. + + + +Recommendations +--------------- + +Read your drivers documentation! E.g. for i40e the ethtool change of RSS queues may lead to kernel panics if done wrong. + +Generic: set RSS queues to 1 or make sure RSS hashing is symmetric. Disable NIC offloading. + +AF_PACKET: 1 RSS queue and stay on kernel <=4.2 until futher notice. Exception: if RSS is symmetric cluster-type 'cluster_qm' can be used to bind Suricata to the RSS queues. Disable NIC offloading except the rx/tx csum. + +PF_RING: 1 RSS queue and use cluster-type 'cluster_flow'. Disable NIC offloading except the rx/tx csum. + +NETMAP: 1 RSS queue. There is no flow based load balancing built-in, but the 'lb' tool can be helpful. Another option is to use the 'autofp' runmode. Exception: if RSS is symmetric, load balancing is based on the RSS hash and multiple RSS queues can be used. Disable all NIC offloading. \ No newline at end of file diff --git a/doc/userguide/rules/flow-keywords.rst b/doc/userguide/rules/flow-keywords.rst index ba057fd99a46..75824db03c28 100644 --- a/doc/userguide/rules/flow-keywords.rst +++ b/doc/userguide/rules/flow-keywords.rst @@ -29,7 +29,7 @@ Flowbits have different actions. These are: flowbits: unset, name Can be used to unset the condition in the flow. flowbits: isnotset, name Can be used in the rule to make sure it generates an alert when it matches and the condition is not set in the flow. - flowbits: noalert Does not generate an alert for this rule. + flowbits: noalert No alert will be generated by this rule. Example: @@ -52,13 +52,10 @@ different functions. Flow ~~~~ -The flow keyword can be used to match on direction of the flow, so -to/from client or to/from server. The to_client is equal to -from_server, same goes for from_client and to_server - there's no -difference, both names are supported due to historical reasons. It can -also match if the flow is established or not. The flow keyword can -also be use to say the signature has to match on stream only -(only_stream) or on packet only (no_stream). +The flow keyword can be used to match on direction of the flow, so to/from +client or to/from server. It can also match if the flow is established or not. +The flow keyword can also be use to say the signature has to match on stream +only (only_stream) or on packet only (no_stream). So with the flow keyword you can match on: @@ -73,7 +70,7 @@ So with the flow keyword you can match on: *to_server* and _from_client_. This comes from the original Snort language and we support it for compatibility reasons. -These options from the different columns can be combined. You can use +These options can be combined. You can use up to three options. For example: :: diff --git a/doc/userguide/rules/header-keywords.rst b/doc/userguide/rules/header-keywords.rst index a4bc69d3051c..dc1c589f9ae5 100644 --- a/doc/userguide/rules/header-keywords.rst +++ b/doc/userguide/rules/header-keywords.rst @@ -88,12 +88,9 @@ Example of ip_proto in a rule: .. image:: header-keywords/ip_proto.png -An example of the text based version of the protocol, say IPv6 whose -code is 41 would be:: +The named variante of that example would be:: - ip_proto:IPv6 - -No quotes are needed around the name. + ip_proto:PIM Id -- diff --git a/doc/userguide/rules/http-keywords.rst b/doc/userguide/rules/http-keywords.rst index 9584014a2fd4..594ecd4376bb 100644 --- a/doc/userguide/rules/http-keywords.rst +++ b/doc/userguide/rules/http-keywords.rst @@ -3,13 +3,11 @@ HTTP Keywords ============= -There are additional content modifiers that can provide -protocol-specific capabilities at the application layer (if you are -unfamiliar with content modifiers, please visit the page -:doc:`payload-keywords` These keywords make sure the signature checks -only specific parts of the network traffic. For instance, to check -specifically on the request URI, cookies, or the HTTP request or -response body, etc. +There are additional content modifiers that can provide protocol-specific +capabilities at the application layer. More information can be found at +:doc:`payload-keywords` These keywords make sure the signature checks only +specific parts of the network traffic. For instance, to check specifically on +the request URI, cookies, or the HTTP request or response body, etc. Use ``http_method`` to match on the HTTP request method, ``http_uri`` or ``http_raw_uri`` to match on the request URI, ``http_stat_code`` to @@ -159,9 +157,8 @@ modifiers, like ``depth``, ``distance``, ``offset``, ``nocase`` and **Note**: the header buffer is *normalized*. Any trailing whitespace and tab characters are removed. See: - http://lists.openinfosecfoundation.org/pipermail/oisf-users/2011-October/000935.html. Match - on the ``http_raw_header`` buffer if you require the raw - (non-normalized) headers. + http://lists.openinfosecfoundation.org/pipermail/oisf-users/2011-October/000935.html. + To avoid that, use the ``http_raw_header`` keyword. Example of a header in a HTTP request: @@ -279,9 +276,7 @@ http_server_body With the ``http_server_body`` content modifier, it is possible to match specifically and only on the HTTP response body. The keyword can be used in combination with all previously mentioned content modifiers -like ``distance``, ``offset``, ``nocase``, ``within``, etc. If the -response body is *gzip* encoded, it is first uncompressed for -inspection. +like ``distance``, ``offset``, ``nocase``, ``within``, etc. Note: how much of the response/server body is inspected is controlled in your :ref:`libhtp configuration section @@ -320,20 +315,13 @@ The ``file_data`` keyword affects all following content matches, until the ``pkt_data`` keyword is encountered or it reaches the end of the rule. This makes it a useful shortcut for applying many content matches to the HTTP response body, eliminating the need to modify each -content match individually. If the response body is *gzip* encoded, it -is first uncompressed for inspection. +content match individually. Note: how much of the response/server body is inspected is controlled in your :ref:`libhtp configuration section ` via the ``response-body-limit`` setting. -**NOTE:** In 2.0.x, ``file_data`` is only supported for HTTP server -bodies (specified as flow direction **to_client**). Starting with -2.1-dev and above, ``file_data`` is handled more intelligently -per-protocol, supported with **to_server** for SMTP and **to_client** -for HTTP. - urilen ------ @@ -360,10 +348,8 @@ Example of ``urilen`` in a signature: .. image:: http-keywords/urilen1.png -You can specify whether the inspected URI buffer is either the -normalized or the raw buffer by appending ``norm`` or ``raw``:: - - urilen:<5,raw; +You can also append ``norm`` or ``raw`` to define what sort of buffer you want +to use (normalized or raw buffer). pcre ---- diff --git a/doc/userguide/rules/rule-lua-scripting.rst b/doc/userguide/rules/rule-lua-scripting.rst index 91f3de1af8f3..726f1ab3224e 100644 --- a/doc/userguide/rules/rule-lua-scripting.rst +++ b/doc/userguide/rules/rule-lua-scripting.rst @@ -1,10 +1,6 @@ Lua Scripting ============= -In order to enable Lua scripting, please reference this page before -continuing `Installation from GIT with luajit -`_. - Syntax: :: From ba4931ddb64713bcadb7523dad83aa829783e073 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 19 Aug 2016 10:20:49 -0600 Subject: [PATCH 1826/2553] doc: flow:not_established not supported --- doc/userguide/snort-compatibility.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/userguide/snort-compatibility.rst b/doc/userguide/snort-compatibility.rst index cc9e4e2bb969..bf158edd3626 100644 --- a/doc/userguide/snort-compatibility.rst +++ b/doc/userguide/snort-compatibility.rst @@ -64,3 +64,10 @@ This was fixed in Suricata 2.0.9. See: * https://redmine.openinfosecfoundation.org/issues/1481 + +Keyword: flow:not_established +----------------------------- + +*Versions affected: all* + +The ``not_established`` argument to the ``flow`` keyword is not supported. From 7f5ffeebada67d09a1dfa8e4f002510593e0d83d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Sep 2016 08:59:10 -0600 Subject: [PATCH 1827/2553] doc: dns: sync up with wiki --- doc/userguide/rules/dns-keywords.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide/rules/dns-keywords.rst b/doc/userguide/rules/dns-keywords.rst index a437553c81df..e7e4fc1d61b5 100644 --- a/doc/userguide/rules/dns-keywords.rst +++ b/doc/userguide/rules/dns-keywords.rst @@ -12,7 +12,7 @@ network-traffic. dns_query --------- -With **dns_query** the DNS response body is inspected. The dns_query +With **dns_query** the DNS request queries are inspected. The dns_query keyword works a bit different from the normal content modifiers. When used in a rule all contents following it are affected by it. Example: From 5e76a54714d41aac12818d4a535001a313689b3e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Sep 2016 08:59:26 -0600 Subject: [PATCH 1828/2553] doc: packet capture: sync up with wiki --- doc/userguide/performance/packet_capture.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/userguide/performance/packet_capture.rst b/doc/userguide/performance/packet_capture.rst index 148c0b416f03..e860ed597c5a 100644 --- a/doc/userguide/performance/packet_capture.rst +++ b/doc/userguide/performance/packet_capture.rst @@ -8,7 +8,7 @@ To get the best performance, Suricata will need to run in 'workers' mode. This e The AF_PACKET and PF_RING capture methods both have options to select the 'cluster-type'. These default to 'cluster_flow' which instructs the capture method to hash by flow (5 tuple). This hash is symmetric. Netmap does not have a cluster_flow mode built-in. It can be added separately by using the "'lb' tool":https://github.com/luigirizzo/netmap/tree/master/apps/lb -> **WARNING** Recent AF_PACKET changes have "broken":https://redmine.openinfosecfoundation.org/issues/1777 this symmetry. Work is under way to "address this":https://redmine.openinfosecfoundation.org/issues/1777#note-7, but for now stay on kernel <=4.2. +> **WARNING** Recent AF_PACKET changes have "broken":https://redmine.openinfosecfoundation.org/issues/1777 this symmetry. Work is under way to "address this":https://redmine.openinfosecfoundation.org/issues/1777#note-7, but for now stay on kernel <=4.2 or update to 4.4.16+, 4.6.5+ or 4.7+. On multi-queue NICs, which is almost any modern NIC, RSS settings need to be considered. @@ -73,8 +73,8 @@ Read your drivers documentation! E.g. for i40e the ethtool change of RSS queues Generic: set RSS queues to 1 or make sure RSS hashing is symmetric. Disable NIC offloading. -AF_PACKET: 1 RSS queue and stay on kernel <=4.2 until futher notice. Exception: if RSS is symmetric cluster-type 'cluster_qm' can be used to bind Suricata to the RSS queues. Disable NIC offloading except the rx/tx csum. +AF_PACKET: 1 RSS queue and stay on kernel <=4.2 or make sure you have >=4.4.16, >=4.6.5 or >=4.7. Exception: if RSS is symmetric cluster-type 'cluster_qm' can be used to bind Suricata to the RSS queues. Disable NIC offloading except the rx/tx csum. PF_RING: 1 RSS queue and use cluster-type 'cluster_flow'. Disable NIC offloading except the rx/tx csum. -NETMAP: 1 RSS queue. There is no flow based load balancing built-in, but the 'lb' tool can be helpful. Another option is to use the 'autofp' runmode. Exception: if RSS is symmetric, load balancing is based on the RSS hash and multiple RSS queues can be used. Disable all NIC offloading. \ No newline at end of file +NETMAP: 1 RSS queue. There is no flow based load balancing built-in, but the 'lb' tool can be helpful. Another option is to use the 'autofp' runmode. Exception: if RSS is symmetric, load balancing is based on the RSS hash and multiple RSS queues can be used. Disable all NIC offloading. From 6eedd0068b9af4f1480558aa3f6b1aef4ae6be21 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 18 Feb 2016 15:50:13 -0600 Subject: [PATCH 1829/2553] doc: hook sphinx into build --- configure.ac | 9 ++++++++- doc/Makefile.am | 2 ++ doc/userguide/.gitignore | 1 + doc/userguide/Makefile.am | 12 ++++++++++++ doc/userguide/{Makefile => Makefile.sphinx} | 0 5 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 doc/userguide/.gitignore create mode 100644 doc/userguide/Makefile.am rename doc/userguide/{Makefile => Makefile.sphinx} (100%) diff --git a/configure.ac b/configure.ac index 39c178d60ca3..9861b4aaf766 100644 --- a/configure.ac +++ b/configure.ac @@ -1881,6 +1881,13 @@ AC_DEFINE([CLS],[64],[L1 cache line size]) fi +# sphinx for documentation + AC_PATH_PROG(HAVE_SPHINXBUILD, sphinx-build, "no") + if test "$HAVE_SPHINXBUILD" = "no"; then + enable_sphinxbuild=no + fi + AM_CONDITIONAL([HAVE_SPHINXBUILD], [test "x$enable_sphinxbuild" != "xno"]) + # get revision if test -f ./revision; then REVISION=`cat ./revision` @@ -1960,7 +1967,7 @@ AC_SUBST(CONFIGURE_PREFIX) AC_SUBST(CONFIGURE_SYSCONDIR) AC_SUBST(CONFIGURE_LOCALSTATEDIR) -AC_OUTPUT(Makefile src/Makefile qa/Makefile qa/coccinelle/Makefile rules/Makefile doc/Makefile contrib/Makefile contrib/file_processor/Makefile contrib/file_processor/Action/Makefile contrib/file_processor/Processor/Makefile contrib/tile_pcie_logd/Makefile suricata.yaml scripts/Makefile scripts/suricatasc/Makefile scripts/suricatasc/suricatasc) +AC_OUTPUT(Makefile src/Makefile qa/Makefile qa/coccinelle/Makefile rules/Makefile doc/Makefile doc/userguide/Makefile contrib/Makefile contrib/file_processor/Makefile contrib/file_processor/Action/Makefile contrib/file_processor/Processor/Makefile contrib/tile_pcie_logd/Makefile suricata.yaml scripts/Makefile scripts/suricatasc/Makefile scripts/suricatasc/suricatasc) SURICATA_BUILD_CONF="Suricata Configuration: AF_PACKET support: ${enable_af_packet} diff --git a/doc/Makefile.am b/doc/Makefile.am index 386debc8fc2c..4589a9fe1004 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = userguide + EXTRA_DIST = \ AUTHORS \ GITGUIDE \ diff --git a/doc/userguide/.gitignore b/doc/userguide/.gitignore new file mode 100644 index 000000000000..e35d8850c968 --- /dev/null +++ b/doc/userguide/.gitignore @@ -0,0 +1 @@ +_build diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am new file mode 100644 index 000000000000..27124d4e1da6 --- /dev/null +++ b/doc/userguide/Makefile.am @@ -0,0 +1,12 @@ +if HAVE_SPHINXBUILD +man1_MANS = _build/man/suricata.1 + +html: + $(MAKE) -f Makefile.sphinx html + +_build/man/suricata.1: + $(MAKE) -f Makefile.sphinx man + +clean-local: + rm -rf $(top_builddir)/doc/userguide/_build +endif diff --git a/doc/userguide/Makefile b/doc/userguide/Makefile.sphinx similarity index 100% rename from doc/userguide/Makefile rename to doc/userguide/Makefile.sphinx From 15d2a7a49d07796007c4b9639b5cf5130e265a16 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 26 Feb 2016 17:30:15 -0600 Subject: [PATCH 1830/2553] doc: minimal man page: suricata.1 --- doc/userguide/conf.py | 5 +- doc/userguide/index.rst | 1 + doc/userguide/manpages/index.rst | 7 + doc/userguide/manpages/suricata.rst | 193 ++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 doc/userguide/manpages/index.rst create mode 100644 doc/userguide/manpages/suricata.rst diff --git a/doc/userguide/conf.py b/doc/userguide/conf.py index 6224fe72c14f..7bec508d3e66 100644 --- a/doc/userguide/conf.py +++ b/doc/userguide/conf.py @@ -259,8 +259,9 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'suricata', u'Suricata Documentation', - [author], 1) + # (master_doc, 'suricata', u'Suricata Documentation', + # [author], 1) + ("manpages/suricata", "suricata", "Suricata", [], 1) ] # If true, show URL addresses after external links. diff --git a/doc/userguide/index.rst b/doc/userguide/index.rst index 63055a0675fd..07f284e7208a 100644 --- a/doc/userguide/index.rst +++ b/doc/userguide/index.rst @@ -20,5 +20,6 @@ Suricata User Guide file-extraction/file-extraction.rst public-data-sets capture-hardware/index.rst + manpages/index.rst acknowledgements licenses/index.rst diff --git a/doc/userguide/manpages/index.rst b/doc/userguide/manpages/index.rst new file mode 100644 index 000000000000..3c257d2cb05f --- /dev/null +++ b/doc/userguide/manpages/index.rst @@ -0,0 +1,7 @@ +Man Pages +========= + +.. toctree:: + :maxdepth: 1 + + suricata diff --git a/doc/userguide/manpages/suricata.rst b/doc/userguide/manpages/suricata.rst new file mode 100644 index 000000000000..defa47008e0b --- /dev/null +++ b/doc/userguide/manpages/suricata.rst @@ -0,0 +1,193 @@ +Suricata +======== + +SYNOPSIS +-------- + +**suricata** [OPTIONS] [BPF FILTER] + +DESCRIPTION +----------- + +Suricata is a high performance Network IDS, IPS and Network Security +Monitoring engine. Open Source and owned by a community run non-profit +foundation, the Open Information Security Foundation (OISF). + +OPTIONS +------- + +.. option:: -c + + Path to configuration file. + +.. option:: -T + + Test configuration. + +.. option:: -i + + Run in PCAP live mode on provided interface. + +.. option:: -F + + Use BPF filter from file. + +.. option:: -r + + Run in pcap offline mode reading files from pcap file. + +.. option:: -q + + Run inline of the NFQUEUE queue ID provided. May be provided + multiple times. + +.. option:: -s + + Path to a signature file to load. Will be loaded in addition to the + rule files specified in the configuration file. + +.. option:: -S + + Path to signature file to load exclusively. Signature files + specified in the configuration file will not be loaded. + +.. option:: -l + + Set log directory. Overrides the default-log-directory provided in + the configuration file. + +.. option:: -D + + Run as a daemon. + +.. option:: -k [all|none] + + Force (all) the checksum check or disable (none) all checksum + checks. + +.. option:: -V + + Display version. + +.. option:: -v[v] + + Increase the verbosity of logging. This is Suricata application + logging, not event or NSM logging. + +.. option:: -u + + Run the unit tests and exit. Requires that Suricata be compiled + with *--enable-unittests*. + +.. option:: -U, --unittest-filter=REGEX + + File the executed unit tests with a regular expression. + +.. option:: --list-unittests + + List all unit tests. + +.. option:: --fatal-unittests + + Enables fatal failure on a unit test error. Suricata will exit + instead of continuuing more tests. + +.. option:: --unittests-coverage + + Display unit test coverage report. + +.. option:: --list-app-layer-protos + + List all supported application layer protocols. + +.. option:: --list-keywords=[all|csv|] + + List all supported rule keywords. + +.. option:: --list-runmodes + + List all supported run modes. + +.. option:: --runmode + + Run with a specific run mode. Run modes may be viewed with the + *--list-runmodes* option. Usually one of *workers*, *autofp*, or + *single*. + +.. option:: --engine-analysis + + Print reports on analysis of different sections in the engine and + exit. Please have a look at the conf parameter engine-analysis on + what reports can be printed + +.. option:: --pidfile + + Write the process ID to file. Overrides the *pid-file* option in + the configuration file and forces the file to be written when not + running as a daemon. + +.. option:: --init-errors-fatal + + Exit with a failure when errors are encountered loading signatures. + +.. option:: --disable-detection + + Disable the detection engine. + +.. option:: --dump-config + + Dump the configuration loaded from the configuration file to the + terminal and exit. + +.. option:: --build-info + + Display the build information the Suricata was built with. + +.. option:: --pcap= + + Run in PCAP mode. If no device is provided the interfaces + provided in the *pcap* section of the configuration file will be + used. + +.. option:: --pcap-buffer-size= + + Set the size of the PCAP buffer (0 - 2147483647). + +.. option:: --af-packet= + + Run in AF_PACKET mode. If no device is provided the interfaces + provided in the *af-packet* section of the configuration file will be + used. + +.. option:: --simulate-ips + + Force the engine into IPS mode. Useful for QA. + +.. option:: --user= + + Set the process user after initialization. Overrides the user + provided in the *run-as* section of the configuration file. + +.. option:: --group= + + Set the process group to group after initialization. Overrides the + group provided in the *run-as* section of the configuration file. + +.. option:: --erf-in= + + Run in offline mode reading the specific ERF file (Endace + extensible record format). + +.. option:: --unix-socket= + + Use file as the Suricata unix control socket. Overrides the + *filename* provided in the *unix-command* section of the + configuration file. + +.. option:: --set = + + Set a configuration value. Useful for overriding basic + configuration parameters in the configuration. For example, to + change the default log directory:: + + --set default-log-dir=/var/tmp From b9a7335ec4605ba41f257059541efb964669cb36 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 7 Mar 2016 13:11:01 -0600 Subject: [PATCH 1831/2553] doc: expose variables for substition in docs --- doc/userguide/Makefile.am | 8 ++++++-- doc/userguide/conf.py | 22 ++++++++++++++++------ doc/userguide/manpages/suricata.rst | 9 +++++++++ 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index 27124d4e1da6..d3407aee7dd1 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -2,10 +2,14 @@ if HAVE_SPHINXBUILD man1_MANS = _build/man/suricata.1 html: - $(MAKE) -f Makefile.sphinx html + sysconfdir=$(sysconfdir) \ + localstatedir=$(localstatedir) \ + sphinx-build -b html -d _build/doctrees . _build/html _build/man/suricata.1: - $(MAKE) -f Makefile.sphinx man + sysconfdir=$(sysconfdir) \ + localstatedir=$(localstatedir) \ + sphinx-build -b man -d _build/doctrees . _build/man clean-local: rm -rf $(top_builddir)/doc/userguide/_build diff --git a/doc/userguide/conf.py b/doc/userguide/conf.py index 7bec508d3e66..5df33a98d09b 100644 --- a/doc/userguide/conf.py +++ b/doc/userguide/conf.py @@ -49,7 +49,7 @@ # General information about the project. project = u'Suricata' -copyright = u'2015, OISF' +copyright = u'2016, OISF' author = u'OISF' # The version info for the project you're documenting, acts as replacement for @@ -111,11 +111,13 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. if not on_rtd: - #html_theme = 'alabaster' - html_theme = 'sphinx_rtd_theme' - #html_theme = 'classic' - #html_theme = 'default' - #html_theme = 'nature' + # Attempt to use the read the docs theme. + try: + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + except: + html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -290,3 +292,11 @@ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False + +rst_epilog = """ +.. |sysconfdir| replace:: %(sysconfdir)s +.. |localstatedir| replace:: %(localstatedir)s +""" % { + "sysconfdir": os.getenv("sysconfdir", "/etc"), + "localstatedir": os.getenv("localstatedir", "/var"), +} diff --git a/doc/userguide/manpages/suricata.rst b/doc/userguide/manpages/suricata.rst index defa47008e0b..bb8922d4c970 100644 --- a/doc/userguide/manpages/suricata.rst +++ b/doc/userguide/manpages/suricata.rst @@ -191,3 +191,12 @@ OPTIONS change the default log directory:: --set default-log-dir=/var/tmp + +FILES AND DIRECTORIES +--------------------- + +|sysconfdir|/suricata/suricata.yaml + Default location of the Suricata configuration file. + +|localstatedir|/log/suricata + Default Suricata log directory. From b8521a52f38e1ccc5607a9b13ba8fe6ce6043940 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Sep 2016 09:28:09 -0600 Subject: [PATCH 1832/2553] doc: link up hyperscan and packet capture --- doc/userguide/performance/index.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/userguide/performance/index.rst b/doc/userguide/performance/index.rst index b06bee6f5862..989666ddf1bd 100644 --- a/doc/userguide/performance/index.rst +++ b/doc/userguide/performance/index.rst @@ -11,3 +11,5 @@ Performance runmodes tcmalloc ignoring-traffic + hyperscan + packet_capture From ab93eb97b9a61079afdfd66a52b1fe80b00040eb Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Sep 2016 09:29:17 -0600 Subject: [PATCH 1833/2553] doc: use - instead of _ in filenames for consistency --- doc/userguide/performance/index.rst | 2 +- .../performance/{packet_capture.rst => packet-capture.rst} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename doc/userguide/performance/{packet_capture.rst => packet-capture.rst} (100%) diff --git a/doc/userguide/performance/index.rst b/doc/userguide/performance/index.rst index 989666ddf1bd..7e08a99bdb8e 100644 --- a/doc/userguide/performance/index.rst +++ b/doc/userguide/performance/index.rst @@ -12,4 +12,4 @@ Performance tcmalloc ignoring-traffic hyperscan - packet_capture + packet-capture diff --git a/doc/userguide/performance/packet_capture.rst b/doc/userguide/performance/packet-capture.rst similarity index 100% rename from doc/userguide/performance/packet_capture.rst rename to doc/userguide/performance/packet-capture.rst From b1ced40ee437a964218fdb4eee4fd58c954e15f4 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Sep 2016 09:57:36 -0600 Subject: [PATCH 1834/2553] doc: get Suricata version from autoconf vars --- doc/userguide/Makefile.am | 2 ++ doc/userguide/conf.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index d3407aee7dd1..056e8237cb31 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -4,11 +4,13 @@ man1_MANS = _build/man/suricata.1 html: sysconfdir=$(sysconfdir) \ localstatedir=$(localstatedir) \ + version=$(PACKAGE_VERSION) \ sphinx-build -b html -d _build/doctrees . _build/html _build/man/suricata.1: sysconfdir=$(sysconfdir) \ localstatedir=$(localstatedir) \ + version=$(PACKAGE_VERSION) \ sphinx-build -b man -d _build/doctrees . _build/man clean-local: diff --git a/doc/userguide/conf.py b/doc/userguide/conf.py index 5df33a98d09b..02433a4936a4 100644 --- a/doc/userguide/conf.py +++ b/doc/userguide/conf.py @@ -57,7 +57,7 @@ # built documents. # # The short X.Y version. -version = '3.0dev' +version = os.environ.get('version', "unknown") # The full version, including alpha/beta/rc tags. release = version From 2e78bf0ba81bcb8cebc25bd49f717daf301d8658 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Sep 2016 10:37:51 -0600 Subject: [PATCH 1835/2553] doc: list files/directories in EXTRA_DIST So files get included in the distribution and pass make distcheck. --- doc/userguide/Makefile.am | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index 056e8237cb31..c70fafdf37f3 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -1,3 +1,28 @@ +EXTRA_DIST = \ + conf.py \ + index.rst \ + acknowledgements.rst \ + oinkmaster.rst \ + snort-compatibility.rst \ + command-line-options.rst \ + initscripts.rst \ + public-data-sets.rst \ + what-is-suricata.rst \ + dropping-privileges.rst \ + make-sense-alerts.rst \ + setting-up-ipsinline-for-linux.rst \ + capture-hardware \ + configuration \ + file-extraction \ + licenses \ + manpages \ + oinkmaster \ + output \ + performance \ + reputation \ + rules \ + setting-up-ipsinline-for-linux + if HAVE_SPHINXBUILD man1_MANS = _build/man/suricata.1 @@ -5,13 +30,15 @@ html: sysconfdir=$(sysconfdir) \ localstatedir=$(localstatedir) \ version=$(PACKAGE_VERSION) \ - sphinx-build -b html -d _build/doctrees . _build/html + sphinx-build -b html -d _build/doctrees \ + $(top_srcdir)/doc/userguide _build/html _build/man/suricata.1: sysconfdir=$(sysconfdir) \ localstatedir=$(localstatedir) \ version=$(PACKAGE_VERSION) \ - sphinx-build -b man -d _build/doctrees . _build/man + sphinx-build -b man -d _build/doctrees \ + $(top_srcdir)/doc/userguide _build/man clean-local: rm -rf $(top_builddir)/doc/userguide/_build From 6149b014ec3ec8e3bec380212488761371a8b075 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Sep 2016 10:48:14 -0600 Subject: [PATCH 1836/2553] doc: shorten some paths to satisfy distcheck Long paths were being dropped from the source package. --- .../elk.rst} | 12 ++++++------ .../elk}/Logstash1.png | Bin .../elk}/Logstash2.png | Bin .../elk}/Logstash3.png | Bin .../elk}/Logstash4.png | Bin .../elk}/Logstash5.png | Bin .../elk}/Logstash6.png | Bin .../files-json.rst} | 2 +- .../mongodb.rst | 0 .../{files-json-log-output => files-json}/mysql.rst | 0 .../postgresql.rst | 0 .../script-follow-json.rst | 0 .../useful-queries-for-mysql-and-postgresql.rst | 0 doc/userguide/output/index.rst | 2 +- 14 files changed, 8 insertions(+), 8 deletions(-) rename doc/userguide/output/{files-json-log-output/logstash-kibana-and-suricata-json-output.rst => files-json/elk.rst} (94%) rename doc/userguide/output/{files-json-log-output/logstash-kibana-and-suricata-json-output => files-json/elk}/Logstash1.png (100%) rename doc/userguide/output/{files-json-log-output/logstash-kibana-and-suricata-json-output => files-json/elk}/Logstash2.png (100%) rename doc/userguide/output/{files-json-log-output/logstash-kibana-and-suricata-json-output => files-json/elk}/Logstash3.png (100%) rename doc/userguide/output/{files-json-log-output/logstash-kibana-and-suricata-json-output => files-json/elk}/Logstash4.png (100%) rename doc/userguide/output/{files-json-log-output/logstash-kibana-and-suricata-json-output => files-json/elk}/Logstash5.png (100%) rename doc/userguide/output/{files-json-log-output/logstash-kibana-and-suricata-json-output => files-json/elk}/Logstash6.png (100%) rename doc/userguide/output/{files-json-log-output/files-json-log-output.rst => files-json/files-json.rst} (97%) rename doc/userguide/output/{files-json-log-output => files-json}/mongodb.rst (100%) rename doc/userguide/output/{files-json-log-output => files-json}/mysql.rst (100%) rename doc/userguide/output/{files-json-log-output => files-json}/postgresql.rst (100%) rename doc/userguide/output/{files-json-log-output => files-json}/script-follow-json.rst (100%) rename doc/userguide/output/{files-json-log-output => files-json}/useful-queries-for-mysql-and-postgresql.rst (100%) diff --git a/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst b/doc/userguide/output/files-json/elk.rst similarity index 94% rename from doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst rename to doc/userguide/output/files-json/elk.rst index adbb73aa6681..234cf203ca54 100644 --- a/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst +++ b/doc/userguide/output/files-json/elk.rst @@ -219,21 +219,21 @@ Some possible customization of the output of Logstash and Kibana -.. image:: logstash-kibana-and-suricata-json-output/Logstash1.png +.. image:: elk/Logstash1.png -.. image:: logstash-kibana-and-suricata-json-output/Logstash2.png +.. image:: elk/Logstash2.png -.. image:: logstash-kibana-and-suricata-json-output/Logstash3.png +.. image:: elk/Logstash3.png -.. image:: logstash-kibana-and-suricata-json-output/Logstash4.png +.. image:: elk/Logstash4.png -.. image:: logstash-kibana-and-suricata-json-output/Logstash5.png +.. image:: elk/Logstash5.png -.. image:: logstash-kibana-and-suricata-json-output/Logstash6.png +.. image:: elk/Logstash6.png Peter Manev diff --git a/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash1.png b/doc/userguide/output/files-json/elk/Logstash1.png similarity index 100% rename from doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash1.png rename to doc/userguide/output/files-json/elk/Logstash1.png diff --git a/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash2.png b/doc/userguide/output/files-json/elk/Logstash2.png similarity index 100% rename from doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash2.png rename to doc/userguide/output/files-json/elk/Logstash2.png diff --git a/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash3.png b/doc/userguide/output/files-json/elk/Logstash3.png similarity index 100% rename from doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash3.png rename to doc/userguide/output/files-json/elk/Logstash3.png diff --git a/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash4.png b/doc/userguide/output/files-json/elk/Logstash4.png similarity index 100% rename from doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash4.png rename to doc/userguide/output/files-json/elk/Logstash4.png diff --git a/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash5.png b/doc/userguide/output/files-json/elk/Logstash5.png similarity index 100% rename from doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash5.png rename to doc/userguide/output/files-json/elk/Logstash5.png diff --git a/doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash6.png b/doc/userguide/output/files-json/elk/Logstash6.png similarity index 100% rename from doc/userguide/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash6.png rename to doc/userguide/output/files-json/elk/Logstash6.png diff --git a/doc/userguide/output/files-json-log-output/files-json-log-output.rst b/doc/userguide/output/files-json/files-json.rst similarity index 97% rename from doc/userguide/output/files-json-log-output/files-json-log-output.rst rename to doc/userguide/output/files-json/files-json.rst index 036d77f73485..472ae3bbd153 100644 --- a/doc/userguide/output/files-json-log-output/files-json-log-output.rst +++ b/doc/userguide/output/files-json/files-json.rst @@ -8,7 +8,7 @@ What to do with files-json.log output postgresql useful-queries-for-mysql-and-postgresql mongodb - logstash-kibana-and-suricata-json-output + elk Suricata has the ability to produce the files-json.log output. Basically this is a JSON style format output logfile with entries like this: diff --git a/doc/userguide/output/files-json-log-output/mongodb.rst b/doc/userguide/output/files-json/mongodb.rst similarity index 100% rename from doc/userguide/output/files-json-log-output/mongodb.rst rename to doc/userguide/output/files-json/mongodb.rst diff --git a/doc/userguide/output/files-json-log-output/mysql.rst b/doc/userguide/output/files-json/mysql.rst similarity index 100% rename from doc/userguide/output/files-json-log-output/mysql.rst rename to doc/userguide/output/files-json/mysql.rst diff --git a/doc/userguide/output/files-json-log-output/postgresql.rst b/doc/userguide/output/files-json/postgresql.rst similarity index 100% rename from doc/userguide/output/files-json-log-output/postgresql.rst rename to doc/userguide/output/files-json/postgresql.rst diff --git a/doc/userguide/output/files-json-log-output/script-follow-json.rst b/doc/userguide/output/files-json/script-follow-json.rst similarity index 100% rename from doc/userguide/output/files-json-log-output/script-follow-json.rst rename to doc/userguide/output/files-json/script-follow-json.rst diff --git a/doc/userguide/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst b/doc/userguide/output/files-json/useful-queries-for-mysql-and-postgresql.rst similarity index 100% rename from doc/userguide/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst rename to doc/userguide/output/files-json/useful-queries-for-mysql-and-postgresql.rst diff --git a/doc/userguide/output/index.rst b/doc/userguide/output/index.rst index 40aec04dc047..6d9a4f286415 100644 --- a/doc/userguide/output/index.rst +++ b/doc/userguide/output/index.rst @@ -7,4 +7,4 @@ Output lua-output syslog-alerting-comp custom-http-logging - files-json-log-output/files-json-log-output.rst + files-json/files-json.rst From 614e2f1d432ba5ba8eeeada3170a489f1b1b7002 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Sep 2016 17:07:15 -0600 Subject: [PATCH 1837/2553] doc: make target for pdf, and suricata.1 shortcut --- doc/userguide/Makefile.am | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index c70fafdf37f3..9feb4f3f311e 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -26,19 +26,30 @@ EXTRA_DIST = \ if HAVE_SPHINXBUILD man1_MANS = _build/man/suricata.1 +SPHINX_BUILD = sphinx-build -q + html: sysconfdir=$(sysconfdir) \ localstatedir=$(localstatedir) \ version=$(PACKAGE_VERSION) \ - sphinx-build -b html -d _build/doctrees \ + $(SPHINX_BUILD) -b html -d _build/doctrees \ $(top_srcdir)/doc/userguide _build/html +pdf: + sysconfdir=$(sysconfdir) \ + localstatedir=$(localstatedir) \ + version=$(PACKAGE_VERSION) \ + $(SPHINX_BUILD) -b latex -d _build/doctrees \ + $(top_srcdir)/doc/userguide _build/latex + cd _build/latex && $(MAKE) all-pdf + _build/man/suricata.1: sysconfdir=$(sysconfdir) \ localstatedir=$(localstatedir) \ version=$(PACKAGE_VERSION) \ - sphinx-build -b man -d _build/doctrees \ + $(SPHINX_BUILD) -b man -d _build/doctrees \ $(top_srcdir)/doc/userguide _build/man +man: _build/man/suricata.1 clean-local: rm -rf $(top_builddir)/doc/userguide/_build From 7ad667f282aaa5b7dd580da317fa3fdda05b5401 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Sep 2016 07:38:45 +0200 Subject: [PATCH 1838/2553] doc: move snort compat to rule chapter --- doc/userguide/Makefile.am | 1 - doc/userguide/index.rst | 1 - doc/userguide/rules/index.rst | 1 + doc/userguide/{ => rules}/snort-compatibility.rst | 0 4 files changed, 1 insertion(+), 2 deletions(-) rename doc/userguide/{ => rules}/snort-compatibility.rst (100%) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index 9feb4f3f311e..58df915a9d86 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -3,7 +3,6 @@ EXTRA_DIST = \ index.rst \ acknowledgements.rst \ oinkmaster.rst \ - snort-compatibility.rst \ command-line-options.rst \ initscripts.rst \ public-data-sets.rst \ diff --git a/doc/userguide/index.rst b/doc/userguide/index.rst index 07f284e7208a..9524ff76ab17 100644 --- a/doc/userguide/index.rst +++ b/doc/userguide/index.rst @@ -7,7 +7,6 @@ Suricata User Guide what-is-suricata command-line-options - snort-compatibility rules/index.rst oinkmaster make-sense-alerts diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst index 9cf0058edb1a..db477dd185e9 100644 --- a/doc/userguide/rules/index.rst +++ b/doc/userguide/rules/index.rst @@ -20,3 +20,4 @@ Suricata Rules normalized-buffers modbus-keyword dnp3-keywords + snort-compatibility diff --git a/doc/userguide/snort-compatibility.rst b/doc/userguide/rules/snort-compatibility.rst similarity index 100% rename from doc/userguide/snort-compatibility.rst rename to doc/userguide/rules/snort-compatibility.rst From f511f863986db86d5b060bc1a92da1077cd6e3fb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Sep 2016 07:39:09 +0200 Subject: [PATCH 1839/2553] doc: rename to 'Suricata User Guide' --- doc/userguide/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/userguide/conf.py b/doc/userguide/conf.py index 02433a4936a4..e16144cb85c0 100644 --- a/doc/userguide/conf.py +++ b/doc/userguide/conf.py @@ -231,7 +231,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'Suricata.tex', u'Suricata Documentation', + (master_doc, 'Suricata.tex', u'Suricata User Guide', u'OISF', 'manual'), ] @@ -276,7 +276,7 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'Suricata', u'Suricata Documentation', + (master_doc, 'Suricata', u'Suricata User Guide', author, 'Suricata', 'One line description of project.', 'Miscellaneous'), ] From 7fa390de39b155b7e39f811bc6478d5856fab2e2 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Sep 2016 21:16:05 -0600 Subject: [PATCH 1840/2553] doc: bundle pre-built man page in distribution --- configure.ac | 4 ++++ doc/userguide/Makefile.am | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 9861b4aaf766..1ccd5e343999 100644 --- a/configure.ac +++ b/configure.ac @@ -1885,8 +1885,12 @@ AC_PATH_PROG(HAVE_SPHINXBUILD, sphinx-build, "no") if test "$HAVE_SPHINXBUILD" = "no"; then enable_sphinxbuild=no + if test -e "$srcdir/doc/userguide/suricata.1"; then + have_suricata_man=yes + fi fi AM_CONDITIONAL([HAVE_SPHINXBUILD], [test "x$enable_sphinxbuild" != "xno"]) + AM_CONDITIONAL([HAVE_SURICATA_MAN], [test "x$have_suricata_man" = "xyes"]) # get revision if test -f ./revision; then diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index 58df915a9d86..8f64e9a154ff 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -22,8 +22,14 @@ EXTRA_DIST = \ rules \ setting-up-ipsinline-for-linux +if HAVE_SURICATA_MAN +man1_MANS = suricata.1 +endif + if HAVE_SPHINXBUILD -man1_MANS = _build/man/suricata.1 +man1_MANS = suricata.1 + +EXTRA_DIST += $(man1_MANS) SPHINX_BUILD = sphinx-build -q @@ -48,8 +54,13 @@ _build/man/suricata.1: version=$(PACKAGE_VERSION) \ $(SPHINX_BUILD) -b man -d _build/doctrees \ $(top_srcdir)/doc/userguide _build/man + man: _build/man/suricata.1 +suricata.1: _build/man/suricata.1 + cp _build/man/suricata.1 suricata.1 + clean-local: rm -rf $(top_builddir)/doc/userguide/_build + rm -f $(top_builddir)/doc/userguide/suricata.1 endif From 879ab41ade086a05a4eacb3d3e0fe83f69b805e5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Sep 2016 13:33:46 +0200 Subject: [PATCH 1841/2553] doc: move drop privs into configuration --- doc/userguide/Makefile.am | 1 - doc/userguide/command-line-options.rst | 2 -- doc/userguide/{ => configuration}/dropping-privileges.rst | 0 doc/userguide/configuration/index.rst | 1 + 4 files changed, 1 insertion(+), 3 deletions(-) rename doc/userguide/{ => configuration}/dropping-privileges.rst (100%) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index 8f64e9a154ff..9f83c42f4376 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -7,7 +7,6 @@ EXTRA_DIST = \ initscripts.rst \ public-data-sets.rst \ what-is-suricata.rst \ - dropping-privileges.rst \ make-sense-alerts.rst \ setting-up-ipsinline-for-linux.rst \ capture-hardware \ diff --git a/doc/userguide/command-line-options.rst b/doc/userguide/command-line-options.rst index 29d32e9600bf..672e646a4b98 100644 --- a/doc/userguide/command-line-options.rst +++ b/doc/userguide/command-line-options.rst @@ -3,8 +3,6 @@ Command Line Options .. toctree:: - dropping-privileges - You can use command line options in two ways. Using only one line followed by one character or using two lines followed by a word, like this: diff --git a/doc/userguide/dropping-privileges.rst b/doc/userguide/configuration/dropping-privileges.rst similarity index 100% rename from doc/userguide/dropping-privileges.rst rename to doc/userguide/configuration/dropping-privileges.rst diff --git a/doc/userguide/configuration/index.rst b/doc/userguide/configuration/index.rst index 6327c7274cdc..f25591952c7d 100644 --- a/doc/userguide/configuration/index.rst +++ b/doc/userguide/configuration/index.rst @@ -8,3 +8,4 @@ Configuration snort-to-suricata log-rotation multi-tenant + dropping-privileges From 1f2f1d70634221c637685b43fe50541ca7d52267 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Sep 2016 13:45:55 +0200 Subject: [PATCH 1842/2553] doc: commandline improvements --- doc/userguide/command-line-options.rst | 63 ++++++++++++++++++++------ 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/doc/userguide/command-line-options.rst b/doc/userguide/command-line-options.rst index 672e646a4b98..de981ba44e5c 100644 --- a/doc/userguide/command-line-options.rst +++ b/doc/userguide/command-line-options.rst @@ -3,14 +3,15 @@ Command Line Options .. toctree:: -You can use command line options in two ways. Using only one line -followed by one character or using two lines followed by a word, like -this: +Suricata's command line options: -:: +.. option:: -h - -a - --long-option + Display a brief usage overview. + +.. option:: -V + + Displays the version of Suricata. .. option:: -c @@ -20,8 +21,13 @@ this: .. option:: -i After the -i option you can enter the interface card you would like - to use to sniff packets from. It concerns sniffing packets with - libpcap in the pcap live mode. + to use to sniff packets from. This option will try to use the best + capture method available. + +.. option:: -v + + The -v option enables more verbosity of Suricata's output. Supply + multiple times for more verbosity. .. option:: -r @@ -32,7 +38,12 @@ this: .. option:: -s With the -s option you can set a file with signatures, which will - be loaded together with the rules set in yaml. + be loaded together with the rules set in the yaml. + +.. option:: -S + + With the -S option you can set a file with signatures, which will + be loaded exclusively, regardless of the rules set in the yaml. .. option:: -l @@ -71,9 +82,37 @@ this: For more information about runmodes see: :doc:`performance/runmodes` +.. option:: --build-info + + Gives an overview of the configure and build options that were + supplied to Suricata's build process at compile time. + +Capture Options +~~~~~~~~~~~~~~~ + +.. option:: --af-packet +.. option:: --af-packet= + + Enable capture of packet using AF_PACKET on Linux. If no device is + supplied, the list of devices from the af-packet section in the + yaml is used. + +.. option:: --netmap +.. option:: --netmap= + + Enable capture of packet using NETMAP on FreeBSD or Linux. If no + device is supplied, the list of devices from the af-packet section + in the yaml is used. + Unit Tests ~~~~~~~~~~ +Builtin unittests are only available if Suricata has been built with +--enable-unittests. + +Running unittests does not take a configuration file. Use -l to supply +an output directory. + .. option:: -u With the -u option you can run unit tests to test Suricata's code. @@ -95,9 +134,3 @@ Unit Tests will stop immediately after one test fails so you can see directly where it went wrong. -PF_RING options -~~~~~~~~~~~~~~~ - -In order to use PF_RING-enabled libpcap, you must start suricata with -the --pfring-int= switch or it will not invoke the PF_RING -enhancements in libpcap. From 43c2db0a557352e9f73d097f314269f48484a76a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Sep 2016 14:10:56 +0200 Subject: [PATCH 1843/2553] doc: update what is suricata section --- doc/userguide/what-is-suricata.rst | 62 ++---------------------------- 1 file changed, 4 insertions(+), 58 deletions(-) diff --git a/doc/userguide/what-is-suricata.rst b/doc/userguide/what-is-suricata.rst index ef585b67ae10..8cd49cdca94a 100644 --- a/doc/userguide/what-is-suricata.rst +++ b/doc/userguide/what-is-suricata.rst @@ -1,67 +1,13 @@ What is Suricata ================ -The Suricata Engine is an Open Source Next Generation Intrusion -Detection and Prevention Engine. This engine is not intended to just -replace or emulate the existing tools in the industry, but will bring -new ideas and technologies to the field. The Suricata Engine and the -HTP Library are available to use under the GPLv2. +Suricata is a high performance Network IDS, IPS and Network Security Monitoring engine. It is open source and owned by a community-run non-profit foundation, the Open Information Security Foundation (OISF). Suricata is developed by the OISF. -IDS/IPS -------- - -Suricata is a rule-based ID/PS engine that utilises externally -developed rule sets to monitor network traffic and provide alerts to -the system administrator when suspicious events occur. Designed to be -compatible with existing network security components, Suricata -features unified output functionality and pluggable library options to -accept calls from other applications. The initial release of Suricata -runs on a Linux 2.6 platform that supports inline and passive traffic -monitoring configuration capable of handling multiple gigabit traffic -levels. Linux 2.4 is supported with reduced configuration -functionality, such as no inline option. Available under Version 2 of -the General Public License, Suricata eliminates the ID/PS engine cost -concerns while providing a scalable option for the most complex -network security architectures. - -Multi-threading ---------------- - -As a multi-threaded engine, Suricata offers increased speed and -efficiency in network traffic analysis. In addition to hardware -acceleration (with hardware and network card limitations), the engine -is build to utilise the increased processing power offered by the -latest multi-core CPU chip sets. Suricata is developed for ease of -implementation and accompanied by a step-by-step getting started -documentation and user manual. - -Development and Features ------------------------- - -The goal of the Suricata Project Phase 1 was to have a distributable -and functional ID/PS engine. The initial beta release was made -available for download on January 1, 2010. The engine supports or -provides the following functionality: the latest Snort VRT, Snort -logging, rule language options, multi-threading, hardware acceleration -(with hardware and network card dependencies/limitations), unified -output enabling interaction with external log management systems, -IPv6, rule-based IP reputation, library plug-ability for interaction -with other applications, performance statistics output, and a simple -and effective getting started user manual. +About the Open Information Security Foundation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -By engaging the open source community and the leading ID/PS rule set -resources available, OISF has built the Suricata engine to simplify -the process of maintaining optimum security levels. Through strategic -partnerships, OISF is leveraging the expertise of Emerging Threats -(www.emergingthreats.net) and other prominent resources in the -industry to provide the most current and comprehensive rule sets -available. +The Open Information Security Foundation is a non-profit foundation organized to build community and to support open-source security technologies like Suricata, the world-class IDS/IPS engine. -The HTP Library is an HTTP normaliser and parser written by Ivan -Ristic of Mod Security fame for the OISF. This integrates and provides -very advanced processing of HTTP streams for Suricata. The HTP library -is required by the engine, but may also be used independently in a -range of applications and tools. License ------- From 73b355e24a3dd9d4ec4b7cbe8870083dc243bf2a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Sep 2016 14:47:23 +0200 Subject: [PATCH 1844/2553] doc: fix lua keyword name --- doc/userguide/rules/rule-lua-scripting.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide/rules/rule-lua-scripting.rst b/doc/userguide/rules/rule-lua-scripting.rst index 726f1ab3224e..8094ec85d034 100644 --- a/doc/userguide/rules/rule-lua-scripting.rst +++ b/doc/userguide/rules/rule-lua-scripting.rst @@ -5,7 +5,7 @@ Syntax: :: - luajit:[!]; + lua:[!]; The script filename will be appended to your default rules location. From 7011d8f34cc235eaeac2787c787041a07f1afcc7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Sep 2016 15:14:00 +0200 Subject: [PATCH 1845/2553] doc: remove/cleanup 'guides' --- .../file-extraction/file-extraction.rst | 65 ++------- doc/userguide/file-extraction/md5.rst | 129 +----------------- doc/userguide/output/index.rst | 1 - 3 files changed, 10 insertions(+), 185 deletions(-) diff --git a/doc/userguide/file-extraction/file-extraction.rst b/doc/userguide/file-extraction/file-extraction.rst index 2cd9e710f740..001ea525cd1d 100644 --- a/doc/userguide/file-extraction/file-extraction.rst +++ b/doc/userguide/file-extraction/file-extraction.rst @@ -1,19 +1,10 @@ File Extraction =============== -.. toctree:: - - md5 - filemd5-and-whiteblacklisting-with-md5 - public-sha1-md5-data-sets - -Starting with Suricata version 1.2 it's possible to extract files from HTTP sessions as well as match on file name, extension and "magic". - - Architecture ~~~~~~~~~~~~ -The file extraction code works on top of the HTTP parser which itself is largely a wrapper for libhtp. The HTTP parser takes care of dechunking and unzipping the request and/or response data if necessary. The HTTP parser runs on top of the stream reassembly engine. +The file extraction code works on top of the HTTP and SMTP parsers. The HTTP parser takes care of dechunking and unzipping the request and/or response data if necessary. The HTTP/SMTP parsers runs on top of the stream reassembly engine. This means that settings in the stream engine, reassembly engine and the HTTP parser all affect the workings of the file extraction. @@ -31,53 +22,6 @@ Settings *libhtp.default-config.response-body-limit* / *libhtp.server-config..response-body-limit* is like the request body limit, only it applies to the HTTP response body. -NIC offloading -~~~~~~~~~~~~~~ - -NIC offloading should be disabled: - -:: - - - apt-get install ethtool - - -:: - - - ethtool -k eth3 - - Offload parameters for eth3: - rx-checksumming: off - tx-checksumming: off - scatter-gather: off - tcp-segmentation-offload: off - udp-fragmentation-offload: off - generic-segmentation-offload: off - generic-receive-offload: off - large-receive-offload: off - rx-vlan-offload: off - tx-vlan-offload: off - -Everything should be OFF. If it is not here is how you can disable it: - - -:: - - - ethtool -K eth3 tso off - ethtool -K eth3 gro off - ethtool -K eth3 lro off - ethtool -K eth3 gso off - ethtool -K eth3 rx off - ethtool -K eth3 tx off - ethtool -K eth3 sg off - ethtool -K eth3 rxvlan off - ethtool -K eth3 txvlan off - -NOTICE the difference between small k and a BIG K !! -Please make sure you choose the appropriate interface name (eth0,eth1,eth5...) - Output ~~~~~~ @@ -148,3 +92,10 @@ MD5 ~~~ Suricata can calculate MD5 checksums of files on the fly and log them. See :doc:`md5` for an explanation on how to enable this. + + +.. toctree:: + + md5 + public-sha1-md5-data-sets + diff --git a/doc/userguide/file-extraction/md5.rst b/doc/userguide/file-extraction/md5.rst index 3cc94cad1873..7e992a7d28ef 100644 --- a/doc/userguide/file-extraction/md5.rst +++ b/doc/userguide/file-extraction/md5.rst @@ -3,125 +3,6 @@ Storing MD5s checksums ====================== -In this particular example we are using: Ubuntu 14.04 LTS - -Also - we are using the latest git master (git installation) - -Make sure you have libnss and libnspr installed -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -:: - - - root@LTS-64-1:~/Work/tmp/oisf# dpkg -l |grep libnss - ii libnss-mdns:amd64 0.10-6 amd64 NSS module for Multicast DNS name resolution - ii libnss3:amd64 2:3.17.4-0ubuntu0.14.04.1 amd64 Network Security Service libraries - ii libnss3-1d:amd64 2:3.17.4-0ubuntu0.14.04.1 amd64 Network Security Service libraries - transitional package - ii libnss3-dev:amd64 2:3.17.4-0ubuntu0.14.04.1 amd64 Development files for the Network Security Service libraries - ii libnss3-nssdb 2:3.17.4-0ubuntu0.14.04.1 all Network Security Security libraries - shared databases - ii libnss3-tools 2:3.17.4-0ubuntu0.14.04.1 amd64 Network Security Service tools - - - -:: - - - root@LTS-64-1:~/Work/tmp/oisf# dpkg -l |grep libnspr - ii libnspr4:amd64 2:4.10.7-0ubuntu0.14.04.1 amd64 NetScape Portable Runtime Library - ii libnspr4-dev 2:4.10.7-0ubuntu0.14.04.1 amd64 Development files for the NetScape Portable Runtime library - -If not install them: - -:: - - - apt-get install libnss3-dev libnspr4-dev - -**Note:** Fedora users need to install the following: - -:: - - - nss-util - nss-util-devel - nss-devel - nspr-devel - nspr - -Get the Suricata code -~~~~~~~~~~~~~~~~~~~~~ - -Execute: - -:: - - - git clone git://phalanx.openinfosecfoundation.org/oisf.git && cd oisf - git clone https://github.com/OISF/libhtp.git -b 0.5.x - -Building Suricata -~~~~~~~~~~~~~~~~~~ - -You have to compile/install suri like this in order to enable MD5s: - -:: - - - ./autogen.sh - ./configure --with-libnss-libraries=/usr/lib --with-libnss-includes=/usr/include/nss/ --with-libnspr-libraries=/usr/lib --with-libnspr-includes=/usr/include/nspr - make clean - make - sudo make install - - -Output of configure: - - -:: - - - Suricata Configuration: -   AF_PACKET support:                       yes -   PF_RING support:                         no -   NFQueue support:                         no -   IPFW support:                            no -   DAG enabled:                             no -   Napatech enabled:                        no - -   libnss support:                          yes -   libnspr support:                         yes -   Prelude support:                         no -   PCRE jit:                                no - -This is what is important to have: - -:: - - - libnss support:                          yes - libnspr support:                         yes - -Confirm everything is built correctly: - - -:: - - - # suricata --build-info - [10010] 1/5/2012 -- 11:16:23 - (suricata.c:502) (SCPrintBuildInfo) -- This is Suricata version 1.3dev (rev e6dea5c) - [10010] 1/5/2012 -- 11:16:23 - (suricata.c:575) (SCPrintBuildInfo) -- Features: PCAP_SET_BUFF LIBPCAP_VERSION_MAJOR=1 AF_PACKET HAVE_PACKET_FANOUT LIBCAP_NG LIBNET1.1 HAVE_HTP_URI_NORMALIZE_HOOK HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW HAVE_NSS - [10010] 1/5/2012 -- 11:16:23 - (suricata.c:589) (SCPrintBuildInfo) -- 32-bits, Little-endian architecture - [10010] 1/5/2012 -- 11:16:23 - (suricata.c:591) (SCPrintBuildInfo) -- GCC version 4.4.5, C version 199901 - [10010] 1/5/2012 -- 11:16:23 - (suricata.c:597) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 - [10010] 1/5/2012 -- 11:16:23 - (suricata.c:600) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 - [10010] 1/5/2012 -- 11:16:23 - (suricata.c:603) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 - [10010] 1/5/2012 -- 11:16:23 - (suricata.c:606) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 - [10010] 1/5/2012 -- 11:16:23 - (suricata.c:613) (SCPrintBuildInfo) -- compiled with -fstack-protector - [10010] 1/5/2012 -- 11:16:23 - (suricata.c:619) (SCPrintBuildInfo) -- compiled with _FORTIFY_SOURCE=2 - -Make sure we have **HAVE_NSS** in the **Features** line. - Configuration ~~~~~~~~~~~~~ @@ -194,7 +75,7 @@ For the purpose of testing we use this rule only in a file.rules (a test/example This rule above will save all the file data for files that are opened/downloaded through HTTP -Start Suricta (-S option loads ONLY the specified rule file, with disregard if any other rules that are enabled in suricata.yaml): +Start Suricata (-S option loads ONLY the specified rule file, with disregard if any other rules that are enabled in suricata.yaml): :: @@ -203,12 +84,7 @@ Start Suricta (-S option loads ONLY the specified rule file, with disregard if a suricata -c /etc/suricata/suricata.yaml -S file.rules -i eth0 -I tried that link (Cisco Prod Brochure PDF, just googled "Cisco PDF"): - -* http://www.cisco.com/c/en/us/products/routers/3800-series-integrated-services-routers-isr/index.html - -and in file directory (/var/log/suricata/files) I got the meta data: - +Meta data: :: @@ -263,4 +139,3 @@ If you would like to log MD5s for everything and anything that passes through th force-magic: yes # force logging magic on all logged files force-md5: yes # force logging of md5 checksums -This is in short what is needed to have MD5s logged. diff --git a/doc/userguide/output/index.rst b/doc/userguide/output/index.rst index 6d9a4f286415..e0738e01f3f0 100644 --- a/doc/userguide/output/index.rst +++ b/doc/userguide/output/index.rst @@ -7,4 +7,3 @@ Output lua-output syslog-alerting-comp custom-http-logging - files-json/files-json.rst From 616782aa986be1a5da6db405413cf9cda8d4645e Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Wed, 20 Jul 2016 11:46:00 +0200 Subject: [PATCH 1846/2553] packet: add API for bypass --- src/decode.c | 7 +++++++ src/decode.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/src/decode.c b/src/decode.c index 95504d843db5..7980e2019530 100644 --- a/src/decode.c +++ b/src/decode.c @@ -382,6 +382,13 @@ void PacketDefragPktSetupParent(Packet *parent) DecodeSetNoPayloadInspectionFlag(parent); } +void PacketBypassCallback(Packet *p) +{ + if (p->BypassPacketsFlow) { + p->BypassPacketsFlow(p); + } +} + void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) { /* register counters */ diff --git a/src/decode.h b/src/decode.h index 0a829ec2fa2d..bb4d39f96b67 100644 --- a/src/decode.h +++ b/src/decode.h @@ -447,6 +447,9 @@ typedef struct Packet_ /** The release function for packet structure and data */ void (*ReleasePacket)(struct Packet_ *); + /** The function triggering bypass the flow in the capture method. + * Return 1 for success and 0 on error */ + int (*BypassPacketsFlow)(struct Packet_ *); /* pkt vars */ PktVar *pktvar; @@ -774,6 +777,7 @@ void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s); (p)->vlanh[1] = NULL; \ (p)->payload = NULL; \ (p)->payload_len = 0; \ + (p)->BypassPacketsFlow = NULL; \ (p)->pktlen = 0; \ (p)->alerts.cnt = 0; \ (p)->alerts.drop.action = 0; \ @@ -902,6 +906,7 @@ int PacketCopyData(Packet *p, uint8_t *pktdata, int pktlen); int PacketSetData(Packet *p, uint8_t *pktdata, int pktlen); int PacketCopyDataOffset(Packet *p, int offset, uint8_t *data, int datalen); const char *PktSrcToString(enum PktSrcEnum pkt_src); +void PacketBypassCallback(Packet *p); DecodeThreadVars *DecodeThreadVarsAlloc(ThreadVars *); void DecodeThreadVarsFree(ThreadVars *, DecodeThreadVars *); From e88555caf96feb0a78552f02c48a4a5f294cf196 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 17 Sep 2016 10:18:08 +0200 Subject: [PATCH 1847/2553] flow: add bypassed states This patch adds two new states to the flow: * local bypass: for suricata only bypass, packets belonging to a flow in this state will be discard fast * capture bypass: capture method is handling the bypass and suricata will discard packets that are currently queued A bypassed state to flow that will be set on flow when a bypass decision is taken. In the case of capture bypass this will allow to remove faster the flow entry from the flow table instead of waiting for the "established" timeout. --- src/flow-manager.c | 6 ++++++ src/flow.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/flow-manager.c b/src/flow-manager.c index 0deb0bc571ca..0455b90ef07c 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -67,6 +67,8 @@ #include "output-flow.h" +#define FLOW_BYPASSED_TIMEOUT 6 + /* Run mode selected at suricata.c */ extern int run_mode; @@ -203,11 +205,15 @@ static inline uint32_t FlowGetFlowTimeout(const Flow *f, enum FlowState state) timeout = flow_timeouts[f->protomap].new_timeout; break; case FLOW_STATE_ESTABLISHED: + case FLOW_STATE_LOCAL_BYPASSED: timeout = flow_timeouts[f->protomap].est_timeout; break; case FLOW_STATE_CLOSED: timeout = flow_timeouts[f->protomap].closed_timeout; break; + case FLOW_STATE_CAPTURE_BYPASSED: + timeout = FLOW_BYPASSED_TIMEOUT; + break; } return timeout; } diff --git a/src/flow.h b/src/flow.h index df5d9a4ac4d7..ec05ec1765e6 100644 --- a/src/flow.h +++ b/src/flow.h @@ -425,6 +425,8 @@ enum FlowState { FLOW_STATE_NEW = 0, FLOW_STATE_ESTABLISHED, FLOW_STATE_CLOSED, + FLOW_STATE_LOCAL_BYPASSED, + FLOW_STATE_CAPTURE_BYPASSED, }; typedef struct FlowProtoTimeout_ { From 745dad9809bde03c6e3560e969b255321a241556 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 16 Sep 2016 00:49:35 +0200 Subject: [PATCH 1848/2553] flow: display info about bypass in log --- src/flow-manager.c | 4 ++++ src/flow.h | 1 + src/output-json-flow.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/src/flow-manager.c b/src/flow-manager.c index 0455b90ef07c..09e190f46e2f 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -349,6 +349,10 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, f->flow_end_flags |= FLOW_END_FLAG_STATE_ESTABLISHED; else if (state == FLOW_STATE_CLOSED) f->flow_end_flags |= FLOW_END_FLAG_STATE_CLOSED; + else if (state == FLOW_STATE_LOCAL_BYPASSED) + f->flow_end_flags |= FLOW_END_FLAG_STATE_BYPASSED; + else if (state == FLOW_STATE_CAPTURE_BYPASSED) + f->flow_end_flags |= FLOW_END_FLAG_STATE_BYPASSED; if (emergency) f->flow_end_flags |= FLOW_END_FLAG_EMERGENCY; diff --git a/src/flow.h b/src/flow.h index ec05ec1765e6..e42e21147bfb 100644 --- a/src/flow.h +++ b/src/flow.h @@ -190,6 +190,7 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_END_FLAG_TIMEOUT 0x10 #define FLOW_END_FLAG_FORCED 0x20 #define FLOW_END_FLAG_SHUTDOWN 0x40 +#define FLOW_END_FLAG_STATE_BYPASSED 0x80 /** Mutex or RWLocks for the flow. */ //#define FLOWLOCK_RWLOCK diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 2d0f76acfe65..8e34169e3889 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -219,6 +219,8 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) state = "established"; else if (f->flow_end_flags & FLOW_END_FLAG_STATE_CLOSED) state = "closed"; + else if (f->flow_end_flags & FLOW_END_FLAG_STATE_BYPASSED) + state = "bypassed"; json_object_set_new(hjs, "state", json_string(state)); From 07ef451c2b89f6785047b4855003895e002b9fcb Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 24 Sep 2016 12:12:09 +0200 Subject: [PATCH 1849/2553] flow: add pruned bypassed flow counter --- src/flow-manager.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 09e190f46e2f..eacd69f30069 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -110,6 +110,7 @@ typedef struct FlowTimeoutCounters_ { uint32_t new; uint32_t est; uint32_t clo; + uint32_t byp; uint32_t tcp_reuse; uint32_t flows_checked; @@ -380,6 +381,10 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, case FLOW_STATE_CLOSED: counters->clo++; break; + case FLOW_STATE_LOCAL_BYPASSED: + case FLOW_STATE_CAPTURE_BYPASSED: + counters->byp++; + break; } counters->flows_removed++; } else { @@ -555,6 +560,7 @@ typedef struct FlowManagerThreadData_ { uint16_t flow_mgr_cnt_clo; uint16_t flow_mgr_cnt_new; uint16_t flow_mgr_cnt_est; + uint16_t flow_mgr_cnt_byp; uint16_t flow_mgr_spare; uint16_t flow_emerg_mode_enter; uint16_t flow_emerg_mode_over; @@ -605,6 +611,7 @@ static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) ftd->flow_mgr_cnt_clo = StatsRegisterCounter("flow_mgr.closed_pruned", t); ftd->flow_mgr_cnt_new = StatsRegisterCounter("flow_mgr.new_pruned", t); ftd->flow_mgr_cnt_est = StatsRegisterCounter("flow_mgr.est_pruned", t); + ftd->flow_mgr_cnt_est = StatsRegisterCounter("flow_mgr.bypassed_pruned", t); ftd->flow_mgr_spare = StatsRegisterCounter("flow.spare", t); ftd->flow_emerg_mode_enter = StatsRegisterCounter("flow.emerg_mode_entered", t); ftd->flow_emerg_mode_over = StatsRegisterCounter("flow.emerg_mode_over", t); @@ -691,7 +698,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) FlowUpdateSpareFlows(); /* try to time out flows */ - FlowTimeoutCounters counters = { 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,}; + FlowTimeoutCounters counters = { 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0}; FlowTimeoutHash(&ts, 0 /* check all */, ftd->min, ftd->max, &counters); @@ -711,6 +718,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) StatsAddUI64(th_v, ftd->flow_mgr_cnt_clo, (uint64_t)counters.clo); StatsAddUI64(th_v, ftd->flow_mgr_cnt_new, (uint64_t)counters.new); StatsAddUI64(th_v, ftd->flow_mgr_cnt_est, (uint64_t)counters.est); + StatsAddUI64(th_v, ftd->flow_mgr_cnt_byp, (uint64_t)counters.byp); StatsAddUI64(th_v, ftd->flow_tcp_reuse, (uint64_t)counters.tcp_reuse); StatsSetUI64(th_v, ftd->flow_mgr_flows_checked, (uint64_t)counters.flows_checked); @@ -1363,7 +1371,7 @@ static int FlowMgrTest05 (void) struct timeval ts; TimeGet(&ts); /* try to time out flows */ - FlowTimeoutCounters counters = { 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,}; + FlowTimeoutCounters counters = { 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0}; FlowTimeoutHash(&ts, 0 /* check all */, 0, flow_config.hash_size, &counters); if (flow_recycle_q.len > 0) { From 39c8786a8ef2f146cfaff04929d3a19617933bfc Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 26 Sep 2016 01:25:32 +0200 Subject: [PATCH 1850/2553] flow: get bypass info in get used flow function --- src/flow-hash.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/flow-hash.c b/src/flow-hash.c index a330101b991d..79758fc70138 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -661,6 +661,10 @@ static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv) f->flow_end_flags |= FLOW_END_FLAG_STATE_ESTABLISHED; else if (state == FLOW_STATE_CLOSED) f->flow_end_flags |= FLOW_END_FLAG_STATE_CLOSED; + else if (state == FLOW_STATE_CAPTURE_BYPASSED) + f->flow_end_flags |= FLOW_END_FLAG_STATE_BYPASSED; + else if (state == FLOW_STATE_LOCAL_BYPASSED) + f->flow_end_flags |= FLOW_END_FLAG_STATE_BYPASSED; f->flow_end_flags |= FLOW_END_FLAG_FORCED; From 68d9677eea1fce8553223c49e7d808d0deee200c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 26 Sep 2016 01:25:52 +0200 Subject: [PATCH 1851/2553] flow: force reassembly for bypassed flows As capture method like nfq will cut both side of the flow instantly we will not get the hack for most data which have been received. So it is better to force reassembly to be sure to get the timeout of the entry. --- src/flow-manager.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/flow-manager.c b/src/flow-manager.c index eacd69f30069..2a30fdcddc41 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -265,6 +265,16 @@ static int FlowManagerFlowTimedOut(Flow *f, struct timeval *ts) } int server = 0, client = 0; + + int state = SC_ATOMIC_GET(f->flow_state); + if ((state == FLOW_STATE_LOCAL_BYPASSED) || + (state == FLOW_STATE_CAPTURE_BYPASSED)) { + if (FlowForceReassemblyNeedReassembly(f, &server, &client) == 1) { + FlowForceReassemblyForFlow(f, server, client); + } + return 1; + } + if (!(f->flags & FLOW_TIMEOUT_REASSEMBLY_DONE) && FlowForceReassemblyNeedReassembly(f, &server, &client) == 1) { FlowForceReassemblyForFlow(f, server, client); From 285b4dd981c3d62997477f94fe267ccc7e525fc6 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 19 Sep 2016 16:21:55 +0200 Subject: [PATCH 1852/2553] decode: implement bypass function Call the packet bypass callback if necessary and update the flow state. In case of failure we switch to local bypassed state and set capture bypassed state if the callback is successful. --- src/decode.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/decode.c b/src/decode.c index 7980e2019530..209a55080caf 100644 --- a/src/decode.c +++ b/src/decode.c @@ -384,8 +384,18 @@ void PacketDefragPktSetupParent(Packet *parent) void PacketBypassCallback(Packet *p) { - if (p->BypassPacketsFlow) { - p->BypassPacketsFlow(p); + /* Don't try to bypass if flow is already out or + * if we have failed to do it once */ + int state = SC_ATOMIC_GET(p->flow->flow_state); + if ((state == FLOW_STATE_LOCAL_BYPASSED) || + (state == FLOW_STATE_CAPTURE_BYPASSED)) { + return; + } + + if (p->BypassPacketsFlow && p->BypassPacketsFlow(p)) { + FlowUpdateState(p->flow, FLOW_STATE_CAPTURE_BYPASSED); + } else { + FlowUpdateState(p->flow, FLOW_STATE_LOCAL_BYPASSED); } } From 97783f81428049dec040f53207b2bd9743e266dc Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 23 May 2016 09:31:12 +0200 Subject: [PATCH 1853/2553] nfq: introduce bypass function --- src/source-nfq.c | 35 ++++++++++++++++++++++++++++++++++- suricata.yaml.in | 6 ++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/source-nfq.c b/src/source-nfq.c index c8923f63d6b3..e84e32d8fc0d 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -132,7 +132,6 @@ typedef struct NFQThreadVars_ int datalen; /** Length of per function and thread data */ CaptureStats stats; - } NFQThreadVars; /* shared vars for all for nfq queues and threads */ static NFQGlobalVars nfq_g; @@ -169,6 +168,8 @@ typedef struct NFQCnf_ { NFQMode mode; uint32_t mark; uint32_t mask; + uint32_t bypass_mark; + uint32_t bypass_mask; uint32_t next_queue; uint32_t flags; uint8_t batchcount; @@ -263,6 +264,14 @@ void NFQInitConfig(char quiet) nfq_config.mask = (uint32_t)value; } + if ((ConfGetInt("nfq.bypass-mark", &value)) == 1) { + nfq_config.bypass_mark = (uint32_t)value; + } + + if ((ConfGetInt("nfq.bypass-mask", &value)) == 1) { + nfq_config.bypass_mask = (uint32_t)value; + } + if ((ConfGetInt("nfq.route-queue", &value)) == 1) { nfq_config.next_queue = ((uint32_t)value) << 16; } @@ -492,6 +501,26 @@ static void NFQReleasePacket(Packet *p) PacketFreeOrRelease(p); } +static int NFQBypassCallback(Packet *p) +{ + if (IS_TUNNEL_PKT(p)) { + SCMutex *m = p->root ? &p->root->tunnel_mutex : &p->tunnel_mutex; + SCMutexLock(m); + + p->root->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) + | (p->nfq_v.mark & ~nfq_config.bypass_mask); + p->root->flags |= PKT_MARK_MODIFIED; + + SCMutexUnlock(m); + } else { + p->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) + | (p->nfq_v.mark & ~nfq_config.bypass_mask); + p->flags |= PKT_MARK_MODIFIED; + } + + return 1; +} + static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) { @@ -507,6 +536,10 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, PKT_SET_SRC(p, PKT_SRC_WIRE); p->nfq_v.nfq_index = ntv->nfq_index; + /* if bypass mask is set then we may want to bypass so set pointer */ + if (nfq_config.bypass_mask) { + p->BypassPacketsFlow = NFQBypassCallback; + } ret = NFQSetupPkt(p, qh, (void *)nfa); if (ret == -1) { #ifdef COUNTERS diff --git a/suricata.yaml.in b/suricata.yaml.in index 9faf1f623a50..10eda8a4fd9a 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1417,10 +1417,16 @@ profiling: # by processing several packets before sending a verdict (worker runmode only). # On linux >= 3.6, you can set the fail-open option to yes to have the kernel # accept the packet if suricata is not able to keep pace. +# bypass mark and mask can be used to implement NFQ bypass. If bypass mark is +# set then the NFQ bypass is activated. Suricata will set the bypass mark/mask +# on packet of a flow that need to be bypassed. The Nefilter ruleset has to +# directly accept all packets of a flow once a packet has been marked. nfq: # mode: accept # repeat-mark: 1 # repeat-mask: 1 +# bypass-mark: 1 +# bypass-mask: 1 # route-queue: 2 # batchcount: 20 # fail-open: yes From 177df305d429079642f31c5aaa14b17899b22a24 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 23 May 2016 09:53:08 +0200 Subject: [PATCH 1854/2553] stream-tcp: enable bypass setting This permits to enable/disable in suricata.yaml and the bypass function will be called when stream.depth is reached. --- src/stream-tcp-reassemble.c | 1 + src/stream-tcp.c | 20 ++++++++++++++++++++ src/stream-tcp.h | 4 +++- suricata.yaml.in | 1 + 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 28bf4b537ce7..052db7d34c03 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -45,6 +45,7 @@ #include "util-host-os-info.h" #include "util-unittest-helper.h" #include "util-byte.h" +#include "util-device.h" #include "stream-tcp.h" #include "stream-tcp-private.h" diff --git a/src/stream-tcp.c b/src/stream-tcp.c index d56bd5048c34..3bc8b5088d6a 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -416,6 +416,21 @@ void StreamTcpInitConfig(char quiet) SCLogConfig("stream.\"inline\": %s", stream_inline ? "enabled" : "disabled"); } + int bypass = 0; + if ((ConfGetBool("stream.bypass", &bypass)) == 1) { + if (bypass == 1) { + stream_config.bypass = 1; + } else { + stream_config.bypass = 0; + } + } else { + stream_config.bypass = 0; + } + + if (!quiet) { + SCLogConfig("stream \"bypass\": %s", bypass ? "enabled" : "disabled"); + } + if ((ConfGetInt("stream.max-synack-queued", &value)) == 1) { if (value >= 0 && value <= 255) { stream_config.max_synack_queued = (uint8_t)value; @@ -5766,6 +5781,11 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback return cnt; } +int StreamTcpBypassEnabled(void) +{ + return stream_config.bypass; +} + #ifdef UNITTESTS /** diff --git a/src/stream-tcp.h b/src/stream-tcp.h index 57e8abc41194..dc106830ad6f 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -63,6 +63,7 @@ typedef struct TcpStreamCnf_ { uint16_t reassembly_toclient_chunk_size; int check_overlap_different_data; + int bypass; /** reassembly -- inline mode * @@ -228,7 +229,8 @@ void StreamTcpSessionClear(void *ssnptr); void StreamTcpSessionCleanup(TcpSession *ssn); /* cleanup stream, but don't free the stream */ void StreamTcpStreamCleanup(TcpStream *stream); - +/* check if bypass is enabled */ +int StreamTcpBypassEnabled(void); uint32_t StreamTcpGetStreamSize(TcpStream *stream); diff --git a/suricata.yaml.in b/suricata.yaml.in index 10eda8a4fd9a..061f5830c41d 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1110,6 +1110,7 @@ flow-timeouts: # async-oneside: false # don't enable async stream handling # inline: no # stream inline mode # max-synack-queued: 5 # Max different SYN/ACKs to queue +# bypass: no # Bypass packets when stream.depth is reached # # reassembly: # memcap: 64mb # Can be specified in kb, mb, gb. Just a number From c19cd12620b8d5ce90f37f8c6b52681bb06eb3d3 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 28 Jan 2016 21:41:24 +0100 Subject: [PATCH 1855/2553] flow: bypass encrypted and after stream depth flow This patch activates bypass for encrypted flow and for flow that have reached stream depth on both side. For encrypted flow , suricata is stopping the inspection so we can just get it out via bypass. The same logic apply for flow that have reached the stream depth. For a basic test of feature, use the following ruleset: ``` table ip filter { chain output { type filter hook output priority 0; policy accept; ct mark 0x1 counter accept oif lo counter queue num 0 } chain connmark_save { type filter hook output priority 1; policy accept; mark 0x1 ct mark set mark counter ct mark 0x1 counter } } ``` And use bypass mark and mask of 1 in nfq configuration. Then you can test the system by scp big file to 127.0.0.1. You can also use iperf to measure the performance on localhost. It is recommended to lower the MTU to 1500 to get something more realistic by increasing the number of packets.. --- src/stream-tcp.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 3bc8b5088d6a..062b44e12edc 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4635,6 +4635,15 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, /* check for conditions that may make us not want to log this packet */ /* streams that hit depth */ + if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) && + (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED)) + { + /* we can call bypass callback, if enabled */ + if (StreamTcpBypassEnabled()) { + PacketBypassCallback(p); + } + } + if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) || (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED)) { @@ -4646,6 +4655,10 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, (PKT_IS_TOCLIENT(p) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY))) { p->flags |= PKT_STREAM_NOPCAPLOG; + /* we can call bypass callback, if enabled */ + if (StreamTcpBypassEnabled()) { + PacketBypassCallback(p); + } } } From 07564c4e41cfcfdbcaaecf20d52d89159acc23f4 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Tue, 2 Feb 2016 11:37:23 +0100 Subject: [PATCH 1856/2553] detect: add bypass keyword This adds a new keyword which permits to call the bypass callback when a sig is matched. The callback must be called when the match of the sig is complete. --- src/Makefile.am | 1 + src/detect-bypass.c | 238 ++++++++++++++++++++++++++++++++++++++++++++ src/detect-bypass.h | 29 ++++++ src/detect.c | 2 + src/detect.h | 3 + 5 files changed, 273 insertions(+) create mode 100644 src/detect-bypass.c create mode 100644 src/detect-bypass.h diff --git a/src/Makefile.am b/src/Makefile.am index 97a7749bdea7..2e805a28dff8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -76,6 +76,7 @@ detect-base64-decode.c detect-base64-decode.h \ detect-byte-extract.c detect-byte-extract.h \ detect-bytejump.c detect-bytejump.h \ detect-bytetest.c detect-bytetest.h \ +detect-bypass.c detect-bypass.h \ detect.c detect.h \ detect-classtype.c detect-classtype.h \ detect-content.c detect-content.h \ diff --git a/src/detect-bypass.c b/src/detect-bypass.c new file mode 100644 index 000000000000..9faaad13702d --- /dev/null +++ b/src/detect-bypass.c @@ -0,0 +1,238 @@ +/* Copyright (C) 2016 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 Giuseppe Longo + * + */ + +#include "suricata-common.h" +#include "threads.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "debug.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-sigorder.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "stream-tcp.h" + +#include "util-debug.h" +#include "util-spm-bm.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-device.h" + +int DetectBypassMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectBypassSetup(DetectEngineCtx *, Signature *, char *); +static void DetectBypassRegisterTests(void); + +/** + * \brief Registration function for keyword: bypass + */ +void DetectBypassRegister(void) +{ + sigmatch_table[DETECT_BYPASS].name = "bypass"; + sigmatch_table[DETECT_BYPASS].desc = "call the bypass callback when the match of a sig is complete"; + sigmatch_table[DETECT_BYPASS].url = ""; + sigmatch_table[DETECT_BYPASS].Match = DetectBypassMatch; + sigmatch_table[DETECT_BYPASS].AppLayerMatch = NULL; + sigmatch_table[DETECT_BYPASS].Setup = DetectBypassSetup; + sigmatch_table[DETECT_BYPASS].Free = NULL; + sigmatch_table[DETECT_BYPASS].RegisterTests = DetectBypassRegisterTests; + sigmatch_table[DETECT_BYPASS].flags = SIGMATCH_NOOPT; +} + +static int DetectBypassSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SigMatch *sm = NULL; + + if (s->flags & SIG_FLAG_FILESTORE) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "bypass can't work with filestore keyword"); + return -1; + } + s->flags |= SIG_FLAG_BYPASS; + + sm = SigMatchAlloc(); + if (sm == NULL) + return -1; + + sm->type = DETECT_BYPASS; + sm->ctx = NULL; + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); + + return 0; +} + +int DetectBypassMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + PacketBypassCallback(p); + + return 1; +} + +#ifdef UNITTESTS +static int callback_var = 0; + +static int BypassCallback() +{ + callback_var = 1; + return 1; +} + +static void ResetCallbackVar() +{ + callback_var = 0; +} + +static int DetectBypassTestSig01(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This is dummy message body\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "message"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + LiveDevice *livedev = SCMalloc(sizeof(LiveDevice)); + FAIL_IF(livedev == NULL); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF(p1 == NULL); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF(p2 == NULL); + + p1->BypassPacketsFlow = BypassCallback; + p2->BypassPacketsFlow = BypassCallback; + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->livedev = livedev; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->livedev = livedev; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + de_ctx->flags |= DE_QUIET; + + char *sigs[3]; + sigs[0] = "alert tcp any any -> any any (bypass; content:\"GET \"; sid:1;)"; + sigs[1] = "alert http any any -> any any " + "(bypass; content:\"message\"; http_server_body; " + "sid:2;)"; + sigs[2] = "alert http any any -> any any " + "(bypass; content:\"message\"; http_host; " + "sid:3;)"; + FAIL_IF(UTHAppendSigs(de_ctx, sigs, 3) == 0); + + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + FAIL_IF(http_state == NULL); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, + http_buf2, http_len2); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + FAIL_IF(!(PacketAlertCheck(p2, 2))); + FAIL_IF(!(PacketAlertCheck(p1, 3))); + + FAIL_IF(callback_var == 0); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + ResetCallbackVar(); + SCFree(livedev); + PASS; +} +#endif /* UNITTESTS */ + +void DetectBypassRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectBypassTestSig01", DetectBypassTestSig01); +#endif /* UNITTESTS */ +} diff --git a/src/detect-bypass.h b/src/detect-bypass.h new file mode 100644 index 000000000000..7afc4c9a323d --- /dev/null +++ b/src/detect-bypass.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2016 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 Giuseppe Longo + */ + +#ifndef __DETECT_BYPASS_H__ +#define __DETECT_BYPASS_H__ + +void DetectBypassRegister(void); + +#endif /* __DETECT_BYPASS_H__ */ diff --git a/src/detect.c b/src/detect.c index 2fb7243f1fac..d57294f54bd8 100644 --- a/src/detect.c +++ b/src/detect.c @@ -164,6 +164,7 @@ #include "detect-app-layer-protocol.h" #include "detect-template.h" #include "detect-template-buffer.h" +#include "detect-bypass.h" #include "util-rule-vars.h" @@ -4462,6 +4463,7 @@ void SigTableSetup(void) DetectBase64DataRegister(); DetectTemplateRegister(); DetectTemplateBufferRegister(); + DetectBypassRegister(); } void SigTableRegisterTests(void) diff --git a/src/detect.h b/src/detect.h index f9754ff94e4a..142ca40c040e 100644 --- a/src/detect.h +++ b/src/detect.h @@ -273,6 +273,7 @@ typedef struct DetectPort_ { #define SIG_FLAG_TLSSTORE (1<<21) +#define SIG_FLAG_BYPASS (1<<22) /* 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) */ @@ -1244,6 +1245,8 @@ enum { DETECT_TEMPLATE, DETECT_AL_TEMPLATE_BUFFER, + DETECT_BYPASS, + /* make sure this stays last */ DETECT_TBLSIZE, }; From 5b71b5834f8a319702685ef791c8b62ed6420c83 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 8 Feb 2016 13:21:54 +0100 Subject: [PATCH 1857/2553] filestore: avoid conflict with bypass keyword If a packet triggers a rule which contains both bypass and filestore keywords, it won't be stored since it's not inspected. To avoid that, when a rule containing filestore keyword we make sure that also bypass keyword is present. --- src/detect-filestore.c | 45 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 84c8acc60c11..3e6957586cf9 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -63,6 +63,7 @@ static int DetectFilestoreMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, Signature *, SigMatch *); static int DetectFilestoreSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilestoreFree(void *); +static void DetectFilestoreRegisterTests(void); /** * \brief Registration function for keyword: filestore @@ -75,7 +76,7 @@ void DetectFilestoreRegister(void) sigmatch_table[DETECT_FILESTORE].FileMatch = DetectFilestoreMatch; sigmatch_table[DETECT_FILESTORE].Setup = DetectFilestoreSetup; sigmatch_table[DETECT_FILESTORE].Free = DetectFilestoreFree; - sigmatch_table[DETECT_FILESTORE].RegisterTests = NULL; + sigmatch_table[DETECT_FILESTORE].RegisterTests = DetectFilestoreRegisterTests; sigmatch_table[DETECT_FILESTORE].flags = SIGMATCH_OPTIONAL_OPT; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); @@ -291,6 +292,13 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *st int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; + /* filestore and bypass keywords can't work together */ + if (s->flags & SIG_FLAG_BYPASS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "filestore can't work with bypass keyword"); + return -1; + } + sm = SigMatchAlloc(); if (sm == NULL) goto error; @@ -408,3 +416,38 @@ static void DetectFilestoreFree(void *ptr) SCFree(ptr); } } + +#ifdef UNITTESTS +/* + * The purpose of this test is to confirm that + * filestore and bypass keywords can't + * can't work together + */ +static int DetectFilestoreTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 1; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(bypass; filestore; " + "content:\"message\"; http_host; " + "sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); + + DetectEngineCtxFree(de_ctx); + + return result; +} +#endif /* UNITTESTS */ + +void DetectFilestoreRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectFilestoreTest01", DetectFilestoreTest01); +#endif /* UNITTESTS */ +} From 4cf887b4f7bbc68f814925e04d8e2fc6dc781ef2 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 26 Sep 2016 13:17:01 +0200 Subject: [PATCH 1858/2553] flow: update lastts in FlowHandlePacketUpdate This allows to make it conditional to the state of packet and then trigger modified behavior. --- src/flow-hash.c | 8 -------- src/flow-worker.c | 2 ++ src/flow.c | 7 +++++++ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/flow-hash.c b/src/flow-hash.c index 79758fc70138..89c1940b33e4 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -489,8 +489,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p f->fb = fb; FlowUpdateState(f, FLOW_STATE_NEW); - /* update the last seen timestamp of this flow */ - COPY_TIMESTAMP(&p->ts,&f->lastts); FlowReference(dest, f); FBLOCK_UNLOCK(fb); @@ -526,8 +524,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p f->fb = fb; FlowUpdateState(f, FLOW_STATE_NEW); - /* update the last seen timestamp of this flow */ - COPY_TIMESTAMP(&p->ts,&f->lastts); FlowReference(dest, f); FBLOCK_UNLOCK(fb); @@ -562,8 +558,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p } } - /* update the last seen timestamp of this flow */ - COPY_TIMESTAMP(&p->ts,&f->lastts); FlowReference(dest, f); FBLOCK_UNLOCK(fb); @@ -582,8 +576,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p } } - /* update the last seen timestamp of this flow */ - COPY_TIMESTAMP(&p->ts,&f->lastts); FlowReference(dest, f); FBLOCK_UNLOCK(fb); diff --git a/src/flow-worker.c b/src/flow-worker.c index c3b95d6bf479..a0fb0b013ce6 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -42,6 +42,8 @@ #include "util-validate.h" +#include "flow-util.h" + typedef DetectEngineThreadCtx *DetectEngineThreadCtxPtr; typedef struct FlowWorkerThreadData_ { diff --git a/src/flow.c b/src/flow.c index e7671c59f89e..8c82424c3ca9 100644 --- a/src/flow.c +++ b/src/flow.c @@ -223,6 +223,13 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p) { SCLogDebug("packet %"PRIu64" -- flow %p", p->pcap_cnt, f); + int state = SC_ATOMIC_GET(f->flow_state); + + if (state != FLOW_STATE_CAPTURE_BYPASSED) { + /* update the last seen timestamp of this flow */ + COPY_TIMESTAMP(&p->ts, &f->lastts); + } + /* update flags and counters */ if (FlowGetPacketDirection(f, p) == TOSERVER) { f->todstpktcnt++; From 724069626d036adf2bff532b3275d501ea926409 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 26 Sep 2016 13:22:34 +0200 Subject: [PATCH 1859/2553] flow: downgrade to local bypass if we see packets If we see packets for a capture bypassed flow after some times, it means that the capture method is not handling correctly the bypass so it is better to switch to local bypass method. --- src/flow-manager.c | 2 -- src/flow-private.h | 2 ++ src/flow.c | 7 +++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 2a30fdcddc41..0ccbea80f8ee 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -67,8 +67,6 @@ #include "output-flow.h" -#define FLOW_BYPASSED_TIMEOUT 6 - /* Run mode selected at suricata.c */ extern int run_mode; diff --git a/src/flow-private.h b/src/flow-private.h index c1323db3b0d8..a523f6a07c4a 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -57,6 +57,8 @@ #define FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT 10 #define FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT 100 +#define FLOW_BYPASSED_TIMEOUT 6 + enum { FLOW_PROTO_TCP = 0, FLOW_PROTO_UDP, diff --git a/src/flow.c b/src/flow.c index 8c82424c3ca9..3718d5c9fb02 100644 --- a/src/flow.c +++ b/src/flow.c @@ -228,6 +228,13 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p) if (state != FLOW_STATE_CAPTURE_BYPASSED) { /* update the last seen timestamp of this flow */ COPY_TIMESTAMP(&p->ts, &f->lastts); + } else { + /* still seeing packet, we downgrade to local bypass */ + if (p->ts.tv_sec - f->lastts.tv_sec > FLOW_BYPASSED_TIMEOUT / 2) { + SCLogDebug("Downgrading flow to local bypass"); + COPY_TIMESTAMP(&p->ts, &f->lastts); + FlowUpdateState(f, FLOW_STATE_LOCAL_BYPASSED); + } } /* update flags and counters */ From 51bfe4960a1b55a7108ab0f6c6219d9d3fe2c7e5 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 26 Sep 2016 13:35:44 +0200 Subject: [PATCH 1860/2553] flow: discard packets belonging to bypassed flows --- src/flow-worker.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/flow-worker.c b/src/flow-worker.c index a0fb0b013ce6..84ac31c7be3c 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -66,9 +66,18 @@ typedef struct FlowWorkerThreadData_ { * * Handle flow creation/lookup */ -static inline void FlowUpdate(Packet *p) +static inline TmEcode FlowUpdate(Packet *p) { FlowHandlePacketUpdate(p->flow, p); + + int state = SC_ATOMIC_GET(p->flow->flow_state); + switch (state) { + case FLOW_STATE_CAPTURE_BYPASSED: + case FLOW_STATE_LOCAL_BYPASSED: + return TM_ECODE_DONE; + default: + return TM_ECODE_OK; + } } static TmEcode FlowWorkerThreadInit(ThreadVars *tv, void *initdata, void **data) @@ -159,7 +168,10 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac FlowHandlePacket(tv, fw->dtv, p); if (likely(p->flow != NULL)) { DEBUG_ASSERT_FLOW_LOCKED(p->flow); - FlowUpdate(p); + if (FlowUpdate(p) == TM_ECODE_DONE) { + FLOWLOCK_UNLOCK(p->flow); + return TM_ECODE_OK; + } } /* Flow is now LOCKED */ From e6bac998d9acfc9eac1f08ff255e8b72ff5c3364 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 26 Sep 2016 16:45:15 +0200 Subject: [PATCH 1861/2553] flow: add timeout for local bypass This adds a new timeout value for local bypassed state. For user simplication it is called only `bypassed`. The patch also adds a emergency value so we can clean bypassed flows a bit faster. --- src/flow-manager.c | 4 +- src/flow-private.h | 5 +++ src/flow.c | 103 ++++++++++++++++++++++++++++++++++++++------- src/flow.h | 1 + suricata.yaml.in | 12 +++++- 5 files changed, 108 insertions(+), 17 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 0ccbea80f8ee..8da17f93e63f 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -204,7 +204,6 @@ static inline uint32_t FlowGetFlowTimeout(const Flow *f, enum FlowState state) timeout = flow_timeouts[f->protomap].new_timeout; break; case FLOW_STATE_ESTABLISHED: - case FLOW_STATE_LOCAL_BYPASSED: timeout = flow_timeouts[f->protomap].est_timeout; break; case FLOW_STATE_CLOSED: @@ -213,6 +212,9 @@ static inline uint32_t FlowGetFlowTimeout(const Flow *f, enum FlowState state) case FLOW_STATE_CAPTURE_BYPASSED: timeout = FLOW_BYPASSED_TIMEOUT; break; + case FLOW_STATE_LOCAL_BYPASSED: + timeout = flow_timeouts[f->protomap].bypassed_timeout; + break; } return timeout; } diff --git a/src/flow-private.h b/src/flow-private.h index a523f6a07c4a..19b81b44848a 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -40,16 +40,21 @@ #define FLOW_DEFAULT_NEW_TIMEOUT 30 #define FLOW_DEFAULT_EST_TIMEOUT 300 #define FLOW_DEFAULT_CLOSED_TIMEOUT 0 +#define FLOW_DEFAULT_BYPASSED_TIMEOUT 100 #define FLOW_IPPROTO_TCP_NEW_TIMEOUT 30 #define FLOW_IPPROTO_TCP_EST_TIMEOUT 300 +#define FLOW_IPPROTO_TCP_BYPASSED_TIMEOUT 100 #define FLOW_IPPROTO_UDP_NEW_TIMEOUT 30 #define FLOW_IPPROTO_UDP_EST_TIMEOUT 300 +#define FLOW_IPPROTO_UDP_BYPASSED_TIMEOUT 100 #define FLOW_IPPROTO_ICMP_NEW_TIMEOUT 30 #define FLOW_IPPROTO_ICMP_EST_TIMEOUT 300 +#define FLOW_IPPROTO_ICMP_BYPASSED_TIMEOUT 100 #define FLOW_DEFAULT_EMERG_NEW_TIMEOUT 10 #define FLOW_DEFAULT_EMERG_EST_TIMEOUT 100 #define FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT 0 +#define FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT 50 #define FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT 10 #define FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT 100 #define FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT 10 diff --git a/src/flow.c b/src/flow.c index 3718d5c9fb02..f33c2bc5ba6f 100644 --- a/src/flow.c +++ b/src/flow.c @@ -499,34 +499,36 @@ void FlowInitFlowProto(void) { FlowTimeoutsInit(); -#define SET_DEFAULTS(p, n, e, c, ne, ee, ce) \ - flow_timeouts_normal[(p)].new_timeout = (n); \ - flow_timeouts_normal[(p)].est_timeout = (e); \ - flow_timeouts_normal[(p)].closed_timeout = (c); \ - flow_timeouts_emerg[(p)].new_timeout = (ne); \ - flow_timeouts_emerg[(p)].est_timeout = (ee); \ - flow_timeouts_emerg[(p)].closed_timeout = (ce); +#define SET_DEFAULTS(p, n, e, c, b, ne, ee, ce, be) \ + flow_timeouts_normal[(p)].new_timeout = (n); \ + flow_timeouts_normal[(p)].est_timeout = (e); \ + flow_timeouts_normal[(p)].closed_timeout = (c); \ + flow_timeouts_normal[(p)].bypassed_timeout = (b); \ + flow_timeouts_emerg[(p)].new_timeout = (ne); \ + flow_timeouts_emerg[(p)].est_timeout = (ee); \ + flow_timeouts_emerg[(p)].closed_timeout = (ce); \ + flow_timeouts_emerg[(p)].bypassed_timeout = (be); \ SET_DEFAULTS(FLOW_PROTO_DEFAULT, FLOW_DEFAULT_NEW_TIMEOUT, FLOW_DEFAULT_EST_TIMEOUT, - FLOW_DEFAULT_CLOSED_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, FLOW_DEFAULT_BYPASSED_TIMEOUT, FLOW_DEFAULT_EMERG_NEW_TIMEOUT, FLOW_DEFAULT_EMERG_EST_TIMEOUT, - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT); + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); SET_DEFAULTS(FLOW_PROTO_TCP, FLOW_IPPROTO_TCP_NEW_TIMEOUT, FLOW_IPPROTO_TCP_EST_TIMEOUT, - FLOW_DEFAULT_CLOSED_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, FLOW_IPPROTO_TCP_BYPASSED_TIMEOUT, FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT, - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT); + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); SET_DEFAULTS(FLOW_PROTO_UDP, FLOW_IPPROTO_UDP_NEW_TIMEOUT, FLOW_IPPROTO_UDP_EST_TIMEOUT, - FLOW_DEFAULT_CLOSED_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, FLOW_IPPROTO_UDP_BYPASSED_TIMEOUT, FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT, - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT); + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); SET_DEFAULTS(FLOW_PROTO_ICMP, FLOW_IPPROTO_ICMP_NEW_TIMEOUT, FLOW_IPPROTO_ICMP_EST_TIMEOUT, - FLOW_DEFAULT_CLOSED_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, FLOW_IPPROTO_ICMP_BYPASSED_TIMEOUT, FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT, - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT); + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); flow_freefuncs[FLOW_PROTO_DEFAULT].Freefunc = NULL; flow_freefuncs[FLOW_PROTO_TCP].Freefunc = NULL; @@ -537,9 +539,11 @@ void FlowInitFlowProto(void) const char *new = NULL; const char *established = NULL; const char *closed = NULL; + const char *bypassed = NULL; const char *emergency_new = NULL; const char *emergency_established = NULL; const char *emergency_closed = NULL; + const char *emergency_bypassed = NULL; ConfNode *flow_timeouts = ConfGetNode("flow-timeouts"); if (flow_timeouts != NULL) { @@ -552,11 +556,14 @@ void FlowInitFlowProto(void) new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); closed = ConfNodeLookupChildValue(proto, "closed"); + bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); emergency_closed = ConfNodeLookupChildValue(proto, "emergency-closed"); + emergency_bypassed = ConfNodeLookupChildValue(proto, + "emergency-bypassed"); if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { @@ -575,6 +582,13 @@ void FlowInitFlowProto(void) flow_timeouts_normal[FLOW_PROTO_DEFAULT].closed_timeout = configval; } + if (bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(bypassed), + bypassed) > 0) { + + flow_timeouts_normal[FLOW_PROTO_DEFAULT].bypassed_timeout = configval; + } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { @@ -595,6 +609,13 @@ void FlowInitFlowProto(void) flow_timeouts_emerg[FLOW_PROTO_DEFAULT].closed_timeout = configval; } + if (emergency_bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(emergency_bypassed), + emergency_bypassed) > 0) { + + flow_timeouts_emerg[FLOW_PROTO_DEFAULT].bypassed_timeout = configval; + } } /* TCP. */ @@ -603,11 +624,14 @@ void FlowInitFlowProto(void) new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); closed = ConfNodeLookupChildValue(proto, "closed"); + bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); emergency_closed = ConfNodeLookupChildValue(proto, "emergency-closed"); + emergency_bypassed = ConfNodeLookupChildValue(proto, + "emergency-bypassed"); if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { @@ -626,6 +650,13 @@ void FlowInitFlowProto(void) flow_timeouts_normal[FLOW_PROTO_TCP].closed_timeout = configval; } + if (bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(bypassed), + bypassed) > 0) { + + flow_timeouts_normal[FLOW_PROTO_TCP].bypassed_timeout = configval; + } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { @@ -646,6 +677,13 @@ void FlowInitFlowProto(void) flow_timeouts_emerg[FLOW_PROTO_TCP].closed_timeout = configval; } + if (emergency_bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(emergency_bypassed), + emergency_bypassed) > 0) { + + flow_timeouts_emerg[FLOW_PROTO_TCP].bypassed_timeout = configval; + } } /* UDP. */ @@ -653,9 +691,13 @@ void FlowInitFlowProto(void) if (proto != NULL) { new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); + bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); + emergency_bypassed = ConfNodeLookupChildValue(proto, + "emergency-bypassed"); + if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { @@ -667,6 +709,13 @@ void FlowInitFlowProto(void) flow_timeouts_normal[FLOW_PROTO_UDP].est_timeout = configval; } + if (bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(bypassed), + bypassed) > 0) { + + flow_timeouts_normal[FLOW_PROTO_UDP].bypassed_timeout = configval; + } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { @@ -680,6 +729,13 @@ void FlowInitFlowProto(void) flow_timeouts_emerg[FLOW_PROTO_UDP].est_timeout = configval; } + if (emergency_bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(emergency_bypassed), + emergency_bypassed) > 0) { + + flow_timeouts_emerg[FLOW_PROTO_UDP].bypassed_timeout = configval; + } } /* ICMP. */ @@ -687,9 +743,12 @@ void FlowInitFlowProto(void) if (proto != NULL) { new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); + bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); + emergency_bypassed = ConfNodeLookupChildValue(proto, + "emergency-bypassed"); if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { @@ -702,6 +761,13 @@ void FlowInitFlowProto(void) flow_timeouts_normal[FLOW_PROTO_ICMP].est_timeout = configval; } + if (bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(bypassed), + bypassed) > 0) { + + flow_timeouts_normal[FLOW_PROTO_ICMP].bypassed_timeout = configval; + } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { @@ -715,6 +781,13 @@ void FlowInitFlowProto(void) flow_timeouts_emerg[FLOW_PROTO_ICMP].est_timeout = configval; } + if (emergency_bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(emergency_bypassed), + emergency_bypassed) > 0) { + + flow_timeouts_emerg[FLOW_PROTO_UDP].bypassed_timeout = configval; + } } } diff --git a/src/flow.h b/src/flow.h index e42e21147bfb..52dec76df1be 100644 --- a/src/flow.h +++ b/src/flow.h @@ -434,6 +434,7 @@ typedef struct FlowProtoTimeout_ { uint32_t new_timeout; uint32_t est_timeout; uint32_t closed_timeout; + uint32_t bypassed_timeout; } FlowProtoTimeout; typedef struct FlowProtoFreeFunc_ { diff --git a/suricata.yaml.in b/suricata.yaml.in index 061f5830c41d..69dfbdaec84c 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1055,7 +1055,9 @@ vlan: # of that flow). The value of "established" is the amount of # seconds that the engine will wait to free the flow if it spend that amount # without receiving new packets or closing the connection. "closed" is the -# amount of time to wait after a flow is closed (usually zero). +# amount of time to wait after a flow is closed (usually zero). "bypassed" +# timeout controls locally bypassed flows. For these flows we don't do any other +# tracking. If no packets have been seen after this timeout, the flow is discarded. # # There's an emergency mode that will become active under attack circumstances, # making the engine to check flow status faster. This configuration variables @@ -1069,26 +1071,34 @@ flow-timeouts: new: 30 established: 300 closed: 0 + bypassed: 100 emergency-new: 10 emergency-established: 100 emergency-closed: 0 + emergency-bypassed: 50 tcp: new: 60 established: 600 closed: 60 + bypassed: 100 emergency-new: 5 emergency-established: 100 emergency-closed: 10 + emergency-bypassed: 50 udp: new: 30 established: 300 + bypassed: 100 emergency-new: 10 emergency-established: 100 + emergency-bypassed: 50 icmp: new: 30 established: 300 + bypassed: 100 emergency-new: 10 emergency-established: 100 + emergency-bypassed: 50 # Stream engine settings. Here the TCP stream tracking and reassembly # engine is configured. From 3ca663d7ffe98e9c77f18bc0efff3bad5753f24c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 28 Sep 2016 13:50:01 +0200 Subject: [PATCH 1862/2553] output-json-flow: display bypass method In the case of a bypassed flow we add a 'bypass' key that can be 'local' or 'capture'. This will allow the user to know if capture bypass method is failing by looking at the 'bypass' key. --- src/output-json-flow.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 8e34169e3889..26723fdf0248 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -219,8 +219,24 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) state = "established"; else if (f->flow_end_flags & FLOW_END_FLAG_STATE_CLOSED) state = "closed"; - else if (f->flow_end_flags & FLOW_END_FLAG_STATE_BYPASSED) + else if (f->flow_end_flags & FLOW_END_FLAG_STATE_BYPASSED) { state = "bypassed"; + int flow_state = SC_ATOMIC_GET(f->flow_state); + switch (flow_state) { + case FLOW_STATE_LOCAL_BYPASSED: + json_object_set_new(hjs, "bypass", + json_string("local")); + break; + case FLOW_STATE_CAPTURE_BYPASSED: + json_object_set_new(hjs, "bypass", + json_string("capture")); + break; + default: + SCLogError(SC_ERR_INVALID_VALUE, + "Invalid flow state: %d, contact developers", + flow_state); + } + } json_object_set_new(hjs, "state", json_string(state)); From 485544d88559239efb83223babb5b1e66ccf106d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Sep 2016 20:44:17 +0200 Subject: [PATCH 1863/2553] doc: improve commandline options --- doc/userguide/command-line-options.rst | 48 ++++++++++++++++---------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/doc/userguide/command-line-options.rst b/doc/userguide/command-line-options.rst index de981ba44e5c..15f9c6165159 100644 --- a/doc/userguide/command-line-options.rst +++ b/doc/userguide/command-line-options.rst @@ -15,8 +15,7 @@ Suricata's command line options: .. option:: -c - The -c option the most important option. After -c you can enter the - path to the location of suricata.yaml. + Select suricata.yaml configuration file. .. option:: -i @@ -62,23 +61,13 @@ Suricata's command line options: able to use the console for other tasks without disturbing the engine running. -.. option:: --list-app-layer-protos - - List supported app layer protocols. - -.. option:: --list-keywords[=all|csv|] - - List keywords implemented by the engine - -.. option:: --list-runmodes - - The option --list-runmodes lists all possible runmodes. - .. option:: --runmode - (in combination with the command line opion -i or -r) With - the --runmode option you can set the runmode that you would like to - use. This command line option can override the yaml runmode option. + With the --runmode option you can set the runmode that you would + like to use. This command line option can override the yaml + runmode option. + + Runmodes are: workers, autofp and single. For more information about runmodes see: :doc:`performance/runmodes` @@ -101,9 +90,32 @@ Capture Options .. option:: --netmap= Enable capture of packet using NETMAP on FreeBSD or Linux. If no - device is supplied, the list of devices from the af-packet section + device is supplied, the list of devices from the netmap section in the yaml is used. +Advanced Options +~~~~~~~~~~~~~~~~ + +.. option:: --dump-config + + Displays a list of key value pairs with Suricata's configuration. + +.. option:: --set = + + Override any configuration option. + +.. option:: --list-app-layer-protos + + List supported app layer protocols. + +.. option:: --list-keywords[=all|csv|] + + List keywords implemented by the engine + +.. option:: --list-runmodes + + The option --list-runmodes lists all possible runmodes. + Unit Tests ~~~~~~~~~~ From c7c8de7d59333d1da1c8b8a524bd9468e06d2aa7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Sep 2016 20:44:30 +0200 Subject: [PATCH 1864/2553] doc: fix ET example URL --- doc/userguide/oinkmaster.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide/oinkmaster.rst b/doc/userguide/oinkmaster.rst index 55e8a85f57bd..39036738487d 100644 --- a/doc/userguide/oinkmaster.rst +++ b/doc/userguide/oinkmaster.rst @@ -23,7 +23,7 @@ Oinkmaster has to know where the rules an be found. These rules can be found at: :: - http://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz + https://rules.emergingthreats.net/open/suricata-3.2/emerging.rules.tar.gz open oinkmaster.conf to add this link by entering: From 99d5bf4e68adf640b4dbd14aea64acfb1d374002 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Sep 2016 21:01:58 +0200 Subject: [PATCH 1865/2553] doc: improve tuning/perf docs --- .../performance/high-performance-config.rst | 73 +++---------------- doc/userguide/performance/index.rst | 10 +-- .../performance/tuning-considerations.rst | 26 +++---- 3 files changed, 25 insertions(+), 84 deletions(-) diff --git a/doc/userguide/performance/high-performance-config.rst b/doc/userguide/performance/high-performance-config.rst index fa1a3cde1732..19c5e8f62126 100644 --- a/doc/userguide/performance/high-performance-config.rst +++ b/doc/userguide/performance/high-performance-config.rst @@ -1,72 +1,19 @@ High Performance Configuration ============================== -If you have enough RAM, consider the following options in -suricata.yaml to off-load as much work from the CPU's as possible: +If you have enough RAM, consider the following options in suricata.yaml to off-load as much work from the CPU's as possible: :: - detect-engine: - - profile: custom - - custom-values: - toclient-src-groups: 200 - toclient-dst-groups: 200 - toclient-sp-groups: 200 - toclient-dp-groups: 300 - toserver-src-groups: 200 - toserver-dst-groups: 400 - toserver-sp-groups: 200 - toserver-dp-groups: 200 - - sgh-mpm-context: auto - - inspection-recursion-limit: 3000 + detect: + profile: custom + custom-values: + toclient-groups: 200 + toserver-groups: 200 + sgh-mpm-context: auto + inspection-recursion-limit: 3000 -Be advised, however, that this will require >= 32 GB of RAM for even -modestly sized rule sets. Also be aware that having additional CPU's -available provides a greater performance boost than having more RAM -available. That is, it would be better to spend money on CPU's -instead of RAM when configuring a system. +Be advised, however, that this may require lots of RAM for even modestly sized rule sets. Also be aware that having additional CPU's available provides a greater performance boost than having more RAM available. That is, it would be better to spend money on CPU's instead of RAM when configuring a system. -As a rough benchmark, in an HTTP-rich traffic stream, the full -Emerging Threats rule set will require roughly one CPU per 50 Mb/sec -of traffic when using "low" memory settings and using PF_RING to -ensure there are no traffic drops. +It may also lead to significantly longer rule loading times. -Here are the build in values for LOW/MEDIUM/HIGH profiles: - -:: - - - ENGINE_PROFILE_LOW: - toclient-src-groups: 2 - toclient-dst-groups: 2 - toclient-sp-groups: 2 - toclient-dp-groups: 3 - toserver-src-groups: 2 - toserver-dst-groups: 4 - toserver-sp-groups: 2 - toserver-dp-groups: 25 - - ENGINE_PROFILE_HIGH: - toclient-src-groups: 15 - toclient-dst-groups: 15 - toclient-sp-groups: 15 - toclient-dp-groups: 20 - toserver-src-groups: 15 - toserver-dst-groups: 15 - toserver-sp-groups: 15 - toserver-dp-groups: 40 - -If not provided: - -:: - - - default and MEDIUM profiles: - toclient-src-groups: 4 - toclient-dst-groups: 4 - toclient-sp-groups: 4 - toclient-dp-groups: 6 - toserver-src-groups: 4 - toserver-dst-groups: 8 - toserver-sp-groups: 4 - toserver-dp-groups: 30 diff --git a/doc/userguide/performance/index.rst b/doc/userguide/performance/index.rst index 7e08a99bdb8e..d43fa658963e 100644 --- a/doc/userguide/performance/index.rst +++ b/doc/userguide/performance/index.rst @@ -3,13 +3,13 @@ Performance .. toctree:: - high-performance-config + runmodes + packet-capture tuning-considerations + hyperscan + high-performance-config statistics + ignoring-traffic packet-profiling rule-profiling - runmodes tcmalloc - ignoring-traffic - hyperscan - packet-capture diff --git a/doc/userguide/performance/tuning-considerations.rst b/doc/userguide/performance/tuning-considerations.rst index b94e92ff8bc6..b2e74946c345 100644 --- a/doc/userguide/performance/tuning-considerations.rst +++ b/doc/userguide/performance/tuning-considerations.rst @@ -12,13 +12,12 @@ but setting it too high will lead to degradation. Suggested setting: 1000 or higher. Max is ~65000. -mpm-algo: +mpm-algo: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Controls the pattern matcher algorithm. AC is the default and best -choice for most if not all cases. +Controls the pattern matcher algorithm. AC is the default. On supported platforms, :doc:`performance/hyperscan` is the best option. -detect-engine.profile: +detect.profile: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The detection engine tries to split out separate signatures into @@ -32,24 +31,19 @@ The "custom" setting allows modification of the group sizes: :: - - custom-values: - toclient-src-groups: 2 - toclient-dst-groups: 2 - toclient-sp-groups: 2 - toclient-dp-groups: 3 - toserver-src-groups: 2 - toserver-dst-groups: 4 - toserver-sp-groups: 2 - toserver-dp-groups: 25 + custom-values: + toclient-groups: 50 + toserver-groups: 50 In general, increasing will improve performance, but will lead to higher memory usage. -detect-engine.sgh-mpm-context: +detect.sgh-mpm-context: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The multi pattern matcher can have it's context per signature group (full) or globally (single). Auto selects between single and full -based on the **mpm-algo** selected. ac, ac-gfbs and ac-bs use -"single". All others "full". Setting this to "full" with AC requires a +based on the **mpm-algo** selected. ac and ac-bs use "single". +All others "full". Setting this to "full" with AC requires a lot of memory: 32GB+ for a reasonable rule set. + From 3ab405dc502222e4263234ccb5f0953293744b2a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Sep 2016 21:11:14 +0200 Subject: [PATCH 1866/2553] doc: reorganize hyperscan guide --- doc/userguide/performance/hyperscan.rst | 60 +++++++++---------- .../performance/tuning-considerations.rst | 2 +- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/doc/userguide/performance/hyperscan.rst b/doc/userguide/performance/hyperscan.rst index 64c23a7cc32b..180c4226a9ad 100644 --- a/doc/userguide/performance/hyperscan.rst +++ b/doc/userguide/performance/hyperscan.rst @@ -1,16 +1,39 @@ -Hyperscan guide for Ubuntu -========================== +Hyperscan +========= Introduction -============ +~~~~~~~~~~~~ "Hyperscan is a high-performance multiple regex matching library." https://01.org/hyperscan In Suricata it can be used to perform multi pattern matching (mpm). Support was implemented by Justin Viiret and Jim Xu from Intel: https://github.com/inliniac/suricata/pull/1965, https://redmine.openinfosecfoundation.org/issues/1704 +Compilation +~~~~~~~~~~~ + +It's possible to pass --with-libhs-includes=/usr/local/include/hs/ --with-libhs-libraries=/usr/local/lib/, although by default this shouldn't be necessary. Suricata should pick up Hyperscan's pkg-config file automagically. + +When Suricata's compilation succeeded, you should have: + +:: + + + suricata --build-info|grep Hyperscan + Hyperscan support: yes + + +Using Hyperscan +~~~~~~~~~~~~~~~ + +To use the hyperscan support edit your suricata.yaml. Change the mpm-algo and spm-algo values to 'hs'. + +Alternatively, use this commandline option: --set mpm-algo=hs --set spm-algo=hs + + -Installation -============ + +Ubuntu Hyperscan Installation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To use Suricata with Hyperscan support, install dependencies: @@ -35,7 +58,7 @@ On Ubuntu 15.10 or 16.04+, simply do: Trusty -~~~~~~ +------ Trusty has 1.57, so it's too old. We can grab a newer libboost version, but we *don't* install it system wide. It's only the headers we care about during compilation of Hyperscan. @@ -111,28 +134,3 @@ Note that you may have to add /usr/local/lib to your ld search path echo "/usr/local/lib" | sudo tee --append /etc/ld.so.conf.d/usrlocal.conf sudo ldconfig -Suricata --------- - -Compilation -~~~~~~~~~~~ - -Suricata's installation is now quite standard. - -It's possible to pass --with-libhs-includes=/usr/local/include/hs/ --with-libhs-libraries=/usr/local/lib/, although by default this shouldn't be necessary. Suricata should pick up Hyperscan's pkg-config file automagically. - -When Suricata's compilation succeeded, you should have: - -:: - - - suricata --build-info|grep Hyperscan - Hyperscan support: yes - - -Using Hyperscan -~~~~~~~~~~~~~~~ - -To use the hyperscan support edit your suricata.yaml and change the mpm-algo value to 'hs'. - -Alternatively, use this commandline option: --set mpm-algo=hs diff --git a/doc/userguide/performance/tuning-considerations.rst b/doc/userguide/performance/tuning-considerations.rst index b2e74946c345..28ebd54d85df 100644 --- a/doc/userguide/performance/tuning-considerations.rst +++ b/doc/userguide/performance/tuning-considerations.rst @@ -15,7 +15,7 @@ Suggested setting: 1000 or higher. Max is ~65000. mpm-algo: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Controls the pattern matcher algorithm. AC is the default. On supported platforms, :doc:`performance/hyperscan` is the best option. +Controls the pattern matcher algorithm. AC is the default. On supported platforms, :doc:`performance/Hyperscan` is the best option. detect.profile: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From c4dcb205225097dc7c672b4c8435506465ac8b44 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Aug 2016 09:59:22 +0200 Subject: [PATCH 1867/2553] detect-parse: add new func to get last sigmatch Add SigMatchGetLastSM which simply returns the very last SM added to the signature. Minor cleanups. --- src/detect-parse.c | 35 +++++++++++++++++++++++++++++------ src/detect-parse.h | 3 ++- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/detect-parse.c b/src/detect-parse.c index ca1a238afba8..1215d56211b5 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -411,7 +411,7 @@ void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list) * * \retval match Pointer to the last SigMatch instance of type 'type'. */ -static inline SigMatch *SigMatchGetLastSM(SigMatch *sm, uint8_t type) +static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, uint8_t type) { while (sm != NULL) { if (sm->type == type) { @@ -424,11 +424,12 @@ static inline SigMatch *SigMatchGetLastSM(SigMatch *sm, uint8_t type) } /** - * \brief Returns the sm with the largest index (added latest) from all the lists. + * \brief Returns the sm with the largest index (added latest) from the lists + * passed to us. * * \retval Pointer to Last sm. */ -SigMatch *SigMatchGetLastSMFromLists(Signature *s, int args, ...) +SigMatch *SigMatchGetLastSMFromLists(const Signature *s, int args, ...) { if (args == 0 || args % 2 != 0) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "You need to send an even no of args " @@ -449,11 +450,11 @@ SigMatch *SigMatchGetLastSMFromLists(Signature *s, int args, ...) for (i = 0; i < args; i += 2) { int sm_type = va_arg(ap, int); SigMatch *sm_list = va_arg(ap, SigMatch *); - sm_new = SigMatchGetLastSM(sm_list, sm_type); + sm_new = SigMatchGetLastSMByType(sm_list, sm_type); if (sm_new == NULL) - continue; + continue; if (sm_last == NULL || sm_new->idx > sm_last->idx) - sm_last = sm_new; + sm_last = sm_new; } va_end(ap); @@ -461,6 +462,28 @@ SigMatch *SigMatchGetLastSMFromLists(Signature *s, int args, ...) return sm_last; } +/** + * \brief Returns the sm with the largest index (added latest) from this sig + * + * \retval Pointer to Last sm. + */ +SigMatch *SigMatchGetLastSM(const Signature *s) +{ + SigMatch *sm_last = NULL; + SigMatch *sm_new; + int i; + + for (i = 0; i < DETECT_SM_LIST_MAX; i ++) { + sm_new = s->sm_lists_tail[i]; + if (sm_new == NULL) + continue; + if (sm_last == NULL || sm_new->idx > sm_last->idx) + sm_last = sm_new; + } + + return sm_last; +} + void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, SigMatch **src_sm_list, SigMatch **src_sm_list_tail, SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail) diff --git a/src/detect-parse.h b/src/detect-parse.h index e780b86ad67e..6d1d454adf79 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -45,7 +45,8 @@ Signature *SigAlloc(void); void SigFree(Signature *s); Signature *SigInit(DetectEngineCtx *,char *sigstr); Signature *SigInitReal(DetectEngineCtx *, char *); -SigMatch *SigMatchGetLastSMFromLists(Signature *, int, ...); +SigMatch *SigMatchGetLastSMFromLists(const Signature *, int, ...); +SigMatch *SigMatchGetLastSM(const Signature *); void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, SigMatch **, SigMatch **s, SigMatch **, SigMatch **); From d461c7888ad3c08e8ea0c5abca418ecdd46640cd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 09:24:00 +0200 Subject: [PATCH 1868/2553] mpm uri: remove unused function args --- src/detect-engine-uri.c | 12 +++--------- src/detect-engine-uri.h | 2 ++ src/detect-uricontent.h | 4 ---- src/detect.c | 2 +- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index fd7e558ff1a6..a5fad2fc9c49 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -57,14 +57,12 @@ * \retval ret number of matches */ static inline uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *uri, const uint16_t uri_len, - const uint8_t flags) + const uint8_t *uri, const uint16_t uri_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_uri_ctx_ts == NULL); if (uri_len >= det_ctx->sgh->mpm_uri_ctx_ts->minlen) { @@ -88,12 +86,9 @@ static inline uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, * \param f locked flow * \param htp_state initialized htp state * - * \warning Make sure the flow/state is locked * \todo what should we return? Just the fact that we matched? */ -uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, void *txv) { SCEnter(); @@ -105,8 +100,7 @@ uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, goto end; cnt = UriPatternSearch(det_ctx, (const uint8_t *) bstr_ptr(tx_ud->request_uri_normalized), - bstr_len(tx_ud->request_uri_normalized), - flags); + bstr_len(tx_ud->request_uri_normalized)); end: SCReturnUInt(cnt); diff --git a/src/detect-engine-uri.h b/src/detect-engine-uri.h index 92b22cd35dbb..b9f4431ea840 100644 --- a/src/detect-engine-uri.h +++ b/src/detect-engine-uri.h @@ -24,6 +24,8 @@ #ifndef __DETECT_ENGINE_URICONTENT_H__ #define __DETECT_ENGINE_URICONTENT_H__ +uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, void *tx); + int DetectEngineInspectPacketUris(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-uricontent.h b/src/detect-uricontent.h index 812e69db9c85..4c64d4338a08 100644 --- a/src/detect-uricontent.h +++ b/src/detect-uricontent.h @@ -34,8 +34,4 @@ void DetectUricontentRegister (void); uint32_t DetectUricontentMaxId(DetectEngineCtx *); void DetectUricontentPrint(DetectContentData *); -uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); - #endif /* __DETECT_URICONTENT_H__ */ diff --git a/src/detect.c b/src/detect.c index d57294f54bd8..08485fa7f055 100644 --- a/src/detect.c +++ b/src/detect.c @@ -904,7 +904,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, if (tx_progress > HTP_REQUEST_LINE) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_URI) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_URI); - DetectUricontentInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectUricontentInspectMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_URI); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRUD) { From 3d5807ba448c874a69565e690f10718cdc2c1a7c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 09:25:48 +0200 Subject: [PATCH 1869/2553] mpm raw uri: remove unused function args --- src/detect-engine-hrud.c | 18 +++++++----------- src/detect-engine-hrud.h | 5 ++--- src/detect.c | 2 +- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 383669301c9d..7084ad58922d 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -68,14 +68,12 @@ * \retval ret Number of matches. */ static inline uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *uri, const uint32_t uri_len, - const uint8_t flags) + const uint8_t *uri, const uint32_t uri_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrud_ctx_ts == NULL); if (uri_len >= det_ctx->sgh->mpm_hrud_ctx_ts->minlen) { @@ -92,9 +90,7 @@ static inline uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, * * \retval cnt Number of matches reported by the mpm algo. */ -int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, void *txv) { SCEnter(); @@ -105,7 +101,7 @@ int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, Flow *f, cnt = HttpRawUriPatternSearch(det_ctx, (const uint8_t *)bstr_ptr(tx->request_uri), - bstr_len(tx->request_uri), flags); + bstr_len(tx->request_uri)); end: SCReturnInt(cnt); } @@ -2262,7 +2258,7 @@ static int DetectEngineHttpRawUriTest17(void) /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); + uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len); if (r != 1) { printf("expected 1 result, got %"PRIu32": ", r); goto end; @@ -2334,7 +2330,7 @@ static int DetectEngineHttpRawUriTest18(void) /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); + uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len); if (r != 0) { printf("expected 0 result, got %"PRIu32": ", r); goto end; @@ -2406,7 +2402,7 @@ static int DetectEngineHttpRawUriTest19(void) /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); + uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len); if (r != 0) { printf("expected 0 result, got %"PRIu32": ", r); goto end; @@ -2478,7 +2474,7 @@ static int DetectEngineHttpRawUriTest20(void) /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); + uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len); if (r < 1) { printf("expected result >= 1, got %"PRIu32": ", r); goto end; diff --git a/src/detect-engine-hrud.h b/src/detect-engine-hrud.h index 85ad88e1f687..e6f72d2461d4 100644 --- a/src/detect-engine-hrud.h +++ b/src/detect-engine-hrud.h @@ -26,9 +26,8 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); +int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, void *txv); + int DetectEngineInspectHttpRawUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect.c b/src/detect.c index 08485fa7f055..81eda3dc7219 100644 --- a/src/detect.c +++ b/src/detect.c @@ -909,7 +909,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRUD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRUD); - DetectEngineRunHttpRawUriMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectEngineRunHttpRawUriMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRUD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HMD) { From b40ecb73563ca4acb034ae69aefeea08aa48b467 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 09:29:36 +0200 Subject: [PATCH 1870/2553] mpm method: remove unused function args --- src/detect-engine-hmd.c | 11 +++-------- src/detect-engine-hmd.h | 6 +++--- src/detect.c | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 64d63cae4e2c..391a623b119d 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -68,14 +68,12 @@ * \retval ret Number of matches. */ static inline uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *raw_method, const uint32_t raw_method_len, - const uint8_t flags) + const uint8_t *raw_method, const uint32_t raw_method_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hmd_ctx_ts == NULL); if (raw_method_len >= det_ctx->sgh->mpm_hmd_ctx_ts->minlen) { @@ -87,9 +85,7 @@ static inline uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, SCReturnUInt(ret); } -int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, void *txv) { uint32_t cnt = 0; htp_tx_t *tx = (htp_tx_t *)txv; @@ -98,8 +94,7 @@ int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, Flow *f, cnt = HttpMethodPatternSearch(det_ctx, (const uint8_t *)bstr_ptr(tx->request_method), - bstr_len(tx->request_method), - flags); + bstr_len(tx->request_method)); end: return cnt; } diff --git a/src/detect-engine-hmd.h b/src/detect-engine-hmd.h index faf26aa2e2b6..c176755a6620 100644 --- a/src/detect-engine-hmd.h +++ b/src/detect-engine-hmd.h @@ -31,9 +31,9 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv, Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + +int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, void *txv); + void DetectEngineHttpMethodRegisterTests(void); #endif /* __DETECT_ENGINE_HMD_H__ */ diff --git a/src/detect.c b/src/detect.c index 81eda3dc7219..9cb643630697 100644 --- a/src/detect.c +++ b/src/detect.c @@ -914,7 +914,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HMD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HMD); - DetectEngineRunHttpMethodMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectEngineRunHttpMethodMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HMD); } } From 1380853ee859e589e43ba5e2e2790d2b32785c0a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 09:34:43 +0200 Subject: [PATCH 1871/2553] mpm host: remove unused function args --- src/detect-engine-hhhd.c | 10 +++------- src/detect-engine-hhhd.h | 6 +++--- src/detect.c | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 43af0b9e9a29..fbd4580d5c17 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -71,14 +71,12 @@ * \retval ret Number of matches. */ static inline uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *hh, const uint32_t hh_len, - const uint8_t flags) + const uint8_t *hh, const uint32_t hh_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhhd_ctx_ts == NULL); if (hh_len >= det_ctx->sgh->mpm_hhhd_ctx_ts->minlen) { @@ -90,9 +88,7 @@ static inline uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, SCReturnUInt(ret); } -int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, void *txv) { uint32_t cnt = 0; htp_tx_t *tx = (htp_tx_t *)txv; @@ -103,7 +99,7 @@ int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, goto end; const uint32_t hname_len = bstr_len(tx->request_hostname); - cnt = HttpHHPatternSearch(det_ctx, hname, hname_len, flags); + cnt = HttpHHPatternSearch(det_ctx, hname, hname_len); end: return cnt; diff --git a/src/detect-engine-hhhd.h b/src/detect-engine-hhhd.h index e6cec9071ca9..fdfed26a2bbf 100644 --- a/src/detect-engine-hhhd.h +++ b/src/detect-engine-hhhd.h @@ -31,9 +31,9 @@ int DetectEngineInspectHttpHH(ThreadVars *tv, Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + +int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, void *txv); + void DetectEngineHttpHHRegisterTests(void); #endif /* __DETECT_ENGINE_HHHD_H__ */ diff --git a/src/detect.c b/src/detect.c index 9cb643630697..a0cf82264f38 100644 --- a/src/detect.c +++ b/src/detect.c @@ -922,7 +922,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, if (tx_progress >= HTP_REQUEST_HEADERS) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHHD); - DetectEngineRunHttpHHMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectEngineRunHttpHHMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHHD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHHD) { From 4229e603f0b47469e1ada05248824dbed91928eb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 09:37:30 +0200 Subject: [PATCH 1872/2553] mpm raw host: remove unused function args --- src/detect-engine-hrhhd.c | 11 +++-------- src/detect-engine-hrhhd.h | 6 +++--- src/detect.c | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index b0a9f1134adc..3debb11a37f1 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -66,19 +66,16 @@ * \param det_ctx Detection engine thread ctx. * \param hrh Raw hostname to inspect. * \param hrh_len Raw hostname buffer length. - * \param flags Flags * * \retval ret Number of matches. */ static inline uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *hrh, const uint32_t hrh_len, - const uint8_t flags) + const uint8_t *hrh, const uint32_t hrh_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL); if (hrh_len >= det_ctx->sgh->mpm_hrhhd_ctx_ts->minlen) { @@ -90,9 +87,7 @@ static inline uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, SCReturnUInt(ret); } -int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, void *txv) { uint32_t cnt = 0; htp_tx_t *tx = (htp_tx_t *)txv; @@ -119,7 +114,7 @@ int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, } if (hname != NULL) { - cnt = HttpHRHPatternSearch(det_ctx, hname, hname_len, flags); + cnt = HttpHRHPatternSearch(det_ctx, hname, hname_len); } end: diff --git a/src/detect-engine-hrhhd.h b/src/detect-engine-hrhhd.h index 24c3b43e219a..c939a173f09e 100644 --- a/src/detect-engine-hrhhd.h +++ b/src/detect-engine-hrhhd.h @@ -31,9 +31,9 @@ int DetectEngineInspectHttpHRH(ThreadVars *tv, Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + +int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, void *txv); + void DetectEngineHttpHRHRegisterTests(void); #endif /* __DETECT_ENGINE_HRHHD_H__ */ diff --git a/src/detect.c b/src/detect.c index a0cf82264f38..4aab3172d09d 100644 --- a/src/detect.c +++ b/src/detect.c @@ -927,7 +927,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHHD); - DetectEngineRunHttpHRHMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectEngineRunHttpHRHMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHHD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCD) { From 704afeb078343baaa41abe66cc4bbeca1d2cf623 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 09:42:52 +0200 Subject: [PATCH 1873/2553] mpm cookie: remove unused function args --- src/detect-engine-hcd.c | 5 ++--- src/detect-engine-hcd.h | 7 ++++--- src/detect.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index f783af0d25bf..5372a4686d85 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -96,9 +96,8 @@ static inline uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *det_ctx, SCReturnUInt(ret); } -int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, + uint8_t flags, void *txv) { uint32_t cnt = 0; htp_tx_t *tx = (htp_tx_t *)txv; diff --git a/src/detect-engine-hcd.h b/src/detect-engine-hcd.h index 78f92407f256..a3853c23d90b 100644 --- a/src/detect-engine-hcd.h +++ b/src/detect-engine-hcd.h @@ -31,9 +31,10 @@ int DetectEngineInspectHttpCookie(ThreadVars *tv, Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + +int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, + uint8_t flags, void *tx); + void DetectEngineHttpCookieRegisterTests(void); #endif /* __DETECT_ENGINE_HCD_H__ */ diff --git a/src/detect.c b/src/detect.c index 4aab3172d09d..edcf3d1823df 100644 --- a/src/detect.c +++ b/src/detect.c @@ -932,7 +932,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCD); - DetectEngineRunHttpCookieMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectEngineRunHttpCookieMpm(det_ctx, flags, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HUAD) { @@ -986,7 +986,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCD); - DetectEngineRunHttpCookieMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectEngineRunHttpCookieMpm(det_ctx, flags, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCD); } } From 6d54b70db4b14d4b55115fd1c5dde347029cac28 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 09:45:19 +0200 Subject: [PATCH 1874/2553] mpm ua: remove unused function args --- src/detect-engine-hua.c | 10 +++------- src/detect-engine-hua.h | 6 +++--- src/detect.c | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index 41842f8fbbb3..6e8ad44d9531 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -69,14 +69,12 @@ * \retval ret Number of matches. */ static inline uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *ua, const uint32_t ua_len, - const uint8_t flags) + const uint8_t *ua, const uint32_t ua_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_huad_ctx_ts == NULL); if (ua_len >= det_ctx->sgh->mpm_huad_ctx_ts->minlen) { @@ -88,9 +86,7 @@ static inline uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, SCReturnUInt(ret); } -int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, void *txv) { uint32_t cnt = 0; htp_tx_t *tx = (htp_tx_t *)txv; @@ -105,7 +101,7 @@ int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, Flow *f, } cnt = HttpUAPatternSearch(det_ctx, (const uint8_t *)bstr_ptr(h->value), - bstr_len(h->value), flags); + bstr_len(h->value)); end: return cnt; } diff --git a/src/detect-engine-hua.h b/src/detect-engine-hua.h index c18ac76183c2..a6664e55ab5f 100644 --- a/src/detect-engine-hua.h +++ b/src/detect-engine-hua.h @@ -31,9 +31,9 @@ int DetectEngineInspectHttpUA(ThreadVars *tv, Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + +int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, void *txv); + void DetectEngineHttpUARegisterTests(void); #endif /* __DETECT_ENGINE_HUA_H__ */ diff --git a/src/detect.c b/src/detect.c index edcf3d1823df..020811e401d0 100644 --- a/src/detect.c +++ b/src/detect.c @@ -937,7 +937,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HUAD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HUAD); - DetectEngineRunHttpUAMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectEngineRunHttpUAMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HUAD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHD) { From bd03307921a76ac0df01b176fd24f20a9ba251c9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 10:24:19 +0200 Subject: [PATCH 1875/2553] mpm stat msg: remove unused function args --- src/detect-engine-hsmd.c | 10 +++------- src/detect-engine-hsmd.h | 5 ++--- src/detect.c | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index cacee62fefc4..46d3e4fe000a 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -65,14 +65,12 @@ * \retval ret Number of matches. */ static inline uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *stat_msg, const uint32_t stat_msg_len, - const uint8_t flags) + const uint8_t *stat_msg, const uint32_t stat_msg_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsmd_ctx_tc == NULL); if (stat_msg_len >= det_ctx->sgh->mpm_hsmd_ctx_tc->minlen) { @@ -89,9 +87,7 @@ static inline uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, * * \retval cnt Number of matches reported by the mpm algo. */ -int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, void *txv) { SCEnter(); @@ -102,7 +98,7 @@ int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, Flow *f, cnt = HttpStatMsgPatternSearch(det_ctx, (const uint8_t *)bstr_ptr(tx->response_message), - bstr_len(tx->response_message), flags); + bstr_len(tx->response_message)); end: SCReturnInt(cnt); } diff --git a/src/detect-engine-hsmd.h b/src/detect-engine-hsmd.h index 01fc3612b772..9faa2064f8b7 100644 --- a/src/detect-engine-hsmd.h +++ b/src/detect-engine-hsmd.h @@ -25,9 +25,8 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); +int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, void *txv); + int DetectEngineInspectHttpStatMsg(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect.c b/src/detect.c index 020811e401d0..1ddde948dbbf 100644 --- a/src/detect.c +++ b/src/detect.c @@ -968,7 +968,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, if (tx_progress > HTP_RESPONSE_LINE) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSMD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSMD); - DetectEngineRunHttpStatMsgMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectEngineRunHttpStatMsgMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSMD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSCD) { From d647db17751837fe15e157992b9b3890359403a5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 10:25:52 +0200 Subject: [PATCH 1876/2553] mpm stat code: remove unused function args --- src/detect-engine-hscd.c | 10 +++------- src/detect-engine-hscd.h | 5 ++--- src/detect.c | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 1c55e17637d6..8d0cbbee5a35 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -65,14 +65,12 @@ * \retval ret Number of matches. */ static inline uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *stat_code, const uint32_t stat_code_len, - const uint8_t flags) + const uint8_t *stat_code, const uint32_t stat_code_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hscd_ctx_tc == NULL); if (stat_code_len >= det_ctx->sgh->mpm_hscd_ctx_tc->minlen) { @@ -89,9 +87,7 @@ static inline uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, * * \retval cnt Number of matches reported by the mpm algo. */ -int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, void *txv) { SCEnter(); @@ -102,7 +98,7 @@ int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, Flow *f, cnt = HttpStatCodePatternSearch(det_ctx, (const uint8_t *)bstr_ptr(tx->response_status), - bstr_len(tx->response_status), flags); + bstr_len(tx->response_status)); end: SCReturnInt(cnt); } diff --git a/src/detect-engine-hscd.h b/src/detect-engine-hscd.h index 2a97c2ff0de0..d85921d3ebe6 100644 --- a/src/detect-engine-hscd.h +++ b/src/detect-engine-hscd.h @@ -25,9 +25,8 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); +int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, void *txv); + int DetectEngineInspectHttpStatCode(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect.c b/src/detect.c index 1ddde948dbbf..20fdde08d3ed 100644 --- a/src/detect.c +++ b/src/detect.c @@ -973,7 +973,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSCD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSCD); - DetectEngineRunHttpStatCodeMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectEngineRunHttpStatCodeMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSCD); } } From ad3a55d9381c82ee7164fa89143fa77064654d9f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 10:30:47 +0200 Subject: [PATCH 1877/2553] mpm dns query: remove unused function args --- src/detect-dns-query.h | 4 ++-- src/detect-engine-dns.c | 12 +++--------- src/detect.c | 4 ++-- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/detect-dns-query.h b/src/detect-dns-query.h index 75605231288f..4065c4103411 100644 --- a/src/detect-dns-query.h +++ b/src/detect-dns-query.h @@ -27,7 +27,7 @@ #include "app-layer-dns-common.h" void DetectDnsQueryRegister (void); -uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - DNSState *dns_state, uint8_t flags, void *txv, uint64_t tx_id); + +uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, void *txv); #endif /* __DETECT_DNS_QUERY_H__ */ diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index e68c1093b0c8..f3441e1afcec 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -105,14 +105,12 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, * \retval ret Number of matches. */ static inline uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *buffer, const uint32_t buffer_len, - const uint8_t flags) + const uint8_t *buffer, const uint32_t buffer_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL); if (buffer_len >= det_ctx->sgh->mpm_dnsquery_ctx_ts->minlen) { @@ -130,12 +128,9 @@ static inline uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, * \param f locked flow * \param dns_state initialized dns state * - * \warning Make sure the flow/state is locked * \todo what should we return? Just the fact that we matched? */ -uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - DNSState *dns_state, uint8_t flags, void *txv, - uint64_t tx_id) +uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, void *txv) { SCEnter(); @@ -152,8 +147,7 @@ uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, buffer_len = query->len; cnt += DnsQueryPatternSearch(det_ctx, - buffer, buffer_len, - flags); + buffer, buffer_len); } SCReturnUInt(cnt); diff --git a/src/detect.c b/src/detect.c index 20fdde08d3ed..3907a0a6e300 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1027,7 +1027,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, continue; PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_DNSQUERY); - DetectDnsQueryInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectDnsQueryInspectMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY); } } @@ -1136,7 +1136,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, continue; SCLogDebug("tx %p",tx); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_DNSQUERY); - DetectDnsQueryInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx); + DetectDnsQueryInspectMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY); } } From ff70e0cca0a57011d2073d3fe05a2006b7ffb868 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 10:33:28 +0200 Subject: [PATCH 1878/2553] mpm tls: remove unused function args --- src/detect-engine-tls.c | 50 ++++++++++++++--------------------- src/detect-tls-cert-issuer.h | 2 +- src/detect-tls-cert-subject.h | 2 +- src/detect-tls-sni.h | 3 +-- src/detect.c | 6 ++--- 5 files changed, 26 insertions(+), 37 deletions(-) diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 25891671d0c2..940833106c01 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -57,14 +57,12 @@ */ static inline uint32_t TlsSniPatternSearch(DetectEngineThreadCtx *det_ctx, const uint8_t *buffer, - const uint32_t buffer_len, - const uint8_t flags) + const uint32_t buffer_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_tlssni_ctx_ts == NULL); if (buffer_len >= det_ctx->sgh->mpm_tlssni_ctx_ts->minlen) { @@ -86,8 +84,8 @@ static inline uint32_t TlsSniPatternSearch(DetectEngineThreadCtx *det_ctx, * * \retval cnt Number of matches */ -uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - SSLState *ssl_state, uint8_t flags) +uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, + SSLState *ssl_state) { SCEnter(); @@ -101,7 +99,7 @@ uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, buffer = (uint8_t *)ssl_state->client_connp.sni; buffer_len = strlen(ssl_state->client_connp.sni); - cnt = TlsSniPatternSearch(det_ctx, buffer, buffer_len, flags); + cnt = TlsSniPatternSearch(det_ctx, buffer, buffer_len); SCReturnUInt(cnt); } @@ -147,23 +145,20 @@ int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, /** * \brief TLS issuer match -- searches for one pattern per signature. * - * \param det_ctx Detection engine thread ctx - * \param hrh Buffer to inspect - * \param hrh_len Buffer length - * \param flags Flags + * \param det_ctx Detection engine thread ctx + * \param buffer Buffer to inspect + * \param buffer_len Buffer length * * \retval ret Number of matches */ static inline uint32_t TlsIssuerPatternSearch(DetectEngineThreadCtx *det_ctx, const uint8_t *buffer, - const uint32_t buffer_len, - const uint8_t flags) + const uint32_t buffer_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOSERVER); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_tlsissuer_ctx_ts == NULL); if (buffer_len >= det_ctx->sgh->mpm_tlsissuer_ctx_ts->minlen) { @@ -180,13 +175,12 @@ static inline uint32_t TlsIssuerPatternSearch(DetectEngineThreadCtx *det_ctx, * * \param det_ctx Detection engine thread ctx * \param f Locked flow - * \param dns_state Initialized dns state - * \param flags Flags + * \param ssl_state Initialized ssl state * * \retval cnt Number of matches */ uint32_t DetectTlsIssuerInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - SSLState *ssl_state, uint8_t flags) + SSLState *ssl_state) { SCEnter(); @@ -200,7 +194,7 @@ uint32_t DetectTlsIssuerInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, buffer = (uint8_t *)ssl_state->server_connp.cert0_issuerdn; buffer_len = strlen(ssl_state->server_connp.cert0_issuerdn); - cnt = TlsIssuerPatternSearch(det_ctx, buffer, buffer_len, flags); + cnt = TlsIssuerPatternSearch(det_ctx, buffer, buffer_len); SCReturnUInt(cnt); } @@ -224,7 +218,7 @@ int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, uint64_t tx_id) { uint8_t *buffer; - uint16_t buffer_len; + uint32_t buffer_len; int cnt = 0; SSLState *ssl_state = (SSLState *)alstate; @@ -246,23 +240,20 @@ int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, /** * \brief TLS subject match -- searches for one pattern per signature. * - * \param det_ctx Detection engine thread ctx - * \param hrh Buffer to inspect - * \param hrh_len Buffer length - * \param flags Flags + * \param det_ctx Detection engine thread ctx + * \param buffer Buffer to inspect + * \param buffer_len Buffer length * * \retval ret Number of matches */ static inline uint32_t TlsSubjectPatternSearch(DetectEngineThreadCtx *det_ctx, const uint8_t *buffer, - const uint32_t buffer_len, - const uint8_t flags) + const uint32_t buffer_len) { SCEnter(); uint32_t ret = 0; - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOSERVER); DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_tlssubject_ctx_ts == NULL); if (buffer_len >= det_ctx->sgh->mpm_tlssubject_ctx_ts->minlen) { @@ -279,13 +270,12 @@ static inline uint32_t TlsSubjectPatternSearch(DetectEngineThreadCtx *det_ctx, * * \param det_ctx Detection engine thread ctx * \param f Locked flow - * \param dns_state Initialized dns state - * \param flags Flags + * \param ssl_state Initialized ssl state * * \retval cnt Number of matches */ uint32_t DetectTlsSubjectInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - SSLState *ssl_state, uint8_t flags) + SSLState *ssl_state) { SCEnter(); @@ -299,7 +289,7 @@ uint32_t DetectTlsSubjectInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, buffer = (uint8_t *)ssl_state->server_connp.cert0_subject; buffer_len = strlen(ssl_state->server_connp.cert0_subject); - cnt = TlsSubjectPatternSearch(det_ctx, buffer, buffer_len, flags); + cnt = TlsSubjectPatternSearch(det_ctx, buffer, buffer_len); SCReturnUInt(cnt); } @@ -323,7 +313,7 @@ int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, uint64_t tx_id) { uint8_t *buffer; - uint16_t buffer_len; + uint32_t buffer_len; int cnt = 0; SSLState *ssl_state = (SSLState *)alstate; diff --git a/src/detect-tls-cert-issuer.h b/src/detect-tls-cert-issuer.h index 8febf749f14e..a0b0846f7eb8 100644 --- a/src/detect-tls-cert-issuer.h +++ b/src/detect-tls-cert-issuer.h @@ -28,6 +28,6 @@ void DetectTlsIssuerRegister(void); uint32_t DetectTlsIssuerInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - SSLState *ssl_state, uint8_t flags); + SSLState *ssl_state); #endif /* __DETECT_TLS_ISSUER_H__ */ diff --git a/src/detect-tls-cert-subject.h b/src/detect-tls-cert-subject.h index e8fd1d3f99e2..2edce96c86ab 100644 --- a/src/detect-tls-cert-subject.h +++ b/src/detect-tls-cert-subject.h @@ -28,6 +28,6 @@ void DetectTlsSubjectRegister(void); uint32_t DetectTlsSubjectInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - SSLState *ssl_state, uint8_t flags); + SSLState *ssl_state); #endif /* __DETECT_TLS_SUBJECT_H__ */ diff --git a/src/detect-tls-sni.h b/src/detect-tls-sni.h index 8e6d93086cad..a3117906c1b3 100644 --- a/src/detect-tls-sni.h +++ b/src/detect-tls-sni.h @@ -27,7 +27,6 @@ #include "app-layer-ssl.h" void DetectTlsSniRegister(void); -uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - SSLState *ssl_state, uint8_t flags); +uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, SSLState *ssl_state); #endif /* __DETECT_TLS_SNI_H__ */ diff --git a/src/detect.c b/src/detect.c index 3907a0a6e300..3ce90ff6f4ca 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1042,18 +1042,18 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, if (p->flowflags & FLOW_PKT_TOSERVER) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSSNI) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSSNI); - DetectTlsSniInspectMpm(det_ctx, p->flow, alstate, flags); + DetectTlsSniInspectMpm(det_ctx, alstate); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSNI); } } else if (p->flowflags & FLOW_PKT_TOCLIENT) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSISSUER) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSISSUER); - DetectTlsIssuerInspectMpm(det_ctx, p->flow, alstate, flags); + DetectTlsIssuerInspectMpm(det_ctx, p->flow, alstate); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSISSUER); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSSUBJECT) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSSUBJECT); - DetectTlsSubjectInspectMpm(det_ctx, p->flow, alstate, flags); + DetectTlsSubjectInspectMpm(det_ctx, p->flow, alstate); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSUBJECT); } } From a41695f29f06e7ed692e25851a9f5298de34c8c3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 10:48:04 +0200 Subject: [PATCH 1879/2553] uricontent: remove left over func decl --- src/detect-uricontent.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/detect-uricontent.h b/src/detect-uricontent.h index 4c64d4338a08..1729e58f3e3d 100644 --- a/src/detect-uricontent.h +++ b/src/detect-uricontent.h @@ -31,7 +31,6 @@ /* prototypes */ void DetectUricontentRegister (void); -uint32_t DetectUricontentMaxId(DetectEngineCtx *); void DetectUricontentPrint(DetectContentData *); #endif /* __DETECT_URICONTENT_H__ */ From 7c4701691309305ef294cde729542f22ebe9aaa2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 15 Jul 2016 16:09:03 +0200 Subject: [PATCH 1880/2553] detect-fragoffset: minor cleanup --- src/detect-fragoffset.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index 28d467b67044..9e6f32e6432b 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -99,13 +99,16 @@ int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet switch (fragoff->mode) { case FRAG_LESS: - if (frag < fragoff->frag_off) return 1; + if (frag < fragoff->frag_off) + return 1; break; case FRAG_MORE: - if (frag > fragoff->frag_off) return 1; + if (frag > fragoff->frag_off) + return 1; break; default: - if (frag == fragoff->frag_off) return 1; + if (frag == fragoff->frag_off) + return 1; } return 0; From 4c0ab681f20b804d2eae174698579f7043a38974 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 10 Jul 2016 11:40:19 +0200 Subject: [PATCH 1881/2553] mpm: remove Cleanup API call It's unused by all of the implementations. --- src/detect-engine-mpm.c | 22 ---------------------- src/util-mpm-ac-bs.c | 1 - src/util-mpm-ac-tile.c | 1 - src/util-mpm-ac.c | 2 -- src/util-mpm-hs.c | 1 - src/util-mpm.h | 1 - 6 files changed, 28 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index f078d6d1e3f0..08bb30fff600 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -376,28 +376,6 @@ uint16_t PatternMatchDefaultMatcher(void) void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) { PmqReset(&det_ctx->pmq); - - if (det_ctx->sgh == NULL) - return; - - /* content */ - if (det_ctx->sgh->mpm_packet_ctx != NULL && - mpm_table[det_ctx->sgh->mpm_packet_ctx->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_packet_ctx->mpm_type].Cleanup(&det_ctx->mtc); - } - - /* uricontent */ - if (det_ctx->sgh->mpm_uri_ctx_ts != NULL && mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type].Cleanup(&det_ctx->mtcu); - } - - /* stream content */ - if (det_ctx->sgh->mpm_stream_ctx != NULL && - mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type].Cleanup(&det_ctx->mtcs); - } - - return; } void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher) diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 85d3b3bef8f0..6e88c27089b8 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -103,7 +103,6 @@ void MpmACBSRegister(void) mpm_table[MPM_AC_BS].AddPatternNocase = SCACBSAddPatternCI; mpm_table[MPM_AC_BS].Prepare = SCACBSPreparePatterns; mpm_table[MPM_AC_BS].Search = SCACBSSearch; - mpm_table[MPM_AC_BS].Cleanup = NULL; mpm_table[MPM_AC_BS].PrintCtx = SCACBSPrintInfo; mpm_table[MPM_AC_BS].PrintThreadCtx = SCACBSPrintSearchStats; mpm_table[MPM_AC_BS].RegisterUnittests = SCACBSRegisterTests; diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 62fda87e106c..27c4e5b7a139 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -1500,7 +1500,6 @@ void MpmACTileRegister(void) mpm_table[MPM_AC_TILE].AddPatternNocase = SCACTileAddPatternCI; mpm_table[MPM_AC_TILE].Prepare = SCACTilePreparePatterns; mpm_table[MPM_AC_TILE].Search = SCACTileSearch; - mpm_table[MPM_AC_TILE].Cleanup = NULL; mpm_table[MPM_AC_TILE].PrintCtx = SCACTilePrintInfo; mpm_table[MPM_AC_TILE].PrintThreadCtx = SCACTilePrintSearchStats; mpm_table[MPM_AC_TILE].RegisterUnittests = SCACTileRegisterTests; diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 095cde6d5a79..70142fed4121 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -1767,7 +1767,6 @@ void MpmACRegister(void) mpm_table[MPM_AC].AddPatternNocase = SCACAddPatternCI; mpm_table[MPM_AC].Prepare = SCACPreparePatterns; mpm_table[MPM_AC].Search = SCACSearch; - mpm_table[MPM_AC].Cleanup = NULL; mpm_table[MPM_AC].PrintCtx = SCACPrintInfo; mpm_table[MPM_AC].PrintThreadCtx = SCACPrintSearchStats; mpm_table[MPM_AC].RegisterUnittests = SCACRegisterTests; @@ -1791,7 +1790,6 @@ void MpmACCudaRegister(void) mpm_table[MPM_AC_CUDA].AddPatternNocase = SCACAddPatternCI; mpm_table[MPM_AC_CUDA].Prepare = SCACPreparePatterns; mpm_table[MPM_AC_CUDA].Search = SCACSearch; - mpm_table[MPM_AC_CUDA].Cleanup = NULL; mpm_table[MPM_AC_CUDA].PrintCtx = SCACPrintInfo; mpm_table[MPM_AC_CUDA].PrintThreadCtx = SCACPrintSearchStats; mpm_table[MPM_AC_CUDA].RegisterUnittests = SCACRegisterTests; diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index 43e74d3142a8..e0153a4748cb 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -1045,7 +1045,6 @@ void MpmHSRegister(void) mpm_table[MPM_HS].AddPatternNocase = SCHSAddPatternCI; mpm_table[MPM_HS].Prepare = SCHSPreparePatterns; mpm_table[MPM_HS].Search = SCHSSearch; - mpm_table[MPM_HS].Cleanup = NULL; mpm_table[MPM_HS].PrintCtx = SCHSPrintInfo; mpm_table[MPM_HS].PrintThreadCtx = SCHSPrintSearchStats; mpm_table[MPM_HS].RegisterUnittests = SCHSRegisterTests; diff --git a/src/util-mpm.h b/src/util-mpm.h index 4930f0a6b62c..60634c45ef49 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -179,7 +179,6 @@ typedef struct MpmTableElmt_ { int (*AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int (*Prepare)(struct MpmCtx_ *); uint32_t (*Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, const uint8_t *, uint16_t); - void (*Cleanup)(struct MpmThreadCtx_ *); void (*PrintCtx)(struct MpmCtx_ *); void (*PrintThreadCtx)(struct MpmThreadCtx_ *); void (*RegisterUnittests)(void); From bb0cd0e883c90e551110e79638b8bd017eac1a66 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 Jul 2016 13:15:31 +0200 Subject: [PATCH 1882/2553] prefilter: rename PatternMatcherQueue datatype In preparation of the introduction of more general purpose prefilter engines, rename PatternMatcherQueue to PrefilterRuleStore. The new engines will fill this structure a similar way to the current mpm prefilters. --- src/Makefile.am | 1 + src/app-layer-detect-proto.c | 2 +- src/app-layer-smtp.c | 2 +- src/detect.h | 5 +- src/threadvars.h | 1 - src/util-mpm-ac-bs.c | 74 ++++++++++---------- src/util-mpm-ac-tile-small.c | 2 +- src/util-mpm-ac-tile.c | 92 ++++++++++++------------ src/util-mpm-ac-tile.h | 4 +- src/util-mpm-ac.c | 80 +++++++++++---------- src/util-mpm-ac.h | 2 +- src/util-mpm-hs.c | 64 ++++++++--------- src/util-mpm.c | 106 ---------------------------- src/util-mpm.h | 63 ++--------------- src/util-prefilter.c | 132 +++++++++++++++++++++++++++++++++++ src/util-prefilter.h | 80 +++++++++++++++++++++ 16 files changed, 388 insertions(+), 322 deletions(-) create mode 100644 src/util-prefilter.c create mode 100644 src/util-prefilter.h diff --git a/src/Makefile.am b/src/Makefile.am index 2e805a28dff8..9f0f7e64f1dd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -389,6 +389,7 @@ util-path.c util-path.h \ util-pidfile.c util-pidfile.h \ util-pool.c util-pool.h \ util-pool-thread.c util-pool-thread.h \ +util-prefilter.c util-prefilter.h \ util-print.c util-print.h \ util-privs.c util-privs.h \ util-profiling.c util-profiling.h \ diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 68690441d82e..cca1ae7a8f55 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -157,7 +157,7 @@ typedef struct AppLayerProtoDetectCtx_ { * \brief The app layer protocol detection thread context. */ struct AppLayerProtoDetectThreadCtx_ { - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; /* The value 2 is for direction(0 - toserver, 1 - toclient). */ MpmThreadCtx mpm_tctx[FLOW_PROTO_DEFAULT][2]; SpmThreadCtx *spm_thread_ctx; diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 1224b54adefc..8462cc366d58 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -154,7 +154,7 @@ SCEnumCharMap smtp_decoder_event_table[ ] = { typedef struct SMTPThreadCtx_ { MpmThreadCtx *smtp_mpm_thread_ctx; - PatternMatcherQueue *pmq; + PrefilterRuleStore *pmq; } SMTPThreadCtx; #define SMTP_MPM DEFAULT_MPM diff --git a/src/detect.h b/src/detect.h index 142ca40c040e..014a1c1acf51 100644 --- a/src/detect.h +++ b/src/detect.h @@ -30,8 +30,9 @@ #include "detect-engine-proto.h" #include "detect-reference.h" - #include "packet-queue.h" + +#include "util-prefilter.h" #include "util-mpm.h" #include "util-spm.h" #include "util-hash.h" @@ -831,7 +832,7 @@ typedef struct DetectEngineThreadCtx_ { MpmThreadCtx mtc; /**< thread ctx for the mpm */ MpmThreadCtx mtcu; /**< thread ctx for uricontent mpm */ MpmThreadCtx mtcs; /**< thread ctx for stream mpm */ - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; /** SPM thread context used for scanning. This has been cloned from the * prototype held by DetectEngineCtx. */ diff --git a/src/threadvars.h b/src/threadvars.h index 389f22a14eaa..80c61cfa0883 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -24,7 +24,6 @@ #ifndef __THREADVARS_H__ #define __THREADVARS_H__ -#include "util-mpm.h" #include "util-affinity.h" #include "tm-queues.h" #include "counters.h" diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 6e88c27089b8..07bbd08d8ef2 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -70,7 +70,7 @@ int SCACBSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int SCACBSPreparePatterns(MpmCtx *mpm_ctx); uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen); + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); void SCACBSPrintInfo(MpmCtx *mpm_ctx); void SCACBSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACBSRegisterTests(void); @@ -1147,7 +1147,7 @@ void SCACBSDestroyCtx(MpmCtx *mpm_ctx) * \retval matches Match count. */ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen) + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen) { const SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int i = 0; @@ -1226,7 +1226,8 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); + PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1234,7 +1235,8 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); + PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1308,7 +1310,8 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); + PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1316,7 +1319,8 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); + PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1422,7 +1426,7 @@ static int SCACBSTest01(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1456,7 +1460,7 @@ static int SCACBSTest02(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1489,7 +1493,7 @@ static int SCACBSTest03(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1526,7 +1530,7 @@ static int SCACBSTest04(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1560,7 +1564,7 @@ static int SCACBSTest05(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1594,7 +1598,7 @@ static int SCACBSTest06(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1626,7 +1630,7 @@ static int SCACBSTest07(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1671,7 +1675,7 @@ static int SCACBSTest08(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1703,7 +1707,7 @@ static int SCACBSTest09(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1735,7 +1739,7 @@ static int SCACBSTest10(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1772,7 +1776,7 @@ static int SCACBSTest11(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1819,7 +1823,7 @@ static int SCACBSTest12(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1854,7 +1858,7 @@ static int SCACBSTest13(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1888,7 +1892,7 @@ static int SCACBSTest14(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1922,7 +1926,7 @@ static int SCACBSTest15(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1956,7 +1960,7 @@ static int SCACBSTest16(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1990,7 +1994,7 @@ static int SCACBSTest17(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2024,7 +2028,7 @@ static int SCACBSTest18(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2058,7 +2062,7 @@ static int SCACBSTest19(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2091,7 +2095,7 @@ static int SCACBSTest20(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2125,7 +2129,7 @@ static int SCACBSTest21(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2157,7 +2161,7 @@ static int SCACBSTest22(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2192,7 +2196,7 @@ static int SCACBSTest23(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2224,7 +2228,7 @@ static int SCACBSTest24(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2256,7 +2260,7 @@ static int SCACBSTest25(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2290,7 +2294,7 @@ static int SCACBSTest26(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2323,7 +2327,7 @@ static int SCACBSTest27(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2356,7 +2360,7 @@ static int SCACBSTest28(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2389,7 +2393,7 @@ static int SCACBSTest29(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); diff --git a/src/util-mpm-ac-tile-small.c b/src/util-mpm-ac-tile-small.c index 0a875778d643..a5e1ef0eacaf 100644 --- a/src/util-mpm-ac-tile-small.c +++ b/src/util-mpm-ac-tile-small.c @@ -32,7 +32,7 @@ /* This function handles (ctx->state_count < 32767) */ uint32_t FUNC_NAME(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen) + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen) { int i = 0; int matches = 0; diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index 27c4e5b7a139..e6b3d1ed5378 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -92,51 +92,51 @@ int SCACTileAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int SCACTilePreparePatterns(MpmCtx *mpm_ctx); uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, const uint8_t *buf, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); void SCACTilePrintInfo(MpmCtx *mpm_ctx); void SCACTilePrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACTileRegisterTests(void); uint32_t SCACTileSearchLarge(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchSmall256(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchSmall128(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchSmall64(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchSmall32(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchSmall16(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchSmall8(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchTiny256(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchTiny128(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchTiny64(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchTiny32(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchTiny16(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); uint32_t SCACTileSearchTiny8(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); @@ -1172,7 +1172,7 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) #define EXTRA 4 // need 4 extra bytes to avoid OOB reads #endif -int CheckMatch(const SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, +int CheckMatch(const SCACTileSearchCtx *ctx, PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen, uint16_t state, int i, int matches, uint8_t *mpm_bitarray) @@ -1214,7 +1214,7 @@ int CheckMatch(const SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, /* Always add the Signature IDs, since they could be different in the current MPM * than in a previous MPM on the same PMQ when finding the same pattern. */ - MpmAddSids(pmq, pattern_list[pindex].sids, + PrefilterAddSids(pmq, pattern_list[pindex].sids, pattern_list[pindex].sids_size); matches++; } @@ -1235,7 +1235,7 @@ int CheckMatch(const SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, * \retval matches Match count. */ uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen) + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen) { const SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; @@ -1248,7 +1248,7 @@ uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* This function handles (ctx->state_count >= 32767) */ uint32_t SCACTileSearchLarge(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen) { int i = 0; @@ -1515,7 +1515,7 @@ static int SCACTileTest01(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1549,7 +1549,7 @@ static int SCACTileTest02(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1582,7 +1582,7 @@ static int SCACTileTest03(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1619,7 +1619,7 @@ static int SCACTileTest04(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1653,7 +1653,7 @@ static int SCACTileTest05(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1687,7 +1687,7 @@ static int SCACTileTest06(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1719,7 +1719,7 @@ static int SCACTileTest07(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1764,7 +1764,7 @@ static int SCACTileTest08(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1796,7 +1796,7 @@ static int SCACTileTest09(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1828,7 +1828,7 @@ static int SCACTileTest10(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1865,7 +1865,7 @@ static int SCACTileTest11(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1912,7 +1912,7 @@ static int SCACTileTest12(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1947,7 +1947,7 @@ static int SCACTileTest13(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1981,7 +1981,7 @@ static int SCACTileTest14(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2015,7 +2015,7 @@ static int SCACTileTest15(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2049,7 +2049,7 @@ static int SCACTileTest16(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2083,7 +2083,7 @@ static int SCACTileTest17(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2117,7 +2117,7 @@ static int SCACTileTest18(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2151,7 +2151,7 @@ static int SCACTileTest19(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2185,7 +2185,7 @@ static int SCACTileTest20(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2219,7 +2219,7 @@ static int SCACTileTest21(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2251,7 +2251,7 @@ static int SCACTileTest22(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2286,7 +2286,7 @@ static int SCACTileTest23(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2318,7 +2318,7 @@ static int SCACTileTest24(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2350,7 +2350,7 @@ static int SCACTileTest25(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2384,7 +2384,7 @@ static int SCACTileTest26(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2417,7 +2417,7 @@ static int SCACTileTest27(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2450,7 +2450,7 @@ static int SCACTileTest28(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); diff --git a/src/util-mpm-ac-tile.h b/src/util-mpm-ac-tile.h index 5f47f23018d7..1f9ba4e5ecbb 100644 --- a/src/util-mpm-ac-tile.h +++ b/src/util-mpm-ac-tile.h @@ -64,7 +64,7 @@ typedef struct SCACTileCtx_ { * 32 bits. */ uint32_t (*search)(const struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, - PatternMatcherQueue *, const uint8_t *, uint16_t); + PrefilterRuleStore *, const uint8_t *, uint16_t); /* Function to set the next state based on size of next state * (bytes_per_state). @@ -117,7 +117,7 @@ typedef struct SCACTileSearchCtx_ { * 32 bits. */ uint32_t (*search)(const struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, - PatternMatcherQueue *, const uint8_t *, uint16_t); + PrefilterRuleStore *, const uint8_t *, uint16_t); /* Convert input character to matching alphabet */ uint8_t translate_table[256]; diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 70142fed4121..45d537258652 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -79,7 +79,7 @@ int SCACAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int SCACPreparePatterns(MpmCtx *mpm_ctx); uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen); + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); void SCACPrintInfo(MpmCtx *mpm_ctx); void SCACPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACRegisterTests(void); @@ -1027,7 +1027,7 @@ void SCACDestroyCtx(MpmCtx *mpm_ctx) * \retval matches Match count. */ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, const uint8_t *buf, uint16_t buflen) + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen) { const SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; int i = 0; @@ -1063,7 +1063,8 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); + PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1071,7 +1072,8 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); + PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1103,7 +1105,8 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); + PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1111,7 +1114,8 @@ uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, ; } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); + PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1546,7 +1550,7 @@ static void *SCACCudaDispatcher(void *arg) } uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, - PatternMatcherQueue *pmq) + PrefilterRuleStore *pmq) { uint32_t u = 0; @@ -1603,7 +1607,8 @@ uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, ; } else { bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - MpmAddSids(pmq, pid_pat_list[lower_pid].sids, pid_pat_list[lower_pid].sids_size); + PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { @@ -1611,7 +1616,8 @@ uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, ; } else { bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - MpmAddSids(pmq, pid_pat_list[pids[k]].sids, pid_pat_list[pids[k]].sids_size); + PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1808,7 +1814,7 @@ static int SCACTest01(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1842,7 +1848,7 @@ static int SCACTest02(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1875,7 +1881,7 @@ static int SCACTest03(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1912,7 +1918,7 @@ static int SCACTest04(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1946,7 +1952,7 @@ static int SCACTest05(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1980,7 +1986,7 @@ static int SCACTest06(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2012,7 +2018,7 @@ static int SCACTest07(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2057,7 +2063,7 @@ static int SCACTest08(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2089,7 +2095,7 @@ static int SCACTest09(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2121,7 +2127,7 @@ static int SCACTest10(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2158,7 +2164,7 @@ static int SCACTest11(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2205,7 +2211,7 @@ static int SCACTest12(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2240,7 +2246,7 @@ static int SCACTest13(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2274,7 +2280,7 @@ static int SCACTest14(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2308,7 +2314,7 @@ static int SCACTest15(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2342,7 +2348,7 @@ static int SCACTest16(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2376,7 +2382,7 @@ static int SCACTest17(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2410,7 +2416,7 @@ static int SCACTest18(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2444,7 +2450,7 @@ static int SCACTest19(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2478,7 +2484,7 @@ static int SCACTest20(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2512,7 +2518,7 @@ static int SCACTest21(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2544,7 +2550,7 @@ static int SCACTest22(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2579,7 +2585,7 @@ static int SCACTest23(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2611,7 +2617,7 @@ static int SCACTest24(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2643,7 +2649,7 @@ static int SCACTest25(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2677,7 +2683,7 @@ static int SCACTest26(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2710,7 +2716,7 @@ static int SCACTest27(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2743,7 +2749,7 @@ static int SCACTest28(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); diff --git a/src/util-mpm-ac.h b/src/util-mpm-ac.h index 97ae48e8d710..490ebfdfb9a9 100644 --- a/src/util-mpm-ac.h +++ b/src/util-mpm-ac.h @@ -188,7 +188,7 @@ int MpmCudaBufferDeSetup(void); void SCACCudaStartDispatcher(void); void SCACCudaKillDispatcher(void); uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, - PatternMatcherQueue *pmq); + PrefilterRuleStore *pmq); void DetermineCudaStateTableSize(DetectEngineCtx *de_ctx); void CudaReleasePacket(Packet *p); diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index e0153a4748cb..61224d743ceb 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -56,7 +56,7 @@ int SCHSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int SCHSPreparePatterns(MpmCtx *mpm_ctx); uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, const uint8_t *buf, const uint16_t buflen); + PrefilterRuleStore *pmq, const uint8_t *buf, const uint16_t buflen); void SCHSPrintInfo(MpmCtx *mpm_ctx); void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCHSRegisterTests(void); @@ -885,7 +885,7 @@ static int SCHSMatchEvent(unsigned int id, unsigned long long from, void *ctx) { SCHSCallbackCtx *cctx = ctx; - PatternMatcherQueue *pmq = cctx->pmq; + PrefilterRuleStore *pmq = cctx->pmq; const PatternDatabase *pd = cctx->ctx->pattern_db; const SCHSPattern *pat = pd->parray[id]; @@ -893,7 +893,7 @@ static int SCHSMatchEvent(unsigned int id, unsigned long long from, " (pat id=%" PRIu32 ")", cctx->match_count, (uint32_t)id, (uintmax_t)to, pat->id); - MpmAddSids(pmq, pat->sids, pat->sids_size); + PrefilterAddSids(pmq, pat->sids, pat->sids_size); cctx->match_count++; return 0; @@ -912,7 +912,7 @@ static int SCHSMatchEvent(unsigned int id, unsigned long long from, * \retval matches Match count. */ uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, const uint8_t *buf, const uint16_t buflen) + PrefilterRuleStore *pmq, const uint8_t *buf, const uint16_t buflen) { uint32_t ret = 0; SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; @@ -1086,7 +1086,7 @@ static int SCHSTest01(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1120,7 +1120,7 @@ static int SCHSTest02(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1153,7 +1153,7 @@ static int SCHSTest03(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1190,7 +1190,7 @@ static int SCHSTest04(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1224,7 +1224,7 @@ static int SCHSTest05(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1258,7 +1258,7 @@ static int SCHSTest06(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1290,7 +1290,7 @@ static int SCHSTest07(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1334,7 +1334,7 @@ static int SCHSTest08(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1366,7 +1366,7 @@ static int SCHSTest09(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1398,7 +1398,7 @@ static int SCHSTest10(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1435,7 +1435,7 @@ static int SCHSTest11(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1483,7 +1483,7 @@ static int SCHSTest12(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1518,7 +1518,7 @@ static int SCHSTest13(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1552,7 +1552,7 @@ static int SCHSTest14(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1586,7 +1586,7 @@ static int SCHSTest15(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1620,7 +1620,7 @@ static int SCHSTest16(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1654,7 +1654,7 @@ static int SCHSTest17(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1688,7 +1688,7 @@ static int SCHSTest18(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1732,7 +1732,7 @@ static int SCHSTest19(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1766,7 +1766,7 @@ static int SCHSTest20(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1812,7 +1812,7 @@ static int SCHSTest21(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1844,7 +1844,7 @@ static int SCHSTest22(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1879,7 +1879,7 @@ static int SCHSTest23(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1911,7 +1911,7 @@ static int SCHSTest24(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1943,7 +1943,7 @@ static int SCHSTest25(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1977,7 +1977,7 @@ static int SCHSTest26(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2010,7 +2010,7 @@ static int SCHSTest27(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -2043,7 +2043,7 @@ static int SCHSTest28(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); diff --git a/src/util-mpm.c b/src/util-mpm.c index af2ecffc4a13..b4e728ba8b33 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -391,112 +391,6 @@ void MpmCudaEnvironmentSetup() #endif -/** - * \brief Setup a pmq - * - * \param pmq Pattern matcher queue to be initialized - * - * \retval -1 error - * \retval 0 ok - */ -int PmqSetup(PatternMatcherQueue *pmq) -{ - SCEnter(); - - if (pmq == NULL) { - SCReturnInt(-1); - } - - memset(pmq, 0, sizeof(PatternMatcherQueue)); - - pmq->rule_id_array_size = 128; /* Initial size, TODO: Make configure option. */ - pmq->rule_id_array_cnt = 0; - - size_t bytes = pmq->rule_id_array_size * sizeof(SigIntId); - pmq->rule_id_array = (SigIntId*)SCMalloc(bytes); - if (pmq->rule_id_array == NULL) { - pmq->rule_id_array_size = 0; - SCReturnInt(-1); - } - // Don't need to zero memory since it is always written first. - - SCReturnInt(0); -} - -/** \brief Add array of Signature IDs to rule ID array. - * - * Checks size of the array first - * - * \param pmq storage for match results - * \param new_size number of Signature IDs needing to be stored. - * - */ -int -MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size) -{ - /* Need to make the array bigger. Double the size needed to - * also handle the case that sids_size might still be - * larger than the old size. - */ - new_size = new_size * 2; - SigIntId *new_array = (SigIntId*)SCRealloc(pmq->rule_id_array, - new_size * sizeof(SigIntId)); - if (unlikely(new_array == NULL)) { - /* Try again just big enough. */ - new_size = new_size / 2; - new_array = (SigIntId*)SCRealloc(pmq->rule_id_array, - new_size * sizeof(SigIntId)); - if (unlikely(new_array == NULL)) { - - SCLogError(SC_ERR_MEM_ALLOC, "Failed to realloc PatternMatchQueue" - " rule ID array. Some signature ID matches lost"); - return 0; - } - } - pmq->rule_id_array = new_array; - pmq->rule_id_array_size = new_size; - - return new_size; -} - -/** \brief Reset a Pmq for reusage. Meant to be called after a single search. - * \param pmq Pattern matcher to be reset. - * \todo memset is expensive, but we need it as we merge pmq's. We might use - * a flag so we can clear pmq's the old way if we can. - */ -void PmqReset(PatternMatcherQueue *pmq) -{ - if (pmq == NULL) - return; - - pmq->rule_id_array_cnt = 0; - /* TODO: Realloc the rule id array smaller at some size? */ -} - -/** \brief Cleanup a Pmq - * \param pmq Pattern matcher queue to be cleaned up. - */ -void PmqCleanup(PatternMatcherQueue *pmq) -{ - if (pmq == NULL) - return; - if (pmq->rule_id_array != NULL) { - SCFree(pmq->rule_id_array); - pmq->rule_id_array = NULL; - } -} - -/** \brief Cleanup and free a Pmq - * \param pmq Pattern matcher queue to be free'd. - */ -void PmqFree(PatternMatcherQueue *pmq) -{ - if (pmq == NULL) - return; - - PmqCleanup(pmq); -} - void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher) { mpm_table[matcher].InitThreadCtx(NULL, mpm_thread_ctx); diff --git a/src/util-mpm.h b/src/util-mpm.h index 60634c45ef49..fe161c12c163 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -23,8 +23,8 @@ #ifndef __UTIL_MPM_H__ #define __UTIL_MPM_H__ -#include "suricata-common.h" +#include "util-prefilter.h" #define MPM_INIT_HASH_SIZE 65536 @@ -66,21 +66,6 @@ typedef struct MpmThreadCtx_ { } MpmThreadCtx; -/** \brief helper structure for the pattern matcher engine. The Pattern Matcher - * thread has this and passes a pointer to it to the pattern matcher. - * The actual pattern matcher will fill the structure. */ -typedef struct PatternMatcherQueue_ { - /* used for storing rule id's */ - - /* Array of rule IDs found. */ - SigIntId *rule_id_array; - /* Number of rule IDs in the array. */ - uint32_t rule_id_array_cnt; - /* The number of slots allocated for storing rule IDs */ - uint32_t rule_id_array_size; - -} PatternMatcherQueue; - typedef struct MpmPattern_ { /* length of the pattern */ uint16_t len; @@ -178,7 +163,7 @@ typedef struct MpmTableElmt_ { int (*AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int (*AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int (*Prepare)(struct MpmCtx_ *); - uint32_t (*Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, const uint8_t *, uint16_t); + uint32_t (*Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint16_t); void (*PrintCtx)(struct MpmCtx_ *); void (*PrintThreadCtx)(struct MpmThreadCtx_ *); void (*RegisterUnittests)(void); @@ -231,10 +216,10 @@ MpmCtx *MpmFactoryGetMpmCtxForProfile(const struct DetectEngineCtx_ *, int32_t, void MpmFactoryDeRegisterAllMpmCtxProfiles(struct DetectEngineCtx_ *); int32_t MpmFactoryIsMpmCtxAvailable(const struct DetectEngineCtx_ *, const MpmCtx *); -int PmqSetup(PatternMatcherQueue *); -void PmqReset(PatternMatcherQueue *); -void PmqCleanup(PatternMatcherQueue *); -void PmqFree(PatternMatcherQueue *); +int PmqSetup(PrefilterRuleStore *); +void PmqReset(PrefilterRuleStore *); +void PmqCleanup(PrefilterRuleStore *); +void PmqFree(PrefilterRuleStore *); void MpmTableSetup(void); void MpmRegisterTests(void); @@ -255,40 +240,4 @@ int MpmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags); -/* Resize Signature ID array. Only called from MpmAddSids(). */ -int MpmAddSidsResize(PatternMatcherQueue *pmq, uint32_t new_size); - -/** \brief Add array of Signature IDs to rule ID array. - * - * Checks size of the array first. Calls MpmAddSidsResize to increase - * The size of the array, since that is the slow path. - * - * \param pmq storage for match results - * \param sids pointer to array of Signature IDs - * \param sids_size number of Signature IDs in sids array. - * - */ -static inline void -MpmAddSids(PatternMatcherQueue *pmq, SigIntId *sids, uint32_t sids_size) -{ - if (sids_size == 0) - return; - - uint32_t new_size = pmq->rule_id_array_cnt + sids_size; - if (new_size > pmq->rule_id_array_size) { - if (MpmAddSidsResize(pmq, new_size) == 0) { - // Failed to allocate larger memory for all the SIDS, but - // keep as many as we can. - sids_size = pmq->rule_id_array_size - pmq->rule_id_array_cnt; - } - } - SCLogDebug("Adding %u sids", sids_size); - // Add SIDs for this pattern to the end of the array - SigIntId *ptr = pmq->rule_id_array + pmq->rule_id_array_cnt; - SigIntId *end = ptr + sids_size; - do { - *ptr++ = *sids++; - } while (ptr != end); - pmq->rule_id_array_cnt += sids_size; -} #endif /* __UTIL_MPM_H__ */ diff --git a/src/util-prefilter.c b/src/util-prefilter.c new file mode 100644 index 000000000000..406cee6bfb0b --- /dev/null +++ b/src/util-prefilter.c @@ -0,0 +1,132 @@ +/* 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 + * + * Pattern matcher utility Functions + */ + +#include "suricata-common.h" + +/** + * \brief Setup a pmq + * + * \param pmq Pattern matcher queue to be initialized + * + * \retval -1 error + * \retval 0 ok + */ +int PmqSetup(PrefilterRuleStore *pmq) +{ + SCEnter(); + + if (pmq == NULL) { + SCReturnInt(-1); + } + + memset(pmq, 0, sizeof(PrefilterRuleStore)); + + pmq->rule_id_array_size = 128; /* Initial size, TODO: Make configure option. */ + pmq->rule_id_array_cnt = 0; + + size_t bytes = pmq->rule_id_array_size * sizeof(SigIntId); + pmq->rule_id_array = (SigIntId*)SCMalloc(bytes); + if (pmq->rule_id_array == NULL) { + pmq->rule_id_array_size = 0; + SCReturnInt(-1); + } + // Don't need to zero memory since it is always written first. + + SCReturnInt(0); +} + +/** \brief Add array of Signature IDs to rule ID array. + * + * Checks size of the array first + * + * \param pmq storage for match results + * \param new_size number of Signature IDs needing to be stored. + * + */ +int +PrefilterAddSidsResize(PrefilterRuleStore *pmq, uint32_t new_size) +{ + /* Need to make the array bigger. Double the size needed to + * also handle the case that sids_size might still be + * larger than the old size. + */ + new_size = new_size * 2; + SigIntId *new_array = (SigIntId*)SCRealloc(pmq->rule_id_array, + new_size * sizeof(SigIntId)); + if (unlikely(new_array == NULL)) { + /* Try again just big enough. */ + new_size = new_size / 2; + new_array = (SigIntId*)SCRealloc(pmq->rule_id_array, + new_size * sizeof(SigIntId)); + if (unlikely(new_array == NULL)) { + + SCLogError(SC_ERR_MEM_ALLOC, "Failed to realloc PatternMatchQueue" + " rule ID array. Some signature ID matches lost"); + return 0; + } + } + pmq->rule_id_array = new_array; + pmq->rule_id_array_size = new_size; + + return new_size; +} + +/** \brief Reset a Pmq for reusage. Meant to be called after a single search. + * \param pmq Pattern matcher to be reset. + * \todo memset is expensive, but we need it as we merge pmq's. We might use + * a flag so we can clear pmq's the old way if we can. + */ +void PmqReset(PrefilterRuleStore *pmq) +{ + if (pmq == NULL) + return; + + pmq->rule_id_array_cnt = 0; + /* TODO: Realloc the rule id array smaller at some size? */ +} + +/** \brief Cleanup a Pmq + * \param pmq Pattern matcher queue to be cleaned up. + */ +void PmqCleanup(PrefilterRuleStore *pmq) +{ + if (pmq == NULL) + return; + if (pmq->rule_id_array != NULL) { + SCFree(pmq->rule_id_array); + pmq->rule_id_array = NULL; + } +} + +/** \brief Cleanup and free a Pmq + * \param pmq Pattern matcher queue to be free'd. + */ +void PmqFree(PrefilterRuleStore *pmq) +{ + if (pmq == NULL) + return; + + PmqCleanup(pmq); +} diff --git a/src/util-prefilter.h b/src/util-prefilter.h new file mode 100644 index 000000000000..1106795d3d31 --- /dev/null +++ b/src/util-prefilter.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2016 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 + */ + +#ifndef __UTIL_PREFILTER_H__ +#define __UTIL_PREFILTER_H__ + +/** \brief structure for storing potential rule matches + * + * Helper structure for the prefilter engine. The Pattern Matchers + * and other prefilter engines will add rule id's for potential + * rule matches */ +typedef struct PrefilterRuleStore_ { + /* used for storing rule id's */ + + /* Array of rule IDs found. */ + SigIntId *rule_id_array; + /* Number of rule IDs in the array. */ + uint32_t rule_id_array_cnt; + /* The number of slots allocated for storing rule IDs */ + uint32_t rule_id_array_size; + +} PrefilterRuleStore; + +/* Resize Signature ID array. Only called from MpmAddSids(). */ +int PrefilterAddSidsResize(PrefilterRuleStore *pmq, uint32_t new_size); + +/** \brief Add array of Signature IDs to rule ID array. + * + * Checks size of the array first. Calls PrefilterAddSidsResize to increase + * The size of the array, since that is the slow path. + * + * \param pmq storage for match results + * \param sids pointer to array of Signature IDs + * \param sids_size number of Signature IDs in sids array. + * + */ +static inline void +PrefilterAddSids(PrefilterRuleStore *pmq, SigIntId *sids, uint32_t sids_size) +{ + if (sids_size == 0) + return; + + uint32_t new_size = pmq->rule_id_array_cnt + sids_size; + if (new_size > pmq->rule_id_array_size) { + if (PrefilterAddSidsResize(pmq, new_size) == 0) { + // Failed to allocate larger memory for all the SIDS, but + // keep as many as we can. + sids_size = pmq->rule_id_array_size - pmq->rule_id_array_cnt; + } + } + SCLogDebug("Adding %u sids", sids_size); + // Add SIDs for this pattern to the end of the array + SigIntId *ptr = pmq->rule_id_array + pmq->rule_id_array_cnt; + SigIntId *end = ptr + sids_size; + do { + *ptr++ = *sids++; + } while (ptr != end); + pmq->rule_id_array_cnt += sids_size; +} +#endif /* __UTIL_PREFILTER_H__ */ From 17bc0299fe1eb4305d0bcea05399eccaa5b13b6d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 Jul 2016 13:37:34 +0200 Subject: [PATCH 1883/2553] detect: rename non_mpm lists/vars to non_pf Rename to non_pf: non prefilter. --- src/detect-engine-siggroup.c | 80 ++++++++++++++++----------------- src/detect-engine-siggroup.h | 2 +- src/detect-engine.c | 12 ++--- src/detect.c | 50 +++++++++++---------- src/detect.h | 20 ++++----- src/util-profiling-rulegroups.c | 4 +- 6 files changed, 85 insertions(+), 83 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 22019a3d3625..b021a8977367 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -151,16 +151,16 @@ void SigGroupHeadFree(SigGroupHead *sgh) sgh->match_array = NULL; } - if (sgh->non_mpm_other_store_array != NULL) { - SCFree(sgh->non_mpm_other_store_array); - sgh->non_mpm_other_store_array = NULL; - sgh->non_mpm_other_store_cnt = 0; + if (sgh->non_pf_other_store_array != NULL) { + SCFree(sgh->non_pf_other_store_array); + sgh->non_pf_other_store_array = NULL; + sgh->non_pf_other_store_cnt = 0; } - if (sgh->non_mpm_syn_store_array != NULL) { - SCFree(sgh->non_mpm_syn_store_array); - sgh->non_mpm_syn_store_array = NULL; - sgh->non_mpm_syn_store_cnt = 0; + if (sgh->non_pf_syn_store_array != NULL) { + SCFree(sgh->non_pf_syn_store_array); + sgh->non_pf_syn_store_array = NULL; + sgh->non_pf_syn_store_cnt = 0; } sgh->sig_cnt = 0; @@ -675,20 +675,20 @@ void SigGroupHeadSetFilestoreCount(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return; } -/** \brief build an array of rule id's for sigs with no mpm - * Also updated de_ctx::non_mpm_store_cnt_max to track the highest cnt +/** \brief build an array of rule id's for sigs with no prefilter + * Also updated de_ctx::non_pf_store_cnt_max to track the highest cnt */ -int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; uint32_t sig = 0; - uint32_t non_mpm = 0; - uint32_t non_mpm_syn = 0; + uint32_t non_pf = 0; + uint32_t non_pf_syn = 0; if (sgh == NULL) return 0; - BUG_ON(sgh->non_mpm_other_store_array != NULL); + BUG_ON(sgh->non_pf_other_store_array != NULL); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; @@ -697,28 +697,28 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) if (s->mpm_sm == NULL || (s->flags & SIG_FLAG_MPM_NEG)) { if (!(DetectFlagsSignatureNeedsSynPackets(s))) { - non_mpm++; + non_pf++; } - non_mpm_syn++; + non_pf_syn++; } } - if (non_mpm == 0 && non_mpm_syn == 0) { - sgh->non_mpm_other_store_array = NULL; - sgh->non_mpm_syn_store_array = NULL; + if (non_pf == 0 && non_pf_syn == 0) { + sgh->non_pf_other_store_array = NULL; + sgh->non_pf_syn_store_array = NULL; return 0; } - if (non_mpm > 0) { - sgh->non_mpm_other_store_array = SCMalloc(non_mpm * sizeof(SignatureNonMpmStore)); - BUG_ON(sgh->non_mpm_other_store_array == NULL); - memset(sgh->non_mpm_other_store_array, 0, non_mpm * sizeof(SignatureNonMpmStore)); + if (non_pf > 0) { + sgh->non_pf_other_store_array = SCMalloc(non_pf * sizeof(SignatureNonMpmStore)); + BUG_ON(sgh->non_pf_other_store_array == NULL); + memset(sgh->non_pf_other_store_array, 0, non_pf * sizeof(SignatureNonMpmStore)); } - if (non_mpm_syn > 0) { - sgh->non_mpm_syn_store_array = SCMalloc(non_mpm_syn * sizeof(SignatureNonMpmStore)); - BUG_ON(sgh->non_mpm_syn_store_array == NULL); - memset(sgh->non_mpm_syn_store_array, 0, non_mpm_syn * sizeof(SignatureNonMpmStore)); + if (non_pf_syn > 0) { + sgh->non_pf_syn_store_array = SCMalloc(non_pf_syn * sizeof(SignatureNonMpmStore)); + BUG_ON(sgh->non_pf_syn_store_array == NULL); + memset(sgh->non_pf_syn_store_array, 0, non_pf_syn * sizeof(SignatureNonMpmStore)); } for (sig = 0; sig < sgh->sig_cnt; sig++) { @@ -728,25 +728,25 @@ int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) if (s->mpm_sm == NULL || (s->flags & SIG_FLAG_MPM_NEG)) { if (!(DetectFlagsSignatureNeedsSynPackets(s))) { - BUG_ON(sgh->non_mpm_other_store_cnt >= non_mpm); - BUG_ON(sgh->non_mpm_other_store_array == NULL); - sgh->non_mpm_other_store_array[sgh->non_mpm_other_store_cnt].id = s->num; - sgh->non_mpm_other_store_array[sgh->non_mpm_other_store_cnt].mask = s->mask; - sgh->non_mpm_other_store_cnt++; + BUG_ON(sgh->non_pf_other_store_cnt >= non_pf); + BUG_ON(sgh->non_pf_other_store_array == NULL); + sgh->non_pf_other_store_array[sgh->non_pf_other_store_cnt].id = s->num; + sgh->non_pf_other_store_array[sgh->non_pf_other_store_cnt].mask = s->mask; + sgh->non_pf_other_store_cnt++; } - BUG_ON(sgh->non_mpm_syn_store_cnt >= non_mpm_syn); - BUG_ON(sgh->non_mpm_syn_store_array == NULL); - sgh->non_mpm_syn_store_array[sgh->non_mpm_syn_store_cnt].id = s->num; - sgh->non_mpm_syn_store_array[sgh->non_mpm_syn_store_cnt].mask = s->mask; - sgh->non_mpm_syn_store_cnt++; + BUG_ON(sgh->non_pf_syn_store_cnt >= non_pf_syn); + BUG_ON(sgh->non_pf_syn_store_array == NULL); + sgh->non_pf_syn_store_array[sgh->non_pf_syn_store_cnt].id = s->num; + sgh->non_pf_syn_store_array[sgh->non_pf_syn_store_cnt].mask = s->mask; + sgh->non_pf_syn_store_cnt++; } } /* track highest cnt for any sgh in our de_ctx */ - uint32_t max = MAX(sgh->non_mpm_other_store_cnt, sgh->non_mpm_syn_store_cnt); - if (max > de_ctx->non_mpm_store_cnt_max) - de_ctx->non_mpm_store_cnt_max = max; + uint32_t max = MAX(sgh->non_pf_other_store_cnt, sgh->non_pf_syn_store_cnt); + if (max > de_ctx->non_pf_store_cnt_max) + de_ctx->non_pf_store_cnt_max = max; return 0; } diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index b8dd6b1c9fc3..a5b24808267a 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -72,6 +72,6 @@ void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *, SigGroupHead *); uint16_t SigGroupHeadGetMinMpmSize(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int list); -int SigGroupHeadBuildNonMpmArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh); +int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh); #endif /* __DETECT_ENGINE_SIGGROUP_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 638ebf070277..f734abb975ea 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1526,10 +1526,10 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * } /* sized to the max of our sgh settings. A max setting of 0 implies that all - * sgh's have: sgh->non_mpm_store_cnt == 0 */ - if (de_ctx->non_mpm_store_cnt_max > 0) { - det_ctx->non_mpm_id_array = SCCalloc(de_ctx->non_mpm_store_cnt_max, sizeof(SigIntId)); - BUG_ON(det_ctx->non_mpm_id_array == NULL); + * sgh's have: sgh->non_pf_store_cnt == 0 */ + if (de_ctx->non_pf_store_cnt_max > 0) { + det_ctx->non_pf_id_array = SCCalloc(de_ctx->non_pf_store_cnt_max, sizeof(SigIntId)); + BUG_ON(det_ctx->non_pf_id_array == NULL); } /* IP-ONLY */ @@ -1744,8 +1744,8 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) SpmDestroyThreadCtx(det_ctx->spm_thread_ctx); } - if (det_ctx->non_mpm_id_array != NULL) - SCFree(det_ctx->non_mpm_id_array); + if (det_ctx->non_pf_id_array != NULL) + SCFree(det_ctx->non_pf_id_array); if (det_ctx->de_state_sig_array != NULL) SCFree(det_ctx->de_state_sig_array); diff --git a/src/detect.c b/src/detect.c index 3ce90ff6f4ca..3d78875d4461 100644 --- a/src/detect.c +++ b/src/detect.c @@ -705,9 +705,9 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, SigIntId mpm, nonmpm; det_ctx->match_array_cnt = 0; SigIntId *mpm_ptr = det_ctx->pmq.rule_id_array; - SigIntId *nonmpm_ptr = det_ctx->non_mpm_id_array; + SigIntId *nonmpm_ptr = det_ctx->non_pf_id_array; uint32_t m_cnt = det_ctx->pmq.rule_id_array_cnt; - uint32_t n_cnt = det_ctx->non_mpm_id_cnt; + uint32_t n_cnt = det_ctx->non_pf_id_cnt; SigIntId *final_ptr; uint32_t final_cnt; SigIntId id; @@ -820,7 +820,7 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, det_ctx->match_array_cnt = match_array - det_ctx->match_array; - BUG_ON((det_ctx->pmq.rule_id_array_cnt + det_ctx->non_mpm_id_cnt) < det_ctx->match_array_cnt); + BUG_ON((det_ctx->pmq.rule_id_array_cnt + det_ctx->non_pf_id_cnt) < det_ctx->match_array_cnt); } /* Return true is the list is sorted smallest to largest */ @@ -1227,15 +1227,16 @@ static void AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(Packet *p, DetectEn return; } -static inline void DetectPrefilterBuildNonMpmList(DetectEngineThreadCtx *det_ctx, SignatureMask mask) +static inline void +DetectPrefilterBuildNonPrefilterList(DetectEngineThreadCtx *det_ctx, SignatureMask mask) { uint32_t x = 0; - for (x = 0; x < det_ctx->non_mpm_store_cnt; x++) { + for (x = 0; x < det_ctx->non_pf_store_cnt; x++) { /* only if the mask matches this rule can possibly match, * so build the non_mpm array only for match candidates */ - SignatureMask rule_mask = det_ctx->non_mpm_store_ptr[x].mask; + SignatureMask rule_mask = det_ctx->non_pf_store_ptr[x].mask; if ((rule_mask & mask) == rule_mask) { - det_ctx->non_mpm_id_array[det_ctx->non_mpm_id_cnt++] = det_ctx->non_mpm_store_ptr[x].id; + det_ctx->non_pf_id_array[det_ctx->non_pf_id_cnt++] = det_ctx->non_pf_store_ptr[x].id; } } } @@ -1243,19 +1244,20 @@ static inline void DetectPrefilterBuildNonMpmList(DetectEngineThreadCtx *det_ctx /** \internal * \brief select non-mpm list * Based on the packet properties, select the non-mpm list to use */ -static inline void DetectPrefilterSetNonMpmList(const Packet *p, DetectEngineThreadCtx *det_ctx) +static inline void +DetectPrefilterSetNonPrefilterList(const Packet *p, DetectEngineThreadCtx *det_ctx) { if ((p->proto == IPPROTO_TCP) && (p->tcph != NULL) && (p->tcph->th_flags & TH_SYN)) { - det_ctx->non_mpm_store_ptr = det_ctx->sgh->non_mpm_syn_store_array; - det_ctx->non_mpm_store_cnt = det_ctx->sgh->non_mpm_syn_store_cnt; + det_ctx->non_pf_store_ptr = det_ctx->sgh->non_pf_syn_store_array; + det_ctx->non_pf_store_cnt = det_ctx->sgh->non_pf_syn_store_cnt; } else { - det_ctx->non_mpm_store_ptr = det_ctx->sgh->non_mpm_other_store_array; - det_ctx->non_mpm_store_cnt = det_ctx->sgh->non_mpm_other_store_cnt; + det_ctx->non_pf_store_ptr = det_ctx->sgh->non_pf_other_store_array; + det_ctx->non_pf_store_cnt = det_ctx->sgh->non_pf_other_store_cnt; } - SCLogDebug("sgh non_mpm ptr %p cnt %u (syn %p/%u, other %p/%u)", - det_ctx->non_mpm_store_ptr, det_ctx->non_mpm_store_cnt, - det_ctx->sgh->non_mpm_syn_store_array, det_ctx->sgh->non_mpm_syn_store_cnt, - det_ctx->sgh->non_mpm_other_store_array, det_ctx->sgh->non_mpm_other_store_cnt); + SCLogDebug("sgh non_pf ptr %p cnt %u (syn %p/%u, other %p/%u)", + det_ctx->non_pf_store_ptr, det_ctx->non_pf_store_cnt, + det_ctx->sgh->non_pf_syn_store_array, det_ctx->sgh->non_pf_syn_store_cnt, + det_ctx->sgh->non_pf_other_store_array, det_ctx->sgh->non_pf_other_store_cnt); } /** @@ -1459,7 +1461,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh goto end; } - DetectPrefilterSetNonMpmList(p, det_ctx); + DetectPrefilterSetNonPrefilterList(p, det_ctx); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); /* stateful app layer detection */ @@ -1481,11 +1483,11 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SignatureMask mask = 0; PacketCreateMask(p, &mask, alproto, has_state, smsg, app_decoder_events); - /* build and prefilter non_mpm list against the mask of the packet */ + /* build and prefilter non_pf list against the mask of the packet */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_NONMPMLIST); - det_ctx->non_mpm_id_cnt = 0; - if (likely(det_ctx->non_mpm_store_cnt > 0)) { - DetectPrefilterBuildNonMpmList(det_ctx, mask); + det_ctx->non_pf_id_cnt = 0; + if (likely(det_ctx->non_pf_store_cnt > 0)) { + DetectPrefilterBuildNonPrefilterList(det_ctx, mask); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_NONMPMLIST); @@ -1498,10 +1500,10 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh StatsAddUI64(th_v, det_ctx->counter_mpm_list, (uint64_t)det_ctx->pmq.rule_id_array_cnt); StatsAddUI64(th_v, det_ctx->counter_nonmpm_list, - (uint64_t)det_ctx->non_mpm_store_cnt); + (uint64_t)det_ctx->non_pf_store_cnt); /* non mpm sigs after mask prefilter */ StatsAddUI64(th_v, det_ctx->counter_fnonmpm_list, - (uint64_t)det_ctx->non_mpm_id_cnt); + (uint64_t)det_ctx->non_pf_id_cnt); } #endif @@ -4067,7 +4069,7 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SCLogDebug("filestore count %u", sgh->filestore_cnt); BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); - SigGroupHeadBuildNonMpmArray(de_ctx, sgh); + SigGroupHeadBuildNonPrefilterArray(de_ctx, sgh); sgh->id = idx; cnt++; diff --git a/src/detect.h b/src/detect.h index 014a1c1acf51..70b924e386a8 100644 --- a/src/detect.h +++ b/src/detect.h @@ -565,7 +565,7 @@ typedef struct DetectEngineCtx_ { /** Maximum value of all our sgh's non_mpm_store_cnt setting, * used to alloc det_ctx::non_mpm_id_array */ - uint32_t non_mpm_store_cnt_max; + uint32_t non_pf_store_cnt_max; /* used by the signature ordering module */ struct SCSigOrderFunc_ *sc_sig_order_funcs; @@ -737,8 +737,8 @@ typedef struct DetectEngineThreadCtx_ { /* the thread to which this detection engine thread belongs */ ThreadVars *tv; - SigIntId *non_mpm_id_array; - uint32_t non_mpm_id_cnt; // size is cnt * sizeof(uint32_t) + 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; @@ -823,8 +823,8 @@ typedef struct DetectEngineThreadCtx_ { struct SigGroupHead_ *sgh; - SignatureNonMpmStore *non_mpm_store_ptr; - uint32_t non_mpm_store_cnt; + SignatureNonMpmStore *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 @@ -997,12 +997,12 @@ typedef struct SigGroupHead_ { /* number of sigs in this head */ SigIntId sig_cnt; - /* non mpm list excluding SYN rules */ - uint32_t non_mpm_other_store_cnt; - uint32_t non_mpm_syn_store_cnt; - SignatureNonMpmStore *non_mpm_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) + /* non prefilter list excluding SYN rules */ + uint32_t non_pf_other_store_cnt; + uint32_t non_pf_syn_store_cnt; + SignatureNonMpmStore *non_pf_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) /* non mpm list including SYN rules */ - SignatureNonMpmStore *non_mpm_syn_store_array; // size is non_mpm_syn_store_cnt * sizeof(SignatureNonMpmStore) + SignatureNonMpmStore *non_pf_syn_store_array; // size is non_mpm_syn_store_cnt * sizeof(SignatureNonMpmStore) /** the number of signatures in this sgh that have the filestore keyword * set. */ diff --git a/src/util-profiling-rulegroups.c b/src/util-profiling-rulegroups.c index 8f55e717fbf1..1bbf4f7961f1 100644 --- a/src/util-profiling-rulegroups.c +++ b/src/util-profiling-rulegroups.c @@ -286,8 +286,8 @@ SCProfilingSghUpdateCounter(DetectEngineThreadCtx *det_ctx, const SigGroupHead * SCProfileSghData *p = &det_ctx->sgh_perf_data[sgh->id]; p->checks++; - if (det_ctx->non_mpm_store_cnt > 0) { - if (det_ctx->non_mpm_store_ptr == sgh->non_mpm_syn_store_array) + if (det_ctx->non_pf_store_cnt > 0) { + if (det_ctx->non_pf_store_ptr == sgh->non_pf_syn_store_array) p->non_mpm_syn++; else p->non_mpm_generic++; From 3dad824fb2b5501bfac34513c6a9d26cf0265a49 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 Jul 2016 15:02:43 +0200 Subject: [PATCH 1884/2553] detect: rename SignatureNonMpmStore New name is SignatureNonPrefilterStore to reflect that it's not just about MPM anymore. --- src/detect-engine-siggroup.c | 8 ++++---- src/detect.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index b021a8977367..d681ce931b31 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -710,15 +710,15 @@ int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sg } if (non_pf > 0) { - sgh->non_pf_other_store_array = SCMalloc(non_pf * sizeof(SignatureNonMpmStore)); + sgh->non_pf_other_store_array = SCMalloc(non_pf * sizeof(SignatureNonPrefilterStore)); BUG_ON(sgh->non_pf_other_store_array == NULL); - memset(sgh->non_pf_other_store_array, 0, non_pf * sizeof(SignatureNonMpmStore)); + memset(sgh->non_pf_other_store_array, 0, non_pf * sizeof(SignatureNonPrefilterStore)); } if (non_pf_syn > 0) { - sgh->non_pf_syn_store_array = SCMalloc(non_pf_syn * sizeof(SignatureNonMpmStore)); + sgh->non_pf_syn_store_array = SCMalloc(non_pf_syn * sizeof(SignatureNonPrefilterStore)); BUG_ON(sgh->non_pf_syn_store_array == NULL); - memset(sgh->non_pf_syn_store_array, 0, non_pf_syn * sizeof(SignatureNonMpmStore)); + memset(sgh->non_pf_syn_store_array, 0, non_pf_syn * sizeof(SignatureNonPrefilterStore)); } for (sig = 0; sig < sgh->sig_cnt; sig++) { diff --git a/src/detect.h b/src/detect.h index 70b924e386a8..9aa17f280e7a 100644 --- a/src/detect.h +++ b/src/detect.h @@ -721,10 +721,10 @@ typedef struct FiledataReassembledBody_ { #define DETECT_FILESTORE_MAX 15 -typedef struct SignatureNonMpmStore_ { +typedef struct SignatureNonPrefilterStore_ { SigIntId id; SignatureMask mask; -} SignatureNonMpmStore; +} SignatureNonPrefilterStore; /** * Detection engine thread data. @@ -823,7 +823,7 @@ typedef struct DetectEngineThreadCtx_ { struct SigGroupHead_ *sgh; - SignatureNonMpmStore *non_pf_store_ptr; + SignatureNonPrefilterStore *non_pf_store_ptr; uint32_t non_pf_store_cnt; /** pointer to the current mpm ctx that is stored @@ -1000,9 +1000,9 @@ typedef struct SigGroupHead_ { /* non prefilter list excluding SYN rules */ uint32_t non_pf_other_store_cnt; uint32_t non_pf_syn_store_cnt; - SignatureNonMpmStore *non_pf_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonMpmStore) + SignatureNonPrefilterStore *non_pf_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonPrefilterStore) /* non mpm list including SYN rules */ - SignatureNonMpmStore *non_pf_syn_store_array; // size is non_mpm_syn_store_cnt * sizeof(SignatureNonMpmStore) + 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. */ From 5bcdbe39221d5da8b63b9e44b834102c07cb49dd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 6 Jul 2016 21:45:47 +0200 Subject: [PATCH 1885/2553] prefilter: introduce prefilter engines Introduce abstraction layer for prefilter engines. --- src/Makefile.am | 1 + src/detect-engine-prefilter.c | 207 ++++++++++++++++++++++++++++++++++ src/detect-engine-prefilter.h | 42 +++++++ src/detect-engine-siggroup.c | 4 + src/detect.c | 5 + src/detect.h | 28 +++++ 6 files changed, 287 insertions(+) create mode 100644 src/detect-engine-prefilter.c create mode 100644 src/detect-engine-prefilter.h diff --git a/src/Makefile.am b/src/Makefile.am index 9f0f7e64f1dd..24ec6759f2aa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -125,6 +125,7 @@ detect-engine-loader.c detect-engine-loader.h \ detect-engine-mpm.c detect-engine-mpm.h \ detect-engine-payload.c detect-engine-payload.h \ detect-engine-port.c detect-engine-port.h \ +detect-engine-prefilter.c detect-engine-prefilter.h \ detect-engine-proto.c detect-engine-proto.h \ detect-engine-profile.c detect-engine-profile.h \ detect-engine-siggroup.c detect-engine-siggroup.h \ diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c new file mode 100644 index 000000000000..9fb570e42d9a --- /dev/null +++ b/src/detect-engine-prefilter.c @@ -0,0 +1,207 @@ +/* Copyright (C) 2016 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 + * + * Prefilter engine + * + * Prefilter engines have as purpose to check for a critical common part of + * a set of rules. If the condition is present in the traffic, the rules + * will have to be inspected individually. Otherwise, the rules can be + * skipped. + * + * The best example of this is the MPM. From each rule take a pattern and + * add it to the MPM state machine. Inspect that in one step and only + * individually inspect the rules that had a match in MPM. + * + * This prefilter API is designed to abstract this logic so that it becomes + * easier to add other types of prefilters. + * + * The prefilter engines are structured as a simple list of engines. Each + * engine checks for a condition using it's callback function and private + * data. It then adds the rule match candidates to the PrefilterRuleStore + * structure. + * + * After the engines have run the resulting list of match candidates is + * sorted by the rule id's so that the individual inspection happens in + * the correct order. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "detect-engine-prefilter.h" + +#include "app-layer-parser.h" +#include "app-layer-htp.h" + +static inline void PrefilterTx(DetectEngineThreadCtx *det_ctx, + const SigGroupHead *sgh, Packet *p, const uint8_t flags) +{ + SCEnter(); + + const AppProto alproto = p->flow->alproto; + const uint8_t ipproto = p->proto; + + if (!(AppLayerParserProtocolIsTxAware(ipproto, alproto))) + SCReturn; + + void *alstate = p->flow->alstate; + uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); + const uint64_t total_txs = AppLayerParserGetTxCnt(ipproto, alproto, alstate); + + /* HACK test HTTP state here instead of in each engine */ + if (alproto == ALPROTO_HTTP) { + HtpState *htp_state = (HtpState *)alstate; + if (unlikely(htp_state->connp == NULL)) { + SCLogDebug("no HTTP connp"); + SCReturn; + } + } + + /* run our engines against each tx */ + for (; idx < total_txs; idx++) { + void *tx = AppLayerParserGetTx(ipproto, alproto, alstate, idx); + if (tx == NULL) + continue; + + const int tx_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags); + SCLogDebug("tx %p progress %d", tx, tx_progress); + + PrefilterEngine *engine = sgh->tx_engines; + do { + if (engine->alproto != alproto) + goto next; + if (engine->tx_min_progress > tx_progress) + goto next; + + engine->PrefilterTx(det_ctx, engine->pectx, + p, p->flow, tx, idx, flags); + next: + engine = engine->next; + } while (engine); + } +} + +void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, + Packet *p, const uint8_t flags, int has_state) +{ + SCEnter(); + + /* run packet engines */ + PrefilterEngine *engine = sgh->engines; + while (engine) { + engine->Prefilter(det_ctx, p, engine->pectx); + engine = engine->next; + } + + /* run tx engines */ + if (((p->proto == IPPROTO_TCP && p->flowflags & FLOW_PKT_ESTABLISHED) || p->proto != IPPROTO_TCP) && has_state) { + if (sgh->tx_engines != NULL && p->flow != NULL && + p->flow->alproto != ALPROTO_UNKNOWN && p->flow->alstate != NULL) + { + PrefilterTx(det_ctx, sgh, p, flags); + } + } +} + +int PrefilterAppendEngine(SigGroupHead *sgh, + void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), + void *pectx, void (*FreeFunc)(void *pectx)) +{ + if (sgh == NULL || Prefilter == NULL || pectx == NULL) + return -1; + + PrefilterEngine *e = SCCalloc(1, sizeof(*e)); + if (e == NULL) + return -1; + + e->Prefilter = Prefilter; + e->pectx = pectx; + e->Free = FreeFunc; + + if (sgh->engines == NULL) { + sgh->engines = e; + return 0; + } + + PrefilterEngine *t = sgh->engines; + while (t->next != NULL) { + t = t->next; + } + + t->next = e; + e->id = t->id + 1; + return 0; +} + +int PrefilterAppendTxEngine(SigGroupHead *sgh, + void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *tx, + const uint64_t idx, const uint8_t flags), + AppProto alproto, int tx_min_progress, + void *pectx, void (*FreeFunc)(void *pectx)) +{ + if (sgh == NULL || PrefilterTx == NULL || pectx == NULL) + return -1; + + PrefilterEngine *e = SCCalloc(1, sizeof(*e)); + if (e == NULL) + return -1; + + e->PrefilterTx = PrefilterTx; + e->pectx = pectx; + e->alproto = alproto; + e->tx_min_progress = tx_min_progress; + e->Free = FreeFunc; + + if (sgh->tx_engines == NULL) { + sgh->tx_engines = e; + return 0; + } + + PrefilterEngine *t = sgh->tx_engines; + while (t->next != NULL) { + t = t->next; + } + + t->next = e; + e->id = t->id + 1; + return 0; +} + +static void PrefilterFreeEngine(PrefilterEngine *e) +{ + if (e->Free) { + e->Free(e->pectx); + } + SCFree(e); +} + +void PrefilterFreeEngines(PrefilterEngine *list) +{ + PrefilterEngine *t = list; + + while (t != NULL) { + PrefilterEngine *next = t->next; + PrefilterFreeEngine(t); + t = next; + } +} diff --git a/src/detect-engine-prefilter.h b/src/detect-engine-prefilter.h new file mode 100644 index 000000000000..0293135f9f1b --- /dev/null +++ b/src/detect-engine-prefilter.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2016 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 + */ + +#ifndef __DETECT_ENGINE_PREFILTER_H__ +#define __DETECT_ENGINE_PREFILTER_H__ + +void Prefilter(DetectEngineThreadCtx *, const SigGroupHead *, Packet *p, + const uint8_t flags, int has_state); + +int PrefilterAppendEngine(SigGroupHead *sgh, + void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), + void *pectx, void (*FreeFunc)(void *pectx)); +int PrefilterAppendTxEngine(SigGroupHead *sgh, + void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *tx, + const uint64_t idx, const uint8_t flags), + const AppProto alproto, const int tx_min_progress, + void *pectx, void (*FreeFunc)(void *pectx)); + +void PrefilterFreeEngines(PrefilterEngine *list); + +#endif diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index d681ce931b31..c546d4da52f8 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -36,6 +36,7 @@ #include "detect-engine-address.h" #include "detect-engine-mpm.h" #include "detect-engine-siggroup.h" +#include "detect-engine-prefilter.h" #include "detect-content.h" #include "detect-uricontent.h" @@ -170,6 +171,9 @@ void SigGroupHeadFree(SigGroupHead *sgh) sgh->init = NULL; } + PrefilterFreeEngines(sgh->tx_engines); + PrefilterFreeEngines(sgh->engines); + SCFree(sgh); return; diff --git a/src/detect.c b/src/detect.c index 3d78875d4461..18b61ac355e3 100644 --- a/src/detect.c +++ b/src/detect.c @@ -43,6 +43,7 @@ #include "detect-engine-mpm.h" #include "detect-engine-iponly.h" #include "detect-engine-threshold.h" +#include "detect-engine-prefilter.h" #include "detect-engine-payload.h" #include "detect-engine-dcepayload.h" @@ -1491,10 +1492,14 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_NONMPMLIST); + /* run the prefilter engines */ + Prefilter(det_ctx, det_ctx->sgh, p, flow_flags, has_state); + /* run the mpm for each type */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM); DetectMpmPrefilter(de_ctx, det_ctx, smsg, p, flow_flags, alproto, has_state, &sms_runflags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); + #ifdef PROFILING if (th_v) { StatsAddUI64(th_v, det_ctx->counter_mpm_list, diff --git a/src/detect.h b/src/detect.h index 9aa17f280e7a..5f9ecc86e9f1 100644 --- a/src/detect.h +++ b/src/detect.h @@ -975,6 +975,31 @@ typedef struct MpmStore_ { } MpmStore; +typedef struct PrefilterEngine_ { + 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 */ + int tx_min_progress; + + /** 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); + void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *tx, + const uint64_t idx, const uint8_t flags); + + struct PrefilterEngine_ *next; + + /** Free function for pectx data. If NULL the memory is not freed. */ + void (*Free)(void *pectx); + +} PrefilterEngine; + typedef struct SigGroupHeadInitData_ { MpmStore mpm_store[MPMB_MAX]; @@ -1042,6 +1067,9 @@ typedef struct SigGroupHead_ { }; }; + PrefilterEngine *engines; + PrefilterEngine *tx_engines; + /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ Signature **match_array; From b62c4cc359c223eacceec3e095cd3172aca03564 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 13:22:20 +0200 Subject: [PATCH 1886/2553] http_uri: mpm prefilter engine Inspect partial request line as well. --- src/detect-engine-mpm.c | 55 ++++++++++++++++++++--------------- src/detect-engine-uri.c | 63 +++++++++++++++-------------------------- src/detect-engine-uri.h | 2 +- src/detect.c | 5 ---- 4 files changed, 56 insertions(+), 69 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 08bb30fff600..3355e79ce0ff 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -47,7 +47,8 @@ #include "detect-flow.h" #include "detect-content.h" -#include "detect-uricontent.h" + +#include "detect-engine-uri.h" #include "stream.h" @@ -73,44 +74,48 @@ typedef struct AppLayerMpms_ { int direction; /**< SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT */ int sm_list; uint32_t flags; /**< flags set to SGH when this mpm is present */ + + int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int id; /**< index into this array and result arrays */ } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_UMATCH, SIG_GROUP_HEAD_MPM_URI, 0 }, - { "http_raw_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRUDMATCH, SIG_GROUP_HEAD_MPM_HRUD, 1 }, + { "http_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_UMATCH, + SIG_GROUP_HEAD_MPM_URI, PrefilterTxUriRegister, 0 }, + { "http_raw_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRUDMATCH, SIG_GROUP_HEAD_MPM_HRUD, NULL, 1 }, - { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, 2}, - { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, 3}, + { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, NULL, 2}, + { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, NULL, 3}, - { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, SIG_GROUP_HEAD_MPM_HUAD, 4}, + { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, SIG_GROUP_HEAD_MPM_HUAD, NULL, 4}, - { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, 5}, - { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, 6}, + { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, NULL, 5}, + { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, NULL, 6}, - { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, SIG_GROUP_HEAD_MPM_HMD, 7}, + { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, SIG_GROUP_HEAD_MPM_HMD, NULL, 7}, - { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_FD_SMTP, 8}, /* smtp */ - { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_HSBD, 9}, /* http server body */ + { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_FD_SMTP, NULL, 8}, /* smtp */ + { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_HSBD, NULL, 9}, /* http server body */ - { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, SIG_GROUP_HEAD_MPM_HSMD, 10}, - { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, SIG_GROUP_HEAD_MPM_HSCD, 11}, + { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, SIG_GROUP_HEAD_MPM_HSMD, NULL, 10}, + { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, SIG_GROUP_HEAD_MPM_HSCD, NULL, 11}, - { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, SIG_GROUP_HEAD_MPM_HCBD, 12}, + { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, SIG_GROUP_HEAD_MPM_HCBD, NULL, 12}, - { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, SIG_GROUP_HEAD_MPM_HHHD, 13}, - { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, SIG_GROUP_HEAD_MPM_HRHHD, 14}, + { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, SIG_GROUP_HEAD_MPM_HHHD, NULL, 13}, + { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, SIG_GROUP_HEAD_MPM_HRHHD, NULL, 14}, - { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, 15}, - { "http_cookie", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, 16}, + { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, NULL, 15}, + { "http_cookie", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, NULL, 16}, - { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, SIG_GROUP_HEAD_MPM_DNSQUERY, 17}, + { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, SIG_GROUP_HEAD_MPM_DNSQUERY, NULL, 17}, - { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, SIG_GROUP_HEAD_MPM_TLSSNI, 18}, - { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, SIG_GROUP_HEAD_MPM_TLSISSUER, 19}, - { "tls_cert_subject", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSSUBJECT_MATCH, SIG_GROUP_HEAD_MPM_TLSSUBJECT, 20}, + { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, SIG_GROUP_HEAD_MPM_TLSSNI, NULL, 18}, + { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, SIG_GROUP_HEAD_MPM_TLSISSUER, NULL, 19}, + { "tls_cert_subject", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSSUBJECT_MATCH, SIG_GROUP_HEAD_MPM_TLSSUBJECT, NULL, 20}, - { NULL, 0, 0, 0, 0, 0, } + { NULL, 0, 0, 0, 0, NULL, 0, } }; void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) @@ -1291,6 +1296,10 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->init->app_mpms[a->id] = mpm_store->mpm_ctx; if (sh->init->app_mpms[a->id] != NULL) sh->flags |= a->flags; + + if (a->PrefilterRegister) { + BUG_ON(a->PrefilterRegister(sh, mpm_store->mpm_ctx) != 0); + } } a++; } diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index a5fad2fc9c49..18695997937a 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -32,6 +32,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -49,61 +50,43 @@ #include "app-layer-protos.h" #include "util-validate.h" -/** \brief Uri Pattern match -- searches for one pattern per signature. +/** \brief HTTP URI Mpm prefilter callback * * \param det_ctx detection engine thread ctx * \param p packet to inspect - * - * \retval ret number of matches + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *uri, const uint16_t uri_len) +static void PrefilterTxUri(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; - - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_uri_ctx_ts == NULL); + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - if (uri_len >= det_ctx->sgh->mpm_uri_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_uri_ctx_ts, - &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); - } + if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) + return; - //PrintRawDataFp(stdout, uri, uri_len); + const uint32_t uri_len = bstr_len(tx_ud->request_uri_normalized); + const uint8_t *uri = bstr_ptr(tx_ud->request_uri_normalized); - SCReturnUInt(ret); + if (uri_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); + } } -/** - * \brief Run the pattern matcher against the uri(s) - * - * We run against _all_ uri(s) we have as the pattern matcher will - * flag each sig that has a match. We need to do this for all uri(s) - * to not miss possible events. - * - * \param f locked flow - * \param htp_state initialized htp state - * - * \todo what should we return? Just the fact that we matched? - */ -uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, void *txv) +int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); - htp_tx_t *tx = (htp_tx_t *)txv; - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - uint32_t cnt = 0; - - if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) - goto end; - cnt = UriPatternSearch(det_ctx, (const uint8_t *) - bstr_ptr(tx_ud->request_uri_normalized), - bstr_len(tx_ud->request_uri_normalized)); - -end: - SCReturnUInt(cnt); + return PrefilterAppendTxEngine(sgh, PrefilterTxUri, + ALPROTO_HTTP, HTP_REQUEST_LINE, + mpm_ctx, NULL); } /** diff --git a/src/detect-engine-uri.h b/src/detect-engine-uri.h index b9f4431ea840..804ba875e31d 100644 --- a/src/detect-engine-uri.h +++ b/src/detect-engine-uri.h @@ -24,7 +24,7 @@ #ifndef __DETECT_ENGINE_URICONTENT_H__ #define __DETECT_ENGINE_URICONTENT_H__ -uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, void *tx); +int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectPacketUris(ThreadVars *tv, DetectEngineCtx *de_ctx, diff --git a/src/detect.c b/src/detect.c index 18b61ac355e3..c863d964e278 100644 --- a/src/detect.c +++ b/src/detect.c @@ -903,11 +903,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); if (tx_progress > HTP_REQUEST_LINE) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_URI) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_URI); - DetectUricontentInspectMpm(det_ctx, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_URI); - } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRUD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRUD); DetectEngineRunHttpRawUriMpm(det_ctx, tx); From 72f2a78b1f5cf22766a26b5f9c1e41886284954c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 18:56:20 +0200 Subject: [PATCH 1887/2553] http_method: mpm prefilter engine --- src/detect-engine-hmd.c | 53 ++++++++++++++++++++--------------------- src/detect-engine-hmd.h | 2 +- src/detect-engine-mpm.c | 4 +++- src/detect.c | 5 ---- 4 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 391a623b119d..72f5c43597b4 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -41,6 +41,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -58,45 +59,43 @@ #include "app-layer-protos.h" #include "util-validate.h" -/** - * \brief Http method match -- searches for one pattern per signature. +/** \brief HTTP Method Mpm prefilter callback * - * \param det_ctx Detection engine thread ctx. - * \param method Method to inspect. - * \param method_len Method length. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context * - * \retval ret Number of matches. + * \retval ret number of matches */ -static inline uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *raw_method, const uint32_t raw_method_len) +static void PrefilterTxMethod(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hmd_ctx_ts == NULL); + if (tx->request_method == NULL) + return; - if (raw_method_len >= det_ctx->sgh->mpm_hmd_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hmd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, raw_method, raw_method_len); - } + const uint32_t buffer_len = bstr_len(tx->request_method); + const uint8_t *buffer = bstr_ptr(tx->request_method); - SCReturnUInt(ret); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } } -int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, void *txv) +int PrefilterTxMethodRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { - uint32_t cnt = 0; - htp_tx_t *tx = (htp_tx_t *)txv; - if (tx->request_method == NULL) - goto end; - - cnt = HttpMethodPatternSearch(det_ctx, - (const uint8_t *)bstr_ptr(tx->request_method), - bstr_len(tx->request_method)); - end: - return cnt; + return PrefilterAppendTxEngine(sgh, PrefilterTxMethod, + ALPROTO_HTTP, HTP_REQUEST_LINE, + mpm_ctx, NULL); } /** diff --git a/src/detect-engine-hmd.h b/src/detect-engine-hmd.h index c176755a6620..e2be754be4bc 100644 --- a/src/detect-engine-hmd.h +++ b/src/detect-engine-hmd.h @@ -32,7 +32,7 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, void *txv); +int PrefilterTxMethodRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); void DetectEngineHttpMethodRegisterTests(void); diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 3355e79ce0ff..0d625b1119e4 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -49,6 +49,7 @@ #include "detect-content.h" #include "detect-engine-uri.h" +#include "detect-engine-hmd.h" #include "stream.h" @@ -93,7 +94,8 @@ AppLayerMpms app_mpms[] = { { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, NULL, 5}, { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, NULL, 6}, - { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, SIG_GROUP_HEAD_MPM_HMD, NULL, 7}, + { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, + SIG_GROUP_HEAD_MPM_HMD, PrefilterTxMethodRegister, 7}, { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_FD_SMTP, NULL, 8}, /* smtp */ { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_HSBD, NULL, 9}, /* http server body */ diff --git a/src/detect.c b/src/detect.c index c863d964e278..e9fc09f0638e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -908,11 +908,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunHttpRawUriMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRUD); } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HMD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HMD); - DetectEngineRunHttpMethodMpm(det_ctx, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HMD); - } } if (tx_progress >= HTP_REQUEST_HEADERS) { From 9ff5703c4972effbb9a93dcbaefb18917c0a566b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 7 Jul 2016 19:25:10 +0200 Subject: [PATCH 1888/2553] packet/stream: mpm prefilter engine --- src/detect-engine-mpm.c | 15 ++ src/detect-engine-mpm.h | 3 - src/detect-engine-payload.c | 114 ++++----- src/detect-engine-payload.h | 3 + src/detect-fast-pattern.c | 491 ------------------------------------ src/detect.c | 55 +--- src/detect.h | 4 + 7 files changed, 80 insertions(+), 605 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 0d625b1119e4..165d48c66897 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -48,6 +48,7 @@ #include "detect-content.h" +#include "detect-engine-payload.h" #include "detect-engine-uri.h" #include "detect-engine-hmd.h" @@ -1230,6 +1231,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_packet_ctx = mpm_store->mpm_ctx; if (sh->mpm_packet_ctx) sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + + PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TS); @@ -1239,6 +1242,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_stream_ctx = mpm_store->mpm_ctx; if (sh->mpm_stream_ctx) sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; + + PrefilterPktStreamRegister(sh, mpm_store->mpm_ctx); } } if (SGH_DIRECTION_TC(sh)) { @@ -1248,6 +1253,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_packet_ctx = mpm_store->mpm_ctx; if (sh->mpm_packet_ctx) sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + + PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TC); @@ -1256,6 +1263,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_stream_ctx = mpm_store->mpm_ctx; if (sh->mpm_stream_ctx) sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; + + PrefilterPktStreamRegister(sh, mpm_store->mpm_ctx); } } } else if (SGH_PROTO(sh, IPPROTO_UDP)) { @@ -1268,6 +1277,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (sh->mpm_packet_ctx != NULL) sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + + PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } } if (SGH_DIRECTION_TC(sh)) { @@ -1278,6 +1289,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (sh->mpm_packet_ctx != NULL) sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + + PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } } } else { @@ -1288,6 +1301,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (sh->mpm_packet_ctx != NULL) sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; + + PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } } diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 5e83a2553987..bb73a6a3030e 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -40,9 +40,6 @@ void DetectMpmPrepareBuiltinMpms(DetectEngineCtx *de_ctx); uint32_t PatternStrength(uint8_t *, uint16_t); uint16_t PatternMatchDefaultMatcher(void); -uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *, Packet *); -uint32_t PacketPatternSearch(DetectEngineThreadCtx *, Packet *); -uint32_t StreamPatternSearch(DetectEngineThreadCtx *, Packet *, StreamMsg *, uint8_t); uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *buffer, uint32_t buffer_len, uint8_t flags); void PacketPatternCleanup(ThreadVars *, DetectEngineThreadCtx *); diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index d3a17bac35fe..85f69925b02c 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -32,6 +32,7 @@ #include "detect-engine.h" #include "detect-parse.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "stream.h" @@ -44,100 +45,77 @@ #include "util-mpm-ac.h" -uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, - const Packet *p) +static void PrefilterPktStream(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + const StreamMsg *smsg = det_ctx->smsg; - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_stream_ctx == NULL); - if (det_ctx->sgh->mpm_stream_ctx == NULL) - SCReturnInt(0); + /* for established packets inspect any smsg we may have queued up */ + if (p->flowflags & FLOW_PKT_ESTABLISHED) { + SCLogDebug("p->flowflags & FLOW_PKT_ESTABLISHED"); - if (p->payload_len >= det_ctx->sgh->mpm_stream_ctx->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx, &det_ctx->mtc, &det_ctx->pmq, - p->payload, p->payload_len); + for ( ; smsg != NULL; smsg = smsg->next) { + if (smsg->data_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcs, &det_ctx->pmq, + smsg->data, smsg->data_len); + } + } + } else { + SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); } - SCReturnInt(ret); -} - -/** \brief Pattern match -- searches for only one pattern per signature. - * - * \param det_ctx detection engine thread ctx - * \param p packet - * \param smsg stream msg (reassembled stream data) - * \param flags stream flags - * - * \retval ret number of matches - */ -uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, const Packet *p, - const StreamMsg *smsg, const uint8_t flags) -{ - SCEnter(); - - uint32_t ret = 0; - - //PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); - - uint32_t r; - for ( ; smsg != NULL; smsg = smsg->next) { - if (smsg->data_len >= det_ctx->sgh->mpm_stream_ctx->minlen) { - r = mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx, &det_ctx->mtcs, - &det_ctx->pmq, smsg->data, smsg->data_len); - if (r > 0) { - ret += r; - } + /* packets that have not been added to the stream will be inspected + * as if they are stream chunks */ + if ((!(p->flags & PKT_NOPAYLOAD_INSPECTION)) && + !(p->flags & PKT_STREAM_ADD)) + { + if (p->payload_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtc, &det_ctx->pmq, + p->payload, p->payload_len); } } +} - SCReturnInt(ret); +int PrefilterPktStreamRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + return PrefilterAppendEngine(sgh, PrefilterPktStream, mpm_ctx, NULL); } -/** \brief Pattern match -- searches for only one pattern per signature. - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * - * \retval ret number of matches - */ -uint32_t PacketPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p) +static void PrefilterPktPayload(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx) { SCEnter(); - uint32_t ret = 0; - const MpmCtx *mpm_ctx = NULL; - - mpm_ctx = det_ctx->sgh->mpm_packet_ctx; - if (unlikely(mpm_ctx == NULL)) - SCReturnInt(0); + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; if (p->payload_len < mpm_ctx->minlen) - SCReturnInt(0); + SCReturn; #ifdef __SC_CUDA_SUPPORT__ if (p->cuda_pkt_vars.cuda_mpm_enabled && p->pkt_src == PKT_SRC_WIRE) { - ret = SCACCudaPacketResultsProcessing(p, mpm_ctx, &det_ctx->pmq); + (void)SCACCudaPacketResultsProcessing(p, mpm_ctx, &det_ctx->pmq); } else { - ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtc, - &det_ctx->pmq, - p->payload, - p->payload_len); + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtc, &det_ctx->pmq, + p->payload, p->payload_len); } #else - ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtc, - &det_ctx->pmq, - p->payload, - p->payload_len); + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtc, &det_ctx->pmq, + p->payload, p->payload_len); #endif +} - SCReturnInt(ret); +int PrefilterPktPayloadRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + return PrefilterAppendEngine(sgh, PrefilterPktPayload, mpm_ctx, NULL); } + /** * \brief Do the content inspection & validation for a signature * diff --git a/src/detect-engine-payload.h b/src/detect-engine-payload.h index d6220b18a598..67d0be24656a 100644 --- a/src/detect-engine-payload.h +++ b/src/detect-engine-payload.h @@ -24,6 +24,9 @@ #ifndef __DETECT_ENGINE_PAYLOAD_H__ #define __DETECT_ENGINE_PAYLOAD_H__ +int PrefilterPktPayloadRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterPktStreamRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectPacketPayload(DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, Packet *); int DetectEngineInspectStreamPayload(DetectEngineCtx *, diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index b2e569416759..1180209bc870 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -518,488 +518,6 @@ int DetectFastPatternTest04(void) return result; } -/** - * \test Checks that a fast_pattern is used in the mpm phase. - */ -int DetectFastPatternTest05(void) -{ - uint8_t *buf = (uint8_t *) "Oh strin1. But what " - "strin2. This is strings3. We strins_str4. we " - "have strins_string5"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; fast_pattern; " - "content:\"strings_str4\"; content:\"strings_string5\"; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) != 0) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -end: - UTHFreePackets(&p, 1); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a fast_pattern is used in the mpm phase. - */ -int DetectFastPatternTest06(void) -{ - uint8_t *buf = (uint8_t *) "Oh this is a string1. But what is this with " - "string2. This is strings3. We have strings_str4. We also have " - "strings_string5"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; fast_pattern; " - "content:\"strings_str4\"; content:\"strings_string5\"; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) != 0) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -end: - UTHFreePackets(&p, 1); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a fast_pattern is used in the mpm phase, when the payload - * doesn't contain the fast_pattern string within it. - */ -int DetectFastPatternTest07(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. now here comes our " - "dark knight strings_string5. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; fast_pattern; " - "content:\"strings_str4\"; content:\"strings_string5\"; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -end: - UTHFreePackets(&p, 1); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a fast_pattern is used in the mpm phase and that we get - * exactly 1 match for the mpm phase. - */ -int DetectFastPatternTest08(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. now here comes our " - "dark knight strings3. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("de_ctx init: "); - goto end; - } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; fast_pattern; " - "content:\"strings_str4\"; content:\"strings_string5\"; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = PacketPatternSearchWithStreamCtx(det_ctx, p); - if (r != 1) { - printf("expected 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; -end: - UTHFreePackets(&p, 1); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - return result; -} -/** - * \test Checks that a fast_pattern is used in the mpm phase, when the payload - * doesn't contain the fast_pattern string within it. - */ -int DetectFastPatternTest09(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. no_strings4 _imp now here " - "comes our dark knight strings3. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; " - "content:\"strings4_imp\"; fast_pattern; " - "content:\"strings_string5\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -end: - UTHFreePackets(&p, 1); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a the SigInit chooses the fast_pattern with better pattern - * strength, when we have multiple fast_patterns in the Signature. Also - * checks that we get a match for the fast_pattern from the mpm phase. - */ -int DetectFastPatternTest10(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. strings4_imp now here " - "comes our dark knight strings5. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("de_ctx init: "); - goto end; - } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; " - "content:\"strings4_imp\"; fast_pattern; " - "content:\"strings_string5\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = PacketPatternSearchWithStreamCtx(det_ctx, p); - if (r != 1) { - printf("expected 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; -end: - UTHFreePackets(&p, 1); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a the SigInit chooses the fast_pattern with better pattern - * strength, when we have multiple fast_patterns in the Signature. Also - * checks that we get no matches for the fast_pattern from the mpm phase. - */ -int DetectFastPatternTest11(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. strings5_imp now here " - "comes our dark knight strings5. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; " - "content:\"strings4_imp\"; fast_pattern; " - "content:\"strings_string5\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) - result = 1; - - -end: - UTHFreePackets(&p, 1); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - return result; -} - -/** - * \test Checks that we don't get a match for the mpm phase. - */ -int DetectFastPatternTest12(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. strings5_imp now here " - "comes our dark knight strings5. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; " - "content:\"strings4_imp\"; " - "content:\"strings_string5\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -end: - UTHFreePackets(&p, 1); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a the SigInit chooses the fast_pattern with a better - * strength from the available patterns, when we don't specify a - * fast_pattern. We also check that we get a match from the mpm - * phase. - */ -int DetectFastPatternTest13(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. strings5_imp now here " - "comes our dark knight strings_string5. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("de_ctx init: "); - goto end; - } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; " - "content:\"strings4_imp\"; " - "content:\"strings_string5\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = PacketPatternSearchWithStreamCtx(det_ctx, p); - if (r != 1) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; -end: - UTHFreePackets(&p, 1); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - return result; -} - /** * \test Checks to make sure that other sigs work that should when fast_pattern is inspecting on the same payload * @@ -19430,15 +18948,6 @@ void DetectFastPatternRegisterTests(void) UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); UtRegisterTest("DetectFastPatternTest03", DetectFastPatternTest03); UtRegisterTest("DetectFastPatternTest04", DetectFastPatternTest04); - UtRegisterTest("DetectFastPatternTest05", DetectFastPatternTest05); - UtRegisterTest("DetectFastPatternTest06", DetectFastPatternTest06); - UtRegisterTest("DetectFastPatternTest07", DetectFastPatternTest07); - UtRegisterTest("DetectFastPatternTest08", DetectFastPatternTest08); - UtRegisterTest("DetectFastPatternTest09", DetectFastPatternTest09); - UtRegisterTest("DetectFastPatternTest10", DetectFastPatternTest10); - UtRegisterTest("DetectFastPatternTest11", DetectFastPatternTest11); - UtRegisterTest("DetectFastPatternTest12", DetectFastPatternTest12); - UtRegisterTest("DetectFastPatternTest13", DetectFastPatternTest13); UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14); UtRegisterTest("DetectFastPatternTest15", DetectFastPatternTest15); UtRegisterTest("DetectFastPatternTest16", DetectFastPatternTest16); diff --git a/src/detect.c b/src/detect.c index e9fc09f0638e..6b5b70b649eb 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1072,42 +1072,9 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } } } - - if (smsg != NULL && (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_STREAM)) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_STREAM); - StreamPatternSearch(det_ctx, p, smsg, flags); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_STREAM); - } else { - SCLogDebug("smsg NULL or no stream mpm for this sgh"); - } } else { SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); } - - if (p->payload_len > 0 && (!(p->flags & PKT_NOPAYLOAD_INSPECTION))) { - if (!(p->flags & PKT_STREAM_ADD) && (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_STREAM)) { - *sms_runflags |= SMS_USED_PM; - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_PKT_STREAM); - PacketPatternSearchWithStreamCtx(det_ctx, p); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_PKT_STREAM); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_PACKET) { - /* run the multi packet matcher against the payload of the packet */ - SCLogDebug("search: (%p, sgh->sig_cnt %" PRIu32 ")", - det_ctx->sgh, det_ctx->sgh->sig_cnt); - - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_PACKET); - PacketPatternSearch(det_ctx, p); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_PACKET); - - *sms_runflags |= SMS_USED_PM; - } else { - SCLogDebug("not packet"); - } - } else { - SCLogDebug("how did we get here?"); - } - /* UDP DNS inspection is independent of est or not */ if (alproto == ALPROTO_DNS && has_state) { if (p->flowflags & FLOW_PKT_TOSERVER) { @@ -1266,7 +1233,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh int smatch = 0; /* signature match: 1, no match: 0 */ #endif uint8_t flow_flags = 0; /* flow/state flags */ - StreamMsg *smsg = NULL; Signature *s = NULL; Signature *next_s = NULL; uint8_t alversion = 0; @@ -1281,7 +1247,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh p->alerts.cnt = 0; det_ctx->filestore_cnt = 0; - + det_ctx->smsg = NULL; det_ctx->base64_decoded_len = 0; /* No need to perform any detection on this packet, if the the given flag is set.*/ @@ -1358,7 +1324,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_GETSGH); - smsg = SigMatchSignaturesGetSmsg(pflow, p, flow_flags); + det_ctx->smsg = SigMatchSignaturesGetSmsg(pflow, p, flow_flags); #if 0 StreamMsg *tmpsmsg = smsg; while (tmpsmsg) { @@ -1428,7 +1394,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh #ifdef DEBUG if (pflow) { - DebugInspectIds(p, pflow, smsg); + DebugInspectIds(p, pflow, det_ctx->smsg); } #endif } else { /* p->flags & PKT_HAS_FLOW */ @@ -1472,7 +1438,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* create our prefilter mask */ SignatureMask mask = 0; - PacketCreateMask(p, &mask, alproto, has_state, smsg, app_decoder_events); + PacketCreateMask(p, &mask, alproto, has_state, det_ctx->smsg, + app_decoder_events); /* build and prefilter non_pf list against the mask of the packet */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_NONMPMLIST); @@ -1487,7 +1454,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* run the mpm for each type */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM); - DetectMpmPrefilter(de_ctx, det_ctx, smsg, p, flow_flags, alproto, has_state, &sms_runflags); + DetectMpmPrefilter(de_ctx, det_ctx, det_ctx->smsg, p, flow_flags, + alproto, has_state, &sms_runflags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); #ifdef PROFILING @@ -1663,12 +1631,12 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh * but not for a "dsize" signature */ if (sflags & SIG_FLAG_REQUIRE_STREAM) { char pmatch = 0; - if (smsg != NULL) { + if (det_ctx->smsg != NULL) { uint8_t pmq_idx = 0; - StreamMsg *smsg_inspect = smsg; + StreamMsg *smsg_inspect = det_ctx->smsg; for ( ; smsg_inspect != NULL; smsg_inspect = smsg_inspect->next, pmq_idx++) { if (DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, pflow, smsg_inspect->data, smsg_inspect->data_len) == 1) { - SCLogDebug("match in smsg %p", smsg); + SCLogDebug("match in smsg %p", smsg_inspect); pmatch = 1; det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH; /* Tell the engine that this reassembled stream can drop the @@ -1937,7 +1905,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* if we had no alerts that involved the smsgs, * we can get rid of them now. */ - StreamMsgReturnListToPool(smsg); + StreamMsgReturnListToPool(det_ctx->smsg); + det_ctx->smsg = NULL; } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_CLEANUP); diff --git a/src/detect.h b/src/detect.h index 5f9ecc86e9f1..6c8b333ba6ee 100644 --- a/src/detect.h +++ b/src/detect.h @@ -45,6 +45,8 @@ #include "detect-mark.h" +#include "stream.h" + #define DETECT_MAX_RULE_SIZE 8192 /* forward declarations for the structures from detect-engine-sigorder.h */ @@ -834,6 +836,8 @@ typedef struct DetectEngineThreadCtx_ { MpmThreadCtx mtcs; /**< thread ctx for stream mpm */ PrefilterRuleStore pmq; + StreamMsg *smsg; + /** SPM thread context used for scanning. This has been cloned from the * prototype held by DetectEngineCtx. */ SpmThreadCtx *spm_thread_ctx; From 746a169127b2939f05f92d62543a47d20a2d7b49 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 Jul 2016 10:15:20 +0200 Subject: [PATCH 1889/2553] dns_query: mpm prefilter engine --- src/detect-dns-query.h | 2 -- src/detect-engine-dns.c | 73 ++++++++++++++++------------------------- src/detect-engine-dns.h | 2 ++ src/detect-engine-mpm.c | 4 ++- src/detect.c | 49 --------------------------- 5 files changed, 34 insertions(+), 96 deletions(-) diff --git a/src/detect-dns-query.h b/src/detect-dns-query.h index 4065c4103411..ef6dac2c913f 100644 --- a/src/detect-dns-query.h +++ b/src/detect-dns-query.h @@ -28,6 +28,4 @@ void DetectDnsQueryRegister (void); -uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, void *txv); - #endif /* __DETECT_DNS_QUERY_H__ */ diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index f3441e1afcec..fafb6987b0a8 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Open Information Security Foundation +/* Copyright (C) 2013-2016 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 @@ -31,6 +31,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -94,63 +95,47 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, return r; } -/** - * \brief DNS query match -- searches for one pattern per signature. +/** \brief DNS Query Mpm prefilter callback * - * \param det_ctx Detection engine thread ctx. - * \param hrh Buffer to inspect. - * \param hrh_len buffer length. - * \param flags Flags - * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *buffer, const uint32_t buffer_len) -{ - SCEnter(); - - uint32_t ret = 0; - - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL); - - if (buffer_len >= det_ctx->sgh->mpm_dnsquery_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_dnsquery_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_dnsquery_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); - } - - SCReturnUInt(ret); -} - -/** - * \brief Run the pattern matcher against the queries - * - * \param f locked flow - * \param dns_state initialized dns state - * - * \todo what should we return? Just the fact that we matched? - */ -uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, void *txv) +static void PrefilterTxDnsQuery(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; DNSTransaction *tx = (DNSTransaction *)txv; DNSQueryEntry *query = NULL; - uint8_t *buffer; - uint16_t buffer_len; - uint32_t cnt = 0; TAILQ_FOREACH(query, &tx->query_list, next) { SCLogDebug("tx %p query %p", tx, query); - buffer = (uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)); - buffer_len = query->len; + const uint8_t *buffer = + (const uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)); + const uint32_t buffer_len = query->len; - cnt += DnsQueryPatternSearch(det_ctx, - buffer, buffer_len); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, + buffer, buffer_len); + } } +} + +int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); - SCReturnUInt(cnt); + return PrefilterAppendTxEngine(sgh, PrefilterTxDnsQuery, + ALPROTO_DNS, 1, + mpm_ctx, NULL); } int DetectEngineInspectDnsRequest(ThreadVars *tv, diff --git a/src/detect-engine-dns.h b/src/detect-engine-dns.h index 801a22d42155..5b2367a66010 100644 --- a/src/detect-engine-dns.h +++ b/src/detect-engine-dns.h @@ -23,6 +23,8 @@ #ifndef __DETECT_ENGINE_DNS_H__ #define __DETECT_ENGINE_DNS_H__ +int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectDnsQueryName(ThreadVars *, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, void *, uint64_t); diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 165d48c66897..6ad75e8624cf 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -51,6 +51,7 @@ #include "detect-engine-payload.h" #include "detect-engine-uri.h" #include "detect-engine-hmd.h" +#include "detect-engine-dns.h" #include "stream.h" @@ -112,7 +113,8 @@ AppLayerMpms app_mpms[] = { { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, NULL, 15}, { "http_cookie", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, NULL, 16}, - { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, SIG_GROUP_HEAD_MPM_DNSQUERY, NULL, 17}, + { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, + SIG_GROUP_HEAD_MPM_DNSQUERY, PrefilterTxDnsQueryRegister, 17}, { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, SIG_GROUP_HEAD_MPM_TLSSNI, NULL, 18}, { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, SIG_GROUP_HEAD_MPM_TLSISSUER, NULL, 19}, diff --git a/src/detect.c b/src/detect.c index 6b5b70b649eb..57a023791fe8 100644 --- a/src/detect.c +++ b/src/detect.c @@ -999,30 +999,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } } } /* for */ - } - /* all dns based mpms */ - else if (alproto == ALPROTO_DNS && has_state) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_DNSQUERY) { - void *alstate = FlowGetAppState(p->flow); - if (alstate == NULL) { - SCLogDebug("no alstate"); - return; - } - - uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); - uint64_t total_txs = AppLayerParserGetTxCnt(p->flow->proto, alproto, alstate); - for (; idx < total_txs; idx++) { - void *tx = AppLayerParserGetTx(p->flow->proto, alproto, alstate, idx); - if (tx == NULL) - continue; - - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_DNSQUERY); - DetectDnsQueryInspectMpm(det_ctx, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY); - } - } - } } else if (alproto == ALPROTO_TLS && has_state) { void *alstate = FlowGetAppState(p->flow); if (alstate == NULL) { @@ -1075,31 +1051,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } else { SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); } - /* UDP DNS inspection is independent of est or not */ - if (alproto == ALPROTO_DNS && has_state) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - SCLogDebug("mpm inspection"); - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_DNSQUERY) { - void *alstate = FlowGetAppState(p->flow); - if (alstate == NULL) { - SCLogDebug("no alstate"); - return; - } - - uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); - uint64_t total_txs = AppLayerParserGetTxCnt(p->flow->proto, alproto, alstate); - for (; idx < total_txs; idx++) { - void *tx = AppLayerParserGetTx(p->flow->proto, alproto, alstate, idx); - if (tx == NULL) - continue; - SCLogDebug("tx %p",tx); - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_DNSQUERY); - DetectDnsQueryInspectMpm(det_ctx, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY); - } - } - } - } /* Sort the rule list to lets look at pmq. * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ From 7a46364e429eb15c3420de8f5e1ec5c4e19c65b1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 Jul 2016 13:07:52 +0200 Subject: [PATCH 1890/2553] http_raw_uri: mpm prefilter engine --- src/detect-engine-hrud.c | 356 +++------------------------------------ src/detect-engine-hrud.h | 2 +- src/detect-engine-mpm.c | 4 +- src/detect.c | 8 - 4 files changed, 30 insertions(+), 340 deletions(-) diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 7084ad58922d..5139b21a8603 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP raw uri match */ @@ -40,6 +41,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -58,52 +60,42 @@ #include "util-validate.h" -/** - * \brief Http raw uri match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param uri Raw uri to inspect. - * \param uri_len Raw uri length. +/** \brief HTTP URI Raw Mpm prefilter callback * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *uri, const uint32_t uri_len) +static void PrefilterTxRawUri(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrud_ctx_ts == NULL); + if (likely(tx->request_uri != NULL)) { + const uint32_t uri_len = bstr_len(tx->request_uri); + const uint8_t *uri = bstr_ptr(tx->request_uri); - if (uri_len >= det_ctx->sgh->mpm_hrud_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrud_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, uri, uri_len); + if (uri_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); + } } - - SCReturnUInt(ret); } -/** - * \brief Run the mpm against raw http uris. - * - * \retval cnt Number of matches reported by the mpm algo. - */ -int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, void *txv) +int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); - htp_tx_t *tx = (htp_tx_t *)txv; - uint32_t cnt = 0; - if (tx->request_uri == NULL) - goto end; - - cnt = HttpRawUriPatternSearch(det_ctx, - (const uint8_t *)bstr_ptr(tx->request_uri), - bstr_len(tx->request_uri)); -end: - SCReturnInt(cnt); + return PrefilterAppendTxEngine(sgh, PrefilterTxRawUri, + ALPROTO_HTTP, HTP_REQUEST_LINE, + mpm_ctx, NULL); } /** @@ -2208,294 +2200,6 @@ static int DetectEngineHttpRawUriTest16(void) return result; } -static int DetectEngineHttpRawUriTest17(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This_is_dummy_body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"body1\"; http_raw_uri; " - "content:\"bambu\"; http_raw_uri; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len); - if (r != 1) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpRawUriTest18(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This_is_dummy_body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"body1\"; http_raw_uri; " - "content:\"bambu\"; http_raw_uri; fast_pattern; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len); - if (r != 0) { - printf("expected 0 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpRawUriTest19(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This_is_dummy_body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"bambu\"; http_raw_uri; " - "content:\"is\"; http_raw_uri; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len); - if (r != 0) { - printf("expected 0 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpRawUriTest20(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This_is_dummy_body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"bambu\"; http_raw_uri; " - "content:\"is\"; http_raw_uri; fast_pattern; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len); - if (r < 1) { - printf("expected result >= 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - static int DetectEngineHttpRawUriTest21(void) { TcpSession ssn; @@ -3762,14 +3466,6 @@ void DetectEngineHttpRawUriRegisterTests(void) DetectEngineHttpRawUriTest15); UtRegisterTest("DetectEngineHttpRawUriTest16", DetectEngineHttpRawUriTest16); - UtRegisterTest("DetectEngineHttpRawUriTest17", - DetectEngineHttpRawUriTest17); - UtRegisterTest("DetectEngineHttpRawUriTest18", - DetectEngineHttpRawUriTest18); - UtRegisterTest("DetectEngineHttpRawUriTest19", - DetectEngineHttpRawUriTest19); - UtRegisterTest("DetectEngineHttpRawUriTest20", - DetectEngineHttpRawUriTest20); UtRegisterTest("DetectEngineHttpRawUriTest21", DetectEngineHttpRawUriTest21); UtRegisterTest("DetectEngineHttpRawUriTest22", diff --git a/src/detect-engine-hrud.h b/src/detect-engine-hrud.h index e6f72d2461d4..9418b077ca2f 100644 --- a/src/detect-engine-hrud.h +++ b/src/detect-engine-hrud.h @@ -26,7 +26,7 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, void *txv); +int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpRawUri(ThreadVars *tv, DetectEngineCtx *de_ctx, diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 6ad75e8624cf..9402e2099ebf 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -50,6 +50,7 @@ #include "detect-engine-payload.h" #include "detect-engine-uri.h" +#include "detect-engine-hrud.h" #include "detect-engine-hmd.h" #include "detect-engine-dns.h" @@ -86,7 +87,8 @@ typedef struct AppLayerMpms_ { AppLayerMpms app_mpms[] = { { "http_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_UMATCH, SIG_GROUP_HEAD_MPM_URI, PrefilterTxUriRegister, 0 }, - { "http_raw_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRUDMATCH, SIG_GROUP_HEAD_MPM_HRUD, NULL, 1 }, + { "http_raw_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRUDMATCH, + SIG_GROUP_HEAD_MPM_HRUD, PrefilterTxRawUriRegister, 1 }, { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, NULL, 2}, { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, NULL, 3}, diff --git a/src/detect.c b/src/detect.c index 57a023791fe8..0788c6fe55af 100644 --- a/src/detect.c +++ b/src/detect.c @@ -902,14 +902,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, if (p->flowflags & FLOW_PKT_TOSERVER) { tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); - if (tx_progress > HTP_REQUEST_LINE) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRUD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRUD); - DetectEngineRunHttpRawUriMpm(det_ctx, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRUD); - } - } - if (tx_progress >= HTP_REQUEST_HEADERS) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHHD); From a43a69305ddaf543daeef8f86317f74506287465 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 Jul 2016 17:01:48 +0200 Subject: [PATCH 1891/2553] http_cookie: mpm prefilter engine --- src/detect-engine-hcd.c | 128 ++++++++++++++++++++++++---------------- src/detect-engine-hcd.h | 6 +- src/detect-engine-mpm.c | 7 ++- src/detect.c | 10 ---- 4 files changed, 84 insertions(+), 67 deletions(-) diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index 5372a4686d85..7f04da0edecf 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP cookie match * @@ -41,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -58,74 +60,96 @@ #include "app-layer-protos.h" #include "util-validate.h" -/** - * \brief Http cookie match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param cookie Cookie to inspect. - * \param cookie_len Cookie length. +/** \brief HTTP Cookie Mpm prefilter callback * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *cookie, const uint32_t cookie_len, - const uint8_t flags) +static void PrefilterTxRequestCookie(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - if (flags & STREAM_TOSERVER) { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcd_ctx_ts == NULL); + if (tx->request_headers == NULL) + return; - if (cookie_len >= det_ctx->sgh->mpm_hcd_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hcd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, cookie, cookie_len); - } - } else { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcd_ctx_tc == NULL); + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, + "Cookie"); + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP cookie header not present in this request"); + return; + } - if (cookie_len >= det_ctx->sgh->mpm_hcd_ctx_tc->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hcd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, cookie, cookie_len); - } + const uint32_t buffer_len = bstr_len(h->value); + const uint8_t *buffer = bstr_ptr(h->value); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } +} - SCReturnUInt(ret); +int PrefilterTxRequestCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxRequestCookie, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL); } -int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, - uint8_t flags, void *txv) +/** \brief HTTP Cookie Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxResponseCookie(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - uint32_t cnt = 0; + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; - if (tx->request_headers == NULL) - goto end; - htp_header_t *h = NULL; - if (flags & STREAM_TOSERVER) { - h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "Cookie"); - if (h == NULL) { - SCLogDebug("HTTP cookie header not present in this request"); - goto end; - } - } else { - h = (htp_header_t *)htp_table_get_c(tx->response_headers, - "Set-Cookie"); - if (h == NULL) { - SCLogDebug("HTTP Set-Cookie header not present in this request"); - goto end; - } + if (tx->response_headers == NULL) + return; + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers, + "Set-Cookie"); + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP cookie header not present in this request"); + return; } - cnt = HttpCookiePatternSearch(det_ctx, - (uint8_t *)bstr_ptr(h->value), - bstr_len(h->value), flags); - end: - return cnt; + const uint32_t buffer_len = bstr_len(h->value); + const uint8_t *buffer = bstr_ptr(h->value); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxResponseCookie, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS, + mpm_ctx, NULL); } /** diff --git a/src/detect-engine-hcd.h b/src/detect-engine-hcd.h index a3853c23d90b..f5c23514d867 100644 --- a/src/detect-engine-hcd.h +++ b/src/detect-engine-hcd.h @@ -25,6 +25,9 @@ #include "app-layer-htp.h" +int PrefilterTxRequestCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpCookie(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -32,9 +35,6 @@ int DetectEngineInspectHttpCookie(ThreadVars *tv, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, - uint8_t flags, void *tx); - void DetectEngineHttpCookieRegisterTests(void); #endif /* __DETECT_ENGINE_HCD_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 9402e2099ebf..9e640191ccfe 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -52,6 +52,7 @@ #include "detect-engine-uri.h" #include "detect-engine-hrud.h" #include "detect-engine-hmd.h" +#include "detect-engine-hcd.h" #include "detect-engine-dns.h" #include "stream.h" @@ -112,8 +113,10 @@ AppLayerMpms app_mpms[] = { { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, SIG_GROUP_HEAD_MPM_HHHD, NULL, 13}, { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, SIG_GROUP_HEAD_MPM_HRHHD, NULL, 14}, - { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, NULL, 15}, - { "http_cookie", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, NULL, 16}, + { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, + SIG_GROUP_HEAD_MPM_HCD, PrefilterTxRequestCookieRegister, 15}, + { "http_cookie", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HCDMATCH, + SIG_GROUP_HEAD_MPM_HCD, PrefilterTxResponseCookieRegister, 16}, { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, SIG_GROUP_HEAD_MPM_DNSQUERY, PrefilterTxDnsQueryRegister, 17}, diff --git a/src/detect.c b/src/detect.c index 0788c6fe55af..0eac7d725b0d 100644 --- a/src/detect.c +++ b/src/detect.c @@ -913,11 +913,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunHttpHRHMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHHD); } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCD); - DetectEngineRunHttpCookieMpm(det_ctx, flags, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCD); - } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HUAD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HUAD); DetectEngineRunHttpUAMpm(det_ctx, tx); @@ -967,11 +962,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHD); } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCD); - DetectEngineRunHttpCookieMpm(det_ctx, flags, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCD); - } } if (tx_progress > HTP_RESPONSE_HEADERS) { From 61c3748fc479510cf525dbee090dcb2d3c622750 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 Jul 2016 18:27:36 +0200 Subject: [PATCH 1892/2553] http_user_agent: mpm prefilter engine --- src/detect-engine-hua.c | 66 ++++++++++++++++++++--------------------- src/detect-engine-hua.h | 4 +-- src/detect-engine-mpm.c | 4 ++- src/detect.c | 5 ---- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index 6e8ad44d9531..4cfe46abce75 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP user agent match * @@ -40,6 +41,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -59,51 +61,49 @@ #include "detect-engine-hua.h" #include "util-validate.h" -/** - * \brief Http user agent match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param ua User-Agent to inspect. - * \param ua_len User-Agent buffer length. +/** \brief HTTP UA Mpm prefilter callback * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *ua, const uint32_t ua_len) +static void PrefilterTxUA(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_huad_ctx_ts == NULL); + if (tx->request_headers == NULL) + return; - if (ua_len >= det_ctx->sgh->mpm_huad_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, ua, ua_len); + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, + "User-Agent"); + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP UA header not present in this request"); + return; } - SCReturnUInt(ret); + const uint32_t buffer_len = bstr_len(h->value); + const uint8_t *buffer = bstr_ptr(h->value); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } } -int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, void *txv) +int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { - uint32_t cnt = 0; - htp_tx_t *tx = (htp_tx_t *)txv; - if (tx->request_headers == NULL) - goto end; + SCEnter(); - htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "User-Agent"); - if (h == NULL) { - SCLogDebug("HTTP user agent header not present in this request"); - goto end; - } - cnt = HttpUAPatternSearch(det_ctx, - (const uint8_t *)bstr_ptr(h->value), - bstr_len(h->value)); - end: - return cnt; + return PrefilterAppendTxEngine(sgh, PrefilterTxUA, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL); } /** diff --git a/src/detect-engine-hua.h b/src/detect-engine-hua.h index a6664e55ab5f..eceddf97b137 100644 --- a/src/detect-engine-hua.h +++ b/src/detect-engine-hua.h @@ -25,6 +25,8 @@ #include "app-layer-htp.h" +int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpUA(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -32,8 +34,6 @@ int DetectEngineInspectHttpUA(ThreadVars *tv, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, void *txv); - void DetectEngineHttpUARegisterTests(void); #endif /* __DETECT_ENGINE_HUA_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 9e640191ccfe..f2d393f1ea42 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -53,6 +53,7 @@ #include "detect-engine-hrud.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" +#include "detect-engine-hua.h" #include "detect-engine-dns.h" #include "stream.h" @@ -94,7 +95,8 @@ AppLayerMpms app_mpms[] = { { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, NULL, 2}, { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, NULL, 3}, - { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, SIG_GROUP_HEAD_MPM_HUAD, NULL, 4}, + { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, + SIG_GROUP_HEAD_MPM_HUAD, PrefilterTxUARegister, 4}, { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, NULL, 5}, { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, NULL, 6}, diff --git a/src/detect.c b/src/detect.c index 0eac7d725b0d..4448f5f26a18 100644 --- a/src/detect.c +++ b/src/detect.c @@ -913,11 +913,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunHttpHRHMpm(det_ctx, tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHHD); } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HUAD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HUAD); - DetectEngineRunHttpUAMpm(det_ctx, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HUAD); - } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHD); DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); From 521884921300cedca9c8ba8034d47c4c4d104bba Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 Jul 2016 18:38:33 +0200 Subject: [PATCH 1893/2553] http_host: mpm prefilter engine --- src/detect-engine-hhhd.c | 60 +++++++++++++++++++--------------------- src/detect-engine-hhhd.h | 6 ++-- src/detect-engine-mpm.c | 4 ++- src/detect.c | 5 ---- 4 files changed, 34 insertions(+), 41 deletions(-) diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index fbd4580d5c17..28d8d59b72fd 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP host header. * HHHD - Http Host Header Data @@ -41,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -60,49 +62,43 @@ #include "detect-engine-hhhd.h" #include "util-validate.h" -/** - * \brief Http host header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param hh Host header to inspect. - * \param hh_len Host header buffer length. - * \param flags Flags +/** \brief HTTP Host Mpm prefilter callback * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *hh, const uint32_t hh_len) +static void PrefilterTxHostname(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhhd_ctx_ts == NULL); + if (tx->request_hostname == NULL) + return; - if (hh_len >= det_ctx->sgh->mpm_hhhd_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hhhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, hh, hh_len); - } + const uint32_t buffer_len = bstr_len(tx->request_hostname); + const uint8_t *buffer = bstr_ptr(tx->request_hostname); - SCReturnUInt(ret); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } } -int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, void *txv) +int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { - uint32_t cnt = 0; - htp_tx_t *tx = (htp_tx_t *)txv; - if (tx->request_hostname == NULL) - goto end; - const uint8_t *hname = (const uint8_t *)bstr_ptr(tx->request_hostname); - if (hname == NULL) - goto end; - const uint32_t hname_len = bstr_len(tx->request_hostname); - - cnt = HttpHHPatternSearch(det_ctx, hname, hname_len); + SCEnter(); - end: - return cnt; + return PrefilterAppendTxEngine(sgh, PrefilterTxHostname, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL); } /** diff --git a/src/detect-engine-hhhd.h b/src/detect-engine-hhhd.h index fdfed26a2bbf..dab5080d42f4 100644 --- a/src/detect-engine-hhhd.h +++ b/src/detect-engine-hhhd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,6 +25,8 @@ #include "app-layer-htp.h" +int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpHH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -32,8 +34,6 @@ int DetectEngineInspectHttpHH(ThreadVars *tv, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, void *txv); - void DetectEngineHttpHHRegisterTests(void); #endif /* __DETECT_ENGINE_HHHD_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index f2d393f1ea42..f3f4736359a4 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -54,6 +54,7 @@ #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hua.h" +#include "detect-engine-hhhd.h" #include "detect-engine-dns.h" #include "stream.h" @@ -112,7 +113,8 @@ AppLayerMpms app_mpms[] = { { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, SIG_GROUP_HEAD_MPM_HCBD, NULL, 12}, - { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, SIG_GROUP_HEAD_MPM_HHHD, NULL, 13}, + { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, + SIG_GROUP_HEAD_MPM_HHHD, PrefilterTxHostnameRegister, 13}, { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, SIG_GROUP_HEAD_MPM_HRHHD, NULL, 14}, { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, diff --git a/src/detect.c b/src/detect.c index 4448f5f26a18..63c7bf57fa7d 100644 --- a/src/detect.c +++ b/src/detect.c @@ -903,11 +903,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); if (tx_progress >= HTP_REQUEST_HEADERS) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHHD); - DetectEngineRunHttpHHMpm(det_ctx, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHHD); - } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHHD); DetectEngineRunHttpHRHMpm(det_ctx, tx); From 86d303e32ba1cc7a4dba4a989b74387ab30b3d03 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 Jul 2016 18:48:54 +0200 Subject: [PATCH 1894/2553] http_raw_host: mpm prefilter engine --- src/detect-engine-hrhhd.c | 80 ++++++++++++++++++--------------------- src/detect-engine-hrhhd.h | 4 +- src/detect-engine-mpm.c | 4 +- src/detect.c | 5 --- 4 files changed, 41 insertions(+), 52 deletions(-) diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index 3debb11a37f1..eb5c97204b42 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP host header. * HRHHD - Http Raw Host Header Data @@ -41,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -60,65 +62,55 @@ #include "detect-engine-hrhhd.h" #include "util-validate.h" -/** - * \brief Http raw host header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param hrh Raw hostname to inspect. - * \param hrh_len Raw hostname buffer length. +/** \brief HTTP Host (Raw) Mpm prefilter callback * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *hrh, const uint32_t hrh_len) +static void PrefilterTxHostnameRaw(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; - - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL); - - if (hrh_len >= det_ctx->sgh->mpm_hrhhd_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrhhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, hrh, hrh_len); - } - - SCReturnUInt(ret); -} - -int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, void *txv) -{ - uint32_t cnt = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; const uint8_t *hname = NULL; uint32_t hname_len = 0; if (tx->parsed_uri == NULL || tx->parsed_uri->hostname == NULL) { if (tx->request_headers == NULL) - goto end; - htp_header_t *h = NULL; - h = (htp_header_t *)htp_table_get_c(tx->request_headers, "Host"); - if (h != NULL) { - hname = (const uint8_t *)bstr_ptr(h->value); - if (hname != NULL) - hname_len = bstr_len(h->value); - } else { - SCLogDebug("HTTP host header not present in this request"); - goto end; - } + return; + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, + "Host"); + if (h == NULL || h->value == NULL) + return; + + hname = (const uint8_t *)bstr_ptr(h->value); + hname_len = bstr_len(h->value); } else { - hname = (uint8_t *)bstr_ptr(tx->parsed_uri->hostname); - if (hname != NULL) - hname_len = bstr_len(tx->parsed_uri->hostname); + hname = (const uint8_t *)bstr_ptr(tx->parsed_uri->hostname); + hname_len = bstr_len(tx->parsed_uri->hostname); } - if (hname != NULL) { - cnt = HttpHRHPatternSearch(det_ctx, hname, hname_len); + if (hname != NULL && hname_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, hname, hname_len); } +} - end: - return cnt; +int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxHostnameRaw, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL); } /** diff --git a/src/detect-engine-hrhhd.h b/src/detect-engine-hrhhd.h index c939a173f09e..9fd427247d26 100644 --- a/src/detect-engine-hrhhd.h +++ b/src/detect-engine-hrhhd.h @@ -25,6 +25,8 @@ #include "app-layer-htp.h" +int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpHRH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -32,8 +34,6 @@ int DetectEngineInspectHttpHRH(ThreadVars *tv, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, void *txv); - void DetectEngineHttpHRHRegisterTests(void); #endif /* __DETECT_ENGINE_HRHHD_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index f3f4736359a4..481c77ddc6bc 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -55,6 +55,7 @@ #include "detect-engine-hcd.h" #include "detect-engine-hua.h" #include "detect-engine-hhhd.h" +#include "detect-engine-hrhhd.h" #include "detect-engine-dns.h" #include "stream.h" @@ -115,7 +116,8 @@ AppLayerMpms app_mpms[] = { { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, SIG_GROUP_HEAD_MPM_HHHD, PrefilterTxHostnameRegister, 13}, - { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, SIG_GROUP_HEAD_MPM_HRHHD, NULL, 14}, + { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, + SIG_GROUP_HEAD_MPM_HRHHD, PrefilterTxHostnameRawRegister, 14}, { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, SIG_GROUP_HEAD_MPM_HCD, PrefilterTxRequestCookieRegister, 15}, diff --git a/src/detect.c b/src/detect.c index 63c7bf57fa7d..6e524fd06a97 100644 --- a/src/detect.c +++ b/src/detect.c @@ -903,11 +903,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); if (tx_progress >= HTP_REQUEST_HEADERS) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHHD); - DetectEngineRunHttpHRHMpm(det_ctx, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHHD); - } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHD); DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); From 4d57b2fc6380d45b737c3adc619cef0fbc4c52ab Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 Jul 2016 19:28:46 +0200 Subject: [PATCH 1895/2553] http_stat_msg: mpm prefilter engine --- src/detect-engine-hsmd.c | 62 ++++++++++++++++++---------------------- src/detect-engine-hsmd.h | 4 +-- src/detect-engine-mpm.c | 4 ++- src/detect.c | 5 ---- 4 files changed, 33 insertions(+), 42 deletions(-) diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 46d3e4fe000a..b0d12e67b18b 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,6 +25,7 @@ * \file * * \author Anoop Saldanha + * \author Victor Julien */ #include "suricata-common.h" @@ -38,6 +39,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -55,52 +57,44 @@ #include "app-layer-protos.h" #include "util-validate.h" -/** - * \brief Http stat msg match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param stat_msg Stat msg to inspect. - * \param stat_msg_len Stat msg length. +/** \brief HTTP Status Message Mpm prefilter callback * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *stat_msg, const uint32_t stat_msg_len) +static void PrefilterTxHttpStatMsg(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsmd_ctx_tc == NULL); + if (tx->response_message == NULL) + return; - if (stat_msg_len >= det_ctx->sgh->mpm_hsmd_ctx_tc->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hsmd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, stat_msg, stat_msg_len); - } + const uint32_t buffer_len = bstr_len(tx->response_message); + const uint8_t *buffer = bstr_ptr(tx->response_message); - SCReturnUInt(ret); + if (buffer != NULL && buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } } -/** - * \brief Run the mpm against http stat msg. - * - * \retval cnt Number of matches reported by the mpm algo. - */ -int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, void *txv) +int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); - uint32_t cnt = 0; - htp_tx_t *tx = (htp_tx_t *)txv; - if (tx->response_message == NULL) - goto end; - - cnt = HttpStatMsgPatternSearch(det_ctx, - (const uint8_t *)bstr_ptr(tx->response_message), - bstr_len(tx->response_message)); -end: - SCReturnInt(cnt); + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpStatMsg, + ALPROTO_HTTP, + HTP_RESPONSE_LINE+1, /* inspect when response line completely parsed */ + mpm_ctx, NULL); } /** diff --git a/src/detect-engine-hsmd.h b/src/detect-engine-hsmd.h index 9faa2064f8b7..2feddd3bdcd3 100644 --- a/src/detect-engine-hsmd.h +++ b/src/detect-engine-hsmd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,7 +25,7 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, void *txv); +int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpStatMsg(ThreadVars *tv, DetectEngineCtx *de_ctx, diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 481c77ddc6bc..a8a3a3de3dbc 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -56,6 +56,7 @@ #include "detect-engine-hua.h" #include "detect-engine-hhhd.h" #include "detect-engine-hrhhd.h" +#include "detect-engine-hsmd.h" #include "detect-engine-dns.h" #include "stream.h" @@ -109,7 +110,8 @@ AppLayerMpms app_mpms[] = { { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_FD_SMTP, NULL, 8}, /* smtp */ { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_HSBD, NULL, 9}, /* http server body */ - { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, SIG_GROUP_HEAD_MPM_HSMD, NULL, 10}, + { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, + SIG_GROUP_HEAD_MPM_HSMD, PrefilterTxHttpStatMsgRegister, 10}, { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, SIG_GROUP_HEAD_MPM_HSCD, NULL, 11}, { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, SIG_GROUP_HEAD_MPM_HCBD, NULL, 12}, diff --git a/src/detect.c b/src/detect.c index 6e524fd06a97..7216425cec8a 100644 --- a/src/detect.c +++ b/src/detect.c @@ -929,11 +929,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); if (tx_progress > HTP_RESPONSE_LINE) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSMD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSMD); - DetectEngineRunHttpStatMsgMpm(det_ctx, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSMD); - } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSCD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSCD); DetectEngineRunHttpStatCodeMpm(det_ctx, tx); From 9cab3ea2cdf78e815714febcf364317fb7072f60 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 8 Jul 2016 19:35:13 +0200 Subject: [PATCH 1896/2553] http_stat_code: mpm prefilter engine --- src/detect-engine-hscd.c | 62 ++++++++++++++++++---------------------- src/detect-engine-hscd.h | 4 +-- src/detect-engine-mpm.c | 4 ++- src/detect.c | 8 ------ 4 files changed, 33 insertions(+), 45 deletions(-) diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 8d0cbbee5a35..205005570f3b 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,6 +25,7 @@ * \file * * \author Anoop Saldanha + * \author Victor Julien */ #include "suricata-common.h" @@ -38,6 +39,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -55,52 +57,44 @@ #include "app-layer-protos.h" #include "util-validate.h" -/** - * \brief Http stat code match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param stat_code Stat code to inspect. - * \param stat_code_len Stat code length. +/** \brief HTTP Status Code Mpm prefilter callback * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *stat_code, const uint32_t stat_code_len) +static void PrefilterTxHttpStatCode(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hscd_ctx_tc == NULL); + if (tx->response_status == NULL) + return; - if (stat_code_len >= det_ctx->sgh->mpm_hscd_ctx_tc->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hscd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, stat_code, stat_code_len); - } + const uint32_t buffer_len = bstr_len(tx->response_status); + const uint8_t *buffer = bstr_ptr(tx->response_status); - SCReturnUInt(ret); + if (buffer != NULL && buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } } -/** - * \brief Run the mpm against http stat code. - * - * \retval cnt Number of matches reported by the mpm algo. - */ -int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, void *txv) +int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); - uint32_t cnt = 0; - htp_tx_t *tx = (htp_tx_t *)txv; - if (tx->response_status == NULL) - goto end; - - cnt = HttpStatCodePatternSearch(det_ctx, - (const uint8_t *)bstr_ptr(tx->response_status), - bstr_len(tx->response_status)); -end: - SCReturnInt(cnt); + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpStatCode, + ALPROTO_HTTP, + HTP_RESPONSE_LINE+1, /* inspect when response line completely parsed */ + mpm_ctx, NULL); } /** diff --git a/src/detect-engine-hscd.h b/src/detect-engine-hscd.h index d85921d3ebe6..73977eccec37 100644 --- a/src/detect-engine-hscd.h +++ b/src/detect-engine-hscd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,7 +25,7 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, void *txv); +int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpStatCode(ThreadVars *tv, DetectEngineCtx *de_ctx, diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index a8a3a3de3dbc..a231fdcf708e 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -57,6 +57,7 @@ #include "detect-engine-hhhd.h" #include "detect-engine-hrhhd.h" #include "detect-engine-hsmd.h" +#include "detect-engine-hscd.h" #include "detect-engine-dns.h" #include "stream.h" @@ -112,7 +113,8 @@ AppLayerMpms app_mpms[] = { { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, SIG_GROUP_HEAD_MPM_HSMD, PrefilterTxHttpStatMsgRegister, 10}, - { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, SIG_GROUP_HEAD_MPM_HSCD, NULL, 11}, + { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, + SIG_GROUP_HEAD_MPM_HSCD, PrefilterTxHttpStatCodeRegister, 11}, { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, SIG_GROUP_HEAD_MPM_HCBD, NULL, 12}, diff --git a/src/detect.c b/src/detect.c index 7216425cec8a..701eca169cc7 100644 --- a/src/detect.c +++ b/src/detect.c @@ -928,14 +928,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } else { /* implied FLOW_PKT_TOCLIENT */ tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); - if (tx_progress > HTP_RESPONSE_LINE) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSCD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSCD); - DetectEngineRunHttpStatCodeMpm(det_ctx, tx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSCD); - } - } - if (tx_progress >= HTP_RESPONSE_HEADERS) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHD); From 9b6fd6bb48d1d8284e253e8bc44eb7d1c2834280 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 9 Jul 2016 07:16:58 +0200 Subject: [PATCH 1897/2553] http_headers: mpm prefilter engines Register for both regular headers and trailers. --- src/detect-engine-hhd.c | 267 ++++++++++++---------------------------- src/detect-engine-hhd.h | 6 +- src/detect-engine-mpm.c | 7 +- src/detect.c | 16 --- 4 files changed, 85 insertions(+), 211 deletions(-) diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 228189135657..9523f948a6fd 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -41,6 +41,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -214,62 +215,102 @@ static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return headers_buffer; } -/** - * \brief Http header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param headers Headers to inspect. - * \param headers_len Headers length. +/** \brief HTTP Headers Mpm prefilter callback * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *headers, const uint32_t headers_len, - const uint8_t flags) +static void PrefilterTxHttpRequestHeaders(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - if (flags & STREAM_TOSERVER) { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhd_ctx_ts == NULL); + if (tx->request_headers == NULL) + return; - if (headers_len >= det_ctx->sgh->mpm_hhd_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, headers, headers_len); - } - } else { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hhd_ctx_tc == NULL); + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); - if (headers_len >= det_ctx->sgh->mpm_hhd_ctx_tc->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hhd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, headers, headers_len); - } + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } +} - SCReturnUInt(ret); +int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaders, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL); + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaders, + ALPROTO_HTTP, HTP_REQUEST_TRAILER, + mpm_ctx, NULL); } -int DetectEngineRunHttpHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx) +/** \brief HTTP Headers Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpResponseHeaders(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - uint32_t cnt = 0; + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return; + + HtpState *htp_state = f->alstate; uint32_t buffer_len = 0; - uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, NULL, det_ctx, f, htp_state, flags, &buffer_len); - if (buffer_len == 0) - goto end; - cnt = HttpHeaderPatternSearch(det_ctx, buffer, buffer_len, flags); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} - end: - return cnt; +int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaders, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS, + mpm_ctx, NULL); + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaders, + ALPROTO_HTTP, HTP_RESPONSE_TRAILER, + mpm_ctx, NULL); } int DetectEngineInspectHttpHeader(ThreadVars *tv, @@ -1979,156 +2020,6 @@ static int DetectEngineHttpHeaderTest17(void) return result; } -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest18(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http_buf[] = - "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"five\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = HttpHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); - if (r < 1) { - printf("expected result >= 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest19(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http_buf[] = - "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; fast_pattern; content:\"five\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = HttpHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); - if (r != 1) { - printf("expected result 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - static int DetectEngineHttpHeaderTest20(void) { TcpSession ssn; @@ -3939,10 +3830,6 @@ void DetectEngineHttpHeaderRegisterTests(void) DetectEngineHttpHeaderTest16); UtRegisterTest("DetectEngineHttpHeaderTest17", DetectEngineHttpHeaderTest17); - UtRegisterTest("DetectEngineHttpHeaderTest18", - DetectEngineHttpHeaderTest18); - UtRegisterTest("DetectEngineHttpHeaderTest19", - DetectEngineHttpHeaderTest19); UtRegisterTest("DetectEngineHttpHeaderTest20", DetectEngineHttpHeaderTest20); UtRegisterTest("DetectEngineHttpHeaderTest21", diff --git a/src/detect-engine-hhd.h b/src/detect-engine-hhd.h index e163000c71af..9826dcda5ab2 100644 --- a/src/detect-engine-hhd.h +++ b/src/detect-engine-hhd.h @@ -25,15 +25,15 @@ #include "app-layer-htp.h" +int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx); void DetectEngineHttpHeaderRegisterTests(void); diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index a231fdcf708e..f9776b947c85 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -52,6 +52,7 @@ #include "detect-engine-uri.h" #include "detect-engine-hrud.h" #include "detect-engine-hmd.h" +#include "detect-engine-hhd.h" #include "detect-engine-hcd.h" #include "detect-engine-hua.h" #include "detect-engine-hhhd.h" @@ -96,8 +97,10 @@ AppLayerMpms app_mpms[] = { { "http_raw_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRUDMATCH, SIG_GROUP_HEAD_MPM_HRUD, PrefilterTxRawUriRegister, 1 }, - { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, NULL, 2}, - { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, SIG_GROUP_HEAD_MPM_HHD, NULL, 3}, + { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, + SIG_GROUP_HEAD_MPM_HHD, PrefilterTxHttpRequestHeadersRegister, 2}, + { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, + SIG_GROUP_HEAD_MPM_HHD, PrefilterTxHttpRequestHeadersRegister, 3}, { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, SIG_GROUP_HEAD_MPM_HUAD, PrefilterTxUARegister, 4}, diff --git a/src/detect.c b/src/detect.c index 701eca169cc7..9bc2adef8867 100644 --- a/src/detect.c +++ b/src/detect.c @@ -902,14 +902,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, if (p->flowflags & FLOW_PKT_TOSERVER) { tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); - if (tx_progress >= HTP_REQUEST_HEADERS) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHD); - DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHD); - } - } - if (tx_progress > HTP_REQUEST_HEADERS) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHD); @@ -928,14 +920,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } else { /* implied FLOW_PKT_TOCLIENT */ tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); - if (tx_progress >= HTP_RESPONSE_HEADERS) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHD); - DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHD); - } - } - if (tx_progress > HTP_RESPONSE_HEADERS) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHD); From 5646dd9ecf8b0032c2389a8ef2bcdacf693e208d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 9 Jul 2016 07:59:29 +0200 Subject: [PATCH 1898/2553] http_client_body: mpm prefilter engine --- src/detect-engine-hcbd.c | 66 ++++++++++++++++++---------------------- src/detect-engine-hcbd.h | 6 ++-- src/detect-engine-mpm.c | 4 ++- src/detect.c | 7 ----- 4 files changed, 34 insertions(+), 49 deletions(-) diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index c0016f9b18b6..933f0cd54646 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP request body match corresponding to http_client_body * keyword. @@ -41,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -212,56 +214,46 @@ static const uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_i return buffer; } -/** \brief Http client body pattern match -- searches for one pattern per - * signature. +/** \brief HTTP Client Body Mpm prefilter callback * - * \param det_ctx Detection engine thread ctx. - * \param body The request body to inspect. - * \param body_len Body length. - * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *body, const uint32_t body_len, - const uint8_t flags) +static void PrefilterTxHttpRequestBody(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hcbd_ctx_ts == NULL); - - if (body_len >= det_ctx->sgh->mpm_hcbd_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hcbd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, body, body_len); - } - - SCReturnUInt(ret); -} - -int DetectEngineRunHttpClientBodyMpm(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx) -{ - uint32_t cnt = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + HtpState *htp_state = f->alstate; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; const uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, idx, - de_ctx, det_ctx, + NULL, det_ctx, f, htp_state, flags, &buffer_len, &stream_start_offset); - if (buffer_len == 0) - goto end; - cnt = HttpClientBodyPatternSearch(det_ctx, (uint8_t *)buffer, buffer_len, flags); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxHttpRequestBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); - end: - return cnt; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestBody, + ALPROTO_HTTP, HTP_REQUEST_BODY, + mpm_ctx, NULL); } int DetectEngineInspectHttpClientBody(ThreadVars *tv, diff --git a/src/detect-engine-hcbd.h b/src/detect-engine-hcbd.h index 6dce3230c9a2..4ed0b5088590 100644 --- a/src/detect-engine-hcbd.h +++ b/src/detect-engine-hcbd.h @@ -27,10 +27,8 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpClientBodyMpm(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); +int PrefilterTxHttpRequestBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpClientBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index f9776b947c85..68fabfe3e5a2 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -59,6 +59,7 @@ #include "detect-engine-hrhhd.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" +#include "detect-engine-hcbd.h" #include "detect-engine-dns.h" #include "stream.h" @@ -119,7 +120,8 @@ AppLayerMpms app_mpms[] = { { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, SIG_GROUP_HEAD_MPM_HSCD, PrefilterTxHttpStatCodeRegister, 11}, - { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, SIG_GROUP_HEAD_MPM_HCBD, NULL, 12}, + { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, + SIG_GROUP_HEAD_MPM_HCBD, PrefilterTxHttpRequestBodyRegister, 12}, { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, SIG_GROUP_HEAD_MPM_HHHD, PrefilterTxHostnameRegister, 13}, diff --git a/src/detect.c b/src/detect.c index 9bc2adef8867..d2486b43eccb 100644 --- a/src/detect.c +++ b/src/detect.c @@ -910,13 +910,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, } } - if (tx_progress >= HTP_REQUEST_BODY) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCBD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCBD); - DetectEngineRunHttpClientBodyMpm(de_ctx, det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCBD); - } - } } else { /* implied FLOW_PKT_TOCLIENT */ tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); From cef12ed80f8bf9db3c9a12d8f3bcbb031f27efd9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 9 Jul 2016 08:11:31 +0200 Subject: [PATCH 1899/2553] http_server_body / file_data: mpm prefilter engine --- src/detect-engine-hsbd.c | 66 ++++++++++++++++++---------------------- src/detect-engine-hsbd.h | 6 ++-- src/detect-engine-mpm.c | 4 ++- src/detect.c | 8 ----- 4 files changed, 34 insertions(+), 50 deletions(-) diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 694fabe5ef9f..87a6827e8e84 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -42,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -217,58 +218,49 @@ static const uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_i return buffer; } -/** \brief Http server body pattern match -- searches for one pattern per - * signature. +/** \brief HTTP Server Body Mpm prefilter callback * - * \param det_ctx Detection engine thread ctx. - * \param body The request body to inspect. - * \param body_len Body length. - * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *body, const uint32_t body_len, - const uint8_t flags) +static void PrefilterTxHttpResponseBody(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; - - DEBUG_VALIDATE_BUG_ON(!(flags & STREAM_TOCLIENT)); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hsbd_ctx_tc == NULL); - - if (body_len >= det_ctx->sgh->mpm_hsbd_ctx_tc->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hsbd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, body, body_len); - } - - SCReturnUInt(ret); -} - -int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx) -{ - uint32_t cnt = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + HtpState *htp_state = f->alstate; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; const uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, idx, - de_ctx, det_ctx, + NULL, det_ctx, f, htp_state, flags, &buffer_len, &stream_start_offset); - if (buffer_len == 0) - goto end; - cnt = HttpServerBodyPatternSearch(det_ctx, (uint8_t *)buffer, buffer_len, flags); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} - end: - return cnt; +int PrefilterTxHttpResponseBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseBody, + ALPROTO_HTTP, HTP_RESPONSE_BODY, + mpm_ctx, NULL); } + int DetectEngineInspectHttpServerBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine-hsbd.h b/src/detect-engine-hsbd.h index a44248245fce..edb8d17d91cc 100644 --- a/src/detect-engine-hsbd.h +++ b/src/detect-engine-hsbd.h @@ -27,10 +27,8 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); +int PrefilterTxHttpResponseBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpServerBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 68fabfe3e5a2..c6f7ef70ff6f 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -60,6 +60,7 @@ #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" #include "detect-engine-hcbd.h" +#include "detect-engine-hsbd.h" #include "detect-engine-dns.h" #include "stream.h" @@ -113,7 +114,8 @@ AppLayerMpms app_mpms[] = { SIG_GROUP_HEAD_MPM_HMD, PrefilterTxMethodRegister, 7}, { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_FD_SMTP, NULL, 8}, /* smtp */ - { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_HSBD, NULL, 9}, /* http server body */ + { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, + SIG_GROUP_HEAD_MPM_HSBD, PrefilterTxHttpResponseBodyRegister, 9}, /* http server body */ { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, SIG_GROUP_HEAD_MPM_HSMD, PrefilterTxHttpStatMsgRegister, 10}, diff --git a/src/detect.c b/src/detect.c index d2486b43eccb..4fc038683b18 100644 --- a/src/detect.c +++ b/src/detect.c @@ -920,14 +920,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHD); } } - - if (tx_progress >= HTP_RESPONSE_BODY) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSBD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSBD); - DetectEngineRunHttpServerBodyMpm(de_ctx, det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSBD); - } - } } } /* for */ } else if (alproto == ALPROTO_TLS && has_state) { From 0019a7bd9f36916ccb699793d5af4893ee88dcda Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 9 Jul 2016 08:27:56 +0200 Subject: [PATCH 1900/2553] http_raw_header: mpm prefilter engine Register for both regular headers and trailer. --- src/detect-engine-hrhd.c | 275 ++++++++++----------------------------- src/detect-engine-hrhd.h | 6 +- src/detect-engine-mpm.c | 7 +- src/detect.c | 47 +------ 4 files changed, 79 insertions(+), 256 deletions(-) diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 496f9b5b4f48..c20135c0f029 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP raw header match. * @@ -41,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -59,75 +61,92 @@ #include "util-validate.h" -/** - * \brief Http raw header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param raw_headers Raw headers to inspect. - * \param raw_headers_len Raw headers length. +/** \brief HTTP Raw Header Mpm prefilter callback * - * \retval ret Number of matches. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *raw_headers, const uint32_t raw_headers_len, - const uint8_t flags) +static void PrefilterTxRequestHeadersRaw(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; - - if (flags & STREAM_TOSERVER) { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhd_ctx_ts == NULL); + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + if (tx_ud == NULL || tx_ud->request_headers_raw == NULL) + return; - if (raw_headers_len >= det_ctx->sgh->mpm_hrhd_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, raw_headers, raw_headers_len); - } - } else { - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_hrhd_ctx_tc == NULL); + const uint32_t buffer_len = tx_ud->request_headers_raw_len; + const uint8_t *buffer = tx_ud->request_headers_raw; - if (raw_headers_len >= det_ctx->sgh->mpm_hrhd_ctx_tc->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hrhd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, raw_headers, raw_headers_len); - } + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } - - SCReturnUInt(ret); } -int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +int PrefilterTxRequestHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); - uint32_t cnt = 0; + int r = PrefilterAppendTxEngine(sgh, PrefilterTxRequestHeadersRaw, + ALPROTO_HTTP, HTP_REQUEST_HEADERS+1, /* inspect when headers complete */ + mpm_ctx, NULL); + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxRequestHeadersRaw, + ALPROTO_HTTP, HTP_REQUEST_TRAILER+1, /* inspect when trailer complete */ + mpm_ctx, NULL); +} + +/** \brief HTTP Raw Header Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxResponseHeadersRaw(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - if (tx_ud == NULL) { - SCReturnInt(0); - } + if (tx_ud == NULL || tx_ud->response_headers_raw == NULL) + return; - if (flags & STREAM_TOSERVER) { - if (tx_ud->request_headers_raw != NULL) { - cnt = HttpRawHeaderPatternSearch(det_ctx, - tx_ud->request_headers_raw, - tx_ud->request_headers_raw_len, - flags); - } - } else { - if (tx_ud->response_headers_raw != NULL) { - cnt = HttpRawHeaderPatternSearch(det_ctx, - tx_ud->response_headers_raw, - tx_ud->response_headers_raw_len, - flags); - } + const uint32_t buffer_len = tx_ud->response_headers_raw_len; + const uint8_t *buffer = tx_ud->response_headers_raw; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } +} - SCReturnInt(cnt); +int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxResponseHeadersRaw, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS+1, /* inspect when headers complete */ + mpm_ctx, NULL); + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxResponseHeadersRaw, + ALPROTO_HTTP, HTP_RESPONSE_TRAILER+1, /* inspect when trailer complete */ + mpm_ctx, NULL); } /** @@ -1851,156 +1870,6 @@ static int DetectEngineHttpRawHeaderTest17(void) return result; } -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpRawHeaderTest18(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http_buf[] = - "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; content:\"five\"; http_raw_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = HttpRawHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); - if (r < 1) { - printf("expected result >= 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpRawHeaderTest19(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http_buf[] = - "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; fast_pattern; content:\"five\"; http_raw_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = HttpRawHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); - if (r != 1) { - printf("expected result 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - static int DetectEngineHttpRawHeaderTest20(void) { TcpSession ssn; @@ -3577,10 +3446,6 @@ void DetectEngineHttpRawHeaderRegisterTests(void) DetectEngineHttpRawHeaderTest16); UtRegisterTest("DetectEngineHttpRawHeaderTest17", DetectEngineHttpRawHeaderTest17); - UtRegisterTest("DetectEngineHttpRawHeaderTest18", - DetectEngineHttpRawHeaderTest18); - UtRegisterTest("DetectEngineHttpRawHeaderTest19", - DetectEngineHttpRawHeaderTest19); UtRegisterTest("DetectEngineHttpRawHeaderTest20", DetectEngineHttpRawHeaderTest20); UtRegisterTest("DetectEngineHttpRawHeaderTest21", diff --git a/src/detect-engine-hrhd.h b/src/detect-engine-hrhd.h index c33d57e7d7e4..6d043f3cf040 100644 --- a/src/detect-engine-hrhd.h +++ b/src/detect-engine-hrhd.h @@ -25,15 +25,15 @@ #include "app-layer-htp.h" +int PrefilterTxRequestHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpRawHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); -int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); void DetectEngineHttpRawHeaderRegisterTests(void); #endif /* __DETECT_ENGINE_HHD_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index c6f7ef70ff6f..d142872e828a 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -53,6 +53,7 @@ #include "detect-engine-hrud.h" #include "detect-engine-hmd.h" #include "detect-engine-hhd.h" +#include "detect-engine-hrhd.h" #include "detect-engine-hcd.h" #include "detect-engine-hua.h" #include "detect-engine-hhhd.h" @@ -107,8 +108,10 @@ AppLayerMpms app_mpms[] = { { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, SIG_GROUP_HEAD_MPM_HUAD, PrefilterTxUARegister, 4}, - { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, NULL, 5}, - { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, SIG_GROUP_HEAD_MPM_HRHD, NULL, 6}, + { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, + SIG_GROUP_HEAD_MPM_HRHD, PrefilterTxRequestHeadersRawRegister, 5}, + { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, + SIG_GROUP_HEAD_MPM_HRHD, PrefilterTxResponseHeadersRawRegister, 6}, { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, SIG_GROUP_HEAD_MPM_HMD, PrefilterTxMethodRegister, 7}, diff --git a/src/detect.c b/src/detect.c index 4fc038683b18..1e72d656567b 100644 --- a/src/detect.c +++ b/src/detect.c @@ -877,52 +877,7 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, if (p->flowflags & FLOW_PKT_ESTABLISHED) { SCLogDebug("p->flowflags & FLOW_PKT_ESTABLISHED"); - /* all http based mpms */ - if (has_state && alproto == ALPROTO_HTTP) { - void *alstate = FlowGetAppState(p->flow); - if (alstate == NULL) { - SCLogDebug("no alstate"); - return; - } - - HtpState *htp_state = (HtpState *)alstate; - if (htp_state->connp == NULL) { - SCLogDebug("no HTTP connp"); - return; - } - - int tx_progress = 0; - uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); - uint64_t total_txs = AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, alstate); - for (; idx < total_txs; idx++) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, idx); - if (tx == NULL) - continue; - - if (p->flowflags & FLOW_PKT_TOSERVER) { - tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); - - if (tx_progress > HTP_REQUEST_HEADERS) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHD); - DetectEngineRunHttpRawHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHD); - } - } - - } else { /* implied FLOW_PKT_TOCLIENT */ - tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags); - - if (tx_progress > HTP_RESPONSE_HEADERS) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHD); - DetectEngineRunHttpRawHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHD); - } - } - } - } /* for */ - } else if (alproto == ALPROTO_TLS && has_state) { + if (alproto == ALPROTO_TLS && has_state) { void *alstate = FlowGetAppState(p->flow); if (alstate == NULL) { SCLogDebug("no alstate"); From 7acdc660613918e6279318f45e8d966beb35b0d3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 9 Jul 2016 08:47:45 +0200 Subject: [PATCH 1901/2553] smtp file_data: mpm prefilter engine --- src/detect-engine-filedata-smtp.c | 77 ++++++++++++++----------------- src/detect-engine-filedata-smtp.h | 7 +-- src/detect-engine-mpm.c | 4 +- src/detect.c | 23 --------- 4 files changed, 39 insertions(+), 72 deletions(-) diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 4e65b8ce43d1..422c19cebad7 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Open Information Security Foundation +/* Copyright (C) 2015-2016 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 @@ -19,6 +19,7 @@ /** \file * * \author Giuseppe Longo + * \author Victor Julien * */ @@ -32,6 +33,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -233,64 +235,53 @@ void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx) return; } -/** - * \brief SMTP Filedata match -- searches for one pattern per signature. +/** \brief SMTP Filedata Mpm prefilter callback * - * \param det_ctx Detection engine thread ctx. - * \param buffer Buffer to inspect. - * \param buffer_len buffer length. - * \param flags Flags + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context * - * \retval ret Number of matches. + * \todo check files against actual tx */ -static inline uint32_t SMTPFiledataPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *buffer, const uint32_t buffer_len, - const uint8_t flags) +static void PrefilterTxSmtpFiledata(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; - - DEBUG_VALIDATE_BUG_ON(flags & STREAM_TOCLIENT); - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_smtp_filedata_ctx_ts == NULL); - - if (buffer_len >= det_ctx->sgh->mpm_smtp_filedata_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_smtp_filedata_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_smtp_filedata_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); - } - - SCReturnUInt(ret); -} - -int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow *f, - SMTPState *smtp_state, uint8_t flags, - void *tx, uint64_t idx) -{ + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + SMTPState *smtp_state = f->alstate; FileContainer *ffc = smtp_state->files_ts; - uint32_t cnt = 0; - uint32_t buffer_len = 0; - uint32_t stream_start_offset = 0; - const uint8_t *buffer = NULL; - if (ffc != NULL) { File *file = ffc->head; for (; file != NULL; file = file->next) { - buffer = DetectEngineSMTPGetBufferForTX(idx, - de_ctx, det_ctx, + uint32_t buffer_len = 0; + uint32_t stream_start_offset = 0; + + const uint8_t *buffer = DetectEngineSMTPGetBufferForTX(idx, + NULL, det_ctx, f, file, flags, &buffer_len, &stream_start_offset); - if (buffer_len == 0) - goto end; - - cnt += SMTPFiledataPatternSearch(det_ctx, (uint8_t *)buffer, buffer_len, flags); + if (buffer != NULL && buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } } } -end: - return cnt; +} + +int PrefilterTxSmtpFiledataRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxSmtpFiledata, + ALPROTO_SMTP, 0, + mpm_ctx, NULL); } #ifdef UNITTESTS diff --git a/src/detect-engine-filedata-smtp.h b/src/detect-engine-filedata-smtp.h index e04832b77b0e..f4f45af0df7a 100644 --- a/src/detect-engine-filedata-smtp.h +++ b/src/detect-engine-filedata-smtp.h @@ -25,6 +25,8 @@ #include "app-layer-smtp.h" +int PrefilterTxSmtpFiledataRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectSMTPFiledata(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -33,11 +35,6 @@ int DetectEngineInspectSMTPFiledata(ThreadVars *tv, void *tx, uint64_t tx_id); void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx); -int DetectEngineRunSMTPMpm(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow *f, - SMTPState *smtp_state, uint8_t flags, - void *tx, uint64_t idx); - void DetectEngineSMTPFiledataRegisterTests(void); #endif /* __DETECT_ENGINE_FILEDATA_SMTP_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index d142872e828a..71ebe9353009 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -63,6 +63,7 @@ #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-dns.h" +#include "detect-engine-filedata-smtp.h" #include "stream.h" @@ -116,7 +117,8 @@ AppLayerMpms app_mpms[] = { { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, SIG_GROUP_HEAD_MPM_HMD, PrefilterTxMethodRegister, 7}, - { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_FD_SMTP, NULL, 8}, /* smtp */ + { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, + SIG_GROUP_HEAD_MPM_FD_SMTP, PrefilterTxSmtpFiledataRegister, 8}, /* smtp */ { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, SIG_GROUP_HEAD_MPM_HSBD, PrefilterTxHttpResponseBodyRegister, 9}, /* http server body */ diff --git a/src/detect.c b/src/detect.c index 1e72d656567b..3aad7940acf6 100644 --- a/src/detect.c +++ b/src/detect.c @@ -902,29 +902,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSUBJECT); } } - } else if (alproto == ALPROTO_SMTP && has_state) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_FD_SMTP) { - void *alstate = FlowGetAppState(p->flow); - if (alstate == NULL) { - SCLogDebug("no alstate"); - return; - } - - SMTPState *smtp_state = (SMTPState *)alstate; - uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); - uint64_t total_txs = AppLayerParserGetTxCnt(p->flow->proto, alproto, alstate); - for (; idx < total_txs; idx++) { - void *tx = AppLayerParserGetTx(p->flow->proto, alproto, alstate, idx); - if (tx == NULL) - continue; - - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_FD_SMTP); - DetectEngineRunSMTPMpm(de_ctx, det_ctx, p->flow, smtp_state, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_FD_SMTP); - } - } - } } } else { SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); From 08407b6d47606f625bf4f0c502df254659fa9843 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 9 Jul 2016 09:05:58 +0200 Subject: [PATCH 1902/2553] tls: mpm prefilter engines --- src/detect-engine-mpm.c | 10 +- src/detect-engine-tls.c | 198 ++++++++++++---------------------- src/detect-engine-tls.h | 4 + src/detect-tls-cert-issuer.h | 2 - src/detect-tls-cert-subject.h | 2 - src/detect.c | 27 ----- 6 files changed, 81 insertions(+), 162 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 71ebe9353009..6c94e7a4a8f9 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -64,6 +64,7 @@ #include "detect-engine-hsbd.h" #include "detect-engine-dns.h" #include "detect-engine-filedata-smtp.h" +#include "detect-engine-tls.h" #include "stream.h" @@ -143,9 +144,12 @@ AppLayerMpms app_mpms[] = { { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, SIG_GROUP_HEAD_MPM_DNSQUERY, PrefilterTxDnsQueryRegister, 17}, - { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, SIG_GROUP_HEAD_MPM_TLSSNI, NULL, 18}, - { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, SIG_GROUP_HEAD_MPM_TLSISSUER, NULL, 19}, - { "tls_cert_subject", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSSUBJECT_MATCH, SIG_GROUP_HEAD_MPM_TLSSUBJECT, NULL, 20}, + { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, + SIG_GROUP_HEAD_MPM_TLSSNI, PrefilterTxTlsSniRegister, 18}, + { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, + SIG_GROUP_HEAD_MPM_TLSISSUER, PrefilterTxTlsIssuerRegister, 19}, + { "tls_cert_subject", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSSUBJECT_MATCH, + SIG_GROUP_HEAD_MPM_TLSSUBJECT, PrefilterTxTlsSubjectRegister, 20}, { NULL, 0, 0, 0, 0, NULL, 0, } }; diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 940833106c01..a4ce75caf382 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -30,6 +30,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -45,63 +46,42 @@ #include "util-unittest-helper.h" #include "util-validate.h" -/** - * \brief TLS sni match -- searches for one pattern per signature. +/** \brief TLS SNI Mpm prefilter callback * - * \param det_ctx Detection engine thread ctx - * \param hrh Buffer to inspect - * \param hrh_len Buffer length - * \param flags Flags - * - * \retval ret Number of matches + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t TlsSniPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *buffer, - const uint32_t buffer_len) +static void PrefilterTxTlsSni(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + SSLState *ssl_state = f->alstate; + + if (ssl_state->client_connp.sni == NULL) + return; - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_tlssni_ctx_ts == NULL); + const uint8_t *buffer = (uint8_t *)ssl_state->client_connp.sni; + const uint32_t buffer_len = strlen(ssl_state->client_connp.sni); - if (buffer_len >= det_ctx->sgh->mpm_tlssni_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_tlssni_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_tlssni_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } - - SCReturnUInt(ret); } -/** - * \brief Run the pattern matcher against the SNI buffer - * - * \param det_ctx Detection engine thread ctx - * \param f Locked flow - * \param dns_state Initialized dns state - * \param flags Flags - * - * \retval cnt Number of matches - */ -uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, - SSLState *ssl_state) +int PrefilterTxTlsSniRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); - uint8_t *buffer; - uint32_t buffer_len; - uint32_t cnt = 0; - - if (ssl_state->client_connp.sni == NULL) - return 0; - - buffer = (uint8_t *)ssl_state->client_connp.sni; - buffer_len = strlen(ssl_state->client_connp.sni); - - cnt = TlsSniPatternSearch(det_ctx, buffer, buffer_len); - - SCReturnUInt(cnt); + return PrefilterAppendTxEngine(sgh, PrefilterTxTlsSni, + ALPROTO_TLS, 0, // TODO a special 'cert ready' state might be good to add + mpm_ctx, NULL); } /** \brief Do the content inspection and validation for a signature @@ -142,61 +122,42 @@ int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, return cnt; } -/** - * \brief TLS issuer match -- searches for one pattern per signature. +/** \brief TLS Issuer Mpm prefilter callback * - * \param det_ctx Detection engine thread ctx - * \param buffer Buffer to inspect - * \param buffer_len Buffer length - * - * \retval ret Number of matches + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t TlsIssuerPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *buffer, - const uint32_t buffer_len) +static void PrefilterTxTlsIssuer(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + SSLState *ssl_state = f->alstate; - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_tlsissuer_ctx_ts == NULL); + if (ssl_state->server_connp.cert0_issuerdn == NULL) + return; - if (buffer_len >= det_ctx->sgh->mpm_tlsissuer_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_tlsissuer_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_tlsissuer_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); - } + const uint8_t *buffer = (const uint8_t *)ssl_state->server_connp.cert0_issuerdn; + const uint32_t buffer_len = strlen(ssl_state->server_connp.cert0_issuerdn); - SCReturnUInt(ret); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } } -/** - * \brief Run the pattern matcher against the TLS issuer buffer - * - * \param det_ctx Detection engine thread ctx - * \param f Locked flow - * \param ssl_state Initialized ssl state - * - * \retval cnt Number of matches - */ -uint32_t DetectTlsIssuerInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - SSLState *ssl_state) +int PrefilterTxTlsIssuerRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); - uint8_t *buffer; - uint32_t buffer_len; - uint32_t cnt = 0; - - if (ssl_state->server_connp.cert0_issuerdn == NULL) - return 0; - - buffer = (uint8_t *)ssl_state->server_connp.cert0_issuerdn; - buffer_len = strlen(ssl_state->server_connp.cert0_issuerdn); - - cnt = TlsIssuerPatternSearch(det_ctx, buffer, buffer_len); - - SCReturnUInt(cnt); + return PrefilterAppendTxEngine(sgh, PrefilterTxTlsIssuer, + ALPROTO_TLS, 0, // TODO a special 'cert ready' state might be good to add + mpm_ctx, NULL); } /** \brief Do the content inspection and validation for a signature @@ -237,61 +198,42 @@ int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, return cnt; } -/** - * \brief TLS subject match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx - * \param buffer Buffer to inspect - * \param buffer_len Buffer length +/** \brief TLS Subject Mpm prefilter callback * - * \retval ret Number of matches + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -static inline uint32_t TlsSubjectPatternSearch(DetectEngineThreadCtx *det_ctx, - const uint8_t *buffer, - const uint32_t buffer_len) +static void PrefilterTxTlsSubject(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t ret = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + SSLState *ssl_state = f->alstate; + + if (ssl_state->server_connp.cert0_issuerdn == NULL) + return; - DEBUG_VALIDATE_BUG_ON(det_ctx->sgh->mpm_tlssubject_ctx_ts == NULL); + const uint8_t *buffer = (const uint8_t *)ssl_state->server_connp.cert0_subject; + const uint32_t buffer_len = strlen(ssl_state->server_connp.cert0_subject); - if (buffer_len >= det_ctx->sgh->mpm_tlssubject_ctx_ts->minlen) { - ret = mpm_table[det_ctx->sgh->mpm_tlssubject_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_tlssubject_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } - - SCReturnUInt(ret); } -/** - * \brief Run the pattern matcher against the TLS subject buffer - * - * \param det_ctx Detection engine thread ctx - * \param f Locked flow - * \param ssl_state Initialized ssl state - * - * \retval cnt Number of matches - */ -uint32_t DetectTlsSubjectInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - SSLState *ssl_state) +int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); - uint8_t *buffer; - uint32_t buffer_len; - uint32_t cnt = 0; - - if (ssl_state->server_connp.cert0_subject == NULL) - return 0; - - buffer = (uint8_t *)ssl_state->server_connp.cert0_subject; - buffer_len = strlen(ssl_state->server_connp.cert0_subject); - - cnt = TlsSubjectPatternSearch(det_ctx, buffer, buffer_len); - - SCReturnUInt(cnt); + return PrefilterAppendTxEngine(sgh, PrefilterTxTlsSubject, + ALPROTO_TLS, 0, // TODO a special 'cert ready' state might be good to add + mpm_ctx, NULL); } /** \brief Do the content inspection and validation for a signature diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h index efcc111f7bf5..56bb63172df2 100644 --- a/src/detect-engine-tls.h +++ b/src/detect-engine-tls.h @@ -23,6 +23,10 @@ #ifndef __DETECT_ENGINE_TLS_H__ #define __DETECT_ENGINE_TLS_H__ +int PrefilterTxTlsSniRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxTlsIssuerRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, diff --git a/src/detect-tls-cert-issuer.h b/src/detect-tls-cert-issuer.h index a0b0846f7eb8..8e26cb75965c 100644 --- a/src/detect-tls-cert-issuer.h +++ b/src/detect-tls-cert-issuer.h @@ -27,7 +27,5 @@ #include "app-layer-ssl.h" void DetectTlsIssuerRegister(void); -uint32_t DetectTlsIssuerInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - SSLState *ssl_state); #endif /* __DETECT_TLS_ISSUER_H__ */ diff --git a/src/detect-tls-cert-subject.h b/src/detect-tls-cert-subject.h index 2edce96c86ab..8d037275e34b 100644 --- a/src/detect-tls-cert-subject.h +++ b/src/detect-tls-cert-subject.h @@ -27,7 +27,5 @@ #include "app-layer-ssl.h" void DetectTlsSubjectRegister(void); -uint32_t DetectTlsSubjectInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - SSLState *ssl_state); #endif /* __DETECT_TLS_SUBJECT_H__ */ diff --git a/src/detect.c b/src/detect.c index 3aad7940acf6..62e959986ffa 100644 --- a/src/detect.c +++ b/src/detect.c @@ -876,33 +876,6 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, /* have a look at the reassembled stream (if any) */ if (p->flowflags & FLOW_PKT_ESTABLISHED) { SCLogDebug("p->flowflags & FLOW_PKT_ESTABLISHED"); - - if (alproto == ALPROTO_TLS && has_state) { - void *alstate = FlowGetAppState(p->flow); - if (alstate == NULL) { - SCLogDebug("no alstate"); - return; - } - - if (p->flowflags & FLOW_PKT_TOSERVER) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSSNI) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSSNI); - DetectTlsSniInspectMpm(det_ctx, alstate); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSNI); - } - } else if (p->flowflags & FLOW_PKT_TOCLIENT) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSISSUER) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSISSUER); - DetectTlsIssuerInspectMpm(det_ctx, p->flow, alstate); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSISSUER); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_TLSSUBJECT) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_TLSSUBJECT); - DetectTlsSubjectInspectMpm(det_ctx, p->flow, alstate); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_TLSSUBJECT); - } - } - } } else { SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); } From 82d3c0b5209f85e5e5e63877cea8abb33345ee0e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 9 Jul 2016 09:16:24 +0200 Subject: [PATCH 1903/2553] sgh: remove unused flags --- src/detect-engine-mpm.c | 64 +++++++++++++----------------------- src/detect-engine-siggroup.c | 55 ------------------------------- src/detect.h | 27 --------------- 3 files changed, 22 insertions(+), 124 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 6c94e7a4a8f9..6ec91025eff1 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -89,7 +89,6 @@ typedef struct AppLayerMpms_ { int32_t sgh_mpm_context; /**< mpm factory id */ int direction; /**< SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT */ int sm_list; - uint32_t flags; /**< flags set to SGH when this mpm is present */ int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx); @@ -98,60 +97,60 @@ typedef struct AppLayerMpms_ { AppLayerMpms app_mpms[] = { { "http_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_UMATCH, - SIG_GROUP_HEAD_MPM_URI, PrefilterTxUriRegister, 0 }, + PrefilterTxUriRegister, 0 }, { "http_raw_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRUDMATCH, - SIG_GROUP_HEAD_MPM_HRUD, PrefilterTxRawUriRegister, 1 }, + PrefilterTxRawUriRegister, 1 }, { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, - SIG_GROUP_HEAD_MPM_HHD, PrefilterTxHttpRequestHeadersRegister, 2}, + PrefilterTxHttpRequestHeadersRegister, 2}, { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, - SIG_GROUP_HEAD_MPM_HHD, PrefilterTxHttpRequestHeadersRegister, 3}, + PrefilterTxHttpRequestHeadersRegister, 3}, { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, - SIG_GROUP_HEAD_MPM_HUAD, PrefilterTxUARegister, 4}, + PrefilterTxUARegister, 4}, { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, - SIG_GROUP_HEAD_MPM_HRHD, PrefilterTxRequestHeadersRawRegister, 5}, + PrefilterTxRequestHeadersRawRegister, 5}, { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, - SIG_GROUP_HEAD_MPM_HRHD, PrefilterTxResponseHeadersRawRegister, 6}, + PrefilterTxResponseHeadersRawRegister, 6}, { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, - SIG_GROUP_HEAD_MPM_HMD, PrefilterTxMethodRegister, 7}, + PrefilterTxMethodRegister, 7}, { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, - SIG_GROUP_HEAD_MPM_FD_SMTP, PrefilterTxSmtpFiledataRegister, 8}, /* smtp */ + PrefilterTxSmtpFiledataRegister, 8}, /* smtp */ { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, - SIG_GROUP_HEAD_MPM_HSBD, PrefilterTxHttpResponseBodyRegister, 9}, /* http server body */ + PrefilterTxHttpResponseBodyRegister, 9}, /* http server body */ { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, - SIG_GROUP_HEAD_MPM_HSMD, PrefilterTxHttpStatMsgRegister, 10}, + PrefilterTxHttpStatMsgRegister, 10}, { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, - SIG_GROUP_HEAD_MPM_HSCD, PrefilterTxHttpStatCodeRegister, 11}, + PrefilterTxHttpStatCodeRegister, 11}, { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, - SIG_GROUP_HEAD_MPM_HCBD, PrefilterTxHttpRequestBodyRegister, 12}, + PrefilterTxHttpRequestBodyRegister, 12}, { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, - SIG_GROUP_HEAD_MPM_HHHD, PrefilterTxHostnameRegister, 13}, + PrefilterTxHostnameRegister, 13}, { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, - SIG_GROUP_HEAD_MPM_HRHHD, PrefilterTxHostnameRawRegister, 14}, + PrefilterTxHostnameRawRegister, 14}, { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, - SIG_GROUP_HEAD_MPM_HCD, PrefilterTxRequestCookieRegister, 15}, + PrefilterTxRequestCookieRegister, 15}, { "http_cookie", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HCDMATCH, - SIG_GROUP_HEAD_MPM_HCD, PrefilterTxResponseCookieRegister, 16}, + PrefilterTxResponseCookieRegister, 16}, { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, - SIG_GROUP_HEAD_MPM_DNSQUERY, PrefilterTxDnsQueryRegister, 17}, + PrefilterTxDnsQueryRegister, 17}, { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, - SIG_GROUP_HEAD_MPM_TLSSNI, PrefilterTxTlsSniRegister, 18}, + PrefilterTxTlsSniRegister, 18}, { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, - SIG_GROUP_HEAD_MPM_TLSISSUER, PrefilterTxTlsIssuerRegister, 19}, + PrefilterTxTlsIssuerRegister, 19}, { "tls_cert_subject", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSSUBJECT_MATCH, - SIG_GROUP_HEAD_MPM_TLSSUBJECT, PrefilterTxTlsSubjectRegister, 20}, + PrefilterTxTlsSubjectRegister, 20}, - { NULL, 0, 0, 0, 0, NULL, 0, } + { NULL, 0, 0, 0, NULL, 0, } }; void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) @@ -1262,8 +1261,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (mpm_store != NULL) { BUG_ON(sh->mpm_packet_ctx); sh->mpm_packet_ctx = mpm_store->mpm_ctx; - if (sh->mpm_packet_ctx) - sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } @@ -1273,8 +1270,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) BUG_ON(mpm_store == NULL); BUG_ON(sh->mpm_stream_ctx); sh->mpm_stream_ctx = mpm_store->mpm_ctx; - if (sh->mpm_stream_ctx) - sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; PrefilterPktStreamRegister(sh, mpm_store->mpm_ctx); } @@ -1284,8 +1279,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (mpm_store != NULL) { BUG_ON(sh->mpm_packet_ctx); sh->mpm_packet_ctx = mpm_store->mpm_ctx; - if (sh->mpm_packet_ctx) - sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } @@ -1294,8 +1287,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (mpm_store != NULL) { BUG_ON(sh->mpm_stream_ctx); sh->mpm_stream_ctx = mpm_store->mpm_ctx; - if (sh->mpm_stream_ctx) - sh->flags |= SIG_GROUP_HEAD_MPM_STREAM; PrefilterPktStreamRegister(sh, mpm_store->mpm_ctx); } @@ -1308,9 +1299,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) BUG_ON(sh->mpm_packet_ctx); sh->mpm_packet_ctx = mpm_store->mpm_ctx; - if (sh->mpm_packet_ctx != NULL) - sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } } @@ -1320,9 +1308,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) BUG_ON(sh->mpm_packet_ctx); sh->mpm_packet_ctx = mpm_store->mpm_ctx; - if (sh->mpm_packet_ctx != NULL) - sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } } @@ -1332,9 +1317,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) BUG_ON(sh->mpm_packet_ctx); sh->mpm_packet_ctx = mpm_store->mpm_ctx; - if (sh->mpm_packet_ctx != NULL) - sh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } } @@ -1344,8 +1326,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) mpm_store = MpmStorePrepareBuffer2(de_ctx, sh, a); if (mpm_store != NULL) { sh->init->app_mpms[a->id] = mpm_store->mpm_ctx; - if (sh->init->app_mpms[a->id] != NULL) - sh->flags |= a->flags; if (a->PrefilterRegister) { BUG_ON(a->PrefilterRegister(sh, mpm_store->mpm_ctx) != 0); diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index c546d4da52f8..dee7234a96c6 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -1235,60 +1235,6 @@ static int SigGroupHeadTest10(void) UTHFreePackets(&p, 1); return result; } - -/** - * \test sig grouping bug. - */ -static int SigGroupHeadTest11(void) -{ - int result = 0; - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - Signature *s = NULL; - Packet *p = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - ThreadVars th_v; - - memset(&th_v, 0, sizeof(ThreadVars)); - - p = UTHBuildPacketReal(NULL, 0, IPPROTO_TCP, "192.168.1.1", "1.2.3.4", 60000, 80); - - if (de_ctx == NULL || p == NULL) - return 0; - - s = DetectEngineAppendSig(de_ctx, "alert tcp any 1024: -> any 1024: (content:\"abc\"; sid:1;)"); - if (s == NULL) { - goto end; - } - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"def\"; http_client_body; sid:2;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - AddressDebugPrint(&p->dst); - - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - goto end; - } - - /* check if hcbd flag is set in sgh */ - if (!(sgh->flags & SIG_GROUP_HEAD_MPM_HCBD)) { - printf("sgh has not SIG_GROUP_HEAD_MPM_HCBD flag set: "); - goto end; - } - - /* check if sig 2 is part of the sgh */ - - result = 1; -end: - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - UTHFreePackets(&p, 1); - return result; -} #endif void SigGroupHeadRegisterTests(void) @@ -1300,6 +1246,5 @@ void SigGroupHeadRegisterTests(void) UtRegisterTest("SigGroupHeadTest08", SigGroupHeadTest08); UtRegisterTest("SigGroupHeadTest09", SigGroupHeadTest09); UtRegisterTest("SigGroupHeadTest10", SigGroupHeadTest10); - UtRegisterTest("SigGroupHeadTest11", SigGroupHeadTest11); #endif } diff --git a/src/detect.h b/src/detect.h index 6c8b333ba6ee..e40511331dc3 100644 --- a/src/detect.h +++ b/src/detect.h @@ -920,39 +920,12 @@ typedef struct SigTableElmt_ { } 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_HAVEFILEMAGIC (1 << 20) #define SIG_GROUP_HEAD_HAVEFILEMD5 (1 << 21) #define SIG_GROUP_HEAD_HAVEFILESIZE (1 << 22) #define SIG_GROUP_HEAD_HAVEFILESHA1 (1 << 23) #define SIG_GROUP_HEAD_HAVEFILESHA256 (1 << 24) -#define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 25) -#define SIG_GROUP_HEAD_MPM_TLSSNI (1 << 26) -#define SIG_GROUP_HEAD_MPM_TLSISSUER (1 << 27) -#define SIG_GROUP_HEAD_MPM_TLSSUBJECT (1 << 28) -#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 29) - #define APP_MPMS_MAX 21 enum MpmBuiltinBuffers { From 85cb749e8b62f0a665aeec29d534f7727d4bfb20 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 10 Jul 2016 11:33:27 +0200 Subject: [PATCH 1904/2553] detect cleanup: remove sgh mpm_ctx pointers --- src/detect-engine-mpm.c | 84 ----------------------------------------- src/detect.h | 32 ---------------- 2 files changed, 116 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 6ec91025eff1..fbe576e95b4a 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1189,66 +1189,6 @@ MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, App return NULL; } -/** \todo fixup old mpm ptrs. We could use the array directly later */ -void MpmStoreFixup(SigGroupHead *sgh) -{ - if (!(SGH_PROTO(sgh, IPPROTO_TCP) || SGH_PROTO(sgh, IPPROTO_UDP))) - return; - -#define SET_TS(sgh, ptr) do { \ - if (SGH_DIRECTION_TS((sgh))) \ - (ptr) = (sgh)->init->app_mpms[i++]; \ - else \ - i++; \ - } while(0) - -#define SET_TC(sgh, ptr) do { \ - if (SGH_DIRECTION_TC((sgh))) \ - (ptr) = (sgh)->init->app_mpms[i++]; \ - else \ - i++; \ - } while(0) - - int i = 0; - SET_TS(sgh, sgh->mpm_uri_ctx_ts); - SET_TS(sgh, sgh->mpm_hrud_ctx_ts); - - SET_TS(sgh, sgh->mpm_hhd_ctx_ts); - SET_TC(sgh, sgh->mpm_hhd_ctx_tc); - - SET_TS(sgh, sgh->mpm_huad_ctx_ts); - - SET_TS(sgh, sgh->mpm_hrhd_ctx_ts); - SET_TC(sgh, sgh->mpm_hrhd_ctx_tc); - - SET_TS(sgh, sgh->mpm_hmd_ctx_ts); - - SET_TS(sgh, sgh->mpm_smtp_filedata_ctx_ts); - SET_TC(sgh, sgh->mpm_hsbd_ctx_tc); - - SET_TC(sgh, sgh->mpm_hsmd_ctx_tc); - SET_TC(sgh, sgh->mpm_hscd_ctx_tc); - - SET_TS(sgh, sgh->mpm_hcbd_ctx_ts); - - SET_TS(sgh, sgh->mpm_hhhd_ctx_ts); - SET_TS(sgh, sgh->mpm_hrhhd_ctx_ts); - - SET_TS(sgh, sgh->mpm_hcd_ctx_ts); - SET_TC(sgh, sgh->mpm_hcd_ctx_tc); - - SET_TS(sgh, sgh->mpm_dnsquery_ctx_ts); - - SET_TS(sgh, sgh->mpm_tlssni_ctx_ts); - SET_TC(sgh, sgh->mpm_tlsissuer_ctx_ts); - SET_TC(sgh, sgh->mpm_tlssubject_ctx_ts); - - BUG_ON(APP_MPMS_MAX != 21 || i != 21); - -#undef SET_TS -#undef SET_TC -} - /** \brief Prepare the pattern matcher ctx in a sig group head. * */ @@ -1259,35 +1199,22 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (SGH_DIRECTION_TS(sh)) { mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TS); if (mpm_store != NULL) { - BUG_ON(sh->mpm_packet_ctx); - sh->mpm_packet_ctx = mpm_store->mpm_ctx; - PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TS); if (mpm_store != NULL) { - BUG_ON(mpm_store == NULL); - BUG_ON(sh->mpm_stream_ctx); - sh->mpm_stream_ctx = mpm_store->mpm_ctx; - PrefilterPktStreamRegister(sh, mpm_store->mpm_ctx); } } if (SGH_DIRECTION_TC(sh)) { mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TC); if (mpm_store != NULL) { - BUG_ON(sh->mpm_packet_ctx); - sh->mpm_packet_ctx = mpm_store->mpm_ctx; - PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TC); if (mpm_store != NULL) { - BUG_ON(sh->mpm_stream_ctx); - sh->mpm_stream_ctx = mpm_store->mpm_ctx; - PrefilterPktStreamRegister(sh, mpm_store->mpm_ctx); } } @@ -1295,28 +1222,18 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (SGH_DIRECTION_TS(sh)) { mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TS); if (mpm_store != NULL) { - BUG_ON(mpm_store == NULL); - BUG_ON(sh->mpm_packet_ctx); - sh->mpm_packet_ctx = mpm_store->mpm_ctx; - PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } } if (SGH_DIRECTION_TC(sh)) { mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TC); if (mpm_store != NULL) { - BUG_ON(sh->mpm_packet_ctx); - sh->mpm_packet_ctx = mpm_store->mpm_ctx; - PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } } } else { mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_OTHERIP); if (mpm_store != NULL) { - BUG_ON(sh->mpm_packet_ctx); - sh->mpm_packet_ctx = mpm_store->mpm_ctx; - PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); } } @@ -1334,7 +1251,6 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) a++; } - MpmStoreFixup(sh); return 0; } diff --git a/src/detect.h b/src/detect.h index e40511331dc3..85d64a8ce260 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1012,38 +1012,6 @@ typedef struct SigGroupHead_ { uint32_t id; /**< unique id used to index sgh_array for stats */ - /* pattern matcher instances */ - const MpmCtx *mpm_packet_ctx; - const MpmCtx *mpm_stream_ctx; - - union { - struct { - const MpmCtx *mpm_uri_ctx_ts; - const MpmCtx *mpm_hcbd_ctx_ts; - const MpmCtx *mpm_hhd_ctx_ts; - const MpmCtx *mpm_hrhd_ctx_ts; - const MpmCtx *mpm_hmd_ctx_ts; - const MpmCtx *mpm_hcd_ctx_ts; - const MpmCtx *mpm_hrud_ctx_ts; - const MpmCtx *mpm_huad_ctx_ts; - const MpmCtx *mpm_hhhd_ctx_ts; - const MpmCtx *mpm_hrhhd_ctx_ts; - const MpmCtx *mpm_dnsquery_ctx_ts; - const MpmCtx *mpm_tlssni_ctx_ts; - const MpmCtx *mpm_tlsissuer_ctx_ts; - const MpmCtx *mpm_tlssubject_ctx_ts; - const MpmCtx *mpm_smtp_filedata_ctx_ts; - }; - struct { - const MpmCtx *mpm_hsbd_ctx_tc; - const MpmCtx *mpm_hhd_ctx_tc; - const MpmCtx *mpm_hrhd_ctx_tc; - const MpmCtx *mpm_hcd_ctx_tc; - const MpmCtx *mpm_hsmd_ctx_tc; - const MpmCtx *mpm_hscd_ctx_tc; - }; - }; - PrefilterEngine *engines; PrefilterEngine *tx_engines; From 56239690d041a55ae9c74f6d925d1ae25d48b526 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 Jul 2016 17:10:00 +0200 Subject: [PATCH 1905/2553] prefilter: implement prefilter keyword Introduce prefilter keyword to force a keyword to be used as prefilter. e.g. alert tcp any any -> any any (content:"A"; flags:R; prefilter; sid:1;) alert tcp any any -> any any (content:"A"; flags:R; sid:2;) alert tcp any any -> any any (content:"A"; dsize:1; prefilter; sid:3;) alert tcp any any -> any any (content:"A"; dsize:1; sid:4;) In sid 2 and 4 the content keyword is used in the MPM engine. In sid 1 and 3 the flags and dsize keywords will be used. --- src/Makefile.am | 1 + src/detect-engine-mpm.c | 5 ++ src/detect-engine-siggroup.c | 4 +- src/detect-prefilter.c | 104 +++++++++++++++++++++++++++++++++++ src/detect-prefilter.h | 30 ++++++++++ src/detect.c | 29 ++++++++++ src/detect.h | 10 ++++ 7 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 src/detect-prefilter.c create mode 100644 src/detect-prefilter.h diff --git a/src/Makefile.am b/src/Makefile.am index 24ec6759f2aa..84bf66063b2f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -191,6 +191,7 @@ detect-parse.c detect-parse.h \ detect-pcre.c detect-pcre.h \ detect-pkt-data.c detect-pkt-data.h \ detect-pktvar.c detect-pktvar.h \ +detect-prefilter.c detect-prefilter.h \ detect-priority.c detect-priority.h \ detect-rawbytes.c detect-rawbytes.h \ detect-reference.c detect-reference.h \ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index fbe576e95b4a..619093828544 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1283,11 +1283,16 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) * true size, since duplicates are removed below, but counted here. */ for (s = de_ctx->sig_list; s != NULL; s = s->next) { + if (s->flags & SIG_FLAG_PREFILTER) + continue; + RetrieveFPForSig(s); if (s->mpm_sm != NULL) { DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; struct_total_size += sizeof(DetectFPAndItsId); content_total_size += cd->content_len; + + s->flags |= SIG_FLAG_PREFILTER; } } diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index dee7234a96c6..60bf5abecb38 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -699,7 +699,7 @@ int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sg if (s == NULL) continue; - if (s->mpm_sm == NULL || (s->flags & SIG_FLAG_MPM_NEG)) { + if (!(s->flags & SIG_FLAG_PREFILTER) || (s->flags & SIG_FLAG_MPM_NEG)) { if (!(DetectFlagsSignatureNeedsSynPackets(s))) { non_pf++; } @@ -730,7 +730,7 @@ int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sg if (s == NULL) continue; - if (s->mpm_sm == NULL || (s->flags & SIG_FLAG_MPM_NEG)) { + if (!(s->flags & SIG_FLAG_PREFILTER) || (s->flags & SIG_FLAG_MPM_NEG)) { if (!(DetectFlagsSignatureNeedsSynPackets(s))) { BUG_ON(sgh->non_pf_other_store_cnt >= non_pf); BUG_ON(sgh->non_pf_other_store_array == NULL); diff --git a/src/detect-prefilter.c b/src/detect-prefilter.c new file mode 100644 index 000000000000..faef7a4f0c17 --- /dev/null +++ b/src/detect-prefilter.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2007-2016 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 + * + * Implements the prefilter keyword + */ + +#include "suricata-common.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-content.h" + +#include "util-debug.h" + +static int DetectPrefilterSetup (DetectEngineCtx *, Signature *, char *); + +void DetectPrefilterRegister(void) +{ + sigmatch_table[DETECT_PREFILTER].name = "prefilter"; + sigmatch_table[DETECT_PREFILTER].desc = "force a condition to be used as prefilter"; + sigmatch_table[DETECT_PREFILTER].Match = NULL; + sigmatch_table[DETECT_PREFILTER].Setup = DetectPrefilterSetup; + sigmatch_table[DETECT_PREFILTER].Free = NULL; + sigmatch_table[DETECT_PREFILTER].RegisterTests = NULL; + + sigmatch_table[DETECT_PREFILTER].flags |= SIGMATCH_NOOPT; +} + +/** + * \internal + * \brief Apply the prefilter keyword to the last match + * \param det_ctx detection engine ctx + * \param s signature + * \param nullstr should be null + * \retval 0 ok + * \retval -1 failure + */ +static int DetectPrefilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *nullstr) +{ + SCEnter(); + + SigMatch *sm = NULL; + int ret = -1; + + if (nullstr != NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "prefilter has value"); + goto end; + } + + if (s->flags & SIG_FLAG_PREFILTER) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "prefilter already set"); + goto end; + } + + sm = SigMatchGetLastSM(s); + if (sm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "prefilter needs preceding match"); + goto end; + } + + s->prefilter_sm = sm; + s->flags |= SIG_FLAG_PREFILTER; + + /* if the sig match is content, prefilter should act like + * 'fast_pattern' w/o options. */ + if (sm->type == DETECT_CONTENT) { + DetectContentData *cd = (DetectContentData *)sm->ctx; + if ((cd->flags & DETECT_CONTENT_NEGATED) && + ((cd->flags & DETECT_CONTENT_DISTANCE) || + (cd->flags & DETECT_CONTENT_WITHIN) || + (cd->flags & DETECT_CONTENT_OFFSET) || + (cd->flags & DETECT_CONTENT_DEPTH))) + { + SCLogError(SC_ERR_INVALID_SIGNATURE, "prefilter; cannot be " + "used with negated content, along with relative modifiers"); + goto end; + } + cd->flags |= DETECT_CONTENT_FAST_PATTERN; + } + + ret = 0; + end: + SCReturnInt(ret); +} diff --git a/src/detect-prefilter.h b/src/detect-prefilter.h new file mode 100644 index 000000000000..afc64db43f8f --- /dev/null +++ b/src/detect-prefilter.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2016 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 + */ + +#ifndef __DETECT_PREFILTER_H__ +#define __DETECT_PREFILTER_H__ + +/* prototypes */ +void DetectPrefilterRegister (void); + +#endif /* __DETECT_PREFILTER_H__ */ diff --git a/src/detect.c b/src/detect.c index 62e959986ffa..30c62f6f39c6 100644 --- a/src/detect.c +++ b/src/detect.c @@ -89,6 +89,7 @@ #include "detect-distance.h" #include "detect-offset.h" #include "detect-sid.h" +#include "detect-prefilter.h" #include "detect-priority.h" #include "detect-classtype.h" #include "detect-reference.h" @@ -3419,6 +3420,24 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) RuleSetWhitelist(tmp_s); + if (!(tmp_s->flags & SIG_FLAG_PREFILTER)) { + int i; + for (i = 0; i < DETECT_SM_LIST_DETECT_MAX; i++) { + SigMatch *sm = tmp_s->sm_lists[i]; + while (sm != NULL) { + if (sigmatch_table[sm->type].SupportsPrefilter != NULL) { + if (sigmatch_table[sm->type].SupportsPrefilter(tmp_s) == TRUE) { + tmp_s->prefilter_sm = sm; + tmp_s->flags |= SIG_FLAG_PREFILTER; + SCLogConfig("sid %u: prefilter is on \"%s\"", tmp_s->id, sigmatch_table[sm->type].name); + break; + } + } + sm = sm->next; + } + } + } + de_ctx->sig_cnt++; } @@ -3812,6 +3831,15 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SCLogDebug("filestore count %u", sgh->filestore_cnt); BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); + + int i = 0; + for (i = 0; i < DETECT_TBLSIZE; i++) + { + if (sigmatch_table[i].SetupPrefilter != NULL) { + sigmatch_table[i].SetupPrefilter(sgh); + } + } + SigGroupHeadBuildNonPrefilterArray(de_ctx, sgh); sgh->id = idx; @@ -4103,6 +4131,7 @@ void SigTableSetup(void) DetectSidRegister(); DetectPriorityRegister(); + DetectPrefilterRegister(); DetectRevRegister(); DetectClasstypeRegister(); DetectReferenceRegister(); diff --git a/src/detect.h b/src/detect.h index 85d64a8ce260..2021a070018c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -277,6 +277,9 @@ typedef struct DetectPort_ { #define SIG_FLAG_TLSSTORE (1<<21) #define SIG_FLAG_BYPASS (1<<22) + +#define SIG_FLAG_PREFILTER (1<<23) /**< sig is part of a prefilter engine */ + /* 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) */ @@ -439,6 +442,8 @@ typedef struct Signature_ { SigMatch *dsize_sm; /* 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; @@ -905,6 +910,9 @@ typedef struct SigTableElmt_ { /** keyword setup function pointer */ int (*Setup)(DetectEngineCtx *, Signature *, char *); + _Bool (*SupportsPrefilter)(const Signature *s); + int (*SetupPrefilter)(struct SigGroupHead_ *sgh); + void (*Free)(void *); void (*RegisterTests)(void); @@ -1221,6 +1229,8 @@ enum { DETECT_BYPASS, + DETECT_PREFILTER, + /* make sure this stays last */ DETECT_TBLSIZE, }; From f80623fd73e7d6df56bbc33f19218b4bc1e1e581 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Sep 2016 15:07:31 +0200 Subject: [PATCH 1906/2553] prefilter: show prefilter capability in --list-keywords --- src/detect.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/detect.c b/src/detect.c index 30c62f6f39c6..521065c7ce9c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4020,8 +4020,10 @@ int SigGroupCleanup (DetectEngineCtx *de_ctx) return 0; } -static inline void PrintFeatureList(int flags, char sep) +static void PrintFeatureList(const SigTableElmt *e, char sep) { + const uint8_t flags = e->flags; + int prev = 0; if (flags & SIGMATCH_NOOPT) { printf("No option"); @@ -4045,18 +4047,24 @@ static inline void PrintFeatureList(int flags, char sep) printf("payload inspecting keyword"); prev = 1; } + if (e->SupportsPrefilter) { + if (prev == 1) + printf("%c", sep); + printf("prefilter"); + prev = 1; + } if (prev == 0) { printf("none"); } } -static inline void SigMultilinePrint(int i, char *prefix) +static void SigMultilinePrint(int i, char *prefix) { if (sigmatch_table[i].desc) { printf("%sDescription: %s\n", prefix, sigmatch_table[i].desc); } printf("%sFeatures: ", prefix); - PrintFeatureList(sigmatch_table[i].flags, ','); + PrintFeatureList(&sigmatch_table[i], ','); if (sigmatch_table[i].url) { printf("\n%sDocumentation: %s", prefix, sigmatch_table[i].url); } @@ -4079,7 +4087,7 @@ void SigTableList(const char *keyword) } } } - } else if (!strcmp("csv", keyword)) { + } else if (strcmp("csv", keyword) == 0) { printf("name;description;app layer;features;documentation\n"); for (i = 0; i < size; i++) { if (sigmatch_table[i].name != NULL) { @@ -4092,7 +4100,7 @@ void SigTableList(const char *keyword) } /* Build feature */ printf(";Unset;"); // this used to be alproto - PrintFeatureList(sigmatch_table[i].flags, ':'); + PrintFeatureList(&sigmatch_table[i], ':'); printf(";"); if (sigmatch_table[i].url) { printf("%s", sigmatch_table[i].url); @@ -4101,7 +4109,7 @@ void SigTableList(const char *keyword) printf("\n"); } } - } else if (!strcmp("all", keyword)) { + } else if (strcmp("all", keyword) == 0) { for (i = 0; i < size; i++) { if (sigmatch_table[i].name != NULL) { printf("%s:\n", sigmatch_table[i].name); @@ -4111,7 +4119,7 @@ void SigTableList(const char *keyword) } else { for (i = 0; i < size; i++) { if ((sigmatch_table[i].name != NULL) && - !strcmp(sigmatch_table[i].name, keyword)) { + strcmp(sigmatch_table[i].name, keyword) == 0) { printf("= %s =\n", sigmatch_table[i].name); if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { printf("Not built-in\n"); From 99b9896bd75399993d2ece2bd1dc39629f5dd8b3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Aug 2016 10:03:21 +0200 Subject: [PATCH 1907/2553] prefilter: common funcs for packet header prefilters --- src/Makefile.am | 1 + src/detect-engine-prefilter-common.c | 165 +++++++++++++++++++++++++++ src/detect-engine-prefilter-common.h | 41 +++++++ 3 files changed, 207 insertions(+) create mode 100644 src/detect-engine-prefilter-common.c create mode 100644 src/detect-engine-prefilter-common.h diff --git a/src/Makefile.am b/src/Makefile.am index 84bf66063b2f..89cc563f932b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -126,6 +126,7 @@ detect-engine-mpm.c detect-engine-mpm.h \ detect-engine-payload.c detect-engine-payload.h \ detect-engine-port.c detect-engine-port.h \ detect-engine-prefilter.c detect-engine-prefilter.h \ +detect-engine-prefilter-common.c detect-engine-prefilter-common.h \ detect-engine-proto.c detect-engine-proto.h \ detect-engine-profile.c detect-engine-profile.h \ detect-engine-siggroup.c detect-engine-siggroup.h \ diff --git a/src/detect-engine-prefilter-common.c b/src/detect-engine-prefilter-common.c new file mode 100644 index 000000000000..114edb078325 --- /dev/null +++ b/src/detect-engine-prefilter-common.c @@ -0,0 +1,165 @@ +/* Copyright (C) 2007-2016 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. + */ + +#include "suricata-common.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" + +typedef struct PrefilterPacketHeaderHashCtx_ { + PrefilterPacketHeaderValue v1; + + uint32_t cnt; +} PrefilterPacketHeaderHashCtx; + +static uint32_t PrefilterPacketHeaderHashFunc(HashListTable *ht, void *data, uint16_t datalen) +{ + PrefilterPacketHeaderCtx *ctx = data; + uint64_t hash = ctx->v1.u64; + hash %= ht->array_size; + return hash; +} + +static char PrefilterPacketHeaderCompareFunc(void *data1, uint16_t len1, + void *data2, uint16_t len2) +{ + PrefilterPacketHeaderHashCtx *ctx1 = data1; + PrefilterPacketHeaderHashCtx *ctx2 = data2; + return (ctx1->v1.u64 == ctx2->v1.u64); +} + +static void PrefilterPacketHeaderFreeFunc(void *ptr) +{ + SCFree(ptr); +} + +static void PrefilterPacketHeaderFree(void *pectx) +{ + PrefilterPacketHeaderCtx *ctx = pectx; + SCFree(ctx->sigs_array); + SCFree(ctx); +} + +/** \internal + */ +static int +SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, + PrefilterPacketHeaderValue v, uint32_t count, + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) +{ + Signature *s = NULL; + uint32_t sig = 0; + uint32_t sig_offset = 0; + + PrefilterPacketHeaderCtx *ctx = SCCalloc(1, sizeof(PrefilterPacketHeaderCtx)); + if (ctx == NULL) + return -1; + + ctx->v1 = v; + ctx->sigs_cnt = count; + ctx->sigs_array = SCCalloc(ctx->sigs_cnt, sizeof(SigIntId)); + if (ctx->sigs_array == NULL) { + SCFree(ctx); + return -1; + } + + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; + if (s->prefilter_sm == NULL || s->prefilter_sm->type != sm_type) + continue; + + if (Compare(v, s->prefilter_sm->ctx)) { + SCLogDebug("appending sid %u on %u", s->id, sig_offset); + ctx->sigs_array[sig_offset] = s->num; + sig_offset++; + + s->flags |= SIG_FLAG_PREFILTER; + } + } + + PrefilterAppendEngine(sgh, Match, ctx, PrefilterPacketHeaderFree); + return 0; +} + +int PrefilterSetupPacketHeader(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) +{ + Signature *s = NULL; + uint32_t sig = 0; + + if (sgh == NULL) + return 0; + + /* first count how many engines we will need */ + + HashListTable *hash_table = HashListTableInit(4096, + PrefilterPacketHeaderHashFunc, + PrefilterPacketHeaderCompareFunc, + PrefilterPacketHeaderFreeFunc); + if (hash_table == NULL) + return -1; + + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; + if (s->prefilter_sm == NULL || s->prefilter_sm->type != sm_type) + continue; + + PrefilterPacketHeaderHashCtx ctx; + memset(&ctx, 0, sizeof(ctx)); + Set(&ctx.v1, s->prefilter_sm->ctx); + + PrefilterPacketHeaderHashCtx *rctx = HashListTableLookup(hash_table, (void *)&ctx, 0); + if (rctx != 0) { + rctx->cnt++; + } else { + PrefilterPacketHeaderHashCtx *actx = SCCalloc(1, sizeof(*actx)); + if (actx == NULL) + goto error; + + Set(&actx->v1, s->prefilter_sm->ctx); + actx->cnt = 1; + + int ret = HashListTableAdd(hash_table, actx, 0); + if (ret != 0) { + SCFree(actx); + goto error; + } + } + } + + // for each ack value, do + HashListTableBucket *hb = HashListTableGetListHead(hash_table); + for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); + + SetupEngineForPacketHeader(sgh, sm_type, + ctx->v1, ctx->cnt, + Compare, Match); + } + + HashListTableFree(hash_table); + return 0; +error: + HashListTableFree(hash_table); + return -1; +} diff --git a/src/detect-engine-prefilter-common.h b/src/detect-engine-prefilter-common.h new file mode 100644 index 000000000000..2ccf37953fa5 --- /dev/null +++ b/src/detect-engine-prefilter-common.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2007-2016 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. + */ + +#ifndef __DETECT_ENGINE_PREFILTER_COMMON_H__ +#define __DETECT_ENGINE_PREFILTER_COMMON_H__ + +typedef union { + uint8_t u8[8]; + uint16_t u16[4]; + uint32_t u32[2]; + uint64_t u64; +} PrefilterPacketHeaderValue; + +typedef struct PrefilterPacketHeaderCtx_ { + PrefilterPacketHeaderValue v1; + + /** rules to add when the flags are present */ + uint32_t sigs_cnt; + SigIntId *sigs_array; +} PrefilterPacketHeaderCtx; + +int PrefilterSetupPacketHeader(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)); + +#endif /* __DETECT_ENGINE_PREFILTER_COMMON_H__ */ From ea26ee906f4c9b54fa1c4f6b974373a1a23f94e7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 22 Aug 2016 15:21:19 +0200 Subject: [PATCH 1908/2553] prefilter: intro common engine for u8 matches --- src/detect-engine-prefilter-common.c | 225 +++++++++++++++++++++++++-- src/detect-engine-prefilter-common.h | 24 ++- 2 files changed, 239 insertions(+), 10 deletions(-) diff --git a/src/detect-engine-prefilter-common.c b/src/detect-engine-prefilter-common.c index 114edb078325..0278026e0fb1 100644 --- a/src/detect-engine-prefilter-common.c +++ b/src/detect-engine-prefilter-common.c @@ -53,6 +53,20 @@ static void PrefilterPacketHeaderFree(void *pectx) SCFree(ctx); } +static void PrefilterPacketU8HashCtxFree(void *vctx) +{ + PrefilterPacketU8HashCtx *ctx = vctx; + int i; + for (i = 0; i < 256; i++) { + SigsArray *sa = ctx->array[i]; + if (sa == NULL) + continue; + SCFree(sa->sigs); + SCFree(sa); + } + SCFree(ctx); +} + /** \internal */ static int @@ -97,13 +111,190 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, return 0; } -int PrefilterSetupPacketHeader(SigGroupHead *sgh, int sm_type, +/** \internal + * \brief apply signature to each value */ +static void ApplyToU8Hash(PrefilterPacketU8HashCtx *ctx, PrefilterPacketHeaderValue v, Signature *s) +{ + switch (v.u8[0]) { + case PREFILTER_U8HASH_MODE_EQ: + { + SigsArray *sa = ctx->array[v.u8[1]]; + sa->sigs[sa->offset++] = s->num; + break; + } + case PREFILTER_U8HASH_MODE_LT: + { + uint8_t x = v.u8[1] - 1; + do { + SigsArray *sa = ctx->array[x]; + sa->sigs[sa->offset++] = s->num; + } while (x--); + + break; + } + case PREFILTER_U8HASH_MODE_GT: + { + int x = v.u8[1] + 1; + do { + SigsArray *sa = ctx->array[x]; + sa->sigs[sa->offset++] = s->num; + } while (++x < 256); + + break; + } + case PREFILTER_U8HASH_MODE_RA: + { + int x = v.u8[1] + 1; + do { + SigsArray *sa = ctx->array[x]; + sa->sigs[sa->offset++] = s->num; + } while (++x < v.u8[2]); + + break; + } + } +} + +/** \internal + * \brief turn values into a u8 hash map + * \todo improve error handling + * \todo deduplicate sigs arrays + */ +static int +SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(SigGroupHead *sgh, int sm_type, + uint32_t *counts, void (*Set)(PrefilterPacketHeaderValue *v, void *), _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) { Signature *s = NULL; uint32_t sig = 0; + uint32_t cnt = 0; + + PrefilterPacketU8HashCtx *ctx = SCCalloc(1, sizeof(PrefilterPacketU8HashCtx)); + if (ctx == NULL) + return -1; + + int i; + for (i = 0; i < 256; i++) { + if (counts[i] == 0) + continue; + ctx->array[i] = SCCalloc(1, sizeof(SigsArray)); + BUG_ON(ctx->array[i] == NULL); + + ctx->array[i]->cnt = counts[i]; + ctx->array[i]->sigs = SCCalloc(ctx->array[i]->cnt, sizeof(SigIntId)); + BUG_ON(ctx->array[i]->sigs == NULL); + } + + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; + if (s->prefilter_sm == NULL || s->prefilter_sm->type != sm_type) + continue; + + PrefilterPacketHeaderValue v; + memset(&v, 0, sizeof(v)); + Set(&v, s->prefilter_sm->ctx); + + ApplyToU8Hash(ctx, v, s); + s->flags |= SIG_FLAG_PREFILTER; + cnt++; + } + + if (cnt) { + PrefilterAppendEngine(sgh, Match, ctx, + PrefilterPacketU8HashCtxFree); + } else { + PrefilterPacketU8HashCtxFree(ctx); + } + return 0; +} + +/** \internal + * \brief setup a engine for each unique value + */ +static void SetupSingle(HashListTable *hash_table, + SigGroupHead *sgh, int sm_type, + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)) +{ + HashListTableBucket *hb = HashListTableGetListHead(hash_table); + for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); + + SetupEngineForPacketHeader(sgh, sm_type, + ctx->v1, ctx->cnt, + Compare, Match); + } +} + +/** \internal + * \brief setup a single engine with a hash map for u8 values + */ +static void SetupU8Hash(HashListTable *hash_table, + SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)) +{ + uint32_t counts[256]; + memset(&counts, 0, sizeof(counts)); + + HashListTableBucket *hb = HashListTableGetListHead(hash_table); + for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); + + switch (ctx->v1.u8[0]) { + case PREFILTER_U8HASH_MODE_EQ: + counts[ctx->v1.u8[1]] += ctx->cnt; + break; + case PREFILTER_U8HASH_MODE_LT: + { + uint8_t v = ctx->v1.u8[1] - 1; + do { + counts[v] += ctx->cnt; + } while (v--); + + break; + } + case PREFILTER_U8HASH_MODE_GT: + { + int v = ctx->v1.u8[1] + 1; + do { + counts[v] += ctx->cnt; + } while (++v < 256); + + break; + } + case PREFILTER_U8HASH_MODE_RA: + { + int v = ctx->v1.u8[1] + 1; + do { + counts[v] += ctx->cnt; + } while (++v < ctx->v1.u8[2]); + + break; + } + } + } + + SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(sgh, sm_type, + counts, Set, Compare, Match); +} + +static int PrefilterSetupPacketHeaderCommon(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx), + _Bool u8hash) +{ + Signature *s = NULL; + uint32_t sig = 0; if (sgh == NULL) return 0; @@ -147,14 +338,10 @@ int PrefilterSetupPacketHeader(SigGroupHead *sgh, int sm_type, } } - // for each ack value, do - HashListTableBucket *hb = HashListTableGetListHead(hash_table); - for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { - PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); - - SetupEngineForPacketHeader(sgh, sm_type, - ctx->v1, ctx->cnt, - Compare, Match); + if (u8hash == FALSE) { + SetupSingle(hash_table, sgh, sm_type, Compare, Match); + } else { + SetupU8Hash(hash_table, sgh, sm_type, Set, Compare, Match); } HashListTableFree(hash_table); @@ -163,3 +350,23 @@ int PrefilterSetupPacketHeader(SigGroupHead *sgh, int sm_type, HashListTableFree(hash_table); return -1; } + +int PrefilterSetupPacketHeaderU8Hash(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)) +{ + return PrefilterSetupPacketHeaderCommon(sgh, sm_type, + Set, Compare, Match, TRUE); +} + +int PrefilterSetupPacketHeader(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)) +{ + return PrefilterSetupPacketHeaderCommon(sgh, sm_type, + Set, Compare, Match, FALSE); +} diff --git a/src/detect-engine-prefilter-common.h b/src/detect-engine-prefilter-common.h index 2ccf37953fa5..6867f90f3234 100644 --- a/src/detect-engine-prefilter-common.h +++ b/src/detect-engine-prefilter-common.h @@ -33,9 +33,31 @@ typedef struct PrefilterPacketHeaderCtx_ { SigIntId *sigs_array; } PrefilterPacketHeaderCtx; +typedef struct SigsArray_ { + SigIntId *sigs; + uint32_t cnt; + uint32_t offset; // used to track assign pos +} SigsArray; + +typedef struct PrefilterPacketU8HashCtx_ { + SigsArray *array[256]; +} PrefilterPacketU8HashCtx; + +#define PREFILTER_U8HASH_MODE_EQ 0 +#define PREFILTER_U8HASH_MODE_LT 1 +#define PREFILTER_U8HASH_MODE_GT 2 +#define PREFILTER_U8HASH_MODE_RA 3 + int PrefilterSetupPacketHeader(SigGroupHead *sgh, int sm_type, void (*Set)(PrefilterPacketHeaderValue *v, void *), _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), - void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)); + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)); + +int PrefilterSetupPacketHeaderU8Hash(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)); #endif /* __DETECT_ENGINE_PREFILTER_COMMON_H__ */ From 8798bf48b210123617a10c9b8046f2fe4ce701a5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Aug 2016 14:54:37 +0200 Subject: [PATCH 1909/2553] profiling: support prefilter engines --- src/decode.h | 10 ++ src/detect-engine-dns.c | 2 +- src/detect-engine-filedata-smtp.c | 2 +- src/detect-engine-hcbd.c | 2 +- src/detect-engine-hcd.c | 4 +- src/detect-engine-hhd.c | 8 +- src/detect-engine-hhhd.c | 2 +- src/detect-engine-hmd.c | 2 +- src/detect-engine-hrhd.c | 8 +- src/detect-engine-hrhhd.c | 2 +- src/detect-engine-hrud.c | 2 +- src/detect-engine-hsbd.c | 2 +- src/detect-engine-hscd.c | 2 +- src/detect-engine-hsmd.c | 2 +- src/detect-engine-hua.c | 2 +- src/detect-engine-payload.c | 4 +- src/detect-engine-prefilter-common.c | 6 +- src/detect-engine-prefilter.c | 179 ++++++++++++++++++++++++--- src/detect-engine-prefilter.h | 10 +- src/detect-engine-tls.c | 6 +- src/detect-engine-uri.c | 2 +- src/detect.c | 68 ++++------ src/detect.h | 10 ++ src/suricata-common.h | 21 ---- src/util-profiling.c | 110 ++++++++++++---- src/util-profiling.h | 33 +++++ 26 files changed, 367 insertions(+), 134 deletions(-) diff --git a/src/decode.h b/src/decode.h index bb4d39f96b67..f760b17acb93 100644 --- a/src/decode.h +++ b/src/decode.h @@ -347,6 +347,15 @@ typedef struct PktProfilingLoggerData_ { uint64_t ticks_spent; } PktProfilingLoggerData; +typedef struct PktProfilingPrefilterEngine_ { + uint64_t ticks_spent; +} PktProfilingPrefilterEngine; + +typedef struct PktProfilingPrefilterData_ { + PktProfilingPrefilterEngine *engines; + uint32_t size; /**< array size */ +} PktProfilingPrefilterData; + /** \brief Per pkt stats storage */ typedef struct PktProfiling_ { uint64_t ticks_start; @@ -357,6 +366,7 @@ typedef struct PktProfiling_ { PktProfilingAppData app[ALPROTO_MAX]; PktProfilingDetectData detect[PROF_DETECT_SIZE]; PktProfilingLoggerData logger[LOGGER_SIZE]; + PktProfilingPrefilterData prefilter; uint64_t proto_detect; } PktProfiling; diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index fafb6987b0a8..d7a135e3a709 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -135,7 +135,7 @@ int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxDnsQuery, ALPROTO_DNS, 1, - mpm_ctx, NULL); + mpm_ctx, NULL, "dns_query"); } int DetectEngineInspectDnsRequest(ThreadVars *tv, diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 422c19cebad7..5d0d3aec1589 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -281,7 +281,7 @@ int PrefilterTxSmtpFiledataRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxSmtpFiledata, ALPROTO_SMTP, 0, - mpm_ctx, NULL); + mpm_ctx, NULL, "file_data (smtp)"); } #ifdef UNITTESTS diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 933f0cd54646..8c8ac0645ea8 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -253,7 +253,7 @@ int PrefilterTxHttpRequestBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestBody, ALPROTO_HTTP, HTP_REQUEST_BODY, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_client_body"); } int DetectEngineInspectHttpClientBody(ThreadVars *tv, diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index 7f04da0edecf..b43bf5096d75 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -103,7 +103,7 @@ int PrefilterTxRequestCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxRequestCookie, ALPROTO_HTTP, HTP_REQUEST_HEADERS, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_cookie (request)"); } /** \brief HTTP Cookie Mpm prefilter callback @@ -149,7 +149,7 @@ int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxResponseCookie, ALPROTO_HTTP, HTP_RESPONSE_HEADERS, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_cookie (response)"); } /** diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 9523f948a6fd..fe48fdbaac2b 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -256,12 +256,12 @@ int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaders, ALPROTO_HTTP, HTP_REQUEST_HEADERS, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_header (request)"); if (r != 0) return r; return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaders, ALPROTO_HTTP, HTP_REQUEST_TRAILER, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_header (request)"); } /** \brief HTTP Headers Mpm prefilter callback @@ -305,12 +305,12 @@ int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaders, ALPROTO_HTTP, HTP_RESPONSE_HEADERS, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_header (response)"); if (r != 0) return r; return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaders, ALPROTO_HTTP, HTP_RESPONSE_TRAILER, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_header (response)"); } int DetectEngineInspectHttpHeader(ThreadVars *tv, diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 28d8d59b72fd..4824db7a41c4 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -98,7 +98,7 @@ int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxHostname, ALPROTO_HTTP, HTP_REQUEST_HEADERS, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_host"); } /** diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 72f5c43597b4..fbf92e7b8d92 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -95,7 +95,7 @@ int PrefilterTxMethodRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { return PrefilterAppendTxEngine(sgh, PrefilterTxMethod, ALPROTO_HTTP, HTP_REQUEST_LINE, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_method"); } /** diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index c20135c0f029..7f0a56a82808 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -97,12 +97,12 @@ int PrefilterTxRequestHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int r = PrefilterAppendTxEngine(sgh, PrefilterTxRequestHeadersRaw, ALPROTO_HTTP, HTP_REQUEST_HEADERS+1, /* inspect when headers complete */ - mpm_ctx, NULL); + mpm_ctx, NULL, "http_raw_header (request)"); if (r != 0) return r; return PrefilterAppendTxEngine(sgh, PrefilterTxRequestHeadersRaw, ALPROTO_HTTP, HTP_REQUEST_TRAILER+1, /* inspect when trailer complete */ - mpm_ctx, NULL); + mpm_ctx, NULL, "http_raw_header (request)"); } /** \brief HTTP Raw Header Mpm prefilter callback @@ -141,12 +141,12 @@ int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int r = PrefilterAppendTxEngine(sgh, PrefilterTxResponseHeadersRaw, ALPROTO_HTTP, HTP_RESPONSE_HEADERS+1, /* inspect when headers complete */ - mpm_ctx, NULL); + mpm_ctx, NULL, "http_raw_header (response)"); if (r != 0) return r; return PrefilterAppendTxEngine(sgh, PrefilterTxResponseHeadersRaw, ALPROTO_HTTP, HTP_RESPONSE_TRAILER+1, /* inspect when trailer complete */ - mpm_ctx, NULL); + mpm_ctx, NULL, "http_raw_header (response)"); } /** diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index eb5c97204b42..2f4edfbcf71b 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -110,7 +110,7 @@ int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxHostnameRaw, ALPROTO_HTTP, HTP_REQUEST_HEADERS, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_raw_host"); } /** diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 5139b21a8603..e0a0d50805fd 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -95,7 +95,7 @@ int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxRawUri, ALPROTO_HTTP, HTP_REQUEST_LINE, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_raw_uri"); } /** diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 87a6827e8e84..8f9495453568 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -257,7 +257,7 @@ int PrefilterTxHttpResponseBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseBody, ALPROTO_HTTP, HTP_RESPONSE_BODY, - mpm_ctx, NULL); + mpm_ctx, NULL, "file_data (http response)"); } diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 205005570f3b..929f788ff5f7 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -94,7 +94,7 @@ int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxHttpStatCode, ALPROTO_HTTP, HTP_RESPONSE_LINE+1, /* inspect when response line completely parsed */ - mpm_ctx, NULL); + mpm_ctx, NULL, "http_stat_code"); } /** diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index b0d12e67b18b..c707ab381a63 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -94,7 +94,7 @@ int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxHttpStatMsg, ALPROTO_HTTP, HTP_RESPONSE_LINE+1, /* inspect when response line completely parsed */ - mpm_ctx, NULL); + mpm_ctx, NULL, "http_stat_msg"); } /** diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index 4cfe46abce75..b057db38ae0e 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -103,7 +103,7 @@ int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxUA, ALPROTO_HTTP, HTP_REQUEST_HEADERS, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_user_agent"); } /** diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index 85f69925b02c..4ce0be416f78 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -83,7 +83,7 @@ static void PrefilterPktStream(DetectEngineThreadCtx *det_ctx, int PrefilterPktStreamRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { - return PrefilterAppendEngine(sgh, PrefilterPktStream, mpm_ctx, NULL); + return PrefilterAppendEngine(sgh, PrefilterPktStream, mpm_ctx, NULL, "stream"); } static void PrefilterPktPayload(DetectEngineThreadCtx *det_ctx, @@ -112,7 +112,7 @@ static void PrefilterPktPayload(DetectEngineThreadCtx *det_ctx, int PrefilterPktPayloadRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { - return PrefilterAppendEngine(sgh, PrefilterPktPayload, mpm_ctx, NULL); + return PrefilterAppendEngine(sgh, PrefilterPktPayload, mpm_ctx, NULL, "payload"); } diff --git a/src/detect-engine-prefilter-common.c b/src/detect-engine-prefilter-common.c index 0278026e0fb1..65c28131f9c6 100644 --- a/src/detect-engine-prefilter-common.c +++ b/src/detect-engine-prefilter-common.c @@ -107,7 +107,8 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, } } - PrefilterAppendEngine(sgh, Match, ctx, PrefilterPacketHeaderFree); + PrefilterAppendEngine(sgh, Match, ctx, PrefilterPacketHeaderFree, + sigmatch_table[sm_type].name); return 0; } @@ -205,7 +206,8 @@ SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(SigGroupHead *sgh, int sm_typ if (cnt) { PrefilterAppendEngine(sgh, Match, ctx, - PrefilterPacketU8HashCtxFree); + PrefilterPacketU8HashCtxFree, + sigmatch_table[sm_type].name); } else { PrefilterPacketU8HashCtxFree(ctx); } diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index 9fb570e42d9a..e0a39d1f021e 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -52,6 +52,12 @@ #include "app-layer-parser.h" #include "app-layer-htp.h" +#include "util-profiling.h" + +#ifdef PROFILING +static int PrefilterStoreGetId(const char *name); +#endif + static inline void PrefilterTx(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, const uint8_t flags) { @@ -92,8 +98,10 @@ static inline void PrefilterTx(DetectEngineThreadCtx *det_ctx, if (engine->tx_min_progress > tx_progress) goto next; + PROFILING_PREFILTER_START(p); engine->PrefilterTx(det_ctx, engine->pectx, p, p->flow, tx, idx, flags); + PROFILING_PREFILTER_END(p, engine->profile_id); next: engine = engine->next; } while (engine); @@ -105,10 +113,15 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, { SCEnter(); + PROFILING_PREFILTER_RESET(p, det_ctx->de_ctx->profile_prefilter_maxid); + /* run packet engines */ PrefilterEngine *engine = sgh->engines; while (engine) { + PROFILING_PREFILTER_START(p); engine->Prefilter(det_ctx, p, engine->pectx); + PROFILING_PREFILTER_END(p, engine->profile_id); + engine = engine->next; } @@ -124,7 +137,8 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, int PrefilterAppendEngine(SigGroupHead *sgh, void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), - void *pectx, void (*FreeFunc)(void *pectx)) + void *pectx, void (*FreeFunc)(void *pectx), + const char *name) { if (sgh == NULL || Prefilter == NULL || pectx == NULL) return -1; @@ -139,16 +153,21 @@ int PrefilterAppendEngine(SigGroupHead *sgh, if (sgh->engines == NULL) { sgh->engines = e; - return 0; - } + } else { + PrefilterEngine *t = sgh->engines; + while (t->next != NULL) { + t = t->next; + } - PrefilterEngine *t = sgh->engines; - while (t->next != NULL) { - t = t->next; + t->next = e; + e->id = t->id + 1; } - t->next = e; - e->id = t->id + 1; +#ifdef PROFILING + sgh->engines_cnt = e->id; + e->name = name; + e->profile_id = PrefilterStoreGetId(e->name); +#endif return 0; } @@ -157,7 +176,8 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, Packet *p, Flow *f, void *tx, const uint64_t idx, const uint8_t flags), AppProto alproto, int tx_min_progress, - void *pectx, void (*FreeFunc)(void *pectx)) + void *pectx, void (*FreeFunc)(void *pectx), + const char *name) { if (sgh == NULL || PrefilterTx == NULL || pectx == NULL) return -1; @@ -174,16 +194,20 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, if (sgh->tx_engines == NULL) { sgh->tx_engines = e; - return 0; - } + } else { + PrefilterEngine *t = sgh->tx_engines; + while (t->next != NULL) { + t = t->next; + } - PrefilterEngine *t = sgh->tx_engines; - while (t->next != NULL) { - t = t->next; + t->next = e; + e->id = t->id + 1; } - - t->next = e; - e->id = t->id + 1; +#ifdef PROFILING + sgh->tx_engines_cnt = e->id; + e->name = name; + e->profile_id = PrefilterStoreGetId(e->name); +#endif return 0; } @@ -205,3 +229,124 @@ void PrefilterFreeEngines(PrefilterEngine *list) t = next; } } + +#ifdef PROFILING +/* hash table for assigning a unique id to each engine type. */ + +typedef struct PrefilterStore_ { + const char *name; + uint32_t id; +} PrefilterStore; + +static uint32_t PrefilterStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen) +{ + PrefilterStore *ctx = data; + + uint32_t hash = strlen(ctx->name); + uint16_t u; + + for (u = 0; u < strlen(ctx->name); u++) { + hash += ctx->name[u]; + } + + hash %= ht->array_size; + return hash; +} + +static char PrefilterStoreCompareFunc(void *data1, uint16_t len1, + void *data2, uint16_t len2) +{ + PrefilterStore *ctx1 = data1; + PrefilterStore *ctx2 = data2; + return (strcmp(ctx1->name, ctx2->name) == 0); +} + +static void PrefilterStoreFreeFunc(void *ptr) +{ + SCFree(ptr); +} + +static SCMutex g_prefilter_mutex = SCMUTEX_INITIALIZER; +static uint32_t g_prefilter_id = 0; +static HashListTable *g_prefilter_hash_table = NULL; + +static void PrefilterDeinit(void) +{ + SCMutexLock(&g_prefilter_mutex); + BUG_ON(g_prefilter_hash_table == NULL); + HashListTableFree(g_prefilter_hash_table); + SCMutexUnlock(&g_prefilter_mutex); +} + +static void PrefilterInit(void) +{ + SCMutexLock(&g_prefilter_mutex); + BUG_ON(g_prefilter_hash_table != NULL); + + g_prefilter_hash_table = HashListTableInit(256, + PrefilterStoreHashFunc, + PrefilterStoreCompareFunc, + PrefilterStoreFreeFunc); + BUG_ON(g_prefilter_hash_table == NULL); + atexit(PrefilterDeinit); + SCMutexUnlock(&g_prefilter_mutex); +} + +static int PrefilterStoreGetId(const char *name) +{ + PrefilterStore ctx = { name, 0 }; + + if (g_prefilter_hash_table == NULL) { + PrefilterInit(); + } + + SCLogDebug("looking up %s", name); + + SCMutexLock(&g_prefilter_mutex); + PrefilterStore *rctx = HashListTableLookup(g_prefilter_hash_table, (void *)&ctx, 0); + if (rctx != NULL) { + SCMutexUnlock(&g_prefilter_mutex); + return rctx->id; + } + + PrefilterStore *actx = SCCalloc(1, sizeof(*actx)); + if (actx == NULL) { + SCMutexUnlock(&g_prefilter_mutex); + return -1; + } + + actx->name = name; + actx->id = g_prefilter_id++; + SCLogDebug("prefilter engine %s has profile id %u", actx->name, actx->id); + + int ret = HashListTableAdd(g_prefilter_hash_table, actx, 0); + if (ret != 0) { + SCMutexUnlock(&g_prefilter_mutex); + SCFree(actx); + return -1; + } + + int r = actx->id; + SCMutexUnlock(&g_prefilter_mutex); + return r; +} + +/** \warning slow */ +const char *PrefilterStoreGetName(const uint32_t id) +{ + const char *name = NULL; + SCMutexLock(&g_prefilter_mutex); + if (g_prefilter_hash_table != NULL) { + HashListTableBucket *hb = HashListTableGetListHead(g_prefilter_hash_table); + for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + PrefilterStore *ctx = HashListTableGetListData(hb); + if (ctx->id == id) { + name = ctx->name; + break; + } + } + } + SCMutexUnlock(&g_prefilter_mutex); + return name; +} +#endif /* PROFILING */ diff --git a/src/detect-engine-prefilter.h b/src/detect-engine-prefilter.h index 0293135f9f1b..d98bee7b5970 100644 --- a/src/detect-engine-prefilter.h +++ b/src/detect-engine-prefilter.h @@ -29,14 +29,20 @@ void Prefilter(DetectEngineThreadCtx *, const SigGroupHead *, Packet *p, int PrefilterAppendEngine(SigGroupHead *sgh, void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), - void *pectx, void (*FreeFunc)(void *pectx)); + void *pectx, void (*FreeFunc)(void *pectx), + const char *name); int PrefilterAppendTxEngine(SigGroupHead *sgh, void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f, void *tx, const uint64_t idx, const uint8_t flags), const AppProto alproto, const int tx_min_progress, - void *pectx, void (*FreeFunc)(void *pectx)); + void *pectx, void (*FreeFunc)(void *pectx), + const char *name); void PrefilterFreeEngines(PrefilterEngine *list); +#ifdef PROFILING +const char *PrefilterStoreGetName(const uint32_t id); +#endif + #endif diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index a4ce75caf382..6e6f025a7e12 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -81,7 +81,7 @@ int PrefilterTxTlsSniRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxTlsSni, ALPROTO_TLS, 0, // TODO a special 'cert ready' state might be good to add - mpm_ctx, NULL); + mpm_ctx, NULL, "tls_sni"); } /** \brief Do the content inspection and validation for a signature @@ -157,7 +157,7 @@ int PrefilterTxTlsIssuerRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxTlsIssuer, ALPROTO_TLS, 0, // TODO a special 'cert ready' state might be good to add - mpm_ctx, NULL); + mpm_ctx, NULL, "tls_cert_issuer"); } /** \brief Do the content inspection and validation for a signature @@ -233,7 +233,7 @@ int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxTlsSubject, ALPROTO_TLS, 0, // TODO a special 'cert ready' state might be good to add - mpm_ctx, NULL); + mpm_ctx, NULL, "tls_cert_subject"); } /** \brief Do the content inspection and validation for a signature diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index 18695997937a..7b6ad2ab1b72 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -86,7 +86,7 @@ int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) return PrefilterAppendTxEngine(sgh, PrefilterTxUri, ALPROTO_HTTP, HTP_REQUEST_LINE, - mpm_ctx, NULL); + mpm_ctx, NULL, "http_uri"); } /** diff --git a/src/detect.c b/src/detect.c index 521065c7ce9c..ca6ebfd52937 100644 --- a/src/detect.c +++ b/src/detect.c @@ -853,41 +853,6 @@ static void QuickSortSigIntId(SigIntId *sids, uint32_t n) #define SMS_USE_FLOW_SGH 0x01 #define SMS_USED_PM 0x02 -/** - * \internal - * \brief Run mpm on packet, stream and other buffers based on - * alproto, sgh state. - * - * \param de_ctx Pointer to the detection engine context. - * \param det_ctx Pointer to the detection engine thread context. - * \param smsg The stream segment to inspect for stream mpm. - * \param p Packet. - * \param flags Flags. - * \param alproto Flow alproto. - * \param has_state Bool indicating we have (al)state - * \param sms_runflags Used to store state by detection engine. - */ -static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, StreamMsg *smsg, Packet *p, - const uint8_t flags, const AppProto alproto, - const int has_state, uint8_t *sms_runflags) -{ - SCEnter(); - - /* have a look at the reassembled stream (if any) */ - if (p->flowflags & FLOW_PKT_ESTABLISHED) { - SCLogDebug("p->flowflags & FLOW_PKT_ESTABLISHED"); - } else { - SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); - } - - /* Sort the rule list to lets look at pmq. - * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ - if (det_ctx->pmq.rule_id_array_cnt > 1) { - QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt); - } -} - #ifdef DEBUG static void DebugInspectIds(Packet *p, Flow *f, StreamMsg *smsg) { @@ -1229,14 +1194,16 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_NONMPMLIST); + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PREFILTER); /* run the prefilter engines */ Prefilter(det_ctx, det_ctx->sgh, p, flow_flags, has_state); - - /* run the mpm for each type */ - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM); - DetectMpmPrefilter(de_ctx, det_ctx, det_ctx->smsg, p, flow_flags, - alproto, has_state, &sms_runflags); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); + /* Sort the rule list to lets look at pmq. + * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ + if (det_ctx->pmq.rule_id_array_cnt > 1) { + QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt); + } + DetectPrefilterMergeSort(de_ctx, det_ctx); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PREFILTER); #ifdef PROFILING if (th_v) { @@ -1250,9 +1217,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } #endif - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PREFILTER); - DetectPrefilterMergeSort(de_ctx, det_ctx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PREFILTER); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_RULES); /* inspect the sigs against the packet */ @@ -3840,6 +3804,22 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) } } +#ifdef PROFILING + PrefilterEngine *e; + uint32_t engines = 0; + uint32_t tx_engines = 0; + + for (e = sgh->engines ; e != NULL; e = e->next) { + engines++; + de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + } + for (e = sgh->tx_engines ; e != NULL; e = e->next) { + tx_engines++; + de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + } + SCLogDebug("SGH %p: engines %u tx_engines %u", sgh, engines, tx_engines); +#endif + SigGroupHeadBuildNonPrefilterArray(de_ctx, sgh); sgh->id = idx; diff --git a/src/detect.h b/src/detect.h index 2021a070018c..81577b040916 100644 --- a/src/detect.h +++ b/src/detect.h @@ -669,6 +669,7 @@ typedef struct DetectEngineCtx_ { struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; struct SCProfileSghDetectCtx_ *profile_sgh_ctx; uint32_t profile_match_logging_threshold; + uint32_t profile_prefilter_maxid; #endif char config_prefix[64]; @@ -983,6 +984,10 @@ typedef struct PrefilterEngine_ { /** Free function for pectx data. If NULL the memory is not freed. */ void (*Free)(void *pectx); + const char *name; +#ifdef PROFILING + uint32_t profile_id; +#endif } PrefilterEngine; typedef struct SigGroupHeadInitData_ { @@ -1023,6 +1028,11 @@ typedef struct SigGroupHead_ { PrefilterEngine *engines; PrefilterEngine *tx_engines; +#ifdef PROFILING + uint32_t engines_cnt; + uint32_t tx_engines_cnt; +#endif + /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ Signature **match_array; diff --git a/src/suricata-common.h b/src/suricata-common.h index cb2c214837a5..ffbeafb65b20 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -310,27 +310,6 @@ #define BIT_U64(n) (1ULL << (n)) typedef enum PacketProfileDetectId_ { - PROF_DETECT_MPM, - PROF_DETECT_MPM_PACKET, /* PKT MPM */ - PROF_DETECT_MPM_PKT_STREAM, /* PKT inspected with stream MPM */ - PROF_DETECT_MPM_STREAM, /* STREAM MPM */ - PROF_DETECT_MPM_URI, - PROF_DETECT_MPM_HCBD, - PROF_DETECT_MPM_HSBD, - PROF_DETECT_MPM_HHD, - PROF_DETECT_MPM_HRHD, - PROF_DETECT_MPM_HMD, - PROF_DETECT_MPM_HCD, - PROF_DETECT_MPM_HRUD, - PROF_DETECT_MPM_HSMD, - PROF_DETECT_MPM_HSCD, - PROF_DETECT_MPM_HUAD, - PROF_DETECT_MPM_HHHD, - PROF_DETECT_MPM_HRHHD, - PROF_DETECT_MPM_DNSQUERY, - PROF_DETECT_MPM_TLSSNI, - PROF_DETECT_MPM_TLSISSUER, - PROF_DETECT_MPM_TLSSUBJECT, PROF_DETECT_IPONLY, PROF_DETECT_RULES, PROF_DETECT_STATEFUL, diff --git a/src/util-profiling.c b/src/util-profiling.c index 8ee1fcb1c480..76812a0325e5 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -29,6 +29,7 @@ #include "suricata-common.h" #include "decode.h" #include "detect.h" +#include "detect-engine-prefilter.h" #include "conf.h" #include "flow-worker.h" @@ -94,6 +95,9 @@ struct ProfileProtoRecords { SCProfilePacketData records4[257]; SCProfilePacketData records6[257]; }; +static SCProfilePacketData prefilter4[256][256]; +static SCProfilePacketData prefilter6[256][256]; + struct ProfileProtoRecords packet_profile_flowworker_data[PROFILE_FLOWWORKER_SIZE]; @@ -174,6 +178,8 @@ SCProfilingInit(void) memset(&packet_profile_log_data4, 0, sizeof(packet_profile_log_data4)); memset(&packet_profile_log_data6, 0, sizeof(packet_profile_log_data6)); memset(&packet_profile_flowworker_data, 0, sizeof(packet_profile_flowworker_data)); + memset(&prefilter4, 0, sizeof(prefilter4)); + memset(&prefilter6, 0, sizeof(prefilter6)); const char *filename = ConfNodeLookupChildValue(conf, "filename"); if (filename != NULL) { @@ -317,6 +323,85 @@ SCProfilingDump(void) SCLogPerf("Done dumping profiling data."); } +static void DumpPrefilterIP(FILE *fp, int ipv, uint64_t total) +{ + char totalstr[256]; + + int i; + for (i = 0; i < 256; i++) { + const char *name = PrefilterStoreGetName(i); + + for (int p = 0; p < 256; p++) { + SCProfilePacketData *pd = ipv == 4 ? &prefilter4[i][p] : &prefilter6[i][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / + (long double)total * 100; + + fprintf(fp, "%-30s IPv%d %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %11s %-6.2f\n", + name, ipv, p, pd->cnt, + pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } +} + +static void DumpPrefilter(FILE *fp) +{ + uint64_t total = 0; + + int i; + for (i = 0; i < 256; i++) { + for (int p = 0; p < 256; p++) { + SCProfilePacketData *pd = &prefilter4[i][p]; + total += pd->tot; + pd = &prefilter6[i][p]; + total += pd->tot; + } + } + + fprintf(fp, "\n%-30s %-6s %-5s %-12s %-12s %-12s %-12s %-11s %-3s\n", + "Prefilter", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot", "%%"); + fprintf(fp, "%-30s %-6s %-5s %-12s %-12s %-12s %-12s %-11s %-3s\n", + "--------------------", "------", "-----", "----------", + "------------", "------------", "-----------", "---------", "---"); + DumpPrefilterIP(fp, 4, total); + DumpPrefilterIP(fp, 6, total); +} + +static void SCProfilingUpdatePrefilterRecords(Packet *p) +{ + if (p->profile->prefilter.engines != NULL) { + uint32_t x; + for (x = 0; x < p->profile->prefilter.size; x++) { + uint64_t ticks = p->profile->prefilter.engines[x].ticks_spent; + if (ticks == 0) + continue; + + SCProfilePacketData *pd = NULL; + if (PKT_IS_IPV4(p)) { + pd = &prefilter4[x][p->proto]; + } else if (PKT_IS_IPV6(p)) { + pd = &prefilter6[x][p->proto]; + } else { + continue; + } + + if (pd->min == 0 || ticks < pd->min) { + pd->min = ticks; + } + if (pd->max < ticks) { + pd->max = ticks; + } + + pd->tot += ticks; + pd->cnt ++; + } + } +} + static void DumpFlowWorkerIP(FILE *fp, int ipv, uint64_t total) { char totalstr[256]; @@ -743,6 +828,8 @@ void SCProfilingDumpPacketStats(void) } } + DumpPrefilter(fp); + fprintf(fp, "\nGeneral detection engine stats:\n"); total = 0; @@ -1166,6 +1253,8 @@ void SCProfilingAddPacket(Packet *p) SCProfilingUpdatePacketDetectRecords(p); SCProfilingUpdatePacketLogRecords(p); } + + SCProfilingUpdatePrefilterRecords(p); } pthread_mutex_unlock(&packet_profile_lock); } @@ -1209,25 +1298,6 @@ int SCProfileRuleStart(Packet *p) const char * PacketProfileDetectIdToString(PacketProfileDetectId id) { switch (id) { - CASE_CODE (PROF_DETECT_MPM); - CASE_CODE (PROF_DETECT_MPM_PACKET); -// CASE_CODE (PROF_DETECT_MPM_PKT_STREAM); - CASE_CODE (PROF_DETECT_MPM_STREAM); - CASE_CODE (PROF_DETECT_MPM_URI); - CASE_CODE (PROF_DETECT_MPM_HCBD); - CASE_CODE (PROF_DETECT_MPM_HSBD); - CASE_CODE (PROF_DETECT_MPM_HHD); - CASE_CODE (PROF_DETECT_MPM_HRHD); - CASE_CODE (PROF_DETECT_MPM_HMD); - CASE_CODE (PROF_DETECT_MPM_HCD); - CASE_CODE (PROF_DETECT_MPM_HRUD); - CASE_CODE (PROF_DETECT_MPM_HSMD); - CASE_CODE (PROF_DETECT_MPM_HSCD); - CASE_CODE (PROF_DETECT_MPM_HUAD); - CASE_CODE (PROF_DETECT_MPM_DNSQUERY); - CASE_CODE (PROF_DETECT_MPM_TLSSNI); - CASE_CODE (PROF_DETECT_MPM_TLSISSUER); - CASE_CODE (PROF_DETECT_MPM_TLSSUBJECT); CASE_CODE (PROF_DETECT_IPONLY); CASE_CODE (PROF_DETECT_RULES); CASE_CODE (PROF_DETECT_PREFILTER); @@ -1236,8 +1306,6 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id) CASE_CODE (PROF_DETECT_CLEANUP); CASE_CODE (PROF_DETECT_GETSGH); CASE_CODE (PROF_DETECT_NONMPMLIST); - case PROF_DETECT_MPM_PKT_STREAM: - return "PROF_DETECT_MPM_PKT_STR"; default: return "UNKNOWN"; } diff --git a/src/util-profiling.h b/src/util-profiling.h index 990697ca1ec3..d10bee673e4d 100644 --- a/src/util-profiling.h +++ b/src/util-profiling.h @@ -179,6 +179,7 @@ PktProfiling *SCProfilePacketStart(void); #define PACKET_PROFILING_RESET(p) \ if (profiling_packets_enabled && (p)->profile != NULL) { \ + SCFree((p)->profile->prefilter.engines); \ SCFree((p)->profile); \ (p)->profile = NULL; \ } @@ -274,6 +275,34 @@ PktProfiling *SCProfilePacketStart(void); SCProfilingSghUpdateCounter((det_ctx), (sgh)); \ } +#define PROFILING_PREFILTER_RESET(p, detectsize) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((p)->profile->prefilter.size != ((detectsize) + 1)) { \ + if ((p)->profile->prefilter.engines != NULL) \ + SCFree((p)->profile->prefilter.engines); \ + (p)->profile->prefilter.engines = \ + SCCalloc((detectsize)+1, sizeof(PktProfilingPrefilterEngine)); \ + (p)->profile->prefilter.size = (detectsize)+1;\ + } else { \ + memset((p)->profile->prefilter.engines, 0x00, \ + ((detectsize)+1 * sizeof(PktProfilingPrefilterEngine))); \ + } \ + } \ + +#define PROFILING_PREFILTER_START(p) \ + uint64_t ticks_start = 0; \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + ticks_start = UtilCpuGetTicks(); \ + } \ + +#define PROFILING_PREFILTER_END(p, profile_id) \ + if (profiling_packets_enabled && (p)->profile != NULL && \ + ticks_start) \ + { \ + uint64_t ticks_end = UtilCpuGetTicks(); \ + (p)->profile->prefilter.engines[(profile_id)].ticks_spent += (ticks_end - ticks_start); \ + ticks_start = 0; \ + } \ void SCProfilingRulesGlobalInit(void); void SCProfilingRuleDestroyCtx(struct SCProfileDetectCtx_ *); @@ -338,6 +367,10 @@ void SCProfilingDump(void); #define FLOWWORKER_PROFILING_START(p, id) #define FLOWWORKER_PROFILING_END(p, id) +#define PROFILING_PREFILTER_RESET(p, detectsize) +#define PROFILING_PREFILTER_START(p) +#define PROFILING_PREFILTER_END(p, profile_id) + #endif /* PROFILING */ #endif /* ! __UTIL_PROFILE_H__ */ From 31ad0a133b9bb7d3e2384467fb3befd552ec803a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 14 Jul 2016 17:17:31 +0200 Subject: [PATCH 1910/2553] prefilter: engine for tcp flags keyword If there are many rules for TCP flags these rules would be inspected against each TCP packet. Even though the flags check is not expensive, the combined cost of inspecting multiple rules against each and every packet is high. This patch implements a prefilter engine for flags. If a rule group has rules looking for specific flags and engine for that flag or flags combination is set up. This way those rules are only inspected if the flag is actually present in the packet. --- src/detect-flags.c | 139 ++++++++++++++++++++++++++++++++++----------- src/detect.h | 2 + 2 files changed, 107 insertions(+), 34 deletions(-) diff --git a/src/detect-flags.c b/src/detect-flags.c index 1d6c3d11aadf..b1524671c3fc 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -29,6 +29,8 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" #include "flow-var.h" #include "decode-events.h" @@ -60,6 +62,9 @@ static int DetectFlagsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Si static int DetectFlagsSetup (DetectEngineCtx *, Signature *, char *); static void DetectFlagsFree(void *); +static _Bool PrefilterTcpFlagsIsPrefilterable(const Signature *s); +static int PrefilterSetupTcpFlags(SigGroupHead *sgh); + /** * \brief Registration function for flags: keyword */ @@ -72,67 +77,47 @@ void DetectFlagsRegister (void) sigmatch_table[DETECT_FLAGS].Free = DetectFlagsFree; sigmatch_table[DETECT_FLAGS].RegisterTests = FlagsRegisterTests; + sigmatch_table[DETECT_FLAGS].SupportsPrefilter = PrefilterTcpFlagsIsPrefilterable; + sigmatch_table[DETECT_FLAGS].SetupPrefilter = PrefilterSetupTcpFlags; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/** - * \internal - * \brief This function is used to match flags on a packet with those passed via flags: - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param s pointer to the Signature - * \param m pointer to the sigmatch - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static inline int FlagsMatch(const uint8_t pflags, const uint8_t modifier, + const uint8_t dflags, const uint8_t iflags) { - SCEnter(); - - uint8_t flags = 0; - const DetectFlagsData *de = (const DetectFlagsData *)ctx; - - if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { - SCReturnInt(0); - } - - flags = p->tcph->th_flags; - - if (!de->flags && flags) { - if(de->modifier == MODIFIER_NOT) { + if (!dflags && pflags) { + if(modifier == MODIFIER_NOT) { SCReturnInt(1); } SCReturnInt(0); } - flags &= de->ignored_flags; + const uint8_t flags = pflags & iflags; - switch (de->modifier) { + switch (modifier) { case MODIFIER_ANY: - if ((flags & de->flags) > 0) { + if ((flags & dflags) > 0) { SCReturnInt(1); } SCReturnInt(0); case MODIFIER_PLUS: - if (((flags & de->flags) == de->flags)) { + if (((flags & dflags) == dflags)) { SCReturnInt(1); } SCReturnInt(0); case MODIFIER_NOT: - if ((flags & de->flags) != de->flags) { + if ((flags & dflags) != dflags) { SCReturnInt(1); } SCReturnInt(0); default: - SCLogDebug("flags %"PRIu8" and de->flags %"PRIu8"",flags,de->flags); - if (flags == de->flags) { + SCLogDebug("flags %"PRIu8" and de->flags %"PRIu8"", flags, dflags); + if (flags == dflags) { SCReturnInt(1); } } @@ -140,6 +125,33 @@ static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack SCReturnInt(0); } +/** + * \internal + * \brief This function is used to match flags on a packet with those passed via flags: + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param s pointer to the Signature + * \param m pointer to the sigmatch + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { + SCReturnInt(0); + } + + const DetectFlagsData *de = (const DetectFlagsData *)ctx; + const uint8_t flags = p->tcph->th_flags; + + return FlagsMatch(flags, de->modifier, de->flags, de->ignored_flags); +} + /** * \internal * \brief This function is used to parse flags options passed via flags: keyword @@ -540,6 +552,65 @@ int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s) return 0; } +static void +PrefilterPacketFlagsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + const PrefilterPacketHeaderCtx *ctx = pectx; + const uint8_t flags = p->tcph->th_flags; + + if (FlagsMatch(flags, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) + { + SCLogDebug("packet matches TCP flags %02x", ctx->v1.u8[1]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketFlagsSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectFlagsData *a = smctx; + v->u8[0] = a->modifier; + v->u8[1] = a->flags; + v->u8[2] = a->ignored_flags; + SCLogDebug("v->u8[0] = %02x", v->u8[0]); +} + +static _Bool +PrefilterPacketFlagsCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectFlagsData *a = smctx; + if (v.u8[0] == a->modifier && + v.u8[1] == a->flags && + v.u8[2] == a->ignored_flags) + return TRUE; + return FALSE; +} + +static int PrefilterSetupTcpFlags(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_FLAGS, + PrefilterPacketFlagsSet, + PrefilterPacketFlagsCompare, + PrefilterPacketFlagsMatch); + +} + +static _Bool PrefilterTcpFlagsIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FLAGS: + return TRUE; + } + } + return FALSE; +} + /* * ONLY TESTS BELOW THIS COMMENT */ diff --git a/src/detect.h b/src/detect.h index 81577b040916..06469d6eda15 100644 --- a/src/detect.h +++ b/src/detect.h @@ -457,6 +457,8 @@ typedef struct Signature_ { * to warn the user about any possible problem */ char *sig_str; + int prefilter_list; + /** ptr to the next sig in the list */ struct Signature_ *next; } Signature; From 3b4aa06377461773240ae5a3e68fbf1d3b100b21 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 15 Jul 2016 15:34:06 +0200 Subject: [PATCH 1911/2553] prefilter: engine for ack rules Rules for the 'ack' keyword are uncommon, but if used inspected against almost every packet. --- src/detect-ack.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/detect-ack.c b/src/detect-ack.c index eb1d8e64959d..75d3427eea33 100644 --- a/src/detect-ack.c +++ b/src/detect-ack.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -19,6 +19,7 @@ * \file * * \author Brian Rectanus + * \author Victor Julien * * Implements the "ack" keyword. */ @@ -31,6 +32,8 @@ #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" #include "detect-ack.h" @@ -45,6 +48,8 @@ static int DetectAckMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static void DetectAckRegisterTests(void); static void DetectAckFree(void *); +static int PrefilterSetupTcpAck(SigGroupHead *sgh); +static _Bool PrefilterTcpAckIsPrefilterable(const Signature *s); void DetectAckRegister(void) { @@ -54,6 +59,10 @@ void DetectAckRegister(void) sigmatch_table[DETECT_ACK].Match = DetectAckMatch; sigmatch_table[DETECT_ACK].Setup = DetectAckSetup; sigmatch_table[DETECT_ACK].Free = DetectAckFree; + + sigmatch_table[DETECT_ACK].SupportsPrefilter = PrefilterTcpAckIsPrefilterable; + sigmatch_table[DETECT_ACK].SetupPrefilter = PrefilterSetupTcpAck; + sigmatch_table[DETECT_ACK].RegisterTests = DetectAckRegisterTests; } @@ -140,6 +149,56 @@ static void DetectAckFree(void *ptr) SCFree(data); } +/* prefilter code */ + +static void +PrefilterPacketAckMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) && + (p->tcph != NULL) && (TCP_GET_ACK(p) == ctx->v1.u32[0])) + { + SCLogDebug("packet matches TCP ack %u", ctx->v1.u32[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketAckSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectAckData *a = smctx; + v->u32[0] = a->ack; +} + +static _Bool +PrefilterPacketAckCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectAckData *a = smctx; + if (v.u32[0] == a->ack) + return TRUE; + return FALSE; +} + +static int PrefilterSetupTcpAck(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ACK, + PrefilterPacketAckSet, + PrefilterPacketAckCompare, + PrefilterPacketAckMatch); +} + +static _Bool PrefilterTcpAckIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ACK: + return TRUE; + } + } + return FALSE; +} #ifdef UNITTESTS /** From 9ccd0c0f9081bad82921e50daad129705b91fda4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 18 Aug 2016 14:20:41 +0200 Subject: [PATCH 1912/2553] prefilter: implement fragbits --- src/detect-fragbits.c | 133 +++++++++++++++++++++++++++++++++--------- src/detect-fragbits.h | 2 +- 2 files changed, 107 insertions(+), 28 deletions(-) diff --git a/src/detect-fragbits.c b/src/detect-fragbits.c index 4150d3a6f5c4..293b0fdb2c11 100644 --- a/src/detect-fragbits.c +++ b/src/detect-fragbits.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -19,6 +19,7 @@ * \file * * \author Breno Silva + * \author Victor Julien * * Implements fragbits keyword */ @@ -29,6 +30,8 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" #include "flow-var.h" #include "decode-events.h" @@ -69,6 +72,9 @@ static int DetectFragBitsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, static int DetectFragBitsSetup (DetectEngineCtx *, Signature *, char *); static void DetectFragBitsFree(void *); +static int PrefilterSetupFragBits(SigGroupHead *sgh); +static _Bool PrefilterFragBitsIsPrefilterable(const Signature *s); + /** * \brief Registration function for fragbits: keyword */ @@ -83,9 +89,39 @@ void DetectFragBitsRegister (void) sigmatch_table[DETECT_FRAGBITS].Free = DetectFragBitsFree; sigmatch_table[DETECT_FRAGBITS].RegisterTests = FragBitsRegisterTests; + sigmatch_table[DETECT_FRAGBITS].SetupPrefilter = PrefilterSetupFragBits; + sigmatch_table[DETECT_FRAGBITS].SupportsPrefilter = PrefilterFragBitsIsPrefilterable; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } +static inline int +FragBitsMatch(const uint8_t pbits, const uint8_t modifier, + const uint8_t dbits) +{ + switch (modifier) { + case MODIFIER_ANY: + if ((pbits & dbits) > 0) + return 1; + return 0; + + case MODIFIER_PLUS: + if (((pbits & dbits) == dbits) && (((pbits - dbits) > 0))) + return 1; + return 0; + + case MODIFIER_NOT: + if ((pbits & dbits) != dbits) + return 1; + return 0; + + default: + if (pbits == dbits) + return 1; + } + return 0; +} + /** * \internal * \brief This function is used to match fragbits on a packet with those passed via fragbits: @@ -99,15 +135,14 @@ void DetectFragBitsRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectFragBitsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectFragBitsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - uint16_t fragbits = 0; - const DetectFragBitsData *de = (const DetectFragBitsData *)ctx; - - if (!de || !PKT_IS_IPV4(p) || !p || PKT_IS_PSEUDOPKT(p)) - return ret; + if (!ctx || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) + return 0; + uint8_t fragbits = 0; + const DetectFragBitsData *de = (const DetectFragBitsData *)ctx; if(IPV4_GET_MF(p)) fragbits |= FRAGBITS_HAVE_MF; if(IPV4_GET_DF(p)) @@ -115,25 +150,7 @@ static int DetectFragBitsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, P if(IPV4_GET_RF(p)) fragbits |= FRAGBITS_HAVE_RF; - switch(de->modifier) { - case MODIFIER_ANY: - if((fragbits & de->fragbits) > 0) - return 1; - return ret; - case MODIFIER_PLUS: - if(((fragbits & de->fragbits) == de->fragbits) && (((fragbits - de->fragbits) > 0))) - return 1; - return ret; - case MODIFIER_NOT: - if((fragbits & de->fragbits) != de->fragbits) - return 1; - return ret; - default: - if(fragbits == de->fragbits) - return 1; - } - - return ret; + return FragBitsMatch(fragbits, de->modifier, de->fragbits); } /** @@ -307,6 +324,68 @@ static void DetectFragBitsFree(void *de_ptr) if(de) SCFree(de); } +static void +PrefilterPacketFragBitsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (!PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) + return; + + uint8_t fragbits = 0; + if (IPV4_GET_MF(p)) + fragbits |= FRAGBITS_HAVE_MF; + if (IPV4_GET_DF(p)) + fragbits |= FRAGBITS_HAVE_DF; + if (IPV4_GET_RF(p)) + fragbits |= FRAGBITS_HAVE_RF; + + if (FragBitsMatch(fragbits, ctx->v1.u8[0], ctx->v1.u8[1])) + { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketFragBitsSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectFragBitsData *fb = smctx; + v->u8[0] = fb->modifier; + v->u8[1] = fb->fragbits; +} + +static _Bool +PrefilterPacketFragBitsCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectFragBitsData *fb = smctx; + if (v.u8[0] == fb->modifier && + v.u8[1] == fb->fragbits) + { + return TRUE; + } + return FALSE; +} + +static int PrefilterSetupFragBits(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_FRAGBITS, + PrefilterPacketFragBitsSet, + PrefilterPacketFragBitsCompare, + PrefilterPacketFragBitsMatch); +} + +static _Bool PrefilterFragBitsIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FRAGBITS: + return TRUE; + } + } + return FALSE; +} + /* * ONLY TESTS BELOW THIS COMMENT */ diff --git a/src/detect-fragbits.h b/src/detect-fragbits.h index 2fdf03237ee8..d85886670334 100644 --- a/src/detect-fragbits.h +++ b/src/detect-fragbits.h @@ -39,7 +39,7 @@ */ typedef struct DetectFragBitsData_ { - uint16_t fragbits; /**< TCP fragbits */ + uint8_t fragbits; /**< IP fragbits */ uint8_t modifier; /**< !(1) +(2) *(3) modifiers */ } DetectFragBitsData; From 065d9bceaebd7427cde8461ec0fcc58a62e08e17 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Aug 2016 16:34:38 +0200 Subject: [PATCH 1913/2553] detect-dsize: enable prefilter support Enable prefilter support for the dsize keyword. --- src/detect-dsize.c | 91 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 8 deletions(-) diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 00da7727e697..0368c8364bac 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -28,6 +28,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "flow-var.h" @@ -53,6 +54,9 @@ static int DetectDsizeSetup (DetectEngineCtx *, Signature *s, char *str); void DsizeRegisterTests(void); static void DetectDsizeFree(void *); +static int PrefilterSetupDsize(SigGroupHead *sgh); +static _Bool PrefilterDsizeIsPrefilterable(const Signature *s); + /** * \brief Registration function for dsize: keyword */ @@ -66,9 +70,28 @@ void DetectDsizeRegister (void) sigmatch_table[DETECT_DSIZE].Free = DetectDsizeFree; sigmatch_table[DETECT_DSIZE].RegisterTests = DsizeRegisterTests; + sigmatch_table[DETECT_DSIZE].SupportsPrefilter = PrefilterDsizeIsPrefilterable; + sigmatch_table[DETECT_DSIZE].SetupPrefilter = PrefilterSetupDsize; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } +static inline int +DsizeMatch(const uint16_t psize, const uint8_t mode, + const uint16_t dsize, const uint16_t dsize2) +{ + if (mode == DETECTDSIZE_EQ && dsize == psize) + return 1; + else if (mode == DETECTDSIZE_LT && psize < dsize) + return 1; + else if (mode == DETECTDSIZE_GT && psize > dsize) + return 1; + else if (mode == DETECTDSIZE_RA && psize > dsize && psize < dsize2) + return 1; + + return 0; +} + /** * \internal * \brief This function is used to match flags on a packet with those passed via dsize: @@ -95,14 +118,7 @@ int DetectDsizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, SCLogDebug("p->payload_len %"PRIu16"", p->payload_len); - if (dd->mode == DETECTDSIZE_EQ && dd->dsize == p->payload_len) - ret = 1; - else if (dd->mode == DETECTDSIZE_LT && p->payload_len < dd->dsize) - ret = 1; - else if (dd->mode == DETECTDSIZE_GT && p->payload_len > dd->dsize) - ret = 1; - else if (dd->mode == DETECTDSIZE_RA && p->payload_len > dd->dsize && p->payload_len < dd->dsize2) - ret = 1; + ret = DsizeMatch(p->payload_len, dd->mode, dd->dsize, dd->dsize2); SCReturnInt(ret); } @@ -296,6 +312,65 @@ void DetectDsizeFree(void *de_ptr) if(dd) SCFree(dd); } +/* prefilter code */ + +static void +PrefilterPacketDsizeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + const PrefilterPacketHeaderCtx *ctx = pectx; + const uint16_t dsize = p->payload_len; + + if (DsizeMatch(dsize, ctx->v1.u8[0], ctx->v1.u16[1], ctx->v1.u16[2])) + { + SCLogDebug("packet matches dsize %u", dsize); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketDsizeSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectDsizeData *a = smctx; + v->u8[0] = a->mode; + v->u16[1] = a->dsize; + v->u16[2] = a->dsize2; +} + +static _Bool +PrefilterPacketDsizeCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectDsizeData *a = smctx; + if (v.u8[0] == a->mode && + v.u16[1] == a->dsize && + v.u16[2] == a->dsize2) + return TRUE; + return FALSE; +} + +static int PrefilterSetupDsize(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_DSIZE, + PrefilterPacketDsizeSet, + PrefilterPacketDsizeCompare, + PrefilterPacketDsizeMatch); +} + +static _Bool PrefilterDsizeIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_DSIZE: + return TRUE; + } + } + return FALSE; +} + /* * ONLY TESTS BELOW THIS COMMENT */ From 9195708d58cea902423f761d45ca070ec1d980e6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 19 Aug 2016 17:04:51 +0200 Subject: [PATCH 1914/2553] detect analyzer: give minimal prefilter info --- src/detect-engine-analyzer.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 2933c0a6d218..23775349f9c1 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -95,6 +95,13 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "%s\n", line); fprintf(fp_engine_analysis_FD, " Fast Pattern analysis:\n"); + if (s->prefilter_sm != NULL) { + fprintf(fp_engine_analysis_FD, " Prefilter on: %s\n", + sigmatch_table[s->prefilter_sm->type].name); + fprintf(fp_engine_analysis_FD, "\n"); + return; + } + if (fp_cd == NULL) { fprintf(fp_engine_analysis_FD, " No content present\n"); fprintf(fp_engine_analysis_FD, "\n"); @@ -858,7 +865,12 @@ void EngineAnalysisRules(const Signature *s, const char *line) } /* print fast pattern info */ - EngineAnalysisRulesPrintFP(s); + if (s->prefilter_sm) { + fprintf(rule_engine_analysis_FD, " Prefilter on: %s.\n", + sigmatch_table[s->prefilter_sm->type].name); + } else { + EngineAnalysisRulesPrintFP(s); + } /* this is where the warnings start */ if (warn_pcre_no_content /*rule_pcre > 0 && rule_content == 0 && rule_content_http == 0*/) { From 4104f8c066bd8bff3c6796746921ab0b4023ad66 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Aug 2016 11:00:43 +0200 Subject: [PATCH 1915/2553] detect-fragoffset: implement prefilter --- src/detect-fragoffset.c | 110 ++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 15 deletions(-) diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index 9e6f32e6432b..20277ade5592 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -31,6 +31,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-fragoffset.h" @@ -48,6 +49,9 @@ static int DetectFragOffsetSetup(DetectEngineCtx *, Signature *, char *); void DetectFragOffsetRegisterTests(void); void DetectFragOffsetFree(void *); +static int PrefilterSetupFragOffset(SigGroupHead *sgh); +static _Bool PrefilterFragOffsetIsPrefilterable(const Signature *s); + /** * \brief Registration function for fragoffset */ @@ -61,9 +65,31 @@ void DetectFragOffsetRegister (void) sigmatch_table[DETECT_FRAGOFFSET].Free = DetectFragOffsetFree; sigmatch_table[DETECT_FRAGOFFSET].RegisterTests = DetectFragOffsetRegisterTests; + sigmatch_table[DETECT_FRAGOFFSET].SupportsPrefilter = PrefilterFragOffsetIsPrefilterable; + sigmatch_table[DETECT_FRAGOFFSET].SetupPrefilter = PrefilterSetupFragOffset; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } +static inline int FragOffsetMatch(const uint16_t poffset, const uint8_t mode, + const uint16_t doffset) +{ + switch (mode) { + case FRAG_LESS: + if (poffset < doffset) + return 1; + break; + case FRAG_MORE: + if (poffset > doffset) + return 1; + break; + default: + if (poffset == doffset) + return 1; + } + return 0; +} + /** * \brief This function is used to match fragoffset rule option set on a packet * @@ -97,21 +123,7 @@ int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet return 0; } - switch (fragoff->mode) { - case FRAG_LESS: - if (frag < fragoff->frag_off) - return 1; - break; - case FRAG_MORE: - if (frag > fragoff->frag_off) - return 1; - break; - default: - if (frag == fragoff->frag_off) - return 1; - } - - return 0; + return FragOffsetMatch(frag, fragoff->mode, fragoff->frag_off);; } /** @@ -240,6 +252,74 @@ void DetectFragOffsetFree (void *ptr) SCFree(fragoff); } +static void +PrefilterPacketFragOffsetMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) + return; + + uint16_t frag; + + if (PKT_IS_IPV4(p)) { + frag = IPV4_GET_IPOFFSET(p); + } else if (PKT_IS_IPV6(p)) { + if (IPV6_EXTHDR_ISSET_FH(p)) { + frag = IPV6_EXTHDR_GET_FH_OFFSET(p); + } else { + return; + } + } else { + SCLogDebug("No IPv4 or IPv6 packet"); + return; + } + + const PrefilterPacketHeaderCtx *ctx = pectx; + if (FragOffsetMatch(frag, ctx->v1.u8[0], ctx->v1.u16[1])) + { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketFragOffsetSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectFragOffsetData *fb = smctx; + v->u8[0] = fb->mode; + v->u16[1] = fb->frag_off; +} + +static _Bool +PrefilterPacketFragOffsetCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectFragOffsetData *fb = smctx; + if (v.u8[0] == fb->mode && + v.u16[1] == fb->frag_off) + { + return TRUE; + } + return FALSE; +} + +static int PrefilterSetupFragOffset(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_FRAGOFFSET, + PrefilterPacketFragOffsetSet, + PrefilterPacketFragOffsetCompare, + PrefilterPacketFragOffsetMatch); +} + +static _Bool PrefilterFragOffsetIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FRAGOFFSET: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h" From 14b0537f9502ecbbdbc36f9120a064ee0f25c322 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Aug 2016 13:04:22 +0200 Subject: [PATCH 1916/2553] prefilter: implement basic prefilter priority order --- src/detect.c | 18 +++++++++++++++++- src/detect.h | 36 +++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/detect.c b/src/detect.c index ca6ebfd52937..cbc1d56bcf14 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3386,18 +3386,34 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) if (!(tmp_s->flags & SIG_FLAG_PREFILTER)) { int i; + int prefilter_list = DETECT_TBLSIZE; + + /* get the keyword supporting prefilter with the lowest type */ for (i = 0; i < DETECT_SM_LIST_DETECT_MAX; i++) { SigMatch *sm = tmp_s->sm_lists[i]; while (sm != NULL) { if (sigmatch_table[sm->type].SupportsPrefilter != NULL) { if (sigmatch_table[sm->type].SupportsPrefilter(tmp_s) == TRUE) { + prefilter_list = MIN(prefilter_list, sm->type); + } + } + sm = sm->next; + } + } + + /* apply that keyword as prefilter */ + if (prefilter_list != DETECT_TBLSIZE) { + for (i = 0; i < DETECT_SM_LIST_DETECT_MAX; i++) { + SigMatch *sm = tmp_s->sm_lists[i]; + while (sm != NULL) { + if (sm->type == prefilter_list) { tmp_s->prefilter_sm = sm; tmp_s->flags |= SIG_FLAG_PREFILTER; SCLogConfig("sid %u: prefilter is on \"%s\"", tmp_s->id, sigmatch_table[sm->type].name); break; } + sm = sm->next; } - sm = sm->next; } } } diff --git a/src/detect.h b/src/detect.h index 06469d6eda15..6bfb75df015c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1111,6 +1111,27 @@ enum { DETECT_PRIORITY, DETECT_REV, DETECT_CLASSTYPE, + + /* sorted by prefilter priority. Higher in this list means it will be + * picked over ones lower in the list */ + DETECT_ACK, + DETECT_SEQ, + DETECT_WINDOW, + DETECT_IPOPTS, + DETECT_FLAGS, + DETECT_FRAGBITS, + DETECT_FRAGOFFSET, + DETECT_TTL, + DETECT_TOS, + DETECT_ITYPE, + DETECT_ICODE, + DETECT_ICMP_ID, + DETECT_ICMP_SEQ, + DETECT_DSIZE, + + DETECT_FLOW, + /* end prefilter sort */ + DETECT_THRESHOLD, DETECT_METADATA, DETECT_REFERENCE, @@ -1119,8 +1140,6 @@ enum { DETECT_CONTENT, DETECT_URICONTENT, DETECT_PCRE, - DETECT_ACK, - DETECT_SEQ, DETECT_DEPTH, DETECT_DISTANCE, DETECT_WITHIN, @@ -1134,13 +1153,10 @@ enum { 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, @@ -1156,19 +1172,9 @@ enum { 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, From 822e034753130234b6713f28f355adc2d004d606 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Aug 2016 13:05:09 +0200 Subject: [PATCH 1917/2553] detect-flow: implement prefilter --- src/detect-flow.c | 117 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 29 deletions(-) diff --git a/src/detect-flow.c b/src/detect-flow.c index 304d97d9b937..78032cd005cd 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -30,6 +30,7 @@ #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" +#include "detect-engine-prefilter-common.h" #include "flow.h" #include "flow-var.h" @@ -53,6 +54,9 @@ static int DetectFlowSetup (DetectEngineCtx *, Signature *, char *); void DetectFlowRegisterTests(void); void DetectFlowFree(void *); +static int PrefilterSetupFlow(SigGroupHead *sgh); +static _Bool PrefilterFlowIsPrefilterable(const Signature *s); + /** * \brief Registration function for flow: keyword */ @@ -66,14 +70,39 @@ void DetectFlowRegister (void) sigmatch_table[DETECT_FLOW].Free = DetectFlowFree; sigmatch_table[DETECT_FLOW].RegisterTests = DetectFlowRegisterTests; + sigmatch_table[DETECT_FLOW].SupportsPrefilter = PrefilterFlowIsPrefilterable; + sigmatch_table[DETECT_FLOW].SetupPrefilter = PrefilterSetupFlow; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/* - * returns 0: no match - * 1: match - * -1: error - */ +static inline int FlowMatch(const uint8_t pflowflags, const uint16_t tflags, + const uint8_t dflags, const uint8_t match_cnt) +{ + uint8_t cnt = 0; + + if ((dflags & DETECT_FLOW_FLAG_TOSERVER) && (pflowflags & FLOW_PKT_TOSERVER)) { + cnt++; + } else if ((dflags & DETECT_FLOW_FLAG_TOCLIENT) && (pflowflags & FLOW_PKT_TOCLIENT)) { + cnt++; + } + + if ((dflags & DETECT_FLOW_FLAG_ESTABLISHED) && (pflowflags & FLOW_PKT_ESTABLISHED)) { + cnt++; + } else if (dflags & DETECT_FLOW_FLAG_STATELESS) { + cnt++; + } + + if (tflags & DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH) { + if (dflags & DETECT_FLOW_FLAG_ONLYSTREAM) + cnt++; + } else { + if (dflags & DETECT_FLOW_FLAG_NOSTREAM) + cnt++; + } + + return (match_cnt == cnt) ? 1 : 0; +} /** * \brief This function is used to match flow flags set on a packet with those passed via flow: @@ -102,32 +131,11 @@ int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S SCLogDebug("FLOW_PKT_ESTABLISHED"); } - uint8_t cnt = 0; const DetectFlowData *fd = (const DetectFlowData *)ctx; - if ((fd->flags & DETECT_FLOW_FLAG_TOSERVER) && (p->flowflags & FLOW_PKT_TOSERVER)) { - cnt++; - } else if ((fd->flags & DETECT_FLOW_FLAG_TOCLIENT) && (p->flowflags & FLOW_PKT_TOCLIENT)) { - cnt++; - } - - if ((fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) && (p->flowflags & FLOW_PKT_ESTABLISHED)) { - cnt++; - } else if (fd->flags & DETECT_FLOW_FLAG_STATELESS) { - cnt++; - } - - if (det_ctx->flags & DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH) { - if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) - cnt++; - } else { - if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) - cnt++; - } - - int ret = (fd->match_cnt == cnt) ? 1 : 0; - SCLogDebug("returning %" PRId32 " cnt %" PRIu8 " fd->match_cnt %" PRId32 " fd->flags 0x%02X p->flowflags 0x%02X", - ret, cnt, fd->match_cnt, fd->flags, p->flowflags); + int ret = FlowMatch(p->flowflags, det_ctx->flags, fd->flags, fd->match_cnt);; + SCLogDebug("returning %" PRId32 " fd->match_cnt %" PRId32 " fd->flags 0x%02X p->flowflags 0x%02X", + ret, fd->match_cnt, fd->flags, p->flowflags); SCReturnInt(ret); } @@ -338,6 +346,57 @@ void DetectFlowFree(void *ptr) SCFree(fd); } +static void +PrefilterPacketFlowMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (FlowMatch(p->flowflags, det_ctx->flags, ctx->v1.u8[0], ctx->v1.u8[1])) + { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketFlowSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectFlowData *fb = smctx; + v->u8[0] = fb->flags; + v->u8[1] = fb->match_cnt; +} + +static _Bool +PrefilterPacketFlowCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectFlowData *fb = smctx; + if (v.u8[0] == fb->flags && + v.u8[1] == fb->match_cnt) + { + return TRUE; + } + return FALSE; +} + +static int PrefilterSetupFlow(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_FLOW, + PrefilterPacketFlowSet, + PrefilterPacketFlowCompare, + PrefilterPacketFlowMatch); +} + +static _Bool PrefilterFlowIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FLOW: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS /** From 9ce300620e899ec189bcd22d9736076002a334dc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Aug 2016 13:11:01 +0200 Subject: [PATCH 1918/2553] detect-seq: implement prefilter --- src/detect-seq.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/detect-seq.c b/src/detect-seq.c index 279a54b19f5c..7df03ba941bf 100644 --- a/src/detect-seq.c +++ b/src/detect-seq.c @@ -30,7 +30,8 @@ #include "detect-parse.h" #include "detect-engine.h" -#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" #include "detect-seq.h" @@ -44,7 +45,8 @@ static int DetectSeqMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); static void DetectSeqRegisterTests(void); static void DetectSeqFree(void *); - +static int PrefilterSetupTcpSeq(SigGroupHead *sgh); +static _Bool PrefilterTcpSeqIsPrefilterable(const Signature *s); void DetectSeqRegister(void) { @@ -55,6 +57,9 @@ void DetectSeqRegister(void) sigmatch_table[DETECT_SEQ].Setup = DetectSeqSetup; sigmatch_table[DETECT_SEQ].Free = DetectSeqFree; sigmatch_table[DETECT_SEQ].RegisterTests = DetectSeqRegisterTests; + + sigmatch_table[DETECT_SEQ].SupportsPrefilter = PrefilterTcpSeqIsPrefilterable; + sigmatch_table[DETECT_SEQ].SetupPrefilter = PrefilterSetupTcpSeq; } /** @@ -139,6 +144,57 @@ static void DetectSeqFree(void *ptr) SCFree(data); } +/* prefilter code */ + +static void +PrefilterPacketSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) && + (p->tcph != NULL) && (TCP_GET_SEQ(p) == ctx->v1.u32[0])) + { + SCLogDebug("packet matches TCP seq %u", ctx->v1.u32[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketSeqSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectSeqData *a = smctx; + v->u32[0] = a->seq; +} + +static _Bool +PrefilterPacketSeqCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectSeqData *a = smctx; + if (v.u32[0] == a->seq) + return TRUE; + return FALSE; +} + +static int PrefilterSetupTcpSeq(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_SEQ, + PrefilterPacketSeqSet, + PrefilterPacketSeqCompare, + PrefilterPacketSeqMatch); +} + +static _Bool PrefilterTcpSeqIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_SEQ: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS From b88c0a56b99644693b5bef8ce0d552ca5ae2b55c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Aug 2016 13:25:37 +0200 Subject: [PATCH 1919/2553] detect-ttl: implement prefilter --- src/detect-ttl.c | 110 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 15 deletions(-) diff --git a/src/detect-ttl.c b/src/detect-ttl.c index 051131f95016..97e9055af4ca 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-ttl.h" #include "util-debug.h" @@ -47,6 +48,9 @@ static int DetectTtlSetup (DetectEngineCtx *, Signature *, char *); void DetectTtlFree (void *); void DetectTtlRegisterTests (void); +static int PrefilterSetupTtl(SigGroupHead *sgh); +static _Bool PrefilterTtlIsPrefilterable(const Signature *s); + /** * \brief Registration function for ttl: keyword */ @@ -61,10 +65,29 @@ void DetectTtlRegister(void) sigmatch_table[DETECT_TTL].Free = DetectTtlFree; sigmatch_table[DETECT_TTL].RegisterTests = DetectTtlRegisterTests; + sigmatch_table[DETECT_TTL].SupportsPrefilter = PrefilterTtlIsPrefilterable; + sigmatch_table[DETECT_TTL].SetupPrefilter = PrefilterSetupTtl; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); return; } +static inline int TtlMatch(const uint8_t pttl, const uint8_t mode, + const uint8_t dttl1, const uint8_t dttl2) +{ + if (mode == DETECT_TTL_EQ && pttl == dttl1) + return 1; + else if (mode == DETECT_TTL_LT && pttl < dttl1) + return 1; + else if (mode == DETECT_TTL_GT && pttl > dttl1) + return 1; + else if (mode == DETECT_TTL_RA && (pttl > dttl1 && pttl < dttl2)) + return 1; + + return 0; + +} + /** * \brief This function is used to match TTL rule option on a packet with those passed via ttl: * @@ -79,32 +102,21 @@ void DetectTtlRegister(void) int DetectTtlMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - uint8_t pttl; - const DetectTtlData *ttld = (const DetectTtlData *)ctx; - if (PKT_IS_PSEUDOPKT(p)) return 0; + uint8_t pttl; if (PKT_IS_IPV4(p)) { pttl = IPV4_GET_IPTTL(p); } else if (PKT_IS_IPV6(p)) { pttl = IPV6_GET_HLIM(p); } else { SCLogDebug("Packet is of not IPv4 or IPv6"); - return ret; + return 0; } - if (ttld->mode == DETECT_TTL_EQ && pttl == ttld->ttl1) - ret = 1; - else if (ttld->mode == DETECT_TTL_LT && pttl < ttld->ttl1) - ret = 1; - else if (ttld->mode == DETECT_TTL_GT && pttl > ttld->ttl1) - ret = 1; - else if (ttld->mode == DETECT_TTL_RA && (pttl > ttld->ttl1 && pttl < ttld->ttl2)) - ret = 1; - - return ret; + const DetectTtlData *ttld = (const DetectTtlData *)ctx; + return TtlMatch(pttl, ttld->mode, ttld->ttl1, ttld->ttl2); } /** @@ -293,6 +305,74 @@ void DetectTtlFree(void *ptr) SCFree(ttld); } +/* prefilter code */ + +static void +PrefilterPacketTtlMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + uint8_t pttl; + if (PKT_IS_IPV4(p)) { + pttl = IPV4_GET_IPTTL(p); + } else if (PKT_IS_IPV6(p)) { + pttl = IPV6_GET_HLIM(p); + } else { + SCLogDebug("Packet is of not IPv4 or IPv6"); + return; + } + + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (TtlMatch(pttl, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) + { + SCLogDebug("packet matches ttl/hl %u", pttl); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketTtlSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectTtlData *a = smctx; + v->u8[0] = a->mode; + v->u8[1] = a->ttl1; + v->u8[2] = a->ttl2; +} + +static _Bool +PrefilterPacketTtlCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectTtlData *a = smctx; + if (v.u8[0] == a->mode && + v.u8[1] == a->ttl1 && + v.u8[2] == a->ttl2) + return TRUE; + return FALSE; +} + +static int PrefilterSetupTtl(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_TTL, + PrefilterPacketTtlSet, + PrefilterPacketTtlCompare, + PrefilterPacketTtlMatch); +} + +static _Bool PrefilterTtlIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_TTL: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h" From 10f8e636d61e6aca87c5eac2749746f00ab43e72 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Aug 2016 15:59:22 +0200 Subject: [PATCH 1920/2553] detect-itype: implement prefilter --- src/detect-itype.c | 118 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 97 insertions(+), 21 deletions(-) diff --git a/src/detect-itype.c b/src/detect-itype.c index 00ad80288612..91395f0fd61b 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-itype.h" @@ -50,6 +51,8 @@ static int DetectITypeSetup(DetectEngineCtx *, Signature *, char *); void DetectITypeRegisterTests(void); void DetectITypeFree(void *); +static int PrefilterSetupIType(SigGroupHead *sgh); +static _Bool PrefilterITypeIsPrefilterable(const Signature *s); /** * \brief Registration function for itype: keyword @@ -64,9 +67,31 @@ void DetectITypeRegister (void) sigmatch_table[DETECT_ITYPE].Free = DetectITypeFree; sigmatch_table[DETECT_ITYPE].RegisterTests = DetectITypeRegisterTests; + sigmatch_table[DETECT_ITYPE].SupportsPrefilter = PrefilterITypeIsPrefilterable; + sigmatch_table[DETECT_ITYPE].SetupPrefilter = PrefilterSetupIType; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } +static inline int ITypeMatch(const uint8_t ptype, const uint8_t mode, + const uint8_t dtype1, const uint8_t dtype2) +{ + switch (mode) { + case DETECT_ITYPE_EQ: + return (ptype == dtype1) ? 1 : 0; + + case DETECT_ITYPE_LT: + return (ptype < dtype1) ? 1 : 0; + + case DETECT_ITYPE_GT: + return (ptype > dtype1) ? 1 : 0; + + case DETECT_ITYPE_RN: + return (ptype > dtype1 && ptype < dtype2) ? 1 : 0; + } + return 0; +} + /** * \brief This function is used to match itype rule option set on a packet with those passed via itype: * @@ -80,38 +105,21 @@ void DetectITypeRegister (void) */ int DetectITypeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - uint8_t pitype; - const DetectITypeData *itd = (const DetectITypeData *)ctx; - if (PKT_IS_PSEUDOPKT(p)) return 0; + uint8_t pitype; if (PKT_IS_ICMPV4(p)) { pitype = ICMPV4_GET_TYPE(p); } else if (PKT_IS_ICMPV6(p)) { pitype = ICMPV6_GET_TYPE(p); } else { /* Packet not ICMPv4 nor ICMPv6 */ - return ret; - } - - switch(itd->mode) { - case DETECT_ITYPE_EQ: - ret = (pitype == itd->type1) ? 1 : 0; - break; - case DETECT_ITYPE_LT: - ret = (pitype < itd->type1) ? 1 : 0; - break; - case DETECT_ITYPE_GT: - ret = (pitype > itd->type1) ? 1 : 0; - break; - case DETECT_ITYPE_RN: - ret = (pitype > itd->type1 && pitype < itd->type2) ? 1 : 0; - break; + return 0; } - return ret; + const DetectITypeData *itd = (const DetectITypeData *)ctx; + return ITypeMatch(pitype, itd->mode, itd->type1, itd->type2); } /** @@ -263,6 +271,74 @@ void DetectITypeFree(void *ptr) SCFree(itd); } +/* prefilter code */ + +static void +PrefilterPacketITypeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + uint8_t pitype; + if (PKT_IS_ICMPV4(p)) { + pitype = ICMPV4_GET_TYPE(p); + } else if (PKT_IS_ICMPV6(p)) { + pitype = ICMPV6_GET_TYPE(p); + } else { + /* Packet not ICMPv4 nor ICMPv6 */ + return; + } + + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (ITypeMatch(pitype, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) + { + SCLogDebug("packet matches ICMP type %u", pitype); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketITypeSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectITypeData *a = smctx; + v->u8[0] = a->mode; + v->u8[1] = a->type1; + v->u8[2] = a->type2; +} + +static _Bool +PrefilterPacketITypeCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectITypeData *a = smctx; + if (v.u8[0] == a->mode && + v.u8[1] == a->type1 && + v.u8[2] == a->type2) + return TRUE; + return FALSE; +} + +static int PrefilterSetupIType(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ITYPE, + PrefilterPacketITypeSet, + PrefilterPacketITypeCompare, + PrefilterPacketITypeMatch); +} + +static _Bool PrefilterITypeIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ITYPE: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS #include "detect-engine.h" From d5e5c11bd1582704606ced7d95c168fd2a5b01ef Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Aug 2016 16:26:37 +0200 Subject: [PATCH 1921/2553] detect-icode: implement prefilter --- src/detect-icode.c | 120 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 22 deletions(-) diff --git a/src/detect-icode.c b/src/detect-icode.c index cc91bce1fabc..111fa7cdeb64 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-icode.h" @@ -50,6 +51,8 @@ static int DetectICodeSetup(DetectEngineCtx *, Signature *, char *); void DetectICodeRegisterTests(void); void DetectICodeFree(void *); +static int PrefilterSetupICode(SigGroupHead *sgh); +static _Bool PrefilterICodeIsPrefilterable(const Signature *s); /** * \brief Registration function for icode: keyword @@ -64,9 +67,31 @@ void DetectICodeRegister (void) sigmatch_table[DETECT_ICODE].Free = DetectICodeFree; sigmatch_table[DETECT_ICODE].RegisterTests = DetectICodeRegisterTests; + sigmatch_table[DETECT_ICODE].SupportsPrefilter = PrefilterICodeIsPrefilterable; + sigmatch_table[DETECT_ICODE].SetupPrefilter = PrefilterSetupICode; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } +static inline int ICodeMatch(const uint8_t pcode, const uint8_t mode, + const uint8_t dcode1, const uint8_t dcode2) +{ + switch (mode) { + case DETECT_ICODE_EQ: + return (pcode == dcode1) ? 1 : 0; + + case DETECT_ICODE_LT: + return (pcode < dcode1) ? 1 : 0; + + case DETECT_ICODE_GT: + return (pcode > dcode1) ? 1 : 0; + + case DETECT_ICODE_RN: + return (pcode > dcode1 && pcode < dcode2) ? 1 : 0; + } + return 0; +} + /** * \brief This function is used to match icode rule option set on a packet with those passed via icode: * @@ -80,38 +105,21 @@ void DetectICodeRegister (void) */ int DetectICodeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - uint8_t picode; - const DetectICodeData *icd = (const DetectICodeData *)ctx; - if (PKT_IS_PSEUDOPKT(p)) return 0; + uint8_t picode; if (PKT_IS_ICMPV4(p)) { picode = ICMPV4_GET_CODE(p); } else if (PKT_IS_ICMPV6(p)) { picode = ICMPV6_GET_CODE(p); } else { /* Packet not ICMPv4 nor ICMPv6 */ - return ret; - } - - switch(icd->mode) { - case DETECT_ICODE_EQ: - ret = (picode == icd->code1) ? 1 : 0; - break; - case DETECT_ICODE_LT: - ret = (picode < icd->code1) ? 1 : 0; - break; - case DETECT_ICODE_GT: - ret = (picode > icd->code1) ? 1 : 0; - break; - case DETECT_ICODE_RN: - ret = (picode >= icd->code1 && picode <= icd->code2) ? 1 : 0; - break; + return 0; } - return ret; + const DetectICodeData *icd = (const DetectICodeData *)ctx; + return ICodeMatch(picode, icd->mode, icd->code1, icd->code2); } /** @@ -263,6 +271,74 @@ void DetectICodeFree(void *ptr) SCFree(icd); } +/* prefilter code */ + +static void +PrefilterPacketICodeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + uint8_t picode; + if (PKT_IS_ICMPV4(p)) { + picode = ICMPV4_GET_CODE(p); + } else if (PKT_IS_ICMPV6(p)) { + picode = ICMPV6_GET_CODE(p); + } else { + /* Packet not ICMPv4 nor ICMPv6 */ + return; + } + + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (ICodeMatch(picode, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) + { + SCLogDebug("packet matches ICMP code %u", picode); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketICodeSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectICodeData *a = smctx; + v->u8[0] = a->mode; + v->u8[1] = a->code1; + v->u8[2] = a->code2; +} + +static _Bool +PrefilterPacketICodeCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectICodeData *a = smctx; + if (v.u8[0] == a->mode && + v.u8[1] == a->code1 && + v.u8[2] == a->code2) + return TRUE; + return FALSE; +} + +static int PrefilterSetupICode(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ICODE, + PrefilterPacketICodeSet, + PrefilterPacketICodeCompare, + PrefilterPacketICodeMatch); +} + +static _Bool PrefilterICodeIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ICODE: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h" From f5d2166e23e693b0133651e3f272ff58a804f3e3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Aug 2016 17:02:13 +0200 Subject: [PATCH 1922/2553] detect-id: implement prefilter --- src/detect-id.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/detect-id.c b/src/detect-id.c index 9b2b7a849f54..5034d34db687 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -31,6 +31,7 @@ #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" +#include "detect-engine-prefilter-common.h" #include "detect-id.h" #include "flow.h" @@ -54,6 +55,9 @@ static int DetectIdSetup (DetectEngineCtx *, Signature *, char *); void DetectIdRegisterTests(void); void DetectIdFree(void *); +static int PrefilterSetupId(SigGroupHead *sgh); +static _Bool PrefilterIdIsPrefilterable(const Signature *s); + /** * \brief Registration function for keyword: id */ @@ -67,6 +71,9 @@ void DetectIdRegister (void) sigmatch_table[DETECT_ID].Free = DetectIdFree; sigmatch_table[DETECT_ID].RegisterTests = DetectIdRegisterTests; + sigmatch_table[DETECT_ID].SupportsPrefilter = PrefilterIdIsPrefilterable; + sigmatch_table[DETECT_ID].SetupPrefilter = PrefilterSetupId; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } @@ -229,6 +236,60 @@ void DetectIdFree(void *ptr) SCFree(id_d); } +/* prefilter code */ + +static void +PrefilterPacketIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (!PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) { + return; + } + + if (IPV4_GET_IPID(p) == ctx->v1.u16[0]) + { + SCLogDebug("packet matches IP id %u", ctx->v1.u16[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketIdSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectIdData *a = smctx; + v->u16[0] = a->id; +} + +static _Bool +PrefilterPacketIdCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectIdData *a = smctx; + if (v.u16[0] == a->id) + return TRUE; + return FALSE; +} + +static int PrefilterSetupId(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ID, + PrefilterPacketIdSet, + PrefilterPacketIdCompare, + PrefilterPacketIdMatch); +} + +static _Bool PrefilterIdIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ID: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS /* UNITTESTS */ /** From 6a3917b375a8c4298a02105d6f52359770bc76b9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 22 Aug 2016 15:21:55 +0200 Subject: [PATCH 1923/2553] detect-itype: implement as u8 hash prefilter --- src/detect-itype.c | 34 ++++++++++++++++++++++++---------- src/detect-itype.h | 12 ------------ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/detect-itype.c b/src/detect-itype.c index 91395f0fd61b..f453a11520ed 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -73,6 +73,18 @@ void DetectITypeRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } +#define DETECT_ITYPE_EQ PREFILTER_U8HASH_MODE_EQ /**< "equal" operator */ +#define DETECT_ITYPE_LT PREFILTER_U8HASH_MODE_LT /**< "less than" operator */ +#define DETECT_ITYPE_GT PREFILTER_U8HASH_MODE_GT /**< "greater than" operator */ +#define DETECT_ITYPE_RN PREFILTER_U8HASH_MODE_RA /**< "range" operator */ + +typedef struct DetectITypeData_ { + uint8_t type1; + uint8_t type2; + + uint8_t mode; +} DetectITypeData; + static inline int ITypeMatch(const uint8_t ptype, const uint8_t mode, const uint8_t dtype1, const uint8_t dtype2) { @@ -271,10 +283,14 @@ void DetectITypeFree(void *ptr) SCFree(itd); } -/* prefilter code */ +/* prefilter code + * + * Prefilter uses the U8Hash logic, where we setup a 256 entry array + * for each ICMP type. Each array element has the list of signatures + * that need to be inspected. */ -static void -PrefilterPacketITypeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketITypeMatch(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx) { if (PKT_IS_PSEUDOPKT(p)) { SCReturn; @@ -290,12 +306,10 @@ PrefilterPacketITypeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void return; } - const PrefilterPacketHeaderCtx *ctx = pectx; - - if (ITypeMatch(pitype, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) - { - SCLogDebug("packet matches ICMP type %u", pitype); - PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + const PrefilterPacketU8HashCtx *h = pectx; + const SigsArray *sa = h->array[pitype]; + if (sa) { + PrefilterAddSids(&det_ctx->pmq, sa->sigs, sa->cnt); } } @@ -321,7 +335,7 @@ PrefilterPacketITypeCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupIType(SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(sgh, DETECT_ITYPE, + return PrefilterSetupPacketHeaderU8Hash(sgh, DETECT_ITYPE, PrefilterPacketITypeSet, PrefilterPacketITypeCompare, PrefilterPacketITypeMatch); diff --git a/src/detect-itype.h b/src/detect-itype.h index 168e0e7b36b3..c8d1092e6bfc 100644 --- a/src/detect-itype.h +++ b/src/detect-itype.h @@ -24,18 +24,6 @@ #ifndef __DETECT_ITYPE_H__ #define __DETECT_ITYPE_H__ -#define DETECT_ITYPE_EQ 0 /**< "equal" operator */ -#define DETECT_ITYPE_LT 1 /**< "less than" operator */ -#define DETECT_ITYPE_GT 2 /**< "greater than" operator */ -#define DETECT_ITYPE_RN 3 /**< "range" operator */ - -typedef struct DetectITypeData_ { - uint8_t type1; - uint8_t type2; - - uint8_t mode; -} DetectITypeData; - /* prototypes */ void DetectITypeRegister(void); From 3a86aeac65bedb5a002fa929940dde2c55ba60ce Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 22 Aug 2016 16:29:48 +0200 Subject: [PATCH 1924/2553] detect-icode: implement as u8 hash prefilter --- src/detect-icode.c | 28 +++++++++++++++++++--------- src/detect-icode.h | 12 ------------ 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/detect-icode.c b/src/detect-icode.c index 111fa7cdeb64..ef3c92e94d67 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -73,6 +73,18 @@ void DetectICodeRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } +#define DETECT_ICODE_EQ PREFILTER_U8HASH_MODE_EQ /**< "equal" operator */ +#define DETECT_ICODE_LT PREFILTER_U8HASH_MODE_LT /**< "less than" operator */ +#define DETECT_ICODE_GT PREFILTER_U8HASH_MODE_GT /**< "greater than" operator */ +#define DETECT_ICODE_RN PREFILTER_U8HASH_MODE_RA /**< "range" operator */ + +typedef struct DetectICodeData_ { + uint8_t code1; + uint8_t code2; + + uint8_t mode; +} DetectICodeData; + static inline int ICodeMatch(const uint8_t pcode, const uint8_t mode, const uint8_t dcode1, const uint8_t dcode2) { @@ -273,8 +285,8 @@ void DetectICodeFree(void *ptr) /* prefilter code */ -static void -PrefilterPacketICodeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketICodeMatch(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx) { if (PKT_IS_PSEUDOPKT(p)) { SCReturn; @@ -290,12 +302,10 @@ PrefilterPacketICodeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void return; } - const PrefilterPacketHeaderCtx *ctx = pectx; - - if (ICodeMatch(picode, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) - { - SCLogDebug("packet matches ICMP code %u", picode); - PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + const PrefilterPacketU8HashCtx *h = pectx; + const SigsArray *sa = h->array[picode]; + if (sa) { + PrefilterAddSids(&det_ctx->pmq, sa->sigs, sa->cnt); } } @@ -321,7 +331,7 @@ PrefilterPacketICodeCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupICode(SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(sgh, DETECT_ICODE, + return PrefilterSetupPacketHeaderU8Hash(sgh, DETECT_ICODE, PrefilterPacketICodeSet, PrefilterPacketICodeCompare, PrefilterPacketICodeMatch); diff --git a/src/detect-icode.h b/src/detect-icode.h index 88a4d4814065..9d0a179c2f5e 100644 --- a/src/detect-icode.h +++ b/src/detect-icode.h @@ -26,18 +26,6 @@ #ifndef __DETECT_ICODE_H__ #define __DETECT_ICODE_H__ -#define DETECT_ICODE_EQ 0 /**< "equal" operator */ -#define DETECT_ICODE_LT 1 /**< "less than" operator */ -#define DETECT_ICODE_GT 2 /**< "greater than" operator */ -#define DETECT_ICODE_RN 3 /**< "range" operator */ - -typedef struct DetectICodeData_ { - uint8_t code1; - uint8_t code2; - - uint8_t mode; -}DetectICodeData; - /* prototypes */ void DetectICodeRegister(void); From fbe7e0aaebcb2b9d2503ba2f26702e4745e28138 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 22 Aug 2016 18:44:00 +0200 Subject: [PATCH 1925/2553] detect-icmp-seq: prefilter --- src/detect-icmp-seq.c | 106 +++++++++++++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 17 deletions(-) diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index 4026b3756128..017e562560d0 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-icmp-seq.h" @@ -46,6 +47,8 @@ int DetectIcmpSeqMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signatur static int DetectIcmpSeqSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpSeqRegisterTests(void); void DetectIcmpSeqFree(void *); +static int PrefilterSetupIcmpSeq(SigGroupHead *sgh); +static _Bool PrefilterIcmpSeqIsPrefilterable(const Signature *s); /** * \brief Registration function for icmp_seq @@ -60,27 +63,18 @@ void DetectIcmpSeqRegister (void) sigmatch_table[DETECT_ICMP_SEQ].Free = DetectIcmpSeqFree; sigmatch_table[DETECT_ICMP_SEQ].RegisterTests = DetectIcmpSeqRegisterTests; + sigmatch_table[DETECT_ICMP_SEQ].SupportsPrefilter = PrefilterIcmpSeqIsPrefilterable; + sigmatch_table[DETECT_ICMP_SEQ].SetupPrefilter = PrefilterSetupIcmpSeq; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/** - * \brief This function is used to match icmp_seq rule option set on a packet - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectIcmpSeqData - * - * \retval 0 no match - * \retval 1 match - */ -int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static inline _Bool GetIcmpSeq(Packet *p, uint16_t *seq) { uint16_t seqn; - const DetectIcmpSeqData *iseq = (const DetectIcmpSeqData *)ctx; if (PKT_IS_PSEUDOPKT(p)) - return 0; + return FALSE; if (PKT_IS_ICMPV4(p)) { switch (ICMPV4_GET_TYPE(p)){ @@ -100,7 +94,7 @@ int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p break; default: SCLogDebug("Packet has no seq field"); - return 0; + return FALSE; } } else if (PKT_IS_ICMPV6(p)) { @@ -115,13 +109,36 @@ int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p break; default: SCLogDebug("Packet has no seq field"); - return 0; + return FALSE; } } else { SCLogDebug("Packet not ICMPV4 nor ICMPV6"); - return 0; + return FALSE; } + *seq = seqn; + return TRUE; +} + +/** + * \brief This function is used to match icmp_seq rule option set on a packet + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectIcmpSeqData + * + * \retval 0 no match + * \retval 1 match + */ +int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + uint16_t seqn; + + if (GetIcmpSeq(p, &seqn) == FALSE) + return 0; + + const DetectIcmpSeqData *iseq = (const DetectIcmpSeqData *)ctx; if (seqn == iseq->seq) return 1; @@ -248,6 +265,61 @@ void DetectIcmpSeqFree (void *ptr) SCFree(iseq); } +/* prefilter code */ + +static void +PrefilterPacketIcmpSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + uint16_t seqn; + + if (GetIcmpSeq(p, &seqn) == FALSE) + return; + + if (seqn == ctx->v1.u16[0]) + { + SCLogDebug("packet matches ICMP SEQ %u", ctx->v1.u16[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketIcmpSeqSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectIcmpSeqData *a = smctx; + v->u16[0] = a->seq; +} + +static _Bool +PrefilterPacketIcmpSeqCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectIcmpSeqData *a = smctx; + if (v.u16[0] == a->seq) + return TRUE; + return FALSE; +} + +static int PrefilterSetupIcmpSeq(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ICMP_SEQ, + PrefilterPacketIcmpSeqSet, + PrefilterPacketIcmpSeqCompare, + PrefilterPacketIcmpSeqMatch); +} + +static _Bool PrefilterIcmpSeqIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ICMP_SEQ: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h" From 5537e25f384bd7e27f8fa871cd739dc65b1a29c4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 22 Aug 2016 18:44:08 +0200 Subject: [PATCH 1926/2553] detect-icmp-id: prefilter --- src/detect-icmp-id.c | 108 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 19 deletions(-) diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index 34be0d7bb421..820d276cf1fb 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-icmp-id.h" @@ -46,6 +47,8 @@ int DetectIcmpIdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature static int DetectIcmpIdSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpIdRegisterTests(void); void DetectIcmpIdFree(void *); +static int PrefilterSetupIcmpId(SigGroupHead *sgh); +static _Bool PrefilterIcmpIdIsPrefilterable(const Signature *s); /** * \brief Registration function for icode: icmp_id @@ -60,28 +63,18 @@ void DetectIcmpIdRegister (void) sigmatch_table[DETECT_ICMP_ID].Free = DetectIcmpIdFree; sigmatch_table[DETECT_ICMP_ID].RegisterTests = DetectIcmpIdRegisterTests; + sigmatch_table[DETECT_ICMP_ID].SupportsPrefilter = PrefilterIcmpIdIsPrefilterable; + sigmatch_table[DETECT_ICMP_ID].SetupPrefilter = PrefilterSetupIcmpId; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/** - * \brief This function is used to match icmp_id rule option set on a packet - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectIcmpIdData - * - * \retval 0 no match - * \retval 1 match - */ -int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static inline _Bool GetIcmpId(Packet *p, uint16_t *id) { - uint16_t pid; - const DetectIcmpIdData *iid = (const DetectIcmpIdData *)ctx; - if (PKT_IS_PSEUDOPKT(p)) - return 0; + return FALSE; + uint16_t pid; if (PKT_IS_ICMPV4(p)) { switch (ICMPV4_GET_TYPE(p)){ case ICMP_ECHOREPLY: @@ -100,7 +93,7 @@ int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, break; default: SCLogDebug("Packet has no id field"); - return 0; + return FALSE; } } else if (PKT_IS_ICMPV6(p)) { switch (ICMPV6_GET_TYPE(p)) { @@ -114,13 +107,36 @@ int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, break; default: SCLogDebug("Packet has no id field"); - return 0; + return FALSE; } } else { SCLogDebug("Packet not ICMPV4 nor ICMPV6"); - return 0; + return FALSE; } + *id = pid; + return TRUE; +} + +/** + * \brief This function is used to match icmp_id rule option set on a packet + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectIcmpIdData + * + * \retval 0 no match + * \retval 1 match + */ +int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + uint16_t pid; + + if (GetIcmpId(p, &pid) == FALSE) + return 0; + + const DetectIcmpIdData *iid = (const DetectIcmpIdData *)ctx; if (pid == iid->id) return 1; @@ -247,6 +263,60 @@ void DetectIcmpIdFree (void *ptr) SCFree(iid); } +/* prefilter code */ + +static void +PrefilterPacketIcmpIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + uint16_t pid; + if (GetIcmpId(p, &pid) == FALSE) + return; + + if (pid == ctx->v1.u16[0]) + { + SCLogDebug("packet matches ICMP ID %u", ctx->v1.u16[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketIcmpIdSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectIcmpIdData *a = smctx; + v->u16[0] = a->id; +} + +static _Bool +PrefilterPacketIcmpIdCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectIcmpIdData *a = smctx; + if (v.u16[0] == a->id) + return TRUE; + return FALSE; +} + +static int PrefilterSetupIcmpId(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ICMP_ID, + PrefilterPacketIcmpIdSet, + PrefilterPacketIcmpIdCompare, + PrefilterPacketIcmpIdMatch); +} + +static _Bool PrefilterIcmpIdIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ICMP_ID: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h" From 9187c20782884a1ac2f9ccc3ef5462f7b43738e4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 23 Aug 2016 16:47:35 +0200 Subject: [PATCH 1927/2553] detect mpm: negated setup fix --- src/detect-engine-mpm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 619093828544..d3d0c5531c35 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1244,7 +1244,9 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (mpm_store != NULL) { sh->init->app_mpms[a->id] = mpm_store->mpm_ctx; - if (a->PrefilterRegister) { + /* if we have just certain types of negated patterns, + * mpm_ctx can be NULL */ + if (a->PrefilterRegister && mpm_store->mpm_ctx) { BUG_ON(a->PrefilterRegister(sh, mpm_store->mpm_ctx) != 0); } } From e2eb9f8ede2a8b6a5ebd34b8565a4ac5f2c519c3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 12:59:33 +0200 Subject: [PATCH 1928/2553] prefilter: add 'extra match' logic to packet engines Many of the packet engines are very generic. Rules are generally more limited. A rule like 'alert tcp any any -> any 888 (flags:S; sid:1;)' would still be inspected against every SYN packet in most cases (it depends a bit on rule grouping though). This extra match logic adds an additional check to these packet engines. It can add a check based on alproto, source port and dest port. It uses only one of these 3. Priority order is src port > alproto > dst port. For the ports only 'single' ports are used at this time. --- src/detect-engine-prefilter-common.c | 54 +++++++++++++++++++++++----- src/detect-engine-prefilter-common.h | 32 +++++++++++++++++ 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/src/detect-engine-prefilter-common.c b/src/detect-engine-prefilter-common.c index 65c28131f9c6..e1bf0baa5a14 100644 --- a/src/detect-engine-prefilter-common.c +++ b/src/detect-engine-prefilter-common.c @@ -22,13 +22,16 @@ typedef struct PrefilterPacketHeaderHashCtx_ { PrefilterPacketHeaderValue v1; + uint16_t type; /**< PREFILTER_EXTRA_MATCH_* */ + uint16_t value; + uint32_t cnt; } PrefilterPacketHeaderHashCtx; static uint32_t PrefilterPacketHeaderHashFunc(HashListTable *ht, void *data, uint16_t datalen) { PrefilterPacketHeaderCtx *ctx = data; - uint64_t hash = ctx->v1.u64; + uint64_t hash = ctx->v1.u64 + ctx->type + ctx->value; hash %= ht->array_size; return hash; } @@ -38,7 +41,9 @@ static char PrefilterPacketHeaderCompareFunc(void *data1, uint16_t len1, { PrefilterPacketHeaderHashCtx *ctx1 = data1; PrefilterPacketHeaderHashCtx *ctx2 = data2; - return (ctx1->v1.u64 == ctx2->v1.u64); + return (ctx1->v1.u64 == ctx2->v1.u64 && + ctx1->type == ctx2->type && + ctx1->value == ctx2->value); } static void PrefilterPacketHeaderFreeFunc(void *ptr) @@ -67,11 +72,29 @@ static void PrefilterPacketU8HashCtxFree(void *vctx) SCFree(ctx); } +static void GetExtraMatch(const Signature *s, uint16_t *type, uint16_t *value) +{ + if (s->sp != NULL && s->sp->next == NULL && s->sp->port == s->sp->port2 && + !(s->sp->flags & PORT_FLAG_NOT)) + { + *type = PREFILTER_EXTRA_MATCH_SRCPORT; + *value = s->sp->port; + } else if (s->alproto != ALPROTO_UNKNOWN) { + *type = PREFILTER_EXTRA_MATCH_ALPROTO; + *value = s->alproto; + } else if (s->dp != NULL && s->dp->next == NULL && s->dp->port == s->dp->port2 && + !(s->dp->flags & PORT_FLAG_NOT)) + { + *type = PREFILTER_EXTRA_MATCH_DSTPORT; + *value = s->dp->port; + } +} + /** \internal */ static int SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, - PrefilterPacketHeaderValue v, uint32_t count, + PrefilterPacketHeaderHashCtx *hctx, _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) { @@ -83,8 +106,11 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, if (ctx == NULL) return -1; - ctx->v1 = v; - ctx->sigs_cnt = count; + ctx->v1 = hctx->v1; + ctx->type = hctx->type; + ctx->value = hctx->value; + + ctx->sigs_cnt = hctx->cnt; ctx->sigs_array = SCCalloc(ctx->sigs_cnt, sizeof(SigIntId)); if (ctx->sigs_array == NULL) { SCFree(ctx); @@ -98,7 +124,13 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, if (s->prefilter_sm == NULL || s->prefilter_sm->type != sm_type) continue; - if (Compare(v, s->prefilter_sm->ctx)) { + uint16_t type = 0; + uint16_t value = 0; + GetExtraMatch(s, &type, &value); + + if (Compare(ctx->v1, s->prefilter_sm->ctx) && + ctx->type == type && ctx->value == value) + { SCLogDebug("appending sid %u on %u", s->id, sig_offset); ctx->sigs_array[sig_offset] = s->num; sig_offset++; @@ -107,6 +139,9 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, } } + SCLogDebug("%s: ctx %p extra type %u extra value %u, sig cnt %u", + sigmatch_table[sm_type].name, ctx, ctx->type, ctx->value, + ctx->sigs_cnt); PrefilterAppendEngine(sgh, Match, ctx, PrefilterPacketHeaderFree, sigmatch_table[sm_type].name); return 0; @@ -228,8 +263,7 @@ static void SetupSingle(HashListTable *hash_table, PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); SetupEngineForPacketHeader(sgh, sm_type, - ctx->v1, ctx->cnt, - Compare, Match); + ctx, Compare, Match); } } @@ -321,6 +355,8 @@ static int PrefilterSetupPacketHeaderCommon(SigGroupHead *sgh, int sm_type, memset(&ctx, 0, sizeof(ctx)); Set(&ctx.v1, s->prefilter_sm->ctx); + GetExtraMatch(s, &ctx.type, &ctx.value); + PrefilterPacketHeaderHashCtx *rctx = HashListTableLookup(hash_table, (void *)&ctx, 0); if (rctx != 0) { rctx->cnt++; @@ -331,6 +367,8 @@ static int PrefilterSetupPacketHeaderCommon(SigGroupHead *sgh, int sm_type, Set(&actx->v1, s->prefilter_sm->ctx); actx->cnt = 1; + actx->type = ctx.type; + actx->value = ctx.value; int ret = HashListTableAdd(hash_table, actx, 0); if (ret != 0) { diff --git a/src/detect-engine-prefilter-common.h b/src/detect-engine-prefilter-common.h index 6867f90f3234..6072b56c51fa 100644 --- a/src/detect-engine-prefilter-common.h +++ b/src/detect-engine-prefilter-common.h @@ -25,9 +25,17 @@ typedef union { uint64_t u64; } PrefilterPacketHeaderValue; +#define PREFILTER_EXTRA_MATCH_UNUSED 0 +#define PREFILTER_EXTRA_MATCH_ALPROTO 1 +#define PREFILTER_EXTRA_MATCH_SRCPORT 2 +#define PREFILTER_EXTRA_MATCH_DSTPORT 3 + typedef struct PrefilterPacketHeaderCtx_ { PrefilterPacketHeaderValue v1; + uint16_t type; + uint16_t value; + /** rules to add when the flags are present */ uint32_t sigs_cnt; SigIntId *sigs_array; @@ -60,4 +68,28 @@ int PrefilterSetupPacketHeaderU8Hash(SigGroupHead *sgh, int sm_type, void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)); +static inline _Bool +PrefilterPacketHeaderExtraMatch(const PrefilterPacketHeaderCtx *ctx, + const Packet *p) +{ + switch (ctx->type) + { + case PREFILTER_EXTRA_MATCH_UNUSED: + break; + case PREFILTER_EXTRA_MATCH_ALPROTO: + if (p->flow == NULL || p->flow->alproto != ctx->value) + return FALSE; + break; + case PREFILTER_EXTRA_MATCH_SRCPORT: + if (p->sp != ctx->value) + return FALSE; + break; + case PREFILTER_EXTRA_MATCH_DSTPORT: + if (p->dp != ctx->value) + return FALSE; + break; + } + return TRUE; +} + #endif /* __DETECT_ENGINE_PREFILTER_COMMON_H__ */ From ace8f9f5df3ea7ca87d2fdae934dd29ca70c1a2c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 13:04:15 +0200 Subject: [PATCH 1929/2553] detect-flow: prefilter extra match support --- src/detect-flow.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detect-flow.c b/src/detect-flow.c index 78032cd005cd..cec40b78db70 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -351,6 +351,9 @@ PrefilterPacketFlowMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void * { const PrefilterPacketHeaderCtx *ctx = pectx; + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + if (FlowMatch(p->flowflags, det_ctx->flags, ctx->v1.u8[0], ctx->v1.u8[1])) { PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); From 34e3484dad3af5be0ad916fa9130fc93b430b056 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 13:04:25 +0200 Subject: [PATCH 1930/2553] detect-flags: prefilter extra match support --- src/detect-flags.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/detect-flags.c b/src/detect-flags.c index b1524671c3fc..28e01d1bfa22 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -560,8 +560,10 @@ PrefilterPacketFlagsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void } const PrefilterPacketHeaderCtx *ctx = pectx; - const uint8_t flags = p->tcph->th_flags; + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + const uint8_t flags = p->tcph->th_flags; if (FlagsMatch(flags, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) { SCLogDebug("packet matches TCP flags %02x", ctx->v1.u8[1]); From fbb0490c31fc62b60240e3fde4a1462555105f9b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 15:12:39 +0200 Subject: [PATCH 1931/2553] detect-dsize: extra match support --- src/detect-dsize.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 0368c8364bac..6eb7d1b5aa6f 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -322,8 +322,10 @@ PrefilterPacketDsizeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void } const PrefilterPacketHeaderCtx *ctx = pectx; - const uint16_t dsize = p->payload_len; + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + const uint16_t dsize = p->payload_len; if (DsizeMatch(dsize, ctx->v1.u8[0], ctx->v1.u16[1], ctx->v1.u16[2])) { SCLogDebug("packet matches dsize %u", dsize); From a270dfa008f2d5c19f8c571fd4a4139ffc3df7ad Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 15:12:51 +0200 Subject: [PATCH 1932/2553] detect-id: extra match support --- src/detect-id.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detect-id.c b/src/detect-id.c index 5034d34db687..5a1b18ec5c7c 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -247,6 +247,9 @@ PrefilterPacketIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pe return; } + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + if (IPV4_GET_IPID(p) == ctx->v1.u16[0]) { SCLogDebug("packet matches IP id %u", ctx->v1.u16[0]); From a1accbbaf0465eabcd5743f9d20c631a79f8c09d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 15:12:59 +0200 Subject: [PATCH 1933/2553] detect-ttl: extra match support --- src/detect-ttl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detect-ttl.c b/src/detect-ttl.c index 97e9055af4ca..96ae1273342a 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -325,6 +325,8 @@ PrefilterPacketTtlMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *p } const PrefilterPacketHeaderCtx *ctx = pectx; + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; if (TtlMatch(pttl, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) { From a41bf2ae142428a6badfcbf3f6ded32706e2c82c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 15:13:16 +0200 Subject: [PATCH 1934/2553] detect-seq: extra match support --- src/detect-seq.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detect-seq.c b/src/detect-seq.c index 7df03ba941bf..60bd2ad2ced4 100644 --- a/src/detect-seq.c +++ b/src/detect-seq.c @@ -151,6 +151,9 @@ PrefilterPacketSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *p { const PrefilterPacketHeaderCtx *ctx = pectx; + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) && (p->tcph != NULL) && (TCP_GET_SEQ(p) == ctx->v1.u32[0])) { From e3b98d5bbf6f8677c0adf345cfe063c7f5ea6c98 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 15:13:25 +0200 Subject: [PATCH 1935/2553] detect-ack: extra match support --- src/detect-ack.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detect-ack.c b/src/detect-ack.c index 75d3427eea33..0ea0dc285ac1 100644 --- a/src/detect-ack.c +++ b/src/detect-ack.c @@ -156,6 +156,9 @@ PrefilterPacketAckMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *p { const PrefilterPacketHeaderCtx *ctx = pectx; + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) && (p->tcph != NULL) && (TCP_GET_ACK(p) == ctx->v1.u32[0])) { From 9bb12ccb270fdb54cd76ed4db1e794aa2812a161 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 17:55:33 +0200 Subject: [PATCH 1936/2553] prefilter: move payload engines into separate list --- src/detect-engine-payload.c | 4 +-- src/detect-engine-prefilter.c | 56 ++++++++++++++++++++++++++++++++--- src/detect-engine-prefilter.h | 4 +++ src/detect-engine-siggroup.c | 3 +- src/detect.c | 6 +++- src/detect.h | 3 +- 6 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index 4ce0be416f78..a16e8a0e3e6d 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -83,7 +83,7 @@ static void PrefilterPktStream(DetectEngineThreadCtx *det_ctx, int PrefilterPktStreamRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { - return PrefilterAppendEngine(sgh, PrefilterPktStream, mpm_ctx, NULL, "stream"); + return PrefilterAppendPayloadEngine(sgh, PrefilterPktStream, mpm_ctx, NULL, "stream"); } static void PrefilterPktPayload(DetectEngineThreadCtx *det_ctx, @@ -112,7 +112,7 @@ static void PrefilterPktPayload(DetectEngineThreadCtx *det_ctx, int PrefilterPktPayloadRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { - return PrefilterAppendEngine(sgh, PrefilterPktPayload, mpm_ctx, NULL, "payload"); + return PrefilterAppendPayloadEngine(sgh, PrefilterPktPayload, mpm_ctx, NULL, "payload"); } diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index e0a39d1f021e..b7dac35bd0d7 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -116,7 +116,7 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, PROFILING_PREFILTER_RESET(p, det_ctx->de_ctx->profile_prefilter_maxid); /* run packet engines */ - PrefilterEngine *engine = sgh->engines; + PrefilterEngine *engine = sgh->pkt_engines; while (engine) { PROFILING_PREFILTER_START(p); engine->Prefilter(det_ctx, p, engine->pectx); @@ -125,6 +125,18 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, engine = engine->next; } + /* run payload inspecting engines */ + if ((p->payload_len > 0 || det_ctx->smsg != NULL) && !(p->flags & PKT_NOPAYLOAD_INSPECTION)) { + engine = sgh->payload_engines; + while (engine) { + PROFILING_PREFILTER_START(p); + engine->Prefilter(det_ctx, p, engine->pectx); + PROFILING_PREFILTER_END(p, engine->profile_id); + + engine = engine->next; + } + } + /* run tx engines */ if (((p->proto == IPPROTO_TCP && p->flowflags & FLOW_PKT_ESTABLISHED) || p->proto != IPPROTO_TCP) && has_state) { if (sgh->tx_engines != NULL && p->flow != NULL && @@ -151,10 +163,46 @@ int PrefilterAppendEngine(SigGroupHead *sgh, e->pectx = pectx; e->Free = FreeFunc; - if (sgh->engines == NULL) { - sgh->engines = e; + if (sgh->pkt_engines == NULL) { + sgh->pkt_engines = e; + } else { + PrefilterEngine *t = sgh->pkt_engines; + while (t->next != NULL) { + t = t->next; + } + + t->next = e; + e->id = t->id + 1; + } + +#ifdef PROFILING + sgh->engines_cnt = e->id; + e->name = name; + e->profile_id = PrefilterStoreGetId(e->name); +#endif + return 0; +} + +int PrefilterAppendPayloadEngine(SigGroupHead *sgh, + void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), + void *pectx, void (*FreeFunc)(void *pectx), + const char *name) +{ + if (sgh == NULL || Prefilter == NULL || pectx == NULL) + return -1; + + PrefilterEngine *e = SCCalloc(1, sizeof(*e)); + if (e == NULL) + return -1; + + e->Prefilter = Prefilter; + e->pectx = pectx; + e->Free = FreeFunc; + + if (sgh->payload_engines == NULL) { + sgh->payload_engines = e; } else { - PrefilterEngine *t = sgh->engines; + PrefilterEngine *t = sgh->payload_engines; while (t->next != NULL) { t = t->next; } diff --git a/src/detect-engine-prefilter.h b/src/detect-engine-prefilter.h index d98bee7b5970..5ce32fea0a5a 100644 --- a/src/detect-engine-prefilter.h +++ b/src/detect-engine-prefilter.h @@ -31,6 +31,10 @@ int PrefilterAppendEngine(SigGroupHead *sgh, void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), void *pectx, void (*FreeFunc)(void *pectx), const char *name); +int PrefilterAppendPayloadEngine(SigGroupHead *sgh, + void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), + void *pectx, void (*FreeFunc)(void *pectx), + const char *name); int PrefilterAppendTxEngine(SigGroupHead *sgh, void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f, void *tx, diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 60bf5abecb38..aab2fd46165b 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -172,7 +172,8 @@ void SigGroupHeadFree(SigGroupHead *sgh) } PrefilterFreeEngines(sgh->tx_engines); - PrefilterFreeEngines(sgh->engines); + PrefilterFreeEngines(sgh->pkt_engines); + PrefilterFreeEngines(sgh->payload_engines); SCFree(sgh); diff --git a/src/detect.c b/src/detect.c index cbc1d56bcf14..497f9026dbc8 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3825,7 +3825,11 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) uint32_t engines = 0; uint32_t tx_engines = 0; - for (e = sgh->engines ; e != NULL; e = e->next) { + for (e = sgh->pkt_engines ; e != NULL; e = e->next) { + engines++; + de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + } + for (e = sgh->payload_engines ; e != NULL; e = e->next) { engines++; de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); } diff --git a/src/detect.h b/src/detect.h index 6bfb75df015c..9b70c7c7b785 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1027,7 +1027,8 @@ typedef struct SigGroupHead_ { uint32_t id; /**< unique id used to index sgh_array for stats */ - PrefilterEngine *engines; + PrefilterEngine *pkt_engines; + PrefilterEngine *payload_engines; PrefilterEngine *tx_engines; #ifdef PROFILING From 732921922a7eed53bc929c4ecf022ad9861fd9ed Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 26 Aug 2016 10:14:06 +0200 Subject: [PATCH 1937/2553] detect mpm: consider sgh direction when adding rules --- src/detect-engine-mpm.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index d3d0c5531c35..ab53f653ef27 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1157,6 +1157,7 @@ MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, App return NULL; MpmStore lookup = { sids_array, max_sid, am->direction, MPMB_MAX, am->sm_list, 0, NULL}; + SCLogDebug("am->direction %d am->sm_list %d", am->direction, am->sm_list); MpmStore *result = MpmStoreLookup(de_ctx, &lookup); if (result == NULL) { @@ -1184,6 +1185,7 @@ MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, App MpmStoreAdd(de_ctx, copy); return copy; } else { + SCLogDebug("using existing mpm %p", result); return result; } return NULL; @@ -1240,14 +1242,18 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) AppLayerMpms *a = app_mpms; while (a->name != NULL) { - mpm_store = MpmStorePrepareBuffer2(de_ctx, sh, a); - if (mpm_store != NULL) { - sh->init->app_mpms[a->id] = mpm_store->mpm_ctx; + if ((a->direction == SIG_FLAG_TOSERVER && SGH_DIRECTION_TS(sh)) || + (a->direction == SIG_FLAG_TOCLIENT && SGH_DIRECTION_TC(sh))) + { + mpm_store = MpmStorePrepareBuffer2(de_ctx, sh, a); + if (mpm_store != NULL) { + sh->init->app_mpms[a->id] = mpm_store->mpm_ctx; - /* if we have just certain types of negated patterns, - * mpm_ctx can be NULL */ - if (a->PrefilterRegister && mpm_store->mpm_ctx) { - BUG_ON(a->PrefilterRegister(sh, mpm_store->mpm_ctx) != 0); + /* if we have just certain types of negated patterns, + * mpm_ctx can be NULL */ + if (a->PrefilterRegister && mpm_store->mpm_ctx) { + BUG_ON(a->PrefilterRegister(sh, mpm_store->mpm_ctx) != 0); + } } } a++; From 2e878c202468ea7866de136048191d4d82771589 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 26 Aug 2016 12:45:47 +0200 Subject: [PATCH 1938/2553] prefilter: alloc CLS aligned memory --- src/detect-engine-prefilter.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index b7dac35bd0d7..bd62a91bf91b 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -155,9 +155,10 @@ int PrefilterAppendEngine(SigGroupHead *sgh, if (sgh == NULL || Prefilter == NULL || pectx == NULL) return -1; - PrefilterEngine *e = SCCalloc(1, sizeof(*e)); + PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); if (e == NULL) return -1; + memset(e, 0x00, sizeof(*e)); e->Prefilter = Prefilter; e->pectx = pectx; @@ -191,9 +192,10 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh, if (sgh == NULL || Prefilter == NULL || pectx == NULL) return -1; - PrefilterEngine *e = SCCalloc(1, sizeof(*e)); + PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); if (e == NULL) return -1; + memset(e, 0x00, sizeof(*e)); e->Prefilter = Prefilter; e->pectx = pectx; @@ -230,9 +232,10 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, if (sgh == NULL || PrefilterTx == NULL || pectx == NULL) return -1; - PrefilterEngine *e = SCCalloc(1, sizeof(*e)); + PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); if (e == NULL) return -1; + memset(e, 0x00, sizeof(*e)); e->PrefilterTx = PrefilterTx; e->pectx = pectx; @@ -264,7 +267,7 @@ static void PrefilterFreeEngine(PrefilterEngine *e) if (e->Free) { e->Free(e->pectx); } - SCFree(e); + SCFreeAligned(e); } void PrefilterFreeEngines(PrefilterEngine *list) From 36f713c8d4accc90aab5039f78a3929687fb9dab Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 26 Aug 2016 14:24:16 +0200 Subject: [PATCH 1939/2553] prefilter: in profiling print totals --- src/util-profiling.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/util-profiling.c b/src/util-profiling.c index 76812a0325e5..d4130eb58fec 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -327,6 +327,9 @@ static void DumpPrefilterIP(FILE *fp, int ipv, uint64_t total) { char totalstr[256]; + SCProfilePacketData total_pd; + memset(&total_pd, 0, sizeof(total_pd)); + int i; for (i = 0; i < 256; i++) { const char *name = PrefilterStoreGetName(i); @@ -337,6 +340,9 @@ static void DumpPrefilterIP(FILE *fp, int ipv, uint64_t total) continue; } + total_pd.cnt += pd->cnt; + total_pd.tot += pd->tot; + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); double percent = (long double)pd->tot / (long double)total * 100; @@ -346,6 +352,11 @@ static void DumpPrefilterIP(FILE *fp, int ipv, uint64_t total) pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); } } + if (total_pd.cnt) { + FormatNumber(total_pd.tot, totalstr, sizeof(totalstr)); + fprintf(fp, "%-30s IPv%d %12"PRIu64" %12"PRIu64" %11s\n", + "Total", ipv, total_pd.cnt, (uint64_t)(total_pd.tot / total_pd.cnt), totalstr); + } } static void DumpPrefilter(FILE *fp) From 125603871bf80149d593099741c8b695e316acb7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 26 Aug 2016 16:10:59 +0200 Subject: [PATCH 1940/2553] detect: config opt to enable keyword prefilters --- src/detect-engine.c | 18 ++++++++++++++++++ src/detect.c | 17 +++++++++++------ src/detect.h | 8 ++++++++ suricata.yaml.in | 6 ++++++ 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index f734abb975ea..6171e5e1fcc1 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1335,6 +1335,24 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) } } + de_ctx->prefilter_setting = DETECT_PREFILTER_MPM; + char *pf_setting = NULL; + if (ConfGet("detect.prefilter.default", &pf_setting) == 1 && pf_setting) { + if (strcasecmp(pf_setting, "mpm") == 0) { + de_ctx->prefilter_setting = DETECT_PREFILTER_MPM; + } else if (strcasecmp(pf_setting, "auto") == 0) { + de_ctx->prefilter_setting = DETECT_PREFILTER_AUTO; + } + } + switch (de_ctx->prefilter_setting) { + case DETECT_PREFILTER_MPM: + SCLogConfig("prefilter engines: MPM"); + break; + case DETECT_PREFILTER_AUTO: + SCLogConfig("prefilter engines: MPM and keywords"); + break; + } + return 0; error: return -1; diff --git a/src/detect.c b/src/detect.c index 497f9026dbc8..a6a88bb68830 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3384,7 +3384,10 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) RuleSetWhitelist(tmp_s); - if (!(tmp_s->flags & SIG_FLAG_PREFILTER)) { + /* if keyword engines are enabled in the config, handle them here */ + if (de_ctx->prefilter_setting == DETECT_PREFILTER_AUTO && + !(tmp_s->flags & SIG_FLAG_PREFILTER)) + { int i; int prefilter_list = DETECT_TBLSIZE; @@ -3812,11 +3815,13 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); - int i = 0; - for (i = 0; i < DETECT_TBLSIZE; i++) - { - if (sigmatch_table[i].SetupPrefilter != NULL) { - sigmatch_table[i].SetupPrefilter(sgh); + if (de_ctx->prefilter_setting == DETECT_PREFILTER_AUTO) { + int i = 0; + for (i = 0; i < DETECT_TBLSIZE; i++) + { + if (sigmatch_table[i].SetupPrefilter != NULL) { + sigmatch_table[i].SetupPrefilter(sgh); + } } } diff --git a/src/detect.h b/src/detect.h index 9b70c7c7b785..a725e056cd58 100644 --- a/src/detect.h +++ b/src/detect.h @@ -550,6 +550,12 @@ typedef struct DetectEngineThreadKeywordCtxItem_ { 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 */ +}; + /** \brief main detection engine ctx */ typedef struct DetectEngineCtx_ { uint8_t flags; @@ -687,6 +693,8 @@ typedef struct DetectEngineCtx_ { /** id of loader thread 'owning' this de_ctx */ int loader_id; + /** are we useing just mpm or also other prefilters */ + enum DetectEnginePrefilterSetting prefilter_setting; HashListTable *dport_hash_table; diff --git a/suricata.yaml.in b/suricata.yaml.in index 69dfbdaec84c..a0a78eeb0843 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1245,6 +1245,12 @@ detect: # is started. This will limit the downtime in IPS mode. #delayed-detect: yes + prefilter: + # default prefiltering setting. "mpm" only creates MPM/fast_pattern + # engines. "auto" also sets up prefilter engines for other keywords. + # Use --list-keywords=all to see which keywords support prefiltering. + default: mpm + # the grouping values above control how many groups are created per # direction. Port whitelisting forces that port to get it's own group. # Very common ports will benefit, as well as ports with many expensive From dba14b676cee6fe104fc7085409277b29774eb5a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 18:36:26 +0200 Subject: [PATCH 1941/2553] profiling: more prefilter profiling --- src/detect-engine-prefilter.c | 6 ++++++ src/detect.c | 4 ++++ src/suricata-common.h | 5 +++++ src/util-profiling.c | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index bd62a91bf91b..c72ee6eef929 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -115,6 +115,7 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, PROFILING_PREFILTER_RESET(p, det_ctx->de_ctx->profile_prefilter_maxid); + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PKT); /* run packet engines */ PrefilterEngine *engine = sgh->pkt_engines; while (engine) { @@ -124,9 +125,11 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, engine = engine->next; } + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PKT); /* run payload inspecting engines */ if ((p->payload_len > 0 || det_ctx->smsg != NULL) && !(p->flags & PKT_NOPAYLOAD_INSPECTION)) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PAYLOAD); engine = sgh->payload_engines; while (engine) { PROFILING_PREFILTER_START(p); @@ -135,6 +138,7 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, engine = engine->next; } + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PAYLOAD); } /* run tx engines */ @@ -142,7 +146,9 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, if (sgh->tx_engines != NULL && p->flow != NULL && p->flow->alproto != ALPROTO_UNKNOWN && p->flow->alstate != NULL) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_TX); PrefilterTx(det_ctx, sgh, p, flags); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_TX); } } } diff --git a/src/detect.c b/src/detect.c index a6a88bb68830..b3e7c19e772e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1200,9 +1200,13 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* Sort the rule list to lets look at pmq. * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ if (det_ctx->pmq.rule_id_array_cnt > 1) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_SORT1); QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_SORT1); } + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_SORT2); DetectPrefilterMergeSort(de_ctx, det_ctx); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_SORT2); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PREFILTER); #ifdef PROFILING diff --git a/src/suricata-common.h b/src/suricata-common.h index ffbeafb65b20..1c097d2314e5 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -314,6 +314,11 @@ typedef enum PacketProfileDetectId_ { PROF_DETECT_RULES, PROF_DETECT_STATEFUL, PROF_DETECT_PREFILTER, + PROF_DETECT_PF_PKT, + PROF_DETECT_PF_PAYLOAD, + PROF_DETECT_PF_TX, + PROF_DETECT_PF_SORT1, + PROF_DETECT_PF_SORT2, PROF_DETECT_NONMPMLIST, PROF_DETECT_ALERT, PROF_DETECT_CLEANUP, diff --git a/src/util-profiling.c b/src/util-profiling.c index d4130eb58fec..a49d80aeaf73 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1312,6 +1312,11 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id) CASE_CODE (PROF_DETECT_IPONLY); CASE_CODE (PROF_DETECT_RULES); CASE_CODE (PROF_DETECT_PREFILTER); + CASE_CODE (PROF_DETECT_PF_PKT); + CASE_CODE (PROF_DETECT_PF_PAYLOAD); + CASE_CODE (PROF_DETECT_PF_TX); + CASE_CODE (PROF_DETECT_PF_SORT1); + CASE_CODE (PROF_DETECT_PF_SORT2); CASE_CODE (PROF_DETECT_STATEFUL); CASE_CODE (PROF_DETECT_ALERT); CASE_CODE (PROF_DETECT_CLEANUP); From e1eb4816478ed27f05082c371136ec9035d95364 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 26 Aug 2016 18:49:17 +0200 Subject: [PATCH 1942/2553] prefilter: cleanup and optimization --- src/detect-engine-prefilter.c | 58 ++++++++++++++++++++++++++++------- src/detect.c | 32 ------------------- 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index c72ee6eef929..a7cc85f8db26 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -58,6 +58,30 @@ static int PrefilterStoreGetId(const char *name); #endif +static inline void QuickSortSigIntId(SigIntId *sids, uint32_t n) +{ + if (n < 2) + return; + SigIntId p = sids[n / 2]; + SigIntId *l = sids; + SigIntId *r = sids + n - 1; + while (l <= r) { + if (*l < p) + l++; + else if (*r > p) + r--; + else { + SigIntId t = *l; + *l = *r; + *r = t; + l++; + r--; + } + } + QuickSortSigIntId(sids, r - sids + 1); + QuickSortSigIntId(l, sids + n - l); +} + static inline void PrefilterTx(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, const uint8_t flags) { @@ -115,22 +139,26 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, PROFILING_PREFILTER_RESET(p, det_ctx->de_ctx->profile_prefilter_maxid); - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PKT); - /* run packet engines */ - PrefilterEngine *engine = sgh->pkt_engines; - while (engine) { - PROFILING_PREFILTER_START(p); - engine->Prefilter(det_ctx, p, engine->pectx); - PROFILING_PREFILTER_END(p, engine->profile_id); + if (sgh->pkt_engines) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PKT); + /* run packet engines */ + PrefilterEngine *engine = sgh->pkt_engines; + do { + PROFILING_PREFILTER_START(p); + engine->Prefilter(det_ctx, p, engine->pectx); + PROFILING_PREFILTER_END(p, engine->profile_id); - engine = engine->next; + engine = engine->next; + } while (engine != NULL); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PKT); } - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PKT); /* run payload inspecting engines */ - if ((p->payload_len > 0 || det_ctx->smsg != NULL) && !(p->flags & PKT_NOPAYLOAD_INSPECTION)) { + if (sgh->payload_engines && + (p->payload_len > 0 || det_ctx->smsg != NULL) && + !(p->flags & PKT_NOPAYLOAD_INSPECTION)) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PAYLOAD); - engine = sgh->payload_engines; + PrefilterEngine *engine = sgh->payload_engines; while (engine) { PROFILING_PREFILTER_START(p); engine->Prefilter(det_ctx, p, engine->pectx); @@ -151,6 +179,14 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_TX); } } + + /* Sort the rule list to lets look at pmq. + * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ + if (likely(det_ctx->pmq.rule_id_array_cnt > 1)) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_SORT1); + QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_SORT1); + } } int PrefilterAppendEngine(SigGroupHead *sgh, diff --git a/src/detect.c b/src/detect.c index b3e7c19e772e..99860efd82cb 100644 --- a/src/detect.c +++ b/src/detect.c @@ -825,31 +825,6 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, BUG_ON((det_ctx->pmq.rule_id_array_cnt + det_ctx->non_pf_id_cnt) < det_ctx->match_array_cnt); } -/* Return true is the list is sorted smallest to largest */ -static void QuickSortSigIntId(SigIntId *sids, uint32_t n) -{ - if (n < 2) - return; - SigIntId p = sids[n / 2]; - SigIntId *l = sids; - SigIntId *r = sids + n - 1; - while (l <= r) { - if (*l < p) - l++; - else if (*r > p) - r--; - else { - SigIntId t = *l; - *l = *r; - *r = t; - l++; - r--; - } - } - QuickSortSigIntId(sids, r - sids + 1); - QuickSortSigIntId(l, sids + n - l); -} - #define SMS_USE_FLOW_SGH 0x01 #define SMS_USED_PM 0x02 @@ -1197,13 +1172,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PREFILTER); /* run the prefilter engines */ Prefilter(det_ctx, det_ctx->sgh, p, flow_flags, has_state); - /* Sort the rule list to lets look at pmq. - * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ - if (det_ctx->pmq.rule_id_array_cnt > 1) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_SORT1); - QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_SORT1); - } PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_SORT2); DetectPrefilterMergeSort(de_ctx, det_ctx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_SORT2); From ae5846b4deed24cd3150d87465f088503ead29b7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 14 Sep 2016 23:12:08 +0200 Subject: [PATCH 1943/2553] detect: simplify content inspection types Instead of a type per buffer type, pass just 3 possible types: packet, stream, state. The individual types weren't used. State is just there to be not packet and not stream. --- src/detect-base64-data.c | 2 +- src/detect-engine-content-inspection.h | 30 +++----------------------- src/detect-engine-dcepayload.c | 4 ++-- src/detect-engine-dns.c | 2 +- src/detect-engine-filedata-smtp.c | 2 +- src/detect-engine-hcbd.c | 2 +- src/detect-engine-hcd.c | 2 +- src/detect-engine-hhd.c | 2 +- src/detect-engine-hhhd.c | 2 +- src/detect-engine-hmd.c | 2 +- src/detect-engine-hrhd.c | 2 +- src/detect-engine-hrhhd.c | 2 +- src/detect-engine-hrl.c | 2 +- src/detect-engine-hrud.c | 2 +- src/detect-engine-hsbd.c | 2 +- src/detect-engine-hscd.c | 2 +- src/detect-engine-hsmd.c | 2 +- src/detect-engine-hua.c | 2 +- src/detect-engine-template.c | 4 ++-- src/detect-engine-tls.c | 6 +++--- src/detect-engine-uri.c | 2 +- 21 files changed, 27 insertions(+), 51 deletions(-) diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c index eeea153d2946..107b90ca42fe 100644 --- a/src/detect-base64-data.c +++ b/src/detect-base64-data.c @@ -77,7 +77,7 @@ int DetectBase64DataDoMatch(DetectEngineCtx *de_ctx, return DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_BASE64_DATA], f, det_ctx->base64_decoded, det_ctx->base64_decoded_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_BASE64, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } return 0; diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 3fc4b451e9f3..91b62d6c6b89 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -24,37 +24,13 @@ #ifndef __DETECT_ENGINE_CONTENT_INSPECTION_H__ #define __DETECT_ENGINE_CONTENT_INSPECTION_H__ -/** \warning make sure to add new entries to the proper position - * wrt flow lock status +/** indication to content engine what type of data + * we're inspecting */ enum { - /* called with flow unlocked */ DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD = 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM, - - /* called with flow locked */ - DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_URI, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRL, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRUD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCBD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSBD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HMD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSCD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSMD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HUAD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSNI, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSISSUER, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSUBJECT, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_BASE64, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, }; int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index 44fc98d94209..5cdb10d35f2c 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -90,7 +90,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, dce_stub_data, dce_stub_data_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, dcerpc_state); + 0, dcerpc_state); //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, //dce_stub_data, dce_stub_data_len, dcerpc_state); if (r == 1) { @@ -113,7 +113,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, dce_stub_data, dce_stub_data_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, dcerpc_state); + 0, dcerpc_state); //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, //dce_stub_data, dce_stub_data_len, dcerpc_state); if (r == 1) { diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index d7a135e3a709..0dac77734fbd 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -88,7 +88,7 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH], f, buffer, buffer_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) break; } diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 5d0d3aec1589..e0fa467e9ea4 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -208,7 +208,7 @@ int DetectEngineInspectSMTPFiledata(ThreadVars *tv, (uint8_t *)buffer, buffer_len, stream_start_offset, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (match == 1) r = 1; } diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 8c8ac0645ea8..62d12517cb44 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -282,7 +282,7 @@ int DetectEngineInspectHttpClientBody(ThreadVars *tv, (uint8_t *)buffer, buffer_len, stream_start_offset, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCBD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index b43bf5096d75..63ed33fe9391 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -198,7 +198,7 @@ int DetectEngineInspectHttpCookie(ThreadVars *tv, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index fe48fdbaac2b..7a3af7e12ecb 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -338,7 +338,7 @@ int DetectEngineInspectHttpHeader(ThreadVars *tv, buffer, buffer_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 4824db7a41c4..b761a1fe6c43 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -136,7 +136,7 @@ int DetectEngineInspectHttpHH(ThreadVars *tv, f, hname, hname_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index fbf92e7b8d92..23b964cf984e 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -134,7 +134,7 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HMD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; else diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 7f0a56a82808..3181d45bf313 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -202,7 +202,7 @@ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, headers_raw, headers_raw_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index 2f4edfbcf71b..02db16fe1a6f 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -159,7 +159,7 @@ int DetectEngineInspectHttpHRH(ThreadVars *tv, f, hname, hname_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hrl.c b/src/detect-engine-hrl.c index 30dd06441f6b..244f64436b7c 100644 --- a/src/detect-engine-hrl.c +++ b/src/detect-engine-hrl.c @@ -94,7 +94,7 @@ int DetectEngineInspectHttpRequestLine(ThreadVars *tv, bstr_ptr(tx->request_line), bstr_len(tx->request_line), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRL, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) { return DETECT_ENGINE_INSPECT_SIG_MATCH; } else { diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index e0a0d50805fd..4957f3292fee 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -136,7 +136,7 @@ int DetectEngineInspectHttpRawUri(ThreadVars *tv, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRUD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; else diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 8f9495453568..84856fc51bf9 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -288,7 +288,7 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv, (uint8_t *)buffer, buffer_len, stream_start_offset, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSBD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 929f788ff5f7..e8e94822d02f 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -134,7 +134,7 @@ int DetectEngineInspectHttpStatCode(ThreadVars *tv, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSCD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; else diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index c707ab381a63..68811eea7ba9 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -134,7 +134,7 @@ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, (uint8_t *)bstr_ptr(tx->response_message), bstr_len(tx->response_message), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSMD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; else diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index b057db38ae0e..66c8859cb2e9 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -142,7 +142,7 @@ int DetectEngineInspectHttpUA(ThreadVars *tv, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HUAD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-template.c b/src/detect-engine-template.c index 1d70d11fedd5..70785da1e340 100644 --- a/src/detect-engine-template.c +++ b/src/detect-engine-template.c @@ -47,13 +47,13 @@ int DetectEngineInspectTemplateBuffer(ThreadVars *tv, DetectEngineCtx *de_ctx, ret = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH], f, tx->request_buffer, tx->request_buffer_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { ret = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH], f, tx->response_buffer, tx->response_buffer_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } SCLogNotice("Returning %d.", ret); diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 6e6f025a7e12..6adac0f8b8f3 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -117,7 +117,7 @@ int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_TLSSNI_MATCH], f, buffer, buffer_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSNI, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); return cnt; } @@ -193,7 +193,7 @@ int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_TLSISSUER_MATCH], f, buffer, buffer_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSISSUER, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); return cnt; } @@ -269,7 +269,7 @@ int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_TLSSUBJECT_MATCH], f, buffer, buffer_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_TLSSUBJECT, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); return cnt; } diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index 7b6ad2ab1b72..caf5c10ecddb 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -136,7 +136,7 @@ int DetectEngineInspectPacketUris(ThreadVars *tv, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_URI, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) { return DETECT_ENGINE_INSPECT_SIG_MATCH; } else { From 5b2e36a1b00e9ef0144551c4318cbed5c957d42c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Sep 2016 18:52:59 +0200 Subject: [PATCH 1944/2553] mpm: add App Layer MPM registery Register keywords globally at start up. Create a map of the registery per detection engine. This we need because the sgh_mpm_context value is set per detect engine. Remove APP_MPMS_MAX. --- src/detect-engine-mpm.c | 209 ++++++++++++++++++++++++----------- src/detect-engine-mpm.h | 14 +++ src/detect-engine-siggroup.c | 3 + src/detect-engine.c | 2 + src/detect.c | 2 + src/detect.h | 27 ++++- src/suricata.c | 2 + 7 files changed, 190 insertions(+), 69 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index ab53f653ef27..24bc4fb2dd1f 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -86,78 +86,129 @@ const char *builtin_mpms[] = { typedef struct AppLayerMpms_ { const char *name; - int32_t sgh_mpm_context; /**< mpm factory id */ + int unused; int direction; /**< SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT */ int sm_list; int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx); - int id; /**< index into this array and result arrays */ + int id; + } AppLayerMpms; AppLayerMpms app_mpms[] = { { "http_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_UMATCH, PrefilterTxUriRegister, 0 }, { "http_raw_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRUDMATCH, - PrefilterTxRawUriRegister, 1 }, + PrefilterTxRawUriRegister, 0 }, { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, - PrefilterTxHttpRequestHeadersRegister, 2}, + PrefilterTxHttpRequestHeadersRegister, 0}, { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, - PrefilterTxHttpRequestHeadersRegister, 3}, + PrefilterTxHttpRequestHeadersRegister, 0}, { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, - PrefilterTxUARegister, 4}, + PrefilterTxUARegister, 0}, { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, - PrefilterTxRequestHeadersRawRegister, 5}, + PrefilterTxRequestHeadersRawRegister, 0}, { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, - PrefilterTxResponseHeadersRawRegister, 6}, + PrefilterTxResponseHeadersRawRegister, 0}, { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, - PrefilterTxMethodRegister, 7}, + PrefilterTxMethodRegister, 0}, { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, - PrefilterTxSmtpFiledataRegister, 8}, /* smtp */ + PrefilterTxSmtpFiledataRegister, 0}, /* smtp */ { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, - PrefilterTxHttpResponseBodyRegister, 9}, /* http server body */ + PrefilterTxHttpResponseBodyRegister, 0}, /* http server body */ { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, - PrefilterTxHttpStatMsgRegister, 10}, + PrefilterTxHttpStatMsgRegister, 0}, { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, - PrefilterTxHttpStatCodeRegister, 11}, + PrefilterTxHttpStatCodeRegister, 0}, { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, - PrefilterTxHttpRequestBodyRegister, 12}, + PrefilterTxHttpRequestBodyRegister, 0}, { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, - PrefilterTxHostnameRegister, 13}, + PrefilterTxHostnameRegister, 0}, { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, - PrefilterTxHostnameRawRegister, 14}, + PrefilterTxHostnameRawRegister, 0}, { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, - PrefilterTxRequestCookieRegister, 15}, + PrefilterTxRequestCookieRegister, 0}, { "http_cookie", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HCDMATCH, - PrefilterTxResponseCookieRegister, 16}, + PrefilterTxResponseCookieRegister, 0}, { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, - PrefilterTxDnsQueryRegister, 17}, + PrefilterTxDnsQueryRegister, 0}, { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, - PrefilterTxTlsSniRegister, 18}, + PrefilterTxTlsSniRegister, 0}, { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, - PrefilterTxTlsIssuerRegister, 19}, + PrefilterTxTlsIssuerRegister, 0}, { "tls_cert_subject", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSSUBJECT_MATCH, - PrefilterTxTlsSubjectRegister, 20}, + PrefilterTxTlsSubjectRegister, 0}, { NULL, 0, 0, 0, NULL, 0, } }; +/* Registery for mpm keywords + * + * Keywords are registered at engine start up + */ + +static DetectMpmAppLayerRegistery *g_app_mpms_list = NULL; +static int g_app_mpms_list_cnt = 0; + +void DetectMpmAppLayerRegister(const char *name, int direction, int sm_list, + int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)) +{ + DetectMpmAppLayerRegistery *am = SCCalloc(1, sizeof(*am)); + BUG_ON(am == NULL); + am->name = name; + am->direction = direction; + am->sm_list = sm_list; + am->PrefilterRegister = PrefilterRegister; + + if (g_app_mpms_list == NULL) { + g_app_mpms_list = am; + } else { + DetectMpmAppLayerRegistery *t = g_app_mpms_list; + while (t->next != NULL) { + t = t->next; + } + + t->next = am; + am->id = t->id + 1; + } + g_app_mpms_list_cnt++; +} + +/* temporary table for turning the table app_mpms into the registery + * TODO to be removed */ +void RegisterAppMpmTable(void) +{ + AppLayerMpms *am = app_mpms; + while (am->name != NULL) { + DetectMpmAppLayerRegister(am->name, am->direction, + am->sm_list, am->PrefilterRegister); + am++; + } +} + void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) { - int i; - for (i = 0; i < APP_MPMS_MAX; i++) { - AppLayerMpms *am = &app_mpms[i]; + BUG_ON(g_app_mpms_list_cnt == 0); + + de_ctx->app_mpms = SCCalloc(g_app_mpms_list_cnt + 1, sizeof(DetectMpmAppLayerKeyword)); + BUG_ON(de_ctx->app_mpms == NULL); + + DetectMpmAppLayerRegistery *list = g_app_mpms_list; + while (list != NULL) { + DetectMpmAppLayerKeyword *am = &de_ctx->app_mpms[list->id]; + am->reg = list; /* default to whatever the global setting is */ int shared = (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE); @@ -165,24 +216,26 @@ void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) /* see if we use a unique or shared mpm ctx for this type */ int confshared = 0; char confstring[256] = "detect.mpm."; - strlcat(confstring, am->name, sizeof(confstring)); + strlcat(confstring, am->reg->name, sizeof(confstring)); strlcat(confstring, ".shared", sizeof(confstring)); if (ConfGetBool(confstring, &confshared) == 1) shared = confshared; if (shared == 0) { if (!(de_ctx->flags & DE_QUIET)) { - SCLogPerf("using unique mpm ctx' for %s", am->name); + SCLogPerf("using unique mpm ctx' for %s", am->reg->name); } am->sgh_mpm_context = MPM_CTX_FACTORY_UNIQUE_CONTEXT; } else { if (!(de_ctx->flags & DE_QUIET)) { - SCLogPerf("using shared mpm ctx' for %s", am->name); + SCLogPerf("using shared mpm ctx' for %s", am->reg->name); } - am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name); + am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->reg->name); } - SCLogDebug("AppLayer MPM %s: %u", am->name, am->sgh_mpm_context); + SCLogDebug("AppLayer MPM %s: %u", am->reg->name, am->sgh_mpm_context); + + list = list->next; } } @@ -192,11 +245,9 @@ void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) */ void DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx) { - int i; - for (i = 0; i < APP_MPMS_MAX; i++) { - AppLayerMpms *am = &app_mpms[i]; - - int dir = (am->direction == SIG_FLAG_TOSERVER) ? 1 : 0; + DetectMpmAppLayerKeyword *am = de_ctx->app_mpms; + while (am->reg != NULL) { + int dir = (am->reg->direction == SIG_FLAG_TOSERVER) ? 1 : 0; if (am->sgh_mpm_context != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { @@ -207,6 +258,7 @@ void DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx) } } } + am++; } } @@ -575,7 +627,7 @@ void RetrieveFPForSig(Signature *s) int count_n_sm_list = 0; int list_id; - /* inspect rule to see if we have the fast_pattern keyword to + /* inspect rule to see if we have the fast_pattern reg to * force using a sig, otherwise keep stats about the patterns */ for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { if (!FastPatternSupportEnabledForSigMatchList(list_id)) @@ -824,8 +876,15 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx) { HashListTableBucket *htb = NULL; + int app_mpms_cnt = 0; + DetectMpmAppLayerKeyword *a = de_ctx->app_mpms; + while (a->reg != NULL) { + a++; + app_mpms_cnt++; + } uint32_t stats[MPMB_MAX] = {0}; - uint32_t appstats[APP_MPMS_MAX] = {0}; + uint32_t appstats[app_mpms_cnt]; + memset(&appstats, 0x00, sizeof(appstats)); for (htb = HashListTableGetListHead(de_ctx->mpm_hash_table); htb != NULL; @@ -838,34 +897,37 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx) if (ms->buffer < MPMB_MAX) stats[ms->buffer]++; else if (ms->sm_list != DETECT_SM_LIST_PMATCH) { - int i; - for (i = 0; i < APP_MPMS_MAX; i++) { - AppLayerMpms *am = &app_mpms[i]; - if (ms->sm_list == am->sm_list && - ms->direction == am->direction) + int i = 0; + DetectMpmAppLayerKeyword *am = de_ctx->app_mpms; + while (am->reg != NULL) { + if (ms->sm_list == am->reg->sm_list && + ms->direction == am->reg->direction) { - SCLogDebug("%s %s: %u patterns. Min %u, Max %u. Ctx %p", am->name, - am->direction == SIG_FLAG_TOSERVER ? "toserver":"toclient", + SCLogDebug("%s %s: %u patterns. Min %u, Max %u. Ctx %p", + am->reg->name, + am->reg->direction == SIG_FLAG_TOSERVER ? "toserver":"toclient", ms->mpm_ctx->pattern_cnt, ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen, ms->mpm_ctx); appstats[i]++; break; } + i++; + am++; } } } if (!(de_ctx->flags & DE_QUIET)) { - uint32_t x; + int x; for (x = 0; x < MPMB_MAX; x++) { SCLogPerf("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]); } - for (x = 0; x < APP_MPMS_MAX; x++) { + for (x = 0; x < app_mpms_cnt; x++) { if (appstats[x] == 0) continue; - const char *name = app_mpms[x].name; - char *direction = app_mpms[x].direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient"; + const char *name = de_ctx->app_mpms[x].reg->name; + char *direction = de_ctx->app_mpms[x].reg->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient"; SCLogPerf("AppLayer MPM \"%s %s\": %u", direction, name, appstats[x]); } } @@ -1119,7 +1181,8 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, } } -MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, AppLayerMpms *am) +static MpmStore *MpmStorePrepareBufferAppLayer(DetectEngineCtx *de_ctx, + SigGroupHead *sgh, DetectMpmAppLayerKeyword *am) { const Signature *s = NULL; uint32_t sig; @@ -1128,8 +1191,9 @@ MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, App uint8_t sids_array[max_sid]; memset(sids_array, 0x00, max_sid); - SCLogDebug("handling %s direction %s for list %d", am->name, - am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", am->sm_list); + SCLogDebug("handling %s direction %s for list %d", am->reg->name, + am->reg->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", + am->reg->sm_list); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; @@ -1143,10 +1207,10 @@ MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, App if (list < 0) continue; - if ((s->flags & am->direction) == 0) + if ((s->flags & am->reg->direction) == 0) continue; - if (list != am->sm_list) + if (list != am->reg->sm_list) continue; sids_array[s->num / 8] |= 1 << (s->num % 8); @@ -1156,13 +1220,17 @@ MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, App if (cnt == 0) return NULL; - MpmStore lookup = { sids_array, max_sid, am->direction, MPMB_MAX, am->sm_list, 0, NULL}; - SCLogDebug("am->direction %d am->sm_list %d", am->direction, am->sm_list); + MpmStore lookup = { sids_array, max_sid, am->reg->direction, + MPMB_MAX, am->reg->sm_list, 0, NULL}; + SCLogDebug("am->direction %d am->sm_list %d", + am->reg->direction, am->reg->sm_list); MpmStore *result = MpmStoreLookup(de_ctx, &lookup); if (result == NULL) { SCLogDebug("new unique mpm for %s %s: %u patterns", - am->name, am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", cnt); + am->reg->name, + am->reg->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", + cnt); MpmStore *copy = SCCalloc(1, sizeof(MpmStore)); if (copy == NULL) @@ -1177,8 +1245,8 @@ MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, App copy->sid_array = sids; copy->sid_array_size = max_sid; copy->buffer = MPMB_MAX; - copy->direction = am->direction; - copy->sm_list = am->sm_list; + copy->direction = am->reg->direction; + copy->sm_list = am->reg->sm_list; copy->sgh_mpm_context = am->sgh_mpm_context; MpmStoreSetup(de_ctx, copy); @@ -1240,19 +1308,28 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) } } - AppLayerMpms *a = app_mpms; - while (a->name != NULL) { - if ((a->direction == SIG_FLAG_TOSERVER && SGH_DIRECTION_TS(sh)) || - (a->direction == SIG_FLAG_TOCLIENT && SGH_DIRECTION_TC(sh))) + int i = 0; + DetectMpmAppLayerKeyword *a = de_ctx->app_mpms; + while (a->reg != NULL) { + i++; + a++; + } + sh->init->app_mpms = SCCalloc(i, sizeof(MpmCtx *)); + BUG_ON(sh->init->app_mpms == NULL); + + a = de_ctx->app_mpms; + while (a->reg != NULL) { + if ((a->reg->direction == SIG_FLAG_TOSERVER && SGH_DIRECTION_TS(sh)) || + (a->reg->direction == SIG_FLAG_TOCLIENT && SGH_DIRECTION_TC(sh))) { - mpm_store = MpmStorePrepareBuffer2(de_ctx, sh, a); + mpm_store = MpmStorePrepareBufferAppLayer(de_ctx, sh, a); if (mpm_store != NULL) { - sh->init->app_mpms[a->id] = mpm_store->mpm_ctx; + sh->init->app_mpms[a->reg->id] = mpm_store->mpm_ctx; /* if we have just certain types of negated patterns, * mpm_ctx can be NULL */ - if (a->PrefilterRegister && mpm_store->mpm_ctx) { - BUG_ON(a->PrefilterRegister(sh, mpm_store->mpm_ctx) != 0); + if (a->reg->PrefilterRegister && mpm_store->mpm_ctx) { + BUG_ON(a->reg->PrefilterRegister(sh, mpm_store->mpm_ctx) != 0); } } } diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index bb73a6a3030e..6d4063243bd1 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -80,5 +80,19 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, enum */ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx); +void RegisterAppMpmTable(void); + +/** \brief register an app layer keyword for mpm + * \param name keyword name + * \param direction SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT + * \param sm_list list that contains the keyword's sigmatches + * \param PrefilterRegister Prefilter api registration function + * + * \note direction must be set to either toserver or toclient. + * If both are needed, register the keyword twice. + */ +void DetectMpmAppLayerRegister(const char *name, int direction, int sm_list, + int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)); + #endif /* __DETECT_ENGINE_MPM_H__ */ diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index aab2fd46165b..92d8dc66d447 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -61,6 +61,9 @@ void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid) SCFree(sghid->sig_array); sghid->sig_array = NULL; } + if (sghid->app_mpms != NULL) { + SCFree(sghid->app_mpms); + } SCFree(sghid); } diff --git a/src/detect-engine.c b/src/detect-engine.c index 6171e5e1fcc1..cc64d2b4fa06 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1017,6 +1017,8 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) SCSigSignatureOrderingModuleCleanup(de_ctx); ThresholdContextDestroy(de_ctx); SigCleanSignatures(de_ctx); + SCFree(de_ctx->app_mpms); + de_ctx->app_mpms = NULL; VariableNameFreeHash(de_ctx); if (de_ctx->sig_array) diff --git a/src/detect.c b/src/detect.c index 99860efd82cb..1f5a22d5ae90 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3987,6 +3987,8 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) #ifdef PROFILING SCProfilingRuleInitCounters(de_ctx); #endif + SCFree(de_ctx->app_mpms); + de_ctx->app_mpms = NULL; return 0; } diff --git a/src/detect.h b/src/detect.h index a725e056cd58..f0bae5ccb063 100644 --- a/src/detect.h +++ b/src/detect.h @@ -463,6 +463,25 @@ typedef struct Signature_ { struct Signature_ *next; } Signature; +/** \brief one time registration of keywords at start up */ +typedef struct DetectMpmAppLayerRegistery_ { + const char *name; + int direction; /**< SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT */ + int sm_list; + + int (*PrefilterRegister)(struct SigGroupHead_ *sgh, MpmCtx *mpm_ctx); + + int id; /**< index into this array and result arrays */ + struct DetectMpmAppLayerRegistery_ *next; +} DetectMpmAppLayerRegistery; + +/** \brief structure for storing per detect engine mpm keyword settings + */ +typedef struct DetectMpmAppLayerKeyword_ { + const DetectMpmAppLayerRegistery *reg; + int32_t sgh_mpm_context; /**< mpm factory id */ +} DetectMpmAppLayerKeyword; + typedef struct DetectReplaceList_ { struct DetectContentData_ *cd; uint8_t *found; @@ -704,6 +723,10 @@ typedef struct DetectEngineCtx_ { /** table for storing the string representation with the parsers result */ HashListTable *address_table; + /** table with mpms and their registration function + * \todo we only need this at init, so perhaps this + * can move to a DetectEngineCtx 'init' struct */ + DetectMpmAppLayerKeyword *app_mpms; } DetectEngineCtx; /* Engine groups profiles (low, medium, high, custom) */ @@ -945,8 +968,6 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_HAVEFILESHA1 (1 << 23) #define SIG_GROUP_HEAD_HAVEFILESHA256 (1 << 24) -#define APP_MPMS_MAX 21 - enum MpmBuiltinBuffers { MPMB_TCP_PKT_TS, MPMB_TCP_PKT_TC, @@ -1010,7 +1031,7 @@ typedef struct SigGroupHeadInitData_ { 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[APP_MPMS_MAX]; + MpmCtx **app_mpms; /* port ptr */ struct DetectPort_ *port; diff --git a/src/suricata.c b/src/suricata.c index 1a395ce3b3d3..27c4cc506518 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2400,6 +2400,8 @@ int main(int argc, char **argv) * are specified, IPS mode will overwrite this */ EngineModeSetIDS(); + /* TODO temporary */ + RegisterAppMpmTable(); #ifdef OS_WIN32 /* service initialization */ From 7289d12f1bc3e122bb90a43ca0981da7ff472524 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 11:28:25 +0200 Subject: [PATCH 1945/2553] http_uri: register mpm from keyword --- src/detect-engine-mpm.c | 2 -- src/detect-http-uri.c | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 24bc4fb2dd1f..27686c1c4f39 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,8 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_UMATCH, - PrefilterTxUriRegister, 0 }, { "http_raw_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRUDMATCH, PrefilterTxRawUriRegister, 0 }, diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 028459380d9a..328ce67cd4c1 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -53,6 +53,7 @@ #include "app-layer-htp.h" #include "detect-http-uri.h" #include "detect-uricontent.h" +#include "detect-engine-uri.h" #include "stream-tcp.h" int DetectHttpUriSetup (DetectEngineCtx *, Signature *, char *); @@ -74,6 +75,10 @@ void DetectHttpUriRegister (void) sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_PAYLOAD; + + DetectMpmAppLayerRegister("http_uri", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_UMATCH, + PrefilterTxUriRegister); } From 38e018e2d3530e33bb29f01ff6a5c7116d19e151 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 11:33:16 +0200 Subject: [PATCH 1946/2553] http_raw_uri: register mpm from keyword --- src/detect-engine-mpm.c | 3 --- src/detect-http-raw-uri.c | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 27686c1c4f39..9ab0d38e84aa 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,9 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_raw_uri", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRUDMATCH, - PrefilterTxRawUriRegister, 0 }, - { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, PrefilterTxHttpRequestHeadersRegister, 0}, { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 70eabd6c8aa7..9eda2d600e44 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -52,6 +52,7 @@ #include "app-layer-htp.h" #include "detect-http-raw-uri.h" +#include "detect-engine-hrud.h" #include "stream-tcp.h" static int DetectHttpRawUriSetup(DetectEngineCtx *, Signature *, char *); @@ -73,6 +74,10 @@ void DetectHttpRawUriRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_PAYLOAD; + DetectMpmAppLayerRegister("http_raw_uri", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HRUDMATCH, + PrefilterTxRawUriRegister); + return; } From 7b98c0073f9d29353674751891873188fd6595af Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 11:37:30 +0200 Subject: [PATCH 1947/2553] http_header: register mpm from keyword --- src/detect-engine-mpm.c | 5 ----- src/detect-http-header.c | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 9ab0d38e84aa..3460b3917256 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,11 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, - PrefilterTxHttpRequestHeadersRegister, 0}, - { "http_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, - PrefilterTxHttpRequestHeadersRegister, 0}, - { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, PrefilterTxUARegister, 0}, diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 6a75e8199146..e94c35e9d453 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -57,6 +57,7 @@ #include "app-layer-htp.h" #include "detect-http-header.h" +#include "detect-engine-hhd.h" #include "stream-tcp.h" int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, char *); @@ -80,6 +81,11 @@ void DetectHttpHeaderRegister(void) sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_PAYLOAD ; + DetectMpmAppLayerRegister("http_header", SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, + PrefilterTxHttpRequestHeadersRegister); + DetectMpmAppLayerRegister("http_header", SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, + PrefilterTxHttpResponseHeadersRegister); + return; } From 7813a834d0eff25fbce58d11c8e6eb7f721f1175 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 11:39:46 +0200 Subject: [PATCH 1948/2553] http_user_agent: register mpm from keyword --- src/detect-engine-mpm.c | 3 --- src/detect-http-ua.c | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 3460b3917256..9301541c2a04 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,9 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_user_agent", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HUADMATCH, - PrefilterTxUARegister, 0}, - { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, PrefilterTxRequestHeadersRawRegister, 0}, { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index b923c43fda8e..2042ee8d776c 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -57,6 +57,7 @@ #include "app-layer-htp.h" #include "stream-tcp.h" #include "detect-http-ua.h" +#include "detect-engine-hua.h" int DetectHttpUASetup(DetectEngineCtx *, Signature *, char *); void DetectHttpUARegisterTests(void); @@ -79,6 +80,10 @@ void DetectHttpUARegister(void) sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_PAYLOAD ; + DetectMpmAppLayerRegister("http_user_agent", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HUADMATCH, + PrefilterTxUARegister); + return; } From e4ea38a8deb22f7cfdacea4e335968dee22bc5c3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 11:41:35 +0200 Subject: [PATCH 1949/2553] http_raw_header: register mpm from keyword --- src/detect-engine-mpm.c | 5 ----- src/detect-http-raw-header.c | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 9301541c2a04..21d4ca34ee10 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,11 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_raw_header", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHDMATCH, - PrefilterTxRequestHeadersRawRegister, 0}, - { "http_raw_header", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HRHDMATCH, - PrefilterTxResponseHeadersRawRegister, 0}, - { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, PrefilterTxMethodRegister, 0}, diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index 7397948387e7..fe670bfb2b4a 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -57,6 +57,7 @@ #include "app-layer-htp.h" #include "detect-http-raw-header.h" +#include "detect-engine-hrhd.h" #include "stream-tcp.h" int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, char *); @@ -78,6 +79,13 @@ void DetectHttpRawHeaderRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_PAYLOAD; + DetectMpmAppLayerRegister("http_raw_header", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HRHDMATCH, + PrefilterTxRequestHeadersRawRegister); + DetectMpmAppLayerRegister("http_raw_header", SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HRHDMATCH, + PrefilterTxResponseHeadersRawRegister); + return; } From 6d0632a9c64f0a11acc9ed62f42581eddfbef315 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 11:43:08 +0200 Subject: [PATCH 1950/2553] http_method: register mpm from keyword --- src/detect-engine-mpm.c | 3 --- src/detect-http-method.c | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 21d4ca34ee10..7319afba7300 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,9 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_method", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HMDMATCH, - PrefilterTxMethodRegister, 0}, - { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, PrefilterTxSmtpFiledataRegister, 0}, /* smtp */ { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 5167bad16221..ed8cbd9a65c0 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -57,6 +57,7 @@ #include "app-layer-htp.h" #include "detect-http-method.h" +#include "detect-engine-hmd.h" #include "stream-tcp.h" @@ -80,6 +81,10 @@ void DetectHttpMethodRegister(void) sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_PAYLOAD; + DetectMpmAppLayerRegister("http_method", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HMDMATCH, + PrefilterTxMethodRegister); + SCLogDebug("registering http_method rule option"); } From 43b281a510afb3a6a304d05aa135dd2d4f497d2b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 11:47:29 +0200 Subject: [PATCH 1951/2553] file_data: register mpm from keyword --- src/detect-engine-mpm.c | 5 ----- src/detect-file-data.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 7319afba7300..08bb6c7fcdc2 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,11 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "file_data", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_FILEDATA, - PrefilterTxSmtpFiledataRegister, 0}, /* smtp */ - { "file_data", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, - PrefilterTxHttpResponseBodyRegister, 0}, /* http server body */ - { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, PrefilterTxHttpStatMsgRegister, 0}, { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, diff --git a/src/detect-file-data.c b/src/detect-file-data.c index b3e18ec1452b..12b54cbe004f 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -34,6 +34,9 @@ #include "detect-engine-mpm.h" #include "detect-engine-state.h" +#include "detect-engine-filedata-smtp.h" +#include "detect-engine-hsbd.h" + #include "flow.h" #include "flow-var.h" #include "flow-util.h" @@ -59,6 +62,13 @@ void DetectFiledataRegister(void) sigmatch_table[DETECT_FILE_DATA].Free = NULL; sigmatch_table[DETECT_FILE_DATA].RegisterTests = DetectFiledataRegisterTests; sigmatch_table[DETECT_FILE_DATA].flags = SIGMATCH_NOOPT; + + DetectMpmAppLayerRegister("file_data", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_FILEDATA, + PrefilterTxSmtpFiledataRegister); + DetectMpmAppLayerRegister("file_data", SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_FILEDATA, + PrefilterTxHttpResponseBodyRegister); } /** From cf96db095aeb46b4652eb8b383f4bd46fb779329 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 11:49:17 +0200 Subject: [PATCH 1952/2553] http_stat_msg: register mpm from keyword --- src/detect-engine-mpm.c | 2 -- src/detect-http-stat-msg.c | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 08bb6c7fcdc2..536f0a1879e9 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,8 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_stat_msg", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSMDMATCH, - PrefilterTxHttpStatMsgRegister, 0}, { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, PrefilterTxHttpStatCodeRegister, 0}, diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index 0c3151a3313c..ed02a9c57425 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -59,6 +59,7 @@ #include "app-layer-htp.h" #include "detect-http-stat-msg.h" +#include "detect-engine-hsmd.h" #include "stream-tcp-private.h" #include "stream-tcp.h" @@ -85,6 +86,10 @@ void DetectHttpStatMsgRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_PAYLOAD; + + DetectMpmAppLayerRegister("http_stat_msg", SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HSMDMATCH, + PrefilterTxHttpStatMsgRegister); } /** From 644d4dc61b466e28319c53af177878b4175b5241 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 12:21:22 +0200 Subject: [PATCH 1953/2553] http_stat_code: register mpm from keyword --- src/detect-engine-mpm.c | 3 --- src/detect-http-stat-code.c | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 536f0a1879e9..ba1147166cda 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,9 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_stat_code", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, - PrefilterTxHttpStatCodeRegister, 0}, - { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, PrefilterTxHttpRequestBodyRegister, 0}, diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index 2248694d1ed3..58e28fd46584 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -59,6 +59,7 @@ #include "app-layer-htp.h" #include "detect-http-stat-code.h" +#include "detect-engine-hscd.h" #include "stream-tcp-private.h" #include "stream-tcp.h" @@ -85,6 +86,10 @@ void DetectHttpStatCodeRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_PAYLOAD; + + DetectMpmAppLayerRegister("http_stat_code", SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HSCDMATCH, + PrefilterTxHttpStatCodeRegister); } /** From 91695c81aacca8db1b9035be73b3b7d0e4f5353b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 12:22:59 +0200 Subject: [PATCH 1954/2553] http_client_body: register mpm from keyword --- src/detect-engine-mpm.c | 3 --- src/detect-http-client-body.c | 6 ++++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index ba1147166cda..5f4cac6f8ab5 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,9 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_client_body", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCBDMATCH, - PrefilterTxHttpRequestBodyRegister, 0}, - { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, PrefilterTxHostnameRegister, 0}, { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 4497836ffa78..8b74276a9d34 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -55,6 +55,7 @@ #include "app-layer-parser.h" #include "app-layer-htp.h" #include "detect-http-client-body.h" +#include "detect-engine-hcbd.h" #include "stream-tcp.h" int DetectHttpClientBodySetup(DetectEngineCtx *, Signature *, char *); @@ -77,6 +78,11 @@ void DetectHttpClientBodyRegister(void) sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_PAYLOAD ; + + DetectMpmAppLayerRegister("http_client_body", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HCBDMATCH, + PrefilterTxHttpRequestBodyRegister); + } static void DetectHttpClientBodySetupCallback(Signature *s) From b5cd4889aed4a126e92dd35d7cb8931a869a3f43 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 12:26:17 +0200 Subject: [PATCH 1955/2553] http_host: register mpm from keyword --- src/detect-engine-mpm.c | 2 -- src/detect-http-hh.c | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 5f4cac6f8ab5..f1e75807cb39 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,8 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, - PrefilterTxHostnameRegister, 0}, { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, PrefilterTxHostnameRawRegister, 0}, diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index f8c33879747b..c2c99055a81f 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -57,6 +57,7 @@ #include "app-layer-htp.h" #include "stream-tcp.h" #include "detect-http-hh.h" +#include "detect-engine-hhhd.h" int DetectHttpHHSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpHHRegisterTests(void); @@ -78,6 +79,9 @@ void DetectHttpHHRegister(void) sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_PAYLOAD ; + DetectMpmAppLayerRegister("http_host", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HHHDMATCH, + PrefilterTxHostnameRegister); return; } From 74661449e0b7019cabe851fed80759673fc083d9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 13:01:32 +0200 Subject: [PATCH 1956/2553] http_raw_host: register mpm from keyword --- src/detect-engine-mpm.c | 3 --- src/detect-http-hrh.c | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index f1e75807cb39..acb2b9d68947 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,9 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_raw_host", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HRHHDMATCH, - PrefilterTxHostnameRawRegister, 0}, - { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, PrefilterTxRequestCookieRegister, 0}, { "http_cookie", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HCDMATCH, diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index 0243885d0595..c5bbaa7aa6f0 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -57,6 +57,7 @@ #include "app-layer-htp.h" #include "stream-tcp.h" #include "detect-http-hrh.h" +#include "detect-engine-hrhhd.h" int DetectHttpHRHSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpHRHRegisterTests(void); @@ -78,6 +79,10 @@ void DetectHttpHRHRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_PAYLOAD ; + DetectMpmAppLayerRegister("http_raw_host", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HRHHDMATCH, + PrefilterTxHostnameRawRegister); + return; } From a1a2187a0c8f7750ff4a2d5d911db0dd339689c9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 13:03:39 +0200 Subject: [PATCH 1957/2553] http_cookie: register mpm from keyword --- src/detect-engine-mpm.c | 5 ----- src/detect-http-cookie.c | 9 +++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index acb2b9d68947..ee114cb933b8 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,11 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "http_cookie", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_HCDMATCH, - PrefilterTxRequestCookieRegister, 0}, - { "http_cookie", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HCDMATCH, - PrefilterTxResponseCookieRegister, 0}, - { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, PrefilterTxDnsQueryRegister, 0}, diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 5d17c89ea48d..59fa1c1c07ad 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -58,6 +58,7 @@ #include "app-layer-htp.h" #include "detect-http-cookie.h" +#include "detect-engine-hcd.h" #include "stream-tcp.h" static int DetectHttpCookieSetup (DetectEngineCtx *, Signature *, char *); @@ -80,6 +81,14 @@ void DetectHttpCookieRegister(void) sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_PAYLOAD; + + DetectMpmAppLayerRegister("http_cookie", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HCDMATCH, + PrefilterTxRequestCookieRegister); + DetectMpmAppLayerRegister("http_cookie", SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HCDMATCH, + PrefilterTxResponseCookieRegister); + } /** From 57ae3c43e53d35a3b43ee61d4100b988804adacc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 13:05:18 +0200 Subject: [PATCH 1958/2553] dns_query: register mpm from keyword --- src/detect-dns-query.c | 8 +++++++- src/detect-engine-mpm.c | 3 --- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index ee49592872e1..0994546f5a90 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -54,6 +54,7 @@ #include "app-layer.h" #include "app-layer-dns-common.h" #include "detect-dns-query.h" +#include "detect-engine-dns.h" #include "util-unittest-helper.h" @@ -61,7 +62,7 @@ static int DetectDnsQuerySetup (DetectEngineCtx *, Signature *, char *); static void DetectDnsQueryRegisterTests(void); /** - * \brief Registration function for keyword: http_uri + * \brief Registration function for keyword: dns_query */ void DetectDnsQueryRegister (void) { @@ -75,6 +76,11 @@ void DetectDnsQueryRegister (void) sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_PAYLOAD; + + DetectMpmAppLayerRegister("dns_query", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_DNSQUERYNAME_MATCH, + PrefilterTxDnsQueryRegister); + } diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index ee114cb933b8..424260503f2d 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,9 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "dns_query", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_DNSQUERYNAME_MATCH, - PrefilterTxDnsQueryRegister, 0}, - { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, PrefilterTxTlsSniRegister, 0}, { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, From e68b2214e559327bc9bc2bfa9e223ec69f89e945 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 13:06:32 +0200 Subject: [PATCH 1959/2553] tls: register mpm from keywords --- src/detect-engine-mpm.c | 7 ------- src/detect-tls-cert-issuer.c | 5 +++++ src/detect-tls-cert-subject.c | 5 +++++ src/detect-tls-sni.c | 6 ++++++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 424260503f2d..c3ea035f06c8 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -97,13 +97,6 @@ typedef struct AppLayerMpms_ { } AppLayerMpms; AppLayerMpms app_mpms[] = { - { "tls_sni", 0, SIG_FLAG_TOSERVER, DETECT_SM_LIST_TLSSNI_MATCH, - PrefilterTxTlsSniRegister, 0}, - { "tls_cert_issuer", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, - PrefilterTxTlsIssuerRegister, 0}, - { "tls_cert_subject", 0, SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSSUBJECT_MATCH, - PrefilterTxTlsSubjectRegister, 0}, - { NULL, 0, 0, 0, NULL, 0, } }; diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index bbdb419607f6..7399e40bf983 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -32,6 +32,7 @@ #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" +#include "detect-engine-tls.h" #include "detect-content.h" #include "detect-pcre.h" @@ -70,6 +71,10 @@ void DetectTlsIssuerRegister(void) sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_PAYLOAD; + + DetectMpmAppLayerRegister("tls_cert_issuer", SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_TLSISSUER_MATCH, + PrefilterTxTlsIssuerRegister); } diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index 48c30c030d40..41706b1179a6 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -32,6 +32,7 @@ #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" +#include "detect-engine-tls.h" #include "detect-content.h" #include "detect-pcre.h" @@ -70,6 +71,10 @@ void DetectTlsSubjectRegister(void) sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_PAYLOAD; + + DetectMpmAppLayerRegister("tls_cert_subject", SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_TLSSUBJECT_MATCH, + PrefilterTxTlsSubjectRegister); } /** diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index 77774cc918b2..2d8b96e6e6d1 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -48,6 +48,7 @@ #include "app-layer.h" #include "app-layer-ssl.h" +#include "detect-engine-tls.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -70,6 +71,11 @@ void DetectTlsSniRegister(void) sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_PAYLOAD; + + DetectMpmAppLayerRegister("tls_sni", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_TLSSNI_MATCH, + PrefilterTxTlsSniRegister); + } From 6dd4dff7b288f9446568c91c5ae5c70fa5ba5ba6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 13:08:16 +0200 Subject: [PATCH 1960/2553] mpm: remove empty app_mpms table --- src/detect-engine-mpm.c | 28 ---------------------------- src/detect-engine-mpm.h | 2 -- src/suricata.c | 3 --- 3 files changed, 33 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index c3ea035f06c8..8f94aa442168 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -84,22 +84,6 @@ const char *builtin_mpms[] = { NULL }; -typedef struct AppLayerMpms_ { - const char *name; - int unused; - int direction; /**< SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT */ - int sm_list; - - int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx); - - int id; - -} AppLayerMpms; - -AppLayerMpms app_mpms[] = { - { NULL, 0, 0, 0, NULL, 0, } -}; - /* Registery for mpm keywords * * Keywords are registered at engine start up @@ -132,18 +116,6 @@ void DetectMpmAppLayerRegister(const char *name, int direction, int sm_list, g_app_mpms_list_cnt++; } -/* temporary table for turning the table app_mpms into the registery - * TODO to be removed */ -void RegisterAppMpmTable(void) -{ - AppLayerMpms *am = app_mpms; - while (am->name != NULL) { - DetectMpmAppLayerRegister(am->name, am->direction, - am->sm_list, am->PrefilterRegister); - am++; - } -} - void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) { BUG_ON(g_app_mpms_list_cnt == 0); diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 6d4063243bd1..3d12506fd153 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -80,8 +80,6 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, enum */ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx); -void RegisterAppMpmTable(void); - /** \brief register an app layer keyword for mpm * \param name keyword name * \param direction SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT diff --git a/src/suricata.c b/src/suricata.c index 27c4cc506518..cfdb9dcc24e2 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2400,9 +2400,6 @@ int main(int argc, char **argv) * are specified, IPS mode will overwrite this */ EngineModeSetIDS(); - /* TODO temporary */ - RegisterAppMpmTable(); - #ifdef OS_WIN32 /* service initialization */ if (WindowsInit(argc, argv) != 0) { From 960461f4db37fb3dcdc167933261c2d0222f98f7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 17 Sep 2016 14:44:09 +0200 Subject: [PATCH 1961/2553] fast_pattern: register app layer mpms automatically Allow for duplicate registrations for the same list. After the first registration new calls will be ignored. --- src/detect-dns-query.c | 2 +- src/detect-engine-mpm.c | 5 ++- src/detect-engine-mpm.h | 3 +- src/detect-fast-pattern.c | 61 +++++++++-------------------------- src/detect-fast-pattern.h | 2 ++ src/detect-file-data.c | 4 +-- src/detect-http-client-body.c | 2 +- src/detect-http-cookie.c | 4 +-- src/detect-http-header.c | 6 ++-- src/detect-http-hh.c | 2 +- src/detect-http-hrh.c | 2 +- src/detect-http-method.c | 2 +- src/detect-http-raw-header.c | 4 +-- src/detect-http-raw-uri.c | 2 +- src/detect-http-stat-code.c | 2 +- src/detect-http-stat-msg.c | 2 +- src/detect-http-ua.c | 2 +- src/detect-http-uri.c | 2 +- src/detect-tls-cert-issuer.c | 2 +- src/detect-tls-cert-subject.c | 2 +- src/detect-tls-sni.c | 2 +- 21 files changed, 47 insertions(+), 68 deletions(-) diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 0994546f5a90..a9e072999ca6 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -78,7 +78,7 @@ void DetectDnsQueryRegister (void) sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("dns_query", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_DNSQUERYNAME_MATCH, + DETECT_SM_LIST_DNSQUERYNAME_MATCH, 2, PrefilterTxDnsQueryRegister); } diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 8f94aa442168..c1ee337d6efb 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -92,7 +92,8 @@ const char *builtin_mpms[] = { static DetectMpmAppLayerRegistery *g_app_mpms_list = NULL; static int g_app_mpms_list_cnt = 0; -void DetectMpmAppLayerRegister(const char *name, int direction, int sm_list, +void DetectMpmAppLayerRegister(const char *name, + int direction, int sm_list, int priority, int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)) { DetectMpmAppLayerRegistery *am = SCCalloc(1, sizeof(*am)); @@ -114,6 +115,8 @@ void DetectMpmAppLayerRegister(const char *name, int direction, int sm_list, am->id = t->id + 1; } g_app_mpms_list_cnt++; + + SupportFastPatternForSigMatchList(sm_list, priority); } void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 3d12506fd153..27de064d8937 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -89,7 +89,8 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx); * \note direction must be set to either toserver or toclient. * If both are needed, register the keyword twice. */ -void DetectMpmAppLayerRegister(const char *name, int direction, int sm_list, +void DetectMpmAppLayerRegister(const char *name, + int direction, int sm_list, int priority, int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)); #endif /* __DETECT_ENGINE_MPM_H__ */ diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 1180209bc870..dba0850f36c7 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -56,8 +56,22 @@ SCFPSupportSMList *sm_fp_support_smlist_list = NULL; * \param list_id SM list id. * \param priority Priority for this list. */ -static void SupportFastPatternForSigMatchList(int list_id, int priority) +void SupportFastPatternForSigMatchList(int list_id, int priority) { + SCFPSupportSMList *ip = NULL; + /* insertion point - ip */ + for (SCFPSupportSMList *tmp = sm_fp_support_smlist_list; tmp != NULL; tmp = tmp->next) { + if (list_id == tmp->list_id) { + SCLogDebug("SM list already registered."); + return; + } + + if (priority <= tmp->priority) + break; + + ip = tmp; + } + if (sm_fp_support_smlist_list == NULL) { SCFPSupportSMList *new = SCMalloc(sizeof(SCFPSupportSMList)); if (unlikely(new == NULL)) @@ -71,20 +85,6 @@ static void SupportFastPatternForSigMatchList(int list_id, int priority) return; } - /* insertion point - ip */ - SCFPSupportSMList *ip = NULL; - for (SCFPSupportSMList *tmp = sm_fp_support_smlist_list; tmp != NULL; tmp = tmp->next) { - if (list_id == tmp->list_id) { - SCLogError(SC_ERR_FATAL, "SM list already registered."); - exit(EXIT_FAILURE); - } - - if (priority <= tmp->priority) - break; - - ip = tmp; - } - SCFPSupportSMList *new = SCMalloc(sizeof(SCFPSupportSMList)); if (unlikely(new == NULL)) exit(EXIT_FAILURE); @@ -99,13 +99,6 @@ static void SupportFastPatternForSigMatchList(int list_id, int priority) ip->next = new; } - for (SCFPSupportSMList *tmp = new->next; tmp != NULL; tmp = tmp->next) { - if (list_id == tmp->list_id) { - SCLogError(SC_ERR_FATAL, "SM list already registered."); - exit(EXIT_FAILURE); - } - } - return; } @@ -114,31 +107,9 @@ static void SupportFastPatternForSigMatchList(int list_id, int priority) */ void SupportFastPatternForSigMatchTypes(void) { - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCBDMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_FILEDATA, 2); - - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHDMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHDMATCH, 2); - - SupportFastPatternForSigMatchList(DETECT_SM_LIST_UMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRUDMATCH, 2); - - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHHDMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHHDMATCH, 2); - - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCDMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HUADMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_PMATCH, 3); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HMDMATCH, 3); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSCDMATCH, 3); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSMDMATCH, 3); - - SupportFastPatternForSigMatchList(DETECT_SM_LIST_DNSQUERYNAME_MATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_TLSSNI_MATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_TLSISSUER_MATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_TLSSUBJECT_MATCH, 2); + /* other types are handled by DetectMpmAppLayerRegister() */ #if 0 SCFPSupportSMList *tmp = sm_fp_support_smlist_list; diff --git a/src/detect-fast-pattern.h b/src/detect-fast-pattern.h index 8298e7bbf9de..ff8bc5cc3708 100644 --- a/src/detect-fast-pattern.h +++ b/src/detect-fast-pattern.h @@ -59,6 +59,8 @@ static inline int FastPatternSupportEnabledForSigMatchList(int list_id) return 0; } +void SupportFastPatternForSigMatchList(int list_id, int priority); + void SupportFastPatternForSigMatchTypes(void); void DetectFastPatternRegister(void); diff --git a/src/detect-file-data.c b/src/detect-file-data.c index 12b54cbe004f..981a2d5f10e3 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -64,10 +64,10 @@ void DetectFiledataRegister(void) sigmatch_table[DETECT_FILE_DATA].flags = SIGMATCH_NOOPT; DetectMpmAppLayerRegister("file_data", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_FILEDATA, + DETECT_SM_LIST_FILEDATA, 2, PrefilterTxSmtpFiledataRegister); DetectMpmAppLayerRegister("file_data", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_FILEDATA, + DETECT_SM_LIST_FILEDATA, 2, PrefilterTxHttpResponseBodyRegister); } diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 8b74276a9d34..4437fafb2787 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -80,7 +80,7 @@ void DetectHttpClientBodyRegister(void) sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_PAYLOAD ; DetectMpmAppLayerRegister("http_client_body", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HCBDMATCH, + DETECT_SM_LIST_HCBDMATCH, 2, PrefilterTxHttpRequestBodyRegister); } diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 59fa1c1c07ad..bb57e139d1a1 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -83,10 +83,10 @@ void DetectHttpCookieRegister(void) sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("http_cookie", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HCDMATCH, + DETECT_SM_LIST_HCDMATCH, 2, PrefilterTxRequestCookieRegister); DetectMpmAppLayerRegister("http_cookie", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HCDMATCH, + DETECT_SM_LIST_HCDMATCH, 2, PrefilterTxResponseCookieRegister); } diff --git a/src/detect-http-header.c b/src/detect-http-header.c index e94c35e9d453..291be548991e 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -81,9 +81,11 @@ void DetectHttpHeaderRegister(void) sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_PAYLOAD ; - DetectMpmAppLayerRegister("http_header", SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHDMATCH, + DetectMpmAppLayerRegister("http_header", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HHDMATCH, 2, PrefilterTxHttpRequestHeadersRegister); - DetectMpmAppLayerRegister("http_header", SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HHDMATCH, + DetectMpmAppLayerRegister("http_header", SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HHDMATCH, 2, PrefilterTxHttpResponseHeadersRegister); return; diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index c2c99055a81f..85098c295bdd 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -80,7 +80,7 @@ void DetectHttpHHRegister(void) sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_PAYLOAD ; DetectMpmAppLayerRegister("http_host", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HHHDMATCH, + DETECT_SM_LIST_HHHDMATCH, 2, PrefilterTxHostnameRegister); return; } diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index c5bbaa7aa6f0..3ba72481fb03 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -80,7 +80,7 @@ void DetectHttpHRHRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_PAYLOAD ; DetectMpmAppLayerRegister("http_raw_host", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HRHHDMATCH, + DETECT_SM_LIST_HRHHDMATCH, 2, PrefilterTxHostnameRawRegister); return; diff --git a/src/detect-http-method.c b/src/detect-http-method.c index ed8cbd9a65c0..5fa9e30c99d6 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -82,7 +82,7 @@ void DetectHttpMethodRegister(void) sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("http_method", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HMDMATCH, + DETECT_SM_LIST_HMDMATCH, 4, PrefilterTxMethodRegister); SCLogDebug("registering http_method rule option"); diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index fe670bfb2b4a..8729d26e7dda 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -80,10 +80,10 @@ void DetectHttpRawHeaderRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("http_raw_header", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HRHDMATCH, + DETECT_SM_LIST_HRHDMATCH, 2, PrefilterTxRequestHeadersRawRegister); DetectMpmAppLayerRegister("http_raw_header", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HRHDMATCH, + DETECT_SM_LIST_HRHDMATCH, 2, PrefilterTxResponseHeadersRawRegister); return; diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 9eda2d600e44..deb9b879e72c 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -75,7 +75,7 @@ void DetectHttpRawUriRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("http_raw_uri", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HRUDMATCH, + DETECT_SM_LIST_HRUDMATCH, 2, PrefilterTxRawUriRegister); return; diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index 58e28fd46584..b127dcc70b1e 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -88,7 +88,7 @@ void DetectHttpStatCodeRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("http_stat_code", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HSCDMATCH, + DETECT_SM_LIST_HSCDMATCH, 4, PrefilterTxHttpStatCodeRegister); } diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index ed02a9c57425..de60f7178812 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -88,7 +88,7 @@ void DetectHttpStatMsgRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("http_stat_msg", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HSMDMATCH, + DETECT_SM_LIST_HSMDMATCH, 3, PrefilterTxHttpStatMsgRegister); } diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index 2042ee8d776c..d018c11b7c12 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -81,7 +81,7 @@ void DetectHttpUARegister(void) sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_PAYLOAD ; DetectMpmAppLayerRegister("http_user_agent", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HUADMATCH, + DETECT_SM_LIST_HUADMATCH, 2, PrefilterTxUARegister); return; diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 328ce67cd4c1..113bde124613 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -77,7 +77,7 @@ void DetectHttpUriRegister (void) sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("http_uri", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_UMATCH, + DETECT_SM_LIST_UMATCH, 2, PrefilterTxUriRegister); } diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index 7399e40bf983..fad644822295 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -73,7 +73,7 @@ void DetectTlsIssuerRegister(void) sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("tls_cert_issuer", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_TLSISSUER_MATCH, + DETECT_SM_LIST_TLSISSUER_MATCH, 2, PrefilterTxTlsIssuerRegister); } diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index 41706b1179a6..9a3d4b464f7d 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -73,7 +73,7 @@ void DetectTlsSubjectRegister(void) sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("tls_cert_subject", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_TLSSUBJECT_MATCH, + DETECT_SM_LIST_TLSSUBJECT_MATCH, 2, PrefilterTxTlsSubjectRegister); } diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index 2d8b96e6e6d1..cdfb1e5087f2 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -73,7 +73,7 @@ void DetectTlsSniRegister(void) sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("tls_sni", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_TLSSNI_MATCH, + DETECT_SM_LIST_TLSSNI_MATCH, 2, PrefilterTxTlsSniRegister); } From 4c98b6cef3dc36e212d24efd335875888292f571 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 8 Sep 2016 12:35:44 +0200 Subject: [PATCH 1962/2553] http_request_line: implement keyword and mpm Implemented as 'stickybuffer'. Move all logic into the keyword file and remove bad tests that tested URI instead of request line. --- src/Makefile.am | 2 +- src/detect-engine-hrl.c | 4237 ----------------- src/detect-engine-state.h | 2 +- src/detect-engine.c | 9 +- src/detect-fast-pattern.c | 7 +- src/detect-http-request-line.c | 316 ++ ...ngine-hrl.h => detect-http-request-line.h} | 17 +- src/detect-lua.c | 2 +- src/detect-parse.c | 6 +- src/detect.c | 2 + src/detect.h | 3 +- 11 files changed, 345 insertions(+), 4258 deletions(-) delete mode 100644 src/detect-engine-hrl.c create mode 100644 src/detect-http-request-line.c rename src/{detect-engine-hrl.h => detect-http-request-line.h} (73%) diff --git a/src/Makefile.am b/src/Makefile.am index 89cc563f932b..b950ad220a75 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -115,7 +115,6 @@ detect-engine-hmd.c detect-engine-hmd.h \ detect-engine-hrhd.c detect-engine-hrhd.h \ detect-engine-hrhhd.c detect-engine-hrhhd.h \ detect-engine-hrud.c detect-engine-hrud.h \ -detect-engine-hrl.c detect-engine-hrl.h \ detect-engine-hsbd.c detect-engine-hsbd.h \ detect-engine-hscd.c detect-engine-hscd.h \ detect-engine-hsmd.c detect-engine-hsmd.h \ @@ -165,6 +164,7 @@ detect-http-hrh.c detect-http-hrh.h \ detect-http-method.c detect-http-method.h \ detect-http-raw-header.c detect-http-raw-header.h \ detect-http-raw-uri.c detect-http-raw-uri.h \ +detect-http-request-line.c detect-http-request-line.h \ detect-http-server-body.c detect-http-server-body.h \ detect-http-stat-code.c detect-http-stat-code.h \ detect-http-stat-msg.c detect-http-stat-msg.h \ diff --git a/src/detect-engine-hrl.c b/src/detect-engine-hrl.c deleted file mode 100644 index 244f64436b7c..000000000000 --- a/src/detect-engine-hrl.c +++ /dev/null @@ -1,4237 +0,0 @@ -/* Copyright (C) 2015 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 - * - * Based on detect-engine-uri.c - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "decode.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-parse.h" -#include "detect-engine-state.h" -#include "detect-engine-content-inspection.h" - -#include "flow-util.h" -#include "util-debug.h" -#include "util-print.h" -#include "flow.h" - -#include "stream-tcp.h" - -#include "app-layer-parser.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "app-layer.h" -#include "app-layer-htp.h" -#include "app-layer-protos.h" - -/** - * \brief Do the content inspection & validation for a signature - * - * \param de_ctx Detection engine context - * \param det_ctx Detection engine thread context - * \param s Signature to inspect - * \param sm SigMatch to inspect - * \param f Flow - * \param flags app layer flags - * \param state App layer state - * - * \retval 0 no match. - * \retval 1 match. - * \retval 2 Sig can't match. - */ -int DetectEngineInspectHttpRequestLine(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) -{ - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->request_line == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_LINE) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - else - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; - } - - det_ctx->discontinue_matching = 0; - det_ctx->buffer_offset = 0; - det_ctx->inspection_recursion_counter = 0; - -#if 0 - PrintRawDataFp(stdout, (uint8_t *)bstr_ptr(tx_ud->request_uri_normalized), - bstr_len(tx_ud->request_uri_normalized)); -#endif - - /* Inspect all the uricontents fetched on each - * transaction at the app layer */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRLMATCH], - f, - bstr_ptr(tx->request_line), - bstr_len(tx->request_line), - 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); - if (r == 1) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } else { - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } -} - -/***********************************Unittests**********************************/ - -#ifdef UNITTESTS -/** \test Test a simple uricontent option */ -static int UriTestSig01(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test uricontent option\"; " - "uricontent:\"one\"; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test the pcre /U option */ -static int UriTestSig02(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /on HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option\"; " - "pcre:/one/U; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted with payload2, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert, but it should: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test the pcre /U option */ -static int UriTestSig03(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option\"; " - "pcre:/blah/U; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test the urilen option */ -static int UriTestSig04(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test urilen option\"; " - "urilen:>20; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test the urilen option */ -static int UriTestSig05(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test urilen option\"; " - "urilen:>4; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert with payload2, but it should: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test the pcre /U option */ -static int UriTestSig06(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option\"; " - "pcre:/(oneself)+/U; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert on payload2, but it should: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test the pcre /U option in combination with urilen */ -static int UriTestSig07(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option with urilen \"; " - "pcre:/(one){2,}(self)?/U; urilen:3<>20; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert, but it should: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert with payload2, but it should: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test the pcre /U option in combination with urilen */ -static int UriTestSig08(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option with urilen\"; " - "pcre:/(blabla){2,}(self)?/U; urilen:3<>20; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test the pcre /U option in combination with urilen */ -static int UriTestSig09(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option with urilen \"; " - "pcre:/(one){2,}(self)?/U; urilen:<2; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test the uricontent option in combination with urilen */ -static int UriTestSig10(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test uricontent with urilen option\"; " - "uricontent:\"one\"; urilen:<2; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test content, uricontent, urilen, pcre /U options */ -static int UriTestSig11(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test content, uricontent, pcre /U and urilen options\"; " - "content:\"one\"; uricontent:\"one\"; pcre:/(one){2,}(self)?/U;" - "urilen:<2; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test uricontent, urilen, pcre /U options */ -static int UriTestSig12(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U, uricontent and urilen option\"; " - "uricontent:\"one\"; " - "pcre:/(one)+self/U; urilen:>2; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert with payload2, but it should: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test uricontent, urilen */ -static int UriTestSig13(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test urilen option\"; " - "urilen:>2; uricontent:\"one\"; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert with pkt, but it should: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert with payload2, but it should: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test uricontent, pcre /U */ -static int UriTestSig14(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test uricontent option\"; " - "uricontent:\"one\"; pcre:/one(self)?/U;sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert with pkt, but it should: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert with payload2, but it should: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test pcre /U with anchored regex (bug 155) */ -static int UriTestSig15(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test uricontent option\"; " - "uricontent:\"one\"; pcre:/^\\/one(self)?$/U;sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert with pkt, but it should: "); - goto end; - } - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didnt alert with payload2, but it should: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** \test Test pcre /U with anchored regex (bug 155) */ -static int UriTestSig16(void) -{ - int result = 0; - Flow f; - HtpState *http_state = NULL; - uint8_t http_buf1[] = "POST /search?q=123&aq=7123abcee HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0/\r\n" - "Host: 1.2.3.4\r\n\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = "POST /search?q=123&aq=7123abcee HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any (msg:\"ET TROJAN Downadup/Conficker A or B Worm reporting\"; flow:to_server,established; uricontent:\"/search?q=\"; pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; sid:2009024; rev:9;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 2009024)) { - printf("sig 1 didnt alert with pkt, but it should: "); - goto end; - } - p->alerts.cnt = 0; - - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - p->payload = http_buf2; - p->payload_len = http_buf2_len; - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 2009024)) { - printf("sig 1 alerted, but it should not (host should not match): "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test multiple relative contents - */ -static int UriTestSig17(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /now_this_is_is_big_big_string_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"this\"; uricontent:\"is\"; within:6; " - "uricontent:\"big\"; within:8; " - "uricontent:\"string\"; within:8; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test multiple relative contents - */ -static int UriTestSig18(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /now_this_is_is_is_big_big_big_string_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"this\"; uricontent:\"is\"; within:9; " - "uricontent:\"big\"; within:12; " - "uricontent:\"string\"; within:8; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test multiple relative contents - */ -static int UriTestSig19(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /this_this_now_is_is_____big_string_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"now\"; uricontent:\"this\"; " - "uricontent:\"is\"; within:12; " - "uricontent:\"big\"; within:8; " - "uricontent:\"string\"; within:8; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test multiple relative contents with offset - */ -static int UriTestSig20(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /_________thus_thus_is_a_big HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"thus\"; offset:8; " - "uricontent:\"is\"; within:6; " - "uricontent:\"big\"; within:8; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test multiple relative contents with a negated content. - */ -static int UriTestSig21(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"fix\"; uricontent:\"this\"; within:6; " - "uricontent:!\"and\"; distance:0; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test relative pcre. - */ -static int UriTestSig22(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /this_is_a_super_duper_" - "nova_in_super_nova_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "pcre:/super/U; uricontent:\"nova\"; within:7; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but it should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test multiple relative contents with a negated content. - */ -static int UriTestSig23(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:!\"fix_this_now\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test multiple relative contents with a negated content. - */ -static int UriTestSig24(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"we_need_to\"; uricontent:!\"fix_this_now\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it should not: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test normalized uricontents. - */ -static int UriTestSig25(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "pcre:/normalized/U; uricontent:\"normalized uri\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but it should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test multiple relative contents with a negated content. - */ -static int UriTestSig26(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"fix_this\"; isdataat:4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but it should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -/** - * \test Test multiple relative contents with a negated content. - */ -static int UriTestSig27(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"fix_this\"; isdataat:!10,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but it should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static int UriTestSig28(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"dummy\"; " - "uricontent:\"this\"; " - "byte_extract:1,2,one,string,dec,relative; " - "uricontent:\"ring\"; distance:one; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -static int UriTestSig29(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"dummy\"; " - "uricontent:\"this\"; " - "byte_extract:1,2,one,string,dec,relative; " - "uricontent:\"ring\"; distance:one; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -static int UriTestSig30(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"dummy\"; " - "uricontent:\"this\"; " - "byte_extract:1,2,one,string,dec,relative; " - "uricontent:\"_b5ig\"; offset:one; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -static int UriTestSig31(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"dummy\"; " - "uricontent:\"this\"; " - "byte_extract:1,2,one,string,dec,relative; " - "uricontent:\"his\"; depth:one; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -static int UriTestSig32(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"dummy\"; " - "uricontent:\"this\"; " - "byte_extract:1,2,one,string,dec,relative; " - "uricontent:\"g_st\"; within:one; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -static int UriTestSig33(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:15; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but it should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -static int UriTestSig34(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:15, norm; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but it should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -static int UriTestSig35(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:16; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it shouldn't have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -static int UriTestSig36(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:16, norm; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it shouldn't have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -static int UriTestSig37(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:17, raw; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert, but it should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -static int UriTestSig38(void) -{ - int result = 0; - uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; - uint32_t http_buf_len = strlen((char *)http_buf); - Flow f; - TcpSession ssn; - HtpState *http_state = NULL; - Packet *p = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_HTTP; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:18, raw; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted, but it shouldn't have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePacket(p); - return result; -} - -#endif /* UNITTESTS */ - -void HttpRequestLineRegisterTests(void) -{ - -#ifdef UNITTESTS - UtRegisterTest("UriTestSig01", UriTestSig01); - UtRegisterTest("UriTestSig02", UriTestSig02); - UtRegisterTest("UriTestSig03", UriTestSig03); - UtRegisterTest("UriTestSig04", UriTestSig04); - UtRegisterTest("UriTestSig05", UriTestSig05); - UtRegisterTest("UriTestSig06", UriTestSig06); - UtRegisterTest("UriTestSig07", UriTestSig07); - UtRegisterTest("UriTestSig08", UriTestSig08); - UtRegisterTest("UriTestSig09", UriTestSig09); - UtRegisterTest("UriTestSig10", UriTestSig10); - UtRegisterTest("UriTestSig11", UriTestSig11); - UtRegisterTest("UriTestSig12", UriTestSig12); - UtRegisterTest("UriTestSig13", UriTestSig13); - UtRegisterTest("UriTestSig14", UriTestSig14); - UtRegisterTest("UriTestSig15", UriTestSig15); - UtRegisterTest("UriTestSig16", UriTestSig16); - UtRegisterTest("UriTestSig17", UriTestSig17); - UtRegisterTest("UriTestSig18", UriTestSig18); - UtRegisterTest("UriTestSig19", UriTestSig19); - UtRegisterTest("UriTestSig20", UriTestSig20); - UtRegisterTest("UriTestSig21", UriTestSig21); - UtRegisterTest("UriTestSig22", UriTestSig22); - UtRegisterTest("UriTestSig23", UriTestSig23); - UtRegisterTest("UriTestSig24", UriTestSig24); - UtRegisterTest("UriTestSig25", UriTestSig25); - UtRegisterTest("UriTestSig26", UriTestSig26); - UtRegisterTest("UriTestSig27", UriTestSig27); - - UtRegisterTest("UriTestSig28", UriTestSig28); - UtRegisterTest("UriTestSig29", UriTestSig29); - UtRegisterTest("UriTestSig30", UriTestSig30); - UtRegisterTest("UriTestSig31", UriTestSig31); - UtRegisterTest("UriTestSig32", UriTestSig32); - UtRegisterTest("UriTestSig33", UriTestSig33); - UtRegisterTest("UriTestSig34", UriTestSig34); - UtRegisterTest("UriTestSig35", UriTestSig35); - UtRegisterTest("UriTestSig36", UriTestSig36); - UtRegisterTest("UriTestSig37", UriTestSig37); - UtRegisterTest("UriTestSig38", UriTestSig38); -#endif /* UNITTESTS */ - - return; -} diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index e079bedbca3c..70d9d30fb48d 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -83,7 +83,7 @@ #define DE_STATE_FLAG_DNSQUERYNAME_INSPECT BIT_U32(17) #define DE_STATE_FLAG_APP_EVENT_INSPECT BIT_U32(18) #define DE_STATE_FLAG_MODBUS_INSPECT BIT_U32(19) -#define DE_STATE_FLAG_HRL_INSPECT BIT_U32(20) +#define DE_STATE_FLAG_HTTP_REQLINE_INSPECT BIT_U32(20) #define DE_STATE_FLAG_FD_SMTP_INSPECT BIT_U32(21) #define DE_STATE_FLAG_DNSREQUEST_INSPECT BIT_U32(22) #define DE_STATE_FLAG_DNSRESPONSE_INSPECT BIT_U32(23) diff --git a/src/detect-engine.c b/src/detect-engine.c index cc64d2b4fa06..e5e2957005da 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -52,7 +52,6 @@ #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" -#include "detect-engine-hrl.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" #include "detect-engine-hua.h" @@ -73,6 +72,8 @@ #include "detect-uricontent.h" #include "detect-engine-threshold.h" +#include "detect-http-request-line.h" + #include "detect-engine-loader.h" #include "util-classification-config.h" @@ -176,8 +177,8 @@ void DetectEngineRegisterAppInspectionEngines(void) DetectEngineInspectPacketUris }, { IPPROTO_TCP, ALPROTO_HTTP, - DETECT_SM_LIST_HRLMATCH, - DE_STATE_FLAG_HRL_INSPECT, + DETECT_SM_LIST_HTTP_REQLINEMATCH, + DE_STATE_FLAG_HTTP_REQLINE_INSPECT, 0, DetectEngineInspectHttpRequestLine }, { IPPROTO_TCP, @@ -2806,7 +2807,7 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http cookie"; case DETECT_SM_LIST_HUADMATCH: return "http user-agent"; - case DETECT_SM_LIST_HRLMATCH: + case DETECT_SM_LIST_HTTP_REQLINEMATCH: return "http request line"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index dba0850f36c7..c890419377f7 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -180,14 +180,16 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_TLSISSUER_MATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_TLSSUBJECT_MATCH] == NULL) { + s->sm_lists_tail[DETECT_SM_LIST_TLSSUBJECT_MATCH] == NULL && + s->sm_lists_tail[DETECT_SM_LIST_HTTP_REQLINEMATCH] == NULL) { SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " "rule, without a preceding content based keyword. " "Currently we provide fast_pattern support for content, " "uricontent, http_client_body, http_server_body, http_header, " "http_raw_header, http_method, http_cookie, " "http_raw_uri, http_stat_msg, http_stat_code, " - "http_user_agent, http_host, http_raw_host, dns_query, " + "http_user_agent, http_host, http_raw_host, " + "http_request_line, dns_query, " "tls_sni, tls_cert_issuer or tls_cert_subject option"); return -1; } @@ -207,6 +209,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HTTP_REQLINEMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSISSUER_MATCH], diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c new file mode 100644 index 000000000000..0c43d9ae4bbe --- /dev/null +++ b/src/detect-http-request-line.c @@ -0,0 +1,316 @@ +/* Copyright (C) 2007-2016 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. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support for the http_request_line keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "stream-tcp.h" +#include "detect-http-request-line.h" + +int DetectHttpRequestLineSetup(DetectEngineCtx *, Signature *, char *); +void DetectHttpRequestLineRegisterTests(void); +void DetectHttpRequestLineFree(void *); +static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + +/** + * \brief Registers the keyword handlers for the "http_request_line" keyword. + */ +void DetectHttpRequestLineRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].name = "http_request_line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].desc = "content modifier to match only on the HTTP request line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_request_line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Match = NULL; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Setup = DetectHttpRequestLineSetup; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].RegisterTests = DetectHttpRequestLineRegisterTests; + + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].flags |= SIGMATCH_PAYLOAD ; + + DetectMpmAppLayerRegister("http_request_line", SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HTTP_REQLINEMATCH, 2, + PrefilterTxHttpRequestLineRegister); + + return; +} + +/** + * \brief The setup function for the http_request_line keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to the signature for the current Signature being + * parsed from the rules. + * \param m Pointer to the head of the SigMatch for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +int DetectHttpRequestLineSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->list = DETECT_SM_LIST_HTTP_REQLINEMATCH; + s->alproto = ALPROTO_HTTP; + return 0; +} + +/** \brief HTTP request line Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpRequestLine(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_line == NULL) + return; + + const uint32_t buffer_len = bstr_len(tx->request_line); + const uint8_t *buffer = bstr_ptr(tx->request_line); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestLine, + ALPROTO_HTTP, HTP_REQUEST_LINE, + mpm_ctx, NULL, "http_request_line"); +} + +/** + * \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags app layer flags + * \param state App layer state + * + * \retval 0 no match. + * \retval 1 match. + * \retval 2 Sig can't match. + */ +int DetectEngineInspectHttpRequestLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *txv, uint64_t tx_id) +{ + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_line == NULL) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_LINE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + else + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } + + det_ctx->discontinue_matching = 0; + det_ctx->buffer_offset = 0; + det_ctx->inspection_recursion_counter = 0; + + /* Inspect all the uricontents fetched on each + * transaction at the app layer */ + int r = DetectEngineContentInspection(de_ctx, det_ctx, + s, s->sm_lists[DETECT_SM_LIST_HTTP_REQLINEMATCH], + f, + bstr_ptr(tx->request_line), + bstr_len(tx->request_line), + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } else { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS + +#include "stream-tcp-reassemble.h" + +/** + * \test Test that a signature containting a http_request_line is correctly parsed + * and the keyword is registered. + */ +static int DetectHttpRequestLineTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(http_request_line; content:\"GET /\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + DetectEngineCtxFree(de_ctx); + PASS; +} + + +/** + *\test Test that the http_request_line content matches against a http request + * which holds the content. + */ +static int DetectHttpRequestLineTest02(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy message body\r\n" + "Content-Type: text/html\r\n" + "\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF_NULL(p); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(http_request_line; content:\"GET /index.html HTTP/1.0\"; " + "sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(&th_v, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FAIL_IF(r != 0); + + http_state = f.alstate; + FAIL_IF_NULL(http_state); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + FAIL_IF(!(PacketAlertCheck(p, 1))); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +#endif /* UNITTESTS */ + +void DetectHttpRequestLineRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectHttpRequestLineTest01", DetectHttpRequestLineTest01); + UtRegisterTest("DetectHttpRequestLineTest02", DetectHttpRequestLineTest02); +#endif /* UNITTESTS */ + + return; +} +/** + * @} + */ diff --git a/src/detect-engine-hrl.h b/src/detect-http-request-line.h similarity index 73% rename from src/detect-engine-hrl.h rename to src/detect-http-request-line.h index cb5360d9a08b..0c47f5fa5e69 100644 --- a/src/detect-engine-hrl.h +++ b/src/detect-http-request-line.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -15,20 +15,21 @@ * 02110-1301, USA. */ -/** \file +/** + * \file * - * \author Victor Julien + * \author Victor Julien */ -#ifndef __DETECT_ENGINE_HRL_H__ -#define __DETECT_ENGINE_HRL_H__ +#ifndef __DETECT_HTTP_REQUEST_LINE_H__ +#define __DETECT_HTTP_REQUEST_LINE_H__ int DetectEngineInspectHttpRequestLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); -void HttpRequestLineRegisterTests(void); + void *txv, uint64_t tx_id); +void DetectHttpRequestLineRegister(void); -#endif /* __DETECT_ENGINE_HRL_H__ */ +#endif /* __DETECT_HTTP_REQUEST_LINE_H__ */ diff --git a/src/detect-lua.c b/src/detect-lua.c index a4716d44eeaa..ab044347393e 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1109,7 +1109,7 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) else if (luajit->flags & DATATYPE_HTTP_RESPONSE_COOKIE) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); else - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRLMATCH); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HTTP_REQLINEMATCH); } else if (luajit->alproto == ALPROTO_DNS) { if (luajit->flags & DATATYPE_DNS_RRNAME) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSQUERYNAME_MATCH); diff --git a/src/detect-parse.c b/src/detect-parse.c index 1215d56211b5..639c5aad9097 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -155,7 +155,7 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HMDMATCH, "http_method"); CASE_CODE_STRING(DETECT_SM_LIST_HCDMATCH, "http_cookie"); CASE_CODE_STRING(DETECT_SM_LIST_HUADMATCH, "http_user_agent"); - CASE_CODE_STRING(DETECT_SM_LIST_HRLMATCH, "http_request_line"); + CASE_CODE_STRING(DETECT_SM_LIST_HTTP_REQLINEMATCH, "http_request_line"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -199,7 +199,7 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HMDMATCH); CASE_CODE(DETECT_SM_LIST_HCDMATCH); CASE_CODE(DETECT_SM_LIST_HUADMATCH); - CASE_CODE(DETECT_SM_LIST_HRLMATCH); + CASE_CODE(DETECT_SM_LIST_HTTP_REQLINEMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); @@ -1561,7 +1561,7 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_AMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HRLMATCH]) + if (sig->sm_lists[DETECT_SM_LIST_HTTP_REQLINEMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HCBDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; diff --git a/src/detect.c b/src/detect.c index 1f5a22d5ae90..160feb323d11 100644 --- a/src/detect.c +++ b/src/detect.c @@ -142,6 +142,7 @@ #include "detect-http-uri.h" #include "detect-http-raw-uri.h" #include "detect-http-stat-msg.h" +#include "detect-http-request-line.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-hhd.h" @@ -4225,6 +4226,7 @@ void SigTableSetup(void) DetectTemplateRegister(); DetectTemplateBufferRegister(); DetectBypassRegister(); + DetectHttpRequestLineRegister(); } void SigTableRegisterTests(void) diff --git a/src/detect.h b/src/detect.h index f0bae5ccb063..ba154d11a0a6 100644 --- a/src/detect.h +++ b/src/detect.h @@ -114,7 +114,7 @@ enum DetectSigmatchListEnum { /* list for http_user_agent keyword and the ones relative to it */ DETECT_SM_LIST_HUADMATCH, /* list for http_request_line keyword and the ones relative to it */ - DETECT_SM_LIST_HRLMATCH, + DETECT_SM_LIST_HTTP_REQLINEMATCH, /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, @@ -1230,6 +1230,7 @@ enum { DETECT_AL_HTTP_USER_AGENT, DETECT_AL_HTTP_HOST, DETECT_AL_HTTP_RAW_HOST, + DETECT_AL_HTTP_REQUEST_LINE, DETECT_AL_SSH_PROTOVERSION, DETECT_AL_SSH_SOFTWAREVERSION, DETECT_AL_SSL_VERSION, From f1e38405160d5d56c0f92354c17938ba5caa3fd5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 8 Sep 2016 15:19:40 +0200 Subject: [PATCH 1963/2553] http_response_body: implement keyword with mpm Implemented as 'stickybuffer'. --- src/Makefile.am | 1 + src/detect-engine-state.h | 1 + src/detect-engine.c | 9 + src/detect-http-response-line.c | 331 ++++++++++++++++++++++++++++++++ src/detect-http-response-line.h | 35 ++++ src/detect-parse.c | 4 + src/detect.c | 2 + src/detect.h | 3 + 8 files changed, 386 insertions(+) create mode 100644 src/detect-http-response-line.c create mode 100644 src/detect-http-response-line.h diff --git a/src/Makefile.am b/src/Makefile.am index b950ad220a75..b76063152123 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -165,6 +165,7 @@ detect-http-method.c detect-http-method.h \ detect-http-raw-header.c detect-http-raw-header.h \ detect-http-raw-uri.c detect-http-raw-uri.h \ detect-http-request-line.c detect-http-request-line.h \ +detect-http-response-line.c detect-http-response-line.h \ detect-http-server-body.c detect-http-server-body.h \ detect-http-stat-code.c detect-http-stat-code.h \ detect-http-stat-msg.c detect-http-stat-msg.h \ diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 70d9d30fb48d..c5b18c73000c 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -93,6 +93,7 @@ #define DE_STATE_FLAG_TLSVALIDITY_INSPECT BIT_U32(27) #define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(28) #define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(29) +#define DE_STATE_FLAG_HTTP_RESLINE_INSPECT BIT_U32(30) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine.c b/src/detect-engine.c index e5e2957005da..6a2215569021 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -73,6 +73,7 @@ #include "detect-engine-threshold.h" #include "detect-http-request-line.h" +#include "detect-http-response-line.h" #include "detect-engine-loader.h" @@ -352,6 +353,12 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_HSCD_INSPECT, 1, DetectEngineInspectHttpStatCode }, + { IPPROTO_TCP, + ALPROTO_HTTP, + DETECT_SM_LIST_HTTP_RESLINEMATCH, + DE_STATE_FLAG_HTTP_RESLINE_INSPECT, + 1, + DetectEngineInspectHttpResponseLine }, /* Modbus */ { IPPROTO_TCP, ALPROTO_MODBUS, @@ -2809,6 +2816,8 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http user-agent"; case DETECT_SM_LIST_HTTP_REQLINEMATCH: return "http request line"; + case DETECT_SM_LIST_HTTP_RESLINEMATCH: + return "http response line"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c new file mode 100644 index 000000000000..7b4131108381 --- /dev/null +++ b/src/detect-http-response-line.c @@ -0,0 +1,331 @@ +/* Copyright (C) 2007-2016 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. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support for the http_response_line keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "stream-tcp.h" +#include "detect-http-response-line.h" + +int DetectHttpResponseLineSetup(DetectEngineCtx *, Signature *, char *); +void DetectHttpResponseLineRegisterTests(void); +void DetectHttpResponseLineFree(void *); +static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + +/** + * \brief Registers the keyword handlers for the "http_response_line" keyword. + */ +void DetectHttpResponseLineRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].name = "http_response_line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].desc = "content modifier to match only on the HTTP response line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_response_line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].Match = NULL; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].Setup = DetectHttpResponseLineSetup; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].RegisterTests = DetectHttpResponseLineRegisterTests; + + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].flags |= SIGMATCH_PAYLOAD ; + + DetectMpmAppLayerRegister("http_response_line", SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HTTP_RESLINEMATCH, 2, + PrefilterTxHttpResponseLineRegister); + return; +} + +/** + * \brief The setup function for the http_response_line keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to the signature for the current Signature being + * parsed from the rules. + * \param m Pointer to the head of the SigMatch for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +int DetectHttpResponseLineSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->list = DETECT_SM_LIST_HTTP_RESLINEMATCH; + s->alproto = ALPROTO_HTTP; + return 0; +} + +/** \brief HTTP response line Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpResponseLine(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_line == NULL) + return; + + const uint32_t buffer_len = bstr_len(tx->response_line); + const uint8_t *buffer = bstr_ptr(tx->response_line); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseLine, + ALPROTO_HTTP, HTP_RESPONSE_LINE, + mpm_ctx, NULL, "http_response_line"); +} + +/** + * \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags app layer flags + * \param state App layer state + * + * \retval 0 no match. + * \retval 1 match. + * \retval 2 Sig can't match. + */ +int DetectEngineInspectHttpResponseLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *txv, uint64_t tx_id) +{ + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_line == NULL) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_RESPONSE_LINE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + else + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } + + det_ctx->discontinue_matching = 0; + det_ctx->buffer_offset = 0; + det_ctx->inspection_recursion_counter = 0; + +#if 0 + PrintRawDataFp(stdout, (uint8_t *)bstr_ptr(tx->response_line), + bstr_len(tx->response_line)); +#endif + + /* run the inspection against the buffer */ + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HTTP_RESLINEMATCH], + f, + bstr_ptr(tx->response_line), + bstr_len(tx->response_line), + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } else { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS + +#include "stream-tcp-reassemble.h" + +/** + * \test Test that a signature containting a http_response_line is correctly parsed + * and the keyword is registered. + */ +static int DetectHttpResponseLineTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(http_response_line; content:\"200 OK\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + DetectEngineCtxFree(de_ctx); + PASS; +} + + +/** + *\test Test that the http_response_line content matches against a http request + * which holds the content. + */ +static int DetectHttpResponseLineTest02(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy message body\r\n" + "Content-Type: text/html\r\n" + "\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 OK\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "message"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF_NULL(p); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= (FLOW_PKT_TOSERVER|FLOW_PKT_ESTABLISHED); + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(http_response_line; content:\"HTTP/1.0 200 OK\"; " + "sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(&th_v, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FAIL_IF(r != 0); + + http_state = f.alstate; + FAIL_IF_NULL(http_state); + + r = AppLayerParserParse(&th_v, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FAIL_IF(r != 0); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(PacketAlertCheck(p, 1)); + + p->flowflags = (FLOW_PKT_TOCLIENT|FLOW_PKT_ESTABLISHED); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!(PacketAlertCheck(p, 1))); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +#endif /* UNITTESTS */ + +void DetectHttpResponseLineRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectHttpResponseLineTest01", DetectHttpResponseLineTest01); + UtRegisterTest("DetectHttpResponseLineTest02", DetectHttpResponseLineTest02); +#endif /* UNITTESTS */ + + return; +} +/** + * @} + */ diff --git a/src/detect-http-response-line.h b/src/detect-http-response-line.h new file mode 100644 index 000000000000..53e74801307c --- /dev/null +++ b/src/detect-http-response-line.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2007-2016 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 + */ + +#ifndef __DETECT_HTTP_RESPONSE_LINE_H__ +#define __DETECT_HTTP_RESPONSE_LINE_H__ + +int DetectEngineInspectHttpResponseLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *txv, uint64_t tx_id); +void DetectHttpResponseLineRegister(void); + +#endif /* __DETECT_HTTP_RESPONSE_LINE_H__ */ diff --git a/src/detect-parse.c b/src/detect-parse.c index 639c5aad9097..ec7e0b18c854 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -156,6 +156,7 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HCDMATCH, "http_cookie"); CASE_CODE_STRING(DETECT_SM_LIST_HUADMATCH, "http_user_agent"); CASE_CODE_STRING(DETECT_SM_LIST_HTTP_REQLINEMATCH, "http_request_line"); + CASE_CODE_STRING(DETECT_SM_LIST_HTTP_RESLINEMATCH, "http_response_line"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -200,6 +201,7 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HCDMATCH); CASE_CODE(DETECT_SM_LIST_HUADMATCH); CASE_CODE(DETECT_SM_LIST_HTTP_REQLINEMATCH); + CASE_CODE(DETECT_SM_LIST_HTTP_RESLINEMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); @@ -1563,6 +1565,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HTTP_REQLINEMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_HTTP_RESLINEMATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HCBDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_FILEDATA]) diff --git a/src/detect.c b/src/detect.c index 160feb323d11..c80daf800bc1 100644 --- a/src/detect.c +++ b/src/detect.c @@ -143,6 +143,7 @@ #include "detect-http-raw-uri.h" #include "detect-http-stat-msg.h" #include "detect-http-request-line.h" +#include "detect-http-response-line.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-hhd.h" @@ -4227,6 +4228,7 @@ void SigTableSetup(void) DetectTemplateBufferRegister(); DetectBypassRegister(); DetectHttpRequestLineRegister(); + DetectHttpResponseLineRegister(); } void SigTableRegisterTests(void) diff --git a/src/detect.h b/src/detect.h index ba154d11a0a6..c181c90a0168 100644 --- a/src/detect.h +++ b/src/detect.h @@ -115,6 +115,8 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_HUADMATCH, /* list for http_request_line keyword and the ones relative to it */ DETECT_SM_LIST_HTTP_REQLINEMATCH, + /* list for http_response_line keyword and the ones relative to it */ + DETECT_SM_LIST_HTTP_RESLINEMATCH, /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, @@ -1231,6 +1233,7 @@ enum { DETECT_AL_HTTP_HOST, DETECT_AL_HTTP_RAW_HOST, DETECT_AL_HTTP_REQUEST_LINE, + DETECT_AL_HTTP_RESPONSE_LINE, DETECT_AL_SSH_PROTOVERSION, DETECT_AL_SSH_SOFTWAREVERSION, DETECT_AL_SSL_VERSION, From bac37fc9ae5e3469652fda2ef268de617de485dd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Sep 2016 16:17:20 +0200 Subject: [PATCH 1964/2553] detect state: reorganize flags List the common non-buffer specific flags on top. --- src/detect-engine-state.h | 63 ++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index c5b18c73000c..4998c1fe4ba3 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -63,37 +63,38 @@ #define DE_STATE_CHUNK_SIZE 15 /* per sig flags */ -#define DE_STATE_FLAG_URI_INSPECT BIT_U32(0) -#define DE_STATE_FLAG_HRUD_INSPECT BIT_U32(1) -#define DE_STATE_FLAG_HCBD_INSPECT BIT_U32(2) -#define DE_STATE_FLAG_HSBD_INSPECT BIT_U32(3) -#define DE_STATE_FLAG_HHD_INSPECT BIT_U32(4) -#define DE_STATE_FLAG_HRHD_INSPECT BIT_U32(5) -#define DE_STATE_FLAG_HHHD_INSPECT BIT_U32(6) -#define DE_STATE_FLAG_HRHHD_INSPECT BIT_U32(7) -#define DE_STATE_FLAG_HUAD_INSPECT BIT_U32(8) -#define DE_STATE_FLAG_HMD_INSPECT BIT_U32(9) -#define DE_STATE_FLAG_HCD_INSPECT BIT_U32(10) -#define DE_STATE_FLAG_HSMD_INSPECT BIT_U32(11) -#define DE_STATE_FLAG_HSCD_INSPECT BIT_U32(12) -#define DE_STATE_FLAG_FILE_TC_INSPECT BIT_U32(13) -#define DE_STATE_FLAG_FILE_TS_INSPECT BIT_U32(14) -#define DE_STATE_FLAG_FULL_INSPECT BIT_U32(15) -#define DE_STATE_FLAG_SIG_CANT_MATCH BIT_U32(16) -#define DE_STATE_FLAG_DNSQUERYNAME_INSPECT BIT_U32(17) -#define DE_STATE_FLAG_APP_EVENT_INSPECT BIT_U32(18) -#define DE_STATE_FLAG_MODBUS_INSPECT BIT_U32(19) -#define DE_STATE_FLAG_HTTP_REQLINE_INSPECT BIT_U32(20) -#define DE_STATE_FLAG_FD_SMTP_INSPECT BIT_U32(21) -#define DE_STATE_FLAG_DNSREQUEST_INSPECT BIT_U32(22) -#define DE_STATE_FLAG_DNSRESPONSE_INSPECT BIT_U32(23) -#define DE_STATE_FLAG_TLSSNI_INSPECT BIT_U32(24) -#define DE_STATE_FLAG_TLSISSUER_INSPECT BIT_U32(25) -#define DE_STATE_FLAG_TLSSUBJECT_INSPECT BIT_U32(26) -#define DE_STATE_FLAG_TLSVALIDITY_INSPECT BIT_U32(27) -#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(28) -#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(29) -#define DE_STATE_FLAG_HTTP_RESLINE_INSPECT BIT_U32(30) +#define DE_STATE_FLAG_FULL_INSPECT BIT_U32(0) +#define DE_STATE_FLAG_SIG_CANT_MATCH BIT_U32(1) + +#define DE_STATE_FLAG_URI_INSPECT BIT_U32(2) +#define DE_STATE_FLAG_HRUD_INSPECT BIT_U32(3) +#define DE_STATE_FLAG_HCBD_INSPECT BIT_U32(4) +#define DE_STATE_FLAG_HSBD_INSPECT BIT_U32(5) +#define DE_STATE_FLAG_HHD_INSPECT BIT_U32(6) +#define DE_STATE_FLAG_HRHD_INSPECT BIT_U32(7) +#define DE_STATE_FLAG_HHHD_INSPECT BIT_U32(8) +#define DE_STATE_FLAG_HRHHD_INSPECT BIT_U32(9) +#define DE_STATE_FLAG_HUAD_INSPECT BIT_U32(10) +#define DE_STATE_FLAG_HMD_INSPECT BIT_U32(11) +#define DE_STATE_FLAG_HCD_INSPECT BIT_U32(12) +#define DE_STATE_FLAG_HSMD_INSPECT BIT_U32(13) +#define DE_STATE_FLAG_HSCD_INSPECT BIT_U32(14) +#define DE_STATE_FLAG_FILE_TC_INSPECT BIT_U32(15) +#define DE_STATE_FLAG_FILE_TS_INSPECT BIT_U32(16) +#define DE_STATE_FLAG_DNSQUERYNAME_INSPECT BIT_U32(17) +#define DE_STATE_FLAG_APP_EVENT_INSPECT BIT_U32(18) +#define DE_STATE_FLAG_MODBUS_INSPECT BIT_U32(19) +#define DE_STATE_FLAG_HTTP_REQLINE_INSPECT BIT_U32(20) +#define DE_STATE_FLAG_FD_SMTP_INSPECT BIT_U32(21) +#define DE_STATE_FLAG_DNSREQUEST_INSPECT BIT_U32(22) +#define DE_STATE_FLAG_DNSRESPONSE_INSPECT BIT_U32(23) +#define DE_STATE_FLAG_TLSSNI_INSPECT BIT_U32(24) +#define DE_STATE_FLAG_TLSISSUER_INSPECT BIT_U32(25) +#define DE_STATE_FLAG_TLSSUBJECT_INSPECT BIT_U32(26) +#define DE_STATE_FLAG_TLSVALIDITY_INSPECT BIT_U32(27) +#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(28) +#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(29) +#define DE_STATE_FLAG_HTTP_RESLINE_INSPECT BIT_U32(30) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 From 5f994756e684457d81000530f57d7243b4e099c9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Sep 2016 17:43:41 +0200 Subject: [PATCH 1965/2553] detect-engine: improved inspect engines Inspect engines are called per signature per sigmatch list. Most wrap around DetectEngineContentInspection, but it's more generic. Until now, the inspect engines were setup in a large per ipproto, per alproto, per direction table. For stateful inspection each engine needed a global flag. This approach had a number of issues: 1. inefficient: each inspection round walked the table and then checked if the inspect engine was even needed for the current rule. 2. clumsy registration with global flag registration. 3. global flag space was approaching the need for 64 bits 4. duplicate registration for alprotos supporting both TCP and TCP (DNS). This patch introduces a new approach. First, it does away with the per ipproto engines. This wasn't used. Second, it adds a per signature list of inspect engine containing only those engines that actually apply to the rule. Third, it gets rid of the global flags and replaces it with flags assigned per rule per engine. --- src/detect-engine-state.c | 253 ++++----------- src/detect-engine-state.h | 35 +- src/detect-engine.c | 654 ++++++-------------------------------- src/detect-engine.h | 36 +-- src/detect-parse.c | 45 +-- src/detect.c | 2 + src/detect.h | 25 ++ 7 files changed, 216 insertions(+), 834 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 6120e1dda84a..a42ec82b17bc 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -523,13 +523,13 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, det_ctx->tx_id = tx_id; det_ctx->tx_id_set = 1; - DetectEngineAppInspectionEngine *engine = app_inspection_engine[f->protomap][alproto][direction]; + DetectEngineAppInspectionEngine *engine = s->app_inspect; SCLogDebug("engine %p", engine); inspect_flags = 0; while (engine != NULL) { SCLogDebug("engine %p", engine); SCLogDebug("inspect_flags %x", inspect_flags); - if (s->sm_lists[engine->sm_list] != NULL) { + if (direction == engine->dir) { KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); int match = engine->Callback(tv, de_ctx, det_ctx, s, f, flags, alstate, @@ -843,7 +843,8 @@ static int DoInspectItem(ThreadVars *tv, det_ctx->tx_id_set = 1; SCLogDebug("inspecting: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); - DetectEngineAppInspectionEngine *engine = app_inspection_engine[f->protomap][alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; + uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; + DetectEngineAppInspectionEngine *engine = s->app_inspect; void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); if (inspect_tx == NULL) { RULE_PROFILING_END(det_ctx, s, 0, p); @@ -852,7 +853,7 @@ static int DoInspectItem(ThreadVars *tv, while (engine != NULL) { if (!(item->flags & engine->inspect_flags) && - s->sm_lists[engine->sm_list] != NULL) + direction == engine->dir) { SCLogDebug("inspect_flags %x", inspect_flags); KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); @@ -1341,13 +1342,8 @@ static int DeStateTest02(void) static int DeStateTest03(void) { - int result = 0; - DetectEngineState *state = DetectEngineStateAlloc(); - if (state == NULL) { - printf("d == NULL: "); - goto end; - } + FAIL_IF_NULL(state); Signature s; memset(&s, 0x00, sizeof(s)); @@ -1357,34 +1353,20 @@ static int DeStateTest03(void) s.num = 11; DeStateSignatureAppend(state, &s, 0, direction); s.num = 22; - DeStateSignatureAppend(state, &s, DE_STATE_FLAG_URI_INSPECT, direction); + DeStateSignatureAppend(state, &s, BIT_U32(DE_STATE_FLAG_BASE), direction); - if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL) { - goto end; - } + FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL); - if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].sid != 11) { - goto end; - } + FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].sid != 11); - if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].flags & DE_STATE_FLAG_URI_INSPECT) { - goto end; - } + FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].flags & BIT_U32(DE_STATE_FLAG_BASE)); - if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 22) { - goto end; - } + FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 22); - if (!(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].flags & DE_STATE_FLAG_URI_INSPECT)) { - goto end; - } + FAIL_IF(!(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].flags & BIT_U32(DE_STATE_FLAG_BASE))); - result = 1; -end: - if (state != NULL) { - DetectEngineStateFree(state); - } - return result; + DetectEngineStateFree(state); + PASS; } static int DeStateSigTest01(void) @@ -1535,7 +1517,6 @@ static int DeStateSigTest01(void) /** \test multiple pipelined http transactions */ static int DeStateSigTest02(void) { - int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; @@ -1578,22 +1559,14 @@ static int DeStateSigTest02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"/\"; http_uri; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"body\"; nocase; http_client_body; sid:1; rev:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; sid:2; rev:1;)"); - if (s == NULL) { - printf("sig2 parse failed: "); - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -1601,116 +1574,74 @@ static int DeStateSigTest02(void) FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (2): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted too early: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, f.alstate, 0); - if (tx == NULL) { - printf("no http tx: "); - goto end; - } + FAIL_IF_NULL(tx); + DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(IPPROTO_TCP, ALPROTO_HTTP, tx); - if (tx_de_state == NULL || tx_de_state->dir_state[0].cnt != 1 || - tx_de_state->dir_state[0].head->store[0].flags != 0x00000001) { - printf("de_state not present or has unexpected content: "); - goto end; - } + FAIL_IF_NULL(tx_de_state); + FAIL_IF(tx_de_state->dir_state[0].cnt != 1); + FAIL_IF(tx_de_state->dir_state[0].head->store[0].flags != BIT_U32(DE_STATE_FLAG_BASE)); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't match: "); - goto end; - } - p->alerts.cnt = 0; + FAIL_IF(!(PacketAlertCheck(p, 1))); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); - if (r != 0) { - printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (5): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); - if (r != 0) { - printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { - printf("sig 1 alerted (request 2, chunk 6): "); - goto end; - } + FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))); p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); @@ -1718,36 +1649,21 @@ static int DeStateSigTest02(void) FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); - if (r != 0) { - printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 2))) { - printf("signature 2 didn't match, but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 2))); p->alerts.cnt = 0; - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); - } - + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + PASS; } static int DeStateSigTest03(void) @@ -1766,7 +1682,6 @@ static int DeStateSigTest03(void) uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ ThreadVars th_v; TcpSession ssn; - int result = 0; Flow *f = NULL; Packet *p = NULL; HtpState *http_state = NULL; @@ -1777,31 +1692,24 @@ static int DeStateSigTest03(void) DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->protoctx = &ssn; f->proto = IPPROTO_TCP; f->alproto = ALPROTO_HTTP; p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - if (p == NULL) - goto end; + FAIL_IF_NULL(p); p->flow = f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; @@ -1815,69 +1723,36 @@ static int DeStateSigTest03(void) STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(f); - goto end; - } FLOWLOCK_UNLOCK(f); - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert: "); - goto end; - } + FAIL_IF(r != 0); http_state = f->alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(http_state); + FAIL_IF_NULL(http_state->files_ts); - if (http_state->files_ts == NULL) { - printf("no files in state: "); - goto end; - } + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!(PacketAlertCheck(p, 1))); FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); - if (files == NULL) { - printf("no stored files: "); - FLOWLOCK_UNLOCK(f); - goto end; - } FLOWLOCK_UNLOCK(f); + FAIL_IF_NULL(files); File *file = files->head; - if (file == NULL) { - printf("no file: "); - goto end; - } + FAIL_IF_NULL(file); - if (!(file->flags & FILE_STORE)) { - printf("file is set to store, but sig didn't match: "); - goto end; - } + FAIL_IF(!(file->flags & FILE_STORE)); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); UTHFreeFlow(f); - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); - } + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); - return result; + PASS; } static int DeStateSigTest04(void) diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 4998c1fe4ba3..af4f87247e9a 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -66,35 +66,12 @@ #define DE_STATE_FLAG_FULL_INSPECT BIT_U32(0) #define DE_STATE_FLAG_SIG_CANT_MATCH BIT_U32(1) -#define DE_STATE_FLAG_URI_INSPECT BIT_U32(2) -#define DE_STATE_FLAG_HRUD_INSPECT BIT_U32(3) -#define DE_STATE_FLAG_HCBD_INSPECT BIT_U32(4) -#define DE_STATE_FLAG_HSBD_INSPECT BIT_U32(5) -#define DE_STATE_FLAG_HHD_INSPECT BIT_U32(6) -#define DE_STATE_FLAG_HRHD_INSPECT BIT_U32(7) -#define DE_STATE_FLAG_HHHD_INSPECT BIT_U32(8) -#define DE_STATE_FLAG_HRHHD_INSPECT BIT_U32(9) -#define DE_STATE_FLAG_HUAD_INSPECT BIT_U32(10) -#define DE_STATE_FLAG_HMD_INSPECT BIT_U32(11) -#define DE_STATE_FLAG_HCD_INSPECT BIT_U32(12) -#define DE_STATE_FLAG_HSMD_INSPECT BIT_U32(13) -#define DE_STATE_FLAG_HSCD_INSPECT BIT_U32(14) -#define DE_STATE_FLAG_FILE_TC_INSPECT BIT_U32(15) -#define DE_STATE_FLAG_FILE_TS_INSPECT BIT_U32(16) -#define DE_STATE_FLAG_DNSQUERYNAME_INSPECT BIT_U32(17) -#define DE_STATE_FLAG_APP_EVENT_INSPECT BIT_U32(18) -#define DE_STATE_FLAG_MODBUS_INSPECT BIT_U32(19) -#define DE_STATE_FLAG_HTTP_REQLINE_INSPECT BIT_U32(20) -#define DE_STATE_FLAG_FD_SMTP_INSPECT BIT_U32(21) -#define DE_STATE_FLAG_DNSREQUEST_INSPECT BIT_U32(22) -#define DE_STATE_FLAG_DNSRESPONSE_INSPECT BIT_U32(23) -#define DE_STATE_FLAG_TLSSNI_INSPECT BIT_U32(24) -#define DE_STATE_FLAG_TLSISSUER_INSPECT BIT_U32(25) -#define DE_STATE_FLAG_TLSSUBJECT_INSPECT BIT_U32(26) -#define DE_STATE_FLAG_TLSVALIDITY_INSPECT BIT_U32(27) -#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(28) -#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT BIT_U32(29) -#define DE_STATE_FLAG_HTTP_RESLINE_INSPECT BIT_U32(30) +#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(2) +#define DE_STATE_FLAG_FILE_TC_INSPECT BIT_U32(3) +#define DE_STATE_FLAG_FILE_TS_INSPECT BIT_U32(4) + +/* first bit position after the built-ins */ +#define DE_STATE_FLAG_BASE 5UL /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine.c b/src/detect-engine.c index 6a2215569021..b2e21658441c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -118,48 +118,11 @@ static void TenantIdFree(void *d); static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p); static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p); -/* 2 - for each direction */ -DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; - -#if 0 - -static void DetectEnginePrintAppInspectionEngines(DetectEngineAppInspectionEngine *list[][ALPROTO_MAX][2]) -{ - printf("\n"); - - AppProto alproto = ALPROTO_UNKNOWN + 1; - for ( ; alproto < ALPROTO_MAX; alproto++) { - printf("alproto - %d\n", alproto); - int dir = 0; - for ( ; dir < 2; dir++) { - printf(" direction - %d\n", dir); - DetectEngineAppInspectionEngine *engine = list[alproto][dir]; - while (engine != NULL) { - printf(" engine->alproto - %"PRIu16"\n", engine->alproto); - printf(" engine->dir - %"PRIu16"\n", engine->dir); - printf(" engine->sm_list - %d\n", engine->sm_list); - printf(" engine->inspect_flags - %"PRIu32"\n", engine->inspect_flags); - printf(" engine->match_flags - %"PRIu32"\n", engine->match_flags); - printf("\n"); - - engine = engine->next; - } - } /* for ( ; dir < 2; dir++) */ - } /* for ( ; alproto < ALPROTO_MAX; alproto++) */ - - return; -} - -#endif - void DetectEngineRegisterAppInspectionEngines(void) { struct tmp_t { - uint8_t ipproto; AppProto alproto; int32_t sm_list; - uint32_t inspect_flags; - uint16_t dir; int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -170,317 +133,150 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toserver[] = { - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, - 0, DetectEngineInspectPacketUris }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HTTP_REQLINEMATCH, - DE_STATE_FLAG_HTTP_REQLINE_INSPECT, - 0, DetectEngineInspectHttpRequestLine }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HCBDMATCH, - DE_STATE_FLAG_HCBD_INSPECT, - 0, DetectEngineInspectHttpClientBody }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HHDMATCH, - DE_STATE_FLAG_HHD_INSPECT, - 0, DetectEngineInspectHttpHeader }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HRHDMATCH, - DE_STATE_FLAG_HRHD_INSPECT, - 0, DetectEngineInspectHttpRawHeader }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HMDMATCH, - DE_STATE_FLAG_HMD_INSPECT, - 0, DetectEngineInspectHttpMethod }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HCDMATCH, - DE_STATE_FLAG_HCD_INSPECT, - 0, DetectEngineInspectHttpCookie }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HRUDMATCH, - DE_STATE_FLAG_HRUD_INSPECT, - 0, DetectEngineInspectHttpRawUri }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TS_INSPECT, - 0, DetectFileInspectHttp }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HUADMATCH, - DE_STATE_FLAG_HUAD_INSPECT, - 0, DetectEngineInspectHttpUA }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HHHDMATCH, - DE_STATE_FLAG_HHHD_INSPECT, - 0, DetectEngineInspectHttpHH }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HRHHDMATCH, - DE_STATE_FLAG_HRHHD_INSPECT, - 0, DetectEngineInspectHttpHRH }, /* DNS */ - { IPPROTO_TCP, - ALPROTO_DNS, - DETECT_SM_LIST_DNSQUERYNAME_MATCH, - DE_STATE_FLAG_DNSQUERYNAME_INSPECT, - 0, - DetectEngineInspectDnsQueryName }, - /* specifically for UDP, register again - * allows us to use the alproto w/o translation - * in the detection engine */ - { IPPROTO_UDP, - ALPROTO_DNS, + { ALPROTO_DNS, DETECT_SM_LIST_DNSQUERYNAME_MATCH, - DE_STATE_FLAG_DNSQUERYNAME_INSPECT, - 0, DetectEngineInspectDnsQueryName }, - { IPPROTO_TCP, - ALPROTO_DNS, + { ALPROTO_DNS, DETECT_SM_LIST_DNSREQUEST_MATCH, - DE_STATE_FLAG_DNSREQUEST_INSPECT, - 0, - DetectEngineInspectDnsRequest }, - /* specifically for UDP, register again - * allows us to use the alproto w/o translation - * in the detection engine */ - { IPPROTO_UDP, - ALPROTO_DNS, - DETECT_SM_LIST_DNSREQUEST_MATCH, - DE_STATE_FLAG_DNSREQUEST_INSPECT, - 0, DetectEngineInspectDnsRequest }, /* TLS */ - { IPPROTO_TCP, - ALPROTO_TLS, + { ALPROTO_TLS, DETECT_SM_LIST_TLSSNI_MATCH, - DE_STATE_FLAG_TLSSNI_INSPECT, - 0, DetectEngineInspectTlsSni }, /* SMTP */ - { IPPROTO_TCP, - ALPROTO_SMTP, + { ALPROTO_SMTP, DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TS_INSPECT, - 0, DetectFileInspectSmtp }, /* Modbus */ - { IPPROTO_TCP, - ALPROTO_MODBUS, + { ALPROTO_MODBUS, DETECT_SM_LIST_MODBUS_MATCH, - DE_STATE_FLAG_MODBUS_INSPECT, - 0, DetectEngineInspectModbus }, /* file_data smtp */ - { IPPROTO_TCP, - ALPROTO_SMTP, + { ALPROTO_SMTP, DETECT_SM_LIST_FILEDATA, - DE_STATE_FLAG_FD_SMTP_INSPECT, - 0, DetectEngineInspectSMTPFiledata }, /* Template. */ - { IPPROTO_TCP, - ALPROTO_TEMPLATE, + { ALPROTO_TEMPLATE, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, - DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT, - 0, DetectEngineInspectTemplateBuffer }, }; struct tmp_t data_toclient[] = { - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_FILEDATA, - DE_STATE_FLAG_HSBD_INSPECT, - 1, DetectEngineInspectHttpServerBody }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HHDMATCH, - DE_STATE_FLAG_HHD_INSPECT, - 1, DetectEngineInspectHttpHeader }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HRHDMATCH, - DE_STATE_FLAG_HRHD_INSPECT, - 1, DetectEngineInspectHttpRawHeader }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HCDMATCH, - DE_STATE_FLAG_HCD_INSPECT, - 1, DetectEngineInspectHttpCookie }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TC_INSPECT, - 1, DetectFileInspectHttp }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HSMDMATCH, - DE_STATE_FLAG_HSMD_INSPECT, - 1, DetectEngineInspectHttpStatMsg }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HSCDMATCH, - DE_STATE_FLAG_HSCD_INSPECT, - 1, DetectEngineInspectHttpStatCode }, - { IPPROTO_TCP, - ALPROTO_HTTP, + { ALPROTO_HTTP, DETECT_SM_LIST_HTTP_RESLINEMATCH, - DE_STATE_FLAG_HTTP_RESLINE_INSPECT, - 1, DetectEngineInspectHttpResponseLine }, /* Modbus */ - { IPPROTO_TCP, - ALPROTO_MODBUS, + { ALPROTO_MODBUS, DETECT_SM_LIST_MODBUS_MATCH, - DE_STATE_FLAG_MODBUS_INSPECT, - 0, DetectEngineInspectModbus }, - { IPPROTO_TCP, - ALPROTO_DNS, + { ALPROTO_DNS, DETECT_SM_LIST_DNSRESPONSE_MATCH, - DE_STATE_FLAG_DNSRESPONSE_INSPECT, - 1, DetectEngineInspectDnsResponse }, /* TLS */ - { IPPROTO_TCP, - ALPROTO_TLS, + { ALPROTO_TLS, DETECT_SM_LIST_TLSISSUER_MATCH, - DE_STATE_FLAG_TLSISSUER_INSPECT, - 1, DetectEngineInspectTlsIssuer }, - { IPPROTO_TCP, - ALPROTO_TLS, + { ALPROTO_TLS, DETECT_SM_LIST_TLSSUBJECT_MATCH, - DE_STATE_FLAG_TLSSUBJECT_INSPECT, - 1, DetectEngineInspectTlsSubject }, - { IPPROTO_TCP, - ALPROTO_TLS, + { ALPROTO_TLS, DETECT_SM_LIST_TLSVALIDITY_MATCH, - DE_STATE_FLAG_TLSVALIDITY_INSPECT, - 1, DetectEngineInspectTlsValidity }, - /* specifically for UDP, register again - * allows us to use the alproto w/o translation - * in the detection engine */ - { IPPROTO_UDP, - ALPROTO_DNS, - DETECT_SM_LIST_DNSRESPONSE_MATCH, - DE_STATE_FLAG_DNSRESPONSE_INSPECT, - 1, - DetectEngineInspectDnsResponse }, /* Template. */ - { IPPROTO_TCP, - ALPROTO_TEMPLATE, + { ALPROTO_TEMPLATE, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, - DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT, - 1, DetectEngineInspectTemplateBuffer }, }; size_t i; for (i = 0 ; i < sizeof(data_toserver) / sizeof(struct tmp_t); i++) { - DetectEngineRegisterAppInspectionEngine(data_toserver[i].ipproto, - data_toserver[i].alproto, - data_toserver[i].dir, + DetectEngineRegisterAppInspectionEngine(data_toserver[i].alproto, + 0, data_toserver[i].sm_list, - data_toserver[i].inspect_flags, - data_toserver[i].Callback, - app_inspection_engine); + data_toserver[i].Callback); } for (i = 0 ; i < sizeof(data_toclient) / sizeof(struct tmp_t); i++) { - DetectEngineRegisterAppInspectionEngine(data_toclient[i].ipproto, - data_toclient[i].alproto, - data_toclient[i].dir, + DetectEngineRegisterAppInspectionEngine(data_toclient[i].alproto, + 1, data_toclient[i].sm_list, - data_toclient[i].inspect_flags, - data_toclient[i].Callback, - app_inspection_engine); + data_toclient[i].Callback); } -#if 0 - DetectEnginePrintAppInspectionEngines(app_inspection_engine); -#endif - return; } -static void AppendAppInspectionEngine(DetectEngineAppInspectionEngine *engine, - DetectEngineAppInspectionEngine *list[][ALPROTO_MAX][2]) -{ - /* append to the list */ - DetectEngineAppInspectionEngine *tmp = list[FlowGetProtoMapping(engine->ipproto)][engine->alproto][engine->dir]; - DetectEngineAppInspectionEngine *insert = NULL; - while (tmp != NULL) { - if (tmp->dir == engine->dir && - (tmp->sm_list == engine->sm_list || - tmp->inspect_flags == engine->inspect_flags - )) { - SCLogError(SC_ERR_DETECT_PREPARE, "App Inspection Engine already " - "registered for this direction(%"PRIu16") ||" - "sm_list(%d) || " - "[inspect(%"PRIu32")]_flags", - tmp->dir, tmp->sm_list, tmp->inspect_flags); - exit(EXIT_FAILURE); - } - insert = tmp; - tmp = tmp->next; - } - if (insert == NULL) - list[FlowGetProtoMapping(engine->ipproto)][engine->alproto][engine->dir] = engine; - else - insert->next = engine; +static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL; - return; -} - -void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, - AppProto alproto, +void DetectEngineRegisterAppInspectionEngine(AppProto alproto, uint16_t dir, int32_t sm_list, - uint32_t inspect_flags, int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *sig, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id), - DetectEngineAppInspectionEngine *list[][ALPROTO_MAX][2]) + void *tx, uint64_t tx_id)) { - if ((list == NULL) || - (alproto <= ALPROTO_UNKNOWN || alproto >= ALPROTO_FAILED) || + if ((alproto <= ALPROTO_UNKNOWN || alproto >= ALPROTO_FAILED) || (dir > 1) || (sm_list < DETECT_SM_LIST_MATCH || sm_list >= DETECT_SM_LIST_MAX) || (Callback == NULL)) @@ -489,31 +285,76 @@ void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, exit(EXIT_FAILURE); } - DetectEngineAppInspectionEngine *tmp = list[FlowGetProtoMapping(ipproto)][alproto][dir]; - while (tmp != NULL) { - if (tmp->sm_list == sm_list && tmp->Callback == Callback) { - return; - } - tmp = tmp->next; - } - DetectEngineAppInspectionEngine *new_engine = SCMalloc(sizeof(DetectEngineAppInspectionEngine)); if (unlikely(new_engine == NULL)) { exit(EXIT_FAILURE); } memset(new_engine, 0, sizeof(*new_engine)); - new_engine->ipproto = ipproto; new_engine->alproto = alproto; new_engine->dir = dir; new_engine->sm_list = sm_list; - new_engine->inspect_flags = inspect_flags; new_engine->Callback = Callback; - AppendAppInspectionEngine(new_engine, list); + if (g_app_inspect_engines == NULL) { + g_app_inspect_engines = new_engine; + } else { + DetectEngineAppInspectionEngine *t = g_app_inspect_engines; + while (t->next != NULL) { + t = t->next; + } + t->next = new_engine; + } return; } +int DetectEngineAppInspectionEngine2Signature(Signature *s) +{ + DetectEngineAppInspectionEngine *t = g_app_inspect_engines; + while (t != NULL) { + if (s->sm_lists[t->sm_list] == NULL) + goto next; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != t->alproto) + goto next; + + if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) { + if (t->dir == 1) + goto next; + } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) { + if (t->dir == 0) + goto next; + } + + DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine)); + if (unlikely(new_engine == NULL)) { + exit(EXIT_FAILURE); + } + new_engine->alproto = t->alproto; + new_engine->dir = t->dir; + new_engine->sm_list = t->sm_list; + new_engine->Callback = t->Callback; + + if (s->app_inspect == NULL) { + s->app_inspect = new_engine; + new_engine->inspect_flags = BIT_U32(DE_STATE_FLAG_BASE); // start beyond the built-ins + } else { + DetectEngineAppInspectionEngine *t = s->app_inspect; + while (t->next != NULL) { + t = t->next; + } + + t->next = new_engine; + new_engine->id = t->id + 1; + new_engine->inspect_flags = BIT_U32(new_engine->id + DE_STATE_FLAG_BASE); + } + SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id); +next: + t = t->next; + } + + return 0; +} + /* code to control the main thread to do a reload */ enum DetectEngineSyncState { @@ -3044,300 +2885,6 @@ static int DetectEngineTest04(void) return result; } -int DummyTestAppInspectionEngine01(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, - Flow *f, - uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) -{ - return 0; -} - -int DummyTestAppInspectionEngine02(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, - Flow *f, - uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) -{ - return 0; -} - -int DetectEngineTest05(void) -{ - int result = 0; - int ip = 0; - - DetectEngineAppInspectionEngine *engine_list[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; - memset(engine_list, 0, sizeof(engine_list)); - - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - ALPROTO_HTTP, - 0 /* STREAM_TOSERVER */, - DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, - DummyTestAppInspectionEngine01, - engine_list); - - int alproto = ALPROTO_UNKNOWN + 1; - for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) { - for ( ; alproto < ALPROTO_FAILED; alproto++) { - int dir = 0; - for ( ; dir < 2; dir++) { - if (alproto == ALPROTO_HTTP && dir == 0) { - if (engine_list[ip][alproto][dir]->next != NULL) { - printf("more than one entry found\n"); - goto end; - } - - DetectEngineAppInspectionEngine *engine = engine_list[ip][alproto][dir]; - - if (engine->alproto != alproto || - engine->dir != dir || - engine->sm_list != DETECT_SM_LIST_UMATCH || - engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || - engine->Callback != DummyTestAppInspectionEngine01) { - printf("failed for http and dir(0-toserver)\n"); - goto end; - } - } /* if (alproto == ALPROTO_HTTP && dir == 0) */ - - if (alproto == ALPROTO_HTTP && dir == 1) { - if (engine_list[ip][alproto][dir] != NULL) { - printf("failed for http and dir(1-toclient)\n"); - goto end; - } - } - - if (alproto != ALPROTO_HTTP && - engine_list[ip][alproto][0] != NULL && - engine_list[ip][alproto][1] != NULL) { - printf("failed for protocol %d\n", alproto); - goto end; - } - } /* for ( ; dir < 2 ..)*/ - } /* for ( ; alproto < ALPROTO_FAILED; ..) */ - } - - result = 1; - end: - return result; -} - -int DetectEngineTest06(void) -{ - int result = 0; - int ip = 0; - - DetectEngineAppInspectionEngine *engine_list[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; - memset(engine_list, 0, sizeof(engine_list)); - - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - ALPROTO_HTTP, - 0 /* STREAM_TOSERVER */, - DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, - DummyTestAppInspectionEngine01, - engine_list); - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - ALPROTO_HTTP, - 1 /* STREAM_TOCLIENT */, - DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, - DummyTestAppInspectionEngine02, - engine_list); - - int alproto = ALPROTO_UNKNOWN + 1; - for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) { - for ( ; alproto < ALPROTO_FAILED; alproto++) { - int dir = 0; - for ( ; dir < 2; dir++) { - if (alproto == ALPROTO_HTTP && dir == 0) { - if (engine_list[ip][alproto][dir]->next != NULL) { - printf("more than one entry found\n"); - goto end; - } - - DetectEngineAppInspectionEngine *engine = engine_list[ip][alproto][dir]; - - if (engine->alproto != alproto || - engine->dir != dir || - engine->sm_list != DETECT_SM_LIST_UMATCH || - engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || - engine->Callback != DummyTestAppInspectionEngine01) { - printf("failed for http and dir(0-toserver)\n"); - goto end; - } - } /* if (alproto == ALPROTO_HTTP && dir == 0) */ - - if (alproto == ALPROTO_HTTP && dir == 1) { - if (engine_list[ip][alproto][dir]->next != NULL) { - printf("more than one entry found\n"); - goto end; - } - - DetectEngineAppInspectionEngine *engine = engine_list[ip][alproto][dir]; - - if (engine->alproto != alproto || - engine->dir != dir || - engine->sm_list != DETECT_SM_LIST_UMATCH || - engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || - engine->Callback != DummyTestAppInspectionEngine02) { - printf("failed for http and dir(0-toclient)\n"); - goto end; - } - } /* if (alproto == ALPROTO_HTTP && dir == 1) */ - - if (alproto != ALPROTO_HTTP && - engine_list[ip][alproto][0] != NULL && - engine_list[ip][alproto][1] != NULL) { - printf("failed for protocol %d\n", alproto); - goto end; - } - } /* for ( ; dir < 2 ..)*/ - } /* for ( ; alproto < ALPROTO_FAILED; ..) */ - } - - result = 1; - end: - return result; -} - -int DetectEngineTest07(void) -{ - int result = 0; - int ip = 0; - - DetectEngineAppInspectionEngine *engine_list[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; - memset(engine_list, 0, sizeof(engine_list)); - - struct test_data_t { - int32_t sm_list; - uint32_t inspect_flags; - uint16_t dir; - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); - - }; - - struct test_data_t data[] = { - { DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HCBDMATCH, - DE_STATE_FLAG_HCBD_INSPECT, - 0, - DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_FILEDATA, - DE_STATE_FLAG_HSBD_INSPECT, - 1, - DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_HHDMATCH, - DE_STATE_FLAG_HHD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HRHDMATCH, - DE_STATE_FLAG_HRHD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HMDMATCH, - DE_STATE_FLAG_HMD_INSPECT, - 0, - DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_HCDMATCH, - DE_STATE_FLAG_HCD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HRUDMATCH, - DE_STATE_FLAG_HRUD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TS_INSPECT, - 0, - DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TC_INSPECT, - 1, - DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_HSMDMATCH, - DE_STATE_FLAG_HSMD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HSCDMATCH, - DE_STATE_FLAG_HSCD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HUADMATCH, - DE_STATE_FLAG_HUAD_INSPECT, - 0, - DummyTestAppInspectionEngine02 }, - }; - - size_t i = 0; - for ( ; i < sizeof(data) / sizeof(struct test_data_t); i++) { - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - ALPROTO_HTTP, - data[i].dir /* STREAM_TOCLIENT */, - data[i].sm_list, - data[i].inspect_flags, - data[i].Callback, - engine_list); - } - -#if 0 - DetectEnginePrintAppInspectionEngines(engine_list); -#endif - - int alproto = ALPROTO_UNKNOWN + 1; - for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) { - for ( ; alproto < ALPROTO_FAILED; alproto++) { - int dir = 0; - for ( ; dir < 2; dir++) { - if (alproto == ALPROTO_HTTP) { - DetectEngineAppInspectionEngine *engine = engine_list[ip][alproto][dir]; - - size_t i = 0; - for ( ; i < (sizeof(data) / sizeof(struct test_data_t)); i++) { - if (data[i].dir != dir) - continue; - - if (engine->alproto != ALPROTO_HTTP || - engine->dir != data[i].dir || - engine->sm_list != data[i].sm_list || - engine->inspect_flags != data[i].inspect_flags || - engine->Callback != data[i].Callback) { - printf("failed for http\n"); - goto end; - } - engine = engine->next; - } - } else { - if (engine_list[ip][alproto][0] != NULL && - engine_list[ip][alproto][1] != NULL) { - printf("failed for protocol %d\n", alproto); - goto end; - } - } /* else */ - } /* for ( ; dir < 2; dir++) */ - } /* for ( ; alproto < ALPROTO_FAILED; ..) */ - } - - result = 1; - end: - return result; -} - static int DetectEngineTest08(void) { char *conf = @@ -3416,9 +2963,6 @@ void DetectEngineRegisterTests() UtRegisterTest("DetectEngineTest02", DetectEngineTest02); UtRegisterTest("DetectEngineTest03", DetectEngineTest03); UtRegisterTest("DetectEngineTest04", DetectEngineTest04); - UtRegisterTest("DetectEngineTest05", DetectEngineTest05); - UtRegisterTest("DetectEngineTest06", DetectEngineTest06); - UtRegisterTest("DetectEngineTest07", DetectEngineTest07); UtRegisterTest("DetectEngineTest08", DetectEngineTest08); UtRegisterTest("DetectEngineTest09", DetectEngineTest09); #endif diff --git a/src/detect-engine.h b/src/detect-engine.h index 3211c601d9f2..ea888cf426b3 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -28,30 +28,6 @@ #include "tm-threads.h" #include "flow-private.h" -typedef struct DetectEngineAppInspectionEngine_ { - uint8_t ipproto; - AppProto alproto; - uint16_t dir; - - int32_t sm_list; - uint32_t inspect_flags; - - /* \retval 0 No match. Don't discontinue matching yet. We need more data. - * 1 Match. - * 2 Sig can't match. - * 3 Special value used by filestore sigs to indicate disabling - * filestore for the tx. - */ - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); - - struct DetectEngineAppInspectionEngine_ *next; -} DetectEngineAppInspectionEngine; - -extern DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; - /* prototypes */ void DetectEngineRegisterAppInspectionEngines(void); DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix); @@ -111,16 +87,16 @@ int DetectEngineInspectGenericList(ThreadVars *, const DetectEngineCtx *, * the inpsect_flags. * \param Callback The engine callback. */ -void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, - AppProto alproto, - uint16_t direction, +void DetectEngineRegisterAppInspectionEngine(AppProto alproto, + uint16_t dir, int32_t sm_list, - uint32_t inspect_flags, int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *sig, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id), - DetectEngineAppInspectionEngine *list[][ALPROTO_MAX][2]); + void *tx, uint64_t tx_id)); + +int DetectEngineAppInspectionEngine2Signature(Signature *s); + #endif /* __DETECT_ENGINE_H__ */ diff --git a/src/detect-parse.c b/src/detect-parse.c index ec7e0b18c854..e3bc8b31a047 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1096,6 +1096,13 @@ void SigFree(Signature *s) SigRefFree(s); + DetectEngineAppInspectionEngine *ie = s->app_inspect; + while (ie) { + DetectEngineAppInspectionEngine *next = ie->next; + SCFree(ie); + ie = next; + } + SCFree(s); } @@ -1636,44 +1643,20 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, SigBuildAddressMatchArray(sig); if (sig->sm_lists[DETECT_SM_LIST_APP_EVENT] != NULL) { - if (AppLayerParserProtocolIsTxEventAware(IPPROTO_TCP, sig->alproto)) { - if (sig->flags & SIG_FLAG_TOSERVER) { - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - sig->alproto, - 0, - DETECT_SM_LIST_APP_EVENT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DetectEngineAptEventInspect, - app_inspection_engine); - } - if (sig->flags & SIG_FLAG_TOCLIENT) { - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - sig->alproto, - 1, - DETECT_SM_LIST_APP_EVENT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DetectEngineAptEventInspect, - app_inspection_engine); - } - } - if (AppLayerParserProtocolIsTxEventAware(IPPROTO_UDP, sig->alproto)) { + if (AppLayerParserProtocolIsTxEventAware(IPPROTO_TCP, sig->alproto) || + AppLayerParserProtocolIsTxEventAware(IPPROTO_UDP, sig->alproto)) + { if (sig->flags & SIG_FLAG_TOSERVER) { - DetectEngineRegisterAppInspectionEngine(IPPROTO_UDP, - sig->alproto, + DetectEngineRegisterAppInspectionEngine(sig->alproto, 0, DETECT_SM_LIST_APP_EVENT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DetectEngineAptEventInspect, - app_inspection_engine); + DetectEngineAptEventInspect); } if (sig->flags & SIG_FLAG_TOCLIENT) { - DetectEngineRegisterAppInspectionEngine(IPPROTO_UDP, - sig->alproto, + DetectEngineRegisterAppInspectionEngine(sig->alproto, 1, DETECT_SM_LIST_APP_EVENT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DetectEngineAptEventInspect, - app_inspection_engine); + DetectEngineAptEventInspect); } } } diff --git a/src/detect.c b/src/detect.c index c80daf800bc1..d87c9f9a6877 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3891,8 +3891,10 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) } } } + DetectEngineAppInspectionEngine2Signature(s); } + SCReturnInt(0); } diff --git a/src/detect.h b/src/detect.h index c181c90a0168..222bc7620adf 100644 --- a/src/detect.h +++ b/src/detect.h @@ -364,6 +364,29 @@ typedef struct SigMatchData_ { SigMatchCtx *ctx; /**< plugin specific data */ } SigMatchData; +struct DetectEngineThreadCtx_;// DetectEngineThreadCtx; + +typedef struct DetectEngineAppInspectionEngine_ { + AppProto alproto; + uint8_t dir; + uint8_t id; + int sm_list; + uint32_t inspect_flags; + + /* \retval 0 No match. Don't discontinue matching yet. We need more data. + * 1 Match. + * 2 Sig can't match. + * 3 Special value used by filestore sigs to indicate disabling + * filestore for the tx. + */ + int (*Callback)(ThreadVars *tv, + struct DetectEngineCtx_ *de_ctx, struct DetectEngineThreadCtx_ *det_ctx, + struct Signature_ *sig, Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id); + + struct DetectEngineAppInspectionEngine_ *next; +} DetectEngineAppInspectionEngine; + /** \brief Signature container */ typedef struct Signature_ { @@ -420,6 +443,8 @@ typedef struct Signature_ { /** netblocks and hosts specified at the sid, in CIDR format */ IPOnlyCIDRItem *CidrSrc, *CidrDst; + DetectEngineAppInspectionEngine *app_inspect; + /* Hold copies of the sm lists for Match() */ SigMatchData *sm_arrays[DETECT_SM_LIST_MAX]; From ad3c97f47077adee0a7cf2adcb9404e32e138f05 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Sep 2016 22:50:13 +0200 Subject: [PATCH 1966/2553] detect-mpm: cleanup --- src/detect-engine-mpm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index c1ee337d6efb..a38d415ec41d 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -458,10 +458,10 @@ uint32_t PatternStrength(uint8_t *pat, uint16_t patlen) return s; } -static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, - const DetectContentData *cd, - const Signature *s, uint8_t flags, - int chop) +static void PopulateMpmHelperAddPattern(MpmCtx *mpm_ctx, + const DetectContentData *cd, + const Signature *s, uint8_t flags, + int chop) { uint16_t pat_offset = cd->offset; uint16_t pat_depth = cd->depth; @@ -948,7 +948,7 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) } if (!skip) { - PopulateMpmHelperAddPatternToPktCtx(ms->mpm_ctx, + PopulateMpmHelperAddPattern(ms->mpm_ctx, cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); } } From 9a0bbd623997305b505a59ca9bf3a18fa19e9d91 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 09:09:11 +0200 Subject: [PATCH 1967/2553] detect mpm: small optimization --- src/detect-engine-mpm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index a38d415ec41d..fee6ec7031b8 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -550,7 +550,10 @@ void RetrieveFPForSig(Signature *s) /* inspect rule to see if we have the fast_pattern reg to * force using a sig, otherwise keep stats about the patterns */ - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { + for (list_id = 0; list_id < DETECT_SM_LIST_DETECT_MAX; list_id++) { + if (s->sm_lists[list_id] == NULL) + continue; + if (!FastPatternSupportEnabledForSigMatchList(list_id)) continue; @@ -588,7 +591,7 @@ void RetrieveFPForSig(Signature *s) return; } - int final_sm_list[DETECT_SM_LIST_MAX]; + int final_sm_list[DETECT_SM_LIST_DETECT_MAX] = { 0 }; int count_final_sm_list = 0; int priority; From 5bde86b0e865bea1acf7e5be6121cb5db877369a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:00:29 +0200 Subject: [PATCH 1968/2553] detect-engine: new registration call Make it more in line with MPM registration. --- src/detect-engine.c | 21 +++++++++++++++++++++ src/detect-engine.h | 9 +++++++++ 2 files changed, 30 insertions(+) diff --git a/src/detect-engine.c b/src/detect-engine.c index b2e21658441c..5bbaafc555f5 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -308,6 +308,27 @@ void DetectEngineRegisterAppInspectionEngine(AppProto alproto, return; } +void DetectAppLayerInspectEngineRegister(AppProto alproto, + uint32_t dir, int32_t sm_list, + int (*Callback)(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *sig, Flow *f, + uint8_t flags, void *alstate, + void *tx, uint64_t tx_id)) +{ + BUG_ON(!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)); + + int direction; + if (dir == SIG_FLAG_TOSERVER) { + direction = 0; + } else { + direction = 1; + } + + DetectEngineRegisterAppInspectionEngine(alproto, direction, sm_list, Callback); +} + int DetectEngineAppInspectionEngine2Signature(Signature *s) { DetectEngineAppInspectionEngine *t = g_app_inspect_engines; diff --git a/src/detect-engine.h b/src/detect-engine.h index ea888cf426b3..4eb48a353e5c 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -96,6 +96,15 @@ void DetectEngineRegisterAppInspectionEngine(AppProto alproto, Signature *sig, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id)); +void DetectAppLayerInspectEngineRegister(AppProto alproto, + uint32_t dir, + int32_t sm_list, + int (*Callback)(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *sig, Flow *f, + uint8_t flags, void *alstate, + void *tx, uint64_t tx_id)); int DetectEngineAppInspectionEngine2Signature(Signature *s); From 0feeb8d538c0c4515db48d787d2dd2ae18bb3acd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:02:39 +0200 Subject: [PATCH 1969/2553] http_request_line: register inspect engine from keyword --- src/detect-engine.c | 4 ---- src/detect-http-request-line.c | 13 +++++++++++-- src/detect-http-request-line.h | 6 ------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 5bbaafc555f5..f6744b0ab4ae 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -72,7 +72,6 @@ #include "detect-uricontent.h" #include "detect-engine-threshold.h" -#include "detect-http-request-line.h" #include "detect-http-response-line.h" #include "detect-engine-loader.h" @@ -136,9 +135,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_UMATCH, DetectEngineInspectPacketUris }, - { ALPROTO_HTTP, - DETECT_SM_LIST_HTTP_REQLINEMATCH, - DetectEngineInspectHttpRequestLine }, { ALPROTO_HTTP, DETECT_SM_LIST_HCBDMATCH, DetectEngineInspectHttpClientBody }, diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 0c43d9ae4bbe..9a27ee6fdb55 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -64,7 +64,12 @@ int DetectHttpRequestLineSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpRequestLineRegisterTests(void); void DetectHttpRequestLineFree(void *); static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); - +static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *txv, uint64_t tx_id); /** * \brief Registers the keyword handlers for the "http_request_line" keyword. */ @@ -85,6 +90,10 @@ void DetectHttpRequestLineRegister(void) DETECT_SM_LIST_HTTP_REQLINEMATCH, 2, PrefilterTxHttpRequestLineRegister); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HTTP_REQLINEMATCH, + DetectEngineInspectHttpRequestLine); + return; } @@ -162,7 +171,7 @@ static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx * \retval 1 match. * \retval 2 Sig can't match. */ -int DetectEngineInspectHttpRequestLine(ThreadVars *tv, +static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, diff --git a/src/detect-http-request-line.h b/src/detect-http-request-line.h index 0c47f5fa5e69..64751b7ee32e 100644 --- a/src/detect-http-request-line.h +++ b/src/detect-http-request-line.h @@ -24,12 +24,6 @@ #ifndef __DETECT_HTTP_REQUEST_LINE_H__ #define __DETECT_HTTP_REQUEST_LINE_H__ -int DetectEngineInspectHttpRequestLine(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id); void DetectHttpRequestLineRegister(void); #endif /* __DETECT_HTTP_REQUEST_LINE_H__ */ From cc96fedb90eac286144f7efa6b3a2662d66d8301 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:06:43 +0200 Subject: [PATCH 1970/2553] http_response_line: register inspect engine from keyword --- src/detect-engine.c | 5 ----- src/detect-http-response-line.c | 11 +++++++++++ src/detect-http-response-line.h | 6 ------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index f6744b0ab4ae..b42bd16cf6f8 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -72,8 +72,6 @@ #include "detect-uricontent.h" #include "detect-engine-threshold.h" -#include "detect-http-response-line.h" - #include "detect-engine-loader.h" #include "util-classification-config.h" @@ -216,9 +214,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_HSCDMATCH, DetectEngineInspectHttpStatCode }, - { ALPROTO_HTTP, - DETECT_SM_LIST_HTTP_RESLINEMATCH, - DetectEngineInspectHttpResponseLine }, /* Modbus */ { ALPROTO_MODBUS, DETECT_SM_LIST_MODBUS_MATCH, diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index 7b4131108381..70d5de472454 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -64,6 +64,12 @@ int DetectHttpResponseLineSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpResponseLineRegisterTests(void); void DetectHttpResponseLineFree(void *); static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +static int DetectEngineInspectHttpResponseLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *txv, uint64_t tx_id); /** * \brief Registers the keyword handlers for the "http_response_line" keyword. @@ -84,6 +90,11 @@ void DetectHttpResponseLineRegister(void) DetectMpmAppLayerRegister("http_response_line", SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HTTP_RESLINEMATCH, 2, PrefilterTxHttpResponseLineRegister); + + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HTTP_RESLINEMATCH, + DetectEngineInspectHttpResponseLine); + return; } diff --git a/src/detect-http-response-line.h b/src/detect-http-response-line.h index 53e74801307c..0563feaf60b1 100644 --- a/src/detect-http-response-line.h +++ b/src/detect-http-response-line.h @@ -24,12 +24,6 @@ #ifndef __DETECT_HTTP_RESPONSE_LINE_H__ #define __DETECT_HTTP_RESPONSE_LINE_H__ -int DetectEngineInspectHttpResponseLine(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id); void DetectHttpResponseLineRegister(void); #endif /* __DETECT_HTTP_RESPONSE_LINE_H__ */ From b96c2c5db566114d2ea2bad83e96441cf0164551 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:13:03 +0200 Subject: [PATCH 1971/2553] http_uri: register inspect engine from keyword --- src/detect-engine-uri.c | 2 +- src/detect-engine-uri.h | 2 +- src/detect-engine.c | 3 --- src/detect-http-uri.c | 4 ++++ 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index caf5c10ecddb..9058afba1415 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -104,7 +104,7 @@ int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 match. * \retval 2 Sig can't match. */ -int DetectEngineInspectPacketUris(ThreadVars *tv, +int DetectEngineInspectHttpUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, diff --git a/src/detect-engine-uri.h b/src/detect-engine-uri.h index 804ba875e31d..d5ba12298da5 100644 --- a/src/detect-engine-uri.h +++ b/src/detect-engine-uri.h @@ -26,7 +26,7 @@ int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); -int DetectEngineInspectPacketUris(ThreadVars *tv, +int DetectEngineInspectHttpUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, diff --git a/src/detect-engine.c b/src/detect-engine.c index b42bd16cf6f8..e5dc9eacb735 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -130,9 +130,6 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toserver[] = { - { ALPROTO_HTTP, - DETECT_SM_LIST_UMATCH, - DetectEngineInspectPacketUris }, { ALPROTO_HTTP, DETECT_SM_LIST_HCBDMATCH, DetectEngineInspectHttpClientBody }, diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 113bde124613..7c45260cec6e 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -79,6 +79,10 @@ void DetectHttpUriRegister (void) DetectMpmAppLayerRegister("http_uri", SIG_FLAG_TOSERVER, DETECT_SM_LIST_UMATCH, 2, PrefilterTxUriRegister); + + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_UMATCH, + DetectEngineInspectHttpUri); } From 4096f76b1be228e9a1c8f6d94565aa84cbb9ff6a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:19:05 +0200 Subject: [PATCH 1972/2553] http_client_body: register inspect engine from keyword --- src/detect-engine.c | 4 ---- src/detect-http-client-body.c | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index e5dc9eacb735..8992238dbeb5 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -41,7 +41,6 @@ #include "detect-engine-address.h" #include "detect-engine-port.h" #include "detect-engine-mpm.h" -#include "detect-engine-hcbd.h" #include "detect-engine-iponly.h" #include "detect-engine-tag.h" @@ -130,9 +129,6 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toserver[] = { - { ALPROTO_HTTP, - DETECT_SM_LIST_HCBDMATCH, - DetectEngineInspectHttpClientBody }, { ALPROTO_HTTP, DETECT_SM_LIST_HHDMATCH, DetectEngineInspectHttpHeader }, diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 4437fafb2787..8d3afd3548b2 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -83,6 +83,9 @@ void DetectHttpClientBodyRegister(void) DETECT_SM_LIST_HCBDMATCH, 2, PrefilterTxHttpRequestBodyRegister); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HCBDMATCH, + DetectEngineInspectHttpClientBody); } static void DetectHttpClientBodySetupCallback(Signature *s) From eb19eb3fe4f761ee876aff0b9a58a70844e73d17 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:22:20 +0200 Subject: [PATCH 1973/2553] http_header: register inspect engine from keyword --- src/detect-engine.c | 7 ------- src/detect-http-header.c | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 8992238dbeb5..8c83ae1977a0 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -46,7 +46,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hsbd.h" -#include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" @@ -129,9 +128,6 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toserver[] = { - { ALPROTO_HTTP, - DETECT_SM_LIST_HHDMATCH, - DetectEngineInspectHttpHeader }, { ALPROTO_HTTP, DETECT_SM_LIST_HRHDMATCH, DetectEngineInspectHttpRawHeader }, @@ -189,9 +185,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_FILEDATA, DetectEngineInspectHttpServerBody }, - { ALPROTO_HTTP, - DETECT_SM_LIST_HHDMATCH, - DetectEngineInspectHttpHeader }, { ALPROTO_HTTP, DETECT_SM_LIST_HRHDMATCH, DetectEngineInspectHttpRawHeader }, diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 291be548991e..8ff357a3701c 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -88,6 +88,13 @@ void DetectHttpHeaderRegister(void) DETECT_SM_LIST_HHDMATCH, 2, PrefilterTxHttpResponseHeadersRegister); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HHDMATCH, + DetectEngineInspectHttpHeader); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HHDMATCH, + DetectEngineInspectHttpHeader); + return; } From b3148296142942d6ebed789d819c9010abce8b1e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:27:57 +0200 Subject: [PATCH 1974/2553] http_raw_header: register inspect engine from keyword --- src/detect-engine.c | 6 ------ src/detect-http-raw-header.c | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 8c83ae1977a0..2f90f1deb4b9 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -128,9 +128,6 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toserver[] = { - { ALPROTO_HTTP, - DETECT_SM_LIST_HRHDMATCH, - DetectEngineInspectHttpRawHeader }, { ALPROTO_HTTP, DETECT_SM_LIST_HMDMATCH, DetectEngineInspectHttpMethod }, @@ -185,9 +182,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_FILEDATA, DetectEngineInspectHttpServerBody }, - { ALPROTO_HTTP, - DETECT_SM_LIST_HRHDMATCH, - DetectEngineInspectHttpRawHeader }, { ALPROTO_HTTP, DETECT_SM_LIST_HCDMATCH, DetectEngineInspectHttpCookie }, diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index 8729d26e7dda..6f5c6ada7e22 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -86,6 +86,12 @@ void DetectHttpRawHeaderRegister(void) DETECT_SM_LIST_HRHDMATCH, 2, PrefilterTxResponseHeadersRawRegister); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HRHDMATCH, + DetectEngineInspectHttpRawHeader); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HRHDMATCH, + DetectEngineInspectHttpRawHeader); return; } From cd8b1b0b4c448810a59dc2917352f765249e9ce0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:33:20 +0200 Subject: [PATCH 1975/2553] http_method: register inspect engine from keyword --- src/detect-engine.c | 4 ---- src/detect-http-method.c | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 2f90f1deb4b9..17c713e63e8d 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -47,7 +47,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hsbd.h" #include "detect-engine-hrhd.h" -#include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" @@ -128,9 +127,6 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toserver[] = { - { ALPROTO_HTTP, - DETECT_SM_LIST_HMDMATCH, - DetectEngineInspectHttpMethod }, { ALPROTO_HTTP, DETECT_SM_LIST_HCDMATCH, DetectEngineInspectHttpCookie }, diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 5fa9e30c99d6..07d448d0f095 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -85,6 +85,10 @@ void DetectHttpMethodRegister(void) DETECT_SM_LIST_HMDMATCH, 4, PrefilterTxMethodRegister); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HMDMATCH, + DetectEngineInspectHttpMethod); + SCLogDebug("registering http_method rule option"); } From b1adea6eee3a99a5eb1acb8e37a436a0825d007d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:35:59 +0200 Subject: [PATCH 1976/2553] http_cookie: register inspect engine from keyword --- src/detect-engine.c | 7 ------- src/detect-http-cookie.c | 6 ++++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 17c713e63e8d..463942087780 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -47,7 +47,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hsbd.h" #include "detect-engine-hrhd.h" -#include "detect-engine-hcd.h" #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" @@ -127,9 +126,6 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toserver[] = { - { ALPROTO_HTTP, - DETECT_SM_LIST_HCDMATCH, - DetectEngineInspectHttpCookie }, { ALPROTO_HTTP, DETECT_SM_LIST_HRUDMATCH, DetectEngineInspectHttpRawUri }, @@ -178,9 +174,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_FILEDATA, DetectEngineInspectHttpServerBody }, - { ALPROTO_HTTP, - DETECT_SM_LIST_HCDMATCH, - DetectEngineInspectHttpCookie }, { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectHttp }, diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index bb57e139d1a1..fe0ba43564a3 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -89,6 +89,12 @@ void DetectHttpCookieRegister(void) DETECT_SM_LIST_HCDMATCH, 2, PrefilterTxResponseCookieRegister); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HCDMATCH, + DetectEngineInspectHttpCookie); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HCDMATCH, + DetectEngineInspectHttpCookie); } /** From fc857c5455d097419adb758134486fe9eebafd8d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:39:06 +0200 Subject: [PATCH 1977/2553] http_raw_uri: register inspect engine from keyword --- src/detect-engine.c | 4 ---- src/detect-http-raw-uri.c | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 463942087780..f5876b46b9fd 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -47,7 +47,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hsbd.h" #include "detect-engine-hrhd.h" -#include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" #include "detect-engine-hua.h" @@ -126,9 +125,6 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toserver[] = { - { ALPROTO_HTTP, - DETECT_SM_LIST_HRUDMATCH, - DetectEngineInspectHttpRawUri }, { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectHttp }, diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index deb9b879e72c..5782fdf3d34d 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -78,6 +78,10 @@ void DetectHttpRawUriRegister(void) DETECT_SM_LIST_HRUDMATCH, 2, PrefilterTxRawUriRegister); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HRUDMATCH, + DetectEngineInspectHttpRawUri); + return; } From edb293699872d0180a1c447f9b84fe20d471efdf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:47:54 +0200 Subject: [PATCH 1978/2553] http_user_agent: register inspect engine from keyword --- src/detect-engine.c | 4 ---- src/detect-http-ua.c | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index f5876b46b9fd..efe0ec39e685 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -49,7 +49,6 @@ #include "detect-engine-hrhd.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" -#include "detect-engine-hua.h" #include "detect-engine-hhhd.h" #include "detect-engine-hrhhd.h" #include "detect-engine-file.h" @@ -128,9 +127,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectHttp }, - { ALPROTO_HTTP, - DETECT_SM_LIST_HUADMATCH, - DetectEngineInspectHttpUA }, { ALPROTO_HTTP, DETECT_SM_LIST_HHHDMATCH, DetectEngineInspectHttpHH }, diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index d018c11b7c12..26b51407574a 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -84,6 +84,10 @@ void DetectHttpUARegister(void) DETECT_SM_LIST_HUADMATCH, 2, PrefilterTxUARegister); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HUADMATCH, + DetectEngineInspectHttpUA); + return; } From a00629ab555ce666b4a0e08e0bc96b8523c8d6fd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 17:51:25 +0200 Subject: [PATCH 1979/2553] http_host: register inspect engine from keyword --- src/detect-engine.c | 4 ---- src/detect-http-hh.c | 5 +++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index efe0ec39e685..da7c73c59a9c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -49,7 +49,6 @@ #include "detect-engine-hrhd.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" -#include "detect-engine-hhhd.h" #include "detect-engine-hrhhd.h" #include "detect-engine-file.h" #include "detect-engine-dns.h" @@ -127,9 +126,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectHttp }, - { ALPROTO_HTTP, - DETECT_SM_LIST_HHHDMATCH, - DetectEngineInspectHttpHH }, { ALPROTO_HTTP, DETECT_SM_LIST_HRHHDMATCH, DetectEngineInspectHttpHRH }, diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 85098c295bdd..fbe0db94353b 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -82,6 +82,11 @@ void DetectHttpHHRegister(void) DetectMpmAppLayerRegister("http_host", SIG_FLAG_TOSERVER, DETECT_SM_LIST_HHHDMATCH, 2, PrefilterTxHostnameRegister); + + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HHHDMATCH, + DetectEngineInspectHttpHH); + return; } From 0496b3f6a55a1f72c46c570737e871cc7ebf7289 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Sep 2016 18:05:52 +0200 Subject: [PATCH 1980/2553] http_raw_host: register inspect engine from keyword --- src/detect-engine.c | 4 ---- src/detect-http-hrh.c | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index da7c73c59a9c..193740f5965a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -49,7 +49,6 @@ #include "detect-engine-hrhd.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" -#include "detect-engine-hrhhd.h" #include "detect-engine-file.h" #include "detect-engine-dns.h" #include "detect-engine-tls.h" @@ -126,9 +125,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectHttp }, - { ALPROTO_HTTP, - DETECT_SM_LIST_HRHHDMATCH, - DetectEngineInspectHttpHRH }, /* DNS */ { ALPROTO_DNS, DETECT_SM_LIST_DNSQUERYNAME_MATCH, diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index 3ba72481fb03..53c1919e30d5 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -83,6 +83,10 @@ void DetectHttpHRHRegister(void) DETECT_SM_LIST_HRHHDMATCH, 2, PrefilterTxHostnameRawRegister); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_HRHHDMATCH, + DetectEngineInspectHttpHRH); + return; } From 20e93ba419bafbbfa2a096199c766ffbba2b71a2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 08:20:51 +0200 Subject: [PATCH 1981/2553] file_data: register inspect engine from keyword --- src/detect-engine.c | 9 --------- src/detect-file-data.c | 7 +++++++ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 193740f5965a..b0b1dc0f8767 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -45,7 +45,6 @@ #include "detect-engine-tag.h" #include "detect-engine-uri.h" -#include "detect-engine-hsbd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" @@ -53,7 +52,6 @@ #include "detect-engine-dns.h" #include "detect-engine-tls.h" #include "detect-engine-modbus.h" -#include "detect-engine-filedata-smtp.h" #include "detect-engine-template.h" #include "detect-engine.h" @@ -144,10 +142,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_MODBUS, DETECT_SM_LIST_MODBUS_MATCH, DetectEngineInspectModbus }, - /* file_data smtp */ - { ALPROTO_SMTP, - DETECT_SM_LIST_FILEDATA, - DetectEngineInspectSMTPFiledata }, /* Template. */ { ALPROTO_TEMPLATE, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, @@ -155,9 +149,6 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toclient[] = { - { ALPROTO_HTTP, - DETECT_SM_LIST_FILEDATA, - DetectEngineInspectHttpServerBody }, { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectHttp }, diff --git a/src/detect-file-data.c b/src/detect-file-data.c index 981a2d5f10e3..ac518362d37d 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -69,6 +69,13 @@ void DetectFiledataRegister(void) DetectMpmAppLayerRegister("file_data", SIG_FLAG_TOCLIENT, DETECT_SM_LIST_FILEDATA, 2, PrefilterTxHttpResponseBodyRegister); + + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_FILEDATA, + DetectEngineInspectHttpServerBody); + DetectAppLayerInspectEngineRegister(ALPROTO_SMTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_FILEDATA, + DetectEngineInspectSMTPFiledata); } /** From cd705752db5bb55c03db0f1af35c7dc139d94ffb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 08:30:57 +0200 Subject: [PATCH 1982/2553] http_stat_msg: register inspect engine from keyword --- src/detect-engine.c | 4 ---- src/detect-http-stat-msg.c | 8 ++++++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index b0b1dc0f8767..a77933a51a20 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -46,7 +46,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hrhd.h" -#include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" #include "detect-engine-file.h" #include "detect-engine-dns.h" @@ -152,9 +151,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectHttp }, - { ALPROTO_HTTP, - DETECT_SM_LIST_HSMDMATCH, - DetectEngineInspectHttpStatMsg }, { ALPROTO_HTTP, DETECT_SM_LIST_HSCDMATCH, DetectEngineInspectHttpStatCode }, diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index de60f7178812..cbaa4a7f5886 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -88,8 +88,12 @@ void DetectHttpStatMsgRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_PAYLOAD; DetectMpmAppLayerRegister("http_stat_msg", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HSMDMATCH, 3, - PrefilterTxHttpStatMsgRegister); + DETECT_SM_LIST_HSMDMATCH, 3, + PrefilterTxHttpStatMsgRegister); + + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HSMDMATCH, + DetectEngineInspectHttpStatMsg); } /** From 200a4c159352bf8f20f4094671c82ede93a0ffe0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 08:38:37 +0200 Subject: [PATCH 1983/2553] http_stat_code: register inspect engine from keyword --- src/detect-engine.c | 4 ---- src/detect-http-stat-code.c | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index a77933a51a20..cff2e0d26ddc 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -46,7 +46,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hrhd.h" -#include "detect-engine-hscd.h" #include "detect-engine-file.h" #include "detect-engine-dns.h" #include "detect-engine-tls.h" @@ -151,9 +150,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectHttp }, - { ALPROTO_HTTP, - DETECT_SM_LIST_HSCDMATCH, - DetectEngineInspectHttpStatCode }, /* Modbus */ { ALPROTO_MODBUS, DETECT_SM_LIST_MODBUS_MATCH, diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index b127dcc70b1e..1cd484bc9bc0 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -90,6 +90,10 @@ void DetectHttpStatCodeRegister (void) DetectMpmAppLayerRegister("http_stat_code", SIG_FLAG_TOCLIENT, DETECT_SM_LIST_HSCDMATCH, 4, PrefilterTxHttpStatCodeRegister); + + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_HSCDMATCH, + DetectEngineInspectHttpStatCode); } /** From a87c196b607779912ce9d89d2cfd90a392870c0f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 08:43:25 +0200 Subject: [PATCH 1984/2553] tls_sni: register inspect engine from keyword --- src/detect-engine.c | 4 ---- src/detect-tls-sni.c | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index cff2e0d26ddc..7b1238f45ce5 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -128,10 +128,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_DNS, DETECT_SM_LIST_DNSREQUEST_MATCH, DetectEngineInspectDnsRequest }, - /* TLS */ - { ALPROTO_TLS, - DETECT_SM_LIST_TLSSNI_MATCH, - DetectEngineInspectTlsSni }, /* SMTP */ { ALPROTO_SMTP, DETECT_SM_LIST_FILEMATCH, diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index cdfb1e5087f2..ee455310d387 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -76,6 +76,9 @@ void DetectTlsSniRegister(void) DETECT_SM_LIST_TLSSNI_MATCH, 2, PrefilterTxTlsSniRegister); + DetectAppLayerInspectEngineRegister(ALPROTO_TLS, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_TLSSNI_MATCH, + DetectEngineInspectTlsSni); } From e28e98bcaaf42b50a4cf71584eb332c1d7ce1e88 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 08:45:29 +0200 Subject: [PATCH 1985/2553] tls_cert_subject: register inspect engine from keyword --- src/detect-engine.c | 6 ------ src/detect-tls-cert-subject.c | 5 +++++ src/detect-tls-cert-validity.c | 5 +++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 7b1238f45ce5..a9455499f4bf 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -157,12 +157,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_TLS, DETECT_SM_LIST_TLSISSUER_MATCH, DetectEngineInspectTlsIssuer }, - { ALPROTO_TLS, - DETECT_SM_LIST_TLSSUBJECT_MATCH, - DetectEngineInspectTlsSubject }, - { ALPROTO_TLS, - DETECT_SM_LIST_TLSVALIDITY_MATCH, - DetectEngineInspectTlsValidity }, /* Template. */ { ALPROTO_TEMPLATE, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index 9a3d4b464f7d..f6d62f438a91 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -75,6 +75,11 @@ void DetectTlsSubjectRegister(void) DetectMpmAppLayerRegister("tls_cert_subject", SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSSUBJECT_MATCH, 2, PrefilterTxTlsSubjectRegister); + + DetectAppLayerInspectEngineRegister(ALPROTO_TLS, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_TLSSUBJECT_MATCH, + DetectEngineInspectTlsSubject); + } /** diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index 47f009cce16d..08d0122263bd 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -35,6 +35,7 @@ #include "detect-content.h" #include "detect-pcre.h" #include "detect-tls-cert-validity.h" +#include "detect-engine-tls.h" #include "flow.h" #include "flow-util.h" @@ -93,6 +94,10 @@ void DetectTlsValidityRegister (void) sigmatch_table[DETECT_AL_TLS_NOTAFTER].RegisterTests = TlsNotAfterRegisterTests; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + DetectAppLayerInspectEngineRegister(ALPROTO_TLS, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_TLSVALIDITY_MATCH, + DetectEngineInspectTlsValidity); } /** From c9bb762f643587996864e8d343a7847fdd4fe7f6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 08:47:00 +0200 Subject: [PATCH 1986/2553] tls_cert_issuer: register inspect engine from keyword --- src/detect-engine.c | 5 ----- src/detect-tls-cert-issuer.c | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index a9455499f4bf..524f7a327009 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -48,7 +48,6 @@ #include "detect-engine-hrhd.h" #include "detect-engine-file.h" #include "detect-engine-dns.h" -#include "detect-engine-tls.h" #include "detect-engine-modbus.h" #include "detect-engine-template.h" @@ -153,10 +152,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_DNS, DETECT_SM_LIST_DNSRESPONSE_MATCH, DetectEngineInspectDnsResponse }, - /* TLS */ - { ALPROTO_TLS, - DETECT_SM_LIST_TLSISSUER_MATCH, - DetectEngineInspectTlsIssuer }, /* Template. */ { ALPROTO_TEMPLATE, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index fad644822295..7126af1a75f0 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -75,6 +75,10 @@ void DetectTlsIssuerRegister(void) DetectMpmAppLayerRegister("tls_cert_issuer", SIG_FLAG_TOCLIENT, DETECT_SM_LIST_TLSISSUER_MATCH, 2, PrefilterTxTlsIssuerRegister); + + DetectAppLayerInspectEngineRegister(ALPROTO_TLS, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_TLSISSUER_MATCH, + DetectEngineInspectTlsIssuer); } From 2db094ab7ae86787602f3a9723dbdb21642f6c8d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 09:02:38 +0200 Subject: [PATCH 1987/2553] dns detect: register inspect engine from keyword --- src/detect-dns-query.c | 11 +++++++++++ src/detect-engine.c | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index a9e072999ca6..54de91204ce7 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -81,6 +81,17 @@ void DetectDnsQueryRegister (void) DETECT_SM_LIST_DNSQUERYNAME_MATCH, 2, PrefilterTxDnsQueryRegister); + DetectAppLayerInspectEngineRegister(ALPROTO_DNS, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_DNSQUERYNAME_MATCH, + DetectEngineInspectDnsQueryName); + + /* register these generic engines from here for now */ + DetectAppLayerInspectEngineRegister(ALPROTO_DNS, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_DNSREQUEST_MATCH, + DetectEngineInspectDnsRequest); + DetectAppLayerInspectEngineRegister(ALPROTO_DNS, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_DNSRESPONSE_MATCH, + DetectEngineInspectDnsResponse); } diff --git a/src/detect-engine.c b/src/detect-engine.c index 524f7a327009..da8a4a8234cc 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -47,7 +47,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hrhd.h" #include "detect-engine-file.h" -#include "detect-engine-dns.h" #include "detect-engine-modbus.h" #include "detect-engine-template.h" @@ -120,13 +119,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectHttp }, - /* DNS */ - { ALPROTO_DNS, - DETECT_SM_LIST_DNSQUERYNAME_MATCH, - DetectEngineInspectDnsQueryName }, - { ALPROTO_DNS, - DETECT_SM_LIST_DNSREQUEST_MATCH, - DetectEngineInspectDnsRequest }, /* SMTP */ { ALPROTO_SMTP, DETECT_SM_LIST_FILEMATCH, @@ -149,9 +141,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_MODBUS, DETECT_SM_LIST_MODBUS_MATCH, DetectEngineInspectModbus }, - { ALPROTO_DNS, - DETECT_SM_LIST_DNSRESPONSE_MATCH, - DetectEngineInspectDnsResponse }, /* Template. */ { ALPROTO_TEMPLATE, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, From 08d0fe0916c5bdbbe973e816a032c6f29a5e1e44 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 09:11:33 +0200 Subject: [PATCH 1988/2553] modbus detect: register inspect engine from keyword --- src/detect-engine.c | 9 --------- src/detect-modbus.c | 11 +++++++++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index da8a4a8234cc..5b82b68b0057 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -47,7 +47,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hrhd.h" #include "detect-engine-file.h" -#include "detect-engine-modbus.h" #include "detect-engine-template.h" #include "detect-engine.h" @@ -123,10 +122,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_SMTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectSmtp }, - /* Modbus */ - { ALPROTO_MODBUS, - DETECT_SM_LIST_MODBUS_MATCH, - DetectEngineInspectModbus }, /* Template. */ { ALPROTO_TEMPLATE, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, @@ -137,10 +132,6 @@ void DetectEngineRegisterAppInspectionEngines(void) { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DetectFileInspectHttp }, - /* Modbus */ - { ALPROTO_MODBUS, - DETECT_SM_LIST_MODBUS_MATCH, - DetectEngineInspectModbus }, /* Template. */ { ALPROTO_TEMPLATE, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, diff --git a/src/detect-modbus.c b/src/detect-modbus.c index fe585f6d121c..b426b4b2c863 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -45,8 +45,10 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine.h" #include "detect-modbus.h" +#include "detect-engine-modbus.h" #include "util-debug.h" @@ -412,11 +414,16 @@ void DetectModbusRegister(void) &function_parse_regex, &function_parse_regex_study); DetectSetupParseRegexes(PARSE_REGEX_ACCESS, &access_parse_regex, &access_parse_regex_study); + + DetectAppLayerInspectEngineRegister(ALPROTO_MODBUS, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_MODBUS_MATCH, + DetectEngineInspectModbus); + DetectAppLayerInspectEngineRegister(ALPROTO_MODBUS, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_MODBUS_MATCH, + DetectEngineInspectModbus); } #ifdef UNITTESTS /* UNITTESTS */ -#include "detect-engine.h" - #include "util-unittest.h" /** \test Signature containing a function. */ From 6f253e1ea7d02469d471ee5a0bb37cc7c1a08e48 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 09:21:07 +0200 Subject: [PATCH 1989/2553] file detect: register inspect engines from keyword --- src/detect-engine.c | 10 ---------- src/detect-filename.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 5b82b68b0057..6e9c6a78aee3 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -115,13 +115,6 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toserver[] = { - { ALPROTO_HTTP, - DETECT_SM_LIST_FILEMATCH, - DetectFileInspectHttp }, - /* SMTP */ - { ALPROTO_SMTP, - DETECT_SM_LIST_FILEMATCH, - DetectFileInspectSmtp }, /* Template. */ { ALPROTO_TEMPLATE, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, @@ -129,9 +122,6 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toclient[] = { - { ALPROTO_HTTP, - DETECT_SM_LIST_FILEMATCH, - DetectFileInspectHttp }, /* Template. */ { ALPROTO_TEMPLATE, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, diff --git a/src/detect-filename.c b/src/detect-filename.c index 638bb7439fb3..ce89d0caf871 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -34,6 +34,7 @@ #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" +#include "detect-engine-file.h" #include "flow.h" #include "flow-var.h" @@ -70,6 +71,17 @@ void DetectFilenameRegister(void) sigmatch_table[DETECT_FILENAME].Free = DetectFilenameFree; sigmatch_table[DETECT_FILENAME].RegisterTests = DetectFilenameRegisterTests; + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_FILEMATCH, + DetectFileInspectHttp); + DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_FILEMATCH, + DetectFileInspectHttp); + + DetectAppLayerInspectEngineRegister(ALPROTO_SMTP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_FILEMATCH, + DetectFileInspectSmtp); + SCLogDebug("registering filename rule option"); return; } From 8a0bea872c8d73e4fa2ae4bd3c7e123fbb15c5ef Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 09:35:53 +0200 Subject: [PATCH 1990/2553] template_buffer: register inspect engine from keyword --- src/detect-engine.c | 11 ++--------- src/detect-template-buffer.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 6e9c6a78aee3..e83f3ee533cf 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -47,7 +47,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hrhd.h" #include "detect-engine-file.h" -#include "detect-engine-template.h" #include "detect-engine.h" #include "detect-engine-state.h" @@ -115,17 +114,11 @@ void DetectEngineRegisterAppInspectionEngines(void) }; struct tmp_t data_toserver[] = { - /* Template. */ - { ALPROTO_TEMPLATE, - DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, - DetectEngineInspectTemplateBuffer }, + {0,0,NULL}, }; struct tmp_t data_toclient[] = { - /* Template. */ - { ALPROTO_TEMPLATE, - DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, - DetectEngineInspectTemplateBuffer }, + {0,0,NULL}, }; size_t i; diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index 65debf5ecba9..83b55765a019 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -33,7 +33,9 @@ #include "suricata-common.h" #include "conf.h" #include "detect.h" +#include "detect-engine.h" #include "app-layer-template.h" +#include "detect-engine-template.h" static int DetectTemplateBufferSetup(DetectEngineCtx *, Signature *, char *); static void DetectTemplateBufferRegisterTests(void); @@ -55,6 +57,14 @@ void DetectTemplateBufferRegister(void) sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_PAYLOAD; + /* register inspect engines */ + DetectAppLayerInspectEngineRegister(ALPROTO_TEMPLATE, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + DetectEngineInspectTemplateBuffer); + DetectAppLayerInspectEngineRegister(ALPROTO_TEMPLATE, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + DetectEngineInspectTemplateBuffer); + SCLogNotice("Template application layer detect registered."); } From 9e35fa7f417e68fc7a20d829900b83b77a961235 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 09:37:54 +0200 Subject: [PATCH 1991/2553] detect: remove empty app registration table --- src/detect-engine.c | 40 ---------------------------------------- src/detect-engine.h | 1 - src/runmode-unittests.c | 2 -- src/suricata.c | 2 -- 4 files changed, 45 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index e83f3ee533cf..987ef4e1cb10 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -99,46 +99,6 @@ static void TenantIdFree(void *d); static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p); static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p); -void DetectEngineRegisterAppInspectionEngines(void) -{ - struct tmp_t { - AppProto alproto; - int32_t sm_list; - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); - - }; - - struct tmp_t data_toserver[] = { - {0,0,NULL}, - }; - - struct tmp_t data_toclient[] = { - {0,0,NULL}, - }; - - size_t i; - for (i = 0 ; i < sizeof(data_toserver) / sizeof(struct tmp_t); i++) { - DetectEngineRegisterAppInspectionEngine(data_toserver[i].alproto, - 0, - data_toserver[i].sm_list, - data_toserver[i].Callback); - } - - for (i = 0 ; i < sizeof(data_toclient) / sizeof(struct tmp_t); i++) { - DetectEngineRegisterAppInspectionEngine(data_toclient[i].alproto, - 1, - data_toclient[i].sm_list, - data_toclient[i].Callback); - } - - return; -} - static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL; void DetectEngineRegisterAppInspectionEngine(AppProto alproto, diff --git a/src/detect-engine.h b/src/detect-engine.h index 4eb48a353e5c..4646a5099e80 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -29,7 +29,6 @@ #include "flow-private.h" /* prototypes */ -void DetectEngineRegisterAppInspectionEngines(void); DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix); DetectEngineCtx *DetectEngineCtxInit(void); DetectEngineCtx *DetectEngineCtxInitMinimal(void); diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 7326bcec3be9..7c97d286293d 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -181,8 +181,6 @@ void RunUnittests(int list_unittests, char *regex_arg) RegisterAllModules(); - DetectEngineRegisterAppInspectionEngines(); - HostBitInitCtx(); StorageFinalize(); diff --git a/src/suricata.c b/src/suricata.c index cfdb9dcc24e2..596544902a84 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2336,8 +2336,6 @@ static int PostConfLoadedSetup(SCInstance *suri) AppLayerHtpNeedFileInspection(); - DetectEngineRegisterAppInspectionEngines(); - StorageFinalize(); TmModuleRunInit(); From a24870f29f4d8d1677db8594c1d8fd1468a44851 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 09:56:23 +0200 Subject: [PATCH 1992/2553] detect app-layer-event: clean up registration Move engine and registration into the keyword file. Register as 'ALPROTO_UNKNOWN' instead of per alproto. The registration will only apply it to those rules that have events set. --- src/Makefile.am | 1 - src/detect-app-layer-event.c | 60 +++++++++++++++++++++++++- src/detect-engine-apt-event.c | 79 ----------------------------------- src/detect-engine-apt-event.h | 34 --------------- src/detect-engine.c | 6 ++- src/detect-parse.c | 20 --------- 6 files changed, 63 insertions(+), 137 deletions(-) delete mode 100644 src/detect-engine-apt-event.c delete mode 100644 src/detect-engine-apt-event.h diff --git a/src/Makefile.am b/src/Makefile.am index b76063152123..92b9472e1afc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -97,7 +97,6 @@ detect-engine-address-ipv4.c detect-engine-address-ipv4.h \ detect-engine-address-ipv6.c detect-engine-address-ipv6.h \ detect-engine-alert.c detect-engine-alert.h \ detect-engine-analyzer.c detect-engine-analyzer.h \ -detect-engine-apt-event.c detect-engine-apt-event.h \ detect-engine.c detect-engine.h \ detect-engine-content-inspection.c detect-engine-content-inspection.h \ detect-engine-dcepayload.c detect-engine-dcepayload.h \ diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 8ca0804bf0ca..b33948aceb2a 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -53,7 +53,12 @@ static int DetectAppLayerEventAppMatch(ThreadVars *, DetectEngineThreadCtx *, Fl static int DetectAppLayerEventSetupP1(DetectEngineCtx *, Signature *, char *); static void DetectAppLayerEventRegisterTests(void); static void DetectAppLayerEventFree(void *); - +static int DetectEngineAptEventInspect(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *tx, uint64_t tx_id); /** * \brief Registers the keyword handlers for the "app-layer-event" keyword. */ @@ -69,9 +74,62 @@ void DetectAppLayerEventRegister(void) sigmatch_table[DETECT_AL_APP_LAYER_EVENT].RegisterTests = DetectAppLayerEventRegisterTests; + DetectAppLayerInspectEngineRegister(ALPROTO_UNKNOWN, + SIG_FLAG_TOSERVER, DETECT_SM_LIST_APP_EVENT, + DetectEngineAptEventInspect); + DetectAppLayerInspectEngineRegister(ALPROTO_UNKNOWN, + SIG_FLAG_TOCLIENT, DETECT_SM_LIST_APP_EVENT, + DetectEngineAptEventInspect); + return; } +static int DetectEngineAptEventInspect(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *tx, uint64_t tx_id) +{ + AppLayerDecoderEvents *decoder_events = NULL; + int r = 0; + AppProto alproto; + SigMatch *sm; + DetectAppLayerEventData *aled = NULL; + + alproto = f->alproto; + decoder_events = AppLayerParserGetEventsByTx(f->proto, alproto, alstate, tx_id); + if (decoder_events == NULL) + goto end; + + for (sm = s->sm_lists[DETECT_SM_LIST_APP_EVENT]; sm != NULL; sm = sm->next) { + aled = (DetectAppLayerEventData *)sm->ctx; + KEYWORD_PROFILING_START; + if (AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) { + KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + continue; + } + + KEYWORD_PROFILING_END(det_ctx, sm->type, 0); + goto end; + } + + r = 1; + + end: + if (r == 1) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } else { + if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) == + AppLayerParserGetStateProgressCompletionStatus(alproto, flags)) + { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } + } +} + static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) diff --git a/src/detect-engine-apt-event.c b/src/detect-engine-apt-event.c deleted file mode 100644 index 344102970ad9..000000000000 --- a/src/detect-engine-apt-event.c +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Anoop Saldanha - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "app-layer-parser.h" -#include "detect-app-layer-event.h" -#include "detect-engine-state.h" -#include "stream.h" -#include "detect-engine-apt-event.h" -#include "util-profiling.h" -#include "util-unittest.h" - -int DetectEngineAptEventInspect(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) -{ - AppLayerDecoderEvents *decoder_events = NULL; - int r = 0; - AppProto alproto; - SigMatch *sm; - DetectAppLayerEventData *aled = NULL; - - alproto = f->alproto; - decoder_events = AppLayerParserGetEventsByTx(f->proto, alproto, alstate, tx_id); - if (decoder_events == NULL) - goto end; - - for (sm = s->sm_lists[DETECT_SM_LIST_APP_EVENT]; sm != NULL; sm = sm->next) { - aled = (DetectAppLayerEventData *)sm->ctx; - KEYWORD_PROFILING_START; - if (AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - continue; - } - - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); - goto end; - } - - r = 1; - - end: - if (r == 1) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } else { - if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) == - AppLayerParserGetStateProgressCompletionStatus(alproto, flags)) - { - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } else { - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; - } - } -} - diff --git a/src/detect-engine-apt-event.h b/src/detect-engine-apt-event.h deleted file mode 100644 index c264efe94563..000000000000 --- a/src/detect-engine-apt-event.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Anoop Saldanha - */ - -#ifndef __DETECT_ENGINE_APT_EVENT__H__ -#define __DETECT_ENGINE_APT_EVENT__H__ - -int DetectEngineAptEventInspect(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); -void DetectEngineAptEventRegisterTests(void); - -#endif /* __DETECT_ENGINE_APT_EVENT__H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 987ef4e1cb10..8aeda61049b2 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -111,7 +111,7 @@ void DetectEngineRegisterAppInspectionEngine(AppProto alproto, uint8_t flags, void *alstate, void *tx, uint64_t tx_id)) { - if ((alproto <= ALPROTO_UNKNOWN || alproto >= ALPROTO_FAILED) || + if ((alproto >= ALPROTO_FAILED) || (dir > 1) || (sm_list < DETECT_SM_LIST_MATCH || sm_list >= DETECT_SM_LIST_MAX) || (Callback == NULL)) @@ -170,7 +170,9 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) while (t != NULL) { if (s->sm_lists[t->sm_list] == NULL) goto next; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != t->alproto) + if (t->alproto == ALPROTO_UNKNOWN) { + /* special case, inspect engine applies to all protocols */ + } else if (s->alproto != ALPROTO_UNKNOWN && s->alproto != t->alproto) goto next; if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) { diff --git a/src/detect-parse.c b/src/detect-parse.c index e3bc8b31a047..f71d7166b8be 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -40,7 +40,6 @@ #include "detect-ipproto.h" #include "detect-flow.h" #include "detect-app-layer-protocol.h" -#include "detect-engine-apt-event.h" #include "detect-lua.h" #include "detect-app-layer-event.h" #include "detect-http-method.h" @@ -1642,25 +1641,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, SigBuildAddressMatchArray(sig); - if (sig->sm_lists[DETECT_SM_LIST_APP_EVENT] != NULL) { - if (AppLayerParserProtocolIsTxEventAware(IPPROTO_TCP, sig->alproto) || - AppLayerParserProtocolIsTxEventAware(IPPROTO_UDP, sig->alproto)) - { - if (sig->flags & SIG_FLAG_TOSERVER) { - DetectEngineRegisterAppInspectionEngine(sig->alproto, - 0, - DETECT_SM_LIST_APP_EVENT, - DetectEngineAptEventInspect); - } - if (sig->flags & SIG_FLAG_TOCLIENT) { - DetectEngineRegisterAppInspectionEngine(sig->alproto, - 1, - DETECT_SM_LIST_APP_EVENT, - DetectEngineAptEventInspect); - } - } - } - /* validate signature, SigValidate will report the error reason */ if (SigValidate(de_ctx, sig) == 0) { goto error; From 58ac4027ef7c3dc6603b21ae1a6d85ee857f372a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 10:01:02 +0200 Subject: [PATCH 1993/2553] detect: clean up inspect engine registration --- src/detect-engine.c | 50 +++++++++++++++------------------------------ src/detect-engine.h | 16 ++------------- 2 files changed, 19 insertions(+), 47 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 8aeda61049b2..0a74031e2b76 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -101,18 +101,17 @@ static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet * static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL; -void DetectEngineRegisterAppInspectionEngine(AppProto alproto, - uint16_t dir, - int32_t sm_list, - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id)) +void DetectAppLayerInspectEngineRegister(AppProto alproto, + uint32_t dir, int32_t sm_list, + int (*Callback)(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *sig, Flow *f, + uint8_t flags, void *alstate, + void *tx, uint64_t tx_id)) { if ((alproto >= ALPROTO_FAILED) || - (dir > 1) || + (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) || (sm_list < DETECT_SM_LIST_MATCH || sm_list >= DETECT_SM_LIST_MAX) || (Callback == NULL)) { @@ -120,13 +119,20 @@ void DetectEngineRegisterAppInspectionEngine(AppProto alproto, exit(EXIT_FAILURE); } + int direction; + if (dir == SIG_FLAG_TOSERVER) { + direction = 0; + } else { + direction = 1; + } + DetectEngineAppInspectionEngine *new_engine = SCMalloc(sizeof(DetectEngineAppInspectionEngine)); if (unlikely(new_engine == NULL)) { exit(EXIT_FAILURE); } memset(new_engine, 0, sizeof(*new_engine)); new_engine->alproto = alproto; - new_engine->dir = dir; + new_engine->dir = direction; new_engine->sm_list = sm_list; new_engine->Callback = Callback; @@ -140,28 +146,6 @@ void DetectEngineRegisterAppInspectionEngine(AppProto alproto, t->next = new_engine; } - return; -} - -void DetectAppLayerInspectEngineRegister(AppProto alproto, - uint32_t dir, int32_t sm_list, - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id)) -{ - BUG_ON(!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)); - - int direction; - if (dir == SIG_FLAG_TOSERVER) { - direction = 0; - } else { - direction = 1; - } - - DetectEngineRegisterAppInspectionEngine(alproto, direction, sm_list, Callback); } int DetectEngineAppInspectionEngine2Signature(Signature *s) diff --git a/src/detect-engine.h b/src/detect-engine.h index 4646a5099e80..608f0685d807 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -78,23 +78,11 @@ int DetectEngineInspectGenericList(ThreadVars *, const DetectEngineCtx *, * \brief Registers an app inspection engine. * * \param alproto App layer protocol for which we will register the engine. - * \param direction The direction for the engine. 0 - toserver; 1- toclient. + * \param direction The direction for the engine: SIG_FLAG_TOSERVER or + * SIG_FLAG_TOCLIENT * \param sm_list The SigMatch list against which the engine works. - * \param inspect_flags The inspection flags to be used by de_state - * against the engine. - * \param match_flags The match flags to be used by de_state in tandem with - * the inpsect_flags. * \param Callback The engine callback. */ -void DetectEngineRegisterAppInspectionEngine(AppProto alproto, - uint16_t dir, - int32_t sm_list, - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id)); void DetectAppLayerInspectEngineRegister(AppProto alproto, uint32_t dir, int32_t sm_list, From d36c0c15eabfc4145affd66295738a4e1e9ce125 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Sep 2016 11:25:38 +0200 Subject: [PATCH 1994/2553] detect: reshuffle keyword registration order The order of keyword registration currently affects inspect engine registration order and ultimately the order of inspect engines per rule. Which in turn affects state keeping. This patch makes sure the ordering is the same as with older releases. --- src/detect.c | 69 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/src/detect.c b/src/detect.c index d87c9f9a6877..a955b5fe2a97 100644 --- a/src/detect.c +++ b/src/detect.c @@ -4134,6 +4134,48 @@ void SigTableSetup(void) DetectSeqRegister(); DetectContentRegister(); DetectUricontentRegister(); + + /* NOTE: the order of these currently affects inspect + * engine registration order and ultimately the order + * of inspect engines in the rule. Which in turn affects + * state keeping */ + DetectHttpUriRegister(); + DetectHttpRequestLineRegister(); + DetectHttpClientBodyRegister(); + DetectHttpResponseLineRegister(); + DetectHttpServerBodyRegister(); + DetectHttpHeaderRegister(); + DetectHttpRawHeaderRegister(); + DetectHttpMethodRegister(); + DetectHttpCookieRegister(); + DetectHttpRawUriRegister(); + + DetectFilenameRegister(); + DetectFileextRegister(); + DetectFilestoreRegister(); + DetectFilemagicRegister(); + DetectFileMd5Register(); + DetectFileSha1Register(); + DetectFileSha256Register(); + DetectFilesizeRegister(); + + DetectHttpUARegister(); + DetectHttpHHRegister(); + DetectHttpHRHRegister(); + + DetectHttpStatMsgRegister(); + DetectHttpStatCodeRegister(); + + DetectDnsQueryRegister(); + DetectModbusRegister(); + + DetectTlsSniRegister(); + DetectTlsIssuerRegister(); + DetectTlsSubjectRegister(); + + DetectAppLayerEventRegister(); + /* end of order dependent regs */ + DetectPcreRegister(); DetectDepthRegister(); DetectNocaseRegister(); @@ -4181,48 +4223,21 @@ void SigTableSetup(void) DetectDceIfaceRegister(); DetectDceOpnumRegister(); DetectDceStubDataRegister(); - DetectHttpCookieRegister(); - DetectHttpMethodRegister(); - DetectHttpStatMsgRegister(); DetectTlsRegister(); DetectTlsValidityRegister(); DetectTlsVersionRegister(); DetectUrilenRegister(); DetectDetectionFilterRegister(); - DetectHttpHeaderRegister(); - DetectHttpRawHeaderRegister(); - DetectHttpClientBodyRegister(); - DetectHttpServerBodyRegister(); - DetectHttpUriRegister(); - DetectHttpRawUriRegister(); DetectAsn1Register(); DetectSshVersionRegister(); DetectSshSoftwareVersionRegister(); DetectSslStateRegister(); - DetectHttpStatCodeRegister(); DetectSslVersionRegister(); DetectByteExtractRegister(); DetectFiledataRegister(); DetectPktDataRegister(); - DetectFilenameRegister(); - DetectFileextRegister(); - DetectFilestoreRegister(); - DetectFilemagicRegister(); - DetectFileMd5Register(); - DetectFileSha1Register(); - DetectFileSha256Register(); - DetectFilesizeRegister(); - DetectAppLayerEventRegister(); - DetectHttpUARegister(); - DetectHttpHHRegister(); - DetectHttpHRHRegister(); DetectLuaRegister(); DetectIPRepRegister(); - DetectDnsQueryRegister(); - DetectTlsSniRegister(); - DetectTlsIssuerRegister(); - DetectTlsSubjectRegister(); - DetectModbusRegister(); DetectAppLayerProtocolRegister(); DetectBase64DecodeRegister(); DetectBase64DataRegister(); From 8321f04ef32f12be82b8e2d4afd835a18da69ba2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Sep 2016 11:56:58 +0200 Subject: [PATCH 1995/2553] prefilter: clean up setup code --- src/detect-engine-prefilter.c | 36 +++++++++++++++++++++++++++++++++++ src/detect-engine-prefilter.h | 2 ++ src/detect.c | 32 +------------------------------ 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index a7cc85f8db26..dee4c316dc6d 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -48,6 +48,7 @@ #include "suricata.h" #include "detect-engine-prefilter.h" +#include "detect-engine-mpm.h" #include "app-layer-parser.h" #include "app-layer-htp.h" @@ -323,6 +324,41 @@ void PrefilterFreeEngines(PrefilterEngine *list) } } +void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +{ + BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); + + if (de_ctx->prefilter_setting == DETECT_PREFILTER_AUTO) { + int i = 0; + for (i = 0; i < DETECT_TBLSIZE; i++) + { + if (sigmatch_table[i].SetupPrefilter != NULL) { + sigmatch_table[i].SetupPrefilter(sgh); + } + } + } + +#ifdef PROFILING + PrefilterEngine *e; + uint32_t engines = 0; + uint32_t tx_engines = 0; + + for (e = sgh->pkt_engines ; e != NULL; e = e->next) { + engines++; + de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + } + for (e = sgh->payload_engines ; e != NULL; e = e->next) { + engines++; + de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + } + for (e = sgh->tx_engines ; e != NULL; e = e->next) { + tx_engines++; + de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + } + SCLogDebug("SGH %p: engines %u tx_engines %u", sgh, engines, tx_engines); +#endif +} + #ifdef PROFILING /* hash table for assigning a unique id to each engine type. */ diff --git a/src/detect-engine-prefilter.h b/src/detect-engine-prefilter.h index 5ce32fea0a5a..7836bab39a1c 100644 --- a/src/detect-engine-prefilter.h +++ b/src/detect-engine-prefilter.h @@ -45,6 +45,8 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, void PrefilterFreeEngines(PrefilterEngine *list); +void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh); + #ifdef PROFILING const char *PrefilterStoreGetName(const uint32_t id); #endif diff --git a/src/detect.c b/src/detect.c index a955b5fe2a97..900f82438619 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3787,37 +3787,7 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SigGroupHeadSetFilestoreCount(de_ctx, sgh); SCLogDebug("filestore count %u", sgh->filestore_cnt); - BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); - - if (de_ctx->prefilter_setting == DETECT_PREFILTER_AUTO) { - int i = 0; - for (i = 0; i < DETECT_TBLSIZE; i++) - { - if (sigmatch_table[i].SetupPrefilter != NULL) { - sigmatch_table[i].SetupPrefilter(sgh); - } - } - } - -#ifdef PROFILING - PrefilterEngine *e; - uint32_t engines = 0; - uint32_t tx_engines = 0; - - for (e = sgh->pkt_engines ; e != NULL; e = e->next) { - engines++; - de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); - } - for (e = sgh->payload_engines ; e != NULL; e = e->next) { - engines++; - de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); - } - for (e = sgh->tx_engines ; e != NULL; e = e->next) { - tx_engines++; - de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); - } - SCLogDebug("SGH %p: engines %u tx_engines %u", sgh, engines, tx_engines); -#endif + PrefilterSetupRuleGroup(de_ctx, sgh); SigGroupHeadBuildNonPrefilterArray(de_ctx, sgh); From 798ba010ca956310fd17f2b6ecda3c6f383c3818 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Sep 2016 13:46:08 +0200 Subject: [PATCH 1996/2553] prefilter: use array of engines per sgh Instead of the linked list of engines setup an array with the engines. This should provide better locality. Also shrink the engine structure so that we can fit 2 on a cacheline. Remove the FreeFunc from the runtime engines. Engines now have a 'gid' (global id) that can be used to look up the registered Free function. --- src/detect-engine-prefilter.c | 252 ++++++++++++++++++++++++---------- src/detect-engine-prefilter.h | 3 +- src/detect-engine-siggroup.c | 10 +- src/detect.h | 45 ++++-- 4 files changed, 223 insertions(+), 87 deletions(-) diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index dee4c316dc6d..0b182880300f 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -55,9 +55,14 @@ #include "util-profiling.h" -#ifdef PROFILING -static int PrefilterStoreGetId(const char *name); -#endif +typedef struct PrefilterStore_ { + const char *name; + void (*FreeFunc)(void *); + uint32_t id; +} PrefilterStore; + +static int PrefilterStoreGetId(const char *name, void (*FreeFunc)(void *)); +static const PrefilterStore *PrefilterStoreGetStore(const uint32_t id); static inline void QuickSortSigIntId(SigIntId *sids, uint32_t n) { @@ -124,12 +129,14 @@ static inline void PrefilterTx(DetectEngineThreadCtx *det_ctx, goto next; PROFILING_PREFILTER_START(p); - engine->PrefilterTx(det_ctx, engine->pectx, + engine->cb.PrefilterTx(det_ctx, engine->pectx, p, p->flow, tx, idx, flags); - PROFILING_PREFILTER_END(p, engine->profile_id); + PROFILING_PREFILTER_END(p, engine->gid); next: - engine = engine->next; - } while (engine); + if (engine->is_last) + break; + engine++; + } while (1); } } @@ -138,7 +145,7 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, { SCEnter(); - PROFILING_PREFILTER_RESET(p, det_ctx->de_ctx->profile_prefilter_maxid); + PROFILING_PREFILTER_RESET(p, det_ctx->de_ctx->prefilter_maxid); if (sgh->pkt_engines) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PKT); @@ -146,11 +153,13 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, PrefilterEngine *engine = sgh->pkt_engines; do { PROFILING_PREFILTER_START(p); - engine->Prefilter(det_ctx, p, engine->pectx); - PROFILING_PREFILTER_END(p, engine->profile_id); + engine->cb.Prefilter(det_ctx, p, engine->pectx); + PROFILING_PREFILTER_END(p, engine->gid); - engine = engine->next; - } while (engine != NULL); + if (engine->is_last) + break; + engine++; + } while (1); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PKT); } @@ -160,12 +169,14 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, !(p->flags & PKT_NOPAYLOAD_INSPECTION)) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PAYLOAD); PrefilterEngine *engine = sgh->payload_engines; - while (engine) { + while (1) { PROFILING_PREFILTER_START(p); - engine->Prefilter(det_ctx, p, engine->pectx); - PROFILING_PREFILTER_END(p, engine->profile_id); + engine->cb.Prefilter(det_ctx, p, engine->pectx); + PROFILING_PREFILTER_END(p, engine->gid); - engine = engine->next; + if (engine->is_last) + break; + engine++; } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PAYLOAD); } @@ -198,7 +209,7 @@ int PrefilterAppendEngine(SigGroupHead *sgh, if (sgh == NULL || Prefilter == NULL || pectx == NULL) return -1; - PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); + PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); if (e == NULL) return -1; memset(e, 0x00, sizeof(*e)); @@ -207,10 +218,10 @@ int PrefilterAppendEngine(SigGroupHead *sgh, e->pectx = pectx; e->Free = FreeFunc; - if (sgh->pkt_engines == NULL) { - sgh->pkt_engines = e; + if (sgh->init->pkt_engines == NULL) { + sgh->init->pkt_engines = e; } else { - PrefilterEngine *t = sgh->pkt_engines; + PrefilterEngineList *t = sgh->init->pkt_engines; while (t->next != NULL) { t = t->next; } @@ -219,11 +230,8 @@ int PrefilterAppendEngine(SigGroupHead *sgh, e->id = t->id + 1; } -#ifdef PROFILING - sgh->engines_cnt = e->id; e->name = name; - e->profile_id = PrefilterStoreGetId(e->name); -#endif + e->gid = PrefilterStoreGetId(e->name, e->Free); return 0; } @@ -235,7 +243,7 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh, if (sgh == NULL || Prefilter == NULL || pectx == NULL) return -1; - PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); + PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); if (e == NULL) return -1; memset(e, 0x00, sizeof(*e)); @@ -244,10 +252,10 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh, e->pectx = pectx; e->Free = FreeFunc; - if (sgh->payload_engines == NULL) { - sgh->payload_engines = e; + if (sgh->init->payload_engines == NULL) { + sgh->init->payload_engines = e; } else { - PrefilterEngine *t = sgh->payload_engines; + PrefilterEngineList *t = sgh->init->payload_engines; while (t->next != NULL) { t = t->next; } @@ -256,11 +264,8 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh, e->id = t->id + 1; } -#ifdef PROFILING - sgh->engines_cnt = e->id; e->name = name; - e->profile_id = PrefilterStoreGetId(e->name); -#endif + e->gid = PrefilterStoreGetId(e->name, e->Free); return 0; } @@ -275,7 +280,7 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, if (sgh == NULL || PrefilterTx == NULL || pectx == NULL) return -1; - PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); + PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); if (e == NULL) return -1; memset(e, 0x00, sizeof(*e)); @@ -286,10 +291,10 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, e->tx_min_progress = tx_min_progress; e->Free = FreeFunc; - if (sgh->tx_engines == NULL) { - sgh->tx_engines = e; + if (sgh->init->tx_engines == NULL) { + sgh->init->tx_engines = e; } else { - PrefilterEngine *t = sgh->tx_engines; + PrefilterEngineList *t = sgh->init->tx_engines; while (t->next != NULL) { t = t->next; } @@ -297,33 +302,64 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, t->next = e; e->id = t->id + 1; } -#ifdef PROFILING - sgh->tx_engines_cnt = e->id; + e->name = name; - e->profile_id = PrefilterStoreGetId(e->name); -#endif + e->gid = PrefilterStoreGetId(e->name, e->Free); return 0; } -static void PrefilterFreeEngine(PrefilterEngine *e) +static void PrefilterFreeEngineList(PrefilterEngineList *e) { - if (e->Free) { + if (e->Free && e->pectx) { e->Free(e->pectx); } SCFreeAligned(e); } -void PrefilterFreeEngines(PrefilterEngine *list) +void PrefilterFreeEnginesList(PrefilterEngineList *list) { - PrefilterEngine *t = list; + PrefilterEngineList *t = list; while (t != NULL) { - PrefilterEngine *next = t->next; - PrefilterFreeEngine(t); + PrefilterEngineList *next = t->next; + PrefilterFreeEngineList(t); t = next; } } +static void PrefilterFreeEngines(PrefilterEngine *list) +{ + PrefilterEngine *t = list; + + while (1) { + const PrefilterStore *s = PrefilterStoreGetStore(t->gid); + if (s && s->FreeFunc && t->pectx) { + s->FreeFunc(t->pectx); + } + + if (t->is_last) + break; + t++; + } + SCFreeAligned(list); +} + +void PrefilterCleanupRuleGroup(SigGroupHead *sgh) +{ + if (sgh->pkt_engines) { + PrefilterFreeEngines(sgh->pkt_engines); + sgh->pkt_engines = NULL; + } + if (sgh->payload_engines) { + PrefilterFreeEngines(sgh->payload_engines); + sgh->payload_engines = NULL; + } + if (sgh->tx_engines) { + PrefilterFreeEngines(sgh->tx_engines); + sgh->tx_engines = NULL; + } +} + void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); @@ -338,35 +374,90 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) } } -#ifdef PROFILING - PrefilterEngine *e; - uint32_t engines = 0; - uint32_t tx_engines = 0; - - for (e = sgh->pkt_engines ; e != NULL; e = e->next) { - engines++; - de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + /* we have lists of engines in sgh->init now. Lets setup the + * match arrays */ + PrefilterEngineList *el; + if (sgh->init->pkt_engines != NULL) { + uint32_t cnt = 0; + for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) { + cnt++; + de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid); + } + sgh->pkt_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS); + if (sgh->pkt_engines == NULL) { + return; + } + memset(sgh->pkt_engines, 0x00, (cnt * sizeof(PrefilterEngine))); + + PrefilterEngine *e = sgh->pkt_engines; + for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) { + e->id = el->id; + e->cb.Prefilter = el->Prefilter; + e->pectx = el->pectx; + el->pectx = NULL; // e now owns the ctx + e->gid = el->gid; + if (el->next == NULL) { + e->is_last = TRUE; + } + e++; + } } - for (e = sgh->payload_engines ; e != NULL; e = e->next) { - engines++; - de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + if (sgh->init->payload_engines != NULL) { + uint32_t cnt = 0; + for (el = sgh->init->payload_engines ; el != NULL; el = el->next) { + cnt++; + de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid); + } + sgh->payload_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS); + if (sgh->payload_engines == NULL) { + return; + } + memset(sgh->payload_engines, 0x00, (cnt * sizeof(PrefilterEngine))); + + PrefilterEngine *e = sgh->payload_engines; + for (el = sgh->init->payload_engines ; el != NULL; el = el->next) { + e->id = el->id; + e->cb.Prefilter = el->Prefilter; + e->pectx = el->pectx; + el->pectx = NULL; // e now owns the ctx + e->gid = el->gid; + if (el->next == NULL) { + e->is_last = TRUE; + } + e++; + } } - for (e = sgh->tx_engines ; e != NULL; e = e->next) { - tx_engines++; - de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + if (sgh->init->tx_engines != NULL) { + uint32_t cnt = 0; + for (el = sgh->init->tx_engines ; el != NULL; el = el->next) { + cnt++; + de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid); + } + sgh->tx_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS); + if (sgh->tx_engines == NULL) { + return; + } + memset(sgh->tx_engines, 0x00, (cnt * sizeof(PrefilterEngine))); + + PrefilterEngine *e = sgh->tx_engines; + for (el = sgh->init->tx_engines ; el != NULL; el = el->next) { + e->id = el->id; + e->alproto = el->alproto; + e->tx_min_progress = el->tx_min_progress; + e->cb.PrefilterTx = el->PrefilterTx; + e->pectx = el->pectx; + el->pectx = NULL; // e now owns the ctx + e->gid = el->gid; + if (el->next == NULL) { + e->is_last = TRUE; + } + e++; + } } - SCLogDebug("SGH %p: engines %u tx_engines %u", sgh, engines, tx_engines); -#endif } -#ifdef PROFILING /* hash table for assigning a unique id to each engine type. */ -typedef struct PrefilterStore_ { - const char *name; - uint32_t id; -} PrefilterStore; - static uint32_t PrefilterStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen) { PrefilterStore *ctx = data; @@ -421,9 +512,9 @@ static void PrefilterInit(void) SCMutexUnlock(&g_prefilter_mutex); } -static int PrefilterStoreGetId(const char *name) +static int PrefilterStoreGetId(const char *name, void (*FreeFunc)(void *)) { - PrefilterStore ctx = { name, 0 }; + PrefilterStore ctx = { name, FreeFunc, 0 }; if (g_prefilter_hash_table == NULL) { PrefilterInit(); @@ -445,6 +536,7 @@ static int PrefilterStoreGetId(const char *name) } actx->name = name; + actx->FreeFunc = FreeFunc; actx->id = g_prefilter_id++; SCLogDebug("prefilter engine %s has profile id %u", actx->name, actx->id); @@ -460,6 +552,25 @@ static int PrefilterStoreGetId(const char *name) return r; } +/** \warning slow */ +static const PrefilterStore *PrefilterStoreGetStore(const uint32_t id) +{ + const PrefilterStore *store = NULL; + SCMutexLock(&g_prefilter_mutex); + if (g_prefilter_hash_table != NULL) { + HashListTableBucket *hb = HashListTableGetListHead(g_prefilter_hash_table); + for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + PrefilterStore *ctx = HashListTableGetListData(hb); + if (ctx->id == id) { + store = ctx; + break; + } + } + } + SCMutexUnlock(&g_prefilter_mutex); + return store; +} + /** \warning slow */ const char *PrefilterStoreGetName(const uint32_t id) { @@ -478,4 +589,3 @@ const char *PrefilterStoreGetName(const uint32_t id) SCMutexUnlock(&g_prefilter_mutex); return name; } -#endif /* PROFILING */ diff --git a/src/detect-engine-prefilter.h b/src/detect-engine-prefilter.h index 7836bab39a1c..b058cf738eb6 100644 --- a/src/detect-engine-prefilter.h +++ b/src/detect-engine-prefilter.h @@ -43,9 +43,10 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, void *pectx, void (*FreeFunc)(void *pectx), const char *name); -void PrefilterFreeEngines(PrefilterEngine *list); +void PrefilterFreeEnginesList(PrefilterEngineList *list); void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh); +void PrefilterCleanupRuleGroup(SigGroupHead *sgh); #ifdef PROFILING const char *PrefilterStoreGetName(const uint32_t id); diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 92d8dc66d447..0c49ef035a93 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -64,6 +64,11 @@ void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid) if (sghid->app_mpms != NULL) { SCFree(sghid->app_mpms); } + + PrefilterFreeEnginesList(sghid->tx_engines); + PrefilterFreeEnginesList(sghid->pkt_engines); + PrefilterFreeEnginesList(sghid->payload_engines); + SCFree(sghid); } @@ -174,10 +179,7 @@ void SigGroupHeadFree(SigGroupHead *sgh) sgh->init = NULL; } - PrefilterFreeEngines(sgh->tx_engines); - PrefilterFreeEngines(sgh->pkt_engines); - PrefilterFreeEngines(sgh->payload_engines); - + PrefilterCleanupRuleGroup(sgh); SCFree(sgh); return; diff --git a/src/detect.h b/src/detect.h index 222bc7620adf..b82c9bf53c8f 100644 --- a/src/detect.h +++ b/src/detect.h @@ -723,8 +723,8 @@ typedef struct DetectEngineCtx_ { struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; struct SCProfileSghDetectCtx_ *profile_sgh_ctx; uint32_t profile_match_logging_threshold; - uint32_t profile_prefilter_maxid; #endif + uint32_t prefilter_maxid; char config_prefix[64]; @@ -1019,7 +1019,7 @@ typedef struct MpmStore_ { } MpmStore; -typedef struct PrefilterEngine_ { +typedef struct PrefilterEngineList_ { uint16_t id; /** App Proto this engine applies to: only used with Tx Engines */ @@ -1037,15 +1037,39 @@ typedef struct PrefilterEngine_ { Packet *p, Flow *f, void *tx, const uint64_t idx, const uint8_t flags); - struct PrefilterEngine_ *next; + struct PrefilterEngineList_ *next; /** Free function for pectx data. If NULL the memory is not freed. */ void (*Free)(void *pectx); const char *name; -#ifdef PROFILING - uint32_t profile_id; -#endif + /* global id for this prefilter */ + uint32_t gid; +} PrefilterEngineList; + +typedef struct PrefilterEngine_ { + 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 */ + int tx_min_progress; + + /** 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); + void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *tx, + const uint64_t idx, const uint8_t flags); + } cb; + + /* global id for this prefilter */ + uint32_t gid; + int is_last; } PrefilterEngine; typedef struct SigGroupHeadInitData_ { @@ -1060,6 +1084,10 @@ typedef struct SigGroupHeadInitData_ { MpmCtx **app_mpms; + PrefilterEngineList *pkt_engines; + PrefilterEngineList *payload_engines; + PrefilterEngineList *tx_engines; + /* port ptr */ struct DetectPort_ *port; } SigGroupHeadInitData; @@ -1087,11 +1115,6 @@ typedef struct SigGroupHead_ { PrefilterEngine *payload_engines; PrefilterEngine *tx_engines; -#ifdef PROFILING - uint32_t engines_cnt; - uint32_t tx_engines_cnt; -#endif - /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ Signature **match_array; From 44022743f263712e99ee06b151b2e70c0f91579f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Sep 2016 17:16:38 +0200 Subject: [PATCH 1997/2553] http: track if request/response have trailers --- src/app-layer-htp.c | 21 +++++++++++++++++++++ src/app-layer-htp.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index d4c15359dafe..0f297df1fc48 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1918,6 +1918,24 @@ void HTPFreeConfig(void) SCReturn; } +static int HTPCallbackRequestHasTrailer(htp_tx_t *tx) +{ + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + htud->request_has_trailers = 1; + } + return HTP_OK; +} + +static int HTPCallbackResponseHasTrailer(htp_tx_t *tx) +{ + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + htud->response_has_trailers = 1; + } + return HTP_OK; +} + /** * \brief callback for request to store the recent incoming request in to the recent_in_tx for the given htp state @@ -2142,6 +2160,9 @@ static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec) htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData); htp_config_register_response_trailer_data(cfg_prec->cfg, HTPCallbackResponseHeaderData); + htp_config_register_request_trailer(cfg_prec->cfg, HTPCallbackRequestHasTrailer); + htp_config_register_response_trailer(cfg_prec->cfg, HTPCallbackResponseHasTrailer); + htp_config_register_request_body_data(cfg_prec->cfg, HTPCallbackRequestBodyData); htp_config_register_response_body_data(cfg_prec->cfg, HTPCallbackResponseBodyData); diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index a2ad92b9c06d..0e3503c3e8ee 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -192,6 +192,9 @@ typedef struct HtpTxUserData_ { uint8_t request_body_init; uint8_t response_body_init; + uint8_t request_has_trailers; + uint8_t response_has_trailers; + /* indicates which loggers that have logged */ uint32_t logged; From 358eacf14f4ccc7e5fb1633b7d4e284e92e69bb8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Sep 2016 17:24:02 +0200 Subject: [PATCH 1998/2553] http_header: only run trailer mpm if we have trailers --- src/detect-engine-hhd.c | 66 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 7a3af7e12ecb..d28016251ab2 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -250,6 +250,37 @@ static void PrefilterTxHttpRequestHeaders(DetectEngineThreadCtx *det_ctx, } } +static void PrefilterTxHttpRequestTrailers(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_headers == NULL) + return; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && !htud->request_has_trailers) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); @@ -259,7 +290,7 @@ int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) mpm_ctx, NULL, "http_header (request)"); if (r != 0) return r; - return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaders, + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestTrailers, ALPROTO_HTTP, HTP_REQUEST_TRAILER, mpm_ctx, NULL, "http_header (request)"); } @@ -299,6 +330,37 @@ static void PrefilterTxHttpResponseHeaders(DetectEngineThreadCtx *det_ctx, } } +static void PrefilterTxHttpResponseTrailers(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && !htud->response_has_trailers) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); @@ -308,7 +370,7 @@ int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) mpm_ctx, NULL, "http_header (response)"); if (r != 0) return r; - return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaders, + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseTrailers, ALPROTO_HTTP, HTP_RESPONSE_TRAILER, mpm_ctx, NULL, "http_header (response)"); } From d9811e58b6b4ef4fd5d4c96001ca4114a09813ab Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 28 Sep 2016 08:46:27 +0200 Subject: [PATCH 1999/2553] http_header: don't separately inspect trailer yet Currently the regular 'Header' inspection code will run each time after the HTTP progress moved beyond 'headers'. This will include the trailers if there are any. Leave the code in place as this model will change in the not too distant future. --- src/detect-engine-hhd.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index d28016251ab2..c4146169cc5b 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -249,7 +249,7 @@ static void PrefilterTxHttpRequestHeaders(DetectEngineThreadCtx *det_ctx, &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } } - +#if 0 static void PrefilterTxHttpRequestTrailers(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f, void *txv, @@ -280,7 +280,7 @@ static void PrefilterTxHttpRequestTrailers(DetectEngineThreadCtx *det_ctx, &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } } - +#endif int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); @@ -288,11 +288,14 @@ int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaders, ALPROTO_HTTP, HTP_REQUEST_HEADERS, mpm_ctx, NULL, "http_header (request)"); + return r; +#if 0 if (r != 0) return r; return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestTrailers, ALPROTO_HTTP, HTP_REQUEST_TRAILER, mpm_ctx, NULL, "http_header (request)"); +#endif } /** \brief HTTP Headers Mpm prefilter callback @@ -329,7 +332,7 @@ static void PrefilterTxHttpResponseHeaders(DetectEngineThreadCtx *det_ctx, &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } } - +#if 0 static void PrefilterTxHttpResponseTrailers(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f, void *txv, @@ -360,7 +363,7 @@ static void PrefilterTxHttpResponseTrailers(DetectEngineThreadCtx *det_ctx, &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } } - +#endif int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) { SCEnter(); @@ -368,11 +371,14 @@ int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaders, ALPROTO_HTTP, HTP_RESPONSE_HEADERS, mpm_ctx, NULL, "http_header (response)"); + return r; +#if 0 if (r != 0) return r; return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseTrailers, ALPROTO_HTTP, HTP_RESPONSE_TRAILER, mpm_ctx, NULL, "http_header (response)"); +#endif } int DetectEngineInspectHttpHeader(ThreadVars *tv, From 5bd906ae9f6cea9db02583786d26afcc6cfb86c1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 29 Sep 2016 14:17:22 +0200 Subject: [PATCH 2000/2553] doc: prefilter keyword and config --- doc/userguide/configuration/suricata-yaml.rst | 88 +++++++++++-------- doc/userguide/rules/index.rst | 1 + doc/userguide/rules/prefilter.rst | 13 +++ 3 files changed, 66 insertions(+), 36 deletions(-) create mode 100644 doc/userguide/rules/prefilter.rst diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index 7a574d1745aa..bf13de9ffec5 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -571,43 +571,17 @@ Detection engine Inspection configuration ~~~~~~~~~~~~~~~~~~~~~~~~ -The detection-engine builds internal groups of signatures. Suricata -loads signatures, with which the network traffic will be compared. The -fact is, that many rules certainly will not be necessary. (For -instance: if there appears a packet with the UDP-protocol, all -signatures for the TCP-protocol won't be needed.) For that reason, -all signatures will be divided in groups. However, a distribution -containing many groups will make use of a lot of memory. Not every -type of signature gets its own group. There is a possibility that -different signatures with several properties in common, will be placed -together in a group. The quantity of groups will determine the -balance between memory and performance. A small amount of groups will -lower the performance yet uses little memory. The opposite counts for -a higher amount of groups. The engine allows you to manage the balance -between memory and performance. To manage this, (by determining the -amount of groups) there are several general options:high for good -performance and more use of memory, low for low performance and little -use of memory. The option medium is the balance between performance -and memory usage. This is the default setting.The option custom is for -advanced users. This option has eight values which can be managed by -the user. - -:: - - detect-engine: - -profile: medium #The balance between performance and memory usage. This is the default setting. - - custom-values: - toclient_src_groups: 2 - toclient_dst_groups: 2 - toclient_sp_groups: 2 - toclient_dp_groups: 3 - toserver_src_groups: 2 - toserver_dst_groups: 4 - toserver_sp_groups: 2 - toserver_dp_groups: 25 - - sgh-mpm-context: auto - - inspection-recursion-limit: 3000 +The detection-engine builds internal groups of signatures. Suricata loads signatures, with which the network traffic will be compared. The fact is, that many rules certainly will not be necessary. (For instance: if there appears a packet with the UDP-protocol, all signatures for the TCP-protocol won't be needed.) For that reason, all signatures will be divided in groups. However, a distribution containing many groups will make use of a lot of memory. Not every type of signature gets its own group. There is a possibility that different signatures with several properties in common, will be placed together in a group. The quantity of groups will determine the balance between memory and performance. A small amount of groups will lower the performance yet uses little memory. The opposite counts for a higher amount of groups. The engine allows you to manage the balance between memory and performance. To manage this, (by determining the amount of groups) there are several general options:high for good performance and more use of memory, low for low performance and little use of memory. The option medium is the balance between performance and memory usage. This is the default setting.The option custom is for advanced users. This option has values which can be managed by the user. +:: + + detect: + profile: medium + custom-values: + toclient-groups: 2 + toserver-groups: 25 + sgh-mpm-context: auto + inspection-recursion-limit: 3000 At all of these options, you can add (or change) a value. Most signatures have the adjustment to focus on one direction, meaning @@ -657,6 +631,48 @@ option inspection-recursion-limit you can limit this action. .. image:: suricata-yaml/grouping_tree_detail.png +.. _suricata-yaml-prefilter: + +Prefilter Engines +~~~~~~~~~~~~~~~~~ + +The concept of prefiltering is that there are far too many rules to inspect individually. The approach prefilter takes is that from each rule one condition is added to prefilter, which is then checked in one step. The most common example is MPM (also known as fast_pattern). This takes a single pattern per rule and adds it to the MPM. Only for those rules that have at least one pattern match in the MPM stage, individual inspection is performed. + +Next to MPM, other types of keywords support prefiltering. ICMP itype, icode, icmp_seq and icmp_id for example. TCP window, IP TTL are other examples. + +For a full list of keywords that support prefilter, see: + +:: + + suricata --list-keywords=all + +Suricata can automatically select prefilter options, or it can be set manually. + +:: + + detect: + prefilter: + default: mpm + +By default, only MPM/fast_pattern is used. + +The prefilter engines for other non-MPM keywords can then be enabled in specific rules by using the 'prefilter' keyword. + +E.g. + +:: + + alert ip any any -> any any (ttl:123; prefilter; sid:1;) + +To let Suricata make these decisions set default to 'auto': + +:: + + detect: + prefilter: + default: auto + + CUDA (Compute United Device Architecture) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst index db477dd185e9..1aee1808978e 100644 --- a/doc/userguide/rules/index.rst +++ b/doc/userguide/rules/index.rst @@ -6,6 +6,7 @@ Suricata Rules intro meta header-keywords + prefilter payload-keywords http-keywords flow-keywords diff --git a/doc/userguide/rules/prefilter.rst b/doc/userguide/rules/prefilter.rst new file mode 100644 index 000000000000..0d136abbf789 --- /dev/null +++ b/doc/userguide/rules/prefilter.rst @@ -0,0 +1,13 @@ +Prefilter +========= + +The prefilter engines for other non-MPM keywords can be enabled in specific rules by using the 'prefilter' keyword. + +In the following rule the TTL test will be used in prefiltering instead of the single byte pattern: + +:: + + alert ip any any -> any any (ttl:123; prefilter; content:"a"; sid:1;) + +For more information on how to configure the prefilter engines, see :ref:`suricata-yaml-prefilter` + From a3ffebd8354c5c207f0a31b929dd2464aac53e22 Mon Sep 17 00:00:00 2001 From: kwong Date: Thu, 29 Sep 2016 13:15:54 -0400 Subject: [PATCH 2001/2553] Adding SCADA EtherNet/IP and CIP protocol support Add support for the ENIP/CIP Industrial protocol This is an app layer implementation which uses the "enip" protocol and "cip_service" and "enip_command" keywords Implements AFL entry points --- doc/userguide/rules/enip-keyword.rst | 40 ++ src/Makefile.am | 4 + src/app-layer-detect-proto.c | 4 + src/app-layer-enip-common.c | 947 +++++++++++++++++++++++++++ src/app-layer-enip-common.h | 250 +++++++ src/app-layer-enip.c | 605 +++++++++++++++++ src/app-layer-enip.h | 35 + src/app-layer-parser.c | 3 + src/app-layer-protos.c | 3 + src/app-layer-protos.h | 1 + src/detect-cipservice.c | 474 ++++++++++++++ src/detect-cipservice.h | 100 +++ src/detect-engine-enip.c | 375 +++++++++++ src/detect-engine-enip.h | 35 + src/detect-engine.c | 5 + src/detect-parse.c | 5 + src/detect.c | 12 + src/detect.h | 6 + src/suricata.c | 13 + src/util-error.c | 1 + src/util-error.h | 1 + suricata.yaml.in | 2 + 22 files changed, 2921 insertions(+) create mode 100644 doc/userguide/rules/enip-keyword.rst create mode 100644 src/app-layer-enip-common.c create mode 100644 src/app-layer-enip-common.h create mode 100644 src/app-layer-enip.c create mode 100644 src/app-layer-enip.h create mode 100644 src/detect-cipservice.c create mode 100644 src/detect-cipservice.h create mode 100644 src/detect-engine-enip.c create mode 100644 src/detect-engine-enip.h diff --git a/doc/userguide/rules/enip-keyword.rst b/doc/userguide/rules/enip-keyword.rst new file mode 100644 index 000000000000..d37f26859f12 --- /dev/null +++ b/doc/userguide/rules/enip-keyword.rst @@ -0,0 +1,40 @@ +ENIP/CIP Keywords +============== + +The enip_command and cip_service keywords can be used for matching on various properties of +ENIP requests. + +There are three ways of using this keyword: + +* matching on ENIP command with the setting "enip_command"; +* matching on CIP Service with the setting "cip_service". +* matching both the ENIP command and the CIP Service with "enip_command" and "cip_service" together + + +For the ENIP command, we are matching against the command field found in the ENIP encapsulation. + +For the CIP Service, we use a maximum of 3 comma seperated values representing the Service, Class and Attribute. +These values are described in the CIP specification. CIP Classes are associated with their Service, and CIP Attributes +are associated with their Service. If you only need to match up until the Service, then only provide the Service value. +If you want to match to the CIP Attribute, then you must provide all 3 values. + + +Syntax:: + + enip_command: + cip_service: + enip_command:, cip_service: + + +Examples:: + + enip_command:99 + cip_service:75 + cip_service:16,246,6 + enip_command:111, cip_service:5 + + +(cf. http://read.pudn.com/downloads166/ebook/763211/EIP-CIP-V1-1.0.pdf) + +Information on the protocol can be found here: +http://literature.rockwellautomation.com/idc/groups/literature/documents/wp/enet-wp001_-en-p.pdf diff --git a/src/Makefile.am b/src/Makefile.am index 92b9472e1afc..d636765cff2f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,6 +19,8 @@ app-layer-detect-proto.c app-layer-detect-proto.h \ app-layer-dns-common.c app-layer-dns-common.h \ app-layer-dns-tcp.c app-layer-dns-tcp.h \ app-layer-dns-udp.c app-layer-dns-udp.h \ +app-layer-enip.c app-layer-enip.h \ +app-layer-enip-common.c app-layer-enip-common.h \ app-layer-events.c app-layer-events.h \ app-layer-ftp.c app-layer-ftp.h \ app-layer-htp-body.c app-layer-htp-body.h \ @@ -103,6 +105,7 @@ detect-engine-dcepayload.c detect-engine-dcepayload.h \ detect-engine-dns.c detect-engine-dns.h \ detect-engine-tls.c detect-engine-tls.h \ detect-engine-modbus.c detect-engine-modbus.h \ +detect-engine-enip.c detect-engine-enip.h \ detect-engine-event.c detect-engine-event.h \ detect-engine-file.c detect-engine-file.h \ detect-engine-filedata-smtp.c detect-engine-filedata-smtp.h \ @@ -222,6 +225,7 @@ detect-window.c detect-window.h \ detect-within.c detect-within.h \ detect-modbus.c detect-modbus.h \ detect-xbits.c detect-xbits.h \ +detect-cipservice.c detect-cipservice.h \ flow-bit.c flow-bit.h \ flow.c flow.h \ flow-hash.c flow-hash.h \ diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index cca1ae7a8f55..74e22d4ae08a 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -691,6 +691,8 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp printf(" alproto: ALPROTO_DNS\n"); else if (pp_pe->alproto == ALPROTO_MODBUS) printf(" alproto: ALPROTO_MODBUS\n"); + else if (pp_pe->alproto == ALPROTO_ENIP) + printf(" alproto: ALPROTO_ENIP\n"); else if (pp_pe->alproto == ALPROTO_TEMPLATE) printf(" alproto: ALPROTO_TEMPLATE\n"); else @@ -744,6 +746,8 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp printf(" alproto: ALPROTO_DNS\n"); else if (pp_pe->alproto == ALPROTO_MODBUS) printf(" alproto: ALPROTO_MODBUS\n"); + else if (pp_pe->alproto == ALPROTO_ENIP) + printf(" alproto: ALPROTO_ENIP\n"); else if (pp_pe->alproto == ALPROTO_TEMPLATE) printf(" alproto: ALPROTO_TEMPLATE\n"); else diff --git a/src/app-layer-enip-common.c b/src/app-layer-enip-common.c new file mode 100644 index 000000000000..72ebc00be23c --- /dev/null +++ b/src/app-layer-enip-common.c @@ -0,0 +1,947 @@ +/* Copyright (C) 2015 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 Kevin Wong + * + * App-layer parser for ENIP protocol common code + * + */ + +#include "suricata-common.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "util-byte.h" +#include "pkt-var.h" +#include "util-profiling.h" + +#include "app-layer-enip-common.h" + +/** + * \brief Extract 8 bits and move up the offset + * @param res + * @param input + * @param offset + */ +int ENIPExtractUint8(uint8_t *res, uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (*offset > (input_len - sizeof(uint8_t))) + { + SCLogDebug("ENIPExtractUint8: Parsing beyond payload length\n"); + return 0; + } + + *res = *(input + *offset); + *offset += sizeof(uint8_t); + return 1; +} + +/** + * \brief Extract 16 bits and move up the offset + * @param res + * @param input + * @param offset + */ +int ENIPExtractUint16(uint16_t *res, uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (*offset > (input_len - sizeof(uint16_t))) + { + SCLogDebug("ENIPExtractUint16: Parsing beyond payload length\n"); + return 0; + } + + ByteExtractUint16(res, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *) (input + *offset)); + *offset += sizeof(uint16_t); + return 1; +} + +/** + * \brief Extract 32 bits and move up the offset + * @param res + * @param input + * @param offset + */ +int ENIPExtractUint32(uint32_t *res, uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (*offset > (input_len - sizeof(uint32_t))) + { + SCLogDebug("ENIPExtractUint32: Parsing beyond payload length\n"); + return 0; + } + + ByteExtractUint32(res, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), + (const uint8_t *) (input + *offset)); + *offset += sizeof(uint32_t); + return 1; +} + +/** + * \brief Extract 64 bits and move up the offset + * @param res + * @param input + * @param offset + */ +int ENIPExtractUint64(uint64_t *res, uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (*offset > (input_len - sizeof(uint64_t))) + { + SCLogDebug("ENIPExtractUint64: Parsing beyond payload length\n"); + return 0; + } + + ByteExtractUint64(res, BYTE_LITTLE_ENDIAN, sizeof(uint64_t), + (const uint8_t *) (input + *offset)); + *offset += sizeof(uint64_t); + return 1; +} + + +/** + * \brief Create service entry, add to transaction + * @param tx Transaction + * @return service entry + */ +static CIPServiceEntry *CIPServiceAlloc(ENIPTransaction *tx) +{ + + CIPServiceEntry *svc = (CIPServiceEntry *) SCCalloc(1, + sizeof(CIPServiceEntry)); + if (unlikely(svc == NULL)) + return NULL; + + memset(svc, 0x00, sizeof(CIPServiceEntry)); + + TAILQ_INIT(&svc->segment_list); + TAILQ_INIT(&svc->attrib_list); + + TAILQ_INSERT_TAIL(&tx->service_list, svc, next); + tx->service_count++; + return svc; + +} + + +/** + * \brief Delete service entry + */ + +void CIPServiceFree(void *s) +{ + SCEnter(); + if (s) + { + CIPServiceEntry *svc = (CIPServiceEntry *) s; + + SegmentEntry *seg = NULL; + while ((seg = TAILQ_FIRST(&svc->segment_list))) + { + TAILQ_REMOVE(&svc->segment_list, seg, next); + SCFree(seg); + } + + AttributeEntry *attr = NULL; + while ((attr = TAILQ_FIRST(&svc->attrib_list))) + { + TAILQ_REMOVE(&svc->attrib_list, attr, next); + SCFree(attr); + } + + SCFree(s); + } + SCReturn; +} + + + +/** + * \brief Decode ENIP Encapsulation Header + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeENIPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data) +{ + int ret = 1; + + uint16_t offset = 0; //byte offset + + //Decode Encapsulation Header + uint16_t cmd; + uint16_t len; + uint32_t session; + uint32_t status; + uint64_t context; + uint32_t option; + if (ENIPExtractUint16(&cmd, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&len, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint32(&session, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint32(&status, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint64(&context, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint32(&option, input, &offset, input_len) != 1) + { + return 0; + } + + enip_data->header.command = cmd; + enip_data->header.length = len; + enip_data->header.session = session; + enip_data->header.status = status; + enip_data->header.context = context; + enip_data->header.option = option; + + switch (enip_data->header.command) + { + case NOP: + SCLogDebug("DecodeENIP - NOP\n"); + break; + case LIST_SERVICES: + SCLogDebug("DecodeENIP - LIST_SERVICES\n"); + break; + case LIST_IDENTITY: + SCLogDebug("DecodeENIP - LIST_IDENTITY\n"); + break; + case LIST_INTERFACES: + SCLogDebug("DecodeENIP - LIST_INTERFACES\n"); + break; + case REGISTER_SESSION: + SCLogDebug("DecodeENIP - REGISTER_SESSION\n"); + break; + case UNREGISTER_SESSION: + SCLogDebug("DecodeENIP - UNREGISTER_SESSION\n"); + break; + case SEND_RR_DATA: + SCLogDebug( + "DecodeENIP - SEND_RR_DATA - parse Common Packet Format\n"); + ret = DecodeCommonPacketFormatPDU(input, input_len, enip_data, + offset); + break; + case SEND_UNIT_DATA: + SCLogDebug( + "DecodeENIP - SEND UNIT DATA - parse Common Packet Format\n"); + ret = DecodeCommonPacketFormatPDU(input, input_len, enip_data, + offset); + break; + case INDICATE_STATUS: + SCLogDebug("DecodeENIP - INDICATE_STATUS\n"); + break; + case CANCEL: + SCLogDebug("DecodeENIP - CANCEL\n"); + break; + default: + SCLogDebug("DecodeENIP - UNSUPPORTED COMMAND 0x%x\n", + enip_data->header.command); + } + + return ret; +} + + +/** + * \brief Decode Common Packet Format + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCommonPacketFormatPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + + if (enip_data->header.length < sizeof(ENIPEncapDataHdr)) + { + SCLogDebug("DecodeCommonPacketFormat: Malformed ENIP packet\n"); + return 0; + } + + uint32_t handle; + uint16_t timeout; + uint16_t count; + if (ENIPExtractUint32(&handle, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&timeout, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&count, input, &offset, input_len) != 1) + { + return 0; + } + enip_data->encap_data_header.interface_handle = handle; + enip_data->encap_data_header.timeout = timeout; + enip_data->encap_data_header.item_count = count; + + uint16_t address_type; + uint16_t address_length; //length of connection id in bytes + uint32_t address_connectionid = 0; + uint32_t address_sequence = 0; + + if (ENIPExtractUint16(&address_type, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&address_length, input, &offset, input_len) != 1) + { + return 0; + } + + //depending on addr type, get connection id, sequence if needed. Can also use addr length too? + if (address_type == CONNECTION_BASED) + { //get 4 byte connection id + if (ENIPExtractUint32(&address_connectionid, input, &offset, input_len) != 1) + { + return 0; + } + } else if (address_type == SEQUENCE_ADDR_ITEM) + { // get 4 byte connection id and 4 byte sequence + if (ENIPExtractUint32(&address_connectionid, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint32(&address_sequence, input, &offset, input_len) != 1) + { + return 0; + } + } + + enip_data->encap_addr_item.type = address_type; + enip_data->encap_addr_item.length = address_length; + enip_data->encap_addr_item.conn_id = address_connectionid; + enip_data->encap_addr_item.sequence_num = address_sequence; + + uint16_t data_type; + uint16_t data_length; //length of data in bytes + uint16_t data_sequence_count; + + if (ENIPExtractUint16(&data_type, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&data_length, input, &offset, input_len) != 1) + { + return 0; + } + + enip_data->encap_data_item.type = data_type; + enip_data->encap_data_item.length = data_length; + + if (enip_data->encap_data_item.type == CONNECTED_DATA_ITEM) + { //connected data items have seq number + if (ENIPExtractUint16(&data_sequence_count, input, &offset, input_len) != 1) + { + return 0; + } + enip_data->encap_data_item.sequence_count = data_sequence_count; + } + + switch (enip_data->encap_data_item.type) + { + case CONNECTED_DATA_ITEM: + SCLogDebug( + "DecodeCommonPacketFormat - CONNECTED DATA ITEM - parse CIP\n"); + DecodeCIPPDU(input, input_len, enip_data, offset); + break; + case UNCONNECTED_DATA_ITEM: + SCLogDebug("DecodeCommonPacketFormat - UNCONNECTED DATA ITEM\n"); + DecodeCIPPDU(input, input_len, enip_data, offset); + break; + default: + SCLogDebug("DecodeCommonPacketFormat - UNKNOWN TYPE 0x%x\n\n", + enip_data->encap_data_item.type); + return 0; + } + + return 1; +} + +/** + * \brief Decode CIP packet + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ + +int DecodeCIPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (enip_data->encap_data_item.length == 0) + { + SCLogDebug("DecodeCIP: No CIP Data\n"); + return 0; + } + + if (offset > (input_len - sizeof(uint8_t))) + { + SCLogDebug("DecodeCIP: Parsing beyond payload length\n"); + return 0; + } + + uint8_t service = 0; + service = *(input + offset); + + //SCLogDebug("CIP Service 0x%x\n", service); + + //use service code first bit to determine request/response, no need to save or push offset + if (service >> 7) + { + ret = DecodeCIPResponsePDU(input, input_len, enip_data, offset); + } else + { + ret = DecodeCIPRequestPDU(input, input_len, enip_data, offset); + } + + return ret; +} + + + +/** + * \brief Decode CIP Request + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPRequestPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (enip_data->encap_data_item.length < sizeof(CIPReqHdr)) + { + SCLogDebug("DecodeCIPRequest - Malformed CIP Data\n"); + return 0; + } + + uint8_t service; //<-----CIP SERVICE + uint8_t path_size; + + if (ENIPExtractUint8(&service, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint8(&path_size, input, &offset, input_len) != 1) + { + return 0; + } + + if (service > MAX_CIP_SERVICE) + { // service codes of value 0x80 or greater are not permitted because in the CIP protocol the highest order bit is used to flag request(0)/response(1) + SCLogDebug("DecodeCIPRequest - INVALID CIP SERVICE 0x%x\n", service); + return 0; + } + + //reached maximum number of services + if (enip_data->service_count > 32) + { + SCLogDebug("DecodeCIPRequest: Maximum services reached\n"); + return 0; + } + + //save CIP data + CIPServiceEntry *node = CIPServiceAlloc(enip_data); + if (node == NULL) + { + SCLogDebug("DecodeCIPRequest: Unable to create CIP service\n"); + return 0; + } + node->direction = 0; + node->service = service; + node->request.path_size = path_size; + node->request.path_offset = offset; + // SCLogDebug("DecodeCIPRequestPDU: service 0x%x size %d\n", node->service, + // node->request.path_size); + + DecodeCIPRequestPathPDU(input, input_len, node, offset); + + offset += path_size * sizeof(uint16_t); //move offset past pathsize + + //list of CIP services is large and can be vendor specific, store CIP service anyways and let the rule decide the action + switch (service) + { + case CIP_RESERVED: + SCLogDebug("DecodeCIPRequest - CIP_RESERVED\n"); + break; + case CIP_GET_ATTR_ALL: + SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_ALL\n"); + break; + case CIP_GET_ATTR_LIST: + SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_LIST\n"); + break; + case CIP_SET_ATTR_LIST: + SCLogDebug("DecodeCIPRequest - CIP_SET_ATTR_LIST\n"); + break; + case CIP_RESET: + SCLogDebug("DecodeCIPRequest - CIP_RESET\n"); + break; + case CIP_START: + SCLogDebug("DecodeCIPRequest - CIP_START\n"); + break; + case CIP_STOP: + SCLogDebug("DecodeCIPRequest - CIP_STOP\n"); + break; + case CIP_CREATE: + SCLogDebug("DecodeCIPRequest - CIP_CREATE\n"); + break; + case CIP_DELETE: + SCLogDebug("DecodeCIPRequest - CIP_DELETE\n"); + break; + case CIP_MSP: + SCLogDebug("DecodeCIPRequest - CIP_MSP\n"); + DecodeCIPRequestMSPPDU(input, input_len, enip_data, offset); + break; + case CIP_APPLY_ATTR: + SCLogDebug("DecodeCIPRequest - CIP_APPLY_ATTR\n"); + break; + case CIP_KICK_TIMER: + SCLogDebug("DecodeCIPRequest - CIP_KICK_TIMER\n"); + break; + case CIP_OPEN_CONNECTION: + SCLogDebug("DecodeCIPRequest - CIP_OPEN_CONNECTION\n"); + break; + case CIP_CHANGE_START: + SCLogDebug("DecodeCIPRequest - CIP_CHANGE_START\n"); + break; + case CIP_GET_STATUS: + SCLogDebug("DecodeCIPRequest - CIP_GET_STATUS\n"); + break; + default: + SCLogDebug("DecodeCIPRequest - CIP SERVICE 0x%x\n", service); + } + + return ret; +} + + +/** + * \brief Deocde CIP Request Path + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @param cipserviced the cip service rule + * @return 1 Packet matches + * @return 0 Packet not match + */ +int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, + CIPServiceEntry *node, uint16_t offset) +{ + //SCLogDebug("DecodeCIPRequestPath: service 0x%x size %d length %d\n", + // node->service, node->request.path_size, input_len); + + if (node->request.path_size < 1) + { + //SCLogDebug("DecodeCIPRequestPath: empty path or CIP Response\n"); + return 0; + } + + int bytes_remain = node->request.path_size; + + uint8_t segment; + uint8_t reserved; //unused byte reserved by ODVA + + //8 bit fields + uint8_t req_path_class8; + uint8_t req_path_instance8; + uint8_t req_path_attr8; + + //16 bit fields + uint16_t req_path_class16; + uint16_t req_path_instance16; + + uint16_t class = 0; + + SegmentEntry *seg = NULL; + + while (bytes_remain > 0) + { + if (ENIPExtractUint8(&segment, input, &offset, input_len) != 1) + { + return 0; + } + switch (segment) + { //assume order is class then instance. Can have multiple + case PATH_CLASS_8BIT: + if (ENIPExtractUint8(&req_path_class8, input, &offset, input_len) != 1) + { + return 0; + } + class = (uint16_t) req_path_class8; + SCLogDebug("DecodeCIPRequestPathPDU: 8bit class 0x%x\n", class); + + seg = SCMalloc(sizeof(SegmentEntry)); + if (unlikely(seg == NULL)) + return 0; + seg->segment = segment; + seg->value = class; + TAILQ_INSERT_TAIL(&node->segment_list, seg, next); + + bytes_remain--; + break; + case PATH_INSTANCE_8BIT: + if (ENIPExtractUint8(&req_path_instance8, input, &offset, input_len) != 1) + { + return 0; + } + //skip instance, don't need to store + bytes_remain--; + break; + case PATH_ATTR_8BIT: //single attribute + if (ENIPExtractUint8(&req_path_attr8, input, &offset, input_len) != 1) + { + return 0; + } + //uint16_t attrib = (uint16_t) req_path_attr8; + //SCLogDebug("DecodeCIPRequestPath: 8bit attr 0x%x\n", attrib); + + seg = SCMalloc(sizeof(SegmentEntry)); + if (unlikely(seg == NULL)) + return 0; + seg->segment = segment; + seg->value = class; + TAILQ_INSERT_TAIL(&node->segment_list, seg, next); + + bytes_remain--; + break; + case PATH_CLASS_16BIT: + if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) //skip reserved + { + return 0; + } + if (ENIPExtractUint16(&req_path_class16, input, &offset, input_len) != 1) + { + return 0; + } + class = req_path_class16; + SCLogDebug("DecodeCIPRequestPath: 16bit class 0x%x\n", class); + + seg = SCMalloc(sizeof(SegmentEntry)); + if (unlikely(seg == NULL)) + return 0; + seg->segment = segment; + seg->value = class; + TAILQ_INSERT_TAIL(&node->segment_list, seg, next); + if (bytes_remain >= 2) + { + bytes_remain = bytes_remain - 2; + } else + { + bytes_remain = 0; + } + break; + case PATH_INSTANCE_16BIT: + if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) // skip reserved + { + return 0; + } + if (ENIPExtractUint16(&req_path_instance16, input, &offset, input_len) != 1) + { + return 0; + } + //skip instance, don't need to store + if (bytes_remain >= 2) + { + bytes_remain = bytes_remain - 2; + } else + { + bytes_remain = 0; + } + break; + default: + SCLogDebug( + "DecodeCIPRequestPath: UNKNOWN SEGMENT 0x%x service 0x%x\n", + segment, node->service); + return 0; + } + } + + if ((node->service == CIP_SET_ATTR_LIST) || (node->service + == CIP_GET_ATTR_LIST)) + { + uint16_t attr_list_count; + uint16_t attribute; + //parse get/set attribute list + + if (ENIPExtractUint16(&attr_list_count, input, &offset, input_len) != 1) + { + return 0; + } + SCLogDebug("DecodeCIPRequestPathPDU: attribute list count %d\n", + attr_list_count); + for (int i = 0; i < attr_list_count; i++) + { + if (ENIPExtractUint16(&attribute, input, &offset, input_len) != 1) + { + return 0; + } + SCLogDebug("DecodeCIPRequestPathPDU: attribute %d\n", attribute); + //save attrs + AttributeEntry *attr = SCMalloc(sizeof(AttributeEntry)); + if (unlikely(attr == NULL)) + return 0; + attr->attribute = attribute; + TAILQ_INSERT_TAIL(&node->attrib_list, attr, next); + + } + } + + return 1; +} + +/** + * \brief Decode CIP Response + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPResponsePDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (enip_data->encap_data_item.length < sizeof(CIPRespHdr)) + { + SCLogDebug("DecodeCIPResponse - Malformed CIP Data\n"); + return 0; + } + + uint8_t service; //<----CIP SERVICE + uint8_t reserved; //unused byte reserved by ODVA + uint16_t status; + + if (ENIPExtractUint8(&service, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&status, input, &offset, input_len) != 1) + { + return 0; + } + + //SCLogDebug("DecodeCIPResponse: service 0x%x\n",service); + service &= 0x7f; //strip off top bit to get service code. Responses have first bit as 1 + + SCLogDebug("CIP service 0x%x status 0x%x\n", service, status); + + //reached maximum number of services + if (enip_data->service_count > 32) + { + SCLogDebug("DecodeCIPRequest: Maximum services reached\n"); + return 0; + } + + //save CIP data + CIPServiceEntry *node = CIPServiceAlloc(enip_data); + if (node == NULL) + { + SCLogDebug("DecodeCIPRequest: Unable to create CIP service\n"); + return 0; + } + node->direction = 1; + node->service = service; + node->response.status = status; + + SCLogDebug("DecodeCIPResponsePDU: service 0x%x size %d\n", node->service, + node->request.path_size); + + //list of CIP services is large and can be vendor specific, store CIP service anyways and let the rule decide the action + switch (service) + { + case CIP_RESERVED: + SCLogDebug("DecodeCIPResponse - CIP_RESERVED\n"); + break; + case CIP_GET_ATTR_ALL: + SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_ALL\n"); + break; + case CIP_GET_ATTR_LIST: + SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_LIST\n"); + break; + case CIP_SET_ATTR_LIST: + SCLogDebug("DecodeCIPResponse - CIP_SET_ATTR_LIST\n"); + break; + case CIP_RESET: + SCLogDebug("DecodeCIPResponse - CIP_RESET\n"); + break; + case CIP_START: + SCLogDebug("DecodeCIPResponse - CIP_START\n"); + break; + case CIP_STOP: + SCLogDebug("DecodeCIPResponse - CIP_STOP\n"); + break; + case CIP_CREATE: + SCLogDebug("DecodeCIPResponse - CIP_CREATE\n"); + break; + case CIP_DELETE: + SCLogDebug("DecodeCIPResponse - CIP_DELETE\n"); + break; + case CIP_MSP: + SCLogDebug("DecodeCIPResponse - CIP_MSP\n"); + DecodeCIPResponseMSPPDU(input, input_len, enip_data, offset); + break; + case CIP_APPLY_ATTR: + SCLogDebug("DecodeCIPResponse - CIP_APPLY_ATTR\n"); + break; + case CIP_KICK_TIMER: + SCLogDebug("DecodeCIPResponse - CIP_KICK_TIMER\n"); + break; + case CIP_OPEN_CONNECTION: + SCLogDebug("DecodeCIPResponse - CIP_OPEN_CONNECTION\n"); + break; + case CIP_CHANGE_START: + SCLogDebug("DecodeCIPResponse - CIP_CHANGE_START\n"); + break; + case CIP_GET_STATUS: + SCLogDebug("DecodeCIPResponse - CIP_GET_STATUS\n"); + break; + default: + SCLogDebug("DecodeCIPResponse - CIP SERVICE 0x%x\n", service); + } + + return ret; +} + + +/** + * \brief Decode CIP Request Multi Service Packet + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPRequestMSPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + if (offset >= (input_len - sizeof(uint16_t))) + { + SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length\n"); + return 0; + } + //use temp_offset just to grab the service offset, don't want to use and push offset + uint16_t temp_offset = offset; + uint16_t num_services; + ByteExtractUint16(&num_services, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *) (input + temp_offset)); + temp_offset += sizeof(uint16_t); + //SCLogDebug("DecodeCIPRequestMSP number of services %d\n",num_services); + + for (int svc = 1; svc < num_services + 1; svc++) + { + if (temp_offset >= (input_len - sizeof(uint16_t))) + { + SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length\n"); + return 0; + } + + uint16_t svc_offset; //read set of service offsets + ByteExtractUint16(&svc_offset, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *) (input + temp_offset)); + temp_offset += sizeof(uint16_t); + //SCLogDebug("parseCIPRequestMSP service %d offset %d\n",svc, svc_offset); + + DecodeCIPPDU(input, input_len, enip_data, offset + svc_offset); //parse CIP at found offset + } + + return ret; +} + + + +/** + * \brief Decode CIP Response MultiService Packet. + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPResponseMSPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (offset >= (input_len - sizeof(uint16_t))) + { + SCLogDebug("DecodeCIPResponseMSPPDU: Parsing beyond payload length\n"); + return 0; + } + //use temp_offset just to grab the service offset, don't want to use and push offset + uint16_t temp_offset = offset; + uint16_t num_services; + ByteExtractUint16(&num_services, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *) (input + temp_offset)); + temp_offset += sizeof(uint16_t); + //SCLogDebug("DecodeCIPResponseMSP number of services %d\n", num_services); + + for (int svc = 0; svc < num_services; svc++) + { + if (temp_offset >= (input_len - sizeof(uint16_t))) + { + SCLogDebug("DecodeCIPResponseMSP: Parsing beyond payload length\n"); + return 0; + } + + uint16_t svc_offset; //read set of service offsets + ByteExtractUint16(&svc_offset, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *) (input + temp_offset)); + temp_offset += sizeof(uint16_t); + //SCLogDebug("parseCIPResponseMSP service %d offset %d\n", svc, svc_offset); + + DecodeCIPPDU(input, input_len, enip_data, offset + svc_offset); //parse CIP at found offset + } + + return ret; +} diff --git a/src/app-layer-enip-common.h b/src/app-layer-enip-common.h new file mode 100644 index 000000000000..77777c8837ef --- /dev/null +++ b/src/app-layer-enip-common.h @@ -0,0 +1,250 @@ +/* Copyright (C) 2015 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 Kevin Wong + */ + +#ifndef __APP_LAYER_ENIP_COMMON_H__ +#define __APP_LAYER_ENIP_COMMON_H__ + +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "flow.h" +#include "queue.h" + +#define MAX_ENIP_CMD 65535 + +// EtherNet/IP commands +#define NOP 0x0000 +#define LIST_SERVICES 0x0004 +#define LIST_IDENTITY 0x0063 +#define LIST_INTERFACES 0x0064 +#define REGISTER_SESSION 0x0065 +#define UNREGISTER_SESSION 0x0066 +#define SEND_RR_DATA 0x006F +#define SEND_UNIT_DATA 0x0070 +#define INDICATE_STATUS 0x0072 +#define CANCEL 0x0073 + +//Common Packet Format Types +#define NULL_ADDR 0x0000 +#define CONNECTION_BASED 0x00a1 +#define CONNECTED_DATA_ITEM 0x00b1 +#define UNCONNECTED_DATA_ITEM 0x00b2 +#define SEQUENCE_ADDR_ITEM 0xB002 + +//status codes +#define SUCCESS 0x0000 +#define INVALID_CMD 0x0001 +#define NO_RESOURCES 0x0002 +#define INCORRECT_DATA 0x0003 +#define INVALID_SESSION 0x0064 +#define INVALID_LENGTH 0x0065 +#define UNSUPPORTED_PROT_REV 0x0069 + +#define MAX_CIP_SERVICE 127 +#define MAX_CIP_CLASS 65535 +#define MAX_CIP_ATTRIBUTE 65535 + +// CIP service codes +#define CIP_RESERVED 0x00 +#define CIP_GET_ATTR_ALL 0x01 +#define CIP_GET_ATTR_LIST 0x03 +#define CIP_SET_ATTR_LIST 0x04 +#define CIP_RESET 0x05 +#define CIP_START 0x06 +#define CIP_STOP 0x07 +#define CIP_CREATE 0x08 +#define CIP_DELETE 0x09 +#define CIP_MSP 0x0a +#define CIP_APPLY_ATTR 0x0d +#define CIP_GET_ATTR_SINGLE 0x0e +#define CIP_SET_ATTR_SINGLE 0x10 +#define CIP_KICK_TIMER 0x4b +#define CIP_OPEN_CONNECTION 0x4c +#define CIP_CHANGE_START 0x4f +#define CIP_GET_STATUS 0x50 + +//PATH sizing codes +#define PATH_CLASS_8BIT 0x20 +#define PATH_CLASS_16BIT 0x21 +#define PATH_INSTANCE_8BIT 0x24 +#define PATH_INSTANCE_16BIT 0x25 +#define PATH_ATTR_8BIT 0x30 +#define PATH_ATTR_16BIT 0x31 //possible value + +/** + * ENIP encapsulation header + */ +typedef struct ENIPEncapHdr_ +{ + uint64_t context; + uint32_t session; + uint32_t status; + uint32_t option; + uint16_t command; + uint16_t length; +} ENIPEncapHdr; + +/** + * ENIP encapsulation data header + */ +typedef struct ENIPEncapDataHdr_ +{ + uint32_t interface_handle; + uint16_t timeout; + uint16_t item_count; +} ENIPEncapDataHdr; + +/** + * ENIP encapsulation address item + */ +typedef struct ENIPEncapAddresItem_ +{ + uint16_t type; + uint16_t length; + uint16_t conn_id; + uint16_t sequence_num; +} ENIPEncapAddresItem; + +/** + * ENIP encapsulation data item + */ +typedef struct ENIPEncapDataItem_ +{ + uint16_t type; + uint16_t length; + uint16_t sequence_count; +} ENIPEncapDataItem; + +/** + * CIP Request Header + */ +typedef struct CIPReqHdr_ +{ + uint8_t service; + uint8_t path_size; +} CIPReqHdr; + +/** + * CIP Response Header + */ +typedef struct CIPRespHdr_ +{ + uint8_t service; + uint8_t pad; + uint8_t status; + uint8_t status_size; +} CIPRespHdr; + +typedef struct SegmentEntry_ +{ + uint16_t segment; //segment type + uint16_t value; //segment value (class or attribute) + +TAILQ_ENTRY(SegmentEntry_) next; +} SegmentEntry; + +typedef struct AttributeEntry_ +{ + uint16_t attribute; //segment class + +TAILQ_ENTRY(AttributeEntry_) next; +} AttributeEntry; + +typedef struct CIPServiceEntry_ +{ + uint8_t service; //cip service + uint8_t direction; + union + { + struct + { + uint8_t path_size; //cip path size + uint16_t path_offset; //offset to cip path + } request; + struct + { + uint8_t status; + } response; + }; + + TAILQ_HEAD(, SegmentEntry_) segment_list; /**< list for CIP segment */ + TAILQ_HEAD(, AttributeEntry_) attrib_list; /**< list for CIP segment */ + + TAILQ_ENTRY(CIPServiceEntry_) next; +} CIPServiceEntry; + +typedef struct ENIPTransaction_ +{ + struct ENIPState_ *enip; + uint16_t tx_num; /**< internal: id */ + uint16_t tx_id; /**< transaction id */ + uint16_t service_count; /**< transaction id */ + + ENIPEncapHdr header; //encapsulation header + ENIPEncapDataHdr encap_data_header; //encapsulation data header + ENIPEncapAddresItem encap_addr_item; //encapsulated address item + ENIPEncapDataItem encap_data_item; //encapsulated data item + + TAILQ_HEAD(, CIPServiceEntry_) service_list; /**< list for CIP */ + + AppLayerDecoderEvents *decoder_events; /**< per tx events */ + + TAILQ_ENTRY(ENIPTransaction_) next; + DetectEngineState *de_state; +} ENIPTransaction; + +/** \brief Per flow ENIP state container */ +typedef struct ENIPState_ +{ + TAILQ_HEAD(, ENIPTransaction_) tx_list; /**< transaction list */ + ENIPTransaction *curr; /**< ptr to current tx */ + ENIPTransaction *iter; + uint64_t transaction_max; + uint64_t tx_with_detect_state_cnt; + + uint16_t events; + uint16_t givenup; + + /* used by TCP only */ + uint16_t offset; + uint16_t record_len; + uint8_t *buffer; +} ENIPState; + +int DecodeENIPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data); +int DecodeCommonPacketFormatPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPRequestPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPResponsePDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, + CIPServiceEntry *node, uint16_t offset); +int DecodeCIPRequestMSPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPResponseMSPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); + +#endif /* __APP_LAYER_ENIP_COMMON_H__ */ diff --git a/src/app-layer-enip.c b/src/app-layer-enip.c new file mode 100644 index 000000000000..db50221a4c13 --- /dev/null +++ b/src/app-layer-enip.c @@ -0,0 +1,605 @@ +/* Copyright (C) 2015 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 Kevin Wong + * + * App-layer parser for ENIP protocol + * + */ + +#include "suricata-common.h" + +#include "util-debug.h" +#include "util-byte.h" +#include "util-enum.h" +#include "util-mem.h" +#include "util-misc.h" + +#include "stream.h" + +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer-enip.h" +#include "app-layer-enip-common.h" + +#include "app-layer-detect-proto.h" + +#include "conf.h" +#include "decode.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "util-byte.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "pkt-var.h" +#include "util-profiling.h" + + +SCEnumCharMap enip_decoder_event_table[ ] = { + { NULL, -1 }, +}; + +/** \brief get value for 'complete' status in ENIP + * + * For ENIP we use a simple bool. + */ +int ENIPGetAlstateProgress(void *tx, uint8_t direction) +{ + return 1; +} + +/** \brief get value for 'complete' status in ENIP + * + * For ENIP we use a simple bool. + */ +int ENIPGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return 1; +} + +DetectEngineState *ENIPGetTxDetectState(void *vtx) +{ + ENIPTransaction *tx = (ENIPTransaction *)vtx; + return tx->de_state; +} + +int ENIPSetTxDetectState(void *state, void *vtx, DetectEngineState *s) +{ + ENIPTransaction *tx = (ENIPTransaction *)vtx; + tx->de_state = s; + return 0; +} + +void *ENIPGetTx(void *alstate, uint64_t tx_id) { + ENIPState *enip = (ENIPState *) alstate; + ENIPTransaction *tx = NULL; + + if (enip->curr && enip->curr->tx_num == tx_id + 1) + return enip->curr; + + TAILQ_FOREACH(tx, &enip->tx_list, next) { + if (tx->tx_num != (tx_id+1)) + continue; + + SCLogDebug("returning tx %p", tx); + return tx; + } + + return NULL; +} + +uint64_t ENIPGetTxCnt(void *alstate) { + return ((uint64_t) ((ENIPState *) alstate)->transaction_max); +} + +AppLayerDecoderEvents *ENIPGetEvents(void *state, uint64_t id) { + ENIPState *enip = (ENIPState *) state; + ENIPTransaction *tx; + + if (enip->curr && enip->curr->tx_num == (id + 1)) + return enip->curr->decoder_events; + + TAILQ_FOREACH(tx, &enip->tx_list, next) { + if (tx->tx_num == (id+1)) + return tx->decoder_events; + } + + return NULL; +} + +int ENIPHasEvents(void *state) { + return (((ENIPState *) state)->events > 0); +} + +int ENIPStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type) { + *event_id = SCMapEnumNameToValue(event_name, enip_decoder_event_table); + + if (*event_id == -1) { + SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in " + "enip's enum map table.", event_name); + /* yes this is fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +/** \brief Allocate enip state + * + * return state + */ +void *ENIPStateAlloc(void) +{ + SCLogDebug("ENIPStateAlloc \n"); + void *s = SCMalloc(sizeof(ENIPState)); + if (unlikely(s == NULL)) + return NULL; + + memset(s, 0, sizeof(ENIPState)); + + ENIPState *enip_state = (ENIPState *) s; + + TAILQ_INIT(&enip_state->tx_list); + return s; +} + +/** \internal + * \brief Free a ENIP TX + * \param tx ENIP TX to free */ +static void ENIPTransactionFree(ENIPTransaction *tx, ENIPState *state) +{ + SCEnter(); + SCLogDebug("ENIPTransactionFree \n"); + CIPServiceEntry *svc = NULL; + while ((svc = TAILQ_FIRST(&tx->service_list))) + { + TAILQ_REMOVE(&tx->service_list, svc, next); + + SegmentEntry *seg = NULL; + while ((seg = TAILQ_FIRST(&svc->segment_list))) + { + TAILQ_REMOVE(&svc->segment_list, seg, next); + SCFree(seg); + } + + AttributeEntry *attr = NULL; + while ((attr = TAILQ_FIRST(&svc->attrib_list))) + { + TAILQ_REMOVE(&svc->attrib_list, attr, next); + SCFree(attr); + } + + SCFree(svc); + } + + AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + + if (tx->de_state != NULL) + { + DetectEngineStateFree(tx->de_state); + + state->tx_with_detect_state_cnt--; + } + + if (state->iter == tx) + state->iter = NULL; + + SCFree(tx); + SCReturn; +} + +/** \brief Free enip state + * + */ +void ENIPStateFree(void *s) +{ + SCEnter(); + SCLogDebug("ENIPStateFree \n"); + if (s) + { + ENIPState *enip_state = (ENIPState *) s; + + ENIPTransaction *tx = NULL; + while ((tx = TAILQ_FIRST(&enip_state->tx_list))) + { + TAILQ_REMOVE(&enip_state->tx_list, tx, next); + ENIPTransactionFree(tx, enip_state); + } + + if (enip_state->buffer != NULL) + { + SCFree(enip_state->buffer); + } + + SCFree(s); + } + SCReturn; +} + +/** \internal + * \brief Allocate a ENIP TX + * \retval tx or NULL */ +static ENIPTransaction *ENIPTransactionAlloc(ENIPState *state) +{ + SCLogDebug("ENIPStateTransactionAlloc \n"); + ENIPTransaction *tx = (ENIPTransaction *) SCCalloc(1, + sizeof(ENIPTransaction)); + if (unlikely(tx == NULL)) + return NULL; + + state->curr = tx; + state->transaction_max++; + + memset(tx, 0x00, sizeof(ENIPTransaction)); + TAILQ_INIT(&tx->service_list); + + tx->enip = state; + tx->tx_num = state->transaction_max; + tx->service_count = 0; + + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + + return tx; +} + +/** + * \brief enip transaction cleanup callback + */ +void ENIPStateTransactionFree(void *state, uint64_t tx_id) +{ + SCEnter(); + SCLogDebug("ENIPStateTransactionFree \n"); + ENIPState *enip_state = state; + ENIPTransaction *tx = NULL; + TAILQ_FOREACH(tx, &enip_state->tx_list, next) + { + + if ((tx_id+1) < tx->tx_num) + break; + else if ((tx_id+1) > tx->tx_num) + continue; + + if (tx == enip_state->curr) + enip_state->curr = NULL; + + if (tx->decoder_events != NULL) + { + if (tx->decoder_events->cnt <= enip_state->events) + enip_state->events -= tx->decoder_events->cnt; + else + enip_state->events = 0; + } + + TAILQ_REMOVE(&enip_state->tx_list, tx, next); + ENIPTransactionFree(tx, state); + break; + } + SCReturn; +} + +/** \internal + * + * \brief This function is called to retrieve a ENIP + * + * \param state ENIP state structure for the parser + * \param input Input line of the command + * \param input_len Length of the request + * + * \retval 1 when the command is parsed, 0 otherwise + */ +static int ENIPParse(Flow *f, void *state, AppLayerParserState *pstate, + uint8_t *input, uint32_t input_len, void *local_data) +{ + SCEnter(); + ENIPState *enip = (ENIPState *) state; + ENIPTransaction *tx; + + if (input == NULL && AppLayerParserStateIssetFlag(pstate, + APP_LAYER_PARSER_EOF)) + { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) + { + SCReturnInt(-1); + } + + while (input_len > 0) + { + tx = ENIPTransactionAlloc(enip); + if (tx == NULL) + SCReturnInt(0); + + SCLogDebug("ENIPParse input len %d\n", input_len); + DecodeENIPPDU(input, input_len, tx); + uint32_t pkt_len = tx->header.length + sizeof(ENIPEncapHdr); + SCLogDebug("ENIPParse packet len %d\n", pkt_len); + if (pkt_len > input_len) + { + SCLogDebug("Invalid packet length \n"); + break; + } + + input += pkt_len; + input_len -= pkt_len; + //SCLogDebug("remaining %d\n", input_len); + + if (input_len < sizeof(ENIPEncapHdr)) + { + //SCLogDebug("Not enough data\n"); //not enough data for ENIP + break; + } + } + + return 1; +} + + + +static uint16_t ENIPProbingParser(uint8_t *input, uint32_t input_len, + uint32_t *offset) +{ + // SCLogDebug("ENIPProbingParser %d\n", input_len); + if (input_len < sizeof(ENIPEncapHdr)) + { + printf("Length too small to be a ENIP header \n"); + return ALPROTO_UNKNOWN; + } + + return ALPROTO_ENIP; +} + +/** + * \brief Function to register the ENIP protocol parsers and other functions + */ +void RegisterENIPUDPParsers(void) +{ + SCEnter(); + char *proto_name = "enip"; + + if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) + { + AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name); + + if (RunmodeIsUnittests()) + { + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, + 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser); + + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, + 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser); + + } else + { + if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, + proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), + ENIPProbingParser)) + { + SCLogDebug( + "no ENIP UDP config found enabling ENIP detection on port 44818."); + + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", + ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, + ENIPProbingParser); + + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", + ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, + ENIPProbingParser); + } + } + + } else + { + printf("Protocol detection and parser disabled for %s protocol.", + proto_name); + return; + } + + if (AppLayerParserConfParserEnabled("udp", proto_name)) + { + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, + STREAM_TOSERVER, ENIPParse); + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, + STREAM_TOCLIENT, ENIPParse); + + AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_ENIP, + ENIPStateAlloc, ENIPStateFree); + + AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetEvents); + AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPHasEvents); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_ENIP, NULL, + ENIPGetTxDetectState, ENIPSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTx); + AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxCnt); + AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateTransactionFree); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetAlstateProgress); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_ENIP, ENIPGetAlstateProgressCompletionStatus); + + AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfo); + + AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_UDP, + ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT); + + } else + { + SCLogInfo( + "Parsed disabled for %s protocol. Protocol detection" "still on.", + proto_name); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_ENIP, ENIPParserRegisterTests); +#endif + + SCReturn; +} + +/** + * \brief Function to register the ENIP protocol parsers and other functions + */ +void RegisterENIPTCPParsers(void) +{ + SCEnter(); + char *proto_name = "enip"; + + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) + { + AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name); + + if (RunmodeIsUnittests()) + { + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, + 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, + 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser); + + } else + { + if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, + proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), + ENIPProbingParser)) + { + SCLogDebug( + "no ENIP TCP config found enabling ENIP detection on port 44818."); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", + ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, + ENIPProbingParser); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", + ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, + ENIPProbingParser); + } + } + + } else + { + SCLogDebug("Protocol detection and parser disabled for %s protocol.", + proto_name); + return; + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) + { + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, + STREAM_TOSERVER, ENIPParse); + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, + STREAM_TOCLIENT, ENIPParse); + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_ENIP, + ENIPStateAlloc, ENIPStateFree); + + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetEvents); + AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPHasEvents); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_ENIP, NULL, + ENIPGetTxDetectState, ENIPSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTx); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxCnt); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateTransactionFree); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetAlstateProgress); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_ENIP, ENIPGetAlstateProgressCompletionStatus); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateGetEventInfo); + + AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, + ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT); + } else + { + SCLogInfo( + "Parsed disabled for %s protocol. Protocol detection" "still on.", + proto_name); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_ENIP, ENIPParserRegisterTests); +#endif + + SCReturn; +} + +/* UNITTESTS */ +#ifdef UNITTESTS +#include "app-layer-parser.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "flow-util.h" +#include "stream-tcp.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static uint8_t listIdentity[] = {/* List ID */ 0x63, 0x00, + /* Length */ 0x00, 0x00, + /* Session */ 0x00, 0x00, 0x00, 0x00, + /* Status */ 0x00, 0x00, 0x00, 0x00, + /* Delay*/ 0x00, + /* Context */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Quantity of coils */ 0x00, 0x00, 0x00, 0x00, 0x00}; + +/** + * \brief Test if ENIP Packet matches signature + */ +int ALDecodeENIPTest(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_ENIP, STREAM_TOSERVER, + listIdentity, sizeof(listIdentity)); + FAIL_IF(r != 0); + + ENIPState *enip_state = f.alstate; + FAIL_IF_NULL(enip_state); + + ENIPTransaction *tx = ENIPGetTx(enip_state, 0); + FAIL_IF_NULL(tx); + + FAIL_IF(tx->header.command != 99); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + + PASS; +} + +#endif /* UNITTESTS */ + +void ENIPParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("ALDecodeENIPTest", ALDecodeENIPTest); +#endif /* UNITTESTS */ +} diff --git a/src/app-layer-enip.h b/src/app-layer-enip.h new file mode 100644 index 000000000000..d31cfb3aad0b --- /dev/null +++ b/src/app-layer-enip.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2015 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 Kevin Wong + */ + +#ifndef __APP_LAYER_ENIP_H__ +#define __APP_LAYER_ENIP_H__ + +#include "decode.h" +#include "detect-engine-state.h" +#include "queue.h" + +void RegisterENIPUDPParsers(void); +void RegisterENIPTCPParsers(void); +void ENIPParserRegisterTests(void); + +#endif /* __APP_LAYER_ENIP_H__ */ diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 36a2792f5b2b..410e1adfebde 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -58,6 +58,7 @@ #include "app-layer-dns-udp.h" #include "app-layer-dns-tcp.h" #include "app-layer-modbus.h" +#include "app-layer-enip.h" #include "app-layer-template.h" #include "conf.h" @@ -1191,6 +1192,8 @@ void AppLayerParserRegisterProtocolParsers(void) RegisterDNSUDPParsers(); RegisterDNSTCPParsers(); RegisterModbusParsers(); + RegisterENIPUDPParsers(); + RegisterENIPTCPParsers(); RegisterTemplateParsers(); /** IMAP */ diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index e8875643f879..50d1342c4923 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -75,6 +75,9 @@ const char *AppProtoToString(AppProto alproto) case ALPROTO_MODBUS: proto_name = "modbus"; break; + case ALPROTO_ENIP: + proto_name = "enip"; + break; case ALPROTO_TEMPLATE: proto_name = "template"; break; diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index aff90e9bbaf7..907bd8629b0e 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -42,6 +42,7 @@ enum AppProtoEnum { ALPROTO_DNS, ALPROTO_MODBUS, + ALPROTO_ENIP, ALPROTO_TEMPLATE, /* used by the probing parser when alproto detection fails diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c new file mode 100644 index 000000000000..1e738e6b57c8 --- /dev/null +++ b/src/detect-cipservice.c @@ -0,0 +1,474 @@ +/* Copyright (C) 2015 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 Kevin Wong + * + * Set up ENIP Commnad and CIP Service rule parsing and entry point for matching + */ + +#include "suricata-common.h" +#include "util-unittest.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "util-byte.h" + +#include "detect-cipservice.h" + + +/* + * CIP SERVICE CODE + */ + +/** + * \brief CIP Service Detect Prototypes + */ +static int DetectCipServiceSetup(DetectEngineCtx *, Signature *, char *); +static void DetectCipServiceFree(void *); +static void DetectCipServiceRegisterTests(void); + +/** + * \brief Registration function for cip_service: keyword + */ +void DetectCipServiceRegister(void) +{ + SCEnter(); + sigmatch_table[DETECT_CIPSERVICE].name = "cip_service"; //rule keyword + sigmatch_table[DETECT_CIPSERVICE].desc = "Rules for detecting CIP Service "; + sigmatch_table[DETECT_CIPSERVICE].Match = NULL; + sigmatch_table[DETECT_CIPSERVICE].AppLayerMatch = NULL; + sigmatch_table[DETECT_CIPSERVICE].Setup = DetectCipServiceSetup; + sigmatch_table[DETECT_CIPSERVICE].Free = DetectCipServiceFree; + sigmatch_table[DETECT_CIPSERVICE].RegisterTests + = DetectCipServiceRegisterTests; + + SCReturn; +} + +/** + * \brief This function is used to parse cip_service options passed via cip_service: keyword + * + * \param rulestr Pointer to the user provided rulestr options + * Takes comma seperated string with numeric tokens. Only first 3 are used + * + * \retval cipserviced pointer to DetectCipServiceData on success + * \retval NULL on failure + */ +DetectCipServiceData *DetectCipServiceParse(char *rulestr) +{ + const char delims[] = ","; + DetectCipServiceData *cipserviced = NULL; + + //SCLogDebug("DetectCipServiceParse - rule string %s\n", rulestr); + + cipserviced = SCMalloc(sizeof(DetectCipServiceData)); + if (unlikely(cipserviced == NULL)) + goto error; + + cipserviced->cipservice = 0; + cipserviced->cipclass = 0; + cipserviced->matchattribute = 1; + cipserviced->cipattribute = 0; + + char* token; + char *save; + int var; + int input[3]; + int i = 0; + + token = strtok_r(rulestr, delims, &save); + while (token != NULL) + { + if (i > 2) //for now only need 3 parameters + { + printf("DetectEnipCommandParse: Too many parameters\n"); + goto error; + } + + if (i < 2) //if on service or class + { + if (!isdigit((int) *token)) + { + printf("DetectCipServiceParse - Parameter Error %s\n", token); + goto error; + } + } else //if on attribute + { + + if (token[0] == '!') + { + cipserviced->matchattribute = 0; + token++; + } + + if (!isdigit((int) *token)) + { + printf("DetectCipServiceParse - Attribute Error %s\n", token); + goto error; + } + + } + + unsigned long num = atol(token); + if ((num > MAX_CIP_SERVICE) && (i == 0))//if service greater than 7 bit + { + printf("DetectEnipCommandParse: Invalid CIP service %lu\n", num); + goto error; + } else if ((num > MAX_CIP_CLASS) && (i == 1))//if service greater than 16 bit + { + printf("DetectEnipCommandParse: Invalid CIP class %lu\n", num); + goto error; + } else if ((num > MAX_CIP_ATTRIBUTE) && (i == 2))//if service greater than 16 bit + { + printf("DetectEnipCommandParse: Invalid CIP attribute %lu\n", num); + goto error; + } + + sscanf(token, "%d", &var); + input[i++] = var; + + token = strtok_r(NULL, delims, &save); + } + + cipserviced->cipservice = input[0]; + cipserviced->cipclass = input[1]; + cipserviced->cipattribute = input[2]; + cipserviced->tokens = i; + + SCLogDebug("DetectCipServiceParse - tokens %d\n", cipserviced->tokens); + SCLogDebug("DetectCipServiceParse - service %d\n", cipserviced->cipservice); + SCLogDebug("DetectCipServiceParse - class %d\n", cipserviced->cipclass); + SCLogDebug("DetectCipServiceParse - match attribute %d\n", + cipserviced->matchattribute); + SCLogDebug("DetectCipServiceParse - attribute %d\n", + cipserviced->cipattribute); + + SCReturnPtr(cipserviced, "DetectENIPFunction"); + +error: + if (cipserviced) + SCFree(cipserviced); + printf("DetectCipServiceParse - Error Parsing Parameters\n"); + SCReturnPtr(NULL, "DetectENIP"); +} + +/** + * \brief this function is used to a cipserviced the parsed cip_service data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rulestr pointer to the user provided cip_service options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectCipServiceSetup(DetectEngineCtx *de_ctx, Signature *s, + char *rulestr) +{ + SCEnter(); + + DetectCipServiceData *cipserviced = NULL; + SigMatch *sm = NULL; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_ENIP) + { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "rule contains conflicting keywords."); + goto error; + } + + cipserviced = DetectCipServiceParse(rulestr); + if (cipserviced == NULL) + goto error; + + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_CIPSERVICE; + sm->ctx = (void *) cipserviced; + + s->alproto = ALPROTO_ENIP; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_CIP_MATCH); + + SCReturnInt(0); + +error: + if (cipserviced != NULL) + DetectCipServiceFree(cipserviced); + if (sm != NULL) + SCFree(sm); + printf("DetectCipServiceSetup - Error\n"); + + SCReturnInt(-1); +} + +/** + * \brief this function will free memory associated with DetectCipServiceData + * + * \param ptr pointer to DetectCipServiceData + */ +void DetectCipServiceFree(void *ptr) +{ + DetectCipServiceData *cipserviced = (DetectCipServiceData *) ptr; + SCFree(cipserviced); +} + +#ifdef UNITTESTS + +/** + * \test Test CIP Command parameter parsing + */ +static int DetectCipServiceParseTest01 (void) +{ + uint8_t res = 1; + + /*DetectCipServiceData *cipserviced = NULL; + cipserviced = DetectCipServiceParse("1"); + if (cipserviced != NULL) + { + if (cipserviced->cipservice == 1) + { + res = 1; + } + + DetectCipServiceFree(cipserviced); + } + */ + return res; +} + +/** + * \test Test CIP Service signature + */ +static int DetectCipServiceSignatureTest01 (void) +{ + uint8_t res = 0; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (cip_service:1; sid:1; rev:1;)"); + if (sig == NULL) + { + printf("parsing signature failed: "); + goto end; + } + + /* if we get here, all conditions pass */ + res = 1; +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return res; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for DetectCipService + */ +void DetectCipServiceRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectCipServiceParseTest01", + DetectCipServiceParseTest01); + UtRegisterTest("DetectCipServiceSignatureTest01", + DetectCipServiceSignatureTest01); +#endif /* UNITTESTS */ +} + +/* + * ENIP COMMAND CODE + */ + +/** + * \brief ENIP Commond Detect Prototypes + */ +static int DetectEnipCommandSetup(DetectEngineCtx *, Signature *, char *); +static void DetectEnipCommandFree(void *); +static void DetectEnipCommandRegisterTests(void); + +/** + * \brief Registration function for enip_command: keyword + */ +void DetectEnipCommandRegister(void) +{ + sigmatch_table[DETECT_ENIPCOMMAND].name = "enip_command"; //rule keyword + sigmatch_table[DETECT_ENIPCOMMAND].desc + = "Rules for detecting EtherNet/IP command"; + sigmatch_table[DETECT_ENIPCOMMAND].Match = NULL; + sigmatch_table[DETECT_ENIPCOMMAND].AppLayerMatch = NULL; + sigmatch_table[DETECT_ENIPCOMMAND].Setup = DetectEnipCommandSetup; + sigmatch_table[DETECT_ENIPCOMMAND].Free = DetectEnipCommandFree; + sigmatch_table[DETECT_ENIPCOMMAND].RegisterTests + = DetectEnipCommandRegisterTests; + +} + +/** + * \brief This function is used to parse cip_service options passed via enip_command: keyword + * + * \param rulestr Pointer to the user provided rulestr options + * Takes single single numeric value + * + * \retval enipcmdd pointer to DetectCipServiceData on success + * \retval NULL on failure + */ +DetectEnipCommandData *DetectEnipCommandParse(char *rulestr) +{ + DetectEnipCommandData *enipcmdd = NULL; + + enipcmdd = SCMalloc(sizeof(DetectEnipCommandData)); + if (unlikely(enipcmdd == NULL)) + goto error; + + if (isdigit((int) *rulestr)) + { + unsigned long cmd = atol(rulestr); + if (cmd > MAX_ENIP_CMD) //if command greater than 16 bit + { + //printf("DetectEnipCommandParse: Invalid ENIP command %lu\n", cmd); + goto error; + } + + enipcmdd->enipcommand = (uint16_t) atoi(rulestr); + + } else + { + goto error; + } + + return enipcmdd; + +error: + if (enipcmdd) + SCFree(enipcmdd); + //printf("DetectEnipCommandParse - Error Parsing Parameters\n"); + return NULL; +} + +/** + * \brief this function is used by enipcmdd to parse enip_command data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rulestr pointer to the user provided enip command options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectEnipCommandSetup(DetectEngineCtx *de_ctx, Signature *s, + char *rulestr) +{ + DetectEnipCommandData *enipcmdd = NULL; + SigMatch *sm = NULL; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_ENIP) + { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "rule contains conflicting keywords."); + goto error; + } + + enipcmdd = DetectEnipCommandParse(rulestr); + if (enipcmdd == NULL) + goto error; + + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_ENIPCOMMAND; + sm->ctx = (void *) enipcmdd; + + s->alproto = ALPROTO_ENIP; + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_ENIP_MATCH); + + SCReturnInt(0); + +error: + if (enipcmdd != NULL) + DetectEnipCommandFree(enipcmdd); + if (sm != NULL) + SCFree(sm); + printf("DetectEnipCommandSetup - Error\n"); + SCReturnInt(-1); +} + +/** + * \brief this function will free memory associated with DetectEnipCommandData + * + * \param ptr pointer to DetectEnipCommandData + */ +void DetectEnipCommandFree(void *ptr) +{ + DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *) ptr; + SCFree(enipcmdd); +} + +#ifdef UNITTESTS + +/** + * \test ENIP parameter test + */ + +static int DetectEnipCommandParseTest01 (void) +{ + DetectEnipCommandData *enipcmdd = NULL; + + enipcmdd = DetectEnipCommandParse("1"); + FAIL_IF_NULL(enipcmdd); + FAIL_IF_NOT(enipcmdd->enipcommand == 1); + + DetectEnipCommandFree(enipcmdd); + PASS; +} + +/** + * \test ENIP Command signature test + */ +static int DetectEnipCommandSignatureTest01 (void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (enip_command:1; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for DetectEnipCommand + */ +void DetectEnipCommandRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectEnipCommandParseTest01", + DetectEnipCommandParseTest01); + UtRegisterTest("DetectEnipCommandSignatureTest01", + DetectEnipCommandSignatureTest01); +#endif /* UNITTESTS */ +} diff --git a/src/detect-cipservice.h b/src/detect-cipservice.h new file mode 100644 index 000000000000..50bd9de6f143 --- /dev/null +++ b/src/detect-cipservice.h @@ -0,0 +1,100 @@ +/* Copyright (C) 2015 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 Kevin Wong + */ + +#ifndef _DETECT_CIPSERVICE_H +#define _DETECT_CIPSERVICE_H + +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "flow.h" +#include "queue.h" +#include "app-layer-enip-common.h" + +#define ENIP_PORT 44818 //standard EtherNet/IP port + +/** + * CIP Service rule data structure + */ +typedef struct DetectCipServiceData_ +{ + uint8_t cipservice; /* cip service type */ + uint16_t cipclass; + uint16_t cipattribute; + uint8_t matchattribute; /* whether to match on attribute*/ + uint8_t tokens; /* number of parameters*/ +} DetectCipServiceData; + +/** + * ENIP Command rule data structure + */ +typedef struct DetectEnipCommandData_ +{ + uint16_t enipcommand; /* enip command */ +} DetectEnipCommandData; + +void DetectCipServiceRegister(void); +void DetectEnipCommandRegister(void); + +/** + * link list node for storing CIP service data + */ +typedef struct CIPServiceData_ +{ + uint8_t service; //cip service + union + { + struct + { + uint8_t path_size; //cip path size + uint16_t path_offset; //offset to cip path + } request; + struct + { + uint8_t status; + } response; + }; + struct CIPServiceData* next; +} CIPServiceData; + +/** + * ENIP data structure + */ +typedef struct ENIPData_ +{ + int direction; + ENIPEncapHdr header; //encapsulation header + ENIPEncapDataHdr encap_data_header; //encapsulation data header + ENIPEncapAddresItem encap_addr_item; //encapsulated address item + ENIPEncapDataItem encap_data_item; //encapsulated data item + + CIPServiceData* service_head; //head of cip service data list + CIPServiceData* service_tail; //tail of cip service data list + +} ENIPData; + +/** + * Add new CIPServiceData node to link list + */ +CIPServiceData *CreateCIPServiceData(ENIPData *enip_data); + +#endif /* _DETECT_CIPSERVICE_H */ diff --git a/src/detect-engine-enip.c b/src/detect-engine-enip.c new file mode 100644 index 000000000000..4efcb49fd256 --- /dev/null +++ b/src/detect-engine-enip.c @@ -0,0 +1,375 @@ +/* Copyright (C) 2015 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 Kevin Wong + * + * Based on detect-engine-modbus.c + */ + +#include "suricata-common.h" + +#include "app-layer.h" + +#include "detect.h" +#include "detect-cipservice.h" +#include "detect-engine-enip.h" + +#include "flow.h" + +#include "util-debug.h" + +/** + * \brief Print fields from ENIP Packet + * @param enip_data + */ +void PrintENIPAL(ENIPTransaction *enip_data) +{ + SCLogDebug("============================================\n"); + SCLogDebug("ENCAP HEADER cmd 0x%x, length %d, session 0x%x, status 0x%x\n", + enip_data->header.command, enip_data->header.length, + enip_data->header.session, enip_data->header.status); + //SCLogDebug("context 0x%x option 0x%x\n", enip_data->header.context, enip_data->header.option); + SCLogDebug("ENCAP DATA HEADER handle 0x%x, timeout %d, count %d\n", + enip_data->encap_data_header.interface_handle, + enip_data->encap_data_header.timeout, + enip_data->encap_data_header.item_count); + SCLogDebug("ENCAP ADDR ITEM type 0x%x, length %d \n", + enip_data->encap_addr_item.type, enip_data->encap_addr_item.length); + SCLogDebug("ENCAP DATA ITEM type 0x%x, length %d sequence 0x%x\n", + enip_data->encap_data_item.type, enip_data->encap_data_item.length, + enip_data->encap_data_item.sequence_count); + + CIPServiceEntry *svc = NULL; + + int count = 0; + TAILQ_FOREACH(svc, &enip_data->service_list, next) + { + //SCLogDebug("CIP Service #%d : 0x%x\n", count, svc->service); + count++; + } +} + +/** + * \brief Matches the rule to the CIP segment in ENIP Packet + * @param svc - the CIP service entry + * * @param cipserviced - the CIP service rule + */ +int CIPPathMatch(CIPServiceEntry *svc, DetectCipServiceData *cipserviced) +{ + + uint16_t class = 0; + uint16_t attrib = 0; + int found_class = 0; + + SegmentEntry *seg = NULL; + TAILQ_FOREACH(seg, &svc->segment_list, next) + { + switch(seg->segment) + { + case PATH_CLASS_8BIT: + class = seg->value; + if (cipserviced->cipclass == class) + { + if (cipserviced->tokens == 2) + {// if rule only has class + return 1; + } else + { + found_class = 1; + } + } + break; + case PATH_INSTANCE_8BIT: + break; + case PATH_ATTR_8BIT: //single attribute + attrib = seg->value; + if ((cipserviced->tokens == 3) && + (cipserviced->cipclass == class) && + (cipserviced->cipattribute == attrib) && + (cipserviced->matchattribute == 1)) + { // if rule has class & attribute, matched all here + return 1; + } + if ((cipserviced->tokens == 3) && + (cipserviced->cipclass == class) && + (cipserviced->matchattribute == 0)) + { // for negation rule on attribute + return 1; + } + break; + case PATH_CLASS_16BIT: + class = seg->value; + if (cipserviced->cipclass == class) + { + if (cipserviced->tokens == 2) + {// if rule only has class + return 1; + } else + { + found_class = 1; + } + } + break; + case PATH_INSTANCE_16BIT: + break; + default: + return 0; + } + } + + if (found_class == 0) + { // if haven't matched class yet, no need to check attribute + return 0; + } + + if ((svc->service == CIP_SET_ATTR_LIST) || + (svc->service == CIP_GET_ATTR_LIST)) + { + AttributeEntry *attr = NULL; + TAILQ_FOREACH (attr, &svc->attrib_list, next) + { + if (cipserviced->cipattribute == attr->attribute) + { + return 1; + } + } + } + + return 0; +} + +/** + * \brief Matches the rule to the ENIP Transaction + * @param enip_data - the ENIP transation + * * @param cipserviced - the CIP service rule + */ + +int CIPServiceMatch(ENIPTransaction *enip_data, + DetectCipServiceData *cipserviced) +{ + int count = 1; + CIPServiceEntry *svc = NULL; + //SCLogDebug("CIPServiceMatchAL\n"); + TAILQ_FOREACH(svc, &enip_data->service_list, next) + { + SCLogDebug("CIPServiceMatchAL service #%d : 0x%x dir %d \n", count, svc->service, svc->direction); + + if (cipserviced->cipservice == svc->service) + { // compare service + //SCLogDebug("Rule Match for cip service %d\n",cipserviced->cipservice ); + if (cipserviced->tokens > 1) + { //if rule params have class and attribute + + + if ((svc->service == CIP_SET_ATTR_LIST) || (svc->service + == CIP_SET_ATTR_SINGLE) || (svc->service + == CIP_GET_ATTR_LIST) || (svc->service + == CIP_GET_ATTR_SINGLE)) + { //decode path + if (CIPPathMatch(svc, cipserviced) == 1) + { + if (svc->direction == 1) return 0; //don't match responses + + return 1; + } + } + } else + { + if (svc->direction == 1) return 0; //don't match responses + + // SCLogDebug("CIPServiceMatchAL found\n"); + return 1; + } + } + count++; + } + return 0; +} + +/** \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect ( and sm: SigMatch to inspect) + * \param f Flow + * \param flags App layer flags + * \param alstate App layer state + * \param txv Pointer to ENIP Transaction structure + * + * \retval 0 no match or 1 match + */ +int DetectEngineInspectCIP(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + SCEnter(); + + + ENIPTransaction *tx = (ENIPTransaction *) txv; + SigMatch *sm = s->sm_lists[DETECT_SM_LIST_CIP_MATCH]; + DetectCipServiceData *cipserviced = (DetectCipServiceData *) sm->ctx; + + if (cipserviced == NULL) + { + SCLogDebug("no cipservice state, no match"); + SCReturnInt(0); + } + // SCLogDebug("DetectEngineInspectCIP %d\n", cipserviced->cipservice); + + if (CIPServiceMatch(tx, cipserviced) == 1) + { + // SCLogDebug("DetectCIPServiceMatchAL found\n"); + SCReturnInt(1); + } + + SCReturnInt(0); +} + +/** \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect ( and sm: SigMatch to inspect) + * \param f Flow + * \param flags App layer flags + * \param alstate App layer state + * \param txv Pointer to ENIP Transaction structure + * + * \retval 0 no match or 1 match + */ + +int DetectEngineInspectENIP(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + SCEnter(); + + ENIPTransaction *tx = (ENIPTransaction *) txv; + SigMatch *sm = s->sm_lists[DETECT_SM_LIST_ENIP_MATCH]; + DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *) sm->ctx; + + if (enipcmdd == NULL) + { + SCLogDebug("no enipcommand state, no match"); + SCReturnInt(0); + } + + //SCLogDebug("DetectEngineInspectENIP %d, %d\n", enipcmdd->enipcommand, tx->header.command); + + if (enipcmdd->enipcommand == tx->header.command) + { + // SCLogDebug("DetectENIPCommandMatchAL found!\n"); + SCReturnInt(1); + } + + SCReturnInt(0); +} + +#ifdef UNITTESTS /* UNITTESTS */ +#include "app-layer-parser.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "flow-util.h" +#include "stream-tcp.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static uint8_t listIdentity[] = {/* List ID */ 0x00, 0x63, + /* Length */ 0x00, 0x00, + /* Session */ 0x00, 0x00, 0x00, 0x00, + /* Status */ 0x00, 0x00, 0x00, 0x00, + /* Delay*/ 0x00, + /* Context */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Quantity of coils */ 0x00, 0x00, 0x00, 0x00,}; + +/** \test Test code function. */ +static int DetectEngineInspectENIPTest01(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(listIdentity, sizeof(listIdentity), IPPROTO_TCP); + FAIL_IF_NULL(p); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_ENIP; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = de_ctx->sig_list = SigInit(de_ctx, "alert enip any any -> any any " + "(msg:\"Testing enip command\"; " + "enipcommand:99 ; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_ENIP, STREAM_TOSERVER, + listIdentity, sizeof(listIdentity)); + FAIL_IF(r != 0); + + ENIPState *enip_state = f.alstate; + FAIL_IF_NULL(enip_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF(!(PacketAlertCheck(p, 1))); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + + PASS; +} + +#endif /* UNITTESTS */ + +void DetectEngineInspectENIPRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectEngineInspectENIPTest01", DetectEngineInspectENIPTest01); +#endif /* UNITTESTS */ + return; +} diff --git a/src/detect-engine-enip.h b/src/detect-engine-enip.h new file mode 100644 index 000000000000..1d701d414d5a --- /dev/null +++ b/src/detect-engine-enip.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2015 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 Kevin Wong + */ + +#ifndef __DETECT_ENGINE_ENIP_H__ +#define __DETECT_ENGINE_ENIP_H__ + +int DetectEngineInspectCIP(ThreadVars *, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *, Signature *, + Flow *, uint8_t, void *, void *, uint64_t); + +int DetectEngineInspectENIP(ThreadVars *, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *, Signature *, + Flow *, uint8_t, void *, void *, uint64_t); + +void DetectEngineInspectENIPRegisterTests(void); +#endif /* __DETECT_ENGINE_ENIP_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 0a74031e2b76..52bee574fea1 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2533,6 +2533,11 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; + case DETECT_SM_LIST_CIP_MATCH: + return "cip"; + case DETECT_SM_LIST_ENIP_MATCH: + return "enip"; + case DETECT_SM_LIST_BASE64_DATA: return "base64_data"; diff --git a/src/detect-parse.c b/src/detect-parse.c index f71d7166b8be..5a476d10b93a 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1630,6 +1630,11 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (sig->sm_lists[DETECT_SM_LIST_APP_EVENT]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_CIP_MATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_ENIP_MATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; + if (!(sig->init_flags & SIG_FLAG_INIT_FLOW)) { sig->flags |= SIG_FLAG_TOSERVER; sig->flags |= SIG_FLAG_TOCLIENT; diff --git a/src/detect.c b/src/detect.c index 900f82438619..8dfd63f506f4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -186,6 +186,7 @@ #include "detect-ssl-version.h" #include "detect-ssl-state.h" #include "detect-modbus.h" +#include "detect-cipservice.h" #include "action-globals.h" #include "tm-threads.h" @@ -2186,6 +2187,10 @@ PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, int has_state SCLogDebug("packet/flow has smtp state"); (*mask) |= SIG_MASK_REQUIRE_SMTP_STATE; break; + case ALPROTO_ENIP: + SCLogDebug("packet/flow has enip state"); + (*mask) |= SIG_MASK_REQUIRE_ENIP_STATE; + break; case ALPROTO_TEMPLATE: SCLogDebug("packet/flow has template state"); (*mask) |= SIG_MASK_REQUIRE_TEMPLATE_STATE; @@ -2431,6 +2436,10 @@ static int SignatureCreateMask(Signature *s) s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; SCLogDebug("sig requires smtp state"); } + if (s->alproto == ALPROTO_ENIP) { + s->mask |= SIG_MASK_REQUIRE_ENIP_STATE; + SCLogDebug("sig requires enip state"); + } if (s->alproto == ALPROTO_TEMPLATE) { s->mask |= SIG_MASK_REQUIRE_TEMPLATE_STATE; SCLogDebug("sig requires template state"); @@ -2442,6 +2451,7 @@ static int SignatureCreateMask(Signature *s) (s->mask & SIG_MASK_REQUIRE_DNS_STATE) || (s->mask & SIG_MASK_REQUIRE_FTP_STATE) || (s->mask & SIG_MASK_REQUIRE_SMTP_STATE) || + (s->mask & SIG_MASK_REQUIRE_ENIP_STATE) || (s->mask & SIG_MASK_REQUIRE_TEMPLATE_STATE) || (s->mask & SIG_MASK_REQUIRE_TLS_STATE)) { @@ -4138,6 +4148,8 @@ void SigTableSetup(void) DetectDnsQueryRegister(); DetectModbusRegister(); + DetectCipServiceRegister(); + DetectEnipCommandRegister(); DetectTlsSniRegister(); DetectTlsIssuerRegister(); diff --git a/src/detect.h b/src/detect.h index b82c9bf53c8f..e71f72216502 100644 --- a/src/detect.h +++ b/src/detect.h @@ -136,6 +136,9 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_MODBUS_MATCH, + DETECT_SM_LIST_CIP_MATCH, + DETECT_SM_LIST_ENIP_MATCH, + DETECT_SM_LIST_BASE64_DATA, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, @@ -305,6 +308,7 @@ typedef struct DetectPort_ { #define SIG_MASK_REQUIRE_FTP_STATE (1<<11) #define SIG_MASK_REQUIRE_SMTP_STATE (1<<12) #define SIG_MASK_REQUIRE_TEMPLATE_STATE (1<<13) +#define SIG_MASK_REQUIRE_ENIP_STATE (1<<14) /* for now a uint8_t is enough */ #define SignatureMask uint16_t @@ -1319,6 +1323,8 @@ enum { DETECT_AL_TLS_CERT_ISSUER, DETECT_AL_TLS_CERT_SUBJECT, DETECT_AL_MODBUS, + DETECT_CIPSERVICE, + DETECT_ENIPCOMMAND, DETECT_XBITS, DETECT_BASE64_DECODE, diff --git a/src/suricata.c b/src/suricata.c index 596544902a84..2376decb158f 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -122,6 +122,7 @@ #include "app-layer-smtp.h" #include "app-layer-smb.h" #include "app-layer-modbus.h" +#include "app-layer-enip.h" #include "util-decode-der.h" #include "util-radix-tree.h" @@ -1158,6 +1159,8 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"afl-smb", required_argument, 0 , 0}, {"afl-modbus-request", required_argument, 0 , 0}, {"afl-modbus", required_argument, 0 , 0}, + {"afl-enip-request", required_argument, 0 , 0}, + {"afl-enip", required_argument, 0 , 0}, {"afl-mime", required_argument, 0 , 0}, {"afl-decoder-ppp", required_argument, 0 , 0}, @@ -1428,6 +1431,16 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerParserSetup(); RegisterModbusParsers(); exit(AppLayerParserFromFile(ALPROTO_MODBUS, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-enip-request") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterENIPTCPParsers(); + exit(AppLayerParserRequestFromFile(ALPROTO_ENIP, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-enip") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterENIPTCPParsers(); + exit(AppLayerParserFromFile(ALPROTO_ENIP, optarg)); #endif #ifdef AFLFUZZ_MIME } else if(strcmp((long_opts[option_index]).name, "afl-mime") == 0) { diff --git a/src/util-error.c b/src/util-error.c index 7e13f67d8a6e..82c820a335aa 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -297,6 +297,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_DNS_CONFIG); CASE_CODE (SC_ERR_MODBUS_CONFIG); CASE_CODE (SC_ERR_CONF_YAML_ERROR); + CASE_CODE (SC_ERR_ENIP_CONFIG); CASE_CODE (SC_ERR_CONF_NAME_TOO_LONG); CASE_CODE (SC_ERR_APP_LAYER_PROTOCOL_DETECTION); CASE_CODE (SC_ERR_PCIE_INIT_FAILED); diff --git a/src/util-error.h b/src/util-error.h index 6aef68cbb9bc..1b63e43554e2 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -319,6 +319,7 @@ typedef enum { SC_ERR_INVALID_HASH, SC_ERR_NO_SHA1_SUPPORT, SC_ERR_NO_SHA256_SUPPORT, + SC_ERR_ENIP_CONFIG, } SCError; const char *SCErrorToString(SCError); diff --git a/suricata.yaml.in b/suricata.yaml.in index a0a78eeb0843..a682da02dd35 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -831,6 +831,8 @@ app-layer: # response-body-limit: 4096 # double-decode-path: no # double-decode-query: no + enip: + enabled: no # Limit for the maximum number of asn1 frames to decode (default 256) asn1-max-frames: 256 From 6b1c21b115d1fb144d912c3a236e2f4de74dfa1f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 08:10:18 +0200 Subject: [PATCH 2002/2553] enip/cip: register inspect engines --- src/detect-cipservice.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c index 1e738e6b57c8..1db2a4259839 100644 --- a/src/detect-cipservice.c +++ b/src/detect-cipservice.c @@ -30,7 +30,7 @@ #include "util-byte.h" #include "detect-cipservice.h" - +#include "detect-engine-enip.h" /* * CIP SERVICE CODE @@ -58,6 +58,13 @@ void DetectCipServiceRegister(void) sigmatch_table[DETECT_CIPSERVICE].RegisterTests = DetectCipServiceRegisterTests; + DetectAppLayerInspectEngineRegister(ALPROTO_ENIP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_CIP_MATCH, + DetectEngineInspectCIP); + DetectAppLayerInspectEngineRegister(ALPROTO_ENIP, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_CIP_MATCH, + DetectEngineInspectCIP); + SCReturn; } @@ -322,6 +329,12 @@ void DetectEnipCommandRegister(void) sigmatch_table[DETECT_ENIPCOMMAND].RegisterTests = DetectEnipCommandRegisterTests; + DetectAppLayerInspectEngineRegister(ALPROTO_ENIP, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_ENIP_MATCH, + DetectEngineInspectENIP); + DetectAppLayerInspectEngineRegister(ALPROTO_ENIP, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_ENIP_MATCH, + DetectEngineInspectENIP); } /** From 050f36eaa5b8de1f63997654446f0ec1dd0eb445 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 08:14:00 +0200 Subject: [PATCH 2003/2553] enip: improve yaml --- suricata.yaml.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/suricata.yaml.in b/suricata.yaml.in index a682da02dd35..7fb4ac555900 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -831,6 +831,8 @@ app-layer: # response-body-limit: 4096 # double-decode-path: no # double-decode-query: no + + # SCADA EtherNet/IP and CIP protocol support enip: enabled: no From a2d8cfb5d39c979932b666a8090b9dc5be8201ec Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 08:15:12 +0200 Subject: [PATCH 2004/2553] doc: reorder rule docs --- doc/userguide/rules/index.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst index 1aee1808978e..4044ede56d92 100644 --- a/doc/userguide/rules/index.rst +++ b/doc/userguide/rules/index.rst @@ -13,12 +13,12 @@ Suricata Rules flowint file-keywords thresholding - rule-lua-scripting - adding-your-own-rules - live-rule-swap dns-keywords tls-keywords - normalized-buffers modbus-keyword dnp3-keywords + rule-lua-scripting + normalized-buffers + live-rule-swap + adding-your-own-rules snort-compatibility From 92b393ee9ad9b73d46d5d59e66ab6cc0371b8d02 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 08:18:22 +0200 Subject: [PATCH 2005/2553] doc: include enip page --- doc/userguide/rules/enip-keyword.rst | 2 +- doc/userguide/rules/index.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/userguide/rules/enip-keyword.rst b/doc/userguide/rules/enip-keyword.rst index d37f26859f12..fdcc6eec4b9d 100644 --- a/doc/userguide/rules/enip-keyword.rst +++ b/doc/userguide/rules/enip-keyword.rst @@ -1,5 +1,5 @@ ENIP/CIP Keywords -============== +================= The enip_command and cip_service keywords can be used for matching on various properties of ENIP requests. diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst index 4044ede56d92..1600014f6dd2 100644 --- a/doc/userguide/rules/index.rst +++ b/doc/userguide/rules/index.rst @@ -17,6 +17,7 @@ Suricata Rules tls-keywords modbus-keyword dnp3-keywords + enip-keyword rule-lua-scripting normalized-buffers live-rule-swap From 72b5da43137f4194251373c09a190960954ba210 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 08:23:39 +0200 Subject: [PATCH 2006/2553] enip/cip: improve output & style Remove printf, remove \n from SCLogDebug. Add SCLogError for rule parsing issues. Fix various style issues --- src/app-layer-enip-common.c | 162 ++++++++++++++++++------------------ src/app-layer-enip-common.h | 38 ++++----- src/app-layer-enip.c | 26 +++--- src/detect-cipservice.c | 31 +++---- src/detect-engine-enip.c | 35 ++++---- 5 files changed, 145 insertions(+), 147 deletions(-) diff --git a/src/app-layer-enip-common.c b/src/app-layer-enip-common.c index 72ebc00be23c..3af826814562 100644 --- a/src/app-layer-enip-common.c +++ b/src/app-layer-enip-common.c @@ -46,7 +46,7 @@ int ENIPExtractUint8(uint8_t *res, uint8_t *input, uint16_t *offset, uint32_t in if (*offset > (input_len - sizeof(uint8_t))) { - SCLogDebug("ENIPExtractUint8: Parsing beyond payload length\n"); + SCLogDebug("ENIPExtractUint8: Parsing beyond payload length"); return 0; } @@ -66,7 +66,7 @@ int ENIPExtractUint16(uint16_t *res, uint8_t *input, uint16_t *offset, uint32_t if (*offset > (input_len - sizeof(uint16_t))) { - SCLogDebug("ENIPExtractUint16: Parsing beyond payload length\n"); + SCLogDebug("ENIPExtractUint16: Parsing beyond payload length"); return 0; } @@ -87,7 +87,7 @@ int ENIPExtractUint32(uint32_t *res, uint8_t *input, uint16_t *offset, uint32_t if (*offset > (input_len - sizeof(uint32_t))) { - SCLogDebug("ENIPExtractUint32: Parsing beyond payload length\n"); + SCLogDebug("ENIPExtractUint32: Parsing beyond payload length"); return 0; } @@ -108,7 +108,7 @@ int ENIPExtractUint64(uint64_t *res, uint8_t *input, uint16_t *offset, uint32_t if (*offset > (input_len - sizeof(uint64_t))) { - SCLogDebug("ENIPExtractUint64: Parsing beyond payload length\n"); + SCLogDebug("ENIPExtractUint64: Parsing beyond payload length"); return 0; } @@ -232,43 +232,43 @@ int DecodeENIPPDU(uint8_t *input, uint32_t input_len, switch (enip_data->header.command) { case NOP: - SCLogDebug("DecodeENIP - NOP\n"); + SCLogDebug("DecodeENIP - NOP"); break; case LIST_SERVICES: - SCLogDebug("DecodeENIP - LIST_SERVICES\n"); + SCLogDebug("DecodeENIP - LIST_SERVICES"); break; case LIST_IDENTITY: - SCLogDebug("DecodeENIP - LIST_IDENTITY\n"); + SCLogDebug("DecodeENIP - LIST_IDENTITY"); break; case LIST_INTERFACES: - SCLogDebug("DecodeENIP - LIST_INTERFACES\n"); + SCLogDebug("DecodeENIP - LIST_INTERFACES"); break; case REGISTER_SESSION: - SCLogDebug("DecodeENIP - REGISTER_SESSION\n"); + SCLogDebug("DecodeENIP - REGISTER_SESSION"); break; case UNREGISTER_SESSION: - SCLogDebug("DecodeENIP - UNREGISTER_SESSION\n"); + SCLogDebug("DecodeENIP - UNREGISTER_SESSION"); break; case SEND_RR_DATA: SCLogDebug( - "DecodeENIP - SEND_RR_DATA - parse Common Packet Format\n"); + "DecodeENIP - SEND_RR_DATA - parse Common Packet Format"); ret = DecodeCommonPacketFormatPDU(input, input_len, enip_data, offset); break; case SEND_UNIT_DATA: SCLogDebug( - "DecodeENIP - SEND UNIT DATA - parse Common Packet Format\n"); + "DecodeENIP - SEND UNIT DATA - parse Common Packet Format"); ret = DecodeCommonPacketFormatPDU(input, input_len, enip_data, offset); break; case INDICATE_STATUS: - SCLogDebug("DecodeENIP - INDICATE_STATUS\n"); + SCLogDebug("DecodeENIP - INDICATE_STATUS"); break; case CANCEL: - SCLogDebug("DecodeENIP - CANCEL\n"); + SCLogDebug("DecodeENIP - CANCEL"); break; default: - SCLogDebug("DecodeENIP - UNSUPPORTED COMMAND 0x%x\n", + SCLogDebug("DecodeENIP - UNSUPPORTED COMMAND 0x%x", enip_data->header.command); } @@ -290,7 +290,7 @@ int DecodeCommonPacketFormatPDU(uint8_t *input, uint32_t input_len, if (enip_data->header.length < sizeof(ENIPEncapDataHdr)) { - SCLogDebug("DecodeCommonPacketFormat: Malformed ENIP packet\n"); + SCLogDebug("DecodeCommonPacketFormat: Malformed ENIP packet"); return 0; } @@ -380,15 +380,15 @@ int DecodeCommonPacketFormatPDU(uint8_t *input, uint32_t input_len, { case CONNECTED_DATA_ITEM: SCLogDebug( - "DecodeCommonPacketFormat - CONNECTED DATA ITEM - parse CIP\n"); + "DecodeCommonPacketFormat - CONNECTED DATA ITEM - parse CIP"); DecodeCIPPDU(input, input_len, enip_data, offset); break; case UNCONNECTED_DATA_ITEM: - SCLogDebug("DecodeCommonPacketFormat - UNCONNECTED DATA ITEM\n"); + SCLogDebug("DecodeCommonPacketFormat - UNCONNECTED DATA ITEM"); DecodeCIPPDU(input, input_len, enip_data, offset); break; default: - SCLogDebug("DecodeCommonPacketFormat - UNKNOWN TYPE 0x%x\n\n", + SCLogDebug("DecodeCommonPacketFormat - UNKNOWN TYPE 0x%x", enip_data->encap_data_item.type); return 0; } @@ -412,20 +412,20 @@ int DecodeCIPPDU(uint8_t *input, uint32_t input_len, if (enip_data->encap_data_item.length == 0) { - SCLogDebug("DecodeCIP: No CIP Data\n"); + SCLogDebug("DecodeCIP: No CIP Data"); return 0; } if (offset > (input_len - sizeof(uint8_t))) { - SCLogDebug("DecodeCIP: Parsing beyond payload length\n"); + SCLogDebug("DecodeCIP: Parsing beyond payload length"); return 0; } uint8_t service = 0; service = *(input + offset); - //SCLogDebug("CIP Service 0x%x\n", service); + //SCLogDebug("CIP Service 0x%x", service); //use service code first bit to determine request/response, no need to save or push offset if (service >> 7) @@ -456,7 +456,7 @@ int DecodeCIPRequestPDU(uint8_t *input, uint32_t input_len, if (enip_data->encap_data_item.length < sizeof(CIPReqHdr)) { - SCLogDebug("DecodeCIPRequest - Malformed CIP Data\n"); + SCLogDebug("DecodeCIPRequest - Malformed CIP Data"); return 0; } @@ -474,14 +474,14 @@ int DecodeCIPRequestPDU(uint8_t *input, uint32_t input_len, if (service > MAX_CIP_SERVICE) { // service codes of value 0x80 or greater are not permitted because in the CIP protocol the highest order bit is used to flag request(0)/response(1) - SCLogDebug("DecodeCIPRequest - INVALID CIP SERVICE 0x%x\n", service); + SCLogDebug("DecodeCIPRequest - INVALID CIP SERVICE 0x%x", service); return 0; } //reached maximum number of services if (enip_data->service_count > 32) { - SCLogDebug("DecodeCIPRequest: Maximum services reached\n"); + SCLogDebug("DecodeCIPRequest: Maximum services reached"); return 0; } @@ -489,14 +489,14 @@ int DecodeCIPRequestPDU(uint8_t *input, uint32_t input_len, CIPServiceEntry *node = CIPServiceAlloc(enip_data); if (node == NULL) { - SCLogDebug("DecodeCIPRequest: Unable to create CIP service\n"); + SCLogDebug("DecodeCIPRequest: Unable to create CIP service"); return 0; } node->direction = 0; node->service = service; node->request.path_size = path_size; node->request.path_offset = offset; - // SCLogDebug("DecodeCIPRequestPDU: service 0x%x size %d\n", node->service, + // SCLogDebug("DecodeCIPRequestPDU: service 0x%x size %d", node->service, // node->request.path_size); DecodeCIPRequestPathPDU(input, input_len, node, offset); @@ -507,53 +507,53 @@ int DecodeCIPRequestPDU(uint8_t *input, uint32_t input_len, switch (service) { case CIP_RESERVED: - SCLogDebug("DecodeCIPRequest - CIP_RESERVED\n"); + SCLogDebug("DecodeCIPRequest - CIP_RESERVED"); break; case CIP_GET_ATTR_ALL: - SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_ALL\n"); + SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_ALL"); break; case CIP_GET_ATTR_LIST: - SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_LIST\n"); + SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_LIST"); break; case CIP_SET_ATTR_LIST: - SCLogDebug("DecodeCIPRequest - CIP_SET_ATTR_LIST\n"); + SCLogDebug("DecodeCIPRequest - CIP_SET_ATTR_LIST"); break; case CIP_RESET: - SCLogDebug("DecodeCIPRequest - CIP_RESET\n"); + SCLogDebug("DecodeCIPRequest - CIP_RESET"); break; case CIP_START: - SCLogDebug("DecodeCIPRequest - CIP_START\n"); + SCLogDebug("DecodeCIPRequest - CIP_START"); break; case CIP_STOP: - SCLogDebug("DecodeCIPRequest - CIP_STOP\n"); + SCLogDebug("DecodeCIPRequest - CIP_STOP"); break; case CIP_CREATE: - SCLogDebug("DecodeCIPRequest - CIP_CREATE\n"); + SCLogDebug("DecodeCIPRequest - CIP_CREATE"); break; case CIP_DELETE: - SCLogDebug("DecodeCIPRequest - CIP_DELETE\n"); + SCLogDebug("DecodeCIPRequest - CIP_DELETE"); break; case CIP_MSP: - SCLogDebug("DecodeCIPRequest - CIP_MSP\n"); + SCLogDebug("DecodeCIPRequest - CIP_MSP"); DecodeCIPRequestMSPPDU(input, input_len, enip_data, offset); break; case CIP_APPLY_ATTR: - SCLogDebug("DecodeCIPRequest - CIP_APPLY_ATTR\n"); + SCLogDebug("DecodeCIPRequest - CIP_APPLY_ATTR"); break; case CIP_KICK_TIMER: - SCLogDebug("DecodeCIPRequest - CIP_KICK_TIMER\n"); + SCLogDebug("DecodeCIPRequest - CIP_KICK_TIMER"); break; case CIP_OPEN_CONNECTION: - SCLogDebug("DecodeCIPRequest - CIP_OPEN_CONNECTION\n"); + SCLogDebug("DecodeCIPRequest - CIP_OPEN_CONNECTION"); break; case CIP_CHANGE_START: - SCLogDebug("DecodeCIPRequest - CIP_CHANGE_START\n"); + SCLogDebug("DecodeCIPRequest - CIP_CHANGE_START"); break; case CIP_GET_STATUS: - SCLogDebug("DecodeCIPRequest - CIP_GET_STATUS\n"); + SCLogDebug("DecodeCIPRequest - CIP_GET_STATUS"); break; default: - SCLogDebug("DecodeCIPRequest - CIP SERVICE 0x%x\n", service); + SCLogDebug("DecodeCIPRequest - CIP SERVICE 0x%x", service); } return ret; @@ -572,12 +572,12 @@ int DecodeCIPRequestPDU(uint8_t *input, uint32_t input_len, int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, CIPServiceEntry *node, uint16_t offset) { - //SCLogDebug("DecodeCIPRequestPath: service 0x%x size %d length %d\n", + //SCLogDebug("DecodeCIPRequestPath: service 0x%x size %d length %d", // node->service, node->request.path_size, input_len); if (node->request.path_size < 1) { - //SCLogDebug("DecodeCIPRequestPath: empty path or CIP Response\n"); + //SCLogDebug("DecodeCIPRequestPath: empty path or CIP Response"); return 0; } @@ -613,7 +613,7 @@ int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, return 0; } class = (uint16_t) req_path_class8; - SCLogDebug("DecodeCIPRequestPathPDU: 8bit class 0x%x\n", class); + SCLogDebug("DecodeCIPRequestPathPDU: 8bit class 0x%x", class); seg = SCMalloc(sizeof(SegmentEntry)); if (unlikely(seg == NULL)) @@ -638,7 +638,7 @@ int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, return 0; } //uint16_t attrib = (uint16_t) req_path_attr8; - //SCLogDebug("DecodeCIPRequestPath: 8bit attr 0x%x\n", attrib); + //SCLogDebug("DecodeCIPRequestPath: 8bit attr 0x%x", attrib); seg = SCMalloc(sizeof(SegmentEntry)); if (unlikely(seg == NULL)) @@ -659,7 +659,7 @@ int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, return 0; } class = req_path_class16; - SCLogDebug("DecodeCIPRequestPath: 16bit class 0x%x\n", class); + SCLogDebug("DecodeCIPRequestPath: 16bit class 0x%x", class); seg = SCMalloc(sizeof(SegmentEntry)); if (unlikely(seg == NULL)) @@ -695,7 +695,7 @@ int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, break; default: SCLogDebug( - "DecodeCIPRequestPath: UNKNOWN SEGMENT 0x%x service 0x%x\n", + "DecodeCIPRequestPath: UNKNOWN SEGMENT 0x%x service 0x%x", segment, node->service); return 0; } @@ -712,7 +712,7 @@ int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, { return 0; } - SCLogDebug("DecodeCIPRequestPathPDU: attribute list count %d\n", + SCLogDebug("DecodeCIPRequestPathPDU: attribute list count %d", attr_list_count); for (int i = 0; i < attr_list_count; i++) { @@ -720,7 +720,7 @@ int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, { return 0; } - SCLogDebug("DecodeCIPRequestPathPDU: attribute %d\n", attribute); + SCLogDebug("DecodeCIPRequestPathPDU: attribute %d", attribute); //save attrs AttributeEntry *attr = SCMalloc(sizeof(AttributeEntry)); if (unlikely(attr == NULL)) @@ -749,7 +749,7 @@ int DecodeCIPResponsePDU(uint8_t *input, uint32_t input_len, if (enip_data->encap_data_item.length < sizeof(CIPRespHdr)) { - SCLogDebug("DecodeCIPResponse - Malformed CIP Data\n"); + SCLogDebug("DecodeCIPResponse - Malformed CIP Data"); return 0; } @@ -770,15 +770,15 @@ int DecodeCIPResponsePDU(uint8_t *input, uint32_t input_len, return 0; } - //SCLogDebug("DecodeCIPResponse: service 0x%x\n",service); + //SCLogDebug("DecodeCIPResponse: service 0x%x",service); service &= 0x7f; //strip off top bit to get service code. Responses have first bit as 1 - SCLogDebug("CIP service 0x%x status 0x%x\n", service, status); + SCLogDebug("CIP service 0x%x status 0x%x", service, status); //reached maximum number of services if (enip_data->service_count > 32) { - SCLogDebug("DecodeCIPRequest: Maximum services reached\n"); + SCLogDebug("DecodeCIPRequest: Maximum services reached"); return 0; } @@ -786,67 +786,67 @@ int DecodeCIPResponsePDU(uint8_t *input, uint32_t input_len, CIPServiceEntry *node = CIPServiceAlloc(enip_data); if (node == NULL) { - SCLogDebug("DecodeCIPRequest: Unable to create CIP service\n"); + SCLogDebug("DecodeCIPRequest: Unable to create CIP service"); return 0; } node->direction = 1; node->service = service; node->response.status = status; - SCLogDebug("DecodeCIPResponsePDU: service 0x%x size %d\n", node->service, + SCLogDebug("DecodeCIPResponsePDU: service 0x%x size %d", node->service, node->request.path_size); //list of CIP services is large and can be vendor specific, store CIP service anyways and let the rule decide the action switch (service) { case CIP_RESERVED: - SCLogDebug("DecodeCIPResponse - CIP_RESERVED\n"); + SCLogDebug("DecodeCIPResponse - CIP_RESERVED"); break; case CIP_GET_ATTR_ALL: - SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_ALL\n"); + SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_ALL"); break; case CIP_GET_ATTR_LIST: - SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_LIST\n"); + SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_LIST"); break; case CIP_SET_ATTR_LIST: - SCLogDebug("DecodeCIPResponse - CIP_SET_ATTR_LIST\n"); + SCLogDebug("DecodeCIPResponse - CIP_SET_ATTR_LIST"); break; case CIP_RESET: - SCLogDebug("DecodeCIPResponse - CIP_RESET\n"); + SCLogDebug("DecodeCIPResponse - CIP_RESET"); break; case CIP_START: - SCLogDebug("DecodeCIPResponse - CIP_START\n"); + SCLogDebug("DecodeCIPResponse - CIP_START"); break; case CIP_STOP: - SCLogDebug("DecodeCIPResponse - CIP_STOP\n"); + SCLogDebug("DecodeCIPResponse - CIP_STOP"); break; case CIP_CREATE: - SCLogDebug("DecodeCIPResponse - CIP_CREATE\n"); + SCLogDebug("DecodeCIPResponse - CIP_CREATE"); break; case CIP_DELETE: - SCLogDebug("DecodeCIPResponse - CIP_DELETE\n"); + SCLogDebug("DecodeCIPResponse - CIP_DELETE"); break; case CIP_MSP: - SCLogDebug("DecodeCIPResponse - CIP_MSP\n"); + SCLogDebug("DecodeCIPResponse - CIP_MSP"); DecodeCIPResponseMSPPDU(input, input_len, enip_data, offset); break; case CIP_APPLY_ATTR: - SCLogDebug("DecodeCIPResponse - CIP_APPLY_ATTR\n"); + SCLogDebug("DecodeCIPResponse - CIP_APPLY_ATTR"); break; case CIP_KICK_TIMER: - SCLogDebug("DecodeCIPResponse - CIP_KICK_TIMER\n"); + SCLogDebug("DecodeCIPResponse - CIP_KICK_TIMER"); break; case CIP_OPEN_CONNECTION: - SCLogDebug("DecodeCIPResponse - CIP_OPEN_CONNECTION\n"); + SCLogDebug("DecodeCIPResponse - CIP_OPEN_CONNECTION"); break; case CIP_CHANGE_START: - SCLogDebug("DecodeCIPResponse - CIP_CHANGE_START\n"); + SCLogDebug("DecodeCIPResponse - CIP_CHANGE_START"); break; case CIP_GET_STATUS: - SCLogDebug("DecodeCIPResponse - CIP_GET_STATUS\n"); + SCLogDebug("DecodeCIPResponse - CIP_GET_STATUS"); break; default: - SCLogDebug("DecodeCIPResponse - CIP SERVICE 0x%x\n", service); + SCLogDebug("DecodeCIPResponse - CIP SERVICE 0x%x", service); } return ret; @@ -867,7 +867,7 @@ int DecodeCIPRequestMSPPDU(uint8_t *input, uint32_t input_len, int ret = 1; if (offset >= (input_len - sizeof(uint16_t))) { - SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length\n"); + SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length"); return 0; } //use temp_offset just to grab the service offset, don't want to use and push offset @@ -876,13 +876,13 @@ int DecodeCIPRequestMSPPDU(uint8_t *input, uint32_t input_len, ByteExtractUint16(&num_services, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *) (input + temp_offset)); temp_offset += sizeof(uint16_t); - //SCLogDebug("DecodeCIPRequestMSP number of services %d\n",num_services); + //SCLogDebug("DecodeCIPRequestMSP number of services %d",num_services); for (int svc = 1; svc < num_services + 1; svc++) { if (temp_offset >= (input_len - sizeof(uint16_t))) { - SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length\n"); + SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length"); return 0; } @@ -890,7 +890,7 @@ int DecodeCIPRequestMSPPDU(uint8_t *input, uint32_t input_len, ByteExtractUint16(&svc_offset, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *) (input + temp_offset)); temp_offset += sizeof(uint16_t); - //SCLogDebug("parseCIPRequestMSP service %d offset %d\n",svc, svc_offset); + //SCLogDebug("parseCIPRequestMSP service %d offset %d",svc, svc_offset); DecodeCIPPDU(input, input_len, enip_data, offset + svc_offset); //parse CIP at found offset } @@ -915,7 +915,7 @@ int DecodeCIPResponseMSPPDU(uint8_t *input, uint32_t input_len, if (offset >= (input_len - sizeof(uint16_t))) { - SCLogDebug("DecodeCIPResponseMSPPDU: Parsing beyond payload length\n"); + SCLogDebug("DecodeCIPResponseMSPPDU: Parsing beyond payload length"); return 0; } //use temp_offset just to grab the service offset, don't want to use and push offset @@ -924,13 +924,13 @@ int DecodeCIPResponseMSPPDU(uint8_t *input, uint32_t input_len, ByteExtractUint16(&num_services, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *) (input + temp_offset)); temp_offset += sizeof(uint16_t); - //SCLogDebug("DecodeCIPResponseMSP number of services %d\n", num_services); + //SCLogDebug("DecodeCIPResponseMSP number of services %d", num_services); for (int svc = 0; svc < num_services; svc++) { if (temp_offset >= (input_len - sizeof(uint16_t))) { - SCLogDebug("DecodeCIPResponseMSP: Parsing beyond payload length\n"); + SCLogDebug("DecodeCIPResponseMSP: Parsing beyond payload length"); return 0; } @@ -938,7 +938,7 @@ int DecodeCIPResponseMSPPDU(uint8_t *input, uint32_t input_len, ByteExtractUint16(&svc_offset, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *) (input + temp_offset)); temp_offset += sizeof(uint16_t); - //SCLogDebug("parseCIPResponseMSP service %d offset %d\n", svc, svc_offset); + //SCLogDebug("parseCIPResponseMSP service %d offset %d", svc, svc_offset); DecodeCIPPDU(input, input_len, enip_data, offset + svc_offset); //parse CIP at found offset } diff --git a/src/app-layer-enip-common.h b/src/app-layer-enip-common.h index 77777c8837ef..dec1f0510a9c 100644 --- a/src/app-layer-enip-common.h +++ b/src/app-layer-enip-common.h @@ -156,29 +156,29 @@ typedef struct CIPRespHdr_ typedef struct SegmentEntry_ { - uint16_t segment; //segment type - uint16_t value; //segment value (class or attribute) + uint16_t segment; /**< segment type */ + uint16_t value; /**< segment value (class or attribute) */ -TAILQ_ENTRY(SegmentEntry_) next; + TAILQ_ENTRY(SegmentEntry_) next; } SegmentEntry; typedef struct AttributeEntry_ { - uint16_t attribute; //segment class + uint16_t attribute; /**< segment class */ -TAILQ_ENTRY(AttributeEntry_) next; + TAILQ_ENTRY(AttributeEntry_) next; } AttributeEntry; typedef struct CIPServiceEntry_ { - uint8_t service; //cip service + uint8_t service; /**< cip service */ uint8_t direction; union { struct { - uint8_t path_size; //cip path size - uint16_t path_offset; //offset to cip path + uint8_t path_size; /**< cip path size */ + uint16_t path_offset; /**< offset to cip path */ } request; struct { @@ -186,8 +186,8 @@ typedef struct CIPServiceEntry_ } response; }; - TAILQ_HEAD(, SegmentEntry_) segment_list; /**< list for CIP segment */ - TAILQ_HEAD(, AttributeEntry_) attrib_list; /**< list for CIP segment */ + TAILQ_HEAD(, SegmentEntry_) segment_list; /**< list for CIP segment */ + TAILQ_HEAD(, AttributeEntry_) attrib_list; /**< list for CIP segment */ TAILQ_ENTRY(CIPServiceEntry_) next; } CIPServiceEntry; @@ -195,18 +195,18 @@ typedef struct CIPServiceEntry_ typedef struct ENIPTransaction_ { struct ENIPState_ *enip; - uint16_t tx_num; /**< internal: id */ - uint16_t tx_id; /**< transaction id */ - uint16_t service_count; /**< transaction id */ + uint16_t tx_num; /**< internal: id */ + uint16_t tx_id; /**< transaction id */ + uint16_t service_count; - ENIPEncapHdr header; //encapsulation header - ENIPEncapDataHdr encap_data_header; //encapsulation data header - ENIPEncapAddresItem encap_addr_item; //encapsulated address item - ENIPEncapDataItem encap_data_item; //encapsulated data item + ENIPEncapHdr header; /**< encapsulation header */ + ENIPEncapDataHdr encap_data_header; /**< encapsulation data header */ + ENIPEncapAddresItem encap_addr_item; /**< encapsulated address item */ + ENIPEncapDataItem encap_data_item; /**< encapsulated data item */ TAILQ_HEAD(, CIPServiceEntry_) service_list; /**< list for CIP */ - AppLayerDecoderEvents *decoder_events; /**< per tx events */ + AppLayerDecoderEvents *decoder_events; /**< per tx events */ TAILQ_ENTRY(ENIPTransaction_) next; DetectEngineState *de_state; @@ -216,7 +216,7 @@ typedef struct ENIPTransaction_ typedef struct ENIPState_ { TAILQ_HEAD(, ENIPTransaction_) tx_list; /**< transaction list */ - ENIPTransaction *curr; /**< ptr to current tx */ + ENIPTransaction *curr; /**< ptr to current tx */ ENIPTransaction *iter; uint64_t transaction_max; uint64_t tx_with_detect_state_cnt; diff --git a/src/app-layer-enip.c b/src/app-layer-enip.c index db50221a4c13..a480d304db87 100644 --- a/src/app-layer-enip.c +++ b/src/app-layer-enip.c @@ -150,7 +150,7 @@ int ENIPStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventTy */ void *ENIPStateAlloc(void) { - SCLogDebug("ENIPStateAlloc \n"); + SCLogDebug("ENIPStateAlloc"); void *s = SCMalloc(sizeof(ENIPState)); if (unlikely(s == NULL)) return NULL; @@ -169,7 +169,7 @@ void *ENIPStateAlloc(void) static void ENIPTransactionFree(ENIPTransaction *tx, ENIPState *state) { SCEnter(); - SCLogDebug("ENIPTransactionFree \n"); + SCLogDebug("ENIPTransactionFree"); CIPServiceEntry *svc = NULL; while ((svc = TAILQ_FIRST(&tx->service_list))) { @@ -214,7 +214,7 @@ static void ENIPTransactionFree(ENIPTransaction *tx, ENIPState *state) void ENIPStateFree(void *s) { SCEnter(); - SCLogDebug("ENIPStateFree \n"); + SCLogDebug("ENIPStateFree"); if (s) { ENIPState *enip_state = (ENIPState *) s; @@ -241,7 +241,7 @@ void ENIPStateFree(void *s) * \retval tx or NULL */ static ENIPTransaction *ENIPTransactionAlloc(ENIPState *state) { - SCLogDebug("ENIPStateTransactionAlloc \n"); + SCLogDebug("ENIPStateTransactionAlloc"); ENIPTransaction *tx = (ENIPTransaction *) SCCalloc(1, sizeof(ENIPTransaction)); if (unlikely(tx == NULL)) @@ -268,7 +268,7 @@ static ENIPTransaction *ENIPTransactionAlloc(ENIPState *state) void ENIPStateTransactionFree(void *state, uint64_t tx_id) { SCEnter(); - SCLogDebug("ENIPStateTransactionFree \n"); + SCLogDebug("ENIPStateTransactionFree"); ENIPState *enip_state = state; ENIPTransaction *tx = NULL; TAILQ_FOREACH(tx, &enip_state->tx_list, next) @@ -329,23 +329,23 @@ static int ENIPParse(Flow *f, void *state, AppLayerParserState *pstate, if (tx == NULL) SCReturnInt(0); - SCLogDebug("ENIPParse input len %d\n", input_len); + SCLogDebug("ENIPParse input len %d", input_len); DecodeENIPPDU(input, input_len, tx); uint32_t pkt_len = tx->header.length + sizeof(ENIPEncapHdr); - SCLogDebug("ENIPParse packet len %d\n", pkt_len); + SCLogDebug("ENIPParse packet len %d", pkt_len); if (pkt_len > input_len) { - SCLogDebug("Invalid packet length \n"); + SCLogDebug("Invalid packet length"); break; } input += pkt_len; input_len -= pkt_len; - //SCLogDebug("remaining %d\n", input_len); + //SCLogDebug("remaining %d", input_len); if (input_len < sizeof(ENIPEncapHdr)) { - //SCLogDebug("Not enough data\n"); //not enough data for ENIP + //SCLogDebug("Not enough data"); //not enough data for ENIP break; } } @@ -358,10 +358,10 @@ static int ENIPParse(Flow *f, void *state, AppLayerParserState *pstate, static uint16_t ENIPProbingParser(uint8_t *input, uint32_t input_len, uint32_t *offset) { - // SCLogDebug("ENIPProbingParser %d\n", input_len); + // SCLogDebug("ENIPProbingParser %d", input_len); if (input_len < sizeof(ENIPEncapHdr)) { - printf("Length too small to be a ENIP header \n"); + SCLogDebug("length too small to be a ENIP header"); return ALPROTO_UNKNOWN; } @@ -409,7 +409,7 @@ void RegisterENIPUDPParsers(void) } else { - printf("Protocol detection and parser disabled for %s protocol.", + SCLogConfig("Protocol detection and parser disabled for %s protocol.", proto_name); return; } diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c index 1db2a4259839..2488bf30ffbb 100644 --- a/src/detect-cipservice.c +++ b/src/detect-cipservice.c @@ -82,7 +82,7 @@ DetectCipServiceData *DetectCipServiceParse(char *rulestr) const char delims[] = ","; DetectCipServiceData *cipserviced = NULL; - //SCLogDebug("DetectCipServiceParse - rule string %s\n", rulestr); + //SCLogDebug("DetectCipServiceParse - rule string %s", rulestr); cipserviced = SCMalloc(sizeof(DetectCipServiceData)); if (unlikely(cipserviced == NULL)) @@ -104,7 +104,7 @@ DetectCipServiceData *DetectCipServiceParse(char *rulestr) { if (i > 2) //for now only need 3 parameters { - printf("DetectEnipCommandParse: Too many parameters\n"); + SCLogError(SC_ERR_INVALID_SIGNATURE, "too many parameters"); goto error; } @@ -112,7 +112,7 @@ DetectCipServiceData *DetectCipServiceParse(char *rulestr) { if (!isdigit((int) *token)) { - printf("DetectCipServiceParse - Parameter Error %s\n", token); + SCLogError(SC_ERR_INVALID_SIGNATURE, "parameter error %s", token); goto error; } } else //if on attribute @@ -126,7 +126,7 @@ DetectCipServiceData *DetectCipServiceParse(char *rulestr) if (!isdigit((int) *token)) { - printf("DetectCipServiceParse - Attribute Error %s\n", token); + SCLogError(SC_ERR_INVALID_SIGNATURE, "attribute error %s", token); goto error; } @@ -135,15 +135,15 @@ DetectCipServiceData *DetectCipServiceParse(char *rulestr) unsigned long num = atol(token); if ((num > MAX_CIP_SERVICE) && (i == 0))//if service greater than 7 bit { - printf("DetectEnipCommandParse: Invalid CIP service %lu\n", num); + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid CIP service %lu", num); goto error; } else if ((num > MAX_CIP_CLASS) && (i == 1))//if service greater than 16 bit { - printf("DetectEnipCommandParse: Invalid CIP class %lu\n", num); + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid CIP class %lu", num); goto error; } else if ((num > MAX_CIP_ATTRIBUTE) && (i == 2))//if service greater than 16 bit { - printf("DetectEnipCommandParse: Invalid CIP attribute %lu\n", num); + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid CIP attribute %lu", num); goto error; } @@ -158,12 +158,12 @@ DetectCipServiceData *DetectCipServiceParse(char *rulestr) cipserviced->cipattribute = input[2]; cipserviced->tokens = i; - SCLogDebug("DetectCipServiceParse - tokens %d\n", cipserviced->tokens); - SCLogDebug("DetectCipServiceParse - service %d\n", cipserviced->cipservice); - SCLogDebug("DetectCipServiceParse - class %d\n", cipserviced->cipclass); - SCLogDebug("DetectCipServiceParse - match attribute %d\n", + SCLogDebug("DetectCipServiceParse - tokens %d", cipserviced->tokens); + SCLogDebug("DetectCipServiceParse - service %d", cipserviced->cipservice); + SCLogDebug("DetectCipServiceParse - class %d", cipserviced->cipclass); + SCLogDebug("DetectCipServiceParse - match attribute %d", cipserviced->matchattribute); - SCLogDebug("DetectCipServiceParse - attribute %d\n", + SCLogDebug("DetectCipServiceParse - attribute %d", cipserviced->cipattribute); SCReturnPtr(cipserviced, "DetectENIPFunction"); @@ -171,7 +171,6 @@ DetectCipServiceData *DetectCipServiceParse(char *rulestr) error: if (cipserviced) SCFree(cipserviced); - printf("DetectCipServiceParse - Error Parsing Parameters\n"); SCReturnPtr(NULL, "DetectENIP"); } @@ -222,8 +221,6 @@ static int DetectCipServiceSetup(DetectEngineCtx *de_ctx, Signature *s, DetectCipServiceFree(cipserviced); if (sm != NULL) SCFree(sm); - printf("DetectCipServiceSetup - Error\n"); - SCReturnInt(-1); } @@ -359,7 +356,7 @@ DetectEnipCommandData *DetectEnipCommandParse(char *rulestr) unsigned long cmd = atol(rulestr); if (cmd > MAX_ENIP_CMD) //if command greater than 16 bit { - //printf("DetectEnipCommandParse: Invalid ENIP command %lu\n", cmd); + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid ENIP command %lu", cmd); goto error; } @@ -375,7 +372,6 @@ DetectEnipCommandData *DetectEnipCommandParse(char *rulestr) error: if (enipcmdd) SCFree(enipcmdd); - //printf("DetectEnipCommandParse - Error Parsing Parameters\n"); return NULL; } @@ -423,7 +419,6 @@ static int DetectEnipCommandSetup(DetectEngineCtx *de_ctx, Signature *s, DetectEnipCommandFree(enipcmdd); if (sm != NULL) SCFree(sm); - printf("DetectEnipCommandSetup - Error\n"); SCReturnInt(-1); } diff --git a/src/detect-engine-enip.c b/src/detect-engine-enip.c index 4efcb49fd256..2facecc08410 100644 --- a/src/detect-engine-enip.c +++ b/src/detect-engine-enip.c @@ -34,24 +34,25 @@ #include "util-debug.h" +#if 0 /** * \brief Print fields from ENIP Packet * @param enip_data */ void PrintENIPAL(ENIPTransaction *enip_data) { - SCLogDebug("============================================\n"); - SCLogDebug("ENCAP HEADER cmd 0x%x, length %d, session 0x%x, status 0x%x\n", + SCLogDebug("============================================"); + SCLogDebug("ENCAP HEADER cmd 0x%x, length %d, session 0x%x, status 0x%x", enip_data->header.command, enip_data->header.length, enip_data->header.session, enip_data->header.status); - //SCLogDebug("context 0x%x option 0x%x\n", enip_data->header.context, enip_data->header.option); - SCLogDebug("ENCAP DATA HEADER handle 0x%x, timeout %d, count %d\n", + //SCLogDebug("context 0x%x option 0x%x", enip_data->header.context, enip_data->header.option); + SCLogDebug("ENCAP DATA HEADER handle 0x%x, timeout %d, count %d", enip_data->encap_data_header.interface_handle, enip_data->encap_data_header.timeout, enip_data->encap_data_header.item_count); - SCLogDebug("ENCAP ADDR ITEM type 0x%x, length %d \n", + SCLogDebug("ENCAP ADDR ITEM type 0x%x, length %d", enip_data->encap_addr_item.type, enip_data->encap_addr_item.length); - SCLogDebug("ENCAP DATA ITEM type 0x%x, length %d sequence 0x%x\n", + SCLogDebug("ENCAP DATA ITEM type 0x%x, length %d sequence 0x%x", enip_data->encap_data_item.type, enip_data->encap_data_item.length, enip_data->encap_data_item.sequence_count); @@ -60,10 +61,11 @@ void PrintENIPAL(ENIPTransaction *enip_data) int count = 0; TAILQ_FOREACH(svc, &enip_data->service_list, next) { - //SCLogDebug("CIP Service #%d : 0x%x\n", count, svc->service); + //SCLogDebug("CIP Service #%d : 0x%x", count, svc->service); count++; } } +#endif /** * \brief Matches the rule to the CIP segment in ENIP Packet @@ -72,7 +74,6 @@ void PrintENIPAL(ENIPTransaction *enip_data) */ int CIPPathMatch(CIPServiceEntry *svc, DetectCipServiceData *cipserviced) { - uint16_t class = 0; uint16_t attrib = 0; int found_class = 0; @@ -165,14 +166,16 @@ int CIPServiceMatch(ENIPTransaction *enip_data, { int count = 1; CIPServiceEntry *svc = NULL; - //SCLogDebug("CIPServiceMatchAL\n"); + //SCLogDebug("CIPServiceMatchAL"); TAILQ_FOREACH(svc, &enip_data->service_list, next) { - SCLogDebug("CIPServiceMatchAL service #%d : 0x%x dir %d \n", count, svc->service, svc->direction); + SCLogDebug("CIPServiceMatchAL service #%d : 0x%x dir %d", + count, svc->service, svc->direction); if (cipserviced->cipservice == svc->service) { // compare service - //SCLogDebug("Rule Match for cip service %d\n",cipserviced->cipservice ); + //SCLogDebug("Rule Match for cip service %d",cipserviced->cipservice ); + if (cipserviced->tokens > 1) { //if rule params have class and attribute @@ -193,7 +196,7 @@ int CIPServiceMatch(ENIPTransaction *enip_data, { if (svc->direction == 1) return 0; //don't match responses - // SCLogDebug("CIPServiceMatchAL found\n"); + // SCLogDebug("CIPServiceMatchAL found"); return 1; } } @@ -230,11 +233,11 @@ int DetectEngineInspectCIP(ThreadVars *tv, DetectEngineCtx *de_ctx, SCLogDebug("no cipservice state, no match"); SCReturnInt(0); } - // SCLogDebug("DetectEngineInspectCIP %d\n", cipserviced->cipservice); + //SCLogDebug("DetectEngineInspectCIP %d", cipserviced->cipservice); if (CIPServiceMatch(tx, cipserviced) == 1) { - // SCLogDebug("DetectCIPServiceMatchAL found\n"); + //SCLogDebug("DetectCIPServiceMatchAL found"); SCReturnInt(1); } @@ -270,11 +273,11 @@ int DetectEngineInspectENIP(ThreadVars *tv, DetectEngineCtx *de_ctx, SCReturnInt(0); } - //SCLogDebug("DetectEngineInspectENIP %d, %d\n", enipcmdd->enipcommand, tx->header.command); + //SCLogDebug("DetectEngineInspectENIP %d, %d", enipcmdd->enipcommand, tx->header.command); if (enipcmdd->enipcommand == tx->header.command) { - // SCLogDebug("DetectENIPCommandMatchAL found!\n"); + // SCLogDebug("DetectENIPCommandMatchAL found!"); SCReturnInt(1); } From 80c3aedbfcff676f709907637809d398a7293417 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 08:54:27 +0200 Subject: [PATCH 2007/2553] enip: parsing and tests cleanup --- src/detect-cipservice.c | 74 ++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c index 2488bf30ffbb..de4599af7546 100644 --- a/src/detect-cipservice.c +++ b/src/detect-cipservice.c @@ -77,13 +77,18 @@ void DetectCipServiceRegister(void) * \retval cipserviced pointer to DetectCipServiceData on success * \retval NULL on failure */ -DetectCipServiceData *DetectCipServiceParse(char *rulestr) +static DetectCipServiceData *DetectCipServiceParse(const char *rulestrc) { const char delims[] = ","; DetectCipServiceData *cipserviced = NULL; //SCLogDebug("DetectCipServiceParse - rule string %s", rulestr); + /* strtok_r modifies the string so work with a copy */ + char *rulestr = SCStrdup(rulestrc); + if (unlikely(rulestr == NULL)) + goto error; + cipserviced = SCMalloc(sizeof(DetectCipServiceData)); if (unlikely(cipserviced == NULL)) goto error; @@ -166,11 +171,14 @@ DetectCipServiceData *DetectCipServiceParse(char *rulestr) SCLogDebug("DetectCipServiceParse - attribute %d", cipserviced->cipattribute); + SCFree(rulestr); SCReturnPtr(cipserviced, "DetectENIPFunction"); error: if (cipserviced) SCFree(cipserviced); + if (rulestr) + SCFree(rulestr); SCReturnPtr(NULL, "DetectENIP"); } @@ -242,21 +250,12 @@ void DetectCipServiceFree(void *ptr) */ static int DetectCipServiceParseTest01 (void) { - uint8_t res = 1; - - /*DetectCipServiceData *cipserviced = NULL; - cipserviced = DetectCipServiceParse("1"); - if (cipserviced != NULL) - { - if (cipserviced->cipservice == 1) - { - res = 1; - } - - DetectCipServiceFree(cipserviced); - } - */ - return res; + DetectCipServiceData *cipserviced = NULL; + cipserviced = DetectCipServiceParse("7"); + FAIL_IF_NULL(cipserviced); + FAIL_IF(cipserviced->cipservice != 7); + DetectCipServiceFree(cipserviced); + PASS; } /** @@ -264,25 +263,12 @@ static int DetectCipServiceParseTest01 (void) */ static int DetectCipServiceSignatureTest01 (void) { - uint8_t res = 0; - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - + FAIL_IF_NULL(de_ctx); Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (cip_service:1; sid:1; rev:1;)"); - if (sig == NULL) - { - printf("parsing signature failed: "); - goto end; - } - - /* if we get here, all conditions pass */ - res = 1; -end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return res; + FAIL_IF_NULL(sig); + DetectEngineCtxFree(de_ctx); + PASS; } #endif /* UNITTESTS */ @@ -343,7 +329,7 @@ void DetectEnipCommandRegister(void) * \retval enipcmdd pointer to DetectCipServiceData on success * \retval NULL on failure */ -DetectEnipCommandData *DetectEnipCommandParse(char *rulestr) +static DetectEnipCommandData *DetectEnipCommandParse(const char *rulestr) { DetectEnipCommandData *enipcmdd = NULL; @@ -351,22 +337,20 @@ DetectEnipCommandData *DetectEnipCommandParse(char *rulestr) if (unlikely(enipcmdd == NULL)) goto error; - if (isdigit((int) *rulestr)) - { - unsigned long cmd = atol(rulestr); - if (cmd > MAX_ENIP_CMD) //if command greater than 16 bit - { - SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid ENIP command %lu", cmd); - goto error; - } - - enipcmdd->enipcommand = (uint16_t) atoi(rulestr); + if (!(isdigit((int) *rulestr))) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid ENIP command %s", rulestr); + goto error; + } - } else + unsigned long cmd = atol(rulestr); + if (cmd > MAX_ENIP_CMD) //if command greater than 16 bit { + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid ENIP command %lu", cmd); goto error; } + enipcmdd->enipcommand = (uint16_t) atoi(rulestr); + return enipcmdd; error: From 960ebb2822d1f2e7b75cac91912106f7353083fa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 10:34:39 +0200 Subject: [PATCH 2008/2553] enip: fix scan-build warnings detect-cipservice.c:161:29: warning: Assigned value is garbage or undefined cipserviced->cipservice = input[0]; ^ ~~~~~~~~ detect-cipservice.c:162:27: warning: Assigned value is garbage or undefined cipserviced->cipclass = input[1]; ^ ~~~~~~~~ detect-cipservice.c:163:31: warning: Assigned value is garbage or undefined cipserviced->cipattribute = input[2]; ^ ~~~~~~~~ 3 warnings generated. --- src/detect-cipservice.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c index de4599af7546..091e37713263 100644 --- a/src/detect-cipservice.c +++ b/src/detect-cipservice.c @@ -101,7 +101,7 @@ static DetectCipServiceData *DetectCipServiceParse(const char *rulestrc) char* token; char *save; int var; - int input[3]; + int input[3] = { 0, 0, 0 }; int i = 0; token = strtok_r(rulestr, delims, &save); @@ -158,6 +158,11 @@ static DetectCipServiceData *DetectCipServiceParse(const char *rulestrc) token = strtok_r(NULL, delims, &save); } + if (i == 0) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "no tokens found"); + goto error; + } + cipserviced->cipservice = input[0]; cipserviced->cipclass = input[1]; cipserviced->cipattribute = input[2]; From a63c6b320eaebcf130c94ce80368277d3ea8d7db Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 24 Nov 2015 21:52:06 +0100 Subject: [PATCH 2009/2553] stream: per TcpStream reassembly depth --- src/stream-tcp-private.h | 1 + src/stream-tcp-reassemble.c | 18 +++++++++--------- src/stream-tcp.c | 10 ++++++++++ src/stream-tcp.h | 1 + 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 5c03c4bcd7a0..c13da8667173 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -222,6 +222,7 @@ typedef struct TcpSession_ { uint8_t tcp_packet_flags; /* coccinelle: TcpSession:flags:STREAMTCP_FLAG */ uint16_t flags; + uint32_t reassembly_depth; /**< reassembly depth for the stream */ TcpStream server; TcpStream client; struct StreamMsg_ *toserver_smsg_head; /**< list of stream msgs (for detection inspection) */ diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 052db7d34c03..5dec16e49374 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -1770,14 +1770,14 @@ int StreamTcpReassembleDepthReached(Packet *p) * * \retval size Part of the size that fits in the depth, 0 if none */ -static uint32_t StreamTcpReassembleCheckDepth(TcpStream *stream, +static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream, uint32_t seq, uint32_t size) { SCEnter(); /* if the configured depth value is 0, it means there is no limit on reassembly depth. Otherwise carry on my boy ;) */ - if (stream_config.reassembly_depth == 0) { + if (ssn->reassembly_depth == 0) { SCReturnUInt(size); } @@ -1790,25 +1790,25 @@ static uint32_t StreamTcpReassembleCheckDepth(TcpStream *stream, * checking and just reject the rest of the packets including * retransmissions. Saves us the hassle of dealing with sequence * wraps as well */ - if (SEQ_GEQ((StreamTcpReassembleGetRaBaseSeq(stream)+1),(stream->isn + stream_config.reassembly_depth))) { + if (SEQ_GEQ((StreamTcpReassembleGetRaBaseSeq(stream)+1),(stream->isn + ssn->reassembly_depth))) { stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED; SCReturnUInt(0); } SCLogDebug("full Depth not yet reached: %"PRIu32" <= %"PRIu32, (StreamTcpReassembleGetRaBaseSeq(stream)+1), - (stream->isn + stream_config.reassembly_depth)); + (stream->isn + ssn->reassembly_depth)); - if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + stream_config.reassembly_depth))) { + if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + ssn->reassembly_depth))) { /* packet (partly?) fits the depth window */ - if (SEQ_LEQ((seq + size),(stream->isn + stream_config.reassembly_depth))) { + if (SEQ_LEQ((seq + size),(stream->isn + ssn->reassembly_depth))) { /* complete fit */ SCReturnUInt(size); } else { stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED; /* partial fit, return only what fits */ - uint32_t part = (stream->isn + stream_config.reassembly_depth) - seq; + uint32_t part = (stream->isn + ssn->reassembly_depth) - seq; #if DEBUG BUG_ON(part > size); #else @@ -1903,7 +1903,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre /* If we have reached the defined depth for either of the stream, then stop reassembling the TCP session */ - uint32_t size = StreamTcpReassembleCheckDepth(stream, TCP_GET_SEQ(p), p->payload_len); + uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, TCP_GET_SEQ(p), p->payload_len); SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size); if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { @@ -7286,7 +7286,7 @@ static int StreamTcpReassembleTest45 (void) ssn.state = TCP_ESTABLISHED; /* set the default value of reassembly depth, as there is no config file */ - stream_config.reassembly_depth = httplen1 + 1; + ssn.reassembly_depth = httplen1 + 1; TcpStream *s = NULL; s = &ssn.server; diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 062b44e12edc..f76444fc565b 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -647,6 +647,7 @@ TcpSession *StreamTcpNewSession (Packet *p, int id) } ssn->state = TCP_NONE; + ssn->reassembly_depth = stream_config.reassembly_depth; ssn->flags = stream_config.ssn_init_flags; ssn->tcp_packet_flags = p->tcph ? p->tcph->th_flags : 0; @@ -5799,6 +5800,15 @@ int StreamTcpBypassEnabled(void) return stream_config.bypass; } +void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size) +{ + if (size > ssn->reassembly_depth || size == 0) { + ssn->reassembly_depth = size; + } + + return; +} + #ifdef UNITTESTS /** diff --git a/src/stream-tcp.h b/src/stream-tcp.h index dc106830ad6f..2ae304fa472a 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -123,6 +123,7 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); void StreamTcpReassembleConfigEnableOverlapCheck(void); +void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size); /** ------- Inline functions: ------ */ From b160c49e9eab730791b06a224a72fe68246aacd5 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Tue, 1 Dec 2015 15:50:02 +0100 Subject: [PATCH 2010/2553] app-layer-parser: add stream depth This permits to set a stream depth value for each app-layer. By default, the stream depth specified for tcp is set, then it's possible to specify a own value into the app-layer module with a proper API. --- src/app-layer-parser.c | 28 ++++++++++++++++++++++++++++ src/app-layer-parser.h | 6 ++++++ 2 files changed, 34 insertions(+) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 410e1adfebde..02bfd63a9ce3 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -115,6 +115,9 @@ typedef struct AppLayerParserProtoCtx_ DetectEngineState *(*GetTxDetectState)(void *tx); int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *); + /* each app-layer has its own value */ + uint32_t stream_depth; + /* Indicates the direction the parser is ready to see the data * the first time for a flow. Values accepted - * STREAM_TOSERVER, STREAM_TOCLIENT */ @@ -185,6 +188,9 @@ int AppLayerParserSetup(void) { SCEnter(); + AppProto alproto = 0; + int flow_proto = 0; + memset(&alp_ctx, 0, sizeof(alp_ctx)); /* set the default tx handler if none was set explicitly */ @@ -192,6 +198,14 @@ int AppLayerParserSetup(void) RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveDetectLog); } + /* lets set a default value for stream_depth */ + for (flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) { + for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { + alp_ctx.ctxs[flow_proto][alproto].stream_depth = + stream_config.reassembly_depth; + } + } + SCReturnInt(0); } @@ -1155,6 +1169,20 @@ void AppLayerParserTriggerRawStreamReassembly(Flow *f) SCReturn; } +void AppLayerParserSetStreamDepth(uint8_t ipproto, AppProto alproto, uint32_t stream_depth) +{ + SCEnter(); + + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].stream_depth = stream_depth; + + SCReturn; +} + +uint32_t AppLayerParserGetStreamDepth(uint8_t ipproto, AppProto alproto) +{ + SCReturnInt(alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].stream_depth); +} + /***** Cleanup *****/ void AppLayerParserStateCleanup(uint8_t ipproto, AppProto alproto, void *alstate, diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index 368c7938a330..be4043032c0d 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -28,6 +28,7 @@ #include "app-layer-events.h" #include "detect-engine-state.h" #include "util-file.h" +#include "stream-tcp-private.h" #define APP_LAYER_PARSER_EOF 0x01 #define APP_LAYER_PARSER_NO_INSPECTION 0x02 @@ -149,6 +150,9 @@ void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, int (*StateHasTxDetectState)(void *alstate), DetectEngineState *(*GetTxDetectState)(void *tx), int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *)); +void AppLayerParserRegisterGetStreamDepth(uint8_t ipproto, + AppProto alproto, + uint32_t (*GetStreamDepth)(void)); /***** Get and transaction functions *****/ @@ -205,6 +209,8 @@ int AppLayerParserProtocolIsTxEventAware(uint8_t ipproto, AppProto alproto); int AppLayerParserProtocolSupportsTxs(uint8_t ipproto, AppProto alproto); int AppLayerParserProtocolHasLogger(uint8_t ipproto, AppProto alproto); void AppLayerParserTriggerRawStreamReassembly(Flow *f); +void AppLayerParserSetStreamDepth(uint8_t ipproto, AppProto alproto, uint32_t stream_depth); +uint32_t AppLayerParserGetStreamDepth(uint8_t ipproto, AppProto alproto); /***** Cleanup *****/ From 9ab1194f68d55f32bb958b7da437e2381665a6de Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 1 Aug 2016 16:30:03 +0200 Subject: [PATCH 2011/2553] modbus: set stream depth Some protocol like modbus requires a infinite stream depth because session are kept open and we want to analyze everything. Since we have a stream reassembly depth per stream, we can also set a stream reassembly depth per proto. --- doc/userguide/configuration/suricata-yaml.rst | 18 +++ src/app-layer-modbus.c | 131 +++++++++++++++++- suricata.yaml.in | 3 + 3 files changed, 151 insertions(+), 1 deletion(-) diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index bf13de9ffec5..745c3690ff40 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -2050,3 +2050,21 @@ in which two threads have to wait for each other . When using two threads, the time threads might have to wait for each other will be taken in account when/during profiling packets. For more information see :doc:`../performance/packet-profiling`. + +Application layers +------------------ + +Modbus +~~~~~~ + +According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it +is recommended to keep the TCP connection opened with a remote device +and not to open and close it for each MODBUS/TCP transaction. +In that case, it is important to set the stream-depth of the modbus as +unlimited. + +:: + + modbus: + # Stream reassembly size for modbus, default is 0 + stream-depth: 0 diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index cffb61cef63d..de09843aa187 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -43,6 +43,7 @@ #include "util-misc.h" #include "stream.h" +#include "stream-tcp.h" #include "app-layer-protos.h" #include "app-layer-parser.h" @@ -51,6 +52,7 @@ #include "app-layer-detect-proto.h" #include "conf.h" +#include "conf-yaml-loader.h" #include "decode.h" SCEnumCharMap modbus_decoder_event_table[ ] = { @@ -163,7 +165,11 @@ typedef struct ModbusHeader_ ModbusHeader; /* Modbus Default unreplied Modbus requests are considered a flood */ #define MODBUS_CONFIG_DEFAULT_REQUEST_FLOOD 500 +/* Modbus default stream reassembly depth */ +#define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH 0 + static uint32_t request_flood = MODBUS_CONFIG_DEFAULT_REQUEST_FLOOD; +static uint32_t stream_depth = MODBUS_CONFIG_DEFAULT_STREAM_DEPTH; int ModbusStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type) { *event_id = SCMapEnumNameToValue(event_name, modbus_decoder_event_table); @@ -1463,7 +1469,8 @@ void RegisterModbusParsers(void) } } - ConfNode *p = ConfGetNode("app-layer.protocols.modbus.request-flood"); + ConfNode *p = NULL; + p = ConfGetNode("app-layer.protocols.modbus.request-flood"); if (p != NULL) { uint32_t value; if (ParseSizeStringU32(p->val, &value) < 0) { @@ -1473,6 +1480,17 @@ void RegisterModbusParsers(void) } } SCLogConfig("Modbus request flood protection level: %u", request_flood); + + p = ConfGetNode("app-layer.protocols.modbus.stream-depth"); + if (p != NULL) { + uint32_t value; + if (ParseSizeStringU32(p->val, &value) < 0) { + SCLogError(SC_ERR_MODBUS_CONFIG, "invalid value for stream-depth %s", p->val); + } else { + stream_depth = value; + } + } + SCLogInfo("Modbus stream depth: %u", stream_depth); } else { #ifndef AFLFUZZ_APPLAYER SCLogConfig("Protocol detection and parser disabled for %s protocol.", proto_name); @@ -1506,6 +1524,8 @@ void RegisterModbusParsers(void) AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateGetEventInfo); AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOSERVER); + + AppLayerParserSetStreamDepth(IPPROTO_TCP, ALPROTO_MODBUS, stream_depth); } else { SCLogConfig("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); } @@ -3107,6 +3127,111 @@ static int ModbusParserTest16(void) { UTHFreePackets(&p, 1); return result; } + +/** \test Checks if stream_depth is correct */ +static int ModbusParserTest17(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + FAIL_IF(alp_tctx == NULL); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readCoilsReq, sizeof(readCoilsReq)); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(f.alstate == NULL); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + readCoilsRsp, sizeof(readCoilsRsp)); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + PASS; +} + +/*/ \test Checks if stream depth is correct over 2 TCP packets */ +static int ModbusParserTest18(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + uint32_t input_len = sizeof(readCoilsReq), part2_len = 3; + uint8_t *input = readCoilsReq; + + FAIL_IF(alp_tctx == NULL); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + input, input_len - part2_len); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + input, input_len); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + FAIL_IF(f.alstate == NULL); + + input_len = sizeof(readCoilsRsp); + part2_len = 10; + input = readCoilsRsp; + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + input, input_len - part2_len); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + input, input_len); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + PASS; +} #endif /* UNITTESTS */ void ModbusParserRegisterTests(void) { @@ -3143,5 +3268,9 @@ void ModbusParserRegisterTests(void) { ModbusParserTest15); UtRegisterTest("ModbusParserTest16 - Modbus invalid Write single register request", ModbusParserTest16); + UtRegisterTest("ModbusParserTest17 - Modbus stream depth", + ModbusParserTest17); + UtRegisterTest("ModbusParserTest18 - Modbus stream depth in 2 TCP packets", + ModbusParserTest18); #endif /* UNITTESTS */ } diff --git a/suricata.yaml.in b/suricata.yaml.in index 7fb4ac555900..0920b2da9816 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -700,6 +700,9 @@ app-layer: # If the limit is reached, app-layer-event:modbus.flooded; will match. #request-flood: 500 + # Stream reassembly size for modbus, default is 0 + stream-depth: 0 + enabled: no detection-ports: dp: 502 From 4751677e2490bf18649ce51d146bf3e38c707806 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 29 Aug 2016 11:46:33 +0200 Subject: [PATCH 2012/2553] app-layer: use StreamTcpSetReassemblyDepth This calls StreamTcpSetReassemblyDepth to set the stream depth specified for the protocol. --- src/app-layer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app-layer.c b/src/app-layer.c index 8e1855d48ec6..3f5ed89f0890 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -33,6 +33,7 @@ #include "stream-tcp-reassemble.h" #include "stream-tcp-private.h" #include "stream-tcp-inline.h" +#include "stream-tcp.h" #include "flow.h" #include "flow-util.h" #include "flow-private.h" @@ -190,6 +191,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, f->alproto = *alproto; StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); + TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, *alproto)); /* account flow if we have both side */ if (*alproto_otherdir != ALPROTO_UNKNOWN) { @@ -375,6 +377,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION); StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); f->data_al_so_far[dir] = 0; + TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, *alproto)); } else { f->data_al_so_far[dir] = data_len; } From 3f214b506a66e390ecf7821a8ac51cd1c0916ca5 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Tue, 1 Dec 2015 11:21:24 +0100 Subject: [PATCH 2013/2553] file-store: add depth setting When a rules match and fired filestore we may want to increase the stream reassembly depth for this specific. This add the 'depth' setting in file-store config, which permits to specify how much data we want to reassemble into a stream. --- .../file-extraction/file-extraction.rst | 3 ++- src/detect-filestore.c | 4 +++ src/log-filestore.c | 16 ++++++++++++ src/util-file.c | 25 +++++++++++++++++++ src/util-file.h | 2 ++ suricata.yaml.in | 3 ++- 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/doc/userguide/file-extraction/file-extraction.rst b/doc/userguide/file-extraction/file-extraction.rst index 001ea525cd1d..f4bc439ff49d 100644 --- a/doc/userguide/file-extraction/file-extraction.rst +++ b/doc/userguide/file-extraction/file-extraction.rst @@ -16,7 +16,7 @@ Settings *stream.checksum_validation* controls whether or not the stream engine rejects packets with invalid checksums. A good idea normally, but the network interface performs checksum offloading a lot of packets may seem to be broken. This setting is enabled by default, and can be disabled by setting to "no". Note that the checksum handling can be controlled per interface, see "checksum_checks" in example configuration. -*stream.reassembly.depth* controls how far into a stream reassembly is done. Beyond this value no reassembly will be done. This means that after this value the HTTP session will no longer be tracked. By default a settings of 1 Megabyte is used. 0 sets it to unlimited. +*file-store.stream-depth* controls how far into a stream reassembly is done. Beyond this value no reassembly will be done. This means that after this value the HTTP session will no longer be tracked. By default a settings of 1 Megabyte is used. 0 sets it to unlimited. If set to no, it is disabled and stream.reassembly.depth is considered. *libhtp.default-config.request-body-limit* / *libhtp.server-config..request-body-limit* controls how much of the HTTP request body is tracked for inspection by the http_client_body keyword, but also used to limit file inspection. A value of 0 means unlimited. @@ -40,6 +40,7 @@ drop dir must be configured. log-dir: files # directory to store the files force-magic: no # force logging magic on all stored files force-md5: no # force logging of md5 checksums + stream-depth: 1mb # reassemble 1mb into a stream, set to no to disable waldo: file.waldo # waldo file to store the file_id across runs Each file that is stored with have a name "file.". The id will be reset and files will be overwritten unless the waldo option is used. diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 3e6957586cf9..efbeda0deca1 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -198,6 +198,10 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack #endif } + /* set filestore depth for stream reassembling */ + TcpSession *ssn = (TcpSession *)p->flow->protoctx; + TcpSessionSetReassemblyDepth(ssn, FileReassemblyDepth()); + if (p->flowflags & FLOW_PKT_TOCLIENT) flags |= STREAM_TOCLIENT; else diff --git a/src/log-filestore.c b/src/log-filestore.c index d793d341e28c..d57b589246f1 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -46,6 +46,7 @@ #include "util-atomic.h" #include "util-file.h" #include "util-time.h" +#include "util-misc.h" #include "output.h" @@ -484,6 +485,21 @@ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) FileForceHashParseCfg(conf); SCLogInfo("storing files in %s", g_logfile_base_dir); + const char *stream_depth_str = ConfNodeLookupChildValue(conf, "stream-depth"); + if (stream_depth_str != NULL && strcmp(stream_depth_str, "no")) { + uint32_t stream_depth = 0; + if (ParseSizeStringU32(stream_depth_str, + &stream_depth) < 0) { + SCLogError(SC_ERR_SIZE_PARSE, "Error parsing " + "file-store.stream-depth " + "from conf file - %s. Killing engine", + stream_depth_str); + exit(EXIT_FAILURE); + } else { + FileReassemblyDepthEnable(stream_depth); + } + } + SCReturnPtr(output_ctx, "OutputCtx"); } diff --git a/src/util-file.c b/src/util-file.c index 5089210216b8..f2ffa8a9f0dc 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -28,6 +28,7 @@ #include "debug.h" #include "flow.h" #include "stream.h" +#include "stream-tcp.h" #include "runmodes.h" #include "util-hash.h" #include "util-debug.h" @@ -66,6 +67,16 @@ static int g_file_force_sha256 = 0; */ static int g_file_force_tracking = 0; +/** \brief switch to use g_file_store_reassembly_depth + * to reassembly files + */ +static int g_file_store_enable = 0; + +/** \brief stream_config.reassembly_depth equivalent + * for files + */ +static uint32_t g_file_store_reassembly_depth = 0; + /* prototypes */ static void FileFree(File *); @@ -99,6 +110,20 @@ int FileForceFilestore(void) return g_file_force_filestore; } +void FileReassemblyDepthEnable(uint32_t size) +{ + g_file_store_enable = 1; + g_file_store_reassembly_depth = size; +} + +uint32_t FileReassemblyDepth(void) +{ + if (g_file_store_enable == 1) + return g_file_store_reassembly_depth; + else + return stream_config.reassembly_depth; +} + int FileForceMagic(void) { return g_file_force_magic; diff --git a/src/util-file.h b/src/util-file.h index 3b9ee9daee46..8e9b1a3c8d94 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -182,6 +182,8 @@ void FilePrune(FileContainer *ffc); void FileForceFilestoreEnable(void); int FileForceFilestore(void); +void FileReassemblyDepthEnable(uint32_t size); +uint32_t FileReassemblyDepth(void); void FileDisableMagic(Flow *f, uint8_t); void FileForceMagicEnable(void); diff --git a/suricata.yaml.in b/suricata.yaml.in index 0920b2da9816..9d6f65231c2f 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -394,7 +394,7 @@ outputs: # file "file..meta" is created. # # File extraction depends on a lot of things to be fully done: - # - stream reassembly depth. For optimal results, set this to 0 (unlimited) + # - file-store stream-depth. For optimal results, set this to 0 (unlimited) # - http request / response body sizes. Again set to 0 for optimal results. # - rules that contain the "filestore" keyword. - file-store: @@ -405,6 +405,7 @@ outputs: # sha1 and sha256 #force-hash: [md5] force-filestore: no # force storing of all files + stream-depth: 1mb # reassemble 1mb into a stream, set to no to disable #waldo: file.waldo # waldo file to store the file_id across runs # output module to log files tracked in a easily parsable json format From e6cf7ae8fa0ce5fdb10e36b53ec2181b9f149ecd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 12:04:40 +0200 Subject: [PATCH 2014/2553] yaml: improve stream-depth comments --- suricata.yaml.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 9d6f65231c2f..54cfc0868e4b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -405,7 +405,9 @@ outputs: # sha1 and sha256 #force-hash: [md5] force-filestore: no # force storing of all files - stream-depth: 1mb # reassemble 1mb into a stream, set to no to disable + # override global stream-depth for sessions in which we want to + # perform file extraction. Set to 0 for unlimited. + #stream-depth: 0 #waldo: file.waldo # waldo file to store the file_id across runs # output module to log files tracked in a easily parsable json format @@ -701,7 +703,7 @@ app-layer: # If the limit is reached, app-layer-event:modbus.flooded; will match. #request-flood: 500 - # Stream reassembly size for modbus, default is 0 + # Stream reassembly size for modbus. By default track it completely. stream-depth: 0 enabled: no From 07d2312d96cb1798d58e9f3ff23775b7b87c99e7 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 27 Sep 2016 08:56:28 +0200 Subject: [PATCH 2015/2553] detect-tls-validity: use flags for modes Use flags for modes to support using multiple modes at the same time. --- src/detect-tls-cert-validity.c | 24 +++++++++++++----------- src/detect-tls-cert-validity.h | 8 ++++---- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index 08d0122263bd..742249c15297 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -148,13 +148,13 @@ static int DetectTlsValidityMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx if (cert_epoch == 0) SCReturnInt(0); - if (dd->mode == DETECT_TLS_VALIDITY_EQ && cert_epoch == dd->epoch) + if ((dd->mode & DETECT_TLS_VALIDITY_EQ) && cert_epoch == dd->epoch) ret = 1; - else if (dd->mode == DETECT_TLS_VALIDITY_LT && cert_epoch <= dd->epoch) + else if ((dd->mode & DETECT_TLS_VALIDITY_LT) && cert_epoch <= dd->epoch) ret = 1; - else if (dd->mode == DETECT_TLS_VALIDITY_GT && cert_epoch >= dd->epoch) + else if ((dd->mode & DETECT_TLS_VALIDITY_GT) && cert_epoch >= dd->epoch) ret = 1; - else if (dd->mode == DETECT_TLS_VALIDITY_RA && + else if ((dd->mode & DETECT_TLS_VALIDITY_RA) && cert_epoch >= dd->epoch && cert_epoch <= dd->epoch2) ret = 1; @@ -315,20 +315,18 @@ static DetectTlsValidityData *DetectTlsValidityParse (char *rawstr) dd->epoch = 0; dd->epoch2 = 0; - dd->mode = DETECT_TLS_VALIDITY_EQ; + dd->mode = 0; if (strlen(mode) > 0) { if (mode[0] == '<') - dd->mode = DETECT_TLS_VALIDITY_LT; + dd->mode |= DETECT_TLS_VALIDITY_LT; else if (mode[0] == '>') - dd->mode = DETECT_TLS_VALIDITY_GT; - else - dd->mode = DETECT_TLS_VALIDITY_EQ; + dd->mode |= DETECT_TLS_VALIDITY_GT; } if (strlen(range) > 0) { if (strcmp("<>", range) == 0) - dd->mode = DETECT_TLS_VALIDITY_RA; + dd->mode |= DETECT_TLS_VALIDITY_RA; } if (strlen(range) != 0 && strlen(mode) != 0) { @@ -337,6 +335,10 @@ static DetectTlsValidityData *DetectTlsValidityParse (char *rawstr) goto error; } + if (dd->mode == 0) { + dd->mode |= DETECT_TLS_VALIDITY_EQ; + } + /* set the first value */ dd->epoch = DateStringToEpoch(value1); if (dd->epoch == -1) @@ -344,7 +346,7 @@ static DetectTlsValidityData *DetectTlsValidityParse (char *rawstr) /* set the second value if specified */ if (strlen(value2) > 0) { - if (dd->mode != DETECT_TLS_VALIDITY_RA) { + if (!(dd->mode & DETECT_TLS_VALIDITY_RA)) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Multiple tls validity values specified but mode is not range"); goto error; diff --git a/src/detect-tls-cert-validity.h b/src/detect-tls-cert-validity.h index 1589821ab4bb..382b028ef556 100644 --- a/src/detect-tls-cert-validity.h +++ b/src/detect-tls-cert-validity.h @@ -24,10 +24,10 @@ #ifndef __DETECT_TLS_VALIDITY_H__ #define __DETECT_TLS_VALIDITY_H__ -#define DETECT_TLS_VALIDITY_LT 0 -#define DETECT_TLS_VALIDITY_EQ 1 -#define DETECT_TLS_VALIDITY_GT 2 -#define DETECT_TLS_VALIDITY_RA 3 +#define DETECT_TLS_VALIDITY_EQ (1) /* equal */ +#define DETECT_TLS_VALIDITY_LT (1<<1) /* less than */ +#define DETECT_TLS_VALIDITY_GT (1<<2) /* greater than */ +#define DETECT_TLS_VALIDITY_RA (1<<3) /* range */ #define DETECT_TLS_TYPE_NOTBEFORE 0 #define DETECT_TLS_TYPE_NOTAFTER 1 From f22c9d9781cd6f8a6feaa5256a4c7ff37a5b094b Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 27 Sep 2016 13:39:43 +0200 Subject: [PATCH 2016/2553] detect: add keyword tls_cert_expired Add keyword to check if TLS certificate is expired. --- src/detect-tls-cert-validity.c | 418 +++++++++++++++++++++++++++++++++ src/detect-tls-cert-validity.h | 3 + src/detect.h | 1 + 3 files changed, 422 insertions(+) diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index 742249c15297..bf1b869ea0c0 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -63,11 +63,13 @@ static int DetectTlsValidityMatch (ThreadVars *, DetectEngineThreadCtx *, Flow * static time_t DateStringToEpoch (char *); static DetectTlsValidityData *DetectTlsValidityParse (char *); +static int DetectTlsExpiredSetup (DetectEngineCtx *, Signature *s, char *str); static int DetectTlsNotBeforeSetup (DetectEngineCtx *, Signature *s, char *str); static int DetectTlsNotAfterSetup (DetectEngineCtx *, Signature *s, char *str); static int DetectTlsValiditySetup (DetectEngineCtx *, Signature *s, char *str, uint8_t); void TlsNotBeforeRegisterTests(void); void TlsNotAfterRegisterTests(void); +void TlsExpiredRegisterTests(void); static void DetectTlsValidityFree(void *); /** @@ -93,6 +95,16 @@ void DetectTlsValidityRegister (void) sigmatch_table[DETECT_AL_TLS_NOTAFTER].Free = DetectTlsValidityFree; sigmatch_table[DETECT_AL_TLS_NOTAFTER].RegisterTests = TlsNotAfterRegisterTests; + sigmatch_table[DETECT_AL_TLS_EXPIRED].name = "tls_cert_expired"; + sigmatch_table[DETECT_AL_TLS_EXPIRED].desc = "match expired TLS certificates"; + sigmatch_table[DETECT_AL_TLS_EXPIRED].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsexpired"; + sigmatch_table[DETECT_AL_TLS_EXPIRED].Match = NULL; + sigmatch_table[DETECT_AL_TLS_EXPIRED].AppLayerTxMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_EXPIRED].Setup = DetectTlsExpiredSetup; + sigmatch_table[DETECT_AL_TLS_EXPIRED].Free = DetectTlsValidityFree; + sigmatch_table[DETECT_AL_TLS_EXPIRED].RegisterTests = TlsExpiredRegisterTests; + sigmatch_table[DETECT_AL_TLS_EXPIRED].flags = SIGMATCH_NOOPT; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); DetectAppLayerInspectEngineRegister(ALPROTO_TLS, SIG_FLAG_TOCLIENT, @@ -157,6 +169,9 @@ static int DetectTlsValidityMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx else if ((dd->mode & DETECT_TLS_VALIDITY_RA) && cert_epoch >= dd->epoch && cert_epoch <= dd->epoch2) ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_EX) && + f->lastts.tv_sec > cert_epoch) + ret = 1; SCReturnInt(ret); } @@ -370,6 +385,64 @@ static DetectTlsValidityData *DetectTlsValidityParse (char *rawstr) return NULL; } +/** + * \brief Function to add the parsed tls_cert_expired into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsExpiredSetup (DetectEngineCtx *de_ctx, Signature *s, + char *rawstr) +{ + DetectTlsValidityData *dd = NULL; + SigMatch *sm = NULL; + + SCLogDebug("\'%s\'", rawstr); + + dd = SCMalloc(sizeof(DetectTlsValidityData)); + if (dd == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT,"Allocation \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "rule contains conflicting keywords."); + goto error; + } + + dd->mode |= DETECT_TLS_VALIDITY_EX; + dd->type = DETECT_TLS_TYPE_NOTAFTER; + dd->epoch = 0; + dd->epoch2 = 0; + + sm->type = DETECT_AL_TLS_EXPIRED; + sm->ctx = (void *)dd; + + s->flags |= SIG_FLAG_APPLAYER; + s->alproto = ALPROTO_TLS; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TLSVALIDITY_MATCH); + + return 0; + +error: + DetectTlsValidityFree(dd); + if (sm) + SCFree(sm); + return -1; +} + /** * \brief Function to add the parsed tls_notbefore into the current signature. * @@ -1171,6 +1244,341 @@ int ValidityTestDetect01(void) PASS; } +/** + * \test Test matching on an expired certificate. + * + * Traffic from expired.badssl.com + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ExpiredTestDetect01(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x5a, 0x01, 0x00, 0x00, + 0x56, 0x03, 0x03, 0x62, 0x87, 0xa4, 0x11, 0x3e, + 0x11, 0x32, 0x7d, 0xbc, 0x5b, 0x63, 0xb7, 0xaf, + 0x55, 0x8d, 0x46, 0x5b, 0x8f, 0xac, 0x50, 0x02, + 0x90, 0xe3, 0x55, 0x03, 0xfe, 0xad, 0xa6, 0x92, + 0x56, 0x75, 0xf9, 0x00, 0x00, 0x08, 0x00, 0x35, + 0x00, 0x2f, 0x00, 0x0a, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x25, 0x00, 0x00, 0x00, 0x17, 0x00, 0x15, + 0x00, 0x00, 0x12, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x64, 0x2e, 0x62, 0x61, 0x64, 0x73, 0x73, + 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x0d, 0x00, + 0x06, 0x00, 0x04, 0x04, 0x01, 0x02, 0x01 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x55, 0x02, 0x00, 0x00, + 0x51, 0x03, 0x03, 0x22, 0xa1, 0xd8, 0xd0, 0x3c, + 0x8d, 0x32, 0x7e, 0x4f, 0x60, 0x27, 0xf6, 0x0c, + 0x99, 0x7a, 0x8e, 0x6e, 0x52, 0xa5, 0xf4, 0x20, + 0x2e, 0xa1, 0xa4, 0x0b, 0xd5, 0x80, 0x9b, 0xec, + 0xbd, 0x2c, 0x6c, 0x20, 0x7a, 0x9b, 0xcc, 0x6b, + 0xbf, 0x3d, 0xfc, 0x7c, 0x31, 0x78, 0x65, 0x1e, + 0xcc, 0x41, 0x0b, 0x8b, 0x3d, 0x4e, 0xde, 0x45, + 0xe5, 0x20, 0xf5, 0xbd, 0x8e, 0x99, 0xce, 0xc2, + 0xad, 0x88, 0x08, 0x27, 0x00, 0x2f, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, + 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x05, 0x59, 0x0b, 0x00, 0x05, + 0x55, 0x00, 0x05, 0x52, 0x00, 0x05, 0x4f, 0x30, + 0x82, 0x05, 0x4b, 0x30, 0x82, 0x04, 0x33, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x4a, 0xe7, + 0x95, 0x49, 0xfa, 0x9a, 0xbe, 0x3f, 0x10, 0x0f, + 0x17, 0xa4, 0x78, 0xe1, 0x69, 0x09, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x90, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x30, + 0x19, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x12, + 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20, + 0x4d, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x73, 0x74, + 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x61, 0x6c, + 0x66, 0x6f, 0x72, 0x64, 0x31, 0x1a, 0x30, 0x18, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43, + 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, + 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, + 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x2d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, + 0x4f, 0x20, 0x52, 0x53, 0x41, 0x20, 0x44, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, + 0x30, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x5a, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, 0x31, + 0x32, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, + 0x30, 0x59, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x20, 0x56, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x1d, 0x30, + 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x14, + 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x53, 0x53, 0x4c, 0x20, 0x57, 0x69, 0x6c, 0x64, + 0x63, 0x61, 0x72, 0x64, 0x31, 0x15, 0x30, 0x13, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x14, 0x0c, 0x2a, + 0x2e, 0x62, 0x61, 0x64, 0x73, 0x73, 0x6c, 0x2e, + 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xc2, 0x04, 0xec, 0xf8, + 0x8c, 0xee, 0x04, 0xc2, 0xb3, 0xd8, 0x50, 0xd5, + 0x70, 0x58, 0xcc, 0x93, 0x18, 0xeb, 0x5c, 0xa8, + 0x68, 0x49, 0xb0, 0x22, 0xb5, 0xf9, 0x95, 0x9e, + 0xb1, 0x2b, 0x2c, 0x76, 0x3e, 0x6c, 0xc0, 0x4b, + 0x60, 0x4c, 0x4c, 0xea, 0xb2, 0xb4, 0xc0, 0x0f, + 0x80, 0xb6, 0xb0, 0xf9, 0x72, 0xc9, 0x86, 0x02, + 0xf9, 0x5c, 0x41, 0x5d, 0x13, 0x2b, 0x7f, 0x71, + 0xc4, 0x4b, 0xbc, 0xe9, 0x94, 0x2e, 0x50, 0x37, + 0xa6, 0x67, 0x1c, 0x61, 0x8c, 0xf6, 0x41, 0x42, + 0xc5, 0x46, 0xd3, 0x16, 0x87, 0x27, 0x9f, 0x74, + 0xeb, 0x0a, 0x9d, 0x11, 0x52, 0x26, 0x21, 0x73, + 0x6c, 0x84, 0x4c, 0x79, 0x55, 0xe4, 0xd1, 0x6b, + 0xe8, 0x06, 0x3d, 0x48, 0x15, 0x52, 0xad, 0xb3, + 0x28, 0xdb, 0xaa, 0xff, 0x6e, 0xff, 0x60, 0x95, + 0x4a, 0x77, 0x6b, 0x39, 0xf1, 0x24, 0xd1, 0x31, + 0xb6, 0xdd, 0x4d, 0xc0, 0xc4, 0xfc, 0x53, 0xb9, + 0x6d, 0x42, 0xad, 0xb5, 0x7c, 0xfe, 0xae, 0xf5, + 0x15, 0xd2, 0x33, 0x48, 0xe7, 0x22, 0x71, 0xc7, + 0xc2, 0x14, 0x7a, 0x6c, 0x28, 0xea, 0x37, 0x4a, + 0xdf, 0xea, 0x6c, 0xb5, 0x72, 0xb4, 0x7e, 0x5a, + 0xa2, 0x16, 0xdc, 0x69, 0xb1, 0x57, 0x44, 0xdb, + 0x0a, 0x12, 0xab, 0xde, 0xc3, 0x0f, 0x47, 0x74, + 0x5c, 0x41, 0x22, 0xe1, 0x9a, 0xf9, 0x1b, 0x93, + 0xe6, 0xad, 0x22, 0x06, 0x29, 0x2e, 0xb1, 0xba, + 0x49, 0x1c, 0x0c, 0x27, 0x9e, 0xa3, 0xfb, 0x8b, + 0xf7, 0x40, 0x72, 0x00, 0xac, 0x92, 0x08, 0xd9, + 0x8c, 0x57, 0x84, 0x53, 0x81, 0x05, 0xcb, 0xe6, + 0xfe, 0x6b, 0x54, 0x98, 0x40, 0x27, 0x85, 0xc7, + 0x10, 0xbb, 0x73, 0x70, 0xef, 0x69, 0x18, 0x41, + 0x07, 0x45, 0x55, 0x7c, 0xf9, 0x64, 0x3f, 0x3d, + 0x2c, 0xc3, 0xa9, 0x7c, 0xeb, 0x93, 0x1a, 0x4c, + 0x86, 0xd1, 0xca, 0x85, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x01, 0xd5, 0x30, 0x82, 0x01, + 0xd1, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, + 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x90, 0xaf, + 0x6a, 0x3a, 0x94, 0x5a, 0x0b, 0xd8, 0x90, 0xea, + 0x12, 0x56, 0x73, 0xdf, 0x43, 0xb4, 0x3a, 0x28, + 0xda, 0xe7, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9d, 0xee, 0xc1, + 0x7b, 0x81, 0x0b, 0x3a, 0x47, 0x69, 0x71, 0x18, + 0x7d, 0x11, 0x37, 0x93, 0xbc, 0xa5, 0x1b, 0x3f, + 0xfb, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, + 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, + 0xa0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x4f, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x48, 0x30, + 0x46, 0x30, 0x3a, 0x06, 0x0b, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x02, 0x07, + 0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1d, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x08, 0x06, + 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x01, 0x30, + 0x54, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x4d, + 0x30, 0x4b, 0x30, 0x49, 0xa0, 0x47, 0xa0, 0x45, + 0x86, 0x43, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, + 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, + 0x52, 0x53, 0x41, 0x44, 0x6f, 0x6d, 0x61, 0x69, + 0x6e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, + 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x81, 0x85, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x01, 0x04, 0x79, 0x30, 0x77, 0x30, 0x4f, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x02, 0x86, 0x43, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x4f, 0x4d, 0x4f, + 0x44, 0x4f, 0x52, 0x53, 0x41, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, + 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, + 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, + 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x23, 0x06, + 0x03, 0x55, 0x1d, 0x11, 0x04, 0x1c, 0x30, 0x1a, + 0x82, 0x0c, 0x2a, 0x2e, 0x62, 0x61, 0x64, 0x73, + 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x0a, + 0x62, 0x61, 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x6a, 0x7a, + 0xf1, 0xda, 0xff, 0x03, 0x07, 0x72, 0x78, 0xc5, + 0x66, 0xa1, 0x4f, 0x46, 0x43, 0x0e, 0x5f, 0x14, + 0x21, 0x8c, 0x75, 0x1a, 0xeb, 0x36, 0xe0, 0x1f, + 0xa4, 0x10, 0x15, 0xec, 0xda, 0x33, 0x25, 0x7c, + 0x3b, 0xb5, 0x0a, 0xc7, 0x01, 0x38, 0x3d, 0x27, + 0xfd, 0x58, 0xd9, 0xcc, 0xea, 0x2d, 0x69, 0x39, + 0x7c, 0xbe, 0x97, 0xef, 0x0b, 0xd6, 0x0b, 0x58, + 0xe7, 0x8c, 0x7f, 0xbf, 0xb3, 0x4c, 0x1d, 0xf3, + 0xb7, 0x90, 0x80, 0xa6, 0x36, 0x7c, 0x14, 0x5b, + 0xec, 0x07, 0x2d, 0x02, 0x3e, 0x1b, 0x5b, 0x63, + 0x5b, 0x15, 0xab, 0x00, 0xfa, 0x1f, 0x3b, 0x19, + 0x2d, 0xdf, 0xe2, 0x23, 0x10, 0x11, 0x07, 0x7e, + 0x72, 0x7f, 0xe2, 0xbf, 0xb7, 0x00, 0x1b, 0x98, + 0x2f, 0x2c, 0x3f, 0xce, 0x85, 0x9a, 0x27, 0x8c, + 0x10, 0x22, 0x08, 0x41, 0x2b, 0x8a, 0x3e, 0x82, + 0x4e, 0xfc, 0xdd, 0x21, 0xc6, 0x56, 0x74, 0x70, + 0xa4, 0x34, 0xf2, 0xb1, 0x40, 0x9e, 0x2b, 0x58, + 0xa2, 0x59, 0x0f, 0x1d, 0x48, 0xef, 0xeb, 0x11, + 0x3e, 0xc1, 0x4a, 0x9e, 0xbc, 0x65, 0x55, 0x6d, + 0xc6, 0xa3, 0xef, 0xd5, 0xd4, 0x96, 0xcd, 0xf1, + 0xae, 0x27, 0xf7, 0xa4, 0x57, 0x14, 0x3c, 0x94, + 0x41, 0x05, 0x7a, 0x8b, 0xa1, 0x37, 0x47, 0xd7, + 0xf5, 0x7d, 0xdc, 0xfa, 0xce, 0x6f, 0x31, 0xa2, + 0xb0, 0x8c, 0xea, 0xcc, 0x12, 0x9b, 0x22, 0xf1, + 0x34, 0x70, 0xcf, 0x7d, 0x75, 0x4a, 0x8b, 0x68, + 0x29, 0x0c, 0x1e, 0xe9, 0x96, 0xa8, 0xcf, 0xb0, + 0x12, 0x1f, 0x5c, 0x2a, 0xee, 0x67, 0x2f, 0x7f, + 0xbd, 0x73, 0xf3, 0x5a, 0x01, 0x22, 0x0c, 0x70, + 0xfa, 0xcd, 0x45, 0xef, 0x78, 0x5c, 0xce, 0x0d, + 0xfa, 0x4e, 0xe1, 0xef, 0xce, 0x65, 0x9f, 0x47, + 0x0c, 0x4f, 0xbb, 0x36, 0x44, 0x68, 0x56, 0x5c, + 0x56, 0x59, 0xad, 0xaa, 0x8a, 0xbc, + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + f.lastts.tv_sec = 1474978656; /* 2016-09-27 */ + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_expired\"; " + "tls_cert_expired; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_hello, sizeof(client_hello)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + #endif /* UNITTESTS */ /** @@ -1214,3 +1622,13 @@ void TlsNotAfterRegisterTests(void) UtRegisterTest("ValidityTestParse22", ValidityTestParse22); #endif /* UNITTESTS */ } + +/** + * \brief Register unit tests for tls_cert_expired + */ +void TlsExpiredRegisterTests(void) +{ +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("ExpiredTestDetect01", ExpiredTestDetect01); +#endif /* UNITTESTS */ +} diff --git a/src/detect-tls-cert-validity.h b/src/detect-tls-cert-validity.h index 382b028ef556..9840635a1e3d 100644 --- a/src/detect-tls-cert-validity.h +++ b/src/detect-tls-cert-validity.h @@ -29,6 +29,9 @@ #define DETECT_TLS_VALIDITY_GT (1<<2) /* greater than */ #define DETECT_TLS_VALIDITY_RA (1<<3) /* range */ +/* Used by tls_cert_expired */ +#define DETECT_TLS_VALIDITY_EX (1<<4) /* expired */ + #define DETECT_TLS_TYPE_NOTBEFORE 0 #define DETECT_TLS_TYPE_NOTAFTER 1 diff --git a/src/detect.h b/src/detect.h index e71f72216502..a48bcef7c4d4 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1267,6 +1267,7 @@ enum { DETECT_AL_TLS_ISSUERDN, DETECT_AL_TLS_NOTBEFORE, DETECT_AL_TLS_NOTAFTER, + DETECT_AL_TLS_EXPIRED, DETECT_AL_TLS_FINGERPRINT, DETECT_AL_TLS_STORE, From f7e0083269df2ce7a6c1001123314c92ec690fbe Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 27 Sep 2016 13:41:38 +0200 Subject: [PATCH 2017/2553] detect-cert-validity: fix typos --- src/detect-tls-cert-validity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index bf1b869ea0c0..005538d4b3ae 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -1582,7 +1582,7 @@ int ExpiredTestDetect01(void) #endif /* UNITTESTS */ /** - * \brief Register unit tests for tls_notbefore. + * \brief Register unit tests for tls_cert_notbefore. */ void TlsNotBeforeRegisterTests(void) { @@ -1604,7 +1604,7 @@ void TlsNotBeforeRegisterTests(void) } /** - * \brief Register unit tests for tls_notafter. + * \brief Register unit tests for tls_cert_notafter. */ void TlsNotAfterRegisterTests(void) { From 1fea52dd8aaab9e0f4da57981f8a581ea347f036 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 27 Sep 2016 14:19:03 +0200 Subject: [PATCH 2018/2553] detect: add keyword tls_cert_valid Add keyword to check if TLS certificate is valid. --- src/detect-tls-cert-validity.c | 403 +++++++++++++++++++++++++++++++++ src/detect-tls-cert-validity.h | 3 + src/detect.h | 1 + 3 files changed, 407 insertions(+) diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index 005538d4b3ae..e14ed5c4f868 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -64,12 +64,14 @@ static int DetectTlsValidityMatch (ThreadVars *, DetectEngineThreadCtx *, Flow * static time_t DateStringToEpoch (char *); static DetectTlsValidityData *DetectTlsValidityParse (char *); static int DetectTlsExpiredSetup (DetectEngineCtx *, Signature *s, char *str); +static int DetectTlsValidSetup (DetectEngineCtx *, Signature *s, char *str); static int DetectTlsNotBeforeSetup (DetectEngineCtx *, Signature *s, char *str); static int DetectTlsNotAfterSetup (DetectEngineCtx *, Signature *s, char *str); static int DetectTlsValiditySetup (DetectEngineCtx *, Signature *s, char *str, uint8_t); void TlsNotBeforeRegisterTests(void); void TlsNotAfterRegisterTests(void); void TlsExpiredRegisterTests(void); +void TlsValidRegisterTests(void); static void DetectTlsValidityFree(void *); /** @@ -105,6 +107,16 @@ void DetectTlsValidityRegister (void) sigmatch_table[DETECT_AL_TLS_EXPIRED].RegisterTests = TlsExpiredRegisterTests; sigmatch_table[DETECT_AL_TLS_EXPIRED].flags = SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_VALID].name = "tls_cert_valid"; + sigmatch_table[DETECT_AL_TLS_VALID].desc = "match valid TLS certificates"; + sigmatch_table[DETECT_AL_TLS_VALID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsvalid"; + sigmatch_table[DETECT_AL_TLS_VALID].Match = NULL; + sigmatch_table[DETECT_AL_TLS_VALID].AppLayerTxMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_VALID].Setup = DetectTlsValidSetup; + sigmatch_table[DETECT_AL_TLS_VALID].Free = DetectTlsValidityFree; + sigmatch_table[DETECT_AL_TLS_VALID].RegisterTests = TlsValidRegisterTests; + sigmatch_table[DETECT_AL_TLS_VALID].flags = SIGMATCH_NOOPT; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); DetectAppLayerInspectEngineRegister(ALPROTO_TLS, SIG_FLAG_TOCLIENT, @@ -172,6 +184,9 @@ static int DetectTlsValidityMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx else if ((dd->mode & DETECT_TLS_VALIDITY_EX) && f->lastts.tv_sec > cert_epoch) ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_VA) && + f->lastts.tv_sec <= cert_epoch) + ret = 1; SCReturnInt(ret); } @@ -443,6 +458,64 @@ static int DetectTlsExpiredSetup (DetectEngineCtx *de_ctx, Signature *s, return -1; } +/** + * \brief Function to add the parsed tls_cert_valid into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsValidSetup (DetectEngineCtx *de_ctx, Signature *s, + char *rawstr) +{ + DetectTlsValidityData *dd = NULL; + SigMatch *sm = NULL; + + SCLogDebug("\'%s\'", rawstr); + + dd = SCMalloc(sizeof(DetectTlsValidityData)); + if (dd == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT,"Allocation \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "rule contains conflicting keywords."); + goto error; + } + + dd->mode |= DETECT_TLS_VALIDITY_VA; + dd->type = DETECT_TLS_TYPE_NOTAFTER; + dd->epoch = 0; + dd->epoch2 = 0; + + sm->type = DETECT_AL_TLS_VALID; + sm->ctx = (void *)dd; + + s->flags |= SIG_FLAG_APPLAYER; + s->alproto = ALPROTO_TLS; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TLSVALIDITY_MATCH); + + return 0; + +error: + DetectTlsValidityFree(dd); + if (sm) + SCFree(sm); + return -1; +} + /** * \brief Function to add the parsed tls_notbefore into the current signature. * @@ -1579,6 +1652,326 @@ int ExpiredTestDetect01(void) PASS; } +/** + * \test Test matching on a valid TLS certificate. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidTestDetect01(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, + 0x5b, 0x85, 0xd4, 0x40, 0xab, 0xbe, 0xc0, 0xbc, + 0x41, 0xf2, 0x26, 0xf0, 0xfe, 0x21, 0xee, 0x8b, + 0x4c, 0x7e, 0x07, 0xc8, 0xec, 0xd2, 0x00, 0x46, + 0x4c, 0xeb, 0xb7, 0x00, 0x00, 0x16, 0xc0, 0x2b, + 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, + 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, + 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0xff, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, + 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, + 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, + 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, + 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, + 0x14, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, + 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x04, 0x02, 0x02, 0x02 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, + 0xdb, 0xbb, 0x23, 0xcf, 0x0b, 0x43, 0x02, 0x1d, + 0x46, 0x11, 0x27, 0x5c, 0x98, 0xcf, 0x67, 0xe1, + 0x94, 0x3d, 0x62, 0x7d, 0x38, 0x48, 0x21, 0x23, + 0xa5, 0x62, 0x31, 0x00, 0xc0, 0x2f, 0x00, 0x00, + 0x1c, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, + 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, + 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x19, + 0xb7, 0xb1, 0x32, 0x3b, 0x1c, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, + 0x31, 0x33, 0x31, 0x33, 0x32, 0x34, 0x35, 0x32, + 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x30, + 0x35, 0x31, 0x33, 0x31, 0x36, 0x30, 0x30, 0x5a, + 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa5, 0x0a, 0xb9, 0xb1, 0xca, 0x36, 0xd1, 0xae, + 0x22, 0x38, 0x07, 0x06, 0xc9, 0x1a, 0x56, 0x4f, + 0xbb, 0xdf, 0xa8, 0x6d, 0xbd, 0xee, 0x76, 0x16, + 0xbc, 0x53, 0x3c, 0x03, 0x6a, 0x5c, 0x94, 0x50, + 0x87, 0x2f, 0x28, 0xb4, 0x4e, 0xd5, 0x9b, 0x8f, + 0xfe, 0x02, 0xde, 0x2a, 0x83, 0x01, 0xf9, 0x45, + 0x61, 0x0e, 0x66, 0x0e, 0x24, 0x22, 0xe2, 0x59, + 0x66, 0x0d, 0xd3, 0xe9, 0x77, 0x8a, 0x7e, 0x42, + 0xaa, 0x5a, 0xf9, 0x05, 0xbf, 0x30, 0xc7, 0x03, + 0x2b, 0xdc, 0xa6, 0x9c, 0xe0, 0x9f, 0x0d, 0xf1, + 0x28, 0x19, 0xf8, 0xf2, 0x02, 0xfa, 0xbd, 0x62, + 0xa0, 0xf3, 0x02, 0x2b, 0xcd, 0xf7, 0x09, 0x04, + 0x3b, 0x52, 0xd8, 0x65, 0x4b, 0x4a, 0x70, 0xe4, + 0x57, 0xc9, 0x2e, 0x2a, 0xf6, 0x9c, 0x6e, 0xd8, + 0xde, 0x01, 0x52, 0xc9, 0x6f, 0xe9, 0xef, 0x82, + 0xbc, 0x0b, 0x95, 0xb2, 0xef, 0xcb, 0x91, 0xa6, + 0x0b, 0x2d, 0x14, 0xc6, 0x00, 0xa9, 0x33, 0x86, + 0x64, 0x00, 0xd4, 0x92, 0x19, 0x53, 0x3d, 0xfd, + 0xcd, 0xc6, 0x1a, 0xf2, 0x0e, 0x67, 0xc2, 0x1d, + 0x2c, 0xe0, 0xe8, 0x29, 0x97, 0x1c, 0xb6, 0xc4, + 0xb2, 0x02, 0x0c, 0x83, 0xb8, 0x60, 0x61, 0xf5, + 0x61, 0x2d, 0x73, 0x5e, 0x85, 0x4d, 0xbd, 0x0d, + 0xe7, 0x1a, 0x37, 0x56, 0x8d, 0xe5, 0x50, 0x0c, + 0xc9, 0x64, 0x4c, 0x11, 0xea, 0xf3, 0xcb, 0x26, + 0x34, 0xbd, 0x02, 0xf5, 0xc1, 0xfb, 0xa2, 0xec, + 0x27, 0xbb, 0x60, 0xbe, 0x0b, 0xf6, 0xe7, 0x3c, + 0x2d, 0xc9, 0xe7, 0xb0, 0x30, 0x28, 0x17, 0x3d, + 0x90, 0xf1, 0x63, 0x8e, 0x49, 0xf7, 0x15, 0x78, + 0x21, 0xcc, 0x45, 0xe6, 0x86, 0xb2, 0xd8, 0xb0, + 0x2e, 0x5a, 0xb0, 0x58, 0xd3, 0xb6, 0x11, 0x40, + 0xae, 0x81, 0x1f, 0x6b, 0x7a, 0xaf, 0x40, 0x50, + 0xf9, 0x2e, 0x81, 0x8b, 0xec, 0x26, 0x11, 0x3f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x53, 0x30, 0x82, 0x01, 0x4f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, + 0x0b, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x6e, 0x6f, 0x82, 0x09, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xc6, 0x53, 0x87, 0x42, + 0x2d, 0xc8, 0xee, 0x7a, 0x62, 0x1e, 0x83, 0xdb, + 0x0d, 0xe2, 0x32, 0xeb, 0x8b, 0xaf, 0x69, 0x40, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, + 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, + 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, + 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, + 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, + 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, + 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x7b, 0x27, 0x00, 0x46, 0x8f, 0xfd, 0x5b, 0xff, + 0xcb, 0x05, 0x9b, 0xf7, 0xf1, 0x68, 0xf6, 0x9a, + 0x7b, 0xba, 0x53, 0xdf, 0x63, 0xed, 0x11, 0x94, + 0x39, 0xf2, 0xd0, 0x20, 0xcd, 0xa3, 0xc4, 0x98, + 0xa5, 0x10, 0x74, 0xe7, 0x10, 0x6d, 0x07, 0xf8, + 0x33, 0x87, 0x05, 0x43, 0x0e, 0x64, 0x77, 0x09, + 0x18, 0x4f, 0x38, 0x2e, 0x45, 0xae, 0xa8, 0x34, + 0x3a, 0xa8, 0x33, 0xac, 0x9d, 0xdd, 0x25, 0x91, + 0x59, 0x43, 0xbe, 0x0f, 0x87, 0x16, 0x2f, 0xb5, + 0x27, 0xfd, 0xce, 0x2f, 0x35, 0x5d, 0x12, 0xa1, + 0x66, 0xac, 0xf7, 0x95, 0x38, 0x0f, 0xe5, 0xb1, + 0x18, 0x18, 0xe6, 0x80, 0x52, 0x31, 0x8a, 0x66, + 0x02, 0x52, 0x1a, 0xa4, 0x32, 0x6a, 0x61, 0x05, + 0xcf, 0x1d, 0xf9, 0x90, 0x73, 0xf0, 0xeb, 0x20, + 0x31, 0x7b, 0x2e, 0xc0, 0xb0, 0xfb, 0x5c, 0xcc, + 0xdc, 0x76, 0x55, 0x72, 0xaf, 0xb1, 0x05, 0xf4, + 0xad, 0xf9, 0xd7, 0x73, 0x5c, 0x2c, 0xbf, 0x0d, + 0x84, 0x18, 0x01, 0x1d, 0x4d, 0x08, 0xa9, 0x4e, + 0x37, 0xb7, 0x58, 0xc4, 0x05, 0x0e, 0x65, 0x63, + 0xd2, 0x88, 0x02, 0xf5, 0x82, 0x17, 0x08, 0xd5, + 0x8f, 0x80, 0xc7, 0x82, 0x29, 0xbb, 0xe1, 0x04, + 0xbe, 0xf6, 0xe1, 0x8c, 0xbc, 0x3a, 0xf8, 0xf9, + 0x56, 0xda, 0xdc, 0x8e, 0xc6, 0xe6, 0x63, 0x98, + 0x12, 0x08, 0x41, 0x2c, 0x9d, 0x7c, 0x82, 0x0d, + 0x1e, 0xea, 0xba, 0xde, 0x32, 0x09, 0xda, 0x52, + 0x24, 0x4f, 0xcc, 0xb6, 0x09, 0x33, 0x8b, 0x00, + 0xf9, 0x83, 0xb3, 0xc6, 0xa4, 0x90, 0x49, 0x83, + 0x2d, 0x36, 0xd9, 0x11, 0x78, 0xd0, 0x62, 0x9f, + 0xc4, 0x8f, 0x84, 0xba, 0x7f, 0xaa, 0x04, 0xf1, + 0xd9, 0xa4, 0xad, 0x5d, 0x63, 0xee, 0x72, 0xc6, + 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, + 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + f.lastts.tv_sec = 1474978656; /* 2016-09-27 */ + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_valid\"; " + "tls_cert_valid; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_hello, sizeof(client_hello)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + + SCMutexLock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + SCMutexUnlock(&f.m); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + #endif /* UNITTESTS */ /** @@ -1632,3 +2025,13 @@ void TlsExpiredRegisterTests(void) UtRegisterTest("ExpiredTestDetect01", ExpiredTestDetect01); #endif /* UNITTESTS */ } + +/** + * \brief Register unit tests for tls_cert_valid + */ +void TlsValidRegisterTests(void) +{ +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("ValidTestDetect01", ValidTestDetect01); +#endif /* UNITTESTS */ +} diff --git a/src/detect-tls-cert-validity.h b/src/detect-tls-cert-validity.h index 9840635a1e3d..256be6b4b2b5 100644 --- a/src/detect-tls-cert-validity.h +++ b/src/detect-tls-cert-validity.h @@ -32,6 +32,9 @@ /* Used by tls_cert_expired */ #define DETECT_TLS_VALIDITY_EX (1<<4) /* expired */ +/* Used by tls_cert_valid */ +#define DETECT_TLS_VALIDITY_VA (1<<5) /* valid */ + #define DETECT_TLS_TYPE_NOTBEFORE 0 #define DETECT_TLS_TYPE_NOTAFTER 1 diff --git a/src/detect.h b/src/detect.h index a48bcef7c4d4..a1b266ca644e 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1268,6 +1268,7 @@ enum { DETECT_AL_TLS_NOTBEFORE, DETECT_AL_TLS_NOTAFTER, DETECT_AL_TLS_EXPIRED, + DETECT_AL_TLS_VALID, DETECT_AL_TLS_FINGERPRINT, DETECT_AL_TLS_STORE, From 10d827639e279d9fab977bd32ac9503f9b44c841 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 27 Sep 2016 17:56:22 +0200 Subject: [PATCH 2019/2553] detect-tls-cert-validity: clean up unit tests Remove locks, unnecessary function calls and conditional statements. --- src/detect-tls-cert-validity.c | 51 ++++++---------------------------- 1 file changed, 9 insertions(+), 42 deletions(-) diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index e14ed5c4f868..09bb60eb6afc 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -1259,11 +1259,9 @@ int ValidityTestDetect01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); - SCMutexUnlock(&f.m); FAIL_IF(r != 0); @@ -1275,10 +1273,8 @@ int ValidityTestDetect01(void) FAIL_IF(PacketAlertCheck(p1, 1)); FAIL_IF(PacketAlertCheck(p1, 2)); - SCMutexLock(&f.m); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); - SCMutexUnlock(&f.m); FAIL_IF(r != 0); @@ -1287,10 +1283,8 @@ int ValidityTestDetect01(void) FAIL_IF(PacketAlertCheck(p2, 1)); FAIL_IF(PacketAlertCheck(p2, 2)); - SCMutexLock(&f.m); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); - SCMutexUnlock(&f.m); FAIL_IF(r != 0); @@ -1299,14 +1293,9 @@ int ValidityTestDetect01(void) FAIL_IF_NOT(PacketAlertCheck(p3, 1)); FAIL_IF_NOT(PacketAlertCheck(p3, 2)); - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); @@ -1598,10 +1587,8 @@ int ExpiredTestDetect01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); - SCMutexUnlock(&f.m); FAIL_IF(r != 0); @@ -1612,10 +1599,8 @@ int ExpiredTestDetect01(void) FAIL_IF(PacketAlertCheck(p1, 1)); - SCMutexLock(&f.m); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); - SCMutexUnlock(&f.m); FAIL_IF(r != 0); @@ -1623,10 +1608,8 @@ int ExpiredTestDetect01(void) FAIL_IF(PacketAlertCheck(p2, 1)); - SCMutexLock(&f.m); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); - SCMutexUnlock(&f.m); FAIL_IF(r != 0); @@ -1634,14 +1617,9 @@ int ExpiredTestDetect01(void) FAIL_IF_NOT(PacketAlertCheck(p3, 1)); - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); @@ -1918,10 +1896,8 @@ int ValidTestDetect01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); - SCMutexUnlock(&f.m); FAIL_IF(r != 0); @@ -1932,10 +1908,8 @@ int ValidTestDetect01(void) FAIL_IF(PacketAlertCheck(p1, 1)); - SCMutexLock(&f.m); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); - SCMutexUnlock(&f.m); FAIL_IF(r != 0); @@ -1943,10 +1917,8 @@ int ValidTestDetect01(void) FAIL_IF(PacketAlertCheck(p2, 1)); - SCMutexLock(&f.m); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); - SCMutexUnlock(&f.m); FAIL_IF(r != 0); @@ -1954,14 +1926,9 @@ int ValidTestDetect01(void) FAIL_IF_NOT(PacketAlertCheck(p3, 1)); - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); From 7e4df3a1d17ad7d7279601a395b2e9329ad8ee43 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 12:33:49 +0200 Subject: [PATCH 2020/2553] tls-validity: fix memory handling --- src/detect-tls-cert-validity.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index 09bb60eb6afc..1da3270324d9 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -418,7 +418,7 @@ static int DetectTlsExpiredSetup (DetectEngineCtx *de_ctx, Signature *s, SCLogDebug("\'%s\'", rawstr); - dd = SCMalloc(sizeof(DetectTlsValidityData)); + dd = SCCalloc(1, sizeof(DetectTlsValidityData)); if (dd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Allocation \'%s\' failed", rawstr); goto error; @@ -436,7 +436,7 @@ static int DetectTlsExpiredSetup (DetectEngineCtx *de_ctx, Signature *s, goto error; } - dd->mode |= DETECT_TLS_VALIDITY_EX; + dd->mode = DETECT_TLS_VALIDITY_EX; dd->type = DETECT_TLS_TYPE_NOTAFTER; dd->epoch = 0; dd->epoch2 = 0; @@ -476,7 +476,7 @@ static int DetectTlsValidSetup (DetectEngineCtx *de_ctx, Signature *s, SCLogDebug("\'%s\'", rawstr); - dd = SCMalloc(sizeof(DetectTlsValidityData)); + dd = SCCalloc(1, sizeof(DetectTlsValidityData)); if (dd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Allocation \'%s\' failed", rawstr); goto error; @@ -494,7 +494,7 @@ static int DetectTlsValidSetup (DetectEngineCtx *de_ctx, Signature *s, goto error; } - dd->mode |= DETECT_TLS_VALIDITY_VA; + dd->mode = DETECT_TLS_VALIDITY_VA; dd->type = DETECT_TLS_TYPE_NOTAFTER; dd->epoch = 0; dd->epoch2 = 0; From 595c20ddf4e21d6f2251a037dea9b8ba5c13ee77 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 14:06:32 +0200 Subject: [PATCH 2021/2553] der: fix asan/valgrind errors in time parsing --- src/util-decode-der-get.c | 4 ++-- src/util-time.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util-decode-der-get.c b/src/util-decode-der-get.c index 747bf4b4226b..fc132cf45e2d 100644 --- a/src/util-decode-der-get.c +++ b/src/util-decode-der-get.c @@ -85,7 +85,7 @@ static time_t GentimeToTime(char *gentime) if (strlen(gentime) != 15) goto error; - tm.tm_gmtoff = 0; + memset(&tm, 0, sizeof(tm)); strptime(gentime, "%Y%m%d%H%M%SZ", &tm); time = SCMkTimeUtc(&tm); @@ -102,7 +102,7 @@ static time_t UtctimeToTime(char *utctime) { time_t time; unsigned int year; - char yy[2]; + char yy[3]; char buf[20]; /* UTCTime values MUST be expressed in Greenwich Mean Time (Zulu) diff --git a/src/util-time.c b/src/util-time.c index 6670a0157add..b1726e81c578 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -180,6 +180,7 @@ void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size) { time_t time = ts->tv_sec; struct tm local_tm; + memset(&local_tm, 0, sizeof(local_tm)); struct tm *t = (struct tm*)SCLocalTime(time, &local_tm); char time_fmt[64] = { 0 }; @@ -195,6 +196,7 @@ void CreateUtcIsoTimeString (const struct timeval *ts, char *str, size_t size) { time_t time = ts->tv_sec; struct tm local_tm; + memset(&local_tm, 0, sizeof(local_tm)); struct tm *t = (struct tm*)SCUtcTime(time, &local_tm); char time_fmt[64] = { 0 }; From a3a175747213f38b19af28af262b5c6b80344650 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 30 Sep 2016 16:26:40 +0200 Subject: [PATCH 2022/2553] flow-mgr: fix bypass counter registration --- src/flow-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 8da17f93e63f..dece557ea15b 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -621,7 +621,7 @@ static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) ftd->flow_mgr_cnt_clo = StatsRegisterCounter("flow_mgr.closed_pruned", t); ftd->flow_mgr_cnt_new = StatsRegisterCounter("flow_mgr.new_pruned", t); ftd->flow_mgr_cnt_est = StatsRegisterCounter("flow_mgr.est_pruned", t); - ftd->flow_mgr_cnt_est = StatsRegisterCounter("flow_mgr.bypassed_pruned", t); + ftd->flow_mgr_cnt_byp = StatsRegisterCounter("flow_mgr.bypassed_pruned", t); ftd->flow_mgr_spare = StatsRegisterCounter("flow.spare", t); ftd->flow_emerg_mode_enter = StatsRegisterCounter("flow.emerg_mode_entered", t); ftd->flow_emerg_mode_over = StatsRegisterCounter("flow.emerg_mode_over", t); From 46f5f4cff81411c1d40997b2e393ab20df219f88 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 2 Oct 2016 22:39:29 +0200 Subject: [PATCH 2023/2553] util: add facility to check for RWX page support Some code won't work well when the OS doesn't allow RWX pages. This page introduces a check for runtime evaluation of the OS' policy on this. Thanks to Shawn Webb from HardenedBSD for suggesting this solution. --- src/Makefile.am | 1 + src/util-pages.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util-pages.h | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 src/util-pages.c create mode 100644 src/util-pages.h diff --git a/src/Makefile.am b/src/Makefile.am index d636765cff2f..191776a5d288 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -392,6 +392,7 @@ util-mpm-ac-tile-small.c \ util-mpm-hs.c util-mpm-hs.h \ util-mpm.c util-mpm.h \ util-optimize.h \ +util-pages.c util-pages.h \ util-path.c util-path.h \ util-pidfile.c util-pidfile.h \ util-pool.c util-pool.h \ diff --git a/src/util-pages.c b/src/util-pages.c new file mode 100644 index 000000000000..900c063be9b7 --- /dev/null +++ b/src/util-pages.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2016 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 + * + * Page util functions + */ + +#include "suricata-common.h" +#ifndef HAVE_SYS_MMAN_H +#define PageSupportsRWX 1 +#else +#include + +/** \brief check if OS allows for RWX pages + * + * Some OS' disallow RWX pages for security reasons. This function mmaps + * some memory RW and then tries to turn it into RWX. If this fails we + * assume that the OS doesn't allow for this. + * + * Thanks to Shawn Webb from HardenedBSD for the suggestion. + * + * \retval 1 RWX supported + * \retval 0 not supported + */ +int PageSupportsRWX(void) +{ + int retval = 1; + void *ptr; + ptr = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); + if (ptr != MAP_FAILED) { + if (mprotect(ptr, getpagesize(), PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { + SCLogConfig("RWX pages denied by OS"); + retval = 0; + } + munmap(ptr, getpagesize()); + } + return retval; +} +#endif /* HAVE_SYS_MMAN_H */ + diff --git a/src/util-pages.h b/src/util-pages.h new file mode 100644 index 000000000000..dd096734a10b --- /dev/null +++ b/src/util-pages.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2016 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 + * + */ + +#ifndef __UTIL_PAGES_H__ +#define __UTIL_PAGES_H__ + +#include "suricata-common.h" + +#ifdef __OpenBSD__ + /* OpenBSD won't allow for this test: + * "suricata(...): mprotect W^X violation" */ + #define PageSupportsRWX() 0 +#else + #ifndef HAVE_SYS_MMAN_H + #define PageSupportsRWX() 1 + #else + int PageSupportsRWX(void); + #endif /* HAVE_SYS_MMAN_H */ +#endif + +#endif /* __UTIL_PAGES_H__ */ From 4a190e07a608633dc7c8e58ce6beab717399d677 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 2 Oct 2016 22:49:32 +0200 Subject: [PATCH 2024/2553] pcre: disable JIT if RWX pages not supported --- src/detect-pcre.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index ed66a9f1e6f6..c9733deb6210 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -57,6 +57,7 @@ #include "stream-tcp-reassemble.h" #include "app-layer-protos.h" #include "app-layer-parser.h" +#include "util-pages.h" #define PARSE_CAPTURE_REGEX "\\(\\?P\\<([A-z]+)\\_([A-z0-9_]+)\\>" #define PARSE_REGEX "(?sd = pcre_study(pd->re, PCRE_STUDY_JIT_COMPILE, &eb); + if (pcre_use_jit) + options |= PCRE_STUDY_JIT_COMPILE; +#endif + pd->sd = pcre_study(pd->re, options, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed : %s", eb); goto error; } +#ifdef PCRE_HAVE_JIT int jit = 0; ret = pcre_fullinfo(pd->re, pd->sd, PCRE_INFO_JIT, &jit); if (ret != 0 || jit != 1) { @@ -520,12 +538,6 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, "Falling back to regular PCRE handling (%s:%d)", regexstr, de_ctx->rule_file, de_ctx->rule_line); } -#else - pd->sd = pcre_study(pd->re, 0, &eb); - if(eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed : %s", eb); - goto error; - } #endif /*PCRE_HAVE_JIT*/ if (pd->sd == NULL) From 96c28b2995e9681cb6e5ca15b891415c8501369b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 2 Oct 2016 23:29:38 +0200 Subject: [PATCH 2025/2553] bug 1353: don't cut off last char of unix path --- src/unix-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index 86f619676364..fb88c30efe1c 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -154,7 +154,7 @@ int UnixNew(UnixCommand * this) addr.sun_family = AF_UNIX; strlcpy(addr.sun_path, sockettarget, sizeof(addr.sun_path)); addr.sun_path[sizeof(addr.sun_path) - 1] = 0; - len = strlen(addr.sun_path) + sizeof(addr.sun_family); + len = strlen(addr.sun_path) + sizeof(addr.sun_family) + 1; /* create socket */ this->socket = socket(AF_UNIX, SOCK_STREAM, 0); From f80ce51ddfaf8bd96c12106e60b19525c75074cb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Oct 2016 08:33:11 +0200 Subject: [PATCH 2026/2553] unix-socket: don't try to change permissions on BSD On BSD using fchmod on a socket is not supported and will result in EINVAL. --- src/unix-manager.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index fb88c30efe1c..d1959684c5bc 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -167,9 +167,10 @@ int UnixNew(UnixCommand * this) } this->select_max = this->socket + 1; +#if !(defined OS_FREEBSD || defined __OpenBSD__) /* Set file mode: will not fully work on most system, the group - * permission is not changed on some Linux and *BSD won't do the - * chmod. */ + * permission is not changed on some Linux. *BSD won't do the + * chmod: it returns EINVAL when calling fchmod on sockets. */ ret = fchmod(this->socket, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (ret == -1) { int err = errno; @@ -178,6 +179,7 @@ int UnixNew(UnixCommand * this) strerror(err), err); } +#endif /* set reuse option */ ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); From bec128bbf949b17838908c694c2fa00d65f9ad86 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 28 Sep 2016 15:25:48 -0600 Subject: [PATCH 2027/2553] doc: attempt to parse version if not in environment Should fix the version displayed on readthedocs. --- doc/userguide/conf.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/userguide/conf.py b/doc/userguide/conf.py index e16144cb85c0..219dfd15798c 100644 --- a/doc/userguide/conf.py +++ b/doc/userguide/conf.py @@ -15,6 +15,7 @@ import sys import os import shlex +import re on_rtd = os.environ.get('READTHEDOCS', None) == 'True' @@ -57,8 +58,18 @@ # built documents. # # The short X.Y version. -version = os.environ.get('version', "unknown") -# The full version, including alpha/beta/rc tags. + +# Attempt to extract the version configure.ac. +try: + version = os.environ.get('version', None) + if not version: + version = re.search( + "AC_INIT\(suricata,\s*(.*)?\)", + open("../../configure.ac").read()).groups()[0] + if not version: + version = "unknown" +except: + version = "unknown" release = version # The language for content autogenerated by Sphinx. Refer to documentation From 214e97814ccb1a617acbbebcd1848f3ec229a658 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 29 Sep 2016 14:25:43 -0600 Subject: [PATCH 2028/2553] doc: bring in unix socket interaction from wiki --- doc/userguide/index.rst | 1 + doc/userguide/unix-socket.rst | 229 ++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 doc/userguide/unix-socket.rst diff --git a/doc/userguide/index.rst b/doc/userguide/index.rst index 9524ff76ab17..6654f8da0bbf 100644 --- a/doc/userguide/index.rst +++ b/doc/userguide/index.rst @@ -19,6 +19,7 @@ Suricata User Guide file-extraction/file-extraction.rst public-data-sets capture-hardware/index.rst + unix-socket.rst manpages/index.rst acknowledgements licenses/index.rst diff --git a/doc/userguide/unix-socket.rst b/doc/userguide/unix-socket.rst new file mode 100644 index 000000000000..2a4849ddf59d --- /dev/null +++ b/doc/userguide/unix-socket.rst @@ -0,0 +1,229 @@ +Interacting via Unix Socket +=========================== + +Introduction +------------ + +Since 1.4 version, Suricata can listen to a unix socket and accept +commands from the user. The exchange protocol is JSON-based and the +format of the message has been done to be generic and it is described +in this commit message. An example script called suricatasc is +provided in the source and installed automatically when updating +Suricata. + +The unix socket is disabled by default. + +You need to have libjansson installed: + +* libjansson4 - C library for encoding, decoding and manipulating JSON data +* libjansson-dev - C library for encoding, decoding and manipulating JSON data (dev) +* python-simplejson - simple, fast, extensible JSON encoder/decoder for Python + +:: + + apt-get install libjansson4 libjansson-dev python-simplejson + +If libjansson is present on the system , unix socket will be compiled +in automatically - when you use "--enable-unix-socket" in your +configure line. + +The creation of the socket is activated by setting enabled to yes +under unix-command in Suricata YAML configuration file: + +:: + + unix-command: + enabled: yes + #filename: custom.socket # use this to specify an alternate file + +The ``filename`` variable can be used to set an alternate socket +filename. The filename is always relative to the local state base +directory. + +Clients are implemented for some language and can be used as code +example to write custom scripts: + +* Python: https://github.com/inliniac/suricata/blob/master/scripts/suricatasc/suricatasc.in (provided with suricata and used in this document) +* Perl: https://github.com/aflab/suricatac (a simple Perl client with interactive mode) +* C: https://github.com/regit/SuricataC (a unix socket mode client in C without interactive mode) + +Commands in standard running mode +--------------------------------- + + +The set of existing commands is the following: + +* command-list: list available commands +* shutdown: this shutdown suricata +* iface-list: list interfaces where Suricata is sniffing packets +* iface-stat: list statistic for an interface +* help: alias of command-list +* version: display Suricata's version +* uptime: display Suricata's uptime +* running-mode: display running mode (workers, autofp, simple) +* capture-mode: display capture system used +* conf-get: get configuration item (see example below) +* dump-counters: dump Suricata's performance counters + +You can access to these commands with the provided example script which +is named ``suricatasc``. A typical session with ``suricatasc`` will looks like: + +:: + + # suricatasc + Command list: shutdown, command-list, help, version, uptime, running-mode, capture-mode, conf-get, dump-counters, iface-stat, iface-list, quit + >>> iface-list + Success: {'count': 2, 'ifaces': ['eth0', 'eth1']} + >>> iface-stat eth0 + Success: {'pkts': 378, 'drop': 0, 'invalid-checksums': 0} + >>> conf-get unix-command.enabled + Success: + "yes" + +Commands on the cmd prompt +-------------------------- + +You can use suricatasc directly on the command prompt: + +:: + + + root@debian64:~# suricatasc -c version + {'message': '2.1beta2 RELEASE', 'return': 'OK'} + root@debian64:~# + root@debian64:~# suricatasc -c uptime + {'message': 35264, 'return': 'OK'} + root@debian64:~# + + +**NOTE:** +You need to quote commands involving more than one argument: + +:: + + + root@debian64:~# suricatasc -c "iface-stat eth0" + {'message': {'pkts': 5110429, 'drop': 0, 'invalid-checksums': 0}, 'return': 'OK'} + root@debian64:~# + + +Pcap processing mode +-------------------- + +This mode is one of main motivation behind this code. The idea is to +be able to ask to Suricata to treat different pcap files without +having to restart Suricata between the files. This provides you a huge +gain in time as you don’t need to wait for the signature engine to +initialize. + +To use this mode, start suricata with your preferred YAML file and +provide the option ``--unix-socket`` as argument: + +:: + + suricata -c /etc/suricata-full-sigs.yaml --unix-socket + +It is also possible to specify the socket filename as argument: + +:: + + suricata --unix-socket=custom.socket + +In this last case, you will need to provide the complete path to the +socket to ``suricatasc``. To do so, you need to pass the filename as +first argument of ``suricatasc``: + +:: + + suricatasc custom.socket + +Once Suricata is started, you can use the provided script +``suricatasc`` to connect to the command socket and ask for pcap +treatment: + +:: + + root@tiger:~# suricatasc + >>> pcap-file /home/benches/file1.pcap /tmp/file1 + Success: Successfully added file to list + >>> pcap-file /home/benches/file2.pcap /tmp/file2 + Success: Successfully added file to list + +You can add multiple files without waiting the result: they will be +sequentially processed and the generated log/alert files will be put +into the directory specified as second arguments of the pcap-file +command. You need to provide absolute path to the files and directory +as suricata don’t know from where the script has been run. + +To know how much files are waiting to get processed, you can do: + +:: + + >>> pcap-file-number + Success: 3 + +To get the list of queued files, do: + +:: + + >>> pcap-file-list + Success: {'count': 2, 'files': ['/home/benches/file1.pcap', '/home/benches/file2.pcap']} + +To get current processed file: + +:: + + >>> pcap-current + Success: + "/tmp/test.pcap" + +Build your own client +--------------------- + +The protocol is documented in the following page +https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Unix_Socket#Protocol + +The following session show what is send (SND) and received (RCV) by +the server. Initial negotiation is the following: + +:: + + # suricatasc + SND: {"version": "0.1"} + RCV: {"return": "OK"} + +Once this is done, command can be issued: + +:: + + >>> iface-list + SND: {"command": "iface-list"} + RCV: {"message": {"count": 1, "ifaces": ["wlan0"]}, "return": "OK"} + Success: {'count': 1, 'ifaces': ['wlan0']} + >>> iface-stat wlan0 + SND: {"command": "iface-stat", "arguments": {"iface": "wlan0"}} + RCV: {"message": {"pkts": 41508, "drop": 0, "invalid-checksums": 0}, "return": "OK"} + Success: {'pkts': 41508, 'drop': 0, 'invalid-checksums': 0} + +In pcap-file mode, this gives: + +:: + + >>> pcap-file /home/eric/git/oisf/benches/sandnet.pcap /tmp/bench + SND: {"command": "pcap-file", "arguments": {"output-dir": "/tmp/bench", "filename": "/home/eric/git/oisf/benches/sandnet.pcap"}} + RCV: {"message": "Successfully added file to list", "return": "OK"} + Success: Successfully added file to list + >>> pcap-file-number + SND: {"command": "pcap-file-number"} + RCV: {"message": 1, "return": "OK"} + >>> pcap-file-list + SND: {"command": "pcap-file-list"} + RCV: {"message": {"count": 1, "files": ["/home/eric/git/oisf/benches/sandnet.pcap"]}, "return": "OK"} + Success: {'count': 1, 'files': ['/home/eric/git/oisf/benches/sandnet.pcap']} + +There is one thing to be careful about: a suricata message is sent in +multiple send operations. This result in possible incomplete read on +client side. The worse workaround is to sleep a bit before trying a +recv call. An other solution is to use non blocking socket and retry a +recv if the previous one has failed. This method is used here: +source:scripts/suricatasc/suricatasc.in#L43 From a6854147be6103d5c33e2c20411cc316c20d13f6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Sun, 25 Sep 2016 19:28:23 -0600 Subject: [PATCH 2029/2553] pcap-log config: sguil-base-dir -> dir and update comment The code already looks for "dir" first instead of "squil-base-dir", and already respects this configuration parameter in other modes than the "sguil" mode. Coda will still access "sguil-base-dir". --- suricata.yaml.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 54cfc0868e4b..74b73d7f1d8b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -341,7 +341,11 @@ outputs: max-files: 2000 mode: normal # normal, multi or sguil. - #sguil-base-dir: /nsm_data/ + + # Directory to place pcap files. If not provided the default log + # directory will be used. Required for "sguil" mode. + #dir: /nsm_data/ + #ts-format: usec # sec or usec second format (default) is filename.sec usec is filename.sec.usec use-stream-depth: no #If set to "yes" packets seen after reaching stream inspection depth are ignored. "no" logs all packets honor-pass-rules: no # If set to "yes", flows in which a pass rule matched will stopped being logged. From 09c3e1dd8ad8d695c6c1b4916382b4202d60c7bd Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Sat, 24 Sep 2016 08:01:02 -0600 Subject: [PATCH 2030/2553] pcap-log: cleanup allocations at exit Particularly in multi-mode, allocations made for each thread were not being cleaned. ASAN reports no leaks now on exit. --- src/log-pcap.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/log-pcap.c b/src/log-pcap.c index 258e483ece23..b21f785452ac 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -547,6 +547,27 @@ static void StatsMerge(PcapLogData *dst, PcapLogData *src) dst->profile_data_size += src->profile_data_size; } +static void PcapLogDataFree(PcapLogData *pl) +{ + + PcapFileName *pf; + while ((pf = TAILQ_FIRST(&pl->pcap_file_list)) != NULL) { + TAILQ_REMOVE(&pl->pcap_file_list, pf, next); + PcapFileNameFree(pf); + } + if (pl == g_pcap_data) { + for (int i = 0; i < MAX_TOKS; i++) { + if (pl->filename_parts[i] != NULL) { + SCFree(pl->filename_parts[i]); + } + } + } + SCFree(pl->h); + SCFree(pl->filename); + SCFree(pl->prefix); + SCFree(pl); +} + /** * \brief Thread deinit function. * @@ -579,6 +600,11 @@ static TmEcode PcapLogDataDeinit(ThreadVars *t, void *thread_data) pl->reported = 1; } } + + if (pl != g_pcap_data) { + PcapLogDataFree(pl); + } + SCFree(td); return TM_ECODE_OK; } @@ -902,6 +928,7 @@ static void PcapLogFileDeInitCtx(OutputCtx *output_ctx) TAILQ_FOREACH(pf, &pl->pcap_file_list, next) { SCLogDebug("PCAP files left at exit: %s\n", pf->filename); } + PcapLogDataFree(pl); SCFree(output_ctx); return; } From d4c7c2c2c706f3ab604fd0f4f459cb2c5807a9da Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Oct 2016 09:53:13 +0200 Subject: [PATCH 2031/2553] cygwin: leave magic-file commented out in yaml --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index 1ccd5e343999..c3b8e8b65bb4 100644 --- a/configure.ac +++ b/configure.ac @@ -1939,7 +1939,6 @@ if test "$WINDOWS_PATH" = "yes"; then e_sysconfdir="$e_winbase\\\\" e_sysconfrulesdir="$e_winbase\\\\rules\\\\" e_magic_file="$e_winbase\\\\magic.mgc" - e_magic_file_comment="" e_logdir="$e_winbase\\\\log" e_logfilesdir="$e_logdir\\\\files" e_logcertsdir="$e_logdir\\\\certs" From 790ac8d417d451358a2aca6db81a4cc5363fad33 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Oct 2016 14:56:41 +0200 Subject: [PATCH 2032/2553] changelog: update for 3.2beta1 --- ChangeLog | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ChangeLog b/ChangeLog index aa5541095ae6..8972324b77cf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +3.2beta1 -- 2016-10-03 + +Feature #509: add SHA1 and SHA256 checksum support for files +Feature #1231: ssl_state negation support +Feature #1345: OOBE -3- disable NIC offloading by default +Feature #1373: Allow different reassembly depth for filestore rules +Feature #1495: EtherNet/IP and CIP support +Feature #1583: tls: validity fields (notBefore and notAfter) +Feature #1657: Per application layer stats +Feature #1896: Reimplement tls.subject and tls.isserdn +Feature #1903: tls: tls_cert_valid and tls_cert_expired keywords +Feature #1907: http_request_line and http_response_line +Optimization #1044: TLS buffers evaluated by fast_pattern matcher. +Optimization #1277: Trigger second live rule-reload while first one is in progress +Bug #312: incorrect parsing of rules with missing semi-colon for keywords +Bug #712: wildcard matches on tls.subject +Bug #1353: unix-command socket created with last character missing +Bug #1486: invalid rule: parser err msg not descriptive enough +Bug #1525: Use pkg-config for libnetfilter_queue +Bug #1893: tls: src_ip and dest_ip reversed in TLS events for IPS vs IDS mode. +Bug #1898: Inspection does not always stop when stream depth is reached + 3.1.2 -- 2016-09-06 Feature #1830: support 'tag' in eve log From 79d21e9eee4dafcfefcae3588ee35188c42430b7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 3 Oct 2016 10:21:39 -0600 Subject: [PATCH 2033/2553] docs: include userguide.pdf in dist --- doc/userguide/Makefile.am | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index 9f83c42f4376..ed69f0a62d16 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -28,7 +28,7 @@ endif if HAVE_SPHINXBUILD man1_MANS = suricata.1 -EXTRA_DIST += $(man1_MANS) +EXTRA_DIST += $(man1_MANS) userguide.pdf SPHINX_BUILD = sphinx-build -q @@ -39,7 +39,7 @@ html: $(SPHINX_BUILD) -b html -d _build/doctrees \ $(top_srcdir)/doc/userguide _build/html -pdf: +_build/latex/Suricata.pdf: sysconfdir=$(sysconfdir) \ localstatedir=$(localstatedir) \ version=$(PACKAGE_VERSION) \ @@ -47,6 +47,11 @@ pdf: $(top_srcdir)/doc/userguide _build/latex cd _build/latex && $(MAKE) all-pdf +userguide.pdf: _build/latex/Suricata.pdf + cp _build/latex/Suricata.pdf userguide.pdf + +pdf: userguide.pdf + _build/man/suricata.1: sysconfdir=$(sysconfdir) \ localstatedir=$(localstatedir) \ @@ -54,12 +59,15 @@ _build/man/suricata.1: $(SPHINX_BUILD) -b man -d _build/doctrees \ $(top_srcdir)/doc/userguide _build/man -man: _build/man/suricata.1 - suricata.1: _build/man/suricata.1 cp _build/man/suricata.1 suricata.1 +man: _build/man/suricata.1 + +# Remove build artifacts that aren't tracked by autotools. clean-local: rm -rf $(top_builddir)/doc/userguide/_build rm -f $(top_builddir)/doc/userguide/suricata.1 -endif + rm -f $(top_builddir)/doc/userguide/suricata.pdf + +endif # HAVE_SPHINXBUILD From 3df7f97a33a0897cfd1738d6385c3459ae8645a8 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 3 Oct 2016 11:15:50 -0600 Subject: [PATCH 2034/2553] doc: fail on sphinx warnings --- doc/userguide/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index ed69f0a62d16..796392d7db34 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -30,7 +30,7 @@ man1_MANS = suricata.1 EXTRA_DIST += $(man1_MANS) userguide.pdf -SPHINX_BUILD = sphinx-build -q +SPHINX_BUILD = sphinx-build -q -W html: sysconfdir=$(sysconfdir) \ From cd4c9e73f8f69bd667ef2d560cfd6c00e9eb8878 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 3 Oct 2016 11:16:13 -0600 Subject: [PATCH 2035/2553] doc: fix sphinx warnings This involved removing documents that were intentionally not referenced as they are not good candidates for the user guide. --- doc/userguide/command-line-options.rst | 6 +- .../file-extraction/file-extraction.rst | 1 - ...filemd5-and-whiteblacklisting-with-md5.rst | 256 ------------------ doc/userguide/output/files-json/elk.rst | 239 ---------------- .../output/files-json/files-json.rst | 62 ----- doc/userguide/output/files-json/mongodb.rst | 97 ------- doc/userguide/output/files-json/mysql.rst | 36 --- .../output/files-json/postgresql.rst | 79 ------ .../output/files-json/script-follow-json.rst | 100 ------- ...seful-queries-for-mysql-and-postgresql.rst | 138 ---------- .../performance/tuning-considerations.rst | 2 +- doc/userguide/rules/enip-keyword.rst | 2 +- 12 files changed, 4 insertions(+), 1014 deletions(-) delete mode 100644 doc/userguide/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst delete mode 100644 doc/userguide/output/files-json/elk.rst delete mode 100644 doc/userguide/output/files-json/files-json.rst delete mode 100644 doc/userguide/output/files-json/mongodb.rst delete mode 100644 doc/userguide/output/files-json/mysql.rst delete mode 100644 doc/userguide/output/files-json/postgresql.rst delete mode 100644 doc/userguide/output/files-json/script-follow-json.rst delete mode 100644 doc/userguide/output/files-json/useful-queries-for-mysql-and-postgresql.rst diff --git a/doc/userguide/command-line-options.rst b/doc/userguide/command-line-options.rst index 15f9c6165159..ed522eff5d6c 100644 --- a/doc/userguide/command-line-options.rst +++ b/doc/userguide/command-line-options.rst @@ -79,15 +79,13 @@ For more information about runmodes see: :doc:`performance/runmodes` Capture Options ~~~~~~~~~~~~~~~ -.. option:: --af-packet -.. option:: --af-packet= +.. option:: --af-packet[=] Enable capture of packet using AF_PACKET on Linux. If no device is supplied, the list of devices from the af-packet section in the yaml is used. -.. option:: --netmap -.. option:: --netmap= +.. option:: --netmap[=] Enable capture of packet using NETMAP on FreeBSD or Linux. If no device is supplied, the list of devices from the netmap section diff --git a/doc/userguide/file-extraction/file-extraction.rst b/doc/userguide/file-extraction/file-extraction.rst index f4bc439ff49d..cb7d10259c98 100644 --- a/doc/userguide/file-extraction/file-extraction.rst +++ b/doc/userguide/file-extraction/file-extraction.rst @@ -99,4 +99,3 @@ Suricata can calculate MD5 checksums of files on the fly and log them. See :doc: md5 public-sha1-md5-data-sets - diff --git a/doc/userguide/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst b/doc/userguide/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst deleted file mode 100644 index 1e24c2a59189..000000000000 --- a/doc/userguide/file-extraction/filemd5-and-whiteblacklisting-with-md5.rst +++ /dev/null @@ -1,256 +0,0 @@ -.. _filemd5-listing: - -Filemd5 and white or black listing with MD5 hashes -================================================== - - - -This guide will show you how to set up a white/black MD5 listing using latest Suricata on Ubuntu LTS 12.04 64 bit -and a file containing 87 million MD5s - white list. - - -In this set up we had/did the following : - -1. A Suricata installation with :doc:`md5` enabled. -2. We start Suricata with about 4.5K rules and the MD5 white list file containing 87 million MD5 entries. -3. We have a 9.5Gb of traffic. -4. We have the following set up: - - -:: - - - CPU: One Intel(R) Xeon(R) CPU E5-2680 0 @ 2.70GHz (16 cores counting Hyperthreading) - Memory: 32Gb - capture NIC: Intel 82599EB 10-Gigabit SFI/SFP+ - - - -You need to get the white list file containing MD5s from here - http://www.nsrl.nist.gov/Downloads.htm -This is an official database containing SHA-1 and MD5s for files that are " traceable ". -For example after you download and unzip (I used the Combo DVD link) you would get a file like so: - - -:: - - - - "SHA-1","MD5","CRC32","FileName","FileSize","ProductCode","OpSystemCode","SpecialCode" - "000000206738748EDD92C4E3D2E823896700F849","392126E756571EBF112CB1C1CDEDF926","EBD105A0","I05002T2.PFB",98865,3095,"WIN","" - "0000004DA6391F7F5D2F7FCCF36CEBDA60C6EA02","0E53C14A3E48D94FF596A2824307B492","AA6A7B16","00br2026.gif",2226,228,"WIN","" - "000000A9E47BD385A0A3685AA12C2DB6FD727A20","176308F27DD52890F013A3FD80F92E51","D749B562","femvo523.wav",42748,4887,"MacOSX","" - "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,16848,"358","" - "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,18266,"358","" - "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,20316,"358","" - "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,20401,"358","" - "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,2322,"WIN","" - "00000142988AFA836117B1B572FAE4713F200567","9B3702B0E788C6D62996392FE3C9786A","05E566DF","J0180794.JPG",32768,23822,"358","" - - -The file contains 87 million entries/lines, each line having -"SHA-1","MD5","CRC32","FileName","FileSize","ProductCode","OpSystemCode","SpecialCode" -of a traceable file. - -You can use the Linux "cut" utility to make this file into only a MD5 file - have only the MD5 check sums (second row) - which is what we need. -Here is what you can do: - -Download the ComboDVD - http://www.nsrl.nist.gov/RDS/rds_2.47/RDS_247.iso - -unzip/tar, then - -:: - - - cat NSRFile.txt | more - -would be able to see the beginning of the file and get an idea of what does it contain.(shown above) -**NOTE – this is a 10GB file, make sure you have the space!** - -the MD5 column ... should start with "MD5" - - -:: - - - sudo cut -d'"' -f4 NSRFile.txt >> MD5.txt - -and you have only MD5s ...but still with "MD5" on top - - -:: - - - sed -i '1d' MD5.txt - -wait for a while -check the file - - -:: - - - wc -l MD5.txt - -wait for about 2-3 min - -should be about 87Mil something md5s , one per line -**NOTE:** -You can also import the file into a MySQL database, if you would like: - - -:: - - - mysql> create user 'filejson'@'localhost' IDENTIFIED BY 'PASSWORD123'; - Query OK, 0 rows affected (0.00 sec) - - mysql>create database filejsondb; - mysql> grant all privileges on filejsondb.* to 'filejson'@'localhost' with grant option; - mysql> flush privileges; - mysql> use filejsondb; - -Then: - -:: - - - CREATE TABLE MD5(md5_whitelist VARCHAR(32)); - -The trick here for the import is that **the table name and the file name MUST be the same** - aka MySQL table "MD5" and the file is called MD5.txt! - -:: - - - sudo mysqlimport -u root -p --local filejsondb MD5.txt - -Where "filejsondb" is the name of the database. - - - -So , here is how we did it .... - - - -:: - - - pevman@suricata:~$ ls -lh /etc/suricata/et-config/MD5_NSRFile.txt - -rw-r--r-- 1 root root 2.7G Aug 29 00:35 /etc/suricata/et-config/MD5_NSRFile.txt - - pevman@suricata:~$ wc -l /etc/suricata/et-config/MD5_NSRFile.txt - 87345542 /etc/suricata/et-config/MD5_NSRFile.txt - pevman@suricata:~$ - - - - - - -:: - - - pevman@suricata:~$ sudo tcpstat -i eth3 - Time:1346241952 n=6664547 avg=898.01 stddev=757.68 bps=9575769952.00 - Time:1346241957 n=6670750 avg=897.22 stddev=754.07 bps=9576254160.00 - Time:1346241962 n=6626520 avg=903.62 stddev=747.26 bps=9580577822.40 - Time:1346241967 n=6685956 avg=895.15 stddev=749.34 bps=9575883715.20 - Time:1346241972 n=6712481 avg=891.53 stddev=747.34 bps=9575027134.40 - Time:1346241977 n=6696189 avg=893.82 stddev=746.62 bps=9576294273.60 - Time:1346241982 n=6681826 avg=895.75 stddev=749.67 bps=9576376033.60 - - - - - -:: - - - pevman@suricata:~$ suricata --build-info - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:539) (SCPrintBuildInfo) -- This is Suricata version 1.4dev (rev 75af345) - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:612) (SCPrintBuildInfo) -- Features: PCAP_SET_BUFF LIBPCAP_VERSION_MAJOR=1 AF_PACKET HAVE_PACKET_FANOUT LIBCAP_NG LIBNET1.1 HAVE_HTP_URI_NORMALIZE_HOOK HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW HAVE_NSS - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:626) (SCPrintBuildInfo) -- 64-bits, Little-endian architecture - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:628) (SCPrintBuildInfo) -- GCC version 4.6.3, C version 199901 - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:634) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:637) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:640) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:643) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:646) (SCPrintBuildInfo) -- __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:650) (SCPrintBuildInfo) -- compiled with -fstack-protector - [2746] 29/8/2012 -- 15:07:25 - (suricata.c:656) (SCPrintBuildInfo) -- compiled with _FORTIFY_SOURCE=2 - -During Suricata start up : -... - -:: - - - [3071] 29/8/2012 -- 15:23:45 - (detect.c:670) (SigLoadSignatures) -- Loading rule file: /var/data/peter/md5test.rules - [3071] 29/8/2012 -- 15:23:45 - (detect-filemd5.c:105) (Md5ReadString) -- [ERRCODE: SC_ERR_INVALID_MD5(214)] - md5 string not 32 bytes - [3071] 29/8/2012 -- 15:24:25 - (detect-filemd5.c:277) (DetectFileMd5Parse) -- MD5 hash size 1399625840 bytes, negated match - [3071] 29/8/2012 -- 15:24:25 - (detect.c:701) (SigLoadSignatures) -- 5 rule files processed. 4641 rules succesfully loaded, 0 rules failed - - -You will get the - -:: - - [ERRCODE: SC_ERR_INVALID_MD5(214)] - md5 string not 32 bytes - -if a line of the file is not containing a proper MD5 hash. - -For example above we get the err message (which is more of a warning) because in the file , the first line was containing: -"SHA-1","MD5","CRC32","FileName","FileSize","ProductCode","OpSystemCode","SpecialCode" - -However , nonetheless Suricata will continue loading the rest of the MD5 hashes from the file. REMEMBER - you would need put only the MD5 hashes in the file. - - -Then we just created the following test rules: - -:: - - - root@suricata:/etc/suricata/peter-yaml# cat /var/data/peter/md5test.rules - alert http any any -> any any (msg:"FILE MD5 Check PDF against a white list"; filemagic:"pdf"; filemd5:!MD5_NSRFile.txt; sid:9966699; rev:1;) - alert http any any -> any any (msg:"FILE MD5 Check EXE against a white list"; filemagic:"exe"; filemd5:!MD5_NSRFile.txt; sid:9977799; rev:2;) - -Make sure the **MD5_NSRFile.txt** file (containing the MD5 hashes) is in your "rules directory" (where you load the rules from). - - -Basically the two rules above are telling Suricata to do the following: -1. If you see a PDF document that has a MD5 hash NOT in the MD5_NSRFile.txt - generate an alert -2. If you see an EXE file that has a MD5 hash NOT in the MD5_NSRFile.txt - generate an alert - -all that on the fly, while inspecting traffic. - - -Then all that is left is to start Suricata: - -:: - - - sudo /usr/local/bin/suricata -c /etc/suricata/peter-yaml/suricata-af-packet-mmap.yaml -s /var/data/peter/md5test.rules --af-packet=eth3 - -and we get the alerts: - - -:: - - - 08/29/2012-15:38:43.165038 [**] [1:9977799:2] FILE MD5 Check EXE against a white list [**] [Classification: (null)] [Priority: 3] {TCP} y.y.y.y:80 -> x.x.x.x:23836 - 08/29/2012-15:39:32.551950 [**] [1:9977799:2] FILE MD5 Check EXE against a white list [**] [Classification: (null)] [Priority: 3] {TCP} y.y.y.y:2091 -> x.x.x.x:80 - - - -That's it. - -You can reverse and use the above rules with a "blacklisting" of MD5 hashes, for example: - - -:: - - - alert http any any -> any any (msg:"FILE MD5 Check PDF against a black list"; filemagic:"pdf"; filemd5:BlackMD5s.txt; sid:9966699; rev:1;) - -You can also use the filestore keyword to store the file on disk and do further analysis on the particular file - or blend it in with other :doc:`../rules/file-keywords`. - -Peter Manev diff --git a/doc/userguide/output/files-json/elk.rst b/doc/userguide/output/files-json/elk.rst deleted file mode 100644 index 234cf203ca54..000000000000 --- a/doc/userguide/output/files-json/elk.rst +++ /dev/null @@ -1,239 +0,0 @@ -Logstash Kibana and Suricata JSON output -======================================== - -With the release of Suricata 2.0rc1 , Suricata introduces all JSON output capability. - -What is JSON - http://en.wikipedia.org/wiki/JSON - -One way to handle easily Suricata's JSON log outputs is through Kibana - http://kibana.org/ : - -:: - - Kibana is a highly scalable interface for Logstash (http://logstash.net/) and ElasticSearch (http://www.elasticsearch.org/) that allows you to efficiently search, graph, analyze and otherwise make sense of a mountain of logs. - -The installation is very simple/basic start up with minor specifics for ubuntu. You can be up and running, looking through the logs in under 5 min. - -The downloads can be found here - http://www.elasticsearch.org/overview/elkdownloads/ - -This is what yo need to do. - -Suricata ---------- - -Make sure your Suricata is compiled/installed with libjansson support enabled: - -:: - - - $ suricata --build-info - This is Suricata version 2.0 RELEASE - Features: NFQ PCAP_SET_BUFF LIBPCAP_VERSION_MAJOR=1 AF_PACKET HAVE_PACKET_FANOUT LIBCAP_NG LIBNET1.1 HAVE_HTP_URI_NORMALIZE_HOOK HAVE_NSS HAVE_LIBJANSSON - ... - libnss support: yes - libnspr support: yes - libjansson support: --> yes <-- - Prelude support: no - PCRE jit: no - libluajit: no - libgeoip: yes - Non-bundled htp: yes - Old barnyard2 support: no - CUDA enabled: no - ... - -If it isn't check out the `Suricata Installation `_ page to install or compile Suricata for your distribution. -**NOTE:** you will need these packages installed -> **libjansson4** and *libjansson-dev* before compilation. - -Configure suricata ------------------- - -In your suricata.yaml - -:: - - - # "United" event log in JSON format - - eve-log: - enabled: yes - type: file #file|syslog|unix_dgram|unix_stream - filename: eve.json - # the following are valid when type: syslog above - #identity: "suricata" - #facility: local5 - #level: Info ## possible levels: Emergency, Alert, Critical, - ## Error, Warning, Notice, Info, Debug - types: - - alert - - http: - extended: yes # enable this for extended logging information - - dns - - tls: - extended: yes # enable this for extended logging information - - files: - force-magic: yes # force logging magic on all logged files - force-md5: yes # force logging of md5 checksums - #- drop - - ssh - - smtp - - flow - -Install ELK (elasticsearch, logstash, kibana) ---------------------------------------------- - -First install the dependencies - -**NOTE:** ELK recommends running with Oracle Java - how to: - -* http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup-service.html#_installing_the_oracle_jdk - -Otherwise you can install the openjdk: - -:: - - - apt-get install apache2 openjdk-7-jdk openjdk-7-jre-headless - -Then download and install the software. - -Make sure you download the latest versions - - -* http://www.elasticsearch.org/overview/elkdownloads/ - -The installation process is simple (for example): - -:: - - - wget https://download.elasticsearch.org/kibana/kibana/kibana-3.0.0.tar.gz - wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.6.1.deb - wget https://download.elastic.co/logstash/logstash/packages/debian/logstash_1.5.3-1_all.deb - - tar -C /var/www/ -xzf kibana-3.0.0.tar.gz - dpkg -i elasticsearch-1.6.1.deb - dpkg -i logstash_1.5.3-1_all.deb - -Logstash configuration ----------------------- - -Create and save a **logstash.conf** file with the following content in the /etc/logstash/conf.d/ directory : - -:: - - - touch /etc/logstash/conf.d/logstash.conf - -Insert the following(make sure the directory path is correct): - -:: - - - input { - file { - path => ["/var/log/suricata/eve.json"] - sincedb_path => ["/var/lib/logstash/"] - codec => json - type => "SuricataIDPS" - } - - } - - filter { - if [type] == "SuricataIDPS" { - date { - match => [ "timestamp", "ISO8601" ] - } - ruby { - code => "if event['event_type'] == 'fileinfo'; event['fileinfo']['type']=event['fileinfo']['magic'].to_s.split(',')[0]; end;" - } - } - - if [src_ip] { - geoip { - source => "src_ip" - target => "geoip" - #database => "/opt/logstash/vendor/geoip/GeoLiteCity.dat" - add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ] - add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}" ] - } - mutate { - convert => [ "[geoip][coordinates]", "float" ] - } - if ![geoip.ip] { - if [dest_ip] { - geoip { - source => "dest_ip" - target => "geoip" - #database => "/opt/logstash/vendor/geoip/GeoLiteCity.dat" - add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ] - add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}" ] - } - mutate { - convert => [ "[geoip][coordinates]", "float" ] - } - } - } - } - } - - output { - elasticsearch { - host => localhost - #protocol => http - } - } - - -Configure the start-up services -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -:: - - - update-rc.d elasticsearch defaults 95 10 - update-rc.d logstash defaults - - service apache2 restart - service elasticsearch start - service logstash start - -Enjoy ------ - -That's all. Now make sure Suricata is running and you have logs written in your JSON log files and you point your browser towards - -:: - - - http://localhost/kibana-3.0.0 - -**NOTE:** -Some ready to use templates can be found here: - -* https://github.com/pevma/Suricata-Logstash-Templates - -From here on if you would like to customize and familiarize yourself more with the interface you should read the documentation about Kibana and Logstash. -Please have in mind that this is a very quick(under 5 min) tutorial. You should customize and review the proper way for you of using it as a service and/or consider using **httpS web interface and reversy proxy with some authentication**. - -Some possible customization of the output of Logstash and Kibana - - - -.. image:: elk/Logstash1.png - - -.. image:: elk/Logstash2.png - - -.. image:: elk/Logstash3.png - - -.. image:: elk/Logstash4.png - - -.. image:: elk/Logstash5.png - - -.. image:: elk/Logstash6.png - -Peter Manev diff --git a/doc/userguide/output/files-json/files-json.rst b/doc/userguide/output/files-json/files-json.rst deleted file mode 100644 index 472ae3bbd153..000000000000 --- a/doc/userguide/output/files-json/files-json.rst +++ /dev/null @@ -1,62 +0,0 @@ -What to do with files-json.log output -===================================== - -.. toctree:: - - script-follow-json - mysql - postgresql - useful-queries-for-mysql-and-postgresql - mongodb - elk - -Suricata has the ability to produce the files-json.log output. -Basically this is a JSON style format output logfile with entries like this: - -:: - - { - "timestamp": "10\/01\/2012-16:52:59.217616", - "ipver": 4, - "srcip": "80.239.217.171", - "dstip": "192.168.42.197", - "protocol": 6, - "sp": 80, - "dp": 32982, - "http_uri": "\/frameworks\/barlesque\/2.11.0\/desktop\/3.5\/style\/main.css", "http_host": "static.bbci.co.uk", "http_referer": "http:\/\/www.bbc.com\/", "filename": "\/frameworks\/barl - esque\/2.11.0\/desktop\/3.5\/style\/main.css", - "magic": "ASCII text, with very long lines, with no line terminators", - "state": "CLOSED", - "md5": "be7db5e9a4416a4123d556f389b7f4b8", - "stored": false, - "size": 29261 - } - -for every single file that crossed your http pipe. -This in general is very helpful and informative. -In this section we are going to try to explore/suggest approaches for putting it to actual use, since it could aggregate millions of entries in just a week. -There are a god few options in general since the JSON style format is pretty common. -http://www.json.org/ - - -This guide offers a couple of approaches - -use of custom created script with MySQL or PostgreSQL import (bulk or continuous) -or importing it directly to MongoDB(native import of JSON files). - -Please read the all the pages before you jump into executing scripts and/or installing/configuring things. -Te guide is written using Ubuntu LTS server 12.04 - -Thee are 3 options in general that we suggest, that we are going to explain here: - -1. import JSON into MySQL -2. import JSON into PostgreSQL -3. import JSON into MongoDB - -The suggested approach is -configure Suricata.yaml -configure your Database -run the script (not applicable to MongoDB) -and then execute queries against the DB to get the big picture. - - -Peter Manev diff --git a/doc/userguide/output/files-json/mongodb.rst b/doc/userguide/output/files-json/mongodb.rst deleted file mode 100644 index 0143ab6dff93..000000000000 --- a/doc/userguide/output/files-json/mongodb.rst +++ /dev/null @@ -1,97 +0,0 @@ -MongoDB -======= - -If you do not have it installed, follow the istructions here: -http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/ - -Basically you do: - - -:: - - - sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10 - deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen - sudo apt-get update && sudo apt-get install mongodb-10gen - - -The bigest benefit of MongoDB is that it can natively import json.log files: -if you have MongoDB installed - all you have to do is: - - -:: - - - mongoimport --db filejsondb --collection filejson --file files-json.log - -here: - -* --db filejsondb is the database, -* --collections filejson is the equivalent of SQL "table" -* --file files-json.log - is the json log created and logged into from Suricata. - -last but not least - it would automatically create the db and tables for you. - -this would import a 5 Gb (15 million entries) json log file in about 5-10 minutes - default configuration, without tuning MongoDB for high performance. (your set up and HW will definitely have effect on the import time ) - - - -MongoDB Example queries (once you have imported the files-json.log - described above - just go ahead with these queries): - - -:: - - - db.files.group( { cond : {"magic":/.*PDF*./ }, key: {"srcip":true,"http_host":true,"magic":true} ,initial: {count: 0},reduce: function(value, total) {total+=value.count;} } ); - - -:: - - - db.filejson.find({magic:/.*PDF.*/},{srcip:1,http_host:1,magic:1}).sort({srcip:1,http_host:1,magic:1}).limit(20) - - -Get a sorted table biggest to smallest number hosts of file downloads: - - -:: - - - > map = function () { emit({srcip:this.srcip,http_host:this.http_host,magic:this.magic}, {count:1}); } - function () { - emit({srcip:this.srcip, http_host:this.http_host, magic:this.magic}, {count:1}); - } - > reduce = function(k, values) {var result = {count: 0}; values.forEach(function(value) { result.count += value.count; }); return result; } - function (k, values) { - var result = {count:0}; - values.forEach(function (value) {result.count += value.count;}); - return result; - } - > db.filejson.mapReduce(map,reduce,{out: "myoutput" }); - { - "result" : "myoutput", - "timeMillis" : 578806, - "counts" : { - "input" : 3110871, - "emit" : 3110871, - "reduce" : 673186, - "output" : 219840 - }, - "ok" : 1, - } - > db.myoutput.find().sort({'value.count':-1}).limit(10) - { "_id" : { "srcip" : "184.107.x.x", "http_host" : "arexx.x", "magic" : "very short file (no magic)" }, "value" : { "count" : 42560 } } - { "_id" : { "srcip" : "66.135.210.182", "http_host" : "www.ebay.co.uk", "magic" : "XML document text" }, "value" : { "count" : 30896 } } - { "_id" : { "srcip" : "66.135.210.62", "http_host" : "www.ebay.co.uk", "magic" : "XML document text" }, "value" : { "count" : 27812 } } - { "_id" : { "srcip" : "213.91.x.x", "http_host" : "www.focxxxx.x", "magic" : "HTML document, ISO-8859 text" }, "value" : { "count" : 26301 } } - { "_id" : { "srcip" : "195.168.x.x", "http_host" : "search.etaxxx.x", "magic" : "JPEG image data, JFIF standard 1.01, comment: \"CREATOR: gd-jpeg v1.0 (using IJG JPEG v80), quality = 100\"" }, "value" : { "count" : 16131 } } - { "_id" : { "srcip" : "184.107.x.x", "http_host" : "p2p.arxx.x:2710", "magic" : "ASCII text, with no line terminators" }, "value" : { "count" : 15829 } } - { "_id" : { "srcip" : "213.91.x.x", "http_host" : "www.focxx.x", "magic" : "HTML document, ISO-8859 text" }, "value" : { "count" : 14472 } } - { "_id" : { "srcip" : "64.111.199.222", "http_host" : "syndication.exoclick.com", "magic" : "HTML document, ASCII text, with very long lines, with no line terminators" }, "value" : { "count" : 14009 } } - { "_id" : { "srcip" : "69.171.242.70", "http_host" : "www.facebook.com", "magic" : "ASCII text, with no line terminators" }, "value" : { "count" : 13098 } } - { "_id" : { "srcip" : "69.171.242.74", "http_host" : "www.facebook.com", "magic" : "ASCII text, with no line terminators" }, "value" : { "count" : 12801 } } - > - - - -Peter Manev diff --git a/doc/userguide/output/files-json/mysql.rst b/doc/userguide/output/files-json/mysql.rst deleted file mode 100644 index 0e0c32867014..000000000000 --- a/doc/userguide/output/files-json/mysql.rst +++ /dev/null @@ -1,36 +0,0 @@ -MySQL -===== - -If you do not have MySQL installed - go ahead and do so: - -:: - - - sudo apt-get update && sudo apt-get upgrade - sudo apt-get install mysql-server mysql-client - - -For MySQL make sure you create a db and a table: - - -:: - - - mysql>create database filejsondb; - mysql> create user 'filejson'@'localhost' IDENTIFIED BY 'PASSWORD123'; - Query OK, 0 rows affected (0.00 sec) - mysql> grant all privileges on filejsondb.* to 'filejson'@'localhost' with grant option; - mysql> flush privileges; - mysql> use filejsondb; - - mysql> CREATE TABLE filejson( time_received VARCHAR(64), ipver VARCHAR(4), srcip VARCHAR(40), dstip VARCHAR(40), protocol SMALLINT UNSIGNED, sp SMALLINT UNSIGNED, dp SMALLINT UNSIGNED, http_uri TEXT, http_host TEXT, http_referer TEXT, filename TEXT, magic TEXT, state VARCHAR(32), md5 VARCHAR(32), stored VARCHAR(32), size BIGINT UNSIGNED); - - mysql> show columns from filejson; - - - -OPTIONALLY - if you would like you can add in the MD5 whitelist table and import the data as described here :ref:`FileMD5 and white/black listing with md5 ` - -now you can go ahead and execute the script - :ref:`Script FollowJSON ` - -Peter Manev diff --git a/doc/userguide/output/files-json/postgresql.rst b/doc/userguide/output/files-json/postgresql.rst deleted file mode 100644 index 256fea4d4dab..000000000000 --- a/doc/userguide/output/files-json/postgresql.rst +++ /dev/null @@ -1,79 +0,0 @@ -PostgreSQL -========== - -If you do not have PostgreSQL installed: - - -:: - - - sudo apt-get update && sudo apt-get upgrade - sudo apt-get install postgresql - - - -:: - - - sudo vim /etc/postgresql/9.1/main/pg_hba.conf - -change the line: - - -:: - - - local all all trust - -to - - -:: - - - local all all md5 - - -login and change passwords - -:: - - - sudo -u postgres psql postgres - \password postgres - - -Then - - - - -:: - - - create database filejsondb; - \c filejsondb; - create user filejson with password 'PASSWORD123'; - CREATE TABLE filejson( time_received VARCHAR(64), ipver VARCHAR(4), srcip VARCHAR(40), dstip VARCHAR(40), protocol INTEGER, sp INTEGER, dp INTEGER, http_uri TEXT, http_host TEXT, http_referer TEXT, filename TEXT, magic TEXT, state VARCHAR(32), md5 VARCHAR(32), stored VARCHAR(32), size BIGINT); - grant all privileges on database filejsondb to filejson; - -Log out and log in again (with the "filejson" user) to test if everything is ok: - - -:: - - - psql -d filejson -U filejson - - - - -Optionally you could create and import the MD5 white list data if you wish - generally the same guidance as described in :ref:`FileMD5 and white/black listing with md5 ` - -Some more general info and basic commands/queries: -http://jazstudios.blogspot.se/2010/06/postgresql-login-commands.html -http://www.thegeekstuff.com/2009/05/15-advanced-postgresql-commands-with-examples/ - - -now you can go ahead and execute the script - :ref:`Script FollowJSON ` - -Peter Manev diff --git a/doc/userguide/output/files-json/script-follow-json.rst b/doc/userguide/output/files-json/script-follow-json.rst deleted file mode 100644 index a914fa4082bc..000000000000 --- a/doc/userguide/output/files-json/script-follow-json.rst +++ /dev/null @@ -1,100 +0,0 @@ -.. _script-follow-json: - -Script FollowJSON -================= - -BEFORE you run the script - make sure you have set up suricata.yaml and your database correctly !! - -Suricata.yaml: - -1. make sure json-log is enabled -2. and append is set to yes -3. optionally - you have compilled in Suricata with MD5's enabled - -MD5's are enabled and forced in the suricata yaml config ( :ref:`MD5 ` ) -bottom of the page "Log all MD5s without any rules" . - - -:: - - - - file-log: - enabled: yes - filename: files-json.log - append: yes - #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' - force-magic: yes # force logging magic on all logged files - force-md5: yes # force logging of md5 checksums - - -**Append is set to yes** - this is very important if you "follow" , json.log - if you use the tool to constantly parse and insert logs from files-json.log as they are being written onto the log file. - - -There is a python script (in BETA now and) available here: - -* https://redmine.openinfosecfoundation.org/attachments/download/843/FollowJSON.tar.gz - -that you can use for helping out in importing files-json.log entries into a MSQL or PostgreSQL database. - -The script would allow you to do the following: - - -* it contains 2 files -* one python executable -* one yaml config file -* one LICENSE (GPLv2) - -This is what the script does: - -1. Multi-threaded - spawns multiple processes if itself -2. uses yaml as configuration -3. Can: - - 3.1. Read files-json.log file - - 3.1.1. - Continuously - as logs are being written in the log file - 3.1.2. - mass import a stand alone files-json.log into a database - - 3.2. Into (your choice) - - 3.2.1. MySQL DB (locally/remotely,ip) - 3.2.2. PostgreSQL DB (locally/remotely,ip) - -4. Customizable number of processes (default is number of cores - if you have more then 16 - suggested value is NumCores/2) -5. Customizable "chunk" lines to read at once by every process - suggested (default) value is 10 (16 cores = 16 processes * 10 = 160 entries per second) - -**Please look into the configurational yaml file** for more information. - -The script is in BETA state - it has been tested , it works - but still, you should test it and adjust the configuration accordingly and run it on your test environment first before you put it in production. - -After you have made: - -#. your choices of database type (MySQL or PostgreSQL and installed/configured tables for it), -#. created the appropriate database structure and tables (explained in the next tutorial(s) ), -#. adjusted the yaml configuration accordingly, -#. started Suricata, - -you would need: - -:: - - - sudo apt-get install python-yaml python-mysqldb python-psycopg2 - -Then you just run the script, after you have started Suricata: - - -:: - - - sudo python Follow_JSON_Multi.py - -if you would like to execute the script in the background: - - -:: - - - sudo python Follow_JSON_Multi.py & - -Peter Manev diff --git a/doc/userguide/output/files-json/useful-queries-for-mysql-and-postgresql.rst b/doc/userguide/output/files-json/useful-queries-for-mysql-and-postgresql.rst deleted file mode 100644 index d3d81ec13a36..000000000000 --- a/doc/userguide/output/files-json/useful-queries-for-mysql-and-postgresql.rst +++ /dev/null @@ -1,138 +0,0 @@ -Useful queries - for MySQL and PostgreSQL -========================================= - - -General Purpose and Useful Queries (MySQL - 99% the same for PostgreSQL) for the files-json.log databases and tables: - - -:: - - - mysql>select srcip,http_host,count(*) as total from filejson where magic like "%PDF document%" group by srcip,http_host order by total DESC limit 10; - -above top 10 source ip from which PDF's where downloaded -change srcip with dstip to get top 10 IPs downloading PDFs - - -:: - - - mysql>select srcip,http_host,count(*) as total from filejson where magic like "%executable%" group by srcip,http_host order by total DESC limit 10; - -above top 10 source ip from which executables where downloaded from, -change srcip with dstip to get top 10 IPs downloading executables - - - -:: - - - mysql> SELECT srcip,http_host,count(*) AS Total , (COUNT(*) / (SELECT COUNT(*) FROM filejson where magic like "%executable%")) * 100 AS 'Percentage to all items' FROM filejson WHERE magic like "%executable%" GROUP BY srcip,http_host order by total DESC limit 10; - -:: - - - +----------------+----------------------+-------+-------------------------+ - | srcip | http_host | Total | Percentage to all items | - +----------------+----------------------+-------+-------------------------+ - | 149.5.130.7 | ws.livepcsupport.com | 225 | 9.1167 | - .............................. - ............................. - -This would give you a sorted table depicting source ip and host name, number of executable downloads from that host/source ip and what percentage is that of the total executable downloads. -Note: the term executable means - dll, exe, com, msi, java ... and so on , NOT just .exe files - - - -:: - - - mysql>select count(magic) as totalPDF from filejson where magic like "%PDF%" - -This will give you the total number of PDFs out of all files - - -:: - - - mysql>SELECT ( select count(magic) from filejson where magic like "%PDF%" ) as "PDF Total" , (select count(magic) from filejson where magic like "%executable%") as "Executables Total" , (select count(magic) from filejson where filename like "%.xls") as "Excel Total"; - -This will give you: - -:: - - - +-----------+-------------------+-------------+ - | PDF Total | Executables Total | Excel Total | - +-----------+-------------------+-------------+ - | 391 | 2468 | 7 | - +-----------+-------------------+-------------+ - - -:: - - - mysql> SELECT ( select count(magic) from filejson where magic like "%PDF%" ) as "PDF Total" , (select count(magic) from filejson where magic like "%executable%") as "Executables Total" , (select count(magic) from filejson where filename like "%.xls") as "Excel Total", (select count(magic) from filejson) as "TOTAL NUMER OF FILES"; - -:: - - - +-----------+-------------------+-------------+----------------------+ - | PDF Total | Executables Total | Excel Total | TOTAL NUMER OF FILES | - +-----------+-------------------+-------------+----------------------+ - | 391 | 2468 | 7 | 3743925 | - +-----------+-------------------+-------------+----------------------+ - -the above query - a breakdown for PDF, executables and files hat have extension .xls - - - -:: - - - mysql>select srcip,filename,http_host,count(*) as total from filejson where filename like "%.xls" group by srcip,filename,http_host order by total DESC limit 10; - -the above will select top 10 source ip and document NAMES where excel files (files with extension .xls) were downloaded form - - -:: - - - mysql>select srcip,http_host,count(*) as total from filejson where filename like "%.exe" group by srcip,http_host order by total DESC limit 10; - -the above will select the top 10 source ips from where ".exe" files where downloaded from - - -:: - - - mysql>select srcip,http_host,count(*) as total from filejson where filename like "%.doc" group by srcip,http_host order by total DESC limit 10; - -the above for ".doc" files - - -:: - - - mysql>select magic,http_host,count(*) as count from filejson group by magic,http_host order by count DESC limit 20; - -select top 20 hosts grouped and ordered by count - - -:: - - - mysql>select dstip,size,count(*) as total from filejson group by dstip,size order by total DESC limit 10; - -the above query will show you he top 10 downloading ips by size of downloads - - -:: - - - mysql>select dstip,http_host,count(*) as total from filejson where filename like "%.exe" group by dstip order by total DESC limit 5; - -the above query will show you the top 5 downloading ips (and the hosts they downloaded from) that downloaded files with .exe extensions. - - -Peter Manev diff --git a/doc/userguide/performance/tuning-considerations.rst b/doc/userguide/performance/tuning-considerations.rst index 28ebd54d85df..6549c1c5b6fa 100644 --- a/doc/userguide/performance/tuning-considerations.rst +++ b/doc/userguide/performance/tuning-considerations.rst @@ -15,7 +15,7 @@ Suggested setting: 1000 or higher. Max is ~65000. mpm-algo: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Controls the pattern matcher algorithm. AC is the default. On supported platforms, :doc:`performance/Hyperscan` is the best option. +Controls the pattern matcher algorithm. AC is the default. On supported platforms, :doc:`hyperscan` is the best option. detect.profile: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/userguide/rules/enip-keyword.rst b/doc/userguide/rules/enip-keyword.rst index fdcc6eec4b9d..d833e0923f50 100644 --- a/doc/userguide/rules/enip-keyword.rst +++ b/doc/userguide/rules/enip-keyword.rst @@ -37,4 +37,4 @@ Examples:: (cf. http://read.pudn.com/downloads166/ebook/763211/EIP-CIP-V1-1.0.pdf) Information on the protocol can be found here: -http://literature.rockwellautomation.com/idc/groups/literature/documents/wp/enet-wp001_-en-p.pdf +``_ From 5c78fdbc9cff1e71c1d696d12861ea439f2383ca Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 3 Oct 2016 12:05:32 -0600 Subject: [PATCH 2036/2553] doc: break out command line options into a common doc The command line options can now be consumed by the man page and the user guide. Some attempt was made to order the options from common/basic progressing to advanced with some notion of options grouped together. --- doc/userguide/command-line-options.rst | 131 +---------- doc/userguide/manpages/suricata.rst | 179 +-------------- doc/userguide/partials/options-unittests.rst | 25 +++ doc/userguide/partials/options.rst | 222 +++++++++++++++++++ 4 files changed, 254 insertions(+), 303 deletions(-) create mode 100644 doc/userguide/partials/options-unittests.rst create mode 100644 doc/userguide/partials/options.rst diff --git a/doc/userguide/command-line-options.rst b/doc/userguide/command-line-options.rst index ed522eff5d6c..77f6a381a6fc 100644 --- a/doc/userguide/command-line-options.rst +++ b/doc/userguide/command-line-options.rst @@ -5,114 +5,7 @@ Command Line Options Suricata's command line options: -.. option:: -h - - Display a brief usage overview. - -.. option:: -V - - Displays the version of Suricata. - -.. option:: -c - - Select suricata.yaml configuration file. - -.. option:: -i - - After the -i option you can enter the interface card you would like - to use to sniff packets from. This option will try to use the best - capture method available. - -.. option:: -v - - The -v option enables more verbosity of Suricata's output. Supply - multiple times for more verbosity. - -.. option:: -r - - After the -r option you can enter the path to the pcap-file in - which packets are recorded. That way you can inspect the packets in - that file in the pcap/offline mode. - -.. option:: -s - - With the -s option you can set a file with signatures, which will - be loaded together with the rules set in the yaml. - -.. option:: -S - - With the -S option you can set a file with signatures, which will - be loaded exclusively, regardless of the rules set in the yaml. - -.. option:: -l - - With the -l option you can set the default log directory. If you - already have the default-log-dir set in yaml, it will not be used - by Suricata if you use the -l option. It will use the log dir that - is set with the -l option. If you do not set a directory with - the -l option, Suricata will use the directory that is set in yaml. - -.. option:: -D - - Normally if you run Suricata on your console, it keeps your console - occupied. You can not use it for other purposes, and when you close - the window, Suricata stops running. If you run Suricata as deamon - (using the -D option), it runs at the background and you will be - able to use the console for other tasks without disturbing the - engine running. - -.. option:: --runmode - - With the --runmode option you can set the runmode that you would - like to use. This command line option can override the yaml - runmode option. - - Runmodes are: workers, autofp and single. - -For more information about runmodes see: :doc:`performance/runmodes` - -.. option:: --build-info - - Gives an overview of the configure and build options that were - supplied to Suricata's build process at compile time. - -Capture Options -~~~~~~~~~~~~~~~ - -.. option:: --af-packet[=] - - Enable capture of packet using AF_PACKET on Linux. If no device is - supplied, the list of devices from the af-packet section in the - yaml is used. - -.. option:: --netmap[=] - - Enable capture of packet using NETMAP on FreeBSD or Linux. If no - device is supplied, the list of devices from the netmap section - in the yaml is used. - -Advanced Options -~~~~~~~~~~~~~~~~ - -.. option:: --dump-config - - Displays a list of key value pairs with Suricata's configuration. - -.. option:: --set = - - Override any configuration option. - -.. option:: --list-app-layer-protos - - List supported app layer protocols. - -.. option:: --list-keywords[=all|csv|] - - List keywords implemented by the engine - -.. option:: --list-runmodes - - The option --list-runmodes lists all possible runmodes. +.. include:: partials/options.rst Unit Tests ~~~~~~~~~~ @@ -123,24 +16,4 @@ Builtin unittests are only available if Suricata has been built with Running unittests does not take a configuration file. Use -l to supply an output directory. -.. option:: -u - - With the -u option you can run unit tests to test Suricata's code. - -.. option:: -U - - With the -U option you can select which of the unit tests you want - to run. This option uses REGEX. Example of use: suricata -u -U - http - -.. option:: --list-unittests - - The --list-unittests option shows a list with all possible unit - tests. - -.. option:: --fatal-unittests - - With the --fatal-unittests option you can run unit tests but it - will stop immediately after one test fails so you can see directly - where it went wrong. - +.. include:: partials/options-unittests.rst diff --git a/doc/userguide/manpages/suricata.rst b/doc/userguide/manpages/suricata.rst index bb8922d4c970..c290dfd42c9c 100644 --- a/doc/userguide/manpages/suricata.rst +++ b/doc/userguide/manpages/suricata.rst @@ -14,183 +14,14 @@ Monitoring engine. Open Source and owned by a community run non-profit foundation, the Open Information Security Foundation (OISF). OPTIONS -------- +-------------- -.. option:: -c +.. include:: ../partials/options.rst - Path to configuration file. +OPTIONS FOR DEVELOPERS +---------------------- -.. option:: -T - - Test configuration. - -.. option:: -i - - Run in PCAP live mode on provided interface. - -.. option:: -F - - Use BPF filter from file. - -.. option:: -r - - Run in pcap offline mode reading files from pcap file. - -.. option:: -q - - Run inline of the NFQUEUE queue ID provided. May be provided - multiple times. - -.. option:: -s - - Path to a signature file to load. Will be loaded in addition to the - rule files specified in the configuration file. - -.. option:: -S - - Path to signature file to load exclusively. Signature files - specified in the configuration file will not be loaded. - -.. option:: -l - - Set log directory. Overrides the default-log-directory provided in - the configuration file. - -.. option:: -D - - Run as a daemon. - -.. option:: -k [all|none] - - Force (all) the checksum check or disable (none) all checksum - checks. - -.. option:: -V - - Display version. - -.. option:: -v[v] - - Increase the verbosity of logging. This is Suricata application - logging, not event or NSM logging. - -.. option:: -u - - Run the unit tests and exit. Requires that Suricata be compiled - with *--enable-unittests*. - -.. option:: -U, --unittest-filter=REGEX - - File the executed unit tests with a regular expression. - -.. option:: --list-unittests - - List all unit tests. - -.. option:: --fatal-unittests - - Enables fatal failure on a unit test error. Suricata will exit - instead of continuuing more tests. - -.. option:: --unittests-coverage - - Display unit test coverage report. - -.. option:: --list-app-layer-protos - - List all supported application layer protocols. - -.. option:: --list-keywords=[all|csv|] - - List all supported rule keywords. - -.. option:: --list-runmodes - - List all supported run modes. - -.. option:: --runmode - - Run with a specific run mode. Run modes may be viewed with the - *--list-runmodes* option. Usually one of *workers*, *autofp*, or - *single*. - -.. option:: --engine-analysis - - Print reports on analysis of different sections in the engine and - exit. Please have a look at the conf parameter engine-analysis on - what reports can be printed - -.. option:: --pidfile - - Write the process ID to file. Overrides the *pid-file* option in - the configuration file and forces the file to be written when not - running as a daemon. - -.. option:: --init-errors-fatal - - Exit with a failure when errors are encountered loading signatures. - -.. option:: --disable-detection - - Disable the detection engine. - -.. option:: --dump-config - - Dump the configuration loaded from the configuration file to the - terminal and exit. - -.. option:: --build-info - - Display the build information the Suricata was built with. - -.. option:: --pcap= - - Run in PCAP mode. If no device is provided the interfaces - provided in the *pcap* section of the configuration file will be - used. - -.. option:: --pcap-buffer-size= - - Set the size of the PCAP buffer (0 - 2147483647). - -.. option:: --af-packet= - - Run in AF_PACKET mode. If no device is provided the interfaces - provided in the *af-packet* section of the configuration file will be - used. - -.. option:: --simulate-ips - - Force the engine into IPS mode. Useful for QA. - -.. option:: --user= - - Set the process user after initialization. Overrides the user - provided in the *run-as* section of the configuration file. - -.. option:: --group= - - Set the process group to group after initialization. Overrides the - group provided in the *run-as* section of the configuration file. - -.. option:: --erf-in= - - Run in offline mode reading the specific ERF file (Endace - extensible record format). - -.. option:: --unix-socket= - - Use file as the Suricata unix control socket. Overrides the - *filename* provided in the *unix-command* section of the - configuration file. - -.. option:: --set = - - Set a configuration value. Useful for overriding basic - configuration parameters in the configuration. For example, to - change the default log directory:: - - --set default-log-dir=/var/tmp +.. include:: ../partials/options-unittests.rst FILES AND DIRECTORIES --------------------- diff --git a/doc/userguide/partials/options-unittests.rst b/doc/userguide/partials/options-unittests.rst new file mode 100644 index 000000000000..68087fa09105 --- /dev/null +++ b/doc/userguide/partials/options-unittests.rst @@ -0,0 +1,25 @@ +.. Options for developers - unittests. + +.. option:: -u + + Run the unit tests and exit. Requires that Suricata be compiled + with *--enable-unittests*. + +.. option:: -U, --unittest-filter=REGEX + + With the -U option you can select which of the unit tests you want + to run. This option uses REGEX. Example of use: suricata -u -U + http + +.. option:: --list-unittests + + List all unit tests. + +.. option:: --fatal-unittests + + Enables fatal failure on a unit test error. Suricata will exit + instead of continuuing more tests. + +.. option:: --unittests-coverage + + Display unit test coverage report. diff --git a/doc/userguide/partials/options.rst b/doc/userguide/partials/options.rst new file mode 100644 index 000000000000..70e2ae985d0e --- /dev/null +++ b/doc/userguide/partials/options.rst @@ -0,0 +1,222 @@ +.. Start with the most common basic options. + +.. option:: -h + + Display a brief usage overview. + +.. option:: -V + + Displays the version of Suricata. + +.. option:: -c + + Path to configuration file. + +.. option:: -T + + Test configuration. + +.. option:: -v + + The -v option enables more verbosity of Suricata's output. Supply + multiple times for more verbosity. + +.. Basic input options. + +.. option:: -r + + Run in pcap offline mode reading files from pcap file. + +.. option:: -i + + After the -i option you can enter the interface card you would like + to use to sniff packets from. This option will try to use the best + capture method available. + +.. option:: --pcap[=] + + Run in PCAP mode. If no device is provided the interfaces + provided in the *pcap* section of the configuration file will be + used. + +.. option:: --af-packet[=] + + Enable capture of packet using AF_PACKET on Linux. If no device is + supplied, the list of devices from the af-packet section in the + yaml is used. + +.. option:: -q + + Run inline of the NFQUEUE queue ID provided. May be provided + multiple times. + +.. Back to other basic options. + +.. option:: -s + + With the -s option you can set a file with signatures, which will + be loaded together with the rules set in the yaml. + +.. option:: -S + + With the -S option you can set a file with signatures, which will + be loaded exclusively, regardless of the rules set in the yaml. + +.. option:: -l + + With the -l option you can set the default log directory. If you + already have the default-log-dir set in yaml, it will not be used + by Suricata if you use the -l option. It will use the log dir that + is set with the -l option. If you do not set a directory with + the -l option, Suricata will use the directory that is set in yaml. + +.. option:: -D + + Normally if you run Suricata on your console, it keeps your console + occupied. You can not use it for other purposes, and when you close + the window, Suricata stops running. If you run Suricata as deamon + (using the -D option), it runs at the background and you will be + able to use the console for other tasks without disturbing the + engine running. + +.. option:: --runmode + + With the *--runmode* option you can set the runmode that you would + like to use. This command line option can override the yaml runmode + option. + + Runmodes are: *workers*, *autofp* and *single*. + + For more information about runmodes see :doc:`Runmodes + ` in the user guide. + +.. option:: -F + + Use BPF filter from file. + +.. option:: -k [all|none] + + Force (all) the checksum check or disable (none) all checksum + checks. + +.. option:: --user= + + Set the process user after initialization. Overrides the user + provided in the *run-as* section of the configuration file. + +.. option:: --group= + + Set the process group to group after initialization. Overrides the + group provided in the *run-as* section of the configuration file. + +.. option:: --pidfile + + Write the process ID to file. Overrides the *pid-file* option in + the configuration file and forces the file to be written when not + running as a daemon. + +.. option:: --init-errors-fatal + + Exit with a failure when errors are encountered loading signatures. + +.. option:: --disable-detection + + Disable the detection engine. + +.. Information options. + +.. option:: --dump-config + + Dump the configuration loaded from the configuration file to the + terminal and exit. + +.. option:: --build-info + + Display the build information the Suricata was built with. + +.. option:: --list-app-layer-protos + + List all supported application layer protocols. + +.. option:: --list-keywords=[all|csv|] + + List all supported rule keywords. + +.. option:: --list-runmodes + + List all supported run modes. + +.. Advanced options. + +.. option:: --set = + + Set a configuration value. Useful for overriding basic + configuration parameters in the configuration. For example, to + change the default log directory:: + + --set default-log-dir=/var/tmp + +.. option:: --engine-analysis + + Print reports on analysis of different sections in the engine and + exit. Please have a look at the conf parameter engine-analysis on + what reports can be printed + +.. option:: --unix-socket= + + Use file as the Suricata unix control socket. Overrides the + *filename* provided in the *unix-command* section of the + configuration file. + +.. Advanced input options. + +.. option:: --pcap-buffer-size= + + Set the size of the PCAP buffer (0 - 2147483647). + +.. option:: --netmap[=] + + Enable capture of packet using NETMAP on FreeBSD or Linux. If no + device is supplied, the list of devices from the netmap section + in the yaml is used. + +.. option:: --pfring[=] + + Enable PF_RING packet capture. If no device provided, the devices in + the Suricata configuration will be used. + +.. option:: --pfring-cluster-id + + Set the PF_RING cluster ID. + +.. option:: --pfring-cluster-type + + Set the PF_RING cluster type (cluster_round_robin, cluster_flow). + +.. option:: -d + + Run inline using IPFW divert mode. + +.. option:: --dag + + Enable packet capture off a DAG card. If capturing off a specific + stream the stream can be select using a device name like + "dag0:4". This option may be provided multiple times read off + multiple devices and/or streams. + +.. option:: --napatech + + Enable packet capture using the Napatech Streams API. + +.. option:: --mpipe + + Enable packet capture using the TileGX mpipe interface. + +.. option:: --erf-in= + + Run in offline mode reading the specific ERF file (Endace + extensible record format). + +.. option:: --simulate-ips + + Simulate IPS mode when running in a non-IPS mode. From a4450b768eeb56eb095805c62cc793173ec129b1 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 3 Oct 2016 14:13:16 -0600 Subject: [PATCH 2037/2553] doc: manpage: add signals section --- doc/userguide/manpages/suricata.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/userguide/manpages/suricata.rst b/doc/userguide/manpages/suricata.rst index c290dfd42c9c..6b30a8c4739b 100644 --- a/doc/userguide/manpages/suricata.rst +++ b/doc/userguide/manpages/suricata.rst @@ -23,6 +23,19 @@ OPTIONS FOR DEVELOPERS .. include:: ../partials/options-unittests.rst +SIGNALS +------- + +Suricata will respond to the following signals: + +SIGUSR2 + Causes Suricata to perform a live rule reload. + +SIGHUP + Causes Suricata to close and re-open all log files. This can be + used to re-open log files after they may have been moved away by + log rotation utilities. + FILES AND DIRECTORIES --------------------- From 82a6bfd599cd47a9ffa81aaacea4e0546eec8960 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 3 Oct 2016 14:22:07 -0600 Subject: [PATCH 2038/2553] doc: manpage: add bugs and notes section --- doc/userguide/manpages/suricata.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/userguide/manpages/suricata.rst b/doc/userguide/manpages/suricata.rst index 6b30a8c4739b..2cc213969da4 100644 --- a/doc/userguide/manpages/suricata.rst +++ b/doc/userguide/manpages/suricata.rst @@ -44,3 +44,20 @@ FILES AND DIRECTORIES |localstatedir|/log/suricata Default Suricata log directory. + +BUGS +---- + +Please visit Suricata's support page for information about submitting +bugs or feature requests. + +NOTES +----- + +* Suricata Home Page + + https://suricata-ids.org/ + +* Suricata Support Page + + https://suricata-ids.org/support/ From adb6c75e2eec71e2a53af6fd61d1f1ff2c218631 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 4 Oct 2016 07:19:23 +0200 Subject: [PATCH 2039/2553] doc: only make sphinx warnings fatal on html/pdf --- doc/userguide/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index 796392d7db34..da5810a371e6 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -30,20 +30,20 @@ man1_MANS = suricata.1 EXTRA_DIST += $(man1_MANS) userguide.pdf -SPHINX_BUILD = sphinx-build -q -W +SPHINX_BUILD = sphinx-build -q html: sysconfdir=$(sysconfdir) \ localstatedir=$(localstatedir) \ version=$(PACKAGE_VERSION) \ - $(SPHINX_BUILD) -b html -d _build/doctrees \ + $(SPHINX_BUILD) -W -b html -d _build/doctrees \ $(top_srcdir)/doc/userguide _build/html _build/latex/Suricata.pdf: sysconfdir=$(sysconfdir) \ localstatedir=$(localstatedir) \ version=$(PACKAGE_VERSION) \ - $(SPHINX_BUILD) -b latex -d _build/doctrees \ + $(SPHINX_BUILD) -W -b latex -d _build/doctrees \ $(top_srcdir)/doc/userguide _build/latex cd _build/latex && $(MAKE) all-pdf From 34bfacdee050a9c2791a1cd0691203b099ba856d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Oct 2016 17:58:20 +0200 Subject: [PATCH 2040/2553] doc: add minimal http request/response line sections --- doc/userguide/rules/http-keywords.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/userguide/rules/http-keywords.rst b/doc/userguide/rules/http-keywords.rst index 594ecd4376bb..388cbdd6f95c 100644 --- a/doc/userguide/rules/http-keywords.rst +++ b/doc/userguide/rules/http-keywords.rst @@ -143,6 +143,15 @@ When authoring new rules, it is recommended that the ``http_uri`` content modifier be used rather than the deprecated ``uricontent`` keyword. +http_request_line +----------------- + +The ``http_request_line`` forces the whole HTTP request line to be inspected. + +Example:: + + alert http any any -> any any (http_request_line; content:"GET / HTTP/1.0"; sid:1;) + http_header and http_raw_header ------------------------------- @@ -270,6 +279,15 @@ Example of the purpose of ``http_stat_msg``: .. image:: http-keywords/stat_msg_1.png +http_response_line +------------------ + +The ``http_response_line`` forces the whole HTTP response line to be inspected. + +Example:: + + alert http any any -> any any (http_response_line; content:"HTTP/1.0 200 OK"; sid:1;) + http_server_body ---------------- From 0d155932585a76e16b6da89e3f9f10009b0cd796 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Oct 2016 18:02:07 +0200 Subject: [PATCH 2041/2553] doc: move urilen to other uri keywords --- doc/userguide/rules/http-keywords.rst | 58 +++++++++++++-------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/doc/userguide/rules/http-keywords.rst b/doc/userguide/rules/http-keywords.rst index 388cbdd6f95c..c032ab3a7c97 100644 --- a/doc/userguide/rules/http-keywords.rst +++ b/doc/userguide/rules/http-keywords.rst @@ -143,6 +143,35 @@ When authoring new rules, it is recommended that the ``http_uri`` content modifier be used rather than the deprecated ``uricontent`` keyword. +urilen +------ + +The ``urilen`` keyword is used to match on the length of the request +URI. It is possible to use the ``<`` and ``>`` operators, which +indicate respectively *smaller than* and *larger than*. + +The format of ``urilen`` is:: + + urilen:3; + +Other possibilities are:: + + urilen:1; + urilen:>1; + urilen:<10; + urilen:10<>20; (bigger than 10, smaller than 20) + +Example: + +.. image:: http-keywords/urilen.png + +Example of ``urilen`` in a signature: + +.. image:: http-keywords/urilen1.png + +You can also append ``norm`` or ``raw`` to define what sort of buffer you want +to use (normalized or raw buffer). + http_request_line ----------------- @@ -340,35 +369,6 @@ in your :ref:`libhtp configuration section ` via the ``response-body-limit`` setting. -urilen ------- - -The ``urilen`` keyword is used to match on the length of the request -URI. It is possible to use the ``<`` and ``>`` operators, which -indicate respectively *smaller than* and *larger than*. - -The format of ``urilen`` is:: - - urilen:3; - -Other possibilities are:: - - urilen:1; - urilen:>1; - urilen:<10; - urilen:10<>20; (bigger than 10, smaller than 20) - -Example: - -.. image:: http-keywords/urilen.png - -Example of ``urilen`` in a signature: - -.. image:: http-keywords/urilen1.png - -You can also append ``norm`` or ``raw`` to define what sort of buffer you want -to use (normalized or raw buffer). - pcre ---- From 3cf1b1206174eb3ae7c2030dafe6b0862b165390 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Oct 2016 18:18:02 +0200 Subject: [PATCH 2042/2553] doc: http sticky vs modifier --- doc/userguide/rules/http-keywords.rst | 55 +++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/doc/userguide/rules/http-keywords.rst b/doc/userguide/rules/http-keywords.rst index c032ab3a7c97..4418ab8983e8 100644 --- a/doc/userguide/rules/http-keywords.rst +++ b/doc/userguide/rules/http-keywords.rst @@ -9,10 +9,57 @@ capabilities at the application layer. More information can be found at specific parts of the network traffic. For instance, to check specifically on the request URI, cookies, or the HTTP request or response body, etc. -Use ``http_method`` to match on the HTTP request method, ``http_uri`` -or ``http_raw_uri`` to match on the request URI, ``http_stat_code`` to -match on the response status code and ``http_stat_msg`` to match on the -response status message. +Types of modifiers +------------------ + +There are 2 types of modifiers. The older style 'content modifiers' look back in the rule. + +Example:: + + alert http any any -> any any (content:"index.php"; http_uri; sid:1;) + +In the above example the pattern 'index.php' is modified to inspect the HTTP uri buffer. + +The more recent type is called the 'sticky buffer'. It places the buffer name first and all keywords following it apply to that buffer. + +Example:: + + alert http any any -> any any (http_response_line; content:"403 Forbidden"; sid:1;) + +In the above example the pattern '403 Forbidden' is inspected against the HTTP response line because it follows the ``http_response_line`` keyword. + +The following request keywords are available: + +============================== ======================== ================== +Keyword Sticky or Modifier Direction +============================== ======================== ================== +http_uri Modifier Request +http_raw_uri Modifier Request +http_method Modifier Request +http_request_line Sticky Buffer Request +http_client_body Modifier Request +http_header Modifier Both +http_raw_header Modifier Both +http_cookie Modifier Both +http_user_agent Modifier Request +http_host Modifier Request +http_raw_host Modifier Request +============================== ======================== ================== + +The following response keywords are available: + +============================== ======================== ================== +Keyword Sticky or Modifier Direction +============================== ======================== ================== +http_stat_msg Modifier Response +http_stat_code Modifier Response +http_response_line Sticky Buffer Response +http_header Modifier Both +http_raw_header Modifier Both +http_cookie Modifier Both +http_server_body Modifier Response +file_data Sticky Buffer Response +============================== ======================== ================== It is important to understand the structure of HTTP requests and responses. A simple example of a HTTP request and response follows: From 76b55214f025b9ba32f3bbb64f17cec7e0cd4fa7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Oct 2016 18:44:53 +0200 Subject: [PATCH 2043/2553] doc: rules-meta small cleanup --- doc/userguide/rules/meta.rst | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/doc/userguide/rules/meta.rst b/doc/userguide/rules/meta.rst index 4fb169f467f9..41ab444ab3c5 100644 --- a/doc/userguide/rules/meta.rst +++ b/doc/userguide/rules/meta.rst @@ -1,25 +1,21 @@ Meta-settings ============= -Meta-settings have no effect on Suricata's inspection; they have an -effect on the way Suricata reports events. +Meta-settings have no effect on Suricata's inspection; they do have an effect on the way Suricata reports events. msg (message) ------------- -The keyword msg gives more information about the signature and the -possible alert. The first part shows the filename of the -signature. It is a convention that part is written in uppercase +The keyword msg gives more information about the signature and the possible alert. The first part shows the class of the signature. It is a convention that part is written in uppercase characters. The format of msg is: :: + msg: "some description"; - msg: “..........”; - -Example: +Examples: :: @@ -28,7 +24,7 @@ Example: :: - It is a convention that msg is always the first keyword of a signature. +It is a convention that msg is always the first keyword of a signature. Another example of msg in a signature: @@ -39,8 +35,7 @@ In this example the red, bold-faced part is the msg. Sid (signature id) ------------------ -The keyword sid gives every signature its own id. This id is stated -with a number. +The keyword sid gives every signature its own id. This id is stated with a number. The format of sid is: From 879c3d8ad7a29aac6dd1581bfa1b59ca98a10d97 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 4 Oct 2016 09:16:24 +0200 Subject: [PATCH 2044/2553] detect: fix scan-build 0-size alloc warnings --- src/detect-engine-mpm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index fee6ec7031b8..87e63b8862de 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -807,7 +807,7 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx) app_mpms_cnt++; } uint32_t stats[MPMB_MAX] = {0}; - uint32_t appstats[app_mpms_cnt]; + uint32_t appstats[app_mpms_cnt + 1]; // +1 to silence scan-build memset(&appstats, 0x00, sizeof(appstats)); for (htb = HashListTableGetListHead(de_ctx->mpm_hash_table); @@ -1238,6 +1238,9 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) i++; a++; } + if (i == 0) + return 0; + sh->init->app_mpms = SCCalloc(i, sizeof(MpmCtx *)); BUG_ON(sh->init->app_mpms == NULL); @@ -1304,6 +1307,9 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) s->flags |= SIG_FLAG_PREFILTER; } } + /* no rules */ + if (struct_total_size + content_total_size == 0) + return 0; /* array hash buffer - i've run out of ideas to name it */ uint8_t *ahb = SCMalloc(sizeof(uint8_t) * (struct_total_size + content_total_size)); From a35bea28f364e43287f31430f4012e1c580f8aa4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 4 Oct 2016 12:51:39 +0200 Subject: [PATCH 2045/2553] doc: rules-meta typo --- doc/userguide/rules/meta.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/userguide/rules/meta.rst b/doc/userguide/rules/meta.rst index 41ab444ab3c5..048152c746c7 100644 --- a/doc/userguide/rules/meta.rst +++ b/doc/userguide/rules/meta.rst @@ -22,8 +22,6 @@ Examples: msg:"ATTACK-RESPONSES 403 Forbidden"; msg:"ET EXPLOIT SMB-DS DCERPC PnP bind attempt"; -:: - It is a convention that msg is always the first keyword of a signature. Another example of msg in a signature: From aaf0fe4d29e5c9d0319732c07c17bd3c1df381ea Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 4 Oct 2016 12:51:53 +0200 Subject: [PATCH 2046/2553] doc: eve update --- doc/userguide/configuration/suricata-yaml.rst | 131 ++++++++++--- doc/userguide/output/eve/eve-json-output.rst | 179 +++++++++++++++--- 2 files changed, 257 insertions(+), 53 deletions(-) diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index 745c3690ff40..9701df415634 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -249,32 +249,111 @@ Eve (Extensible Event Format) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is an JSON output for alerts and events. It allows for easy -integration with tools like logstash. - -:: - - # Extensible Event Format (nicknamed EVE) event log in JSON format - - eve-log: - enabled: yes - type: file #file|syslog|unix_dgram|unix_stream - filename: eve.json - # the following are valid when type: syslog above - #identity: "suricata" - #facility: local5 - #level: Info ## possible levels: Emergency, Alert, Critical, - ## Error, Warning, Notice, Info, Debug - types: - - alert - - http: - extended: yes # enable this for extended logging information - - dns - - tls: - extended: yes # enable this for extended logging information - - files: - force-magic: no # force logging magic on all logged files - force-md5: no # force logging of md5 checksums - #- drop - - ssh +integration with 3rd party tools like logstash. + +:: + + # Extensible Event Format (nicknamed EVE) event log in JSON format + - eve-log: + enabled: yes + filetype: regular #regular|syslog|unix_dgram|unix_stream|redis + filename: eve.json + #prefix: "@cee: " # prefix to prepend to each log entry + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + #redis: + # server: 127.0.0.1 + # port: 6379 + # mode: list ## possible values: list (default), channel + # key: suricata ## key or channel to use (default to suricata) + # Redis pipelining set up. This will enable to only do a query every + # 'batch-size' events. This should lower the latency induced by network + # connection at the cost of some memory. There is no flushing implemented + # so this setting as to be reserved to high traffic suricata. + # pipelining: + # enabled: yes ## set enable to yes to enable query pipelining + # batch-size: 10 ## number of entry to keep in buffer + types: + - alert: + # payload: yes # enable dumping payload in Base64 + # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log + # payload-printable: yes # enable dumping payload in printable (lossy) format + # packet: yes # enable dumping of packet (without stream segments) + http: yes # enable dumping of http fields + tls: yes # enable dumping of tls fields + ssh: yes # enable dumping of ssh fields + smtp: yes # enable dumping of smtp fields + + # Enable the logging of tagged packets for rules using the + # "tag" keyword. + tagged-packets: yes + + # HTTP X-Forwarded-For support by adding an extra field or overwriting + # the source or destination IP address (depending on flow direction) + # with the one reported in the X-Forwarded-For HTTP header. This is + # helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. + xff: + enabled: no + # Two operation modes are available, "extra-data" and "overwrite". + mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For + - http: + extended: yes # enable this for extended logging information + # custom allows additional http fields to be included in eve-log + # the example below adds three additional fields when uncommented + #custom: [Accept-Encoding, Accept-Language, Authorization] + - dns: + # control logging of queries and answers + # default yes, no to disable + query: yes # enable logging of DNS queries + answer: yes # enable logging of DNS answers + # control which RR types are logged + # all enabled if custom not specified + #custom: [a, aaaa, cname, mx, ns, ptr, txt] + - tls: + extended: yes # enable this for extended logging information + - files: + force-magic: no # force logging magic on all logged files + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] + #- drop: + # alerts: yes # log alerts that caused drops + # flows: all # start or all: 'start' logs only a single drop + # # per flow direction. All logs each dropped pkt. + - smtp: + #extended: yes # enable this for extended logging information + # this includes: bcc, message-id, subject, x_mailer, user-agent + # custom fields logging from the list: + # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, + # x-originating-ip, in-reply-to, references, importance, priority, + # sensitivity, organization, content-md5, date + #custom: [received, x-mailer, x-originating-ip, relays, reply-to, bcc] + # output md5 of fields: body, subject + # for the body you need to set app-layer.protocols.smtp.mime.body-md5 + # to yes + #md5: [body, subject] + + - ssh + - stats: + totals: yes # stats for all threads merged together + threads: no # per thread stats + deltas: no # include delta values + # bi-directional flows + - flow + # uni-directional flows + #- netflow For more advanced configuration options, see :ref:`Eve JSON Output `. diff --git a/doc/userguide/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst index 8d42930d8657..5c0b8195d006 100644 --- a/doc/userguide/output/eve/eve-json-output.rst +++ b/doc/userguide/output/eve/eve-json-output.rst @@ -3,36 +3,164 @@ Eve JSON Output =============== -JSON output - -Starting in 2.0, Suricata can output alerts, http events, dns events, tls events and file info through json. +Suricata can output alerts, http events, dns events, tls events and file info through json. The most common way to use this is through 'EVE', which is a firehose approach where all these logs go into a single file. :: - - outputs: - - eve-log: - enabled: yes - type: file #file|syslog|unix_dgram|unix_stream - filename: eve.json - types: - - alert - - http: - extended: yes # enable this for extended logging information - - dns - - tls: - extended: yes # enable this for extended logging information - - files: - force-magic: no # force logging magic on all logged files - force-md5: no # force logging of md5 checksums - #- drop - - ssh - -Each alert, http log, etc will go into this one file: 'eve.json'. This file can than be processed by Logstash for example. - + # Extensible Event Format (nicknamed EVE) event log in JSON format + - eve-log: + enabled: yes + filetype: regular #regular|syslog|unix_dgram|unix_stream|redis + filename: eve.json + #prefix: "@cee: " # prefix to prepend to each log entry + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + #redis: + # server: 127.0.0.1 + # port: 6379 + # mode: list ## possible values: list (default), channel + # key: suricata ## key or channel to use (default to suricata) + # Redis pipelining set up. This will enable to only do a query every + # 'batch-size' events. This should lower the latency induced by network + # connection at the cost of some memory. There is no flushing implemented + # so this setting as to be reserved to high traffic suricata. + # pipelining: + # enabled: yes ## set enable to yes to enable query pipelining + # batch-size: 10 ## number of entry to keep in buffer + types: + - alert: + # payload: yes # enable dumping payload in Base64 + # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log + # payload-printable: yes # enable dumping payload in printable (lossy) format + # packet: yes # enable dumping of packet (without stream segments) + http: yes # enable dumping of http fields + tls: yes # enable dumping of tls fields + ssh: yes # enable dumping of ssh fields + smtp: yes # enable dumping of smtp fields + + # Enable the logging of tagged packets for rules using the + # "tag" keyword. + tagged-packets: yes + + # HTTP X-Forwarded-For support by adding an extra field or overwriting + # the source or destination IP address (depending on flow direction) + # with the one reported in the X-Forwarded-For HTTP header. This is + # helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. + xff: + enabled: no + # Two operation modes are available, "extra-data" and "overwrite". + mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For + - http: + extended: yes # enable this for extended logging information + # custom allows additional http fields to be included in eve-log + # the example below adds three additional fields when uncommented + #custom: [Accept-Encoding, Accept-Language, Authorization] + - dns: + # control logging of queries and answers + # default yes, no to disable + query: yes # enable logging of DNS queries + answer: yes # enable logging of DNS answers + # control which RR types are logged + # all enabled if custom not specified + #custom: [a, aaaa, cname, mx, ns, ptr, txt] + - tls: + extended: yes # enable this for extended logging information + - files: + force-magic: no # force logging magic on all logged files + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] + #- drop: + # alerts: yes # log alerts that caused drops + # flows: all # start or all: 'start' logs only a single drop + # # per flow direction. All logs each dropped pkt. + - smtp: + #extended: yes # enable this for extended logging information + # this includes: bcc, message-id, subject, x_mailer, user-agent + # custom fields logging from the list: + # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, + # x-originating-ip, in-reply-to, references, importance, priority, + # sensitivity, organization, content-md5, date + #custom: [received, x-mailer, x-originating-ip, relays, reply-to, bcc] + # output md5 of fields: body, subject + # for the body you need to set app-layer.protocols.smtp.mime.body-md5 + # to yes + #md5: [body, subject] + + - ssh + - stats: + totals: yes # stats for all threads merged together + threads: no # per thread stats + deltas: no # include delta values + # bi-directional flows + - flow + # uni-directional flows + #- netflow + +Each alert, http log, etc will go into this one file: 'eve.json'. This file +can then be processed by 3rd party tools like Logstash or jq. + +Output types +~~~~~~~~~~~~ + +EVE can output to multiple methods. ``regular`` is a normal file. Other +options are ``syslog``, ``unix_dgram``, ``unix_stream`` and ``redis``. + +Output types:: + + filetype: regular #regular|syslog|unix_dgram|unix_stream|redis + filename: eve.json + #prefix: "@cee: " # prefix to prepend to each log entry + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + #redis: + # server: 127.0.0.1 + # port: 6379 + # mode: list ## possible values: list (default), channel + # key: suricata ## key or channel to use (default to suricata) + # Redis pipelining set up. This will enable to only do a query every + # 'batch-size' events. This should lower the latency induced by network + # connection at the cost of some memory. There is no flushing implemented + # so this setting as to be reserved to high traffic suricata. + # pipelining: + # enabled: yes ## set enable to yes to enable query pipelining + # batch-size: 10 ## number of entry to keep in buffer + +Alerts +~~~~~~ + +Alerts are event records for rule matches. They can be ammended with metadata, +such as the HTTP record an alert was generated for. + +Metadata:: + + - alert: + # payload: yes # enable dumping payload in Base64 + # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log + # payload-printable: yes # enable dumping payload in printable (lossy) format + # packet: yes # enable dumping of packet (without stream segments) + http: yes # enable dumping of http fields + tls: yes # enable dumping of tls fields + ssh: yes # enable dumping of ssh fields + smtp: yes # enable dumping of smtp fields Multiple Logger Instances ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -41,7 +169,6 @@ It is possible to have multiple 'EVE' instances, for example the following is va :: - outputs: - eve-log: enabled: yes @@ -66,7 +193,6 @@ In addition to this, each log can be handled completely separately: :: - outputs: - alert-json-log: enabled: yes @@ -91,7 +217,6 @@ For most output types, you can add multiple: :: - outputs: - alert-json-log: enabled: yes From dbde356053f5b994f29577db3c7b1475cd9d3346 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 4 Oct 2016 08:56:16 -0600 Subject: [PATCH 2047/2553] doc: exclude docs in partials/ from reference errors These docs are already included with the include statement, but older versions of Sphinx still complain that they are not in a table of contents. --- doc/userguide/conf.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/userguide/conf.py b/doc/userguide/conf.py index 219dfd15798c..f93222049a3f 100644 --- a/doc/userguide/conf.py +++ b/doc/userguide/conf.py @@ -87,7 +87,12 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = [ + '_build', + + # Documents that are included, rather than in a TOC. + 'partials', +] # The reST default role (used for this markup: `text`) to use for all # documents. From afead7e5652bc715ac228b14095dd31037830ed2 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 5 Oct 2016 12:02:59 -0600 Subject: [PATCH 2048/2553] doc: add missing docs to EXTRA_DIST --- doc/userguide/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index da5810a371e6..a63a8eb53cc8 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -9,6 +9,7 @@ EXTRA_DIST = \ what-is-suricata.rst \ make-sense-alerts.rst \ setting-up-ipsinline-for-linux.rst \ + unix-socket.rst \ capture-hardware \ configuration \ file-extraction \ @@ -19,7 +20,8 @@ EXTRA_DIST = \ performance \ reputation \ rules \ - setting-up-ipsinline-for-linux + setting-up-ipsinline-for-linux \ + partials if HAVE_SURICATA_MAN man1_MANS = suricata.1 From 2c60e9b4deadb2c330fe37f754f75cebf8006284 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 5 Oct 2016 12:06:19 -0600 Subject: [PATCH 2049/2553] doc: remove userguide.pdf on clean instead of suricata.pdf As the pdf is a built artifact, it needs to be removed to satisfy distcheck. --- doc/userguide/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index a63a8eb53cc8..ab89a2bd319f 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -70,6 +70,6 @@ man: _build/man/suricata.1 clean-local: rm -rf $(top_builddir)/doc/userguide/_build rm -f $(top_builddir)/doc/userguide/suricata.1 - rm -f $(top_builddir)/doc/userguide/suricata.pdf + rm -f $(top_builddir)/doc/userguide/userguide.pdf endif # HAVE_SPHINXBUILD From 6a831f8125c256009946688a9bf7a1e1ae789d7c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Oct 2016 13:16:53 +0200 Subject: [PATCH 2050/2553] doc: add simple install guide --- doc/userguide/Makefile.am | 1 + doc/userguide/index.rst | 1 + doc/userguide/install.rst | 133 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 doc/userguide/install.rst diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index ab89a2bd319f..56c375db8f6e 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -1,6 +1,7 @@ EXTRA_DIST = \ conf.py \ index.rst \ + install.rst \ acknowledgements.rst \ oinkmaster.rst \ command-line-options.rst \ diff --git a/doc/userguide/index.rst b/doc/userguide/index.rst index 6654f8da0bbf..85b792f154f0 100644 --- a/doc/userguide/index.rst +++ b/doc/userguide/index.rst @@ -6,6 +6,7 @@ Suricata User Guide :titlesonly: what-is-suricata + install.rst command-line-options rules/index.rst oinkmaster diff --git a/doc/userguide/install.rst b/doc/userguide/install.rst new file mode 100644 index 000000000000..5049c69b87b5 --- /dev/null +++ b/doc/userguide/install.rst @@ -0,0 +1,133 @@ +Installation +============ + +Before Suricata can be used it has to be installed. Suricata can be installed +on various distributions using binary packages: :ref:`install-binary-packages`. + +For people familiar with compiling their own software, the Source method is +recommended. + +Advanced users can check the advanced guides, see :ref:`install-advanced`. + +Source +------ + +Installing from the source distribution files gives the most control over the Suricata installation. + +Basic steps:: + + tar xzvf suricata-3.2beta1.tar.gz + cd suricata-3.2beta1 + ./configure + make + make install + +This will install Suricata into ``/usr/local/bin/``, use the default +configuration in ``/usr/local/etc/suricata/`` and will output to +``/usr/local/var/log/suricata`` + + +Common configure options +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. option:: --disable-gccmarch-native + + Do not optimize the binary for the hardware it is built on. Add this + flag if the binary is meant to be portable or if Suricata is to be used in a VM. + +.. option:: --prefix=/usr/ + + Installs the Suricata binary into /usr/bin/. Default ``/usr/local/`` + +.. option:: --sysconfdir=/etc + + Installs the Suricata configuration files into /etc/suricata/. Default ``/usr/local/etc/`` + +.. option:: --localstatedir=/var + + Setups Suricata for logging into /var/log/suricata/. Default ``/usr/local/var/log/suricata`` + +.. option:: --enable-lua + + Enables Lua support for detection and output. + +.. option:: --enable-geopip + + Enables GeoIP support for detection. + + +Dependencies +^^^^^^^^^^^^ + +For Suricata's compilation you'll need the following libraries and their development headers installed: + + libpcap, libpcre, libmagic, zlib, libyaml + +The following tools are required: + + make gcc (or clang) pkg-config + +Ubuntu/Debian +""""""""""""" + +:: + + sudo apt-get install libpcre3 libpcre3-dbg libpcre3-dev build-essential libpcap-dev \ + libnet1-dev libyaml-0-2 libyaml-dev pkg-config zlib1g zlib1g-dev \ + libcap-ng-dev libcap-ng0 make libmagic-dev libjansson-dev + + +.. _install-binary-packages: + +Binary packages +--------------- + +Ubuntu +^^^^^^ + +For Ubuntu, the OISF maintains a PPA ``suricata-stable`` that is always contains the latest stable release. + +To use it:: + + sudo add-apt-repository ppa:oisf/suricata-stable + sudo apt-get update + sudo sudo apt-get install suricata + +Debian +^^^^^^ + +In Debian Jessie Suricata is out of date, but an updated version is in Debian Backports. + +As root do:: + + echo "deb http://http.debian.net/debian jessie-backports main" > \ + /etc/apt/sources.list.d/backports.list + apt-get update + apt-get install suricata -t jessie-backports + +Fedora +^^^^^^ + +:: + + dnf install suricata + +RHEL/CentOS +^^^^^^^^^^^ + +For RedHat Enterprise Linux 7 and CentOS 7 the EPEL repository can be used. + +:: + + yum install epel-release + yum install suricata + + +.. _install-advanced: + +Advanced Installation +--------------------- + +Various installation guides for installing from GIT and for other operating systems are maintained at: +https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Installation + From 40af9aad025217b3ea70450f690e668e3c7240cc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Oct 2016 17:49:21 +0200 Subject: [PATCH 2051/2553] streaming: improve error handling When memory allocations happened in HTTP body and general file tracking, malloc/realloc errors (most likely in the form of memcap reached conditions) could lead to an endless loop in the buffer grow logic. This patch implements proper error handling for all Append/Insert functions for the streaming API, and it explicitly enables compiler warnings if the results are ignored. --- src/app-layer-htp-body.c | 10 ++- src/util-file.c | 4 +- src/util-streaming-buffer.c | 168 ++++++++++++++++++++---------------- src/util-streaming-buffer.h | 14 +-- 4 files changed, 112 insertions(+), 84 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index bfb9ba73af29..e1cda5659c09 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -100,7 +100,10 @@ int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, SCReturnInt(-1); } - StreamingBufferAppend(body->sb, &bd->sbseg, data, len); + if (StreamingBufferAppend(body->sb, &bd->sbseg, data, len) != 0) { + HTPFree(bd, sizeof(HtpBodyChunk)); + SCReturnInt(-1); + } body->first = body->last = bd; @@ -111,7 +114,10 @@ int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, SCReturnInt(-1); } - StreamingBufferAppend(body->sb, &bd->sbseg, data, len); + if (StreamingBufferAppend(body->sb, &bd->sbseg, data, len) != 0) { + HTPFree(bd, sizeof(HtpBodyChunk)); + SCReturnInt(-1); + } body->last->next = bd; body->last = bd; diff --git a/src/util-file.c b/src/util-file.c index f2ffa8a9f0dc..cc48b946c998 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -527,7 +527,9 @@ static int FileStoreNoStoreCheck(File *ff) static int AppendData(File *file, const uint8_t *data, uint32_t data_len) { - StreamingBufferAppendNoTrack(file->sb, data, data_len); + if (StreamingBufferAppendNoTrack(file->sb, data, data_len) != 0) { + SCReturnInt(-1); + } #ifdef HAVE_NSS if (file->md5_ctx) { diff --git a/src/util-streaming-buffer.c b/src/util-streaming-buffer.c index d0df5f687da2..9305a41ef126 100644 --- a/src/util-streaming-buffer.c +++ b/src/util-streaming-buffer.c @@ -103,7 +103,8 @@ static void AutoSlide(StreamingBuffer *sb) sb->buf_offset = size; } -static void GrowToSize(StreamingBuffer *sb, uint32_t size) +static int __attribute__((warn_unused_result)) +GrowToSize(StreamingBuffer *sb, uint32_t size) { /* try to grow in multiples of sb->cfg->buf_size */ uint32_t x = sb->cfg->buf_size ? size % sb->cfg->buf_size : 0; @@ -111,44 +112,53 @@ static void GrowToSize(StreamingBuffer *sb, uint32_t size) uint32_t grow = base + sb->cfg->buf_size; void *ptr = REALLOC(sb->cfg, sb->buf, sb->buf_size, grow); - if (ptr != NULL) { - /* for safe printing and general caution, lets memset the - * new data to 0 */ - size_t diff = grow - sb->buf_size; - void *new_mem = ((char *)ptr) + sb->buf_size; - memset(new_mem, 0, diff); - - sb->buf = ptr; - sb->buf_size = grow; - SCLogDebug("grown buffer to %u", grow); + if (ptr == NULL) + return -1; + + /* for safe printing and general caution, lets memset the + * new data to 0 */ + size_t diff = grow - sb->buf_size; + void *new_mem = ((char *)ptr) + sb->buf_size; + memset(new_mem, 0, diff); + + sb->buf = ptr; + sb->buf_size = grow; + SCLogDebug("grown buffer to %u", grow); #ifdef DEBUG - if (sb->buf_size > sb->buf_size_max) { - sb->buf_size_max = sb->buf_size; - } -#endif + if (sb->buf_size > sb->buf_size_max) { + sb->buf_size_max = sb->buf_size; } +#endif + return 0; } -static void Grow(StreamingBuffer *sb) +/** \internal + * \brief try to double the buffer size + * \retval 0 ok + * \retval -1 failed, buffer unchanged + */ +static int __attribute__((warn_unused_result)) Grow(StreamingBuffer *sb) { uint32_t grow = sb->buf_size * 2; void *ptr = REALLOC(sb->cfg, sb->buf, sb->buf_size, grow); - if (ptr != NULL) { - /* for safe printing and general caution, lets memset the - * new data to 0 */ - size_t diff = grow - sb->buf_size; - void *new_mem = ((char *)ptr) + sb->buf_size; - memset(new_mem, 0, diff); - - sb->buf = ptr; - sb->buf_size = grow; - SCLogDebug("grown buffer to %u", grow); + if (ptr == NULL) + return -1; + + /* for safe printing and general caution, lets memset the + * new data to 0 */ + size_t diff = grow - sb->buf_size; + void *new_mem = ((char *)ptr) + sb->buf_size; + memset(new_mem, 0, diff); + + sb->buf = ptr; + sb->buf_size = grow; + SCLogDebug("grown buffer to %u", grow); #ifdef DEBUG - if (sb->buf_size > sb->buf_size_max) { - sb->buf_size_max = sb->buf_size; - } -#endif + if (sb->buf_size > sb->buf_size_max) { + sb->buf_size_max = sb->buf_size; } +#endif + return 0; } /** @@ -188,24 +198,26 @@ StreamingBufferSegment *StreamingBufferAppendRaw(StreamingBuffer *sb, const uint return NULL; } - StreamingBufferSegment *seg = CALLOC(sb->cfg, 1, sizeof(StreamingBufferSegment)); - if (seg != NULL) { - if (!DATA_FITS(sb, data_len)) { - if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) - AutoSlide(sb); - if (sb->buf_size == 0) { - GrowToSize(sb, data_len); - } else { - while (!DATA_FITS(sb, data_len)) { - Grow(sb); + if (!DATA_FITS(sb, data_len)) { + if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) + AutoSlide(sb); + if (sb->buf_size == 0) { + if (GrowToSize(sb, data_len) != 0) + return NULL; + } else { + while (!DATA_FITS(sb, data_len)) { + if (Grow(sb) != 0) { + return NULL; } } } - if (!DATA_FITS(sb, data_len)) { - FREE(sb->cfg, seg, sizeof(StreamingBufferSegment)); - return NULL; - } + } + if (!DATA_FITS(sb, data_len)) { + return NULL; + } + StreamingBufferSegment *seg = CALLOC(sb->cfg, 1, sizeof(StreamingBufferSegment)); + if (seg != NULL) { memcpy(sb->buf + sb->buf_offset, data, data_len); seg->stream_offset = sb->stream_offset + sb->buf_offset; seg->segment_len = data_len; @@ -215,65 +227,73 @@ StreamingBufferSegment *StreamingBufferAppendRaw(StreamingBuffer *sb, const uint return NULL; } -void StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg, - const uint8_t *data, uint32_t data_len) +int StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len) { BUG_ON(seg == NULL); if (sb->buf == NULL) { if (InitBuffer(sb) == -1) - return; + return -1; } if (!DATA_FITS(sb, data_len)) { if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) AutoSlide(sb); if (sb->buf_size == 0) { - GrowToSize(sb, data_len); + if (GrowToSize(sb, data_len) != 0) + return -1; } else { while (!DATA_FITS(sb, data_len)) { - Grow(sb); + if (Grow(sb) != 0) { + return -1; + } } } } if (!DATA_FITS(sb, data_len)) { - return; + return -1; } memcpy(sb->buf + sb->buf_offset, data, data_len); seg->stream_offset = sb->stream_offset + sb->buf_offset; seg->segment_len = data_len; sb->buf_offset += data_len; + return 0; } /** * \brief add data w/o tracking a segment */ -void StreamingBufferAppendNoTrack(StreamingBuffer *sb, - const uint8_t *data, uint32_t data_len) +int StreamingBufferAppendNoTrack(StreamingBuffer *sb, + const uint8_t *data, uint32_t data_len) { if (sb->buf == NULL) { if (InitBuffer(sb) == -1) - return; + return -1; } if (!DATA_FITS(sb, data_len)) { if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) AutoSlide(sb); if (sb->buf_size == 0) { - GrowToSize(sb, data_len); + if (GrowToSize(sb, data_len) != 0) + return -1; } else { while (!DATA_FITS(sb, data_len)) { - Grow(sb); + if (Grow(sb) != 0) { + return -1; + } } } } if (!DATA_FITS(sb, data_len)) { - return; + return -1; } memcpy(sb->buf + sb->buf_offset, data, data_len); sb->buf_offset += data_len; + return 0; } #define DATA_FITS_AT_OFFSET(sb, len, offset) \ @@ -282,18 +302,18 @@ void StreamingBufferAppendNoTrack(StreamingBuffer *sb, /** * \param offset offset relative to StreamingBuffer::stream_offset */ -void StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, - const uint8_t *data, uint32_t data_len, - uint64_t offset) +int StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len, + uint64_t offset) { BUG_ON(seg == NULL); if (offset < sb->stream_offset) - return; + return -1; if (sb->buf == NULL) { if (InitBuffer(sb) == -1) - return; + return -1; } uint32_t rel_offset = offset - sb->stream_offset; @@ -303,7 +323,8 @@ void StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, rel_offset = offset - sb->stream_offset; } if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) { - GrowToSize(sb, (rel_offset + data_len)); + if (GrowToSize(sb, (rel_offset + data_len)) != 0) + return -1; } } BUG_ON(!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)); @@ -313,8 +334,7 @@ void StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, seg->segment_len = data_len; if (rel_offset + data_len > sb->buf_offset) sb->buf_offset = rel_offset + data_len; - - + return 0; } int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb, @@ -529,9 +549,9 @@ static int StreamingBufferTest02(void) FAIL_IF(sb == NULL); StreamingBufferSegment seg1; - StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8); + FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); StreamingBufferSegment seg2; - StreamingBufferAppend(sb, &seg2, (const uint8_t *)"01234567", 8); + FAIL_IF(StreamingBufferAppend(sb, &seg2, (const uint8_t *)"01234567", 8) != 0); FAIL_IF(sb->stream_offset != 0); FAIL_IF(sb->buf_offset != 16); FAIL_IF(seg1.stream_offset != 0); @@ -545,7 +565,7 @@ static int StreamingBufferTest02(void) StreamingBufferSlide(sb, 6); StreamingBufferSegment seg3; - StreamingBufferAppend(sb, &seg3, (const uint8_t *)"QWERTY", 6); + FAIL_IF(StreamingBufferAppend(sb, &seg3, (const uint8_t *)"QWERTY", 6) != 0); FAIL_IF(sb->stream_offset != 6); FAIL_IF(sb->buf_offset != 16); FAIL_IF(seg3.stream_offset != 16); @@ -577,9 +597,9 @@ static int StreamingBufferTest03(void) FAIL_IF(sb == NULL); StreamingBufferSegment seg1; - StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8); + FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); StreamingBufferSegment seg2; - StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14); + FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14) != 0); FAIL_IF(sb->stream_offset != 0); FAIL_IF(sb->buf_offset != 22); FAIL_IF(seg1.stream_offset != 0); @@ -591,7 +611,7 @@ static int StreamingBufferTest03(void) DumpSegment(sb, &seg2); StreamingBufferSegment seg3; - StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8); + FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0); FAIL_IF(sb->stream_offset != 0); FAIL_IF(sb->buf_offset != 22); FAIL_IF(seg3.stream_offset != 8); @@ -623,9 +643,9 @@ static int StreamingBufferTest04(void) FAIL_IF(sb == NULL); StreamingBufferSegment seg1; - StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8); + FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); StreamingBufferSegment seg2; - StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14); + FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14) != 0); FAIL_IF(sb->stream_offset != 0); FAIL_IF(sb->buf_offset != 22); FAIL_IF(seg1.stream_offset != 0); @@ -637,7 +657,7 @@ static int StreamingBufferTest04(void) DumpSegment(sb, &seg2); StreamingBufferSegment seg3; - StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8); + FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0); FAIL_IF(sb->stream_offset != 0); FAIL_IF(sb->buf_offset != 22); FAIL_IF(seg3.stream_offset != 8); @@ -651,7 +671,7 @@ static int StreamingBufferTest04(void) /* far ahead of curve: */ StreamingBufferSegment seg4; - StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"XYZ", 3, 124); + FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"XYZ", 3, 124) != 0); FAIL_IF(sb->stream_offset != 0); FAIL_IF(sb->buf_offset != 127); FAIL_IF(sb->buf_size != 128); diff --git a/src/util-streaming-buffer.h b/src/util-streaming-buffer.h index d35e1aaca4f8..20c0a8904b79 100644 --- a/src/util-streaming-buffer.h +++ b/src/util-streaming-buffer.h @@ -105,14 +105,14 @@ void StreamingBufferSlide(StreamingBuffer *sb, uint32_t slide); void StreamingBufferSlideToOffset(StreamingBuffer *sb, uint64_t offset); StreamingBufferSegment *StreamingBufferAppendRaw(StreamingBuffer *sb, - const uint8_t *data, uint32_t data_len); -void StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg, - const uint8_t *data, uint32_t data_len); -void StreamingBufferAppendNoTrack(StreamingBuffer *sb, - const uint8_t *data, uint32_t data_len); -void StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len) __attribute__((warn_unused_result)); +int StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len) __attribute__((warn_unused_result)); +int StreamingBufferAppendNoTrack(StreamingBuffer *sb, + const uint8_t *data, uint32_t data_len) __attribute__((warn_unused_result)); +int StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len, - uint64_t offset); + uint64_t offset) __attribute__((warn_unused_result)); void StreamingBufferSegmentGetData(const StreamingBuffer *sb, const StreamingBufferSegment *seg, From f867bb61e669a00ff9417efbee23a6bc45b3409e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Oct 2016 19:23:32 +0200 Subject: [PATCH 2052/2553] http: fix memory leak in error path --- src/app-layer-htp-body.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index e1cda5659c09..dfda083b6bef 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -166,9 +166,6 @@ void HtpBodyFree(HtpBody *body) { SCEnter(); - if (body->first == NULL) - return; - SCLogDebug("removing chunks of body %p", body); HtpBodyChunk *cur = NULL; From e5ee665f2482367ab2d023be075c5593973e2031 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 09:55:50 +0200 Subject: [PATCH 2053/2553] doc: rewrite rule reload doc --- doc/userguide/rules/live-rule-swap.rst | 70 ++++++-------------------- 1 file changed, 15 insertions(+), 55 deletions(-) diff --git a/doc/userguide/rules/live-rule-swap.rst b/doc/userguide/rules/live-rule-swap.rst index fdc79b00bb0d..25a3c3e57588 100644 --- a/doc/userguide/rules/live-rule-swap.rst +++ b/doc/userguide/rules/live-rule-swap.rst @@ -1,64 +1,24 @@ -Live Rule Reloads -================= +Rule Reloads +============ -As of revision - Suricata version 1.3dev (rev 7109a05), Suricata -supports live rule swap. In other words if you decide to -change/update/remove/add rules you can do it on the fly without -stopping Suricata. This is how you can do it. +Suricata can be told to reloads it's rules without restarting. -The live rule reload is available by default without any additional -config changes needed. Lets say you have started Suricata the regular -way with about 11000 rules: +This works by sending Suricata a signal or by using the unix socket. When Suricata is told to reload the rules these are the basic steps it takes: -:: +* Load new config +* Load new rules +* Construct new detection engine +* Swap old and new detection engines +* Make sure all threads are updated +* Free old detection engine - root@LTS-64-1:~ # suricata -c /etc/suricata/suricata.yaml -v --af-packet - .... - [9907] 13/7/2015 -- 14:53:03 - (detect.c:520) (SigLoadSignatures) -- 50 rule files processed. 16659 rules successfully loaded, 0 rules failed - [9907] 13/7/2015 -- 14:53:04 - (detect.c:2912) (SigAddressPrepareStage1) -- 16667 signatures processed. 989 are IP-only rules, 6019 are inspecting packet payload, 12447 inspect application layer, 72 are decoder event only - [9907] 13/7/2015 -- 14:53:04 - (detect.c:2915) (SigAddressPrepareStage1) -- building signature grouping structure, stage 1: preprocessing rules... complete - [9907] 13/7/2015 -- 14:53:04 - (detect.c:3548) (SigAddressPrepareStage2) -- building signature grouping structure, stage 2: building source address list... complete - [9907] 13/7/2015 -- 14:53:05 - (detect.c:4194) (SigAddressPrepareStage3) -- building signature grouping structure, stage 3: building destination address lists... complete - [9907] 13/7/2015 -- 14:53:06 - (util-threshold-config.c:1176) (SCThresholdConfParseFile) -- Threshold config parsed: 0 rule(s) found - [9907] 13/7/2015 -- 14:53:06 - (util-coredump-config.c:122) (CoredumpLoadConfig) -- Core dump size set to unlimited. - [9907] 13/7/2015 -- 14:53:06 - (util-logopenfile.c:227) (SCConfLogOpenGeneric) -- fast output device (regular) initialized: fast.log - [9907] 13/7/2015 -- 14:53:06 - (util-logopenfile.c:227) (SCConfLogOpenGeneric) -- eve-log output device (regular) initialized: eve.json - [9907] 13/7/2015 -- 14:53:06 - (runmodes.c:774) (RunModeInitializeOutputs) -- enabling 'eve-log' module 'alert' - [9907] 13/7/2015 -- 14:53:06 - (runmodes.c:774) (RunModeInitializeOutputs) -- enabling 'eve-log' module 'http' - [9907] 13/7/2015 -- 14:53:06 - (runmodes.c:774) (RunModeInitializeOutputs) -- enabling 'eve-log' module 'dns' - [9907] 13/7/2015 -- 14:53:06 - (runmodes.c:774) (RunModeInitializeOutputs) -- enabling 'eve-log' module 'tls' - [9907] 13/7/2015 -- 14:53:06 - (runmodes.c:774) (RunModeInitializeOutputs) -- enabling 'eve-log' module 'files' - .... - ... +Suricata will continue to process packets normally during this process. Keep in mind though, that the system should have enough memory for both detection engines. -But there is a new ruleset update and you have made some changes to -some rules and/or added new ones and you would like to do a live swap. +Signal:: -Find what is the PID of Suricata: + kill -USR2 $(pidof suricata) -:: +Unix socket:: - root@LTS-64-1:~ # ps aux |grep suricata - root 9907 56.9 15.9 840624 410544 pts/0 Sl+ 14:52 0:06 suricata -c /etc/suricata/suricata.yaml -v --af-packet - root@LTS-64-1:~ # + suricatasc -c reload-rules -Send the signal: - -:: - - root@LTS-64-1:~ # kill -USR2 9907 - -Suricata will now reload the rules: - -:: - - [9907] 13/7/2015 -- 14:57:11 - (detect.c:520) (SigLoadSignatures) -- 50 rule files processed. 16659 rules successfully loaded, 0 rules failed - [9907] 13/7/2015 -- 14:57:11 - (detect.c:2912) (SigAddressPrepareStage1) -- 16667 signatures processed. 989 are IP-only rules, 6019 are inspecting packet payload, 12447 inspect application layer, 72 are decoder event only - [9907] 13/7/2015 -- 14:57:11 - (detect.c:2915) (SigAddressPrepareStage1) -- building signature grouping structure, stage 1: preprocessing rules... complete - [9907] 13/7/2015 -- 14:57:12 - (detect.c:3548) (SigAddressPrepareStage2) -- building signature grouping structure, stage 2: building source address list... complete - [9907] 13/7/2015 -- 14:57:13 - (detect.c:4194) (SigAddressPrepareStage3) -- building signature grouping structure, stage 3: building destination address lists... complete - [9907] 13/7/2015 -- 14:57:14 - (util-threshold-config.c:1176) (SCThresholdConfParseFile) -- Threshold config parsed: 0 rule(s) found - [9907] 13/7/2015 -- 14:57:14 - (detect-engine.c:543) (DetectEngineReloadThreads) -- rule reload starting - [9907] 13/7/2015 -- 14:57:14 - (detect-engine.c:622) (DetectEngineReloadThreads) -- Live rule swap has swapped 2 old det_ctx's with new ones, along with the new de_ctx - [9907] 13/7/2015 -- 14:58:31 - (detect-engine.c:694) (DetectEngineReloadThreads) -- rule reload complete - [9907] 13/7/2015 -- 14:58:31 - (detect.c:4226) (SigAddressCleanupStage1) -- cleaning up signature grouping structure... complete From 729fd2e406acddcdff9785032833992a9eb17813 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 09:56:22 +0200 Subject: [PATCH 2054/2553] doc: update libcap-ng doc --- .../configuration/dropping-privileges.rst | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/doc/userguide/configuration/dropping-privileges.rst b/doc/userguide/configuration/dropping-privileges.rst index ade11c1b4970..937a3951a498 100644 --- a/doc/userguide/configuration/dropping-privileges.rst +++ b/doc/userguide/configuration/dropping-privileges.rst @@ -5,22 +5,22 @@ Currently, libcap-ng is needed for dropping privileges on Suricata after startup. For libcap, see status of feature request number #276 -- Libcap support for dropping privileges. -Download the current version of libcap-ng from upstream, see also +Most distributions have ``libcap-ng`` in their repositories. + +To download the current version of libcap-ng from upstream, see also http://people.redhat.com/sgrubb/libcap-ng/ChangeLog :: - wget http://people.redhat.com/sgrubb/libcap-ng/libcap-ng-0.7.4.tar.gz - tar -xzvf libcap-ng-0.7.4.tar.gz - cd libcap-ng-0.7.4 + wget http://people.redhat.com/sgrubb/libcap-ng/libcap-ng-0.7.8.tar.gz + tar -xzvf libcap-ng-0.7.8.tar.gz + cd libcap-ng-0.7.8 ./configure make make install -Download, configure, compile, and install Suricata for your particular -setup. See `Suricata Installation -`_. Depending -on your environment, you may need to add the +Download, configure, compile and install Suricata for your particular setup. +See :doc:`../install`. Depending on your environment, you may need to add the --with-libpcap_ng-libraries and --with-libpcap_ng-includes options during the configure step. e.g: @@ -35,8 +35,7 @@ e.g. (this assumes a 'suri' user and group): :: - /usr/local/bin/suricata -c /etc/suricata/suricata.yaml \ - -D -i eth0 --user=suri --group=suri + suricata -D -i eth0 --user=suri --group=suri You will also want to make sure your user/group permissions are set so suricata can still write to its log files which are usually located in From f64decf5e2b0d366b3f0b98dfc094246f8d92050 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 09:57:02 +0200 Subject: [PATCH 2055/2553] doc: clean up log rotation --- doc/userguide/configuration/log-rotation.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/userguide/configuration/log-rotation.rst b/doc/userguide/configuration/log-rotation.rst index 4bf507189e01..85c4a63e75b8 100644 --- a/doc/userguide/configuration/log-rotation.rst +++ b/doc/userguide/configuration/log-rotation.rst @@ -1,9 +1,10 @@ Log Rotation ============ -Starting with Suricata version 2.0.2 (#1200), log rotation is made a -lot easier. A HUP signal sent to Suricata will force it to reopen the -logfiles. +Suricata can generate lot of output, so it's important to manage the files +to avoid issues with disks filling up. + +A HUP signal sent to Suricata will force it to reopen the logfiles. Example logrotate file: From 48274218df6ceac0c7fb864e93e8ad30ed2aa049 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 09:57:44 +0200 Subject: [PATCH 2056/2553] doc: multi-tenancy is not work in progress --- doc/userguide/configuration/multi-tenant.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/userguide/configuration/multi-tenant.rst b/doc/userguide/configuration/multi-tenant.rst index f7142313aca1..73abdae8556f 100644 --- a/doc/userguide/configuration/multi-tenant.rst +++ b/doc/userguide/configuration/multi-tenant.rst @@ -1,10 +1,6 @@ Multi Tenancy ============= -**Work In Progress** - -This is part of Suricata 3.0RC1. - Introduction ------------ From 80bd59ae86e25962cd7a318b670d9bd8176aa7e6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 09:58:10 +0200 Subject: [PATCH 2057/2553] doc: improve install doc, configure --- configure.ac | 3 ++- doc/userguide/install.rst | 26 +++++++++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index c3b8e8b65bb4..d4ecfc25e206 100644 --- a/configure.ac +++ b/configure.ac @@ -1858,7 +1858,8 @@ echo " from https://github.com/redis/hiredis or your distribution:" echo echo " Ubuntu: apt-get install libhiredis-dev" - echo " Fedora: yum install libhiredis-devel" + echo " Fedora: dnf install hiredis-devel" + echo " RHEL/CentOS: yum install hiredis-devel" echo exit 1 fi diff --git a/doc/userguide/install.rst b/doc/userguide/install.rst index 5049c69b87b5..20bd332e7fe3 100644 --- a/doc/userguide/install.rst +++ b/doc/userguide/install.rst @@ -67,15 +67,31 @@ The following tools are required: make gcc (or clang) pkg-config +For full features, also add: + + libjansson, libnss, libgeoip, liblua5.1, libhiredis + Ubuntu/Debian """"""""""""" -:: +Minimal:: + + apt-get install libpcre3 libpcre3-dbg libpcre3-dev build-essential libpcap-dev \ + libyaml-0-2 libyaml-dev pkg-config zlib1g zlib1g-dev \ + make libmagic-dev + +Recommended:: + + apt-get install libpcre3 libpcre3-dbg libpcre3-dev build-essential libpcap-dev \ + libnet1-dev libyaml-0-2 libyaml-dev pkg-config zlib1g zlib1g-dev \ + libcap-ng-dev libcap-ng0 make libmagic-dev libjansson-dev \ + libnss3-dev libgeoip-dev liblua5.1-dev libhiredis-dev - sudo apt-get install libpcre3 libpcre3-dbg libpcre3-dev build-essential libpcap-dev \ - libnet1-dev libyaml-0-2 libyaml-dev pkg-config zlib1g zlib1g-dev \ - libcap-ng-dev libcap-ng0 make libmagic-dev libjansson-dev +Extra for iptables/nftables IPS integration:: + apt-get install libnetfilter-queue-dev libnetfilter-queue1 \ + libnetfilter-log-dev libnetfilter-log1 \ + libnfnetlink-dev libnfnetlink0 .. _install-binary-packages: @@ -85,7 +101,7 @@ Binary packages Ubuntu ^^^^^^ -For Ubuntu, the OISF maintains a PPA ``suricata-stable`` that is always contains the latest stable release. +For Ubuntu, the OISF maintains a PPA ``suricata-stable`` that always contains the latest stable release. To use it:: From e24c3937b3e4da44a746896e897739ed464018cf Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 10:06:05 +0200 Subject: [PATCH 2058/2553] doc: add rule-management chapter --- doc/userguide/Makefile.am | 3 +-- doc/userguide/index.rst | 2 +- doc/userguide/rule-management/index.rst | 6 ++++++ doc/userguide/{ => rule-management}/oinkmaster.rst | 0 .../oinkmaster/oinkmasterconf.png | Bin .../oinkmaster/suricata_yaml.png | Bin doc/userguide/rules/intro.rst | 2 +- 7 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 doc/userguide/rule-management/index.rst rename doc/userguide/{ => rule-management}/oinkmaster.rst (100%) rename doc/userguide/{ => rule-management}/oinkmaster/oinkmasterconf.png (100%) rename doc/userguide/{ => rule-management}/oinkmaster/suricata_yaml.png (100%) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index 56c375db8f6e..c71f2b7af0b0 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -3,7 +3,7 @@ EXTRA_DIST = \ index.rst \ install.rst \ acknowledgements.rst \ - oinkmaster.rst \ + rule-management \ command-line-options.rst \ initscripts.rst \ public-data-sets.rst \ @@ -16,7 +16,6 @@ EXTRA_DIST = \ file-extraction \ licenses \ manpages \ - oinkmaster \ output \ performance \ reputation \ diff --git a/doc/userguide/index.rst b/doc/userguide/index.rst index 85b792f154f0..13f4f6838f28 100644 --- a/doc/userguide/index.rst +++ b/doc/userguide/index.rst @@ -9,7 +9,7 @@ Suricata User Guide install.rst command-line-options rules/index.rst - oinkmaster + rule-management/index.rst make-sense-alerts performance/index.rst configuration/index.rst diff --git a/doc/userguide/rule-management/index.rst b/doc/userguide/rule-management/index.rst new file mode 100644 index 000000000000..59a0f5d1b349 --- /dev/null +++ b/doc/userguide/rule-management/index.rst @@ -0,0 +1,6 @@ +Rule Management +=============== + +.. toctree:: + + oinkmaster diff --git a/doc/userguide/oinkmaster.rst b/doc/userguide/rule-management/oinkmaster.rst similarity index 100% rename from doc/userguide/oinkmaster.rst rename to doc/userguide/rule-management/oinkmaster.rst diff --git a/doc/userguide/oinkmaster/oinkmasterconf.png b/doc/userguide/rule-management/oinkmaster/oinkmasterconf.png similarity index 100% rename from doc/userguide/oinkmaster/oinkmasterconf.png rename to doc/userguide/rule-management/oinkmaster/oinkmasterconf.png diff --git a/doc/userguide/oinkmaster/suricata_yaml.png b/doc/userguide/rule-management/oinkmaster/suricata_yaml.png similarity index 100% rename from doc/userguide/oinkmaster/suricata_yaml.png rename to doc/userguide/rule-management/oinkmaster/suricata_yaml.png diff --git a/doc/userguide/rules/intro.rst b/doc/userguide/rules/intro.rst index 726c9171a25e..9e1e6ce56d10 100644 --- a/doc/userguide/rules/intro.rst +++ b/doc/userguide/rules/intro.rst @@ -8,7 +8,7 @@ people are using existing rulesets. The most used are `Emerging Threats `_, `Emerging Threats Pro `_ and Sourcefire's `VRT `_. A way to install rules is described in -:doc:`../oinkmaster`. This Suricata Rules document explains all about +:doc:`../rule-management/oinkmaster`. This Suricata Rules document explains all about signatures; how to read-, adjust-and create them. A rule/signature consists of the following: From d80914d350fcc943b24b78e8eca94cc6892e483c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 10:10:30 +0200 Subject: [PATCH 2059/2553] doc: move rule reload and adding rules into rule-management --- .../{rules => rule-management}/adding-your-own-rules.rst | 2 +- doc/userguide/rule-management/index.rst | 2 ++ .../live-rule-swap.rst => rule-management/rule-reload.rst} | 1 - doc/userguide/rules/index.rst | 2 -- 4 files changed, 3 insertions(+), 4 deletions(-) rename doc/userguide/{rules => rule-management}/adding-your-own-rules.rst (96%) rename doc/userguide/{rules/live-rule-swap.rst => rule-management/rule-reload.rst} (99%) diff --git a/doc/userguide/rules/adding-your-own-rules.rst b/doc/userguide/rule-management/adding-your-own-rules.rst similarity index 96% rename from doc/userguide/rules/adding-your-own-rules.rst rename to doc/userguide/rule-management/adding-your-own-rules.rst index 2b2aa5ce2101..83305cdb9266 100644 --- a/doc/userguide/rules/adding-your-own-rules.rst +++ b/doc/userguide/rule-management/adding-your-own-rules.rst @@ -11,7 +11,7 @@ your console: sudo nano local.rules -Write your rule, see :doc:`intro` and save it. +Write your rule, see :doc:`../rules/intro` and save it. Open yaml diff --git a/doc/userguide/rule-management/index.rst b/doc/userguide/rule-management/index.rst index 59a0f5d1b349..75caabfeb275 100644 --- a/doc/userguide/rule-management/index.rst +++ b/doc/userguide/rule-management/index.rst @@ -4,3 +4,5 @@ Rule Management .. toctree:: oinkmaster + adding-your-own-rules + rule-reload diff --git a/doc/userguide/rules/live-rule-swap.rst b/doc/userguide/rule-management/rule-reload.rst similarity index 99% rename from doc/userguide/rules/live-rule-swap.rst rename to doc/userguide/rule-management/rule-reload.rst index 25a3c3e57588..a857a21197de 100644 --- a/doc/userguide/rules/live-rule-swap.rst +++ b/doc/userguide/rule-management/rule-reload.rst @@ -21,4 +21,3 @@ Signal:: Unix socket:: suricatasc -c reload-rules - diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst index 1600014f6dd2..6680d030f726 100644 --- a/doc/userguide/rules/index.rst +++ b/doc/userguide/rules/index.rst @@ -20,6 +20,4 @@ Suricata Rules enip-keyword rule-lua-scripting normalized-buffers - live-rule-swap - adding-your-own-rules snort-compatibility From 0bce4b5534d4a3bc5181216d1f5b3e8e81a99cf8 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 6 Oct 2016 11:08:40 -0600 Subject: [PATCH 2060/2553] macOS: thread return value affects newer macOS as well ALl OS X/macOS versions since 10.10 return EDEADLK here instead of EBUSY. Assume they will moving forward as well. --- src/threads.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/threads.c b/src/threads.c index 19f55d805df1..29b924f4a74c 100644 --- a/src/threads.c +++ b/src/threads.c @@ -89,10 +89,9 @@ int ThreadMacrosTest03RWLocks(void) int r = 0; r |= SCRWLockInit(&rwl_write, NULL); r |= SCRWLockWRLock(&rwl_write); -/* work around OS X 10.10 Yosemite returning EDEADLK. All other - * OS' (and versions of OS X that I tested) seem to return EBUSY - * instead. */ -#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__==101000 +/* OS X/macOS 10.10 (Yosemite) and newer return EDEADLK. Older versions + * and other tested OS's return EBUSY. */ +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__>=101000 r |= (SCRWLockTryWRLock(&rwl_write) == EDEADLK)? 0 : 1; #else r |= (SCRWLockTryWRLock(&rwl_write) == EBUSY)? 0 : 1; From 3fab684f974e6f13c3bf217029501e2cd1e4fe67 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 6 Oct 2016 09:59:13 -0600 Subject: [PATCH 2061/2553] logging: don't log that json is disabled in each logger A warning log is already emitted if eve-log is enabled in the configuration but json support is not built so the logger registration functions can be silent. --- src/output-json-alert.c | 1 - src/output-json-dns.c | 1 - src/output-json-drop.c | 1 - src/output-json-file.c | 1 - src/output-json-flow.c | 1 - src/output-json-http.c | 1 - src/output-json-netflow.c | 1 - src/output-json-smtp.c | 1 - src/output-json-ssh.c | 1 - src/output-json-stats.c | 1 - src/output-json-template.c | 2 -- src/output-json-tls.c | 1 - 12 files changed, 13 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 682377448771..1db766d61f7b 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -740,7 +740,6 @@ void JsonAlertLogRegister (void) void JsonAlertLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-dns.c b/src/output-json-dns.c index f55d6d546173..948cce7def8c 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -878,7 +878,6 @@ void JsonDnsLogRegister (void) void JsonDnsLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 66ab32aea9f5..e26fd6dcb6ed 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -438,7 +438,6 @@ void JsonDropLogRegister (void) void JsonDropLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-file.c b/src/output-json-file.c index 4fb08b5ea190..29b3d0e5d1e6 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -310,7 +310,6 @@ void JsonFileLogRegister (void) void JsonFileLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 26723fdf0248..09b15c09e162 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -483,7 +483,6 @@ void JsonFlowLogRegister (void) void JsonFlowLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-http.c b/src/output-json-http.c index 381ddeb4c4ab..a22025278063 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -599,7 +599,6 @@ void JsonHttpLogRegister (void) void JsonHttpLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index fb39d219e467..4733a7dcb781 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -447,7 +447,6 @@ void JsonNetFlowLogRegister(void) void JsonNetFlowLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 368e917c280b..6bec700e161f 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -273,7 +273,6 @@ void JsonSmtpLogRegister (void) { void JsonSmtpLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 2b0ac7f99c0c..627b2b6f598e 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -326,7 +326,6 @@ void JsonSshLogRegister (void) void JsonSshLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-stats.c b/src/output-json-stats.c index be1646a4456a..16bf629c910c 100644 --- a/src/output-json-stats.c +++ b/src/output-json-stats.c @@ -387,7 +387,6 @@ void JsonStatsLogRegister(void) { void JsonStatsLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif diff --git a/src/output-json-template.c b/src/output-json-template.c index 88e8ee7981fc..fcbee919b9c7 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -210,8 +210,6 @@ void JsonTemplateLogRegister(void) void JsonTemplateLogRegister(void) { - SCLogInfo("Cannot register JSON output for template. " - "JSON support was disabled during build."); } #endif /* HAVE_LIBJANSSON */ diff --git a/src/output-json-tls.c b/src/output-json-tls.c index f1accdde3281..0f75547c9cad 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -347,7 +347,6 @@ void JsonTlsLogRegister (void) void JsonTlsLogRegister (void) { - SCLogInfo("Can't register JSON output - JSON support was disabled during build."); } #endif From c81aaeda7bbfa92cef5ad7a6f577ba607b528a1e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 5 Oct 2016 09:16:25 +0200 Subject: [PATCH 2062/2553] flow: move file flags into their own variable Move FLOW_FILE_* flags into Flow::file_flags. Rename them to FLOWFILE_* so non updated code will break. --- src/app-layer-htp-file.c | 4 ++-- src/app-layer-smtp.c | 2 +- src/flow-util.h | 2 ++ src/flow.h | 38 ++++++++++++++++++++-------------- src/util-file.c | 44 ++++++++++++++++++++-------------------- 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index ab0121d69b82..199290610ae2 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -109,7 +109,7 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, ((s->flags & HTP_FLAG_STORE_FILES_TX_TS) && txid == s->store_tx_id)) { flags |= FILE_STORE; flags &= ~FILE_NOSTORE; - } else if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TC)) { + } else if (!(flags & FILE_STORE) && (s->f->file_flags & FLOWFILE_NO_STORE_TC)) { flags |= FILE_NOSTORE; } @@ -132,7 +132,7 @@ int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, ((s->flags & HTP_FLAG_STORE_FILES_TX_TC) && txid == s->store_tx_id)) { flags |= FILE_STORE; flags &= ~FILE_NOSTORE; - } else if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TS)) { + } else if (!(flags & FILE_STORE) && (s->f->file_flags & FLOWFILE_NO_STORE_TS)) { flags |= FILE_NOSTORE; } diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 8462cc366d58..1eb0aa29d0ae 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -4938,7 +4938,7 @@ static int SMTPParserTest14(void) static int SMTPProcessDataChunkTest01(void){ Flow f; FLOW_INITIALIZE(&f); - f.flags = FLOW_FILE_NO_STORE_TS; + f.file_flags = FLOWFILE_NO_STORE_TS; MimeDecParseState *state = MimeDecInitParser(&f, NULL); int ret; ret = SMTPProcessDataChunk(NULL, 0, state); diff --git a/src/flow-util.h b/src/flow-util.h index 7ab08f6c4f0a..3874050b4aa1 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -46,6 +46,7 @@ (f)->probing_parser_toserver_alproto_masks = 0; \ (f)->probing_parser_toclient_alproto_masks = 0; \ (f)->flags = 0; \ + (f)->file_flags = 0; \ (f)->lastts.tv_sec = 0; \ (f)->lastts.tv_usec = 0; \ FLOWLOCK_INIT((f)); \ @@ -89,6 +90,7 @@ (f)->probing_parser_toserver_alproto_masks = 0; \ (f)->probing_parser_toclient_alproto_masks = 0; \ (f)->flags = 0; \ + (f)->file_flags = 0; \ (f)->lastts.tv_sec = 0; \ (f)->lastts.tv_usec = 0; \ (f)->protoctx = NULL; \ diff --git a/src/flow.h b/src/flow.h index 52dec76df1be..21dc0acfa690 100644 --- a/src/flow.h +++ b/src/flow.h @@ -48,9 +48,6 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_TO_DST_SEEN 0x00000002 /** Don't return this from the flow hash. It has been replaced. */ #define FLOW_TCP_REUSED 0x00000004 -/** 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 @@ -88,30 +85,38 @@ typedef struct AppLayerParserState_ AppLayerParserState; /** Probing parser alproto detection done */ #define FLOW_TC_PP_ALPROTO_DETECT_DONE 0x00040000 #define FLOW_TIMEOUT_REASSEMBLY_DONE 0x00080000 -/** even if the flow has files, don't store 'm */ -#define FLOW_FILE_NO_STORE_TS 0x00100000 -#define FLOW_FILE_NO_STORE_TC 0x00200000 /** flow is ipv4 */ #define FLOW_IPV4 0x00400000 /** flow is ipv6 */ #define FLOW_IPV6 0x00800000 + +/* File flags */ + +/** no magic on files in this flow */ +#define FLOWFILE_NO_MAGIC_TS BIT_U16(0) +#define FLOWFILE_NO_MAGIC_TC BIT_U16(1) + +/** even if the flow has files, don't store 'm */ +#define FLOWFILE_NO_STORE_TS BIT_U16(2) +#define FLOWFILE_NO_STORE_TC BIT_U16(3) /** no md5 on files in this flow */ -#define FLOW_FILE_NO_MD5_TS 0x01000000 -#define FLOW_FILE_NO_MD5_TC 0x02000000 +#define FLOWFILE_NO_MD5_TS BIT_U16(4) +#define FLOWFILE_NO_MD5_TC BIT_U16(5) /** no sha1 on files in this flow */ -#define FLOW_FILE_NO_SHA1_TS 0x04000000 -#define FLOW_FILE_NO_SHA1_TC 0x08000000 +#define FLOWFILE_NO_SHA1_TS BIT_U16(6) +#define FLOWFILE_NO_SHA1_TC BIT_U16(7) /** no sha256 on files in this flow */ -#define FLOW_FILE_NO_SHA256_TS 0x10000000 -#define FLOW_FILE_NO_SHA256_TC 0x20000000 +#define FLOWFILE_NO_SHA256_TS BIT_U16(8) +#define FLOWFILE_NO_SHA256_TC BIT_U16(9) /** no size tracking of files in this flow */ -#define FLOW_FILE_NO_SIZE_TS 0x40000000 -#define FLOW_FILE_NO_SIZE_TC 0x80000000 +#define FLOWFILE_NO_SIZE_TS BIT_U16(10) +#define FLOWFILE_NO_SIZE_TC BIT_U16(11) + #define FLOW_IS_IPV4(f) \ (((f)->flags & FLOW_IPV4) == FLOW_IPV4) @@ -350,7 +355,10 @@ typedef struct Flow_ uint32_t probing_parser_toserver_alproto_masks; uint32_t probing_parser_toclient_alproto_masks; - uint32_t flags; + uint32_t flags; /**< generic flags */ + + uint16_t file_flags; /**< file tracking/extraction flags */ + /* coccinelle: Flow:file_flags:FLOWFILE_ */ #ifdef FLOWLOCK_RWLOCK SCRWLock r; diff --git a/src/util-file.c b/src/util-file.c index cc48b946c998..c8ef9b3916ee 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -217,43 +217,43 @@ uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction) uint16_t flags = 0; if (direction == STREAM_TOSERVER) { - if (flow->flags & FLOW_FILE_NO_STORE_TS) { + if (flow->file_flags & FLOWFILE_NO_STORE_TS) { flags |= FILE_NOSTORE; } - if (flow->flags & FLOW_FILE_NO_MAGIC_TS) { + if (flow->file_flags & FLOWFILE_NO_MAGIC_TS) { flags |= FILE_NOMAGIC; } - if (flow->flags & FLOW_FILE_NO_MD5_TS) { + if (flow->file_flags & FLOWFILE_NO_MD5_TS) { flags |= FILE_NOMD5; } - if (flow->flags & FLOW_FILE_NO_SHA1_TS) { + if (flow->file_flags & FLOWFILE_NO_SHA1_TS) { flags |= FILE_NOSHA1; } - if (flow->flags & FLOW_FILE_NO_SHA256_TS) { + if (flow->file_flags & FLOWFILE_NO_SHA256_TS) { flags |= FILE_NOSHA256; } } else { - if (flow->flags & FLOW_FILE_NO_STORE_TC) { + if (flow->file_flags & FLOWFILE_NO_STORE_TC) { flags |= FILE_NOSTORE; } - if (flow->flags & FLOW_FILE_NO_MAGIC_TC) { + if (flow->file_flags & FLOWFILE_NO_MAGIC_TC) { flags |= FILE_NOMAGIC; } - if (flow->flags & FLOW_FILE_NO_MD5_TC) { + if (flow->file_flags & FLOWFILE_NO_MD5_TC) { flags |= FILE_NOMD5; } - if (flow->flags & FLOW_FILE_NO_SHA1_TC) { + if (flow->file_flags & FLOWFILE_NO_SHA1_TC) { flags |= FILE_NOSHA1; } - if (flow->flags & FLOW_FILE_NO_SHA256_TC) { + if (flow->file_flags & FLOWFILE_NO_SHA256_TC) { flags |= FILE_NOSHA256; } } @@ -813,9 +813,9 @@ void FileDisableStoring(Flow *f, uint8_t direction) DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) - f->flags |= FLOW_FILE_NO_STORE_TS; + f->file_flags |= FLOWFILE_NO_STORE_TS; else - f->flags |= FLOW_FILE_NO_STORE_TC; + f->file_flags |= FLOWFILE_NO_STORE_TC; FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); if (ffc != NULL) { @@ -845,9 +845,9 @@ void FileDisableMagic(Flow *f, uint8_t direction) DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) - f->flags |= FLOW_FILE_NO_MAGIC_TS; + f->file_flags |= FLOWFILE_NO_MAGIC_TS; else - f->flags |= FLOW_FILE_NO_MAGIC_TC; + f->file_flags |= FLOWFILE_NO_MAGIC_TC; FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); if (ffc != NULL) { @@ -876,9 +876,9 @@ void FileDisableMd5(Flow *f, uint8_t direction) DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) - f->flags |= FLOW_FILE_NO_MD5_TS; + f->file_flags |= FLOWFILE_NO_MD5_TS; else - f->flags |= FLOW_FILE_NO_MD5_TC; + f->file_flags |= FLOWFILE_NO_MD5_TC; FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); if (ffc != NULL) { @@ -915,9 +915,9 @@ void FileDisableSha1(Flow *f, uint8_t direction) DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) - f->flags |= FLOW_FILE_NO_SHA1_TS; + f->file_flags |= FLOWFILE_NO_SHA1_TS; else - f->flags |= FLOW_FILE_NO_SHA1_TC; + f->file_flags |= FLOWFILE_NO_SHA1_TC; FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); if (ffc != NULL) { @@ -954,9 +954,9 @@ void FileDisableSha256(Flow *f, uint8_t direction) DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) - f->flags |= FLOW_FILE_NO_SHA256_TS; + f->file_flags |= FLOWFILE_NO_SHA256_TS; else - f->flags |= FLOW_FILE_NO_SHA256_TC; + f->file_flags |= FLOWFILE_NO_SHA256_TC; FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); if (ffc != NULL) { @@ -993,9 +993,9 @@ void FileDisableFilesize(Flow *f, uint8_t direction) DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) - f->flags |= FLOW_FILE_NO_SIZE_TS; + f->file_flags |= FLOWFILE_NO_SIZE_TS; else - f->flags |= FLOW_FILE_NO_SIZE_TC; + f->file_flags |= FLOWFILE_NO_SIZE_TC; FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); if (ffc != NULL) { From 664f9aa9068dccfde49c64ca8dd2d1bc049262a6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 5 Oct 2016 09:25:19 +0200 Subject: [PATCH 2063/2553] flow: use BIT_U32 for flags --- src/flow.h | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/flow.h b/src/flow.h index 21dc0acfa690..540ef9d9926b 100644 --- a/src/flow.h +++ b/src/flow.h @@ -43,53 +43,51 @@ typedef struct AppLayerParserState_ AppLayerParserState; /* per flow flags */ /** At least on packet from the source address was seen */ -#define FLOW_TO_SRC_SEEN 0x00000001 +#define FLOW_TO_SRC_SEEN BIT_U32(0) /** At least on packet from the destination address was seen */ -#define FLOW_TO_DST_SEEN 0x00000002 +#define FLOW_TO_DST_SEEN BIT_U32(1) /** Don't return this from the flow hash. It has been replaced. */ -#define FLOW_TCP_REUSED 0x00000004 +#define FLOW_TCP_REUSED BIT_U32(2) /** Flow was inspected against IP-Only sigs in the toserver direction */ -#define FLOW_TOSERVER_IPONLY_SET 0x00000020 +#define FLOW_TOSERVER_IPONLY_SET BIT_U32(3) /** Flow was inspected against IP-Only sigs in the toclient direction */ -#define FLOW_TOCLIENT_IPONLY_SET 0x00000040 +#define FLOW_TOCLIENT_IPONLY_SET BIT_U32(4) /** Packet belonging to this flow should not be inspected at all */ -#define FLOW_NOPACKET_INSPECTION 0x00000080 +#define FLOW_NOPACKET_INSPECTION BIT_U32(5) /** Packet payloads belonging to this flow should not be inspected */ -#define FLOW_NOPAYLOAD_INSPECTION 0x00000100 +#define FLOW_NOPAYLOAD_INSPECTION BIT_U32(6) /** All packets in this flow should be dropped */ -#define FLOW_ACTION_DROP 0x00000200 +#define FLOW_ACTION_DROP BIT_U32(7) /** Sgh for toserver direction set (even if it's NULL) */ -#define FLOW_SGH_TOSERVER 0x00000400 +#define FLOW_SGH_TOSERVER BIT_U32(8) /** Sgh for toclient direction set (even if it's NULL) */ -#define FLOW_SGH_TOCLIENT 0x00000800 +#define FLOW_SGH_TOCLIENT BIT_U32(9) /** packet to server direction has been logged in drop file (only in IPS mode) */ -#define FLOW_TOSERVER_DROP_LOGGED 0x00001000 +#define FLOW_TOSERVER_DROP_LOGGED BIT_U32(10) /** packet to client direction has been logged in drop file (only in IPS mode) */ -#define FLOW_TOCLIENT_DROP_LOGGED 0x00002000 +#define FLOW_TOCLIENT_DROP_LOGGED BIT_U32(11) /** alproto detect done. Right now we need it only for udp */ -#define FLOW_ALPROTO_DETECT_DONE 0x00004000 - -// vacany 1x +#define FLOW_ALPROTO_DETECT_DONE BIT_U32(12) /** Pattern matcher alproto detection done */ -#define FLOW_TS_PM_ALPROTO_DETECT_DONE 0x00008000 +#define FLOW_TS_PM_ALPROTO_DETECT_DONE BIT_U32(13) /** Probing parser alproto detection done */ -#define FLOW_TS_PP_ALPROTO_DETECT_DONE 0x00010000 +#define FLOW_TS_PP_ALPROTO_DETECT_DONE BIT_U32(14) /** Pattern matcher alproto detection done */ -#define FLOW_TC_PM_ALPROTO_DETECT_DONE 0x00020000 +#define FLOW_TC_PM_ALPROTO_DETECT_DONE BIT_U32(15) /** Probing parser alproto detection done */ -#define FLOW_TC_PP_ALPROTO_DETECT_DONE 0x00040000 -#define FLOW_TIMEOUT_REASSEMBLY_DONE 0x00080000 +#define FLOW_TC_PP_ALPROTO_DETECT_DONE BIT_U32(16) +#define FLOW_TIMEOUT_REASSEMBLY_DONE BIT_U32(17) /** flow is ipv4 */ -#define FLOW_IPV4 0x00400000 +#define FLOW_IPV4 BIT_U32(18) /** flow is ipv6 */ -#define FLOW_IPV6 0x00800000 +#define FLOW_IPV6 BIT_U32(19) /* File flags */ From d3fb4de1b54fe63f2e72d2d43736729900a44928 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 5 Oct 2016 09:44:41 +0200 Subject: [PATCH 2064/2553] detect: move file flags update into it's own function --- src/detect.c | 141 ++++++++++++++++++++------------------------------- 1 file changed, 55 insertions(+), 86 deletions(-) diff --git a/src/detect.c b/src/detect.c index 8dfd63f506f4..519394ab7b5f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -941,6 +941,57 @@ DetectPrefilterSetNonPrefilterList(const Packet *p, DetectEngineThreadCtx *det_c det_ctx->sgh->non_pf_other_store_array, det_ctx->sgh->non_pf_other_store_cnt); } +/** \internal + * \brief update flow's file tracking flags based on the detection engine + */ +static inline void +DetectPostInspectFileFlagsUpdate(Flow *pflow, const SigGroupHead *sgh, uint8_t direction) +{ + /* see if this sgh requires us to consider file storing */ + if (sgh == NULL || sgh->filestore_cnt == 0) { + FileDisableStoring(pflow, direction); + } + + /* see if this sgh requires us to consider file magic */ + if (!FileForceMagic() && (sgh == NULL || + !(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC))) + { + SCLogDebug("disabling magic for flow"); + FileDisableMagic(pflow, direction); + } + + /* see if this sgh requires us to consider file md5 */ + if (!FileForceMd5() && (sgh == NULL || + !(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMD5))) + { + SCLogDebug("disabling md5 for flow"); + FileDisableMd5(pflow, direction); + } + + /* see if this sgh requires us to consider file sha1 */ + if (!FileForceSha1() && (sgh == NULL || + !(sgh->flags & SIG_GROUP_HEAD_HAVEFILESHA1))) + { + SCLogDebug("disabling sha1 for flow"); + FileDisableSha1(pflow, direction); + } + + /* see if this sgh requires us to consider file sha256 */ + if (!FileForceSha256() && (sgh == NULL || + !(sgh->flags & SIG_GROUP_HEAD_HAVEFILESHA256))) + { + SCLogDebug("disabling sha256 for flow"); + FileDisableSha256(pflow, direction); + } + + /* see if this sgh requires us to consider filesize */ + if (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) + { + SCLogDebug("disabling filesize for flow"); + FileDisableFilesize(pflow, direction); + } +} + /** * \brief Signature match function * @@ -1528,97 +1579,15 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh pflow->sgh_toserver = det_ctx->sgh; pflow->flags |= FLOW_SGH_TOSERVER; - /* see if this sgh requires us to consider file storing */ - if (pflow->sgh_toserver == NULL || pflow->sgh_toserver->filestore_cnt == 0) { - FileDisableStoring(pflow, STREAM_TOSERVER); - } - - /* see if this sgh requires us to consider file magic */ - if (!FileForceMagic() && (pflow->sgh_toserver == NULL || - !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC))) - { - SCLogDebug("disabling magic for flow"); - FileDisableMagic(pflow, STREAM_TOSERVER); - } + DetectPostInspectFileFlagsUpdate(pflow, + pflow->sgh_toserver, STREAM_TOSERVER); - /* see if this sgh requires us to consider file md5 */ - if (!FileForceMd5() && (pflow->sgh_toserver == NULL || - !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILEMD5))) - { - SCLogDebug("disabling md5 for flow"); - FileDisableMd5(pflow, STREAM_TOSERVER); - } - - /* see if this sgh requires us to consider file sha1 */ - if (!FileForceSha1() && (pflow->sgh_toserver == NULL || - !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESHA1))) - { - SCLogDebug("disabling sha1 for flow"); - FileDisableSha1(pflow, STREAM_TOSERVER); - } - - /* see if this sgh requires us to consider file sha256 */ - if (!FileForceSha256() && (pflow->sgh_toserver == NULL || - !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESHA256))) - { - SCLogDebug("disabling sha256 for flow"); - FileDisableSha256(pflow, STREAM_TOSERVER); - } - - /* see if this sgh requires us to consider filesize */ - if (pflow->sgh_toserver == NULL || - !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) - { - SCLogDebug("disabling filesize for flow"); - FileDisableFilesize(pflow, STREAM_TOSERVER); - } } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && !(pflow->flags & FLOW_SGH_TOCLIENT)) { pflow->sgh_toclient = det_ctx->sgh; pflow->flags |= FLOW_SGH_TOCLIENT; - if (pflow->sgh_toclient == NULL || pflow->sgh_toclient->filestore_cnt == 0) { - FileDisableStoring(pflow, STREAM_TOCLIENT); - } - - /* check if this flow needs magic, if not disable it */ - if (!FileForceMagic() && (pflow->sgh_toclient == NULL || - !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC))) - { - SCLogDebug("disabling magic for flow"); - FileDisableMagic(pflow, STREAM_TOCLIENT); - } - - /* check if this flow needs md5, if not disable it */ - if (!FileForceMd5() && (pflow->sgh_toclient == NULL || - !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILEMD5))) - { - SCLogDebug("disabling md5 for flow"); - FileDisableMd5(pflow, STREAM_TOCLIENT); - } - - /* check if this flow needs sha1, if not disable it */ - if (!FileForceSha1() && (pflow->sgh_toclient == NULL || - !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESHA1))) - { - SCLogDebug("disabling sha1 for flow"); - FileDisableSha1(pflow, STREAM_TOCLIENT); - } - - /* check if this flow needs sha256, if not disable it */ - if (!FileForceSha256() && (pflow->sgh_toclient == NULL || - !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESHA256))) - { - SCLogDebug("disabling sha256 for flow"); - FileDisableSha256(pflow, STREAM_TOCLIENT); - } - - /* see if this sgh requires us to consider filesize */ - if (pflow->sgh_toclient == NULL || - !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) - { - SCLogDebug("disabling filesize for flow"); - FileDisableFilesize(pflow, STREAM_TOCLIENT); - } + DetectPostInspectFileFlagsUpdate(pflow, + pflow->sgh_toclient, STREAM_TOCLIENT); } } From 0e3112460959811d5e2e8a890d8f74e27bd0ebbd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 5 Oct 2016 10:12:27 +0200 Subject: [PATCH 2065/2553] detect: add util func for post-inspect tasks on first sgh --- src/detect.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/detect.c b/src/detect.c index 519394ab7b5f..e916ee5354e7 100644 --- a/src/detect.c +++ b/src/detect.c @@ -992,6 +992,26 @@ DetectPostInspectFileFlagsUpdate(Flow *pflow, const SigGroupHead *sgh, uint8_t d } } +static inline void +DetectPostInspectFirstSGH(const Packet *p, Flow *pflow, SigGroupHead *sgh) +{ + if ((p->flowflags & FLOW_PKT_TOSERVER) && !(pflow->flags & FLOW_SGH_TOSERVER)) { + /* first time we see this toserver sgh, store it */ + pflow->sgh_toserver = sgh; + pflow->flags |= FLOW_SGH_TOSERVER; + + DetectPostInspectFileFlagsUpdate(pflow, + pflow->sgh_toserver, STREAM_TOSERVER); + + } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && !(pflow->flags & FLOW_SGH_TOCLIENT)) { + pflow->sgh_toclient = sgh; + pflow->flags |= FLOW_SGH_TOCLIENT; + + DetectPostInspectFileFlagsUpdate(pflow, + pflow->sgh_toclient, STREAM_TOCLIENT); + } +} + /** * \brief Signature match function * @@ -1574,21 +1594,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh ; /* no-op */ } else if (!(sms_runflags & SMS_USE_FLOW_SGH)) { - if ((p->flowflags & FLOW_PKT_TOSERVER) && !(pflow->flags & FLOW_SGH_TOSERVER)) { - /* first time we see this toserver sgh, store it */ - pflow->sgh_toserver = det_ctx->sgh; - pflow->flags |= FLOW_SGH_TOSERVER; - - DetectPostInspectFileFlagsUpdate(pflow, - pflow->sgh_toserver, STREAM_TOSERVER); - - } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && !(pflow->flags & FLOW_SGH_TOCLIENT)) { - pflow->sgh_toclient = det_ctx->sgh; - pflow->flags |= FLOW_SGH_TOCLIENT; - - DetectPostInspectFileFlagsUpdate(pflow, - pflow->sgh_toclient, STREAM_TOCLIENT); - } + DetectPostInspectFirstSGH(p, pflow, det_ctx->sgh); } /* if we had no alerts that involved the smsgs, From 43aed70976762a9e80c0938603c5ccdf4974abde Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 5 Oct 2016 10:19:01 +0200 Subject: [PATCH 2066/2553] detect: during detection sgh is read only so turn into const --- src/detect-engine-state.c | 2 +- src/detect.c | 2 +- src/detect.h | 2 +- src/flow.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index a42ec82b17bc..46ff40c825f9 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -255,7 +255,7 @@ static void DeStateStoreFileNoMatchCnt(DetectEngineState *de_state, uint16_t fil return; } -static int DeStateStoreFilestoreSigsCantMatch(SigGroupHead *sgh, DetectEngineState *de_state, uint8_t direction) +static int DeStateStoreFilestoreSigsCantMatch(const SigGroupHead *sgh, DetectEngineState *de_state, uint8_t direction) { if (de_state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].filestore_cnt == sgh->filestore_cnt) return 1; diff --git a/src/detect.c b/src/detect.c index e916ee5354e7..bf26a97f81e3 100644 --- a/src/detect.c +++ b/src/detect.c @@ -993,7 +993,7 @@ DetectPostInspectFileFlagsUpdate(Flow *pflow, const SigGroupHead *sgh, uint8_t d } static inline void -DetectPostInspectFirstSGH(const Packet *p, Flow *pflow, SigGroupHead *sgh) +DetectPostInspectFirstSGH(const Packet *p, Flow *pflow, const SigGroupHead *sgh) { if ((p->flowflags & FLOW_PKT_TOSERVER) && !(pflow->flags & FLOW_SGH_TOSERVER)) { /* first time we see this toserver sgh, store it */ diff --git a/src/detect.h b/src/detect.h index a1b266ca644e..2a84d51f0a3d 100644 --- a/src/detect.h +++ b/src/detect.h @@ -893,7 +893,7 @@ typedef struct DetectEngineThreadCtx_ { SigIntId de_state_sig_array_len; uint8_t *de_state_sig_array; - struct SigGroupHead_ *sgh; + const struct SigGroupHead_ *sgh; SignatureNonPrefilterStore *non_pf_store_ptr; uint32_t non_pf_store_cnt; diff --git a/src/flow.h b/src/flow.h index 540ef9d9926b..044f61e1d3d8 100644 --- a/src/flow.h +++ b/src/flow.h @@ -404,10 +404,10 @@ typedef struct Flow_ /** toclient sgh for this flow. Only use when FLOW_SGH_TOCLIENT flow flag * has been set. */ - struct SigGroupHead_ *sgh_toclient; + const struct SigGroupHead_ *sgh_toclient; /** toserver sgh for this flow. Only use when FLOW_SGH_TOSERVER flow flag * has been set. */ - struct SigGroupHead_ *sgh_toserver; + const struct SigGroupHead_ *sgh_toserver; /* pointer to the var list */ GenericVar *flowvar; From f1046db113cda5aa3c2e092b8462beb5e0e5009c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 17:09:43 +0200 Subject: [PATCH 2067/2553] doc: fix header keywords layout --- doc/userguide/rules/header-keywords.rst | 35 ++++++++++++++----------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/doc/userguide/rules/header-keywords.rst b/doc/userguide/rules/header-keywords.rst index dc1c589f9ae5..b0bfa79a6061 100644 --- a/doc/userguide/rules/header-keywords.rst +++ b/doc/userguide/rules/header-keywords.rst @@ -5,7 +5,7 @@ IP-keywords ----------- ttl ---- +^^^ The ttl keyword is used to check for a specific IP time-to-live value in the header of a packet. The format is:: @@ -30,7 +30,7 @@ Example of the ttl keyword in a rule: .. image:: header-keywords/ttl.png Ipopts ------- +^^^^^^ With the ipopts keyword you can check if a specific ip option is set. Ipopts has to be used at the beginning of a rule. You can only @@ -52,7 +52,7 @@ Example of ipopts in a rule: .. image:: header-keywords/ipopts_rule.png sameip ------- +^^^^^^ Every packet has a source IP-address and a destination IP-address. It can be that the source IP is the same as the destination IP. With the @@ -67,7 +67,7 @@ Example of sameip in a rule: .. image:: header-keywords/sameip.png ip_proto --------- +^^^^^^^^ With the ip_proto keyword you can match on the IP protocol in the packet-header. You can use the name or the number of the protocol. @@ -93,7 +93,7 @@ The named variante of that example would be:: ip_proto:PIM Id --- +^^ With the id keyword, you can match on a specific IP ID value. The ID identifies each packet sent by a host and increments usually with one @@ -113,7 +113,7 @@ Example of id in a rule: .. image:: header-keywords/id.png Geoip ------ +^^^^^ The geoip keyword enables (you) to match on the source, destination or source and destination IP addresses of network traffic, and to see to @@ -136,8 +136,11 @@ direction you would like to match:: dest: if the destination matches with the given geoip. src: the source matches with the given geoip. +Fragments +--------- + Fragbits --------- +^^^^^^^^ With the fragbits keyword, you can check if the fragmentation and reserved bits are set in the IP header. The fragbits keyword should be @@ -170,7 +173,7 @@ Example of fragbits in a rule: .. image:: header-keywords/fragbits.png Fragoffset ----------- +^^^^^^^^^^ With the fragoffset keyword you can match on specific decimal values of the IP fragment offset field. If you would like to check the first @@ -198,7 +201,7 @@ TCP keywords ------------ seq ---- +^^^ The seq keyword can be used in a signature to check for a specific TCP sequence number. A sequence number is a number that is generated @@ -227,7 +230,7 @@ Example of seq in a packet (Wireshark): ack ---- +^^^ The ack is the acknowledgement of the receipt of all previous (data)-bytes send by the other side of the TCP-connection. In most @@ -248,8 +251,8 @@ Example of ack in a packet (Wireshark): .. image:: header-keywords/Wireshark_ack.png -Window ------- +window +^^^^^^ The window keyword is used to check for a specific TCP window size. The TCP window size is a mechanism that has control of the @@ -289,7 +292,7 @@ matched with corresponding ICMP-keywords. These are: the type, the code, the id and the sequence of a message. itype ------- +^^^^^ The itype keyword is for matching on a specific ICMP type (number). ICMP has several kinds of messages and uses codes to clarify those @@ -312,7 +315,7 @@ Example of the itype keyword in a signature: .. image:: header-keywords/icmp_type.png icode ------- +^^^^^ With the icode keyword you can match on a specific ICMP code. The code of a ICMP message clarifies the message. Together with the @@ -334,7 +337,7 @@ Example of the icode keyword in a rule: .. image:: header-keywords/icode.png icmp_id --------- +^^^^^^^ With the icmp_id keyword you can match on specific ICMP id-values. Every ICMP-packet gets an id when it is being send. At the moment the @@ -356,7 +359,7 @@ Example of the icmp_id keyword in a rule: .. image:: header-keywords/icmp_id.png icmp_seq ---------- +^^^^^^^^ You can use the icmp_seq keyword to check for a ICMP sequence number. ICMP messages all have sequence numbers. This can be useful (together From 08b875c03b973e28c423ad2ff42b7bea8b62ecea Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 17:15:32 +0200 Subject: [PATCH 2068/2553] doc: clean up fast_pattern --- .../rules/fast-pattern-explained.rst | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/doc/userguide/rules/fast-pattern-explained.rst b/doc/userguide/rules/fast-pattern-explained.rst index 86654e59542a..103d93a1c102 100644 --- a/doc/userguide/rules/fast-pattern-explained.rst +++ b/doc/userguide/rules/fast-pattern-explained.rst @@ -13,36 +13,7 @@ Be aware that if there are positive (i.e. non-negated) content matches, then negated content matches are ignored for fast pattern determination. Otherwise, negated content matches are considered. -Suricata 1.1.x - 1.4.x ----------------------- - -#. The longest (in terms of character/byte length) content match is - used as the fast pattern match. - -#. If multiple content matches qualify for the longest length, the one - with the highest character/byte diversity score ("Pattern - Strength") is used as the fast pattern match. See :ref:`Appendix C - ` for details on the algorithm - used to determine Pattern Strength. - -#. If multiple content matches qualify for the longest length and have - the same highest Pattern Strength, the buffer that has the *lower - "list_id"* is used as the fast pattern match. See :ref:`Appendix A - ` for the list_id of each - buffers/list. - -#. If multiple content matches qualify for the longest length and have - the same highest Pattern Strength, and have the same list_id - (i.e. are looking in the same buffer), then the one that comes - first (from left-to-right) in the rule is used as the fast pattern - match. - -It is worth noting that for content matches that have the same length -and Pattern Strength, regular 'content' matches take precedence over -matches that use the 'http_*' buffers. - -Suricata 2.0.x --------------- +The fast_pattern selection criteria are as follows: #. Suricata first identifies all content matches that have the highest "priority" that are used in the signature. The priority is based From e3b2d951002da4fd275a2f34dedcc5b7fca38f93 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 17:36:01 +0200 Subject: [PATCH 2069/2553] doc: add recent tls keywords --- doc/userguide/rules/tls-keywords.rst | 70 ++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/doc/userguide/rules/tls-keywords.rst b/doc/userguide/rules/tls-keywords.rst index 3700c21395a6..f37ef30603c6 100644 --- a/doc/userguide/rules/tls-keywords.rst +++ b/doc/userguide/rules/tls-keywords.rst @@ -3,6 +3,71 @@ SSL/TLS Keywords Suricata comes with several rule keywords to match on various properties of TLS/SSL handshake. Matches are string inclusion matches. +tls_cert_subject +---------------- + +Match TLS/SSL certificate Subject field. + +Examples:: + + tls_cert_subject; content:"CN=*.googleusercontent.com"; isdataat:!1,relative; + tls_cert_subject; content:"google.com"; nocase; pcre:"/google.com$/"; + +``tls_cert_subject`` is a 'Sticky buffer'. + +tls_cert_issuer +--------------- + +Match TLS/SSL certificate Issuer field. + +Examples:: + + tls_cert_issuer; content:"WoSign"; nocase; isdataat:!1,relative; + tls_cert_issuer; content:"StartCom"; nocase; pcre:"/StartCom$/"; + +``tls_cert_issuer`` is a 'Sticky buffer'. + +tls_cert_notbefore +------------------ + +Match on the NotBefore field in a certificate. + +Example:: + + alert tls any any -> any any (msg:"match cert NotBefore"; \ + tls_cert_notbefore:1998-05-01<>2008-05-01; sid:200005;) + +tls_cert_notafter +----------------- + +Match on the NotAfter field in a certificate. + +Example:: + + alert tls any any -> any any (msg:"match cert NotAfter"; \ + tls_cert_notafter:>2015; sid:200006;) + +tls_cert_expired +---------------- + +Match returns true if certificate is expired. It evaluates the validity date +from the certificate. + +Usage:: + + tls_cert_expired; + +tls_cert_valid +-------------- + +Match returns true if certificate is not expired. It only evaluates the +validity date. It does *not* do cert chain validation. It is the opposite +of ``tls_cert_expired``. + +Usage:: + + tls_cert_valid; + tls.version ----------- @@ -28,6 +93,8 @@ Support added in Suricata version 1.3. Case sensitve, can't use 'nocase'. +Legacy keyword. ``tls_cert_subject`` is the replacement. + tls.issuerdn ------------ @@ -44,6 +111,8 @@ Support added in Suricata version 1.3. Case sensitve, can't use 'nocase'. +Legacy keyword. ``tls_cert_issuer`` is the replacement. + tls.fingerprint --------------- @@ -77,3 +146,4 @@ are ``client_hello``, ``server_hello``, ``client_keyx``, ``server_keyx`` and ``u You can specify several states with ``|`` (OR) to check for any of the specified states. Negation support is not available yet, see https://redmine.openinfosecfoundation.org/issues/1231 + From 4126fd82a05038ef8aed18fe42b1570dee398f12 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 17:45:12 +0200 Subject: [PATCH 2070/2553] doc: small eve update: add dns --- doc/userguide/output/eve/eve-json-output.rst | 22 +++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/userguide/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst index 5c0b8195d006..104fc10b4643 100644 --- a/doc/userguide/output/eve/eve-json-output.rst +++ b/doc/userguide/output/eve/eve-json-output.rst @@ -162,6 +162,25 @@ Metadata:: ssh: yes # enable dumping of ssh fields smtp: yes # enable dumping of smtp fields +DNS +~~~ + +DNS records are logged one log record per query/answer record. + +YAML:: + + - dns: + # control logging of queries and answers + # default yes, no to disable + query: yes # enable logging of DNS queries + answer: yes # enable logging of DNS answers + # control which RR types are logged + # all enabled if custom not specified + #custom: [a, aaaa, cname, mx, ns, ptr, txt] + +To reduce verbosity the output can be filtered by supplying the record types +to be logged under ``custom``. + Multiple Logger Instances ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -225,4 +244,5 @@ For most output types, you can add multiple: enabled: yes filename: alert-json2.log -Except for drop and tls, for those only one logger instance is supported. +Except for ``drop`` for which only a single logger instance is supported. + From f4b165de945beaa9b03981c0b84880845ac587c3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 19:02:32 +0200 Subject: [PATCH 2071/2553] file: register filedata loggers before file This fixes the issue that 'stored' remained false even if the file was stored. Reported-by: Chris Wakelin --- src/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output.c b/src/output.c index d4dbb7da3f84..e53ffec24db7 100644 --- a/src/output.c +++ b/src/output.c @@ -1029,8 +1029,8 @@ void OutputRegisterRootLoggers(void) { OutputPacketLoggerRegister(); OutputTxLoggerRegister(); - OutputFileLoggerRegister(); OutputFiledataLoggerRegister(); + OutputFileLoggerRegister(); OutputStreamingLoggerRegister(); } From e95e6ccded36789ebcf73bb1a5a51cf21037cd75 Mon Sep 17 00:00:00 2001 From: Nicolas Thill Date: Fri, 5 Feb 2016 11:40:08 +0100 Subject: [PATCH 2072/2553] lua: add an SCPacketTimestamp function The SCPacketTimestamp function returns packet timestamps as 2 real numbers (seconds & microseconds). Example: local sec, usec = SCPacketTimestamp() Signed-off-by: Nicolas Thill --- src/util-lua-common.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/util-lua-common.c b/src/util-lua-common.c index 3c9e7718d9a8..74116fec3e7d 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -158,6 +158,21 @@ static int LuaCallbackPacketPayload(lua_State *luastate) return LuaCallbackPacketPayloadPushToStackFromPacket(luastate, p); } +/** \internal + * \brief fill lua stack with packet timestamp + * \param luastate the lua state + * \param p packet + * \retval cnt number of data items placed on the stack + * + * Places: seconds (number), microseconds (number) + */ +static int LuaCallbackTimestampPushToStack(lua_State *luastate, const struct timeval *ts) +{ + lua_pushnumber(luastate, (double)ts->tv_sec); + lua_pushnumber(luastate, (double)ts->tv_usec); + return 2; +} + /** \internal * \brief fill lua stack with header info * \param luastate the lua state @@ -174,6 +189,19 @@ static int LuaCallbackTimeStringPushToStackFromPacket(lua_State *luastate, const return 1; } +/** \internal + * \brief Wrapper for getting packet timestamp (as numbers) into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackPacketTimestamp(lua_State *luastate) +{ + const Packet *p = LuaStateGetPacket(luastate); + if (p == NULL) + return LuaCallbackError(luastate, "internal error: no packet"); + + return LuaCallbackTimestampPushToStack(luastate, &p->ts); +} + /** \internal * \brief Wrapper for getting tuple info into a lua script * \retval cnt number of items placed on the stack @@ -719,6 +747,8 @@ int LuaRegisterFunctions(lua_State *luastate) /* registration of the callbacks */ lua_pushcfunction(luastate, LuaCallbackPacketPayload); lua_setglobal(luastate, "SCPacketPayload"); + lua_pushcfunction(luastate, LuaCallbackPacketTimestamp); + lua_setglobal(luastate, "SCPacketTimestamp"); lua_pushcfunction(luastate, LuaCallbackPacketTimeString); lua_setglobal(luastate, "SCPacketTimeString"); lua_pushcfunction(luastate, LuaCallbackTuple); From 3750c1563219d271155eab217335f25ec1efd09a Mon Sep 17 00:00:00 2001 From: Nicolas Thill Date: Tue, 11 Oct 2016 17:16:33 +0200 Subject: [PATCH 2073/2553] doc: add SCPacketTimestamp Lua function Signed-off-by: Nicolas Thill --- doc/userguide/output/lua-output.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/userguide/output/lua-output.rst b/doc/userguide/output/lua-output.rst index 5c0f554c7b8a..d1193ae95d98 100644 --- a/doc/userguide/output/lua-output.rst +++ b/doc/userguide/output/lua-output.rst @@ -99,6 +99,18 @@ Initialize with: return needs end +SCPacketTimestamp +~~~~~~~~~~~~~~~~~ + +Get packets timestamp as 2 numbers: seconds & microseconds elapsed since +1970-01-01 00:00:00 UTC. + +:: + + function log(args) + local sec, usec = SCPacketTimestamp() + end + SCPacketTimeString ~~~~~~~~~~~~~~~~~~ From 69e1ff7ba7834585bb9f97d3d02d553856af0f6a Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 6 Oct 2016 14:10:13 +0900 Subject: [PATCH 2074/2553] stream-tcp: bypass encrypted when both side ready Suricata should not completely bypass a flow before both end of it have reached the stream depth or have reached a certain state. Justification is that suricata need the ACK to treat the other side so we can't really decide to cut only one side. --- src/stream-tcp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index f76444fc565b..c58dc1cd3fb4 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4656,6 +4656,11 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, (PKT_IS_TOCLIENT(p) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY))) { p->flags |= PKT_STREAM_NOPCAPLOG; + } + + if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && + (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) + { /* we can call bypass callback, if enabled */ if (StreamTcpBypassEnabled()) { PacketBypassCallback(p); From 4eca40ac34debc8584b5d08180b7521bd8d737c1 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 7 Oct 2016 16:51:22 +0900 Subject: [PATCH 2075/2553] app-layer-tls: stop detection if no reassembly It no-reassembly is asked in TLS conf then we can stop inspection after handshake and cause bypass to be triggered on the flow. --- src/app-layer-ssl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 79b0368d3e53..5980efd34afc 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -1213,6 +1213,13 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, handshake must be done */ ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; + /* Encrypted data, reassembly not asked, bypass asked, let's sacrifice + * heartbeat lke inspection to be able to be able to bypass the flow */ + if (ssl_config.no_reassemble == 1) { + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY); + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION); + } + break; case SSLV3_HANDSHAKE_PROTOCOL: From 18c9312380e04d4233862b772078211b25c1fb8d Mon Sep 17 00:00:00 2001 From: Thomas Andrejak Date: Mon, 16 May 2016 12:37:38 +0200 Subject: [PATCH 2076/2553] Add macro for TCP and UDP header access --- src/decode-icmpv4.h | 3 ++- src/decode-icmpv6.h | 1 + src/decode-tcp.h | 4 ++++ src/decode-udp.h | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/decode-icmpv4.h b/src/decode-icmpv4.h index b28dd259a6cd..d3ade18fac04 100644 --- a/src/decode-icmpv4.h +++ b/src/decode-icmpv4.h @@ -210,7 +210,8 @@ typedef struct ICMPV4Vars_ /** macro for icmpv4 "code" access */ #define ICMPV4_GET_CODE(p) (p)->icmpv4h->code /** macro for icmpv4 "csum" access */ -#define ICMPV4_GET_CSUM(p) (p)->icmpv4h->csum +#define ICMPV4_GET_RAW_CSUM(p) ntohs((p)->icmpv4h->checksum) +#define ICMPV4_GET_CSUM(p) (p)->icmpv4h->checksum /* If message is informational */ diff --git a/src/decode-icmpv6.h b/src/decode-icmpv6.h index a9a15ff72b1b..187b158bfcdb 100644 --- a/src/decode-icmpv6.h +++ b/src/decode-icmpv6.h @@ -80,6 +80,7 @@ /** macro for icmpv6 "code" access */ #define ICMPV6_GET_CODE(p) (p)->icmpv6h->code /** macro for icmpv6 "csum" access */ +#define ICMPV6_GET_RAW_CSUM(p) ntohs((p)->icmpv6h->csum) #define ICMPV6_GET_CSUM(p) (p)->icmpv6h->csum /** If message is informational */ diff --git a/src/decode-tcp.h b/src/decode-tcp.h index f9611e723db4..c544036bd46e 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -75,6 +75,7 @@ #define TCP_GET_RAW_WINDOW(tcph) ntohs((tcph)->th_win) #define TCP_GET_RAW_URG_POINTER(tcph) ntohs((tcph)->th_urp) +#define TCP_GET_RAW_SUM(tcph) ntohs((tcph)->th_sum) /** macro for getting the first timestamp from the packet in host order */ #define TCP_GET_TSVAL(p) ((p)->tcpvars.ts_val) @@ -98,6 +99,7 @@ #define TCP_GET_SACK_CNT(p) (TCP_HAS_SACK((p)) ? (((p)->tcpvars.sack.len - 2) / 8) : 0) #define TCP_GET_OFFSET(p) TCP_GET_RAW_OFFSET((p)->tcph) +#define TCP_GET_X2(p) TCP_GET_RAW_X2((p)->tcph) #define TCP_GET_HLEN(p) (TCP_GET_OFFSET((p)) << 2) #define TCP_GET_SRC_PORT(p) TCP_GET_RAW_SRC_PORT((p)->tcph) #define TCP_GET_DST_PORT(p) TCP_GET_RAW_DST_PORT((p)->tcph) @@ -105,6 +107,8 @@ #define TCP_GET_ACK(p) TCP_GET_RAW_ACK((p)->tcph) #define TCP_GET_WINDOW(p) TCP_GET_RAW_WINDOW((p)->tcph) #define TCP_GET_URG_POINTER(p) TCP_GET_RAW_URG_POINTER((p)->tcph) +#define TCP_GET_SUM(p) TCP_GET_RAW_SUM((p)->tcph) +#define TCP_GET_FLAGS(p) (p)->tcph->th_flags #define TCP_ISSET_FLAG_FIN(p) ((p)->tcph->th_flags & TH_FIN) #define TCP_ISSET_FLAG_SYN(p) ((p)->tcph->th_flags & TH_SYN) diff --git a/src/decode-udp.h b/src/decode-udp.h index 7bc0ec080510..027938f094eb 100644 --- a/src/decode-udp.h +++ b/src/decode-udp.h @@ -30,10 +30,12 @@ #define UDP_GET_RAW_LEN(udph) ntohs((udph)->uh_len) #define UDP_GET_RAW_SRC_PORT(udph) ntohs((udph)->uh_sport) #define UDP_GET_RAW_DST_PORT(udph) ntohs((udph)->uh_dport) +#define UDP_GET_RAW_SUM(udph) ntohs((udph)->uh_sum) #define UDP_GET_LEN(p) UDP_GET_RAW_LEN(p->udph) #define UDP_GET_SRC_PORT(p) UDP_GET_RAW_SRC_PORT(p->udph) #define UDP_GET_DST_PORT(p) UDP_GET_RAW_DST_PORT(p->udph) +#define UDP_GET_SUM(p) UDP_GET_RAW_SUM(p->udph) /* UDP header structure */ typedef struct UDPHdr_ From 4d4a3d0b8f2ab729be8fbd65ff40c3cd0cf77077 Mon Sep 17 00:00:00 2001 From: Thomas Andrejak Date: Mon, 16 May 2016 12:35:17 +0200 Subject: [PATCH 2077/2553] prelude: Add log when failed to create assessment or impact object --- src/alert-prelude.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index 8fd9b7ba64da..d480708b7b05 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -194,12 +194,18 @@ static int EventToImpact(const PacketAlert *pa, const Packet *p, idmef_alert_t * SCEnter(); ret = idmef_alert_new_assessment(alert, &assessment); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating assessment: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); + } ret = idmef_assessment_new_impact(assessment, &impact); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating assessment impact: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); + } if ( (unsigned int)pa->s->prio < mid_priority ) severity = IDMEF_IMPACT_SEVERITY_HIGH; From b1c1699699298b91386c9d47cbe7291bcda75e78 Mon Sep 17 00:00:00 2001 From: Thomas Andrejak Date: Mon, 16 May 2016 12:36:29 +0200 Subject: [PATCH 2078/2553] prelude: Add other actions than just ACTION_DROP when packet drop --- src/alert-prelude.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index d480708b7b05..fdc50eb21e5a 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -221,7 +221,10 @@ static int EventToImpact(const PacketAlert *pa, const Packet *p, idmef_alert_t * idmef_impact_set_severity(impact, severity); - if (PACKET_TEST_ACTION(p, ACTION_DROP)) { + if (PACKET_TEST_ACTION(p, ACTION_DROP) || + PACKET_TEST_ACTION(p, ACTION_REJECT) || + PACKET_TEST_ACTION(p, ACTION_REJECT_DST) || + PACKET_TEST_ACTION(p, ACTION_REJECT_BOTH) ) { idmef_action_t *action; ret = idmef_action_new(&action); From e33060cee097f57f20614cc907c53ce178d384d2 Mon Sep 17 00:00:00 2001 From: Thomas Andrejak Date: Mon, 16 May 2016 12:55:32 +0200 Subject: [PATCH 2079/2553] prelude: coding style, it's better to use macro --- src/alert-prelude.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index fdc50eb21e5a..1b844ee5baa4 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -492,28 +492,27 @@ static int PacketToData(const Packet *p, const PacketAlert *pa, idmef_alert_t *a PacketToDataV6(p, pa, alert); if ( PKT_IS_TCP(p) ) { - AddIntData(alert, "tcp_seq", ntohl(p->tcph->th_seq)); - AddIntData(alert, "tcp_ack", ntohl(p->tcph->th_ack)); + AddIntData(alert, "tcp_seq", TCP_GET_SEQ(p)); + AddIntData(alert, "tcp_ack", TCP_GET_ACK(p)); - AddIntData(alert, "tcp_off", TCP_GET_RAW_OFFSET(p->tcph)); - AddIntData(alert, "tcp_res", TCP_GET_RAW_X2(p->tcph)); - AddIntData(alert, "tcp_flags", p->tcph->th_flags); - - AddIntData(alert, "tcp_win", ntohs(p->tcph->th_win)); - AddIntData(alert, "tcp_sum", ntohs(p->tcph->th_sum)); - AddIntData(alert, "tcp_urp", ntohs(p->tcph->th_urp)); + AddIntData(alert, "tcp_off", TCP_GET_OFFSET(p)); + AddIntData(alert, "tcp_res", TCP_GET_X2(p)); + AddIntData(alert, "tcp_flags", TCP_GET_FLAGS(p)); + AddIntData(alert, "tcp_win", TCP_GET_WINDOW(p)); + AddIntData(alert, "tcp_sum", TCP_GET_SUM(p)); + AddIntData(alert, "tcp_urp", TCP_GET_URG_POINTER(p)); } else if ( PKT_IS_UDP(p) ) { - AddIntData(alert, "udp_len", ntohs(p->udph->uh_len)); - AddIntData(alert, "udp_sum", ntohs(p->udph->uh_sum)); + AddIntData(alert, "udp_len", UDP_GET_LEN(p)); + AddIntData(alert, "udp_sum", UDP_GET_SUM(p)); } else if ( PKT_IS_ICMPV4(p) ) { - AddIntData(alert, "icmp_type", p->icmpv4h->type); - AddIntData(alert, "icmp_code", p->icmpv4h->code); - AddIntData(alert, "icmp_sum", ntohs(p->icmpv4h->checksum)); + AddIntData(alert, "icmp_type", ICMPV4_GET_TYPE(p)); + AddIntData(alert, "icmp_code", ICMPV4_GET_CODE(p)); + AddIntData(alert, "icmp_sum", ICMPV4_GET_RAW_CSUM(p)); } } From 671320aab8c2151a63a9e4f052f7e800c8ad6acc Mon Sep 17 00:00:00 2001 From: Thomas ANDREJAK Date: Thu, 7 Apr 2016 22:54:56 +0200 Subject: [PATCH 2080/2553] prelude: update URL --- m4/libprelude.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/m4/libprelude.m4 b/m4/libprelude.m4 index 07eebe0ca93e..64b6478e3970 100644 --- a/m4/libprelude.m4 +++ b/m4/libprelude.m4 @@ -101,7 +101,7 @@ main () prelude_check_version(NULL) ); printf("*** You need a version of LIBPRELUDE newer than %s. The latest version of\n", "$min_libprelude_version" ); - printf("*** LIBPRELUDE is always available from http://www.prelude-ids.com/development/download/\n"); + printf("*** LIBPRELUDE is always available from http://www.prelude-siem.com/index.php/en/community/download\n"); printf("*** \n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the libprelude-config shell script is\n"); From dcce2251023a6bf404217623ab264ef6d95b3157 Mon Sep 17 00:00:00 2001 From: Thomas Andrejak Date: Mon, 16 May 2016 12:56:12 +0200 Subject: [PATCH 2081/2553] prelude: add missing TCP header to additional data --- src/alert-prelude.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index 1b844ee5baa4..f8045b3a253a 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -502,6 +502,22 @@ static int PacketToData(const Packet *p, const PacketAlert *pa, idmef_alert_t *a AddIntData(alert, "tcp_win", TCP_GET_WINDOW(p)); AddIntData(alert, "tcp_sum", TCP_GET_SUM(p)); AddIntData(alert, "tcp_urp", TCP_GET_URG_POINTER(p)); + if (p->tcpvars.ts_val != NULL) { + AddIntData(alert, "tcp_tsval", TCP_GET_TSVAL(p)); + } + if (p->tcpvars.ts_ecr != NULL) { + AddIntData(alert, "tcp_tsecr", TCP_GET_TSECR(p)); + } + if (p->tcph != NULL) { + AddIntData(alert, "tcp_wscale", TCP_GET_WSCALE(p)); + } + if (TCP_HAS_SACKOK(p)) { + AddIntData(alert, "tcp_sackok", TCP_GET_SACKOK(p)); + } + if (TCP_HAS_SACK(p)) { + AddIntData(alert, "tcp_sack_cnt", TCP_GET_SACK_CNT(p)); + } + AddIntData(alert, "tcp_hlen", TCP_GET_HLEN(p)); } else if ( PKT_IS_UDP(p) ) { From c17402fdcb95be613e23c4e0c7cf3e77a5832155 Mon Sep 17 00:00:00 2001 From: Thomas Andrejak Date: Mon, 16 May 2016 12:56:50 +0200 Subject: [PATCH 2082/2553] prelude: add IPv6 support --- src/alert-prelude.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index f8045b3a253a..2526320ac344 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -463,7 +463,17 @@ static int PacketToDataV4(const Packet *p, const PacketAlert *pa, idmef_alert_t */ static int PacketToDataV6(const Packet *p, const PacketAlert *pa, idmef_alert_t *alert) { - return 0; + SCEnter(); + + AddIntData(alert, "ip_ver", IPV6_GET_VER(p)); + AddIntData(alert, "ip_class", IPV6_GET_CLASS(p)); + AddIntData(alert, "ip_flow", IPV6_GET_FLOW(p)); + AddIntData(alert, "ip_nh", IPV6_GET_NH(p)); + AddIntData(alert, "ip_plen", IPV6_GET_PLEN(p)); + AddIntData(alert, "ip_hlim", IPV6_GET_HLIM(p)); + AddIntData(alert, "ip_proto", IPV6_GET_L4PROTO(p)); + + SCReturnInt(0); } @@ -531,6 +541,12 @@ static int PacketToData(const Packet *p, const PacketAlert *pa, idmef_alert_t *a AddIntData(alert, "icmp_sum", ICMPV4_GET_RAW_CSUM(p)); } + + else if ( PKT_IS_ICMPV6(p) ) { + AddIntData(alert, "icmp_type", ICMPV6_GET_TYPE(p)); + AddIntData(alert, "icmp_code", ICMPV6_GET_CODE(p)); + AddIntData(alert, "icmp_csum", ICMPV6_GET_RAW_CSUM(p)); + } } if (ctx->log_packet_content) From b789d2ae3d13cdb0d0bf6a5e40eafa96b82ced04 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 12 Oct 2016 11:21:28 +0200 Subject: [PATCH 2083/2553] tls: change 'no-reassemble' option to default off This option was broken so there should be no visible change to actual deployments. --- src/app-layer-ssl.c | 12 +++++------- suricata.yaml.in | 4 ++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 5980efd34afc..6fcfb2997983 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -79,6 +79,9 @@ SCEnumCharMap tls_decoder_event_table[ ] = { { NULL, -1 }, }; +/* by default we keep tracking */ +#define SSL_CONFIG_DEFAULT_NOREASSEMBLE 0 + typedef struct SslConfig_ { int no_reassemble; } SslConfig; @@ -1807,10 +1810,10 @@ void RegisterSSLParsers(void) /* Get the value of no reassembly option from the config file */ if (ConfGetNode("app-layer.protocols.tls.no-reassemble") == NULL) { if (ConfGetBool("tls.no-reassemble", &ssl_config.no_reassemble) != 1) - ssl_config.no_reassemble = 1; + ssl_config.no_reassemble = SSL_CONFIG_DEFAULT_NOREASSEMBLE; } else { if (ConfGetBool("app-layer.protocols.tls.no-reassemble", &ssl_config.no_reassemble) != 1) - ssl_config.no_reassemble = 1; + ssl_config.no_reassemble = SSL_CONFIG_DEFAULT_NOREASSEMBLE; } } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" @@ -1820,11 +1823,6 @@ void RegisterSSLParsers(void) #ifdef UNITTESTS AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_TLS, SSLParserRegisterTests); #endif - - /* Get the value of no reassembly option from the config file */ - if (ConfGetBool("tls.no-reassemble", &ssl_config.no_reassemble) != 1) - ssl_config.no_reassemble = 1; - return; } diff --git a/suricata.yaml.in b/suricata.yaml.in index 74b73d7f1d8b..6fa50fea232b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -654,6 +654,10 @@ app-layer: detection-ports: dp: 443 + # Completely stop processing TLS/SSL session after the handshake + # completed. If bypass is enabled this will also trigger flow + # bypass. If disabled (the default), TLS/SSL session is still + # tracked for Heartbleed and other anomalies. #no-reassemble: yes dcerpc: enabled: yes From c6134e007e0785bc9a3ef5b524fd03adf7fa2c09 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 12 Oct 2016 12:30:19 +0200 Subject: [PATCH 2084/2553] doc: app-layer tls including no-reassemble --- doc/userguide/configuration/suricata-yaml.rst | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index 9701df415634..ab04dc1d0097 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -2133,6 +2133,47 @@ see :doc:`../performance/packet-profiling`. Application layers ------------------ +SSL/TLS +~~~~~~~ + +SSL/TLS parsers track encrypted SSLv2, SSLv3, TLSv1, TLSv1.1 and TLSv1.2 +sessions. + +Protocol detection is done using patterns and a probing parser running +on only TCP/443 by default. The pattern based protocol detection is +port independent. + +:: + + tls: + enabled: yes + detection-ports: + dp: 443 + + # Completely stop processing TLS/SSL session after the handshake + # completed. If bypass is enabled this will also trigger flow + # bypass. If disabled (the default), TLS/SSL session is still + # tracked for Heartbleed and other anomalies. + #no-reassemble: yes + +Encrypted traffic +^^^^^^^^^^^^^^^^^ + +There is no decryption of encrypted traffic, so once the handshake is complete +continued tracking of the session is of limited use. The ``no-reassemble`` +option controls the behaviour after the handshake. + +If ``no-reassemble`` is set to ``true``, all processing of this session is +stopped. No further parsing and inspection happens. If ``bypass`` is enabled +this will lead to the flow being bypassed, either inside Suricata or by the +capture method if it supports it. + +If ``no-reassemble`` is set to ``false``, which is the default, Suricata will +continue to track the SSL/TLS session. Inspection will be limited, as +``content`` inspection will still be disabled. There is no point in doing +pattern matching on traffic known to be encrypted. Inspection for (encrypted) +Heartbleed and other protocol anomalies still happens. + Modbus ~~~~~~ From 8347aa01fa9d32c364b8b72163e921f32ce01cbc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 10 Oct 2016 11:18:06 +0200 Subject: [PATCH 2085/2553] app-layer: clean up counters registration --- src/app-layer.c | 82 +++++++++++++++------------------------------- src/flow-private.h | 2 ++ 2 files changed, 28 insertions(+), 56 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 3f5ed89f0890..5a2b12d70888 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -68,14 +68,21 @@ struct AppLayerThreadCtx_ { #endif }; +#define MAX_COUNTER_SIZE 64 +typedef struct AppLayerCounterNames_ { + char name[MAX_COUNTER_SIZE]; + char tx_name[MAX_COUNTER_SIZE]; +} AppLayerCounterNames; + typedef struct AppLayerCounters_ { - char *name; - char *tx_name; uint16_t counter_id; uint16_t counter_tx_id; } AppLayerCounters; -AppLayerCounters applayer_counters[FLOW_PROTO_MAX][ALPROTO_MAX]; +/* counter names. Only used at init. */ +AppLayerCounterNames applayer_counter_names[FLOW_PROTO_APPLAYER_MAX][ALPROTO_MAX]; +/* counter id's. Used that runtime. */ +AppLayerCounters applayer_counters[FLOW_PROTO_APPLAYER_MAX][ALPROTO_MAX]; void AppLayerSetupCounters(); void AppLayerDeSetupCounters(); @@ -707,48 +714,29 @@ void AppLayerSetupCounters() for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { if (alprotos[alproto] == 1) { - char *str = "app_layer.flow."; - char *tx_str = "app_layer.tx."; - char *alproto_str = AppLayerGetProtoName(alproto); - int alproto_len = strlen(alproto_str) + 1; + const char *str = "app_layer.flow."; + const char *tx_str = "app_layer.tx."; + const char *alproto_str = AppLayerGetProtoName(alproto); uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); - size_t size; if (AppLayerParserProtoIsRegistered(ipprotos[ipproto], alproto) && AppLayerParserProtoIsRegistered(other_ipproto, alproto)) { - size = strlen(str) + alproto_len + strlen(ipproto_suffix); - applayer_counters[ipproto_map][alproto].name = SCMalloc(size); - if (applayer_counters[ipproto_map][alproto].name == NULL) { - return; - } - - snprintf(applayer_counters[ipproto_map][alproto].name, size, + snprintf(applayer_counter_names[ipproto_map][alproto].name, + sizeof(applayer_counter_names[ipproto_map][alproto].name), "%s%s%s", str, alproto_str, ipproto_suffix); if (AppLayerParserProtocolIsTxAware(ipprotos[ipproto], alproto)) { - size = strlen(tx_str) + alproto_len + strlen(ipproto_suffix); - applayer_counters[ipproto_map][alproto].tx_name = SCMalloc(size); - if (applayer_counters[ipproto_map][alproto].tx_name == NULL) { - return; - } - snprintf(applayer_counters[ipproto_map][alproto].tx_name, size, + snprintf(applayer_counter_names[ipproto_map][alproto].tx_name, + sizeof(applayer_counter_names[ipproto_map][alproto].tx_name), "%s%s%s", tx_str, alproto_str, ipproto_suffix); } } else { - size = strlen(str) + alproto_len; - applayer_counters[ipproto_map][alproto].name = SCMalloc(size); - if (applayer_counters[ipproto_map][alproto].name == NULL) { - return; - } - snprintf(applayer_counters[ipproto_map][alproto].name, size, + snprintf(applayer_counter_names[ipproto_map][alproto].name, + sizeof(applayer_counter_names[ipproto_map][alproto].name), "%s%s", str, alproto_str); if (AppLayerParserProtocolIsTxAware(ipprotos[ipproto], alproto)) { - size = strlen(tx_str) + alproto_len; - applayer_counters[ipproto_map][alproto].tx_name = SCMalloc(size); - if (applayer_counters[ipproto_map][alproto].tx_name == NULL) { - return; - } - snprintf(applayer_counters[ipproto_map][alproto].tx_name, size, + snprintf(applayer_counter_names[ipproto_map][alproto].tx_name, + sizeof(applayer_counter_names[ipproto_map][alproto].tx_name), "%s%s", tx_str, alproto_str); } } @@ -771,11 +759,11 @@ void AppLayerRegisterThreadCounters(ThreadVars *tv) if (alprotos[alproto] == 1) { uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); applayer_counters[ipproto_map][alproto].counter_id = - StatsRegisterCounter(applayer_counters[ipproto_map][alproto].name, tv); + StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); if (AppLayerParserProtocolIsTxAware(ipprotos[ipproto], alproto)) { applayer_counters[ipproto_map][alproto].counter_tx_id = - StatsRegisterCounter(applayer_counters[ipproto_map][alproto].tx_name, tv); + StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].tx_name, tv); } } } @@ -784,28 +772,10 @@ void AppLayerRegisterThreadCounters(ThreadVars *tv) void AppLayerDeSetupCounters() { - uint8_t ipprotos[] = { IPPROTO_TCP, IPPROTO_UDP }; - uint8_t ipproto; - AppProto alproto; - AppProto alprotos[ALPROTO_MAX]; - - AppLayerProtoDetectSupportedAppProtocols(alprotos); - - for (ipproto = 0; ipproto < IPPROTOS_MAX; ipproto++) { - for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { - if (alprotos[alproto] == 1) { - if (applayer_counters[FlowGetProtoMapping(ipprotos[ipproto])][alproto].name) { - SCFree(applayer_counters[FlowGetProtoMapping(ipprotos[ipproto])][alproto].name); - applayer_counters[FlowGetProtoMapping(ipprotos[ipproto])][alproto].name = NULL; - } - } - if (applayer_counters[FlowGetProtoMapping(ipproto)][alproto].tx_name) { - SCFree(applayer_counters[FlowGetProtoMapping(ipproto)][alproto].tx_name); - applayer_counters[FlowGetProtoMapping(ipproto)][alproto].tx_name = NULL; - } - } - } + memset(applayer_counter_names, 0, sizeof(applayer_counter_names)); + memset(applayer_counters, 0, sizeof(applayer_counters)); } + /***** Unittests *****/ #ifdef UNITTESTS diff --git a/src/flow-private.h b/src/flow-private.h index 19b81b44848a..543170892f5a 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -74,6 +74,8 @@ enum { /* should be last */ FLOW_PROTO_MAX, }; +/* max used in app-layer (counters) */ +#define FLOW_PROTO_APPLAYER_MAX FLOW_PROTO_UDP + 1 /* * Variables From 6022fa44a50520883a4769e1a1ab5ddbb354afd7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Oct 2016 10:22:35 +0200 Subject: [PATCH 2086/2553] proto detect: TCP cleanup Split function into multiple smaller ones. --- src/app-layer.c | 705 ++++++++++++++++++-------------- src/detect-app-layer-protocol.c | 17 +- 2 files changed, 396 insertions(+), 326 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 5a2b12d70888..29c0346cfcd9 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -115,29 +115,163 @@ void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step) } } -int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - Packet *p, Flow *f, - TcpSession *ssn, TcpStream *stream, - uint8_t *data, uint32_t data_len, - uint8_t flags) +/* See if we're going to have to give up: + * + * If we're getting a lot of data in one direction and the + * proto for this direction is unknown, proto detect will + * hold up segments in the segment list in the stream. + * They are held so that if we detect the protocol on the + * opposing stream, we can still parse this side of the stream + * as well. However, some sessions are very unbalanced. FTP + * data channels, large PUT/POST request and many others, can + * lead to cases where we would have to store many megabytes + * worth of segments before we see the opposing stream. This + * leads to risks of resource starvation. + * + * Here a cutoff point is enforced. If we've stored 100k in + * one direction and we've seen no data in the other direction, + * we give up. + * + * Giving up means we disable applayer an set an applayer event + */ +static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet *p) { - SCEnter(); + uint32_t size_ts = ssn->client.last_ack - ssn->client.isn - 1; + uint32_t size_tc = ssn->server.last_ack - ssn->server.isn - 1; + SCLogDebug("size_ts %u, size_tc %u", size_ts, size_tc); - DEBUG_ASSERT_FLOW_LOCKED(f); +#ifdef DEBUG_VALIDATION + if (!(ssn->client.flags & STREAMTCP_STREAM_FLAG_GAP)) + BUG_ON(size_ts > 1000000UL); + if (!(ssn->server.flags & STREAMTCP_STREAM_FLAG_GAP)) + BUG_ON(size_tc > 1000000UL); +#endif /* DEBUG_VALIDATION */ - AppLayerThreadCtx *app_tctx = ra_ctx->app_tctx; - AppProto *alproto; - AppProto *alproto_otherdir; - uint8_t dir; - uint32_t data_al_so_far; - int r = 0; - uint8_t first_data_dir; + if (ProtoDetectDone(f, ssn, STREAM_TOSERVER) && + ProtoDetectDone(f, ssn, STREAM_TOCLIENT)) + { + DisableAppLayer(f); + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + + } else if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && + size_ts > 100000 && size_tc == 0) + { + DisableAppLayer(f); + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); + + } else if (FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && + size_tc > 100000 && size_ts == 0) + { + DisableAppLayer(f); + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); + + /* little data in ts direction, pp done, pm not done (max + * depth not reached), ts direction done, lots of data in + * tc direction. */ + } else if (size_tc > 100000 && + FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && + FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) + { + DisableAppLayer(f); + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); + + /* little data in tc direction, pp done, pm not done (max + * depth not reached), tc direction done, lots of data in + * ts direction. */ + } else if (size_ts > 100000 && + FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && !(FLOW_IS_PM_DONE(f, STREAM_TOCLIENT)) && + FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) + { + DisableAppLayer(f); + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); + + /* in case of really low TS data (e.g. 4 bytes) we can have + * the PP complete, PM not complete (depth not reached) and + * the TC side also not recognized (proto unknown) */ + } else if (size_tc > 100000 && + FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && + (!FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && !FLOW_IS_PP_DONE(f, STREAM_TOCLIENT))) + { + DisableAppLayer(f); + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); + } +} - SCLogDebug("data_len %u flags %02X", data_len, flags); - if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) { - SCLogDebug("STREAMTCP_FLAG_APP_LAYER_DISABLED is set"); - goto end; +/** \todo modifying p this way seems too hacky */ +static int TCPProtoDetectTriggerOpposingSide(ThreadVars *tv, + TcpReassemblyThreadCtx *ra_ctx, + Packet *p, TcpSession *ssn, TcpStream *stream, + uint8_t flags) +{ + TcpStream *opposing_stream = NULL; + if (stream == &ssn->client) { + opposing_stream = &ssn->server; + if (StreamTcpInlineMode()) { + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + } else { + p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_TOSERVER; + } + } else { + opposing_stream = &ssn->client; + if (StreamTcpInlineMode()) { + p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_TOSERVER; + } else { + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + } + } + + int ret = 0; + /* if the opposing side is not going to work, then + * we just have to give up. */ + if (opposing_stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) + ret = -1; + else + ret = StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, + opposing_stream, p); + if (stream == &ssn->client) { + if (StreamTcpInlineMode()) { + p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_TOSERVER; + } else { + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + } + } else { + if (StreamTcpInlineMode()) { + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + } else { + p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_TOSERVER; + } } + return ret; +} + +/** \todo data const */ +static int TCPProtoDetect(ThreadVars *tv, + TcpReassemblyThreadCtx *ra_ctx, AppLayerThreadCtx *app_tctx, + Packet *p, Flow *f, TcpSession *ssn, TcpStream *stream, + uint8_t *data, uint32_t data_len, uint8_t flags) +{ + uint32_t data_al_so_far = 0; + AppProto *alproto; + AppProto *alproto_otherdir; + int dir; if (flags & STREAM_TOSERVER) { alproto = &f->alproto_ts; @@ -148,328 +282,263 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, alproto_otherdir = &f->alproto_ts; dir = 1; } + if (data_len > 0) + data_al_so_far = f->data_al_so_far[dir]; - /* if we don't know the proto yet and we have received a stream - * initializer message, we run proto detection. - * We receive 2 stream init msgs (one for each direction) but we - * only run the proto detection once. */ - if (*alproto == ALPROTO_UNKNOWN && (flags & STREAM_GAP)) { - StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); - StreamTcpSetSessionNoReassemblyFlag(ssn, dir); - SCLogDebug("ALPROTO_UNKNOWN flow %p, due to GAP in stream start", f); - } else if (*alproto == ALPROTO_UNKNOWN && (flags & STREAM_START)) { - if (data_len == 0) - data_al_so_far = 0; - else - data_al_so_far = f->data_al_so_far[dir]; - - SCLogDebug("Stream initializer (len %" PRIu32 ")", data_len); + SCLogDebug("Stream initializer (len %" PRIu32 ")", data_len); #ifdef PRINT - if (data_len > 0) { - printf("=> Init Stream Data (app layer) -- start %s%s\n", - flags & STREAM_TOCLIENT ? "toclient" : "", - flags & STREAM_TOSERVER ? "toserver" : ""); - PrintRawDataFp(stdout, data, data_len); - printf("=> Init Stream Data -- end\n"); - } + if (data_len > 0) { + printf("=> Init Stream Data (app layer) -- start %s%s\n", + flags & STREAM_TOCLIENT ? "toclient" : "", + flags & STREAM_TOSERVER ? "toserver" : ""); + PrintRawDataFp(stdout, data, data_len); + printf("=> Init Stream Data -- end\n"); + } #endif - PACKET_PROFILING_APP_PD_START(app_tctx); - *alproto = AppLayerProtoDetectGetProto(app_tctx->alpd_tctx, - f, - data, data_len, - IPPROTO_TCP, flags); - PACKET_PROFILING_APP_PD_END(app_tctx); - - if (*alproto != ALPROTO_UNKNOWN) { - if (*alproto_otherdir != ALPROTO_UNKNOWN && *alproto_otherdir != *alproto) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS); - /* it indicates some data has already been sent to the parser */ - if (ssn->data_first_seen_dir == APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { + PACKET_PROFILING_APP_PD_START(app_tctx); + *alproto = AppLayerProtoDetectGetProto(app_tctx->alpd_tctx, + f, data, data_len, + IPPROTO_TCP, flags); + PACKET_PROFILING_APP_PD_END(app_tctx); + + if (*alproto != ALPROTO_UNKNOWN) { + if (*alproto_otherdir != ALPROTO_UNKNOWN && *alproto_otherdir != *alproto) { + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS); + /* it indicates some data has already been sent to the parser */ + if (ssn->data_first_seen_dir == APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { + f->alproto = *alproto = *alproto_otherdir; + } else { + if (flags & STREAM_TOCLIENT) + f->alproto = *alproto_otherdir = *alproto; + else f->alproto = *alproto = *alproto_otherdir; - } else { - if (flags & STREAM_TOCLIENT) - f->alproto = *alproto_otherdir = *alproto; - else - f->alproto = *alproto = *alproto_otherdir; - } } + } + + f->alproto = *alproto; + StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); + TcpSessionSetReassemblyDepth(ssn, + AppLayerParserGetStreamDepth(f->proto, *alproto)); - f->alproto = *alproto; - StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); - TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, *alproto)); + /* account flow if we have both sides */ + if (*alproto_otherdir != ALPROTO_UNKNOWN) { + AppLayerIncFlowCounter(tv, f); + } - /* account flow if we have both side */ - if (*alproto_otherdir != ALPROTO_UNKNOWN) { - AppLayerIncFlowCounter(tv, f); + /* if we have seen data from the other direction first, send + * data for that direction first to the parser. This shouldn't + * be an issue, since each stream processing happens + * independently of the other stream direction. At this point of + * call, you need to know that this function's already being + * called by the very same StreamReassembly() function that we + * will now call shortly for the opposing direction. */ + if ((ssn->data_first_seen_dir & (STREAM_TOSERVER | STREAM_TOCLIENT)) && + !(flags & ssn->data_first_seen_dir)) + { + if (TCPProtoDetectTriggerOpposingSide(tv, ra_ctx, + p, ssn, stream, flags) != 0) + { + DisableAppLayer(f); + goto failure; } + } - /* if we have seen data from the other direction first, send - * data for that direction first to the parser. This shouldn't - * be an issue, since each stream processing happens - * independently of the other stream direction. At this point of - * call, you need to know that this function's already being - * called by the very same StreamReassembly() function that we - * will now call shortly for the opposing direction. */ - if ((ssn->data_first_seen_dir & (STREAM_TOSERVER | STREAM_TOCLIENT)) && - !(flags & ssn->data_first_seen_dir)) { - TcpStream *opposing_stream = NULL; - if (stream == &ssn->client) { - opposing_stream = &ssn->server; - if (StreamTcpInlineMode()) { - p->flowflags &= ~FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_TOCLIENT; - } else { - p->flowflags &= ~FLOW_PKT_TOCLIENT; - p->flowflags |= FLOW_PKT_TOSERVER; - } - } else { - opposing_stream = &ssn->client; - if (StreamTcpInlineMode()) { - p->flowflags &= ~FLOW_PKT_TOCLIENT; - p->flowflags |= FLOW_PKT_TOSERVER; - } else { - p->flowflags &= ~FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_TOCLIENT; - } - } + /* if the parser operates such that it needs to see data from + * a particular direction first, we check if we have seen + * data from that direction first for the flow. IF it is not + * the same, we set an event and exit. + * + * \todo We need to figure out a more robust solution for this, + * as this can lead to easy evasion tactics, where the + * attackeer can first send some dummy data in the wrong + * direction first to mislead our proto detection process. + * While doing this we need to update the parsers as well, + * since the parsers must be robust to see such wrong + * direction data. + * Either ways the moment we see the + * APPLAYER_WRONG_DIRECTION_FIRST_DATA event set for the + * flow, it shows something's fishy. + */ + if (ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { + uint8_t first_data_dir; + first_data_dir = AppLayerParserGetFirstDataDir(f->proto, *alproto); + + if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) { + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_WRONG_DIRECTION_FIRST_DATA); + DisableAppLayer(f); + /* Set a value that is neither STREAM_TOSERVER, nor STREAM_TOCLIENT */ + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + goto failure; + } + /* This can happen if the current direction is not the + * right direction, and the data from the other(also + * the right direction) direction is available to be sent + * to the app layer, but it is not ack'ed yet and hence + * the forced call to STreamTcpAppLayerReassemble still + * hasn't managed to send data from the other direction + * to the app layer. */ + if (first_data_dir && !(first_data_dir & flags)) { + BUG_ON(*alproto_otherdir != ALPROTO_UNKNOWN); + FlowCleanupAppLayer(f); + f->alproto = *alproto = ALPROTO_UNKNOWN; + StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream); + FLOW_RESET_PP_DONE(f, flags); + FLOW_RESET_PM_DONE(f, flags); + goto failure; + } + } - int ret = 0; - /* if the opposing side is not going to work, then - * we just have to give up. */ - if (opposing_stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) - ret = -1; - else - ret = StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, - opposing_stream, p); - if (stream == &ssn->client) { - if (StreamTcpInlineMode()) { - p->flowflags &= ~FLOW_PKT_TOCLIENT; - p->flowflags |= FLOW_PKT_TOSERVER; - } else { - p->flowflags &= ~FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_TOCLIENT; - } - } else { - if (StreamTcpInlineMode()) { - p->flowflags &= ~FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_TOCLIENT; - } else { - p->flowflags &= ~FLOW_PKT_TOCLIENT; - p->flowflags |= FLOW_PKT_TOSERVER; - } - } - if (ret < 0) { - DisableAppLayer(f); - goto failure; - } + /* Set a value that is neither STREAM_TOSERVER, nor STREAM_TOCLIENT */ + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + + /* finally, invoke the parser */ + PACKET_PROFILING_APP_START(app_tctx, *alproto); + int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, *alproto, + flags, data + data_al_so_far, + data_len - data_al_so_far); + PACKET_PROFILING_APP_END(app_tctx, *alproto); + f->data_al_so_far[dir] = 0; + if (r < 0) + goto failure; + + } else { + /* if the ssn is midstream, we may end up with a case where the + * start of an HTTP request is missing. We won't detect HTTP based + * on the request. However, the reply is fine, so we detect + * HTTP anyway. This leads to passing the incomplete request to + * the htp parser. + * + * This has been observed, where the http parser then saw many + * bogus requests in the incomplete data. + * + * To counter this case, a midstream session MUST find it's + * protocol in the toserver direction. If not, we assume the + * start of the request/toserver is incomplete and no reliable + * detection and parsing is possible. So we give up. + */ + if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) && + !(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) + { + if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { + SCLogDebug("midstream end pd %p", ssn); + /* midstream and toserver detection failed: give up */ + DisableAppLayer(f); + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + goto end; } + } - /* if the parser operates such that it needs to see data from - * a particular direction first, we check if we have seen - * data from that direction first for the flow. IF it is not - * the same, we set an event and exit. - * - * \todo We need to figure out a more robust solution for this, - * as this can lead to easy evasion tactics, where the - * attackeer can first send some dummy data in the wrong - * direction first to mislead our proto detection process. - * While doing this we need to update the parsers as well, - * since the parsers must be robust to see such wrong - * direction data. - * Either ways the moment we see the - * APPLAYER_WRONG_DIRECTION_FIRST_DATA event set for the - * flow, it shows something's fishy. + if (*alproto_otherdir != ALPROTO_UNKNOWN) { + uint8_t first_data_dir; + first_data_dir = AppLayerParserGetFirstDataDir(f->proto, *alproto_otherdir); + + /* this would handle this test case - + * http parser which says it wants to see toserver data first only. + * tcp handshake + * toclient data first received. - RUBBISH DATA which + * we don't detect as http + * toserver data next sent - we detect this as http. + * at this stage we see that toclient is the first data seen + * for this session and we try and redetect the app protocol, + * but we are unable to detect the app protocol like before. + * But since we have managed to detect the protocol for the + * other direction as http, we try to use that. At this + * stage we check if the direction of this stream matches + * to that acceptable by the app parser. If it is not the + * acceptable direction we error out. */ - if (ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - first_data_dir = AppLayerParserGetFirstDataDir(f->proto, *alproto); - - if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_WRONG_DIRECTION_FIRST_DATA); - DisableAppLayer(f); - /* Set a value that is neither STREAM_TOSERVER, nor STREAM_TOCLIENT */ - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - goto failure; - } - /* This can happen if the current direction is not the - * right direction, and the data from the other(also - * the right direction) direction is available to be sent - * to the app layer, but it is not ack'ed yet and hence - * the forced call to STreamTcpAppLayerReassemble still - * hasn't managed to send data from the other direction - * to the app layer. */ - if (first_data_dir && !(first_data_dir & flags)) { - BUG_ON(*alproto_otherdir != ALPROTO_UNKNOWN); - FlowCleanupAppLayer(f); - f->alproto = *alproto = ALPROTO_UNKNOWN; - StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream); - FLOW_RESET_PP_DONE(f, flags); - FLOW_RESET_PM_DONE(f, flags); - goto failure; - } + if ((ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) && + (first_data_dir) && !(first_data_dir & flags)) + { + DisableAppLayer(f); + goto failure; } - /* Set a value that is neither STREAM_TOSERVER, nor STREAM_TOCLIENT */ - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + if (data_len > 0) + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - PACKET_PROFILING_APP_START(app_tctx, *alproto); - r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, *alproto, - flags, data + data_al_so_far, - data_len - data_al_so_far); - PACKET_PROFILING_APP_END(app_tctx, *alproto); - f->data_al_so_far[dir] = 0; - } else { - /* if the ssn is midstream, we may end up with a case where the - * start of an HTTP request is missing. We won't detect HTTP based - * on the request. However, the reply is fine, so we detect - * HTTP anyway. This leads to passing the incomplete request to - * the htp parser. - * - * This has been observed, where the http parser then saw many - * bogus requests in the incomplete data. - * - * To counter this case, a midstream session MUST find it's - * protocol in the toserver direction. If not, we assume the - * start of the request/toserver is incomplete and no reliable - * detection and parsing is possible. So we give up. - */ - if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) && !(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) { - if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { - SCLogDebug("midstream end pd %p", ssn); - /* midstream and toserver detection failed: give up */ - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - goto end; - } + PACKET_PROFILING_APP_START(app_tctx, *alproto_otherdir); + int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, + *alproto_otherdir, flags, + data + data_al_so_far, + data_len - data_al_so_far); + PACKET_PROFILING_APP_END(app_tctx, *alproto_otherdir); + if (FLOW_IS_PM_DONE(f, flags) && FLOW_IS_PP_DONE(f, flags)) { + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION); + StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); + f->data_al_so_far[dir] = 0; + TcpSessionSetReassemblyDepth(ssn, + AppLayerParserGetStreamDepth(f->proto, *alproto)); + } else { + f->data_al_so_far[dir] = data_len; } + if (r < 0) + goto failure; - if (*alproto_otherdir != ALPROTO_UNKNOWN) { - first_data_dir = AppLayerParserGetFirstDataDir(f->proto, *alproto_otherdir); - - /* this would handle this test case - - * http parser which says it wants to see toserver data first only. - * tcp handshake - * toclient data first received. - RUBBISH DATA which - * we don't detect as http - * toserver data next sent - we detect this as http. - * at this stage we see that toclient is the first data seen - * for this session and we try and redetect the app protocol, - * but we are unable to detect the app protocol like before. - * But since we have managed to detect the protocol for the - * other direction as http, we try to use that. At this - * stage we check if the direction of this stream matches - * to that acceptable by the app parser. If it is not the - * acceptable direction we error out. - */ - if ((ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) && - (first_data_dir) && !(first_data_dir & flags)) - { - DisableAppLayer(f); - goto failure; - } + } else { + /* both sides unknown, let's see if we need to give up */ + TCPProtoDetectCheckBailConditions(f, ssn, p); + } + } +end: + return 0; - if (data_len > 0) - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - - PACKET_PROFILING_APP_START(app_tctx, *alproto_otherdir); - r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, - *alproto_otherdir, flags, - data + data_al_so_far, - data_len - data_al_so_far); - PACKET_PROFILING_APP_END(app_tctx, *alproto_otherdir); - if (FLOW_IS_PM_DONE(f, flags) && FLOW_IS_PP_DONE(f, flags)) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); - f->data_al_so_far[dir] = 0; - TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, *alproto)); - } else { - f->data_al_so_far[dir] = data_len; - } - } else { - /* See if we're going to have to give up: - * - * If we're getting a lot of data in one direction and the - * proto for this direction is unknown, proto detect will - * hold up segments in the segment list in the stream. - * They are held so that if we detect the protocol on the - * opposing stream, we can still parse this side of the stream - * as well. However, some sessions are very unbalanced. FTP - * data channels, large PUT/POST request and many others, can - * lead to cases where we would have to store many megabytes - * worth of segments before we see the opposing stream. This - * leads to risks of resource starvation. - * - * Here a cutoff point is enforced. If we've stored 100k in - * one direction and we've seen no data in the other direction, - * we give up. */ - uint32_t size_ts = ssn->client.last_ack - ssn->client.isn - 1; - uint32_t size_tc = ssn->server.last_ack - ssn->server.isn - 1; - SCLogDebug("size_ts %u, size_tc %u", size_ts, size_tc); -#ifdef DEBUG_VALIDATION - if (!(ssn->client.flags & STREAMTCP_STREAM_FLAG_GAP)) - BUG_ON(size_ts > 1000000UL); - if (!(ssn->server.flags & STREAMTCP_STREAM_FLAG_GAP)) - BUG_ON(size_tc > 1000000UL); -#endif /* DEBUG_VALIDATION */ +failure: + return -1; +} - if (ProtoDetectDone(f, ssn, STREAM_TOSERVER) && - ProtoDetectDone(f, ssn, STREAM_TOCLIENT)) - { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; +/** \brief handle TCP data for the app-layer. + * + * First run protocol detection and then when the protocol is known invoke + * the app layer parser. + */ +int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, + Packet *p, Flow *f, + TcpSession *ssn, TcpStream *stream, + uint8_t *data, uint32_t data_len, + uint8_t flags) +{ + SCEnter(); - } else if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && - size_ts > 100000 && size_tc == 0) - { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); - } else if (FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && - size_tc > 100000 && size_ts == 0) - { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); - /* little data in ts direction, pp done, pm not done (max - * depth not reached), ts direction done, lots of data in - * tc direction. */ - } else if (size_tc > 100000 && - FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && - FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) - { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); - /* little data in tc direction, pp done, pm not done (max - * depth not reached), tc direction done, lots of data in - * ts direction. */ - } else if (size_ts > 100000 && - FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && !(FLOW_IS_PM_DONE(f, STREAM_TOCLIENT)) && - FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) - { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); - /* in case of really low TS data (e.g. 4 bytes) we can have - * the PP complete, PM not complete (depth not reached) and - * the TC side also not recognized (proto unknown) */ - } else if (size_tc > 100000 && - FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && - (!FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && !FLOW_IS_PP_DONE(f, STREAM_TOCLIENT))) - { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); - } - } + DEBUG_ASSERT_FLOW_LOCKED(f); + + AppLayerThreadCtx *app_tctx = ra_ctx->app_tctx; + AppProto alproto; + uint8_t dir; + int r = 0; + + SCLogDebug("data_len %u flags %02X", data_len, flags); + if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) { + SCLogDebug("STREAMTCP_FLAG_APP_LAYER_DISABLED is set"); + goto end; + } + + if (flags & STREAM_TOSERVER) { + alproto = f->alproto_ts; + dir = 0; + } else { + alproto = f->alproto_tc; + dir = 1; + } + + /* if we don't know the proto yet and we have received a stream + * initializer message, we run proto detection. + * We receive 2 stream init msgs (one for each direction) but we + * only run the proto detection once. */ + if (alproto == ALPROTO_UNKNOWN && (flags & STREAM_GAP)) { + StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); + StreamTcpSetSessionNoReassemblyFlag(ssn, dir); + SCLogDebug("ALPROTO_UNKNOWN flow %p, due to GAP in stream start", f); + + } else if (alproto == ALPROTO_UNKNOWN && (flags & STREAM_START)) { + /* run protocol detection */ + if (TCPProtoDetect(tv, ra_ctx, app_tctx, p, f, ssn, stream, + data, data_len, flags) != 0) { + goto failure; } } else { SCLogDebug("stream data (len %" PRIu32 " alproto " diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index c0d210900b0c..130789b34ab1 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -31,19 +31,21 @@ #include "util-unittest.h" #include "util-unittest-helper.h" -void DetectAppLayerProtocolRegisterTests(void); +static void DetectAppLayerProtocolRegisterTests(void); -int DetectAppLayerProtocolMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, +static int DetectAppLayerProtocolMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { + SCEnter(); + int r = 0; DetectAppLayerProtocolData *data = (DetectAppLayerProtocolData *)m->ctx; r = (data->negated) ? (f->alproto != data->alproto) : (f->alproto == data->alproto); - return r; + SCReturnInt(r); } static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg) @@ -86,8 +88,8 @@ static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg) return data; } -int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, - char *arg) +static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, + Signature *s, char *arg) { DetectAppLayerProtocolData *data = NULL; SigMatch *sm = NULL; @@ -125,10 +127,9 @@ int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, return -1; } -void DetectAppLayerProtocolFree(void *ptr) +static void DetectAppLayerProtocolFree(void *ptr) { SCFree(ptr); - return; } @@ -389,7 +390,7 @@ int DetectAppLayerProtocolTest09(void) #endif /* UNITTESTS */ -void DetectAppLayerProtocolRegisterTests(void) +static void DetectAppLayerProtocolRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectAppLayerProtocolTest01", From d7c828bcb0f9737d92128ec379ddc9d1e93bc582 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Oct 2016 11:47:35 +0200 Subject: [PATCH 2087/2553] proto detect: update behavior on partial detection When the current direction doesn't get a protocol detection, but the opposing direction did, previously we would send the current data to the parser. Then when we'd be invoked again (until the protocol detection finally failed) we'd get the same data + the new data. To make sure we'd not send the same data to the parser again, the flow kept track of how much was already sent to the app-layer using data_al_so_far. This patch changes the behaviour. Instead of sending the data for the current direction right away, we only do this when protocol detection is complete. This way we won't have to track anything. --- src/app-layer.c | 482 ++++++++++++++++++++++-------------------------- 1 file changed, 224 insertions(+), 258 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 29c0346cfcd9..304d6867f620 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -457,28 +457,31 @@ static int TCPProtoDetect(ThreadVars *tv, goto failure; } - if (data_len > 0) - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - - PACKET_PROFILING_APP_START(app_tctx, *alproto_otherdir); - int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, - *alproto_otherdir, flags, - data + data_al_so_far, - data_len - data_al_so_far); - PACKET_PROFILING_APP_END(app_tctx, *alproto_otherdir); + /* if protocol detection is marked done for our direction we + * pass our data on. We're only succeeded in finding one + * direction: the opposing stream + * + * If PD was not yet complete, we don't do anything. + */ if (FLOW_IS_PM_DONE(f, flags) && FLOW_IS_PP_DONE(f, flags)) { + if (data_len > 0) + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + + PACKET_PROFILING_APP_START(app_tctx, *alproto_otherdir); + int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, + *alproto_otherdir, flags, + data + data_al_so_far, + data_len - data_al_so_far); + PACKET_PROFILING_APP_END(app_tctx, *alproto_otherdir); AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION); StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); f->data_al_so_far[dir] = 0; TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, *alproto)); - } else { - f->data_al_so_far[dir] = data_len; + if (r < 0) + goto failure; } - if (r < 0) - goto failure; - } else { /* both sides unknown, let's see if we need to give up */ TCPProtoDetectCheckBailConditions(f, ssn, p); @@ -1627,8 +1630,7 @@ static int AppLayerTest03(void) static int AppLayerTest04(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); Flow f; ThreadVars tv; StreamTcpThread *stt = NULL; @@ -1646,8 +1648,6 @@ static int AppLayerTest04(void) p->flow = &f; p->tcph = &tcph; - int ret = 0; - StreamTcpInitConfig(TRUE); StreamTcpThreadInit(&tv, NULL, (void **)&stt); @@ -1657,25 +1657,22 @@ static int AppLayerTest04(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); TcpSession *ssn = (TcpSession *)f.protoctx; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != 0); /* handshake */ p->tcph->th_ack = htonl(1); @@ -1683,22 +1680,20 @@ static int AppLayerTest04(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != 0); /* handshake */ p->tcph->th_ack = htonl(1); @@ -1707,22 +1702,20 @@ static int AppLayerTest04(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != 0); /* request */ uint8_t request[] = { @@ -1737,53 +1730,51 @@ static int AppLayerTest04(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + PrintRawDataFp(stdout, request, sizeof(request)); p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); // TOSERVER data now seen /* partial response */ uint8_t response1[] = { 0x58, 0x54, 0x54, 0x50, }; + PrintRawDataFp(stdout, response1, sizeof(response1)); p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response1); p->payload = response1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); // toserver complete + FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer /* partial response ack */ p->tcph->th_ack = htonl(5); @@ -1792,22 +1783,20 @@ static int AppLayerTest04(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 4 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); // toserver complete + FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer /* remaining response */ uint8_t response2[] = { @@ -1852,28 +1841,27 @@ static int AppLayerTest04(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + PrintRawDataFp(stdout, response2, sizeof(response2)); p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response2); p->payload = response2; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 4 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 7\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); // toserver complete + FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer /* response ack */ p->tcph->th_ack = htonl(328); @@ -1882,31 +1870,25 @@ static int AppLayerTest04(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 8\n"); - goto end; - } - + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); // toclient complete (failed) + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); // toserver complete + FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: StreamTcpFreeConfig(TRUE); SCFree(p); FLOW_DESTROY(&f); - return ret; + PASS; } /** @@ -1915,8 +1897,7 @@ static int AppLayerTest04(void) static int AppLayerTest05(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); Flow f; ThreadVars tv; StreamTcpThread *stt = NULL; @@ -1934,8 +1915,6 @@ static int AppLayerTest05(void) p->flow = &f; p->tcph = &tcph; - int ret = 0; - StreamTcpInitConfig(TRUE); StreamTcpThreadInit(&tv, NULL, (void **)&stt); @@ -1944,27 +1923,25 @@ static int AppLayerTest05(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + + TcpSession *ssn = (TcpSession *)f.protoctx; + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != 0); /* handshake */ p->tcph->th_ack = htonl(1); @@ -1972,22 +1949,20 @@ static int AppLayerTest05(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != 0); /* handshake */ p->tcph->th_ack = htonl(1); @@ -1996,22 +1971,20 @@ static int AppLayerTest05(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != 0); /* full request */ uint8_t request[] = { @@ -2026,28 +1999,27 @@ static int AppLayerTest05(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + PrintRawDataFp(stdout, request, sizeof(request)); p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -2092,28 +2064,27 @@ static int AppLayerTest05(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + PrintRawDataFp(stdout, response, sizeof(response)); p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -2122,31 +2093,26 @@ static int AppLayerTest05(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_HTTP); + FAIL_IF(f.data_al_so_far[0] != 0); + FAIL_IF(f.data_al_so_far[1] != 0); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: StreamTcpFreeConfig(TRUE); SCFree(p); FLOW_DESTROY(&f); - return ret; + PASS; } /** From ac2cf526f1c925c138ea5cfa4021bc11bc9f3134 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Oct 2016 12:02:25 +0200 Subject: [PATCH 2088/2553] proto detect: remove flow data tracking The Flow::data_al_so_far was used for tracking data already parsed when protocol for the current direction wasn't known yet. As this behaviour has changed the tracking can be removed. --- src/app-layer.c | 164 +----------------------------------- src/flow-util.h | 4 - src/flow.h | 2 - src/stream-tcp-reassemble.c | 34 -------- 4 files changed, 2 insertions(+), 202 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 304d6867f620..ac432d622aa2 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -268,22 +268,16 @@ static int TCPProtoDetect(ThreadVars *tv, Packet *p, Flow *f, TcpSession *ssn, TcpStream *stream, uint8_t *data, uint32_t data_len, uint8_t flags) { - uint32_t data_al_so_far = 0; AppProto *alproto; AppProto *alproto_otherdir; - int dir; if (flags & STREAM_TOSERVER) { alproto = &f->alproto_ts; alproto_otherdir = &f->alproto_tc; - dir = 0; } else { alproto = &f->alproto_tc; alproto_otherdir = &f->alproto_ts; - dir = 1; } - if (data_len > 0) - data_al_so_far = f->data_al_so_far[dir]; SCLogDebug("Stream initializer (len %" PRIu32 ")", data_len); #ifdef PRINT @@ -397,10 +391,8 @@ static int TCPProtoDetect(ThreadVars *tv, /* finally, invoke the parser */ PACKET_PROFILING_APP_START(app_tctx, *alproto); int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, *alproto, - flags, data + data_al_so_far, - data_len - data_al_so_far); + flags, data, data_len); PACKET_PROFILING_APP_END(app_tctx, *alproto); - f->data_al_so_far[dir] = 0; if (r < 0) goto failure; @@ -470,13 +462,11 @@ static int TCPProtoDetect(ThreadVars *tv, PACKET_PROFILING_APP_START(app_tctx, *alproto_otherdir); int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, *alproto_otherdir, flags, - data + data_al_so_far, - data_len - data_al_so_far); + data, data_len); PACKET_PROFILING_APP_END(app_tctx, *alproto_otherdir); AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION); StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); - f->data_al_so_far[dir] = 0; TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, *alproto)); if (r < 0) @@ -902,8 +892,6 @@ static int AppLayerTest01(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -926,8 +914,6 @@ static int AppLayerTest01(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -950,8 +936,6 @@ static int AppLayerTest01(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -986,8 +970,6 @@ static int AppLayerTest01(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1052,8 +1034,6 @@ static int AppLayerTest01(void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1076,8 +1056,6 @@ static int AppLayerTest01(void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1142,8 +1120,6 @@ static int AppLayerTest02(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1166,8 +1142,6 @@ static int AppLayerTest02(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1190,8 +1164,6 @@ static int AppLayerTest02(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1215,8 +1187,6 @@ static int AppLayerTest02(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1239,8 +1209,6 @@ static int AppLayerTest02(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1275,8 +1243,6 @@ static int AppLayerTest02(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1341,8 +1307,6 @@ static int AppLayerTest02(void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1365,8 +1329,6 @@ static int AppLayerTest02(void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1431,8 +1393,6 @@ static int AppLayerTest03(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1454,8 +1414,6 @@ static int AppLayerTest03(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1478,8 +1436,6 @@ static int AppLayerTest03(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1514,8 +1470,6 @@ static int AppLayerTest03(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1580,8 +1534,6 @@ static int AppLayerTest03(void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1604,8 +1556,6 @@ static int AppLayerTest03(void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -1665,8 +1615,6 @@ static int AppLayerTest04(void) FAIL_IF(f.alproto != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -1686,8 +1634,6 @@ static int AppLayerTest04(void) FAIL_IF(f.alproto != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -1708,8 +1654,6 @@ static int AppLayerTest04(void) FAIL_IF(f.alproto != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -1743,8 +1687,6 @@ static int AppLayerTest04(void) FAIL_IF(f.alproto != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -1767,8 +1709,6 @@ static int AppLayerTest04(void) FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -1789,8 +1729,6 @@ static int AppLayerTest04(void) FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -1854,8 +1792,6 @@ static int AppLayerTest04(void) FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -1876,8 +1812,6 @@ static int AppLayerTest04(void) FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -1934,8 +1868,6 @@ static int AppLayerTest05(void) FAIL_IF(f.alproto != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -1955,8 +1887,6 @@ static int AppLayerTest05(void) FAIL_IF(f.alproto != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -1977,8 +1907,6 @@ static int AppLayerTest05(void) FAIL_IF(f.alproto != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -2012,8 +1940,6 @@ static int AppLayerTest05(void) FAIL_IF(f.alproto != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -2077,8 +2003,6 @@ static int AppLayerTest05(void) FAIL_IF(f.alproto != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -2099,8 +2023,6 @@ static int AppLayerTest05(void) FAIL_IF(f.alproto != ALPROTO_HTTP); FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); FAIL_IF(f.alproto_tc != ALPROTO_HTTP); - FAIL_IF(f.data_al_so_far[0] != 0); - FAIL_IF(f.data_al_so_far[1] != 0); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); @@ -2161,8 +2083,6 @@ static int AppLayerTest06(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2185,8 +2105,6 @@ static int AppLayerTest06(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2209,8 +2127,6 @@ static int AppLayerTest06(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2275,8 +2191,6 @@ static int AppLayerTest06(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2311,8 +2225,6 @@ static int AppLayerTest06(void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2377,8 +2289,6 @@ static int AppLayerTest07(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2401,8 +2311,6 @@ static int AppLayerTest07(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2425,8 +2333,6 @@ static int AppLayerTest07(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2461,8 +2367,6 @@ static int AppLayerTest07(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2527,8 +2431,6 @@ static int AppLayerTest07(void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2551,8 +2453,6 @@ static int AppLayerTest07(void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2617,8 +2517,6 @@ static int AppLayerTest08(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2641,8 +2539,6 @@ static int AppLayerTest08(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2665,8 +2561,6 @@ static int AppLayerTest08(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2701,8 +2595,6 @@ static int AppLayerTest08(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2767,8 +2659,6 @@ static int AppLayerTest08(void) f.alproto != ALPROTO_DCERPC || f.alproto_ts != ALPROTO_DCERPC || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2791,8 +2681,6 @@ static int AppLayerTest08(void) f.alproto != ALPROTO_DCERPC || f.alproto_ts != ALPROTO_DCERPC || f.alproto_tc != ALPROTO_DCERPC || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2859,8 +2747,6 @@ static int AppLayerTest09(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2883,8 +2769,6 @@ static int AppLayerTest09(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2907,8 +2791,6 @@ static int AppLayerTest09(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2933,8 +2815,6 @@ static int AppLayerTest09(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2957,8 +2837,6 @@ static int AppLayerTest09(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -2983,8 +2861,6 @@ static int AppLayerTest09(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3049,8 +2925,6 @@ static int AppLayerTest09(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3073,8 +2947,6 @@ static int AppLayerTest09(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3140,8 +3012,6 @@ static int AppLayerTest10(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3164,8 +3034,6 @@ static int AppLayerTest10(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3188,8 +3056,6 @@ static int AppLayerTest10(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3215,8 +3081,6 @@ static int AppLayerTest10(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3239,8 +3103,6 @@ static int AppLayerTest10(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3305,8 +3167,6 @@ static int AppLayerTest10(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3329,8 +3189,6 @@ static int AppLayerTest10(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3397,8 +3255,6 @@ static int AppLayerTest11(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3421,8 +3277,6 @@ static int AppLayerTest11(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3445,8 +3299,6 @@ static int AppLayerTest11(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3472,8 +3324,6 @@ static int AppLayerTest11(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3496,8 +3346,6 @@ static int AppLayerTest11(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3522,8 +3370,6 @@ static int AppLayerTest11(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3546,8 +3392,6 @@ static int AppLayerTest11(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3611,8 +3455,6 @@ static int AppLayerTest11(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -3635,8 +3477,6 @@ static int AppLayerTest11(void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || diff --git a/src/flow-util.h b/src/flow-util.h index 3874050b4aa1..8eea21ee4207 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -55,8 +55,6 @@ (f)->alproto = 0; \ (f)->alproto_ts = 0; \ (f)->alproto_tc = 0; \ - (f)->data_al_so_far[0] = 0; \ - (f)->data_al_so_far[1] = 0; \ (f)->de_ctx_id = 0; \ (f)->thread_id = 0; \ (f)->detect_alversion[0] = 0; \ @@ -100,8 +98,6 @@ (f)->alproto = 0; \ (f)->alproto_ts = 0; \ (f)->alproto_tc = 0; \ - (f)->data_al_so_far[0] = 0; \ - (f)->data_al_so_far[1] = 0; \ (f)->de_ctx_id = 0; \ (f)->thread_id = 0; \ (f)->detect_alversion[0] = 0; \ diff --git a/src/flow.h b/src/flow.h index 044f61e1d3d8..316d9ef8077d 100644 --- a/src/flow.h +++ b/src/flow.h @@ -380,8 +380,6 @@ typedef struct Flow_ AppProto alproto_ts; AppProto alproto_tc; - uint32_t data_al_so_far[2]; - /** 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. */ diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 5dec16e49374..1b5e42c0b480 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -6261,8 +6261,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6288,8 +6286,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6316,8 +6312,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6345,8 +6339,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6375,8 +6367,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6416,8 +6406,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6488,8 +6476,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6517,8 +6503,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6546,8 +6530,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6574,8 +6556,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6602,8 +6582,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6632,8 +6610,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6662,8 +6638,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6691,8 +6665,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6721,8 +6693,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6764,8 +6734,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || @@ -6791,8 +6759,6 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || From 7d7ec78cc3e80ce47888684f65034cac6f69bc47 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Oct 2016 19:31:38 +0200 Subject: [PATCH 2089/2553] app-layer-protocol: improve detection Add negated matches to match list instead of amatch. Allow matching on 'failed'. Introduce per packet flags for proto detection. Flags are used to only inspect once per direction. Flag packet on PD-failure too. --- src/app-layer.c | 70 +++++++++++++++++++++++++++------ src/decode.h | 4 ++ src/detect-app-layer-protocol.c | 64 +++++++++++++++++++++++++----- src/flow.c | 10 +++++ src/flow.h | 3 ++ 5 files changed, 130 insertions(+), 21 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index ac432d622aa2..5a891d200f0f 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -115,6 +115,38 @@ void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step) } } +/* in IDS mode protocol detection is done in reverse order: + * when TCP data is ack'd. We want to flag the correct packet, + * so in this case we set a flag in the flow so that the first + * packet in the correct direction can be tagged. + * + * For IPS things are much simpler, and we don't use the flow + * flag. We just tag the packet directly. */ +static inline void FlagPacketFlow(Packet *p, Flow *f, uint8_t dir) +{ + if (EngineModeIsIPS()) { + if (dir == STREAM_TOSERVER) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + p->flags |= PKT_PROTO_DETECT_TS_DONE; + } else { + f->flags |= FLOW_PROTO_DETECT_TS_DONE; + } + } else { + if (p->flowflags & FLOW_PKT_TOCLIENT) { + p->flags |= PKT_PROTO_DETECT_TC_DONE; + } else { + f->flags |= FLOW_PROTO_DETECT_TC_DONE; + } + } + } else { + if (dir == STREAM_TOSERVER) { + f->flags |= FLOW_PROTO_DETECT_TS_DONE; + } else { + f->flags |= FLOW_PROTO_DETECT_TC_DONE; + } + } +} + /* See if we're going to have to give up: * * If we're getting a lot of data in one direction and the @@ -150,24 +182,21 @@ static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet * if (ProtoDetectDone(f, ssn, STREAM_TOSERVER) && ProtoDetectDone(f, ssn, STREAM_TOCLIENT)) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + goto failure; } else if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && size_ts > 100000 && size_tc == 0) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; } else if (FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && size_tc > 100000 && size_ts == 0) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; /* little data in ts direction, pp done, pm not done (max * depth not reached), ts direction done, lots of data in @@ -176,10 +205,9 @@ static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet * FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; /* little data in tc direction, pp done, pm not done (max * depth not reached), tc direction done, lots of data in @@ -188,10 +216,9 @@ static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet * FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && !(FLOW_IS_PM_DONE(f, STREAM_TOCLIENT)) && FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; /* in case of really low TS data (e.g. 4 bytes) we can have * the PP complete, PM not complete (depth not reached) and @@ -200,11 +227,20 @@ static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet * FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && (!FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && !FLOW_IS_PP_DONE(f, STREAM_TOCLIENT))) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; } + return; + +failure: + DisableAppLayer(f); + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + f->alproto = f->alproto_tc = f->alproto_ts = ALPROTO_FAILED; + + FlagPacketFlow(p, f, STREAM_TOSERVER); + FlagPacketFlow(p, f, STREAM_TOCLIENT); + return; } /** \todo modifying p this way seems too hacky */ @@ -315,6 +351,10 @@ static int TCPProtoDetect(ThreadVars *tv, StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, *alproto)); + if (flags & STREAM_TOCLIENT) + FlagPacketFlow(p, f, STREAM_TOCLIENT); + else + FlagPacketFlow(p, f, STREAM_TOSERVER); /* account flow if we have both sides */ if (*alproto_otherdir != ALPROTO_UNKNOWN) { @@ -469,6 +509,12 @@ static int TCPProtoDetect(ThreadVars *tv, StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, *alproto)); + + if (flags & STREAM_TOCLIENT) + FlagPacketFlow(p, f, STREAM_TOCLIENT); + else + FlagPacketFlow(p, f, STREAM_TOSERVER); + if (r < 0) goto failure; } diff --git a/src/decode.h b/src/decode.h index f760b17acb93..deebbe8cdfa4 100644 --- a/src/decode.h +++ b/src/decode.h @@ -1096,6 +1096,10 @@ int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder); * flow engine: Packet::flow_hash will be set */ #define PKT_WANTS_FLOW (1<<22) +/** protocol detection done */ +#define PKT_PROTO_DETECT_TS_DONE (1<<23) +#define PKT_PROTO_DETECT_TC_DONE (1<<24) + /** \brief return 1 if the packet is a pseudo packet */ #define PKT_IS_PSEUDOPKT(p) ((p)->flags & PKT_PSEUDO_STREAM_END) diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 130789b34ab1..4694804b5703 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -33,6 +33,41 @@ static void DetectAppLayerProtocolRegisterTests(void); +static int DetectAppLayerProtocolPacketMatch(ThreadVars *tv, + DetectEngineThreadCtx *det_ctx, + Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + int r = 0; + const DetectAppLayerProtocolData *data = (const DetectAppLayerProtocolData *)ctx; + + if ((p->flags & (PKT_PROTO_DETECT_TS_DONE|PKT_PROTO_DETECT_TC_DONE)) == 0) { + SCLogNotice("packet %u: flags not set", (uint)p->pcap_cnt); + SCReturnInt(0); + } + + const Flow *f = p->flow; + if (f == NULL) { + SCLogNotice("packet %u: no flow", (uint)p->pcap_cnt); + SCReturnInt(0); + } + + if ((p->flags & PKT_PROTO_DETECT_TS_DONE) && (p->flowflags & FLOW_PKT_TOSERVER)) { + SCLogNotice("toserver packet %u: looking for %u/neg %u, got %u", (uint)p->pcap_cnt, + data->alproto, data->negated, f->alproto_ts); + r = (data->negated) ? (f->alproto_ts != data->alproto) : + (f->alproto_ts == data->alproto); + } else if ((p->flags & PKT_PROTO_DETECT_TC_DONE) && (p->flowflags & FLOW_PKT_TOCLIENT)) { + SCLogNotice("toclient packet %u: looking for %u/neg %u, got %u", (uint)p->pcap_cnt, + data->alproto, data->negated, f->alproto_tc); + r = (data->negated) ? (f->alproto_tc != data->alproto) : + (f->alproto_tc == data->alproto); + } + + SCReturnInt(r); +} + static int DetectAppLayerProtocolMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) @@ -40,7 +75,7 @@ static int DetectAppLayerProtocolMatch(ThreadVars *t, DetectEngineThreadCtx *det SCEnter(); int r = 0; - DetectAppLayerProtocolData *data = (DetectAppLayerProtocolData *)m->ctx; + const DetectAppLayerProtocolData *data = (const DetectAppLayerProtocolData *)m->ctx; r = (data->negated) ? (f->alproto != data->alproto) : (f->alproto == data->alproto); @@ -72,11 +107,15 @@ static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg) while (*arg != '\0' && isspace((unsigned char)*arg)) arg++; - alproto = AppLayerGetProtoByName((char *)arg); - if (alproto == ALPROTO_UNKNOWN) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-protocol " - "keyword supplied with unknown protocol \"%s\"", arg); - return NULL; + if (strcmp(arg, "failed") == 0) { + alproto = ALPROTO_FAILED; + } else { + alproto = AppLayerGetProtoByName((char *)arg); + if (alproto == ALPROTO_UNKNOWN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-protocol " + "keyword supplied with unknown protocol \"%s\"", arg); + return NULL; + } } data = SCMalloc(sizeof(DetectAppLayerProtocolData)); @@ -116,8 +155,14 @@ static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, sm->type = DETECT_AL_APP_LAYER_PROTOCOL; sm->ctx = (void *)data; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - s->flags |= SIG_FLAG_APPLAYER; + if (data->negated || data->alproto == ALPROTO_FAILED) { + SCLogNotice("DETECT_SM_LIST_MATCH"); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); + } else { + SCLogNotice("DETECT_SM_LIST_AMATCH"); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + s->flags |= SIG_FLAG_APPLAYER; + } return 0; @@ -136,7 +181,8 @@ static void DetectAppLayerProtocolFree(void *ptr) void DetectAppLayerProtocolRegister(void) { sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].name = "app-layer-protocol"; - sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Match = NULL; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Match = + DetectAppLayerProtocolPacketMatch; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].AppLayerMatch = DetectAppLayerProtocolMatch; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Setup = diff --git a/src/flow.c b/src/flow.c index f33c2bc5ba6f..be5ea03e3023 100644 --- a/src/flow.c +++ b/src/flow.c @@ -248,6 +248,11 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p) p->flowflags |= FLOW_PKT_TOSERVER_FIRST; } } + /* xfer proto detect ts flag to first packet in ts dir */ + if (f->flags & FLOW_PROTO_DETECT_TS_DONE) { + f->flags &= ~FLOW_PROTO_DETECT_TS_DONE; + p->flags |= PKT_PROTO_DETECT_TS_DONE; + } } else { f->tosrcpktcnt++; f->tosrcbytecnt += GET_PKT_LEN(p); @@ -258,6 +263,11 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p) p->flowflags |= FLOW_PKT_TOCLIENT_FIRST; } } + /* xfer proto detect tc flag to first packet in tc dir */ + if (f->flags & FLOW_PROTO_DETECT_TC_DONE) { + f->flags &= ~FLOW_PROTO_DETECT_TC_DONE; + p->flags |= PKT_PROTO_DETECT_TC_DONE; + } } if ((f->flags & (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) == (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) { diff --git a/src/flow.h b/src/flow.h index 316d9ef8077d..a9d7c95d1314 100644 --- a/src/flow.h +++ b/src/flow.h @@ -89,6 +89,9 @@ typedef struct AppLayerParserState_ AppLayerParserState; /** flow is ipv6 */ #define FLOW_IPV6 BIT_U32(19) +#define FLOW_PROTO_DETECT_TS_DONE BIT_U32(20) +#define FLOW_PROTO_DETECT_TC_DONE BIT_U32(21) + /* File flags */ From 9560e8b5b2ce7a0e4ea62e0d3b5dc908695f142b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Oct 2016 18:00:37 +0200 Subject: [PATCH 2090/2553] proto-detect: update mismatch handling Improve protocol mismatch handling. Preserve both protos. Use otherdir if already sent to parser, use toclient otherwise. --- src/app-layer.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 5a891d200f0f..e19e33365af7 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -336,21 +336,25 @@ static int TCPProtoDetect(ThreadVars *tv, if (*alproto_otherdir != ALPROTO_UNKNOWN && *alproto_otherdir != *alproto) { AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS); - /* it indicates some data has already been sent to the parser */ + if (ssn->data_first_seen_dir == APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - f->alproto = *alproto = *alproto_otherdir; + /* if we already invoked the parser, we go with that proto */ + f->alproto = *alproto_otherdir; } else { + /* no data sent to parser yet, we can still choose + * we're trusting the server more. */ if (flags & STREAM_TOCLIENT) - f->alproto = *alproto_otherdir = *alproto; + f->alproto = *alproto; else - f->alproto = *alproto = *alproto_otherdir; + f->alproto = *alproto_otherdir; } + } else { + f->alproto = *alproto; } - f->alproto = *alproto; StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); TcpSessionSetReassemblyDepth(ssn, - AppLayerParserGetStreamDepth(f->proto, *alproto)); + AppLayerParserGetStreamDepth(f->proto, f->alproto)); if (flags & STREAM_TOCLIENT) FlagPacketFlow(p, f, STREAM_TOCLIENT); else @@ -397,7 +401,7 @@ static int TCPProtoDetect(ThreadVars *tv, */ if (ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { uint8_t first_data_dir; - first_data_dir = AppLayerParserGetFirstDataDir(f->proto, *alproto); + first_data_dir = AppLayerParserGetFirstDataDir(f->proto, f->alproto); if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) { AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, @@ -415,9 +419,7 @@ static int TCPProtoDetect(ThreadVars *tv, * hasn't managed to send data from the other direction * to the app layer. */ if (first_data_dir && !(first_data_dir & flags)) { - BUG_ON(*alproto_otherdir != ALPROTO_UNKNOWN); FlowCleanupAppLayer(f); - f->alproto = *alproto = ALPROTO_UNKNOWN; StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream); FLOW_RESET_PP_DONE(f, flags); FLOW_RESET_PM_DONE(f, flags); @@ -429,10 +431,10 @@ static int TCPProtoDetect(ThreadVars *tv, ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; /* finally, invoke the parser */ - PACKET_PROFILING_APP_START(app_tctx, *alproto); - int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, *alproto, + PACKET_PROFILING_APP_START(app_tctx, f->alproto); + int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, f->alproto, flags, data, data_len); - PACKET_PROFILING_APP_END(app_tctx, *alproto); + PACKET_PROFILING_APP_END(app_tctx, f->alproto); if (r < 0) goto failure; @@ -499,22 +501,26 @@ static int TCPProtoDetect(ThreadVars *tv, if (data_len > 0) ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - PACKET_PROFILING_APP_START(app_tctx, *alproto_otherdir); + PACKET_PROFILING_APP_START(app_tctx, f->alproto); int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, - *alproto_otherdir, flags, + f->alproto, flags, data, data_len); - PACKET_PROFILING_APP_END(app_tctx, *alproto_otherdir); + PACKET_PROFILING_APP_END(app_tctx, f->alproto); + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION); StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); TcpSessionSetReassemblyDepth(ssn, - AppLayerParserGetStreamDepth(f->proto, *alproto)); + AppLayerParserGetStreamDepth(f->proto, f->alproto)); + *alproto = ALPROTO_FAILED; if (flags & STREAM_TOCLIENT) FlagPacketFlow(p, f, STREAM_TOCLIENT); else FlagPacketFlow(p, f, STREAM_TOSERVER); + SCLogDebug("packet %u: pd done(us %u them %u), parser called (r==%d), APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION set", + (uint)p->pcap_cnt, *alproto, *alproto_otherdir, r); if (r < 0) goto failure; } From e955cf3366ca87745fc85b9f49cae5ce5388df9e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 9 Oct 2016 11:23:49 +0200 Subject: [PATCH 2091/2553] detect-app-layer-protocol: improve error handling Redo tests. --- src/detect-app-layer-protocol.c | 317 ++++++++++++++++---------------- 1 file changed, 160 insertions(+), 157 deletions(-) diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 4694804b5703..6ca76bb5af09 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -145,8 +145,19 @@ static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, if (data == NULL) goto error; - if (!data->negated) + if (!data->negated && data->alproto != ALPROTO_FAILED) { + SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + for ( ; sm != NULL; sm = sm->next) { + if (sm->type == DETECT_AL_APP_LAYER_PROTOCOL) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "can't mix " + "positive app-layer-protocol match with negated " + "match or match for 'failed'."); + goto error; + } + } + s->alproto = data->alproto; + } sm = SigMatchAlloc(); if (sm == NULL) @@ -199,239 +210,223 @@ void DetectAppLayerProtocolRegister(void) #ifdef UNITTESTS -int DetectAppLayerProtocolTest01(void) +static int DetectAppLayerProtocolTest01(void) { - int result = 0; - DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("http"); - if (data == NULL) - goto end; - if (data->alproto != ALPROTO_HTTP || data->negated) { - printf("test failure. Holding wrong state\n"); - goto end; - } - - result = 1; - - end: - if (data != NULL) - DetectAppLayerProtocolFree(data); - return result; + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated != 0); + DetectAppLayerProtocolFree(data); + PASS; } -int DetectAppLayerProtocolTest02(void) +static int DetectAppLayerProtocolTest02(void) { - int result = 0; - DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("!http"); - if (data == NULL) - goto end; - if (data->alproto != ALPROTO_HTTP || !data->negated) { - printf("test failure. Holding wrong state\n"); - goto end; - } - - result = 1; - - end: - if (data != NULL) - DetectAppLayerProtocolFree(data); - return result; + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated == 0); + DetectAppLayerProtocolFree(data); + PASS; } -int DetectAppLayerProtocolTest03(void) +static int DetectAppLayerProtocolTest03(void) { - int result = 0; Signature *s = NULL; DetectAppLayerProtocolData *data = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:http; sid:1;)"); - if (s->alproto != ALPROTO_HTTP) { - printf("signature alproto should be http\n"); - goto end; - } - data = (DetectAppLayerProtocolData *)s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx; - if (data->alproto != ALPROTO_HTTP || data->negated) { - printf("if (data->alproto != ALPROTO_HTTP || data->negated)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; sid:1;)"); + FAIL_IF_NULL(s); - result = 1; + FAIL_IF(s->alproto != ALPROTO_HTTP); - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_AMATCH]); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx); + + data = (DetectAppLayerProtocolData *)s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx; + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated); DetectEngineCtxFree(de_ctx); - return result; + PASS; } -int DetectAppLayerProtocolTest04(void) +static int DetectAppLayerProtocolTest04(void) { - int result = 0; Signature *s = NULL; DetectAppLayerProtocolData *data = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:!http; sid:1;)"); - if (s->alproto != ALPROTO_UNKNOWN) { - printf("signature alproto should be unknown\n"); - goto end; - } - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { - printf("if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL)\n"); - goto end; - } - data = (DetectAppLayerProtocolData*)s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx; - if (data == NULL) { - printf("if (data == NULL)\n"); - goto end; - } - if (data->alproto != ALPROTO_HTTP || !data->negated) { - printf("if (data->alproto != ALPROTO_HTTP || !data->negated)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:!http; sid:1;)"); + FAIL_IF_NULL(s); + FAIL_IF(s->alproto != ALPROTO_UNKNOWN); + FAIL_IF(s->flags & SIG_FLAG_APPLAYER); - result = 1; + /* negated match means we use MATCH not AMATCH */ + FAIL_IF_NOT(s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); + + data = (DetectAppLayerProtocolData*)s->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated == 0); - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } -int DetectAppLayerProtocolTest05(void) +static int DetectAppLayerProtocolTest05(void) { - int result = 0; Signature *s = NULL; + DetectAppLayerProtocolData *data = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:!http; app-layer-protocol:!smtp; sid:1;)"); - if (s->alproto != ALPROTO_UNKNOWN) { - printf("signature alproto should be unknown\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:!http; app-layer-protocol:!smtp; sid:1;)"); + FAIL_IF_NULL(s); + FAIL_IF(s->alproto != ALPROTO_UNKNOWN); + FAIL_IF(s->flags & SIG_FLAG_APPLAYER); + + /* negated match means we use MATCH not AMATCH */ + FAIL_IF_NOT(s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); - result = 1; + data = (DetectAppLayerProtocolData*)s->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated == 0); + + data = (DetectAppLayerProtocolData*)s->sm_lists[DETECT_SM_LIST_MATCH]->next->ctx; + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_SMTP); + FAIL_IF(data->negated == 0); - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } -int DetectAppLayerProtocolTest06(void) +static int DetectAppLayerProtocolTest06(void) { - int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert http any any -> any any " - "(app-layer-protocol:smtp; sid:1;)"); - if (s != NULL) { - printf("if (s != NULL)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(app-layer-protocol:smtp; sid:1;)"); + FAIL_IF_NOT_NULL(s); + DetectEngineCtxFree(de_ctx); + PASS; +} - result = 1; +static int DetectAppLayerProtocolTest07(void) +{ + Signature *s = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(app-layer-protocol:!smtp; sid:1;)"); + FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); - return result; + PASS; } -int DetectAppLayerProtocolTest07(void) +static int DetectAppLayerProtocolTest08(void) { - int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert http any any -> any any " - "(app-layer-protocol:!smtp; sid:1;)"); - if (s != NULL) { - printf("if (s != NULL)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:!smtp; app-layer-protocol:http; sid:1;)"); + FAIL_IF_NOT_NULL(s); + DetectEngineCtxFree(de_ctx); + PASS; +} - result = 1; +static int DetectAppLayerProtocolTest09(void) +{ + Signature *s = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; app-layer-protocol:!smtp; sid:1;)"); + FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); - return result; + PASS; } -int DetectAppLayerProtocolTest08(void) +static int DetectAppLayerProtocolTest10(void) { - int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:!smtp; app-layer-protocol:http; sid:1;)"); - if (s != NULL) { - printf("if (s != NULL)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:smtp; app-layer-protocol:!http; sid:1;)"); + FAIL_IF_NOT_NULL(s); + DetectEngineCtxFree(de_ctx); + PASS; +} - result = 1; +static int DetectAppLayerProtocolTest11(void) +{ + DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("failed"); + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_FAILED); + FAIL_IF(data->negated != 0); + DetectAppLayerProtocolFree(data); + PASS; +} - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - return result; +static int DetectAppLayerProtocolTest12(void) +{ + DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("!failed"); + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_FAILED); + FAIL_IF(data->negated == 0); + DetectAppLayerProtocolFree(data); + PASS; } -int DetectAppLayerProtocolTest09(void) +static int DetectAppLayerProtocolTest13(void) { - int result = 0; Signature *s = NULL; + DetectAppLayerProtocolData *data = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:http; app-layer-protocol:!smtp; sid:1;)"); - if (s != NULL) { - printf("if (s != NULL)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:failed; sid:1;)"); + FAIL_IF_NULL(s); + + FAIL_IF(s->alproto != ALPROTO_UNKNOWN); - result = 1; + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + data = (DetectAppLayerProtocolData *)s->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF(data->alproto != ALPROTO_FAILED); + FAIL_IF(data->negated); DetectEngineCtxFree(de_ctx); - return result; + PASS; } #endif /* UNITTESTS */ @@ -457,6 +452,14 @@ static void DetectAppLayerProtocolRegisterTests(void) DetectAppLayerProtocolTest08); UtRegisterTest("DetectAppLayerProtocolTest09", DetectAppLayerProtocolTest09); + UtRegisterTest("DetectAppLayerProtocolTest10", + DetectAppLayerProtocolTest10); + UtRegisterTest("DetectAppLayerProtocolTest11", + DetectAppLayerProtocolTest11); + UtRegisterTest("DetectAppLayerProtocolTest12", + DetectAppLayerProtocolTest12); + UtRegisterTest("DetectAppLayerProtocolTest13", + DetectAppLayerProtocolTest13); #endif /* UNITTESTS */ return; From 90bf2b5a32f6ea0aeb46ded8fed40df3bca075af Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 9 Oct 2016 23:49:09 +0200 Subject: [PATCH 2092/2553] proto detect: improve error case handling Improve flags logic, update tests. --- src/app-layer.c | 2136 +++++++++++++---------------------------------- 1 file changed, 566 insertions(+), 1570 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index e19e33365af7..f2c6f2627496 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -89,12 +89,6 @@ void AppLayerDeSetupCounters(); /***** L7 layer dispatchers *****/ -static void DisableAppLayer(Flow *f) -{ - SCLogDebug("disable app layer for flow %p", f); - StreamTcpDisableAppLayer(f); -} - static inline int ProtoDetectDone(const Flow *f, const TcpSession *ssn, uint8_t direction) { const TcpStream *stream = (direction & STREAM_TOSERVER) ? &ssn->client : &ssn->server; return ((stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) || @@ -147,6 +141,31 @@ static inline void FlagPacketFlow(Packet *p, Flow *f, uint8_t dir) } } +static void DisableAppLayer(Flow *f, Packet *p) +{ + SCLogDebug("disable app layer for flow %p alproto %u ts %u tc %u", + f, f->alproto, f->alproto_ts, f->alproto_tc); + StreamTcpDisableAppLayer(f); + TcpSession *ssn = f->protoctx; + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + f->alproto = ALPROTO_FAILED; + + if (f->alproto_tc != ALPROTO_FAILED) { + if (f->alproto_tc == ALPROTO_UNKNOWN) { + f->alproto_tc = ALPROTO_FAILED; + } + FlagPacketFlow(p, f, STREAM_TOCLIENT); + } + if (f->alproto_ts != ALPROTO_FAILED) { + if (f->alproto_ts == ALPROTO_UNKNOWN) { + f->alproto_ts = ALPROTO_FAILED; + } + FlagPacketFlow(p, f, STREAM_TOSERVER); + } + SCLogDebug("disabled app layer for flow %p alproto %u ts %u tc %u", + f, f->alproto, f->alproto_ts, f->alproto_tc); +} + /* See if we're going to have to give up: * * If we're getting a lot of data in one direction and the @@ -234,12 +253,7 @@ static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet * return; failure: - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - f->alproto = f->alproto_tc = f->alproto_ts = ALPROTO_FAILED; - - FlagPacketFlow(p, f, STREAM_TOSERVER); - FlagPacketFlow(p, f, STREAM_TOCLIENT); + DisableAppLayer(f, p); return; } @@ -378,7 +392,7 @@ static int TCPProtoDetect(ThreadVars *tv, if (TCPProtoDetectTriggerOpposingSide(tv, ra_ctx, p, ssn, stream, flags) != 0) { - DisableAppLayer(f); + DisableAppLayer(f, p); goto failure; } } @@ -406,9 +420,7 @@ static int TCPProtoDetect(ThreadVars *tv, if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) { AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_WRONG_DIRECTION_FIRST_DATA); - DisableAppLayer(f); - /* Set a value that is neither STREAM_TOSERVER, nor STREAM_TOCLIENT */ - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + DisableAppLayer(f, p); goto failure; } /* This can happen if the current direction is not the @@ -459,8 +471,7 @@ static int TCPProtoDetect(ThreadVars *tv, if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { SCLogDebug("midstream end pd %p", ssn); /* midstream and toserver detection failed: give up */ - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + DisableAppLayer(f, p); goto end; } } @@ -487,7 +498,7 @@ static int TCPProtoDetect(ThreadVars *tv, if ((ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) && (first_data_dir) && !(first_data_dir & flags)) { - DisableAppLayer(f); + DisableAppLayer(f, p); goto failure; } @@ -893,108 +904,109 @@ void AppLayerDeSetupCounters() /***** Unittests *****/ #ifdef UNITTESTS +#include "pkt-var.h" #include "stream-tcp.h" #include "stream-tcp-util.h" #include "stream.h" #include "util-unittest.h" +#define TEST_START \ + Packet *p = SCMalloc(SIZE_OF_PACKET);\ + FAIL_IF_NULL(p);\ + Flow f;\ + ThreadVars tv;\ + StreamTcpThread *stt = NULL;\ + TCPHdr tcph;\ + PacketQueue pq;\ + memset(&pq,0,sizeof(PacketQueue));\ + memset(p, 0, SIZE_OF_PACKET);\ + memset (&f, 0, sizeof(Flow));\ + memset(&tv, 0, sizeof (ThreadVars));\ + memset(&tcph, 0, sizeof (TCPHdr));\ +\ + FLOW_INITIALIZE(&f);\ + f.flags = FLOW_IPV4;\ + f.proto = IPPROTO_TCP;\ + p->flow = &f;\ + p->tcph = &tcph;\ +\ + StreamTcpInitConfig(TRUE);\ + StreamTcpThreadInit(&tv, NULL, (void **)&stt);\ +\ + /* handshake */\ + tcph.th_win = htons(5480);\ + tcph.th_flags = TH_SYN;\ + p->flowflags = FLOW_PKT_TOSERVER;\ + p->payload_len = 0;\ + p->payload = NULL;\ + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1);\ + TcpSession *ssn = (TcpSession *)f.protoctx;\ +\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));\ + FAIL_IF(f.alproto != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);\ + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(ssn->data_first_seen_dir != 0);\ +\ + /* handshake */\ + p->tcph->th_ack = htonl(1);\ + p->tcph->th_flags = TH_SYN | TH_ACK;\ + p->flowflags = FLOW_PKT_TOCLIENT;\ + p->payload_len = 0;\ + p->payload = NULL;\ + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1);\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));\ + FAIL_IF(f.alproto != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);\ + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(ssn->data_first_seen_dir != 0);\ +\ + /* handshake */\ + p->tcph->th_ack = htonl(1);\ + p->tcph->th_seq = htonl(1);\ + p->tcph->th_flags = TH_ACK;\ + p->flowflags = FLOW_PKT_TOSERVER;\ + p->payload_len = 0;\ + p->payload = NULL;\ + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1);\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));\ + FAIL_IF(f.alproto != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);\ + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(ssn->data_first_seen_dir != 0); +#define TEST_END \ + StreamTcpSessionClear(p->flow->protoctx);\ + StreamTcpThreadDeinit(&tv, (void *)stt); \ + StreamTcpFreeConfig(TRUE);\ + PACKET_DESTRUCTOR(p);\ + SCFree(p);\ + FLOW_DESTROY(&f); \ + StatsThreadCleanup(&tv); + /** * \test GET -> HTTP/1.1 */ static int AppLayerTest01(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request[] = { @@ -1015,20 +1027,18 @@ static int AppLayerTest01(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -1079,20 +1089,18 @@ static int AppLayerTest01(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -1101,29 +1109,21 @@ static int AppLayerTest01(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_HTTP); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); - return ret; + TEST_END; + PASS; } /** @@ -1131,98 +1131,7 @@ static int AppLayerTest01(void) */ static int AppLayerTest02(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - /* handshake */ - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* partial request */ uint8_t request1[] = { 0x47, 0x45, }; @@ -1232,20 +1141,18 @@ static int AppLayerTest02(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request1); p->payload = request1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack against partial request */ p->tcph->th_ack = htonl(3); @@ -1254,20 +1161,18 @@ static int AppLayerTest02(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* complete partial request */ uint8_t request2[] = { @@ -1288,20 +1193,18 @@ static int AppLayerTest02(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request2); p->payload = request2; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 6\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response - request ack */ uint8_t response[] = { @@ -1352,20 +1255,18 @@ static int AppLayerTest02(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 7\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -1374,29 +1275,21 @@ static int AppLayerTest02(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 8\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_HTTP); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); - return ret; + TEST_END; + PASS; } /** @@ -1404,97 +1297,7 @@ static int AppLayerTest02(void) */ static int AppLayerTest03(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* request */ uint8_t request[] = { @@ -1515,20 +1318,18 @@ static int AppLayerTest03(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* rubbish response */ uint8_t response[] = { @@ -1579,139 +1380,49 @@ static int AppLayerTest03(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } - - /* response ack */ - p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(88); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); - return ret; -} - -/** - * \test GE -> RUBBISH(TC - PM AND PP NOT DONE) -> RUBBISH(TC - PM AND PP DONE). - */ -static int AppLayerTest04(void) -{ - Packet *p = SCMalloc(SIZE_OF_PACKET); - FAIL_IF_NULL(p); - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - /* handshake */ - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); - TcpSession *ssn = (TcpSession *)f.protoctx; - - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); - FAIL_IF(f.alproto != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); - FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(ssn->data_first_seen_dir != 0); - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); - FAIL_IF(f.alproto != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(ssn->data_first_seen_dir != 0); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); + /* response ack */ + p->tcph->th_ack = htonl(328); + p->tcph->th_seq = htonl(88); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); - FAIL_IF(f.alproto != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(ssn->data_first_seen_dir != 0); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; +} + +/** + * \test GE -> RUBBISH(TC - PM AND PP NOT DONE) -> RUBBISH(TC - PM AND PP DONE). + */ +static int AppLayerTest04(void) +{ + TEST_START; /* request */ uint8_t request[] = { @@ -1863,17 +1574,15 @@ static int AppLayerTest04(void) FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); // toserver complete FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete - FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); // tc failed FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer - StreamTcpSessionClear(p->flow->protoctx); - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); + + TEST_END; PASS; } @@ -1882,89 +1591,7 @@ static int AppLayerTest04(void) */ static int AppLayerTest05(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - FAIL_IF_NULL(p); - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - - /* handshake */ - FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); - - TcpSession *ssn = (TcpSession *)f.protoctx; - - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); - FAIL_IF(f.alproto != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); - FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(ssn->data_first_seen_dir != 0); - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); - FAIL_IF(f.alproto != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); - FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(ssn->data_first_seen_dir != 0); - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); - FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); - FAIL_IF(f.alproto != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); - FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); - FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); - FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); - FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(ssn->data_first_seen_dir != 0); + TEST_START; /* full request */ uint8_t request[] = { @@ -2073,7 +1700,7 @@ static int AppLayerTest05(void) FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); FAIL_IF(f.alproto != ALPROTO_HTTP); - FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_FAILED); FAIL_IF(f.alproto_tc != ALPROTO_HTTP); FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); @@ -2082,10 +1709,7 @@ static int AppLayerTest05(void) FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); - StreamTcpSessionClear(p->flow->protoctx); - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); + TEST_END; PASS; } @@ -2094,98 +1718,7 @@ static int AppLayerTest05(void) */ static int AppLayerTest06(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full response - request ack */ uint8_t response[] = { @@ -2236,20 +1769,18 @@ static int AppLayerTest06(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOCLIENT) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOCLIENT); /* full request - response ack*/ uint8_t request[] = { @@ -2270,29 +1801,21 @@ static int AppLayerTest06(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_HTTP || - !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_FAILED); + FAIL_IF(f.alproto_ts != ALPROTO_FAILED); + FAIL_IF(f.alproto_tc != ALPROTO_HTTP); + FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); - return ret; + TEST_END; + PASS; } /** @@ -2300,98 +1823,7 @@ static int AppLayerTest06(void) */ static int AppLayerTest07(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request[] = { @@ -2412,20 +1844,18 @@ static int AppLayerTest07(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -2476,20 +1906,18 @@ static int AppLayerTest07(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -2498,29 +1926,21 @@ static int AppLayerTest07(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_DCERPC); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; } /** @@ -2528,98 +1948,7 @@ static int AppLayerTest07(void) */ static int AppLayerTest08(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request[] = { @@ -2640,20 +1969,18 @@ static int AppLayerTest08(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -2704,20 +2031,18 @@ static int AppLayerTest08(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_DCERPC || - f.alproto_ts != ALPROTO_DCERPC || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_DCERPC); + FAIL_IF(f.alproto_ts != ALPROTO_DCERPC); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -2726,29 +2051,21 @@ static int AppLayerTest08(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_DCERPC || - f.alproto_ts != ALPROTO_DCERPC || - f.alproto_tc != ALPROTO_DCERPC || - !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6 %04x\n", ssn->flags); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_DCERPC); + FAIL_IF(f.alproto_ts != ALPROTO_DCERPC); + FAIL_IF(f.alproto_tc != ALPROTO_HTTP); + FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); - return ret; + TEST_END; + PASS; } /** @@ -2758,98 +2075,7 @@ static int AppLayerTest08(void) */ static int AppLayerTest09(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request1[] = { @@ -2860,20 +2086,18 @@ static int AppLayerTest09(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request1); p->payload = request1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response - request ack */ p->tcph->th_ack = htonl(9); @@ -2882,20 +2106,18 @@ static int AppLayerTest09(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full request */ uint8_t request2[] = { @@ -2906,20 +2128,18 @@ static int AppLayerTest09(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request2); p->payload = request2; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 6\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -2970,20 +2190,18 @@ static int AppLayerTest09(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 7\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -2992,29 +2210,21 @@ static int AppLayerTest09(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 8\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_FAILED); + FAIL_IF(f.alproto_ts != ALPROTO_FAILED); + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); + FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); - return ret; + TEST_END; + PASS; } /** @@ -3023,98 +2233,7 @@ static int AppLayerTest09(void) */ static int AppLayerTest10(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request1[] = { @@ -3126,20 +2245,18 @@ static int AppLayerTest10(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request1); p->payload = request1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response - request ack */ p->tcph->th_ack = htonl(18); @@ -3148,20 +2265,18 @@ static int AppLayerTest10(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -3212,20 +2327,18 @@ static int AppLayerTest10(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 7\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -3234,29 +2347,21 @@ static int AppLayerTest10(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 8\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_FAILED); + FAIL_IF(f.alproto_ts != ALPROTO_FAILED); + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); + FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); - return ret; + TEST_END; + PASS; } /** @@ -3266,98 +2371,7 @@ static int AppLayerTest10(void) */ static int AppLayerTest11(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request1[] = { @@ -3369,20 +2383,18 @@ static int AppLayerTest11(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request1); p->payload = request1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response - request ack */ p->tcph->th_ack = htonl(18); @@ -3391,20 +2403,18 @@ static int AppLayerTest11(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response1[] = { @@ -3415,20 +2425,18 @@ static int AppLayerTest11(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response1); p->payload = response1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 6\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack from request */ p->tcph->th_ack = htonl(5); @@ -3437,20 +2445,18 @@ static int AppLayerTest11(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 7\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); uint8_t response2[] = { 0x2f, 0x31, 0x2e, 0x31, @@ -3500,20 +2506,18 @@ static int AppLayerTest11(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response2); p->payload = response2; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 8\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack from request */ p->tcph->th_ack = htonl(328); @@ -3522,29 +2526,21 @@ static int AppLayerTest11(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - !(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 9\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_FAILED); + FAIL_IF(f.alproto_ts != ALPROTO_FAILED); + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); + FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - FLOW_DESTROY(&f); - return ret; + TEST_END; + PASS; } void AppLayerUnittestsRegister(void) From 3b98feef011571e9b90804be4e673419a2b1f5eb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 10 Oct 2016 12:06:48 +0200 Subject: [PATCH 2093/2553] proto-detect: clean up UDP handling Set FAILED instead of using a flow flag. Flag packets in both sides when detection is done. Detection is only done in one direction. --- src/app-layer.c | 35 ++++++++++++++++------------------- src/flow.h | 4 ++-- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index f2c6f2627496..a581aaaefe42 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -652,11 +652,11 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * flags |= STREAM_TOCLIENT; } - /* if we don't know the proto yet and we have received a stream - * initializer message, we run proto detection. - * We receive 2 stream init msgs (one for each direction) but we - * only run the proto detection once. */ - if (f->alproto == ALPROTO_UNKNOWN && !(f->flags & FLOW_ALPROTO_DETECT_DONE)) { + if (f->alproto == ALPROTO_FAILED) { + SCReturnInt(0); + + /* if the protocol is still unknown, run detection */ + } else if (f->alproto == ALPROTO_UNKNOWN) { SCLogDebug("Detecting AL proto on udp mesg (len %" PRIu32 ")", p->payload_len); @@ -668,7 +668,6 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * PACKET_PROFILING_APP_PD_END(tctx); if (f->alproto != ALPROTO_UNKNOWN) { - f->flags |= FLOW_ALPROTO_DETECT_DONE; AppLayerIncFlowCounter(tv, f); PACKET_PROFILING_APP_START(tctx, f->alproto); @@ -676,24 +675,22 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * flags, p->payload, p->payload_len); PACKET_PROFILING_APP_END(tctx, f->alproto); } else { - f->flags |= FLOW_ALPROTO_DETECT_DONE; + f->alproto = ALPROTO_FAILED; SCLogDebug("ALPROTO_UNKNOWN flow %p", f); } + /* we do only inspection in one direction, so flag both + * sides as done here */ + FlagPacketFlow(p, f, STREAM_TOSERVER); + FlagPacketFlow(p, f, STREAM_TOCLIENT); } else { - SCLogDebug("stream data (len %" PRIu32 " ), alproto " + SCLogDebug("data (len %" PRIu32 " ), alproto " "%"PRIu16" (flow %p)", p->payload_len, f->alproto, f); - /* if we don't have a data object here we are not getting it - * a start msg should have gotten us one */ - if (f->alproto != ALPROTO_UNKNOWN) { - PACKET_PROFILING_APP_START(tctx, f->alproto); - r = AppLayerParserParse(tv, tctx->alp_tctx, f, f->alproto, - flags, p->payload, p->payload_len); - PACKET_PROFILING_APP_END(tctx, f->alproto); - } else { - SCLogDebug("udp session has started, but failed to detect alproto " - "for l7"); - } + /* run the parser */ + PACKET_PROFILING_APP_START(tctx, f->alproto); + r = AppLayerParserParse(tv, tctx->alp_tctx, f, f->alproto, + flags, p->payload, p->payload_len); + PACKET_PROFILING_APP_END(tctx, f->alproto); } PACKET_PROFILING_APP_STORE(tctx, p); diff --git a/src/flow.h b/src/flow.h index a9d7c95d1314..d215a58210ad 100644 --- a/src/flow.h +++ b/src/flow.h @@ -71,8 +71,8 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_TOSERVER_DROP_LOGGED BIT_U32(10) /** packet to client direction has been logged in drop file (only in IPS mode) */ #define FLOW_TOCLIENT_DROP_LOGGED BIT_U32(11) -/** alproto detect done. Right now we need it only for udp */ -#define FLOW_ALPROTO_DETECT_DONE BIT_U32(12) + +// vacancy bit 12 /** Pattern matcher alproto detection done */ #define FLOW_TS_PM_ALPROTO_DETECT_DONE BIT_U32(13) From 93298e91c77ac86c2098e7f0a53a830957271063 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Oct 2016 22:54:19 +0200 Subject: [PATCH 2094/2553] app-layer counters: count failed protocol detect --- src/app-layer.c | 50 ++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index a581aaaefe42..5d0fa13581a9 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -116,10 +116,10 @@ void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step) * * For IPS things are much simpler, and we don't use the flow * flag. We just tag the packet directly. */ -static inline void FlagPacketFlow(Packet *p, Flow *f, uint8_t dir) +static inline void FlagPacketFlow(Packet *p, Flow *f, uint8_t flags) { if (EngineModeIsIPS()) { - if (dir == STREAM_TOSERVER) { + if (flags & STREAM_TOSERVER) { if (p->flowflags & FLOW_PKT_TOSERVER) { p->flags |= PKT_PROTO_DETECT_TS_DONE; } else { @@ -133,7 +133,7 @@ static inline void FlagPacketFlow(Packet *p, Flow *f, uint8_t dir) } } } else { - if (dir == STREAM_TOSERVER) { + if (flags & STREAM_TOSERVER) { f->flags |= FLOW_PROTO_DETECT_TS_DONE; } else { f->flags |= FLOW_PROTO_DETECT_TC_DONE; @@ -141,7 +141,7 @@ static inline void FlagPacketFlow(Packet *p, Flow *f, uint8_t dir) } } -static void DisableAppLayer(Flow *f, Packet *p) +static void DisableAppLayer(ThreadVars *tv, Flow *f, Packet *p) { SCLogDebug("disable app layer for flow %p alproto %u ts %u tc %u", f, f->alproto, f->alproto_ts, f->alproto_tc); @@ -149,6 +149,7 @@ static void DisableAppLayer(Flow *f, Packet *p) TcpSession *ssn = f->protoctx; ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; f->alproto = ALPROTO_FAILED; + AppLayerIncFlowCounter(tv, f); if (f->alproto_tc != ALPROTO_FAILED) { if (f->alproto_tc == ALPROTO_UNKNOWN) { @@ -185,7 +186,8 @@ static void DisableAppLayer(Flow *f, Packet *p) * * Giving up means we disable applayer an set an applayer event */ -static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet *p) +static void TCPProtoDetectCheckBailConditions(ThreadVars *tv, + Flow *f, TcpSession *ssn, Packet *p) { uint32_t size_ts = ssn->client.last_ack - ssn->client.isn - 1; uint32_t size_tc = ssn->server.last_ack - ssn->server.isn - 1; @@ -253,7 +255,7 @@ static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet * return; failure: - DisableAppLayer(f, p); + DisableAppLayer(tv, f, p); return; } @@ -369,10 +371,7 @@ static int TCPProtoDetect(ThreadVars *tv, StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, f->alproto)); - if (flags & STREAM_TOCLIENT) - FlagPacketFlow(p, f, STREAM_TOCLIENT); - else - FlagPacketFlow(p, f, STREAM_TOSERVER); + FlagPacketFlow(p, f, flags); /* account flow if we have both sides */ if (*alproto_otherdir != ALPROTO_UNKNOWN) { @@ -392,7 +391,7 @@ static int TCPProtoDetect(ThreadVars *tv, if (TCPProtoDetectTriggerOpposingSide(tv, ra_ctx, p, ssn, stream, flags) != 0) { - DisableAppLayer(f, p); + DisableAppLayer(tv, f, p); goto failure; } } @@ -420,7 +419,7 @@ static int TCPProtoDetect(ThreadVars *tv, if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) { AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_WRONG_DIRECTION_FIRST_DATA); - DisableAppLayer(f, p); + DisableAppLayer(tv, f, p); goto failure; } /* This can happen if the current direction is not the @@ -471,7 +470,7 @@ static int TCPProtoDetect(ThreadVars *tv, if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { SCLogDebug("midstream end pd %p", ssn); /* midstream and toserver detection failed: give up */ - DisableAppLayer(f, p); + DisableAppLayer(tv, f, p); goto end; } } @@ -498,7 +497,7 @@ static int TCPProtoDetect(ThreadVars *tv, if ((ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) && (first_data_dir) && !(first_data_dir & flags)) { - DisableAppLayer(f, p); + DisableAppLayer(tv, f, p); goto failure; } @@ -524,11 +523,7 @@ static int TCPProtoDetect(ThreadVars *tv, TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, f->alproto)); *alproto = ALPROTO_FAILED; - - if (flags & STREAM_TOCLIENT) - FlagPacketFlow(p, f, STREAM_TOCLIENT); - else - FlagPacketFlow(p, f, STREAM_TOSERVER); + FlagPacketFlow(p, f, flags); SCLogDebug("packet %u: pd done(us %u them %u), parser called (r==%d), APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION set", (uint)p->pcap_cnt, *alproto, *alproto_otherdir, r); @@ -537,7 +532,7 @@ static int TCPProtoDetect(ThreadVars *tv, } } else { /* both sides unknown, let's see if we need to give up */ - TCPProtoDetectCheckBailConditions(f, ssn, p); + TCPProtoDetectCheckBailConditions(tv, f, ssn, p); } } end: @@ -676,6 +671,7 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * PACKET_PROFILING_APP_END(tctx, f->alproto); } else { f->alproto = ALPROTO_FAILED; + AppLayerIncFlowCounter(tv, f); SCLogDebug("ALPROTO_UNKNOWN flow %p", f); } /* we do only inspection in one direction, so flag both @@ -827,19 +823,19 @@ void AppLayerSetupCounters() uint8_t ipproto; AppProto alproto; AppProto alprotos[ALPROTO_MAX]; + const char *str = "app_layer.flow."; AppLayerProtoDetectSupportedAppProtocols(alprotos); for (ipproto = 0; ipproto < IPPROTOS_MAX; ipproto++) { + uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); uint8_t other_ipproto = (ipprotos[ipproto] == IPPROTO_TCP) ? IPPROTO_UDP : IPPROTO_TCP; const char *ipproto_suffix = (ipprotos[ipproto] == IPPROTO_TCP) ? "_tcp" : "_udp"; for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { if (alprotos[alproto] == 1) { - const char *str = "app_layer.flow."; const char *tx_str = "app_layer.tx."; const char *alproto_str = AppLayerGetProtoName(alproto); - uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); if (AppLayerParserProtoIsRegistered(ipprotos[ipproto], alproto) && AppLayerParserProtoIsRegistered(other_ipproto, alproto)) @@ -862,6 +858,10 @@ void AppLayerSetupCounters() "%s%s", tx_str, alproto_str); } } + } else if (alproto == ALPROTO_FAILED) { + snprintf(applayer_counter_names[ipproto_map][alproto].name, + sizeof(applayer_counter_names[ipproto_map][alproto].name), + "%s%s%s", str, "failed", ipproto_suffix); } } } @@ -877,9 +877,10 @@ void AppLayerRegisterThreadCounters(ThreadVars *tv) AppLayerProtoDetectSupportedAppProtocols(alprotos); for (ipproto = 0; ipproto < IPPROTOS_MAX; ipproto++) { + uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); + for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { if (alprotos[alproto] == 1) { - uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); applayer_counters[ipproto_map][alproto].counter_id = StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); @@ -887,6 +888,9 @@ void AppLayerRegisterThreadCounters(ThreadVars *tv) applayer_counters[ipproto_map][alproto].counter_tx_id = StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].tx_name, tv); } + } else if (alproto == ALPROTO_FAILED) { + applayer_counters[ipproto_map][alproto].counter_id = + StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); } } } From dbb3a12b32e8c841e8721e8c4126755027182c74 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Oct 2016 23:07:32 +0200 Subject: [PATCH 2095/2553] logging: return string for ALPROTO_FAILED --- src/app-layer-protos.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index 50d1342c4923..596a0defe763 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -82,6 +82,8 @@ const char *AppProtoToString(AppProto alproto) proto_name = "template"; break; case ALPROTO_FAILED: + proto_name = "failed"; + break; #ifdef UNITTESTS case ALPROTO_TEST: #endif From c28d9d053861ad0ee396f2a4d2ce6368022c1a1b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 8 Oct 2016 23:08:04 +0200 Subject: [PATCH 2096/2553] eve: print app_proto_ts/app_proto_tc --- src/output-json-flow.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 09b15c09e162..d5fe37cd73a1 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -187,7 +187,16 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) return; } - json_object_set_new(js, "app_proto", json_string(AppProtoToString(f->alproto))); + json_object_set_new(js, "app_proto", + json_string(AppProtoToString(f->alproto))); + if (f->alproto_ts != f->alproto) { + json_object_set_new(js, "app_proto_ts", + json_string(AppProtoToString(f->alproto_ts))); + } + if (f->alproto_tc != f->alproto) { + json_object_set_new(js, "app_proto_tc", + json_string(AppProtoToString(f->alproto_tc))); + } json_object_set_new(hjs, "pkts_toserver", json_integer(f->todstpktcnt)); From 8094b2b12e89a1329fbf96cb8e39487a00e18ec3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 13 Oct 2016 23:33:06 +0200 Subject: [PATCH 2097/2553] detect-app-layer-protocol: convert to pkt match --- src/detect-app-layer-protocol.c | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 6ca76bb5af09..ca7fe7b92e5d 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -53,12 +53,12 @@ static int DetectAppLayerProtocolPacketMatch(ThreadVars *tv, SCReturnInt(0); } - if ((p->flags & PKT_PROTO_DETECT_TS_DONE) && (p->flowflags & FLOW_PKT_TOSERVER)) { + if ((f->alproto_ts != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOSERVER)) { SCLogNotice("toserver packet %u: looking for %u/neg %u, got %u", (uint)p->pcap_cnt, data->alproto, data->negated, f->alproto_ts); r = (data->negated) ? (f->alproto_ts != data->alproto) : (f->alproto_ts == data->alproto); - } else if ((p->flags & PKT_PROTO_DETECT_TC_DONE) && (p->flowflags & FLOW_PKT_TOCLIENT)) { + } else if ((f->alproto_tc != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOCLIENT)) { SCLogNotice("toclient packet %u: looking for %u/neg %u, got %u", (uint)p->pcap_cnt, data->alproto, data->negated, f->alproto_tc); r = (data->negated) ? (f->alproto_tc != data->alproto) : @@ -68,21 +68,6 @@ static int DetectAppLayerProtocolPacketMatch(ThreadVars *tv, SCReturnInt(r); } -static int DetectAppLayerProtocolMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - Signature *s, SigMatch *m) -{ - SCEnter(); - - int r = 0; - const DetectAppLayerProtocolData *data = (const DetectAppLayerProtocolData *)m->ctx; - - r = (data->negated) ? (f->alproto != data->alproto) : - (f->alproto == data->alproto); - - SCReturnInt(r); -} - static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg) { DetectAppLayerProtocolData *data; @@ -166,14 +151,8 @@ static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, sm->type = DETECT_AL_APP_LAYER_PROTOCOL; sm->ctx = (void *)data; - if (data->negated || data->alproto == ALPROTO_FAILED) { - SCLogNotice("DETECT_SM_LIST_MATCH"); - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); - } else { - SCLogNotice("DETECT_SM_LIST_AMATCH"); - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - s->flags |= SIG_FLAG_APPLAYER; - } + SCLogNotice("DETECT_SM_LIST_MATCH"); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; @@ -194,8 +173,6 @@ void DetectAppLayerProtocolRegister(void) sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].name = "app-layer-protocol"; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Match = DetectAppLayerProtocolPacketMatch; - sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].AppLayerMatch = - DetectAppLayerProtocolMatch; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Setup = DetectAppLayerProtocolSetup; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Free = From 0ed119068d09842361195a905f1bce73b262b99a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 14 Oct 2016 10:11:56 +0200 Subject: [PATCH 2098/2553] detect-app-layer-protocol: implement prefilter Introduce 'Protocol detection'-only rules. These rules will only be fully evaluated when the protocol detection completed. To allow mixing of the app-layer-protocol keyword with other types of matches the keyword can also inspect the flow's app-protos per packet. Implement prefilter for the 'PD-only' rules. --- src/detect-app-layer-protocol.c | 117 ++++++++++++++++++++++++++++---- src/detect-engine-analyzer.c | 1 + src/detect.c | 104 +++++++++++++++++++++++++++- src/detect.h | 6 +- 4 files changed, 213 insertions(+), 15 deletions(-) diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index ca7fe7b92e5d..1378b817ed53 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -23,6 +23,8 @@ #include "suricata-common.h" #include "detect-engine.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" #include "detect-parse.h" #include "detect-app-layer-protocol.h" #include "app-layer.h" @@ -42,28 +44,44 @@ static int DetectAppLayerProtocolPacketMatch(ThreadVars *tv, int r = 0; const DetectAppLayerProtocolData *data = (const DetectAppLayerProtocolData *)ctx; - if ((p->flags & (PKT_PROTO_DETECT_TS_DONE|PKT_PROTO_DETECT_TC_DONE)) == 0) { - SCLogNotice("packet %u: flags not set", (uint)p->pcap_cnt); + /* if the sig is PD-only we only match when PD packet flags are set */ + if ((s->flags & SIG_FLAG_PDONLY) && + (p->flags & (PKT_PROTO_DETECT_TS_DONE|PKT_PROTO_DETECT_TC_DONE)) == 0) + { + SCLogDebug("packet %"PRIu64": flags not set", p->pcap_cnt); SCReturnInt(0); } const Flow *f = p->flow; if (f == NULL) { - SCLogNotice("packet %u: no flow", (uint)p->pcap_cnt); + SCLogDebug("packet %"PRIu64": no flow", p->pcap_cnt); SCReturnInt(0); } - if ((f->alproto_ts != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOSERVER)) { - SCLogNotice("toserver packet %u: looking for %u/neg %u, got %u", (uint)p->pcap_cnt, - data->alproto, data->negated, f->alproto_ts); + /* unknown means protocol detection isn't ready yet */ + + if ((f->alproto_ts != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOSERVER)) + { + SCLogDebug("toserver packet %"PRIu64": looking for %u/neg %u, got %u", + p->pcap_cnt, data->alproto, data->negated, f->alproto_ts); + r = (data->negated) ? (f->alproto_ts != data->alproto) : (f->alproto_ts == data->alproto); - } else if ((f->alproto_tc != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOCLIENT)) { - SCLogNotice("toclient packet %u: looking for %u/neg %u, got %u", (uint)p->pcap_cnt, - data->alproto, data->negated, f->alproto_tc); + + } else if ((f->alproto_tc != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOCLIENT)) + { + SCLogDebug("toclient packet %"PRIu64": looking for %u/neg %u, got %u", + p->pcap_cnt, data->alproto, data->negated, f->alproto_tc); + r = (data->negated) ? (f->alproto_tc != data->alproto) : (f->alproto_tc == data->alproto); } + else { + SCLogDebug("packet %"PRIu64": default case: direction %02x, approtos %u/%u/%u", + p->pcap_cnt, + p->flowflags & (FLOW_PKT_TOCLIENT|FLOW_PKT_TOSERVER), + f->alproto, f->alproto_ts, f->alproto_tc); + } SCReturnInt(r); } @@ -140,8 +158,6 @@ static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, goto error; } } - - s->alproto = data->alproto; } sm = SigMatchAlloc(); @@ -151,9 +167,7 @@ static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, sm->type = DETECT_AL_APP_LAYER_PROTOCOL; sm->ctx = (void *)data; - SCLogNotice("DETECT_SM_LIST_MATCH"); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); - return 0; error: @@ -168,6 +182,79 @@ static void DetectAppLayerProtocolFree(void *ptr) return; } +/** \internal + * \brief prefilter function for protocol detect matching + */ +static void +PrefilterPacketAppProtoMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) { + SCLogDebug("packet %"PRIu64": extra match failed", p->pcap_cnt); + SCReturn; + } + + if (p->flow == NULL) { + SCLogDebug("packet %"PRIu64": no flow, no alproto", p->pcap_cnt); + SCReturn; + } + + if ((p->flags & (PKT_PROTO_DETECT_TS_DONE|PKT_PROTO_DETECT_TC_DONE)) == 0) { + SCLogDebug("packet %"PRIu64": flags not set", p->pcap_cnt); + SCReturn; + } + + if ((p->flags & PKT_PROTO_DETECT_TS_DONE) && (p->flowflags & FLOW_PKT_TOSERVER)) + { + int r = (ctx->v1.u16[0] == p->flow->alproto_ts) ^ ctx->v1.u8[2]; + if (r) { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } + } else if ((p->flags & PKT_PROTO_DETECT_TC_DONE) && (p->flowflags & FLOW_PKT_TOCLIENT)) + { + int r = (ctx->v1.u16[0] == p->flow->alproto_tc) ^ ctx->v1.u8[2]; + if (r) { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } + } +} + +static void +PrefilterPacketAppProtoSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectAppLayerProtocolData *a = smctx; + v->u16[0] = a->alproto; + v->u8[2] = (uint8_t)a->negated; +} + +static _Bool +PrefilterPacketAppProtoCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectAppLayerProtocolData *a = smctx; + if (v.u16[0] == a->alproto && + v.u8[2] == (uint8_t)a->negated) + return TRUE; + return FALSE; +} + +static int PrefilterSetupAppProto(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_AL_APP_LAYER_PROTOCOL, + PrefilterPacketAppProtoSet, + PrefilterPacketAppProtoCompare, + PrefilterPacketAppProtoMatch); +} + +static _Bool PrefilterAppProtoIsPrefilterable(const Signature *s) +{ + if (s->flags & SIG_FLAG_PDONLY) { + SCLogDebug("prefilter on PD %u", s->id); + return TRUE; + } + return FALSE; +} + void DetectAppLayerProtocolRegister(void) { sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].name = "app-layer-protocol"; @@ -180,6 +267,10 @@ void DetectAppLayerProtocolRegister(void) sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].RegisterTests = DetectAppLayerProtocolRegisterTests; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].SetupPrefilter = + PrefilterSetupAppProto; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].SupportsPrefilter = + PrefilterAppProtoIsPrefilterable; return; } diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 23775349f9c1..a2f7f9b7c4ed 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -840,6 +840,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) fprintf(rule_engine_analysis_FD, "%s\n", line); if (s->flags & SIG_FLAG_IPONLY) fprintf(rule_engine_analysis_FD, " Rule is ip only.\n"); + if (s->flags & SIG_FLAG_PDONLY) fprintf(rule_engine_analysis_FD, " Rule is PD only.\n"); if (rule_ipv6_only) fprintf(rule_engine_analysis_FD, " Rule is IPv6 only.\n"); if (rule_ipv4_only) fprintf(rule_engine_analysis_FD, " Rule is IPv4 only.\n"); if (packet_buf) fprintf(rule_engine_analysis_FD, " Rule matches on packets.\n"); diff --git a/src/detect.c b/src/detect.c index bf26a97f81e3..cd0d226d035f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1998,6 +1998,103 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) return 1; } +/** \internal + * \brief Test is a initialized signature is inspecting protocol detection only + * \param de_ctx detection engine ctx + * \param s the signature + * \retval 1 sig is dp only + * \retval 0 sig is not dp only + */ +static int SignatureIsPDOnly(const Signature *s) +{ + if (s->alproto != ALPROTO_UNKNOWN) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) + return 0; + + if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) + return 0; + + /* TMATCH list can be ignored, it contains TAGs and + * tags are compatible to DP-only. */ + + /* match list matches may be compatible to DP only. We follow the same + * logic as IP-only so we can use that flag */ + + SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + if (sm == NULL) + return 0; + + int pd = 0; + for ( ; sm != NULL; sm = sm->next) { + if (sm->type == DETECT_AL_APP_LAYER_PROTOCOL) { + pd = 1; + } else { + /* flowbits are supported for dp only sigs, as long + * as the sig only has a "set" flowbits */ + if (sm->type == DETECT_FLOWBITS) { + if ((((DetectFlowbitsData *)sm->ctx)->cmd != DETECT_FLOWBITS_CMD_SET) ) { + SCLogDebug("%u: not PD-only: flowbit settings other than 'set'", s->id); + return 0; + } + } else if (sm->type == DETECT_FLOW) { + if (((DetectFlowData *)sm->ctx)->flags & ~(DETECT_FLOW_FLAG_TOSERVER|DETECT_FLOW_FLAG_TOCLIENT)) { + SCLogDebug("%u: not PD-only: flow settings other than toserver/toclient", s->id); + return 0; + } + } else if ( !(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)) { + SCLogDebug("%u: not PD-only: %s not PD/IP-only compat", s->id, sigmatch_table[sm->type].name); + return 0; + } + } + } + + if (pd) { + SCLogDebug("PD-ONLY (%" PRIu32 ")", s->id); + } + return pd; +} + /** * \internal * \brief Check if the initialized signature is inspecting the packet payload @@ -3283,8 +3380,13 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) SCLogDebug("Signature %" PRIu32 ", internal id %" PRIu32 ", ptrs %p %p ", tmp_s->id, tmp_s->num, tmp_s, de_ctx->sig_array[tmp_s->num]); + /* see if the sig is dp only */ + if (SignatureIsPDOnly(tmp_s) == 1) { + tmp_s->flags |= SIG_FLAG_PDONLY; + SCLogDebug("Signature %"PRIu32" is considered \"PD only\"", tmp_s->id); + /* see if the sig is ip only */ - if (SignatureIsIPOnly(de_ctx, tmp_s) == 1) { + } else if (SignatureIsIPOnly(de_ctx, tmp_s) == 1) { tmp_s->flags |= SIG_FLAG_IPONLY; cnt_iponly++; diff --git a/src/detect.h b/src/detect.h index 2a84d51f0a3d..823a490b7f7a 100644 --- a/src/detect.h +++ b/src/detect.h @@ -285,6 +285,10 @@ typedef struct DetectPort_ { #define SIG_FLAG_PREFILTER (1<<23) /**< sig is part of a prefilter engine */ +/** Proto detect only signature. + * Inspected once per direction when protocol detection is done. */ +#define SIG_FLAG_PDONLY (1<<24) + /* 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) */ @@ -1198,6 +1202,7 @@ enum { /* sorted by prefilter priority. Higher in this list means it will be * picked over ones lower in the list */ + DETECT_AL_APP_LAYER_PROTOCOL, DETECT_ACK, DETECT_SEQ, DETECT_WINDOW, @@ -1296,7 +1301,6 @@ enum { DETECT_FILE_DATA, DETECT_PKT_DATA, DETECT_AL_APP_LAYER_EVENT, - DETECT_AL_APP_LAYER_PROTOCOL, DETECT_DCE_IFACE, DETECT_DCE_OPNUM, From 449c93e062c4b575ca537d887c8f35250604dce8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 14 Oct 2016 10:23:44 +0200 Subject: [PATCH 2099/2553] detect-app-layer-protocol: improve rule validation Also add tests for PD-only conditions --- src/detect-app-layer-protocol.c | 86 +++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 1378b817ed53..34c3be96026b 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -130,6 +130,23 @@ static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg) return data; } +static _Bool HasConflicts(const DetectAppLayerProtocolData *us, + const DetectAppLayerProtocolData *them) +{ + /* mixing negated and non negated is illegal */ + if (them->negated ^ us->negated) + return TRUE; + /* multiple non-negated is illegal */ + if (!us->negated) + return TRUE; + /* duplicate option */ + if (us->alproto == them->alproto) + return TRUE; + + /* all good */ + return FALSE; +} + static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { @@ -148,10 +165,12 @@ static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, if (data == NULL) goto error; - if (!data->negated && data->alproto != ALPROTO_FAILED) { - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; - for ( ; sm != NULL; sm = sm->next) { - if (sm->type == DETECT_AL_APP_LAYER_PROTOCOL) { + SigMatch *tsm = s->sm_lists[DETECT_SM_LIST_MATCH]; + for ( ; tsm != NULL; tsm = tsm->next) { + if (tsm->type == DETECT_AL_APP_LAYER_PROTOCOL) { + const DetectAppLayerProtocolData *them = (const DetectAppLayerProtocolData *)tsm->ctx; + + if (HasConflicts(data, them)) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "can't mix " "positive app-layer-protocol match with negated " "match or match for 'failed'."); @@ -310,12 +329,12 @@ static int DetectAppLayerProtocolTest03(void) "(app-layer-protocol:http; sid:1;)"); FAIL_IF_NULL(s); - FAIL_IF(s->alproto != ALPROTO_HTTP); + FAIL_IF(s->alproto != ALPROTO_UNKNOWN); - FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_AMATCH]); - FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); - data = (DetectAppLayerProtocolData *)s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx; + data = (DetectAppLayerProtocolData *)s->sm_lists[DETECT_SM_LIST_MATCH]->ctx; FAIL_IF(data->alproto != ALPROTO_HTTP); FAIL_IF(data->negated); DetectEngineCtxFree(de_ctx); @@ -336,7 +355,6 @@ static int DetectAppLayerProtocolTest04(void) FAIL_IF(s->alproto != ALPROTO_UNKNOWN); FAIL_IF(s->flags & SIG_FLAG_APPLAYER); - /* negated match means we use MATCH not AMATCH */ FAIL_IF_NOT(s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL); FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); @@ -364,7 +382,6 @@ static int DetectAppLayerProtocolTest05(void) FAIL_IF(s->alproto != ALPROTO_UNKNOWN); FAIL_IF(s->flags & SIG_FLAG_APPLAYER); - /* negated match means we use MATCH not AMATCH */ FAIL_IF_NOT(s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL); FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); @@ -497,6 +514,53 @@ static int DetectAppLayerProtocolTest13(void) PASS; } +static int DetectAppLayerProtocolTest14(void) +{ + DetectAppLayerProtocolData *data = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s1 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; flowbits:set,blah; sid:1;)"); + FAIL_IF_NULL(s1); + FAIL_IF(s1->alproto != ALPROTO_UNKNOWN); + FAIL_IF_NULL(s1->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s1->sm_lists[DETECT_SM_LIST_MATCH]->ctx); + data = (DetectAppLayerProtocolData *)s1->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated); + + Signature *s2 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; flow:to_client; sid:2;)"); + FAIL_IF_NULL(s2); + FAIL_IF(s2->alproto != ALPROTO_UNKNOWN); + FAIL_IF_NULL(s2->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s2->sm_lists[DETECT_SM_LIST_MATCH]->ctx); + data = (DetectAppLayerProtocolData *)s2->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated); + + /* flow:established and other options not supported for PD-only */ + Signature *s3 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; flow:to_client,established; sid:3;)"); + FAIL_IF_NULL(s3); + FAIL_IF(s3->alproto != ALPROTO_UNKNOWN); + FAIL_IF_NULL(s3->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s3->sm_lists[DETECT_SM_LIST_MATCH]->ctx); + data = (DetectAppLayerProtocolData *)s3->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated); + + SigGroupBuild(de_ctx); + FAIL_IF_NOT(s1->flags & SIG_FLAG_PDONLY); + FAIL_IF_NOT(s2->flags & SIG_FLAG_PDONLY); + FAIL_IF(s3->flags & SIG_FLAG_PDONLY); // failure now + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ static void DetectAppLayerProtocolRegisterTests(void) @@ -528,6 +592,8 @@ static void DetectAppLayerProtocolRegisterTests(void) DetectAppLayerProtocolTest12); UtRegisterTest("DetectAppLayerProtocolTest13", DetectAppLayerProtocolTest13); + UtRegisterTest("DetectAppLayerProtocolTest14", + DetectAppLayerProtocolTest14); #endif /* UNITTESTS */ return; From 56ffba9fd82bb30858a661f6406a05148e187e07 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 14 Oct 2016 17:28:34 +0200 Subject: [PATCH 2100/2553] doc: initial app-layer keywords Document app-layer-protocol and make a start with app-layer-event. --- doc/userguide/rules/app-layer.rst | 80 +++++++++++++++++++++++++++++++ doc/userguide/rules/index.rst | 1 + 2 files changed, 81 insertions(+) create mode 100644 doc/userguide/rules/app-layer.rst diff --git a/doc/userguide/rules/app-layer.rst b/doc/userguide/rules/app-layer.rst new file mode 100644 index 000000000000..8295d58ef3a9 --- /dev/null +++ b/doc/userguide/rules/app-layer.rst @@ -0,0 +1,80 @@ +Generic App Layer Keywords +========================== + +app-layer-protocol +------------------ + +Match on the detected app-layer protocol. + +Syntax:: + + app-layer-protocol:[!]; + +Examples:: + + app-layer-protocol:ssh; + app-layer-protocol:!tls; + app-layer-protocol:failed; + +A special value 'failed' can be used for matching on flows in which +protocol detection failed. This can happen if Suricata doesn't know +the protocol or when certain 'bail out' conditions happen. + +.. _proto-detect-bail-out: + +Bail out conditions +~~~~~~~~~~~~~~~~~~~ + +Protocol detection gives up in several cases: + +* both sides are inspected and no match was found +* side A detection failed, side B has no traffic at all (e.g. FTP data channel) +* side A detection failed, side B has so little data detection is inconclusive + +In these last 2 cases the ``app-layer-event:applayer_proto_detection_skipped`` +is set. + + +app-layer-event +--------------- + +Match on events generated by the App Layer Parsers and the protocol detection +engine. + +Syntax:: + + app-layer-event:; + +Examples:: + + app-layer-event:applayer_mismatch_protocol_both_directions; + app-layer-event:http.gzip_decompression_failed; + +Protocol Detection +~~~~~~~~~~~~~~~~~~ + +applayer_mismatch_protocol_both_directions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The toserver and toclient directions have different protocols. For example a +client talking HTTP to a SSH server. + +applayer_wrong_direction_first_data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some protocol implementations in Suricata have a requirement with regards to +the first data direction. The HTTP parser is an example of this. + +https://redmine.openinfosecfoundation.org/issues/993 + +applayer_detect_protocol_only_one_direction +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Protocol detection only succeeded in one direction. For FTP and SMTP this is +expected. + +applayer_proto_detection_skipped +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Protocol detection was skipped because of :ref:`proto-detect-bail-out`. + diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst index 6680d030f726..1818572aca10 100644 --- a/doc/userguide/rules/index.rst +++ b/doc/userguide/rules/index.rst @@ -18,6 +18,7 @@ Suricata Rules modbus-keyword dnp3-keywords enip-keyword + app-layer rule-lua-scripting normalized-buffers snort-compatibility From 6948b2332abeb1531212594f117976c54470f119 Mon Sep 17 00:00:00 2001 From: Duarte Silva Date: Sat, 15 Oct 2016 16:53:03 +0200 Subject: [PATCH 2101/2553] file-hashing: Fixed line parsing code --- src/util-detect-file-hash.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/util-detect-file-hash.c b/src/util-detect-file-hash.c index 2cd884975f1d..840f61c2bbbd 100644 --- a/src/util-detect-file-hash.c +++ b/src/util-detect-file-hash.c @@ -193,6 +193,8 @@ int DetectFileHashMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, SCReturnInt(ret); } +static const char *hexcodes = "ABCDEFabcdef0123456789"; + /** * \brief Parse the filemd5, filesha1 or filesha256 keyword * @@ -251,24 +253,17 @@ static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, int line_no = 0; while(fgets(line, (int)sizeof(line), fp) != NULL) { - size_t len = strlen(line); + size_t valid = 0, len = strlen(line); line_no++; - /* ignore comments and empty lines */ - if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') - continue; - - while (isspace(line[--len])); + while (strchr(hexcodes, line[valid]) != NULL && valid++ < len); - /* Check if we have a trailing newline, and remove it */ - len = strlen(line); - if (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) { - line[len - 1] = '\0'; - } + /* lines that do not contain sequentially any valid character are ignored */ + if (valid == 0) + continue; - /* cut off longer lines than a SHA256 represented in hexadecimal */ - if (strlen(line) > 64) - line[64] = 0x00; + /* ignore anything after the sequence of valid characters */ + line[valid] = '\0'; if (LoadHashTable(filehash->hash, line, filename, line_no, type) != 1) { goto error; From dc762cd44d08d0b682c62b64c52c9ed592fce1d6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 11 Oct 2016 10:43:34 -0600 Subject: [PATCH 2102/2553] detect-flow: use new unit test macros --- src/detect-flow.c | 519 ++++++++++++++-------------------------------- 1 file changed, 150 insertions(+), 369 deletions(-) diff --git a/src/detect-flow.c b/src/detect-flow.c index cec40b78db70..966d46957feb 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -408,15 +408,11 @@ static _Bool PrefilterFlowIsPrefilterable(const Signature *s) */ int DetectFlowTestParse01 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("established"); - if (fd != NULL) { - DetectFlowFree(fd); - result = 1; - } - - return result; + FAIL_IF_NULL(fd); + DetectFlowFree(fd); + PASS; } /** @@ -424,19 +420,12 @@ int DetectFlowTestParse01 (void) */ int DetectFlowTestParse02 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("established"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && + fd->match_cnt == 1); + PASS; } /** @@ -444,19 +433,12 @@ int DetectFlowTestParse02 (void) */ int DetectFlowTestParse03 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("stateless"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -464,19 +446,12 @@ int DetectFlowTestParse03 (void) */ int DetectFlowTestParse04 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOCLIENT, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -484,19 +459,12 @@ int DetectFlowTestParse04 (void) */ int DetectFlowTestParse05 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_server"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOSERVER, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -504,19 +472,12 @@ int DetectFlowTestParse05 (void) */ int DetectFlowTestParse06 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOCLIENT, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -524,19 +485,12 @@ int DetectFlowTestParse06 (void) */ int DetectFlowTestParse07 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_client"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOSERVER, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -544,19 +498,12 @@ int DetectFlowTestParse07 (void) */ int DetectFlowTestParse08 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("established,to_client"); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2) { - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -564,19 +511,14 @@ int DetectFlowTestParse08 (void) */ int DetectFlowTestParse09 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client,stateless"); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2) { - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -584,19 +526,14 @@ int DetectFlowTestParse09 (void) */ int DetectFlowTestParse10 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,stateless"); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2){ - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -604,19 +541,14 @@ int DetectFlowTestParse10 (void) */ int DetectFlowTestParse11 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse(" from_server , stateless "); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2){ - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -625,15 +557,11 @@ int DetectFlowTestParse11 (void) */ int DetectFlowTestParseNocase01 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED"); - if (fd != NULL) { - DetectFlowFree(fd); - result = 1; - } - - return result; + FAIL_IF_NULL(fd); + DetectFlowFree(fd); + PASS; } /** @@ -641,19 +569,13 @@ int DetectFlowTestParseNocase01 (void) */ int DetectFlowTestParseNocase02 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && + fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -661,19 +583,11 @@ int DetectFlowTestParseNocase02 (void) */ int DetectFlowTestParseNocase03 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("STATELESS"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1); DetectFlowFree(fd); + PASS; } /** @@ -681,19 +595,12 @@ int DetectFlowTestParseNocase03 (void) */ int DetectFlowTestParseNocase04 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_CLIENT"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOCLIENT, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -701,19 +608,12 @@ int DetectFlowTestParseNocase04 (void) */ int DetectFlowTestParseNocase05 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_SERVER"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOSERVER, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -721,19 +621,12 @@ int DetectFlowTestParseNocase05 (void) */ int DetectFlowTestParseNocase06 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOCLIENT, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -741,19 +634,12 @@ int DetectFlowTestParseNocase06 (void) */ int DetectFlowTestParseNocase07 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_CLIENT"); - if (fd != NULL) { - if (fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_TOSERVER, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -761,19 +647,14 @@ int DetectFlowTestParseNocase07 (void) */ int DetectFlowTestParseNocase08 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED,TO_CLIENT"); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2) { - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -781,19 +662,14 @@ int DetectFlowTestParseNocase08 (void) */ int DetectFlowTestParseNocase09 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_CLIENT,STATELESS"); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2) { - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -801,19 +677,14 @@ int DetectFlowTestParseNocase09 (void) */ int DetectFlowTestParseNocase10 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,STATELESS"); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2){ - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -821,37 +692,25 @@ int DetectFlowTestParseNocase10 (void) */ int DetectFlowTestParseNocase11 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse(" FROM_SERVER , STATELESS "); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2){ - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_STATELESS + DETECT_FLOW_FLAG_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } - /** * \test DetectFlowTestParse12 is a test for setting an invalid seperator : */ int DetectFlowTestParse12 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server:stateless"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -859,32 +718,21 @@ int DetectFlowTestParse12 (void) */ int DetectFlowTestParse13 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("invalidoptiontest"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } + /** * \test DetectFlowTestParse14 is a test for a empty option */ int DetectFlowTestParse14 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse(""); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -892,16 +740,10 @@ int DetectFlowTestParse14 (void) */ int DetectFlowTestParse15 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("established,stateless"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -909,16 +751,10 @@ int DetectFlowTestParse15 (void) */ int DetectFlowTestParse16 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client,to_server"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -927,16 +763,10 @@ int DetectFlowTestParse16 (void) */ int DetectFlowTestParse17 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client,from_server"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -944,20 +774,15 @@ int DetectFlowTestParse17 (void) */ int DetectFlowTestParse18 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,only_stream"); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM && fd->match_cnt == 3) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT + DETECT_FLOW_FLAG_ONLYSTREAM, 3, - fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM && + fd->match_cnt == 3); + DetectFlowFree(fd); + PASS; } /** @@ -965,20 +790,15 @@ int DetectFlowTestParse18 (void) */ int DetectFlowTestParseNocase18 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,ESTABLISHED,ONLY_STREAM"); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM && fd->match_cnt == 3) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT + DETECT_FLOW_FLAG_ONLYSTREAM, 3, - fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM && + fd->match_cnt == 3); + DetectFlowFree(fd); + PASS; } @@ -987,16 +807,10 @@ int DetectFlowTestParseNocase18 (void) */ int DetectFlowTestParse19 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,only_stream,a"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -1004,21 +818,15 @@ int DetectFlowTestParse19 (void) */ int DetectFlowTestParse20 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,no_stream"); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->flags & DETECT_FLOW_FLAG_NOSTREAM && fd->match_cnt == 3) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT + DETECT_FLOW_FLAG_NOSTREAM, 3, - fd->flags, fd->match_cnt); - } - - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->flags & DETECT_FLOW_FLAG_NOSTREAM && + fd->match_cnt == 3); + DetectFlowFree(fd); + PASS; } /** @@ -1026,21 +834,15 @@ int DetectFlowTestParse20 (void) */ int DetectFlowTestParseNocase20 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,ESTABLISHED,NO_STREAM"); - if (fd != NULL) { - if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->flags & DETECT_FLOW_FLAG_NOSTREAM && fd->match_cnt == 3) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", DETECT_FLOW_FLAG_ESTABLISHED + DETECT_FLOW_FLAG_TOCLIENT + DETECT_FLOW_FLAG_NOSTREAM, 3, - fd->flags, fd->match_cnt); - } - - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->flags & DETECT_FLOW_FLAG_NOSTREAM && + fd->match_cnt == 3); + DetectFlowFree(fd); + PASS; } /** @@ -1048,21 +850,14 @@ int DetectFlowTestParseNocase20 (void) */ int DetectFlowTestParse21 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,a,no_stream"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } static int DetectFlowSigTest01(void) { - int result = 0; ThreadVars th_v; DecodeThreadVars dtv; DetectEngineCtx *de_ctx = NULL; @@ -1071,10 +866,7 @@ static int DetectFlowSigTest01(void) uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); - if (p->flow != NULL) { - printf("packet has flow set\n"); - goto end; - } + FAIL_IF_NULL(p); char *sig1 = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; flow:no_stream; sid:1;)"; @@ -1083,29 +875,18 @@ static int DetectFlowSigTest01(void) memset(&th_v, 0, sizeof(th_v)); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("de_ctx == NULL: "); - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); - if (de_ctx->sig_list == NULL) { - printf("signature == NULL: "); - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) != 1) { - goto end; - } - - result = 1; + FAIL_IF(PacketAlertCheck(p, 1) != 1); - end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); @@ -1118,7 +899,7 @@ static int DetectFlowSigTest01(void) if (p != NULL) UTHFreePacket(p); - return result; + PASS; } #endif /* UNITTESTS */ From 571f56cfcf8fdd541b2a6d4d594afe749b55e2e9 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 11 Oct 2016 11:11:26 -0600 Subject: [PATCH 2103/2553] detect-flow: support flow:not_established --- src/detect-flow.c | 27 +++++++++++++++++++++++++++ src/detect-flow.h | 13 +++++++------ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/detect-flow.c b/src/detect-flow.c index 966d46957feb..64e3d9d38d7a 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -89,6 +89,8 @@ static inline int FlowMatch(const uint8_t pflowflags, const uint16_t tflags, if ((dflags & DETECT_FLOW_FLAG_ESTABLISHED) && (pflowflags & FLOW_PKT_ESTABLISHED)) { cnt++; + } else if (dflags & DETECT_FLOW_FLAG_NOT_ESTABLISHED && (!(pflowflags & FLOW_PKT_ESTABLISHED))) { + cnt++; } else if (dflags & DETECT_FLOW_FLAG_STATELESS) { cnt++; } @@ -207,6 +209,15 @@ DetectFlowData *DetectFlowParse (char *flowstr) goto error; } fd->flags |= DETECT_FLOW_FLAG_ESTABLISHED; + } else if (strcasecmp(args[i], "not_established") == 0) { + if (fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_NOT_ESTABLISHED flag is already set"); + goto error; + } else if (fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_NOT_ESTABLISHED, DETECT_FLOW_FLAG_ESTABLISHED already set"); + goto error; + } + fd->flags |= DETECT_FLOW_FLAG_NOT_ESTABLISHED; } else if (strcasecmp(args[i], "stateless") == 0) { if (fd->flags & DETECT_FLOW_FLAG_STATELESS) { SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_STATELESS flag is already set"); @@ -901,6 +912,20 @@ static int DetectFlowSigTest01(void) PASS; } + +/** + * \test Test parsing of the not_established keyword. + */ +static int DetectFlowTestParseNotEstablished(void) +{ + DetectFlowData *fd = NULL; + fd = DetectFlowParse("not_established"); + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED); + DetectFlowFree(fd); + PASS; +} + #endif /* UNITTESTS */ /** @@ -943,6 +968,8 @@ void DetectFlowRegisterTests(void) UtRegisterTest("DetectFlowTestParse20", DetectFlowTestParse20); UtRegisterTest("DetectFlowTestParseNocase20", DetectFlowTestParseNocase20); UtRegisterTest("DetectFlowTestParse21", DetectFlowTestParse21); + UtRegisterTest("DetectFlowTestParseNotEstablished", + DetectFlowTestParseNotEstablished); UtRegisterTest("DetectFlowSigTest01", DetectFlowSigTest01); #endif /* UNITTESTS */ diff --git a/src/detect-flow.h b/src/detect-flow.h index b3774c292f68..91139db4735b 100644 --- a/src/detect-flow.h +++ b/src/detect-flow.h @@ -24,12 +24,13 @@ #ifndef __DETECT_FLOW_H__ #define __DETECT_FLOW_H__ -#define DETECT_FLOW_FLAG_TOSERVER 0x01 -#define DETECT_FLOW_FLAG_TOCLIENT 0x02 -#define DETECT_FLOW_FLAG_ESTABLISHED 0x04 -#define DETECT_FLOW_FLAG_STATELESS 0x08 -#define DETECT_FLOW_FLAG_ONLYSTREAM 0x10 -#define DETECT_FLOW_FLAG_NOSTREAM 0x20 +#define DETECT_FLOW_FLAG_TOSERVER 0x01 +#define DETECT_FLOW_FLAG_TOCLIENT 0x02 +#define DETECT_FLOW_FLAG_ESTABLISHED 0x04 +#define DETECT_FLOW_FLAG_NOT_ESTABLISHED 0x08 +#define DETECT_FLOW_FLAG_STATELESS 0x10 +#define DETECT_FLOW_FLAG_ONLYSTREAM 0x20 +#define DETECT_FLOW_FLAG_NOSTREAM 0x40 typedef struct DetectFlowData_ { uint8_t flags; /* flags to match */ From f81619a13efeb08c4a744238a07a75dc7af7cd71 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 13 Oct 2016 12:08:40 -0600 Subject: [PATCH 2104/2553] defrag: set flag on packets reassembled from fragments Set the PKT_REBUILT_FRAGMENT on packets that are re-assembled from fragments. --- src/decode.h | 3 +++ src/defrag.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/decode.h b/src/decode.h index deebbe8cdfa4..9c6420389b07 100644 --- a/src/decode.h +++ b/src/decode.h @@ -1100,6 +1100,9 @@ int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder); #define PKT_PROTO_DETECT_TS_DONE (1<<23) #define PKT_PROTO_DETECT_TC_DONE (1<<24) +#define PKT_REBUILT_FRAGMENT (1<<25) /**< Packet is rebuilt from + * fragments. */ + /** \brief return 1 if the packet is a pseudo packet */ #define PKT_IS_PSEUDOPKT(p) ((p)->flags & PKT_PSEUDO_STREAM_END) diff --git a/src/defrag.c b/src/defrag.c index 68ac0886e935..c7ebd9f97649 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -294,6 +294,7 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) goto error_remove_tracker; } PKT_SET_SRC(rp, PKT_SRC_DEFRAG); + rp->flags |= PKT_REBUILT_FRAGMENT; rp->recursion_level = p->recursion_level; int fragmentable_offset = 0; From 8f56c234683551f9418377cd250c434938c08ddc Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 13 Oct 2016 11:31:21 -0600 Subject: [PATCH 2105/2553] detect-flow: no_frag and only_frag keyword support Support flow:no_frag and flow:only_frag keywords from Snort. --- src/detect-flow.c | 117 ++++++++++++++++++++++++++++++++++++++++++++-- src/detect-flow.h | 20 ++++---- 2 files changed, 124 insertions(+), 13 deletions(-) diff --git a/src/detect-flow.c b/src/detect-flow.c index 64e3d9d38d7a..3e3455c548cf 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -76,11 +76,26 @@ void DetectFlowRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -static inline int FlowMatch(const uint8_t pflowflags, const uint16_t tflags, - const uint8_t dflags, const uint8_t match_cnt) +/** + * \param pflags packet flags (p->flags) + * \param pflowflags packet flow flags (p->flowflags) + * \param tflags detection flags (det_ctx->flags) + * \param dflags detect flow flags + * \param match_cnt number of matches to trigger + */ +static inline int FlowMatch(const uint32_t pflags, const uint8_t pflowflags, + const uint16_t tflags, const uint16_t dflags, const uint8_t match_cnt) { uint8_t cnt = 0; + if ((dflags & DETECT_FLOW_FLAG_NO_FRAG) && + (!(pflags & PKT_REBUILT_FRAGMENT))) { + cnt++; + } else if ((dflags & DETECT_FLOW_FLAG_ONLY_FRAG) && + (pflags & PKT_REBUILT_FRAGMENT)) { + cnt++; + } + if ((dflags & DETECT_FLOW_FLAG_TOSERVER) && (pflowflags & FLOW_PKT_TOSERVER)) { cnt++; } else if ((dflags & DETECT_FLOW_FLAG_TOCLIENT) && (pflowflags & FLOW_PKT_TOCLIENT)) { @@ -135,7 +150,7 @@ int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S const DetectFlowData *fd = (const DetectFlowData *)ctx; - int ret = FlowMatch(p->flowflags, det_ctx->flags, fd->flags, fd->match_cnt);; + int ret = FlowMatch(p->flags, p->flowflags, det_ctx->flags, fd->flags, fd->match_cnt);; SCLogDebug("returning %" PRId32 " fd->match_cnt %" PRId32 " fd->flags 0x%02X p->flowflags 0x%02X", ret, fd->match_cnt, fd->flags, p->flowflags); SCReturnInt(ret); @@ -263,6 +278,24 @@ DetectFlowData *DetectFlowParse (char *flowstr) goto error; } fd->flags |= DETECT_FLOW_FLAG_NOSTREAM; + } else if (strcasecmp(args[i], "no_frag") == 0) { + if (fd->flags & DETECT_FLOW_FLAG_NO_FRAG) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_frag flag is already set"); + goto error; + } else if (fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_frag flag, only_frag already set"); + goto error; + } + fd->flags |= DETECT_FLOW_FLAG_NO_FRAG; + } else if (strcasecmp(args[i], "only_frag") == 0) { + if (fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_frag flag is already set"); + goto error; + } else if (fd->flags & DETECT_FLOW_FLAG_NO_FRAG) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_frag flag, no_frag already set"); + goto error; + } + fd->flags |= DETECT_FLOW_FLAG_ONLY_FRAG; } else { SCLogError(SC_ERR_INVALID_VALUE, "invalid flow option \"%s\"", args[i]); goto error; @@ -365,7 +398,7 @@ PrefilterPacketFlowMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void * if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) return; - if (FlowMatch(p->flowflags, det_ctx->flags, ctx->v1.u8[0], ctx->v1.u8[1])) + if (FlowMatch(p->flags, p->flowflags, det_ctx->flags, ctx->v1.u8[0], ctx->v1.u8[1])) { PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } @@ -926,6 +959,75 @@ static int DetectFlowTestParseNotEstablished(void) PASS; } +/** + * \test Test parsing of the "no_frag" flow argument. + */ +static int DetectFlowTestParseNoFrag(void) +{ + DetectFlowData *fd = NULL; + fd = DetectFlowParse("no_frag"); + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_NO_FRAG); + DetectFlowFree(fd); + PASS; +} + +/** + * \test Test parsing of the "only_frag" flow argument. + */ +static int DetectFlowTestParseOnlyFrag(void) +{ + DetectFlowData *fd = NULL; + fd = DetectFlowParse("only_frag"); + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG); + DetectFlowFree(fd); + PASS; +} + +/** + * \test Test that parsing of only_frag and no_frag together fails. + */ +static int DetectFlowTestParseNoFragOnlyFrag(void) +{ + DetectFlowData *fd = NULL; + fd = DetectFlowParse("no_frag,only_frag"); + FAIL_IF_NOT_NULL(fd); + PASS; +} + +/** + * \test Test no_frag matching. + */ +static int DetectFlowTestNoFragMatch(void) +{ + uint32_t pflags = 0; + DetectFlowData *fd = DetectFlowParse("no_frag"); + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_NO_FRAG); + FAIL_IF_NOT(fd->match_cnt == 1); + FAIL_IF_NOT(FlowMatch(pflags, 0, 0, fd->flags, fd->match_cnt)); + pflags |= PKT_REBUILT_FRAGMENT; + FAIL_IF(FlowMatch(pflags, 0, 0, fd->flags, fd->match_cnt)); + PASS; +} + +/** + * \test Test only_frag matching. + */ +static int DetectFlowTestOnlyFragMatch(void) +{ + uint32_t pflags = 0; + DetectFlowData *fd = DetectFlowParse("only_frag"); + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG); + FAIL_IF_NOT(fd->match_cnt == 1); + FAIL_IF(FlowMatch(pflags, 0, 0, fd->flags, fd->match_cnt)); + pflags |= PKT_REBUILT_FRAGMENT; + FAIL_IF_NOT(FlowMatch(pflags, 0, 0, fd->flags, fd->match_cnt)); + PASS; +} + #endif /* UNITTESTS */ /** @@ -970,6 +1072,13 @@ void DetectFlowRegisterTests(void) UtRegisterTest("DetectFlowTestParse21", DetectFlowTestParse21); UtRegisterTest("DetectFlowTestParseNotEstablished", DetectFlowTestParseNotEstablished); + UtRegisterTest("DetectFlowTestParseNoFrag", DetectFlowTestParseNoFrag); + UtRegisterTest("DetectFlowTestParseOnlyFrag", + DetectFlowTestParseOnlyFrag); + UtRegisterTest("DetectFlowTestParseNoFragOnlyFrag", + DetectFlowTestParseNoFragOnlyFrag); + UtRegisterTest("DetectFlowTestNoFragMatch", DetectFlowTestNoFragMatch); + UtRegisterTest("DetectFlowTestOnlyFragMatch", DetectFlowTestOnlyFragMatch); UtRegisterTest("DetectFlowSigTest01", DetectFlowSigTest01); #endif /* UNITTESTS */ diff --git a/src/detect-flow.h b/src/detect-flow.h index 91139db4735b..dc050b40d9a0 100644 --- a/src/detect-flow.h +++ b/src/detect-flow.h @@ -24,17 +24,19 @@ #ifndef __DETECT_FLOW_H__ #define __DETECT_FLOW_H__ -#define DETECT_FLOW_FLAG_TOSERVER 0x01 -#define DETECT_FLOW_FLAG_TOCLIENT 0x02 -#define DETECT_FLOW_FLAG_ESTABLISHED 0x04 -#define DETECT_FLOW_FLAG_NOT_ESTABLISHED 0x08 -#define DETECT_FLOW_FLAG_STATELESS 0x10 -#define DETECT_FLOW_FLAG_ONLYSTREAM 0x20 -#define DETECT_FLOW_FLAG_NOSTREAM 0x40 +#define DETECT_FLOW_FLAG_TOSERVER BIT_U16(0) +#define DETECT_FLOW_FLAG_TOCLIENT BIT_U16(1) +#define DETECT_FLOW_FLAG_ESTABLISHED BIT_U16(2) +#define DETECT_FLOW_FLAG_NOT_ESTABLISHED BIT_U16(3) +#define DETECT_FLOW_FLAG_STATELESS BIT_U16(4) +#define DETECT_FLOW_FLAG_ONLYSTREAM BIT_U16(5) +#define DETECT_FLOW_FLAG_NOSTREAM BIT_U16(6) +#define DETECT_FLOW_FLAG_NO_FRAG BIT_U16(7) +#define DETECT_FLOW_FLAG_ONLY_FRAG BIT_U16(8) typedef struct DetectFlowData_ { - uint8_t flags; /* flags to match */ - uint8_t match_cnt; /* number of matches we need */ + uint16_t flags; /* flags to match */ + uint8_t match_cnt; /* number of matches we need */ } DetectFlowData; /* prototypes */ From 1a724ba851b8c63c2d66232046b68da47a8de6fa Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 13 Oct 2016 13:53:27 -0600 Subject: [PATCH 2106/2553] doc: flow: update and add new keywords --- doc/userguide/rules/flow-keywords.rst | 73 +++++++++++++++------------ 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/doc/userguide/rules/flow-keywords.rst b/doc/userguide/rules/flow-keywords.rst index 75824db03c28..f9f354539b07 100644 --- a/doc/userguide/rules/flow-keywords.rst +++ b/doc/userguide/rules/flow-keywords.rst @@ -59,37 +59,48 @@ only (only_stream) or on packet only (no_stream). So with the flow keyword you can match on: -:: - - to_client established only_stream - from_client stateless no_stream - to_server - from_server - -**NOTE:** *from_server* and *to_client* are the same, and so are - *to_server* and _from_client_. This comes from the original Snort - language and we support it for compatibility reasons. - -These options can be combined. You can use -up to three options. For example: - -:: - - flow:to_client, established; - flow:from_client, established, only_stream; - -There are different ways in which can be checked whether the -connection is established or not. With tcp-traffic a connection starts -with the three-way-handshake. In the flow is a part in which the state -is set. There will be checked in which state the connection is. In -other cases there will be just checked if traffic comes from two -sides. - -Example: - -.. image:: flow-keywords/Flow1.png - -.. image:: flow-keywords/Flow2.png +to_client + Match on packets from server to client. +to_server + Match on packets from client to server. +from_client + Match on packets from client to server (same as to_server). +from_server + Match on packets from server to client (same as to_client). +established + Match on established connections. +not_established + Match on packets that are not part of an established connection. +stateless + Match on packets that are and are not part of an established connection. +only_stream + Match on packets that have been reassembled by the stream engine. +no_stream + Match on packets that have not been reassembled by the stream + engine. Will not match packets that have been reeassembled. +only_frag + Match packets that have been reassembled from fragments. +no_frag + Match packets that have not been reassembled from fragments. + +Multiple flow options can be combined, for example:: + + flow:to_client, established + flow:to_server, established, only_stream + flow:to_server, not_established, no_frag + +The determination of *established* depends on the protocol: + +* For TCP a connection will be established after a three way + handshake. + + .. image:: flow-keywords/Flow1.png + +* For other protocols (for example UDP), the connection will be + considered established after seeing traffic from both sides of the + connection. + + .. image:: flow-keywords/Flow2.png Flowint ~~~~~~~ From dcdf160ab2c99185ae605d93db6207bc648a4dfa Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 17 Oct 2016 12:56:35 -0600 Subject: [PATCH 2107/2553] conf: cleanup compiler warning (unintialized vars) --- src/conf.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/conf.c b/src/conf.c index d575d2734c97..606ef650834f 100644 --- a/src/conf.c +++ b/src/conf.c @@ -379,7 +379,7 @@ int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, */ int ConfGetInt(const char *name, intmax_t *val) { - char *strval; + char *strval = NULL; intmax_t tmpint; char *endptr; @@ -399,7 +399,7 @@ int ConfGetInt(const char *name, intmax_t *val) int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val) { - char *strval; + char *strval = NULL; intmax_t tmpint; char *endptr; @@ -441,7 +441,7 @@ int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, */ int ConfGetBool(const char *name, int *val) { - char *strval; + char *strval = NULL; *val = 0; if (ConfGet(name, &strval) != 1) @@ -454,7 +454,7 @@ int ConfGetBool(const char *name, int *val) int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val) { - char *strval; + char *strval = NULL; *val = 0; if (ConfGetChildValue(base, name, &strval) == 0) @@ -539,7 +539,7 @@ int ConfValIsFalse(const char *val) */ int ConfGetDouble(const char *name, double *val) { - char *strval; + char *strval = NULL; double tmpdo; char *endptr; @@ -569,7 +569,7 @@ int ConfGetDouble(const char *name, double *val) */ int ConfGetFloat(const char *name, float *val) { - char *strval; + char *strval = NULL; double tmpfl; char *endptr; From e072e70ea6b2be7ae335a08c835b6cb61f6ae2ef Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 18 Oct 2016 18:09:39 +0200 Subject: [PATCH 2108/2553] alert: fix rate_filter issues Fix rate_filter issues: if action was modified it wouldn't be logged in EVE. To address this pass the PacketAlert structure to the threshold code so it can flag the PacketAlert as modified. Use this in logging. Update API to use const where possible. Fix a timout issue that this uncovered. --- src/decode.h | 2 + src/detect-engine-address.c | 2 +- src/detect-engine-address.h | 2 +- src/detect-engine-alert.c | 17 +++-- src/detect-engine-threshold.c | 126 +++++++++++++--------------------- src/detect-engine-threshold.h | 6 +- src/output-json-alert.c | 16 +++-- 7 files changed, 74 insertions(+), 97 deletions(-) diff --git a/src/decode.h b/src/decode.h index 9c6420389b07..c4b686322cc6 100644 --- a/src/decode.h +++ b/src/decode.h @@ -274,6 +274,8 @@ typedef struct PacketAlert_ { #define PACKET_ALERT_FLAG_STREAM_MATCH 0x04 /** alert is in a tx, tx_id set */ #define PACKET_ALERT_FLAG_TX 0x08 +/** action was changed by rate_filter */ +#define PACKET_ALERT_RATE_FILTER_MODIFIED 0x10 #define PACKET_ALERT_MAX 15 diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 60964cd9c837..1a277c6e1793 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -1897,7 +1897,7 @@ void DetectAddressPrint(DetectAddress *gr) * \retval g On success pointer to an DetectAddress if we find a match * for the Address "a", in the DetectAddressHead "gh". */ -DetectAddress *DetectAddressLookupInHead(DetectAddressHead *gh, Address *a) +DetectAddress *DetectAddressLookupInHead(const DetectAddressHead *gh, Address *a) { SCEnter(); diff --git a/src/detect-engine-address.h b/src/detect-engine-address.h index dcbde2e4277b..8c5d1256f07f 100644 --- a/src/detect-engine-address.h +++ b/src/detect-engine-address.h @@ -44,7 +44,7 @@ void DetectAddressPrintList(DetectAddress *); int DetectAddressInsert(DetectEngineCtx *, DetectAddressHead *, DetectAddress *); int DetectAddressJoin(DetectEngineCtx *, DetectAddress *, DetectAddress *); -DetectAddress *DetectAddressLookupInHead(DetectAddressHead *, Address *); +DetectAddress *DetectAddressLookupInHead(const DetectAddressHead *, Address *); DetectAddress *DetectAddressLookupInList(DetectAddress *, DetectAddress *); int DetectAddressMatch(DetectAddress *, Address *); diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index f48da78023bd..2abff2212b8f 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -67,12 +67,12 @@ PacketAlert *PacketAlertGetTag(void) * \retval 0 alert is suppressed */ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Packet *p, uint16_t pos) + const Signature *s, Packet *p, PacketAlert *pa) { SCEnter(); int ret = 1; - DetectThresholdData *td = NULL; - SigMatch *sm; + const DetectThresholdData *td = NULL; + const SigMatch *sm; if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) { SCReturnInt(1); @@ -90,7 +90,7 @@ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det /* PacketAlertThreshold returns 2 if the alert is suppressed but * we do need to apply rule actions to the packet. */ KEYWORD_PROFILING_START; - ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s); + ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s, pa); if (ret == 0 || ret == 2) { KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 0); /* It doesn't match threshold, remove it */ @@ -113,7 +113,7 @@ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det /* PacketAlertThreshold returns 2 if the alert is suppressed but * we do need to apply rule actions to the packet. */ KEYWORD_PROFILING_START; - ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s); + ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s, pa); if (ret == 0 || ret == 2) { KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD ,0); /* It doesn't match threshold, remove it */ @@ -239,14 +239,13 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx { SCEnter(); int i = 0; - Signature *s = NULL; SigMatch *sm = NULL; while (i < p->alerts.cnt) { SCLogDebug("Sig->num: %"PRIu16, p->alerts.alerts[i].num); - s = de_ctx->sig_array[p->alerts.alerts[i].num]; + const Signature *s = de_ctx->sig_array[p->alerts.alerts[i].num]; - int res = PacketAlertHandle(de_ctx, det_ctx, s, p, i); + int res = PacketAlertHandle(de_ctx, det_ctx, s, p, &p->alerts.alerts[i]); if (res > 0) { /* Now, if we have an alert, we have to check if we want * to tag this session or src/dst host */ @@ -255,7 +254,7 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx while (sm) { /* tags are set only for alerts */ KEYWORD_PROFILING_START; - sigmatch_table[sm->type].Match(NULL, det_ctx, p, s, sm->ctx); + sigmatch_table[sm->type].Match(NULL, det_ctx, p, (Signature *)s, sm->ctx); KEYWORD_PROFILING_END(det_ctx, sm->type, 1); sm = sm->next; } diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index 2d37e55e7c38..6b0d21141f1c 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -98,10 +98,11 @@ int ThresholdHostHasThreshold(Host *host) * * */ -DetectThresholdData *SigGetThresholdTypeIter(Signature *sig, Packet *p, SigMatch **psm, int list) +const DetectThresholdData *SigGetThresholdTypeIter(const Signature *sig, + Packet *p, const SigMatch **psm, int list) { - SigMatch *sm = NULL; - DetectThresholdData *tsh = NULL; + const SigMatch *sm = NULL; + const DetectThresholdData *tsh = NULL; if (sig == NULL) return NULL; @@ -178,7 +179,9 @@ int ThresholdTimeoutCheck(Host *host, struct timeval *tv) return retval; } -static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, uint32_t sid, uint32_t gid) +static inline DetectThresholdEntry * +DetectThresholdEntryAlloc(const DetectThresholdData *td, Packet *p, + uint32_t sid, uint32_t gid) { SCEnter(); @@ -209,7 +212,7 @@ static DetectThresholdEntry *ThresholdHostLookupEntry(Host *h, uint32_t sid, uin return e; } -int ThresholdHandlePacketSuppress(Packet *p, DetectThresholdData *td, uint32_t sid, uint32_t gid) +int ThresholdHandlePacketSuppress(Packet *p, const DetectThresholdData *td, uint32_t sid, uint32_t gid) { int ret = 0; DetectAddress *m = NULL; @@ -244,12 +247,38 @@ int ThresholdHandlePacketSuppress(Packet *p, DetectThresholdData *td, uint32_t s return ret; } +static inline void RateFilterSetAction(Packet *p, PacketAlert *pa, uint8_t new_action) +{ + switch (new_action) { + case TH_ACTION_ALERT: + PACKET_ALERT(p); + pa->flags |= PACKET_ALERT_RATE_FILTER_MODIFIED; + break; + case TH_ACTION_DROP: + PACKET_DROP(p); + pa->flags |= PACKET_ALERT_RATE_FILTER_MODIFIED; + break; + case TH_ACTION_REJECT: + PACKET_REJECT(p); + pa->flags |= PACKET_ALERT_RATE_FILTER_MODIFIED; + break; + case TH_ACTION_PASS: + PACKET_PASS(p); + pa->flags |= PACKET_ALERT_RATE_FILTER_MODIFIED; + break; + default: + /* Weird, leave the default action */ + break; + } +} + /** * \retval 2 silent match (no alert but apply actions) * \retval 1 normal match * \retval 0 no match */ -int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint32_t sid, uint32_t gid) +int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdData *td, + uint32_t sid, uint32_t gid, PacketAlert *pa) { int ret = 0; @@ -426,23 +455,7 @@ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint3 } else { /* Already matching */ /* Take the action to perform */ - switch (td->new_action) { - case TH_ACTION_ALERT: - PACKET_ALERT(p); - break; - case TH_ACTION_DROP: - PACKET_DROP(p); - break; - case TH_ACTION_REJECT: - PACKET_REJECT(p); - break; - case TH_ACTION_PASS: - PACKET_PASS(p); - break; - default: - /* Weird, leave the default action */ - break; - } + RateFilterSetAction(p, pa, td->new_action); ret = 1; } /* else - if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) */ @@ -455,23 +468,7 @@ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint3 * timeout */ lookup_tsh->tv_timeout = p->ts.tv_sec; /* Take the action to perform */ - switch (td->new_action) { - case TH_ACTION_ALERT: - PACKET_ALERT(p); - break; - case TH_ACTION_DROP: - PACKET_DROP(p); - break; - case TH_ACTION_REJECT: - PACKET_REJECT(p); - break; - case TH_ACTION_PASS: - PACKET_PASS(p); - break; - default: - /* Weird, leave the default action */ - break; - } + RateFilterSetAction(p, pa, td->new_action); ret = 1; } } else { @@ -506,7 +503,8 @@ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint3 return ret; } -static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectThresholdData *td, Signature *s) +static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, + const DetectThresholdData *td, const Signature *s, PacketAlert *pa) { int ret = 0; @@ -519,27 +517,11 @@ static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectT * we still matching (and enabling the new_action) */ if ( (p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) { /* Ok, we are done, timeout reached */ - td->timeout = 0; + lookup_tsh->tv_timeout = 0; } else { /* Already matching */ /* Take the action to perform */ - switch (td->new_action) { - case TH_ACTION_ALERT: - PACKET_ALERT(p); - break; - case TH_ACTION_DROP: - PACKET_DROP(p); - break; - case TH_ACTION_REJECT: - PACKET_REJECT(p); - break; - case TH_ACTION_PASS: - PACKET_PASS(p); - break; - default: - /* Weird, leave the default action */ - break; - } + RateFilterSetAction(p, pa, td->new_action); ret = 1; } @@ -551,23 +533,7 @@ static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectT * timeout */ lookup_tsh->tv_timeout = p->ts.tv_sec; /* Take the action to perform */ - switch (td->new_action) { - case TH_ACTION_ALERT: - PACKET_ALERT(p); - break; - case TH_ACTION_DROP: - PACKET_DROP(p); - break; - case TH_ACTION_REJECT: - PACKET_REJECT(p); - break; - case TH_ACTION_PASS: - PACKET_PASS(p); - break; - default: - /* Weird, leave the default action */ - break; - } + RateFilterSetAction(p, pa, td->new_action); ret = 1; } } else { @@ -605,7 +571,7 @@ static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectT * \retval 0 do not alert on this event */ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - DetectThresholdData *td, Packet *p, Signature *s) + const DetectThresholdData *td, Packet *p, const Signature *s, PacketAlert *pa) { SCEnter(); @@ -619,18 +585,18 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx } else if (td->track == TRACK_SRC) { Host *src = HostGetHostFromHash(&p->src); if (src) { - ret = ThresholdHandlePacketHost(src,p,td,s->id,s->gid); + ret = ThresholdHandlePacketHost(src,p,td,s->id,s->gid,pa); HostRelease(src); } } else if (td->track == TRACK_DST) { Host *dst = HostGetHostFromHash(&p->dst); if (dst) { - ret = ThresholdHandlePacketHost(dst,p,td,s->id,s->gid); + ret = ThresholdHandlePacketHost(dst,p,td,s->id,s->gid,pa); HostRelease(dst); } } else if (td->track == TRACK_RULE) { SCMutexLock(&de_ctx->ths_ctx.threshold_table_lock); - ret = ThresholdHandlePacketRule(de_ctx,p,td,s); + ret = ThresholdHandlePacketRule(de_ctx,p,td,s,pa); SCMutexUnlock(&de_ctx->ths_ctx.threshold_table_lock); } diff --git a/src/detect-engine-threshold.h b/src/detect-engine-threshold.h index b874ecb2fa15..cef5f2058d89 100644 --- a/src/detect-engine-threshold.h +++ b/src/detect-engine-threshold.h @@ -33,9 +33,11 @@ void ThresholdInit(void); int ThresholdHostStorageId(void); int ThresholdHostHasThreshold(Host *); -DetectThresholdData *SigGetThresholdTypeIter(Signature *, Packet *, SigMatch **, int list); +const DetectThresholdData *SigGetThresholdTypeIter(const Signature *, + Packet *, const SigMatch **, int list); int PacketAlertThreshold(DetectEngineCtx *, DetectEngineThreadCtx *, - DetectThresholdData *, Packet *, Signature *); + const DetectThresholdData *, Packet *, + const Signature *, PacketAlert *); void ThresholdHashInit(DetectEngineCtx *); void ThresholdContextDestroy(DetectEngineCtx *); diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 1db766d61f7b..e4836f0a27d0 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -142,10 +142,18 @@ static void AlertJsonSsh(const Flow *f, json_t *js) void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js) { char *action = "allowed"; - if (pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) { - action = "blocked"; - } else if ((pa->action & ACTION_DROP) && EngineModeIsIPS()) { - action = "blocked"; + /* use packet action if rate_filter modified the action */ + if (unlikely(pa->flags & PACKET_ALERT_RATE_FILTER_MODIFIED)) { + if (PACKET_TEST_ACTION(p, (ACTION_DROP|ACTION_REJECT| + ACTION_REJECT_DST|ACTION_REJECT_BOTH))) { + action = "blocked"; + } + } else { + if (pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) { + action = "blocked"; + } else if ((pa->action & ACTION_DROP) && EngineModeIsIPS()) { + action = "blocked"; + } } /* Add tx_id to root element for correlation with other events. */ From 1aa70fb39e5581956cef99cc4ac3daef80e0454e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 18 Oct 2016 18:33:11 +0200 Subject: [PATCH 2109/2553] doc: add rate_filter --- .../configuration/global-thresholds.rst | 84 ++++++++++++++++++- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/doc/userguide/configuration/global-thresholds.rst b/doc/userguide/configuration/global-thresholds.rst index a5acbe406873..adb5cb8b47fe 100644 --- a/doc/userguide/configuration/global-thresholds.rst +++ b/doc/userguide/configuration/global-thresholds.rst @@ -6,7 +6,10 @@ Thresholds can be configured in the rules themselves, see their intel for creating a rule combined with a judgement on how often a rule will alert. -Next to these settings, thresholding can be configured on the sensor +Threshold Config +---------------- + +Next to rule thresholding more thresholding can be configured on the sensor using the threshold.config. threshold/event_filter @@ -16,12 +19,87 @@ Syntax: :: - threshold gen_id , sig_id , type , track , count , seconds + threshold gen_id , sig_id , type , \ + track , count , seconds rate_filter ~~~~~~~~~~~ -TODO +Rate filters allow changing of a rule action when a rule matches. + +Syntax:: + + rate_filter: rate_filter gen_id , sig_id , track , \ + count , seconds , new_action , timeout + +Example:: + + rate_filter gen_id 1, sig_id 1000, track by_rule, count 100, seconds 60, \ + new_action alert, timeout 30 + +gen_id +^^^^^^ +Generator id. Normally 1, but if a rule uses the ``gid`` keyword to set +another value it has to be matched in the ``gen_id``. + +sig_id +^^^^^^ + +Rule/signature id as set by the rule ``sid`` keyword. + +track +^^^^^ + +Where to track the rule matches. When using by_src/by_dst the tracking is +done per IP-address. The Host table is used for storage. When using by_rule +it's done globally for the rule. + +count +^^^^^ + +Number of rule hits before the ``rate_filter`` is activated. + +seconds +^^^^^^^ + +Time period within which the ``count`` needs to be reached to activate +the ``rate_filter`` + +new_action +^^^^^^^^^^ + +New action that is applied to matching traffic when the ``rate_filter`` +is in place. + +Values:: + + + +Note: 'sdrop' and 'log' are supported by the parser but not implemented otherwise. + +timeout +^^^^^^^ + +Time in seconds during which the ``rate_filter`` will remain active. + +Example +^^^^^^^ + +Lets say we want to limit incoming connections to our SSH server. The rule +``888`` below simply alerts on SYN packets to the SSH port of our SSH server. +If an IP-address triggers this more than 10 or more with a minute, the +drop ``rate_filter`` is set with a timeout of 5 minutes. + +Rule:: + + alert tcp any any -> $MY_SSH_SERVER 22 (msg:"Connection to SSH server"; \ + flow:to_server; flags:S,12; sid:888;) + +Rate filter:: + + rate_filter gen_id 1, sig_id 888, track by_src, count 10, seconds 60, \ + new_action drop, timeout 300 + suppress ~~~~~~~~ From 368d5d931c702e3606d139e08dea0fd4d82aa5b4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 19 Oct 2016 11:11:10 +0200 Subject: [PATCH 2110/2553] flow-timeout: don't leak flow reference in error path --- src/flow-timeout.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 8df85cddcd99..e62ccd4a2eff 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -122,7 +122,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, */ if (GET_PKT_DIRECT_MAX_SIZE(p) < 40) { if (PacketCallocExtPkt(p, 40) == -1) { - return NULL; + goto error; } } /* set the ip header */ @@ -167,7 +167,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, */ if (GET_PKT_DIRECT_MAX_SIZE(p) < 60) { if (PacketCallocExtPkt(p, 60) == -1) { - return NULL; + goto error; } } /* set the ip header */ @@ -256,6 +256,10 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, AppLayerParserSetEOF(f->alparser); return p; + +error: + FlowDeReference(&p->flow); + return NULL; } static inline Packet *FlowForceReassemblyPseudoPacketGet(int direction, From d1d618a668df1337cf1be268c640f5687f93fc6f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 19 Oct 2016 12:50:47 +0200 Subject: [PATCH 2111/2553] flow-manager: cleanups and comment improvements --- src/flow-manager.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index dece557ea15b..a1e78b82bb9a 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -258,8 +258,8 @@ static int FlowManagerFlowTimeout(const Flow *f, enum FlowState state, struct ti */ static int FlowManagerFlowTimedOut(Flow *f, struct timeval *ts) { - /** never prune a flow that is used by a packet or stream msg - * we are currently processing in one of the threads */ + /* never prune a flow that is used by a packet we + * are currently processing in one of the threads */ if (SC_ATOMIC_GET(f->use_cnt) > 0) { return 0; } @@ -369,14 +369,10 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, f->flow_end_flags |= FLOW_END_FLAG_EMERGENCY; f->flow_end_flags |= FLOW_END_FLAG_TIMEOUT; -// FlowClearMemory (f, f->protomap); - /* no one is referring to this flow, use_cnt 0, removed from hash - * so we can unlock it and move it back to the spare queue. */ + * so we can unlock it and pass it to the flow recycler */ FLOWLOCK_UNLOCK(f); FlowEnqueue(&flow_recycle_q, f); - /* move to spare list */ -// FlowMoveToSpare(f); cnt++; From 7e54ee7d0e7dac51c7436724961fdba78af85561 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 19 Oct 2016 12:52:46 +0200 Subject: [PATCH 2112/2553] flow-timeout: fix memory errors on flow bypass For flow bypass, the flow timeout handling is triggered which may create up to 3 pseudo packets that hold a reference to the flow. However, in the bypass case the code signaled to the timeout logic that the flow can be freed unconditionally by returning 1. This lead to packets going through the engine with a pointer to a now freed/recycled flow. This patch fixes the logic by removing the special bypass case, which seemed redundant anyway. Effectively reverts 68d9677. Bug #1928. --- src/flow-manager.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index a1e78b82bb9a..87292d876d5b 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -266,15 +266,6 @@ static int FlowManagerFlowTimedOut(Flow *f, struct timeval *ts) int server = 0, client = 0; - int state = SC_ATOMIC_GET(f->flow_state); - if ((state == FLOW_STATE_LOCAL_BYPASSED) || - (state == FLOW_STATE_CAPTURE_BYPASSED)) { - if (FlowForceReassemblyNeedReassembly(f, &server, &client) == 1) { - FlowForceReassemblyForFlow(f, server, client); - } - return 1; - } - if (!(f->flags & FLOW_TIMEOUT_REASSEMBLY_DONE) && FlowForceReassemblyNeedReassembly(f, &server, &client) == 1) { FlowForceReassemblyForFlow(f, server, client); From 397c541c09aa8dd6c221fa215ce922b70ab73ab1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 22 Oct 2016 22:14:10 +0200 Subject: [PATCH 2113/2553] detect: fix multi-tenant loaders --- src/detect-engine-loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-loader.c b/src/detect-engine-loader.c index f88cc99850d7..0e10edc41ac6 100644 --- a/src/detect-engine-loader.c +++ b/src/detect-engine-loader.c @@ -150,7 +150,7 @@ void TmThreadWakeupDetectLoaderThreads() for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { - if (strcmp(tv->name,"DetectLoader") == 0) { + if (strncmp(tv->name,"DL#",3) == 0) { BUG_ON(tv->ctrl_cond == NULL); pthread_cond_broadcast(tv->ctrl_cond); } @@ -174,7 +174,7 @@ void TmThreadContinueDetectLoaderThreads() for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { - if (strcmp(tv->name,"DetectLoader") == 0) + if (strncmp(tv->name,"DL#",3) == 0) TmThreadContinue(tv); tv = tv->next; From 0d4b93cafde51332bf2b36fb9ab98e9bf181a954 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Oct 2016 08:58:32 +0200 Subject: [PATCH 2114/2553] tls-rules: install on 'make install-full' --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 55c93e61f0cf..e71290c4b85f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,6 +41,7 @@ endif @test -e "$(DESTDIR)$(e_sysconfrulesdir)smtp-events.rules" || install -m 600 "$(top_srcdir)/rules/smtp-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @test -e "$(DESTDIR)$(e_sysconfrulesdir)http-events.rules" || install -m 600 "$(top_srcdir)/rules/http-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @test -e "$(DESTDIR)$(e_sysconfrulesdir)dns-events.rules" || install -m 600 "$(top_srcdir)/rules/dns-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)tls-events.rules" || install -m 600 "$(top_srcdir)/rules/tls-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @test -e "$(DESTDIR)$(e_sysconfrulesdir)modbus-events.rules" || install -m 600 "$(top_srcdir)/rules/modbus-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @test -e "$(DESTDIR)$(e_sysconfrulesdir)app-layer-events.rules" || install -m 600 "$(top_srcdir)/rules/app-layer-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @echo "" From e0000eb58da21eb04c9e85a3f942c642e579b9da Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 12 Oct 2016 22:18:12 +0200 Subject: [PATCH 2115/2553] source-nfq: fix tunnel mark callback algorithm In case of a tunnel packet, adding a mark to the root packet will have for consequence to bypass all the flows that are hosted in this tunnel. This is not the attended behavior and as initial fix let's simply warn suricata that bypass for NFQ is not possible for this kind of packets. This patch also fixes a segfault. The root packet was accessed even if it is NULL causing a NULL dereference: ASAN:SIGSEGV ================================================================= ==24408==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000060 (pc 0x00000076f948 bp 0x7f435c000240 sp 0x7f435c000220 T5) ASAN:SIGSEGV ==24408==AddressSanitizer: while reporting a bug found another one. Ignoring. #0 0x76f947 in NFQBypassCallback /home/victor/dev/suricata/src/source-nfq.c:510 #1 0x4d0f02 in PacketBypassCallback /home/victor/dev/suricata/src/decode.c:395 #2 0x7b8a95 in StreamTcpPacket /home/victor/dev/suricata/src/stream-tcp.c:4661 #3 0x7b9ddd in StreamTcp /home/victor/dev/suricata/src/stream-tcp.c:4913 #4 0x68fa50 in FlowWorker /home/victor/dev/suricata/src/flow-worker.c:194 #5 0x7f0abd in TmThreadsSlotVarRun /home/victor/dev/suricata/src/tm-threads.c:128 #6 0x7f2958 in TmThreadsSlotVar /home/victor/dev/suricata/src/tm-threads.c:585 #7 0x7f436368e6f9 in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x76f9) #8 0x7f4362802b5c in clone (/lib/x86_64-linux-gnu/libc.so.6+0x106b5c) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV /home/victor/dev/suricata/src/source-nfq.c:510 NFQBypassCallback Thread T5 (W#04) created by T0 (Suricata-Main) here: #0 0x7f4364ff2253 in pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x36253) #1 0x7f9c48 in TmThreadSpawn /home/victor/dev/suricata/src/tm-threads.c:1843 #2 0x8da7c0 in RunModeSetIPSAutoFp /home/victor/dev/suricata/src/util-runmodes.c:519 #3 0x73e3ff in RunModeIpsNFQAutoFp /home/victor/dev/suricata/src/runmode-nfq.c:74 #4 0x7503fa in RunModeDispatch /home/victor/dev/suricata/src/runmodes.c:382 #5 0x7e5cb3 in main /home/victor/dev/suricata/src/suricata.c:2547 #6 0x7f436271c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) --- src/source-nfq.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/source-nfq.c b/src/source-nfq.c index e84e32d8fc0d..1f208585da8c 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -504,14 +504,7 @@ static void NFQReleasePacket(Packet *p) static int NFQBypassCallback(Packet *p) { if (IS_TUNNEL_PKT(p)) { - SCMutex *m = p->root ? &p->root->tunnel_mutex : &p->tunnel_mutex; - SCMutexLock(m); - - p->root->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) - | (p->nfq_v.mark & ~nfq_config.bypass_mask); - p->root->flags |= PKT_MARK_MODIFIED; - - SCMutexUnlock(m); + return 0; } else { p->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) | (p->nfq_v.mark & ~nfq_config.bypass_mask); From d8acf3542dec7265f4da7d33e22f3de2c3a39596 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 19 Oct 2016 22:05:25 +0200 Subject: [PATCH 2116/2553] source-nfq: document bypass function --- src/source-nfq.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/source-nfq.c b/src/source-nfq.c index 1f208585da8c..344c5096dab5 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -501,6 +501,12 @@ static void NFQReleasePacket(Packet *p) PacketFreeOrRelease(p); } +/** + * \brief bypass callback function for NFQ + * + * \param p a Packet to use information from to trigger bypass + * \return 1 if bypass is successful, 0 if not + */ static int NFQBypassCallback(Packet *p) { if (IS_TUNNEL_PKT(p)) { From 629fa3034587ef8010e4f559ffa03dcfaa4b626d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Oct 2016 14:25:55 +0200 Subject: [PATCH 2117/2553] nfq_set_mask: set mark on root pkt for tunnels --- src/detect-mark.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/detect-mark.c b/src/detect-mark.c index b298ccfe7faa..b2326f98dc5d 100644 --- a/src/detect-mark.c +++ b/src/detect-mark.c @@ -222,9 +222,23 @@ int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S #ifdef NFQ const DetectMarkData *nf_data = (const DetectMarkData *)ctx; if (nf_data->mask) { - p->nfq_v.mark = (nf_data->mark & nf_data->mask) - | (p->nfq_v.mark & ~(nf_data->mask)); - p->flags |= PKT_MARK_MODIFIED; + if (!(IS_TUNNEL_PKT(p))) { + p->nfq_v.mark = (nf_data->mark & nf_data->mask) + | (p->nfq_v.mark & ~(nf_data->mask)); + p->flags |= PKT_MARK_MODIFIED; + } else { + /* real tunnels may have multiple flows inside them, so marking + * might 'mark' too much. Rebuilt packets from IP fragments + * are fine. */ + if (p->flags & PKT_REBUILT_FRAGMENT) { + Packet *tp = p->root ? p->root : p; + SCMutexLock(&tp->tunnel_mutex); + tp->nfq_v.mark = (nf_data->mark & nf_data->mask) + | (tp->nfq_v.mark & ~(nf_data->mask)); + tp->flags |= PKT_MARK_MODIFIED; + SCMutexUnlock(&tp->tunnel_mutex); + } + } } #endif return 1; From e4b2729399d2fbd1499983006f75017e74dfc131 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Oct 2016 14:31:41 +0200 Subject: [PATCH 2118/2553] nfq: support bypass for rebuilt fragment packets --- src/source-nfq.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/source-nfq.c b/src/source-nfq.c index 344c5096dab5..2c82f591fbff 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -510,6 +510,17 @@ static void NFQReleasePacket(Packet *p) static int NFQBypassCallback(Packet *p) { if (IS_TUNNEL_PKT(p)) { + /* real tunnels may have multiple flows inside them, so bypass can't + * work for those. Rebuilt packets from IP fragments are fine. */ + if (p->flags & PKT_REBUILT_FRAGMENT) { + Packet *tp = p->root ? p->root : p; + SCMutexLock(&tp->tunnel_mutex); + tp->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) + | (tp->nfq_v.mark & ~nfq_config.bypass_mask); + tp->flags |= PKT_MARK_MODIFIED; + SCMutexUnlock(&tp->tunnel_mutex); + return 1; + } return 0; } else { p->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) From 321fb6463e0e8e6cf20c53dfdc28f83fc1b7e7de Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 20 Oct 2016 14:21:53 +0200 Subject: [PATCH 2119/2553] vars: small cleanups --- src/detect.c | 2 +- src/util-var-name.c | 7 +++---- src/util-var-name.h | 6 ++++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/detect.c b/src/detect.c index cd0d226d035f..6c1c907798f9 100644 --- a/src/detect.c +++ b/src/detect.c @@ -876,7 +876,7 @@ static void AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(Packet *p, DetectEn } FlowBit *fb = (FlowBit *) gv; - char *name = VariableIdxGetName(de_ctx, fb->idx, VAR_TYPE_FLOW_BIT); + const char *name = VariableIdxGetName(de_ctx, fb->idx, VAR_TYPE_FLOW_BIT); if (name != NULL) { p->debuglog_flowbits_names[i] = SCStrdup(name); if (p->debuglog_flowbits_names[i] == NULL) { diff --git a/src/util-var-name.c b/src/util-var-name.c index 91322189780a..73f87d3daded 100644 --- a/src/util-var-name.c +++ b/src/util-var-name.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -31,7 +31,6 @@ typedef struct VariableName_ { char *name; uint8_t type; /* flowbit, pktvar, etc */ - uint8_t flags; uint16_t idx; } VariableName; @@ -135,7 +134,7 @@ void VariableNameFreeHash(DetectEngineCtx *de_ctx) * \retval 0 in case of error * \retval idx the idx or 0 */ -uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, char *name, enum VarTypes type) +uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, const char *name, enum VarTypes type) { uint16_t idx = 0; @@ -174,7 +173,7 @@ uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, char *name, enum VarTypes t * \retval NULL in case of error * \retval name of the variable if successful. */ -char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, enum VarTypes type) +const char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, enum VarTypes type) { VariableName *fn = SCMalloc(sizeof(VariableName)); if (unlikely(fn == NULL)) diff --git a/src/util-var-name.h b/src/util-var-name.h index 2be142689ae9..7d2c527a31af 100644 --- a/src/util-var-name.h +++ b/src/util-var-name.h @@ -27,8 +27,10 @@ int VariableNameInitHash(DetectEngineCtx *); void VariableNameFreeHash(DetectEngineCtx *); -uint16_t VariableNameGetIdx(DetectEngineCtx *, char *, enum VarTypes); -char * VariableIdxGetName(DetectEngineCtx *, uint16_t , enum VarTypes); +uint16_t VariableNameGetIdx(DetectEngineCtx *, + const char *name, enum VarTypes type); +const char *VariableIdxGetName(DetectEngineCtx *, + uint16_t id, enum VarTypes type); #endif From 059b25b56474ffe3cc0f1811056a99ef321c75cb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 26 Oct 2016 10:34:28 +0200 Subject: [PATCH 2120/2553] detect: suppress debug message for reloads --- src/detect-engine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 52bee574fea1..d6584fb72cdf 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -502,8 +502,8 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) /* threads now all have new data, however they may not have started using * it and may still use the old data */ - SCLogInfo("Live rule swap has swapped %d old det_ctx's with new ones, " - "along with the new de_ctx", no_of_detect_tvs); + SCLogDebug("Live rule swap has swapped %d old det_ctx's with new ones, " + "along with the new de_ctx", no_of_detect_tvs); InjectPackets(detect_tvs, new_det_ctx, no_of_detect_tvs); From 51bb1f0d7774351d00c6c1257cc20603ae18391c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Oct 2016 20:58:53 +0200 Subject: [PATCH 2121/2553] multi-tenants: fix minor memleak --- src/detect-engine-loader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect-engine-loader.c b/src/detect-engine-loader.c index 0e10edc41ac6..1c4ad0872be3 100644 --- a/src/detect-engine-loader.c +++ b/src/detect-engine-loader.c @@ -241,6 +241,7 @@ static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data) int r = task->Func(task->ctx, ftd->instance); loader->result |= r; TAILQ_REMOVE(&loader->task_list, task, next); + SCFree(task->ctx); SCFree(task); } From db1c47cb6e5cea4db5828fac9fa5396d85df6e8a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 26 Oct 2016 10:33:55 +0200 Subject: [PATCH 2122/2553] multi-tenant: make less verbose --- src/detect-engine.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index d6584fb72cdf..0dea5da9ae73 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1175,7 +1175,7 @@ static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThread /* set up hash for tenant lookup */ list = master->list; while (list) { - SCLogInfo("tenant-id %u", list->tenant_id); + SCLogDebug("tenant-id %u", list->tenant_id); if (list->tenant_id != 0) { DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0); if (mt_det_ctx == NULL) @@ -1729,7 +1729,7 @@ static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *f char prefix[64]; snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt); reload_cnt++; - SCLogInfo("prefix %s", prefix); + SCLogDebug("prefix %s", prefix); if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { SCLogError(SC_ERR_INITIALIZATION,"failed to load yaml"); @@ -1891,7 +1891,7 @@ int DetectEngineMultiTenantSetup(void) char *handler = NULL; if (ConfGet("multi-detect.selector", &handler) == 1) { - SCLogInfo("multi-tenant selector type %s", handler); + SCLogConfig("multi-tenant selector type %s", handler); if (strcmp(handler, "vlan") == 0) { tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN; @@ -1914,7 +1914,7 @@ int DetectEngineMultiTenantSetup(void) } } SCMutexUnlock(&master->lock); - SCLogInfo("multi-detect is enabled (multi tenancy). Selector: %s", handler); + SCLogConfig("multi-detect is enabled (multi tenancy). Selector: %s", handler); /* traffic -- tenant mappings */ ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings"); @@ -1956,7 +1956,7 @@ int DetectEngineMultiTenantSetup(void) if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) { goto error; } - SCLogInfo("vlan %u connected to tenant-id %u", vlan_id, tenant_id); + SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id); mapping_cnt++; continue; @@ -2007,7 +2007,7 @@ int DetectEngineMultiTenantSetup(void) "of %s is invalid", id_node->val); goto bad_tenant; } - SCLogInfo("tenant id: %u, %s", tenant_id, yaml_node->val); + SCLogDebug("tenant id: %u, %s", tenant_id, yaml_node->val); /* setup the yaml in this loop so that it's not done by the loader * threads. ConfYamlLoadFileWithPrefix is not thread safe. */ From 2d4df19401968a56754b8f1acfd9613792003feb Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 25 Oct 2016 14:13:31 -0600 Subject: [PATCH 2123/2553] tcp dns: fix advancement to next request in buffer The advancement through the buffer was not taking into account the size of the length field resulting in the second request being detected as bad data. --- src/app-layer-dns-tcp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index dbce7ce30a8d..1449eb4c5012 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -321,8 +321,8 @@ static int DNSTCPRequestParse(Flow *f, void *dstate, goto bad_data; /* treat the rest of the data as a (potential) new record */ - input += ntohs(dns_tcp_header->len); - input_len -= ntohs(dns_tcp_header->len); + input += (2 + ntohs(dns_tcp_header->len)); + input_len -= (2 + ntohs(dns_tcp_header->len)); goto next_record; } else { /* not enough data, store record length and buffer */ @@ -534,8 +534,8 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, goto bad_data; /* treat the rest of the data as a (potential) new record */ - input += ntohs(dns_tcp_header->len); - input_len -= ntohs(dns_tcp_header->len); + input += (2 + ntohs(dns_tcp_header->len)); + input_len -= (2 + ntohs(dns_tcp_header->len)); goto next_record; } else { /* not enough data, store record length and buffer */ From 64cc91a569fd78550fe64d7dc3fe0985945d0eb2 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 26 Oct 2016 09:48:42 -0600 Subject: [PATCH 2124/2553] tcp dns: unit test for multi-request buffer --- src/app-layer-dns-tcp.c | 122 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 2 deletions(-) diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 1449eb4c5012..73637c5770d0 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -674,13 +674,131 @@ void RegisterDNSTCPParsers(void) "still on.", proto_name); } +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_DNS, + DNSTCPParserRegisterTests); +#endif + return; } /* UNITTESTS */ #ifdef UNITTESTS + +#include "util-unittest-helper.h" + +static int DNSTCPParserTestMultiRecord(void) +{ + /* This is a buffer containing 20 DNS requests each prefixed by + * the request length for transport over TCP. It was generated with Scapy, + * where each request is: + * DNS(id=i, rd=1, qd=DNSQR(qname="%d.google.com" % i, qtype="A")) + * where i is 0 to 19. + */ + uint8_t req[] = { + 0x00, 0x1e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x31, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x03, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x04, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x34, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x35, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x06, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x36, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x07, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x37, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x08, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x09, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x39, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1f, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, + 0x30, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x1f, 0x00, 0x0b, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x31, 0x31, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0c, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x31, 0x32, 0x06, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0d, 0x01, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x31, 0x33, 0x06, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0e, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x31, 0x34, 0x06, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00, + 0x0f, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x31, 0x35, 0x06, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, + 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f, + 0x00, 0x10, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x36, 0x06, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, + 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x1f, 0x00, 0x11, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x37, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1f, 0x00, 0x12, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, + 0x38, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x1f, 0x00, 0x13, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x31, 0x39, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, + 0x00, 0x01 + }; + size_t reqlen = sizeof(req); + + DNSState *state = DNSStateAlloc(); + FAIL_IF_NULL(state); + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); + FAIL_IF_NULL(f); + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_DNS; + f->alstate = state; + + FAIL_IF_NOT(DNSTCPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF(state->transaction_max != 20); + + UTHFreeFlow(f); + PASS; +} + void DNSTCPParserRegisterTests(void) { -// UtRegisterTest("DNSTCPParserTest01", DNSTCPParserTest01, 1); + UtRegisterTest("DNSTCPParserTestMultiRecord", DNSTCPParserTestMultiRecord); } -#endif + +#endif /* UNITTESTS */ From a8f6fb0f78448c4cd757d99361a2ee83fcb84ed1 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 25 Oct 2016 00:13:07 -0600 Subject: [PATCH 2125/2553] dns: support back to back requests without a response Address the issue where a DNS response would not be logged when the traffic is like: - Request 1 - Request 2 - Response 1 - Response 2 which can happen on dual stack machines where the request for A and AAAA are sent out at the same time on the same UDP "session". A "window" is used to set the maximum number of outstanding responses before considering the olders lost. --- src/app-layer-dns-common.c | 25 ++-- src/app-layer-dns-common.h | 7 ++ src/app-layer-dns-tcp.c | 19 +++ src/app-layer-dns-udp.c | 249 +++++++++++++++++++++++++++++++++++++ 4 files changed, 284 insertions(+), 16 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 8c5bc02affa0..31ed2c26852c 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -392,6 +392,9 @@ DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16 TAILQ_FOREACH(tx, &dns_state->tx_list, next) { if (tx->tx_id == tx_id) { return tx; + } else if ((dns_state->transaction_max - tx->tx_num) > + (dns_state->window - 1U)) { + tx->reply_lost = 1; } } } @@ -554,19 +557,11 @@ void DNSStoreQueryInState(DNSState *dns_state, const uint8_t *fqdn, const uint16 return; } - /* see if the last tx is unreplied */ - if (dns_state->curr != tx && dns_state->curr != NULL && - dns_state->curr->replied == 0) - { - dns_state->curr->reply_lost = 1; - dns_state->unreplied_cnt++; - - /* check flood limit */ - if (dns_config.request_flood != 0 && - dns_state->unreplied_cnt > dns_config.request_flood) { - DNSSetEvent(dns_state, DNS_DECODER_EVENT_FLOODED); - dns_state->givenup = 1; - } + /* check flood limit */ + if (dns_config.request_flood != 0 && + dns_state->unreplied_cnt > dns_config.request_flood) { + DNSSetEvent(dns_state, DNS_DECODER_EVENT_FLOODED); + dns_state->givenup = 1; } if (tx == NULL) { @@ -579,6 +574,7 @@ void DNSStoreQueryInState(DNSState *dns_state, const uint8_t *fqdn, const uint16 dns_state->curr = tx; tx->tx_num = dns_state->transaction_max; SCLogDebug("new tx %u with internal id %u", tx->tx_id, tx->tx_num); + dns_state->unreplied_cnt++; } if (DNSCheckMemcap((sizeof(DNSQueryEntry) + fqdn_len), dns_state) < 0) @@ -645,9 +641,6 @@ void DNSStoreAnswerInState(DNSState *dns_state, const int rtype, const uint8_t * /* mark tx is as replied so we can log it */ tx->replied = 1; - - /* reset unreplied counter */ - dns_state->unreplied_cnt = 0; } /** \internal diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index 184fb26408d7..bc20907f6f48 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -218,6 +218,13 @@ typedef struct DNSState_ { state-memcap settings */ uint64_t tx_with_detect_state_cnt; + struct timeval last_req; /**< Timestamp of last request. */ + struct timeval last_resp; /**< Timestamp of last response. */ + + uint16_t window; /**< Window of allowed unreplied + * requests. Set by the maximum + * number of subsequent requests + * without a response. */ uint16_t events; uint16_t givenup; diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 73637c5770d0..d22ab923f54d 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -196,6 +196,14 @@ static int DNSRequestParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu //PrintRawDataFp(stdout, (uint8_t*)data, input_len - (data - input)); + if (dns_state != NULL) { + if (timercmp(&dns_state->last_req, &dns_state->last_resp, >=)) { + if (dns_state->window <= dns_state->unreplied_cnt) { + dns_state->window++; + } + } + } + for (q = 0; q < ntohs(dns_header->questions); q++) { uint8_t fqdn[DNS_MAX_SIZE]; uint16_t fqdn_offset = 0; @@ -355,6 +363,10 @@ static int DNSTCPRequestParse(Flow *f, void *dstate, goto bad_data; } + if (dns_state != NULL && f != NULL) { + dns_state->last_req = f->lastts; + } + SCReturnInt(1); insufficient_data: SCReturnInt(-1); @@ -377,6 +389,8 @@ static int DNSReponseParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu if (!found) { SCLogDebug("DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE"); DNSSetEvent(dns_state, DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE); + } else if (dns_state->unreplied_cnt > 0) { + dns_state->unreplied_cnt--; } uint16_t q; @@ -567,6 +581,11 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, if (r < 0) goto bad_data; } + + if (dns_state != NULL && f != NULL) { + dns_state->last_req = f->lastts; + } + SCReturnInt(1); insufficient_data: SCReturnInt(-1); diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index f2636df48ab6..e34c4b146076 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -81,6 +81,14 @@ static int DNSUDPRequestParse(Flow *f, void *dstate, if (DNSValidateRequestHeader(dns_state, dns_header) < 0) goto bad_data; + if (dns_state != NULL) { + if (timercmp(&dns_state->last_req, &dns_state->last_resp, >=)) { + if (dns_state->window <= dns_state->unreplied_cnt) { + dns_state->window++; + } + } + } + uint16_t q; const uint8_t *data = input + sizeof(DNSHeader); for (q = 0; q < ntohs(dns_header->questions); q++) { @@ -151,6 +159,10 @@ static int DNSUDPRequestParse(Flow *f, void *dstate, } } + if (dns_state != NULL && f != NULL) { + dns_state->last_req = f->lastts; + } + SCReturnInt(1); bad_data: insufficient_data: @@ -196,6 +208,8 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, if (!found) { SCLogDebug("DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE"); DNSSetEvent(dns_state, DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE); + } else if (dns_state->unreplied_cnt > 0) { + dns_state->unreplied_cnt--; } if (DNSValidateResponseHeader(dns_state, dns_header) < 0) @@ -300,6 +314,9 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, tx->replied = 1; } + if (dns_state != NULL && f != NULL) { + dns_state->last_resp = f->lastts; + } SCReturnInt(1); bad_data: @@ -627,6 +644,233 @@ static int DNSUDPParserTest05 (void) return (result); } +/** + * \test Test subsequent requests before response. + * + * This test sends 2 DNS requests on the same state then sends the response + * to the first request checking that it is seen and associated with the + * transaction. + */ +static int DNSUDPParserTestDelayedResponse(void) +{ + /* DNS request: + * - Flags: 0x0100 Standard query + * - A www.google.com + */ + uint8_t req[] = { + 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + }; + size_t reqlen = sizeof(req); + + /* DNS response: + * - Flags: 0x8180 Standard query response, no error + * - www.google.com A 24.244.4.56 + * - www.google.com A 24.244.4.54 + * - www.google.com A 24.244.4.57 + * - www.google.com A 24.244.4.55 + * - www.google.com A 24.244.4.52 + * - www.google.com A 24.244.4.53 + * - www.google.com A 24.244.4.58 + * - www.google.com A 24.244.4.59 + */ + uint8_t res[] = { + 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x38, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x39, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x34, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x35, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x36, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3b, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x37, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3a + }; + size_t reslen = sizeof(res); + + DNSState *state = DNSStateAlloc(); + FAIL_IF_NULL(state); + Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 53); + FAIL_IF_NULL(f); + f->proto = IPPROTO_UDP; + f->alproto = ALPROTO_DNS; + f->alstate = state; + + /* Send to requests with an incrementing tx id. */ + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + req[1] = 0x02; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + + /* Send response to the first request. */ + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, res, reslen, NULL)); + DNSTransaction *tx = TAILQ_FIRST(&state->tx_list); + FAIL_IF_NULL(tx); + FAIL_IF_NOT(tx->replied); + + /* Also free's state. */ + UTHFreeFlow(f); + + PASS; +} + +/** + * \test Test entering the flood/givenup state. + */ +static int DNSUDPParserTestFlood(void) +{ + /* DNS request: + * - Flags: 0x0100 Standard query + * - A www.google.com + */ + uint8_t req[] = { + 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + }; + size_t reqlen = sizeof(req); + + DNSState *state = DNSStateAlloc(); + FAIL_IF_NULL(state); + Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 53); + FAIL_IF_NULL(f); + f->proto = IPPROTO_UDP; + f->alproto = ALPROTO_DNS; + f->alstate = state; + + uint16_t txid; + for (txid = 1; txid <= DNS_CONFIG_DEFAULT_REQUEST_FLOOD + 1; txid++) { + req[0] = (txid >> 8) & 0xff; + req[1] = txid & 0xff; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF(state->givenup); + } + + /* With one more request we should enter a flooded state. */ + txid++; + req[0] = (txid >> 8) & 0xff; + req[1] = txid & 0xff; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF(!state->givenup); + + /* Also free's state. */ + UTHFreeFlow(f); + + PASS; +} + +static int DNSUDPParserTestLostResponse(void) +{ + /* DNS request: + * - Flags: 0x0100 Standard query + * - A www.google.com + */ + uint8_t req[] = { + 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + }; + size_t reqlen = sizeof(req); + + uint8_t res[] = { + 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x38, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x39, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x34, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x35, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x36, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3b, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x37, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3a + }; + size_t reslen = sizeof(res); + + DNSTransaction *tx; + DNSState *state = DNSStateAlloc(); + FAIL_IF_NULL(state); + Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 53); + FAIL_IF_NULL(f); + f->proto = IPPROTO_UDP; + f->alproto = ALPROTO_DNS; + f->alstate = state; + + /* First request. */ + req[1] = 0x01; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF_NOT(state->transaction_max == 1); + FAIL_IF_NOT(state->unreplied_cnt == 1); + FAIL_IF_NOT(state->window == 1); + + /* Second request. */ + req[1] = 0x02; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF_NOT(state->transaction_max == 2); + FAIL_IF_NOT(state->unreplied_cnt == 2); + FAIL_IF_NOT(state->window == 2); + + /* Third request. */ + req[1] = 0x03; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF_NOT(state->transaction_max == 3); + FAIL_IF_NOT(state->unreplied_cnt == 3); + FAIL_IF_NOT(state->window == 3); + + /* Now respond to the second. */ + res[1] = 0x02; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, res, reslen, NULL)); + FAIL_IF_NOT(state->unreplied_cnt == 2); + FAIL_IF_NOT(state->window == 3); + tx = TAILQ_FIRST(&state->tx_list); + FAIL_IF_NULL(tx); + FAIL_IF(tx->replied); + FAIL_IF(tx->reply_lost); + + /* Send a 4th request. */ + req[1] = 0x04; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF_NOT(state->unreplied_cnt == 3); + FAIL_IF(state->window != 3); + FAIL_IF_NOT(state->transaction_max == 4); + + /* Response to the third request. */ + res[1] = 0x03; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, res, reslen, NULL)); + FAIL_IF_NOT(state->unreplied_cnt == 2); + FAIL_IF_NOT(state->window == 3); + tx = TAILQ_FIRST(&state->tx_list); + FAIL_IF_NULL(tx); + FAIL_IF(tx->replied); + FAIL_IF(!tx->reply_lost); + + /* Also free's state. */ + UTHFreeFlow(f); + + PASS; +} void DNSUDPParserRegisterTests(void) { @@ -635,5 +879,10 @@ void DNSUDPParserRegisterTests(void) UtRegisterTest("DNSUDPParserTest03", DNSUDPParserTest03); UtRegisterTest("DNSUDPParserTest04", DNSUDPParserTest04); UtRegisterTest("DNSUDPParserTest05", DNSUDPParserTest05); + UtRegisterTest("DNSUDPParserTestFlood", DNSUDPParserTestFlood); + UtRegisterTest("DNSUDPParserTestDelayedResponse", + DNSUDPParserTestDelayedResponse); + UtRegisterTest("DNSUDPParserTestLostResponse", + DNSUDPParserTestLostResponse); } #endif From 7d734edca84c0fd1ba03cf2f89ccfdd4ab58a605 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 25 Oct 2016 14:56:09 -0600 Subject: [PATCH 2126/2553] dns: use new unittest macros --- src/app-layer-dns-udp.c | 60 +++++++++++------------------------------ 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index e34c4b146076..b34aacf42322 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -462,7 +462,6 @@ void RegisterDNSUDPParsers(void) static int DNSUDPParserTest01 (void) { - int result = 0; /* query: abcdefghijk.com * TTL: 86400 * serial 20130422 refresh 28800 retry 7200 exp 604800 min ttl 86400 @@ -482,25 +481,19 @@ static int DNSUDPParserTest01 (void) Flow *f = NULL; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->proto = IPPROTO_UDP; f->alproto = ALPROTO_DNS; f->alstate = DNSStateAlloc(); - int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL); - if (r != 1) - goto end; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL)); - result = 1; -end: UTHFreeFlow(f); - return (result); + PASS; } static int DNSUDPParserTest02 (void) { - int result = 0; uint8_t buf[] = { 0x6D,0x08,0x84,0x80,0x00,0x01,0x00,0x08,0x00,0x00,0x00,0x01,0x03,0x57,0x57,0x57, 0x04,0x54,0x54,0x54,0x54,0x03,0x56,0x56,0x56,0x03,0x63,0x6F,0x6D,0x02,0x79,0x79, @@ -517,25 +510,19 @@ static int DNSUDPParserTest02 (void) Flow *f = NULL; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->proto = IPPROTO_UDP; f->alproto = ALPROTO_DNS; f->alstate = DNSStateAlloc(); - int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL); - if (r != 1) - goto end; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL)); - result = 1; -end: UTHFreeFlow(f); - return (result); + PASS; } static int DNSUDPParserTest03 (void) { - int result = 0; uint8_t buf[] = { 0x6F,0xB4,0x84,0x80,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x03,0x03,0x57,0x57,0x77, 0x0B,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x03,0x55,0x55,0x55, @@ -552,26 +539,20 @@ static int DNSUDPParserTest03 (void) Flow *f = NULL; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->proto = IPPROTO_UDP; f->alproto = ALPROTO_DNS; f->alstate = DNSStateAlloc(); - int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL); - if (r != 1) - goto end; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL)); - result = 1; -end: UTHFreeFlow(f); - return (result); + PASS; } /** \test TXT records in answer */ static int DNSUDPParserTest04 (void) { - int result = 0; uint8_t buf[] = { 0xc2,0x2f,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x0a,0x41,0x41,0x41, 0x41,0x41,0x4f,0x31,0x6b,0x51,0x41,0x05,0x3d,0x61,0x75,0x74,0x68,0x03,0x73,0x72, @@ -590,26 +571,20 @@ static int DNSUDPParserTest04 (void) Flow *f = NULL; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->proto = IPPROTO_UDP; f->alproto = ALPROTO_DNS; f->alstate = DNSStateAlloc(); - int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL); - if (r != 1) - goto end; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL)); - result = 1; -end: UTHFreeFlow(f); - return (result); + PASS; } /** \test TXT records in answer, bad txtlen */ static int DNSUDPParserTest05 (void) { - int result = 0; uint8_t buf[] = { 0xc2,0x2f,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x0a,0x41,0x41,0x41, 0x41,0x41,0x4f,0x31,0x6b,0x51,0x41,0x05,0x3d,0x61,0x75,0x74,0x68,0x03,0x73,0x72, @@ -628,20 +603,15 @@ static int DNSUDPParserTest05 (void) Flow *f = NULL; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->proto = IPPROTO_UDP; f->alproto = ALPROTO_DNS; f->alstate = DNSStateAlloc(); - int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL); - if (r != -1) - goto end; + FAIL_IF(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL) != -1); - result = 1; -end: UTHFreeFlow(f); - return (result); + PASS; } /** From 9d271e9a71140d7cfa48922d249f40f670193cba Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 26 Oct 2016 15:34:43 -0600 Subject: [PATCH 2127/2553] fast-pattern: fix tls_sni Use all 38 arguments in call to SigMatchGetLastSMFromLists Was preventing fast_pattern from being applied to tls_sni: https://redmine.openinfosecfoundation.org/issues/1936 --- src/detect-fast-pattern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index c890419377f7..6eeda8044d66 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -194,7 +194,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a return -1; } - SigMatch *pm = SigMatchGetLastSMFromLists(s, 28, + SigMatch *pm = SigMatchGetLastSMFromLists(s, 38, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], From 2758f825151925c8fce8cb618cd43fac14ab6d38 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 26 Oct 2016 16:19:13 +0200 Subject: [PATCH 2128/2553] flowvar: cleanups --- src/detect-flowvar.c | 23 +++++++++-------------- src/detect-flowvar.h | 10 ++++------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index 962ec6fdc600..e662ad17abc5 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -259,11 +259,12 @@ int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx) * \param sm sigmatch containing the idx to store * \retval 1 or -1 in case of error */ -static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectFlowvarPostMatch(ThreadVars *tv, + DetectEngineThreadCtx *det_ctx, + Packet *p, Signature *s, const SigMatchCtx *ctx) { DetectFlowvarList *fs, *prev; const DetectFlowvarData *fd; - const int flow_locked = det_ctx->flow_locked; if (det_ctx->flowvarlist == NULL || p->flow == NULL) return 1; @@ -277,10 +278,7 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx SCLogDebug("adding to the flow %u:", fs->idx); //PrintRawDataFp(stdout, fs->buffer, fs->len); - if (flow_locked) - FlowVarAddStrNoLock(p->flow, fs->idx, fs->buffer, fs->len); - else - FlowVarAddStr(p->flow, fs->idx, fs->buffer, fs->len); + FlowVarAddStrNoLock(p->flow, fs->idx, fs->buffer, fs->len); /* memory at fs->buffer is now the responsibility of * the flowvar code. */ @@ -303,10 +301,10 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx /** \brief Handle flowvar candidate list in det_ctx: * - clean up the list - * - enforce storage for type ALWAYS (luajit) + * - enforce storage for type ALWAYS (vars set from lua) * Only called from DetectFlowvarProcessList() when flowvarlist is not NULL . */ -void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f, const int flow_locked) +void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f) { DetectFlowvarList *next; @@ -314,18 +312,15 @@ void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f, const int next = fs->next; if (fs->type == DETECT_FLOWVAR_TYPE_ALWAYS) { - BUG_ON(f == NULL); SCLogDebug("adding to the flow %u:", fs->idx); //PrintRawDataFp(stdout, fs->buffer, fs->len); - if (flow_locked) - FlowVarAddStrNoLock(f, fs->idx, fs->buffer, fs->len); - else - FlowVarAddStr(f, fs->idx, fs->buffer, fs->len); + FlowVarAddStrNoLock(f, fs->idx, fs->buffer, fs->len); /* memory at fs->buffer is now the responsibility of * the flowvar code. */ - } else + } else { SCFree(fs->buffer); + } SCFree(fs); fs = next; } while (fs != NULL); diff --git a/src/detect-flowvar.h b/src/detect-flowvar.h index 9e72a5bcb5c4..c8081385b87a 100644 --- a/src/detect-flowvar.h +++ b/src/detect-flowvar.h @@ -39,17 +39,15 @@ int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx); int DetectFlowvarStoreMatch(DetectEngineThreadCtx *, uint16_t, uint8_t *, uint16_t, int); /* For use only by DetectFlowvarProcessList() */ -void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f, const int flow_locked); +void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f); static inline void DetectFlowvarProcessList(DetectEngineThreadCtx *det_ctx, Flow *f) { DetectFlowvarList *fs = det_ctx->flowvarlist; - const int flow_locked = det_ctx->flow_locked; - SCLogDebug("det_ctx->flowvarlist %p", fs); - - if (fs != NULL) { + SCLogDebug("flow %p det_ctx->flowvarlist %p", f, fs); + if (f && fs != NULL) { det_ctx->flowvarlist = NULL; - DetectFlowvarProcessListInternal(fs, f, flow_locked); + DetectFlowvarProcessListInternal(fs, f); } } From f6c0abaae7fb91e9b2f867c519b97662260f9934 Mon Sep 17 00:00:00 2001 From: fooinha Date: Mon, 24 Oct 2016 15:52:06 +0000 Subject: [PATCH 2129/2553] eve: check redis reply in non pipeline mode We may lose the reply if disconnection happens. Reconnection is needed. --- src/util-logopenfile.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 120742a1f996..f35a7acdbb77 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -597,21 +597,26 @@ static int LogFileWriteRedis(LogFileCtx *file_ctx, const char *string, size_t s file_ctx->redis_setup.key, string); - switch (reply->type) { - case REDIS_REPLY_ERROR: - SCLogWarning(SC_ERR_SOCKET, "Redis error: %s", reply->str); - SCConfLogReopenRedis(file_ctx); - break; - case REDIS_REPLY_INTEGER: - SCLogDebug("Redis integer %lld", reply->integer); - break; - default: - SCLogError(SC_ERR_INVALID_VALUE, - "Redis default triggered with %d", reply->type); - SCConfLogReopenRedis(file_ctx); - break; + /* We may lose the reply if disconnection happens! */ + if (reply) { + switch (reply->type) { + case REDIS_REPLY_ERROR: + SCLogWarning(SC_ERR_SOCKET, "Redis error: %s", reply->str); + SCConfLogReopenRedis(file_ctx); + break; + case REDIS_REPLY_INTEGER: + SCLogDebug("Redis integer %lld", reply->integer); + break; + default: + SCLogError(SC_ERR_INVALID_VALUE, + "Redis default triggered with %d", reply->type); + SCConfLogReopenRedis(file_ctx); + break; + } + freeReplyObject(reply); + } else { + SCConfLogReopenRedis(file_ctx); } - freeReplyObject(reply); } return 0; } From da40714cb12b7e2642e42be253b4f33b8bf79ecb Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 25 Apr 2016 00:17:58 -0600 Subject: [PATCH 2130/2553] common: define json_boolean when not defined Older versions of jansson in current use don't have this macro defined. --- src/suricata-common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/suricata-common.h b/src/suricata-common.h index 1c097d2314e5..9dda1f3ca21b 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -219,6 +219,10 @@ #ifndef JSON_ESCAPE_SLASH #define JSON_ESCAPE_SLASH 0 #endif +/* Appears not all current distros have jansson that defines this. */ +#ifndef json_boolean +#define json_boolean(val) ((val) ? json_true() : json_false()) +#endif #endif #if CPPCHECK==1 From 240d789c40b51c475da56c2c4a7a67ab2f508809 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 8 Feb 2016 15:16:01 -0600 Subject: [PATCH 2131/2553] DNP3: dnp3-gen: code generator for repetitive DNP3 code --- scripts/dnp3-gen/dnp3-gen.py | 729 +++++++ scripts/dnp3-gen/dnp3-objects.yaml | 2995 ++++++++++++++++++++++++++++ 2 files changed, 3724 insertions(+) create mode 100755 scripts/dnp3-gen/dnp3-gen.py create mode 100644 scripts/dnp3-gen/dnp3-objects.yaml diff --git a/scripts/dnp3-gen/dnp3-gen.py b/scripts/dnp3-gen/dnp3-gen.py new file mode 100755 index 000000000000..29d7ae2e5983 --- /dev/null +++ b/scripts/dnp3-gen/dnp3-gen.py @@ -0,0 +1,729 @@ +#! /usr/bin/env python +# +# Copyright (C) 2015 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. + +# This script generates DNP3 related source code based on definitions +# of DNP3 objects (currently the object structs). + +from __future__ import print_function + +import sys +import re +from cStringIO import StringIO +import yaml +import types + +import jinja2 + +IN_PLACE_START = "/* START GENERATED CODE */" +IN_PLACE_END = "/* END GENERATED CODE */" + +util_lua_dnp3_objects_c_template = """/* Copyright (C) 2015 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. + */ + +/** + * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. + * + * Generated by command: + * {{command_line}} + */ + +#include "suricata-common.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" + +/** + * \\brief Push an object point item onto the stack. + */ +void DNP3PushPoint(lua_State *luastate, DNP3Object *object, + DNP3Point *point) +{ + switch (DNP3_OBJECT_CODE(object->group, object->variation)) { +{% for object in objects %} + case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): { + DNP3ObjectG{{object.group}}V{{object.variation}} *data = point->data; +{% for field in object.fields %} +{% if is_integer_type(field.type) %} + lua_pushliteral(luastate, "{{field.name}}"); + lua_pushinteger(luastate, data->{{field.name}}); + lua_settable(luastate, -3); +{% elif field["type"] in ["flt32", "flt64"] %} + lua_pushliteral(luastate, "{{field.name}}"); + lua_pushnumber(luastate, data->{{field.name}}); + lua_settable(luastate, -3); +{% elif field["type"] == "chararray" %} + lua_pushliteral(luastate, "{{field.name}}"); + LuaPushStringBuffer(luastate, (uint8_t *)data->{{field.name}}, + strlen(data->{{field.name}})); + lua_settable(luastate, -3); +{% elif field["type"] == "vstr4" %} + lua_pushliteral(luastate, "{{field.name}}"); + LuaPushStringBuffer(luastate, (uint8_t *)data->{{field.name}}, + strlen(data->{{field.name}})); + lua_settable(luastate, -3); +{% elif field.type == "bytearray" %} + lua_pushliteral(luastate, "{{field.name}}"); + lua_pushlstring(luastate, (const char *)data->{{field.name}}, + data->{{field.len_field}}); + lua_settable(luastate, -3); +{% elif field.type == "bstr8" %} +{% for field in field.fields %} + lua_pushliteral(luastate, "{{field.name}}"); + lua_pushinteger(luastate, data->{{field.name}}); + lua_settable(luastate, -3); +{% endfor %} +{% else %} +{{ raise("Unhandled datatype: %s" % (field.type)) }} +{% endif %} +{% endfor %} + break; + } +{% endfor %} + default: + break; + } +} + +#endif /* HAVE_LUA */ + +""" + +output_json_dnp3_objects_template = """/* Copyright (C) 2015 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. + */ + +/** + * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. + * + * Generated by command: + * {{command_line}} + */ + +#include "suricata-common.h" + +#include "util-crypt.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#ifdef HAVE_LIBJANSSON + +void OutputJsonDNP3SetItem(json_t *js, DNP3Object *object, + DNP3Point *point) +{ + + switch (DNP3_OBJECT_CODE(object->group, object->variation)) { +{% for object in objects %} + case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): { + DNP3ObjectG{{object.group}}V{{object.variation}} *data = point->data; +{% for field in object.fields %} +{% if is_integer_type(field.type) %} + json_object_set_new(js, "{{field.name}}", + json_integer(data->{{field.name}})); +{% elif field.type in ["flt32", "flt64"] %} + json_object_set_new(js, "{{field.name}}", + json_real(data->{{field.name}})); +{% elif field.type == "bytearray" %} + unsigned long {{field.name}}_b64_len = data->{{field.len_field}} * 2; + uint8_t {{field.name}}_b64[{{field.name}}_b64_len]; + Base64Encode(data->{{field.name}}, data->{{field.len_field}}, + {{field.name}}_b64, &{{field.name}}_b64_len); + json_object_set_new(js, "data->{{field.name}}", + json_string((char *){{field.name}}_b64)); +{% elif field.type == "vstr4" %} + json_object_set_new(js, "data->{{field.name}}", json_string(data->{{field.name}})); +{% elif field.type == "chararray" %} + if (data->{{field.len_field}} > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->{{field.len_field}} + 1]; + memcpy(tmpbuf, data->{{field.name}}, data->{{field.len_field}}); + tmpbuf[data->{{field.len_field}}] = '\\0'; + json_object_set_new(js, "{{field.name}}", json_string(tmpbuf)); + } else { + json_object_set_new(js, "{{field.name}}", json_string("")); + } +{% elif field.type == "bstr8" %} +{% for field in field.fields %} + json_object_set_new(js, "{{field.name}}", + json_integer(data->{{field.name}})); +{% endfor %} +{% else %} +{{ raise("Unhandled datatype: %s" % (field.type)) }} +{% endif %} +{% endfor %} + break; + } +{% endfor %} + default: + SCLogDebug("Unknown object: %d:%d", object->group, + object->variation); + break; + } + +} + +#endif /* HAVE_LIBJANSSON */ + +""" + +def has_freeable_types(fields): + freeable_types = [ + "bytearray", + ] + for field in fields: + if field["type"] in freeable_types: + return True + return False + +def is_integer_type(datatype): + integer_types = [ + "uint64", + "uint32", + "uint24", + "uint16", + "uint8", + "int64", + "int32", + "int16", + "int8", + "dnp3time", + ] + return datatype in integer_types + +def to_type(datatype): + type_map = { + "uint8": "uint8_t", + } + if datatype in type_map: + return type_map[datatype] + else: + raise Exception("Unknown datatype: %s" % (datatype)) + +def generate(template, filename, context): + print("Generating %s." % (filename)) + try: + env = jinja2.Environment(trim_blocks=True) + output = env.from_string(template).render(context) + with open(filename, "w") as fileobj: + fileobj.write(output) + except Exception as err: + print("Failed to generate %s: %s" % (filename, err)) + sys.exit(1) + +def raise_helper(msg): + raise Exception(msg) + +def gen_object_structs(context): + """ Generate structs for all the define DNP3 objects. """ + + template = """ + +/* Code generated by: + * {{command_line}} + */ + +{% for object in objects %} +typedef struct DNP3ObjectG{{object.group}}V{{object.variation}}_ { +{% for field in object.fields %} +{% if field.type == "bstr8" %} +{% for field in field.fields %} + uint8_t {{field.name}}:{{field.width}}; +{% endfor %} +{% else %} +{% if field.type == "int16" %} + int16_t {{field.name}}; +{% elif field.type == "int32" %} + int32_t {{field.name}}; +{% elif field.type == "uint8" %} + uint8_t {{field.name}}; +{% elif field.type == "uint16" %} + uint16_t {{field.name}}; +{% elif field.type == "uint24" %} + uint32_t {{field.name}}; +{% elif field.type == "uint32" %} + uint32_t {{field.name}}; +{% elif field.type == "uint64" %} + uint64_t {{field.name}}; +{% elif field.type == "flt32" %} + float {{field.name}}; +{% elif field.type == "flt64" %} + double {{field.name}}; +{% elif field.type == "dnp3time" %} + uint64_t {{field.name}}; +{% elif field.type == "bytearray" %} + uint8_t *{{field.name}}; +{% elif field.type == "vstr4" %} + char {{field.name}}[5]; +{% elif field.type == "chararray" %} + char {{field.name}}[{{field.size}}]; +{% else %} + {{ raise("Unknown datatype type '%s' for object %d:%d" % ( + field.type, object.group, object.variation)) }} +{% endif %} +{% endif %} +{% endfor %} +{% if object.extra_fields %} +{% for field in object.extra_fields %} +{% if field.type == "uint8" %} + uint8_t {{field.name}}; +{% elif field.type == "uint16" %} + uint16_t {{field.name}}; +{% elif field.type == "uint32" %} + uint32_t {{field.name}}; +{% else %} + {{ raise("Unknown datatype: %s" % (field.type)) }} +{% endif %} +{% endfor %} +{% endif %} +} DNP3ObjectG{{object.group}}V{{object.variation}}; + +{% endfor %} +""" + + filename = "src/app-layer-dnp3-objects.h" + try: + env = jinja2.Environment(trim_blocks=True) + code = env.from_string(template).render(context) + content = open(filename).read() + content = re.sub( + "(%s).*(%s)" % (re.escape(IN_PLACE_START), re.escape(IN_PLACE_END)), + r"\1%s\2" % (code), content, 1, re.M | re.DOTALL) + open(filename, "w").write(content) + print("Updated %s." % (filename)) + except Exception as err: + print("Failed to update %s: %s" % (filename, err), file=sys.stderr) + sys.exit(1) + +def gen_object_decoders(context): + """ Generate decoders for all defined DNP3 objects. """ + + template = """ + +/* Code generated by: + * {{command_line}} + */ + +{% for object in objects %} +{% if object.packed %} +static int DNP3DecodeObjectG{{object.group}}V{{object.variation}}(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG{{object.group}}V{{object.variation}} *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + {{object.fields[0].width}}) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + +{% if object.fields[0].width == 1 %} + object->{{object.fields[0].name}} = (octet >> j) & 0x1; +{% elif object.fields[0].width == 2 %} + object->{{object.fields[0].name}} = (octet >> j) & 0x3; +{% else %} +#error "Unhandled field width: {{object.fields[0].width}}" +{% endif %} + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +{% else %} +static int DNP3DecodeObjectG{{object.group}}V{{object.variation}}(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG{{object.group}}V{{object.variation}} *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; +{% if object._track_offset %} + uint32_t offset; +{% endif %} +{% if object.constraints %} + +{% for (key, val) in object.constraints.items() %} +{% if key == "require_size_prefix" %} + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } +{% elif key == "require_prefix_code" %} + if (prefix_code != {{val}}) { + goto error; + } +{% else %} +{{ raise("Unhandled constraint: %s" % (key)) }} +{% endif %} +{% endfor %} +{% endif %} + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } +{% if object._track_offset %} + + offset = *len; +{% endif %} + +{% for field in object.fields %} +{% if field.type == "int16" %} + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->{{field.name}})) { + goto error; + } +{% elif field.type == "int32" %} + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->{{field.name}})) { + goto error; + } +{% elif field.type == "uint8" %} + if (!DNP3ReadUint8(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "uint16" %} + if (!DNP3ReadUint16(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "uint24" %} + if (!DNP3ReadUint24(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "uint32" %} + if (!DNP3ReadUint32(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "uint64" %} + if (!DNP3ReadUint64(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "flt32" %} + if (!DNP3ReadFloat32(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "flt64" %} + if (!DNP3ReadFloat64(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "dnp3time" %} + if (!DNP3ReadUint48(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "vstr4" %} + if (*len < 4) { + goto error; + } + memcpy(object->{{field.name}}, *buf, 4); + object->{{field.name}}[4] = '\\\\0'; + *buf += 4; + *len -= 4; +{% elif field.type == "bytearray" %} +{% if field.len_from_prefix %} + object->{{field.len_field}} = prefix - (offset - *len); +{% endif %} + if (object->{{field.len_field}} > 0) { + if (*len < object->{{field.len_field}}) { + /* Not enough data. */ + goto error; + } + object->{{field.name}} = SCCalloc(1, object->{{field.len_field}}); + if (unlikely(object->{{field.name}} == NULL)) { + goto error; + } + memcpy(object->{{field.name}}, *buf, object->{{field.len_field}}); + *buf += object->{{field.len_field}}; + *len -= object->{{field.len_field}}; + } +{% elif field.type == "chararray" %} +{% if field.len_from_prefix %} + object->{{field.len_field}} = prefix - (offset - *len); +{% endif %} + if (object->{{field.len_field}} > 0) { + memcpy(object->{{field.name}}, *buf, object->{{field.len_field}}); + *buf += object->{{field.len_field}}; + *len -= object->{{field.len_field}}; + } + object->{{field.name}}[object->{{field.len_field}}] = '\\\\0'; +{% elif field.type == "bstr8" %} + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } +{% set shift = 0 %} +{% for field in field.fields %} +{% if field.width == 1 %} + object->{{field.name}} = (octet >> {{shift}}) & 0x1; +{% elif field.width == 2 %} + object->{{field.name}} = (octet >> {{shift}}) & 0x3; +{% elif field.width == 4 %} + object->{{field.name}} = (octet >> {{shift}}) & 0xf; +{% elif field.width == 7 %} + object->{{field.name}} = (octet >> {{shift}}) & 0x7f; +{% else %} +{{ raise("Unhandled width of %d." % (field.width)) }} +{% endif %} +{% set shift = shift + field.width %} +{% endfor %} + } +{% else %} +{{ raise("Unhandled datatype '%s' for object %d:%d." % (field.type, + object.group, object.variation)) }} +{% endif %} +{% endfor %} + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +{% endif %} +{% endfor %} + +void DNP3FreeObjectPoint(int group, int variation, void *point) +{ + switch(DNP3_OBJECT_CODE(group, variation)) { +{% for object in objects %} +{% if f_has_freeable_types(object.fields) %} + case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): { + DNP3ObjectG{{object.group}}V{{object.variation}} *object = (DNP3ObjectG{{object.group}}V{{object.variation}} *) point; +{% for field in object.fields %} +{% if field.type == "bytearray" %} + if (object->{{field.name}} != NULL) { + SCFree(object->{{field.name}}); + } +{% endif %} +{% endfor %} + break; + } +{% endif %} +{% endfor %} + default: + break; + } + SCFree(point); +} + +/** + * \\\\brief Decode a DNP3 object. + * + * \\\\retval 0 on success. On failure a positive integer corresponding + * to a DNP3 application layer event will be returned. + */ +int DNP3DecodeObject(int group, int variation, const uint8_t **buf, + uint32_t *len, uint8_t prefix_code, uint32_t start, + uint32_t count, DNP3PointList *points) +{ + int rc = 0; + + switch (DNP3_OBJECT_CODE(group, variation)) { +{% for object in objects %} + case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): + rc = DNP3DecodeObjectG{{object.group}}V{{object.variation}}(buf, len, prefix_code, start, count, + points); + break; +{% endfor %} + default: + return DNP3_DECODER_EVENT_UNKNOWN_OBJECT; + } + + return rc ? 0 : DNP3_DECODER_EVENT_MALFORMED; +} + +""" + + try: + filename = "src/app-layer-dnp3-objects.c" + env = jinja2.Environment(trim_blocks=True, lstrip_blocks=True) + code = env.from_string(template).render(context) + content = open(filename).read() + content = re.sub( + "(%s).*(%s)" % (re.escape(IN_PLACE_START), re.escape(IN_PLACE_END)), + r"\1%s\n\2" % (code), content, 1, re.M | re.DOTALL) + open(filename, "w").write(content) + print("Updated %s." % (filename)) + except Exception as err: + print("Failed to update %s: %s" % (filename, err), file=sys.stderr) + sys.exit(1) + +def preprocess_object(obj): + + valid_keys = [ + "group", + "variation", + "constraints", + "extra_fields", + "fields", + "packed", + ] + + valid_field_keys = [ + "type", + "name", + "width", + "len_from_prefix", + "len_field", + "fields", + "size", + ] + + if "unimplemented" in obj: + print("Object not implemented: %s:%s: %s" % ( + str(obj["group"]), str(obj["variation"]), obj["unimplemented"])) + return None + + for key, val in obj.items(): + + if key not in valid_keys: + print("Invalid key '%s' in object %d:%d" % ( + key, obj["group"], obj["variation"]), file=sys.stderr) + sys.exit(1) + + for field in obj["fields"]: + + for key in field.keys(): + if key not in valid_field_keys: + print("Invalid key '%s' in object %d:%d" % ( + key, obj["group"], obj["variation"]), file=sys.stderr) + sys.exit(1) + + if "len_from_prefix" in field and field["len_from_prefix"]: + obj["_track_offset"] = True + break + + if field["type"] == "bstr8": + width = 0 + for subfield in field["fields"]: + width += int(subfield["width"]) + assert(width == 8) + + return obj + +def main(): + + definitions = yaml.load(open("scripts/dnp3-gen/dnp3-objects.yaml")) + print("Loaded %s objects." % (len(definitions["objects"]))) + definitions["objects"] = map(preprocess_object, definitions["objects"]) + + # Filter out unimplemented objects. + definitions["objects"] = [ + obj for obj in definitions["objects"] if obj != None] + + context = { + "raise": raise_helper, + "objects": definitions["objects"], + "is_integer_type": is_integer_type, + "f_to_type": to_type, + "f_has_freeable_types": has_freeable_types, + "command_line": " ".join(sys.argv), + } + + gen_object_structs(context) + gen_object_decoders(context) + generate(util_lua_dnp3_objects_c_template, + "src/util-lua-dnp3-objects.c", + context) + generate(output_json_dnp3_objects_template, + "src/output-json-dnp3-objects.c", + context) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/dnp3-gen/dnp3-objects.yaml b/scripts/dnp3-gen/dnp3-objects.yaml new file mode 100644 index 000000000000..529910f78d44 --- /dev/null +++ b/scripts/dnp3-gen/dnp3-objects.yaml @@ -0,0 +1,2995 @@ +objects: + + - group: 1 + variation: 1 + packed: true + fields: + - type: uint8 + name: state + width: 1 + + - group: 1 + variation: 2 + fields: + - type: bstr8 + fields: + - type: uint8 + name: online + width: 1 + - type: uint8 + name: restart + width: 1 + - name: comm_lost + type: uint8 + width: 1 + - name: remote_forced + type: uint8 + width: 1 + - name: local_forced + type: uint8 + width: 1 + - name: chatter_filter + type: uint8 + width: 1 + - name: reserved + type: uint8 + width: 1 + - name: state + type: uint8 + width: 1 + + - group: 2 + variation: 1 + fields: + - type: uint8 + name: state + width: 1 + + - group: 2 + variation: 2 + fields: + - type: bstr8 + fields: + - type: uint8 + name: online + width: 1 + - type: uint8 + name: restart + width: 1 + - name: comm_lost + type: uint8 + width: 1 + - name: remote_forced + type: uint8 + width: 1 + - name: local_forced + type: uint8 + width: 1 + - name: chatter_filter + type: uint8 + width: 1 + - name: reserved + type: uint8 + width: 1 + - name: state + type: uint8 + width: 1 + - type: dnp3time + name: timestamp + + - group: 2 + variation: 3 + fields: + - type: bstr8 + fields: + - type: uint8 + name: online + width: 1 + - type: uint8 + name: restart + width: 1 + - name: comm_lost + type: uint8 + width: 1 + - name: remote_forced + type: uint8 + width: 1 + - name: local_forced + type: uint8 + width: 1 + - name: chatter_filter + type: uint8 + width: 1 + - name: reserved + type: uint8 + width: 1 + - name: state + type: uint8 + width: 1 + - type: uint16 + name: timestamp + + - group: 3 + variation: 1 + packed: true + fields: + - type: uint8 + name: state + width: 2 + + - group: 3 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: chatter_filter + width: 1 + - name: state + width: 2 + + - group: 4 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: chatter_filter + width: 1 + - name: state + width: 2 + + - group: 4 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: chatter_filter + width: 1 + - name: state + width: 2 + - type: dnp3time + name: timestamp + + - group: 4 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: chatter_filter + width: 1 + - name: state + width: 2 + - type: uint16 + name: relative_time_ms + + - group: 10 + variation: 1 + packed: true + fields: + - type: uint8 + name: state + width: 1 + + - group: 10 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - name: state + width: 1 + + - group: 11 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - name: state + width: 1 + + - group: 11 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - name: state + width: 1 + - type: dnp3time + name: timestamp + + - group: 12 + variation: 1 + fields: + - type: bstr8 + fields: + - name: op_type + type: uint8 + width: 4 + - name: qu + type: uint8 + width: 1 + - name: cr + type: uint8 + width: 1 + - name: tcc + type: uint8 + width: 2 + - name: count + type: uint8 + - name: ontime + type: uint32 + - name: offtime + type: uint32 + - type: bstr8 + fields: + - name: status_code + type: uint8 + width: 7 + - name: reserved + type: uint32 + width: 1 + + - group: 12 + variation: 2 + fields: + - type: bstr8 + fields: + - name: op_type + type: uint8 + width: 4 + - name: qu + type: uint8 + width: 1 + - name: cr + type: uint8 + width: 1 + - name: tcc + type: uint8 + width: 2 + - name: count + type: uint8 + - name: ontime + type: uint32 + - name: offtime + type: uint32 + - type: bstr8 + fields: + - name: status_code + type: uint8 + width: 7 + - name: reserved + type: uint32 + width: 1 + + - group: 12 + variation: 3 + packed: true + fields: + - type: uint8 + name: point + width: 1 + + - group: 13 + variation: 1 + fields: + - type: bstr8 + fields: + - type: uint8 + width: 7 + name: status_code + - type: uint8 + width: 1 + name: commanded_state + + - group: 13 + variation: 2 + fields: + - type: bstr8 + fields: + - type: uint8 + width: 7 + name: status_code + - type: uint8 + width: 1 + name: commanded_state + - type: dnp3time + name: timestamp + + - group: 20 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint32 + name: count + + - group: 20 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint16 + name: count + + - group: 20 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + + - group: 20 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + + - group: 20 + variation: 5 + fields: + - type: uint32 + name: count + + - group: 20 + variation: 6 + fields: + - type: uint16 + name: count + + - group: 20 + variation: 7 + fields: + - type: uint32 + name: count + + - group: 20 + variation: 8 + fields: + - type: uint16 + name: count + + - group: 21 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint32 + name: count + + - group: 21 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint16 + name: count + + - group: 21 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + + - group: 21 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + + - group: 21 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 21 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 21 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 21 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 21 + variation: 9 + fields: + - type: uint32 + name: count + + - group: 21 + variation: 10 + fields: + - type: uint16 + name: count + + - group: 21 + variation: 11 + fields: + - type: uint32 + name: count + + - group: 21 + variation: 12 + fields: + - type: uint16 + name: count + + - group: 22 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint32 + name: count + + - group: 22 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint16 + name: count + + - group: 22 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + + - group: 22 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + + - group: 22 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 22 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 22 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 22 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 23 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint32 + name: count + + - group: 23 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + + - group: 23 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + + - group: 23 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + + - group: 23 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 23 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 23 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 23 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 30 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 30 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 30 + variation: 3 + fields: + - type: int32 + name: value + + - group: 30 + variation: 4 + fields: + - type: int16 + name: value + + - group: 30 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 30 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 31 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 31 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 31 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + - type: dnp3time + name: timestamp + + - group: 31 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + - type: dnp3time + name: timestamp + + - group: 31 + variation: 5 + fields: + - type: int32 + name: value + + - group: 31 + variation: 6 + fields: + - type: int16 + name: value + + - group: 31 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 31 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 32 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 32 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 32 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + - type: dnp3time + name: timestamp + + - group: 32 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + - type: dnp3time + name: timestamp + + - group: 32 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 32 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 32 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + - type: dnp3time + name: timestamp + + - group: 32 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + # XXX Spec says FLT32, pretty sure its FLT64 and OpenDNP uses a 64 bit + # float as well. + - type: flt64 + name: value + - type: dnp3time + name: timestamp + + - group: 33 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 33 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 33 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + - type: dnp3time + name: timestamp + + - group: 33 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + - type: dnp3time + name: timestamp + + - group: 33 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 33 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 33 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + - type: dnp3time + name: timestamp + + - group: 33 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + # XXX Spec says FLT32, I think its FLT64. + - type: flt64 + name: value + - type: dnp3time + name: timestamp + + - group: 34 + variation: 1 + fields: + - type: uint16 + name: deadband_value + + - group: 34 + variation: 2 + fields: + - type: uint32 + name: deadband_value + + - group: 34 + variation: 3 + fields: + - type: flt32 + name: deadband_value + + - group: 40 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 40 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 40 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 40 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 41 + variation: 1 + fields: + - type: int32 + name: value + - type: uint8 + name: control_status + + - group: 41 + variation: 2 + fields: + - type: int16 + name: value + - type: uint8 + name: control_status + + - group: 41 + variation: 3 + fields: + - type: flt32 + name: value + - type: uint8 + name: control_status + + - group: 41 + variation: 4 + fields: + - type: flt64 + name: value + - type: uint8 + name: control_status + + - group: 42 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 42 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 42 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + - type: dnp3time + name: timestamp + + - group: 42 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + - type: dnp3time + name: timestamp + + - group: 42 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 42 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 42 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + - type: dnp3time + name: timestamp + + - group: 42 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + - type: dnp3time + name: timestamp + + - group: 43 + variation: 1 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: int32 + name: commanded_value + + - group: 43 + variation: 2 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: int16 + name: commanded_value + + - group: 43 + variation: 3 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: int32 + name: commanded_value + - type: dnp3time + name: timestamp + + - group: 43 + variation: 4 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: int16 + name: commanded_value + - type: dnp3time + name: timestamp + + - group: 43 + variation: 5 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: flt32 + name: commanded_value + + - group: 43 + variation: 6 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: flt64 + name: commanded_value + + - group: 43 + variation: 7 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: flt32 + name: commanded_value + - type: dnp3time + name: timestamp + + - group: 43 + variation: 8 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: flt64 + name: commanded_value + - type: dnp3time + name: timestamp + + - group: 50 + variation: 1 + fields: + - type: dnp3time + name: timestamp + + - group: 50 + variation: 2 + fields: + - type: dnp3time + name: timestamp + - type: uint32 + name: interval + + - group: 50 + variation: 3 + fields: + - type: dnp3time + name: timestamp + + - group: 50 + variation: 4 + fields: + - type: dnp3time + name: timestamp + - type: uint32 + name: interval_count + - type: uint8 + name: interval_units + + - group: 51 + variation: 1 + fields: + - type: dnp3time + name: timestamp + + - group: 51 + variation: 2 + fields: + - type: dnp3time + name: timestamp + + - group: 52 + variation: 1 + fields: + - type: uint16 + name: delay_secs + + - group: 52 + variation: 2 + fields: + - type: uint16 + name: delay_ms + + # 1815-2012: New DNP3 implementation should avoid using this object. + - group: 70 + variation: 1 + fields: + - type: uint16 + name: filename_size + - type: uint8 + name: filetype_code + - type: uint8 + name: attribute_code + - type: uint16 + name: start_record + - type: uint16 + name: end_record + - type: uint32 + name: file_size + - type: dnp3time + name: created_timestamp + # XXX Actually bit flags. + - type: uint16 + name: permission + - type: uint32 + name: file_id + - type: uint32 + name: owner_id + - type: uint32 + name: group_id + - type: uint8 + name: file_function_code + - type: uint8 + name: status_code + - type: chararray + name: filename + size: 65535 + len_field: filename_size + - type: uint16 + name: data_size + - type: chararray + name: data + size: 65535 + len_field: data_size + + - group: 70 + variation: 2 + fields: + - type: uint16 + name: username_offset + - type: uint16 + name: username_size + - type: uint16 + name: password_offset + - type: uint16 + name: password_size + - type: uint32 + name: authentication_key + - type: chararray + name: username + size: 65535 + len_field: username_size + - type: chararray + name: password + size: 65535 + len_field: password_size + + - group: 70 + variation: 3 + fields: + - type: uint16 + name: filename_offset + - type: uint16 + name: filename_size + - type: dnp3time + name: created + # XXX Break out to bit flags. + - type: uint16 + name: permissions + - type: uint32 + name: authentication_key + - type: uint32 + name: file_size + - type: uint16 + name: operational_mode + - type: uint16 + name: maximum_block_size + - type: uint16 + name: request_id + - type: chararray + name: filename + size: 65535 + len_field: filename_size + + # Checked. + - group: 70 + variation: 4 + constraints: + require_size_prefix: true + extra_fields: + - type: uint8 + name: optional_text_len + fields: + - type: uint32 + name: file_handle + - type: uint32 + name: file_size + - type: uint16 + name: maximum_block_size + - type: uint16 + name: request_id + - type: uint8 + name: status_code + - type: chararray + name: optional_text + size: 0xff + len_from_prefix: true + len_field: optional_text_len + + # Checked. + - group: 70 + variation: 5 + constraints: + require_size_prefix: true + extra_fields: + - type: uint8 + name: file_data_len + fields: + - type: uint32 + name: file_handle + - type: uint32 + name: block_number # Includes "last" flag. + - type: chararray + name: file_data + size: 0xff + len_from_prefix: true + len_field: file_data_len + + # Checked. + - group: 70 + variation: 6 + constraints: + require_size_prefix: true + extra_fields: + - type: uint8 + name: optional_text_len + fields: + - type: uint32 + name: file_handle + - type: uint32 + name: block_number # Includes "last" flag. + - type: uint8 + name: status_code + - type: chararray + name: optional_text + size: 0xff + len_from_prefix: true + len_field: optional_text_len + + # Checked. + - group: 70 + variation: 7 + fields: + - type: uint16 + name: filename_offset + - type: uint16 + name: filename_size + - type: uint16 + name: file_type + - type: uint32 + name: file_size + - type: dnp3time + name: created_timestamp + - type: uint16 + name: permissions + - type: uint16 + name: request_id + - type: chararray + name: filename + size: 0xffff + len_field: filename_size + + # Checked. + - group: 70 + variation: 8 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: file_specification_len + fields: + - type: chararray + name: file_specification + size: 0xffff + len_from_prefix: true + len_field: file_specification_len + + # Checked. + - group: 80 + variation: 1 + packed: true + fields: + - type: uint8 + name: state + width: 1 + + # Checked. + - group: 81 + variation: 1 + fields: + - type: bstr8 + fields: + - type: uint8 + width: 7 + name: fill_percentage + - type: uint8 + width: 1 + name: overflow_state + - type: uint8 + name: group + - type: uint8 + name: variation + + - group: 82 + variation: 1 + unimplemented: object header types not yet supported + + - group: 83 + variation: 1 + fields: + - type: vstr4 + name: vendor_code + - type: uint16 + name: object_id + - type: uint16 + name: length + - type: bytearray + name: data_objects + len_field: length + + - group: 83 + variation: 2 + unimplemented: set objects not yet supported + + - group: 85 + variation: 1 + unimplemented: set objects not yet supported + + - group: 86 + variation: 1 + unimplemented: set objects not yet supported + + # Checked. + - group: 86 + variation: 2 + fields: + - type: bstr8 + fields: + - name: rd + width: 1 + - name: wr + width: 1 + - name: st + width: 1 + - name: ev + width: 1 + - name: df + width: 1 + - name: padding0 + width: 1 + - name: padding1 + width: 1 + - name: padding2 + width: 1 + + - group: 86 + variation: 3 + unimplemented: set objects not yet supported + + - group: 87 + variation: 1 + unimplemented: set objects not yet supported + + - group: 88 + variation: 1 + unimplemented: set objects not yet supported + + - group: 90 + variation: 1 + unimplemented: set objects not yet supported + + - group: 91 + variation: 1 + unimplemented: set objects not yet supported + + - group: 100 + variation: "*" + unimplemented: obsolete object type + + - group: 101 + variation: 1 + unimplemented: bcd types not yet supported + + - group: 101 + variation: 2 + unimplemented: bcd types not yet supported + + - group: 101 + variation: 3 + unimplemented: bcd types not yet supported + + # Checked. + - group: 102 + variation: 1 + fields: + - type: uint8 + name: value + + - group: 110 + variation: "*" + unimplemented: variation all not yet supported + + - group: 111 + variation: "*" + unimplemented: variation all not yet supported + + - group: 112 + variation: "*" + unimplemented: variation all not yet supported + + - group: 113 + variation: "*" + unimplemented: variation all not yet supported + + # Checked. + - group: 120 + variation: 1 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: challenge_data_len + fields: + - type: uint32 + name: csq + - type: uint16 + name: usr + - type: uint8 + name: mal + - type: uint8 + name: reason + - type: bytearray + name: challenge_data + len_from_prefix: true + len_field: challenge_data_len + + - group: 120 + variation: 2 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: mac_value_len + fields: + - type: uint32 + name: csq + - type: uint16 + name: usr + - type: bytearray + name: mac_value + len_from_prefix: true + len_field: mac_value_len + + # Checked. + - group: 120 + variation: 3 + fields: + - type: uint32 + name: csq + - type: uint16 + name: user_number + + # Checked. + - group: 120 + variation: 4 + fields: + - type: uint16 + name: user_number + + # Checked. + - group: 120 + variation: 5 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: mac_value_len + fields: + - type: uint32 + name: ksq + - type: uint16 + name: user_number + - type: uint8 + name: key_wrap_alg + - type: uint8 + name: key_status + - type: uint8 + name: mal + - type: uint16 + name: challenge_data_len + - type: bytearray + name: challenge_data + len_field: challenge_data_len + - type: bytearray + name: mac_value + len_from_prefix: true + len_field: mac_value_len + + # Checked. + - group: 120 + variation: 6 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: wrapped_key_data_len + fields: + - type: uint24 + name: ksq + - type: uint16 + name: usr + - type: bytearray + name: wrapped_key_data + len_from_prefix: true + len_field: wrapped_key_data_len + + # Checked. + - group: 120 + variation: 7 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: error_text_len + fields: + - type: uint32 + name: sequence_number + - type: uint16 + name: usr + - type: uint16 + name: association_id + - type: uint8 + name: error_code + - type: dnp3time + name: time_of_error + - type: chararray + name: error_text + size: 65535 + len_from_prefix: true + len_field: error_text_len + + # Checked. + - group: 120 + variation: 8 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: certificate_len + fields: + - type: uint8 + name: key_change_method + - type: uint8 + name: certificate_type + - type: bytearray + name: certificate + len_from_prefix: true + len_field: certificate_len + + # Checked. + - group: 120 + variation: 9 + extra_fields: + - type: uint16 + name: mac_value_len + fields: + - type: bytearray + name: mac_value + len_from_prefix: true + len_field: mac_value_len + + # Checked. + - group: 120 + variation: 10 + constraints: + require_prefix_code: 0x5 + fields: + - type: uint8 + name: key_change_method + - type: uint8 + name: operation + - type: uint32 + name: scs + - type: uint16 + name: user_role + - type: uint16 + name: user_role_expiry_interval + - type: uint16 + name: username_len + - type: uint16 + name: user_public_key_len + - type: uint16 + name: certification_data_len + - type: chararray + name: username + size: 65535 + len_field: username_len + - type: bytearray + name: user_public_key + len_field: user_public_key_len + - type: bytearray + name: certification_data + len_field: certification_data_len + + # Checked. + - group: 120 + variation: 11 + constraints: + require_prefix_code: 0x5 + fields: + - type: uint8 + name: key_change_method + - type: uint16 + name: username_len + - type: uint16 + name: master_challenge_data_len + - type: chararray + size: 65535 + name: username + len_field: username_len + - type: bytearray + name: master_challenge_data + len_field: master_challenge_data_len + + # Checked. + - group: 120 + variation: 12 + constraints: + require_prefix_code: 0x5 + fields: + - type: uint32 + name: ksq + - type: uint16 + name: user_number + - type: uint16 + name: challenge_data_len + - type: bytearray + name: challenge_data + len_field: challenge_data_len + + # Checked. + - group: 120 + variation: 13 + constraints: + require_prefix_code: 0x5 + fields: + - type: uint32 + name: ksq + - type: uint16 + name: user_number + - type: uint16 + name: encrypted_update_key_len + - type: bytearray + name: encrypted_update_key_data + len_field: encrypted_update_key_len + + # Checked. + - group: 120 + variation: 14 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: digital_signature_len + fields: + - type: bytearray + name: digital_signature + len_from_prefix: true + len_field: digital_signature_len + + # Checked. + - group: 120 + variation: 15 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint32 + name: mac_len + fields: + - type: bytearray + name: mac + len_field: mac_len + len_from_prefix: true + + # Checked. + - group: 121 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: discontinuity + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: association_id + - type: uint32 + name: count_value + + # Checked. + - group: 122 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: discontinuity + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: association_id + - type: uint32 + name: count_value + + # Checked. + - group: 122 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: discontinuity + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: association_id + - type: uint32 + name: count_value + - type: dnp3time + name: timestamp From bbaa79b80e4faea321593eb4aa552f976357ac86 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 10 Apr 2015 09:33:20 -0600 Subject: [PATCH 2132/2553] DNP3: Application layer decoder. Decodes TCP DNP3 and raises some DNP3 decoder alerts. --- Makefile.am | 1 + rules/Makefile.am | 3 +- rules/dnp3-events.rules | 26 + src/Makefile.am | 2 + src/app-layer-detect-proto.c | 4 + src/app-layer-dnp3-objects.c | 9148 ++++++++++++++++++++++++++++++++++ src/app-layer-dnp3-objects.h | 1464 ++++++ src/app-layer-dnp3.c | 2661 ++++++++++ src/app-layer-dnp3.h | 277 + src/app-layer-parser.c | 2 + src/app-layer-protos.c | 3 + src/app-layer-protos.h | 1 + src/util-error.c | 1 + src/util-error.h | 1 + suricata.yaml.in | 8 + 15 files changed, 13601 insertions(+), 1 deletion(-) create mode 100644 rules/dnp3-events.rules create mode 100644 src/app-layer-dnp3-objects.c create mode 100644 src/app-layer-dnp3-objects.h create mode 100644 src/app-layer-dnp3.c create mode 100644 src/app-layer-dnp3.h diff --git a/Makefile.am b/Makefile.am index e71290c4b85f..b265b6f2dc5a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,6 +44,7 @@ endif @test -e "$(DESTDIR)$(e_sysconfrulesdir)tls-events.rules" || install -m 600 "$(top_srcdir)/rules/tls-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @test -e "$(DESTDIR)$(e_sysconfrulesdir)modbus-events.rules" || install -m 600 "$(top_srcdir)/rules/modbus-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @test -e "$(DESTDIR)$(e_sysconfrulesdir)app-layer-events.rules" || install -m 600 "$(top_srcdir)/rules/app-layer-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)dnp3-events.rules" || install -m 600 "$(top_srcdir)/rules/dnp3-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @echo "" @echo "You can now start suricata by running as root something like '$(DESTDIR)$(bindir)/suricata -c $(DESTDIR)$(e_sysconfdir)/suricata.yaml -i eth0'." @echo "" diff --git a/rules/Makefile.am b/rules/Makefile.am index 7ab27bdf1e56..98a484d3a5b2 100644 --- a/rules/Makefile.am +++ b/rules/Makefile.am @@ -7,4 +7,5 @@ dns-events.rules \ tls-events.rules \ modbus-events.rules \ app-layer-events.rules \ -files.rules +files.rules \ +dnp3-events.rules diff --git a/rules/dnp3-events.rules b/rules/dnp3-events.rules new file mode 100644 index 000000000000..dfb1cf2217d7 --- /dev/null +++ b/rules/dnp3-events.rules @@ -0,0 +1,26 @@ +# DNP3 application decoder event rules. +# +# This SIDs fall in the 2270000+ range. See: +# http://doc.emergingthreats.net/bin/view/Main/SidAllocation + +# Flooded. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Request flood detected"; \ + app-layer-event:dnp3.flooded; sid:2270000; rev:1;) + +# Length to small for PDU type. For example, link specifies the type +# as user data, but the length field is not large enough for user +# data. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Length too small"; \ + app-layer-event:dnp3.len_too_small; sid:2270001; rev:2;) + +# Bad link layer CRC. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Bad link CRC"; \ + app-layer-event:dnp3.bad_link_crc; sid:2270002; rev:1;) + +# Bad transport layer CRC. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Bad transport CRC"; \ + app-layer-event:dnp3.bad_transport_crc; sid:2270003; rev:1;) + +# Unknown object. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Unknown object"; \ + app-layer-event:dnp3.unknown_object; sid:2270004; rev:1;) diff --git a/src/Makefile.am b/src/Makefile.am index 191776a5d288..c5bb60e7a257 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,8 @@ app-layer.c app-layer.h \ app-layer-dcerpc.c app-layer-dcerpc.h \ app-layer-dcerpc-udp.c app-layer-dcerpc-udp.h \ app-layer-detect-proto.c app-layer-detect-proto.h \ +app-layer-dnp3.c app-layer-dnp3.h \ +app-layer-dnp3-objects.c app-layer-dnp3-objects.h \ app-layer-dns-common.c app-layer-dns-common.h \ app-layer-dns-tcp.c app-layer-dns-tcp.h \ app-layer-dns-udp.c app-layer-dns-udp.h \ diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 74e22d4ae08a..286dde89cfa6 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -695,6 +695,8 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp printf(" alproto: ALPROTO_ENIP\n"); else if (pp_pe->alproto == ALPROTO_TEMPLATE) printf(" alproto: ALPROTO_TEMPLATE\n"); + else if (pp_pe->alproto == ALPROTO_DNP3) + printf(" alproto: ALPROTO_DNP3\n"); else printf("impossible\n"); @@ -750,6 +752,8 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp printf(" alproto: ALPROTO_ENIP\n"); else if (pp_pe->alproto == ALPROTO_TEMPLATE) printf(" alproto: ALPROTO_TEMPLATE\n"); + else if (pp_pe->alproto == ALPROTO_DNP3) + printf(" alproto: ALPROTO_DNP3\n"); else printf("impossible\n"); diff --git a/src/app-layer-dnp3-objects.c b/src/app-layer-dnp3-objects.c new file mode 100644 index 000000000000..275e646b2cb3 --- /dev/null +++ b/src/app-layer-dnp3-objects.c @@ -0,0 +1,9148 @@ +/* Copyright (C) 2015 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 Jason Ish + * + * This file contains the DNP3 object decoders. + */ + +#include "suricata-common.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +void DNP3FreeObjectPoint(int group, int variation, void *point); + +#if 0 +static void DNP3HexDump(uint8_t *data, int len) +{ + for (int i = 0; i < len; i++) { + printf("%02x ", data[i]); + } +} +#endif + +/** + * \brief Allocate a list for DNP3 points. + */ +DNP3PointList *DNP3PointListAlloc(void) +{ + DNP3PointList *items = SCCalloc(1, sizeof(*items)); + if (unlikely(items == NULL)) { + return NULL; + } + TAILQ_INIT(items); + return items; +} + +/** + * \brief Free a DNP3PointList. + */ +void DNP3FreeObjectPointList(int group, int variation, DNP3PointList *list) +{ + DNP3Point *point; + while ((point = TAILQ_FIRST(list)) != NULL) { + TAILQ_REMOVE(list, point, next); + if (point->data != NULL) { + DNP3FreeObjectPoint(group, variation, point->data); + } + SCFree(point); + } + SCFree(list); +} + +/** + * \brief Read an uint8_t from a buffer. + * + * Reads a uint8_t from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint8(const uint8_t **buf, uint32_t *len, uint8_t *out) +{ + if (*len < (int)sizeof(*out)) { + return 0; + } + *out = *(uint8_t *)(*buf); + *buf += sizeof(*out); + *len -= sizeof(*out); + return 1; +} + +/** + * \brief Read an uint16_t from a buffer. + * + * Reads an uint16_t from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint16(const uint8_t **buf, uint32_t *len, uint16_t *out) +{ + if (*len < (int)sizeof(*out)) { + return 0; + } + *out = DNP3_SWAP16(*(uint16_t *)(*buf)); + *buf += sizeof(*out); + *len -= sizeof(*out); + return 1; +} + +/** + * \brief Read an unsigned 24 bit integer from a buffer. + * + * Reads an an unsigned 24 bit integer from a buffer advancing the + * pointer and decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint24(const uint8_t **buf, uint32_t *len, uint32_t *out) +{ + if (*len < (int)(sizeof(uint8_t) * 3)) { + return 0; + } + +#if __BYTE_ORDER__ == __BIG_ENDIAN + *out = ((uint32_t)(*buf)[0] << 16) | ((uint32_t)(*buf)[1] << 8) | + (uint32_t)(*buf)[2]; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + *out = ((uint64_t)(*buf)[0]) | ((uint64_t)(*buf)[1] << 8) | + ((uint64_t)(*buf)[2] << 16); +#endif + + *buf += 3; + *len -= 3; + + return 1; +} + +/** + * \brief Read an uint32_t from a buffer. + * + * Reads an uint32_t from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint32(const uint8_t **buf, uint32_t *len, uint32_t *out) +{ + if (*len < (int)sizeof(*out)) { + return 0; + } + *out = DNP3_SWAP32(*(uint32_t *)(*buf)); + *buf += sizeof(*out); + *len -= sizeof(*out); + return 1; +} + +/** + * \brief Read an unsigned 48 bit integer from a buffer. + * + * Reads an an unsigned 48 bit integer from a buffer advancing the + * pointer and decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint48(const uint8_t **buf, uint32_t *len, uint64_t *out) +{ + if (*len < (int)(sizeof(uint8_t) * 6)) { + return 0; + } + +#if __BYTE_ORDER__ == __BIG_ENDIAN + *out = ((uint64_t)(*buf)[0] << 40) | ((uint64_t)(*buf)[1] << 32) | + ((uint64_t)(*buf)[2] << 24) | ((uint64_t)(*buf)[3] << 16) | + ((uint64_t)(*buf)[4] << 8) | (uint64_t)(*buf)[5]; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + *out = ((uint64_t)(*buf)[0]) | ((uint64_t)(*buf)[1] << 8) | + ((uint64_t)(*buf)[2] << 16) | ((uint64_t)(*buf)[3] << 24) | + ((uint64_t)(*buf)[4] << 32) | ((uint64_t)(*buf)[5] << 40); +#endif + + *buf += 6; + *len -= 6; + + return 1; +} + +/** + * \brief Read a 32 bit float from a buffer. + * + * Reads an 32 bit float from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadFloat32(const uint8_t **buf, uint32_t *len, float *out) +{ + if (*len < 4) { + return 0; + } + +#if __BYTE_ORDER == __LITTLE_ENDIAN + *((uint8_t *)out + 0) = (*buf)[0]; + *((uint8_t *)out + 1) = (*buf)[1]; + *((uint8_t *)out + 2) = (*buf)[2]; + *((uint8_t *)out + 3) = (*buf)[3]; +#else + *((uint8_t *)out + 3) = (*buf)[0]; + *((uint8_t *)out + 2) = (*buf)[1]; + *((uint8_t *)out + 1) = (*buf)[2]; + *((uint8_t *)out + 0) = (*buf)[3]; +#endif + *len -= 4; + *buf += 4; + + return 1; +} + +/** + * \brief Read a 64 bit float from a buffer. + * + * Reads an 64 bit float from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadFloat64(const uint8_t **buf, uint32_t *len, double *out) +{ + if (*len < 8) { + return 0; + } + +#if __BYTE_ORDER == __LITTLE_ENDIAN + *((uint8_t *)out + 0) = (*buf)[0]; + *((uint8_t *)out + 1) = (*buf)[1]; + *((uint8_t *)out + 2) = (*buf)[2]; + *((uint8_t *)out + 3) = (*buf)[3]; + *((uint8_t *)out + 4) = (*buf)[4]; + *((uint8_t *)out + 5) = (*buf)[5]; + *((uint8_t *)out + 6) = (*buf)[6]; + *((uint8_t *)out + 7) = (*buf)[7]; +#else + *((uint8_t *)out + 7) = (*buf)[0]; + *((uint8_t *)out + 6) = (*buf)[1]; + *((uint8_t *)out + 5) = (*buf)[2]; + *((uint8_t *)out + 4) = (*buf)[3]; + *((uint8_t *)out + 3) = (*buf)[4]; + *((uint8_t *)out + 2) = (*buf)[5]; + *((uint8_t *)out + 1) = (*buf)[6]; + *((uint8_t *)out + 0) = (*buf)[7]; +#endif + *len -= 8; + *buf += 8; + + return 1; +} + +/** + * \brief Get the prefix value and advance the buffer. + */ +static int DNP3ReadPrefix( + const uint8_t **buf, uint32_t *len, uint8_t prefix_code, uint32_t *out) +{ + uint8_t prefix_len = 0; + + switch (prefix_code) { + case 0x01: + case 0x04: + prefix_len = 1; + break; + case 0x02: + case 0x05: + prefix_len = 2; + break; + case 0x03: + case 0x06: + prefix_len = 4; + default: + break; + } + + if (*len < (uint32_t)prefix_len) { + return 0; + } + + switch (prefix_len) { + case sizeof(uint32_t): + DNP3ReadUint32(buf, len, out); + break; + case sizeof(uint16_t): { + /* Temp value for strict-aliasing. */ + uint16_t val = 0; + DNP3ReadUint16(buf, len, &val); + *out = val; + break; + } + case sizeof(uint8_t): { + /* Temp value for strict-aliasing. */ + uint8_t val = 0; + DNP3ReadUint8(buf, len, &val); + *out = val; + break; + } + default: + *out = 0; + break; + } + + return 1; +} + +/** + * \brief Add an object to a DNP3PointList. + * + * \retval 1 if successfull, 0 on failure. + */ +static int DNP3AddPoint(DNP3PointList *list, void *object, uint32_t index, + uint8_t prefix_code, uint32_t prefix) +{ + DNP3Point *point = SCCalloc(1, sizeof(*point)); + if (unlikely(point == NULL)) { + return 0; + } + TAILQ_INSERT_TAIL(list, point, next); + point->data = object; + point->prefix = prefix; + point->index = index; + switch (prefix_code) { + case 0x00: + break; + case 0x01: + case 0x02: + case 0x03: + point->index = prefix; + break; + case 0x04: + case 0x05: + case 0x06: + point->size = prefix; + break; + default: + break; + } + + return 1; +} + +/* START GENERATED CODE */ + +/* Code generated by: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +static int DNP3DecodeObjectG1V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG1V1 *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG1V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG1V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->reserved = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG2V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG2V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->state)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG2V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG2V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->reserved = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG2V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG2V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->reserved = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG3V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG3V1 *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 2) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x3; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG3V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG3V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG4V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG4V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG4V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG4V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG4V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG4V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint16(buf, len, &object->relative_time_ms)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG10V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG10V1 *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG10V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG10V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->reserved1 = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG11V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG11V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->reserved1 = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG11V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG11V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->reserved1 = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG12V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG12V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->op_type = (octet >> 0) & 0xf; + object->qu = (octet >> 4) & 0x1; + object->cr = (octet >> 5) & 0x1; + object->tcc = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint8(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->ontime)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->offtime)) { + goto error; + } + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG12V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG12V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->op_type = (octet >> 0) & 0xf; + object->qu = (octet >> 4) & 0x1; + object->cr = (octet >> 5) & 0x1; + object->tcc = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint8(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->ontime)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->offtime)) { + goto error; + } + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG12V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG12V3 *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->point = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG13V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG13V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->commanded_state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG13V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG13V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->commanded_state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V9(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V9 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V10(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V10 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V11(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V11 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V12(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V12 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG34V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG34V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->deadband_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG34V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG34V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->deadband_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG34V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG34V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadFloat32(buf, len, &object->deadband_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG40V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG40V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG40V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG40V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG41V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG41V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG41V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG41V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG50V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG50V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->interval)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG50V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG50V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->interval_count)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->interval_units)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG51V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG51V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG51V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG51V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG52V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG52V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->delay_secs)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG52V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG52V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->delay_ms)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->filename_size)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->filetype_code)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->attribute_code)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->start_record)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->end_record)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->created_timestamp)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->permission)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->owner_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->group_id)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->file_function_code)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->status_code)) { + goto error; + } + if (object->filename_size > 0) { + memcpy(object->filename, *buf, object->filename_size); + *buf += object->filename_size; + *len -= object->filename_size; + } + object->filename[object->filename_size] = '\0'; + if (!DNP3ReadUint16(buf, len, &object->data_size)) { + goto error; + } + if (object->data_size > 0) { + memcpy(object->data, *buf, object->data_size); + *buf += object->data_size; + *len -= object->data_size; + } + object->data[object->data_size] = '\0'; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->username_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->username_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->password_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->password_size)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->authentication_key)) { + goto error; + } + if (object->username_size > 0) { + memcpy(object->username, *buf, object->username_size); + *buf += object->username_size; + *len -= object->username_size; + } + object->username[object->username_size] = '\0'; + if (object->password_size > 0) { + memcpy(object->password, *buf, object->password_size); + *buf += object->password_size; + *len -= object->password_size; + } + object->password[object->password_size] = '\0'; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->filename_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->filename_size)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->created)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->permissions)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->authentication_key)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->operational_mode)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->maximum_block_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->request_id)) { + goto error; + } + if (object->filename_size > 0) { + memcpy(object->filename, *buf, object->filename_size); + *buf += object->filename_size; + *len -= object->filename_size; + } + object->filename[object->filename_size] = '\0'; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->file_handle)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->maximum_block_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->request_id)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->status_code)) { + goto error; + } + object->optional_text_len = prefix - (offset - *len); + if (object->optional_text_len > 0) { + memcpy(object->optional_text, *buf, object->optional_text_len); + *buf += object->optional_text_len; + *len -= object->optional_text_len; + } + object->optional_text[object->optional_text_len] = '\0'; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->file_handle)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->block_number)) { + goto error; + } + object->file_data_len = prefix - (offset - *len); + if (object->file_data_len > 0) { + memcpy(object->file_data, *buf, object->file_data_len); + *buf += object->file_data_len; + *len -= object->file_data_len; + } + object->file_data[object->file_data_len] = '\0'; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->file_handle)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->block_number)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->status_code)) { + goto error; + } + object->optional_text_len = prefix - (offset - *len); + if (object->optional_text_len > 0) { + memcpy(object->optional_text, *buf, object->optional_text_len); + *buf += object->optional_text_len; + *len -= object->optional_text_len; + } + object->optional_text[object->optional_text_len] = '\0'; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->filename_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->filename_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->file_type)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->created_timestamp)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->permissions)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->request_id)) { + goto error; + } + if (object->filename_size > 0) { + memcpy(object->filename, *buf, object->filename_size); + *buf += object->filename_size; + *len -= object->filename_size; + } + object->filename[object->filename_size] = '\0'; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + object->file_specification_len = prefix - (offset - *len); + if (object->file_specification_len > 0) { + memcpy(object->file_specification, *buf, object->file_specification_len); + *buf += object->file_specification_len; + *len -= object->file_specification_len; + } + object->file_specification[object->file_specification_len] = '\0'; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG80V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG80V1 *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG81V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG81V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->fill_percentage = (octet >> 0) & 0x7f; + object->overflow_state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint8(buf, len, &object->group)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->variation)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG83V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG83V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (*len < 4) { + goto error; + } + memcpy(object->vendor_code, *buf, 4); + object->vendor_code[4] = '\0'; + *buf += 4; + *len -= 4; + if (!DNP3ReadUint16(buf, len, &object->object_id)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->length)) { + goto error; + } + if (object->length > 0) { + if (*len < object->length) { + /* Not enough data. */ + goto error; + } + object->data_objects = SCCalloc(1, object->length); + if (unlikely(object->data_objects == NULL)) { + goto error; + } + memcpy(object->data_objects, *buf, object->length); + *buf += object->length; + *len -= object->length; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG86V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG86V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->rd = (octet >> 0) & 0x1; + object->wr = (octet >> 1) & 0x1; + object->st = (octet >> 2) & 0x1; + object->ev = (octet >> 3) & 0x1; + object->df = (octet >> 4) & 0x1; + object->padding0 = (octet >> 5) & 0x1; + object->padding1 = (octet >> 6) & 0x1; + object->padding2 = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG102V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG102V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->csq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->mal)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->reason)) { + goto error; + } + object->challenge_data_len = prefix - (offset - *len); + if (object->challenge_data_len > 0) { + if (*len < object->challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->challenge_data = SCCalloc(1, object->challenge_data_len); + if (unlikely(object->challenge_data == NULL)) { + goto error; + } + memcpy(object->challenge_data, *buf, object->challenge_data_len); + *buf += object->challenge_data_len; + *len -= object->challenge_data_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->csq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + object->mac_value_len = prefix - (offset - *len); + if (object->mac_value_len > 0) { + if (*len < object->mac_value_len) { + /* Not enough data. */ + goto error; + } + object->mac_value = SCCalloc(1, object->mac_value_len); + if (unlikely(object->mac_value == NULL)) { + goto error; + } + memcpy(object->mac_value, *buf, object->mac_value_len); + *buf += object->mac_value_len; + *len -= object->mac_value_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V3 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->csq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V4 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V5 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->key_wrap_alg)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->key_status)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->mal)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->challenge_data_len)) { + goto error; + } + if (object->challenge_data_len > 0) { + if (*len < object->challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->challenge_data = SCCalloc(1, object->challenge_data_len); + if (unlikely(object->challenge_data == NULL)) { + goto error; + } + memcpy(object->challenge_data, *buf, object->challenge_data_len); + *buf += object->challenge_data_len; + *len -= object->challenge_data_len; + } + object->mac_value_len = prefix - (offset - *len); + if (object->mac_value_len > 0) { + if (*len < object->mac_value_len) { + /* Not enough data. */ + goto error; + } + object->mac_value = SCCalloc(1, object->mac_value_len); + if (unlikely(object->mac_value == NULL)) { + goto error; + } + memcpy(object->mac_value, *buf, object->mac_value_len); + *buf += object->mac_value_len; + *len -= object->mac_value_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V6 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint24(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + object->wrapped_key_data_len = prefix - (offset - *len); + if (object->wrapped_key_data_len > 0) { + if (*len < object->wrapped_key_data_len) { + /* Not enough data. */ + goto error; + } + object->wrapped_key_data = SCCalloc(1, object->wrapped_key_data_len); + if (unlikely(object->wrapped_key_data == NULL)) { + goto error; + } + memcpy(object->wrapped_key_data, *buf, object->wrapped_key_data_len); + *buf += object->wrapped_key_data_len; + *len -= object->wrapped_key_data_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V7 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->sequence_number)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->error_code)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->time_of_error)) { + goto error; + } + object->error_text_len = prefix - (offset - *len); + if (object->error_text_len > 0) { + memcpy(object->error_text, *buf, object->error_text_len); + *buf += object->error_text_len; + *len -= object->error_text_len; + } + object->error_text[object->error_text_len] = '\0'; + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V8 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->certificate_type)) { + goto error; + } + object->certificate_len = prefix - (offset - *len); + if (object->certificate_len > 0) { + if (*len < object->certificate_len) { + /* Not enough data. */ + goto error; + } + object->certificate = SCCalloc(1, object->certificate_len); + if (unlikely(object->certificate == NULL)) { + goto error; + } + memcpy(object->certificate, *buf, object->certificate_len); + *buf += object->certificate_len; + *len -= object->certificate_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V9(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V9 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + object->mac_value_len = prefix - (offset - *len); + if (object->mac_value_len > 0) { + if (*len < object->mac_value_len) { + /* Not enough data. */ + goto error; + } + object->mac_value = SCCalloc(1, object->mac_value_len); + if (unlikely(object->mac_value == NULL)) { + goto error; + } + memcpy(object->mac_value, *buf, object->mac_value_len); + *buf += object->mac_value_len; + *len -= object->mac_value_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V10(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V10 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->operation)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->scs)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_role)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_role_expiry_interval)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->username_len)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_public_key_len)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->certification_data_len)) { + goto error; + } + if (object->username_len > 0) { + memcpy(object->username, *buf, object->username_len); + *buf += object->username_len; + *len -= object->username_len; + } + object->username[object->username_len] = '\0'; + if (object->user_public_key_len > 0) { + if (*len < object->user_public_key_len) { + /* Not enough data. */ + goto error; + } + object->user_public_key = SCCalloc(1, object->user_public_key_len); + if (unlikely(object->user_public_key == NULL)) { + goto error; + } + memcpy(object->user_public_key, *buf, object->user_public_key_len); + *buf += object->user_public_key_len; + *len -= object->user_public_key_len; + } + if (object->certification_data_len > 0) { + if (*len < object->certification_data_len) { + /* Not enough data. */ + goto error; + } + object->certification_data = SCCalloc(1, object->certification_data_len); + if (unlikely(object->certification_data == NULL)) { + goto error; + } + memcpy(object->certification_data, *buf, object->certification_data_len); + *buf += object->certification_data_len; + *len -= object->certification_data_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V11(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V11 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->username_len)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->master_challenge_data_len)) { + goto error; + } + if (object->username_len > 0) { + memcpy(object->username, *buf, object->username_len); + *buf += object->username_len; + *len -= object->username_len; + } + object->username[object->username_len] = '\0'; + if (object->master_challenge_data_len > 0) { + if (*len < object->master_challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->master_challenge_data = SCCalloc(1, object->master_challenge_data_len); + if (unlikely(object->master_challenge_data == NULL)) { + goto error; + } + memcpy(object->master_challenge_data, *buf, object->master_challenge_data_len); + *buf += object->master_challenge_data_len; + *len -= object->master_challenge_data_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V12(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V12 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->challenge_data_len)) { + goto error; + } + if (object->challenge_data_len > 0) { + if (*len < object->challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->challenge_data = SCCalloc(1, object->challenge_data_len); + if (unlikely(object->challenge_data == NULL)) { + goto error; + } + memcpy(object->challenge_data, *buf, object->challenge_data_len); + *buf += object->challenge_data_len; + *len -= object->challenge_data_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V13(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V13 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->encrypted_update_key_len)) { + goto error; + } + if (object->encrypted_update_key_len > 0) { + if (*len < object->encrypted_update_key_len) { + /* Not enough data. */ + goto error; + } + object->encrypted_update_key_data = SCCalloc(1, object->encrypted_update_key_len); + if (unlikely(object->encrypted_update_key_data == NULL)) { + goto error; + } + memcpy(object->encrypted_update_key_data, *buf, object->encrypted_update_key_len); + *buf += object->encrypted_update_key_len; + *len -= object->encrypted_update_key_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V14(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V14 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + object->digital_signature_len = prefix - (offset - *len); + if (object->digital_signature_len > 0) { + if (*len < object->digital_signature_len) { + /* Not enough data. */ + goto error; + } + object->digital_signature = SCCalloc(1, object->digital_signature_len); + if (unlikely(object->digital_signature == NULL)) { + goto error; + } + memcpy(object->digital_signature, *buf, object->digital_signature_len); + *buf += object->digital_signature_len; + *len -= object->digital_signature_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V15(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V15 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + object->mac_len = prefix - (offset - *len); + if (object->mac_len > 0) { + if (*len < object->mac_len) { + /* Not enough data. */ + goto error; + } + object->mac = SCCalloc(1, object->mac_len); + if (unlikely(object->mac == NULL)) { + goto error; + } + memcpy(object->mac, *buf, object->mac_len); + *buf += object->mac_len; + *len -= object->mac_len; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG121V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG121V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->count_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG122V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG122V1 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->count_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG122V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG122V2 *object = NULL; + uint32_t prefix = 0; + uint32_t index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->count_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + + +void DNP3FreeObjectPoint(int group, int variation, void *point) +{ + switch(DNP3_OBJECT_CODE(group, variation)) { + case DNP3_OBJECT_CODE(83, 1): { + DNP3ObjectG83V1 *object = (DNP3ObjectG83V1 *) point; + if (object->data_objects != NULL) { + SCFree(object->data_objects); + } + break; + } + case DNP3_OBJECT_CODE(120, 1): { + DNP3ObjectG120V1 *object = (DNP3ObjectG120V1 *) point; + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 2): { + DNP3ObjectG120V2 *object = (DNP3ObjectG120V2 *) point; + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + break; + } + case DNP3_OBJECT_CODE(120, 5): { + DNP3ObjectG120V5 *object = (DNP3ObjectG120V5 *) point; + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + break; + } + case DNP3_OBJECT_CODE(120, 6): { + DNP3ObjectG120V6 *object = (DNP3ObjectG120V6 *) point; + if (object->wrapped_key_data != NULL) { + SCFree(object->wrapped_key_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 8): { + DNP3ObjectG120V8 *object = (DNP3ObjectG120V8 *) point; + if (object->certificate != NULL) { + SCFree(object->certificate); + } + break; + } + case DNP3_OBJECT_CODE(120, 9): { + DNP3ObjectG120V9 *object = (DNP3ObjectG120V9 *) point; + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + break; + } + case DNP3_OBJECT_CODE(120, 10): { + DNP3ObjectG120V10 *object = (DNP3ObjectG120V10 *) point; + if (object->user_public_key != NULL) { + SCFree(object->user_public_key); + } + if (object->certification_data != NULL) { + SCFree(object->certification_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 11): { + DNP3ObjectG120V11 *object = (DNP3ObjectG120V11 *) point; + if (object->master_challenge_data != NULL) { + SCFree(object->master_challenge_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 12): { + DNP3ObjectG120V12 *object = (DNP3ObjectG120V12 *) point; + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 13): { + DNP3ObjectG120V13 *object = (DNP3ObjectG120V13 *) point; + if (object->encrypted_update_key_data != NULL) { + SCFree(object->encrypted_update_key_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 14): { + DNP3ObjectG120V14 *object = (DNP3ObjectG120V14 *) point; + if (object->digital_signature != NULL) { + SCFree(object->digital_signature); + } + break; + } + case DNP3_OBJECT_CODE(120, 15): { + DNP3ObjectG120V15 *object = (DNP3ObjectG120V15 *) point; + if (object->mac != NULL) { + SCFree(object->mac); + } + break; + } + default: + break; + } + SCFree(point); +} + +/** + * \brief Decode a DNP3 object. + * + * \retval 0 on success. On failure a positive integer corresponding + * to a DNP3 application layer event will be returned. + */ +int DNP3DecodeObject(int group, int variation, const uint8_t **buf, + uint32_t *len, uint8_t prefix_code, uint32_t start, + uint32_t count, DNP3PointList *points) +{ + int rc = 0; + + switch (DNP3_OBJECT_CODE(group, variation)) { + case DNP3_OBJECT_CODE(1, 1): + rc = DNP3DecodeObjectG1V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(1, 2): + rc = DNP3DecodeObjectG1V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(2, 1): + rc = DNP3DecodeObjectG2V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(2, 2): + rc = DNP3DecodeObjectG2V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(2, 3): + rc = DNP3DecodeObjectG2V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(3, 1): + rc = DNP3DecodeObjectG3V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(3, 2): + rc = DNP3DecodeObjectG3V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(4, 1): + rc = DNP3DecodeObjectG4V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(4, 2): + rc = DNP3DecodeObjectG4V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(4, 3): + rc = DNP3DecodeObjectG4V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(10, 1): + rc = DNP3DecodeObjectG10V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(10, 2): + rc = DNP3DecodeObjectG10V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(11, 1): + rc = DNP3DecodeObjectG11V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(11, 2): + rc = DNP3DecodeObjectG11V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(12, 1): + rc = DNP3DecodeObjectG12V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(12, 2): + rc = DNP3DecodeObjectG12V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(12, 3): + rc = DNP3DecodeObjectG12V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(13, 1): + rc = DNP3DecodeObjectG13V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(13, 2): + rc = DNP3DecodeObjectG13V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 1): + rc = DNP3DecodeObjectG20V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 2): + rc = DNP3DecodeObjectG20V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 3): + rc = DNP3DecodeObjectG20V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 4): + rc = DNP3DecodeObjectG20V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 5): + rc = DNP3DecodeObjectG20V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 6): + rc = DNP3DecodeObjectG20V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 7): + rc = DNP3DecodeObjectG20V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 8): + rc = DNP3DecodeObjectG20V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 1): + rc = DNP3DecodeObjectG21V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 2): + rc = DNP3DecodeObjectG21V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 3): + rc = DNP3DecodeObjectG21V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 4): + rc = DNP3DecodeObjectG21V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 5): + rc = DNP3DecodeObjectG21V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 6): + rc = DNP3DecodeObjectG21V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 7): + rc = DNP3DecodeObjectG21V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 8): + rc = DNP3DecodeObjectG21V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 9): + rc = DNP3DecodeObjectG21V9(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 10): + rc = DNP3DecodeObjectG21V10(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 11): + rc = DNP3DecodeObjectG21V11(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 12): + rc = DNP3DecodeObjectG21V12(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 1): + rc = DNP3DecodeObjectG22V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 2): + rc = DNP3DecodeObjectG22V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 3): + rc = DNP3DecodeObjectG22V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 4): + rc = DNP3DecodeObjectG22V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 5): + rc = DNP3DecodeObjectG22V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 6): + rc = DNP3DecodeObjectG22V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 7): + rc = DNP3DecodeObjectG22V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 8): + rc = DNP3DecodeObjectG22V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 1): + rc = DNP3DecodeObjectG23V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 2): + rc = DNP3DecodeObjectG23V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 3): + rc = DNP3DecodeObjectG23V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 4): + rc = DNP3DecodeObjectG23V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 5): + rc = DNP3DecodeObjectG23V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 6): + rc = DNP3DecodeObjectG23V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 7): + rc = DNP3DecodeObjectG23V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 8): + rc = DNP3DecodeObjectG23V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 1): + rc = DNP3DecodeObjectG30V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 2): + rc = DNP3DecodeObjectG30V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 3): + rc = DNP3DecodeObjectG30V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 4): + rc = DNP3DecodeObjectG30V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 5): + rc = DNP3DecodeObjectG30V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 6): + rc = DNP3DecodeObjectG30V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 1): + rc = DNP3DecodeObjectG31V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 2): + rc = DNP3DecodeObjectG31V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 3): + rc = DNP3DecodeObjectG31V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 4): + rc = DNP3DecodeObjectG31V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 5): + rc = DNP3DecodeObjectG31V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 6): + rc = DNP3DecodeObjectG31V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 7): + rc = DNP3DecodeObjectG31V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 8): + rc = DNP3DecodeObjectG31V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 1): + rc = DNP3DecodeObjectG32V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 2): + rc = DNP3DecodeObjectG32V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 3): + rc = DNP3DecodeObjectG32V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 4): + rc = DNP3DecodeObjectG32V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 5): + rc = DNP3DecodeObjectG32V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 6): + rc = DNP3DecodeObjectG32V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 7): + rc = DNP3DecodeObjectG32V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 8): + rc = DNP3DecodeObjectG32V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 1): + rc = DNP3DecodeObjectG33V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 2): + rc = DNP3DecodeObjectG33V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 3): + rc = DNP3DecodeObjectG33V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 4): + rc = DNP3DecodeObjectG33V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 5): + rc = DNP3DecodeObjectG33V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 6): + rc = DNP3DecodeObjectG33V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 7): + rc = DNP3DecodeObjectG33V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 8): + rc = DNP3DecodeObjectG33V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(34, 1): + rc = DNP3DecodeObjectG34V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(34, 2): + rc = DNP3DecodeObjectG34V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(34, 3): + rc = DNP3DecodeObjectG34V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(40, 1): + rc = DNP3DecodeObjectG40V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(40, 2): + rc = DNP3DecodeObjectG40V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(40, 3): + rc = DNP3DecodeObjectG40V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(40, 4): + rc = DNP3DecodeObjectG40V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(41, 1): + rc = DNP3DecodeObjectG41V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(41, 2): + rc = DNP3DecodeObjectG41V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(41, 3): + rc = DNP3DecodeObjectG41V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(41, 4): + rc = DNP3DecodeObjectG41V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 1): + rc = DNP3DecodeObjectG42V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 2): + rc = DNP3DecodeObjectG42V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 3): + rc = DNP3DecodeObjectG42V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 4): + rc = DNP3DecodeObjectG42V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 5): + rc = DNP3DecodeObjectG42V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 6): + rc = DNP3DecodeObjectG42V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 7): + rc = DNP3DecodeObjectG42V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 8): + rc = DNP3DecodeObjectG42V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 1): + rc = DNP3DecodeObjectG43V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 2): + rc = DNP3DecodeObjectG43V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 3): + rc = DNP3DecodeObjectG43V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 4): + rc = DNP3DecodeObjectG43V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 5): + rc = DNP3DecodeObjectG43V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 6): + rc = DNP3DecodeObjectG43V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 7): + rc = DNP3DecodeObjectG43V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 8): + rc = DNP3DecodeObjectG43V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(50, 1): + rc = DNP3DecodeObjectG50V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(50, 2): + rc = DNP3DecodeObjectG50V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(50, 3): + rc = DNP3DecodeObjectG50V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(50, 4): + rc = DNP3DecodeObjectG50V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(51, 1): + rc = DNP3DecodeObjectG51V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(51, 2): + rc = DNP3DecodeObjectG51V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(52, 1): + rc = DNP3DecodeObjectG52V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(52, 2): + rc = DNP3DecodeObjectG52V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 1): + rc = DNP3DecodeObjectG70V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 2): + rc = DNP3DecodeObjectG70V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 3): + rc = DNP3DecodeObjectG70V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 4): + rc = DNP3DecodeObjectG70V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 5): + rc = DNP3DecodeObjectG70V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 6): + rc = DNP3DecodeObjectG70V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 7): + rc = DNP3DecodeObjectG70V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 8): + rc = DNP3DecodeObjectG70V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(80, 1): + rc = DNP3DecodeObjectG80V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(81, 1): + rc = DNP3DecodeObjectG81V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(83, 1): + rc = DNP3DecodeObjectG83V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(86, 2): + rc = DNP3DecodeObjectG86V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(102, 1): + rc = DNP3DecodeObjectG102V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 1): + rc = DNP3DecodeObjectG120V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 2): + rc = DNP3DecodeObjectG120V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 3): + rc = DNP3DecodeObjectG120V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 4): + rc = DNP3DecodeObjectG120V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 5): + rc = DNP3DecodeObjectG120V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 6): + rc = DNP3DecodeObjectG120V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 7): + rc = DNP3DecodeObjectG120V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 8): + rc = DNP3DecodeObjectG120V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 9): + rc = DNP3DecodeObjectG120V9(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 10): + rc = DNP3DecodeObjectG120V10(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 11): + rc = DNP3DecodeObjectG120V11(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 12): + rc = DNP3DecodeObjectG120V12(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 13): + rc = DNP3DecodeObjectG120V13(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 14): + rc = DNP3DecodeObjectG120V14(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 15): + rc = DNP3DecodeObjectG120V15(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(121, 1): + rc = DNP3DecodeObjectG121V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(122, 1): + rc = DNP3DecodeObjectG122V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(122, 2): + rc = DNP3DecodeObjectG122V2(buf, len, prefix_code, start, count, + points); + break; + default: + return DNP3_DECODER_EVENT_UNKNOWN_OBJECT; + } + + return rc ? 0 : DNP3_DECODER_EVENT_MALFORMED; +} + +/* END GENERATED CODE */ diff --git a/src/app-layer-dnp3-objects.h b/src/app-layer-dnp3-objects.h new file mode 100644 index 000000000000..e292f012758b --- /dev/null +++ b/src/app-layer-dnp3-objects.h @@ -0,0 +1,1464 @@ +/* Copyright (C) 2015 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 Jason Ish + * + * This file contains the types (definitions) of the DNP3 objects. + */ + +#ifndef __APP_LAYER_DNP3_OBJECTS_H__ +#define __APP_LAYER_DNP3_OBJECTS_H__ + +#define DNP3_OBJECT_CODE(group, variation) (group << 8 | variation) + +/* START GENERATED CODE */ + +/* Code generated by: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +typedef struct DNP3ObjectG1V1_ { + uint8_t state; +} DNP3ObjectG1V1; + +typedef struct DNP3ObjectG1V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t reserved:1; + uint8_t state:1; +} DNP3ObjectG1V2; + +typedef struct DNP3ObjectG2V1_ { + uint8_t state; +} DNP3ObjectG2V1; + +typedef struct DNP3ObjectG2V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t reserved:1; + uint8_t state:1; + uint64_t timestamp; +} DNP3ObjectG2V2; + +typedef struct DNP3ObjectG2V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t reserved:1; + uint8_t state:1; + uint16_t timestamp; +} DNP3ObjectG2V3; + +typedef struct DNP3ObjectG3V1_ { + uint8_t state; +} DNP3ObjectG3V1; + +typedef struct DNP3ObjectG3V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t state:2; +} DNP3ObjectG3V2; + +typedef struct DNP3ObjectG4V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t state:2; +} DNP3ObjectG4V1; + +typedef struct DNP3ObjectG4V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t state:2; + uint64_t timestamp; +} DNP3ObjectG4V2; + +typedef struct DNP3ObjectG4V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t state:2; + uint16_t relative_time_ms; +} DNP3ObjectG4V3; + +typedef struct DNP3ObjectG10V1_ { + uint8_t state; +} DNP3ObjectG10V1; + +typedef struct DNP3ObjectG10V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint8_t state:1; +} DNP3ObjectG10V2; + +typedef struct DNP3ObjectG11V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint8_t state:1; +} DNP3ObjectG11V1; + +typedef struct DNP3ObjectG11V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint8_t state:1; + uint64_t timestamp; +} DNP3ObjectG11V2; + +typedef struct DNP3ObjectG12V1_ { + uint8_t op_type:4; + uint8_t qu:1; + uint8_t cr:1; + uint8_t tcc:2; + uint8_t count; + uint32_t ontime; + uint32_t offtime; + uint8_t status_code:7; + uint8_t reserved:1; +} DNP3ObjectG12V1; + +typedef struct DNP3ObjectG12V2_ { + uint8_t op_type:4; + uint8_t qu:1; + uint8_t cr:1; + uint8_t tcc:2; + uint8_t count; + uint32_t ontime; + uint32_t offtime; + uint8_t status_code:7; + uint8_t reserved:1; +} DNP3ObjectG12V2; + +typedef struct DNP3ObjectG12V3_ { + uint8_t point; +} DNP3ObjectG12V3; + +typedef struct DNP3ObjectG13V1_ { + uint8_t status_code:7; + uint8_t commanded_state:1; +} DNP3ObjectG13V1; + +typedef struct DNP3ObjectG13V2_ { + uint8_t status_code:7; + uint8_t commanded_state:1; + uint64_t timestamp; +} DNP3ObjectG13V2; + +typedef struct DNP3ObjectG20V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint32_t count; +} DNP3ObjectG20V1; + +typedef struct DNP3ObjectG20V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint16_t count; +} DNP3ObjectG20V2; + +typedef struct DNP3ObjectG20V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; +} DNP3ObjectG20V3; + +typedef struct DNP3ObjectG20V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; +} DNP3ObjectG20V4; + +typedef struct DNP3ObjectG20V5_ { + uint32_t count; +} DNP3ObjectG20V5; + +typedef struct DNP3ObjectG20V6_ { + uint16_t count; +} DNP3ObjectG20V6; + +typedef struct DNP3ObjectG20V7_ { + uint32_t count; +} DNP3ObjectG20V7; + +typedef struct DNP3ObjectG20V8_ { + uint16_t count; +} DNP3ObjectG20V8; + +typedef struct DNP3ObjectG21V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint32_t count; +} DNP3ObjectG21V1; + +typedef struct DNP3ObjectG21V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint16_t count; +} DNP3ObjectG21V2; + +typedef struct DNP3ObjectG21V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; +} DNP3ObjectG21V3; + +typedef struct DNP3ObjectG21V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; +} DNP3ObjectG21V4; + +typedef struct DNP3ObjectG21V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved1:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG21V5; + +typedef struct DNP3ObjectG21V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved1:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG21V6; + +typedef struct DNP3ObjectG21V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG21V7; + +typedef struct DNP3ObjectG21V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG21V8; + +typedef struct DNP3ObjectG21V9_ { + uint32_t count; +} DNP3ObjectG21V9; + +typedef struct DNP3ObjectG21V10_ { + uint16_t count; +} DNP3ObjectG21V10; + +typedef struct DNP3ObjectG21V11_ { + uint32_t count; +} DNP3ObjectG21V11; + +typedef struct DNP3ObjectG21V12_ { + uint16_t count; +} DNP3ObjectG21V12; + +typedef struct DNP3ObjectG22V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint32_t count; +} DNP3ObjectG22V1; + +typedef struct DNP3ObjectG22V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint16_t count; +} DNP3ObjectG22V2; + +typedef struct DNP3ObjectG22V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; +} DNP3ObjectG22V3; + +typedef struct DNP3ObjectG22V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; +} DNP3ObjectG22V4; + +typedef struct DNP3ObjectG22V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG22V5; + +typedef struct DNP3ObjectG22V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG22V6; + +typedef struct DNP3ObjectG22V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG22V7; + +typedef struct DNP3ObjectG22V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG22V8; + +typedef struct DNP3ObjectG23V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint32_t count; +} DNP3ObjectG23V1; + +typedef struct DNP3ObjectG23V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; +} DNP3ObjectG23V2; + +typedef struct DNP3ObjectG23V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; +} DNP3ObjectG23V3; + +typedef struct DNP3ObjectG23V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; +} DNP3ObjectG23V4; + +typedef struct DNP3ObjectG23V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG23V5; + +typedef struct DNP3ObjectG23V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG23V6; + +typedef struct DNP3ObjectG23V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG23V7; + +typedef struct DNP3ObjectG23V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG23V8; + +typedef struct DNP3ObjectG30V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG30V1; + +typedef struct DNP3ObjectG30V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG30V2; + +typedef struct DNP3ObjectG30V3_ { + int32_t value; +} DNP3ObjectG30V3; + +typedef struct DNP3ObjectG30V4_ { + int16_t value; +} DNP3ObjectG30V4; + +typedef struct DNP3ObjectG30V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG30V5; + +typedef struct DNP3ObjectG30V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG30V6; + +typedef struct DNP3ObjectG31V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG31V1; + +typedef struct DNP3ObjectG31V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG31V2; + +typedef struct DNP3ObjectG31V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG31V3; + +typedef struct DNP3ObjectG31V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG31V4; + +typedef struct DNP3ObjectG31V5_ { + int32_t value; +} DNP3ObjectG31V5; + +typedef struct DNP3ObjectG31V6_ { + int16_t value; +} DNP3ObjectG31V6; + +typedef struct DNP3ObjectG31V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG31V7; + +typedef struct DNP3ObjectG31V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG31V8; + +typedef struct DNP3ObjectG32V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG32V1; + +typedef struct DNP3ObjectG32V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG32V2; + +typedef struct DNP3ObjectG32V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG32V3; + +typedef struct DNP3ObjectG32V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG32V4; + +typedef struct DNP3ObjectG32V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG32V5; + +typedef struct DNP3ObjectG32V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG32V6; + +typedef struct DNP3ObjectG32V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; + uint64_t timestamp; +} DNP3ObjectG32V7; + +typedef struct DNP3ObjectG32V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; + uint64_t timestamp; +} DNP3ObjectG32V8; + +typedef struct DNP3ObjectG33V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG33V1; + +typedef struct DNP3ObjectG33V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG33V2; + +typedef struct DNP3ObjectG33V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG33V3; + +typedef struct DNP3ObjectG33V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG33V4; + +typedef struct DNP3ObjectG33V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG33V5; + +typedef struct DNP3ObjectG33V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG33V6; + +typedef struct DNP3ObjectG33V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; + uint64_t timestamp; +} DNP3ObjectG33V7; + +typedef struct DNP3ObjectG33V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; + uint64_t timestamp; +} DNP3ObjectG33V8; + +typedef struct DNP3ObjectG34V1_ { + uint16_t deadband_value; +} DNP3ObjectG34V1; + +typedef struct DNP3ObjectG34V2_ { + uint32_t deadband_value; +} DNP3ObjectG34V2; + +typedef struct DNP3ObjectG34V3_ { + float deadband_value; +} DNP3ObjectG34V3; + +typedef struct DNP3ObjectG40V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG40V1; + +typedef struct DNP3ObjectG40V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG40V2; + +typedef struct DNP3ObjectG40V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG40V3; + +typedef struct DNP3ObjectG40V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG40V4; + +typedef struct DNP3ObjectG41V1_ { + int32_t value; + uint8_t control_status; +} DNP3ObjectG41V1; + +typedef struct DNP3ObjectG41V2_ { + int16_t value; + uint8_t control_status; +} DNP3ObjectG41V2; + +typedef struct DNP3ObjectG41V3_ { + float value; + uint8_t control_status; +} DNP3ObjectG41V3; + +typedef struct DNP3ObjectG41V4_ { + double value; + uint8_t control_status; +} DNP3ObjectG41V4; + +typedef struct DNP3ObjectG42V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG42V1; + +typedef struct DNP3ObjectG42V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG42V2; + +typedef struct DNP3ObjectG42V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG42V3; + +typedef struct DNP3ObjectG42V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG42V4; + +typedef struct DNP3ObjectG42V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG42V5; + +typedef struct DNP3ObjectG42V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG42V6; + +typedef struct DNP3ObjectG42V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; + uint64_t timestamp; +} DNP3ObjectG42V7; + +typedef struct DNP3ObjectG42V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; + uint64_t timestamp; +} DNP3ObjectG42V8; + +typedef struct DNP3ObjectG43V1_ { + uint8_t status_code:7; + uint8_t reserved0:1; + int32_t commanded_value; +} DNP3ObjectG43V1; + +typedef struct DNP3ObjectG43V2_ { + uint8_t status_code:7; + uint8_t reserved0:1; + int16_t commanded_value; +} DNP3ObjectG43V2; + +typedef struct DNP3ObjectG43V3_ { + uint8_t status_code:7; + uint8_t reserved0:1; + int32_t commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V3; + +typedef struct DNP3ObjectG43V4_ { + uint8_t status_code:7; + uint8_t reserved0:1; + int16_t commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V4; + +typedef struct DNP3ObjectG43V5_ { + uint8_t status_code:7; + uint8_t reserved0:1; + float commanded_value; +} DNP3ObjectG43V5; + +typedef struct DNP3ObjectG43V6_ { + uint8_t status_code:7; + uint8_t reserved0:1; + double commanded_value; +} DNP3ObjectG43V6; + +typedef struct DNP3ObjectG43V7_ { + uint8_t status_code:7; + uint8_t reserved0:1; + float commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V7; + +typedef struct DNP3ObjectG43V8_ { + uint8_t status_code:7; + uint8_t reserved0:1; + double commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V8; + +typedef struct DNP3ObjectG50V1_ { + uint64_t timestamp; +} DNP3ObjectG50V1; + +typedef struct DNP3ObjectG50V2_ { + uint64_t timestamp; + uint32_t interval; +} DNP3ObjectG50V2; + +typedef struct DNP3ObjectG50V3_ { + uint64_t timestamp; +} DNP3ObjectG50V3; + +typedef struct DNP3ObjectG50V4_ { + uint64_t timestamp; + uint32_t interval_count; + uint8_t interval_units; +} DNP3ObjectG50V4; + +typedef struct DNP3ObjectG51V1_ { + uint64_t timestamp; +} DNP3ObjectG51V1; + +typedef struct DNP3ObjectG51V2_ { + uint64_t timestamp; +} DNP3ObjectG51V2; + +typedef struct DNP3ObjectG52V1_ { + uint16_t delay_secs; +} DNP3ObjectG52V1; + +typedef struct DNP3ObjectG52V2_ { + uint16_t delay_ms; +} DNP3ObjectG52V2; + +typedef struct DNP3ObjectG70V1_ { + uint16_t filename_size; + uint8_t filetype_code; + uint8_t attribute_code; + uint16_t start_record; + uint16_t end_record; + uint32_t file_size; + uint64_t created_timestamp; + uint16_t permission; + uint32_t file_id; + uint32_t owner_id; + uint32_t group_id; + uint8_t file_function_code; + uint8_t status_code; + char filename[65535]; + uint16_t data_size; + char data[65535]; +} DNP3ObjectG70V1; + +typedef struct DNP3ObjectG70V2_ { + uint16_t username_offset; + uint16_t username_size; + uint16_t password_offset; + uint16_t password_size; + uint32_t authentication_key; + char username[65535]; + char password[65535]; +} DNP3ObjectG70V2; + +typedef struct DNP3ObjectG70V3_ { + uint16_t filename_offset; + uint16_t filename_size; + uint64_t created; + uint16_t permissions; + uint32_t authentication_key; + uint32_t file_size; + uint16_t operational_mode; + uint16_t maximum_block_size; + uint16_t request_id; + char filename[65535]; +} DNP3ObjectG70V3; + +typedef struct DNP3ObjectG70V4_ { + uint32_t file_handle; + uint32_t file_size; + uint16_t maximum_block_size; + uint16_t request_id; + uint8_t status_code; + char optional_text[255]; + uint8_t optional_text_len; +} DNP3ObjectG70V4; + +typedef struct DNP3ObjectG70V5_ { + uint32_t file_handle; + uint32_t block_number; + char file_data[255]; + uint8_t file_data_len; +} DNP3ObjectG70V5; + +typedef struct DNP3ObjectG70V6_ { + uint32_t file_handle; + uint32_t block_number; + uint8_t status_code; + char optional_text[255]; + uint8_t optional_text_len; +} DNP3ObjectG70V6; + +typedef struct DNP3ObjectG70V7_ { + uint16_t filename_offset; + uint16_t filename_size; + uint16_t file_type; + uint32_t file_size; + uint64_t created_timestamp; + uint16_t permissions; + uint16_t request_id; + char filename[65535]; +} DNP3ObjectG70V7; + +typedef struct DNP3ObjectG70V8_ { + char file_specification[65535]; + uint16_t file_specification_len; +} DNP3ObjectG70V8; + +typedef struct DNP3ObjectG80V1_ { + uint8_t state; +} DNP3ObjectG80V1; + +typedef struct DNP3ObjectG81V1_ { + uint8_t fill_percentage:7; + uint8_t overflow_state:1; + uint8_t group; + uint8_t variation; +} DNP3ObjectG81V1; + +typedef struct DNP3ObjectG83V1_ { + char vendor_code[5]; + uint16_t object_id; + uint16_t length; + uint8_t *data_objects; +} DNP3ObjectG83V1; + +typedef struct DNP3ObjectG86V2_ { + uint8_t rd:1; + uint8_t wr:1; + uint8_t st:1; + uint8_t ev:1; + uint8_t df:1; + uint8_t padding0:1; + uint8_t padding1:1; + uint8_t padding2:1; +} DNP3ObjectG86V2; + +typedef struct DNP3ObjectG102V1_ { + uint8_t value; +} DNP3ObjectG102V1; + +typedef struct DNP3ObjectG120V1_ { + uint32_t csq; + uint16_t usr; + uint8_t mal; + uint8_t reason; + uint8_t *challenge_data; + uint16_t challenge_data_len; +} DNP3ObjectG120V1; + +typedef struct DNP3ObjectG120V2_ { + uint32_t csq; + uint16_t usr; + uint8_t *mac_value; + uint16_t mac_value_len; +} DNP3ObjectG120V2; + +typedef struct DNP3ObjectG120V3_ { + uint32_t csq; + uint16_t user_number; +} DNP3ObjectG120V3; + +typedef struct DNP3ObjectG120V4_ { + uint16_t user_number; +} DNP3ObjectG120V4; + +typedef struct DNP3ObjectG120V5_ { + uint32_t ksq; + uint16_t user_number; + uint8_t key_wrap_alg; + uint8_t key_status; + uint8_t mal; + uint16_t challenge_data_len; + uint8_t *challenge_data; + uint8_t *mac_value; + uint16_t mac_value_len; +} DNP3ObjectG120V5; + +typedef struct DNP3ObjectG120V6_ { + uint32_t ksq; + uint16_t usr; + uint8_t *wrapped_key_data; + uint16_t wrapped_key_data_len; +} DNP3ObjectG120V6; + +typedef struct DNP3ObjectG120V7_ { + uint32_t sequence_number; + uint16_t usr; + uint16_t association_id; + uint8_t error_code; + uint64_t time_of_error; + char error_text[65535]; + uint16_t error_text_len; +} DNP3ObjectG120V7; + +typedef struct DNP3ObjectG120V8_ { + uint8_t key_change_method; + uint8_t certificate_type; + uint8_t *certificate; + uint16_t certificate_len; +} DNP3ObjectG120V8; + +typedef struct DNP3ObjectG120V9_ { + uint8_t *mac_value; + uint16_t mac_value_len; +} DNP3ObjectG120V9; + +typedef struct DNP3ObjectG120V10_ { + uint8_t key_change_method; + uint8_t operation; + uint32_t scs; + uint16_t user_role; + uint16_t user_role_expiry_interval; + uint16_t username_len; + uint16_t user_public_key_len; + uint16_t certification_data_len; + char username[65535]; + uint8_t *user_public_key; + uint8_t *certification_data; +} DNP3ObjectG120V10; + +typedef struct DNP3ObjectG120V11_ { + uint8_t key_change_method; + uint16_t username_len; + uint16_t master_challenge_data_len; + char username[65535]; + uint8_t *master_challenge_data; +} DNP3ObjectG120V11; + +typedef struct DNP3ObjectG120V12_ { + uint32_t ksq; + uint16_t user_number; + uint16_t challenge_data_len; + uint8_t *challenge_data; +} DNP3ObjectG120V12; + +typedef struct DNP3ObjectG120V13_ { + uint32_t ksq; + uint16_t user_number; + uint16_t encrypted_update_key_len; + uint8_t *encrypted_update_key_data; +} DNP3ObjectG120V13; + +typedef struct DNP3ObjectG120V14_ { + uint8_t *digital_signature; + uint16_t digital_signature_len; +} DNP3ObjectG120V14; + +typedef struct DNP3ObjectG120V15_ { + uint8_t *mac; + uint32_t mac_len; +} DNP3ObjectG120V15; + +typedef struct DNP3ObjectG121V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t discontinuity:1; + uint8_t reserved1:1; + uint16_t association_id; + uint32_t count_value; +} DNP3ObjectG121V1; + +typedef struct DNP3ObjectG122V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t discontinuity:1; + uint8_t reserved1:1; + uint16_t association_id; + uint32_t count_value; +} DNP3ObjectG122V1; + +typedef struct DNP3ObjectG122V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t discontinuity:1; + uint8_t reserved1:1; + uint16_t association_id; + uint32_t count_value; + uint64_t timestamp; +} DNP3ObjectG122V2; + +/* END GENERATED CODE */ + +int DNP3DecodeObject(int group, int variation, const uint8_t **buf, + uint32_t *len, uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *); +DNP3PointList *DNP3PointListAlloc(void); +void DNP3FreeObjectPointList(int group, int variation, DNP3PointList *); + +#endif /* __APP_LAYER_DNP3_OBJECTS_H__ */ diff --git a/src/app-layer-dnp3.c b/src/app-layer-dnp3.c new file mode 100644 index 000000000000..a2bba227027e --- /dev/null +++ b/src/app-layer-dnp3.c @@ -0,0 +1,2661 @@ +/* Copyright (C) 2015 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. + */ + +#include "suricata-common.h" +#include "stream.h" +#include "util-byte.h" +#include "util-unittest.h" +#include "util-hashlist.h" + +#include "util-print.h" + +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer-detect-proto.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +/* For hexdump(). */ +#include "app-layer-dcerpc-common.h" + +/* Default number of unreplied requests to be considered a flood. */ +#define DNP3_DEFAULT_REQ_FLOOD_COUNT 500 + +#define DNP3_DEFAULT_PORT "20000" + +/* Expected values for the start bytes. */ +#define DNP3_START_BYTE0 0x05 +#define DNP3_START_BYTE1 0x64 + +/* Minimum length for a DNP3 frame. */ +#define DNP3_MIN_LEN 5 + +/* Length of each CRC. */ +#define DNP3_CRC_LEN 2 + +/* DNP3 block size. After the link header a CRC is inserted after + * after 16 bytes of data. */ +#define DNP3_BLOCK_SIZE 16 + +/* Maximum transport layer sequence number. */ +#define DNP3_MAX_TRAN_SEQNO 64 + +/* Maximum application layer sequence number. */ +#define DNP3_MAX_APP_SEQNO 16 + +/* The number of bytes in the header that are counted as part of the + * header length field. */ +#define DNP3_LINK_HDR_LEN 5 + +/* Link function codes. */ +enum { + DNP3_LINK_FC_CONFIRMED_USER_DATA = 3, + DNP3_LINK_FC_UNCONFIRMED_USER_DATA +}; + +/* Reserved addresses. */ +#define DNP3_RESERVED_ADDR_MIN 0xfff0 +#define DNP3_RESERVED_ADDR_MAX 0xfffb + +/* Source addresses must be < 0xfff0. */ +#define DNP3_SRC_ADDR_MAX 0xfff0 + +#define DNP3_OBJ_TIME_SIZE 6 /* AKA UINT48. */ +#define DNP3_OBJ_G12_V1_SIZE 11 +#define DNP3_OBJ_G12_V2_SIZE 11 +#define DNP3_OBJ_G12_V3_SIZE 1 + +/* Extract the prefix code from the object qualifier. */ +#define DNP3_OBJ_PREFIX(x) ((x >> 4) & 0x7) + +/* Extract the range code from the object qualifier. */ +#define DNP3_OBJ_RANGE(x) (x & 0xf) + +/* Decoder event map. */ +SCEnumCharMap dnp3_decoder_event_table[] = { + {"FLOODED", DNP3_DECODER_EVENT_FLOODED}, + {"LEN_TOO_SMALL", DNP3_DECODER_EVENT_LEN_TOO_SMALL}, + {"BAD_LINK_CRC", DNP3_DECODER_EVENT_BAD_LINK_CRC}, + {"BAD_TRANSPORT_CRC", DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC}, + {"MALFORMED", DNP3_DECODER_EVENT_MALFORMED}, + {"UNKNOWN_OBJECT", DNP3_DECODER_EVENT_UNKNOWN_OBJECT}, + {NULL, -1}, +}; + +/* Some DNP3 servers start with a banner. */ +static const char banner[] = "DNP3"; + +/* Calculate the next transport sequence number. */ +#define NEXT_TH_SEQNO(current) ((current + 1) % DNP3_MAX_TRAN_SEQNO) + +/* Calculate the next application sequence number. */ +#define NEXT_APP_SEQNO(current) ((current + 1) % DNP3_MAX_APP_SEQNO) + +/* CRC table generated by pycrc - http://github.com/tpircher/pycrc. + * - Polynomial: 0x3d65. */ +static const uint16_t crc_table[256] = { + 0x0000, 0x365e, 0x6cbc, 0x5ae2, 0xd978, 0xef26, 0xb5c4, 0x839a, + 0xff89, 0xc9d7, 0x9335, 0xa56b, 0x26f1, 0x10af, 0x4a4d, 0x7c13, + 0xb26b, 0x8435, 0xded7, 0xe889, 0x6b13, 0x5d4d, 0x07af, 0x31f1, + 0x4de2, 0x7bbc, 0x215e, 0x1700, 0x949a, 0xa2c4, 0xf826, 0xce78, + 0x29af, 0x1ff1, 0x4513, 0x734d, 0xf0d7, 0xc689, 0x9c6b, 0xaa35, + 0xd626, 0xe078, 0xba9a, 0x8cc4, 0x0f5e, 0x3900, 0x63e2, 0x55bc, + 0x9bc4, 0xad9a, 0xf778, 0xc126, 0x42bc, 0x74e2, 0x2e00, 0x185e, + 0x644d, 0x5213, 0x08f1, 0x3eaf, 0xbd35, 0x8b6b, 0xd189, 0xe7d7, + 0x535e, 0x6500, 0x3fe2, 0x09bc, 0x8a26, 0xbc78, 0xe69a, 0xd0c4, + 0xacd7, 0x9a89, 0xc06b, 0xf635, 0x75af, 0x43f1, 0x1913, 0x2f4d, + 0xe135, 0xd76b, 0x8d89, 0xbbd7, 0x384d, 0x0e13, 0x54f1, 0x62af, + 0x1ebc, 0x28e2, 0x7200, 0x445e, 0xc7c4, 0xf19a, 0xab78, 0x9d26, + 0x7af1, 0x4caf, 0x164d, 0x2013, 0xa389, 0x95d7, 0xcf35, 0xf96b, + 0x8578, 0xb326, 0xe9c4, 0xdf9a, 0x5c00, 0x6a5e, 0x30bc, 0x06e2, + 0xc89a, 0xfec4, 0xa426, 0x9278, 0x11e2, 0x27bc, 0x7d5e, 0x4b00, + 0x3713, 0x014d, 0x5baf, 0x6df1, 0xee6b, 0xd835, 0x82d7, 0xb489, + 0xa6bc, 0x90e2, 0xca00, 0xfc5e, 0x7fc4, 0x499a, 0x1378, 0x2526, + 0x5935, 0x6f6b, 0x3589, 0x03d7, 0x804d, 0xb613, 0xecf1, 0xdaaf, + 0x14d7, 0x2289, 0x786b, 0x4e35, 0xcdaf, 0xfbf1, 0xa113, 0x974d, + 0xeb5e, 0xdd00, 0x87e2, 0xb1bc, 0x3226, 0x0478, 0x5e9a, 0x68c4, + 0x8f13, 0xb94d, 0xe3af, 0xd5f1, 0x566b, 0x6035, 0x3ad7, 0x0c89, + 0x709a, 0x46c4, 0x1c26, 0x2a78, 0xa9e2, 0x9fbc, 0xc55e, 0xf300, + 0x3d78, 0x0b26, 0x51c4, 0x679a, 0xe400, 0xd25e, 0x88bc, 0xbee2, + 0xc2f1, 0xf4af, 0xae4d, 0x9813, 0x1b89, 0x2dd7, 0x7735, 0x416b, + 0xf5e2, 0xc3bc, 0x995e, 0xaf00, 0x2c9a, 0x1ac4, 0x4026, 0x7678, + 0x0a6b, 0x3c35, 0x66d7, 0x5089, 0xd313, 0xe54d, 0xbfaf, 0x89f1, + 0x4789, 0x71d7, 0x2b35, 0x1d6b, 0x9ef1, 0xa8af, 0xf24d, 0xc413, + 0xb800, 0x8e5e, 0xd4bc, 0xe2e2, 0x6178, 0x5726, 0x0dc4, 0x3b9a, + 0xdc4d, 0xea13, 0xb0f1, 0x86af, 0x0535, 0x336b, 0x6989, 0x5fd7, + 0x23c4, 0x159a, 0x4f78, 0x7926, 0xfabc, 0xcce2, 0x9600, 0xa05e, + 0x6e26, 0x5878, 0x029a, 0x34c4, 0xb75e, 0x8100, 0xdbe2, 0xedbc, + 0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235 +}; + +/** + * \brief Compute the CRC for a buffer. + * + * \param buf Buffer to create CRC from. + * \param len Length of buffer (number of bytes to use for CRC). + + */ +static uint16_t DNP3ComputeCRC(const uint8_t *buf, uint32_t len) +{ + const uint8_t *byte = buf; + uint16_t crc = 0; + int idx; + + while (len--) { + idx = (crc ^ *byte) & 0xff; + crc = (crc_table[idx] ^ (crc >> 8)) & 0xffff; + byte++; + } + + return ~crc & 0xffff; +} + +/** + * \brief Check the CRC of a block. + * + * \param block The block of data with CRC to be checked. + * \param len The size of the data block. + * + * \retval 1 if CRC is OK, otherwise 0. + */ +static int DNP3CheckCRC(const uint8_t *block, uint32_t len) +{ + uint32_t crc_offset; + uint16_t crc; + + /* Need at least one byte plus the CRC. */ + if (len < DNP3_CRC_LEN + 1) { + return 0; + } + + crc_offset = len - DNP3_CRC_LEN; + crc = DNP3ComputeCRC(block, len - DNP3_CRC_LEN); + if (((crc & 0xff) == block[crc_offset]) && + ((crc >> 8) == block[crc_offset + 1])) { + return 1; + } + + return 0; +} + +/** + * \brief Check the CRC of the link header. + * + * \param header Point to the link header. + * + * \retval 1 if header CRC is OK, otherwise 0. + */ +static int DNP3CheckLinkHeaderCRC(const DNP3LinkHeader *header) +{ + return DNP3CheckCRC((uint8_t *)header, sizeof(DNP3LinkHeader)); +} + +/** + * \brief Check user data CRCs. + * + * \param data Pointer to user data. + * \param len Length of user data. + * + * \retval 1 if CRCs are OK, otherwise 0. + */ +static int DNP3CheckUserDataCRCs(const uint8_t *data, uint32_t len) +{ + uint32_t offset = 0; + uint32_t block_size; + + while (offset < len) { + if (len - offset >= DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { + block_size = DNP3_BLOCK_SIZE + DNP3_CRC_LEN; + } + else { + block_size = len - offset; + } + + if (!DNP3CheckCRC(data + offset, block_size)) { + /* Once failed, may as well return immediately. */ + return 0; + } + + offset += block_size; + } + + return 1; +} + +/** + * \brief Check the DNP3 frame start bytes. + * + * \retval 1 if valid, 0 if not. + */ +static int DNP3CheckStartBytes(const DNP3LinkHeader *header) +{ + return header->start_byte0 == DNP3_START_BYTE0 && + header->start_byte1 == DNP3_START_BYTE1; +} + +/** + * \brief Check if a frame contains a banner. + * + * Some servers (outstations) appear to send back a banner that fails + * the normal frame checks. So first check for a banner. + * + * \retval 1 if a banner is found, 0 if not. + */ +static int DNP3ContainsBanner(const uint8_t *input, uint32_t len) +{ + return memmem(input, len, banner, strlen(banner)) != NULL; +} + +/** + * \brief DNP3 probing parser. + */ +static uint16_t DNP3ProbingParser(uint8_t *input, uint32_t len, + uint32_t *offset) +{ + DNP3LinkHeader *hdr = (DNP3LinkHeader *)input; + + /* Check that we have the minimum amount of bytes. */ + if (len < sizeof(DNP3LinkHeader)) { + SCLogDebug("Length too small to be a DNP3 header."); + return ALPROTO_UNKNOWN; + } + + /* May be a banner. */ + if (DNP3ContainsBanner(input, len)) { + SCLogDebug("Packet contains a DNP3 banner."); + goto end; + } + + /* Verify start value (from AN2013-004b). */ + if (!DNP3CheckStartBytes(hdr)) { + SCLogDebug("Invalid start bytes."); + return ALPROTO_FAILED; + } + + /* Verify minimum length. */ + if (hdr->len < DNP3_MIN_LEN) { + SCLogDebug("Packet too small to be a valid DNP3 fragment."); + return ALPROTO_FAILED; + } + +end: + SCLogDebug("Detected DNP3."); + return ALPROTO_DNP3; +} + +/** + * \brief Caculate the length of the transport layer with CRCs removed. + * + * \param input_len The length of the transport layer buffer. + * + * \retval The length of the buffer after CRCs are removed. + */ +static int DNP3CalculateTransportLengthWithoutCRCs(uint32_t input_len) +{ + /* Too small. */ + if (input_len < DNP3_CRC_LEN) { + return -1; + } + + /* Get the number of complete blocks. */ + int blocks = input_len / (DNP3_BLOCK_SIZE + DNP3_CRC_LEN); + + /* And the number of bytes in the last block. */ + int rem = input_len - (blocks * (DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); + + if (rem) { + if (rem < DNP3_CRC_LEN) { + return -1; + } + return (blocks * DNP3_BLOCK_SIZE) + (rem - DNP3_CRC_LEN); + } + else { + return (blocks * DNP3_BLOCK_SIZE); + } +} + +/** + * \brief Reassemble the application layer by stripping the CRCs. + * + * Remove the CRCs from the user data blocks. The output is the user + * data with the CRCs removed as well as the transport header removed, + * but the input data still needs to include the transport header as + * its part of the first user data block. + * + * If the output length passed in is non-null, the new input data will + * be appended, and the output length pointer incremented as needed. + * + * \param input Input buffer starting at the transport header (which + * will be removed from the output). + * \param input_len Length of the input buffer. + * \param output Pointer to output buffer (may be realloc'd). + * \param output_len Pointer to output length. + * + * \retval 1 if reassembly was successful, otherwise 0. + */ +static int DNP3ReassembleApplicationLayer(const uint8_t *input, + uint32_t input_len, uint8_t **output, uint32_t *output_len) +{ + int len = DNP3CalculateTransportLengthWithoutCRCs(input_len); + + if (len <= 0) { + return 0; + } + + /* Remove one byte for the transport header and make sure we have + * at least one byte of user data. */ + if (--len < 1) { + return 0; + } + + if (*output == NULL) { + *output = SCCalloc(1, len); + if (unlikely(*output == NULL)) { + return 0; + } + } + else { + uint8_t *ptr = SCRealloc(*output, (size_t)(*output_len + len)); + if (unlikely(ptr == NULL)) { + return 0; + } + *output = ptr; + } + + int offset = 0, block_size; + while ((uint32_t)offset < input_len) { + if (input_len - offset > DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { + block_size = DNP3_BLOCK_SIZE + DNP3_CRC_LEN; + } + else { + block_size = input_len - offset; + } + + /* If handling the first block (offset is 0), trim off the + * first byte which is the transport header, and not part of + * the application data. */ + if (offset == 0) { + offset++; + block_size--; + } + + /* Need at least 3 bytes to continue. One for application + * data, and 2 for the CRC. If not, return failure for + * malformed frame. */ + if (block_size < DNP3_CRC_LEN + 1) { + SCLogDebug("Not enough data to continue."); + return 0; + } + + /* Make sure there is enough space to write into. */ + if (block_size - DNP3_CRC_LEN > len) { + SCLogDebug("Not enough data to continue."); + return 0; + } + + memcpy(*output + *output_len, input + offset, + block_size - DNP3_CRC_LEN); + *output_len += block_size - DNP3_CRC_LEN; + offset += block_size; + len -= block_size - DNP3_CRC_LEN; + } + + return 1; +} + +/** + * \brief Allocate a DNP3 state object. + * + * The DNP3 state object represents a single DNP3 TCP session. + */ +static void *DNP3StateAlloc(void) +{ + SCEnter(); + DNP3State *dnp3; + + dnp3 = (DNP3State *)SCCalloc(1, sizeof(DNP3State)); + if (unlikely(dnp3 == NULL)) { + return NULL; + } + TAILQ_INIT(&dnp3->tx_list); + + SCReturnPtr(dnp3, "void"); +} + +/** + * \brief Set a DNP3 application layer event. + * + * Sets an event on the current transaction object. + */ +static void DNP3SetEvent(DNP3State *dnp3, uint8_t event) +{ + if (dnp3 && dnp3->curr) { + AppLayerDecoderEventsSetEventRaw(&dnp3->curr->decoder_events, event); + dnp3->events++; + } + else { + SCLogWarning(SC_ERR_ALPARSER, + "Fail set set event, state or txn was NULL."); + } +} + +/** + * \brief Set a DNP3 application layer event on a transaction. + */ +static void DNP3SetEventTx(DNP3Transaction *tx, uint8_t event) +{ + AppLayerDecoderEventsSetEventRaw(&tx->decoder_events, event); + tx->dnp3->events++; +} + +/** + * \brief Allocation a DNP3 transaction. + */ +static DNP3Transaction *DNP3TxAlloc(DNP3State *dnp3) +{ + DNP3Transaction *tx = SCCalloc(1, sizeof(DNP3Transaction)); + if (unlikely(tx == NULL)) { + return NULL; + } + dnp3->transaction_max++; + dnp3->unreplied++; + dnp3->curr = tx; + tx->dnp3 = dnp3; + tx->tx_num = dnp3->transaction_max; + TAILQ_INIT(&tx->request_objects); + TAILQ_INIT(&tx->response_objects); + TAILQ_INSERT_TAIL(&dnp3->tx_list, tx, next); + + /* Check for flood state. */ + if (dnp3->unreplied > DNP3_DEFAULT_REQ_FLOOD_COUNT) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_FLOODED); + dnp3->flooded = 1; + } + + return tx; +} + +/** + * \brief Calculate the length of a link frame with CRCs. + * + * This is required as the length parameter in the DNP3 header does not + * include the added CRCs. + * + * \param length The length from the DNP3 link header. + * + * \retval The length of the frame with CRCs included or 0 if the length isn't + * long enough to be a valid DNP3 frame. + */ +static uint32_t DNP3CalculateLinkLength(uint8_t length) +{ + uint32_t frame_len = 0; + int rem; + + /* Fail early if the length is less than the minimum size. */ + if (length < DNP3_LINK_HDR_LEN) { + return 0; + } + + /* Subtract the 5 bytes of the header that are included in the + * length. */ + length -= DNP3_LINK_HDR_LEN; + + rem = length % DNP3_BLOCK_SIZE; + frame_len = (length / DNP3_BLOCK_SIZE) * (DNP3_BLOCK_SIZE + DNP3_CRC_LEN); + if (rem) { + frame_len += rem + DNP3_CRC_LEN; + } + + return frame_len + sizeof(DNP3LinkHeader); +} + +/** + * \brief Check if the link function code specifies user data. + * + * \param header Point to link header. + * + * \retval 1 if frame contains user data, otherwise 0. + */ +static int DNP3IsUserData(const DNP3LinkHeader *header) +{ + switch (DNP3_LINK_FC(header->control)) { + case DNP3_LINK_FC_CONFIRMED_USER_DATA: + case DNP3_LINK_FC_UNCONFIRMED_USER_DATA: + return 1; + default: + return 0; + } +} + +/** + * \brief Check if the frame has user data. + * + * Check if the DNP3 frame actually has user data by checking if data + * exists after the headers. + * + * \retval 1 if user data exists, otherwise 0. + */ +static int DNP3HasUserData(const DNP3LinkHeader *header) +{ + if (DNP3_LINK_DIR(header->control)) { + return header->len >= DNP3_LINK_HDR_LEN + sizeof(DNP3TransportHeader) + + sizeof(DNP3ApplicationHeader); + } + else { + return header->len >= DNP3_LINK_HDR_LEN + sizeof(DNP3TransportHeader) + + sizeof(DNP3ApplicationHeader) + sizeof(DNP3InternalInd); + } +} + +/** + * \brief Reset a DNP3Buffer. + */ +static void DNP3BufferReset(DNP3Buffer *buffer) +{ + buffer->offset = 0; + buffer->len = 0; +} + +/** + * \brief Add data to a DNP3 buffer, enlarging the buffer if required. + * + * \param buffer Buffer to add data data. + * \param data Data to be added to buffer. + * \param len Size of data to be added to buffer. + * + * \param 1 if data was added successful, otherwise 0. + */ +static int DNP3BufferAdd(DNP3Buffer *buffer, const uint8_t *data, uint32_t len) +{ + if (buffer->size == 0) { + buffer->buffer = SCCalloc(1, len); + if (unlikely(buffer->buffer == NULL)) { + return 0; + } + buffer->size = len; + } + else if (buffer->len + len > buffer->size) { + uint8_t *tmp = SCRealloc(buffer->buffer, buffer->len + len); + if (unlikely(tmp == NULL)) { + return 0; + } + buffer->buffer = tmp; + buffer->size = buffer->len + len; + } + memcpy(buffer->buffer + buffer->len, data, len); + buffer->len += len; + + return 1; +} + +/** + * \brief Trim a DNP3 buffer. + * + * Trimming a buffer moves the data in the buffer up to the front of + * the buffer freeing up room at the end for more incoming data. + * + * \param buffer The buffer to trim. + */ +static void DNP3BufferTrim(DNP3Buffer *buffer) +{ + if (buffer->offset == buffer->len) { + DNP3BufferReset(buffer); + } + else if (buffer->offset > 0) { + memmove(buffer->buffer, buffer->buffer + buffer->offset, + buffer->len - buffer->offset); + buffer->len = buffer->len - buffer->offset; + buffer->offset = 0; + } +} + +/** + * \brief Free a DNP3 object. + */ +static void DNP3ObjectFree(DNP3Object *object) +{ + if (object->points != NULL) { + DNP3FreeObjectPointList(object->group, object->variation, + object->points); + } + SCFree(object); +} + +/** + * \breif Allocate a DNP3 object. + */ +static DNP3Object *DNP3ObjectAlloc(void) +{ + DNP3Object *object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + return NULL; + } + object->points = DNP3PointListAlloc(); + if (object->points == NULL) { + DNP3ObjectFree(object); + return NULL; + } + return object; +} + +/** + * \brief Decode DNP3 application objects. + * + * This function decoded known DNP3 application objects. As the + * protocol isn't self describing, we can only decode the buffer while + * the application objects are known. As soon as an unknown + * group/variation is hit, we must stop processing. + * + * \param buf the input buffer + * \param len length of the input buffer + * \param objects pointer to list where decoded objects will be stored. + * + * \retval 1 if all objects decoded, 0 if all objects could not be decoded ( + * unknown group/variations) + */ +static int DNP3DecodeApplicationObjects(DNP3Transaction *tx, const uint8_t *buf, + uint32_t len, DNP3ObjectList *objects) +{ + int retval = 0; + + if (buf == NULL || len == 0) { + return 1; + } + + while (len) { + uint32_t offset = 0; + + if (len < sizeof(DNP3ObjHeader)) { + goto done; + } + DNP3ObjHeader *header = (DNP3ObjHeader *)buf; + offset += sizeof(DNP3ObjHeader); + + DNP3Object *object = DNP3ObjectAlloc(); + if (unlikely(object == NULL)) { + goto done; + } + TAILQ_INSERT_TAIL(objects, object, next); + + object->group = header->group; + object->variation = header->variation; + object->qualifier = header->qualifier; + object->prefix_code = DNP3_OBJ_PREFIX(header->qualifier); + object->range_code = DNP3_OBJ_RANGE(header->qualifier); + + /* IEEE 1815-2012, Table 4-5. */ + switch (object->range_code) { + case 0x00: + case 0x03: { + /* 1 octet start and stop indexes OR 1 octet start and + * stop virtual addresses. */ + if (offset + (sizeof(uint8_t) * 2) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->start = buf[offset++]; + object->stop = buf[offset++]; + object->count = object->stop - object->start + 1; + break; + } + case 0x01: + case 0x04: { + /* 2 octet start and stop indexes OR 2 octect start + * and stop virtual addresses. */ + if (offset + (sizeof(uint16_t) * 2) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->start = DNP3_SWAP16(*(uint16_t *)(buf + offset)); + offset += sizeof(uint16_t); + object->stop = DNP3_SWAP16(*(uint16_t *)(buf + offset)); + offset += sizeof(uint16_t); + object->count = object->stop - object->start + 1; + break; + } + case 0x02: + case 0x05: { + /* 4 octet start and stop indexes OR 4 octect start + * and stop virtual addresses. */ + if (offset + (sizeof(uint32_t) * 2) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->start = DNP3_SWAP32(*(uint32_t *)(buf + offset)); + offset += sizeof(uint32_t); + object->stop = DNP3_SWAP32(*(uint32_t *)(buf + offset)); + offset += sizeof(uint32_t); + object->count = object->stop - object->start + 1; + break; + } + case 0x06: + /* No range field. */ + object->count = 0; + break; + case 0x07: + /* 1 octet count of objects. */ + if (offset + sizeof(uint8_t) > len) { + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = buf[offset]; + offset += sizeof(uint8_t); + break; + case 0x08: { + /* 2 octet count of objects. */ + if (offset + sizeof(uint16_t) > len) { + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = DNP3_SWAP16(*(uint16_t *)(buf + offset)); + offset += sizeof(uint16_t); + break; + } + case 0x09: { + /* 4 octet count of objects. */ + if (offset + sizeof(uint32_t) > len) { + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = DNP3_SWAP32(*(uint32_t *)(buf + offset)); + offset += sizeof(uint32_t); + break; + } + case 0x0b: { + if (offset + sizeof(uint8_t) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = *(uint8_t *)(buf + offset); + offset += sizeof(uint8_t); + break; + } + default: + SCLogDebug("Range code 0x%02x is reserved.", + object->range_code); + goto done; + } + + buf += offset; + len -= offset; + + if (object->variation == 0 || object->count == 0) { + goto next; + } + + int event = DNP3DecodeObject(header->group, header->variation, &buf, + &len, object->prefix_code, object->start, object->count, + object->points); + if (event) { + DNP3SetEventTx(tx, DNP3_DECODER_EVENT_UNKNOWN_OBJECT); + goto done; + } + + next: + continue; + } + + /* All objects were decoded. */ + retval = 1; + +not_enough_data: +done: + return retval; +} + +/** + * \brief Handle DNP3 request user data. + * + * \param dnp3 the current DNP3State + * \param input pointer to the DNP3 frame (starting with link header) + * \param input_len length of the input frame + */ +static void DNP3HandleUserDataRequest(DNP3State *dnp3, const uint8_t *input, + uint32_t input_len) +{ + DNP3LinkHeader *lh; + DNP3TransportHeader th; + DNP3ApplicationHeader *ah; + DNP3Transaction *tx = NULL, *ttx; + + lh = (DNP3LinkHeader *)input; + + if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), + input_len - sizeof(DNP3LinkHeader))) { + return; + } + + th = input[sizeof(DNP3LinkHeader)]; + + if (!DNP3_TH_FIR(th)) { + TAILQ_FOREACH(ttx, &dnp3->tx_list, next) { + if (ttx->request_lh.src == lh->src && + ttx->request_lh.dst == lh->dst && + ttx->has_request && + !ttx->request_done && + NEXT_TH_SEQNO(DNP3_TH_SEQ(ttx->request_th)) == DNP3_TH_SEQ(th)) + { + tx = ttx; + break; + } + } + + if (tx == NULL) { + return; + } + + /* Update the saved transport header so subsequent segments + * will be matched to this sequence number. */ + tx->response_th = th; + } + else { + ah = (DNP3ApplicationHeader *)(input + sizeof(DNP3LinkHeader) + + sizeof(DNP3TransportHeader)); + + /* Ignore confirms - for now. */ + if (ah->function_code == DNP3_APP_FC_CONFIRM) { + return; + } + + /* Create a transaction. */ + tx = DNP3TxAlloc(dnp3); + if (unlikely(tx == NULL)) { + return; + } + tx->request_lh = *lh; + tx->request_th = th; + tx->request_ah = *ah; + tx->has_request = 1; + + } + + if (!DNP3ReassembleApplicationLayer(input + sizeof(DNP3LinkHeader), + input_len - sizeof(DNP3LinkHeader), + &tx->request_buffer, &tx->request_buffer_len)) { + + /* Malformed, set event and mark as done. */ + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_MALFORMED); + tx->request_done = 1; + return; + } + + /* If this is not the final segment, just return. */ + if (!DNP3_TH_FIN(th)) { + return; + } + + tx->request_done = 1; + + /* Some function codes do not expect a reply. */ + switch (tx->request_ah.function_code) { + case DNP3_APP_FC_CONFIRM: + case DNP3_APP_FC_DIR_OPERATE_NR: + case DNP3_APP_FC_FREEZE_NR: + case DNP3_APP_FC_FREEZE_CLEAR_NR: + case DNP3_APP_FC_FREEZE_AT_TIME_NR: + case DNP3_APP_FC_AUTH_REQ_NR: + tx->response_done = 1; + default: + break; + } + + if (DNP3DecodeApplicationObjects( + tx, tx->request_buffer + sizeof(DNP3ApplicationHeader), + tx->request_buffer_len - sizeof(DNP3ApplicationHeader), + &tx->request_objects)) { + tx->request_complete = 1; + } +} + +static void DNP3HandleUserDataResponse(DNP3State *dnp3, const uint8_t *input, + uint32_t input_len) +{ + DNP3LinkHeader *lh; + DNP3TransportHeader th; + DNP3ApplicationHeader *ah; + DNP3InternalInd *iin; + DNP3Transaction *tx = NULL, *ttx; + uint32_t offset = 0; + + lh = (DNP3LinkHeader *)input; + offset += sizeof(DNP3LinkHeader); + + if (!DNP3CheckUserDataCRCs(input + offset, input_len - offset)) { + return; + } + + th = input[offset++]; + + if (!DNP3_TH_FIR(th)) { + TAILQ_FOREACH(ttx, &dnp3->tx_list, next) { + if (ttx->response_lh.src == lh->src && + ttx->response_lh.dst == lh->dst && + ttx->has_response && !ttx->response_done && + NEXT_TH_SEQNO(DNP3_TH_SEQ(ttx->response_th)) == DNP3_TH_SEQ(th)) + { + tx = ttx; + break; + } + } + + if (tx == NULL) { + return; + } + + /* Replace the transport header in the transaction with this + * one in case there are more frames. */ + tx->response_th = th; + } + else { + ah = (DNP3ApplicationHeader *)(input + offset); + offset += sizeof(DNP3ApplicationHeader); + iin = (DNP3InternalInd *)(input + offset); + + if (ah->function_code == DNP3_APP_FC_UNSOLICITED_RESP) { + tx = DNP3TxAlloc(dnp3); + if (unlikely(tx == NULL)) { + return; + } + + /* There is no request associated with an unsolicited + * response, so mark the request done as far as + * transaction state handling is concerned. */ + tx->request_done = 1; + } + else { + /* Find transaction. */ + TAILQ_FOREACH(ttx, &dnp3->tx_list, next) { + if (ttx->has_request && + ttx->request_done && + ttx->request_lh.src == lh->dst && + ttx->request_lh.dst == lh->src && + !ttx->has_response && + !ttx->response_done && + DNP3_APP_SEQ(ttx->request_ah.control) == DNP3_APP_SEQ(ah->control)) { + tx = ttx; + break; + } + } + if (tx == NULL) { + return; + } + } + + tx->has_response = 1; + tx->response_lh = *lh; + tx->response_th = th; + tx->response_ah = *ah; + tx->response_iin = *iin; + } + + if (!DNP3ReassembleApplicationLayer(input + sizeof(DNP3LinkHeader), + input_len - sizeof(DNP3LinkHeader), + &tx->response_buffer, &tx->response_buffer_len)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_MALFORMED); + return; + } + + if (!DNP3_TH_FIN(th)) { + return; + } + + tx->response_done = 1; + + offset = sizeof(DNP3ApplicationHeader) + sizeof(DNP3InternalInd); + if (DNP3DecodeApplicationObjects(tx, tx->response_buffer + offset, + tx->response_buffer_len - offset, + &tx->response_objects)) { + tx->response_complete = 1; + } +} + +/** + * \brief Decode the DNP3 request link layer. + * + * \retval number of bytes processed or -1 if the data stream does not look + * like DNP3. + */ +static int DNP3HandleRequestLinkLayer(DNP3State *dnp3, const uint8_t *input, + uint32_t input_len) +{ + SCEnter(); + uint32_t processed = 0; + + while (input_len) { + + /* Need at least enough bytes for a DNP3 header. */ + if (input_len < sizeof(DNP3LinkHeader)) { + break; + } + + DNP3LinkHeader *header = (DNP3LinkHeader *)input; + + if (!DNP3CheckStartBytes(header)) { + goto error; + } + + if (!DNP3CheckLinkHeaderCRC(header)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_LINK_CRC); + goto error; + } + + uint32_t frame_len = DNP3CalculateLinkLength(header->len); + if (frame_len == 0) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto error; + } + if (input_len < frame_len) { + /* Insufficient data, just break - will wait for more data. */ + break; + } + + /* Ignore non-user data for now. */ + if (!DNP3IsUserData(header)) { + goto next; + } + + /* Make sure the header length is large enough for transport and + * application headers. */ + if (!DNP3HasUserData(header)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto next; + } + + if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), + frame_len - sizeof(DNP3LinkHeader))) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC); + goto next; + } + + DNP3HandleUserDataRequest(dnp3, input, frame_len); + + next: + /* Advance the input buffer. */ + input += frame_len; + input_len -= frame_len; + processed += frame_len; + } + + SCReturnInt(processed); +error: + /* Error out. Should only happen if this doesn't look like a DNP3 + * frame. */ + SCReturnInt(-1); +} + +/** + * \brief Handle incoming request data. + * + * The actual request PDU parsing is done in + * DNP3HandleRequestLinkLayer. This function takes care of buffering TCP + * date if a segment does not contain a complete frame (or contains + * multiple frames, but not the complete final frame). + */ +static int DNP3ParseRequest(Flow *f, void *state, AppLayerParserState *pstate, + uint8_t *input, uint32_t input_len, void *local_data) +{ + SCEnter(); + DNP3State *dnp3 = (DNP3State *)state; + DNP3Buffer *buffer = &dnp3->request_buffer; + int processed = 0; + + if (input_len == 0) { + SCReturnInt(1); + } + + if (buffer->len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory to buffer " + "DNP3 request data"); + goto error; + } + processed = DNP3HandleRequestLinkLayer(dnp3, + buffer->buffer + buffer->offset, + buffer->len - buffer->offset); + if (processed < 0) { + goto error; + } + buffer->offset += processed; + DNP3BufferTrim(buffer); + } + else { + processed = DNP3HandleRequestLinkLayer(dnp3, input, input_len); + if (processed < 0) { + SCLogDebug("Failed to process request link layer."); + goto error; + } + + input += processed; + input_len -= processed; + + /* Not all data was processed, buffer it. */ + if (input_len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + SCLogError(SC_ERR_MEM_ALLOC, + "Failed to allocate memory to buffer DNP3 request data"); + goto error; + } + } + } + + SCReturnInt(1); + +error: + /* Reset the buffer. */ + DNP3BufferReset(buffer); + SCReturnInt(-1); +} + +/** + * \brief Decode the DNP3 response link layer. + * + * \retval number of bytes processed or -1 if the data stream does not + * like look DNP3. + */ +static int DNP3HandleResponseLinkLayer(DNP3State *dnp3, const uint8_t *input, + uint32_t input_len) +{ + SCEnter(); + uint32_t processed = 0; + + while (input_len) { + + /* Need at least enough bytes for a DNP3 header. */ + if (input_len < sizeof(DNP3LinkHeader)) { + break; + } + + DNP3LinkHeader *header = (DNP3LinkHeader *)input; + + if (!DNP3CheckStartBytes(header)) { + goto error; + } + + if (!DNP3CheckLinkHeaderCRC(header)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_LINK_CRC); + goto error; + } + + /* Calculate the number of bytes needed to for this frame. */ + uint32_t frame_len = DNP3CalculateLinkLength(header->len); + if (frame_len == 0) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto error; + } + if (input_len < frame_len) { + /* Insufficient data, just break - will wait for more data. */ + break; + } + + /* Only handle user data frames for now. */ + if (!DNP3IsUserData(header)) { + goto next; + } + + /* Make sure the header length is large enough for transport and + * application headers. */ + if (!DNP3HasUserData(header)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto error; + } + + if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), + frame_len - sizeof(DNP3LinkHeader))) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC); + goto next; + } + + DNP3HandleUserDataResponse(dnp3, input, frame_len); + + next: + /* Advance the input buffer. */ + input += frame_len; + input_len -= frame_len; + processed += frame_len; + } + + SCReturnInt(processed); +error: + /* Error out. Should only happen if the data stream no longer + * looks like DNP3. */ + SCReturnInt(-1); +} + +/** + * \brief Parse incoming data. + * + * This is the entry function for DNP3 application layer data. Its + * main responsibility is buffering incoming data that cannot be + * processed. + * + * See DNP3ParseResponsePDUs for DNP3 frame handling. + */ +static int DNP3ParseResponse(Flow *f, void *state, AppLayerParserState *pstate, + uint8_t *input, uint32_t input_len, void *local_data) +{ + SCEnter(); + DNP3State *dnp3 = (DNP3State *)state; + DNP3Buffer *buffer = &dnp3->response_buffer; + int processed; + + if (buffer->len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory to buffer " + "DNP3 response data"); + goto error; + } + processed = DNP3HandleResponseLinkLayer(dnp3, + buffer->buffer + buffer->offset, + buffer->len - buffer->offset); + if (processed < 0) { + goto error; + } + buffer->offset += processed; + DNP3BufferTrim(buffer); + } + else { + + /* Check if this is a banner, ignore if it is. */ + if (DNP3ContainsBanner(input, input_len)) { + goto done; + } + + processed = DNP3HandleResponseLinkLayer(dnp3, input, input_len); + if (processed < 0) { + goto error; + } + input += processed; + input_len -= processed; + + /* Not all data was processed, buffer it. */ + if (input_len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + SCLogError(SC_ERR_MEM_ALLOC, + "Failed to allocate memory to buffer DNP3 response data"); + goto error; + } + } + } + +done: + SCReturnInt(1); + +error: + /* An error occurred while processing DNP3 frames. Dump the + * buffer as we can't be assured that they are valid anymore. */ + DNP3BufferReset(buffer); + SCReturnInt(-1); +} + +static AppLayerDecoderEvents *DNP3GetEvents(void *state, uint64_t tx_id) +{ + DNP3State *dnp3 = state; + DNP3Transaction *tx; + uint64_t tx_num = tx_id + 1; + + if (dnp3->curr && dnp3->curr->tx_num == tx_num) { + return dnp3->curr->decoder_events; + } + + TAILQ_FOREACH(tx, &dnp3->tx_list, next) { + if (tx->tx_num == tx_num) { + return tx->decoder_events; + } + } + + return NULL; +} + +static int DNP3HasEvents(void *state) +{ + SCEnter(); + uint16_t events = (((DNP3State *)state)->events); + SCReturnInt((events > 0)); +} + +static void *DNP3GetTx(void *alstate, uint64_t tx_id) +{ + SCEnter(); + DNP3State *dnp3 = (DNP3State *)alstate; + DNP3Transaction *tx = NULL; + uint64_t tx_num = tx_id + 1; + + if (dnp3->curr && dnp3->curr->tx_num == (tx_num)) { + SCReturnPtr(dnp3->curr, "void"); + } + + TAILQ_FOREACH(tx, &dnp3->tx_list, next) { + if (tx_num != tx->tx_num) { + continue; + } + SCReturnPtr(tx, "void"); + } + + SCReturnPtr(NULL, "void"); +} + +static uint64_t DNP3GetTxCnt(void *state) +{ + SCEnter(); + uint64_t count = ((uint64_t)((DNP3State *)state)->transaction_max); + SCReturnUInt(count); +} + +/** + * \brief Free all the objects in a DNP3ObjectList. + */ +static void DNP3TxFreeObjectList(DNP3ObjectList *objects) +{ + DNP3Object *object; + + while ((object = TAILQ_FIRST(objects)) != NULL) { + TAILQ_REMOVE(objects, object, next); + DNP3ObjectFree(object); + } +} + +/** + * \brief Free a DNP3 transaction. + */ +static void DNP3TxFree(DNP3Transaction *tx) +{ + SCEnter(); + + if (tx->request_buffer != NULL) { + SCFree(tx->request_buffer); + } + + if (tx->response_buffer != NULL) { + SCFree(tx->response_buffer); + } + + AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + + if (tx->de_state != NULL) { + DetectEngineStateFree(tx->de_state); + } + + DNP3TxFreeObjectList(&tx->request_objects); + DNP3TxFreeObjectList(&tx->response_objects); + + SCFree(tx); + SCReturn; +} + +/** + * \brief Free a transaction by ID on a specific DNP3 state. + * + * This function is called by the app-layer to free a transaction on a + * specific DNP3 state object. + */ +static void DNP3StateTxFree(void *state, uint64_t tx_id) +{ + SCEnter(); + DNP3State *dnp3 = state; + DNP3Transaction *tx = NULL, *ttx; + uint64_t tx_num = tx_id + 1; + + TAILQ_FOREACH_SAFE(tx, &dnp3->tx_list, next, ttx) { + + if (tx->tx_num != tx_num) { + continue; + } + + if (tx == dnp3->curr) { + dnp3->curr = NULL; + } + + if (tx->decoder_events != NULL) { + if (tx->decoder_events->cnt <= dnp3->events) { + dnp3->events -= tx->decoder_events->cnt; + } + else { + dnp3->events = 0; + } + } + dnp3->unreplied--; + + /* Check flood state. */ + if (dnp3->flooded && dnp3->unreplied < DNP3_DEFAULT_REQ_FLOOD_COUNT) { + dnp3->flooded = 0; + } + + TAILQ_REMOVE(&dnp3->tx_list, tx, next); + DNP3TxFree(tx); + break; + } + + SCReturn; +} + +/** + * \brief Free a DNP3 state. + */ +static void DNP3StateFree(void *state) +{ + SCEnter(); + DNP3State *dnp3 = state; + DNP3Transaction *tx; + if (state != NULL) { + while ((tx = TAILQ_FIRST(&dnp3->tx_list)) != NULL) { + TAILQ_REMOVE(&dnp3->tx_list, tx, next); + DNP3TxFree(tx); + } + if (dnp3->request_buffer.buffer != NULL) { + SCFree(dnp3->request_buffer.buffer); + } + if (dnp3->response_buffer.buffer != NULL) { + SCFree(dnp3->response_buffer.buffer); + } + SCFree(dnp3); + } + SCReturn; +} + +/** + * \brief Called by the app-layer to get the state progress. + */ +static int DNP3GetAlstateProgress(void *tx, uint8_t direction) +{ + DNP3Transaction *dnp3tx = (DNP3Transaction *)tx; + DNP3State *dnp3 = dnp3tx->dnp3; + int retval = 0; + + /* If flooded, "ack" old transactions. */ + if (dnp3->flooded && (dnp3->transaction_max - + dnp3tx->tx_num >= DNP3_DEFAULT_REQ_FLOOD_COUNT)) { + SCLogDebug("flooded: returning tx as done."); + SCReturnInt(1); + } + + if (direction & STREAM_TOCLIENT && dnp3tx->response_done) { + retval = 1; + } + else if (direction & STREAM_TOSERVER && dnp3tx->request_done) { + retval = 1; + } + + SCReturnInt(retval); +} + +/** + * \brief App-layer support. + */ +static int DNP3GetAlstateProgressCompletionStatus(uint8_t direction) +{ + return 1; +} + +/** + * \brief App-layer support. + */ +static int DNP3StateGetEventInfo(const char *event_name, int *event_id, + AppLayerEventType *event_type) +{ + *event_id = SCMapEnumNameToValue(event_name, dnp3_decoder_event_table); + if (*event_id == -1) { + SCLogError(SC_ERR_INVALID_ENUM_MAP, "Event \"%s\" not present in " + "the DNP3 enum event map table.", event_name); + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +/** + * \brief App-layer support. + */ +static DetectEngineState *DNP3GetTxDetectState(void *vtx) +{ + DNP3Transaction *tx = vtx; + return tx->de_state; +} + +/** + * \brief App-layer support. + */ +static int DNP3SetTxDetectState(void *state, void *vtx, DetectEngineState *s) +{ + DNP3Transaction *tx = vtx; + tx->de_state = s; + return 0; +} + +static void DNP3SetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + DNP3Transaction *tx = (DNP3Transaction *)vtx; + tx->logged |= logger; +} + +static int DNP3GetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + DNP3Transaction *tx = (DNP3Transaction *)vtx; + if (tx->logged & logger) { + return 1; + } + + return 0; +} + +/** + * \brief Check if the prefix code is a size prefix. + * + * \retval 1 if the prefix_code specifies a size prefix, 0 if not. + */ +int DNP3PrefixIsSize(uint8_t prefix_code) +{ + switch (prefix_code) { + case 0x04: + case 0x05: + case 0x06: + return 1; + break; + default: + return 0; + } +} + +/** + * \brief Register the DNP3 application protocol parser. + */ +void RegisterDNP3Parsers(void) +{ + SCEnter(); + + char *proto_name = "dnp3"; + + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + + AppLayerProtoDetectRegisterProtocol(ALPROTO_DNP3, proto_name); + + if (RunmodeIsUnittests()) { + AppLayerProtoDetectPPRegister(IPPROTO_TCP, DNP3_DEFAULT_PORT, + ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), STREAM_TOSERVER, + DNP3ProbingParser); + } + else { + if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, + proto_name, ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), + DNP3ProbingParser)) { + SCLogWarning(SC_ERR_DNP3_CONFIG, + "No DNP3 configuration found, enabling DNP3 detection on " + "port " DNP3_DEFAULT_PORT); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, DNP3_DEFAULT_PORT, + ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), STREAM_TOSERVER, + DNP3ProbingParser); + } + } + + } + else { + SCLogInfo("Protocol detection and parser disabled for DNP3."); + SCReturn; + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) { + + SCLogInfo("Registering DNP3/tcp parsers."); + + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_DNP3, STREAM_TOSERVER, + DNP3ParseRequest); + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_DNP3, STREAM_TOCLIENT, + DNP3ParseResponse); + + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_DNP3, + DNP3StateAlloc, DNP3StateFree); + + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_DNP3, + DNP3GetEvents); + AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_DNP3, + DNP3HasEvents); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DNP3, NULL, + DNP3GetTxDetectState, DNP3SetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTx); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTxCnt); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_DNP3, + DNP3StateTxFree); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_DNP3, + DNP3GetAlstateProgress); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNP3, + DNP3GetAlstateProgressCompletionStatus); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_DNP3, + DNP3StateGetEventInfo); + + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_DNP3, + DNP3GetTxLogged, DNP3SetTxLogged); + } + else { + SCLogInfo("Parser disabled for protocol %s. " + "Protocol detection still on.", proto_name); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_DNP3, + DNP3ParserRegisterTests); +#endif + + SCReturn; +} + +#ifdef UNITTESTS + +#include "flow-util.h" +#include "stream-tcp.h" + +/** + * \brief Utility function to fix CRCs when mangling a frame. + */ +static void DNP3FixCrc(uint8_t *data, uint32_t len) +{ + uint32_t block_size; + + while (len) { + if (len >= DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { + block_size = DNP3_BLOCK_SIZE; + } else { + block_size = len - DNP3_CRC_LEN; + } + uint16_t crc = DNP3ComputeCRC(data, block_size); + data[block_size + 1] = (crc >> 8) & 0xff; + data[block_size] = crc & 0xff; + data += block_size + DNP3_CRC_LEN; + len -= block_size + DNP3_CRC_LEN; + } +} + +/** + * \test Test CRC checking on partial and full blocks. + */ +static int DNP3ParserTestCheckCRC(void) +{ + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer - segment 1. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, + + /* Application layer - segment 2. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + + /* Check link header CRC. */ + FAIL_IF(!DNP3CheckCRC(request, sizeof(DNP3LinkHeader))); + + /* Check first application layer segment. */ + FAIL_IF(!DNP3CheckCRC(request + sizeof(DNP3LinkHeader), + DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); + + /* Change a byte in link header, should fail now. */ + request[2]++; + FAIL_IF(DNP3CheckCRC(request, sizeof(DNP3LinkHeader))); + + /* Change a byte in the first application segment, should fail + * now. */ + request[sizeof(DNP3LinkHeader) + 3]++; + FAIL_IF(DNP3CheckCRC(request + sizeof(DNP3LinkHeader), + DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); + + PASS; +} + +/** + * \test Test validation of all CRCs in user data. + */ +static int DNP3CheckUserDataCRCsTest(void) +{ + /* Multi-block data with valid CRCs. */ + uint8_t data_valid[] = { + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00, 0x00, 0x00, + 0x00, + 0xff, 0xff, /* CRC. */ + }; + FAIL_IF(!DNP3CheckUserDataCRCs(data_valid, sizeof(data_valid))); + + /* Multi-block data with one non-crc byte altered. */ + uint8_t data_invalid[] = { + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00, 0x00, 0x00, + 0x01, /* Invalid byte. */ + 0xff, 0xff, /* CRC. */ + }; + FAIL_IF(DNP3CheckUserDataCRCs(data_invalid, sizeof(data_invalid))); + + /* 1 byte - need at least 3. */ + uint8_t one_byte_nocrc[] = { 0x01 }; + FAIL_IF(DNP3CheckUserDataCRCs(one_byte_nocrc, sizeof(one_byte_nocrc))); + + /* 2 bytes - need at least 3. */ + uint8_t two_byte_nocrc[] = { 0x01, 0x02 }; + FAIL_IF(DNP3CheckUserDataCRCs(two_byte_nocrc, sizeof(two_byte_nocrc))); + + /* 3 bytes, valid CRC. */ + uint8_t three_bytes_good_crc[] = { 0x00, 0x00, 0x00 }; + *(uint16_t *)(three_bytes_good_crc + 1) = DNP3ComputeCRC( + three_bytes_good_crc, 1); + FAIL_IF(!DNP3CheckUserDataCRCs(three_bytes_good_crc, + sizeof(three_bytes_good_crc))); + + PASS; +} + +/** + * \test Test the link layer length calculation. + * + * Test the calculation that converts the link provided in the DNP3 + * header to the actual length of the frame. That is the length with + * CRCs as the length in the header does not include CRCs. + */ +static int DNP3CalculateLinkLengthTest(void) +{ + /* These are invalid. */ + FAIL_IF(DNP3CalculateLinkLength(0) != 0); + FAIL_IF(DNP3CalculateLinkLength(1) != 0); + FAIL_IF(DNP3CalculateLinkLength(2) != 0); + FAIL_IF(DNP3CalculateLinkLength(3) != 0); + FAIL_IF(DNP3CalculateLinkLength(4) != 0); + + /* This is the minimum size. */ + FAIL_IF(DNP3CalculateLinkLength(5) != 10); + + /* 1 full user data blocks of data. */ + FAIL_IF(DNP3CalculateLinkLength(21) != 28); + + /* 2 full user data blocks of data. */ + FAIL_IF(DNP3CalculateLinkLength(37) != 46); + + /* 2 full user data blocks, plus one more byte. */ + /* 2 full user data blocks of data. */ + FAIL_IF(DNP3CalculateLinkLength(38) != 49); + + /* The maximum size. */ + FAIL_IF(DNP3CalculateLinkLength(255) != 292); + + PASS; +} + +/** + * \test The conversion of length with CRCs to the length without + * CRCs. + */ +static int DNP3CalculateTransportLengthWithoutCRCsTest(void) +{ + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(0) != -1); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(1) != -1); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(2) != 0); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(3) != 1); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(16) != 14); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(17) != 15); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(18) != 16); + + /* 19 bytes is not enough for a second block. */ + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(19) != -1); + + /* 20 bytes really isn't enough either, but is large enough to + * satisfy the CRC on the second block. */ + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(20) != 16); + + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(21) != 17); + + PASS; +} + +/** + * \test Test the validation of the link header CRC. + */ +static int DNP3ParserCheckLinkHeaderCRC(void) +{ + /* DNP3 frame with valid headers and CRCs. */ + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + + DNP3LinkHeader *header = (DNP3LinkHeader *)request; + FAIL_IF(!DNP3CheckLinkHeaderCRC(header)); + + /* Alter a byte in the header. */ + request[4] = 0; + FAIL_IF(DNP3CheckLinkHeaderCRC(header)); + + PASS; +} + +/** + * \test Test removal of CRCs from user data. + */ +static int DNP3ReassembleApplicationLayerTest01(void) +{ + uint32_t reassembled_len = 0; + uint8_t *output = NULL; + + uint8_t payload[] = { + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00, 0x00, 0x00, + 0x00, + 0xff, 0xff, /* CRC. */ + }; + + uint8_t expected[] = { + 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + /* CRC removed. */ + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + /* CRC removed. */ + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + /* CRC removed. */ + 0x00, 0x00, 0x00, 0x00, + 0x00 + /* CRC removed. */ + }; + + /* Valid frame. */ + FAIL_IF(!DNP3ReassembleApplicationLayer(payload, + sizeof(payload), &output, &reassembled_len)); + FAIL_IF(output == NULL); + FAIL_IF(reassembled_len != sizeof(expected)); + FAIL_IF(memcmp(expected, output, reassembled_len)); + SCFree(output); + + /* 1 byte, invalid. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(DNP3ReassembleApplicationLayer(payload, 1, &output, + &reassembled_len)); + FAIL_IF(output != NULL); + FAIL_IF(reassembled_len != 0); + + /* 2 bytes, invalid. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(DNP3ReassembleApplicationLayer(payload, 2, &output, + &reassembled_len)); + FAIL_IF(output != NULL); + FAIL_IF(reassembled_len != 0); + + /* 3 bytes, minimum - but that would only be the transport header + * which isn't included in the output. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(DNP3ReassembleApplicationLayer(payload, 3, &output, + &reassembled_len)); + FAIL_IF(output != NULL); + FAIL_IF(reassembled_len != 0); + + /* 4 bytes is the minimum to get any reassembled data. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(!DNP3ReassembleApplicationLayer(payload, 4, &output, + &reassembled_len)); + FAIL_IF(output == NULL); + FAIL_IF(reassembled_len != 1); + + /* Last block too short (by 1 byte) for data + CRC. */ + uint8_t short_payload1[] = { + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00 + }; + reassembled_len = 0; + FAIL_IF(DNP3ReassembleApplicationLayer(short_payload1, + sizeof(short_payload1), &output, &reassembled_len)); + + /* Last block too short (by 2 bytes) for data + CRC. */ + uint8_t short_payload2[] = { + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, + }; + reassembled_len = 0; + FAIL_IF(DNP3ReassembleApplicationLayer(short_payload2, + sizeof(short_payload2), &output, &reassembled_len)); + + PASS; +} + +/** + * \test Test the probing parser. + */ +static int DNP3ProbingParserTest(void) +{ + uint8_t pkt[] = { + 0x05, 0x64, 0x05, 0xc9, 0x03, 0x00, 0x04, 0x00, + 0xbd, 0x71 + }; + + /* Valid frame. */ + FAIL_IF(DNP3ProbingParser(pkt, sizeof(pkt), NULL) != ALPROTO_DNP3); + + /* Send too little bytes. */ + FAIL_IF(DNP3ProbingParser(pkt, sizeof(DNP3LinkHeader) - 1, NULL) != ALPROTO_UNKNOWN); + + /* Bad start bytes. */ + pkt[0] = 0x06; + FAIL_IF(DNP3ProbingParser(pkt, sizeof(pkt), NULL) != ALPROTO_FAILED); + + /* Restore start byte. */ + pkt[0] = 0x05; + + /* Set the length to a value less than the minimum length of 5. */ + pkt[2] = 0x03; + FAIL_IF(DNP3ProbingParser(pkt, sizeof(pkt), NULL) != ALPROTO_FAILED); + + /* Send a banner. */ + char banner[] = "Welcome to DNP3 SCADA."; + FAIL_IF(DNP3ProbingParser((uint8_t *)banner, sizeof(banner), NULL) != ALPROTO_DNP3); + + PASS; +} + +/** + * \test Test a basic request/response. + */ +int DNP3ParserTestRequestResponse(void) +{ + DNP3State *state = NULL; + + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + + uint8_t response[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00, + 0xe2, 0x59, + + /* Transport header. */ + 0xc3, + + /* Application layer. */ + 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff + }; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(DNP3HasEvents(state)); + + DNP3Transaction *tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->request_buffer == NULL); + FAIL_IF(tx->request_buffer_len != 20); + FAIL_IF(tx->request_ah.function_code != DNP3_APP_FC_DIR_OPERATE); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOCLIENT, response, sizeof(response))); + SCMutexUnlock(&flow.m); + FAIL_IF(DNP3GetTx(state, 0) != tx); + FAIL_IF(!tx->response_done); + FAIL_IF(tx->response_buffer == NULL); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&flow); + DNP3StateFree(state); + PASS; +} + +/** + * \test Test an unsolicited response from an outstation. + * + * This is kind of like a request initiated from the "server". + */ +static int DNP3ParserTestUnsolicitedResponseConfirm(void) +{ + DNP3State *state = NULL; + + /* Unsolicited response with confirm bit set. */ + uint8_t response[] = { + 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, + 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02, + 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8, + 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9 + }; + + /* Confirm. */ + uint8_t confirm[] = { + 0x05, 0x64, 0x08, 0xc4, 0x02, 0x00, + 0x01, 0x00, 0xd3, 0xb7, 0xc0, 0xda, 0x00, 0x6a, + 0x3d + }; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOCLIENT, response, sizeof(response))); + SCMutexUnlock(&flow.m); + + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(DNP3HasEvents(state)); + + DNP3Transaction *tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->request_buffer != NULL); + FAIL_IF(tx->response_buffer == NULL); + FAIL_IF(!tx->response_done); + FAIL_IF(tx->response_ah.function_code != DNP3_APP_FC_UNSOLICITED_RESP); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, confirm, sizeof(confirm))); + SCMutexUnlock(&flow.m); + FAIL_IF(DNP3GetTx(state, 0) != tx); + FAIL_IF(!tx->response_done); + FAIL_IF(tx->response_buffer == NULL); + /* FAIL_IF(tx->iin1 != 0 || tx->iin2 != 0); */ + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&flow); + DNP3StateFree(state); + PASS; +} + +/** + * \test Test flood state. + */ +int DNP3ParserTestFlooded(void) +{ + DNP3State *state = NULL; + + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(DNP3HasEvents(state)); + + DNP3Transaction *tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->request_buffer == NULL); + FAIL_IF(tx->request_buffer_len != 20); + /* FAIL_IF(tx->app_function_code != DNP3_APP_FC_DIR_OPERATE); */ + FAIL_IF(tx->response_done); + + for (int i = 0; i < DNP3_DEFAULT_REQ_FLOOD_COUNT - 1; i++) { + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + } + FAIL_IF(state->flooded); + FAIL_IF(DNP3GetAlstateProgress(tx, 0)); + + /* One more request should trip us into flooded state. */ + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + FAIL_IF(!state->flooded); + + /* Progress for the oldest tx should return 1. */ + FAIL_IF(!DNP3GetAlstateProgress(tx, 0)); + + /* But progress for the current state should still return 0. */ + FAIL_IF(DNP3GetAlstateProgress(state->curr, 0)); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&flow); + DNP3StateFree(state); + PASS; +} + +/** + * \test Test parsing of partial frames. + * + * As DNP3 operates over TCP, it is possible that a partial DNP3 frame + * is received. Test that the partial frame will be buffered until the + * remainder is seen. + */ +static int DNP3ParserTestPartialFrame(void) +{ + DNP3State *state = NULL; + DNP3Transaction *tx; + int r; + + uint8_t request_partial1[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + }; + + uint8_t request_partial2[] = { + /* Remainder of application layer. */ + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + + uint8_t response_partial1[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00, + 0xe2, 0x59, + + /* Transport header. */ + 0xc3, + + /* Application layer. */ + 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01, + }; + + uint8_t response_partial2[] = { + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff + }; + + /* Boiler plate for app layer setup. */ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + StreamTcpInitConfig(TRUE); + + /* Pass in the first partial frame. */ + + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request_partial1, sizeof(request_partial1)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + /* Frame should just be buffered, but not yet processed. */ + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(state->request_buffer.len != sizeof(request_partial1)); + FAIL_IF(state->request_buffer.offset != 0); + FAIL_IF(memcmp(state->request_buffer.buffer, request_partial1, + sizeof(request_partial1))); + + /* There should not be a transaction yet. */ + FAIL_IF(state->transaction_max != 0); + FAIL_IF(DNP3GetTx(state, 0) != NULL); + + /* Send the second partial. */ + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request_partial2, sizeof(request_partial2)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + /* The second partial completed the frame, the buffer should now + * be clear. */ + FAIL_IF(state->request_buffer.len != 0); + FAIL_IF(state->request_buffer.offset != 0); + + /* Should now have a complete transaction. */ + tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->request_buffer == NULL); + FAIL_IF(tx->request_buffer_len != 20); + FAIL_IF(tx->request_ah.function_code != DNP3_APP_FC_DIR_OPERATE); + + /* Send partial response. */ + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOCLIENT, response_partial1, sizeof(response_partial1)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + FAIL_IF(state->response_buffer.len != sizeof(response_partial1)); + FAIL_IF(state->response_buffer.offset != 0); + FAIL_IF(tx->response_done); + + /* Send rest of response. */ + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOCLIENT, response_partial2, sizeof(response_partial2)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + /* Buffer should now be empty. */ + FAIL_IF(state->response_buffer.len != 0); + FAIL_IF(state->response_buffer.offset != 0); + + /* Transaction should be replied to now. */ + FAIL_IF(!tx->response_done); + FAIL_IF(tx->response_buffer == NULL); + FAIL_IF(tx->response_buffer_len == 0); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&flow); + DNP3StateFree(state); + PASS; +} + +/** + * \test Test multiple DNP3 frames in one TCP read. + */ +static int DNP3ParserTestMultiFrame(void) +{ + DNP3State *state = NULL; + + /* Unsolicited response 1. */ + uint8_t unsol_response1[] = { + 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, + 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02, + 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8, + 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9, + }; + + /* Unsolicited response 2. */ + uint8_t unsol_response2[] = { + 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, + 0x89, 0xe5, 0xc5, 0xfb, 0x82, 0x00, 0x00, 0x02, + 0x02, 0x17, 0x01, 0x0c, 0x01, 0xd8, 0x75, 0xd8, + 0x32, 0x4c, 0xc9, 0x3c, 0x01, 0xa1, 0xc9, + }; + + uint8_t combined[sizeof(unsol_response1) + sizeof(unsol_response2)]; + memcpy(combined, unsol_response1, sizeof(unsol_response1)); + memcpy(combined + sizeof(unsol_response1), unsol_response2, + sizeof(unsol_response2)); + + /* Setup. */ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + int r; + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + StreamTcpInitConfig(TRUE); + + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOCLIENT, combined, sizeof(combined)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(state->transaction_max != 2); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&flow); + DNP3StateFree(state); + PASS; +} + +/** + * \test Test the parsing of a request PDU. + * + * The PDU under test contains a single read request object: + * - Group: 1 + * - Variation: 0 + * - Count: 0 + */ +static int DNP3ParserTestParsePDU01(void) +{ + /* Frame to be tested. This frame is a DNP3 request with one read + * request data object, group 1, variation 0. */ + const uint8_t pkt[] = { + 0x05, 0x64, + 0x0b, 0xc4, 0x17, 0x00, 0xef, 0xff, 0xc4, 0x8f, + 0xe1, 0xc8, 0x01, 0x01, 0x00, 0x06, 0x77, 0x6e + }; + + DNP3State *dnp3state = DNP3StateAlloc(); + int pdus = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); + FAIL_IF(pdus < 1); + DNP3Transaction *dnp3tx = DNP3GetTx(dnp3state, 0); + FAIL_IF_NULL(dnp3tx); + FAIL_IF(!dnp3tx->has_request); + FAIL_IF(TAILQ_EMPTY(&dnp3tx->request_objects)); + DNP3Object *object = TAILQ_FIRST(&dnp3tx->request_objects); + FAIL_IF(object->group != 1 || object->variation != 0); + FAIL_IF(object->count != 0); + + DNP3StateFree(dnp3state); + PASS; +} + +/** + * \test Test the decode of a DNP3 fragment with a single 70:3 object. + */ +static int DNP3ParserDecodeG70V3Test(void) +{ + const uint8_t pkt[] = { + 0x05, 0x64, + 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, 0xc7, 0xee, + 0xc7, 0xc9, 0x1b, 0x46, 0x03, 0x5b, 0x01, 0x55, + 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, + 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43, + 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44, + 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c, + 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, + 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d, + 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c, + 0xc4, 0x8b + }; + + DNP3State *dnp3state = DNP3StateAlloc(); + FAIL_IF_NULL(dnp3state); + int bytes = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); + FAIL_IF(bytes != sizeof(pkt)); + FAIL_IF(DNP3HasEvents(dnp3state)); + DNP3Transaction *tx = DNP3GetTx(dnp3state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NOT(tx->has_request); + DNP3Object *obj = TAILQ_FIRST(&tx->request_objects); + FAIL_IF_NULL(obj); + FAIL_IF_NOT(obj->group == 70); + FAIL_IF_NOT(obj->variation == 3); + FAIL_IF_NOT(obj->prefix_code == 0x5); + FAIL_IF_NOT(obj->range_code == 0xb); + FAIL_IF_NOT(obj->count == 1); + DNP3Point *point = TAILQ_FIRST(obj->points); + FAIL_IF_NULL(point); + FAIL_IF_NOT(point->prefix == 85); + FAIL_IF_NOT(point->size == 85); + FAIL_IF_NULL(point->data); + DNP3ObjectG70V3 *data = point->data; + FAIL_IF_NOT(strcmp( + data->filename, + "C:/temp/DNPDeviceConfiguration written to Remote Device.xml") == 0); + DNP3StateFree(dnp3state); + PASS; +} + +/** + * \brief Test that an alert is raised on an unknown object. + */ +static int DNP3ParserUnknownEventAlertTest(void) +{ + /* Valid DNP3 frame with 70:3 object. */ + uint8_t pkt[] = { + 0x05, 0x64, 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, + 0xc7, 0xee, + + 0xc7, 0xc9, 0x1b, + + /* Object and variation. Originally 70:3, now 70:99, an + * unknown object. */ + 0x46, 0x63, + + 0x5b, 0x01, 0x55, + 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, + 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43, + 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44, + 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c, + 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, + 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d, + 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c, + 0xc4, 0x8b + }; + + DNP3FixCrc(pkt + 10, sizeof(pkt) - 10); + + DNP3State *dnp3state = DNP3StateAlloc(); + FAIL_IF_NULL(dnp3state); + int bytes = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); + FAIL_IF(bytes != sizeof(pkt)); + + /* Should have an event now. */ + FAIL_IF_NOT(DNP3HasEvents(dnp3state)); + + DNP3StateFree(dnp3state); + PASS; +} + +#endif + +void DNP3ParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DNP3ParserTestCheckCRC", DNP3ParserTestCheckCRC); + UtRegisterTest("DNP3ParserCheckLinkHeaderCRC", + DNP3ParserCheckLinkHeaderCRC); + UtRegisterTest("DNP3CheckUserDataCRCsTest", DNP3CheckUserDataCRCsTest); + UtRegisterTest("DNP3CalculateLinkLengthTest", DNP3CalculateLinkLengthTest); + UtRegisterTest("DNP3CalculateTransportLengthWithoutCRCsTest", + DNP3CalculateTransportLengthWithoutCRCsTest); + UtRegisterTest("DNP3ReassembleApplicationLayerTest01", + DNP3ReassembleApplicationLayerTest01); + UtRegisterTest("DNP3ProbingParserTest", DNP3ProbingParserTest); + UtRegisterTest("DNP3ParserTestRequestResponse", + DNP3ParserTestRequestResponse); + UtRegisterTest("DNP3ParserTestUnsolicitedResponseConfirm", + DNP3ParserTestUnsolicitedResponseConfirm); + UtRegisterTest("DNP3ParserTestPartialFrame", DNP3ParserTestPartialFrame); + UtRegisterTest("DNP3ParserTestMultiFrame", DNP3ParserTestMultiFrame); + UtRegisterTest("DNP3ParserTestFlooded", DNP3ParserTestFlooded); + UtRegisterTest("DNP3ParserTestParsePDU01", DNP3ParserTestParsePDU01); + UtRegisterTest("DNP3ParserDecodeG70V3Test", DNP3ParserDecodeG70V3Test); + UtRegisterTest("DNP3ParserUnknownEventAlertTest", + DNP3ParserUnknownEventAlertTest); +#endif +} diff --git a/src/app-layer-dnp3.h b/src/app-layer-dnp3.h new file mode 100644 index 000000000000..13cebc7478eb --- /dev/null +++ b/src/app-layer-dnp3.h @@ -0,0 +1,277 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __APP_LAYER_DNP3_H__ +#define __APP_LAYER_DNP3_H__ + +#include "detect-engine-state.h" +#include "util-hashlist.h" +#include "util-byte.h" + +/** + * The maximum size of a DNP3 link PDU. + */ +#define DNP3_MAX_LINK_PDU_LEN 292 + +/* DNP3 application request function codes. */ +#define DNP3_APP_FC_CONFIRM 0x00 +#define DNP3_APP_FC_READ 0x01 +#define DNP3_APP_FC_WRITE 0x02 +#define DNP3_APP_FC_SELECT 0x03 +#define DNP3_APP_FC_OPERATE 0x04 +#define DNP3_APP_FC_DIR_OPERATE 0x05 +#define DNP3_APP_FC_DIR_OPERATE_NR 0x06 +#define DNP3_APP_FC_FREEZE 0x07 +#define DNP3_APP_FC_FREEZE_NR 0x08 +#define DNP3_APP_FC_FREEZE_CLEAR 0x09 +#define DNP3_APP_FC_FREEZE_CLEAR_NR 0x0a +#define DNP3_APP_FC_FREEZE_AT_TIME 0x0b +#define DNP3_APP_FC_FREEZE_AT_TIME_NR 0x0c +#define DNP3_APP_FC_COLD_RESTART 0x0d +#define DNP3_APP_FC_WARM_RESTART 0x0e +#define DNP3_APP_FC_INITIALIZE_DATA 0x0f +#define DNP3_APP_FC_INITIALIZE_APPLICATION 0x10 +#define DNP3_APP_FC_START_APPLICATION 0x11 +#define DNP3_APP_FC_STOP_APPLICATION 0x12 +#define DNP3_APP_FC_SAVE_CONFIGURATION 0x13 +#define DNP3_APP_FC_ENABLE_UNSOLICITED 0x14 +#define DNP3_APP_FC_DISABLE_UNSOLICTED 0x15 +#define DNP3_APP_FC_ASSIGN_CLASS 0x16 +#define DNP3_APP_FC_DELAY_MEASUREMENT 0x17 +#define DNP3_APP_FC_RECORD_CURRENT_TIME 0x18 +#define DNP3_APP_FC_OPEN_TIME 0x19 +#define DNP3_APP_FC_CLOSE_FILE 0x1a +#define DNP3_APP_FC_DELETE_FILE 0x1b +#define DNP3_APP_FC_GET_FILE_INFO 0x1c +#define DNP3_APP_FC_AUTHENTICATE_FILE 0x1d +#define DNP3_APP_FC_ABORT_FILE 0x1e +#define DNP3_APP_FC_ACTIVATE_CONFIG 0x1f +#define DNP3_APP_FC_AUTH_REQ 0x20 +#define DNP3_APP_FC_AUTH_REQ_NR 0x21 + +/* DNP3 application response function codes. */ +#define DNP3_APP_FC_RESPONSE 0x81 +#define DNP3_APP_FC_UNSOLICITED_RESP 0x82 +#define DNP3_APP_FC_AUTH_RESP 0x83 + +/* Extract fields from the link control octet. */ +#define DNP3_LINK_DIR(control) (control & 0x80) +#define DNP3_LINK_PRI(control) (control & 0x40) +#define DNP3_LINK_FCB(control) (control & 0x20) +#define DNP3_LINK_FCV(control) (control & 0x10) +#define DNP3_LINK_FC(control) (control & 0x0f) + +/* Extract fields from transport layer header octet. */ +#define DNP3_TH_FIN(x) (x & 0x80) +#define DNP3_TH_FIR(x) (x & 0x40) +#define DNP3_TH_SEQ(x) (x & 0x3f) + +/* Extract fields from the application control octet. */ +#define DNP3_APP_FIR(x) (x & 0x80) +#define DNP3_APP_FIN(x) (x & 0x40) +#define DNP3_APP_CON(x) (x & 0x20) +#define DNP3_APP_UNS(x) (x & 0x10) +#define DNP3_APP_SEQ(x) (x & 0x0f) + +/* DNP3 values are stored in little endian on the wire, so swapping will be + * needed on big endian architectures. */ +#if __BYTE_ORDER == __BIG_ENDIAN +#define DNP3_SWAP16(x) SCByteSwap16(x) +#define DNP3_SWAP32(x) SCByteSwap32(x) +#define DNP3_SWAP64(x) SCByteSwap64(x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define DNP3_SWAP16(x) x +#define DNP3_SWAP32(x) x +#define DNP3_SWAP64(x) x +#endif + +/* DNP3 decoder events. */ +enum { + DNP3_DECODER_EVENT_FLOODED = 1, + DNP3_DECODER_EVENT_LEN_TOO_SMALL, + DNP3_DECODER_EVENT_BAD_LINK_CRC, + DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC, + DNP3_DECODER_EVENT_MALFORMED, + DNP3_DECODER_EVENT_UNKNOWN_OBJECT, +}; + +/** + * \brief DNP3 link header. + */ +typedef struct DNP3LinkHeader_ { + uint8_t start_byte0; /**< First check byte. */ + uint8_t start_byte1; /**< Second check byte. */ + uint8_t len; /**< Length of PDU without CRCs. */ + uint8_t control; /**< Control flags. */ + uint16_t dst; /**< DNP3 destination address. */ + uint16_t src; /**< DNP3 source address. */ + uint16_t crc; /**< Link header CRC. */ +} __attribute__((__packed__)) DNP3LinkHeader; + +/** + * \brief DNP3 transport header. + */ +typedef uint8_t DNP3TransportHeader; + +/** + * \brief DNP3 application header. + */ +typedef struct DNP3ApplicationHeader_ { + uint8_t control; /**< Control flags. */ + uint8_t function_code; /**< Application function code. */ +} __attribute__((__packed__)) DNP3ApplicationHeader; + +/** + * \brief DNP3 internal indicators. + * + * Part of the application header for responses only. + */ +typedef struct DNP3InternalInd_ { + uint8_t iin1; + uint8_t iin2; +} __attribute__((__packed__)) DNP3InternalInd; + +/** + * \brief A struct used for buffering incoming data prior to reassembly. + */ +typedef struct DNP3Buffer_ { + uint8_t *buffer; + size_t size; + int len; + int offset; +} DNP3Buffer; + +/** + * \brief DNP3 application object header. + */ +typedef struct DNP3ObjHeader_ { + uint8_t group; + uint8_t variation; + uint8_t qualifier; +} __attribute__((packed)) DNP3ObjHeader; + +/** + * \brief DNP3 object point. + * + * Each DNP3 object can have 0 or more points representing the values + * of the object. + */ +typedef struct DNP3Point_ { + uint32_t prefix; /**< Prefix value for point. */ + uint32_t index; /**< Index of point. If the object is prefixed + * with an index then this will be that + * value. Otherwise this is the place the point + * was in the list of points (starting at 0). */ + uint32_t size; /**< Size of point if the object prefix was a + * size. */ + void *data; /**< Data for this point. */ + TAILQ_ENTRY(DNP3Point_) next; +} DNP3Point; + +typedef TAILQ_HEAD(DNP3PointList_, DNP3Point_) DNP3PointList; + +/** + * \brief Struct to hold the list of decoded objects. + */ +typedef struct DNP3Object_ { + uint8_t group; + uint8_t variation; + uint8_t qualifier; + uint8_t prefix_code; + uint8_t range_code; + uint32_t start; + uint32_t stop; + uint32_t count; + DNP3PointList *points; /**< List of points for this object. */ + + TAILQ_ENTRY(DNP3Object_) next; +} DNP3Object; + +typedef TAILQ_HEAD(DNP3ObjectList_, DNP3Object_) DNP3ObjectList; + +/** + * \brief DNP3 transaction. + */ +typedef struct DNP3Transaction_ { + uint64_t tx_num; /**< Internal transaction ID. */ + uint32_t logged; /**< Flags indicating which loggers have logged this tx. */ + + struct DNP3State_ *dnp3; + + uint8_t has_request; + uint8_t request_done; + DNP3LinkHeader request_lh; + DNP3TransportHeader request_th; + DNP3ApplicationHeader request_ah; + uint8_t *request_buffer; /**< Reassembled request + * buffer. */ + uint32_t request_buffer_len; + uint8_t request_complete; /**< Was the decode + * complete. It will not be + * complete if we hit objects + * we do not know. */ + DNP3ObjectList request_objects; + + uint8_t has_response; + uint8_t response_done; + DNP3LinkHeader response_lh; + DNP3TransportHeader response_th; + DNP3ApplicationHeader response_ah; + DNP3InternalInd response_iin; + uint8_t *response_buffer; /**< Reassembed response + * buffer. */ + uint32_t response_buffer_len; + uint8_t response_complete; /**< Was the decode + * complete. It will not be + * complete if we hit objects + * we do not know. */ + DNP3ObjectList response_objects; + + AppLayerDecoderEvents *decoder_events; /**< Per transcation + * decoder events. */ + DetectEngineState *de_state; + + TAILQ_ENTRY(DNP3Transaction_) next; +} DNP3Transaction; + +TAILQ_HEAD(TxListHead, DNP3Transaction_); + +/** + * \brief Per flow DNP3 state. + */ +typedef struct DNP3State_ { + TAILQ_HEAD(, DNP3Transaction_) tx_list; + DNP3Transaction *curr; /**< Current transaction. */ + uint64_t transaction_max; + uint16_t events; + uint32_t unreplied; /**< Number of unreplied requests. */ + uint8_t flooded; /**< Flag indicating flood. */ + + DNP3Buffer request_buffer; /**< Request buffer for buffering + * incomplete request PDUs received + * over TCP. */ + DNP3Buffer response_buffer; /**< Response buffer for buffering + * incomplete response PDUs received + * over TCP. */ + +} DNP3State; + +void RegisterDNP3Parsers(void); +void DNP3ParserRegisterTests(void); +int DNP3PrefixIsSize(uint8_t); + +#endif /* __APP_LAYER_DNP3_H__ */ diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 02bfd63a9ce3..6730e8144e97 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -59,6 +59,7 @@ #include "app-layer-dns-tcp.h" #include "app-layer-modbus.h" #include "app-layer-enip.h" +#include "app-layer-dnp3.h" #include "app-layer-template.h" #include "conf.h" @@ -1222,6 +1223,7 @@ void AppLayerParserRegisterProtocolParsers(void) RegisterModbusParsers(); RegisterENIPUDPParsers(); RegisterENIPTCPParsers(); + RegisterDNP3Parsers(); RegisterTemplateParsers(); /** IMAP */ diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index 596a0defe763..9830af5b2cbd 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -78,6 +78,9 @@ const char *AppProtoToString(AppProto alproto) case ALPROTO_ENIP: proto_name = "enip"; break; + case ALPROTO_DNP3: + proto_name = "dnp3"; + break; case ALPROTO_TEMPLATE: proto_name = "template"; break; diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index 907bd8629b0e..bcecc79577e4 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -43,6 +43,7 @@ enum AppProtoEnum { ALPROTO_DNS, ALPROTO_MODBUS, ALPROTO_ENIP, + ALPROTO_DNP3, ALPROTO_TEMPLATE, /* used by the probing parser when alproto detection fails diff --git a/src/util-error.c b/src/util-error.c index 82c820a335aa..d76c2d3c2291 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -330,6 +330,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_INVALID_HASH); CASE_CODE (SC_ERR_NO_SHA1_SUPPORT); CASE_CODE (SC_ERR_NO_SHA256_SUPPORT); + CASE_CODE (SC_ERR_DNP3_CONFIG); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 1b63e43554e2..b57e6b228518 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -320,6 +320,7 @@ typedef enum { SC_ERR_NO_SHA1_SUPPORT, SC_ERR_NO_SHA256_SUPPORT, SC_ERR_ENIP_CONFIG, + SC_ERR_DNP3_CONFIG, } SCError; const char *SCErrorToString(SCError); diff --git a/suricata.yaml.in b/suricata.yaml.in index 6fa50fea232b..b4cfd843d7eb 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -99,6 +99,7 @@ rule-files: - tls-events.rules # available in suricata sources under rules dir # - modbus-events.rules # available in suricata sources under rules dir # - app-layer-events.rules # available in suricata sources under rules dir +# - dnp3-events.rules # available in suricata sources under rules dir classification-file: @e_sysconfdir@classification.config reference-config-file: @e_sysconfdir@reference.config @@ -163,6 +164,7 @@ outputs: tls: yes # enable dumping of tls fields ssh: yes # enable dumping of ssh fields smtp: yes # enable dumping of smtp fields + dnp3: yes # enable dumping of DNP3 fields # Enable the logging of tagged packets for rules using the # "tag" keyword. @@ -231,6 +233,7 @@ outputs: - flow # uni-directional flows #- netflow + #- dnp3 # alert output for use with Barnyard2 - unified2-alert: @@ -722,6 +725,11 @@ app-layer: # and not to open and close it for each MODBUS/TCP transaction. In that # case, it is important to set the depth of the stream reassembling as # unlimited (stream.reassembly.depth: 0) + # DNP3 + dnp3: + enabled: no + detection-ports: + dp: 20000 # smb2 detection is disabled internally inside the engine. #smb2: # enabled: yes From 1a31bded4a18311b4bbe78db2574ae8546cae711 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 10 Apr 2015 10:22:25 -0600 Subject: [PATCH 2133/2553] DNP3: dnp3_data, dnp3_func, dnp3_ind, dnp3_obj rule keywords --- src/Makefile.am | 1 + src/detect-dnp3.c | 1036 ++++++++++++++++++++++++++++++++++ src/detect-dnp3.h | 34 ++ src/detect-engine-analyzer.c | 2 + src/detect-engine.c | 4 + src/detect-parse.c | 5 + src/detect.c | 10 + src/detect.h | 9 + 8 files changed, 1101 insertions(+) create mode 100644 src/detect-dnp3.c create mode 100644 src/detect-dnp3.h diff --git a/src/Makefile.am b/src/Makefile.am index c5bb60e7a257..04384c9fe93e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -91,6 +91,7 @@ detect-dce-stub-data.c detect-dce-stub-data.h \ detect-depth.c detect-depth.h \ detect-detection-filter.c detect-detection-filter.h \ detect-distance.c detect-distance.h \ +detect-dnp3.c detect-dnp3.h \ detect-dns-query.c detect-dns-query.h \ detect-tls-sni.c detect-tls-sni.h \ detect-tls-cert-issuer.c detect-tls-cert-issuer.h \ diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c new file mode 100644 index 000000000000..ec210cf5d27d --- /dev/null +++ b/src/detect-dnp3.c @@ -0,0 +1,1036 @@ +/* Copyright (C) 2015 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. + */ + +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-dnp3.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" + +/** + * The detection struct. + */ +typedef struct DetectDNP3_ { + union { + struct { + /* Function code for function code detection. */ + uint8_t function_code; + }; + struct { + /* Internal indicator flags for IIN detection. */ + uint16_t ind_flags; + }; + struct { + /* Object info for object detection. */ + uint8_t obj_group; + uint8_t obj_variation; + }; + }; +} DetectDNP3; + +/** + * Indicator names to value mappings (Snort compatible). + */ +DNP3Mapping DNP3IndicatorsMap[] = { + {"device_restart", 0x8000}, + {"device_trouble", 0x4000}, + {"local_control", 0x2000}, + {"need_time", 0x1000}, + {"class_3_events", 0x0800}, + {"class_2_events", 0x0400}, + {"class_1_events", 0x0200}, + {"all_stations", 0x0100}, + + {"reserved_1", 0x0080}, + {"reserved_2", 0x0040}, + {"config_corrupt", 0x0020}, + {"already_executing", 0x0010}, + {"event_buffer_overflow", 0x0008}, + {"parameter_error", 0x0004}, + {"object_unknown", 0x0002}, + {"no_func_code_support", 0x0001}, + + {NULL, 0}, +}; + +/** + * Application function code name to code mappings (Snort compatible). + */ +DNP3Mapping DNP3FunctionNameMap[] = { + {"confirm", 0}, + {"read", 1}, + {"write", 2}, + {"select", 3}, + {"operate", 4}, + {"direct_operate", 5}, + {"direct_operate_nr", 6}, + {"immed_freeze", 7}, + {"immed_freeze_nr", 8}, + {"freeze_clear", 9}, + {"freeze_clear_nr", 10}, + {"freeze_at_time", 11}, + {"freeze_at_time_nr", 12}, + {"cold_restart", 13}, + {"warm_restart", 14}, + {"initialize_data", 15}, + {"initialize_appl", 16}, + {"start_appl", 17}, + {"stop_appl", 18}, + {"save_config", 19}, + {"enable_unsolicited", 20}, + {"disable_unsolicited", 21}, + {"assign_class", 22}, + {"delay_measure", 23}, + {"record_current_time", 24}, + {"open_file", 25}, + {"close_file", 26}, + {"delete_file", 27}, + {"get_file_info", 28}, + {"authenticate_file", 29}, + {"abort_file", 30}, + {"activate_config", 31}, + {"authenticate_req", 32}, + {"authenticate_err", 33}, + {"response", 129}, + {"unsolicited_response", 130}, + {"authenticate_resp", 131} +}; + +static void DetectDNP3FuncRegisterTests(void); +static void DetectDNP3IndRegisterTests(void); +static void DetectDNP3ObjRegisterTests(void); +static void DetectDNP3DataRegisterTests(void); + +/** + * \brief Utility function to trim leading and trailing whitespace + * from a string. + */ +static char *TrimString(char *str) +{ + char *end = str + strlen(str) - 1; + while (isspace(*str)) { + str++; + } + while (end > str && isspace(*end)) { + end--; + } + *(end + 1) = '\0'; + return str; +} + +static int DetectEngineInspectDNP3Data(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + SCEnter(); + DNP3Transaction *tx = (DNP3Transaction *)txv; + + int r = 0; + + /* Content match - should probably be put into its own file. */ + if (flags & STREAM_TOSERVER && tx->request_buffer != NULL) { + r = DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_DNP3_DATA_MATCH], f, tx->request_buffer, + tx->request_buffer_len, 0, 0, NULL); + } + else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { + r = DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_DNP3_DATA_MATCH], f, tx->response_buffer, + tx->response_buffer_len, 0, 0, NULL); + } + + SCReturnInt(r); +} + +static int DetectEngineInspectDNP3(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, + alstate, txv, tx_id, DETECT_SM_LIST_DNP3_MATCH); +} + +/** + * \brief Parse the provided function name or code to its integer + * value. + * + * If the value passed is a number, it will be checked that it falls + * within the range of valid function codes. If function name is + * passed it will be resolved to its function code. + * + * \retval The function code as an integer if successul, -1 on + * failure. + */ +static int DetectDNP3FuncParseFunctionCode(char *str, uint8_t *fc) +{ + if (ByteExtractStringUint8(fc, 10, strlen(str), str) >= 0) { + return 1; + } + else { + /* Lookup by name. */ + for (size_t i = 0; + i < sizeof(DNP3FunctionNameMap) / sizeof(DNP3Mapping); i++) { + if (strcasecmp(str, DNP3FunctionNameMap[i].name) == 0) { + *fc = DNP3FunctionNameMap[i].value; + return 1; + } + } + } + + return 0; +} + +static int DetectDNP3FuncSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCEnter(); + DetectDNP3 *dnp3 = NULL; + SigMatch *sm = NULL; + uint8_t function_code; + + if (!DetectDNP3FuncParseFunctionCode(str, &function_code)) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "Invalid argument \"%s\" supplied to dnp3_func keyword.", str); + return -1; + } + + dnp3 = SCCalloc(1, sizeof(DetectDNP3)); + if (unlikely(dnp3 == NULL)) { + goto error; + } + dnp3->detect_type = DNP3_DETECT_TYPE_FC; + dnp3->function_code = function_code; + + sm = SigMatchAlloc(); + if (sm == NULL) { + goto error; + } + sm->type = DETECT_AL_DNP3FUNC; + sm->ctx = (void *)dnp3; + s->alproto = ALPROTO_DNP3; + s->flags |= SIG_FLAG_STATE_MATCH; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNP3_MATCH); + + SCReturnInt(0); +error: + if (dnp3 != NULL) { + SCFree(dnp3); + } + if (sm != NULL) { + SCFree(sm); + } + SCReturnInt(-1); +} + +static int DetectDNP3IndParseByName(char *str, uint16_t *flags) +{ + char tmp[strlen(str) + 1]; + char *p, *last = NULL; + + strlcpy(tmp, str, sizeof(tmp)); + + for ((p = strtok_r(tmp, ",", &last)); p; (p = strtok_r(NULL, ",", &last))) { + p = TrimString(p); + int found = 0; + int i = 0; + while (DNP3IndicatorsMap[i].name != NULL) { + if (strcasecmp(p, DNP3IndicatorsMap[i].name) == 0) { + *flags |= DNP3IndicatorsMap[i].value; + found = 1; + break; + } + i++; + } + + if (!found) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "Bad argument \"%s\" supplied to dnp3.ind keyword.", p); + return 0; + } + } + + return 1; +} + +static int DetectDNP3IndParse(char *str, uint16_t *flags) +{ + *flags = 0; + + if (ByteExtractStringUint16(flags, 0, strlen(str), str) > 0) { + return 1; + } + + /* Parse by name - will log a more specific error message on error. */ + if (DetectDNP3IndParseByName(str, flags)) { + return 1; + } + + return 0; +} + +static int DetectDNP3IndSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCEnter(); + DetectDNP3 *detect = NULL; + SigMatch *sm = NULL; + uint16_t flags; + + if (!DetectDNP3IndParse(str, &flags)) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "Invalid argument \"%s\" supplied to dnp3.ind keyword.", str); + return -1; + } + + detect = SCCalloc(1, sizeof(DetectDNP3)); + if (unlikely(detect == NULL)) { + goto error; + } + detect->detect_type = DNP3_DETECT_TYPE_IND; + detect->ind_flags = flags; + + sm = SigMatchAlloc(); + if (sm == NULL) { + goto error; + } + sm->type = DETECT_AL_DNP3IND; + sm->ctx = (void *)detect; + s->alproto = ALPROTO_DNP3; + s->flags |= SIG_FLAG_STATE_MATCH; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNP3_MATCH); + + SCReturnInt(0); +error: + if (detect != NULL) { + SCFree(detect); + } + if (sm != NULL) { + SCFree(sm); + } + SCReturnInt(-1); +} + +/** + * \brief Parse the value of string of the dnp3_obj keyword. + * + * \param str the input string + * \param gout pointer to variable to store the parsed group integer + * \param vout pointer to variable to store the parsed variation integer + * + * \retval 1 if parsing successful otherwise 0. + */ +static int DetectDNP3ObjParse(const char *str, uint8_t *group, uint8_t *var) +{ + char *groupstr = NULL, *varstr, *sep; + int result = 0; + + groupstr = SCStrdup(str); + if (unlikely(groupstr == NULL)) { + return 0; + } + + sep = strchr(groupstr, ','); + if (sep == NULL) { + goto fail; + } + *sep = '\0'; + varstr = sep + 1; + + if (ByteExtractStringUint8(group, 0, strlen(groupstr), groupstr) < 0) { + goto fail; + } + + if (ByteExtractStringUint8(var, 0, strlen(varstr), varstr) < 0) { + goto fail; + } + + result = 1; +fail: + if (groupstr == NULL) { + SCFree(groupstr); + } + return result; +} + +static int DetectDNP3ObjSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCEnter(); + uint8_t group; + uint8_t variation; + DetectDNP3 *detect = NULL; + SigMatch *sm = NULL; + + if (!DetectDNP3ObjParse(str, &group, &variation)) { + goto fail; + } + + detect = SCCalloc(1, sizeof(*detect)); + if (unlikely(detect == NULL)) { + goto fail; + } + detect->detect_type = DNP3_DETECT_TYPE_OBJ; + detect->obj_group = group; + detect->obj_variation = variation; + + sm = SigMatchAlloc(); + if (unlikely(sm == NULL)) { + goto fail; + } + sm->type = DETECT_AL_DNP3OBJ; + sm->ctx = (void *)detect; + s->alproto = ALPROTO_DNP3; + s->flags |= SIG_FLAG_STATE_MATCH; + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNP3_MATCH); + + SCReturnInt(1); +fail: + if (detect != NULL) { + SCFree(detect); + } + if (sm != NULL) { + SCFree(sm); + } + SCReturnInt(0); +} + +static void DetectDNP3Free(void *ptr) +{ + SCEnter(); + if (ptr != NULL) { + SCFree(ptr); + } + SCReturn; +} + +static int DetectDNP3FuncMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, + const SigMatchCtx *ctx) +{ + DNP3Transaction *tx = (DNP3Transaction *)txv; + DetectDNP3 *detect = (DetectDNP3 *)ctx; + int match = 0; + + if (flags & STREAM_TOSERVER) { + match = detect->function_code == tx->request_ah.function_code; + } + else if (flags & STREAM_TOCLIENT) { + match = detect->function_code == tx->response_ah.function_code; + } + + return match; +} + +static int DetectDNP3ObjMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, + const SigMatchCtx *ctx) +{ + DNP3Transaction *tx = (DNP3Transaction *)txv; + DetectDNP3 *detect = (DetectDNP3 *)ctx; + DNP3ObjectList *objects = NULL; + + if (flags & STREAM_TOSERVER) { + objects = &tx->request_objects; + } + else if (flags & STREAM_TOCLIENT) { + objects = &tx->response_objects; + } + + if (objects != NULL) { + DNP3Object *object; + TAILQ_FOREACH(object, objects, next) { + if (object->group == detect->obj_group && + object->variation == detect->obj_variation) { + return 1; + } + } + } + + return 0; +} + +static int DetectDNP3IndMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, + const SigMatchCtx *ctx) +{ + DNP3Transaction *tx = (DNP3Transaction *)txv; + DetectDNP3 *detect = (DetectDNP3 *)ctx; + + if (flags & STREAM_TOCLIENT) { + if ((tx->response_iin.iin1 & (detect->ind_flags >> 8)) || + (tx->response_iin.iin2 & (detect->ind_flags & 0xf))) { + return 1; + } + } + + return 0; +} + +static void DetectDNP3FuncRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3FUNC].name = "dnp3.func"; + sigmatch_table[DETECT_AL_DNP3FUNC].alias = "dnp3_func"; + sigmatch_table[DETECT_AL_DNP3FUNC].Match = NULL; + sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_DNP3FUNC].Setup = DetectDNP3FuncSetup; + sigmatch_table[DETECT_AL_DNP3FUNC].Free = DetectDNP3Free; + sigmatch_table[DETECT_AL_DNP3FUNC].RegisterTests = + DetectDNP3FuncRegisterTests; + + SCReturn; +} + +static void DetectDNP3IndRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3IND].name = "dnp3.ind"; + sigmatch_table[DETECT_AL_DNP3IND].alias = "dnp3_ind"; + sigmatch_table[DETECT_AL_DNP3IND].Match = NULL; + sigmatch_table[DETECT_AL_DNP3IND].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_DNP3IND].Setup = DetectDNP3IndSetup; + sigmatch_table[DETECT_AL_DNP3IND].Free = DetectDNP3Free; + sigmatch_table[DETECT_AL_DNP3IND].RegisterTests = + DetectDNP3IndRegisterTests; + + SCReturn; +} + +static void DetectDNP3ObjRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3OBJ].name = "dnp3.obj"; + sigmatch_table[DETECT_AL_DNP3OBJ].alias = "dnp3_obj"; + sigmatch_table[DETECT_AL_DNP3OBJ].Match = NULL; + sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_DNP3OBJ].Setup = DetectDNP3ObjSetup; + sigmatch_table[DETECT_AL_DNP3OBJ].Free = DetectDNP3Free; + sigmatch_table[DETECT_AL_DNP3OBJ].RegisterTests = + DetectDNP3ObjRegisterTests; + + SCReturn; +} + +static int DetectDNP3DataSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCEnter(); + s->list = DETECT_SM_LIST_DNP3_DATA_MATCH; + s->alproto = ALPROTO_DNP3; + SCReturnInt(0); +} + +static void DetectDNP3DataRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3DATA].name = "dnp3_data"; + sigmatch_table[DETECT_AL_DNP3DATA].Match = NULL; + sigmatch_table[DETECT_AL_DNP3DATA].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_DNP3DATA].Setup = DetectDNP3DataSetup; + sigmatch_table[DETECT_AL_DNP3DATA].Free = NULL; + sigmatch_table[DETECT_AL_DNP3DATA].RegisterTests = + DetectDNP3DataRegisterTests; + + sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_PAYLOAD; + + DetectAppLayerInspectEngineRegister(ALPROTO_DNP3, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_DNP3_DATA_MATCH, DetectEngineInspectDNP3Data); + DetectAppLayerInspectEngineRegister(ALPROTO_DNP3, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_DNP3_DATA_MATCH, DetectEngineInspectDNP3Data); + + SCReturn; +} + +void DetectDNP3Register(void) +{ + DetectDNP3DataRegister(); + + DetectDNP3FuncRegister(); + DetectDNP3IndRegister(); + DetectDNP3ObjRegister(); + + /* Register the list of func, ind and obj. */ + DetectAppLayerInspectEngineRegister(ALPROTO_DNP3, SIG_FLAG_TOSERVER, + DETECT_SM_LIST_DNP3_MATCH, DetectEngineInspectDNP3); + DetectAppLayerInspectEngineRegister(ALPROTO_DNP3, SIG_FLAG_TOCLIENT, + DETECT_SM_LIST_DNP3_MATCH, DetectEngineInspectDNP3); +} + +#ifdef UNITTESTS + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer-parser.h" +#include "detect-engine.h" +#include "flow-util.h" +#include "stream-tcp.h" + +static int DetectDNP3FuncParseFunctionCodeTest(void) +{ + uint8_t fc; + + /* Valid. */ + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("0", &fc)); + FAIL_IF(fc != 0); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("1", &fc)); + FAIL_IF(fc != 1); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("254", &fc)); + FAIL_IF(fc != 254); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("255", &fc)); + FAIL_IF(fc != 255); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("confirm", &fc)); + FAIL_IF(fc != 0); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("CONFIRM", &fc)); + FAIL_IF(fc != 0); + + /* Invalid. */ + FAIL_IF(DetectDNP3FuncParseFunctionCode("", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("-1", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("-2", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("256", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("unknown_function_code", &fc)); + + PASS; +} + +static int DetectDNP3FuncTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectDNP3 *dnp3func = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->sig_list = SigInit(de_ctx, + "alert dnp3 any any -> any any " + "(msg:\"SURICATA DNP3 Write request\"; " + "dnp3_func:2; sid:5000009; rev:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH]); + FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH]->ctx); + + dnp3func = (DetectDNP3 *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH]->ctx; + FAIL_IF(dnp3func->function_code != 2); + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + PASS; +} + +static int DetectDNP3IndTestParseAsInteger(void) +{ + uint16_t flags = 0; + + FAIL_IF(!DetectDNP3IndParse("0", &flags)); + FAIL_IF(flags != 0); + FAIL_IF(!DetectDNP3IndParse("1", &flags)); + FAIL_IF(flags != 0x0001); + + FAIL_IF(!DetectDNP3IndParse("0x0", &flags)); + FAIL_IF(flags != 0); + FAIL_IF(!DetectDNP3IndParse("0x0000", &flags)); + FAIL_IF(flags != 0); + FAIL_IF(!DetectDNP3IndParse("0x0001", &flags)); + FAIL_IF(flags != 0x0001); + + FAIL_IF(!DetectDNP3IndParse("0x8421", &flags)); + FAIL_IF(flags != 0x8421); + + FAIL_IF(DetectDNP3IndParse("a", &flags)); + + PASS; +} + +static int DetectDNP3IndTestParseByName(void) +{ + uint16_t flags = 0; + + FAIL_IF(!DetectDNP3IndParse("all_stations", &flags)); + FAIL_IF(!(flags & 0x0100)); + FAIL_IF(!DetectDNP3IndParse("class_1_events , class_2_events", &flags)); + FAIL_IF(!(flags & 0x0200)); + FAIL_IF(!(flags & 0x0400)); + FAIL_IF((flags & 0xf9ff)); + + FAIL_IF(DetectDNP3IndParse("something", &flags)); + + PASS; +} + +static int DetectDNP3ObjSetupTest(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectDNP3 *detect = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + de_ctx->sig_list = SigInit(de_ctx, + "alert dnp3 any any -> any any " + "(msg:\"SURICATA DNP3 Object Test\"; " + "dnp3_obj:99,99; sid:1; rev:1;)"); + FAIL_IF(de_ctx->sig_list == NULL); + + FAIL_IF(de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH] == NULL); + FAIL_IF(de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH]->ctx == NULL); + + detect = (DetectDNP3 *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH]->ctx; + FAIL_IF(detect->obj_group != 99); + FAIL_IF(detect->obj_variation != 99); + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + PASS; +} + +static int DetectDNP3ObjParseTest(void) +{ + uint8_t group, var; + + FAIL_IF(!DetectDNP3ObjParse("0,0", &group, &var)); + FAIL_IF(group != 0 || var != 0); + + FAIL_IF(!DetectDNP3ObjParse("255,255", &group, &var)); + FAIL_IF(group != 255 || var != 255); + + FAIL_IF(DetectDNP3ObjParse("-1,-1", &group, &var)); + FAIL_IF(DetectDNP3ObjParse("256,256", &group, &var)); + FAIL_IF(DetectDNP3ObjParse("a,1", &group, &var)); + FAIL_IF(DetectDNP3ObjParse("1,a", &group, &var)); + + PASS; +} + +/** + * Test request (to server) content match. + */ +static int DetectDNP3DataTest01(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p; + TcpSession tcp; + ThreadVars tv; + + uint8_t request[] = { + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + 0xff, 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + + /* CRC. */ + 0x72, 0xef, + + 0x00, 0x00, 0x00, 0x00, 0x00, + + /* CRC. */ + 0xff, 0xff, + }; + + /* Setup flow. */ + memset(&f, 0, sizeof(Flow)); + memset(&tcp, 0, sizeof(TcpSession)); + memset(&tv, 0, sizeof(ThreadVars)); + p = UTHBuildPacket(request, sizeof(request), IPPROTO_TCP); + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_DNP3; + f.protoctx = (void *)&tcp; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + /* Either direction - should match. */ + Signature *s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00 00 00 00|\"; " + "sid:1; rev:1;)"); + FAIL_IF(s == NULL); + + /* To server - should match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "flow:established,to_server; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00 00 00 00|\"; " + "sid:2; rev:1;)"); + FAIL_IF(s == NULL); + + /* To client - should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "flow:established,to_client; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00 00 00 00|\"; " + "sid:3; rev:1;)"); + FAIL_IF(s == NULL); + + /* The content of a CRC - should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "dnp3_data; " + "content:\"|72 ef|\"; " + "sid:4; rev:1;)"); + FAIL_IF(s == NULL); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request)); + SCMutexUnlock(&f.m); + FAIL_IF(r); + + FAIL_IF(f.alstate == NULL); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 1)); + FAIL_IF(!PacketAlertCheck(p, 2)); + FAIL_IF(PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + PASS; +} + +/** + * Test response (to client) content match. + */ +static int DetectDNP3DataTest02(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p; + TcpSession tcp; + ThreadVars tv; + + uint8_t request[] = { + /* Link header. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + + /* CRC. */ + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + + /* CRC. */ + 0x72, 0xef, + + /* Application layer. */ + 0x00, 0x00, 0x00, 0x00, 0x00, + + /* CRC. */ + 0xff, 0xff, + }; + + uint8_t response[] = { + /* Link header. */ + 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00, + + /* CRC. */ + 0xe2, 0x59, + + /* Transport header. */ + 0xc3, + + /* Application layyer. */ + 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + + /* CRC. */ + 0x7a, 0x65, + + /* Application layer. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* CRC. */ + 0xff, 0xff + }; + + /* Setup flow. */ + memset(&f, 0, sizeof(Flow)); + memset(&tcp, 0, sizeof(TcpSession)); + memset(&tv, 0, sizeof(ThreadVars)); + p = UTHBuildPacket(response, sizeof(response), IPPROTO_TCP); + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_DNP3; + f.protoctx = (void *)&tcp; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOCLIENT | FLOW_PKT_ESTABLISHED; + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + /* Either direction - should match. */ + Signature *s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00|\"; " + "sid:1; rev:1;)"); + FAIL_IF(s == NULL); + + /* To server - should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "flow:established,to_server; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00|\"; " + "sid:2; rev:1;)"); + FAIL_IF(s == NULL); + + /* To client - should match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "flow:established,to_client; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00|\"; " + "sid:3; rev:1;)"); + FAIL_IF(s == NULL); + + /* The content of a CRC - should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "dnp3_data; " + "content:\"|7a 65|\"; " + "sid:4; rev:1;)"); + FAIL_IF(s == NULL); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + /* Send through the request, then response. */ + SCMutexLock(&f.m); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request)); + SCMutexUnlock(&f.m); + FAIL_IF(r); + FAIL_IF(f.alstate == NULL); + + SCMutexLock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNP3, STREAM_TOCLIENT, + response, sizeof(response)); + SCMutexUnlock(&f.m); + FAIL_IF(r); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + FAIL_IF(!PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + PASS; +} + +#endif + +static void DetectDNP3FuncRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectDNP3FuncParseFunctionCodeTest", + DetectDNP3FuncParseFunctionCodeTest); + UtRegisterTest("DetectDNP3FuncTest01", DetectDNP3FuncTest01); +#endif +} + +static void DetectDNP3IndRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectDNP3IndTestParseAsInteger", + DetectDNP3IndTestParseAsInteger); + UtRegisterTest("DetectDNP3IndTestParseByName", + DetectDNP3IndTestParseByName); +#endif +} + +static void DetectDNP3ObjRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectDNP3ObjParseTest", DetectDNP3ObjParseTest); + UtRegisterTest("DetectDNP3ObjSetupTest", DetectDNP3ObjSetupTest); +#endif +} + +void DetectDNP3DataRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectDNP3DataTest01", DetectDNP3DataTest01); + UtRegisterTest("DetectDNP3DataTest02", DetectDNP3DataTest02); +#endif +} diff --git a/src/detect-dnp3.h b/src/detect-dnp3.h new file mode 100644 index 000000000000..b8230db7c96c --- /dev/null +++ b/src/detect-dnp3.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __DETECT_DNP3_H__ +#define __DETECT_DNP3_H__ + +/** + * Struct for mapping symbolic names to values. + */ +typedef struct DNP3Mapping_ { + char *name; + uint16_t value; +} DNP3Mapping; + +/* Map of internal indicators to value for external use. */ +extern DNP3Mapping DNP3IndicatorsMap[]; + +void DetectDNP3Register(void); + +#endif /* __DETECT_DNP3_H__ */ diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index a2f7f9b7c4ed..6f4a15adc878 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -491,6 +491,8 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "tls issuer content"); else if (list_type == DETECT_SM_LIST_TLSSUBJECT_MATCH) fprintf(rule_engine_analysis_FD, "tls subject content"); + else if (list_type == DETECT_SM_LIST_DNP3_DATA_MATCH) + fprintf(rule_engine_analysis_FD, "dnp3 data content"); fprintf(rule_engine_analysis_FD, "\" buffer.\n"); diff --git a/src/detect-engine.c b/src/detect-engine.c index 0dea5da9ae73..120b41d0ab73 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2532,6 +2532,10 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; + case DETECT_SM_LIST_DNP3_DATA_MATCH: + return "dnp3_data"; + case DETECT_SM_LIST_DNP3_MATCH: + return "dnp3"; case DETECT_SM_LIST_CIP_MATCH: return "cip"; diff --git a/src/detect-parse.c b/src/detect-parse.c index 5a476d10b93a..168c12ca8206 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1600,6 +1600,11 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (sig->sm_lists[DETECT_SM_LIST_HRHHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + /* DNP3. */ + if (sig->sm_lists[DETECT_SM_LIST_DNP3_DATA_MATCH]) { + sig->flags |= SIG_FLAG_STATE_MATCH; + } + /* Template. */ if (sig->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH]) { sig->flags |= SIG_FLAG_STATE_MATCH; diff --git a/src/detect.c b/src/detect.c index 6c1c907798f9..458248f4ec19 100644 --- a/src/detect.c +++ b/src/detect.c @@ -187,6 +187,7 @@ #include "detect-ssl-state.h" #include "detect-modbus.h" #include "detect-cipservice.h" +#include "detect-dnp3.h" #include "action-globals.h" #include "tm-threads.h" @@ -2262,6 +2263,9 @@ PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, int has_state case ALPROTO_ENIP: SCLogDebug("packet/flow has enip state"); (*mask) |= SIG_MASK_REQUIRE_ENIP_STATE; + case ALPROTO_DNP3: + SCLogDebug("packet/flow has dnp3 state"); + (*mask) |= SIG_MASK_REQUIRE_DNP3_STATE; break; case ALPROTO_TEMPLATE: SCLogDebug("packet/flow has template state"); @@ -2500,6 +2504,10 @@ static int SignatureCreateMask(Signature *s) s->mask |= SIG_MASK_REQUIRE_DNS_STATE; SCLogDebug("sig requires dns state"); } + if (s->alproto == ALPROTO_DNP3) { + s->mask |= SIG_MASK_REQUIRE_DNP3_STATE; + SCLogDebug("sig requires dnp3 state"); + } if (s->alproto == ALPROTO_FTP) { s->mask |= SIG_MASK_REQUIRE_FTP_STATE; SCLogDebug("sig requires ftp state"); @@ -2521,6 +2529,7 @@ static int SignatureCreateMask(Signature *s) (s->mask & SIG_MASK_REQUIRE_HTTP_STATE) || (s->mask & SIG_MASK_REQUIRE_SSH_STATE) || (s->mask & SIG_MASK_REQUIRE_DNS_STATE) || + (s->mask & SIG_MASK_REQUIRE_DNP3_STATE) || (s->mask & SIG_MASK_REQUIRE_FTP_STATE) || (s->mask & SIG_MASK_REQUIRE_SMTP_STATE) || (s->mask & SIG_MASK_REQUIRE_ENIP_STATE) || @@ -4227,6 +4236,7 @@ void SigTableSetup(void) DetectModbusRegister(); DetectCipServiceRegister(); DetectEnipCommandRegister(); + DetectDNP3Register(); DetectTlsSniRegister(); DetectTlsIssuerRegister(); diff --git a/src/detect.h b/src/detect.h index 823a490b7f7a..a6ae3d4f89aa 100644 --- a/src/detect.h +++ b/src/detect.h @@ -141,6 +141,9 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_BASE64_DATA, + DETECT_SM_LIST_DNP3_DATA_MATCH, + DETECT_SM_LIST_DNP3_MATCH, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, /* Demarcation between detection and post-detection lists. All @@ -313,6 +316,7 @@ typedef struct DetectPort_ { #define SIG_MASK_REQUIRE_SMTP_STATE (1<<12) #define SIG_MASK_REQUIRE_TEMPLATE_STATE (1<<13) #define SIG_MASK_REQUIRE_ENIP_STATE (1<<14) +#define SIG_MASK_REQUIRE_DNP3_STATE (1<<15) /* for now a uint8_t is enough */ #define SignatureMask uint16_t @@ -1332,6 +1336,11 @@ enum { DETECT_CIPSERVICE, DETECT_ENIPCOMMAND, + DETECT_AL_DNP3DATA, + DETECT_AL_DNP3FUNC, + DETECT_AL_DNP3IND, + DETECT_AL_DNP3OBJ, + DETECT_XBITS, DETECT_BASE64_DECODE, DETECT_BASE64_DATA, From 1c3f37354383884075e69397abdc2820d95d1fe2 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 7 May 2015 11:53:39 -0600 Subject: [PATCH 2134/2553] DNP3: Log DNP3 transactions. --- src/Makefile.am | 2 + src/output-json-dnp3-objects.c | 2720 ++++++++++++++++++++++++++++++++ src/output-json-dnp3-objects.h | 26 + src/output-json-dnp3.c | 446 ++++++ src/output-json-dnp3.h | 30 + src/suricata.c | 3 +- 6 files changed, 3226 insertions(+), 1 deletion(-) create mode 100644 src/output-json-dnp3-objects.c create mode 100644 src/output-json-dnp3-objects.h create mode 100644 src/output-json-dnp3.c create mode 100644 src/output-json-dnp3.h diff --git a/src/Makefile.am b/src/Makefile.am index 04384c9fe93e..e91786a31488 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -265,6 +265,8 @@ output-filedata.c output-filedata.h \ output-flow.c output-flow.h \ output-json-alert.c output-json-alert.h \ output-json-dns.c output-json-dns.h \ +output-json-dnp3.c output-json-dnp3.h \ +output-json-dnp3-objects.c output-json-dnp3-objects.h \ output-json-drop.c output-json-drop.h \ output-json-email-common.c output-json-email-common.h \ output-json-file.c output-json-file.h \ diff --git a/src/output-json-dnp3-objects.c b/src/output-json-dnp3-objects.c new file mode 100644 index 000000000000..8fc7e760c0d5 --- /dev/null +++ b/src/output-json-dnp3-objects.c @@ -0,0 +1,2720 @@ +/* Copyright (C) 2015 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. + */ + +/** + * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. + * + * Generated by command: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +#include "suricata-common.h" + +#include "util-crypt.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#ifdef HAVE_LIBJANSSON + +void OutputJsonDNP3SetItem(json_t *js, DNP3Object *object, + DNP3Point *point) +{ + + switch (DNP3_OBJECT_CODE(object->group, object->variation)) { + case DNP3_OBJECT_CODE(1, 1): { + DNP3ObjectG1V1 *data = point->data; + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(1, 2): { + DNP3ObjectG1V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "reserved", + json_integer(data->reserved)); + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(2, 1): { + DNP3ObjectG2V1 *data = point->data; + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(2, 2): { + DNP3ObjectG2V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "reserved", + json_integer(data->reserved)); + json_object_set_new(js, "state", + json_integer(data->state)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(2, 3): { + DNP3ObjectG2V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "reserved", + json_integer(data->reserved)); + json_object_set_new(js, "state", + json_integer(data->state)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(3, 1): { + DNP3ObjectG3V1 *data = point->data; + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(3, 2): { + DNP3ObjectG3V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(4, 1): { + DNP3ObjectG4V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(4, 2): { + DNP3ObjectG4V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "state", + json_integer(data->state)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(4, 3): { + DNP3ObjectG4V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "state", + json_integer(data->state)); + json_object_set_new(js, "relative_time_ms", + json_integer(data->relative_time_ms)); + break; + } + case DNP3_OBJECT_CODE(10, 1): { + DNP3ObjectG10V1 *data = point->data; + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(10, 2): { + DNP3ObjectG10V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(11, 1): { + DNP3ObjectG11V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(11, 2): { + DNP3ObjectG11V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "state", + json_integer(data->state)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(12, 1): { + DNP3ObjectG12V1 *data = point->data; + json_object_set_new(js, "op_type", + json_integer(data->op_type)); + json_object_set_new(js, "qu", + json_integer(data->qu)); + json_object_set_new(js, "cr", + json_integer(data->cr)); + json_object_set_new(js, "tcc", + json_integer(data->tcc)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "ontime", + json_integer(data->ontime)); + json_object_set_new(js, "offtime", + json_integer(data->offtime)); + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved", + json_integer(data->reserved)); + break; + } + case DNP3_OBJECT_CODE(12, 2): { + DNP3ObjectG12V2 *data = point->data; + json_object_set_new(js, "op_type", + json_integer(data->op_type)); + json_object_set_new(js, "qu", + json_integer(data->qu)); + json_object_set_new(js, "cr", + json_integer(data->cr)); + json_object_set_new(js, "tcc", + json_integer(data->tcc)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "ontime", + json_integer(data->ontime)); + json_object_set_new(js, "offtime", + json_integer(data->offtime)); + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved", + json_integer(data->reserved)); + break; + } + case DNP3_OBJECT_CODE(12, 3): { + DNP3ObjectG12V3 *data = point->data; + json_object_set_new(js, "point", + json_integer(data->point)); + break; + } + case DNP3_OBJECT_CODE(13, 1): { + DNP3ObjectG13V1 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "commanded_state", + json_integer(data->commanded_state)); + break; + } + case DNP3_OBJECT_CODE(13, 2): { + DNP3ObjectG13V2 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "commanded_state", + json_integer(data->commanded_state)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(20, 1): { + DNP3ObjectG20V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 2): { + DNP3ObjectG20V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 3): { + DNP3ObjectG20V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 4): { + DNP3ObjectG20V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 5): { + DNP3ObjectG20V5 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 6): { + DNP3ObjectG20V6 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 7): { + DNP3ObjectG20V7 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 8): { + DNP3ObjectG20V8 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 1): { + DNP3ObjectG21V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 2): { + DNP3ObjectG21V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 3): { + DNP3ObjectG21V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 4): { + DNP3ObjectG21V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 5): { + DNP3ObjectG21V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(21, 6): { + DNP3ObjectG21V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(21, 7): { + DNP3ObjectG21V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(21, 8): { + DNP3ObjectG21V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(21, 9): { + DNP3ObjectG21V9 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 10): { + DNP3ObjectG21V10 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 11): { + DNP3ObjectG21V11 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 12): { + DNP3ObjectG21V12 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(22, 1): { + DNP3ObjectG22V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(22, 2): { + DNP3ObjectG22V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(22, 3): { + DNP3ObjectG22V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(22, 4): { + DNP3ObjectG22V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(22, 5): { + DNP3ObjectG22V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(22, 6): { + DNP3ObjectG22V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(22, 7): { + DNP3ObjectG22V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(22, 8): { + DNP3ObjectG22V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(23, 1): { + DNP3ObjectG23V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(23, 2): { + DNP3ObjectG23V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(23, 3): { + DNP3ObjectG23V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(23, 4): { + DNP3ObjectG23V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(23, 5): { + DNP3ObjectG23V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(23, 6): { + DNP3ObjectG23V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(23, 7): { + DNP3ObjectG23V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(23, 8): { + DNP3ObjectG23V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(30, 1): { + DNP3ObjectG30V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(30, 2): { + DNP3ObjectG30V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(30, 3): { + DNP3ObjectG30V3 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(30, 4): { + DNP3ObjectG30V4 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(30, 5): { + DNP3ObjectG30V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(30, 6): { + DNP3ObjectG30V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 1): { + DNP3ObjectG31V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 2): { + DNP3ObjectG31V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 3): { + DNP3ObjectG31V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(31, 4): { + DNP3ObjectG31V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(31, 5): { + DNP3ObjectG31V5 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 6): { + DNP3ObjectG31V6 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 7): { + DNP3ObjectG31V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 8): { + DNP3ObjectG31V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(32, 1): { + DNP3ObjectG32V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(32, 2): { + DNP3ObjectG32V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(32, 3): { + DNP3ObjectG32V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(32, 4): { + DNP3ObjectG32V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(32, 5): { + DNP3ObjectG32V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(32, 6): { + DNP3ObjectG32V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(32, 7): { + DNP3ObjectG32V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(32, 8): { + DNP3ObjectG32V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(33, 1): { + DNP3ObjectG33V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(33, 2): { + DNP3ObjectG33V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(33, 3): { + DNP3ObjectG33V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(33, 4): { + DNP3ObjectG33V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(33, 5): { + DNP3ObjectG33V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(33, 6): { + DNP3ObjectG33V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(33, 7): { + DNP3ObjectG33V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(33, 8): { + DNP3ObjectG33V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(34, 1): { + DNP3ObjectG34V1 *data = point->data; + json_object_set_new(js, "deadband_value", + json_integer(data->deadband_value)); + break; + } + case DNP3_OBJECT_CODE(34, 2): { + DNP3ObjectG34V2 *data = point->data; + json_object_set_new(js, "deadband_value", + json_integer(data->deadband_value)); + break; + } + case DNP3_OBJECT_CODE(34, 3): { + DNP3ObjectG34V3 *data = point->data; + json_object_set_new(js, "deadband_value", + json_real(data->deadband_value)); + break; + } + case DNP3_OBJECT_CODE(40, 1): { + DNP3ObjectG40V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(40, 2): { + DNP3ObjectG40V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(40, 3): { + DNP3ObjectG40V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(40, 4): { + DNP3ObjectG40V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(41, 1): { + DNP3ObjectG41V1 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "control_status", + json_integer(data->control_status)); + break; + } + case DNP3_OBJECT_CODE(41, 2): { + DNP3ObjectG41V2 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "control_status", + json_integer(data->control_status)); + break; + } + case DNP3_OBJECT_CODE(41, 3): { + DNP3ObjectG41V3 *data = point->data; + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "control_status", + json_integer(data->control_status)); + break; + } + case DNP3_OBJECT_CODE(41, 4): { + DNP3ObjectG41V4 *data = point->data; + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "control_status", + json_integer(data->control_status)); + break; + } + case DNP3_OBJECT_CODE(42, 1): { + DNP3ObjectG42V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(42, 2): { + DNP3ObjectG42V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(42, 3): { + DNP3ObjectG42V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(42, 4): { + DNP3ObjectG42V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(42, 5): { + DNP3ObjectG42V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(42, 6): { + DNP3ObjectG42V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(42, 7): { + DNP3ObjectG42V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(42, 8): { + DNP3ObjectG42V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(43, 1): { + DNP3ObjectG43V1 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_integer(data->commanded_value)); + break; + } + case DNP3_OBJECT_CODE(43, 2): { + DNP3ObjectG43V2 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_integer(data->commanded_value)); + break; + } + case DNP3_OBJECT_CODE(43, 3): { + DNP3ObjectG43V3 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_integer(data->commanded_value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(43, 4): { + DNP3ObjectG43V4 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_integer(data->commanded_value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(43, 5): { + DNP3ObjectG43V5 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_real(data->commanded_value)); + break; + } + case DNP3_OBJECT_CODE(43, 6): { + DNP3ObjectG43V6 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_real(data->commanded_value)); + break; + } + case DNP3_OBJECT_CODE(43, 7): { + DNP3ObjectG43V7 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_real(data->commanded_value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(43, 8): { + DNP3ObjectG43V8 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_real(data->commanded_value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(50, 1): { + DNP3ObjectG50V1 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(50, 2): { + DNP3ObjectG50V2 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + json_object_set_new(js, "interval", + json_integer(data->interval)); + break; + } + case DNP3_OBJECT_CODE(50, 3): { + DNP3ObjectG50V3 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(50, 4): { + DNP3ObjectG50V4 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + json_object_set_new(js, "interval_count", + json_integer(data->interval_count)); + json_object_set_new(js, "interval_units", + json_integer(data->interval_units)); + break; + } + case DNP3_OBJECT_CODE(51, 1): { + DNP3ObjectG51V1 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(51, 2): { + DNP3ObjectG51V2 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(52, 1): { + DNP3ObjectG52V1 *data = point->data; + json_object_set_new(js, "delay_secs", + json_integer(data->delay_secs)); + break; + } + case DNP3_OBJECT_CODE(52, 2): { + DNP3ObjectG52V2 *data = point->data; + json_object_set_new(js, "delay_ms", + json_integer(data->delay_ms)); + break; + } + case DNP3_OBJECT_CODE(70, 1): { + DNP3ObjectG70V1 *data = point->data; + json_object_set_new(js, "filename_size", + json_integer(data->filename_size)); + json_object_set_new(js, "filetype_code", + json_integer(data->filetype_code)); + json_object_set_new(js, "attribute_code", + json_integer(data->attribute_code)); + json_object_set_new(js, "start_record", + json_integer(data->start_record)); + json_object_set_new(js, "end_record", + json_integer(data->end_record)); + json_object_set_new(js, "file_size", + json_integer(data->file_size)); + json_object_set_new(js, "created_timestamp", + json_integer(data->created_timestamp)); + json_object_set_new(js, "permission", + json_integer(data->permission)); + json_object_set_new(js, "file_id", + json_integer(data->file_id)); + json_object_set_new(js, "owner_id", + json_integer(data->owner_id)); + json_object_set_new(js, "group_id", + json_integer(data->group_id)); + json_object_set_new(js, "file_function_code", + json_integer(data->file_function_code)); + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + if (data->filename_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->filename_size + 1]; + memcpy(tmpbuf, data->filename, data->filename_size); + tmpbuf[data->filename_size] = '\0'; + json_object_set_new(js, "filename", json_string(tmpbuf)); + } else { + json_object_set_new(js, "filename", json_string("")); + } + json_object_set_new(js, "data_size", + json_integer(data->data_size)); + if (data->data_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->data_size + 1]; + memcpy(tmpbuf, data->data, data->data_size); + tmpbuf[data->data_size] = '\0'; + json_object_set_new(js, "data", json_string(tmpbuf)); + } else { + json_object_set_new(js, "data", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 2): { + DNP3ObjectG70V2 *data = point->data; + json_object_set_new(js, "username_offset", + json_integer(data->username_offset)); + json_object_set_new(js, "username_size", + json_integer(data->username_size)); + json_object_set_new(js, "password_offset", + json_integer(data->password_offset)); + json_object_set_new(js, "password_size", + json_integer(data->password_size)); + json_object_set_new(js, "authentication_key", + json_integer(data->authentication_key)); + if (data->username_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->username_size + 1]; + memcpy(tmpbuf, data->username, data->username_size); + tmpbuf[data->username_size] = '\0'; + json_object_set_new(js, "username", json_string(tmpbuf)); + } else { + json_object_set_new(js, "username", json_string("")); + } + if (data->password_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->password_size + 1]; + memcpy(tmpbuf, data->password, data->password_size); + tmpbuf[data->password_size] = '\0'; + json_object_set_new(js, "password", json_string(tmpbuf)); + } else { + json_object_set_new(js, "password", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 3): { + DNP3ObjectG70V3 *data = point->data; + json_object_set_new(js, "filename_offset", + json_integer(data->filename_offset)); + json_object_set_new(js, "filename_size", + json_integer(data->filename_size)); + json_object_set_new(js, "created", + json_integer(data->created)); + json_object_set_new(js, "permissions", + json_integer(data->permissions)); + json_object_set_new(js, "authentication_key", + json_integer(data->authentication_key)); + json_object_set_new(js, "file_size", + json_integer(data->file_size)); + json_object_set_new(js, "operational_mode", + json_integer(data->operational_mode)); + json_object_set_new(js, "maximum_block_size", + json_integer(data->maximum_block_size)); + json_object_set_new(js, "request_id", + json_integer(data->request_id)); + if (data->filename_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->filename_size + 1]; + memcpy(tmpbuf, data->filename, data->filename_size); + tmpbuf[data->filename_size] = '\0'; + json_object_set_new(js, "filename", json_string(tmpbuf)); + } else { + json_object_set_new(js, "filename", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 4): { + DNP3ObjectG70V4 *data = point->data; + json_object_set_new(js, "file_handle", + json_integer(data->file_handle)); + json_object_set_new(js, "file_size", + json_integer(data->file_size)); + json_object_set_new(js, "maximum_block_size", + json_integer(data->maximum_block_size)); + json_object_set_new(js, "request_id", + json_integer(data->request_id)); + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + if (data->optional_text_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->optional_text_len + 1]; + memcpy(tmpbuf, data->optional_text, data->optional_text_len); + tmpbuf[data->optional_text_len] = '\0'; + json_object_set_new(js, "optional_text", json_string(tmpbuf)); + } else { + json_object_set_new(js, "optional_text", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 5): { + DNP3ObjectG70V5 *data = point->data; + json_object_set_new(js, "file_handle", + json_integer(data->file_handle)); + json_object_set_new(js, "block_number", + json_integer(data->block_number)); + if (data->file_data_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->file_data_len + 1]; + memcpy(tmpbuf, data->file_data, data->file_data_len); + tmpbuf[data->file_data_len] = '\0'; + json_object_set_new(js, "file_data", json_string(tmpbuf)); + } else { + json_object_set_new(js, "file_data", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 6): { + DNP3ObjectG70V6 *data = point->data; + json_object_set_new(js, "file_handle", + json_integer(data->file_handle)); + json_object_set_new(js, "block_number", + json_integer(data->block_number)); + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + if (data->optional_text_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->optional_text_len + 1]; + memcpy(tmpbuf, data->optional_text, data->optional_text_len); + tmpbuf[data->optional_text_len] = '\0'; + json_object_set_new(js, "optional_text", json_string(tmpbuf)); + } else { + json_object_set_new(js, "optional_text", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 7): { + DNP3ObjectG70V7 *data = point->data; + json_object_set_new(js, "filename_offset", + json_integer(data->filename_offset)); + json_object_set_new(js, "filename_size", + json_integer(data->filename_size)); + json_object_set_new(js, "file_type", + json_integer(data->file_type)); + json_object_set_new(js, "file_size", + json_integer(data->file_size)); + json_object_set_new(js, "created_timestamp", + json_integer(data->created_timestamp)); + json_object_set_new(js, "permissions", + json_integer(data->permissions)); + json_object_set_new(js, "request_id", + json_integer(data->request_id)); + if (data->filename_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->filename_size + 1]; + memcpy(tmpbuf, data->filename, data->filename_size); + tmpbuf[data->filename_size] = '\0'; + json_object_set_new(js, "filename", json_string(tmpbuf)); + } else { + json_object_set_new(js, "filename", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 8): { + DNP3ObjectG70V8 *data = point->data; + if (data->file_specification_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->file_specification_len + 1]; + memcpy(tmpbuf, data->file_specification, data->file_specification_len); + tmpbuf[data->file_specification_len] = '\0'; + json_object_set_new(js, "file_specification", json_string(tmpbuf)); + } else { + json_object_set_new(js, "file_specification", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(80, 1): { + DNP3ObjectG80V1 *data = point->data; + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(81, 1): { + DNP3ObjectG81V1 *data = point->data; + json_object_set_new(js, "fill_percentage", + json_integer(data->fill_percentage)); + json_object_set_new(js, "overflow_state", + json_integer(data->overflow_state)); + json_object_set_new(js, "group", + json_integer(data->group)); + json_object_set_new(js, "variation", + json_integer(data->variation)); + break; + } + case DNP3_OBJECT_CODE(83, 1): { + DNP3ObjectG83V1 *data = point->data; + json_object_set_new(js, "data->vendor_code", json_string(data->vendor_code)); + json_object_set_new(js, "object_id", + json_integer(data->object_id)); + json_object_set_new(js, "length", + json_integer(data->length)); + unsigned long data_objects_b64_len = data->length * 2; + uint8_t data_objects_b64[data_objects_b64_len]; + Base64Encode(data->data_objects, data->length, + data_objects_b64, &data_objects_b64_len); + json_object_set_new(js, "data->data_objects", + json_string((char *)data_objects_b64)); + break; + } + case DNP3_OBJECT_CODE(86, 2): { + DNP3ObjectG86V2 *data = point->data; + json_object_set_new(js, "rd", + json_integer(data->rd)); + json_object_set_new(js, "wr", + json_integer(data->wr)); + json_object_set_new(js, "st", + json_integer(data->st)); + json_object_set_new(js, "ev", + json_integer(data->ev)); + json_object_set_new(js, "df", + json_integer(data->df)); + json_object_set_new(js, "padding0", + json_integer(data->padding0)); + json_object_set_new(js, "padding1", + json_integer(data->padding1)); + json_object_set_new(js, "padding2", + json_integer(data->padding2)); + break; + } + case DNP3_OBJECT_CODE(102, 1): { + DNP3ObjectG102V1 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(120, 1): { + DNP3ObjectG120V1 *data = point->data; + json_object_set_new(js, "csq", + json_integer(data->csq)); + json_object_set_new(js, "usr", + json_integer(data->usr)); + json_object_set_new(js, "mal", + json_integer(data->mal)); + json_object_set_new(js, "reason", + json_integer(data->reason)); + unsigned long challenge_data_b64_len = data->challenge_data_len * 2; + uint8_t challenge_data_b64[challenge_data_b64_len]; + Base64Encode(data->challenge_data, data->challenge_data_len, + challenge_data_b64, &challenge_data_b64_len); + json_object_set_new(js, "data->challenge_data", + json_string((char *)challenge_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 2): { + DNP3ObjectG120V2 *data = point->data; + json_object_set_new(js, "csq", + json_integer(data->csq)); + json_object_set_new(js, "usr", + json_integer(data->usr)); + unsigned long mac_value_b64_len = data->mac_value_len * 2; + uint8_t mac_value_b64[mac_value_b64_len]; + Base64Encode(data->mac_value, data->mac_value_len, + mac_value_b64, &mac_value_b64_len); + json_object_set_new(js, "data->mac_value", + json_string((char *)mac_value_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 3): { + DNP3ObjectG120V3 *data = point->data; + json_object_set_new(js, "csq", + json_integer(data->csq)); + json_object_set_new(js, "user_number", + json_integer(data->user_number)); + break; + } + case DNP3_OBJECT_CODE(120, 4): { + DNP3ObjectG120V4 *data = point->data; + json_object_set_new(js, "user_number", + json_integer(data->user_number)); + break; + } + case DNP3_OBJECT_CODE(120, 5): { + DNP3ObjectG120V5 *data = point->data; + json_object_set_new(js, "ksq", + json_integer(data->ksq)); + json_object_set_new(js, "user_number", + json_integer(data->user_number)); + json_object_set_new(js, "key_wrap_alg", + json_integer(data->key_wrap_alg)); + json_object_set_new(js, "key_status", + json_integer(data->key_status)); + json_object_set_new(js, "mal", + json_integer(data->mal)); + json_object_set_new(js, "challenge_data_len", + json_integer(data->challenge_data_len)); + unsigned long challenge_data_b64_len = data->challenge_data_len * 2; + uint8_t challenge_data_b64[challenge_data_b64_len]; + Base64Encode(data->challenge_data, data->challenge_data_len, + challenge_data_b64, &challenge_data_b64_len); + json_object_set_new(js, "data->challenge_data", + json_string((char *)challenge_data_b64)); + unsigned long mac_value_b64_len = data->mac_value_len * 2; + uint8_t mac_value_b64[mac_value_b64_len]; + Base64Encode(data->mac_value, data->mac_value_len, + mac_value_b64, &mac_value_b64_len); + json_object_set_new(js, "data->mac_value", + json_string((char *)mac_value_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 6): { + DNP3ObjectG120V6 *data = point->data; + json_object_set_new(js, "ksq", + json_integer(data->ksq)); + json_object_set_new(js, "usr", + json_integer(data->usr)); + unsigned long wrapped_key_data_b64_len = data->wrapped_key_data_len * 2; + uint8_t wrapped_key_data_b64[wrapped_key_data_b64_len]; + Base64Encode(data->wrapped_key_data, data->wrapped_key_data_len, + wrapped_key_data_b64, &wrapped_key_data_b64_len); + json_object_set_new(js, "data->wrapped_key_data", + json_string((char *)wrapped_key_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 7): { + DNP3ObjectG120V7 *data = point->data; + json_object_set_new(js, "sequence_number", + json_integer(data->sequence_number)); + json_object_set_new(js, "usr", + json_integer(data->usr)); + json_object_set_new(js, "association_id", + json_integer(data->association_id)); + json_object_set_new(js, "error_code", + json_integer(data->error_code)); + json_object_set_new(js, "time_of_error", + json_integer(data->time_of_error)); + if (data->error_text_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->error_text_len + 1]; + memcpy(tmpbuf, data->error_text, data->error_text_len); + tmpbuf[data->error_text_len] = '\0'; + json_object_set_new(js, "error_text", json_string(tmpbuf)); + } else { + json_object_set_new(js, "error_text", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(120, 8): { + DNP3ObjectG120V8 *data = point->data; + json_object_set_new(js, "key_change_method", + json_integer(data->key_change_method)); + json_object_set_new(js, "certificate_type", + json_integer(data->certificate_type)); + unsigned long certificate_b64_len = data->certificate_len * 2; + uint8_t certificate_b64[certificate_b64_len]; + Base64Encode(data->certificate, data->certificate_len, + certificate_b64, &certificate_b64_len); + json_object_set_new(js, "data->certificate", + json_string((char *)certificate_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 9): { + DNP3ObjectG120V9 *data = point->data; + unsigned long mac_value_b64_len = data->mac_value_len * 2; + uint8_t mac_value_b64[mac_value_b64_len]; + Base64Encode(data->mac_value, data->mac_value_len, + mac_value_b64, &mac_value_b64_len); + json_object_set_new(js, "data->mac_value", + json_string((char *)mac_value_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 10): { + DNP3ObjectG120V10 *data = point->data; + json_object_set_new(js, "key_change_method", + json_integer(data->key_change_method)); + json_object_set_new(js, "operation", + json_integer(data->operation)); + json_object_set_new(js, "scs", + json_integer(data->scs)); + json_object_set_new(js, "user_role", + json_integer(data->user_role)); + json_object_set_new(js, "user_role_expiry_interval", + json_integer(data->user_role_expiry_interval)); + json_object_set_new(js, "username_len", + json_integer(data->username_len)); + json_object_set_new(js, "user_public_key_len", + json_integer(data->user_public_key_len)); + json_object_set_new(js, "certification_data_len", + json_integer(data->certification_data_len)); + if (data->username_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->username_len + 1]; + memcpy(tmpbuf, data->username, data->username_len); + tmpbuf[data->username_len] = '\0'; + json_object_set_new(js, "username", json_string(tmpbuf)); + } else { + json_object_set_new(js, "username", json_string("")); + } + unsigned long user_public_key_b64_len = data->user_public_key_len * 2; + uint8_t user_public_key_b64[user_public_key_b64_len]; + Base64Encode(data->user_public_key, data->user_public_key_len, + user_public_key_b64, &user_public_key_b64_len); + json_object_set_new(js, "data->user_public_key", + json_string((char *)user_public_key_b64)); + unsigned long certification_data_b64_len = data->certification_data_len * 2; + uint8_t certification_data_b64[certification_data_b64_len]; + Base64Encode(data->certification_data, data->certification_data_len, + certification_data_b64, &certification_data_b64_len); + json_object_set_new(js, "data->certification_data", + json_string((char *)certification_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 11): { + DNP3ObjectG120V11 *data = point->data; + json_object_set_new(js, "key_change_method", + json_integer(data->key_change_method)); + json_object_set_new(js, "username_len", + json_integer(data->username_len)); + json_object_set_new(js, "master_challenge_data_len", + json_integer(data->master_challenge_data_len)); + if (data->username_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->username_len + 1]; + memcpy(tmpbuf, data->username, data->username_len); + tmpbuf[data->username_len] = '\0'; + json_object_set_new(js, "username", json_string(tmpbuf)); + } else { + json_object_set_new(js, "username", json_string("")); + } + unsigned long master_challenge_data_b64_len = data->master_challenge_data_len * 2; + uint8_t master_challenge_data_b64[master_challenge_data_b64_len]; + Base64Encode(data->master_challenge_data, data->master_challenge_data_len, + master_challenge_data_b64, &master_challenge_data_b64_len); + json_object_set_new(js, "data->master_challenge_data", + json_string((char *)master_challenge_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 12): { + DNP3ObjectG120V12 *data = point->data; + json_object_set_new(js, "ksq", + json_integer(data->ksq)); + json_object_set_new(js, "user_number", + json_integer(data->user_number)); + json_object_set_new(js, "challenge_data_len", + json_integer(data->challenge_data_len)); + unsigned long challenge_data_b64_len = data->challenge_data_len * 2; + uint8_t challenge_data_b64[challenge_data_b64_len]; + Base64Encode(data->challenge_data, data->challenge_data_len, + challenge_data_b64, &challenge_data_b64_len); + json_object_set_new(js, "data->challenge_data", + json_string((char *)challenge_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 13): { + DNP3ObjectG120V13 *data = point->data; + json_object_set_new(js, "ksq", + json_integer(data->ksq)); + json_object_set_new(js, "user_number", + json_integer(data->user_number)); + json_object_set_new(js, "encrypted_update_key_len", + json_integer(data->encrypted_update_key_len)); + unsigned long encrypted_update_key_data_b64_len = data->encrypted_update_key_len * 2; + uint8_t encrypted_update_key_data_b64[encrypted_update_key_data_b64_len]; + Base64Encode(data->encrypted_update_key_data, data->encrypted_update_key_len, + encrypted_update_key_data_b64, &encrypted_update_key_data_b64_len); + json_object_set_new(js, "data->encrypted_update_key_data", + json_string((char *)encrypted_update_key_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 14): { + DNP3ObjectG120V14 *data = point->data; + unsigned long digital_signature_b64_len = data->digital_signature_len * 2; + uint8_t digital_signature_b64[digital_signature_b64_len]; + Base64Encode(data->digital_signature, data->digital_signature_len, + digital_signature_b64, &digital_signature_b64_len); + json_object_set_new(js, "data->digital_signature", + json_string((char *)digital_signature_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 15): { + DNP3ObjectG120V15 *data = point->data; + unsigned long mac_b64_len = data->mac_len * 2; + uint8_t mac_b64[mac_b64_len]; + Base64Encode(data->mac, data->mac_len, + mac_b64, &mac_b64_len); + json_object_set_new(js, "data->mac", + json_string((char *)mac_b64)); + break; + } + case DNP3_OBJECT_CODE(121, 1): { + DNP3ObjectG121V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "association_id", + json_integer(data->association_id)); + json_object_set_new(js, "count_value", + json_integer(data->count_value)); + break; + } + case DNP3_OBJECT_CODE(122, 1): { + DNP3ObjectG122V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "association_id", + json_integer(data->association_id)); + json_object_set_new(js, "count_value", + json_integer(data->count_value)); + break; + } + case DNP3_OBJECT_CODE(122, 2): { + DNP3ObjectG122V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "association_id", + json_integer(data->association_id)); + json_object_set_new(js, "count_value", + json_integer(data->count_value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + default: + SCLogDebug("Unknown object: %d:%d", object->group, + object->variation); + break; + } + +} + +#endif /* HAVE_LIBJANSSON */ diff --git a/src/output-json-dnp3-objects.h b/src/output-json-dnp3-objects.h new file mode 100644 index 000000000000..6517d0631da1 --- /dev/null +++ b/src/output-json-dnp3-objects.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2016 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. + */ + +#ifndef __OUTPUT_JSON_DNP3_OBJECTS_H__ +#define __OUTPUT_JSON_DNP3_OBJECTS_H__ + +#ifdef HAVE_LIBJANSSON +void OutputJsonDNP3SetItem(json_t *js, DNP3Object *object, + DNP3Point *item); +#endif /* HAVE_LIBJANSSON */ + +#endif /* __OUTPUT_JSON_DNP3_OBJECTS_H__ */ diff --git a/src/output-json-dnp3.c b/src/output-json-dnp3.c new file mode 100644 index 000000000000..34de8c6c2d36 --- /dev/null +++ b/src/output-json-dnp3.c @@ -0,0 +1,446 @@ +/* Copyright (C) 2015 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. + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" +#include "util-buffer.h" +#include "util-crypt.h" +#include "util-debug.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#include "detect-dnp3.h" + +#include "output.h" +#include "output-json.h" +#include "output-json-dnp3-objects.h" + +#ifdef HAVE_LIBJANSSON +#include + +typedef struct LogDNP3FileCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; + uint8_t include_object_data; +} LogDNP3FileCtx; + +typedef struct LogDNP3LogThread_ { + LogDNP3FileCtx *dnp3log_ctx; + uint32_t count; + MemBuffer *buffer; +} LogDNP3LogThread; + +static json_t *JsonDNP3LogLinkControl(uint8_t lc) +{ + json_t *lcjs = json_object(); + if (unlikely(lcjs == NULL)) { + return NULL; + } + + json_object_set_new(lcjs, "dir", json_boolean(DNP3_LINK_DIR(lc))); + json_object_set_new(lcjs, "pri", json_boolean(DNP3_LINK_PRI(lc))); + json_object_set_new(lcjs, "fcb", json_boolean(DNP3_LINK_FCB(lc))); + json_object_set_new(lcjs, "fcv", json_boolean(DNP3_LINK_FCV(lc))); + json_object_set_new(lcjs, "function_code", json_integer(DNP3_LINK_FC(lc))); + + return lcjs; +} + +static json_t *JsonDNP3LogIin(uint16_t iin) +{ + json_t *iinjs = json_object(); + if (unlikely(iinjs == NULL)) { + return NULL; + } + + json_t *indicators = json_array(); + if (unlikely(indicators == NULL)) { + json_decref(iinjs); + return NULL; + } + + if (iin) { + int mapping = 0; + do { + if (iin & DNP3IndicatorsMap[mapping].value) { + json_array_append_new(indicators, + json_string(DNP3IndicatorsMap[mapping].name)); + } + mapping++; + } while (DNP3IndicatorsMap[mapping].name != NULL); + } + json_object_set_new(iinjs, "indicators", indicators); + + return iinjs; +} + +static json_t *JsonDNP3LogApplicationControl(uint8_t ac) +{ + json_t *acjs = json_object(); + if (unlikely(acjs == NULL)) { + return NULL; + } + + json_object_set_new(acjs, "fir", json_boolean(DNP3_APP_FIR(ac))); + json_object_set_new(acjs, "fin", json_boolean(DNP3_APP_FIN(ac))); + json_object_set_new(acjs, "con", json_boolean(DNP3_APP_CON(ac))); + json_object_set_new(acjs, "uns", json_boolean(DNP3_APP_UNS(ac))); + json_object_set_new(acjs, "sequence", json_integer(DNP3_APP_SEQ(ac))); + + return acjs; +} + +/** + * \brief Log the items (points) for an object. + * + * TODO: Autogenerate this function based on object definitions. + */ +static json_t *JsonDNP3LogObjectItems(DNP3Object *object) +{ + DNP3Point *item; + json_t *jsitems; + + if (unlikely((jsitems = json_array()) == NULL)) { + return NULL; + } + + TAILQ_FOREACH(item, object->points, next) { + json_t *js = json_object(); + if (unlikely(js == NULL)) { + break; + } + + json_object_set_new(js, "prefix", json_integer(item->prefix)); + json_object_set_new(js, "index", json_integer(item->index)); + if (DNP3PrefixIsSize(object->prefix_code)) { + json_object_set_new(js, "size", json_integer(item->size)); + } + + OutputJsonDNP3SetItem(js, object, item); + json_array_append_new(jsitems, js); + } + + return jsitems; +} + +/** + * \brief Log the application layer objects. + * + * \param objects A list of DNP3 objects. + * + * \retval a json_t pointer containing the logged DNP3 objects. + */ +static json_t *JsonDNP3LogObjects(DNP3ObjectList *objects) +{ + DNP3Object *object; + json_t *js = json_array(); + if (unlikely(js == NULL)) { + return NULL; + } + + TAILQ_FOREACH(object, objects, next) { + json_t *objs = json_object(); + if (unlikely(objs == NULL)) { + goto error; + } + json_object_set_new(objs, "group", json_integer(object->group)); + json_object_set_new(objs, "variation", + json_integer(object->variation)); + json_object_set_new(objs, "qualifier", json_integer(object->qualifier)); + json_object_set_new(objs, "prefix_code", + json_integer(object->prefix_code)); + json_object_set_new(objs, "range_code", + json_integer(object->range_code)); + json_object_set_new(objs, "start", json_integer(object->start)); + json_object_set_new(objs, "stop", json_integer(object->stop)); + json_object_set_new(objs, "count", json_integer(object->count)); + + if (object->points != NULL && !TAILQ_EMPTY(object->points)) { + json_t *points = JsonDNP3LogObjectItems(object); + if (points != NULL) { + json_object_set_new(objs, "points", points); + } + } + + json_array_append_new(js, objs); + } + + return js; +error: + json_decref(js); + return NULL; +} + +json_t *JsonDNP3LogRequest(DNP3Transaction *dnp3tx) +{ + json_t *dnp3js = json_object(); + if (dnp3js == NULL) { + return NULL;; + } + json_object_set_new(dnp3js, "type", json_string("request")); + + json_t *lcjs = JsonDNP3LogLinkControl(dnp3tx->request_lh.control); + if (lcjs != NULL) { + json_object_set_new(dnp3js, "control", lcjs); + } + + json_object_set_new(dnp3js, "src", json_integer(dnp3tx->request_lh.src)); + json_object_set_new(dnp3js, "dst", json_integer(dnp3tx->request_lh.dst)); + + /* DNP3 application layer. */ + json_t *al = json_object(); + if (al == NULL) { + goto error; + } + json_object_set_new(dnp3js, "application", al); + + json_t *acjs = JsonDNP3LogApplicationControl(dnp3tx->request_ah.control); + if (acjs != NULL) { + json_object_set_new(al, "control", acjs); + } + + json_object_set_new(al, "function_code", + json_integer(dnp3tx->request_ah.function_code)); + + json_t *objects = JsonDNP3LogObjects(&dnp3tx->request_objects); + if (objects != NULL) { + json_object_set_new(al, "objects", objects); + } + json_object_set_new(al, "complete", + json_boolean(dnp3tx->request_complete)); + + return dnp3js; + +error: + json_decref(dnp3js); + return NULL; +} + +json_t *JsonDNP3LogResponse(DNP3Transaction *dnp3tx) +{ + json_t *dnp3js = json_object(); + if (dnp3js == NULL) { + return NULL; + } + if (dnp3tx->response_ah.function_code == DNP3_APP_FC_UNSOLICITED_RESP) { + json_object_set_new(dnp3js, "type", + json_string("unsolicited_response")); + } + else { + json_object_set_new(dnp3js, "type", json_string("response")); + } + + json_t *lcjs = JsonDNP3LogLinkControl(dnp3tx->response_lh.control); + if (lcjs != NULL) { + json_object_set_new(dnp3js, "control", lcjs); + } + + json_object_set_new(dnp3js, "src", json_integer(dnp3tx->response_lh.src)); + json_object_set_new(dnp3js, "dst", json_integer(dnp3tx->response_lh.dst)); + + /* DNP3 application layer. */ + json_t *al = json_object(); + if (al == NULL) { + goto error; + } + json_object_set_new(dnp3js, "application", al); + + json_t *acjs = JsonDNP3LogApplicationControl(dnp3tx->response_ah.control); + if (acjs != NULL) { + json_object_set_new(al, "control", acjs); + } + + json_object_set_new(al, "function_code", + json_integer(dnp3tx->response_ah.function_code)); + + json_t *iinjs = JsonDNP3LogIin(dnp3tx->response_iin.iin1 << 8 | + dnp3tx->response_iin.iin2); + if (iinjs != NULL) { + json_object_set_new(dnp3js, "iin", iinjs); + } + + json_t *objects = JsonDNP3LogObjects(&dnp3tx->response_objects); + if (objects != NULL) { + json_object_set_new(al, "objects", objects); + } + json_object_set_new(al, "complete", + json_boolean(dnp3tx->response_complete)); + + return dnp3js; + +error: + json_decref(dnp3js); + return NULL; +} + +static int JsonDNP3Logger(ThreadVars *tv, void *thread_data, const Packet *p, + Flow *f, void *state, void *vtx, uint64_t tx_id) +{ + SCEnter(); + LogDNP3LogThread *thread = (LogDNP3LogThread *)thread_data; + DNP3Transaction *tx = vtx; + + MemBuffer *buffer = (MemBuffer *)thread->buffer; + + MemBufferReset(buffer); + if (tx->has_request && tx->request_done) { + json_t *js = CreateJSONHeader((Packet *)p, 1, "dnp3"); + if (unlikely(js == NULL)) { + return TM_ECODE_OK; + } + json_t *dnp3js = JsonDNP3LogRequest(tx); + if (dnp3js != NULL) { + json_object_set_new(js, "dnp3", dnp3js); + OutputJSONBuffer(js, thread->dnp3log_ctx->file_ctx, &buffer); + } + json_decref(js); + } + + MemBufferReset(buffer); + if (tx->has_response && tx->response_done) { + json_t *js = CreateJSONHeader((Packet *)p, 1, "dnp3"); + if (unlikely(js == NULL)) { + return TM_ECODE_OK; + } + json_t *dnp3js = JsonDNP3LogResponse(tx); + if (dnp3js != NULL) { + json_object_set_new(js, "dnp3", dnp3js); + OutputJSONBuffer(js, thread->dnp3log_ctx->file_ctx, &buffer); + } + json_decref(js); + } + + SCReturnInt(TM_ECODE_OK); +} + +static void OutputDNP3LogDeInitCtxSub(OutputCtx *output_ctx) +{ + SCLogDebug("cleaning up sub output_ctx %p", output_ctx); + LogDNP3FileCtx *dnp3log_ctx = (LogDNP3FileCtx *)output_ctx->data; + SCFree(dnp3log_ctx); + SCFree(output_ctx); +} + +#define DEFAULT_LOG_FILENAME "dnp3.json" + +static OutputCtx *OutputDNP3LogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AlertJsonThread *ajt = parent_ctx->data; + + LogDNP3FileCtx *dnp3log_ctx = SCCalloc(1, sizeof(*dnp3log_ctx)); + if (unlikely(dnp3log_ctx == NULL)) { + return NULL; + } + dnp3log_ctx->file_ctx = ajt->file_ctx; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(dnp3log_ctx); + return NULL; + } + output_ctx->data = dnp3log_ctx; + output_ctx->DeInit = OutputDNP3LogDeInitCtxSub; + + SCLogInfo("DNP3 log sub-module initialized."); + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNP3); + + return output_ctx; +} + +#define OUTPUT_BUFFER_SIZE 65535 + +static TmEcode JsonDNP3LogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + LogDNP3LogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for DNP3. \"initdata\" is NULL."); + SCFree(thread); + return TM_ECODE_FAILED; + } + + thread->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (unlikely(thread->buffer == NULL)) { + SCFree(thread); + return TM_ECODE_FAILED; + } + + thread->dnp3log_ctx = ((OutputCtx *)initdata)->data; + *data = (void *)thread; + + return TM_ECODE_OK; +} + +static TmEcode JsonDNP3LogThreadDeinit(ThreadVars *t, void *data) +{ + LogDNP3LogThread *thread = (LogDNP3LogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + if (thread->buffer != NULL) { + MemBufferFree(thread->buffer); + } + SCFree(thread); + return TM_ECODE_OK; +} + +void TmModuleJsonDNP3LogRegister(void) +{ + tmm_modules[TMM_JSONDNP3LOG].name = "JsonDNP3Log"; + tmm_modules[TMM_JSONDNP3LOG].ThreadInit = JsonDNP3LogThreadInit; + tmm_modules[TMM_JSONDNP3LOG].ThreadDeinit = JsonDNP3LogThreadDeinit; + tmm_modules[TMM_JSONDNP3LOG].RegisterTests = NULL; + tmm_modules[TMM_JSONDNP3LOG].cap_flags = 0; + tmm_modules[TMM_JSONDNP3LOG].flags = TM_FLAG_LOGAPI_TM; + + /* Register as en eve sub-module. */ + OutputRegisterTxSubModule("eve-log", "JsonDNP3Log", "eve-log.dnp3", + OutputDNP3LogInitSub, ALPROTO_DNP3, JsonDNP3Logger); +} + +#else + +static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) +{ + SCLogInfo("Can't init JSON output - JSON support was disabled during build."); + return TM_ECODE_FAILED; +} + +void TmModuleJsonDNP3LogRegister (void) +{ + tmm_modules[TMM_JSONDNP3LOG].name = "JsonDNP3Log"; + tmm_modules[TMM_JSONDNP3LOG].ThreadInit = OutputJsonThreadInit; +} + +#endif diff --git a/src/output-json-dnp3.h b/src/output-json-dnp3.h new file mode 100644 index 000000000000..da1e0193007e --- /dev/null +++ b/src/output-json-dnp3.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __OUTPUT_JSON_DNP3_H__ +#define __OUTPUT_JSON_DNP3_H__ + +#include "app-layer-dnp3.h" + +#ifdef HAVE_LIBJANSSON +json_t *JsonDNP3LogRequest(DNP3Transaction *); +json_t *JsonDNP3LogResponse(DNP3Transaction *); +#endif /* HAVE_LIBJANSSON */ + +void JsonDNP3LogRegister(void); + +#endif /* __OUTPUT_JSON_DNP3_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 2376decb158f..06bb916b67a7 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -73,7 +73,6 @@ #include "conf.h" #include "conf-yaml-loader.h" - #include "stream-tcp.h" #include "source-nfq.h" @@ -843,6 +842,8 @@ void RegisterAllModules() TmModuleReceiveNFLOGRegister(); TmModuleDecodeNFLOGRegister(); + /* dnp3 */ + TmModuleJsonDNP3LogRegister(); } static TmEcode LoadYamlConfig(SCInstance *suri) From 44a69f63556a99317162aceabed2e95606c89047 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 28 Sep 2015 16:33:48 -0600 Subject: [PATCH 2135/2553] DNP3: Log DNP3 info with DNP3 alert. --- src/output-json-alert.c | 72 +++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index e4836f0a27d0..6d921dd05ded 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -44,6 +44,7 @@ #include "detect-engine-mpm.h" #include "detect-reference.h" #include "app-layer-parser.h" +#include "app-layer-dnp3.h" #include "app-layer-htp.h" #include "app-layer-htp-xff.h" #include "util-classification-config.h" @@ -52,6 +53,7 @@ #include "output.h" #include "output-json.h" +#include "output-json-dnp3.h" #include "output-json-http.h" #include "output-json-tls.h" #include "output-json-ssh.h" @@ -70,20 +72,21 @@ #ifdef HAVE_LIBJANSSON -#define LOG_JSON_PAYLOAD 0x01 -#define LOG_JSON_PACKET 0x02 -#define LOG_JSON_PAYLOAD_BASE64 0x04 -#define LOG_JSON_HTTP 0x08 -#define LOG_JSON_TLS 0x10 -#define LOG_JSON_SSH 0x20 -#define LOG_JSON_SMTP 0x40 -#define LOG_JSON_TAGGED_PACKETS 0x80 +#define LOG_JSON_PAYLOAD 0x001 +#define LOG_JSON_PACKET 0x002 +#define LOG_JSON_PAYLOAD_BASE64 0x004 +#define LOG_JSON_HTTP 0x008 +#define LOG_JSON_TLS 0x010 +#define LOG_JSON_SSH 0x020 +#define LOG_JSON_SMTP 0x040 +#define LOG_JSON_TAGGED_PACKETS 0x080 +#define LOG_JSON_DNP3 0x100 #define JSON_STREAM_BUFFER_SIZE 4096 typedef struct AlertJsonOutputCtx_ { LogFileCtx* file_ctx; - uint8_t flags; + uint16_t flags; uint32_t payload_buffer_size; HttpXFFCfg *xff_cfg; } AlertJsonOutputCtx; @@ -139,6 +142,42 @@ static void AlertJsonSsh(const Flow *f, json_t *js) return; } +static void AlertJsonDnp3(const Flow *f, json_t *js) +{ + DNP3State *dnp3_state = (DNP3State *)FlowGetAppState(f); + json_t *dnp3js = NULL; + if (dnp3_state) { + uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); + DNP3Transaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_DNP3, + dnp3_state, tx_id); + if (tx) { + json_t *dnp3js = json_object(); + if (unlikely(dnp3js == NULL)) { + goto error; + } + if (tx->has_request && tx->request_done) { + json_t *request = JsonDNP3LogRequest(tx); + if (request != NULL) { + json_object_set_new(dnp3js, "request", request); + } + } + if (tx->has_response && tx->response_done) { + json_t *response = JsonDNP3LogResponse(tx); + if (response != NULL) { + json_object_set_new(dnp3js, "response", response); + } + } + json_object_set_new(js, "dnp3", dnp3js); + } + } + + return; +error: + if (dnp3js != NULL) { + json_decref(dnp3js); + } +} + void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js) { char *action = "allowed"; @@ -277,6 +316,15 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } } + if (json_output_ctx->flags & LOG_JSON_DNP3) { + if (p->flow != NULL) { + uint16_t proto = FlowGetAppProtocol(p->flow); + if (proto == ALPROTO_DNP3) { + AlertJsonDnp3(p->flow, js); + } + } + } + /* payload */ if (json_output_ctx->flags & (LOG_JSON_PAYLOAD | LOG_JSON_PAYLOAD_BASE64)) { int stream = (p->proto == IPPROTO_TCP) ? @@ -592,6 +640,7 @@ static void XffSetup(AlertJsonOutputCtx *json_output_ctx, ConfNode *conf) const char *ssh = ConfNodeLookupChildValue(conf, "ssh"); const char *smtp = ConfNodeLookupChildValue(conf, "smtp"); const char *tagged_packets = ConfNodeLookupChildValue(conf, "tagged-packets"); + const char *dnp3 = ConfNodeLookupChildValue(conf, "dnp3"); if (ssh != NULL) { if (ConfValIsTrue(ssh)) { @@ -644,6 +693,11 @@ static void XffSetup(AlertJsonOutputCtx *json_output_ctx, ConfNode *conf) json_output_ctx->flags |= LOG_JSON_TAGGED_PACKETS; } } + if (dnp3 != NULL) { + if (ConfValIsTrue(dnp3)) { + json_output_ctx->flags |= LOG_JSON_DNP3; + } + } json_output_ctx->payload_buffer_size = payload_buffer_size; HttpXFFGetCfg(conf, xff_cfg); From a59f31a99fc775d8962ad11fbfb4cc3413710ffd Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 10 Dec 2015 11:59:48 -0600 Subject: [PATCH 2136/2553] DNP3: Lua detect support. Adds support for access the DNP3 transaction in Lua rules. --- src/Makefile.am | 2 + src/detect-dnp3.c | 10 +- src/detect-lua-extensions.c | 2 + src/detect-lua.c | 10 + src/detect-parse.c | 3 + src/output-json-dnp3.c | 23 +- src/output.c | 4 + src/suricata-common.h | 1 + src/suricata.c | 3 - src/util-lua-dnp3-objects.c | 3542 +++++++++++++++++++++++++++++++++++ src/util-lua-dnp3-objects.h | 24 + src/util-lua-dnp3.c | 201 ++ src/util-lua-dnp3.h | 27 + 13 files changed, 3828 insertions(+), 24 deletions(-) create mode 100644 src/util-lua-dnp3-objects.c create mode 100644 src/util-lua-dnp3-objects.h create mode 100644 src/util-lua-dnp3.c create mode 100644 src/util-lua-dnp3.h diff --git a/src/Makefile.am b/src/Makefile.am index e91786a31488..708ecb7a6250 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -379,6 +379,8 @@ util-logopenfile.h util-logopenfile.c \ util-logopenfile-tile.h util-logopenfile-tile.c \ util-lua.c util-lua.h \ util-lua-common.c util-lua-common.h \ +util-lua-dnp3.c util-lua-dnp3.h \ +util-lua-dnp3-objects.c util-lua-dnp3-objects.h \ util-lua-dns.c util-lua-dns.h \ util-lua-http.c util-lua-http.h \ util-lua-tls.c util-lua-tls.h \ diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index ec210cf5d27d..3abb0cff9497 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -17,12 +17,16 @@ #include "suricata-common.h" +#include "stream.h" + #include "detect.h" #include "detect-parse.h" #include "detect-dnp3.h" #include "detect-engine.h" #include "detect-engine-content-inspection.h" +#include "app-layer-dnp3.h" + /** * The detection struct. */ @@ -213,7 +217,6 @@ static int DetectDNP3FuncSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) if (unlikely(dnp3 == NULL)) { goto error; } - dnp3->detect_type = DNP3_DETECT_TYPE_FC; dnp3->function_code = function_code; sm = SigMatchAlloc(); @@ -301,7 +304,6 @@ static int DetectDNP3IndSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) if (unlikely(detect == NULL)) { goto error; } - detect->detect_type = DNP3_DETECT_TYPE_IND; detect->ind_flags = flags; sm = SigMatchAlloc(); @@ -384,7 +386,6 @@ static int DetectDNP3ObjSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) if (unlikely(detect == NULL)) { goto fail; } - detect->detect_type = DNP3_DETECT_TYPE_OBJ; detect->obj_group = group; detect->obj_variation = variation; @@ -489,6 +490,7 @@ static void DetectDNP3FuncRegister(void) sigmatch_table[DETECT_AL_DNP3FUNC].alias = "dnp3_func"; sigmatch_table[DETECT_AL_DNP3FUNC].Match = NULL; sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerTxMatch = DetectDNP3FuncMatch; sigmatch_table[DETECT_AL_DNP3FUNC].Setup = DetectDNP3FuncSetup; sigmatch_table[DETECT_AL_DNP3FUNC].Free = DetectDNP3Free; sigmatch_table[DETECT_AL_DNP3FUNC].RegisterTests = @@ -505,6 +507,7 @@ static void DetectDNP3IndRegister(void) sigmatch_table[DETECT_AL_DNP3IND].alias = "dnp3_ind"; sigmatch_table[DETECT_AL_DNP3IND].Match = NULL; sigmatch_table[DETECT_AL_DNP3IND].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_DNP3IND].AppLayerTxMatch = DetectDNP3IndMatch; sigmatch_table[DETECT_AL_DNP3IND].Setup = DetectDNP3IndSetup; sigmatch_table[DETECT_AL_DNP3IND].Free = DetectDNP3Free; sigmatch_table[DETECT_AL_DNP3IND].RegisterTests = @@ -521,6 +524,7 @@ static void DetectDNP3ObjRegister(void) sigmatch_table[DETECT_AL_DNP3OBJ].alias = "dnp3_obj"; sigmatch_table[DETECT_AL_DNP3OBJ].Match = NULL; sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerTxMatch = DetectDNP3ObjMatch; sigmatch_table[DETECT_AL_DNP3OBJ].Setup = DetectDNP3ObjSetup; sigmatch_table[DETECT_AL_DNP3OBJ].Free = DetectDNP3Free; sigmatch_table[DETECT_AL_DNP3OBJ].RegisterTests = diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index 6bd5c2453bce..7825967f6947 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -69,6 +69,7 @@ #include "util-lua-tls.h" #include "util-lua-ssh.h" #include "util-lua-smtp.h" +#include "util-lua-dnp3.h" static const char luaext_key_ld[] = "suricata:luajitdata"; static const char luaext_key_det_ctx[] = "suricata:det_ctx"; @@ -580,6 +581,7 @@ int LuaRegisterExtensions(lua_State *lua_state) LuaRegisterTlsFunctions(lua_state); LuaRegisterSshFunctions(lua_state); LuaRegisterSmtpFunctions(lua_state); + LuaRegisterDNP3Functions(lua_state); return 0; } diff --git a/src/detect-lua.c b/src/detect-lua.c index ab044347393e..d77ee4edd531 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -168,6 +168,8 @@ void DetectLuaRegister(void) #define DATATYPE_SSH (1<<19) #define DATATYPE_SMTP (1<<20) +#define DATATYPE_DNP3 (1<<20) + #ifdef HAVE_LUAJIT static void *LuaStatePoolAlloc(void) { @@ -1023,6 +1025,12 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) ld->flags |= DATATYPE_SMTP; + } else if (strncmp(k, "dnp3", 4) == 0 && strcmp(v, "true") == 0) { + + ld->alproto = ALPROTO_DNP3; + + ld->flags |= DATATYPE_DNP3; + } else { SCLogError(SC_ERR_LUA_ERROR, "unsupported data type %s", k); goto error; @@ -1124,6 +1132,8 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); } else if (luajit->alproto == ALPROTO_SMTP) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + } else if (luajit->alproto == ALPROTO_DNP3) { + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNP3_MATCH); } else { SCLogError(SC_ERR_LUA_ERROR, "luajit can't be used with protocol %s", AppLayerGetProtoName(luajit->alproto)); diff --git a/src/detect-parse.c b/src/detect-parse.c index 168c12ca8206..1af519b090bd 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1604,6 +1604,9 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (sig->sm_lists[DETECT_SM_LIST_DNP3_DATA_MATCH]) { sig->flags |= SIG_FLAG_STATE_MATCH; } + if (sig->sm_lists[DETECT_SM_LIST_DNP3_MATCH]) { + sig->flags |= SIG_FLAG_STATE_MATCH; + } /* Template. */ if (sig->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH]) { diff --git a/src/output-json-dnp3.c b/src/output-json-dnp3.c index 34de8c6c2d36..1ea1c3df8756 100644 --- a/src/output-json-dnp3.c +++ b/src/output-json-dnp3.c @@ -415,32 +415,19 @@ static TmEcode JsonDNP3LogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleJsonDNP3LogRegister(void) +void JsonDNP3LogRegister(void) { - tmm_modules[TMM_JSONDNP3LOG].name = "JsonDNP3Log"; - tmm_modules[TMM_JSONDNP3LOG].ThreadInit = JsonDNP3LogThreadInit; - tmm_modules[TMM_JSONDNP3LOG].ThreadDeinit = JsonDNP3LogThreadDeinit; - tmm_modules[TMM_JSONDNP3LOG].RegisterTests = NULL; - tmm_modules[TMM_JSONDNP3LOG].cap_flags = 0; - tmm_modules[TMM_JSONDNP3LOG].flags = TM_FLAG_LOGAPI_TM; - /* Register as en eve sub-module. */ - OutputRegisterTxSubModule("eve-log", "JsonDNP3Log", "eve-log.dnp3", - OutputDNP3LogInitSub, ALPROTO_DNP3, JsonDNP3Logger); + OutputRegisterTxSubModule(LOGGER_JSON_DNP3, "eve-log", "JsonDNP3Log", + "eve-log.dnp3", OutputDNP3LogInitSub, ALPROTO_DNP3, JsonDNP3Logger, + JsonDNP3LogThreadInit, JsonDNP3LogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) +void JsonDNP3LogRegister (void) { SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -void TmModuleJsonDNP3LogRegister (void) -{ - tmm_modules[TMM_JSONDNP3LOG].name = "JsonDNP3Log"; - tmm_modules[TMM_JSONDNP3LOG].ThreadInit = OutputJsonThreadInit; } #endif diff --git a/src/output.c b/src/output.c index e53ffec24db7..befdc58d2a37 100644 --- a/src/output.c +++ b/src/output.c @@ -69,6 +69,7 @@ #include "output-json.h" #include "output-json-template.h" #include "output-lua.h" +#include "output-json-dnp3.h" typedef struct RootLogger_ { ThreadInitFunc ThreadInit; @@ -1087,6 +1088,9 @@ void OutputRegisterLoggers(void) /* json stats */ JsonStatsLogRegister(); + /* DNP3. */ + JsonDNP3LogRegister(); + /* Template JSON logger. */ JsonTemplateLogRegister(); } diff --git a/src/suricata-common.h b/src/suricata-common.h index 9dda1f3ca21b..a2c9414a1603 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -361,6 +361,7 @@ typedef enum { LOGGER_JSON_STATS, LOGGER_PRELUDE, LOGGER_PCAP, + LOGGER_JSON_DNP3, LOGGER_SIZE, } LoggerId; diff --git a/src/suricata.c b/src/suricata.c index 06bb916b67a7..48125f58330c 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -841,9 +841,6 @@ void RegisterAllModules() /* nflog */ TmModuleReceiveNFLOGRegister(); TmModuleDecodeNFLOGRegister(); - - /* dnp3 */ - TmModuleJsonDNP3LogRegister(); } static TmEcode LoadYamlConfig(SCInstance *suri) diff --git a/src/util-lua-dnp3-objects.c b/src/util-lua-dnp3-objects.c new file mode 100644 index 000000000000..6c3dcc51ab33 --- /dev/null +++ b/src/util-lua-dnp3-objects.c @@ -0,0 +1,3542 @@ +/* Copyright (C) 2015 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. + */ + +/** + * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. + * + * Generated by command: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +#include "suricata-common.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" + +/** + * \brief Push an object point item onto the stack. + */ +void DNP3PushPoint(lua_State *luastate, DNP3Object *object, + DNP3Point *point) +{ + switch (DNP3_OBJECT_CODE(object->group, object->variation)) { + case DNP3_OBJECT_CODE(1, 1): { + DNP3ObjectG1V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(1, 2): { + DNP3ObjectG1V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(2, 1): { + DNP3ObjectG2V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(2, 2): { + DNP3ObjectG2V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(2, 3): { + DNP3ObjectG2V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(3, 1): { + DNP3ObjectG3V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(3, 2): { + DNP3ObjectG3V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(4, 1): { + DNP3ObjectG4V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(4, 2): { + DNP3ObjectG4V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(4, 3): { + DNP3ObjectG4V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "relative_time_ms"); + lua_pushinteger(luastate, data->relative_time_ms); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(10, 1): { + DNP3ObjectG10V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(10, 2): { + DNP3ObjectG10V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(11, 1): { + DNP3ObjectG11V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(11, 2): { + DNP3ObjectG11V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(12, 1): { + DNP3ObjectG12V1 *data = point->data; + lua_pushliteral(luastate, "op_type"); + lua_pushinteger(luastate, data->op_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "qu"); + lua_pushinteger(luastate, data->qu); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "cr"); + lua_pushinteger(luastate, data->cr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "tcc"); + lua_pushinteger(luastate, data->tcc); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "ontime"); + lua_pushinteger(luastate, data->ontime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "offtime"); + lua_pushinteger(luastate, data->offtime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(12, 2): { + DNP3ObjectG12V2 *data = point->data; + lua_pushliteral(luastate, "op_type"); + lua_pushinteger(luastate, data->op_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "qu"); + lua_pushinteger(luastate, data->qu); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "cr"); + lua_pushinteger(luastate, data->cr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "tcc"); + lua_pushinteger(luastate, data->tcc); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "ontime"); + lua_pushinteger(luastate, data->ontime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "offtime"); + lua_pushinteger(luastate, data->offtime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(12, 3): { + DNP3ObjectG12V3 *data = point->data; + lua_pushliteral(luastate, "point"); + lua_pushinteger(luastate, data->point); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(13, 1): { + DNP3ObjectG13V1 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_state"); + lua_pushinteger(luastate, data->commanded_state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(13, 2): { + DNP3ObjectG13V2 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_state"); + lua_pushinteger(luastate, data->commanded_state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 1): { + DNP3ObjectG20V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 2): { + DNP3ObjectG20V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 3): { + DNP3ObjectG20V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 4): { + DNP3ObjectG20V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 5): { + DNP3ObjectG20V5 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 6): { + DNP3ObjectG20V6 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 7): { + DNP3ObjectG20V7 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 8): { + DNP3ObjectG20V8 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 1): { + DNP3ObjectG21V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 2): { + DNP3ObjectG21V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 3): { + DNP3ObjectG21V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 4): { + DNP3ObjectG21V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 5): { + DNP3ObjectG21V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 6): { + DNP3ObjectG21V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 7): { + DNP3ObjectG21V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 8): { + DNP3ObjectG21V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 9): { + DNP3ObjectG21V9 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 10): { + DNP3ObjectG21V10 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 11): { + DNP3ObjectG21V11 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 12): { + DNP3ObjectG21V12 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 1): { + DNP3ObjectG22V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 2): { + DNP3ObjectG22V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 3): { + DNP3ObjectG22V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 4): { + DNP3ObjectG22V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 5): { + DNP3ObjectG22V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 6): { + DNP3ObjectG22V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 7): { + DNP3ObjectG22V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 8): { + DNP3ObjectG22V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 1): { + DNP3ObjectG23V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 2): { + DNP3ObjectG23V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 3): { + DNP3ObjectG23V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 4): { + DNP3ObjectG23V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 5): { + DNP3ObjectG23V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 6): { + DNP3ObjectG23V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 7): { + DNP3ObjectG23V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 8): { + DNP3ObjectG23V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 1): { + DNP3ObjectG30V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 2): { + DNP3ObjectG30V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 3): { + DNP3ObjectG30V3 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 4): { + DNP3ObjectG30V4 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 5): { + DNP3ObjectG30V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 6): { + DNP3ObjectG30V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 1): { + DNP3ObjectG31V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 2): { + DNP3ObjectG31V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 3): { + DNP3ObjectG31V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 4): { + DNP3ObjectG31V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 5): { + DNP3ObjectG31V5 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 6): { + DNP3ObjectG31V6 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 7): { + DNP3ObjectG31V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 8): { + DNP3ObjectG31V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 1): { + DNP3ObjectG32V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 2): { + DNP3ObjectG32V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 3): { + DNP3ObjectG32V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 4): { + DNP3ObjectG32V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 5): { + DNP3ObjectG32V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 6): { + DNP3ObjectG32V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 7): { + DNP3ObjectG32V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 8): { + DNP3ObjectG32V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 1): { + DNP3ObjectG33V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 2): { + DNP3ObjectG33V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 3): { + DNP3ObjectG33V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 4): { + DNP3ObjectG33V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 5): { + DNP3ObjectG33V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 6): { + DNP3ObjectG33V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 7): { + DNP3ObjectG33V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 8): { + DNP3ObjectG33V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(34, 1): { + DNP3ObjectG34V1 *data = point->data; + lua_pushliteral(luastate, "deadband_value"); + lua_pushinteger(luastate, data->deadband_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(34, 2): { + DNP3ObjectG34V2 *data = point->data; + lua_pushliteral(luastate, "deadband_value"); + lua_pushinteger(luastate, data->deadband_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(34, 3): { + DNP3ObjectG34V3 *data = point->data; + lua_pushliteral(luastate, "deadband_value"); + lua_pushnumber(luastate, data->deadband_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 1): { + DNP3ObjectG40V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 2): { + DNP3ObjectG40V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 3): { + DNP3ObjectG40V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 4): { + DNP3ObjectG40V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 1): { + DNP3ObjectG41V1 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 2): { + DNP3ObjectG41V2 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 3): { + DNP3ObjectG41V3 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 4): { + DNP3ObjectG41V4 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 1): { + DNP3ObjectG42V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 2): { + DNP3ObjectG42V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 3): { + DNP3ObjectG42V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 4): { + DNP3ObjectG42V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 5): { + DNP3ObjectG42V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 6): { + DNP3ObjectG42V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 7): { + DNP3ObjectG42V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 8): { + DNP3ObjectG42V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 1): { + DNP3ObjectG43V1 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 2): { + DNP3ObjectG43V2 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 3): { + DNP3ObjectG43V3 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 4): { + DNP3ObjectG43V4 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 5): { + DNP3ObjectG43V5 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 6): { + DNP3ObjectG43V6 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 7): { + DNP3ObjectG43V7 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 8): { + DNP3ObjectG43V8 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 1): { + DNP3ObjectG50V1 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 2): { + DNP3ObjectG50V2 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "interval"); + lua_pushinteger(luastate, data->interval); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 3): { + DNP3ObjectG50V3 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 4): { + DNP3ObjectG50V4 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "interval_count"); + lua_pushinteger(luastate, data->interval_count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "interval_units"); + lua_pushinteger(luastate, data->interval_units); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(51, 1): { + DNP3ObjectG51V1 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(51, 2): { + DNP3ObjectG51V2 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(52, 1): { + DNP3ObjectG52V1 *data = point->data; + lua_pushliteral(luastate, "delay_secs"); + lua_pushinteger(luastate, data->delay_secs); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(52, 2): { + DNP3ObjectG52V2 *data = point->data; + lua_pushliteral(luastate, "delay_ms"); + lua_pushinteger(luastate, data->delay_ms); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 1): { + DNP3ObjectG70V1 *data = point->data; + lua_pushliteral(luastate, "filename_size"); + lua_pushinteger(luastate, data->filename_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filetype_code"); + lua_pushinteger(luastate, data->filetype_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "attribute_code"); + lua_pushinteger(luastate, data->attribute_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "start_record"); + lua_pushinteger(luastate, data->start_record); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "end_record"); + lua_pushinteger(luastate, data->end_record); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "created_timestamp"); + lua_pushinteger(luastate, data->created_timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "permission"); + lua_pushinteger(luastate, data->permission); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_id"); + lua_pushinteger(luastate, data->file_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "owner_id"); + lua_pushinteger(luastate, data->owner_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "group_id"); + lua_pushinteger(luastate, data->group_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_function_code"); + lua_pushinteger(luastate, data->file_function_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename"); + LuaPushStringBuffer(luastate, (uint8_t *)data->filename, + strlen(data->filename)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "data_size"); + lua_pushinteger(luastate, data->data_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "data"); + LuaPushStringBuffer(luastate, (uint8_t *)data->data, + strlen(data->data)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 2): { + DNP3ObjectG70V2 *data = point->data; + lua_pushliteral(luastate, "username_offset"); + lua_pushinteger(luastate, data->username_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username_size"); + lua_pushinteger(luastate, data->username_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "password_offset"); + lua_pushinteger(luastate, data->password_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "password_size"); + lua_pushinteger(luastate, data->password_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "authentication_key"); + lua_pushinteger(luastate, data->authentication_key); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username"); + LuaPushStringBuffer(luastate, (uint8_t *)data->username, + strlen(data->username)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "password"); + LuaPushStringBuffer(luastate, (uint8_t *)data->password, + strlen(data->password)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 3): { + DNP3ObjectG70V3 *data = point->data; + lua_pushliteral(luastate, "filename_offset"); + lua_pushinteger(luastate, data->filename_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename_size"); + lua_pushinteger(luastate, data->filename_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "created"); + lua_pushinteger(luastate, data->created); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "permissions"); + lua_pushinteger(luastate, data->permissions); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "authentication_key"); + lua_pushinteger(luastate, data->authentication_key); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "operational_mode"); + lua_pushinteger(luastate, data->operational_mode); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "maximum_block_size"); + lua_pushinteger(luastate, data->maximum_block_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "request_id"); + lua_pushinteger(luastate, data->request_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename"); + LuaPushStringBuffer(luastate, (uint8_t *)data->filename, + strlen(data->filename)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 4): { + DNP3ObjectG70V4 *data = point->data; + lua_pushliteral(luastate, "file_handle"); + lua_pushinteger(luastate, data->file_handle); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "maximum_block_size"); + lua_pushinteger(luastate, data->maximum_block_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "request_id"); + lua_pushinteger(luastate, data->request_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "optional_text"); + LuaPushStringBuffer(luastate, (uint8_t *)data->optional_text, + strlen(data->optional_text)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 5): { + DNP3ObjectG70V5 *data = point->data; + lua_pushliteral(luastate, "file_handle"); + lua_pushinteger(luastate, data->file_handle); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "block_number"); + lua_pushinteger(luastate, data->block_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_data"); + LuaPushStringBuffer(luastate, (uint8_t *)data->file_data, + strlen(data->file_data)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 6): { + DNP3ObjectG70V6 *data = point->data; + lua_pushliteral(luastate, "file_handle"); + lua_pushinteger(luastate, data->file_handle); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "block_number"); + lua_pushinteger(luastate, data->block_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "optional_text"); + LuaPushStringBuffer(luastate, (uint8_t *)data->optional_text, + strlen(data->optional_text)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 7): { + DNP3ObjectG70V7 *data = point->data; + lua_pushliteral(luastate, "filename_offset"); + lua_pushinteger(luastate, data->filename_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename_size"); + lua_pushinteger(luastate, data->filename_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_type"); + lua_pushinteger(luastate, data->file_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "created_timestamp"); + lua_pushinteger(luastate, data->created_timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "permissions"); + lua_pushinteger(luastate, data->permissions); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "request_id"); + lua_pushinteger(luastate, data->request_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename"); + LuaPushStringBuffer(luastate, (uint8_t *)data->filename, + strlen(data->filename)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 8): { + DNP3ObjectG70V8 *data = point->data; + lua_pushliteral(luastate, "file_specification"); + LuaPushStringBuffer(luastate, (uint8_t *)data->file_specification, + strlen(data->file_specification)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(80, 1): { + DNP3ObjectG80V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(81, 1): { + DNP3ObjectG81V1 *data = point->data; + lua_pushliteral(luastate, "fill_percentage"); + lua_pushinteger(luastate, data->fill_percentage); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "overflow_state"); + lua_pushinteger(luastate, data->overflow_state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "group"); + lua_pushinteger(luastate, data->group); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "variation"); + lua_pushinteger(luastate, data->variation); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(83, 1): { + DNP3ObjectG83V1 *data = point->data; + lua_pushliteral(luastate, "vendor_code"); + LuaPushStringBuffer(luastate, (uint8_t *)data->vendor_code, + strlen(data->vendor_code)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "object_id"); + lua_pushinteger(luastate, data->object_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "length"); + lua_pushinteger(luastate, data->length); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "data_objects"); + lua_pushlstring(luastate, (const char *)data->data_objects, + data->length); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(86, 2): { + DNP3ObjectG86V2 *data = point->data; + lua_pushliteral(luastate, "rd"); + lua_pushinteger(luastate, data->rd); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "wr"); + lua_pushinteger(luastate, data->wr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "st"); + lua_pushinteger(luastate, data->st); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "ev"); + lua_pushinteger(luastate, data->ev); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "df"); + lua_pushinteger(luastate, data->df); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "padding0"); + lua_pushinteger(luastate, data->padding0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "padding1"); + lua_pushinteger(luastate, data->padding1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "padding2"); + lua_pushinteger(luastate, data->padding2); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(102, 1): { + DNP3ObjectG102V1 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 1): { + DNP3ObjectG120V1 *data = point->data; + lua_pushliteral(luastate, "csq"); + lua_pushinteger(luastate, data->csq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mal"); + lua_pushinteger(luastate, data->mal); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reason"); + lua_pushinteger(luastate, data->reason); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data"); + lua_pushlstring(luastate, (const char *)data->challenge_data, + data->challenge_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 2): { + DNP3ObjectG120V2 *data = point->data; + lua_pushliteral(luastate, "csq"); + lua_pushinteger(luastate, data->csq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mac_value"); + lua_pushlstring(luastate, (const char *)data->mac_value, + data->mac_value_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 3): { + DNP3ObjectG120V3 *data = point->data; + lua_pushliteral(luastate, "csq"); + lua_pushinteger(luastate, data->csq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 4): { + DNP3ObjectG120V4 *data = point->data; + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 5): { + DNP3ObjectG120V5 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "key_wrap_alg"); + lua_pushinteger(luastate, data->key_wrap_alg); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "key_status"); + lua_pushinteger(luastate, data->key_status); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mal"); + lua_pushinteger(luastate, data->mal); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data_len"); + lua_pushinteger(luastate, data->challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data"); + lua_pushlstring(luastate, (const char *)data->challenge_data, + data->challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mac_value"); + lua_pushlstring(luastate, (const char *)data->mac_value, + data->mac_value_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 6): { + DNP3ObjectG120V6 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "wrapped_key_data"); + lua_pushlstring(luastate, (const char *)data->wrapped_key_data, + data->wrapped_key_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 7): { + DNP3ObjectG120V7 *data = point->data; + lua_pushliteral(luastate, "sequence_number"); + lua_pushinteger(luastate, data->sequence_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "error_code"); + lua_pushinteger(luastate, data->error_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "time_of_error"); + lua_pushinteger(luastate, data->time_of_error); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "error_text"); + LuaPushStringBuffer(luastate, (uint8_t *)data->error_text, + strlen(data->error_text)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 8): { + DNP3ObjectG120V8 *data = point->data; + lua_pushliteral(luastate, "key_change_method"); + lua_pushinteger(luastate, data->key_change_method); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certificate_type"); + lua_pushinteger(luastate, data->certificate_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certificate"); + lua_pushlstring(luastate, (const char *)data->certificate, + data->certificate_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 9): { + DNP3ObjectG120V9 *data = point->data; + lua_pushliteral(luastate, "mac_value"); + lua_pushlstring(luastate, (const char *)data->mac_value, + data->mac_value_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 10): { + DNP3ObjectG120V10 *data = point->data; + lua_pushliteral(luastate, "key_change_method"); + lua_pushinteger(luastate, data->key_change_method); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "operation"); + lua_pushinteger(luastate, data->operation); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "scs"); + lua_pushinteger(luastate, data->scs); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_role"); + lua_pushinteger(luastate, data->user_role); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_role_expiry_interval"); + lua_pushinteger(luastate, data->user_role_expiry_interval); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username_len"); + lua_pushinteger(luastate, data->username_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_public_key_len"); + lua_pushinteger(luastate, data->user_public_key_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certification_data_len"); + lua_pushinteger(luastate, data->certification_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username"); + LuaPushStringBuffer(luastate, (uint8_t *)data->username, + strlen(data->username)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_public_key"); + lua_pushlstring(luastate, (const char *)data->user_public_key, + data->user_public_key_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certification_data"); + lua_pushlstring(luastate, (const char *)data->certification_data, + data->certification_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 11): { + DNP3ObjectG120V11 *data = point->data; + lua_pushliteral(luastate, "key_change_method"); + lua_pushinteger(luastate, data->key_change_method); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username_len"); + lua_pushinteger(luastate, data->username_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "master_challenge_data_len"); + lua_pushinteger(luastate, data->master_challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username"); + LuaPushStringBuffer(luastate, (uint8_t *)data->username, + strlen(data->username)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "master_challenge_data"); + lua_pushlstring(luastate, (const char *)data->master_challenge_data, + data->master_challenge_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 12): { + DNP3ObjectG120V12 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data_len"); + lua_pushinteger(luastate, data->challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data"); + lua_pushlstring(luastate, (const char *)data->challenge_data, + data->challenge_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 13): { + DNP3ObjectG120V13 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "encrypted_update_key_len"); + lua_pushinteger(luastate, data->encrypted_update_key_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "encrypted_update_key_data"); + lua_pushlstring(luastate, (const char *)data->encrypted_update_key_data, + data->encrypted_update_key_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 14): { + DNP3ObjectG120V14 *data = point->data; + lua_pushliteral(luastate, "digital_signature"); + lua_pushlstring(luastate, (const char *)data->digital_signature, + data->digital_signature_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 15): { + DNP3ObjectG120V15 *data = point->data; + lua_pushliteral(luastate, "mac"); + lua_pushlstring(luastate, (const char *)data->mac, + data->mac_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(121, 1): { + DNP3ObjectG121V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count_value"); + lua_pushinteger(luastate, data->count_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(122, 1): { + DNP3ObjectG122V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count_value"); + lua_pushinteger(luastate, data->count_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(122, 2): { + DNP3ObjectG122V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count_value"); + lua_pushinteger(luastate, data->count_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + default: + break; + } +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-dnp3-objects.h b/src/util-lua-dnp3-objects.h new file mode 100644 index 000000000000..6575695a2650 --- /dev/null +++ b/src/util-lua-dnp3-objects.h @@ -0,0 +1,24 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __UTIL_LUA_DNP3_OBJECTS_H__ +#define __UTIL_LUA_DNP3_OBJECTS_H__ + +void DNP3PushPoint(lua_State *luastate, DNP3Object *object, + DNP3Point *item); + +#endif /* ! __UTIL_LUA_DNP3_OBJECTS_H__ */ diff --git a/src/util-lua-dnp3.c b/src/util-lua-dnp3.c new file mode 100644 index 000000000000..96b7a5ea6b0f --- /dev/null +++ b/src/util-lua-dnp3.c @@ -0,0 +1,201 @@ +/* Copyright (C) 2015 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. + */ + +#include "suricata-common.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" +#include "util-lua-common.h" +#include "util-lua-dnp3-objects.h" + +/** + * \brief Helper macro to push key and integer value onto a table. + */ +#define LUA_PUSHT_INT(l, k, v) do { \ + lua_pushliteral(luastate, k); \ + lua_pushinteger(luastate, v); \ + lua_settable(luastate, -3); \ + } while (0); + +static void DNP3PushPoints(lua_State *luastate, DNP3Object *object) +{ + DNP3Point *point; + int i = 1; + + TAILQ_FOREACH(point, object->points, next) { + lua_pushinteger(luastate, i++); + lua_newtable(luastate); + + lua_pushliteral(luastate, "index"); + lua_pushinteger(luastate, point->index); + lua_settable(luastate, -3); + + DNP3PushPoint(luastate, object, point); + + lua_settable(luastate, -3); + } +} + +static void DNP3PushObjects(lua_State *luastate, DNP3ObjectList *objects) +{ + DNP3Object *object = NULL; + int i = 1; + + TAILQ_FOREACH(object, objects, next) { + lua_pushinteger(luastate, i++); + lua_newtable(luastate); + + lua_pushliteral(luastate, "group"); + lua_pushinteger(luastate, object->group); + lua_settable(luastate, -3); + + lua_pushliteral(luastate, "variation"); + lua_pushinteger(luastate, object->variation); + lua_settable(luastate, -3); + + lua_pushliteral(luastate, "points"); + lua_newtable(luastate); + DNP3PushPoints(luastate, object); + lua_settable(luastate, -3); + + lua_settable(luastate, -3); + } +} + +static void DNP3PushLinkHeader(lua_State *luastate, DNP3LinkHeader *header) +{ + LUA_PUSHT_INT(luastate, "len", header->len); + LUA_PUSHT_INT(luastate, "control", header->control); + LUA_PUSHT_INT(luastate, "dst", header->dst); + LUA_PUSHT_INT(luastate, "src", header->src); + LUA_PUSHT_INT(luastate, "crc", header->crc); +} + +static void DNP3PushApplicationHeader(lua_State *luastate, + DNP3ApplicationHeader *header) +{ + LUA_PUSHT_INT(luastate, "control", header->control); + LUA_PUSHT_INT(luastate, "function_code", header->function_code); +} + +static void DNP3PushRequest(lua_State *luastate, DNP3Transaction *tx) +{ + /* Link header. */ + lua_pushliteral(luastate, "link_header"); + lua_newtable(luastate); + DNP3PushLinkHeader(luastate, &tx->request_lh); + lua_settable(luastate, -3); + + /* Transport header. */ + LUA_PUSHT_INT(luastate, "transport_header", tx->request_th); + + /* Application header. */ + lua_pushliteral(luastate, "application_header"); + lua_newtable(luastate); + DNP3PushApplicationHeader(luastate, &tx->request_ah); + lua_settable(luastate, -3); + + lua_pushliteral(luastate, "objects"); + lua_newtable(luastate); + DNP3PushObjects(luastate, &tx->request_objects); + lua_settable(luastate, -3); +} + +static void DNP3PushResponse(lua_State *luastate, DNP3Transaction *tx) +{ + /* Link header. */ + lua_pushliteral(luastate, "link_header"); + lua_newtable(luastate); + DNP3PushLinkHeader(luastate, &tx->response_lh); + lua_settable(luastate, -3); + + /* Transport header. */ + LUA_PUSHT_INT(luastate, "transport_header", tx->response_th); + + /* Application header. */ + lua_pushliteral(luastate, "application_header"); + lua_newtable(luastate); + DNP3PushApplicationHeader(luastate, &tx->response_ah); + lua_settable(luastate, -3); + + /* Internal indicators. */ + LUA_PUSHT_INT(luastate, "indicators", + tx->response_iin.iin1 << 8 | tx->response_iin.iin2); + + lua_pushliteral(luastate, "objects"); + lua_newtable(luastate); + DNP3PushObjects(luastate, &tx->response_objects); + lua_settable(luastate, -3); +} + +static int DNP3GetTx(lua_State *luastate) +{ + if (!LuaStateNeedProto(luastate, ALPROTO_DNP3)) { + return LuaCallbackError(luastate, "error: protocol not dnp3"); + } + + DNP3Transaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) { + return LuaCallbackError(luastate, "error: no tx"); + } + + lua_newtable(luastate); + + lua_pushliteral(luastate, "tx_num"); + lua_pushinteger(luastate, tx->tx_num); + lua_settable(luastate, -3); + + LUA_PUSHT_INT(luastate, "has_request", tx->has_request); + if (tx->has_request) { + lua_pushliteral(luastate, "request"); + lua_newtable(luastate); + LUA_PUSHT_INT(luastate, "done", tx->request_done); + LUA_PUSHT_INT(luastate, "complete", tx->request_complete); + DNP3PushRequest(luastate, tx); + lua_settable(luastate, -3); + } + + LUA_PUSHT_INT(luastate, "has_response", tx->has_response); + if (tx->has_response) { + lua_pushliteral(luastate, "response"); + lua_newtable(luastate); + LUA_PUSHT_INT(luastate, "done", tx->response_done); + LUA_PUSHT_INT(luastate, "complete", tx->response_complete); + DNP3PushResponse(luastate, tx); + lua_settable(luastate, -3); + } + + return 1; +} + +int LuaRegisterDNP3Functions(lua_State *luastate) +{ + lua_pushcfunction(luastate, DNP3GetTx); + lua_setglobal(luastate, "DNP3GetTx"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-dnp3.h b/src/util-lua-dnp3.h new file mode 100644 index 000000000000..3430e41b2205 --- /dev/null +++ b/src/util-lua-dnp3.h @@ -0,0 +1,27 @@ +/* Copyright (C) 2015 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. + */ + +#ifndef __UTIL_LUA_DNP3_H__ +#define __UTIL_LUA_DNP3_H__ + +#ifdef HAVE_LUA + +int LuaRegisterDNP3Functions(lua_State *); + +#endif /* HAVE_LUA */ + +#endif /* !__UTIL_LUA_DNP3_H__ */ From f70badeb0e9a3c9f55023a57abefc9857d2f729f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 15 Apr 2016 16:49:28 -0600 Subject: [PATCH 2137/2553] DNP3: --afl-dnp3 entry point --- src/suricata.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/suricata.c b/src/suricata.c index 48125f58330c..ac228242809b 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -122,6 +122,7 @@ #include "app-layer-smb.h" #include "app-layer-modbus.h" #include "app-layer-enip.h" +#include "app-layer-dnp3.h" #include "util-decode-der.h" #include "util-radix-tree.h" @@ -1140,7 +1141,8 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"netmap", optional_argument, 0, 0}, {"pcap", optional_argument, 0, 0}, {"simulate-ips", 0, 0 , 0}, - {"afl-rules", required_argument, 0 , 0}, + + /* AFL app-layer options. */ {"afl-http-request", required_argument, 0 , 0}, {"afl-http", required_argument, 0 , 0}, {"afl-tls-request", required_argument, 0 , 0}, @@ -1160,9 +1162,15 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"afl-enip-request", required_argument, 0 , 0}, {"afl-enip", required_argument, 0 , 0}, {"afl-mime", required_argument, 0 , 0}, + {"afl-dnp3-request", required_argument, 0, 0}, + {"afl-dnp3", required_argument, 0, 0}, + /* Other AFL options. */ + {"afl-rules", required_argument, 0 , 0}, + {"afl-mime", required_argument, 0 , 0}, {"afl-decoder-ppp", required_argument, 0 , 0}, {"afl-der", required_argument, 0, 0}, + #ifdef BUILD_UNIX_SOCKET {"unix-socket", optional_argument, 0, 0}, #endif @@ -1439,6 +1447,14 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerParserSetup(); RegisterENIPTCPParsers(); exit(AppLayerParserFromFile(ALPROTO_ENIP, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-dnp3-request") == 0) { + AppLayerParserSetup(); + RegisterDNP3Parsers(); + exit(AppLayerParserRequestFromFile(ALPROTO_DNP3, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-dnp3") == 0) { + AppLayerParserSetup(); + RegisterDNP3Parsers(); + exit(AppLayerParserFromFile(ALPROTO_DNP3, optarg)); #endif #ifdef AFLFUZZ_MIME } else if(strcmp((long_opts[option_index]).name, "afl-mime") == 0) { From f0de1d04a9a9eca4eabf74fba0cf9f60f35fbc1f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 13 Jul 2016 09:04:15 -0600 Subject: [PATCH 2138/2553] DNP3: Use directional logging. Instead of waiting for a transaction complete, log the request as soon as it is completes which will give it a more accurate timestamp. --- src/output-json-dnp3.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/output-json-dnp3.c b/src/output-json-dnp3.c index 1ea1c3df8756..e726959d48e9 100644 --- a/src/output-json-dnp3.c +++ b/src/output-json-dnp3.c @@ -300,8 +300,8 @@ json_t *JsonDNP3LogResponse(DNP3Transaction *dnp3tx) return NULL; } -static int JsonDNP3Logger(ThreadVars *tv, void *thread_data, const Packet *p, - Flow *f, void *state, void *vtx, uint64_t tx_id) +static int JsonDNP3LoggerToServer(ThreadVars *tv, void *thread_data, + const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) { SCEnter(); LogDNP3LogThread *thread = (LogDNP3LogThread *)thread_data; @@ -323,6 +323,18 @@ static int JsonDNP3Logger(ThreadVars *tv, void *thread_data, const Packet *p, json_decref(js); } + SCReturnInt(TM_ECODE_OK); +} + +static int JsonDNP3LoggerToClient(ThreadVars *tv, void *thread_data, + const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) +{ + SCEnter(); + LogDNP3LogThread *thread = (LogDNP3LogThread *)thread_data; + DNP3Transaction *tx = vtx; + + MemBuffer *buffer = (MemBuffer *)thread->buffer; + MemBufferReset(buffer); if (tx->has_response && tx->response_done) { json_t *js = CreateJSONHeader((Packet *)p, 1, "dnp3"); @@ -417,17 +429,21 @@ static TmEcode JsonDNP3LogThreadDeinit(ThreadVars *t, void *data) void JsonDNP3LogRegister(void) { - /* Register as en eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_DNP3, "eve-log", "JsonDNP3Log", - "eve-log.dnp3", OutputDNP3LogInitSub, ALPROTO_DNP3, JsonDNP3Logger, - JsonDNP3LogThreadInit, JsonDNP3LogThreadDeinit, NULL); + /* Register direction aware eve sub-modules. */ + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_DNP3, "eve-log", + "JsonDNP3Log", "eve-log.dnp3", OutputDNP3LogInitSub, ALPROTO_DNP3, + JsonDNP3LoggerToServer, 0, 1, JsonDNP3LogThreadInit, + JsonDNP3LogThreadDeinit, NULL); + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_DNP3, "eve-log", + "JsonDNP3Log", "eve-log.dnp3", OutputDNP3LogInitSub, ALPROTO_DNP3, + JsonDNP3LoggerToClient, 1, 1, JsonDNP3LogThreadInit, + JsonDNP3LogThreadDeinit, NULL); } #else void JsonDNP3LogRegister (void) { - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); } #endif From 7cf231c7ecfa96df408825c87dc363a1e3c83bf6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 27 Oct 2016 11:55:17 +0200 Subject: [PATCH 2139/2553] DNP3: don't leak memory on dnp3_obj parsing --- src/detect-dnp3.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 3abb0cff9497..f70c87f7ff20 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -339,35 +339,26 @@ static int DetectDNP3IndSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) */ static int DetectDNP3ObjParse(const char *str, uint8_t *group, uint8_t *var) { - char *groupstr = NULL, *varstr, *sep; - int result = 0; - - groupstr = SCStrdup(str); - if (unlikely(groupstr == NULL)) { - return 0; - } + size_t size = strlen(str) + 1; + char groupstr[size], *varstr, *sep; + strlcpy(groupstr, str, size); sep = strchr(groupstr, ','); if (sep == NULL) { - goto fail; + return 0; } *sep = '\0'; varstr = sep + 1; if (ByteExtractStringUint8(group, 0, strlen(groupstr), groupstr) < 0) { - goto fail; + return 0; } if (ByteExtractStringUint8(var, 0, strlen(varstr), varstr) < 0) { - goto fail; + return 0; } - result = 1; -fail: - if (groupstr == NULL) { - SCFree(groupstr); - } - return result; + return 1; } static int DetectDNP3ObjSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) From 5dc9c1b8748fea884bf83dc376972fac00f4c007 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 27 Oct 2016 11:55:28 +0200 Subject: [PATCH 2140/2553] DNP3: minor cleanup --- src/detect-dnp3.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index f70c87f7ff20..5cdad9565f88 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -186,14 +186,13 @@ static int DetectDNP3FuncParseFunctionCode(char *str, uint8_t *fc) if (ByteExtractStringUint8(fc, 10, strlen(str), str) >= 0) { return 1; } - else { - /* Lookup by name. */ - for (size_t i = 0; - i < sizeof(DNP3FunctionNameMap) / sizeof(DNP3Mapping); i++) { - if (strcasecmp(str, DNP3FunctionNameMap[i].name) == 0) { - *fc = DNP3FunctionNameMap[i].value; - return 1; - } + + /* Lookup by name. */ + for (size_t i = 0; + i < sizeof(DNP3FunctionNameMap) / sizeof(DNP3Mapping); i++) { + if (strcasecmp(str, DNP3FunctionNameMap[i].name) == 0) { + *fc = DNP3FunctionNameMap[i].value; + return 1; } } From 8831e5b375797c07992758c5d7f3c5167c1c4f72 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 27 Oct 2016 14:56:21 +0200 Subject: [PATCH 2141/2553] pkt-var: const name --- src/decode.h | 2 +- src/pkt-var.c | 4 ++-- src/pkt-var.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/decode.h b/src/decode.h index c4b686322cc6..b84f466e0abd 100644 --- a/src/decode.h +++ b/src/decode.h @@ -298,7 +298,7 @@ typedef struct PacketEngineEvents_ { } PacketEngineEvents; typedef struct PktVar_ { - char *name; + const char *name; struct PktVar_ *next; /* right now just implement this as a list, * in the long run we have thing of something * faster. */ diff --git a/src/pkt-var.c b/src/pkt-var.c index b3878bde049a..dcc706959b5d 100644 --- a/src/pkt-var.c +++ b/src/pkt-var.c @@ -45,7 +45,7 @@ void PktVarUpdate(PktVar *pv, uint8_t *value, uint16_t size) /* get the pktvar with name 'name' from the pkt * * name is a normal string*/ -PktVar *PktVarGet(Packet *p, char *name) +PktVar *PktVarGet(Packet *p, const char *name) { PktVar *pv = p->pktvar; @@ -58,7 +58,7 @@ PktVar *PktVarGet(Packet *p, char *name) } /* add a pktvar to the pkt, or update it */ -void PktVarAdd(Packet *p, char *name, uint8_t *value, uint16_t size) +void PktVarAdd(Packet *p, const char *name, uint8_t *value, uint16_t size) { //printf("Adding packet var \"%s\" with value(%" PRId32 ") \"%s\"\n", name, size, value); diff --git a/src/pkt-var.h b/src/pkt-var.h index 0ba875721320..613bd1d7e76f 100644 --- a/src/pkt-var.h +++ b/src/pkt-var.h @@ -24,8 +24,8 @@ #ifndef __PKT_VAR_H__ #define __PKT_VAR_H__ -void PktVarAdd(Packet *, char *, uint8_t *, uint16_t); -PktVar *PktVarGet(Packet *, char *); +void PktVarAdd(Packet *, const char *, uint8_t *, uint16_t); +PktVar *PktVarGet(Packet *, const char *); void PktVarFree(PktVar *); void PktVarPrint(PktVar *); From 56ff853e733235ac0e02284c1843c7bdcc6d45f1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Oct 2016 21:15:44 +0200 Subject: [PATCH 2142/2553] hostbits: test fixes --- src/detect-hostbits.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index c12bc604ed29..5d5863b1b7b7 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -547,8 +547,7 @@ static int HostBitsTestSig01(void) "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -577,19 +576,8 @@ static int HostBitsTestSig01(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); HostBitsTestShutdown(); SCFree(p); @@ -637,8 +625,6 @@ static int HostBitsTestSig02(void) "alert ip any any -> any any (hostbits:toggle,abc,dst; content:\"GET \"; sid:5;)"); FAIL_IF_NULL(s); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); PASS; } From 39a23d8d1b2240ba826dad464e45a1d5b0f2adc5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 28 Oct 2016 12:23:23 +0200 Subject: [PATCH 2143/2553] flowint: allow / in name --- src/detect-flowint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-flowint.c b/src/detect-flowint.c index e8a7a2c7d98e..cdc8851c870f 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -47,7 +47,7 @@ #include "util-profiling.h" /* name modifiers value */ -#define PARSE_REGEX "^\\s*([a-zA-Z][\\w\\d_.]+)\\s*,\\s*([+=-]{1}|==|!=|<|<=|>|>=|isset|notset)\\s*,?\\s*([a-zA-Z][\\w\\d]+|[\\d]{1,10})?\\s*$" +#define PARSE_REGEX "^\\s*([a-zA-Z][\\w\\d_./]+)\\s*,\\s*([+=-]{1}|==|!=|<|<=|>|>=|isset|notset)\\s*,?\\s*([a-zA-Z][\\w\\d]+|[\\d]{1,10})?\\s*$" /* Varnames must begin with a letter */ static pcre *parse_regex; From c0f25bddaf3a5b05d8fc963b37472878eeeb175f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 31 Oct 2016 11:14:41 +0100 Subject: [PATCH 2144/2553] eve: make payload printing in alerts more robust --- src/output-json-alert.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 6d921dd05ded..4fc6cb5a2949 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -368,8 +368,9 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (json_output_ctx->flags & LOG_JSON_PAYLOAD_BASE64) { unsigned long len = p->payload_len * 2 + 1; uint8_t encoded[len]; - Base64Encode(p->payload, p->payload_len, encoded, &len); - json_object_set_new(js, "payload", json_string((char *)encoded)); + if (Base64Encode(p->payload, p->payload_len, encoded, &len) == SC_BASE64_OK) { + json_object_set_new(js, "payload", json_string((char *)encoded)); + } } if (json_output_ctx->flags & LOG_JSON_PAYLOAD) { @@ -378,6 +379,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) PrintStringsToBuffer(printable_buf, &offset, p->payload_len + 1, p->payload, p->payload_len); + printable_buf[p->payload_len] = '\0'; json_object_set_new(js, "payload_printable", json_string((char *)printable_buf)); } } From 1f670837acd702159ce4edb4aac0abd4265758a9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 31 Oct 2016 11:30:26 +0100 Subject: [PATCH 2145/2553] detect: add missing break (CID 1374301) --- src/detect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect.c b/src/detect.c index 458248f4ec19..27047c5c0a02 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2263,6 +2263,7 @@ PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, int has_state case ALPROTO_ENIP: SCLogDebug("packet/flow has enip state"); (*mask) |= SIG_MASK_REQUIRE_ENIP_STATE; + break; case ALPROTO_DNP3: SCLogDebug("packet/flow has dnp3 state"); (*mask) |= SIG_MASK_REQUIRE_DNP3_STATE; From 65bf06975c8efdde3b542f44403e2d253e88d91d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 27 Oct 2016 11:19:05 -0600 Subject: [PATCH 2146/2553] dnp3: fix coverity checks; return value not checked --- src/app-layer-dnp3-objects.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/app-layer-dnp3-objects.c b/src/app-layer-dnp3-objects.c index 275e646b2cb3..48d39b42b01a 100644 --- a/src/app-layer-dnp3-objects.c +++ b/src/app-layer-dnp3-objects.c @@ -318,19 +318,25 @@ static int DNP3ReadPrefix( switch (prefix_len) { case sizeof(uint32_t): - DNP3ReadUint32(buf, len, out); + if (!DNP3ReadUint32(buf, len, out)) { + return 0; + } break; case sizeof(uint16_t): { /* Temp value for strict-aliasing. */ uint16_t val = 0; - DNP3ReadUint16(buf, len, &val); + if (!DNP3ReadUint16(buf, len, &val)) { + return 0; + } *out = val; break; } case sizeof(uint8_t): { /* Temp value for strict-aliasing. */ uint8_t val = 0; - DNP3ReadUint8(buf, len, &val); + if (!DNP3ReadUint8(buf, len, &val)) { + return 0; + } *out = val; break; } From d709bf49e8e494c89ade36a6c743e79b10836e64 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 27 Oct 2016 14:37:56 +0300 Subject: [PATCH 2147/2553] readme: Add link to up-to-date user guide and mark wiki as deprecated. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd4a63d04929..3d60232493a8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,9 @@ https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Instal User Guide ========== -https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_User_Guide +You can follow the [Suricata user guide](http://suricata.readthedocs.io/en/latest/) to get started. + +Our deprecated (but still useful) user guide is also [available](https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_User_Guide). Contributing From 6d9733a72b122c5478c10c2de88bc85379863b8b Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 27 Oct 2016 14:38:28 +0300 Subject: [PATCH 2148/2553] readme: reformat some key points about possible security issues --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d60232493a8..5f8847def34e 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,13 @@ Contributing We're happily taking patches and other contributions. Please see https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Contributing for how to get started. -Suricata is a complex piece of software dealing with mostly untrusted input. Mishandling this input will have serious consequences: in IPS mode a crash may knock a network offline; in passive mode a compromise of the IDS may lead to loss of critical and confidential data; missed detection may lead to undetected compromise of the network. In other words, we think the stakes are pretty high, especially since in many common cases the IDS/IPS will be directly reachable by an attacker. +Suricata is a complex piece of software dealing with mostly untrusted input. Mishandling this input will have serious consequences: + +* in IPS mode a crash may knock a network offline; +* in passive mode a compromise of the IDS may lead to loss of critical and confidential data; +* missed detection may lead to undetected compromise of the network. + +In other words, we think the stakes are pretty high, especially since in many common cases the IDS/IPS will be directly reachable by an attacker. For this reason, we have developed a QA process that is quite extensive. A consequence is that contributing to Suricata can be a somewhat lengthy process. From 12849fa9278298f7347abb5a078cb6f2cac2c609 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 27 Oct 2016 14:41:00 +0300 Subject: [PATCH 2149/2553] readme: Fix markdown header levels --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5f8847def34e..9fc5d03a2256 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,19 @@ -======== Suricata ======== Introduction -============ +------------ Suricata is a network IDS, IPS and NSM engine. Installation -============ +------------ https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Installation User Guide -========== +---------- You can follow the [Suricata user guide](http://suricata.readthedocs.io/en/latest/) to get started. @@ -22,7 +21,7 @@ Our deprecated (but still useful) user guide is also [available](https://redmine Contributing -============ +------------ We're happily taking patches and other contributions. Please see https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Contributing for how to get started. @@ -46,8 +45,7 @@ On a high level, the steps are: -Overview of Suricata's QA steps -------------------------------- +### Overview of Suricata's QA steps Trusted devs and core team members are able to submit builds to our (semi) public Buildbot instance. It will run a series of build tests and a regression suite to confirm no existing features break. @@ -80,8 +78,7 @@ Of course it can happen that after the merge the community will find issues. For -FAQ ---- +### FAQ __Q: Will you accept my PR?__ From 080a2f0cfb159eb0c8ea12bd333a61b3238b93e3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 31 Oct 2016 13:40:19 +0100 Subject: [PATCH 2150/2553] DNP3: disable in case of no dnp3 config --- src/app-layer-dnp3.c | 21 ++++++++------------- src/app-layer-modbus.c | 2 +- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/app-layer-dnp3.c b/src/app-layer-dnp3.c index a2bba227027e..c5cb45480f59 100644 --- a/src/app-layer-dnp3.c +++ b/src/app-layer-dnp3.c @@ -1585,8 +1585,8 @@ void RegisterDNP3Parsers(void) char *proto_name = "dnp3"; - if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { - + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) + { AppLayerProtoDetectRegisterProtocol(ALPROTO_DNP3, proto_name); if (RunmodeIsUnittests()) { @@ -1598,24 +1598,19 @@ void RegisterDNP3Parsers(void) if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), DNP3ProbingParser)) { - SCLogWarning(SC_ERR_DNP3_CONFIG, - "No DNP3 configuration found, enabling DNP3 detection on " - "port " DNP3_DEFAULT_PORT); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, DNP3_DEFAULT_PORT, - ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), STREAM_TOSERVER, - DNP3ProbingParser); + return; } } } else { - SCLogInfo("Protocol detection and parser disabled for DNP3."); + SCLogConfig("Protocol detection and parser disabled for DNP3."); SCReturn; } - if (AppLayerParserConfParserEnabled("tcp", proto_name)) { - - SCLogInfo("Registering DNP3/tcp parsers."); + if (AppLayerParserConfParserEnabled("tcp", proto_name)) + { + SCLogConfig("Registering DNP3/tcp parsers."); AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_DNP3, STREAM_TOSERVER, DNP3ParseRequest); @@ -1649,7 +1644,7 @@ void RegisterDNP3Parsers(void) DNP3GetTxLogged, DNP3SetTxLogged); } else { - SCLogInfo("Parser disabled for protocol %s. " + SCLogConfig("Parser disabled for protocol %s. " "Protocol detection still on.", proto_name); } diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index de09843aa187..ec75e004718e 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1490,7 +1490,7 @@ void RegisterModbusParsers(void) stream_depth = value; } } - SCLogInfo("Modbus stream depth: %u", stream_depth); + SCLogConfig("Modbus stream depth: %u", stream_depth); } else { #ifndef AFLFUZZ_APPLAYER SCLogConfig("Protocol detection and parser disabled for %s protocol.", proto_name); From 238163bc8d3c3b7a60ba677b10c9089638fe7f8f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 31 Oct 2016 13:41:46 +0100 Subject: [PATCH 2151/2553] ENIP: disable parser if no config found --- src/app-layer-enip.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/app-layer-enip.c b/src/app-layer-enip.c index a480d304db87..161d2550fdb9 100644 --- a/src/app-layer-enip.c +++ b/src/app-layer-enip.c @@ -482,15 +482,7 @@ void RegisterENIPTCPParsers(void) proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), ENIPProbingParser)) { - SCLogDebug( - "no ENIP TCP config found enabling ENIP detection on port 44818."); - - AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", - ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, - ENIPProbingParser); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", - ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, - ENIPProbingParser); + return; } } @@ -529,8 +521,7 @@ void RegisterENIPTCPParsers(void) ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT); } else { - SCLogInfo( - "Parsed disabled for %s protocol. Protocol detection" "still on.", + SCLogConfig("Parser disabled for %s protocol. Protocol detection still on.", proto_name); } From b2315589576c1c7f81f803030b96b03e31126943 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 31 Oct 2016 14:10:53 +0100 Subject: [PATCH 2152/2553] ENIP: add default ports to yaml --- suricata.yaml.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/suricata.yaml.in b/suricata.yaml.in index b4cfd843d7eb..c657be3f406e 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -857,6 +857,9 @@ app-layer: # SCADA EtherNet/IP and CIP protocol support enip: enabled: no + detection-ports: + dp: 44818 + sp: 44818 # Limit for the maximum number of asn1 frames to decode (default 256) asn1-max-frames: 256 From 397336316496d89beda4bbd28a58be76c49c5a0d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 31 Oct 2016 14:11:57 +0100 Subject: [PATCH 2153/2553] yaml: group ICS protocols together --- suricata.yaml.in | 54 +++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index c657be3f406e..1a431dc3348f 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -704,32 +704,6 @@ app-layer: enabled: yes detection-ports: dp: 139 - # Note: Modbus probe parser is minimalist due to the poor significant field - # Only Modbus message length (greater than Modbus header length) - # And Protocol ID (equal to 0) are checked in probing parser - # It is important to enable detection port and define Modbus port - # to avoid false positive - modbus: - # How many unreplied Modbus requests are considered a flood. - # If the limit is reached, app-layer-event:modbus.flooded; will match. - #request-flood: 500 - - # Stream reassembly size for modbus. By default track it completely. - stream-depth: 0 - - enabled: no - detection-ports: - dp: 502 - # According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it - # is recommended to keep the TCP connection opened with a remote device - # and not to open and close it for each MODBUS/TCP transaction. In that - # case, it is important to set the depth of the stream reassembling as - # unlimited (stream.reassembly.depth: 0) - # DNP3 - dnp3: - enabled: no - detection-ports: - dp: 20000 # smb2 detection is disabled internally inside the engine. #smb2: # enabled: yes @@ -854,6 +828,34 @@ app-layer: # double-decode-path: no # double-decode-query: no + # Note: Modbus probe parser is minimalist due to the poor significant field + # Only Modbus message length (greater than Modbus header length) + # And Protocol ID (equal to 0) are checked in probing parser + # It is important to enable detection port and define Modbus port + # to avoid false positive + modbus: + # How many unreplied Modbus requests are considered a flood. + # If the limit is reached, app-layer-event:modbus.flooded; will match. + #request-flood: 500 + + enabled: no + detection-ports: + dp: 502 + # According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it + # is recommended to keep the TCP connection opened with a remote device + # and not to open and close it for each MODBUS/TCP transaction. In that + # case, it is important to set the depth of the stream reassembling as + # unlimited (stream.reassembly.depth: 0) + + # Stream reassembly size for modbus. By default track it completely. + stream-depth: 0 + + # DNP3 + dnp3: + enabled: no + detection-ports: + dp: 20000 + # SCADA EtherNet/IP and CIP protocol support enip: enabled: no From f9f5e8a348e8c042bf0798aa5a1d1797ff2c04be Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 1 Nov 2016 13:11:18 +0100 Subject: [PATCH 2154/2553] changelog: update for 3.2RC1 release --- ChangeLog | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8972324b77cf..62bf36d6a5b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +3.2RC1 -- 2016-11-01 + +Feature #1906: doc: install man page and ship pdf +Feature #1916: lua: add an SCPacketTimestamp function +Feature #1867: rule compatibility: flow:not_established not supported. +Bug #1525: Use pkg-config for libnetfilter_queue +Bug #1690: app-layer-proto negation issue +Bug #1909: libhtp 0.5.23 +Bug #1914: file log always shows stored: no even if file is stored +Bug #1917: nfq: bypass SEGV +Bug #1919: filemd5: md5-list does not allow comments any more +Bug #1923: dns - back to back requests results in loss of response +Bug #1928: flow bypass leads to memory errors +Bug #1931: multi-tenancy fails to start +Bug #1932: make install-full does not install tls-events.rules +Bug #1935: Check redis reply in non pipeline mode +Bug #1936: Can't set fast_pattern on tls_sni content + 3.2beta1 -- 2016-10-03 Feature #509: add SHA1 and SHA256 checksum support for files From 064c070db7127d8670bbf7da84a36988bbf1214b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 23 Nov 2016 10:35:42 +0100 Subject: [PATCH 2155/2553] pcap-file: minor cleanup --- src/source-pcap-file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 51515b7c8523..c6b1c3bbf3d2 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -399,7 +399,7 @@ TmEcode ReceivePcapFileThreadDeinit(ThreadVars *tv, void *data) SCReturnInt(TM_ECODE_OK); } -double prev_signaled_ts = 0; +static double prev_signaled_ts = 0; TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { From ee16b86900c50364078f5a43e2e18bd4d352bb55 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 18 Nov 2016 11:41:11 -0600 Subject: [PATCH 2156/2553] doc: fix build pdf on non gnu make platforms The Makefile generated by sphinx-build is GNU Make specific causing the PDF phase to fail. Instead call pdflatex directly based on how the generated Makefile was doing it. --- doc/userguide/Makefile.am | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index c71f2b7af0b0..afa535692dca 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -47,7 +47,14 @@ _build/latex/Suricata.pdf: version=$(PACKAGE_VERSION) \ $(SPHINX_BUILD) -W -b latex -d _build/doctrees \ $(top_srcdir)/doc/userguide _build/latex - cd _build/latex && $(MAKE) all-pdf +# The Sphinx generated Makefile is GNU Make specific, so just do what +# it does here - yes, multiple passes of pdflatex is required. + cd _build/latex && pdflatex Suricata.tex + cd _build/latex && pdflatex Suricata.tex + cd _build/latex && pdflatex Suricata.tex + cd _build/latex && makeindex -s python.ist Suricata.idx + cd _build/latex && pdflatex Suricata.tex + cd _build/latex && pdflatex Suricata.tex userguide.pdf: _build/latex/Suricata.pdf cp _build/latex/Suricata.pdf userguide.pdf From 0792f80909ad86506a95954348a007301e951bba Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 18 Nov 2016 11:50:02 -0600 Subject: [PATCH 2157/2553] doc: only build pdf on dist if pdflatex is installed --- configure.ac | 7 +++++++ doc/userguide/Makefile.am | 2 ++ 2 files changed, 9 insertions(+) diff --git a/configure.ac b/configure.ac index d4ecfc25e206..da13e099fde2 100644 --- a/configure.ac +++ b/configure.ac @@ -1893,6 +1893,13 @@ AM_CONDITIONAL([HAVE_SPHINXBUILD], [test "x$enable_sphinxbuild" != "xno"]) AM_CONDITIONAL([HAVE_SURICATA_MAN], [test "x$have_suricata_man" = "xyes"]) +# pdflatex for the pdf version of the user manual + AC_PATH_PROG(HAVE_PDFLATEX, pdflatex, "no") + if test "$HAVE_PDFLATEX" = "no"; then + enable_pdflatex=no + fi + AM_CONDITIONAL([HAVE_PDFLATEX], [test "x$enable_pdflatex" != "xno"]) + # get revision if test -f ./revision; then REVISION=`cat ./revision` diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am index afa535692dca..3852a251dae9 100644 --- a/doc/userguide/Makefile.am +++ b/doc/userguide/Makefile.am @@ -30,7 +30,9 @@ endif if HAVE_SPHINXBUILD man1_MANS = suricata.1 +if HAVE_PDFLATEX EXTRA_DIST += $(man1_MANS) userguide.pdf +endif SPHINX_BUILD = sphinx-build -q From 3da7dad514fff3469d14f8eb9993062cabaee523 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 17 Nov 2016 08:54:44 +0100 Subject: [PATCH 2158/2553] lua: luajit improvements Luajit has a strange memory requirement, it's 'states' need to be in the first 2G of the process' memory. This patch improves the pool approach by moving it to the front of the start up. A new config option 'luajit.states' is added to control how many states are preallocated. It defaults to 128. Add a warning when more states are used then preallocated. This may fail if flow/stream/detect engines use a lot of memory. Add hint at exit that gives the max states in use if it's higher than the default. --- src/Makefile.am | 1 + src/detect-lua.c | 114 +---------------------------- src/detect-lua.h | 8 --- src/detect.c | 9 +-- src/output-lua.c | 12 ++-- src/runmode-unittests.c | 9 +++ src/suricata-common.h | 6 ++ src/suricata.c | 13 +++- src/util-lua.c | 22 ++++++ src/util-lua.h | 5 ++ src/util-luajit.c | 155 ++++++++++++++++++++++++++++++++++++++++ src/util-luajit.h | 36 ++++++++++ 12 files changed, 256 insertions(+), 134 deletions(-) create mode 100644 src/util-luajit.c create mode 100644 src/util-luajit.h diff --git a/src/Makefile.am b/src/Makefile.am index 708ecb7a6250..48f5dd0ee0bc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -378,6 +378,7 @@ util-ip.h util-ip.c \ util-logopenfile.h util-logopenfile.c \ util-logopenfile-tile.h util-logopenfile-tile.c \ util-lua.c util-lua.h \ +util-luajit.c util-luajit.h \ util-lua-common.c util-lua-common.h \ util-lua-dnp3.c util-lua-dnp3.h \ util-lua-dnp3-objects.c util-lua-dnp3-objects.h \ diff --git a/src/detect-lua.c b/src/detect-lua.c index d77ee4edd531..a1ce74328572 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -85,26 +85,6 @@ void DetectLuaRegister(void) #else /* HAVE_LUA */ -#ifdef HAVE_LUAJIT -#include "util-pool.h" - -/** \brief lua_State pool - * - * Lua requires states to be alloc'd in memory <2GB. For this reason we - * prealloc the states early during engine startup so we have a better chance - * of getting the states. We protect the pool with a lock as the detect - * threads access it during their init and cleanup. - * - * Pool size is automagically determined based on number of keyword occurences, - * cpus/cores and rule reloads being enabled or not. - * - * Alternatively, the "detect-engine.luajit-states" var can be set. - */ -static Pool *luajit_states = NULL; -static pthread_mutex_t luajit_states_lock = SCMUTEX_INITIALIZER; - -#endif /* HAVE_LUAJIT */ - #include "util-lua.h" static int DetectLuaMatch (ThreadVars *, DetectEngineThreadCtx *, @@ -170,94 +150,6 @@ void DetectLuaRegister(void) #define DATATYPE_DNP3 (1<<20) -#ifdef HAVE_LUAJIT -static void *LuaStatePoolAlloc(void) -{ - return luaL_newstate(); -} - -static void LuaStatePoolFree(void *d) -{ - lua_State *s = (lua_State *)d; - if (s != NULL) - lua_close(s); -} - -/** \brief Populate lua states pool - * - * \param num keyword instances - * \param reloads bool indicating we have rule reloads enabled - */ -int DetectLuajitSetupStatesPool(int num, int reloads) -{ - int retval = 0; - pthread_mutex_lock(&luajit_states_lock); - - if (luajit_states == NULL) { - intmax_t cnt = 0; - ConfNode *denode = NULL; - ConfNode *decnf = ConfGetNode("detect-engine"); - if (decnf != NULL) { - TAILQ_FOREACH(denode, &decnf->head, next) { - if (strcmp(denode->val, "luajit-states") == 0) { - ConfGetChildValueInt(denode, "luajit-states", &cnt); - } - } - } - - if (cnt == 0) { - int cpus = UtilCpuGetNumProcessorsOnline(); - if (cpus == 0) { - cpus = 10; - } - cnt = num * cpus; - cnt *= 3; /* assume 3 threads per core */ - - /* alloc a bunch extra so reload can add new rules/instances */ - if (reloads) - cnt *= 5; - } - - luajit_states = PoolInit(0, cnt, 0, LuaStatePoolAlloc, NULL, NULL, NULL, LuaStatePoolFree); - if (luajit_states == NULL) { - SCLogError(SC_ERR_LUA_ERROR, "luastate pool init failed, lua/luajit keywords won't work"); - retval = -1; - } - } - - pthread_mutex_unlock(&luajit_states_lock); - return retval; -} -#endif /* HAVE_LUAJIT */ - -static lua_State *DetectLuaGetState(void) -{ - - lua_State *s = NULL; -#ifdef HAVE_LUAJIT - pthread_mutex_lock(&luajit_states_lock); - if (luajit_states != NULL) - s = (lua_State *)PoolGet(luajit_states); - pthread_mutex_unlock(&luajit_states_lock); -#else - s = luaL_newstate(); -#endif - return s; -} - -static void DetectLuaReturnState(lua_State *s) -{ - if (s != NULL) { -#ifdef HAVE_LUAJIT - pthread_mutex_lock(&luajit_states_lock); - PoolReturn(luajit_states, (void *)s); - pthread_mutex_unlock(&luajit_states_lock); -#else - lua_close(s); -#endif - } -} - /** \brief dump stack from lua state to screen */ void LuaDumpStack(lua_State *state) { @@ -691,7 +583,7 @@ static void *DetectLuaThreadInit(void *data) t->alproto = luajit->alproto; t->flags = luajit->flags; - t->luastate = DetectLuaGetState(); + t->luastate = LuaGetState(); if (t->luastate == NULL) { SCLogError(SC_ERR_LUA_ERROR, "luastate pool depleted"); goto error; @@ -737,7 +629,7 @@ static void *DetectLuaThreadInit(void *data) error: if (t->luastate != NULL) - DetectLuaReturnState(t->luastate); + LuaReturnState(t->luastate); SCFree(t); return NULL; } @@ -747,7 +639,7 @@ static void DetectLuaThreadFree(void *ctx) if (ctx != NULL) { DetectLuaThreadData *t = (DetectLuaThreadData *)ctx; if (t->luastate != NULL) - DetectLuaReturnState(t->luastate); + LuaReturnState(t->luastate); SCFree(t); } } diff --git a/src/detect-lua.h b/src/detect-lua.h index f1e86c2f2efb..d1259b3e66a4 100644 --- a/src/detect-lua.h +++ b/src/detect-lua.h @@ -26,10 +26,6 @@ #ifdef HAVE_LUA -#include -#include -#include - typedef struct DetectLuaThreadData { lua_State *luastate; uint32_t flags; @@ -63,10 +59,6 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch uint8_t *buffer, uint32_t buffer_len, uint32_t offset, Flow *f); -#ifdef HAVE_LUAJIT -int DetectLuajitSetupStatesPool(int num, int reloads); -#endif /* HAVE_LUAJIT */ - void DetectLuaPostSetup(Signature *s); #endif /* __DETECT_FILELUAJIT_H__ */ diff --git a/src/detect.c b/src/detect.c index 27047c5c0a02..e75e393dd7e4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -200,6 +200,7 @@ #include "stream-tcp.h" #include "stream-tcp-inline.h" +#include "util-lua.h" #include "util-var-name.h" #include "util-classification-config.h" #include "util-print.h" @@ -3366,14 +3367,6 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) "preprocessing rules..."); } -#ifdef HAVE_LUAJIT - /* run this before the mpm states are initialized */ - if (DetectLuajitSetupStatesPool(de_ctx->detect_luajit_instances, TRUE) != 0) { - if (de_ctx->failure_fatal) - return -1; - } -#endif - de_ctx->sig_array_len = DetectEngineGetMaxSigId(de_ctx); de_ctx->sig_array_size = (de_ctx->sig_array_len * sizeof(Signature *)); de_ctx->sig_array = (Signature **)SCMalloc(de_ctx->sig_array_size); diff --git a/src/output-lua.c b/src/output-lua.c index b71b0e3736f1..d9a6dc497a07 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -521,7 +521,7 @@ typedef struct LogLuaScriptOptions_ { static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { int status; - lua_State *luastate = luaL_newstate(); + lua_State *luastate = LuaGetState(); if (luastate == NULL) goto error; luaL_openlibs(luastate); @@ -649,11 +649,11 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { /* pop the table */ lua_pop(luastate, 1); - lua_close(luastate); + LuaReturnState(luastate); return 0; error: if (luastate) - lua_close(luastate); + LuaReturnState(luastate); return -1; } @@ -665,7 +665,7 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { */ static lua_State *LuaScriptSetup(const char *filename) { - lua_State *luastate = luaL_newstate(); + lua_State *luastate = LuaGetState(); if (luastate == NULL) { SCLogError(SC_ERR_LUA_ERROR, "luaL_newstate failed"); goto error; @@ -720,7 +720,7 @@ static lua_State *LuaScriptSetup(const char *filename) return luastate; error: if (luastate) - lua_close(luastate); + LuaReturnState(luastate); return NULL; } @@ -941,7 +941,7 @@ static void OutputLuaLogDoDeinit(LogLuaCtx *lua_ctx) SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'deinit' function: %s", lua_tostring(luastate, -1)); return; } - lua_close(luastate); + LuaReturnState(luastate); } /** \internal diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 7c97d286293d..4f03f18486d1 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -121,6 +121,7 @@ #include "detect-engine-siggroup.h" #include "util-streaming-buffer.h" +#include "util-lua.h" #endif /* UNITTESTS */ @@ -143,6 +144,11 @@ void RunUnittests(int list_unittests, char *regex_arg) GlobalInits(); TimeInit(); SupportFastPatternForSigMatchTypes(); +#ifdef HAVE_LUAJIT + if (LuajitSetupStatesPool() != 0) { + exit(EXIT_FAILURE); + } +#endif default_packet_size = DEFAULT_PACKET_SIZE; #ifdef __SC_CUDA_SUPPORT__ @@ -309,6 +315,9 @@ void RunUnittests(int list_unittests, char *regex_arg) } } +#ifdef HAVE_LUAJIT + LuajitFreeStatesPool(); +#endif #ifdef DBG_MEM_ALLOC SCLogInfo("Total memory used (without SCFree()): %"PRIdMAX, (intmax_t)global_mem); #endif diff --git a/src/suricata-common.h b/src/suricata-common.h index a2c9414a1603..5a40156b16a6 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -376,6 +376,12 @@ typedef enum { #include "util-path.h" #include "util-conf.h" +#ifdef HAVE_LUA +#include +#include +#include +#endif + #ifndef HAVE_STRLCAT size_t strlcat(char *, const char *src, size_t siz); #endif diff --git a/src/suricata.c b/src/suricata.c index ac228242809b..292ffd708e47 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -170,6 +170,8 @@ #include "util-storage.h" #include "host-storage.h" +#include "util-lua.h" + /* * we put this here, because we only use it here in main. */ @@ -2221,6 +2223,13 @@ static int PostConfLoadedSetup(SCInstance *suri) { char *hostmode = NULL; + /* do this as early as possible #1577 #1955 */ +#ifdef HAVE_LUAJIT + if (LuajitSetupStatesPool() != 0) { + SCReturnInt(TM_ECODE_FAILED); + } +#endif + /* load the pattern matchers */ MpmTableSetup(); #ifdef __SC_CUDA_SUPPORT__ @@ -2782,7 +2791,9 @@ int main(int argc, char **argv) CudaHandlerFreeProfiles(); #endif ConfDeInit(); - +#ifdef HAVE_LUAJIT + LuajitFreeStatesPool(); +#endif SCLogDeInitLogModule(); DetectParseFreeRegexes(); exit(engine_retval); diff --git a/src/util-lua.c b/src/util-lua.c index 7f1d44348c47..bc0c20c88715 100644 --- a/src/util-lua.c +++ b/src/util-lua.c @@ -56,6 +56,28 @@ #include "util-lua.h" +lua_State *LuaGetState(void) +{ + lua_State *s = NULL; +#ifdef HAVE_LUAJIT + s = LuajitGetState(); +#else + s = luaL_newstate(); +#endif + return s; +} + +void LuaReturnState(lua_State *s) +{ + if (s != NULL) { +#ifdef HAVE_LUAJIT + LuajitReturnState(s); +#else + lua_close(s); +#endif + } +} + /* key for tv (threadvars) pointer */ const char lua_ext_key_tv[] = "suricata:lua:tv:ptr"; /* key for tx pointer */ diff --git a/src/util-lua.h b/src/util-lua.h index 30431e74e8c2..d6a9838cd896 100644 --- a/src/util-lua.h +++ b/src/util-lua.h @@ -26,12 +26,17 @@ #ifdef HAVE_LUA +#include "util-luajit.h" + typedef struct LuaStreamingBuffer_ { const uint8_t *data; uint32_t data_len; uint8_t flags; } LuaStreamingBuffer; +lua_State *LuaGetState(void); +void LuaReturnState(lua_State *s); + /* gets */ /** \brief get tv pointer from the lua state */ diff --git a/src/util-luajit.c b/src/util-luajit.c new file mode 100644 index 000000000000..cb11dc79af46 --- /dev/null +++ b/src/util-luajit.c @@ -0,0 +1,155 @@ +/* Copyright (C) 2007-2016 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 + * + */ + +#include "suricata-common.h" + +#ifdef HAVE_LUAJIT +#include "conf.h" +#include "util-pool.h" +#include "util-lua.h" + +/** \brief lua_State pool + * + * Lua requires states to be alloc'd in memory <2GB. For this reason we + * prealloc the states early during engine startup so we have a better chance + * of getting the states. We protect the pool with a lock as the detect + * threads access it during their init and cleanup. + * + * Pool size is automagically determined based on number of keyword occurences, + * cpus/cores and rule reloads being enabled or not. + * + * Alternatively, the "detect-engine.luajit-states" var can be set. + */ +static Pool *luajit_states = NULL; +static pthread_mutex_t luajit_states_lock = SCMUTEX_INITIALIZER; +static int luajit_states_cnt = 0; +static int luajit_states_cnt_max = 0; +static int luajit_states_size = 0; +#define LUAJIT_DEFAULT_STATES 128 + +static void *LuaStatePoolAlloc(void) +{ + return luaL_newstate(); +} + +static void LuaStatePoolFree(void *d) +{ + lua_State *s = (lua_State *)d; + if (s != NULL) + lua_close(s); +} + +/** \brief Populate lua states pool + * + * \param num keyword instances + * \param reloads bool indicating we have rule reloads enabled + */ +int LuajitSetupStatesPool(void) +{ + int retval = 0; + pthread_mutex_lock(&luajit_states_lock); + + if (luajit_states == NULL) { + intmax_t cnt = 0; + if (ConfGetInt("luajit.states", &cnt) != 1) { + ConfNode *denode = NULL; + ConfNode *decnf = ConfGetNode("detect-engine"); + if (decnf != NULL) { + TAILQ_FOREACH(denode, &decnf->head, next) { + if (strcmp(denode->val, "luajit-states") == 0) { + ConfGetChildValueInt(denode, "luajit-states", &cnt); + } + } + } + } + if (cnt == 0) { + cnt = LUAJIT_DEFAULT_STATES; + } + luajit_states_size = cnt; + + luajit_states = PoolInit(0, cnt, 0, LuaStatePoolAlloc, NULL, NULL, NULL, LuaStatePoolFree); + if (luajit_states == NULL) { + SCLogError(SC_ERR_LUA_ERROR, "luastate pool init failed, lua/luajit keywords won't work"); + retval = -1; + } + + if (retval == 0) { + SCLogConfig("luajit states preallocated: %d", luajit_states_size); + } + } + + pthread_mutex_unlock(&luajit_states_lock); + return retval; +} + +void LuajitFreeStatesPool(void) +{ + pthread_mutex_lock(&luajit_states_lock); + if (luajit_states_cnt_max > luajit_states_size) { + SCLogNotice("luajit states used %d is bigger than pool size %d. Set " + "luajit.states to %d to avoid memory issues. " + "See #1577 and #1955.", luajit_states_cnt_max, luajit_states_size, + luajit_states_cnt_max); + } + PoolFree(luajit_states); + luajit_states = NULL; + luajit_states_size = 0; + luajit_states_cnt = 0; + pthread_mutex_unlock(&luajit_states_lock); +} + +lua_State *LuajitGetState(void) +{ + lua_State *s = NULL; + pthread_mutex_lock(&luajit_states_lock); + if (luajit_states != NULL) { + s = (lua_State *)PoolGet(luajit_states); + if (s != NULL) { + if (luajit_states_cnt == luajit_states_size) { + SCLogWarning(SC_WARN_LUA_SCRIPT, "luajit states pool size %d " + "reached. Increase luajit.states config option. " + "See #1577 and #1955", luajit_states_size); + } + + luajit_states_cnt++; + if (luajit_states_cnt > luajit_states_cnt_max) + luajit_states_cnt_max = luajit_states_cnt; + } + } + pthread_mutex_unlock(&luajit_states_lock); + return s; +} + +void LuajitReturnState(lua_State *s) +{ + if (s != NULL) { + pthread_mutex_lock(&luajit_states_lock); + PoolReturn(luajit_states, (void *)s); + BUG_ON(luajit_states_cnt <= 0); + luajit_states_cnt--; + pthread_mutex_unlock(&luajit_states_lock); + } +} + +#endif /* HAVE_LUAJIT */ diff --git a/src/util-luajit.h b/src/util-luajit.h new file mode 100644 index 000000000000..5aa810b1eaa9 --- /dev/null +++ b/src/util-luajit.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2007-2016 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 + */ + +#ifndef __UTIL_LUAJIT_H__ +#define __UTIL_LUAJIT_H__ + +#ifdef HAVE_LUAJIT + +int LuajitSetupStatesPool(void); +void LuajitFreeStatesPool(void); +lua_State *LuajitGetState(void); +void LuajitReturnState(lua_State *s); + +#endif /* HAVE_LUAJIT */ + +#endif /* __UTIL_LUAJIT_H__ */ From 3012edae1cc3989d6b461366b06672e3c7776d5c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 17 Nov 2016 14:27:41 +0100 Subject: [PATCH 2159/2553] luajit: update default yaml and doc for 'states' --- doc/userguide/configuration/suricata-yaml.rst | 22 +++++++++++++++++++ suricata.yaml.in | 9 ++++++++ 2 files changed, 31 insertions(+) diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index ab04dc1d0097..8feee0f5383e 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -2188,3 +2188,25 @@ unlimited. modbus: # Stream reassembly size for modbus, default is 0 stream-depth: 0 + +Advanced Options +---------------- + +luajit +~~~~~~ + +states +^^^^^^ + +Luajit has a strange memory requirement, it's 'states' need to be in the +first 2G of the process' memory. For this reason when luajit is used the +states are allocated at the process startup. This option controls how many +states are preallocated. + +If the pool is depleted a warning is generated. Suricata will still try to +continue, but may fail if other parts of the engine take too much memory. +If the pool was depleted a hint will be printed at the engines exit. + +States are allocated as follows: for each detect script a state is used per +detect thread. For each output script, a single state is used. Keep in +mind that a rule reload temporary doubles the states requirement. diff --git a/suricata.yaml.in b/suricata.yaml.in index 1a431dc3348f..e701c335c691 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1381,6 +1381,15 @@ threading: # detect-thread-ratio: 1.0 +# Luajit has a strange memory requirement, it's 'states' need to be in the +# first 2G of the process' memory. +# +# 'luajit.states' is used to control how many states are preallocated. +# State use: per detect script: 1 per detect thread. Per output script: 1 per +# script. +luajit: + states: 128 + # Profiling settings. Only effective if Suricata has been built with the # the --enable-profiling configure flag. # From 0366d47608eeb00bb69ff93d2b8cef354c3435ec Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 18 Nov 2016 11:18:33 +0100 Subject: [PATCH 2160/2553] luajit: remove unused instance counter --- src/detect-lua.c | 1 - src/detect.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/detect-lua.c b/src/detect-lua.c index a1ce74328572..ae0be3f95274 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1032,7 +1032,6 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) goto error; } - de_ctx->detect_luajit_instances++; return 0; error: diff --git a/src/detect.h b/src/detect.h index a6ae3d4f89aa..4277115b5b51 100644 --- a/src/detect.h +++ b/src/detect.h @@ -727,8 +727,6 @@ typedef struct DetectEngineCtx_ { DetectEngineThreadKeywordCtxItem *keyword_list; int keyword_id; - int detect_luajit_instances; - #ifdef PROFILING struct SCProfileDetectCtx_ *profile_ctx; struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx; From 3f8ee2afd3b861486ae6380d80dfd1966c6b61b1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 18 Nov 2016 11:18:57 +0100 Subject: [PATCH 2161/2553] detect-lua: unify on using 'lua' name vs 'luajit' --- src/detect-lua-extensions.c | 16 +- src/detect-lua.c | 358 ++++++++++++++++++------------------ src/detect.h | 2 +- 3 files changed, 188 insertions(+), 188 deletions(-) diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index 7825967f6947..06a11569a534 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -71,7 +71,7 @@ #include "util-lua-smtp.h" #include "util-lua-dnp3.h" -static const char luaext_key_ld[] = "suricata:luajitdata"; +static const char luaext_key_ld[] = "suricata:luadata"; static const char luaext_key_det_ctx[] = "suricata:det_ctx"; static int LuaGetFlowvar(lua_State *luastate) @@ -82,7 +82,7 @@ static int LuaGetFlowvar(lua_State *luastate) FlowVar *fv; DetectLuaData *ld; - /* need luajit data for id -> idx conversion */ + /* need lua data for id -> idx conversion */ lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); lua_gettable(luastate, LUA_REGISTRYINDEX); ld = lua_touserdata(luastate, -1); @@ -145,7 +145,7 @@ int LuaSetFlowvar(lua_State *luastate) DetectEngineThreadCtx *det_ctx; DetectLuaData *ld; - /* need luajit data for id -> idx conversion */ + /* need lua data for id -> idx conversion */ lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); lua_gettable(luastate, LUA_REGISTRYINDEX); ld = lua_touserdata(luastate, -1); @@ -244,7 +244,7 @@ static int LuaGetFlowint(lua_State *luastate) DetectLuaData *ld; uint32_t number; - /* need luajit data for id -> idx conversion */ + /* need lua data for id -> idx conversion */ lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); lua_gettable(luastate, LUA_REGISTRYINDEX); ld = lua_touserdata(luastate, -1); @@ -313,7 +313,7 @@ int LuaSetFlowint(lua_State *luastate) uint32_t number; lua_Number luanumber; - /* need luajit data for id -> idx conversion */ + /* need lua data for id -> idx conversion */ lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); lua_gettable(luastate, LUA_REGISTRYINDEX); ld = lua_touserdata(luastate, -1); @@ -391,7 +391,7 @@ static int LuaIncrFlowint(lua_State *luastate) DetectLuaData *ld; uint32_t number; - /* need luajit data for id -> idx conversion */ + /* need lua data for id -> idx conversion */ lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); lua_gettable(luastate, LUA_REGISTRYINDEX); ld = lua_touserdata(luastate, -1); @@ -460,7 +460,7 @@ static int LuaDecrFlowint(lua_State *luastate) DetectLuaData *ld; uint32_t number; - /* need luajit data for id -> idx conversion */ + /* need lua data for id -> idx conversion */ lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); lua_gettable(luastate, LUA_REGISTRYINDEX); ld = lua_touserdata(luastate, -1); @@ -525,7 +525,7 @@ void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld, DetectEngi { SCLogDebug("det_ctx %p, f %p", det_ctx, f); - /* luajit keyword data */ + /* lua keyword data */ lua_pushlightuserdata(lua_state, (void *)&luaext_key_ld); lua_pushlightuserdata(lua_state, (void *)ld); lua_settable(lua_state, LUA_REGISTRYINDEX); diff --git a/src/detect-lua.c b/src/detect-lua.c index ae0be3f95274..b3a8222b1e59 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -68,7 +68,7 @@ static int DetectLuaSetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) } /** - * \brief Registration function for keyword: luajit + * \brief Registration function for keyword: lua */ void DetectLuaRegister(void) { @@ -100,13 +100,13 @@ static void DetectLuaRegisterTests(void); static void DetectLuaFree(void *); /** - * \brief Registration function for keyword: luajit + * \brief Registration function for keyword: lua */ void DetectLuaRegister(void) { sigmatch_table[DETECT_LUA].name = "lua"; sigmatch_table[DETECT_LUA].alias = "luajit"; - sigmatch_table[DETECT_LUA].desc = "match via a luajit script"; + sigmatch_table[DETECT_LUA].desc = "match via a lua script"; sigmatch_table[DETECT_LUA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Lua_scripting"; sigmatch_table[DETECT_LUA].Match = DetectLuaMatch; sigmatch_table[DETECT_LUA].AppLayerMatch = DetectLuaAppMatch; @@ -115,7 +115,7 @@ void DetectLuaRegister(void) sigmatch_table[DETECT_LUA].Free = DetectLuaFree; sigmatch_table[DETECT_LUA].RegisterTests = DetectLuaRegisterTests; - SCLogDebug("registering luajit rule option"); + SCLogDebug("registering lua rule option"); return; } @@ -185,7 +185,8 @@ void LuaDumpStack(lua_State *state) } } -int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, +int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, + Signature *s, SigMatch *sm, uint8_t *buffer, uint32_t buffer_len, uint32_t offset, Flow *f) { @@ -195,53 +196,53 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch if (buffer == NULL || buffer_len == 0) SCReturnInt(0); - DetectLuaData *luajit = (DetectLuaData *)sm->ctx; - if (luajit == NULL) + DetectLuaData *lua = (DetectLuaData *)sm->ctx; + if (lua == NULL) SCReturnInt(0); - DetectLuaThreadData *tluajit = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, luajit->thread_ctx_id); - if (tluajit == NULL) + DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); + if (tlua == NULL) SCReturnInt(0); - LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, + LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx, f, /* no packet in the ctx */NULL, 0); /* prepare data to pass to script */ - lua_getglobal(tluajit->luastate, "match"); - lua_newtable(tluajit->luastate); /* stack at -1 */ + lua_getglobal(tlua->luastate, "match"); + lua_newtable(tlua->luastate); /* stack at -1 */ - lua_pushliteral (tluajit->luastate, "offset"); /* stack at -2 */ - lua_pushnumber (tluajit->luastate, (int)(offset + 1)); - lua_settable(tluajit->luastate, -3); + lua_pushliteral (tlua->luastate, "offset"); /* stack at -2 */ + lua_pushnumber (tlua->luastate, (int)(offset + 1)); + lua_settable(tlua->luastate, -3); - lua_pushstring (tluajit->luastate, luajit->buffername); /* stack at -2 */ - LuaPushStringBuffer(tluajit->luastate, (const uint8_t *)buffer, (size_t)buffer_len); - lua_settable(tluajit->luastate, -3); + lua_pushstring (tlua->luastate, lua->buffername); /* stack at -2 */ + LuaPushStringBuffer(tlua->luastate, (const uint8_t *)buffer, (size_t)buffer_len); + lua_settable(tlua->luastate, -3); - int retval = lua_pcall(tluajit->luastate, 1, 1, 0); + int retval = lua_pcall(tlua->luastate, 1, 1, 0); if (retval != 0) { - SCLogInfo("failed to run script: %s", lua_tostring(tluajit->luastate, -1)); + SCLogInfo("failed to run script: %s", lua_tostring(tlua->luastate, -1)); } /* process returns from script */ - if (lua_gettop(tluajit->luastate) > 0) { + if (lua_gettop(tlua->luastate) > 0) { /* script returns a number (return 1 or return 0) */ - if (lua_type(tluajit->luastate, 1) == LUA_TNUMBER) { - double script_ret = lua_tonumber(tluajit->luastate, 1); + if (lua_type(tlua->luastate, 1) == LUA_TNUMBER) { + double script_ret = lua_tonumber(tlua->luastate, 1); SCLogDebug("script_ret %f", script_ret); - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); if (script_ret == 1.0) ret = 1; /* script returns a table */ - } else if (lua_type(tluajit->luastate, 1) == LUA_TTABLE) { - lua_pushnil(tluajit->luastate); + } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) { + lua_pushnil(tlua->luastate); const char *k, *v; - while (lua_next(tluajit->luastate, -2)) { - v = lua_tostring(tluajit->luastate, -1); - lua_pop(tluajit->luastate, 1); - k = lua_tostring(tluajit->luastate, -1); + while (lua_next(tlua->luastate, -2)) { + v = lua_tostring(tlua->luastate, -1); + lua_pop(tlua->luastate, 1); + k = lua_tostring(tlua->luastate, -1); if (!k || !v) continue; @@ -257,18 +258,18 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch } /* pop the table */ - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); } } else { SCLogDebug("no stack"); } /* clear the stack */ - while (lua_gettop(tluajit->luastate) > 0) { - lua_pop(tluajit->luastate, 1); + while (lua_gettop(tlua->luastate) > 0) { + lua_pop(tlua->luastate, 1); } - if (luajit->negated) { + if (lua->negated) { if (ret == 1) ret = 0; else @@ -276,11 +277,10 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch } SCReturnInt(ret); - } /** - * \brief match the specified luajit + * \brief match the specified lua script * * \param t thread local vars * \param det_ctx pattern matcher thread local data @@ -296,12 +296,12 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, { SCEnter(); int ret = 0; - DetectLuaData *luajit = (DetectLuaData *)ctx; - if (luajit == NULL) + DetectLuaData *lua = (DetectLuaData *)ctx; + if (lua == NULL) SCReturnInt(0); - DetectLuaThreadData *tluajit = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, luajit->thread_ctx_id); - if (tluajit == NULL) + DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); + if (tlua == NULL) SCReturnInt(0); /* setup extension data for use in lua c functions */ @@ -311,38 +311,38 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, else if (p->flowflags & FLOW_PKT_TOCLIENT) flags = STREAM_TOCLIENT; - LuaStateSetThreadVars(tluajit->luastate, tv); + LuaStateSetThreadVars(tlua->luastate, tv); - LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, + LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx, p->flow, p, flags); - if ((tluajit->flags & DATATYPE_PAYLOAD) && p->payload_len == 0) + if ((tlua->flags & DATATYPE_PAYLOAD) && p->payload_len == 0) SCReturnInt(0); - if ((tluajit->flags & DATATYPE_PACKET) && GET_PKT_LEN(p) == 0) + if ((tlua->flags & DATATYPE_PACKET) && GET_PKT_LEN(p) == 0) SCReturnInt(0); - if (tluajit->alproto != ALPROTO_UNKNOWN) { + if (tlua->alproto != ALPROTO_UNKNOWN) { if (p->flow == NULL) SCReturnInt(0); AppProto alproto = p->flow->alproto; - if (tluajit->alproto != alproto) + if (tlua->alproto != alproto) SCReturnInt(0); } - lua_getglobal(tluajit->luastate, "match"); - lua_newtable(tluajit->luastate); /* stack at -1 */ + lua_getglobal(tlua->luastate, "match"); + lua_newtable(tlua->luastate); /* stack at -1 */ - if ((tluajit->flags & DATATYPE_PAYLOAD) && p->payload_len) { - lua_pushliteral(tluajit->luastate, "payload"); /* stack at -2 */ - LuaPushStringBuffer (tluajit->luastate, (const uint8_t *)p->payload, (size_t)p->payload_len); /* stack at -3 */ - lua_settable(tluajit->luastate, -3); + if ((tlua->flags & DATATYPE_PAYLOAD) && p->payload_len) { + lua_pushliteral(tlua->luastate, "payload"); /* stack at -2 */ + LuaPushStringBuffer (tlua->luastate, (const uint8_t *)p->payload, (size_t)p->payload_len); /* stack at -3 */ + lua_settable(tlua->luastate, -3); } - if ((tluajit->flags & DATATYPE_PACKET) && GET_PKT_LEN(p)) { - lua_pushliteral(tluajit->luastate, "packet"); /* stack at -2 */ - LuaPushStringBuffer (tluajit->luastate, (const uint8_t *)GET_PKT_DATA(p), (size_t)GET_PKT_LEN(p)); /* stack at -3 */ - lua_settable(tluajit->luastate, -3); + if ((tlua->flags & DATATYPE_PACKET) && GET_PKT_LEN(p)) { + lua_pushliteral(tlua->luastate, "packet"); /* stack at -2 */ + LuaPushStringBuffer (tlua->luastate, (const uint8_t *)GET_PKT_DATA(p), (size_t)GET_PKT_LEN(p)); /* stack at -3 */ + lua_settable(tlua->luastate, -3); } - if (tluajit->alproto == ALPROTO_HTTP) { + if (tlua->alproto == ALPROTO_HTTP) { HtpState *htp_state = p->flow->alstate; if (htp_state != NULL && htp_state->connp != NULL) { htp_tx_t *tx = NULL; @@ -354,43 +354,43 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, if (tx == NULL) continue; - if ((tluajit->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && + if ((tlua->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && bstr_len(tx->request_line) > 0) { - lua_pushliteral(tluajit->luastate, "http.request_line"); /* stack at -2 */ - LuaPushStringBuffer(tluajit->luastate, + lua_pushliteral(tlua->luastate, "http.request_line"); /* stack at -2 */ + LuaPushStringBuffer(tlua->luastate, (const uint8_t *)bstr_ptr(tx->request_line), bstr_len(tx->request_line)); - lua_settable(tluajit->luastate, -3); + lua_settable(tlua->luastate, -3); } } } } - int retval = lua_pcall(tluajit->luastate, 1, 1, 0); + int retval = lua_pcall(tlua->luastate, 1, 1, 0); if (retval != 0) { - SCLogInfo("failed to run script: %s", lua_tostring(tluajit->luastate, -1)); + SCLogInfo("failed to run script: %s", lua_tostring(tlua->luastate, -1)); } /* process returns from script */ - if (lua_gettop(tluajit->luastate) > 0) { + if (lua_gettop(tlua->luastate) > 0) { /* script returns a number (return 1 or return 0) */ - if (lua_type(tluajit->luastate, 1) == LUA_TNUMBER) { - double script_ret = lua_tonumber(tluajit->luastate, 1); + if (lua_type(tlua->luastate, 1) == LUA_TNUMBER) { + double script_ret = lua_tonumber(tlua->luastate, 1); SCLogDebug("script_ret %f", script_ret); - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); if (script_ret == 1.0) ret = 1; /* script returns a table */ - } else if (lua_type(tluajit->luastate, 1) == LUA_TTABLE) { - lua_pushnil(tluajit->luastate); + } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) { + lua_pushnil(tlua->luastate); const char *k, *v; - while (lua_next(tluajit->luastate, -2)) { - v = lua_tostring(tluajit->luastate, -1); - lua_pop(tluajit->luastate, 1); - k = lua_tostring(tluajit->luastate, -1); + while (lua_next(tlua->luastate, -2)) { + v = lua_tostring(tlua->luastate, -1); + lua_pop(tlua->luastate, 1); + k = lua_tostring(tlua->luastate, -1); if (!k || !v) continue; @@ -406,14 +406,14 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, } /* pop the table */ - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); } } - while (lua_gettop(tluajit->luastate) > 0) { - lua_pop(tluajit->luastate, 1); + while (lua_gettop(tlua->luastate) > 0) { + lua_pop(tlua->luastate, 1); } - if (luajit->negated) { + if (lua->negated) { if (ret == 1) ret = 0; else @@ -429,70 +429,70 @@ static int DetectLuaAppMatchCommon (ThreadVars *t, DetectEngineThreadCtx *det_ct { SCEnter(); int ret = 0; - DetectLuaData *luajit = (DetectLuaData *)ctx; - if (luajit == NULL) + DetectLuaData *lua = (DetectLuaData *)ctx; + if (lua == NULL) SCReturnInt(0); - DetectLuaThreadData *tluajit = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, luajit->thread_ctx_id); - if (tluajit == NULL) + DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); + if (tlua == NULL) SCReturnInt(0); /* setup extension data for use in lua c functions */ - LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, + LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx, f, NULL, flags); - if (tluajit->alproto != ALPROTO_UNKNOWN) { + if (tlua->alproto != ALPROTO_UNKNOWN) { int alproto = f->alproto; - if (tluajit->alproto != alproto) + if (tlua->alproto != alproto) SCReturnInt(0); } - lua_getglobal(tluajit->luastate, "match"); - lua_newtable(tluajit->luastate); /* stack at -1 */ + lua_getglobal(tlua->luastate, "match"); + lua_newtable(tlua->luastate); /* stack at -1 */ - if (tluajit->alproto == ALPROTO_HTTP) { + if (tlua->alproto == ALPROTO_HTTP) { HtpState *htp_state = state; if (htp_state != NULL && htp_state->connp != NULL) { htp_tx_t *tx = NULL; tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, det_ctx->tx_id); if (tx != NULL) { - if ((tluajit->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && + if ((tlua->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && bstr_len(tx->request_line) > 0) { - lua_pushliteral(tluajit->luastate, "http.request_line"); /* stack at -2 */ - LuaPushStringBuffer(tluajit->luastate, + lua_pushliteral(tlua->luastate, "http.request_line"); /* stack at -2 */ + LuaPushStringBuffer(tlua->luastate, (const uint8_t *)bstr_ptr(tx->request_line), bstr_len(tx->request_line)); - lua_settable(tluajit->luastate, -3); + lua_settable(tlua->luastate, -3); } } } } - int retval = lua_pcall(tluajit->luastate, 1, 1, 0); + int retval = lua_pcall(tlua->luastate, 1, 1, 0); if (retval != 0) { - SCLogInfo("failed to run script: %s", lua_tostring(tluajit->luastate, -1)); + SCLogInfo("failed to run script: %s", lua_tostring(tlua->luastate, -1)); } /* process returns from script */ - if (lua_gettop(tluajit->luastate) > 0) { + if (lua_gettop(tlua->luastate) > 0) { /* script returns a number (return 1 or return 0) */ - if (lua_type(tluajit->luastate, 1) == LUA_TNUMBER) { - double script_ret = lua_tonumber(tluajit->luastate, 1); + if (lua_type(tlua->luastate, 1) == LUA_TNUMBER) { + double script_ret = lua_tonumber(tlua->luastate, 1); SCLogDebug("script_ret %f", script_ret); - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); if (script_ret == 1.0) ret = 1; /* script returns a table */ - } else if (lua_type(tluajit->luastate, 1) == LUA_TTABLE) { - lua_pushnil(tluajit->luastate); + } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) { + lua_pushnil(tlua->luastate); const char *k, *v; - while (lua_next(tluajit->luastate, -2)) { - v = lua_tostring(tluajit->luastate, -1); - lua_pop(tluajit->luastate, 1); - k = lua_tostring(tluajit->luastate, -1); + while (lua_next(tlua->luastate, -2)) { + v = lua_tostring(tlua->luastate, -1); + lua_pop(tlua->luastate, 1); + k = lua_tostring(tlua->luastate, -1); if (!k || !v) continue; @@ -508,14 +508,14 @@ static int DetectLuaAppMatchCommon (ThreadVars *t, DetectEngineThreadCtx *det_ct } /* pop the table */ - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); } } - while (lua_gettop(tluajit->luastate) > 0) { - lua_pop(tluajit->luastate, 1); + while (lua_gettop(tlua->luastate) > 0) { + lua_pop(tlua->luastate, 1); } - if (luajit->negated) { + if (lua->negated) { if (ret == 1) ret = 0; else @@ -562,7 +562,7 @@ static int DetectLuaAppTxMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, } #ifdef UNITTESTS -/* if this ptr is set the luajit setup functions will use this buffer as the +/* if this ptr is set the lua setup functions will use this buffer as the * lua script instead of calling luaL_loadfile on the filename supplied. */ static const char *ut_script = NULL; #endif @@ -570,8 +570,8 @@ static const char *ut_script = NULL; static void *DetectLuaThreadInit(void *data) { int status; - DetectLuaData *luajit = (DetectLuaData *)data; - BUG_ON(luajit == NULL); + DetectLuaData *lua = (DetectLuaData *)data; + BUG_ON(lua == NULL); DetectLuaThreadData *t = SCMalloc(sizeof(DetectLuaThreadData)); if (unlikely(t == NULL)) { @@ -580,8 +580,8 @@ static void *DetectLuaThreadInit(void *data) } memset(t, 0x00, sizeof(DetectLuaThreadData)); - t->alproto = luajit->alproto; - t->flags = luajit->flags; + t->alproto = lua->alproto; + t->flags = lua->flags; t->luastate = LuaGetState(); if (t->luastate == NULL) { @@ -593,11 +593,11 @@ static void *DetectLuaThreadInit(void *data) LuaRegisterExtensions(t->luastate); - lua_pushinteger(t->luastate, (lua_Integer)(luajit->sid)); + lua_pushinteger(t->luastate, (lua_Integer)(lua->sid)); lua_setglobal(t->luastate, "SCRuleSid"); - lua_pushinteger(t->luastate, (lua_Integer)(luajit->rev)); + lua_pushinteger(t->luastate, (lua_Integer)(lua->rev)); lua_setglobal(t->luastate, "SCRuleRev"); - lua_pushinteger(t->luastate, (lua_Integer)(luajit->gid)); + lua_pushinteger(t->luastate, (lua_Integer)(lua->gid)); lua_setglobal(t->luastate, "SCRuleGid"); /* hackish, needed to allow unittests to pass buffers as scripts instead of files */ @@ -610,7 +610,7 @@ static void *DetectLuaThreadInit(void *data) } } else { #endif - status = luaL_loadfile(t->luastate, luajit->filename); + status = luaL_loadfile(t->luastate, lua->filename); if (status) { SCLogError(SC_ERR_LUA_ERROR, "couldn't load file: %s", lua_tostring(t->luastate, -1)); goto error; @@ -645,40 +645,40 @@ static void DetectLuaThreadFree(void *ctx) } /** - * \brief Parse the luajit keyword + * \brief Parse the lua keyword * * \param str Pointer to the user provided option * - * \retval luajit pointer to DetectLuaData on success + * \retval lua pointer to DetectLuaData on success * \retval NULL on failure */ static DetectLuaData *DetectLuaParse (const DetectEngineCtx *de_ctx, char *str) { - DetectLuaData *luajit = NULL; + DetectLuaData *lua = NULL; - /* We have a correct luajit option */ - luajit = SCMalloc(sizeof(DetectLuaData)); - if (unlikely(luajit == NULL)) + /* We have a correct lua option */ + lua = SCMalloc(sizeof(DetectLuaData)); + if (unlikely(lua == NULL)) goto error; - memset(luajit, 0x00, sizeof(DetectLuaData)); + memset(lua, 0x00, sizeof(DetectLuaData)); if (strlen(str) && str[0] == '!') { - luajit->negated = 1; + lua->negated = 1; str++; } /* get full filename */ - luajit->filename = DetectLoadCompleteSigPath(de_ctx, str); - if (luajit->filename == NULL) { + lua->filename = DetectLoadCompleteSigPath(de_ctx, str); + if (lua->filename == NULL) { goto error; } - return luajit; + return lua; error: - if (luajit != NULL) - DetectLuaFree(luajit); + if (lua != NULL) + DetectLuaFree(lua); return NULL; } @@ -939,40 +939,40 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) } /** - * \brief this function is used to parse luajit options + * \brief this function is used to parse lua options * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature - * \param str pointer to the user provided "luajit" option + * \param str pointer to the user provided "lua" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { - DetectLuaData *luajit = NULL; + DetectLuaData *lua = NULL; SigMatch *sm = NULL; - luajit = DetectLuaParse(de_ctx, str); - if (luajit == NULL) + lua = DetectLuaParse(de_ctx, str); + if (lua == NULL) goto error; - if (DetectLuaSetupPrime(de_ctx, luajit) == -1) { + if (DetectLuaSetupPrime(de_ctx, lua) == -1) { goto error; } - luajit->thread_ctx_id = DetectRegisterThreadCtxFuncs(de_ctx, "luajit", - DetectLuaThreadInit, (void *)luajit, + lua->thread_ctx_id = DetectRegisterThreadCtxFuncs(de_ctx, "lua", + DetectLuaThreadInit, (void *)lua, DetectLuaThreadFree, 0); - if (luajit->thread_ctx_id == -1) + if (lua->thread_ctx_id == -1) goto error; - if (luajit->alproto != ALPROTO_UNKNOWN) { - if (s->alproto != ALPROTO_UNKNOWN && luajit->alproto != s->alproto) { + if (lua->alproto != ALPROTO_UNKNOWN) { + if (s->alproto != ALPROTO_UNKNOWN && lua->alproto != s->alproto) { goto error; } - s->alproto = luajit->alproto; + s->alproto = lua->alproto; } /* Okay so far so good, lets get this into a SigMatch @@ -982,61 +982,61 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) goto error; sm->type = DETECT_LUA; - sm->ctx = (SigMatchCtx *)luajit; + sm->ctx = (SigMatchCtx *)lua; - if (luajit->alproto == ALPROTO_UNKNOWN) { - if (luajit->flags & DATATYPE_STREAM) + if (lua->alproto == ALPROTO_UNKNOWN) { + if (lua->flags & DATATYPE_STREAM) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); else SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); - } else if (luajit->alproto == ALPROTO_HTTP) { - if (luajit->flags & DATATYPE_HTTP_RESPONSE_BODY) + } else if (lua->alproto == ALPROTO_HTTP) { + if (lua->flags & DATATYPE_HTTP_RESPONSE_BODY) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEDATA); - else if (luajit->flags & DATATYPE_HTTP_REQUEST_BODY) + else if (lua->flags & DATATYPE_HTTP_REQUEST_BODY) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCBDMATCH); - else if (luajit->flags & DATATYPE_HTTP_URI) + else if (lua->flags & DATATYPE_HTTP_URI) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); - else if (luajit->flags & DATATYPE_HTTP_URI_RAW) + else if (lua->flags & DATATYPE_HTTP_URI_RAW) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); - else if (luajit->flags & DATATYPE_HTTP_REQUEST_COOKIE) + else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); - else if (luajit->flags & DATATYPE_HTTP_REQUEST_UA) + else if (lua->flags & DATATYPE_HTTP_REQUEST_UA) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HUADMATCH); - else if (luajit->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) + else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HHDMATCH); - else if (luajit->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) + else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRHDMATCH); - else if (luajit->flags & DATATYPE_HTTP_RESPONSE_COOKIE) + else if (lua->flags & DATATYPE_HTTP_RESPONSE_COOKIE) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); else SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HTTP_REQLINEMATCH); - } else if (luajit->alproto == ALPROTO_DNS) { - if (luajit->flags & DATATYPE_DNS_RRNAME) { + } else if (lua->alproto == ALPROTO_DNS) { + if (lua->flags & DATATYPE_DNS_RRNAME) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSQUERYNAME_MATCH); - } else if (luajit->flags & DATATYPE_DNS_REQUEST) { + } else if (lua->flags & DATATYPE_DNS_REQUEST) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSREQUEST_MATCH); - } else if (luajit->flags & DATATYPE_DNS_RESPONSE) { + } else if (lua->flags & DATATYPE_DNS_RESPONSE) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSRESPONSE_MATCH); } - } else if (luajit->alproto == ALPROTO_TLS) { + } else if (lua->alproto == ALPROTO_TLS) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - } else if (luajit->alproto == ALPROTO_SSH) { + } else if (lua->alproto == ALPROTO_SSH) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - } else if (luajit->alproto == ALPROTO_SMTP) { + } else if (lua->alproto == ALPROTO_SMTP) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - } else if (luajit->alproto == ALPROTO_DNP3) { + } else if (lua->alproto == ALPROTO_DNP3) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNP3_MATCH); } else { - SCLogError(SC_ERR_LUA_ERROR, "luajit can't be used with protocol %s", - AppLayerGetProtoName(luajit->alproto)); + SCLogError(SC_ERR_LUA_ERROR, "lua can't be used with protocol %s", + AppLayerGetProtoName(lua->alproto)); goto error; } return 0; error: - if (luajit != NULL) - DetectLuaFree(luajit); + if (lua != NULL) + DetectLuaFree(lua); if (sm != NULL) SCFree(sm); return -1; @@ -1066,19 +1066,19 @@ void DetectLuaPostSetup(Signature *s) /** * \brief this function will free memory associated with DetectLuaData * - * \param luajit pointer to DetectLuaData + * \param ptr pointer to DetectLuaData */ static void DetectLuaFree(void *ptr) { if (ptr != NULL) { - DetectLuaData *luajit = (DetectLuaData *)ptr; + DetectLuaData *lua = (DetectLuaData *)ptr; - if (luajit->buffername) - SCFree(luajit->buffername); - if (luajit->filename) - SCFree(luajit->filename); + if (lua->buffername) + SCFree(lua->buffername); + if (lua->filename) + SCFree(lua->filename); - SCFree(luajit); + SCFree(lua); } } @@ -1114,7 +1114,7 @@ static int LuaMatchTest01(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert http any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1280,7 +1280,7 @@ static int LuaMatchTest02(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert tcp any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert tcp any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1416,7 +1416,7 @@ static int LuaMatchTest03(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert tcp any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert tcp any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1549,7 +1549,7 @@ static int LuaMatchTest04(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert http any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1699,7 +1699,7 @@ static int LuaMatchTest05(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert http any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1854,7 +1854,7 @@ static int LuaMatchTest06(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert http any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" diff --git a/src/detect.h b/src/detect.h index 4277115b5b51..e3f479063075 100644 --- a/src/detect.h +++ b/src/detect.h @@ -529,7 +529,7 @@ typedef struct 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) */ +/** execute flowvar storage even if rule doesn't match (for lua) */ #define DETECT_FLOWVAR_TYPE_ALWAYS 2 /** list for flowvar store candidates, to be stored from From 2b874abada529288fb54e7274b458e980cfb186c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 21 Nov 2016 10:16:14 -0600 Subject: [PATCH 2162/2553] compiler warnings: fix compiler warnings in format strings --- src/log-dnslog.c | 2 +- src/output-tx.c | 4 ++-- src/source-ipfw.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/log-dnslog.c b/src/log-dnslog.c index 51d524a59fcb..54fcf7e342fb 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -170,7 +170,7 @@ static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, Flow *f, { LogDnsLogThread *aft = (LogDnsLogThread *)data; DNSTransaction *dns_tx = (DNSTransaction *)tx; - SCLogDebug("pcap_cnt %ju", p->pcap_cnt); + SCLogDebug("pcap_cnt %"PRIu64, p->pcap_cnt); char timebuf[64]; CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); diff --git a/src/output-tx.c b/src/output-tx.c index 339cd3b4fab8..aac57e524ca5 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -193,7 +193,7 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) "tc_log_progress %d", logger, logger->LogCondition, logger->ts_log_progress, logger->tc_log_progress); if (logger->alproto == alproto) { - SCLogDebug("alproto match, logging tx_id %ju", tx_id); + SCLogDebug("alproto match, logging tx_id %"PRIu64, tx_id); if (AppLayerParserGetTxLogged(p->proto, alproto, alstate, tx, logger->id)) { @@ -243,7 +243,7 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) } if (!logger_not_logged) { - SCLogDebug("updating log tx_id %ju", tx_id); + SCLogDebug("updating log tx_id %"PRIu64, tx_id); AppLayerParserSetTransactionLogId(f->alparser); } } diff --git a/src/source-ipfw.c b/src/source-ipfw.c index e3e0e4986e32..97abf79006d5 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -300,7 +300,7 @@ TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) PacketCopyData(p, pkt, pktlen); SCLogDebug("Packet info: pkt_len: %" PRIu32 " (pkt %02x, pkt_data %02x)", - GET_PKT_LEN(p), *pkt, GET_PKT_DATA(p)); + GET_PKT_LEN(p), *pkt, *(GET_PKT_DATA(p))); if (TmThreadsSlotProcessPkt(tv, ((TmSlot *) slot)->slot_next, p) != TM_ECODE_OK) { From d5eca41a715640d9af3b8229a8dec50fbad3fb22 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 21 Nov 2016 10:24:17 -0600 Subject: [PATCH 2163/2553] ipfw: disable more code to suppress compiler warnings Disabled code lead to unused variable warnings, so disable the variable code as well. --- src/source-ipfw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/source-ipfw.c b/src/source-ipfw.c index 97abf79006d5..05392828b3ff 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -515,7 +515,9 @@ TmEcode DecodeIPFWThreadDeinit(ThreadVars *tv, void *data) TmEcode IPFWSetVerdict(ThreadVars *tv, IPFWThreadVars *ptv, Packet *p) { uint32_t verdict; +#if 0 struct pollfd IPFWpoll; +#endif IPFWQueueVars *nq = NULL; SCEnter(); @@ -531,8 +533,10 @@ TmEcode IPFWSetVerdict(ThreadVars *tv, IPFWThreadVars *ptv, Packet *p) SCReturnInt(TM_ECODE_FAILED); } +#if 0 IPFWpoll.fd = nq->fd; IPFWpoll.events = POLLWRNORM; +#endif if (PACKET_TEST_ACTION(p, ACTION_DROP)) { verdict = IPFW_DROP; From b9ba792279a8bab2255cba960e977e2cc549596c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 7 Nov 2016 10:02:18 -0500 Subject: [PATCH 2164/2553] dns-events: fix direction of malformed events + typo --- rules/dns-events.rules | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rules/dns-events.rules b/rules/dns-events.rules index 693f2f1b3b36..82ee63311368 100644 --- a/rules/dns-events.rules +++ b/rules/dns-events.rules @@ -1,8 +1,8 @@ # Response (answer) we didn't see a Request for. Could be packet loss. -alert dns any any -> any any (msg:"SURICATA DNS Unsollicited response"; flow:to_client; app-layer-event:dns.unsollicited_response; sid:2240001; rev:1;) +alert dns any any -> any any (msg:"SURICATA DNS Unsolicited response"; flow:to_client; app-layer-event:dns.unsollicited_response; sid:2240001; rev:1;) # Malformed data in request. Malformed means length fields are wrong, etc. -alert dns any any -> any any (msg:"SURICATA DNS malformed request data"; flow:to_client; app-layer-event:dns.malformed_data; sid:2240002; rev:1;) -alert dns any any -> any any (msg:"SURICATA DNS malformed response data"; flow:to_server; app-layer-event:dns.malformed_data; sid:2240003; rev:1;) +alert dns any any -> any any (msg:"SURICATA DNS malformed request data"; flow:to_server; app-layer-event:dns.malformed_data; sid:2240002; rev:1;) +alert dns any any -> any any (msg:"SURICATA DNS malformed response data"; flow:to_client; app-layer-event:dns.malformed_data; sid:2240003; rev:1;) # Response flag set on to_server packet alert dns any any -> any any (msg:"SURICATA DNS Not a request"; flow:to_server; app-layer-event:dns.not_a_request; sid:2240004; rev:1;) # Response flag not set on to_client packet From 666fecc5795d57c5bf7c8b619ff5159a4954a95f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 7 Nov 2016 10:46:45 -0500 Subject: [PATCH 2165/2553] dns: accept a data length of 0 without marking as malformed Addresses issue: https://redmine.openinfosecfoundation.org/issues/1924 --- src/app-layer-dns-common.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 31ed2c26852c..81c0e12e617c 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -833,6 +833,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ } const DNSAnswerHeader *head = (DNSAnswerHeader *)data; + uint16_t datalen = ntohs(head->len); data += sizeof(DNSAnswerHeader); @@ -848,7 +849,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ switch (ntohs(head->type)) { case DNS_RECORD_TYPE_A: { - if (ntohs(head->len) == 4) { + if (datalen == 0 || datalen == 4) { //PrintRawDataFp(stdout, data, ntohs(head->len)); //char a[16]; //PrintInet(AF_INET, (const void *)data, a, sizeof(a)); @@ -862,12 +863,12 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ goto bad_data; } - data += ntohs(head->len); + data += datalen; break; } case DNS_RECORD_TYPE_AAAA: { - if (ntohs(head->len) == 16) { + if (datalen == 0 || datalen == 16) { //char a[46]; //PrintInet(AF_INET6, (const void *)data, a, sizeof(a)); //SCLogInfo("AAAA %s TTL %u", a, ntohl(head->ttl)); @@ -880,7 +881,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ goto bad_data; } - data += ntohs(head->len); + data += datalen; break; } case DNS_RECORD_TYPE_MX: From 73a1d047790dac5ef3d336d996be517cc205a5c0 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 8 Nov 2016 10:13:01 -0500 Subject: [PATCH 2166/2553] logging: open application log file in append mode It was being open in read/write mode, which was likely a mistake with append mode being the intention. --- src/util-debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-debug.c b/src/util-debug.c index 5e85e7744f83..b4a13214a210 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -689,7 +689,7 @@ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, iface_ctx->iface = SC_LOG_OP_IFACE_FILE; iface_ctx->type = type; - if ( (iface_ctx->file_d = fopen(file, "w+")) == NULL) { + if ( (iface_ctx->file_d = fopen(file, "a")) == NULL) { printf("Error opening file %s\n", file); goto error; } From fffdc6e3fdbf9e3912ec5e5faf731554f1dcc90f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 8 Nov 2016 12:02:23 -0500 Subject: [PATCH 2167/2553] logging: hook the application log file into rotation --- src/util-debug.c | 30 ++++++++++++++++++++++++++++++ src/util-debug.h | 3 +++ 2 files changed, 33 insertions(+) diff --git a/src/util-debug.c b/src/util-debug.c index b4a13214a210..0bf067c863dd 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -34,6 +34,7 @@ #include "detect.h" #include "packet-queue.h" #include "threadvars.h" +#include "output.h" #include "tm-queuehandlers.h" #include "tm-queues.h" @@ -154,6 +155,11 @@ static inline int SCLogMapLogLevelToSyslogLevel(int log_level) */ static inline void SCLogPrintToStream(FILE *fd, char *msg) { + /* Would only happen if the log file failed to re-open during rotation. */ + if (fd == NULL) { + return; + } + #if defined (OS_WIN32) SCMutexLock(&sc_log_stream_lock); #endif /* OS_WIN32 */ @@ -515,6 +521,24 @@ static SCError SCLogMessageGetBuffer( return SC_ERR_SPRINTF; } +static void SCLogReopen(SCLogOPIfaceCtx *op_iface_ctx) +{ + if (op_iface_ctx->file_d == NULL) { + return; + } + + if (op_iface_ctx->file == NULL) { + return; + } + + fclose(op_iface_ctx->file_d); + op_iface_ctx->file_d = fopen(op_iface_ctx->file, "a"); + if (op_iface_ctx->file_d == NULL) { + SCLogError(SC_ERR_FOPEN, "Erroring re-opening file \"%s\": %s", + op_iface_ctx->file, strerror(errno)); + } +} + /** * \brief Adds the global log_format to the outgoing buffer * @@ -569,6 +593,10 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file, log_level, file, line, function, error_code, message) == 0) { + if (op_iface_ctx->rotation_flag) { + SCLogReopen(op_iface_ctx); + op_iface_ctx->rotation_flag = 0; + } SCLogPrintToStream(op_iface_ctx->file_d, buffer); } break; @@ -702,6 +730,8 @@ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, goto error; } + OutputRegisterFileRotationFlag(&iface_ctx->rotation_flag); + iface_ctx->log_level = log_level; return iface_ctx; diff --git a/src/util-debug.h b/src/util-debug.h index 48d9eee9568b..46157763e1e9 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -127,6 +127,9 @@ typedef struct SCLogOPIfaceCtx_ { /* the output file descriptor for the above file */ FILE * file_d; + /* registered to be set on a file rotation signal */ + int rotation_flag; + /* the facility code if the interface is SC_LOG_IFACE_SYSLOG */ int facility; From a2e2f50fb933d9d6a0c15b23d28a71b5fc80ff13 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 9 Nov 2016 14:08:07 -0500 Subject: [PATCH 2168/2553] documentation: fix list keywords URLs Update URLs in keyword definition to point to sphinx documentation. --- src/detect-ack.c | 2 +- src/detect-base64-data.c | 2 +- src/detect-base64-decode.c | 2 +- src/detect-classtype.c | 2 +- src/detect-content.c | 2 +- src/detect-depth.c | 2 +- src/detect-detection-filter.c | 2 +- src/detect-distance.c | 2 +- src/detect-dsize.c | 2 +- src/detect-fast-pattern.c | 2 +- src/detect-file-data.c | 2 +- src/detect-fileext.c | 2 +- src/detect-filemagic.c | 2 +- src/detect-filemd5.c | 2 +- src/detect-filename.c | 2 +- src/detect-filesha1.c | 2 +- src/detect-filesha256.c | 2 +- src/detect-filesize.c | 2 +- src/detect-filestore.c | 2 +- src/detect-flow.c | 2 +- src/detect-flowbits.c | 2 +- src/detect-flowint.c | 2 +- src/detect-fragbits.c | 2 +- src/detect-fragoffset.c | 2 +- src/detect-gid.c | 2 +- src/detect-hostbits.c | 2 +- src/detect-http-client-body.c | 2 +- src/detect-http-cookie.c | 2 +- src/detect-http-header.c | 2 +- src/detect-http-method.c | 2 +- src/detect-http-raw-uri.c | 2 +- src/detect-http-request-line.c | 2 +- src/detect-http-response-line.c | 2 +- src/detect-http-server-body.c | 2 +- src/detect-http-stat-code.c | 2 +- src/detect-http-stat-msg.c | 2 +- src/detect-http-ua.c | 2 +- src/detect-http-uri.c | 2 +- src/detect-icmp-id.c | 2 +- src/detect-icmp-seq.c | 2 +- src/detect-icode.c | 2 +- src/detect-id.c | 2 +- src/detect-ipopts.c | 2 +- src/detect-ipproto.c | 2 +- src/detect-isdataat.c | 2 +- src/detect-itype.c | 2 +- src/detect-metadata.c | 2 +- src/detect-msg.c | 2 +- src/detect-nocase.c | 2 +- src/detect-offset.c | 2 +- src/detect-pcre.c | 2 +- src/detect-priority.c | 2 +- src/detect-reference.c | 2 +- src/detect-rev.c | 2 +- src/detect-rpc.c | 2 +- src/detect-sameip.c | 2 +- src/detect-seq.c | 2 +- src/detect-sid.c | 2 +- src/detect-stream_size.c | 2 +- src/detect-threshold.c | 2 +- src/detect-tls-cert-validity.c | 8 ++++---- src/detect-tls-version.c | 2 +- src/detect-tls.c | 8 ++++---- src/detect-ttl.c | 2 +- src/detect-urilen.c | 2 +- src/detect-window.c | 2 +- src/detect-within.c | 2 +- src/detect-xbits.c | 2 +- src/suricata.h | 8 ++++++++ 69 files changed, 82 insertions(+), 74 deletions(-) diff --git a/src/detect-ack.c b/src/detect-ack.c index 0ea0dc285ac1..aaef98a96428 100644 --- a/src/detect-ack.c +++ b/src/detect-ack.c @@ -55,7 +55,7 @@ void DetectAckRegister(void) { sigmatch_table[DETECT_ACK].name = "ack"; sigmatch_table[DETECT_ACK].desc = "check for a specific TCP acknowledgement number"; - sigmatch_table[DETECT_ACK].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#ack"; + sigmatch_table[DETECT_ACK].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#ack"; sigmatch_table[DETECT_ACK].Match = DetectAckMatch; sigmatch_table[DETECT_ACK].Setup = DetectAckSetup; sigmatch_table[DETECT_ACK].Free = DetectAckFree; diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c index 107b90ca42fe..ce54f1d661fc 100644 --- a/src/detect-base64-data.c +++ b/src/detect-base64-data.c @@ -31,7 +31,7 @@ void DetectBase64DataRegister(void) sigmatch_table[DETECT_BASE64_DATA].desc = "Content match base64 decoded data."; sigmatch_table[DETECT_BASE64_DATA].url = - "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#base64_data"; + DOC_URL DOC_VERSION "/rules/payload-keywords.html#base64-data"; sigmatch_table[DETECT_BASE64_DATA].Setup = DetectBase64DataSetup; sigmatch_table[DETECT_BASE64_DATA].RegisterTests = DetectBase64DataRegisterTests; diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index 25010e43644a..d0687780d434 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -42,7 +42,7 @@ void DetectBase64DecodeRegister(void) sigmatch_table[DETECT_BASE64_DECODE].desc = "Decodes base64 encoded data."; sigmatch_table[DETECT_BASE64_DECODE].url = - "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#base64_decode"; + DOC_URL DOC_VERSION "/rules/payload-keywords.html#base64-decode"; sigmatch_table[DETECT_BASE64_DECODE].Setup = DetectBase64DecodeSetup; sigmatch_table[DETECT_BASE64_DECODE].Free = DetectBase64DecodeFree; sigmatch_table[DETECT_BASE64_DECODE].RegisterTests = diff --git a/src/detect-classtype.c b/src/detect-classtype.c index c1ce60774468..547f3a0f3ff6 100644 --- a/src/detect-classtype.c +++ b/src/detect-classtype.c @@ -52,7 +52,7 @@ void DetectClasstypeRegister(void) { sigmatch_table[DETECT_CLASSTYPE].name = "classtype"; sigmatch_table[DETECT_CLASSTYPE].desc = "information about the classification of rules and alerts"; - sigmatch_table[DETECT_CLASSTYPE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Classtype"; + sigmatch_table[DETECT_CLASSTYPE].url = DOC_URL DOC_VERSION "/rules/meta.html#classtype"; sigmatch_table[DETECT_CLASSTYPE].Match = NULL; sigmatch_table[DETECT_CLASSTYPE].Setup = DetectClasstypeSetup; sigmatch_table[DETECT_CLASSTYPE].Free = NULL; diff --git a/src/detect-content.c b/src/detect-content.c index 18050bd34e2b..a62b4e274bdf 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -56,7 +56,7 @@ void DetectContentRegister (void) { sigmatch_table[DETECT_CONTENT].name = "content"; sigmatch_table[DETECT_CONTENT].desc = "match on payload content"; - sigmatch_table[DETECT_CONTENT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Content"; + sigmatch_table[DETECT_CONTENT].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#content"; sigmatch_table[DETECT_CONTENT].Match = NULL; sigmatch_table[DETECT_CONTENT].Setup = DetectContentSetup; sigmatch_table[DETECT_CONTENT].Free = DetectContentFree; diff --git a/src/detect-depth.c b/src/detect-depth.c index 90661e61aa6d..e2b098c1ca13 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -45,7 +45,7 @@ void DetectDepthRegister (void) { sigmatch_table[DETECT_DEPTH].name = "depth"; sigmatch_table[DETECT_DEPTH].desc = "designate how many bytes from the beginning of the payload will be checked"; - sigmatch_table[DETECT_DEPTH].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Depth"; + sigmatch_table[DETECT_DEPTH].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#depth"; sigmatch_table[DETECT_DEPTH].Match = NULL; sigmatch_table[DETECT_DEPTH].Setup = DetectDepthSetup; sigmatch_table[DETECT_DEPTH].Free = NULL; diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 32e39393f473..e69d66fada3d 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -63,7 +63,7 @@ void DetectDetectionFilterRegister (void) { sigmatch_table[DETECT_DETECTION_FILTER].name = "detection_filter"; sigmatch_table[DETECT_DETECTION_FILTER].desc = "alert on every match after a threshold has been reached"; - sigmatch_table[DETECT_DETECTION_FILTER].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Rule-Thresholding#detection_filter"; + sigmatch_table[DETECT_DETECTION_FILTER].url = DOC_URL DOC_VERSION "/rules/thresholding.html#detection-filter"; sigmatch_table[DETECT_DETECTION_FILTER].Match = DetectDetectionFilterMatch; sigmatch_table[DETECT_DETECTION_FILTER].Setup = DetectDetectionFilterSetup; sigmatch_table[DETECT_DETECTION_FILTER].Free = DetectDetectionFilterFree; diff --git a/src/detect-distance.c b/src/detect-distance.c index 6f1c492052d0..bac5a3cafab0 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -52,7 +52,7 @@ void DetectDistanceRegister(void) { sigmatch_table[DETECT_DISTANCE].name = "distance"; sigmatch_table[DETECT_DISTANCE].desc = "indicates a relation between this content keyword and the content preceding it"; - sigmatch_table[DETECT_DISTANCE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Distance"; + sigmatch_table[DETECT_DISTANCE].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#distance"; sigmatch_table[DETECT_DISTANCE].Match = NULL; sigmatch_table[DETECT_DISTANCE].Setup = DetectDistanceSetup; sigmatch_table[DETECT_DISTANCE].Free = NULL; diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 6eb7d1b5aa6f..548ac3ced34f 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -64,7 +64,7 @@ void DetectDsizeRegister (void) { sigmatch_table[DETECT_DSIZE].name = "dsize"; sigmatch_table[DETECT_DSIZE].desc = "match on the size of the packet payload"; - sigmatch_table[DETECT_DSIZE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Dsize"; + sigmatch_table[DETECT_DSIZE].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#dsize"; sigmatch_table[DETECT_DSIZE].Match = DetectDsizeMatch; sigmatch_table[DETECT_DSIZE].Setup = DetectDsizeSetup; sigmatch_table[DETECT_DSIZE].Free = DetectDsizeFree; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 6eeda8044d66..c4cb73dd0bc2 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -130,7 +130,7 @@ void DetectFastPatternRegister(void) { sigmatch_table[DETECT_FAST_PATTERN].name = "fast_pattern"; sigmatch_table[DETECT_FAST_PATTERN].desc = "force using preceding content in the multi pattern matcher"; - sigmatch_table[DETECT_FAST_PATTERN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#fast_pattern"; + sigmatch_table[DETECT_FAST_PATTERN].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#fast-pattern"; sigmatch_table[DETECT_FAST_PATTERN].Match = NULL; sigmatch_table[DETECT_FAST_PATTERN].Setup = DetectFastPatternSetup; sigmatch_table[DETECT_FAST_PATTERN].Free = NULL; diff --git a/src/detect-file-data.c b/src/detect-file-data.c index ac518362d37d..1d9a5f4ee30b 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -55,7 +55,7 @@ void DetectFiledataRegister(void) { sigmatch_table[DETECT_FILE_DATA].name = "file_data"; sigmatch_table[DETECT_FILE_DATA].desc = "make content keywords match on HTTP response body"; - sigmatch_table[DETECT_FILE_DATA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#file_data"; + sigmatch_table[DETECT_FILE_DATA].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#file-data"; sigmatch_table[DETECT_FILE_DATA].Match = NULL; sigmatch_table[DETECT_FILE_DATA].AppLayerMatch = NULL; sigmatch_table[DETECT_FILE_DATA].Setup = DetectFiledataSetup; diff --git a/src/detect-fileext.c b/src/detect-fileext.c index 4416d3787318..568c97802ab3 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -64,7 +64,7 @@ void DetectFileextRegister(void) { sigmatch_table[DETECT_FILEEXT].name = "fileext"; sigmatch_table[DETECT_FILEEXT].desc = "match on the extension of a file name"; - sigmatch_table[DETECT_FILEEXT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#fileext"; + sigmatch_table[DETECT_FILEEXT].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#fileext"; sigmatch_table[DETECT_FILEEXT].FileMatch = DetectFileextMatch; sigmatch_table[DETECT_FILEEXT].Setup = DetectFileextSetup; sigmatch_table[DETECT_FILEEXT].Free = DetectFileextFree; diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 76b0e0ce797f..44386939bef2 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -67,7 +67,7 @@ void DetectFilemagicRegister(void) { sigmatch_table[DETECT_FILEMAGIC].name = "filemagic"; sigmatch_table[DETECT_FILEMAGIC].desc = "match on the information libmagic returns about a file"; - sigmatch_table[DETECT_FILEMAGIC].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemagic"; + sigmatch_table[DETECT_FILEMAGIC].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filemagic"; sigmatch_table[DETECT_FILEMAGIC].FileMatch = DetectFilemagicMatch; sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetup; sigmatch_table[DETECT_FILEMAGIC].Free = DetectFilemagicFree; diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index c5cf4c192401..8f1b43d1975e 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -66,7 +66,7 @@ void DetectFileMd5Register(void) { sigmatch_table[DETECT_FILEMD5].name = "filemd5"; sigmatch_table[DETECT_FILEMD5].desc = "match file MD5 against list of MD5 checksums"; - sigmatch_table[DETECT_FILEMD5].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemd5"; + sigmatch_table[DETECT_FILEMD5].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filemd5"; sigmatch_table[DETECT_FILEMD5].FileMatch = DetectFileHashMatch; sigmatch_table[DETECT_FILEMD5].Setup = DetectFileMd5Setup; sigmatch_table[DETECT_FILEMD5].Free = DetectFileHashFree; diff --git a/src/detect-filename.c b/src/detect-filename.c index ce89d0caf871..35b27d17b45a 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -65,7 +65,7 @@ void DetectFilenameRegister(void) { sigmatch_table[DETECT_FILENAME].name = "filename"; sigmatch_table[DETECT_FILENAME].desc = "match on the file name"; - sigmatch_table[DETECT_FILENAME].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filename"; + sigmatch_table[DETECT_FILENAME].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filename"; sigmatch_table[DETECT_FILENAME].FileMatch = DetectFilenameMatch; sigmatch_table[DETECT_FILENAME].Setup = DetectFilenameSetup; sigmatch_table[DETECT_FILENAME].Free = DetectFilenameFree; diff --git a/src/detect-filesha1.c b/src/detect-filesha1.c index ad1886648849..22196bda9336 100644 --- a/src/detect-filesha1.c +++ b/src/detect-filesha1.c @@ -67,7 +67,7 @@ void DetectFileSha1Register(void) { sigmatch_table[DETECT_FILESHA1].name = "filesha1"; sigmatch_table[DETECT_FILESHA1].desc = "match file SHA-1 against list of SHA-1 checksums"; - sigmatch_table[DETECT_FILESHA1].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filesha1"; + sigmatch_table[DETECT_FILESHA1].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filesha1"; sigmatch_table[DETECT_FILESHA1].FileMatch = DetectFileHashMatch; sigmatch_table[DETECT_FILESHA1].Setup = DetectFileSha1Setup; sigmatch_table[DETECT_FILESHA1].Free = DetectFileHashFree; diff --git a/src/detect-filesha256.c b/src/detect-filesha256.c index 4310445080c4..0a58e33a3091 100644 --- a/src/detect-filesha256.c +++ b/src/detect-filesha256.c @@ -67,7 +67,7 @@ void DetectFileSha256Register(void) { sigmatch_table[DETECT_FILESHA256].name = "filesha256"; sigmatch_table[DETECT_FILESHA256].desc = "match file SHA-256 against list of SHA-256 checksums"; - sigmatch_table[DETECT_FILESHA256].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filesha256"; + sigmatch_table[DETECT_FILESHA256].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filesha256"; sigmatch_table[DETECT_FILESHA256].FileMatch = DetectFileHashMatch; sigmatch_table[DETECT_FILESHA256].Setup = DetectFileSha256Setup; sigmatch_table[DETECT_FILESHA256].Free = DetectFileHashFree; diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 416cb467849d..142baa02ae48 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -62,7 +62,7 @@ void DetectFilesizeRegister(void) { sigmatch_table[DETECT_FILESIZE].name = "filesize"; sigmatch_table[DETECT_FILESIZE].desc = "match on the size of the file as it is being transferred"; - sigmatch_table[DETECT_FILESIZE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filesize"; + sigmatch_table[DETECT_FILESIZE].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filesize"; sigmatch_table[DETECT_FILESIZE].FileMatch = DetectFilesizeMatch; sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup; sigmatch_table[DETECT_FILESIZE].Free = DetectFilesizeFree; diff --git a/src/detect-filestore.c b/src/detect-filestore.c index efbeda0deca1..ab096573fd7d 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -72,7 +72,7 @@ void DetectFilestoreRegister(void) { sigmatch_table[DETECT_FILESTORE].name = "filestore"; sigmatch_table[DETECT_FILESTORE].desc = "stores files to disk if the rule matched"; - sigmatch_table[DETECT_FILESTORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filestore"; + sigmatch_table[DETECT_FILESTORE].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filestore"; sigmatch_table[DETECT_FILESTORE].FileMatch = DetectFilestoreMatch; sigmatch_table[DETECT_FILESTORE].Setup = DetectFilestoreSetup; sigmatch_table[DETECT_FILESTORE].Free = DetectFilestoreFree; diff --git a/src/detect-flow.c b/src/detect-flow.c index 3e3455c548cf..376944f67886 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -64,7 +64,7 @@ void DetectFlowRegister (void) { sigmatch_table[DETECT_FLOW].name = "flow"; sigmatch_table[DETECT_FLOW].desc = "match on direction and state of the flow"; - sigmatch_table[DETECT_FLOW].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flow"; + sigmatch_table[DETECT_FLOW].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#flow"; sigmatch_table[DETECT_FLOW].Match = DetectFlowMatch; sigmatch_table[DETECT_FLOW].Setup = DetectFlowSetup; sigmatch_table[DETECT_FLOW].Free = DetectFlowFree; diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 6745bda54d8b..9b1af1781124 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -58,7 +58,7 @@ void DetectFlowbitsRegister (void) { sigmatch_table[DETECT_FLOWBITS].name = "flowbits"; sigmatch_table[DETECT_FLOWBITS].desc = "operate on flow flag"; - sigmatch_table[DETECT_FLOWBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flowbits"; + sigmatch_table[DETECT_FLOWBITS].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#flowbits"; sigmatch_table[DETECT_FLOWBITS].Match = DetectFlowbitMatch; sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup; sigmatch_table[DETECT_FLOWBITS].Free = DetectFlowbitFree; diff --git a/src/detect-flowint.c b/src/detect-flowint.c index cdc8851c870f..8b0389ef9617 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -63,7 +63,7 @@ void DetectFlowintRegister(void) { sigmatch_table[DETECT_FLOWINT].name = "flowint"; sigmatch_table[DETECT_FLOWINT].desc = "operate on a per-flow integer"; - sigmatch_table[DETECT_FLOWINT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flowint"; + sigmatch_table[DETECT_FLOWINT].url = DOC_URL DOC_VERSION "/rules/flowint.html"; sigmatch_table[DETECT_FLOWINT].Match = DetectFlowintMatch; sigmatch_table[DETECT_FLOWINT].Setup = DetectFlowintSetup; sigmatch_table[DETECT_FLOWINT].Free = DetectFlowintFree; diff --git a/src/detect-fragbits.c b/src/detect-fragbits.c index 293b0fdb2c11..5c0e014ab76c 100644 --- a/src/detect-fragbits.c +++ b/src/detect-fragbits.c @@ -83,7 +83,7 @@ void DetectFragBitsRegister (void) { sigmatch_table[DETECT_FRAGBITS].name = "fragbits"; sigmatch_table[DETECT_FRAGBITS].desc = "check if the fragmentation and reserved bits are set in the IP header"; - sigmatch_table[DETECT_FRAGBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Fragbits"; + sigmatch_table[DETECT_FRAGBITS].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#fragbits"; sigmatch_table[DETECT_FRAGBITS].Match = DetectFragBitsMatch; sigmatch_table[DETECT_FRAGBITS].Setup = DetectFragBitsSetup; sigmatch_table[DETECT_FRAGBITS].Free = DetectFragBitsFree; diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index 20277ade5592..aa43ced0a57b 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -59,7 +59,7 @@ void DetectFragOffsetRegister (void) { sigmatch_table[DETECT_FRAGOFFSET].name = "fragoffset"; sigmatch_table[DETECT_FRAGOFFSET].desc = "match on specific decimal values of the IP fragment offset field"; - sigmatch_table[DETECT_FRAGOFFSET].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Fragoffset"; + sigmatch_table[DETECT_FRAGOFFSET].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#fragoffset"; sigmatch_table[DETECT_FRAGOFFSET].Match = DetectFragOffsetMatch; sigmatch_table[DETECT_FRAGOFFSET].Setup = DetectFragOffsetSetup; sigmatch_table[DETECT_FRAGOFFSET].Free = DetectFragOffsetFree; diff --git a/src/detect-gid.c b/src/detect-gid.c index 3344fe37997d..5fe93e494c86 100644 --- a/src/detect-gid.c +++ b/src/detect-gid.c @@ -46,7 +46,7 @@ void DetectGidRegister (void) { sigmatch_table[DETECT_GID].name = "gid"; sigmatch_table[DETECT_GID].desc = "give different groups of signatures another id value"; - sigmatch_table[DETECT_GID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Gid-group-id"; + sigmatch_table[DETECT_GID].url = DOC_URL DOC_VERSION "/rules/meta.html#gid-group-id"; sigmatch_table[DETECT_GID].Match = NULL; sigmatch_table[DETECT_GID].Setup = DetectGidSetup; sigmatch_table[DETECT_GID].Free = NULL; diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 5d5863b1b7b7..229d7ada1ab8 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -77,7 +77,7 @@ void DetectHostbitsRegister (void) { sigmatch_table[DETECT_HOSTBITS].name = "hostbits"; sigmatch_table[DETECT_HOSTBITS].desc = "operate on host flag"; -// sigmatch_table[DETECT_HOSTBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flowbits"; +// sigmatch_table[DETECT_HOSTBITS].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#flowbits"; sigmatch_table[DETECT_HOSTBITS].Match = DetectHostbitMatch; sigmatch_table[DETECT_HOSTBITS].Setup = DetectHostbitSetup; sigmatch_table[DETECT_HOSTBITS].Free = DetectHostbitFree; diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 8d3afd3548b2..f805fda82f28 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -69,7 +69,7 @@ void DetectHttpClientBodyRegister(void) { sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].name = "http_client_body"; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].desc = "content modifier to match only on HTTP request-body"; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_client_body"; + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_client-body"; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Match = NULL; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Setup = DetectHttpClientBodySetup; diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index fe0ba43564a3..104d39d9a77a 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -72,7 +72,7 @@ void DetectHttpCookieRegister(void) { sigmatch_table[DETECT_AL_HTTP_COOKIE].name = "http_cookie"; sigmatch_table[DETECT_AL_HTTP_COOKIE].desc = "content modifier to match only on the HTTP cookie-buffer"; - sigmatch_table[DETECT_AL_HTTP_COOKIE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_cookie"; + sigmatch_table[DETECT_AL_HTTP_COOKIE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-cookie"; sigmatch_table[DETECT_AL_HTTP_COOKIE].Match = NULL; sigmatch_table[DETECT_AL_HTTP_COOKIE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_COOKIE].Setup = DetectHttpCookieSetup; diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 8ff357a3701c..8d3e6b81899b 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -71,7 +71,7 @@ void DetectHttpHeaderRegister(void) { sigmatch_table[DETECT_AL_HTTP_HEADER].name = "http_header"; sigmatch_table[DETECT_AL_HTTP_HEADER].desc = "content modifier to match only on the HTTP header-buffer"; - sigmatch_table[DETECT_AL_HTTP_HEADER].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_header"; + sigmatch_table[DETECT_AL_HTTP_HEADER].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-header"; sigmatch_table[DETECT_AL_HTTP_HEADER].Match = NULL; sigmatch_table[DETECT_AL_HTTP_HEADER].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_HEADER].Setup = DetectHttpHeaderSetup; diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 07d448d0f095..0f12b35784ba 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -72,7 +72,7 @@ void DetectHttpMethodRegister(void) { sigmatch_table[DETECT_AL_HTTP_METHOD].name = "http_method"; sigmatch_table[DETECT_AL_HTTP_METHOD].desc = "content modifier to match only on the HTTP method-buffer"; - sigmatch_table[DETECT_AL_HTTP_METHOD].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_method"; + sigmatch_table[DETECT_AL_HTTP_METHOD].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-method"; sigmatch_table[DETECT_AL_HTTP_METHOD].Match = NULL; sigmatch_table[DETECT_AL_HTTP_METHOD].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_METHOD].Setup = DetectHttpMethodSetup; diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 5782fdf3d34d..2ef9a1a72f4d 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -65,7 +65,7 @@ void DetectHttpRawUriRegister(void) { sigmatch_table[DETECT_AL_HTTP_RAW_URI].name = "http_raw_uri"; sigmatch_table[DETECT_AL_HTTP_RAW_URI].desc = "content modifier to match on HTTP uri"; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_uri-and-http_raw_uri"; + sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_uri-and-http_raw-uri"; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Match = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Setup = DetectHttpRawUriSetup; diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 9a27ee6fdb55..4d9cf2795dba 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -77,7 +77,7 @@ void DetectHttpRequestLineRegister(void) { sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].name = "http_request_line"; sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].desc = "content modifier to match only on the HTTP request line"; - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_request_line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_request-line"; sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Match = NULL; sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Setup = DetectHttpRequestLineSetup; diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index 70d5de472454..8887ce979ae7 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -78,7 +78,7 @@ void DetectHttpResponseLineRegister(void) { sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].name = "http_response_line"; sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].desc = "content modifier to match only on the HTTP response line"; - sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_response_line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_response-line"; sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].Match = NULL; sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].Setup = DetectHttpResponseLineSetup; diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index 1f2b3113edea..5971ed3d5681 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -70,7 +70,7 @@ void DetectHttpServerBodyRegister(void) { sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].name = "http_server_body"; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].desc = "content modifier to match only on the HTTP response-body"; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_server_body"; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_server-body"; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Match = NULL; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Setup = DetectHttpServerBodySetup; diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index 1cd484bc9bc0..a67bf26ed400 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -77,7 +77,7 @@ void DetectHttpStatCodeRegister (void) { sigmatch_table[DETECT_AL_HTTP_STAT_CODE].name = "http_stat_code"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].desc = "content modifier to match only on HTTP stat-code-buffer"; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_stat_code"; + sigmatch_table[DETECT_AL_HTTP_STAT_CODE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_stat-code"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Match = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetup; diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index cbaa4a7f5886..2207d13b61e5 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -77,7 +77,7 @@ void DetectHttpStatMsgRegister (void) { sigmatch_table[DETECT_AL_HTTP_STAT_MSG].name = "http_stat_msg"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].desc = "content modifier to match on HTTP stat-msg-buffer"; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_stat_msg"; + sigmatch_table[DETECT_AL_HTTP_STAT_MSG].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_stat-msg"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Match = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetup; diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index 26b51407574a..c500387cc127 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -70,7 +70,7 @@ void DetectHttpUARegister(void) { sigmatch_table[DETECT_AL_HTTP_USER_AGENT].name = "http_user_agent"; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].desc = "content modifier to match only on the HTTP User-Agent header"; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_user_agent"; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_user-agent"; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Match = NULL; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Setup = DetectHttpUASetup; diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 7c45260cec6e..11d8f2c3d0db 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -66,7 +66,7 @@ void DetectHttpUriRegister (void) { sigmatch_table[DETECT_AL_HTTP_URI].name = "http_uri"; sigmatch_table[DETECT_AL_HTTP_URI].desc = "content modifier to match specifically and only on the HTTP uri-buffer"; - sigmatch_table[DETECT_AL_HTTP_URI].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_uri-and-http_raw_uri"; + sigmatch_table[DETECT_AL_HTTP_URI].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_uri-and-http_raw-uri"; sigmatch_table[DETECT_AL_HTTP_URI].Match = NULL; sigmatch_table[DETECT_AL_HTTP_URI].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_URI].Setup = DetectHttpUriSetup; diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index 820d276cf1fb..22acfb3356b3 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -57,7 +57,7 @@ void DetectIcmpIdRegister (void) { sigmatch_table[DETECT_ICMP_ID].name = "icmp_id"; sigmatch_table[DETECT_ICMP_ID].desc = "check for a ICMP id"; - sigmatch_table[DETECT_ICMP_ID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#icmp_id"; + sigmatch_table[DETECT_ICMP_ID].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#icmp-id"; sigmatch_table[DETECT_ICMP_ID].Match = DetectIcmpIdMatch; sigmatch_table[DETECT_ICMP_ID].Setup = DetectIcmpIdSetup; sigmatch_table[DETECT_ICMP_ID].Free = DetectIcmpIdFree; diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index 017e562560d0..9ddd4e6b36cd 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -57,7 +57,7 @@ void DetectIcmpSeqRegister (void) { sigmatch_table[DETECT_ICMP_SEQ].name = "icmp_seq"; sigmatch_table[DETECT_ICMP_SEQ].desc = "check for a ICMP sequence number"; - sigmatch_table[DETECT_ICMP_SEQ].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#icmp_seq"; + sigmatch_table[DETECT_ICMP_SEQ].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#icmp-seq"; sigmatch_table[DETECT_ICMP_SEQ].Match = DetectIcmpSeqMatch; sigmatch_table[DETECT_ICMP_SEQ].Setup = DetectIcmpSeqSetup; sigmatch_table[DETECT_ICMP_SEQ].Free = DetectIcmpSeqFree; diff --git a/src/detect-icode.c b/src/detect-icode.c index ef3c92e94d67..8468c3aff67e 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -61,7 +61,7 @@ void DetectICodeRegister (void) { sigmatch_table[DETECT_ICODE].name = "icode"; sigmatch_table[DETECT_ICODE].desc = "match on specific ICMP id-value"; - sigmatch_table[DETECT_ICODE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#icode"; + sigmatch_table[DETECT_ICODE].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#icode"; sigmatch_table[DETECT_ICODE].Match = DetectICodeMatch; sigmatch_table[DETECT_ICODE].Setup = DetectICodeSetup; sigmatch_table[DETECT_ICODE].Free = DetectICodeFree; diff --git a/src/detect-id.c b/src/detect-id.c index 5a1b18ec5c7c..de2e21dd6194 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -65,7 +65,7 @@ void DetectIdRegister (void) { sigmatch_table[DETECT_ID].name = "id"; sigmatch_table[DETECT_ID].desc = "match on a specific IP ID value"; - sigmatch_table[DETECT_ID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Id"; + sigmatch_table[DETECT_ID].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#id"; sigmatch_table[DETECT_ID].Match = DetectIdMatch; sigmatch_table[DETECT_ID].Setup = DetectIdSetup; sigmatch_table[DETECT_ID].Free = DetectIdFree; diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index d861b21909de..21e8a4aa52de 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -55,7 +55,7 @@ void DetectIpOptsRegister (void) { sigmatch_table[DETECT_IPOPTS].name = "ipopts"; sigmatch_table[DETECT_IPOPTS].desc = "check if a specific IP option is set"; - sigmatch_table[DETECT_IPOPTS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Ipopts"; + sigmatch_table[DETECT_IPOPTS].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#ipopts"; sigmatch_table[DETECT_IPOPTS].Match = DetectIpOptsMatch; sigmatch_table[DETECT_IPOPTS].Setup = DetectIpOptsSetup; sigmatch_table[DETECT_IPOPTS].Free = DetectIpOptsFree; diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index dec6ad3ab5f4..b60effaedba2 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -63,7 +63,7 @@ void DetectIPProtoRegister(void) { sigmatch_table[DETECT_IPPROTO].name = "ip_proto"; sigmatch_table[DETECT_IPPROTO].desc = "match on the IP protocol in the packet-header"; - sigmatch_table[DETECT_IPPROTO].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#ip_proto"; + sigmatch_table[DETECT_IPPROTO].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#ip-proto"; sigmatch_table[DETECT_IPPROTO].Match = NULL; sigmatch_table[DETECT_IPPROTO].Setup = DetectIPProtoSetup; sigmatch_table[DETECT_IPPROTO].Free = DetectIPProtoFree; diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 0d81d70c5424..be09d5edcf9f 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -66,7 +66,7 @@ void DetectIsdataatRegister(void) { sigmatch_table[DETECT_ISDATAAT].name = "isdataat"; sigmatch_table[DETECT_ISDATAAT].desc = "check if there is still data at a specific part of the payload"; - sigmatch_table[DETECT_ISDATAAT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Isadataat"; + sigmatch_table[DETECT_ISDATAAT].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#isadataat"; /* match is handled in DetectEngineContentInspection() */ sigmatch_table[DETECT_ISDATAAT].Match = NULL; sigmatch_table[DETECT_ISDATAAT].Setup = DetectIsdataatSetup; diff --git a/src/detect-itype.c b/src/detect-itype.c index f453a11520ed..35b962d53fa1 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -61,7 +61,7 @@ void DetectITypeRegister (void) { sigmatch_table[DETECT_ITYPE].name = "itype"; sigmatch_table[DETECT_ITYPE].desc = "matching on a specific ICMP type"; - sigmatch_table[DETECT_ITYPE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#itype"; + sigmatch_table[DETECT_ITYPE].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#itype"; sigmatch_table[DETECT_ITYPE].Match = DetectITypeMatch; sigmatch_table[DETECT_ITYPE].Setup = DetectITypeSetup; sigmatch_table[DETECT_ITYPE].Free = DetectITypeFree; diff --git a/src/detect-metadata.c b/src/detect-metadata.c index 3055ec78867e..d5b46949d93f 100644 --- a/src/detect-metadata.c +++ b/src/detect-metadata.c @@ -35,7 +35,7 @@ void DetectMetadataRegister (void) { sigmatch_table[DETECT_METADATA].name = "metadata"; sigmatch_table[DETECT_METADATA].desc = "ignored by suricata"; - sigmatch_table[DETECT_METADATA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Metadata"; + sigmatch_table[DETECT_METADATA].url = DOC_URL DOC_VERSION "/rules/meta.html#metadata"; sigmatch_table[DETECT_METADATA].Match = NULL; sigmatch_table[DETECT_METADATA].Setup = DetectMetadataSetup; sigmatch_table[DETECT_METADATA].Free = NULL; diff --git a/src/detect-msg.c b/src/detect-msg.c index 31484511a902..314a2f21b5f2 100644 --- a/src/detect-msg.c +++ b/src/detect-msg.c @@ -40,7 +40,7 @@ void DetectMsgRegister (void) { sigmatch_table[DETECT_MSG].name = "msg"; sigmatch_table[DETECT_MSG].desc = "information about the rule and the possible alert"; - sigmatch_table[DETECT_MSG].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#msg-message"; + sigmatch_table[DETECT_MSG].url = DOC_URL DOC_VERSION "/rules/meta.html#msg-message"; sigmatch_table[DETECT_MSG].Match = NULL; sigmatch_table[DETECT_MSG].Setup = DetectMsgSetup; sigmatch_table[DETECT_MSG].Free = NULL; diff --git a/src/detect-nocase.c b/src/detect-nocase.c index b9dbda34cf54..91bf45cc840d 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -48,7 +48,7 @@ void DetectNocaseRegister(void) { sigmatch_table[DETECT_NOCASE].name = "nocase"; sigmatch_table[DETECT_NOCASE].desc = "modify content match to be case insensitive"; - sigmatch_table[DETECT_NOCASE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Nocase"; + sigmatch_table[DETECT_NOCASE].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#nocase"; sigmatch_table[DETECT_NOCASE].Match = NULL; sigmatch_table[DETECT_NOCASE].Setup = DetectNocaseSetup; sigmatch_table[DETECT_NOCASE].Free = NULL; diff --git a/src/detect-offset.c b/src/detect-offset.c index e13de7f602a0..b448f1db2512 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -45,7 +45,7 @@ void DetectOffsetRegister (void) { sigmatch_table[DETECT_OFFSET].name = "offset"; sigmatch_table[DETECT_OFFSET].desc = "designate from which byte in the payload will be checked to find a match"; - sigmatch_table[DETECT_OFFSET].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Offset"; + sigmatch_table[DETECT_OFFSET].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#offset"; sigmatch_table[DETECT_OFFSET].Match = NULL; sigmatch_table[DETECT_OFFSET].Setup = DetectOffsetSetup; sigmatch_table[DETECT_OFFSET].Free = NULL; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index c9733deb6210..c43981ff6ab8 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -88,7 +88,7 @@ void DetectPcreRegister (void) { sigmatch_table[DETECT_PCRE].name = "pcre"; sigmatch_table[DETECT_PCRE].desc = "match on regular expression"; - sigmatch_table[DETECT_PCRE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#Pcre-Perl-Compatible-Regular-Expressions"; + sigmatch_table[DETECT_PCRE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#pcre-perl-compatible-regular-expressions"; sigmatch_table[DETECT_PCRE].Match = NULL; sigmatch_table[DETECT_PCRE].AppLayerMatch = NULL; sigmatch_table[DETECT_PCRE].Setup = DetectPcreSetup; diff --git a/src/detect-priority.c b/src/detect-priority.c index 2a7a80b5365e..e4b10740ecae 100644 --- a/src/detect-priority.c +++ b/src/detect-priority.c @@ -48,7 +48,7 @@ void DetectPriorityRegister (void) { sigmatch_table[DETECT_PRIORITY].name = "priority"; sigmatch_table[DETECT_PRIORITY].desc = "rules with a higher priority will be examined first"; - sigmatch_table[DETECT_PRIORITY].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Priority"; + sigmatch_table[DETECT_PRIORITY].url = DOC_URL DOC_VERSION "/rules/meta.html#priority"; sigmatch_table[DETECT_PRIORITY].Match = NULL; sigmatch_table[DETECT_PRIORITY].Setup = DetectPrioritySetup; sigmatch_table[DETECT_PRIORITY].Free = NULL; diff --git a/src/detect-reference.c b/src/detect-reference.c index 6fe04a2b9159..d1a82dfed55b 100644 --- a/src/detect-reference.c +++ b/src/detect-reference.c @@ -57,7 +57,7 @@ void DetectReferenceRegister(void) { sigmatch_table[DETECT_REFERENCE].name = "reference"; sigmatch_table[DETECT_REFERENCE].desc = "direct to places where information about the rule can be found"; - sigmatch_table[DETECT_REFERENCE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Reference"; + sigmatch_table[DETECT_REFERENCE].url = DOC_URL DOC_VERSION "/rules/meta.html#reference"; sigmatch_table[DETECT_REFERENCE].Match = NULL; sigmatch_table[DETECT_REFERENCE].Setup = DetectReferenceSetup; sigmatch_table[DETECT_REFERENCE].Free = NULL; diff --git a/src/detect-rev.c b/src/detect-rev.c index d540ec6163a0..1c1bc401da5a 100644 --- a/src/detect-rev.c +++ b/src/detect-rev.c @@ -34,7 +34,7 @@ void DetectRevRegister (void) { sigmatch_table[DETECT_REV].name = "rev"; sigmatch_table[DETECT_REV].desc = "set version of the rule"; - sigmatch_table[DETECT_REV].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Rev-Revision"; + sigmatch_table[DETECT_REV].url = DOC_URL DOC_VERSION "/rules/meta.html#rev-revision"; sigmatch_table[DETECT_REV].Match = NULL; sigmatch_table[DETECT_REV].Setup = DetectRevSetup; sigmatch_table[DETECT_REV].Free = NULL; diff --git a/src/detect-rpc.c b/src/detect-rpc.c index 52f6d7469a16..b3052ce547b4 100644 --- a/src/detect-rpc.c +++ b/src/detect-rpc.c @@ -60,7 +60,7 @@ void DetectRpcRegister (void) { sigmatch_table[DETECT_RPC].name = "rpc"; sigmatch_table[DETECT_RPC].desc = "match RPC procedure numbers and RPC version"; - sigmatch_table[DETECT_RPC].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#rpc"; + sigmatch_table[DETECT_RPC].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#rpc"; sigmatch_table[DETECT_RPC].Match = DetectRpcMatch; sigmatch_table[DETECT_RPC].Setup = DetectRpcSetup; sigmatch_table[DETECT_RPC].Free = DetectRpcFree; diff --git a/src/detect-sameip.c b/src/detect-sameip.c index 351b95ec5bf6..e22a943f384e 100644 --- a/src/detect-sameip.c +++ b/src/detect-sameip.c @@ -50,7 +50,7 @@ void DetectSameipRegister(void) { sigmatch_table[DETECT_SAMEIP].name = "sameip"; sigmatch_table[DETECT_SAMEIP].desc = "check if the IP address of the source is the same as the IP address of the destination"; - sigmatch_table[DETECT_SAMEIP].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#sameip"; + sigmatch_table[DETECT_SAMEIP].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#sameip"; sigmatch_table[DETECT_SAMEIP].Match = DetectSameipMatch; sigmatch_table[DETECT_SAMEIP].Setup = DetectSameipSetup; sigmatch_table[DETECT_SAMEIP].Free = NULL; diff --git a/src/detect-seq.c b/src/detect-seq.c index 60bd2ad2ced4..cb2bb9930f16 100644 --- a/src/detect-seq.c +++ b/src/detect-seq.c @@ -52,7 +52,7 @@ void DetectSeqRegister(void) { sigmatch_table[DETECT_SEQ].name = "seq"; sigmatch_table[DETECT_SEQ].desc = "check for a specific TCP sequence number"; - sigmatch_table[DETECT_SEQ].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#seq"; + sigmatch_table[DETECT_SEQ].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#seq"; sigmatch_table[DETECT_SEQ].Match = DetectSeqMatch; sigmatch_table[DETECT_SEQ].Setup = DetectSeqSetup; sigmatch_table[DETECT_SEQ].Free = DetectSeqFree; diff --git a/src/detect-sid.c b/src/detect-sid.c index 649604fb129f..d148a3dd0728 100644 --- a/src/detect-sid.c +++ b/src/detect-sid.c @@ -38,7 +38,7 @@ void DetectSidRegister (void) { sigmatch_table[DETECT_SID].name = "sid"; sigmatch_table[DETECT_SID].desc = "set rule id"; - sigmatch_table[DETECT_SID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Sid-signature-id"; + sigmatch_table[DETECT_SID].url = DOC_URL DOC_VERSION "/rules/meta.html#sid-signature-id"; sigmatch_table[DETECT_SID].Match = NULL; sigmatch_table[DETECT_SID].Setup = DetectSidSetup; sigmatch_table[DETECT_SID].Free = NULL; diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c index 159d4d6f7c84..f2296a04f4fe 100644 --- a/src/detect-stream_size.c +++ b/src/detect-stream_size.c @@ -57,7 +57,7 @@ void DetectStreamSizeRegister(void) { sigmatch_table[DETECT_STREAM_SIZE].name = "stream_size"; sigmatch_table[DETECT_STREAM_SIZE].desc = "match on amount of bytes of a stream"; - sigmatch_table[DETECT_STREAM_SIZE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#stream_size"; + sigmatch_table[DETECT_STREAM_SIZE].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#stream-size"; sigmatch_table[DETECT_STREAM_SIZE].Match = DetectStreamSizeMatch; sigmatch_table[DETECT_STREAM_SIZE].Setup = DetectStreamSizeSetup; sigmatch_table[DETECT_STREAM_SIZE].Free = DetectStreamSizeFree; diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 2cc211c209c2..487de7685ad6 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -76,7 +76,7 @@ void DetectThresholdRegister(void) { sigmatch_table[DETECT_THRESHOLD].name = "threshold"; sigmatch_table[DETECT_THRESHOLD].desc = "control the rule's alert frequency"; - sigmatch_table[DETECT_THRESHOLD].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Rule-Thresholding#threshold"; + sigmatch_table[DETECT_THRESHOLD].url = DOC_URL DOC_VERSION "/rules/thresholding.html#threshold"; sigmatch_table[DETECT_THRESHOLD].Match = DetectThresholdMatch; sigmatch_table[DETECT_THRESHOLD].Setup = DetectThresholdSetup; sigmatch_table[DETECT_THRESHOLD].Free = DetectThresholdFree; diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index 1da3270324d9..f3ad4fd9c27f 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -81,7 +81,7 @@ void DetectTlsValidityRegister (void) { sigmatch_table[DETECT_AL_TLS_NOTBEFORE].name = "tls_cert_notbefore"; sigmatch_table[DETECT_AL_TLS_NOTBEFORE].desc = "match TLS certificate notBefore field"; - sigmatch_table[DETECT_AL_TLS_NOTBEFORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsnotbefore"; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsnotbefore"; sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Match = NULL; sigmatch_table[DETECT_AL_TLS_NOTBEFORE].AppLayerTxMatch = DetectTlsValidityMatch; sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Setup = DetectTlsNotBeforeSetup; @@ -90,7 +90,7 @@ void DetectTlsValidityRegister (void) sigmatch_table[DETECT_AL_TLS_NOTAFTER].name = "tls_cert_notafter"; sigmatch_table[DETECT_AL_TLS_NOTAFTER].desc = "match TLS certificate notAfter field"; - sigmatch_table[DETECT_AL_TLS_NOTAFTER].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsnotafter"; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsnotafter"; sigmatch_table[DETECT_AL_TLS_NOTAFTER].Match = NULL; sigmatch_table[DETECT_AL_TLS_NOTAFTER].AppLayerTxMatch = DetectTlsValidityMatch; sigmatch_table[DETECT_AL_TLS_NOTAFTER].Setup = DetectTlsNotAfterSetup; @@ -99,7 +99,7 @@ void DetectTlsValidityRegister (void) sigmatch_table[DETECT_AL_TLS_EXPIRED].name = "tls_cert_expired"; sigmatch_table[DETECT_AL_TLS_EXPIRED].desc = "match expired TLS certificates"; - sigmatch_table[DETECT_AL_TLS_EXPIRED].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsexpired"; + sigmatch_table[DETECT_AL_TLS_EXPIRED].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsexpired"; sigmatch_table[DETECT_AL_TLS_EXPIRED].Match = NULL; sigmatch_table[DETECT_AL_TLS_EXPIRED].AppLayerTxMatch = DetectTlsValidityMatch; sigmatch_table[DETECT_AL_TLS_EXPIRED].Setup = DetectTlsExpiredSetup; @@ -109,7 +109,7 @@ void DetectTlsValidityRegister (void) sigmatch_table[DETECT_AL_TLS_VALID].name = "tls_cert_valid"; sigmatch_table[DETECT_AL_TLS_VALID].desc = "match valid TLS certificates"; - sigmatch_table[DETECT_AL_TLS_VALID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsvalid"; + sigmatch_table[DETECT_AL_TLS_VALID].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsvalid"; sigmatch_table[DETECT_AL_TLS_VALID].Match = NULL; sigmatch_table[DETECT_AL_TLS_VALID].AppLayerTxMatch = DetectTlsValidityMatch; sigmatch_table[DETECT_AL_TLS_VALID].Setup = DetectTlsValidSetup; diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index eb78cfb3bb4f..574ec7de4d71 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -71,7 +71,7 @@ void DetectTlsVersionRegister (void) { sigmatch_table[DETECT_AL_TLS_VERSION].name = "tls.version"; sigmatch_table[DETECT_AL_TLS_VERSION].desc = "match on TLS/SSL version"; - sigmatch_table[DETECT_AL_TLS_VERSION].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsversion"; + sigmatch_table[DETECT_AL_TLS_VERSION].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsversion"; sigmatch_table[DETECT_AL_TLS_VERSION].Match = NULL; sigmatch_table[DETECT_AL_TLS_VERSION].AppLayerMatch = DetectTlsVersionMatch; sigmatch_table[DETECT_AL_TLS_VERSION].Setup = DetectTlsVersionSetup; diff --git a/src/detect-tls.c b/src/detect-tls.c index f61265957ab2..b199b1fa175e 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -95,7 +95,7 @@ void DetectTlsRegister (void) { sigmatch_table[DETECT_AL_TLS_SUBJECT].name = "tls.subject"; sigmatch_table[DETECT_AL_TLS_SUBJECT].desc = "match TLS/SSL certificate Subject field"; - sigmatch_table[DETECT_AL_TLS_SUBJECT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlssubject"; + sigmatch_table[DETECT_AL_TLS_SUBJECT].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlssubject"; sigmatch_table[DETECT_AL_TLS_SUBJECT].Match = NULL; sigmatch_table[DETECT_AL_TLS_SUBJECT].AppLayerMatch = DetectTlsSubjectMatch; sigmatch_table[DETECT_AL_TLS_SUBJECT].Setup = DetectTlsSubjectSetup; @@ -104,7 +104,7 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_ISSUERDN].name = "tls.issuerdn"; sigmatch_table[DETECT_AL_TLS_ISSUERDN].desc = "match TLS/SSL certificate IssuerDN field"; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsissuerdn"; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsissuerdn"; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Match = NULL; sigmatch_table[DETECT_AL_TLS_ISSUERDN].AppLayerMatch = DetectTlsIssuerDNMatch; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Setup = DetectTlsIssuerDNSetup; @@ -113,7 +113,7 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_FINGERPRINT].name = "tls.fingerprint"; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].desc = "match TLS/SSL certificate SHA1 fingerprint"; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsfingerprint"; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsfingerprint"; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Match = NULL; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].AppLayerMatch = DetectTlsFingerprintMatch; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup; @@ -122,7 +122,7 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_STORE].name = "tls.store"; sigmatch_table[DETECT_AL_TLS_STORE].desc = "store TLS/SSL certificate on disk"; - sigmatch_table[DETECT_AL_TLS_STORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsstore"; + sigmatch_table[DETECT_AL_TLS_STORE].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsstore"; sigmatch_table[DETECT_AL_TLS_STORE].Match = NULL; sigmatch_table[DETECT_AL_TLS_STORE].AppLayerMatch = DetectTlsStoreMatch; sigmatch_table[DETECT_AL_TLS_STORE].Setup = DetectTlsStoreSetup; diff --git a/src/detect-ttl.c b/src/detect-ttl.c index 96ae1273342a..096a4ad136e0 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -59,7 +59,7 @@ void DetectTtlRegister(void) { sigmatch_table[DETECT_TTL].name = "ttl"; sigmatch_table[DETECT_TTL].desc = "check for a specific IP time-to-live value"; - sigmatch_table[DETECT_TTL].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#ttl"; + sigmatch_table[DETECT_TTL].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#ttl"; sigmatch_table[DETECT_TTL].Match = DetectTtlMatch; sigmatch_table[DETECT_TTL].Setup = DetectTtlSetup; sigmatch_table[DETECT_TTL].Free = DetectTtlFree; diff --git a/src/detect-urilen.c b/src/detect-urilen.c index 898fa9497a3d..860bb9291745 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -61,7 +61,7 @@ void DetectUrilenRegister(void) { sigmatch_table[DETECT_AL_URILEN].name = "urilen"; sigmatch_table[DETECT_AL_URILEN].desc = "match on the length of the HTTP uri"; - sigmatch_table[DETECT_AL_URILEN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#Urilen"; + sigmatch_table[DETECT_AL_URILEN].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#urilen"; sigmatch_table[DETECT_AL_URILEN].Match = NULL; sigmatch_table[DETECT_AL_URILEN].AppLayerMatch = NULL /**< We handle this at detect-engine-uri.c now */; sigmatch_table[DETECT_AL_URILEN].Setup = DetectUrilenSetup; diff --git a/src/detect-window.c b/src/detect-window.c index 39f879aa935c..c9a81920eae3 100644 --- a/src/detect-window.c +++ b/src/detect-window.c @@ -59,7 +59,7 @@ void DetectWindowRegister (void) { sigmatch_table[DETECT_WINDOW].name = "window"; sigmatch_table[DETECT_WINDOW].desc = "check for a specific TCP window size"; - sigmatch_table[DETECT_WINDOW].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Window"; + sigmatch_table[DETECT_WINDOW].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#window"; sigmatch_table[DETECT_WINDOW].Match = DetectWindowMatch; sigmatch_table[DETECT_WINDOW].Setup = DetectWindowSetup; sigmatch_table[DETECT_WINDOW].Free = DetectWindowFree; diff --git a/src/detect-within.c b/src/detect-within.c index 3057858e74f0..a0d503e89f76 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -50,7 +50,7 @@ void DetectWithinRegister(void) { sigmatch_table[DETECT_WITHIN].name = "within"; sigmatch_table[DETECT_WITHIN].desc = "indicate that this content match has to be within a certain distance of the previous content keyword match"; - sigmatch_table[DETECT_WITHIN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Within"; + sigmatch_table[DETECT_WITHIN].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#within"; sigmatch_table[DETECT_WITHIN].Match = NULL; sigmatch_table[DETECT_WITHIN].Setup = DetectWithinSetup; sigmatch_table[DETECT_WITHIN].Free = NULL; diff --git a/src/detect-xbits.c b/src/detect-xbits.c index af9384fb486a..261f0c82b6e5 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -66,7 +66,7 @@ void DetectXbitsRegister (void) { sigmatch_table[DETECT_XBITS].name = "xbits"; sigmatch_table[DETECT_XBITS].desc = "operate on bits"; -// sigmatch_table[DETECT_XBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flowbits"; +// sigmatch_table[DETECT_XBITS].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#flowbits"; sigmatch_table[DETECT_XBITS].Match = DetectXbitMatch; sigmatch_table[DETECT_XBITS].Setup = DetectXbitSetup; sigmatch_table[DETECT_XBITS].Free = DetectXbitFree; diff --git a/src/suricata.h b/src/suricata.h index 4273ecb6e96b..2e92e634a66b 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -85,6 +85,14 @@ #define DEFAULT_PID_BASENAME "suricata.pid" #define DEFAULT_PID_FILENAME DEFAULT_PID_DIR DEFAULT_PID_BASENAME +#define DOC_URL "http://suricata.readthedocs.io/en/" + +#if defined RELEASE +#define DOC_VERSION PROG_VER +#else +#define DOC_VERSION "latest" +#endif + /* runtime engine control flags */ #define SURICATA_STOP (1 << 0) /**< gracefully stop the engine: process all outstanding packets first */ From bbb93e487e6a4c206b158335128f108c8b08f909 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 23 Sep 2016 20:46:06 -0600 Subject: [PATCH 2169/2553] pcap-log: seed ring buffer on start up On start, look for existing pcap log files and add them to the ring buffer. This makes pcap-log self maintaining over restarts removing the need for external tools to clear orphaned files. --- configure.ac | 1 + src/log-pcap.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++- src/util-error.c | 2 + src/util-error.h | 2 + 4 files changed, 242 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index da13e099fde2..2144a36980a2 100644 --- a/configure.ac +++ b/configure.ac @@ -132,6 +132,7 @@ AC_CHECK_HEADERS([sys/ioctl.h linux/if_ether.h linux/if_packet.h linux/filter.h]) AC_CHECK_HEADERS([linux/ethtool.h linux/sockios.h]) AC_CHECK_HEADER(glob.h,,[AC_ERROR(glob.h not found ...)]) + AC_CHECK_HEADERS([dirent.h fnmatch.h]) AC_CHECK_HEADERS([sys/socket.h net/if.h sys/mman.h linux/if_arp.h], [], [], [[#ifdef HAVE_SYS_SOCKET_H diff --git a/src/log-pcap.c b/src/log-pcap.c index b21f785452ac..1d2dba964459 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -26,6 +26,13 @@ */ #include "suricata-common.h" + +#if defined(HAVE_DIRENT_H) && defined(HAVE_FNMATCH_H) +#define INIT_RING_BUFFER +#include +#include +#endif + #include "debug.h" #include "detect.h" #include "flow.h" @@ -80,6 +87,14 @@ SC_ATOMIC_DECLARE(uint32_t, thread_cnt); typedef struct PcapFileName_ { char *filename; char *dirname; + + /* Like a struct timeval, but with fixed size. This is only used when + * seeding the ring buffer on start. */ + struct { + uint64_t secs; + uint32_t usecs; + }; + TAILQ_ENTRY(PcapFileName_) next; /**< Pointer to next Pcap File for tailq. */ } PcapFileName; @@ -138,6 +153,11 @@ typedef struct PcapLogThreadData_ { PcapLogData *pcap_log; } PcapLogThreadData; +/* Pattern for extracting timestamp from pcap log files. */ +static const char timestamp_pattern[] = ".*?(\\d+)(\\.(\\d+))?"; +static pcre *pcre_timestamp_code = NULL; +static pcre_extra *pcre_timestamp_extra = NULL; + /* global pcap data for when we're using multi mode. At exit we'll * merge counters into this one and then report counters. */ static PcapLogData *g_pcap_data = NULL; @@ -475,6 +495,194 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl) return copy; } +#ifdef INIT_RING_BUFFER +static int PcapLogGetTimeOfFile(const char *filename, uint64_t *secs, + uint32_t *usecs) +{ + int pcre_ovecsize = 4 * 3; + int pcre_ovec[pcre_ovecsize]; + char buf[PATH_MAX]; + + int n = pcre_exec(pcre_timestamp_code, pcre_timestamp_extra, + filename, strlen(filename), 0, 0, pcre_ovec, + pcre_ovecsize); + if (n != 2 && n != 4) { + /* No match. */ + return 0; + } + + if (n >= 2) { + /* Extract seconds. */ + if (pcre_copy_substring(filename, pcre_ovec, pcre_ovecsize, + 1, buf, sizeof(buf)) < 0) { + return 0; + } + if (ByteExtractStringUint64(secs, 10, 0, buf) < 0) { + return 0; + } + } + if (n == 4) { + /* Extract microseconds. */ + if (pcre_copy_substring(filename, pcre_ovec, pcre_ovecsize, + 3, buf, sizeof(buf)) < 0) { + return 0; + } + if (ByteExtractStringUint32(usecs, 10, 0, buf) < 0) { + return 0; + } + } + + return 1; +} + +static TmEcode PcapLogInitRingBuffer(PcapLogData *pl) +{ + char pattern[PATH_MAX]; + + SCLogInfo("Initializing PCAP ring buffer for %s/%s.", + pl->dir, pl->prefix); + + strlcpy(pattern, pl->dir, PATH_MAX); + if (pattern[strlen(pattern) - 1] != '/') { + strlcat(pattern, "/", PATH_MAX); + } + if (pl->mode == LOGMODE_MULTI) { + for (int i = 0; i < pl->filename_part_cnt; i++) { + char *part = pl->filename_parts[i]; + if (part == NULL || strlen(part) == 0) { + continue; + } + if (part[0] != '%' || strlen(part) < 2) { + strlcat(pattern, part, PATH_MAX); + continue; + } + switch (part[1]) { + case 'i': + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Thread ID not allowed inring buffer mode."); + return TM_ECODE_FAILED; + case 'n': { + char tmp[PATH_MAX]; + snprintf(tmp, PATH_MAX, "%"PRIu32, pl->thread_number); + strlcat(pattern, tmp, PATH_MAX); + break; + } + case 't': + strlcat(pattern, "*", PATH_MAX); + break; + default: + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Unsupported format character: %%%s", part); + return TM_ECODE_FAILED; + } + } + } else { + strlcat(pattern, pl->prefix, PATH_MAX); + strlcat(pattern, ".*", PATH_MAX); + } + + char *basename = strrchr(pattern, '/'); + *basename++ = '\0'; + + /* Pattern is now just the directory name. */ + DIR *dir = opendir(pattern); + if (dir == NULL) { + SCLogWarning(SC_ERR_DIR_OPEN, "Failed to open directory %s: %s", + pattern, strerror(errno)); + return TM_ECODE_FAILED; + } + + for (;;) { + struct dirent *entry = readdir(dir); + if (entry == NULL) { + break; + } + if (fnmatch(basename, entry->d_name, 0) != 0) { + continue; + } + + uint64_t secs = 0; + uint32_t usecs = 0; + + if (!PcapLogGetTimeOfFile(entry->d_name, &secs, &usecs)) { + /* Failed to get time stamp out of file name. Not necessarily a + * failure as the file might just not be a pcap log file. */ + continue; + } + + PcapFileName *pf = SCCalloc(sizeof(*pf), 1); + if (unlikely(pf == NULL)) { + return TM_ECODE_FAILED; + } + char path[PATH_MAX]; + snprintf(path, PATH_MAX - 1, "%s/%s", pattern, entry->d_name); + if ((pf->filename = SCStrdup(path)) == NULL) { + goto fail; + } + if ((pf->dirname = SCStrdup(pattern)) == NULL) { + goto fail; + } + pf->secs = secs; + pf->usecs = usecs; + + if (TAILQ_EMPTY(&pl->pcap_file_list)) { + TAILQ_INSERT_TAIL(&pl->pcap_file_list, pf, next); + } else { + /* Ordered insert. */ + PcapFileName *it = TAILQ_FIRST(&pl->pcap_file_list); + TAILQ_FOREACH(it, &pl->pcap_file_list, next) { + if (pf->secs < it->secs) { + break; + } else if (pf->secs == it->secs && pf->usecs < it->usecs) { + break; + } + } + if (it == NULL) { + TAILQ_INSERT_TAIL(&pl->pcap_file_list, pf, next); + } else { + TAILQ_INSERT_BEFORE(it, pf, next); + } + } + pl->file_cnt++; + continue; + + fail: + if (pf != NULL) { + if (pf->filename != NULL) { + SCFree(pf->filename); + } + if (pf->dirname != NULL) { + SCFree(pf->dirname); + } + SCFree(pf); + } + break; + } + + if (pl->file_cnt > pl->max_files) { + PcapFileName *pf = TAILQ_FIRST(&pl->pcap_file_list); + while (pf != NULL && pl->file_cnt > pl->max_files) { + SCLogDebug("Removing PCAP file %s", pf->filename); + if (remove(pf->filename) != 0) { + SCLogWarning(SC_WARN_REMOVE_FILE, + "Failed to remove PCAP file %s: %s", pf->filename, + strerror(errno)); + } + TAILQ_REMOVE(&pl->pcap_file_list, pf, next); + pf = TAILQ_FIRST(&pl->pcap_file_list); + pl->file_cnt--; + } + } + + closedir(dir); + + /* For some reason file count is initialized at one, instead of 0. */ + SCLogNotice("Ring buffer initialized with %d files.", pl->file_cnt - 1); + + return TM_ECODE_OK; +} +#endif /* INIT_RING_BUFFER */ + static TmEcode PcapLogDataInit(ThreadVars *t, void *initdata, void **data) { if (initdata == NULL) { @@ -500,7 +708,9 @@ static TmEcode PcapLogDataInit(ThreadVars *t, void *initdata, void **data) td->pcap_log->pkt_cnt = 0; td->pcap_log->pcap_dead_handle = NULL; td->pcap_log->pcap_dumper = NULL; - td->pcap_log->file_cnt = 1; + if (td->pcap_log->file_cnt < 1) { + td->pcap_log->file_cnt = 1; + } struct timeval ts; memset(&ts, 0x00, sizeof(struct timeval)); @@ -518,6 +728,16 @@ static TmEcode PcapLogDataInit(ThreadVars *t, void *initdata, void **data) *data = (void *)td; + if (pl->max_files && (pl->mode == LOGMODE_MULTI || pl->threads == 1)) { +#ifdef INIT_RING_BUFFER + if (PcapLogInitRingBuffer(td->pcap_log) == TM_ECODE_FAILED) { + return TM_ECODE_FAILED; + } +#else + SCLogInfo("Unable to initialize ring buffer on this platform."); +#endif /* INIT_RING_BUFFER */ + } + return TM_ECODE_OK; } @@ -701,6 +921,9 @@ static int ParseFilename(PcapLogData *pl, const char *filename) * */ static OutputCtx *PcapLogInitCtx(ConfNode *conf) { + const char *pcre_errbuf; + int pcre_erroffset; + PcapLogData *pl = SCMalloc(sizeof(PcapLogData)); if (unlikely(pl == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate Memory for PcapLogData"); @@ -727,6 +950,19 @@ static OutputCtx *PcapLogInitCtx(ConfNode *conf) SCMutexInit(&pl->plog_lock, NULL); + /* Initialize PCREs. */ + pcre_timestamp_code = pcre_compile(timestamp_pattern, 0, &pcre_errbuf, + &pcre_erroffset, NULL); + if (pcre_timestamp_code == NULL) { + FatalError(SC_ERR_PCRE_COMPILE, + "Failed to compile \"%s\" at offset %"PRIu32": %s", + timestamp_pattern, pcre_erroffset, pcre_errbuf); + } + pcre_timestamp_extra = pcre_study(pcre_timestamp_code, 0, &pcre_errbuf); + if (pcre_timestamp_extra == NULL) { + FatalError(SC_ERR_PCRE_STUDY, "Fail to study pcre: %s", pcre_errbuf); + } + /* conf params */ const char *filename = NULL; diff --git a/src/util-error.c b/src/util-error.c index d76c2d3c2291..bc144a43321c 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -331,6 +331,8 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_NO_SHA1_SUPPORT); CASE_CODE (SC_ERR_NO_SHA256_SUPPORT); CASE_CODE (SC_ERR_DNP3_CONFIG); + CASE_CODE (SC_ERR_DIR_OPEN); + CASE_CODE(SC_WARN_REMOVE_FILE); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index b57e6b228518..9a68fe501154 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -321,6 +321,8 @@ typedef enum { SC_ERR_NO_SHA256_SUPPORT, SC_ERR_ENIP_CONFIG, SC_ERR_DNP3_CONFIG, + SC_ERR_DIR_OPEN, + SC_WARN_REMOVE_FILE, } SCError; const char *SCErrorToString(SCError); From e6ed0d815c02db335383fa40e2391e07ea3234af Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 24 Nov 2016 13:31:05 +0100 Subject: [PATCH 2170/2553] qa: update url in libhtp script --- qa/travis-libhtp.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/travis-libhtp.sh b/qa/travis-libhtp.sh index febe1fe7f4df..109d6d398bc6 100755 --- a/qa/travis-libhtp.sh +++ b/qa/travis-libhtp.sh @@ -1,3 +1,3 @@ #!/bin/sh set -ex -git clone https://github.com/ironbee/libhtp -b 0.5.x +git clone https://github.com/OISF/libhtp -b 0.5.x From a67c31d4e164b04c1ec5766b692bf984790cdad5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 23 Nov 2016 15:27:28 +0100 Subject: [PATCH 2171/2553] qa: appveyor support --- appveyor.yml | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000000..6ff4c260d324 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,60 @@ +# Based on https://github.com/redis/hiredis/blob/master/appveyor.yml +# and https://github.com/dokan-dev/dokany/pull/336/files +# Appveyor configuration file for CI build of hiredis on Windows (under Cygwin) +environment: + matrix: +# - CYG_ROOT: C:\cygwin64 +# CYG_SETUP: setup-x86_64.exe +# CYG_MIRROR: http://cygwin.mirror.constant.com +# CYG_CACHE: C:\cygwin64\var\cache\setup +# CYG_BASH: C:\cygwin64\bin\bash +# CC: gcc + - CYG_ROOT: C:\cygwin + CYG_SETUP: setup-x86.exe + CYG_MIRROR: http://cygwin.mirror.constant.com + CYG_CACHE: C:\cygwin\var\cache\setup + CYG_BASH: C:\cygwin\bin\bash + CC: gcc + +# Cache Cygwin files to speed up build +cache: + - '%CYG_CACHE%' +clone_depth: 1 + +# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail +init: + - git config --global core.autocrlf input +# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + +# Install needed build dependencies. First update cygwin to avoid weird dll issues. +install: + - ps: 'Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP"' + - '%CYG_SETUP% -gqnNdO --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" > NUL 2>&1' + - '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages automake,bison,gcc-core,libtool,make,gettext-devel,gettext,intltool,pkg-config,clang,llvm,libpcre-devel,file-devel,wget,zlib-devel,libnss-devel,libnspr-devel,libGeoIP-devel,libyaml-devel,luajit-devel,unzip > NUL 2>&1' + - '%CYG_BASH% -lc "cygcheck -dc cygwin"' + - '%CYG_BASH% -lc "wget https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip && ls && unzip WpdPack_4_1_2.zip"' + - '%CYG_BASH% -lc "cp WpdPack/Lib/libpacket.a /usr/lib/"' + - '%CYG_BASH% -lc "cp WpdPack/Lib/libwpcap.a /usr/lib/libpcap.a"' # so -lpcap works +# - '%CYG_BASH% -lc "cp WpdPack/Lib/libwpcap.a /usr/lib/libwpcap.a"' + - '%CYG_BASH% -lc "cp WpdPack/Lib/Packet.lib /usr/lib/"' + - '%CYG_BASH% -lc "cp WpdPack/Lib/wpcap.lib /usr/lib/"' + - '%CYG_BASH% -lc "mkdir -p /usr/include/pcap"' + - '%CYG_BASH% -lc "cp -r WpdPack/Include/* /usr/include/"' + - choco install winpcap # userspace + +build_script: + - 'echo building...' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; bash ./qa/travis-libhtp.sh"' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh"' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; ./configure --enable-unittests --disable-shared --disable-gccmarch-native --enable-luajit --enable-geoip"' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Wed, 23 Nov 2016 15:59:28 -0600 Subject: [PATCH 2172/2553] doc: document that that ;, \, " need to be escaped in rules --- doc/userguide/rules/intro.rst | 6 ++++++ doc/userguide/rules/meta.rst | 5 +++-- doc/userguide/rules/payload-keywords.rst | 3 +++ doc/userguide/rules/pcre.rst | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/doc/userguide/rules/intro.rst b/doc/userguide/rules/intro.rst index 9e1e6ce56d10..fb20a1c7ec7f 100644 --- a/doc/userguide/rules/intro.rst +++ b/doc/userguide/rules/intro.rst @@ -172,6 +172,12 @@ There are specific settings for: * payloads * flows +.. note:: The characters ``;`` and ``"`` have special meaning in the + Suricata rule language and must be escaped when used in a + rule option value. For example:: + + msg:"Message with semicolon\;"; + For more information about these settings, you can click on the following headlines: diff --git a/doc/userguide/rules/meta.rst b/doc/userguide/rules/meta.rst index 048152c746c7..7132f2dff6a3 100644 --- a/doc/userguide/rules/meta.rst +++ b/doc/userguide/rules/meta.rst @@ -26,10 +26,11 @@ It is a convention that msg is always the first keyword of a signature. Another example of msg in a signature: -.. image:: meta/msg.png - In this example the red, bold-faced part is the msg. +.. note:: The following characters must be escaped inside the msg: + ``;`` ``\`` ``"`` + Sid (signature id) ------------------ diff --git a/doc/userguide/rules/payload-keywords.rst b/doc/userguide/rules/payload-keywords.rst index 6104c5ba7973..2e0f4db0cafc 100644 --- a/doc/userguide/rules/payload-keywords.rst +++ b/doc/userguide/rules/payload-keywords.rst @@ -93,6 +93,9 @@ For example:: You see ``content:!”Firefox/3.6.13”;``. This means an alert will be generated if the the used version of Firefox is not 3.6.13. +.. note:: The following characters must be escaped inside the content: + ``;`` ``\`` ``"`` + Nocase ------ diff --git a/doc/userguide/rules/pcre.rst b/doc/userguide/rules/pcre.rst index 784b56681c97..9c0f4035c863 100644 --- a/doc/userguide/rules/pcre.rst +++ b/doc/userguide/rules/pcre.rst @@ -54,6 +54,9 @@ qualities of pcre as well. These are: * ``E``: Ignores newline characters at the end of the buffer/payload. * ``G``: Inverts the greediness. +.. note:: The following characters must be escaped inside the content: + ``;`` ``\`` ``"`` + Suricata's modifiers ~~~~~~~~~~~~~~~~~~~~ From 553f7ec290441dccffec5f63e5f1033bc79c0683 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 24 Nov 2016 10:36:27 -0600 Subject: [PATCH 2173/2553] log-pcap.c: fix resource leak found by coverity Goto the failure label instead of returning which will allow the open directory to get cleaned up. Fixes: *** CID 1394675: Resource leaks (RESOURCE_LEAK) /src/log-pcap.c: 615 in PcapLogInitRingBuffer() 609 * failure as the file might just not be a pcap log file. */ 610 continue; 611 } 612 613 PcapFileName *pf = SCCalloc(sizeof(*pf), 1); 614 if (unlikely(pf == NULL)) { >>> CID 1394675: Resource leaks (RESOURCE_LEAK) >>> Variable "dir" going out of scope leaks the storage it points to. 615 return TM_ECODE_FAILED; 616 } 617 char path[PATH_MAX]; 618 snprintf(path, PATH_MAX - 1, "%s/%s", pattern, entry->d_name); 619 if ((pf->filename = SCStrdup(path)) == NULL) { 620 goto fail; This also means that pf can be NULL which should clear up CID 1394676 (REVERSE_INULL). --- src/log-pcap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/log-pcap.c b/src/log-pcap.c index 1d2dba964459..0513c41debb3 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -612,7 +612,7 @@ static TmEcode PcapLogInitRingBuffer(PcapLogData *pl) PcapFileName *pf = SCCalloc(sizeof(*pf), 1); if (unlikely(pf == NULL)) { - return TM_ECODE_FAILED; + goto fail; } char path[PATH_MAX]; snprintf(path, PATH_MAX - 1, "%s/%s", pattern, entry->d_name); From a1eca40611e4526bc921ca6461dbb330f82ed575 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 24 Nov 2016 10:59:15 -0600 Subject: [PATCH 2174/2553] log-pcap.c: cleanup scan-build warning Don't initialize value to a value that is never used. --- src/log-pcap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/log-pcap.c b/src/log-pcap.c index 0513c41debb3..622b30466c35 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -629,7 +629,7 @@ static TmEcode PcapLogInitRingBuffer(PcapLogData *pl) TAILQ_INSERT_TAIL(&pl->pcap_file_list, pf, next); } else { /* Ordered insert. */ - PcapFileName *it = TAILQ_FIRST(&pl->pcap_file_list); + PcapFileName *it = NULL; TAILQ_FOREACH(it, &pl->pcap_file_list, next) { if (pf->secs < it->secs) { break; From c91974e24adefc44a6a321b037cc8ef9713d178e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 24 Nov 2016 11:21:48 -0600 Subject: [PATCH 2175/2553] issue 1961: depth: fail if numeric value has trailing text Catches the case where the depth is not terminated with a semicolon (eg: "depth:17 classtype:trojan-activity") which is usually a sign the rule has a missing semi-colon. --- src/detect-depth.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/detect-depth.c b/src/detect-depth.c index e2b098c1ca13..03d7d5bfa244 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -37,6 +37,7 @@ #include "flow-var.h" #include "app-layer.h" +#include "util-byte.h" #include "util-debug.h" static int DetectDepthSetup (DetectEngineCtx *, Signature *, char *); @@ -137,11 +138,10 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths cd->depth = ((DetectByteExtractData *)bed_sm->ctx)->local_id; cd->flags |= DETECT_CONTENT_DEPTH_BE; } else { - cd->depth = (uint32_t)atoi(str); - if (cd->depth < cd->content_len) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "depth - %"PRIu16 - " smaller than content length - %"PRIu32, - cd->depth, cd->content_len); + if (ByteExtractStringUint16(&cd->depth, 0, 0, str) != (int)strlen(str)) + { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "invalid value for depth: %s", str); goto end; } /* Now update the real limit, as depth is relative to the offset */ From ad8f9f93346fed7c5ab9cd85d2a71560014ff541 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:11:42 +0100 Subject: [PATCH 2176/2553] ssl-state: coverity 400558 --- src/detect-ssl-state.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 855e76542234..a46d55c5405c 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -259,8 +259,6 @@ DetectSslStateData *DetectSslStateParse(char *arg) return ssd; error: - if (ssd != NULL) - DetectSslStateFree(ssd); return NULL; } From d30f7f6b4850e52562e144afae2b15cef7d3d1de Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:12:23 +0100 Subject: [PATCH 2177/2553] tos: coverity 400559 --- src/detect-tos.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/detect-tos.c b/src/detect-tos.c index 8beeb329eb35..994454671171 100644 --- a/src/detect-tos.c +++ b/src/detect-tos.c @@ -163,8 +163,6 @@ DetectTosData *DetectTosParse(char *arg) return tosd; error: - if (tosd != NULL) - DetectTosFree(tosd); return NULL; } From 9904b3f3480d08ccf4396912c0bf83f804633a12 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:16:05 +0100 Subject: [PATCH 2178/2553] ttl: coverity 400560 + minor cleanups --- src/detect-ttl.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/detect-ttl.c b/src/detect-ttl.c index 096a4ad136e0..1c1e0e5b3188 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -176,7 +176,7 @@ DetectTtlData *DetectTtlParse (char *ttlstr) ttld = SCMalloc(sizeof (DetectTtlData)); if (unlikely(ttld == NULL)) - goto error; + goto error; ttld->ttl1 = 0; ttld->ttl2 = 0; @@ -226,7 +226,9 @@ DetectTtlData *DetectTtlParse (char *ttlstr) default: ttld->mode = DETECT_TTL_EQ; - if ((arg2 != NULL && strlen(arg2) > 0) || (arg3 != NULL && strlen(arg3) > 0) || (arg1 == NULL ||strlen(arg1) == 0)) + if ((arg2 != NULL && strlen(arg2) > 0) || + (arg3 != NULL && strlen(arg3) > 0) || + (arg1 == NULL ||strlen(arg1) == 0)) goto error; ttld->ttl1 = (uint8_t) atoi(arg1); @@ -235,9 +237,8 @@ DetectTtlData *DetectTtlParse (char *ttlstr) } else { ttld->mode = DETECT_TTL_EQ; - if ((arg2 != NULL && strlen(arg2) > 0) || - (arg3 != NULL && strlen(arg3) > 0) || - (arg1 == NULL ||strlen(arg1) == 0)) + if ((arg3 != NULL && strlen(arg3) > 0) || + (arg1 == NULL ||strlen(arg1) == 0)) goto error; ttld->ttl1 = (uint8_t) atoi(arg1); @@ -249,10 +250,14 @@ DetectTtlData *DetectTtlParse (char *ttlstr) return ttld; error: - if (ttld) SCFree(ttld); - if (arg1) SCFree(arg1); - if (arg2) SCFree(arg2); - if (arg3) SCFree(arg3); + if (ttld) + SCFree(ttld); + if (arg1) + SCFree(arg1); + if (arg2) + SCFree(arg2); + if (arg3) + SCFree(arg3); return NULL; } From da6bf0c1b688a3787808f17e11de684295f5d910 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:20:01 +0100 Subject: [PATCH 2179/2553] host-info: coverity 1298890 --- src/util-host-os-info.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/util-host-os-info.c b/src/util-host-os-info.c index eed01c7134e6..eaea28432c08 100644 --- a/src/util-host-os-info.c +++ b/src/util-host-os-info.c @@ -230,8 +230,7 @@ int SCHInfoAddHostOSInfo(char *host_os, char *host_os_ip_range, int is_ipv4) SCHInfoAddHostOSInfo(host_os, ip_str_rem, is_ipv4); } - if (ip_str != NULL) - SCFree(ip_str); + SCFree(ip_str); if (ipv4_addr != NULL) SCFree(ipv4_addr); if (ipv6_addr != NULL) From 7021959689d46eb2d9c859456162165b0b5869d7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:34:43 +0100 Subject: [PATCH 2180/2553] nfq: suppress CID 1374302 and 1374303 --- src/detect-mark.c | 1 + src/source-nfq.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/detect-mark.c b/src/detect-mark.c index b2326f98dc5d..83fa09690ab4 100644 --- a/src/detect-mark.c +++ b/src/detect-mark.c @@ -223,6 +223,7 @@ int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S const DetectMarkData *nf_data = (const DetectMarkData *)ctx; if (nf_data->mask) { if (!(IS_TUNNEL_PKT(p))) { + /* coverity[missing_lock] */ p->nfq_v.mark = (nf_data->mark & nf_data->mask) | (p->nfq_v.mark & ~(nf_data->mask)); p->flags |= PKT_MARK_MODIFIED; diff --git a/src/source-nfq.c b/src/source-nfq.c index 2c82f591fbff..749bf2d1caf4 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -433,6 +433,7 @@ int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data) //p->nfq_v.hw_protocol = ntohs(p->nfq_v.ph->hw_protocol); p->nfq_v.hw_protocol = ph->hw_protocol; } + /* coverity[missing_lock] */ p->nfq_v.mark = nfq_get_nfmark(tb); if (nfq_config.mode == NFQ_REPEAT_MODE) { if ((nfq_config.mark & nfq_config.mask) == @@ -523,6 +524,7 @@ static int NFQBypassCallback(Packet *p) } return 0; } else { + /* coverity[missing_lock] */ p->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) | (p->nfq_v.mark & ~nfq_config.bypass_mask); p->flags |= PKT_MARK_MODIFIED; From edcc8e7ec9652465724ef09f0a46d80d12b0a6e0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:39:02 +0100 Subject: [PATCH 2181/2553] stat: suppress CID 1293508 and 1312013 --- src/conf-yaml-loader.c | 2 ++ src/log-tlsstore.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index db5340696675..6f40ab784e1a 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -475,6 +475,7 @@ ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix) } struct stat stat_buf; + /* coverity[toctou] */ if (stat(filename, &stat_buf) == 0) { if (stat_buf.st_mode & S_IFDIR) { SCLogError(SC_ERR_FATAL, "yaml argument is not a file but a directory: %s. " @@ -483,6 +484,7 @@ ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix) } } + /* coverity[toctou] */ infile = fopen(filename, "r"); if (infile == NULL) { SCLogError(SC_ERR_FATAL, "failed to open file: %s: %s", filename, diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c index ddabd41fa377..6648f592aa48 100644 --- a/src/log-tlsstore.c +++ b/src/log-tlsstore.c @@ -307,8 +307,10 @@ static TmEcode LogTlsStoreLogThreadInit(ThreadVars *t, void *initdata, void **da } struct stat stat_buf; + /* coverity[toctou] */ if (stat(tls_logfile_base_dir, &stat_buf) != 0) { int ret; + /* coverity[toctou] */ ret = mkdir(tls_logfile_base_dir, S_IRWXU|S_IXGRP|S_IRGRP); if (ret != 0) { int err = errno; From 8915f2de386064856554cd1501bd0f2132fe7127 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 13:53:57 +0100 Subject: [PATCH 2182/2553] flow: suppress coverity CID 400600 --- src/flow-util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flow-util.c b/src/flow-util.c index b4b54c188e45..dae4194bd55d 100644 --- a/src/flow-util.c +++ b/src/flow-util.c @@ -64,6 +64,7 @@ Flow *FlowAlloc(void) } memset(f, 0, size); + /* coverity[missing_lock] */ FLOW_INITIALIZE(f); return f; } From 287fd837960e39f425fcb438cf4af94ce978717b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:44:23 +0100 Subject: [PATCH 2183/2553] dnp3: fix coverity CID 1374300 --- src/output-json-alert.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 4fc6cb5a2949..c589f1213b57 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -145,37 +145,31 @@ static void AlertJsonSsh(const Flow *f, json_t *js) static void AlertJsonDnp3(const Flow *f, json_t *js) { DNP3State *dnp3_state = (DNP3State *)FlowGetAppState(f); - json_t *dnp3js = NULL; if (dnp3_state) { uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); DNP3Transaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_DNP3, dnp3_state, tx_id); if (tx) { json_t *dnp3js = json_object(); - if (unlikely(dnp3js == NULL)) { - goto error; - } - if (tx->has_request && tx->request_done) { - json_t *request = JsonDNP3LogRequest(tx); - if (request != NULL) { - json_object_set_new(dnp3js, "request", request); + if (likely(dnp3js != NULL)) { + if (tx->has_request && tx->request_done) { + json_t *request = JsonDNP3LogRequest(tx); + if (request != NULL) { + json_object_set_new(dnp3js, "request", request); + } } - } - if (tx->has_response && tx->response_done) { - json_t *response = JsonDNP3LogResponse(tx); - if (response != NULL) { - json_object_set_new(dnp3js, "response", response); + if (tx->has_response && tx->response_done) { + json_t *response = JsonDNP3LogResponse(tx); + if (response != NULL) { + json_object_set_new(dnp3js, "response", response); + } } + json_object_set_new(js, "dnp3", dnp3js); } - json_object_set_new(js, "dnp3", dnp3js); } } return; -error: - if (dnp3js != NULL) { - json_decref(dnp3js); - } } void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js) From 6a971a5a0278ed7ee1c2e7b9a2e5920ed5f8c59b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:48:22 +0100 Subject: [PATCH 2184/2553] app-layer-proto-detect: fix -Wshadow warning --- src/app-layer-detect-proto.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 286dde89cfa6..9d93e9d73da2 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -580,7 +580,7 @@ AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, uint16_t port, uint16_t min_depth, uint16_t max_depth, - uint16_t (*AppLayerProtoDetectProbingParser) + uint16_t (*AppLayerProtoDetectProbingParserFunc) (uint8_t *input, uint32_t input_len, uint32_t *offset)) { AppLayerProtoDetectProbingParserElement *pe = AppLayerProtoDetectProbingParserElementAlloc(); @@ -590,7 +590,7 @@ AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, pe->alproto_mask = AppLayerProtoDetectProbingParserGetMask(alproto); pe->min_depth = min_depth; pe->max_depth = max_depth; - pe->ProbingParser = AppLayerProtoDetectProbingParser; + pe->ProbingParser = AppLayerProtoDetectProbingParserFunc; pe->next = NULL; if (max_depth != 0 && min_depth >= max_depth) { @@ -603,7 +603,7 @@ AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, "the probing parser. Invalid alproto - %d", alproto); goto error; } - if (AppLayerProtoDetectProbingParser == NULL) { + if (AppLayerProtoDetectProbingParserFunc == NULL) { SCLogError(SC_ERR_ALPARSER, "Invalid arguments sent to " "register the probing parser. Probing parser func NULL"); goto error; From f97e857c02fbee2e39c23b853169cc006587aa0e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:55:17 +0100 Subject: [PATCH 2185/2553] dns: fix -Wshadow warnings --- src/app-layer-dns-common.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 81c0e12e617c..165bc52721f1 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -688,8 +688,8 @@ static uint16_t DNSResponseGetNameByOffset(const uint8_t * const input, const ui while (length != 0) { int cnt = 0; while (length & 0xc0) { - uint16_t offset = ((length & 0x3f) << 8) + *(qdata+1); - qdata = (const uint8_t *)input + offset; + uint16_t off = ((length & 0x3f) << 8) + *(qdata+1); + qdata = (const uint8_t *)input + off; if ((uint64_t)((qdata + 1) - input) >= (uint64_t)input_len) { SCLogDebug("input buffer too small"); @@ -833,7 +833,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ } const DNSAnswerHeader *head = (DNSAnswerHeader *)data; - uint16_t datalen = ntohs(head->len); + const uint16_t datalen = ntohs(head->len); data += sizeof(DNSAnswerHeader); @@ -976,9 +976,9 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ } case DNS_RECORD_TYPE_TXT: { - uint16_t datalen = ntohs(head->len); + uint16_t txtdatalen = datalen; - if (datalen == 0) { + if (txtdatalen == 0) { DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto bad_data; } @@ -989,24 +989,24 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ do { //PrintRawDataFp(stdout, (uint8_t*)tdata, txtlen); - if (txtlen >= datalen) + if (txtlen >= txtdatalen) goto bad_data; DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), (uint8_t*)tdata, (uint16_t)txtlen, ntohs(dns_header->tx_id)); - datalen -= txtlen; + txtdatalen -= txtlen; tdata += txtlen; txtlen = *tdata; tdata++; - datalen--; + txtdatalen--; - SCLogDebug("datalen %u, txtlen %u", datalen, txtlen); - } while (datalen > 1); + SCLogDebug("datalen %u, txtlen %u", txtdatalen, txtlen); + } while (txtdatalen > 1); - data += ntohs(head->len); + data += datalen; break; } case DNS_RECORD_TYPE_SSHFP: @@ -1021,7 +1021,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ ntohs(head->type), ntohs(head->class), ntohl(head->ttl), data, ntohs(head->len), ntohs(dns_header->tx_id)); - data += ntohs(head->len); + data += datalen; break; } default: /* unsupported record */ @@ -1031,7 +1031,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ NULL, 0, ntohs(dns_header->tx_id)); //PrintRawDataFp(stdout, data, ntohs(head->len)); - data += ntohs(head->len); + data += datalen; break; } } From 02df79f67b297d82a21cf1ca09da4154012f0d0d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:58:44 +0100 Subject: [PATCH 2186/2553] mem: fix SCStrdup -Wshadow warning --- src/util-mem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-mem.h b/src/util-mem.h index b720ac361781..799c942c3ead 100644 --- a/src/util-mem.h +++ b/src/util-mem.h @@ -223,9 +223,9 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage); ptrmem = strdup((a)); \ if (ptrmem == NULL) { \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ - size_t len = strlen((a)); \ + size_t _scstrdup_len = strlen((a)); \ SCLogError(SC_ERR_MEM_ALLOC, "SCStrdup failed: %s, while trying " \ - "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)len); \ + "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)_scstrdup_len); \ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ From d50b4b84711daf23a2e5c3ea650368677edc4123 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 09:59:05 +0100 Subject: [PATCH 2187/2553] content: fix -Wshadow warning --- src/detect-content.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/detect-content.c b/src/detect-content.c index a62b4e274bdf..9b990a940512 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -291,8 +291,7 @@ void DetectContentPrint(DetectContentData *cd) SCLogDebug("DetectContentData \"cd\" is NULL"); return; } - char *tmpstr=SCMalloc(sizeof(char) * cd->content_len + 1); - + char *tmpstr = SCMalloc(sizeof(char) * cd->content_len + 1); if (tmpstr != NULL) { for (i = 0; i < cd->content_len; i++) { if (isprint(cd->content[i])) @@ -318,19 +317,20 @@ void DetectContentPrint(DetectContentData *cd) SCLogDebug("flags: %u ", cd->flags); SCLogDebug("negated: %s ", cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); SCLogDebug("relative match next: %s ", cd->flags & DETECT_CONTENT_RELATIVE_NEXT ? "true" : "false"); + if (cd->replace && cd->replace_len) { - char *tmpstr=SCMalloc(sizeof(char) * cd->replace_len + 1); + char *tmprstr = SCMalloc(sizeof(char) * cd->replace_len + 1); - if (tmpstr != NULL) { + if (tmprstr != NULL) { for (i = 0; i < cd->replace_len; i++) { if (isprint(cd->replace[i])) - tmpstr[i] = cd->replace[i]; + tmprstr[i] = cd->replace[i]; else - tmpstr[i] = '.'; + tmprstr[i] = '.'; } - tmpstr[i] = '\0'; - SCLogDebug("Replace: \"%s\"", tmpstr); - SCFree(tmpstr); + tmprstr[i] = '\0'; + SCLogDebug("Replace: \"%s\"", tmprstr); + SCFree(tmprstr); } else { SCLogDebug("Replace: "); for (i = 0; i < cd->replace_len; i++) From 34b030b45fd68608e7086d93cb451615cf6d797d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:00:35 +0100 Subject: [PATCH 2188/2553] distance: fix -Wshadow warning --- src/detect-distance.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect-distance.c b/src/detect-distance.c index bac5a3cafab0..8be8219bab1d 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -155,15 +155,15 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, goto end; } if (prev_pm->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)prev_pm->ctx; - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + DetectContentData *prev_cd = (DetectContentData *)prev_pm->ctx; + if (prev_cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "previous keyword " "has a fast_pattern:only; set. Can't " "have relative keywords around a fast_pattern " "only content"); goto end; } - cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; + prev_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } else if (prev_pm->type == DETECT_PCRE) { DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx; pd->flags |= DETECT_PCRE_RELATIVE_NEXT; From 691fae6520b3d2abe165fe9e51fa7c4d94ff1587 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:01:52 +0100 Subject: [PATCH 2189/2553] address: fix -Wshadow warning --- src/detect-engine-address.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 1a277c6e1793..af34c07c2182 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -1248,7 +1248,6 @@ int DetectAddressMergeNot(DetectAddressHead *gh, DetectAddressHead *ghn) #endif if (ghn->ipv4_head != NULL || ghn->ipv6_head != NULL) { int cnt = 0; - DetectAddress *ad; for (ad = ghn->ipv4_head; ad; ad = ad->next) cnt++; From 070a6caaf322f04dee60c18e61295f1496af7770 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:03:11 +0100 Subject: [PATCH 2190/2553] app engines: fix -Wshadow warning --- src/detect-engine.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 120b41d0ab73..408b0bd0497d 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -180,13 +180,13 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) s->app_inspect = new_engine; new_engine->inspect_flags = BIT_U32(DE_STATE_FLAG_BASE); // start beyond the built-ins } else { - DetectEngineAppInspectionEngine *t = s->app_inspect; - while (t->next != NULL) { - t = t->next; + DetectEngineAppInspectionEngine *a = s->app_inspect; + while (a->next != NULL) { + a = a->next; } - t->next = new_engine; - new_engine->id = t->id + 1; + a->next = new_engine; + new_engine->id = a->id + 1; new_engine->inspect_flags = BIT_U32(new_engine->id + DE_STATE_FLAG_BASE); } SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id); From f2f0f84ccab2ef060864233d1e908c8c99fb4ed4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:04:25 +0100 Subject: [PATCH 2191/2553] detect: fix -Wshadow warning --- src/detect-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 408b0bd0497d..6be055da560c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -530,7 +530,7 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) * silently after setting RUNNING_DONE flag and while waiting for * THV_DEINIT flag */ if (i != no_of_detect_tvs) { // not all threads we swapped - ThreadVars *tv = tv_root[TVT_PPT]; + tv = tv_root[TVT_PPT]; while (tv) { /* obtain the slots for this TV */ TmSlot *slots = tv->tm_slots; From 47c4a8cd28facb3f172a4dd2fc86a082a398bfb6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:05:51 +0100 Subject: [PATCH 2192/2553] prefilter: fix -Wshadow warnings --- src/detect-engine-prefilter.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index 0b182880300f..1bb2dc649590 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -202,11 +202,11 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, } int PrefilterAppendEngine(SigGroupHead *sgh, - void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), + void (*PrefilterFunc)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), void *pectx, void (*FreeFunc)(void *pectx), const char *name) { - if (sgh == NULL || Prefilter == NULL || pectx == NULL) + if (sgh == NULL || PrefilterFunc == NULL || pectx == NULL) return -1; PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); @@ -214,7 +214,7 @@ int PrefilterAppendEngine(SigGroupHead *sgh, return -1; memset(e, 0x00, sizeof(*e)); - e->Prefilter = Prefilter; + e->Prefilter = PrefilterFunc; e->pectx = pectx; e->Free = FreeFunc; @@ -236,11 +236,11 @@ int PrefilterAppendEngine(SigGroupHead *sgh, } int PrefilterAppendPayloadEngine(SigGroupHead *sgh, - void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), + void (*PrefilterFunc)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), void *pectx, void (*FreeFunc)(void *pectx), const char *name) { - if (sgh == NULL || Prefilter == NULL || pectx == NULL) + if (sgh == NULL || PrefilterFunc == NULL || pectx == NULL) return -1; PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); @@ -248,7 +248,7 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh, return -1; memset(e, 0x00, sizeof(*e)); - e->Prefilter = Prefilter; + e->Prefilter = PrefilterFunc; e->pectx = pectx; e->Free = FreeFunc; @@ -270,14 +270,14 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh, } int PrefilterAppendTxEngine(SigGroupHead *sgh, - void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, + void (*PrefilterTxFunc)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f, void *tx, const uint64_t idx, const uint8_t flags), AppProto alproto, int tx_min_progress, void *pectx, void (*FreeFunc)(void *pectx), const char *name) { - if (sgh == NULL || PrefilterTx == NULL || pectx == NULL) + if (sgh == NULL || PrefilterTxFunc == NULL || pectx == NULL) return -1; PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); @@ -285,7 +285,7 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, return -1; memset(e, 0x00, sizeof(*e)); - e->PrefilterTx = PrefilterTx; + e->PrefilterTx = PrefilterTxFunc; e->pectx = pectx; e->alproto = alproto; e->tx_min_progress = tx_min_progress; From 70452f67a4bae237fb9012e94ab1aa1cc80ae979 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:06:42 +0100 Subject: [PATCH 2193/2553] within: fix -Wshadow warning --- src/detect-within.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detect-within.c b/src/detect-within.c index a0d503e89f76..f10b0275c6f0 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -170,15 +170,15 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, char *within goto end; } if (prev_pm->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)prev_pm->ctx; - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + DetectContentData *prev_cd = (DetectContentData *)prev_pm->ctx; + if (prev_cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "previous keyword " "has a fast_pattern:only; set. Can't " "have relative keywords around a fast_pattern " "only content"); goto end; } - cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; + prev_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } else if (prev_pm->type == DETECT_PCRE) { DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx; pd->flags |= DETECT_PCRE_RELATIVE_NEXT; From 0c3b89356e77c8a6dc7cccfd5b3f3164b4c07189 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:07:09 +0100 Subject: [PATCH 2194/2553] flow: fix -Wshadow warning --- src/flow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flow.c b/src/flow.c index be5ea03e3023..df1dec39ff42 100644 --- a/src/flow.c +++ b/src/flow.c @@ -472,7 +472,7 @@ void FlowShutdown(void) if (flow_hash != NULL) { /* clean up flow mutexes */ for (u = 0; u < flow_config.hash_size; u++) { - Flow *f = flow_hash[u].head; + f = flow_hash[u].head; while (f) { #ifdef DEBUG_VALIDATION BUG_ON(SC_ATOMIC_GET(f->use_cnt) != 0); From 5f786b5cd7cd345c020bbe2e6eba78283def80aa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:07:25 +0100 Subject: [PATCH 2195/2553] host: fix -Wshadow warning --- src/host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host.c b/src/host.c index d992b0a0c352..8df0cde874e1 100644 --- a/src/host.c +++ b/src/host.c @@ -275,7 +275,7 @@ void HostShutdown(void) /* clear and free the hash */ if (host_hash != NULL) { for (u = 0; u < host_config.hash_size; u++) { - Host *h = host_hash[u].head; + h = host_hash[u].head; while (h) { Host *n = h->hnext; HostFree(h); From ed0918bc35aea78599e3bd879607ab9f4d0f6b16 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:07:39 +0100 Subject: [PATCH 2196/2553] ippair: fix -Wshadow warning --- src/ippair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ippair.c b/src/ippair.c index c83aa2b5d898..84137ca8fa3c 100644 --- a/src/ippair.c +++ b/src/ippair.c @@ -271,7 +271,7 @@ void IPPairShutdown(void) /* clear and free the hash */ if (ippair_hash != NULL) { for (u = 0; u < ippair_config.hash_size; u++) { - IPPair *h = ippair_hash[u].head; + h = ippair_hash[u].head; while (h) { IPPair *n = h->hnext; IPPairFree(h); From 9477fd46287f8285f555e8b15a4542d6d4a3dfe9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:09:16 +0100 Subject: [PATCH 2197/2553] eve-file: fix -Wshadow warnings --- src/output-json-file.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/output-json-file.c b/src/output-json-file.c index 29b3d0e5d1e6..b47340aa6597 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -128,29 +128,29 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F if (ff->flags & FILE_MD5) { size_t x; int i; - char s[256]; + char str[256]; for (i = 0, x = 0; x < sizeof(ff->md5); x++) { - i += snprintf(&s[i], 255-i, "%02x", ff->md5[x]); + i += snprintf(&str[i], 255-i, "%02x", ff->md5[x]); } - json_object_set_new(fjs, "md5", json_string(s)); + json_object_set_new(fjs, "md5", json_string(str)); } if (ff->flags & FILE_SHA1) { size_t x; int i; - char s[256]; + char str[256]; for (i = 0, x = 0; x < sizeof(ff->sha1); x++) { - i += snprintf(&s[i], 255-i, "%02x", ff->sha1[x]); + i += snprintf(&str[i], 255-i, "%02x", ff->sha1[x]); } - json_object_set_new(fjs, "sha1", json_string(s)); + json_object_set_new(fjs, "sha1", json_string(str)); } if (ff->flags & FILE_SHA256) { size_t x; int i; - char s[256]; + char str[256]; for (i = 0, x = 0; x < sizeof(ff->sha256); x++) { - i += snprintf(&s[i], 255-i, "%02x", ff->sha256[x]); + i += snprintf(&str[i], 255-i, "%02x", ff->sha256[x]); } - json_object_set_new(fjs, "sha256", json_string(s)); + json_object_set_new(fjs, "sha256", json_string(str)); } #endif break; From d893bc55e0fa19c2ae1bc3d71494c7a713029c8f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:10:40 +0100 Subject: [PATCH 2198/2553] eve-flow: fix -Wshadow warning --- src/output-json-flow.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/output-json-flow.c b/src/output-json-flow.c index d5fe37cd73a1..cf65c51da2ba 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -289,46 +289,46 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) JsonTcpFlags(ssn ? ssn->tcp_packet_flags : 0, tjs); if (ssn) { - char *state = NULL; + char *tcp_state = NULL; switch (ssn->state) { case TCP_NONE: - state = "none"; + tcp_state = "none"; break; case TCP_LISTEN: - state = "listen"; + tcp_state = "listen"; break; case TCP_SYN_SENT: - state = "syn_sent"; + tcp_state = "syn_sent"; break; case TCP_SYN_RECV: - state = "syn_recv"; + tcp_state = "syn_recv"; break; case TCP_ESTABLISHED: - state = "established"; + tcp_state = "established"; break; case TCP_FIN_WAIT1: - state = "fin_wait1"; + tcp_state = "fin_wait1"; break; case TCP_FIN_WAIT2: - state = "fin_wait2"; + tcp_state = "fin_wait2"; break; case TCP_TIME_WAIT: - state = "time_wait"; + tcp_state = "time_wait"; break; case TCP_LAST_ACK: - state = "last_ack"; + tcp_state = "last_ack"; break; case TCP_CLOSE_WAIT: - state = "close_wait"; + tcp_state = "close_wait"; break; case TCP_CLOSING: - state = "closing"; + tcp_state = "closing"; break; case TCP_CLOSED: - state = "closed"; + tcp_state = "closed"; break; } - json_object_set_new(tjs, "state", json_string(state)); + json_object_set_new(tjs, "state", json_string(tcp_state)); } json_object_set_new(js, "tcp", tjs); From 65d2443ccdb37e3203ef6178cde061cf3728ed31 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:11:44 +0100 Subject: [PATCH 2199/2553] reputation: fix -Wshadow warnings --- src/reputation.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/reputation.c b/src/reputation.c index 6f03ce98c798..232871817c14 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -1109,17 +1109,17 @@ Reputation *SCReputationClone(Reputation *orig) return rep; } -void SCReputationFreeCtx(IPReputationCtx *rep_ctx) +void SCReputationFreeCtx(IPReputationCtx *ctx) { - if (rep_ctx->reputationIPV4_tree != NULL) { - SCRadixReleaseRadixTree(rep_ctx->reputationIPV4_tree); - rep_ctx->reputationIPV4_tree = NULL; - SCMutexDestroy(&rep_ctx->reputationIPV4_lock); - } - if (rep_ctx->reputationIPV6_tree != NULL) { - SCRadixReleaseRadixTree(rep_ctx->reputationIPV6_tree); - rep_ctx->reputationIPV6_tree = NULL; - SCMutexDestroy(&rep_ctx->reputationIPV6_lock); + if (ctx->reputationIPV4_tree != NULL) { + SCRadixReleaseRadixTree(ctx->reputationIPV4_tree); + ctx->reputationIPV4_tree = NULL; + SCMutexDestroy(&ctx->reputationIPV4_lock); + } + if (ctx->reputationIPV6_tree != NULL) { + SCRadixReleaseRadixTree(ctx->reputationIPV6_tree); + ctx->reputationIPV6_tree = NULL; + SCMutexDestroy(&ctx->reputationIPV6_lock); } } From 69ee2f0eb94b62d1971836cb6abc8b2027ef2dba Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:18:03 +0100 Subject: [PATCH 2200/2553] nfq: fix -Wshadow warnings Rename globals to make sure it's clear they are globals. --- src/source-nfq.c | 89 ++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/src/source-nfq.c b/src/source-nfq.c index 749bf2d1caf4..a53d080c3652 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -136,8 +136,8 @@ typedef struct NFQThreadVars_ /* shared vars for all for nfq queues and threads */ static NFQGlobalVars nfq_g; -static NFQThreadVars nfq_t[NFQ_MAX_QUEUE]; -static NFQQueueVars nfq_q[NFQ_MAX_QUEUE]; +static NFQThreadVars g_nfq_t[NFQ_MAX_QUEUE]; +static NFQQueueVars g_nfq_q[NFQ_MAX_QUEUE]; static uint16_t receive_queue_num = 0; static SCMutex nfq_init_lock; @@ -555,10 +555,10 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, ret = NFQSetupPkt(p, qh, (void *)nfa); if (ret == -1) { #ifdef COUNTERS - NFQQueueVars *nfq_q = NFQGetQueue(ntv->nfq_index); - nfq_q->errs++; - nfq_q->pkts++; - nfq_q->bytes += GET_PKT_LEN(p); + NFQQueueVars *q = NFQGetQueue(ntv->nfq_index); + q->errs++; + q->pkts++; + q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ /* NFQSetupPkt is issuing a verdict so we only recycle Packet and leave */ @@ -569,9 +569,9 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, p->ReleasePacket = NFQReleasePacket; #ifdef COUNTERS - NFQQueueVars *nfq_q = NFQGetQueue(ntv->nfq_index); - nfq_q->pkts++; - nfq_q->bytes += GET_PKT_LEN(p); + NFQQueueVars *q = NFQGetQueue(ntv->nfq_index); + q->pkts++; + q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ if (ntv->slot) { @@ -587,20 +587,20 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, return 0; } -TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) +TmEcode NFQInitThread(NFQThreadVars *t, uint32_t queue_maxlen) { #ifndef OS_WIN32 struct timeval tv; int opt; #endif - NFQQueueVars *nfq_q = NFQGetQueue(nfq_t->nfq_index); - if (nfq_q == NULL) { + NFQQueueVars *q = NFQGetQueue(t->nfq_index); + if (q == NULL) { SCLogError(SC_ERR_NFQ_OPEN, "no queue for given index"); return TM_ECODE_FAILED; } SCLogDebug("opening library handle"); - nfq_q->h = nfq_open(); - if (!nfq_q->h) { + q->h = nfq_open(); + if (q->h == NULL) { SCLogError(SC_ERR_NFQ_OPEN, "nfq_open() failed"); return TM_ECODE_FAILED; } @@ -610,11 +610,11 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) /* VJ: on my Ubuntu Hardy system this fails the first time it's * run. Ignoring the error seems to have no bad effects. */ SCLogDebug("unbinding existing nf_queue handler for AF_INET (if any)"); - if (nfq_unbind_pf(nfq_q->h, AF_INET) < 0) { + if (nfq_unbind_pf(q->h, AF_INET) < 0) { SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET failed"); exit(EXIT_FAILURE); } - if (nfq_unbind_pf(nfq_q->h, AF_INET6) < 0) { + if (nfq_unbind_pf(q->h, AF_INET6) < 0) { SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET6 failed"); exit(EXIT_FAILURE); } @@ -622,23 +622,22 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) SCLogDebug("binding nfnetlink_queue as nf_queue handler for AF_INET and AF_INET6"); - if (nfq_bind_pf(nfq_q->h, AF_INET) < 0) { + if (nfq_bind_pf(q->h, AF_INET) < 0) { SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET failed"); exit(EXIT_FAILURE); } - if (nfq_bind_pf(nfq_q->h, AF_INET6) < 0) { + if (nfq_bind_pf(q->h, AF_INET6) < 0) { SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET6 failed"); exit(EXIT_FAILURE); } } - SCLogInfo("binding this thread %d to queue '%" PRIu32 "'", nfq_t->nfq_index, nfq_q->queue_num); + SCLogInfo("binding this thread %d to queue '%" PRIu32 "'", t->nfq_index, q->queue_num); /* pass the thread memory as a void ptr so the * callback function has access to it. */ - nfq_q->qh = nfq_create_queue(nfq_q->h, nfq_q->queue_num, &NFQCallBack, (void *)nfq_t); - if (nfq_q->qh == NULL) - { + q->qh = nfq_create_queue(q->h, q->queue_num, &NFQCallBack, (void *)t); + if (q->qh == NULL) { SCLogError(SC_ERR_NFQ_CREATE_QUEUE, "nfq_create_queue failed"); return TM_ECODE_FAILED; } @@ -647,7 +646,7 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) /* 05DC = 1500 */ //if (nfq_set_mode(nfq_t->qh, NFQNL_COPY_PACKET, 0x05DC) < 0) { - if (nfq_set_mode(nfq_q->qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) { + if (nfq_set_mode(q->qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) { SCLogError(SC_ERR_NFQ_SET_MODE, "can't set packet_copy mode"); return TM_ECODE_FAILED; } @@ -657,7 +656,7 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) SCLogInfo("setting queue length to %" PRId32 "", queue_maxlen); /* non-fatal if it fails */ - if (nfq_set_queue_maxlen(nfq_q->qh, queue_maxlen) < 0) { + if (nfq_set_queue_maxlen(q->qh, queue_maxlen) < 0) { SCLogWarning(SC_ERR_NFQ_MAXLEN, "can't set queue maxlen: your kernel probably " "doesn't support setting the queue length"); } @@ -666,18 +665,18 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) #ifndef OS_WIN32 /* set netlink buffer size to a decent value */ - nfnl_rcvbufsiz(nfq_nfnlh(nfq_q->h), queue_maxlen * 1500); + nfnl_rcvbufsiz(nfq_nfnlh(q->h), queue_maxlen * 1500); SCLogInfo("setting nfnl bufsize to %" PRId32 "", queue_maxlen * 1500); - nfq_q->nh = nfq_nfnlh(nfq_q->h); - nfq_q->fd = nfnl_fd(nfq_q->nh); - NFQMutexInit(nfq_q); + q->nh = nfq_nfnlh(q->h); + q->fd = nfnl_fd(q->nh); + NFQMutexInit(q); /* Set some netlink specific option on the socket to increase performance */ opt = 1; #ifdef NETLINK_BROADCAST_SEND_ERROR - if (setsockopt(nfq_q->fd, SOL_NETLINK, + if (setsockopt(q->fd, SOL_NETLINK, NETLINK_BROADCAST_SEND_ERROR, &opt, sizeof(int)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set netlink broadcast error: %s", @@ -687,7 +686,7 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) /* Don't send error about no buffer space available but drop the packets instead */ #ifdef NETLINK_NO_ENOBUFS - if (setsockopt(nfq_q->fd, SOL_NETLINK, + if (setsockopt(q->fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(int)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set netlink enobufs: %s", @@ -699,7 +698,7 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) if (nfq_config.flags & NFQ_FLAG_FAIL_OPEN) { uint32_t flags = NFQA_CFG_F_FAIL_OPEN; uint32_t mask = NFQA_CFG_F_FAIL_OPEN; - int r = nfq_set_queue_flags(nfq_q->qh, mask, flags); + int r = nfq_set_queue_flags(q->qh, mask, flags); if (r == -1) { SCLogWarning(SC_ERR_NFQ_SET_MODE, "can't set fail-open mode: %s", @@ -712,7 +711,7 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) #ifdef HAVE_NFQ_SET_VERDICT_BATCH if (runmode_workers) { - nfq_q->verdict_cache.maxlen = nfq_config.batchcount; + q->verdict_cache.maxlen = nfq_config.batchcount; } else if (nfq_config.batchcount) { SCLogError(SC_ERR_INVALID_ARGUMENT, "nfq.batchcount is only valid in workers runmode."); } @@ -723,17 +722,17 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) tv.tv_sec = 1; tv.tv_usec = 0; - if(setsockopt(nfq_q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { + if(setsockopt(q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set socket timeout: %s", strerror(errno)); } SCLogDebug("nfq_q->h %p, nfq_q->nh %p, nfq_q->qh %p, nfq_q->fd %" PRId32 "", - nfq_q->h, nfq_q->nh, nfq_q->qh, nfq_q->fd); + q->h, q->nh, q->qh, q->fd); #else /* OS_WIN32 */ - NFQMutexInit(nfq_q); - nfq_q->ovr.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - nfq_q->fd = nfq_fd(nfq_q->h); - SCLogDebug("nfq_q->h %p, nfq_q->qh %p, nfq_q->fd %p", nfq_q->h, nfq_q->qh, nfq_q->fd); + NFQMutexInit(q); + q->ovr.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + q->fd = nfq_fd(q->h); + SCLogDebug("q->h %p, q->qh %p, q->fd %p", q->h, q->qh, q->fd); #endif /* OS_WIN32 */ return TM_ECODE_OK; @@ -857,14 +856,14 @@ int NFQRegisterQueue(char *queue) return -1; } if (receive_queue_num == 0) { - memset(&nfq_t, 0, sizeof(nfq_t)); - memset(&nfq_q, 0, sizeof(nfq_q)); + memset(&g_nfq_t, 0, sizeof(g_nfq_t)); + memset(&g_nfq_q, 0, sizeof(g_nfq_q)); } - ntv = &nfq_t[receive_queue_num]; + ntv = &g_nfq_t[receive_queue_num]; ntv->nfq_index = receive_queue_num; - nq = &nfq_q[receive_queue_num]; + nq = &g_nfq_q[receive_queue_num]; nq->queue_num = queue_num; receive_queue_num++; SCMutexUnlock(&nfq_init_lock); @@ -889,7 +888,7 @@ void *NFQGetQueue(int number) if (number >= receive_queue_num) return NULL; - return (void *)&nfq_q[number]; + return (void *)&g_nfq_q[number]; } /** @@ -907,7 +906,7 @@ void *NFQGetThread(int number) if (number >= receive_queue_num) return NULL; - return (void *)&nfq_t[number]; + return (void *)&g_nfq_t[number]; } /** @@ -1082,7 +1081,7 @@ TmEcode NFQSetVerdict(Packet *p) int ret = 0; uint32_t verdict = NF_ACCEPT; /* we could also have a direct pointer but we need to have a ref counf in this case */ - NFQQueueVars *t = nfq_q + p->nfq_v.nfq_index; + NFQQueueVars *t = g_nfq_q + p->nfq_v.nfq_index; /** \todo add a test on validity of the entry NFQQueueVars could have been * wipeout From cd04da673b626676128ba2c7459de8ecee279f2e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:21:53 +0100 Subject: [PATCH 2201/2553] commandline: fix -Wshadow warnings --- src/suricata.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 292ffd708e47..e649fe7b0166 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -861,12 +861,12 @@ static TmEcode LoadYamlConfig(SCInstance *suri) SCReturnInt(TM_ECODE_OK); } -static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) +static TmEcode ParseInterfacesList(int runmode, char *pcap_dev) { SCEnter(); /* run the selected runmode */ - if (run_mode == RUNMODE_PCAP_DEV) { + if (runmode == RUNMODE_PCAP_DEV) { if (strlen(pcap_dev) == 0) { int ret = LiveBuildDeviceList("pcap"); if (ret == 0) { @@ -875,7 +875,7 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) } } #ifdef HAVE_MPIPE - } else if (run_mode == RUNMODE_TILERA_MPIPE) { + } else if (runmode == RUNMODE_TILERA_MPIPE) { if (strlen(pcap_dev)) { if (ConfSetFinal("mpipe.single_mpipe_dev", pcap_dev) != 1) { fprintf(stderr, "ERROR: Failed to set mpipe.single_mpipe_dev\n"); @@ -889,7 +889,7 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) } } #endif - } else if (run_mode == RUNMODE_PFRING) { + } else if (runmode == RUNMODE_PFRING) { /* FIXME add backward compat support */ /* iface has been set on command line */ if (strlen(pcap_dev)) { @@ -902,7 +902,7 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) LiveBuildDeviceList("pfring"); } #ifdef HAVE_AF_PACKET - } else if (run_mode == RUNMODE_AFP_DEV) { + } else if (runmode == RUNMODE_AFP_DEV) { /* iface has been set on command line */ if (strlen(pcap_dev)) { if (ConfSetFinal("af-packet.live-interface", pcap_dev) != 1) { @@ -922,7 +922,7 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) } #endif #ifdef HAVE_NETMAP - } else if (run_mode == RUNMODE_NETMAP) { + } else if (runmode == RUNMODE_NETMAP) { /* iface has been set on command line */ if (strlen(pcap_dev)) { if (ConfSetFinal("netmap.live-interface", pcap_dev) != 1) { @@ -942,7 +942,7 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) } #endif #ifdef HAVE_NFLOG - } else if (run_mode == RUNMODE_NFLOG) { + } else if (runmode == RUNMODE_NFLOG) { int ret = LiveBuildDeviceListCustom("nflog", "group"); if (ret == 0) { SCLogError(SC_ERR_INITIALIZATION, "No group found in config for nflog"); From 0d6d8e01c82cf31ec6e09137d350e0b0e692bab2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:27:18 +0100 Subject: [PATCH 2202/2553] threads: fix -Wshadow warnings --- src/threads.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/threads.h b/src/threads.h index 213b064243b3..6a1329dea2b5 100644 --- a/src/threads.h +++ b/src/threads.h @@ -216,47 +216,47 @@ enum { #define SCGetThreadIdLong(...) ({ \ long tmpthid; \ thr_self(&tmpthid); \ - u_long tid = (u_long)tmpthid; \ - tid; \ + u_long _scgetthread_tid = (u_long)tmpthid; \ + _scgetthread_tid; \ }) #elif __OpenBSD__ #define SCGetThreadIdLong(...) ({ \ pid_t tpid; \ tpid = getpid(); \ - u_long tid = (u_long)tpid; \ - tid; \ + u_long _scgetthread_tid = (u_long)tpid; \ + _scgetthread_tid; \ }) #elif __CYGWIN__ #define SCGetThreadIdLong(...) ({ \ - u_long tid = (u_long)GetCurrentThreadId(); \ - tid; \ + u_long _scgetthread_tid = (u_long)GetCurrentThreadId(); \ + _scgetthread_tid; \ }) #elif OS_WIN32 #define SCGetThreadIdLong(...) ({ \ - u_long tid = (u_long)GetCurrentThreadId(); \ - tid; \ + u_long _scgetthread_tid = (u_long)GetCurrentThreadId(); \ + _scgetthread_tid; \ }) #elif OS_DARWIN #define SCGetThreadIdLong(...) ({ \ thread_port_t tpid; \ tpid = mach_thread_self(); \ - u_long tid = (u_long)tpid; \ - tid; \ + u_long _scgetthread_tid = (u_long)tpid; \ + _scgetthread_tid; \ }) #elif defined(sun) #include #define SCGetThreadIdLong(...) ({ \ thread_t tmpthid = thr_self(); \ - u_long tid = (u_long)tmpthid; \ - tid; \ + u_long _scgetthread_tid = (u_long)tmpthid; \ + _scgetthread_tid; \ }) #else #define SCGetThreadIdLong(...) ({ \ pid_t tmpthid; \ tmpthid = syscall(SYS_gettid); \ - u_long tid = (u_long)tmpthid; \ - tid; \ + u_long _scgetthread_tid = (u_long)tmpthid; \ + _scgetthread_tid; \ }) #endif /* OS FREEBSD */ From 8c1d157cd22b14ec1d6c4ae2cb4de22865f89f0b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:27:34 +0100 Subject: [PATCH 2203/2553] mpm ac-bs: fix -Wshadow warnings --- src/util-mpm-ac-bs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 07bbd08d8ef2..049a5776557f 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -1210,10 +1210,10 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, match_u16: if (state & 0x8000) { - uint32_t no_of_entries = ctx->output_table[state & 0x7FFF].no_of_entries; + uint32_t nentries = ctx->output_table[state & 0x7FFF].no_of_entries; uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; uint32_t k; - for (k = 0; k < no_of_entries; k++) { + for (k = 0; k < nentries; k++) { if (pids[k] & 0xFFFF0000) { uint32_t lower_pid = pids[k] & 0x0000FFFF; if (SCMemcmp(pid_pat_list[lower_pid].cs, @@ -1294,10 +1294,10 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, match_u32: if (state & 0xFF000000) { - uint32_t no_of_entries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; + uint32_t nentries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; uint32_t k; - for (k = 0; k < no_of_entries; k++) { + for (k = 0; k < nentries; k++) { if (pids[k] & 0xFFFF0000) { uint32_t lower_pid = pids[k] & 0x0000FFFF; if (SCMemcmp(pid_pat_list[lower_pid].cs, From bb2d8a713382984b90b20d425230f32ce4106b3e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 10:29:25 +0100 Subject: [PATCH 2204/2553] runmodes: fix -Wshadow warnings --- src/util-runmodes.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/util-runmodes.c b/src/util-runmodes.c index 6800eb5e75c6..e4b05a64ad74 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -169,21 +169,21 @@ int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, int lthread; for (lthread = 0; lthread < nlive; lthread++) { - const char *live_dev = LiveGetDeviceName(lthread); + const char *dev = LiveGetDeviceName(lthread); const char *visual_devname = LiveGetShortName(live_dev); void *aconf; int threads_count; - if (live_dev == NULL) { + if (dev == NULL) { SCLogError(SC_ERR_RUNMODE, "Failed to lookup live dev %d", lthread); exit(EXIT_FAILURE); } - SCLogDebug("live_dev %s", live_dev); + SCLogDebug("dev %s", dev); - aconf = ConfigParser(live_dev); + aconf = ConfigParser(dev); if (aconf == NULL) { SCLogError(SC_ERR_RUNMODE, "Multidev: Failed to allocate config for %s (%d)", - live_dev, lthread); + dev, lthread); exit(EXIT_FAILURE); } @@ -467,7 +467,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } - TmModule *tm_module = TmModuleGetByName(recv_mod_name); + tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName failed for %s", recv_mod_name); exit(EXIT_FAILURE); @@ -505,7 +505,7 @@ int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, exit(EXIT_FAILURE); } - TmModule *tm_module = TmModuleGetByName("FlowWorker"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); @@ -609,7 +609,7 @@ int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, } TmSlotSetFuncAppend(tv, tm_module, NULL); - TmModule *tm_module = TmModuleGetByName("FlowWorker"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); From 968813b6559586d6ccb47bf4c8fba51c04036c81 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 12:24:03 +0100 Subject: [PATCH 2205/2553] dnp3: fix test for -Wshadow --- src/app-layer-dnp3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-dnp3.c b/src/app-layer-dnp3.c index c5cb45480f59..3c84d544d302 100644 --- a/src/app-layer-dnp3.c +++ b/src/app-layer-dnp3.c @@ -2070,8 +2070,8 @@ static int DNP3ProbingParserTest(void) FAIL_IF(DNP3ProbingParser(pkt, sizeof(pkt), NULL) != ALPROTO_FAILED); /* Send a banner. */ - char banner[] = "Welcome to DNP3 SCADA."; - FAIL_IF(DNP3ProbingParser((uint8_t *)banner, sizeof(banner), NULL) != ALPROTO_DNP3); + char mybanner[] = "Welcome to DNP3 SCADA."; + FAIL_IF(DNP3ProbingParser((uint8_t *)mybanner, sizeof(mybanner), NULL) != ALPROTO_DNP3); PASS; } From 613174e9ceff45b28b511c6ee4e06cbbf4318e1e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 12:24:19 +0100 Subject: [PATCH 2206/2553] yaml: fix tests for -Wshadow --- src/conf.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/conf.c b/src/conf.c index 606ef650834f..59e5aef47aae 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1109,13 +1109,13 @@ static int ConfGetChildValueWithDefaultTest(void) ConfSet("af-packet.1.interface", "default"); ConfSet("af-packet.1.cluster-type", "cluster_cpu"); - ConfNode *root = ConfGetNode("af-packet.0"); + ConfNode *myroot = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); - ConfGetChildValueWithDefault(root, dflt, "cluster-type", &val); + ConfGetChildValueWithDefault(myroot, dflt, "cluster-type", &val); FAIL_IF(strcmp(val, "cluster_cpu")); ConfSet("af-packet.0.cluster-type", "cluster_flow"); - ConfGetChildValueWithDefault(root, dflt, "cluster-type", &val); + ConfGetChildValueWithDefault(myroot, dflt, "cluster-type", &val); FAIL_IF(strcmp(val, "cluster_flow")); @@ -1133,13 +1133,13 @@ static int ConfGetChildValueIntWithDefaultTest(void) ConfSet("af-packet.1.interface", "default"); ConfSet("af-packet.1.threads", "2"); - ConfNode *root = ConfGetNode("af-packet.0"); + ConfNode *myroot = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); - ConfGetChildValueIntWithDefault(root, dflt, "threads", &val); + ConfGetChildValueIntWithDefault(myroot, dflt, "threads", &val); FAIL_IF(val != 2); ConfSet("af-packet.0.threads", "1"); - ConfGetChildValueIntWithDefault(root, dflt, "threads", &val); + ConfGetChildValueIntWithDefault(myroot, dflt, "threads", &val); FAIL_IF(val != 1); ConfDeInit(); @@ -1157,13 +1157,13 @@ static int ConfGetChildValueBoolWithDefaultTest(void) ConfSet("af-packet.1.interface", "default"); ConfSet("af-packet.1.use-mmap", "yes"); - ConfNode *root = ConfGetNode("af-packet.0"); + ConfNode *myroot = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); - ConfGetChildValueBoolWithDefault(root, dflt, "use-mmap", &val); + ConfGetChildValueBoolWithDefault(myroot, dflt, "use-mmap", &val); FAIL_IF(val == 0); ConfSet("af-packet.0.use-mmap", "no"); - ConfGetChildValueBoolWithDefault(root, dflt, "use-mmap", &val); + ConfGetChildValueBoolWithDefault(myroot, dflt, "use-mmap", &val); FAIL_IF(val); ConfDeInit(); From dab51144af030982d96f71a5cfde9091c43babfd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 12:24:35 +0100 Subject: [PATCH 2207/2553] asn1: modernize test --- src/detect-asn1.c | 86 +++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/src/detect-asn1.c b/src/detect-asn1.c index bb12180750fb..587cb96811c0 100644 --- a/src/detect-asn1.c +++ b/src/detect-asn1.c @@ -636,67 +636,59 @@ int DetectAsn1TestParse15(void) /** * \test DetectAsn1Test01 Ensure that the checks work when they should */ -int DetectAsn1Test01(void) +static int DetectAsn1Test01(void) { - int result = 0; /* Match if any of the nodes after offset 0 has greater length than 10 */ char str[] = "oversize_length 132 absolute_offset 0"; - DetectAsn1Data *ad = NULL; - - ad = DetectAsn1Parse(str); - if (ad != NULL && ad->oversize_length == 132 - && (ad->flags & ASN1_OVERSIZE_LEN) - && ad->absolute_offset == 0 - && (ad->flags & ASN1_ABSOLUTE_OFFSET)) - { - // Example from the specification X.690-0207 Appendix A.3 - uint8_t *str = (uint8_t*) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" - "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" - "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" - "Jones""\xA0\x0A\x43\x08""19590717"; - - Asn1Ctx *ac = SCAsn1CtxNew(); - if (ac == NULL) - return 0; - uint16_t len = strlen((char *)str)-1; - - SCAsn1CtxInit(ac, str, len); + DetectAsn1Data *ad = DetectAsn1Parse(str); + FAIL_IF_NULL(ad); + FAIL_IF_NOT(ad->oversize_length == 132); + FAIL_IF_NOT(ad->flags & ASN1_OVERSIZE_LEN); + FAIL_IF_NOT(ad->absolute_offset == 0); + FAIL_IF_NOT(ad->flags & ASN1_ABSOLUTE_OFFSET); + + // Example from the specification X.690-0207 Appendix A.3 + char buf[] = "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" + "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" + "\x42\x01\x33\xA1\x0A\x43\x08""19710917" + "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" + "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" + "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" + "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" + "Jones""\xA0\x0A\x43\x08""19590717"; - SCAsn1Decode(ac, ac->cur_frame); + Asn1Ctx *ac = SCAsn1CtxNew(); + FAIL_IF_NULL(ac); - /* The first node has length 133, so it should match the oversize */ - if (ac->cur_frame > 0) { - /* We spect at least one node */ - uint16_t n_iter = 0; + uint16_t len = strlen((char *)buf)-1; - for (; n_iter <= ac->cur_frame; n_iter++) { - Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); + SCAsn1CtxInit(ac, (uint8_t *)buf, len); + SCAsn1Decode(ac, ac->cur_frame); - if (node == NULL || node->id.ptr == NULL) - continue; /* Should not happen */ + /* The first node has length 133, so it should match the oversize */ + FAIL_IF_NOT(ac->cur_frame > 0); - result = DetectAsn1Checks(node, ad); - /* Got a match? */ - if (result == 1) - break; - } - } + /* We spect at least one node */ + uint16_t n_iter = 0; + int result = 0; + for (; n_iter <= ac->cur_frame; n_iter++) { + Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); - SCAsn1CtxDestroy(ac); - DetectAsn1Free(ad); + if (node == NULL || node->id.ptr == NULL) + continue; /* Should not happen */ + result = DetectAsn1Checks(node, ad); + /* Got a match? */ + if (result == 1) + break; } + FAIL_IF(result != 1); - if (result == 0) { - printf("Error, oversize_length should match the first node: "); - } + SCAsn1CtxDestroy(ac); + DetectAsn1Free(ad); - return result; + PASS; } /** From 9a20335b6de9876d7c0b18350645d007f0ab6eea Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 12:36:26 +0100 Subject: [PATCH 2208/2553] asn1: fix -Wshadow warnings --- src/detect-asn1.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/detect-asn1.c b/src/detect-asn1.c index 587cb96811c0..c9602bdb767e 100644 --- a/src/detect-asn1.c +++ b/src/detect-asn1.c @@ -708,7 +708,7 @@ int DetectAsn1Test02(void) && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { // Example from the specification X.690-0207 Appendix A.3 - uint8_t *str = (uint8_t*) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" + uint8_t *buf = (uint8_t*) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" @@ -721,9 +721,9 @@ int DetectAsn1Test02(void) if (ac == NULL) return 0; - uint16_t len = strlen((char *)str)-1; + uint16_t len = strlen((char *)buf)-1; - SCAsn1CtxInit(ac, str, len); + SCAsn1CtxInit(ac, buf, len); SCAsn1Decode(ac, ac->cur_frame); @@ -777,7 +777,7 @@ int DetectAsn1Test03(void) /* Let's say tagnum bitstring, primitive, and as universal tag, * and then length = 1 octet, but the next octet specify to ignore * the last 256 bits... (let's match!) */ - uint8_t *str = (uint8_t*) "\x03\x01\xFF"; + uint8_t *buf = (uint8_t*) "\x03\x01\xFF"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) @@ -785,7 +785,7 @@ int DetectAsn1Test03(void) uint16_t len = 3; - SCAsn1CtxInit(ac, str, len); + SCAsn1CtxInit(ac, buf, len); SCAsn1Decode(ac, ac->cur_frame); @@ -836,7 +836,7 @@ int DetectAsn1Test04(void) /* Let's say tagnum bitstring, primitive, and as universal tag, * and then length = 1 octet, but the next octet specify to ignore * the last 7 bits... (should not match) */ - uint8_t *str = (uint8_t*) "\x03\x01\x07"; + uint8_t *buf = (uint8_t*) "\x03\x01\x07"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) @@ -844,7 +844,7 @@ int DetectAsn1Test04(void) uint16_t len = 3; - SCAsn1CtxInit(ac, str, len); + SCAsn1CtxInit(ac, buf, len); SCAsn1Decode(ac, ac->cur_frame); @@ -897,19 +897,19 @@ int DetectAsn1Test05(void) { /* Let's say tag num 9 (type Real), and encoded as ASCII, with length * 257, then we must match */ - uint8_t str[261]; + uint8_t buf[261]; /* universal class, primitive type, tag_num = 9 (Data type Real) */ - str[0] = '\x09'; + buf[0] = '\x09'; /* length, definite form, 2 octets */ - str[1] = '\x82'; + buf[1] = '\x82'; /* length is the sum of the following octets (257): */ - str[2] = '\xFE'; - str[3] = '\x03'; + buf[2] = '\xFE'; + buf[3] = '\x03'; /* Fill the content of the number */ uint16_t i = 4; for (; i < 257;i++) - str[i] = '\x05'; + buf[i] = '\x05'; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) @@ -917,7 +917,7 @@ int DetectAsn1Test05(void) uint16_t len = 261; - SCAsn1CtxInit(ac, str, len); + SCAsn1CtxInit(ac, buf, len); SCAsn1Decode(ac, ac->cur_frame); @@ -967,19 +967,19 @@ int DetectAsn1Test06(void) { /* Let's say tag num 9 (type Real), and encoded as ASCII, with length * 256, which fit in the buffer, so it should not match */ - uint8_t str[260]; + uint8_t buf[260]; /* universal class, primitive type, tag_num = 9 (Data type Real) */ - str[0] = '\x09'; + buf[0] = '\x09'; /* length, definite form, 2 octets */ - str[1] = '\x82'; + buf[1] = '\x82'; /* length is the sum of the following octets (256): */ - str[2] = '\xFE'; - str[3] = '\x02'; + buf[2] = '\xFE'; + buf[3] = '\x02'; /* Fill the content of the number */ uint16_t i = 4; for (; i < 256;i++) - str[i] = '\x05'; + buf[i] = '\x05'; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) @@ -987,7 +987,7 @@ int DetectAsn1Test06(void) uint16_t len = 260; - SCAsn1CtxInit(ac, str, len); + SCAsn1CtxInit(ac, buf, len); SCAsn1Decode(ac, ac->cur_frame); From 66c213f30c5d0eb85e09a7917324303f0f0cd15d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 12:36:41 +0100 Subject: [PATCH 2209/2553] detect-address: fix -Wshadow warnings --- src/detect-engine-address.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index af34c07c2182..4720d5e31ddc 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -3261,11 +3261,11 @@ int AddressTestAddressGroupSetup04(void) r = DetectAddressParse(NULL, gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { - DetectAddress *prev_head = gh->ipv4_head; + DetectAddress *ph = gh->ipv4_head; r = DetectAddressParse(NULL, gh, "1.2.3.2"); - if (r == 0 && gh->ipv4_head != prev_head && - gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { + if (r == 0 && gh->ipv4_head != ph && + gh->ipv4_head != NULL && gh->ipv4_head->next == ph) { result = 1; } } @@ -3289,11 +3289,11 @@ int AddressTestAddressGroupSetup05(void) r = DetectAddressParse(NULL, gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next != prev_head) { - DetectAddress *prev_head = gh->ipv4_head; + DetectAddress *ph = gh->ipv4_head; r = DetectAddressParse(NULL, gh, "1.2.3.4"); - if (r == 0 && gh->ipv4_head == prev_head && - gh->ipv4_head != NULL && gh->ipv4_head->next != prev_head) { + if (r == 0 && gh->ipv4_head == ph && + gh->ipv4_head != NULL && gh->ipv4_head->next != ph) { result = 1; } } @@ -3674,11 +3674,11 @@ int AddressTestAddressGroupSetup17(void) r = DetectAddressParse(NULL, gh, "2001::3"); if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { - DetectAddress *prev_head = gh->ipv6_head; + DetectAddress *ph = gh->ipv6_head; r = DetectAddressParse(NULL, gh, "2001::2"); - if (r == 0 && gh->ipv6_head != prev_head && - gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { + if (r == 0 && gh->ipv6_head != ph && + gh->ipv6_head != NULL && gh->ipv6_head->next == ph) { result = 1; } } @@ -3702,11 +3702,11 @@ int AddressTestAddressGroupSetup18(void) r = DetectAddressParse(NULL, gh, "2001::3"); if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next != prev_head) { - DetectAddress *prev_head = gh->ipv6_head; + DetectAddress *ph = gh->ipv6_head; r = DetectAddressParse(NULL, gh, "2001::4"); - if (r == 0 && gh->ipv6_head == prev_head && - gh->ipv6_head != NULL && gh->ipv6_head->next != prev_head) { + if (r == 0 && gh->ipv6_head == ph && + gh->ipv6_head != NULL && gh->ipv6_head->next != ph) { result = 1; } } From 783d2991e5c0bfb2eaa317e3cfd626410ffbada2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 12:51:52 +0100 Subject: [PATCH 2210/2553] commandline: fix -Wshadow warnings --- src/suricata.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index e649fe7b0166..1238f972d14d 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -355,14 +355,14 @@ void EngineDone(void) suricata_ctl_flags |= SURICATA_DONE; } -static int SetBpfString(int optind, char *argv[]) +static int SetBpfString(int argc, char *argv[]) { char *bpf_filter = NULL; uint32_t bpf_len = 0; int tmpindex = 0; /* attempt to parse remaining args as bpf filter */ - tmpindex = optind; + tmpindex = argc; while(argv[tmpindex] != NULL) { bpf_len+=strlen(argv[tmpindex]) + 1; tmpindex++; @@ -1029,21 +1029,21 @@ static void SCPrintElapsedTime(SCInstance *suri) SCLogInfo("time elapsed %.3fs", (float)milliseconds/(float)1000); } -static int ParseCommandLineAfpacket(SCInstance *suri, const char *optarg) +static int ParseCommandLineAfpacket(SCInstance *suri, const char *in_arg) { #ifdef HAVE_AF_PACKET if (suri->run_mode == RUNMODE_UNKNOWN) { suri->run_mode = RUNMODE_AFP_DEV; - if (optarg) { - LiveRegisterDevice(optarg); + if (in_arg) { + LiveRegisterDevice(in_arg); memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - strlcpy(suri->pcap_dev, optarg, sizeof(suri->pcap_dev)); + strlcpy(suri->pcap_dev, in_arg, sizeof(suri->pcap_dev)); } } else if (suri->run_mode == RUNMODE_AFP_DEV) { SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " "multiple devices to get packets is experimental."); - if (optarg) { - LiveRegisterDevice(optarg); + if (in_arg) { + LiveRegisterDevice(in_arg); } else { SCLogInfo("Multiple af-packet option without interface on each is useless"); } @@ -1062,31 +1062,31 @@ static int ParseCommandLineAfpacket(SCInstance *suri, const char *optarg) #endif } -static int ParseCommandLinePcapLive(SCInstance *suri, const char *optarg) +static int ParseCommandLinePcapLive(SCInstance *suri, const char *in_arg) { memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - if (optarg != NULL) { + if (in_arg != NULL) { /* some windows shells require escaping of the \ in \Device. Otherwise * the backslashes are stripped. We put them back here. */ - if (strlen(optarg) > 9 && strncmp(optarg, "DeviceNPF", 9) == 0) { - snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", optarg+9); + if (strlen(in_arg) > 9 && strncmp(in_arg, "DeviceNPF", 9) == 0) { + snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", in_arg+9); } else { - strlcpy(suri->pcap_dev, optarg, sizeof(suri->pcap_dev)); + strlcpy(suri->pcap_dev, in_arg, sizeof(suri->pcap_dev)); PcapTranslateIPToDevice(suri->pcap_dev, sizeof(suri->pcap_dev)); } - if (strcmp(suri->pcap_dev, optarg) != 0) { - SCLogInfo("translated %s to pcap device %s", optarg, suri->pcap_dev); + if (strcmp(suri->pcap_dev, in_arg) != 0) { + SCLogInfo("translated %s to pcap device %s", in_arg, suri->pcap_dev); } else if (strlen(suri->pcap_dev) > 0 && isdigit((unsigned char)suri->pcap_dev[0])) { - SCLogError(SC_ERR_PCAP_TRANSLATE, "failed to find a pcap device for IP %s", optarg); + SCLogError(SC_ERR_PCAP_TRANSLATE, "failed to find a pcap device for IP %s", in_arg); return TM_ECODE_FAILED; } } if (suri->run_mode == RUNMODE_UNKNOWN) { suri->run_mode = RUNMODE_PCAP_DEV; - if (optarg) { + if (in_arg) { LiveRegisterDevice(suri->pcap_dev); } } else if (suri->run_mode == RUNMODE_PCAP_DEV) { From 07e1e3e02a46a1173171b9fee0c3fe68e016f270 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 12:54:16 +0100 Subject: [PATCH 2211/2553] dcerpc: fix -Wshadow warnings --- src/app-layer-dcerpc.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index da547716160f..5ba04d974930 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -5056,7 +5056,7 @@ int DCERPCParserTest13(void) Flow f; int r = 0; - uint8_t bind[] = { + uint8_t bindbuf[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, @@ -5067,7 +5067,7 @@ int DCERPCParserTest13(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; - uint32_t bind_len = sizeof(bind); + uint32_t bindbuf_len = sizeof(bindbuf); TcpSession ssn; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5083,7 +5083,7 @@ int DCERPCParserTest13(void) FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, bind, bind_len); + STREAM_TOSERVER, bindbuf, bindbuf_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5141,7 +5141,7 @@ int DCERPCParserTest14(void) Flow f; int r = 0; - uint8_t bind[] = { + uint8_t bindbuf[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, @@ -5158,7 +5158,7 @@ int DCERPCParserTest14(void) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0xFF /* ka boom - endless loop */ }; - uint32_t bind_len = sizeof(bind); + uint32_t bindbuf_len = sizeof(bindbuf); TcpSession ssn; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5174,7 +5174,7 @@ int DCERPCParserTest14(void) FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, bind, bind_len); + STREAM_TOSERVER, bindbuf, bindbuf_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; @@ -5868,7 +5868,7 @@ int DCERPCParserTest17(void) Flow f; int r = 0; - uint8_t bind[] = { + uint8_t bindbuf[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, @@ -5879,7 +5879,7 @@ int DCERPCParserTest17(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; - uint32_t bind_len = sizeof(bind); + uint32_t bindbuf_len = sizeof(bindbuf); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, @@ -5944,7 +5944,7 @@ int DCERPCParserTest17(void) FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, bind, bind_len); + STREAM_TOSERVER, bindbuf, bindbuf_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; From b4ac048b41a60c2a705125d83b397ac4a269b6d0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 13:03:34 +0100 Subject: [PATCH 2212/2553] proto detect: fix -Wshadow warning --- src/app-layer-detect-proto.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 9d93e9d73da2..623a71b969aa 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1079,7 +1079,6 @@ static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx) PatIntId max_id = 0; TempContainer *struct_offset = NULL; uint8_t *content_offset = NULL; - TempContainer *dup = NULL; int ret = 0; if (ctx->head == NULL) @@ -1098,21 +1097,21 @@ static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx) struct_offset = (TempContainer *)ahb; content_offset = ahb + struct_total_size; for (s = ctx->head; s != NULL; s = s->next) { - dup = (TempContainer *)ahb; + TempContainer *tcdup = (TempContainer *)ahb; content = s->cd->content; content_len = s->cd->content_len; - for (; dup != struct_offset; dup++) { - if (dup->content_len != content_len || - SCMemcmp(dup->content, content, dup->content_len) != 0) + for (; tcdup != struct_offset; tcdup++) { + if (tcdup->content_len != content_len || + SCMemcmp(tcdup->content, content, tcdup->content_len) != 0) { continue; } break; } - if (dup != struct_offset) { - s->cd->id = dup->id; + if (tcdup != struct_offset) { + s->cd->id = tcdup->id; continue; } From 4d8e9ae6656e4d420ba4fcf1a8d9b5d581bd277d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 14:40:20 +0100 Subject: [PATCH 2213/2553] qa: add -Wshadow to appveyor builds --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index 6ff4c260d324..58915eddb2f5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,6 +15,7 @@ environment: CYG_CACHE: C:\cygwin\var\cache\setup CYG_BASH: C:\cygwin\bin\bash CC: gcc + CFLAGS: -Wall -Wextra -Werror -Wshadow -Wno-unused-parameter -Wno-unused-function # Cache Cygwin files to speed up build cache: From 2a0bb108d02755aec142c9523b99f87f956eea7a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 28 Nov 2016 10:06:14 -0600 Subject: [PATCH 2214/2553] dnp3-gen: rename index variable to point_index Gcc 4.6 will warning with -Wshadow for a local variable named "index" as has a function named "index". Newer versions of gcc handle this case. --- scripts/dnp3-gen/dnp3-gen.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/dnp3-gen/dnp3-gen.py b/scripts/dnp3-gen/dnp3-gen.py index 29d7ae2e5983..67cee0e2bcaa 100755 --- a/scripts/dnp3-gen/dnp3-gen.py +++ b/scripts/dnp3-gen/dnp3-gen.py @@ -363,7 +363,7 @@ def gen_object_decoders(context): DNP3ObjectG{{object.group}}V{{object.variation}} *object = NULL; int bytes = (count / 8) + 1; uint32_t prefix = 0; - int index = start; + int point_index = start; if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { goto error; @@ -392,13 +392,13 @@ def gen_object_decoders(context): #error "Unhandled field width: {{object.fields[0].width}}" {% endif %} - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; count--; - index++; + point_index++; } } @@ -418,7 +418,7 @@ def gen_object_decoders(context): { DNP3ObjectG{{object.group}}V{{object.variation}} *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; {% if object._track_offset %} uint32_t offset; {% endif %} @@ -558,12 +558,12 @@ def gen_object_decoders(context): {% endif %} {% endfor %} - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; From 53a8c75385100cf14b1c0dc6d7d6084b78e0ef49 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 28 Nov 2016 10:07:41 -0600 Subject: [PATCH 2215/2553] dnp3: rename "index" variables to "point_index" Gcc 4.6 will warning with -Wshadow for a local variable named "index" as has a function named "index". Newer versions of gcc handle this case. --- src/app-layer-dnp3-objects.c | 910 +++++++++++++++++------------------ 1 file changed, 455 insertions(+), 455 deletions(-) diff --git a/src/app-layer-dnp3-objects.c b/src/app-layer-dnp3-objects.c index 48d39b42b01a..6c1a1d296cf7 100644 --- a/src/app-layer-dnp3-objects.c +++ b/src/app-layer-dnp3-objects.c @@ -353,7 +353,7 @@ static int DNP3ReadPrefix( * * \retval 1 if successfull, 0 on failure. */ -static int DNP3AddPoint(DNP3PointList *list, void *object, uint32_t index, +static int DNP3AddPoint(DNP3PointList *list, void *object, uint32_t point_index, uint8_t prefix_code, uint32_t prefix) { DNP3Point *point = SCCalloc(1, sizeof(*point)); @@ -363,7 +363,7 @@ static int DNP3AddPoint(DNP3PointList *list, void *object, uint32_t index, TAILQ_INSERT_TAIL(list, point, next); point->data = object; point->prefix = prefix; - point->index = index; + point->index = point_index; switch (prefix_code) { case 0x00: break; @@ -397,7 +397,7 @@ static int DNP3DecodeObjectG1V1(const uint8_t **buf, uint32_t *len, DNP3ObjectG1V1 *object = NULL; int bytes = (count / 8) + 1; uint32_t prefix = 0; - int index = start; + int point_index = start; if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { goto error; @@ -420,13 +420,13 @@ static int DNP3DecodeObjectG1V1(const uint8_t **buf, uint32_t *len, object->state = (octet >> j) & 0x1; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; count--; - index++; + point_index++; } } @@ -445,7 +445,7 @@ static int DNP3DecodeObjectG1V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG1V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -473,12 +473,12 @@ static int DNP3DecodeObjectG1V2(const uint8_t **buf, uint32_t *len, object->state = (octet >> 7) & 0x1; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -496,7 +496,7 @@ static int DNP3DecodeObjectG2V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG2V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -513,12 +513,12 @@ static int DNP3DecodeObjectG2V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -536,7 +536,7 @@ static int DNP3DecodeObjectG2V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG2V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -567,12 +567,12 @@ static int DNP3DecodeObjectG2V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -590,7 +590,7 @@ static int DNP3DecodeObjectG2V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG2V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -621,12 +621,12 @@ static int DNP3DecodeObjectG2V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -645,7 +645,7 @@ static int DNP3DecodeObjectG3V1(const uint8_t **buf, uint32_t *len, DNP3ObjectG3V1 *object = NULL; int bytes = (count / 8) + 1; uint32_t prefix = 0; - int index = start; + int point_index = start; if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { goto error; @@ -668,13 +668,13 @@ static int DNP3DecodeObjectG3V1(const uint8_t **buf, uint32_t *len, object->state = (octet >> j) & 0x3; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; count--; - index++; + point_index++; } } @@ -693,7 +693,7 @@ static int DNP3DecodeObjectG3V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG3V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -720,12 +720,12 @@ static int DNP3DecodeObjectG3V2(const uint8_t **buf, uint32_t *len, object->state = (octet >> 6) & 0x3; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -743,7 +743,7 @@ static int DNP3DecodeObjectG4V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG4V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -770,12 +770,12 @@ static int DNP3DecodeObjectG4V1(const uint8_t **buf, uint32_t *len, object->state = (octet >> 6) & 0x3; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -793,7 +793,7 @@ static int DNP3DecodeObjectG4V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG4V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -823,12 +823,12 @@ static int DNP3DecodeObjectG4V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -846,7 +846,7 @@ static int DNP3DecodeObjectG4V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG4V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -876,12 +876,12 @@ static int DNP3DecodeObjectG4V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -900,7 +900,7 @@ static int DNP3DecodeObjectG10V1(const uint8_t **buf, uint32_t *len, DNP3ObjectG10V1 *object = NULL; int bytes = (count / 8) + 1; uint32_t prefix = 0; - int index = start; + int point_index = start; if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { goto error; @@ -923,13 +923,13 @@ static int DNP3DecodeObjectG10V1(const uint8_t **buf, uint32_t *len, object->state = (octet >> j) & 0x1; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; count--; - index++; + point_index++; } } @@ -948,7 +948,7 @@ static int DNP3DecodeObjectG10V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG10V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -976,12 +976,12 @@ static int DNP3DecodeObjectG10V2(const uint8_t **buf, uint32_t *len, object->state = (octet >> 7) & 0x1; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -999,7 +999,7 @@ static int DNP3DecodeObjectG11V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG11V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1027,12 +1027,12 @@ static int DNP3DecodeObjectG11V1(const uint8_t **buf, uint32_t *len, object->state = (octet >> 7) & 0x1; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1050,7 +1050,7 @@ static int DNP3DecodeObjectG11V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG11V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1081,12 +1081,12 @@ static int DNP3DecodeObjectG11V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1104,7 +1104,7 @@ static int DNP3DecodeObjectG12V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG12V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1145,12 +1145,12 @@ static int DNP3DecodeObjectG12V1(const uint8_t **buf, uint32_t *len, object->reserved = (octet >> 7) & 0x1; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1168,7 +1168,7 @@ static int DNP3DecodeObjectG12V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG12V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1209,12 +1209,12 @@ static int DNP3DecodeObjectG12V2(const uint8_t **buf, uint32_t *len, object->reserved = (octet >> 7) & 0x1; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1233,7 +1233,7 @@ static int DNP3DecodeObjectG12V3(const uint8_t **buf, uint32_t *len, DNP3ObjectG12V3 *object = NULL; int bytes = (count / 8) + 1; uint32_t prefix = 0; - int index = start; + int point_index = start; if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { goto error; @@ -1256,13 +1256,13 @@ static int DNP3DecodeObjectG12V3(const uint8_t **buf, uint32_t *len, object->point = (octet >> j) & 0x1; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; count--; - index++; + point_index++; } } @@ -1281,7 +1281,7 @@ static int DNP3DecodeObjectG13V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG13V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1303,12 +1303,12 @@ static int DNP3DecodeObjectG13V1(const uint8_t **buf, uint32_t *len, object->commanded_state = (octet >> 7) & 0x1; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1326,7 +1326,7 @@ static int DNP3DecodeObjectG13V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG13V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1351,12 +1351,12 @@ static int DNP3DecodeObjectG13V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1374,7 +1374,7 @@ static int DNP3DecodeObjectG20V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG20V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1405,12 +1405,12 @@ static int DNP3DecodeObjectG20V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1428,7 +1428,7 @@ static int DNP3DecodeObjectG20V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG20V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1459,12 +1459,12 @@ static int DNP3DecodeObjectG20V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1482,7 +1482,7 @@ static int DNP3DecodeObjectG20V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG20V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1513,12 +1513,12 @@ static int DNP3DecodeObjectG20V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1536,7 +1536,7 @@ static int DNP3DecodeObjectG20V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG20V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1567,12 +1567,12 @@ static int DNP3DecodeObjectG20V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1590,7 +1590,7 @@ static int DNP3DecodeObjectG20V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG20V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1607,12 +1607,12 @@ static int DNP3DecodeObjectG20V5(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1630,7 +1630,7 @@ static int DNP3DecodeObjectG20V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG20V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1647,12 +1647,12 @@ static int DNP3DecodeObjectG20V6(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1670,7 +1670,7 @@ static int DNP3DecodeObjectG20V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG20V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1687,12 +1687,12 @@ static int DNP3DecodeObjectG20V7(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1710,7 +1710,7 @@ static int DNP3DecodeObjectG20V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG20V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1727,12 +1727,12 @@ static int DNP3DecodeObjectG20V8(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1750,7 +1750,7 @@ static int DNP3DecodeObjectG21V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1781,12 +1781,12 @@ static int DNP3DecodeObjectG21V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1804,7 +1804,7 @@ static int DNP3DecodeObjectG21V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1835,12 +1835,12 @@ static int DNP3DecodeObjectG21V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1858,7 +1858,7 @@ static int DNP3DecodeObjectG21V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1889,12 +1889,12 @@ static int DNP3DecodeObjectG21V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1912,7 +1912,7 @@ static int DNP3DecodeObjectG21V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -1943,12 +1943,12 @@ static int DNP3DecodeObjectG21V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -1966,7 +1966,7 @@ static int DNP3DecodeObjectG21V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2000,12 +2000,12 @@ static int DNP3DecodeObjectG21V5(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2023,7 +2023,7 @@ static int DNP3DecodeObjectG21V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2057,12 +2057,12 @@ static int DNP3DecodeObjectG21V6(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2080,7 +2080,7 @@ static int DNP3DecodeObjectG21V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2114,12 +2114,12 @@ static int DNP3DecodeObjectG21V7(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2137,7 +2137,7 @@ static int DNP3DecodeObjectG21V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2171,12 +2171,12 @@ static int DNP3DecodeObjectG21V8(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2194,7 +2194,7 @@ static int DNP3DecodeObjectG21V9(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V9 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2211,12 +2211,12 @@ static int DNP3DecodeObjectG21V9(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2234,7 +2234,7 @@ static int DNP3DecodeObjectG21V10(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V10 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2251,12 +2251,12 @@ static int DNP3DecodeObjectG21V10(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2274,7 +2274,7 @@ static int DNP3DecodeObjectG21V11(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V11 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2291,12 +2291,12 @@ static int DNP3DecodeObjectG21V11(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2314,7 +2314,7 @@ static int DNP3DecodeObjectG21V12(const uint8_t **buf, uint32_t *len, { DNP3ObjectG21V12 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2331,12 +2331,12 @@ static int DNP3DecodeObjectG21V12(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2354,7 +2354,7 @@ static int DNP3DecodeObjectG22V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG22V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2385,12 +2385,12 @@ static int DNP3DecodeObjectG22V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2408,7 +2408,7 @@ static int DNP3DecodeObjectG22V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG22V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2439,12 +2439,12 @@ static int DNP3DecodeObjectG22V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2462,7 +2462,7 @@ static int DNP3DecodeObjectG22V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG22V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2493,12 +2493,12 @@ static int DNP3DecodeObjectG22V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2516,7 +2516,7 @@ static int DNP3DecodeObjectG22V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG22V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2547,12 +2547,12 @@ static int DNP3DecodeObjectG22V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2570,7 +2570,7 @@ static int DNP3DecodeObjectG22V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG22V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2604,12 +2604,12 @@ static int DNP3DecodeObjectG22V5(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2627,7 +2627,7 @@ static int DNP3DecodeObjectG22V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG22V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2661,12 +2661,12 @@ static int DNP3DecodeObjectG22V6(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2684,7 +2684,7 @@ static int DNP3DecodeObjectG22V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG22V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2718,12 +2718,12 @@ static int DNP3DecodeObjectG22V7(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2741,7 +2741,7 @@ static int DNP3DecodeObjectG22V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG22V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2775,12 +2775,12 @@ static int DNP3DecodeObjectG22V8(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2798,7 +2798,7 @@ static int DNP3DecodeObjectG23V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG23V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2829,12 +2829,12 @@ static int DNP3DecodeObjectG23V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2852,7 +2852,7 @@ static int DNP3DecodeObjectG23V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG23V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2883,12 +2883,12 @@ static int DNP3DecodeObjectG23V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2906,7 +2906,7 @@ static int DNP3DecodeObjectG23V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG23V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2937,12 +2937,12 @@ static int DNP3DecodeObjectG23V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -2960,7 +2960,7 @@ static int DNP3DecodeObjectG23V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG23V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -2991,12 +2991,12 @@ static int DNP3DecodeObjectG23V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3014,7 +3014,7 @@ static int DNP3DecodeObjectG23V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG23V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3048,12 +3048,12 @@ static int DNP3DecodeObjectG23V5(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3071,7 +3071,7 @@ static int DNP3DecodeObjectG23V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG23V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3105,12 +3105,12 @@ static int DNP3DecodeObjectG23V6(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3128,7 +3128,7 @@ static int DNP3DecodeObjectG23V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG23V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3162,12 +3162,12 @@ static int DNP3DecodeObjectG23V7(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3185,7 +3185,7 @@ static int DNP3DecodeObjectG23V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG23V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3219,12 +3219,12 @@ static int DNP3DecodeObjectG23V8(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3242,7 +3242,7 @@ static int DNP3DecodeObjectG30V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG30V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3273,12 +3273,12 @@ static int DNP3DecodeObjectG30V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3296,7 +3296,7 @@ static int DNP3DecodeObjectG30V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG30V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3327,12 +3327,12 @@ static int DNP3DecodeObjectG30V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3350,7 +3350,7 @@ static int DNP3DecodeObjectG30V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG30V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3367,12 +3367,12 @@ static int DNP3DecodeObjectG30V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3390,7 +3390,7 @@ static int DNP3DecodeObjectG30V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG30V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3407,12 +3407,12 @@ static int DNP3DecodeObjectG30V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3430,7 +3430,7 @@ static int DNP3DecodeObjectG30V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG30V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3461,12 +3461,12 @@ static int DNP3DecodeObjectG30V5(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3484,7 +3484,7 @@ static int DNP3DecodeObjectG30V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG30V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3515,12 +3515,12 @@ static int DNP3DecodeObjectG30V6(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3538,7 +3538,7 @@ static int DNP3DecodeObjectG31V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG31V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3569,12 +3569,12 @@ static int DNP3DecodeObjectG31V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3592,7 +3592,7 @@ static int DNP3DecodeObjectG31V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG31V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3623,12 +3623,12 @@ static int DNP3DecodeObjectG31V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3646,7 +3646,7 @@ static int DNP3DecodeObjectG31V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG31V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3680,12 +3680,12 @@ static int DNP3DecodeObjectG31V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3703,7 +3703,7 @@ static int DNP3DecodeObjectG31V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG31V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3737,12 +3737,12 @@ static int DNP3DecodeObjectG31V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3760,7 +3760,7 @@ static int DNP3DecodeObjectG31V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG31V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3777,12 +3777,12 @@ static int DNP3DecodeObjectG31V5(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3800,7 +3800,7 @@ static int DNP3DecodeObjectG31V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG31V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3817,12 +3817,12 @@ static int DNP3DecodeObjectG31V6(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3840,7 +3840,7 @@ static int DNP3DecodeObjectG31V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG31V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3871,12 +3871,12 @@ static int DNP3DecodeObjectG31V7(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3894,7 +3894,7 @@ static int DNP3DecodeObjectG31V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG31V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3925,12 +3925,12 @@ static int DNP3DecodeObjectG31V8(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -3948,7 +3948,7 @@ static int DNP3DecodeObjectG32V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG32V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -3979,12 +3979,12 @@ static int DNP3DecodeObjectG32V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4002,7 +4002,7 @@ static int DNP3DecodeObjectG32V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG32V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4033,12 +4033,12 @@ static int DNP3DecodeObjectG32V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4056,7 +4056,7 @@ static int DNP3DecodeObjectG32V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG32V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4090,12 +4090,12 @@ static int DNP3DecodeObjectG32V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4113,7 +4113,7 @@ static int DNP3DecodeObjectG32V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG32V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4147,12 +4147,12 @@ static int DNP3DecodeObjectG32V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4170,7 +4170,7 @@ static int DNP3DecodeObjectG32V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG32V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4201,12 +4201,12 @@ static int DNP3DecodeObjectG32V5(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4224,7 +4224,7 @@ static int DNP3DecodeObjectG32V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG32V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4255,12 +4255,12 @@ static int DNP3DecodeObjectG32V6(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4278,7 +4278,7 @@ static int DNP3DecodeObjectG32V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG32V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4312,12 +4312,12 @@ static int DNP3DecodeObjectG32V7(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4335,7 +4335,7 @@ static int DNP3DecodeObjectG32V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG32V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4369,12 +4369,12 @@ static int DNP3DecodeObjectG32V8(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4392,7 +4392,7 @@ static int DNP3DecodeObjectG33V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG33V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4423,12 +4423,12 @@ static int DNP3DecodeObjectG33V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4446,7 +4446,7 @@ static int DNP3DecodeObjectG33V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG33V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4477,12 +4477,12 @@ static int DNP3DecodeObjectG33V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4500,7 +4500,7 @@ static int DNP3DecodeObjectG33V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG33V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4534,12 +4534,12 @@ static int DNP3DecodeObjectG33V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4557,7 +4557,7 @@ static int DNP3DecodeObjectG33V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG33V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4591,12 +4591,12 @@ static int DNP3DecodeObjectG33V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4614,7 +4614,7 @@ static int DNP3DecodeObjectG33V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG33V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4645,12 +4645,12 @@ static int DNP3DecodeObjectG33V5(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4668,7 +4668,7 @@ static int DNP3DecodeObjectG33V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG33V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4699,12 +4699,12 @@ static int DNP3DecodeObjectG33V6(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4722,7 +4722,7 @@ static int DNP3DecodeObjectG33V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG33V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4756,12 +4756,12 @@ static int DNP3DecodeObjectG33V7(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4779,7 +4779,7 @@ static int DNP3DecodeObjectG33V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG33V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4813,12 +4813,12 @@ static int DNP3DecodeObjectG33V8(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4836,7 +4836,7 @@ static int DNP3DecodeObjectG34V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG34V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4853,12 +4853,12 @@ static int DNP3DecodeObjectG34V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4876,7 +4876,7 @@ static int DNP3DecodeObjectG34V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG34V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4893,12 +4893,12 @@ static int DNP3DecodeObjectG34V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4916,7 +4916,7 @@ static int DNP3DecodeObjectG34V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG34V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4933,12 +4933,12 @@ static int DNP3DecodeObjectG34V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -4956,7 +4956,7 @@ static int DNP3DecodeObjectG40V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG40V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -4987,12 +4987,12 @@ static int DNP3DecodeObjectG40V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5010,7 +5010,7 @@ static int DNP3DecodeObjectG40V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG40V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5041,12 +5041,12 @@ static int DNP3DecodeObjectG40V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5064,7 +5064,7 @@ static int DNP3DecodeObjectG40V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG40V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5095,12 +5095,12 @@ static int DNP3DecodeObjectG40V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5118,7 +5118,7 @@ static int DNP3DecodeObjectG40V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG40V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5149,12 +5149,12 @@ static int DNP3DecodeObjectG40V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5172,7 +5172,7 @@ static int DNP3DecodeObjectG41V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG41V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5192,12 +5192,12 @@ static int DNP3DecodeObjectG41V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5215,7 +5215,7 @@ static int DNP3DecodeObjectG41V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG41V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5235,12 +5235,12 @@ static int DNP3DecodeObjectG41V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5258,7 +5258,7 @@ static int DNP3DecodeObjectG41V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG41V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5278,12 +5278,12 @@ static int DNP3DecodeObjectG41V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5301,7 +5301,7 @@ static int DNP3DecodeObjectG41V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG41V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5321,12 +5321,12 @@ static int DNP3DecodeObjectG41V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5344,7 +5344,7 @@ static int DNP3DecodeObjectG42V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG42V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5375,12 +5375,12 @@ static int DNP3DecodeObjectG42V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5398,7 +5398,7 @@ static int DNP3DecodeObjectG42V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG42V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5429,12 +5429,12 @@ static int DNP3DecodeObjectG42V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5452,7 +5452,7 @@ static int DNP3DecodeObjectG42V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG42V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5486,12 +5486,12 @@ static int DNP3DecodeObjectG42V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5509,7 +5509,7 @@ static int DNP3DecodeObjectG42V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG42V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5543,12 +5543,12 @@ static int DNP3DecodeObjectG42V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5566,7 +5566,7 @@ static int DNP3DecodeObjectG42V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG42V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5597,12 +5597,12 @@ static int DNP3DecodeObjectG42V5(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5620,7 +5620,7 @@ static int DNP3DecodeObjectG42V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG42V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5651,12 +5651,12 @@ static int DNP3DecodeObjectG42V6(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5674,7 +5674,7 @@ static int DNP3DecodeObjectG42V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG42V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5708,12 +5708,12 @@ static int DNP3DecodeObjectG42V7(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5731,7 +5731,7 @@ static int DNP3DecodeObjectG42V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG42V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5765,12 +5765,12 @@ static int DNP3DecodeObjectG42V8(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5788,7 +5788,7 @@ static int DNP3DecodeObjectG43V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG43V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5813,12 +5813,12 @@ static int DNP3DecodeObjectG43V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5836,7 +5836,7 @@ static int DNP3DecodeObjectG43V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG43V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5861,12 +5861,12 @@ static int DNP3DecodeObjectG43V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5884,7 +5884,7 @@ static int DNP3DecodeObjectG43V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG43V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5912,12 +5912,12 @@ static int DNP3DecodeObjectG43V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5935,7 +5935,7 @@ static int DNP3DecodeObjectG43V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG43V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -5963,12 +5963,12 @@ static int DNP3DecodeObjectG43V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -5986,7 +5986,7 @@ static int DNP3DecodeObjectG43V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG43V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6011,12 +6011,12 @@ static int DNP3DecodeObjectG43V5(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6034,7 +6034,7 @@ static int DNP3DecodeObjectG43V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG43V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6059,12 +6059,12 @@ static int DNP3DecodeObjectG43V6(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6082,7 +6082,7 @@ static int DNP3DecodeObjectG43V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG43V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6110,12 +6110,12 @@ static int DNP3DecodeObjectG43V7(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6133,7 +6133,7 @@ static int DNP3DecodeObjectG43V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG43V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6161,12 +6161,12 @@ static int DNP3DecodeObjectG43V8(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6184,7 +6184,7 @@ static int DNP3DecodeObjectG50V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG50V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6201,12 +6201,12 @@ static int DNP3DecodeObjectG50V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6224,7 +6224,7 @@ static int DNP3DecodeObjectG50V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG50V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6244,12 +6244,12 @@ static int DNP3DecodeObjectG50V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6267,7 +6267,7 @@ static int DNP3DecodeObjectG50V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG50V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6284,12 +6284,12 @@ static int DNP3DecodeObjectG50V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6307,7 +6307,7 @@ static int DNP3DecodeObjectG50V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG50V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6330,12 +6330,12 @@ static int DNP3DecodeObjectG50V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6353,7 +6353,7 @@ static int DNP3DecodeObjectG51V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG51V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6370,12 +6370,12 @@ static int DNP3DecodeObjectG51V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6393,7 +6393,7 @@ static int DNP3DecodeObjectG51V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG51V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6410,12 +6410,12 @@ static int DNP3DecodeObjectG51V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6433,7 +6433,7 @@ static int DNP3DecodeObjectG52V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG52V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6450,12 +6450,12 @@ static int DNP3DecodeObjectG52V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6473,7 +6473,7 @@ static int DNP3DecodeObjectG52V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG52V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6490,12 +6490,12 @@ static int DNP3DecodeObjectG52V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6513,7 +6513,7 @@ static int DNP3DecodeObjectG70V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG70V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6581,12 +6581,12 @@ static int DNP3DecodeObjectG70V1(const uint8_t **buf, uint32_t *len, } object->data[object->data_size] = '\0'; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6604,7 +6604,7 @@ static int DNP3DecodeObjectG70V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG70V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6645,12 +6645,12 @@ static int DNP3DecodeObjectG70V2(const uint8_t **buf, uint32_t *len, } object->password[object->password_size] = '\0'; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6668,7 +6668,7 @@ static int DNP3DecodeObjectG70V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG70V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6715,12 +6715,12 @@ static int DNP3DecodeObjectG70V3(const uint8_t **buf, uint32_t *len, } object->filename[object->filename_size] = '\0'; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6738,7 +6738,7 @@ static int DNP3DecodeObjectG70V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG70V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (!DNP3PrefixIsSize(prefix_code)) { @@ -6781,12 +6781,12 @@ static int DNP3DecodeObjectG70V4(const uint8_t **buf, uint32_t *len, } object->optional_text[object->optional_text_len] = '\0'; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6804,7 +6804,7 @@ static int DNP3DecodeObjectG70V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG70V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (!DNP3PrefixIsSize(prefix_code)) { @@ -6838,12 +6838,12 @@ static int DNP3DecodeObjectG70V5(const uint8_t **buf, uint32_t *len, } object->file_data[object->file_data_len] = '\0'; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6861,7 +6861,7 @@ static int DNP3DecodeObjectG70V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG70V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (!DNP3PrefixIsSize(prefix_code)) { @@ -6898,12 +6898,12 @@ static int DNP3DecodeObjectG70V6(const uint8_t **buf, uint32_t *len, } object->optional_text[object->optional_text_len] = '\0'; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6921,7 +6921,7 @@ static int DNP3DecodeObjectG70V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG70V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -6962,12 +6962,12 @@ static int DNP3DecodeObjectG70V7(const uint8_t **buf, uint32_t *len, } object->filename[object->filename_size] = '\0'; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -6985,7 +6985,7 @@ static int DNP3DecodeObjectG70V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG70V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (prefix_code != 5) { @@ -7013,12 +7013,12 @@ static int DNP3DecodeObjectG70V8(const uint8_t **buf, uint32_t *len, } object->file_specification[object->file_specification_len] = '\0'; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7037,7 +7037,7 @@ static int DNP3DecodeObjectG80V1(const uint8_t **buf, uint32_t *len, DNP3ObjectG80V1 *object = NULL; int bytes = (count / 8) + 1; uint32_t prefix = 0; - int index = start; + int point_index = start; if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { goto error; @@ -7060,13 +7060,13 @@ static int DNP3DecodeObjectG80V1(const uint8_t **buf, uint32_t *len, object->state = (octet >> j) & 0x1; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; count--; - index++; + point_index++; } } @@ -7085,7 +7085,7 @@ static int DNP3DecodeObjectG81V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG81V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -7113,12 +7113,12 @@ static int DNP3DecodeObjectG81V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7136,7 +7136,7 @@ static int DNP3DecodeObjectG83V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG83V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -7176,12 +7176,12 @@ static int DNP3DecodeObjectG83V1(const uint8_t **buf, uint32_t *len, *len -= object->length; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7199,7 +7199,7 @@ static int DNP3DecodeObjectG86V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG86V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -7227,12 +7227,12 @@ static int DNP3DecodeObjectG86V2(const uint8_t **buf, uint32_t *len, object->padding2 = (octet >> 7) & 0x1; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7250,7 +7250,7 @@ static int DNP3DecodeObjectG102V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG102V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -7267,12 +7267,12 @@ static int DNP3DecodeObjectG102V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7290,7 +7290,7 @@ static int DNP3DecodeObjectG120V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (prefix_code != 5) { @@ -7337,12 +7337,12 @@ static int DNP3DecodeObjectG120V1(const uint8_t **buf, uint32_t *len, *len -= object->challenge_data_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7360,7 +7360,7 @@ static int DNP3DecodeObjectG120V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (prefix_code != 5) { @@ -7401,12 +7401,12 @@ static int DNP3DecodeObjectG120V2(const uint8_t **buf, uint32_t *len, *len -= object->mac_value_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7424,7 +7424,7 @@ static int DNP3DecodeObjectG120V3(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V3 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -7444,12 +7444,12 @@ static int DNP3DecodeObjectG120V3(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7467,7 +7467,7 @@ static int DNP3DecodeObjectG120V4(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V4 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -7484,12 +7484,12 @@ static int DNP3DecodeObjectG120V4(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7507,7 +7507,7 @@ static int DNP3DecodeObjectG120V5(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V5 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (prefix_code != 5) { @@ -7573,12 +7573,12 @@ static int DNP3DecodeObjectG120V5(const uint8_t **buf, uint32_t *len, *len -= object->mac_value_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7596,7 +7596,7 @@ static int DNP3DecodeObjectG120V6(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V6 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (prefix_code != 5) { @@ -7637,12 +7637,12 @@ static int DNP3DecodeObjectG120V6(const uint8_t **buf, uint32_t *len, *len -= object->wrapped_key_data_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7660,7 +7660,7 @@ static int DNP3DecodeObjectG120V7(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V7 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (prefix_code != 5) { @@ -7703,12 +7703,12 @@ static int DNP3DecodeObjectG120V7(const uint8_t **buf, uint32_t *len, } object->error_text[object->error_text_len] = '\0'; - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7726,7 +7726,7 @@ static int DNP3DecodeObjectG120V8(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V8 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (prefix_code != 5) { @@ -7767,12 +7767,12 @@ static int DNP3DecodeObjectG120V8(const uint8_t **buf, uint32_t *len, *len -= object->certificate_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7790,7 +7790,7 @@ static int DNP3DecodeObjectG120V9(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V9 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; while (count--) { @@ -7821,12 +7821,12 @@ static int DNP3DecodeObjectG120V9(const uint8_t **buf, uint32_t *len, *len -= object->mac_value_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7844,7 +7844,7 @@ static int DNP3DecodeObjectG120V10(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V10 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; if (prefix_code != 5) { goto error; @@ -7918,12 +7918,12 @@ static int DNP3DecodeObjectG120V10(const uint8_t **buf, uint32_t *len, *len -= object->certification_data_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -7941,7 +7941,7 @@ static int DNP3DecodeObjectG120V11(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V11 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; if (prefix_code != 5) { goto error; @@ -7987,12 +7987,12 @@ static int DNP3DecodeObjectG120V11(const uint8_t **buf, uint32_t *len, *len -= object->master_challenge_data_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -8010,7 +8010,7 @@ static int DNP3DecodeObjectG120V12(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V12 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; if (prefix_code != 5) { goto error; @@ -8050,12 +8050,12 @@ static int DNP3DecodeObjectG120V12(const uint8_t **buf, uint32_t *len, *len -= object->challenge_data_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -8073,7 +8073,7 @@ static int DNP3DecodeObjectG120V13(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V13 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; if (prefix_code != 5) { goto error; @@ -8113,12 +8113,12 @@ static int DNP3DecodeObjectG120V13(const uint8_t **buf, uint32_t *len, *len -= object->encrypted_update_key_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -8136,7 +8136,7 @@ static int DNP3DecodeObjectG120V14(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V14 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (prefix_code != 5) { @@ -8171,12 +8171,12 @@ static int DNP3DecodeObjectG120V14(const uint8_t **buf, uint32_t *len, *len -= object->digital_signature_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -8194,7 +8194,7 @@ static int DNP3DecodeObjectG120V15(const uint8_t **buf, uint32_t *len, { DNP3ObjectG120V15 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; uint32_t offset; if (prefix_code != 5) { @@ -8229,12 +8229,12 @@ static int DNP3DecodeObjectG120V15(const uint8_t **buf, uint32_t *len, *len -= object->mac_len; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -8252,7 +8252,7 @@ static int DNP3DecodeObjectG121V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG121V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -8286,12 +8286,12 @@ static int DNP3DecodeObjectG121V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -8309,7 +8309,7 @@ static int DNP3DecodeObjectG122V1(const uint8_t **buf, uint32_t *len, { DNP3ObjectG122V1 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -8343,12 +8343,12 @@ static int DNP3DecodeObjectG122V1(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; @@ -8366,7 +8366,7 @@ static int DNP3DecodeObjectG122V2(const uint8_t **buf, uint32_t *len, { DNP3ObjectG122V2 *object = NULL; uint32_t prefix = 0; - uint32_t index = start; + uint32_t point_index = start; while (count--) { @@ -8403,12 +8403,12 @@ static int DNP3DecodeObjectG122V2(const uint8_t **buf, uint32_t *len, goto error; } - if (!DNP3AddPoint(points, object, index, prefix_code, prefix)) { + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { goto error; } object = NULL; - index++; + point_index++; } return 1; From 5c80a3edf794929b48df75e9dde2ee3c187300bd Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 28 Nov 2016 12:18:23 -0600 Subject: [PATCH 2216/2553] modbus: fix format string compiler warnings --- src/app-layer-modbus.c | 103 ++++++++++++++++++++--------------------- src/detect-modbus.c | 30 ++++++------ 2 files changed, 66 insertions(+), 67 deletions(-) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index ec75e004718e..630aff5755a5 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1762,11 +1762,10 @@ static int ModbusParserTest01(void) { } ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); - if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 1, tx->function); - printf("expected address %" PRIu8 ", got %" PRIu8 ": ", 0x7890, tx->read.address); - printf("expected quantity %" PRIu8 ", got %" PRIu8 ": ", 19, tx->read.quantity); + printf("expected function %d, got %" PRIu8 ": ", 1, tx->function); + printf("expected address %d, got %" PRIu16 ": ", 0x7890, tx->read.address); + printf("expected quantity %d, got %" PRIu16 ": ", 19, tx->read.quantity); goto end; } @@ -1782,7 +1781,7 @@ static int ModbusParserTest01(void) { FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { - printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); goto end; } @@ -1833,12 +1832,12 @@ static int ModbusParserTest02(void) { if ((tx->function != 16) || (tx->write.address != 0x01) || (tx->write.quantity != 2) || (tx->write.count != 4) || (tx->data[0] != 0x000A) || (tx->data[1] != 0x0102)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); - printf("expected write address %" PRIu8 ", got %" PRIu8 ": ", 0x01, tx->write.address); - printf("expected write quantity %" PRIu8 ", got %" PRIu8 ": ", 2, tx->write.quantity); - printf("expected write count %" PRIu8 ", got %" PRIu8 ": ", 4, tx->write.count); - printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x000A, tx->data[0]); - printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x0102, tx->data[1]); + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address); + printf("expected write quantity %d, got %" PRIu16 ": ", 2, tx->write.quantity); + printf("expected write count %d, got %" PRIu8 ": ", 4, tx->write.count); + printf("expected data %d, got %" PRIu16 ": ", 0x000A, tx->data[0]); + printf("expected data %d, got %" PRIu16 ": ", 0x0102, tx->data[1]); goto end; } @@ -1854,7 +1853,7 @@ static int ModbusParserTest02(void) { FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { - printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); goto end; } @@ -1936,15 +1935,15 @@ static int ModbusParserTest03(void) { if ((tx->function != 23) || (tx->read.address != 0x03) || (tx->read.quantity != 6) || (tx->write.address != 0x0E) || (tx->write.quantity != 3) || (tx->write.count != 6) || (tx->data[0] != 0x1234) || (tx->data[1] != 0x5678) || (tx->data[2] != 0x9ABC)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 23, tx->function); - printf("expected read address %" PRIu8 ", got %" PRIu8 ": ", 0x03, tx->read.address); - printf("expected read quantity %" PRIu8 ", got %" PRIu8 ": ", 6, tx->read.quantity); - printf("expected write address %" PRIu8 ", got %" PRIu8 ": ", 0x0E, tx->write.address); - printf("expected write quantity %" PRIu8 ", got %" PRIu8 ": ", 3, tx->write.quantity); - printf("expected write count %" PRIu8 ", got %" PRIu8 ": ", 6, tx->write.count); - printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x1234, tx->data[0]); - printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x5678, tx->data[1]); - printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x9ABC, tx->data[2]); + printf("expected function %d, got %" PRIu8 ": ", 23, tx->function); + printf("expected read address %d, got %" PRIu16 ": ", 0x03, tx->read.address); + printf("expected read quantity %d, got %" PRIu16 ": ", 6, tx->read.quantity); + printf("expected write address %d, got %" PRIu16 ": ", 0x0E, tx->write.address); + printf("expected write quantity %d, got %" PRIu16 ": ", 3, tx->write.quantity); + printf("expected write count %d, got %" PRIu8 ": ", 6, tx->write.count); + printf("expected data %d, got %" PRIu16 ": ", 0x1234, tx->data[0]); + printf("expected data %d, got %" PRIu16 ": ", 0x5678, tx->data[1]); + printf("expected data %d, got %" PRIu16 ": ", 0x9ABC, tx->data[2]); goto end; } @@ -1960,7 +1959,7 @@ static int ModbusParserTest03(void) { FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { - printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); goto end; } @@ -2025,8 +2024,8 @@ static int ModbusParserTest04(void) { ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); if ((tx->function != 8) || (tx->subFunction != 4)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 8, tx->function); - printf("expected sub-function %" PRIu8 ", got %" PRIu8 ": ", 0x04, tx->subFunction); + printf("expected function %d, got %" PRIu8 ": ", 8, tx->function); + printf("expected sub-function %d, got %" PRIu16 ": ", 0x04, tx->subFunction); goto end; } @@ -2367,9 +2366,9 @@ static int ModbusParserTest08(void) { ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 1, tx->function); - printf("expected address %" PRIu8 ", got %" PRIu8 ": ", 0x7890, tx->read.address); - printf("expected quantity %" PRIu8 ", got %" PRIu8 ": ", 19, tx->read.quantity); + printf("expected function %d, got %" PRIu8 ": ", 1, tx->function); + printf("expected address %d, got %" PRIu16 ": ", 0x7890, tx->read.address); + printf("expected quantity %d, got %" PRIu16 ": ", 19, tx->read.quantity); goto end; } @@ -2385,7 +2384,7 @@ static int ModbusParserTest08(void) { FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { - printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); goto end; } @@ -2460,9 +2459,9 @@ static int ModbusParserTest09(void) { ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 1, tx->function); - printf("expected address %" PRIu8 ", got %" PRIu8 ": ", 0x7890, tx->read.address); - printf("expected quantity %" PRIu8 ", got %" PRIu8 ": ", 19, tx->read.quantity); + printf("expected function %d, got %" PRIu8 ": ", 1, tx->function); + printf("expected address %d, got %" PRIu16 ": ", 0x7890, tx->read.address); + printf("expected quantity %d, got %" PRIu16 ": ", 19, tx->read.quantity); goto end; } @@ -2489,7 +2488,7 @@ static int ModbusParserTest09(void) { FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { - printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); goto end; } @@ -2546,7 +2545,7 @@ static int ModbusParserTest10(void) { } if (modbus_state->transaction_max !=2) { - printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 2, modbus_state->transaction_max); + printf("expected transaction_max %d, got %" PRIu64 ": ", 2, modbus_state->transaction_max); goto end; } @@ -2554,12 +2553,12 @@ static int ModbusParserTest10(void) { if ((tx->function != 16) || (tx->write.address != 0x01) || (tx->write.quantity != 2) || (tx->write.count != 4) || (tx->data[0] != 0x000A) || (tx->data[1] != 0x0102)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); - printf("expected write address %" PRIu8 ", got %" PRIu8 ": ", 0x01, tx->write.address); - printf("expected write quantity %" PRIu8 ", got %" PRIu8 ": ", 2, tx->write.quantity); - printf("expected write count %" PRIu8 ", got %" PRIu8 ": ", 4, tx->write.count); - printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x000A, tx->data[0]); - printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x0102, tx->data[1]); + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address); + printf("expected write quantity %d, got %" PRIu16 ": ", 2, tx->write.quantity); + printf("expected write count %d, got %" PRIu8 ": ", 4, tx->write.count); + printf("expected data %d, got %" PRIu16 ": ", 0x000A, tx->data[0]); + printf("expected data %d, got %" PRIu16 ": ", 0x0102, tx->data[1]); goto end; } @@ -2807,9 +2806,9 @@ static int ModbusParserTest13(void) { ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); if ((tx->function != 22) || (tx->data[0] != 0x00F2) || (tx->data[1] != 0x0025)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); - printf("expected And_Mask %" PRIu8 ", got %" PRIu8 ": ", 0x00F2, tx->data[0]); - printf("expected Or_Mask %" PRIu8 ", got %" PRIu8 ": ", 0x0025, tx->data[1]); + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + printf("expected And_Mask %d, got %" PRIu16 ": ", 0x00F2, tx->data[0]); + printf("expected Or_Mask %d, got %" PRIu16 ": ", 0x0025, tx->data[1]); goto end; } @@ -2825,7 +2824,7 @@ static int ModbusParserTest13(void) { FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { - printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); goto end; } @@ -2875,9 +2874,9 @@ static int ModbusParserTest14(void) { ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); if ((tx->function != 6) || (tx->write.address != 0x0001) || (tx->data[0] != 0x0003)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); - printf("expected write address %" PRIu8 ", got %" PRIu8 ": ", 0x01, tx->write.address); - printf("expected data %" PRIu8 ", got %" PRIu8 ": ", 0x03, tx->data[0]); + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address); + printf("expected data %d, got %" PRIu16 ": ", 0x03, tx->data[0]); goto end; } @@ -2893,7 +2892,7 @@ static int ModbusParserTest14(void) { FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { - printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); goto end; } @@ -2972,7 +2971,7 @@ static int ModbusParserTest15(void) { ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); if (tx->function != 22) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); goto end; } @@ -2996,7 +2995,7 @@ static int ModbusParserTest15(void) { FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { - printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); goto end; } @@ -3083,8 +3082,8 @@ static int ModbusParserTest16(void) { ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); if ((tx->function != 6) || (tx->write.address != 0x0001)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 16, tx->function); - printf("expected write address %" PRIu8 ", got %" PRIu8 ": ", 0x01, tx->write.address); + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address); goto end; } @@ -3108,7 +3107,7 @@ static int ModbusParserTest16(void) { FLOWLOCK_UNLOCK(&f); if (modbus_state->transaction_max !=1) { - printf("expected transaction_max %" PRIu8 ", got %" PRIu64 ": ", 1, modbus_state->transaction_max); + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); goto end; } diff --git a/src/detect-modbus.c b/src/detect-modbus.c index b426b4b2c863..5e71d8f61a19 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -456,7 +456,7 @@ static int DetectModbusTest01(void) modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; if (modbus->function != 1) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 1, modbus->function); + printf("expected function %d, got %" PRIu8 ": ", 1, modbus->function); goto end; } @@ -500,8 +500,8 @@ static int DetectModbusTest02(void) modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; if ((modbus->function != 8) || (*modbus->subfunction != 4)) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", 1, modbus->function); - printf("expected subfunction %" PRIu8 ", got %" PRIu16 ": ", 4, *modbus->subfunction); + printf("expected function %d, got %" PRIu8 ": ", 1, modbus->function); + printf("expected subfunction %d, got %" PRIu16 ": ", 4, *modbus->subfunction); goto end; } @@ -545,7 +545,7 @@ static int DetectModbusTest03(void) modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; if (modbus->category != MODBUS_CAT_RESERVED) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", MODBUS_CAT_RESERVED, modbus->category); + printf("expected function %d, got %" PRIu8 ": ", MODBUS_CAT_RESERVED, modbus->category); goto end; } @@ -591,7 +591,7 @@ static int DetectModbusTest04(void) modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; if (modbus->category != category) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", ~MODBUS_CAT_PUBLIC_ASSIGNED, modbus->category); + printf("expected function %u, got %" PRIu8 ": ", ~MODBUS_CAT_PUBLIC_ASSIGNED, modbus->category); goto end; } @@ -635,7 +635,7 @@ static int DetectModbusTest05(void) modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; if (modbus->type != MODBUS_TYP_READ) { - printf("expected function %" PRIu8 ", got %" PRIu8 ": ", MODBUS_TYP_READ, modbus->type); + printf("expected function %d, got %" PRIu8 ": ", MODBUS_TYP_READ, modbus->type); goto end; } @@ -730,8 +730,8 @@ static int DetectModbusTest07(void) ((*modbus->address).mode != mode) || ((*modbus->address).min != 1000)) { printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); - printf("expected mode %" PRIu8 ", got %" PRIu16 ": ", mode, (*modbus->address).mode); - printf("expected address %" PRIu8 ", got %" PRIu16 ": ", 1000, (*modbus->address).min); + printf("expected mode %u, got %u: ", mode, (*modbus->address).mode); + printf("expected address %d, got %" PRIu16 ": ", 1000, (*modbus->address).min); goto end; } @@ -780,8 +780,8 @@ static int DetectModbusTest08(void) ((*modbus->address).mode != mode) || ((*modbus->address).min != 500)) { printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); - printf("expected mode %" PRIu8 ", got %" PRIu16 ": ", mode, (*modbus->address).mode); - printf("expected address %" PRIu8 ", got %" PRIu16 ": ", 500, (*modbus->address).min); + printf("expected mode %d, got %u: ", mode, (*modbus->address).mode); + printf("expected address %u, got %" PRIu16 ": ", 500, (*modbus->address).min); goto end; } @@ -834,11 +834,11 @@ static int DetectModbusTest09(void) ((*modbus->data).min != 500) || ((*modbus->data).max != 1000)) { printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); - printf("expected address mode %" PRIu8 ", got %" PRIu16 ": ", addressMode, (*modbus->address).mode); - printf("expected address %" PRIu8 ", got %" PRIu16 ": ", 500, (*modbus->address).min); - printf("expected value mode %" PRIu8 ", got %" PRIu16 ": ", valueMode, (*modbus->data).mode); - printf("expected min value %" PRIu8 ", got %" PRIu16 ": ", 500, (*modbus->data).min); - printf("expected max value %" PRIu8 ", got %" PRIu16 ": ", 1000, (*modbus->data).max); + printf("expected address mode %u, got %u: ", addressMode, (*modbus->address).mode); + printf("expected address %d, got %" PRIu16 ": ", 500, (*modbus->address).min); + printf("expected value mode %u, got %u: ", valueMode, (*modbus->data).mode); + printf("expected min value %d, got %" PRIu16 ": ", 500, (*modbus->data).min); + printf("expected max value %d, got %" PRIu16 ": ", 1000, (*modbus->data).max); goto end; } From c0377a98708f897805f980ff1b87581bf785a555 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 28 Nov 2016 12:18:47 -0600 Subject: [PATCH 2217/2553] stream-tcp: fix format string compiler warnings --- src/stream-tcp.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index c58dc1cd3fb4..2223548fbdc3 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -7175,9 +7175,9 @@ static int StreamTcpTest14 (void) printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) - (p->flow->protoctx))->client.os_policy, OS_POLICY_WINDOWS, + (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_WINDOWS, ((TcpSession *)(p->flow->protoctx))->server.os_policy, - OS_POLICY_LINUX); + (uint8_t)OS_POLICY_LINUX); goto end; } StreamTcpSessionClear(p->flow->protoctx); @@ -7589,9 +7589,9 @@ static int StreamTcpTest15 (void) printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) - (p->flow->protoctx))->client.os_policy, OS_POLICY_WINDOWS, + (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_WINDOWS, ((TcpSession *)(p->flow->protoctx))->server.os_policy, - OS_POLICY_LINUX); + (uint8_t)OS_POLICY_LINUX); goto end; } StreamTcpSessionPktFree(p); @@ -7763,9 +7763,9 @@ static int StreamTcpTest16 (void) printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) - (p->flow->protoctx))->client.os_policy, OS_POLICY_LINUX, + (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_LINUX, ((TcpSession *)(p->flow->protoctx))->server.os_policy, - OS_POLICY_WINDOWS); + (uint8_t)OS_POLICY_WINDOWS); goto end; } StreamTcpSessionPktFree(p); @@ -7938,9 +7938,9 @@ static int StreamTcpTest17 (void) printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) - (p->flow->protoctx))->client.os_policy, OS_POLICY_LINUX, + (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_LINUX, ((TcpSession *)(p->flow->protoctx))->server.os_policy, - OS_POLICY_DEFAULT); + (uint8_t)OS_POLICY_DEFAULT); goto end; } StreamTcpSessionPktFree(p); @@ -8045,7 +8045,7 @@ static int StreamTcpTest19 (void) if (stream.os_policy != OS_POLICY_WINDOWS) { printf("expected os_policy: %"PRIu8" but received %"PRIu8": ", - OS_POLICY_WINDOWS, stream.os_policy); + (uint8_t)OS_POLICY_WINDOWS, stream.os_policy); goto end; } @@ -8097,7 +8097,7 @@ static int StreamTcpTest20 (void) if (stream.os_policy != OS_POLICY_LINUX) { printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n", - OS_POLICY_LINUX, stream.os_policy); + (uint8_t)OS_POLICY_LINUX, stream.os_policy); goto end; } @@ -8149,7 +8149,7 @@ static int StreamTcpTest21 (void) if (stream.os_policy != OS_POLICY_LINUX) { printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n", - OS_POLICY_LINUX, stream.os_policy); + (uint8_t)OS_POLICY_LINUX, stream.os_policy); goto end; } @@ -8201,7 +8201,7 @@ static int StreamTcpTest22 (void) if (stream.os_policy != OS_POLICY_DEFAULT) { printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n", - OS_POLICY_DEFAULT, stream.os_policy); + (uint8_t)OS_POLICY_DEFAULT, stream.os_policy); goto end; } From 4aceaf9fcd2c0a9fca174a38d0e754d0028c2a3a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 28 Nov 2016 12:19:13 -0600 Subject: [PATCH 2218/2553] detect-stream_size: fix format string compiler warnings --- src/detect-stream_size.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c index f2296a04f4fe..d27dcd2dda51 100644 --- a/src/detect-stream_size.c +++ b/src/detect-stream_size.c @@ -354,7 +354,7 @@ static int DetectStreamSizeParseTest02 (void) DetectStreamSizeData *sd = NULL; sd = DetectStreamSizeParse("invalidoption,<,6"); if (sd != NULL) { - printf("expected: NULL got 0x%02X %" PRId16 ": ",sd->flags, sd->ssize); + printf("expected: NULL got 0x%02X %" PRIu32 ": ",sd->flags, sd->ssize); result = 0; DetectStreamSizeFree(sd); } From ba6a1aa73ebbb5fb9eb3bb03c7e33cad9a0d68db Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 28 Nov 2016 12:19:52 -0600 Subject: [PATCH 2219/2553] unittest-helper: fix format string compiler warnings --- src/util-unittest-helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-unittest-helper.c b/src/util-unittest-helper.c index 2eb2df207385..f82da37bda99 100644 --- a/src/util-unittest-helper.c +++ b/src/util-unittest-helper.c @@ -570,7 +570,7 @@ int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], for (; i < numsids; i++) { uint16_t r = PacketAlertCheck(p, sids[i]); if (r != results[i]) { - SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, and not %"PRIu16 + SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, and not %"PRIu32 " as expected", sids[i], r, results[i]); res = 0; } else { From 51f5ce6563e9d9f085154b2fc36e005564d72dfd Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 28 Nov 2016 10:23:34 -0600 Subject: [PATCH 2220/2553] travis: macos support --- .travis.yml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7fbbedd11580..59554c776564 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ +os: + - linux + - osx +osx_image: xcode8.1 language: c env: - CFLAGS="-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function" @@ -5,10 +9,17 @@ compiler: - gcc - clang # Change this to your needs -script: sh autogen.sh && ./configure --enable-nfqueue --enable-unittests --enable-hiredis && make && make check +script: + - sh autogen.sh + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./configure --enable-nfqueue --enable-unittests --enable-hiredis; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./configure --enable-unittests --enable-hiredis --enable-ipfw --enable-lua --with-libpcre-includes=/usr/local/include --with-libpcre-includes=/usr/local/include --with-libpcre-libraries=/usr/local/lib --with-libnss-includes=/usr/local/opt/nss/include/nss --with-libnss-libraries=/usr/local/opt/nss/lib --with-libnspr-includes=/usr/local/opt/nspr/include/nspr --with-libnspr-libraries=/usr/local/opt/nspr/lib; fi + - make + - make check before_install: - - sudo add-apt-repository -y ppa:npalix/coccinelle - - sudo apt-get update -qq - - sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 coccinelle libjansson-dev libhiredis-dev + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo add-apt-repository -y ppa:npalix/coccinelle; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update -qq; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 coccinelle libjansson-dev libhiredis-dev; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install pkg-config libmagic libyaml nss nspr jansson libnet lua pcre hiredis; fi - ./qa/travis-libhtp.sh From 8b8426934fed76c0d01e86999f592b9076ec528f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Nov 2016 09:29:17 +0100 Subject: [PATCH 2221/2553] qa: only run cocci tests on one linux builder --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 59554c776564..ae4981cd8fe1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,9 +16,10 @@ script: - make - make check before_install: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo add-apt-repository -y ppa:npalix/coccinelle; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "gcc" ]]; then sudo add-apt-repository -y ppa:npalix/coccinelle; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update -qq; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 coccinelle libjansson-dev libhiredis-dev; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "gcc" ]]; then sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 coccinelle libjansson-dev libhiredis-dev; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "clang" ]]; then sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 libjansson-dev libhiredis-dev; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install pkg-config libmagic libyaml nss nspr jansson libnet lua pcre hiredis; fi - ./qa/travis-libhtp.sh From e492f0dc8908ef64acb844e94f5d71b15baa0ada Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Wed, 12 Oct 2016 11:12:34 +0300 Subject: [PATCH 2222/2553] Fix port parsing in config file, added one more corresponding test. Some examples from wiki caused parsing errors. For example, "[1:80,![2,4]]" was treated as a mistake. Also fixed loop detection in variables declaration. For example, 'A: "HOME_NET, !$HOME_NET"' resulted in parsing error. --- src/detect-engine-address.c | 14 +++++------- src/detect-engine-port.c | 45 ++++++++++++++++++++++++++++++++----- src/util-var.c | 4 ++++ 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 4720d5e31ddc..a924855bcd1e 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -826,12 +826,6 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, char *rule_var_address = NULL; char *temp_rule_var_address = NULL; - if (AddVariableToResolveList(var_list, s) == -1) { - SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Found a loop in a address " - "groups declaration. This is likely a misconfiguration."); - goto error; - } - SCLogDebug("s %s negate %s", s, negate ? "true" : "false"); for (u = 0, x = 0; u < size && x < sizeof(address); u++) { @@ -996,6 +990,12 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, } x = 0; + if (AddVariableToResolveList(var_list, address) == -1) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Found a loop in a address " + "groups declaration. This is likely a misconfiguration."); + goto error; + } + if (d_set == 1) { rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); @@ -1324,8 +1324,6 @@ int DetectAddressTestConfVars(void) goto error; } - CleanVariableResolveList(&var_list); - if (DetectAddressIsCompleteIPSpace(ghn)) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "address var - \"%s\" has the complete IP space negated " diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index f1b9d106b94a..661cb47686d3 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -972,12 +972,6 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, char *rule_var_port = NULL; int r = 0; - if (AddVariableToResolveList(var_list, s) == -1) { - SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Found a loop in a port " - "groups declaration. This is likely a misconfiguration."); - goto error; - } - SCLogDebug("head %p, *head %p, negate %d", head, *head, negate); for (u = 0, x = 0; u < size && x < sizeof(address); u++) { @@ -1078,6 +1072,13 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, address[x] = '\0'; } SCLogDebug("%s", address); + + if (AddVariableToResolveList(var_list, address) == -1) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Found a loop in a port " + "groups declaration. This is likely a misconfiguration."); + goto error; + } + x = 0; if (d_set == 1) { char *temp_rule_var_port = NULL, @@ -1121,6 +1122,8 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, goto error; } n_set = 0; + } else if (depth == 1 && s[u] == ',') { + range = 0; } } @@ -2018,6 +2021,7 @@ int PortTestParse16 (void) DetectPortCleanupList(dd); return result; } + /** * \test Test general functions */ @@ -2390,6 +2394,34 @@ static int PortTestFunctions06(void) return result; } +/** + * \test Test general functions + */ +static int PortTestFunctions07(void) +{ + DetectPort *dd = NULL; + + // This one should fail due to negation in a range + FAIL_IF(DetectPortParse(NULL, &dd, "[80:!99]") == 0); + + // Correct: from 80 till 100 but 99 excluded + FAIL_IF_NOT(DetectPortParse(NULL, &dd, "[80:100,!99]") == 0); + FAIL_IF_NULL(dd->next); + FAIL_IF_NOT(dd->port == 80); + FAIL_IF_NOT(dd->port2 == 98); + FAIL_IF_NOT(dd->next->port == 100); + + // Also good: from 1 till 80 except of 2 and 4 + FAIL_IF_NOT(DetectPortParse(NULL, &dd, "[1:80,![2,4]]") == 0); + FAIL_IF_NOT(dd->port == 1); + FAIL_IF_NULL(DetectPortLookupGroup(dd, 3)); + FAIL_IF_NOT_NULL(DetectPortLookupGroup(dd, 2)); + FAIL_IF_NULL(DetectPortLookupGroup(dd, 80)); + + DetectPortCleanupList(dd); + PASS; +} + /** * \test Test packet Matches * \param raw_eth_pkt pointer to the ethernet packet @@ -2713,6 +2745,7 @@ void DetectPortTests(void) UtRegisterTest("PortTestFunctions04", PortTestFunctions04); UtRegisterTest("PortTestFunctions05", PortTestFunctions05); UtRegisterTest("PortTestFunctions06", PortTestFunctions06); + UtRegisterTest("PortTestFunctions07", PortTestFunctions07); UtRegisterTest("PortTestMatchReal01", PortTestMatchReal01); UtRegisterTest("PortTestMatchReal02", PortTestMatchReal02); UtRegisterTest("PortTestMatchReal03", PortTestMatchReal03); diff --git a/src/util-var.c b/src/util-var.c index dd7bbc132d91..f5c0379fda72 100644 --- a/src/util-var.c +++ b/src/util-var.c @@ -137,6 +137,10 @@ int AddVariableToResolveList(ResolvedVariablesList *list, const char *var) if (list == NULL || var == NULL) return 0; + if (var[0] != '$') { + return 0; + } + TAILQ_FOREACH(p_item, list, next) { if (!strcmp(p_item->var_name, var)) { return -1; From ab8faefd3751b8db6009e4a4df62bb5236da0ec4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Oct 2016 13:49:40 +0200 Subject: [PATCH 2223/2553] af-packet: fix fanout support on Debian Jessie Debian Jessie with kernel 3.16 would not accept the 'id' of 99 used in the test. Id 1 does work. --- src/source-af-packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 1909cdcbf6df..da80ea324ca6 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1815,7 +1815,7 @@ int AFPIsFanoutSupported(void) int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (fd != -1) { uint16_t mode = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; - uint16_t id = 99; + uint16_t id = 1; uint32_t option = (mode << 16) | (id & 0xffff); int r = setsockopt(fd, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); close(fd); From 2ce95babd6d83d503f15b0e383087c16f4537528 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 29 Nov 2016 07:57:02 -0600 Subject: [PATCH 2224/2553] dnp3: use _ in keyword names instead of "." dnp3.ind -> dnp3_ind dnp3.func -> dnp3_func dnp3.obj -> dnp3_obj The variations with a "." are now aliases. --- src/detect-dnp3.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 5cdad9565f88..3baf124f58b8 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -476,8 +476,8 @@ static void DetectDNP3FuncRegister(void) { SCEnter(); - sigmatch_table[DETECT_AL_DNP3FUNC].name = "dnp3.func"; - sigmatch_table[DETECT_AL_DNP3FUNC].alias = "dnp3_func"; + sigmatch_table[DETECT_AL_DNP3FUNC].name = "dnp3_func"; + sigmatch_table[DETECT_AL_DNP3FUNC].alias = "dnp3.func"; sigmatch_table[DETECT_AL_DNP3FUNC].Match = NULL; sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerTxMatch = DetectDNP3FuncMatch; @@ -493,8 +493,8 @@ static void DetectDNP3IndRegister(void) { SCEnter(); - sigmatch_table[DETECT_AL_DNP3IND].name = "dnp3.ind"; - sigmatch_table[DETECT_AL_DNP3IND].alias = "dnp3_ind"; + sigmatch_table[DETECT_AL_DNP3IND].name = "dnp3_ind"; + sigmatch_table[DETECT_AL_DNP3IND].alias = "dnp3.ind"; sigmatch_table[DETECT_AL_DNP3IND].Match = NULL; sigmatch_table[DETECT_AL_DNP3IND].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_DNP3IND].AppLayerTxMatch = DetectDNP3IndMatch; @@ -510,8 +510,8 @@ static void DetectDNP3ObjRegister(void) { SCEnter(); - sigmatch_table[DETECT_AL_DNP3OBJ].name = "dnp3.obj"; - sigmatch_table[DETECT_AL_DNP3OBJ].alias = "dnp3_obj"; + sigmatch_table[DETECT_AL_DNP3OBJ].name = "dnp3_obj"; + sigmatch_table[DETECT_AL_DNP3OBJ].alias = "dnp3.obj"; sigmatch_table[DETECT_AL_DNP3OBJ].Match = NULL; sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerTxMatch = DetectDNP3ObjMatch; From 7db3172479cce5b76c76bf5725c6f46b6078ce77 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Nov 2016 18:15:42 +0100 Subject: [PATCH 2225/2553] Update Changelog for 3.2 release --- ChangeLog | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ChangeLog b/ChangeLog index 62bf36d6a5b9..bdbc04129140 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +3.2 -- 2016-12-01 + +Bug #1117: PCAP file count does not persist +Bug #1577: luajit scripts load error +Bug #1924: Windows dynamic DNS updates trigger 'DNS malformed request data' alerts +Bug #1938: suricata: log handling issues +Bug #1955: luajit script init failed +Bug #1960: Error while parsing rule with PCRE keyword with semicolon +Bug #1961: No error on missing semicolon between depth and classtype +Bug #1965: dnp3/enip/cip keywords naming convention +Bug #1966: af-packet fanout detection broken on Debian Jessie (master) + 3.2RC1 -- 2016-11-01 Feature #1906: doc: install man page and ship pdf From 93680136452e0fb534ab57e9ab6eba0ccbe830a5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Dec 2016 14:54:04 +0100 Subject: [PATCH 2226/2553] unix-socket: don't error out on unix socket failure If --init-errors-fatal is specified do error out. Bug https://redmine.openinfosecfoundation.org/issues/1973 --- src/unix-manager.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index d1959684c5bc..71ef3802ffcc 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -908,16 +908,18 @@ static TmEcode UnixManagerThreadInit(ThreadVars *t, void *initdata, void **data) if (UnixNew(&command) == 0) { int failure_fatal = 0; - SCLogError(SC_ERR_INITIALIZATION, - "Unable to create unix command socket"); if (ConfGetBool("engine.init-failure-fatal", &failure_fatal) != 1) { SCLogDebug("ConfGetBool could not load the value."); } SCFree(utd); if (failure_fatal) { + SCLogError(SC_ERR_INITIALIZATION, + "Unable to create unix command socket"); exit(EXIT_FAILURE); } else { - return TM_ECODE_FAILED; + SCLogWarning(SC_ERR_INITIALIZATION, + "Unable to create unix command socket"); + return TM_ECODE_OK; } } From 3f741e450bbcf96cf13f3f8697f51e4717fe1779 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Dec 2016 15:06:57 +0100 Subject: [PATCH 2227/2553] unix-socket: be more specific about problems --- src/unix-manager.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/unix-manager.c b/src/unix-manager.c index 71ef3802ffcc..07f99268c072 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -140,11 +140,21 @@ int UnixNew(UnixCommand * this) SCLogInfo("Using unix socket file '%s'", sockettarget); } if (sockettarget == NULL) { + struct stat stat_buf; + /* coverity[toctou] */ + if (stat(SOCKET_PATH, &stat_buf) != 0) { + SCLogWarning(SC_ERR_INITIALIZATION, + "Unix socket: problem with requested directory in %s: %s", + SOCKET_TARGET, strerror(errno)); + return 0; + } sockettarget = SCStrdup(SOCKET_TARGET); if (unlikely(sockettarget == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); return 0; } + + } /* Remove socket file */ From c5e550b10d4b61fb5be4b117679bd2cab00420e5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Dec 2016 15:19:35 +0100 Subject: [PATCH 2228/2553] unix-socket: create socket directory if possible Create the socket directory in the default case. Since we're doing stat+mkdir indicate to Coverity not to worry about the toctou case. --- src/unix-manager.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index 07f99268c072..cc7af7eb6c4c 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -143,18 +143,27 @@ int UnixNew(UnixCommand * this) struct stat stat_buf; /* coverity[toctou] */ if (stat(SOCKET_PATH, &stat_buf) != 0) { - SCLogWarning(SC_ERR_INITIALIZATION, - "Unix socket: problem with requested directory in %s: %s", - SOCKET_TARGET, strerror(errno)); - return 0; + int ret; + /* coverity[toctou] */ + ret = mkdir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP); + if (ret != 0) { + int err = errno; + if (err != EEXIST) { + SCLogError(SC_ERR_INITIALIZATION, + "Cannot create socket directory %s: %s", + SOCKET_PATH, strerror(err)); + return 0; + } + } else { + SCLogInfo("Created socket directory %s", + SOCKET_PATH); + } } sockettarget = SCStrdup(SOCKET_TARGET); if (unlikely(sockettarget == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); return 0; } - - } /* Remove socket file */ From abbc0f76eb4cd5005312f3b0f2eabd0f473c40a5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 2 Dec 2016 10:10:20 +0100 Subject: [PATCH 2229/2553] unix-socket: clean up path handling Create/check socket path in a single place. Don't use dynamic memory allocation. --- src/unix-manager.c | 49 ++++++++++++---------------------------------- 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index cc7af7eb6c4c..b84b2c7a6589 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -97,7 +97,7 @@ int UnixNew(UnixCommand * this) int len; int ret; int on = 1; - char *sockettarget = NULL; + char sockettarget[PATH_MAX]; char *socketname; this->start_timestamp = time(NULL); @@ -108,38 +108,22 @@ int UnixNew(UnixCommand * this) TAILQ_INIT(&this->tasks); TAILQ_INIT(&this->clients); + int check_dir = 0; if (ConfGet("unix-command.filename", &socketname) == 1) { if (PathIsAbsolute(socketname)) { - sockettarget = SCStrdup(socketname); - if (unlikely(sockettarget == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); - return 0; - } + strlcpy(sockettarget, socketname, sizeof(sockettarget)); } else { - int socketlen = strlen(SOCKET_PATH) + strlen(socketname) + 2; - sockettarget = SCMalloc(socketlen); - if (unlikely(sockettarget == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); - return 0; - } - snprintf(sockettarget, socketlen, "%s/%s", SOCKET_PATH, socketname); - - /* Create socket dir */ - ret = mkdir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP); - if ( ret != 0 ) { - int err = errno; - if (err != EEXIST) { - SCFree(sockettarget); - SCLogError(SC_ERR_OPENING_FILE, - "Cannot create socket directory %s: %s", SOCKET_PATH, strerror(err)); - return 0; - } - } - + snprintf(sockettarget, sizeof(sockettarget), "%s/%s", + SOCKET_PATH, socketname); + check_dir = 1; } - SCLogInfo("Using unix socket file '%s'", sockettarget); + } else { + strlcpy(sockettarget, SOCKET_TARGET, sizeof(sockettarget)); + check_dir = 1; } - if (sockettarget == NULL) { + SCLogInfo("Using unix socket file '%s'", sockettarget); + + if (check_dir) { struct stat stat_buf; /* coverity[toctou] */ if (stat(SOCKET_PATH, &stat_buf) != 0) { @@ -159,11 +143,6 @@ int UnixNew(UnixCommand * this) SOCKET_PATH); } } - sockettarget = SCStrdup(SOCKET_TARGET); - if (unlikely(sockettarget == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); - return 0; - } } /* Remove socket file */ @@ -181,7 +160,6 @@ int UnixNew(UnixCommand * this) SCLogWarning(SC_ERR_OPENING_FILE, "Unix Socket: unable to create UNIX socket %s: %s", addr.sun_path, strerror(errno)); - SCFree(sockettarget); return 0; } this->select_max = this->socket + 1; @@ -213,7 +191,6 @@ int UnixNew(UnixCommand * this) SCLogWarning(SC_ERR_INITIALIZATION, "Unix socket: UNIX socket bind(%s) error: %s", sockettarget, strerror(errno)); - SCFree(sockettarget); return 0; } @@ -222,10 +199,8 @@ int UnixNew(UnixCommand * this) SCLogWarning(SC_ERR_INITIALIZATION, "Command server: UNIX socket listen() error: %s", strerror(errno)); - SCFree(sockettarget); return 0; } - SCFree(sockettarget); return 1; } From 92885d6960135b5f5f0c6a0e18ee796031b7f752 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 29 Nov 2016 10:45:02 -0600 Subject: [PATCH 2230/2553] profiling: fix shadow error Local variable store was shadowing variable in function definition. --- src/util-profiling.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-profiling.c b/src/util-profiling.c index a49d80aeaf73..122db86ea997 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1117,7 +1117,7 @@ static inline void SCProfilingUpdatePacketGenericRecord(PktProfilingData *pdt, } static void SCProfilingUpdatePacketGenericRecords(Packet *p, PktProfilingData *pd, - struct ProfileProtoRecords *store, int size) + struct ProfileProtoRecords *records, int size) { int i; for (i = 0; i < size; i++) { @@ -1127,7 +1127,7 @@ static void SCProfilingUpdatePacketGenericRecords(Packet *p, PktProfilingData *p continue; } - struct ProfileProtoRecords *r = &store[i]; + struct ProfileProtoRecords *r = &records[i]; SCProfilePacketData *store = NULL; if (PKT_IS_IPV4(p)) { From 94bc7e5f5f4756e0a4495227ee6dde2c7bba85ef Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 29 Nov 2016 11:03:03 -0600 Subject: [PATCH 2231/2553] travis: use a build matrix and add additional builds The following builds were added: - linux, clang with -Wshadow - linux w/ profiling - linux w/ debug - linux w/ no-json support Removes the extra OS X build. Travis file was reworked signficantly for readabilty. --- .travis.yml | 135 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 117 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index ae4981cd8fe1..98cb63b64454 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,125 @@ -os: - - linux - - osx -osx_image: xcode8.1 +# Default parameters, even this default build is excluded in the build +# matrix below. We define so Travis doesn't think this is a Ruby +# project. +os: linux language: c -env: - - CFLAGS="-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function" -compiler: - - gcc - - clang +compiler: gcc + +# Define the default CFLAGS used by all builds as a YAML anchor. +default-cflags: &default-cflags + CFLAGS="-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function" + +# The default build is Linux with gcc. Add additional builds to the +# matrix here. +matrix: + # Exclude the default build so any the builds in the matrix will be done. + exclude: + - os: linux + compiler: gcc + include: + # Linux, gcc, cocci tests enabled. + - os: linux + compiler: gcc + env: + - NAME="linux,gcc,cocci" + - *default-cflags + - ENABLE_COCCI="yes" + # Linux, clang. For this build we'll also enable -Wshadow. + - os: linux + compiler: clang + env: + - NAME="linux,clang" + - *default-cflags + - EXTRA_CFLAGS="-Wshadow" + # Linux, gcc, profiling. + - os: linux + compiler: gcc + env: + - NAME="linux,gcc,profiling" + - *default-cflags + - ARGS="--enable-profiling" + # Linux, gcc, debug. + - os: linux + compiler: gcc + env: + - NAME="linux,gcc,debug" + - *default-cflags + - ARGS="--enable-debug" + - ENABLE_DEBUG="yes" + # Linux, gcc, no json support. + - os: linux + compiler: gcc + env: + - NAME="linux,gcc,no-json" + - *default-cflags + - DISABLE_JSON="yes" + # OSX 10.12, XCode 8.1. + - os: osx + compiler: gcc + osx_image: xcode8.1 + env: + - NAME="osx,gcc" + - *default-cflags + # Change this to your needs script: - sh autogen.sh - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./configure --enable-nfqueue --enable-unittests --enable-hiredis; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./configure --enable-unittests --enable-hiredis --enable-ipfw --enable-lua --with-libpcre-includes=/usr/local/include --with-libpcre-includes=/usr/local/include --with-libpcre-libraries=/usr/local/lib --with-libnss-includes=/usr/local/opt/nss/include/nss --with-libnss-libraries=/usr/local/opt/nss/lib --with-libnspr-includes=/usr/local/opt/nspr/include/nspr --with-libnspr-libraries=/usr/local/opt/nspr/lib; fi + - | + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + ./configure --enable-nfqueue --enable-unittests --enable-hiredis ${ARGS} + fi + - | + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + export CFLAGS="${CFLAGS} ${EXTRA_CFLAGS}" + ./configure --enable-unittests --enable-hiredis --enable-ipfw \ + --enable-lua --with-libpcre-includes=/usr/local/include \ + --with-libpcre-includes=/usr/local/include \ + --with-libpcre-libraries=/usr/local/lib \ + --with-libnss-includes=/usr/local/opt/nss/include/nss \ + --with-libnss-libraries=/usr/local/opt/nss/lib \ + --with-libnspr-includes=/usr/local/opt/nspr/include/nspr \ + --with-libnspr-libraries=/usr/local/opt/nspr/lib + fi - make - - make check + # With debug enabled too much output is generated for Travis, so + # redirect stderr to a file. + - | + if [[ "$ENABLE_DEBUG" == "yes" ]]; then + make check 2> stderr.log + else + make check + fi before_install: - - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "gcc" ]]; then sudo add-apt-repository -y ppa:npalix/coccinelle; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update -qq; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "gcc" ]]; then sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 coccinelle libjansson-dev libhiredis-dev; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "clang" ]]; then sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 libjansson-dev libhiredis-dev; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install pkg-config libmagic libyaml nss nspr jansson libnet lua pcre hiredis; fi + - | + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + + if [[ "$ENABLE_COCCI" == "yes" ]]; then + sudo add-apt-repository -y ppa:npalix/coccinelle + fi + + sudo apt-get update -qq + sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev \ + build-essential autoconf automake libtool libpcap-dev libnet1-dev \ + libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev \ + libcap-ng0 make libmagic-dev libnetfilter-queue-dev \ + libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 \ + libhiredis-dev + + + if [[ "$ENABLE_COCCI" == "yes" ]]; then + sudo apt-get install -y coccinelle + fi + + if [[ "$DISABLE_JSON" != "yes" ]]; then + sudo apt-get install -y libjansson-dev + fi + + fi + - | + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew update + brew install pkg-config libmagic libyaml nss nspr jansson libnet lua \ + pcre hiredis + fi - ./qa/travis-libhtp.sh From 579d6d3ff77af42d3d7d1b85a68a1f55c704fbf3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 13 Dec 2016 10:23:21 +0100 Subject: [PATCH 2232/2553] http: allow lower/mixed case in proto detect In HTTP detection registered patterns were upper case only. Since the detection is based on both sides this would still work for sessions where one of the talkers misbehaved. If both sides misbehave this would fail however, so this patch introduces case insensive matching. --- src/app-layer-htp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 0f297df1fc48..4d435cc236d5 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2737,7 +2737,7 @@ static int HTPRegisterPatternsForProtocolDetection(void) * 3 is subtracted from the length since the spacing is hex typed as |xx| * but the pattern matching should only be one char */ - register_result = AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, + register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP, method_buffer, strlen(method_buffer)-3, 0, STREAM_TOSERVER); if (register_result < 0) { return -1; @@ -2747,7 +2747,7 @@ static int HTPRegisterPatternsForProtocolDetection(void) /* Loop through all the http verions patterns that are TO_CLIENT */ for (versions_pos = 0; versions[versions_pos]; versions_pos++) { - register_result = AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, + register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP, versions[versions_pos], strlen(versions[versions_pos]), 0, STREAM_TOCLIENT); if (register_result < 0) { From a44b612a4172885dea288ec7a55d07ba088b7728 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Dec 2016 12:11:18 +0100 Subject: [PATCH 2233/2553] hostbits/xbits: free hostbit Fix memory leak. Hostbits were not actually freed. Bug #1975. --- src/host-bit.c | 1 + src/util-var.c | 2 +- src/util-var.h | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/host-bit.c b/src/host-bit.c index db86924ee5a0..9c4083b02eda 100644 --- a/src/host-bit.c +++ b/src/host-bit.c @@ -123,6 +123,7 @@ static void HostBitRemove(Host *h, uint16_t idx) GenericVar *gv = HostGetStorageById(h, host_bit_id); if (gv) { GenericVarRemove(&gv, (GenericVar *)fb); + XBitFree(fb); HostSetStorageById(h, host_bit_id, gv); } } diff --git a/src/util-var.c b/src/util-var.c index f5c0379fda72..8a2df63f1fa7 100644 --- a/src/util-var.c +++ b/src/util-var.c @@ -36,7 +36,7 @@ #include "util-debug.h" -static void XBitFree(XBit *fb) +void XBitFree(XBit *fb) { if (fb == NULL) return; diff --git a/src/util-var.h b/src/util-var.h index b95b59fd2b25..39f2698dc088 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -57,6 +57,8 @@ typedef struct XBit_ { uint32_t expire; } XBit; +void XBitFree(XBit *); + // A list of variables we try to resolve while parsing configuration file. // Helps to detect recursive declarations. typedef struct ResolvedVariable_ { From 41074a87a02daae8a225316672bd536d1e428400 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 4 Dec 2016 11:10:18 +0100 Subject: [PATCH 2234/2553] doc: DNP3 support is now available --- doc/userguide/rules/dnp3-keywords.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/userguide/rules/dnp3-keywords.rst b/doc/userguide/rules/dnp3-keywords.rst index 7fe34f75de57..88763306158c 100644 --- a/doc/userguide/rules/dnp3-keywords.rst +++ b/doc/userguide/rules/dnp3-keywords.rst @@ -1,8 +1,6 @@ DNP3 Keywords ============= -**NOTE: DNP3 is currently in development and is not yet available.** - The DNP3 keywords can be used to match on fields in decoded DNP3 messages. The keywords are based on Snort's DNP3 keywords and aim to be 100% compatible. From 79a3c6c7b1f1b2a99191ff8df4deb43f12c9c547 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 15 Dec 2016 12:36:25 -0600 Subject: [PATCH 2235/2553] log-pcap: use a snaplen of 262144 instead of -1. Newer versions of libpcap will not open pcap files with a snaplen of -1, instead use the current maximum value of 262144. Issue: https://redmine.openinfosecfoundation.org/issues/1987 --- src/log-pcap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/log-pcap.c b/src/log-pcap.c index 622b30466c35..cc309e318a06 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -82,6 +82,8 @@ #define HONOR_PASS_RULES_DISABLED 0 #define HONOR_PASS_RULES_ENABLED 1 +#define PCAP_SNAPLEN 262144 + SC_ATOMIC_DECLARE(uint32_t, thread_cnt); typedef struct PcapFileName_ { @@ -317,7 +319,7 @@ static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p) if (pl->pcap_dead_handle == NULL) { if ((pl->pcap_dead_handle = pcap_open_dead(p->datalink, - -1)) == NULL) { + PCAP_SNAPLEN)) == NULL) { SCLogDebug("Error opening dead pcap handle"); return TM_ECODE_FAILED; } From 810e43f373480662c5092aa3d3de81479711abe7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 13 Nov 2016 08:36:25 -0500 Subject: [PATCH 2236/2553] magic: make optional Make libmagic optional. If installed it will be enabled by default in configure. Use --disable-libmagic to disable. --- configure.ac | 63 ++++++++++++++++++++---------------- src/detect-engine-siggroup.c | 3 +- src/detect-filemagic.c | 24 ++++++++++++++ src/detect-filemagic.h | 5 +-- src/detect.c | 4 +-- src/detect.h | 2 ++ src/log-file.c | 4 +-- src/log-filestore.c | 3 +- src/output-file.c | 4 +-- src/output-filedata.c | 3 +- src/output-json-file.c | 2 ++ src/suricata-common.h | 4 +++ src/suricata.c | 11 +++++-- src/util-error.c | 1 + src/util-error.h | 1 + src/util-file.c | 8 ++--- src/util-file.h | 2 ++ src/util-lua-common.c | 8 ++++- src/util-magic.c | 5 +-- src/util-magic.h | 4 +-- 20 files changed, 112 insertions(+), 49 deletions(-) diff --git a/configure.ac b/configure.ac index 2144a36980a2..7b2e1be76749 100644 --- a/configure.ac +++ b/configure.ac @@ -1554,35 +1554,43 @@ fi # libmagic - AC_ARG_WITH(libmagic_includes, - [ --with-libmagic-includes=DIR libmagic include directory], - [with_libmagic_includes="$withval"],[with_libmagic_includes=no]) - AC_ARG_WITH(libmagic_libraries, - [ --with-libmagic-libraries=DIR libmagic library directory], - [with_libmagic_libraries="$withval"],[with_libmagic_libraries="no"]) - - if test "$with_libmagic_includes" != "no"; then - CPPFLAGS="${CPPFLAGS} -I${with_libmagic_includes}" - fi - - AC_CHECK_HEADER(magic.h,,[AC_ERROR(magic.h not found ...)]) - - if test "$with_libmagic_libraries" != "no"; then - LDFLAGS="${LDFLAGS} -L${with_libmagic_libraries}" - fi + enable_magic="no" + AC_ARG_ENABLE(libmagic, + AS_HELP_STRING([--enable-libmagic], [Enable libmagic support [default=yes]]), + ,[enable_magic=yes]) + if test "$enable_magic" = "yes"; then + AC_ARG_WITH(libmagic_includes, + [ --with-libmagic-includes=DIR libmagic include directory], + [with_libmagic_includes="$withval"],[with_libmagic_includes=no]) + AC_ARG_WITH(libmagic_libraries, + [ --with-libmagic-libraries=DIR libmagic library directory], + [with_libmagic_libraries="$withval"],[with_libmagic_libraries="no"]) + + if test "$with_libmagic_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_libmagic_includes}" + fi - MAGIC="" - AC_CHECK_LIB(magic, magic_open,, MAGIC="no") + AC_CHECK_HEADER(magic.h,,MAGIC="no") + if test "$MAGIC" != "no"; then + MAGIC="" + AC_CHECK_LIB(magic, magic_open,, MAGIC="no") + fi - if test "$MAGIC" = "no"; then - echo - echo " ERROR! magic library not found, go get it" - echo " from http://www.darwinsys.com/file/ or your distribution:" - echo - echo " Ubuntu: apt-get install libmagic-dev" - echo " Fedora: yum install file-devel" - echo - exit 1 + if test "x$MAGIC" != "xno"; then + if test "$with_libmagic_libraries" != "no"; then + LDFLAGS="${LDFLAGS} -L${with_libmagic_libraries}" + fi + AC_DEFINE([HAVE_MAGIC],[1],(Libmagic for file handling)) + else + echo + echo " WARNING! magic library not found, go get it" + echo " from http://www.darwinsys.com/file/ or your distribution:" + echo + echo " Ubuntu: apt-get install libmagic-dev" + echo " Fedora: yum install file-devel" + echo + enable_magic="no" + fi fi # Napatech - Using the 3GD API @@ -1994,6 +2002,7 @@ SURICATA_BUILD_CONF="Suricata Configuration: Unix socket enabled: ${enable_unixsocket} Detection enabled: ${enable_detection} + Libmagic support: ${enable_magic} libnss support: ${enable_nss} libnspr support: ${enable_nspr} libjansson support: ${enable_jansson} diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 0c49ef035a93..276f204983d1 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -533,6 +533,7 @@ int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, */ void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { +#ifdef HAVE_MAGIC Signature *s = NULL; uint32_t sig = 0; @@ -549,7 +550,7 @@ void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) break; } } - +#endif return; } diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 44386939bef2..9fe540ffa8cc 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -54,6 +54,27 @@ #include "conf.h" +#ifndef HAVE_MAGIC + +static int DetectFilemagicSetupNoSupport (DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCLogError(SC_ERR_NO_MAGIC_SUPPORT, "no libmagic support built in, needed for filemagic keyword"); + return -1; +} + +/** + * \brief Registration function for keyword: filemagic + */ +void DetectFilemagicRegister(void) +{ + sigmatch_table[DETECT_FILEMAGIC].name = "filemagic"; + sigmatch_table[DETECT_FILEMAGIC].desc = "match on the information libmagic returns about a file"; + sigmatch_table[DETECT_FILEMAGIC].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemagic"; + sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetupNoSupport; +} + +#else /* HAVE_MAGIC */ + static int DetectFilemagicMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, Signature *, SigMatch *); static int DetectFilemagicSetup (DetectEngineCtx *, Signature *, char *); @@ -453,3 +474,6 @@ void DetectFilemagicRegisterTests(void) UtRegisterTest("DetectFilemagicTestParse03", DetectFilemagicTestParse03); #endif /* UNITTESTS */ } + +#endif /* HAVE_MAGIC */ + diff --git a/src/detect-filemagic.h b/src/detect-filemagic.h index 97cd79543fb5..e36dfcbcfe8d 100644 --- a/src/detect-filemagic.h +++ b/src/detect-filemagic.h @@ -24,8 +24,8 @@ #ifndef __DETECT_FILEMAGIC_H__ #define __DETECT_FILEMAGIC_H__ +#ifdef HAVE_MAGIC #include "util-spm-bm.h" -#include typedef struct DetectFilemagicThreadData { magic_t ctx; @@ -40,7 +40,8 @@ typedef struct DetectFilemagicData { } DetectFilemagicData; /* prototypes */ -void DetectFilemagicRegister (void); int FilemagicGlobalLookup(File *file); +#endif +void DetectFilemagicRegister (void); #endif /* __DETECT_FILEMAGIC_H__ */ diff --git a/src/detect.c b/src/detect.c index e75e393dd7e4..448e41612b03 100644 --- a/src/detect.c +++ b/src/detect.c @@ -953,7 +953,7 @@ DetectPostInspectFileFlagsUpdate(Flow *pflow, const SigGroupHead *sgh, uint8_t d if (sgh == NULL || sgh->filestore_cnt == 0) { FileDisableStoring(pflow, direction); } - +#ifdef HAVE_MAGIC /* see if this sgh requires us to consider file magic */ if (!FileForceMagic() && (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC))) @@ -961,7 +961,7 @@ DetectPostInspectFileFlagsUpdate(Flow *pflow, const SigGroupHead *sgh, uint8_t d SCLogDebug("disabling magic for flow"); FileDisableMagic(pflow, direction); } - +#endif /* see if this sgh requires us to consider file md5 */ if (!FileForceMd5() && (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMD5))) diff --git a/src/detect.h b/src/detect.h index e3f479063075..9021c940dcdc 100644 --- a/src/detect.h +++ b/src/detect.h @@ -999,7 +999,9 @@ typedef struct SigTableElmt_ { } SigTableElmt; +#ifdef HAVE_MAGIC #define SIG_GROUP_HEAD_HAVEFILEMAGIC (1 << 20) +#endif #define SIG_GROUP_HEAD_HAVEFILEMD5 (1 << 21) #define SIG_GROUP_HEAD_HAVEFILESIZE (1 << 22) #define SIG_GROUP_HEAD_HAVEFILESHA1 (1 << 23) diff --git a/src/log-file.c b/src/log-file.c index 19821a22f885..0b441127b94a 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -269,7 +269,7 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const fprintf(fp, "\"filename\": \""); PrintRawJsonFp(fp, ff->name, ff->name_len); fprintf(fp, "\", "); - +#ifdef HAVE_MAGIC fprintf(fp, "\"magic\": \""); if (ff->magic) { PrintRawJsonFp(fp, (uint8_t *)ff->magic, strlen(ff->magic)); @@ -277,7 +277,7 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const fprintf(fp, "unknown"); } fprintf(fp, "\", "); - +#endif switch (ff->state) { case FILE_STATE_CLOSED: fprintf(fp, "\"state\": \"CLOSED\", "); diff --git a/src/log-filestore.c b/src/log-filestore.c index d57b589246f1..260357cb9d3a 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -247,9 +247,10 @@ static void LogFilestoreLogCloseMetaFile(const File *ff) snprintf(metafilename, sizeof(metafilename), "%s.meta", filename); FILE *fp = fopen(metafilename, "a"); if (fp != NULL) { +#ifdef HAVE_MAGIC fprintf(fp, "MAGIC: %s\n", ff->magic ? ff->magic : ""); - +#endif switch (ff->state) { case FILE_STATE_CLOSED: fprintf(fp, "STATE: CLOSED\n"); diff --git a/src/output-file.c b/src/output-file.c index f43d63970f02..020be8e28288 100644 --- a/src/output-file.c +++ b/src/output-file.c @@ -147,11 +147,11 @@ static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data) ff->state == FILE_STATE_ERROR) { int file_logged = 0; - +#ifdef HAVE_MAGIC if (FileForceMagic() && ff->magic == NULL) { FilemagicGlobalLookup(ff); } - +#endif logger = list; store = op_thread_data->store; while (logger && store) { diff --git a/src/output-filedata.c b/src/output-filedata.c index 50cff2816276..3e7734375bbf 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -165,10 +165,11 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data) if (ffc != NULL) { File *ff; for (ff = ffc->head; ff != NULL; ff = ff->next) { +#ifdef HAVE_MAGIC if (FileForceMagic() && ff->magic == NULL) { FilemagicGlobalLookup(ff); } - +#endif SCLogDebug("ff %p", ff); if (ff->flags & FILE_STORED) { SCLogDebug("stored flag set"); diff --git a/src/output-json-file.c b/src/output-json-file.c index b47340aa6597..74ac35912bbd 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -119,8 +119,10 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F json_object_set_new(fjs, "filename", json_string(s)); if (s != NULL) SCFree(s); +#ifdef HAVE_MAGIC if (ff->magic) json_object_set_new(fjs, "magic", json_string((char *)ff->magic)); +#endif switch (ff->state) { case FILE_STATE_CLOSED: json_object_set_new(fjs, "state", json_string("CLOSED")); diff --git a/src/suricata-common.h b/src/suricata-common.h index 5a40156b16a6..4ac5275fb130 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -225,6 +225,10 @@ #endif #endif +#ifdef HAVE_MAGIC +#include +#endif + #if CPPCHECK==1 #define BUG_ON(x) if (((x))) exit(1) #else diff --git a/src/suricata.c b/src/suricata.c index 1238f972d14d..85d4bb5459b5 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -679,6 +679,9 @@ void SCPrintBuildInfo(void) #endif #ifdef TLS strlcat(features, "TLS ", sizeof(features)); +#endif +#ifdef HAVE_MAGIC + strlcat(features, "MAGIC ", sizeof(features)); #endif if (strlen(features) == 0) { strlcat(features, "none", sizeof(features)); @@ -2397,10 +2400,10 @@ static int PostConfLoadedSetup(SCInstance *suri) } HostInitConfig(HOST_VERBOSE); - +#ifdef HAVE_MAGIC if (MagicInit() != 0) SCReturnInt(TM_ECODE_FAILED); - +#endif SCAsn1LoadConfig(); CoredumpLoadConfig(); @@ -2563,7 +2566,9 @@ int main(int argc, char **argv) if (suri.run_mode == RUNMODE_CONF_TEST){ SCLogNotice("Configuration provided was successfully loaded. Exiting."); +#ifdef HAVE_MAGIC MagicDeinit(); +#endif exit(EXIT_SUCCESS); } @@ -2752,7 +2757,9 @@ int main(int argc, char **argv) SCReferenceConfDeinit(); SCClassConfDeinit(); } +#ifdef HAVE_MAGIC MagicDeinit(); +#endif TmqhCleanup(); TmModuleRunDeInit(); ParseSizeDeinit(); diff --git a/src/util-error.c b/src/util-error.c index bc144a43321c..b7fc7b929371 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -333,6 +333,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_DNP3_CONFIG); CASE_CODE (SC_ERR_DIR_OPEN); CASE_CODE(SC_WARN_REMOVE_FILE); + CASE_CODE (SC_ERR_NO_MAGIC_SUPPORT); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 9a68fe501154..2a825b18ba94 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -323,6 +323,7 @@ typedef enum { SC_ERR_DNP3_CONFIG, SC_ERR_DIR_OPEN, SC_WARN_REMOVE_FILE, + SC_ERR_NO_MAGIC_SUPPORT, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-file.c b/src/util-file.c index c8ef9b3916ee..8a79fcbdeb99 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -286,7 +286,7 @@ uint64_t FileSize(const File *file) static int FilePruneFile(File *file) { SCEnter(); - +#ifdef HAVE_MAGIC if (!(file->flags & FILE_NOMAGIC)) { /* need magic but haven't set it yet, bail out */ if (file->magic == NULL) @@ -296,7 +296,7 @@ static int FilePruneFile(File *file) } else { SCLogDebug("file->flags & FILE_NOMAGIC == true"); } - +#endif uint64_t left_edge = file->content_stored; if (file->flags & FILE_NOSTORE) { left_edge = FileSize(file); @@ -443,11 +443,11 @@ static void FileFree(File *ff) if (ff->name != NULL) SCFree(ff->name); - +#ifdef HAVE_MAGIC /* magic returned by libmagic is strdup'd by MagicLookup. */ if (ff->magic != NULL) SCFree(ff->magic); - +#endif if (ff->sb != NULL) { StreamingBufferFree(ff->sb); } diff --git a/src/util-file.h b/src/util-file.h index 8e9b1a3c8d94..e0d154de89ac 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -67,7 +67,9 @@ typedef struct File_ { uint64_t txid; /**< tx this file is part of */ uint32_t file_id; uint8_t *name; +#ifdef HAVE_MAGIC char *magic; +#endif struct File_ *next; #ifdef HAVE_NSS HASHContext *md5_ctx; diff --git a/src/util-lua-common.c b/src/util-lua-common.c index 74116fec3e7d..b51f8aad40bd 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -651,7 +651,13 @@ static int LuaCallbackFileInfoPushToStackFromFile(lua_State *luastate, const Fil lua_pushnumber(luastate, file->txid); lua_pushlstring(luastate, (char *)file->name, file->name_len); lua_pushnumber(luastate, FileSize(file)); - lua_pushstring (luastate, file->magic); + lua_pushstring (luastate, +#ifdef HAVE_MAGIC + file->magic +#else + "nomagic" +#endif + ); lua_pushstring(luastate, md5ptr); lua_pushstring(luastate, sha1ptr); lua_pushstring(luastate, sha256ptr); diff --git a/src/util-magic.c b/src/util-magic.c index 5f0719787598..e0f08a2ac214 100644 --- a/src/util-magic.c +++ b/src/util-magic.c @@ -28,10 +28,11 @@ */ #include "suricata-common.h" + +#ifdef HAVE_MAGIC #include "conf.h" #include "util-unittest.h" -#include static magic_t g_magic_ctx = NULL; static SCMutex g_magic_lock; @@ -654,7 +655,7 @@ static int MagicDetectTest10ValgrindError(void) } #endif /* UNITTESTS */ - +#endif void MagicRegisterTests(void) { diff --git a/src/util-magic.h b/src/util-magic.h index 85b72d1b157f..a2ffc7bac550 100644 --- a/src/util-magic.h +++ b/src/util-magic.h @@ -24,12 +24,12 @@ #ifndef __UTIL_MAGIC_H__ #define __UTIL_MAGIC_H__ -#include - +#ifdef HAVE_MAGIC int MagicInit(void); void MagicDeinit(void); char *MagicGlobalLookup(const uint8_t *, uint32_t); char *MagicThreadLookup(magic_t *, const uint8_t *, uint32_t); +#endif void MagicRegisterTests(void); #endif /* __UTIL_MAGIC_H__ */ From 554065189c6734c52467d107aac30f7e77441fa4 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 13 Dec 2016 14:56:26 +0100 Subject: [PATCH 2237/2553] tls: don't trigger decoder event on no extensions in CLIENT_HELLO No extensions are allowed in Date: Fri, 16 Dec 2016 13:04:03 +0100 Subject: [PATCH 2238/2553] tls: increase max number of tls records per packet Tls packets may contain several records. This increase the number of allowed records per packet from 30 to 255, and adds a new and more informative decoder event when this limit is reached. --- rules/tls-events.rules | 3 ++- src/app-layer-ssl.c | 8 ++++++-- src/app-layer-ssl.h | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/rules/tls-events.rules b/rules/tls-events.rules index f22b1fed93a4..2555f1895283 100644 --- a/rules/tls-events.rules +++ b/rules/tls-events.rules @@ -26,5 +26,6 @@ alert tls any any -> any any (msg:"SURICATA TLS multiple SNI extensions"; flow:e alert tls any any -> any any (msg:"SURICATA TLS invalid SNI type"; flow:established,to_server; app-layer-event:tls.invalid_sni_type; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230017; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS invalid SNI length"; flow:established,to_server; app-layer-event:tls.invalid_sni_length; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230018; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS handshake invalid length"; flow:established; app-layer-event:tls.handshake_invalid_length; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230019; rev:1;) +alert tls any any -> any any (msg:"SURICATA TLS too many records in packet"; flow:established; app-layer-event:tls.too_many_records_in_packet; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230020; rev:1;) -#next sid is 2230020 +#next sid is 2230021 diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 5de302ed870d..6483f224d603 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -67,6 +67,7 @@ SCEnumCharMap tls_decoder_event_table[ ] = { { "MULTIPLE_SNI_EXTENSIONS", TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS }, { "INVALID_SNI_TYPE", TLS_DECODER_EVENT_INVALID_SNI_TYPE }, { "INVALID_SNI_LENGTH", TLS_DECODER_EVENT_INVALID_SNI_LENGTH }, + { "TOO_MANY_RECORDS_IN_PACKET", TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET }, /* certificate decoding messages */ { "INVALID_CERTIFICATE", TLS_DECODER_EVENT_INVALID_CERTIFICATE }, { "CERTIFICATE_MISSING_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT }, @@ -131,6 +132,8 @@ SslConfig ssl_config; #define TLS_HB_REQUEST 1 #define TLS_HB_RESPONSE 2 +#define SSL_PACKET_MAX_RECORDS 255 + #define HAS_SPACE(n) ((uint32_t)((input) + (n) - (initial_input)) > (uint32_t)(input_len)) ? 0 : 1 static void SSLParserReset(SSLState *ssl_state) @@ -1365,11 +1368,12 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt /* if we have more than one record */ while (input_len > 0) { - if (counter++ == 30) { + if (counter++ == SSL_PACKET_MAX_RECORDS) { SCLogDebug("Looks like we have looped quite a bit. Reset state " "and get out of here"); SSLParserReset(ssl_state); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET); return -1; } diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 31ca913e7467..1a8a0a2ec228 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -46,6 +46,7 @@ enum { TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS, TLS_DECODER_EVENT_INVALID_SNI_TYPE, TLS_DECODER_EVENT_INVALID_SNI_LENGTH, + TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET, /* Certificates decoding messages */ TLS_DECODER_EVENT_INVALID_CERTIFICATE, TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT, From ffcb4ad232da6250199477d413ae13fee6d2a945 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 16 Dec 2016 14:43:43 +0100 Subject: [PATCH 2239/2553] tls: fix tls_cert_subject prefilter bug If check in prefilter was checking that issuer was non-NULL, when it in fact should be checking subject. --- src/detect-engine-tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 6adac0f8b8f3..8e216618b04a 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -215,7 +215,7 @@ static void PrefilterTxTlsSubject(DetectEngineThreadCtx *det_ctx, const void *pe const MpmCtx *mpm_ctx = (MpmCtx *)pectx; SSLState *ssl_state = f->alstate; - if (ssl_state->server_connp.cert0_issuerdn == NULL) + if (ssl_state->server_connp.cert0_subject == NULL) return; const uint8_t *buffer = (const uint8_t *)ssl_state->server_connp.cert0_subject; From 9f6b58747b6939ec1c04019ea03aadf8432b3f5a Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 14 Dec 2016 18:01:09 +0100 Subject: [PATCH 2240/2553] smtp: commands and replies are not case sensitive RFC states that "Commands and replies are not case sensitive" and patterns were registered to be case sensitive. So this patch fixes a trivial evasion of SMTP signatures. --- src/app-layer-smtp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 1eb0aa29d0ae..cd02d91236d8 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1490,17 +1490,17 @@ int SMTPStateGetEventInfo(const char *event_name, static int SMTPRegisterPatternsForProtocolDetection(void) { - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP, + if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP, "EHLO", 4, 0, STREAM_TOSERVER) < 0) { return -1; } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP, + if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP, "HELO", 4, 0, STREAM_TOSERVER) < 0) { return -1; } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP, + if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP, "QUIT", 4, 0, STREAM_TOSERVER) < 0) { return -1; From 27ec81118715bacc9ec50a75ac6b5efdb1e489e7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 19 Dec 2016 09:11:48 -0600 Subject: [PATCH 2241/2553] pcap-log: fix memory leak during initialization of ring buffer A free was missing when files are removed during initialization of the ring buffer. Redmine issue: https://redmine.openinfosecfoundation.org/issues/1985 --- src/log-pcap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/log-pcap.c b/src/log-pcap.c index cc309e318a06..70f4c6bf91af 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -671,6 +671,7 @@ static TmEcode PcapLogInitRingBuffer(PcapLogData *pl) strerror(errno)); } TAILQ_REMOVE(&pl->pcap_file_list, pf, next); + PcapFileNameFree(pf); pf = TAILQ_FIRST(&pl->pcap_file_list); pl->file_cnt--; } From cb08f02140c0097734853977abb5db642f5b3d9d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 13 Oct 2016 12:42:17 +0200 Subject: [PATCH 2242/2553] xbits: clean up parsing and tests --- src/detect-xbits.c | 213 +++++++++++++++++++++++++-------------------- src/detect-xbits.h | 2 + 2 files changed, 120 insertions(+), 95 deletions(-) diff --git a/src/detect-xbits.c b/src/detect-xbits.c index 261f0c82b6e5..07409b1e0508 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -180,10 +180,16 @@ int DetectXbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S return 0; } -int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +/** \internal + * \brief parse xbits rule options + * \retval 0 ok + * \retval -1 bad + * \param[out] cdout return DetectXbitsData structure or NULL if noalert + */ +static int DetectXbitParse(DetectEngineCtx *de_ctx, + const char *rawstr, DetectXbitsData **cdout) { DetectXbitsData *cd = NULL; - SigMatch *sm = NULL; uint8_t fb_cmd = 0; uint8_t hb_dir = 0; #define MAX_SUBSTRINGS 30 @@ -192,7 +198,7 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) char fb_cmd_str[16] = "", fb_name[256] = ""; char hb_dir_str[16] = ""; enum VarTypes var_type = VAR_TYPE_NOT_SET; - int expire = 30; + int expire = DETECT_XBITS_EXPIRE_DEFAULT; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 2 && ret != 3 && ret != 4 && ret != 5) { @@ -210,13 +216,13 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, fb_name, sizeof(fb_name)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - goto error; + return -1; } if (ret >= 4) { res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, hb_dir_str, sizeof(hb_dir_str)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - goto error; + return -1; } SCLogDebug("hb_dir_str %s", hb_dir_str); if (strlen(hb_dir_str) > 0) { @@ -231,7 +237,7 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) var_type = VAR_TYPE_IPPAIR_BIT; } else { // TODO - goto error; + return -1; } } @@ -240,10 +246,19 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, expire_str, sizeof(expire_str)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - goto error; + return -1; } SCLogDebug("expire_str %s", expire_str); expire = atoi(expire_str); + if (expire < 0) { + SCLogError(SC_ERR_INVALID_VALUE, "expire must be positive. " + "Got %d (\"%s\")", expire, expire_str); + return -1; + } + if (expire == 0) { + SCLogError(SC_ERR_INVALID_VALUE, "expire must be bigger than 0"); + return -1; + } SCLogDebug("expire %d", expire); } } @@ -262,16 +277,18 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) } else if (strcmp(fb_cmd_str,"toggle") == 0) { fb_cmd = DETECT_XBITS_CMD_TOGGLE; } else { - SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str); - goto error; + SCLogError(SC_ERR_UNKNOWN_VALUE, "xbits action \"%s\" is not supported.", fb_cmd_str); + return -1; } switch (fb_cmd) { - case DETECT_XBITS_CMD_NOALERT: + case DETECT_XBITS_CMD_NOALERT: { if (strlen(fb_name) != 0) - goto error; - s->flags |= SIG_FLAG_NOALERT; + return -1; + /* return ok, cd is NULL. Flag sig. */ + *cdout = NULL; return 0; + } case DETECT_XBITS_CMD_ISNOTSET: case DETECT_XBITS_CMD_ISSET: case DETECT_XBITS_CMD_SET: @@ -279,13 +296,13 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) case DETECT_XBITS_CMD_TOGGLE: default: if (strlen(fb_name) == 0) - goto error; + return -1; break; } cd = SCMalloc(sizeof(DetectXbitsData)); if (unlikely(cd == NULL)) - goto error; + return -1; cd->idx = VariableNameGetIdx(de_ctx, fb_name, var_type); cd->cmd = fb_cmd; @@ -296,6 +313,24 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); + *cdout = cd; + return 0; +} + +int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +{ + SigMatch *sm = NULL; + DetectXbitsData *cd = NULL; + + int result = DetectXbitParse(de_ctx, rawstr, &cd); + if (result < 0) { + return -1; + /* noalert doesn't use a cd/sm struct. It flags the sig. We're done. */ + } else if (result == 0 && cd == NULL) { + s->flags |= SIG_FLAG_NOALERT; + return 0; + } + /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ sm = SigMatchAlloc(); @@ -305,7 +340,7 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) sm->type = DETECT_XBITS; sm->ctx = (void *)cd; - switch (fb_cmd) { + switch (cd->cmd) { /* case DETECT_XBITS_CMD_NOALERT can't happen here */ case DETECT_XBITS_CMD_ISNOTSET: @@ -327,8 +362,6 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) error: if (cd != NULL) SCFree(cd); - if (sm != NULL) - SCFree(sm); return -1; } @@ -361,11 +394,59 @@ static void XBitsTestShutdown(void) StorageCleanup(); } + +static int XBitsTestParse01(void) +{ + DetectEngineCtx *de_ctx = NULL; + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + DetectXbitsData *cd = NULL; + +#define BAD_INPUT(str) \ + FAIL_IF_NOT(DetectXbitParse(de_ctx, (str), &cd) == -1); + + BAD_INPUT("alert"); + BAD_INPUT("n0alert"); + BAD_INPUT("nOalert"); + BAD_INPUT("set,abc,track nonsense, expire 3600"); + BAD_INPUT("set,abc,track ip_source, expire 3600"); + BAD_INPUT("set,abc,track ip_src, expire -1"); + BAD_INPUT("set,abc,track ip_src, expire 0"); + +#undef BAD_INPUT + +#define GOOD_INPUT(str, command, trk, typ, exp) \ + FAIL_IF_NOT(DetectXbitParse(de_ctx, (str), &cd) == 0); \ + FAIL_IF_NULL(cd); \ + FAIL_IF_NOT(cd->cmd == (command)); \ + FAIL_IF_NOT(cd->tracker == (trk)); \ + FAIL_IF_NOT(cd->type == (typ)); \ + FAIL_IF_NOT(cd->expire == (exp)); \ + DetectXbitFree(cd); \ + cd = NULL; + + GOOD_INPUT("set,abc,track ip_pair", + DETECT_XBITS_CMD_SET, + DETECT_XBITS_TRACK_IPPAIR, VAR_TYPE_IPPAIR_BIT, + DETECT_XBITS_EXPIRE_DEFAULT); + GOOD_INPUT("set,abc,track ip_pair, expire 3600", + DETECT_XBITS_CMD_SET, + DETECT_XBITS_TRACK_IPPAIR, VAR_TYPE_IPPAIR_BIT, + 3600); + GOOD_INPUT("set,abc,track ip_src, expire 1234", + DETECT_XBITS_CMD_SET, + DETECT_XBITS_TRACK_IPSRC, VAR_TYPE_HOST_BIT, + 1234); + +#undef GOOD_INPUT + + DetectEngineCtxFree(de_ctx); + PASS; +} + /** - * \test HostBitsTestSig01 is a test for a valid noalert flowbits option - * - * \retval 1 on succces - * \retval 0 on failure + * \test */ static int XBitsTestSig01(void) @@ -376,13 +457,11 @@ static int XBitsTestSig01(void) "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); @@ -395,46 +474,23 @@ static int XBitsTestSig01(void) XBitsTestSetup(); de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - printf("bad de_ctx: "); - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (xbits:set,abc,track ip_pair; content:\"GET \"; sid:1;)"); - if (s == NULL) { - printf("bad sig: "); - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); XBitsTestShutdown(); - SCFree(p); - return result; + StatsThreadCleanup(&th_v); + StatsReleaseResources(); + PASS; } /** @@ -447,67 +503,33 @@ static int XBitsTestSig01(void) static int XBitsTestSig02(void) { Signature *s = NULL; - ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; - int result = 0; - int error_count = 0; - - memset(&th_v, 0, sizeof(th_v)); - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (xbits:isset,abc,track ip_src; content:\"GET \"; sid:1;)"); - if (s == NULL) { - error_count++; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (xbits:isnotset,abc,track ip_dst; content:\"GET \"; sid:2;)"); - if (s == NULL) { - error_count++; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (xbits:set,abc,track ip_pair; content:\"GET \"; sid:3;)"); - if (s == NULL) { - error_count++; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (xbits:unset,abc,track ip_src; content:\"GET \"; sid:4;)"); - if (s == NULL) { - error_count++; - } + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (xbits:toggle,abc,track ip_dst; content:\"GET \"; sid:5;)"); - if (s == NULL) { - error_count++; - } + FAIL_IF_NULL(s); - if (error_count != 0) - goto end; - - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - } - - return result; + PASS; } #endif /* UNITTESTS */ @@ -518,6 +540,7 @@ static int XBitsTestSig02(void) void XBitsRegisterTests(void) { #ifdef UNITTESTS + UtRegisterTest("XBitsTestParse01", XBitsTestParse01); UtRegisterTest("XBitsTestSig01", XBitsTestSig01); UtRegisterTest("XBitsTestSig02", XBitsTestSig02); #endif /* UNITTESTS */ diff --git a/src/detect-xbits.h b/src/detect-xbits.h index 477aab8c2bda..6794af2d9c56 100644 --- a/src/detect-xbits.h +++ b/src/detect-xbits.h @@ -37,6 +37,8 @@ #define DETECT_XBITS_TRACK_IPPAIR 2 #define DETECT_XBITS_TRACK_FLOW 3 +#define DETECT_XBITS_EXPIRE_DEFAULT 30 + typedef struct DetectXbitsData_ { uint16_t idx; uint8_t cmd; From bc38cd593224405c1bb55284524533200b6a944f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 14 Oct 2016 17:29:54 +0200 Subject: [PATCH 2243/2553] doc: initial xbits documentation --- doc/userguide/rules/index.rst | 1 + doc/userguide/rules/xbits.rst | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 doc/userguide/rules/xbits.rst diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst index 1818572aca10..115458da101a 100644 --- a/doc/userguide/rules/index.rst +++ b/doc/userguide/rules/index.rst @@ -11,6 +11,7 @@ Suricata Rules http-keywords flow-keywords flowint + xbits file-keywords thresholding dns-keywords diff --git a/doc/userguide/rules/xbits.rst b/doc/userguide/rules/xbits.rst new file mode 100644 index 000000000000..026e3831813f --- /dev/null +++ b/doc/userguide/rules/xbits.rst @@ -0,0 +1,48 @@ +Xbits +===== + +Set, unset, toggle and check for bits stored per host or ip_pair. + +Syntax:: + + xbits:noalert; + xbits:,,track ; + xbits:,,track \ + [,expire ]; + xbits:,,track \ + [,expire ]; + +YAML settings +------------- + +Bits that are stored per host are stored in the Host table. + +Bits that are stored per IP pair are stored in the IPPair table. + +Threading +--------- + +Due to subtle timing issues between threads the order of sets and checks +can be slightly unpredictible. + +Example: create a SSH blacklist +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Below is an example of rules incoming to a SSH server. + +The first 2 rules match on a SSH software version often used in bots. +They drop the traffic and create an 'xbit' 'badssh' for the source ip. +It expires in an hour:: + + drop ssh any any -> $MYSERVER 22 (msg:"DROP libssh incoming"; \ + flow:to_server,established; ssh.softwareversion:"libssh"; \ + xbits:set, badssh, track ip_src, expire 3600; sid:4000000005;) + drop ssh any any -> $MYSERVER 22 (msg:"DROP PUTTY incoming"; \ + flow:to_server,established; ssh.softwareversion:"PUTTY"; \ + xbits:set, badssh, track ip_src, expire 3600; sid:4000000007;) + +Then the following rule simply drops any incoming traffic to that server +that is on that 'badssh' list:: + + drop ssh any any -> $MYSERVER 22 (msg:"DROP BLACKLISTED"; \ + xbits:isset, badssh, track ip_src; sid:4000000006;) From 63a3b8412753c78414ef28a8f0d3cdb6670dfcee Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 20 Dec 2016 10:43:07 +0100 Subject: [PATCH 2244/2553] util-magic: fix build when magic is not available If HAVE_MAGIC is not defined then we don't have the test functions so we can't register them. --- src/util-magic.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util-magic.c b/src/util-magic.c index e0f08a2ac214..96af56e17103 100644 --- a/src/util-magic.c +++ b/src/util-magic.c @@ -659,6 +659,7 @@ static int MagicDetectTest10ValgrindError(void) void MagicRegisterTests(void) { +#ifdef HAVE_MAGIC #ifdef UNITTESTS UtRegisterTest("MagicInitTest01", MagicInitTest01); UtRegisterTest("MagicInitTest02", MagicInitTest02); @@ -676,4 +677,6 @@ void MagicRegisterTests(void) UtRegisterTest("MagicDetectTest10ValgrindError", MagicDetectTest10ValgrindError); #endif /* UNITTESTS */ +#endif /* HAVE_MAGIC */ } + From 8c65d45d55cc4945346f98dd3417ef2fbd2943ca Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 14 Dec 2016 14:24:44 +0100 Subject: [PATCH 2245/2553] detect: remove dead code --- src/detect-engine-siggroup.c | 47 ------------------------------------ 1 file changed, 47 deletions(-) diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 276f204983d1..28996a5e91c1 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -321,17 +321,6 @@ void SigGroupHeadHashFree(DetectEngineCtx *de_ctx) return; } -static uint16_t SignatureGetMpmPatternLen(const Signature *s, const int list) -{ - if (s->sm_lists[list] != NULL && s->mpm_sm != NULL && - SigMatchListSMBelongsTo(s, s->mpm_sm) == list) - { - DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; - return cd->content_len; - } - return 0; -} - /** * \brief Add a Signature to a SigGroupHead. * @@ -554,42 +543,6 @@ void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return; } -/** - * \brief Get size of the shortest mpm pattern. - * - * \param de_ctx detection engine ctx for the signatures - * \param sgh sig group head to set the flag in - * \param list sm_list to consider - */ -uint16_t SigGroupHeadGetMinMpmSize(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, int list) -{ - Signature *s = NULL; - uint32_t sig = 0; - uint16_t min = USHRT_MAX; - - if (sgh == NULL) - return 0; - - for (sig = 0; sig < sgh->sig_cnt; sig++) { - s = sgh->match_array[sig]; - if (s == NULL) - continue; - - uint16_t mpm_content_minlen = SignatureGetMpmPatternLen(s, DETECT_SM_LIST_PMATCH); - if (mpm_content_minlen > 0) { - if (mpm_content_minlen < min) - min = mpm_content_minlen; - SCLogDebug("mpm_content_minlen %u", mpm_content_minlen); - } - } - - if (min == USHRT_MAX) - min = 0; - SCLogDebug("min mpm size %u", min); - return min; -} - /** * \brief Set the need size flag in the sgh. * From df28c1ac6eb318c6ccb29062052e4c99f84217e4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Dec 2016 16:17:33 +0100 Subject: [PATCH 2246/2553] common: add WARN_UNUSED macro --- src/suricata-common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/suricata-common.h b/src/suricata-common.h index 4ac5275fb130..ef14825cecba 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -317,6 +317,8 @@ #define BIT_U32(n) (1UL << (n)) #define BIT_U64(n) (1ULL << (n)) +#define WARN_UNUSED __attribute__((warn_unused_result)) + typedef enum PacketProfileDetectId_ { PROF_DETECT_IPONLY, PROF_DETECT_RULES, From 2820ed332e4fa09e1e60e9733cdb3aeb3780893c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 22 Nov 2016 18:04:29 +0100 Subject: [PATCH 2247/2553] redis: use 'binary' notation for output --- src/util-logopenfile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index f35a7acdbb77..8eac7e1ee078 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -592,10 +592,10 @@ static int LogFileWriteRedis(LogFileCtx *file_ctx, const char *string, size_t s file_ctx->redis_setup.batch_count++; } } else { - redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s", + redisReply *reply = redisCommand(file_ctx->redis, "%s %s %b", file_ctx->redis_setup.command, file_ctx->redis_setup.key, - string); + string, string_len); /* We may lose the reply if disconnection happens! */ if (reply) { From 586774203f69131baad05bb57c5627b239e9a9d6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 22 Nov 2016 21:46:20 +0100 Subject: [PATCH 2248/2553] redis: support for all output types --- src/util-error.c | 1 + src/util-error.h | 1 + src/util-logopenfile.c | 9 +++++++++ 3 files changed, 11 insertions(+) diff --git a/src/util-error.c b/src/util-error.c index b7fc7b929371..105add555dc6 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -334,6 +334,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_DIR_OPEN); CASE_CODE(SC_WARN_REMOVE_FILE); CASE_CODE (SC_ERR_NO_MAGIC_SUPPORT); + CASE_CODE (SC_ERR_REDIS); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 2a825b18ba94..acaec8162567 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -324,6 +324,7 @@ typedef enum { SC_ERR_DIR_OPEN, SC_WARN_REMOVE_FILE, SC_ERR_NO_MAGIC_SUPPORT, + SC_ERR_REDIS, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 8eac7e1ee078..636aaab83f5d 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -280,6 +280,15 @@ SCConfLogOpenGeneric(ConfNode *conf, log_ctx->pcie_fp = SCLogOpenPcieFp(log_ctx, log_path, append); if (log_ctx->pcie_fp == NULL) return -1; // Error already logged by Open...Fp routine +#ifdef HAVE_LIBHIREDIS + } else if (strcasecmp(filetype, "redis") == 0) { + ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); + if (SCConfLogOpenRedis(redis_node, log_ctx) < 0) { + SCLogError(SC_ERR_REDIS, "failed to open redis output"); + return -1; + } + log_ctx->type = LOGFILE_TYPE_REDIS; +#endif } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "%s.filetype. Expected \"regular\" (default), \"unix_stream\", " From c35c18a7975e13412a19d76e4c907c15fd95951c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Dec 2016 14:50:58 -0600 Subject: [PATCH 2249/2553] app-layer: support to server and to client probing parsers When registering a probing parser allow to_server and to_client parsers to be registered. Previously the probing parser may be called for both directions which in some cases works OK, but in others can cause the to_client side to be detected as failed. --- src/app-layer-detect-proto.c | 110 +++++++++++++++++++---------------- src/app-layer-detect-proto.h | 6 +- src/app-layer-dnp3.c | 4 +- src/app-layer-dns-tcp.c | 6 +- src/app-layer-dns-udp.c | 7 ++- src/app-layer-enip.c | 16 ++--- src/app-layer-modbus.c | 4 +- src/app-layer-smb.c | 8 +-- src/app-layer-ssl.c | 4 +- src/app-layer-template.c | 6 +- 10 files changed, 91 insertions(+), 80 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 623a71b969aa..f861349045dd 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -75,8 +75,12 @@ typedef struct AppLayerProtoDetectProbingParserElement_ { uint32_t min_depth; /* the max length of data after which this parser won't be invoked */ uint32_t max_depth; - /* the probing parser function */ - ProbingParserFPtr ProbingParser; + + /* the to_server probing parser function */ + ProbingParserFPtr ProbingParserTs; + + /* the to_client probing parser function */ + ProbingParserFPtr ProbingParserTc; struct AppLayerProtoDetectProbingParserElement_ *next; } AppLayerProtoDetectProbingParserElement; @@ -395,14 +399,18 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, continue; } - alproto = pe->ProbingParser(buf, buflen, NULL); - if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) - goto end; - if (alproto == ALPROTO_FAILED || - (pe->max_depth != 0 && buflen > pe->max_depth)) { - alproto_masks[0] |= pe->alproto_mask; - } - pe = pe->next; + if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { + alproto = pe->ProbingParserTs(buf, buflen, NULL); + } else if (pe->ProbingParserTc != NULL) { + alproto = pe->ProbingParserTc(buf, buflen, NULL); + } + if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) + goto end; + if (alproto == ALPROTO_FAILED || + (pe->max_depth != 0 && buflen > pe->max_depth)) { + alproto_masks[0] |= pe->alproto_mask; + } + pe = pe->next; } pe = pe2; while (pe != NULL) { @@ -412,7 +420,7 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, continue; } - alproto = pe->ProbingParser(buf, buflen, NULL); + alproto = pe->ProbingParserTs(buf, buflen, NULL); if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) goto end; if (alproto == ALPROTO_FAILED || @@ -579,9 +587,7 @@ static AppLayerProtoDetectProbingParserElement * AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, uint16_t port, uint16_t min_depth, - uint16_t max_depth, - uint16_t (*AppLayerProtoDetectProbingParserFunc) - (uint8_t *input, uint32_t input_len, uint32_t *offset)) + uint16_t max_depth) { AppLayerProtoDetectProbingParserElement *pe = AppLayerProtoDetectProbingParserElementAlloc(); @@ -590,7 +596,6 @@ AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, pe->alproto_mask = AppLayerProtoDetectProbingParserGetMask(alproto); pe->min_depth = min_depth; pe->max_depth = max_depth; - pe->ProbingParser = AppLayerProtoDetectProbingParserFunc; pe->next = NULL; if (max_depth != 0 && min_depth >= max_depth) { @@ -603,11 +608,6 @@ AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, "the probing parser. Invalid alproto - %d", alproto); goto error; } - if (AppLayerProtoDetectProbingParserFunc == NULL) { - SCLogError(SC_ERR_ALPARSER, "Invalid arguments sent to " - "register the probing parser. Probing parser func NULL"); - goto error; - } SCReturnPtr(pe, "AppLayerProtoDetectProbingParserElement"); error: @@ -627,7 +627,8 @@ AppLayerProtoDetectProbingParserElementDuplicate(AppLayerProtoDetectProbingParse new_pe->alproto_mask = pe->alproto_mask; new_pe->min_depth = pe->min_depth; new_pe->max_depth = pe->max_depth; - new_pe->ProbingParser = pe->ProbingParser; + new_pe->ProbingParserTs = pe->ProbingParserTs; + new_pe->ProbingParserTc = pe->ProbingParserTc; new_pe->next = NULL; SCReturnPtr(new_pe, "AppLayerProtoDetectProbingParserElement"); @@ -860,7 +861,8 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, - ProbingParserFPtr ProbingParser) + ProbingParserFPtr ProbingParser1, + ProbingParserFPtr ProbingParser2) { SCEnter(); @@ -964,13 +966,14 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing AppLayerProtoDetectProbingParserElement *new_pe = AppLayerProtoDetectProbingParserElementCreate(alproto, curr_port->port, - min_depth, max_depth, - ProbingParser); + min_depth, max_depth); if (new_pe == NULL) goto error; curr_pe = new_pe; AppLayerProtoDetectProbingParserElement **head_pe; if (direction & STREAM_TOSERVER) { + curr_pe->ProbingParserTs = ProbingParser1; + curr_pe->ProbingParserTc = ProbingParser2; if (curr_port->dp == NULL) curr_port->dp_max_depth = new_pe->max_depth; if (new_pe->max_depth == 0) @@ -982,6 +985,8 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing curr_port->alproto_mask |= new_pe->alproto_mask; head_pe = &curr_port->dp; } else { + curr_pe->ProbingParserTs = ProbingParser2; + curr_pe->ProbingParserTc = ProbingParser1; if (curr_port->sp == NULL) curr_port->sp_max_depth = new_pe->max_depth; if (new_pe->max_depth == 0) @@ -1390,7 +1395,8 @@ void AppLayerProtoDetectPPRegister(uint8_t ipproto, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, - ProbingParserFPtr ProbingParser) + ProbingParserFPtr ProbingParser1, + ProbingParserFPtr ProbingParser2) { SCEnter(); @@ -1408,7 +1414,8 @@ void AppLayerProtoDetectPPRegister(uint8_t ipproto, alproto, min_depth, max_depth, direction, - ProbingParser); + ProbingParser1, + ProbingParser2); } temp_dp = temp_dp->next; } @@ -1422,7 +1429,8 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, - ProbingParserFPtr ProbingParser) + ProbingParserFPtr ProbingParserTs, + ProbingParserFPtr ProbingParserTc) { SCEnter(); @@ -1469,7 +1477,7 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, alproto, min_depth, max_depth, STREAM_TOSERVER, /* to indicate dp */ - ProbingParser); + ProbingParserTs, ProbingParserTc); } /* detect by source port of flow */ @@ -1483,7 +1491,7 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, alproto, min_depth, max_depth, STREAM_TOCLIENT, /* to indicate sp */ - ProbingParser); + ProbingParserTc, ProbingParserTs); } @@ -2980,57 +2988,57 @@ static int AppLayerProtoDetectTest15(void) ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_SMB, 5, 6, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_FTP, 7, 10, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_FTP, 7, 15, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_SMTP, 12, 0, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_TLS, 12, 18, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_FTP, 7, 15, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); result = 1; AppLayerProtoDetectPPRegister(IPPROTO_UDP, @@ -3038,7 +3046,7 @@ static int AppLayerProtoDetectTest15(void) ALPROTO_IMAP, 12, 23, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); /* toclient */ AppLayerProtoDetectPPRegister(IPPROTO_TCP, @@ -3046,74 +3054,74 @@ static int AppLayerProtoDetectTest15(void) ALPROTO_JABBER, 12, 23, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_IRC, 12, 14, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_DCERPC, 9, 10, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_FTP, 7, 15, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_TLS, 12, 18, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_HTTP, 5, 8, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_DCERPC, 9, 10, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "90", ALPROTO_FTP, 7, 15, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_SMB, 5, 6, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_UDP, "85", ALPROTO_IMAP, 12, 23, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_SMTP, 12, 17, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_FTP, 7, 10, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPTestDataElement element_ts_80[] = { { "http", ALPROTO_HTTP, 80, 1 << ALPROTO_HTTP, 5, 8 }, diff --git a/src/app-layer-detect-proto.h b/src/app-layer-detect-proto.h index 81b75fe392be..591ccbf5f843 100644 --- a/src/app-layer-detect-proto.h +++ b/src/app-layer-detect-proto.h @@ -65,7 +65,8 @@ void AppLayerProtoDetectPPRegister(uint8_t ipproto, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, - ProbingParserFPtr ProbingParser); + ProbingParserFPtr ProbingParser1, + ProbingParserFPtr ProbingParser2); /** * \retval bool 0 if no config was found, 1 if config was found */ @@ -74,7 +75,8 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, - ProbingParserFPtr ProbingParser); + ProbingParserFPtr ProbingParserTs, + ProbingParserFPtr ProbingParserTc); /***** PM registration *****/ diff --git a/src/app-layer-dnp3.c b/src/app-layer-dnp3.c index 3c84d544d302..31391adab9c9 100644 --- a/src/app-layer-dnp3.c +++ b/src/app-layer-dnp3.c @@ -1592,12 +1592,12 @@ void RegisterDNP3Parsers(void) if (RunmodeIsUnittests()) { AppLayerProtoDetectPPRegister(IPPROTO_TCP, DNP3_DEFAULT_PORT, ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), STREAM_TOSERVER, - DNP3ProbingParser); + DNP3ProbingParser, NULL); } else { if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), - DNP3ProbingParser)) { + DNP3ProbingParser, NULL)) { return; } } diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index d22ab923f54d..8ddae27a9504 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -641,12 +641,12 @@ void RegisterDNSTCPParsers(void) ALPROTO_DNS, 0, sizeof(DNSTcpHeader), STREAM_TOSERVER, - DNSTcpProbingParser); + DNSTcpProbingParser, NULL); } else { int have_cfg = AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_DNS, 0, sizeof(DNSTcpHeader), - DNSTcpProbingParser); + DNSTcpProbingParser, NULL); /* if we have no config, we enable the default port 53 */ if (!have_cfg) { SCLogWarning(SC_ERR_DNS_CONFIG, "no DNS TCP config found, " @@ -654,7 +654,7 @@ void RegisterDNSTCPParsers(void) "port 53."); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "53", ALPROTO_DNS, 0, sizeof(DNSTcpHeader), - STREAM_TOSERVER, DNSTcpProbingParser); + STREAM_TOSERVER, DNSTcpProbingParser, NULL); } } } else { diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index b34aacf42322..6a2523454d3b 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -395,12 +395,13 @@ void RegisterDNSUDPParsers(void) ALPROTO_DNS, 0, sizeof(DNSHeader), STREAM_TOSERVER, - DNSUdpProbingParser); + DNSUdpProbingParser, + NULL); } else { int have_cfg = AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, proto_name, ALPROTO_DNS, 0, sizeof(DNSHeader), - DNSUdpProbingParser); + DNSUdpProbingParser, NULL); /* if we have no config, we enable the default port 53 */ if (!have_cfg) { SCLogWarning(SC_ERR_DNS_CONFIG, "no DNS UDP config found, " @@ -408,7 +409,7 @@ void RegisterDNSUDPParsers(void) "port 53."); AppLayerProtoDetectPPRegister(IPPROTO_UDP, "53", ALPROTO_DNS, 0, sizeof(DNSHeader), - STREAM_TOSERVER, DNSUdpProbingParser); + STREAM_TOSERVER, DNSUdpProbingParser, NULL); } } } else { diff --git a/src/app-layer-enip.c b/src/app-layer-enip.c index 161d2550fdb9..05a63824ca7a 100644 --- a/src/app-layer-enip.c +++ b/src/app-layer-enip.c @@ -383,27 +383,27 @@ void RegisterENIPUDPParsers(void) if (RunmodeIsUnittests()) { AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, - 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser); + 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL); AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, - 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser); + 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL); } else { if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), - ENIPProbingParser)) + ENIPProbingParser, ENIPProbingParser)) { SCLogDebug( "no ENIP UDP config found enabling ENIP detection on port 44818."); AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, - ENIPProbingParser); + ENIPProbingParser, NULL); AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, - ENIPProbingParser); + ENIPProbingParser, NULL); } } @@ -471,16 +471,16 @@ void RegisterENIPTCPParsers(void) if (RunmodeIsUnittests()) { AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, - 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser); + 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, - 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser); + 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL); } else { if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), - ENIPProbingParser)) + ENIPProbingParser, ENIPProbingParser)) { return; } diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 630aff5755a5..f8c7a7c104a8 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1455,14 +1455,14 @@ void RegisterModbusParsers(void) ALPROTO_MODBUS, 0, sizeof(ModbusHeader), STREAM_TOSERVER, - ModbusProbingParser); + ModbusProbingParser, NULL); } else { /* If there is no app-layer section for Modbus, silently * leave it disabled. */ if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_MODBUS, 0, sizeof(ModbusHeader), - ModbusProbingParser)) { + ModbusProbingParser, NULL)) { #ifndef AFLFUZZ_APPLAYER return; #endif diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index bbf66dc2b44c..1c2c7063d7ef 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -1526,12 +1526,12 @@ void RegisterSMBParsers(void) ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, STREAM_TOSERVER, - SMBProbingParser); + SMBProbingParser, NULL); } else { AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, - SMBProbingParser); + SMBProbingParser, NULL); } AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_SMB, STREAM_TOSERVER); @@ -2217,7 +2217,7 @@ int SMBParserTest05(void) ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, STREAM_TOSERVER, - SMBProbingParser); + SMBProbingParser, NULL); AppLayerProtoDetectPrepareState(); alpd_tctx = AppLayerProtoDetectGetCtxThread(); @@ -2301,7 +2301,7 @@ int SMBParserTest06(void) ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, STREAM_TOSERVER, - SMBProbingParser); + SMBProbingParser, NULL); AppLayerProtoDetectPrepareState(); alpd_tctx = AppLayerProtoDetectGetCtxThread(); diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 6483f224d603..0d2c25b3480a 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -1766,12 +1766,12 @@ void RegisterSSLParsers(void) ALPROTO_TLS, 0, 3, STREAM_TOSERVER, - SSLProbingParser); + SSLProbingParser, NULL); } else { AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_TLS, 0, 3, - SSLProbingParser); + SSLProbingParser, NULL); } } else { SCLogInfo("Protocol detection and parser disabled for %s protocol", diff --git a/src/app-layer-template.c b/src/app-layer-template.c index a454b119bf89..fd5bc7cc88c8 100644 --- a/src/app-layer-template.c +++ b/src/app-layer-template.c @@ -472,21 +472,21 @@ void RegisterTemplateParsers(void) SCLogNotice("Unittest mode, registeringd default configuration."); AppLayerProtoDetectPPRegister(IPPROTO_TCP, TEMPLATE_DEFAULT_PORT, ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER, - TemplateProbingParser); + TemplateProbingParser, NULL); } else { if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, - TemplateProbingParser)) { + TemplateProbingParser, NULL)) { SCLogNotice("No echo app-layer configuration, enabling echo" " detection TCP detection on port %s.", TEMPLATE_DEFAULT_PORT); AppLayerProtoDetectPPRegister(IPPROTO_TCP, TEMPLATE_DEFAULT_PORT, ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER, - TemplateProbingParser); + TemplateProbingParser, NULL); } } From bcdbd12839859910c7876104fcdd15abd4e84175 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Dec 2016 15:37:33 -0600 Subject: [PATCH 2250/2553] dns (tcp): register a to_client (response) probing parser Just a minimal parser to make sure the data contains at least a header. --- src/app-layer-dns-tcp.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 8ddae27a9504..b27d8d87e9a9 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -627,6 +627,28 @@ static uint16_t DNSTcpProbingParser(uint8_t *input, uint32_t ilen, uint32_t *off return ALPROTO_DNS; } +/** + * \brief Probing parser for TCP DNS responses. + * + * This is a minimal parser that just checks that the input contains enough + * data for a TCP DNS response. + */ +static uint16_t DNSTcpProbeResponse(uint8_t *input, uint32_t len, + uint32_t *offset) +{ + if (len == 0 || len < sizeof(DNSTcpHeader)) { + return ALPROTO_UNKNOWN; + } + + DNSTcpHeader *dns_header = (DNSTcpHeader *)input; + + if (ntohs(dns_header->len) < sizeof(DNSHeader)) { + return ALPROTO_FAILED; + } + + return ALPROTO_DNS; +} + void RegisterDNSTCPParsers(void) { char *proto_name = "dns"; @@ -646,7 +668,8 @@ void RegisterDNSTCPParsers(void) int have_cfg = AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_DNS, 0, sizeof(DNSTcpHeader), - DNSTcpProbingParser, NULL); + DNSTcpProbingParser, + DNSTcpProbeResponse); /* if we have no config, we enable the default port 53 */ if (!have_cfg) { SCLogWarning(SC_ERR_DNS_CONFIG, "no DNS TCP config found, " @@ -654,7 +677,8 @@ void RegisterDNSTCPParsers(void) "port 53."); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "53", ALPROTO_DNS, 0, sizeof(DNSTcpHeader), - STREAM_TOSERVER, DNSTcpProbingParser, NULL); + STREAM_TOSERVER, DNSTcpProbingParser, + DNSTcpProbeResponse); } } } else { From 98e8b13bf085ee7aed42cf938de07e6f3c4bccbe Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Fri, 13 Jan 2017 23:44:57 +0100 Subject: [PATCH 2251/2553] decode-icmpv6: add missing types There have been some ICMPv6 types missing within the DecodeICMPV6 that are added by this commit and the code check is adjusted to always use the DEFINE. --- src/decode-icmpv6.c | 141 +++++++++++++++++++++++++++++++++++++++++--- src/decode-icmpv6.h | 23 ++++++++ 2 files changed, 155 insertions(+), 9 deletions(-) diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index fc82d5949353..dc01d121c15b 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -254,7 +254,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, SCLogDebug("ICMP6_ECHO_REPLY id: %u seq: %u", p->icmpv6h->icmpv6b.icmpv6i.id, p->icmpv6h->icmpv6b.icmpv6i.seq); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { p->icmpv6vars.id = p->icmpv6h->icmpv6b.icmpv6i.id; @@ -265,37 +265,37 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, break; case ND_ROUTER_SOLICIT: SCLogDebug("ND_ROUTER_SOLICIT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; case ND_ROUTER_ADVERT: SCLogDebug("ND_ROUTER_ADVERT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; case ND_NEIGHBOR_SOLICIT: SCLogDebug("ND_NEIGHBOR_SOLICIT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; case ND_NEIGHBOR_ADVERT: SCLogDebug("ND_NEIGHBOR_ADVERT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; case ND_REDIRECT: SCLogDebug("ND_REDIRECT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; case MLD_LISTENER_QUERY: SCLogDebug("MLD_LISTENER_QUERY"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } if (IPV6_GET_HLIM(p) != 1) { @@ -304,7 +304,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, break; case MLD_LISTENER_REPORT: SCLogDebug("MLD_LISTENER_REPORT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } if (IPV6_GET_HLIM(p) != 1) { @@ -313,13 +313,136 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, break; case MLD_LISTENER_REDUCTION: SCLogDebug("MLD_LISTENER_REDUCTION"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } if (IPV6_GET_HLIM(p) != 1) { ENGINE_SET_EVENT(p, ICMPV6_MLD_MESSAGE_WITH_INVALID_HL); } break; + case ICMP6_RR: + SCLogDebug("ICMP6_RR"); + if (ICMPV6_GET_CODE(p) > 2 && ICMPV6_GET_CODE(p) != 255) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case ICMP6_NI_QUERY: + SCLogDebug("ICMP6_NI_QUERY"); + if (ICMPV6_GET_CODE(p) > 2) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case ICMP6_NI_REPLY: + SCLogDebug("ICMP6_NI_REPLY"); + if (ICMPV6_GET_CODE(p) > 2) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case ND_INVERSE_SOLICIT: + SCLogDebug("ND_INVERSE_SOLICIT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case ND_INVERSE_ADVERT: + SCLogDebug("ND_INVERSE_ADVERT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case MLD_V2_LIST_REPORT: + SCLogDebug("MLD_V2_LIST_REPORT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case HOME_AGENT_AD_REQUEST: + SCLogDebug("HOME_AGENT_AD_REQUEST"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case HOME_AGENT_AD_REPLY: + SCLogDebug("HOME_AGENT_AD_REPLY"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case MOBILE_PREFIX_SOLICIT: + SCLogDebug("MOBILE_PREFIX_SOLICIT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case MOBILE_PREFIX_ADVERT: + SCLogDebug("MOBILE_PREFIX_ADVERT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case CERT_PATH_SOLICIT: + SCLogDebug("CERT_PATH_SOLICIT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case CERT_PATH_ADVERT: + SCLogDebug("CERT_PATH_ADVERT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case ICMP6_MOBILE_EXPERIMENTAL: + SCLogDebug("ICMP6_MOBILE_EXPERIMENTAL"); + break; + case MC_ROUTER_ADVERT: + SCLogDebug("MC_ROUTER_ADVERT"); + break; + case MC_ROUTER_SOLICIT: + SCLogDebug("MC_ROUTER_SOLICIT"); + break; + case MC_ROUTER_TERMINATE: + SCLogDebug("MC_ROUTER_TERMINATE"); + break; + case FMIPV6_MSG: + SCLogDebug("FMIPV6_MSG"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case RPL_CONTROL_MSG: + SCLogDebug("RPL_CONTROL_MSG"); + if (ICMPV6_GET_CODE(p) > 3 && ICMPV6_GET_CODE(p) < 128) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + if (ICMPV6_GET_CODE(p) > 132) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case LOCATOR_UDATE_MSG: + SCLogDebug("LOCATOR_UDATE_MSG"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case DUPL_ADDR_REQUEST: + SCLogDebug("DUPL_ADDR_REQUEST"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case DUPL_ADDR_CONFIRM: + SCLogDebug("DUPL_ADDR_CONFIRM"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case MPL_CONTROL_MSG: + SCLogDebug("MPL_CONTROL_MSG"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; default: /* Various range taken from: * http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-2 diff --git a/src/decode-icmpv6.h b/src/decode-icmpv6.h index 187b158bfcdb..eb0b0fd691c8 100644 --- a/src/decode-icmpv6.h +++ b/src/decode-icmpv6.h @@ -53,6 +53,29 @@ #define ND_NEIGHBOR_ADVERT 136 #define ND_REDIRECT 137 +#define ICMP6_RR 138 +#define ICMP6_NI_QUERY 139 +#define ICMP6_NI_REPLY 140 +#define ND_INVERSE_SOLICIT 141 +#define ND_INVERSE_ADVERT 142 +#define MLD_V2_LIST_REPORT 143 +#define HOME_AGENT_AD_REQUEST 144 +#define HOME_AGENT_AD_REPLY 145 +#define MOBILE_PREFIX_SOLICIT 146 +#define MOBILE_PREFIX_ADVERT 147 +#define CERT_PATH_SOLICIT 148 +#define CERT_PATH_ADVERT 149 +#define ICMP6_MOBILE_EXPERIMENTAL 150 +#define MC_ROUTER_ADVERT 151 +#define MC_ROUTER_SOLICIT 152 +#define MC_ROUTER_TERMINATE 153 +#define FMIPV6_MSG 154 +#define RPL_CONTROL_MSG 155 +#define LOCATOR_UDATE_MSG 156 +#define DUPL_ADDR_REQUEST 157 +#define DUPL_ADDR_CONFIRM 158 +#define MPL_CONTROL_MSG 159 + /** Destination Unreachable Message (type=1) Code: */ #define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ From fe4e119278a09185076fa25f22f7ad6ed5d0c3ea Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 16 Jan 2017 16:00:25 +0100 Subject: [PATCH 2252/2553] common: improve BUG_ON When BUG_ON is a wrapper for assert(), we risk getting rid of certain code lines. Assert is a no-op when NDEBUG is defined. This patch defines an alternate path for BUG_ON that exits after printing an error. Bug #2003. --- src/suricata-common.h | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/suricata-common.h b/src/suricata-common.h index ef14825cecba..7fbe4f31f20c 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -229,22 +229,28 @@ #include #endif -#if CPPCHECK==1 -#define BUG_ON(x) if (((x))) exit(1) -#else -#ifdef HAVE_ASSERT_H -#include -#define BUG_ON(x) assert(!(x)) -#else -#define BUG_ON(x) -#endif -#endif - /* we need this to stringify the defines which are supplied at compiletime see: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/cpp/Stringification.html#Stringification */ #define xstr(s) str(s) #define str(s) #s +#if CPPCHECK==1 + #define BUG_ON(x) if (((x))) exit(1) +#else + #if defined HAVE_ASSERT_H && !defined NDEBUG + #include + #define BUG_ON(x) assert(!(x)) + #else + #define BUG_ON(x) do { \ + if (((x))) { \ + fprintf(stderr, "BUG at %s:%d(%s)\n", __FILE__, __LINE__, __func__); \ + fprintf(stderr, "Code: '%s'\n", xstr((x))); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + #endif +#endif + /** type for the internal signature id. Since it's used in the matching engine * extensively keeping this as small as possible reduces the overall memory * footprint of the engine. Set to uint32_t if the engine needs to support From b0de5ad1a848e75ee4c3245c124ccef2343fde7e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 9 Jan 2017 15:13:16 -0600 Subject: [PATCH 2253/2553] dns: increment tx id when allocated during response --- src/app-layer-dns-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 165bc52721f1..3eb507adbf28 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -605,6 +605,7 @@ void DNSStoreAnswerInState(DNSState *dns_state, const int rtype, const uint8_t * return; TAILQ_INSERT_TAIL(&dns_state->tx_list, tx, next); dns_state->curr = tx; + dns_state->transaction_max++; tx->tx_num = dns_state->transaction_max; } From 5b1de57d732f1c938cd3b781059d79ca974f2e0c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 10 Jan 2017 14:46:48 -0800 Subject: [PATCH 2254/2553] detect-parse: simplify port prefiltering Regular expression was not matching some authorized setting like "![1234, 1235]". This patch simplify the regexp to match on possible character and let the port parsing code handle the complete verification. --- src/detect-parse.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/detect-parse.c b/src/detect-parse.c index 1af519b090bd..7307d974be7b 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -104,11 +104,7 @@ typedef struct SigDuplWrapper_ { ")" /* if enclosed in [], spaces are allowed */ -#define CONFIG_PCRE_PORT "(" \ - "[\\:A-z0-9_\\$\\!,]+"\ - "|"\ - "\\[[\\:A-z0-9_\\$\\!,\\s]+\\]"\ - ")" +#define CONFIG_PCRE_PORT "([\\[\\]\\:A-z0-9_\\$\\!,\\s]+)" /* format: action space(s) protocol spaces(s) src space(s) sp spaces(s) dir spaces(s) dst spaces(s) dp spaces(s) options */ #define CONFIG_PCRE "^([A-z]+)\\s+([A-z0-9\\-]+)\\s+" \ From dfbfb50f6409a4c380f233706402ded243155392 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 16 Jan 2017 10:31:01 -0600 Subject: [PATCH 2255/2553] dns (tcp) - fix coverity cid 1374307 CID 1374307 (#1 of 1): Dereference before null check (REVERSE_INULL) check_after_deref: Null-checking dns_state suggests that it may be null, but it has already been dereferenced on all paths leading to the check. 317 if (dns_state != NULL && f != NULL) { 318 dns_state->last_resp = f->lastts; 319 } --- src/app-layer-dns-udp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index 6a2523454d3b..d8ee37d30f34 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -314,7 +314,7 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, tx->replied = 1; } - if (dns_state != NULL && f != NULL) { + if (f != NULL) { dns_state->last_resp = f->lastts; } SCReturnInt(1); From a10a9220cf8f9072b6c3ad771525a333ab990f8c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 16 Jan 2017 10:34:19 -0600 Subject: [PATCH 2256/2553] dns (tcp) - fix coverity CIDs 1374306, 1374305 CID 1374306 (#1 of 1): Dereference before null check (REVERSE_INULL) check_after_deref: Null-checking dns_state suggests that it may be null, but it has already been dereferenced on all paths leading to the check. 585 if (dns_state != NULL && f != NULL) { 586 dns_state->last_req = f->lastts; 587 } CID 1374305 (#1 of 1): Dereference before null check (REVERSE_INULL) check_after_deref: Null-checking dns_state suggests that it may be null, but it has already been dereferenced on all paths leading to the check. 366 if (dns_state != NULL && f != NULL) { 367 dns_state->last_req = f->lastts; 368 } --- src/app-layer-dns-tcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index b27d8d87e9a9..4296a49c15f5 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -363,7 +363,7 @@ static int DNSTCPRequestParse(Flow *f, void *dstate, goto bad_data; } - if (dns_state != NULL && f != NULL) { + if (f != NULL) { dns_state->last_req = f->lastts; } @@ -582,7 +582,7 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, goto bad_data; } - if (dns_state != NULL && f != NULL) { + if (f != NULL) { dns_state->last_req = f->lastts; } From d09cd16c8c0be79c02422ffc86297709e150421a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 16 Jan 2017 10:38:08 -0600 Subject: [PATCH 2257/2553] template logger - fix coverity CID 1324964 null: At condition templatejs != NULL, the value of templatejs must be NULL. dead_error_condition: The condition templatejs != NULL cannot be true. 113 if (templatejs != NULL) { CID 1324964 (#1 of 1): Logically dead code (DEADCODE) dead_error_line: Execution cannot reach this statement: json_decref(templatejs);. 114 json_decref(templatejs); 115 } --- src/output-json-template.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/output-json-template.c b/src/output-json-template.c index fcbee919b9c7..3747121f584f 100644 --- a/src/output-json-template.c +++ b/src/output-json-template.c @@ -110,9 +110,6 @@ static int JsonTemplateLogger(ThreadVars *tv, void *thread_data, return TM_ECODE_OK; error: - if (templatejs != NULL) { - json_decref(templatejs); - } json_decref(js); return TM_ECODE_FAILED; } From 87b5bf9541acc5bb3b64bf667a31b90f9fd6e075 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 16 Jan 2017 10:44:19 -0600 Subject: [PATCH 2258/2553] proto detect - fix coverity CID 1204325 CID 1204325 (#1 of 1): Logically dead code (DEADCODE) dead_error_line: Execution cannot reach this statement: mask = 0U;. 433 mask = 0; additionally, mask is initialized to 0 --- src/app-layer-detect-proto.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index f861349045dd..c82cc8d0d978 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -437,8 +437,6 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, mask = pp_port_dp->alproto_mask; else if (pp_port_sp) mask = pp_port_sp->alproto_mask; - else - mask = 0; if (alproto_masks[0] == mask) { FLOW_SET_PP_DONE(f, direction); From 03ad9d4ec01c9915dea60787147ecad56d7536c9 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 22 Dec 2016 08:38:46 +0100 Subject: [PATCH 2259/2553] tls-store: fix bug that causes Suricata to crash Fix bug that causes Suricata to crash when the tls.store keyword is used. *** Error in `/usr/bin/suricata': free(): invalid next size (fast): 0x00007fd4b4373180 *** --- src/log-tlsstore.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c index 6648f592aa48..861a2da69aef 100644 --- a/src/log-tlsstore.c +++ b/src/log-tlsstore.c @@ -166,7 +166,6 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s goto end_fwrite_fp; } fclose(fp); - SCFree(aft->enc_buf); //Logging certificate informations memcpy(filename + (strlen(filename) - 3), "meta", 4); @@ -223,7 +222,6 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s end_fwrite_fp: fclose(fp); - SCFree(aft->enc_buf); if (logging_dir_not_writable < LOGGING_WRITE_ISSUE_LIMIT) { SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate"); logging_dir_not_writable++; @@ -338,6 +336,9 @@ static TmEcode LogTlsStoreLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } + if (aft->enc_buf != NULL) + SCFree(aft->enc_buf); + /* clear memory */ memset(aft, 0, sizeof(LogTlsStoreLogThread)); From f08cc1f3db1cae44274c15855d1e4fce6141ff31 Mon Sep 17 00:00:00 2001 From: Travis Green Date: Wed, 21 Dec 2016 08:56:15 -0700 Subject: [PATCH 2260/2553] yaml: update commented rule files Disabled scada.rules, added commented rule file names to help administrators find informational rule files. --- suricata.yaml.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index e701c335c691..d4d813ee5703 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -50,6 +50,7 @@ vars: default-rule-path: @e_sysconfdir@rules rule-files: - botcc.rules + # - botcc.portgrouped.rules - ciarmy.rules - compromised.rules - drop.rules @@ -67,6 +68,7 @@ rule-files: # - emerging-icmp.rules - emerging-imap.rules # - emerging-inappropriate.rules +# - emerging-info.rules - emerging-malware.rules - emerging-misc.rules - emerging-mobile_malware.rules @@ -75,7 +77,8 @@ rule-files: - emerging-policy.rules - emerging-pop3.rules - emerging-rpc.rules - - emerging-scada.rules +# - emerging-scada.rules +# - emerging-scada_special.rules - emerging-scan.rules # - emerging-shellcode.rules - emerging-smtp.rules From bbc02205fb8c398f2d9890254c209e52aea831fd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 11 Jan 2017 14:34:41 +0100 Subject: [PATCH 2261/2553] queue: add debug assertions to TAILQ To avoid scan-build fp's add assertions that are only active if built with scan-build. --- src/queue.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/queue.h b/src/queue.h index 13455aa42905..5e2a7b1366f4 100644 --- a/src/queue.h +++ b/src/queue.h @@ -82,12 +82,18 @@ * For details on the use of these macros, see the queue(3) manual page. */ -#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#if defined(__clang_analyzer__) || defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) #define _Q_INVALIDATE(a) ((a) = ((void *)-1)) #else #define _Q_INVALIDATE(a) #endif +#if defined(__clang_analyzer__) +#define _Q_ASSERT(a) assert((a)) +#else +#define _Q_ASSERT(a) +#endif + /* * Singly-linked List definitions. */ @@ -377,9 +383,12 @@ struct { \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ + _Q_ASSERT((elm)); \ + _Q_ASSERT((head)); \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ + _Q_ASSERT(*(head)->tqh_last); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) @@ -407,6 +416,7 @@ struct { \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_ASSERT((head)->tqh_first != (elm)); \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) From 618ab4e177b054e9b8e227d8cf78f8b0a7454050 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 11 Jan 2017 14:55:13 +0100 Subject: [PATCH 2262/2553] ac-bs: fix scan-build warnings --- src/util-mpm-ac-bs.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 049a5776557f..56ccbc8cf8d8 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -719,7 +719,6 @@ static inline void SCACBSCreateModDeltaTable(MpmCtx *mpm_ctx) uint16_t *curr_loc = (uint16_t *)ctx->state_table_mod; uint16_t *no_of_entries = NULL; uint16_t *ascii_codes = NULL; - state = 0; uint16_t ascii_code = 0; uint16_t k = 0; for (state = 0; state < ctx->state_count; state++) { @@ -794,7 +793,6 @@ static inline void SCACBSCreateModDeltaTable(MpmCtx *mpm_ctx) uint32_t *curr_loc = (uint32_t *)ctx->state_table_mod; uint32_t *no_of_entries = NULL; uint32_t *ascii_codes = NULL; - state = 0; uint32_t ascii_code = 0; uint32_t k = 0; for (state = 0; state < ctx->state_count; state++) { @@ -1192,7 +1190,6 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, int low = 0; int high = no_of_entries; int mid; - state = 0; while (low <= high) { mid = (low + high) / 2; if (ascii_codes[mid] == buf_local) { @@ -1276,7 +1273,6 @@ uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, int low = 0; int high = no_of_entries; int mid; - state = 0; while (low <= high) { mid = (low + high) / 2; if (ascii_codes[mid] == buf_local) { From 709d20f8c62e03c308279004c1fa93a0ba007b72 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 11 Jan 2017 14:55:34 +0100 Subject: [PATCH 2263/2553] smb/dcerpc: suppress scan-build warnings --- src/app-layer-dcerpc.c | 26 ++++++++++++++++++++++++++ src/app-layer-smb.c | 3 +++ 2 files changed, 29 insertions(+) diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 5ba04d974930..407ed819f163 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -1553,7 +1553,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) (dcerpc->dcerpchdr.type == BIND) ? "BIND" : "ALTER_CONTEXT"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1579,7 +1581,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) //parsed -= input_len; SCLogDebug("Error Parsing CTX Item %u\n", parsed); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ dcerpc->dcerpcbindbindack.numctxitemsleft = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); @@ -1606,7 +1610,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1633,7 +1639,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) (dcerpc->dcerpchdr.type == BIND_ACK) ? "BIND_ACK" : "ALTER_CONTEXT_RESP"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1652,7 +1660,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else if (input_len) { SCLogDebug("Error parsing Secondary Address"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1679,7 +1689,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else if (input_len) { SCLogDebug("Error parsing DCERPC Padding"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1698,7 +1710,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else if (input_len) { SCLogDebug("Error parsing CTX Items"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1721,7 +1735,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else if (input_len) { SCLogDebug("Error parsing CTX Items"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ dcerpc->dcerpcbindbindack.numctxitemsleft = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); @@ -1759,7 +1775,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1783,8 +1801,10 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) SCLogDebug("Error parsing DCERPC %s", (dcerpc->dcerpchdr.type == REQUEST) ? "REQUEST" : "RESPONSE"); parsed = 0; + (void)parsed; /* for scan-build */ dcerpc->padleft = 0; input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1800,7 +1820,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else if (input_len) { SCLogDebug("Error parsing DCERPC Stub Data"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1842,7 +1864,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1875,7 +1899,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 1c2c7063d7ef..8e23f0e5dd67 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -678,6 +678,7 @@ static int32_t DataParser(void *smb_state, AppLayerParserState *pstate, sstate->bytesprocessed += parsed; sstate->bytecount.bytecountleft -= parsed; input_len -= parsed; + (void)input_len; /* for scan-build */ } } SCReturnInt(parsed); @@ -833,7 +834,9 @@ static uint32_t SMBParseByteCount(Flow *f, void *smb_state, sres = DataParser(sstate, pstate, input + parsed, input_len); if (sres != -1 && sres <= (int32_t)input_len) { parsed += (uint32_t)sres; + (void)parsed; /* for scan-build */ input_len -= (uint32_t)sres; + (void)input_len; /* for scan-build */ } else { /* Did not Validate as DCERPC over SMB */ while (sstate->bytecount.bytecountleft-- && input_len--) { SCLogDebug("0x%02x bytecount %"PRIu16"/%"PRIu16" input_len %"PRIu32, *p, From 61b72c6981fd578a00b2bf9e1c8a10f2b741e4b5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 11 Jan 2017 15:20:25 +0100 Subject: [PATCH 2264/2553] output: clean up output function Don't allocate memory per call. --- src/util-debug.c | 68 +++++++++++++++++------------------------------- 1 file changed, 24 insertions(+), 44 deletions(-) diff --git a/src/util-debug.c b/src/util-debug.c index 0bf067c863dd..1a0f19341e1b 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -300,29 +300,19 @@ static SCError SCLogMessageGetBuffer( blue = "\x1b[34m"; reset = "\x1b[0m"; } - /* no of characters_written(cw) by snprintf */ int cw = 0; - if (sc_log_module_initialized != 1) { -#ifdef DEBUG - printf("Logging module not initialized. Call SCLogInitLogModule(), " - "before using the logging API\n"); -#endif - return SC_ERR_LOG_MODULE_NOT_INIT; - } + BUG_ON(sc_log_module_initialized != 1); - char *temp_fmt = strdup(log_format); - if (unlikely(temp_fmt == NULL)) { - return SC_ERR_MEM_ALLOC; - } - char *temp_fmt_h = temp_fmt; + /* make a copy of the format string as it will be modified below */ + char local_format[strlen(log_format) + 1]; + strlcpy(local_format, log_format, sizeof(local_format)); + char *temp_fmt = local_format; char *substr = temp_fmt; while ( (temp_fmt = index(temp_fmt, SC_LOG_FMT_PREFIX)) ) { if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { - if (temp_fmt_h != NULL) - SCFree(temp_fmt_h); return SC_OK; } switch(temp_fmt[1]) { @@ -338,7 +328,7 @@ static SCError SCLogMessageGetBuffer( tms->tm_year + 1900, tms->tm_hour, tms->tm_min, tms->tm_sec, reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -350,7 +340,7 @@ static SCError SCLogMessageGetBuffer( cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%u%s", substr, yellow, getpid(), reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -362,12 +352,13 @@ static SCError SCLogMessageGetBuffer( cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%lu%s", substr, yellow, SCGetThreadIdLong(), reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; substr++; break; + case SC_LOG_FMT_TM: temp_fmt[0] = '\0'; /* disabled to prevent dead lock: @@ -382,12 +373,13 @@ static SCError SCLogMessageGetBuffer( cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, "N/A"); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; substr++; break; + case SC_LOG_FMT_LOG_LEVEL: temp_fmt[0] = '\0'; s = SCMapEnumValueToName(log_level, sc_log_level_map); @@ -409,7 +401,7 @@ static SCError SCLogMessageGetBuffer( "%s%s", substr, "INVALID"); } if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -421,7 +413,7 @@ static SCError SCLogMessageGetBuffer( cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr, blue, file, reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -433,7 +425,7 @@ static SCError SCLogMessageGetBuffer( cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%u%s", substr, green, line, reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -445,7 +437,7 @@ static SCError SCLogMessageGetBuffer( cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr, green, function, reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -456,29 +448,25 @@ static SCError SCLogMessageGetBuffer( temp_fmt++; } if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { - if (temp_fmt_h != NULL) - SCFree(temp_fmt_h); return SC_OK; } cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr); - if (cw < 0) - goto error; + if (cw < 0) { + return SC_ERR_SPRINTF; + } temp += cw; if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { - if (temp_fmt_h != NULL) - SCFree(temp_fmt_h); return SC_OK; } if (error_code != SC_OK) { cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "[%sERRCODE%s: %s%s%s(%s%d%s)] - ", yellow, reset, red, SCErrorToString(error_code), reset, yellow, error_code, reset); - if (cw < 0) - goto error; + if (cw < 0) { + return SC_ERR_SPRINTF; + } temp += cw; if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { - if (temp_fmt_h != NULL) - SCFree(temp_fmt_h); return SC_OK; } } @@ -489,17 +477,14 @@ static SCError SCLogMessageGetBuffer( else if (log_level <= SC_LOG_NOTICE) hi = yellow; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", hi, message, reset); - if (cw < 0) - goto error; + if (cw < 0) { + return SC_ERR_SPRINTF; + } temp += cw; if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { - if (temp_fmt_h != NULL) - SCFree(temp_fmt_h); return SC_OK; } - SCFree(temp_fmt_h); - if (sc_log_config->op_filter_regex != NULL) { #define MAX_SUBSTRINGS 30 int ov[MAX_SUBSTRINGS]; @@ -514,11 +499,6 @@ static SCError SCLogMessageGetBuffer( } return SC_OK; - - error: - if (temp_fmt_h != NULL) - SCFree(temp_fmt_h); - return SC_ERR_SPRINTF; } static void SCLogReopen(SCLogOPIfaceCtx *op_iface_ctx) From a6fccd952e39a220454c057b77f90b9abc08ffa6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 11 Jan 2017 15:32:45 +0100 Subject: [PATCH 2265/2553] ssl: suppress scan-build warnings --- src/app-layer-ssl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 0d2c25b3480a..96c7cc863ad8 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -442,6 +442,7 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, ssl_state->curr_connp->trec_len = 0; /* error, skip packet */ parsed += input_len; + (void)parsed; /* for scan-build */ ssl_state->curr_connp->bytes_processed += input_len; return -1; } @@ -1258,6 +1259,7 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, parsed += retval; input_len -= retval; + (void)input_len; /* for scan-build */ if (ssl_state->curr_connp->bytes_processed == ssl_state->curr_connp->record_length + From f964cdbc937df5e2864eaea319a0b2f8038d112f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 11 Jan 2017 15:36:15 +0100 Subject: [PATCH 2266/2553] address parsing: fix memory leak in error path --- src/detect-engine-address.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index a924855bcd1e..079ec36dc005 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -959,8 +959,11 @@ static int DetectAddressParse2(const DetectEngineCtx *de_ctx, if (DetectAddressParse2(de_ctx, gh, ghn, temp_rule_var_address, (negate + n_set) % 2, var_list) < 0) + { + if (temp_rule_var_address != rule_var_address) + SCFree(temp_rule_var_address); goto error; - + } d_set = 0; n_set = 0; if (temp_rule_var_address != rule_var_address) From f180ed8715aed4db725053156fc2ee53a948a0b0 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 17 Jan 2017 15:31:25 -0600 Subject: [PATCH 2267/2553] travis: add a build with -DNDEBUG --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index 98cb63b64454..515ee9d51488 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,13 @@ matrix: - NAME="linux,gcc,cocci" - *default-cflags - ENABLE_COCCI="yes" + # Linux, gcc, -DNDEBUG. + - os: linux + compiler: gcc + env: + - NAME="linux,gcc,ndebug" + - *default-cflags + - EXTRA_CFLAGS="-DNDEBUG" # Linux, clang. For this build we'll also enable -Wshadow. - os: linux compiler: clang From 3e70d7befc198a5c55944bc7ef0899f31f1a3d1f Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 17 Jan 2017 15:39:15 -0600 Subject: [PATCH 2268/2553] travis: export CFLAGS on linux --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 515ee9d51488..409ff648e6f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -73,6 +73,7 @@ script: - sh autogen.sh - | if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + export CFLAGS="${CFLAGS} ${EXTRA_CFLAGS}" ./configure --enable-nfqueue --enable-unittests --enable-hiredis ${ARGS} fi - | From 20111cab23a5281c08d5982df9195ba47ca1c202 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 17 Jan 2017 15:48:33 -0600 Subject: [PATCH 2269/2553] unix-socket: fix shadowed variable ret does not need to be redefined here, the existing declaration of ret can be used. --- src/unix-manager.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index b84b2c7a6589..79dc5f7dc834 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -127,7 +127,6 @@ int UnixNew(UnixCommand * this) struct stat stat_buf; /* coverity[toctou] */ if (stat(SOCKET_PATH, &stat_buf) != 0) { - int ret; /* coverity[toctou] */ ret = mkdir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP); if (ret != 0) { From 0d5fd0f6580682b30628b9f1abf02e478b1eda94 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 17 Jan 2017 12:59:51 -0800 Subject: [PATCH 2270/2553] util-file: fix error logic in hash computation This patch fixes an issue with hash computation resulting in the invalidity of at least one hash when at least two different hashes functions were used. Impact was setting as `force-hash: [md5, sha256]` not to be valid. Also it could lead to false negative if too different hash functions had to be used on a single file due to signatures. --- src/util-file.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/util-file.c b/src/util-file.c index 8a79fcbdeb99..a327f139358c 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -574,19 +574,23 @@ int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) if (FileStoreNoStoreCheck(ffc->tail) == 1) { #ifdef HAVE_NSS + int hash_done = 0; /* no storage but forced hashing */ if (ffc->tail->md5_ctx) { HASH_Update(ffc->tail->md5_ctx, data, data_len); - SCReturnInt(0); + hash_done = 1; } if (ffc->tail->sha1_ctx) { HASH_Update(ffc->tail->sha1_ctx, data, data_len); - SCReturnInt(0); + hash_done = 1; } if (ffc->tail->sha256_ctx) { HASH_Update(ffc->tail->sha256_ctx, data, data_len); - SCReturnInt(0); + hash_done = 1; } + + if (hash_done) + SCReturnInt(0); #endif if (g_file_force_tracking || (!(ffc->tail->flags & FILE_NOTRACK))) SCReturnInt(0); From e9fccfa67c0badc26649593cd8f30a5f8c2e7055 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 9 Jan 2017 16:11:08 -0600 Subject: [PATCH 2271/2553] tx logging: only update logged tx id if all loggers logged Prevents the case where the logged id is incremented if a newer transaction is complete and an older one is still outstanding. For example, dns request0, unsolicited dns response, dns response0 would result in the valid response0 never being logged. Similarily this could happen for: request0, request1, response1, response0 which would end up having request0, request1 and response1 logged, but response0 would not be logged. --- src/app-layer-parser.c | 4 ++-- src/app-layer-parser.h | 2 +- src/output-tx.c | 40 ++++++++++++++++++++++++++++++++-------- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 6730e8144e97..359bd9a07601 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -597,12 +597,12 @@ uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate) SCReturnCT((pstate == NULL) ? 0 : pstate->log_id, "uint64_t"); } -void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate) +void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate, uint64_t tx_id) { SCEnter(); if (pstate != NULL) - pstate->log_id++; + pstate->log_id = tx_id; SCReturn; } diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index be4043032c0d..8e70d258fba9 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -162,7 +162,7 @@ void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto a uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate); -void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate); +void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate, uint64_t tx_id); void AppLayerParserSetTxLogged(uint8_t ipproto, AppProto alproto, void *alstate, void *tx, uint32_t logger); int AppLayerParserGetTxLogged(uint8_t ipproto, AppProto alproto, void *alstate, diff --git a/src/output-tx.c b/src/output-tx.c index aac57e524ca5..482fa087d9ad 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -163,10 +163,17 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) uint64_t total_txs = AppLayerParserGetTxCnt(p->proto, alproto, alstate); uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); + uint64_t max_id = tx_id; + int logged = 0; + int gap = 0; for (; tx_id < total_txs; tx_id++) { - int logger_not_logged = 0; + /* Track the number of loggers, of the eligible loggers that + * actually logged this transaction. They all must have logged + * before the transaction is considered logged. */ + int number_of_loggers = 0; + int loggers_that_logged = 0; void *tx = AppLayerParserGetTx(p->proto, alproto, alstate, tx_id); if (tx == NULL) { @@ -195,10 +202,12 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) if (logger->alproto == alproto) { SCLogDebug("alproto match, logging tx_id %"PRIu64, tx_id); + number_of_loggers++; + if (AppLayerParserGetTxLogged(p->proto, alproto, alstate, tx, logger->id)) { SCLogDebug("logger has already logged this transaction"); - + loggers_that_logged++; goto next; } @@ -208,30 +217,30 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) int r = logger->LogCondition(tv, p, alstate, tx, tx_id); if (r == FALSE) { SCLogDebug("conditions not met, not logging"); - logger_not_logged = 1; goto next; } } else { if (tx_progress_tc < logger->tc_log_progress) { SCLogDebug("progress not far enough, not logging"); - logger_not_logged = 1; goto next; } if (tx_progress_ts < logger->ts_log_progress) { SCLogDebug("progress not far enough, not logging"); - logger_not_logged = 1; goto next; } } } + SCLogDebug("Logging tx_id %"PRIu64" to logger %d", tx_id, + logger->logger_id); PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, p, f, alstate, tx, tx_id); PACKET_PROFILING_LOGGER_END(p, logger->logger_id); AppLayerParserSetTxLogged(p->proto, alproto, alstate, tx, logger->id); + loggers_that_logged++; } next: @@ -242,12 +251,27 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) BUG_ON(logger != NULL && store == NULL); } - if (!logger_not_logged) { - SCLogDebug("updating log tx_id %"PRIu64, tx_id); - AppLayerParserSetTransactionLogId(f->alparser); + /* If all loggers logged set a flag and update the last tx_id + * that was logged. + * + * If not all loggers were logged we flag that there was a gap + * so any subsequent transactions in this loop don't increase + * the maximum ID that was logged. */ + if (!gap && loggers_that_logged == number_of_loggers) { + logged = 1; + max_id = tx_id; + } else { + gap = 1; } } + /* Update the the last ID that has been logged with all + * transactions before it. */ + if (logged) { + SCLogDebug("updating log tx_id %"PRIu64, max_id); + AppLayerParserSetTransactionLogId(f->alparser, max_id + 1); + } + end: return TM_ECODE_OK; } From fa8cbd87417a58c314a48208cc6986acd56177e7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 Jan 2017 11:36:33 +0100 Subject: [PATCH 2272/2553] smb: detect protocol in both directions --- src/app-layer-smb.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 8e23f0e5dd67..e5c6c10afb24 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -1500,18 +1500,17 @@ static uint16_t SMBProbingParser(uint8_t *input, uint32_t ilen, uint32_t *offset static int SMBRegisterPatternsForProtocolDetection(void) { - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, - "|ff|SMB", 8, 4, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB2, - "|fe|SMB", 8, 4, STREAM_TOSERVER) < 0) - { - return -1; - } - - return 0; + int r = 0; + r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, + "|ff|SMB", 8, 4, STREAM_TOSERVER); + r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, + "|ff|SMB", 8, 4, STREAM_TOCLIENT); + + r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB2, + "|fe|SMB", 8, 4, STREAM_TOSERVER); + r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB2, + "|fe|SMB", 8, 4, STREAM_TOCLIENT); + return r == 0 ? 0 : -1; } void RegisterSMBParsers(void) @@ -1529,12 +1528,12 @@ void RegisterSMBParsers(void) ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, STREAM_TOSERVER, - SMBProbingParser, NULL); + SMBProbingParser, SMBProbingParser); } else { AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, - SMBProbingParser, NULL); + SMBProbingParser, SMBProbingParser); } AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_SMB, STREAM_TOSERVER); From 15f4144edac75c831d0f1ff69c01df3a6f6d9529 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 Jan 2017 11:37:25 +0100 Subject: [PATCH 2273/2553] smb: add tcp/445 to proto detect fallback --- suricata.yaml.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index d4d813ee5703..b733ea1b108b 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -706,7 +706,7 @@ app-layer: smb: enabled: yes detection-ports: - dp: 139 + dp: 139, 445 # smb2 detection is disabled internally inside the engine. #smb2: # enabled: yes From cb36dee47783b2a7c91fd0b0138dee8bd37354b9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 Jan 2017 15:13:40 +0100 Subject: [PATCH 2274/2553] hyperscan: fix minor coverity issue in error path *** CID 1398951: API usage errors (LOCK) /src/util-mpm-hs.c: 722 in SCHSPreparePatterns() 716 SCMutexUnlock(&g_db_table_mutex); 717 718 SCHSFreeCompileData(cd); 719 return 0; 720 721 error: >>> CID 1398951: API usage errors (LOCK) >>> "pthread_mutex_unlock" unlocks "g_db_table_mutex" while it is unlocked. 722 SCMutexUnlock(&g_db_table_mutex); 723 if (pd) { 724 PatternDatabaseFree(pd); 725 } 726 if (cd) { --- src/util-mpm-hs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c index 61224d743ceb..2b59eeaff869 100644 --- a/src/util-mpm-hs.c +++ b/src/util-mpm-hs.c @@ -657,6 +657,7 @@ int SCHSPreparePatterns(MpmCtx *mpm_ctx) if (p->flags & (MPM_PATTERN_FLAG_OFFSET | MPM_PATTERN_FLAG_DEPTH)) { cd->ext[i] = SCMalloc(sizeof(hs_expr_ext_t)); if (cd->ext[i] == NULL) { + SCMutexUnlock(&g_db_table_mutex); goto error; } memset(cd->ext[i], 0, sizeof(hs_expr_ext_t)); @@ -685,6 +686,7 @@ int SCHSPreparePatterns(MpmCtx *mpm_ctx) SCLogError(SC_ERR_FATAL, "compile error: %s", compile_err->message); } hs_free_compile_error(compile_err); + SCMutexUnlock(&g_db_table_mutex); goto error; } @@ -695,12 +697,14 @@ int SCHSPreparePatterns(MpmCtx *mpm_ctx) SCMutexUnlock(&g_scratch_proto_mutex); if (err != HS_SUCCESS) { SCLogError(SC_ERR_FATAL, "failed to allocate scratch"); + SCMutexUnlock(&g_db_table_mutex); goto error; } err = hs_database_size(pd->hs_db, &ctx->hs_db_size); if (err != HS_SUCCESS) { SCLogError(SC_ERR_FATAL, "failed to query database size"); + SCMutexUnlock(&g_db_table_mutex); goto error; } @@ -719,7 +723,6 @@ int SCHSPreparePatterns(MpmCtx *mpm_ctx) return 0; error: - SCMutexUnlock(&g_db_table_mutex); if (pd) { PatternDatabaseFree(pd); } From ec44585dcad0118036f23486a371ecfc2f1a7912 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 18 Jan 2017 09:30:48 -0600 Subject: [PATCH 2275/2553] app-layer - fix secondary probing parser logic Apply the same logic to pe2 as pe1 for determining which probe to call. Missed in previous commit. --- src/app-layer-detect-proto.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index c82cc8d0d978..46085620c145 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -420,7 +420,11 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, continue; } - alproto = pe->ProbingParserTs(buf, buflen, NULL); + if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { + alproto = pe->ProbingParserTs(buf, buflen, NULL); + } else if (pe->ProbingParserTc != NULL) { + alproto = pe->ProbingParserTc(buf, buflen, NULL); + } if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) goto end; if (alproto == ALPROTO_FAILED || From 5c553736794fdef710b34a9c9dfee06762d95bca Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 18 Jan 2017 09:32:23 -0600 Subject: [PATCH 2276/2553] app-layer-detect-proto.c: fix indent A recent commit was outdented by 1 column. --- src/app-layer-detect-proto.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 46085620c145..9563ffb1fdc5 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -399,18 +399,18 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, continue; } - if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { + if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { alproto = pe->ProbingParserTs(buf, buflen, NULL); - } else if (pe->ProbingParserTc != NULL) { + } else if (pe->ProbingParserTc != NULL) { alproto = pe->ProbingParserTc(buf, buflen, NULL); - } - if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) - goto end; - if (alproto == ALPROTO_FAILED || - (pe->max_depth != 0 && buflen > pe->max_depth)) { - alproto_masks[0] |= pe->alproto_mask; - } - pe = pe->next; + } + if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) + goto end; + if (alproto == ALPROTO_FAILED || + (pe->max_depth != 0 && buflen > pe->max_depth)) { + alproto_masks[0] |= pe->alproto_mask; + } + pe = pe->next; } pe = pe2; while (pe != NULL) { From 28c1516be758f835a3ae8d42cb73806667cbd0a3 Mon Sep 17 00:00:00 2001 From: Peter Sanders Date: Fri, 9 Dec 2016 15:18:47 -0500 Subject: [PATCH 2277/2553] doc: initial Napatech documentation --- doc/userguide/capture-hardware/Napatech.rst | 216 ++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 doc/userguide/capture-hardware/Napatech.rst diff --git a/doc/userguide/capture-hardware/Napatech.rst b/doc/userguide/capture-hardware/Napatech.rst new file mode 100644 index 000000000000..9a7e2e9e1c13 --- /dev/null +++ b/doc/userguide/capture-hardware/Napatech.rst @@ -0,0 +1,216 @@ + + +Napatech Suricata Installation Guide +============================================================= + +**Contents:** +-------------- + + * Introduction + + * Package Installation + + * Basic Configuration + + * Advanced Multithreaded Configuration + +**Introduction:** +------------------ + +Napatech packet capture accelerator cards can greatly improve the performance of your Suricata deployment using these +hardware based features: + + * On board burst buffering (up to 12GB) + + * Zero-copy kernel bypass DMA + + * Non-blocking PCIe performance + + * Port merging + + * Load distribution to up 128 host buffers + + * Precise timestamping + + * Accurate time synchronization + +The Napatech Software Suite (driver package) comes in two varieties, NAC and OEM. +The NAC package distributes deb and rpm packages to ease the installation. +The OEM package uses a proprietary shell script to handle the installation process. +In either case, gcc, make and the kernel header files are required to compile the kernel module and +install the software. + + +**Package Installation:** +------------------------------------ + +*Note that make, gcc, and the kernel headers are required for installation* + +*Root privileges are also required* + +Napatech NAC Package: +^^^^^^^^^^^^^^^^^^^^^^^^ + +Red Hat Based Distros:: + + $ yum install kernel-devel-$(uname -r) gcc make ncurses-libs + $ yum install nac-pcap-.x86_64.rpm + +Some distributions will require you to use the --nogpgcheck option with yum for the NAC Software Suite package file:: + + $ yum --nogpgcheck install nac-pcap-.x86_64.rpm + +Debian Based Distros:: + + $ apt-get install linux-headers-$(uname .r) gcc make libncurses5 + $ dpkg .i nac-pcap__amd64.deb + +To complete installation for all distros stop ntservice:: + + $ /opt/napatech3/bin/ntstop.sh -m + +Remove these existing setup files:: + + $ cd /opt/napatech3/config + $ rm ntservice.ini setup.ini + +Restart ntservice (a new ntservice.ini configuration file will be generated automatically):: + + $ /opt/napatech3/bin/ntstart.sh -m + + +Napatech OEM Package: +^^^^^^^^^^^^^^^^^^^^^^ + +*Note that you will be prompted to install the Napatech libpcap library. Answer "yes" if you would like to +use the Napatech card to capture packets in WIreshark, tcpdump, or another pcap based application. +Libpcap is not needed for Suricata as native Napatech API support is included* + +Red Hat Based Distros:: + + $ yum install kernel-devel-$(uname -r) gcc make + $ ./package_install_3gd.sh + +Debian Based Distros:: + + $ apt-get install linux-headers-$(uname .r) gcc make + $ ./package_install_3gd.sh + +To complete installation for all distros ntservice:: + + $ /opt/napatech3/bin/ntstart.sh -m + +**Suricata Installation:** +--------------------------- + +After downloading and extracting the Suricata tarball, you need to run configure to enable Napatech support and +prepare for compilation:: + + $ ./configure --enable_napatech --with-napatech-includes=/opt/napatech3/include --with-napatech-libraries=/opt/napatech3/lib + $ make + $ make install-full + +Now edit the suricata.yaml file to configure the maximum number of streams to use. If you plan on using the load distribution +(RSS - like) feature in the Napatech accelerator, then the list should contain the same number of streams as host buffers defined in +ntservice.ini:: + + Napatech: + # The Host Buffer Allowance for all streams + # (-1 = OFF, 1 - 100 = percentage of the host buffer that can be held back) + hba: -1 + + # use_all_streams set to "yes" will query the Napatech service for all configured + # streams and listen on all of them. When set to "no" the streams config array + # will be used. + use-all-streams: yes + + # The streams to listen on + streams: [0, 1, 2, 3, 4, 5, 6, 7] + + +**Basic Configuration:** +------------------------- + +For the basic installation we will setup the Napatech capture accelerator to merge all physical +ports into single stream that Suricata can read from. for this configuration, Suricata will +handle the packet distribution to multiple threads. + +Here are the lines that need changing in /opt/napatech3/bin/ntservice.ini for best single buffer performance:: + + TimeSyncReferencePriority = OSTime # Timestamp clock synchronized to the OS + HostBuffersRx = [1,16,0] # [number of host buffers, Size(MB), NUMA node] + +Stop and restart ntservice after making changes to ntservice:: + + $ /opt/napatech3/bin/ntstop.sh -m + $ /opt/napatech3/bin/ntstart.sh -m + +Now we need to execute a few NTPL (Napatech Programming Language) commands to complete the setup. Create +a file will the following commands:: + + Delete=All # Delete any existing filters + Setup[numaNode=0] = streamid==0 # Set stream ID 0 to NUMA 0 + Assign[priority=0; streamid=0]= all # Assign all phisical ports to stream ID 0 + +Next execute those command using the ntpl tool:: + + $ /opt/napatech3/bin/ntpl -f + +Now you are ready to start suricata:: + + $ suricata -c /usr/local/etc/suricata/suricata.yaml --napatech --runmode workers + +**Advanced Multithreaded Configuration** +------------------------------------------ + +Now let's do a more advanced configuration where we will use the load distribution (RSS - like) capability in the +accelerator. We will create 8 streams and setup the accelerator to distribute the load based on a 5 tuple hash. +Increasing buffer size will minimize packet loss only if your CPU cores are fully saturated. Setting the minimum +buffer size (16MB) will gave the best performance (minimize L3 cache hits) if your CPU cores are keeping up. + +*Note that it is extremely important that the NUMA node the host buffers are define in is the same physical CPU +socket that the Napatech accelerator is plugged into* + +First let's modify the ntservice.ini file to increase the number and size of the host buffers:: + + HostBuffersRx = [8,256,0] # [number of host buffers, Size (MB), NUMA node] + +Stop and restart ntservice after making changes to ntservice:: + + $ /opt/napatech3/bin/ntstop.sh -m + $ /opt/napatech3/bin/ntstart.sh -m + +Now let's assign the streams to host buffers and configure the load distribution. The load distribution will be +setup to support both tunneled and non-tunneled traffic. Create a file that contains the ntpl commands below:: + + Delete=All # Delete any existing filters + Setup[numaNode=0] = streamid==0 + Setup[numaNode=0] = streamid==1 + Setup[numaNode=0] = streamid==2 + Setup[numaNode=0] = streamid==3 + Setup[numaNode=0] = streamid==4 + Setup[numaNode=0] = streamid==5 + Setup[numaNode=0] = streamid==6 + Setup[numaNode=0] = streamid==7 + HashMode[priority=0; InnerLayer4Type=UDP, TCP, SCTP] = HashInner5TupleSorted + HashMode[priority=1; InnerLayer3Type=IPV4] = HashInner2TupleSorted + HashMode[priority=2; Layer4Type=UDP, TCP, SCTP] = Hash5TupleSorted + HashMode[priority=3; Layer3Type=IPV4] = Hash2TupleSorted + HashMode[priority=4]=HashRoundRobin + Assign[priority=0; streamid=(0..7)]= all + +Next execute those command using the ntpl tool:: + + $ /opt/napatech3/bin/ntpl -f + +Now you are ready to start Suricata:: + + $ suricata -c /usr/local/etc/suricata/suricata.yaml --napatech --runmode workers + +Questions? + + Contact a support engineer at: ntsupport@napatech.com + +Happy capturing! + +PAS From b7b9b5b682aebae0faa5dfc2f141e89d0194040e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 Jan 2017 16:07:37 +0100 Subject: [PATCH 2278/2553] doc: add napatech to userguide --- doc/userguide/capture-hardware/index.rst | 1 + doc/userguide/capture-hardware/{Napatech.rst => napatech.rst} | 0 2 files changed, 1 insertion(+) rename doc/userguide/capture-hardware/{Napatech.rst => napatech.rst} (100%) diff --git a/doc/userguide/capture-hardware/index.rst b/doc/userguide/capture-hardware/index.rst index 071ed7fab85d..a078541e36bb 100644 --- a/doc/userguide/capture-hardware/index.rst +++ b/doc/userguide/capture-hardware/index.rst @@ -4,4 +4,5 @@ Using Capture Hardware .. toctree:: endace-dag + napatech myricom diff --git a/doc/userguide/capture-hardware/Napatech.rst b/doc/userguide/capture-hardware/napatech.rst similarity index 100% rename from doc/userguide/capture-hardware/Napatech.rst rename to doc/userguide/capture-hardware/napatech.rst From a2d31b5e04674b9b33fb0288cddb9f0c22859d26 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 17 Jan 2017 16:28:49 +0100 Subject: [PATCH 2279/2553] doc: napatech formatting fixes --- doc/userguide/capture-hardware/napatech.rst | 57 ++++++++++----------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/doc/userguide/capture-hardware/napatech.rst b/doc/userguide/capture-hardware/napatech.rst index 9a7e2e9e1c13..fdd1e2bd9c51 100644 --- a/doc/userguide/capture-hardware/napatech.rst +++ b/doc/userguide/capture-hardware/napatech.rst @@ -3,8 +3,8 @@ Napatech Suricata Installation Guide ============================================================= -**Contents:** --------------- +Contents +-------- * Introduction @@ -14,8 +14,8 @@ Napatech Suricata Installation Guide * Advanced Multithreaded Configuration -**Introduction:** ------------------- +Introduction +------------ Napatech packet capture accelerator cards can greatly improve the performance of your Suricata deployment using these hardware based features: @@ -41,29 +41,29 @@ In either case, gcc, make and the kernel header files are required to compile th install the software. -**Package Installation:** ------------------------------------- +Package Installation +-------------------- *Note that make, gcc, and the kernel headers are required for installation* *Root privileges are also required* -Napatech NAC Package: -^^^^^^^^^^^^^^^^^^^^^^^^ +Napatech NAC Package +^^^^^^^^^^^^^^^^^^^^ Red Hat Based Distros:: - $ yum install kernel-devel-$(uname -r) gcc make ncurses-libs - $ yum install nac-pcap-.x86_64.rpm + $ yum install kernel-devel-$(uname -r) gcc make ncurses-libs + $ yum install nac-pcap-.x86_64.rpm Some distributions will require you to use the --nogpgcheck option with yum for the NAC Software Suite package file:: - $ yum --nogpgcheck install nac-pcap-.x86_64.rpm + $ yum --nogpgcheck install nac-pcap-.x86_64.rpm Debian Based Distros:: - $ apt-get install linux-headers-$(uname .r) gcc make libncurses5 - $ dpkg .i nac-pcap__amd64.deb + $ apt-get install linux-headers-$(uname .r) gcc make libncurses5 + $ dpkg .i nac-pcap__amd64.deb To complete installation for all distros stop ntservice:: @@ -79,8 +79,8 @@ Restart ntservice (a new ntservice.ini configuration file will be generated auto $ /opt/napatech3/bin/ntstart.sh -m -Napatech OEM Package: -^^^^^^^^^^^^^^^^^^^^^^ +Napatech OEM Package +^^^^^^^^^^^^^^^^^^^^ *Note that you will be prompted to install the Napatech libpcap library. Answer "yes" if you would like to use the Napatech card to capture packets in WIreshark, tcpdump, or another pcap based application. @@ -88,20 +88,20 @@ Libpcap is not needed for Suricata as native Napatech API support is included* Red Hat Based Distros:: - $ yum install kernel-devel-$(uname -r) gcc make - $ ./package_install_3gd.sh + $ yum install kernel-devel-$(uname -r) gcc make + $ ./package_install_3gd.sh Debian Based Distros:: - $ apt-get install linux-headers-$(uname .r) gcc make - $ ./package_install_3gd.sh + $ apt-get install linux-headers-$(uname .r) gcc make + $ ./package_install_3gd.sh To complete installation for all distros ntservice:: $ /opt/napatech3/bin/ntstart.sh -m -**Suricata Installation:** ---------------------------- +Suricata Installation +--------------------- After downloading and extracting the Suricata tarball, you need to run configure to enable Napatech support and prepare for compilation:: @@ -128,8 +128,8 @@ ntservice.ini:: streams: [0, 1, 2, 3, 4, 5, 6, 7] -**Basic Configuration:** -------------------------- +Basic Configuration +------------------- For the basic installation we will setup the Napatech capture accelerator to merge all physical ports into single stream that Suricata can read from. for this configuration, Suricata will @@ -160,8 +160,8 @@ Now you are ready to start suricata:: $ suricata -c /usr/local/etc/suricata/suricata.yaml --napatech --runmode workers -**Advanced Multithreaded Configuration** ------------------------------------------- +Advanced Multithreaded Configuration +------------------------------------ Now let's do a more advanced configuration where we will use the load distribution (RSS - like) capability in the accelerator. We will create 8 streams and setup the accelerator to distribute the load based on a 5 tuple hash. @@ -207,10 +207,9 @@ Now you are ready to start Suricata:: $ suricata -c /usr/local/etc/suricata/suricata.yaml --napatech --runmode workers -Questions? - Contact a support engineer at: ntsupport@napatech.com +Support +------- -Happy capturing! +Contact a support engineer at: ntsupport@napatech.com -PAS From 19e578a740057a69118149812ed2b240293a9a8e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 18 Jan 2017 23:23:11 -0600 Subject: [PATCH 2280/2553] pcap-log: fix pcre_study error check Code was failing on a NULL return value which can be returned when there was nothing todo instead of an error. Instead check the errbuf for a non-NULL value to determine error. --- src/log-pcap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/log-pcap.c b/src/log-pcap.c index 70f4c6bf91af..0d1a2f776a38 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -962,7 +962,7 @@ static OutputCtx *PcapLogInitCtx(ConfNode *conf) timestamp_pattern, pcre_erroffset, pcre_errbuf); } pcre_timestamp_extra = pcre_study(pcre_timestamp_code, 0, &pcre_errbuf); - if (pcre_timestamp_extra == NULL) { + if (pcre_errbuf != NULL) { FatalError(SC_ERR_PCRE_STUDY, "Fail to study pcre: %s", pcre_errbuf); } From 187a6f392c51eb8e07a1d997fff53adabe30f6d7 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Thu, 19 Jan 2017 13:31:38 +0300 Subject: [PATCH 2281/2553] Bug #2009: added CAP_NET_ADMIN for PCAP and af-packet modes. Without this capability suricata is unable to get network interface's settings. --- src/util-privs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util-privs.c b/src/util-privs.c index 9b2a0058f6f3..d44cbc7b396d 100644 --- a/src/util-privs.c +++ b/src/util-privs.c @@ -77,6 +77,7 @@ void SCDropMainThreadCaps(uint32_t userid, uint32_t groupid) capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_RAW, /* needed for pcap live mode */ CAP_SYS_NICE, + CAP_NET_ADMIN, -1); break; case RUNMODE_PFRING: From fbc2dbac288f42f1c68e8fb4d9de15541568d9d7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 18 Jan 2017 11:08:21 -0800 Subject: [PATCH 2282/2553] util-file: change file size computation The file size returned by FileSize is invalid if file store is not used so we introduce a new size field in File structure that is used to store the size. --- src/util-file.c | 4 ++++ src/util-file.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/util-file.c b/src/util-file.c index a327f139358c..8148f7a2ea2d 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -565,6 +565,8 @@ int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) SCReturnInt(-1); } + ffc->tail->size += data_len; + if (ffc->tail->state != FILE_STATE_OPENED) { if (ffc->tail->flags & FILE_NOSTORE) { SCReturnInt(-2); @@ -699,6 +701,7 @@ File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, FileContainerAdd(ffc, ff); if (data != NULL) { + ff->size += data_len; if (AppendData(ff, data, data_len) != 0) { ff->state = FILE_STATE_ERROR; SCReturnPtr(NULL, "File"); @@ -723,6 +726,7 @@ static int FileCloseFilePtr(File *ff, const uint8_t *data, } if (data != NULL) { + ff->size += data_len; if (ff->flags & FILE_NOSTORE) { #ifdef HAVE_NSS /* no storage but hashing */ diff --git a/src/util-file.h b/src/util-file.h index e0d154de89ac..6794364eb448 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -82,6 +82,7 @@ typedef struct File_ { uint64_t content_inspected; /**< used in pruning if FILE_USE_DETECT * flag is set */ uint64_t content_stored; + uint64_t size; } File; typedef struct FileContainer_ { From a098896b285bde587db122baf0a3f6256f89d0a8 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 18 Jan 2017 11:09:29 -0800 Subject: [PATCH 2283/2553] output-json-file: use size instead of FileSize FileSize is not returning the actual value when file store is not used. --- src/output-json-file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output-json-file.c b/src/output-json-file.c index 74ac35912bbd..0258c985136c 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -171,7 +171,7 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F if (ff->flags & FILE_STORED) { json_object_set_new(fjs, "file_id", json_integer(ff->file_id)); } - json_object_set_new(fjs, "size", json_integer(FileSize(ff))); + json_object_set_new(fjs, "size", json_integer(ff->size)); json_object_set_new(fjs, "tx_id", json_integer(ff->txid)); /* originally just 'file', but due to bug 1127 naming it fileinfo */ From 569cc5d238639c27a88a94069bf28d8f60809f03 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 19 Jan 2017 10:52:41 -0800 Subject: [PATCH 2284/2553] util-file: introduce new functions for file size This patch introduces the FileDataSize and FileTrackedSize functions. The first one is just a renaming of the initial FilSize function whereas the other one is using the newly introduced size field as value. --- src/app-layer-htp-file.c | 4 ++-- src/app-layer-smtp.c | 8 ++++---- src/detect-engine-file.c | 2 +- src/detect-engine-filedata-smtp.c | 4 ++-- src/detect-filemagic.c | 8 ++++---- src/detect-filesize.c | 2 +- src/log-file.c | 2 +- src/log-filestore.c | 2 +- src/output-filedata.c | 2 +- src/output-json-file.c | 2 +- src/util-file.c | 30 ++++++++++++++++++++++-------- src/util-file.h | 3 ++- src/util-lua-common.c | 2 +- 13 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index 199290610ae2..520f734c0350 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -633,11 +633,11 @@ static int HTPFileParserTest03(void) } if (http_state->files_ts->head == NULL || - FileSize(http_state->files_ts->head) != 11) + FileDataSize(http_state->files_ts->head) != 11) { if (http_state->files_ts->head != NULL) printf("filedata len not 11 but %"PRIu64": ", - FileSize(http_state->files_ts->head)); + FileDataSize(http_state->files_ts->head)); goto end; } diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index cd02d91236d8..f1e9aecb83d7 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -371,7 +371,7 @@ static void SMTPPruneFiles(FileContainer *files) if (file->sb->stream_offset == 0) window = MAX(window, smtp_config.content_inspect_min_size); - uint64_t file_size = FileSize(file); + uint64_t file_size = FileDataSize(file); uint64_t data_size = file_size - file->sb->stream_offset; SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64, @@ -4840,8 +4840,8 @@ static int SMTPParserTest14(void) printf("smtp-mime file name is incorrect"); goto end; } - if (FileSize(file) != filesize){ - printf("smtp-mime file size %"PRIu64" is incorrect", FileSize(file)); + if (FileTrackedSize(file) != filesize){ + printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file)); goto end; } static uint8_t org_binary[] = { @@ -5127,7 +5127,7 @@ static int SMTPProcessDataChunkTest05(void){ FAIL_IF(file == NULL); ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); FAIL_IF(ret != 0); - FAIL_IF((uint32_t)FileSize(file) != 106); + FAIL_IF((uint32_t)FileDataSize(file) != 106); SMTPStateFree(smtp_state); FLOW_DESTROY(&f); PASS; diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index dafb28a880e5..9b9462ab5dda 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -110,7 +110,7 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, break; } - uint64_t file_size = FileSize(file); + uint64_t file_size = FileDataSize(file); if ((s->file_flags & FILE_SIG_NEED_MAGIC) && file_size == 0) { SCLogDebug("sig needs file content, but we don't have any"); r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index e0fa467e9ea4..4635ad10ee22 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -96,7 +96,7 @@ static const uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, const uint8_t *buffer = NULL; *buffer_len = 0; *stream_start_offset = 0; - uint64_t file_size = FileSize(curr_file); + uint64_t file_size = FileDataSize(curr_file); if (det_ctx->smtp_buffers_list_len == 0) { if (SMTPCreateSpace(det_ctx, 1) < 0) @@ -160,7 +160,7 @@ static const uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, det_ctx->smtp[index].offset = curr_file->content_inspected; /* updat inspected tracker */ - curr_file->content_inspected = FileSize(curr_file); + curr_file->content_inspected = FileDataSize(curr_file); SCLogDebug("content_inspected %u, offset %u", (uint)curr_file->content_inspected, (uint)det_ctx->smtp[index].offset); diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 9fe540ffa8cc..2c2c46f676f6 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -110,7 +110,7 @@ void DetectFilemagicRegister(void) */ int FilemagicGlobalLookup(File *file) { - if (file == NULL || FileSize(file) == 0) { + if (file == NULL || FileDataSize(file) == 0) { SCReturnInt(-1); } @@ -121,7 +121,7 @@ int FilemagicGlobalLookup(File *file) StreamingBufferGetData(file->sb, &data, &data_len, &offset); if (offset == 0) { - if (FileSize(file) >= FILEMAGIC_MIN_SIZE) { + if (FileDataSize(file) >= FILEMAGIC_MIN_SIZE) { file->magic = MagicGlobalLookup(data, data_len); } else if (file->state >= FILE_STATE_CLOSED) { file->magic = MagicGlobalLookup(data, data_len); @@ -141,7 +141,7 @@ int FilemagicGlobalLookup(File *file) */ int FilemagicThreadLookup(magic_t *ctx, File *file) { - if (ctx == NULL || file == NULL || FileSize(file) == 0) { + if (ctx == NULL || file == NULL || FileDataSize(file) == 0) { SCReturnInt(-1); } @@ -152,7 +152,7 @@ int FilemagicThreadLookup(magic_t *ctx, File *file) StreamingBufferGetData(file->sb, &data, &data_len, &offset); if (offset == 0) { - if (FileSize(file) >= FILEMAGIC_MIN_SIZE) { + if (FileDataSize(file) >= FILEMAGIC_MIN_SIZE) { file->magic = MagicThreadLookup(ctx, data, data_len); } else if (file->state >= FILE_STATE_CLOSED) { file->magic = MagicThreadLookup(ctx, data, data_len); diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 142baa02ae48..12b4c18f25c5 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -93,7 +93,7 @@ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, F DetectFilesizeData *fsd = (DetectFilesizeData *)m->ctx; int ret = 0; - uint64_t file_size = FileSize(file); + uint64_t file_size = FileTrackedSize(file); SCLogDebug("file size %"PRIu64", check %"PRIu64, file_size, fsd->size1); diff --git a/src/log-file.c b/src/log-file.c index 0b441127b94a..3ddf8643b1bf 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -319,7 +319,7 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const break; } fprintf(fp, "\"stored\": %s, ", ff->flags & FILE_STORED ? "true" : "false"); - fprintf(fp, "\"size\": %"PRIu64" ", FileSize(ff)); + fprintf(fp, "\"size\": %"PRIu64" ", FileTrackedSize(ff)); fprintf(fp, "}\n"); fflush(fp); SCMutexUnlock(&aft->file_ctx->fp_mutex); diff --git a/src/log-filestore.c b/src/log-filestore.c index 260357cb9d3a..5fca12d203dc 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -291,7 +291,7 @@ static void LogFilestoreLogCloseMetaFile(const File *ff) fprintf(fp, "STATE: UNKNOWN\n"); break; } - fprintf(fp, "SIZE: %"PRIu64"\n", FileSize(ff)); + fprintf(fp, "SIZE: %"PRIu64"\n", FileTrackedSize(ff)); fclose(fp); } else { diff --git a/src/output-filedata.c b/src/output-filedata.c index 3e7734375bbf..0f2f9e29d73d 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -183,7 +183,7 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data) /* if we have no data chunks left to log, we should still * close the logger(s) */ - if (FileSize(ff) == ff->content_stored && + if (FileDataSize(ff) == ff->content_stored && (file_trunc || file_close)) { CallLoggers(tv, store, p, ff, NULL, 0, OUTPUT_FILEDATA_FLAG_CLOSE); ff->flags |= FILE_STORED; diff --git a/src/output-json-file.c b/src/output-json-file.c index 0258c985136c..e840b669c842 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -171,7 +171,7 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F if (ff->flags & FILE_STORED) { json_object_set_new(fjs, "file_id", json_integer(ff->file_id)); } - json_object_set_new(fjs, "size", json_integer(ff->size)); + json_object_set_new(fjs, "size", json_integer(FileTrackedSize(ff))); json_object_set_new(fjs, "tx_id", json_integer(ff->txid)); /* originally just 'file', but due to bug 1127 naming it fileinfo */ diff --git a/src/util-file.c b/src/util-file.c index 8148f7a2ea2d..f868222a85c6 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -267,12 +267,12 @@ int FileMagicSize(void) } /** - * \brief get the size of the file + * \brief get the size of the file data * * This doesn't reflect how much of the file we have in memory, just the - * total size tracked so far. + * total size of filedata so far. */ -uint64_t FileSize(const File *file) +uint64_t FileDataSize(const File *file) { if (file != NULL && file->sb != NULL) { SCLogDebug("returning %"PRIu64, @@ -283,6 +283,20 @@ uint64_t FileSize(const File *file) return 0; } +/** + * \brief get the size of the file + * + * This doesn't reflect how much of the file we have in memory, just the + * total size of file so far. + */ +uint64_t FileTrackedSize(const File *file) +{ + if (file != NULL) { + return file->size; + } + return 0; +} + static int FilePruneFile(File *file) { SCEnter(); @@ -299,7 +313,7 @@ static int FilePruneFile(File *file) #endif uint64_t left_edge = file->content_stored; if (file->flags & FILE_NOSTORE) { - left_edge = FileSize(file); + left_edge = FileDataSize(file); } if (file->flags & FILE_USE_DETECT) { left_edge = MIN(left_edge, file->content_inspected); @@ -309,7 +323,7 @@ static int FilePruneFile(File *file) StreamingBufferSlideToOffset(file->sb, left_edge); } - if (left_edge != FileSize(file)) { + if (left_edge != FileDataSize(file)) { SCReturnInt(0); } @@ -516,7 +530,7 @@ static int FileStoreNoStoreCheck(File *ff) if (ff->flags & FILE_NOSTORE) { if (ff->state == FILE_STATE_OPENED && - FileSize(ff) >= (uint64_t)FileMagicSize()) + FileDataSize(ff) >= (uint64_t)FileMagicSize()) { SCReturnInt(1); } @@ -706,7 +720,7 @@ File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, ff->state = FILE_STATE_ERROR; SCReturnPtr(NULL, "File"); } - SCLogDebug("file size is now %"PRIu64, FileSize(ff)); + SCLogDebug("file size is now %"PRIu64, FileTrackedSize(ff)); } SCReturnPtr(ff, "File"); @@ -1034,7 +1048,7 @@ void FileDisableStoringForFile(File *ff) SCLogDebug("not storing this file"); ff->flags |= FILE_NOSTORE; - if (ff->state == FILE_STATE_OPENED && FileSize(ff) >= (uint64_t)FileMagicSize()) { + if (ff->state == FILE_STATE_OPENED && FileDataSize(ff) >= (uint64_t)FileMagicSize()) { if (g_file_force_md5 == 0 && g_file_force_sha1 == 0 && g_file_force_sha256 == 0 && g_file_force_tracking == 0) { (void)FileCloseFilePtr(ff, NULL, 0, diff --git a/src/util-file.h b/src/util-file.h index 6794364eb448..8c3828d9b956 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -214,7 +214,8 @@ void FileStoreFileById(FileContainer *fc, uint32_t); void FileTruncateAllOpenFiles(FileContainer *); -uint64_t FileSize(const File *file); +uint64_t FileDataSize(const File *file); +uint64_t FileTrackedSize(const File *file); uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction); diff --git a/src/util-lua-common.c b/src/util-lua-common.c index b51f8aad40bd..f1c13a8a9584 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -650,7 +650,7 @@ static int LuaCallbackFileInfoPushToStackFromFile(lua_State *luastate, const Fil lua_pushnumber(luastate, file->file_id); lua_pushnumber(luastate, file->txid); lua_pushlstring(luastate, (char *)file->name, file->name_len); - lua_pushnumber(luastate, FileSize(file)); + lua_pushnumber(luastate, FileTrackedSize(file)); lua_pushstring (luastate, #ifdef HAVE_MAGIC file->magic From d9b87e502d78497fd0e311724aff78c5bfa45d31 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 13 Jan 2017 11:03:55 +0100 Subject: [PATCH 2285/2553] flow: set flag to indicate that a flow has alerts Set FLOW_HAS_ALERTS flag on the flow on alerts. Add FlowHasAlerts(..) and FlowSetHasAlertsFlag(..) to check and set this flag. --- src/detect-engine-alert.c | 6 ++++++ src/flow.c | 24 ++++++++++++++++++++++++ src/flow.h | 5 ++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index 2abff2212b8f..21047a0df5cb 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -327,6 +327,12 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx * keyword context for sessions and hosts */ if (!(p->flags & PKT_PSEUDO_STREAM_END)) TagHandlePacket(de_ctx, det_ctx, p); + + /* Set flag on flow to indicate that it has alerts */ + if (p->flow != NULL && p->alerts.cnt > 0) { + FlowSetHasAlertsFlag(p->flow); + } + } diff --git a/src/flow.c b/src/flow.c index df1dec39ff42..df4a79a7af6e 100644 --- a/src/flow.c +++ b/src/flow.c @@ -157,6 +157,30 @@ void FlowSetIPOnlyFlag(Flow *f, int direction) return; } +/** \brief Set flag to indicate that flow has alerts + * + * \param f flow + */ +void FlowSetHasAlertsFlag(Flow *f) +{ + f->flags |= FLOW_HAS_ALERTS; +} + +/** \brief Check if flow has alerts + * + * \param f flow + * \retval 1 has alerts + * \retval 0 has not alerts + */ +int FlowHasAlerts(const Flow *f) +{ + if (f->flags & FLOW_HAS_ALERTS) { + return 1; + } + + return 0; +} + /** * \brief determine the direction of the packet compared to the flow * \retval 0 to_server diff --git a/src/flow.h b/src/flow.h index d215a58210ad..d6660dd00c25 100644 --- a/src/flow.h +++ b/src/flow.h @@ -72,7 +72,8 @@ typedef struct AppLayerParserState_ AppLayerParserState; /** packet to client direction has been logged in drop file (only in IPS mode) */ #define FLOW_TOCLIENT_DROP_LOGGED BIT_U32(11) -// vacancy bit 12 +/** flow has alerts */ +#define FLOW_HAS_ALERTS BIT_U32(12) /** Pattern matcher alproto detection done */ #define FLOW_TS_PM_ALPROTO_DETECT_DONE BIT_U32(13) @@ -458,6 +459,8 @@ void FlowInitConfig (char); void FlowPrintQueueInfo (void); void FlowShutdown(void); void FlowSetIPOnlyFlag(Flow *, int); +void FlowSetHasAlertsFlag(Flow *); +int FlowHasAlerts(const Flow *); void FlowRegisterTests (void); int FlowSetProtoTimeout(uint8_t ,uint32_t ,uint32_t ,uint32_t); From c531e8f77cfcbe91b353ece306143439613f27cf Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 13 Jan 2017 11:08:55 +0100 Subject: [PATCH 2286/2553] lua: add SCFlowHasAlerts function Add SCFlowHasAlerts() to check if a flow has alerts. Returns true on alerts, false otherwise. Example: has_alerts = SCFlowHasAlerts() if has_alerts then -- do something end --- src/util-lua-common.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/util-lua-common.c b/src/util-lua-common.c index f1c13a8a9584..cb3d2dac4dc5 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -247,6 +247,37 @@ static int LuaCallbackFlowTimeString(lua_State *luastate) return r; } +/** \internal + * \brief fill lua stack with flow has alerts + * \param luastate the lua state + * \param flow flow + * \retval cnt number of data items placed on the stack + * + * Places alerts (bool) + */ +static int LuaCallbackHasAlertsPushToStackFromFlow(lua_State *luastate, const Flow *flow) +{ + lua_pushboolean(luastate, FlowHasAlerts(flow)); + + return 1; +} + +/** \internal + * \brief Wrapper for getting flow has alerts info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackFlowHasAlerts(lua_State *luastate) +{ + int r = 0; + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = LuaCallbackHasAlertsPushToStackFromFlow(luastate, flow); + + return r; +} + /** \internal * \brief fill lua stack with header info * \param luastate the lua state @@ -768,6 +799,8 @@ int LuaRegisterFunctions(lua_State *luastate) lua_setglobal(luastate, "SCFlowAppLayerProto"); lua_pushcfunction(luastate, LuaCallbackStatsFlow); lua_setglobal(luastate, "SCFlowStats"); + lua_pushcfunction(luastate, LuaCallbackFlowHasAlerts); + lua_setglobal(luastate, "SCFlowHasAlerts"); lua_pushcfunction(luastate, LuaCallbackStreamingBuffer); lua_setglobal(luastate, "SCStreamingBuffer"); From a2659ed7ec648ae2fe269335a76766852e915076 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 13 Jan 2017 11:46:59 +0100 Subject: [PATCH 2287/2553] output-json-flow: add has_alerts field Add has_alerts field to flow eve-log to indicate if a flow has any alerts or not. --- src/output-json-flow.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output-json-flow.c b/src/output-json-flow.c index cf65c51da2ba..e2d7c1b5c255 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -261,6 +261,8 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) json_object_set_new(hjs, "reason", json_string(reason)); + json_object_set_new(hjs, "alerted", json_boolean(FlowHasAlerts(f))); + json_object_set_new(js, "flow", hjs); From edbb035160a2090dd0e3e8fbba55449609bbae9f Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 13 Jan 2017 11:50:35 +0100 Subject: [PATCH 2288/2553] doc: add documentation for Lua SCFlowHasAlerts --- doc/userguide/output/lua-output.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/userguide/output/lua-output.rst b/doc/userguide/output/lua-output.rst index d1193ae95d98..158c0505b06f 100644 --- a/doc/userguide/output/lua-output.rst +++ b/doc/userguide/output/lua-output.rst @@ -178,6 +178,22 @@ Example: end end +SCFlowHasAlerts +~~~~~~~~~~~~~~~ + +Returns true if flow has alerts. + +Example: + +:: + + function log(args) + has_alerts = SCFlowHasAlerts() + if has_alerts then + -- do something + end + end + SCFlowStats ~~~~~~~~~~~ From a18af7325f7d64f983cb9a2110f87e0c937b050a Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Thu, 19 Jan 2017 23:48:59 +0100 Subject: [PATCH 2289/2553] configure: prevent combination of unittests and debug-validation --- configure.ac | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7b2e1be76749..b216aa78c008 100644 --- a/configure.ac +++ b/configure.ac @@ -395,7 +395,11 @@ AC_ARG_ENABLE(debug-validation, AS_HELP_STRING([--enable-debug-validation], [Enable (debug) validation code output]),,[enable_debug_validation=no]) AS_IF([test "x$enable_debug_validation" = "xyes"], [ - AC_DEFINE([DEBUG_VALIDATION],[1],[Enable (debug) validation code output]) + if test "$enable_unittests" = "yes"; then + AC_MSG_ERROR([debug_validation can't be enabled with enabled unittests!]) + else + AC_DEFINE([DEBUG_VALIDATION],[1],[Enable (debug) validation code output]) + fi ]) # profiling support From 1abaf1c96d7e2a49f7d3645e48f9ab83868547c7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 18 Nov 2016 10:53:25 -0600 Subject: [PATCH 2290/2553] templates: require the protocol name to start with a capital When running ./setup-app-layer.sh require the protocol name to start with a capital letter so it looks somewhat like a proper name. This will help give better function names. For example: ./setup-app-layer.sh IRC ./setup-app-layer.sh Irc will create function names starting with IRC or Irc. But we do not want function names to start with "irc". --- scripts/setup-app-layer.sh | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/scripts/setup-app-layer.sh b/scripts/setup-app-layer.sh index 2789f20dd7cd..87cebab80085 100755 --- a/scripts/setup-app-layer.sh +++ b/scripts/setup-app-layer.sh @@ -139,10 +139,25 @@ EOF protoname="$1" -if [ "${protoname}" = "" ]; then - usage - exit 1 -fi +# Make sure the protocol name looks like a proper name (starts with a +# capital letter). +case "${protoname}" in + + [[:upper:]]*) + # OK. + ;; + + "") + usage + exit 1 + ;; + + *) + echo "error: protocol name must beging with an upper case letter" + exit 1 + ;; + +esac protoname_lower=$(printf ${protoname} | tr '[:upper:]' '[:lower:]') protoname_upper=$(printf ${protoname} | tr '[:lower:]' '[:upper:]') From f73806211a93f40873d08d865c51fba3e3d11ce9 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 19 Jan 2017 09:28:45 -0600 Subject: [PATCH 2291/2553] template script: use bash and require ed For now these scripts only work in bash, and the "ed" program is required. --- scripts/setup-app-layer-detect.sh | 2 +- scripts/setup-app-layer-logger.sh | 2 +- scripts/setup-app-layer.sh | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/setup-app-layer-detect.sh b/scripts/setup-app-layer-detect.sh index ef4bccaa8e9f..8127370962eb 100755 --- a/scripts/setup-app-layer-detect.sh +++ b/scripts/setup-app-layer-detect.sh @@ -1,4 +1,4 @@ -#! /bin/sh +#! /usr/bin/env bash # # Script to provision a new application layer detector and parser. diff --git a/scripts/setup-app-layer-logger.sh b/scripts/setup-app-layer-logger.sh index 51f8e6d105f1..f05be59a2867 100755 --- a/scripts/setup-app-layer-logger.sh +++ b/scripts/setup-app-layer-logger.sh @@ -1,4 +1,4 @@ -#! /bin/sh +#! /usr/bin/env bash set -e diff --git a/scripts/setup-app-layer.sh b/scripts/setup-app-layer.sh index 87cebab80085..f7fa1ba6709e 100755 --- a/scripts/setup-app-layer.sh +++ b/scripts/setup-app-layer.sh @@ -1,10 +1,16 @@ -#! /bin/sh +#! /usr/bin/env bash # # Script to provision a new application layer detector and parser. set -e #set -x +# Fail if "ed" is not available. +if ! which edx > /dev/null 2>&1; then + echo "error: the program \"ed\" is required for this script" + exit 1 +fi + function usage() { cat < Date: Thu, 26 Jan 2017 10:16:53 +0100 Subject: [PATCH 2292/2553] threads: fix missed logging at shutdown At shutdown, all flows that still need work are handled by the flow force reassembly logic. This means one or more flow end pseudo packets are generated and pushed through the engine for final detection and logging. In some cases this would not work correctly. This was caused by the flow timeout logic kicking in before all the 'live' packets were processed. Before the flow timeout handling runs the receive threads are disabled, however the engine did not wait for the in-flight packets to be fully processed. In autofp mode, packets could still be in the queue between receive thread(s) and flow worker(s). This patch adds a new function that 'drains' all the packet threads of any in-progress packets before moving on the flow timeout logic. Bug #1946. --- src/tm-threads.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/tm-threads.c b/src/tm-threads.c index 9df10ff9370a..bc866aa215dc 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1521,6 +1521,64 @@ void TmThreadKillThread(ThreadVars *tv) return; } +/** \internal + * + * \brief make sure that all packet threads are done processing their + * in-flight packets + */ +static void TmThreadDrainPacketThreads(void) +{ + /* value in seconds */ +#define THREAD_KILL_MAX_WAIT_TIME 60 + /* value in microseconds */ +#define WAIT_TIME 1000 + + uint64_t total_wait_time = 0; + + ThreadVars *tv = NULL; + +again: + if (total_wait_time > (THREAD_KILL_MAX_WAIT_TIME * 1000000)) { + SCLogWarning(SC_ERR_SHUTDOWN, "unable to get all packet threads " + "to process their packets in time"); + return; + } + + SCMutexLock(&tv_root_lock); + + /* all receive threads are part of packet processing threads */ + tv = tv_root[TVT_PPT]; + + while (tv) { + if (tv->inq != NULL) { + /* we wait till we dry out all the inq packets, before we + * kill this thread. Do note that you should have disabled + * packet acquire by now using TmThreadDisableReceiveThreads()*/ + if (!(strlen(tv->inq->name) == strlen("packetpool") && + strcasecmp(tv->inq->name, "packetpool") == 0)) { + PacketQueue *q = &trans_q[tv->inq->id]; + if (q->len != 0) { + SCMutexUnlock(&tv_root_lock); + + total_wait_time += WAIT_TIME; + + /* don't sleep while holding a lock */ + usleep(WAIT_TIME); + goto again; + } + } + } + + tv = tv->next; + } + + SCMutexUnlock(&tv_root_lock); + return; + +#undef THREAD_KILL_MAX_WAIT_TIME +#undef WAIT_TIME +} + /** * \brief Disable all threads having the specified TMs. * @@ -1618,6 +1676,11 @@ void TmThreadDisableReceiveThreads(void) SCMutexUnlock(&tv_root_lock); + /* finally wait for all packet threads to have + * processed all of their 'live' packets so we + * don't process the last live packets together + * with FFR packets */ + TmThreadDrainPacketThreads(); return; } @@ -1635,6 +1698,8 @@ void TmThreadDisablePacketThreads(void) ThreadVars *tv = NULL; + /* first drain all packet threads of their packets */ + TmThreadDrainPacketThreads(); again: SCMutexLock(&tv_root_lock); From babe8a299e92a0b4b4d0055c2b21deb53371be95 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 24 Jan 2017 12:27:35 +0100 Subject: [PATCH 2293/2553] startup/shutdown: cleanup and unify with unix mode --- src/runmode-unix-socket.c | 131 ++++++++-------------- src/runmodes.c | 9 +- src/suricata.c | 221 ++++++++++++++++++-------------------- src/suricata.h | 4 + src/unix-manager.c | 20 +++- src/unix-manager.h | 2 +- 6 files changed, 179 insertions(+), 208 deletions(-) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 7b45928a1377..092cadaa9981 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -299,102 +299,57 @@ TmEcode UnixSocketPcapFilesCheck(void *data) } this->currentfile = NULL; - /* needed by FlowForceReassembly */ - PacketPoolInit(); - - /* handle graceful shutdown of the flow engine, it's helper - * threads and the packet threads */ - FlowDisableFlowManagerThread(); - TmThreadDisableReceiveThreads(); - FlowForceReassembly(); - TmThreadDisablePacketThreads(); - FlowDisableFlowRecyclerThread(); - - /* kill the stats threads */ - TmThreadKillThreadsFamily(TVT_MGMT); - TmThreadClearThreadsFamily(TVT_MGMT); - - /* kill packet threads -- already in 'disabled' state */ - TmThreadKillThreadsFamily(TVT_PPT); - TmThreadClearThreadsFamily(TVT_PPT); - - PacketPoolDestroy(); - - /* mgt and ppt threads killed, we can run non thread-safe - * shutdown functions */ - StatsReleaseResources(); - RunModeShutDown(); - FlowShutdown(); - IPPairShutdown(); - HostCleanup(); - StreamTcpFreeConfig(STREAM_VERBOSE); - DefragDestroy(); - TmqResetQueues(); -#ifdef PROFILING - if (profiling_rules_enabled) - SCProfilingDump(); - SCProfilingDestroy(); -#endif + PostRunDeinit(RUNMODE_PCAP_FILE, NULL /* no ts */); + } + if (TAILQ_EMPTY(&this->files)) { + // nothing to do + return TM_ECODE_OK; } - if (!TAILQ_EMPTY(&this->files)) { - PcapFiles *cfile = TAILQ_FIRST(&this->files); - TAILQ_REMOVE(&this->files, cfile, next); - SCLogInfo("Starting run for '%s'", cfile->filename); - unix_manager_file_task_running = 1; - this->running = 1; - if (ConfSet("pcap-file.file", cfile->filename) != 1) { + + PcapFiles *cfile = TAILQ_FIRST(&this->files); + TAILQ_REMOVE(&this->files, cfile, next); + SCLogInfo("Starting run for '%s'", cfile->filename); + unix_manager_file_task_running = 1; + this->running = 1; + if (ConfSet("pcap-file.file", cfile->filename) != 1) { + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "Can not set working file to '%s'", cfile->filename); + PcapFilesFree(cfile); + return TM_ECODE_FAILED; + } + if (cfile->output_dir) { + if (ConfSet("default-log-dir", cfile->output_dir) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENTS, - "Can not set working file to '%s'", cfile->filename); + "Can not set output dir to '%s'", cfile->output_dir); PcapFilesFree(cfile); return TM_ECODE_FAILED; } - if (cfile->output_dir) { - if (ConfSet("default-log-dir", cfile->output_dir) != 1) { - SCLogError(SC_ERR_INVALID_ARGUMENTS, - "Can not set output dir to '%s'", cfile->output_dir); - PcapFilesFree(cfile); - return TM_ECODE_FAILED; - } - } - if (cfile->tenant_id > 0) { - char tstr[16]; - snprintf(tstr, sizeof(tstr), "%d", cfile->tenant_id); - if (ConfSet("pcap-file.tenant-id", tstr) != 1) { - SCLogError(SC_ERR_INVALID_ARGUMENTS, - "Can not set working tenant-id to '%s'", tstr); - PcapFilesFree(cfile); - return TM_ECODE_FAILED; - } - } else { - SCLogInfo("pcap-file.tenant-id not set"); - } - this->currentfile = SCStrdup(cfile->filename); - if (unlikely(this->currentfile == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Failed file name allocation"); + } + if (cfile->tenant_id > 0) { + char tstr[16]; + snprintf(tstr, sizeof(tstr), "%d", cfile->tenant_id); + if (ConfSet("pcap-file.tenant-id", tstr) != 1) { + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "Can not set working tenant-id to '%s'", tstr); + PcapFilesFree(cfile); return TM_ECODE_FAILED; } - PcapFilesFree(cfile); - StatsInit(); -#ifdef PROFILING - SCProfilingRulesGlobalInit(); - SCProfilingKeywordsGlobalInit(); - SCProfilingSghsGlobalInit(); - SCProfilingInit(); -#endif /* PROFILING */ - DefragInit(); - FlowInitConfig(FLOW_QUIET); - IPPairInitConfig(FLOW_QUIET); - StreamTcpInitConfig(STREAM_VERBOSE); - AppLayerRegisterGlobalCounters(); - RunModeInitializeOutputs(); - StatsSetupPostConfig(); - RunModeDispatch(RUNMODE_PCAP_FILE, NULL); - FlowManagerThreadSpawn(); - FlowRecyclerThreadSpawn(); - StatsSpawnThreads(); - /* Un-pause all the paused threads */ - TmThreadContinueThreads(); + } else { + SCLogInfo("pcap-file.tenant-id not set"); } + this->currentfile = SCStrdup(cfile->filename); + if (unlikely(this->currentfile == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed file name allocation"); + return TM_ECODE_FAILED; + } + PcapFilesFree(cfile); + + PreRunInit(RUNMODE_PCAP_FILE); + PreRunPostPrivsDropInit(RUNMODE_PCAP_FILE); + RunModeDispatch(RUNMODE_PCAP_FILE, NULL); + + /* Un-pause all the paused threads */ + TmThreadContinueThreads(); return TM_ECODE_OK; } #endif diff --git a/src/runmodes.c b/src/runmodes.c index f98343c82e98..fdedea8f1886 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -50,6 +50,8 @@ #include "source-pfring.h" #include "tmqh-flow.h" +#include "flow-manager.h" +#include "counters.h" #ifdef __SC_CUDA_SUPPORT__ #include "util-cuda-buffer.h" @@ -392,7 +394,12 @@ void RunModeDispatch(int runmode, const char *custom_mode) /* Check if the alloted queues have at least 1 reader and writer */ TmValidateQueueState(); - return; + if (runmode != RUNMODE_UNIX_SOCKET) { + /* spawn management threads */ + FlowManagerThreadSpawn(); + FlowRecyclerThreadSpawn(); + StatsSpawnThreads(); + } } /** diff --git a/src/suricata.c b/src/suricata.c index 85d4bb5459b5..a12f8a91a1d7 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -211,7 +211,7 @@ intmax_t max_pending_packets; int g_detect_disabled = 0; /** set caps or not */ -int sc_set_caps; +int sc_set_caps = FALSE; int EngineModeIsIPS(void) { @@ -314,6 +314,12 @@ void CreateLowercaseTable() void GlobalInits() { +#ifdef __SC_CUDA_SUPPORT__ + /* Init the CUDA environment */ + SCCudaInitCudaEnvironment(); + CudaBufferInit(); +#endif + memset(trans_q, 0, sizeof(trans_q)); memset(data_queues, 0, sizeof(data_queues)); @@ -334,6 +340,9 @@ void GlobalInits() } CreateLowercaseTable(); + + TimeInit(); + SupportFastPatternForSigMatchTypes(); } /** \brief make sure threads can stop the engine by calling this @@ -1022,13 +1031,15 @@ static void SCSetStartTime(SCInstance *suri) gettimeofday(&suri->start_time, NULL); } -static void SCPrintElapsedTime(SCInstance *suri) +static void SCPrintElapsedTime(struct timeval *start_time) { + if (start_time == NULL) + return; struct timeval end_time; memset(&end_time, 0, sizeof(end_time)); gettimeofday(&end_time, NULL); - uint64_t milliseconds = ((end_time.tv_sec - suri->start_time.tv_sec) * 1000) + - (((1000000 + end_time.tv_usec - suri->start_time.tv_usec) / 1000) - 1000); + uint64_t milliseconds = ((end_time.tv_sec - start_time->tv_sec) * 1000) + + (((1000000 + end_time.tv_usec - start_time->tv_usec) / 1000) - 1000); SCLogInfo("time elapsed %.3fs", (float)milliseconds/(float)1000); } @@ -2032,6 +2043,89 @@ static int InitSignalHandler(SCInstance *suri) return TM_ECODE_OK; } +/* initialization code for both the main modes and for + * unix socket mode. + * + * Will be run once per pcap in unix-socket mode */ +void PreRunInit(const int runmode) +{ + if (runmode == RUNMODE_UNIX_SOCKET) + return; + + StatsInit(); +#ifdef PROFILING + SCProfilingRulesGlobalInit(); + SCProfilingKeywordsGlobalInit(); + SCProfilingSghsGlobalInit(); + SCProfilingInit(); +#endif /* PROFILING */ + DefragInit(); + FlowInitConfig(FLOW_QUIET); + IPPairInitConfig(FLOW_QUIET); + StreamTcpInitConfig(STREAM_VERBOSE); + AppLayerRegisterGlobalCounters(); +} + +/* tasks we need to run before packets start flowing, + * but after we dropped privs */ +void PreRunPostPrivsDropInit(const int runmode) +{ + if (runmode == RUNMODE_UNIX_SOCKET) + return; + + RunModeInitializeOutputs(); + StatsSetupPostConfig(); +} + +/* clean up / shutdown code for both the main modes and for + * unix socket mode. + * + * Will be run once per pcap in unix-socket mode */ +void PostRunDeinit(const int runmode, struct timeval *start_time) +{ + if (runmode == RUNMODE_UNIX_SOCKET) + return; + + /* needed by FlowForceReassembly */ + PacketPoolInit(); + + /* handle graceful shutdown of the flow engine, it's helper + * threads and the packet threads */ + FlowDisableFlowManagerThread(); + TmThreadDisableReceiveThreads(); + FlowForceReassembly(); + TmThreadDisablePacketThreads(); + SCPrintElapsedTime(start_time); + FlowDisableFlowRecyclerThread(); + + /* kill the stats threads */ + TmThreadKillThreadsFamily(TVT_MGMT); + TmThreadClearThreadsFamily(TVT_MGMT); + + /* kill packet threads -- already in 'disabled' state */ + TmThreadKillThreadsFamily(TVT_PPT); + TmThreadClearThreadsFamily(TVT_PPT); + + PacketPoolDestroy(); + + /* mgt and ppt threads killed, we can run non thread-safe + * shutdown functions */ + StatsReleaseResources(); + RunModeShutDown(); + FlowShutdown(); + IPPairShutdown(); + HostCleanup(); + StreamTcpFreeConfig(STREAM_VERBOSE); + DefragDestroy(); + TmqResetQueues(); +#ifdef PROFILING + if (profiling_rules_enabled) + SCProfilingDump(); + SCProfilingDestroy(); +#endif +} + + int StartInternalRunMode(SCInstance *suri, int argc, char **argv) { /* Treat internal running mode */ @@ -2319,9 +2413,6 @@ static int PostConfLoadedSetup(SCInstance *suri) /* Load the Host-OS lookup. */ SCHInfoLoadFromConfig(); - if (suri->run_mode != RUNMODE_UNIX_SOCKET) { - DefragInit(); - } if (suri->run_mode == RUNMODE_ENGINE_ANALYSIS) { SCLogInfo("== Carrying out Engine Analysis =="); @@ -2341,14 +2432,6 @@ static int PostConfLoadedSetup(SCInstance *suri) StorageInit(); CIDRInit(); SigParsePrepare(); -#ifdef PROFILING - if (suri->run_mode != RUNMODE_UNIX_SOCKET) { - SCProfilingRulesGlobalInit(); - SCProfilingKeywordsGlobalInit(); - SCProfilingSghsGlobalInit(); - SCProfilingInit(); - } -#endif /* PROFILING */ SCReputationInitCtx(); SCProtoNameInit(); @@ -2408,6 +2491,8 @@ static int PostConfLoadedSetup(SCInstance *suri) CoredumpLoadConfig(); + PreRunInit(suri->run_mode); + SCReturnInt(TM_ECODE_OK); } @@ -2418,25 +2503,16 @@ int main(int argc, char **argv) SCInstanceInit(&suri); suri.progname = argv[0]; - sc_set_caps = FALSE; - SC_ATOMIC_INIT(engine_stage); /* initialize the logging subsys */ SCLogInitLogModule(NULL); - if (SCSetThreadName("Suricata-Main") < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } + (void)SCSetThreadName("Suricata-Main"); ParseSizeInit(); - RunModeRegisterRunModes(); - /* By default use IDS mode, but if nfq or ipfw - * are specified, IPS mode will overwrite this */ - EngineModeSetIDS(); - #ifdef OS_WIN32 /* service initialization */ if (WindowsInit(argc, argv) != 0) { @@ -2462,19 +2538,8 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } -#ifdef __SC_CUDA_SUPPORT__ - /* Init the CUDA environment */ - SCCudaInitCudaEnvironment(); - CudaBufferInit(); -#endif - /* Initializations for global vars, queues, etc (memsets, mutex init..) */ GlobalInits(); - TimeInit(); - SupportFastPatternForSigMatchTypes(); - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - StatsInit(); - } /* Load yaml configuration file if provided. */ if (LoadYamlConfig(&suri) != TM_ECODE_OK) { @@ -2502,13 +2567,6 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - FlowInitConfig(FLOW_VERBOSE); - StreamTcpInitConfig(STREAM_VERBOSE); - IPPairInitConfig(IPPAIR_VERBOSE); - AppLayerRegisterGlobalCounters(); - } - DetectEngineCtx *de_ctx = NULL; if (!suri.disabled_detect) { SCClassConfInit(); @@ -2558,11 +2616,7 @@ int main(int argc, char **argv) SCSetStartTime(&suri); SCDropMainThreadCaps(suri.userid, suri.groupid); - - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - RunModeInitializeOutputs(); - StatsSetupPostConfig(); - } + PreRunPostPrivsDropInit(suri.run_mode); if (suri.run_mode == RUNMODE_CONF_TEST){ SCLogNotice("Configuration provided was successfully loaded. Exiting."); @@ -2573,23 +2627,8 @@ int main(int argc, char **argv) } RunModeDispatch(suri.run_mode, suri.runmode_custom_mode); - - /* In Unix socket runmode, Flow manager is started on demand */ if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - /* Spawn the unix socket manager thread */ - int unix_socket = ConfUnixSocketIsEnable(); - if (unix_socket == 1) { - UnixManagerThreadSpawn(0); -#ifdef BUILD_UNIX_SOCKET - UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL, - UNIX_CMD_TAKE_ARGS); - UnixManagerRegisterCommand("iface-list", LiveDeviceIfaceList, NULL, 0); -#endif - } - /* Spawn the flow manager thread */ - FlowManagerThreadSpawn(); - FlowRecyclerThreadSpawn(); - StatsSpawnThreads(); + UnixManagerThreadSpawnNonRunmode(); } /* Wait till all the threads have been initialized */ @@ -2617,7 +2656,6 @@ int main(int argc, char **argv) SCLogNotice("Signature(s) loaded, Detect thread(s) activated."); } - #ifdef DBG_MEM_ALLOC SCLogInfo("Memory used at startup: %"PRIdMAX, (intmax_t)global_mem); #ifdef DBG_MEM_ALLOC_SKIP_STARTUP @@ -2675,50 +2713,11 @@ int main(int argc, char **argv) (void) SC_ATOMIC_CAS(&engine_stage, SURICATA_RUNTIME, SURICATA_DEINIT); UnixSocketKillSocketThread(); - - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - /* First we need to disable the flow manager thread */ - FlowDisableFlowManagerThread(); - } - - - /* Disable packet acquisition first */ - TmThreadDisableReceiveThreads(); - - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - /* we need a packet pool for FlowForceReassembly */ - PacketPoolInit(); - - FlowForceReassembly(); - /* kill receive threads when they have processed all - * flow timeout packets */ - TmThreadDisablePacketThreads(); - } - - SCPrintElapsedTime(&suri); - - /* before TmThreadKillThreads, as otherwise that kills it - * but more slowly */ - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - FlowDisableFlowRecyclerThread(); - } - + PostRunDeinit(suri.run_mode, &suri.start_time); /* kill remaining threads */ TmThreadKillThreads(); - - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - /* destroy the packet pool for flow reassembly after all - * the other threads are gone. */ - PacketPoolDestroy(); - - StatsReleaseResources(); - IPPairShutdown(); - FlowShutdown(); - StreamTcpFreeConfig(STREAM_VERBOSE); - } HostShutdown(); - HTPFreeConfig(); HTPAtExitPrintStats(); @@ -2746,13 +2745,9 @@ int main(int argc, char **argv) TagDestroyCtx(); LiveDeviceListClean(); - RunModeShutDown(); OutputDeregisterAll(); TimeDeinit(); SCProtoNameDeInit(); - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - DefragDestroy(); - } if (!suri.disabled_detect) { SCReferenceConfDeinit(); SCClassConfDeinit(); @@ -2772,14 +2767,6 @@ int main(int argc, char **argv) AFPPeersListClean(); #endif -#ifdef PROFILING - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - if (profiling_rules_enabled) - SCProfilingDump(); - SCProfilingDestroy(); - } -#endif - #ifdef OS_WIN32 if (daemon) { return 0; diff --git a/src/suricata.h b/src/suricata.h index 2e92e634a66b..50c7b1f860a3 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -195,5 +195,9 @@ int IsRuleReloadSet(int quiet); extern int run_mode; +void PreRunInit(const int runmode); +void PreRunPostPrivsDropInit(const int runmode); +void PostRunDeinit(const int runmode, struct timeval *start_time); + #endif /* __SURICATA_H__ */ diff --git a/src/unix-manager.c b/src/unix-manager.c index 79dc5f7dc834..559a8b398019 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -31,8 +31,8 @@ #include "util-privs.h" #include "util-debug.h" +#include "util-device.h" #include "util-signal.h" - #include "util-buffer.h" #include @@ -1011,6 +1011,19 @@ void UnixManagerThreadSpawn(int mode) return; } +// TODO can't think of a good name +void UnixManagerThreadSpawnNonRunmode(void) +{ + /* Spawn the unix socket manager thread */ + int unix_socket = ConfUnixSocketIsEnable(); + if (unix_socket == 1) { + UnixManagerThreadSpawn(0); + UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL, + UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("iface-list", LiveDeviceIfaceList, NULL, 0); + } +} + /** * \brief Used to kill unix manager thread(s). * @@ -1065,6 +1078,11 @@ void UnixSocketKillSocketThread(void) return; } +void UnixManagerThreadSpawnNonRunmode(void) +{ + return; +} + #endif /* BUILD_UNIX_SOCKET */ void TmModuleUnixManagerRegister (void) diff --git a/src/unix-manager.h b/src/unix-manager.h index 848da76137d6..5ec3c889e348 100644 --- a/src/unix-manager.h +++ b/src/unix-manager.h @@ -36,7 +36,6 @@ SCCtrlMutex unix_manager_ctrl_mutex; void UnixManagerThreadSpawn(int mode); void UnixSocketKillSocketThread(void); - #ifdef BUILD_UNIX_SOCKET TmEcode UnixManagerRegisterCommand(const char * keyword, TmEcode (*Func)(json_t *, json_t *, void *), @@ -47,5 +46,6 @@ TmEcode UnixManagerRegisterBackgroundTask( #endif void TmModuleUnixManagerRegister(void); +void UnixManagerThreadSpawnNonRunmode(void); #endif /* UNIX_MANAGER_H */ From f452df761ac0b0c0625a37c5748b8bc4c9330a29 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Jan 2017 09:34:57 +0100 Subject: [PATCH 2294/2553] shutdown: move global shutdown steps into func --- src/suricata.c | 145 +++++++++++++++++++++++++------------------------ src/suricata.h | 2 +- 2 files changed, 76 insertions(+), 71 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index a12f8a91a1d7..d050175cf62c 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -312,7 +312,7 @@ void CreateLowercaseTable() } } -void GlobalInits() +void GlobalsInitPreConfig() { #ifdef __SC_CUDA_SUPPORT__ /* Init the CUDA environment */ @@ -345,6 +345,77 @@ void GlobalInits() SupportFastPatternForSigMatchTypes(); } +void GlobalsDestroy(SCInstance *suri) +{ + HostShutdown(); + HTPFreeConfig(); + HTPAtExitPrintStats(); + +#ifdef DBG_MEM_ALLOC + SCLogInfo("Total memory used (without SCFree()): %"PRIdMAX, (intmax_t)global_mem); +#ifdef DBG_MEM_ALLOC_SKIP_STARTUP + print_mem_flag = 0; +#endif +#endif + + SCPidfileRemove(suri->pid_filename); + + AppLayerHtpPrintStats(); + + /* TODO this can do into it's own func */ + DetectEngineCtx *de_ctx = DetectEngineGetCurrent(); + if (de_ctx) { + DetectEngineMoveToFreeList(de_ctx); + DetectEngineDeReference(&de_ctx); + } + DetectEnginePruneFreeList(); + + AppLayerDeSetup(); + + TagDestroyCtx(); + + LiveDeviceListClean(); + OutputDeregisterAll(); + TimeDeinit(); + SCProtoNameDeInit(); + if (!suri->disabled_detect) { + SCReferenceConfDeinit(); + SCClassConfDeinit(); + } +#ifdef HAVE_MAGIC + MagicDeinit(); +#endif + TmqhCleanup(); + TmModuleRunDeInit(); + ParseSizeDeinit(); +#ifdef HAVE_NSS + NSS_Shutdown(); + PR_Cleanup(); +#endif + +#ifdef HAVE_AF_PACKET + AFPPeersListClean(); +#endif + + SC_ATOMIC_DESTROY(engine_stage); + +#ifdef BUILD_HYPERSCAN + MpmHSGlobalCleanup(); +#endif + +#ifdef __SC_CUDA_SUPPORT__ + if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) + MpmCudaBufferDeSetup(); + CudaHandlerFreeProfiles(); +#endif + ConfDeInit(); +#ifdef HAVE_LUAJIT + LuajitFreeStatesPool(); +#endif + SCLogDeInitLogModule(); + DetectParseFreeRegexes(); +} + /** \brief make sure threads can stop the engine by calling this * function. Purpose: pcap file mode needs to be able to tell the * engine the file eof is reached. */ @@ -2539,7 +2610,7 @@ int main(int argc, char **argv) } /* Initializations for global vars, queues, etc (memsets, mutex init..) */ - GlobalInits(); + GlobalsInitPreConfig(); /* Load yaml configuration file if provided. */ if (LoadYamlConfig(&suri) != TM_ECODE_OK) { @@ -2613,8 +2684,6 @@ int main(int argc, char **argv) RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveLogOnly); } - SCSetStartTime(&suri); - SCDropMainThreadCaps(suri.userid, suri.groupid); PreRunPostPrivsDropInit(suri.run_mode); @@ -2626,6 +2695,7 @@ int main(int argc, char **argv) exit(EXIT_SUCCESS); } + SCSetStartTime(&suri); RunModeDispatch(suri.run_mode, suri.runmode_custom_mode); if (suri.run_mode != RUNMODE_UNIX_SOCKET) { UnixManagerThreadSpawnNonRunmode(); @@ -2717,55 +2787,7 @@ int main(int argc, char **argv) /* kill remaining threads */ TmThreadKillThreads(); - HostShutdown(); - HTPFreeConfig(); - HTPAtExitPrintStats(); - -#ifdef DBG_MEM_ALLOC - SCLogInfo("Total memory used (without SCFree()): %"PRIdMAX, (intmax_t)global_mem); -#ifdef DBG_MEM_ALLOC_SKIP_STARTUP - print_mem_flag = 0; -#endif -#endif - - SCPidfileRemove(suri.pid_filename); - - AppLayerHtpPrintStats(); - - /** TODO this can do into it's own func */ - de_ctx = DetectEngineGetCurrent(); - if (de_ctx) { - DetectEngineMoveToFreeList(de_ctx); - DetectEngineDeReference(&de_ctx); - } - DetectEnginePruneFreeList(); - - AppLayerDeSetup(); - - TagDestroyCtx(); - - LiveDeviceListClean(); - OutputDeregisterAll(); - TimeDeinit(); - SCProtoNameDeInit(); - if (!suri.disabled_detect) { - SCReferenceConfDeinit(); - SCClassConfDeinit(); - } -#ifdef HAVE_MAGIC - MagicDeinit(); -#endif - TmqhCleanup(); - TmModuleRunDeInit(); - ParseSizeDeinit(); -#ifdef HAVE_NSS - NSS_Shutdown(); - PR_Cleanup(); -#endif - -#ifdef HAVE_AF_PACKET - AFPPeersListClean(); -#endif + GlobalsDestroy(&suri); #ifdef OS_WIN32 if (daemon) { @@ -2773,22 +2795,5 @@ int main(int argc, char **argv) } #endif /* OS_WIN32 */ - SC_ATOMIC_DESTROY(engine_stage); - -#ifdef BUILD_HYPERSCAN - MpmHSGlobalCleanup(); -#endif - -#ifdef __SC_CUDA_SUPPORT__ - if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) - MpmCudaBufferDeSetup(); - CudaHandlerFreeProfiles(); -#endif - ConfDeInit(); -#ifdef HAVE_LUAJIT - LuajitFreeStatesPool(); -#endif - SCLogDeInitLogModule(); - DetectParseFreeRegexes(); exit(engine_retval); } diff --git a/src/suricata.h b/src/suricata.h index 50c7b1f860a3..42482bb03394 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -169,7 +169,7 @@ typedef struct SCInstance_ { /* memset to zeros, and mutex init! */ -void GlobalInits(); +void GlobalsInitPreConfig(); extern volatile uint8_t suricata_ctl_flags; From 2eec07cc3abb1cf10ece854db501d3e82725eef0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Jan 2017 09:51:15 +0100 Subject: [PATCH 2295/2553] unittests: clean up registration and startup --- src/runmode-unittests.c | 141 ++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 70 deletions(-) diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 4f03f18486d1..b24c078fc470 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -128,77 +128,9 @@ void RegisterAllModules(); void TmqhSetup (void); -/** - * Run or list unittests - * - * \param list_unittests If set to 1, list unittests. Run them if set to 0. - * \param regex_arg A regular expression to select unittests to run - * - * This function is terminal and will call exit after being called. - */ - -void RunUnittests(int list_unittests, char *regex_arg) -{ #ifdef UNITTESTS - /* Initializations for global vars, queues, etc (memsets, mutex init..) */ - GlobalInits(); - TimeInit(); - SupportFastPatternForSigMatchTypes(); -#ifdef HAVE_LUAJIT - if (LuajitSetupStatesPool() != 0) { - exit(EXIT_FAILURE); - } -#endif - - default_packet_size = DEFAULT_PACKET_SIZE; -#ifdef __SC_CUDA_SUPPORT__ - /* Init the CUDA environment */ - SCCudaInitCudaEnvironment(); - CudaBufferInit(); -#endif - /* load the pattern matchers */ - MpmTableSetup(); -#ifdef __SC_CUDA_SUPPORT__ - MpmCudaEnvironmentSetup(); -#endif - SpmTableSetup(); - - AppLayerSetup(); - - /* hardcoded initialization code */ - SigTableSetup(); /* load the rule keywords */ - TmqhSetup(); - - StorageInit(); - CIDRInit(); - SigParsePrepare(); - -#ifdef DBG_MEM_ALLOC - SCLogInfo("Memory used at startup: %"PRIdMAX, (intmax_t)global_mem); -#endif - SCReputationInitCtx(); - SCProtoNameInit(); - - TagInitCtx(); - SCReferenceConfInit(); - SCClassConfInit(); - - UtInitialize(); - - RegisterAllModules(); - - HostBitInitCtx(); - - StorageFinalize(); - /* test and initialize the unittesting subsystem */ - if(regex_arg == NULL){ - regex_arg = ".*"; - UtRunSelftest(regex_arg); /* inits and cleans up again */ - } - - AppLayerHtpEnableRequestBodyCallback(); - AppLayerHtpNeedFileInspection(); - +static void RegisterUnittests(void) +{ UTHRegisterTests(); StreamTcpRegisterTests(); SigRegisterTests(); @@ -290,6 +222,75 @@ void RunUnittests(int list_unittests, char *regex_arg) AppLayerUnittestsRegister(); MimeDecRegisterTests(); StreamingBufferRegisterTests(); +} +#endif + +/** + * Run or list unittests + * + * \param list_unittests If set to 1, list unittests. Run them if set to 0. + * \param regex_arg A regular expression to select unittests to run + * + * This function is terminal and will call exit after being called. + */ + +void RunUnittests(int list_unittests, char *regex_arg) +{ +#ifdef UNITTESTS + /* Initializations for global vars, queues, etc (memsets, mutex init..) */ + GlobalsInitPreConfig(); + +#ifdef HAVE_LUAJIT + if (LuajitSetupStatesPool() != 0) { + exit(EXIT_FAILURE); + } +#endif + + default_packet_size = DEFAULT_PACKET_SIZE; + /* load the pattern matchers */ + MpmTableSetup(); +#ifdef __SC_CUDA_SUPPORT__ + MpmCudaEnvironmentSetup(); +#endif + SpmTableSetup(); + + AppLayerSetup(); + + /* hardcoded initialization code */ + SigTableSetup(); /* load the rule keywords */ + TmqhSetup(); + + StorageInit(); + CIDRInit(); + SigParsePrepare(); + +#ifdef DBG_MEM_ALLOC + SCLogInfo("Memory used at startup: %"PRIdMAX, (intmax_t)global_mem); +#endif + SCReputationInitCtx(); + SCProtoNameInit(); + + TagInitCtx(); + SCReferenceConfInit(); + SCClassConfInit(); + + UtInitialize(); + + RegisterAllModules(); + + HostBitInitCtx(); + + StorageFinalize(); + /* test and initialize the unittesting subsystem */ + if(regex_arg == NULL){ + regex_arg = ".*"; + UtRunSelftest(regex_arg); /* inits and cleans up again */ + } + + AppLayerHtpEnableRequestBodyCallback(); + AppLayerHtpNeedFileInspection(); + + RegisterUnittests(); if (list_unittests) { UtListTests(regex_arg); From 816dd7b30109d78b0044c6d71772223bb080812f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 25 Jan 2017 10:13:46 +0100 Subject: [PATCH 2296/2553] startup: clean up main loop --- src/suricata.c | 235 +++++++++++++++++++++++++------------------------ 1 file changed, 121 insertions(+), 114 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index d050175cf62c..f3ca71c1e2ce 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1037,10 +1037,11 @@ static TmEcode ParseInterfacesList(int runmode, char *pcap_dev) SCReturnInt(TM_ECODE_OK); } -static void SCInstanceInit(SCInstance *suri) +static void SCInstanceInit(SCInstance *suri, const char *progname) { memset(suri, 0x00, sizeof(*suri)); + suri->progname = progname; suri->run_mode = RUNMODE_UNKNOWN; memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); @@ -2383,6 +2384,72 @@ static int ConfigGetCaptureValue(SCInstance *suri) return TM_ECODE_OK; } + +static void PostRunStartedDetectSetup(SCInstance *suri) +{ + /* registering signal handlers we use. We register usr2 here, so that one + * can't call it during the first sig load phase or while threads are still + * starting up. */ + if (DetectEngineEnabled() && suri->sig_file == NULL && + suri->delayed_detect == 0) + UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); + + if (suri->delayed_detect) { + /* force 'reload', this will load the rules and swap engines */ + DetectEngineReload(suri); + SCLogNotice("Signature(s) loaded, Detect thread(s) activated."); + } +} + +static void PostConfLoadedDetectSetup(SCInstance *suri) +{ + DetectEngineCtx *de_ctx = NULL; + if (!suri->disabled_detect) { + SCClassConfInit(); + SCReferenceConfInit(); + SetupDelayedDetect(suri); + int mt_enabled = 0; + (void)ConfGetBool("multi-detect.enabled", &mt_enabled); + int default_tenant = 0; + if (mt_enabled) + (void)ConfGetBool("multi-detect.default", &default_tenant); + if (DetectEngineMultiTenantSetup() == -1) { + SCLogError(SC_ERR_INITIALIZATION, "initializing multi-detect " + "detection engine contexts failed."); + exit(EXIT_FAILURE); + } + if ((suri->delayed_detect || (mt_enabled && !default_tenant)) && + (suri->run_mode != RUNMODE_CONF_TEST)) { + de_ctx = DetectEngineCtxInitMinimal(); + } else { + de_ctx = DetectEngineCtxInit(); + } + if (de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " + "context failed."); + exit(EXIT_FAILURE); + } + +#ifdef __SC_CUDA_SUPPORT__ + if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) + CudaVarsSetDeCtx(de_ctx); +#endif /* __SC_CUDA_SUPPORT__ */ + + if (!de_ctx->minimal) { + if (LoadSignatures(de_ctx, suri) != TM_ECODE_OK) + exit(EXIT_FAILURE); + if (suri->run_mode == RUNMODE_ENGINE_ANALYSIS) { + exit(EXIT_SUCCESS); + } + } + + DetectEngineAddToMaster(de_ctx); + } else { + /* tell the app layer to consider only the log id */ + RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveLogOnly); + } +} + /** * This function is meant to contain code that needs * to be run once the configuration has been loaded. @@ -2567,12 +2634,58 @@ static int PostConfLoadedSetup(SCInstance *suri) SCReturnInt(TM_ECODE_OK); } +static void SuricataMainLoop(SCInstance *suri) +{ + while(1) { + if (sigterm_count || sigint_count) { + suricata_ctl_flags |= SURICATA_STOP; + } + + if (suricata_ctl_flags & SURICATA_STOP) { + SCLogNotice("Signal Received. Stopping engine."); + break; + } + + TmThreadCheckThreadState(); + + if (sighup_count > 0) { + OutputNotifyFileRotation(); + sighup_count--; + } + + if (sigusr2_count > 0) { + if (suri->sig_file != NULL) { + SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload not " + "possible if -s or -S option used at runtime."); + sigusr2_count--; + } else { + if (!(DetectEngineReloadIsStart())) { + DetectEngineReloadStart(); + DetectEngineReload(suri); + DetectEngineReloadSetDone(); + sigusr2_count--; + } + } + + } else if (DetectEngineReloadIsStart()) { + if (suri->sig_file != NULL) { + SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload not " + "possible if -s or -S option used at runtime."); + DetectEngineReloadSetDone(); + } else { + DetectEngineReload(suri); + DetectEngineReloadSetDone(); + } + } + + usleep(10* 1000); + } +} + int main(int argc, char **argv) { SCInstance suri; - - SCInstanceInit(&suri); - suri.progname = argv[0]; + SCInstanceInit(&suri, argv[0]); SC_ATOMIC_INIT(engine_stage); @@ -2627,7 +2740,6 @@ int main(int argc, char **argv) SCLogLoadConfig(suri.daemon, suri.verbose); SCPrintVersion(); - UtilCpuPrintSummary(); if (ParseInterfacesList(suri.run_mode, suri.pcap_dev) != TM_ECODE_OK) { @@ -2637,52 +2749,7 @@ int main(int argc, char **argv) if (PostConfLoadedSetup(&suri) != TM_ECODE_OK) { exit(EXIT_FAILURE); } - - DetectEngineCtx *de_ctx = NULL; - if (!suri.disabled_detect) { - SCClassConfInit(); - SCReferenceConfInit(); - SetupDelayedDetect(&suri); - int mt_enabled = 0; - (void)ConfGetBool("multi-detect.enabled", &mt_enabled); - int default_tenant = 0; - if (mt_enabled) - (void)ConfGetBool("multi-detect.default", &default_tenant); - if (DetectEngineMultiTenantSetup() == -1) { - SCLogError(SC_ERR_INITIALIZATION, "initializing multi-detect " - "detection engine contexts failed."); - exit(EXIT_FAILURE); - } - if ((suri.delayed_detect || (mt_enabled && !default_tenant)) && - (suri.run_mode != RUNMODE_CONF_TEST)) { - de_ctx = DetectEngineCtxInitMinimal(); - } else { - de_ctx = DetectEngineCtxInit(); - } - if (de_ctx == NULL) { - SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " - "context failed."); - exit(EXIT_FAILURE); - } - -#ifdef __SC_CUDA_SUPPORT__ - if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) - CudaVarsSetDeCtx(de_ctx); -#endif /* __SC_CUDA_SUPPORT__ */ - - if (!de_ctx->minimal) { - if (LoadSignatures(de_ctx, &suri) != TM_ECODE_OK) - exit(EXIT_FAILURE); - if (suri.run_mode == RUNMODE_ENGINE_ANALYSIS) { - exit(EXIT_SUCCESS); - } - } - - DetectEngineAddToMaster(de_ctx); - } else { - /* tell the app layer to consider only the log id */ - RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveLogOnly); - } + PostConfLoadedDetectSetup(&suri); SCDropMainThreadCaps(suri.userid, suri.groupid); PreRunPostPrivsDropInit(suri.run_mode); @@ -2713,18 +2780,8 @@ int main(int argc, char **argv) /* Un-pause all the paused threads */ TmThreadContinueThreads(); - /* registering singal handlers we use. We register usr2 here, so that one - * can't call it during the first sig load phase or while threads are still - * starting up. */ - if (DetectEngineEnabled() && suri.sig_file == NULL && - suri.delayed_detect == 0) - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - if (suri.delayed_detect) { - /* force 'reload', this will load the rules and swap engines */ - DetectEngineReload(&suri); - SCLogNotice("Signature(s) loaded, Detect thread(s) activated."); - } + PostRunStartedDetectSetup(&suri); #ifdef DBG_MEM_ALLOC SCLogInfo("Memory used at startup: %"PRIdMAX, (intmax_t)global_mem); @@ -2733,51 +2790,7 @@ int main(int argc, char **argv) #endif #endif - int engine_retval = EXIT_SUCCESS; - while(1) { - if (sigterm_count || sigint_count) { - suricata_ctl_flags |= SURICATA_STOP; - } - - if (suricata_ctl_flags & SURICATA_STOP) { - SCLogNotice("Signal Received. Stopping engine."); - break; - } - - TmThreadCheckThreadState(); - - if (sighup_count > 0) { - OutputNotifyFileRotation(); - sighup_count--; - } - - if (sigusr2_count > 0) { - if (suri.sig_file != NULL) { - SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload not " - "possible if -s or -S option used at runtime."); - sigusr2_count--; - } else { - if (!(DetectEngineReloadIsStart())) { - DetectEngineReloadStart(); - DetectEngineReload(&suri); - DetectEngineReloadSetDone(); - sigusr2_count--; - } - } - - } else if (DetectEngineReloadIsStart()) { - if (suri.sig_file != NULL) { - SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload not " - "possible if -s or -S option used at runtime."); - DetectEngineReloadSetDone(); - } else { - DetectEngineReload(&suri); - DetectEngineReloadSetDone(); - } - } - - usleep(10* 1000); - } + SuricataMainLoop(&suri); /* Update the engine stage/status flag */ (void) SC_ATOMIC_CAS(&engine_stage, SURICATA_RUNTIME, SURICATA_DEINIT); @@ -2789,11 +2802,5 @@ int main(int argc, char **argv) GlobalsDestroy(&suri); -#ifdef OS_WIN32 - if (daemon) { - return 0; - } -#endif /* OS_WIN32 */ - - exit(engine_retval); + exit(EXIT_SUCCESS); } From 7ca466c5989f92ed2f54c5c4d7809ef05104777c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 Jan 2017 10:15:59 +0100 Subject: [PATCH 2297/2553] shutdown: remove pid file last --- src/suricata.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index f3ca71c1e2ce..dc5f55c48fd9 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -358,8 +358,6 @@ void GlobalsDestroy(SCInstance *suri) #endif #endif - SCPidfileRemove(suri->pid_filename); - AppLayerHtpPrintStats(); /* TODO this can do into it's own func */ @@ -414,6 +412,8 @@ void GlobalsDestroy(SCInstance *suri) #endif SCLogDeInitLogModule(); DetectParseFreeRegexes(); + + SCPidfileRemove(suri->pid_filename); } /** \brief make sure threads can stop the engine by calling this From 1ba15d3721343a670436ea7363b050702bb2f043 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 27 Jan 2017 10:03:39 +0100 Subject: [PATCH 2298/2553] mtu: track max mtu for capture devices --- src/decode.h | 6 +++++- src/suricata.c | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/decode.h b/src/decode.h index b84f466e0abd..aa21f1a8adf1 100644 --- a/src/decode.h +++ b/src/decode.h @@ -594,7 +594,11 @@ typedef struct Packet_ #endif Packet; -#define DEFAULT_PACKET_SIZE (1500 + ETHERNET_HEADER_LEN) +/** highest mtu of the interfaces we monitor */ +extern int g_default_mtu; +#define DEFAULT_MTU 1500 + +#define DEFAULT_PACKET_SIZE (DEFAULT_MTU + ETHERNET_HEADER_LEN) /* storage: maximum ip packet size + link header */ #define MAX_PAYLOAD_SIZE (IPV6_HEADER_LEN + 65536 + 28) uint32_t default_packet_size; diff --git a/src/suricata.c b/src/suricata.c index dc5f55c48fd9..2d2a5c2872ea 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -213,6 +213,9 @@ int g_detect_disabled = 0; /** set caps or not */ int sc_set_caps = FALSE; +/** highest mtu of the interfaces we monitor */ +int g_default_mtu = 0; + int EngineModeIsIPS(void) { return (g_engine_mode == ENGINE_MODE_IPS); @@ -2360,6 +2363,8 @@ static int ConfigGetCaptureValue(SCInstance *suri) dev[len-1] = '\0'; } } + int mtu = GetIfaceMTU(dev); + g_default_mtu = MAX(mtu, g_default_mtu); unsigned int iface_max_packet_size = GetIfaceMaxPacketSize(dev); if (iface_max_packet_size > default_packet_size) @@ -2369,6 +2374,7 @@ static int ConfigGetCaptureValue(SCInstance *suri) break; /* fall through */ default: + g_default_mtu = DEFAULT_MTU; default_packet_size = DEFAULT_PACKET_SIZE; } } else { From a0580d8805cfd74b8a216d9f8d3906ebe7e41cf0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 26 Jan 2017 18:05:11 +0100 Subject: [PATCH 2299/2553] stream: initialize stream segment pool from mtu If segments section in the yaml is ommitted (default) or when the pool size is set to 'from_mtu', the size of the pool will be MTU minus 40. If the MTU couldn't be determined, it's assumed to be 1500, so the segment size for the bool will be 1460. --- src/decode.h | 1 + src/stream-tcp-reassemble.c | 27 ++++++++++++++++++++------- suricata.yaml.in | 4 +++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/decode.h b/src/decode.h index aa21f1a8adf1..85b4faf5601c 100644 --- a/src/decode.h +++ b/src/decode.h @@ -597,6 +597,7 @@ Packet; /** highest mtu of the interfaces we monitor */ extern int g_default_mtu; #define DEFAULT_MTU 1500 +#define MINIMUM_MTU 68 /**< ipv4 minimum: rfc791 */ #define DEFAULT_PACKET_SIZE (DEFAULT_MTU + ETHERNET_HEADER_LEN) /* storage: maximum ip packet size + link header */ diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 1b5e42c0b480..a3896435ae67 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -344,12 +344,21 @@ int StreamTcpReassemblyConfig(char quiet) SCLogDebug("segpre->val %s", segpre->val); uint16_t pktsize = 0; - if (ByteExtractStringUint16(&pktsize, 10, strlen(segsize->val), - segsize->val) == -1) - { - SCLogError(SC_ERR_INVALID_ARGUMENT, "segment packet size " - "of %s is invalid", segsize->val); - return -1; + if (strcmp("from_mtu", segsize->val) == 0) { + int mtu = g_default_mtu ? g_default_mtu : DEFAULT_MTU; + if (mtu < MINIMUM_MTU) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, "invalid mtu %d", mtu); + continue; + } + pktsize = mtu - 40; + } else { + if (ByteExtractStringUint16(&pktsize, 10, strlen(segsize->val), + segsize->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "segment packet size " + "of %s is invalid", segsize->val); + return -1; + } } uint32_t prealloc = 0; if (ByteExtractStringUint32(&prealloc, 10, strlen(segpre->val), @@ -379,6 +388,10 @@ int StreamTcpReassemblyConfig(char quiet) SCLogConfig("appended a segment pool for pktsize 65536"); } } else if (npools == 0) { + int mtu = g_default_mtu; + if (mtu < MINIMUM_MTU) + mtu = DEFAULT_MTU; + /* defaults */ sizes[0].pktsize = 4; sizes[0].prealloc = 256; @@ -392,7 +405,7 @@ int StreamTcpReassemblyConfig(char quiet) sizes[4].prealloc = 512; sizes[5].pktsize = 768; sizes[5].prealloc = 1024; - sizes[6].pktsize = 1448; + sizes[6].pktsize = mtu - 40; // min size of ipv4+tcp hdrs sizes[6].prealloc = 1024; sizes[7].pktsize = 0xffff; sizes[7].prealloc = 128; diff --git a/suricata.yaml.in b/suricata.yaml.in index b733ea1b108b..caecd0798ac8 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1220,7 +1220,9 @@ stream: # prealloc: 512 # - size: 768 # prealloc: 1024 - # - size: 1448 + # 'from_mtu' means that the size is mtu - 40, + # or 1460 if mtu couldn't be determined. + # - size: from_mtu # prealloc: 1024 # - size: 65535 # prealloc: 128 From e6044aaf1c572b7ef1655bdb8b122db9d8295bf1 Mon Sep 17 00:00:00 2001 From: Sascha Steinbiss Date: Fri, 20 Jan 2017 15:28:41 +0100 Subject: [PATCH 2300/2553] mpm/spm: check for SSSE3 and enable/disable HS The new Hyperscan 4.4 API provides a function to check for SSSE3 presence at runtime. This allows us to fall back to non-Hyperscan matchers on systems without SSSE3 even when the suricata executable is built with Hyperscan support. Addresses Redmine issue #2010. Signed-off-by: Sascha Steinbiss Tested-by: Arturo Borrero Gonzalez --- configure.ac | 1 + src/app-layer-detect-proto.c | 2 +- src/app-layer-smtp.c | 2 +- src/detect-csum.c | 2 +- src/detect-dns-query.c | 14 ++++---- src/detect-engine-mpm.c | 2 +- src/detect-engine-payload.c | 68 +++++++++++++++++------------------ src/detect-http-header.c | 2 +- src/detect-ipproto.c | 4 +-- src/detect-tls-cert-issuer.c | 2 +- src/detect-tls-cert-subject.c | 2 +- src/detect-tls-sni.c | 4 +-- src/util-mpm.c | 36 ++++++++++++++++++- src/util-mpm.h | 13 +------ src/util-spm.c | 26 ++++++++++++-- 15 files changed, 113 insertions(+), 67 deletions(-) diff --git a/configure.ac b/configure.ac index b216aa78c008..f2e7ffcb5ee3 100644 --- a/configure.ac +++ b/configure.ac @@ -622,6 +622,7 @@ fi AC_CHECK_LIB(hs,hs_compile,,HYPERSCAN="no") + AC_CHECK_FUNCS(hs_valid_platform) enable_hyperscan="yes" if test "$HYPERSCAN" = "no"; then echo diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 9563ffb1fdc5..1ec0d4c1b4b9 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1550,7 +1550,7 @@ int AppLayerProtoDetectSetup(void) #ifdef __SC_CUDA_SUPPORT__ /* CUDA won't work here, so fall back to AC */ if (mpm_matcher == MPM_AC_CUDA) - mpm_matcher = DEFAULT_MPM; + mpm_matcher = mpm_default_matcher; #endif alpd_ctx.spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index f1e9aecb83d7..c12eee7359b3 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -157,7 +157,7 @@ typedef struct SMTPThreadCtx_ { PrefilterRuleStore *pmq; } SMTPThreadCtx; -#define SMTP_MPM DEFAULT_MPM +#define SMTP_MPM mpm_default_matcher static MpmCtx *smtp_mpm_ctx = NULL; diff --git a/src/detect-csum.c b/src/detect-csum.c index 4a338f5409b7..badeebb51206 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -1544,7 +1544,7 @@ int DetectCsumICMPV6Test01(void) printf("DetectEngineCtxInit failure\n"); goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 54de91204ce7..92c610c976b4 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -153,7 +153,7 @@ static int DetectDnsQueryTest01(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -286,7 +286,7 @@ static int DetectDnsQueryTest02(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -441,7 +441,7 @@ static int DetectDnsQueryTest03(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -548,7 +548,7 @@ static int DetectDnsQueryTest04(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -714,7 +714,7 @@ static int DetectDnsQueryTest05(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -887,7 +887,7 @@ static int DetectDnsQueryTest06(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -1034,7 +1034,7 @@ static int DetectDnsQueryTest07(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 87e63b8862de..1faa66a2aca6 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -343,7 +343,7 @@ int SignatureHasStreamContent(const Signature *s) uint16_t PatternMatchDefaultMatcher(void) { char *mpm_algo; - uint16_t mpm_algo_val = DEFAULT_MPM; + uint16_t mpm_algo_val = mpm_default_matcher; /* Get the mpm algo defined in config file by the user */ if ((ConfGet("mpm-algo", &mpm_algo)) == 1) { diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index a16e8a0e3e6d..70351e9aa4dc 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -214,7 +214,7 @@ static int PayloadTestSig01 (void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"abc\"; content:\"d\"; distance:0; within:1; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -236,7 +236,7 @@ static int PayloadTestSig02 (void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"abc\"; nocase; content:\"d\"; distance:0; within:1; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -258,7 +258,7 @@ static int PayloadTestSig03 (void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"aBc\"; nocase; content:\"abca\"; distance:-10; within:4; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -283,7 +283,7 @@ static int PayloadTestSig04(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"this\"; content:\"is\"; within:6; content:\"big\"; within:8; " "content:\"string\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -308,7 +308,7 @@ static int PayloadTestSig05(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"this\"; content:\"is\"; within:9; content:\"big\"; within:12; " "content:\"string\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -333,7 +333,7 @@ static int PayloadTestSig06(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"now\"; content:\"this\"; content:\"is\"; within:12; content:\"big\"; within:8; " "content:\"string\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -358,7 +358,7 @@ static int PayloadTestSig07(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"thus\"; offset:8; content:\"is\"; within:6; content:\"big\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -384,7 +384,7 @@ static int PayloadTestSig08(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"fix\"; content:\"this\"; within:6; content:!\"and\"; distance:0; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) != 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 1) { goto end; } @@ -408,7 +408,7 @@ static int PayloadTestSig09(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "pcre:/super/; content:\"nova\"; within:7; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -433,7 +433,7 @@ static int PayloadTestSig10(void) char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "byte_test:4,>,2,0,relative; sid:11;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1) { result = 0; goto end; } @@ -458,7 +458,7 @@ static int PayloadTestSig11(void) char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "byte_jump:1,0,relative; sid:11;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1) { result = 0; goto end; } @@ -483,7 +483,7 @@ static int PayloadTestSig12(void) char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "isdataat:10,relative; sid:11;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1) { result = 0; goto end; } @@ -523,7 +523,7 @@ static int PayloadTestSig13(void) uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; - uint16_t mpm_type = DEFAULT_MPM; + uint16_t mpm_type = mpm_default_matcher; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"aa\"; content:\"aa\"; distance:0; content:\"aa\"; distance:0; " @@ -605,7 +605,7 @@ static int PayloadTestSig14(void) //char sig[] = "alert tcp any any -> any any (content:\"User-Agent: Mozilla/5.0 (Macintosh; \"; content:\"Firefox/3.\"; distance:0; content:!\"Firefox/3.6.12\"; distance:-10; content:!\"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b4) Gecko/20090423 Firefox/3.6 GTB5\"; sid:1; rev:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1) { goto end; } @@ -626,7 +626,7 @@ static int PayloadTestSig15(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; isdataat:18,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -649,7 +649,7 @@ static int PayloadTestSig16(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; isdataat:!20,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -673,7 +673,7 @@ static int PayloadTestSig17(void) "content:\"%\"; depth:4; offset:0; " "content:\"%\"; within:2; distance:1; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -702,7 +702,7 @@ static int PayloadTestSig18(void) "byte_extract:1,2,one,string,dec,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -731,7 +731,7 @@ static int PayloadTestSig19(void) "byte_extract:1,2,one,string,hex,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -760,7 +760,7 @@ static int PayloadTestSig20(void) "byte_extract:1,2,one,string,dec,relative; " "content:\"|06 35 07 08|\"; offset:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -789,7 +789,7 @@ static int PayloadTestSig21(void) "byte_extract:1,2,one,string,dec,relative; " "content:\"|03 04 05 06|\"; depth:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -818,7 +818,7 @@ static int PayloadTestSig22(void) "byte_extract:1,2,one,string,dec,relative; " "content:\"|09 0A 0B 0C|\"; within:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -848,7 +848,7 @@ static int PayloadTestSig23(void) "byte_extract:1,3,two,string,dec,relative; " "byte_test:1,=,one,two,string,dec,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -878,7 +878,7 @@ static int PayloadTestSig24(void) "byte_jump:1,one,string,dec,relative; " "content:\"|0D 0E 0F|\"; distance:0; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -910,7 +910,7 @@ static int PayloadTestSig25(void) "byte_extract:1,-4,one,string,dec,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -942,7 +942,7 @@ static int PayloadTestSig26(void) "byte_extract:1,-3000,one,string,dec,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) != 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 0) { result = 0; goto end; } @@ -970,7 +970,7 @@ static int PayloadTestSig27(void) "depth:5; sid:1;)"; p->flags |= PKT_STREAM_ADD; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) != 1) + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 1) goto end; result = 1; @@ -996,7 +996,7 @@ static int PayloadTestSig28(void) "offset:4; depth:12; sid:1;)"; p->flags |= PKT_STREAM_ADD; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) != 1) + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 1) goto end; result = 1; @@ -1020,7 +1020,7 @@ static int PayloadTestSig29(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "pcre:/^.{4}/; content:\"nova\"; within:4; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1) { result = 0; goto end; } @@ -1041,7 +1041,7 @@ static int PayloadTestSig30(void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"one\"; pcre:\"/^two/R\"; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -1062,7 +1062,7 @@ static int PayloadTestSig31(void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"one\"; pcre:\"/(fiv|^two)/R\"; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -1087,7 +1087,7 @@ static int PayloadTestSig32(void) char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_jump:2,-14,string,dec,relative; content:\"card\"; within:4; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) goto end; result = 1; @@ -1110,7 +1110,7 @@ static int PayloadTestSig33(void) char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_test:1,=,2,-14,string,dec,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) goto end; result = 1; @@ -1133,7 +1133,7 @@ static int PayloadTestSig34(void) char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_extract:1,-14,boom,string,dec,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) goto end; result = 1; diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 8d3e6b81899b..a118249dcd68 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -724,7 +724,7 @@ static int DetectHttpHeaderTest09(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index b60effaedba2..f1f559143170 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -9281,7 +9281,7 @@ static int DetectIPProtoTestSig2(void) goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -9366,7 +9366,7 @@ static int DetectIPProtoTestSig3(void) goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index 7126af1a75f0..350016860bd2 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -387,7 +387,7 @@ static int DetectTlsIssuerTest02(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index f6d62f438a91..0a6a6aef78bb 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -387,7 +387,7 @@ static int DetectTlsSubjectTest02(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index ee455310d387..c6ea1e9ce179 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -156,7 +156,7 @@ static int DetectTlsSniTest01(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " @@ -248,7 +248,7 @@ static int DetectTlsSniTest02(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " diff --git a/src/util-mpm.c b/src/util-mpm.c index b4e728ba8b33..92fdedd52e46 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -46,6 +46,9 @@ #include "detect-engine-mpm.h" #endif #include "util-memcpy.h" +#ifdef BUILD_HYPERSCAN +#include "hs.h" +#endif /** * \brief Register a new Mpm Context. @@ -402,15 +405,46 @@ void MpmInitCtx (MpmCtx *mpm_ctx, uint16_t matcher) mpm_table[matcher].InitCtx(mpm_ctx); } +/* MPM matcher to use by default, i.e. when "mpm-algo" is set to "auto". + * If Hyperscan is available, use it. Otherwise, use AC. */ +#ifdef BUILD_HYPERSCAN +# define DEFAULT_MPM MPM_HS +# ifdef __tile__ +# define DEFAULT_MPM_AC MPM_AC_TILE +# else +# define DEFAULT_MPM_AC MPM_AC +# endif +#else +# ifdef __tile__ +# define DEFAULT_MPM MPM_AC_TILE +# else +# define DEFAULT_MPM MPM_AC +# endif +#endif + void MpmTableSetup(void) { memset(mpm_table, 0, sizeof(mpm_table)); + mpm_default_matcher = DEFAULT_MPM; MpmACRegister(); MpmACBSRegister(); MpmACTileRegister(); #ifdef BUILD_HYPERSCAN - MpmHSRegister(); + #ifdef HAVE_HS_VALID_PLATFORM + /* Enable runtime check for SSSE3. Do not use Hyperscan MPM matcher if + * check is not successful. */ + if (hs_valid_platform() != HS_SUCCESS) { + SCLogInfo("SSSE3 support not detected, disabling Hyperscan for " + "MPM"); + /* Fall back to best Aho-Corasick variant. */ + mpm_default_matcher = DEFAULT_MPM_AC; + } else { + MpmHSRegister(); + } + #else + MpmHSRegister(); + #endif /* HAVE_HS_VALID_PLATFORM */ #endif /* BUILD_HYPERSCAN */ #ifdef __SC_CUDA_SUPPORT__ MpmACCudaRegister(); diff --git a/src/util-mpm.h b/src/util-mpm.h index fe161c12c163..f20bf73774fd 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -43,18 +43,6 @@ enum { MPM_TABLE_SIZE, }; -/* MPM matcher to use by default, i.e. when "mpm-algo" is set to "auto". - * If Hyperscan is available, use it. Otherwise, use AC. */ -#ifdef BUILD_HYPERSCAN -# define DEFAULT_MPM MPM_HS -#else -# ifdef __tile__ -# define DEFAULT_MPM MPM_AC_TILE -# else -# define DEFAULT_MPM MPM_AC -# endif -#endif - /* Internal Pattern Index: 0 to pattern_cnt-1 */ typedef uint32_t MpmPatternIndex; @@ -171,6 +159,7 @@ typedef struct MpmTableElmt_ { } MpmTableElmt; MpmTableElmt mpm_table[MPM_TABLE_SIZE]; +int mpm_default_matcher; /* macros decides if cuda is enabled for the platform or not */ #ifdef __SC_CUDA_SUPPORT__ diff --git a/src/util-spm.c b/src/util-spm.c index d9cbf3f41bfe..52432b8adc0e 100644 --- a/src/util-spm.c +++ b/src/util-spm.c @@ -55,6 +55,9 @@ #include "util-spm-bm.h" #include "util-spm-hs.h" #include "util-clock.h" +#ifdef BUILD_HYPERSCAN +#include "hs.h" +#endif /** * \brief Returns the single pattern matcher algorithm to be used, based on the @@ -89,7 +92,20 @@ uint16_t SinglePatternMatchDefaultMatcher(void) /* When Suricata is built with Hyperscan support, default to using it for * SPM. */ #ifdef BUILD_HYPERSCAN - return SPM_HS; + #ifdef HAVE_HS_VALID_PLATFORM + /* Enable runtime check for SSSE3. Do not use Hyperscan SPM matcher if + * check is not successful. */ + if (hs_valid_platform() != HS_SUCCESS) { + SCLogInfo("SSSE3 support not detected, disabling Hyperscan for " + "SPM"); + /* Use Boyer-Moore as fallback. */ + return SPM_BM; + } else { + return SPM_HS; + } + #else + return SPM_HS; + #endif #else /* Otherwise, default to Boyer-Moore */ return SPM_BM; @@ -102,7 +118,13 @@ void SpmTableSetup(void) SpmBMRegister(); #ifdef BUILD_HYPERSCAN - SpmHSRegister(); + #ifdef HAVE_HS_VALID_PLATFORM + if (hs_valid_platform() == HS_SUCCESS) { + SpmHSRegister(); + } + #else + SpmHSRegister(); + #endif #endif } From 15accc86c9e5e7457d99d2fbfab7a50302b5ff0c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 15:17:01 +0100 Subject: [PATCH 2301/2553] common: add BIT_U8 macro --- src/suricata-common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/suricata-common.h b/src/suricata-common.h index 7fbe4f31f20c..c6bf0d16c7b6 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -319,6 +319,7 @@ #define MAX(x, y) (((x)<(y))?(y):(x)) #endif +#define BIT_U8(n) ((uint8_t)(1 << (n))) #define BIT_U16(n) ((uint16_t)(1 << (n))) #define BIT_U32(n) (1UL << (n)) #define BIT_U64(n) (1ULL << (n)) From 473dae75b52f37aaad3358a790652ed01b98bd7e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Dec 2016 20:10:57 +0100 Subject: [PATCH 2302/2553] tls: introduce 'cert ready' state --- src/app-layer-ssl.c | 7 +++++++ src/app-layer-ssl.h | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 96c7cc863ad8..58f54feea67c 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -235,6 +235,13 @@ int SSLGetAlstateProgress(void *tx, uint8_t direction) return TLS_HANDSHAKE_DONE; } + if (direction == STREAM_TOSERVER && + (ssl_state->server_connp.cert0_subject != NULL || + ssl_state->server_connp.cert0_issuerdn != NULL)) + { + return TLS_STATE_CERT_READY; + } + return TLS_STATE_IN_PROGRESS; } diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 1a8a0a2ec228..d2279e2f2b43 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -59,8 +59,9 @@ enum { enum { TLS_STATE_IN_PROGRESS = 0, - TLS_HANDSHAKE_DONE = 1, - TLS_STATE_FINISHED = 2 + TLS_STATE_CERT_READY = 1, + TLS_HANDSHAKE_DONE = 2, + TLS_STATE_FINISHED = 3 }; /* Flag to indicate that server will now on send encrypted msgs */ From 6e876182d7b95ddb1d91b3a86beb152fe395ba6e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Dec 2016 20:13:28 +0100 Subject: [PATCH 2303/2553] detect: use TLS_STATE_CERT_READY in cert inspect --- src/detect-engine-tls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 8e216618b04a..98eeab60e19b 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -156,7 +156,7 @@ int PrefilterTxTlsIssuerRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) SCEnter(); return PrefilterAppendTxEngine(sgh, PrefilterTxTlsIssuer, - ALPROTO_TLS, 0, // TODO a special 'cert ready' state might be good to add + ALPROTO_TLS, TLS_STATE_CERT_READY, mpm_ctx, NULL, "tls_cert_issuer"); } @@ -232,7 +232,7 @@ int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) SCEnter(); return PrefilterAppendTxEngine(sgh, PrefilterTxTlsSubject, - ALPROTO_TLS, 0, // TODO a special 'cert ready' state might be good to add + ALPROTO_TLS, TLS_STATE_CERT_READY, mpm_ctx, NULL, "tls_cert_subject"); } From addf64f1f784bb152a54b43cca86e3ecdf6851a6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 11:08:11 +0100 Subject: [PATCH 2304/2553] profiling: fix memory leaks --- src/util-profiling-keywords.c | 10 +++------- src/util-profiling-rulegroups.c | 10 +++------- src/util-profiling-rules.c | 10 +++------- src/util-profiling.c | 23 +++++++++-------------- 4 files changed, 18 insertions(+), 35 deletions(-) diff --git a/src/util-profiling-keywords.c b/src/util-profiling-keywords.c index c512727d3b83..9ba367f56cf0 100644 --- a/src/util-profiling-keywords.c +++ b/src/util-profiling-keywords.c @@ -63,7 +63,7 @@ typedef struct SCProfileKeywordDetectCtx_ { static int profiling_keywords_output_to_file = 0; int profiling_keyword_enabled = 0; __thread int profiling_keyword_entered = 0; -static char *profiling_file_name = ""; +static char profiling_file_name[PATH_MAX]; static const char *profiling_file_mode = "a"; void SCProfilingKeywordsGlobalInit(void) @@ -80,12 +80,8 @@ void SCProfilingKeywordsGlobalInit(void) char *log_dir; log_dir = ConfigGetLogDirectory(); - profiling_file_name = SCMalloc(PATH_MAX); - if (unlikely(profiling_file_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); - exit(EXIT_FAILURE); - } - snprintf(profiling_file_name, PATH_MAX, "%s/%s", log_dir, filename); + snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", + log_dir, filename); const char *v = ConfNodeLookupChildValue(conf, "append"); if (v == NULL || ConfValIsTrue(v)) { diff --git a/src/util-profiling-rulegroups.c b/src/util-profiling-rulegroups.c index 1bbf4f7961f1..8f69338a1313 100644 --- a/src/util-profiling-rulegroups.c +++ b/src/util-profiling-rulegroups.c @@ -64,7 +64,7 @@ typedef struct SCProfileSghDetectCtx_ { static int profiling_sghs_output_to_file = 0; int profiling_sghs_enabled = 0; -static char *profiling_file_name = ""; +static char profiling_file_name[PATH_MAX]; static const char *profiling_file_mode = "a"; #ifdef HAVE_LIBJANSSON static int profiling_rulegroup_json = 0; @@ -84,12 +84,8 @@ void SCProfilingSghsGlobalInit(void) char *log_dir; log_dir = ConfigGetLogDirectory(); - profiling_file_name = SCMalloc(PATH_MAX); - if (unlikely(profiling_file_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); - exit(EXIT_FAILURE); - } - snprintf(profiling_file_name, PATH_MAX, "%s/%s", log_dir, filename); + snprintf(profiling_file_name, sizeof(profiling_file_name), + "%s/%s", log_dir, filename); const char *v = ConfNodeLookupChildValue(conf, "append"); if (v == NULL || ConfValIsTrue(v)) { diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index fbfa491b7871..49d1199eded4 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -79,7 +79,7 @@ typedef struct SCProfileSummary_ { extern int profiling_output_to_file; int profiling_rules_enabled = 0; -static char *profiling_file_name = ""; +static char profiling_file_name[PATH_MAX] = ""; static const char *profiling_file_mode = "a"; #ifdef HAVE_LIBJANSSON static int profiling_rule_json = 0; @@ -165,12 +165,8 @@ void SCProfilingRulesGlobalInit(void) char *log_dir; log_dir = ConfigGetLogDirectory(); - profiling_file_name = SCMalloc(PATH_MAX); - if (unlikely(profiling_file_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); - exit(EXIT_FAILURE); - } - snprintf(profiling_file_name, PATH_MAX, "%s/%s", log_dir, filename); + snprintf(profiling_file_name, sizeof(profiling_file_name), + "%s/%s", log_dir, filename); const char *v = ConfNodeLookupChildValue(conf, "append"); if (v == NULL || ConfValIsTrue(v)) { diff --git a/src/util-profiling.c b/src/util-profiling.c index 122db86ea997..9cbe49de3556 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -102,14 +102,14 @@ static SCProfilePacketData prefilter6[256][256]; struct ProfileProtoRecords packet_profile_flowworker_data[PROFILE_FLOWWORKER_SIZE]; int profiling_packets_enabled = 0; -int profiling_packets_csv_enabled = 0; - int profiling_output_to_file = 0; -int profiling_packets_output_to_file = 0; -char *profiling_file_name; -char *profiling_packets_file_name; -char *profiling_csv_file_name; -const char *profiling_packets_file_mode = "a"; + +static int profiling_packets_csv_enabled = 0; +static int profiling_packets_output_to_file = 0; +static char *profiling_file_name; +static char profiling_packets_file_name[PATH_MAX]; +static char *profiling_csv_file_name; +static const char *profiling_packets_file_mode = "a"; static int rate = 1; static SC_ATOMIC_DECLARE(uint64_t, samples); @@ -187,13 +187,8 @@ SCProfilingInit(void) char *log_dir; log_dir = ConfigGetLogDirectory(); - profiling_packets_file_name = SCMalloc(PATH_MAX); - if (unlikely(profiling_packets_file_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); - exit(EXIT_FAILURE); - } - - snprintf(profiling_packets_file_name, PATH_MAX, "%s/%s", log_dir, filename); + snprintf(profiling_packets_file_name, sizeof(profiling_packets_file_name), + "%s/%s", log_dir, filename); const char *v = ConfNodeLookupChildValue(conf, "append"); if (v == NULL || ConfValIsTrue(v)) { From 31a96d5a79c91fca3cae88351ab04d87fe30ce9c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 11:58:30 +0100 Subject: [PATCH 2305/2553] detect: make tenant loading less verbose --- src/detect-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 6be055da560c..e1af308ed11e 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2440,7 +2440,7 @@ int DetectEngineMTApply(void) } else { DetectEngineCtx *list = master->list; for ( ; list != NULL; list = list->next) { - SCLogInfo("list %p tenant %u", list, list->tenant_id); + SCLogDebug("list %p tenant %u", list, list->tenant_id); if (list->tenant_id == 0) { minimal_de_ctx = list; From f91d490d25ef03b86aaa26622afaa5f6fa210257 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 14:59:11 +0100 Subject: [PATCH 2306/2553] detect: remove unused flow_locked hint --- src/detect.c | 2 -- src/detect.h | 4 ---- 2 files changed, 6 deletions(-) diff --git a/src/detect.c b/src/detect.c index 448e41612b03..479d0db192a2 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1734,9 +1734,7 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue } if (p->flow) { - det_ctx->flow_locked = 1; DetectFlow(tv, de_ctx, det_ctx, p); - det_ctx->flow_locked = 0; } else { DetectNoFlow(tv, de_ctx, det_ctx, p); } diff --git a/src/detect.h b/src/detect.h index 9021c940dcdc..d0c0e58b4e62 100644 --- a/src/detect.h +++ b/src/detect.h @@ -838,10 +838,6 @@ typedef struct DetectEngineThreadCtx_ { /* counter for the filestore array below -- up here for cache reasons. */ uint16_t filestore_cnt; - /* bool to hint the POSTMATCH list members about the lock status of the - * flow. If locked this is TRUE, unlocked or no-flow: FALSE */ - uint8_t flow_locked; - HttpReassembledBody *hsbd; uint64_t hsbd_start_tx_id; uint16_t hsbd_buffers_size; From d8b5bf9bc60f1e70de7611730ebd4a9fe0b954bb Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 29 Nov 2016 22:10:56 +0100 Subject: [PATCH 2307/2553] app-layer-parsing: detect malformed input If the app-layer-parsing has a very long content it exceeds the maximum defined in "alproto_name". This adds a check for the too long content before it will be passed to "strlcpy" and logs an error. --- src/detect-app-layer-event.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index b33948aceb2a..c237ecf4b282 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -46,6 +46,8 @@ #include "util-unittest-helper.h" #include "stream-tcp-util.h" +#define MAX_ALPROTO_NAME 50 + static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx); static int DetectAppLayerEventAppMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, @@ -193,10 +195,14 @@ static int DetectAppLayerEventParseAppP2(DetectAppLayerEventData *data, int event_id = 0; const char *p_idx; uint8_t ipproto; - char alproto_name[50]; + char alproto_name[MAX_ALPROTO_NAME]; int r = 0; p_idx = strchr(data->arg, '.'); + if (strlen(data->arg) > MAX_ALPROTO_NAME) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-event keyword is too long or malformed"); + return -1; + } strlcpy(alproto_name, data->arg, p_idx - data->arg + 1); if (ipproto_bitarray[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8)) { @@ -227,9 +233,13 @@ static DetectAppLayerEventData *DetectAppLayerEventParseAppP1(const char *arg) DetectAppLayerEventData *aled; AppProto alproto; const char *p_idx; - char alproto_name[50]; + char alproto_name[MAX_ALPROTO_NAME]; p_idx = strchr(arg, '.'); + if (strlen(arg) > MAX_ALPROTO_NAME) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-event keyword is too long or malformed"); + return NULL; + } /* + 1 for trailing \0 */ strlcpy(alproto_name, arg, p_idx - arg + 1); From 21bbac56482a5c76ce153723f4daf03398bb7ea8 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 31 Jan 2017 12:32:18 -0600 Subject: [PATCH 2308/2553] dns-log: log requests even when there is no response The JSON logger had already been updated to handle transactions without a response. Apply the same logic to the older dns-log where a logger is registered for each direction. Fixes issue 2012. --- src/log-dnslog.c | 64 +++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/log-dnslog.c b/src/log-dnslog.c index 54fcf7e342fb..ea32c6b292e7 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -165,8 +165,8 @@ static void LogAnswer(LogDnsLogThread *aft, char *timebuf, char *srcip, char *ds SCMutexUnlock(&hlog->file_ctx->fp_mutex); } -static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, Flow *f, - void *state, void *tx, uint64_t tx_id) +static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, + Flow *f, void *state, void *tx, uint64_t tx_id, uint8_t direction) { LogDnsLogThread *aft = (LogDnsLogThread *)data; DNSTransaction *dns_tx = (DNSTransaction *)tx; @@ -214,24 +214,26 @@ static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, Flow *f, dp = p->sp; } - DNSQueryEntry *query = NULL; - TAILQ_FOREACH(query, &dns_tx->query_list, next) { - LogQuery(aft, timebuf, dstip, srcip, dp, sp, dns_tx, query); - } - - if (dns_tx->rcode) - LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, NULL); - if (dns_tx->recursion_desired) - LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, NULL); - - DNSAnswerEntry *entry = NULL; - TAILQ_FOREACH(entry, &dns_tx->answer_list, next) { - LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, entry); - } + if (direction == STREAM_TOSERVER) { + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &dns_tx->query_list, next) { + LogQuery(aft, timebuf, dstip, srcip, dp, sp, dns_tx, query); + } + } else if (direction == STREAM_TOCLIENT) { + if (dns_tx->rcode) + LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, NULL); + if (dns_tx->recursion_desired) + LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, NULL); + + DNSAnswerEntry *entry = NULL; + TAILQ_FOREACH(entry, &dns_tx->answer_list, next) { + LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, entry); + } - entry = NULL; - TAILQ_FOREACH(entry, &dns_tx->authority_list, next) { - LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, entry); + entry = NULL; + TAILQ_FOREACH(entry, &dns_tx->authority_list, next) { + LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, entry); + } } aft->dns_cnt++; @@ -239,6 +241,18 @@ static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, Flow *f, return 0; } +static int LogDnsRequestLogger(ThreadVars *tv, void *data, const Packet *p, + Flow *f, void *state, void *tx, uint64_t tx_id) +{ + return LogDnsLogger(tv, data, p, f, state, tx, tx_id, STREAM_TOSERVER); +} + +static int LogDnsResponseLogger(ThreadVars *tv, void *data, const Packet *p, + Flow *f, void *state, void *tx, uint64_t tx_id) +{ + return LogDnsLogger(tv, data, p, f, state, tx, tx_id, STREAM_TOCLIENT); +} + static TmEcode LogDnsLogThreadInit(ThreadVars *t, void *initdata, void **data) { LogDnsLogThread *aft = SCMalloc(sizeof(LogDnsLogThread)); @@ -346,9 +360,15 @@ static OutputCtx *LogDnsLogInitCtx(ConfNode *conf) void LogDnsLogRegister (void) { - OutputRegisterTxModule(LOGGER_DNS, MODULE_NAME, "dns-log", LogDnsLogInitCtx, - ALPROTO_DNS, LogDnsLogger, LogDnsLogThreadInit, LogDnsLogThreadDeinit, - LogDnsLogExitPrintStats); + /* Request logger. */ + OutputRegisterTxModuleWithProgress(LOGGER_DNS, MODULE_NAME, "dns-log", + LogDnsLogInitCtx, ALPROTO_DNS, LogDnsRequestLogger, 0, 1, + LogDnsLogThreadInit, LogDnsLogThreadDeinit, LogDnsLogExitPrintStats); + + /* Response logger. */ + OutputRegisterTxModuleWithProgress(LOGGER_DNS, MODULE_NAME, "dns-log", + LogDnsLogInitCtx, ALPROTO_DNS, LogDnsResponseLogger, 1, 1, + LogDnsLogThreadInit, LogDnsLogThreadDeinit, LogDnsLogExitPrintStats); /* enable the logger for the app layer */ SCLogDebug("registered %s", MODULE_NAME); From 0695ad4bf070a8a9ff4b1b82c6ca4d9c9c78527d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 30 Jan 2017 19:18:37 +0100 Subject: [PATCH 2309/2553] detect-xbits: set documentation URL --- src/detect-xbits.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-xbits.c b/src/detect-xbits.c index 07409b1e0508..131e29e4a32f 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -66,7 +66,7 @@ void DetectXbitsRegister (void) { sigmatch_table[DETECT_XBITS].name = "xbits"; sigmatch_table[DETECT_XBITS].desc = "operate on bits"; -// sigmatch_table[DETECT_XBITS].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#flowbits"; + sigmatch_table[DETECT_XBITS].url = DOC_URL DOC_VERSION "/rules/xbits.html"; sigmatch_table[DETECT_XBITS].Match = DetectXbitMatch; sigmatch_table[DETECT_XBITS].Setup = DetectXbitSetup; sigmatch_table[DETECT_XBITS].Free = DetectXbitFree; From 1af713d67d215b46c665e0fa213cd603068aba2d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 30 Jan 2017 20:13:04 +0100 Subject: [PATCH 2310/2553] detect-tls: add url field pointing to doc --- src/detect-tls-cert-issuer.c | 1 + src/detect-tls-cert-subject.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index 350016860bd2..84ba64d3747f 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -63,6 +63,7 @@ void DetectTlsIssuerRegister(void) { sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].name = "tls_cert_issuer"; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].desc = "content modifier to match specifically and only on the TLS cert issuer buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-cert-issuer"; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Match = NULL; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Setup = DetectTlsIssuerSetup; diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index 0a6a6aef78bb..dcfbe2f8f1f1 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -63,6 +63,7 @@ void DetectTlsSubjectRegister(void) { sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].name = "tls_cert_subject"; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].desc = "content modifier to match specifically and only on the TLS cert subject buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-cert-subject"; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Match = NULL; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Setup = DetectTlsSubjectSetup; From c357dafed9561a50d1284f86441af3cf0b2c1c68 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 30 Jan 2017 20:24:10 +0100 Subject: [PATCH 2311/2553] doc: document the tls_sni keyword --- doc/userguide/rules/tls-keywords.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/userguide/rules/tls-keywords.rst b/doc/userguide/rules/tls-keywords.rst index f37ef30603c6..a84821ca8da6 100644 --- a/doc/userguide/rules/tls-keywords.rst +++ b/doc/userguide/rules/tls-keywords.rst @@ -27,6 +27,18 @@ Examples:: ``tls_cert_issuer`` is a 'Sticky buffer'. +tls_sni +------- + +Match TLS/SSL Server Name Indication field. + +Examples:: + + tls_sni; content:"oisf.net"; nocase; isdataat:!1,relative; + tls_sni; content:"oisf.net"; nocase; pcre:"/oisf.net$/"; + +``tls_sni`` is a 'Sticky buffer'. + tls_cert_notbefore ------------------ From f407d77016dcf037bc533c68495b38bd36884974 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 30 Jan 2017 20:25:41 +0100 Subject: [PATCH 2312/2553] detect-tls-sni: add link to documentation --- src/detect-tls-sni.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index c6ea1e9ce179..ada7e2a4f333 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -63,6 +63,7 @@ void DetectTlsSniRegister(void) { sigmatch_table[DETECT_AL_TLS_SNI].name = "tls_sni"; sigmatch_table[DETECT_AL_TLS_SNI].desc = "content modifier to match specifically and only on the TLS SNI buffer"; + sigmatch_table[DETECT_AL_TLS_SNI].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-sni"; sigmatch_table[DETECT_AL_TLS_SNI].Match = NULL; sigmatch_table[DETECT_AL_TLS_SNI].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_TLS_SNI].Setup = DetectTlsSniSetup; From ecf59be413f2c51960614efc4063fee6777943f2 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 1 Nov 2016 22:09:31 +0100 Subject: [PATCH 2313/2553] af-packet: add VLAN header when needed in IPS mode When packet is coming from a real ethernet card, the kernel is stripping the vlan header and delivering a modified packet so we need to insert the VLAN header back before sending the packet on the wire. To do so, we pass an option to the raw socket to add a reserve before the packet data. It will get Suricata some head room to to move the ethernet addresses before there actual place and and insert the VLAN header in the correct place. We get VLAN info from the ring buffer as the call of AFPWrite is always done in the release function so we still have access to the memory. --- src/source-af-packet.c | 64 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index da80ea324ca6..289b92f58d62 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2016 Open Information Security Foundation +/* Copyright (C) 2011-2017 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -662,10 +662,23 @@ int AFPRead(AFPThreadVars *ptv) SCReturnInt(AFP_READ_OK); } -TmEcode AFPWritePacket(Packet *p) +/** + * \brief AF packet write function. + * + * This function has to be called before the memory + * related to Packet in ring buffer is released. + * + * \param pointer to Packet + * \param version of capture: TPACKET_V2 or TPACKET_V3 + * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success + * + */ +static TmEcode AFPWritePacket(Packet *p, int version) { struct sockaddr_ll socket_address; int socket; + uint8_t *pstart; + size_t plen; if (p->afp_v.copy_mode == AFP_COPY_MODE_IPS) { if (PACKET_TEST_ACTION(p, ACTION_DROP)) { @@ -691,7 +704,31 @@ TmEcode AFPWritePacket(Packet *p) if (p->afp_v.peer->flags & AFP_SOCK_PROTECT) SCMutexLock(&p->afp_v.peer->sock_protect); socket = SC_ATOMIC_GET(p->afp_v.peer->socket); - if (sendto(socket, GET_PKT_DATA(p), GET_PKT_LEN(p), 0, + + if (version == TPACKET_V2) { + union thdr h; + h.raw = p->afp_v.relptr; + /* Copy VLAN header from ring memory. For post june 2011 kernel we test + * the flag. It is not defined for older kernel so we go best effort + * and test for non zero value of the TCI header. */ + if (h.h2->tp_status & TP_STATUS_VLAN_VALID || h.h2->tp_vlan_tci) { + pstart = GET_PKT_DATA(p) - VLAN_HEADER_LEN; + plen = GET_PKT_LEN(p) + VLAN_HEADER_LEN; + /* move ethernet addresses */ + memmove(pstart, GET_PKT_DATA(p), 2 * ETH_ALEN); + /* write vlan info */ + *(uint16_t *)(pstart + 2 * ETH_ALEN) = htons(0x8100); + *(uint16_t *)(pstart + 2 * ETH_ALEN + 2) = htons(h.h2->tp_vlan_tci); + } else { + pstart = GET_PKT_DATA(p); + plen = GET_PKT_LEN(p); + } + } else { + pstart = GET_PKT_DATA(p); + plen = GET_PKT_LEN(p); + } + + if (sendto(socket, pstart, plen, 0, (struct sockaddr*) &socket_address, sizeof(struct sockaddr_ll)) < 0) { SCLogWarning(SC_ERR_SOCKET, "Sending packet failed on socket %d: %s", @@ -712,7 +749,7 @@ void AFPReleaseDataFromRing(Packet *p) /* Need to be in copy mode and need to detect early release where Ethernet header could not be set (and pseudo packet) */ if ((p->afp_v.copy_mode != AFP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) { - AFPWritePacket(p); + AFPWritePacket(p, TPACKET_V2); } if (AFPDerefSocket(p->afp_v.mpeer) == 0) @@ -728,15 +765,17 @@ void AFPReleaseDataFromRing(Packet *p) AFPV_CLEANUP(&p->afp_v); } +#ifdef HAVE_TPACKET_V3 void AFPReleasePacketV3(Packet *p) { /* Need to be in copy mode and need to detect early release where Ethernet header could not be set (and pseudo packet) */ if ((p->afp_v.copy_mode != AFP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) { - AFPWritePacket(p); + AFPWritePacket(p, TPACKET_V3); } PacketFreeOrRelease(p); } +#endif void AFPReleasePacket(Packet *p) { @@ -1686,6 +1725,21 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) } #endif + /* Let's reserve head room so we can add the VLAN header in IPS + * or TAP mode before write the packet */ + if (ptv->copy_mode != AFP_COPY_MODE_NONE) { + /* Only one vlan is extracted from AFP header so + * one VLAN header length is enough. */ + int reserve = VLAN_HEADER_LEN; + if (setsockopt(ptv->socket, SOL_PACKET, PACKET_RESERVE, (void *) &reserve, + sizeof(reserve)) < 0) { + SCLogError(SC_ERR_AFP_CREATE, + "Can't activate reserve on packet socket: %s", + strerror(errno)); + return AFP_FATAL_ERROR; + } + } + /* Allocate RX ring */ #ifdef HAVE_TPACKET_V3 if (ptv->flags & AFP_TPACKET_V3) { From c89ce17017ae91dce20a701974e902a3947e14be Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Feb 2017 08:40:46 +0100 Subject: [PATCH 2314/2553] afl: with -Wshadow issues --- src/app-layer-parser.c | 12 ++++++------ src/decode.c | 6 +++--- src/util-decode-mime.c | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 359bd9a07601..5dd7c7e59148 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -1344,8 +1344,8 @@ int AppLayerParserRequestFromFile(AppProto alproto, char *filename) int start = 1; while (1) { int done = 0; - size_t result = fread(&buffer, 1, sizeof(buffer), fp); - if (result < sizeof(buffer)) + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + if (size < sizeof(buffer)) done = 1; //SCLogInfo("result %u done %d start %d", (uint)result, done, start); @@ -1361,7 +1361,7 @@ int AppLayerParserRequestFromFile(AppProto alproto, char *filename) //PrintRawDataFp(stdout, buffer, result); (void)AppLayerParserParse(NULL, alp_tctx, f, alproto, flags, - buffer, result); + buffer, size); if (done) break; } @@ -1421,8 +1421,8 @@ int AppLayerParserFromFile(AppProto alproto, char *filename) int flip = 0; while (1) { int done = 0; - size_t result = fread(&buffer, 1, sizeof(buffer), fp); - if (result < sizeof(buffer)) + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + if (size < sizeof(buffer)) done = 1; //SCLogInfo("result %u done %d start %d", (uint)result, done, start); @@ -1445,7 +1445,7 @@ int AppLayerParserFromFile(AppProto alproto, char *filename) //PrintRawDataFp(stdout, buffer, result); (void)AppLayerParserParse(NULL, alp_tctx, f, alproto, flags, - buffer, result); + buffer, size); if (done) break; } diff --git a/src/decode.c b/src/decode.c index 209a55080caf..58fa61b33879 100644 --- a/src/decode.c +++ b/src/decode.c @@ -622,13 +622,13 @@ int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder) { while (1) { int done = 0; - size_t result = fread(&buffer, 1, sizeof(buffer), fp); - if (result < sizeof(buffer)) + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + if (size < sizeof(buffer)) done = 1; Packet *p = PacketGetFromAlloc(); if (p != NULL) { - (void) Decoder (&tv, dtv, p, buffer, result, NULL); + (void) Decoder (&tv, dtv, p, buffer, size, NULL); PacketFree(p); } diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c index eb1dcab56659..fcda28c05585 100644 --- a/src/util-decode-mime.c +++ b/src/util-decode-mime.c @@ -2645,11 +2645,11 @@ int MimeParserDataFromFile(char *filename) while (1) { int done = 0; - size_t result = fread(&buffer, 1, sizeof(buffer), fp); - if (result < sizeof(buffer)) + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + if (size < sizeof(buffer)) done = 1; - (void) MimeDecParseLine(buffer, result, 1, state); + (void) MimeDecParseLine(buffer, size, 1, state); if (done) break; From 4683b0e662aa1349168c9706440aaeab1bef0e47 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Feb 2017 09:20:54 +0100 Subject: [PATCH 2315/2553] afl: fix ENIP, switch DNS to UDP and add --afl-dnstcp* --- src/app-layer-detect-proto.c | 3 ++ src/app-layer-dnp3.c | 2 ++ src/app-layer-dns-udp.c | 2 ++ src/app-layer-enip.c | 2 ++ src/app-layer-modbus.c | 4 --- src/app-layer-parser.c | 17 +++++++++--- src/app-layer-parser.h | 4 +-- src/suricata.c | 53 ++++++++++++++++++++++-------------- 8 files changed, 56 insertions(+), 31 deletions(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 1ec0d4c1b4b9..92bb37eefc79 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1624,6 +1624,9 @@ int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, ConfNode *node; int r; +#ifdef AFLFUZZ_APPLAYER + goto enabled; +#endif if (RunmodeIsUnittests()) goto enabled; diff --git a/src/app-layer-dnp3.c b/src/app-layer-dnp3.c index 31391adab9c9..4d2efa165f3a 100644 --- a/src/app-layer-dnp3.c +++ b/src/app-layer-dnp3.c @@ -1598,7 +1598,9 @@ void RegisterDNP3Parsers(void) if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), DNP3ProbingParser, NULL)) { +#ifndef AFLFUZZ_APPLAYER return; +#endif } } diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index d8ee37d30f34..83d1834ce6f1 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -404,9 +404,11 @@ void RegisterDNSUDPParsers(void) DNSUdpProbingParser, NULL); /* if we have no config, we enable the default port 53 */ if (!have_cfg) { +#ifndef AFLFUZZ_APPLAYER SCLogWarning(SC_ERR_DNS_CONFIG, "no DNS UDP config found, " "enabling DNS detection on " "port 53."); +#endif AppLayerProtoDetectPPRegister(IPPROTO_UDP, "53", ALPROTO_DNS, 0, sizeof(DNSHeader), STREAM_TOSERVER, DNSUdpProbingParser, NULL); diff --git a/src/app-layer-enip.c b/src/app-layer-enip.c index 05a63824ca7a..d6218fa22f92 100644 --- a/src/app-layer-enip.c +++ b/src/app-layer-enip.c @@ -482,7 +482,9 @@ void RegisterENIPTCPParsers(void) proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), ENIPProbingParser, ENIPProbingParser)) { +#ifndef AFLFUZZ_APPLAYER return; +#endif } } diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index f8c7a7c104a8..cdb47bd86338 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1497,11 +1497,7 @@ void RegisterModbusParsers(void) return; #endif } -#ifndef AFLFUZZ_APPLAYER if (AppLayerParserConfParserEnabled("tcp", proto_name)) { -#else - if (1) { -#endif AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOSERVER, ModbusParseRequest); AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOCLIENT, ModbusParseResponse); AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateAlloc, ModbusStateFree); diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 5dd7c7e59148..d16391d07e22 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -265,6 +265,10 @@ void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx) SCReturn; } +/** \brief check if a parser is enabled in the config + * Returns enabled always if: were running unittests and + * when compiled with --enable-afl + */ int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name) { @@ -275,6 +279,9 @@ int AppLayerParserConfParserEnabled(const char *ipproto, ConfNode *node; int r; +#ifdef AFLFUZZ_APPLAYER + goto enabled; +#endif if (RunmodeIsUnittests()) goto enabled; @@ -1307,7 +1314,7 @@ void AppLayerParserStatePrintDetails(AppLayerParserState *pstate) #endif #ifdef AFLFUZZ_APPLAYER -int AppLayerParserRequestFromFile(AppProto alproto, char *filename) +int AppLayerParserRequestFromFile(uint8_t ipproto, AppProto alproto, char *filename) { int result = 1; Flow *f = NULL; @@ -1327,7 +1334,8 @@ int AppLayerParserRequestFromFile(AppProto alproto, char *filename) f->sp = 10000; f->dp = 80; f->protoctx = &ssn; - f->proto = IPPROTO_TCP; + f->proto = ipproto; + f->protomap = FlowGetProtoMapping(f->proto); f->alproto = alproto; uint8_t buffer[64]; @@ -1383,7 +1391,7 @@ int AppLayerParserRequestFromFile(AppProto alproto, char *filename) return result; } -int AppLayerParserFromFile(AppProto alproto, char *filename) +int AppLayerParserFromFile(uint8_t ipproto, AppProto alproto, char *filename) { int result = 1; Flow *f = NULL; @@ -1403,7 +1411,8 @@ int AppLayerParserFromFile(AppProto alproto, char *filename) f->sp = 10000; f->dp = 80; f->protoctx = &ssn; - f->proto = IPPROTO_TCP; + f->proto = ipproto; + f->protomap = FlowGetProtoMapping(f->proto); f->alproto = alproto; uint8_t buffer[64]; diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index 8e70d258fba9..9cd6d99192f7 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -237,8 +237,8 @@ void AppLayerParserStatePrintDetails(AppLayerParserState *pstate); #endif #ifdef AFLFUZZ_APPLAYER -int AppLayerParserRequestFromFile(AppProto alproto, char *filename); -int AppLayerParserFromFile(AppProto alproto, char *filename); +int AppLayerParserRequestFromFile(uint8_t ipproto, AppProto alproto, char *filename); +int AppLayerParserFromFile(uint8_t ipproto, AppProto alproto, char *filename); #endif /***** Unittests *****/ diff --git a/src/suricata.c b/src/suricata.c index 2d2a5c2872ea..128e7417a7a2 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -116,6 +116,7 @@ #include "app-layer-htp.h" #include "app-layer-ssl.h" #include "app-layer-dns-tcp.h" +#include "app-layer-dns-udp.h" #include "app-layer-ssh.h" #include "app-layer-ftp.h" #include "app-layer-smtp.h" @@ -1415,7 +1416,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterHTPParsers(); - exit(AppLayerParserRequestFromFile(ALPROTO_HTTP, optarg)); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_HTTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-http") == 0) { //printf("arg: //%s\n", optarg); MpmTableSetup(); @@ -1423,7 +1424,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterHTPParsers(); - exit(AppLayerParserFromFile(ALPROTO_HTTP, optarg)); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_HTTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-tls-request") == 0) { //printf("arg: //%s\n", optarg); @@ -1432,7 +1433,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSSLParsers(); - exit(AppLayerParserRequestFromFile(ALPROTO_TLS, optarg)); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_TLS, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-tls") == 0) { //printf("arg: //%s\n", optarg); MpmTableSetup(); @@ -1440,17 +1441,27 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSSLParsers(); - exit(AppLayerParserFromFile(ALPROTO_TLS, optarg)); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_TLS, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-dns-request") == 0) { //printf("arg: //%s\n", optarg); - RegisterDNSTCPParsers(); - exit(AppLayerParserRequestFromFile(ALPROTO_DNS, optarg)); + RegisterDNSUDPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_UDP, ALPROTO_DNS, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-dns") == 0) { + //printf("arg: //%s\n", optarg); + AppLayerParserSetup(); + RegisterDNSUDPParsers(); + exit(AppLayerParserFromFile(IPPROTO_UDP, ALPROTO_DNS, optarg)); + + } else if(strcmp((long_opts[option_index]).name, "afl-dnstcp-request") == 0) { + //printf("arg: //%s\n", optarg); + RegisterDNSTCPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_DNS, optarg)); + } else if(strcmp((long_opts[option_index]).name, "afl-dnstcp") == 0) { //printf("arg: //%s\n", optarg); AppLayerParserSetup(); RegisterDNSTCPParsers(); - exit(AppLayerParserFromFile(ALPROTO_DNS, optarg)); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_DNS, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-ssh-request") == 0) { //printf("arg: //%s\n", optarg); @@ -1458,7 +1469,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) SpmTableSetup(); AppLayerProtoDetectSetup(); RegisterSSHParsers(); - exit(AppLayerParserRequestFromFile(ALPROTO_SSH, optarg)); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SSH, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-ssh") == 0) { //printf("arg: //%s\n", optarg); MpmTableSetup(); @@ -1466,7 +1477,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSSHParsers(); - exit(AppLayerParserFromFile(ALPROTO_SSH, optarg)); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SSH, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-ftp-request") == 0) { //printf("arg: //%s\n", optarg); @@ -1475,7 +1486,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterFTPParsers(); - exit(AppLayerParserRequestFromFile(ALPROTO_FTP, optarg)); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_FTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-ftp") == 0) { //printf("arg: //%s\n", optarg); MpmTableSetup(); @@ -1483,7 +1494,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterFTPParsers(); - exit(AppLayerParserFromFile(ALPROTO_FTP, optarg)); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_FTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-smtp-request") == 0) { //printf("arg: //%s\n", optarg); @@ -1492,7 +1503,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSMTPParsers(); - exit(AppLayerParserRequestFromFile(ALPROTO_SMTP, optarg)); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SMTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-smtp") == 0) { //printf("arg: //%s\n", optarg); MpmTableSetup(); @@ -1500,7 +1511,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSMTPParsers(); - exit(AppLayerParserFromFile(ALPROTO_SMTP, optarg)); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SMTP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-smb-request") == 0) { //printf("arg: //%s\n", optarg); @@ -1508,7 +1519,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) SpmTableSetup(); AppLayerProtoDetectSetup(); RegisterSMBParsers(); - exit(AppLayerParserRequestFromFile(ALPROTO_SMB, optarg)); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SMB, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-smb") == 0) { //printf("arg: //%s\n", optarg); MpmTableSetup(); @@ -1516,36 +1527,36 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) AppLayerProtoDetectSetup(); AppLayerParserSetup(); RegisterSMBParsers(); - exit(AppLayerParserFromFile(ALPROTO_SMB, optarg)); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SMB, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-modbus-request") == 0) { //printf("arg: //%s\n", optarg); AppLayerParserSetup(); RegisterModbusParsers(); - exit(AppLayerParserRequestFromFile(ALPROTO_MODBUS, optarg)); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_MODBUS, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-modbus") == 0) { //printf("arg: //%s\n", optarg); AppLayerParserSetup(); RegisterModbusParsers(); - exit(AppLayerParserFromFile(ALPROTO_MODBUS, optarg)); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_MODBUS, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-enip-request") == 0) { //printf("arg: //%s\n", optarg); AppLayerParserSetup(); RegisterENIPTCPParsers(); - exit(AppLayerParserRequestFromFile(ALPROTO_ENIP, optarg)); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_ENIP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-enip") == 0) { //printf("arg: //%s\n", optarg); AppLayerParserSetup(); RegisterENIPTCPParsers(); - exit(AppLayerParserFromFile(ALPROTO_ENIP, optarg)); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_ENIP, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-dnp3-request") == 0) { AppLayerParserSetup(); RegisterDNP3Parsers(); - exit(AppLayerParserRequestFromFile(ALPROTO_DNP3, optarg)); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_DNP3, optarg)); } else if(strcmp((long_opts[option_index]).name, "afl-dnp3") == 0) { AppLayerParserSetup(); RegisterDNP3Parsers(); - exit(AppLayerParserFromFile(ALPROTO_DNP3, optarg)); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_DNP3, optarg)); #endif #ifdef AFLFUZZ_MIME } else if(strcmp((long_opts[option_index]).name, "afl-mime") == 0) { From 86222428dd51adf2b6ff562a49e0e1ed22e0da76 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 8 Feb 2017 13:55:34 +0100 Subject: [PATCH 2316/2553] detect: don't run IP inspection on non-IP packets The code to get the rule group (sgh) would return the group for IP proto 0 instead of nothing. This lead to certain types of rules unintentionally matching (False Positive). Since the packets weren't actually IP, the logged alert records were missing the IP header. Bug #2017. --- src/detect.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/detect.c b/src/detect.c index 479d0db192a2..5660c28339a2 100644 --- a/src/detect.c +++ b/src/detect.c @@ -588,6 +588,11 @@ SigGroupHead *SigMatchSignaturesGetSgh(DetectEngineCtx *de_ctx, DetectEngineThre * the decoder events sgh we have. */ if (p->proto == 0 && p->events.cnt > 0) { SCReturnPtr(de_ctx->decoder_event_sgh, "SigGroupHead"); + } else if (p->proto == 0) { + if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) { + /* not IP, so nothing to do */ + SCReturnPtr(NULL, "SigGroupHead"); + } } /* select the flow_gh */ From b25b067d9333bd1160cae643b47467cb02914446 Mon Sep 17 00:00:00 2001 From: Sascha Steinbiss Date: Wed, 8 Feb 2017 12:40:00 +0100 Subject: [PATCH 2317/2553] alert: silence compiler type warning The `ts_ecr' and `ts_val' struct fields are integer types, not pointers. This leads GCC 6.3.0 to complain about comparisons to NULL. Signed-off-by: Sascha Steinbiss --- src/alert-prelude.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/alert-prelude.c b/src/alert-prelude.c index 2526320ac344..9c55b2815417 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -512,10 +512,10 @@ static int PacketToData(const Packet *p, const PacketAlert *pa, idmef_alert_t *a AddIntData(alert, "tcp_win", TCP_GET_WINDOW(p)); AddIntData(alert, "tcp_sum", TCP_GET_SUM(p)); AddIntData(alert, "tcp_urp", TCP_GET_URG_POINTER(p)); - if (p->tcpvars.ts_val != NULL) { + if (p->tcpvars.ts_val != 0) { AddIntData(alert, "tcp_tsval", TCP_GET_TSVAL(p)); } - if (p->tcpvars.ts_ecr != NULL) { + if (p->tcpvars.ts_ecr != 0) { AddIntData(alert, "tcp_tsecr", TCP_GET_TSECR(p)); } if (p->tcph != NULL) { @@ -961,4 +961,3 @@ void AlertPreludeRegister (void) AlertPreludeThreadInit, AlertPreludeThreadDeinit, NULL); } #endif /* PRELUDE */ - From 5e969779839585dbeae7b103e9e7c9016140159b Mon Sep 17 00:00:00 2001 From: Sascha Steinbiss Date: Wed, 8 Feb 2017 12:39:06 +0100 Subject: [PATCH 2318/2553] mpm-ac: fix integer overflow on allocation The size of a memory buffer to be allocated was kept in a signed int instead of a size_t, leading to an overflow when large lists of long and diverse patterns cause the amount of AC states to blow up (>2GB). Fixes Redmine issues #1827 and #1843. Signed-off-by: Sascha Steinbiss --- src/util-mpm-ac.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index 45d537258652..6ab2e883fb1f 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -120,6 +120,28 @@ static void SCACGetConfig() return; } +/** + * \internal + * \brief Check if size_t multiplication would overflow and perform operation + * if safe. In case of an overflow we exit(). + * + * \param a First size_t value to multiplicate. + * \param b Second size_t value to multiplicate. + * + * \retval The product of a and b, guaranteed to not overflow. + */ +static inline size_t SCACCheckSafeSizetMult(size_t a, size_t b) +{ + /* check for safety of multiplication operation */ + if (b > 0 && a > SIZE_MAX / b) { + SCLogError(SC_ERR_MEM_ALLOC, "%"PRIuMAX" * %"PRIuMAX" > %" + PRIuMAX" would overflow size_t calculating buffer size", + (uintmax_t) a, (uintmax_t) b, (uintmax_t) SIZE_MAX); + exit(EXIT_FAILURE); + } + return a * b; +} + /** * \internal * \brief Initialize a new state in the goto and output tables. @@ -130,12 +152,13 @@ static void SCACGetConfig() */ static inline int SCACReallocState(SCACCtx *ctx, uint32_t cnt) { - void *ptmp; - int size = 0; + void *ptmp = NULL; + size_t size = 0; /* reallocate space in the goto table to include a new state */ - size = cnt * ctx->single_state_size; - ptmp = SCRealloc(ctx->goto_table, size); + size = SCACCheckSafeSizetMult((size_t) cnt, (size_t) ctx->single_state_size); + if (size > 0) + ptmp = SCRealloc(ctx->goto_table, size); if (ptmp == NULL) { SCFree(ctx->goto_table); ctx->goto_table = NULL; @@ -145,12 +168,15 @@ static inline int SCACReallocState(SCACCtx *ctx, uint32_t cnt) ctx->goto_table = ptmp; /* reallocate space in the output table for the new state */ - int oldsize = ctx->state_count * sizeof(SCACOutputTable); - size = cnt * sizeof(SCACOutputTable); - SCLogDebug("oldsize %d size %d cnt %u ctx->state_count %u", - oldsize, size, cnt, ctx->state_count); - - ptmp = SCRealloc(ctx->output_table, size); + size_t oldsize = SCACCheckSafeSizetMult((size_t) ctx->state_count, + sizeof(SCACOutputTable)); + size = SCACCheckSafeSizetMult((size_t) cnt, sizeof(SCACOutputTable)); + SCLogDebug("oldsize %"PRIuMAX" size %"PRIuMAX" cnt %d ctx->state_count %u", + (uintmax_t) oldsize, (uintmax_t) size, cnt, ctx->state_count); + + ptmp = NULL; + if (size > 0) + ptmp = SCRealloc(ctx->output_table, size); if (ptmp == NULL) { SCFree(ctx->output_table); ctx->output_table = NULL; From 923d93f314ac10dd17bbb8b2cbf443bb6680614e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Feb 2017 09:45:54 +0100 Subject: [PATCH 2319/2553] afl: add decoder ipv4 option --- src/suricata.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index 128e7417a7a2..7f16679525ee 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1261,6 +1261,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"afl-rules", required_argument, 0 , 0}, {"afl-mime", required_argument, 0 , 0}, {"afl-decoder-ppp", required_argument, 0 , 0}, + {"afl-decoder-ipv4", required_argument, 0 , 0}, {"afl-der", required_argument, 0, 0}, #ifdef BUILD_UNIX_SOCKET @@ -1573,6 +1574,15 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) FlowInitConfig(FLOW_QUIET); //printf("arg: //%s\n", optarg); exit(DecoderParseDataFromFile(optarg, DecodePPP)); + } else if(strcmp((long_opts[option_index]).name, "afl-decoder-ipv4") == 0) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + DefragInit(); + FlowInitConfig(FLOW_QUIET); + //printf("arg: //%s\n", optarg); + exit(DecoderParseDataFromFile(optarg, DecodeIPV4)); #endif #ifdef AFLFUZZ_DER } else if(strcmp((long_opts[option_index]).name, "afl-der") == 0) { From fbd69729aaa1c6089ad9037b83990704bddcbd93 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Feb 2017 18:22:18 +0100 Subject: [PATCH 2320/2553] afl: improve packet fuzz testing Due to the use of AFL_LOOP and initialization/deinit outside of it, part of the fuzzing relied on the global 'state' in flow and defrag. Because of this crashes that were found could not be reproduced. The saved crash input was only the last in the series. This patch addresses that. It requires a new output directory 'dump' where the packet fuzzers will store all their input. If the AFL_LOOP fails the files will not be removed and this 'serie' can be read again for reproducing the issue. e.g.: AFL would work with: --afl-decoder-ppp=@@ and after a crash is found the produced serie can be read with: --afl-decoder-ppp-serie=1486656919-514163 The series have a timestamp as name and a suffix that controls the order in which the files will be 'replayed' in Suricata. --- src/Makefile.am | 1 + src/decode-afl.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++ src/decode.c | 49 ---------------- src/decode.h | 1 + src/suricata.c | 33 +++++++---- 5 files changed, 174 insertions(+), 59 deletions(-) create mode 100644 src/decode-afl.c diff --git a/src/Makefile.am b/src/Makefile.am index 48f5dd0ee0bc..ada1afc6a4d8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,6 +46,7 @@ conf-yaml-loader.c conf-yaml-loader.h \ counters.c counters.h \ data-queue.c data-queue.h \ decode.c decode.h \ +decode-afl.c \ decode-erspan.c decode-erspan.h \ decode-ethernet.c decode-ethernet.h \ decode-events.c decode-events.h \ diff --git a/src/decode-afl.c b/src/decode-afl.c new file mode 100644 index 000000000000..59fd6fe13c53 --- /dev/null +++ b/src/decode-afl.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "conf.h" +#include "decode.h" +#include "util-debug.h" +#include "util-mem.h" +#include "app-layer-detect-proto.h" +#include "app-layer.h" +#include "tm-threads.h" +#include "util-error.h" +#include "util-print.h" +#include "tmqh-packetpool.h" +#include "util-profiling.h" +#include "pkt-var.h" +#include "util-mpm-ac.h" + +#include "output.h" +#include "output-flow.h" + +#include "defrag.h" +#include "flow.h" + +#ifdef AFLFUZZ_DECODER + +/* stateful processing of data as packets. Because AFL in case of a + * crash will only safe the last input, we dump all the inputs to a + * directory 'dump' with a unique timestamp for the serie and an + * incrementing 'id' so that we can 'replay' it in + * DecoderParseDataFromFileSerie(). + */ +int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder) { + uint8_t buffer[65536]; + + struct timeval ts; + memset(&ts, 0, sizeof(ts)); + gettimeofday(&ts, NULL); + + uint32_t cnt = 0; + + DefragInit(); + FlowInitConfig(FLOW_QUIET); + + ThreadVars tv; + memset(&tv, 0, sizeof(tv)); + DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv); + DecodeRegisterPerfCounters(dtv, &tv); + StatsSetupPrivate(&tv); + +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + char outfilename[256]; + snprintf(outfilename, sizeof(outfilename), "dump/%u-%u.%u", (uint)ts.tv_sec, (uint)ts.tv_usec, cnt); + FILE *out_fp = fopen(outfilename, "w"); + BUG_ON(out_fp == NULL); + (void)fwrite(buffer, size, 1, out_fp); + fclose(out_fp); + + Packet *p = PacketGetFromAlloc(); + if (p != NULL) { + (void) Decoder (&tv, dtv, p, buffer, size, NULL); + PacketFree(p); + } + fclose(fp); + cnt++; + +#ifdef AFLFUZZ_PERSISTANT_MODE + } +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + /* if we get here there was no crash, so we can remove our files */ + uint32_t x = 0; + for (x = 0; x < cnt; x++) { + char rmfilename[256]; + snprintf(rmfilename, sizeof(rmfilename), "dump/%u-%u.%u", (uint)ts.tv_sec, (uint)ts.tv_usec, x); + unlink(rmfilename); + } + + DecodeThreadVarsFree(&tv, dtv); + FlowShutdown(); + DefragDestroy(); + return 0; +} + +/* load a serie of files generated by DecoderParseDataFromFile() in + * the same order as it was produced. */ +int DecoderParseDataFromFileSerie(char *fileprefix, DecoderFunc Decoder) +{ + uint8_t buffer[65536]; + uint32_t cnt = 0; + + DefragInit(); + FlowInitConfig(FLOW_QUIET); + ThreadVars tv; + memset(&tv, 0, sizeof(tv)); + DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv); + DecodeRegisterPerfCounters(dtv, &tv); + StatsSetupPrivate(&tv); + + char filename[256]; + snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt); + FILE *fp; + while ((fp = fopen(filename, "r")) != NULL) + { + memset(buffer, 0, sizeof(buffer)); + + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + + Packet *p = PacketGetFromAlloc(); + if (p != NULL) { + (void) Decoder (&tv, dtv, p, buffer, size, NULL); + PacketFree(p); + } + fclose(fp); + cnt++; + snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt); + } + DecodeThreadVarsFree(&tv, dtv); + FlowShutdown(); + DefragDestroy(); + return 0; +} +#endif /* AFLFUZZ_DECODER */ + diff --git a/src/decode.c b/src/decode.c index 58fa61b33879..4b064c8300d6 100644 --- a/src/decode.c +++ b/src/decode.c @@ -600,55 +600,6 @@ void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s) s->counter_ips_replaced = StatsRegisterCounter("ips.replaced", tv); } -#ifdef AFLFUZZ_DECODER -int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder) { - uint8_t buffer[65536]; - int result = 1; - -#ifdef AFLFUZZ_PERSISTANT_MODE - while (__AFL_LOOP(1000)) { - /* reset state */ - memset(buffer, 0, sizeof(buffer)); -#endif /* AFLFUZZ_PERSISTANT_MODE */ - - FILE *fp = fopen(filename, "r"); - BUG_ON(fp == NULL); - - ThreadVars tv; - memset(&tv, 0, sizeof(tv)); - DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv); - DecodeRegisterPerfCounters(dtv, &tv); - StatsSetupPrivate(&tv); - - while (1) { - int done = 0; - size_t size = fread(&buffer, 1, sizeof(buffer), fp); - if (size < sizeof(buffer)) - done = 1; - - Packet *p = PacketGetFromAlloc(); - if (p != NULL) { - (void) Decoder (&tv, dtv, p, buffer, size, NULL); - PacketFree(p); - } - - if (done) - break; - } - DecodeThreadVarsFree(&tv, dtv); - - fclose(fp); - -#ifdef AFLFUZZ_PERSISTANT_MODE - } -#endif /* AFLFUZZ_PERSISTANT_MODE */ - - result = 0; - return result; - -} -#endif /* AFLFUZZ_DECODER */ - /** * @} */ diff --git a/src/decode.h b/src/decode.h index 85b4faf5601c..dcf7e2e120f5 100644 --- a/src/decode.h +++ b/src/decode.h @@ -958,6 +958,7 @@ typedef int (*DecoderFunc)(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq); int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder); +int DecoderParseDataFromFileSerie(char *fileprefix, DecoderFunc Decoder); #endif /** \brief Set the No payload inspection Flag for the packet. diff --git a/src/suricata.c b/src/suricata.c index 7f16679525ee..92d728088097 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1261,7 +1261,11 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"afl-rules", required_argument, 0 , 0}, {"afl-mime", required_argument, 0 , 0}, {"afl-decoder-ppp", required_argument, 0 , 0}, + {"afl-decoder-ppp-serie", required_argument, 0 , 0}, {"afl-decoder-ipv4", required_argument, 0 , 0}, + {"afl-decoder-ipv4-serie", required_argument, 0 , 0}, + {"afl-decoder-ipv6", required_argument, 0 , 0}, + {"afl-decoder-ipv6-serie", required_argument, 0 , 0}, {"afl-der", required_argument, 0, 0}, #ifdef BUILD_UNIX_SOCKET @@ -1565,24 +1569,33 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) exit(MimeParserDataFromFile(optarg)); #endif #ifdef AFLFUZZ_DECODER - } else if(strcmp((long_opts[option_index]).name, "afl-decoder-ppp") == 0) { + } else if(strstr((long_opts[option_index]).name, "afl-decoder-ppp") != NULL) { StatsInit(); MpmTableSetup(); SpmTableSetup(); AppLayerProtoDetectSetup(); - DefragInit(); - FlowInitConfig(FLOW_QUIET); - //printf("arg: //%s\n", optarg); - exit(DecoderParseDataFromFile(optarg, DecodePPP)); - } else if(strcmp((long_opts[option_index]).name, "afl-decoder-ipv4") == 0) { + if (strcmp((long_opts[option_index]).name, "afl-decoder-ppp") == 0) + exit(DecoderParseDataFromFile(optarg, DecodePPP)); + else + exit(DecoderParseDataFromFileSerie(optarg, DecodePPP)); + } else if(strstr((long_opts[option_index]).name, "afl-decoder-ipv4") != NULL) { StatsInit(); MpmTableSetup(); SpmTableSetup(); AppLayerProtoDetectSetup(); - DefragInit(); - FlowInitConfig(FLOW_QUIET); - //printf("arg: //%s\n", optarg); - exit(DecoderParseDataFromFile(optarg, DecodeIPV4)); + if (strcmp((long_opts[option_index]).name, "afl-decoder-ipv4") == 0) + exit(DecoderParseDataFromFile(optarg, DecodeIPV4)); + else + exit(DecoderParseDataFromFileSerie(optarg, DecodeIPV4)); + } else if(strstr((long_opts[option_index]).name, "afl-decoder-ipv6") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp((long_opts[option_index]).name, "afl-decoder-ipv6") == 0) + exit(DecoderParseDataFromFile(optarg, DecodeIPV6)); + else + exit(DecoderParseDataFromFileSerie(optarg, DecodeIPV6)); #endif #ifdef AFLFUZZ_DER } else if(strcmp((long_opts[option_index]).name, "afl-der") == 0) { From 6bd265258e67873e9ccaa6a84ae2d8e3170793ba Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Feb 2017 18:34:20 +0100 Subject: [PATCH 2321/2553] afl: util script to list crashed series --- scripts/afl/listcrashedseries.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 scripts/afl/listcrashedseries.sh diff --git a/scripts/afl/listcrashedseries.sh b/scripts/afl/listcrashedseries.sh new file mode 100644 index 000000000000..16b7e3b72e4d --- /dev/null +++ b/scripts/afl/listcrashedseries.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +NAME=$1 + +SERIES=$(ls ${NAME}/dump/ |sort|cut -f 1 -d'.'|sort -u) + +for S in $SERIES; do + FILEPATH="${NAME}/dump/${S}.999" + if [ ! -f $FILEPATH ]; then + echo "SERIE $S incomplete, possible crash" + fi +done + From 322c260749c4ce74e912dd15572daaa344473599 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Feb 2017 19:10:02 +0100 Subject: [PATCH 2322/2553] afl: minimalistic script to start AFL fuzzers in suricata source dir: mkdir afl cd afl bash ../scripts/afl/runafl.sh decoder-ipv4 --- scripts/afl/runafl.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 scripts/afl/runafl.sh diff --git a/scripts/afl/runafl.sh b/scripts/afl/runafl.sh new file mode 100644 index 000000000000..2bab3ad1c8fd --- /dev/null +++ b/scripts/afl/runafl.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +PROTO=$1 + +if [ ! -d $1 ]; then + mkdir -p $1/output + mkdir -p $1/dump + mkdir -p $1/input + echo "1" > $1/input/seed.txt +else + CRASHES=$(ls ${1}/output/crashes|wc -l) + if [ $CRASHED -ne "0" ]; then + DIRNAME=$(date +%s) + mkdir "${1}/$DIRNAME" + mv -f ${1}/output/crashes/* ${1}/$DIRNAME/ + fi + mv -f $1/output/queue/id* $1/input/ + rm -r $1/output/ + mkdir $1/output +fi +cd $1 +export ASAN_OPTIONS="detect_leaks=0 abort_on_error=1 symbolize=0" +export AFL_SKIP_CPUFREQ=1 +/usr/local/bin/afl-fuzz -T ${PROTO} -t 1000 -m none -i input/ -o output/ -- ../../src/suricata --afl-${PROTO}=@@ From 35488eefdab64e074d33d414d8a8298ba4eb69c3 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 10 Feb 2017 11:21:57 -0600 Subject: [PATCH 2323/2553] afl: set the packet data so pktlen gets set --- src/decode-afl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/decode-afl.c b/src/decode-afl.c index 59fd6fe13c53..22faadd94399 100644 --- a/src/decode-afl.c +++ b/src/decode-afl.c @@ -83,6 +83,7 @@ int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder) { Packet *p = PacketGetFromAlloc(); if (p != NULL) { + PacketSetData(p, buffer, size); (void) Decoder (&tv, dtv, p, buffer, size, NULL); PacketFree(p); } @@ -133,6 +134,7 @@ int DecoderParseDataFromFileSerie(char *fileprefix, DecoderFunc Decoder) Packet *p = PacketGetFromAlloc(); if (p != NULL) { + PacketSetData(p, buffer, size); (void) Decoder (&tv, dtv, p, buffer, size, NULL); PacketFree(p); } From b56b04f84c08ef7c7ba7f1aae7c624cc3fcaae6e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 10 Feb 2017 19:58:27 +0100 Subject: [PATCH 2324/2553] afl: pass a packet queue to decoder calls --- src/decode-afl.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/decode-afl.c b/src/decode-afl.c index 22faadd94399..16b3ab87e478 100644 --- a/src/decode-afl.c +++ b/src/decode-afl.c @@ -62,6 +62,8 @@ int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder) { DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv); DecodeRegisterPerfCounters(dtv, &tv); StatsSetupPrivate(&tv); + PacketQueue pq; + memset(&pq, 0, sizeof(pq)); #ifdef AFLFUZZ_PERSISTANT_MODE while (__AFL_LOOP(1000)) { @@ -84,7 +86,13 @@ int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder) { Packet *p = PacketGetFromAlloc(); if (p != NULL) { PacketSetData(p, buffer, size); - (void) Decoder (&tv, dtv, p, buffer, size, NULL); + (void) Decoder (&tv, dtv, p, buffer, size, &pq); + while (1) { + Packet *extra_p = PacketDequeue(&pq); + if (unlikely(extra_p == NULL)) + break; + PacketFree(extra_p); + } PacketFree(p); } fclose(fp); @@ -122,6 +130,8 @@ int DecoderParseDataFromFileSerie(char *fileprefix, DecoderFunc Decoder) DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv); DecodeRegisterPerfCounters(dtv, &tv); StatsSetupPrivate(&tv); + PacketQueue pq; + memset(&pq, 0, sizeof(pq)); char filename[256]; snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt); @@ -135,7 +145,13 @@ int DecoderParseDataFromFileSerie(char *fileprefix, DecoderFunc Decoder) Packet *p = PacketGetFromAlloc(); if (p != NULL) { PacketSetData(p, buffer, size); - (void) Decoder (&tv, dtv, p, buffer, size, NULL); + (void) Decoder (&tv, dtv, p, buffer, size, &pq); + while (1) { + Packet *extra_p = PacketDequeue(&pq); + if (unlikely(extra_p == NULL)) + break; + PacketFree(extra_p); + } PacketFree(p); } fclose(fp); From 49c41fc79e869290b1db5179b2bb92682a95f68c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 11 Feb 2017 10:47:38 +0100 Subject: [PATCH 2325/2553] afl: clean up commandline parsing --- src/suricata.c | 404 +++++++++++++++++++++++++------------------------ 1 file changed, 209 insertions(+), 195 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index 92d728088097..257c79d5abb1 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1198,6 +1198,213 @@ static int ParseCommandLinePcapLive(SCInstance *suri, const char *in_arg) return TM_ECODE_OK; } +static void ParseCommandLineAFL(const char *opt_name, char *opt_arg) +{ +#ifdef AFLFUZZ_RULES + if(strcmp(opt_name, "afl-rules") == 0) { + MpmTableSetup(); + SpmTableSetup(); + exit(RuleParseDataFromFile(opt_arg)); + } else +#endif +#ifdef AFLFUZZ_APPLAYER + if(strcmp(opt_name, "afl-http-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterHTPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_HTTP, opt_arg)); + } else if(strcmp(opt_name, "afl-http") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterHTPParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_HTTP, opt_arg)); + + } else if(strcmp(opt_name, "afl-tls-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSSLParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_TLS, opt_arg)); + } else if(strcmp(opt_name, "afl-tls") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSSLParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_TLS, opt_arg)); + + } else if(strcmp(opt_name, "afl-dns-request") == 0) { + //printf("arg: //%s\n", opt_arg); + RegisterDNSUDPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_UDP, ALPROTO_DNS, opt_arg)); + } else if(strcmp(opt_name, "afl-dns") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterDNSUDPParsers(); + exit(AppLayerParserFromFile(IPPROTO_UDP, ALPROTO_DNS, opt_arg)); + + } else if(strcmp(opt_name, "afl-dnstcp-request") == 0) { + //printf("arg: //%s\n", opt_arg); + RegisterDNSTCPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_DNS, opt_arg)); + } else if(strcmp(opt_name, "afl-dnstcp") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterDNSTCPParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_DNS, opt_arg)); + + } else if(strcmp(opt_name, "afl-ssh-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + RegisterSSHParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SSH, opt_arg)); + } else if(strcmp(opt_name, "afl-ssh") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSSHParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SSH, opt_arg)); + + } else if(strcmp(opt_name, "afl-ftp-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterFTPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_FTP, opt_arg)); + } else if(strcmp(opt_name, "afl-ftp") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterFTPParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_FTP, opt_arg)); + + } else if(strcmp(opt_name, "afl-smtp-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSMTPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SMTP, opt_arg)); + } else if(strcmp(opt_name, "afl-smtp") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSMTPParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SMTP, opt_arg)); + + } else if(strcmp(opt_name, "afl-smb-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + RegisterSMBParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SMB, opt_arg)); + } else if(strcmp(opt_name, "afl-smb") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSMBParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SMB, opt_arg)); + + } else if(strcmp(opt_name, "afl-modbus-request") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterModbusParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_MODBUS, opt_arg)); + } else if(strcmp(opt_name, "afl-modbus") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterModbusParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_MODBUS, opt_arg)); + } else if(strcmp(opt_name, "afl-enip-request") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterENIPTCPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_ENIP, opt_arg)); + } else if(strcmp(opt_name, "afl-enip") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterENIPTCPParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_ENIP, opt_arg)); + } else if(strcmp(opt_name, "afl-dnp3-request") == 0) { + AppLayerParserSetup(); + RegisterDNP3Parsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_DNP3, opt_arg)); + } else if(strcmp(opt_name, "afl-dnp3") == 0) { + AppLayerParserSetup(); + RegisterDNP3Parsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_DNP3, opt_arg)); + } else +#endif +#ifdef AFLFUZZ_MIME + if(strcmp(opt_name, "afl-mime") == 0) { + //printf("arg: //%s\n", opt_arg); + exit(MimeParserDataFromFile(opt_arg)); + } else +#endif +#ifdef AFLFUZZ_DECODER + if(strstr(opt_name, "afl-decoder-ppp") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp(opt_name, "afl-decoder-ppp") == 0) + exit(DecoderParseDataFromFile(opt_arg, DecodePPP)); + else + exit(DecoderParseDataFromFileSerie(opt_arg, DecodePPP)); + } else if(strstr(opt_name, "afl-decoder-ipv4") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp(opt_name, "afl-decoder-ipv4") == 0) + exit(DecoderParseDataFromFile(opt_arg, DecodeIPV4)); + else + exit(DecoderParseDataFromFileSerie(opt_arg, DecodeIPV4)); + } else if(strstr(opt_name, "afl-decoder-ipv6") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp(opt_name, "afl-decoder-ipv6") == 0) + exit(DecoderParseDataFromFile(opt_arg, DecodeIPV6)); + else + exit(DecoderParseDataFromFileSerie(opt_arg, DecodeIPV6)); + } else +#endif +#ifdef AFLFUZZ_DER + if(strcmp(opt_name, "afl-der") == 0) { + //printf("arg: //%s\n", opt_arg); + exit(DerParseDataFromFile(opt_arg)); + } else +#endif + { + abort(); + } +} + static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) { int opt; @@ -1407,201 +1614,8 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } -#ifdef AFLFUZZ_RULES - } else if(strcmp((long_opts[option_index]).name, "afl-rules") == 0) { - MpmTableSetup(); - SpmTableSetup(); - exit(RuleParseDataFromFile(optarg)); -#endif -#ifdef AFLFUZZ_APPLAYER - } else if(strcmp((long_opts[option_index]).name, "afl-http-request") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - RegisterHTPParsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_HTTP, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-http") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - RegisterHTPParsers(); - exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_HTTP, optarg)); - - } else if(strcmp((long_opts[option_index]).name, "afl-tls-request") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - RegisterSSLParsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_TLS, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-tls") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - RegisterSSLParsers(); - exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_TLS, optarg)); - - } else if(strcmp((long_opts[option_index]).name, "afl-dns-request") == 0) { - //printf("arg: //%s\n", optarg); - RegisterDNSUDPParsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_UDP, ALPROTO_DNS, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-dns") == 0) { - //printf("arg: //%s\n", optarg); - AppLayerParserSetup(); - RegisterDNSUDPParsers(); - exit(AppLayerParserFromFile(IPPROTO_UDP, ALPROTO_DNS, optarg)); - - } else if(strcmp((long_opts[option_index]).name, "afl-dnstcp-request") == 0) { - //printf("arg: //%s\n", optarg); - RegisterDNSTCPParsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_DNS, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-dnstcp") == 0) { - //printf("arg: //%s\n", optarg); - AppLayerParserSetup(); - RegisterDNSTCPParsers(); - exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_DNS, optarg)); - - } else if(strcmp((long_opts[option_index]).name, "afl-ssh-request") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - RegisterSSHParsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SSH, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-ssh") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - RegisterSSHParsers(); - exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SSH, optarg)); - - } else if(strcmp((long_opts[option_index]).name, "afl-ftp-request") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - RegisterFTPParsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_FTP, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-ftp") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - RegisterFTPParsers(); - exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_FTP, optarg)); - - } else if(strcmp((long_opts[option_index]).name, "afl-smtp-request") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - RegisterSMTPParsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SMTP, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-smtp") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - RegisterSMTPParsers(); - exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SMTP, optarg)); - - } else if(strcmp((long_opts[option_index]).name, "afl-smb-request") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - RegisterSMBParsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SMB, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-smb") == 0) { - //printf("arg: //%s\n", optarg); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - RegisterSMBParsers(); - exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SMB, optarg)); - - } else if(strcmp((long_opts[option_index]).name, "afl-modbus-request") == 0) { - //printf("arg: //%s\n", optarg); - AppLayerParserSetup(); - RegisterModbusParsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_MODBUS, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-modbus") == 0) { - //printf("arg: //%s\n", optarg); - AppLayerParserSetup(); - RegisterModbusParsers(); - exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_MODBUS, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-enip-request") == 0) { - //printf("arg: //%s\n", optarg); - AppLayerParserSetup(); - RegisterENIPTCPParsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_ENIP, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-enip") == 0) { - //printf("arg: //%s\n", optarg); - AppLayerParserSetup(); - RegisterENIPTCPParsers(); - exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_ENIP, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-dnp3-request") == 0) { - AppLayerParserSetup(); - RegisterDNP3Parsers(); - exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_DNP3, optarg)); - } else if(strcmp((long_opts[option_index]).name, "afl-dnp3") == 0) { - AppLayerParserSetup(); - RegisterDNP3Parsers(); - exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_DNP3, optarg)); -#endif -#ifdef AFLFUZZ_MIME - } else if(strcmp((long_opts[option_index]).name, "afl-mime") == 0) { - //printf("arg: //%s\n", optarg); - exit(MimeParserDataFromFile(optarg)); -#endif -#ifdef AFLFUZZ_DECODER - } else if(strstr((long_opts[option_index]).name, "afl-decoder-ppp") != NULL) { - StatsInit(); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - if (strcmp((long_opts[option_index]).name, "afl-decoder-ppp") == 0) - exit(DecoderParseDataFromFile(optarg, DecodePPP)); - else - exit(DecoderParseDataFromFileSerie(optarg, DecodePPP)); - } else if(strstr((long_opts[option_index]).name, "afl-decoder-ipv4") != NULL) { - StatsInit(); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - if (strcmp((long_opts[option_index]).name, "afl-decoder-ipv4") == 0) - exit(DecoderParseDataFromFile(optarg, DecodeIPV4)); - else - exit(DecoderParseDataFromFileSerie(optarg, DecodeIPV4)); - } else if(strstr((long_opts[option_index]).name, "afl-decoder-ipv6") != NULL) { - StatsInit(); - MpmTableSetup(); - SpmTableSetup(); - AppLayerProtoDetectSetup(); - if (strcmp((long_opts[option_index]).name, "afl-decoder-ipv6") == 0) - exit(DecoderParseDataFromFile(optarg, DecodeIPV6)); - else - exit(DecoderParseDataFromFileSerie(optarg, DecodeIPV6)); -#endif -#ifdef AFLFUZZ_DER - } else if(strcmp((long_opts[option_index]).name, "afl-der") == 0) { - //printf("arg: //%s\n", optarg); - exit(DerParseDataFromFile(optarg)); -#endif + } else if(strncmp((long_opts[option_index]).name, "afl-", 4) == 0) { + ParseCommandLineAFL((long_opts[option_index]).name, optarg); } else if(strcmp((long_opts[option_index]).name, "simulate-ips") == 0) { SCLogInfo("Setting IPS mode"); EngineModeSetIPS(); From 292baf0872abfebf2762e08e613565703595db6c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 12 Feb 2017 07:52:04 +0100 Subject: [PATCH 2326/2553] afl: add ethernet and erspan entry points --- src/suricata.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index 257c79d5abb1..40ac45709dcb 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1392,6 +1392,24 @@ static void ParseCommandLineAFL(const char *opt_name, char *opt_arg) exit(DecoderParseDataFromFile(opt_arg, DecodeIPV6)); else exit(DecoderParseDataFromFileSerie(opt_arg, DecodeIPV6)); + } else if(strstr(opt_name, "afl-decoder-ethernet") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp(opt_name, "afl-decoder-ethernet") == 0) + exit(DecoderParseDataFromFile(opt_arg, DecodeEthernet)); + else + exit(DecoderParseDataFromFileSerie(opt_arg, DecodeEthernet)); + } else if(strstr(opt_name, "afl-decoder-erspan") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp(opt_name, "afl-decoder-erspan") == 0) + exit(DecoderParseDataFromFile(opt_arg, DecodeERSPAN)); + else + exit(DecoderParseDataFromFileSerie(opt_arg, DecodeERSPAN)); } else #endif #ifdef AFLFUZZ_DER @@ -1469,6 +1487,10 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"afl-mime", required_argument, 0 , 0}, {"afl-decoder-ppp", required_argument, 0 , 0}, {"afl-decoder-ppp-serie", required_argument, 0 , 0}, + {"afl-decoder-ethernet", required_argument, 0 , 0}, + {"afl-decoder-ethernet-serie", required_argument, 0 , 0}, + {"afl-decoder-erspan", required_argument, 0 , 0}, + {"afl-decoder-erspan-serie", required_argument, 0 , 0}, {"afl-decoder-ipv4", required_argument, 0 , 0}, {"afl-decoder-ipv4-serie", required_argument, 0 , 0}, {"afl-decoder-ipv6", required_argument, 0 , 0}, From 4a04f814b15762eb446a5ead4d69d021512df6f8 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Sun, 5 Feb 2017 07:57:54 -0600 Subject: [PATCH 2327/2553] defrag - take protocol into account during re-assembly The IP protocol was not being used to match fragments with their packets allowing a carefully constructed packet with a different protocol to be matched, allowing re-assembly to complete, creating a packet that would not be re-assembled by the destination host. --- src/defrag-hash.c | 2 + src/defrag.c | 170 +++++++++++++++++++++++++++------------------- src/defrag.h | 2 + 3 files changed, 106 insertions(+), 68 deletions(-) diff --git a/src/defrag-hash.c b/src/defrag-hash.c index 082eb4967380..736099c58761 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -92,6 +92,7 @@ static void DefragTrackerInit(DefragTracker *dt, Packet *p) dt->id = (int32_t)IPV6_EXTHDR_GET_FH_ID(p); dt->af = AF_INET6; } + dt->proto = IP_GET_IPPROTO(p); dt->vlan_id[0] = p->vlan_id[0]; dt->vlan_id[1] = p->vlan_id[1]; dt->policy = DefragGetOsPolicy(p); @@ -406,6 +407,7 @@ static inline uint32_t DefragHashGetKey(Packet *p) CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \ (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && \ CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \ + (d1)->proto == IP_GET_IPPROTO(p) && \ (d1)->id == (id) && \ (d1)->vlan_id[0] == (d2)->vlan_id[0] && \ (d1)->vlan_id[1] == (d2)->vlan_id[1]) diff --git a/src/defrag.c b/src/defrag.c index c7ebd9f97649..5433ce78607c 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -996,8 +996,8 @@ void DefragDestroy(void) * with some payload of no particular protocol. */ static Packet * -BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content, - int content_len) +BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf, + const char content, int content_len) { Packet *p = NULL; int hlen = 20; @@ -1023,7 +1023,7 @@ BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content, else ip4h.ip_off = htons(off); ip4h.ip_ttl = ttl; - ip4h.ip_proto = IPPROTO_ICMP; + ip4h.ip_proto = proto; ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */ ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */ @@ -1059,7 +1059,7 @@ BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content, goto error; if (IPV4_GET_IPTTL(p) != ttl) goto error; - if (IPV4_GET_IPPROTO(p) != IPPROTO_ICMP) + if (IPV4_GET_IPPROTO(p) != proto) goto error; return p; @@ -1074,8 +1074,8 @@ void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, uint16_t prev_hdrextlen); static Packet * -IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, - int content_len) +IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off, int mf, + const char content, int content_len) { Packet *p = NULL; uint8_t *pcontent; @@ -1109,7 +1109,7 @@ IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, IPV6_SET_RAW_VER(p->ip6h, 6); /* Fragmentation header. */ IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr)); - fh->ip6fh_nxt = IPPROTO_ICMP; + fh->ip6fh_nxt = proto; fh->ip6fh_ident = htonl(id); fh->ip6fh_offlg = htons((off << 3) | mf); @@ -1159,13 +1159,13 @@ DefragInOrderSimpleTest(void) DefragInit(); - p1 = BuildTestPacket(id, 0, 1, 'A', 8); + p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8); if (p1 == NULL) goto end; - p2 = BuildTestPacket(id, 1, 1, 'B', 8); + p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8); if (p2 == NULL) goto end; - p3 = BuildTestPacket(id, 2, 0, 'C', 3); + p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3); if (p3 == NULL) goto end; @@ -1236,13 +1236,13 @@ DefragReverseSimpleTest(void) DefragInit(); - p1 = BuildTestPacket(id, 0, 1, 'A', 8); + p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8); if (p1 == NULL) goto end; - p2 = BuildTestPacket(id, 1, 1, 'B', 8); + p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8); if (p2 == NULL) goto end; - p3 = BuildTestPacket(id, 2, 0, 'C', 3); + p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3); if (p3 == NULL) goto end; @@ -1308,13 +1308,13 @@ IPV6DefragInOrderSimpleTest(void) DefragInit(); - p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8); + p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8); if (p1 == NULL) goto end; - p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8); + p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8); if (p2 == NULL) goto end; - p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3); + p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3); if (p3 == NULL) goto end; @@ -1378,13 +1378,13 @@ IPV6DefragReverseSimpleTest(void) if (dc == NULL) goto end; - p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8); + p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8); if (p1 == NULL) goto end; - p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8); + p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8); if (p2 == NULL) goto end; - p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3); + p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3); if (p3 == NULL) goto end; @@ -1452,59 +1452,59 @@ DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) */ /* A*24 at 0. */ - packets[0] = BuildTestPacket(id, 0, 1, 'A', 24); + packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24); /* B*15 at 32. */ - packets[1] = BuildTestPacket(id, 32 >> 3, 1, 'B', 16); + packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16); /* C*24 at 48. */ - packets[2] = BuildTestPacket(id, 48 >> 3, 1, 'C', 24); + packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24); /* D*8 at 80. */ - packets[3] = BuildTestPacket(id, 80 >> 3, 1, 'D', 8); + packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8); /* E*16 at 104. */ - packets[4] = BuildTestPacket(id, 104 >> 3, 1, 'E', 16); + packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16); /* F*24 at 120. */ - packets[5] = BuildTestPacket(id, 120 >> 3, 1, 'F', 24); + packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24); /* G*16 at 144. */ - packets[6] = BuildTestPacket(id, 144 >> 3, 1, 'G', 16); + packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16); /* H*16 at 160. */ - packets[7] = BuildTestPacket(id, 160 >> 3, 1, 'H', 16); + packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16); /* I*8 at 176. */ - packets[8] = BuildTestPacket(id, 176 >> 3, 1, 'I', 8); + packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8); /* * Overlapping subsequent fragments. */ /* J*32 at 8. */ - packets[9] = BuildTestPacket(id, 8 >> 3, 1, 'J', 32); + packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32); /* K*24 at 48. */ - packets[10] = BuildTestPacket(id, 48 >> 3, 1, 'K', 24); + packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24); /* L*24 at 72. */ - packets[11] = BuildTestPacket(id, 72 >> 3, 1, 'L', 24); + packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24); /* M*24 at 96. */ - packets[12] = BuildTestPacket(id, 96 >> 3, 1, 'M', 24); + packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24); /* N*8 at 128. */ - packets[13] = BuildTestPacket(id, 128 >> 3, 1, 'N', 8); + packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8); /* O*8 at 152. */ - packets[14] = BuildTestPacket(id, 152 >> 3, 1, 'O', 8); + packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8); /* P*8 at 160. */ - packets[15] = BuildTestPacket(id, 160 >> 3, 1, 'P', 8); + packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8); /* Q*16 at 176. */ - packets[16] = BuildTestPacket(id, 176 >> 3, 0, 'Q', 16); + packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16); default_policy = policy; @@ -1587,59 +1587,59 @@ IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) */ /* A*24 at 0. */ - packets[0] = IPV6BuildTestPacket(id, 0, 1, 'A', 24); + packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24); /* B*15 at 32. */ - packets[1] = IPV6BuildTestPacket(id, 32 >> 3, 1, 'B', 16); + packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16); /* C*24 at 48. */ - packets[2] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'C', 24); + packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24); /* D*8 at 80. */ - packets[3] = IPV6BuildTestPacket(id, 80 >> 3, 1, 'D', 8); + packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8); /* E*16 at 104. */ - packets[4] = IPV6BuildTestPacket(id, 104 >> 3, 1, 'E', 16); + packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16); /* F*24 at 120. */ - packets[5] = IPV6BuildTestPacket(id, 120 >> 3, 1, 'F', 24); + packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24); /* G*16 at 144. */ - packets[6] = IPV6BuildTestPacket(id, 144 >> 3, 1, 'G', 16); + packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16); /* H*16 at 160. */ - packets[7] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'H', 16); + packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16); /* I*8 at 176. */ - packets[8] = IPV6BuildTestPacket(id, 176 >> 3, 1, 'I', 8); + packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8); /* * Overlapping subsequent fragments. */ /* J*32 at 8. */ - packets[9] = IPV6BuildTestPacket(id, 8 >> 3, 1, 'J', 32); + packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32); /* K*24 at 48. */ - packets[10] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'K', 24); + packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24); /* L*24 at 72. */ - packets[11] = IPV6BuildTestPacket(id, 72 >> 3, 1, 'L', 24); + packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24); /* M*24 at 96. */ - packets[12] = IPV6BuildTestPacket(id, 96 >> 3, 1, 'M', 24); + packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24); /* N*8 at 128. */ - packets[13] = IPV6BuildTestPacket(id, 128 >> 3, 1, 'N', 8); + packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8); /* O*8 at 152. */ - packets[14] = IPV6BuildTestPacket(id, 152 >> 3, 1, 'O', 8); + packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8); /* P*8 at 160. */ - packets[15] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'P', 8); + packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8); /* Q*16 at 176. */ - packets[16] = IPV6BuildTestPacket(id, 176 >> 3, 0, 'Q', 16); + packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16); default_policy = policy; @@ -2125,7 +2125,7 @@ DefragTimeoutTest(void) /* Load in 16 packets. */ for (i = 0; i < 16; i++) { - Packet *p = BuildTestPacket(i, 0, 1, 'A' + i, 16); + Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16); if (p == NULL) goto end; @@ -2141,7 +2141,7 @@ DefragTimeoutTest(void) /* Build a new packet but push the timestamp out by our timeout. * This should force our previous fragments to be timed out. */ - Packet *p = BuildTestPacket(99, 0, 1, 'A' + i, 16); + Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16); if (p == NULL) goto end; @@ -2189,7 +2189,7 @@ DefragIPv4NoDataTest(void) goto end; /* This packet has an offset > 0, more frags set to 0 and no data. */ - p = BuildTestPacket(id, 1, 0, 'A', 0); + p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0); if (p == NULL) goto end; @@ -2228,7 +2228,7 @@ DefragIPv4TooLargeTest(void) /* Create a fragment that would extend past the max allowable size * for an IPv4 packet. */ - p = BuildTestPacket(1, 8183, 0, 'A', 71); + p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71); if (p == NULL) goto end; @@ -2267,10 +2267,10 @@ DefragVlanTest(void) DefragInit(); - p1 = BuildTestPacket(1, 0, 1, 'A', 8); + p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8); if (p1 == NULL) goto end; - p2 = BuildTestPacket(1, 1, 0, 'B', 8); + p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8); if (p2 == NULL) goto end; @@ -2313,10 +2313,10 @@ DefragVlanQinQTest(void) DefragInit(); - p1 = BuildTestPacket(1, 0, 1, 'A', 8); + p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8); if (p1 == NULL) goto end; - p2 = BuildTestPacket(1, 1, 0, 'B', 8); + p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8); if (p2 == NULL) goto end; @@ -2361,7 +2361,7 @@ static int DefragTrackerReuseTest(void) /* Build a packet, its not a fragment but shouldn't matter for * this test. */ - p1 = BuildTestPacket(id, 0, 0, 'A', 8); + p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8); if (p1 == NULL) { goto end; } @@ -2431,9 +2431,9 @@ static int DefragMfIpv4Test(void) DefragInit(); - Packet *p1 = BuildTestPacket(ip_id, 2, 1, 'C', 8); - Packet *p2 = BuildTestPacket(ip_id, 0, 1, 'A', 8); - Packet *p3 = BuildTestPacket(ip_id, 1, 0, 'B', 8); + Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8); + Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8); + Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8); if (p1 == NULL || p2 == NULL || p3 == NULL) { goto end; } @@ -2495,9 +2495,9 @@ static int DefragMfIpv6Test(void) DefragInit(); - Packet *p1 = IPV6BuildTestPacket(ip_id, 2, 1, 'C', 8); - Packet *p2 = IPV6BuildTestPacket(ip_id, 0, 1, 'A', 8); - Packet *p3 = IPV6BuildTestPacket(ip_id, 1, 0, 'B', 8); + Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8); + Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8); + Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8); if (p1 == NULL || p2 == NULL || p3 == NULL) { goto end; } @@ -2542,6 +2542,39 @@ static int DefragMfIpv6Test(void) return retval; } +/** + * \brief Test that fragments that match other than the proto don't + * actually get matched. + */ +static int DefragTestBadProto(void) +{ + Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; + int id = 12; + + DefragInit(); + + p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8); + FAIL_IF_NULL(p1); + p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8); + FAIL_IF_NULL(p2); + p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3); + FAIL_IF_NULL(p3); + + FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1, NULL)); + FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2, NULL)); + FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3, NULL)); + + if (p1 != NULL) + SCFree(p1); + if (p2 != NULL) + SCFree(p2); + if (p3 != NULL) + SCFree(p3); + + DefragDestroy(); + PASS; +} + #endif /* UNITTESTS */ void @@ -2583,6 +2616,7 @@ DefragRegisterTests(void) UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest); UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test); UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test); + UtRegisterTest("DefragTestBadProto", DefragTestBadProto); #endif /* UNITTESTS */ } diff --git a/src/defrag.h b/src/defrag.h index 2dfaec60cf30..c3a0c693733a 100644 --- a/src/defrag.h +++ b/src/defrag.h @@ -84,6 +84,8 @@ typedef struct DefragTracker_ { uint32_t id; /**< IP ID for this tracker. 32 bits for IPv6, 16 * for IPv4. */ + uint8_t proto; /**< IP protocol for this tracker. */ + uint8_t policy; /**< Reassembly policy this tracker will use. */ uint8_t af; /**< Address family for this tracker, AF_INET or From 20990f7a7eb7939946a275dfc9a95426b0080a19 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Feb 2017 15:40:30 +0100 Subject: [PATCH 2328/2553] dns: fix out of bounds read On a zero size A or AAAA record, 4 or 16 bytes would still be read. Found with AFL+ASAN. --- src/app-layer-dns-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 3eb507adbf28..c9f7eb334595 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -858,7 +858,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), - data, 4, ntohs(dns_header->tx_id)); + data, datalen, ntohs(dns_header->tx_id)); } else { SCLogDebug("invalid length for A response data: %u", ntohs(head->len)); goto bad_data; @@ -876,7 +876,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), - data, 16, ntohs(dns_header->tx_id)); + data, datalen, ntohs(dns_header->tx_id)); } else { SCLogDebug("invalid length for AAAA response data: %u", ntohs(head->len)); goto bad_data; From 71710f088e5568621b323c253b154052e3161658 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Feb 2017 10:39:26 +0100 Subject: [PATCH 2329/2553] dns: fix outputs with 0-len A/AAAA records --- src/log-dnslog.c | 4 ++-- src/output-json-dns.c | 4 ++-- src/util-lua-dns.c | 10 +++++++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/log-dnslog.c b/src/log-dnslog.c index ea32c6b292e7..297e98f080c4 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -138,11 +138,11 @@ static void LogAnswer(LogDnsLogThread *aft, char *timebuf, char *srcip, char *ds " [**] %s [**] TTL %u [**] ", record, entry->ttl); uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry) + entry->fqdn_len); - if (entry->type == DNS_RECORD_TYPE_A) { + if (entry->type == DNS_RECORD_TYPE_A && entry->data_len == 4) { char a[16] = ""; PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); MemBufferWriteString(aft->buffer, "%s", a); - } else if (entry->type == DNS_RECORD_TYPE_AAAA) { + } else if (entry->type == DNS_RECORD_TYPE_AAAA && entry->data_len == 16) { char a[46]; PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); MemBufferWriteString(aft->buffer, "%s", a); diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 948cce7def8c..96689777ec24 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -479,11 +479,11 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, json_object_set_new(js, "ttl", json_integer(entry->ttl)); uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len); - if (entry->type == DNS_RECORD_TYPE_A) { + if (entry->type == DNS_RECORD_TYPE_A && entry->data_len == 4) { char a[16] = ""; PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); json_object_set_new(js, "rdata", json_string(a)); - } else if (entry->type == DNS_RECORD_TYPE_AAAA) { + } else if (entry->type == DNS_RECORD_TYPE_AAAA && entry->data_len == 16) { char a[46] = ""; PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); json_object_set_new(js, "rdata", json_string(a)); diff --git a/src/util-lua-dns.c b/src/util-lua-dns.c index dcebc6a13204..b43413f377e3 100644 --- a/src/util-lua-dns.c +++ b/src/util-lua-dns.c @@ -214,13 +214,17 @@ static int DnsGetAnswerTable(lua_State *luastate) ptr = (uint8_t *)((uint8_t *)answer + sizeof(DNSAnswerEntry) + answer->fqdn_len); if (answer->type == DNS_RECORD_TYPE_A) { char a[16] = ""; - PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); + if (answer->data_len == 4) { + PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); + } lua_pushstring(luastate, "addr"); LuaPushStringBuffer(luastate, (uint8_t *)a, strlen(a)); lua_settable(luastate, -3); } else if (answer->type == DNS_RECORD_TYPE_AAAA) { - char a[46]; - PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); + char a[46] = ""; + if (answer->data_len == 16) { + PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); + } lua_pushstring(luastate, "addr"); LuaPushStringBuffer(luastate, (uint8_t *)a, strlen(a)); lua_settable(luastate, -3); From e072a10f64cd509d09e0349050b92b02fea4df9c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 15 Feb 2017 08:49:07 +0100 Subject: [PATCH 2330/2553] changelog: update for 3.2.1 release --- ChangeLog | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/ChangeLog b/ChangeLog index bdbc04129140..9401b1579f4e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,36 @@ +3.2.1 -- 2017-02-15 + +Feature #1951: Allow building without libmagic/file +Feature #1972: SURICATA ICMPv6 unknown type 143 for MLDv2 report +Feature #2010: Suricata should confirm SSSE3 presence at runtime when built with Hyperscan support +Bug #467: compilation with unittests & debug validation +Bug #1780: VLAN tags not forwarded in afpacket inline mode +Bug #1827: Mpm AC fails to alloc memory +Bug #1843: Mpm Ac: int overflow during init +Bug #1887: pcap-log sets snaplen to -1 +Bug #1946: can't get response info in some situation +Bug #1973: suricata fails to start because of unix socket +Bug #1975: hostbits/xbits memory leak +Bug #1982: tls: invalid record event triggers on valid traffic +Bug #1984: http: protocol detection issue if both sides are malformed +Bug #1985: pcap-log: minor memory leaks +Bug #1987: log-pcap: pcap files created with invalid snaplen +Bug #1988: tls_cert_subject bug +Bug #1989: SMTP protocol detection is case sensitive +Bug #1991: Suricata cannot parse ports: "![1234, 1235]" +Bug #1997: tls-store: bug that cause Suricata to crash +Bug #2001: Handling of unsolicited DNS responses. +Bug #2003: BUG_ON body sometimes contains side-effectual code +Bug #2004: Invalid file hash computation when force-hash is used +Bug #2005: Incoherent sizes between request, capture and http length +Bug #2007: smb: protocol detection just checks toserver +Bug #2008: Suricata 3.2, pcap-log no longer works due to timestamp_pattern PCRE +Bug #2009: Suricata is unable to get offloading settings when run under non-root +Bug #2012: dns.log does not log unanswered queries +Bug #2017: EVE Log Missing Fields +Bug #2019: IPv4 defrag evasion issue +Bug #2022: dns: out of bound memory read + 3.2 -- 2016-12-01 Bug #1117: PCAP file count does not persist From 113a238e9045f14edd17e049da7c17aa2c453fea Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Feb 2017 10:35:19 +0100 Subject: [PATCH 2331/2553] Open 4.0 development branch --- configure.ac | 2 +- src/suricata.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index f2e7ffcb5ee3..9129c5fe77ed 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ - AC_INIT(suricata, 3.2dev) + AC_INIT(suricata, 4.0dev) m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])AM_SILENT_RULES([yes]) m4_ifndef([AS_VERSION_COMPARE], [AC_DEFUN([AS_VERSION_COMPARE],[])]) AC_CONFIG_HEADERS([config.h]) diff --git a/src/suricata.h b/src/suricata.h index 42482bb03394..912f33b5d648 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -71,7 +71,7 @@ /* the name of our binary */ #define PROG_NAME "Suricata" -#define PROG_VER "3.2dev" +#define PROG_VER "4.0dev" /* workaround SPlint error (don't know __gnuc_va_list) */ #ifdef S_SPLINT_S From be3ee5330fdb40a4d7ee128eff43a136aabf3f6d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 14:24:44 +0100 Subject: [PATCH 2332/2553] detect: remove alproto from keyword registration It was already marked as depricated and no longer in use anywhere. --- src/detect.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/detect.h b/src/detect.h index d0c0e58b4e62..30d95f014be5 100644 --- a/src/detect.h +++ b/src/detect.h @@ -985,9 +985,6 @@ typedef struct SigTableElmt_ { uint8_t flags; - /** unused: warn user. Will be removed in the future. */ - AppProto alproto __attribute__((deprecated)); - char *name; /**< keyword name alias */ char *alias; /**< name alias */ char *desc; From a44da9f5cb0be1c1c85ce847a86d4addaf2868d8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 18 Oct 2016 00:41:17 +0200 Subject: [PATCH 2333/2553] detect: simplify SIG_FLAG_STATE_MATCH set logic --- src/detect-engine.c | 2 ++ src/detect-parse.c | 77 ++------------------------------------------- 2 files changed, 4 insertions(+), 75 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index e1af308ed11e..05fe1a0f7648 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -190,6 +190,8 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) new_engine->inspect_flags = BIT_U32(new_engine->id + DE_STATE_FLAG_BASE); } SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id); + + s->flags |= SIG_FLAG_STATE_MATCH; next: t = t->next; } diff --git a/src/detect-parse.c b/src/detect-parse.c index 7307d974be7b..17042cb54dd0 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1559,85 +1559,12 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (sig->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) sig->flags |= SIG_FLAG_APPLAYER; - if (sig->sm_lists[DETECT_SM_LIST_UMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_DMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_AMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HTTP_REQLINEMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HTTP_RESLINEMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HCBDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_FILEDATA]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HHDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HRHDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HMDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HCDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HRUDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_FILEMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HSMDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HSCDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HUADMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HHHDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HRHHDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - - /* DNP3. */ - if (sig->sm_lists[DETECT_SM_LIST_DNP3_DATA_MATCH]) { - sig->flags |= SIG_FLAG_STATE_MATCH; - } - if (sig->sm_lists[DETECT_SM_LIST_DNP3_MATCH]) { - sig->flags |= SIG_FLAG_STATE_MATCH; - } - - /* Template. */ - if (sig->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH]) { - sig->flags |= SIG_FLAG_STATE_MATCH; - } - - /* DNS */ - if (sig->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_DNSREQUEST_MATCH]) { - sig->flags |= SIG_FLAG_STATE_MATCH; - } - if (sig->sm_lists[DETECT_SM_LIST_DNSRESPONSE_MATCH]) { - sig->flags |= SIG_FLAG_STATE_MATCH; - } - - /* TLS */ - if (sig->sm_lists[DETECT_SM_LIST_TLSSNI_MATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_TLSISSUER_MATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_TLSSUBJECT_MATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_TLSVALIDITY_MATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - - if (sig->sm_lists[DETECT_SM_LIST_MODBUS_MATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_APP_EVENT]) - sig->flags |= SIG_FLAG_STATE_MATCH; - - if (sig->sm_lists[DETECT_SM_LIST_CIP_MATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_ENIP_MATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; + /* for other lists this flag is set when the inspect engines + * are registered */ if (!(sig->init_flags & SIG_FLAG_INIT_FLOW)) { sig->flags |= SIG_FLAG_TOSERVER; From bfd4bc82333a5d0990a5acd81283758e2c9e425c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Oct 2016 10:49:14 +0200 Subject: [PATCH 2334/2553] detect: constify Signature/SigMatch use at runtime --- src/alert-unified2-alert.c | 30 +++++++------- src/decode.h | 2 +- src/detect-ack.c | 4 +- src/detect-app-layer-event.c | 14 +++---- src/detect-app-layer-protocol.c | 2 +- src/detect-asn1.c | 4 +- src/detect-base64-data.h | 2 +- src/detect-base64-decode.c | 2 +- src/detect-base64-decode.h | 4 +- src/detect-bypass.c | 6 ++- src/detect-byte-extract.c | 12 +++--- src/detect-byte-extract.h | 6 +-- src/detect-bytejump.c | 4 +- src/detect-bytejump.h | 4 +- src/detect-bytetest.c | 6 ++- src/detect-bytetest.h | 4 +- src/detect-csum.c | 56 +++++++++++++------------- src/detect-dce-iface.c | 9 +++-- src/detect-dce-opnum.c | 9 +++-- src/detect-detection-filter.c | 6 ++- src/detect-dnp3.c | 4 +- src/detect-dsize.c | 6 ++- src/detect-engine-alert.c | 3 +- src/detect-engine-alert.h | 3 +- src/detect-engine-content-inspection.c | 2 +- src/detect-engine-content-inspection.h | 2 +- src/detect-engine-dcepayload.c | 2 +- src/detect-engine-dcepayload.h | 2 +- src/detect-engine-dns.c | 6 +-- src/detect-engine-dns.h | 6 +-- src/detect-engine-enip.c | 4 +- src/detect-engine-enip.h | 4 +- src/detect-engine-event.c | 6 ++- src/detect-engine-file.h | 4 +- src/detect-engine-filedata-smtp.h | 2 +- src/detect-engine-hcbd.h | 2 +- src/detect-engine-hcd.c | 2 +- src/detect-engine-hcd.h | 2 +- src/detect-engine-hhd.c | 2 +- src/detect-engine-hhd.h | 2 +- src/detect-engine-hhhd.c | 2 +- src/detect-engine-hhhd.h | 2 +- src/detect-engine-hmd.c | 2 +- src/detect-engine-hmd.h | 2 +- src/detect-engine-hrhd.c | 2 +- src/detect-engine-hrhd.h | 2 +- src/detect-engine-hrhhd.c | 2 +- src/detect-engine-hrhhd.h | 2 +- src/detect-engine-hrud.c | 2 +- src/detect-engine-hrud.h | 2 +- src/detect-engine-hsbd.h | 2 +- src/detect-engine-hscd.c | 2 +- src/detect-engine-hscd.h | 2 +- src/detect-engine-hsmd.c | 2 +- src/detect-engine-hsmd.h | 2 +- src/detect-engine-hua.c | 2 +- src/detect-engine-hua.h | 2 +- src/detect-engine-modbus.c | 2 +- src/detect-engine-modbus.h | 2 +- src/detect-engine-payload.c | 2 +- src/detect-engine-payload.h | 4 +- src/detect-engine-state.c | 20 ++++----- src/detect-engine-state.h | 5 ++- src/detect-engine-template.h | 2 +- src/detect-engine-tls.c | 2 +- src/detect-engine-tls.h | 8 ++-- src/detect-engine-uri.h | 2 +- src/detect-engine.c | 2 +- src/detect-engine.h | 2 +- src/detect-fileext.c | 4 +- src/detect-filemagic.c | 4 +- src/detect-filename.c | 4 +- src/detect-filesize.c | 4 +- src/detect-filestore.c | 6 +-- src/detect-filestore.h | 4 +- src/detect-flags.c | 6 ++- src/detect-flow.c | 6 ++- src/detect-flowbits.c | 6 ++- src/detect-flowint.c | 4 +- src/detect-flowvar.c | 11 +++-- src/detect-fragbits.c | 5 ++- src/detect-fragoffset.c | 6 ++- src/detect-ftpbounce.c | 18 ++++----- src/detect-hostbits.c | 6 ++- src/detect-http-request-line.c | 4 +- src/detect-http-response-line.c | 4 +- src/detect-icmp-id.c | 6 ++- src/detect-icmp-seq.c | 6 ++- src/detect-icode.c | 6 ++- src/detect-id.c | 8 ++-- src/detect-ipopts.c | 6 ++- src/detect-iprep.c | 6 ++- src/detect-itype.c | 6 ++- src/detect-lua.c | 11 ++--- src/detect-lua.h | 3 +- src/detect-mark.c | 6 ++- src/detect-pcre.c | 4 +- src/detect-pcre.h | 3 +- src/detect-pktvar.c | 6 ++- src/detect-rpc.c | 8 ++-- src/detect-sameip.c | 4 +- src/detect-seq.c | 4 +- src/detect-ssh-proto-version.c | 6 ++- src/detect-ssh-software-version.c | 6 ++- src/detect-ssl-state.c | 12 +++--- src/detect-ssl-version.c | 9 +++-- src/detect-stream_size.c | 6 ++- src/detect-tag.c | 6 ++- src/detect-template.c | 4 +- src/detect-threshold.c | 6 ++- src/detect-tls-version.c | 6 ++- src/detect-tls.c | 20 +++++---- src/detect-tos.c | 6 +-- src/detect-ttl.c | 6 ++- src/detect-window.c | 12 +++--- src/detect-xbits.c | 4 +- src/detect.c | 26 ++++++------ src/detect.h | 24 +++++------ src/util-detect-file-hash.c | 2 +- src/util-detect-file-hash.h | 2 +- 120 files changed, 384 insertions(+), 313 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index b922fe8f5eea..2628676fa644 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -1455,10 +1455,10 @@ static int Unified2Test01(void) memset(&s, 0, sizeof(Signature)); p->alerts.cnt++; + s.id = 1; + s.gid = 1; + s.rev = 1; p->alerts.alerts[p->alerts.cnt-1].s = &s; - p->alerts.alerts[p->alerts.cnt-1].s->id = 1; - p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; - p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ipv4_tcp)); FlowInitConfig(FLOW_QUIET); @@ -1546,10 +1546,10 @@ static int Unified2Test02(void) memset(&s, 0, sizeof(Signature)); p->alerts.cnt++; + s.id = 1; + s.gid = 1; + s.rev = 1; p->alerts.alerts[p->alerts.cnt-1].s = &s; - p->alerts.alerts[p->alerts.cnt-1].s->id = 1; - p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; - p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ipv6_tcp)); FlowInitConfig(FLOW_QUIET); @@ -1643,10 +1643,10 @@ static int Unified2Test03(void) memset(&s, 0, sizeof(Signature)); p->alerts.cnt++; + s.id = 1; + s.gid = 1; + s.rev = 1; p->alerts.alerts[p->alerts.cnt-1].s = &s; - p->alerts.alerts[p->alerts.cnt-1].s->id = 1; - p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; - p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_gre)); FlowInitConfig(FLOW_QUIET); @@ -1740,10 +1740,10 @@ static int Unified2Test04(void) memset(&s, 0, sizeof(Signature)); p->alerts.cnt++; + s.id = 1; + s.gid = 1; + s.rev = 1; p->alerts.alerts[p->alerts.cnt-1].s = &s; - p->alerts.alerts[p->alerts.cnt-1].s->id = 1; - p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; - p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ppp)); FlowInitConfig(FLOW_QUIET); @@ -1828,10 +1828,10 @@ static int Unified2Test05(void) memset(&s, 0, sizeof(Signature)); p->alerts.cnt++; + s.id = 1; + s.gid = 1; + s.rev = 1; p->alerts.alerts[p->alerts.cnt-1].s = &s; - p->alerts.alerts[p->alerts.cnt-1].s->id = 1; - p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; - p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ipv4_tcp)); FlowInitConfig(FLOW_QUIET); diff --git a/src/decode.h b/src/decode.h index dcf7e2e120f5..d11b1cf931dd 100644 --- a/src/decode.h +++ b/src/decode.h @@ -260,7 +260,7 @@ typedef struct PacketAlert_ { SigIntId num; /* Internal num, used for sorting */ uint8_t action; /* Internal num, used for sorting */ uint8_t flags; - struct Signature_ *s; + const struct Signature_ *s; uint64_t tx_id; } PacketAlert; diff --git a/src/detect-ack.c b/src/detect-ack.c index aaef98a96428..79c33390dbba 100644 --- a/src/detect-ack.c +++ b/src/detect-ack.c @@ -45,7 +45,7 @@ /* prototypes */ static int DetectAckSetup(DetectEngineCtx *, Signature *, char *); static int DetectAckMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, const SigMatchCtx *); + Packet *, const Signature *, const SigMatchCtx *); static void DetectAckRegisterTests(void); static void DetectAckFree(void *); static int PrefilterSetupTcpAck(SigGroupHead *sgh); @@ -79,7 +79,7 @@ void DetectAckRegister(void) * \retval 1 match */ static int DetectAckMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectAckData *data = (const DetectAckData *)ctx; diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index c237ecf4b282..a7930dee85df 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -49,16 +49,16 @@ #define MAX_ALPROTO_NAME 50 static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx); + Packet *p, const Signature *s, const SigMatchCtx *ctx); static int DetectAppLayerEventAppMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, Signature *, SigMatch *); + uint8_t, void *, const Signature *, const SigMatch *); static int DetectAppLayerEventSetupP1(DetectEngineCtx *, Signature *, char *); static void DetectAppLayerEventRegisterTests(void); static void DetectAppLayerEventFree(void *); static int DetectEngineAptEventInspect(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); /** @@ -89,7 +89,7 @@ void DetectAppLayerEventRegister(void) static int DetectEngineAptEventInspect(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { @@ -134,7 +134,7 @@ static int DetectEngineAptEventInspect(ThreadVars *tv, static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectAppLayerEventData *aled = (const DetectAppLayerEventData *)ctx; @@ -143,8 +143,8 @@ static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det } static int DetectAppLayerEventAppMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, - SigMatch *m) + Flow *f, uint8_t flags, void *state, const Signature *s, + const SigMatch *m) { SCEnter(); AppLayerDecoderEvents *decoder_events = NULL; diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 34c3be96026b..c28f5867b6e0 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -37,7 +37,7 @@ static void DetectAppLayerProtocolRegisterTests(void); static int DetectAppLayerProtocolPacketMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); diff --git a/src/detect-asn1.c b/src/detect-asn1.c index c9602bdb767e..5cb6e3bb9ee6 100644 --- a/src/detect-asn1.c +++ b/src/detect-asn1.c @@ -43,7 +43,7 @@ const char *ASN_DELIM = " \t,\n"; int DetectAsn1Match(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); + const Signature *, const SigMatchCtx *); static int DetectAsn1Setup (DetectEngineCtx *, Signature *, char *); void DetectAsn1RegisterTests(void); void DetectAsn1Free(void *); @@ -138,7 +138,7 @@ static uint8_t DetectAsn1Checks(Asn1Node *node, const DetectAsn1Data *ad) * \retval 1 match */ int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s, const SigMatchCtx *ctx) + const Signature *s, const SigMatchCtx *ctx) { uint8_t ret = 0; diff --git a/src/detect-base64-data.h b/src/detect-base64-data.h index 12fa60de56e0..38bb93fc0691 100644 --- a/src/detect-base64-data.h +++ b/src/detect-base64-data.h @@ -20,6 +20,6 @@ void DetectBase64DataRegister(void); int DetectBase64DataDoMatch(DetectEngineCtx *, DetectEngineThreadCtx *, - Signature *, Flow *); + const Signature *, Flow *); #endif /* __DETECT_BASE64_DATA_H__ */ diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index d0687780d434..251a89f9cdfd 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -54,7 +54,7 @@ void DetectBase64DecodeRegister(void) DetectSetupParseRegexes(decode_pattern, &decode_pcre, &decode_pcre_study); } -int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, +int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatch *sm, uint8_t *payload, uint32_t payload_len) { DetectBase64Decode *data = (DetectBase64Decode *)sm->ctx; diff --git a/src/detect-base64-decode.h b/src/detect-base64-decode.h index a1ce388f188f..e2f602313dad 100644 --- a/src/detect-base64-decode.h +++ b/src/detect-base64-decode.h @@ -27,7 +27,7 @@ typedef struct DetectBase64Decode_ { } DetectBase64Decode; void DetectBase64DecodeRegister(void); -int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *, Signature *, - const SigMatch *, uint8_t *, uint32_t); +int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *, + const Signature *, const SigMatch *, uint8_t *, uint32_t); #endif /* __DETECT_BASE64_DECODE_H__ */ diff --git a/src/detect-bypass.c b/src/detect-bypass.c index 9faaad13702d..dce7abe44ae0 100644 --- a/src/detect-bypass.c +++ b/src/detect-bypass.c @@ -49,7 +49,8 @@ #include "util-unittest-helper.h" #include "util-device.h" -int DetectBypassMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +int DetectBypassMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectBypassSetup(DetectEngineCtx *, Signature *, char *); static void DetectBypassRegisterTests(void); @@ -91,7 +92,8 @@ static int DetectBypassSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) return 0; } -int DetectBypassMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +int DetectBypassMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { PacketBypassCallback(p); diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index a4549a1d6d08..7c1a50dd3788 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -90,7 +90,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectByteExtractMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, SigMatch *); + Packet *, const Signature *, const SigMatch *); int DetectByteExtractSetup(DetectEngineCtx *, Signature *, char *); void DetectByteExtractRegisterTests(void); void DetectByteExtractFree(void *); @@ -112,8 +112,8 @@ void DetectByteExtractRegister(void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, SigMatch *sm, - Signature *s, uint8_t *payload, +int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatch *sm, + const Signature *s, uint8_t *payload, uint16_t payload_len, uint64_t *value, uint8_t endian) { @@ -204,10 +204,8 @@ int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, SigMatch *sm, int DetectByteExtractMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, const Signature *s, const SigMatch *m) { - goto end; - end: return 1; } @@ -756,7 +754,7 @@ void DetectByteExtractFree(void *ptr) * * \retval A pointer to the SigMatch if found, otherwise NULL. */ -SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, Signature *s) +SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, const Signature *s) { DetectByteExtractData *bed = NULL; int list; diff --git a/src/detect-byte-extract.h b/src/detect-byte-extract.h index 020494da0e5e..506b1eb773ce 100644 --- a/src/detect-byte-extract.h +++ b/src/detect-byte-extract.h @@ -63,9 +63,9 @@ void DetectByteExtractRegister(void); int DetectByteExtractSetup(DetectEngineCtx *, Signature *, char *); void DetectByteExtractFree(void *); int DetectByteExtractMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, SigMatch *); -SigMatch *DetectByteExtractRetrieveSMVar(const char *, Signature *); -int DetectByteExtractDoMatch(DetectEngineThreadCtx *, SigMatch *, Signature *, + Packet *, const Signature *, const SigMatch *); +SigMatch *DetectByteExtractRetrieveSMVar(const char *, const Signature *); +int DetectByteExtractDoMatch(DetectEngineThreadCtx *, const SigMatch *, const Signature *, uint8_t *, uint16_t, uint64_t *, uint8_t); #endif /* __DETECT_BYTEEXTRACT_H__ */ diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index cf89e9fca950..ebdd3c35f060 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -84,7 +84,7 @@ void DetectBytejumpRegister (void) * \retval 1 match * \retval 0 no match */ -int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, +int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchCtx *ctx, uint8_t *payload, uint32_t payload_len, uint8_t flags, int32_t offset) { @@ -197,7 +197,7 @@ int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, } int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectBytejumpData *data = (const DetectBytejumpData *)ctx; uint8_t *ptr = NULL; diff --git a/src/detect-bytejump.h b/src/detect-bytejump.h index 350514867c1d..d88d8c82da14 100644 --- a/src/detect-bytejump.h +++ b/src/detect-bytejump.h @@ -113,8 +113,8 @@ DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset); * error as a match. */ int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx); -int DetectBytejumpDoMatch(DetectEngineThreadCtx *, Signature *, const SigMatchCtx *, + Packet *p, const Signature *s, const SigMatchCtx *ctx); +int DetectBytejumpDoMatch(DetectEngineThreadCtx *, const Signature *, const SigMatchCtx *, uint8_t *, uint32_t, uint8_t, int32_t); #endif /* __DETECT_BYTEJUMP_H__ */ diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 2eaddadb0fa7..a6f08b642da6 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -89,7 +89,9 @@ void DetectBytetestRegister (void) * \retval 1 match * \retval 0 no match */ -int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, const SigMatchCtx *ctx, uint8_t *payload, uint32_t payload_len, +int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchCtx *ctx, + uint8_t *payload, uint32_t payload_len, uint8_t flags, int32_t offset, uint64_t value) { SCEnter(); @@ -231,7 +233,7 @@ int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, const Si } int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { return DetectBytetestDoMatch(det_ctx, s, ctx, p->payload, p->payload_len, ((DetectBytetestData *)ctx)->flags, 0, 0); diff --git a/src/detect-bytetest.h b/src/detect-bytetest.h index 09d453fab698..261c30be7070 100644 --- a/src/detect-bytetest.h +++ b/src/detect-bytetest.h @@ -121,8 +121,8 @@ DetectBytetestData *DetectBytetestParse(char *optstr, char **value, * \todo The return seems backwards. We should return a non-zero error code. One of the error codes is "no match". As-is if someone accidentally does: if (DetectBytetestMatch(...)) { match }, then they catch an error as a match. */ int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx); -int DetectBytetestDoMatch(DetectEngineThreadCtx *, Signature *, + Packet *p, const Signature *s, const SigMatchCtx *ctx); +int DetectBytetestDoMatch(DetectEngineThreadCtx *, const Signature *, const SigMatchCtx *ctx, uint8_t *, uint32_t, uint8_t, int32_t, uint64_t); diff --git a/src/detect-csum.c b/src/detect-csum.c index badeebb51206..ab5ed748e84c 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -40,44 +40,44 @@ #include "util-profiling.h" /* prototypes for the "ipv4-csum" rule keyword */ -int DetectIPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); +static int DetectIPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectIPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectIPV4CsumFree(void *); /* prototypes for the "tcpv4-csum" rule keyword */ -int DetectTCPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); +static int DetectTCPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectTCPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectTCPV4CsumFree(void *); /* prototypes for the "tcpv6-csum" rule keyword */ -int DetectTCPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); +static int DetectTCPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectTCPV6CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectTCPV6CsumFree(void *); /* prototypes for the "udpv4-csum" rule keyword */ -int DetectUDPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); +static int DetectUDPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectUDPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectUDPV4CsumFree(void *); /* prototypes for the "udpv6-csum" rule keyword */ -int DetectUDPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); +static int DetectUDPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectUDPV6CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectUDPV6CsumFree(void *); /* prototypes for the "icmpv4-csum" rule keyword */ -int DetectICMPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); +static int DetectICMPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectICMPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectICMPV4CsumFree(void *); /* prototypes for the "icmpv6-csum" rule keyword */ -int DetectICMPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); +static int DetectICMPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectICMPV6CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectICMPV6CsumFree(void *); @@ -229,8 +229,8 @@ static int DetectCsumParseArg(const char *key, DetectCsumData *cd) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectIPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectIPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -323,8 +323,8 @@ void DetectIPV4CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectTCPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectTCPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -418,8 +418,8 @@ void DetectTCPV4CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectTCPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectTCPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -513,8 +513,8 @@ void DetectTCPV6CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectUDPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectUDPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -609,8 +609,8 @@ void DetectUDPV4CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectUDPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectUDPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -705,8 +705,8 @@ void DetectUDPV6CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectICMPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectICMPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -800,8 +800,8 @@ void DetectICMPV4CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectICMPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectICMPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 10e79d399f64..78c705ce35e9 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -52,8 +52,8 @@ static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; -int DetectDceIfaceMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - void *, Signature *, SigMatch *); +static int DetectDceIfaceMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t, void *, const Signature *, const SigMatch *); static int DetectDceIfaceSetup(DetectEngineCtx *, Signature *, char *); void DetectDceIfaceFree(void *); @@ -242,8 +242,9 @@ static inline int DetectDceIfaceMatchIfaceVersion(uint16_t version, * \retval 1 On Match. * \retval 0 On no match. */ -int DetectDceIfaceMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectDceIfaceMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatch *m) { SCEnter(); diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 023e643b9f0b..e1435fba1eaa 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -52,8 +52,8 @@ static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; -int DetectDceOpnumMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - void *, Signature *, SigMatch *); +static int DetectDceOpnumMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, + void *, const Signature *, const SigMatch *); static int DetectDceOpnumSetup(DetectEngineCtx *, Signature *, char *); void DetectDceOpnumFree(void *); @@ -237,8 +237,9 @@ static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) * \retval 1 On Match. * \retval 0 On no match. */ -int DetectDceOpnumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectDceOpnumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatch *m) { SCEnter(); diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index e69d66fada3d..56a5fad783c9 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -51,7 +51,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectDetectionFilterMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectDetectionFilterMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectDetectionFilterSetup(DetectEngineCtx *, Signature *, char *); void DetectDetectionFilterRegisterTests(void); void DetectDetectionFilterFree(void *); @@ -74,7 +75,8 @@ void DetectDetectionFilterRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -int DetectDetectionFilterMatch (ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectDetectionFilterMatch (ThreadVars *thv, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { return 1; } diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 3baf124f58b8..1a515905bb80 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -139,7 +139,7 @@ static char *TrimString(char *str) } static int DetectEngineInspectDNP3Data(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); @@ -163,7 +163,7 @@ static int DetectEngineInspectDNP3Data(ThreadVars *tv, DetectEngineCtx *de_ctx, } static int DetectEngineInspectDNP3(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 548ac3ced34f..f07d812204ec 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -49,7 +49,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectDsizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectDsizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectDsizeSetup (DetectEngineCtx *, Signature *s, char *str); void DsizeRegisterTests(void); static void DetectDsizeFree(void *); @@ -105,7 +106,8 @@ DsizeMatch(const uint16_t psize, const uint8_t mode, * \retval 0 no match * \retval 1 match */ -int DetectDsizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectDsizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index 21047a0df5cb..8bfd719f75ad 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -186,7 +186,8 @@ int PacketAlertRemove(Packet *p, uint16_t pos) * \param flags alert flags * \param alert_msg ptr to StreamMsg object that the signature matched on */ -int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, uint64_t tx_id, uint8_t flags) +int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, const Signature *s, + Packet *p, uint64_t tx_id, uint8_t flags) { int i = 0; diff --git a/src/detect-engine-alert.h b/src/detect-engine-alert.h index 6f200b268d4e..dc6687885cc0 100644 --- a/src/detect-engine-alert.h +++ b/src/detect-engine-alert.h @@ -29,7 +29,8 @@ #include "detect.h" void PacketAlertFinalize(DetectEngineCtx *, DetectEngineThreadCtx *, Packet *); -int PacketAlertAppend(DetectEngineThreadCtx *, Signature *, Packet *, uint64_t tx_id, uint8_t); +int PacketAlertAppend(DetectEngineThreadCtx *, const Signature *, + Packet *, uint64_t tx_id, uint8_t); int PacketAlertCheck(Packet *, uint32_t); int PacketAlertRemove(Packet *, uint16_t); void PacketAlertTagInit(void); diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index af1b10346220..95f4fc7fdb43 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -99,7 +99,7 @@ * \retval 1 match */ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, SigMatch *sm, + const Signature *s, const SigMatch *sm, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 91b62d6c6b89..8ae5d76a458c 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -34,7 +34,7 @@ enum { }; int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, SigMatch *sm, + const Signature *s, const SigMatch *sm, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index 5cdb10d35f2c..c856408135b0 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -62,7 +62,7 @@ * \retval 1 Match. */ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, + DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, void *alstate) { SCEnter(); diff --git a/src/detect-engine-dcepayload.h b/src/detect-engine-dcepayload.h index ccc4794ba303..da7dfb92996e 100644 --- a/src/detect-engine-dcepayload.h +++ b/src/detect-engine-dcepayload.h @@ -25,7 +25,7 @@ #define __DETECT_ENGINE_DCEPAYLOAD_H__ int DetectEngineInspectDcePayload(DetectEngineCtx *, DetectEngineThreadCtx *, - Signature *, Flow *, uint8_t, void *); + const Signature *, Flow *, uint8_t, void *); void DcePayloadRegisterTests(void); diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index 0dac77734fbd..b9a4ce39fa50 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -63,7 +63,7 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { DNSTransaction *tx = (DNSTransaction *)txv; @@ -141,7 +141,7 @@ int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectDnsRequest(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, @@ -152,7 +152,7 @@ int DetectEngineInspectDnsRequest(ThreadVars *tv, int DetectEngineInspectDnsResponse(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, diff --git a/src/detect-engine-dns.h b/src/detect-engine-dns.h index 5b2367a66010..56ebea25899c 100644 --- a/src/detect-engine-dns.h +++ b/src/detect-engine-dns.h @@ -26,17 +26,17 @@ int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectDnsQueryName(ThreadVars *, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *, Signature *, + DetectEngineThreadCtx *, const Signature *, Flow *, uint8_t, void *, void *, uint64_t); int DetectEngineInspectDnsRequest(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); int DetectEngineInspectDnsResponse(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); #endif /* __DETECT_ENGINE_DNS_H__ */ diff --git a/src/detect-engine-enip.c b/src/detect-engine-enip.c index 2facecc08410..8160d0bae5d8 100644 --- a/src/detect-engine-enip.c +++ b/src/detect-engine-enip.c @@ -218,7 +218,7 @@ int CIPServiceMatch(ENIPTransaction *enip_data, * \retval 0 no match or 1 match */ int DetectEngineInspectCIP(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); @@ -258,7 +258,7 @@ int DetectEngineInspectCIP(ThreadVars *tv, DetectEngineCtx *de_ctx, */ int DetectEngineInspectENIP(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); diff --git a/src/detect-engine-enip.h b/src/detect-engine-enip.h index 1d701d414d5a..9e0e719d850b 100644 --- a/src/detect-engine-enip.h +++ b/src/detect-engine-enip.h @@ -24,11 +24,11 @@ #define __DETECT_ENGINE_ENIP_H__ int DetectEngineInspectCIP(ThreadVars *, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *, Signature *, + DetectEngineThreadCtx *, const Signature *, Flow *, uint8_t, void *, void *, uint64_t); int DetectEngineInspectENIP(ThreadVars *, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *, Signature *, + DetectEngineThreadCtx *, const Signature *, Flow *, uint8_t, void *, void *, uint64_t); void DetectEngineInspectENIPRegisterTests(void); diff --git a/src/detect-engine-event.c b/src/detect-engine-event.c index ebfe865acc1a..06fcfe1086d9 100644 --- a/src/detect-engine-event.c +++ b/src/detect-engine-event.c @@ -47,7 +47,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectEngineEventMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectEngineEventMatch (ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectEngineEventSetup (DetectEngineCtx *, Signature *, char *); static int DetectDecodeEventSetup (DetectEngineCtx *, Signature *, char *); static int DetectStreamEventSetup (DetectEngineCtx *, Signature *, char *); @@ -92,7 +93,8 @@ void DetectEngineEventRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectEngineEventMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectEngineEventMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); diff --git a/src/detect-engine-file.h b/src/detect-engine-file.h index 365ed8a99fb7..4934ed0a2cbf 100644 --- a/src/detect-engine-file.h +++ b/src/detect-engine-file.h @@ -26,11 +26,11 @@ int DetectFileInspectHttp(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, void *alstate, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); int DetectFileInspectSmtp(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, + DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); diff --git a/src/detect-engine-filedata-smtp.h b/src/detect-engine-filedata-smtp.h index f4f45af0df7a..d659e2224162 100644 --- a/src/detect-engine-filedata-smtp.h +++ b/src/detect-engine-filedata-smtp.h @@ -30,7 +30,7 @@ int PrefilterTxSmtpFiledataRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectSMTPFiledata(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx); diff --git a/src/detect-engine-hcbd.h b/src/detect-engine-hcbd.h index 4ed0b5088590..c990bb083dc9 100644 --- a/src/detect-engine-hcbd.h +++ b/src/detect-engine-hcbd.h @@ -32,7 +32,7 @@ int PrefilterTxHttpRequestBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpClientBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineCleanHCBDBuffers(DetectEngineThreadCtx *); diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index 63ed33fe9391..4be2ba6903f7 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -168,7 +168,7 @@ int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpCookie(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-hcd.h b/src/detect-engine-hcd.h index f5c23514d867..9ed0e6c1d758 100644 --- a/src/detect-engine-hcd.h +++ b/src/detect-engine-hcd.h @@ -31,7 +31,7 @@ int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpCookie(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index c4146169cc5b..41cb22d1ffb9 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -384,7 +384,7 @@ int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { diff --git a/src/detect-engine-hhd.h b/src/detect-engine-hhd.h index 9826dcda5ab2..e0da35b186cd 100644 --- a/src/detect-engine-hhd.h +++ b/src/detect-engine-hhd.h @@ -31,7 +31,7 @@ int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx); diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index b761a1fe6c43..5c53ef7097da 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -117,7 +117,7 @@ int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpHH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-hhhd.h b/src/detect-engine-hhhd.h index dab5080d42f4..932a38f6d4f6 100644 --- a/src/detect-engine-hhhd.h +++ b/src/detect-engine-hhhd.h @@ -30,7 +30,7 @@ int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpHH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 23b964cf984e..31df7e24ae98 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -114,7 +114,7 @@ int PrefilterTxMethodRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpMethod(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-hmd.h b/src/detect-engine-hmd.h index e2be754be4bc..cf40eeba617c 100644 --- a/src/detect-engine-hmd.h +++ b/src/detect-engine-hmd.h @@ -28,7 +28,7 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 3181d45bf313..526c6b1424ce 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -165,7 +165,7 @@ int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpRawHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-hrhd.h b/src/detect-engine-hrhd.h index 6d043f3cf040..99c379b225bd 100644 --- a/src/detect-engine-hrhd.h +++ b/src/detect-engine-hrhd.h @@ -31,7 +31,7 @@ int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpRawHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpRawHeaderRegisterTests(void); diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index 02db16fe1a6f..d6b265235de4 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -129,7 +129,7 @@ int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpHRH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-hrhhd.h b/src/detect-engine-hrhhd.h index 9fd427247d26..30aec3b8c702 100644 --- a/src/detect-engine-hrhhd.h +++ b/src/detect-engine-hrhhd.h @@ -30,7 +30,7 @@ int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpHRH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 4957f3292fee..876dcc5e806e 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -114,7 +114,7 @@ int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpRawUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-hrud.h b/src/detect-engine-hrud.h index 9418b077ca2f..4b7933badcf5 100644 --- a/src/detect-engine-hrud.h +++ b/src/detect-engine-hrud.h @@ -31,7 +31,7 @@ int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpRawUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpRawUriRegisterTests(void); diff --git a/src/detect-engine-hsbd.h b/src/detect-engine-hsbd.h index edb8d17d91cc..0512ba46615e 100644 --- a/src/detect-engine-hsbd.h +++ b/src/detect-engine-hsbd.h @@ -32,7 +32,7 @@ int PrefilterTxHttpResponseBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpServerBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineCleanHSBDBuffers(DetectEngineThreadCtx *det_ctx); diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index e8e94822d02f..e9354a91b882 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -113,7 +113,7 @@ int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpStatCode(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-hscd.h b/src/detect-engine-hscd.h index 73977eccec37..390abf5b9b04 100644 --- a/src/detect-engine-hscd.h +++ b/src/detect-engine-hscd.h @@ -30,7 +30,7 @@ int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpStatCode(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpStatCodeRegisterTests(void); diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 68811eea7ba9..4bee372dbc0e 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -113,7 +113,7 @@ int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpStatMsg(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-hsmd.h b/src/detect-engine-hsmd.h index 2feddd3bdcd3..075d34d7132e 100644 --- a/src/detect-engine-hsmd.h +++ b/src/detect-engine-hsmd.h @@ -30,7 +30,7 @@ int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpStatMsg(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpStatMsgRegisterTests(void); diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index 66c8859cb2e9..1cc2a394189e 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -122,7 +122,7 @@ int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpUA(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-hua.h b/src/detect-engine-hua.h index eceddf97b137..499539ee92b4 100644 --- a/src/detect-engine-hua.h +++ b/src/detect-engine-hua.h @@ -30,7 +30,7 @@ int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpUA(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); diff --git a/src/detect-engine-modbus.c b/src/detect-engine-modbus.c index 976e7d901f27..e08cde10d7ce 100644 --- a/src/detect-engine-modbus.c +++ b/src/detect-engine-modbus.c @@ -199,7 +199,7 @@ static int DetectEngineInspectModbusAddress(ModbusTransaction *tx, int DetectEngineInspectModbus(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, + const Signature *s, Flow *f, uint8_t flags, void *alstate, diff --git a/src/detect-engine-modbus.h b/src/detect-engine-modbus.h index e140f975a5ec..ae0935c977a8 100644 --- a/src/detect-engine-modbus.h +++ b/src/detect-engine-modbus.h @@ -34,7 +34,7 @@ #define __DETECT_ENGINE_MODBUS_H__ int DetectEngineInspectModbus(ThreadVars *, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *, Signature *, + DetectEngineThreadCtx *, const Signature *, Flow *, uint8_t, void *, void *, uint64_t); void DetectEngineInspectModbusRegisterTests(void); diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index 70351e9aa4dc..6cdb775adb2e 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -173,7 +173,7 @@ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, * from the current packet here. */ int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, + DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t *payload, uint32_t payload_len) { SCEnter(); diff --git a/src/detect-engine-payload.h b/src/detect-engine-payload.h index 67d0be24656a..205f8523f494 100644 --- a/src/detect-engine-payload.h +++ b/src/detect-engine-payload.h @@ -28,9 +28,9 @@ int PrefilterPktPayloadRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int PrefilterPktStreamRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectPacketPayload(DetectEngineCtx *, - DetectEngineThreadCtx *, Signature *, Flow *, Packet *); + DetectEngineThreadCtx *, const Signature *, Flow *, Packet *); int DetectEngineInspectStreamPayload(DetectEngineCtx *, - DetectEngineThreadCtx *, Signature *, Flow *, + DetectEngineThreadCtx *, const Signature *, Flow *, uint8_t *, uint32_t); void PayloadRegisterTests(void); diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 46ff40c825f9..fe7335a35e97 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -161,7 +161,8 @@ static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIn return 0; } -static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, uint32_t inspect_flags, uint8_t direction) +static void DeStateSignatureAppend(DetectEngineState *state, + const Signature *s, uint32_t inspect_flags, uint8_t direction) { int jump = 0; int i = 0; @@ -202,9 +203,9 @@ static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, uint3 return; } -static void DeStateFlowRuleAppend(DetectEngineStateFlow *state, Signature *s, - SigMatch *sm, uint32_t inspect_flags, - uint8_t direction) +static void DeStateFlowRuleAppend(DetectEngineStateFlow *state, const Signature *s, + const SigMatch *sm, uint32_t inspect_flags, + uint8_t direction) { int jump = 0; int i = 0; @@ -392,7 +393,8 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, static int StoreState(DetectEngineThreadCtx *det_ctx, Flow *f, const uint8_t flags, const uint8_t alversion, - Signature *s, SigMatch *sm, const uint32_t inspect_flags, + const Signature *s, const SigMatch *sm, + const uint32_t inspect_flags, const uint16_t file_no_match) { if (f->de_state == NULL) { @@ -445,7 +447,7 @@ static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx, static void StoreStateTx(DetectEngineThreadCtx *det_ctx, Flow *f, const uint8_t flags, const uint8_t alversion, const uint64_t tx_id, void *tx, - Signature *s, SigMatch *sm, + const Signature *s, const SigMatch *sm, const uint32_t inspect_flags, const uint16_t file_no_match, int check_before_add) { if (AppLayerParserSupportsTxDetectState(f->proto, f->alproto)) { @@ -474,7 +476,7 @@ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Packet *p, Flow *f, uint8_t flags, + const Signature *s, Packet *p, Flow *f, uint8_t flags, AppProto alproto, const uint8_t alversion) { SigMatch *sm = NULL; @@ -946,8 +948,8 @@ static int DoInspectFlowRule(ThreadVars *tv, uint32_t inspect_flags = item->flags; int total_matches = 0; int full_match = 0; - SigMatch *sm = NULL; - Signature *s = de_ctx->sig_array[item->sid]; + const SigMatch *sm = NULL; + const Signature *s = de_ctx->sig_array[item->sid]; RULE_PROFILING_START(p); diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index af4f87247e9a..d61faa5b2c00 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -123,7 +123,7 @@ typedef struct DetectEngineState_ { /* FLOW BASED (AMATCH) */ typedef struct DeStateStoreFlowRule_ { - SigMatch *nm; + const SigMatch *nm; uint32_t flags; SigIntId sid; } DeStateStoreFlowRule; @@ -188,7 +188,8 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint8_t alversion, */ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Packet *p, Flow *f, uint8_t flags, + const Signature *s, Packet *p, Flow *f, + uint8_t flags, AppProto alproto, uint8_t alversion); /** diff --git a/src/detect-engine-template.h b/src/detect-engine-template.h index 98a17bf63d3f..e1f39065bdb2 100644 --- a/src/detect-engine-template.h +++ b/src/detect-engine-template.h @@ -25,7 +25,7 @@ #define __DETECT_TEMPLATE_ENGINE_H__ int DetectEngineInspectTemplateBuffer(ThreadVars *, DetectEngineCtx *, - DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, void *, + DetectEngineThreadCtx *, const Signature *, Flow *, uint8_t, void *, void *, uint64_t); #endif /* __DETECT_TEMPLATE_ENGINE_H__ */ diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 98eeab60e19b..e3e7881e0210 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -98,7 +98,7 @@ int PrefilterTxTlsSniRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 Match */ int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, + DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h index 56bb63172df2..e35281caf31e 100644 --- a/src/detect-engine-tls.h +++ b/src/detect-engine-tls.h @@ -29,22 +29,22 @@ int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); int DetectEngineInspectTlsValidity(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); #endif /* __DETECT_ENGINE_TLS_H__ */ diff --git a/src/detect-engine-uri.h b/src/detect-engine-uri.h index d5ba12298da5..bc5933aa0d54 100644 --- a/src/detect-engine-uri.h +++ b/src/detect-engine-uri.h @@ -29,7 +29,7 @@ int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void UriRegisterTests(void); diff --git a/src/detect-engine.c b/src/detect-engine.c index 05fe1a0f7648..06893021b854 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -106,7 +106,7 @@ void DetectAppLayerInspectEngineRegister(AppProto alproto, int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, + const Signature *sig, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id)) { diff --git a/src/detect-engine.h b/src/detect-engine.h index 608f0685d807..498dd22d8a41 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -89,7 +89,7 @@ void DetectAppLayerInspectEngineRegister(AppProto alproto, int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, + const Signature *sig, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id)); diff --git a/src/detect-fileext.c b/src/detect-fileext.c index 568c97802ab3..fc052e076918 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -52,7 +52,7 @@ #include "detect-fileext.h" static int DetectFileextMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, Signature *, SigMatch *); + uint8_t, File *, const Signature *, const SigMatch *); static int DetectFileextSetup (DetectEngineCtx *, Signature *, char *); static void DetectFileextRegisterTests(void); static void DetectFileextFree(void *); @@ -89,7 +89,7 @@ void DetectFileextRegister(void) * \retval 1 match */ static int DetectFileextMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatch *m) { SCEnter(); int ret = 0; diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 2c2c46f676f6..a64e1d180bb0 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -76,7 +76,7 @@ void DetectFilemagicRegister(void) #else /* HAVE_MAGIC */ static int DetectFilemagicMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, Signature *, SigMatch *); + uint8_t, File *, const Signature *, const SigMatch *); static int DetectFilemagicSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilemagicRegisterTests(void); static void DetectFilemagicFree(void *); @@ -176,7 +176,7 @@ int FilemagicThreadLookup(magic_t *ctx, File *file) * \retval 1 match */ static int DetectFilemagicMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatch *m) { SCEnter(); int ret = 0; diff --git a/src/detect-filename.c b/src/detect-filename.c index 35b27d17b45a..34722fb77f44 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -53,7 +53,7 @@ #include "app-layer-parser.h" static int DetectFilenameMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, Signature *, SigMatch *); + uint8_t, File *, const Signature *, const SigMatch *); static int DetectFilenameSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilenameRegisterTests(void); static void DetectFilenameFree(void *); @@ -101,7 +101,7 @@ void DetectFilenameRegister(void) * \retval 1 match */ static int DetectFilenameMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatch *m) { SCEnter(); int ret = 0; diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 12b4c18f25c5..b26c7a8fc66f 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -49,7 +49,7 @@ static pcre_extra *parse_regex_study; /*prototypes*/ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, Signature *s, SigMatch *m); + uint8_t flags, File *file, const Signature *s, const SigMatch *m); static int DetectFilesizeSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilesizeFree (void *); static void DetectFilesizeRegisterTests (void); @@ -87,7 +87,7 @@ void DetectFilesizeRegister(void) * \retval 1 match */ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, Signature *s, SigMatch *m) + uint8_t flags, File *file, const Signature *s, const SigMatch *m) { SCEnter(); diff --git a/src/detect-filestore.c b/src/detect-filestore.c index ab096573fd7d..4104fc694d47 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -60,7 +60,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectFilestoreMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, File *, Signature *, SigMatch *); + Flow *, uint8_t, File *, const Signature *, const SigMatch *); static int DetectFilestoreSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilestoreFree(void *); static void DetectFilestoreRegisterTests(void); @@ -180,7 +180,7 @@ static int FilestorePostMatchWithOptions(Packet *p, Flow *f, DetectFilestoreData * When we are sure all parts of the signature matched, we run this function * to finalize the filestore. */ -int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s) +int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s) { uint8_t flags = 0; @@ -247,7 +247,7 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack * needs to be put behind a api. */ static int DetectFilestoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, Signature *s, SigMatch *m) + uint8_t flags, File *file, const Signature *s, const SigMatch *m) { uint16_t file_id = 0; diff --git a/src/detect-filestore.h b/src/detect-filestore.h index 1879b87532e2..09d2e25f18da 100644 --- a/src/detect-filestore.h +++ b/src/detect-filestore.h @@ -41,5 +41,7 @@ typedef struct DetectFilestoreData_ { /* prototypes */ void DetectFilestoreRegister (void); -int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *); +int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *); + #endif /* __DETECT_FILESTORE_H__ */ diff --git a/src/detect-flags.c b/src/detect-flags.c index 28e01d1bfa22..be4232856b48 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -58,7 +58,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectFlagsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectFlagsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectFlagsSetup (DetectEngineCtx *, Signature *, char *); static void DetectFlagsFree(void *); @@ -138,7 +139,8 @@ static inline int FlagsMatch(const uint8_t pflags, const uint8_t modifier, * \retval 0 no match * \retval 1 match */ -static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { SCEnter(); diff --git a/src/detect-flow.c b/src/detect-flow.c index 376944f67886..a1d77ea17ffa 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -49,7 +49,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFlowMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +int DetectFlowMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectFlowSetup (DetectEngineCtx *, Signature *, char *); void DetectFlowRegisterTests(void); void DetectFlowFree(void *); @@ -132,7 +133,8 @@ static inline int FlowMatch(const uint32_t pflags, const uint8_t pflowflags, * \retval 0 no match * \retval 1 match */ -int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { SCEnter(); diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 9b1af1781124..41b249efebd5 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -49,7 +49,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFlowbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +int DetectFlowbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectFlowbitSetup (DetectEngineCtx *, Signature *, char *); void DetectFlowbitFree (void *); void FlowBitsRegisterTests(void); @@ -122,7 +123,8 @@ static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd) * -1: error */ -int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx; if (fd == NULL) diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 8b0389ef9617..6ceb7ca39e7f 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -54,7 +54,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectFlowintMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); + const Signature *, const SigMatchCtx *); static int DetectFlowintSetup(DetectEngineCtx *, Signature *, char *); void DetectFlowintFree(void *); void DetectFlowintRegisterTests(void); @@ -87,7 +87,7 @@ void DetectFlowintRegister(void) * condition */ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectFlowintData *sfd = (const DetectFlowintData *)ctx; FlowVar *fv; diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index e662ad17abc5..46741016b696 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -44,9 +44,11 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFlowvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +int DetectFlowvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectFlowvarSetup (DetectEngineCtx *, Signature *, char *); -static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx); +static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx); static void DetectFlowvarDataFree(void *ptr); void DetectFlowvarRegister (void) @@ -93,7 +95,8 @@ static void DetectFlowvarDataFree(void *ptr) * -1: error */ -int DetectFlowvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +int DetectFlowvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { int ret = 0; DetectFlowvarData *fd = (DetectFlowvarData *)ctx; @@ -261,7 +264,7 @@ int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx) */ static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { DetectFlowvarList *fs, *prev; const DetectFlowvarData *fd; diff --git a/src/detect-fragbits.c b/src/detect-fragbits.c index 5c0e014ab76c..0677b5b7b402 100644 --- a/src/detect-fragbits.c +++ b/src/detect-fragbits.c @@ -68,7 +68,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectFragBitsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectFragBitsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectFragBitsSetup (DetectEngineCtx *, Signature *, char *); static void DetectFragBitsFree(void *); @@ -136,7 +137,7 @@ FragBitsMatch(const uint8_t pbits, const uint8_t modifier, * \retval 1 match */ static int DetectFragBitsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { if (!ctx || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) return 0; diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index aa43ced0a57b..ea65f860c640 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -44,7 +44,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFragOffsetMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectFragOffsetMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectFragOffsetSetup(DetectEngineCtx *, Signature *, char *); void DetectFragOffsetRegisterTests(void); void DetectFragOffsetFree(void *); @@ -102,7 +103,8 @@ static inline int FragOffsetMatch(const uint16_t poffset, const uint8_t mode, * \retval 1 match * */ -int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { uint16_t frag = 0; const DetectFragOffsetData *fragoff = (const DetectFragOffsetData *)ctx; diff --git a/src/detect-ftpbounce.c b/src/detect-ftpbounce.c index e6015a16c012..4c067d7d63d7 100644 --- a/src/detect-ftpbounce.c +++ b/src/detect-ftpbounce.c @@ -47,13 +47,11 @@ #include "stream-tcp.h" #include "util-byte.h" -int DetectFtpbounceMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); -int DetectFtpbounceALMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, Signature *, SigMatch *); +static int DetectFtpbounceALMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t, void *, const Signature *, const SigMatch *); static int DetectFtpbounceSetup(DetectEngineCtx *, Signature *, char *); -int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, - uint32_t ip_orig, uint16_t offset); +static int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, + uint32_t ip_orig, uint16_t offset); void DetectFtpbounceRegisterTests(void); void DetectFtpbounceFree(void *); @@ -83,7 +81,7 @@ void DetectFtpbounceRegister(void) * * \retval 1 if ftpbounce detected, 0 if not */ -int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, +static int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, uint32_t ip_orig, uint16_t offset) { SCEnter(); @@ -168,9 +166,9 @@ int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, * \retval 0 no match * \retval 1 match */ -int DetectFtpbounceALMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, - SigMatch *m) +static int DetectFtpbounceALMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, const Signature *s, + const SigMatch *m) { SCEnter(); FtpState *ftp_state =(FtpState *)state; diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 229d7ada1ab8..e2fa800c6f68 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -68,7 +68,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectHostbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectHostbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectHostbitSetup (DetectEngineCtx *, Signature *, char *); void DetectHostbitFree (void *); void HostBitsRegisterTests(void); @@ -265,7 +266,8 @@ int DetectXbitMatchHost(Packet *p, const DetectXbitsData *xd) * -1: error */ -int DetectHostbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectHostbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { const DetectXbitsData *xd = (const DetectXbitsData *)ctx; if (xd == NULL) diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 4d9cf2795dba..6e316f568f84 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -67,7 +67,7 @@ static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); /** @@ -174,7 +174,7 @@ static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index 8887ce979ae7..606c74074688 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -67,7 +67,7 @@ static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ct static int DetectEngineInspectHttpResponseLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); @@ -175,7 +175,7 @@ static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ct int DetectEngineInspectHttpResponseLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index 22acfb3356b3..147a86695e01 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -43,7 +43,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIcmpIdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectIcmpIdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectIcmpIdSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpIdRegisterTests(void); void DetectIcmpIdFree(void *); @@ -129,7 +130,8 @@ static inline _Bool GetIcmpId(Packet *p, uint16_t *id) * \retval 0 no match * \retval 1 match */ -int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { uint16_t pid; diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index 9ddd4e6b36cd..1cd6971dee5a 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -43,7 +43,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIcmpSeqMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectIcmpSeqMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectIcmpSeqSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpSeqRegisterTests(void); void DetectIcmpSeqFree(void *); @@ -131,7 +132,8 @@ static inline _Bool GetIcmpSeq(Packet *p, uint16_t *seq) * \retval 0 no match * \retval 1 match */ -int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { uint16_t seqn; diff --git a/src/detect-icode.c b/src/detect-icode.c index 8468c3aff67e..f6a01ad9aa7a 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -46,7 +46,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectICodeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectICodeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectICodeSetup(DetectEngineCtx *, Signature *, char *); void DetectICodeRegisterTests(void); void DetectICodeFree(void *); @@ -115,7 +116,8 @@ static inline int ICodeMatch(const uint8_t pcode, const uint8_t mode, * \retval 0 no match * \retval 1 match */ -int DetectICodeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectICodeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { if (PKT_IS_PSEUDOPKT(p)) return 0; diff --git a/src/detect-id.c b/src/detect-id.c index de2e21dd6194..8b6d4df75fdc 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -49,8 +49,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIdMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); +static int DetectIdMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectIdSetup (DetectEngineCtx *, Signature *, char *); void DetectIdRegisterTests(void); void DetectIdFree(void *); @@ -88,8 +88,8 @@ void DetectIdRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s, const SigMatchCtx *ctx) +static int DetectIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { const DetectIdData *id_d = (const DetectIdData *)ctx; diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index 21e8a4aa52de..33addb855b3b 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -43,7 +43,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIpOptsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectIpOptsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectIpOptsSetup (DetectEngineCtx *, Signature *, char *); void IpOptsRegisterTests(void); void DetectIpOptsFree(void *); @@ -98,7 +99,8 @@ struct DetectIpOpts_ { * \retval 0 no match * \retval 1 match */ -int DetectIpOptsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectIpOptsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { const DetectIpOptsData *de = (const DetectIpOptsData *)ctx; diff --git a/src/detect-iprep.c b/src/detect-iprep.c index 10da976a86a8..7b0dfb78b6a7 100644 --- a/src/detect-iprep.c +++ b/src/detect-iprep.c @@ -52,7 +52,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIPRepMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectIPRepMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectIPRepSetup (DetectEngineCtx *, Signature *, char *); void DetectIPRepFree (void *); void IPRepRegisterTests(void); @@ -166,7 +167,8 @@ static inline int RepMatch(uint8_t op, uint8_t val1, uint8_t val2) * 1: match * -1: error */ -int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { const DetectIPRepData *rd = (const DetectIPRepData *)ctx; if (rd == NULL) diff --git a/src/detect-itype.c b/src/detect-itype.c index 35b962d53fa1..3d3a0e389606 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -46,7 +46,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectITypeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectITypeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectITypeSetup(DetectEngineCtx *, Signature *, char *); void DetectITypeRegisterTests(void); void DetectITypeFree(void *); @@ -115,7 +116,8 @@ static inline int ITypeMatch(const uint8_t ptype, const uint8_t mode, * \retval 0 no match * \retval 1 match */ -int DetectITypeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectITypeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { if (PKT_IS_PSEUDOPKT(p)) return 0; diff --git a/src/detect-lua.c b/src/detect-lua.c index b3a8222b1e59..27351bfe4a30 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -88,9 +88,9 @@ void DetectLuaRegister(void) #include "util-lua.h" static int DetectLuaMatch (ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, const SigMatchCtx *); + Packet *, const Signature *, const SigMatchCtx *); static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m); + Flow *f, uint8_t flags, void *state, const Signature *s, const SigMatch *m); static int DetectLuaAppTxMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, @@ -186,7 +186,7 @@ void LuaDumpStack(lua_State *state) } int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, - Signature *s, SigMatch *sm, + const Signature *s, const SigMatch *sm, uint8_t *buffer, uint32_t buffer_len, uint32_t offset, Flow *f) { @@ -292,7 +292,7 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, * \retval 1 match */ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; @@ -537,7 +537,8 @@ static int DetectLuaAppMatchCommon (ThreadVars *t, DetectEngineThreadCtx *det_ct * \retval 1 match */ static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatch *m) { return DetectLuaAppMatchCommon(t, det_ctx, f, flags, state, s, m->ctx); } diff --git a/src/detect-lua.h b/src/detect-lua.h index d1259b3e66a4..18298aa20359 100644 --- a/src/detect-lua.h +++ b/src/detect-lua.h @@ -55,7 +55,8 @@ typedef struct DetectLuaData { /* prototypes */ void DetectLuaRegister (void); -int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, +int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, uint8_t *buffer, uint32_t buffer_len, uint32_t offset, Flow *f); diff --git a/src/detect-mark.c b/src/detect-mark.c index 83fa09690ab4..de04203ce881 100644 --- a/src/detect-mark.c +++ b/src/detect-mark.c @@ -43,7 +43,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectMarkSetup (DetectEngineCtx *, Signature *, char *); -int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx); +static int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx); void DetectMarkDataFree(void *ptr); /** @@ -217,7 +218,8 @@ void DetectMarkDataFree(void *ptr) } -int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { #ifdef NFQ const DetectMarkData *nf_data = (const DetectMarkData *)ctx; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index c43981ff6ab8..b8430149158f 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -171,8 +171,8 @@ void DetectPcreRegister (void) * \retval 1 Match. * \retval 0 No match. */ -int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, Signature *s, - SigMatch *sm, Packet *p, Flow *f, uint8_t *payload, +int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, + const SigMatch *sm, Packet *p, Flow *f, uint8_t *payload, uint32_t payload_len) { SCEnter(); diff --git a/src/detect-pcre.h b/src/detect-pcre.h index e0098cb1c024..52e6394b595e 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -44,7 +44,8 @@ typedef struct DetectPcreData_ { } DetectPcreData; /* prototypes */ -int DetectPcrePayloadMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Packet *, Flow *, uint8_t *, uint32_t); +int DetectPcrePayloadMatch(DetectEngineThreadCtx *, const Signature *, + const SigMatch *, Packet *, Flow *, uint8_t *, uint32_t); int DetectPcrePacketPayloadMatch(DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectPcrePayloadDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Packet *, uint8_t *, uint16_t); diff --git a/src/detect-pktvar.c b/src/detect-pktvar.c index d319bd8882cf..930ceeeeaf74 100644 --- a/src/detect-pktvar.c +++ b/src/detect-pktvar.c @@ -39,7 +39,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectPktvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectPktvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectPktvarSetup (DetectEngineCtx *, Signature *, char *); void DetectPktvarRegister (void) @@ -61,7 +62,8 @@ void DetectPktvarRegister (void) * -1: error */ -int DetectPktvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectPktvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { int ret = 0; const DetectPktvarData *pd = (const DetectPktvarData *)ctx; diff --git a/src/detect-rpc.c b/src/detect-rpc.c index b3052ce547b4..b559ad6f07eb 100644 --- a/src/detect-rpc.c +++ b/src/detect-rpc.c @@ -48,8 +48,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectRpcMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); -int DetectRpcSetup (DetectEngineCtx *, Signature *, char *); +static int DetectRpcMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); +static int DetectRpcSetup (DetectEngineCtx *, Signature *, char *); void DetectRpcRegisterTests(void); void DetectRpcFree(void *); @@ -86,7 +87,8 @@ void DetectRpcRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectRpcMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectRpcMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { /* PrintRawDataFp(stdout, p->payload, p->payload_len); */ const DetectRpcData *rd = (const DetectRpcData *)ctx; diff --git a/src/detect-sameip.c b/src/detect-sameip.c index e22a943f384e..780832b8fef4 100644 --- a/src/detect-sameip.c +++ b/src/detect-sameip.c @@ -38,7 +38,7 @@ #include "util-unittest-helper.h" static int DetectSameipMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); + const Signature *, const SigMatchCtx *); static int DetectSameipSetup(DetectEngineCtx *, Signature *, char *); static void DetectSameipRegisterTests(void); @@ -71,7 +71,7 @@ void DetectSameipRegister(void) * \retval 1 match */ static int DetectSameipMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { return CMP_ADDR(&p->src, &p->dst) ? 1 : 0; } diff --git a/src/detect-seq.c b/src/detect-seq.c index cb2bb9930f16..f747d40a59e7 100644 --- a/src/detect-seq.c +++ b/src/detect-seq.c @@ -42,7 +42,7 @@ static int DetectSeqSetup(DetectEngineCtx *, Signature *, char *); static int DetectSeqMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, const SigMatchCtx *); + Packet *, const Signature *, const SigMatchCtx *); static void DetectSeqRegisterTests(void); static void DetectSeqFree(void *); static int PrefilterSetupTcpSeq(SigGroupHead *sgh); @@ -75,7 +75,7 @@ void DetectSeqRegister(void) * \retval 1 match */ static int DetectSeqMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectSeqData *data = (const DetectSeqData *)ctx; diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index 3df3dfe0b48d..f22cfe386f12 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -62,7 +62,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectSshVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectSshVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t, void *, const Signature *, const SigMatch *); static int DetectSshVersionSetup (DetectEngineCtx *, Signature *, char *); void DetectSshVersionRegisterTests(void); void DetectSshVersionFree(void *); @@ -93,7 +94,8 @@ void DetectSshVersionRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectSshVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectSshVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, + uint8_t flags, void *state, const Signature *s, const SigMatch *m) { SCEnter(); diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index 1284bbc37e6e..7a24703b980a 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -66,7 +66,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectSshSoftwareVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectSshSoftwareVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t, void *, const Signature *, const SigMatch *); static int DetectSshSoftwareVersionSetup (DetectEngineCtx *, Signature *, char *); void DetectSshSoftwareVersionRegisterTests(void); void DetectSshSoftwareVersionFree(void *); @@ -98,7 +99,8 @@ void DetectSshSoftwareVersionRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectSshSoftwareVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectSshSoftwareVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, + uint8_t flags, void *state, const Signature *s, const SigMatch *m) { SCEnter(); diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index a46d55c5405c..6be0204ebc42 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -59,9 +59,9 @@ static pcre_extra *parse_regex1_study; static pcre *parse_regex2; static pcre_extra *parse_regex2_study; -int DetectSslStateMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, Signature *, SigMatch *); -int DetectSslStateSetup(DetectEngineCtx *, Signature *, char *); +static int DetectSslStateMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t, void *, const Signature *, const SigMatch *); +static int DetectSslStateSetup(DetectEngineCtx *, Signature *, char *); void DetectSslStateRegisterTests(void); void DetectSslStateFree(void *); @@ -95,9 +95,9 @@ void DetectSslStateRegister(void) * \retval 1 Match. * \retval 0 No match. */ -int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *alstate, Signature *s, - SigMatch *m) +static int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *alstate, const Signature *s, + const SigMatch *m) { DetectSslStateData *ssd = (DetectSslStateData *)m->ctx; SSLState *ssl_state = (SSLState *)alstate; diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index 52a5d4b72aff..a699b10926ff 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -60,8 +60,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectSslVersionMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, Signature *, SigMatch *); +static int DetectSslVersionMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t, void *, const Signature *, const SigMatch *); static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, char *); void DetectSslVersionRegisterTests(void); void DetectSslVersionFree(void *); @@ -92,8 +92,9 @@ void DetectSslVersionRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatch *m) { SCEnter(); diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c index d27dcd2dda51..529139d5c83d 100644 --- a/src/detect-stream_size.c +++ b/src/detect-stream_size.c @@ -44,7 +44,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; /*prototypes*/ -int DetectStreamSizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectStreamSizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectStreamSizeSetup (DetectEngineCtx *, Signature *, char *); void DetectStreamSizeFree(void *); void DetectStreamSizeRegisterTests(void); @@ -121,7 +122,8 @@ static int DetectStreamSizeCompare (uint32_t diff, uint32_t stream_size, uint8_t * \retval 0 no match * \retval 1 match */ -int DetectStreamSizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectStreamSizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { int ret = 0; diff --git a/src/detect-tag.c b/src/detect-tag.c index dfa762d190bb..b844deb7eefd 100644 --- a/src/detect-tag.c +++ b/src/detect-tag.c @@ -57,7 +57,8 @@ SC_ATOMIC_EXTERN(unsigned int, num_tags); static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectTagMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectTagMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectTagSetup(DetectEngineCtx *, Signature *, char *); void DetectTagRegisterTests(void); void DetectTagDataFree(void *); @@ -88,7 +89,8 @@ void DetectTagRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectTagMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectTagMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { const DetectTagData *td = (const DetectTagData *)ctx; DetectTagDataEntry tde; diff --git a/src/detect-template.c b/src/detect-template.c index b3ffb08e7941..b3aff67bde3e 100644 --- a/src/detect-template.c +++ b/src/detect-template.c @@ -40,7 +40,7 @@ static pcre_extra *parse_regex_study; /* Prototypes of functions registered in DetectTemplateRegister below */ static int DetectTemplateMatch (ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, const SigMatchCtx *); + Packet *, const Signature *, const SigMatchCtx *); static int DetectTemplateSetup (DetectEngineCtx *, Signature *, char *); static void DetectTemplateFree (void *); static void DetectTemplateRegisterTests (void); @@ -84,7 +84,7 @@ void DetectTemplateRegister(void) { * \retval 1 match */ static int DetectTemplateMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s, const SigMatchCtx *ctx) + const Signature *s, const SigMatchCtx *ctx) { int ret = 0; const DetectTemplateData *templated = (const DetectTemplateData *) ctx; diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 487de7685ad6..2cefc1896bbd 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -64,7 +64,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectThresholdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectThresholdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectThresholdSetup(DetectEngineCtx *, Signature *, char *); static void DetectThresholdFree(void *); @@ -87,7 +88,8 @@ void DetectThresholdRegister(void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -static int DetectThresholdMatch(ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectThresholdMatch(ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { return 1; } diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index 574ec7de4d71..6482e9128224 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -59,7 +59,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectTlsVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectTlsVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t, void *, const Signature *, const SigMatch *); static int DetectTlsVersionSetup (DetectEngineCtx *, Signature *, char *); void DetectTlsVersionRegisterTests(void); void DetectTlsVersionFree(void *); @@ -92,7 +93,8 @@ void DetectTlsVersionRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectTlsVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectTlsVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, + uint8_t flags, void *state, const Signature *s, const SigMatch *m) { SCEnter(); diff --git a/src/detect-tls.c b/src/detect-tls.c index b199b1fa175e..c97b5fd9f7bd 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -74,19 +74,19 @@ static pcre_extra *issuerdn_parse_regex_study; static pcre *fingerprint_parse_regex; static pcre_extra *fingerprint_parse_regex_study; -static int DetectTlsSubjectMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectTlsSubjectMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatch *); static int DetectTlsSubjectSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsSubjectRegisterTests(void); static void DetectTlsSubjectFree(void *); -static int DetectTlsIssuerDNMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectTlsIssuerDNMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatch *); static int DetectTlsIssuerDNSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsIssuerDNRegisterTests(void); static void DetectTlsIssuerDNFree(void *); -static int DetectTlsFingerprintMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectTlsFingerprintMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatch *); static int DetectTlsFingerprintSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsFingerprintFree(void *); static int DetectTlsStoreSetup (DetectEngineCtx *, Signature *, char *); -static int DetectTlsStoreMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectTlsStoreMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatch *); /** * \brief Registration function for keyword: tls.version @@ -149,7 +149,8 @@ void DetectTlsRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectTlsSubjectMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectTlsSubjectMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, + uint8_t flags, void *state, const Signature *s, const SigMatch *m) { SCEnter(); @@ -359,7 +360,8 @@ static void DetectTlsSubjectRegisterTests(void) * \retval 0 no match * \retval 1 match */ -static int DetectTlsIssuerDNMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectTlsIssuerDNMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, + uint8_t flags, void *state, const Signature *s, const SigMatch *m) { SCEnter(); @@ -641,7 +643,8 @@ static DetectTlsData *DetectTlsFingerprintParse (char *str) * \retval 0 no match * \retval 1 match */ -static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, + uint8_t flags, void *state, const Signature *s, const SigMatch *m) { SCEnter(); DetectTlsData *tls_data = (DetectTlsData *)m->ctx; @@ -793,7 +796,8 @@ static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *str } /** \warning modifies state */ -static int DetectTlsStoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectTlsStoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, + uint8_t flags, void *state, const Signature *s, const SigMatch *m) { SCEnter(); diff --git a/src/detect-tos.c b/src/detect-tos.c index 994454671171..699d2474b11a 100644 --- a/src/detect-tos.c +++ b/src/detect-tos.c @@ -50,7 +50,7 @@ static pcre_extra *parse_regex_study; static int DetectTosSetup(DetectEngineCtx *, Signature *, char *); static int DetectTosMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); + const Signature *, const SigMatchCtx *); static void DetectTosRegisterTests(void); static void DetectTosFree(void *); @@ -82,8 +82,8 @@ void DetectTosRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectTosMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s, const SigMatchCtx *ctx) +static int DetectTosMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { const DetectTosData *tosd = (const DetectTosData *)ctx; int result = 0; diff --git a/src/detect-ttl.c b/src/detect-ttl.c index 1c1e0e5b3188..9b7115864554 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -43,7 +43,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; /*prototypes*/ -int DetectTtlMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectTtlMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectTtlSetup (DetectEngineCtx *, Signature *, char *); void DetectTtlFree (void *); void DetectTtlRegisterTests (void); @@ -99,7 +100,8 @@ static inline int TtlMatch(const uint8_t pttl, const uint8_t mode, * \retval 0 no match * \retval 1 match */ -int DetectTtlMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectTtlMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { if (PKT_IS_PSEUDOPKT(p)) diff --git a/src/detect-window.c b/src/detect-window.c index c9a81920eae3..4c4468254412 100644 --- a/src/detect-window.c +++ b/src/detect-window.c @@ -47,8 +47,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectWindowMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); -int DetectWindowSetup(DetectEngineCtx *, Signature *, char *); +static int DetectWindowMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); +static int DetectWindowSetup(DetectEngineCtx *, Signature *, char *); void DetectWindowRegisterTests(void); void DetectWindowFree(void *); @@ -79,7 +80,8 @@ void DetectWindowRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { const DetectWindowData *wd = (const DetectWindowData *)ctx; @@ -102,7 +104,7 @@ int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, * \retval wd pointer to DetectWindowData on success * \retval NULL on failure */ -DetectWindowData *DetectWindowParse(char *windowstr) +static DetectWindowData *DetectWindowParse(char *windowstr) { DetectWindowData *wd = NULL; #define MAX_SUBSTRINGS 30 @@ -169,7 +171,7 @@ DetectWindowData *DetectWindowParse(char *windowstr) * \retval 0 on Success * \retval -1 on Failure */ -int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, char *windowstr) +static int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, char *windowstr) { DetectWindowData *wd = NULL; SigMatch *sm = NULL; diff --git a/src/detect-xbits.c b/src/detect-xbits.c index 131e29e4a32f..664f9451a3d1 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -57,7 +57,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectXbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectXbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectXbitSetup (DetectEngineCtx *, Signature *, char *); void DetectXbitFree (void *); void XBitsRegisterTests(void); @@ -161,7 +161,7 @@ static int DetectXbitMatchIPPair(Packet *p, const DetectXbitsData *xd) * -1: error */ -int DetectXbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static int DetectXbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectXbitsData *fd = (const DetectXbitsData *)ctx; if (fd == NULL) diff --git a/src/detect.c b/src/detect.c index 5660c28339a2..d998e8db0d84 100644 --- a/src/detect.c +++ b/src/detect.c @@ -539,7 +539,7 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl int SigMatchSignaturesRunPostMatch(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s) + const Signature *s) { /* run the packet match functions */ if (s->sm_arrays[DETECT_SM_LIST_POSTMATCH] != NULL) { @@ -1034,8 +1034,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh int smatch = 0; /* signature match: 1, no match: 0 */ #endif uint8_t flow_flags = 0; /* flow/state flags */ - Signature *s = NULL; - Signature *next_s = NULL; + const Signature *s = NULL; + const Signature *next_s = NULL; uint8_t alversion = 0; int state_alert = 0; int alerts = 0; @@ -1791,7 +1791,7 @@ Signature *SigFindSignatureBySidGid(DetectEngineCtx *de_ctx, uint32_t sid, uint3 } -int SignatureIsAppLayer(DetectEngineCtx *de_ctx, Signature *s) +int SignatureIsAppLayer(DetectEngineCtx *de_ctx, const Signature *s) { if (s->alproto != 0) return 1; @@ -1807,7 +1807,7 @@ int SignatureIsAppLayer(DetectEngineCtx *de_ctx, Signature *s) * \retval 0 no * \retval 1 yes */ -int SignatureIsFilestoring(Signature *s) +int SignatureIsFilestoring(const Signature *s) { if (s == NULL) return 0; @@ -1826,7 +1826,7 @@ int SignatureIsFilestoring(Signature *s) * \retval 0 no * \retval 1 yes */ -int SignatureIsFilemagicInspecting(Signature *s) +int SignatureIsFilemagicInspecting(const Signature *s) { if (s == NULL) return 0; @@ -1845,7 +1845,7 @@ int SignatureIsFilemagicInspecting(Signature *s) * \retval 0 no * \retval 1 yes */ -int SignatureIsFileMd5Inspecting(Signature *s) +int SignatureIsFileMd5Inspecting(const Signature *s) { if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_MD5)) return 1; @@ -1861,7 +1861,7 @@ int SignatureIsFileMd5Inspecting(Signature *s) * \retval 0 no * \retval 1 yes */ -int SignatureIsFileSha1Inspecting(Signature *s) +int SignatureIsFileSha1Inspecting(const Signature *s) { if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_SHA1)) return 1; @@ -1877,7 +1877,7 @@ int SignatureIsFileSha1Inspecting(Signature *s) * \retval 0 no * \retval 1 yes */ -int SignatureIsFileSha256Inspecting(Signature *s) +int SignatureIsFileSha256Inspecting(const Signature *s) { if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_SHA256)) return 1; @@ -1893,7 +1893,7 @@ int SignatureIsFileSha256Inspecting(Signature *s) * \retval 0 no * \retval 1 yes */ -int SignatureIsFilesizeInspecting(Signature *s) +int SignatureIsFilesizeInspecting(const Signature *s) { if (s == NULL) return 0; @@ -1910,7 +1910,7 @@ int SignatureIsFilesizeInspecting(Signature *s) * \retval 1 sig is ip only * \retval 0 sig is not ip only */ -int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) +int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) { if (s->alproto != ALPROTO_UNKNOWN) return 0; @@ -2108,7 +2108,7 @@ static int SignatureIsPDOnly(const Signature *s) * \retval 1 sig is inspecting the payload * \retval 0 sig is not inspecting the payload */ -static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, Signature *s) +static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, const Signature *s) { if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { @@ -2138,7 +2138,7 @@ static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, Signature *s) * \retval 0 not a DEOnly sig * \retval 1 DEOnly sig */ -static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, Signature *s) +static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) { if (s->alproto != ALPROTO_UNKNOWN) { SCReturnInt(0); diff --git a/src/detect.h b/src/detect.h index 30d95f014be5..3040c4875a17 100644 --- a/src/detect.h +++ b/src/detect.h @@ -393,7 +393,7 @@ typedef struct DetectEngineAppInspectionEngine_ { */ int (*Callback)(ThreadVars *tv, struct DetectEngineCtx_ *de_ctx, struct DetectEngineThreadCtx_ *det_ctx, - struct Signature_ *sig, Flow *f, uint8_t flags, void *alstate, + const struct Signature_ *sig, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); struct DetectEngineAppInspectionEngine_ *next; @@ -958,10 +958,10 @@ typedef struct DetectEngineThreadCtx_ { */ typedef struct SigTableElmt_ { /** Packet match function pointer */ - int (*Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); + int (*Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); /** AppLayer match function pointer */ - int (*AppLayerMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, Signature *, SigMatch *); + int (*AppLayerMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, const Signature *, const SigMatch *); /** AppLayer TX match function pointer */ int (*AppLayerTxMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, @@ -972,7 +972,7 @@ typedef struct SigTableElmt_ { int (*FileMatch)(ThreadVars *, /**< thread local vars */ DetectEngineThreadCtx *, Flow *, /**< *LOCKED* flow */ - uint8_t flags, File *, Signature *, SigMatch *); + uint8_t flags, File *, const Signature *, const SigMatch *); /** keyword setup function pointer */ int (*Setup)(DetectEngineCtx *, Signature *, char *); @@ -1377,24 +1377,24 @@ void SigTableSetup(void); int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p); -int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s); +int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const 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 SignatureIsFileSha1Inspecting(Signature *s); -int SignatureIsFileSha256Inspecting(Signature *s); -int SignatureIsFilesizeInspecting(Signature *); +int SignatureIsFilestoring(const Signature *); +int SignatureIsFilemagicInspecting(const Signature *); +int SignatureIsFileMd5Inspecting(const Signature *); +int SignatureIsFileSha1Inspecting(const Signature *s); +int SignatureIsFileSha256Inspecting(const Signature *s); +int SignatureIsFilesizeInspecting(const 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); + const Signature *s); void DetectSignatureApplyActions(Packet *p, const Signature *s); #endif /* __DETECT_H__ */ diff --git a/src/util-detect-file-hash.c b/src/util-detect-file-hash.c index 840f61c2bbbd..8bee60c42308 100644 --- a/src/util-detect-file-hash.c +++ b/src/util-detect-file-hash.c @@ -147,7 +147,7 @@ static int HashMatchHashTable(ROHashTable *hash_table, uint8_t *hash, * \retval 1 match */ int DetectFileHashMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatch *m) { SCEnter(); int ret = 0; diff --git a/src/util-detect-file-hash.h b/src/util-detect-file-hash.h index 0e9835bb4d78..c247fb5aa387 100644 --- a/src/util-detect-file-hash.h +++ b/src/util-detect-file-hash.h @@ -38,7 +38,7 @@ int ReadHashString(uint8_t *, char *, char *, int, uint16_t); int LoadHashTable(ROHashTable *, char *, char *, int, uint32_t); int DetectFileHashMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - File *, Signature *, SigMatch *); + File *, const Signature *, const SigMatch *); int DetectFileHashSetup(DetectEngineCtx *, Signature *, char *, uint32_t); void DetectFileHashFree(void *); From 39613778cd37bcb7a070ba66a4ef61e34b1bccaa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Oct 2016 12:17:04 +0200 Subject: [PATCH 2335/2553] detect: make setup/free/match funcs static where possible --- src/detect-asn1.c | 70 ++++++++-------- src/detect-bypass.c | 6 +- src/detect-byte-extract.c | 147 ++++++++++++++++----------------- src/detect-byte-extract.h | 5 +- src/detect-bytejump.c | 53 ++++++------ src/detect-bytejump.h | 39 --------- src/detect-bytetest.c | 69 +++++++++------- src/detect-bytetest.h | 55 ------------ src/detect-cipservice.c | 8 +- src/detect-cipservice.h | 5 -- src/detect-classtype.c | 10 +-- src/detect-content.c | 112 ++++++++++++------------- src/detect-csum.c | 81 +++++++++--------- src/detect-dce-iface.c | 12 ++- src/detect-dce-iface.h | 1 - src/detect-dce-opnum.c | 17 ++-- src/detect-dce-opnum.h | 1 - src/detect-dce-stub-data.c | 5 +- src/detect-dce-stub-data.h | 1 - src/detect-detection-filter.c | 33 ++++---- src/detect-detection-filter.h | 10 --- src/detect-distance.c | 6 +- src/detect-dsize.c | 4 +- src/detect-engine-dcepayload.c | 90 ++++++++++---------- src/detect-engine-iponly.c | 22 ++--- 25 files changed, 370 insertions(+), 492 deletions(-) diff --git a/src/detect-asn1.c b/src/detect-asn1.c index 5cb6e3bb9ee6..7bdc57957abb 100644 --- a/src/detect-asn1.c +++ b/src/detect-asn1.c @@ -42,11 +42,11 @@ /* delimiters for functions/arguments */ const char *ASN_DELIM = " \t,\n"; -int DetectAsn1Match(ThreadVars *, DetectEngineThreadCtx *, Packet *, +static int DetectAsn1Match(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectAsn1Setup (DetectEngineCtx *, Signature *, char *); -void DetectAsn1RegisterTests(void); -void DetectAsn1Free(void *); +static void DetectAsn1RegisterTests(void); +static void DetectAsn1Free(void *); /** * \brief Registration function for asn1 @@ -137,7 +137,7 @@ static uint8_t DetectAsn1Checks(Asn1Node *node, const DetectAsn1Data *ad) * \retval 0 no match * \retval 1 match */ -int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, +static int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { uint8_t ret = 0; @@ -197,7 +197,7 @@ int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, * \retval fd pointer to DetectAsn1Data on success * \retval NULL on failure */ -DetectAsn1Data *DetectAsn1Parse(char *asn1str) +static DetectAsn1Data *DetectAsn1Parse(char *asn1str) { DetectAsn1Data *fd = NULL; char *tok = NULL; @@ -289,7 +289,7 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) * \retval 0 on Success * \retval -1 on Failure */ -int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, char *asn1str) +static int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, char *asn1str) { DetectAsn1Data *ad = NULL; SigMatch *sm = NULL; @@ -311,8 +311,10 @@ int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, char *asn1str) return 0; error: - if (ad != NULL) DetectAsn1Free(ad); - if (sm != NULL) SCFree(sm); + if (ad != NULL) + DetectAsn1Free(ad); + if (sm != NULL) + SCFree(sm); return -1; } @@ -322,7 +324,7 @@ int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, char *asn1str) * * \param ad pointer to DetectAsn1Data */ -void DetectAsn1Free(void *ptr) +static void DetectAsn1Free(void *ptr) { DetectAsn1Data *ad = (DetectAsn1Data *)ptr; SCFree(ad); @@ -333,7 +335,7 @@ void DetectAsn1Free(void *ptr) /** * \test DetectAsn1TestParse01 check that we parse oversize_length correctly */ -int DetectAsn1TestParse01(void) +static int DetectAsn1TestParse01(void) { int result = 0; char str[] = "oversize_length 1024"; @@ -353,7 +355,7 @@ int DetectAsn1TestParse01(void) /** * \test DetectAsn1TestParse02 check that we parse absolute_offset correctly */ -int DetectAsn1TestParse02(void) +static int DetectAsn1TestParse02(void) { int result = 0; DetectAsn1Data *ad = NULL; @@ -372,7 +374,7 @@ int DetectAsn1TestParse02(void) /** * \test DetectAsn1TestParse03 check that we parse relative_offset correctly */ -int DetectAsn1TestParse03(void) +static int DetectAsn1TestParse03(void) { int result = 0; char str[] = "relative_offset 1024"; @@ -391,7 +393,7 @@ int DetectAsn1TestParse03(void) /** * \test DetectAsn1TestParse04 check that we parse bitstring_overflow correctly */ -int DetectAsn1TestParse04(void) +static int DetectAsn1TestParse04(void) { int result = 0; char str[] = "bitstring_overflow"; @@ -409,7 +411,7 @@ int DetectAsn1TestParse04(void) /** * \test DetectAsn1TestParse05 check that we parse double_overflow correctly */ -int DetectAsn1TestParse05(void) +static int DetectAsn1TestParse05(void) { int result = 0; char str[] = "double_overflow"; @@ -427,7 +429,7 @@ int DetectAsn1TestParse05(void) /** * \test DetectAsn1TestParse06 check that we fail if a needed arg is not given */ -int DetectAsn1TestParse06(void) +static int DetectAsn1TestParse06(void) { int result = 1; char str[] = "absolute_offset"; @@ -445,7 +447,7 @@ int DetectAsn1TestParse06(void) /** * \test DetectAsn1TestParse07 check that we fail if a needed arg is not given */ -int DetectAsn1TestParse07(void) +static int DetectAsn1TestParse07(void) { int result = 1; char str[] = "relative_offset"; @@ -463,7 +465,7 @@ int DetectAsn1TestParse07(void) /** * \test DetectAsn1TestParse08 check that we fail if a needed arg is not given */ -int DetectAsn1TestParse08(void) +static int DetectAsn1TestParse08(void) { int result = 1; char str[] = "oversize_length"; @@ -483,7 +485,7 @@ int DetectAsn1TestParse08(void) /** * \test DetectAsn1TestParse09 test that we break on invalid options */ -int DetectAsn1TestParse09(void) +static int DetectAsn1TestParse09(void) { int result = 1; DetectAsn1Data *fd = NULL; @@ -501,7 +503,7 @@ int DetectAsn1TestParse09(void) /** * \test DetectAsn1TestParse10 test that we break with a empty string */ -int DetectAsn1TestParse10(void) +static int DetectAsn1TestParse10(void) { int result = 1; DetectAsn1Data *fd = NULL; @@ -519,7 +521,7 @@ int DetectAsn1TestParse10(void) /** * \test DetectAsn1TestParse11 check for combinations of keywords */ -int DetectAsn1TestParse11(void) +static int DetectAsn1TestParse11(void) { int result = 0; char str[] = "oversize_length 1024, relative_offset 10"; @@ -541,7 +543,7 @@ int DetectAsn1TestParse11(void) /** * \test DetectAsn1TestParse12 check for combinations of keywords */ -int DetectAsn1TestParse12(void) +static int DetectAsn1TestParse12(void) { int result = 0; char str[] = "oversize_length 1024 absolute_offset 10"; @@ -563,7 +565,7 @@ int DetectAsn1TestParse12(void) /** * \test DetectAsn1TestParse13 check for combinations of keywords */ -int DetectAsn1TestParse13(void) +static int DetectAsn1TestParse13(void) { int result = 0; char str[] = "oversize_length 1024 absolute_offset 10, bitstring_overflow"; @@ -586,7 +588,7 @@ int DetectAsn1TestParse13(void) /** * \test DetectAsn1TestParse14 check for combinations of keywords */ -int DetectAsn1TestParse14(void) +static int DetectAsn1TestParse14(void) { int result = 0; char str[] = "double_overflow, oversize_length 1024 absolute_offset 10," @@ -611,7 +613,7 @@ int DetectAsn1TestParse14(void) /** * \test DetectAsn1TestParse15 check for combinations of keywords */ -int DetectAsn1TestParse15(void) +static int DetectAsn1TestParse15(void) { int result = 0; char str[] = "double_overflow, oversize_length 1024 relative_offset 10," @@ -694,7 +696,7 @@ static int DetectAsn1Test01(void) /** * \test DetectAsn1Test02 Ensure that the checks work when they should */ -int DetectAsn1Test02(void) +static int DetectAsn1Test02(void) { int result = 0; /* Match if any of the nodes has the bitstring overflow condition */ @@ -762,7 +764,7 @@ int DetectAsn1Test02(void) /** * \test DetectAsn1Test03 Ensure that the checks work when they should */ -int DetectAsn1Test03(void) +static int DetectAsn1Test03(void) { int result = 0; /* Match if any of the nodes after offset 0 has a bitstring overflow */ @@ -821,7 +823,7 @@ int DetectAsn1Test03(void) /** * \test DetectAsn1Test04 Ensure that the checks work when they should */ -int DetectAsn1Test04(void) +static int DetectAsn1Test04(void) { int result = 0; /* Match if any of the nodes after offset 0 has a bitstring overflow */ @@ -883,7 +885,7 @@ int DetectAsn1Test04(void) /** * \test DetectAsn1Test05 Ensure that the checks work when they should */ -int DetectAsn1Test05(void) +static int DetectAsn1Test05(void) { int result = 0; /* Match if any of the nodes after offset 0 has a double overflow */ @@ -953,7 +955,7 @@ int DetectAsn1Test05(void) /** * \test DetectAsn1Test06 Ensure that the checks work when they should */ -int DetectAsn1Test06(void) +static int DetectAsn1Test06(void) { int result = 0; /* Match if any of the nodes after offset 0 has a double overflow */ @@ -1026,7 +1028,7 @@ int DetectAsn1Test06(void) /** * \test DetectAsn1TestReal01 Ensure that all works together */ -int DetectAsn1TestReal01(void) +static int DetectAsn1TestReal01(void) { int result = 0; uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" @@ -1105,7 +1107,7 @@ int DetectAsn1TestReal01(void) /** * \test DetectAsn1TestReal02 Ensure that all works together */ -int DetectAsn1TestReal02(void) +static int DetectAsn1TestReal02(void) { int result = 0; uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" @@ -1182,7 +1184,7 @@ int DetectAsn1TestReal02(void) /** * \test DetectAsn1TestReal03 Ensure that all works together */ -int DetectAsn1TestReal03(void) +static int DetectAsn1TestReal03(void) { int result = 0; uint8_t buf[261] = ""; @@ -1243,7 +1245,7 @@ int DetectAsn1TestReal03(void) * relative offset to check negative offset values, in this case * start decoding from -7 bytes respect the content match "John" */ -int DetectAsn1TestReal04(void) +static int DetectAsn1TestReal04(void) { int result = 0; uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" @@ -1322,7 +1324,7 @@ int DetectAsn1TestReal04(void) /** * \brief this function registers unit tests for DetectAsn1 */ -void DetectAsn1RegisterTests(void) +static void DetectAsn1RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectAsn1TestParse01", DetectAsn1TestParse01); diff --git a/src/detect-bypass.c b/src/detect-bypass.c index dce7abe44ae0..a92e2822796a 100644 --- a/src/detect-bypass.c +++ b/src/detect-bypass.c @@ -49,7 +49,7 @@ #include "util-unittest-helper.h" #include "util-device.h" -int DetectBypassMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, +static int DetectBypassMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectBypassSetup(DetectEngineCtx *, Signature *, char *); static void DetectBypassRegisterTests(void); @@ -92,7 +92,7 @@ static int DetectBypassSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) return 0; } -int DetectBypassMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, +static int DetectBypassMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { PacketBypassCallback(p); @@ -232,7 +232,7 @@ static int DetectBypassTestSig01(void) } #endif /* UNITTESTS */ -void DetectBypassRegisterTests(void) +static void DetectBypassRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectBypassTestSig01", DetectBypassTestSig01); diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 7c1a50dd3788..24b577bc84be 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -89,11 +89,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectByteExtractMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatch *); -int DetectByteExtractSetup(DetectEngineCtx *, Signature *, char *); -void DetectByteExtractRegisterTests(void); -void DetectByteExtractFree(void *); +static int DetectByteExtractSetup(DetectEngineCtx *, Signature *, char *); +static void DetectByteExtractRegisterTests(void); +static void DetectByteExtractFree(void *); /** * \brief Registers the keyword handlers for the "byte_extract" keyword. @@ -202,13 +200,6 @@ int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatch *sm, return 1; } - -int DetectByteExtractMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatch *m) -{ - return 1; -} - /** * \internal * \brief Used to parse byte_extract arg. @@ -516,7 +507,7 @@ static inline DetectByteExtractData *DetectByteExtractParse(char *arg) * \retval 0 On success. * \retval -1 On failure. */ -int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { SigMatch *sm = NULL; SigMatch *prev_pm = NULL; @@ -734,7 +725,7 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) * * \param ptr Instance of DetectByteExtractData to be freed. */ -void DetectByteExtractFree(void *ptr) +static void DetectByteExtractFree(void *ptr) { if (ptr != NULL) { DetectByteExtractData *bed = ptr; @@ -779,7 +770,7 @@ SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, const Signature *s) #ifdef UNITTESTS -int DetectByteExtractTest01(void) +static int DetectByteExtractTest01(void) { int result = 0; @@ -805,7 +796,7 @@ int DetectByteExtractTest01(void) return result; } -int DetectByteExtractTest02(void) +static int DetectByteExtractTest02(void) { int result = 0; @@ -831,7 +822,7 @@ int DetectByteExtractTest02(void) return result; } -int DetectByteExtractTest03(void) +static int DetectByteExtractTest03(void) { int result = 0; @@ -857,7 +848,7 @@ int DetectByteExtractTest03(void) return result; } -int DetectByteExtractTest04(void) +static int DetectByteExtractTest04(void) { int result = 0; @@ -884,7 +875,7 @@ int DetectByteExtractTest04(void) return result; } -int DetectByteExtractTest05(void) +static int DetectByteExtractTest05(void) { int result = 0; @@ -910,7 +901,7 @@ int DetectByteExtractTest05(void) return result; } -int DetectByteExtractTest06(void) +static int DetectByteExtractTest06(void) { int result = 0; @@ -936,7 +927,7 @@ int DetectByteExtractTest06(void) return result; } -int DetectByteExtractTest07(void) +static int DetectByteExtractTest07(void) { int result = 0; @@ -962,7 +953,7 @@ int DetectByteExtractTest07(void) return result; } -int DetectByteExtractTest08(void) +static int DetectByteExtractTest08(void) { int result = 0; @@ -988,7 +979,7 @@ int DetectByteExtractTest08(void) return result; } -int DetectByteExtractTest09(void) +static int DetectByteExtractTest09(void) { int result = 0; @@ -1014,7 +1005,7 @@ int DetectByteExtractTest09(void) return result; } -int DetectByteExtractTest10(void) +static int DetectByteExtractTest10(void) { int result = 0; @@ -1040,7 +1031,7 @@ int DetectByteExtractTest10(void) return result; } -int DetectByteExtractTest11(void) +static int DetectByteExtractTest11(void) { int result = 0; @@ -1066,7 +1057,7 @@ int DetectByteExtractTest11(void) return result; } -int DetectByteExtractTest12(void) +static int DetectByteExtractTest12(void) { int result = 0; @@ -1093,7 +1084,7 @@ int DetectByteExtractTest12(void) return result; } -int DetectByteExtractTest13(void) +static int DetectByteExtractTest13(void) { int result = 0; @@ -1121,7 +1112,7 @@ int DetectByteExtractTest13(void) return result; } -int DetectByteExtractTest14(void) +static int DetectByteExtractTest14(void) { int result = 0; @@ -1149,7 +1140,7 @@ int DetectByteExtractTest14(void) return result; } -int DetectByteExtractTest15(void) +static int DetectByteExtractTest15(void) { int result = 0; @@ -1177,7 +1168,7 @@ int DetectByteExtractTest15(void) return result; } -int DetectByteExtractTest16(void) +static int DetectByteExtractTest16(void) { int result = 0; @@ -1206,7 +1197,7 @@ int DetectByteExtractTest16(void) return result; } -int DetectByteExtractTest17(void) +static int DetectByteExtractTest17(void) { int result = 0; @@ -1223,7 +1214,7 @@ int DetectByteExtractTest17(void) return result; } -int DetectByteExtractTest18(void) +static int DetectByteExtractTest18(void) { int result = 0; @@ -1241,7 +1232,7 @@ int DetectByteExtractTest18(void) return result; } -int DetectByteExtractTest19(void) +static int DetectByteExtractTest19(void) { int result = 0; @@ -1259,7 +1250,7 @@ int DetectByteExtractTest19(void) return result; } -int DetectByteExtractTest20(void) +static int DetectByteExtractTest20(void) { int result = 0; @@ -1277,7 +1268,7 @@ int DetectByteExtractTest20(void) return result; } -int DetectByteExtractTest21(void) +static int DetectByteExtractTest21(void) { int result = 0; @@ -1295,7 +1286,7 @@ int DetectByteExtractTest21(void) return result; } -int DetectByteExtractTest22(void) +static int DetectByteExtractTest22(void) { int result = 0; @@ -1313,7 +1304,7 @@ int DetectByteExtractTest22(void) return result; } -int DetectByteExtractTest23(void) +static int DetectByteExtractTest23(void) { int result = 0; @@ -1331,7 +1322,7 @@ int DetectByteExtractTest23(void) return result; } -int DetectByteExtractTest24(void) +static int DetectByteExtractTest24(void) { int result = 0; @@ -1348,7 +1339,7 @@ int DetectByteExtractTest24(void) return result; } -int DetectByteExtractTest25(void) +static int DetectByteExtractTest25(void) { int result = 0; @@ -1365,7 +1356,7 @@ int DetectByteExtractTest25(void) return result; } -int DetectByteExtractTest26(void) +static int DetectByteExtractTest26(void) { int result = 0; @@ -1383,7 +1374,7 @@ int DetectByteExtractTest26(void) return result; } -int DetectByteExtractTest27(void) +static int DetectByteExtractTest27(void) { int result = 0; @@ -1401,7 +1392,7 @@ int DetectByteExtractTest27(void) return result; } -int DetectByteExtractTest28(void) +static int DetectByteExtractTest28(void) { int result = 0; @@ -1416,7 +1407,7 @@ int DetectByteExtractTest28(void) return result; } -int DetectByteExtractTest29(void) +static int DetectByteExtractTest29(void) { int result = 0; @@ -1431,7 +1422,7 @@ int DetectByteExtractTest29(void) return result; } -int DetectByteExtractTest30(void) +static int DetectByteExtractTest30(void) { int result = 0; @@ -1446,7 +1437,7 @@ int DetectByteExtractTest30(void) return result; } -int DetectByteExtractTest31(void) +static int DetectByteExtractTest31(void) { int result = 0; @@ -1461,7 +1452,7 @@ int DetectByteExtractTest31(void) return result; } -int DetectByteExtractTest32(void) +static int DetectByteExtractTest32(void) { int result = 0; @@ -1476,7 +1467,7 @@ int DetectByteExtractTest32(void) return result; } -int DetectByteExtractTest33(void) +static int DetectByteExtractTest33(void) { int result = 0; @@ -1491,7 +1482,7 @@ int DetectByteExtractTest33(void) return result; } -int DetectByteExtractTest34(void) +static int DetectByteExtractTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -1567,7 +1558,7 @@ int DetectByteExtractTest34(void) return result; } -int DetectByteExtractTest35(void) +static int DetectByteExtractTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -1655,7 +1646,7 @@ int DetectByteExtractTest35(void) return result; } -int DetectByteExtractTest36(void) +static int DetectByteExtractTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -1743,7 +1734,7 @@ int DetectByteExtractTest36(void) return result; } -int DetectByteExtractTest37(void) +static int DetectByteExtractTest37(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -1844,7 +1835,7 @@ int DetectByteExtractTest37(void) return result; } -int DetectByteExtractTest38(void) +static int DetectByteExtractTest38(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -1944,7 +1935,7 @@ int DetectByteExtractTest38(void) return result; } -int DetectByteExtractTest39(void) +static int DetectByteExtractTest39(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2045,7 +2036,7 @@ int DetectByteExtractTest39(void) return result; } -int DetectByteExtractTest40(void) +static int DetectByteExtractTest40(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2145,7 +2136,7 @@ int DetectByteExtractTest40(void) return result; } -int DetectByteExtractTest41(void) +static int DetectByteExtractTest41(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2246,7 +2237,7 @@ int DetectByteExtractTest41(void) return result; } -int DetectByteExtractTest42(void) +static int DetectByteExtractTest42(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2397,7 +2388,7 @@ int DetectByteExtractTest42(void) return result; } -int DetectByteExtractTest43(void) +static int DetectByteExtractTest43(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2495,7 +2486,7 @@ int DetectByteExtractTest43(void) return result; } -int DetectByteExtractTest44(void) +static int DetectByteExtractTest44(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2618,7 +2609,7 @@ int DetectByteExtractTest44(void) return result; } -int DetectByteExtractTest45(void) +static int DetectByteExtractTest45(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2717,7 +2708,7 @@ int DetectByteExtractTest45(void) return result; } -int DetectByteExtractTest46(void) +static int DetectByteExtractTest46(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2840,7 +2831,7 @@ int DetectByteExtractTest46(void) return result; } -int DetectByteExtractTest47(void) +static int DetectByteExtractTest47(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2940,7 +2931,7 @@ int DetectByteExtractTest47(void) return result; } -int DetectByteExtractTest48(void) +static int DetectByteExtractTest48(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3068,7 +3059,7 @@ int DetectByteExtractTest48(void) return result; } -int DetectByteExtractTest49(void) +static int DetectByteExtractTest49(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3169,7 +3160,7 @@ int DetectByteExtractTest49(void) return result; } -int DetectByteExtractTest50(void) +static int DetectByteExtractTest50(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3299,7 +3290,7 @@ int DetectByteExtractTest50(void) return result; } -int DetectByteExtractTest51(void) +static int DetectByteExtractTest51(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3397,7 +3388,7 @@ int DetectByteExtractTest51(void) return result; } -int DetectByteExtractTest52(void) +static int DetectByteExtractTest52(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3518,7 +3509,7 @@ int DetectByteExtractTest52(void) return result; } -int DetectByteExtractTest53(void) +static int DetectByteExtractTest53(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3615,7 +3606,7 @@ int DetectByteExtractTest53(void) return result; } -int DetectByteExtractTest54(void) +static int DetectByteExtractTest54(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3733,7 +3724,7 @@ int DetectByteExtractTest54(void) return result; } -int DetectByteExtractTest55(void) +static int DetectByteExtractTest55(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3847,7 +3838,7 @@ int DetectByteExtractTest55(void) return result; } -int DetectByteExtractTest56(void) +static int DetectByteExtractTest56(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3995,7 +3986,7 @@ int DetectByteExtractTest56(void) return result; } -int DetectByteExtractTest57(void) +static int DetectByteExtractTest57(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -4160,7 +4151,7 @@ int DetectByteExtractTest57(void) return result; } -int DetectByteExtractTest58(void) +static int DetectByteExtractTest58(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -4293,7 +4284,7 @@ int DetectByteExtractTest58(void) return result; } -int DetectByteExtractTest59(void) +static int DetectByteExtractTest59(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -4427,7 +4418,7 @@ int DetectByteExtractTest59(void) return result; } -int DetectByteExtractTest60(void) +static int DetectByteExtractTest60(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -4570,7 +4561,7 @@ int DetectByteExtractTest60(void) return result; } -int DetectByteExtractTest61(void) +static int DetectByteExtractTest61(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -4765,7 +4756,7 @@ static int DetectByteExtractTest62(void) return result; } -int DetectByteExtractTest63(void) +static int DetectByteExtractTest63(void) { int result = 0; @@ -4791,7 +4782,7 @@ int DetectByteExtractTest63(void) return result; } -int DetectByteExtractTestParseNoBase(void) +static int DetectByteExtractTestParseNoBase(void) { int result = 0; @@ -4833,7 +4824,7 @@ int DetectByteExtractTestParseNoBase(void) #endif /* UNITTESTS */ -void DetectByteExtractRegisterTests(void) +static void DetectByteExtractRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectByteExtractTest01", DetectByteExtractTest01); diff --git a/src/detect-byte-extract.h b/src/detect-byte-extract.h index 506b1eb773ce..799d35627be2 100644 --- a/src/detect-byte-extract.h +++ b/src/detect-byte-extract.h @@ -60,10 +60,7 @@ typedef struct DetectByteExtractData_ { } DetectByteExtractData; void DetectByteExtractRegister(void); -int DetectByteExtractSetup(DetectEngineCtx *, Signature *, char *); -void DetectByteExtractFree(void *); -int DetectByteExtractMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatch *); + SigMatch *DetectByteExtractRetrieveSMVar(const char *, const Signature *); int DetectByteExtractDoMatch(DetectEngineThreadCtx *, const SigMatch *, const Signature *, uint8_t *, uint16_t, uint64_t *, uint8_t); diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index ebdd3c35f060..78647159016e 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -60,7 +60,12 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -void DetectBytejumpRegisterTests(void); +static int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx); +static DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset); +static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr); +static void DetectBytejumpFree(void *ptr); +static void DetectBytejumpRegisterTests(void); void DetectBytejumpRegister (void) { @@ -196,7 +201,7 @@ int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, SCReturnInt(1); } -int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, +static int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectBytejumpData *data = (const DetectBytejumpData *)ctx; @@ -306,7 +311,7 @@ int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, return 1; } -DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset) +static DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset) { DetectBytejumpData *data = NULL; char args[10][64]; @@ -500,7 +505,7 @@ DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset) return NULL; } -int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) +static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { SigMatch *sm = NULL; SigMatch *prev_pm = NULL; @@ -721,7 +726,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) * * \param data pointer to DetectBytejumpData */ -void DetectBytejumpFree(void *ptr) +static void DetectBytejumpFree(void *ptr) { if (ptr == NULL) return; @@ -738,7 +743,7 @@ void DetectBytejumpFree(void *ptr) * \test DetectBytejumpTestParse01 is a test to make sure that we return * "something" when given valid bytejump opt */ -int DetectBytejumpTestParse01(void) +static int DetectBytejumpTestParse01(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -754,7 +759,7 @@ int DetectBytejumpTestParse01(void) /** * \test DetectBytejumpTestParse02 is a test for setting the required opts */ -int DetectBytejumpTestParse02(void) +static int DetectBytejumpTestParse02(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -778,7 +783,7 @@ int DetectBytejumpTestParse02(void) /** * \test DetectBytejumpTestParse03 is a test for setting the optional flags */ -int DetectBytejumpTestParse03(void) +static int DetectBytejumpTestParse03(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -810,7 +815,7 @@ int DetectBytejumpTestParse03(void) * * \todo This fails becuase we can only have 9 captures and there are 10. */ -int DetectBytejumpTestParse04(void) +static int DetectBytejumpTestParse04(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -840,7 +845,7 @@ int DetectBytejumpTestParse04(void) /** * \test DetectBytejumpTestParse05 is a test for setting base without string */ -int DetectBytejumpTestParse05(void) +static int DetectBytejumpTestParse05(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -856,7 +861,7 @@ int DetectBytejumpTestParse05(void) /** * \test DetectBytejumpTestParse06 is a test for too many bytes to extract */ -int DetectBytejumpTestParse06(void) +static int DetectBytejumpTestParse06(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -871,7 +876,7 @@ int DetectBytejumpTestParse06(void) /** * \test DetectBytejumpTestParse07 is a test for too many string bytes to extract */ -int DetectBytejumpTestParse07(void) +static int DetectBytejumpTestParse07(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -886,7 +891,7 @@ int DetectBytejumpTestParse07(void) /** * \test DetectBytejumpTestParse08 is a test for offset too big */ -int DetectBytejumpTestParse08(void) +static int DetectBytejumpTestParse08(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -901,7 +906,7 @@ int DetectBytejumpTestParse08(void) /** * \test Test dce option. */ -int DetectBytejumpTestParse09(void) +static int DetectBytejumpTestParse09(void) { Signature *s = SigAlloc(); if (s == NULL) @@ -934,7 +939,7 @@ int DetectBytejumpTestParse09(void) /** * \test Test dce option. */ -int DetectBytejumpTestParse10(void) +static int DetectBytejumpTestParse10(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1038,7 +1043,7 @@ int DetectBytejumpTestParse10(void) /** * \test Test dce option. */ -int DetectBytejumpTestParse11(void) +static int DetectBytejumpTestParse11(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1189,7 +1194,7 @@ static int DetectBytejumpTestParse12(void) * byte_jump and byte_jump relative works if the previous keyword is pcre * (bug 142) */ -int DetectByteJumpTestPacket01 (void) +static int DetectByteJumpTestPacket01 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" @@ -1221,7 +1226,7 @@ int DetectByteJumpTestPacket01 (void) * byte_jump and byte_jump relative works if the previous keyword is byte_jump * (bug 165) */ -int DetectByteJumpTestPacket02 (void) +static int DetectByteJumpTestPacket02 (void) { int result = 0; uint8_t buf[] = { 0x00, 0x00, 0x00, 0x77, 0xff, 0x53, @@ -1249,7 +1254,7 @@ int DetectByteJumpTestPacket02 (void) return result; } -int DetectByteJumpTestPacket03(void) +static int DetectByteJumpTestPacket03(void) { int result = 0; uint8_t *buf = NULL; @@ -1284,7 +1289,7 @@ int DetectByteJumpTestPacket03(void) /** * \test check matches of with from_beginning (bug 626/627) */ -int DetectByteJumpTestPacket04 (void) +static int DetectByteJumpTestPacket04 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XYZ04abcdABCD"; @@ -1307,7 +1312,7 @@ int DetectByteJumpTestPacket04 (void) /** * \test check matches of with from_beginning (bug 626/627) */ -int DetectByteJumpTestPacket05 (void) +static int DetectByteJumpTestPacket05 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XYZ04abcdABCD"; @@ -1330,7 +1335,7 @@ int DetectByteJumpTestPacket05 (void) /** * \test check matches of with from_beginning (bug 626/627) */ -int DetectByteJumpTestPacket06 (void) +static int DetectByteJumpTestPacket06 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XX04abcdABCD"; @@ -1353,7 +1358,7 @@ int DetectByteJumpTestPacket06 (void) /** * \test check matches of with from_beginning (bug 626/627) */ -int DetectByteJumpTestPacket07 (void) +static int DetectByteJumpTestPacket07 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XX04abcdABCD"; @@ -1379,7 +1384,7 @@ int DetectByteJumpTestPacket07 (void) /** * \brief this function registers unit tests for DetectBytejump */ -void DetectBytejumpRegisterTests(void) +static void DetectBytejumpRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01); diff --git a/src/detect-bytejump.h b/src/detect-bytejump.h index d88d8c82da14..42bda26299b7 100644 --- a/src/detect-bytejump.h +++ b/src/detect-bytejump.h @@ -58,43 +58,6 @@ typedef struct DetectBytejumpData_ { */ void DetectBytejumpRegister (void); -/** - * This function is used to add the parsed byte_jump data - * into the current signature. - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param optstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -int DetectBytejumpSetup(DetectEngineCtx *, Signature *, char *); - -/** - * \brief this function will free memory associated with DetectBytejumpData - * - * \param data pointer to DetectBytejumpData - */ -void DetectBytejumpFree(void *ptr); - -/** - * This function is used to parse byte_jump options passed via - * - * byte_jump: bytes, offset [,flags [, ...]] - * - * flags: "big", "little", "relative", "string", "oct", "dec", "hex" - * "align", "from beginning", "multiplier N", "post_offset N" - * - * \param optstr Pointer to the user provided byte_jump options - * \param offset Used to pass the offset back, if byte_jump uses a byte_extract - * var. - * - * \retval data pointer to DetectBytejumpData on success - * \retval NULL on failure - */ -DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset); - /** * This function is used to match byte_jump * @@ -112,8 +75,6 @@ DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset); * does: if (DetectBytejumpMatch(...)) { match }, then they catch an * error as a match. */ -int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx); int DetectBytejumpDoMatch(DetectEngineThreadCtx *, const Signature *, const SigMatchCtx *, uint8_t *, uint32_t, uint8_t, int32_t); diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index a6f08b642da6..ae14b3430e33 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -62,7 +62,11 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -void DetectBytetestRegisterTests(void); +static int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx); +static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr); +static void DetectBytetestFree(void *ptr); +static void DetectBytetestRegisterTests(void); void DetectBytetestRegister (void) { @@ -232,14 +236,14 @@ int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, } -int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, +static int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { return DetectBytetestDoMatch(det_ctx, s, ctx, p->payload, p->payload_len, ((DetectBytetestData *)ctx)->flags, 0, 0); } -DetectBytetestData *DetectBytetestParse(char *optstr, char **value, char **offset) +static DetectBytetestData *DetectBytetestParse(char *optstr, char **value, char **offset) { DetectBytetestData *data = NULL; char *args[9] = { @@ -427,7 +431,7 @@ DetectBytetestData *DetectBytetestParse(char *optstr, char **value, char **offse return NULL; } -int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) +static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { SigMatch *sm = NULL; SigMatch *prev_pm = NULL; @@ -659,7 +663,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) * * \param data pointer to DetectBytetestData */ -void DetectBytetestFree(void *ptr) +static void DetectBytetestFree(void *ptr) { if (ptr == NULL) return; @@ -676,7 +680,7 @@ void DetectBytetestFree(void *ptr) * \test DetectBytetestTestParse01 is a test to make sure that we return "something" * when given valid bytetest opt */ -int DetectBytetestTestParse01(void) +static int DetectBytetestTestParse01(void) { int result = 0; DetectBytetestData *data = NULL; @@ -692,7 +696,7 @@ int DetectBytetestTestParse01(void) /** * \test DetectBytetestTestParse02 is a test for setting the required opts */ -int DetectBytetestTestParse02(void) +static int DetectBytetestTestParse02(void) { int result = 0; DetectBytetestData *data = NULL; @@ -716,7 +720,7 @@ int DetectBytetestTestParse02(void) /** * \test DetectBytetestTestParse03 is a test for setting the relative flag */ -int DetectBytetestTestParse03(void) +static int DetectBytetestTestParse03(void) { int result = 0; DetectBytetestData *data = NULL; @@ -741,7 +745,7 @@ int DetectBytetestTestParse03(void) /** * \test DetectBytetestTestParse04 is a test for setting the string/oct flags */ -int DetectBytetestTestParse04(void) +static int DetectBytetestTestParse04(void) { int result = 0; DetectBytetestData *data = NULL; @@ -766,7 +770,7 @@ int DetectBytetestTestParse04(void) /** * \test DetectBytetestTestParse05 is a test for setting the string/dec flags */ -int DetectBytetestTestParse05(void) +static int DetectBytetestTestParse05(void) { int result = 0; DetectBytetestData *data = NULL; @@ -790,7 +794,7 @@ int DetectBytetestTestParse05(void) /** * \test DetectBytetestTestParse06 is a test for setting the string/hex flags */ -int DetectBytetestTestParse06(void) +static int DetectBytetestTestParse06(void) { int result = 0; DetectBytetestData *data = NULL; @@ -814,7 +818,7 @@ int DetectBytetestTestParse06(void) /** * \test DetectBytetestTestParse07 is a test for setting the big flag */ -int DetectBytetestTestParse07(void) +static int DetectBytetestTestParse07(void) { int result = 0; DetectBytetestData *data = NULL; @@ -838,7 +842,7 @@ int DetectBytetestTestParse07(void) /** * \test DetectBytetestTestParse08 is a test for setting the little flag */ -int DetectBytetestTestParse08(void) +static int DetectBytetestTestParse08(void) { int result = 0; DetectBytetestData *data = NULL; @@ -862,7 +866,7 @@ int DetectBytetestTestParse08(void) /** * \test DetectBytetestTestParse09 is a test for neg operator only */ -int DetectBytetestTestParse09(void) +static int DetectBytetestTestParse09(void) { int result = 0; DetectBytetestData *data = NULL; @@ -886,7 +890,7 @@ int DetectBytetestTestParse09(void) /** * \test DetectBytetestTestParse10 is a test for whitespace */ -int DetectBytetestTestParse10(void) +static int DetectBytetestTestParse10(void) { int result = 0; DetectBytetestData *data = NULL; @@ -910,7 +914,7 @@ int DetectBytetestTestParse10(void) /** * \test DetectBytetestTestParse11 is a test for whitespace */ -int DetectBytetestTestParse11(void) +static int DetectBytetestTestParse11(void) { int result = 0; DetectBytetestData *data = NULL; @@ -937,7 +941,7 @@ int DetectBytetestTestParse11(void) /** * \test DetectBytetestTestParse12 is a test for hex w/o string */ -int DetectBytetestTestParse12(void) +static int DetectBytetestTestParse12(void) { int result = 0; DetectBytetestData *data = NULL; @@ -952,7 +956,7 @@ int DetectBytetestTestParse12(void) /** * \test DetectBytetestTestParse13 is a test for too many bytes to extract */ -int DetectBytetestTestParse13(void) +static int DetectBytetestTestParse13(void) { int result = 0; DetectBytetestData *data = NULL; @@ -967,7 +971,7 @@ int DetectBytetestTestParse13(void) /** * \test DetectBytetestTestParse14 is a test for large string extraction */ -int DetectBytetestTestParse14(void) +static int DetectBytetestTestParse14(void) { int result = 0; DetectBytetestData *data = NULL; @@ -991,7 +995,7 @@ int DetectBytetestTestParse14(void) /** * \test DetectBytetestTestParse15 is a test for too many bytes to extract (string) */ -int DetectBytetestTestParse15(void) +static int DetectBytetestTestParse15(void) { int result = 0; DetectBytetestData *data = NULL; @@ -1006,7 +1010,7 @@ int DetectBytetestTestParse15(void) /** * \test DetectBytetestTestParse16 is a test for offset too big */ -int DetectBytetestTestParse16(void) +static int DetectBytetestTestParse16(void) { int result = 0; DetectBytetestData *data = NULL; @@ -1021,7 +1025,7 @@ int DetectBytetestTestParse16(void) /** * \test Test dce option. */ -int DetectBytetestTestParse17(void) +static int DetectBytetestTestParse17(void) { int result = 0; DetectBytetestData *data = NULL; @@ -1043,7 +1047,7 @@ int DetectBytetestTestParse17(void) /** * \test Test dce option. */ -int DetectBytetestTestParse18(void) +static int DetectBytetestTestParse18(void) { int result = 0; DetectBytetestData *data = NULL; @@ -1065,7 +1069,7 @@ int DetectBytetestTestParse18(void) /** * \test Test dce option. */ -int DetectBytetestTestParse19(void) +static int DetectBytetestTestParse19(void) { Signature *s = SigAlloc(); if (s == NULL) @@ -1090,7 +1094,7 @@ int DetectBytetestTestParse19(void) /** * \test Test dce option. */ -int DetectBytetestTestParse20(void) +static int DetectBytetestTestParse20(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1194,7 +1198,7 @@ int DetectBytetestTestParse20(void) /** * \test Test dce option. */ -int DetectBytetestTestParse21(void) +static int DetectBytetestTestParse21(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1370,7 +1374,7 @@ static int DetectBytetestTestParse22(void) * byte_test and byte_test relative works if the previous keyword is pcre * (bug 142) */ -int DetectByteTestTestPacket01 (void) +static int DetectByteTestTestPacket01 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" @@ -1402,7 +1406,7 @@ int DetectByteTestTestPacket01 (void) * byte_test and byte_test relative works if the previous keyword is byte_jump * (bug 158) */ -int DetectByteTestTestPacket02 (void) +static int DetectByteTestTestPacket02 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" @@ -1429,7 +1433,7 @@ int DetectByteTestTestPacket02 (void) return result; } -int DetectByteTestTestPacket03(void) +static int DetectByteTestTestPacket03(void) { int result = 0; uint8_t *buf = NULL; @@ -1460,7 +1464,7 @@ int DetectByteTestTestPacket03(void) } /** \test Test the byte_test signature matching with operator <= */ -int DetectByteTestTestPacket04(void) +static int DetectByteTestTestPacket04(void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" @@ -1490,7 +1494,7 @@ int DetectByteTestTestPacket04(void) } /** \test Test the byte_test signature matching with operator >= */ -int DetectByteTestTestPacket05(void) +static int DetectByteTestTestPacket05(void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" @@ -1525,7 +1529,7 @@ int DetectByteTestTestPacket05(void) /** * \brief this function registers unit tests for DetectBytetest */ -void DetectBytetestRegisterTests(void) +static void DetectBytetestRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectBytetestTestParse01", DetectBytetestTestParse01); @@ -1543,6 +1547,7 @@ void DetectBytetestRegisterTests(void) UtRegisterTest("DetectBytetestTestParse13", DetectBytetestTestParse13); UtRegisterTest("DetectBytetestTestParse14", DetectBytetestTestParse14); UtRegisterTest("DetectBytetestTestParse15", DetectBytetestTestParse15); + UtRegisterTest("DetectBytetestTestParse16", DetectBytetestTestParse16); UtRegisterTest("DetectBytetestTestParse17", DetectBytetestTestParse17); UtRegisterTest("DetectBytetestTestParse18", DetectBytetestTestParse18); UtRegisterTest("DetectBytetestTestParse19", DetectBytetestTestParse19); diff --git a/src/detect-bytetest.h b/src/detect-bytetest.h index 261c30be7070..d55a47f304a5 100644 --- a/src/detect-bytetest.h +++ b/src/detect-bytetest.h @@ -67,61 +67,6 @@ typedef struct DetectBytetestData_ { */ void DetectBytetestRegister (void); -/** - * This function is used to add the parsed byte_test data - * into the current signature. - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param optstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -int DetectBytetestSetup(DetectEngineCtx *, Signature *, char *); - -/** - * \brief this function will free memory associated with DetectBytetestData - * - * \param data pointer to DetectBytetestData - */ -void DetectBytetestFree(void *ptr); - -/** - * This function is used to parse byte_test options passed via - * - * byte_test: bytes, [!]op, value, offset [,flags [, ...]] - * - * flags: "big", "little", "relative", "string", "oct", "dec", "hex" - * - * \param optstr Pointer to the user provided byte_test options - * \param value Used to pass the value back, if byte_test uses a byte_extract - * var. - * \param offset Used to pass the offset back, if byte_test uses a byte_extract - * var. - * - * \retval data pointer to DetectBytetestData on success - * \retval NULL on failure - */ -DetectBytetestData *DetectBytetestParse(char *optstr, char **value, - char **offset); - -/** - * This function is used to match byte_test - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectBytetestData - * - * \retval -1 error - * \retval 0 no match - * \retval 1 match - * - * \todo The return seems backwards. We should return a non-zero error code. One of the error codes is "no match". As-is if someone accidentally does: if (DetectBytetestMatch(...)) { match }, then they catch an error as a match. - */ -int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx); int DetectBytetestDoMatch(DetectEngineThreadCtx *, const Signature *, const SigMatchCtx *ctx, uint8_t *, uint32_t, uint8_t, int32_t, uint64_t); diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c index 091e37713263..68a0a96d1ec2 100644 --- a/src/detect-cipservice.c +++ b/src/detect-cipservice.c @@ -242,7 +242,7 @@ static int DetectCipServiceSetup(DetectEngineCtx *de_ctx, Signature *s, * * \param ptr pointer to DetectCipServiceData */ -void DetectCipServiceFree(void *ptr) +static void DetectCipServiceFree(void *ptr) { DetectCipServiceData *cipserviced = (DetectCipServiceData *) ptr; SCFree(cipserviced); @@ -281,7 +281,7 @@ static int DetectCipServiceSignatureTest01 (void) /** * \brief this function registers unit tests for DetectCipService */ -void DetectCipServiceRegisterTests(void) +static void DetectCipServiceRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectCipServiceParseTest01", @@ -416,7 +416,7 @@ static int DetectEnipCommandSetup(DetectEngineCtx *de_ctx, Signature *s, * * \param ptr pointer to DetectEnipCommandData */ -void DetectEnipCommandFree(void *ptr) +static void DetectEnipCommandFree(void *ptr) { DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *) ptr; SCFree(enipcmdd); @@ -460,7 +460,7 @@ static int DetectEnipCommandSignatureTest01 (void) /** * \brief this function registers unit tests for DetectEnipCommand */ -void DetectEnipCommandRegisterTests(void) +static void DetectEnipCommandRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEnipCommandParseTest01", diff --git a/src/detect-cipservice.h b/src/detect-cipservice.h index 50bd9de6f143..fc6c5aaf7004 100644 --- a/src/detect-cipservice.h +++ b/src/detect-cipservice.h @@ -92,9 +92,4 @@ typedef struct ENIPData_ } ENIPData; -/** - * Add new CIPServiceData node to link list - */ -CIPServiceData *CreateCIPServiceData(ENIPData *enip_data); - #endif /* _DETECT_CIPSERVICE_H */ diff --git a/src/detect-classtype.c b/src/detect-classtype.c index 547f3a0f3ff6..edf555516351 100644 --- a/src/detect-classtype.c +++ b/src/detect-classtype.c @@ -43,7 +43,7 @@ static pcre *regex = NULL; static pcre_extra *regex_study = NULL; static int DetectClasstypeSetup(DetectEngineCtx *, Signature *, char *); -void DetectClasstypeRegisterTests(void); +static void DetectClasstypeRegisterTests(void); /** * \brief Registers the handler functions for the "Classtype" keyword. @@ -153,7 +153,7 @@ static int DetectClasstypeSetup(DetectEngineCtx *de_ctx, Signature *s, char *raw * \test Check that supplying an invalid classtype in the rule, results in the * rule being invalidated. */ -int DetectClasstypeTest01() +static int DetectClasstypeTest01() { int result = 0; @@ -182,7 +182,7 @@ int DetectClasstypeTest01() * properly, with rules containing invalid classtypes being rejected * and the ones containing valid classtypes parsed and returned. */ -int DetectClasstypeTest02() +static int DetectClasstypeTest02() { int result = 0; Signature *last = NULL; @@ -248,7 +248,7 @@ int DetectClasstypeTest02() * \test Check that the signatures are assigned priority based on classtype they * are given. */ -int DetectClasstypeTest03() +static int DetectClasstypeTest03() { int result = 0; Signature *last = NULL; @@ -308,7 +308,7 @@ int DetectClasstypeTest03() /** * \brief This function registers unit tests for Classification Config API. */ -void DetectClasstypeRegisterTests(void) +static void DetectClasstypeRegisterTests(void) { #ifdef UNITTESTS diff --git a/src/detect-content.c b/src/detect-content.c index 9b990a940512..be0d054a2099 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -48,9 +48,7 @@ #include "host.h" #include "util-profiling.h" -int DetectContentMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); -int DetectContentSetup(DetectEngineCtx *, Signature *, char *); -void DetectContentRegisterTests(void); +static void DetectContentRegisterTests(void); void DetectContentRegister (void) { @@ -438,7 +436,7 @@ void DetectContentFree(void *ptr) /** * \test DetectCotentParseTest01 this is a test to make sure we can deal with escaped colons */ -int DetectContentParseTest01 (void) +static int DetectContentParseTest01 (void) { int result = 1; DetectContentData *cd = NULL; @@ -469,7 +467,7 @@ int DetectContentParseTest01 (void) /** * \test DetectCotentParseTest02 this is a test to make sure we can deal with escaped semi-colons */ -int DetectContentParseTest02 (void) +static int DetectContentParseTest02 (void) { int result = 1; DetectContentData *cd = NULL; @@ -500,7 +498,7 @@ int DetectContentParseTest02 (void) /** * \test DetectCotentParseTest03 this is a test to make sure we can deal with escaped double-quotes */ -int DetectContentParseTest03 (void) +static int DetectContentParseTest03 (void) { int result = 1; DetectContentData *cd = NULL; @@ -531,7 +529,7 @@ int DetectContentParseTest03 (void) /** * \test DetectCotentParseTest04 this is a test to make sure we can deal with escaped backslashes */ -int DetectContentParseTest04 (void) +static int DetectContentParseTest04 (void) { int result = 1; DetectContentData *cd = NULL; @@ -563,7 +561,7 @@ int DetectContentParseTest04 (void) /** * \test DetectCotentParseTest05 test illegal escape */ -int DetectContentParseTest05 (void) +static int DetectContentParseTest05 (void) { int result = 1; DetectContentData *cd = NULL; @@ -588,7 +586,7 @@ int DetectContentParseTest05 (void) /** * \test DetectCotentParseTest06 test a binary content */ -int DetectContentParseTest06 (void) +static int DetectContentParseTest06 (void) { int result = 1; DetectContentData *cd = NULL; @@ -620,7 +618,7 @@ int DetectContentParseTest06 (void) /** * \test DetectCotentParseTest07 test an empty content */ -int DetectContentParseTest07 (void) +static int DetectContentParseTest07 (void) { int result = 1; DetectContentData *cd = NULL; @@ -643,7 +641,7 @@ int DetectContentParseTest07 (void) /** * \test DetectCotentParseTest08 test an empty content */ -int DetectContentParseTest08 (void) +static int DetectContentParseTest08 (void) { int result = 1; DetectContentData *cd = NULL; @@ -672,7 +670,7 @@ int DetectContentParseTest08 (void) * \retval return 1 if match * \retval return 0 if not */ -int DetectContentLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, char *sig, +static int DetectContentLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, char *sig, uint32_t sid) { int result = 0; @@ -744,7 +742,7 @@ int DetectContentLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, ch /** * \brief Wrapper for DetectContentLongPatternMatchTest */ -int DetectContentLongPatternMatchTestWrp(char *sig, uint32_t sid) +static int DetectContentLongPatternMatchTestWrp(char *sig, uint32_t sid) { /** Real packet with the following tcp data: * "Hi, this is a big test to check content matches of splitted" @@ -779,7 +777,7 @@ int DetectContentLongPatternMatchTestWrp(char *sig, uint32_t sid) /** * \test Check if we match a normal pattern (not splitted) */ -int DetectContentLongPatternMatchTest01() +static int DetectContentLongPatternMatchTest01() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"Hi, this is a big test\"; sid:1;)"; @@ -789,7 +787,7 @@ int DetectContentLongPatternMatchTest01() /** * \test Check if we match a splitted pattern */ -int DetectContentLongPatternMatchTest02() +static int DetectContentLongPatternMatchTest02() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"Hi, this is a big test to check content matches of" @@ -801,7 +799,7 @@ int DetectContentLongPatternMatchTest02() * \test Check that we don't match the signature if one of the splitted * chunks doesn't match the packet */ -int DetectContentLongPatternMatchTest03() +static int DetectContentLongPatternMatchTest03() { /** The last chunk of the content should not match */ char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" @@ -813,7 +811,7 @@ int DetectContentLongPatternMatchTest03() /** * \test Check if we match multiple content (not splitted) */ -int DetectContentLongPatternMatchTest04() +static int DetectContentLongPatternMatchTest04() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is\"; depth:15 ;content:\"a big test\"; " @@ -829,7 +827,7 @@ int DetectContentLongPatternMatchTest04() * Here we should specify only contents that fit in 32 bytes * Each of them with their modifier values */ -int DetectContentLongPatternMatchTest05() +static int DetectContentLongPatternMatchTest05() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is a big\"; depth:17; " @@ -849,7 +847,7 @@ int DetectContentLongPatternMatchTest05() * Here we should specify contents that fit and contents that must be splitted * Each of them with their modifier values */ -int DetectContentLongPatternMatchTest06() +static int DetectContentLongPatternMatchTest06() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is a big test to check cont\"; depth:36;" @@ -865,7 +863,7 @@ int DetectContentLongPatternMatchTest06() * \test Check if we match contents that are in the payload * but not in the same order as specified in the signature */ -int DetectContentLongPatternMatchTest07() +static int DetectContentLongPatternMatchTest07() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"chunks!\"; " @@ -880,7 +878,7 @@ int DetectContentLongPatternMatchTest07() * \test Check if we match contents that are in the payload * but not in the same order as specified in the signature */ -int DetectContentLongPatternMatchTest08() +static int DetectContentLongPatternMatchTest08() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"ent matches\"; " @@ -896,7 +894,7 @@ int DetectContentLongPatternMatchTest08() * \test Check if we match contents that are in the payload * but not in the same order as specified in the signature */ -int DetectContentLongPatternMatchTest09() +static int DetectContentLongPatternMatchTest09() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"ent matches\"; " @@ -912,7 +910,7 @@ int DetectContentLongPatternMatchTest09() /** * \test Check if we match two consecutive simple contents */ -int DetectContentLongPatternMatchTest10() +static int DetectContentLongPatternMatchTest10() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is a big test to check \"; " @@ -924,7 +922,7 @@ int DetectContentLongPatternMatchTest10() /** * \test Check if we match two contents of length 1 */ -int DetectContentLongPatternMatchTest11() +static int DetectContentLongPatternMatchTest11() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"H\"; " @@ -933,7 +931,7 @@ int DetectContentLongPatternMatchTest11() return DetectContentLongPatternMatchTestWrp(sig, 1); } -int DetectContentParseTest09(void) +static int DetectContentParseTest09(void) { int result = 0; DetectContentData *cd = NULL; @@ -954,7 +952,7 @@ int DetectContentParseTest09(void) return result; } -int DetectContentParseTest10(void) +static int DetectContentParseTest10(void) { int result = 0; DetectContentData *cd = NULL; @@ -975,7 +973,7 @@ int DetectContentParseTest10(void) return result; } -int DetectContentParseNegTest11(void) +static int DetectContentParseNegTest11(void) { int result = 0; DetectContentData *cd = NULL; @@ -996,7 +994,7 @@ int DetectContentParseNegTest11(void) return result; } -int DetectContentParseNegTest12(void) +static int DetectContentParseNegTest12(void) { int result = 0; DetectContentData *cd = NULL; @@ -1017,7 +1015,7 @@ int DetectContentParseNegTest12(void) return result; } -int DetectContentParseNegTest13(void) +static int DetectContentParseNegTest13(void) { int result = 0; DetectContentData *cd = NULL; @@ -1038,7 +1036,7 @@ int DetectContentParseNegTest13(void) return result; } -int DetectContentParseNegTest14(void) +static int DetectContentParseNegTest14(void) { int result = 0; DetectContentData *cd = NULL; @@ -1059,7 +1057,7 @@ int DetectContentParseNegTest14(void) return result; } -int DetectContentParseNegTest15(void) +static int DetectContentParseNegTest15(void) { int result = 0; DetectContentData *cd = NULL; @@ -1080,7 +1078,7 @@ int DetectContentParseNegTest15(void) return result; } -int DetectContentParseNegTest16(void) +static int DetectContentParseNegTest16(void) { int result = 0; DetectContentData *cd = NULL; @@ -1103,7 +1101,7 @@ int DetectContentParseNegTest16(void) * \test Test cases where if within specified is < content lenggth we invalidate * the sig. */ -int DetectContentParseTest17(void) +static int DetectContentParseTest17(void) { int result = 0; char *sigstr = "alert tcp any any -> any any (msg:\"Dummy\"; " @@ -1129,7 +1127,7 @@ int DetectContentParseTest17(void) /** * \test Test content for dce sig. */ -int DetectContentParseTest18(void) +static int DetectContentParseTest18(void) { Signature *s = SigAlloc(); int result = 1; @@ -1164,7 +1162,7 @@ int DetectContentParseTest18(void) * \test Test content for dce sig. */ -int DetectContentParseTest19(void) +static int DetectContentParseTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1453,7 +1451,7 @@ int DetectContentParseTest19(void) /** * \test Test content for dce sig. */ -int DetectContentParseTest20(void) +static int DetectContentParseTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1482,7 +1480,7 @@ int DetectContentParseTest20(void) /** * \test Parsing test */ -int DetectContentParseTest21(void) +static int DetectContentParseTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1511,7 +1509,7 @@ int DetectContentParseTest21(void) /** * \test Parsing test */ -int DetectContentParseTest22(void) +static int DetectContentParseTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1540,7 +1538,7 @@ int DetectContentParseTest22(void) /** * \test Parsing test */ -int DetectContentParseTest23(void) +static int DetectContentParseTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1569,7 +1567,7 @@ int DetectContentParseTest23(void) /** * \test Parsing test */ -int DetectContentParseTest24(void) +static int DetectContentParseTest24(void) { DetectEngineCtx *de_ctx = NULL; DetectContentData *cd = 0; @@ -1610,7 +1608,7 @@ int DetectContentParseTest24(void) /** * \test Parsing test */ -int DetectContentParseTest25(void) +static int DetectContentParseTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1639,7 +1637,7 @@ int DetectContentParseTest25(void) /** * \test Parsing test */ -int DetectContentParseTest26(void) +static int DetectContentParseTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1668,7 +1666,7 @@ int DetectContentParseTest26(void) /** * \test Parsing test */ -int DetectContentParseTest27(void) +static int DetectContentParseTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1697,7 +1695,7 @@ int DetectContentParseTest27(void) /** * \test Parsing test */ -int DetectContentParseTest28(void) +static int DetectContentParseTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1726,7 +1724,7 @@ int DetectContentParseTest28(void) /** * \test Parsing test */ -int DetectContentParseTest29(void) +static int DetectContentParseTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1755,7 +1753,7 @@ int DetectContentParseTest29(void) /** * \test Parsing test */ -int DetectContentParseTest30(void) +static int DetectContentParseTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1784,7 +1782,7 @@ int DetectContentParseTest30(void) /** * \test Parsing test */ -int DetectContentParseTest31(void) +static int DetectContentParseTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1813,7 +1811,7 @@ int DetectContentParseTest31(void) /** * \test Parsing test */ -int DetectContentParseTest32(void) +static int DetectContentParseTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1842,7 +1840,7 @@ int DetectContentParseTest32(void) /** * \test Parsing test */ -int DetectContentParseTest33(void) +static int DetectContentParseTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1871,7 +1869,7 @@ int DetectContentParseTest33(void) /** * \test Parsing test */ -int DetectContentParseTest34(void) +static int DetectContentParseTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1900,7 +1898,7 @@ int DetectContentParseTest34(void) /** * \test Parsing test */ -int DetectContentParseTest35(void) +static int DetectContentParseTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -2170,7 +2168,7 @@ static int DetectContentParseTest40(void) return result; } -int DetectContentParseTest41(void) +static int DetectContentParseTest41(void) { int result = 1; DetectContentData *cd = NULL; @@ -2205,7 +2203,7 @@ int DetectContentParseTest41(void) /** * Tests that content lengths > 255 are supported. */ -int DetectContentParseTest42(void) +static int DetectContentParseTest42(void) { int result = 1; DetectContentData *cd = NULL; @@ -2237,7 +2235,7 @@ int DetectContentParseTest42(void) return result; } -int DetectContentParseTest43(void) +static int DetectContentParseTest43(void) { int result = 1; DetectContentData *cd = NULL; @@ -2276,7 +2274,7 @@ int DetectContentParseTest43(void) /** * Tests that content lengths > 255 are supported. */ -int DetectContentParseTest44(void) +static int DetectContentParseTest44(void) { int result = 1; DetectContentData *cd = NULL; @@ -2315,7 +2313,7 @@ int DetectContentParseTest44(void) /** * \test Parsing test to check for unescaped quote within content section */ -int DetectContentParseTest45(void) +static int DetectContentParseTest45(void) { DetectEngineCtx *de_ctx = NULL; @@ -2854,7 +2852,7 @@ static int DetectLongContentTest3(void) /** * \brief this function registers unit tests for DetectContent */ -void DetectContentRegisterTests(void) +static void DetectContentRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01); diff --git a/src/detect-csum.c b/src/detect-csum.c index ab5ed748e84c..8d9fcf5959cf 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -43,45 +43,45 @@ static int DetectIPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectIPV4CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectIPV4CsumFree(void *); +static void DetectIPV4CsumFree(void *); /* prototypes for the "tcpv4-csum" rule keyword */ static int DetectTCPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectTCPV4CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectTCPV4CsumFree(void *); +static void DetectTCPV4CsumFree(void *); /* prototypes for the "tcpv6-csum" rule keyword */ static int DetectTCPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectTCPV6CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectTCPV6CsumFree(void *); +static void DetectTCPV6CsumFree(void *); /* prototypes for the "udpv4-csum" rule keyword */ static int DetectUDPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectUDPV4CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectUDPV4CsumFree(void *); +static void DetectUDPV4CsumFree(void *); /* prototypes for the "udpv6-csum" rule keyword */ static int DetectUDPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectUDPV6CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectUDPV6CsumFree(void *); +static void DetectUDPV6CsumFree(void *); /* prototypes for the "icmpv4-csum" rule keyword */ static int DetectICMPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectICMPV4CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectICMPV4CsumFree(void *); +static void DetectICMPV4CsumFree(void *); /* prototypes for the "icmpv6-csum" rule keyword */ static int DetectICMPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectICMPV6CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectICMPV6CsumFree(void *); +static void DetectICMPV6CsumFree(void *); -void DetectCsumRegisterTests(void); +static void DetectCsumRegisterTests(void); /** * \brief Registers handlers for all the checksum keywords. The checksum @@ -298,7 +298,7 @@ static int DetectIPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum return -1; } -void DetectIPV4CsumFree(void *ptr) +static void DetectIPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -393,7 +393,7 @@ static int DetectTCPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu return -1; } -void DetectTCPV4CsumFree(void *ptr) +static void DetectTCPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -488,7 +488,7 @@ static int DetectTCPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu return -1; } -void DetectTCPV6CsumFree(void *ptr) +static void DetectTCPV6CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -584,7 +584,7 @@ static int DetectUDPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu return -1; } -void DetectUDPV4CsumFree(void *ptr) +static void DetectUDPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -680,7 +680,7 @@ static int DetectUDPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu return -1; } -void DetectUDPV6CsumFree(void *ptr) +static void DetectUDPV6CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -775,7 +775,7 @@ static int DetectICMPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *cs return -1; } -void DetectICMPV4CsumFree(void *ptr) +static void DetectICMPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -873,7 +873,7 @@ static int DetectICMPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *cs return -1; } -void DetectICMPV6CsumFree(void *ptr) +static void DetectICMPV6CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -887,7 +887,7 @@ void DetectICMPV6CsumFree(void *ptr) #ifdef UNITTESTS -int DetectCsumIPV4ValidArgsTestParse01(void) +static int DetectCsumIPV4ValidArgsTestParse01(void) { Signature s; int result = 0; @@ -911,7 +911,7 @@ int DetectCsumIPV4ValidArgsTestParse01(void) return result; } -int DetectCsumIPV4InValidArgsTestParse02(void) +static int DetectCsumIPV4InValidArgsTestParse02(void) { Signature s; int result = -1; @@ -935,7 +935,7 @@ int DetectCsumIPV4InValidArgsTestParse02(void) return result; } -int DetectCsumIPV4ValidArgsTestParse03(void) +static int DetectCsumIPV4ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; @@ -974,7 +974,7 @@ int DetectCsumIPV4ValidArgsTestParse03(void) return result; } -int DetectCsumICMPV4ValidArgsTestParse01(void) +static int DetectCsumICMPV4ValidArgsTestParse01(void) { Signature s; int result = 0; @@ -998,7 +998,7 @@ int DetectCsumICMPV4ValidArgsTestParse01(void) return result; } -int DetectCsumICMPV4InValidArgsTestParse02(void) +static int DetectCsumICMPV4InValidArgsTestParse02(void) { Signature s; int result = -1; @@ -1022,7 +1022,7 @@ int DetectCsumICMPV4InValidArgsTestParse02(void) return result; } -int DetectCsumICMPV4ValidArgsTestParse03(void) +static int DetectCsumICMPV4ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; @@ -1061,7 +1061,7 @@ int DetectCsumICMPV4ValidArgsTestParse03(void) return result; } -int DetectCsumTCPV4ValidArgsTestParse01(void) +static int DetectCsumTCPV4ValidArgsTestParse01(void) { Signature s; int result = 0; @@ -1085,7 +1085,7 @@ int DetectCsumTCPV4ValidArgsTestParse01(void) return result; } -int DetectCsumTCPV4InValidArgsTestParse02(void) +static int DetectCsumTCPV4InValidArgsTestParse02(void) { Signature s; int result = -1; @@ -1109,7 +1109,7 @@ int DetectCsumTCPV4InValidArgsTestParse02(void) return result; } -int DetectCsumTCPV4ValidArgsTestParse03(void) +static int DetectCsumTCPV4ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; @@ -1148,7 +1148,7 @@ int DetectCsumTCPV4ValidArgsTestParse03(void) return result; } -int DetectCsumUDPV4ValidArgsTestParse01(void) +static int DetectCsumUDPV4ValidArgsTestParse01(void) { Signature s; int result = 0; @@ -1172,7 +1172,7 @@ int DetectCsumUDPV4ValidArgsTestParse01(void) return result; } -int DetectCsumUDPV4InValidArgsTestParse02(void) +static int DetectCsumUDPV4InValidArgsTestParse02(void) { Signature s; int result = -1; @@ -1196,7 +1196,7 @@ int DetectCsumUDPV4InValidArgsTestParse02(void) return result; } -int DetectCsumUDPV4ValidArgsTestParse03(void) +static int DetectCsumUDPV4ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; @@ -1235,7 +1235,7 @@ int DetectCsumUDPV4ValidArgsTestParse03(void) return result; } -int DetectCsumTCPV6ValidArgsTestParse01(void) +static int DetectCsumTCPV6ValidArgsTestParse01(void) { Signature s; int result = 0; @@ -1259,7 +1259,7 @@ int DetectCsumTCPV6ValidArgsTestParse01(void) return result; } -int DetectCsumTCPV6InValidArgsTestParse02(void) +static int DetectCsumTCPV6InValidArgsTestParse02(void) { Signature s; int result = -1; @@ -1283,7 +1283,7 @@ int DetectCsumTCPV6InValidArgsTestParse02(void) return result; } -int DetectCsumTCPV6ValidArgsTestParse03(void) +static int DetectCsumTCPV6ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; @@ -1322,7 +1322,7 @@ int DetectCsumTCPV6ValidArgsTestParse03(void) return result; } -int DetectCsumUDPV6ValidArgsTestParse01(void) +static int DetectCsumUDPV6ValidArgsTestParse01(void) { Signature s; int result = 0; @@ -1346,7 +1346,7 @@ int DetectCsumUDPV6ValidArgsTestParse01(void) return result; } -int DetectCsumUDPV6InValidArgsTestParse02(void) +static int DetectCsumUDPV6InValidArgsTestParse02(void) { Signature s; int result = -1; @@ -1370,7 +1370,7 @@ int DetectCsumUDPV6InValidArgsTestParse02(void) return result; } -int DetectCsumUDPV6ValidArgsTestParse03(void) +static int DetectCsumUDPV6ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; @@ -1409,7 +1409,7 @@ int DetectCsumUDPV6ValidArgsTestParse03(void) return result; } -int DetectCsumICMPV6ValidArgsTestParse01(void) +static int DetectCsumICMPV6ValidArgsTestParse01(void) { Signature s; int result = 0; @@ -1433,7 +1433,7 @@ int DetectCsumICMPV6ValidArgsTestParse01(void) return result; } -int DetectCsumICMPV6InValidArgsTestParse02(void) +static int DetectCsumICMPV6InValidArgsTestParse02(void) { Signature s; int result = -1; @@ -1457,7 +1457,7 @@ int DetectCsumICMPV6InValidArgsTestParse02(void) return result; } -int DetectCsumICMPV6ValidArgsTestParse03(void) +static int DetectCsumICMPV6ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; @@ -1499,7 +1499,7 @@ int DetectCsumICMPV6ValidArgsTestParse03(void) #include "detect-engine.h" #include "stream-tcp.h" -int DetectCsumICMPV6Test01(void) +static int DetectCsumICMPV6Test01(void) { int result = 0; DetectEngineCtx *de_ctx = NULL; @@ -1587,11 +1587,9 @@ int DetectCsumICMPV6Test01(void) #endif /* UNITTESTS */ -void DetectCsumRegisterTests(void) +static void DetectCsumRegisterTests(void) { - #ifdef UNITTESTS - UtRegisterTest("DetectCsumIPV4ValidArgsTestParse01", DetectCsumIPV4ValidArgsTestParse01); UtRegisterTest("DetectCsumIPV4InValidArgsTestParse02", @@ -1642,8 +1640,5 @@ void DetectCsumRegisterTests(void) DetectCsumICMPV6ValidArgsTestParse03); UtRegisterTest("DetectCsumICMPV6Test01", DetectCsumICMPV6Test01); - - #endif /* UNITTESTS */ - } diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 78c705ce35e9..8513c9f0ce23 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -55,7 +55,8 @@ static pcre_extra *parse_regex_study = NULL; static int DetectDceIfaceMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatch *); static int DetectDceIfaceSetup(DetectEngineCtx *, Signature *, char *); -void DetectDceIfaceFree(void *); +static void DetectDceIfaceFree(void *); +static void DetectDceIfaceRegisterTests(void); /** * \brief Registers the keyword handlers for the "dce_iface" keyword. @@ -83,7 +84,7 @@ void DetectDceIfaceRegister(void) * \retval did Pointer to a DetectDceIfaceData instance that holds the data * from the parsed arg. */ -static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) +static DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) { DetectDceIfaceData *did = NULL; #define MAX_SUBSTRINGS 30 @@ -355,7 +356,7 @@ static int DetectDceIfaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return -1; } -void DetectDceIfaceFree(void *ptr) +static void DetectDceIfaceFree(void *ptr) { SCFree(ptr); @@ -1799,9 +1800,8 @@ static int DetectDceIfaceTestParse15(void) #endif -void DetectDceIfaceRegisterTests(void) +static void DetectDceIfaceRegisterTests(void) { - #ifdef UNITTESTS UtRegisterTest("DetectDceIfaceTestParse01", DetectDceIfaceTestParse01); UtRegisterTest("DetectDceIfaceTestParse02", DetectDceIfaceTestParse02); @@ -1823,6 +1823,4 @@ void DetectDceIfaceRegisterTests(void) UtRegisterTest("DetectDceIfaceTestParse14", DetectDceIfaceTestParse14); UtRegisterTest("DetectDceIfaceTestParse15", DetectDceIfaceTestParse15); #endif - - return; } diff --git a/src/detect-dce-iface.h b/src/detect-dce-iface.h index 6a051b0d433d..564cf5522c0a 100644 --- a/src/detect-dce-iface.h +++ b/src/detect-dce-iface.h @@ -40,6 +40,5 @@ typedef struct DetectDceIfaceData_ { } DetectDceIfaceData; void DetectDceIfaceRegister(void); -void DetectDceIfaceRegisterTests(void); #endif /* __DETECT_DCE_IFACE_H__ */ diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index e1435fba1eaa..d33579aff217 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -55,7 +55,8 @@ static pcre_extra *parse_regex_study = NULL; static int DetectDceOpnumMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatch *); static int DetectDceOpnumSetup(DetectEngineCtx *, Signature *, char *); -void DetectDceOpnumFree(void *); +static void DetectDceOpnumFree(void *); +static void DetectDceOpnumRegisterTests(void); /** * \brief Registers the keyword handlers for the "dce_opnum" keyword. @@ -80,7 +81,7 @@ void DetectDceOpnumRegister(void) * * \retval dor Pointer to the new instance DetectDceOpnumRange. */ -static inline DetectDceOpnumRange *DetectDceOpnumAllocDetectDceOpnumRange(void) +static DetectDceOpnumRange *DetectDceOpnumAllocDetectDceOpnumRange(void) { DetectDceOpnumRange *dor = NULL; @@ -101,7 +102,7 @@ static inline DetectDceOpnumRange *DetectDceOpnumAllocDetectDceOpnumRange(void) * \retval did Pointer to a DetectDceIfaceData instance that holds the data * from the parsed arg. */ -static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) +static DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) { DetectDceOpnumData *dod = NULL; @@ -325,7 +326,7 @@ static int DetectDceOpnumSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return -1; } -void DetectDceOpnumFree(void *ptr) +static void DetectDceOpnumFree(void *ptr) { DetectDceOpnumData *dod = ptr; DetectDceOpnumRange *dor = NULL; @@ -2902,12 +2903,10 @@ static int DetectDceOpnumTestParse13(void) return result; } #endif +#endif /* UNITTESTS */ - -#endif -void DetectDceOpnumRegisterTests(void) +static void DetectDceOpnumRegisterTests(void) { - #ifdef UNITTESTS UtRegisterTest("DetectDceOpnumTestParse01", DetectDceOpnumTestParse01); UtRegisterTest("DetectDceOpnumTestParse02", DetectDceOpnumTestParse02); @@ -2927,6 +2926,4 @@ void DetectDceOpnumRegisterTests(void) UtRegisterTest("DetectDceOpnumTestParse13", DetectDceOpnumTestParse13, 1); #endif #endif - - return; } diff --git a/src/detect-dce-opnum.h b/src/detect-dce-opnum.h index a4c1a9b76d8c..7316ab75f548 100644 --- a/src/detect-dce-opnum.h +++ b/src/detect-dce-opnum.h @@ -38,6 +38,5 @@ typedef struct DetectDceOpnumData_ { } DetectDceOpnumData; void DetectDceOpnumRegister(void); -void DetectDceOpnumRegisterTests(void); #endif /* __DETECT_DCE_OPNUM_H__ */ diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index ea47be1efca9..c9a9b914571a 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -49,9 +49,8 @@ #include "stream-tcp.h" -int DetectDceStubDataMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - void *, Signature *, SigMatch *); static int DetectDceStubDataSetup(DetectEngineCtx *, Signature *, char *); +static void DetectDceStubDataRegisterTests(void); /** * \brief Registers the keyword handlers for the "dce_stub_data" keyword. @@ -1851,7 +1850,7 @@ static int DetectDceStubDataTestParse05(void) #endif -void DetectDceStubDataRegisterTests(void) +static void DetectDceStubDataRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectDceStubDataTestParse01", diff --git a/src/detect-dce-stub-data.h b/src/detect-dce-stub-data.h index adc45388a7ce..80c82145c0e8 100644 --- a/src/detect-dce-stub-data.h +++ b/src/detect-dce-stub-data.h @@ -25,6 +25,5 @@ #define __DETECT_DCE_STUB_DATA_H__ void DetectDceStubDataRegister(void); -void DetectDceStubDataRegisterTests(void); #endif /* __DETECT_DCE_STUB_DATA_H__ */ diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 56a5fad783c9..7960f4526fbc 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -54,8 +54,8 @@ static pcre_extra *parse_regex_study; static int DetectDetectionFilterMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectDetectionFilterSetup(DetectEngineCtx *, Signature *, char *); -void DetectDetectionFilterRegisterTests(void); -void DetectDetectionFilterFree(void *); +static void DetectDetectionFilterRegisterTests(void); +static void DetectDetectionFilterFree(void *); /** * \brief Registration function for detection_filter: keyword @@ -90,7 +90,7 @@ static int DetectDetectionFilterMatch (ThreadVars *thv, DetectEngineThreadCtx *d * \retval df pointer to DetectThresholdData on success * \retval NULL on failure */ -DetectThresholdData *DetectDetectionFilterParse (char *rawstr) +static DetectThresholdData *DetectDetectionFilterParse (char *rawstr) { DetectThresholdData *df = NULL; #define MAX_SUBSTRINGS 30 @@ -207,7 +207,7 @@ DetectThresholdData *DetectDetectionFilterParse (char *rawstr) * \retval 0 on Success * \retval -1 on Failure */ -int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +static int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { SCEnter(); DetectThresholdData *df = NULL; @@ -245,8 +245,10 @@ int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *raw return 0; error: - if (df) SCFree(df); - if (sm) SCFree(sm); + if (df) + SCFree(df); + if (sm) + SCFree(sm); return -1; } @@ -256,10 +258,11 @@ int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *raw * * \param df_ptr pointer to DetectDetectionFilterData */ -void DetectDetectionFilterFree(void *df_ptr) +static void DetectDetectionFilterFree(void *df_ptr) { DetectThresholdData *df = (DetectThresholdData *)df_ptr; - if (df) SCFree(df); + if (df) + SCFree(df); } /* @@ -278,7 +281,7 @@ void DetectDetectionFilterFree(void *df_ptr) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse01 (void) +static int DetectDetectionFilterTestParse01 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("track by_dst,count 10,seconds 60"); @@ -296,7 +299,7 @@ int DetectDetectionFilterTestParse01 (void) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse02 (void) +static int DetectDetectionFilterTestParse02 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("track both,count 10,seconds 60"); @@ -314,7 +317,7 @@ int DetectDetectionFilterTestParse02 (void) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse03 (void) +static int DetectDetectionFilterTestParse03 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("track by_dst, seconds 60, count 10"); @@ -333,7 +336,7 @@ int DetectDetectionFilterTestParse03 (void) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse04 (void) +static int DetectDetectionFilterTestParse04 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("count 10, track by_dst, seconds 60, count 10"); @@ -351,7 +354,7 @@ int DetectDetectionFilterTestParse04 (void) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse05 (void) +static int DetectDetectionFilterTestParse05 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("count 10, track by_dst, seconds 60"); @@ -369,7 +372,7 @@ int DetectDetectionFilterTestParse05 (void) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse06 (void) +static int DetectDetectionFilterTestParse06 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("count 10, track by_dst, seconds 0"); @@ -628,7 +631,7 @@ static int DetectDetectionFilterTestSig3(void) } #endif /* UNITTESTS */ -void DetectDetectionFilterRegisterTests(void) +static void DetectDetectionFilterRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectDetectionFilterTestParse01", diff --git a/src/detect-detection-filter.h b/src/detect-detection-filter.h index 2c74d4f40f87..f136d3aca5f9 100644 --- a/src/detect-detection-filter.h +++ b/src/detect-detection-filter.h @@ -24,21 +24,11 @@ #ifndef __DETECT_DETECTION_FILTER_H__ #define __DETECT_DETECTION_FILTER_H__ -#include "decode-events.h" -#include "decode-ipv4.h" -#include "decode-tcp.h" - /** * Registration function for detection_filter: keyword */ void DetectDetectionFilterRegister (void); -/** - * This function registers unit tests for detection_filter - */ - -void DetectDetectionFilterRegisterTests(void); - #endif /*__DETECT_DETECTION_FILTER_H__ */ diff --git a/src/detect-distance.c b/src/detect-distance.c index 8be8219bab1d..9c91c9447326 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -46,7 +46,7 @@ #include "util-unittest-helper.h" static int DetectDistanceSetup(DetectEngineCtx *, Signature *, char *); -void DetectDistanceRegisterTests(void); +static void DetectDistanceRegisterTests(void); void DetectDistanceRegister(void) { @@ -236,7 +236,7 @@ static int DetectDistanceTest01(void) * distance works, if the previous keyword is byte_jump and content * (bug 163) */ -int DetectDistanceTestPacket01 (void) +static int DetectDistanceTestPacket01 (void) { int result = 0; uint8_t buf[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -260,7 +260,7 @@ int DetectDistanceTestPacket01 (void) } #endif /* UNITTESTS */ -void DetectDistanceRegisterTests(void) +static void DetectDistanceRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectDistanceTest01 -- distance / within mix", diff --git a/src/detect-dsize.c b/src/detect-dsize.c index f07d812204ec..21f85a20a1ea 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -52,7 +52,7 @@ static pcre_extra *parse_regex_study; static int DetectDsizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectDsizeSetup (DetectEngineCtx *, Signature *s, char *str); -void DsizeRegisterTests(void); +static void DsizeRegisterTests(void); static void DetectDsizeFree(void *); static int PrefilterSetupDsize(SigGroupHead *sgh); @@ -866,7 +866,7 @@ int DetectDsizeIcmpv6Test01 (void) /** * \brief this function registers unit tests for dsize */ -void DsizeRegisterTests(void) +static void DsizeRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DsizeTestParse01", DsizeTestParse01); diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index c856408135b0..ad0d1929a519 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -131,7 +131,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, /** * \test Test the working of detection engien with respect to dce keywords. */ -int DcePayloadTest01(void) +static int DcePayloadTest01(void) { #if 0 int result = 0; @@ -1828,7 +1828,7 @@ int DcePayloadTest01(void) /** * \test Test the working of detection engien with respect to dce keywords. */ -int DcePayloadTest02(void) +static int DcePayloadTest02(void) { #if 0 int result = 0; @@ -2280,7 +2280,7 @@ int DcePayloadTest02(void) /** * \test Test the working of detection engien with respect to dce keywords. */ -int DcePayloadTest03(void) +static int DcePayloadTest03(void) { #if 0 int result = 0; @@ -2731,7 +2731,7 @@ int DcePayloadTest03(void) /** * \test Test the working of detection engien with respect to dce keywords. */ -int DcePayloadTest04(void) +static int DcePayloadTest04(void) { #if 0 int result = 0; @@ -3182,7 +3182,7 @@ int DcePayloadTest04(void) /** * \test Test the working of detection engien with respect to dce keywords. */ -int DcePayloadTest05(void) +static int DcePayloadTest05(void) { #if 0 int result = 0; @@ -3632,7 +3632,7 @@ int DcePayloadTest05(void) /** * \test Test the working of detection engien with respect to dce keywords. */ -int DcePayloadTest06(void) +static int DcePayloadTest06(void) { #if 0 int result = 0; @@ -4083,7 +4083,7 @@ int DcePayloadTest06(void) /** * \test Test the working of detection engien with respect to dce keywords. */ -int DcePayloadTest07(void) +static int DcePayloadTest07(void) { #if 0 int result = 0; @@ -4533,7 +4533,7 @@ int DcePayloadTest07(void) /** * \test Positive test, to test the working of distance and within. */ -int DcePayloadTest08(void) +static int DcePayloadTest08(void) { #if 0 int result = 0; @@ -4760,7 +4760,7 @@ int DcePayloadTest08(void) /** * \test Positive test, to test the working of distance and within. */ -int DcePayloadTest09(void) +static int DcePayloadTest09(void) { #if 0 int result = 0; @@ -4987,7 +4987,7 @@ int DcePayloadTest09(void) /** * \test Positive test, to test the working of distance and within. */ -int DcePayloadTest10(void) +static int DcePayloadTest10(void) { #if 0 int result = 0; @@ -5214,7 +5214,7 @@ int DcePayloadTest10(void) /** * \test Postive test to check the working of disance and within across frags. */ -int DcePayloadTest11(void) +static int DcePayloadTest11(void) { #if 0 int result = 0; @@ -5590,7 +5590,7 @@ int DcePayloadTest11(void) * \test Negative test the working of contents on stub data with invalid * distance. */ -int DcePayloadTest12(void) +static int DcePayloadTest12(void) { #if 0 /* payload ticks off clamav */ int result = 0; @@ -5969,7 +5969,7 @@ int DcePayloadTest12(void) /** * \test Test the working of detection engien with respect to dce keywords. */ -int DcePayloadTest13(void) +static int DcePayloadTest13(void) { int result = 0; uint8_t request1[] = { @@ -6236,7 +6236,7 @@ int DcePayloadTest13(void) /** * \test Test the working of detection engien with respect to dce keywords. */ -int DcePayloadTest14(void) +static int DcePayloadTest14(void) { int result = 0; @@ -6464,7 +6464,7 @@ int DcePayloadTest14(void) /** * \test Test the working of byte_test endianness. */ -int DcePayloadTest15(void) +static int DcePayloadTest15(void) { int result = 0; @@ -6581,7 +6581,7 @@ int DcePayloadTest15(void) /** * \test Test the working of byte_test endianness. */ -int DcePayloadTest16(void) +static int DcePayloadTest16(void) { int result = 0; @@ -6698,7 +6698,7 @@ int DcePayloadTest16(void) /** * \test Test the working of byte_test endianness. */ -int DcePayloadTest17(void) +static int DcePayloadTest17(void) { int result = 0; @@ -6815,7 +6815,7 @@ int DcePayloadTest17(void) /** * \test Test the working of byte_jump endianness. */ -int DcePayloadTest18(void) +static int DcePayloadTest18(void) { int result = 0; @@ -6932,7 +6932,7 @@ int DcePayloadTest18(void) /** * \test Test the working of byte_jump endianness. */ -int DcePayloadTest19(void) +static int DcePayloadTest19(void) { int result = 0; @@ -7049,7 +7049,7 @@ int DcePayloadTest19(void) /** * \test Test the working of byte_jump endianness. */ -int DcePayloadTest20(void) +static int DcePayloadTest20(void) { int result = 0; @@ -7166,7 +7166,7 @@ int DcePayloadTest20(void) /** * \test Test the working of consecutive relative matches. */ -int DcePayloadTest21(void) +static int DcePayloadTest21(void) { int result = 0; @@ -7268,7 +7268,7 @@ int DcePayloadTest21(void) /** * \test Test the working of consecutive relative matches. */ -int DcePayloadTest22(void) +static int DcePayloadTest22(void) { int result = 0; @@ -7370,7 +7370,7 @@ int DcePayloadTest22(void) /** * \test Test the working of consecutive relative matches. */ -int DcePayloadTest23(void) +static int DcePayloadTest23(void) { int result = 0; @@ -7473,7 +7473,7 @@ int DcePayloadTest23(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest25(void) +static int DcePayloadParseTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -7594,7 +7594,7 @@ int DcePayloadParseTest25(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest26(void) +static int DcePayloadParseTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -7721,7 +7721,7 @@ int DcePayloadParseTest26(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest27(void) +static int DcePayloadParseTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -7847,7 +7847,7 @@ int DcePayloadParseTest27(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest28(void) +static int DcePayloadParseTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -7974,7 +7974,7 @@ int DcePayloadParseTest28(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest29(void) +static int DcePayloadParseTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8116,7 +8116,7 @@ int DcePayloadParseTest29(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest30(void) +static int DcePayloadParseTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8263,7 +8263,7 @@ int DcePayloadParseTest30(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest31(void) +static int DcePayloadParseTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8410,7 +8410,7 @@ int DcePayloadParseTest31(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest32(void) +static int DcePayloadParseTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8557,7 +8557,7 @@ int DcePayloadParseTest32(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest33(void) +static int DcePayloadParseTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8699,7 +8699,7 @@ int DcePayloadParseTest33(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest34(void) +static int DcePayloadParseTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8823,7 +8823,7 @@ int DcePayloadParseTest34(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest35(void) +static int DcePayloadParseTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8910,7 +8910,7 @@ int DcePayloadParseTest35(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest36(void) +static int DcePayloadParseTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9014,7 +9014,7 @@ int DcePayloadParseTest36(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest37(void) +static int DcePayloadParseTest37(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9121,7 +9121,7 @@ int DcePayloadParseTest37(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest38(void) +static int DcePayloadParseTest38(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9243,7 +9243,7 @@ int DcePayloadParseTest38(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest39(void) +static int DcePayloadParseTest39(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9328,7 +9328,7 @@ int DcePayloadParseTest39(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest40(void) +static int DcePayloadParseTest40(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9458,7 +9458,7 @@ int DcePayloadParseTest40(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest41(void) +static int DcePayloadParseTest41(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9587,7 +9587,7 @@ int DcePayloadParseTest41(void) /** * \test Test the working of consecutive relative matches with a negated content. */ -int DcePayloadTest42(void) +static int DcePayloadTest42(void) { int result = 0; @@ -9690,7 +9690,7 @@ int DcePayloadTest42(void) /** * \test Test the working of consecutive relative pcres. */ -int DcePayloadTest43(void) +static int DcePayloadTest43(void) { int result = 0; @@ -9793,7 +9793,7 @@ int DcePayloadTest43(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest44(void) +static int DcePayloadParseTest44(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9920,7 +9920,7 @@ int DcePayloadParseTest44(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest45(void) +static int DcePayloadParseTest45(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -10032,7 +10032,7 @@ int DcePayloadParseTest45(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest46(void) +static int DcePayloadParseTest46(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index 11346a40f687..191a15363629 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -1795,7 +1795,7 @@ static int IPOnlyTestSig04 (void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) */ -int IPOnlyTestSig05(void) +static int IPOnlyTestSig05(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -1832,7 +1832,7 @@ int IPOnlyTestSig05(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) */ -int IPOnlyTestSig06(void) +static int IPOnlyTestSig06(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -1873,7 +1873,7 @@ int IPOnlyTestSig06(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) */ -int IPOnlyTestSig07(void) +static int IPOnlyTestSig07(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -1911,7 +1911,7 @@ int IPOnlyTestSig07(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) */ -int IPOnlyTestSig08(void) +static int IPOnlyTestSig08(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -1948,7 +1948,7 @@ int IPOnlyTestSig08(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) */ -int IPOnlyTestSig09(void) +static int IPOnlyTestSig09(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -1985,7 +1985,7 @@ int IPOnlyTestSig09(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) */ -int IPOnlyTestSig10(void) +static int IPOnlyTestSig10(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2026,7 +2026,7 @@ int IPOnlyTestSig10(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) with ipv4 and ipv6 mixed */ -int IPOnlyTestSig11(void) +static int IPOnlyTestSig11(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2065,7 +2065,7 @@ int IPOnlyTestSig11(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) with ipv4 and ipv6 mixed */ -int IPOnlyTestSig12(void) +static int IPOnlyTestSig12(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2133,7 +2133,7 @@ static int IPOnlyTestSig14(void) PASS; } -int IPOnlyTestSig15(void) +static int IPOnlyTestSig15(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2187,7 +2187,7 @@ int IPOnlyTestSig15(void) /** * \brief Unittest to show #599. We fail to match if we have negated addresses. */ -int IPOnlyTestSig16(void) +static int IPOnlyTestSig16(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2218,7 +2218,7 @@ int IPOnlyTestSig16(void) /** * \brief Unittest to show #611. Ports on portless protocols. */ -int IPOnlyTestSig17(void) +static int IPOnlyTestSig17(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; From 5e0b0eea4b477d91dd73f57045f4c137b590e4f5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Oct 2016 12:58:19 +0200 Subject: [PATCH 2336/2553] detect: remove unused flags --- src/detect-engine-payload.c | 7 ------- src/detect.h | 2 -- 2 files changed, 9 deletions(-) diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index 6cdb775adb2e..c7f4bba8af60 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -142,13 +142,10 @@ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; det_ctx->replist = NULL; - //det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], f, p->payload, p->payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD, p); - //r = DoInspectPacketPayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], p, f, p->payload, p->payload_len); - //det_ctx->flags &= ~DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET; if (r == 1) { SCReturnInt(1); } @@ -186,14 +183,10 @@ int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - //det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], f, payload, payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM, NULL); - - //r = DoInspectPacketPayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], NULL, f, payload, payload_len); - //det_ctx->flags &= ~DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM; if (r == 1) { SCReturnInt(1); } diff --git a/src/detect.h b/src/detect.h index 3040c4875a17..8ff86974cdb6 100644 --- a/src/detect.h +++ b/src/detect.h @@ -321,8 +321,6 @@ typedef struct DetectPort_ { /* for now a uint8_t is enough */ #define SignatureMask uint16_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 From e2c6e1be33deb4a61351d2532628fd21a47be39e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 7 Dec 2016 11:14:20 +0100 Subject: [PATCH 2337/2553] detect-parse: set ipprotos earlier A high level proto like HTTP implies TCP. However this wasn't set until after all the parsing was complete which means that keywords couldn't test if the ipproto matched. This patch populates the ipprotos right when the higher level proto is parsed. --- src/detect-file-data.c | 6 +++--- src/detect-parse.c | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/detect-file-data.c b/src/detect-file-data.c index 1d9a5f4ee30b..e59870524137 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -93,9 +93,9 @@ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str { SCEnter(); - if (!DetectProtoContainsProto(&s->proto, IPPROTO_TCP) && - s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP && - s->alproto != ALPROTO_SMTP) { + if (!DetectProtoContainsProto(&s->proto, IPPROTO_TCP) || + (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP && + s->alproto != ALPROTO_SMTP)) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); return -1; } diff --git a/src/detect-parse.c b/src/detect-parse.c index 17042cb54dd0..b49ee57fcf0e 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -718,8 +718,11 @@ int SigParseProto(Signature *s, const char *protostr) if (r < 0) { s->alproto = AppLayerGetProtoByName((char *)protostr); /* indicate that the signature is app-layer */ - if (s->alproto != ALPROTO_UNKNOWN) + if (s->alproto != ALPROTO_UNKNOWN) { s->flags |= SIG_FLAG_APPLAYER; + + AppLayerProtoDetectSupportedIpprotos(s->alproto, s->proto.proto); + } else { SCLogError(SC_ERR_UNKNOWN_PROTOCOL, "protocol \"%s\" cannot be used " "in a signature. Either detection for this protocol " From faadec0d7fd47515996bffb41008cacbdda69ae1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 7 Dec 2016 11:33:10 +0100 Subject: [PATCH 2338/2553] detect file_data: improve error messages --- src/detect-file-data.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/detect-file-data.c b/src/detect-file-data.c index e59870524137..e7098a6d4fda 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -102,14 +102,16 @@ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str if (s->alproto == ALPROTO_HTTP && (s->init_flags & SIG_FLAG_INIT_FLOW) && (s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with flow:to_server or from_client with http."); - return -1; + SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with " + "flow:to_server or flow:from_client with http."); + return -1; } if (s->alproto == ALPROTO_SMTP && (s->init_flags & SIG_FLAG_INIT_FLOW) && !(s->flags & SIG_FLAG_TOSERVER) && (s->flags & SIG_FLAG_TOCLIENT)) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with flow:to_client or from_server with smtp."); - return -1; + SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with " + "flow:to_client or flow:from_server with smtp."); + return -1; } s->list = DETECT_SM_LIST_FILEDATA; From 99580487e56c18bf4ceda73d8a115d88f8b7dd9d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 7 Dec 2016 11:33:50 +0100 Subject: [PATCH 2339/2553] detect: fix file_data / http_server_body tests --- src/detect-fast-pattern.c | 1275 ++++++++++++++++----------------- src/detect-http-server-body.c | 80 +-- 2 files changed, 653 insertions(+), 702 deletions(-) diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index c4cb73dd0bc2..8370d08af030 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -371,7 +371,7 @@ int DetectFastPatternTest01(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; tcpv4-csum:valid; fast_pattern; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -411,7 +411,7 @@ int DetectFastPatternTest02(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern; " "content:\"boo\"; fast_pattern; " "msg:\"Testing fast_pattern\"; sid:1;)"); @@ -440,7 +440,7 @@ int DetectFastPatternTest03(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -480,7 +480,7 @@ int DetectFastPatternTest04(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:boo; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -569,7 +569,7 @@ int DetectFastPatternTest15(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -610,7 +610,7 @@ int DetectFastPatternTest16(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -648,7 +648,7 @@ int DetectFastPatternTest17(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -684,7 +684,7 @@ int DetectFastPatternTest18(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -719,7 +719,7 @@ int DetectFastPatternTest19(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -741,7 +741,7 @@ int DetectFastPatternTest20(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; distance:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -763,7 +763,7 @@ int DetectFastPatternTest21(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -785,7 +785,7 @@ int DetectFastPatternTest22(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; within:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -807,7 +807,7 @@ int DetectFastPatternTest23(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -829,7 +829,7 @@ int DetectFastPatternTest24(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; offset:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -851,7 +851,7 @@ int DetectFastPatternTest25(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -873,7 +873,7 @@ int DetectFastPatternTest26(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; depth:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -895,7 +895,7 @@ int DetectFastPatternTest27(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -917,7 +917,7 @@ int DetectFastPatternTest28(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; content:\"two\"; distance:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -948,7 +948,7 @@ int DetectFastPatternTest29(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; within:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -978,7 +978,7 @@ int DetectFastPatternTest30(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; offset:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1008,7 +1008,7 @@ int DetectFastPatternTest31(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; depth:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1038,7 +1038,7 @@ int DetectFastPatternTest32(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1069,7 +1069,7 @@ int DetectFastPatternTest33(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1091,7 +1091,7 @@ int DetectFastPatternTest34(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1113,7 +1113,7 @@ int DetectFastPatternTest35(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1135,7 +1135,7 @@ int DetectFastPatternTest36(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1157,7 +1157,7 @@ int DetectFastPatternTest37(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; content:\"oneonetwo\"; fast_pattern:3,4; content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1187,7 +1187,7 @@ int DetectFastPatternTest38(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1217,7 +1217,7 @@ int DetectFastPatternTest39(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1247,7 +1247,7 @@ int DetectFastPatternTest40(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1277,7 +1277,7 @@ int DetectFastPatternTest41(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1307,7 +1307,7 @@ int DetectFastPatternTest42(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; distance:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1337,7 +1337,7 @@ int DetectFastPatternTest43(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; within:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1367,7 +1367,7 @@ int DetectFastPatternTest44(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; offset:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1397,7 +1397,7 @@ int DetectFastPatternTest45(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; depth:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1427,7 +1427,7 @@ int DetectFastPatternTest46(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:65977,4; content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1449,7 +1449,7 @@ int DetectFastPatternTest47(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"twooneone\"; fast_pattern:3,65977; content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1471,7 +1471,7 @@ int DetectFastPatternTest48(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:65534,4; content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1493,7 +1493,7 @@ int DetectFastPatternTest49(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1524,7 +1524,7 @@ int DetectFastPatternTest50(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; distance:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1546,7 +1546,7 @@ int DetectFastPatternTest51(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; within:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1568,7 +1568,7 @@ int DetectFastPatternTest52(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; offset:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1590,7 +1590,7 @@ int DetectFastPatternTest53(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; depth:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1621,7 +1621,7 @@ int DetectFastPatternTest54(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"/one/\"; fast_pattern:only; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -1662,7 +1662,7 @@ int DetectFastPatternTest55(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"oneoneone\"; fast_pattern:3,4; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -1700,7 +1700,7 @@ int DetectFastPatternTest56(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1736,7 +1736,7 @@ int DetectFastPatternTest57(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"oneoneone\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1771,7 +1771,7 @@ int DetectFastPatternTest58(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1793,7 +1793,7 @@ int DetectFastPatternTest59(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; distance:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1815,7 +1815,7 @@ int DetectFastPatternTest60(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1837,7 +1837,7 @@ int DetectFastPatternTest61(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1859,7 +1859,7 @@ int DetectFastPatternTest62(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1881,7 +1881,7 @@ int DetectFastPatternTest63(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1903,7 +1903,7 @@ int DetectFastPatternTest64(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1925,7 +1925,7 @@ int DetectFastPatternTest65(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1947,7 +1947,7 @@ int DetectFastPatternTest66(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1969,7 +1969,7 @@ int DetectFastPatternTest67(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent: \"one\"; uricontent:\"two\"; distance:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2000,7 +2000,7 @@ int DetectFastPatternTest68(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2030,7 +2030,7 @@ int DetectFastPatternTest69(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2060,7 +2060,7 @@ int DetectFastPatternTest70(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2090,7 +2090,7 @@ int DetectFastPatternTest71(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:!\"one\"; fast_pattern; uricontent:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2121,7 +2121,7 @@ int DetectFastPatternTest72(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2143,7 +2143,7 @@ int DetectFastPatternTest73(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2165,7 +2165,7 @@ int DetectFastPatternTest74(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2187,7 +2187,7 @@ int DetectFastPatternTest75(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2209,7 +2209,7 @@ int DetectFastPatternTest76(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2239,7 +2239,7 @@ int DetectFastPatternTest77(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2269,7 +2269,7 @@ int DetectFastPatternTest78(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2299,7 +2299,7 @@ int DetectFastPatternTest79(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2329,7 +2329,7 @@ int DetectFastPatternTest80(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2359,7 +2359,7 @@ int DetectFastPatternTest81(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; distance:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2389,7 +2389,7 @@ int DetectFastPatternTest82(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2419,7 +2419,7 @@ int DetectFastPatternTest83(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2449,7 +2449,7 @@ int DetectFastPatternTest84(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2482,7 +2482,7 @@ int DetectFastPatternTest85(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:65977,4; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2504,7 +2504,7 @@ int DetectFastPatternTest86(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,65977; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2526,7 +2526,7 @@ int DetectFastPatternTest87(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:65534,4; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2548,7 +2548,7 @@ int DetectFastPatternTest88(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2579,7 +2579,7 @@ int DetectFastPatternTest89(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; distance:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2601,7 +2601,7 @@ int DetectFastPatternTest90(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; within:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2623,7 +2623,7 @@ int DetectFastPatternTest91(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; offset:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2645,7 +2645,7 @@ int DetectFastPatternTest92(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; depth:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2672,7 +2672,7 @@ int DetectFastPatternTest93(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2707,7 +2707,7 @@ int DetectFastPatternTest94(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -2748,7 +2748,7 @@ int DetectFastPatternTest95(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -2786,7 +2786,7 @@ int DetectFastPatternTest96(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2822,7 +2822,7 @@ int DetectFastPatternTest97(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2857,7 +2857,7 @@ int DetectFastPatternTest98(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2879,7 +2879,7 @@ int DetectFastPatternTest99(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; distance:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2901,7 +2901,7 @@ int DetectFastPatternTest100(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2923,7 +2923,7 @@ int DetectFastPatternTest101(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; within:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2945,7 +2945,7 @@ int DetectFastPatternTest102(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2967,7 +2967,7 @@ int DetectFastPatternTest103(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; offset:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2989,7 +2989,7 @@ int DetectFastPatternTest104(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3011,7 +3011,7 @@ int DetectFastPatternTest105(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; depth:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3033,7 +3033,7 @@ int DetectFastPatternTest106(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3055,7 +3055,7 @@ int DetectFastPatternTest107(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent: \"one\"; uricontent:\"two\"; distance:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3086,7 +3086,7 @@ int DetectFastPatternTest108(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3116,7 +3116,7 @@ int DetectFastPatternTest109(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3146,7 +3146,7 @@ int DetectFastPatternTest110(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3176,7 +3176,7 @@ int DetectFastPatternTest111(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_uri; uricontent:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3207,7 +3207,7 @@ int DetectFastPatternTest112(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3229,7 +3229,7 @@ int DetectFastPatternTest113(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3251,7 +3251,7 @@ int DetectFastPatternTest114(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3273,7 +3273,7 @@ int DetectFastPatternTest115(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3295,7 +3295,7 @@ int DetectFastPatternTest116(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3325,7 +3325,7 @@ int DetectFastPatternTest117(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3355,7 +3355,7 @@ int DetectFastPatternTest118(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3385,7 +3385,7 @@ int DetectFastPatternTest119(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3415,7 +3415,7 @@ int DetectFastPatternTest120(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3445,7 +3445,7 @@ int DetectFastPatternTest121(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3475,7 +3475,7 @@ int DetectFastPatternTest122(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3505,7 +3505,7 @@ int DetectFastPatternTest123(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3535,7 +3535,7 @@ int DetectFastPatternTest124(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3568,7 +3568,7 @@ int DetectFastPatternTest125(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:65977,4; http_uri; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3590,7 +3590,7 @@ int DetectFastPatternTest126(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,65977; http_uri; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3612,7 +3612,7 @@ int DetectFastPatternTest127(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:65534,4; http_uri; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3634,7 +3634,7 @@ int DetectFastPatternTest128(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3665,7 +3665,7 @@ int DetectFastPatternTest129(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; distance:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3687,7 +3687,7 @@ int DetectFastPatternTest130(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; within:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3709,7 +3709,7 @@ int DetectFastPatternTest131(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; http_uri; offset:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3731,7 +3731,7 @@ int DetectFastPatternTest132(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; depth:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3753,7 +3753,7 @@ int DetectFastPatternTest133(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3789,7 +3789,7 @@ int DetectFastPatternTest134(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3824,7 +3824,7 @@ int DetectFastPatternTest135(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_client_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -3861,7 +3861,7 @@ int DetectFastPatternTest136(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_client_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -3894,7 +3894,7 @@ int DetectFastPatternTest137(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3928,7 +3928,7 @@ int DetectFastPatternTest138(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3961,7 +3961,7 @@ int DetectFastPatternTest139(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3983,7 +3983,7 @@ int DetectFastPatternTest140(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; distance:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4005,7 +4005,7 @@ int DetectFastPatternTest141(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4027,7 +4027,7 @@ int DetectFastPatternTest142(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; within:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4049,7 +4049,7 @@ int DetectFastPatternTest143(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4071,7 +4071,7 @@ int DetectFastPatternTest144(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; offset:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4093,7 +4093,7 @@ int DetectFastPatternTest145(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4115,7 +4115,7 @@ int DetectFastPatternTest146(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; depth:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4137,7 +4137,7 @@ int DetectFastPatternTest147(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4159,7 +4159,7 @@ int DetectFastPatternTest148(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; http_client_body; content:\"two\"; http_client_body; distance:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4190,7 +4190,7 @@ int DetectFastPatternTest149(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; within:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4220,7 +4220,7 @@ int DetectFastPatternTest150(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; offset:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4250,7 +4250,7 @@ int DetectFastPatternTest151(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; depth:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4280,7 +4280,7 @@ int DetectFastPatternTest152(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_client_body; content:\"two\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4311,7 +4311,7 @@ int DetectFastPatternTest153(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4333,7 +4333,7 @@ int DetectFastPatternTest154(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4355,7 +4355,7 @@ int DetectFastPatternTest155(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4377,7 +4377,7 @@ int DetectFastPatternTest156(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4399,7 +4399,7 @@ int DetectFastPatternTest157(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4429,7 +4429,7 @@ int DetectFastPatternTest158(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4459,7 +4459,7 @@ int DetectFastPatternTest159(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4489,7 +4489,7 @@ int DetectFastPatternTest160(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4519,7 +4519,7 @@ int DetectFastPatternTest161(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4549,7 +4549,7 @@ int DetectFastPatternTest162(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4579,7 +4579,7 @@ int DetectFastPatternTest163(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4609,7 +4609,7 @@ int DetectFastPatternTest164(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4639,7 +4639,7 @@ int DetectFastPatternTest165(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4672,7 +4672,7 @@ int DetectFastPatternTest166(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:65977,4; http_client_body; content:\"three\"; http_client_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4694,7 +4694,7 @@ int DetectFastPatternTest167(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,65977; http_client_body; content:\"three\"; distance:10; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4716,7 +4716,7 @@ int DetectFastPatternTest168(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:65534,4; http_client_body; content:\"three\"; http_client_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4738,7 +4738,7 @@ int DetectFastPatternTest169(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4769,7 +4769,7 @@ int DetectFastPatternTest170(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; distance:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4791,7 +4791,7 @@ int DetectFastPatternTest171(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; within:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4813,7 +4813,7 @@ int DetectFastPatternTest172(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"twooneone\"; fast_pattern:3,4; http_client_body; offset:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4835,7 +4835,7 @@ int DetectFastPatternTest173(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; depth:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4857,7 +4857,7 @@ int DetectFastPatternTest174(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4893,7 +4893,7 @@ int DetectFastPatternTest175(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; distance:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4915,7 +4915,7 @@ int DetectFastPatternTest176(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; within:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4937,7 +4937,7 @@ int DetectFastPatternTest177(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; offset:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4959,7 +4959,7 @@ int DetectFastPatternTest178(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; depth:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4985,7 +4985,7 @@ int DetectFastPatternTest179(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_header; " "content:\"three\"; http_header; sid:1;)"); @@ -5022,7 +5022,7 @@ int DetectFastPatternTest180(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_header; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -5059,7 +5059,7 @@ int DetectFastPatternTest181(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_header; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -5092,7 +5092,7 @@ int DetectFastPatternTest182(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5126,7 +5126,7 @@ int DetectFastPatternTest183(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5159,7 +5159,7 @@ int DetectFastPatternTest184(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5181,7 +5181,7 @@ int DetectFastPatternTest185(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; distance:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5203,7 +5203,7 @@ int DetectFastPatternTest186(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5225,7 +5225,7 @@ int DetectFastPatternTest187(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; within:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5247,7 +5247,7 @@ int DetectFastPatternTest188(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5269,7 +5269,7 @@ int DetectFastPatternTest189(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; offset:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5291,7 +5291,7 @@ int DetectFastPatternTest190(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5313,7 +5313,7 @@ int DetectFastPatternTest191(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; depth:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5335,7 +5335,7 @@ int DetectFastPatternTest192(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5357,7 +5357,7 @@ int DetectFastPatternTest193(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; http_header; content:\"two\"; http_header; distance:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5388,7 +5388,7 @@ int DetectFastPatternTest194(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; within:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5418,7 +5418,7 @@ int DetectFastPatternTest195(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; offset:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5448,7 +5448,7 @@ int DetectFastPatternTest196(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; depth:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5478,7 +5478,7 @@ int DetectFastPatternTest197(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_header; content:\"two\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5509,7 +5509,7 @@ int DetectFastPatternTest198(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5531,7 +5531,7 @@ int DetectFastPatternTest199(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5553,7 +5553,7 @@ int DetectFastPatternTest200(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5575,7 +5575,7 @@ int DetectFastPatternTest201(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5597,7 +5597,7 @@ int DetectFastPatternTest202(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5627,7 +5627,7 @@ int DetectFastPatternTest203(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5657,7 +5657,7 @@ int DetectFastPatternTest204(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5687,7 +5687,7 @@ int DetectFastPatternTest205(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5717,7 +5717,7 @@ int DetectFastPatternTest206(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5747,7 +5747,7 @@ int DetectFastPatternTest207(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5777,7 +5777,7 @@ int DetectFastPatternTest208(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5807,7 +5807,7 @@ int DetectFastPatternTest209(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5837,7 +5837,7 @@ int DetectFastPatternTest210(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5870,7 +5870,7 @@ int DetectFastPatternTest211(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:65977,4; http_header; content:\"three\"; http_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5892,7 +5892,7 @@ int DetectFastPatternTest212(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,65977; http_header; content:\"three\"; distance:10; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5914,7 +5914,7 @@ int DetectFastPatternTest213(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:65534,4; http_header; content:\"three\"; http_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5936,7 +5936,7 @@ int DetectFastPatternTest214(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5967,7 +5967,7 @@ int DetectFastPatternTest215(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; distance:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5989,7 +5989,7 @@ int DetectFastPatternTest216(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; within:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6011,7 +6011,7 @@ int DetectFastPatternTest217(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; offset:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6033,7 +6033,7 @@ int DetectFastPatternTest218(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; depth:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6055,7 +6055,7 @@ int DetectFastPatternTest219(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7197,7 +7197,7 @@ int DetectFastPatternTest261(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_method; " "content:\"three\"; http_method; sid:1;)"); @@ -7234,7 +7234,7 @@ int DetectFastPatternTest262(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_method; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -7271,7 +7271,7 @@ int DetectFastPatternTest263(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_method; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -7304,7 +7304,7 @@ int DetectFastPatternTest264(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7338,7 +7338,7 @@ int DetectFastPatternTest265(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7371,7 +7371,7 @@ int DetectFastPatternTest266(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7393,7 +7393,7 @@ int DetectFastPatternTest267(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; distance:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7415,7 +7415,7 @@ int DetectFastPatternTest268(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7437,7 +7437,7 @@ int DetectFastPatternTest269(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; within:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7459,7 +7459,7 @@ int DetectFastPatternTest270(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7481,7 +7481,7 @@ int DetectFastPatternTest271(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; offset:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7503,7 +7503,7 @@ int DetectFastPatternTest272(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7525,7 +7525,7 @@ int DetectFastPatternTest273(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; depth:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7547,7 +7547,7 @@ int DetectFastPatternTest274(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7569,7 +7569,7 @@ int DetectFastPatternTest275(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; http_method; content:\"two\"; http_method; distance:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7600,7 +7600,7 @@ int DetectFastPatternTest276(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; within:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7630,7 +7630,7 @@ int DetectFastPatternTest277(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; offset:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7660,7 +7660,7 @@ int DetectFastPatternTest278(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; depth:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7690,7 +7690,7 @@ int DetectFastPatternTest279(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_method; content:\"two\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7721,7 +7721,7 @@ int DetectFastPatternTest280(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7743,7 +7743,7 @@ int DetectFastPatternTest281(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7765,7 +7765,7 @@ int DetectFastPatternTest282(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7787,7 +7787,7 @@ int DetectFastPatternTest283(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7809,7 +7809,7 @@ int DetectFastPatternTest284(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7839,7 +7839,7 @@ int DetectFastPatternTest285(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7869,7 +7869,7 @@ int DetectFastPatternTest286(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7899,7 +7899,7 @@ int DetectFastPatternTest287(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7929,7 +7929,7 @@ int DetectFastPatternTest288(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7959,7 +7959,7 @@ int DetectFastPatternTest289(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7989,7 +7989,7 @@ int DetectFastPatternTest290(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8019,7 +8019,7 @@ int DetectFastPatternTest291(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8049,7 +8049,7 @@ int DetectFastPatternTest292(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8082,7 +8082,7 @@ int DetectFastPatternTest293(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:65977,4; http_method; content:\"three\"; http_method; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8104,7 +8104,7 @@ int DetectFastPatternTest294(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,65977; http_method; content:\"three\"; distance:10; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8126,7 +8126,7 @@ int DetectFastPatternTest295(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:65534,4; http_method; content:\"three\"; http_method; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8148,7 +8148,7 @@ int DetectFastPatternTest296(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8179,7 +8179,7 @@ int DetectFastPatternTest297(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; distance:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8201,7 +8201,7 @@ int DetectFastPatternTest298(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; within:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8223,7 +8223,7 @@ int DetectFastPatternTest299(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; offset:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8245,7 +8245,7 @@ int DetectFastPatternTest300(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; depth:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8267,7 +8267,7 @@ int DetectFastPatternTest301(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8303,7 +8303,7 @@ int DetectFastPatternTest302(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; " "content:\"three\"; http_cookie; sid:1;)"); @@ -8340,7 +8340,7 @@ int DetectFastPatternTest303(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_cookie; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -8377,7 +8377,7 @@ int DetectFastPatternTest304(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_cookie; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -8410,7 +8410,7 @@ int DetectFastPatternTest305(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8444,7 +8444,7 @@ int DetectFastPatternTest306(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8477,7 +8477,7 @@ int DetectFastPatternTest307(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8499,7 +8499,7 @@ int DetectFastPatternTest308(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; distance:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8521,7 +8521,7 @@ int DetectFastPatternTest309(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8543,7 +8543,7 @@ int DetectFastPatternTest310(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; within:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8565,7 +8565,7 @@ int DetectFastPatternTest311(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8587,7 +8587,7 @@ int DetectFastPatternTest312(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; offset:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8609,7 +8609,7 @@ int DetectFastPatternTest313(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8631,7 +8631,7 @@ int DetectFastPatternTest314(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; depth:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8653,7 +8653,7 @@ int DetectFastPatternTest315(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8675,7 +8675,7 @@ int DetectFastPatternTest316(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; http_cookie; content:\"two\"; http_cookie; distance:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8706,7 +8706,7 @@ int DetectFastPatternTest317(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; within:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8736,7 +8736,7 @@ int DetectFastPatternTest318(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; offset:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8766,7 +8766,7 @@ int DetectFastPatternTest319(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; depth:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8796,7 +8796,7 @@ int DetectFastPatternTest320(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_cookie; content:\"two\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8827,7 +8827,7 @@ int DetectFastPatternTest321(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8849,7 +8849,7 @@ int DetectFastPatternTest322(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8871,7 +8871,7 @@ int DetectFastPatternTest323(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8893,7 +8893,7 @@ int DetectFastPatternTest324(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8915,7 +8915,7 @@ int DetectFastPatternTest325(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8945,7 +8945,7 @@ int DetectFastPatternTest326(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -8975,7 +8975,7 @@ int DetectFastPatternTest327(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9005,7 +9005,7 @@ int DetectFastPatternTest328(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9035,7 +9035,7 @@ int DetectFastPatternTest329(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9065,7 +9065,7 @@ int DetectFastPatternTest330(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9095,7 +9095,7 @@ int DetectFastPatternTest331(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9125,7 +9125,7 @@ int DetectFastPatternTest332(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9155,7 +9155,7 @@ int DetectFastPatternTest333(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9188,7 +9188,7 @@ int DetectFastPatternTest334(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:65977,4; http_cookie; content:\"three\"; http_cookie; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9210,7 +9210,7 @@ int DetectFastPatternTest335(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,65977; http_cookie; content:\"three\"; distance:10; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9232,7 +9232,7 @@ int DetectFastPatternTest336(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:65534,4; http_cookie; content:\"three\"; http_cookie; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9254,7 +9254,7 @@ int DetectFastPatternTest337(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9285,7 +9285,7 @@ int DetectFastPatternTest338(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; distance:10; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9307,7 +9307,7 @@ int DetectFastPatternTest339(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; within:10; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9329,7 +9329,7 @@ int DetectFastPatternTest340(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; offset:10; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9351,7 +9351,7 @@ int DetectFastPatternTest341(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; depth:10; content:\"three2\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9373,7 +9373,7 @@ int DetectFastPatternTest342(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9409,7 +9409,7 @@ int DetectFastPatternTest343(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -9446,7 +9446,7 @@ int DetectFastPatternTest344(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_raw_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -9483,7 +9483,7 @@ int DetectFastPatternTest345(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -9516,7 +9516,7 @@ int DetectFastPatternTest346(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9550,7 +9550,7 @@ int DetectFastPatternTest347(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -9583,7 +9583,7 @@ int DetectFastPatternTest348(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9606,7 +9606,7 @@ int DetectFastPatternTest349(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; distance:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9629,7 +9629,7 @@ int DetectFastPatternTest350(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9652,7 +9652,7 @@ int DetectFastPatternTest351(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; within:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9675,7 +9675,7 @@ int DetectFastPatternTest352(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9698,7 +9698,7 @@ int DetectFastPatternTest353(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; offset:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9721,7 +9721,7 @@ int DetectFastPatternTest354(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9744,7 +9744,7 @@ int DetectFastPatternTest355(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; depth:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9767,7 +9767,7 @@ int DetectFastPatternTest356(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9790,7 +9790,7 @@ int DetectFastPatternTest357(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; distance:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); @@ -9823,7 +9823,7 @@ int DetectFastPatternTest358(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; within:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); @@ -9855,7 +9855,7 @@ int DetectFastPatternTest359(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; offset:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); @@ -9887,7 +9887,7 @@ int DetectFastPatternTest360(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; depth:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); @@ -9919,7 +9919,7 @@ int DetectFastPatternTest361(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_raw_uri; " "content:\"two\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -9951,7 +9951,7 @@ int DetectFastPatternTest362(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9974,7 +9974,7 @@ int DetectFastPatternTest363(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -9997,7 +9997,7 @@ int DetectFastPatternTest364(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10020,7 +10020,7 @@ int DetectFastPatternTest365(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10043,7 +10043,7 @@ int DetectFastPatternTest366(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -10075,7 +10075,7 @@ int DetectFastPatternTest367(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; distance:30; sid:1;)"); @@ -10107,7 +10107,7 @@ int DetectFastPatternTest368(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; within:30; sid:1;)"); @@ -10139,7 +10139,7 @@ int DetectFastPatternTest369(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; offset:30; sid:1;)"); @@ -10171,7 +10171,7 @@ int DetectFastPatternTest370(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; depth:30; sid:1;)"); @@ -10203,7 +10203,7 @@ int DetectFastPatternTest371(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); @@ -10235,7 +10235,7 @@ int DetectFastPatternTest372(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); @@ -10267,7 +10267,7 @@ int DetectFastPatternTest373(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); @@ -10299,7 +10299,7 @@ int DetectFastPatternTest374(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); @@ -10334,7 +10334,7 @@ int DetectFastPatternTest375(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:65977,4; http_raw_uri; " "content:\"three\"; http_raw_uri; distance:10; sid:1;)"); @@ -10358,7 +10358,7 @@ int DetectFastPatternTest376(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_raw_uri; " "content:\"three\"; distance:10; http_raw_uri; sid:1;)"); @@ -10382,7 +10382,7 @@ int DetectFastPatternTest377(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:65534,4; http_raw_uri; " "content:\"three\"; http_raw_uri; distance:10; sid:1;)"); @@ -10406,7 +10406,7 @@ int DetectFastPatternTest378(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -10439,7 +10439,7 @@ int DetectFastPatternTest379(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; distance:10; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -10463,7 +10463,7 @@ int DetectFastPatternTest380(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; within:10; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -10487,7 +10487,7 @@ int DetectFastPatternTest381(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; offset:10; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -10511,7 +10511,7 @@ int DetectFastPatternTest382(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; depth:10; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -10535,7 +10535,7 @@ int DetectFastPatternTest383(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -10573,7 +10573,7 @@ int DetectFastPatternTest384(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -10610,7 +10610,7 @@ int DetectFastPatternTest385(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_msg; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -10647,7 +10647,7 @@ int DetectFastPatternTest386(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_msg; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -10680,7 +10680,7 @@ int DetectFastPatternTest387(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -10716,7 +10716,7 @@ int DetectFastPatternTest388(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -10752,7 +10752,7 @@ int DetectFastPatternTest389(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10775,7 +10775,7 @@ int DetectFastPatternTest390(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; distance:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10798,7 +10798,7 @@ int DetectFastPatternTest391(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10821,7 +10821,7 @@ int DetectFastPatternTest392(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; within:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10844,7 +10844,7 @@ int DetectFastPatternTest393(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10867,7 +10867,7 @@ int DetectFastPatternTest394(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; offset:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10890,7 +10890,7 @@ int DetectFastPatternTest395(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10913,7 +10913,7 @@ int DetectFastPatternTest396(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; depth:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10936,7 +10936,7 @@ int DetectFastPatternTest397(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10959,7 +10959,7 @@ int DetectFastPatternTest398(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; distance:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); @@ -10992,7 +10992,7 @@ int DetectFastPatternTest399(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; within:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); @@ -11024,7 +11024,7 @@ int DetectFastPatternTest400(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; offset:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); @@ -11056,7 +11056,7 @@ int DetectFastPatternTest401(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; depth:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); @@ -11088,7 +11088,7 @@ int DetectFastPatternTest402(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_stat_msg; " "content:\"two\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -11120,7 +11120,7 @@ int DetectFastPatternTest403(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11143,7 +11143,7 @@ int DetectFastPatternTest404(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11166,7 +11166,7 @@ int DetectFastPatternTest405(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11189,7 +11189,7 @@ int DetectFastPatternTest406(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11212,7 +11212,7 @@ int DetectFastPatternTest407(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -11244,7 +11244,7 @@ int DetectFastPatternTest408(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; distance:30; sid:1;)"); @@ -11276,7 +11276,7 @@ int DetectFastPatternTest409(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; within:30; sid:1;)"); @@ -11308,7 +11308,7 @@ int DetectFastPatternTest410(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; offset:30; sid:1;)"); @@ -11340,7 +11340,7 @@ int DetectFastPatternTest411(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; depth:30; sid:1;)"); @@ -11372,7 +11372,7 @@ int DetectFastPatternTest412(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); @@ -11404,7 +11404,7 @@ int DetectFastPatternTest413(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); @@ -11436,7 +11436,7 @@ int DetectFastPatternTest414(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); @@ -11468,7 +11468,7 @@ int DetectFastPatternTest415(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); @@ -11503,7 +11503,7 @@ int DetectFastPatternTest416(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:65977,4; http_stat_msg; " "content:\"three\"; http_stat_msg; distance:10; sid:1;)"); @@ -11527,7 +11527,7 @@ int DetectFastPatternTest417(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_stat_msg; " "content:\"three\"; distance:10; http_stat_msg; sid:1;)"); @@ -11551,7 +11551,7 @@ int DetectFastPatternTest418(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:65534,4; http_stat_msg; " "content:\"three\"; http_stat_msg; distance:10; sid:1;)"); @@ -11575,7 +11575,7 @@ int DetectFastPatternTest419(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -11608,7 +11608,7 @@ int DetectFastPatternTest420(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; distance:10; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -11632,7 +11632,7 @@ int DetectFastPatternTest421(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; within:10; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -11656,7 +11656,7 @@ int DetectFastPatternTest422(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; offset:10; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -11680,7 +11680,7 @@ int DetectFastPatternTest423(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; depth:10; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -11704,7 +11704,7 @@ int DetectFastPatternTest424(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -11742,7 +11742,7 @@ int DetectFastPatternTest425(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -11779,7 +11779,7 @@ int DetectFastPatternTest426(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_code; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -11816,7 +11816,7 @@ int DetectFastPatternTest427(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_code; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -11849,7 +11849,7 @@ int DetectFastPatternTest428(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -11886,7 +11886,7 @@ int DetectFastPatternTest429(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -11922,7 +11922,7 @@ int DetectFastPatternTest430(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11945,7 +11945,7 @@ int DetectFastPatternTest431(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; distance:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11968,7 +11968,7 @@ int DetectFastPatternTest432(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11991,7 +11991,7 @@ int DetectFastPatternTest433(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; within:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12014,7 +12014,7 @@ int DetectFastPatternTest434(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12037,7 +12037,7 @@ int DetectFastPatternTest435(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; offset:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12060,7 +12060,7 @@ int DetectFastPatternTest436(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12083,7 +12083,7 @@ int DetectFastPatternTest437(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; depth:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12106,7 +12106,7 @@ int DetectFastPatternTest438(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12129,7 +12129,7 @@ int DetectFastPatternTest439(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_stat_code; " "content:\"two\"; http_stat_code; distance:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); @@ -12162,7 +12162,7 @@ int DetectFastPatternTest440(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; within:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); @@ -12194,7 +12194,7 @@ int DetectFastPatternTest441(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; offset:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); @@ -12226,7 +12226,7 @@ int DetectFastPatternTest442(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; depth:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); @@ -12258,7 +12258,7 @@ int DetectFastPatternTest443(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_stat_code; " "content:\"two\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -12290,7 +12290,7 @@ int DetectFastPatternTest444(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12313,7 +12313,7 @@ int DetectFastPatternTest445(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12336,7 +12336,7 @@ int DetectFastPatternTest446(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12359,7 +12359,7 @@ int DetectFastPatternTest447(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12382,7 +12382,7 @@ int DetectFastPatternTest448(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -12414,7 +12414,7 @@ int DetectFastPatternTest449(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; distance:30; sid:1;)"); @@ -12446,7 +12446,7 @@ int DetectFastPatternTest450(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; within:30; sid:1;)"); @@ -12478,7 +12478,7 @@ int DetectFastPatternTest451(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; offset:30; sid:1;)"); @@ -12510,7 +12510,7 @@ int DetectFastPatternTest452(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; depth:30; sid:1;)"); @@ -12542,7 +12542,7 @@ int DetectFastPatternTest453(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); @@ -12574,7 +12574,7 @@ int DetectFastPatternTest454(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); @@ -12606,7 +12606,7 @@ int DetectFastPatternTest455(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); @@ -12638,7 +12638,7 @@ int DetectFastPatternTest456(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); @@ -12673,7 +12673,7 @@ int DetectFastPatternTest457(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:65977,4; http_stat_code; " "content:\"three\"; http_stat_code; distance:10; sid:1;)"); @@ -12697,7 +12697,7 @@ int DetectFastPatternTest458(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_stat_code; " "content:\"three\"; distance:10; http_stat_code; sid:1;)"); @@ -12721,7 +12721,7 @@ int DetectFastPatternTest459(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:65534,4; http_stat_code; " "content:\"three\"; http_stat_code; distance:10; sid:1;)"); @@ -12745,7 +12745,7 @@ int DetectFastPatternTest460(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -12778,7 +12778,7 @@ int DetectFastPatternTest461(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; distance:10; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -12802,7 +12802,7 @@ int DetectFastPatternTest462(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; within:10; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -12826,7 +12826,7 @@ int DetectFastPatternTest463(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; offset:10; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -12850,7 +12850,7 @@ int DetectFastPatternTest464(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; depth:10; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -12874,7 +12874,7 @@ int DetectFastPatternTest465(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -12912,7 +12912,7 @@ int DetectFastPatternTest466(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); @@ -12950,7 +12950,7 @@ int DetectFastPatternTest467(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_server_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -12987,7 +12987,7 @@ int DetectFastPatternTest468(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_server_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -13020,7 +13020,7 @@ int DetectFastPatternTest469(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -13056,7 +13056,7 @@ int DetectFastPatternTest470(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -13092,7 +13092,7 @@ int DetectFastPatternTest471(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13115,7 +13115,7 @@ int DetectFastPatternTest472(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; distance:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13138,7 +13138,7 @@ int DetectFastPatternTest473(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13161,7 +13161,7 @@ int DetectFastPatternTest474(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; within:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13184,7 +13184,7 @@ int DetectFastPatternTest475(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13207,7 +13207,7 @@ int DetectFastPatternTest476(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; offset:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13230,7 +13230,7 @@ int DetectFastPatternTest477(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13253,7 +13253,7 @@ int DetectFastPatternTest478(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; depth:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13276,7 +13276,7 @@ int DetectFastPatternTest479(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13299,7 +13299,7 @@ int DetectFastPatternTest480(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_server_body; " "content:\"two\"; http_server_body; distance:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); @@ -13332,7 +13332,7 @@ int DetectFastPatternTest481(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; within:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); @@ -13365,7 +13365,7 @@ int DetectFastPatternTest482(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; offset:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); @@ -13398,7 +13398,7 @@ int DetectFastPatternTest483(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; depth:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); @@ -13431,7 +13431,7 @@ int DetectFastPatternTest484(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_server_body; " "content:\"two\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -13464,7 +13464,7 @@ int DetectFastPatternTest485(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13487,7 +13487,7 @@ int DetectFastPatternTest486(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13510,7 +13510,7 @@ int DetectFastPatternTest487(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13533,7 +13533,7 @@ int DetectFastPatternTest488(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13556,7 +13556,7 @@ int DetectFastPatternTest489(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); @@ -13589,7 +13589,7 @@ int DetectFastPatternTest490(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; distance:30; sid:1;)"); @@ -13622,7 +13622,7 @@ int DetectFastPatternTest491(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; within:30; sid:1;)"); @@ -13655,7 +13655,7 @@ int DetectFastPatternTest492(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; offset:30; sid:1;)"); @@ -13688,7 +13688,7 @@ int DetectFastPatternTest493(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; depth:30; sid:1;)"); @@ -13721,7 +13721,7 @@ int DetectFastPatternTest494(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); @@ -13754,7 +13754,7 @@ int DetectFastPatternTest495(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); @@ -13787,7 +13787,7 @@ int DetectFastPatternTest496(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); @@ -13820,7 +13820,7 @@ int DetectFastPatternTest497(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); @@ -13856,7 +13856,7 @@ int DetectFastPatternTest498(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:65977,4; http_server_body; " "content:\"three\"; http_server_body; distance:10; sid:1;)"); @@ -13880,7 +13880,7 @@ int DetectFastPatternTest499(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_server_body; " "content:\"three\"; distance:10; http_server_body; sid:1;)"); @@ -13904,7 +13904,7 @@ int DetectFastPatternTest500(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:65534,4; http_server_body; " "content:\"three\"; http_server_body; distance:10; sid:1;)"); @@ -13928,7 +13928,7 @@ int DetectFastPatternTest501(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); @@ -13962,7 +13962,7 @@ int DetectFastPatternTest502(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; distance:10; " "content:\"three\"; http_server_body; sid:1;)"); @@ -13986,7 +13986,7 @@ int DetectFastPatternTest503(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; within:10; " "content:\"three\"; http_server_body; sid:1;)"); @@ -14010,7 +14010,7 @@ int DetectFastPatternTest504(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; offset:10; " "content:\"three\"; http_server_body; sid:1;)"); @@ -14034,7 +14034,7 @@ int DetectFastPatternTest505(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; depth:10; " "content:\"three\"; http_server_body; sid:1;)"); @@ -14058,7 +14058,7 @@ int DetectFastPatternTest506(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); @@ -14087,39 +14087,22 @@ int DetectFastPatternTest506(void) /* http_server_body fast_pattern tests ^ */ /* file_data fast_pattern tests v */ - -int DetectFastPatternTest507(void) +/** \test file_data and icmp don't mix */ +static int DetectFastPatternTest507(void) { - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " - "(file_data; content:\"one\"; " - "content:!\"oneonetwo\"; fast_pattern:3,4; " - "content:\"three\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - if (ud->flags & DETECT_CONTENT_FAST_PATTERN && - ud->flags & DETECT_CONTENT_NEGATED && - !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && - ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && - ud->fp_chop_offset == 3 && - ud->fp_chop_len == 4) { - result = 1; - } else { - result = 0; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert icmp any any -> any any " + "(file_data; content:\"one\"; " + "content:!\"oneonetwo\"; fast_pattern:3,4; " + "content:\"three\"; sid:1;)"); + FAIL_IF_NOT_NULL(s); - end: - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -14135,7 +14118,7 @@ int DetectFastPatternTest508(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; fast_pattern:only; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -14172,7 +14155,7 @@ int DetectFastPatternTest509(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"oneoneone\"; fast_pattern:3,4; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -14205,7 +14188,7 @@ int DetectFastPatternTest510(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -14241,7 +14224,7 @@ int DetectFastPatternTest511(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"oneoneone\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -14277,7 +14260,7 @@ int DetectFastPatternTest512(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14300,7 +14283,7 @@ int DetectFastPatternTest513(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; distance:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14323,7 +14306,7 @@ int DetectFastPatternTest514(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14346,7 +14329,7 @@ int DetectFastPatternTest515(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; within:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14369,7 +14352,7 @@ int DetectFastPatternTest516(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14392,7 +14375,7 @@ int DetectFastPatternTest517(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; offset:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14415,7 +14398,7 @@ int DetectFastPatternTest518(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14438,7 +14421,7 @@ int DetectFastPatternTest519(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; depth:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14461,7 +14444,7 @@ int DetectFastPatternTest520(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14484,7 +14467,7 @@ int DetectFastPatternTest521(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\" one\"; " "content:\"two\"; distance:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); @@ -14517,7 +14500,7 @@ int DetectFastPatternTest522(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; within:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); @@ -14550,7 +14533,7 @@ int DetectFastPatternTest523(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; offset:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); @@ -14583,7 +14566,7 @@ int DetectFastPatternTest524(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; depth:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); @@ -14616,7 +14599,7 @@ int DetectFastPatternTest525(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:!\"one\"; fast_pattern; " "content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -14649,7 +14632,7 @@ int DetectFastPatternTest526(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14672,7 +14655,7 @@ int DetectFastPatternTest527(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14695,7 +14678,7 @@ int DetectFastPatternTest528(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14718,7 +14701,7 @@ int DetectFastPatternTest529(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14741,7 +14724,7 @@ int DetectFastPatternTest530(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; sid:1;)"); @@ -14774,7 +14757,7 @@ int DetectFastPatternTest531(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; distance:30; sid:1;)"); @@ -14807,7 +14790,7 @@ int DetectFastPatternTest532(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; within:30; sid:1;)"); @@ -14840,7 +14823,7 @@ int DetectFastPatternTest533(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; offset:30; sid:1;)"); @@ -14873,7 +14856,7 @@ int DetectFastPatternTest534(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; depth:30; sid:1;)"); @@ -14906,7 +14889,7 @@ int DetectFastPatternTest535(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); @@ -14939,7 +14922,7 @@ int DetectFastPatternTest536(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); @@ -14972,7 +14955,7 @@ int DetectFastPatternTest537(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); @@ -15005,7 +14988,7 @@ int DetectFastPatternTest538(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); @@ -15041,7 +15024,7 @@ int DetectFastPatternTest539(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:65977,4; " "content:\"three\"; distance:10; sid:1;)"); @@ -15065,7 +15048,7 @@ int DetectFastPatternTest540(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,65977; " "content:\"three\"; distance:10; sid:1;)"); @@ -15089,7 +15072,7 @@ int DetectFastPatternTest541(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:65534,4; " "content:\"three\"; distance:10; sid:1;)"); @@ -15113,7 +15096,7 @@ int DetectFastPatternTest542(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; sid:1;)"); @@ -15147,7 +15130,7 @@ int DetectFastPatternTest543(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; distance:10; " "content:\"three\"; sid:1;)"); @@ -15171,7 +15154,7 @@ int DetectFastPatternTest544(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; within:10; " "content:\"three\"; sid:1;)"); @@ -15195,7 +15178,7 @@ int DetectFastPatternTest545(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; offset:10; " "content:\"three\"; sid:1;)"); @@ -15219,7 +15202,7 @@ int DetectFastPatternTest546(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; depth:10; " "content:\"three\"; sid:1;)"); @@ -15243,7 +15226,7 @@ int DetectFastPatternTest547(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; sid:1;)"); @@ -15282,7 +15265,7 @@ int DetectFastPatternTest548(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -15320,7 +15303,7 @@ int DetectFastPatternTest549(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_user_agent; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -15357,7 +15340,7 @@ int DetectFastPatternTest550(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_user_agent; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -15390,7 +15373,7 @@ int DetectFastPatternTest551(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -15426,7 +15409,7 @@ int DetectFastPatternTest552(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -15462,7 +15445,7 @@ int DetectFastPatternTest553(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15485,7 +15468,7 @@ int DetectFastPatternTest554(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; distance:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15508,7 +15491,7 @@ int DetectFastPatternTest555(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15531,7 +15514,7 @@ int DetectFastPatternTest556(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; within:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15554,7 +15537,7 @@ int DetectFastPatternTest557(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15577,7 +15560,7 @@ int DetectFastPatternTest558(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; offset:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15600,7 +15583,7 @@ int DetectFastPatternTest559(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15623,7 +15606,7 @@ int DetectFastPatternTest560(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; depth:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15646,7 +15629,7 @@ int DetectFastPatternTest561(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15669,7 +15652,7 @@ int DetectFastPatternTest562(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_user_agent; " "content:\"two\"; http_user_agent; distance:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); @@ -15702,7 +15685,7 @@ int DetectFastPatternTest563(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; within:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); @@ -15734,7 +15717,7 @@ int DetectFastPatternTest564(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; offset:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); @@ -15766,7 +15749,7 @@ int DetectFastPatternTest565(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; depth:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); @@ -15798,7 +15781,7 @@ int DetectFastPatternTest566(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_user_agent; " "content:\"two\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -15830,7 +15813,7 @@ int DetectFastPatternTest567(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15853,7 +15836,7 @@ int DetectFastPatternTest568(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15876,7 +15859,7 @@ int DetectFastPatternTest569(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15899,7 +15882,7 @@ int DetectFastPatternTest570(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15922,7 +15905,7 @@ int DetectFastPatternTest571(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -15954,7 +15937,7 @@ int DetectFastPatternTest572(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; distance:30; sid:1;)"); @@ -15986,7 +15969,7 @@ int DetectFastPatternTest573(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; within:30; sid:1;)"); @@ -16018,7 +16001,7 @@ int DetectFastPatternTest574(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; offset:30; sid:1;)"); @@ -16050,7 +16033,7 @@ int DetectFastPatternTest575(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; depth:30; sid:1;)"); @@ -16082,7 +16065,7 @@ int DetectFastPatternTest576(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); @@ -16114,7 +16097,7 @@ int DetectFastPatternTest577(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); @@ -16146,7 +16129,7 @@ int DetectFastPatternTest578(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); @@ -16178,7 +16161,7 @@ int DetectFastPatternTest579(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); @@ -16213,7 +16196,7 @@ int DetectFastPatternTest580(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:65977,4; http_user_agent; " "content:\"three\"; http_user_agent; distance:10; sid:1;)"); @@ -16237,7 +16220,7 @@ int DetectFastPatternTest581(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_user_agent; " "content:\"three\"; distance:10; http_user_agent; sid:1;)"); @@ -16261,7 +16244,7 @@ int DetectFastPatternTest582(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:65534,4; http_user_agent; " "content:\"three\"; http_user_agent; distance:10; sid:1;)"); @@ -16285,7 +16268,7 @@ int DetectFastPatternTest583(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -16318,7 +16301,7 @@ int DetectFastPatternTest584(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; distance:10; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -16342,7 +16325,7 @@ int DetectFastPatternTest585(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; within:10; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -16366,7 +16349,7 @@ int DetectFastPatternTest586(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; offset:10; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -16390,7 +16373,7 @@ int DetectFastPatternTest587(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; depth:10; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -16414,7 +16397,7 @@ int DetectFastPatternTest588(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -16452,7 +16435,7 @@ int DetectFastPatternTest589(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); @@ -16489,7 +16472,7 @@ int DetectFastPatternTest590(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_host; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -16526,7 +16509,7 @@ int DetectFastPatternTest591(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_host; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -16559,7 +16542,7 @@ int DetectFastPatternTest592(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -16595,7 +16578,7 @@ int DetectFastPatternTest593(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -16631,7 +16614,7 @@ int DetectFastPatternTest594(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16654,7 +16637,7 @@ int DetectFastPatternTest595(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; distance:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16677,7 +16660,7 @@ int DetectFastPatternTest596(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16700,7 +16683,7 @@ int DetectFastPatternTest597(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; within:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16723,7 +16706,7 @@ int DetectFastPatternTest598(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16746,7 +16729,7 @@ int DetectFastPatternTest599(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; offset:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16769,7 +16752,7 @@ int DetectFastPatternTest600(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16792,7 +16775,7 @@ int DetectFastPatternTest601(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; depth:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16815,7 +16798,7 @@ int DetectFastPatternTest602(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16838,7 +16821,7 @@ int DetectFastPatternTest603(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_host; " "content:\"two\"; http_host; distance:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); @@ -16871,7 +16854,7 @@ int DetectFastPatternTest604(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; within:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); @@ -16903,7 +16886,7 @@ int DetectFastPatternTest605(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; offset:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); @@ -16935,7 +16918,7 @@ int DetectFastPatternTest606(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; depth:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); @@ -16967,7 +16950,7 @@ int DetectFastPatternTest607(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_host; " "content:\"two\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -16999,7 +16982,7 @@ int DetectFastPatternTest608(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17022,7 +17005,7 @@ int DetectFastPatternTest609(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17045,7 +17028,7 @@ int DetectFastPatternTest610(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17068,7 +17051,7 @@ int DetectFastPatternTest611(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17091,7 +17074,7 @@ int DetectFastPatternTest612(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); @@ -17123,7 +17106,7 @@ int DetectFastPatternTest613(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; distance:30; sid:1;)"); @@ -17155,7 +17138,7 @@ int DetectFastPatternTest614(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; within:30; sid:1;)"); @@ -17187,7 +17170,7 @@ int DetectFastPatternTest615(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; offset:30; sid:1;)"); @@ -17219,7 +17202,7 @@ int DetectFastPatternTest616(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; depth:30; sid:1;)"); @@ -17251,7 +17234,7 @@ int DetectFastPatternTest617(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); @@ -17283,7 +17266,7 @@ int DetectFastPatternTest618(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); @@ -17315,7 +17298,7 @@ int DetectFastPatternTest619(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); @@ -17347,7 +17330,7 @@ int DetectFastPatternTest620(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); @@ -17382,7 +17365,7 @@ int DetectFastPatternTest621(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:65977,4; http_host; " "content:\"three\"; http_host; distance:10; sid:1;)"); @@ -17406,7 +17389,7 @@ int DetectFastPatternTest622(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_host; " "content:\"three\"; distance:10; http_host; sid:1;)"); @@ -17430,7 +17413,7 @@ int DetectFastPatternTest623(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:65534,4; http_host; " "content:\"three\"; http_host; distance:10; sid:1;)"); @@ -17454,7 +17437,7 @@ int DetectFastPatternTest624(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); @@ -17487,7 +17470,7 @@ int DetectFastPatternTest625(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; distance:10; " "content:\"three\"; http_host; sid:1;)"); @@ -17511,7 +17494,7 @@ int DetectFastPatternTest626(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; within:10; " "content:\"three\"; http_host; sid:1;)"); @@ -17535,7 +17518,7 @@ int DetectFastPatternTest627(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; offset:10; " "content:\"three\"; http_host; sid:1;)"); @@ -17559,7 +17542,7 @@ int DetectFastPatternTest628(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; depth:10; " "content:\"three\"; http_host; sid:1;)"); @@ -17583,7 +17566,7 @@ int DetectFastPatternTest629(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); @@ -17621,7 +17604,7 @@ int DetectFastPatternTest630(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -17659,7 +17642,7 @@ int DetectFastPatternTest631(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_raw_host; nocase; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -17698,7 +17681,7 @@ int DetectFastPatternTest632(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_host; nocase; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -17733,7 +17716,7 @@ int DetectFastPatternTest633(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -17770,7 +17753,7 @@ int DetectFastPatternTest634(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -17807,7 +17790,7 @@ int DetectFastPatternTest635(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; distance:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17830,7 +17813,7 @@ int DetectFastPatternTest636(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; distance:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17853,7 +17836,7 @@ int DetectFastPatternTest637(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; within:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17876,7 +17859,7 @@ int DetectFastPatternTest638(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; within:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17899,7 +17882,7 @@ int DetectFastPatternTest639(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; offset:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17922,7 +17905,7 @@ int DetectFastPatternTest640(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; offset:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17945,7 +17928,7 @@ int DetectFastPatternTest641(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; depth:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17968,7 +17951,7 @@ int DetectFastPatternTest642(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; depth:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17991,7 +17974,7 @@ int DetectFastPatternTest643(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18014,7 +17997,7 @@ int DetectFastPatternTest644(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; distance:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); @@ -18048,7 +18031,7 @@ int DetectFastPatternTest645(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; within:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); @@ -18081,7 +18064,7 @@ int DetectFastPatternTest646(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; offset:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); @@ -18114,7 +18097,7 @@ int DetectFastPatternTest647(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; depth:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); @@ -18147,7 +18130,7 @@ int DetectFastPatternTest648(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_raw_host; nocase; " "content:\"two\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -18180,7 +18163,7 @@ int DetectFastPatternTest649(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; distance:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18203,7 +18186,7 @@ int DetectFastPatternTest650(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; within:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18226,7 +18209,7 @@ int DetectFastPatternTest651(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; offset:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18249,7 +18232,7 @@ int DetectFastPatternTest652(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; depth:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18272,7 +18255,7 @@ int DetectFastPatternTest653(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -18305,7 +18288,7 @@ int DetectFastPatternTest654(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; distance:30; nocase; sid:1;)"); @@ -18338,7 +18321,7 @@ int DetectFastPatternTest655(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; within:30; nocase; sid:1;)"); @@ -18371,7 +18354,7 @@ int DetectFastPatternTest656(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; offset:30; nocase; sid:1;)"); @@ -18404,7 +18387,7 @@ int DetectFastPatternTest657(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; depth:30; nocase; sid:1;)"); @@ -18437,7 +18420,7 @@ int DetectFastPatternTest658(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; distance:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); @@ -18470,7 +18453,7 @@ int DetectFastPatternTest659(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; within:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); @@ -18503,7 +18486,7 @@ int DetectFastPatternTest660(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; offset:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); @@ -18536,7 +18519,7 @@ int DetectFastPatternTest661(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; depth:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); @@ -18572,7 +18555,7 @@ int DetectFastPatternTest662(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:65977,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; distance:10; nocase; sid:1;)"); @@ -18596,7 +18579,7 @@ int DetectFastPatternTest663(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_raw_host; nocase; " "content:\"three\"; distance:10; http_raw_host; nocase; sid:1;)"); @@ -18620,7 +18603,7 @@ int DetectFastPatternTest664(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:65534,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; distance:10; nocase; sid:1;)"); @@ -18644,7 +18627,7 @@ int DetectFastPatternTest665(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -18678,7 +18661,7 @@ int DetectFastPatternTest666(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; distance:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -18702,7 +18685,7 @@ int DetectFastPatternTest667(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; within:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -18726,7 +18709,7 @@ int DetectFastPatternTest668(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; offset:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -18750,7 +18733,7 @@ int DetectFastPatternTest669(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; depth:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -18774,7 +18757,7 @@ int DetectFastPatternTest670(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index 5971ed3d5681..e1337e59ca61 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -1802,7 +1802,7 @@ int DetectHttpServerBodyTest22(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; http_server_body; " "content:\"three\"; distance:10; http_server_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -1857,7 +1857,7 @@ int DetectHttpServerBodyTest23(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; http_server_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -1911,7 +1911,7 @@ int DetectHttpServerBodyTest24(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; within:15; http_server_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -1965,7 +1965,7 @@ int DetectHttpServerBodyTest25(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; http_server_body; " "content:\"four\"; distance:10; sid:1;)"); @@ -2021,7 +2021,7 @@ int DetectHttpServerBodyTest26(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; offset:10; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; http_server_body; within:10; " "content:\"four\"; distance:10; sid:1;)"); @@ -2078,7 +2078,7 @@ int DetectHttpServerBodyTest27(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; offset:10; http_server_body; pcre:/two/; distance:10; " "content:\"three\"; distance:10; http_server_body; depth:10; " "content:\"four\"; distance:10; sid:1;)"); @@ -2104,7 +2104,7 @@ int DetectHttpServerBodyTest28(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; http_server_body; depth:10; " "content:\"four\"; distance:10; sid:1;)"); @@ -2160,7 +2160,7 @@ int DetectHttpServerBodyTest29(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; distance:0; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -2204,7 +2204,7 @@ int DetectHttpServerBodyTest30(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; within:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -2248,7 +2248,7 @@ int DetectHttpServerBodyTest31(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; within:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); @@ -2272,7 +2272,7 @@ int DetectHttpServerBodyTest32(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); @@ -2296,7 +2296,7 @@ int DetectHttpServerBodyTest33(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); @@ -2320,7 +2320,7 @@ int DetectHttpServerBodyTest34(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/Q; " "content:\"two\"; within:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -2371,7 +2371,7 @@ int DetectHttpServerBodyTest35(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_server_body; " "pcre:/one/QR; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -2422,7 +2422,7 @@ int DetectHttpServerBodyTest36(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/Q; " "content:\"two\"; distance:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -2490,7 +2490,6 @@ static int DetectHttpServerBodyFileDataTest01(void) "\r\n" "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; - int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); @@ -2513,74 +2512,43 @@ static int DetectHttpServerBodyFileDataTest01(void) StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "file_data; content:\"message\"; " "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; + FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER | STREAM_START | STREAM_EOF, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } + FAIL_IF(r != 0); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT | STREAM_START | STREAM_EOF, http_buf2, http_len2); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - + FAIL_IF(r != 0); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } + FAIL_IF_NULL(http_state); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 1))); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; } /** From 859cb89c7e573722c745acebf23dceb3240c9ece Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 16 Oct 2016 11:29:23 +0200 Subject: [PATCH 2340/2553] detect alert/threshold/tag: sm_list -> sm_array --- src/detect-engine-alert.c | 39 +++++++++++++++++++---------------- src/detect-engine-threshold.c | 29 +++++++++++++++++--------- src/detect-engine-threshold.h | 2 +- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index 8bfd719f75ad..5187bf9f3cbc 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -72,18 +72,18 @@ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det SCEnter(); int ret = 1; const DetectThresholdData *td = NULL; - const SigMatch *sm; + const SigMatchData *smd; if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) { SCReturnInt(1); } /* handle suppressions first */ - if (s->sm_lists[DETECT_SM_LIST_SUPPRESS] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_SUPPRESS] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_SUPPRESS); - sm = NULL; + smd = NULL; do { - td = SigGetThresholdTypeIter(s, p, &sm, DETECT_SM_LIST_SUPPRESS); + td = SigGetThresholdTypeIter(s, p, &smd, DETECT_SM_LIST_SUPPRESS); if (td != NULL) { SCLogDebug("td %p", td); @@ -98,15 +98,15 @@ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det } KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 1); } - } while (sm != NULL); + } while (smd != NULL); } /* if we're still here, consider thresholding */ - if (s->sm_lists[DETECT_SM_LIST_THRESHOLD] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_THRESHOLD] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_THRESHOLD); - sm = NULL; + smd = NULL; do { - td = SigGetThresholdTypeIter(s, p, &sm, DETECT_SM_LIST_THRESHOLD); + td = SigGetThresholdTypeIter(s, p, &smd, DETECT_SM_LIST_THRESHOLD); if (td != NULL) { SCLogDebug("td %p", td); @@ -121,7 +121,7 @@ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det } KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 1); } - } while (sm != NULL); + } while (smd != NULL); } SCReturnInt(1); } @@ -240,7 +240,6 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx { SCEnter(); int i = 0; - SigMatch *sm = NULL; while (i < p->alerts.cnt) { SCLogDebug("Sig->num: %"PRIu16, p->alerts.alerts[i].num); @@ -250,14 +249,18 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx if (res > 0) { /* Now, if we have an alert, we have to check if we want * to tag this session or src/dst host */ - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_TMATCH); - sm = s->sm_lists[DETECT_SM_LIST_TMATCH]; - while (sm) { - /* tags are set only for alerts */ - KEYWORD_PROFILING_START; - sigmatch_table[sm->type].Match(NULL, det_ctx, p, (Signature *)s, sm->ctx); - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - sm = sm->next; + if (s->sm_arrays[DETECT_SM_LIST_TMATCH] != NULL) { + KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_TMATCH); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_TMATCH]; + while (1) { + /* tags are set only for alerts */ + KEYWORD_PROFILING_START; + sigmatch_table[smd->type].Match(NULL, det_ctx, p, (Signature *)s, smd->ctx); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) + break; + smd++; + } } if (s->flags & SIG_FLAG_IPONLY) { diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index 6b0d21141f1c..27e84d8e9065 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -99,35 +99,44 @@ int ThresholdHostHasThreshold(Host *host) * */ const DetectThresholdData *SigGetThresholdTypeIter(const Signature *sig, - Packet *p, const SigMatch **psm, int list) + Packet *p, const SigMatchData **psm, int list) { - const SigMatch *sm = NULL; + const SigMatchData *smd = NULL; const DetectThresholdData *tsh = NULL; if (sig == NULL) return NULL; if (*psm == NULL) { - sm = sig->sm_lists_tail[list]; + smd = sig->sm_arrays[list]; } else { /* Iteration in progress, using provided value */ - sm = *psm; + smd = *psm; } if (p == NULL) return NULL; - while (sm != NULL) { - if (sm->type == DETECT_THRESHOLD || sm->type == DETECT_DETECTION_FILTER) { - tsh = (DetectThresholdData *)sm->ctx; - *psm = sm->prev; + while (1) { + if (smd->type == DETECT_THRESHOLD || + smd->type == DETECT_DETECTION_FILTER) + { + tsh = (DetectThresholdData *)smd->ctx; + + if (smd->is_last) { + *psm = NULL; + } else { + *psm = smd + 1; + } return tsh; } - sm = sm->prev; + if (smd->is_last) { + break; + } + smd++; } *psm = NULL; - return NULL; } diff --git a/src/detect-engine-threshold.h b/src/detect-engine-threshold.h index cef5f2058d89..76a0759d3549 100644 --- a/src/detect-engine-threshold.h +++ b/src/detect-engine-threshold.h @@ -34,7 +34,7 @@ int ThresholdHostStorageId(void); int ThresholdHostHasThreshold(Host *); const DetectThresholdData *SigGetThresholdTypeIter(const Signature *, - Packet *, const SigMatch **, int list); + Packet *, const SigMatchData **, int list); int PacketAlertThreshold(DetectEngineCtx *, DetectEngineThreadCtx *, const DetectThresholdData *, Packet *, const Signature *, PacketAlert *); From 715ff60087af4a09d36ac5e1656d9f25f61eff25 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 17 Oct 2016 17:30:23 +0200 Subject: [PATCH 2341/2553] detect: remove unused SIG_FLAG_INIT_PAYLOAD init_flag --- src/detect.c | 4 ---- src/detect.h | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/detect.c b/src/detect.c index d998e8db0d84..00b5dfece446 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3400,7 +3400,6 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) /* see if any sig is inspecting the packet payload */ } else if (SignatureIsInspectingPayload(de_ctx, tmp_s) == 1) { - tmp_s->init_flags |= SIG_FLAG_INIT_PAYLOAD; cnt_payload++; SCLogDebug("Signature %"PRIu32" is considered \"Payload inspecting\"", tmp_s->id); @@ -8384,9 +8383,6 @@ int SigTest40NoPayloadInspection02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - if (!(de_ctx->sig_list->init_flags & SIG_FLAG_INIT_PAYLOAD)) - result = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) diff --git a/src/detect.h b/src/detect.h index 8ff86974cdb6..fb05ac7a9b47 100644 --- a/src/detect.h +++ b/src/detect.h @@ -297,8 +297,7 @@ typedef struct DetectPort_ { #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 */ +#define SIG_FLAG_INIT_FIRST_IPPROTO_SEEN (1 << 4) /** < signature has seen the first ip_proto keyword */ /* signature mask flags */ #define SIG_MASK_REQUIRE_PAYLOAD (1<<0) From 5f7e096be487739b46940ae7330a2c5f0ec104c8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 11:54:34 +0200 Subject: [PATCH 2342/2553] detect: shrink inspect engine by using 'id' as state flag --- src/detect-engine-state.c | 14 +++++++------- src/detect-engine.c | 3 +-- src/detect.h | 3 +-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index fe7335a35e97..f130a5ca0094 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -538,7 +538,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, tx, tx_id); SCLogDebug("engine %p match %d", engine, match); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { - inspect_flags |= engine->inspect_flags; + inspect_flags |= BIT_U32(engine->id); engine = engine->next; total_matches++; continue; @@ -551,10 +551,10 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, continue; } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; + inspect_flags |= BIT_U32(engine->id);; } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; + inspect_flags |= BIT_U32(engine->id); file_no_match++; } break; @@ -854,7 +854,7 @@ static int DoInspectItem(ThreadVars *tv, } while (engine != NULL) { - if (!(item->flags & engine->inspect_flags) && + if (!(item->flags & BIT_U32(engine->id)) && direction == engine->dir) { SCLogDebug("inspect_flags %x", inspect_flags); @@ -862,7 +862,7 @@ static int DoInspectItem(ThreadVars *tv, int match = engine->Callback(tv, de_ctx, det_ctx, s, f, flags, alstate, inspect_tx, inspect_tx_id); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { - inspect_flags |= engine->inspect_flags; + inspect_flags |= BIT_U32(engine->id); engine = engine->next; total_matches++; continue; @@ -875,10 +875,10 @@ static int DoInspectItem(ThreadVars *tv, continue; } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; + inspect_flags |= BIT_U32(engine->id); } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; + inspect_flags |= BIT_U32(engine->id); (*file_no_match)++; } break; diff --git a/src/detect-engine.c b/src/detect-engine.c index 06893021b854..b1f06cc0b54e 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -178,7 +178,7 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) if (s->app_inspect == NULL) { s->app_inspect = new_engine; - new_engine->inspect_flags = BIT_U32(DE_STATE_FLAG_BASE); // start beyond the built-ins + new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */ } else { DetectEngineAppInspectionEngine *a = s->app_inspect; while (a->next != NULL) { @@ -187,7 +187,6 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) a->next = new_engine; new_engine->id = a->id + 1; - new_engine->inspect_flags = BIT_U32(new_engine->id + DE_STATE_FLAG_BASE); } SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id); diff --git a/src/detect.h b/src/detect.h index fb05ac7a9b47..66951f6a5297 100644 --- a/src/detect.h +++ b/src/detect.h @@ -378,9 +378,8 @@ struct DetectEngineThreadCtx_;// DetectEngineThreadCtx; typedef struct DetectEngineAppInspectionEngine_ { AppProto alproto; uint8_t dir; - uint8_t id; + uint8_t id; /**< per sig id used in state keeping */ int sm_list; - uint32_t inspect_flags; /* \retval 0 No match. Don't discontinue matching yet. We need more data. * 1 Match. From cf42fbf51f25d7466ea304963d3319e5eccb7391 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 12:09:47 +0200 Subject: [PATCH 2343/2553] detect: use InspectEngineFuncPtr in inspect engines Replace explicit function pointer use by InspectEngineFuncPtr typedef --- src/detect-engine.c | 8 +------- src/detect-engine.h | 9 +-------- src/detect.h | 10 ++++++---- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index b1f06cc0b54e..be0a15e854be 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -102,13 +102,7 @@ static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet * static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL; void DetectAppLayerInspectEngineRegister(AppProto alproto, - uint32_t dir, int32_t sm_list, - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id)) + uint32_t dir, int32_t sm_list, InspectEngineFuncPtr Callback) { if ((alproto >= ALPROTO_FAILED) || (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) || diff --git a/src/detect-engine.h b/src/detect-engine.h index 498dd22d8a41..935a3d79e396 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -84,14 +84,7 @@ int DetectEngineInspectGenericList(ThreadVars *, const DetectEngineCtx *, * \param Callback The engine callback. */ void DetectAppLayerInspectEngineRegister(AppProto alproto, - uint32_t dir, - int32_t sm_list, - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id)); + uint32_t dir, int32_t sm_list, InspectEngineFuncPtr Callback); int DetectEngineAppInspectionEngine2Signature(Signature *s); diff --git a/src/detect.h b/src/detect.h index 66951f6a5297..72280b6ead95 100644 --- a/src/detect.h +++ b/src/detect.h @@ -375,6 +375,11 @@ typedef struct SigMatchData_ { struct DetectEngineThreadCtx_;// DetectEngineThreadCtx; +typedef int (*InspectEngineFuncPtr)(ThreadVars *tv, + struct DetectEngineCtx_ *de_ctx, struct DetectEngineThreadCtx_ *det_ctx, + const struct Signature_ *sig, Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id); + typedef struct DetectEngineAppInspectionEngine_ { AppProto alproto; uint8_t dir; @@ -387,10 +392,7 @@ typedef struct DetectEngineAppInspectionEngine_ { * 3 Special value used by filestore sigs to indicate disabling * filestore for the tx. */ - int (*Callback)(ThreadVars *tv, - struct DetectEngineCtx_ *de_ctx, struct DetectEngineThreadCtx_ *det_ctx, - const struct Signature_ *sig, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); + InspectEngineFuncPtr Callback; struct DetectEngineAppInspectionEngine_ *next; } DetectEngineAppInspectionEngine; From 2f87c975d479e2894c35c56fb6c1bcbce4a3fb11 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 14:10:23 +0200 Subject: [PATCH 2344/2553] detect: add SigMatch arg to inspect functions --- src/detect-app-layer-event.c | 19 +++++++-------- src/detect-dnp3.c | 8 +++---- src/detect-engine-dns.c | 22 ++++++++--------- src/detect-engine-dns.h | 21 ++++++++--------- src/detect-engine-enip.c | 12 ++++++---- src/detect-engine-enip.h | 14 ++++++----- src/detect-engine-file.c | 12 +++++----- src/detect-engine-file.h | 14 +++++------ src/detect-engine-filedata-smtp.c | 8 +++---- src/detect-engine-filedata-smtp.h | 9 ++++--- src/detect-engine-hcbd.c | 7 +++--- src/detect-engine-hcbd.h | 9 ++++--- src/detect-engine-hcd.c | 8 +++---- src/detect-engine-hcd.h | 8 +++---- src/detect-engine-hhd.c | 8 +++---- src/detect-engine-hhd.h | 9 ++++--- src/detect-engine-hhhd.c | 8 +++---- src/detect-engine-hhhd.h | 8 +++---- src/detect-engine-hmd.c | 8 +++---- src/detect-engine-hmd.h | 8 +++---- src/detect-engine-hrhd.c | 8 +++---- src/detect-engine-hrhd.h | 9 ++++--- src/detect-engine-hrhhd.c | 8 +++---- src/detect-engine-hrhhd.h | 8 +++---- src/detect-engine-hrud.c | 8 +++---- src/detect-engine-hrud.h | 9 ++++--- src/detect-engine-hsbd.c | 8 +++---- src/detect-engine-hsbd.h | 10 ++++---- src/detect-engine-hscd.c | 8 +++---- src/detect-engine-hscd.h | 9 ++++--- src/detect-engine-hsmd.c | 8 +++---- src/detect-engine-hsmd.h | 9 ++++--- src/detect-engine-hua.c | 8 +++---- src/detect-engine-hua.h | 8 +++---- src/detect-engine-modbus.c | 1 + src/detect-engine-modbus.h | 7 +++--- src/detect-engine-state.c | 10 ++++---- src/detect-engine-template.c | 7 +++--- src/detect-engine-template.h | 7 +++--- src/detect-engine-tls.c | 33 +++++++++++++------------- src/detect-engine-tls.h | 39 ++++++++++++++++--------------- src/detect-engine-uri.c | 8 +++---- src/detect-engine-uri.h | 9 ++++--- src/detect-http-request-line.c | 17 ++++++-------- src/detect-http-response-line.c | 16 +++++-------- src/detect.h | 5 +++- 46 files changed, 227 insertions(+), 270 deletions(-) diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index a7930dee85df..3447ab3813e5 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -56,11 +56,11 @@ static int DetectAppLayerEventSetupP1(DetectEngineCtx *, Signature *, char *); static void DetectAppLayerEventRegisterTests(void); static void DetectAppLayerEventFree(void *); static int DetectEngineAptEventInspect(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id); + /** * \brief Registers the keyword handlers for the "app-layer-event" keyword. */ @@ -87,11 +87,10 @@ void DetectAppLayerEventRegister(void) } static int DetectEngineAptEventInspect(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *smi, + Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id) { AppLayerDecoderEvents *decoder_events = NULL; int r = 0; diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 1a515905bb80..92922e8f05be 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -139,8 +139,8 @@ static char *TrimString(char *str) } static int DetectEngineInspectDNP3Data(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) + DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); DNP3Transaction *tx = (DNP3Transaction *)txv; @@ -163,8 +163,8 @@ static int DetectEngineInspectDNP3Data(ThreadVars *tv, DetectEngineCtx *de_ctx, } static int DetectEngineInspectDNP3(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) + DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, alstate, txv, tx_id, DETECT_SM_LIST_DNP3_MATCH); diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index b9a4ce39fa50..4b15996195f4 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -61,10 +61,10 @@ * \retval 1 match */ int DetectEngineInspectDnsQueryName(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) { DNSTransaction *tx = (DNSTransaction *)txv; DNSQueryEntry *query = NULL; @@ -139,10 +139,9 @@ int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) } int DetectEngineInspectDnsRequest(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, alstate, txv, tx_id, @@ -150,10 +149,9 @@ int DetectEngineInspectDnsRequest(ThreadVars *tv, } int DetectEngineInspectDnsResponse(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, alstate, txv, tx_id, diff --git a/src/detect-engine-dns.h b/src/detect-engine-dns.h index 56ebea25899c..be25eb3ac1cc 100644 --- a/src/detect-engine-dns.h +++ b/src/detect-engine-dns.h @@ -25,18 +25,17 @@ int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); -int DetectEngineInspectDnsQueryName(ThreadVars *, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *, const Signature *, - Flow *, uint8_t, void *, void *, uint64_t); +int DetectEngineInspectDnsQueryName(ThreadVars *, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, + const Signature *, const SigMatch *sm, + Flow *, uint8_t, void *, void *, uint64_t); int DetectEngineInspectDnsRequest(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); int DetectEngineInspectDnsResponse(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); #endif /* __DETECT_ENGINE_DNS_H__ */ diff --git a/src/detect-engine-enip.c b/src/detect-engine-enip.c index 8160d0bae5d8..814be1c02071 100644 --- a/src/detect-engine-enip.c +++ b/src/detect-engine-enip.c @@ -217,8 +217,9 @@ int CIPServiceMatch(ENIPTransaction *enip_data, * * \retval 0 no match or 1 match */ -int DetectEngineInspectCIP(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, +int DetectEngineInspectCIP(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *smi, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); @@ -257,9 +258,10 @@ int DetectEngineInspectCIP(ThreadVars *tv, DetectEngineCtx *de_ctx, * \retval 0 no match or 1 match */ -int DetectEngineInspectENIP(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) +int DetectEngineInspectENIP(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *smi, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); diff --git a/src/detect-engine-enip.h b/src/detect-engine-enip.h index 9e0e719d850b..eb55917d2c75 100644 --- a/src/detect-engine-enip.h +++ b/src/detect-engine-enip.h @@ -23,13 +23,15 @@ #ifndef __DETECT_ENGINE_ENIP_H__ #define __DETECT_ENGINE_ENIP_H__ -int DetectEngineInspectCIP(ThreadVars *, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *, const Signature *, - Flow *, uint8_t, void *, void *, uint64_t); +int DetectEngineInspectCIP(ThreadVars *, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, + const Signature *, const SigMatch *sm, + Flow *, uint8_t, void *, void *, uint64_t); -int DetectEngineInspectENIP(ThreadVars *, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *, const Signature *, - Flow *, uint8_t, void *, void *, uint64_t); +int DetectEngineInspectENIP(ThreadVars *, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, + const Signature *, const SigMatch *sm, + Flow *, uint8_t, void *, void *, uint64_t); void DetectEngineInspectENIPRegisterTests(void); #endif /* __DETECT_ENGINE_ENIP_H__ */ diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index 9b9462ab5dda..588c72fbbf79 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -229,9 +229,9 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, * \note flow should be locked when this function's called. */ int DetectFileInspectHttp(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { int r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; FileContainer *ffc; @@ -274,9 +274,9 @@ int DetectFileInspectHttp(ThreadVars *tv, * \note flow is not locked at this time */ int DetectFileInspectSmtp(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { SCEnter(); int r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; diff --git a/src/detect-engine-file.h b/src/detect-engine-file.h index 4934ed0a2cbf..f7ea8405f18f 100644 --- a/src/detect-engine-file.h +++ b/src/detect-engine-file.h @@ -25,13 +25,13 @@ #define __DETECT_ENGINE_FILE_H__ int DetectFileInspectHttp(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); -int DetectFileInspectSmtp(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, - Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); +int DetectFileInspectSmtp(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); #endif /* __DETECT_ENGINE_FILE_H__ */ diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 4635ad10ee22..fa27c4c90e5e 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -174,11 +174,9 @@ static const uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, } int DetectEngineInspectSMTPFiledata(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { SMTPState *smtp_state = (SMTPState *)alstate; FileContainer *ffc = smtp_state->files_ts; diff --git a/src/detect-engine-filedata-smtp.h b/src/detect-engine-filedata-smtp.h index d659e2224162..f9c55e3222ef 100644 --- a/src/detect-engine-filedata-smtp.h +++ b/src/detect-engine-filedata-smtp.h @@ -28,11 +28,10 @@ int PrefilterTxSmtpFiledataRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectSMTPFiledata(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx); void DetectEngineSMTPFiledataRegisterTests(void); diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 62d12517cb44..aad694a68c0a 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -257,10 +257,9 @@ int PrefilterTxHttpRequestBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) } int DetectEngineInspectHttpClientBody(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, void *tx, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; diff --git a/src/detect-engine-hcbd.h b/src/detect-engine-hcbd.h index c990bb083dc9..2cdc3e77f9ba 100644 --- a/src/detect-engine-hcbd.h +++ b/src/detect-engine-hcbd.h @@ -30,11 +30,10 @@ int PrefilterTxHttpRequestBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpClientBody(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineCleanHCBDBuffers(DetectEngineThreadCtx *); void DetectEngineHttpClientBodyRegisterTests(void); diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index 4be2ba6903f7..7bee6534b8de 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -166,11 +166,9 @@ int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 Match. */ int DetectEngineInspectHttpCookie(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; htp_header_t *h = NULL; diff --git a/src/detect-engine-hcd.h b/src/detect-engine-hcd.h index 9ed0e6c1d758..621d722801fe 100644 --- a/src/detect-engine-hcd.h +++ b/src/detect-engine-hcd.h @@ -29,11 +29,9 @@ int PrefilterTxRequestCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpCookie(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpCookieRegisterTests(void); diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 41cb22d1ffb9..5586db41dd5a 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -382,11 +382,9 @@ int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) } int DetectEngineInspectHttpHeader(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; diff --git a/src/detect-engine-hhd.h b/src/detect-engine-hhd.h index e0da35b186cd..41e6c5252f66 100644 --- a/src/detect-engine-hhd.h +++ b/src/detect-engine-hhd.h @@ -29,11 +29,10 @@ int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpHeader(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx); void DetectEngineHttpHeaderRegisterTests(void); diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 5c53ef7097da..619136e0ff37 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -115,11 +115,9 @@ int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 Match. */ int DetectEngineInspectHttpHH(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->parsed_uri == NULL || tx->request_hostname == NULL) diff --git a/src/detect-engine-hhhd.h b/src/detect-engine-hhhd.h index 932a38f6d4f6..04c2cf0be8dc 100644 --- a/src/detect-engine-hhhd.h +++ b/src/detect-engine-hhhd.h @@ -28,11 +28,9 @@ int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpHH(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpHHRegisterTests(void); diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 31df7e24ae98..74b004c737ac 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -112,11 +112,9 @@ int PrefilterTxMethodRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 Match. */ int DetectEngineInspectHttpMethod(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->request_method == NULL) { diff --git a/src/detect-engine-hmd.h b/src/detect-engine-hmd.h index cf40eeba617c..71f2009b6401 100644 --- a/src/detect-engine-hmd.h +++ b/src/detect-engine-hmd.h @@ -26,11 +26,9 @@ #include "app-layer-htp.h" int DetectEngineInspectHttpMethod(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); int PrefilterTxMethodRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 526c6b1424ce..8f7ad5a9f3f2 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -163,11 +163,9 @@ int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 Match. */ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { HtpTxUserData *tx_ud = NULL; uint8_t *headers_raw = NULL; diff --git a/src/detect-engine-hrhd.h b/src/detect-engine-hrhd.h index 99c379b225bd..b6deda862753 100644 --- a/src/detect-engine-hrhd.h +++ b/src/detect-engine-hrhd.h @@ -29,11 +29,10 @@ int PrefilterTxRequestHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpRawHeader(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpRawHeaderRegisterTests(void); #endif /* __DETECT_ENGINE_HHD_H__ */ diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index d6b265235de4..d9e79f7604b6 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -127,11 +127,9 @@ int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 Match. */ int DetectEngineInspectHttpHRH(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { uint8_t *hname; uint32_t hname_len; diff --git a/src/detect-engine-hrhhd.h b/src/detect-engine-hrhhd.h index 30aec3b8c702..e45b8b3bf501 100644 --- a/src/detect-engine-hrhhd.h +++ b/src/detect-engine-hrhhd.h @@ -28,11 +28,9 @@ int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpHRH(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpHRHRegisterTests(void); diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 876dcc5e806e..811092c28e90 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -112,11 +112,9 @@ int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 Match. */ int DetectEngineInspectHttpRawUri(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->request_uri == NULL) { diff --git a/src/detect-engine-hrud.h b/src/detect-engine-hrud.h index 4b7933badcf5..10137d6d2bfe 100644 --- a/src/detect-engine-hrud.h +++ b/src/detect-engine-hrud.h @@ -29,11 +29,10 @@ int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpRawUri(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpRawUriRegisterTests(void); #endif /* __DETECT_ENGINE_HRUD_H__ */ diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 84856fc51bf9..326f834f6e1c 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -262,11 +262,9 @@ int PrefilterTxHttpResponseBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpServerBody(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; diff --git a/src/detect-engine-hsbd.h b/src/detect-engine-hsbd.h index 0512ba46615e..7126aabb2ca0 100644 --- a/src/detect-engine-hsbd.h +++ b/src/detect-engine-hsbd.h @@ -30,11 +30,11 @@ int PrefilterTxHttpResponseBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpServerBody(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id); + void DetectEngineCleanHSBDBuffers(DetectEngineThreadCtx *det_ctx); void DetectEngineHttpServerBodyRegisterTests(void); diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index e9354a91b882..77ea0632cf8c 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -111,11 +111,9 @@ int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 Match. */ int DetectEngineInspectHttpStatCode(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->response_status == NULL) { diff --git a/src/detect-engine-hscd.h b/src/detect-engine-hscd.h index 390abf5b9b04..bdcc0cfc0cd3 100644 --- a/src/detect-engine-hscd.h +++ b/src/detect-engine-hscd.h @@ -28,11 +28,10 @@ int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpStatCode(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpStatCodeRegisterTests(void); #endif /* __DETECT_ENGINE_HSCD_H__ */ diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 4bee372dbc0e..7cecf37d6b06 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -111,11 +111,9 @@ int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 Match. */ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->response_message == NULL) { diff --git a/src/detect-engine-hsmd.h b/src/detect-engine-hsmd.h index 075d34d7132e..fd48176ecef0 100644 --- a/src/detect-engine-hsmd.h +++ b/src/detect-engine-hsmd.h @@ -28,11 +28,10 @@ int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpStatMsg(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpStatMsgRegisterTests(void); #endif /* __DETECT_ENGINE_HSMD_H__ */ diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index 1cc2a394189e..18f716f234b3 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -120,11 +120,9 @@ int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 1 Match. */ int DetectEngineInspectHttpUA(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, diff --git a/src/detect-engine-hua.h b/src/detect-engine-hua.h index 499539ee92b4..fba2d8845832 100644 --- a/src/detect-engine-hua.h +++ b/src/detect-engine-hua.h @@ -28,11 +28,9 @@ int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpUA(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpUARegisterTests(void); diff --git a/src/detect-engine-modbus.c b/src/detect-engine-modbus.c index e08cde10d7ce..102ffe39cd49 100644 --- a/src/detect-engine-modbus.c +++ b/src/detect-engine-modbus.c @@ -200,6 +200,7 @@ int DetectEngineInspectModbus(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, + const SigMatch *smi, Flow *f, uint8_t flags, void *alstate, diff --git a/src/detect-engine-modbus.h b/src/detect-engine-modbus.h index ae0935c977a8..66a174c76049 100644 --- a/src/detect-engine-modbus.h +++ b/src/detect-engine-modbus.h @@ -33,9 +33,10 @@ #ifndef __DETECT_ENGINE_MODBUS_H__ #define __DETECT_ENGINE_MODBUS_H__ -int DetectEngineInspectModbus(ThreadVars *, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *, const Signature *, - Flow *, uint8_t, void *, void *, uint64_t); +int DetectEngineInspectModbus(ThreadVars *, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, + const Signature *, const SigMatch *, + Flow *, uint8_t, void *, void *, uint64_t); void DetectEngineInspectModbusRegisterTests(void); #endif /* __DETECT_ENGINE_MODBUS_H__ */ diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index f130a5ca0094..82a40228e1ef 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -533,9 +533,8 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SCLogDebug("inspect_flags %x", inspect_flags); if (direction == engine->dir) { KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); - int match = engine->Callback(tv, de_ctx, det_ctx, s, f, - flags, alstate, - tx, tx_id); + int match = engine->Callback(tv, de_ctx, det_ctx, + s, engine->sm, f, flags, alstate, tx, tx_id); SCLogDebug("engine %p match %d", engine, match); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { inspect_flags |= BIT_U32(engine->id); @@ -859,8 +858,9 @@ static int DoInspectItem(ThreadVars *tv, { SCLogDebug("inspect_flags %x", inspect_flags); KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); - int match = engine->Callback(tv, de_ctx, det_ctx, s, f, - flags, alstate, inspect_tx, inspect_tx_id); + int match = engine->Callback(tv, de_ctx, det_ctx, + s, engine->sm, + f, flags, alstate, inspect_tx, inspect_tx_id); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { inspect_flags |= BIT_U32(engine->id); engine = engine->next; diff --git a/src/detect-engine-template.c b/src/detect-engine-template.c index 70785da1e340..9ad8ff5936e1 100644 --- a/src/detect-engine-template.c +++ b/src/detect-engine-template.c @@ -36,9 +36,10 @@ #include "app-layer-template.h" -int DetectEngineInspectTemplateBuffer(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) +int DetectEngineInspectTemplateBuffer(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { TemplateTransaction *tx = (TemplateTransaction *)txv; int ret = 0; diff --git a/src/detect-engine-template.h b/src/detect-engine-template.h index e1f39065bdb2..60bf5d47863f 100644 --- a/src/detect-engine-template.h +++ b/src/detect-engine-template.h @@ -24,8 +24,9 @@ #ifndef __DETECT_TEMPLATE_ENGINE_H__ #define __DETECT_TEMPLATE_ENGINE_H__ -int DetectEngineInspectTemplateBuffer(ThreadVars *, DetectEngineCtx *, - DetectEngineThreadCtx *, const Signature *, Flow *, uint8_t, void *, void *, - uint64_t); +int DetectEngineInspectTemplateBuffer(ThreadVars *, + DetectEngineCtx *, DetectEngineThreadCtx *, + const Signature *, const SigMatch *, + Flow *, uint8_t, void *, void *tx, uint64_t tx_id); #endif /* __DETECT_TEMPLATE_ENGINE_H__ */ diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index e3e7881e0210..e488fd330162 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -97,10 +97,10 @@ int PrefilterTxTlsSniRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 0 No match * \retval 1 Match */ -int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, - Flow *f, uint8_t flags, void *alstate, void *txv, - uint64_t tx_id) +int DetectEngineInspectTlsSni(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { uint8_t *buffer; uint16_t buffer_len; @@ -173,10 +173,10 @@ int PrefilterTxTlsIssuerRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 0 No match * \retval 1 Match */ -int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, - Flow *f, uint8_t flags, void *alstate, void *txv, - uint64_t tx_id) +int DetectEngineInspectTlsIssuer(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { uint8_t *buffer; uint32_t buffer_len; @@ -249,10 +249,10 @@ int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 0 No match * \retval 1 Match */ -int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, - Flow *f, uint8_t flags, void *alstate, void *txv, - uint64_t tx_id) +int DetectEngineInspectTlsSubject(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { uint8_t *buffer; uint32_t buffer_len; @@ -274,10 +274,11 @@ int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, return cnt; } -int DetectEngineInspectTlsValidity(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, - Flow *f, uint8_t flags, void *alstate, - void *txv, uint64_t tx_id) +int DetectEngineInspectTlsValidity(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) { return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, alstate, txv, tx_id, diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h index e35281caf31e..4172b4a04391 100644 --- a/src/detect-engine-tls.h +++ b/src/detect-engine-tls.h @@ -27,24 +27,25 @@ int PrefilterTxTlsSniRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int PrefilterTxTlsIssuerRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); -int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id); - -int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id); - -int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id); - -int DetectEngineInspectTlsValidity(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id); +int DetectEngineInspectTlsSni(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); + +int DetectEngineInspectTlsIssuer(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); + +int DetectEngineInspectTlsSubject(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); + +int DetectEngineInspectTlsValidity(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); #endif /* __DETECT_ENGINE_TLS_H__ */ diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index 9058afba1415..7f8a46fd80e9 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -105,11 +105,9 @@ int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) * \retval 2 Sig can't match. */ int DetectEngineInspectHttpUri(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { HtpTxUserData *tx_ud = htp_tx_get_user_data(txv); diff --git a/src/detect-engine-uri.h b/src/detect-engine-uri.h index bc5933aa0d54..4760dd184de7 100644 --- a/src/detect-engine-uri.h +++ b/src/detect-engine-uri.h @@ -27,11 +27,10 @@ int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpUri(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void UriRegisterTests(void); #endif /* __DETECT_ENGINE_URICONTENT_H__ */ diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 6e316f568f84..057f84a51486 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -65,11 +65,10 @@ void DetectHttpRequestLineRegisterTests(void); void DetectHttpRequestLineFree(void *); static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); + /** * \brief Registers the keyword handlers for the "http_request_line" keyword. */ @@ -172,11 +171,9 @@ static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx * \retval 2 Sig can't match. */ static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index 606c74074688..04f7a8e53984 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -65,11 +65,9 @@ void DetectHttpResponseLineRegisterTests(void); void DetectHttpResponseLineFree(void *); static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); static int DetectEngineInspectHttpResponseLine(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); /** * \brief Registers the keyword handlers for the "http_response_line" keyword. @@ -173,11 +171,9 @@ static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ct * \retval 2 Sig can't match. */ int DetectEngineInspectHttpResponseLine(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatch *sm, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; diff --git a/src/detect.h b/src/detect.h index 72280b6ead95..a9617a6b0392 100644 --- a/src/detect.h +++ b/src/detect.h @@ -377,7 +377,8 @@ struct DetectEngineThreadCtx_;// DetectEngineThreadCtx; typedef int (*InspectEngineFuncPtr)(ThreadVars *tv, struct DetectEngineCtx_ *de_ctx, struct DetectEngineThreadCtx_ *det_ctx, - const struct Signature_ *sig, Flow *f, uint8_t flags, void *alstate, + const struct Signature_ *sig, const SigMatch *sm_list, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); typedef struct DetectEngineAppInspectionEngine_ { @@ -394,6 +395,8 @@ typedef struct DetectEngineAppInspectionEngine_ { */ InspectEngineFuncPtr Callback; + SigMatch *sm; + struct DetectEngineAppInspectionEngine_ *next; } DetectEngineAppInspectionEngine; From f81b90dacd7fb11b3f34342285ee197352838ea4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 16:26:37 +0200 Subject: [PATCH 2345/2553] detect: when freeing sig also see sm in inspect engine --- src/detect-parse.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/detect-parse.c b/src/detect-parse.c index b49ee57fcf0e..a896e8bc2a2f 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1060,9 +1060,9 @@ void SigFree(Signature *s) int i; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { - SigMatch *sm = s->sm_lists[i], *nsm; + SigMatch *sm = s->sm_lists[i]; while (sm != NULL) { - nsm = sm->next; + SigMatch *nsm = sm->next; SigMatchFree(sm); sm = nsm; } @@ -1097,6 +1097,12 @@ void SigFree(Signature *s) DetectEngineAppInspectionEngine *ie = s->app_inspect; while (ie) { DetectEngineAppInspectionEngine *next = ie->next; + SigMatch *sm = ie->sm; + while (sm != NULL) { + SigMatch *nsm = sm->next; + SigMatchFree(sm); + sm = nsm; + } SCFree(ie); ie = next; } From 1ee32da2ca21a931b5e183fa7e43d8fc80bf5b83 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 18:15:17 +0200 Subject: [PATCH 2346/2553] detect-engine: memory handling of sm_lists For lists that are registered multiple times, like http_header and http_cookie, making the engines owner of the lists is complicated. Multiple engines in a sig may be pointing to the same list. To address this the 'free' code needs to be extra careful about not double freeing, so it takes an approach to first fill an array of the to-free pointers before freeing them. --- src/detect-engine.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/detect-engine.h | 1 + src/detect-parse.c | 13 +------------ 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index be0a15e854be..dad076c42a83 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -144,6 +144,8 @@ void DetectAppLayerInspectEngineRegister(AppProto alproto, int DetectEngineAppInspectionEngine2Signature(Signature *s) { + int lists_used[DETECT_SM_LIST_MAX] = { 0 }; + DetectEngineAppInspectionEngine *t = g_app_inspect_engines; while (t != NULL) { if (s->sm_lists[t->sm_list] == NULL) @@ -189,9 +191,51 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) t = t->next; } + int i; + for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + if (lists_used[i]) { + s->sm_lists[i] = NULL; + s->sm_lists_tail[i] = NULL; + } + } + return 0; } +/** \brief free app inspect engines for a signature + * + * For lists that are registered multiple times, like http_header and + * http_cookie, making the engines owner of the lists is complicated. + * Multiple engines in a sig may be pointing to the same list. To + * address this the 'free' code needs to be extra careful about not + * double freeing, so it takes an approach to first fill an array + * of the to-free pointers before freeing them. + */ +void DetectEngineAppInspectionEngineSignatureFree(Signature *s) +{ + SigMatch *ptrs[DETECT_SM_LIST_MAX] = { NULL }; + + DetectEngineAppInspectionEngine *ie = s->app_inspect; + while (ie) { + DetectEngineAppInspectionEngine *next = ie->next; + BUG_ON(ptrs[ie->sm_list] != NULL && ptrs[ie->sm_list] != ie->sm); + ptrs[ie->sm_list] = ie->sm; + SCFree(ie); + ie = next; + } + + int i; + for (i = 0; i < DETECT_SM_LIST_MAX; i++) + { + SigMatch *sm = ptrs[i]; + while (sm != NULL) { + SigMatch *nsm = sm->next; + SigMatchFree(sm); + sm = nsm; + } + } +} + /* code to control the main thread to do a reload */ enum DetectEngineSyncState { diff --git a/src/detect-engine.h b/src/detect-engine.h index 935a3d79e396..378706187fbd 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -87,5 +87,6 @@ void DetectAppLayerInspectEngineRegister(AppProto alproto, uint32_t dir, int32_t sm_list, InspectEngineFuncPtr Callback); int DetectEngineAppInspectionEngine2Signature(Signature *s); +void DetectEngineAppInspectionEngineSignatureFree(Signature *s); #endif /* __DETECT_ENGINE_H__ */ diff --git a/src/detect-parse.c b/src/detect-parse.c index a896e8bc2a2f..76dc039706cc 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1094,18 +1094,7 @@ void SigFree(Signature *s) SigRefFree(s); - DetectEngineAppInspectionEngine *ie = s->app_inspect; - while (ie) { - DetectEngineAppInspectionEngine *next = ie->next; - SigMatch *sm = ie->sm; - while (sm != NULL) { - SigMatch *nsm = sm->next; - SigMatchFree(sm); - sm = nsm; - } - SCFree(ie); - ie = next; - } + DetectEngineAppInspectionEngineSignatureFree(s); SCFree(s); } From 5a2e5683858ddd152697db740c97dcd81fe5a74a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 14:57:39 +0200 Subject: [PATCH 2347/2553] detect: http lists in engine --- src/detect-engine-filedata-smtp.c | 2 +- src/detect-engine-hcbd.c | 2 +- src/detect-engine-hcd.c | 2 +- src/detect-engine-hhd.c | 7 ++---- src/detect-engine-hhhd.c | 2 +- src/detect-engine-hmd.c | 2 +- src/detect-engine-hrhd.c | 2 +- src/detect-engine-hrhhd.c | 2 +- src/detect-engine-hrud.c | 2 +- src/detect-engine-hsbd.c | 2 +- src/detect-engine-hscd.c | 3 +-- src/detect-engine-hsmd.c | 3 +-- src/detect-engine-hua.c | 2 +- src/detect-engine-uri.c | 2 +- src/detect-engine.c | 25 +++++++++++++++++++++ src/detect-http-request-line.c | 2 +- src/detect-http-response-line.c | 2 +- src/detect-uricontent.c | 37 +++++++------------------------ 18 files changed, 50 insertions(+), 51 deletions(-) diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index fa27c4c90e5e..6b1049cdbaf4 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -201,7 +201,7 @@ int DetectEngineInspectSMTPFiledata(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - match = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_FILEDATA], + match = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, (uint8_t *)buffer, buffer_len, diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index aad694a68c0a..34b0bd7d0087 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -276,7 +276,7 @@ int DetectEngineInspectHttpClientBody(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HCBDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, (uint8_t *)buffer, buffer_len, diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index 7bee6534b8de..c6243f7adfaf 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -191,7 +191,7 @@ int DetectEngineInspectHttpCookie(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HCDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 5586db41dd5a..3554e2a476d4 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -399,7 +399,7 @@ int DetectEngineInspectHttpHeader(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HHDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, buffer, buffer_len, @@ -3200,10 +3200,7 @@ static int DetectEngineHttpHeaderTest28(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } + FAIL_IF(!PacketAlertCheck(p2, 1)); result = 1; diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 619136e0ff37..198d975173db 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -130,7 +130,7 @@ int DetectEngineInspectHttpHH(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HHHDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, hname, hname_len, 0, diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 74b004c737ac..35cdc5969d05 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -127,7 +127,7 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HMDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method), diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 8f7ad5a9f3f2..50626399e4f6 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -195,7 +195,7 @@ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRHDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, headers_raw, headers_raw_len, diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index d9e79f7604b6..8b335cfcf97c 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -153,7 +153,7 @@ int DetectEngineInspectHttpHRH(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRHHDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, hname, hname_len, 0, diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 811092c28e90..e5a40b50b2fa 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -129,7 +129,7 @@ int DetectEngineInspectHttpRawUri(ThreadVars *tv, det_ctx->inspection_recursion_counter = 0; /* Inspect all the uricontents fetched on each * transaction at the app layer */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRUDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri), diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 326f834f6e1c..7f40e6ea28b8 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -281,7 +281,7 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_FILEDATA], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, (uint8_t *)buffer, buffer_len, diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 77ea0632cf8c..0e73d73aa4f5 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -126,8 +126,7 @@ int DetectEngineInspectHttpStatCode(ThreadVars *tv, det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_HSCDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status), diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 7cecf37d6b06..22e38487d9c5 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -126,8 +126,7 @@ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_HSMDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, (uint8_t *)bstr_ptr(tx->response_message), bstr_len(tx->response_message), diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index 18f716f234b3..d2cbbcea7b3b 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -135,7 +135,7 @@ int DetectEngineInspectHttpUA(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HUADMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index 7f8a46fd80e9..6bc28adfeb47 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -129,7 +129,7 @@ int DetectEngineInspectHttpUri(ThreadVars *tv, /* Inspect all the uricontents fetched on each * transaction at the app layer */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_UMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized), diff --git a/src/detect-engine.c b/src/detect-engine.c index dad076c42a83..0fc7dd549924 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -172,6 +172,31 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) new_engine->sm_list = t->sm_list; new_engine->Callback = t->Callback; + switch (new_engine->sm_list) { + case DETECT_SM_LIST_HMDMATCH: + case DETECT_SM_LIST_UMATCH: + case DETECT_SM_LIST_HRUDMATCH: + case DETECT_SM_LIST_HTTP_REQLINEMATCH: + case DETECT_SM_LIST_HTTP_RESLINEMATCH: + case DETECT_SM_LIST_HCBDMATCH: + case DETECT_SM_LIST_FILEDATA: + case DETECT_SM_LIST_HHDMATCH: + case DETECT_SM_LIST_HRHDMATCH: + case DETECT_SM_LIST_HSMDMATCH: + case DETECT_SM_LIST_HSCDMATCH: + case DETECT_SM_LIST_HHHDMATCH: + case DETECT_SM_LIST_HRHHDMATCH: + case DETECT_SM_LIST_HCDMATCH: + case DETECT_SM_LIST_HUADMATCH: + new_engine->sm = s->sm_lists[new_engine->sm_list]; + s->sm_lists[new_engine->sm_list] = NULL; + s->sm_lists_tail[new_engine->sm_list] = NULL; + lists_used[t->sm_list] = 1; + break; + default: + break; + } + if (s->app_inspect == NULL) { s->app_inspect = new_engine; new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */ diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 057f84a51486..8561f3fb5d89 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -191,7 +191,7 @@ static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, /* Inspect all the uricontents fetched on each * transaction at the app layer */ int r = DetectEngineContentInspection(de_ctx, det_ctx, - s, s->sm_lists[DETECT_SM_LIST_HTTP_REQLINEMATCH], + s, sm, f, bstr_ptr(tx->request_line), bstr_len(tx->request_line), diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index 04f7a8e53984..5dff95ec1999 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -194,7 +194,7 @@ int DetectEngineInspectHttpResponseLine(ThreadVars *tv, #endif /* run the inspection against the buffer */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HTTP_RESLINEMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, bstr_ptr(tx->response_line), bstr_len(tx->response_line), diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index a8a1f0d9a3c2..4e66237129c5 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -486,45 +486,24 @@ static int HTTPUriTest04(void) */ int DetectUriSigTest01(void) { - SigMatch *sm = NULL; - int result = 0; ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; Signature *s = NULL; memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\" Test uricontent\"; " - "content:\"me\"; uricontent:\"me\"; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + s = DetectEngineAppendSig(de_ctx,"alert http any any -> any any (msg:" + "\" Test uricontent\"; content:\"me\"; uricontent:\"me\"; sid:1;)"); + FAIL_IF_NULL(s); - BUG_ON(de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL); + BUG_ON(s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL); + FAIL_IF_NOT(de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]->type == DETECT_CONTENT); - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; - if (sm->type == DETECT_CONTENT) { - result = 1; - } else { - result = 0; - } - - end: - if (de_ctx != NULL) SigGroupCleanup(de_ctx); - if (de_ctx != NULL) SigCleanSignatures(de_ctx); - if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + DetectEngineCtxFree(de_ctx); + PASS; } /** \test Check the signature working to alert when http_cookie is matched . */ From 747dbf92ce78783bf93cf7ce65b9dfd174bf8943 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 18:47:42 +0200 Subject: [PATCH 2348/2553] detect: dns & tls lists in engine --- src/detect-engine-dns.c | 2 +- src/detect-engine-tls.c | 9 +++------ src/detect-engine.c | 10 ++++++++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index 4b15996195f4..7269b378ea06 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -86,7 +86,7 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, //PrintRawDataFp(stdout, buffer, buffer_len); r = DetectEngineContentInspection(de_ctx, det_ctx, - s, s->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH], + s, sm, f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index e488fd330162..3e5b458d2e82 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -114,8 +114,7 @@ int DetectEngineInspectTlsSni(ThreadVars *tv, buffer = (uint8_t *)ssl_state->client_connp.sni; buffer_len = strlen(ssl_state->client_connp.sni); - cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_TLSSNI_MATCH], + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); @@ -190,8 +189,7 @@ int DetectEngineInspectTlsIssuer(ThreadVars *tv, buffer = (uint8_t *)ssl_state->server_connp.cert0_issuerdn; buffer_len = strlen(ssl_state->server_connp.cert0_issuerdn); - cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_TLSISSUER_MATCH], + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); @@ -266,8 +264,7 @@ int DetectEngineInspectTlsSubject(ThreadVars *tv, buffer = (uint8_t *)ssl_state->server_connp.cert0_subject; buffer_len = strlen(ssl_state->server_connp.cert0_subject); - cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_TLSSUBJECT_MATCH], + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); diff --git a/src/detect-engine.c b/src/detect-engine.c index 0fc7dd549924..40d32d3ad348 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -188,6 +188,16 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) case DETECT_SM_LIST_HRHHDMATCH: case DETECT_SM_LIST_HCDMATCH: case DETECT_SM_LIST_HUADMATCH: + + case DETECT_SM_LIST_DNSQUERYNAME_MATCH: + //case DETECT_SM_LIST_DNSRESPONSE_MATCH: + //case DETECT_SM_LIST_DNSRESPONSE_MATCH: + + case DETECT_SM_LIST_TLSSNI_MATCH: + case DETECT_SM_LIST_TLSISSUER_MATCH: + case DETECT_SM_LIST_TLSSUBJECT_MATCH: + //case DETECT_SM_LIST_TLSVALIDITY_MATCH: + new_engine->sm = s->sm_lists[new_engine->sm_list]; s->sm_lists[new_engine->sm_list] = NULL; s->sm_lists_tail[new_engine->sm_list] = NULL; From f5adccba1d8afb40e0f8cbbece6dcd805f47b9aa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 18:54:02 +0200 Subject: [PATCH 2349/2553] detect: app-event list in engine --- src/detect-app-layer-event.c | 5 ++--- src/detect-engine.c | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 3447ab3813e5..38504c14b67a 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -88,14 +88,13 @@ void DetectAppLayerEventRegister(void) static int DetectEngineAptEventInspect(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *smi, + const Signature *s, const SigMatch *sm, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { AppLayerDecoderEvents *decoder_events = NULL; int r = 0; AppProto alproto; - SigMatch *sm; DetectAppLayerEventData *aled = NULL; alproto = f->alproto; @@ -103,7 +102,7 @@ static int DetectEngineAptEventInspect(ThreadVars *tv, if (decoder_events == NULL) goto end; - for (sm = s->sm_lists[DETECT_SM_LIST_APP_EVENT]; sm != NULL; sm = sm->next) { + for ( ; sm != NULL; sm = sm->next) { aled = (DetectAppLayerEventData *)sm->ctx; KEYWORD_PROFILING_START; if (AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) { diff --git a/src/detect-engine.c b/src/detect-engine.c index 40d32d3ad348..476e6c26f117 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -198,6 +198,8 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) case DETECT_SM_LIST_TLSSUBJECT_MATCH: //case DETECT_SM_LIST_TLSVALIDITY_MATCH: + case DETECT_SM_LIST_APP_EVENT: + new_engine->sm = s->sm_lists[new_engine->sm_list]; s->sm_lists[new_engine->sm_list] = NULL; s->sm_lists_tail[new_engine->sm_list] = NULL; From 7f7d4296da7f103b96ba2fe0513846f004ff69e8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 19:11:18 +0200 Subject: [PATCH 2350/2553] detect: file list in engine --- src/detect-engine-file.c | 12 ++++++------ src/detect-engine.c | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index 588c72fbbf79..f2f847a65ff3 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -74,9 +74,9 @@ * \note flow is not locked at this time */ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Flow *f, Signature *s, uint8_t flags, FileContainer *ffc) + Flow *f, Signature *s, const SigMatch *smi, uint8_t flags, FileContainer *ffc) { - SigMatch *sm = NULL; + const SigMatch *sm = NULL; int r = 0; int match = 0; int store_r = 0; @@ -148,7 +148,7 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, } /* run the file match functions. */ - for (sm = s->sm_lists[DETECT_SM_LIST_FILEMATCH]; sm != NULL; sm = sm->next) { + for (sm = smi; sm != NULL; sm = sm->next) { SCLogDebug("sm %p, sm->next %p", sm, sm->next); if (sigmatch_table[sm->type].FileMatch != NULL) { @@ -183,7 +183,7 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, } else { /* if we have a filestore sm with a scope > file (so tx, ssn) we * run it here */ - sm = s->sm_lists[DETECT_SM_LIST_FILEMATCH]; + sm = smi; if (sm != NULL && sm->next == NULL && sm->type == DETECT_FILESTORE && sm->ctx != NULL) { @@ -242,7 +242,7 @@ int DetectFileInspectHttp(ThreadVars *tv, else ffc = htp_state->files_ts; - int match = DetectFileInspect(tv, det_ctx, f, s, flags, ffc); + int match = DetectFileInspect(tv, det_ctx, f, s, sm, flags, ffc); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { r = DETECT_ENGINE_INSPECT_SIG_MATCH; } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { @@ -294,7 +294,7 @@ int DetectFileInspectSmtp(ThreadVars *tv, else goto end; - int match = DetectFileInspect(tv, det_ctx, f, s, flags, ffc); + int match = DetectFileInspect(tv, det_ctx, f, s, sm, flags, ffc); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { r = DETECT_ENGINE_INSPECT_SIG_MATCH; } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { diff --git a/src/detect-engine.c b/src/detect-engine.c index 476e6c26f117..413447a2552b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -189,6 +189,8 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) case DETECT_SM_LIST_HCDMATCH: case DETECT_SM_LIST_HUADMATCH: + case DETECT_SM_LIST_FILEMATCH: + case DETECT_SM_LIST_DNSQUERYNAME_MATCH: //case DETECT_SM_LIST_DNSRESPONSE_MATCH: //case DETECT_SM_LIST_DNSRESPONSE_MATCH: From e94a7bddb3ef0311fd0c457af68bc4cd1d212b6b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 19:20:31 +0200 Subject: [PATCH 2351/2553] detect: modbus list in engine --- src/detect-engine-modbus.c | 3 +-- src/detect-engine.c | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/detect-engine-modbus.c b/src/detect-engine-modbus.c index 102ffe39cd49..38a0b6876fa8 100644 --- a/src/detect-engine-modbus.c +++ b/src/detect-engine-modbus.c @@ -200,7 +200,7 @@ int DetectEngineInspectModbus(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, - const SigMatch *smi, + const SigMatch *sm, Flow *f, uint8_t flags, void *alstate, @@ -209,7 +209,6 @@ int DetectEngineInspectModbus(ThreadVars *tv, { SCEnter(); ModbusTransaction *tx = (ModbusTransaction *)txv; - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MODBUS_MATCH]; DetectModbus *modbus = (DetectModbus *) sm->ctx; int ret = 0; diff --git a/src/detect-engine.c b/src/detect-engine.c index 413447a2552b..f87513107ef4 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -202,6 +202,8 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) case DETECT_SM_LIST_APP_EVENT: + case DETECT_SM_LIST_MODBUS_MATCH: + new_engine->sm = s->sm_lists[new_engine->sm_list]; s->sm_lists[new_engine->sm_list] = NULL; s->sm_lists_tail[new_engine->sm_list] = NULL; From da7c816c7cc1b314f3c600827ec8270b7247e206 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 19:24:35 +0200 Subject: [PATCH 2352/2553] detect: enip/cip list in engine --- src/detect-engine-enip.c | 6 ++---- src/detect-engine.c | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect-engine-enip.c b/src/detect-engine-enip.c index 814be1c02071..720a318ac511 100644 --- a/src/detect-engine-enip.c +++ b/src/detect-engine-enip.c @@ -219,14 +219,13 @@ int CIPServiceMatch(ENIPTransaction *enip_data, */ int DetectEngineInspectCIP(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *smi, Flow *f, uint8_t flags, + const Signature *s, const SigMatch *sm, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); ENIPTransaction *tx = (ENIPTransaction *) txv; - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_CIP_MATCH]; DetectCipServiceData *cipserviced = (DetectCipServiceData *) sm->ctx; if (cipserviced == NULL) @@ -260,13 +259,12 @@ int DetectEngineInspectCIP(ThreadVars *tv, int DetectEngineInspectENIP(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *smi, + const Signature *s, const SigMatch *sm, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); ENIPTransaction *tx = (ENIPTransaction *) txv; - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_ENIP_MATCH]; DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *) sm->ctx; if (enipcmdd == NULL) diff --git a/src/detect-engine.c b/src/detect-engine.c index f87513107ef4..ad86cc0c6932 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -203,6 +203,8 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) case DETECT_SM_LIST_APP_EVENT: case DETECT_SM_LIST_MODBUS_MATCH: + case DETECT_SM_LIST_CIP_MATCH: + case DETECT_SM_LIST_ENIP_MATCH: new_engine->sm = s->sm_lists[new_engine->sm_list]; s->sm_lists[new_engine->sm_list] = NULL; From a0fe67a3c0c980fe409ec4fb206fc24a5caf059b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 19:26:48 +0200 Subject: [PATCH 2353/2553] detect: template list in engine --- src/detect-engine-template.c | 10 ++++------ src/detect-engine.c | 2 ++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/detect-engine-template.c b/src/detect-engine-template.c index 9ad8ff5936e1..422a8a3d1e09 100644 --- a/src/detect-engine-template.c +++ b/src/detect-engine-template.c @@ -45,15 +45,13 @@ int DetectEngineInspectTemplateBuffer(ThreadVars *tv, int ret = 0; if (flags & STREAM_TOSERVER && tx->request_buffer != NULL) { - ret = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH], f, - tx->request_buffer, tx->request_buffer_len, 0, + ret = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + f, tx->request_buffer, tx->request_buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { - ret = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH], f, - tx->response_buffer, tx->response_buffer_len, 0, + ret = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + f, tx->response_buffer, tx->response_buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } diff --git a/src/detect-engine.c b/src/detect-engine.c index ad86cc0c6932..b1d4a24cfb46 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -206,6 +206,8 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) case DETECT_SM_LIST_CIP_MATCH: case DETECT_SM_LIST_ENIP_MATCH: + case DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH: + new_engine->sm = s->sm_lists[new_engine->sm_list]; s->sm_lists[new_engine->sm_list] = NULL; s->sm_lists_tail[new_engine->sm_list] = NULL; From bd456076a85edd28d997ac50db785e0aab746156 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Oct 2016 22:37:07 +0200 Subject: [PATCH 2354/2553] detect: pass SigMatchData to inspect functions --- src/detect-app-layer-event.c | 17 ++++-- src/detect-base64-data.c | 2 +- src/detect-base64-decode.c | 4 +- src/detect-base64-decode.h | 4 +- src/detect-byte-extract.c | 4 +- src/detect-byte-extract.h | 2 +- src/detect-dnp3.c | 8 +-- src/detect-engine-content-inspection.c | 80 +++++++++++++------------- src/detect-engine-content-inspection.h | 2 +- src/detect-engine-dcepayload.c | 4 +- src/detect-engine-dns.c | 4 +- src/detect-engine-dns.h | 6 +- src/detect-engine-enip.c | 8 +-- src/detect-engine-enip.h | 4 +- src/detect-engine-file.c | 42 +++++++------- src/detect-engine-file.h | 4 +- src/detect-engine-filedata-smtp.c | 4 +- src/detect-engine-filedata-smtp.h | 2 +- src/detect-engine-hcbd.c | 4 +- src/detect-engine-hcbd.h | 2 +- src/detect-engine-hcd.c | 4 +- src/detect-engine-hcd.h | 2 +- src/detect-engine-hhd.c | 4 +- src/detect-engine-hhd.h | 2 +- src/detect-engine-hhhd.c | 4 +- src/detect-engine-hhhd.h | 2 +- src/detect-engine-hmd.c | 4 +- src/detect-engine-hmd.h | 2 +- src/detect-engine-hrhd.c | 4 +- src/detect-engine-hrhd.h | 2 +- src/detect-engine-hrhhd.c | 4 +- src/detect-engine-hrhhd.h | 2 +- src/detect-engine-hrud.c | 4 +- src/detect-engine-hrud.h | 2 +- src/detect-engine-hsbd.c | 4 +- src/detect-engine-hsbd.h | 2 +- src/detect-engine-hscd.c | 4 +- src/detect-engine-hscd.h | 2 +- src/detect-engine-hsmd.c | 4 +- src/detect-engine-hsmd.h | 2 +- src/detect-engine-hua.c | 4 +- src/detect-engine-hua.h | 2 +- src/detect-engine-modbus.c | 4 +- src/detect-engine-modbus.h | 2 +- src/detect-engine-payload.c | 4 +- src/detect-engine-state.c | 4 +- src/detect-engine-template.c | 6 +- src/detect-engine-template.h | 2 +- src/detect-engine-tls.c | 14 ++--- src/detect-engine-tls.h | 8 +-- src/detect-engine-uri.c | 4 +- src/detect-engine-uri.h | 2 +- src/detect-engine.c | 20 ++----- src/detect-fileext.c | 4 +- src/detect-filemagic.c | 4 +- src/detect-filename.c | 4 +- src/detect-filesize.c | 4 +- src/detect-filestore.c | 4 +- src/detect-http-request-line.c | 6 +- src/detect-http-response-line.c | 6 +- src/detect-lua.c | 4 +- src/detect-lua.h | 2 +- src/detect-pcre.c | 6 +- src/detect-pcre.h | 7 ++- src/detect.h | 7 +-- src/util-detect-file-hash.c | 2 +- src/util-detect-file-hash.h | 2 +- 67 files changed, 204 insertions(+), 201 deletions(-) diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 38504c14b67a..3e95fb57e07e 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -57,7 +57,7 @@ static void DetectAppLayerEventRegisterTests(void); static void DetectAppLayerEventFree(void *); static int DetectEngineAptEventInspect(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); @@ -88,7 +88,7 @@ void DetectAppLayerEventRegister(void) static int DetectEngineAptEventInspect(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { @@ -102,15 +102,20 @@ static int DetectEngineAptEventInspect(ThreadVars *tv, if (decoder_events == NULL) goto end; - for ( ; sm != NULL; sm = sm->next) { - aled = (DetectAppLayerEventData *)sm->ctx; + while (1) { + aled = (DetectAppLayerEventData *)smd->ctx; KEYWORD_PROFILING_START; + if (AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + + if (smd->is_last) + break; + smd++; continue; } - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); goto end; } diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c index ce54f1d661fc..d90d0925134c 100644 --- a/src/detect-base64-data.c +++ b/src/detect-base64-data.c @@ -75,7 +75,7 @@ int DetectBase64DataDoMatch(DetectEngineCtx *de_ctx, { if (det_ctx->base64_decoded_len) { return DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_BASE64_DATA], f, det_ctx->base64_decoded, + s->sm_arrays[DETECT_SM_LIST_BASE64_DATA], f, det_ctx->base64_decoded, det_ctx->base64_decoded_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index 251a89f9cdfd..638e76203e46 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -55,9 +55,9 @@ void DetectBase64DecodeRegister(void) } int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, - const SigMatch *sm, uint8_t *payload, uint32_t payload_len) + const SigMatchData *smd, uint8_t *payload, uint32_t payload_len) { - DetectBase64Decode *data = (DetectBase64Decode *)sm->ctx; + DetectBase64Decode *data = (DetectBase64Decode *)smd->ctx; int decode_len; #if 0 diff --git a/src/detect-base64-decode.h b/src/detect-base64-decode.h index e2f602313dad..4ae19cd93d6b 100644 --- a/src/detect-base64-decode.h +++ b/src/detect-base64-decode.h @@ -27,7 +27,7 @@ typedef struct DetectBase64Decode_ { } DetectBase64Decode; void DetectBase64DecodeRegister(void); -int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *, - const Signature *, const SigMatch *, uint8_t *, uint32_t); +int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *, const Signature *, + const SigMatchData *, uint8_t *, uint32_t); #endif /* __DETECT_BASE64_DECODE_H__ */ diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 24b577bc84be..db379031b35c 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -110,12 +110,12 @@ void DetectByteExtractRegister(void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatch *sm, +int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatchData *smd, const Signature *s, uint8_t *payload, uint16_t payload_len, uint64_t *value, uint8_t endian) { - DetectByteExtractData *data = (DetectByteExtractData *)sm->ctx; + DetectByteExtractData *data = (DetectByteExtractData *)smd->ctx; uint8_t *ptr = NULL; int32_t len = 0; uint64_t val = 0; diff --git a/src/detect-byte-extract.h b/src/detect-byte-extract.h index 799d35627be2..be3641bf270a 100644 --- a/src/detect-byte-extract.h +++ b/src/detect-byte-extract.h @@ -62,7 +62,7 @@ typedef struct DetectByteExtractData_ { void DetectByteExtractRegister(void); SigMatch *DetectByteExtractRetrieveSMVar(const char *, const Signature *); -int DetectByteExtractDoMatch(DetectEngineThreadCtx *, const SigMatch *, const Signature *, +int DetectByteExtractDoMatch(DetectEngineThreadCtx *, const SigMatchData *, const Signature *, uint8_t *, uint16_t, uint64_t *, uint8_t); #endif /* __DETECT_BYTEEXTRACT_H__ */ diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 92922e8f05be..b2b945d0bcd2 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -139,7 +139,7 @@ static char *TrimString(char *str) } static int DetectEngineInspectDNP3Data(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatch *sm, + DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); @@ -150,12 +150,12 @@ static int DetectEngineInspectDNP3Data(ThreadVars *tv, DetectEngineCtx *de_ctx, /* Content match - should probably be put into its own file. */ if (flags & STREAM_TOSERVER && tx->request_buffer != NULL) { r = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_DNP3_DATA_MATCH], f, tx->request_buffer, + s->sm_arrays[DETECT_SM_LIST_DNP3_DATA_MATCH], f, tx->request_buffer, tx->request_buffer_len, 0, 0, NULL); } else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { r = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_DNP3_DATA_MATCH], f, tx->response_buffer, + s->sm_arrays[DETECT_SM_LIST_DNP3_DATA_MATCH], f, tx->response_buffer, tx->response_buffer_len, 0, 0, NULL); } @@ -163,7 +163,7 @@ static int DetectEngineInspectDNP3Data(ThreadVars *tv, DetectEngineCtx *de_ctx, } static int DetectEngineInspectDNP3(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatch *sm, + DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index 95f4fc7fdb43..e7f83da7c175 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -99,7 +99,7 @@ * \retval 1 match */ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, @@ -112,19 +112,19 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx if (det_ctx->inspection_recursion_counter == de_ctx->inspection_recursion_limit) { det_ctx->discontinue_matching = 1; - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); SCReturnInt(0); } - if (sm == NULL || buffer_len == 0) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); + if (smd == NULL || buffer_len == 0) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); SCReturnInt(0); } /* \todo unify this which is phase 2 of payload inspection unification */ - if (sm->type == DETECT_CONTENT) { + if (smd->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)sm->ctx; + DetectContentData *cd = (DetectContentData *)smd->ctx; SCLogDebug("inspecting content %"PRIu32" buffer_len %"PRIu32, cd->id, buffer_len); /* we might have already have this content matched by the mpm. @@ -318,17 +318,18 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* bail out if we have no next match. Technically this is an * error, as the current cd has the DETECT_CONTENT_RELATIVE_NEXT * flag set. */ - if (sm->next == NULL) { + if (smd->is_last) { goto no_match; } SCLogDebug("content %"PRIu32, cd->id); - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); /* see if the next buffer keywords match. If not, we will * search for another occurence of this content and see * if the others match then until we run out of matches */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1, + f, buffer, buffer_len, stream_start_offset, inspection_mode, data); if (r == 1) { SCReturnInt(1); } @@ -343,10 +344,10 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx } while(1); - } else if (sm->type == DETECT_ISDATAAT) { + } else if (smd->type == DETECT_ISDATAAT) { SCLogDebug("inspecting isdataat"); - DetectIsdataatData *id = (DetectIsdataatData *)sm->ctx; + DetectIsdataatData *id = (DetectIsdataatData *)smd->ctx; if (id->flags & ISDATAAT_RELATIVE) { if (det_ctx->buffer_offset + id->dataat > buffer_len) { SCLogDebug("det_ctx->buffer_offset + id->dataat %"PRIu32" > %"PRIu32, det_ctx->buffer_offset + id->dataat, buffer_len); @@ -373,9 +374,9 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx } } - } else if (sm->type == DETECT_PCRE) { + } else if (smd->type == DETECT_PCRE) { SCLogDebug("inspecting pcre"); - DetectPcreData *pe = (DetectPcreData *)sm->ctx; + DetectPcreData *pe = (DetectPcreData *)smd->ctx; uint32_t prev_buffer_offset = det_ctx->buffer_offset; uint32_t prev_offset = 0; int r = 0; @@ -385,7 +386,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx Packet *p = NULL; if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) p = (Packet *)data; - r = DetectPcrePayloadMatch(det_ctx, s, sm, p, f, + r = DetectPcrePayloadMatch(det_ctx, s, smd, p, f, buffer, buffer_len); if (r == 0) { goto no_match; @@ -395,7 +396,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx SCLogDebug("no relative match coming up, so this is a match"); goto match; } - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); /* save it, in case we need to do a pcre match once again */ prev_offset = det_ctx->pcre_match_start_offset; @@ -403,8 +404,8 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* see if the next payload keywords match. If not, we will * search for another occurence of this pcre and see * if the others match, until we run out of matches */ - r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, - f, buffer, buffer_len, stream_start_offset, inspection_mode, data); + r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1, + f, buffer, buffer_len, stream_start_offset, inspection_mode, data); if (r == 1) { SCReturnInt(1); } @@ -416,8 +417,8 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx det_ctx->pcre_match_start_offset = prev_offset; } while (1); - } else if (sm->type == DETECT_BYTETEST) { - DetectBytetestData *btd = (DetectBytetestData *)sm->ctx; + } else if (smd->type == DETECT_BYTETEST) { + DetectBytetestData *btd = (DetectBytetestData *)smd->ctx; uint8_t flags = btd->flags; int32_t offset = btd->offset; uint64_t value = btd->value; @@ -438,15 +439,15 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx DETECT_BYTETEST_LITTLE: 0); } - if (DetectBytetestDoMatch(det_ctx, s, sm->ctx, buffer, buffer_len, flags, + if (DetectBytetestDoMatch(det_ctx, s, smd->ctx, buffer, buffer_len, flags, offset, value) != 1) { goto no_match; } goto match; - } else if (sm->type == DETECT_BYTEJUMP) { - DetectBytejumpData *bjd = (DetectBytejumpData *)sm->ctx; + } else if (smd->type == DETECT_BYTEJUMP) { + DetectBytejumpData *bjd = (DetectBytejumpData *)smd->ctx; uint8_t flags = bjd->flags; int32_t offset = bjd->offset; @@ -464,16 +465,16 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx DETECT_BYTEJUMP_LITTLE: 0); } - if (DetectBytejumpDoMatch(det_ctx, s, sm->ctx, buffer, buffer_len, + if (DetectBytejumpDoMatch(det_ctx, s, smd->ctx, buffer, buffer_len, flags, offset) != 1) { goto no_match; } goto match; - } else if (sm->type == DETECT_BYTE_EXTRACT) { + } else if (smd->type == DETECT_BYTE_EXTRACT) { - DetectByteExtractData *bed = (DetectByteExtractData *)sm->ctx; + DetectByteExtractData *bed = (DetectByteExtractData *)smd->ctx; uint8_t endian = bed->endian; /* if we have dce enabled we will have to use the endianness @@ -488,7 +489,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx DETECT_BYTE_EXTRACT_ENDIAN_LITTLE : DETECT_BYTE_EXTRACT_ENDIAN_BIG); } - if (DetectByteExtractDoMatch(det_ctx, sm, s, buffer, + if (DetectByteExtractDoMatch(det_ctx, smd, s, buffer, buffer_len, &det_ctx->bj_values[bed->local_id], endian) != 1) { @@ -498,11 +499,11 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx goto match; /* we should never get here, but bail out just in case */ - } else if (sm->type == DETECT_AL_URILEN) { + } else if (smd->type == DETECT_AL_URILEN) { SCLogDebug("inspecting uri len"); int r = 0; - DetectUrilenData *urilend = (DetectUrilenData *) sm->ctx; + DetectUrilenData *urilend = (DetectUrilenData *) smd->ctx; switch (urilend->mode) { case DETECT_URILEN_EQ: @@ -534,10 +535,10 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx goto no_match; #ifdef HAVE_LUA } - else if (sm->type == DETECT_LUA) { + else if (smd->type == DETECT_LUA) { SCLogDebug("lua starting"); - if (DetectLuaMatchBuffer(det_ctx, s, sm, buffer, buffer_len, + if (DetectLuaMatchBuffer(det_ctx, s, smd, buffer, buffer_len, det_ctx->buffer_offset, f) != 1) { SCLogDebug("lua no_match"); @@ -546,10 +547,10 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx SCLogDebug("lua match"); goto match; #endif /* HAVE_LUA */ - } else if (sm->type == DETECT_BASE64_DECODE) { - if (DetectBase64DecodeDoMatch(det_ctx, s, sm, buffer, buffer_len)) { + } else if (smd->type == DETECT_BASE64_DECODE) { + if (DetectBase64DecodeDoMatch(det_ctx, s, smd, buffer, buffer_len)) { if (s->sm_arrays[DETECT_SM_LIST_BASE64_DATA] != NULL) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); if (DetectBase64DataDoMatch(de_ctx, det_ctx, s, f)) { /* Base64 is a terminal list. */ goto final_match; @@ -557,25 +558,26 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx } } } else { - SCLogDebug("sm->type %u", sm->type); + SCLogDebug("sm->type %u", smd->type); #ifdef DEBUG BUG_ON(1); #endif } no_match: - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); SCReturnInt(0); match: /* this sigmatch matched, inspect the next one. If it was the last, * the buffer portion of the signature matched. */ - if (sm->next != NULL) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); + if (!smd->is_last) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1, + f, buffer, buffer_len, stream_start_offset, inspection_mode, data); SCReturnInt(r); } final_match: - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); SCReturnInt(1); } diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 8ae5d76a458c..b3436f736617 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -34,7 +34,7 @@ enum { }; int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index ad0d1929a519..780b85aadae4 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -85,7 +85,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], + r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[DETECT_SM_LIST_DMATCH], f, dce_stub_data, dce_stub_data_len, @@ -108,7 +108,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], + r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[DETECT_SM_LIST_DMATCH], f, dce_stub_data, dce_stub_data_len, diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index 7269b378ea06..d243ba025504 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -62,7 +62,7 @@ */ int DetectEngineInspectDnsQueryName(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { @@ -86,7 +86,7 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, //PrintRawDataFp(stdout, buffer, buffer_len); r = DetectEngineContentInspection(de_ctx, det_ctx, - s, sm, + s, smd, f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) diff --git a/src/detect-engine-dns.h b/src/detect-engine-dns.h index be25eb3ac1cc..ed7ef51df730 100644 --- a/src/detect-engine-dns.h +++ b/src/detect-engine-dns.h @@ -27,15 +27,15 @@ int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectDnsQueryName(ThreadVars *, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, - const Signature *, const SigMatch *sm, + const Signature *, const SigMatchData *smd, Flow *, uint8_t, void *, void *, uint64_t); int DetectEngineInspectDnsRequest(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); int DetectEngineInspectDnsResponse(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); #endif /* __DETECT_ENGINE_DNS_H__ */ diff --git a/src/detect-engine-enip.c b/src/detect-engine-enip.c index 720a318ac511..8d873196172c 100644 --- a/src/detect-engine-enip.c +++ b/src/detect-engine-enip.c @@ -219,14 +219,14 @@ int CIPServiceMatch(ENIPTransaction *enip_data, */ int DetectEngineInspectCIP(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, Flow *f, uint8_t flags, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); ENIPTransaction *tx = (ENIPTransaction *) txv; - DetectCipServiceData *cipserviced = (DetectCipServiceData *) sm->ctx; + DetectCipServiceData *cipserviced = (DetectCipServiceData *) smd->ctx; if (cipserviced == NULL) { @@ -259,13 +259,13 @@ int DetectEngineInspectCIP(ThreadVars *tv, int DetectEngineInspectENIP(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { SCEnter(); ENIPTransaction *tx = (ENIPTransaction *) txv; - DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *) sm->ctx; + DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *) smd->ctx; if (enipcmdd == NULL) { diff --git a/src/detect-engine-enip.h b/src/detect-engine-enip.h index eb55917d2c75..23864201d2f1 100644 --- a/src/detect-engine-enip.h +++ b/src/detect-engine-enip.h @@ -25,12 +25,12 @@ int DetectEngineInspectCIP(ThreadVars *, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, - const Signature *, const SigMatch *sm, + const Signature *, const SigMatchData *smd, Flow *, uint8_t, void *, void *, uint64_t); int DetectEngineInspectENIP(ThreadVars *, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, - const Signature *, const SigMatch *sm, + const Signature *, const SigMatchData *smd, Flow *, uint8_t, void *, void *, uint64_t); void DetectEngineInspectENIPRegisterTests(void); diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index f2f847a65ff3..7ffb355740a8 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -74,9 +74,9 @@ * \note flow is not locked at this time */ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Flow *f, Signature *s, const SigMatch *smi, uint8_t flags, FileContainer *ffc) + Flow *f, Signature *s, const SigMatchData *smd, + uint8_t flags, FileContainer *ffc) { - const SigMatch *sm = NULL; int r = 0; int match = 0; int store_r = 0; @@ -148,22 +148,25 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, } /* run the file match functions. */ - for (sm = smi; sm != NULL; sm = sm->next) { - SCLogDebug("sm %p, sm->next %p", sm, sm->next); + while (1) { + SCLogDebug("smd %p", smd); - if (sigmatch_table[sm->type].FileMatch != NULL) { + if (sigmatch_table[smd->type].FileMatch != NULL) { KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - FileMatch(tv, det_ctx, f, flags, file, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + match = sigmatch_table[smd->type]. + FileMatch(tv, det_ctx, f, flags, file, s, smd); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match > 0)); if (match == 0) { r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; break; - } else if (sm->next == NULL) { + } else if (smd->is_last) { r = DETECT_ENGINE_INSPECT_SIG_MATCH; break; } } + if (smd->is_last) + break; + smd++; } /* continue inspection for other files as we may want to store @@ -183,16 +186,15 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, } else { /* if we have a filestore sm with a scope > file (so tx, ssn) we * run it here */ - sm = smi; - if (sm != NULL && sm->next == NULL && sm->type == DETECT_FILESTORE && - sm->ctx != NULL) + if (smd != NULL && smd->is_last && smd->type == DETECT_FILESTORE && + smd->ctx != NULL) { - DetectFilestoreData *fd = (DetectFilestoreData *)sm->ctx; + DetectFilestoreData *fd = (DetectFilestoreData *)smd->ctx; if (fd->scope > FILESTORE_SCOPE_DEFAULT) { KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - FileMatch(tv, det_ctx, f, flags, /* no file */NULL, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + match = sigmatch_table[smd->type]. + FileMatch(tv, det_ctx, f, flags, /* no file */NULL, s, smd); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match > 0)); if (match == 1) { r = DETECT_ENGINE_INSPECT_SIG_MATCH; @@ -230,7 +232,7 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, */ int DetectFileInspectHttp(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, const SigMatch *sm, + Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { int r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -242,7 +244,7 @@ int DetectFileInspectHttp(ThreadVars *tv, else ffc = htp_state->files_ts; - int match = DetectFileInspect(tv, det_ctx, f, s, sm, flags, ffc); + int match = DetectFileInspect(tv, det_ctx, f, s, smd, flags, ffc); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { r = DETECT_ENGINE_INSPECT_SIG_MATCH; } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { @@ -275,7 +277,7 @@ int DetectFileInspectHttp(ThreadVars *tv, */ int DetectFileInspectSmtp(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, const SigMatch *sm, + Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { SCEnter(); @@ -294,7 +296,7 @@ int DetectFileInspectSmtp(ThreadVars *tv, else goto end; - int match = DetectFileInspect(tv, det_ctx, f, s, sm, flags, ffc); + int match = DetectFileInspect(tv, det_ctx, f, s, smd, flags, ffc); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { r = DETECT_ENGINE_INSPECT_SIG_MATCH; } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { diff --git a/src/detect-engine-file.h b/src/detect-engine-file.h index f7ea8405f18f..180b2edd293e 100644 --- a/src/detect-engine-file.h +++ b/src/detect-engine-file.h @@ -26,12 +26,12 @@ int DetectFileInspectHttp(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); int DetectFileInspectSmtp(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); #endif /* __DETECT_ENGINE_FILE_H__ */ diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c index 6b1049cdbaf4..60f24d62e922 100644 --- a/src/detect-engine-filedata-smtp.c +++ b/src/detect-engine-filedata-smtp.c @@ -175,7 +175,7 @@ static const uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, int DetectEngineInspectSMTPFiledata(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, const SigMatch *sm, + Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { SMTPState *smtp_state = (SMTPState *)alstate; @@ -201,7 +201,7 @@ int DetectEngineInspectSMTPFiledata(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - match = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + match = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)buffer, buffer_len, diff --git a/src/detect-engine-filedata-smtp.h b/src/detect-engine-filedata-smtp.h index f9c55e3222ef..a6f3fc4fa88d 100644 --- a/src/detect-engine-filedata-smtp.h +++ b/src/detect-engine-filedata-smtp.h @@ -29,7 +29,7 @@ int PrefilterTxSmtpFiledataRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectSMTPFiledata(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx); diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 34b0bd7d0087..eb00951bfc9a 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -258,7 +258,7 @@ int PrefilterTxHttpRequestBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpClientBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, const SigMatch *sm, + Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { HtpState *htp_state = (HtpState *)alstate; @@ -276,7 +276,7 @@ int DetectEngineInspectHttpClientBody(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)buffer, buffer_len, diff --git a/src/detect-engine-hcbd.h b/src/detect-engine-hcbd.h index 2cdc3e77f9ba..c3c91a76a35b 100644 --- a/src/detect-engine-hcbd.h +++ b/src/detect-engine-hcbd.h @@ -31,7 +31,7 @@ int PrefilterTxHttpRequestBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpClientBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineCleanHCBDBuffers(DetectEngineThreadCtx *); diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index c6243f7adfaf..8f06cda19247 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -167,7 +167,7 @@ int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectHttpCookie(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; @@ -191,7 +191,7 @@ int DetectEngineInspectHttpCookie(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), diff --git a/src/detect-engine-hcd.h b/src/detect-engine-hcd.h index 621d722801fe..bdf9c498d4e9 100644 --- a/src/detect-engine-hcd.h +++ b/src/detect-engine-hcd.h @@ -30,7 +30,7 @@ int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpCookie(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpCookieRegisterTests(void); diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 3554e2a476d4..d17ccafd77fc 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -383,7 +383,7 @@ int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { HtpState *htp_state = (HtpState *)alstate; @@ -399,7 +399,7 @@ int DetectEngineInspectHttpHeader(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, buffer, buffer_len, diff --git a/src/detect-engine-hhd.h b/src/detect-engine-hhd.h index 41e6c5252f66..f8e06e12a701 100644 --- a/src/detect-engine-hhd.h +++ b/src/detect-engine-hhd.h @@ -30,7 +30,7 @@ int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx); diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 198d975173db..f884d7a85a1e 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -116,7 +116,7 @@ int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectHttpHH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; @@ -130,7 +130,7 @@ int DetectEngineInspectHttpHH(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, hname, hname_len, 0, diff --git a/src/detect-engine-hhhd.h b/src/detect-engine-hhhd.h index 04c2cf0be8dc..39e16493a33c 100644 --- a/src/detect-engine-hhhd.h +++ b/src/detect-engine-hhhd.h @@ -29,7 +29,7 @@ int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpHH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpHHRegisterTests(void); diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 35cdc5969d05..27dcb16567c7 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -113,7 +113,7 @@ int PrefilterTxMethodRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectHttpMethod(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; @@ -127,7 +127,7 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method), diff --git a/src/detect-engine-hmd.h b/src/detect-engine-hmd.h index 71f2009b6401..d3fe192f58ea 100644 --- a/src/detect-engine-hmd.h +++ b/src/detect-engine-hmd.h @@ -27,7 +27,7 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); int PrefilterTxMethodRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 50626399e4f6..9cdfbf2385a2 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -164,7 +164,7 @@ int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { HtpTxUserData *tx_ud = NULL; @@ -195,7 +195,7 @@ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, headers_raw, headers_raw_len, diff --git a/src/detect-engine-hrhd.h b/src/detect-engine-hrhd.h index b6deda862753..132ca642ba44 100644 --- a/src/detect-engine-hrhd.h +++ b/src/detect-engine-hrhd.h @@ -30,7 +30,7 @@ int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpRawHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpRawHeaderRegisterTests(void); diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index 8b335cfcf97c..455b98c76737 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -128,7 +128,7 @@ int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectHttpHRH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { uint8_t *hname; @@ -153,7 +153,7 @@ int DetectEngineInspectHttpHRH(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, hname, hname_len, 0, diff --git a/src/detect-engine-hrhhd.h b/src/detect-engine-hrhhd.h index e45b8b3bf501..4523cbc4253a 100644 --- a/src/detect-engine-hrhhd.h +++ b/src/detect-engine-hrhhd.h @@ -29,7 +29,7 @@ int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpHRH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpHRHRegisterTests(void); diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index e5a40b50b2fa..e41c4fdff3ea 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -113,7 +113,7 @@ int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectHttpRawUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; @@ -129,7 +129,7 @@ int DetectEngineInspectHttpRawUri(ThreadVars *tv, det_ctx->inspection_recursion_counter = 0; /* Inspect all the uricontents fetched on each * transaction at the app layer */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri), diff --git a/src/detect-engine-hrud.h b/src/detect-engine-hrud.h index 10137d6d2bfe..2d41f69650cc 100644 --- a/src/detect-engine-hrud.h +++ b/src/detect-engine-hrud.h @@ -30,7 +30,7 @@ int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpRawUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpRawUriRegisterTests(void); diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 7f40e6ea28b8..58727dca0138 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -263,7 +263,7 @@ int PrefilterTxHttpResponseBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectHttpServerBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, const SigMatch *sm, + Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { HtpState *htp_state = (HtpState *)alstate; @@ -281,7 +281,7 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)buffer, buffer_len, diff --git a/src/detect-engine-hsbd.h b/src/detect-engine-hsbd.h index 7126aabb2ca0..1187f936ef48 100644 --- a/src/detect-engine-hsbd.h +++ b/src/detect-engine-hsbd.h @@ -31,7 +31,7 @@ int PrefilterTxHttpResponseBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpServerBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 0e73d73aa4f5..8a563235b167 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -112,7 +112,7 @@ int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectHttpStatCode(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; @@ -126,7 +126,7 @@ int DetectEngineInspectHttpStatCode(ThreadVars *tv, det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status), diff --git a/src/detect-engine-hscd.h b/src/detect-engine-hscd.h index bdcc0cfc0cd3..d2e4d2fff870 100644 --- a/src/detect-engine-hscd.h +++ b/src/detect-engine-hscd.h @@ -29,7 +29,7 @@ int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpStatCode(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpStatCodeRegisterTests(void); diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 22e38487d9c5..cb52c03535a3 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -112,7 +112,7 @@ int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; @@ -126,7 +126,7 @@ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(tx->response_message), bstr_len(tx->response_message), diff --git a/src/detect-engine-hsmd.h b/src/detect-engine-hsmd.h index fd48176ecef0..36eee9024f49 100644 --- a/src/detect-engine-hsmd.h +++ b/src/detect-engine-hsmd.h @@ -29,7 +29,7 @@ int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpStatMsg(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpStatMsgRegisterTests(void); diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index d2cbbcea7b3b..2511767c944e 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -121,7 +121,7 @@ int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectHttpUA(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; @@ -135,7 +135,7 @@ int DetectEngineInspectHttpUA(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), diff --git a/src/detect-engine-hua.h b/src/detect-engine-hua.h index fba2d8845832..40c85887c7fe 100644 --- a/src/detect-engine-hua.h +++ b/src/detect-engine-hua.h @@ -29,7 +29,7 @@ int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpUA(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void DetectEngineHttpUARegisterTests(void); diff --git a/src/detect-engine-modbus.c b/src/detect-engine-modbus.c index 38a0b6876fa8..9e1f8537c4dd 100644 --- a/src/detect-engine-modbus.c +++ b/src/detect-engine-modbus.c @@ -200,7 +200,7 @@ int DetectEngineInspectModbus(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, - const SigMatch *sm, + const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, @@ -209,7 +209,7 @@ int DetectEngineInspectModbus(ThreadVars *tv, { SCEnter(); ModbusTransaction *tx = (ModbusTransaction *)txv; - DetectModbus *modbus = (DetectModbus *) sm->ctx; + DetectModbus *modbus = (DetectModbus *) smd->ctx; int ret = 0; diff --git a/src/detect-engine-modbus.h b/src/detect-engine-modbus.h index 66a174c76049..4ffe45ca6811 100644 --- a/src/detect-engine-modbus.h +++ b/src/detect-engine-modbus.h @@ -35,7 +35,7 @@ int DetectEngineInspectModbus(ThreadVars *, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, - const Signature *, const SigMatch *, + const Signature *, const SigMatchData *, Flow *, uint8_t, void *, void *, uint64_t); void DetectEngineInspectModbusRegisterTests(void); diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index c7f4bba8af60..0699a85fedda 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -143,7 +143,7 @@ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, det_ctx->inspection_recursion_counter = 0; det_ctx->replist = NULL; - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], + r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[DETECT_SM_LIST_PMATCH], f, p->payload, p->payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD, p); if (r == 1) { @@ -184,7 +184,7 @@ int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], + r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[DETECT_SM_LIST_PMATCH], f, payload, payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM, NULL); if (r == 1) { diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 82a40228e1ef..c9053602a085 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -534,7 +534,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (direction == engine->dir) { KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); int match = engine->Callback(tv, de_ctx, det_ctx, - s, engine->sm, f, flags, alstate, tx, tx_id); + s, engine->smd, f, flags, alstate, tx, tx_id); SCLogDebug("engine %p match %d", engine, match); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { inspect_flags |= BIT_U32(engine->id); @@ -859,7 +859,7 @@ static int DoInspectItem(ThreadVars *tv, SCLogDebug("inspect_flags %x", inspect_flags); KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); int match = engine->Callback(tv, de_ctx, det_ctx, - s, engine->sm, + s, engine->smd, f, flags, alstate, inspect_tx, inspect_tx_id); if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { inspect_flags |= BIT_U32(engine->id); diff --git a/src/detect-engine-template.c b/src/detect-engine-template.c index 422a8a3d1e09..c7d751a15154 100644 --- a/src/detect-engine-template.c +++ b/src/detect-engine-template.c @@ -38,19 +38,19 @@ int DetectEngineInspectTemplateBuffer(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, const SigMatch *sm, + Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { TemplateTransaction *tx = (TemplateTransaction *)txv; int ret = 0; if (flags & STREAM_TOSERVER && tx->request_buffer != NULL) { - ret = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + ret = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, tx->request_buffer, tx->request_buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { - ret = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + ret = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, tx->response_buffer, tx->response_buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } diff --git a/src/detect-engine-template.h b/src/detect-engine-template.h index 60bf5d47863f..fb836f0702cb 100644 --- a/src/detect-engine-template.h +++ b/src/detect-engine-template.h @@ -26,7 +26,7 @@ int DetectEngineInspectTemplateBuffer(ThreadVars *, DetectEngineCtx *, DetectEngineThreadCtx *, - const Signature *, const SigMatch *, + const Signature *, const SigMatchData *, Flow *, uint8_t, void *, void *tx, uint64_t tx_id); #endif /* __DETECT_TEMPLATE_ENGINE_H__ */ diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 3e5b458d2e82..43db1f42ad37 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -99,7 +99,7 @@ int PrefilterTxTlsSniRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { uint8_t *buffer; @@ -114,7 +114,7 @@ int DetectEngineInspectTlsSni(ThreadVars *tv, buffer = (uint8_t *)ssl_state->client_connp.sni; buffer_len = strlen(ssl_state->client_connp.sni); - cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); @@ -174,7 +174,7 @@ int PrefilterTxTlsIssuerRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, const SigMatch *sm, + Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { uint8_t *buffer; @@ -189,7 +189,7 @@ int DetectEngineInspectTlsIssuer(ThreadVars *tv, buffer = (uint8_t *)ssl_state->server_connp.cert0_issuerdn; buffer_len = strlen(ssl_state->server_connp.cert0_issuerdn); - cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); @@ -249,7 +249,7 @@ int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, const SigMatch *sm, + Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { uint8_t *buffer; @@ -264,7 +264,7 @@ int DetectEngineInspectTlsSubject(ThreadVars *tv, buffer = (uint8_t *)ssl_state->server_connp.cert0_subject; buffer_len = strlen(ssl_state->server_connp.cert0_subject); - cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); @@ -273,7 +273,7 @@ int DetectEngineInspectTlsSubject(ThreadVars *tv, int DetectEngineInspectTlsValidity(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, const SigMatch *sm, + Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h index 4172b4a04391..573e62d17434 100644 --- a/src/detect-engine-tls.h +++ b/src/detect-engine-tls.h @@ -29,23 +29,23 @@ int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); int DetectEngineInspectTlsIssuer(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); int DetectEngineInspectTlsSubject(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); int DetectEngineInspectTlsValidity(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); #endif /* __DETECT_ENGINE_TLS_H__ */ diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index 6bc28adfeb47..e6684cff7370 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -106,7 +106,7 @@ int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) */ int DetectEngineInspectHttpUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, const SigMatch *sm, + Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { HtpTxUserData *tx_ud = htp_tx_get_user_data(txv); @@ -129,7 +129,7 @@ int DetectEngineInspectHttpUri(ThreadVars *tv, /* Inspect all the uricontents fetched on each * transaction at the app layer */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized), diff --git a/src/detect-engine-uri.h b/src/detect-engine-uri.h index 4760dd184de7..fa18960bdbdc 100644 --- a/src/detect-engine-uri.h +++ b/src/detect-engine-uri.h @@ -28,7 +28,7 @@ int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectHttpUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); void UriRegisterTests(void); diff --git a/src/detect-engine.c b/src/detect-engine.c index b1d4a24cfb46..a5ccbf79f95c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -208,9 +208,7 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) case DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH: - new_engine->sm = s->sm_lists[new_engine->sm_list]; - s->sm_lists[new_engine->sm_list] = NULL; - s->sm_lists_tail[new_engine->sm_list] = NULL; + new_engine->smd = s->sm_arrays[new_engine->sm_list]; lists_used[t->sm_list] = 1; break; default: @@ -239,8 +237,7 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) int i; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { if (lists_used[i]) { - s->sm_lists[i] = NULL; - s->sm_lists_tail[i] = NULL; + s->sm_arrays[i] = NULL; } } @@ -258,13 +255,13 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) */ void DetectEngineAppInspectionEngineSignatureFree(Signature *s) { - SigMatch *ptrs[DETECT_SM_LIST_MAX] = { NULL }; + SigMatchData *ptrs[DETECT_SM_LIST_MAX] = { NULL }; DetectEngineAppInspectionEngine *ie = s->app_inspect; while (ie) { DetectEngineAppInspectionEngine *next = ie->next; - BUG_ON(ptrs[ie->sm_list] != NULL && ptrs[ie->sm_list] != ie->sm); - ptrs[ie->sm_list] = ie->sm; + BUG_ON(ptrs[ie->sm_list] != NULL && ptrs[ie->sm_list] != ie->smd); + ptrs[ie->sm_list] = ie->smd; SCFree(ie); ie = next; } @@ -272,12 +269,7 @@ void DetectEngineAppInspectionEngineSignatureFree(Signature *s) int i; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { - SigMatch *sm = ptrs[i]; - while (sm != NULL) { - SigMatch *nsm = sm->next; - SigMatchFree(sm); - sm = nsm; - } + SCFree(ptrs[i]); } } diff --git a/src/detect-fileext.c b/src/detect-fileext.c index fc052e076918..f9a08dacf374 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -52,7 +52,7 @@ #include "detect-fileext.h" static int DetectFileextMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, const Signature *, const SigMatch *); + uint8_t, File *, const Signature *, const SigMatchData *); static int DetectFileextSetup (DetectEngineCtx *, Signature *, char *); static void DetectFileextRegisterTests(void); static void DetectFileextFree(void *); @@ -89,7 +89,7 @@ void DetectFileextRegister(void) * \retval 1 match */ static int DetectFileextMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchData *m) { SCEnter(); int ret = 0; diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index a64e1d180bb0..b70e4c820d71 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -76,7 +76,7 @@ void DetectFilemagicRegister(void) #else /* HAVE_MAGIC */ static int DetectFilemagicMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, const Signature *, const SigMatch *); + uint8_t, File *, const Signature *, const SigMatchData *); static int DetectFilemagicSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilemagicRegisterTests(void); static void DetectFilemagicFree(void *); @@ -176,7 +176,7 @@ int FilemagicThreadLookup(magic_t *ctx, File *file) * \retval 1 match */ static int DetectFilemagicMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchData *m) { SCEnter(); int ret = 0; diff --git a/src/detect-filename.c b/src/detect-filename.c index 34722fb77f44..e751d2b4faed 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -53,7 +53,7 @@ #include "app-layer-parser.h" static int DetectFilenameMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, const Signature *, const SigMatch *); + uint8_t, File *, const Signature *, const SigMatchData *); static int DetectFilenameSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilenameRegisterTests(void); static void DetectFilenameFree(void *); @@ -101,7 +101,7 @@ void DetectFilenameRegister(void) * \retval 1 match */ static int DetectFilenameMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchData *m) { SCEnter(); int ret = 0; diff --git a/src/detect-filesize.c b/src/detect-filesize.c index b26c7a8fc66f..1b12221b8441 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -49,7 +49,7 @@ static pcre_extra *parse_regex_study; /*prototypes*/ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, const Signature *s, const SigMatch *m); + uint8_t flags, File *file, const Signature *s, const SigMatchData *m); static int DetectFilesizeSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilesizeFree (void *); static void DetectFilesizeRegisterTests (void); @@ -87,7 +87,7 @@ void DetectFilesizeRegister(void) * \retval 1 match */ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, const Signature *s, const SigMatch *m) + uint8_t flags, File *file, const Signature *s, const SigMatchData *m) { SCEnter(); diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 4104fc694d47..de11089092cc 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -60,7 +60,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectFilestoreMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, File *, const Signature *, const SigMatch *); + Flow *, uint8_t, File *, const Signature *, const SigMatchData *); static int DetectFilestoreSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilestoreFree(void *); static void DetectFilestoreRegisterTests(void); @@ -247,7 +247,7 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack * needs to be put behind a api. */ static int DetectFilestoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, const Signature *s, const SigMatch *m) + uint8_t flags, File *file, const Signature *s, const SigMatchData *m) { uint16_t file_id = 0; diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 8561f3fb5d89..8fabe28ff028 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -66,7 +66,7 @@ void DetectHttpRequestLineFree(void *); static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); /** @@ -172,7 +172,7 @@ static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx */ static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; @@ -191,7 +191,7 @@ static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, /* Inspect all the uricontents fetched on each * transaction at the app layer */ int r = DetectEngineContentInspection(de_ctx, det_ctx, - s, sm, + s, smd, f, bstr_ptr(tx->request_line), bstr_len(tx->request_line), diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index 5dff95ec1999..125771a8e614 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -66,7 +66,7 @@ void DetectHttpResponseLineFree(void *); static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); static int DetectEngineInspectHttpResponseLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); /** @@ -172,7 +172,7 @@ static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ct */ int DetectEngineInspectHttpResponseLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; @@ -194,7 +194,7 @@ int DetectEngineInspectHttpResponseLine(ThreadVars *tv, #endif /* run the inspection against the buffer */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm, + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, bstr_ptr(tx->response_line), bstr_len(tx->response_line), diff --git a/src/detect-lua.c b/src/detect-lua.c index 27351bfe4a30..d51746cefff6 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -186,7 +186,7 @@ void LuaDumpStack(lua_State *state) } int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, uint8_t *buffer, uint32_t buffer_len, uint32_t offset, Flow *f) { @@ -196,7 +196,7 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, if (buffer == NULL || buffer_len == 0) SCReturnInt(0); - DetectLuaData *lua = (DetectLuaData *)sm->ctx; + DetectLuaData *lua = (DetectLuaData *)smd->ctx; if (lua == NULL) SCReturnInt(0); diff --git a/src/detect-lua.h b/src/detect-lua.h index 18298aa20359..16e451e91090 100644 --- a/src/detect-lua.h +++ b/src/detect-lua.h @@ -56,7 +56,7 @@ typedef struct DetectLuaData { /* prototypes */ void DetectLuaRegister (void); int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, uint8_t *buffer, uint32_t buffer_len, uint32_t offset, Flow *f); diff --git a/src/detect-pcre.c b/src/detect-pcre.c index b8430149158f..a1177a5928d9 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -172,8 +172,8 @@ void DetectPcreRegister (void) * \retval 0 No match. */ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, - const SigMatch *sm, Packet *p, Flow *f, uint8_t *payload, - uint32_t payload_len) + const SigMatchData *smd, Packet *p, Flow *f, + uint8_t *payload, uint32_t payload_len) { SCEnter(); #define MAX_SUBSTRINGS 30 @@ -183,7 +183,7 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, uint16_t len = 0; uint16_t capture_len = 0; - DetectPcreData *pe = (DetectPcreData *)sm->ctx; + DetectPcreData *pe = (DetectPcreData *)smd->ctx; if (pe->flags & DETECT_PCRE_RELATIVE) { ptr = payload + det_ctx->buffer_offset; diff --git a/src/detect-pcre.h b/src/detect-pcre.h index 52e6394b595e..50b93b052833 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -44,8 +44,11 @@ typedef struct DetectPcreData_ { } DetectPcreData; /* prototypes */ -int DetectPcrePayloadMatch(DetectEngineThreadCtx *, const Signature *, - const SigMatch *, Packet *, Flow *, uint8_t *, uint32_t); + +int DetectPcrePayloadMatch(DetectEngineThreadCtx *, + const Signature *, const SigMatchData *, + Packet *, Flow *, uint8_t *, uint32_t); + int DetectPcrePacketPayloadMatch(DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectPcrePayloadDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Packet *, uint8_t *, uint16_t); diff --git a/src/detect.h b/src/detect.h index a9617a6b0392..f091a89451d3 100644 --- a/src/detect.h +++ b/src/detect.h @@ -377,7 +377,7 @@ struct DetectEngineThreadCtx_;// DetectEngineThreadCtx; typedef int (*InspectEngineFuncPtr)(ThreadVars *tv, struct DetectEngineCtx_ *de_ctx, struct DetectEngineThreadCtx_ *det_ctx, - const struct Signature_ *sig, const SigMatch *sm_list, + const struct Signature_ *sig, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); @@ -395,7 +395,7 @@ typedef struct DetectEngineAppInspectionEngine_ { */ InspectEngineFuncPtr Callback; - SigMatch *sm; + SigMatchData *smd; struct DetectEngineAppInspectionEngine_ *next; } DetectEngineAppInspectionEngine; @@ -955,7 +955,6 @@ typedef struct DetectEngineThreadCtx_ { } 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 */ @@ -973,7 +972,7 @@ typedef struct SigTableElmt_ { int (*FileMatch)(ThreadVars *, /**< thread local vars */ DetectEngineThreadCtx *, Flow *, /**< *LOCKED* flow */ - uint8_t flags, File *, const Signature *, const SigMatch *); + uint8_t flags, File *, const Signature *, const SigMatchData *); /** keyword setup function pointer */ int (*Setup)(DetectEngineCtx *, Signature *, char *); diff --git a/src/util-detect-file-hash.c b/src/util-detect-file-hash.c index 8bee60c42308..aff4302f41be 100644 --- a/src/util-detect-file-hash.c +++ b/src/util-detect-file-hash.c @@ -147,7 +147,7 @@ static int HashMatchHashTable(ROHashTable *hash_table, uint8_t *hash, * \retval 1 match */ int DetectFileHashMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchData *m) { SCEnter(); int ret = 0; diff --git a/src/util-detect-file-hash.h b/src/util-detect-file-hash.h index c247fb5aa387..ee0b37de61cf 100644 --- a/src/util-detect-file-hash.h +++ b/src/util-detect-file-hash.h @@ -38,7 +38,7 @@ int ReadHashString(uint8_t *, char *, char *, int, uint16_t); int LoadHashTable(ROHashTable *, char *, char *, int, uint32_t); int DetectFileHashMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - File *, const Signature *, const SigMatch *); + File *, const Signature *, const SigMatchData *); int DetectFileHashSetup(DetectEngineCtx *, Signature *, char *, uint32_t); void DetectFileHashFree(void *); From f281481b679b13f0c776a64e168c3ab8717dfbf5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 16 Oct 2016 00:07:48 +0200 Subject: [PATCH 2355/2553] detect: use detect list passed to generic funcs Until now the GenericList users used hardcoded list id's. --- src/detect-dnp3.c | 4 ++-- src/detect-engine-dns.c | 14 ++++++-------- src/detect-engine-tls.c | 5 ++--- src/detect-engine.c | 15 ++++++--------- src/detect-engine.h | 5 +++-- 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index b2b945d0bcd2..7cc965905dbd 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -166,8 +166,8 @@ static int DetectEngineInspectDNP3(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { - return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, - alstate, txv, tx_id, DETECT_SM_LIST_DNP3_MATCH); + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); } /** diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index d243ba025504..314b095685c1 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -140,20 +140,18 @@ int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) int DetectEngineInspectDnsRequest(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { - return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, - alstate, txv, tx_id, - DETECT_SM_LIST_DNSREQUEST_MATCH); + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); } int DetectEngineInspectDnsResponse(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { - return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, - alstate, txv, tx_id, - DETECT_SM_LIST_DNSRESPONSE_MATCH); + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); } diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 43db1f42ad37..9b0d35b78451 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -277,7 +277,6 @@ int DetectEngineInspectTlsValidity(ThreadVars *tv, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { - return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, f, flags, - alstate, txv, tx_id, - DETECT_SM_LIST_TLSVALIDITY_MATCH); + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); } diff --git a/src/detect-engine.c b/src/detect-engine.c index a5ccbf79f95c..45061fda2ba5 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -192,13 +192,13 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) case DETECT_SM_LIST_FILEMATCH: case DETECT_SM_LIST_DNSQUERYNAME_MATCH: - //case DETECT_SM_LIST_DNSRESPONSE_MATCH: - //case DETECT_SM_LIST_DNSRESPONSE_MATCH: + case DETECT_SM_LIST_DNSREQUEST_MATCH: + case DETECT_SM_LIST_DNSRESPONSE_MATCH: case DETECT_SM_LIST_TLSSNI_MATCH: case DETECT_SM_LIST_TLSISSUER_MATCH: case DETECT_SM_LIST_TLSSUBJECT_MATCH: - //case DETECT_SM_LIST_TLSVALIDITY_MATCH: + case DETECT_SM_LIST_TLSVALIDITY_MATCH: case DETECT_SM_LIST_APP_EVENT: @@ -352,13 +352,10 @@ int DetectEngineReloadIsDone(void) int DetectEngineInspectGenericList(ThreadVars *tv, const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, Flow *f, const uint8_t flags, - void *alstate, void *txv, uint64_t tx_id, const int list) + const Signature *s, const SigMatchData *smd, + Flow *f, const uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) { -#ifdef PROFILING - KEYWORD_PROFILING_SET_LIST(det_ctx, list); -#endif - SigMatchData *smd = s->sm_arrays[list]; SCLogDebug("running match functions, sm %p", smd); if (smd != NULL) { while (1) { diff --git a/src/detect-engine.h b/src/detect-engine.h index 378706187fbd..e3acb692e99f 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -70,9 +70,10 @@ int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id); int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id); int DetectEngineInspectGenericList(ThreadVars *, const DetectEngineCtx *, - DetectEngineThreadCtx *, const Signature *, + DetectEngineThreadCtx *, + const Signature *, const SigMatchData *, Flow *, const uint8_t, void *, void *, - uint64_t, const int); + uint64_t); /** * \brief Registers an app inspection engine. From 8edc954e828a4a4ed89a6debba86c0225712151a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 16 Oct 2016 15:30:22 +0200 Subject: [PATCH 2356/2553] detect: get rid of Signature::sm_lists Instead use the lists in init_data during setup and the SigMatchData arrays during runtime. --- src/detect-ack.c | 2 +- src/detect-app-layer-event.c | 12 +- src/detect-base64-data.c | 28 ++--- src/detect-base64-decode.c | 168 ++++++++++++------------- src/detect-byte-extract.c | 198 +++++++++++++++--------------- src/detect-bytejump.c | 194 ++++++++++++++--------------- src/detect-bytetest.c | 194 ++++++++++++++--------------- src/detect-dce-iface.c | 6 +- src/detect-dce-opnum.c | 4 +- src/detect-depth.c | 30 ++--- src/detect-detection-filter.c | 4 +- src/detect-distance.c | 30 ++--- src/detect-dsize.c | 4 +- src/detect-engine-analyzer.c | 2 +- src/detect-engine-dcepayload.c | 156 +++++++++++------------ src/detect-engine-iponly.c | 26 ++-- src/detect-engine-mpm.c | 16 ++- src/detect-engine-payload.c | 4 +- src/detect-engine-sigorder.c | 20 +-- src/detect-engine-state.c | 95 +++++++------- src/detect-engine-state.h | 2 +- src/detect-engine.c | 2 +- src/detect-fast-pattern.c | 171 ++++++++++---------------- src/detect-filestore.c | 11 +- src/detect-flags.c | 6 +- src/detect-flow.c | 2 +- src/detect-fragbits.c | 2 +- src/detect-fragoffset.c | 2 +- src/detect-ftpbounce.c | 4 +- src/detect-http-method.c | 4 +- src/detect-icmp-id.c | 2 +- src/detect-icmp-seq.c | 2 +- src/detect-icode.c | 2 +- src/detect-id.c | 2 +- src/detect-ipproto.c | 12 +- src/detect-isdataat.c | 182 +++++++++++++-------------- src/detect-itype.c | 2 +- src/detect-lua.c | 6 +- src/detect-nocase.c | 30 ++--- src/detect-offset.c | 30 ++--- src/detect-parse.c | 180 ++++++++++++++------------- src/detect-rawbytes.c | 2 +- src/detect-replace.c | 2 +- src/detect-seq.c | 2 +- src/detect-ssh-proto-version.c | 10 +- src/detect-ssh-software-version.c | 10 +- src/detect-ssl-state.c | 11 +- src/detect-ssl-version.c | 9 +- src/detect-threshold.c | 2 +- src/detect-tls-version.c | 12 +- src/detect-tls.c | 45 ++++--- src/detect-ttl.c | 2 +- src/detect-within.c | 30 ++--- src/detect.c | 165 ++++++++++++------------- src/detect.h | 25 ++-- src/util-threshold-config.c | 113 +++++------------ 56 files changed, 1123 insertions(+), 1166 deletions(-) diff --git a/src/detect-ack.c b/src/detect-ack.c index 79c33390dbba..0d36096a4d98 100644 --- a/src/detect-ack.c +++ b/src/detect-ack.c @@ -194,7 +194,7 @@ static int PrefilterSetupTcpAck(SigGroupHead *sgh) static _Bool PrefilterTcpAckIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ACK: return TRUE; diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 3e95fb57e07e..24eb6094022d 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -51,7 +51,7 @@ static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx); static int DetectAppLayerEventAppMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, const Signature *, const SigMatch *); + uint8_t, void *, const Signature *, const SigMatchData *); static int DetectAppLayerEventSetupP1(DetectEngineCtx *, Signature *, char *); static void DetectAppLayerEventRegisterTests(void); static void DetectAppLayerEventFree(void *); @@ -146,8 +146,8 @@ static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det } static int DetectAppLayerEventAppMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, const Signature *s, - const SigMatch *m) + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatchData *m) { SCEnter(); AppLayerDecoderEvents *decoder_events = NULL; @@ -370,9 +370,9 @@ static void DetectAppLayerEventFree(void *ptr) int DetectAppLayerEventPrepare(Signature *s) { - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_APP_EVENT]; - s->sm_lists[DETECT_SM_LIST_APP_EVENT] = NULL; - s->sm_lists_tail[DETECT_SM_LIST_APP_EVENT] = NULL; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_APP_EVENT]; + s->init_data->smlists[DETECT_SM_LIST_APP_EVENT] = NULL; + s->init_data->smlists_tail[DETECT_SM_LIST_APP_EVENT] = NULL; while (sm != NULL) { sm->next = sm->prev = NULL; diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c index d90d0925134c..16d36315a766 100644 --- a/src/detect-base64-data.c +++ b/src/detect-base64-data.c @@ -46,20 +46,20 @@ static int DetectBase64DataSetup(DetectEngineCtx *de_ctx, Signature *s, /* Check for a preceding base64_decode. */ pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"base64_data\" keyword seen without preceding base64_decode."); diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index 638e76203e46..d560c99ae9c3 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -205,90 +205,90 @@ static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s, else { /* Copied from detect-isdataat.c. */ pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index db379031b35c..81940c66b23e 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -532,18 +532,18 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *a s->flags |= SIG_FLAG_APPLAYER; if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[sm_list], - DETECT_PCRE, s->sm_lists_tail[sm_list]); + DETECT_CONTENT, s->init_data->smlists_tail[sm_list], + DETECT_PCRE, s->init_data->smlists_tail[sm_list]); } } else if (data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 12, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -560,95 +560,95 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *a } else if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -681,7 +681,7 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *a } SigMatch *prev_bed_sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_BYTE_EXTRACT, s->sm_lists_tail[sm_list]); + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[sm_list]); if (prev_bed_sm == NULL) data->local_id = 0; else @@ -751,7 +751,7 @@ SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, const Signature *s) int list; for (list = 0; list < DETECT_SM_LIST_MAX; list++) { - SigMatch *sm = s->sm_lists[list]; + SigMatch *sm = s->init_data->smlists[list]; while (sm != NULL) { if (sm->type == DETECT_BYTE_EXTRACT) { bed = (DetectByteExtractData *)sm->ctx; diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 78647159016e..6bb66caa872f 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -531,19 +531,19 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts s->flags |= SIG_FLAG_APPLAYER; if (data->flags & DETECT_BYTEJUMP_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[sm_list], - DETECT_PCRE, s->sm_lists_tail[sm_list]); + DETECT_CONTENT, s->init_data->smlists_tail[sm_list], + DETECT_PCRE, s->init_data->smlists_tail[sm_list]); } } else if (data->flags & DETECT_BYTEJUMP_DCE) { if (data->flags & DETECT_BYTEJUMP_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 12, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -560,95 +560,95 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts } else if (data->flags & DETECT_BYTEJUMP_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index ae14b3430e33..22fcf9e78ad6 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -458,19 +458,19 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts s->flags |= SIG_FLAG_APPLAYER; if (data->flags & DETECT_BYTETEST_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[sm_list], - DETECT_PCRE, s->sm_lists_tail[sm_list]); + DETECT_CONTENT, s->init_data->smlists_tail[sm_list], + DETECT_PCRE, s->init_data->smlists_tail[sm_list]); } } else if (data->flags & DETECT_BYTETEST_DCE) { if (data->flags & DETECT_BYTETEST_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 12, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -487,95 +487,95 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts } else if (data->flags & DETECT_BYTETEST_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 8513c9f0ce23..8bdf278f6aaf 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -52,8 +52,8 @@ static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; -static int DetectDceIfaceMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, const Signature *, const SigMatch *); +static int DetectDceIfaceMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, + void *, const Signature *, const SigMatchData *); static int DetectDceIfaceSetup(DetectEngineCtx *, Signature *, char *); static void DetectDceIfaceFree(void *); static void DetectDceIfaceRegisterTests(void); @@ -245,7 +245,7 @@ static inline int DetectDceIfaceMatchIfaceVersion(uint16_t version, */ static int DetectDceIfaceMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatch *m) + const Signature *s, const SigMatchData *m) { SCEnter(); diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index d33579aff217..064cc9563969 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -53,7 +53,7 @@ static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; static int DetectDceOpnumMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - void *, const Signature *, const SigMatch *); + void *, const Signature *, const SigMatchData *); static int DetectDceOpnumSetup(DetectEngineCtx *, Signature *, char *); static void DetectDceOpnumFree(void *); static void DetectDceOpnumRegisterTests(void); @@ -240,7 +240,7 @@ static DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) */ static int DetectDceOpnumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatch *m) + const Signature *s, const SigMatchData *m) { SCEnter(); diff --git a/src/detect-depth.c b/src/detect-depth.c index 03d7d5bfa244..f2496402382d 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -75,23 +75,23 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths /* retrive the sm to apply the depth against */ if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); + pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); } if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 7960f4526fbc..9048f458e445 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -216,14 +216,14 @@ static int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, ch /* checks if there's a previous instance of threshold */ tmpm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists_tail[DETECT_SM_LIST_MATCH]); + DETECT_THRESHOLD, s->init_data->smlists_tail[DETECT_SM_LIST_MATCH]); if (tmpm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"detection_filter\" and \"threshold\" are not allowed in the same rule"); SCReturnInt(-1); } /* checks there's no previous instance of detection_filter */ tmpm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists_tail[DETECT_SM_LIST_MATCH]); + DETECT_DETECTION_FILTER, s->init_data->smlists_tail[DETECT_SM_LIST_MATCH]); if (tmpm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "At most one \"detection_filter\" is allowed per rule"); SCReturnInt(-1); diff --git a/src/detect-distance.c b/src/detect-distance.c index 9c91c9447326..e522ef5ae4e7 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -82,23 +82,23 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, /* retrive the sm to apply the depth against */ if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); + pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); } if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "distance needs " diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 21f85a20a1ea..cb415f5151ba 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -258,7 +258,7 @@ static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr if (SigMatchGetLastSMFromLists(s, 2, DETECT_DSIZE, - s->sm_lists_tail[DETECT_SM_LIST_MATCH]) != NULL) { + s->init_data->smlists_tail[DETECT_SM_LIST_MATCH]) != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use 2 or more dsizes in " "the same sig. Invalidating signature."); goto error; @@ -366,7 +366,7 @@ static int PrefilterSetupDsize(SigGroupHead *sgh) static _Bool PrefilterDsizeIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_DSIZE: return TRUE; diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 6f4a15adc878..a74b9bae9dd1 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -595,7 +595,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { SigMatch *sm = NULL; - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_PCRE) { if (list_id == DETECT_SM_LIST_HCBDMATCH) { rule_pcre_http += 1; diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index 780b85aadae4..874e30f346bc 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -71,7 +71,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, uint16_t dce_stub_data_len; int r = 0; - if (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL || dcerpc_state == NULL) { + if (s->sm_arrays[DETECT_SM_LIST_DMATCH] == NULL || dcerpc_state == NULL) { SCReturnInt(0); } @@ -91,7 +91,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, dce_stub_data_len, 0, 0, dcerpc_state); - //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, + //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->init_data->smlists[DETECT_SM_LIST_DMATCH], f, //dce_stub_data, dce_stub_data_len, dcerpc_state); if (r == 1) { SCReturnInt(1); @@ -114,7 +114,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, dce_stub_data_len, 0, 0, dcerpc_state); - //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, + //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->init_data->smlists[DETECT_SM_LIST_DMATCH], f, //dce_stub_data, dce_stub_data_len, dcerpc_state); if (r == 1) { SCReturnInt(1); @@ -7498,16 +7498,16 @@ static int DcePayloadParseTest25(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -7621,16 +7621,16 @@ static int DcePayloadParseTest26(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -7747,16 +7747,16 @@ static int DcePayloadParseTest27(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] != NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] != NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -7874,16 +7874,16 @@ static int DcePayloadParseTest28(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -7923,7 +7923,7 @@ static int DcePayloadParseTest28(void) if (result == 0) goto end; - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8003,16 +8003,16 @@ static int DcePayloadParseTest29(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -8145,16 +8145,16 @@ static int DcePayloadParseTest30(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -8292,16 +8292,16 @@ static int DcePayloadParseTest31(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -8359,7 +8359,7 @@ static int DcePayloadParseTest31(void) if (result == 0) goto end; - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8439,16 +8439,16 @@ static int DcePayloadParseTest32(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -8506,7 +8506,7 @@ static int DcePayloadParseTest32(void) if (result == 0) goto end; - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8586,16 +8586,16 @@ static int DcePayloadParseTest33(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -8648,7 +8648,7 @@ static int DcePayloadParseTest33(void) if (result == 0) goto end; - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8729,16 +8729,16 @@ static int DcePayloadParseTest34(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -8790,7 +8790,7 @@ static int DcePayloadParseTest34(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8850,16 +8850,16 @@ static int DcePayloadParseTest35(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; @@ -8877,7 +8877,7 @@ static int DcePayloadParseTest35(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8938,16 +8938,16 @@ static int DcePayloadParseTest36(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_ISDATAAT) { result = 0; goto end; @@ -8981,7 +8981,7 @@ static int DcePayloadParseTest36(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9043,16 +9043,16 @@ static int DcePayloadParseTest37(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -9088,7 +9088,7 @@ static int DcePayloadParseTest37(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9152,16 +9152,16 @@ static int DcePayloadParseTest38(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -9210,7 +9210,7 @@ static int DcePayloadParseTest38(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9268,16 +9268,16 @@ static int DcePayloadParseTest39(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9299,7 +9299,7 @@ static int DcePayloadParseTest39(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || @@ -9357,16 +9357,16 @@ static int DcePayloadParseTest40(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9425,7 +9425,7 @@ static int DcePayloadParseTest40(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9487,16 +9487,16 @@ static int DcePayloadParseTest41(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9518,7 +9518,7 @@ static int DcePayloadParseTest41(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9822,16 +9822,16 @@ static int DcePayloadParseTest44(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_ISDATAAT) { result = 0; goto end; @@ -9866,7 +9866,7 @@ static int DcePayloadParseTest44(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9948,16 +9948,16 @@ static int DcePayloadParseTest45(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -9977,7 +9977,7 @@ static int DcePayloadParseTest45(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -10060,16 +10060,16 @@ static int DcePayloadParseTest46(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; @@ -10087,7 +10087,7 @@ static int DcePayloadParseTest46(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index 191a15363629..bd47567781d1 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -941,20 +941,22 @@ int IPOnlyMatchCompatSMs(ThreadVars *tv, Signature *s, Packet *p) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH); - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; - - while (sm != NULL) { - BUG_ON(!(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)); - KEYWORD_PROFILING_START; - if (sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm->ctx) > 0) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - sm = sm->next; - continue; + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH]; + if (smd) { + while (1) { + BUG_ON(!(sigmatch_table[smd->type].flags & SIGMATCH_IPONLY_COMPAT)); + KEYWORD_PROFILING_START; + if (sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx) > 0) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) + break; + smd++; + continue; + } + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); + return 0; } - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); - return 0; } - return 1; } diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 1faa66a2aca6..2c2d3e4c849c 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -286,7 +286,9 @@ int SignatureHasPacketContent(const Signature *s) SCReturnInt(1); } - if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if ((s->init_data != NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) || + (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL)) + { SCLogDebug("no mpm"); SCReturnInt(0); } @@ -320,7 +322,9 @@ int SignatureHasStreamContent(const Signature *s) SCReturnInt(0); } - if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if ((s->init_data != NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) || + (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL)) + { SCLogDebug("no mpm"); SCReturnInt(0); } @@ -551,13 +555,13 @@ void RetrieveFPForSig(Signature *s) /* inspect rule to see if we have the fast_pattern reg to * force using a sig, otherwise keep stats about the patterns */ for (list_id = 0; list_id < DETECT_SM_LIST_DETECT_MAX; list_id++) { - if (s->sm_lists[list_id] == NULL) + if (s->init_data->smlists[list_id] == NULL) continue; if (!FastPatternSupportEnabledForSigMatchList(list_id)) continue; - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) continue; @@ -614,7 +618,7 @@ void RetrieveFPForSig(Signature *s) int max_len = 0; int i; for (i = 0; i < count_final_sm_list; i++) { - for (sm = s->sm_lists[final_sm_list[i]]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[final_sm_list[i]]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) continue; @@ -629,7 +633,7 @@ void RetrieveFPForSig(Signature *s) } for (i = 0; i < count_final_sm_list; i++) { - for (sm = s->sm_lists[final_sm_list[i]]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[final_sm_list[i]]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) continue; diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index 0699a85fedda..ce65a08ba4e8 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -134,7 +134,7 @@ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, SCEnter(); int r = 0; - if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL) { SCReturnInt(0); } @@ -176,7 +176,7 @@ int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, SCEnter(); int r = 0; - if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL) { SCReturnInt(0); } diff --git a/src/detect-engine-sigorder.c b/src/detect-engine-sigorder.c index 1186636f5eaf..56b87c9cc614 100644 --- a/src/detect-engine-sigorder.c +++ b/src/detect-engine-sigorder.c @@ -133,7 +133,7 @@ static inline int SCSigGetFlowbitsType(Signature *sig) int flowbits_user_type = DETECT_FLOWBITS_NOT_USED; int read = 0; int write = 0; - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWBITS) { @@ -151,7 +151,7 @@ static inline int SCSigGetFlowbitsType(Signature *sig) sm = sm->next; } - sm = sig->sm_lists[DETECT_SM_LIST_POSTMATCH]; + sm = sig->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWBITS) { fb = (DetectFlowbitsData *)sm->ctx; @@ -188,7 +188,7 @@ static inline int SCSigGetFlowintType(Signature *sig) int flowint_user_type = DETECT_FLOWINT_NOT_USED; int read = 0; int write = 0; - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWINT) { @@ -212,7 +212,7 @@ static inline int SCSigGetFlowintType(Signature *sig) sm = sm->next; } - sm = sig->sm_lists[DETECT_SM_LIST_POSTMATCH]; + sm = sig->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWINT) { fi = (DetectFlowintData *)sm->ctx; @@ -263,7 +263,7 @@ static inline int SCSigGetFlowvarType(Signature *sig) int type = DETECT_FLOWVAR_NOT_USED; int read = 0; int write = 0; - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_PMATCH]; + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { pd = (DetectPcreData *)sm->ctx; @@ -274,7 +274,7 @@ static inline int SCSigGetFlowvarType(Signature *sig) sm = sm->next; } - sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; pd = NULL; while (sm != NULL) { if (sm->type == DETECT_FLOWVAR) { @@ -315,7 +315,7 @@ static inline int SCSigGetPktvarType(Signature *sig) int type = DETECT_PKTVAR_NOT_USED; int read = 0; int write = 0; - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_PMATCH]; + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { pd = (DetectPcreData *)sm->ctx; @@ -326,7 +326,7 @@ static inline int SCSigGetPktvarType(Signature *sig) sm = sm->next; } - sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; pd = NULL; while (sm != NULL) { if (sm->type == DETECT_PKTVAR) { @@ -367,7 +367,7 @@ static inline int SCSigGetXbitsType(Signature *sig, enum VarTypes type) int xbits_user_type = DETECT_XBITS_NOT_USED; int read = 0; int write = 0; - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { if (sm->type == DETECT_XBITS) { @@ -387,7 +387,7 @@ static inline int SCSigGetXbitsType(Signature *sig, enum VarTypes type) sm = sm->next; } - sm = sig->sm_lists[DETECT_SM_LIST_POSTMATCH]; + sm = sig->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; while (sm != NULL) { if (sm->type == DETECT_HOSTBITS) { fb = (DetectXbitsData *)sm->ctx; diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index c9053602a085..b64aec418f2a 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -204,7 +204,7 @@ static void DeStateSignatureAppend(DetectEngineState *state, } static void DeStateFlowRuleAppend(DetectEngineStateFlow *state, const Signature *s, - const SigMatch *sm, uint32_t inspect_flags, + const SigMatchData *smd, uint32_t inspect_flags, uint8_t direction) { int jump = 0; @@ -238,7 +238,7 @@ static void DeStateFlowRuleAppend(DetectEngineStateFlow *state, const Signature SigIntId idx = dir_state->cnt++ % DE_STATE_CHUNK_SIZE; store->store[idx].sid = s->num; store->store[idx].flags = inspect_flags; - store->store[idx].nm = sm; + store->store[idx].nm = smd; return; } @@ -393,7 +393,7 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, static int StoreState(DetectEngineThreadCtx *det_ctx, Flow *f, const uint8_t flags, const uint8_t alversion, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, const uint32_t inspect_flags, const uint16_t file_no_match) { @@ -404,7 +404,7 @@ static int StoreState(DetectEngineThreadCtx *det_ctx, } } - DeStateFlowRuleAppend(f->de_state, s, sm, inspect_flags, flags); + DeStateFlowRuleAppend(f->de_state, s, smd, inspect_flags, flags); DeStateStoreStateVersion(f, alversion, flags); return 1; } @@ -447,7 +447,7 @@ static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx, static void StoreStateTx(DetectEngineThreadCtx *det_ctx, Flow *f, const uint8_t flags, const uint8_t alversion, const uint64_t tx_id, void *tx, - const Signature *s, const SigMatch *sm, + const Signature *s, const SigMatchData *smd, const uint32_t inspect_flags, const uint16_t file_no_match, int check_before_add) { if (AppLayerParserSupportsTxDetectState(f->proto, f->alproto)) { @@ -479,7 +479,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, const Signature *s, Packet *p, Flow *f, uint8_t flags, AppProto alproto, const uint8_t alversion) { - SigMatch *sm = NULL; + SigMatchData *smd = NULL; uint16_t file_no_match = 0; uint32_t inspect_flags = 0; int alert_cnt = 0; @@ -606,7 +606,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, /* store */ StoreStateTx(det_ctx, f, flags, alversion, tx_id, tx, - s, sm, inspect_flags, file_no_match, check_before_add); + s, smd, inspect_flags, file_no_match, check_before_add); } else { StoreStateTxFileOnly(det_ctx, f, flags, tx_id, tx, file_no_match); } @@ -618,7 +618,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } /* for */ /* DCERPC matches */ - } else if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL && + } else if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL && (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2)) { @@ -648,29 +648,29 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, int amatch = 0; /* flow based matches */ KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_AMATCH); - sm = s->sm_lists[DETECT_SM_LIST_AMATCH]; - if (sm != NULL) { + smd = s->sm_arrays[DETECT_SM_LIST_AMATCH]; + if (smd != NULL) { void *alstate = FlowGetAppState(f); if (alstate == NULL) { goto end; } - for ( ; sm != NULL; sm = sm->next) { - if (sigmatch_table[sm->type].AppLayerMatch != NULL) { + while (1) { + if (sigmatch_table[smd->type].AppLayerMatch != NULL) { int match = 0; if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { SMBState *smb_state = (SMBState *)alstate; if (smb_state->dcerpc_present) { KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match == 1)); + match = sigmatch_table[smd->type]. + AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, smd); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); } } else { KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match == 1)); + match = sigmatch_table[smd->type]. + AppLayerMatch(tv, det_ctx, f, flags, alstate, s, smd); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); } if (match == 0) { @@ -678,17 +678,20 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } else if (match == 2) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; break; - } else if (match == 1 && sm->next == NULL) { + } else if (match == 1 && smd->is_last) { amatch = 1; } } + if (smd->is_last) + break; + smd++; } } /* if AMATCH and/or DMATCH are in use, see if we need to * alert and store the state */ - if ((s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL)) + if ((s->sm_arrays[DETECT_SM_LIST_AMATCH] != NULL || + s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL)) { /* if dmatch in use and match + amatch in use and match or @@ -701,8 +704,8 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; } else { - if ((amatch || s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) && - (dmatch || s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL)) + if ((amatch || s->sm_arrays[DETECT_SM_LIST_AMATCH] == NULL) && + (dmatch || s->sm_arrays[DETECT_SM_LIST_DMATCH] == NULL)) { if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, 0, @@ -717,7 +720,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } StoreState(det_ctx, f, flags, alversion, - s, sm, inspect_flags, file_no_match); + s, smd, inspect_flags, file_no_match); } end: det_ctx->tx_id = 0; @@ -948,7 +951,7 @@ static int DoInspectFlowRule(ThreadVars *tv, uint32_t inspect_flags = item->flags; int total_matches = 0; int full_match = 0; - const SigMatch *sm = NULL; + const SigMatchData *smd = NULL; const Signature *s = de_ctx->sig_array[item->sid]; RULE_PROFILING_START(p); @@ -961,39 +964,49 @@ static int DoInspectFlowRule(ThreadVars *tv, return -1; } - for (sm = item->nm; sm != NULL; sm = sm->next) { - if (sigmatch_table[sm->type].AppLayerMatch != NULL) - { + smd = item->nm; + while(1) { + if (sigmatch_table[smd->type].AppLayerMatch != NULL) { int match = 0; if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { SMBState *smb_state = (SMBState *)alstate; if (smb_state->dcerpc_present) { KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match == 1)); + match = sigmatch_table[smd->type]. + AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, smd); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); } } else { KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match == 1)); + match = sigmatch_table[smd->type]. + AppLayerMatch(tv, det_ctx, f, flags, alstate, s, smd); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); } if (match == 0) break; - else if (match == 2) + else if (match == 2) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - else if (match == 1) + break; + } + else if (match == 1) { total_matches++; + + if (smd->is_last) + full_match = 1; + } } + if (smd->is_last) + break; + smd++; } + } else { + /* AMATCH isn't there */ + full_match = 1; } - /* AMATCH part checked out, or isn't there at all */ - full_match = (sm == NULL); /* DCERPC matches */ - if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL && + if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL && (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) && !(item->flags & DE_STATE_FLAG_DCE_PAYLOAD_INSPECT)) @@ -1021,7 +1034,7 @@ static int DoInspectFlowRule(ThreadVars *tv, } } /* update full_match with DMATCH result */ - if (full_match && s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { + if (full_match && s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL) { full_match = ((inspect_flags & DE_STATE_FLAG_DCE_PAYLOAD_INSPECT) != 0); } @@ -1038,7 +1051,7 @@ static int DoInspectFlowRule(ThreadVars *tv, /* store the progress in the state */ item->flags |= inspect_flags; - item->nm = sm; + item->nm = smd; if (alert) { SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index d61faa5b2c00..3fcd7b08e382 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -123,7 +123,7 @@ typedef struct DetectEngineState_ { /* FLOW BASED (AMATCH) */ typedef struct DeStateStoreFlowRule_ { - const SigMatch *nm; + const SigMatchData *nm; uint32_t flags; SigIntId sid; } DeStateStoreFlowRule; diff --git a/src/detect-engine.c b/src/detect-engine.c index 45061fda2ba5..002e69c1a366 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -148,7 +148,7 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) DetectEngineAppInspectionEngine *t = g_app_inspect_engines; while (t != NULL) { - if (s->sm_lists[t->sm_list] == NULL) + if (s->init_data->smlists[t->sm_list] == NULL) goto next; if (t->alproto == ALPROTO_UNKNOWN) { /* special case, inspect engine applies to all protocols */ diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 8370d08af030..e844f39d11b3 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -163,25 +163,25 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a char arg_substr[128] = ""; DetectContentData *cd = NULL; - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_TLSISSUER_MATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_TLSSUBJECT_MATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HTTP_REQLINEMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_TLSSNI_MATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_TLSISSUER_MATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_TLSSUBJECT_MATCH] == NULL && + s->init_data->smlists_tail[DETECT_SM_LIST_HTTP_REQLINEMATCH] == NULL) { SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " "rule, without a preceding content based keyword. " "Currently we provide fast_pattern support for content, " @@ -195,25 +195,25 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a } SigMatch *pm = SigMatchGetLastSMFromLists(s, 38, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HTTP_REQLINEMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSSNI_MATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSISSUER_MATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_TLSSUBJECT_MATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HTTP_REQLINEMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_TLSSNI_MATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_TLSISSUER_MATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_TLSSUBJECT_MATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " "the rule, without a content context. Please use a " @@ -244,7 +244,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a int list_id = 0; for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { SigMatch *sm = NULL; - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)sm->ctx; if (tmp_cd->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -18793,13 +18793,11 @@ int DetectFastPatternTest670(void) int DetectFastPatternTest671(void) { int no_of_sigs = 6; - int result = 0; char *sigs[no_of_sigs]; Signature *s[no_of_sigs]; - Signature *sig = NULL; DetectEngineCtx *de_ctx = NULL; DetectContentData *cd = NULL; - SigMatch *sm = NULL; + SigMatchData *smd = NULL; int i = 0; sigs[0] = "alert tcp any any -> any any " @@ -18816,83 +18814,42 @@ int DetectFastPatternTest671(void) "(content:\"onetwothreefour\"; fast_pattern:0,15; sid:6;)"; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("DetectEngineCtxInit() failure\n"); - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - i = 0; - s[i] = SigInit(de_ctx, sigs[i]); - de_ctx->sig_list = sig = s[i]; - if (sig == NULL) { - printf("SigInit(de_ctx, sig1) failure\n"); - goto end; - } - i++; - for ( ; i < no_of_sigs; i++) { - s[i] = SigInit(de_ctx, sigs[i]); - sig->next = s[i]; - sig = sig->next; - if (sig == NULL) { - printf("SigInit(de_ctx, sig[%d]) failure\n", i); - goto end; - } + for (i = 0; i < no_of_sigs; i++) { + s[i] = DetectEngineAppendSig(de_ctx, sigs[i]); + FAIL_IF_NULL(s[i]); } SigGroupBuild(de_ctx); - sm = s[0]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = (DetectContentData *)sm->ctx; - if (cd->id != 0) { - printf("sm = s[0]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[0]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 0); - sm = s[1]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = (DetectContentData *)sm->ctx; - if (cd->id != 0) { - printf("sm = s[1]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[1]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 0); - sm = s[2]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = (DetectContentData *)sm->ctx; - if (cd->id != 1) { - printf("sm = s[2]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[2]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 2); - sm = s[3]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = (DetectContentData *)sm->ctx; - if (cd->id != 2) { - printf("sm = s[3]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[3]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 1); - sm = s[4]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = (DetectContentData *)sm->ctx; - if (cd->id != 2) { - printf("sm = s[4]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[4]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 1); - sm = s[5]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = (DetectContentData *)sm->ctx; - if (cd->id != 0) { - printf("sm = s[5]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[5]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 0); - result = 1; -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - } - - return result; + DetectEngineCtxFree(de_ctx); + PASS; } #endif diff --git a/src/detect-filestore.c b/src/detect-filestore.c index de11089092cc..328b2118034a 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -85,7 +85,7 @@ void DetectFilestoreRegister(void) /** * \brief apply the post match filestore with options */ -static int FilestorePostMatchWithOptions(Packet *p, Flow *f, DetectFilestoreData *filestore, FileContainer *fc, +static int FilestorePostMatchWithOptions(Packet *p, Flow *f, const DetectFilestoreData *filestore, FileContainer *fc, uint16_t file_id, uint16_t tx_id) { if (filestore == NULL) { @@ -190,7 +190,7 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack SCReturnInt(0); } - if (s->filestore_sm == NULL || p->flow == NULL) { + if ((s->filestore_ctx == NULL && !(s->flags & SIG_FLAG_FILESTORE)) || p->flow == NULL) { #ifndef DEBUG SCReturnInt(0); #else @@ -211,17 +211,16 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack p->flow->alstate, flags); /* filestore for single files only */ - if (s->filestore_sm->ctx == NULL) { + if (s->filestore_ctx == NULL) { uint16_t u; for (u = 0; u < det_ctx->filestore_cnt; u++) { FileStoreFileById(ffc, det_ctx->filestore[u].file_id); } } else { - DetectFilestoreData *filestore = (DetectFilestoreData *)s->filestore_sm->ctx; uint16_t u; for (u = 0; u < det_ctx->filestore_cnt; u++) { - FilestorePostMatchWithOptions(p, p->flow, filestore, ffc, + FilestorePostMatchWithOptions(p, p->flow, s->filestore_ctx, ffc, det_ctx->filestore[u].file_id, det_ctx->filestore[u].tx_id); } } @@ -403,7 +402,7 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *st } SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - s->filestore_sm = sm; + s->filestore_ctx = (const DetectFilestoreData *)sm->ctx; s->flags |= SIG_FLAG_FILESTORE; return 0; diff --git a/src/detect-flags.c b/src/detect-flags.c index be4232856b48..72ac60d7295f 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -519,7 +519,7 @@ static void DetectFlagsFree(void *de_ptr) int DetectFlagsSignatureNeedsSynPackets(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_FLAGS: { @@ -538,7 +538,7 @@ int DetectFlagsSignatureNeedsSynPackets(const Signature *s) int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_FLAGS: { @@ -606,7 +606,7 @@ static int PrefilterSetupTcpFlags(SigGroupHead *sgh) static _Bool PrefilterTcpFlagsIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_FLAGS: return TRUE; diff --git a/src/detect-flow.c b/src/detect-flow.c index a1d77ea17ffa..fa0a420c25af 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -437,7 +437,7 @@ static int PrefilterSetupFlow(SigGroupHead *sgh) static _Bool PrefilterFlowIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_FLOW: return TRUE; diff --git a/src/detect-fragbits.c b/src/detect-fragbits.c index 0677b5b7b402..fd1fbf18a3b2 100644 --- a/src/detect-fragbits.c +++ b/src/detect-fragbits.c @@ -378,7 +378,7 @@ static int PrefilterSetupFragBits(SigGroupHead *sgh) static _Bool PrefilterFragBitsIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_FRAGBITS: return TRUE; diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index ea65f860c640..5f7a9ec2ed6a 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -313,7 +313,7 @@ static int PrefilterSetupFragOffset(SigGroupHead *sgh) static _Bool PrefilterFragOffsetIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_FRAGOFFSET: return TRUE; diff --git a/src/detect-ftpbounce.c b/src/detect-ftpbounce.c index 4c067d7d63d7..7895c854fb86 100644 --- a/src/detect-ftpbounce.c +++ b/src/detect-ftpbounce.c @@ -48,7 +48,7 @@ #include "util-byte.h" static int DetectFtpbounceALMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, const Signature *, const SigMatch *); + uint8_t, void *, const Signature *, const SigMatchData *); static int DetectFtpbounceSetup(DetectEngineCtx *, Signature *, char *); static int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, uint32_t ip_orig, uint16_t offset); @@ -168,7 +168,7 @@ static int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, */ static int DetectFtpbounceALMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, const Signature *s, - const SigMatch *m) + const SigMatchData *m) { SCEnter(); FtpState *ftp_state =(FtpState *)state; diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 0f12b35784ba..5371b97b2e83 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -135,8 +135,8 @@ int DetectHttpMethodValidateRule(const Signature *s) if (s->alproto != ALPROTO_HTTP) return 1; - if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { - const SigMatch *sm = s->sm_lists[DETECT_SM_LIST_HMDMATCH]; + if (s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL) { + const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_HMDMATCH]; for ( ; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) continue; diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index 147a86695e01..4e9c1f9a41e1 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -310,7 +310,7 @@ static int PrefilterSetupIcmpId(SigGroupHead *sgh) static _Bool PrefilterIcmpIdIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ICMP_ID: return TRUE; diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index 1cd6971dee5a..8ef19c0512d3 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -313,7 +313,7 @@ static int PrefilterSetupIcmpSeq(SigGroupHead *sgh) static _Bool PrefilterIcmpSeqIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ICMP_SEQ: return TRUE; diff --git a/src/detect-icode.c b/src/detect-icode.c index f6a01ad9aa7a..e832f5bbfa63 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -342,7 +342,7 @@ static int PrefilterSetupICode(SigGroupHead *sgh) static _Bool PrefilterICodeIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ICODE: return TRUE; diff --git a/src/detect-id.c b/src/detect-id.c index 8b6d4df75fdc..cdc32ebc1a87 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -284,7 +284,7 @@ static int PrefilterSetupId(SigGroupHead *sgh) static _Bool PrefilterIdIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ID: return TRUE; diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index f1f559143170..16ee37c9136b 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -159,7 +159,7 @@ static DetectIPProtoData *DetectIPProtoParse(const char *optstr) static int DetectIPProtoTypePresentForOP(Signature *s, uint8_t op) { - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; DetectIPProtoData *data; while (sm != NULL) { @@ -262,7 +262,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst s->proto.proto[i] = 0xff; } } else if (lt_set && !not_set) { - SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *temp_sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO) { break; @@ -304,7 +304,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst } } else { DetectIPProtoData *data_temp; - SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *temp_sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO && ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_LT) { @@ -381,7 +381,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst } s->proto.proto[data->proto / 8] = ~(0xff << (data->proto % 8)); } else if (gt_set && !not_set) { - SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *temp_sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO) { break; @@ -424,7 +424,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst } } else { DetectIPProtoData *data_temp; - SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *temp_sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO && ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_GT) { @@ -533,7 +533,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst void DetectIPProtoRemoveAllSMs(Signature *s) { - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { if (sm->type != DETECT_IPPROTO) { diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index be09d5edcf9f..902e9dbcb700 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -219,100 +219,100 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst s->flags |= SIG_FLAG_APPLAYER; if (idad->flags & ISDATAAT_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[sm_list], - DETECT_PCRE, s->sm_lists_tail[sm_list]); + DETECT_CONTENT, s->init_data->smlists_tail[sm_list], + DETECT_PCRE, s->init_data->smlists_tail[sm_list]); } } else if (idad->flags & ISDATAAT_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], + + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (prev_pm == NULL) sm_list = DETECT_SM_LIST_PMATCH; else { diff --git a/src/detect-itype.c b/src/detect-itype.c index 3d3a0e389606..0931972b80f2 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -346,7 +346,7 @@ static int PrefilterSetupIType(SigGroupHead *sgh) static _Bool PrefilterITypeIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ITYPE: return TRUE; diff --git a/src/detect-lua.c b/src/detect-lua.c index d51746cefff6..cda8f94647e0 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -90,7 +90,7 @@ void DetectLuaRegister(void) static int DetectLuaMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, const Signature *s, const SigMatch *m); + Flow *f, uint8_t flags, void *state, const Signature *s, const SigMatchData *m); static int DetectLuaAppTxMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, @@ -538,7 +538,7 @@ static int DetectLuaAppMatchCommon (ThreadVars *t, DetectEngineThreadCtx *det_ct */ static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatch *m) + const Signature *s, const SigMatchData *m) { return DetectLuaAppMatchCommon(t, det_ctx, f, flags, state, s, m->ctx); } @@ -1052,7 +1052,7 @@ void DetectLuaPostSetup(Signature *s) SigMatch *sm; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { - for (sm = s->sm_lists[i]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_LUA) continue; diff --git a/src/detect-nocase.c b/src/detect-nocase.c index 91bf45cc840d..930f577838ab 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -81,23 +81,23 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls /* retrive the sm to apply the depth against */ if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); + pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); } if (pm == NULL) { SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "nocase needs " diff --git a/src/detect-offset.c b/src/detect-offset.c index b448f1db2512..a155a4fa3ded 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -74,23 +74,23 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) /* retrive the sm to apply the depth against */ if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); + pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); } if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs " diff --git a/src/detect-parse.c b/src/detect-parse.c index 76dc039706cc..50fd5c6240b5 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -248,7 +248,7 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s } sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"%s\" keyword " "found inside the rule without a content context. " @@ -279,8 +279,8 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s } pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[sm_list], - DETECT_PCRE, s->sm_lists_tail[sm_list]); + DETECT_CONTENT, s->init_data->smlists_tail[sm_list], + DETECT_PCRE, s->init_data->smlists_tail[sm_list]); if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; @@ -298,10 +298,10 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s /* transfer the sm from the pmatch list to hcbdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, - &s->sm_lists[DETECT_SM_LIST_PMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - &s->sm_lists[sm_list], - &s->sm_lists_tail[sm_list]); + &s->init_data->smlists[DETECT_SM_LIST_PMATCH], + &s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + &s->init_data->smlists[sm_list], + &s->init_data->smlists_tail[sm_list]); ret = 0; end: @@ -366,17 +366,17 @@ SigTableElmt *SigTableGet(char *name) */ void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list) { - if (s->sm_lists[list] == NULL) { - s->sm_lists[list] = new; - s->sm_lists_tail[list] = new; + if (s->init_data->smlists[list] == NULL) { + s->init_data->smlists[list] = new; + s->init_data->smlists_tail[list] = new; new->next = NULL; new->prev = NULL; } else { - SigMatch *cur = s->sm_lists_tail[list]; + SigMatch *cur = s->init_data->smlists_tail[list]; cur->next = new; new->prev = cur; new->next = NULL; - s->sm_lists_tail[list] = new; + s->init_data->smlists_tail[list] = new; } new->idx = s->sm_cnt; @@ -385,11 +385,11 @@ void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list) void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list) { - if (sm == s->sm_lists[sm_list]) { - s->sm_lists[sm_list] = sm->next; + if (sm == s->init_data->smlists[sm_list]) { + s->init_data->smlists[sm_list] = sm->next; } - if (sm == s->sm_lists_tail[sm_list]) { - s->sm_lists_tail[sm_list] = sm->prev; + if (sm == s->init_data->smlists_tail[sm_list]) { + s->init_data->smlists_tail[sm_list] = sm->prev; } if (sm->prev != NULL) sm->prev->next = sm->next; @@ -471,7 +471,7 @@ SigMatch *SigMatchGetLastSM(const Signature *s) int i; for (i = 0; i < DETECT_SM_LIST_MAX; i ++) { - sm_new = s->sm_lists_tail[i]; + sm_new = s->init_data->smlists_tail[i]; if (sm_new == NULL) continue; if (sm_last == NULL || sm_new->idx > sm_last->idx) @@ -518,7 +518,7 @@ int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm) int list = 0; for (list = 0; list < DETECT_SM_LIST_MAX; list++) { - const SigMatch *sm = s->sm_lists[list]; + const SigMatch *sm = s->init_data->smlists[list]; while (sm != NULL) { if (sm == key_sm) return list; @@ -994,9 +994,14 @@ Signature *SigAlloc (void) Signature *sig = SCMalloc(sizeof(Signature)); if (unlikely(sig == NULL)) return NULL; - memset(sig, 0, sizeof(Signature)); + sig->init_data = SCCalloc(1, sizeof(SignatureInitData)); + if (sig->init_data == NULL) { + SCFree(sig); + return NULL; + } + /* assign it to -1, so that we can later check if the value has been * overwritten after the Signature has been parsed, and if it hasn't been * overwritten, we can then assign the default value of 3 */ @@ -1059,12 +1064,14 @@ void SigFree(Signature *s) IPOnlyCIDRListFree(s->CidrSrc); int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { - SigMatch *sm = s->sm_lists[i]; - while (sm != NULL) { - SigMatch *nsm = sm->next; - SigMatchFree(sm); - sm = nsm; + if (s->init_data) { + for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + SigMatch *sm = s->init_data->smlists[i]; + while (sm != NULL) { + SigMatch *nsm = sm->next; + SigMatchFree(sm); + sm = nsm; + } } } SigMatchFreeArrays(s); @@ -1228,7 +1235,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_FLOW) { DetectFlowData *fd = (DetectFlowData *)sm->ctx; if (fd == NULL) @@ -1236,11 +1243,11 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (fd->flags & FLOW_PKT_TOCLIENT) { /* check for uricontent + from_server/to_client */ - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use uricontent " "/http_uri , raw_uri, http_client_body, " "http_method, http_user_agent keywords " @@ -1249,9 +1256,8 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } else if (fd->flags & FLOW_PKT_TOSERVER) { /* check for uricontent + from_server/to_client */ - if (/*s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL ||*/ - s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use http_" "server_body, http_stat_msg, http_stat_code " "with flow:to_server or flow:from_client"); @@ -1261,19 +1267,19 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } - if ((s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_SMTP) || - s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { + if ((s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_SMTP) || + s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) { sig_flags |= SIG_FLAG_TOSERVER; s->flags |= SIG_FLAG_TOSERVER; s->flags &= ~SIG_FLAG_TOCLIENT; } - if ((s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_HTTP) || - s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + if ((s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_HTTP) || + s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) { sig_flags |= SIG_FLAG_TOCLIENT; s->flags |= SIG_FLAG_TOCLIENT; s->flags &= ~SIG_FLAG_TOSERVER; @@ -1285,7 +1291,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } - if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) { if ((s->flags & (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) { SCLogError(SC_ERR_INVALID_SIGNATURE,"http_raw_header signature " "without a flow direction. Use flow:to_server for " @@ -1295,8 +1301,8 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } - if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { - for (sm = s->sm_lists[DETECT_SM_LIST_HHHDMATCH]; + if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { DetectContentData *cd = (DetectContentData *)sm->ctx; @@ -1367,19 +1373,19 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (s->flags & SIG_FLAG_REQUIRE_PACKET) { pm = SigMatchGetLastSMFromLists(s, 24, - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature has" " replace keyword linked with a modified content" @@ -1388,19 +1394,19 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] || - s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]) + if (s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA] || + s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH] || + s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " "specific matches (like dsize, flags, ttl) with stream / " @@ -1410,7 +1416,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } - for (sm = s->sm_lists[DETECT_SM_LIST_AMATCH]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_AMATCH]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_AL_APP_LAYER_PROTOCOL) continue; if (((DetectAppLayerProtocolData *)sm->ctx)->negated) @@ -1427,7 +1433,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) { if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) { s->flags |= SIG_FLAG_REQUIRE_STREAM; - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT && (((DetectContentData *)(sm->ctx))->flags & @@ -1440,13 +1446,13 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } - if (s->sm_lists[DETECT_SM_LIST_BASE64_DATA] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA] != NULL) { int list; - uint16_t idx = s->sm_lists[DETECT_SM_LIST_BASE64_DATA]->idx; + uint16_t idx = s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA]->idx; for (list = 0; list < DETECT_SM_LIST_DETECT_MAX; list++) { if (list != DETECT_SM_LIST_BASE64_DATA && - s->sm_lists[list] != NULL) { - if (s->sm_lists[list]->idx > idx) { + s->init_data->smlists[list] != NULL) { + if (s->init_data->smlists[list]->idx > idx) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Rule buffer " "cannot be reset after base64_data."); SCReturnInt(0); @@ -1462,8 +1468,8 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) #ifdef DEBUG int i; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { - if (s->sm_lists[i] != NULL) { - for (sm = s->sm_lists[i]; sm != NULL; sm = sm->next) { + if (s->init_data->smlists[i] != NULL) { + for (sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) { BUG_ON(sm == sm->prev); BUG_ON(sm == sm->next); } @@ -1543,8 +1549,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, * app layer flag wasn't already set in which case we * only consider the app layer */ if (!(sig->flags & SIG_FLAG_APPLAYER)) { - if (sig->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) { + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; for ( ; sm != NULL; sm = sm->next) { if (sigmatch_table[sm->type].Match != NULL) sig->init_flags |= SIG_FLAG_INIT_PACKET; @@ -1554,12 +1560,12 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, } } - if (sig->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) + if (sig->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) sig->flags |= SIG_FLAG_APPLAYER; - if (sig->sm_lists[DETECT_SM_LIST_DMATCH]) + if (sig->init_data->smlists[DETECT_SM_LIST_DMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_AMATCH]) + if (sig->init_data->smlists[DETECT_SM_LIST_AMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; /* for other lists this flag is set when the inspect engines * are registered */ @@ -3393,7 +3399,7 @@ int SigParseTestMpm01 (void) goto end; } - if (sig->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) { printf("sig doesn't have content list: "); goto end; } @@ -3424,7 +3430,7 @@ int SigParseTestMpm02 (void) goto end; } - if (sig->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) { printf("sig doesn't have content list: "); goto end; } diff --git a/src/detect-rawbytes.c b/src/detect-rawbytes.c index 872a71a07216..85b50392679b 100644 --- a/src/detect-rawbytes.c +++ b/src/detect-rawbytes.c @@ -66,7 +66,7 @@ static int DetectRawbytesSetup (DetectEngineCtx *de_ctx, Signature *s, char *nul } SigMatch *pm = SigMatchGetLastSMFromLists(s, 2, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SCLogError(SC_ERR_RAWBYTES_MISSING_CONTENT, "\"rawbytes\" needs a preceding content option"); SCReturnInt(-1); diff --git a/src/detect-replace.c b/src/detect-replace.c index 9e9269172c72..7f50bbd9b649 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -105,7 +105,7 @@ int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *replacestr) /* add to the latest "content" keyword from either dmatch or pmatch */ pm = SigMatchGetLastSMFromLists(s, 2, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "replace needs" "preceding content option for raw sig"); diff --git a/src/detect-seq.c b/src/detect-seq.c index f747d40a59e7..6c3bd90531cc 100644 --- a/src/detect-seq.c +++ b/src/detect-seq.c @@ -189,7 +189,7 @@ static int PrefilterSetupTcpSeq(SigGroupHead *sgh) static _Bool PrefilterTcpSeqIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_SEQ: return TRUE; diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index f22cfe386f12..322a9137fbf7 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -62,8 +62,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectSshVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, const Signature *, const SigMatch *); +static int DetectSshVersionMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, + const Signature *, const SigMatchData *); static int DetectSshVersionSetup (DetectEngineCtx *, Signature *, char *); void DetectSshVersionRegisterTests(void); void DetectSshVersionFree(void *); @@ -94,8 +95,9 @@ void DetectSshVersionRegister(void) * \retval 0 no match * \retval 1 match */ -static int DetectSshVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, const Signature *s, const SigMatch *m) +static int DetectSshVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatchData *m) { SCEnter(); diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index 7a24703b980a..a9eb19267d27 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -66,8 +66,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectSshSoftwareVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, const Signature *, const SigMatch *); +static int DetectSshSoftwareVersionMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, + const Signature *, const SigMatchData *); static int DetectSshSoftwareVersionSetup (DetectEngineCtx *, Signature *, char *); void DetectSshSoftwareVersionRegisterTests(void); void DetectSshSoftwareVersionFree(void *); @@ -99,8 +100,9 @@ void DetectSshSoftwareVersionRegister(void) * \retval 0 no match * \retval 1 match */ -static int DetectSshSoftwareVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, const Signature *s, const SigMatch *m) +static int DetectSshSoftwareVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatchData *m) { SCEnter(); diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 6be0204ebc42..64b5e7af3f5e 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -59,8 +59,9 @@ static pcre_extra *parse_regex1_study; static pcre *parse_regex2; static pcre_extra *parse_regex2_study; -static int DetectSslStateMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, const Signature *, const SigMatch *); +static int DetectSslStateMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, + const Signature *, const SigMatchData *); static int DetectSslStateSetup(DetectEngineCtx *, Signature *, char *); void DetectSslStateRegisterTests(void); void DetectSslStateFree(void *); @@ -96,10 +97,10 @@ void DetectSslStateRegister(void) * \retval 0 No match. */ static int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *alstate, const Signature *s, - const SigMatch *m) + Flow *f, uint8_t flags, void *alstate, + const Signature *s, const SigMatchData *m) { - DetectSslStateData *ssd = (DetectSslStateData *)m->ctx; + const DetectSslStateData *ssd = (const DetectSslStateData *)m->ctx; SSLState *ssl_state = (SSLState *)alstate; if (ssl_state == NULL) { SCLogDebug("no app state, no match"); diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index a699b10926ff..53dc75131652 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -60,8 +60,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectSslVersionMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, const Signature *, const SigMatch *); +static int DetectSslVersionMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, + const Signature *, const SigMatchData *); static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, char *); void DetectSslVersionRegisterTests(void); void DetectSslVersionFree(void *); @@ -94,7 +95,7 @@ void DetectSslVersionRegister(void) */ static int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatch *m) + const Signature *s, const SigMatchData *m) { SCEnter(); @@ -102,7 +103,7 @@ static int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, uint16_t ver = 0; uint8_t sig_ver = TLS_UNKNOWN; - DetectSslVersionData *ssl = (DetectSslVersionData *)m->ctx; + const DetectSslVersionData *ssl = (const DetectSslVersionData *)m->ctx; SSLState *app_state = (SSLState *)state; if (app_state == NULL) { SCLogDebug("no app state, no match"); diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 2cefc1896bbd..85849295fe4b 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -230,7 +230,7 @@ static int DetectThresholdSetup(DetectEngineCtx *de_ctx, Signature *s, char *raw /* checks if there is a previous instance of detection_filter */ tmpm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_MATCH]); + DETECT_DETECTION_FILTER, s->init_data->smlists[DETECT_SM_LIST_MATCH]); if (tmpm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"detection_filter\" and \"threshold\" are not allowed in the same rule"); SCReturnInt(-1); diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index 6482e9128224..d7ee9c8513c3 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -59,8 +59,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectTlsVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, const Signature *, const SigMatch *); +static int DetectTlsVersionMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, + const Signature *, const SigMatchData *); static int DetectTlsVersionSetup (DetectEngineCtx *, Signature *, char *); void DetectTlsVersionRegisterTests(void); void DetectTlsVersionFree(void *); @@ -93,12 +94,13 @@ void DetectTlsVersionRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectTlsVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, const Signature *s, const SigMatch *m) +static int DetectTlsVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatchData *m) { SCEnter(); - DetectTlsVersionData *tls_data = (DetectTlsVersionData *)m->ctx; + const DetectTlsVersionData *tls_data = (const DetectTlsVersionData *)m->ctx; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); diff --git a/src/detect-tls.c b/src/detect-tls.c index c97b5fd9f7bd..4b5db38213b2 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -74,19 +74,30 @@ static pcre_extra *issuerdn_parse_regex_study; static pcre *fingerprint_parse_regex; static pcre_extra *fingerprint_parse_regex_study; -static int DetectTlsSubjectMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatch *); +static int DetectTlsSubjectMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, + const Signature *, const SigMatchData *); static int DetectTlsSubjectSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsSubjectRegisterTests(void); static void DetectTlsSubjectFree(void *); -static int DetectTlsIssuerDNMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatch *); + +static int DetectTlsIssuerDNMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, + const Signature *, const SigMatchData *); static int DetectTlsIssuerDNSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsIssuerDNRegisterTests(void); static void DetectTlsIssuerDNFree(void *); -static int DetectTlsFingerprintMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatch *); + +static int DetectTlsFingerprintMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, + const Signature *, const SigMatchData *); static int DetectTlsFingerprintSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsFingerprintFree(void *); + static int DetectTlsStoreSetup (DetectEngineCtx *, Signature *, char *); -static int DetectTlsStoreMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatch *); +static int DetectTlsStoreMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, + const Signature *, const SigMatchData *); /** * \brief Registration function for keyword: tls.version @@ -149,12 +160,13 @@ void DetectTlsRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectTlsSubjectMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, const Signature *s, const SigMatch *m) +static int DetectTlsSubjectMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatchData *m) { SCEnter(); - DetectTlsData *tls_data = (DetectTlsData *)m->ctx; + const DetectTlsData *tls_data = (const DetectTlsData *)m->ctx; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -360,12 +372,13 @@ static void DetectTlsSubjectRegisterTests(void) * \retval 0 no match * \retval 1 match */ -static int DetectTlsIssuerDNMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, const Signature *s, const SigMatch *m) +static int DetectTlsIssuerDNMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatchData *m) { SCEnter(); - DetectTlsData *tls_data = (DetectTlsData *)m->ctx; + const DetectTlsData *tls_data = (const DetectTlsData *)m->ctx; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -643,11 +656,12 @@ static DetectTlsData *DetectTlsFingerprintParse (char *str) * \retval 0 no match * \retval 1 match */ -static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, const Signature *s, const SigMatch *m) +static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatchData *m) { SCEnter(); - DetectTlsData *tls_data = (DetectTlsData *)m->ctx; + const DetectTlsData *tls_data = (const DetectTlsData *)m->ctx; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -796,8 +810,9 @@ static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *str } /** \warning modifies state */ -static int DetectTlsStoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, const Signature *s, const SigMatch *m) +static int DetectTlsStoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatchData *m) { SCEnter(); diff --git a/src/detect-ttl.c b/src/detect-ttl.c index 9b7115864554..b70312e47e68 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -373,7 +373,7 @@ static int PrefilterSetupTtl(SigGroupHead *sgh) static _Bool PrefilterTtlIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_TTL: return TRUE; diff --git a/src/detect-within.c b/src/detect-within.c index f10b0275c6f0..fb35bb5ecf2a 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -86,23 +86,23 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, char *within /* retrive the sm to apply the depth against */ if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); + pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], + DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); } if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "within needs " diff --git a/src/detect.c b/src/detect.c index 00b5dfece446..27bef2c56b35 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1492,15 +1492,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } } - SCLogDebug("s->sm_lists[DETECT_SM_LIST_AMATCH] %p, " - "s->sm_lists[DETECT_SM_LIST_UMATCH] %p, " - "s->sm_lists[DETECT_SM_LIST_DMATCH] %p, " - "s->sm_lists[DETECT_SM_LIST_HCDMATCH] %p", - s->sm_lists[DETECT_SM_LIST_AMATCH], - s->sm_lists[DETECT_SM_LIST_UMATCH], - s->sm_lists[DETECT_SM_LIST_DMATCH], - s->sm_lists[DETECT_SM_LIST_HCDMATCH]); - /* consider stateful sig matches */ if (sflags & SIG_FLAG_STATE_MATCH) { if (has_state == 0) { @@ -1915,49 +1906,49 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->alproto != ALPROTO_UNKNOWN) return 0; - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; /* TMATCH list can be ignored, it contains TAGs and @@ -1979,7 +1970,7 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) cidr_item = cidr_item->next; } - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; if (sm == NULL) goto iponly; @@ -2015,49 +2006,49 @@ static int SignatureIsPDOnly(const Signature *s) if (s->alproto != ALPROTO_UNKNOWN) return 0; - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; /* TMATCH list can be ignored, it contains TAGs and @@ -2066,7 +2057,7 @@ static int SignatureIsPDOnly(const Signature *s) /* match list matches may be compatible to DP only. We follow the same * logic as IP-only so we can use that flag */ - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; if (sm == NULL) return 0; @@ -2111,7 +2102,7 @@ static int SignatureIsPDOnly(const Signature *s) static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, const Signature *s) { - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { return 1; } #if 0 @@ -2144,34 +2135,34 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) SCReturnInt(0); } - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { SCReturnInt(0); } /* check for conflicting keywords */ - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; for ( ;sm != NULL; sm = sm->next) { if ( !(sigmatch_table[sm->type].flags & SIGMATCH_DEONLY_COMPAT)) SCReturnInt(0); } /* need at least one decode event keyword to be considered decode event. */ - sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; for ( ;sm != NULL; sm = sm->next) { if (sm->type == DETECT_DECODE_EVENT) goto deonly; @@ -2290,27 +2281,27 @@ static int SignatureCreateMask(Signature *s) { SCEnter(); - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_PAYLOAD; SCLogDebug("sig requires payload"); } - if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_DMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_DCE_STATE; SCLogDebug("sig requires dce state"); } - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http state"); } - if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_FILEDATA] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL) { /* set the state depending from the protocol */ if (s->alproto == ALPROTO_HTTP) s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; @@ -2320,58 +2311,58 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http or smtp app state"); } - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } - if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_AMATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_AMATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { case DETECT_AL_URILEN: case DETECT_AL_HTTP_URI: @@ -2384,7 +2375,7 @@ static int SignatureCreateMask(Signature *s) } } - for (sm = s->sm_lists[DETECT_SM_LIST_APP_EVENT] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_APP_EVENT] ; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_AL_APP_LAYER_EVENT: { @@ -2412,7 +2403,7 @@ static int SignatureCreateMask(Signature *s) } } - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { case DETECT_FLOWBITS: { @@ -2550,7 +2541,7 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires flow"); } - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow"); } @@ -2648,7 +2639,7 @@ static void SigParseApplyDsizeToContent(Signature *s) return; } - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; for ( ; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) { continue; @@ -2671,7 +2662,7 @@ static void SigParseApplyDsizeToContent(Signature *s) /** \brief Pure-PCRE or bytetest rule */ int RuleInspectsPayloadHasNoMpm(const Signature *s) { - if (s->mpm_sm == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) + if (s->mpm_sm == NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 1; return 0; } @@ -2769,7 +2760,7 @@ json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh, if (s->mpm_sm == NULL) { nonmpm_cnt++; - if (s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_MATCH] != NULL) { SCLogDebug("SGH %p Non-MPM inspecting only packets. Rule %u", sgh, s->id); } @@ -3420,7 +3411,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) char copresent = 0; SigMatch *sm; DetectContentData *co; - for (sm = tmp_s->sm_lists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { + for (sm = tmp_s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) continue; @@ -3459,7 +3450,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) /* get the keyword supporting prefilter with the lowest type */ for (i = 0; i < DETECT_SM_LIST_DETECT_MAX; i++) { - SigMatch *sm = tmp_s->sm_lists[i]; + SigMatch *sm = tmp_s->init_data->smlists[i]; while (sm != NULL) { if (sigmatch_table[sm->type].SupportsPrefilter != NULL) { if (sigmatch_table[sm->type].SupportsPrefilter(tmp_s) == TRUE) { @@ -3473,7 +3464,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) /* apply that keyword as prefilter */ if (prefilter_list != DETECT_TBLSIZE) { for (i = 0; i < DETECT_SM_LIST_DETECT_MAX; i++) { - SigMatch *sm = tmp_s->sm_lists[i]; + SigMatch *sm = tmp_s->init_data->smlists[i]; while (sm != NULL) { if (sm->type == prefilter_list) { tmp_s->prefilter_sm = sm; @@ -3934,7 +3925,7 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) for (; s != NULL; s = s->next) { int type; for (type = 0; type < DETECT_SM_LIST_MAX; type++) { - SigMatch *sm = s->sm_lists[type]; + SigMatch *sm = s->init_data->smlists[type]; int len = SigMatchListLen(sm); if (len == 0) s->sm_arrays[type] = NULL; @@ -3954,6 +3945,10 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) } } DetectEngineAppInspectionEngine2Signature(s); + + /* TODO free lists etc */ + SCFree(s->init_data); + s->init_data = NULL; } diff --git a/src/detect.h b/src/detect.h index f091a89451d3..74efc8f84700 100644 --- a/src/detect.h +++ b/src/detect.h @@ -400,6 +400,17 @@ typedef struct DetectEngineAppInspectionEngine_ { struct DetectEngineAppInspectionEngine_ *next; } DetectEngineAppInspectionEngine; +#ifdef UNITTESTS +#define sm_lists init_data->smlists +#define sm_lists_tail init_data->smlists_tail +#endif + +typedef struct SignatureInitData_ { + /* holds all sm lists */ + struct SigMatch_ *smlists[DETECT_SM_LIST_MAX]; + /* holds all sm lists' tails */ + struct SigMatch_ *smlists_tail[DETECT_SM_LIST_MAX]; +} SignatureInitData; /** \brief Signature container */ typedef struct Signature_ { @@ -461,12 +472,8 @@ typedef struct Signature_ { /* Hold copies of the sm lists for Match() */ SigMatchData *sm_arrays[DETECT_SM_LIST_MAX]; - /* 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; + /* memory is still owned by the sm_lists/sm_arrays entry */ + const struct DetectFilestoreData_ *filestore_ctx; char *msg; @@ -499,6 +506,8 @@ typedef struct Signature_ { int prefilter_list; + SignatureInitData *init_data; + /** ptr to the next sig in the list */ struct Signature_ *next; } Signature; @@ -961,7 +970,9 @@ typedef struct SigTableElmt_ { int (*Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); /** AppLayer match function pointer */ - int (*AppLayerMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, const Signature *, const SigMatch *); + int (*AppLayerMatch)(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t flags, void *alstate, + const Signature *, const SigMatchData *); /** AppLayer TX match function pointer */ int (*AppLayerTxMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index d45f7b7030a0..46679d4bbeb8 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -449,7 +449,7 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid if (id == 0 && gid == 0) { for (s = de_ctx->sig_list; s != NULL; s = s->next) { sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " @@ -459,7 +459,7 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid } sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + DETECT_DETECTION_FILTER, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " @@ -512,7 +512,7 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid for (s = de_ctx->sig_list; s != NULL; s = s->next) { if (s->gid == gid) { sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " @@ -522,7 +522,7 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid } sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + DETECT_DETECTION_FILTER, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " @@ -585,7 +585,7 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT) { sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "a threshold set. The signature event var is " @@ -595,7 +595,7 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid } sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + DETECT_DETECTION_FILTER, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "a detection_filter set. The signature event var is " @@ -608,10 +608,10 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid #if 1 } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || parsed_type == TYPE_LIMIT) { sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); if (sm == NULL) { sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + DETECT_DETECTION_FILTER, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); } if (sm != NULL) { SigMatchRemoveSMFromList(s, sm, DETECT_SM_LIST_THRESHOLD); @@ -2609,52 +2609,27 @@ static FILE *SCThresholdConfGenerateInvalidDummyFD12() */ static int SCThresholdConfTest18(void) { - Signature *s = NULL; - int result = 0; - FILE *fd = NULL; - SigMatch *sm = NULL; - DetectThresholdData *de = NULL; - HostInitConfig(HOST_QUIET); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return result; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); - if (s == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateInvalidDummyFD12(); + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); + FAIL_IF_NULL(s); + FILE *fd = SCThresholdConfGenerateInvalidDummyFD12(); + FAIL_IF_NULL(fd); SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); - if (s->sm_lists[DETECT_SM_LIST_SUPPRESS] == NULL) { - printf("no thresholds: "); - goto end; - } - sm = s->sm_lists[DETECT_SM_LIST_SUPPRESS]; - if (sm == NULL) { - printf("no sm: "); - goto end; - } - - de = (DetectThresholdData *)sm->ctx; - if (de == NULL) { - printf("no de: "); - goto end; - } - if (!(de->type == TYPE_SUPPRESS && de->track == TRACK_DST)) { - printf("de state wrong: "); - goto end; - } + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST); - result = 1; -end: DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + PASS; } /** @@ -2684,52 +2659,24 @@ static FILE *SCThresholdConfGenerateInvalidDummyFD13() */ static int SCThresholdConfTest19(void) { - Signature *s = NULL; - int result = 0; - FILE *fd = NULL; - SigMatch *sm = NULL; - DetectThresholdData *de = NULL; - HostInitConfig(HOST_QUIET); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return result; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); - if (s == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateInvalidDummyFD13(); + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); + FAIL_IF_NULL(s); + FILE *fd = SCThresholdConfGenerateInvalidDummyFD13(); + FAIL_IF_NULL(fd); SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); - - if (s->sm_lists[DETECT_SM_LIST_SUPPRESS] == NULL) { - printf("no thresholds: "); - goto end; - } - sm = s->sm_lists[DETECT_SM_LIST_SUPPRESS]; - if (sm == NULL) { - printf("no sm: "); - goto end; - } - - de = (DetectThresholdData *)sm->ctx; - if (de == NULL) { - printf("no de: "); - goto end; - } - if (!(de->type == TYPE_SUPPRESS && de->track == TRACK_DST)) { - printf("de state wrong: "); - goto end; - } - - result = 1; -end: + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST); DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + PASS; } /** From 6f7e4adbe85e634b01f1cb480fbaee0b9238672d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 16 Oct 2016 21:29:34 +0200 Subject: [PATCH 2357/2553] detect: improve memory handling & comments --- src/detect-engine.c | 18 +++++++++++++++++- src/detect-parse.c | 23 ++++++++++++++++++++--- src/detect.c | 21 ++++++++++++++++++++- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 002e69c1a366..d6823fc14b06 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -148,7 +148,7 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) DetectEngineAppInspectionEngine *t = g_app_inspect_engines; while (t != NULL) { - if (s->init_data->smlists[t->sm_list] == NULL) + if (s->sm_arrays[t->sm_list] == NULL) goto next; if (t->alproto == ALPROTO_UNKNOWN) { /* special case, inspect engine applies to all protocols */ @@ -234,6 +234,8 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) t = t->next; } + /* clear s->sm_arrays for those lists that we put + * in the inspect engines. They own it now. */ int i; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { if (lists_used[i]) { @@ -257,6 +259,7 @@ void DetectEngineAppInspectionEngineSignatureFree(Signature *s) { SigMatchData *ptrs[DETECT_SM_LIST_MAX] = { NULL }; + /* free engines and put smd in the array */ DetectEngineAppInspectionEngine *ie = s->app_inspect; while (ie) { DetectEngineAppInspectionEngine *next = ie->next; @@ -266,9 +269,22 @@ void DetectEngineAppInspectionEngineSignatureFree(Signature *s) ie = next; } + /* free the smds */ int i; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + if (ptrs[i] == NULL) + continue; + + SigMatchData *smd = ptrs[i]; + while(1) { + if (sigmatch_table[smd->type].Free != NULL) { + sigmatch_table[smd->type].Free(smd->ctx); + } + if (smd->is_last) + break; + smd++; + } SCFree(ptrs[i]); } } diff --git a/src/detect-parse.c b/src/detect-parse.c index 50fd5c6240b5..48f34de400f5 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1041,13 +1041,26 @@ static void SigRefFree (Signature *s) SCReturn; } -static void SigMatchFreeArrays(Signature *s) +static void SigMatchFreeArrays(Signature *s, int ctxs) { if (s != NULL) { int type; for (type = 0; type < DETECT_SM_LIST_MAX; type++) { - if (s->sm_arrays[type] != NULL) + if (s->sm_arrays[type] != NULL) { + if (ctxs) { + SigMatchData *smd = s->sm_arrays[type]; + while(1) { + if (sigmatch_table[smd->type].Free != NULL) { + sigmatch_table[smd->type].Free(smd->ctx); + } + if (smd->is_last) + break; + smd++; + } + } + SCFree(s->sm_arrays[type]); + } } } } @@ -1074,7 +1087,11 @@ void SigFree(Signature *s) } } } - SigMatchFreeArrays(s); + SigMatchFreeArrays(s, (s->init_data == NULL)); + if (s->init_data) { + SCFree(s->init_data); + s->init_data = NULL; + } if (s->sp != NULL) { DetectPortCleanupList(s->sp); diff --git a/src/detect.c b/src/detect.c index 27bef2c56b35..8e8f92abdb80 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3917,6 +3917,13 @@ static int SigMatchListLen(SigMatch *sm) return len; } +/** \internal + * \brief perform final per signature setup tasks + * + * - Create SigMatchData arrays from the init only SigMatch lists + * - Setup per signature inspect engines + * - remove signature init data. + */ static int SigMatchPrepare(DetectEngineCtx *de_ctx) { SCEnter(); @@ -3940,13 +3947,25 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) for (; sm != NULL; sm = sm->next, smd++) { smd->type = sm->type; smd->ctx = sm->ctx; + sm->ctx = NULL; // SigMatch no longer owns the ctx smd->is_last = (sm->next == NULL); } } } + + /* set up inspect engines */ DetectEngineAppInspectionEngine2Signature(s); - /* TODO free lists etc */ + /* free lists. Ctx' are xferred to sm_arrays so won't get freed */ + int i; + for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + SigMatch *sm = s->init_data->smlists[i]; + while (sm != NULL) { + SigMatch *nsm = sm->next; + SigMatchFree(sm); + sm = nsm; + } + } SCFree(s->init_data); s->init_data = NULL; } From 59303d1fbb02e33e839145a32cacb6d7cf81c546 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 16 Oct 2016 21:12:32 +0200 Subject: [PATCH 2358/2553] threshold: fix and redo tests --- src/detect-engine.c | 1 - src/detect.c | 3 + src/suricata.c | 1 - src/util-threshold-config.c | 1150 ++++++++++++++--------------------- src/util-threshold-config.h | 3 +- 5 files changed, 446 insertions(+), 712 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index d6823fc14b06..bb96379f467a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2463,7 +2463,6 @@ int DetectEngineReload(SCInstance *suri) DetectEngineDeReference(&old_de_ctx); return -1; } - SCThresholdConfInitContext(new_de_ctx, NULL); SCLogDebug("set up new_de_ctx %p", new_de_ctx); /* add to master */ diff --git a/src/detect.c b/src/detect.c index 8e8f92abdb80..83df2f281551 100644 --- a/src/detect.c +++ b/src/detect.c @@ -203,6 +203,7 @@ #include "util-lua.h" #include "util-var-name.h" #include "util-classification-config.h" +#include "util-threshold-config.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -517,6 +518,8 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl SCSigOrderSignatures(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); + SCThresholdConfInitContext(de_ctx); + /* Setup the signature group lookup structure and pattern matchers */ if (SigGroupBuild(de_ctx) < 0) goto end; diff --git a/src/suricata.c b/src/suricata.c index 40ac45709dcb..06ff877662fd 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2386,7 +2386,6 @@ static int LoadSignatures(DetectEngineCtx *de_ctx, SCInstance *suri) return TM_ECODE_FAILED; } - SCThresholdConfInitContext(de_ctx, NULL); return TM_ECODE_OK; } diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index 46679d4bbeb8..c50e69146fe3 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -57,7 +57,10 @@ typedef enum ThresholdRuleType { THRESHOLD_TYPE_SUPPRESS, } ThresholdRuleType; +#ifdef UNITTESTS /* File descriptor for unittests */ +static FILE *g_ut_threshold_fp = NULL; +#endif /* common base for all options */ #define DETECT_BASE_REGEX "^\\s*(event_filter|threshold|rate_filter|suppress)\\s*gen_id\\s*(\\d+)\\s*,\\s*sig_id\\s*(\\d+)\\s*(.*)\\s*$" @@ -94,6 +97,8 @@ static pcre_extra *regex_rate_study = NULL; static pcre *regex_suppress = NULL; static pcre_extra *regex_suppress_study = NULL; +static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd); + /** * \brief Returns the path for the Threshold Config file. We check if we * can retrieve the path from the yaml conf file. If it is not present, @@ -137,26 +142,30 @@ static char *SCThresholdConfGetConfFilename(const DetectEngineCtx *de_ctx) * file. * * \param de_ctx Pointer to the Detection Engine Context. - * \param utfd Pointer for unit test file descriptor. * * \retval 0 On success. * \retval -1 On failure. */ -int SCThresholdConfInitContext(DetectEngineCtx *de_ctx, FILE *utfd) +int SCThresholdConfInitContext(DetectEngineCtx *de_ctx) { char *filename = NULL; const char *eb = NULL; - FILE *fd = utfd; int eo; int opts = 0; - +#ifndef UNITTESTS + FILE *fd = NULL; +#else + FILE *fd = g_ut_threshold_fp; if (fd == NULL) { +#endif filename = SCThresholdConfGetConfFilename(de_ctx); if ( (fd = fopen(filename, "r")) == NULL) { SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } +#ifdef UNITTESTS } +#endif regex_base = pcre_compile(DETECT_BASE_REGEX, opts, &eb, &eo, NULL); if (regex_base == NULL) { @@ -209,6 +218,9 @@ int SCThresholdConfInitContext(DetectEngineCtx *de_ctx, FILE *utfd) SCThresholdConfParseFile(de_ctx, fd); SCThresholdConfDeInitContext(de_ctx, fd); +#ifdef UNITTESTS + g_ut_threshold_fp = NULL; +#endif SCLogDebug("Global thresholding options defined"); return 0; @@ -223,7 +235,7 @@ int SCThresholdConfInitContext(DetectEngineCtx *de_ctx, FILE *utfd) * \param de_ctx Pointer to the Detection Engine Context. * \param fd Pointer to file descriptor. */ -void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd) +static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd) { if (fd != NULL) fclose(fd); @@ -1424,40 +1436,28 @@ FILE *SCThresholdConfGenerateValidDummyFD11() int SCThresholdConfTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD01(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, + DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) - result = 1; - } + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1469,39 +1469,28 @@ int SCThresholdConfTest01(void) int SCThresholdConfTest02(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:100;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:100;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD01(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, + DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_BOTH && de->track == TRACK_DST && de->count == 10 && de->seconds == 60)) - result = 1; - } -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + + FAIL_IF_NOT(de->type == TYPE_BOTH && de->track == TRACK_DST && de->count == 10 && de->seconds == 60); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1513,39 +1502,28 @@ int SCThresholdConfTest02(void) int SCThresholdConfTest03(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD01(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, + DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60)) - result = 1; - } -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1557,40 +1535,24 @@ int SCThresholdConfTest03(void) int SCThresholdConfTest04(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateInValidDummyFD02(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateInValidDummyFD02(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, + DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + FAIL_IF_NOT_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de == NULL) - return result; - else - result = 1; - } -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - return result == 0; + DetectEngineCtxFree(de_ctx); + PASS; } /** @@ -1602,66 +1564,50 @@ int SCThresholdConfTest04(void) int SCThresholdConfTest05(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - Signature *s = NULL, *ns = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1;)"); - if (sig == NULL) { - goto end; - } - - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } - - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:100;)"); - if (sig == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateValidDummyFD03(); - SCThresholdConfInitContext(de_ctx,fd); + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + + sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:100;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD03(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); + + Signature *s = de_ctx->sig_list; + SigMatch *m = SigMatchGetLastSMFromLists(s, 2, + DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + FAIL_IF_NULL(m); + FAIL_IF_NULL(m->ctx); + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); + + s = de_ctx->sig_list->next; + m = SigMatchGetLastSMFromLists(s, 2, + DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + FAIL_IF_NULL(m); + FAIL_IF_NULL(m->ctx); + de = (DetectThresholdData *)m->ctx; + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); + + s = de_ctx->sig_list->next->next; + m = SigMatchGetLastSMFromLists(s, 2, + DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + FAIL_IF_NULL(m); + FAIL_IF_NULL(m->ctx); + de = (DetectThresholdData *)m->ctx; + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); - for (s = de_ctx->sig_list; s != NULL;) { - - ns = s->next; - - if(s->id == 1 || s->id == 10 || s->id == 100) { - - m = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); - - if(m == NULL) { - goto end; - } else { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60)) - result++; - } - } - - s = ns; - } - - if(result == 3) - result = 1; - -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1673,40 +1619,28 @@ int SCThresholdConfTest05(void) int SCThresholdConfTest06(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD04(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD04(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, + DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) - result = 1; - } + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1718,40 +1652,28 @@ int SCThresholdConfTest06(void) int SCThresholdConfTest07(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD05(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD05(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_DETECTION_FILTER, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, + DETECT_DETECTION_FILTER, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) - result = 1; - } + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1764,40 +1686,28 @@ int SCThresholdConfTest07(void) int SCThresholdConfTest08(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD06(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD06(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_DETECTION_FILTER, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, + DETECT_DETECTION_FILTER, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) - result = 1; - } + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1808,65 +1718,49 @@ int SCThresholdConfTest08(void) */ int SCThresholdConfTest09(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - - HostInitConfig(HOST_QUIET); - - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; + HostInitConfig(HOST_QUIET); + struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p); + + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); - fd = SCThresholdConfGenerateValidDummyFD07(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD07(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); - p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { - result = 0; - goto end; - } - + FAIL_IF(p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)); p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { - result = 0; - goto end; - } - + FAIL_IF(p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)); p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { - result = 0; - goto end; - } + FAIL_IF(p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)); TimeSetIncrementTime(2); TimeGet(&p->ts); @@ -1874,10 +1768,7 @@ int SCThresholdConfTest09(void) p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP))) { - result = 0; - goto end; - } + FAIL_IF(p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP))); TimeSetIncrementTime(3); TimeGet(&p->ts); @@ -1885,10 +1776,7 @@ int SCThresholdConfTest09(void) p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP))) { - result = 0; - goto end; - } + FAIL_IF(p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP))); TimeSetIncrementTime(10); TimeGet(&p->ts); @@ -1896,31 +1784,18 @@ int SCThresholdConfTest09(void) p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { - result = 0; - goto end; - } + FAIL_IF(p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)); p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { - result = 0; - goto end; - } - - result = 1; + FAIL_IF(p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)); -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -1931,96 +1806,68 @@ int SCThresholdConfTest09(void) */ int SCThresholdConfTest10(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); - Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10"); - - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int alerts = 0; - - memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; - memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL || p2 == NULL) - return result; + Packet *p1 = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p1); + Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, + "172.26.0.1", "172.26.0.10"); + FAIL_IF_NULL(p2); + + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; + DetectEngineThreadCtx *det_ctx = NULL; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); - fd = SCThresholdConfGenerateValidDummyFD08(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD08(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + TimeGet(&p1->ts); - TimeGet(&p->ts); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts = PacketAlertCheck(p, 10); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF(PacketAlertCheck(p1, 10)); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - alerts += PacketAlertCheck(p2, 10); - if (alerts > 0) { - result = 0; - goto end; - } + FAIL_IF(PacketAlertCheck(p2, 10)); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts += PacketAlertCheck(p, 10); - if (alerts != 1) { - result = 0; - goto end; - } + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 1); TimeSetIncrementTime(2); - TimeGet(&p->ts); + TimeGet(&p1->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - alerts += PacketAlertCheck(p2, 10); - if (alerts != 2) { - result = 0; - goto end; - } + FAIL_IF_NOT(PacketAlertCheck(p2, 10) == 1); TimeSetIncrementTime(10); - TimeGet(&p->ts); + TimeGet(&p1->ts); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts += PacketAlertCheck(p, 10); - - if (alerts == 2) - result = 1; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 0); /* Ensure that a Threshold entry was installed at the sig */ - if (de_ctx->ths_ctx.th_entry[sig->num] == NULL) { - result = 0; - goto end; - } - -end: - UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NULL(de_ctx->ths_ctx.th_entry[s->num]); + UTHFreePacket(p1); + UTHFreePacket(p2); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2031,47 +1878,47 @@ int SCThresholdConfTest10(void) */ int SCThresholdConfTest11(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int alerts10 = 0; - int alerts11 = 0; - int alerts12 = 0; - - memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; - memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p); + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; + DetectEngineThreadCtx *det_ctx = NULL; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); - if (sig == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); + FAIL_IF_NULL(s); - fd = SCThresholdConfGenerateValidDummyFD09(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD09(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); + int alerts10 = 0; + int alerts11 = 0; + int alerts12 = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); @@ -2120,26 +1967,16 @@ int SCThresholdConfTest11(void) alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); - if (alerts10 == 4) - result = 1; - + FAIL_IF_NOT(alerts10 == 4); /* One on the first interval, another on the second */ - if (alerts11 == 2) - result = 1; - - if (alerts12 == 2) - result = 1; + FAIL_IF_NOT(alerts11 == 2); + FAIL_IF_NOT(alerts12 == 2); -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2150,47 +1987,47 @@ int SCThresholdConfTest11(void) */ int SCThresholdConfTest12(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int alerts10 = 0; - int alerts11 = 0; - int alerts12 = 0; - - memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; - memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p); + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; + DetectEngineThreadCtx *det_ctx = NULL; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); - if (sig == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); + FAIL_IF_NULL(s); - fd = SCThresholdConfGenerateValidDummyFD10(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD10(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); + int alerts10 = 0; + int alerts11 = 0; + int alerts12 = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); @@ -2239,27 +2076,16 @@ int SCThresholdConfTest12(void) alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); - /* Yes, none of the alerts will be out of the count of the given interval for type limit */ - if (alerts10 == 10) - result = 1; - + FAIL_IF_NOT(alerts10 == 10); /* One on the first interval, another on the second */ - if (alerts11 == 1) - result = 1; - - if (alerts12 == 1) - result = 1; + FAIL_IF_NOT(alerts11 == 1); + FAIL_IF_NOT(alerts12 == 1); -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2271,43 +2097,28 @@ int SCThresholdConfTest12(void) int SCThresholdConfTest13(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - HostInitConfig(HOST_QUIET); - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD11(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_SUPPRESS]); + SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, + DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_SUPPRESS]); + FAIL_IF_NULL(m); - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) - result = 1; + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); - } -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2318,61 +2129,61 @@ int SCThresholdConfTest13(void) */ int SCThresholdConfTest14(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); - Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", + Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); - Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", + FAIL_IF_NULL(p1); + Packet *p2 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", "192.168.0.100", 1234, 24); - ThreadVars th_v; + FAIL_IF_NULL(p2); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); + + ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); struct timeval ts; - memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; - - de_ctx->flags |= DE_QUIET; - - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)"); - if (sig == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateValidDummyFD11(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if ((PacketAlertCheck(p, 10000) == 0) && (PacketAlertCheck(p, 10) == 1) && - (PacketAlertCheck(p, 1000) == 1) && (PacketAlertCheck(p1, 1000) == 0)) - result = 1; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); -end: - UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NOT(PacketAlertCheck(p1, 10000) == 0); + FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 1); + FAIL_IF_NOT(PacketAlertCheck(p1, 1000) == 1); + FAIL_IF_NOT(PacketAlertCheck(p2, 1000) == 0); + + UTHFreePacket(p1); + UTHFreePacket(p2); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + PASS; } /** @@ -2383,37 +2194,32 @@ int SCThresholdConfTest14(void) */ static int SCThresholdConfTest15(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; + FAIL_IF_NULL(p); + ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; + Signature *sig = DetectEngineAppendSig(de_ctx, + "drop tcp any any -> any any (msg:\"suppress test\"; content:\"lalala\"; gid:1; sid:10000;)"); + FAIL_IF_NULL(sig); - de_ctx->flags |= DE_QUIET; - - sig = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any any (msg:\"suppress test\"; content:\"lalala\"; gid:1; sid:10000;)"); - if (sig == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateValidDummyFD11(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -2421,27 +2227,15 @@ static int SCThresholdConfTest15(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* 10000 shouldn't match */ - if (PacketAlertCheck(p, 10000) != 0) { - printf("sid 10000 should not have alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 10000) != 0); /* however, it should have set the drop flag */ - if (!(PACKET_TEST_ACTION(p, ACTION_DROP))) { - printf("sid 10000 should have set DROP flag even if suppressed: "); - goto end; - } + FAIL_IF(!(PACKET_TEST_ACTION(p, ACTION_DROP))); - result = 1; -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2452,65 +2246,47 @@ static int SCThresholdConfTest15(void) */ static int SCThresholdConfTest16(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", "192.168.0.100", 1234, 24); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; + FAIL_IF_NULL(p); + ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; + Signature *sig = DetectEngineAppendSig(de_ctx, + "drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); - de_ctx->flags |= DE_QUIET; - - sig = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)"); - if (sig == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateValidDummyFD11(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - /* 10000 shouldn't match */ - if (PacketAlertCheck(p, 1000) != 0) { - printf("sid 1000 should not have alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1000) != 0); /* however, it should have set the drop flag */ - if (!(PACKET_TEST_ACTION(p, ACTION_DROP))) { - printf("sid 1000 should have set DROP flag even if suppressed: "); - goto end; - } + FAIL_IF(!(PACKET_TEST_ACTION(p, ACTION_DROP))); - result = 1; -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2521,37 +2297,32 @@ static int SCThresholdConfTest16(void) */ static int SCThresholdConfTest17(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; + FAIL_IF_NULL(p); + ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; - - de_ctx->flags |= DE_QUIET; - - sig = de_ctx->sig_list = SigInit(de_ctx,"drop tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:10000;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "drop tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:10000;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD11(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -2559,27 +2330,15 @@ static int SCThresholdConfTest17(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* 10000 shouldn't match */ - if (PacketAlertCheck(p, 10000) != 0) { - printf("sid 10000 should not have alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 10000) != 0); /* however, it should have set the drop flag */ - if (!(PACKET_TEST_ACTION(p, ACTION_DROP))) { - printf("sid 10000 should have set DROP flag even if suppressed: "); - goto end; - } + FAIL_IF(!(PACKET_TEST_ACTION(p, ACTION_DROP))); - result = 1; -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2614,11 +2373,13 @@ static int SCThresholdConfTest18(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); FAIL_IF_NULL(s); - FILE *fd = SCThresholdConfGenerateInvalidDummyFD12(); - FAIL_IF_NULL(fd); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD12(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); @@ -2663,11 +2424,13 @@ static int SCThresholdConfTest19(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); FAIL_IF_NULL(s); - FILE *fd = SCThresholdConfGenerateInvalidDummyFD13(); - FAIL_IF_NULL(fd); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD13(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; @@ -2707,55 +2470,41 @@ FILE *SCThresholdConfGenerateValidDummyFD20() */ static int SCThresholdConfTest20(void) { - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; sid:1000;)"); + FAIL_IF_NULL(s); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); + SigGroupBuild(de_ctx); + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); - if (de_ctx == NULL) - return result; + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); - de_ctx->flags |= DE_QUIET; + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; sid:1000;)"); - if (sig == NULL) { - goto end; - } + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF_NOT(smd->is_last); - fd = SCThresholdConfGenerateValidDummyFD20(); - SCThresholdConfInitContext(de_ctx,fd); - - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_SUPPRESS]); - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - m = m->next; - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - m = m->next; - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - result = 1; - } - } - } - } - } - } -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + PASS; } /** @@ -2767,55 +2516,40 @@ static int SCThresholdConfTest20(void) */ static int SCThresholdConfTest21(void) { - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); + FAIL_IF_NULL(s); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); + SigGroupBuild(de_ctx); + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); - if (de_ctx == NULL) - return result; + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); - de_ctx->flags |= DE_QUIET; + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); - if (sig == NULL) { - goto end; - } + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF_NOT(smd->is_last); - fd = SCThresholdConfGenerateValidDummyFD20(); - SCThresholdConfInitContext(de_ctx,fd); - - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_SUPPRESS]); - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - m = m->next; - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - m = m->next; - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - result = 1; - } - } - } - } - } - } -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + PASS; } #endif /* UNITTESTS */ diff --git a/src/util-threshold-config.h b/src/util-threshold-config.h index 906ed7c6daae..459c956d0789 100644 --- a/src/util-threshold-config.h +++ b/src/util-threshold-config.h @@ -24,9 +24,8 @@ #ifndef __UTIL_THRESHOLD_CONFIG_H__ #define __UTIL_THRESHOLD_CONFIG_H__ -void SCThresholdConfDeInitContext(DetectEngineCtx *, FILE *); void SCThresholdConfParseFile(DetectEngineCtx *, FILE *); -int SCThresholdConfInitContext(DetectEngineCtx *, FILE *); +int SCThresholdConfInitContext(DetectEngineCtx *); void SCThresholdConfRegisterTests(); From 4978a7a13366fab069fbc6b5135778e7d88cc6f8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 17 Oct 2016 14:17:55 +0200 Subject: [PATCH 2359/2553] detect: reorganize id's in prep of dynamic lists --- src/detect-engine-mpm.c | 4 ++-- src/detect-parse.c | 10 +++++++++- src/detect.c | 4 ++-- src/detect.h | 42 +++++++++++++++++++++++------------------ 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 2c2d3e4c849c..92aee2c26762 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -554,7 +554,7 @@ void RetrieveFPForSig(Signature *s) /* inspect rule to see if we have the fast_pattern reg to * force using a sig, otherwise keep stats about the patterns */ - for (list_id = 0; list_id < DETECT_SM_LIST_DETECT_MAX; list_id++) { + for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { if (s->init_data->smlists[list_id] == NULL) continue; @@ -595,7 +595,7 @@ void RetrieveFPForSig(Signature *s) return; } - int final_sm_list[DETECT_SM_LIST_DETECT_MAX] = { 0 }; + int final_sm_list[DETECT_SM_LIST_MAX] = { 0 }; int count_final_sm_list = 0; int priority; diff --git a/src/detect-parse.c b/src/detect-parse.c index 48f34de400f5..b68cbf924dad 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1466,7 +1466,15 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA] != NULL) { int list; uint16_t idx = s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA]->idx; - for (list = 0; list < DETECT_SM_LIST_DETECT_MAX; list++) { + for (list = 0; list < DETECT_SM_LIST_MAX; list++) { + if (list == DETECT_SM_LIST_POSTMATCH || + list == DETECT_SM_LIST_TMATCH || + list == DETECT_SM_LIST_SUPPRESS || + list == DETECT_SM_LIST_THRESHOLD) + { + continue; + } + if (list != DETECT_SM_LIST_BASE64_DATA && s->init_data->smlists[list] != NULL) { if (s->init_data->smlists[list]->idx > idx) { diff --git a/src/detect.c b/src/detect.c index 83df2f281551..97e286e13436 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3452,7 +3452,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) int prefilter_list = DETECT_TBLSIZE; /* get the keyword supporting prefilter with the lowest type */ - for (i = 0; i < DETECT_SM_LIST_DETECT_MAX; i++) { + for (i = 0; i < DETECT_SM_LIST_MAX; i++) { SigMatch *sm = tmp_s->init_data->smlists[i]; while (sm != NULL) { if (sigmatch_table[sm->type].SupportsPrefilter != NULL) { @@ -3466,7 +3466,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) /* apply that keyword as prefilter */ if (prefilter_list != DETECT_TBLSIZE) { - for (i = 0; i < DETECT_SM_LIST_DETECT_MAX; i++) { + for (i = 0; i < DETECT_SM_LIST_MAX; i++) { SigMatch *sm = tmp_s->init_data->smlists[i]; while (sm != NULL) { if (sm->type == prefilter_list) { diff --git a/src/detect.h b/src/detect.h index 74efc8f84700..c7ab2abf071f 100644 --- a/src/detect.h +++ b/src/detect.h @@ -87,8 +87,31 @@ struct SCSigSignatureWrapper_; enum DetectSigmatchListEnum { DETECT_SM_LIST_MATCH = 0, DETECT_SM_LIST_PMATCH, + + /* list for per flow matches. Deprecated. */ + DETECT_SM_LIST_AMATCH, + + /* list for DCE matches */ + DETECT_SM_LIST_DMATCH, + + /* 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_BUILTIN_MAX, + /* list for http_uri keyword and the ones relative to it */ - DETECT_SM_LIST_UMATCH, + DETECT_SM_LIST_UMATCH = DETECT_SM_LIST_BUILTIN_MAX, /* 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 */ @@ -120,9 +143,6 @@ enum DetectSigmatchListEnum { /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, - DETECT_SM_LIST_AMATCH, - DETECT_SM_LIST_DMATCH, - DETECT_SM_LIST_FILEMATCH, DETECT_SM_LIST_DNSREQUEST_MATCH, /**< per DNS query tx match list */ @@ -139,25 +159,11 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_CIP_MATCH, DETECT_SM_LIST_ENIP_MATCH, - DETECT_SM_LIST_BASE64_DATA, - DETECT_SM_LIST_DNP3_DATA_MATCH, DETECT_SM_LIST_DNP3_MATCH, DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, - /* Demarcation between detection and post-detection lists. All - * detection lists must come before this. */ - DETECT_SM_LIST_DETECT_MAX, - - /* list for post match actions: flowbit set, flowint increment, etc */ - DETECT_SM_LIST_POSTMATCH = DETECT_SM_LIST_DETECT_MAX, - - 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, /* used for Signature->list, which indicates which list From 0a5ae415b89d322cf8d7cf71e45bd97c2166bece Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 17 Oct 2016 16:08:02 +0200 Subject: [PATCH 2360/2553] detect: shrink Signature::sm_arrays Signature::sm_arrays now only contains 'built-in' lists, and so is sized appropriately. --- src/detect-dnp3.c | 4 ++-- src/detect-engine.c | 25 ++++++++++++------------- src/detect-parse.c | 38 +++++++++++++++++++++++++++++++++++++- src/detect-parse.h | 1 + src/detect.c | 36 +++++------------------------------- src/detect.h | 5 +++-- 6 files changed, 60 insertions(+), 49 deletions(-) diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 7cc965905dbd..02e63f7d3b31 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -150,12 +150,12 @@ static int DetectEngineInspectDNP3Data(ThreadVars *tv, DetectEngineCtx *de_ctx, /* Content match - should probably be put into its own file. */ if (flags & STREAM_TOSERVER && tx->request_buffer != NULL) { r = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_arrays[DETECT_SM_LIST_DNP3_DATA_MATCH], f, tx->request_buffer, + smd, f, tx->request_buffer, tx->request_buffer_len, 0, 0, NULL); } else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { r = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_arrays[DETECT_SM_LIST_DNP3_DATA_MATCH], f, tx->response_buffer, + smd, f, tx->response_buffer, tx->response_buffer_len, 0, 0, NULL); } diff --git a/src/detect-engine.c b/src/detect-engine.c index bb96379f467a..5fa3d4fbe14a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -144,11 +144,20 @@ void DetectAppLayerInspectEngineRegister(AppProto alproto, int DetectEngineAppInspectionEngine2Signature(Signature *s) { - int lists_used[DETECT_SM_LIST_MAX] = { 0 }; + SigMatchData *ptrs[DETECT_SM_LIST_MAX] = { NULL }; + + /* convert lists to SigMatchData arrays */ + int i = 0; + for (i = DETECT_SM_LIST_BUILTIN_MAX; i < DETECT_SM_LIST_MAX; i++) { + if (s->init_data->smlists[i] == NULL) + continue; + + ptrs[i] = SigMatchList2DataArray(s->init_data->smlists[i]); + } DetectEngineAppInspectionEngine *t = g_app_inspect_engines; while (t != NULL) { - if (s->sm_arrays[t->sm_list] == NULL) + if (ptrs[t->sm_list] == NULL) goto next; if (t->alproto == ALPROTO_UNKNOWN) { /* special case, inspect engine applies to all protocols */ @@ -208,8 +217,7 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) case DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH: - new_engine->smd = s->sm_arrays[new_engine->sm_list]; - lists_used[t->sm_list] = 1; + new_engine->smd = ptrs[new_engine->sm_list]; break; default: break; @@ -234,15 +242,6 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) t = t->next; } - /* clear s->sm_arrays for those lists that we put - * in the inspect engines. They own it now. */ - int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { - if (lists_used[i]) { - s->sm_arrays[i] = NULL; - } - } - return 0; } diff --git a/src/detect-parse.c b/src/detect-parse.c index b68cbf924dad..1575823b4246 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1045,7 +1045,7 @@ static void SigMatchFreeArrays(Signature *s, int ctxs) { if (s != NULL) { int type; - for (type = 0; type < DETECT_SM_LIST_MAX; type++) { + for (type = 0; type < DETECT_SM_LIST_BUILTIN_MAX; type++) { if (s->sm_arrays[type] != NULL) { if (ctxs) { SigMatchData *smd = s->sm_arrays[type]; @@ -1228,6 +1228,42 @@ static void SigBuildAddressMatchArray(Signature *s) } } +static int SigMatchListLen(SigMatch *sm) +{ + int len = 0; + for (; sm != NULL; sm = sm->next) + len++; + + return len; +} + +/** \brief convert SigMatch list to SigMatchData array + * \note ownership of sm->ctx is transfered to smd->ctx + */ +SigMatchData* SigMatchList2DataArray(SigMatch *head) +{ + int len = SigMatchListLen(head); + if (len == 0) + return NULL; + + SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData)); + if (smd == NULL) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + exit(EXIT_FAILURE); + } + SigMatchData *out = smd; + + /* Copy sm type and Context into array */ + SigMatch *sm = head; + for (; sm != NULL; sm = sm->next, smd++) { + smd->type = sm->type; + smd->ctx = sm->ctx; + sm->ctx = NULL; // SigMatch no longer owns the ctx + smd->is_last = (sm->next == NULL); + } + return out; +} + /** * \internal * \brief validate a just parsed signature for internal inconsistencies diff --git a/src/detect-parse.h b/src/detect-parse.h index 6d1d454adf79..044fcdfd67aa 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -50,6 +50,7 @@ SigMatch *SigMatchGetLastSM(const Signature *); void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, SigMatch **, SigMatch **s, SigMatch **, SigMatch **); +SigMatchData* SigMatchList2DataArray(SigMatch *head); void SigParsePrepare(void); void SigParseRegisterTests(void); Signature *DetectEngineAppendSig(DetectEngineCtx *, char *); diff --git a/src/detect.c b/src/detect.c index 97e286e13436..f8736b81e459 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3911,15 +3911,6 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) SCReturnInt(0); } -static int SigMatchListLen(SigMatch *sm) -{ - int len = 0; - for (; sm != NULL; sm = sm->next) - len++; - - return len; -} - /** \internal * \brief perform final per signature setup tasks * @@ -3933,32 +3924,15 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) Signature *s = de_ctx->sig_list; for (; s != NULL; s = s->next) { + /* set up inspect engines */ + DetectEngineAppInspectionEngine2Signature(s); + int type; - for (type = 0; type < DETECT_SM_LIST_MAX; type++) { + for (type = 0; type < DETECT_SM_LIST_BUILTIN_MAX; type++) { SigMatch *sm = s->init_data->smlists[type]; - int len = SigMatchListLen(sm); - if (len == 0) - s->sm_arrays[type] = NULL; - else { - SigMatchData *smd = (SigMatchData*)SCMalloc(len * sizeof(SigMatchData)); - if (smd == NULL) { - SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); - exit(EXIT_FAILURE); - } - /* Copy sm type and Context into array */ - s->sm_arrays[type] = smd; - for (; sm != NULL; sm = sm->next, smd++) { - smd->type = sm->type; - smd->ctx = sm->ctx; - sm->ctx = NULL; // SigMatch no longer owns the ctx - smd->is_last = (sm->next == NULL); - } - } + s->sm_arrays[type] = SigMatchList2DataArray(sm); } - /* set up inspect engines */ - DetectEngineAppInspectionEngine2Signature(s); - /* free lists. Ctx' are xferred to sm_arrays so won't get freed */ int i; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { diff --git a/src/detect.h b/src/detect.h index c7ab2abf071f..1fb1c3f13e28 100644 --- a/src/detect.h +++ b/src/detect.h @@ -475,8 +475,9 @@ typedef struct Signature_ { DetectEngineAppInspectionEngine *app_inspect; - /* Hold copies of the sm lists for Match() */ - SigMatchData *sm_arrays[DETECT_SM_LIST_MAX]; + /* Matching structures for the built-ins. The others are in + * their inspect engines. */ + SigMatchData *sm_arrays[DETECT_SM_LIST_BUILTIN_MAX]; /* memory is still owned by the sm_lists/sm_arrays entry */ const struct DetectFilestoreData_ *filestore_ctx; From f370e881354e50d978db709d7e0f00f6a0cb5af2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 17 Oct 2016 16:54:40 +0200 Subject: [PATCH 2361/2553] detect: move init only Signature members to init_data --- src/detect-base64-data.c | 2 +- src/detect-base64-decode.c | 4 +- src/detect-byte-extract.c | 6 +- src/detect-bytejump.c | 6 +- src/detect-bytetest.c | 6 +- src/detect-content.c | 6 +- src/detect-dce-stub-data.c | 2 +- src/detect-depth.c | 4 +- src/detect-distance.c | 4 +- src/detect-dnp3.c | 2 +- src/detect-dns-query.c | 2 +- src/detect-dsize.c | 4 +- src/detect-engine-analyzer.c | 18 +- src/detect-engine-mpm.c | 28 +- src/detect-engine-prefilter-common.c | 14 +- src/detect-engine-profile.c | 5 +- src/detect-file-data.c | 6 +- src/detect-flow.c | 4 +- src/detect-http-request-line.c | 2 +- src/detect-http-response-line.c | 2 +- src/detect-ipproto.c | 398 +++++++++++++-------------- src/detect-isdataat.c | 6 +- src/detect-nocase.c | 4 +- src/detect-offset.c | 4 +- src/detect-parse.c | 58 ++-- src/detect-pcre.c | 14 +- src/detect-pkt-data.c | 4 +- src/detect-prefilter.c | 2 +- src/detect-rawbytes.c | 2 +- src/detect-template-buffer.c | 2 +- src/detect-tls-cert-issuer.c | 2 +- src/detect-tls-cert-subject.c | 2 +- src/detect-tls-sni.c | 2 +- src/detect-within.c | 4 +- src/detect.c | 79 +++--- src/detect.h | 54 ++-- 36 files changed, 378 insertions(+), 386 deletions(-) diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c index 16d36315a766..2eb4442a9134 100644 --- a/src/detect-base64-data.c +++ b/src/detect-base64-data.c @@ -66,7 +66,7 @@ static int DetectBase64DataSetup(DetectEngineCtx *de_ctx, Signature *s, return -1; } - s->list = DETECT_SM_LIST_BASE64_DATA; + s->init_data->list = DETECT_SM_LIST_BASE64_DATA; return 0; } diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index d560c99ae9c3..3d0254efe225 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -192,8 +192,8 @@ static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s, data->offset = offset; data->relative = relative; - if (s->list != DETECT_SM_LIST_NOTSET) { - sm_list = s->list; + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + sm_list = s->init_data->list; #if 0 if (data->relative) { pm = SigMatchGetLastSMFromLists(s, 4, diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 81940c66b23e..170f4b8bb675 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -519,8 +519,8 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *a goto error; int sm_list; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_FILEDATA) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list == DETECT_SM_LIST_FILEDATA) { if (data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "dce byte_extract specified " "with file_data option set."); @@ -528,7 +528,7 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *a } AppLayerHtpEnableResponseBodyCallback(); } - sm_list = s->list; + sm_list = s->init_data->list; s->flags |= SIG_FLAG_APPLAYER; if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 4, diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 6bb66caa872f..151181150026 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -518,8 +518,8 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts goto error; int sm_list; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_FILEDATA) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list == DETECT_SM_LIST_FILEDATA) { if (data->flags & DETECT_BYTEJUMP_DCE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "dce bytejump specified " "with file_data option set."); @@ -527,7 +527,7 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts } AppLayerHtpEnableResponseBodyCallback(); } - sm_list = s->list; + sm_list = s->init_data->list; s->flags |= SIG_FLAG_APPLAYER; if (data->flags & DETECT_BYTEJUMP_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 4, diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 22fcf9e78ad6..5c23e3f762fa 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -445,8 +445,8 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts goto error; int sm_list; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_FILEDATA) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list == DETECT_SM_LIST_FILEDATA) { if (data->flags & DETECT_BYTETEST_DCE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "dce bytetest specified " "with file_data option set."); @@ -454,7 +454,7 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts } AppLayerHtpEnableResponseBodyCallback(); } - sm_list = s->list; + sm_list = s->init_data->list; s->flags |= SIG_FLAG_APPLAYER; if (data->flags & DETECT_BYTETEST_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 4, diff --git a/src/detect-content.c b/src/detect-content.c index be0d054a2099..7726c4b8f78f 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -386,14 +386,14 @@ int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentstr) DetectContentPrint(cd); int sm_list; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_FILEDATA && s->alproto == ALPROTO_HTTP) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list == DETECT_SM_LIST_FILEDATA && s->alproto == ALPROTO_HTTP) { AppLayerHtpEnableResponseBodyCallback(); s->alproto = ALPROTO_HTTP; } s->flags |= SIG_FLAG_APPLAYER; - sm_list = s->list; + sm_list = s->init_data->list; } else { sm_list = DETECT_SM_LIST_PMATCH; } diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index c9a9b914571a..b9674cacff36 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -90,7 +90,7 @@ static int DetectDceStubDataSetup(DetectEngineCtx *de_ctx, Signature *s, char *a goto error; } - s->list = DETECT_SM_LIST_DMATCH; + s->init_data->list = DETECT_SM_LIST_DMATCH; s->alproto = ALPROTO_DCERPC; s->flags |= SIG_FLAG_APPLAYER; return 0; diff --git a/src/detect-depth.c b/src/detect-depth.c index f2496402382d..056c107d5914 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -74,8 +74,8 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths } /* retrive the sm to apply the depth against */ - if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->list]); + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->init_data->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], diff --git a/src/detect-distance.c b/src/detect-distance.c index e522ef5ae4e7..3eff265ce5bb 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -81,8 +81,8 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, } /* retrive the sm to apply the depth against */ - if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->list]); + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->init_data->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 02e63f7d3b31..9f47c4ff65fe 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -526,7 +526,7 @@ static void DetectDNP3ObjRegister(void) static int DetectDNP3DataSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); - s->list = DETECT_SM_LIST_DNP3_DATA_MATCH; + s->init_data->list = DETECT_SM_LIST_DNP3_DATA_MATCH; s->alproto = ALPROTO_DNP3; SCReturnInt(0); } diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 92c610c976b4..a5e7823afbd8 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -108,7 +108,7 @@ void DetectDnsQueryRegister (void) static int DetectDnsQuerySetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->list = DETECT_SM_LIST_DNSQUERYNAME_MATCH; + s->init_data->list = DETECT_SM_LIST_DNSQUERYNAME_MATCH; s->alproto = ALPROTO_DNS; return 0; } diff --git a/src/detect-dsize.c b/src/detect-dsize.c index cb415f5151ba..2e835ad8443b 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -292,8 +292,8 @@ static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr s->flags |= SIG_FLAG_REQUIRE_PACKET; s->flags |= SIG_FLAG_DSIZE; - if (s->dsize_sm == NULL) { - s->dsize_sm = sm; + if (s->init_data->dsize_sm == NULL) { + s->init_data->dsize_sm = sm; } return 0; diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index a74b9bae9dd1..850f5ba1aba3 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -77,7 +77,7 @@ void EngineAnalysisFP(Signature *s, char *line) int fast_pattern_only_set = 0; int fast_pattern_chop_set = 0; DetectContentData *fp_cd = NULL; - SigMatch *mpm_sm = s->mpm_sm; + SigMatch *mpm_sm = s->init_data->mpm_sm; if (mpm_sm != NULL) { fp_cd = (DetectContentData *)mpm_sm->ctx; @@ -95,9 +95,9 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "%s\n", line); fprintf(fp_engine_analysis_FD, " Fast Pattern analysis:\n"); - if (s->prefilter_sm != NULL) { + if (s->init_data->prefilter_sm != NULL) { fprintf(fp_engine_analysis_FD, " Prefilter on: %s\n", - sigmatch_table[s->prefilter_sm->type].name); + sigmatch_table[s->init_data->prefilter_sm->type].name); fprintf(fp_engine_analysis_FD, "\n"); return; } @@ -412,7 +412,7 @@ int PerCentEncodingMatch (uint8_t *content, uint8_t content_len) static void EngineAnalysisRulesPrintFP(const Signature *s) { DetectContentData *fp_cd = NULL; - SigMatch *mpm_sm = s->mpm_sm; + SigMatch *mpm_sm = s->init_data->mpm_sm; if (mpm_sm != NULL) { fp_cd = (DetectContentData *)mpm_sm->ctx; @@ -574,7 +574,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) uint32_t warn_no_direction = 0; uint32_t warn_both_direction = 0; - if (s->init_flags & SIG_FLAG_INIT_BIDIREC) { + if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; } @@ -822,8 +822,8 @@ void EngineAnalysisRules(const Signature *s, const char *line) rule_warning += 1; warn_offset_depth_alproto = 1; } - if (s->mpm_sm != NULL && s->alproto == ALPROTO_HTTP && - SigMatchListSMBelongsTo(s, s->mpm_sm) == DETECT_SM_LIST_PMATCH) { + if (s->init_data->mpm_sm != NULL && s->alproto == ALPROTO_HTTP && + SigMatchListSMBelongsTo(s, s->init_data->mpm_sm) == DETECT_SM_LIST_PMATCH) { rule_warning += 1; warn_non_alproto_fp_for_alproto_sig = 1; } @@ -868,9 +868,9 @@ void EngineAnalysisRules(const Signature *s, const char *line) } /* print fast pattern info */ - if (s->prefilter_sm) { + if (s->init_data->prefilter_sm) { fprintf(rule_engine_analysis_FD, " Prefilter on: %s.\n", - sigmatch_table[s->prefilter_sm->type].name); + sigmatch_table[s->init_data->prefilter_sm->type].name); } else { EngineAnalysisRulesPrintFP(s); } diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 92aee2c26762..3cd3471160f7 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -534,13 +534,13 @@ static void SetMpm(Signature *s, SigMatch *mpm_sm) cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; } } - s->mpm_sm = mpm_sm; + s->init_data->mpm_sm = mpm_sm; return; } void RetrieveFPForSig(Signature *s) { - if (s->mpm_sm != NULL) + if (s->init_data->mpm_sm != NULL) return; SigMatch *mpm_sm = NULL, *sm = NULL; @@ -927,9 +927,9 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) s = de_ctx->sig_array[sig]; if (s == NULL) continue; - if (s->mpm_sm == NULL) + if (s->init_data->mpm_sm == NULL) continue; - int list = SigMatchListSMBelongsTo(s, s->mpm_sm); + int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); if (list < 0) continue; if (list != ms->sm_list) @@ -939,7 +939,7 @@ void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) SCLogDebug("adding %u", s->id); - const DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; + const DetectContentData *cd = (DetectContentData *)s->init_data->mpm_sm->ctx; int skip = 0; /* negated logic: if mpm match can't be used to be sure about this @@ -1036,10 +1036,10 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, if (s == NULL) continue; - if (s->mpm_sm == NULL) + if (s->init_data->mpm_sm == NULL) continue; - int list = SigMatchListSMBelongsTo(s, s->mpm_sm); + int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); if (list < 0) continue; @@ -1128,10 +1128,10 @@ static MpmStore *MpmStorePrepareBufferAppLayer(DetectEngineCtx *de_ctx, if (s == NULL) continue; - if (s->mpm_sm == NULL) + if (s->init_data->mpm_sm == NULL) continue; - int list = SigMatchListSMBelongsTo(s, s->mpm_sm); + int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); if (list < 0) continue; @@ -1303,8 +1303,8 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) continue; RetrieveFPForSig(s); - if (s->mpm_sm != NULL) { - DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; + if (s->init_data->mpm_sm != NULL) { + DetectContentData *cd = (DetectContentData *)s->init_data->mpm_sm->ctx; struct_total_size += sizeof(DetectFPAndItsId); content_total_size += cd->content_len; @@ -1327,11 +1327,11 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) uint8_t *content_offset = ahb + struct_total_size; for (s = de_ctx->sig_list; s != NULL; s = s->next) { - if (s->mpm_sm != NULL) { - int sm_list = SigMatchListSMBelongsTo(s, s->mpm_sm); + if (s->init_data->mpm_sm != NULL) { + int sm_list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); BUG_ON(sm_list == -1); - DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; + DetectContentData *cd = (DetectContentData *)s->init_data->mpm_sm->ctx; DetectFPAndItsId *dup = (DetectFPAndItsId *)ahb; if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { content = cd->content + cd->fp_chop_offset; diff --git a/src/detect-engine-prefilter-common.c b/src/detect-engine-prefilter-common.c index e1bf0baa5a14..35f45e71b0a2 100644 --- a/src/detect-engine-prefilter-common.c +++ b/src/detect-engine-prefilter-common.c @@ -121,14 +121,14 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, s = sgh->match_array[sig]; if (s == NULL) continue; - if (s->prefilter_sm == NULL || s->prefilter_sm->type != sm_type) + if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type) continue; uint16_t type = 0; uint16_t value = 0; GetExtraMatch(s, &type, &value); - if (Compare(ctx->v1, s->prefilter_sm->ctx) && + if (Compare(ctx->v1, s->init_data->prefilter_sm->ctx) && ctx->type == type && ctx->value == value) { SCLogDebug("appending sid %u on %u", s->id, sig_offset); @@ -227,12 +227,12 @@ SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(SigGroupHead *sgh, int sm_typ s = sgh->match_array[sig]; if (s == NULL) continue; - if (s->prefilter_sm == NULL || s->prefilter_sm->type != sm_type) + if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type) continue; PrefilterPacketHeaderValue v; memset(&v, 0, sizeof(v)); - Set(&v, s->prefilter_sm->ctx); + Set(&v, s->init_data->prefilter_sm->ctx); ApplyToU8Hash(ctx, v, s); s->flags |= SIG_FLAG_PREFILTER; @@ -348,12 +348,12 @@ static int PrefilterSetupPacketHeaderCommon(SigGroupHead *sgh, int sm_type, s = sgh->match_array[sig]; if (s == NULL) continue; - if (s->prefilter_sm == NULL || s->prefilter_sm->type != sm_type) + if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type) continue; PrefilterPacketHeaderHashCtx ctx; memset(&ctx, 0, sizeof(ctx)); - Set(&ctx.v1, s->prefilter_sm->ctx); + Set(&ctx.v1, s->init_data->prefilter_sm->ctx); GetExtraMatch(s, &ctx.type, &ctx.value); @@ -365,7 +365,7 @@ static int PrefilterSetupPacketHeaderCommon(SigGroupHead *sgh, int sm_type, if (actx == NULL) goto error; - Set(&actx->v1, s->prefilter_sm->ctx); + Set(&actx->v1, s->init_data->prefilter_sm->ctx); actx->cnt = 1; actx->type = ctx.type; actx->value = ctx.value; diff --git a/src/detect-engine-profile.c b/src/detect-engine-profile.c index c60241792984..971c222ad653 100644 --- a/src/detect-engine-profile.c +++ b/src/detect-engine-profile.c @@ -33,6 +33,7 @@ #ifdef PROFILING #ifdef HAVE_LIBJANSSON +#if 0 static void DumpFp(const SigMatch *sm, char *pat_orig, uint32_t pat_orig_sz, char *pat_chop, uint32_t pat_chop_sz) { int fast_pattern_chop_set = 0; @@ -52,6 +53,7 @@ static void DumpFp(const SigMatch *sm, char *pat_orig, uint32_t pat_orig_sz, cha PrintRawUriBuf(pat_chop, &off, pat_chop_sz, cd->content + cd->fp_chop_offset, cd->fp_chop_len); } } +#endif SCMutex g_rule_dump_write_m = SCMUTEX_INITIALIZER; void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, const Packet *p) @@ -78,7 +80,7 @@ void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, const Packet *p) if (unlikely(js == NULL)) continue; json_object_set_new(js_sig, "sig_id", json_integer(s->id)); - +#if 0 json_object_set_new(js_sig, "mpm", (s->mpm_sm != NULL) ? json_true() : json_false()); if (s->mpm_sm != NULL) { @@ -94,6 +96,7 @@ void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, const Packet *p) json_object_set_new(js_sig, "mpm_pattern_chop", json_string(chop)); } } +#endif json_array_append_new(js_array, js_sig); } diff --git a/src/detect-file-data.c b/src/detect-file-data.c index e7098a6d4fda..167ca6713774 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -100,21 +100,21 @@ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str return -1; } - if (s->alproto == ALPROTO_HTTP && (s->init_flags & SIG_FLAG_INIT_FLOW) && + if (s->alproto == ALPROTO_HTTP && (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) && (s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with " "flow:to_server or flow:from_client with http."); return -1; } - if (s->alproto == ALPROTO_SMTP && (s->init_flags & SIG_FLAG_INIT_FLOW) && + if (s->alproto == ALPROTO_SMTP && (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) && !(s->flags & SIG_FLAG_TOSERVER) && (s->flags & SIG_FLAG_TOCLIENT)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with " "flow:to_client or flow:from_server with smtp."); return -1; } - s->list = DETECT_SM_LIST_FILEDATA; + s->init_data->list = DETECT_SM_LIST_FILEDATA; return 0; } diff --git a/src/detect-flow.c b/src/detect-flow.c index fa0a420c25af..bde034165161 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -336,7 +336,7 @@ int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, char *flowstr) goto error; /*ensure only one flow option*/ - if (s->init_flags & SIG_FLAG_INIT_FLOW) { + if (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) { SCLogError (SC_ERR_INVALID_SIGNATURE, "A signature may have only one flow option."); goto error; } @@ -367,7 +367,7 @@ int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, char *flowstr) if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) { s->flags |= SIG_FLAG_REQUIRE_PACKET; } else { - s->init_flags |= SIG_FLAG_INIT_FLOW; + s->init_data->init_flags |= SIG_FLAG_INIT_FLOW; } return 0; diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 8fabe28ff028..8f4b9fd9322f 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -111,7 +111,7 @@ void DetectHttpRequestLineRegister(void) */ int DetectHttpRequestLineSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { - s->list = DETECT_SM_LIST_HTTP_REQLINEMATCH; + s->init_data->list = DETECT_SM_LIST_HTTP_REQLINEMATCH; s->alproto = ALPROTO_HTTP; return 0; } diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index 125771a8e614..b3a369eeb4c3 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -111,7 +111,7 @@ void DetectHttpResponseLineRegister(void) */ int DetectHttpResponseLineSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { - s->list = DETECT_SM_LIST_HTTP_RESLINEMATCH; + s->init_data->list = DETECT_SM_LIST_HTTP_RESLINEMATCH; s->alproto = ALPROTO_HTTP; return 0; } diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index 16ee37c9136b..944b03817d29 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -216,7 +216,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst if (s->proto.flags & (DETECT_PROTO_ANY | DETECT_PROTO_IPV6 | DETECT_PROTO_IPV4)) { s->proto.flags &= ~DETECT_PROTO_ANY; memset(s->proto.proto, 0x00, sizeof(s->proto.proto)); - s->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + s->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; } else { /* The ipproto engine has a relationship with the protocol that is * set after the action and also the app protocol(that can also be @@ -224,7 +224,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst * An ip_proto keyword can be used only with alert ip, which if * not true we error out on the sig. And hence the init_flag to * indicate this. */ - if (!(s->init_flags & SIG_FLAG_INIT_FIRST_IPPROTO_SEEN)) { + if (!(s->init_data->init_flags & SIG_FLAG_INIT_FIRST_IPPROTO_SEEN)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature can use " "ip_proto keyword only when we use alert ip, " "in which case the _ANY flag is set on the sig " @@ -610,7 +610,7 @@ static int DetectIPProtoTestSetup01(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { @@ -650,7 +650,7 @@ static int DetectIPProtoTestSetup02(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { @@ -687,7 +687,7 @@ static int DetectIPProtoTestSetup03(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { @@ -723,7 +723,7 @@ static int DetectIPProtoTestSetup04(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { @@ -759,7 +759,7 @@ static int DetectIPProtoTestSetup05(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { @@ -794,7 +794,7 @@ static int DetectIPProtoTestSetup06(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -821,7 +821,7 @@ static int DetectIPProtoTestSetup07(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -848,7 +848,7 @@ static int DetectIPProtoTestSetup08(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -875,7 +875,7 @@ static int DetectIPProtoTestSetup09(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -902,7 +902,7 @@ static int DetectIPProtoTestSetup10(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -929,7 +929,7 @@ static int DetectIPProtoTestSetup11(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -956,7 +956,7 @@ static int DetectIPProtoTestSetup12(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -983,7 +983,7 @@ static int DetectIPProtoTestSetup13(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1007,7 +1007,7 @@ static int DetectIPProtoTestSetup14(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1033,7 +1033,7 @@ static int DetectIPProtoTestSetup15(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1069,7 +1069,7 @@ static int DetectIPProtoTestSetup15(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1114,7 +1114,7 @@ static int DetectIPProtoTestSetup16(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1150,7 +1150,7 @@ static int DetectIPProtoTestSetup16(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1195,7 +1195,7 @@ static int DetectIPProtoTestSetup17(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1231,7 +1231,7 @@ static int DetectIPProtoTestSetup17(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1272,7 +1272,7 @@ static int DetectIPProtoTestSetup18(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1308,7 +1308,7 @@ static int DetectIPProtoTestSetup18(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1350,7 +1350,7 @@ static int DetectIPProtoTestSetup19(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1389,7 +1389,7 @@ static int DetectIPProtoTestSetup19(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1436,7 +1436,7 @@ static int DetectIPProtoTestSetup20(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1473,7 +1473,7 @@ static int DetectIPProtoTestSetup20(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1521,7 +1521,7 @@ static int DetectIPProtoTestSetup21(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1560,7 +1560,7 @@ static int DetectIPProtoTestSetup21(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1608,7 +1608,7 @@ static int DetectIPProtoTestSetup22(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1647,7 +1647,7 @@ static int DetectIPProtoTestSetup22(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1694,7 +1694,7 @@ static int DetectIPProtoTestSetup23(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -1731,7 +1731,7 @@ static int DetectIPProtoTestSetup23(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -1779,7 +1779,7 @@ static int DetectIPProtoTestSetup24(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -1818,7 +1818,7 @@ static int DetectIPProtoTestSetup24(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -1866,7 +1866,7 @@ static int DetectIPProtoTestSetup25(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1905,7 +1905,7 @@ static int DetectIPProtoTestSetup25(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1952,7 +1952,7 @@ static int DetectIPProtoTestSetup26(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1988,7 +1988,7 @@ static int DetectIPProtoTestSetup26(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2036,7 +2036,7 @@ static int DetectIPProtoTestSetup27(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2074,7 +2074,7 @@ static int DetectIPProtoTestSetup27(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2122,7 +2122,7 @@ static int DetectIPProtoTestSetup28(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2161,7 +2161,7 @@ static int DetectIPProtoTestSetup28(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2208,7 +2208,7 @@ static int DetectIPProtoTestSetup29(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2245,7 +2245,7 @@ static int DetectIPProtoTestSetup29(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2293,7 +2293,7 @@ static int DetectIPProtoTestSetup30(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2332,7 +2332,7 @@ static int DetectIPProtoTestSetup30(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2380,7 +2380,7 @@ static int DetectIPProtoTestSetup31(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2419,7 +2419,7 @@ static int DetectIPProtoTestSetup31(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2466,7 +2466,7 @@ static int DetectIPProtoTestSetup32(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2503,7 +2503,7 @@ static int DetectIPProtoTestSetup32(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2551,7 +2551,7 @@ static int DetectIPProtoTestSetup33(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2590,7 +2590,7 @@ static int DetectIPProtoTestSetup33(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2639,7 +2639,7 @@ static int DetectIPProtoTestSetup34(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2678,7 +2678,7 @@ static int DetectIPProtoTestSetup34(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2707,7 +2707,7 @@ static int DetectIPProtoTestSetup35(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2744,7 +2744,7 @@ static int DetectIPProtoTestSetup35(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2792,7 +2792,7 @@ static int DetectIPProtoTestSetup36(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2831,7 +2831,7 @@ static int DetectIPProtoTestSetup36(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2879,7 +2879,7 @@ static int DetectIPProtoTestSetup37(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2918,7 +2918,7 @@ static int DetectIPProtoTestSetup37(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2958,7 +2958,7 @@ static int DetectIPProtoTestSetup38(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2995,7 +2995,7 @@ static int DetectIPProtoTestSetup38(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3036,7 +3036,7 @@ static int DetectIPProtoTestSetup39(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3075,7 +3075,7 @@ static int DetectIPProtoTestSetup39(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3117,7 +3117,7 @@ static int DetectIPProtoTestSetup40(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3156,7 +3156,7 @@ static int DetectIPProtoTestSetup40(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3197,7 +3197,7 @@ static int DetectIPProtoTestSetup41(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3234,7 +3234,7 @@ static int DetectIPProtoTestSetup41(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3276,7 +3276,7 @@ static int DetectIPProtoTestSetup42(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3315,7 +3315,7 @@ static int DetectIPProtoTestSetup42(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3357,7 +3357,7 @@ static int DetectIPProtoTestSetup43(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3400,7 +3400,7 @@ static int DetectIPProtoTestSetup43(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3451,7 +3451,7 @@ static int DetectIPProtoTestSetup44(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3491,7 +3491,7 @@ static int DetectIPProtoTestSetup44(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3543,7 +3543,7 @@ static int DetectIPProtoTestSetup45(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3586,7 +3586,7 @@ static int DetectIPProtoTestSetup45(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3636,7 +3636,7 @@ static int DetectIPProtoTestSetup46(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3674,7 +3674,7 @@ static int DetectIPProtoTestSetup46(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3725,7 +3725,7 @@ static int DetectIPProtoTestSetup47(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3765,7 +3765,7 @@ static int DetectIPProtoTestSetup47(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3815,7 +3815,7 @@ static int DetectIPProtoTestSetup48(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3853,7 +3853,7 @@ static int DetectIPProtoTestSetup48(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3905,7 +3905,7 @@ static int DetectIPProtoTestSetup49(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3945,7 +3945,7 @@ static int DetectIPProtoTestSetup49(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3993,7 +3993,7 @@ static int DetectIPProtoTestSetup50(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4033,7 +4033,7 @@ static int DetectIPProtoTestSetup50(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4082,7 +4082,7 @@ static int DetectIPProtoTestSetup51(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4122,7 +4122,7 @@ static int DetectIPProtoTestSetup51(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4169,7 +4169,7 @@ static int DetectIPProtoTestSetup52(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4207,7 +4207,7 @@ static int DetectIPProtoTestSetup52(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4255,7 +4255,7 @@ static int DetectIPProtoTestSetup53(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4295,7 +4295,7 @@ static int DetectIPProtoTestSetup53(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4342,7 +4342,7 @@ static int DetectIPProtoTestSetup54(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4380,7 +4380,7 @@ static int DetectIPProtoTestSetup54(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4427,7 +4427,7 @@ static int DetectIPProtoTestSetup55(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4465,7 +4465,7 @@ static int DetectIPProtoTestSetup55(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4513,7 +4513,7 @@ static int DetectIPProtoTestSetup56(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4553,7 +4553,7 @@ static int DetectIPProtoTestSetup56(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4600,7 +4600,7 @@ static int DetectIPProtoTestSetup57(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4638,7 +4638,7 @@ static int DetectIPProtoTestSetup57(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4686,7 +4686,7 @@ static int DetectIPProtoTestSetup58(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4726,7 +4726,7 @@ static int DetectIPProtoTestSetup58(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4774,7 +4774,7 @@ static int DetectIPProtoTestSetup59(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4814,7 +4814,7 @@ static int DetectIPProtoTestSetup59(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4862,7 +4862,7 @@ static int DetectIPProtoTestSetup60(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4902,7 +4902,7 @@ static int DetectIPProtoTestSetup60(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4949,7 +4949,7 @@ static int DetectIPProtoTestSetup61(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4987,7 +4987,7 @@ static int DetectIPProtoTestSetup61(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5038,7 +5038,7 @@ static int DetectIPProtoTestSetup62(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5078,7 +5078,7 @@ static int DetectIPProtoTestSetup62(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5128,7 +5128,7 @@ static int DetectIPProtoTestSetup63(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5166,7 +5166,7 @@ static int DetectIPProtoTestSetup63(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5218,7 +5218,7 @@ static int DetectIPProtoTestSetup64(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5261,7 +5261,7 @@ static int DetectIPProtoTestSetup64(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5312,7 +5312,7 @@ static int DetectIPProtoTestSetup65(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -5352,7 +5352,7 @@ static int DetectIPProtoTestSetup65(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -5404,7 +5404,7 @@ static int DetectIPProtoTestSetup66(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -5447,7 +5447,7 @@ static int DetectIPProtoTestSetup66(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -5498,7 +5498,7 @@ static int DetectIPProtoTestSetup67(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5543,7 +5543,7 @@ static int DetectIPProtoTestSetup68(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5588,7 +5588,7 @@ static int DetectIPProtoTestSetup69(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5626,7 +5626,7 @@ static int DetectIPProtoTestSetup70(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5664,7 +5664,7 @@ static int DetectIPProtoTestSetup71(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5702,7 +5702,7 @@ static int DetectIPProtoTestSetup72(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5740,7 +5740,7 @@ static int DetectIPProtoTestSetup73(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5785,7 +5785,7 @@ static int DetectIPProtoTestSetup74(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5829,7 +5829,7 @@ static int DetectIPProtoTestSetup75(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5866,7 +5866,7 @@ static int DetectIPProtoTestSetup76(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5903,7 +5903,7 @@ static int DetectIPProtoTestSetup77(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5940,7 +5940,7 @@ static int DetectIPProtoTestSetup78(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5978,7 +5978,7 @@ static int DetectIPProtoTestSetup79(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6015,7 +6015,7 @@ static int DetectIPProtoTestSetup80(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6052,7 +6052,7 @@ static int DetectIPProtoTestSetup81(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6090,7 +6090,7 @@ static int DetectIPProtoTestSetup82(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6128,7 +6128,7 @@ static int DetectIPProtoTestSetup83(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6166,7 +6166,7 @@ static int DetectIPProtoTestSetup84(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6204,7 +6204,7 @@ static int DetectIPProtoTestSetup85(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6242,7 +6242,7 @@ static int DetectIPProtoTestSetup86(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6281,7 +6281,7 @@ static int DetectIPProtoTestSetup87(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6329,7 +6329,7 @@ static int DetectIPProtoTestSetup88(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6377,7 +6377,7 @@ static int DetectIPProtoTestSetup89(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6425,7 +6425,7 @@ static int DetectIPProtoTestSetup90(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6473,7 +6473,7 @@ static int DetectIPProtoTestSetup91(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -6521,7 +6521,7 @@ static int DetectIPProtoTestSetup92(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -6569,7 +6569,7 @@ static int DetectIPProtoTestSetup93(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6614,7 +6614,7 @@ static int DetectIPProtoTestSetup94(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6659,7 +6659,7 @@ static int DetectIPProtoTestSetup95(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6704,7 +6704,7 @@ static int DetectIPProtoTestSetup96(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6749,7 +6749,7 @@ static int DetectIPProtoTestSetup97(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -6794,7 +6794,7 @@ static int DetectIPProtoTestSetup98(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -6840,7 +6840,7 @@ static int DetectIPProtoTestSetup99(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6886,7 +6886,7 @@ static int DetectIPProtoTestSetup100(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6932,7 +6932,7 @@ static int DetectIPProtoTestSetup101(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6978,7 +6978,7 @@ static int DetectIPProtoTestSetup102(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7024,7 +7024,7 @@ static int DetectIPProtoTestSetup103(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7070,7 +7070,7 @@ static int DetectIPProtoTestSetup104(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7116,7 +7116,7 @@ static int DetectIPProtoTestSetup105(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7165,7 +7165,7 @@ static int DetectIPProtoTestSetup106(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7214,7 +7214,7 @@ static int DetectIPProtoTestSetup107(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7263,7 +7263,7 @@ static int DetectIPProtoTestSetup108(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7312,7 +7312,7 @@ static int DetectIPProtoTestSetup109(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7361,7 +7361,7 @@ static int DetectIPProtoTestSetup110(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7409,7 +7409,7 @@ static int DetectIPProtoTestSetup111(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7457,7 +7457,7 @@ static int DetectIPProtoTestSetup112(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7505,7 +7505,7 @@ static int DetectIPProtoTestSetup113(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7553,7 +7553,7 @@ static int DetectIPProtoTestSetup114(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7601,7 +7601,7 @@ static int DetectIPProtoTestSetup115(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7649,7 +7649,7 @@ static int DetectIPProtoTestSetup116(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7697,7 +7697,7 @@ static int DetectIPProtoTestSetup117(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7745,7 +7745,7 @@ static int DetectIPProtoTestSetup118(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7793,7 +7793,7 @@ static int DetectIPProtoTestSetup119(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7841,7 +7841,7 @@ static int DetectIPProtoTestSetup120(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7889,7 +7889,7 @@ static int DetectIPProtoTestSetup121(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7937,7 +7937,7 @@ static int DetectIPProtoTestSetup122(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7985,7 +7985,7 @@ static int DetectIPProtoTestSetup123(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8033,7 +8033,7 @@ static int DetectIPProtoTestSetup124(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8081,7 +8081,7 @@ static int DetectIPProtoTestSetup125(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8129,7 +8129,7 @@ static int DetectIPProtoTestSetup126(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8177,7 +8177,7 @@ static int DetectIPProtoTestSetup127(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -8225,7 +8225,7 @@ static int DetectIPProtoTestSetup128(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -8271,7 +8271,7 @@ static int DetectIPProtoTestSetup129(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8308,7 +8308,7 @@ static int DetectIPProtoTestSetup130(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8345,7 +8345,7 @@ static int DetectIPProtoTestSetup131(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8382,7 +8382,7 @@ static int DetectIPProtoTestSetup132(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8419,7 +8419,7 @@ static int DetectIPProtoTestSetup133(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8457,7 +8457,7 @@ static int DetectIPProtoTestSetup134(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8501,7 +8501,7 @@ static int DetectIPProtoTestSetup135(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8565,7 +8565,7 @@ static int DetectIPProtoTestSetup136(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; @@ -8629,7 +8629,7 @@ static int DetectIPProtoTestSetup137(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; @@ -8693,7 +8693,7 @@ static int DetectIPProtoTestSetup138(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8757,7 +8757,7 @@ static int DetectIPProtoTestSetup139(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; @@ -8821,7 +8821,7 @@ static int DetectIPProtoTestSetup140(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; @@ -8885,7 +8885,7 @@ static int DetectIPProtoTestSetup141(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; @@ -8949,7 +8949,7 @@ static int DetectIPProtoTestSetup142(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; @@ -9015,7 +9015,7 @@ static int DetectIPProtoTestSetup143(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -9085,7 +9085,7 @@ static int DetectIPProtoTestSetup144(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value10_str) != 0) goto end; @@ -9155,7 +9155,7 @@ static int DetectIPProtoTestSetup145(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 902e9dbcb700..92d69d562c35 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -210,12 +210,12 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst return -1; int sm_list; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_FILEDATA) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list == DETECT_SM_LIST_FILEDATA) { AppLayerHtpEnableResponseBodyCallback(); s->alproto = ALPROTO_HTTP; } - sm_list = s->list; + sm_list = s->init_data->list; s->flags |= SIG_FLAG_APPLAYER; if (idad->flags & ISDATAAT_RELATIVE) { prev_pm = SigMatchGetLastSMFromLists(s, 4, diff --git a/src/detect-nocase.c b/src/detect-nocase.c index 930f577838ab..bec5f8b8eb5b 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -80,8 +80,8 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls } /* retrive the sm to apply the depth against */ - if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->list]); + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->init_data->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], diff --git a/src/detect-offset.c b/src/detect-offset.c index a155a4fa3ded..d48324757ef3 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -73,8 +73,8 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) } /* retrive the sm to apply the depth against */ - if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->list]); + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->init_data->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], diff --git a/src/detect-parse.c b/src/detect-parse.c index 1575823b4246..2904b9afc47f 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -233,7 +233,7 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s goto end; } - if (s->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"%s\" keyword seen " "with a sticky buffer still set. Reset sticky buffer " "with pkt_data before using the modifier.", @@ -379,8 +379,8 @@ void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list) s->init_data->smlists_tail[list] = new; } - new->idx = s->sm_cnt; - s->sm_cnt++; + new->idx = s->init_data->sm_cnt; + s->init_data->sm_cnt++; } void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list) @@ -680,15 +680,15 @@ static int SigParseAddress(DetectEngineCtx *de_ctx, if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_SRC_ANY; - s->src = DetectParseAddress(de_ctx, addrstr); - if (s->src == NULL) + s->init_data->src = DetectParseAddress(de_ctx, addrstr); + if (s->init_data->src == NULL) goto error; } else { if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_DST_ANY; - s->dst = DetectParseAddress(de_ctx, addrstr); - if (s->dst == NULL) + s->init_data->dst = DetectParseAddress(de_ctx, addrstr); + if (s->init_data->dst == NULL) goto error; } @@ -904,7 +904,7 @@ static int SigParseBasics(DetectEngineCtx *de_ctx, } /* Check if it is bidirectional */ if (strcmp(parser->direction, "<>") == 0) - s->init_flags |= SIG_FLAG_INIT_BIDIREC; + s->init_data->init_flags |= SIG_FLAG_INIT_BIDIREC; /* Parse Address & Ports */ if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) @@ -1007,7 +1007,7 @@ Signature *SigAlloc (void) * overwritten, we can then assign the default value of 3 */ sig->prio = -1; - sig->list = DETECT_SM_LIST_NOTSET; + sig->init_data->list = DETECT_SM_LIST_NOTSET; return sig; } @@ -1134,7 +1134,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* source addresses */ uint16_t cnt = 0; uint16_t idx = 0; - DetectAddress *da = s->src->ipv4_head; + DetectAddress *da = s->init_data->src->ipv4_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1144,7 +1144,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->src->ipv4_head; da != NULL; da = da->next) { + for (da = s->init_data->src->ipv4_head; da != NULL; da = da->next) { s->addr_src_match4[idx].ip = ntohl(da->ip.addr_data32[0]); s->addr_src_match4[idx].ip2 = ntohl(da->ip2.addr_data32[0]); idx++; @@ -1155,7 +1155,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* destination addresses */ cnt = 0; idx = 0; - da = s->dst->ipv4_head; + da = s->init_data->dst->ipv4_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1165,7 +1165,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->dst->ipv4_head; da != NULL; da = da->next) { + for (da = s->init_data->dst->ipv4_head; da != NULL; da = da->next) { s->addr_dst_match4[idx].ip = ntohl(da->ip.addr_data32[0]); s->addr_dst_match4[idx].ip2 = ntohl(da->ip2.addr_data32[0]); idx++; @@ -1176,7 +1176,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* source addresses IPv6 */ cnt = 0; idx = 0; - da = s->src->ipv6_head; + da = s->init_data->src->ipv6_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1186,7 +1186,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->src->ipv6_head; da != NULL; da = da->next) { + for (da = s->init_data->src->ipv6_head; da != NULL; da = da->next) { s->addr_src_match6[idx].ip[0] = ntohl(da->ip.addr_data32[0]); s->addr_src_match6[idx].ip[1] = ntohl(da->ip.addr_data32[1]); s->addr_src_match6[idx].ip[2] = ntohl(da->ip.addr_data32[2]); @@ -1203,7 +1203,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* destination addresses IPv6 */ cnt = 0; idx = 0; - da = s->dst->ipv6_head; + da = s->init_data->dst->ipv6_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1213,7 +1213,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->dst->ipv6_head; da != NULL; da = da->next) { + for (da = s->init_data->dst->ipv6_head; da != NULL; da = da->next) { s->addr_dst_match6[idx].ip[0] = ntohl(da->ip.addr_data32[0]); s->addr_dst_match6[idx].ip[1] = ntohl(da->ip.addr_data32[1]); s->addr_dst_match6[idx].ip[2] = ntohl(da->ip.addr_data32[2]); @@ -1614,10 +1614,10 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; for ( ; sm != NULL; sm = sm->next) { if (sigmatch_table[sm->type].Match != NULL) - sig->init_flags |= SIG_FLAG_INIT_PACKET; + sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET; } } else { - sig->init_flags |= SIG_FLAG_INIT_PACKET; + sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET; } } @@ -1631,14 +1631,14 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, /* for other lists this flag is set when the inspect engines * are registered */ - if (!(sig->init_flags & SIG_FLAG_INIT_FLOW)) { + if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) { sig->flags |= SIG_FLAG_TOSERVER; sig->flags |= SIG_FLAG_TOCLIENT; } SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s", sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set", - sig->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set"); + sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set"); SigBuildAddressMatchArray(sig); @@ -1677,7 +1677,7 @@ Signature *SigInit(DetectEngineCtx *de_ctx, char *sigstr) goto error; } - if (sig->init_flags & SIG_FLAG_INIT_BIDIREC) { + if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED); if (sig->next == NULL) { goto error; @@ -1870,7 +1870,7 @@ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, if (sw_dup->s_prev == NULL) { SigDuplWrapper sw_temp; memset(&sw_temp, 0, sizeof(SigDuplWrapper)); - if (sw_dup->s->init_flags & SIG_FLAG_INIT_BIDIREC) { + if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { sw_temp.s = sw_dup->s->next->next; de_ctx->sig_list = sw_dup->s->next->next; SigFree(sw_dup->s->next); @@ -1888,7 +1888,7 @@ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, } else { SigDuplWrapper sw_temp; memset(&sw_temp, 0, sizeof(SigDuplWrapper)); - if (sw_dup->s->init_flags & SIG_FLAG_INIT_BIDIREC) { + if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { sw_temp.s = sw_dup->s->next->next; sw_dup->s_prev->next = sw_dup->s->next->next; SigFree(sw_dup->s->next); @@ -1958,7 +1958,7 @@ Signature *DetectEngineAppendSig(DetectEngineCtx *de_ctx, char *sigstr) sigstr); } - if (sig->init_flags & SIG_FLAG_INIT_BIDIREC) { + if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { if (sig->next != NULL) { sig->next->next = de_ctx->sig_list; } else { @@ -2904,7 +2904,7 @@ int SigTestBidirec01 (void) goto end; if (sig->next != NULL) goto end; - if (sig->init_flags & SIG_FLAG_INIT_BIDIREC) + if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) goto end; if (de_ctx->signum != 1) goto end; @@ -2938,7 +2938,7 @@ int SigTestBidirec02 (void) goto end; if (de_ctx->sig_list != sig) goto end; - if (!(sig->init_flags & SIG_FLAG_INIT_BIDIREC)) + if (!(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)) goto end; if (sig->next == NULL) goto end; @@ -2947,7 +2947,7 @@ int SigTestBidirec02 (void) copy = sig->next; if (copy->next != NULL) goto end; - if (!(copy->init_flags & SIG_FLAG_INIT_BIDIREC)) + if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)) goto end; result = 1; @@ -3105,7 +3105,7 @@ int SigTestBidirec04 (void) sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)"); if (sig == NULL) goto end; - if ( !(sig->init_flags & SIG_FLAG_INIT_BIDIREC)) + if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)) goto end; if (sig->next == NULL) goto end; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index a1177a5928d9..a43fd8fc5d1f 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -684,7 +684,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst "for the rule."); goto error; } - if (s->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre found with http " "modifier set, with file_data/dce_stub_data sticky " "option set."); @@ -693,17 +693,17 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst } int sm_list = -1; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_FILEDATA) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list == DETECT_SM_LIST_FILEDATA) { SCLogDebug("adding to http server body list because of file data"); AppLayerHtpEnableResponseBodyCallback(); - } else if (s->list == DETECT_SM_LIST_DMATCH) { + } else if (s->init_data->list == DETECT_SM_LIST_DMATCH) { SCLogDebug("adding to dmatch list because of dce_stub_data"); - } else if (s->list == DETECT_SM_LIST_DNSQUERYNAME_MATCH) { + } else if (s->init_data->list == DETECT_SM_LIST_DNSQUERYNAME_MATCH) { SCLogDebug("adding to DETECT_SM_LIST_DNSQUERYNAME_MATCH list because of dns_query"); } s->flags |= SIG_FLAG_APPLAYER; - sm_list = s->list; + sm_list = s->init_data->list; } else { switch(parsed_sm_list) { case DETECT_SM_LIST_HCBDMATCH: @@ -763,7 +763,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst SigMatch *prev_pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); - if (s->list == DETECT_SM_LIST_NOTSET && prev_pm == NULL) { + if (s->init_data->list == DETECT_SM_LIST_NOTSET && prev_pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre with /R (relative) needs " "preceeding match in the same buffer"); goto error_nofree; diff --git a/src/detect-pkt-data.c b/src/detect-pkt-data.c index 7b4934bcc42f..d1c956ea83cb 100644 --- a/src/detect-pkt-data.c +++ b/src/detect-pkt-data.c @@ -74,7 +74,7 @@ void DetectPktDataRegister(void) static int DetectPktDataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); - s->list = DETECT_SM_LIST_NOTSET; + s->init_data->list = DETECT_SM_LIST_NOTSET; return 0; } @@ -127,7 +127,7 @@ static int DetectPktDataTest01(void) } - if (sig->list != DETECT_SM_LIST_NOTSET) { + if (sig->init_data->list != DETECT_SM_LIST_NOTSET) { printf("sticky buffer set: "); goto end; } diff --git a/src/detect-prefilter.c b/src/detect-prefilter.c index faef7a4f0c17..08eacac39e93 100644 --- a/src/detect-prefilter.c +++ b/src/detect-prefilter.c @@ -78,7 +78,7 @@ static int DetectPrefilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *nu goto end; } - s->prefilter_sm = sm; + s->init_data->prefilter_sm = sm; s->flags |= SIG_FLAG_PREFILTER; /* if the sig match is content, prefilter should act like diff --git a/src/detect-rawbytes.c b/src/detect-rawbytes.c index 85b50392679b..0803822c89e5 100644 --- a/src/detect-rawbytes.c +++ b/src/detect-rawbytes.c @@ -60,7 +60,7 @@ static int DetectRawbytesSetup (DetectEngineCtx *de_ctx, Signature *s, char *nul return -1; } - if (s->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { SCLogError(SC_ERR_RAWBYTES_FILE_DATA, "\"rawbytes\" cannot be combined with \"file_data\""); SCReturnInt(-1); } diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index 83b55765a019..866e717abebd 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -71,7 +71,7 @@ void DetectTemplateBufferRegister(void) static int DetectTemplateBufferSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->list = DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH; + s->init_data->list = DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH; s->alproto = ALPROTO_TEMPLATE; return 0; } diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index 84ba64d3747f..10e697c6f3bd 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -94,7 +94,7 @@ void DetectTlsIssuerRegister(void) */ static int DetectTlsIssuerSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->list = DETECT_SM_LIST_TLSISSUER_MATCH; + s->init_data->list = DETECT_SM_LIST_TLSISSUER_MATCH; s->alproto = ALPROTO_TLS; return 0; } diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index dcfbe2f8f1f1..02431a19c6b6 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -94,7 +94,7 @@ void DetectTlsSubjectRegister(void) */ static int DetectTlsSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->list = DETECT_SM_LIST_TLSSUBJECT_MATCH; + s->init_data->list = DETECT_SM_LIST_TLSSUBJECT_MATCH; s->alproto = ALPROTO_TLS; return 0; } diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index ada7e2a4f333..36b64c6584c4 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -94,7 +94,7 @@ void DetectTlsSniRegister(void) */ static int DetectTlsSniSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->list = DETECT_SM_LIST_TLSSNI_MATCH; + s->init_data->list = DETECT_SM_LIST_TLSSNI_MATCH; s->alproto = ALPROTO_TLS; return 0; } diff --git a/src/detect-within.c b/src/detect-within.c index fb35bb5ecf2a..0c243c6fa702 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -85,8 +85,8 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, char *within } /* retrive the sm to apply the depth against */ - if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->list]); + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->init_data->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], diff --git a/src/detect.c b/src/detect.c index f8736b81e459..e8157ed1292f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2539,7 +2539,7 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires flow"); } - if (s->init_flags & SIG_FLAG_INIT_FLOW) { + if (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) { s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow"); } @@ -2572,8 +2572,8 @@ static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) */ static int SigParseGetMaxDsize(Signature *s) { - if (s->flags & SIG_FLAG_DSIZE && s->dsize_sm != NULL) { - DetectDsizeData *dd = (DetectDsizeData *)s->dsize_sm->ctx; + if (s->flags & SIG_FLAG_DSIZE && s->init_data->dsize_sm != NULL) { + DetectDsizeData *dd = (DetectDsizeData *)s->init_data->dsize_sm->ctx; switch (dd->mode) { case DETECTDSIZE_LT: @@ -2594,8 +2594,8 @@ static int SigParseGetMaxDsize(Signature *s) */ static void SigParseSetDsizePair(Signature *s) { - if (s->flags & SIG_FLAG_DSIZE && s->dsize_sm != NULL) { - DetectDsizeData *dd = (DetectDsizeData *)s->dsize_sm->ctx; + if (s->flags & SIG_FLAG_DSIZE && s->init_data->dsize_sm != NULL) { + DetectDsizeData *dd = (DetectDsizeData *)s->init_data->dsize_sm->ctx; uint16_t low = 0; uint16_t high = 65535; @@ -2665,19 +2665,19 @@ static void SigParseApplyDsizeToContent(Signature *s) /** \brief Pure-PCRE or bytetest rule */ int RuleInspectsPayloadHasNoMpm(const Signature *s) { - if (s->mpm_sm == NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) + if (s->init_data->mpm_sm == NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 1; return 0; } int RuleGetMpmPatternSize(const Signature *s) { - if (s->mpm_sm == NULL) + if (s->init_data->mpm_sm == NULL) return -1; - int mpm_list = SigMatchListSMBelongsTo(s, s->mpm_sm); + int mpm_list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); if (mpm_list < 0) return -1; - const DetectContentData *cd = (const DetectContentData *)s->mpm_sm->ctx; + const DetectContentData *cd = (const DetectContentData *)s->init_data->mpm_sm->ctx; if (cd == NULL) return -1; return (int)cd->content_len; @@ -2685,12 +2685,12 @@ int RuleGetMpmPatternSize(const Signature *s) int RuleMpmIsNegated(const Signature *s) { - if (s->mpm_sm == NULL) + if (s->init_data->mpm_sm == NULL) return 0; - int mpm_list = SigMatchListSMBelongsTo(s, s->mpm_sm); + int mpm_list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); if (mpm_list < 0) return 0; - const DetectContentData *cd = (const DetectContentData *)s->mpm_sm->ctx; + const DetectContentData *cd = (const DetectContentData *)s->init_data->mpm_sm->ctx; if (cd == NULL) return 0; return (cd->flags & DETECT_CONTENT_NEGATED); @@ -2760,7 +2760,7 @@ json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh, any5_cnt++; } - if (s->mpm_sm == NULL) { + if (s->init_data->mpm_sm == NULL) { nonmpm_cnt++; if (s->sm_arrays[DETECT_SM_LIST_MATCH] != NULL) { @@ -2782,9 +2782,9 @@ json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh, } } else { - int mpm_list = SigMatchListSMBelongsTo(s, s->mpm_sm); + int mpm_list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); BUG_ON(mpm_list < 0); - const DetectContentData *cd = (const DetectContentData *)s->mpm_sm->ctx; + const DetectContentData *cd = (const DetectContentData *)s->init_data->mpm_sm->ctx; uint32_t size = cd->content_len < 256 ? cd->content_len : 255; mpm_sizes[mpm_list][size]++; @@ -3177,8 +3177,8 @@ static int RuleSetWhitelist(Signature *s) wl = 77; /* one byte pattern in packet/stream payloads */ - } else if (s->mpm_sm != NULL && - SigMatchListSMBelongsTo(s, s->mpm_sm) == DETECT_SM_LIST_PMATCH && + } else if (s->init_data->mpm_sm != NULL && + SigMatchListSMBelongsTo(s, s->init_data->mpm_sm) == DETECT_SM_LIST_PMATCH && RuleGetMpmPatternSize(s) == 1) { SCLogDebug("Rule %u No MPM. Payload inspecting. Whitelisting SGH's.", s->id); @@ -3192,7 +3192,7 @@ static int RuleSetWhitelist(Signature *s) } } - s->whitelist = wl; + s->init_data->whitelist = wl; return wl; } @@ -3244,7 +3244,7 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint3 goto next; } - int wl = s->whitelist; + int wl = s->init_data->whitelist; while (p) { int pwl = PortIsWhitelisted(de_ctx, p, ipproto) ? 111 : 0; pwl = MAX(wl,pwl); @@ -3398,7 +3398,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) SCLogDebug("Signature %"PRIu32" is considered \"Payload inspecting\"", tmp_s->id); } else if (SignatureIsDEOnly(de_ctx, tmp_s) == 1) { - tmp_s->init_flags |= SIG_FLAG_INIT_DEONLY; + tmp_s->init_data->init_flags |= SIG_FLAG_INIT_DEONLY; SCLogDebug("Signature %"PRIu32" is considered \"Decoder Event only\"", tmp_s->id); cnt_deonly++; } @@ -3470,7 +3470,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) SigMatch *sm = tmp_s->init_data->smlists[i]; while (sm != NULL) { if (sm->type == prefilter_list) { - tmp_s->prefilter_sm = sm; + tmp_s->init_data->prefilter_sm = sm; tmp_s->flags |= SIG_FLAG_PREFILTER; SCLogConfig("sid %u: prefilter is on \"%s\"", tmp_s->id, sigmatch_table[sm->type].name); break; @@ -3721,7 +3721,7 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) IPOnlyAddSignature(de_ctx, &de_ctx->io_ctx, tmp_s); } - if (tmp_s->init_flags & SIG_FLAG_INIT_DEONLY) { + if (tmp_s->init_data->init_flags & SIG_FLAG_INIT_DEONLY) { DetectEngineAddDecoderEventSig(de_ctx, tmp_s); } @@ -8341,15 +8341,13 @@ int SigTest40NoPayloadInspection02(void) uint8_t *buf = (uint8_t *) "220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; - memset(&th_v, 0, sizeof(th_v)); + + Packet *p = SCMalloc(SIZE_OF_PACKET); + FAIL_IF_NULL(p); memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; @@ -8357,37 +8355,26 @@ int SigTest40NoPayloadInspection02(void) p->proto = IPPROTO_TCP; p->flags |= PKT_NOPAYLOAD_INSPECTION; + DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - result = 0; - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"No Payload TEST\"; content:\"220 (vsFTPd 2.0.5)\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"No Payload TEST\"; content:\"220 (vsFTPd 2.0.5)\"; sid:1;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - result &= 0; - else - result &= 1; + FAIL_IF(PacketAlertCheck(p, 1)); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: SCFree(p); - return result; + PASS; } static int SigTestMemory01 (void) diff --git a/src/detect.h b/src/detect.h index 1fb1c3f13e28..3520e23e18b9 100644 --- a/src/detect.h +++ b/src/detect.h @@ -412,6 +412,34 @@ typedef struct DetectEngineAppInspectionEngine_ { #endif typedef struct SignatureInitData_ { + /** Number of sigmatches. Used for assigning SigMatch::idx */ + uint16_t sm_cnt; + + /* 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; + + /* 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; + + /** score to influence rule grouping. A higher value leads to a higher + * likelyhood 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 all sm lists */ struct SigMatch_ *smlists[DETECT_SM_LIST_MAX]; /* holds all sm lists' tails */ @@ -463,12 +491,6 @@ typedef struct Signature_ { #ifdef PROFILING uint16_t profiling_id; #endif - /** number of sigmatches in the match and pmatch list */ - uint16_t sm_cnt; - - /* used to hold flags that are predominantly used during init */ - uint32_t init_flags; - /* coccinelle: Signature:init_flags:SIG_FLAG_INIT_ */ /** netblocks and hosts specified at the sid, in CIDR format */ IPOnlyCIDRItem *CidrSrc, *CidrDst; @@ -489,30 +511,10 @@ typedef struct Signature_ { /** Reference */ DetectReference *references; - /** address settings for this signature */ - const DetectAddressHead *src, *dst; - - /* used at init to determine max dsize */ - SigMatch *dsize_sm; - /* 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; - - /** score to influence rule grouping. A higher value leads to a higher - * likelyhood of a rulegroup with this sig ending up as a contained - * group. */ - int whitelist; - /* Be careful, this pointer is only valid while parsing the sig, * to warn the user about any possible problem */ char *sig_str; - int prefilter_list; - SignatureInitData *init_data; /** ptr to the next sig in the list */ From a2b521b7fae12fcd491010bf1c4fee2f4815c870 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 16 Oct 2016 10:44:33 +0200 Subject: [PATCH 2362/2553] detect-csum: redo tests --- src/detect-csum.c | 773 ++++++---------------------------------------- 1 file changed, 99 insertions(+), 674 deletions(-) diff --git a/src/detect-csum.c b/src/detect-csum.c index 8d9fcf5959cf..ed5c17554f09 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -886,622 +886,107 @@ static void DetectICMPV6CsumFree(void *ptr) /* ---------------------------------- Unit Tests --------------------------- */ #ifdef UNITTESTS +#include "detect-engine.h" -static int DetectCsumIPV4ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectIPV4CsumSetup(NULL, &s, "\"valid\"") == 0); - result &= (DetectIPV4CsumSetup(NULL, &s, "\"invalid\"") == 0); - result &= (DetectIPV4CsumSetup(NULL, &s, "\"vaLid\"") == 0); - result &= (DetectIPV4CsumSetup(NULL, &s, "\"VALID\"") == 0); - result &= (DetectIPV4CsumSetup(NULL, &s, "\"iNvaLid\"") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumIPV4InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectIPV4CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectIPV4CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectIPV4CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectIPV4CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectIPV4CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumIPV4ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectIPV4CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectIPV4CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumICMPV4ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV4CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectICMPV4CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectICMPV4CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectICMPV4CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectICMPV4CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumICMPV4InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV4CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectICMPV4CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectICMPV4CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectICMPV4CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectICMPV4CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumICMPV4ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV4CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectICMPV4CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumTCPV4ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV4CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectTCPV4CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectTCPV4CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectTCPV4CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectTCPV4CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumTCPV4InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV4CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectTCPV4CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectTCPV4CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectTCPV4CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectTCPV4CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumTCPV4ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV4CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectTCPV4CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumUDPV4ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV4CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectUDPV4CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectUDPV4CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectUDPV4CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectUDPV4CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumUDPV4InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV4CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectUDPV4CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectUDPV4CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectUDPV4CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectUDPV4CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumUDPV4ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV4CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectUDPV4CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; +#define mystr(s) #s +#define TEST1(kwstr) {\ + DetectEngineCtx *de_ctx = DetectEngineCtxInit();\ + FAIL_IF_NULL(de_ctx);\ + de_ctx->flags = DE_QUIET;\ + \ + Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:valid; sid:1;)");\ + FAIL_IF_NULL(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:invalid; sid:2;)");\ + FAIL_IF_NULL(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:vaLid; sid:3;)");\ + FAIL_IF_NULL(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:VALID; sid:4;)");\ + FAIL_IF_NULL(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:iNvaLid; sid:5;)");\ + FAIL_IF_NULL(s);\ + DetectEngineCtxFree(de_ctx);\ } -static int DetectCsumTCPV6ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV6CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectTCPV6CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectTCPV6CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectTCPV6CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectTCPV6CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} -static int DetectCsumTCPV6InValidArgsTestParse02(void) +static int DetectCsumValidArgsTestParse01(void) { - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV6CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectTCPV6CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectTCPV6CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectTCPV6CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectTCPV6CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; + TEST1(ipv4); + TEST1(tcpv4); + TEST1(tcpv6); + TEST1(udpv4); + TEST1(udpv6); + TEST1(icmpv4); + TEST1(icmpv6); + PASS; } - -static int DetectCsumTCPV6ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV6CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectTCPV6CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; +#undef TEST1 + +#define TEST2(kwstr) { \ + DetectEngineCtx *de_ctx = DetectEngineCtxInit();\ + FAIL_IF_NULL(de_ctx);\ + Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:vaid; sid:1;)");\ + FAIL_IF(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:invaalid; sid:2;)");\ + FAIL_IF(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:vaLiid; sid:3;)");\ + FAIL_IF(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:VALieD; sid:4;)");\ + FAIL_IF(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:iNvamid; sid:5;)");\ + FAIL_IF(s);\ + DetectEngineCtxFree(de_ctx);\ } -static int DetectCsumUDPV6ValidArgsTestParse01(void) +int DetectCsumInvalidArgsTestParse02(void) { - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV6CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectUDPV6CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectUDPV6CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectUDPV6CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectUDPV6CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; + TEST2(ipv4); + TEST2(tcpv4); + TEST2(tcpv6); + TEST2(udpv4); + TEST2(udpv6); + TEST2(icmpv4); + TEST2(icmpv6); + PASS; } - -static int DetectCsumUDPV6InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV6CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectUDPV6CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectUDPV6CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectUDPV6CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectUDPV6CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; +#undef TEST2 + +#define TEST3(kwstr, kwtype) { \ + DetectEngineCtx *de_ctx = DetectEngineCtxInit();\ + FAIL_IF_NULL(de_ctx);\ + Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:valid; sid:1;)");\ + FAIL_IF_NULL(s);\ + SigMatch *sm = SigMatchGetLastSMFromLists(s, 2, (kwtype), s->sm_lists[DETECT_SM_LIST_MATCH]);\ + FAIL_IF_NULL(sm);\ + FAIL_IF_NULL(sm->ctx);\ + FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 1);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:INVALID; sid:2;)");\ + FAIL_IF_NULL(s);\ + sm = SigMatchGetLastSMFromLists(s, 2, (kwtype), s->sm_lists[DETECT_SM_LIST_MATCH]);\ + FAIL_IF_NULL(sm);\ + FAIL_IF_NULL(sm->ctx);\ + FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 0);\ + DetectEngineCtxFree(de_ctx);\ } -static int DetectCsumUDPV6ValidArgsTestParse03(void) +int DetectCsumValidArgsTestParse03(void) { - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV6CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectUDPV6CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumICMPV6ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV6CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectICMPV6CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectICMPV6CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectICMPV6CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectICMPV6CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumICMPV6InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV6CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectICMPV6CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectICMPV6CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectICMPV6CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectICMPV6CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -static int DetectCsumICMPV6ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV6CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectICMPV6CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; + TEST3(ipv4, DETECT_IPV4_CSUM); + TEST3(tcpv4, DETECT_TCPV4_CSUM); + TEST3(tcpv6, DETECT_TCPV6_CSUM); + TEST3(udpv4, DETECT_UDPV4_CSUM); + TEST3(udpv6, DETECT_UDPV6_CSUM); + TEST3(icmpv4, DETECT_ICMPV4_CSUM); + TEST3(icmpv6, DETECT_ICMPV6_CSUM); + PASS; } +#undef TEST3 +#undef mystr #include "detect-engine.h" #include "stream-tcp.h" static int DetectCsumICMPV6Test01(void) { - int result = 0; DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; ThreadVars tv; @@ -1509,10 +994,7 @@ static int DetectCsumICMPV6Test01(void) DecodeThreadVars dtv; Packet *p = PacketGetFromAlloc(); - if (p == NULL) { - printf("failure PacketGetFromAlloc\n"); - goto end; - } + FAIL_IF_NULL(p); uint8_t pkt[] = { 0x00, 0x30, 0x18, 0xa8, 0x7c, 0x23, 0x2c, 0x41, @@ -1540,19 +1022,13 @@ static int DetectCsumICMPV6Test01(void) FlowInitConfig(FLOW_QUIET); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("DetectEngineCtxInit failure\n"); - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " "(icmpv6-csum:valid; sid:1;)"); - if (s == NULL) { - printf("SigInit failed\n"); - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DecodeEthernet(&tv, &dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), NULL); @@ -1561,28 +1037,16 @@ static int DetectCsumICMPV6Test01(void) SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert on p, but it should: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; - - end: - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); - } + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); PACKET_RECYCLE(p); FlowShutdown(); - SCFree(p); - - return result; + PASS; } #endif /* UNITTESTS */ @@ -1590,55 +1054,16 @@ static int DetectCsumICMPV6Test01(void) static void DetectCsumRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectCsumIPV4ValidArgsTestParse01", - DetectCsumIPV4ValidArgsTestParse01); - UtRegisterTest("DetectCsumIPV4InValidArgsTestParse02", - DetectCsumIPV4InValidArgsTestParse02); - UtRegisterTest("DetectCsumIPV4ValidArgsTestParse03", - DetectCsumIPV4ValidArgsTestParse03); - - UtRegisterTest("DetectCsumICMPV4ValidArgsTestParse01", - DetectCsumICMPV4ValidArgsTestParse01); - UtRegisterTest("DetectCsumICMPV4InValidArgsTestParse02", - DetectCsumICMPV4InValidArgsTestParse02); - UtRegisterTest("DetectCsumICMPV4ValidArgsTestParse03", - DetectCsumICMPV4ValidArgsTestParse03); - - UtRegisterTest("DetectCsumTCPV4ValidArgsTestParse01", - DetectCsumTCPV4ValidArgsTestParse01); - UtRegisterTest("DetectCsumTCPV4InValidArgsTestParse02", - DetectCsumTCPV4InValidArgsTestParse02); - UtRegisterTest("DetectCsumTCPV4ValidArgsTestParse03", - DetectCsumTCPV4ValidArgsTestParse03); - - UtRegisterTest("DetectCsumUDPV4ValidArgsTestParse01", - DetectCsumUDPV4ValidArgsTestParse01); - UtRegisterTest("DetectCsumUDPV4InValidArgsTestParse02", - DetectCsumUDPV4InValidArgsTestParse02); - UtRegisterTest("DetectCsumUDPV4ValidArgsTestParse03", - DetectCsumUDPV4ValidArgsTestParse03); - - UtRegisterTest("DetectCsumUDPV6ValidArgsTestParse01", - DetectCsumUDPV6ValidArgsTestParse01); - UtRegisterTest("DetectCsumUDPV6InValidArgsTestParse02", - DetectCsumUDPV6InValidArgsTestParse02); - UtRegisterTest("DetectCsumUDPV6ValidArgsTestParse03", - DetectCsumUDPV6ValidArgsTestParse03); - - UtRegisterTest("DetectCsumTCPV6ValidArgsTestParse01", - DetectCsumTCPV6ValidArgsTestParse01); - UtRegisterTest("DetectCsumTCPV6InValidArgsTestParse02", - DetectCsumTCPV6InValidArgsTestParse02); - UtRegisterTest("DetectCsumTCPV6ValidArgsTestParse03", - DetectCsumTCPV6ValidArgsTestParse03); - - UtRegisterTest("DetectCsumICMPV6ValidArgsTestParse01", - DetectCsumICMPV6ValidArgsTestParse01); - UtRegisterTest("DetectCsumICMPV6InValidArgsTestParse02", - DetectCsumICMPV6InValidArgsTestParse02); - UtRegisterTest("DetectCsumICMPV6ValidArgsTestParse03", - DetectCsumICMPV6ValidArgsTestParse03); - - UtRegisterTest("DetectCsumICMPV6Test01", DetectCsumICMPV6Test01); + + UtRegisterTest("DetectCsumValidArgsTestParse01", + DetectCsumValidArgsTestParse01); + UtRegisterTest("DetectCsumInvalidArgsTestParse02", + DetectCsumInvalidArgsTestParse02); + UtRegisterTest("DetectCsumValidArgsTestParse03", + DetectCsumValidArgsTestParse03); + + UtRegisterTest("DetectCsumICMPV6Test01", + DetectCsumICMPV6Test01); + #endif /* UNITTESTS */ } From debc1a6334bdd9f37ccd043b6e3fe57b9c549d5d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 16 Oct 2016 11:02:50 +0200 Subject: [PATCH 2363/2553] detect: dce test fixes and improvements --- src/detect-dce-opnum.c | 14 --- src/detect-dce-stub-data.c | 24 +++-- src/detect-engine-dcepayload.c | 155 +++++++++++++-------------------- 3 files changed, 69 insertions(+), 124 deletions(-) diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 064cc9563969..75b291a4d3eb 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -354,8 +354,6 @@ static int DetectDceOpnumTestParse01(void) Signature *s = SigAlloc(); int result = 0; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "12") == 0); result &= (DetectDceOpnumSetup(NULL, s, "12,24") == 0); result &= (DetectDceOpnumSetup(NULL, s, "12,12-24") == 0); @@ -380,8 +378,6 @@ static int DetectDceOpnumTestParse02(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "12") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { @@ -409,8 +405,6 @@ static int DetectDceOpnumTestParse03(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "12-24") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { @@ -438,8 +432,6 @@ static int DetectDceOpnumTestParse04(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "12-24,24,62-72,623-635,62,25,213-235") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { @@ -504,8 +496,6 @@ static int DetectDceOpnumTestParse05(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "1,2,3,4,5,6,7") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { @@ -570,8 +560,6 @@ static int DetectDceOpnumTestParse06(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "1-2,3-4,5-6,7-8") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { @@ -618,8 +606,6 @@ static int DetectDceOpnumTestParse07(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "1-2,3-4,5-6,7-8,9") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index b9674cacff36..aa51dd833398 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -105,20 +105,16 @@ static int DetectDceStubDataSetup(DetectEngineCtx *de_ctx, Signature *s, char *a static int DetectDceStubDataTestParse01(void) { - Signature s; - int result = 0; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectDceStubDataSetup(NULL, &s, NULL) == 0); - - if (s.sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { - result = 1; - } else { - result = 0; - } - - return result; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags = DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (dce_stub_data; content:\"1\"; sid:1;)"); + FAIL_IF_NULL(s); + FAIL_IF_NOT_NULL(s->sm_lists[DETECT_SM_LIST_AMATCH]); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_DMATCH]); + DetectEngineCtxFree(de_ctx); + PASS; } /** diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index 874e30f346bc..aa323d71ed40 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -9796,125 +9796,88 @@ static int DcePayloadTest43(void) static int DcePayloadParseTest44(void) { DetectEngineCtx *de_ctx = NULL; - int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectIsdataatData *isd = NULL; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "dce_iface:12345678-1234-1234-1234-123456789012; " - "dce_opnum:10; dce_stub_data; " - "isdataat:10,relative; " - "content:\"one\"; within:4; distance:8; " - "pkt_data; " - "content:\"two\"; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { - result = 0; - goto end; - } - if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { - result = 0; - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" + "content:\"one\"; " + "dce_iface:12345678-1234-1234-1234-123456789012; " + "dce_opnum:10; dce_stub_data; " + "isdataat:10,relative; " + "content:\"one\"; within:4; distance:8; " + "pkt_data; " + "content:\"two\"; " + "sid:1;)"); + FAIL_IF_NULL(s); + + FAIL_IF_NULL(s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH]); + FAIL_IF_NULL(s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); + + /* isdataat:10,relative; */ sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; - if (sm->type != DETECT_ISDATAAT) { - result = 0; - goto end; - } + FAIL_IF(sm->type != DETECT_ISDATAAT); isd = (DetectIsdataatData *)sm->ctx; - if ( isd->flags & ISDATAAT_RAWBYTES || - !(isd->flags & ISDATAAT_RELATIVE)) { - result = 0; - goto end; - } + FAIL_IF(isd->flags & ISDATAAT_RAWBYTES); + FAIL_IF_NOT(isd->flags & ISDATAAT_RELATIVE); + FAIL_IF_NULL(sm->next); sm = sm->next; - if (sm->type != DETECT_CONTENT) { - result = 0; - goto end; - } - data = (DetectContentData *)sm->ctx; - if (data->flags & DETECT_CONTENT_RAWBYTES || - data->flags & DETECT_CONTENT_NOCASE || - !(data->flags & DETECT_CONTENT_WITHIN) || - !(data->flags & DETECT_CONTENT_DISTANCE) || - data->flags & DETECT_CONTENT_FAST_PATTERN || - data->flags & DETECT_CONTENT_RELATIVE_NEXT || - data->flags & DETECT_CONTENT_NEGATED ) { - result = 0; - printf("two failed\n"); - goto end; - } - result &= (strncmp((char *)data->content, "one", 3) == 0); - if (result == 0) - goto end; - - result &= (sm->next == NULL); + /* content:\"one\"; within:4; distance:8; */ + FAIL_IF(sm->type != DETECT_CONTENT); + data = (DetectContentData *)sm->ctx; + FAIL_IF (data->flags & DETECT_CONTENT_RAWBYTES || + data->flags & DETECT_CONTENT_NOCASE || + !(data->flags & DETECT_CONTENT_WITHIN) || + !(data->flags & DETECT_CONTENT_DISTANCE) || + data->flags & DETECT_CONTENT_FAST_PATTERN || + data->flags & DETECT_CONTENT_RELATIVE_NEXT || + data->flags & DETECT_CONTENT_NEGATED ); + + FAIL_IF_NOT(strncmp((char *)data->content, "one", 3) == 0); + FAIL_IF_NOT(sm->next == NULL); + + /* first content:\"one\"; */ sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; - if (sm->type != DETECT_CONTENT) { - result = 0; - goto end; - } + FAIL_IF(sm->type != DETECT_CONTENT); data = (DetectContentData *)sm->ctx; - if (data->flags & DETECT_CONTENT_RAWBYTES || - data->flags & DETECT_CONTENT_NOCASE || - data->flags & DETECT_CONTENT_WITHIN || - data->flags & DETECT_CONTENT_DISTANCE || - data->flags & DETECT_CONTENT_FAST_PATTERN || - data->flags & DETECT_CONTENT_RELATIVE_NEXT || - data->flags & DETECT_CONTENT_NEGATED ) { - printf("three failed\n"); - result = 0; - goto end; - } - result &= (strncmp((char *)data->content, "one", 3) == 0); - if (result == 0) - goto end; - + FAIL_IF(data->flags & DETECT_CONTENT_RAWBYTES); + FAIL_IF(data->flags & DETECT_CONTENT_NOCASE); + FAIL_IF(data->flags & DETECT_CONTENT_WITHIN); + FAIL_IF(data->flags & DETECT_CONTENT_DISTANCE); + FAIL_IF(data->flags & DETECT_CONTENT_FAST_PATTERN); + FAIL_IF(data->flags & DETECT_CONTENT_RELATIVE_NEXT); + FAIL_IF(data->flags & DETECT_CONTENT_NEGATED ); + FAIL_IF_NOT(strncmp((char *)data->content, "one", 3) == 0); + + FAIL_IF_NULL(sm->next); sm = sm->next; - if (sm->type != DETECT_CONTENT) { - result = 0; - goto end; - } + + FAIL_IF(sm->type != DETECT_CONTENT); + data = (DetectContentData *)sm->ctx; - if (data->flags & DETECT_CONTENT_RAWBYTES || - data->flags & DETECT_CONTENT_NOCASE || - data->flags & DETECT_CONTENT_WITHIN || - data->flags & DETECT_CONTENT_DISTANCE || - data->flags & DETECT_CONTENT_FAST_PATTERN || - data->flags & DETECT_CONTENT_NEGATED ) { - printf("two failed\n"); - result = 0; - goto end; - } - result &= (strncmp((char *)data->content, "two", 3) == 0); - if (result == 0) - goto end; + FAIL_IF(data->flags & DETECT_CONTENT_RAWBYTES || + data->flags & DETECT_CONTENT_NOCASE || + data->flags & DETECT_CONTENT_WITHIN || + data->flags & DETECT_CONTENT_DISTANCE || + data->flags & DETECT_CONTENT_FAST_PATTERN || + data->flags & DETECT_CONTENT_NEGATED ); - result &= (sm->next == NULL); + FAIL_IF_NOT(strncmp((char *)data->content, "two", 3) == 0); + + FAIL_IF_NOT(sm->next == NULL); - end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** From 58e1180efea18adb28e5abd64877cfc3221c6268 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 18 Oct 2016 00:42:26 +0200 Subject: [PATCH 2364/2553] detect: inspect engine setup cleanup --- src/detect-engine.c | 43 +------------------------------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 5fa3d4fbe14a..4c14a0c82afd 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -179,50 +179,9 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) new_engine->alproto = t->alproto; new_engine->dir = t->dir; new_engine->sm_list = t->sm_list; + new_engine->smd = ptrs[new_engine->sm_list]; new_engine->Callback = t->Callback; - switch (new_engine->sm_list) { - case DETECT_SM_LIST_HMDMATCH: - case DETECT_SM_LIST_UMATCH: - case DETECT_SM_LIST_HRUDMATCH: - case DETECT_SM_LIST_HTTP_REQLINEMATCH: - case DETECT_SM_LIST_HTTP_RESLINEMATCH: - case DETECT_SM_LIST_HCBDMATCH: - case DETECT_SM_LIST_FILEDATA: - case DETECT_SM_LIST_HHDMATCH: - case DETECT_SM_LIST_HRHDMATCH: - case DETECT_SM_LIST_HSMDMATCH: - case DETECT_SM_LIST_HSCDMATCH: - case DETECT_SM_LIST_HHHDMATCH: - case DETECT_SM_LIST_HRHHDMATCH: - case DETECT_SM_LIST_HCDMATCH: - case DETECT_SM_LIST_HUADMATCH: - - case DETECT_SM_LIST_FILEMATCH: - - case DETECT_SM_LIST_DNSQUERYNAME_MATCH: - case DETECT_SM_LIST_DNSREQUEST_MATCH: - case DETECT_SM_LIST_DNSRESPONSE_MATCH: - - case DETECT_SM_LIST_TLSSNI_MATCH: - case DETECT_SM_LIST_TLSISSUER_MATCH: - case DETECT_SM_LIST_TLSSUBJECT_MATCH: - case DETECT_SM_LIST_TLSVALIDITY_MATCH: - - case DETECT_SM_LIST_APP_EVENT: - - case DETECT_SM_LIST_MODBUS_MATCH: - case DETECT_SM_LIST_CIP_MATCH: - case DETECT_SM_LIST_ENIP_MATCH: - - case DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH: - - new_engine->smd = ptrs[new_engine->sm_list]; - break; - default: - break; - } - if (s->app_inspect == NULL) { s->app_inspect = new_engine; new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */ From 04592efb7655eb95a1067f92f9256e9b11a4f9bc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 14 Dec 2016 12:38:58 +0100 Subject: [PATCH 2365/2553] detect: buffer type API To replace the hardcoded SigMatch list id's, use this API to register and query lists by name. Also allow for registering descriptions and whether mpm is supported. Registration is only allowed at startup. --- src/detect-engine-analyzer.c | 14 ++ src/detect-engine.c | 266 +++++++++++++++++++++++++++++++++++ src/detect-engine.h | 19 +++ src/detect-parse.c | 29 +++- src/detect.c | 44 ++++++ 5 files changed, 371 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 850f5ba1aba3..6faf38c66d37 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -134,6 +134,13 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "http stat msg content\n"); else if (list_type == DETECT_SM_LIST_HUADMATCH) fprintf(fp_engine_analysis_FD, "http user agent content\n"); + else { + const char *desc = DetectBufferTypeGetDescriptionById(list_type); + const char *name = DetectBufferTypeGetNameById(list_type); + if (desc && name) { + fprintf(fp_engine_analysis_FD, "%s (%s)\n", desc, name); + } + } int flags_set = 0; fprintf(fp_engine_analysis_FD, " Flags:"); @@ -493,6 +500,13 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "tls subject content"); else if (list_type == DETECT_SM_LIST_DNP3_DATA_MATCH) fprintf(rule_engine_analysis_FD, "dnp3 data content"); + else { + const char *desc = DetectBufferTypeGetDescriptionById(list_type); + const char *name = DetectBufferTypeGetNameById(list_type); + if (desc && name) { + fprintf(rule_engine_analysis_FD, "%s (%s)", desc, name); + } + } fprintf(rule_engine_analysis_FD, "\" buffer.\n"); diff --git a/src/detect-engine.c b/src/detect-engine.c index 4c14a0c82afd..85e9b19afc45 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -247,6 +247,272 @@ void DetectEngineAppInspectionEngineSignatureFree(Signature *s) } } +/* code for registering buffers */ + +#include "util-hash-lookup3.h" + +static HashListTable *g_buffer_type_hash = NULL; +static int g_buffer_type_id = DETECT_SM_LIST_MAX; // past DETECT_SM_LIST_NOTSET +static int g_buffer_type_reg_closed = 0; + +typedef struct DetectBufferType_ { + const char *string; + const char *description; + int id; + _Bool mpm; + _Bool packet; /**< compat to packet matches */ + void (*SetupCallback)(Signature *); + _Bool (*ValidateCallback)(const Signature *); +} DetectBufferType; + +static DetectBufferType **g_buffer_type_map = NULL; + +int DetectBufferTypeMaxId(void) +{ + return g_buffer_type_id; +} + +static uint32_t DetectBufferTypeHashFunc(HashListTable *ht, void *data, uint16_t datalen) +{ + const DetectBufferType *map = (DetectBufferType *)data; + uint32_t hash = 0; + + hash = hashlittle_safe(map->string, strlen(map->string), 0); + hash %= ht->array_size; + + return hash; +} + +static char DetectBufferTypeCompareFunc(void *data1, uint16_t len1, void *data2, + uint16_t len2) +{ + DetectBufferType *map1 = (DetectBufferType *)data1; + DetectBufferType *map2 = (DetectBufferType *)data2; + + int r = (strcmp(map1->string, map2->string) == 0); + return r; +} + +static void DetectBufferTypeFreeFunc(void *data) +{ + DetectBufferType *map = (DetectBufferType *)data; + if (map != NULL) { + SCFree(map); + } +} + +int DetectBufferTypeInit(void) +{ + BUG_ON(g_buffer_type_hash); + g_buffer_type_hash = HashListTableInit(256, + DetectBufferTypeHashFunc, + DetectBufferTypeCompareFunc, + DetectBufferTypeFreeFunc); + if (g_buffer_type_hash == NULL) + return -1; + + return 0; +} + +void DetectBufferTypeFree(void) +{ + if (g_buffer_type_hash == NULL) + return; + + HashListTableFree(g_buffer_type_hash); + g_buffer_type_hash = NULL; + return; +} + +int DetectBufferTypeAdd(const char *string) +{ + DetectBufferType *map = SCCalloc(1, sizeof(*map)); + if (map == NULL) + return -1; + + map->string = string; + map->id = g_buffer_type_id++; + + BUG_ON(HashListTableAdd(g_buffer_type_hash, (void *)map, 0) != 0); + SCLogDebug("buffer %s registered with id %d", map->string, map->id); + return map->id; +} + +DetectBufferType *DetectBufferTypeLookupByName(const char *string) +{ + DetectBufferType map = { (char *)string, NULL, 0, 0, 0, NULL, NULL }; + + DetectBufferType *res = HashListTableLookup(g_buffer_type_hash, &map, 0); + return res; +} + +int DetectBufferTypeRegister(const char *name) +{ + BUG_ON(g_buffer_type_reg_closed); + if (g_buffer_type_hash == NULL) + DetectBufferTypeInit(); + + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + if (!exists) { + return DetectBufferTypeAdd(name); + } else { + return exists->id; + } +} + +void DetectBufferTypeSupportsPacket(const char *name) +{ + BUG_ON(g_buffer_type_reg_closed); + DetectBufferTypeRegister(name); + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + BUG_ON(!exists); + exists->packet = TRUE; + SCLogDebug("%p %s -- %d supports packet inspection", exists, name, exists->id); +} + +void DetectBufferTypeSupportsMpm(const char *name) +{ + BUG_ON(g_buffer_type_reg_closed); + DetectBufferTypeRegister(name); + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + BUG_ON(!exists); + exists->mpm = TRUE; + SCLogDebug("%p %s -- %d supports mpm", exists, name, exists->id); +} + +int DetectBufferTypeGetByName(const char *name) +{ + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + if (!exists) { + return -1; + } + return exists->id; +} + +const char *DetectBufferTypeGetNameById(const int id) +{ + BUG_ON(id < 0 || id >= g_buffer_type_id); + BUG_ON(g_buffer_type_map == NULL); + + if (g_buffer_type_map[id] == NULL) + return NULL; + + return g_buffer_type_map[id]->string; +} + +const DetectBufferType *DetectBufferTypeGetById(const int id) +{ + BUG_ON(id < 0 || id >= g_buffer_type_id); + BUG_ON(g_buffer_type_map == NULL); + + return g_buffer_type_map[id]; +} + +void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc) +{ + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + if (!exists) { + return; + } + exists->description = desc; +} + +const char *DetectBufferTypeGetDescriptionById(const int id) +{ + const DetectBufferType *exists = DetectBufferTypeGetById(id); + if (!exists) { + return NULL; + } + return exists->description; +} + +const char *DetectBufferTypeGetDescriptionByName(const char *name) +{ + const DetectBufferType *exists = DetectBufferTypeLookupByName(name); + if (!exists) { + return NULL; + } + return exists->description; +} + +_Bool DetectBufferTypeSupportsPacketGetById(const int id) +{ + const DetectBufferType *map = DetectBufferTypeGetById(id); + if (map == NULL) + return FALSE; + SCLogDebug("map %p id %d packet? %d", map, id, map->packet); + return map->packet; +} + +_Bool DetectBufferTypeSupportsMpmGetById(const int id) +{ + const DetectBufferType *map = DetectBufferTypeGetById(id); + if (map == NULL) + return FALSE; + SCLogDebug("map %p id %d mpm? %d", map, id, map->mpm); + return map->mpm; +} + +void DetectBufferTypeRegisterSetupCallback(const char *name, + void (*SetupCallback)(Signature *)) +{ + BUG_ON(g_buffer_type_reg_closed); + DetectBufferTypeRegister(name); + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + BUG_ON(!exists); + exists->SetupCallback = SetupCallback; +} + +void DetectBufferRunSetupCallback(const int id, Signature *s) +{ + const DetectBufferType *map = DetectBufferTypeGetById(id); + if (map && map->SetupCallback) { + map->SetupCallback(s); + } +} + +void DetectBufferTypeRegisterValidateCallback(const char *name, + _Bool (*ValidateCallback)(const Signature *)) +{ + BUG_ON(g_buffer_type_reg_closed); + DetectBufferTypeRegister(name); + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + BUG_ON(!exists); + exists->ValidateCallback = ValidateCallback; +} + +_Bool DetectBufferRunValidateCallback(const int id, const Signature *s) +{ + const DetectBufferType *map = DetectBufferTypeGetById(id); + if (map && map->ValidateCallback) { + return map->ValidateCallback(s); + } + return TRUE; +} + +void DetectBufferTypeFinalizeRegistration(void) +{ + BUG_ON(g_buffer_type_hash == NULL); + + const int size = g_buffer_type_id; + BUG_ON(!(size > 0)); + + g_buffer_type_map = SCCalloc(size, sizeof(DetectBufferType *)); + BUG_ON(!g_buffer_type_map); + + HashListTableBucket *b = HashListTableGetListHead(g_buffer_type_hash); + while (b) { + DetectBufferType *map = HashListTableGetListData(b); + g_buffer_type_map[map->id] = map; + SCLogDebug("name %s id %d mpm %s packet %s -- %s. " + "Callbacks: Setup %p Validate %p", map->string, map->id, + map->mpm ? "true" : "false", map->packet ? "true" : "false", + map->description, map->SetupCallback, map->ValidateCallback); + b = HashListTableGetListNext(b); + } + g_buffer_type_reg_closed = 1; +} + /* code to control the main thread to do a reload */ enum DetectEngineSyncState { diff --git a/src/detect-engine.h b/src/detect-engine.h index e3acb692e99f..c8c51546c9eb 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -28,6 +28,25 @@ #include "tm-threads.h" #include "flow-private.h" +int DetectBufferTypeRegister(const char *name); +int DetectBufferTypeGetByName(const char *name); +const char *DetectBufferTypeGetNameById(const int id); +void DetectBufferTypeSupportsMpm(const char *name); +void DetectBufferTypeSupportsPacket(const char *name); +_Bool DetectBufferTypeSupportsMpmGetById(const int id); +_Bool DetectBufferTypeSupportsPacketGetById(const int id); +int DetectBufferTypeMaxId(void); +void DetectBufferTypeFinalizeRegistration(void); +void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc); +const char *DetectBufferTypeGetDescriptionById(const int id); +const char *DetectBufferTypeGetDescriptionByName(const char *name); +void DetectBufferTypeRegisterSetupCallback(const char *name, + void (*Callback)(Signature *)); +void DetectBufferRunSetupCallback(const int id, Signature *s); +void DetectBufferTypeRegisterValidateCallback(const char *name, + _Bool (*ValidateCallback)(const Signature *)); +_Bool DetectBufferRunValidateCallback(const int id, const Signature *s); + /* prototypes */ DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix); DetectEngineCtx *DetectEngineCtxInit(void); diff --git a/src/detect-parse.c b/src/detect-parse.c index 2904b9afc47f..5731cd589026 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1278,9 +1278,20 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) uint32_t u = 0; uint32_t sig_flags = 0; SigMatch *sm, *pm; + const int nlists = DetectBufferTypeMaxId(); SCEnter(); + /* run buffer type validation callbacks if any */ + int x; + for (x = 0; x < nlists; x++) { + if (s->init_data->smlists[x]) { + if (DetectBufferRunValidateCallback(x, s) == FALSE) { + SCReturnInt(0); + } + } + } + if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && (s->flags & SIG_FLAG_REQUIRE_STREAM)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't mix packet keywords with " @@ -1319,7 +1330,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } } - +#if 0 // TODO figure out why this is even necessary if ((s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_SMTP) || s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || @@ -1337,6 +1348,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) s->flags |= SIG_FLAG_TOCLIENT; s->flags &= ~SIG_FLAG_TOSERVER; } +#endif if ((sig_flags & (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) { SCLogError(SC_ERR_INVALID_SIGNATURE,"You seem to have mixed keywords " "that require inspection in both directions. Atm we only " @@ -1447,6 +1459,21 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } + for (int i = 0; i < nlists; i++) { + if (s->init_data->smlists[i] == NULL) + continue; + if (!(DetectBufferTypeGetNameById(i))) + continue; + + if (!(DetectBufferTypeSupportsPacketGetById(i))) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " + "specific matches (like dsize, flags, ttl) with stream / " + "state matching by matching on app layer proto (like using " + "http_* keywords)."); + SCReturnInt(0); + } + } + if (s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH] || diff --git a/src/detect.c b/src/detect.c index e8157ed1292f..d32dc388d524 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1954,6 +1954,17 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; + /* for now assume that all registered buffer types are incompatible */ + const int nlists = DetectBufferTypeMaxId(); + for (int i = 0; i < nlists; i++) { + if (s->init_data->smlists[i] == NULL) + continue; + if (!(DetectBufferTypeGetNameById(i))) + continue; + + SCReturnInt(0); + } + /* TMATCH list can be ignored, it contains TAGs and * tags are compatible to IP-only. */ @@ -2054,6 +2065,17 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; + /* for now assume that all registered buffer types are incompatible */ + const int nlists = DetectBufferTypeMaxId(); + for (int i = 0; i < nlists; i++) { + if (s->init_data->smlists[i] == NULL) + continue; + if (!(DetectBufferTypeGetNameById(i))) + continue; + + SCReturnInt(0); + } + /* TMATCH list can be ignored, it contains TAGs and * tags are compatible to DP-only. */ @@ -2157,6 +2179,17 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) SCReturnInt(0); } + /* for now assume that all registered buffer types are incompatible */ + const int nlists = DetectBufferTypeMaxId(); + for (int i = 0; i < nlists; i++) { + if (s->init_data->smlists[i] == NULL) + continue; + if (!(DetectBufferTypeGetNameById(i))) + continue; + + SCReturnInt(0); + } + /* check for conflicting keywords */ SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; for ( ;sm != NULL; sm = sm->next) { @@ -3358,6 +3391,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) uint32_t cnt_payload = 0; uint32_t cnt_applayer = 0; uint32_t cnt_deonly = 0; + const int nlists = DetectBufferTypeMaxId(); if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("building signature grouping structure, stage 1: " @@ -3481,6 +3515,13 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) } } + /* run buffer type callbacks if any */ + int x; + for (x = 0; x < nlists; x++) { + if (tmp_s->init_data->smlists[x]) + DetectBufferRunSetupCallback(x, tmp_s); + } + de_ctx->sig_cnt++; } @@ -4302,6 +4343,9 @@ void SigTableSetup(void) DetectBypassRegister(); DetectHttpRequestLineRegister(); DetectHttpResponseLineRegister(); + + /* close keyword registration */ + DetectBufferTypeFinalizeRegistration(); } void SigTableRegisterTests(void) From 779d40cedf6657ab7e0ba63f660fdc68f85e0b4f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 14 Dec 2016 12:39:13 +0100 Subject: [PATCH 2366/2553] detect: remove hardcoded sm_list logic from setup Introduce utility functions to aid this. --- src/detect-app-layer-protocol.c | 2 +- src/detect-base64-data.c | 17 +-- src/detect-base64-decode.c | 90 +------------ src/detect-byte-extract.c | 115 ++--------------- src/detect-bytejump.c | 110 ++-------------- src/detect-bytetest.c | 109 ++-------------- src/detect-csum.c | 4 +- src/detect-depth.c | 20 +-- src/detect-detection-filter.c | 6 +- src/detect-distance.c | 27 +--- src/detect-dsize.c | 4 +- src/detect-engine-analyzer.c | 2 +- src/detect-engine-mpm.c | 27 +++- src/detect-engine-mpm.h | 4 + src/detect-engine.c | 25 +++- src/detect-engine.h | 3 + src/detect-fast-pattern.c | 72 +++-------- src/detect-isdataat.c | 98 +------------- src/detect-nocase.c | 29 +---- src/detect-offset.c | 29 +---- src/detect-parse.c | 221 ++++++++++++++++++++++++-------- src/detect-parse.h | 15 ++- src/detect-pcre.c | 5 +- src/detect-prefilter.c | 2 +- src/detect-rawbytes.c | 4 +- src/detect-replace.c | 6 +- src/detect-threshold.c | 6 +- src/detect-within.c | 34 +---- src/detect.c | 9 +- src/detect.h | 13 +- src/util-threshold-config.c | 86 +++++-------- 31 files changed, 366 insertions(+), 828 deletions(-) diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index c28f5867b6e0..7e4560ffacbf 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -165,7 +165,7 @@ static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, if (data == NULL) goto error; - SigMatch *tsm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *tsm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; for ( ; tsm != NULL; tsm = tsm->next) { if (tsm->type == DETECT_AL_APP_LAYER_PROTOCOL) { const DetectAppLayerProtocolData *them = (const DetectAppLayerProtocolData *)tsm->ctx; diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c index 2eb4442a9134..7b1be1f137f3 100644 --- a/src/detect-base64-data.c +++ b/src/detect-base64-data.c @@ -17,6 +17,7 @@ #include "suricata-common.h" #include "detect.h" +#include "detect-engine.h" #include "detect-engine-content-inspection.h" #include "detect-parse.h" @@ -45,21 +46,7 @@ static int DetectBase64DataSetup(DetectEngineCtx *de_ctx, Signature *s, SigMatch *pm = NULL; /* Check for a preceding base64_decode. */ - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BASE64_DECODE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); + pm = DetectGetLastSMFromLists(s, DETECT_BASE64_DECODE, -1); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"base64_data\" keyword seen without preceding base64_decode."); diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index 3d0254efe225..83dfd64139b8 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -203,92 +203,10 @@ static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s, #endif } else { - /* Copied from detect-isdataat.c. */ - pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); + pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 170f4b8bb675..06f39e5c74e6 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -531,19 +531,13 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *a sm_list = s->init_data->list; s->flags |= SIG_FLAG_APPLAYER; if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->init_data->smlists_tail[sm_list], - DETECT_PCRE, s->init_data->smlists_tail[sm_list]); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } } else if (data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 12, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -559,96 +553,10 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *a s->flags |= SIG_FLAG_APPLAYER; } else if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -680,8 +588,8 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *a } } - SigMatch *prev_bed_sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[sm_list]); + SigMatch *prev_bed_sm = DetectGetLastSMByListId(s, sm_list, + DETECT_BYTE_EXTRACT, -1); if (prev_bed_sm == NULL) data->local_id = 0; else @@ -749,8 +657,9 @@ SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, const Signature *s) { DetectByteExtractData *bed = NULL; int list; + const int nlists = DetectBufferTypeMaxId(); - for (list = 0; list < DETECT_SM_LIST_MAX; list++) { + for (list = 0; list < nlists; list++) { SigMatch *sm = s->init_data->smlists[list]; while (sm != NULL) { if (sm->type == DETECT_BYTE_EXTRACT) { diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 151181150026..4eb362b0b96c 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -530,20 +530,14 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts sm_list = s->init_data->list; s->flags |= SIG_FLAG_APPLAYER; if (data->flags & DETECT_BYTEJUMP_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->init_data->smlists_tail[sm_list], - DETECT_PCRE, s->init_data->smlists_tail[sm_list]); - + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } } else if (data->flags & DETECT_BYTEJUMP_DCE) { if (data->flags & DETECT_BYTEJUMP_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 12, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -559,96 +553,10 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts s->flags |= SIG_FLAG_APPLAYER; } else if (data->flags & DETECT_BYTEJUMP_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 5c23e3f762fa..15938a0c41c6 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -457,20 +457,15 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts sm_list = s->init_data->list; s->flags |= SIG_FLAG_APPLAYER; if (data->flags & DETECT_BYTETEST_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->init_data->smlists_tail[sm_list], - DETECT_PCRE, s->init_data->smlists_tail[sm_list]); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } } else if (data->flags & DETECT_BYTETEST_DCE) { if (data->flags & DETECT_BYTETEST_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 12, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -486,96 +481,10 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts s->flags |= SIG_FLAG_APPLAYER; } else if (data->flags & DETECT_BYTETEST_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { diff --git a/src/detect-csum.c b/src/detect-csum.c index ed5c17554f09..a7e5d9ba4ab3 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -955,13 +955,13 @@ int DetectCsumInvalidArgsTestParse02(void) FAIL_IF_NULL(de_ctx);\ Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:valid; sid:1;)");\ FAIL_IF_NULL(s);\ - SigMatch *sm = SigMatchGetLastSMFromLists(s, 2, (kwtype), s->sm_lists[DETECT_SM_LIST_MATCH]);\ + SigMatch *sm = DetectGetLastSMFromLists(s, (kwtype), -1);\ FAIL_IF_NULL(sm);\ FAIL_IF_NULL(sm->ctx);\ FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 1);\ s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:INVALID; sid:2;)");\ FAIL_IF_NULL(s);\ - sm = SigMatchGetLastSMFromLists(s, 2, (kwtype), s->sm_lists[DETECT_SM_LIST_MATCH]);\ + sm = DetectGetLastSMFromLists(s, (kwtype), -1);\ FAIL_IF_NULL(sm);\ FAIL_IF_NULL(sm->ctx);\ FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 0);\ diff --git a/src/detect-depth.c b/src/detect-depth.c index 056c107d5914..a78f8a1b96d5 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -74,25 +74,7 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths } /* retrive the sm to apply the depth against */ - if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->init_data->list]); - } else { - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); - } + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " "preceding content, uricontent option, http_client_body, " diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 9048f458e445..f209f6991ef7 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -215,15 +215,13 @@ static int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, ch SigMatch *tmpm = NULL; /* checks if there's a previous instance of threshold */ - tmpm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->init_data->smlists_tail[DETECT_SM_LIST_MATCH]); + tmpm = DetectGetLastSMFromLists(s, DETECT_THRESHOLD, -1); if (tmpm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"detection_filter\" and \"threshold\" are not allowed in the same rule"); SCReturnInt(-1); } /* checks there's no previous instance of detection_filter */ - tmpm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->init_data->smlists_tail[DETECT_SM_LIST_MATCH]); + tmpm = DetectGetLastSMFromLists(s, DETECT_DETECTION_FILTER, -1); if (tmpm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "At most one \"detection_filter\" is allowed per rule"); SCReturnInt(-1); diff --git a/src/detect-distance.c b/src/detect-distance.c index 3eff265ce5bb..c700675f4ae7 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -80,26 +80,8 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, dubbed = 1; } - /* retrive the sm to apply the depth against */ - if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->init_data->list]); - } else { - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); - } + /* retrieve the sm to apply the distance against */ + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "distance needs " "preceding content, uricontent option, http_client_body, " @@ -147,9 +129,8 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, } cd->flags |= DETECT_CONTENT_DISTANCE; - SigMatch *prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, pm->prev, - DETECT_PCRE, pm->prev); + SigMatch *prev_pm = DetectGetLastSMByListPtr(s, pm->prev, + DETECT_CONTENT, DETECT_PCRE, -1); if (prev_pm == NULL) { ret = 0; goto end; diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 2e835ad8443b..5f7b7575b524 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -256,9 +256,7 @@ static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr DetectDsizeData *dd = NULL; SigMatch *sm = NULL; - if (SigMatchGetLastSMFromLists(s, 2, - DETECT_DSIZE, - s->init_data->smlists_tail[DETECT_SM_LIST_MATCH]) != NULL) { + if (DetectGetLastSMFromLists(s, DETECT_DSIZE, -1)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use 2 or more dsizes in " "the same sig. Invalidating signature."); goto error; diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 6faf38c66d37..16acb2fc4b15 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -553,7 +553,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) //uint32_t rule_flowvar = 0; uint32_t rule_content_http = 0; uint32_t rule_content_offset_depth = 0; - uint32_t list_id = 0; + int32_t list_id = 0; uint32_t rule_warning = 0; uint32_t raw_http_buf = 0; uint32_t norm_http_buf = 0; diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 3cd3471160f7..073600aa134d 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -119,6 +119,17 @@ void DetectMpmAppLayerRegister(const char *name, SupportFastPatternForSigMatchList(sm_list, priority); } +void DetectAppLayerMpmRegister(const char *name, + int direction, int priority, + int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)) +{ + DetectBufferTypeSupportsMpm(name); + int sm_list = DetectBufferTypeGetByName(name); + BUG_ON(sm_list == -1); + DetectMpmAppLayerRegister(name, direction, sm_list, priority, + PrefilterRegister); +} + void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) { BUG_ON(g_app_mpms_list_cnt == 0); @@ -543,18 +554,20 @@ void RetrieveFPForSig(Signature *s) if (s->init_data->mpm_sm != NULL) return; + const int nlists = DetectBufferTypeMaxId(); + SigMatch *mpm_sm = NULL, *sm = NULL; - int nn_sm_list[DETECT_SM_LIST_MAX]; - int n_sm_list[DETECT_SM_LIST_MAX]; - memset(nn_sm_list, 0, sizeof(nn_sm_list)); - memset(n_sm_list, 0, sizeof(n_sm_list)); + int nn_sm_list[nlists]; + int n_sm_list[nlists]; + memset(nn_sm_list, 0, nlists * sizeof(int)); + memset(n_sm_list, 0, nlists * sizeof(int)); int count_nn_sm_list = 0; int count_n_sm_list = 0; int list_id; /* inspect rule to see if we have the fast_pattern reg to * force using a sig, otherwise keep stats about the patterns */ - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { + for (list_id = 0; list_id < nlists; list_id++) { if (s->init_data->smlists[list_id] == NULL) continue; @@ -595,7 +608,9 @@ void RetrieveFPForSig(Signature *s) return; } - int final_sm_list[DETECT_SM_LIST_MAX] = { 0 }; + int final_sm_list[nlists]; + memset(&final_sm_list, 0, (nlists * sizeof(int))); + int count_final_sm_list = 0; int priority; diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 27de064d8937..9d53c456a8f5 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -93,5 +93,9 @@ void DetectMpmAppLayerRegister(const char *name, int direction, int sm_list, int priority, int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)); +void DetectAppLayerMpmRegister(const char *name, + int direction, int priority, + int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)); + #endif /* __DETECT_ENGINE_MPM_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 85e9b19afc45..f899e029dbf3 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -104,9 +104,11 @@ static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL; void DetectAppLayerInspectEngineRegister(AppProto alproto, uint32_t dir, int32_t sm_list, InspectEngineFuncPtr Callback) { + const int nlists = DetectBufferTypeMaxId(); + if ((alproto >= ALPROTO_FAILED) || (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) || - (sm_list < DETECT_SM_LIST_MATCH || sm_list >= DETECT_SM_LIST_MAX) || + (sm_list < DETECT_SM_LIST_MATCH || sm_list >= nlists) || (Callback == NULL)) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments"); @@ -142,13 +144,24 @@ void DetectAppLayerInspectEngineRegister(AppProto alproto, } } +void DetectAppLayerInspectEngineRegister2(const char *name, + AppProto alproto, uint32_t dir, InspectEngineFuncPtr Callback) +{ + DetectBufferTypeRegister(name); + int sm_list = DetectBufferTypeGetByName(name); + BUG_ON(sm_list == -1); + DetectAppLayerInspectEngineRegister(alproto, dir, sm_list, Callback); +} + int DetectEngineAppInspectionEngine2Signature(Signature *s) { - SigMatchData *ptrs[DETECT_SM_LIST_MAX] = { NULL }; + const int nlists = DetectBufferTypeMaxId(); + SigMatchData *ptrs[nlists]; + memset(&ptrs, 0, (nlists * sizeof(SigMatchData *))); /* convert lists to SigMatchData arrays */ int i = 0; - for (i = DETECT_SM_LIST_BUILTIN_MAX; i < DETECT_SM_LIST_MAX; i++) { + for (i = DETECT_SM_LIST_BUILTIN_MAX; i < nlists; i++) { if (s->init_data->smlists[i] == NULL) continue; @@ -215,7 +228,9 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) */ void DetectEngineAppInspectionEngineSignatureFree(Signature *s) { - SigMatchData *ptrs[DETECT_SM_LIST_MAX] = { NULL }; + const int nlists = DetectBufferTypeMaxId(); + SigMatchData *ptrs[nlists]; + memset(&ptrs, 0, (nlists * sizeof(SigMatchData *))); /* free engines and put smd in the array */ DetectEngineAppInspectionEngine *ie = s->app_inspect; @@ -229,7 +244,7 @@ void DetectEngineAppInspectionEngineSignatureFree(Signature *s) /* free the smds */ int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) + for (i = 0; i < nlists; i++) { if (ptrs[i] == NULL) continue; diff --git a/src/detect-engine.h b/src/detect-engine.h index c8c51546c9eb..ada68647a9f1 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -106,6 +106,9 @@ int DetectEngineInspectGenericList(ThreadVars *, const DetectEngineCtx *, void DetectAppLayerInspectEngineRegister(AppProto alproto, uint32_t dir, int32_t sm_list, InspectEngineFuncPtr Callback); +void DetectAppLayerInspectEngineRegister2(const char *name, + AppProto alproto, uint32_t dir, InspectEngineFuncPtr Callback); + int DetectEngineAppInspectionEngine2Signature(Signature *s); void DetectEngineAppInspectionEngineSignatureFree(Signature *s); diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index e844f39d11b3..9661eee6d2b0 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -162,63 +162,27 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a int ov[MAX_SUBSTRINGS]; char arg_substr[128] = ""; DetectContentData *cd = NULL; + const int nlists = DetectBufferTypeMaxId(); - if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_TLSSNI_MATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_TLSISSUER_MATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_TLSSUBJECT_MATCH] == NULL && - s->init_data->smlists_tail[DETECT_SM_LIST_HTTP_REQLINEMATCH] == NULL) { - SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " - "rule, without a preceding content based keyword. " - "Currently we provide fast_pattern support for content, " - "uricontent, http_client_body, http_server_body, http_header, " - "http_raw_header, http_method, http_cookie, " - "http_raw_uri, http_stat_msg, http_stat_code, " - "http_user_agent, http_host, http_raw_host, " - "http_request_line, dns_query, " - "tls_sni, tls_cert_issuer or tls_cert_subject option"); + SigMatch *pm1 = DetectGetLastSMFromMpmLists(s); + SigMatch *pm2 = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); + if (pm1 == NULL && pm2 == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " + "the rule, without a content context. Please use a " + "content based keyword before using fast_pattern"); return -1; } - SigMatch *pm = SigMatchGetLastSMFromLists(s, 38, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HTTP_REQLINEMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_TLSSNI_MATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_TLSISSUER_MATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_TLSSUBJECT_MATCH]); - if (pm == NULL) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " - "the rule, without a content context. Please use a " - "content based keyword before using fast_pattern"); - return -1; + SigMatch *pm = NULL; + if (pm1 && pm2) { + if (pm1->idx > pm2->idx) + pm = pm1; + else + pm = pm2; + } else if (pm1 && !pm2) { + pm = pm1; + } else { + pm = pm2; } cd = (DetectContentData *)pm->ctx; @@ -242,7 +206,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a } else { /*allow only one content to have fast_pattern modifier*/ int list_id = 0; - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { + for (list_id = 0; list_id < nlists; list_id++) { SigMatch *sm = NULL; for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 92d69d562c35..ad3b16ae7949 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -218,101 +218,13 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst sm_list = s->init_data->list; s->flags |= SIG_FLAG_APPLAYER; if (idad->flags & ISDATAAT_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->init_data->smlists_tail[sm_list], - DETECT_PCRE, s->init_data->smlists_tail[sm_list]); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } } else if (idad->flags & ISDATAAT_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) sm_list = DETECT_SM_LIST_PMATCH; else { diff --git a/src/detect-nocase.c b/src/detect-nocase.c index bec5f8b8eb5b..18a392ed59a7 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -79,37 +79,14 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls goto end; } - /* retrive the sm to apply the depth against */ - if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->init_data->list]); - } else { - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); - } + /* retrive the sm to apply the nocase against */ + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "nocase needs " - "preceding content, uricontent option, http_client_body, " - "http_server_body, http_header option, http_raw_header option, " - "http_method option, http_cookie, http_raw_uri, " - "http_stat_msg, http_stat_code, http_user_agent or " - "file_data/dce_stub_data sticky buffer options"); + "preceding content option"); goto end; } - /* verify other conditions. */ DetectContentData *cd = (DetectContentData *)pm->ctx;; diff --git a/src/detect-offset.c b/src/detect-offset.c index d48324757ef3..b43cca7723be 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -72,37 +72,14 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) dubbed = 1; } - /* retrive the sm to apply the depth against */ - if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->init_data->list]); - } else { - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); - } + /* retrive the sm to apply the offset against */ + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs " - "preceding content, uricontent option, http_client_body, " - "http_server_body, http_header option, http_raw_header option, " - "http_method option, http_cookie, http_raw_uri, " - "http_stat_msg, http_stat_code, http_user_agent or " - "file_data/dce_stub_data sticky buffer options"); + "preceding content option"); goto end; } - /* verify other conditions */ DetectContentData *cd = (DetectContentData *)pm->ctx; diff --git a/src/detect-parse.c b/src/detect-parse.c index 5731cd589026..cec9022deba9 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -75,6 +75,10 @@ static pcre *option_pcre = NULL; static pcre_extra *config_pcre_extra = NULL; static pcre_extra *option_pcre_extra = NULL; +static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, + SigMatch **src_sm_list, SigMatch **src_sm_list_tail, + SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail); + /** * \brief We use this as data to the hash table DetectEngineCtx->dup_sig_hash_table. */ @@ -220,9 +224,10 @@ const char *DetectListToString(int list) return "unknown"; } -int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg, - uint8_t sm_type, uint8_t sm_list, - AppProto alproto, void (*CustomCallback)(Signature *s)) +int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, + Signature *s, const char *arg, + int sm_type, int sm_list, + AppProto alproto, void (*CustomCallback)(Signature *s)) { SigMatch *sm = NULL; int ret = -1; @@ -240,15 +245,14 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s sigmatch_table[sm_type].name); goto end; } - /* for now let's hardcode it as http */ if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting " "alprotos set"); goto end; } - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); + sm = DetectGetLastSMByListId(s, + DETECT_SM_LIST_PMATCH, DETECT_CONTENT, -1); if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"%s\" keyword " "found inside the rule without a content context. " @@ -265,9 +269,8 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s goto end; } if (cd->flags & (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) { - SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, sm->prev, - DETECT_PCRE, sm->prev); + SigMatch *pm = DetectGetLastSMByListPtr(s, sm->prev, + DETECT_CONTENT, DETECT_PCRE, -1); if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; @@ -278,9 +281,8 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s } } - pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->init_data->smlists_tail[sm_list], - DETECT_PCRE, s->init_data->smlists_tail[sm_list]); + pm = DetectGetLastSMByListId(s, sm_list, + DETECT_CONTENT, DETECT_PCRE, -1); if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; @@ -296,7 +298,7 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s s->alproto = alproto; s->flags |= SIG_FLAG_APPLAYER; - /* transfer the sm from the pmatch list to hcbdmatch list */ + /* transfer the sm from the pmatch list to sm_list */ SigMatchTransferSigMatchAcrossLists(sm, &s->init_data->smlists[DETECT_SM_LIST_PMATCH], &s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], @@ -408,7 +410,7 @@ void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list) * * \retval match Pointer to the last SigMatch instance of type 'type'. */ -static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, uint8_t type) +static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, int type) { while (sm != NULL) { if (sm->type == type) { @@ -420,33 +422,139 @@ static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, uint8_t type) return NULL; } +/** \brief get the last SigMatch from lists that support + * MPM. + * \note only supports the lists that are registered through + * DetectBufferTypeSupportsMpm(). + */ +SigMatch *DetectGetLastSMFromMpmLists(const Signature *s) +{ + SigMatch *sm_last = NULL; + SigMatch *sm_new; + int sm_type; + + /* if we have a sticky buffer, use that */ + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + if (!(DetectBufferTypeSupportsMpmGetById(s->init_data->list))) { + return NULL; + } + + sm_last = DetectGetLastSMByListPtr(s, + s->init_data->smlists_tail[s->init_data->list], + DETECT_CONTENT, -1); + return sm_last; + } + + /* otherwise brute force it */ + const int nlists = DetectBufferTypeMaxId(); + for (sm_type = 0; sm_type < nlists; sm_type++) { + if (!DetectBufferTypeSupportsMpmGetById(sm_type)) + continue; + SigMatch *sm_list = s->init_data->smlists_tail[sm_type]; + sm_new = SigMatchGetLastSMByType(sm_list, DETECT_CONTENT); + if (sm_new == NULL) + continue; + if (sm_last == NULL || sm_new->idx > sm_last->idx) + sm_last = sm_new; + } + + return sm_last; +} + /** * \brief Returns the sm with the largest index (added latest) from the lists * passed to us. * * \retval Pointer to Last sm. */ -SigMatch *SigMatchGetLastSMFromLists(const Signature *s, int args, ...) +SigMatch *DetectGetLastSMFromLists(const Signature *s, ...) { - if (args == 0 || args % 2 != 0) { - SCLogError(SC_ERR_INVALID_ARGUMENTS, "You need to send an even no of args " - "(non zero as well) to this function, since we need a " - "SigMatch list for every SigMatch type(send a map of sm_type " - "and sm_list) sent"); - /* as this is a bug we should abort to ease debugging */ - BUG_ON(1); + SigMatch *sm_last = NULL; + SigMatch *sm_new; + + /* otherwise brute force it */ + const int nlists = DetectBufferTypeMaxId(); + for (int buf_type = 0; buf_type < nlists; buf_type++) { + if (s->init_data->smlists[buf_type] == NULL) + continue; + if (s->init_data->list != DETECT_SM_LIST_NOTSET && + buf_type != s->init_data->list) + continue; + + int sm_type; + va_list ap; + va_start(ap, s); + + for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) + { + sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type); + if (sm_new == NULL) + continue; + if (sm_last == NULL || sm_new->idx > sm_last->idx) + sm_last = sm_new; + } + va_end(ap); } + return sm_last; +} + +/** + * \brief Returns the sm with the largest index (added last) from the list + * passed to us as a pointer. + * + * \param sm_list pointer to the SigMatch we should look before + * \param va_args list of keyword types terminated by -1 + * + * \retval sm_last to last sm. + */ +SigMatch *DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list, ...) +{ SigMatch *sm_last = NULL; SigMatch *sm_new; - int i; + int sm_type; + + va_list ap; + va_start(ap, sm_list); + + for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) + { + sm_new = SigMatchGetLastSMByType(sm_list, sm_type); + if (sm_new == NULL) + continue; + if (sm_last == NULL || sm_new->idx > sm_last->idx) + sm_last = sm_new; + } + + va_end(ap); + + return sm_last; +} + +/** + * \brief Returns the sm with the largest index (added last) from the list + * passed to us as an id. + * + * \param list_id id of the list to be searched + * \param va_args list of keyword types terminated by -1 + * + * \retval sm_last to last sm. + */ +SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...) +{ + SigMatch *sm_last = NULL; + SigMatch *sm_new; + int sm_type; + + SigMatch *sm_list = s->init_data->smlists_tail[list_id]; + if (sm_list == NULL) + return NULL; va_list ap; - va_start(ap, args); + va_start(ap, list_id); - for (i = 0; i < args; i += 2) { - int sm_type = va_arg(ap, int); - SigMatch *sm_list = va_arg(ap, SigMatch *); + for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) + { sm_new = SigMatchGetLastSMByType(sm_list, sm_type); if (sm_new == NULL) continue; @@ -462,15 +570,16 @@ SigMatch *SigMatchGetLastSMFromLists(const Signature *s, int args, ...) /** * \brief Returns the sm with the largest index (added latest) from this sig * - * \retval Pointer to Last sm. + * \retval sm_last Pointer to last sm */ -SigMatch *SigMatchGetLastSM(const Signature *s) +SigMatch *DetectGetLastSM(const Signature *s) { + const int nlists = DetectBufferTypeMaxId(); SigMatch *sm_last = NULL; SigMatch *sm_new; int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i ++) { + for (i = 0; i < nlists; i ++) { sm_new = s->init_data->smlists_tail[i]; if (sm_new == NULL) continue; @@ -481,9 +590,9 @@ SigMatch *SigMatchGetLastSM(const Signature *s) return sm_last; } -void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, - SigMatch **src_sm_list, SigMatch **src_sm_list_tail, - SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail) +static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, + SigMatch **src_sm_list, SigMatch **src_sm_list_tail, + SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail) { /* we won't do any checks for args */ @@ -515,9 +624,10 @@ void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm) { + const int nlists = DetectBufferTypeMaxId(); int list = 0; - for (list = 0; list < DETECT_SM_LIST_MAX; list++) { + for (list = 0; list < nlists; list++) { const SigMatch *sm = s->init_data->smlists[list]; while (sm != NULL) { if (sm == key_sm) @@ -1001,6 +1111,22 @@ Signature *SigAlloc (void) SCFree(sig); return NULL; } + int lists = DetectBufferTypeMaxId(); + SCLogDebug("smlists size %d", lists); + sig->init_data->smlists = SCCalloc(lists, sizeof(SigMatch *)); + if (sig->init_data->smlists == NULL) { + SCFree(sig->init_data); + SCFree(sig); + return NULL; + } + + sig->init_data->smlists_tail = SCCalloc(lists, sizeof(SigMatch *)); + if (sig->init_data->smlists_tail == NULL) { + SCFree(sig->init_data->smlists_tail); + SCFree(sig->init_data); + SCFree(sig); + return NULL; + } /* assign it to -1, so that we can later check if the value has been * overwritten after the Signature has been parsed, and if it hasn't been @@ -1067,6 +1193,8 @@ static void SigMatchFreeArrays(Signature *s, int ctxs) void SigFree(Signature *s) { + const int nlists = DetectBufferTypeMaxId(); + if (s == NULL) return; @@ -1078,7 +1206,7 @@ void SigFree(Signature *s) int i; if (s->init_data) { - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { SigMatch *sm = s->init_data->smlists[i]; while (sm != NULL) { SigMatch *nsm = sm->next; @@ -1089,6 +1217,8 @@ void SigFree(Signature *s) } SigMatchFreeArrays(s, (s->init_data == NULL)); if (s->init_data) { + SCFree(s->init_data->smlists); + SCFree(s->init_data->smlists_tail); SCFree(s->init_data); s->init_data = NULL; } @@ -1437,21 +1567,8 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) //} if (s->flags & SIG_FLAG_REQUIRE_PACKET) { - pm = SigMatchGetLastSMFromLists(s, 24, - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_REPLACE, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); - if (pm != NULL) { + pm = DetectGetLastSMFromLists(s, DETECT_REPLACE, -1); + if (pm != NULL && SigMatchListSMBelongsTo(s, pm) != DETECT_SM_LIST_PMATCH) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature has" " replace keyword linked with a modified content" " keyword (http_*, dce_*). It only supports content on" @@ -1529,7 +1646,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA] != NULL) { int list; uint16_t idx = s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA]->idx; - for (list = 0; list < DETECT_SM_LIST_MAX; list++) { + for (list = 0; list < nlists; list++) { if (list == DETECT_SM_LIST_POSTMATCH || list == DETECT_SM_LIST_TMATCH || list == DETECT_SM_LIST_SUPPRESS || @@ -1555,7 +1672,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) #ifdef DEBUG int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { if (s->init_data->smlists[i] != NULL) { for (sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) { BUG_ON(sm == sm->prev); diff --git a/src/detect-parse.h b/src/detect-parse.h index 044fcdfd67aa..9dfe5ac2191a 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -45,11 +45,6 @@ Signature *SigAlloc(void); void SigFree(Signature *s); Signature *SigInit(DetectEngineCtx *,char *sigstr); Signature *SigInitReal(DetectEngineCtx *, char *); -SigMatch *SigMatchGetLastSMFromLists(const Signature *, int, ...); -SigMatch *SigMatchGetLastSM(const Signature *); -void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, - SigMatch **, SigMatch **s, - SigMatch **, SigMatch **); SigMatchData* SigMatchList2DataArray(SigMatch *head); void SigParsePrepare(void); void SigParseRegisterTests(void); @@ -62,13 +57,19 @@ int SigMatchListSMBelongsTo(const Signature *, const SigMatch *); int DetectParseDupSigHashInit(DetectEngineCtx *); void DetectParseDupSigHashFree(DetectEngineCtx *); -int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg, - uint8_t sm_type, uint8_t sm_list, +int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg, + int sm_type, int sm_list, AppProto alproto, void (*CustomCallback)(Signature *s)); const char *DetectListToHumanString(int list); const char *DetectListToString(int list); +SigMatch *DetectGetLastSM(const Signature *); +SigMatch *DetectGetLastSMFromMpmLists(const Signature *s); +SigMatch *DetectGetLastSMFromLists(const Signature *s, ...); +SigMatch *DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list, ...); +SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...); + /* parse regex setup and free util funcs */ void DetectSetupParseRegexes(const char *parse_str, diff --git a/src/detect-pcre.c b/src/detect-pcre.c index a43fd8fc5d1f..918c4759981a 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -760,9 +760,8 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst /* errors below shouldn't free pd */ - SigMatch *prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, sm->prev, - DETECT_PCRE, sm->prev); + SigMatch *prev_pm = DetectGetLastSMByListPtr(s, sm->prev, + DETECT_CONTENT, DETECT_PCRE, -1); if (s->init_data->list == DETECT_SM_LIST_NOTSET && prev_pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre with /R (relative) needs " "preceeding match in the same buffer"); diff --git a/src/detect-prefilter.c b/src/detect-prefilter.c index 08eacac39e93..fe50e39ac0ee 100644 --- a/src/detect-prefilter.c +++ b/src/detect-prefilter.c @@ -72,7 +72,7 @@ static int DetectPrefilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *nu goto end; } - sm = SigMatchGetLastSM(s); + sm = DetectGetLastSM(s); if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "prefilter needs preceding match"); goto end; diff --git a/src/detect-rawbytes.c b/src/detect-rawbytes.c index 0803822c89e5..5e7e48d9749e 100644 --- a/src/detect-rawbytes.c +++ b/src/detect-rawbytes.c @@ -65,8 +65,8 @@ static int DetectRawbytesSetup (DetectEngineCtx *de_ctx, Signature *s, char *nul SCReturnInt(-1); } - SigMatch *pm = SigMatchGetLastSMFromLists(s, 2, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); + SigMatch *pm = DetectGetLastSMByListId(s, DETECT_SM_LIST_PMATCH, + DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_RAWBYTES_MISSING_CONTENT, "\"rawbytes\" needs a preceding content option"); SCReturnInt(-1); diff --git a/src/detect-replace.c b/src/detect-replace.c index 7f50bbd9b649..08ab84c88746 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -103,9 +103,9 @@ int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *replacestr) return 0; } - /* add to the latest "content" keyword from either dmatch or pmatch */ - pm = SigMatchGetLastSMFromLists(s, 2, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); + /* add to the latest "content" keyword from pmatch */ + pm = DetectGetLastSMByListId(s, DETECT_SM_LIST_PMATCH, + DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "replace needs" "preceding content option for raw sig"); diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 85849295fe4b..3632d4d4d187 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -229,10 +229,10 @@ static int DetectThresholdSetup(DetectEngineCtx *de_ctx, Signature *s, char *raw SigMatch *tmpm = NULL; /* checks if there is a previous instance of detection_filter */ - tmpm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->init_data->smlists[DETECT_SM_LIST_MATCH]); + tmpm = DetectGetLastSMFromLists(s, DETECT_DETECTION_FILTER, -1); if (tmpm != NULL) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "\"detection_filter\" and \"threshold\" are not allowed in the same rule"); + SCLogError(SC_ERR_INVALID_SIGNATURE, "\"detection_filter\" and " + "\"threshold\" are not allowed in the same rule"); SCReturnInt(-1); } diff --git a/src/detect-within.c b/src/detect-within.c index 0c243c6fa702..61272e3844e2 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -84,37 +84,14 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, char *within dubbed = 1; } - /* retrive the sm to apply the depth against */ - if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->init_data->smlists_tail[s->init_data->list]); - } else { - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]); - } + /* retrieve the sm to apply the within against */ + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "within needs " - "preceding content, uricontent option, http_client_body, " - "http_server_body, http_header option, http_raw_header option, " - "http_method option, http_cookie, http_raw_uri, " - "http_stat_msg, http_stat_code, http_user_agent or " - "file_data/dce_stub_data sticky buffer option"); + "preceding content option"); goto end; } - /* verify other conditions */ DetectContentData *cd = (DetectContentData *)pm->ctx; if (cd->flags & DETECT_CONTENT_WITHIN) { @@ -162,9 +139,8 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, char *within /* these are the only ones against which we set a flag. We have other * relative keywords like byttest, isdataat, bytejump, but we don't * set a flag against them */ - SigMatch *prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, pm->prev, - DETECT_PCRE, pm->prev); + SigMatch *prev_pm = DetectGetLastSMByListPtr(s, pm->prev, + DETECT_CONTENT, DETECT_PCRE, -1); if (prev_pm == NULL) { ret = 0; goto end; diff --git a/src/detect.c b/src/detect.c index d32dc388d524..3afdf81b70ab 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3486,7 +3486,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) int prefilter_list = DETECT_TBLSIZE; /* get the keyword supporting prefilter with the lowest type */ - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { SigMatch *sm = tmp_s->init_data->smlists[i]; while (sm != NULL) { if (sigmatch_table[sm->type].SupportsPrefilter != NULL) { @@ -3500,7 +3500,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) /* apply that keyword as prefilter */ if (prefilter_list != DETECT_TBLSIZE) { - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { SigMatch *sm = tmp_s->init_data->smlists[i]; while (sm != NULL) { if (sm->type == prefilter_list) { @@ -3963,6 +3963,7 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) { SCEnter(); + const int nlists = DetectBufferTypeMaxId(); Signature *s = de_ctx->sig_list; for (; s != NULL; s = s->next) { /* set up inspect engines */ @@ -3976,7 +3977,7 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) /* free lists. Ctx' are xferred to sm_arrays so won't get freed */ int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { SigMatch *sm = s->init_data->smlists[i]; while (sm != NULL) { SigMatch *nsm = sm->next; @@ -3984,6 +3985,8 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) sm = nsm; } } + SCFree(s->init_data->smlists); + SCFree(s->init_data->smlists_tail); SCFree(s->init_data); s->init_data = NULL; } diff --git a/src/detect.h b/src/detect.h index 3520e23e18b9..e90f9fdee3c5 100644 --- a/src/detect.h +++ b/src/detect.h @@ -108,6 +108,11 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_SUPPRESS, DETECT_SM_LIST_THRESHOLD, + /* 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, + DETECT_SM_LIST_BUILTIN_MAX, /* list for http_uri keyword and the ones relative to it */ @@ -166,10 +171,6 @@ enum DetectSigmatchListEnum { 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 */ @@ -441,9 +442,9 @@ typedef struct SignatureInitData_ { int prefilter_list; /* holds all sm lists */ - struct SigMatch_ *smlists[DETECT_SM_LIST_MAX]; + struct SigMatch_ **smlists; /* holds all sm lists' tails */ - struct SigMatch_ *smlists_tail[DETECT_SM_LIST_MAX]; + struct SigMatch_ **smlists_tail; } SignatureInitData; /** \brief Signature container */ diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index c50e69146fe3..b43173281410 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -460,8 +460,8 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid /* Install it */ if (id == 0 && gid == 0) { for (s = de_ctx->sig_list; s != NULL; s = s->next) { - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + sm = DetectGetLastSMByListId(s, + DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " @@ -470,8 +470,8 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid continue; } - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + sm = DetectGetLastSMByListId(s, + DETECT_SM_LIST_THRESHOLD, DETECT_DETECTION_FILTER, -1); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " @@ -523,18 +523,8 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid } else if (id == 0 && gid > 0) { for (s = de_ctx->sig_list; s != NULL; s = s->next) { if (s->gid == gid) { - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); - if (sm != NULL) { - SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " - "an event var set. The signature event var is " - "given precedence over the threshold.conf one. " - "We'll change this in the future though.", id); - continue; - } - - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, DETECT_DETECTION_FILTER, -1); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " @@ -596,8 +586,8 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid if (parsed_type != TYPE_SUPPRESS && parsed_type != TYPE_THRESHOLD && parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT) { - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + sm = DetectGetLastSMByListId(s, + DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "a threshold set. The signature event var is " @@ -606,8 +596,8 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid goto end; } - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_DETECTION_FILTER, -1); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "a detection_filter set. The signature event var is " @@ -617,20 +607,14 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid } /* replace threshold on sig if we have a global override for it */ -#if 1 } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || parsed_type == TYPE_LIMIT) { - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); - if (sm == NULL) { - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); - } + sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, DETECT_DETECTION_FILTER, -1); if (sm != NULL) { SigMatchRemoveSMFromList(s, sm, DETECT_SM_LIST_THRESHOLD); SigMatchFree(sm); sm = NULL; } -#endif } de = SCMalloc(sizeof(DetectThresholdData)); @@ -1448,8 +1432,8 @@ int SCThresholdConfTest01(void) FAIL_IF_NULL(g_ut_threshold_fp); SCThresholdConfInitContext(de_ctx); - SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); FAIL_IF_NULL(m); DetectThresholdData *de = (DetectThresholdData *)m->ctx; @@ -1481,8 +1465,8 @@ int SCThresholdConfTest02(void) FAIL_IF_NULL(g_ut_threshold_fp); SCThresholdConfInitContext(de_ctx); - SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); FAIL_IF_NULL(m); DetectThresholdData *de = (DetectThresholdData *)m->ctx; @@ -1514,8 +1498,8 @@ int SCThresholdConfTest03(void) FAIL_IF_NULL(g_ut_threshold_fp); SCThresholdConfInitContext(de_ctx); - SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); FAIL_IF_NULL(m); DetectThresholdData *de = (DetectThresholdData *)m->ctx; @@ -1547,8 +1531,8 @@ int SCThresholdConfTest04(void) FAIL_IF_NULL(g_ut_threshold_fp); SCThresholdConfInitContext(de_ctx); - SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); FAIL_IF_NOT_NULL(m); DetectEngineCtxFree(de_ctx); @@ -1584,24 +1568,24 @@ int SCThresholdConfTest05(void) SCThresholdConfInitContext(de_ctx); Signature *s = de_ctx->sig_list; - SigMatch *m = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); FAIL_IF_NULL(m); FAIL_IF_NULL(m->ctx); DetectThresholdData *de = (DetectThresholdData *)m->ctx; FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); s = de_ctx->sig_list->next; - m = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); FAIL_IF_NULL(m); FAIL_IF_NULL(m->ctx); de = (DetectThresholdData *)m->ctx; FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); s = de_ctx->sig_list->next->next; - m = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); FAIL_IF_NULL(m); FAIL_IF_NULL(m->ctx); de = (DetectThresholdData *)m->ctx; @@ -1631,8 +1615,8 @@ int SCThresholdConfTest06(void) FAIL_IF_NULL(g_ut_threshold_fp); SCThresholdConfInitContext(de_ctx); - SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); FAIL_IF_NULL(m); DetectThresholdData *de = (DetectThresholdData *)m->ctx; @@ -1664,8 +1648,8 @@ int SCThresholdConfTest07(void) FAIL_IF_NULL(g_ut_threshold_fp); SCThresholdConfInitContext(de_ctx); - SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_DETECTION_FILTER, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_DETECTION_FILTER, -1); FAIL_IF_NULL(m); DetectThresholdData *de = (DetectThresholdData *)m->ctx; @@ -1698,8 +1682,8 @@ int SCThresholdConfTest08(void) FAIL_IF_NULL(g_ut_threshold_fp); SCThresholdConfInitContext(de_ctx); - SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_DETECTION_FILTER, sig->init_data->smlists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_DETECTION_FILTER, -1); FAIL_IF_NULL(m); DetectThresholdData *de = (DetectThresholdData *)m->ctx; @@ -2109,8 +2093,8 @@ int SCThresholdConfTest13(void) FAIL_IF_NULL(g_ut_threshold_fp); SCThresholdConfInitContext(de_ctx); - SigMatch *m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->init_data->smlists[DETECT_SM_LIST_SUPPRESS]); + SigMatch *m = DetectGetLastSMByListId(sig, + DETECT_SM_LIST_SUPPRESS, DETECT_THRESHOLD, -1); FAIL_IF_NULL(m); DetectThresholdData *de = (DetectThresholdData *)m->ctx; From 7052f9b9338e80956dd0043117796e6473b5168f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 18 Oct 2016 00:50:26 +0200 Subject: [PATCH 2367/2553] http_request_line: dynamic buffer --- src/detect-engine.c | 2 -- src/detect-http-request-line.c | 34 +++++++++++++++++++++++----------- src/detect-lua.c | 6 ++++-- src/detect-parse.c | 2 -- src/detect.h | 2 -- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index f899e029dbf3..460d37502ad2 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2824,8 +2824,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http cookie"; case DETECT_SM_LIST_HUADMATCH: return "http user-agent"; - case DETECT_SM_LIST_HTTP_REQLINEMATCH: - return "http request line"; case DETECT_SM_LIST_HTTP_RESLINEMATCH: return "http response line"; case DETECT_SM_LIST_APP_EVENT: diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 8f4b9fd9322f..15516f37beb0 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -60,14 +60,15 @@ #include "stream-tcp.h" #include "detect-http-request-line.h" -int DetectHttpRequestLineSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpRequestLineRegisterTests(void); -void DetectHttpRequestLineFree(void *); +static int DetectHttpRequestLineSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpRequestLineRegisterTests(void); static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); +static void DetectHttpRequestLineSetupCallback(Signature *s); +static int g_http_request_line_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_request_line" keyword. @@ -85,15 +86,20 @@ void DetectHttpRequestLineRegister(void) sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].flags |= SIGMATCH_PAYLOAD ; - DetectMpmAppLayerRegister("http_request_line", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HTTP_REQLINEMATCH, 2, + DetectAppLayerMpmRegister("http_request_line", SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestLineRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HTTP_REQLINEMATCH, + DetectAppLayerInspectEngineRegister2("http_request_line", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpRequestLine); - return; + DetectBufferTypeSetDescriptionByName("http_request_line", + "http request line"); + + DetectBufferTypeRegisterSetupCallback("http_request_line", + DetectHttpRequestLineSetupCallback); + + g_http_request_line_buffer_id = DetectBufferTypeGetByName("http_request_line"); } /** @@ -109,13 +115,19 @@ void DetectHttpRequestLineRegister(void) * \retval 0 On success * \retval -1 On failure */ -int DetectHttpRequestLineSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +static int DetectHttpRequestLineSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { - s->init_data->list = DETECT_SM_LIST_HTTP_REQLINEMATCH; + s->init_data->list = g_http_request_line_buffer_id; s->alproto = ALPROTO_HTTP; return 0; } +static void DetectHttpRequestLineSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + /** \brief HTTP request line Mpm prefilter callback * * \param det_ctx detection engine thread ctx @@ -308,7 +320,7 @@ static int DetectHttpRequestLineTest02(void) #endif /* UNITTESTS */ -void DetectHttpRequestLineRegisterTests(void) +static void DetectHttpRequestLineRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectHttpRequestLineTest01", DetectHttpRequestLineTest01); diff --git a/src/detect-lua.c b/src/detect-lua.c index cda8f94647e0..06a0315207a7 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1009,8 +1009,10 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRHDMATCH); else if (lua->flags & DATATYPE_HTTP_RESPONSE_COOKIE) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); - else - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HTTP_REQLINEMATCH); + else { + int list = DetectBufferTypeGetByName("http_request_line"); + SigMatchAppendSMToList(s, sm, list); + } } else if (lua->alproto == ALPROTO_DNS) { if (lua->flags & DATATYPE_DNS_RRNAME) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSQUERYNAME_MATCH); diff --git a/src/detect-parse.c b/src/detect-parse.c index cec9022deba9..18fbb9d51a5d 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -154,7 +154,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HMDMATCH, "http_method"); CASE_CODE_STRING(DETECT_SM_LIST_HCDMATCH, "http_cookie"); CASE_CODE_STRING(DETECT_SM_LIST_HUADMATCH, "http_user_agent"); - CASE_CODE_STRING(DETECT_SM_LIST_HTTP_REQLINEMATCH, "http_request_line"); CASE_CODE_STRING(DETECT_SM_LIST_HTTP_RESLINEMATCH, "http_response_line"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); @@ -199,7 +198,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HMDMATCH); CASE_CODE(DETECT_SM_LIST_HCDMATCH); CASE_CODE(DETECT_SM_LIST_HUADMATCH); - CASE_CODE(DETECT_SM_LIST_HTTP_REQLINEMATCH); CASE_CODE(DETECT_SM_LIST_HTTP_RESLINEMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); diff --git a/src/detect.h b/src/detect.h index e90f9fdee3c5..c238bcb39fe7 100644 --- a/src/detect.h +++ b/src/detect.h @@ -141,8 +141,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_HCDMATCH, /* list for http_user_agent keyword and the ones relative to it */ DETECT_SM_LIST_HUADMATCH, - /* list for http_request_line keyword and the ones relative to it */ - DETECT_SM_LIST_HTTP_REQLINEMATCH, /* list for http_response_line keyword and the ones relative to it */ DETECT_SM_LIST_HTTP_RESLINEMATCH, /* app event engine sm list */ From 6bd37611eebe68574d5a29d04d333740a276b928 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 14 Dec 2016 11:42:58 +0100 Subject: [PATCH 2368/2553] file_data: dynamic buffer --- src/detect-base64-data.c | 6 +- src/detect-byte-extract.c | 18 ++-- src/detect-bytejump.c | 20 ++--- src/detect-bytetest.c | 20 ++--- src/detect-content.c | 25 +++--- src/detect-engine-analyzer.c | 14 ++-- src/detect-engine.c | 2 - src/detect-fast-pattern.c | 86 +++++++++---------- src/detect-file-data.c | 109 +++++++++++++++++++++--- src/detect-http-server-body.c | 151 ++++++++++++++++------------------ src/detect-isdataat.c | 105 +---------------------- src/detect-lua.c | 7 +- src/detect-parse.c | 3 - src/detect-pcre.c | 46 +++++------ src/detect-pkt-data.c | 7 +- src/detect.c | 17 ---- src/detect.h | 2 - 17 files changed, 283 insertions(+), 355 deletions(-) diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c index 7b1be1f137f3..97fd2e09b708 100644 --- a/src/detect-base64-data.c +++ b/src/detect-base64-data.c @@ -74,6 +74,8 @@ int DetectBase64DataDoMatch(DetectEngineCtx *de_ctx, #include "detect-engine.h" +static int g_file_data_buffer_id = 0; + static int DetectBase64DataSetupTest01(void) { DetectEngineCtx *de_ctx = NULL; @@ -151,7 +153,7 @@ static int DetectBase64DataSetupTest02(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { printf("DETECT_SM_LIST_FILEDATA is NULL: "); goto end; @@ -249,6 +251,8 @@ static int DetectBase64DataSetupTest04(void) static void DetectBase64DataRegisterTests(void) { #ifdef UNITTESTS + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + UtRegisterTest("DetectBase64DataSetupTest01", DetectBase64DataSetupTest01); UtRegisterTest("DetectBase64DataSetupTest02", DetectBase64DataSetupTest02); UtRegisterTest("DetectBase64DataSetupTest03", DetectBase64DataSetupTest03); diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 06f39e5c74e6..64a512458fab 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -520,16 +520,8 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *a int sm_list; if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - if (s->init_data->list == DETECT_SM_LIST_FILEDATA) { - if (data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "dce byte_extract specified " - "with file_data option set."); - goto error; - } - AppLayerHtpEnableResponseBodyCallback(); - } sm_list = s->init_data->list; - s->flags |= SIG_FLAG_APPLAYER; + if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } @@ -679,6 +671,8 @@ SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, const Signature *s) #ifdef UNITTESTS +static int g_file_data_buffer_id = 0; + static int DetectByteExtractTest01(void) { int result = 0; @@ -4634,11 +4628,11 @@ static int DetectByteExtractTest62(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { + if (s->sm_lists_tail[g_file_data_buffer_id] == NULL) { goto end; } - sm = s->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = s->sm_lists[g_file_data_buffer_id]; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; @@ -4736,6 +4730,8 @@ static int DetectByteExtractTestParseNoBase(void) static void DetectByteExtractRegisterTests(void) { #ifdef UNITTESTS + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + UtRegisterTest("DetectByteExtractTest01", DetectByteExtractTest01); UtRegisterTest("DetectByteExtractTest02", DetectByteExtractTest02); UtRegisterTest("DetectByteExtractTest03", DetectByteExtractTest03); diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 4eb362b0b96c..246f1faab767 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -519,16 +519,8 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts int sm_list; if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - if (s->init_data->list == DETECT_SM_LIST_FILEDATA) { - if (data->flags & DETECT_BYTEJUMP_DCE) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "dce bytejump specified " - "with file_data option set."); - goto error; - } - AppLayerHtpEnableResponseBodyCallback(); - } sm_list = s->init_data->list; - s->flags |= SIG_FLAG_APPLAYER; + if (data->flags & DETECT_BYTEJUMP_RELATIVE) { prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } @@ -647,6 +639,8 @@ static void DetectBytejumpFree(void *ptr) /* UNITTESTS */ #ifdef UNITTESTS #include "util-unittest-helper.h" +static int g_file_data_buffer_id = 0; + /** * \test DetectBytejumpTestParse01 is a test to make sure that we return * "something" when given valid bytejump opt @@ -1070,15 +1064,15 @@ static int DetectBytejumpTestParse12(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { + if (s->sm_lists_tail[g_file_data_buffer_id] == NULL) { goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_BYTEJUMP) { + if (s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_BYTEJUMP) { goto end; } - bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + bd = (DetectBytejumpData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; if ((bd->flags & DETECT_BYTEJUMP_DCE) && (bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && @@ -1295,6 +1289,8 @@ static int DetectByteJumpTestPacket07 (void) static void DetectBytejumpRegisterTests(void) { #ifdef UNITTESTS + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01); UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02); UtRegisterTest("DetectBytejumpTestParse03", DetectBytejumpTestParse03); diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 15938a0c41c6..c51483dd8e9c 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -446,16 +446,8 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts int sm_list; if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - if (s->init_data->list == DETECT_SM_LIST_FILEDATA) { - if (data->flags & DETECT_BYTETEST_DCE) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "dce bytetest specified " - "with file_data option set."); - goto error; - } - AppLayerHtpEnableResponseBodyCallback(); - } sm_list = s->init_data->list; - s->flags |= SIG_FLAG_APPLAYER; + if (data->flags & DETECT_BYTETEST_RELATIVE) { prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } @@ -585,6 +577,8 @@ static void DetectBytetestFree(void *ptr) /* UNITTESTS */ #ifdef UNITTESTS #include "util-unittest-helper.h" +static int g_file_data_buffer_id = 0; + /** * \test DetectBytetestTestParse01 is a test to make sure that we return "something" * when given valid bytetest opt @@ -1248,17 +1242,17 @@ static int DetectBytetestTestParse22(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { + if (s->sm_lists_tail[g_file_data_buffer_id] == NULL) { printf("empty server body list: "); goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_BYTETEST) { + if (s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_BYTETEST) { printf("bytetest not last sm in server body list: "); goto end; } - bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + bd = (DetectBytetestData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; if (bd->flags & DETECT_BYTETEST_DCE && bd->flags & DETECT_BYTETEST_RELATIVE && (bd->flags & DETECT_BYTETEST_STRING) && @@ -1441,6 +1435,8 @@ static int DetectByteTestTestPacket05(void) static void DetectBytetestRegisterTests(void) { #ifdef UNITTESTS + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + UtRegisterTest("DetectBytetestTestParse01", DetectBytetestTestParse01); UtRegisterTest("DetectBytetestTestParse02", DetectBytetestTestParse02); UtRegisterTest("DetectBytetestTestParse03", DetectBytetestTestParse03); diff --git a/src/detect-content.c b/src/detect-content.c index 7726c4b8f78f..9c77013875e4 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -385,16 +385,8 @@ int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentstr) goto error; DetectContentPrint(cd); - int sm_list; - if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - if (s->init_data->list == DETECT_SM_LIST_FILEDATA && s->alproto == ALPROTO_HTTP) { - AppLayerHtpEnableResponseBodyCallback(); - s->alproto = ALPROTO_HTTP; - } - - s->flags |= SIG_FLAG_APPLAYER; - sm_list = s->init_data->list; - } else { + int sm_list = s->init_data->list; + if (sm_list == DETECT_SM_LIST_NOTSET) { sm_list = DETECT_SM_LIST_PMATCH; } @@ -432,6 +424,7 @@ void DetectContentFree(void *ptr) } #ifdef UNITTESTS /* UNITTESTS */ +static int g_file_data_buffer_id = 0; /** * \test DetectCotentParseTest01 this is a test to make sure we can deal with escaped colons @@ -1950,7 +1943,7 @@ static int DetectContentParseTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { printf("content not in FILEDATA list: "); goto end; } @@ -1990,7 +1983,7 @@ static int DetectContentParseTest37(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { printf("content not in FILEDATA list: "); goto end; } @@ -2030,7 +2023,7 @@ static int DetectContentParseTest38(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { printf("content not in FILEDATA list: "); goto end; } @@ -2114,7 +2107,7 @@ static int DetectContentParseTest39(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { printf("content not in FILEDATA list: "); goto end; } @@ -2154,7 +2147,7 @@ static int DetectContentParseTest40(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { printf("content not in FILEDATA list: "); goto end; } @@ -2855,6 +2848,8 @@ static int DetectLongContentTest3(void) static void DetectContentRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01); UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02); UtRegisterTest("DetectContentParseTest03", DetectContentParseTest03); diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 16acb2fc4b15..a13f40528256 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -126,8 +126,6 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "http cookie content\n"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(fp_engine_analysis_FD, "http client body content\n"); - else if (list_type == DETECT_SM_LIST_FILEDATA) - fprintf(fp_engine_analysis_FD, "http server body content\n"); else if (list_type == DETECT_SM_LIST_HSCDMATCH) fprintf(fp_engine_analysis_FD, "http stat code content\n"); else if (list_type == DETECT_SM_LIST_HSMDMATCH) @@ -482,8 +480,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "http cookie content"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(rule_engine_analysis_FD, "http client body content"); - else if (list_type == DETECT_SM_LIST_FILEDATA) - fprintf(rule_engine_analysis_FD, "http server body content"); else if (list_type == DETECT_SM_LIST_HSCDMATCH) fprintf(rule_engine_analysis_FD, "http stat code content"); else if (list_type == DETECT_SM_LIST_HSMDMATCH) @@ -588,6 +584,9 @@ void EngineAnalysisRules(const Signature *s, const char *line) uint32_t warn_no_direction = 0; uint32_t warn_both_direction = 0; + const int nlists = DetectBufferTypeMaxId(); + const int filedata_id = DetectBufferTypeGetByName("file_data"); + if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; } @@ -606,8 +605,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) rule_ipv6_only += 1; } - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { - + for (list_id = 0; list_id < nlists; list_id++) { SigMatch *sm = NULL; for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_PCRE) { @@ -631,7 +629,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) norm_http_buf += 1; http_cookie_buf += 1; } - else if (list_id == DETECT_SM_LIST_FILEDATA) { + else if (list_id == filedata_id) { rule_pcre_http += 1; http_server_body_buf += 1; raw_http_buf += 1; @@ -697,7 +695,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_client_body_buf += 1; } - else if (list_id == DETECT_SM_LIST_FILEDATA) { + else if (list_id == filedata_id) { rule_content_http += 1; raw_http_buf += 1; http_server_body_buf += 1; diff --git a/src/detect-engine.c b/src/detect-engine.c index 460d37502ad2..cbaef3ed9ec7 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2804,8 +2804,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http raw uri"; case DETECT_SM_LIST_HCBDMATCH: return "http client body"; - case DETECT_SM_LIST_FILEDATA: - return "http server body"; case DETECT_SM_LIST_HHDMATCH: return "http headers"; case DETECT_SM_LIST_HRHDMATCH: diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 9661eee6d2b0..e4d415c38296 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -321,6 +321,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a /*----------------------------------Unittests---------------------------------*/ #ifdef UNITTESTS +static int g_file_data_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -12883,7 +12884,7 @@ int DetectFastPatternTest466(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12921,7 +12922,7 @@ int DetectFastPatternTest467(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -12958,7 +12959,7 @@ int DetectFastPatternTest468(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -12989,7 +12990,7 @@ int DetectFastPatternTest469(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { goto end; } @@ -13025,7 +13026,7 @@ int DetectFastPatternTest470(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { goto end; } @@ -13270,7 +13271,7 @@ int DetectFastPatternTest480(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13303,7 +13304,7 @@ int DetectFastPatternTest481(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13336,7 +13337,7 @@ int DetectFastPatternTest482(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13369,7 +13370,7 @@ int DetectFastPatternTest483(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13401,7 +13402,7 @@ int DetectFastPatternTest484(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -13527,7 +13528,7 @@ int DetectFastPatternTest489(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13560,7 +13561,7 @@ int DetectFastPatternTest490(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13593,7 +13594,7 @@ int DetectFastPatternTest491(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13626,7 +13627,7 @@ int DetectFastPatternTest492(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13659,7 +13660,7 @@ int DetectFastPatternTest493(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13692,7 +13693,7 @@ int DetectFastPatternTest494(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13725,7 +13726,7 @@ int DetectFastPatternTest495(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13758,7 +13759,7 @@ int DetectFastPatternTest496(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13791,7 +13792,7 @@ int DetectFastPatternTest497(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13899,7 +13900,7 @@ int DetectFastPatternTest501(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14029,7 +14030,7 @@ int DetectFastPatternTest506(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14089,7 +14090,7 @@ int DetectFastPatternTest508(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -14126,7 +14127,7 @@ int DetectFastPatternTest509(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -14157,7 +14158,7 @@ int DetectFastPatternTest510(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { goto end; } @@ -14193,7 +14194,7 @@ int DetectFastPatternTest511(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { goto end; } @@ -14438,7 +14439,7 @@ int DetectFastPatternTest521(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -14471,7 +14472,7 @@ int DetectFastPatternTest522(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -14504,7 +14505,7 @@ int DetectFastPatternTest523(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -14537,7 +14538,7 @@ int DetectFastPatternTest524(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -14569,7 +14570,7 @@ int DetectFastPatternTest525(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14695,7 +14696,7 @@ int DetectFastPatternTest530(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14728,7 +14729,7 @@ int DetectFastPatternTest531(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14761,7 +14762,7 @@ int DetectFastPatternTest532(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14794,7 +14795,7 @@ int DetectFastPatternTest533(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14827,7 +14828,7 @@ int DetectFastPatternTest534(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14860,7 +14861,7 @@ int DetectFastPatternTest535(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14893,7 +14894,7 @@ int DetectFastPatternTest536(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14926,7 +14927,7 @@ int DetectFastPatternTest537(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14959,7 +14960,7 @@ int DetectFastPatternTest538(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15067,7 +15068,7 @@ int DetectFastPatternTest542(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15197,7 +15198,7 @@ int DetectFastPatternTest547(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18820,8 +18821,9 @@ int DetectFastPatternTest671(void) void DetectFastPatternRegisterTests(void) { - #ifdef UNITTESTS + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); UtRegisterTest("DetectFastPatternTest03", DetectFastPatternTest03); diff --git a/src/detect-file-data.c b/src/detect-file-data.c index 167ca6713774..e9a4a14b9453 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -48,6 +48,9 @@ static int DetectFiledataSetup (DetectEngineCtx *, Signature *, char *); static void DetectFiledataRegisterTests(void); +static void DetectFiledataSetupCallback(Signature *s); +static int g_file_data_buffer_id = 0; + /** * \brief Registration function for keyword: file_data */ @@ -63,19 +66,25 @@ void DetectFiledataRegister(void) sigmatch_table[DETECT_FILE_DATA].RegisterTests = DetectFiledataRegisterTests; sigmatch_table[DETECT_FILE_DATA].flags = SIGMATCH_NOOPT; - DetectMpmAppLayerRegister("file_data", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_FILEDATA, 2, + DetectAppLayerMpmRegister("file_data", SIG_FLAG_TOSERVER, 2, PrefilterTxSmtpFiledataRegister); - DetectMpmAppLayerRegister("file_data", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_FILEDATA, 2, + DetectAppLayerMpmRegister("file_data", SIG_FLAG_TOCLIENT, 2, PrefilterTxHttpResponseBodyRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_FILEDATA, + DetectAppLayerInspectEngineRegister2("file_data", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpServerBody); - DetectAppLayerInspectEngineRegister(ALPROTO_SMTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_FILEDATA, + DetectAppLayerInspectEngineRegister2("file_data", + ALPROTO_SMTP, SIG_FLAG_TOSERVER, DetectEngineInspectSMTPFiledata); + + DetectBufferTypeRegisterSetupCallback("file_data", + DetectFiledataSetupCallback); + + DetectBufferTypeSetDescriptionByName("file_data", + "http response body or smtp attachments data"); + + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); } /** @@ -114,12 +123,27 @@ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str return -1; } - s->init_data->list = DETECT_SM_LIST_FILEDATA; - + s->init_data->list = DetectBufferTypeGetByName("file_data"); return 0; } +static void DetectFiledataSetupCallback(Signature *s) +{ + if (s->alproto == ALPROTO_HTTP || s->alproto == ALPROTO_UNKNOWN) { + AppLayerHtpEnableRequestBodyCallback(); + } + if (s->alproto == ALPROTO_HTTP) { + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; + } else if (s->alproto == ALPROTO_SMTP) { + s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; + } + + SCLogDebug("callback invoked by %u", s->id); +} + #ifdef UNITTESTS +#include "detect-isdataat.h" + static int DetectFiledataParseTest01(void) { DetectEngineCtx *de_ctx = NULL; @@ -143,7 +167,7 @@ static int DetectFiledataParseTest01(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { printf("content not in FILEDATA list: "); goto end; } @@ -180,7 +204,7 @@ static int DetectFiledataParseTest02(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { printf("content not in FILEDATA list: "); goto end; } @@ -217,7 +241,7 @@ static int DetectFiledataParseTest03(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { printf("content not in FILEDATA list: "); goto end; } @@ -286,6 +310,60 @@ static int DetectFiledataParseTest05(void) return result; } + +static int DetectFiledataIsdataatParseTest1(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "file_data; content:\"one\"; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists[g_file_data_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_CONTENT); + sm = sm->next; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +static int DetectFiledataIsdataatParseTest2(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "file_data; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_file_data_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif void DetectFiledataRegisterTests(void) @@ -296,5 +374,10 @@ void DetectFiledataRegisterTests(void) UtRegisterTest("DetectFiledataParseTest03", DetectFiledataParseTest03); UtRegisterTest("DetectFiledataParseTest04", DetectFiledataParseTest04); UtRegisterTest("DetectFiledataParseTest05", DetectFiledataParseTest05); + + UtRegisterTest("DetectFiledataIsdataatParseTest1", + DetectFiledataIsdataatParseTest1); + UtRegisterTest("DetectFiledataIsdataatParseTest2", + DetectFiledataIsdataatParseTest2); #endif } diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index e1337e59ca61..9c40d480d2f5 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -59,9 +59,11 @@ #include "detect-http-server-body.h" #include "stream-tcp.h" -int DetectHttpServerBodySetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpServerBodyRegisterTests(void); -void DetectHttpServerBodyFree(void *); +static int DetectHttpServerBodySetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpServerBodyRegisterTests(void); +static void DetectHttpServerBodyFree(void *); + +static int g_file_data_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_server_body" keyword. @@ -78,15 +80,9 @@ void DetectHttpServerBodyRegister(void) sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].RegisterTests = DetectHttpServerBodyRegisterTests; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_PAYLOAD ; -} + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_PAYLOAD; -static void DetectHttpServerBodySetupCallback(Signature *s) -{ - s->flags |= SIG_FLAG_APPLAYER; - AppLayerHtpEnableResponseBodyCallback(); - - return; + g_file_data_buffer_id = DetectBufferTypeRegister("file_data"); } /** @@ -106,9 +102,8 @@ int DetectHttpServerBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_SERVER_BODY, - DETECT_SM_LIST_FILEDATA, - ALPROTO_HTTP, - DetectHttpServerBodySetupCallback); + g_file_data_buffer_id, + ALPROTO_HTTP, NULL); } /** @@ -166,7 +161,7 @@ static int DetectHttpServerBodyTest01(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { goto end; } @@ -1815,15 +1810,15 @@ int DetectHttpServerBodyTest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1870,15 +1865,15 @@ int DetectHttpServerBodyTest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1924,15 +1919,15 @@ int DetectHttpServerBodyTest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1979,15 +1974,15 @@ int DetectHttpServerBodyTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2035,15 +2030,15 @@ int DetectHttpServerBodyTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2118,15 +2113,15 @@ int DetectHttpServerBodyTest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2173,13 +2168,13 @@ int DetectHttpServerBodyTest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_DISTANCE || @@ -2217,13 +2212,13 @@ int DetectHttpServerBodyTest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_WITHIN || @@ -2316,38 +2311,32 @@ int DetectHttpServerBodyTest34(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/Q; " "content:\"two\"; within:5; http_server_body; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("de_ctx->sig_list == NULL\n"); - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); - goto end; - } + FAIL_IF_NOT_NULL(de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]); - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hsbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { @@ -2384,21 +2373,21 @@ int DetectHttpServerBodyTest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "two", hsbd1->content_len) != 0) { @@ -2435,21 +2424,21 @@ int DetectHttpServerBodyTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->prev->ctx; - DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hsbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index ad3b16ae7949..407b0a6e70de 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -211,12 +211,8 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst int sm_list; if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - if (s->init_data->list == DETECT_SM_LIST_FILEDATA) { - AppLayerHtpEnableResponseBodyCallback(); - s->alproto = ALPROTO_HTTP; - } sm_list = s->init_data->list; - s->flags |= SIG_FLAG_APPLAYER; + if (idad->flags & ISDATAAT_RELATIVE) { prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } @@ -828,103 +824,6 @@ int DetectIsdataatTestParse13(void) return result; } -static int DetectIsdataatTestParse14(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing file_data and isdataat\"; " - "file_data; content:\"one\"; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("server body list empty: "); - goto end; - } - - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_ISDATAAT) { - printf("last server body sm not isdataat: "); - goto end; - } - - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - goto end; - } - - result = 1; - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -/** - * \test file_data with isdataat relative to it - */ -static int DetectIsdataatTestParse15(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing file_data and isdataat\"; " - "file_data; isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse: "); - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL) { - printf("server body list empty: "); - goto end; - } - - if (s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_ISDATAAT) { - printf("last server body sm not isdataat: "); - goto end; - } - - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - goto end; - } - - result = 1; - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - /** * \test dns_query with isdataat relative to it */ @@ -1100,8 +999,6 @@ void DetectIsdataatRegisterTests(void) UtRegisterTest("DetectIsdataatTestParse11", DetectIsdataatTestParse11); UtRegisterTest("DetectIsdataatTestParse12", DetectIsdataatTestParse12); UtRegisterTest("DetectIsdataatTestParse13", DetectIsdataatTestParse13); - UtRegisterTest("DetectIsdataatTestParse14", DetectIsdataatTestParse14); - UtRegisterTest("DetectIsdataatTestParse15", DetectIsdataatTestParse15); UtRegisterTest("DetectIsdataatTestParse16", DetectIsdataatTestParse16); UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01); diff --git a/src/detect-lua.c b/src/detect-lua.c index 06a0315207a7..6a60482c3fc5 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -991,9 +991,10 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) else SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); } else if (lua->alproto == ALPROTO_HTTP) { - if (lua->flags & DATATYPE_HTTP_RESPONSE_BODY) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEDATA); - else if (lua->flags & DATATYPE_HTTP_REQUEST_BODY) + if (lua->flags & DATATYPE_HTTP_RESPONSE_BODY) { + int list = DetectBufferTypeGetByName("file_data"); + SigMatchAppendSMToList(s, sm, list); + } else if (lua->flags & DATATYPE_HTTP_REQUEST_BODY) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCBDMATCH); else if (lua->flags & DATATYPE_HTTP_URI) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); diff --git a/src/detect-parse.c b/src/detect-parse.c index 18fbb9d51a5d..98c3bf1d1478 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -144,7 +144,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_UMATCH, "http_uri"); CASE_CODE_STRING(DETECT_SM_LIST_HRUDMATCH, "http_raw_uri"); CASE_CODE_STRING(DETECT_SM_LIST_HCBDMATCH, "http_client_body"); - CASE_CODE_STRING(DETECT_SM_LIST_FILEDATA, "file_data"); CASE_CODE_STRING(DETECT_SM_LIST_HHDMATCH, "http_header"); CASE_CODE_STRING(DETECT_SM_LIST_HRHDMATCH, "http_raw_header"); CASE_CODE_STRING(DETECT_SM_LIST_HSMDMATCH, "http_stat_msg"); @@ -188,7 +187,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_UMATCH); CASE_CODE(DETECT_SM_LIST_HRUDMATCH); CASE_CODE(DETECT_SM_LIST_HCBDMATCH); - CASE_CODE(DETECT_SM_LIST_FILEDATA); CASE_CODE(DETECT_SM_LIST_HHDMATCH); CASE_CODE(DETECT_SM_LIST_HRHDMATCH); CASE_CODE(DETECT_SM_LIST_HSMDMATCH); @@ -1592,7 +1590,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_FILEDATA] || s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH] || diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 918c4759981a..6be08703aaea 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -458,10 +458,12 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, /* snort's option (http request body inspection) */ *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HCBDMATCH); break; - case 'Q': + case 'Q': { + int list = DetectBufferTypeGetByName("file_data"); /* suricata extension (http response body inspection) */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_FILEDATA); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } case 'Y': /* snort's option */ *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HSMDMATCH); @@ -666,7 +668,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst if (parsed_sm_list == DETECT_SM_LIST_UMATCH || parsed_sm_list == DETECT_SM_LIST_HRUDMATCH || parsed_sm_list == DETECT_SM_LIST_HCBDMATCH || - parsed_sm_list == DETECT_SM_LIST_FILEDATA || parsed_sm_list == DETECT_SM_LIST_HHDMATCH || parsed_sm_list == DETECT_SM_LIST_HRHDMATCH || parsed_sm_list == DETECT_SM_LIST_HSMDMATCH || @@ -694,14 +695,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst int sm_list = -1; if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - if (s->init_data->list == DETECT_SM_LIST_FILEDATA) { - SCLogDebug("adding to http server body list because of file data"); - AppLayerHtpEnableResponseBodyCallback(); - } else if (s->init_data->list == DETECT_SM_LIST_DMATCH) { - SCLogDebug("adding to dmatch list because of dce_stub_data"); - } else if (s->init_data->list == DETECT_SM_LIST_DNSQUERYNAME_MATCH) { - SCLogDebug("adding to DETECT_SM_LIST_DNSQUERYNAME_MATCH list because of dns_query"); - } s->flags |= SIG_FLAG_APPLAYER; sm_list = s->init_data->list; } else { @@ -713,13 +706,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst sm_list = parsed_sm_list; break; - case DETECT_SM_LIST_FILEDATA: - AppLayerHtpEnableResponseBodyCallback(); - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_HTTP; - sm_list = parsed_sm_list; - break; - case DETECT_SM_LIST_UMATCH: case DETECT_SM_LIST_HRUDMATCH: case DETECT_SM_LIST_HHDMATCH: @@ -738,6 +724,9 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_SM_LIST_NOTSET: sm_list = DETECT_SM_LIST_PMATCH; break; + default: + sm_list = parsed_sm_list; + break; } } if (sm_list == -1) @@ -805,6 +794,7 @@ void DetectPcreFree(void *ptr) } #ifdef UNITTESTS /* UNITTESTS */ +static int g_file_data_buffer_id = 0; /** * \test DetectPcreParseTest01 make sure we don't allow invalid opts 7. @@ -1097,11 +1087,11 @@ static int DetectPcreParseTest12(void) FAIL_IF (de_ctx->sig_list == NULL); s = de_ctx->sig_list; - FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL); + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id] == NULL); - FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE); + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + data = (DetectPcreData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE)); @@ -1130,11 +1120,11 @@ static int DetectPcreParseTest13(void) FAIL_IF(de_ctx->sig_list == NULL); s = de_ctx->sig_list; - FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL); + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id] == NULL); - FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE); + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + data = (DetectPcreData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE)); @@ -1163,11 +1153,11 @@ static int DetectPcreParseTest14(void) FAIL_IF(de_ctx->sig_list == NULL); s = de_ctx->sig_list; - FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA] == NULL); + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id] == NULL); - FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->type != DETECT_PCRE); + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_FILEDATA]->ctx; + data = (DetectPcreData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || data->flags & DETECT_PCRE_RELATIVE); @@ -3345,6 +3335,8 @@ static int DetectPcreParseHttpHost(void) void DetectPcreRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01); UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02); UtRegisterTest("DetectPcreParseTest03", DetectPcreParseTest03); diff --git a/src/detect-pkt-data.c b/src/detect-pkt-data.c index d1c956ea83cb..8f740636bc96 100644 --- a/src/detect-pkt-data.c +++ b/src/detect-pkt-data.c @@ -82,6 +82,7 @@ static int DetectPktDataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) #ifdef UNITTESTS /************************************Unittests*********************************/ +static int g_file_data_buffer_id = 0; static int DetectPktDataTest01(void) { @@ -105,9 +106,9 @@ static int DetectPktDataTest01(void) } /* sm should be in the MATCH list */ - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { - printf("sm not in DETECT_SM_LIST_FILEDATA: "); + printf("sm not in g_file_data_buffer_id: "); goto end; } @@ -145,6 +146,8 @@ static int DetectPktDataTest01(void) static void DetectPktDataTestRegister(void) { #ifdef UNITTESTS + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + UtRegisterTest("DetectPktDataTest01", DetectPktDataTest01); #endif } diff --git a/src/detect.c b/src/detect.c index 3afdf81b70ab..11aecad95172 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1918,9 +1918,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL) return 0; @@ -2029,9 +2026,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL) return 0; @@ -2164,7 +2158,6 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL || s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL || @@ -2337,16 +2330,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http app state"); } - if (s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL) { - /* set the state depending from the protocol */ - if (s->alproto == ALPROTO_HTTP) - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - else if (s->alproto == ALPROTO_SMTP) - s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; - - SCLogDebug("sig requires http or smtp app state"); - } - if (s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); diff --git a/src/detect.h b/src/detect.h index c238bcb39fe7..330b918f4b10 100644 --- a/src/detect.h +++ b/src/detect.h @@ -121,8 +121,6 @@ enum DetectSigmatchListEnum { 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_FILEDATA, /* 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 */ From e34102d67aa53ab786987709a9a22b7c6a2a7c09 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 7 Dec 2016 18:02:37 +0100 Subject: [PATCH 2369/2553] http_method: make list dynamic --- src/detect-engine-analyzer.c | 9 +-- src/detect-engine.c | 2 - src/detect-fast-pattern.c | 44 +++++++------- src/detect-http-method.c | 111 ++++++++++++++++++++++++----------- src/detect-http-method.h | 3 - src/detect-isdataat.c | 45 -------------- src/detect-parse.c | 8 --- src/detect-pcre.c | 6 +- src/detect.c | 12 ---- src/detect.h | 2 - 10 files changed, 105 insertions(+), 137 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index a13f40528256..223a3b1c0fed 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -120,8 +120,6 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "http header content\n"); else if (list_type == DETECT_SM_LIST_HRHDMATCH) fprintf(fp_engine_analysis_FD, "http raw header content\n"); - else if (list_type == DETECT_SM_LIST_HMDMATCH) - fprintf(fp_engine_analysis_FD, "http method content\n"); else if (list_type == DETECT_SM_LIST_HCDMATCH) fprintf(fp_engine_analysis_FD, "http cookie content\n"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) @@ -474,8 +472,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "http header content"); else if (list_type == DETECT_SM_LIST_HRHDMATCH) fprintf(rule_engine_analysis_FD, "http raw header content"); - else if (list_type == DETECT_SM_LIST_HMDMATCH) - fprintf(rule_engine_analysis_FD, "http method content"); else if (list_type == DETECT_SM_LIST_HCDMATCH) fprintf(rule_engine_analysis_FD, "http cookie content"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) @@ -586,6 +582,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) const int nlists = DetectBufferTypeMaxId(); const int filedata_id = DetectBufferTypeGetByName("file_data"); + const int httpmethod_id = DetectBufferTypeGetByName("http_method"); if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; @@ -639,7 +636,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_raw_header_buf += 1; } - else if (list_id == DETECT_SM_LIST_HMDMATCH) { + else if (list_id == httpmethod_id) { rule_pcre_http += 1; raw_http_buf += 1; http_method_buf += 1; @@ -720,7 +717,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_stat_code_buf += 1; } - else if (list_id == DETECT_SM_LIST_HMDMATCH) { + else if (list_id == httpmethod_id) { rule_content_http += 1; raw_http_buf += 1; http_method_buf += 1; diff --git a/src/detect-engine.c b/src/detect-engine.c index cbaef3ed9ec7..5bf07207f72d 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2816,8 +2816,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http host"; case DETECT_SM_LIST_HRHHDMATCH: return "http raw host header"; - case DETECT_SM_LIST_HMDMATCH: - return "http method"; case DETECT_SM_LIST_HCDMATCH: return "http cookie"; case DETECT_SM_LIST_HUADMATCH: diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index e4d415c38296..4179b5eac6af 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -322,6 +322,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a #ifdef UNITTESTS static int g_file_data_buffer_id = 0; +static int g_http_method_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -7168,7 +7169,7 @@ int DetectFastPatternTest261(void) "content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7206,7 +7207,7 @@ int DetectFastPatternTest262(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_method_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -7243,7 +7244,7 @@ int DetectFastPatternTest263(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_method_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -7275,7 +7276,7 @@ int DetectFastPatternTest264(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_method_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -7309,7 +7310,7 @@ int DetectFastPatternTest265(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_method_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7539,7 +7540,7 @@ int DetectFastPatternTest275(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7569,7 +7570,7 @@ int DetectFastPatternTest276(void) "(content:\"one\"; http_method; content:\"two\"; http_method; within:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7599,7 +7600,7 @@ int DetectFastPatternTest277(void) "(content:\"one\"; http_method; content:\"two\"; http_method; offset:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7629,7 +7630,7 @@ int DetectFastPatternTest278(void) "(content:\"one\"; http_method; content:\"two\"; http_method; depth:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7659,7 +7660,7 @@ int DetectFastPatternTest279(void) "(content:!\"one\"; fast_pattern; http_method; content:\"two\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7778,7 +7779,7 @@ int DetectFastPatternTest284(void) "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7808,7 +7809,7 @@ int DetectFastPatternTest285(void) "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7838,7 +7839,7 @@ int DetectFastPatternTest286(void) "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7868,7 +7869,7 @@ int DetectFastPatternTest287(void) "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7898,7 +7899,7 @@ int DetectFastPatternTest288(void) "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7928,7 +7929,7 @@ int DetectFastPatternTest289(void) "(content:\"one\"; http_method; content:\"two\"; http_method; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7958,7 +7959,7 @@ int DetectFastPatternTest290(void) "(content:\"one\"; http_method; content:\"two\"; http_method; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7988,7 +7989,7 @@ int DetectFastPatternTest291(void) "(content:\"one\"; http_method; content:\"two\"; http_method; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8018,7 +8019,7 @@ int DetectFastPatternTest292(void) "(content:\"one\"; http_method; content:\"two\"; http_method; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8117,7 +8118,7 @@ int DetectFastPatternTest296(void) "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8236,7 +8237,7 @@ int DetectFastPatternTest301(void) "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18823,6 +18824,7 @@ void DetectFastPatternRegisterTests(void) { #ifdef UNITTESTS g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_http_method_buffer_id = DetectBufferTypeGetByName("http_method"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 5371b97b2e83..af703c9a0f21 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -60,10 +60,12 @@ #include "detect-engine-hmd.h" #include "stream-tcp.h" - +static int g_http_method_buffer_id = 0; static int DetectHttpMethodSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpMethodRegisterTests(void); void DetectHttpMethodFree(void *); +static void DetectHttpMethodSetupCallback(Signature *s); +static _Bool DetectHttpMethodValidateCallback(const Signature *s); /** * \brief Registration function for keyword: http_method @@ -81,14 +83,23 @@ void DetectHttpMethodRegister(void) sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("http_method", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HMDMATCH, 4, + DetectAppLayerMpmRegister("http_method", SIG_FLAG_TOSERVER, 4, PrefilterTxMethodRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HMDMATCH, + DetectAppLayerInspectEngineRegister2("http_method", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpMethod); + DetectBufferTypeSetDescriptionByName("http_method", + "http request method"); + + DetectBufferTypeRegisterSetupCallback("http_method", + DetectHttpMethodSetupCallback); + DetectBufferTypeRegisterValidateCallback("http_method", + DetectHttpMethodValidateCallback); + + g_http_method_buffer_id = DetectBufferTypeGetByName("http_method"); + SCLogDebug("registering http_method rule option"); } @@ -107,7 +118,7 @@ static int DetectHttpMethodSetup(DetectEngineCtx *de_ctx, Signature *s, char *st { return DetectEngineContentModifierBufferSetup(de_ctx, s, str, DETECT_AL_HTTP_METHOD, - DETECT_SM_LIST_HMDMATCH, + g_http_method_buffer_id, ALPROTO_HTTP, NULL); } @@ -126,43 +137,45 @@ void DetectHttpMethodFree(void *ptr) SCFree(data); } +static void DetectHttpMethodSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + /** * \retval 1 valid * \retval 0 invalid */ -int DetectHttpMethodValidateRule(const Signature *s) +static _Bool DetectHttpMethodValidateCallback(const Signature *s) { - if (s->alproto != ALPROTO_HTTP) - return 1; - - if (s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL) { - const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_HMDMATCH]; - for ( ; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - const DetectContentData *cd = (const DetectContentData *)sm->ctx; - if (cd->content && cd->content_len) { - if (cd->content[cd->content_len-1] == 0x20) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with trailing space"); - return 0; - } else if (cd->content[0] == 0x20) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with leading space"); - return 0; - } else if (cd->content[cd->content_len-1] == 0x09) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with trailing tab"); - return 0; - } else if (cd->content[0] == 0x09) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with leading tab"); - return 0; - } + const SigMatch *sm = s->init_data->smlists[g_http_method_buffer_id]; + for ( ; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + const DetectContentData *cd = (const DetectContentData *)sm->ctx; + if (cd->content && cd->content_len) { + if (cd->content[cd->content_len-1] == 0x20) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with trailing space"); + return FALSE; + } else if (cd->content[0] == 0x20) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with leading space"); + return FALSE; + } else if (cd->content[cd->content_len-1] == 0x09) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with trailing tab"); + return FALSE; + } else if (cd->content[0] == 0x09) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with leading tab"); + return FALSE; } } } - return 1; + return TRUE; } #ifdef UNITTESTS /* UNITTESTS */ +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** \test Check a signature with content */ @@ -330,13 +343,13 @@ static int DetectHttpMethodTest12(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL: "); + if (de_ctx->sig_list->sm_lists[g_http_method_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_method_buffer_id] == NULL: "); goto end; } - DetectContentData *hmd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; - DetectContentData *hmd2 = (DetectContentData *)de_ctx->sig_list->next->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *hmd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; + DetectContentData *hmd2 = (DetectContentData *)de_ctx->sig_list->next->sm_lists_tail[g_http_method_buffer_id]->ctx; if (!(hmd1->flags & DETECT_CONTENT_NOCASE)) { printf("nocase flag not set on sig 1: "); @@ -850,6 +863,31 @@ static int DetectHttpMethodSigTest04(void) return result; } +static int DetectHttpMethodIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "content:\"one\"; http_method; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_method_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ /** @@ -873,6 +911,9 @@ void DetectHttpMethodRegisterTests(void) UtRegisterTest("DetectHttpMethodSigTest02", DetectHttpMethodSigTest02); UtRegisterTest("DetectHttpMethodSigTest03", DetectHttpMethodSigTest03); UtRegisterTest("DetectHttpMethodSigTest04", DetectHttpMethodSigTest04); + + UtRegisterTest("DetectHttpMethodIsdataatParseTest", + DetectHttpMethodIsdataatParseTest); #endif /* UNITTESTS */ } diff --git a/src/detect-http-method.h b/src/detect-http-method.h index d1593aed7603..871177b58749 100644 --- a/src/detect-http-method.h +++ b/src/detect-http-method.h @@ -26,9 +26,6 @@ /* prototypes */ void DetectHttpMethodRegister(void); -int DetectHttpMethodDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, - Flow *, uint8_t, void *); -int DetectHttpMethodValidateRule(const Signature *s); #endif /* __DETECT_HTTP_METHOD_H__ */ diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 407b0a6e70de..d2e01b35d3f4 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -736,50 +736,6 @@ int DetectIsdataatTestParse11(void) return result; } -int DetectIsdataatTestParse12(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; http_method; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - int DetectIsdataatTestParse13(void) { DetectEngineCtx *de_ctx = NULL; @@ -997,7 +953,6 @@ void DetectIsdataatRegisterTests(void) UtRegisterTest("DetectIsdataatTestParse09", DetectIsdataatTestParse09); UtRegisterTest("DetectIsdataatTestParse10", DetectIsdataatTestParse10); UtRegisterTest("DetectIsdataatTestParse11", DetectIsdataatTestParse11); - UtRegisterTest("DetectIsdataatTestParse12", DetectIsdataatTestParse12); UtRegisterTest("DetectIsdataatTestParse13", DetectIsdataatTestParse13); UtRegisterTest("DetectIsdataatTestParse16", DetectIsdataatTestParse16); diff --git a/src/detect-parse.c b/src/detect-parse.c index 98c3bf1d1478..7b8670b325f5 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -150,7 +150,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HSCDMATCH, "http_stat_code"); CASE_CODE_STRING(DETECT_SM_LIST_HHHDMATCH, "http_host"); CASE_CODE_STRING(DETECT_SM_LIST_HRHHDMATCH, "http_raw_host"); - CASE_CODE_STRING(DETECT_SM_LIST_HMDMATCH, "http_method"); CASE_CODE_STRING(DETECT_SM_LIST_HCDMATCH, "http_cookie"); CASE_CODE_STRING(DETECT_SM_LIST_HUADMATCH, "http_user_agent"); CASE_CODE_STRING(DETECT_SM_LIST_HTTP_RESLINEMATCH, "http_response_line"); @@ -193,7 +192,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HSCDMATCH); CASE_CODE(DETECT_SM_LIST_HHHDMATCH); CASE_CODE(DETECT_SM_LIST_HRHHDMATCH); - CASE_CODE(DETECT_SM_LIST_HMDMATCH); CASE_CODE(DETECT_SM_LIST_HCDMATCH); CASE_CODE(DETECT_SM_LIST_HUADMATCH); CASE_CODE(DETECT_SM_LIST_HTTP_RESLINEMATCH); @@ -1436,7 +1434,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use uricontent " "/http_uri , raw_uri, http_client_body, " @@ -1461,7 +1458,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) { sig_flags |= SIG_FLAG_TOSERVER; s->flags |= SIG_FLAG_TOSERVER; @@ -1521,9 +1517,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } - if (!DetectHttpMethodValidateRule(s)) - SCReturnInt(0); - //if (s->alproto != ALPROTO_UNKNOWN) { // if (s->flags & SIG_FLAG_STATE_MATCH) { // if (s->alproto == ALPROTO_DNS) { @@ -1592,7 +1585,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HMDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH] || diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 6be08703aaea..c7477d8d9241 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -445,7 +445,8 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'M' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HMDMATCH); + int list = DetectBufferTypeGetByName("http_method"); + *sm_list = DetectPcreSetList(*sm_list, list); break; case 'C': /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { @@ -674,7 +675,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst parsed_sm_list == DETECT_SM_LIST_HSCDMATCH || parsed_sm_list == DETECT_SM_LIST_HHHDMATCH || parsed_sm_list == DETECT_SM_LIST_HRHHDMATCH || - parsed_sm_list == DETECT_SM_LIST_HMDMATCH || +// parsed_sm_list == DETECT_SM_LIST_HMDMATCH || parsed_sm_list == DETECT_SM_LIST_HCDMATCH || parsed_sm_list == DETECT_SM_LIST_HUADMATCH) { @@ -715,7 +716,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_SM_LIST_HSMDMATCH: case DETECT_SM_LIST_HSCDMATCH: case DETECT_SM_LIST_HCDMATCH: - case DETECT_SM_LIST_HMDMATCH: case DETECT_SM_LIST_HUADMATCH: s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; diff --git a/src/detect.c b/src/detect.c index 11aecad95172..321d21af1702 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1924,9 +1924,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL) return 0; @@ -2032,9 +2029,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL) return 0; @@ -2160,7 +2154,6 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL || @@ -2340,11 +2333,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http app state"); } - if (s->init_data->smlists[DETECT_SM_LIST_HMDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - if (s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); diff --git a/src/detect.h b/src/detect.h index 330b918f4b10..976d75b20d21 100644 --- a/src/detect.h +++ b/src/detect.h @@ -133,8 +133,6 @@ enum DetectSigmatchListEnum { 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 */ From 6346a074a7b828952e094b2efd54dc12a6149b2d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 8 Dec 2016 09:19:34 +0100 Subject: [PATCH 2370/2553] http_uri: dynamic buffer Clean up tests --- src/detect-byte-extract.c | 24 ++++--- src/detect-engine-analyzer.c | 11 ++- src/detect-engine.c | 2 - src/detect-fast-pattern.c | 82 +++++++++++----------- src/detect-http-cookie.c | 20 +++--- src/detect-http-uri.c | 130 +++++++++++++++++++++++------------ src/detect-http-uri.h | 5 +- src/detect-isdataat.c | 90 ------------------------ src/detect-lua.c | 7 +- src/detect-parse.c | 10 +-- src/detect-pcre.c | 13 ++-- src/detect-uricontent.c | 89 ++++++++++++++++-------- src/detect-urilen.c | 7 +- src/detect.c | 12 ---- src/detect.h | 4 +- 15 files changed, 238 insertions(+), 268 deletions(-) diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 64a512458fab..1a7a0268cd2c 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -672,6 +672,7 @@ SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, const Signature *s) #ifdef UNITTESTS static int g_file_data_buffer_id = 0; +static int g_http_uri_buffer_id = 0; static int DetectByteExtractTest01(void) { @@ -1691,7 +1692,7 @@ static int DetectByteExtractTest37(void) goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -1804,7 +1805,7 @@ static int DetectByteExtractTest38(void) goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -1892,7 +1893,7 @@ static int DetectByteExtractTest39(void) goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -2005,7 +2006,7 @@ static int DetectByteExtractTest40(void) goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -2237,7 +2238,7 @@ static int DetectByteExtractTest42(void) if (sm->next != NULL) goto end; - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -3776,7 +3777,7 @@ static int DetectByteExtractTest56(void) goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -3948,7 +3949,7 @@ static int DetectByteExtractTest57(void) if (sm->next != NULL) goto end; - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -4411,12 +4412,12 @@ static int DetectByteExtractTest60(void) if (sm->next != NULL) goto end; - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { + if (s->sm_lists_tail[g_http_uri_buffer_id] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -4541,12 +4542,12 @@ static int DetectByteExtractTest61(void) if (sm->next != NULL) goto end; - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { + if (s->sm_lists_tail[g_http_uri_buffer_id] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -4731,6 +4732,7 @@ static void DetectByteExtractRegisterTests(void) { #ifdef UNITTESTS g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); UtRegisterTest("DetectByteExtractTest01", DetectByteExtractTest01); UtRegisterTest("DetectByteExtractTest02", DetectByteExtractTest02); diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 223a3b1c0fed..19f153b03fad 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -112,8 +112,6 @@ void EngineAnalysisFP(Signature *s, char *line) int list_type = SigMatchListSMBelongsTo(s, mpm_sm); if (list_type == DETECT_SM_LIST_PMATCH) fprintf(fp_engine_analysis_FD, "content\n"); - else if (list_type == DETECT_SM_LIST_UMATCH) - fprintf(fp_engine_analysis_FD, "http uri content\n"); else if (list_type == DETECT_SM_LIST_HRUDMATCH) fprintf(fp_engine_analysis_FD, "http raw uri content\n"); else if (list_type == DETECT_SM_LIST_HHDMATCH) @@ -464,8 +462,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "%s", payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream"); } - else if (list_type == DETECT_SM_LIST_UMATCH) - fprintf(rule_engine_analysis_FD, "http uri content"); else if (list_type == DETECT_SM_LIST_HRUDMATCH) fprintf(rule_engine_analysis_FD, "http raw uri content"); else if (list_type == DETECT_SM_LIST_HHDMATCH) @@ -583,6 +579,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) const int nlists = DetectBufferTypeMaxId(); const int filedata_id = DetectBufferTypeGetByName("file_data"); const int httpmethod_id = DetectBufferTypeGetByName("http_method"); + const int httpuri_id = DetectBufferTypeGetByName("http_uri"); if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; @@ -611,7 +608,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) http_client_body_buf += 1; raw_http_buf += 1; } - else if (list_id == DETECT_SM_LIST_UMATCH) { + else if (list_id == httpuri_id) { rule_pcre_http += 1; norm_http_buf += 1; http_uri_buf += 1; @@ -667,7 +664,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) } else if (sm->type == DETECT_CONTENT) { - if (list_id == DETECT_SM_LIST_UMATCH + if (list_id == httpuri_id || list_id == DETECT_SM_LIST_HHDMATCH || list_id == DETECT_SM_LIST_HCDMATCH) { rule_content_http += 1; @@ -677,7 +674,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) warn_encoding_norm_http_buf += 1; rule_warning += 1; } - if (list_id == DETECT_SM_LIST_UMATCH) { + if (list_id == httpuri_id) { http_uri_buf += 1; } else if (list_id == DETECT_SM_LIST_HHDMATCH) { diff --git a/src/detect-engine.c b/src/detect-engine.c index 5bf07207f72d..c9244e904fd3 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2798,8 +2798,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_PMATCH: return "packet/stream payload"; - case DETECT_SM_LIST_UMATCH: - return "http uri"; case DETECT_SM_LIST_HRUDMATCH: return "http raw uri"; case DETECT_SM_LIST_HCBDMATCH: diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 4179b5eac6af..239c0bc8b13e 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -323,6 +323,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a #ifdef UNITTESTS static int g_file_data_buffer_id = 0; static int g_http_method_buffer_id = 0; +static int g_http_uri_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -1594,7 +1595,7 @@ int DetectFastPatternTest54(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & @@ -1635,7 +1636,7 @@ int DetectFastPatternTest55(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & @@ -1672,7 +1673,7 @@ int DetectFastPatternTest56(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && @@ -1708,7 +1709,7 @@ int DetectFastPatternTest57(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && @@ -1940,7 +1941,7 @@ int DetectFastPatternTest67(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -1970,7 +1971,7 @@ int DetectFastPatternTest68(void) "(uricontent:\"one\"; uricontent:\"two\"; within:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2000,7 +2001,7 @@ int DetectFastPatternTest69(void) "(uricontent:\"one\"; uricontent:\"two\"; offset:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2030,7 +2031,7 @@ int DetectFastPatternTest70(void) "(uricontent:\"one\"; uricontent:\"two\"; depth:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2060,7 +2061,7 @@ int DetectFastPatternTest71(void) "(uricontent:!\"one\"; fast_pattern; uricontent:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -2179,7 +2180,7 @@ int DetectFastPatternTest76(void) "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2209,7 +2210,7 @@ int DetectFastPatternTest77(void) "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2239,7 +2240,7 @@ int DetectFastPatternTest78(void) "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2269,7 +2270,7 @@ int DetectFastPatternTest79(void) "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2299,7 +2300,7 @@ int DetectFastPatternTest80(void) "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2329,7 +2330,7 @@ int DetectFastPatternTest81(void) "(uricontent:\"one\"; uricontent:\"two\"; distance:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2359,7 +2360,7 @@ int DetectFastPatternTest82(void) "(uricontent:\"one\"; uricontent:\"two\"; within:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2389,7 +2390,7 @@ int DetectFastPatternTest83(void) "(uricontent:\"one\"; uricontent:\"two\"; offset:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2419,7 +2420,7 @@ int DetectFastPatternTest84(void) "(uricontent:\"one\"; uricontent:\"two\"; depth:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2518,7 +2519,7 @@ int DetectFastPatternTest88(void) "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -2642,7 +2643,7 @@ int DetectFastPatternTest93(void) "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -2680,7 +2681,7 @@ int DetectFastPatternTest94(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & @@ -2721,7 +2722,7 @@ int DetectFastPatternTest95(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & @@ -2758,7 +2759,7 @@ int DetectFastPatternTest96(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && @@ -2794,7 +2795,7 @@ int DetectFastPatternTest97(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && @@ -3026,7 +3027,7 @@ int DetectFastPatternTest107(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3056,7 +3057,7 @@ int DetectFastPatternTest108(void) "(uricontent:\"one\"; uricontent:\"two\"; within:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3086,7 +3087,7 @@ int DetectFastPatternTest109(void) "(uricontent:\"one\"; uricontent:\"two\"; offset:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3116,7 +3117,7 @@ int DetectFastPatternTest110(void) "(uricontent:\"one\"; uricontent:\"two\"; depth:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3146,7 +3147,7 @@ int DetectFastPatternTest111(void) "(content:!\"one\"; fast_pattern; http_uri; uricontent:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3265,7 +3266,7 @@ int DetectFastPatternTest116(void) "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3295,7 +3296,7 @@ int DetectFastPatternTest117(void) "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3325,7 +3326,7 @@ int DetectFastPatternTest118(void) "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3355,7 +3356,7 @@ int DetectFastPatternTest119(void) "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3385,7 +3386,7 @@ int DetectFastPatternTest120(void) "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3415,7 +3416,7 @@ int DetectFastPatternTest121(void) "(uricontent:\"one\"; uricontent:\"two\"; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3445,7 +3446,7 @@ int DetectFastPatternTest122(void) "(uricontent:\"one\"; uricontent:\"two\"; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3475,7 +3476,7 @@ int DetectFastPatternTest123(void) "(uricontent:\"one\"; uricontent:\"two\"; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3505,7 +3506,7 @@ int DetectFastPatternTest124(void) "(uricontent:\"one\"; uricontent:\"two\"; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3604,7 +3605,7 @@ int DetectFastPatternTest128(void) "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3723,7 +3724,7 @@ int DetectFastPatternTest133(void) "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18825,6 +18826,7 @@ void DetectFastPatternRegisterTests(void) #ifdef UNITTESTS g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); g_http_method_buffer_id = DetectBufferTypeGetByName("http_method"); + g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 104d39d9a77a..2bb0e6d46045 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -138,11 +138,13 @@ static int DetectHttpCookieSetup(DetectEngineCtx *de_ctx, Signature *s, char *st #include "stream-tcp-reassemble.h" +static int g_http_uri_buffer_id = 0; + /** * \test Checks if a http_cookie is registered in a Signature, if content is not * specified in the signature */ -int DetectHttpCookieTest01(void) +static int DetectHttpCookieTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -166,7 +168,7 @@ int DetectHttpCookieTest01(void) * \test Checks if a http_cookie is registered in a Signature, if some parameter * is specified with http_cookie in the signature */ -int DetectHttpCookieTest02(void) +static int DetectHttpCookieTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -190,7 +192,7 @@ int DetectHttpCookieTest02(void) /** * \test Checks if a http_cookie is registered in a Signature */ -int DetectHttpCookieTest03(void) +static int DetectHttpCookieTest03(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; @@ -237,7 +239,7 @@ int DetectHttpCookieTest03(void) * \test Checks if a http_cookie is registered in a Signature, when fast_pattern * is also specified in the signature (now it should) */ -int DetectHttpCookieTest04(void) +static int DetectHttpCookieTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -262,7 +264,7 @@ int DetectHttpCookieTest04(void) * \test Checks if a http_cookie is registered in a Signature, when rawbytes is * also specified in the signature */ -int DetectHttpCookieTest05(void) +static int DetectHttpCookieTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -287,7 +289,7 @@ int DetectHttpCookieTest05(void) * \test Checks if a http_cookie is registered in a Signature, when rawbytes is * also specified in the signature */ -int DetectHttpCookieTest06(void) +static int DetectHttpCookieTest06(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -309,12 +311,12 @@ int DetectHttpCookieTest06(void) if (s->sm_lists[DETECT_SM_LIST_HCDMATCH]->type != DETECT_CONTENT) goto end; - if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { + if (s->sm_lists[g_http_uri_buffer_id] == NULL) { printf("expected another SigMatch, got NULL: "); goto end; } - if (s->sm_lists[DETECT_SM_LIST_UMATCH]->type != DETECT_CONTENT) { + if (s->sm_lists[g_http_uri_buffer_id]->type != DETECT_CONTENT) { goto end; } @@ -1279,6 +1281,8 @@ static int DetectHttpCookieSigTest09(void) void DetectHttpCookieRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ + g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); + UtRegisterTest("DetectHttpCookieTest01", DetectHttpCookieTest01); UtRegisterTest("DetectHttpCookieTest02", DetectHttpCookieTest02); UtRegisterTest("DetectHttpCookieTest03", DetectHttpCookieTest03); diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 11d8f2c3d0db..1d6b102785c8 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -56,8 +56,10 @@ #include "detect-engine-uri.h" #include "stream-tcp.h" -int DetectHttpUriSetup (DetectEngineCtx *, Signature *, char *); -void DetectHttpUriRegisterTests(void); +static void DetectHttpUriRegisterTests(void); +static void DetectHttpUriSetupCallback(Signature *s); + +static int g_http_uri_buffer_id = 0; /** * \brief Registration function for keyword: http_uri @@ -76,13 +78,19 @@ void DetectHttpUriRegister (void) sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("http_uri", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_UMATCH, 2, + DetectAppLayerMpmRegister("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterTxUriRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_UMATCH, + DetectAppLayerInspectEngineRegister2("http_uri", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpUri); + + DetectBufferTypeSetDescriptionByName("http_uri", + "http request uri"); + + DetectBufferTypeRegisterSetupCallback("http_uri", + DetectHttpUriSetupCallback); + + g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); } @@ -101,23 +109,29 @@ int DetectHttpUriSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { return DetectEngineContentModifierBufferSetup(de_ctx, s, str, DETECT_AL_HTTP_URI, - DETECT_SM_LIST_UMATCH, + g_http_uri_buffer_id, ALPROTO_HTTP, NULL); } +static void DetectHttpUriSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} /******************************** UNITESTS **********************************/ #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** * \test Checks if a http_uri is registered in a Signature, if content is not * specified in the signature */ -int DetectHttpUriTest01(void) +static int DetectHttpUriTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -141,7 +155,7 @@ int DetectHttpUriTest01(void) * \test Checks if a http_uri is registered in a Signature, if some parameter * is specified with http_uri in the signature */ -int DetectHttpUriTest02(void) +static int DetectHttpUriTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -165,7 +179,7 @@ int DetectHttpUriTest02(void) /** * \test Checks if a http_uri is registered in a Signature */ -int DetectHttpUriTest03(void) +static int DetectHttpUriTest03(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; @@ -186,7 +200,7 @@ int DetectHttpUriTest03(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; @@ -212,7 +226,7 @@ int DetectHttpUriTest03(void) * \test Checks if a http_uri is registered in a Signature, when rawbytes is * also specified in the signature */ -int DetectHttpUriTest04(void) +static int DetectHttpUriTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -237,7 +251,7 @@ int DetectHttpUriTest04(void) * \test Checks if a http_uri is successfully converted to a uricontent * */ -int DetectHttpUriTest05(void) +static int DetectHttpUriTest05(void) { DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; @@ -254,16 +268,16 @@ int DetectHttpUriTest05(void) printf("sig failed to parse\n"); goto end; } - if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) + if (s->sm_lists[g_http_uri_buffer_id] == NULL) goto end; - if (s->sm_lists[DETECT_SM_LIST_UMATCH]->type != DETECT_CONTENT) { + if (s->sm_lists[g_http_uri_buffer_id]->type != DETECT_CONTENT) { printf("wrong type\n"); goto end; } char *str = "we are testing http_uri keyword"; - int uricomp = memcmp((const char *)((DetectContentData*) s->sm_lists[DETECT_SM_LIST_UMATCH]->ctx)->content, str, strlen(str)-1); - int urilen = ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->content_len; + int uricomp = memcmp((const char *)((DetectContentData*) s->sm_lists[g_http_uri_buffer_id]->ctx)->content, str, strlen(str)-1); + int urilen = ((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx)->content_len; if (uricomp != 0 || urilen != strlen("we are testing http_uri keyword")) { printf("sig failed to parse, content not setup properly\n"); @@ -277,7 +291,7 @@ int DetectHttpUriTest05(void) return result; } -int DetectHttpUriTest12(void) +static int DetectHttpUriTest12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -299,13 +313,13 @@ int DetectHttpUriTest12(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL\n"); goto end; } - DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -321,7 +335,7 @@ int DetectHttpUriTest12(void) return result; } -int DetectHttpUriTest13(void) +static int DetectHttpUriTest13(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -343,13 +357,13 @@ int DetectHttpUriTest13(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL\n"); goto end; } - DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || @@ -365,7 +379,7 @@ int DetectHttpUriTest13(void) return result; } -int DetectHttpUriTest14(void) +static int DetectHttpUriTest14(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -389,7 +403,7 @@ int DetectHttpUriTest14(void) return result; } -int DetectHttpUriTest15(void) +static int DetectHttpUriTest15(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -405,12 +419,12 @@ int DetectHttpUriTest15(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL\n"); goto end; } - DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (memcmp(cd->content, "one", cd->content_len) != 0 || cd->flags != DETECT_CONTENT_WITHIN) { goto end; @@ -424,7 +438,7 @@ int DetectHttpUriTest15(void) return result; } -int DetectHttpUriTest16(void) +static int DetectHttpUriTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -448,7 +462,7 @@ int DetectHttpUriTest16(void) return result; } -int DetectHttpUriTest17(void) +static int DetectHttpUriTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -470,13 +484,13 @@ int DetectHttpUriTest17(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL\n"); goto end; } - DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -492,7 +506,7 @@ int DetectHttpUriTest17(void) return result; } -int DetectHttpUriTest18(void) +static int DetectHttpUriTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -514,13 +528,13 @@ int DetectHttpUriTest18(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL\n"); goto end; } - DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || @@ -536,12 +550,37 @@ int DetectHttpUriTest18(void) return result; } +static int DetectHttpUriIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "content:\"one\"; http_uri; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_uri_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ /** * \brief Register the UNITTESTS for the http_uri keyword */ -void DetectHttpUriRegisterTests (void) +static void DetectHttpUriRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectHttpUriTest01", DetectHttpUriTest01); @@ -556,6 +595,9 @@ void DetectHttpUriRegisterTests (void) UtRegisterTest("DetectHttpUriTest16", DetectHttpUriTest16); UtRegisterTest("DetectHttpUriTest17", DetectHttpUriTest17); UtRegisterTest("DetectHttpUriTest18", DetectHttpUriTest18); + + UtRegisterTest("DetectHttpUriIsdataatParseTest", + DetectHttpUriIsdataatParseTest); #endif /* UNITTESTS */ } diff --git a/src/detect-http-uri.h b/src/detect-http-uri.h index cb327804ea0a..b55df07e3318 100644 --- a/src/detect-http-uri.h +++ b/src/detect-http-uri.h @@ -25,10 +25,7 @@ #define _DETECT_HTTP_URI_H /* prototypes */ +int DetectHttpUriSetup (DetectEngineCtx *, Signature *, char *); void DetectHttpUriRegister (void); -int DetectHttpUriSetup(DetectEngineCtx *de_ctx, Signature *s, char *str); -int DetectHttpUriDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, - SigMatch *sm, Flow *f, uint8_t flags, void *state); - #endif /* _DETECT_HTTP_URI_H */ diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index d2e01b35d3f4..5e993547136f 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -516,94 +516,6 @@ int DetectIsdataatTestParse06(void) return result; } -int DetectIsdataatTestParse07(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "uricontent:\"one\"; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -int DetectIsdataatTestParse08(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; http_uri; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - int DetectIsdataatTestParse09(void) { DetectEngineCtx *de_ctx = NULL; @@ -948,8 +860,6 @@ void DetectIsdataatRegisterTests(void) UtRegisterTest("DetectIsdataatTestParse04", DetectIsdataatTestParse04); UtRegisterTest("DetectIsdataatTestParse05", DetectIsdataatTestParse05); UtRegisterTest("DetectIsdataatTestParse06", DetectIsdataatTestParse06); - UtRegisterTest("DetectIsdataatTestParse07", DetectIsdataatTestParse07); - UtRegisterTest("DetectIsdataatTestParse08", DetectIsdataatTestParse08); UtRegisterTest("DetectIsdataatTestParse09", DetectIsdataatTestParse09); UtRegisterTest("DetectIsdataatTestParse10", DetectIsdataatTestParse10); UtRegisterTest("DetectIsdataatTestParse11", DetectIsdataatTestParse11); diff --git a/src/detect-lua.c b/src/detect-lua.c index 6a60482c3fc5..81d96684113a 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -996,9 +996,10 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, list); } else if (lua->flags & DATATYPE_HTTP_REQUEST_BODY) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCBDMATCH); - else if (lua->flags & DATATYPE_HTTP_URI) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); - else if (lua->flags & DATATYPE_HTTP_URI_RAW) + else if (lua->flags & DATATYPE_HTTP_URI) { + int list = DetectBufferTypeGetByName("http_uri"); + SigMatchAppendSMToList(s, sm, list); + } else if (lua->flags & DATATYPE_HTTP_URI_RAW) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); diff --git a/src/detect-parse.c b/src/detect-parse.c index 7b8670b325f5..f2ba0413fd1e 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -141,7 +141,6 @@ const char *DetectListToHumanString(int list) switch (list) { CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); - CASE_CODE_STRING(DETECT_SM_LIST_UMATCH, "http_uri"); CASE_CODE_STRING(DETECT_SM_LIST_HRUDMATCH, "http_raw_uri"); CASE_CODE_STRING(DETECT_SM_LIST_HCBDMATCH, "http_client_body"); CASE_CODE_STRING(DETECT_SM_LIST_HHDMATCH, "http_header"); @@ -183,7 +182,6 @@ const char *DetectListToString(int list) switch (list) { CASE_CODE(DETECT_SM_LIST_MATCH); CASE_CODE(DETECT_SM_LIST_PMATCH); - CASE_CODE(DETECT_SM_LIST_UMATCH); CASE_CODE(DETECT_SM_LIST_HRUDMATCH); CASE_CODE(DETECT_SM_LIST_HCBDMATCH); CASE_CODE(DETECT_SM_LIST_HHDMATCH); @@ -1430,9 +1428,8 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) continue; if (fd->flags & FLOW_PKT_TOCLIENT) { - /* check for uricontent + from_server/to_client */ - if (s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || + /* check for request + from_server/to_client */ + if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use uricontent " @@ -1580,8 +1577,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } - if (s->init_data->smlists_tail[DETECT_SM_LIST_UMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH] || + if (s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] || diff --git a/src/detect-pcre.c b/src/detect-pcre.c index c7477d8d9241..515ec7096af4 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -395,13 +395,15 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, /* buffer selection */ - case 'U': /* snort's option */ + case 'U': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'U' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_UMATCH); + int list = DetectBufferTypeGetByName("http_uri"); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } case 'V': if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'V' inconsistent with 'B'"); @@ -440,7 +442,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, case 'D': /* snort's option */ *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HRHDMATCH); break; - case 'M': /* snort's option */ + case 'M': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'M' inconsistent with 'B'"); goto error; @@ -448,6 +450,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, int list = DetectBufferTypeGetByName("http_method"); *sm_list = DetectPcreSetList(*sm_list, list); break; + } case 'C': /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'C' inconsistent with 'B'"); @@ -666,8 +669,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst if (DetectPcreParseCapture(regexstr, de_ctx, pd) < 0) goto error; - if (parsed_sm_list == DETECT_SM_LIST_UMATCH || - parsed_sm_list == DETECT_SM_LIST_HRUDMATCH || + if (parsed_sm_list == DETECT_SM_LIST_HRUDMATCH || parsed_sm_list == DETECT_SM_LIST_HCBDMATCH || parsed_sm_list == DETECT_SM_LIST_HHDMATCH || parsed_sm_list == DETECT_SM_LIST_HRHDMATCH || @@ -707,7 +709,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst sm_list = parsed_sm_list; break; - case DETECT_SM_LIST_UMATCH: case DETECT_SM_LIST_HRUDMATCH: case DETECT_SM_LIST_HHDMATCH: case DETECT_SM_LIST_HRHDMATCH: diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index 4e66237129c5..719340e75387 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -58,12 +58,10 @@ /* prototypes */ static int DetectUricontentSetup (DetectEngineCtx *, Signature *, char *); -void HttpUriRegisterTests(void); +static void DetectUricontentRegisterTests(void); +static void DetectUricontentFree(void *); -int DetectAppLayerUricontentMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t , void *, - Signature *, SigMatch *); -void DetectUricontentFree(void *); +static int g_http_uri_buffer_id = 0; /** * \brief Registration function for uricontent: keyword @@ -75,9 +73,11 @@ void DetectUricontentRegister (void) sigmatch_table[DETECT_URICONTENT].Match = NULL; sigmatch_table[DETECT_URICONTENT].Setup = DetectUricontentSetup; sigmatch_table[DETECT_URICONTENT].Free = DetectUricontentFree; - sigmatch_table[DETECT_URICONTENT].RegisterTests = HttpUriRegisterTests; + sigmatch_table[DETECT_URICONTENT].RegisterTests = DetectUricontentRegisterTests; sigmatch_table[DETECT_URICONTENT].flags |= SIGMATCH_PAYLOAD; + + g_http_uri_buffer_id = DetectBufferTypeRegister("http_uri"); } /** @@ -194,6 +194,7 @@ int DetectUricontentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentst #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** \test Test case where path traversal has been sent as a path string in the @@ -499,8 +500,8 @@ int DetectUriSigTest01(void) "\" Test uricontent\"; content:\"me\"; uricontent:\"me\"; sid:1;)"); FAIL_IF_NULL(s); - BUG_ON(s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL); - FAIL_IF_NOT(de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]->type == DETECT_CONTENT); + BUG_ON(s->sm_lists[g_http_uri_buffer_id] == NULL); + FAIL_IF_NOT(de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]->type == DETECT_CONTENT); DetectEngineCtxFree(de_ctx); PASS; @@ -777,7 +778,7 @@ static int DetectUriSigTest04(void) "\" Test uricontent\"; " "uricontent:\"foo\"; sid:1;)"); if (s == NULL || - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { @@ -789,7 +790,7 @@ static int DetectUriSigTest04(void) "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";sid:1;)"); if (s == NULL || - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { @@ -802,7 +803,7 @@ static int DetectUriSigTest04(void) "uricontent:\"foo\"; content:\"bar\";" " depth:10; offset: 5; sid:1;)"); if (s == NULL || - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || @@ -817,10 +818,10 @@ static int DetectUriSigTest04(void) "content:\"foo\"; uricontent:\"bar\";" " depth:10; offset: 5; sid:1;)"); if (s == NULL || - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || - ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_UMATCH]->ctx)->depth != 15 || - ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_UMATCH]->ctx)->offset != 5 || + ((DetectContentData *)s->sm_lists[g_http_uri_buffer_id]->ctx)->depth != 15 || + ((DetectContentData *)s->sm_lists[g_http_uri_buffer_id]->ctx)->offset != 5 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 4 failed to parse: "); @@ -852,7 +853,7 @@ static int DetectUriSigTest04(void) "\"two_contents\"; within:30; sid:1;)"); if (s == NULL) { goto end; - } else if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + } else if (s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || @@ -871,15 +872,15 @@ static int DetectUriSigTest04(void) "\"two_uricontents\"; within:30; sid:1;)"); if (s == NULL) { goto end; - } else if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + } else if (s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || - ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->within != 30 || + ((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx)->within != 30 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 8 failed to parse: "); - DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx); + DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx); goto end; } @@ -891,7 +892,7 @@ static int DetectUriSigTest04(void) if (s == NULL) { goto end; } else if ( - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || @@ -911,15 +912,15 @@ static int DetectUriSigTest04(void) if (s == NULL) { goto end; } else if ( - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || - ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->distance != 30 || + ((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx)->distance != 30 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 10 failed to parse: "); - DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx); + DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx); goto end; } @@ -935,21 +936,21 @@ static int DetectUriSigTest04(void) goto end; } - if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { - printf("umatch %p or pmatch %p: ", s->sm_lists[DETECT_SM_LIST_UMATCH], s->sm_lists[DETECT_SM_LIST_PMATCH]); + if (s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("umatch %p or pmatch %p: ", s->sm_lists[g_http_uri_buffer_id], s->sm_lists[DETECT_SM_LIST_PMATCH]); goto end; } if ( ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || - ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->distance != 30 || - ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->within != 60 || + ((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx)->distance != 30 || + ((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx)->within != 60 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx)->distance != 45 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx)->within != 70 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 10 failed to parse, content not setup properly: "); DetectContentPrint((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx); - DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx); + DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx); DetectContentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx); goto end; } @@ -1490,12 +1491,12 @@ int DetectUriSigTest12(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx == NULL) { + if (s->sm_lists_tail[g_http_uri_buffer_id] == NULL || s->sm_lists_tail[g_http_uri_buffer_id]->ctx == NULL) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - ud = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + ud = (DetectContentData *)s->sm_lists_tail[g_http_uri_buffer_id]->ctx; result = (strncmp("boo", (char *)ud->content, ud->content_len) == 0); end: @@ -1855,9 +1856,34 @@ int DetectUriContentParseTest24(void) return result; } +static int DetectUricontentIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "uricontent:\"one\"; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_uri_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ -void HttpUriRegisterTests(void) +static void DetectUricontentRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("HTTPUriTest01", HTTPUriTest01); @@ -1890,5 +1916,8 @@ void HttpUriRegisterTests(void) UtRegisterTest("DetectUriContentParseTest22", DetectUriContentParseTest22); UtRegisterTest("DetectUriContentParseTest23", DetectUriContentParseTest23); UtRegisterTest("DetectUriContentParseTest24", DetectUriContentParseTest24); + + UtRegisterTest("DetectUricontentIsdataatParseTest", + DetectUricontentIsdataatParseTest); #endif /* UNITTESTS */ } diff --git a/src/detect-urilen.c b/src/detect-urilen.c index 860bb9291745..c853efc31597 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -32,6 +32,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine.h" #include "detect-engine-state.h" #include "detect-urilen.h" @@ -53,6 +54,8 @@ static int DetectUrilenSetup (DetectEngineCtx *, Signature *, char *); void DetectUrilenFree (void *); void DetectUrilenRegisterTests (void); +static int g_http_uri_buffer_id = 0; + /** * \brief Registration function for urilen: keyword */ @@ -70,6 +73,8 @@ void DetectUrilenRegister(void) sigmatch_table[DETECT_AL_URILEN].flags |= SIGMATCH_PAYLOAD; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + g_http_uri_buffer_id = DetectBufferTypeRegister("http_uri"); } /** @@ -260,7 +265,7 @@ static int DetectUrilenSetup (DetectEngineCtx *de_ctx, Signature *s, char *urile if (urilend->raw_buffer) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); else - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); + SigMatchAppendSMToList(s, sm, g_http_uri_buffer_id); /* Flagged the signature as to inspect the app layer data */ s->flags |= SIG_FLAG_APPLAYER; diff --git a/src/detect.c b/src/detect.c index 321d21af1702..b4247cc4df80 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1912,9 +1912,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; @@ -2017,9 +2014,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; @@ -2149,7 +2143,6 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) } if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL || @@ -2313,11 +2306,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires dce state"); } - if (s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http state"); - } - if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); diff --git a/src/detect.h b/src/detect.h index 976d75b20d21..bb51b6345a10 100644 --- a/src/detect.h +++ b/src/detect.h @@ -115,10 +115,8 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_BUILTIN_MAX, - /* list for http_uri keyword and the ones relative to it */ - DETECT_SM_LIST_UMATCH = DETECT_SM_LIST_BUILTIN_MAX, /* list for http_raw_uri keyword and the ones relative to it */ - DETECT_SM_LIST_HRUDMATCH, + DETECT_SM_LIST_HRUDMATCH = DETECT_SM_LIST_BUILTIN_MAX, /* list for http_client_body keyword and the ones relative to it */ DETECT_SM_LIST_HCBDMATCH, /* list for http_header keyword and the ones relative to it */ From 9262fa3dcfb54a0c47b69bcea642a3daab7635ff Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 8 Dec 2016 10:33:15 +0100 Subject: [PATCH 2371/2553] http_response_line: dynamic buffer --- src/detect-engine.c | 2 -- src/detect-http-response-line.c | 32 ++++++++++++++++++++++---------- src/detect-parse.c | 2 -- src/detect.h | 2 -- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index c9244e904fd3..db0e9b1a2193 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2818,8 +2818,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http cookie"; case DETECT_SM_LIST_HUADMATCH: return "http user-agent"; - case DETECT_SM_LIST_HTTP_RESLINEMATCH: - return "http response line"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index b3a369eeb4c3..c798e35bb445 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -60,14 +60,15 @@ #include "stream-tcp.h" #include "detect-http-response-line.h" -int DetectHttpResponseLineSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpResponseLineRegisterTests(void); -void DetectHttpResponseLineFree(void *); +static int DetectHttpResponseLineSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpResponseLineRegisterTests(void); static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); static int DetectEngineInspectHttpResponseLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); +static void DetectHttpResponseLineSetupCallback(Signature *s); +static int g_http_response_line_id = 0; /** * \brief Registers the keyword handlers for the "http_response_line" keyword. @@ -85,15 +86,20 @@ void DetectHttpResponseLineRegister(void) sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].flags |= SIGMATCH_PAYLOAD ; - DetectMpmAppLayerRegister("http_response_line", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HTTP_RESLINEMATCH, 2, + DetectAppLayerMpmRegister("http_response_line", SIG_FLAG_TOCLIENT, 2, PrefilterTxHttpResponseLineRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HTTP_RESLINEMATCH, + DetectAppLayerInspectEngineRegister2("http_response_line", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpResponseLine); - return; + DetectBufferTypeSetDescriptionByName("http_response_line", + "http response line"); + + DetectBufferTypeRegisterSetupCallback("http_response_line", + DetectHttpResponseLineSetupCallback); + + g_http_response_line_id = DetectBufferTypeGetByName("http_response_line"); } /** @@ -109,13 +115,19 @@ void DetectHttpResponseLineRegister(void) * \retval 0 On success * \retval -1 On failure */ -int DetectHttpResponseLineSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +static int DetectHttpResponseLineSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { - s->init_data->list = DETECT_SM_LIST_HTTP_RESLINEMATCH; + s->init_data->list = g_http_response_line_id; s->alproto = ALPROTO_HTTP; return 0; } +static void DetectHttpResponseLineSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + /** \brief HTTP response line Mpm prefilter callback * * \param det_ctx detection engine thread ctx diff --git a/src/detect-parse.c b/src/detect-parse.c index f2ba0413fd1e..689c21bfcd89 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -151,7 +151,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HRHHDMATCH, "http_raw_host"); CASE_CODE_STRING(DETECT_SM_LIST_HCDMATCH, "http_cookie"); CASE_CODE_STRING(DETECT_SM_LIST_HUADMATCH, "http_user_agent"); - CASE_CODE_STRING(DETECT_SM_LIST_HTTP_RESLINEMATCH, "http_response_line"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -192,7 +191,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HRHHDMATCH); CASE_CODE(DETECT_SM_LIST_HCDMATCH); CASE_CODE(DETECT_SM_LIST_HUADMATCH); - CASE_CODE(DETECT_SM_LIST_HTTP_RESLINEMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); diff --git a/src/detect.h b/src/detect.h index bb51b6345a10..7a47d367cef3 100644 --- a/src/detect.h +++ b/src/detect.h @@ -135,8 +135,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_HCDMATCH, /* list for http_user_agent keyword and the ones relative to it */ DETECT_SM_LIST_HUADMATCH, - /* list for http_response_line keyword and the ones relative to it */ - DETECT_SM_LIST_HTTP_RESLINEMATCH, /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, From 54604c7bf29cad212283157250bdd5e4723d492d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 8 Dec 2016 11:05:51 +0100 Subject: [PATCH 2372/2553] http_user_agent: dynamic buffer --- src/detect-engine-analyzer.c | 7 +- src/detect-engine.c | 2 - src/detect-fast-pattern.c | 44 ++++++----- src/detect-http-ua.c | 143 +++++++++++++++++++---------------- src/detect-lua.c | 7 +- src/detect-parse.c | 6 +- src/detect-pcre.c | 10 +-- src/detect.c | 12 --- src/detect.h | 2 - 9 files changed, 113 insertions(+), 120 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 19f153b03fad..af9b049c9a34 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -126,8 +126,6 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "http stat code content\n"); else if (list_type == DETECT_SM_LIST_HSMDMATCH) fprintf(fp_engine_analysis_FD, "http stat msg content\n"); - else if (list_type == DETECT_SM_LIST_HUADMATCH) - fprintf(fp_engine_analysis_FD, "http user agent content\n"); else { const char *desc = DetectBufferTypeGetDescriptionById(list_type); const char *name = DetectBufferTypeGetNameById(list_type); @@ -476,8 +474,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "http stat code content"); else if (list_type == DETECT_SM_LIST_HSMDMATCH) fprintf(rule_engine_analysis_FD, "http stat msg content"); - else if (list_type == DETECT_SM_LIST_HUADMATCH) - fprintf(rule_engine_analysis_FD, "http user agent content"); else if (list_type == DETECT_SM_LIST_DNSQUERYNAME_MATCH) fprintf(rule_engine_analysis_FD, "dns query name content"); else if (list_type == DETECT_SM_LIST_TLSSNI_MATCH) @@ -580,6 +576,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) const int filedata_id = DetectBufferTypeGetByName("file_data"); const int httpmethod_id = DetectBufferTypeGetByName("http_method"); const int httpuri_id = DetectBufferTypeGetByName("http_uri"); + const int httpuseragent_id = DetectBufferTypeGetByName("http_user_agent"); if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; @@ -653,7 +650,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_stat_code_buf += 1; } - else if (list_id == DETECT_SM_LIST_HUADMATCH) { + else if (list_id == httpuseragent_id) { rule_pcre_http += 1; norm_http_buf += 1; http_ua_buf += 1; diff --git a/src/detect-engine.c b/src/detect-engine.c index db0e9b1a2193..113ad1f69229 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2816,8 +2816,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http raw host header"; case DETECT_SM_LIST_HCDMATCH: return "http cookie"; - case DETECT_SM_LIST_HUADMATCH: - return "http user-agent"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 239c0bc8b13e..42589e13b324 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -324,6 +324,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a static int g_file_data_buffer_id = 0; static int g_http_method_buffer_id = 0; static int g_http_uri_buffer_id = 0; +static int g_http_ua_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -15238,7 +15239,7 @@ int DetectFastPatternTest548(void) "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15277,7 +15278,7 @@ int DetectFastPatternTest549(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_ua_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -15314,7 +15315,7 @@ int DetectFastPatternTest550(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_ua_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -15345,7 +15346,7 @@ int DetectFastPatternTest551(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_ua_buffer_id]; if (sm == NULL) { goto end; } @@ -15381,7 +15382,7 @@ int DetectFastPatternTest552(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_ua_buffer_id]; if (sm == NULL) { goto end; } @@ -15626,7 +15627,7 @@ int DetectFastPatternTest562(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15658,7 +15659,7 @@ int DetectFastPatternTest563(void) "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15690,7 +15691,7 @@ int DetectFastPatternTest564(void) "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15722,7 +15723,7 @@ int DetectFastPatternTest565(void) "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15753,7 +15754,7 @@ int DetectFastPatternTest566(void) "content:\"two\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15878,7 +15879,7 @@ int DetectFastPatternTest571(void) "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15910,7 +15911,7 @@ int DetectFastPatternTest572(void) "content:\"three\"; http_user_agent; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15942,7 +15943,7 @@ int DetectFastPatternTest573(void) "content:\"three\"; http_user_agent; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15974,7 +15975,7 @@ int DetectFastPatternTest574(void) "content:\"three\"; http_user_agent; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16006,7 +16007,7 @@ int DetectFastPatternTest575(void) "content:\"three\"; http_user_agent; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16038,7 +16039,7 @@ int DetectFastPatternTest576(void) "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16070,7 +16071,7 @@ int DetectFastPatternTest577(void) "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16102,7 +16103,7 @@ int DetectFastPatternTest578(void) "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16134,7 +16135,7 @@ int DetectFastPatternTest579(void) "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16241,7 +16242,7 @@ int DetectFastPatternTest583(void) "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -16370,7 +16371,7 @@ int DetectFastPatternTest588(void) "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18827,6 +18828,7 @@ void DetectFastPatternRegisterTests(void) g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); g_http_method_buffer_id = DetectBufferTypeGetByName("http_method"); g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); + g_http_ua_buffer_id = DetectBufferTypeGetByName("http_user_agent"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index c500387cc127..625d28755015 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -59,9 +59,11 @@ #include "detect-http-ua.h" #include "detect-engine-hua.h" -int DetectHttpUASetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpUARegisterTests(void); -void DetectHttpUAFree(void *); +static int DetectHttpUASetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpUARegisterTests(void); +static void DetectHttpUAFree(void *); +static void DetectHttpUASetupCallback(Signature *); +static int g_http_ua_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_user_agent" keyword. @@ -80,15 +82,20 @@ void DetectHttpUARegister(void) sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_PAYLOAD ; - DetectMpmAppLayerRegister("http_user_agent", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HUADMATCH, 2, + DetectAppLayerMpmRegister("http_user_agent", SIG_FLAG_TOSERVER, 2, PrefilterTxUARegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HUADMATCH, + DetectAppLayerInspectEngineRegister2("http_user_agent", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpUA); - return; + DetectBufferTypeSetDescriptionByName("http_user_agent", + "http user agent"); + + DetectBufferTypeRegisterSetupCallback("http_user_agent", + DetectHttpUASetupCallback); + + g_http_ua_buffer_id = DetectBufferTypeGetByName("http_user_agent"); } /** @@ -108,11 +115,17 @@ int DetectHttpUASetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_USER_AGENT, - DETECT_SM_LIST_HUADMATCH, + g_http_ua_buffer_id, ALPROTO_HTTP, NULL); } +static void DetectHttpUASetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + /** * \brief The function to free the http_user_agent data. * @@ -1443,15 +1456,15 @@ int DetectHttpUATest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1498,15 +1511,15 @@ int DetectHttpUATest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1552,15 +1565,15 @@ int DetectHttpUATest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1607,15 +1620,15 @@ int DetectHttpUATest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1663,15 +1676,15 @@ int DetectHttpUATest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1746,15 +1759,15 @@ int DetectHttpUATest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1801,13 +1814,13 @@ int DetectHttpUATest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_DISTANCE || @@ -1845,13 +1858,13 @@ int DetectHttpUATest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_WITHIN || @@ -1961,21 +1974,21 @@ int DetectHttpUATest34(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || huad2->flags != DETECT_CONTENT_WITHIN || memcmp(huad2->content, "two", huad2->content_len) != 0) { @@ -2012,21 +2025,21 @@ int DetectHttpUATest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "two", huad1->content_len) != 0) { @@ -2063,21 +2076,21 @@ int DetectHttpUATest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || huad2->flags != DETECT_CONTENT_DISTANCE || memcmp(huad2->content, "two", huad2->content_len) != 0) { diff --git a/src/detect-lua.c b/src/detect-lua.c index 81d96684113a..886dfd7f6134 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1003,9 +1003,10 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); - else if (lua->flags & DATATYPE_HTTP_REQUEST_UA) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HUADMATCH); - else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) + else if (lua->flags & DATATYPE_HTTP_REQUEST_UA) { + int list = DetectBufferTypeGetByName("http_user_agent"); + SigMatchAppendSMToList(s, sm, list); + } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HHDMATCH); else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRHDMATCH); diff --git a/src/detect-parse.c b/src/detect-parse.c index 689c21bfcd89..11735db18c3c 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -150,7 +150,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HHHDMATCH, "http_host"); CASE_CODE_STRING(DETECT_SM_LIST_HRHHDMATCH, "http_raw_host"); CASE_CODE_STRING(DETECT_SM_LIST_HCDMATCH, "http_cookie"); - CASE_CODE_STRING(DETECT_SM_LIST_HUADMATCH, "http_user_agent"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -190,7 +189,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HHHDMATCH); CASE_CODE(DETECT_SM_LIST_HRHHDMATCH); CASE_CODE(DETECT_SM_LIST_HCDMATCH); - CASE_CODE(DETECT_SM_LIST_HUADMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); @@ -1428,8 +1426,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (fd->flags & FLOW_PKT_TOCLIENT) { /* check for request + from_server/to_client */ if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) { + s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use uricontent " "/http_uri , raw_uri, http_client_body, " "http_method, http_user_agent keywords " @@ -1582,7 +1579,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HUADMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]) { diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 515ec7096af4..302983dc523e 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -404,13 +404,15 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, *sm_list = DetectPcreSetList(*sm_list, list); break; } - case 'V': + case 'V': { if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'V' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HUADMATCH); + int list = DetectBufferTypeGetByName("http_user_agent"); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } case 'W': if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'W' inconsistent with 'B'"); @@ -678,8 +680,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst parsed_sm_list == DETECT_SM_LIST_HHHDMATCH || parsed_sm_list == DETECT_SM_LIST_HRHHDMATCH || // parsed_sm_list == DETECT_SM_LIST_HMDMATCH || - parsed_sm_list == DETECT_SM_LIST_HCDMATCH || - parsed_sm_list == DETECT_SM_LIST_HUADMATCH) + parsed_sm_list == DETECT_SM_LIST_HCDMATCH) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " @@ -717,7 +718,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_SM_LIST_HSMDMATCH: case DETECT_SM_LIST_HSCDMATCH: case DETECT_SM_LIST_HCDMATCH: - case DETECT_SM_LIST_HUADMATCH: s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; sm_list = parsed_sm_list; diff --git a/src/detect.c b/src/detect.c index b4247cc4df80..1a53d399c4a0 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1933,9 +1933,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) return 0; @@ -2035,9 +2032,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) return 0; @@ -2151,7 +2145,6 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { @@ -2341,11 +2334,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http app state"); } - if (s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); diff --git a/src/detect.h b/src/detect.h index 7a47d367cef3..e9190b539ebb 100644 --- a/src/detect.h +++ b/src/detect.h @@ -133,8 +133,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_HRHHDMATCH, /* 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, From 67b7d9734e1c17eecaebd71ca3efc6b262bd1b95 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 8 Dec 2016 11:40:08 +0100 Subject: [PATCH 2373/2553] http_cookie: dynamic buffer --- src/detect-engine-analyzer.c | 11 ++---- src/detect-engine.c | 2 - src/detect-fast-pattern.c | 44 +++++++++++----------- src/detect-http-cookie.c | 71 +++++++++++++++++++++++++++++------- src/detect-isdataat.c | 45 ----------------------- src/detect-lua.c | 11 +++--- src/detect-parse.c | 3 -- src/detect-pcre.c | 11 +++--- src/detect.c | 12 ------ src/detect.h | 2 - 10 files changed, 95 insertions(+), 117 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index af9b049c9a34..5f1320589e02 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -118,8 +118,6 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "http header content\n"); else if (list_type == DETECT_SM_LIST_HRHDMATCH) fprintf(fp_engine_analysis_FD, "http raw header content\n"); - else if (list_type == DETECT_SM_LIST_HCDMATCH) - fprintf(fp_engine_analysis_FD, "http cookie content\n"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(fp_engine_analysis_FD, "http client body content\n"); else if (list_type == DETECT_SM_LIST_HSCDMATCH) @@ -466,8 +464,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "http header content"); else if (list_type == DETECT_SM_LIST_HRHDMATCH) fprintf(rule_engine_analysis_FD, "http raw header content"); - else if (list_type == DETECT_SM_LIST_HCDMATCH) - fprintf(rule_engine_analysis_FD, "http cookie content"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(rule_engine_analysis_FD, "http client body content"); else if (list_type == DETECT_SM_LIST_HSCDMATCH) @@ -577,6 +573,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) const int httpmethod_id = DetectBufferTypeGetByName("http_method"); const int httpuri_id = DetectBufferTypeGetByName("http_uri"); const int httpuseragent_id = DetectBufferTypeGetByName("http_user_agent"); + const int httpcookie_id = DetectBufferTypeGetByName("http_cookie"); if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; @@ -615,7 +612,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) norm_http_buf += 1; http_header_buf += 1; } - else if (list_id == DETECT_SM_LIST_HCDMATCH) { + else if (list_id == httpcookie_id) { rule_pcre_http += 1; norm_http_buf += 1; http_cookie_buf += 1; @@ -663,7 +660,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) if (list_id == httpuri_id || list_id == DETECT_SM_LIST_HHDMATCH - || list_id == DETECT_SM_LIST_HCDMATCH) { + || list_id == httpcookie_id) { rule_content_http += 1; norm_http_buf += 1; DetectContentData *cd = (DetectContentData *)sm->ctx; @@ -677,7 +674,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) else if (list_id == DETECT_SM_LIST_HHDMATCH) { http_header_buf += 1; } - else if (list_id == DETECT_SM_LIST_HCDMATCH) { + else if (list_id == httpcookie_id) { http_cookie_buf += 1; } } diff --git a/src/detect-engine.c b/src/detect-engine.c index 113ad1f69229..76fe02137df3 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2814,8 +2814,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http host"; case DETECT_SM_LIST_HRHHDMATCH: return "http raw host header"; - case DETECT_SM_LIST_HCDMATCH: - return "http cookie"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 42589e13b324..2d8e701b3bc9 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -325,6 +325,7 @@ static int g_file_data_buffer_id = 0; static int g_http_method_buffer_id = 0; static int g_http_uri_buffer_id = 0; static int g_http_ua_buffer_id = 0; +static int g_http_cookie_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -8277,7 +8278,7 @@ int DetectFastPatternTest302(void) "content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8315,7 +8316,7 @@ int DetectFastPatternTest303(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_cookie_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -8352,7 +8353,7 @@ int DetectFastPatternTest304(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_cookie_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -8384,7 +8385,7 @@ int DetectFastPatternTest305(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_cookie_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -8418,7 +8419,7 @@ int DetectFastPatternTest306(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_cookie_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8648,7 +8649,7 @@ int DetectFastPatternTest316(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8678,7 +8679,7 @@ int DetectFastPatternTest317(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; within:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8708,7 +8709,7 @@ int DetectFastPatternTest318(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; offset:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8738,7 +8739,7 @@ int DetectFastPatternTest319(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; depth:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8768,7 +8769,7 @@ int DetectFastPatternTest320(void) "(content:!\"one\"; fast_pattern; http_cookie; content:\"two\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8887,7 +8888,7 @@ int DetectFastPatternTest325(void) "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8917,7 +8918,7 @@ int DetectFastPatternTest326(void) "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8947,7 +8948,7 @@ int DetectFastPatternTest327(void) "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8977,7 +8978,7 @@ int DetectFastPatternTest328(void) "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9007,7 +9008,7 @@ int DetectFastPatternTest329(void) "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9037,7 +9038,7 @@ int DetectFastPatternTest330(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9067,7 +9068,7 @@ int DetectFastPatternTest331(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9097,7 +9098,7 @@ int DetectFastPatternTest332(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9127,7 +9128,7 @@ int DetectFastPatternTest333(void) "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9226,7 +9227,7 @@ int DetectFastPatternTest337(void) "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -9345,7 +9346,7 @@ int DetectFastPatternTest342(void) "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18829,6 +18830,7 @@ void DetectFastPatternRegisterTests(void) g_http_method_buffer_id = DetectBufferTypeGetByName("http_method"); g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); g_http_ua_buffer_id = DetectBufferTypeGetByName("http_user_agent"); + g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 2bb0e6d46045..56f38e7bf4b3 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -62,8 +62,10 @@ #include "stream-tcp.h" static int DetectHttpCookieSetup (DetectEngineCtx *, Signature *, char *); -void DetectHttpCookieRegisterTests(void); -void DetectHttpCookieFree(void *); +static void DetectHttpCookieRegisterTests(void); +static void DetectHttpCookieFree(void *); +static void DetectHttpCookieSetupCallback(Signature *s); +static int g_http_cookie_buffer_id = 0; /** * \brief Registration function for keyword: http_cookie @@ -82,19 +84,25 @@ void DetectHttpCookieRegister(void) sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("http_cookie", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HCDMATCH, 2, + DetectAppLayerMpmRegister("http_cookie", SIG_FLAG_TOSERVER, 2, PrefilterTxRequestCookieRegister); - DetectMpmAppLayerRegister("http_cookie", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HCDMATCH, 2, + DetectAppLayerMpmRegister("http_cookie", SIG_FLAG_TOCLIENT, 2, PrefilterTxResponseCookieRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HCDMATCH, + DetectAppLayerInspectEngineRegister2("http_cookie", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpCookie); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HCDMATCH, + DetectAppLayerInspectEngineRegister2("http_cookie", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpCookie); + + DetectBufferTypeSetDescriptionByName("http_cookie", + "http cookie header"); + + DetectBufferTypeRegisterSetupCallback("http_cookie", + DetectHttpCookieSetupCallback); + + g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie"); } /** @@ -127,15 +135,23 @@ static int DetectHttpCookieSetup(DetectEngineCtx *de_ctx, Signature *s, char *st { return DetectEngineContentModifierBufferSetup(de_ctx, s, str, DETECT_AL_HTTP_COOKIE, - DETECT_SM_LIST_HCDMATCH, + g_http_cookie_buffer_id, ALPROTO_HTTP, NULL); } +static void DetectHttpCookieSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + + /******************************** UNITESTS **********************************/ #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" static int g_http_uri_buffer_id = 0; @@ -213,7 +229,7 @@ static int DetectHttpCookieTest03(void) } result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_cookie_buffer_id]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; @@ -306,9 +322,9 @@ static int DetectHttpCookieTest06(void) Signature *s = de_ctx->sig_list; - BUG_ON(s->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL); + BUG_ON(s->sm_lists[g_http_cookie_buffer_id] == NULL); - if (s->sm_lists[DETECT_SM_LIST_HCDMATCH]->type != DETECT_CONTENT) + if (s->sm_lists[g_http_cookie_buffer_id]->type != DETECT_CONTENT) goto end; if (s->sm_lists[g_http_uri_buffer_id] == NULL) { @@ -1273,6 +1289,31 @@ static int DetectHttpCookieSigTest09(void) return result; } +static int DetectHttpCookieIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "content:\"one\"; http_cookie; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_cookie_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ /** @@ -1298,6 +1339,8 @@ void DetectHttpCookieRegisterTests (void) UtRegisterTest("DetectHttpCookieSigTest07", DetectHttpCookieSigTest07); UtRegisterTest("DetectHttpCookieSigTest08", DetectHttpCookieSigTest08); UtRegisterTest("DetectHttpCookieSigTest09", DetectHttpCookieSigTest09); + UtRegisterTest("DetectHttpCookieIsdataatParseTest", + DetectHttpCookieIsdataatParseTest); #endif /* UNITTESTS */ } diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 5e993547136f..3b9e087efbac 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -648,50 +648,6 @@ int DetectIsdataatTestParse11(void) return result; } -int DetectIsdataatTestParse13(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; http_cookie; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - /** * \test dns_query with isdataat relative to it */ @@ -863,7 +819,6 @@ void DetectIsdataatRegisterTests(void) UtRegisterTest("DetectIsdataatTestParse09", DetectIsdataatTestParse09); UtRegisterTest("DetectIsdataatTestParse10", DetectIsdataatTestParse10); UtRegisterTest("DetectIsdataatTestParse11", DetectIsdataatTestParse11); - UtRegisterTest("DetectIsdataatTestParse13", DetectIsdataatTestParse13); UtRegisterTest("DetectIsdataatTestParse16", DetectIsdataatTestParse16); UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01); diff --git a/src/detect-lua.c b/src/detect-lua.c index 886dfd7f6134..e349d66f6e96 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1001,17 +1001,18 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, list); } else if (lua->flags & DATATYPE_HTTP_URI_RAW) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); - else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); - else if (lua->flags & DATATYPE_HTTP_REQUEST_UA) { + else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE || + lua->flags & DATATYPE_HTTP_RESPONSE_COOKIE) + { + int list = DetectBufferTypeGetByName("http_cookie"); + SigMatchAppendSMToList(s, sm, list); + } else if (lua->flags & DATATYPE_HTTP_REQUEST_UA) { int list = DetectBufferTypeGetByName("http_user_agent"); SigMatchAppendSMToList(s, sm, list); } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HHDMATCH); else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRHDMATCH); - else if (lua->flags & DATATYPE_HTTP_RESPONSE_COOKIE) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); else { int list = DetectBufferTypeGetByName("http_request_line"); SigMatchAppendSMToList(s, sm, list); diff --git a/src/detect-parse.c b/src/detect-parse.c index 11735db18c3c..4dd800b124be 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -149,7 +149,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HSCDMATCH, "http_stat_code"); CASE_CODE_STRING(DETECT_SM_LIST_HHHDMATCH, "http_host"); CASE_CODE_STRING(DETECT_SM_LIST_HRHHDMATCH, "http_raw_host"); - CASE_CODE_STRING(DETECT_SM_LIST_HCDMATCH, "http_cookie"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -188,7 +187,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HSCDMATCH); CASE_CODE(DETECT_SM_LIST_HHHDMATCH); CASE_CODE(DETECT_SM_LIST_HRHHDMATCH); - CASE_CODE(DETECT_SM_LIST_HCDMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); @@ -1578,7 +1576,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HCDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]) { diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 302983dc523e..13164d25decf 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -453,13 +453,15 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, *sm_list = DetectPcreSetList(*sm_list, list); break; } - case 'C': /* snort's option */ + case 'C': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'C' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HCDMATCH); + int list = DetectBufferTypeGetByName("http_cookie"); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } case 'P': /* snort's option (http request body inspection) */ *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HCBDMATCH); @@ -678,9 +680,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst parsed_sm_list == DETECT_SM_LIST_HSMDMATCH || parsed_sm_list == DETECT_SM_LIST_HSCDMATCH || parsed_sm_list == DETECT_SM_LIST_HHHDMATCH || - parsed_sm_list == DETECT_SM_LIST_HRHHDMATCH || -// parsed_sm_list == DETECT_SM_LIST_HMDMATCH || - parsed_sm_list == DETECT_SM_LIST_HCDMATCH) + parsed_sm_list == DETECT_SM_LIST_HRHHDMATCH) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " @@ -717,7 +717,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_SM_LIST_HRHHDMATCH: case DETECT_SM_LIST_HSMDMATCH: case DETECT_SM_LIST_HSCDMATCH: - case DETECT_SM_LIST_HCDMATCH: s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; sm_list = parsed_sm_list; diff --git a/src/detect.c b/src/detect.c index 1a53d399c4a0..1846fe11494c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1921,9 +1921,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; @@ -2020,9 +2017,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; @@ -2141,7 +2135,6 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || @@ -2314,11 +2307,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http app state"); } - if (s->init_data->smlists[DETECT_SM_LIST_HCDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); diff --git a/src/detect.h b/src/detect.h index e9190b539ebb..4683aee0f99e 100644 --- a/src/detect.h +++ b/src/detect.h @@ -131,8 +131,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_HHHDMATCH, /* list for http_raw_host keyword and the ones relative to it */ DETECT_SM_LIST_HRHHDMATCH, - /* list for http_cookie keyword and the ones relative to it */ - DETECT_SM_LIST_HCDMATCH, /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, From 296c275e23a6110216178cba6a67057a495a9aca Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 9 Dec 2016 12:07:03 +0100 Subject: [PATCH 2374/2553] http_host: dynamic buffer --- src/detect-engine.c | 2 - src/detect-fast-pattern.c | 44 ++++---- src/detect-http-hh.c | 207 ++++++++++++++++++++++++-------------- src/detect-parse.c | 33 ------ src/detect-pcre.c | 12 ++- src/detect.c | 12 --- src/detect.h | 2 - 7 files changed, 162 insertions(+), 150 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 76fe02137df3..3870cd165044 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2810,8 +2810,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http stat msg"; case DETECT_SM_LIST_HSCDMATCH: return "http stat code"; - case DETECT_SM_LIST_HHHDMATCH: - return "http host"; case DETECT_SM_LIST_HRHHDMATCH: return "http raw host header"; case DETECT_SM_LIST_APP_EVENT: diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 2d8e701b3bc9..2cb1d8b39d2a 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -326,6 +326,7 @@ static int g_http_method_buffer_id = 0; static int g_http_uri_buffer_id = 0; static int g_http_ua_buffer_id = 0; static int g_http_cookie_buffer_id = 0; +static int g_http_host_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -16410,7 +16411,7 @@ int DetectFastPatternTest589(void) "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -16448,7 +16449,7 @@ int DetectFastPatternTest590(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_host_buffer_id]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { @@ -16485,7 +16486,7 @@ int DetectFastPatternTest591(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_host_buffer_id]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { @@ -16516,7 +16517,7 @@ int DetectFastPatternTest592(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_host_buffer_id]; if (sm == NULL) { goto end; } @@ -16552,7 +16553,7 @@ int DetectFastPatternTest593(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_host_buffer_id]; if (sm == NULL) { goto end; } @@ -16797,7 +16798,7 @@ int DetectFastPatternTest603(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16829,7 +16830,7 @@ int DetectFastPatternTest604(void) "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16861,7 +16862,7 @@ int DetectFastPatternTest605(void) "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16893,7 +16894,7 @@ int DetectFastPatternTest606(void) "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16924,7 +16925,7 @@ int DetectFastPatternTest607(void) "content:\"two\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -17049,7 +17050,7 @@ int DetectFastPatternTest612(void) "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17081,7 +17082,7 @@ int DetectFastPatternTest613(void) "content:\"three\"; http_host; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17113,7 +17114,7 @@ int DetectFastPatternTest614(void) "content:\"three\"; http_host; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17145,7 +17146,7 @@ int DetectFastPatternTest615(void) "content:\"three\"; http_host; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17177,7 +17178,7 @@ int DetectFastPatternTest616(void) "content:\"three\"; http_host; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17209,7 +17210,7 @@ int DetectFastPatternTest617(void) "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17241,7 +17242,7 @@ int DetectFastPatternTest618(void) "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17273,7 +17274,7 @@ int DetectFastPatternTest619(void) "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17305,7 +17306,7 @@ int DetectFastPatternTest620(void) "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17412,7 +17413,7 @@ int DetectFastPatternTest624(void) "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -17541,7 +17542,7 @@ int DetectFastPatternTest629(void) "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18831,6 +18832,7 @@ void DetectFastPatternRegisterTests(void) g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); g_http_ua_buffer_id = DetectBufferTypeGetByName("http_user_agent"); g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie"); + g_http_host_buffer_id = DetectBufferTypeGetByName("http_host"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index fbe0db94353b..1abaf8a8c2e0 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -59,9 +59,12 @@ #include "detect-http-hh.h" #include "detect-engine-hhhd.h" -int DetectHttpHHSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpHHRegisterTests(void); -void DetectHttpHHFree(void *); +static int DetectHttpHHSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpHHRegisterTests(void); +static void DetectHttpHHFree(void *); +static void DetectHttpHostSetupCallback(Signature *s); +static _Bool DetectHttpHostValidateCallback(const Signature *s); +static int g_http_host_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_host" keyword. @@ -79,15 +82,23 @@ void DetectHttpHHRegister(void) sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_PAYLOAD ; - DetectMpmAppLayerRegister("http_host", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HHHDMATCH, 2, + DetectAppLayerMpmRegister("http_host", SIG_FLAG_TOSERVER, 2, PrefilterTxHostnameRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HHHDMATCH, + DetectAppLayerInspectEngineRegister2("http_host", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpHH); - return; + DetectBufferTypeSetDescriptionByName("http_host", + "http host header"); + + DetectBufferTypeRegisterSetupCallback("http_host", + DetectHttpHostSetupCallback); + + DetectBufferTypeRegisterValidateCallback("http_host", + DetectHttpHostValidateCallback); + + g_http_host_buffer_id = DetectBufferTypeGetByName("http_host"); } /** @@ -107,11 +118,50 @@ int DetectHttpHHSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_HOST, - DETECT_SM_LIST_HHHDMATCH, + g_http_host_buffer_id, ALPROTO_HTTP, NULL); } +static void DetectHttpHostSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +static _Bool DetectHttpHostValidateCallback(const Signature *s) +{ + const SigMatch *sm = s->init_data->smlists[g_http_host_buffer_id]; + for ( ; sm != NULL; sm = sm->next) { + if (sm->type == DETECT_CONTENT) { + DetectContentData *cd = (DetectContentData *)sm->ctx; + if (cd->flags & DETECT_CONTENT_NOCASE) { + SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http_host keyword " + "specified along with \"nocase\". " + "Since the hostname buffer we match against " + "is actually lowercase. So having a " + "nocase is redundant."); + } else { + uint32_t u; + for (u = 0; u < cd->content_len; u++) { + if (isupper(cd->content[u])) + break; + } + if (u != cd->content_len) { + SCLogWarning(SC_ERR_INVALID_SIGNATURE, "A pattern with " + "uppercase chars detected for http_host. " + "Since the hostname buffer we match against " + "is lowercase only, please specify a " + "lowercase pattern."); + return FALSE; + } + } + } + } + + return TRUE; +} + /** * \brief The function to free the http_host data. * @@ -280,6 +330,22 @@ static int DetectHttpHHTest05(void) return result; } +/** \test invalid sig: uppercase content */ +static int DetectHttpHHTest05a(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " + "(content:\"ABC\"; http_host; sid:1;)"); + FAIL_IF_NOT_NULL(s); + + DetectEngineCtxFree(de_ctx); + PASS; +} + /** *\test Test that the http_host content matches against a http request * which holds the content. @@ -1407,16 +1473,6 @@ static int DetectHttpHHTest14(void) return result; } - - - - - - - - - - int DetectHttpHHTest22(void) { DetectEngineCtx *de_ctx = NULL; @@ -1439,15 +1495,15 @@ int DetectHttpHHTest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1494,15 +1550,15 @@ int DetectHttpHHTest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1548,15 +1604,15 @@ int DetectHttpHHTest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1603,15 +1659,15 @@ int DetectHttpHHTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1659,15 +1715,15 @@ int DetectHttpHHTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1742,15 +1798,15 @@ int DetectHttpHHTest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1797,13 +1853,13 @@ int DetectHttpHHTest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || @@ -1841,13 +1897,13 @@ int DetectHttpHHTest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_WITHIN) || @@ -1957,21 +2013,21 @@ int DetectHttpHHTest34(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhhd2->flags != (DETECT_CONTENT_WITHIN) || memcmp(hhhd2->content, "two", hhhd2->content_len) != 0) { @@ -2008,21 +2064,21 @@ int DetectHttpHHTest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "two", hhhd1->content_len) != 0) { @@ -2059,21 +2115,21 @@ int DetectHttpHHTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hhhd2->content, "two", hhhd2->content_len) != 0) { @@ -2098,6 +2154,7 @@ void DetectHttpHHRegisterTests(void) UtRegisterTest("DetectHttpHHTest03", DetectHttpHHTest03); UtRegisterTest("DetectHttpHHTest04", DetectHttpHHTest04); UtRegisterTest("DetectHttpHHTest05", DetectHttpHHTest05); + UtRegisterTest("DetectHttpHHTest05a", DetectHttpHHTest05a); UtRegisterTest("DetectHttpHHTest06", DetectHttpHHTest06); UtRegisterTest("DetectHttpHHTest07", DetectHttpHHTest07); UtRegisterTest("DetectHttpHHTest08", DetectHttpHHTest08); diff --git a/src/detect-parse.c b/src/detect-parse.c index 4dd800b124be..ec9e4bce8420 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -147,7 +147,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HRHDMATCH, "http_raw_header"); CASE_CODE_STRING(DETECT_SM_LIST_HSMDMATCH, "http_stat_msg"); CASE_CODE_STRING(DETECT_SM_LIST_HSCDMATCH, "http_stat_code"); - CASE_CODE_STRING(DETECT_SM_LIST_HHHDMATCH, "http_host"); CASE_CODE_STRING(DETECT_SM_LIST_HRHHDMATCH, "http_raw_host"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); @@ -185,7 +184,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HRHDMATCH); CASE_CODE(DETECT_SM_LIST_HSMDMATCH); CASE_CODE(DETECT_SM_LIST_HSCDMATCH); - CASE_CODE(DETECT_SM_LIST_HHHDMATCH); CASE_CODE(DETECT_SM_LIST_HRHHDMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); @@ -1391,7 +1389,6 @@ SigMatchData* SigMatchList2DataArray(SigMatch *head) */ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) { - uint32_t u = 0; uint32_t sig_flags = 0; SigMatch *sm, *pm; const int nlists = DetectBufferTypeMaxId(); @@ -1478,35 +1475,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } - if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) { - for (sm = s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH]; - sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)sm->ctx; - if (cd->flags & DETECT_CONTENT_NOCASE) { - SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http_host keyword " - "specified along with \"nocase\". " - "Since the hostname buffer we match against " - "is actually lowercase. So having a " - "nocase is redundant."); - } else { - for (u = 0; u < cd->content_len; u++) { - if (isupper(cd->content[u])) - break; - } - if (u != cd->content_len) { - SCLogWarning(SC_ERR_INVALID_SIGNATURE, "A pattern with " - "uppercase chars detected for http_host. " - "Since the hostname buffer we match against " - "is lowercase only, please specify a " - "lowercase pattern."); - SCReturnInt(0); - } - } - } - } - } - //if (s->alproto != ALPROTO_UNKNOWN) { // if (s->flags & SIG_FLAG_STATE_MATCH) { // if (s->alproto == ALPROTO_DNS) { @@ -1576,7 +1544,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HHHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 13164d25decf..433c590c04d9 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -297,6 +297,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; + int check_host_header = 0; /* take the size of the whole input as buffer size for the regex we will * extract below. Add 1 to please Coverity's alloc_strlen test. */ @@ -413,13 +414,16 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, *sm_list = DetectPcreSetList(*sm_list, list); break; } - case 'W': + case 'W': { if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'W' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HHHDMATCH); + int list = DetectBufferTypeGetByName("http_host"); + *sm_list = DetectPcreSetList(*sm_list, list); + check_host_header = 1; break; + } case 'Z': if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'Z' inconsistent with 'B'"); @@ -493,7 +497,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, SCLogDebug("DetectPcreParse: \"%s\"", re); /* host header */ - if (*sm_list == DETECT_SM_LIST_HHHDMATCH) { + if (check_host_header) { if (pd->flags & DETECT_PCRE_CASELESS) { SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http host pcre(\"W\") " "specified along with \"i(caseless)\" modifier. " @@ -679,7 +683,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst parsed_sm_list == DETECT_SM_LIST_HRHDMATCH || parsed_sm_list == DETECT_SM_LIST_HSMDMATCH || parsed_sm_list == DETECT_SM_LIST_HSCDMATCH || - parsed_sm_list == DETECT_SM_LIST_HHHDMATCH || parsed_sm_list == DETECT_SM_LIST_HRHHDMATCH) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { @@ -713,7 +716,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_SM_LIST_HRUDMATCH: case DETECT_SM_LIST_HHDMATCH: case DETECT_SM_LIST_HRHDMATCH: - case DETECT_SM_LIST_HHHDMATCH: case DETECT_SM_LIST_HRHHDMATCH: case DETECT_SM_LIST_HSMDMATCH: case DETECT_SM_LIST_HSCDMATCH: diff --git a/src/detect.c b/src/detect.c index 1846fe11494c..2f39e7a25954 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1930,9 +1930,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) return 0; @@ -2026,9 +2023,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) return 0; @@ -2138,7 +2132,6 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { SCReturnInt(0); @@ -2322,11 +2315,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http app state"); } - if (s->init_data->smlists[DETECT_SM_LIST_HHHDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - if (s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); diff --git a/src/detect.h b/src/detect.h index 4683aee0f99e..a50d0935fd99 100644 --- a/src/detect.h +++ b/src/detect.h @@ -127,8 +127,6 @@ enum DetectSigmatchListEnum { 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, /* app event engine sm list */ From 128b59d4f63389159b40cca8ca32975b4c19811a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 9 Dec 2016 13:47:14 +0100 Subject: [PATCH 2375/2553] http_raw_host: dynamic buffer --- src/detect-engine.c | 2 - src/detect-fast-pattern.c | 44 +++++------ src/detect-http-hrh.c | 150 ++++++++++++++++++++------------------ src/detect-parse.c | 5 +- src/detect-pcre.c | 10 +-- src/detect.c | 14 +--- src/detect.h | 2 - 7 files changed, 108 insertions(+), 119 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 3870cd165044..9bffb0684604 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2810,8 +2810,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http stat msg"; case DETECT_SM_LIST_HSCDMATCH: return "http stat code"; - case DETECT_SM_LIST_HRHHDMATCH: - return "http raw host header"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 2cb1d8b39d2a..30f89aa996db 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -327,6 +327,7 @@ static int g_http_uri_buffer_id = 0; static int g_http_ua_buffer_id = 0; static int g_http_cookie_buffer_id = 0; static int g_http_host_buffer_id = 0; +static int g_http_raw_host_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -17580,7 +17581,7 @@ int DetectFastPatternTest630(void) "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && ud->flags & DETECT_CONTENT_NOCASE && @@ -17619,7 +17620,7 @@ int DetectFastPatternTest631(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) && @@ -17658,7 +17659,7 @@ int DetectFastPatternTest632(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) && @@ -17691,7 +17692,7 @@ int DetectFastPatternTest633(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id]; if (sm == NULL) { goto end; } @@ -17728,7 +17729,7 @@ int DetectFastPatternTest634(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id]; if (sm == NULL) { goto end; } @@ -17974,7 +17975,7 @@ int DetectFastPatternTest644(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18007,7 +18008,7 @@ int DetectFastPatternTest645(void) "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18040,7 +18041,7 @@ int DetectFastPatternTest646(void) "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18073,7 +18074,7 @@ int DetectFastPatternTest647(void) "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18105,7 +18106,7 @@ int DetectFastPatternTest648(void) "content:\"two\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && @@ -18231,7 +18232,7 @@ int DetectFastPatternTest653(void) "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18264,7 +18265,7 @@ int DetectFastPatternTest654(void) "content:\"three\"; http_raw_host; distance:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18297,7 +18298,7 @@ int DetectFastPatternTest655(void) "content:\"three\"; http_raw_host; within:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18330,7 +18331,7 @@ int DetectFastPatternTest656(void) "content:\"three\"; http_raw_host; offset:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18363,7 +18364,7 @@ int DetectFastPatternTest657(void) "content:\"three\"; http_raw_host; depth:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18396,7 +18397,7 @@ int DetectFastPatternTest658(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18429,7 +18430,7 @@ int DetectFastPatternTest659(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18462,7 +18463,7 @@ int DetectFastPatternTest660(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18495,7 +18496,7 @@ int DetectFastPatternTest661(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18603,7 +18604,7 @@ int DetectFastPatternTest665(void) "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && @@ -18733,7 +18734,7 @@ int DetectFastPatternTest670(void) "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && @@ -18833,6 +18834,7 @@ void DetectFastPatternRegisterTests(void) g_http_ua_buffer_id = DetectBufferTypeGetByName("http_user_agent"); g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie"); g_http_host_buffer_id = DetectBufferTypeGetByName("http_host"); + g_http_raw_host_buffer_id = DetectBufferTypeGetByName("http_raw_host"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index 53c1919e30d5..7c9022e98dfe 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -59,9 +59,11 @@ #include "detect-http-hrh.h" #include "detect-engine-hrhhd.h" -int DetectHttpHRHSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpHRHRegisterTests(void); -void DetectHttpHRHFree(void *); +static int DetectHttpHRHSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpHRHRegisterTests(void); +static void DetectHttpHRHFree(void *); +static void DetectHttpHostRawSetupCallback(Signature *); +static int g_http_raw_host_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_raw_host" keyword. @@ -79,15 +81,20 @@ void DetectHttpHRHRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_PAYLOAD ; - DetectMpmAppLayerRegister("http_raw_host", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HRHHDMATCH, 2, + DetectAppLayerMpmRegister("http_raw_host", SIG_FLAG_TOSERVER, 2, PrefilterTxHostnameRawRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HRHHDMATCH, + DetectAppLayerInspectEngineRegister2("http_raw_host", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpHRH); - return; + DetectBufferTypeSetDescriptionByName("http_raw_host", + "http raw host header"); + + DetectBufferTypeRegisterSetupCallback("http_raw_host", + DetectHttpHostRawSetupCallback); + + g_http_raw_host_buffer_id = DetectBufferTypeGetByName("http_raw_host"); } /** @@ -107,11 +114,17 @@ int DetectHttpHRHSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_RAW_HOST, - DETECT_SM_LIST_HRHHDMATCH, + g_http_raw_host_buffer_id, ALPROTO_HTTP, NULL); } +static void DetectHttpHostRawSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + /** * \brief The function to free the http_raw_host data. * @@ -1406,13 +1419,6 @@ static int DetectHttpHRHTest14(void) return result; } - - - - - - - int DetectHttpHRHTest22(void) { DetectEngineCtx *de_ctx = NULL; @@ -1435,15 +1441,15 @@ int DetectHttpHRHTest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1490,15 +1496,15 @@ int DetectHttpHRHTest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1544,15 +1550,15 @@ int DetectHttpHRHTest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1599,15 +1605,15 @@ int DetectHttpHRHTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1655,15 +1661,15 @@ int DetectHttpHRHTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1738,15 +1744,15 @@ int DetectHttpHRHTest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1793,13 +1799,13 @@ int DetectHttpHRHTest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || @@ -1837,13 +1843,13 @@ int DetectHttpHRHTest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_WITHIN) || @@ -1953,21 +1959,21 @@ int DetectHttpHRHTest34(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_CASELESS) || hrhhd2->flags != (DETECT_CONTENT_WITHIN) || memcmp(hrhhd2->content, "two", hrhhd2->content_len) != 0) { @@ -2004,21 +2010,21 @@ int DetectHttpHRHTest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_CASELESS) || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "two", hrhhd1->content_len) != 0) { @@ -2055,21 +2061,21 @@ int DetectHttpHRHTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_CASELESS) || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hrhhd2->content, "two", hrhhd2->content_len) != 0) { diff --git a/src/detect-parse.c b/src/detect-parse.c index ec9e4bce8420..bf60cea1cbef 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -147,7 +147,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HRHDMATCH, "http_raw_header"); CASE_CODE_STRING(DETECT_SM_LIST_HSMDMATCH, "http_stat_msg"); CASE_CODE_STRING(DETECT_SM_LIST_HSCDMATCH, "http_stat_code"); - CASE_CODE_STRING(DETECT_SM_LIST_HRHHDMATCH, "http_raw_host"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -184,7 +183,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HRHDMATCH); CASE_CODE(DETECT_SM_LIST_HSMDMATCH); CASE_CODE(DETECT_SM_LIST_HSCDMATCH); - CASE_CODE(DETECT_SM_LIST_HRHHDMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); @@ -1543,8 +1541,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HRHHDMATCH]) + s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " "specific matches (like dsize, flags, ttl) with stream / " diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 433c590c04d9..627794e5e7eb 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -424,13 +424,15 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, check_host_header = 1; break; } - case 'Z': + case 'Z': { if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'Z' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HRHHDMATCH); + int list = DetectBufferTypeGetByName("http_raw_host"); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } case 'H': /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'H' inconsistent with 'B'"); @@ -682,8 +684,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst parsed_sm_list == DETECT_SM_LIST_HHDMATCH || parsed_sm_list == DETECT_SM_LIST_HRHDMATCH || parsed_sm_list == DETECT_SM_LIST_HSMDMATCH || - parsed_sm_list == DETECT_SM_LIST_HSCDMATCH || - parsed_sm_list == DETECT_SM_LIST_HRHHDMATCH) + parsed_sm_list == DETECT_SM_LIST_HSCDMATCH) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " @@ -716,7 +717,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_SM_LIST_HRUDMATCH: case DETECT_SM_LIST_HHDMATCH: case DETECT_SM_LIST_HRHDMATCH: - case DETECT_SM_LIST_HRHHDMATCH: case DETECT_SM_LIST_HSMDMATCH: case DETECT_SM_LIST_HSCDMATCH: s->flags |= SIG_FLAG_APPLAYER; diff --git a/src/detect.c b/src/detect.c index 2f39e7a25954..197b08ed7453 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1930,9 +1930,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -2023,9 +2020,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -2131,8 +2125,7 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) + s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { SCReturnInt(0); } @@ -2315,11 +2308,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http app state"); } - if (s->init_data->smlists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - SigMatch *sm; for (sm = s->init_data->smlists[DETECT_SM_LIST_AMATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { diff --git a/src/detect.h b/src/detect.h index a50d0935fd99..060b56fe1d2f 100644 --- a/src/detect.h +++ b/src/detect.h @@ -127,8 +127,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_HSMDMATCH, /* list for http_stat_code keyword and the ones relative to it */ DETECT_SM_LIST_HSCDMATCH, - /* list for http_raw_host keyword and the ones relative to it */ - DETECT_SM_LIST_HRHHDMATCH, /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, From 7e3ab4f5eab75fa83bb501b925003ed233ba89b5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 9 Dec 2016 14:00:48 +0100 Subject: [PATCH 2376/2553] http_stat_code: dynamic buffer --- src/detect-engine-analyzer.c | 9 +++----- src/detect-engine.c | 2 -- src/detect-fast-pattern.c | 44 +++++++++++++++++++----------------- src/detect-http-stat-code.c | 35 ++++++++++++++++++---------- src/detect-parse.c | 8 ++----- src/detect-pcre.c | 10 ++++---- src/detect.c | 12 ---------- src/detect.h | 2 -- 8 files changed, 56 insertions(+), 66 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 5f1320589e02..866250308f6c 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -120,8 +120,6 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "http raw header content\n"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(fp_engine_analysis_FD, "http client body content\n"); - else if (list_type == DETECT_SM_LIST_HSCDMATCH) - fprintf(fp_engine_analysis_FD, "http stat code content\n"); else if (list_type == DETECT_SM_LIST_HSMDMATCH) fprintf(fp_engine_analysis_FD, "http stat msg content\n"); else { @@ -466,8 +464,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "http raw header content"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(rule_engine_analysis_FD, "http client body content"); - else if (list_type == DETECT_SM_LIST_HSCDMATCH) - fprintf(rule_engine_analysis_FD, "http stat code content"); else if (list_type == DETECT_SM_LIST_HSMDMATCH) fprintf(rule_engine_analysis_FD, "http stat msg content"); else if (list_type == DETECT_SM_LIST_DNSQUERYNAME_MATCH) @@ -574,6 +570,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) const int httpuri_id = DetectBufferTypeGetByName("http_uri"); const int httpuseragent_id = DetectBufferTypeGetByName("http_user_agent"); const int httpcookie_id = DetectBufferTypeGetByName("http_cookie"); + const int httpstatcode_id = DetectBufferTypeGetByName("http_stat_code"); if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; @@ -642,7 +639,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_stat_msg_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSCDMATCH) { + else if (list_id == httpstatcode_id) { rule_pcre_http += 1; raw_http_buf += 1; http_stat_code_buf += 1; @@ -703,7 +700,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_stat_msg_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSCDMATCH) { + else if (list_id == httpstatcode_id) { rule_content_http += 1; raw_http_buf += 1; http_stat_code_buf += 1; diff --git a/src/detect-engine.c b/src/detect-engine.c index 9bffb0684604..4e68b2479205 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2808,8 +2808,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http raw headers"; case DETECT_SM_LIST_HSMDMATCH: return "http stat msg"; - case DETECT_SM_LIST_HSCDMATCH: - return "http stat code"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 30f89aa996db..513408da5cea 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -328,6 +328,7 @@ static int g_http_ua_buffer_id = 0; static int g_http_cookie_buffer_id = 0; static int g_http_host_buffer_id = 0; static int g_http_raw_host_buffer_id = 0; +static int g_http_stat_code_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -11719,7 +11720,7 @@ int DetectFastPatternTest425(void) "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -11757,7 +11758,7 @@ int DetectFastPatternTest426(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -11794,7 +11795,7 @@ int DetectFastPatternTest427(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -11825,7 +11826,7 @@ int DetectFastPatternTest428(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; if (sm == NULL) { goto end; } @@ -11862,7 +11863,7 @@ int DetectFastPatternTest429(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; if (sm == NULL) { goto end; } @@ -12107,7 +12108,7 @@ int DetectFastPatternTest439(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12139,7 +12140,7 @@ int DetectFastPatternTest440(void) "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12171,7 +12172,7 @@ int DetectFastPatternTest441(void) "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12203,7 +12204,7 @@ int DetectFastPatternTest442(void) "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12234,7 +12235,7 @@ int DetectFastPatternTest443(void) "content:\"two\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12359,7 +12360,7 @@ int DetectFastPatternTest448(void) "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12391,7 +12392,7 @@ int DetectFastPatternTest449(void) "content:\"three\"; http_stat_code; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12423,7 +12424,7 @@ int DetectFastPatternTest450(void) "content:\"three\"; http_stat_code; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12455,7 +12456,7 @@ int DetectFastPatternTest451(void) "content:\"three\"; http_stat_code; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12487,7 +12488,7 @@ int DetectFastPatternTest452(void) "content:\"three\"; http_stat_code; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12519,7 +12520,7 @@ int DetectFastPatternTest453(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12551,7 +12552,7 @@ int DetectFastPatternTest454(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12583,7 +12584,7 @@ int DetectFastPatternTest455(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12615,7 +12616,7 @@ int DetectFastPatternTest456(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12722,7 +12723,7 @@ int DetectFastPatternTest460(void) "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12851,7 +12852,7 @@ int DetectFastPatternTest465(void) "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18835,6 +18836,7 @@ void DetectFastPatternRegisterTests(void) g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie"); g_http_host_buffer_id = DetectBufferTypeGetByName("http_host"); g_http_raw_host_buffer_id = DetectBufferTypeGetByName("http_raw_host"); + g_http_stat_code_buffer_id = DetectBufferTypeGetByName("http_stat_code"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index a67bf26ed400..2749584bb85e 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -63,12 +63,10 @@ #include "stream-tcp-private.h" #include "stream-tcp.h" -int DetectHttpStatCodeMatch(ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t , void *, Signature *, - SigMatch *); static int DetectHttpStatCodeSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpStatCodeRegisterTests(void); -void DetectHttpStatCodeFree(void *); +static void DetectHttpStatCodeRegisterTests(void); +static void DetectHttpStatCodeSetupCallback(Signature *); +static int g_http_stat_code_buffer_id = 0; /** * \brief Registration function for keyword: http_stat_code @@ -87,13 +85,20 @@ void DetectHttpStatCodeRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("http_stat_code", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HSCDMATCH, 4, + DetectAppLayerMpmRegister("http_stat_code", SIG_FLAG_TOCLIENT, 4, PrefilterTxHttpStatCodeRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HSCDMATCH, + DetectAppLayerInspectEngineRegister2("http_stat_code", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpStatCode); + + DetectBufferTypeSetDescriptionByName("http_stat_code", + "http response status code"); + + DetectBufferTypeRegisterSetupCallback("http_stat_code", + DetectHttpStatCodeSetupCallback); + + g_http_stat_code_buffer_id = DetectBufferTypeGetByName("http_stat_code"); } /** @@ -111,11 +116,17 @@ static int DetectHttpStatCodeSetup(DetectEngineCtx *de_ctx, Signature *s, char * { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_STAT_CODE, - DETECT_SM_LIST_HSCDMATCH, + g_http_stat_code_buffer_id, ALPROTO_HTTP, NULL); } +static void DetectHttpStatCodeSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + #ifdef UNITTESTS /** @@ -156,7 +167,7 @@ int DetectHttpStatCodeTest01(void) printf("sid 3 parse failed: "); goto end; } - if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]->ctx)->flags & + if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { goto end; @@ -194,7 +205,7 @@ int DetectHttpStatCodeTest02(void) } result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; diff --git a/src/detect-parse.c b/src/detect-parse.c index bf60cea1cbef..31ec0fa484b2 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -146,7 +146,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HHDMATCH, "http_header"); CASE_CODE_STRING(DETECT_SM_LIST_HRHDMATCH, "http_raw_header"); CASE_CODE_STRING(DETECT_SM_LIST_HSMDMATCH, "http_stat_msg"); - CASE_CODE_STRING(DETECT_SM_LIST_HSCDMATCH, "http_stat_code"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -182,7 +181,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HHDMATCH); CASE_CODE(DETECT_SM_LIST_HRHDMATCH); CASE_CODE(DETECT_SM_LIST_HSMDMATCH); - CASE_CODE(DETECT_SM_LIST_HSCDMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); @@ -1428,8 +1426,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } else if (fd->flags & FLOW_PKT_TOSERVER) { /* check for uricontent + from_server/to_client */ - if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use http_" "server_body, http_stat_msg, http_stat_code " "with flow:to_server or flow:from_client"); @@ -1540,8 +1537,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HSCDMATCH]) + s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " "specific matches (like dsize, flags, ttl) with stream / " diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 627794e5e7eb..e7cd1581f785 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -482,10 +482,12 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, /* snort's option */ *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HSMDMATCH); break; - case 'S': + case 'S': { /* snort's option */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HSCDMATCH); + int list = DetectBufferTypeGetByName("http_stat_code"); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } default: SCLogError(SC_ERR_UNKNOWN_REGEX_MOD, "unknown regex modifier '%c'", *op); goto error; @@ -683,8 +685,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst parsed_sm_list == DETECT_SM_LIST_HCBDMATCH || parsed_sm_list == DETECT_SM_LIST_HHDMATCH || parsed_sm_list == DETECT_SM_LIST_HRHDMATCH || - parsed_sm_list == DETECT_SM_LIST_HSMDMATCH || - parsed_sm_list == DETECT_SM_LIST_HSCDMATCH) + parsed_sm_list == DETECT_SM_LIST_HSMDMATCH) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " @@ -718,7 +719,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_SM_LIST_HHDMATCH: case DETECT_SM_LIST_HRHDMATCH: case DETECT_SM_LIST_HSMDMATCH: - case DETECT_SM_LIST_HSCDMATCH: s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; sm_list = parsed_sm_list; diff --git a/src/detect.c b/src/detect.c index 197b08ed7453..4de426efef11 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1927,9 +1927,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -2017,9 +2014,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -2124,7 +2118,6 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { SCReturnInt(0); @@ -2303,11 +2296,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http app state"); } - if (s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - SigMatch *sm; for (sm = s->init_data->smlists[DETECT_SM_LIST_AMATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { diff --git a/src/detect.h b/src/detect.h index 060b56fe1d2f..35465391641a 100644 --- a/src/detect.h +++ b/src/detect.h @@ -125,8 +125,6 @@ enum DetectSigmatchListEnum { 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, /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, From b694d96e2240920fa12f095b21114a866226f33b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 9 Dec 2016 14:46:05 +0100 Subject: [PATCH 2377/2553] http_stat_msg: dynamic buffer --- src/detect-engine-analyzer.c | 9 +++----- src/detect-engine.c | 2 -- src/detect-fast-pattern.c | 44 +++++++++++++++++++----------------- src/detect-http-stat-msg.c | 35 ++++++++++++++++++---------- src/detect-parse.c | 13 +---------- src/detect-pcre.c | 10 ++++---- src/detect.c | 12 ---------- src/detect.h | 2 -- 8 files changed, 55 insertions(+), 72 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 866250308f6c..5de0ce168c26 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -120,8 +120,6 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "http raw header content\n"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(fp_engine_analysis_FD, "http client body content\n"); - else if (list_type == DETECT_SM_LIST_HSMDMATCH) - fprintf(fp_engine_analysis_FD, "http stat msg content\n"); else { const char *desc = DetectBufferTypeGetDescriptionById(list_type); const char *name = DetectBufferTypeGetNameById(list_type); @@ -464,8 +462,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "http raw header content"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(rule_engine_analysis_FD, "http client body content"); - else if (list_type == DETECT_SM_LIST_HSMDMATCH) - fprintf(rule_engine_analysis_FD, "http stat msg content"); else if (list_type == DETECT_SM_LIST_DNSQUERYNAME_MATCH) fprintf(rule_engine_analysis_FD, "dns query name content"); else if (list_type == DETECT_SM_LIST_TLSSNI_MATCH) @@ -571,6 +567,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) const int httpuseragent_id = DetectBufferTypeGetByName("http_user_agent"); const int httpcookie_id = DetectBufferTypeGetByName("http_cookie"); const int httpstatcode_id = DetectBufferTypeGetByName("http_stat_code"); + const int httpstatmsg_id = DetectBufferTypeGetByName("http_stat_msg"); if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; @@ -634,7 +631,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_raw_uri_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSMDMATCH) { + else if (list_id == httpstatmsg_id) { rule_pcre_http += 1; raw_http_buf += 1; http_stat_msg_buf += 1; @@ -695,7 +692,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_raw_uri_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSMDMATCH) { + else if (list_id == httpstatmsg_id) { rule_content_http += 1; raw_http_buf += 1; http_stat_msg_buf += 1; diff --git a/src/detect-engine.c b/src/detect-engine.c index 4e68b2479205..381342e8921a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2806,8 +2806,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http headers"; case DETECT_SM_LIST_HRHDMATCH: return "http raw headers"; - case DETECT_SM_LIST_HSMDMATCH: - return "http stat msg"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 513408da5cea..e902f261b2f8 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -329,6 +329,7 @@ static int g_http_cookie_buffer_id = 0; static int g_http_host_buffer_id = 0; static int g_http_raw_host_buffer_id = 0; static int g_http_stat_code_buffer_id = 0; +static int g_http_stat_msg_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -10551,7 +10552,7 @@ int DetectFastPatternTest384(void) "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -10589,7 +10590,7 @@ int DetectFastPatternTest385(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -10626,7 +10627,7 @@ int DetectFastPatternTest386(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -10657,7 +10658,7 @@ int DetectFastPatternTest387(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]; if (sm == NULL) { goto end; } @@ -10693,7 +10694,7 @@ int DetectFastPatternTest388(void) if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]; if (sm == NULL) { goto end; } @@ -10938,7 +10939,7 @@ int DetectFastPatternTest398(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10970,7 +10971,7 @@ int DetectFastPatternTest399(void) "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11002,7 +11003,7 @@ int DetectFastPatternTest400(void) "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11034,7 +11035,7 @@ int DetectFastPatternTest401(void) "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11065,7 +11066,7 @@ int DetectFastPatternTest402(void) "content:\"two\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -11190,7 +11191,7 @@ int DetectFastPatternTest407(void) "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11222,7 +11223,7 @@ int DetectFastPatternTest408(void) "content:\"three\"; http_stat_msg; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11254,7 +11255,7 @@ int DetectFastPatternTest409(void) "content:\"three\"; http_stat_msg; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11286,7 +11287,7 @@ int DetectFastPatternTest410(void) "content:\"three\"; http_stat_msg; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11318,7 +11319,7 @@ int DetectFastPatternTest411(void) "content:\"three\"; http_stat_msg; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11350,7 +11351,7 @@ int DetectFastPatternTest412(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11382,7 +11383,7 @@ int DetectFastPatternTest413(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11414,7 +11415,7 @@ int DetectFastPatternTest414(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11446,7 +11447,7 @@ int DetectFastPatternTest415(void) "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11553,7 +11554,7 @@ int DetectFastPatternTest419(void) "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -11682,7 +11683,7 @@ int DetectFastPatternTest424(void) "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18837,6 +18838,7 @@ void DetectFastPatternRegisterTests(void) g_http_host_buffer_id = DetectBufferTypeGetByName("http_host"); g_http_raw_host_buffer_id = DetectBufferTypeGetByName("http_raw_host"); g_http_stat_code_buffer_id = DetectBufferTypeGetByName("http_stat_code"); + g_http_stat_msg_buffer_id = DetectBufferTypeGetByName("http_stat_msg"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index 2207d13b61e5..c61c6659234d 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -63,12 +63,10 @@ #include "stream-tcp-private.h" #include "stream-tcp.h" -int DetectHttpStatMsgMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t , void *, Signature *, - SigMatch *); static int DetectHttpStatMsgSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpStatMsgRegisterTests(void); -void DetectHttpStatMsgFree(void *); +static void DetectHttpStatMsgRegisterTests(void); +static void DetectHttpStatMsgSetupCallback(Signature *s); +static int g_http_stat_msg_buffer_id = 0; /** * \brief Registration function for keyword: http_stat_msg @@ -87,13 +85,20 @@ void DetectHttpStatMsgRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("http_stat_msg", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HSMDMATCH, 3, + DetectAppLayerMpmRegister("http_stat_msg", SIG_FLAG_TOCLIENT, 3, PrefilterTxHttpStatMsgRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HSMDMATCH, + DetectAppLayerInspectEngineRegister2("http_stat_msg", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpStatMsg); + + DetectBufferTypeSetDescriptionByName("http_stat_msg", + "http response status message"); + + DetectBufferTypeRegisterSetupCallback("http_stat_msg", + DetectHttpStatMsgSetupCallback); + + g_http_stat_msg_buffer_id = DetectBufferTypeGetByName("http_stat_msg"); } /** @@ -111,11 +116,17 @@ static int DetectHttpStatMsgSetup(DetectEngineCtx *de_ctx, Signature *s, char *a { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_STAT_MSG, - DETECT_SM_LIST_HSMDMATCH, + g_http_stat_msg_buffer_id, ALPROTO_HTTP, NULL); } +static void DetectHttpStatMsgSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + #ifdef UNITTESTS /** @@ -148,7 +159,7 @@ int DetectHttpStatMsgTest01(void) "fast_pattern; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]->ctx)->flags & + if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { goto end; @@ -186,7 +197,7 @@ int DetectHttpStatMsgTest02(void) } result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; diff --git a/src/detect-parse.c b/src/detect-parse.c index 31ec0fa484b2..842679a376cb 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -145,7 +145,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_HCBDMATCH, "http_client_body"); CASE_CODE_STRING(DETECT_SM_LIST_HHDMATCH, "http_header"); CASE_CODE_STRING(DETECT_SM_LIST_HRHDMATCH, "http_raw_header"); - CASE_CODE_STRING(DETECT_SM_LIST_HSMDMATCH, "http_stat_msg"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -180,7 +179,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_HCBDMATCH); CASE_CODE(DETECT_SM_LIST_HHDMATCH); CASE_CODE(DETECT_SM_LIST_HRHDMATCH); - CASE_CODE(DETECT_SM_LIST_HSMDMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); @@ -1424,14 +1422,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) "with flow:to_client or flow:from_server"); SCReturnInt(0); } - } else if (fd->flags & FLOW_PKT_TOSERVER) { - /* check for uricontent + from_server/to_client */ - if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use http_" - "server_body, http_stat_msg, http_stat_code " - "with flow:to_server or flow:from_client"); - SCReturnInt(0); - } } } } @@ -1536,8 +1526,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH] || s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HSMDMATCH]) + s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " "specific matches (like dsize, flags, ttl) with stream / " diff --git a/src/detect-pcre.c b/src/detect-pcre.c index e7cd1581f785..d430193e5524 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -478,10 +478,12 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, *sm_list = DetectPcreSetList(*sm_list, list); break; } - case 'Y': + case 'Y': { /* snort's option */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HSMDMATCH); + int list = DetectBufferTypeGetByName("http_stat_msg"); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } case 'S': { /* snort's option */ int list = DetectBufferTypeGetByName("http_stat_code"); @@ -684,8 +686,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst if (parsed_sm_list == DETECT_SM_LIST_HRUDMATCH || parsed_sm_list == DETECT_SM_LIST_HCBDMATCH || parsed_sm_list == DETECT_SM_LIST_HHDMATCH || - parsed_sm_list == DETECT_SM_LIST_HRHDMATCH || - parsed_sm_list == DETECT_SM_LIST_HSMDMATCH) + parsed_sm_list == DETECT_SM_LIST_HRHDMATCH) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " @@ -718,7 +719,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_SM_LIST_HRUDMATCH: case DETECT_SM_LIST_HHDMATCH: case DETECT_SM_LIST_HRHDMATCH: - case DETECT_SM_LIST_HSMDMATCH: s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; sm_list = parsed_sm_list; diff --git a/src/detect.c b/src/detect.c index 4de426efef11..5ab7af0c3d27 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1924,9 +1924,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -2011,9 +2008,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -2117,7 +2111,6 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { SCReturnInt(0); @@ -2291,11 +2284,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http app state"); } - if (s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - SigMatch *sm; for (sm = s->init_data->smlists[DETECT_SM_LIST_AMATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { diff --git a/src/detect.h b/src/detect.h index 35465391641a..ce6a609b5ef2 100644 --- a/src/detect.h +++ b/src/detect.h @@ -123,8 +123,6 @@ enum DetectSigmatchListEnum { 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, /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, From e7d5e845c799595faa6b3a25e59218a689144046 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 9 Dec 2016 15:27:51 +0100 Subject: [PATCH 2378/2553] http_header / http_raw_header: dynamic buffers --- src/detect-base64-decode.c | 6 +- src/detect-engine-analyzer.c | 20 ++--- src/detect-engine.c | 4 - src/detect-fast-pattern.c | 88 ++++++++++---------- src/detect-http-header.c | 135 ++++++++++++++++++++----------- src/detect-http-raw-header.c | 150 ++++++++++++++++++++++++----------- src/detect-isdataat.c | 90 --------------------- src/detect-lua.c | 12 +-- src/detect-parse.c | 18 +---- src/detect-pcre.c | 61 +++++++------- src/detect.c | 24 ------ src/detect.h | 4 - 12 files changed, 290 insertions(+), 322 deletions(-) diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index 83dfd64139b8..5bac625e0f1a 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -256,6 +256,8 @@ static void DetectBase64DecodeFree(void *ptr) #include "flow-util.h" #include "stream-tcp.h" +static int g_http_header_buffer_id = 0; + static int DetectBase64TestDecodeParse(void) { int retval = 0; @@ -411,7 +413,7 @@ static int DetectBase64DecodeHttpHeaderTestSetup(void) } /* Test that the http header list is not NULL. */ - if (s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL) { + if (s->sm_lists_tail[g_http_header_buffer_id] == NULL) { goto end; } @@ -662,6 +664,8 @@ static int DetectBase64DecodeTestDecodeRelative(void) static void DetectBase64DecodeRegisterTests(void) { #ifdef UNITTESTS + g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); + UtRegisterTest("DetectBase64TestDecodeParse", DetectBase64TestDecodeParse); UtRegisterTest("DetectBase64DecodeTestSetup", DetectBase64DecodeTestSetup); UtRegisterTest("DetectBase64DecodeHttpHeaderTestSetup", diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 5de0ce168c26..7990afc01992 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -114,10 +114,6 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "content\n"); else if (list_type == DETECT_SM_LIST_HRUDMATCH) fprintf(fp_engine_analysis_FD, "http raw uri content\n"); - else if (list_type == DETECT_SM_LIST_HHDMATCH) - fprintf(fp_engine_analysis_FD, "http header content\n"); - else if (list_type == DETECT_SM_LIST_HRHDMATCH) - fprintf(fp_engine_analysis_FD, "http raw header content\n"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(fp_engine_analysis_FD, "http client body content\n"); else { @@ -456,10 +452,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) } else if (list_type == DETECT_SM_LIST_HRUDMATCH) fprintf(rule_engine_analysis_FD, "http raw uri content"); - else if (list_type == DETECT_SM_LIST_HHDMATCH) - fprintf(rule_engine_analysis_FD, "http header content"); - else if (list_type == DETECT_SM_LIST_HRHDMATCH) - fprintf(rule_engine_analysis_FD, "http raw header content"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(rule_engine_analysis_FD, "http client body content"); else if (list_type == DETECT_SM_LIST_DNSQUERYNAME_MATCH) @@ -568,6 +560,8 @@ void EngineAnalysisRules(const Signature *s, const char *line) const int httpcookie_id = DetectBufferTypeGetByName("http_cookie"); const int httpstatcode_id = DetectBufferTypeGetByName("http_stat_code"); const int httpstatmsg_id = DetectBufferTypeGetByName("http_stat_msg"); + const int httpheader_id = DetectBufferTypeGetByName("http_header"); + const int httprawheader_id = DetectBufferTypeGetByName("http_raw_header"); if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; @@ -601,7 +595,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) norm_http_buf += 1; http_uri_buf += 1; } - else if (list_id == DETECT_SM_LIST_HHDMATCH) { + else if (list_id == httpheader_id) { rule_pcre_http += 1; norm_http_buf += 1; http_header_buf += 1; @@ -616,7 +610,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) http_server_body_buf += 1; raw_http_buf += 1; } - else if (list_id == DETECT_SM_LIST_HRHDMATCH) { + else if (list_id == httprawheader_id) { rule_pcre_http += 1; raw_http_buf += 1; http_raw_header_buf += 1; @@ -653,7 +647,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) else if (sm->type == DETECT_CONTENT) { if (list_id == httpuri_id - || list_id == DETECT_SM_LIST_HHDMATCH + || list_id == httpheader_id || list_id == httpcookie_id) { rule_content_http += 1; norm_http_buf += 1; @@ -665,7 +659,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) if (list_id == httpuri_id) { http_uri_buf += 1; } - else if (list_id == DETECT_SM_LIST_HHDMATCH) { + else if (list_id == httpheader_id) { http_header_buf += 1; } else if (list_id == httpcookie_id) { @@ -682,7 +676,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_server_body_buf += 1; } - else if (list_id == DETECT_SM_LIST_HRHDMATCH) { + else if (list_id == httprawheader_id) { rule_content_http += 1; raw_http_buf += 1; http_raw_header_buf += 1; diff --git a/src/detect-engine.c b/src/detect-engine.c index 381342e8921a..6b64f08cca82 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2802,10 +2802,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) return "http raw uri"; case DETECT_SM_LIST_HCBDMATCH: return "http client body"; - case DETECT_SM_LIST_HHDMATCH: - return "http headers"; - case DETECT_SM_LIST_HRHDMATCH: - return "http raw headers"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index e902f261b2f8..58925d51f670 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -330,6 +330,8 @@ static int g_http_host_buffer_id = 0; static int g_http_raw_host_buffer_id = 0; static int g_http_stat_code_buffer_id = 0; static int g_http_stat_msg_buffer_id = 0; +static int g_http_raw_header_buffer_id = 0; +static int g_http_header_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -4964,7 +4966,7 @@ int DetectFastPatternTest179(void) "content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -5002,7 +5004,7 @@ int DetectFastPatternTest180(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_header_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -5039,7 +5041,7 @@ int DetectFastPatternTest181(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_header_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -5071,7 +5073,7 @@ int DetectFastPatternTest182(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_header_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -5105,7 +5107,7 @@ int DetectFastPatternTest183(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_header_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -5335,7 +5337,7 @@ int DetectFastPatternTest193(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5365,7 +5367,7 @@ int DetectFastPatternTest194(void) "(content:\"one\"; http_header; content:\"two\"; http_header; within:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5395,7 +5397,7 @@ int DetectFastPatternTest195(void) "(content:\"one\"; http_header; content:\"two\"; http_header; offset:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5425,7 +5427,7 @@ int DetectFastPatternTest196(void) "(content:\"one\"; http_header; content:\"two\"; http_header; depth:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5455,7 +5457,7 @@ int DetectFastPatternTest197(void) "(content:!\"one\"; fast_pattern; http_header; content:\"two\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -5574,7 +5576,7 @@ int DetectFastPatternTest202(void) "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5604,7 +5606,7 @@ int DetectFastPatternTest203(void) "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5634,7 +5636,7 @@ int DetectFastPatternTest204(void) "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5664,7 +5666,7 @@ int DetectFastPatternTest205(void) "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5694,7 +5696,7 @@ int DetectFastPatternTest206(void) "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5724,7 +5726,7 @@ int DetectFastPatternTest207(void) "(content:\"one\"; http_header; content:\"two\"; http_header; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5754,7 +5756,7 @@ int DetectFastPatternTest208(void) "(content:\"one\"; http_header; content:\"two\"; http_header; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5784,7 +5786,7 @@ int DetectFastPatternTest209(void) "(content:\"one\"; http_header; content:\"two\"; http_header; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5814,7 +5816,7 @@ int DetectFastPatternTest210(void) "(content:\"one\"; http_header; content:\"two\"; http_header; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5913,7 +5915,7 @@ int DetectFastPatternTest214(void) "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6032,7 +6034,7 @@ int DetectFastPatternTest219(void) "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6070,7 +6072,7 @@ int DetectFastPatternTest220(void) "content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6108,7 +6110,7 @@ int DetectFastPatternTest221(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -6145,7 +6147,7 @@ int DetectFastPatternTest222(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -6177,7 +6179,7 @@ int DetectFastPatternTest223(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -6211,7 +6213,7 @@ int DetectFastPatternTest224(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6441,7 +6443,7 @@ int DetectFastPatternTest234(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -6471,7 +6473,7 @@ int DetectFastPatternTest235(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; within:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -6501,7 +6503,7 @@ int DetectFastPatternTest236(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; offset:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -6531,7 +6533,7 @@ int DetectFastPatternTest237(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; depth:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -6561,7 +6563,7 @@ int DetectFastPatternTest238(void) "(flow:to_server; content:!\"one\"; fast_pattern; http_raw_header; content:\"two\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6680,7 +6682,7 @@ int DetectFastPatternTest243(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6710,7 +6712,7 @@ int DetectFastPatternTest244(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6740,7 +6742,7 @@ int DetectFastPatternTest245(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6770,7 +6772,7 @@ int DetectFastPatternTest246(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6800,7 +6802,7 @@ int DetectFastPatternTest247(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6830,7 +6832,7 @@ int DetectFastPatternTest248(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6860,7 +6862,7 @@ int DetectFastPatternTest249(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6890,7 +6892,7 @@ int DetectFastPatternTest250(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6920,7 +6922,7 @@ int DetectFastPatternTest251(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7019,7 +7021,7 @@ int DetectFastPatternTest255(void) "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7138,7 +7140,7 @@ int DetectFastPatternTest260(void) "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18839,6 +18841,8 @@ void DetectFastPatternRegisterTests(void) g_http_raw_host_buffer_id = DetectBufferTypeGetByName("http_raw_host"); g_http_stat_code_buffer_id = DetectBufferTypeGetByName("http_stat_code"); g_http_stat_msg_buffer_id = DetectBufferTypeGetByName("http_stat_msg"); + g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); + g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-header.c b/src/detect-http-header.c index a118249dcd68..af1524f83419 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -60,9 +60,11 @@ #include "detect-engine-hhd.h" #include "stream-tcp.h" -int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpHeaderRegisterTests(void); -void DetectHttpHeaderFree(void *); +static int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpHeaderRegisterTests(void); +static void DetectHttpHeaderFree(void *); +static void DetectHttpHeaderSetupCallback(Signature *); +static int g_http_header_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_header" keyword. @@ -81,21 +83,25 @@ void DetectHttpHeaderRegister(void) sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_PAYLOAD ; - DetectMpmAppLayerRegister("http_header", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HHDMATCH, 2, + DetectAppLayerMpmRegister("http_header", SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestHeadersRegister); - DetectMpmAppLayerRegister("http_header", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HHDMATCH, 2, + DetectAppLayerMpmRegister("http_header", SIG_FLAG_TOCLIENT, 2, PrefilterTxHttpResponseHeadersRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HHDMATCH, + DetectAppLayerInspectEngineRegister2("http_header", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpHeader); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HHDMATCH, + DetectAppLayerInspectEngineRegister2("http_header", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpHeader); - return; + DetectBufferTypeSetDescriptionByName("http_header", + "http headers"); + + DetectBufferTypeRegisterSetupCallback("http_header", + DetectHttpHeaderSetupCallback); + + g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); } /** @@ -133,15 +139,22 @@ int DetectHttpHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_HEADER, - DETECT_SM_LIST_HHDMATCH, + g_http_header_buffer_id, ALPROTO_HTTP, NULL); } +static void DetectHttpHeaderSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + /************************************Unittests*********************************/ #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** @@ -169,7 +182,7 @@ static int DetectHttpHeaderTest01(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_header_buffer_id]; if (sm != NULL) { result &= (sm->type == DETECT_CONTENT); result &= (sm->next == NULL); @@ -1258,13 +1271,13 @@ int DetectHttpHeaderTest20(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL\n"); goto end; } - DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "one", hhd1->content_len) != 0 || hhd2->flags != DETECT_CONTENT_DISTANCE || @@ -1302,13 +1315,13 @@ int DetectHttpHeaderTest21(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL\n"); goto end; } - DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "one", hhd1->content_len) != 0 || hhd2->flags != DETECT_CONTENT_WITHIN || @@ -1418,21 +1431,21 @@ int DetectHttpHeaderTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_WITHIN || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { @@ -1469,21 +1482,21 @@ int DetectHttpHeaderTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "two", hhd1->content_len) != 0) { @@ -1520,21 +1533,21 @@ int DetectHttpHeaderTest27(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { @@ -1813,6 +1826,32 @@ static int DetectHttpHeaderTest30(void) return result; } +static int DetectHttpHeaderIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "flow:to_server; " + "content:\"one\"; http_header; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_header_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ void DetectHttpHeaderRegisterTests(void) @@ -1842,6 +1881,10 @@ void DetectHttpHeaderRegisterTests(void) UtRegisterTest("DetectHttpHeaderTest28", DetectHttpHeaderTest28); UtRegisterTest("DetectHttpHeaderTest29", DetectHttpHeaderTest29); UtRegisterTest("DetectHttpHeaderTest30", DetectHttpHeaderTest30); + + UtRegisterTest("DetectHttpHeaderIsdataatParseTest", + DetectHttpHeaderIsdataatParseTest); + #endif /* UNITTESTS */ return; diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index 6f5c6ada7e22..e7c122bcd3ae 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -60,9 +60,12 @@ #include "detect-engine-hrhd.h" #include "stream-tcp.h" -int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpRawHeaderRegisterTests(void); -void DetectHttpRawHeaderFree(void *); +static int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpRawHeaderRegisterTests(void); +static void DetectHttpRawHeaderFree(void *); +static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s); +static void DetectHttpRawHeaderSetupCallback(Signature *s); +static int g_http_raw_header_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_raw_header" keyword. @@ -79,20 +82,27 @@ void DetectHttpRawHeaderRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("http_raw_header", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HRHDMATCH, 2, + DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOSERVER, 2, PrefilterTxRequestHeadersRawRegister); - DetectMpmAppLayerRegister("http_raw_header", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HRHDMATCH, 2, + DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOCLIENT, 2, PrefilterTxResponseHeadersRawRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HRHDMATCH, + DetectAppLayerInspectEngineRegister2("http_raw_header", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpRawHeader); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_HRHDMATCH, + DetectAppLayerInspectEngineRegister2("http_raw_header", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpRawHeader); - return; + + DetectBufferTypeSetDescriptionByName("http_raw_header", + "raw http headers"); + + DetectBufferTypeRegisterValidateCallback("http_raw_header", + DetectHttpRawHeaderValidateCallback); + DetectBufferTypeRegisterSetupCallback("http_raw_header", + DetectHttpRawHeaderSetupCallback); + + g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header"); } @@ -131,15 +141,34 @@ int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_RAW_HEADER, - DETECT_SM_LIST_HRHDMATCH, + g_http_raw_header_buffer_id, ALPROTO_HTTP, NULL); } +static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s) +{ + if ((s->flags & (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) { + SCLogError(SC_ERR_INVALID_SIGNATURE,"http_raw_header signature " + "without a flow direction. Use flow:to_server for " + "inspecting request headers or flow:to_client for " + "inspecting response headers."); + SCReturnInt(FALSE); + } + return TRUE; +} + +static void DetectHttpRawHeaderSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + /************************************Unittests*********************************/ #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** @@ -167,7 +196,7 @@ static int DetectHttpRawHeaderTest01(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id]; if (sm != NULL) { result &= (sm->type == DETECT_CONTENT); result &= (sm->next == NULL); @@ -1256,13 +1285,13 @@ int DetectHttpRawHeaderTest20(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL\n"); goto end; } - DetectContentData *hrhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hrhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *hrhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; + DetectContentData *hrhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (hrhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hrhd1->content, "one", hrhd1->content_len) != 0 || hrhd2->flags != DETECT_CONTENT_DISTANCE || @@ -1300,13 +1329,13 @@ int DetectHttpRawHeaderTest21(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL\n"); goto end; } - DetectContentData *hrhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hrhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *hrhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; + DetectContentData *hrhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (hrhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hrhd1->content, "one", hrhd1->content_len) != 0 || hrhd2->flags != DETECT_CONTENT_WITHIN || @@ -1416,21 +1445,21 @@ int DetectHttpRawHeaderTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_WITHIN || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { @@ -1467,21 +1496,21 @@ int DetectHttpRawHeaderTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "two", hhd1->content_len) != 0) { @@ -1518,21 +1547,21 @@ int DetectHttpRawHeaderTest27(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { @@ -1547,6 +1576,32 @@ int DetectHttpRawHeaderTest27(void) return result; } +static int DetectHttpRawHeaderIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "flow:to_server; " + "content:\"one\"; http_raw_header; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_raw_header_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ void DetectHttpRawHeaderRegisterTests(void) @@ -1573,6 +1628,9 @@ void DetectHttpRawHeaderRegisterTests(void) UtRegisterTest("DetectHttpRawHeaderTest25", DetectHttpRawHeaderTest25); UtRegisterTest("DetectHttpRawHeaderTest26", DetectHttpRawHeaderTest26); UtRegisterTest("DetectHttpRawHeaderTest27", DetectHttpRawHeaderTest27); + + UtRegisterTest("DetectHttpRawHeaderIsdataatParseTest", + DetectHttpRawHeaderIsdataatParseTest); #endif /* UNITTESTS */ return; diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 3b9e087efbac..a5d28923ddf3 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -560,94 +560,6 @@ int DetectIsdataatTestParse09(void) return result; } -int DetectIsdataatTestParse10(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; http_header; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -int DetectIsdataatTestParse11(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "flow:to_server; content:\"one\"; http_raw_header; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - /** * \test dns_query with isdataat relative to it */ @@ -817,8 +729,6 @@ void DetectIsdataatRegisterTests(void) UtRegisterTest("DetectIsdataatTestParse05", DetectIsdataatTestParse05); UtRegisterTest("DetectIsdataatTestParse06", DetectIsdataatTestParse06); UtRegisterTest("DetectIsdataatTestParse09", DetectIsdataatTestParse09); - UtRegisterTest("DetectIsdataatTestParse10", DetectIsdataatTestParse10); - UtRegisterTest("DetectIsdataatTestParse11", DetectIsdataatTestParse11); UtRegisterTest("DetectIsdataatTestParse16", DetectIsdataatTestParse16); UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01); diff --git a/src/detect-lua.c b/src/detect-lua.c index e349d66f6e96..652dea1e689a 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1009,11 +1009,13 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) } else if (lua->flags & DATATYPE_HTTP_REQUEST_UA) { int list = DetectBufferTypeGetByName("http_user_agent"); SigMatchAppendSMToList(s, sm, list); - } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HHDMATCH); - else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRHDMATCH); - else { + } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) { + int list = DetectBufferTypeGetByName("http_header"); + SigMatchAppendSMToList(s, sm, list); + } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) { + int list = DetectBufferTypeGetByName("http_raw_header"); + SigMatchAppendSMToList(s, sm, list); + } else { int list = DetectBufferTypeGetByName("http_request_line"); SigMatchAppendSMToList(s, sm, list); } diff --git a/src/detect-parse.c b/src/detect-parse.c index 842679a376cb..513e79ad665b 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -143,8 +143,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); CASE_CODE_STRING(DETECT_SM_LIST_HRUDMATCH, "http_raw_uri"); CASE_CODE_STRING(DETECT_SM_LIST_HCBDMATCH, "http_client_body"); - CASE_CODE_STRING(DETECT_SM_LIST_HHDMATCH, "http_header"); - CASE_CODE_STRING(DETECT_SM_LIST_HRHDMATCH, "http_raw_header"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -177,8 +175,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_PMATCH); CASE_CODE(DETECT_SM_LIST_HRUDMATCH); CASE_CODE(DETECT_SM_LIST_HCBDMATCH); - CASE_CODE(DETECT_SM_LIST_HHDMATCH); - CASE_CODE(DETECT_SM_LIST_HRHDMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); @@ -1450,16 +1446,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } - if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) { - if ((s->flags & (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) { - SCLogError(SC_ERR_INVALID_SIGNATURE,"http_raw_header signature " - "without a flow direction. Use flow:to_server for " - "inspecting request headers or flow:to_client for " - "inspecting response headers."); - SCReturnInt(0); - } - } - //if (s->alproto != ALPROTO_UNKNOWN) { // if (s->flags & SIG_FLAG_STATE_MATCH) { // if (s->alproto == ALPROTO_DNS) { @@ -1524,9 +1510,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } if (s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HHDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HRHDMATCH]) + s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " "specific matches (like dsize, flags, ttl) with stream / " diff --git a/src/detect-pcre.c b/src/detect-pcre.c index d430193e5524..59d2ee1bef24 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -433,23 +433,26 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, *sm_list = DetectPcreSetList(*sm_list, list); break; } - case 'H': /* snort's option */ + case 'H': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'H' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HHDMATCH); + int list = DetectBufferTypeGetByName("http_header"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'I': /* snort's option */ + } case 'I': /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'I' inconsistent with 'B'"); goto error; } *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HRUDMATCH); break; - case 'D': /* snort's option */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HRHDMATCH); + case 'D': { /* snort's option */ + int list = DetectBufferTypeGetByName("http_raw_header"); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } case 'M': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'M' inconsistent with 'B'"); @@ -684,9 +687,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst goto error; if (parsed_sm_list == DETECT_SM_LIST_HRUDMATCH || - parsed_sm_list == DETECT_SM_LIST_HCBDMATCH || - parsed_sm_list == DETECT_SM_LIST_HHDMATCH || - parsed_sm_list == DETECT_SM_LIST_HRHDMATCH) + parsed_sm_list == DETECT_SM_LIST_HCBDMATCH) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " @@ -717,8 +718,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst break; case DETECT_SM_LIST_HRUDMATCH: - case DETECT_SM_LIST_HHDMATCH: - case DETECT_SM_LIST_HRHDMATCH: s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; sm_list = parsed_sm_list; @@ -797,6 +796,7 @@ void DetectPcreFree(void *ptr) #ifdef UNITTESTS /* UNITTESTS */ static int g_file_data_buffer_id = 0; +static int g_http_header_buffer_id = 0; /** * \test DetectPcreParseTest01 make sure we don't allow invalid opts 7. @@ -3031,10 +3031,10 @@ static int DetectPcreFlowvarCapture01(void) s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; sid:1;)"); FAIL_IF(s == NULL); - FAIL_IF(s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE); - DetectPcreData *pd = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || + s->sm_lists[g_http_header_buffer_id]->next == NULL || + s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); + DetectPcreData *pd = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -3132,18 +3132,18 @@ static int DetectPcreFlowvarCapture02(void) s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:1; sid:1;)"); FAIL_IF(s == NULL); - FAIL_IF(s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE); - DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || + s->sm_lists[g_http_header_buffer_id]->next == NULL || + s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); + DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:3; sid:2;)"); FAIL_IF(s == NULL); - FAIL_IF(s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE); - DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || + s->sm_lists[g_http_header_buffer_id]->next == NULL || + s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); + DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; FAIL_IF(pd1->capidx != pd2->capidx); @@ -3248,18 +3248,18 @@ static int DetectPcreFlowvarCapture03(void) s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:1; sid:1;)"); FAIL_IF(s == NULL); - FAIL_IF(s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE); - DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || + s->sm_lists[g_http_header_buffer_id]->next == NULL || + s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); + DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:3; sid:2;)"); FAIL_IF(s == NULL); - FAIL_IF(s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE); - DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || + s->sm_lists[g_http_header_buffer_id]->next == NULL || + s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); + DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; FAIL_IF(pd1->capidx != pd2->capidx); @@ -3338,6 +3338,7 @@ void DetectPcreRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01); UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02); diff --git a/src/detect.c b/src/detect.c index 5ab7af0c3d27..b91192d91ce4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1915,12 +1915,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL) - return 0; - - if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; @@ -1999,12 +1993,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL) - return 0; - - if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; @@ -2109,8 +2097,6 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { SCReturnInt(0); @@ -2269,16 +2255,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires http app state"); } - if (s->init_data->smlists[DETECT_SM_LIST_HHDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->init_data->smlists[DETECT_SM_LIST_HRHDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); diff --git a/src/detect.h b/src/detect.h index ce6a609b5ef2..1b634fb02862 100644 --- a/src/detect.h +++ b/src/detect.h @@ -119,10 +119,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_HRUDMATCH = DETECT_SM_LIST_BUILTIN_MAX, /* list for http_client_body keyword and the ones relative to it */ DETECT_SM_LIST_HCBDMATCH, - /* 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, /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, From ee55aefa1cac7f57b498ae50fe66397cb4cf4278 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 9 Dec 2016 18:09:48 +0100 Subject: [PATCH 2379/2553] http_client_body: dynamic buffer --- src/detect-engine-analyzer.c | 9 +- src/detect-engine.c | 2 - src/detect-fast-pattern.c | 44 ++++----- src/detect-http-client-body.c | 172 +++++++++++++++++++++------------- src/detect-isdataat.c | 45 --------- src/detect-lua.c | 7 +- src/detect-parse.c | 8 +- src/detect-pcre.c | 16 +--- src/detect.c | 12 --- src/detect.h | 2 - 10 files changed, 143 insertions(+), 174 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 7990afc01992..ec5504d50015 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -114,8 +114,6 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "content\n"); else if (list_type == DETECT_SM_LIST_HRUDMATCH) fprintf(fp_engine_analysis_FD, "http raw uri content\n"); - else if (list_type == DETECT_SM_LIST_HCBDMATCH) - fprintf(fp_engine_analysis_FD, "http client body content\n"); else { const char *desc = DetectBufferTypeGetDescriptionById(list_type); const char *name = DetectBufferTypeGetNameById(list_type); @@ -452,8 +450,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) } else if (list_type == DETECT_SM_LIST_HRUDMATCH) fprintf(rule_engine_analysis_FD, "http raw uri content"); - else if (list_type == DETECT_SM_LIST_HCBDMATCH) - fprintf(rule_engine_analysis_FD, "http client body content"); else if (list_type == DETECT_SM_LIST_DNSQUERYNAME_MATCH) fprintf(rule_engine_analysis_FD, "dns query name content"); else if (list_type == DETECT_SM_LIST_TLSSNI_MATCH) @@ -562,6 +558,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) const int httpstatmsg_id = DetectBufferTypeGetByName("http_stat_msg"); const int httpheader_id = DetectBufferTypeGetByName("http_header"); const int httprawheader_id = DetectBufferTypeGetByName("http_raw_header"); + const int httpclientbody_id = DetectBufferTypeGetByName("http_client_body"); if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; @@ -585,7 +582,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) SigMatch *sm = NULL; for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_PCRE) { - if (list_id == DETECT_SM_LIST_HCBDMATCH) { + if (list_id == httpclientbody_id) { rule_pcre_http += 1; http_client_body_buf += 1; raw_http_buf += 1; @@ -666,7 +663,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) http_cookie_buf += 1; } } - else if (list_id == DETECT_SM_LIST_HCBDMATCH) { + else if (list_id == httpclientbody_id) { rule_content_http += 1; raw_http_buf += 1; http_client_body_buf += 1; diff --git a/src/detect-engine.c b/src/detect-engine.c index 6b64f08cca82..3ffcd8cc7c8c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2800,8 +2800,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_HRUDMATCH: return "http raw uri"; - case DETECT_SM_LIST_HCBDMATCH: - return "http client body"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 58925d51f670..cc42066b0f35 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -332,6 +332,7 @@ static int g_http_stat_code_buffer_id = 0; static int g_http_stat_msg_buffer_id = 0; static int g_http_raw_header_buffer_id = 0; static int g_http_header_buffer_id = 0; +static int g_http_client_body_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -3768,7 +3769,7 @@ int DetectFastPatternTest134(void) "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3806,7 +3807,7 @@ int DetectFastPatternTest135(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -3843,7 +3844,7 @@ int DetectFastPatternTest136(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -3875,7 +3876,7 @@ int DetectFastPatternTest137(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -3909,7 +3910,7 @@ int DetectFastPatternTest138(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4139,7 +4140,7 @@ int DetectFastPatternTest148(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4169,7 +4170,7 @@ int DetectFastPatternTest149(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; within:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4199,7 +4200,7 @@ int DetectFastPatternTest150(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; offset:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4229,7 +4230,7 @@ int DetectFastPatternTest151(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; depth:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4259,7 +4260,7 @@ int DetectFastPatternTest152(void) "(content:!\"one\"; fast_pattern; http_client_body; content:\"two\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4378,7 +4379,7 @@ int DetectFastPatternTest157(void) "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4408,7 +4409,7 @@ int DetectFastPatternTest158(void) "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4438,7 +4439,7 @@ int DetectFastPatternTest159(void) "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4468,7 +4469,7 @@ int DetectFastPatternTest160(void) "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4498,7 +4499,7 @@ int DetectFastPatternTest161(void) "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4528,7 +4529,7 @@ int DetectFastPatternTest162(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4558,7 +4559,7 @@ int DetectFastPatternTest163(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4588,7 +4589,7 @@ int DetectFastPatternTest164(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4618,7 +4619,7 @@ int DetectFastPatternTest165(void) "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4717,7 +4718,7 @@ int DetectFastPatternTest169(void) "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4836,7 +4837,7 @@ int DetectFastPatternTest174(void) "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18843,6 +18844,7 @@ void DetectFastPatternRegisterTests(void) g_http_stat_msg_buffer_id = DetectBufferTypeGetByName("http_stat_msg"); g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header"); + g_http_client_body_buffer_id = DetectBufferTypeGetByName("http_client_body"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index f805fda82f28..9e3d2cc7e93d 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -58,9 +58,11 @@ #include "detect-engine-hcbd.h" #include "stream-tcp.h" -int DetectHttpClientBodySetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpClientBodyRegisterTests(void); -void DetectHttpClientBodyFree(void *); +static int DetectHttpClientBodySetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpClientBodyRegisterTests(void); +static void DetectHttpClientBodyFree(void *); +static void DetectHttpClientBodySetupCallback(Signature *s); +static int g_http_client_body_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_client_body" keyword. @@ -79,19 +81,27 @@ void DetectHttpClientBodyRegister(void) sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_NOOPT ; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_PAYLOAD ; - DetectMpmAppLayerRegister("http_client_body", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HCBDMATCH, 2, + DetectAppLayerMpmRegister("http_client_body", SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestBodyRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HCBDMATCH, + DetectAppLayerInspectEngineRegister2("http_client_body", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpClientBody); + + DetectBufferTypeSetDescriptionByName("http_client_body", + "http request body"); + + DetectBufferTypeRegisterSetupCallback("http_client_body", + DetectHttpClientBodySetupCallback); + + g_http_client_body_buffer_id = DetectBufferTypeGetByName("http_client_body"); } static void DetectHttpClientBodySetupCallback(Signature *s) { + SCLogDebug("callback invoked by %u", s->id); AppLayerHtpEnableRequestBodyCallback(); - return; + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; } /** @@ -111,9 +121,9 @@ int DetectHttpClientBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_CLIENT_BODY, - DETECT_SM_LIST_HCBDMATCH, + g_http_client_body_buffer_id, ALPROTO_HTTP, - DetectHttpClientBodySetupCallback); + NULL); } /** @@ -141,6 +151,7 @@ void DetectHttpClientBodyFree(void *ptr) #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** @@ -1751,15 +1762,15 @@ int DetectHttpClientBodyTest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1806,15 +1817,15 @@ int DetectHttpClientBodyTest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1860,15 +1871,15 @@ int DetectHttpClientBodyTest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1915,15 +1926,15 @@ int DetectHttpClientBodyTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1971,15 +1982,15 @@ int DetectHttpClientBodyTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2054,15 +2065,15 @@ int DetectHttpClientBodyTest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2109,13 +2120,13 @@ int DetectHttpClientBodyTest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_DISTANCE || @@ -2153,13 +2164,13 @@ int DetectHttpClientBodyTest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_WITHIN || @@ -2269,21 +2280,21 @@ int DetectHttpClientBodyTest34(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hcbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { @@ -2320,21 +2331,21 @@ int DetectHttpClientBodyTest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "two", hcbd1->content_len) != 0) { @@ -2371,21 +2382,21 @@ int DetectHttpClientBodyTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hcbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { @@ -2400,6 +2411,31 @@ int DetectHttpClientBodyTest36(void) return result; } +static int DetectHttpClientBodyIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "content:\"one\"; http_client_body; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_client_body_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ void DetectHttpClientBodyRegisterTests(void) @@ -2436,6 +2472,10 @@ void DetectHttpClientBodyRegisterTests(void) UtRegisterTest("DetectHttpClientBodyTest34", DetectHttpClientBodyTest34); UtRegisterTest("DetectHttpClientBodyTest35", DetectHttpClientBodyTest35); UtRegisterTest("DetectHttpClientBodyTest36", DetectHttpClientBodyTest36); + + UtRegisterTest("DetectHttpClientBodyIsdataatParseTest", + DetectHttpClientBodyIsdataatParseTest); + #endif /* UNITTESTS */ return; diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index a5d28923ddf3..d6a459934e29 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -516,50 +516,6 @@ int DetectIsdataatTestParse06(void) return result; } -int DetectIsdataatTestParse09(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; http_client_body; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - /** * \test dns_query with isdataat relative to it */ @@ -728,7 +684,6 @@ void DetectIsdataatRegisterTests(void) UtRegisterTest("DetectIsdataatTestParse04", DetectIsdataatTestParse04); UtRegisterTest("DetectIsdataatTestParse05", DetectIsdataatTestParse05); UtRegisterTest("DetectIsdataatTestParse06", DetectIsdataatTestParse06); - UtRegisterTest("DetectIsdataatTestParse09", DetectIsdataatTestParse09); UtRegisterTest("DetectIsdataatTestParse16", DetectIsdataatTestParse16); UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01); diff --git a/src/detect-lua.c b/src/detect-lua.c index 652dea1e689a..618a8f9a7735 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -994,9 +994,10 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) if (lua->flags & DATATYPE_HTTP_RESPONSE_BODY) { int list = DetectBufferTypeGetByName("file_data"); SigMatchAppendSMToList(s, sm, list); - } else if (lua->flags & DATATYPE_HTTP_REQUEST_BODY) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCBDMATCH); - else if (lua->flags & DATATYPE_HTTP_URI) { + } else if (lua->flags & DATATYPE_HTTP_REQUEST_BODY) { + int list = DetectBufferTypeGetByName("http_client_body"); + SigMatchAppendSMToList(s, sm, list); + } else if (lua->flags & DATATYPE_HTTP_URI) { int list = DetectBufferTypeGetByName("http_uri"); SigMatchAppendSMToList(s, sm, list); } else if (lua->flags & DATATYPE_HTTP_URI_RAW) diff --git a/src/detect-parse.c b/src/detect-parse.c index 513e79ad665b..dbfc317b00a8 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -142,7 +142,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); CASE_CODE_STRING(DETECT_SM_LIST_HRUDMATCH, "http_raw_uri"); - CASE_CODE_STRING(DETECT_SM_LIST_HCBDMATCH, "http_client_body"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -174,7 +173,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_MATCH); CASE_CODE(DETECT_SM_LIST_PMATCH); CASE_CODE(DETECT_SM_LIST_HRUDMATCH); - CASE_CODE(DETECT_SM_LIST_HCBDMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); @@ -1410,8 +1408,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (fd->flags & FLOW_PKT_TOCLIENT) { /* check for request + from_server/to_client */ - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use uricontent " "/http_uri , raw_uri, http_client_body, " "http_method, http_user_agent keywords " @@ -1509,8 +1506,7 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } - if (s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH] || - s->init_data->smlists_tail[DETECT_SM_LIST_HCBDMATCH]) + if (s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " "specific matches (like dsize, flags, ttl) with stream / " diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 59d2ee1bef24..c57edd7cb795 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -471,10 +471,12 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, *sm_list = DetectPcreSetList(*sm_list, list); break; } - case 'P': + case 'P': { /* snort's option (http request body inspection) */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HCBDMATCH); + int list = DetectBufferTypeGetByName("http_client_body"); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } case 'Q': { int list = DetectBufferTypeGetByName("file_data"); /* suricata extension (http response body inspection) */ @@ -686,8 +688,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst if (DetectPcreParseCapture(regexstr, de_ctx, pd) < 0) goto error; - if (parsed_sm_list == DETECT_SM_LIST_HRUDMATCH || - parsed_sm_list == DETECT_SM_LIST_HCBDMATCH) + if (parsed_sm_list == DETECT_SM_LIST_HRUDMATCH) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " @@ -710,13 +711,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst sm_list = s->init_data->list; } else { switch(parsed_sm_list) { - case DETECT_SM_LIST_HCBDMATCH: - AppLayerHtpEnableRequestBodyCallback(); - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_HTTP; - sm_list = parsed_sm_list; - break; - case DETECT_SM_LIST_HRUDMATCH: s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; diff --git a/src/detect.c b/src/detect.c index b91192d91ce4..4e7c019fc9a6 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1912,9 +1912,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; @@ -1990,9 +1987,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; @@ -2096,7 +2090,6 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { SCReturnInt(0); @@ -2250,11 +2243,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires dce state"); } - if (s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); diff --git a/src/detect.h b/src/detect.h index 1b634fb02862..5e6d1eb93911 100644 --- a/src/detect.h +++ b/src/detect.h @@ -117,8 +117,6 @@ enum DetectSigmatchListEnum { /* list for http_raw_uri keyword and the ones relative to it */ DETECT_SM_LIST_HRUDMATCH = DETECT_SM_LIST_BUILTIN_MAX, - /* list for http_client_body keyword and the ones relative to it */ - DETECT_SM_LIST_HCBDMATCH, /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT, From 6f867c3c737dc510d671aaae4e86057a7c72f3f1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 9 Dec 2016 18:29:44 +0100 Subject: [PATCH 2380/2553] http_raw_uri: dynamic buffer --- src/detect-engine-analyzer.c | 9 ++--- src/detect-engine.c | 2 -- src/detect-fast-pattern.c | 44 ++++++++++++------------ src/detect-http-raw-uri.c | 66 +++++++++++++++++++++--------------- src/detect-lua.c | 7 ++-- src/detect-parse.c | 29 ---------------- src/detect-pcre.c | 28 +++------------ src/detect-urilen.c | 4 ++- src/detect.c | 16 ++------- src/detect.h | 4 +-- 10 files changed, 79 insertions(+), 130 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index ec5504d50015..68de322fb552 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -112,8 +112,6 @@ void EngineAnalysisFP(Signature *s, char *line) int list_type = SigMatchListSMBelongsTo(s, mpm_sm); if (list_type == DETECT_SM_LIST_PMATCH) fprintf(fp_engine_analysis_FD, "content\n"); - else if (list_type == DETECT_SM_LIST_HRUDMATCH) - fprintf(fp_engine_analysis_FD, "http raw uri content\n"); else { const char *desc = DetectBufferTypeGetDescriptionById(list_type); const char *name = DetectBufferTypeGetNameById(list_type); @@ -448,8 +446,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "%s", payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream"); } - else if (list_type == DETECT_SM_LIST_HRUDMATCH) - fprintf(rule_engine_analysis_FD, "http raw uri content"); else if (list_type == DETECT_SM_LIST_DNSQUERYNAME_MATCH) fprintf(rule_engine_analysis_FD, "dns query name content"); else if (list_type == DETECT_SM_LIST_TLSSNI_MATCH) @@ -559,6 +555,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) const int httpheader_id = DetectBufferTypeGetByName("http_header"); const int httprawheader_id = DetectBufferTypeGetByName("http_raw_header"); const int httpclientbody_id = DetectBufferTypeGetByName("http_client_body"); + const int httprawuri_id = DetectBufferTypeGetByName("http_raw_uri"); if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; @@ -617,7 +614,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_method_buf += 1; } - else if (list_id == DETECT_SM_LIST_HRUDMATCH) { + else if (list_id == httprawuri_id) { rule_pcre_http += 1; raw_http_buf += 1; http_raw_uri_buf += 1; @@ -678,7 +675,7 @@ void EngineAnalysisRules(const Signature *s, const char *line) raw_http_buf += 1; http_raw_header_buf += 1; } - else if (list_id == DETECT_SM_LIST_HRUDMATCH) { + else if (list_id == httprawuri_id) { rule_content_http += 1; raw_http_buf += 1; http_raw_uri_buf += 1; diff --git a/src/detect-engine.c b/src/detect-engine.c index 3ffcd8cc7c8c..3343448802ce 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2798,8 +2798,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_PMATCH: return "packet/stream payload"; - case DETECT_SM_LIST_HRUDMATCH: - return "http raw uri"; case DETECT_SM_LIST_APP_EVENT: return "app layer events"; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index cc42066b0f35..c2ae8166e909 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -333,6 +333,7 @@ static int g_http_stat_msg_buffer_id = 0; static int g_http_raw_header_buffer_id = 0; static int g_http_header_buffer_id = 0; static int g_http_client_body_buffer_id = 0; +static int g_http_raw_uri_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -9391,7 +9392,7 @@ int DetectFastPatternTest343(void) "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -9429,7 +9430,7 @@ int DetectFastPatternTest344(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -9466,7 +9467,7 @@ int DetectFastPatternTest345(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -9498,7 +9499,7 @@ int DetectFastPatternTest346(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -9532,7 +9533,7 @@ int DetectFastPatternTest347(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id]; DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -9773,7 +9774,7 @@ int DetectFastPatternTest357(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9805,7 +9806,7 @@ int DetectFastPatternTest358(void) "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9837,7 +9838,7 @@ int DetectFastPatternTest359(void) "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9869,7 +9870,7 @@ int DetectFastPatternTest360(void) "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9900,7 +9901,7 @@ int DetectFastPatternTest361(void) "content:\"two\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -10025,7 +10026,7 @@ int DetectFastPatternTest366(void) "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10057,7 +10058,7 @@ int DetectFastPatternTest367(void) "content:\"three\"; http_raw_uri; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10089,7 +10090,7 @@ int DetectFastPatternTest368(void) "content:\"three\"; http_raw_uri; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10121,7 +10122,7 @@ int DetectFastPatternTest369(void) "content:\"three\"; http_raw_uri; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10153,7 +10154,7 @@ int DetectFastPatternTest370(void) "content:\"three\"; http_raw_uri; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10185,7 +10186,7 @@ int DetectFastPatternTest371(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10217,7 +10218,7 @@ int DetectFastPatternTest372(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10249,7 +10250,7 @@ int DetectFastPatternTest373(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10281,7 +10282,7 @@ int DetectFastPatternTest374(void) "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10388,7 +10389,7 @@ int DetectFastPatternTest378(void) "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -10517,7 +10518,7 @@ int DetectFastPatternTest383(void) "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18845,6 +18846,7 @@ void DetectFastPatternRegisterTests(void) g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header"); g_http_client_body_buffer_id = DetectBufferTypeGetByName("http_client_body"); + g_http_raw_uri_buffer_id = DetectBufferTypeGetByName("http_raw_uri"); UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 2ef9a1a72f4d..3079f2e87856 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -57,6 +57,8 @@ static int DetectHttpRawUriSetup(DetectEngineCtx *, Signature *, char *); static void DetectHttpRawUriRegisterTests(void); +static void DetectHttpRawUriSetupCallback(Signature *s); +static int g_http_raw_uri_buffer_id = 0; /** * \brief Registration function for keyword http_raw_uri. @@ -74,15 +76,20 @@ void DetectHttpRawUriRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("http_raw_uri", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HRUDMATCH, 2, + DetectAppLayerMpmRegister("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterTxRawUriRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_HRUDMATCH, + DetectAppLayerInspectEngineRegister2("http_raw_uri", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpRawUri); - return; + DetectBufferTypeSetDescriptionByName("http_raw_uri", + "raw http uri"); + + DetectBufferTypeRegisterSetupCallback("http_raw_uri", + DetectHttpRawUriSetupCallback); + + g_http_raw_uri_buffer_id = DetectBufferTypeGetByName("http_raw_uri"); } /** @@ -99,11 +106,16 @@ static int DetectHttpRawUriSetup(DetectEngineCtx *de_ctx, Signature *s, char *ar { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_RAW_URI, - DETECT_SM_LIST_HRUDMATCH, + g_http_raw_uri_buffer_id, ALPROTO_HTTP, NULL); } +static void DetectHttpRawUriSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} /******************************** UNITESTS **********************************/ @@ -184,7 +196,7 @@ int DetectHttpRawUriTest03(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; @@ -256,19 +268,19 @@ int DetectHttpRawUriTest05(void) printf("sig failed to parse\n"); goto end; } - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) + if (s->sm_lists[g_http_raw_uri_buffer_id] == NULL) goto end; - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH]->type != DETECT_CONTENT) { + if (s->sm_lists[g_http_raw_uri_buffer_id]->type != DETECT_CONTENT) { printf("wrong type\n"); goto end; } char *str = "we are testing http_raw_uri keyword"; int uricomp = memcmp((const char *) - ((DetectContentData*)s->sm_lists[DETECT_SM_LIST_HRUDMATCH]->ctx)->content, + ((DetectContentData*)s->sm_lists[g_http_raw_uri_buffer_id]->ctx)->content, str, strlen(str) - 1); - int urilen = ((DetectContentData*)s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx)->content_len; + int urilen = ((DetectContentData*)s->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx)->content_len; if (uricomp != 0 || urilen != strlen("we are testing http_raw_uri keyword")) { printf("sig failed to parse, content not setup properly\n"); @@ -306,15 +318,15 @@ int DetectHttpRawUriTest12(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL\n"); goto end; } DetectContentData *ud1 = - (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; DetectContentData *ud2 = - (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -353,15 +365,15 @@ int DetectHttpRawUriTest13(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL\n"); goto end; } DetectContentData *ud1 = - (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; DetectContentData *ud2 = - (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || @@ -472,15 +484,15 @@ int DetectHttpRawUriTest17(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL\n"); goto end; } DetectContentData *ud1 = - (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; DetectContentData *ud2 = - (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -520,15 +532,15 @@ int DetectHttpRawUriTest18(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL\n"); goto end; } DetectContentData *ud1 = - (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; DetectContentData *ud2 = - (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || diff --git a/src/detect-lua.c b/src/detect-lua.c index 618a8f9a7735..3d59b5d61bb6 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1000,9 +1000,10 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) } else if (lua->flags & DATATYPE_HTTP_URI) { int list = DetectBufferTypeGetByName("http_uri"); SigMatchAppendSMToList(s, sm, list); - } else if (lua->flags & DATATYPE_HTTP_URI_RAW) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); - else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE || + } else if (lua->flags & DATATYPE_HTTP_URI_RAW) { + int list = DetectBufferTypeGetByName("http_raw_uri"); + SigMatchAppendSMToList(s, sm, list); + } else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE || lua->flags & DATATYPE_HTTP_RESPONSE_COOKIE) { int list = DetectBufferTypeGetByName("http_cookie"); diff --git a/src/detect-parse.c b/src/detect-parse.c index dbfc317b00a8..5b8b93937900 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -141,7 +141,6 @@ const char *DetectListToHumanString(int list) switch (list) { CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); - CASE_CODE_STRING(DETECT_SM_LIST_HRUDMATCH, "http_raw_uri"); CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); @@ -172,7 +171,6 @@ const char *DetectListToString(int list) switch (list) { CASE_CODE(DETECT_SM_LIST_MATCH); CASE_CODE(DETECT_SM_LIST_PMATCH); - CASE_CODE(DETECT_SM_LIST_HRUDMATCH); CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); @@ -1400,24 +1398,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { - if (sm->type == DETECT_FLOW) { - DetectFlowData *fd = (DetectFlowData *)sm->ctx; - if (fd == NULL) - continue; - - if (fd->flags & FLOW_PKT_TOCLIENT) { - /* check for request + from_server/to_client */ - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use uricontent " - "/http_uri , raw_uri, http_client_body, " - "http_method, http_user_agent keywords " - "with flow:to_client or flow:from_server"); - SCReturnInt(0); - } - } - } - } #if 0 // TODO figure out why this is even necessary if ((s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_SMTP) || s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || @@ -1505,15 +1485,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } } - - if (s->init_data->smlists_tail[DETECT_SM_LIST_HRUDMATCH]) - { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " - "specific matches (like dsize, flags, ttl) with stream / " - "state matching by matching on app layer proto (like using " - "http_* keywords)."); - SCReturnInt(0); - } } for (sm = s->init_data->smlists[DETECT_SM_LIST_AMATCH]; sm != NULL; sm = sm->next) { diff --git a/src/detect-pcre.c b/src/detect-pcre.c index c57edd7cb795..29106304cc7c 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -441,13 +441,15 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, int list = DetectBufferTypeGetByName("http_header"); *sm_list = DetectPcreSetList(*sm_list, list); break; - } case 'I': /* snort's option */ + } case 'I': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'I' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HRUDMATCH); + int list = DetectBufferTypeGetByName("http_raw_uri"); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } case 'D': { /* snort's option */ int list = DetectBufferTypeGetByName("http_raw_header"); *sm_list = DetectPcreSetList(*sm_list, list); @@ -688,34 +690,12 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst if (DetectPcreParseCapture(regexstr, de_ctx, pd) < 0) goto error; - if (parsed_sm_list == DETECT_SM_LIST_HRUDMATCH) - { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " - "Conflicting alprotos detected for this rule. Http " - "pcre modifier found along with a different protocol " - "for the rule."); - goto error; - } - if (s->init_data->list != DETECT_SM_LIST_NOTSET) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre found with http " - "modifier set, with file_data/dce_stub_data sticky " - "option set."); - goto error; - } - } - int sm_list = -1; if (s->init_data->list != DETECT_SM_LIST_NOTSET) { s->flags |= SIG_FLAG_APPLAYER; sm_list = s->init_data->list; } else { switch(parsed_sm_list) { - case DETECT_SM_LIST_HRUDMATCH: - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_HTTP; - sm_list = parsed_sm_list; - break; case DETECT_SM_LIST_NOTSET: sm_list = DETECT_SM_LIST_PMATCH; break; diff --git a/src/detect-urilen.c b/src/detect-urilen.c index c853efc31597..02e29395ba93 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -55,6 +55,7 @@ void DetectUrilenFree (void *); void DetectUrilenRegisterTests (void); static int g_http_uri_buffer_id = 0; +static int g_http_raw_uri_buffer_id = 0; /** * \brief Registration function for urilen: keyword @@ -75,6 +76,7 @@ void DetectUrilenRegister(void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); g_http_uri_buffer_id = DetectBufferTypeRegister("http_uri"); + g_http_raw_uri_buffer_id = DetectBufferTypeRegister("http_raw_uri"); } /** @@ -263,7 +265,7 @@ static int DetectUrilenSetup (DetectEngineCtx *de_ctx, Signature *s, char *urile sm->ctx = (void *)urilend; if (urilend->raw_buffer) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); + SigMatchAppendSMToList(s, sm, g_http_raw_uri_buffer_id); else SigMatchAppendSMToList(s, sm, g_http_uri_buffer_id); diff --git a/src/detect.c b/src/detect.c index 4e7c019fc9a6..9f755bf09015 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1912,9 +1912,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -1987,9 +1984,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) - return 0; - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -2088,9 +2082,8 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) SCReturnInt(0); } - if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) { SCReturnInt(0); } @@ -2243,11 +2236,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires dce state"); } - if (s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - SigMatch *sm; for (sm = s->init_data->smlists[DETECT_SM_LIST_AMATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { diff --git a/src/detect.h b/src/detect.h index 5e6d1eb93911..290c7d37eacb 100644 --- a/src/detect.h +++ b/src/detect.h @@ -115,10 +115,8 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_BUILTIN_MAX, - /* list for http_raw_uri keyword and the ones relative to it */ - DETECT_SM_LIST_HRUDMATCH = DETECT_SM_LIST_BUILTIN_MAX, /* app event engine sm list */ - DETECT_SM_LIST_APP_EVENT, + DETECT_SM_LIST_APP_EVENT = DETECT_SM_LIST_BUILTIN_MAX, DETECT_SM_LIST_FILEMATCH, From d2f77978ecafc512b3b2ce597a29f18f4383d7d5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 9 Dec 2016 19:01:01 +0100 Subject: [PATCH 2381/2553] detect-parse: content modifier cleanup --- src/detect-http-client-body.c | 3 +-- src/detect-http-cookie.c | 3 +-- src/detect-http-header.c | 3 +-- src/detect-http-hh.c | 3 +-- src/detect-http-hrh.c | 3 +-- src/detect-http-method.c | 3 +-- src/detect-http-raw-header.c | 3 +-- src/detect-http-raw-uri.c | 3 +-- src/detect-http-server-body.c | 2 +- src/detect-http-stat-code.c | 3 +-- src/detect-http-stat-msg.c | 3 +-- src/detect-http-ua.c | 3 +-- src/detect-http-uri.c | 3 +-- src/detect-parse.c | 8 +++----- src/detect-parse.h | 6 +++--- 15 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 9e3d2cc7e93d..9ec6be6d398e 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -122,8 +122,7 @@ int DetectHttpClientBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_CLIENT_BODY, g_http_client_body_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } /** diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 56f38e7bf4b3..1cc61fe8170f 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -136,8 +136,7 @@ static int DetectHttpCookieSetup(DetectEngineCtx *de_ctx, Signature *s, char *st return DetectEngineContentModifierBufferSetup(de_ctx, s, str, DETECT_AL_HTTP_COOKIE, g_http_cookie_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } static void DetectHttpCookieSetupCallback(Signature *s) diff --git a/src/detect-http-header.c b/src/detect-http-header.c index af1524f83419..55a248b1429f 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -140,8 +140,7 @@ int DetectHttpHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_HEADER, g_http_header_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } static void DetectHttpHeaderSetupCallback(Signature *s) diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 1abaf8a8c2e0..5e51c7cba90d 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -119,8 +119,7 @@ int DetectHttpHHSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_HOST, g_http_host_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } static void DetectHttpHostSetupCallback(Signature *s) diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index 7c9022e98dfe..439eaef78595 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -115,8 +115,7 @@ int DetectHttpHRHSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_RAW_HOST, g_http_raw_host_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } static void DetectHttpHostRawSetupCallback(Signature *s) diff --git a/src/detect-http-method.c b/src/detect-http-method.c index af703c9a0f21..3fa059cb770f 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -119,8 +119,7 @@ static int DetectHttpMethodSetup(DetectEngineCtx *de_ctx, Signature *s, char *st return DetectEngineContentModifierBufferSetup(de_ctx, s, str, DETECT_AL_HTTP_METHOD, g_http_method_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } /** diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index e7c122bcd3ae..b1a03254d79d 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -142,8 +142,7 @@ int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_RAW_HEADER, g_http_raw_header_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s) diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 3079f2e87856..29f2c69308c9 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -107,8 +107,7 @@ static int DetectHttpRawUriSetup(DetectEngineCtx *de_ctx, Signature *s, char *ar return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_RAW_URI, g_http_raw_uri_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } static void DetectHttpRawUriSetupCallback(Signature *s) diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index 9c40d480d2f5..b2157d8fefc1 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -103,7 +103,7 @@ int DetectHttpServerBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_SERVER_BODY, g_file_data_buffer_id, - ALPROTO_HTTP, NULL); + ALPROTO_HTTP); } /** diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index 2749584bb85e..8a3b4d4b6eff 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -117,8 +117,7 @@ static int DetectHttpStatCodeSetup(DetectEngineCtx *de_ctx, Signature *s, char * return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_STAT_CODE, g_http_stat_code_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } static void DetectHttpStatCodeSetupCallback(Signature *s) diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index c61c6659234d..d3a916c2b706 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -117,8 +117,7 @@ static int DetectHttpStatMsgSetup(DetectEngineCtx *de_ctx, Signature *s, char *a return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_STAT_MSG, g_http_stat_msg_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } static void DetectHttpStatMsgSetupCallback(Signature *s) diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index 625d28755015..5e0824dab7a7 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -116,8 +116,7 @@ int DetectHttpUASetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_USER_AGENT, g_http_ua_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } static void DetectHttpUASetupCallback(Signature *s) diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 1d6b102785c8..45acf4a7db42 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -110,8 +110,7 @@ int DetectHttpUriSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) return DetectEngineContentModifierBufferSetup(de_ctx, s, str, DETECT_AL_HTTP_URI, g_http_uri_buffer_id, - ALPROTO_HTTP, - NULL); + ALPROTO_HTTP); } static void DetectHttpUriSetupCallback(Signature *s) diff --git a/src/detect-parse.c b/src/detect-parse.c index 5b8b93937900..1886ee9081dd 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -194,10 +194,10 @@ const char *DetectListToString(int list) return "unknown"; } +/** \param arg NULL or empty string */ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, - Signature *s, const char *arg, - int sm_type, int sm_list, - AppProto alproto, void (*CustomCallback)(Signature *s)) + Signature *s, const char *arg, int sm_type, int sm_list, + AppProto alproto) { SigMatch *sm = NULL; int ret = -1; @@ -263,8 +263,6 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, } } } - if (CustomCallback != NULL) - CustomCallback(s); s->alproto = alproto; s->flags |= SIG_FLAG_APPLAYER; diff --git a/src/detect-parse.h b/src/detect-parse.h index 9dfe5ac2191a..15f509226695 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -57,9 +57,9 @@ int SigMatchListSMBelongsTo(const Signature *, const SigMatch *); int DetectParseDupSigHashInit(DetectEngineCtx *); void DetectParseDupSigHashFree(DetectEngineCtx *); -int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg, - int sm_type, int sm_list, - AppProto alproto, void (*CustomCallback)(Signature *s)); +int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, + Signature *s, const char *arg, int sm_type, int sm_list, + AppProto alproto); const char *DetectListToHumanString(int list); const char *DetectListToString(int list); From d9b3ae6cd6da2d8939618a763aa513a774a36b92 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 10 Dec 2016 10:49:51 +0100 Subject: [PATCH 2382/2553] dns: use dynamic buffers --- src/detect-dns-query.c | 58 ++++++++++++++++++++++++++++++------ src/detect-engine-analyzer.c | 2 -- src/detect-engine.c | 7 ----- src/detect-isdataat.c | 51 ------------------------------- src/detect-lua.c | 9 ++++-- src/detect-parse.c | 6 ---- src/detect.h | 4 --- 7 files changed, 55 insertions(+), 82 deletions(-) diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index a5e7823afbd8..573f021f9a5e 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -60,6 +60,7 @@ static int DetectDnsQuerySetup (DetectEngineCtx *, Signature *, char *); static void DetectDnsQueryRegisterTests(void); +static int g_dns_query_buffer_id = 0; /** * \brief Registration function for keyword: dns_query @@ -77,21 +78,30 @@ void DetectDnsQueryRegister (void) sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("dns_query", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_DNSQUERYNAME_MATCH, 2, + DetectAppLayerMpmRegister("dns_query", SIG_FLAG_TOSERVER, 2, PrefilterTxDnsQueryRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_DNS, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_DNSQUERYNAME_MATCH, + DetectAppLayerInspectEngineRegister2("dns_query", + ALPROTO_DNS, SIG_FLAG_TOSERVER, DetectEngineInspectDnsQueryName); + DetectBufferTypeSetDescriptionByName("dns_query", + "dns request query"); + + g_dns_query_buffer_id = DetectBufferTypeGetByName("dns_query"); + /* register these generic engines from here for now */ - DetectAppLayerInspectEngineRegister(ALPROTO_DNS, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_DNSREQUEST_MATCH, + DetectAppLayerInspectEngineRegister2("dns_request", + ALPROTO_DNS, SIG_FLAG_TOSERVER, DetectEngineInspectDnsRequest); - DetectAppLayerInspectEngineRegister(ALPROTO_DNS, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_DNSRESPONSE_MATCH, + DetectAppLayerInspectEngineRegister2("dns_response", + ALPROTO_DNS, SIG_FLAG_TOCLIENT, DetectEngineInspectDnsResponse); + + DetectBufferTypeSetDescriptionByName("dns_request", + "dns requests"); + DetectBufferTypeSetDescriptionByName("dns_response", + "dns responses"); } @@ -108,12 +118,14 @@ void DetectDnsQueryRegister (void) static int DetectDnsQuerySetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->init_data->list = DETECT_SM_LIST_DNSQUERYNAME_MATCH; + s->init_data->list = g_dns_query_buffer_id; s->alproto = ALPROTO_DNS; return 0; } #ifdef UNITTESTS +#include "detect-isdataat.h" + /** \test simple google.com query matching */ static int DetectDnsQueryTest01(void) { @@ -1159,6 +1171,31 @@ static int DetectDnsQueryTest07(void) return result; } +static int DetectDnsQueryIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert dns any any -> any any (" + "dns_query; content:\"one\"; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_dns_query_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif static void DetectDnsQueryRegisterTests(void) @@ -1174,5 +1211,8 @@ static void DetectDnsQueryRegisterTests(void) UtRegisterTest("DetectDnsQueryTest06 -- pcre", DetectDnsQueryTest06); UtRegisterTest("DetectDnsQueryTest07 -- app layer event", DetectDnsQueryTest07); + + UtRegisterTest("DetectDnsQueryIsdataatParseTest", + DetectDnsQueryIsdataatParseTest); #endif } diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 68de322fb552..06647980c2d4 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -446,8 +446,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "%s", payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream"); } - else if (list_type == DETECT_SM_LIST_DNSQUERYNAME_MATCH) - fprintf(rule_engine_analysis_FD, "dns query name content"); else if (list_type == DETECT_SM_LIST_TLSSNI_MATCH) fprintf(rule_engine_analysis_FD, "tls sni extension content"); else if (list_type == DETECT_SM_LIST_TLSISSUER_MATCH) diff --git a/src/detect-engine.c b/src/detect-engine.c index 3343448802ce..994a44290a61 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2811,13 +2811,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_FILEMATCH: return "file"; - case DETECT_SM_LIST_DNSQUERYNAME_MATCH: - return "dns query name"; - case DETECT_SM_LIST_DNSREQUEST_MATCH: - return "dns request"; - case DETECT_SM_LIST_DNSRESPONSE_MATCH: - return "dns response"; - case DETECT_SM_LIST_TLSSNI_MATCH: return "tls sni extension"; case DETECT_SM_LIST_TLSISSUER_MATCH: diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index d6a459934e29..5a018a5891b9 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -516,56 +516,6 @@ int DetectIsdataatTestParse06(void) return result; } -/** - * \test dns_query with isdataat relative to it - */ -static int DetectIsdataatTestParse16(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing dns_query and isdataat\"; " - "dns_query; isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse: "); - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH] == NULL) { - printf("dns_query list empty: "); - goto end; - } - - if (s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH]->type != DETECT_ISDATAAT) { - printf("last dns_query body sm not isdataat: "); - goto end; - } - - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DNSQUERYNAME_MATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - goto end; - } - - result = 1; - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - /** * \test DetectIsdataatTestPacket01 is a test to check matches of * isdataat, and isdataat relative @@ -684,7 +634,6 @@ void DetectIsdataatRegisterTests(void) UtRegisterTest("DetectIsdataatTestParse04", DetectIsdataatTestParse04); UtRegisterTest("DetectIsdataatTestParse05", DetectIsdataatTestParse05); UtRegisterTest("DetectIsdataatTestParse06", DetectIsdataatTestParse06); - UtRegisterTest("DetectIsdataatTestParse16", DetectIsdataatTestParse16); UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01); UtRegisterTest("DetectIsdataatTestPacket02", DetectIsdataatTestPacket02); diff --git a/src/detect-lua.c b/src/detect-lua.c index 3d59b5d61bb6..9b5484407a19 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1023,11 +1023,14 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) } } else if (lua->alproto == ALPROTO_DNS) { if (lua->flags & DATATYPE_DNS_RRNAME) { - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSQUERYNAME_MATCH); + int list = DetectBufferTypeGetByName("dns_query"); + SigMatchAppendSMToList(s, sm, list); } else if (lua->flags & DATATYPE_DNS_REQUEST) { - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSREQUEST_MATCH); + int list = DetectBufferTypeGetByName("dns_request"); + SigMatchAppendSMToList(s, sm, list); } else if (lua->flags & DATATYPE_DNS_RESPONSE) { - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNSRESPONSE_MATCH); + int list = DetectBufferTypeGetByName("dns_response"); + SigMatchAppendSMToList(s, sm, list); } } else if (lua->alproto == ALPROTO_TLS) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); diff --git a/src/detect-parse.c b/src/detect-parse.c index 1886ee9081dd..335484706962 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -146,9 +146,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); CASE_CODE_STRING(DETECT_SM_LIST_FILEMATCH, "file"); - CASE_CODE_STRING(DETECT_SM_LIST_DNSREQUEST_MATCH, "dns_request"); - CASE_CODE_STRING(DETECT_SM_LIST_DNSRESPONSE_MATCH, "dns_response"); - CASE_CODE_STRING(DETECT_SM_LIST_DNSQUERYNAME_MATCH, "dns_query"); CASE_CODE_STRING(DETECT_SM_LIST_TLSSNI_MATCH, "tls_sni"); CASE_CODE_STRING(DETECT_SM_LIST_TLSISSUER_MATCH, "tls_cert_issuer"); CASE_CODE_STRING(DETECT_SM_LIST_TLSSUBJECT_MATCH, "tls_cert_subject"); @@ -176,9 +173,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_DMATCH); CASE_CODE(DETECT_SM_LIST_TMATCH); CASE_CODE(DETECT_SM_LIST_FILEMATCH); - CASE_CODE(DETECT_SM_LIST_DNSREQUEST_MATCH); - CASE_CODE(DETECT_SM_LIST_DNSRESPONSE_MATCH); - CASE_CODE(DETECT_SM_LIST_DNSQUERYNAME_MATCH); CASE_CODE(DETECT_SM_LIST_TLSSNI_MATCH); CASE_CODE(DETECT_SM_LIST_TLSISSUER_MATCH); CASE_CODE(DETECT_SM_LIST_TLSSUBJECT_MATCH); diff --git a/src/detect.h b/src/detect.h index 290c7d37eacb..4f7cf94097ef 100644 --- a/src/detect.h +++ b/src/detect.h @@ -120,10 +120,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_FILEMATCH, - DETECT_SM_LIST_DNSREQUEST_MATCH, /**< per DNS query tx match list */ - DETECT_SM_LIST_DNSRESPONSE_MATCH, /**< per DNS response tx match list */ - DETECT_SM_LIST_DNSQUERYNAME_MATCH, /**< per query in a tx list */ - DETECT_SM_LIST_TLSSNI_MATCH, DETECT_SM_LIST_TLSISSUER_MATCH, DETECT_SM_LIST_TLSSUBJECT_MATCH, From 9ba386a141431354e63a18261cfe3ae6a3a9e04b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 10 Dec 2016 11:36:06 +0100 Subject: [PATCH 2383/2553] tls: dynamic buffers --- src/detect-engine-analyzer.c | 6 ------ src/detect-engine.c | 9 --------- src/detect-parse.c | 8 -------- src/detect-tls-cert-issuer.c | 14 ++++++++------ src/detect-tls-cert-subject.c | 13 +++++++------ src/detect-tls-cert-validity.c | 21 ++++++++++++--------- src/detect-tls-sni.c | 12 +++++++----- src/detect.h | 5 ----- 8 files changed, 34 insertions(+), 54 deletions(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 06647980c2d4..5eb47f8af401 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -446,12 +446,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "%s", payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream"); } - else if (list_type == DETECT_SM_LIST_TLSSNI_MATCH) - fprintf(rule_engine_analysis_FD, "tls sni extension content"); - else if (list_type == DETECT_SM_LIST_TLSISSUER_MATCH) - fprintf(rule_engine_analysis_FD, "tls issuer content"); - else if (list_type == DETECT_SM_LIST_TLSSUBJECT_MATCH) - fprintf(rule_engine_analysis_FD, "tls subject content"); else if (list_type == DETECT_SM_LIST_DNP3_DATA_MATCH) fprintf(rule_engine_analysis_FD, "dnp3 data content"); else { diff --git a/src/detect-engine.c b/src/detect-engine.c index 994a44290a61..32b94f4ab4b3 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2811,15 +2811,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_FILEMATCH: return "file"; - case DETECT_SM_LIST_TLSSNI_MATCH: - return "tls sni extension"; - case DETECT_SM_LIST_TLSISSUER_MATCH: - return "tls issuer"; - case DETECT_SM_LIST_TLSSUBJECT_MATCH: - return "tls subject"; - case DETECT_SM_LIST_TLSVALIDITY_MATCH: - return "tls validity"; - case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; case DETECT_SM_LIST_DNP3_DATA_MATCH: diff --git a/src/detect-parse.c b/src/detect-parse.c index 335484706962..bdfe4bd4711e 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -146,10 +146,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); CASE_CODE_STRING(DETECT_SM_LIST_FILEMATCH, "file"); - CASE_CODE_STRING(DETECT_SM_LIST_TLSSNI_MATCH, "tls_sni"); - CASE_CODE_STRING(DETECT_SM_LIST_TLSISSUER_MATCH, "tls_cert_issuer"); - CASE_CODE_STRING(DETECT_SM_LIST_TLSSUBJECT_MATCH, "tls_cert_subject"); - CASE_CODE_STRING(DETECT_SM_LIST_TLSVALIDITY_MATCH, "tls_cert_validity"); CASE_CODE_STRING(DETECT_SM_LIST_MODBUS_MATCH, "modbus"); CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); @@ -173,10 +169,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_DMATCH); CASE_CODE(DETECT_SM_LIST_TMATCH); CASE_CODE(DETECT_SM_LIST_FILEMATCH); - CASE_CODE(DETECT_SM_LIST_TLSSNI_MATCH); - CASE_CODE(DETECT_SM_LIST_TLSISSUER_MATCH); - CASE_CODE(DETECT_SM_LIST_TLSSUBJECT_MATCH); - CASE_CODE(DETECT_SM_LIST_TLSVALIDITY_MATCH); CASE_CODE(DETECT_SM_LIST_MODBUS_MATCH); CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); CASE_CODE(DETECT_SM_LIST_POSTMATCH); diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index 10e697c6f3bd..f3fa104da8f5 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -55,6 +55,7 @@ static int DetectTlsIssuerSetup(DetectEngineCtx *, Signature *, char *); static void DetectTlsIssuerRegisterTests(void); +static int g_tls_cert_issuer_buffer_id = 0; /** * \brief Registration function for keyword: tls_cert_issuer @@ -73,13 +74,14 @@ void DetectTlsIssuerRegister(void) sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("tls_cert_issuer", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_TLSISSUER_MATCH, 2, + DetectAppLayerMpmRegister("tls_cert_issuer", SIG_FLAG_TOCLIENT, 2, PrefilterTxTlsIssuerRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_TLS, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_TLSISSUER_MATCH, + DetectAppLayerInspectEngineRegister2("tls_cert_issuer", + ALPROTO_TLS, SIG_FLAG_TOCLIENT, DetectEngineInspectTlsIssuer); + + g_tls_cert_issuer_buffer_id = DetectBufferTypeGetByName("tls_cert_issuer"); } @@ -94,7 +96,7 @@ void DetectTlsIssuerRegister(void) */ static int DetectTlsIssuerSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->init_data->list = DETECT_SM_LIST_TLSISSUER_MATCH; + s->init_data->list = g_tls_cert_issuer_buffer_id; s->alproto = ALPROTO_TLS; return 0; } @@ -123,7 +125,7 @@ static int DetectTlsIssuerTest01(void) sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; FAIL_IF_NOT_NULL(sm); - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_TLSISSUER_MATCH]; + sm = de_ctx->sig_list->sm_lists[g_tls_cert_issuer_buffer_id]; FAIL_IF_NULL(sm); FAIL_IF(sm->type != DETECT_CONTENT); diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index 02431a19c6b6..33d4d5116186 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -55,6 +55,7 @@ static int DetectTlsSubjectSetup(DetectEngineCtx *, Signature *, char *); static void DetectTlsSubjectRegisterTests(void); +static int g_tls_cert_subject_buffer_id = 0; /** * \brief Registration function for keyword: tls_cert_issuer @@ -73,14 +74,14 @@ void DetectTlsSubjectRegister(void) sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("tls_cert_subject", SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_TLSSUBJECT_MATCH, 2, + DetectAppLayerMpmRegister("tls_cert_subject", SIG_FLAG_TOCLIENT, 2, PrefilterTxTlsSubjectRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_TLS, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_TLSSUBJECT_MATCH, + DetectAppLayerInspectEngineRegister2("tls_cert_subject", + ALPROTO_TLS, SIG_FLAG_TOCLIENT, DetectEngineInspectTlsSubject); + g_tls_cert_subject_buffer_id = DetectBufferTypeGetByName("tls_cert_subject"); } /** @@ -94,7 +95,7 @@ void DetectTlsSubjectRegister(void) */ static int DetectTlsSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->init_data->list = DETECT_SM_LIST_TLSSUBJECT_MATCH; + s->init_data->list = g_tls_cert_subject_buffer_id; s->alproto = ALPROTO_TLS; return 0; } @@ -123,7 +124,7 @@ static int DetectTlsSubjectTest01(void) sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; FAIL_IF_NOT_NULL(sm); - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_TLSSUBJECT_MATCH]; + sm = de_ctx->sig_list->sm_lists[g_tls_cert_subject_buffer_id]; FAIL_IF_NULL(sm); FAIL_IF(sm->type != DETECT_CONTENT); diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index f3ad4fd9c27f..510a6ca50cbe 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -68,11 +68,12 @@ static int DetectTlsValidSetup (DetectEngineCtx *, Signature *s, char *str); static int DetectTlsNotBeforeSetup (DetectEngineCtx *, Signature *s, char *str); static int DetectTlsNotAfterSetup (DetectEngineCtx *, Signature *s, char *str); static int DetectTlsValiditySetup (DetectEngineCtx *, Signature *s, char *str, uint8_t); -void TlsNotBeforeRegisterTests(void); -void TlsNotAfterRegisterTests(void); -void TlsExpiredRegisterTests(void); -void TlsValidRegisterTests(void); +static void TlsNotBeforeRegisterTests(void); +static void TlsNotAfterRegisterTests(void); +static void TlsExpiredRegisterTests(void); +static void TlsValidRegisterTests(void); static void DetectTlsValidityFree(void *); +static int g_tls_validity_buffer_id = 0; /** * \brief Registration function for tls validity keywords. @@ -119,9 +120,11 @@ void DetectTlsValidityRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - DetectAppLayerInspectEngineRegister(ALPROTO_TLS, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_TLSVALIDITY_MATCH, + DetectAppLayerInspectEngineRegister2("tls_validity", + ALPROTO_TLS, SIG_FLAG_TOCLIENT, DetectEngineInspectTlsValidity); + + g_tls_validity_buffer_id = DetectBufferTypeGetByName("tls_validity"); } /** @@ -447,7 +450,7 @@ static int DetectTlsExpiredSetup (DetectEngineCtx *de_ctx, Signature *s, s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TLSVALIDITY_MATCH); + SigMatchAppendSMToList(s, sm, g_tls_validity_buffer_id); return 0; @@ -505,7 +508,7 @@ static int DetectTlsValidSetup (DetectEngineCtx *de_ctx, Signature *s, s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TLSVALIDITY_MATCH); + SigMatchAppendSMToList(s, sm, g_tls_validity_buffer_id); return 0; @@ -608,7 +611,7 @@ static int DetectTlsValiditySetup (DetectEngineCtx *de_ctx, Signature *s, s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TLSVALIDITY_MATCH); + SigMatchAppendSMToList(s, sm, g_tls_validity_buffer_id); return 0; diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index 36b64c6584c4..07c71f49c13f 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -55,6 +55,7 @@ static int DetectTlsSniSetup(DetectEngineCtx *, Signature *, char *); static void DetectTlsSniRegisterTests(void); +static int g_tls_sni_buffer_id = 0; /** * \brief Registration function for keyword: tls_sni @@ -73,13 +74,14 @@ void DetectTlsSniRegister(void) sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_PAYLOAD; - DetectMpmAppLayerRegister("tls_sni", SIG_FLAG_TOSERVER, - DETECT_SM_LIST_TLSSNI_MATCH, 2, + DetectAppLayerMpmRegister("tls_sni", SIG_FLAG_TOSERVER, 2, PrefilterTxTlsSniRegister); - DetectAppLayerInspectEngineRegister(ALPROTO_TLS, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_TLSSNI_MATCH, + DetectAppLayerInspectEngineRegister2("tls_sni", + ALPROTO_TLS, SIG_FLAG_TOSERVER, DetectEngineInspectTlsSni); + + g_tls_sni_buffer_id = DetectBufferTypeGetByName("tls_sni"); } @@ -94,7 +96,7 @@ void DetectTlsSniRegister(void) */ static int DetectTlsSniSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->init_data->list = DETECT_SM_LIST_TLSSNI_MATCH; + s->init_data->list = g_tls_sni_buffer_id; s->alproto = ALPROTO_TLS; return 0; } diff --git a/src/detect.h b/src/detect.h index 4f7cf94097ef..eb577b2e2463 100644 --- a/src/detect.h +++ b/src/detect.h @@ -120,11 +120,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_FILEMATCH, - DETECT_SM_LIST_TLSSNI_MATCH, - DETECT_SM_LIST_TLSISSUER_MATCH, - DETECT_SM_LIST_TLSSUBJECT_MATCH, - DETECT_SM_LIST_TLSVALIDITY_MATCH, - DETECT_SM_LIST_MODBUS_MATCH, DETECT_SM_LIST_CIP_MATCH, From cfdd934aba2ccda93afa95345b97a9aeb0dd29f2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 10 Dec 2016 14:04:50 +0100 Subject: [PATCH 2384/2553] dnp3: dynamic buffers/lists --- src/detect-dnp3.c | 47 ++++++++++++++++++++++-------------- src/detect-engine-analyzer.c | 2 -- src/detect-engine.c | 4 --- src/detect-lua.c | 3 ++- src/detect.h | 3 --- 5 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 9f47c4ff65fe..6c868a5f212e 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -27,6 +27,9 @@ #include "app-layer-dnp3.h" +static int g_dnp3_match_buffer_id = 0; +static int g_dnp3_data_buffer_id = 0; + /** * The detection struct. */ @@ -227,7 +230,7 @@ static int DetectDNP3FuncSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) s->alproto = ALPROTO_DNP3; s->flags |= SIG_FLAG_STATE_MATCH; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNP3_MATCH); + SigMatchAppendSMToList(s, sm, g_dnp3_match_buffer_id); SCReturnInt(0); error: @@ -314,7 +317,7 @@ static int DetectDNP3IndSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) s->alproto = ALPROTO_DNP3; s->flags |= SIG_FLAG_STATE_MATCH; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNP3_MATCH); + SigMatchAppendSMToList(s, sm, g_dnp3_match_buffer_id); SCReturnInt(0); error: @@ -387,7 +390,7 @@ static int DetectDNP3ObjSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) sm->ctx = (void *)detect; s->alproto = ALPROTO_DNP3; s->flags |= SIG_FLAG_STATE_MATCH; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNP3_MATCH); + SigMatchAppendSMToList(s, sm, g_dnp3_match_buffer_id); SCReturnInt(1); fail: @@ -526,7 +529,7 @@ static void DetectDNP3ObjRegister(void) static int DetectDNP3DataSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); - s->init_data->list = DETECT_SM_LIST_DNP3_DATA_MATCH; + s->init_data->list = g_dnp3_data_buffer_id; s->alproto = ALPROTO_DNP3; SCReturnInt(0); } @@ -546,11 +549,14 @@ static void DetectDNP3DataRegister(void) sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_PAYLOAD; - DetectAppLayerInspectEngineRegister(ALPROTO_DNP3, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_DNP3_DATA_MATCH, DetectEngineInspectDNP3Data); - DetectAppLayerInspectEngineRegister(ALPROTO_DNP3, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_DNP3_DATA_MATCH, DetectEngineInspectDNP3Data); + DetectAppLayerInspectEngineRegister2("dnp3_data", + ALPROTO_DNP3, SIG_FLAG_TOSERVER, + DetectEngineInspectDNP3Data); + DetectAppLayerInspectEngineRegister2("dnp3_data", + ALPROTO_DNP3, SIG_FLAG_TOCLIENT, + DetectEngineInspectDNP3Data); + g_dnp3_data_buffer_id = DetectBufferTypeGetByName("dnp3_data"); SCReturn; } @@ -563,10 +569,15 @@ void DetectDNP3Register(void) DetectDNP3ObjRegister(); /* Register the list of func, ind and obj. */ - DetectAppLayerInspectEngineRegister(ALPROTO_DNP3, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_DNP3_MATCH, DetectEngineInspectDNP3); - DetectAppLayerInspectEngineRegister(ALPROTO_DNP3, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_DNP3_MATCH, DetectEngineInspectDNP3); + DetectAppLayerInspectEngineRegister2("dnp3", + ALPROTO_DNP3, SIG_FLAG_TOSERVER, + DetectEngineInspectDNP3); + DetectAppLayerInspectEngineRegister2("dnp3", + ALPROTO_DNP3, SIG_FLAG_TOCLIENT, + DetectEngineInspectDNP3); + + g_dnp3_match_buffer_id = DetectBufferTypeRegister("dnp3"); + } #ifdef UNITTESTS @@ -625,10 +636,10 @@ static int DetectDNP3FuncTest01(void) "dnp3_func:2; sid:5000009; rev:1;)"); FAIL_IF_NULL(de_ctx->sig_list); - FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH]); - FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH]->ctx); + FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]); + FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx); - dnp3func = (DetectDNP3 *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH]->ctx; + dnp3func = (DetectDNP3 *)de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx; FAIL_IF(dnp3func->function_code != 2); if (de_ctx != NULL) { @@ -691,10 +702,10 @@ static int DetectDNP3ObjSetupTest(void) "dnp3_obj:99,99; sid:1; rev:1;)"); FAIL_IF(de_ctx->sig_list == NULL); - FAIL_IF(de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH] == NULL); - FAIL_IF(de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH]->ctx == NULL); + FAIL_IF(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id] == NULL); + FAIL_IF(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx == NULL); - detect = (DetectDNP3 *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_DNP3_MATCH]->ctx; + detect = (DetectDNP3 *)de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx; FAIL_IF(detect->obj_group != 99); FAIL_IF(detect->obj_variation != 99); diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 5eb47f8af401..51ac3930aaed 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -446,8 +446,6 @@ static void EngineAnalysisRulesPrintFP(const Signature *s) fprintf(rule_engine_analysis_FD, "%s", payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream"); } - else if (list_type == DETECT_SM_LIST_DNP3_DATA_MATCH) - fprintf(rule_engine_analysis_FD, "dnp3 data content"); else { const char *desc = DetectBufferTypeGetDescriptionById(list_type); const char *name = DetectBufferTypeGetNameById(list_type); diff --git a/src/detect-engine.c b/src/detect-engine.c index 32b94f4ab4b3..c58672ebc81f 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2813,10 +2813,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; - case DETECT_SM_LIST_DNP3_DATA_MATCH: - return "dnp3_data"; - case DETECT_SM_LIST_DNP3_MATCH: - return "dnp3"; case DETECT_SM_LIST_CIP_MATCH: return "cip"; diff --git a/src/detect-lua.c b/src/detect-lua.c index 9b5484407a19..a58558943334 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1039,7 +1039,8 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) } else if (lua->alproto == ALPROTO_SMTP) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); } else if (lua->alproto == ALPROTO_DNP3) { - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DNP3_MATCH); + int list = DetectBufferTypeGetByName("dnp3"); + SigMatchAppendSMToList(s, sm, list); } else { SCLogError(SC_ERR_LUA_ERROR, "lua can't be used with protocol %s", AppLayerGetProtoName(lua->alproto)); diff --git a/src/detect.h b/src/detect.h index eb577b2e2463..bd901e37355b 100644 --- a/src/detect.h +++ b/src/detect.h @@ -125,9 +125,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_CIP_MATCH, DETECT_SM_LIST_ENIP_MATCH, - DETECT_SM_LIST_DNP3_DATA_MATCH, - DETECT_SM_LIST_DNP3_MATCH, - DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, DETECT_SM_LIST_MAX, From f2393c1ae084a592de43efe0ba1e7620aac734f1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 10 Dec 2016 14:36:06 +0100 Subject: [PATCH 2385/2553] modbus: dynamic buffer --- src/detect-engine.c | 3 -- src/detect-modbus.c | 68 ++++++++++++++++++++++++--------------------- src/detect-parse.c | 2 -- src/detect.h | 2 -- 4 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index c58672ebc81f..0c5fd77f88ac 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2811,9 +2811,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_FILEMATCH: return "file"; - case DETECT_SM_LIST_MODBUS_MATCH: - return "modbus"; - case DETECT_SM_LIST_CIP_MATCH: return "cip"; case DETECT_SM_LIST_ENIP_MATCH: diff --git a/src/detect-modbus.c b/src/detect-modbus.c index 5e71d8f61a19..82600c909a29 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -70,6 +70,8 @@ static pcre_extra *function_parse_regex_study; static pcre *access_parse_regex; static pcre_extra *access_parse_regex_study; +static int g_modbus_buffer_id = 0; + #define MAX_SUBSTRINGS 30 void DetectModbusRegisterTests(void); @@ -384,7 +386,7 @@ static int DetectModbusSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) sm->type = DETECT_AL_MODBUS; sm->ctx = (void *) modbus; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MODBUS_MATCH); + SigMatchAppendSMToList(s, sm, g_modbus_buffer_id); s->alproto = ALPROTO_MODBUS; SCReturnInt(0); @@ -415,12 +417,14 @@ void DetectModbusRegister(void) DetectSetupParseRegexes(PARSE_REGEX_ACCESS, &access_parse_regex, &access_parse_regex_study); - DetectAppLayerInspectEngineRegister(ALPROTO_MODBUS, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_MODBUS_MATCH, + DetectAppLayerInspectEngineRegister2("modbus", + ALPROTO_MODBUS, SIG_FLAG_TOSERVER, DetectEngineInspectModbus); - DetectAppLayerInspectEngineRegister(ALPROTO_MODBUS, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_MODBUS_MATCH, + DetectAppLayerInspectEngineRegister2("modbus", + ALPROTO_MODBUS, SIG_FLAG_TOCLIENT, DetectEngineInspectModbus); + + g_modbus_buffer_id = DetectBufferTypeGetByName("modbus"); } #ifdef UNITTESTS /* UNITTESTS */ @@ -447,13 +451,13 @@ static int DetectModbusTest01(void) if (de_ctx->sig_list == NULL) goto end; - if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || - (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; if (modbus->function != 1) { printf("expected function %d, got %" PRIu8 ": ", 1, modbus->function); @@ -491,13 +495,13 @@ static int DetectModbusTest02(void) if (de_ctx->sig_list == NULL) goto end; - if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || - (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; if ((modbus->function != 8) || (*modbus->subfunction != 4)) { printf("expected function %d, got %" PRIu8 ": ", 1, modbus->function); @@ -536,13 +540,13 @@ static int DetectModbusTest03(void) if (de_ctx->sig_list == NULL) goto end; - if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || - (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; if (modbus->category != MODBUS_CAT_RESERVED) { printf("expected function %d, got %" PRIu8 ": ", MODBUS_CAT_RESERVED, modbus->category); @@ -582,13 +586,13 @@ static int DetectModbusTest04(void) if (de_ctx->sig_list == NULL) goto end; - if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || - (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; if (modbus->category != category) { printf("expected function %u, got %" PRIu8 ": ", ~MODBUS_CAT_PUBLIC_ASSIGNED, modbus->category); @@ -626,13 +630,13 @@ static int DetectModbusTest05(void) if (de_ctx->sig_list == NULL) goto end; - if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || - (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; if (modbus->type != MODBUS_TYP_READ) { printf("expected function %d, got %" PRIu8 ": ", MODBUS_TYP_READ, modbus->type); @@ -672,13 +676,13 @@ static int DetectModbusTest06(void) if (de_ctx->sig_list == NULL) goto end; - if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || - (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; if (modbus->type != type) { printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); @@ -718,13 +722,13 @@ static int DetectModbusTest07(void) if (de_ctx->sig_list == NULL) goto end; - if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || - (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; if ((modbus->type != type) || ((*modbus->address).mode != mode) || @@ -768,13 +772,13 @@ static int DetectModbusTest08(void) if (de_ctx->sig_list == NULL) goto end; - if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || - (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; if ((modbus->type != type) || ((*modbus->address).mode != mode) || @@ -819,13 +823,13 @@ static int DetectModbusTest09(void) if (de_ctx->sig_list == NULL) goto end; - if ((de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH] == NULL) || - (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx == NULL)) { + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_MODBUS_MATCH]->ctx; + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; if ((modbus->type != type) || ((*modbus->address).mode != addressMode) || diff --git a/src/detect-parse.c b/src/detect-parse.c index bdfe4bd4711e..d8a9928dc80e 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -146,7 +146,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); CASE_CODE_STRING(DETECT_SM_LIST_FILEMATCH, "file"); - CASE_CODE_STRING(DETECT_SM_LIST_MODBUS_MATCH, "modbus"); CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress"); @@ -169,7 +168,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_DMATCH); CASE_CODE(DETECT_SM_LIST_TMATCH); CASE_CODE(DETECT_SM_LIST_FILEMATCH); - CASE_CODE(DETECT_SM_LIST_MODBUS_MATCH); CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); CASE_CODE(DETECT_SM_LIST_POSTMATCH); CASE_CODE(DETECT_SM_LIST_SUPPRESS); diff --git a/src/detect.h b/src/detect.h index bd901e37355b..1e98e8da4d78 100644 --- a/src/detect.h +++ b/src/detect.h @@ -120,8 +120,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_FILEMATCH, - DETECT_SM_LIST_MODBUS_MATCH, - DETECT_SM_LIST_CIP_MATCH, DETECT_SM_LIST_ENIP_MATCH, From e4bfdd53c2a8593fd4ec8aa78c249de7c9aee846 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 10 Dec 2016 21:55:51 +0100 Subject: [PATCH 2386/2553] cip/enip: dynamic buffer --- src/detect-cipservice.c | 26 ++++++++++++++++---------- src/detect-engine.c | 5 ----- src/detect.h | 3 --- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c index 68a0a96d1ec2..8a6d61b90429 100644 --- a/src/detect-cipservice.c +++ b/src/detect-cipservice.c @@ -42,6 +42,7 @@ static int DetectCipServiceSetup(DetectEngineCtx *, Signature *, char *); static void DetectCipServiceFree(void *); static void DetectCipServiceRegisterTests(void); +static int g_cip_buffer_id = 0; /** * \brief Registration function for cip_service: keyword @@ -58,13 +59,15 @@ void DetectCipServiceRegister(void) sigmatch_table[DETECT_CIPSERVICE].RegisterTests = DetectCipServiceRegisterTests; - DetectAppLayerInspectEngineRegister(ALPROTO_ENIP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_CIP_MATCH, + DetectAppLayerInspectEngineRegister2("cip", + ALPROTO_ENIP, SIG_FLAG_TOSERVER, DetectEngineInspectCIP); - DetectAppLayerInspectEngineRegister(ALPROTO_ENIP, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_CIP_MATCH, + DetectAppLayerInspectEngineRegister2("cip", + ALPROTO_ENIP, SIG_FLAG_TOCLIENT, DetectEngineInspectCIP); + g_cip_buffer_id = DetectBufferTypeGetByName("cip"); + SCReturn; } @@ -225,7 +228,7 @@ static int DetectCipServiceSetup(DetectEngineCtx *de_ctx, Signature *s, s->alproto = ALPROTO_ENIP; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_CIP_MATCH); + SigMatchAppendSMToList(s, sm, g_cip_buffer_id); SCReturnInt(0); @@ -301,6 +304,7 @@ static void DetectCipServiceRegisterTests(void) static int DetectEnipCommandSetup(DetectEngineCtx *, Signature *, char *); static void DetectEnipCommandFree(void *); static void DetectEnipCommandRegisterTests(void); +static int g_enip_buffer_id = 0; /** * \brief Registration function for enip_command: keyword @@ -317,12 +321,14 @@ void DetectEnipCommandRegister(void) sigmatch_table[DETECT_ENIPCOMMAND].RegisterTests = DetectEnipCommandRegisterTests; - DetectAppLayerInspectEngineRegister(ALPROTO_ENIP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_ENIP_MATCH, + DetectAppLayerInspectEngineRegister2("enip", + ALPROTO_ENIP, SIG_FLAG_TOSERVER, DetectEngineInspectENIP); - DetectAppLayerInspectEngineRegister(ALPROTO_ENIP, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_ENIP_MATCH, + DetectAppLayerInspectEngineRegister2("enip", + ALPROTO_ENIP, SIG_FLAG_TOCLIENT, DetectEngineInspectENIP); + + g_enip_buffer_id = DetectBufferTypeGetByName("enip"); } /** @@ -399,7 +405,7 @@ static int DetectEnipCommandSetup(DetectEngineCtx *de_ctx, Signature *s, sm->ctx = (void *) enipcmdd; s->alproto = ALPROTO_ENIP; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_ENIP_MATCH); + SigMatchAppendSMToList(s, sm, g_enip_buffer_id); SCReturnInt(0); diff --git a/src/detect-engine.c b/src/detect-engine.c index 0c5fd77f88ac..a577af12a931 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2811,11 +2811,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_FILEMATCH: return "file"; - case DETECT_SM_LIST_CIP_MATCH: - return "cip"; - case DETECT_SM_LIST_ENIP_MATCH: - return "enip"; - case DETECT_SM_LIST_BASE64_DATA: return "base64_data"; diff --git a/src/detect.h b/src/detect.h index 1e98e8da4d78..7895ec683f6f 100644 --- a/src/detect.h +++ b/src/detect.h @@ -120,9 +120,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_FILEMATCH, - DETECT_SM_LIST_CIP_MATCH, - DETECT_SM_LIST_ENIP_MATCH, - DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, DETECT_SM_LIST_MAX, From b68343e372fe817e943cec048a6a504a235b4911 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 10 Dec 2016 22:03:46 +0100 Subject: [PATCH 2387/2553] files: use dynamic list --- src/detect-engine-file.c | 1 - src/detect-engine.c | 3 --- src/detect-fileext.c | 5 ++++- src/detect-filemagic.c | 5 ++++- src/detect-filemd5.c | 7 ++++++- src/detect-filename.c | 17 ++++++++++------- src/detect-filesha1.c | 6 +++++- src/detect-filesha256.c | 6 +++++- src/detect-filesize.c | 6 +++++- src/detect-filestore.c | 5 ++++- src/detect-parse.c | 2 -- src/detect.h | 2 -- src/util-detect-file-hash.c | 4 ++-- src/util-detect-file-hash.h | 2 +- 14 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index 7ffb355740a8..7db290d3e502 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -81,7 +81,6 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, int match = 0; int store_r = 0; - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_FILEMATCH); SCLogDebug("file inspection... %p", ffc); if (ffc != NULL) { diff --git a/src/detect-engine.c b/src/detect-engine.c index a577af12a931..34d338158149 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2808,9 +2808,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_TMATCH: return "tag"; - case DETECT_SM_LIST_FILEMATCH: - return "file"; - case DETECT_SM_LIST_BASE64_DATA: return "base64_data"; diff --git a/src/detect-fileext.c b/src/detect-fileext.c index f9a08dacf374..eecc63ffe5d1 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -56,6 +56,7 @@ static int DetectFileextMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, static int DetectFileextSetup (DetectEngineCtx *, Signature *, char *); static void DetectFileextRegisterTests(void); static void DetectFileextFree(void *); +static int g_file_match_list_id = 0; /** * \brief Registration function for keyword: fileext @@ -70,6 +71,8 @@ void DetectFileextRegister(void) sigmatch_table[DETECT_FILEEXT].Free = DetectFileextFree; sigmatch_table[DETECT_FILEEXT].RegisterTests = DetectFileextRegisterTests; + g_file_match_list_id = DetectBufferTypeRegister("files"); + SCLogDebug("registering fileext rule option"); return; } @@ -208,7 +211,7 @@ static int DetectFileextSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) sm->type = DETECT_FILEEXT; sm->ctx = (void *)fileext; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + SigMatchAppendSMToList(s, sm, g_file_match_list_id); s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_FILENAME); return 0; diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index b70e4c820d71..dbf1dd767e49 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -80,6 +80,7 @@ static int DetectFilemagicMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, static int DetectFilemagicSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilemagicRegisterTests(void); static void DetectFilemagicFree(void *); +static int g_file_match_list_id = 0; /** * \brief Registration function for keyword: filemagic @@ -94,6 +95,8 @@ void DetectFilemagicRegister(void) sigmatch_table[DETECT_FILEMAGIC].Free = DetectFilemagicFree; sigmatch_table[DETECT_FILEMAGIC].RegisterTests = DetectFilemagicRegisterTests; + g_file_match_list_id = DetectBufferTypeRegister("files"); + SCLogDebug("registering filemagic rule option"); return; } @@ -377,7 +380,7 @@ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, char *st sm->type = DETECT_FILEMAGIC; sm->ctx = (void *)filemagic; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + SigMatchAppendSMToList(s, sm, g_file_match_list_id); s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MAGIC); return 0; diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index 8f1b43d1975e..a4f3f56dfe7c 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -24,6 +24,7 @@ #include "suricata-common.h" +#include "detect-engine.h" #include "util-detect-file-hash.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -56,6 +57,8 @@ void DetectFileMd5Register(void) #else /* HAVE_NSS */ +static int g_file_match_list_id = 0; + static int DetectFileMd5Setup (DetectEngineCtx *, Signature *, char *); static void DetectFileMd5RegisterTests(void); @@ -72,6 +75,8 @@ void DetectFileMd5Register(void) sigmatch_table[DETECT_FILEMD5].Free = DetectFileHashFree; sigmatch_table[DETECT_FILEMD5].RegisterTests = DetectFileMd5RegisterTests; + g_file_match_list_id = DetectBufferTypeRegister("files"); + SCLogDebug("registering filemd5 rule option"); return; } @@ -89,7 +94,7 @@ void DetectFileMd5Register(void) */ static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) { - return DetectFileHashSetup(de_ctx, s, str, DETECT_FILEMD5); + return DetectFileHashSetup(de_ctx, s, str, DETECT_FILEMD5, g_file_match_list_id); } #ifdef UNITTESTS diff --git a/src/detect-filename.c b/src/detect-filename.c index e751d2b4faed..1b59519fb9e4 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -57,6 +57,7 @@ static int DetectFilenameMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, static int DetectFilenameSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilenameRegisterTests(void); static void DetectFilenameFree(void *); +static int g_file_match_list_id = 0; /** * \brief Registration function for keyword: filename @@ -71,17 +72,19 @@ void DetectFilenameRegister(void) sigmatch_table[DETECT_FILENAME].Free = DetectFilenameFree; sigmatch_table[DETECT_FILENAME].RegisterTests = DetectFilenameRegisterTests; - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_FILEMATCH, + DetectAppLayerInspectEngineRegister2("files", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectFileInspectHttp); - DetectAppLayerInspectEngineRegister(ALPROTO_HTTP, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_FILEMATCH, + DetectAppLayerInspectEngineRegister2("files", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectFileInspectHttp); - DetectAppLayerInspectEngineRegister(ALPROTO_SMTP, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_FILEMATCH, + DetectAppLayerInspectEngineRegister2("files", + ALPROTO_SMTP, SIG_FLAG_TOSERVER, DetectFileInspectSmtp); + g_file_match_list_id = DetectBufferTypeGetByName("files"); + SCLogDebug("registering filename rule option"); return; } @@ -225,7 +228,7 @@ static int DetectFilenameSetup (DetectEngineCtx *de_ctx, Signature *s, char *str sm->type = DETECT_FILENAME; sm->ctx = (void *)filename; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + SigMatchAppendSMToList(s, sm, g_file_match_list_id); s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_FILENAME); return 0; diff --git a/src/detect-filesha1.c b/src/detect-filesha1.c index 22196bda9336..3bb26b5746a1 100644 --- a/src/detect-filesha1.c +++ b/src/detect-filesha1.c @@ -25,6 +25,7 @@ #include "suricata-common.h" +#include "detect-engine.h" #include "util-detect-file-hash.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -59,6 +60,7 @@ void DetectFileSha1Register(void) static int DetectFileSha1Setup (DetectEngineCtx *, Signature *, char *); static void DetectFileSha1RegisterTests(void); +static int g_file_match_list_id = 0; /** * \brief Registration function for keyword: filesha1 @@ -73,6 +75,8 @@ void DetectFileSha1Register(void) sigmatch_table[DETECT_FILESHA1].Free = DetectFileHashFree; sigmatch_table[DETECT_FILESHA1].RegisterTests = DetectFileSha1RegisterTests; + g_file_match_list_id = DetectBufferTypeRegister("files"); + SCLogDebug("registering filesha1 rule option"); return; } @@ -90,7 +94,7 @@ void DetectFileSha1Register(void) */ static int DetectFileSha1Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) { - return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA1); + return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA1, g_file_match_list_id); } #ifdef UNITTESTS diff --git a/src/detect-filesha256.c b/src/detect-filesha256.c index 0a58e33a3091..b95831e7da20 100644 --- a/src/detect-filesha256.c +++ b/src/detect-filesha256.c @@ -25,6 +25,7 @@ #include "suricata-common.h" +#include "detect-engine.h" #include "util-detect-file-hash.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -59,6 +60,7 @@ void DetectFileSha256Register(void) static int DetectFileSha256Setup (DetectEngineCtx *, Signature *, char *); static void DetectFileSha256RegisterTests(void); +static int g_file_match_list_id = 0; /** * \brief Registration function for keyword: filesha256 @@ -73,6 +75,8 @@ void DetectFileSha256Register(void) sigmatch_table[DETECT_FILESHA256].Free = DetectFileHashFree; sigmatch_table[DETECT_FILESHA256].RegisterTests = DetectFileSha256RegisterTests; + g_file_match_list_id = DetectBufferTypeRegister("files"); + SCLogDebug("registering filesha256 rule option"); return; } @@ -90,7 +94,7 @@ void DetectFileSha256Register(void) */ static int DetectFileSha256Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) { - return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA256); + return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA256, g_file_match_list_id); } #ifdef UNITTESTS diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 1b12221b8441..547ea38963e9 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -31,6 +31,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine.h" #include "detect-engine-state.h" #include "detect-filesize.h" @@ -53,6 +54,7 @@ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, F static int DetectFilesizeSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilesizeFree (void *); static void DetectFilesizeRegisterTests (void); +static int g_file_match_list_id = 0; /** * \brief Registration function for filesize: keyword @@ -70,6 +72,8 @@ void DetectFilesizeRegister(void) sigmatch_table[DETECT_FILESIZE].flags |= SIGMATCH_PAYLOAD; /** XXX necessary? */ DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + g_file_match_list_id = DetectBufferTypeRegister("files"); } /** @@ -286,7 +290,7 @@ static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *str sm->type = DETECT_FILESIZE; sm->ctx = (SigMatchCtx *)fsd; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + SigMatchAppendSMToList(s, sm, g_file_match_list_id); s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_SIZE); SCReturnInt(0); diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 328b2118034a..6801e8cbf0ac 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -64,6 +64,7 @@ static int DetectFilestoreMatch (ThreadVars *, DetectEngineThreadCtx *, static int DetectFilestoreSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilestoreFree(void *); static void DetectFilestoreRegisterTests(void); +static int g_file_match_list_id = 0; /** * \brief Registration function for keyword: filestore @@ -80,6 +81,8 @@ void DetectFilestoreRegister(void) sigmatch_table[DETECT_FILESTORE].flags = SIGMATCH_OPTIONAL_OPT; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + g_file_match_list_id = DetectBufferTypeRegister("files"); } /** @@ -401,7 +404,7 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *st AppLayerHtpNeedFileInspection(); } - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + SigMatchAppendSMToList(s, sm, g_file_match_list_id); s->filestore_ctx = (const DetectFilestoreData *)sm->ctx; s->flags |= SIG_FLAG_FILESTORE; diff --git a/src/detect-parse.c b/src/detect-parse.c index d8a9928dc80e..3b24f5fa3702 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -145,7 +145,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); - CASE_CODE_STRING(DETECT_SM_LIST_FILEMATCH, "file"); CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress"); @@ -167,7 +166,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); CASE_CODE(DETECT_SM_LIST_TMATCH); - CASE_CODE(DETECT_SM_LIST_FILEMATCH); CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); CASE_CODE(DETECT_SM_LIST_POSTMATCH); CASE_CODE(DETECT_SM_LIST_SUPPRESS); diff --git a/src/detect.h b/src/detect.h index 7895ec683f6f..70c76dfadadf 100644 --- a/src/detect.h +++ b/src/detect.h @@ -118,8 +118,6 @@ enum DetectSigmatchListEnum { /* app event engine sm list */ DETECT_SM_LIST_APP_EVENT = DETECT_SM_LIST_BUILTIN_MAX, - DETECT_SM_LIST_FILEMATCH, - DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, DETECT_SM_LIST_MAX, diff --git a/src/util-detect-file-hash.c b/src/util-detect-file-hash.c index aff4302f41be..e7e157bd9eef 100644 --- a/src/util-detect-file-hash.c +++ b/src/util-detect-file-hash.c @@ -303,7 +303,7 @@ static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, * \retval -1 on Failure */ int DetectFileHashSetup (DetectEngineCtx *de_ctx, Signature *s, char *str, - uint32_t type) + uint32_t type, int list) { DetectFileHashData *filehash = NULL; SigMatch *sm = NULL; @@ -321,7 +321,7 @@ int DetectFileHashSetup (DetectEngineCtx *de_ctx, Signature *s, char *str, sm->type = type; sm->ctx = (void *)filehash; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + SigMatchAppendSMToList(s, sm, list); s->file_flags |= FILE_SIG_NEED_FILE; diff --git a/src/util-detect-file-hash.h b/src/util-detect-file-hash.h index ee0b37de61cf..b8d50789344e 100644 --- a/src/util-detect-file-hash.h +++ b/src/util-detect-file-hash.h @@ -39,7 +39,7 @@ int LoadHashTable(ROHashTable *, char *, char *, int, uint32_t); int DetectFileHashMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, const Signature *, const SigMatchData *); -int DetectFileHashSetup(DetectEngineCtx *, Signature *, char *, uint32_t); +int DetectFileHashSetup(DetectEngineCtx *, Signature *, char *, uint32_t, int); void DetectFileHashFree(void *); #endif /* __UTIL_DETECT_FILE_HASH_H__ */ From 815120896ba2e361173020f647a9bfd44d2789a2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 11 Dec 2016 09:59:31 +0100 Subject: [PATCH 2388/2553] app-layer-events: dynamic list --- src/detect-app-layer-event.c | 57 +++++++++++++++++++++++++++++------- src/detect-engine.c | 3 -- src/detect-parse.c | 2 -- src/detect.c | 28 ------------------ src/detect.h | 5 +--- 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 24eb6094022d..ec31ea4b8505 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -60,6 +60,8 @@ static int DetectEngineAptEventInspect(ThreadVars *tv, const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); +static void DetectAppLayerEventSetupCallback(Signature *s); +static int g_applayer_events_list_id = 0; /** * \brief Registers the keyword handlers for the "app-layer-event" keyword. @@ -76,14 +78,17 @@ void DetectAppLayerEventRegister(void) sigmatch_table[DETECT_AL_APP_LAYER_EVENT].RegisterTests = DetectAppLayerEventRegisterTests; - DetectAppLayerInspectEngineRegister(ALPROTO_UNKNOWN, - SIG_FLAG_TOSERVER, DETECT_SM_LIST_APP_EVENT, + DetectAppLayerInspectEngineRegister2("app-layer-events", + ALPROTO_UNKNOWN, SIG_FLAG_TOSERVER, DetectEngineAptEventInspect); - DetectAppLayerInspectEngineRegister(ALPROTO_UNKNOWN, - SIG_FLAG_TOCLIENT, DETECT_SM_LIST_APP_EVENT, + DetectAppLayerInspectEngineRegister2("app-layer-events", + ALPROTO_UNKNOWN, SIG_FLAG_TOCLIENT, DetectEngineAptEventInspect); - return; + DetectBufferTypeRegisterSetupCallback("app-layer-events", + DetectAppLayerEventSetupCallback); + + g_applayer_events_list_id = DetectBufferTypeGetByName("app-layer-events"); } static int DetectEngineAptEventInspect(ThreadVars *tv, @@ -165,6 +170,38 @@ static int DetectAppLayerEventAppMatch(ThreadVars *t, DetectEngineThreadCtx *det SCReturnInt(r); } +static void DetectAppLayerEventSetupCallback(Signature *s) +{ + SigMatch *sm; + for (sm = s->init_data->smlists[g_applayer_events_list_id] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_AL_APP_LAYER_EVENT: + { + DetectAppLayerEventData *aed = (DetectAppLayerEventData *)sm->ctx; + switch (aed->alproto) { + case ALPROTO_HTTP: + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; + SCLogDebug("sig %u requires http app state (http event)", s->id); + break; + case ALPROTO_SMTP: + s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; + SCLogDebug("sig %u requires smtp app state (smtp event)", s->id); + break; + case ALPROTO_DNS: + s->mask |= SIG_MASK_REQUIRE_DNS_STATE; + SCLogDebug("sig %u requires dns app state (dns event)", s->id); + break; + case ALPROTO_TLS: + s->mask |= SIG_MASK_REQUIRE_TLS_STATE; + SCLogDebug("sig %u requires tls app state (tls event)", s->id); + break; + } + break; + } + } + } +} + static DetectAppLayerEventData *DetectAppLayerEventParsePkt(const char *arg, AppLayerEventType *event_type) { @@ -302,7 +339,7 @@ static int DetectAppLayerEventSetupP2(Signature *s, if (event_type == APP_LAYER_EVENT_TYPE_GENERAL) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); else - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_APP_EVENT); + SigMatchAppendSMToList(s, sm, g_applayer_events_list_id); /* We should have set this flag already in SetupP1 */ s->flags |= SIG_FLAG_APPLAYER; @@ -341,7 +378,7 @@ static int DetectAppLayerEventSetupP1(DetectEngineCtx *de_ctx, Signature *s, cha } else { /* We push it to this list temporarily. We deal with * these in DetectAppLayerEventPrepare(). */ - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_APP_EVENT); + SigMatchAppendSMToList(s, sm, g_applayer_events_list_id); s->flags |= SIG_FLAG_APPLAYER; } @@ -370,9 +407,9 @@ static void DetectAppLayerEventFree(void *ptr) int DetectAppLayerEventPrepare(Signature *s) { - SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_APP_EVENT]; - s->init_data->smlists[DETECT_SM_LIST_APP_EVENT] = NULL; - s->init_data->smlists_tail[DETECT_SM_LIST_APP_EVENT] = NULL; + SigMatch *sm = s->init_data->smlists[g_applayer_events_list_id]; + s->init_data->smlists[g_applayer_events_list_id] = NULL; + s->init_data->smlists_tail[g_applayer_events_list_id] = NULL; while (sm != NULL) { sm->next = sm->prev = NULL; diff --git a/src/detect-engine.c b/src/detect-engine.c index 34d338158149..d49cd24649b3 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2798,9 +2798,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_PMATCH: return "packet/stream payload"; - case DETECT_SM_LIST_APP_EVENT: - return "app layer events"; - case DETECT_SM_LIST_AMATCH: return "generic app layer"; case DETECT_SM_LIST_DMATCH: diff --git a/src/detect-parse.c b/src/detect-parse.c index 3b24f5fa3702..c4bb73395803 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -141,7 +141,6 @@ const char *DetectListToHumanString(int list) switch (list) { CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); - CASE_CODE_STRING(DETECT_SM_LIST_APP_EVENT, "app-layer-event"); CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); @@ -162,7 +161,6 @@ const char *DetectListToString(int list) switch (list) { CASE_CODE(DETECT_SM_LIST_MATCH); CASE_CODE(DETECT_SM_LIST_PMATCH); - CASE_CODE(DETECT_SM_LIST_APP_EVENT); CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); CASE_CODE(DETECT_SM_LIST_TMATCH); diff --git a/src/detect.c b/src/detect.c index 9f755bf09015..62de800c0a5d 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2250,34 +2250,6 @@ static int SignatureCreateMask(Signature *s) } } - for (sm = s->init_data->smlists[DETECT_SM_LIST_APP_EVENT] ; sm != NULL; sm = sm->next) { - switch (sm->type) { - case DETECT_AL_APP_LAYER_EVENT: - { - DetectAppLayerEventData *aed = (DetectAppLayerEventData *)sm->ctx; - switch (aed->alproto) { - case ALPROTO_HTTP: - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig %u requires http app state (http event)", s->id); - break; - case ALPROTO_SMTP: - s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; - SCLogDebug("sig %u requires smtp app state (smtp event)", s->id); - break; - case ALPROTO_DNS: - s->mask |= SIG_MASK_REQUIRE_DNS_STATE; - SCLogDebug("sig %u requires dns app state (dns event)", s->id); - break; - case ALPROTO_TLS: - s->mask |= SIG_MASK_REQUIRE_TLS_STATE; - SCLogDebug("sig %u requires tls app state (tls event)", s->id); - break; - } - break; - } - } - } - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { case DETECT_FLOWBITS: diff --git a/src/detect.h b/src/detect.h index 70c76dfadadf..5cb5ec379a1b 100644 --- a/src/detect.h +++ b/src/detect.h @@ -115,10 +115,7 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_BUILTIN_MAX, - /* app event engine sm list */ - DETECT_SM_LIST_APP_EVENT = DETECT_SM_LIST_BUILTIN_MAX, - - DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH = DETECT_SM_LIST_BUILTIN_MAX, DETECT_SM_LIST_MAX, From 40851eecf02e02bdb4d8e2731daa999ba711558c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Dec 2016 12:03:46 +0100 Subject: [PATCH 2389/2553] template: dynamic buffer --- src/detect-engine.c | 4 +--- src/detect-parse.c | 2 -- src/detect-template-buffer.c | 13 ++++++++----- src/detect.h | 2 -- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index d49cd24649b3..b0941fe8427b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2808,9 +2808,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_BASE64_DATA: return "base64_data"; - case DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH: - return "template_buffer"; - case DETECT_SM_LIST_POSTMATCH: return "post-match"; @@ -2819,6 +2816,7 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_THRESHOLD: return "threshold"; + case DETECT_SM_LIST_BUILTIN_MAX: case DETECT_SM_LIST_MAX: return "max (internal)"; case DETECT_SM_LIST_NOTSET: diff --git a/src/detect-parse.c b/src/detect-parse.c index c4bb73395803..5f59ba6b14c7 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -144,7 +144,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); - CASE_CODE_STRING(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, "template"); CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress"); CASE_CODE_STRING(DETECT_SM_LIST_THRESHOLD, "threshold"); @@ -164,7 +163,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); CASE_CODE(DETECT_SM_LIST_TMATCH); - CASE_CODE(DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH); CASE_CODE(DETECT_SM_LIST_POSTMATCH); CASE_CODE(DETECT_SM_LIST_SUPPRESS); CASE_CODE(DETECT_SM_LIST_THRESHOLD); diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index 866e717abebd..929153fd0907 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -39,6 +39,7 @@ static int DetectTemplateBufferSetup(DetectEngineCtx *, Signature *, char *); static void DetectTemplateBufferRegisterTests(void); +static int g_template_buffer_id = 0; void DetectTemplateBufferRegister(void) { @@ -58,20 +59,22 @@ void DetectTemplateBufferRegister(void) sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_PAYLOAD; /* register inspect engines */ - DetectAppLayerInspectEngineRegister(ALPROTO_TEMPLATE, SIG_FLAG_TOSERVER, - DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + DetectAppLayerInspectEngineRegister2("template_buffer", + ALPROTO_TEMPLATE, SIG_FLAG_TOSERVER, DetectEngineInspectTemplateBuffer); - DetectAppLayerInspectEngineRegister(ALPROTO_TEMPLATE, SIG_FLAG_TOCLIENT, - DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + DetectAppLayerInspectEngineRegister2("template_buffer", + ALPROTO_TEMPLATE, SIG_FLAG_TOCLIENT, DetectEngineInspectTemplateBuffer); + g_template_buffer_id = DetectBufferTypeGetByName("template_buffer"); + SCLogNotice("Template application layer detect registered."); } static int DetectTemplateBufferSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->init_data->list = DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH; + s->init_data->list = g_template_buffer_id; s->alproto = ALPROTO_TEMPLATE; return 0; } diff --git a/src/detect.h b/src/detect.h index 5cb5ec379a1b..e7f6a5765d44 100644 --- a/src/detect.h +++ b/src/detect.h @@ -115,8 +115,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_BUILTIN_MAX, - DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH = DETECT_SM_LIST_BUILTIN_MAX, - DETECT_SM_LIST_MAX, }; From 49fbd28ceb4299d5baa26f9423df95bc94fe5a71 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Dec 2016 12:20:46 +0100 Subject: [PATCH 2390/2553] detect: cleanup built-in list id's --- src/detect-engine.c | 8 +++----- src/detect-parse.c | 4 +--- src/detect.c | 3 ++- src/detect.h | 16 ++++++++-------- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index b0941fe8427b..8fc6fb766c6c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -161,7 +161,7 @@ int DetectEngineAppInspectionEngine2Signature(Signature *s) /* convert lists to SigMatchData arrays */ int i = 0; - for (i = DETECT_SM_LIST_BUILTIN_MAX; i < nlists; i++) { + for (i = DETECT_SM_LIST_DYNAMIC_START; i < nlists; i++) { if (s->init_data->smlists[i] == NULL) continue; @@ -267,7 +267,7 @@ void DetectEngineAppInspectionEngineSignatureFree(Signature *s) #include "util-hash-lookup3.h" static HashListTable *g_buffer_type_hash = NULL; -static int g_buffer_type_id = DETECT_SM_LIST_MAX; // past DETECT_SM_LIST_NOTSET +static int g_buffer_type_id = DETECT_SM_LIST_DYNAMIC_START; static int g_buffer_type_reg_closed = 0; typedef struct DetectBufferType_ { @@ -515,6 +515,7 @@ void DetectBufferTypeFinalizeRegistration(void) g_buffer_type_map = SCCalloc(size, sizeof(DetectBufferType *)); BUG_ON(!g_buffer_type_map); + SCLogDebug("DETECT_SM_LIST_DYNAMIC_START %u", DETECT_SM_LIST_DYNAMIC_START); HashListTableBucket *b = HashListTableGetListHead(g_buffer_type_hash); while (b) { DetectBufferType *map = HashListTableGetListData(b); @@ -2816,11 +2817,8 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_THRESHOLD: return "threshold"; - case DETECT_SM_LIST_BUILTIN_MAX: case DETECT_SM_LIST_MAX: return "max (internal)"; - case DETECT_SM_LIST_NOTSET: - return "not set (internal)"; } return "error"; } diff --git a/src/detect-parse.c b/src/detect-parse.c index 5f59ba6b14c7..64aaff96e53a 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -148,7 +148,6 @@ const char *DetectListToHumanString(int list) CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress"); CASE_CODE_STRING(DETECT_SM_LIST_THRESHOLD, "threshold"); CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)"); - CASE_CODE_STRING(DETECT_SM_LIST_NOTSET, "not set (internal)"); } #undef CASE_CODE_STRING return "unknown"; @@ -167,7 +166,6 @@ const char *DetectListToString(int list) CASE_CODE(DETECT_SM_LIST_SUPPRESS); CASE_CODE(DETECT_SM_LIST_THRESHOLD); CASE_CODE(DETECT_SM_LIST_MAX); - CASE_CODE(DETECT_SM_LIST_NOTSET); } return "unknown"; } @@ -1117,7 +1115,7 @@ static void SigMatchFreeArrays(Signature *s, int ctxs) { if (s != NULL) { int type; - for (type = 0; type < DETECT_SM_LIST_BUILTIN_MAX; type++) { + for (type = 0; type < DETECT_SM_LIST_MAX; type++) { if (s->sm_arrays[type] != NULL) { if (ctxs) { SigMatchData *smd = s->sm_arrays[type]; diff --git a/src/detect.c b/src/detect.c index 62de800c0a5d..cb21cbf9e3b8 100644 --- a/src/detect.c +++ b/src/detect.c @@ -3780,8 +3780,9 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) /* set up inspect engines */ DetectEngineAppInspectionEngine2Signature(s); + /* built-ins */ int type; - for (type = 0; type < DETECT_SM_LIST_BUILTIN_MAX; type++) { + for (type = 0; type < DETECT_SM_LIST_MAX; type++) { SigMatch *sm = s->init_data->smlists[type]; s->sm_arrays[type] = SigMatchList2DataArray(sm); } diff --git a/src/detect.h b/src/detect.h index e7f6a5765d44..8b752e4b0397 100644 --- a/src/detect.h +++ b/src/detect.h @@ -108,17 +108,17 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_SUPPRESS, DETECT_SM_LIST_THRESHOLD, - /* 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, - - DETECT_SM_LIST_BUILTIN_MAX, - 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 + /* a is ... than b */ enum { ADDRESS_ER = -1, /**< error e.g. compare ipv4 and ipv6 */ @@ -446,7 +446,7 @@ typedef struct Signature_ { /* Matching structures for the built-ins. The others are in * their inspect engines. */ - SigMatchData *sm_arrays[DETECT_SM_LIST_BUILTIN_MAX]; + SigMatchData *sm_arrays[DETECT_SM_LIST_MAX]; /* memory is still owned by the sm_lists/sm_arrays entry */ const struct DetectFilestoreData_ *filestore_ctx; From 8bd14229486b60d5bd3fea4f92b47c515600d86c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 12 Dec 2016 20:00:26 +0100 Subject: [PATCH 2391/2553] detect: detect engine registration cleanup --- src/detect-app-layer-event.c | 4 ++-- src/detect-cipservice.c | 8 ++++---- src/detect-dnp3.c | 8 ++++---- src/detect-dns-query.c | 6 +++--- src/detect-engine.c | 19 ++++++------------- src/detect-engine.h | 7 ++----- src/detect-file-data.c | 4 ++-- src/detect-filename.c | 6 +++--- src/detect-http-client-body.c | 2 +- src/detect-http-cookie.c | 4 ++-- src/detect-http-header.c | 4 ++-- src/detect-http-hh.c | 2 +- src/detect-http-hrh.c | 2 +- src/detect-http-method.c | 2 +- src/detect-http-raw-header.c | 4 ++-- src/detect-http-raw-uri.c | 2 +- src/detect-http-request-line.c | 2 +- src/detect-http-response-line.c | 2 +- src/detect-http-stat-code.c | 2 +- src/detect-http-stat-msg.c | 2 +- src/detect-http-ua.c | 2 +- src/detect-http-uri.c | 2 +- src/detect-modbus.c | 4 ++-- src/detect-template-buffer.c | 4 ++-- src/detect-tls-cert-issuer.c | 2 +- src/detect-tls-cert-subject.c | 2 +- src/detect-tls-cert-validity.c | 2 +- src/detect-tls-sni.c | 2 +- 28 files changed, 51 insertions(+), 61 deletions(-) diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index ec31ea4b8505..a4207899f426 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -78,10 +78,10 @@ void DetectAppLayerEventRegister(void) sigmatch_table[DETECT_AL_APP_LAYER_EVENT].RegisterTests = DetectAppLayerEventRegisterTests; - DetectAppLayerInspectEngineRegister2("app-layer-events", + DetectAppLayerInspectEngineRegister("app-layer-events", ALPROTO_UNKNOWN, SIG_FLAG_TOSERVER, DetectEngineAptEventInspect); - DetectAppLayerInspectEngineRegister2("app-layer-events", + DetectAppLayerInspectEngineRegister("app-layer-events", ALPROTO_UNKNOWN, SIG_FLAG_TOCLIENT, DetectEngineAptEventInspect); diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c index 8a6d61b90429..1074241d5a1c 100644 --- a/src/detect-cipservice.c +++ b/src/detect-cipservice.c @@ -59,10 +59,10 @@ void DetectCipServiceRegister(void) sigmatch_table[DETECT_CIPSERVICE].RegisterTests = DetectCipServiceRegisterTests; - DetectAppLayerInspectEngineRegister2("cip", + DetectAppLayerInspectEngineRegister("cip", ALPROTO_ENIP, SIG_FLAG_TOSERVER, DetectEngineInspectCIP); - DetectAppLayerInspectEngineRegister2("cip", + DetectAppLayerInspectEngineRegister("cip", ALPROTO_ENIP, SIG_FLAG_TOCLIENT, DetectEngineInspectCIP); @@ -321,10 +321,10 @@ void DetectEnipCommandRegister(void) sigmatch_table[DETECT_ENIPCOMMAND].RegisterTests = DetectEnipCommandRegisterTests; - DetectAppLayerInspectEngineRegister2("enip", + DetectAppLayerInspectEngineRegister("enip", ALPROTO_ENIP, SIG_FLAG_TOSERVER, DetectEngineInspectENIP); - DetectAppLayerInspectEngineRegister2("enip", + DetectAppLayerInspectEngineRegister("enip", ALPROTO_ENIP, SIG_FLAG_TOCLIENT, DetectEngineInspectENIP); diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 6c868a5f212e..438c38cb3a0a 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -549,10 +549,10 @@ static void DetectDNP3DataRegister(void) sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_PAYLOAD; - DetectAppLayerInspectEngineRegister2("dnp3_data", + DetectAppLayerInspectEngineRegister("dnp3_data", ALPROTO_DNP3, SIG_FLAG_TOSERVER, DetectEngineInspectDNP3Data); - DetectAppLayerInspectEngineRegister2("dnp3_data", + DetectAppLayerInspectEngineRegister("dnp3_data", ALPROTO_DNP3, SIG_FLAG_TOCLIENT, DetectEngineInspectDNP3Data); @@ -569,10 +569,10 @@ void DetectDNP3Register(void) DetectDNP3ObjRegister(); /* Register the list of func, ind and obj. */ - DetectAppLayerInspectEngineRegister2("dnp3", + DetectAppLayerInspectEngineRegister("dnp3", ALPROTO_DNP3, SIG_FLAG_TOSERVER, DetectEngineInspectDNP3); - DetectAppLayerInspectEngineRegister2("dnp3", + DetectAppLayerInspectEngineRegister("dnp3", ALPROTO_DNP3, SIG_FLAG_TOCLIENT, DetectEngineInspectDNP3); diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 573f021f9a5e..c8f9690b47b1 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -81,7 +81,7 @@ void DetectDnsQueryRegister (void) DetectAppLayerMpmRegister("dns_query", SIG_FLAG_TOSERVER, 2, PrefilterTxDnsQueryRegister); - DetectAppLayerInspectEngineRegister2("dns_query", + DetectAppLayerInspectEngineRegister("dns_query", ALPROTO_DNS, SIG_FLAG_TOSERVER, DetectEngineInspectDnsQueryName); @@ -91,10 +91,10 @@ void DetectDnsQueryRegister (void) g_dns_query_buffer_id = DetectBufferTypeGetByName("dns_query"); /* register these generic engines from here for now */ - DetectAppLayerInspectEngineRegister2("dns_request", + DetectAppLayerInspectEngineRegister("dns_request", ALPROTO_DNS, SIG_FLAG_TOSERVER, DetectEngineInspectDnsRequest); - DetectAppLayerInspectEngineRegister2("dns_response", + DetectAppLayerInspectEngineRegister("dns_response", ALPROTO_DNS, SIG_FLAG_TOCLIENT, DetectEngineInspectDnsResponse); diff --git a/src/detect-engine.c b/src/detect-engine.c index 8fc6fb766c6c..c19d3f0ef85b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -101,14 +101,16 @@ static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet * static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL; -void DetectAppLayerInspectEngineRegister(AppProto alproto, - uint32_t dir, int32_t sm_list, InspectEngineFuncPtr Callback) +void DetectAppLayerInspectEngineRegister(const char *name, + AppProto alproto, uint32_t dir, InspectEngineFuncPtr Callback) { - const int nlists = DetectBufferTypeMaxId(); + DetectBufferTypeRegister(name); + int sm_list = DetectBufferTypeGetByName(name); + BUG_ON(sm_list == -1); if ((alproto >= ALPROTO_FAILED) || (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) || - (sm_list < DETECT_SM_LIST_MATCH || sm_list >= nlists) || + (sm_list < DETECT_SM_LIST_MATCH) || (Callback == NULL)) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments"); @@ -144,15 +146,6 @@ void DetectAppLayerInspectEngineRegister(AppProto alproto, } } -void DetectAppLayerInspectEngineRegister2(const char *name, - AppProto alproto, uint32_t dir, InspectEngineFuncPtr Callback) -{ - DetectBufferTypeRegister(name); - int sm_list = DetectBufferTypeGetByName(name); - BUG_ON(sm_list == -1); - DetectAppLayerInspectEngineRegister(alproto, dir, sm_list, Callback); -} - int DetectEngineAppInspectionEngine2Signature(Signature *s) { const int nlists = DetectBufferTypeMaxId(); diff --git a/src/detect-engine.h b/src/detect-engine.h index ada68647a9f1..a29db7a5642a 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -97,16 +97,13 @@ int DetectEngineInspectGenericList(ThreadVars *, const DetectEngineCtx *, /** * \brief Registers an app inspection engine. * + * \param name Name of the detection list * \param alproto App layer protocol for which we will register the engine. * \param direction The direction for the engine: SIG_FLAG_TOSERVER or * SIG_FLAG_TOCLIENT - * \param sm_list The SigMatch list against which the engine works. * \param Callback The engine callback. */ -void DetectAppLayerInspectEngineRegister(AppProto alproto, - uint32_t dir, int32_t sm_list, InspectEngineFuncPtr Callback); - -void DetectAppLayerInspectEngineRegister2(const char *name, +void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uint32_t dir, InspectEngineFuncPtr Callback); int DetectEngineAppInspectionEngine2Signature(Signature *s); diff --git a/src/detect-file-data.c b/src/detect-file-data.c index e9a4a14b9453..ef245f91520a 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -71,10 +71,10 @@ void DetectFiledataRegister(void) DetectAppLayerMpmRegister("file_data", SIG_FLAG_TOCLIENT, 2, PrefilterTxHttpResponseBodyRegister); - DetectAppLayerInspectEngineRegister2("file_data", + DetectAppLayerInspectEngineRegister("file_data", ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpServerBody); - DetectAppLayerInspectEngineRegister2("file_data", + DetectAppLayerInspectEngineRegister("file_data", ALPROTO_SMTP, SIG_FLAG_TOSERVER, DetectEngineInspectSMTPFiledata); diff --git a/src/detect-filename.c b/src/detect-filename.c index 1b59519fb9e4..67b386b2f76a 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -72,14 +72,14 @@ void DetectFilenameRegister(void) sigmatch_table[DETECT_FILENAME].Free = DetectFilenameFree; sigmatch_table[DETECT_FILENAME].RegisterTests = DetectFilenameRegisterTests; - DetectAppLayerInspectEngineRegister2("files", + DetectAppLayerInspectEngineRegister("files", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectFileInspectHttp); - DetectAppLayerInspectEngineRegister2("files", + DetectAppLayerInspectEngineRegister("files", ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectFileInspectHttp); - DetectAppLayerInspectEngineRegister2("files", + DetectAppLayerInspectEngineRegister("files", ALPROTO_SMTP, SIG_FLAG_TOSERVER, DetectFileInspectSmtp); diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 9ec6be6d398e..2273aefbaefd 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -84,7 +84,7 @@ void DetectHttpClientBodyRegister(void) DetectAppLayerMpmRegister("http_client_body", SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestBodyRegister); - DetectAppLayerInspectEngineRegister2("http_client_body", + DetectAppLayerInspectEngineRegister("http_client_body", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpClientBody); diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 1cc61fe8170f..2b0baeaa21b9 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -89,10 +89,10 @@ void DetectHttpCookieRegister(void) DetectAppLayerMpmRegister("http_cookie", SIG_FLAG_TOCLIENT, 2, PrefilterTxResponseCookieRegister); - DetectAppLayerInspectEngineRegister2("http_cookie", + DetectAppLayerInspectEngineRegister("http_cookie", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpCookie); - DetectAppLayerInspectEngineRegister2("http_cookie", + DetectAppLayerInspectEngineRegister("http_cookie", ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpCookie); diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 55a248b1429f..b2696463e48c 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -88,10 +88,10 @@ void DetectHttpHeaderRegister(void) DetectAppLayerMpmRegister("http_header", SIG_FLAG_TOCLIENT, 2, PrefilterTxHttpResponseHeadersRegister); - DetectAppLayerInspectEngineRegister2("http_header", + DetectAppLayerInspectEngineRegister("http_header", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpHeader); - DetectAppLayerInspectEngineRegister2("http_header", + DetectAppLayerInspectEngineRegister("http_header", ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpHeader); diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 5e51c7cba90d..7c943d07d64c 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -85,7 +85,7 @@ void DetectHttpHHRegister(void) DetectAppLayerMpmRegister("http_host", SIG_FLAG_TOSERVER, 2, PrefilterTxHostnameRegister); - DetectAppLayerInspectEngineRegister2("http_host", + DetectAppLayerInspectEngineRegister("http_host", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpHH); diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index 439eaef78595..92f504e56676 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -84,7 +84,7 @@ void DetectHttpHRHRegister(void) DetectAppLayerMpmRegister("http_raw_host", SIG_FLAG_TOSERVER, 2, PrefilterTxHostnameRawRegister); - DetectAppLayerInspectEngineRegister2("http_raw_host", + DetectAppLayerInspectEngineRegister("http_raw_host", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpHRH); diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 3fa059cb770f..0cf00f9bcdc4 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -86,7 +86,7 @@ void DetectHttpMethodRegister(void) DetectAppLayerMpmRegister("http_method", SIG_FLAG_TOSERVER, 4, PrefilterTxMethodRegister); - DetectAppLayerInspectEngineRegister2("http_method", + DetectAppLayerInspectEngineRegister("http_method", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpMethod); diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index b1a03254d79d..35b9d3ad6286 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -87,10 +87,10 @@ void DetectHttpRawHeaderRegister(void) DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOCLIENT, 2, PrefilterTxResponseHeadersRawRegister); - DetectAppLayerInspectEngineRegister2("http_raw_header", + DetectAppLayerInspectEngineRegister("http_raw_header", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpRawHeader); - DetectAppLayerInspectEngineRegister2("http_raw_header", + DetectAppLayerInspectEngineRegister("http_raw_header", ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpRawHeader); diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 29f2c69308c9..080586e428b7 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -79,7 +79,7 @@ void DetectHttpRawUriRegister(void) DetectAppLayerMpmRegister("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterTxRawUriRegister); - DetectAppLayerInspectEngineRegister2("http_raw_uri", + DetectAppLayerInspectEngineRegister("http_raw_uri", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpRawUri); diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 15516f37beb0..7c8cd3082e7e 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -89,7 +89,7 @@ void DetectHttpRequestLineRegister(void) DetectAppLayerMpmRegister("http_request_line", SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestLineRegister); - DetectAppLayerInspectEngineRegister2("http_request_line", + DetectAppLayerInspectEngineRegister("http_request_line", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpRequestLine); diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index c798e35bb445..f7dd062faae7 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -89,7 +89,7 @@ void DetectHttpResponseLineRegister(void) DetectAppLayerMpmRegister("http_response_line", SIG_FLAG_TOCLIENT, 2, PrefilterTxHttpResponseLineRegister); - DetectAppLayerInspectEngineRegister2("http_response_line", + DetectAppLayerInspectEngineRegister("http_response_line", ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpResponseLine); diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index 8a3b4d4b6eff..938ce6e5f98e 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -88,7 +88,7 @@ void DetectHttpStatCodeRegister (void) DetectAppLayerMpmRegister("http_stat_code", SIG_FLAG_TOCLIENT, 4, PrefilterTxHttpStatCodeRegister); - DetectAppLayerInspectEngineRegister2("http_stat_code", + DetectAppLayerInspectEngineRegister("http_stat_code", ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpStatCode); diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index d3a916c2b706..57dffbf80721 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -88,7 +88,7 @@ void DetectHttpStatMsgRegister (void) DetectAppLayerMpmRegister("http_stat_msg", SIG_FLAG_TOCLIENT, 3, PrefilterTxHttpStatMsgRegister); - DetectAppLayerInspectEngineRegister2("http_stat_msg", + DetectAppLayerInspectEngineRegister("http_stat_msg", ALPROTO_HTTP, SIG_FLAG_TOCLIENT, DetectEngineInspectHttpStatMsg); diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index 5e0824dab7a7..b154806f39ef 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -85,7 +85,7 @@ void DetectHttpUARegister(void) DetectAppLayerMpmRegister("http_user_agent", SIG_FLAG_TOSERVER, 2, PrefilterTxUARegister); - DetectAppLayerInspectEngineRegister2("http_user_agent", + DetectAppLayerInspectEngineRegister("http_user_agent", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpUA); diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 45acf4a7db42..3ae8f866eb50 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -81,7 +81,7 @@ void DetectHttpUriRegister (void) DetectAppLayerMpmRegister("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterTxUriRegister); - DetectAppLayerInspectEngineRegister2("http_uri", ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectAppLayerInspectEngineRegister("http_uri", ALPROTO_HTTP, SIG_FLAG_TOSERVER, DetectEngineInspectHttpUri); DetectBufferTypeSetDescriptionByName("http_uri", diff --git a/src/detect-modbus.c b/src/detect-modbus.c index 82600c909a29..56717c475cda 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -417,10 +417,10 @@ void DetectModbusRegister(void) DetectSetupParseRegexes(PARSE_REGEX_ACCESS, &access_parse_regex, &access_parse_regex_study); - DetectAppLayerInspectEngineRegister2("modbus", + DetectAppLayerInspectEngineRegister("modbus", ALPROTO_MODBUS, SIG_FLAG_TOSERVER, DetectEngineInspectModbus); - DetectAppLayerInspectEngineRegister2("modbus", + DetectAppLayerInspectEngineRegister("modbus", ALPROTO_MODBUS, SIG_FLAG_TOCLIENT, DetectEngineInspectModbus); diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index 929153fd0907..d3838a0490fe 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -59,10 +59,10 @@ void DetectTemplateBufferRegister(void) sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_PAYLOAD; /* register inspect engines */ - DetectAppLayerInspectEngineRegister2("template_buffer", + DetectAppLayerInspectEngineRegister("template_buffer", ALPROTO_TEMPLATE, SIG_FLAG_TOSERVER, DetectEngineInspectTemplateBuffer); - DetectAppLayerInspectEngineRegister2("template_buffer", + DetectAppLayerInspectEngineRegister("template_buffer", ALPROTO_TEMPLATE, SIG_FLAG_TOCLIENT, DetectEngineInspectTemplateBuffer); diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index f3fa104da8f5..5928e442c057 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -77,7 +77,7 @@ void DetectTlsIssuerRegister(void) DetectAppLayerMpmRegister("tls_cert_issuer", SIG_FLAG_TOCLIENT, 2, PrefilterTxTlsIssuerRegister); - DetectAppLayerInspectEngineRegister2("tls_cert_issuer", + DetectAppLayerInspectEngineRegister("tls_cert_issuer", ALPROTO_TLS, SIG_FLAG_TOCLIENT, DetectEngineInspectTlsIssuer); diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index 33d4d5116186..8c4936bbd381 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -77,7 +77,7 @@ void DetectTlsSubjectRegister(void) DetectAppLayerMpmRegister("tls_cert_subject", SIG_FLAG_TOCLIENT, 2, PrefilterTxTlsSubjectRegister); - DetectAppLayerInspectEngineRegister2("tls_cert_subject", + DetectAppLayerInspectEngineRegister("tls_cert_subject", ALPROTO_TLS, SIG_FLAG_TOCLIENT, DetectEngineInspectTlsSubject); diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index 510a6ca50cbe..2a868566d507 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -120,7 +120,7 @@ void DetectTlsValidityRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - DetectAppLayerInspectEngineRegister2("tls_validity", + DetectAppLayerInspectEngineRegister("tls_validity", ALPROTO_TLS, SIG_FLAG_TOCLIENT, DetectEngineInspectTlsValidity); diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index 07c71f49c13f..8d3f8333f2a1 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -77,7 +77,7 @@ void DetectTlsSniRegister(void) DetectAppLayerMpmRegister("tls_sni", SIG_FLAG_TOSERVER, 2, PrefilterTxTlsSniRegister); - DetectAppLayerInspectEngineRegister2("tls_sni", + DetectAppLayerInspectEngineRegister("tls_sni", ALPROTO_TLS, SIG_FLAG_TOSERVER, DetectEngineInspectTlsSni); From a1465bc4fa608180c972659341d31a667eb7c0dc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 14 Dec 2016 13:08:39 +0100 Subject: [PATCH 2392/2553] detect-engine-mpm: api cleanup --- src/detect-engine-mpm.c | 19 ++++++------------- src/detect-engine-mpm.h | 5 ----- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 073600aa134d..069ea6306d9f 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -92,10 +92,14 @@ const char *builtin_mpms[] = { static DetectMpmAppLayerRegistery *g_app_mpms_list = NULL; static int g_app_mpms_list_cnt = 0; -void DetectMpmAppLayerRegister(const char *name, - int direction, int sm_list, int priority, +void DetectAppLayerMpmRegister(const char *name, + int direction, int priority, int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)) { + DetectBufferTypeSupportsMpm(name); + int sm_list = DetectBufferTypeGetByName(name); + BUG_ON(sm_list == -1); + DetectMpmAppLayerRegistery *am = SCCalloc(1, sizeof(*am)); BUG_ON(am == NULL); am->name = name; @@ -119,17 +123,6 @@ void DetectMpmAppLayerRegister(const char *name, SupportFastPatternForSigMatchList(sm_list, priority); } -void DetectAppLayerMpmRegister(const char *name, - int direction, int priority, - int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)) -{ - DetectBufferTypeSupportsMpm(name); - int sm_list = DetectBufferTypeGetByName(name); - BUG_ON(sm_list == -1); - DetectMpmAppLayerRegister(name, direction, sm_list, priority, - PrefilterRegister); -} - void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) { BUG_ON(g_app_mpms_list_cnt == 0); diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 9d53c456a8f5..d3fee45229d4 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -83,16 +83,11 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx); /** \brief register an app layer keyword for mpm * \param name keyword name * \param direction SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT - * \param sm_list list that contains the keyword's sigmatches * \param PrefilterRegister Prefilter api registration function * * \note direction must be set to either toserver or toclient. * If both are needed, register the keyword twice. */ -void DetectMpmAppLayerRegister(const char *name, - int direction, int sm_list, int priority, - int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)); - void DetectAppLayerMpmRegister(const char *name, int direction, int priority, int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)); From a9a228a2897c2f9fcf5ef78593f9b58c0ae5d1f9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Dec 2016 10:12:21 +0100 Subject: [PATCH 2393/2553] profiling: fix keyword profiling --- src/detect.h | 4 ++-- src/util-profiling-keywords.c | 44 ++++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/detect.h b/src/detect.h index 8b752e4b0397..86895a5f3b0b 100644 --- a/src/detect.h +++ b/src/detect.h @@ -696,7 +696,7 @@ typedef struct DetectEngineCtx_ { #ifdef PROFILING struct SCProfileDetectCtx_ *profile_ctx; struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx; - struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; + struct SCProfileKeywordDetectCtx_ **profile_keyword_ctx_per_list; struct SCProfileSghDetectCtx_ *profile_sgh_ctx; uint32_t profile_match_logging_threshold; #endif @@ -913,7 +913,7 @@ typedef struct DetectEngineThreadCtx_ { 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]; + struct SCProfileKeywordData_ **keyword_perf_data_per_list; int keyword_perf_list; /**< list we're currently inspecting, DETECT_SM_LIST_* */ struct SCProfileSghData_ *sgh_perf_data; #endif diff --git a/src/util-profiling-keywords.c b/src/util-profiling-keywords.c index 9ba367f56cf0..23b31f9ea7a6 100644 --- a/src/util-profiling-keywords.c +++ b/src/util-profiling-keywords.c @@ -159,6 +159,7 @@ SCProfilingKeywordDump(DetectEngineCtx *de_ctx) if (profiling_keyword_enabled == 0) return; + const int nlists = DetectBufferTypeMaxId(); gettimeofday(&tval, NULL); tms = SCLocalTime(tval.tv_sec, &local_tm); @@ -186,16 +187,23 @@ SCProfilingKeywordDump(DetectEngineCtx *de_ctx) /* global stats first */ DoDump(de_ctx->profile_keyword_ctx, fp, "total"); /* per buffer stats next, but only if there are stats to print */ - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { int j; uint64_t checks = 0; for (j = 0; j < DETECT_TBLSIZE; j++) { checks += de_ctx->profile_keyword_ctx_per_list[i]->data[j].checks; } - if (checks) - DoDump(de_ctx->profile_keyword_ctx_per_list[i], fp, - DetectSigmatchListEnumToString(i)); + if (checks) { + const char *name = NULL; + if (i < DETECT_SM_LIST_DYNAMIC_START) { + name = DetectSigmatchListEnumToString(i); + } else { + name = DetectBufferTypeGetNameById(i); + } + + DoDump(de_ctx->profile_keyword_ctx_per_list[i], fp, name); + } } fprintf(fp,"\n"); @@ -228,7 +236,7 @@ SCProfilingKeywordUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t p->ticks_no_match += ticks; /* store per list (buffer type) as well */ - if (det_ctx->keyword_perf_list >= 0 && det_ctx->keyword_perf_list < DETECT_SM_LIST_MAX) { + if (det_ctx->keyword_perf_list >= 0) {// && det_ctx->keyword_perf_list < DETECT_SM_LIST_MAX) { p = &det_ctx->keyword_perf_data_per_list[det_ctx->keyword_perf_list][id]; p->checks++; p->matches += match; @@ -274,10 +282,13 @@ void SCProfilingKeywordDestroyCtx(DetectEngineCtx *de_ctx) SCProfilingKeywordDump(de_ctx); DetroyCtx(de_ctx->profile_keyword_ctx); + + const int nlists = DetectBufferTypeMaxId(); int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { DetroyCtx(de_ctx->profile_keyword_ctx_per_list[i]); } + SCFree(de_ctx->profile_keyword_ctx_per_list); } } @@ -292,8 +303,12 @@ void SCProfilingKeywordThreadSetup(SCProfileKeywordDetectCtx *ctx, DetectEngineT det_ctx->keyword_perf_data = a; } + const int nlists = DetectBufferTypeMaxId(); + det_ctx->keyword_perf_data_per_list = SCCalloc(nlists, sizeof(SCProfileKeywordData *)); + BUG_ON(det_ctx->keyword_perf_data_per_list == NULL); + int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { SCProfileKeywordData *b = SCMalloc(sizeof(SCProfileKeywordData) * DETECT_TBLSIZE); if (b != NULL) { memset(b, 0x00, sizeof(SCProfileKeywordData) * DETECT_TBLSIZE); @@ -320,8 +335,9 @@ static void SCProfilingKeywordThreadMerge(DetectEngineCtx *de_ctx, DetectEngineT de_ctx->profile_keyword_ctx->data[i].max = det_ctx->keyword_perf_data[i].max; } + const int nlists = DetectBufferTypeMaxId(); int j; - for (j = 0; j < DETECT_SM_LIST_MAX; j++) { + for (j = 0; j < nlists; j++) { for (i = 0; i < DETECT_TBLSIZE; i++) { de_ctx->profile_keyword_ctx_per_list[j]->data[i].checks += det_ctx->keyword_perf_data_per_list[j][i].checks; de_ctx->profile_keyword_ctx_per_list[j]->data[i].matches += det_ctx->keyword_perf_data_per_list[j][i].matches; @@ -345,12 +361,13 @@ void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *det_ctx) SCFree(det_ctx->keyword_perf_data); det_ctx->keyword_perf_data = NULL; + const int nlists = DetectBufferTypeMaxId(); int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { SCFree(det_ctx->keyword_perf_data_per_list[i]); det_ctx->keyword_perf_data_per_list[i] = NULL; } - + SCFree(det_ctx->keyword_perf_data_per_list); } /** @@ -364,6 +381,8 @@ SCProfilingKeywordInitCounters(DetectEngineCtx *de_ctx) if (profiling_keyword_enabled == 0) return; + const int nlists = DetectBufferTypeMaxId(); + de_ctx->profile_keyword_ctx = SCProfilingKeywordInitCtx(); BUG_ON(de_ctx->profile_keyword_ctx == NULL); @@ -371,8 +390,11 @@ SCProfilingKeywordInitCounters(DetectEngineCtx *de_ctx) BUG_ON(de_ctx->profile_keyword_ctx->data == NULL); memset(de_ctx->profile_keyword_ctx->data, 0x00, sizeof(SCProfileKeywordData) * DETECT_TBLSIZE); + de_ctx->profile_keyword_ctx_per_list = SCCalloc(nlists, sizeof(SCProfileKeywordDetectCtx *)); + BUG_ON(de_ctx->profile_keyword_ctx_per_list == NULL); + int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { de_ctx->profile_keyword_ctx_per_list[i] = SCProfilingKeywordInitCtx(); BUG_ON(de_ctx->profile_keyword_ctx_per_list[i] == NULL); de_ctx->profile_keyword_ctx_per_list[i]->data = SCMalloc(sizeof(SCProfileKeywordData) * DETECT_TBLSIZE); From 7d8a5a75ef42640c78203f8d57e2d45c3f8edf03 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Dec 2016 11:17:13 +0100 Subject: [PATCH 2394/2553] profiling: honor limit in json rule output --- src/util-profiling-rules.c | 2 +- suricata.yaml.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index 49d1199eded4..746f9fb748a6 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -307,7 +307,7 @@ static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64 CreateIsoTimeString(&tval, timebuf, sizeof(timebuf)); json_object_set_new(js, "timestamp", json_string(timebuf)); - for (i = 0; i < count; i++) { + for (i = 0; i < MIN(count, profiling_rules_limit); i++) { /* Stop dumping when we hit our first rule with 0 checks. Due * to sorting this will be the beginning of all the rules with * 0 checks. */ diff --git a/suricata.yaml.in b/suricata.yaml.in index caecd0798ac8..a502bedab7b2 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1416,7 +1416,7 @@ profiling: # Sort options: ticks, avgticks, checks, matches, maxticks sort: avgticks - # Limit the number of items printed at exit (ignored for json). + # Limit the number of sids for which stats are shown at exit. limit: 100 # output to json From 75907fce0662b500b280a0493524daf06523aaae Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Dec 2016 11:18:44 +0100 Subject: [PATCH 2395/2553] profiling: output all sort options for rules Limit the default number of sids to 10. --- src/util-profiling-rules.c | 132 ++++++++++++++++++++++--------------- suricata.yaml.in | 7 +- 2 files changed, 83 insertions(+), 56 deletions(-) diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index 746f9fb748a6..bab516cb87d7 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -97,7 +97,16 @@ enum { SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH, SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH, }; -static int profiling_rules_sort_order = SC_PROFILING_RULES_SORT_BY_TICKS; + +static int profiling_rules_sort_orders[8] = { + SC_PROFILING_RULES_SORT_BY_TICKS, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH, + SC_PROFILING_RULES_SORT_BY_CHECKS, + SC_PROFILING_RULES_SORT_BY_MATCHES, + SC_PROFILING_RULES_SORT_BY_MAX_TICKS, + -1 }; /** * Maximum number of rules to dump. @@ -106,6 +115,11 @@ static uint32_t profiling_rules_limit = UINT32_MAX; void SCProfilingRulesGlobalInit(void) { +#define SET_ONE(x) { \ + profiling_rules_sort_orders[0] = (x); \ + profiling_rules_sort_orders[1] = -1; \ + } + ConfNode *conf; const char *val; @@ -117,32 +131,25 @@ void SCProfilingRulesGlobalInit(void) val = ConfNodeLookupChildValue(conf, "sort"); if (val != NULL) { if (strcmp(val, "ticks") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_TICKS; + SET_ONE(SC_PROFILING_RULES_SORT_BY_TICKS); } else if (strcmp(val, "avgticks") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_AVG_TICKS; + SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS); } else if (strcmp(val, "avgticks_match") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH; + SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH); } else if (strcmp(val, "avgticks_no_match") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH; + SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH); } else if (strcmp(val, "checks") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_CHECKS; + SET_ONE(SC_PROFILING_RULES_SORT_BY_CHECKS); } else if (strcmp(val, "matches") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_MATCHES; + SET_ONE(SC_PROFILING_RULES_SORT_BY_MATCHES); } else if (strcmp(val, "maxticks") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_MAX_TICKS; + SET_ONE(SC_PROFILING_RULES_SORT_BY_MAX_TICKS); } else { SCLogError(SC_ERR_INVALID_ARGUMENT, @@ -186,6 +193,7 @@ void SCProfilingRulesGlobalInit(void) } } } +#undef SET_ONE } /** @@ -288,7 +296,9 @@ SCProfileSummarySortByMaxTicks(const void *a, const void *b) #ifdef HAVE_LIBJANSSON -static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks) +static void DumpJson(FILE *fp, SCProfileSummary *summary, + uint32_t count, uint64_t total_ticks, + const char *sort_desc) { char timebuf[64]; uint32_t i; @@ -306,6 +316,7 @@ static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64 gettimeofday(&tval, NULL); CreateIsoTimeString(&tval, timebuf, sizeof(timebuf)); json_object_set_new(js, "timestamp", json_string(timebuf)); + json_object_set_new(js, "sort", json_string(sort_desc)); for (i = 0; i < MIN(count, profiling_rules_limit); i++) { /* Stop dumping when we hit our first rule with 0 checks. Due @@ -350,7 +361,9 @@ static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64 #endif /* HAVE_LIBJANSSON */ -static void DumpText(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks) +static void DumpText(FILE *fp, SCProfileSummary *summary, + uint32_t count, uint64_t total_ticks, + const char *sort_desc) { uint32_t i; struct timeval tval; @@ -362,8 +375,9 @@ static void DumpText(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64 fprintf(fp, " ----------------------------------------------" "----------------------------\n"); fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " - "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, + "%02d:%02d:%02d.", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour,tms->tm_min, tms->tm_sec); + fprintf(fp, " Sorted by: %s.\n", sort_desc); fprintf(fp, " ----------------------------------------------" "----------------------------\n"); fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", "Avg Match", "Avg No Match"); @@ -476,43 +490,55 @@ SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx) total_ticks += summary[i].ticks; } - switch (profiling_rules_sort_order) { - case SC_PROFILING_RULES_SORT_BY_TICKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByTicks); - break; - case SC_PROFILING_RULES_SORT_BY_AVG_TICKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByAvgTicks); - break; - case SC_PROFILING_RULES_SORT_BY_CHECKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByChecks); - break; - case SC_PROFILING_RULES_SORT_BY_MATCHES: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByMatches); - break; - case SC_PROFILING_RULES_SORT_BY_MAX_TICKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByMaxTicks); - break; - case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByAvgTicksMatch); - break; - case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByAvgTicksNoMatch); - break; - } + int *order = profiling_rules_sort_orders; + while (*order != -1) { + const char *sort_desc = NULL; + switch (*order) { + case SC_PROFILING_RULES_SORT_BY_TICKS: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByTicks); + sort_desc = "ticks"; + break; + case SC_PROFILING_RULES_SORT_BY_AVG_TICKS: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByAvgTicks); + sort_desc = "average ticks"; + break; + case SC_PROFILING_RULES_SORT_BY_CHECKS: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByChecks); + sort_desc = "number of checks"; + break; + case SC_PROFILING_RULES_SORT_BY_MATCHES: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByMatches); + sort_desc = "number of matches"; + break; + case SC_PROFILING_RULES_SORT_BY_MAX_TICKS: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByMaxTicks); + sort_desc = "max ticks"; + break; + case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByAvgTicksMatch); + sort_desc = "average ticks (match)"; + break; + case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByAvgTicksNoMatch); + sort_desc = "average ticks (no match)"; + break; + } #ifdef HAVE_LIBJANSSON - if (profiling_rule_json) { - DumpJson(fp, summary, count, total_ticks); - } else + if (profiling_rule_json) { + DumpJson(fp, summary, count, total_ticks, sort_desc); + } else #endif - { - DumpText(fp, summary, count, total_ticks); + { + DumpText(fp, summary, count, total_ticks, sort_desc); + } + order++; } if (fp != stdout) diff --git a/suricata.yaml.in b/suricata.yaml.in index a502bedab7b2..eef8799486cb 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1414,10 +1414,11 @@ profiling: append: yes # Sort options: ticks, avgticks, checks, matches, maxticks - sort: avgticks + # If commented out all the sort options will be used. + #sort: avgticks - # Limit the number of sids for which stats are shown at exit. - limit: 100 + # Limit the number of sids for which stats are shown at exit (per sort). + limit: 10 # output to json json: @e_enable_evelog@ From cf9678d926f4e09d962ac1dee1cd808786ccf8cb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Dec 2016 11:25:27 +0100 Subject: [PATCH 2396/2553] detect: global registery for keyword thread data Some keywords need a scratch space where they can do store the results of expensive operations that remain valid for the time of a packets journey through the detection engine. An example is the reconstructed 'http_header' field, that is needed in MPM, and then for each rule that manually inspects it. Storing this data in the flow is a waste, and reconstructing multiple times on demand as well. This API allows for registering a keyword with an init and free function. It it mean to be used an initialization time, when the keyword is registered. --- src/detect-engine.c | 130 +++++++++++++++++++++++++++++++++++++++++++- src/detect-engine.h | 4 ++ src/detect.c | 1 + src/detect.h | 12 +++- 4 files changed, 144 insertions(+), 3 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index c19d3f0ef85b..d6a412f21ee0 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -91,7 +91,8 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( static int DetectEngineCtxLoadConf(DetectEngineCtx *); -static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, 0, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL,}; +static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, + 0, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0}; static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len); static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len); @@ -1387,6 +1388,62 @@ void DetectEngineResetMaxSigId(DetectEngineCtx *de_ctx) de_ctx->signum = 0; } +static int DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx *det_ctx) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->keyword_id > 0) { + det_ctx->global_keyword_ctxs_array = SCCalloc(master->keyword_id, sizeof(void *)); + if (det_ctx->global_keyword_ctxs_array == NULL) { + SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx"); + goto error; + } + det_ctx->global_keyword_ctxs_size = master->keyword_id; + + DetectEngineThreadKeywordCtxItem *item = master->keyword_list; + while (item) { + det_ctx->global_keyword_ctxs_array[item->id] = item->InitFunc(item->data); + if (det_ctx->global_keyword_ctxs_array[item->id] == NULL) { + SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx " + "for keyword \"%s\" failed", item->name); + goto error; + } + item = item->next; + } + } + SCMutexUnlock(&master->lock); + return TM_ECODE_OK; +error: + SCMutexUnlock(&master->lock); + return TM_ECODE_FAILED; +} + +static void DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx->global_keyword_ctxs_array == NULL || + det_ctx->global_keyword_ctxs_size == 0) { + return; + } + + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->keyword_id > 0) { + DetectEngineThreadKeywordCtxItem *item = master->keyword_list; + while (item) { + if (det_ctx->global_keyword_ctxs_array[item->id] != NULL) + item->FreeFunc(det_ctx->global_keyword_ctxs_array[item->id]); + + item = item->next; + } + det_ctx->global_keyword_ctxs_size = 0; + SCFree(det_ctx->global_keyword_ctxs_array); + det_ctx->global_keyword_ctxs_array = NULL; + } + SCMutexUnlock(&master->lock); +} + static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { if (de_ctx->keyword_id > 0) { @@ -1605,6 +1662,7 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * } DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx); + DetectEngineThreadCtxInitGlobalKeywords(det_ctx); #ifdef PROFILING SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx); SCProfilingKeywordThreadSetup(de_ctx->profile_keyword_ctx, det_ctx); @@ -1823,6 +1881,7 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) SCFree(det_ctx->base64_decoded); } + DetectEngineThreadCtxDeinitGlobalKeywords(det_ctx); if (det_ctx->de_ctx != NULL) { DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx); #ifdef UNITTESTS @@ -1924,6 +1983,75 @@ void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) return det_ctx->keyword_ctxs_array[id]; } + +/** \brief Register Thread keyword context Funcs (Global) + * + * IDs stay static over reloads and between tenants + * + * \param name keyword name for error printing + * \param InitFunc function ptr + * \param FreeFunc function ptr + * + * \retval id for retrieval of ctx at runtime + * \retval -1 on error + */ +int DetectRegisterThreadCtxGlobalFuncs(const char *name, + void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *)) +{ + int id; + BUG_ON(InitFunc == NULL || FreeFunc == NULL); + + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + /* if already registered, return existing id */ + DetectEngineThreadKeywordCtxItem *item = master->keyword_list; + while (item != NULL) { + if (strcmp(name, item->name) == 0) { + id = item->id; + SCMutexUnlock(&master->lock); + return id; + } + + item = item->next; + } + + item = SCCalloc(1, sizeof(*item)); + if (unlikely(item == NULL)) + return -1; + + item->InitFunc = InitFunc; + item->FreeFunc = FreeFunc; + item->name = name; + item->data = data; + + item->next = master->keyword_list; + master->keyword_list = item; + item->id = master->keyword_id++; + + id = item->id; + SCMutexUnlock(&master->lock); + return id; +} + +/** \brief Retrieve thread local keyword ctx by id + * + * \param det_ctx detection engine thread ctx to retrieve the ctx from + * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at + * keyword init. + * + * \retval ctx or NULL on error + */ +void *DetectThreadCtxGetGlobalKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) +{ + if (id < 0 || id > det_ctx->global_keyword_ctxs_size || + det_ctx->global_keyword_ctxs_array == NULL) { + return NULL; + } + + return det_ctx->global_keyword_ctxs_array[id]; +} + /** \brief Check if detection is enabled * \retval bool true or false */ int DetectEngineEnabled(void) diff --git a/src/detect-engine.h b/src/detect-engine.h index a29db7a5642a..9c1c1614a5c3 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -53,6 +53,10 @@ DetectEngineCtx *DetectEngineCtxInit(void); DetectEngineCtx *DetectEngineCtxInitMinimal(void); void DetectEngineCtxFree(DetectEngineCtx *); +int DetectRegisterThreadCtxGlobalFuncs(const char *name, + void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *)); +void *DetectThreadCtxGetGlobalKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id); + TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **); TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *); //inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *); diff --git a/src/detect.c b/src/detect.c index cb21cbf9e3b8..0bb8167902f2 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1049,6 +1049,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SCLogDebug("pcap_cnt %"PRIu64, p->pcap_cnt); + det_ctx->ticker++; p->alerts.cnt = 0; det_ctx->filestore_cnt = 0; det_ctx->smsg = NULL; diff --git a/src/detect.h b/src/detect.h index 86895a5f3b0b..c1321914dc66 100644 --- a/src/detect.h +++ b/src/detect.h @@ -778,6 +778,9 @@ typedef struct DetectEngineThreadCtx_ { * on this beeing the first member */ uint32_t tenant_id; + /** ticker that is incremented once per packet. */ + uint64_t ticker; + /* the thread to which this detection engine thread belongs */ ThreadVars *tv; @@ -900,10 +903,12 @@ typedef struct DetectEngineThreadCtx_ { } filestore[DETECT_FILESTORE_MAX]; DetectEngineCtx *de_ctx; - /** store for keyword contexts that need a per thread storage because of - * thread safety issues */ + /** 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; @@ -1146,6 +1151,9 @@ typedef struct DetectEngineMasterCtx_ { * structures. */ DetectEngineTenantMapping *tenant_mapping_list; + /** list of keywords that need thread local ctxs */ + DetectEngineThreadKeywordCtxItem *keyword_list; + int keyword_id; } DetectEngineMasterCtx; /** \brief Signature loader statistics */ From aaeeae0722ffdd91221518a6a2b7ef903cc7ef10 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Dec 2016 11:25:58 +0100 Subject: [PATCH 2397/2553] detect: http_header_names sticky buffer keyword A sticky buffer that allows content inspection on a contructed buffer of HTTP header names. The buffer starts with \r\n, the names are separated by \r\n and the end of the buffer contains an extra \r\n. E.g. \r\nHost\r\nUser-Agent\r\n\r\n The leading \r\n is to make sure one can match on a full name in all cases. --- src/Makefile.am | 1 + src/detect-http-header-names.c | 560 +++++++++++++++++++++++++++++++++ src/detect-http-header-names.h | 29 ++ src/detect.c | 2 + src/detect.h | 1 + 5 files changed, 593 insertions(+) create mode 100644 src/detect-http-header-names.c create mode 100644 src/detect-http-header-names.h diff --git a/src/Makefile.am b/src/Makefile.am index ada1afc6a4d8..4617dfbf647e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -165,6 +165,7 @@ detect-hostbits.c detect-hostbits.h \ detect-http-client-body.c detect-http-client-body.h \ detect-http-cookie.c detect-http-cookie.h \ detect-http-header.c detect-http-header.h \ +detect-http-header-names.c detect-http-header-names.h \ detect-http-hh.c detect-http-hh.h \ detect-http-hrh.c detect-http-hrh.h \ detect-http-method.c detect-http-method.h \ diff --git a/src/detect-http-header-names.c b/src/detect-http-header-names.c new file mode 100644 index 000000000000..df7165f270a5 --- /dev/null +++ b/src/detect-http-header-names.c @@ -0,0 +1,560 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support http_header_names + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" +#include "util-print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "detect-http-header.h" +#include "stream-tcp.h" + +#include "util-print.h" + +#define KEYWORD_NAME "http_header_names" +#define KEYWORD_DOC "http-keywords#http-header-names" +#define BUFFER_NAME "http_header_names" +#define BUFFER_DESC "http header names" +static int g_buffer_id = 0; +static int g_keyword_thread_id = 0; + +#define BUFFER_TX_STEP 4 +#define BUFFER_SIZE_STEP 256 + +typedef struct Buffer_ { + uint8_t *buffer; + uint32_t size; /**< buffer size */ + uint32_t len; /**< part of buffer in use */ +} Buffer; + +typedef struct HttpHeaderNamesThreadData_ { + Buffer *buffers; /**< array of buffers */ + uint16_t buffers_size; /**< number of buffers */ + uint16_t buffers_list_len; + uint64_t start_tx_id; + uint64_t tick; +} HttpHeaderNamesThreadData; + +static inline int CreateSpace(HttpHeaderNamesThreadData *hn, uint64_t size); +static inline int ExpandBuffer(Buffer *buf, uint32_t size); + +static void *HttpHeaderNamesThreadDataInit(void *data) +{ + HttpHeaderNamesThreadData *d = SCCalloc(1, sizeof(*d)); + if (d != NULL) { + /* initialize minimal buffers */ + (void)CreateSpace(d, 1); + int i; + for (i = 0; i < d->buffers_size; i++) { + (void)ExpandBuffer(&d->buffers[i], 1); + } + } + return d; +} + +static void HttpHeaderNamesThreadDataFree(void *data) +{ + HttpHeaderNamesThreadData *hdrnames = data; + + int i; + for (i = 0; i < hdrnames->buffers_size; i++) { + if (hdrnames->buffers[i].buffer) + SCFree(hdrnames->buffers[i].buffer); + if (hdrnames->buffers[i].size) { + SCLogDebug("hdrnames->buffers[%d].size %u (%u)", + i, hdrnames->buffers[i].size, hdrnames->buffers_size); + } + } + SCFree(hdrnames->buffers); + SCFree(hdrnames); +} + +static void Reset(HttpHeaderNamesThreadData *hdrnames, uint64_t tick) +{ + uint16_t i; + for (i = 0; i < hdrnames->buffers_list_len; i++) { + hdrnames->buffers[i].len = 0; + } + hdrnames->buffers_list_len = 0; + hdrnames->start_tx_id = 0; + hdrnames->tick = tick; +} + +static inline int CreateSpace(HttpHeaderNamesThreadData *hn, uint64_t size) +{ + if (size >= SHRT_MAX) + return -1; + + if (size > hn->buffers_size) { + uint16_t extra = BUFFER_TX_STEP; + while (hn->buffers_size + extra < size) { + extra += BUFFER_TX_STEP; + } + SCLogDebug("adding %u to the buffer", (uint)extra); + + void *ptmp = SCRealloc(hn->buffers, + (hn->buffers_size + extra) * sizeof(Buffer)); + if (ptmp == NULL) { + SCFree(hn->buffers); + hn->buffers = NULL; + hn->buffers_size = 0; + hn->buffers_list_len = 0; + return -1; + } + hn->buffers = ptmp; + memset(hn->buffers + hn->buffers_size, 0, extra * sizeof(Buffer)); + hn->buffers_size += extra; + } + + return 0; +} + +static inline int ExpandBuffer(Buffer *buf, uint32_t size) +{ + size_t extra = BUFFER_SIZE_STEP; + while ((buf->size + extra) < (size + buf->len)) { + extra += BUFFER_SIZE_STEP; + } + SCLogDebug("adding %u to the buffer", (uint)extra); + + uint8_t *new_buffer = SCRealloc(buf->buffer, buf->size + extra); + if (unlikely(new_buffer == NULL)) { + buf->len = 0; + return -1; + } + buf->buffer = new_buffer; + buf->size += extra; + return 0; +} + +static Buffer *GetBufferSpaceForTXID(DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, uint64_t tx_id) +{ + int index = 0; + + HttpHeaderNamesThreadData *hdrnames = + DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, g_keyword_thread_id); + if (hdrnames == NULL) + return NULL; + if (hdrnames->tick != det_ctx->ticker) + Reset(hdrnames, det_ctx->ticker); + + if (hdrnames->buffers_list_len == 0) { + /* get the inspect id to use as a 'base id' */ + uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + BUG_ON(base_inspect_id > tx_id); + /* see how many space we need for the current tx_id */ + uint64_t txs = (tx_id - base_inspect_id) + 1; + if (CreateSpace(hdrnames, txs) < 0) + return NULL; + + index = (tx_id - base_inspect_id); + hdrnames->start_tx_id = base_inspect_id; + hdrnames->buffers_list_len = txs; + } else { + /* tx fits in our current buffers */ + if ((tx_id - hdrnames->start_tx_id) < hdrnames->buffers_list_len) { + /* if we previously reassembled, return that buffer */ + if (hdrnames->buffers[(tx_id - hdrnames->start_tx_id)].len != 0) { + return &hdrnames->buffers[(tx_id - hdrnames->start_tx_id)]; + } + /* otherwise fall through */ + } else { + /* not enough space, lets expand */ + uint64_t txs = (tx_id - hdrnames->start_tx_id) + 1; + if (CreateSpace(hdrnames, txs) < 0) + return NULL; + + hdrnames->buffers_list_len = txs; + } + index = (tx_id - hdrnames->start_tx_id); + } + Buffer *buf = &hdrnames->buffers[index]; + return buf; +} + +static uint8_t *GetBufferForTX(htp_tx_t *tx, uint64_t tx_id, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Flow *f, HtpState *htp_state, uint8_t flags, + uint32_t *buffer_len) +{ + *buffer_len = 0; + + Buffer *buf = GetBufferSpaceForTXID(det_ctx, f, flags, tx_id); + if (unlikely(buf == NULL)) { + return NULL; + } else if (buf->len > 0) { + /* already filled buf, reuse */ + *buffer_len = buf->len; + return buf->buffer; + } + + htp_table_t *headers; + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= + HTP_REQUEST_HEADERS) + return NULL; + headers = tx->request_headers; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= + HTP_RESPONSE_HEADERS) + return NULL; + headers = tx->response_headers; + } + if (headers == NULL) + return NULL; + + /* fill the buffer. \r\nName1\r\nName2\r\n\r\n */ + size_t i = 0; + size_t no_of_headers = htp_table_size(headers); + for (; i < no_of_headers; i++) { + htp_header_t *h = htp_table_get_index(headers, i, NULL); + size_t size = bstr_size(h->name) + 2; // for \r\n + if (i == 0) + size += 2; + if (i + 1 == no_of_headers) + size += 2; + + SCLogDebug("size %u + buf->len %u vs buf->size %u", (uint)size, buf->len, buf->size); + if (size + buf->len > buf->size) { + if (ExpandBuffer(buf, size) != 0) { + return NULL; + } + } + + /* start with a \r\n */ + if (i == 0) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } + + memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); + buf->len += bstr_size(h->name); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + + /* end with an extra \r\n */ + if (i + 1 == no_of_headers) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } + } + + *buffer_len = buf->len; + return buf->buffer; +} + +/** \brief HTTP Headers Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpRequestHeaderNames(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_headers == NULL) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = GetBufferForTX(tx, idx, + NULL, det_ctx, f, htp_state, + flags, &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#if 0 +static void PrefilterTxHttpRequestTrailers(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_headers == NULL) + return; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && !htud->request_has_trailers) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#endif +int PrefilterTxHttpRequestHeaderNamesRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaderNames, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + return r; +#if 0 + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestTrailers, + ALPROTO_HTTP, HTP_REQUEST_TRAILER, + mpm_ctx, NULL, "http_header (request)"); +#endif +} + +/** \brief HTTP Headers Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpResponseHeaderNames(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = GetBufferForTX(tx, idx, NULL, det_ctx, + f, htp_state, flags, &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#if 0 +static void PrefilterTxHttpResponseTrailers(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && !htud->response_has_trailers) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#endif +int PrefilterTxHttpResponseHeaderNamesRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaderNames, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + return r; +#if 0 + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseTrailers, + ALPROTO_HTTP, HTP_RESPONSE_TRAILER, + mpm_ctx, NULL, "http_header (response)"); +#endif +} + +int InspectEngineHttpHeaderNames(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + HtpState *htp_state = (HtpState *)alstate; + uint32_t buffer_len = 0; + uint8_t *buffer = GetBufferForTX(tx, tx_id, + de_ctx, det_ctx, f, htp_state, + flags, &buffer_len); + if (buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +/** + * \brief The setup function for the http_header keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to signature for the current Signature being parsed + * from the rules. + * \param m Pointer to the head of the SigMatchs for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int DetectHttpHeaderNamesSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_buffer_id; + return 0; +} + +static void DetectHttpHeaderNamesSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +/** + * \brief Registers the keyword handlers for the "http_header" keyword. + */ +void DetectHttpHeaderNamesRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].url = DOC_URL DOC_VERSION "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].Setup = DetectHttpHeaderNamesSetup; + + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].flags |= SIGMATCH_NOOPT ; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].flags |= SIGMATCH_PAYLOAD ; + + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxHttpRequestHeaderNamesRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxHttpResponseHeaderNamesRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + InspectEngineHttpHeaderNames); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + InspectEngineHttpHeaderNames); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, + BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, + DetectHttpHeaderNamesSetupCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs(KEYWORD_NAME, + HttpHeaderNamesThreadDataInit, HttpHeaderNamesThreadDataFree); + + SCLogDebug("keyword %s registered. Thread id %d. " + "Buffer %s registered. Buffer id %d", + KEYWORD_NAME, g_keyword_thread_id, + BUFFER_NAME, g_buffer_id); +} diff --git a/src/detect-http-header-names.h b/src/detect-http-header-names.h new file mode 100644 index 000000000000..f45a0ae00a60 --- /dev/null +++ b/src/detect-http-header-names.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 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 + */ + +#ifndef __DETECT_HTTP_HEADER_NAMES_H__ +#define __DETECT_HTTP_HEADER_NAMES_H__ + +void DetectHttpHeaderNamesRegister(void); + +#endif /* __DETECT_HTTP_HEADER_NAMES_H__ */ diff --git a/src/detect.c b/src/detect.c index 0bb8167902f2..19d2d9a49150 100644 --- a/src/detect.c +++ b/src/detect.c @@ -138,6 +138,7 @@ #include "detect-http-client-body.h" #include "detect-http-server-body.h" #include "detect-http-header.h" +#include "detect-http-header-names.h" #include "detect-http-raw-header.h" #include "detect-http-uri.h" #include "detect-http-raw-uri.h" @@ -4055,6 +4056,7 @@ void SigTableSetup(void) DetectHttpResponseLineRegister(); DetectHttpServerBodyRegister(); DetectHttpHeaderRegister(); + DetectHttpHeaderNamesRegister(); DetectHttpRawHeaderRegister(); DetectHttpMethodRegister(); DetectHttpCookieRegister(); diff --git a/src/detect.h b/src/detect.h index c1321914dc66..8a68f6774d19 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1255,6 +1255,7 @@ enum { DETECT_AL_HTTP_CLIENT_BODY, DETECT_AL_HTTP_SERVER_BODY, DETECT_AL_HTTP_HEADER, + DETECT_AL_HTTP_HEADER_NAMES, DETECT_AL_HTTP_RAW_HEADER, DETECT_AL_HTTP_URI, DETECT_AL_HTTP_RAW_URI, From 2bb0cae05afdd7211f2529525f4f2684ec05d91f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Dec 2016 14:38:27 +0100 Subject: [PATCH 2398/2553] http_header: move all code into keyword files --- src/detect-engine-hhd.c | 3854 ------------------------------------- src/detect-engine-hhd.h | 12 - src/detect-http-header.c | 3913 +++++++++++++++++++++++++++++++++++++- src/detect-http-header.h | 2 + src/runmode-unittests.c | 1 - 5 files changed, 3876 insertions(+), 3906 deletions(-) diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index d17ccafd77fc..aab3c56205b0 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -61,3870 +61,16 @@ #include "util-validate.h" -#define BUFFER_STEP 50 - -static inline int HHDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) -{ - if (size >= (USHRT_MAX - BUFFER_STEP)) - return -1; - - void *ptmp; - if (size > det_ctx->hhd_buffers_size) { - ptmp = SCRealloc(det_ctx->hhd_buffers, - (det_ctx->hhd_buffers_size + BUFFER_STEP) * sizeof(uint8_t *)); - if (ptmp == NULL) { - SCFree(det_ctx->hhd_buffers); - det_ctx->hhd_buffers = NULL; - det_ctx->hhd_buffers_size = 0; - det_ctx->hhd_buffers_list_len = 0; - return -1; - } - det_ctx->hhd_buffers = ptmp; - - memset(det_ctx->hhd_buffers + det_ctx->hhd_buffers_size, 0, BUFFER_STEP * sizeof(uint8_t *)); - ptmp = SCRealloc(det_ctx->hhd_buffers_len, - (det_ctx->hhd_buffers_size + BUFFER_STEP) * sizeof(uint32_t)); - if (ptmp == NULL) { - SCFree(det_ctx->hhd_buffers_len); - det_ctx->hhd_buffers_len = NULL; - det_ctx->hhd_buffers_size = 0; - det_ctx->hhd_buffers_list_len = 0; - return -1; - } - det_ctx->hhd_buffers_len = ptmp; - - memset(det_ctx->hhd_buffers_len + det_ctx->hhd_buffers_size, 0, BUFFER_STEP * sizeof(uint32_t)); - det_ctx->hhd_buffers_size += BUFFER_STEP; - } - memset(det_ctx->hhd_buffers_len + det_ctx->hhd_buffers_list_len, 0, (size - det_ctx->hhd_buffers_list_len) * sizeof(uint32_t)); - - return 0; -} - -static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Flow *f, HtpState *htp_state, - uint8_t flags, - uint32_t *buffer_len) -{ - uint8_t *headers_buffer = NULL; - int index = 0; - *buffer_len = 0; - - if (det_ctx->hhd_buffers_list_len == 0) { - /* get the inspect id to use as a 'base id' */ - uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); - BUG_ON(base_inspect_id > tx_id); - /* see how many space we need for the current tx_id */ - uint64_t txs = (tx_id - base_inspect_id) + 1; - if (HHDCreateSpace(det_ctx, txs) < 0) - goto end; - - index = (tx_id - base_inspect_id); - det_ctx->hhd_start_tx_id = base_inspect_id; - det_ctx->hhd_buffers_list_len = txs; - } else { - /* tx fits in our current buffers */ - if ((tx_id - det_ctx->hhd_start_tx_id) < det_ctx->hhd_buffers_list_len) { - /* if we previously reassembled, return that buffer */ - if (det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)] != 0) { - *buffer_len = det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)]; - return det_ctx->hhd_buffers[(tx_id - det_ctx->hhd_start_tx_id)]; - } - /* otherwise fall through */ - } else { - /* not enough space, lets expand */ - uint64_t txs = (tx_id - det_ctx->hhd_start_tx_id) + 1; - if (HHDCreateSpace(det_ctx, txs) < 0) - goto end; - - det_ctx->hhd_buffers_list_len = txs; - } - index = (tx_id - det_ctx->hhd_start_tx_id); - } - - htp_table_t *headers; - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_REQUEST_HEADERS) - goto end; - headers = tx->request_headers; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_RESPONSE_HEADERS) - goto end; - headers = tx->response_headers; - } - if (headers == NULL) - goto end; - - htp_header_t *h = NULL; - headers_buffer = det_ctx->hhd_buffers[index]; - size_t headers_buffer_len = 0; - size_t i = 0; - - size_t no_of_headers = htp_table_size(headers); - for (; i < no_of_headers; i++) { - h = htp_table_get_index(headers, i, NULL); - size_t size1 = bstr_size(h->name); - size_t size2 = bstr_size(h->value); - - if (flags & STREAM_TOSERVER) { - if (size1 == 6 && - SCMemcmpLowercase("cookie", bstr_ptr(h->name), 6) == 0) { - continue; - } - } else { - if (size1 == 10 && - SCMemcmpLowercase("set-cookie", bstr_ptr(h->name), 10) == 0) { - continue; - } - } - - /* the extra 4 bytes if for ": " and "\r\n" */ - uint8_t *new_headers_buffer = SCRealloc(headers_buffer, headers_buffer_len + size1 + size2 + 4); - if (unlikely(new_headers_buffer == NULL)) { - if (headers_buffer != NULL) { - SCFree(headers_buffer); - headers_buffer = NULL; - } - det_ctx->hhd_buffers[index] = NULL; - det_ctx->hhd_buffers_len[index] = 0; - goto end; - } - headers_buffer = new_headers_buffer; - - memcpy(headers_buffer + headers_buffer_len, bstr_ptr(h->name), size1); - headers_buffer_len += size1; - headers_buffer[headers_buffer_len] = ':'; - headers_buffer[headers_buffer_len + 1] = ' '; - headers_buffer_len += 2; - memcpy(headers_buffer + headers_buffer_len, bstr_ptr(h->value), size2); - headers_buffer_len += size2 + 2; - /* \r */ - headers_buffer[headers_buffer_len - 2] = '\r'; - /* \n */ - headers_buffer[headers_buffer_len - 1] = '\n'; - } - - /* store the buffers. We will need it for further inspection */ - det_ctx->hhd_buffers[index] = headers_buffer; - det_ctx->hhd_buffers_len[index] = headers_buffer_len; - - *buffer_len = (uint32_t)headers_buffer_len; - end: - return headers_buffer; -} - -/** \brief HTTP Headers Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterTxHttpRequestHeaders(DetectEngineThreadCtx *det_ctx, - const void *pectx, - Packet *p, Flow *f, void *txv, - const uint64_t idx, const uint8_t flags) -{ - SCEnter(); - - const MpmCtx *mpm_ctx = (MpmCtx *)pectx; - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->request_headers == NULL) - return; - - HtpState *htp_state = f->alstate; - uint32_t buffer_len = 0; - const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, - NULL, det_ctx, - f, htp_state, - flags, - &buffer_len); - - if (buffer_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); - } -} -#if 0 -static void PrefilterTxHttpRequestTrailers(DetectEngineThreadCtx *det_ctx, - const void *pectx, - Packet *p, Flow *f, void *txv, - const uint64_t idx, const uint8_t flags) -{ - SCEnter(); - - const MpmCtx *mpm_ctx = (MpmCtx *)pectx; - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->request_headers == NULL) - return; - const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); - /* if the request wasn't flagged as having a trailer, we skip */ - if (htud && !htud->request_has_trailers) - return; - - HtpState *htp_state = f->alstate; - uint32_t buffer_len = 0; - const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, - NULL, det_ctx, - f, htp_state, - flags, - &buffer_len); - - if (buffer_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); - } -} -#endif -int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) -{ - SCEnter(); - - int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaders, - ALPROTO_HTTP, HTP_REQUEST_HEADERS, - mpm_ctx, NULL, "http_header (request)"); - return r; -#if 0 - if (r != 0) - return r; - return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestTrailers, - ALPROTO_HTTP, HTP_REQUEST_TRAILER, - mpm_ctx, NULL, "http_header (request)"); -#endif -} - -/** \brief HTTP Headers Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterTxHttpResponseHeaders(DetectEngineThreadCtx *det_ctx, - const void *pectx, - Packet *p, Flow *f, void *txv, - const uint64_t idx, const uint8_t flags) -{ - SCEnter(); - - const MpmCtx *mpm_ctx = (MpmCtx *)pectx; - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->response_headers == NULL) - return; - - HtpState *htp_state = f->alstate; - uint32_t buffer_len = 0; - const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, - NULL, det_ctx, - f, htp_state, - flags, - &buffer_len); - - if (buffer_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); - } -} -#if 0 -static void PrefilterTxHttpResponseTrailers(DetectEngineThreadCtx *det_ctx, - const void *pectx, - Packet *p, Flow *f, void *txv, - const uint64_t idx, const uint8_t flags) -{ - SCEnter(); - - const MpmCtx *mpm_ctx = (MpmCtx *)pectx; - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->response_headers == NULL) - return; - const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); - /* if the request wasn't flagged as having a trailer, we skip */ - if (htud && !htud->response_has_trailers) - return; - - HtpState *htp_state = f->alstate; - uint32_t buffer_len = 0; - const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, - NULL, det_ctx, - f, htp_state, - flags, - &buffer_len); - - if (buffer_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); - } -} -#endif -int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) -{ - SCEnter(); - - int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaders, - ALPROTO_HTTP, HTP_RESPONSE_HEADERS, - mpm_ctx, NULL, "http_header (response)"); - return r; -#if 0 - if (r != 0) - return r; - return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseTrailers, - ALPROTO_HTTP, HTP_RESPONSE_TRAILER, - mpm_ctx, NULL, "http_header (response)"); -#endif -} - -int DetectEngineInspectHttpHeader(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatchData *smd, - Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) -{ - HtpState *htp_state = (HtpState *)alstate; - uint32_t buffer_len = 0; - uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, tx_id, - de_ctx, det_ctx, - f, htp_state, - flags, - &buffer_len); - if (buffer_len == 0) - goto end; - - det_ctx->buffer_offset = 0; - det_ctx->discontinue_matching = 0; - det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, - f, - buffer, - buffer_len, - 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); - if (r == 1) - return DETECT_ENGINE_INSPECT_SIG_MATCH; - - end: - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx) -{ - if (det_ctx->hhd_buffers_list_len != 0) { - int i; - for (i = 0; i < det_ctx->hhd_buffers_list_len; i++) { - det_ctx->hhd_buffers_len[i] = 0; - } - det_ctx->hhd_buffers_list_len = 0; - } - det_ctx->hhd_start_tx_id = 0; - - return; -} - /***********************************Unittests**********************************/ #ifdef UNITTESTS -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest01(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest02(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; depth:15; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest03(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; depth:5; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest04(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; depth:5; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest05(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; depth:15; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest06(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; offset:10; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest07(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; offset:15; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest08(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; offset:15; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest09(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; offset:10; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest10(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"three\"; http_header; within:10; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest11(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"three\"; http_header; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest12(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"three\"; http_header; within:10; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest13(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"three\"; http_header; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest14(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"five\"; http_header; distance:7; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest15(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"five\"; http_header; distance:15; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest16(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"five\"; http_header; distance:7; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest17(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"five\"; http_header; distance:15; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -static int DetectEngineHttpHeaderTest20(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; http_header; within:7; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest21(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; within:7; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest22(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; distance:3; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest23(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; distance:13; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest24(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; within:15; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest25(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; within:10; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest26(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; distance:8; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest27(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; distance:14; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest28(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Content-Length: 6\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOCLIENT, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - FAIL_IF(!PacketAlertCheck(p2, 1)); - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest29(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Content-Length: 7\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOCLIENT, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -#if 0 - -static int DetectEngineHttpHeaderTest30(void) -{ - int result = 0; - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } - - de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Content-Length: 6\"; http_header; " - "content:\"User-Agent: Mozilla\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list != NULL) { - goto end; - } - - result = 1; - - end: - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -#endif /* #if 0 */ - -static int DetectEngineHttpHeaderTest30(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Set-Cookie: dummycookieset\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"dummycookieset\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOCLIENT, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -/** \test reassembly bug where headers with names of length 6 were - * skipped - */ -static int DetectEngineHttpHeaderTest31(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Accept: blah\r\n" - "Cookie: blah\r\n" - "Crazy6: blah\r\n" - "SixZix: blah\r\n\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Accept|3a|\"; http_header; " - "content:!\"Cookie|3a|\"; http_header; " - "content:\"Crazy6|3a|\"; http_header; " - "content:\"SixZix|3a|\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -/** - * \test Trailing headers. - */ -static int DetectEngineHttpHeaderTest32(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "host: boom\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "13\r\n" - "This is dummy body1\r\n" - "0\r\n" - "Dummy-Header: kaboom\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Dummy\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -/** - * \test Trailing headers. - */ -static int DetectEngineHttpHeaderTest33(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "host: boom\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "13\r\n" - "This is dummy body1\r\n" - "0\r\n"; - uint8_t http2_buf[] = - "Dummy-Header: kaboom\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Dummy\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - FLOWLOCK_WRLOCK(&f); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have\n"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - #endif /* UNITTESTS */ void DetectEngineHttpHeaderRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectEngineHttpHeaderTest01", - DetectEngineHttpHeaderTest01); - UtRegisterTest("DetectEngineHttpHeaderTest02", - DetectEngineHttpHeaderTest02); - UtRegisterTest("DetectEngineHttpHeaderTest03", - DetectEngineHttpHeaderTest03); - UtRegisterTest("DetectEngineHttpHeaderTest04", - DetectEngineHttpHeaderTest04); - UtRegisterTest("DetectEngineHttpHeaderTest05", - DetectEngineHttpHeaderTest05); - UtRegisterTest("DetectEngineHttpHeaderTest06", - DetectEngineHttpHeaderTest06); - UtRegisterTest("DetectEngineHttpHeaderTest07", - DetectEngineHttpHeaderTest07); - UtRegisterTest("DetectEngineHttpHeaderTest08", - DetectEngineHttpHeaderTest08); - UtRegisterTest("DetectEngineHttpHeaderTest09", - DetectEngineHttpHeaderTest09); - UtRegisterTest("DetectEngineHttpHeaderTest10", - DetectEngineHttpHeaderTest10); - UtRegisterTest("DetectEngineHttpHeaderTest11", - DetectEngineHttpHeaderTest11); - UtRegisterTest("DetectEngineHttpHeaderTest12", - DetectEngineHttpHeaderTest12); - UtRegisterTest("DetectEngineHttpHeaderTest13", - DetectEngineHttpHeaderTest13); - UtRegisterTest("DetectEngineHttpHeaderTest14", - DetectEngineHttpHeaderTest14); - UtRegisterTest("DetectEngineHttpHeaderTest15", - DetectEngineHttpHeaderTest15); - UtRegisterTest("DetectEngineHttpHeaderTest16", - DetectEngineHttpHeaderTest16); - UtRegisterTest("DetectEngineHttpHeaderTest17", - DetectEngineHttpHeaderTest17); - UtRegisterTest("DetectEngineHttpHeaderTest20", - DetectEngineHttpHeaderTest20); - UtRegisterTest("DetectEngineHttpHeaderTest21", - DetectEngineHttpHeaderTest21); - UtRegisterTest("DetectEngineHttpHeaderTest22", - DetectEngineHttpHeaderTest22); - UtRegisterTest("DetectEngineHttpHeaderTest23", - DetectEngineHttpHeaderTest23); - UtRegisterTest("DetectEngineHttpHeaderTest24", - DetectEngineHttpHeaderTest24); - UtRegisterTest("DetectEngineHttpHeaderTest25", - DetectEngineHttpHeaderTest25); - UtRegisterTest("DetectEngineHttpHeaderTest26", - DetectEngineHttpHeaderTest26); - UtRegisterTest("DetectEngineHttpHeaderTest27", - DetectEngineHttpHeaderTest27); - UtRegisterTest("DetectEngineHttpHeaderTest28", - DetectEngineHttpHeaderTest28); - UtRegisterTest("DetectEngineHttpHeaderTest29", - DetectEngineHttpHeaderTest29); - UtRegisterTest("DetectEngineHttpHeaderTest30", - DetectEngineHttpHeaderTest30); - UtRegisterTest("DetectEngineHttpHeaderTest31", - DetectEngineHttpHeaderTest31); -#if 0 - UtRegisterTest("DetectEngineHttpHeaderTest30", - DetectEngineHttpHeaderTest30, 1); -#endif - UtRegisterTest("DetectEngineHttpHeaderTest32", - DetectEngineHttpHeaderTest32); - UtRegisterTest("DetectEngineHttpHeaderTest33", - DetectEngineHttpHeaderTest33); #endif /* UNITTESTS */ diff --git a/src/detect-engine-hhd.h b/src/detect-engine-hhd.h index f8e06e12a701..86b9a85b786d 100644 --- a/src/detect-engine-hhd.h +++ b/src/detect-engine-hhd.h @@ -25,16 +25,4 @@ #include "app-layer-htp.h" -int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); -int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); - -int DetectEngineInspectHttpHeader(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatchData *smd, - Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); - -void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx); - -void DetectEngineHttpHeaderRegisterTests(void); - #endif /* __DETECT_ENGINE_HHD_H__ */ diff --git a/src/detect-http-header.c b/src/detect-http-header.c index b2696463e48c..a9f29d2a6608 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -39,6 +39,8 @@ #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" #include "detect-content.h" #include "detect-pcre.h" @@ -51,6 +53,7 @@ #include "util-unittest-helper.h" #include "util-spm.h" #include "util-print.h" +#include "util-memcmp.h" #include "app-layer.h" #include "app-layer-parser.h" @@ -62,62 +65,377 @@ static int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, char *); static void DetectHttpHeaderRegisterTests(void); -static void DetectHttpHeaderFree(void *); static void DetectHttpHeaderSetupCallback(Signature *); static int g_http_header_buffer_id = 0; -/** - * \brief Registers the keyword handlers for the "http_header" keyword. +#define BUFFER_STEP 50 + +static inline int HHDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) +{ + if (size >= (USHRT_MAX - BUFFER_STEP)) + return -1; + + void *ptmp; + if (size > det_ctx->hhd_buffers_size) { + ptmp = SCRealloc(det_ctx->hhd_buffers, + (det_ctx->hhd_buffers_size + BUFFER_STEP) * sizeof(uint8_t *)); + if (ptmp == NULL) { + SCFree(det_ctx->hhd_buffers); + det_ctx->hhd_buffers = NULL; + det_ctx->hhd_buffers_size = 0; + det_ctx->hhd_buffers_list_len = 0; + return -1; + } + det_ctx->hhd_buffers = ptmp; + + memset(det_ctx->hhd_buffers + det_ctx->hhd_buffers_size, 0, BUFFER_STEP * sizeof(uint8_t *)); + ptmp = SCRealloc(det_ctx->hhd_buffers_len, + (det_ctx->hhd_buffers_size + BUFFER_STEP) * sizeof(uint32_t)); + if (ptmp == NULL) { + SCFree(det_ctx->hhd_buffers_len); + det_ctx->hhd_buffers_len = NULL; + det_ctx->hhd_buffers_size = 0; + det_ctx->hhd_buffers_list_len = 0; + return -1; + } + det_ctx->hhd_buffers_len = ptmp; + + memset(det_ctx->hhd_buffers_len + det_ctx->hhd_buffers_size, 0, BUFFER_STEP * sizeof(uint32_t)); + det_ctx->hhd_buffers_size += BUFFER_STEP; + } + memset(det_ctx->hhd_buffers_len + det_ctx->hhd_buffers_list_len, 0, (size - det_ctx->hhd_buffers_list_len) * sizeof(uint32_t)); + + return 0; +} + +static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Flow *f, HtpState *htp_state, + uint8_t flags, + uint32_t *buffer_len) +{ + uint8_t *headers_buffer = NULL; + int index = 0; + *buffer_len = 0; + + if (det_ctx->hhd_buffers_list_len == 0) { + /* get the inspect id to use as a 'base id' */ + uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + BUG_ON(base_inspect_id > tx_id); + /* see how many space we need for the current tx_id */ + uint64_t txs = (tx_id - base_inspect_id) + 1; + if (HHDCreateSpace(det_ctx, txs) < 0) + goto end; + + index = (tx_id - base_inspect_id); + det_ctx->hhd_start_tx_id = base_inspect_id; + det_ctx->hhd_buffers_list_len = txs; + } else { + /* tx fits in our current buffers */ + if ((tx_id - det_ctx->hhd_start_tx_id) < det_ctx->hhd_buffers_list_len) { + /* if we previously reassembled, return that buffer */ + if (det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)] != 0) { + *buffer_len = det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)]; + return det_ctx->hhd_buffers[(tx_id - det_ctx->hhd_start_tx_id)]; + } + /* otherwise fall through */ + } else { + /* not enough space, lets expand */ + uint64_t txs = (tx_id - det_ctx->hhd_start_tx_id) + 1; + if (HHDCreateSpace(det_ctx, txs) < 0) + goto end; + + det_ctx->hhd_buffers_list_len = txs; + } + index = (tx_id - det_ctx->hhd_start_tx_id); + } + + htp_table_t *headers; + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_REQUEST_HEADERS) + goto end; + headers = tx->request_headers; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_RESPONSE_HEADERS) + goto end; + headers = tx->response_headers; + } + if (headers == NULL) + goto end; + + htp_header_t *h = NULL; + headers_buffer = det_ctx->hhd_buffers[index]; + size_t headers_buffer_len = 0; + size_t i = 0; + + size_t no_of_headers = htp_table_size(headers); + for (; i < no_of_headers; i++) { + h = htp_table_get_index(headers, i, NULL); + size_t size1 = bstr_size(h->name); + size_t size2 = bstr_size(h->value); + + if (flags & STREAM_TOSERVER) { + if (size1 == 6 && + SCMemcmpLowercase("cookie", bstr_ptr(h->name), 6) == 0) { + continue; + } + } else { + if (size1 == 10 && + SCMemcmpLowercase("set-cookie", bstr_ptr(h->name), 10) == 0) { + continue; + } + } + + /* the extra 4 bytes if for ": " and "\r\n" */ + uint8_t *new_headers_buffer = SCRealloc(headers_buffer, headers_buffer_len + size1 + size2 + 4); + if (unlikely(new_headers_buffer == NULL)) { + if (headers_buffer != NULL) { + SCFree(headers_buffer); + headers_buffer = NULL; + } + det_ctx->hhd_buffers[index] = NULL; + det_ctx->hhd_buffers_len[index] = 0; + goto end; + } + headers_buffer = new_headers_buffer; + + memcpy(headers_buffer + headers_buffer_len, bstr_ptr(h->name), size1); + headers_buffer_len += size1; + headers_buffer[headers_buffer_len] = ':'; + headers_buffer[headers_buffer_len + 1] = ' '; + headers_buffer_len += 2; + memcpy(headers_buffer + headers_buffer_len, bstr_ptr(h->value), size2); + headers_buffer_len += size2 + 2; + /* \r */ + headers_buffer[headers_buffer_len - 2] = '\r'; + /* \n */ + headers_buffer[headers_buffer_len - 1] = '\n'; + } + + /* store the buffers. We will need it for further inspection */ + det_ctx->hhd_buffers[index] = headers_buffer; + det_ctx->hhd_buffers_len[index] = headers_buffer_len; + + *buffer_len = (uint32_t)headers_buffer_len; + end: + return headers_buffer; +} + +/** \brief HTTP Headers Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -void DetectHttpHeaderRegister(void) +static void PrefilterTxHttpRequestHeaders(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - sigmatch_table[DETECT_AL_HTTP_HEADER].name = "http_header"; - sigmatch_table[DETECT_AL_HTTP_HEADER].desc = "content modifier to match only on the HTTP header-buffer"; - sigmatch_table[DETECT_AL_HTTP_HEADER].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-header"; - sigmatch_table[DETECT_AL_HTTP_HEADER].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_HEADER].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_HEADER].Setup = DetectHttpHeaderSetup; - sigmatch_table[DETECT_AL_HTTP_HEADER].Free = DetectHttpHeaderFree; - sigmatch_table[DETECT_AL_HTTP_HEADER].RegisterTests = DetectHttpHeaderRegisterTests; + SCEnter(); - sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_PAYLOAD ; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - DetectAppLayerMpmRegister("http_header", SIG_FLAG_TOSERVER, 2, - PrefilterTxHttpRequestHeadersRegister); - DetectAppLayerMpmRegister("http_header", SIG_FLAG_TOCLIENT, 2, - PrefilterTxHttpResponseHeadersRegister); + if (tx->request_headers == NULL) + return; - DetectAppLayerInspectEngineRegister("http_header", - ALPROTO_HTTP, SIG_FLAG_TOSERVER, - DetectEngineInspectHttpHeader); - DetectAppLayerInspectEngineRegister("http_header", - ALPROTO_HTTP, SIG_FLAG_TOCLIENT, - DetectEngineInspectHttpHeader); + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#if 0 +static void PrefilterTxHttpRequestTrailers(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); - DetectBufferTypeSetDescriptionByName("http_header", - "http headers"); + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - DetectBufferTypeRegisterSetupCallback("http_header", - DetectHttpHeaderSetupCallback); + if (tx->request_headers == NULL) + return; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && !htud->request_has_trailers) + return; - g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#endif +static int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaders, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL, "http_header (request)"); + return r; +#if 0 + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestTrailers, + ALPROTO_HTTP, HTP_REQUEST_TRAILER, + mpm_ctx, NULL, "http_header (request)"); +#endif } -/** - * \brief this function clears the memory of http_header modifier keyword +/** \brief HTTP Headers Mpm prefilter callback * - * \param ptr Pointer to the Detection Header Data + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -void DetectHttpHeaderFree(void *ptr) +static void PrefilterTxHttpResponseHeaders(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - DetectContentData *hhd = (DetectContentData *)ptr; - if (hhd == NULL) + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#if 0 +static void PrefilterTxHttpResponseTrailers(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && !htud->response_has_trailers) return; - if (hhd->content != NULL) - SCFree(hhd->content); - SCFree(hhd); + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#endif +static int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaders, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS, + mpm_ctx, NULL, "http_header (response)"); + return r; +#if 0 + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseTrailers, + ALPROTO_HTTP, HTP_RESPONSE_TRAILER, + mpm_ctx, NULL, "http_header (response)"); +#endif +} + +static int DetectEngineInspectHttpHeader(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + HtpState *htp_state = (HtpState *)alstate; + uint32_t buffer_len = 0; + uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, tx_id, + de_ctx, det_ctx, + f, htp_state, + flags, + &buffer_len); + if (buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, + buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx->hhd_buffers_list_len != 0) { + int i; + for (i = 0; i < det_ctx->hhd_buffers_list_len; i++) { + det_ctx->hhd_buffers_len[i] = 0; + } + det_ctx->hhd_buffers_list_len = 0; + } + det_ctx->hhd_start_tx_id = 0; return; } @@ -135,7 +453,7 @@ void DetectHttpHeaderFree(void *ptr) * \retval 0 On success. * \retval -1 On failure. */ -int DetectHttpHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +static int DetectHttpHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_HEADER, @@ -149,6 +467,41 @@ static void DetectHttpHeaderSetupCallback(Signature *s) s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; } +/** + * \brief Registers the keyword handlers for the "http_header" keyword. + */ +void DetectHttpHeaderRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_HEADER].name = "http_header"; + sigmatch_table[DETECT_AL_HTTP_HEADER].desc = "content modifier to match only on the HTTP header-buffer"; + sigmatch_table[DETECT_AL_HTTP_HEADER].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-header"; + sigmatch_table[DETECT_AL_HTTP_HEADER].Setup = DetectHttpHeaderSetup; + sigmatch_table[DETECT_AL_HTTP_HEADER].RegisterTests = DetectHttpHeaderRegisterTests; + + sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ; + sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_PAYLOAD ; + + DetectAppLayerMpmRegister("http_header", SIG_FLAG_TOSERVER, 2, + PrefilterTxHttpRequestHeadersRegister); + DetectAppLayerMpmRegister("http_header", SIG_FLAG_TOCLIENT, 2, + PrefilterTxHttpResponseHeadersRegister); + + DetectAppLayerInspectEngineRegister("http_header", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpHeader); + DetectAppLayerInspectEngineRegister("http_header", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DetectEngineInspectHttpHeader); + + DetectBufferTypeSetDescriptionByName("http_header", + "http headers"); + + DetectBufferTypeRegisterSetupCallback("http_header", + DetectHttpHeaderSetupCallback); + + g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); +} + /************************************Unittests*********************************/ #ifdef UNITTESTS @@ -1851,6 +2204,3422 @@ static int DetectHttpHeaderIsdataatParseTest(void) PASS; } +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest01(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest02(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; depth:15; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest03(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; depth:5; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest04(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; depth:5; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest05(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; depth:15; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest06(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; offset:10; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest07(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; offset:15; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest08(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; offset:15; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest09(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; offset:10; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest10(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"three\"; http_header; within:10; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest11(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"three\"; http_header; within:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest12(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"three\"; http_header; within:10; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest13(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"three\"; http_header; within:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest14(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"five\"; http_header; distance:7; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest15(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"five\"; http_header; distance:15; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest16(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"five\"; http_header; distance:7; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest17(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"five\"; http_header; distance:15; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +static int DetectEngineHttpHeaderTest20(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; http_header; within:7; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest21(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; within:7; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest22(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; distance:3; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest23(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; distance:13; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest24(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; within:15; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest25(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; within:10; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest26(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; distance:8; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest27(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; distance:14; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest28(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Content-Length: 6\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + FAIL_IF(!PacketAlertCheck(p2, 1)); + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest29(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Content-Length: 7\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +#if 0 + +static int DetectEngineHttpHeaderTest30(void) +{ + int result = 0; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Content-Length: 6\"; http_header; " + "content:\"User-Agent: Mozilla\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list != NULL) { + goto end; + } + + result = 1; + + end: + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +#endif /* #if 0 */ + +static int DetectEngineHttpHeaderTest30(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Set-Cookie: dummycookieset\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"dummycookieset\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +/** \test reassembly bug where headers with names of length 6 were + * skipped + */ +static int DetectEngineHttpHeaderTest31(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Accept: blah\r\n" + "Cookie: blah\r\n" + "Crazy6: blah\r\n" + "SixZix: blah\r\n\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(content:\"Accept|3a|\"; http_header; " + "content:!\"Cookie|3a|\"; http_header; " + "content:\"Crazy6|3a|\"; http_header; " + "content:\"SixZix|3a|\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (!(PacketAlertCheck(p1, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + return result; +} + +/** + * \test Trailing headers. + */ +static int DetectEngineHttpHeaderTest32(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "host: boom\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "13\r\n" + "This is dummy body1\r\n" + "0\r\n" + "Dummy-Header: kaboom\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(content:\"Dummy\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (!(PacketAlertCheck(p1, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + return result; +} + +/** + * \test Trailing headers. + */ +static int DetectEngineHttpHeaderTest33(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "host: boom\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "13\r\n" + "This is dummy body1\r\n" + "0\r\n"; + uint8_t http2_buf[] = + "Dummy-Header: kaboom\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(content:\"Dummy\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have\n"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + #endif /* UNITTESTS */ void DetectHttpHeaderRegisterTests(void) @@ -1884,6 +5653,72 @@ void DetectHttpHeaderRegisterTests(void) UtRegisterTest("DetectHttpHeaderIsdataatParseTest", DetectHttpHeaderIsdataatParseTest); + UtRegisterTest("DetectEngineHttpHeaderTest01", + DetectEngineHttpHeaderTest01); + UtRegisterTest("DetectEngineHttpHeaderTest02", + DetectEngineHttpHeaderTest02); + UtRegisterTest("DetectEngineHttpHeaderTest03", + DetectEngineHttpHeaderTest03); + UtRegisterTest("DetectEngineHttpHeaderTest04", + DetectEngineHttpHeaderTest04); + UtRegisterTest("DetectEngineHttpHeaderTest05", + DetectEngineHttpHeaderTest05); + UtRegisterTest("DetectEngineHttpHeaderTest06", + DetectEngineHttpHeaderTest06); + UtRegisterTest("DetectEngineHttpHeaderTest07", + DetectEngineHttpHeaderTest07); + UtRegisterTest("DetectEngineHttpHeaderTest08", + DetectEngineHttpHeaderTest08); + UtRegisterTest("DetectEngineHttpHeaderTest09", + DetectEngineHttpHeaderTest09); + UtRegisterTest("DetectEngineHttpHeaderTest10", + DetectEngineHttpHeaderTest10); + UtRegisterTest("DetectEngineHttpHeaderTest11", + DetectEngineHttpHeaderTest11); + UtRegisterTest("DetectEngineHttpHeaderTest12", + DetectEngineHttpHeaderTest12); + UtRegisterTest("DetectEngineHttpHeaderTest13", + DetectEngineHttpHeaderTest13); + UtRegisterTest("DetectEngineHttpHeaderTest14", + DetectEngineHttpHeaderTest14); + UtRegisterTest("DetectEngineHttpHeaderTest15", + DetectEngineHttpHeaderTest15); + UtRegisterTest("DetectEngineHttpHeaderTest16", + DetectEngineHttpHeaderTest16); + UtRegisterTest("DetectEngineHttpHeaderTest17", + DetectEngineHttpHeaderTest17); + UtRegisterTest("DetectEngineHttpHeaderTest20", + DetectEngineHttpHeaderTest20); + UtRegisterTest("DetectEngineHttpHeaderTest21", + DetectEngineHttpHeaderTest21); + UtRegisterTest("DetectEngineHttpHeaderTest22", + DetectEngineHttpHeaderTest22); + UtRegisterTest("DetectEngineHttpHeaderTest23", + DetectEngineHttpHeaderTest23); + UtRegisterTest("DetectEngineHttpHeaderTest24", + DetectEngineHttpHeaderTest24); + UtRegisterTest("DetectEngineHttpHeaderTest25", + DetectEngineHttpHeaderTest25); + UtRegisterTest("DetectEngineHttpHeaderTest26", + DetectEngineHttpHeaderTest26); + UtRegisterTest("DetectEngineHttpHeaderTest27", + DetectEngineHttpHeaderTest27); + UtRegisterTest("DetectEngineHttpHeaderTest28", + DetectEngineHttpHeaderTest28); + UtRegisterTest("DetectEngineHttpHeaderTest29", + DetectEngineHttpHeaderTest29); + UtRegisterTest("DetectEngineHttpHeaderTest30", + DetectEngineHttpHeaderTest30); + UtRegisterTest("DetectEngineHttpHeaderTest31", + DetectEngineHttpHeaderTest31); +#if 0 + UtRegisterTest("DetectEngineHttpHeaderTest30", + DetectEngineHttpHeaderTest30, 1); +#endif + UtRegisterTest("DetectEngineHttpHeaderTest32", + DetectEngineHttpHeaderTest32); + UtRegisterTest("DetectEngineHttpHeaderTest33", + DetectEngineHttpHeaderTest33); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-header.h b/src/detect-http-header.h index 5327b5b81583..6a26f55a0ff1 100644 --- a/src/detect-http-header.h +++ b/src/detect-http-header.h @@ -27,4 +27,6 @@ void DetectHttpHeaderRegister(void); void DetectHttpRawHeaderRegister(void); +void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx); + #endif /* __DETECT_HTTP_HEADER_H__ */ diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index b24c078fc470..17bdc4e97535 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -195,7 +195,6 @@ static void RegisterUnittests(void) MemcmpRegisterTests(); DetectEngineHttpClientBodyRegisterTests(); DetectEngineHttpServerBodyRegisterTests(); - DetectEngineHttpHeaderRegisterTests(); DetectEngineHttpRawHeaderRegisterTests(); DetectEngineHttpMethodRegisterTests(); DetectEngineHttpCookieRegisterTests(); From 5ee68ca2b2e293c4711a5bcf6d6d278a09722796 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Dec 2016 14:43:59 +0100 Subject: [PATCH 2399/2553] http_header: remove old files --- src/Makefile.am | 1 - src/detect-engine-file.c | 1 - src/detect-engine-hhd.c | 81 ---------------------------------------- src/detect-engine-hhd.h | 28 -------------- src/detect-engine-mpm.c | 1 - src/detect-http-header.c | 1 - src/detect.c | 1 - src/runmode-unittests.c | 1 - 8 files changed, 115 deletions(-) delete mode 100644 src/detect-engine-hhd.c delete mode 100644 src/detect-engine-hhd.h diff --git a/src/Makefile.am b/src/Makefile.am index 4617dfbf647e..298eec7c43d0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -115,7 +115,6 @@ detect-engine-file.c detect-engine-file.h \ detect-engine-filedata-smtp.c detect-engine-filedata-smtp.h \ detect-engine-hcbd.c detect-engine-hcbd.h \ detect-engine-hcd.c detect-engine-hcd.h \ -detect-engine-hhd.c detect-engine-hhd.h \ detect-engine-hhhd.c detect-engine-hhhd.h \ detect-engine-hmd.c detect-engine-hmd.h \ detect-engine-hrhd.c detect-engine-hrhd.h \ diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index 7db290d3e502..9464799b4c05 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -34,7 +34,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hcbd.h" -#include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c deleted file mode 100644 index aab3c56205b0..000000000000 --- a/src/detect-engine-hhd.c +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (C) 2007-2010 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. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** \file - * - * \author Anoop Saldanha - * - * \brief Handle HTTP header match - * - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "decode.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-engine-hhd.h" -#include "detect-engine-mpm.h" -#include "detect-parse.h" -#include "detect-engine-state.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-prefilter.h" - -#include "flow-util.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-memcmp.h" -#include "flow.h" - -#include "stream-tcp.h" - -#include "app-layer-parser.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "app-layer.h" -#include "app-layer-htp.h" -#include "app-layer-protos.h" - -#include "util-validate.h" - -/***********************************Unittests**********************************/ - -#ifdef UNITTESTS - -#endif /* UNITTESTS */ - -void DetectEngineHttpHeaderRegisterTests(void) -{ - -#ifdef UNITTESTS - -#endif /* UNITTESTS */ - - return; -} -/** - * @} - */ diff --git a/src/detect-engine-hhd.h b/src/detect-engine-hhd.h deleted file mode 100644 index 86b9a85b786d..000000000000 --- a/src/detect-engine-hhd.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Anoop Saldanha - */ - -#ifndef __DETECT_ENGINE_HHD_H__ -#define __DETECT_ENGINE_HHD_H__ - -#include "app-layer-htp.h" - -#endif /* __DETECT_ENGINE_HHD_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 069ea6306d9f..40ec280f8e79 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -52,7 +52,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hrud.h" #include "detect-engine-hmd.h" -#include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hcd.h" #include "detect-engine-hua.h" diff --git a/src/detect-http-header.c b/src/detect-http-header.c index a9f29d2a6608..fa65b9c062bb 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -60,7 +60,6 @@ #include "app-layer-htp.h" #include "detect-http-header.h" -#include "detect-engine-hhd.h" #include "stream-tcp.h" static int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, char *); diff --git a/src/detect.c b/src/detect.c index 19d2d9a49150..37576ddc36dc 100644 --- a/src/detect.c +++ b/src/detect.c @@ -147,7 +147,6 @@ #include "detect-http-response-line.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" -#include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 17bdc4e97535..6d1632dc4e75 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -38,7 +38,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" -#include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" From 6279ec399e132c9e0389213fd97b7a7394ec137c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Dec 2016 15:45:12 +0100 Subject: [PATCH 2400/2553] http_header: common detection code --- src/Makefile.am | 1 + src/detect-http-header-common.c | 206 ++++++++++++++++++++++++++++++++ src/detect-http-header-common.h | 58 +++++++++ src/detect-http-header-names.c | 162 ++----------------------- 4 files changed, 272 insertions(+), 155 deletions(-) create mode 100644 src/detect-http-header-common.c create mode 100644 src/detect-http-header-common.h diff --git a/src/Makefile.am b/src/Makefile.am index 298eec7c43d0..c3e9a196fc3e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -164,6 +164,7 @@ detect-hostbits.c detect-hostbits.h \ detect-http-client-body.c detect-http-client-body.h \ detect-http-cookie.c detect-http-cookie.h \ detect-http-header.c detect-http-header.h \ +detect-http-header-common.c detect-http-header-common.h \ detect-http-header-names.c detect-http-header-names.h \ detect-http-hh.c detect-http-hh.h \ detect-http-hrh.c detect-http-hrh.h \ diff --git a/src/detect-http-header-common.c b/src/detect-http-header-common.c new file mode 100644 index 000000000000..1ab9b73595f3 --- /dev/null +++ b/src/detect-http-header-common.c @@ -0,0 +1,206 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" +#include "util-print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "detect-http-header.h" +#include "stream-tcp.h" + +#include "util-print.h" + +#include "detect-http-header-common.h" + +static inline int CreateSpace(HttpHeaderThreadData *td, uint64_t size); + +void *HttpHeaderThreadDataInit(void *data) +{ + HttpHeaderThreadData *td = SCCalloc(1, sizeof(*td)); + if (td != NULL) { + if (data == NULL) { + td->tx_step = 4; + td->size_step = 512; + } else { + HttpHeaderThreadDataConfig *c = data; + td->tx_step = c->tx_step; + td->size_step = c->size_step; + } + + /* initialize minimal buffers */ + (void)CreateSpace(td, 1); + int i; + for (i = 0; i < td->buffers_size; i++) { + (void)HttpHeaderExpandBuffer(td, &td->buffers[i], 1); + } + } + return td; +} + +void HttpHeaderThreadDataFree(void *data) +{ + HttpHeaderThreadData *hdrnames = data; + + int i; + for (i = 0; i < hdrnames->buffers_size; i++) { + if (hdrnames->buffers[i].buffer) + SCFree(hdrnames->buffers[i].buffer); + if (hdrnames->buffers[i].size) { + SCLogDebug("hdrnames->buffers[%d].size %u (%u)", + i, hdrnames->buffers[i].size, hdrnames->buffers_size); + } + } + SCFree(hdrnames->buffers); + SCFree(hdrnames); +} + +static void Reset(HttpHeaderThreadData *hdrnames, uint64_t tick) +{ + uint16_t i; + for (i = 0; i < hdrnames->buffers_list_len; i++) { + hdrnames->buffers[i].len = 0; + } + hdrnames->buffers_list_len = 0; + hdrnames->start_tx_id = 0; + hdrnames->tick = tick; +} + +static inline int CreateSpace(HttpHeaderThreadData *td, uint64_t size) +{ + if (size >= SHRT_MAX) + return -1; + + if (size > td->buffers_size) { + uint16_t extra = td->tx_step; + while (td->buffers_size + extra < size) { + extra += td->tx_step; + } + SCLogDebug("adding %u to the buffer", (uint)extra); + + void *ptmp = SCRealloc(td->buffers, + (td->buffers_size + extra) * sizeof(HttpHeaderBuffer)); + if (ptmp == NULL) { + SCFree(td->buffers); + td->buffers = NULL; + td->buffers_size = 0; + td->buffers_list_len = 0; + return -1; + } + td->buffers = ptmp; + memset(td->buffers + td->buffers_size, 0, extra * sizeof(HttpHeaderBuffer)); + td->buffers_size += extra; + } + return 0; +} + +int HttpHeaderExpandBuffer(HttpHeaderThreadData *td, + HttpHeaderBuffer *buf, uint32_t size) +{ + size_t extra = td->size_step; + while ((buf->size + extra) < (size + buf->len)) { + extra += td->size_step; + } + SCLogDebug("adding %u to the buffer", (uint)extra); + + uint8_t *new_buffer = SCRealloc(buf->buffer, buf->size + extra); + if (unlikely(new_buffer == NULL)) { + buf->len = 0; + return -1; + } + buf->buffer = new_buffer; + buf->size += extra; + return 0; +} + +HttpHeaderBuffer *HttpHeaderGetBufferSpaceForTXID(DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, uint64_t tx_id, const int keyword_id, + HttpHeaderThreadData **ret_hdr_td) +{ + int index = 0; + *ret_hdr_td = NULL; + + HttpHeaderThreadData *hdr_td = + DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, keyword_id); + if (hdr_td == NULL) + return NULL; + if (hdr_td->tick != det_ctx->ticker) + Reset(hdr_td, det_ctx->ticker); + *ret_hdr_td = hdr_td; + + if (hdr_td->buffers_list_len == 0) { + /* get the inspect id to use as a 'base id' */ + uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + BUG_ON(base_inspect_id > tx_id); + /* see how many space we need for the current tx_id */ + uint64_t txs = (tx_id - base_inspect_id) + 1; + if (CreateSpace(hdr_td, txs) < 0) + return NULL; + + index = (tx_id - base_inspect_id); + hdr_td->start_tx_id = base_inspect_id; + hdr_td->buffers_list_len = txs; + } else { + /* tx fits in our current buffers */ + if ((tx_id - hdr_td->start_tx_id) < hdr_td->buffers_list_len) { + /* if we previously reassembled, return that buffer */ + if (hdr_td->buffers[(tx_id - hdr_td->start_tx_id)].len != 0) { + return &hdr_td->buffers[(tx_id - hdr_td->start_tx_id)]; + } + /* otherwise fall through */ + } else { + /* not enough space, lets expand */ + uint64_t txs = (tx_id - hdr_td->start_tx_id) + 1; + if (CreateSpace(hdr_td, txs) < 0) + return NULL; + + hdr_td->buffers_list_len = txs; + } + index = (tx_id - hdr_td->start_tx_id); + } + HttpHeaderBuffer *buf = &hdr_td->buffers[index]; + return buf; +} diff --git a/src/detect-http-header-common.h b/src/detect-http-header-common.h new file mode 100644 index 000000000000..c6fc5c684b89 --- /dev/null +++ b/src/detect-http-header-common.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_HTTP_HEADER_COMMON_H__ +#define __DETECT_HTTP_HEADER_COMMON_H__ + +typedef struct HttpHeaderBuffer_ { + uint8_t *buffer; + uint32_t size; /**< buffer size */ + uint32_t len; /**< part of buffer in use */ +} HttpHeaderBuffer; + +typedef struct HttpHeaderThreadConfig_ { + uint16_t tx_step; + uint16_t size_step; +} HttpHeaderThreadDataConfig; + +typedef struct HttpHeaderThreadData_ { + HttpHeaderBuffer *buffers; /**< array of buffers */ + uint16_t buffers_size; /**< number of buffers */ + uint16_t buffers_list_len; + uint16_t size_step; /**< increase size of HttpHeaderBuffer::buffer with this */ + uint16_t tx_step; /**< increase number of txs with this */ + uint64_t start_tx_id; + uint64_t tick; +} HttpHeaderThreadData; + +void *HttpHeaderThreadDataInit(void *data); +void HttpHeaderThreadDataFree(void *data); + +HttpHeaderBuffer *HttpHeaderGetBufferSpaceForTXID(DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, uint64_t tx_id, const int keyword_id, + HttpHeaderThreadData **ret_hdr_td); + +int HttpHeaderExpandBuffer(HttpHeaderThreadData *td, + HttpHeaderBuffer *buf, uint32_t size); + +#endif /* __DETECT_HTTP_HEADER_COMMON_H__ */ diff --git a/src/detect-http-header-names.c b/src/detect-http-header-names.c index df7165f270a5..bdb204d2e15e 100644 --- a/src/detect-http-header-names.c +++ b/src/detect-http-header-names.c @@ -43,6 +43,7 @@ #include "detect-engine-content-inspection.h" #include "detect-content.h" #include "detect-pcre.h" +#include "detect-http-header-common.h" #include "flow.h" #include "flow-var.h" @@ -72,158 +73,7 @@ static int g_keyword_thread_id = 0; #define BUFFER_TX_STEP 4 #define BUFFER_SIZE_STEP 256 - -typedef struct Buffer_ { - uint8_t *buffer; - uint32_t size; /**< buffer size */ - uint32_t len; /**< part of buffer in use */ -} Buffer; - -typedef struct HttpHeaderNamesThreadData_ { - Buffer *buffers; /**< array of buffers */ - uint16_t buffers_size; /**< number of buffers */ - uint16_t buffers_list_len; - uint64_t start_tx_id; - uint64_t tick; -} HttpHeaderNamesThreadData; - -static inline int CreateSpace(HttpHeaderNamesThreadData *hn, uint64_t size); -static inline int ExpandBuffer(Buffer *buf, uint32_t size); - -static void *HttpHeaderNamesThreadDataInit(void *data) -{ - HttpHeaderNamesThreadData *d = SCCalloc(1, sizeof(*d)); - if (d != NULL) { - /* initialize minimal buffers */ - (void)CreateSpace(d, 1); - int i; - for (i = 0; i < d->buffers_size; i++) { - (void)ExpandBuffer(&d->buffers[i], 1); - } - } - return d; -} - -static void HttpHeaderNamesThreadDataFree(void *data) -{ - HttpHeaderNamesThreadData *hdrnames = data; - - int i; - for (i = 0; i < hdrnames->buffers_size; i++) { - if (hdrnames->buffers[i].buffer) - SCFree(hdrnames->buffers[i].buffer); - if (hdrnames->buffers[i].size) { - SCLogDebug("hdrnames->buffers[%d].size %u (%u)", - i, hdrnames->buffers[i].size, hdrnames->buffers_size); - } - } - SCFree(hdrnames->buffers); - SCFree(hdrnames); -} - -static void Reset(HttpHeaderNamesThreadData *hdrnames, uint64_t tick) -{ - uint16_t i; - for (i = 0; i < hdrnames->buffers_list_len; i++) { - hdrnames->buffers[i].len = 0; - } - hdrnames->buffers_list_len = 0; - hdrnames->start_tx_id = 0; - hdrnames->tick = tick; -} - -static inline int CreateSpace(HttpHeaderNamesThreadData *hn, uint64_t size) -{ - if (size >= SHRT_MAX) - return -1; - - if (size > hn->buffers_size) { - uint16_t extra = BUFFER_TX_STEP; - while (hn->buffers_size + extra < size) { - extra += BUFFER_TX_STEP; - } - SCLogDebug("adding %u to the buffer", (uint)extra); - - void *ptmp = SCRealloc(hn->buffers, - (hn->buffers_size + extra) * sizeof(Buffer)); - if (ptmp == NULL) { - SCFree(hn->buffers); - hn->buffers = NULL; - hn->buffers_size = 0; - hn->buffers_list_len = 0; - return -1; - } - hn->buffers = ptmp; - memset(hn->buffers + hn->buffers_size, 0, extra * sizeof(Buffer)); - hn->buffers_size += extra; - } - - return 0; -} - -static inline int ExpandBuffer(Buffer *buf, uint32_t size) -{ - size_t extra = BUFFER_SIZE_STEP; - while ((buf->size + extra) < (size + buf->len)) { - extra += BUFFER_SIZE_STEP; - } - SCLogDebug("adding %u to the buffer", (uint)extra); - - uint8_t *new_buffer = SCRealloc(buf->buffer, buf->size + extra); - if (unlikely(new_buffer == NULL)) { - buf->len = 0; - return -1; - } - buf->buffer = new_buffer; - buf->size += extra; - return 0; -} - -static Buffer *GetBufferSpaceForTXID(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, uint64_t tx_id) -{ - int index = 0; - - HttpHeaderNamesThreadData *hdrnames = - DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, g_keyword_thread_id); - if (hdrnames == NULL) - return NULL; - if (hdrnames->tick != det_ctx->ticker) - Reset(hdrnames, det_ctx->ticker); - - if (hdrnames->buffers_list_len == 0) { - /* get the inspect id to use as a 'base id' */ - uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); - BUG_ON(base_inspect_id > tx_id); - /* see how many space we need for the current tx_id */ - uint64_t txs = (tx_id - base_inspect_id) + 1; - if (CreateSpace(hdrnames, txs) < 0) - return NULL; - - index = (tx_id - base_inspect_id); - hdrnames->start_tx_id = base_inspect_id; - hdrnames->buffers_list_len = txs; - } else { - /* tx fits in our current buffers */ - if ((tx_id - hdrnames->start_tx_id) < hdrnames->buffers_list_len) { - /* if we previously reassembled, return that buffer */ - if (hdrnames->buffers[(tx_id - hdrnames->start_tx_id)].len != 0) { - return &hdrnames->buffers[(tx_id - hdrnames->start_tx_id)]; - } - /* otherwise fall through */ - } else { - /* not enough space, lets expand */ - uint64_t txs = (tx_id - hdrnames->start_tx_id) + 1; - if (CreateSpace(hdrnames, txs) < 0) - return NULL; - - hdrnames->buffers_list_len = txs; - } - index = (tx_id - hdrnames->start_tx_id); - } - Buffer *buf = &hdrnames->buffers[index]; - return buf; -} +static HttpHeaderThreadDataConfig g_td_config = { BUFFER_TX_STEP, BUFFER_SIZE_STEP }; static uint8_t *GetBufferForTX(htp_tx_t *tx, uint64_t tx_id, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -232,7 +82,9 @@ static uint8_t *GetBufferForTX(htp_tx_t *tx, uint64_t tx_id, { *buffer_len = 0; - Buffer *buf = GetBufferSpaceForTXID(det_ctx, f, flags, tx_id); + HttpHeaderThreadData *hdr_td = NULL; + HttpHeaderBuffer *buf = HttpHeaderGetBufferSpaceForTXID(det_ctx, f, flags, + tx_id, g_keyword_thread_id, &hdr_td); if (unlikely(buf == NULL)) { return NULL; } else if (buf->len > 0) { @@ -269,7 +121,7 @@ static uint8_t *GetBufferForTX(htp_tx_t *tx, uint64_t tx_id, SCLogDebug("size %u + buf->len %u vs buf->size %u", (uint)size, buf->len, buf->size); if (size + buf->len > buf->size) { - if (ExpandBuffer(buf, size) != 0) { + if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { return NULL; } } @@ -551,7 +403,7 @@ void DetectHttpHeaderNamesRegister(void) g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs(KEYWORD_NAME, - HttpHeaderNamesThreadDataInit, HttpHeaderNamesThreadDataFree); + HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); SCLogDebug("keyword %s registered. Thread id %d. " "Buffer %s registered. Buffer id %d", From f2fc5a255f09c5287e9a6baf4cbeadab6f35a82b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Dec 2016 17:06:11 +0100 Subject: [PATCH 2401/2553] http_header: convert to use common code --- src/detect-engine.c | 14 --- src/detect-http-header.c | 200 ++++++++++++--------------------------- src/detect.c | 1 - src/detect.h | 6 -- 4 files changed, 59 insertions(+), 162 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index d6a412f21ee0..24da42090605 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1807,8 +1807,6 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) { - int i; - if (det_ctx->tenant_array != NULL) { SCFree(det_ctx->tenant_array); det_ctx->tenant_array = NULL; @@ -1846,18 +1844,6 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) if (det_ctx->bj_values != NULL) SCFree(det_ctx->bj_values); - /* HHD temp storage */ - for (i = 0; i < det_ctx->hhd_buffers_size; i++) { - if (det_ctx->hhd_buffers[i] != NULL) - SCFree(det_ctx->hhd_buffers[i]); - } - if (det_ctx->hhd_buffers) - SCFree(det_ctx->hhd_buffers); - det_ctx->hhd_buffers = NULL; - if (det_ctx->hhd_buffers_len) - SCFree(det_ctx->hhd_buffers_len); - det_ctx->hhd_buffers_len = NULL; - /* HSBD */ if (det_ctx->hsbd != NULL) { SCLogDebug("det_ctx hsbd %u", det_ctx->hsbd_buffers_size); diff --git a/src/detect-http-header.c b/src/detect-http-header.c index fa65b9c062bb..5d2e1ec59d21 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -60,117 +60,54 @@ #include "app-layer-htp.h" #include "detect-http-header.h" +#include "detect-http-header-common.h" #include "stream-tcp.h" static int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, char *); static void DetectHttpHeaderRegisterTests(void); static void DetectHttpHeaderSetupCallback(Signature *); static int g_http_header_buffer_id = 0; +static int g_keyword_thread_id = 0; -#define BUFFER_STEP 50 +#define BUFFER_TX_STEP 4 +#define BUFFER_SIZE_STEP 1024 +static HttpHeaderThreadDataConfig g_td_config = { BUFFER_TX_STEP, BUFFER_SIZE_STEP }; -static inline int HHDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) -{ - if (size >= (USHRT_MAX - BUFFER_STEP)) - return -1; - - void *ptmp; - if (size > det_ctx->hhd_buffers_size) { - ptmp = SCRealloc(det_ctx->hhd_buffers, - (det_ctx->hhd_buffers_size + BUFFER_STEP) * sizeof(uint8_t *)); - if (ptmp == NULL) { - SCFree(det_ctx->hhd_buffers); - det_ctx->hhd_buffers = NULL; - det_ctx->hhd_buffers_size = 0; - det_ctx->hhd_buffers_list_len = 0; - return -1; - } - det_ctx->hhd_buffers = ptmp; - - memset(det_ctx->hhd_buffers + det_ctx->hhd_buffers_size, 0, BUFFER_STEP * sizeof(uint8_t *)); - ptmp = SCRealloc(det_ctx->hhd_buffers_len, - (det_ctx->hhd_buffers_size + BUFFER_STEP) * sizeof(uint32_t)); - if (ptmp == NULL) { - SCFree(det_ctx->hhd_buffers_len); - det_ctx->hhd_buffers_len = NULL; - det_ctx->hhd_buffers_size = 0; - det_ctx->hhd_buffers_list_len = 0; - return -1; - } - det_ctx->hhd_buffers_len = ptmp; - - memset(det_ctx->hhd_buffers_len + det_ctx->hhd_buffers_size, 0, BUFFER_STEP * sizeof(uint32_t)); - det_ctx->hhd_buffers_size += BUFFER_STEP; - } - memset(det_ctx->hhd_buffers_len + det_ctx->hhd_buffers_list_len, 0, (size - det_ctx->hhd_buffers_list_len) * sizeof(uint32_t)); - - return 0; -} - -static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Flow *f, HtpState *htp_state, - uint8_t flags, - uint32_t *buffer_len) +static uint8_t *GetBufferForTX(htp_tx_t *tx, uint64_t tx_id, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Flow *f, HtpState *htp_state, uint8_t flags, + uint32_t *buffer_len) { - uint8_t *headers_buffer = NULL; - int index = 0; *buffer_len = 0; - if (det_ctx->hhd_buffers_list_len == 0) { - /* get the inspect id to use as a 'base id' */ - uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); - BUG_ON(base_inspect_id > tx_id); - /* see how many space we need for the current tx_id */ - uint64_t txs = (tx_id - base_inspect_id) + 1; - if (HHDCreateSpace(det_ctx, txs) < 0) - goto end; - - index = (tx_id - base_inspect_id); - det_ctx->hhd_start_tx_id = base_inspect_id; - det_ctx->hhd_buffers_list_len = txs; - } else { - /* tx fits in our current buffers */ - if ((tx_id - det_ctx->hhd_start_tx_id) < det_ctx->hhd_buffers_list_len) { - /* if we previously reassembled, return that buffer */ - if (det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)] != 0) { - *buffer_len = det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)]; - return det_ctx->hhd_buffers[(tx_id - det_ctx->hhd_start_tx_id)]; - } - /* otherwise fall through */ - } else { - /* not enough space, lets expand */ - uint64_t txs = (tx_id - det_ctx->hhd_start_tx_id) + 1; - if (HHDCreateSpace(det_ctx, txs) < 0) - goto end; - - det_ctx->hhd_buffers_list_len = txs; - } - index = (tx_id - det_ctx->hhd_start_tx_id); + HttpHeaderThreadData *hdr_td = NULL; + HttpHeaderBuffer *buf = HttpHeaderGetBufferSpaceForTXID(det_ctx, f, flags, + tx_id, g_keyword_thread_id, &hdr_td); + if (unlikely(buf == NULL)) { + return NULL; + } else if (buf->len > 0) { + /* already filled buf, reuse */ + *buffer_len = buf->len; + return buf->buffer; } htp_table_t *headers; if (flags & STREAM_TOSERVER) { if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_REQUEST_HEADERS) - goto end; + return NULL; headers = tx->request_headers; } else { if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_RESPONSE_HEADERS) - goto end; + return NULL; headers = tx->response_headers; } if (headers == NULL) - goto end; + return NULL; - htp_header_t *h = NULL; - headers_buffer = det_ctx->hhd_buffers[index]; - size_t headers_buffer_len = 0; size_t i = 0; - size_t no_of_headers = htp_table_size(headers); for (; i < no_of_headers; i++) { - h = htp_table_get_index(headers, i, NULL); + htp_header_t *h = htp_table_get_index(headers, i, NULL); size_t size1 = bstr_size(h->name); size_t size2 = bstr_size(h->value); @@ -186,39 +123,35 @@ static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, } } - /* the extra 4 bytes if for ": " and "\r\n" */ - uint8_t *new_headers_buffer = SCRealloc(headers_buffer, headers_buffer_len + size1 + size2 + 4); - if (unlikely(new_headers_buffer == NULL)) { - if (headers_buffer != NULL) { - SCFree(headers_buffer); - headers_buffer = NULL; + size_t size = size1 + size2 + 4; +#if 0 + if (i + 1 == no_of_headers) + size += 2; +#endif + if (size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { + return NULL; } - det_ctx->hhd_buffers[index] = NULL; - det_ctx->hhd_buffers_len[index] = 0; - goto end; } - headers_buffer = new_headers_buffer; - - memcpy(headers_buffer + headers_buffer_len, bstr_ptr(h->name), size1); - headers_buffer_len += size1; - headers_buffer[headers_buffer_len] = ':'; - headers_buffer[headers_buffer_len + 1] = ' '; - headers_buffer_len += 2; - memcpy(headers_buffer + headers_buffer_len, bstr_ptr(h->value), size2); - headers_buffer_len += size2 + 2; - /* \r */ - headers_buffer[headers_buffer_len - 2] = '\r'; - /* \n */ - headers_buffer[headers_buffer_len - 1] = '\n'; - } - - /* store the buffers. We will need it for further inspection */ - det_ctx->hhd_buffers[index] = headers_buffer; - det_ctx->hhd_buffers_len[index] = headers_buffer_len; - - *buffer_len = (uint32_t)headers_buffer_len; - end: - return headers_buffer; + + memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); + buf->len += bstr_size(h->name); + buf->buffer[buf->len++] = ':'; + buf->buffer[buf->len++] = ' '; + memcpy(buf->buffer + buf->len, bstr_ptr(h->value), bstr_size(h->value)); + buf->len += bstr_size(h->value); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; +#if 0 // looks like this breaks existing rules + if (i + 1 == no_of_headers) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } +#endif + } + + *buffer_len = buf->len; + return buf->buffer; } /** \brief HTTP Headers Mpm prefilter callback @@ -244,11 +177,9 @@ static void PrefilterTxHttpRequestHeaders(DetectEngineThreadCtx *det_ctx, HtpState *htp_state = f->alstate; uint32_t buffer_len = 0; - const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, - NULL, det_ctx, - f, htp_state, - flags, - &buffer_len); + const uint8_t *buffer = GetBufferForTX(tx, idx, + NULL, det_ctx, f, htp_state, + flags, &buffer_len); if (buffer_len >= mpm_ctx->minlen) { (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, @@ -327,7 +258,7 @@ static void PrefilterTxHttpResponseHeaders(DetectEngineThreadCtx *det_ctx, HtpState *htp_state = f->alstate; uint32_t buffer_len = 0; - const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + const uint8_t *buffer = GetBufferForTX(tx, idx, NULL, det_ctx, f, htp_state, flags, @@ -394,11 +325,9 @@ static int DetectEngineInspectHttpHeader(ThreadVars *tv, { HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; - uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, tx_id, - de_ctx, det_ctx, - f, htp_state, - flags, - &buffer_len); + uint8_t *buffer = GetBufferForTX(tx, tx_id, de_ctx, det_ctx, + f, htp_state, + flags, &buffer_len); if (buffer_len == 0) goto end; @@ -425,20 +354,6 @@ static int DetectEngineInspectHttpHeader(ThreadVars *tv, return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } -void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx) -{ - if (det_ctx->hhd_buffers_list_len != 0) { - int i; - for (i = 0; i < det_ctx->hhd_buffers_list_len; i++) { - det_ctx->hhd_buffers_len[i] = 0; - } - det_ctx->hhd_buffers_list_len = 0; - } - det_ctx->hhd_start_tx_id = 0; - - return; -} - /** * \brief The setup function for the http_header keyword for a signature. * @@ -499,6 +414,9 @@ void DetectHttpHeaderRegister(void) DetectHttpHeaderSetupCallback); g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); + + g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs("http_header", + HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); } /************************************Unittests*********************************/ diff --git a/src/detect.c b/src/detect.c index 37576ddc36dc..881608c3a78d 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1577,7 +1577,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh DetectEngineCleanHCBDBuffers(det_ctx); DetectEngineCleanHSBDBuffers(det_ctx); - DetectEngineCleanHHDBuffers(det_ctx); DetectEngineCleanSMTPBuffers(det_ctx); /* store the found sgh (or NULL) in the flow to save us from looking it diff --git a/src/detect.h b/src/detect.h index 8a68f6774d19..9b0526384409 100644 --- a/src/detect.h +++ b/src/detect.h @@ -817,12 +817,6 @@ typedef struct DetectEngineThreadCtx_ { 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; - FiledataReassembledBody *smtp; uint64_t smtp_start_tx_id; uint16_t smtp_buffers_size; From 36535efa04b68fb687d0f60424aa00471ed3bf94 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 19 Dec 2016 23:41:40 +0100 Subject: [PATCH 2402/2553] detect: add http_protocol sticky buffer Matches on protocol field in HTTP. --- src/Makefile.am | 1 + src/detect-http-protocol.c | 240 +++++++++++++++++++++++++++++++++++++ src/detect-http-protocol.h | 29 +++++ src/detect.c | 2 + src/detect.h | 1 + 5 files changed, 273 insertions(+) create mode 100644 src/detect-http-protocol.c create mode 100644 src/detect-http-protocol.h diff --git a/src/Makefile.am b/src/Makefile.am index c3e9a196fc3e..29d1d606984c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -169,6 +169,7 @@ detect-http-header-names.c detect-http-header-names.h \ detect-http-hh.c detect-http-hh.h \ detect-http-hrh.c detect-http-hrh.h \ detect-http-method.c detect-http-method.h \ +detect-http-protocol.c detect-http-protocol.h \ detect-http-raw-header.c detect-http-raw-header.h \ detect-http-raw-uri.c detect-http-raw-uri.h \ detect-http-request-line.c detect-http-request-line.h \ diff --git a/src/detect-http-protocol.c b/src/detect-http-protocol.c new file mode 100644 index 000000000000..fbdf22e9c193 --- /dev/null +++ b/src/detect-http-protocol.c @@ -0,0 +1,240 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support http_protocol sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-http-header-common.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" +#include "util-print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "detect-http-header.h" +#include "stream-tcp.h" + +#include "util-print.h" + +#define KEYWORD_NAME "http_protocol" +#define KEYWORD_DOC "http-keywords#http-protocol" +#define BUFFER_NAME "http_protocol" +#define BUFFER_DESC "http protocol" +static int g_buffer_id = 0; + +/** \brief HTTP Protocol Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpRequestProtocol(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_protocol == NULL) + return; + + uint32_t buffer_len = bstr_size(tx->request_protocol); + const uint8_t *buffer = bstr_ptr(tx->request_protocol); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpRequestProtocolRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestProtocol, + ALPROTO_HTTP, HTP_REQUEST_LINE, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + return r; +} + +/** \brief HTTP Protocol Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpResponseProtocol(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_protocol == NULL) + return; + + uint32_t buffer_len = bstr_size(tx->response_protocol); + const uint8_t *buffer = bstr_ptr(tx->response_protocol); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpResponseProtocolRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseProtocol, + ALPROTO_HTTP, HTP_RESPONSE_LINE, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + return r; +} + +static int InspectEngineHttpProtocol(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + bstr *str = NULL; + htp_tx_t *http_tx = tx; + + if (flags & STREAM_TOSERVER) + str = http_tx->request_protocol; + else if (flags & STREAM_TOCLIENT) + str = http_tx->response_protocol; + + if (str == NULL) + goto end; + + uint32_t buffer_len = bstr_size(str); + uint8_t *buffer = bstr_ptr(str); + if (buffer == NULL ||buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_LINE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_LINE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +int DetectHttpProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_buffer_id; + return 0; +} + +static void DetectHttpProtocolSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +/** + * \brief Registers the keyword handlers for the "http_header" keyword. + */ +void DetectHttpProtocolRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].url = DOC_URL DOC_VERSION "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].Setup = DetectHttpProtocolSetup; + + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].flags |= SIGMATCH_NOOPT ; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].flags |= SIGMATCH_PAYLOAD ; + + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxHttpRequestProtocolRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxHttpResponseProtocolRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + InspectEngineHttpProtocol); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + InspectEngineHttpProtocol); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, + BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, + DetectHttpProtocolSetupCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-http-protocol.h b/src/detect-http-protocol.h new file mode 100644 index 000000000000..88dde2f8c764 --- /dev/null +++ b/src/detect-http-protocol.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 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 + */ + +#ifndef __DETECT_HTTP_PROTOCOL_H__ +#define __DETECT_HTTP_PROTOCOL_H__ + +void DetectHttpProtocolRegister(void); + +#endif /* __DETECT_HTTP_PROTOCOL_H__ */ diff --git a/src/detect.c b/src/detect.c index 881608c3a78d..003d0342b9ed 100644 --- a/src/detect.c +++ b/src/detect.c @@ -141,6 +141,7 @@ #include "detect-http-header-names.h" #include "detect-http-raw-header.h" #include "detect-http-uri.h" +#include "detect-http-protocol.h" #include "detect-http-raw-uri.h" #include "detect-http-stat-msg.h" #include "detect-http-request-line.h" @@ -4055,6 +4056,7 @@ void SigTableSetup(void) DetectHttpServerBodyRegister(); DetectHttpHeaderRegister(); DetectHttpHeaderNamesRegister(); + DetectHttpProtocolRegister(); DetectHttpRawHeaderRegister(); DetectHttpMethodRegister(); DetectHttpCookieRegister(); diff --git a/src/detect.h b/src/detect.h index 9b0526384409..93edd58f397e 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1245,6 +1245,7 @@ enum { DETECT_AL_HTTP_COOKIE, DETECT_AL_HTTP_METHOD, + DETECT_AL_HTTP_PROTOCOL, DETECT_AL_URILEN, DETECT_AL_HTTP_CLIENT_BODY, DETECT_AL_HTTP_SERVER_BODY, From 1087495d6dccea7211e0a454ef9d994d7b05a7b5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 20 Dec 2016 14:04:55 +0100 Subject: [PATCH 2403/2553] detect: http_start sticky buffer Matches on the start of a HTTP request or response. Uses a buffer constructed from the request line and normalized request headers, including the Cookie header. Or for the response side, it uses the response line plus the normalized response headers, including the Set-Cookie header. Both buffers are terminated by an extra \r\n. --- src/Makefile.am | 1 + src/detect-http-start.c | 337 ++++++++++++++++++++++++++++++++++++++++ src/detect-http-start.h | 29 ++++ src/detect.c | 2 + src/detect.h | 1 + 5 files changed, 370 insertions(+) create mode 100644 src/detect-http-start.c create mode 100644 src/detect-http-start.h diff --git a/src/Makefile.am b/src/Makefile.am index 29d1d606984c..7d505307dba2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -175,6 +175,7 @@ detect-http-raw-uri.c detect-http-raw-uri.h \ detect-http-request-line.c detect-http-request-line.h \ detect-http-response-line.c detect-http-response-line.h \ detect-http-server-body.c detect-http-server-body.h \ +detect-http-start.c detect-http-start.h \ detect-http-stat-code.c detect-http-stat-code.h \ detect-http-stat-msg.c detect-http-stat-msg.h \ detect-http-ua.c detect-http-ua.h \ diff --git a/src/detect-http-start.c b/src/detect-http-start.c new file mode 100644 index 000000000000..b4149301c68a --- /dev/null +++ b/src/detect-http-start.c @@ -0,0 +1,337 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements http_start + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-http-header-common.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" +#include "util-print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "detect-http-header.h" +#include "stream-tcp.h" + +#include "util-print.h" + +#define KEYWORD_NAME "http_start" +#define KEYWORD_DOC "http-keywords#http-start" +#define BUFFER_NAME "http_start" +#define BUFFER_DESC "http start: request/response line + headers" +static int g_buffer_id = 0; +static int g_keyword_thread_id = 0; + +#define BUFFER_TX_STEP 4 +#define BUFFER_SIZE_STEP 2048 +static HttpHeaderThreadDataConfig g_td_config = { BUFFER_TX_STEP, BUFFER_SIZE_STEP }; + +static uint8_t *GetBufferForTX(htp_tx_t *tx, uint64_t tx_id, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Flow *f, HtpState *htp_state, uint8_t flags, + uint32_t *buffer_len) +{ + *buffer_len = 0; + + HttpHeaderThreadData *hdr_td = NULL; + HttpHeaderBuffer *buf = HttpHeaderGetBufferSpaceForTXID(det_ctx, f, flags, + tx_id, g_keyword_thread_id, &hdr_td); + if (unlikely(buf == NULL)) { + return NULL; + } else if (buf->len > 0) { + /* already filled buf, reuse */ + *buffer_len = buf->len; + return buf->buffer; + } + + bstr *line = NULL; + htp_table_t *headers; + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= + HTP_REQUEST_HEADERS) + return NULL; + line = tx->request_line; + headers = tx->request_headers; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= + HTP_RESPONSE_HEADERS) + return NULL; + headers = tx->response_headers; + line = tx->response_line; + } + if (headers == NULL) + return NULL; + + size_t line_size = bstr_len(line) + 2; + if (line_size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, line_size) != 0) { + return NULL; + } + } + memcpy(buf->buffer + buf->len, bstr_ptr(line), bstr_size(line)); + buf->len += bstr_size(line); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + + size_t i = 0; + size_t no_of_headers = htp_table_size(headers); + for (; i < no_of_headers; i++) { + htp_header_t *h = htp_table_get_index(headers, i, NULL); + size_t size1 = bstr_size(h->name); + size_t size2 = bstr_size(h->value); +#if 0 + if (flags & STREAM_TOSERVER) { + if (size1 == 6 && + SCMemcmpLowercase("cookie", bstr_ptr(h->name), 6) == 0) { + continue; + } + } else { + if (size1 == 10 && + SCMemcmpLowercase("set-cookie", bstr_ptr(h->name), 10) == 0) { + continue; + } + } +#endif + size_t size = size1 + size2 + 4; + if (i + 1 == no_of_headers) + size += 2; + if (size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { + return NULL; + } + } + + memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); + buf->len += bstr_size(h->name); + buf->buffer[buf->len++] = ':'; + buf->buffer[buf->len++] = ' '; + memcpy(buf->buffer + buf->len, bstr_ptr(h->value), bstr_size(h->value)); + buf->len += bstr_size(h->value); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + if (i + 1 == no_of_headers) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } + } + + *buffer_len = buf->len; + return buf->buffer; +} + +/** \brief HTTP Start Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpRequestStart(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = GetBufferForTX(tx, idx, + NULL, det_ctx, f, htp_state, + flags, &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpRequestStartRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestStart, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + return r; +} + +/** \brief HTTP Start Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpResponseStart(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = GetBufferForTX(tx, idx, NULL, det_ctx, + f, htp_state, flags, &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpResponseStartRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseStart, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + return r; +} + +static int InspectEngineHttpStart(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + HtpState *htp_state = (HtpState *)alstate; + uint32_t buffer_len = 0; + uint8_t *buffer = GetBufferForTX(tx, tx_id, + de_ctx, det_ctx, f, htp_state, + flags, &buffer_len); + if (buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +static int DetectHttpStartSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_buffer_id; + return 0; +} + +static void DetectHttpStartSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +/** + * \brief Registers the keyword handlers for the "http_header" keyword. + */ +void DetectHttpStartRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_START].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_HTTP_START].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_HTTP_START].url = DOC_URL DOC_VERSION "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_HTTP_START].Setup = DetectHttpStartSetup; + + sigmatch_table[DETECT_AL_HTTP_START].flags |= SIGMATCH_NOOPT ; + sigmatch_table[DETECT_AL_HTTP_START].flags |= SIGMATCH_PAYLOAD ; + + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxHttpRequestStartRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxHttpResponseStartRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + InspectEngineHttpStart); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + InspectEngineHttpStart); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, + BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, + DetectHttpStartSetupCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs(KEYWORD_NAME, + HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); + + SCLogDebug("keyword %s registered. Thread id %d. " + "Buffer %s registered. Buffer id %d", + KEYWORD_NAME, g_keyword_thread_id, + BUFFER_NAME, g_buffer_id); +} diff --git a/src/detect-http-start.h b/src/detect-http-start.h new file mode 100644 index 000000000000..52cada1c860a --- /dev/null +++ b/src/detect-http-start.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 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 + */ + +#ifndef __DETECT_HTTP_START_H__ +#define __DETECT_HTTP_START_H__ + +void DetectHttpStartRegister(void); + +#endif /* __DETECT_HTTP_START_H__ */ diff --git a/src/detect.c b/src/detect.c index 003d0342b9ed..8f34641d8aab 100644 --- a/src/detect.c +++ b/src/detect.c @@ -142,6 +142,7 @@ #include "detect-http-raw-header.h" #include "detect-http-uri.h" #include "detect-http-protocol.h" +#include "detect-http-start.h" #include "detect-http-raw-uri.h" #include "detect-http-stat-msg.h" #include "detect-http-request-line.h" @@ -4057,6 +4058,7 @@ void SigTableSetup(void) DetectHttpHeaderRegister(); DetectHttpHeaderNamesRegister(); DetectHttpProtocolRegister(); + DetectHttpStartRegister(); DetectHttpRawHeaderRegister(); DetectHttpMethodRegister(); DetectHttpCookieRegister(); diff --git a/src/detect.h b/src/detect.h index 93edd58f397e..3800e75296d2 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1246,6 +1246,7 @@ enum { DETECT_AL_HTTP_COOKIE, DETECT_AL_HTTP_METHOD, DETECT_AL_HTTP_PROTOCOL, + DETECT_AL_HTTP_START, DETECT_AL_URILEN, DETECT_AL_HTTP_CLIENT_BODY, DETECT_AL_HTTP_SERVER_BODY, From 8eac1156c658a501993f3965e6df1402dd7f6c0f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Dec 2016 17:58:26 +0100 Subject: [PATCH 2404/2553] app-layer-events: remove unused API options --- src/app-layer-events.h | 3 +-- src/detect-app-layer-event.c | 31 ++----------------------------- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/src/app-layer-events.h b/src/app-layer-events.h index 11dfb9e60daa..0261a26f9265 100644 --- a/src/app-layer-events.h +++ b/src/app-layer-events.h @@ -50,8 +50,7 @@ enum { /* the event types for app events */ typedef enum AppLayerEventType_ { - APP_LAYER_EVENT_TYPE_GENERAL = 1, - APP_LAYER_EVENT_TYPE_TRANSACTION, + APP_LAYER_EVENT_TYPE_TRANSACTION = 1, APP_LAYER_EVENT_TYPE_PACKET, } AppLayerEventType; diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index a4207899f426..c7128c27a751 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -50,8 +50,6 @@ static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx); -static int DetectAppLayerEventAppMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, const Signature *, const SigMatchData *); static int DetectAppLayerEventSetupP1(DetectEngineCtx *, Signature *, char *); static void DetectAppLayerEventRegisterTests(void); static void DetectAppLayerEventFree(void *); @@ -71,8 +69,6 @@ void DetectAppLayerEventRegister(void) sigmatch_table[DETECT_AL_APP_LAYER_EVENT].name = "app-layer-event"; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Match = DetectAppLayerEventPktMatch; - sigmatch_table[DETECT_AL_APP_LAYER_EVENT].AppLayerMatch = - DetectAppLayerEventAppMatch; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Setup = DetectAppLayerEventSetupP1; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Free = DetectAppLayerEventFree; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].RegisterTests = @@ -150,26 +146,6 @@ static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det aled->event_id); } -static int DetectAppLayerEventAppMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) -{ - SCEnter(); - AppLayerDecoderEvents *decoder_events = NULL; - int r = 0; - DetectAppLayerEventData *aled = (DetectAppLayerEventData *)m->ctx; - - if (r == 0) { - decoder_events = AppLayerParserGetDecoderEvents(f->alparser); - if (decoder_events != NULL && - AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) { - r = 1; - } - } - - SCReturnInt(r); -} - static void DetectAppLayerEventSetupCallback(Signature *s) { SigMatch *sm; @@ -336,10 +312,7 @@ static int DetectAppLayerEventSetupP2(Signature *s, /* DetectAppLayerEventParseAppP2 prints errors */ return -1; } - if (event_type == APP_LAYER_EVENT_TYPE_GENERAL) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - else - SigMatchAppendSMToList(s, sm, g_applayer_events_list_id); + SigMatchAppendSMToList(s, sm, g_applayer_events_list_id); /* We should have set this flag already in SetupP1 */ s->flags |= SIG_FLAG_APPLAYER; @@ -456,7 +429,7 @@ static int DetectAppLayerEventTestGetEventInfo(const char *event_name, return -1; } - *event_type = APP_LAYER_EVENT_TYPE_GENERAL; + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; return 0; } From 8b3a71a2859c125a8b461b88cf620d48d9c479ca Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Dec 2016 19:43:25 +0100 Subject: [PATCH 2405/2553] tls.store: cleanup --- src/detect-tls.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/detect-tls.c b/src/detect-tls.c index 4b5db38213b2..c86e55f20cb3 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -783,30 +783,22 @@ static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *str { SigMatch *sm = NULL; - s->flags |= SIG_FLAG_TLSSTORE; - - sm = SigMatchAlloc(); - if (sm == NULL) - goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; + return -1; } + sm = SigMatchAlloc(); + if (sm == NULL) + return -1; + sm->type = DETECT_AL_TLS_STORE; s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_TLS; + s->flags |= SIG_FLAG_TLSSTORE; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - return 0; - -error: - if (sm != NULL) - SCFree(sm); - return -1; - } /** \warning modifies state */ From ef149bed7b0d25358582859798d3c2a57129b815 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Dec 2016 19:53:00 +0100 Subject: [PATCH 2406/2553] tls.store: convert to postmatch --- src/detect-tls.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/detect-tls.c b/src/detect-tls.c index c86e55f20cb3..4fadef733c61 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -95,9 +95,8 @@ static int DetectTlsFingerprintSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsFingerprintFree(void *); static int DetectTlsStoreSetup (DetectEngineCtx *, Signature *, char *); -static int DetectTlsStoreMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, void *, - const Signature *, const SigMatchData *); +static int DetectTlsStorePostMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *, const Signature *s, const SigMatchCtx *unused); /** * \brief Registration function for keyword: tls.version @@ -131,11 +130,11 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free = DetectTlsFingerprintFree; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].RegisterTests = NULL; - sigmatch_table[DETECT_AL_TLS_STORE].name = "tls.store"; + sigmatch_table[DETECT_AL_TLS_STORE].name = "tls_store"; + sigmatch_table[DETECT_AL_TLS_STORE].alias = "tls.store"; sigmatch_table[DETECT_AL_TLS_STORE].desc = "store TLS/SSL certificate on disk"; sigmatch_table[DETECT_AL_TLS_STORE].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsstore"; - sigmatch_table[DETECT_AL_TLS_STORE].Match = NULL; - sigmatch_table[DETECT_AL_TLS_STORE].AppLayerMatch = DetectTlsStoreMatch; + sigmatch_table[DETECT_AL_TLS_STORE].Match = DetectTlsStorePostMatch; sigmatch_table[DETECT_AL_TLS_STORE].Setup = DetectTlsStoreSetup; sigmatch_table[DETECT_AL_TLS_STORE].Free = NULL; sigmatch_table[DETECT_AL_TLS_STORE].RegisterTests = NULL; @@ -797,27 +796,26 @@ static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *str s->alproto = ALPROTO_TLS; s->flags |= SIG_FLAG_TLSSTORE; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); return 0; } -/** \warning modifies state */ -static int DetectTlsStoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) +/** \warning modifies Flow::alstate */ +static int DetectTlsStorePostMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *unused) { SCEnter(); - SSLState *ssl_state = (SSLState *)state; + if (p->flow == NULL) + return 0; + + SSLState *ssl_state = FlowGetAppState(p->flow); if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); - SCReturnInt(1); - } - - if (s->flags & SIG_FLAG_TLSSTORE) { - ssl_state->server_connp.cert_log_flag |= SSL_TLS_LOG_PEM; + SCReturnInt(0); } + ssl_state->server_connp.cert_log_flag |= SSL_TLS_LOG_PEM; SCReturnInt(1); } From 6ef4712cd684bd2c9725eb0237eaf196e34b5f79 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Dec 2016 21:27:56 +0100 Subject: [PATCH 2407/2553] detect: convert old tls keywords to dynamic list --- src/detect-tls.c | 93 ++++++++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 39 deletions(-) diff --git a/src/detect-tls.c b/src/detect-tls.c index 4fadef733c61..9a1a2122bfa6 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -75,22 +75,22 @@ static pcre *fingerprint_parse_regex; static pcre_extra *fingerprint_parse_regex_study; static int DetectTlsSubjectMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, void *, - const Signature *, const SigMatchData *); + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectTlsSubjectSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsSubjectRegisterTests(void); static void DetectTlsSubjectFree(void *); static int DetectTlsIssuerDNMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, void *, - const Signature *, const SigMatchData *); + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectTlsIssuerDNSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsIssuerDNRegisterTests(void); static void DetectTlsIssuerDNFree(void *); static int DetectTlsFingerprintMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, void *, - const Signature *, const SigMatchData *); + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectTlsFingerprintSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsFingerprintFree(void *); @@ -98,6 +98,18 @@ static int DetectTlsStoreSetup (DetectEngineCtx *, Signature *, char *); static int DetectTlsStorePostMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *, const Signature *s, const SigMatchCtx *unused); +static int g_tls_cert_list_id = 0; + +static int InspectTlsCert(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} + /** * \brief Registration function for keyword: tls.version */ @@ -106,8 +118,7 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_SUBJECT].name = "tls.subject"; sigmatch_table[DETECT_AL_TLS_SUBJECT].desc = "match TLS/SSL certificate Subject field"; sigmatch_table[DETECT_AL_TLS_SUBJECT].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlssubject"; - sigmatch_table[DETECT_AL_TLS_SUBJECT].Match = NULL; - sigmatch_table[DETECT_AL_TLS_SUBJECT].AppLayerMatch = DetectTlsSubjectMatch; + sigmatch_table[DETECT_AL_TLS_SUBJECT].AppLayerTxMatch = DetectTlsSubjectMatch; sigmatch_table[DETECT_AL_TLS_SUBJECT].Setup = DetectTlsSubjectSetup; sigmatch_table[DETECT_AL_TLS_SUBJECT].Free = DetectTlsSubjectFree; sigmatch_table[DETECT_AL_TLS_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; @@ -115,8 +126,7 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_ISSUERDN].name = "tls.issuerdn"; sigmatch_table[DETECT_AL_TLS_ISSUERDN].desc = "match TLS/SSL certificate IssuerDN field"; sigmatch_table[DETECT_AL_TLS_ISSUERDN].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsissuerdn"; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].Match = NULL; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].AppLayerMatch = DetectTlsIssuerDNMatch; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].AppLayerTxMatch = DetectTlsIssuerDNMatch; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Setup = DetectTlsIssuerDNSetup; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Free = DetectTlsIssuerDNFree; sigmatch_table[DETECT_AL_TLS_ISSUERDN].RegisterTests = DetectTlsIssuerDNRegisterTests; @@ -124,8 +134,7 @@ void DetectTlsRegister (void) sigmatch_table[DETECT_AL_TLS_FINGERPRINT].name = "tls.fingerprint"; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].desc = "match TLS/SSL certificate SHA1 fingerprint"; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsfingerprint"; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Match = NULL; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].AppLayerMatch = DetectTlsFingerprintMatch; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].AppLayerTxMatch = DetectTlsFingerprintMatch; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free = DetectTlsFingerprintFree; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].RegisterTests = NULL; @@ -146,6 +155,12 @@ void DetectTlsRegister (void) &issuerdn_parse_regex, &issuerdn_parse_regex_study); DetectSetupParseRegexes(PARSE_REGEX_FINGERPRINT, &fingerprint_parse_regex, &fingerprint_parse_regex_study); + + g_tls_cert_list_id = DetectBufferTypeRegister("tls_cert"); + + DetectAppLayerInspectEngineRegister("tls_cert", + ALPROTO_TLS, SIG_FLAG_TOCLIENT, + InspectTlsCert); } /** @@ -160,12 +175,12 @@ void DetectTlsRegister (void) * \retval 1 match */ static int DetectTlsSubjectMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - const DetectTlsData *tls_data = (const DetectTlsData *)m->ctx; + const DetectTlsData *tls_data = (const DetectTlsData *)m; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -304,6 +319,11 @@ static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectTlsData *tls = NULL; SigMatch *sm = NULL; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + goto error; + } + tls = DetectTlsSubjectParse(str); if (tls == NULL) goto error; @@ -314,18 +334,13 @@ static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, char *s if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - sm->type = DETECT_AL_TLS_SUBJECT; sm->ctx = (void *)tls; s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_tls_cert_list_id); return 0; @@ -372,12 +387,12 @@ static void DetectTlsSubjectRegisterTests(void) * \retval 1 match */ static int DetectTlsIssuerDNMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - const DetectTlsData *tls_data = (const DetectTlsData *)m->ctx; + const DetectTlsData *tls_data = (const DetectTlsData *)m; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -517,6 +532,11 @@ static int DetectTlsIssuerDNSetup (DetectEngineCtx *de_ctx, Signature *s, char * DetectTlsData *tls = NULL; SigMatch *sm = NULL; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + goto error; + } + tls = DetectTlsIssuerDNParse(str); if (tls == NULL) goto error; @@ -527,18 +547,13 @@ static int DetectTlsIssuerDNSetup (DetectEngineCtx *de_ctx, Signature *s, char * if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - sm->type = DETECT_AL_TLS_ISSUERDN; sm->ctx = (void *)tls; s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_tls_cert_list_id); return 0; @@ -656,11 +671,11 @@ static DetectTlsData *DetectTlsFingerprintParse (char *str) * \retval 1 match */ static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - const DetectTlsData *tls_data = (const DetectTlsData *)m->ctx; + const DetectTlsData *tls_data = (const DetectTlsData *)m; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -720,6 +735,11 @@ static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, cha DetectTlsData *tls = NULL; SigMatch *sm = NULL; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + goto error; + } + tls = DetectTlsFingerprintParse(str); if (tls == NULL) goto error; @@ -730,18 +750,13 @@ static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, cha if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - sm->type = DETECT_AL_TLS_FINGERPRINT; sm->ctx = (void *)tls; s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_tls_cert_list_id); return 0; From 1cacba435b57b704d640acbe6f480d432b52088b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 10:09:34 +0100 Subject: [PATCH 2408/2553] ssl/tls: clean up keywords --- src/detect-ssl-state.c | 43 ++++++++++++++++++++-------------------- src/detect-ssl-version.c | 26 ++++++++++++------------ src/detect-tls-version.c | 35 +++++++++++++++++--------------- 3 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 64b5e7af3f5e..9cb9c7bc2b4f 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -63,8 +63,8 @@ static int DetectSslStateMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatchData *); static int DetectSslStateSetup(DetectEngineCtx *, Signature *, char *); -void DetectSslStateRegisterTests(void); -void DetectSslStateFree(void *); +static void DetectSslStateRegisterTests(void); +static void DetectSslStateFree(void *); /** * \brief Registers the keyword handlers for the "ssl_state" keyword. @@ -125,7 +125,7 @@ static int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, * \retval ssd Pointer to DetectSslStateData on succese. * \retval NULL On failure. */ -DetectSslStateData *DetectSslStateParse(char *arg) +static DetectSslStateData *DetectSslStateParse(char *arg) { #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; @@ -274,11 +274,17 @@ DetectSslStateData *DetectSslStateParse(char *arg) * \retval 0 On success. * \retval -1 On failure. */ -int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +static int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectSslStateData *ssd = NULL; SigMatch *sm = NULL; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "Rule contains conflicting keywords. Have non-tls alproto " + "set for a rule containing \"ssl_state\" keyword"); + goto error; + } ssd = DetectSslStateParse(arg); if (ssd == NULL) goto error; @@ -290,12 +296,6 @@ int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->type = DETECT_AL_SSL_STATE; sm->ctx = (SigMatchCtx*)ssd; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, - "Rule contains conflicting keywords. Have non-tls alproto " - "set for a rule containing \"ssl_state\" keyword"); - goto error; - } s->alproto = ALPROTO_TLS; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); @@ -315,7 +315,7 @@ int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) * * \param ptr pointer to the data to be freed. */ -void DetectSslStateFree(void *ptr) +static void DetectSslStateFree(void *ptr) { if (ptr != NULL) SCFree(ptr); @@ -327,7 +327,7 @@ void DetectSslStateFree(void *ptr) #ifdef UNITTESTS -int DetectSslStateTest01(void) +static int DetectSslStateTest01(void) { DetectSslStateData *ssd = DetectSslStateParse("client_hello"); FAIL_IF_NULL(ssd); @@ -336,7 +336,7 @@ int DetectSslStateTest01(void) PASS; } -int DetectSslStateTest02(void) +static int DetectSslStateTest02(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_hello"); FAIL_IF_NULL(ssd); @@ -346,7 +346,7 @@ int DetectSslStateTest02(void) PASS; } -int DetectSslStateTest03(void) +static int DetectSslStateTest03(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " "client_hello"); @@ -358,7 +358,7 @@ int DetectSslStateTest03(void) PASS; } -int DetectSslStateTest04(void) +static int DetectSslStateTest04(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " "client_hello , server_keyx , " @@ -373,7 +373,7 @@ int DetectSslStateTest04(void) PASS; } -int DetectSslStateTest05(void) +static int DetectSslStateTest05(void) { DetectSslStateData *ssd = DetectSslStateParse(", server_hello , client_keyx , " "client_hello , server_keyx , " @@ -383,7 +383,7 @@ int DetectSslStateTest05(void) PASS; } -int DetectSslStateTest06(void) +static int DetectSslStateTest06(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " "client_hello , server_keyx , " @@ -813,7 +813,7 @@ static int DetectSslStateTest07(void) * \brief Test that the "|" character still works as a separate for * compatibility with older Suricata rules. */ -int DetectSslStateTest08(void) +static int DetectSslStateTest08(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello|client_hello"); FAIL_IF_NULL(ssd); @@ -826,7 +826,7 @@ int DetectSslStateTest08(void) /** * \test Test parsing of negated states. */ -int DetectSslStateTestParseNegate(void) +static int DetectSslStateTestParseNegate(void) { DetectSslStateData *ssd = DetectSslStateParse("!client_hello"); FAIL_IF_NULL(ssd); @@ -845,7 +845,7 @@ int DetectSslStateTestParseNegate(void) #endif /* UNITTESTS */ -void DetectSslStateRegisterTests(void) +static void DetectSslStateRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectSslStateTest01", DetectSslStateTest01); @@ -859,6 +859,5 @@ void DetectSslStateRegisterTests(void) UtRegisterTest("DetectSslStateTestParseNegate", DetectSslStateTestParseNegate); #endif - return; } diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index 53dc75131652..ea8f839c8538 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -64,8 +64,8 @@ static int DetectSslVersionMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatchData *); static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, char *); -void DetectSslVersionRegisterTests(void); -void DetectSslVersionFree(void *); +static void DetectSslVersionRegisterTests(void); +static void DetectSslVersionFree(void *); /** * \brief Registration function for keyword: ssl_version @@ -163,7 +163,7 @@ static int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, * \retval ssl pointer to DetectSslVersionData on success * \retval NULL on failure */ -DetectSslVersionData *DetectSslVersionParse(char *str) +static DetectSslVersionData *DetectSslVersionParse(char *str) { DetectSslVersionData *ssl = NULL; #define MAX_SUBSTRINGS 30 @@ -280,6 +280,11 @@ static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectSslVersionData *ssl = NULL; SigMatch *sm = NULL; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + goto error; + } + ssl = DetectSslVersionParse(str); if (ssl == NULL) goto error; @@ -293,11 +298,6 @@ static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->type = DETECT_AL_SSL_VERSION; sm->ctx = (void *)ssl; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); s->alproto = ALPROTO_TLS; @@ -330,7 +330,7 @@ void DetectSslVersionFree(void *ptr) * \test DetectSslVersionTestParse01 is a test to make sure that we parse the * "ssl_version" option correctly when given valid ssl_version option */ -int DetectSslVersionTestParse01(void) +static int DetectSslVersionTestParse01(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("SSlv3"); @@ -345,7 +345,7 @@ int DetectSslVersionTestParse01(void) * "ssl_version" option correctly when given an invalid ssl_version option * it should return ssl = NULL */ -int DetectSslVersionTestParse02(void) +static int DetectSslVersionTestParse02(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("2.5"); @@ -358,7 +358,7 @@ int DetectSslVersionTestParse02(void) * \test DetectSslVersionTestParse03 is a test to make sure that we parse the * "ssl_version" options correctly when given valid ssl_version options */ -int DetectSslVersionTestParse03(void) +static int DetectSslVersionTestParse03(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("SSlv3,tls1.0, !tls1.2"); @@ -654,7 +654,7 @@ static int DetectSslVersionTestDetect03(void) /** * \brief this function registers unit tests for DetectSslVersion */ -void DetectSslVersionRegisterTests(void) +static void DetectSslVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectSslVersionTestParse01", DetectSslVersionTestParse01); diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index d7ee9c8513c3..ee7d2c1678d7 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -63,8 +63,8 @@ static int DetectTlsVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, const Signature *, const SigMatchData *); static int DetectTlsVersionSetup (DetectEngineCtx *, Signature *, char *); -void DetectTlsVersionRegisterTests(void); -void DetectTlsVersionFree(void *); +static void DetectTlsVersionRegisterTests(void); +static void DetectTlsVersionFree(void *); /** * \brief Registration function for keyword: tls.version @@ -131,7 +131,7 @@ static int DetectTlsVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, * \retval id_d pointer to DetectTlsVersionData on success * \retval NULL on failure */ -DetectTlsVersionData *DetectTlsVersionParse (char *str) +static DetectTlsVersionData *DetectTlsVersionParse (char *str) { uint16_t temp; DetectTlsVersionData *tls = NULL; @@ -219,8 +219,14 @@ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectTlsVersionData *tls = NULL; SigMatch *sm = NULL; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + goto error; + } + tls = DetectTlsVersionParse(str); - if (tls == NULL) goto error; + if (tls == NULL) + goto error; /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ @@ -231,19 +237,16 @@ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->type = DETECT_AL_TLS_VERSION; sm->ctx = (void *)tls; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); s->alproto = ALPROTO_TLS; return 0; error: - if (tls != NULL) DetectTlsVersionFree(tls); - if (sm != NULL) SCFree(sm); + if (tls != NULL) + DetectTlsVersionFree(tls); + if (sm != NULL) + SCFree(sm); return -1; } @@ -253,7 +256,7 @@ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s * * \param id_d pointer to DetectTlsVersionData */ -void DetectTlsVersionFree(void *ptr) +static void DetectTlsVersionFree(void *ptr) { DetectTlsVersionData *id_d = (DetectTlsVersionData *)ptr; SCFree(id_d); @@ -265,7 +268,7 @@ void DetectTlsVersionFree(void *ptr) * \test DetectTlsVersionTestParse01 is a test to make sure that we parse the "id" * option correctly when given valid id option */ -int DetectTlsVersionTestParse01 (void) +static int DetectTlsVersionTestParse01 (void) { DetectTlsVersionData *tls = NULL; tls = DetectTlsVersionParse("1.0"); @@ -280,7 +283,7 @@ int DetectTlsVersionTestParse01 (void) * option correctly when given an invalid id option * it should return id_d = NULL */ -int DetectTlsVersionTestParse02 (void) +static int DetectTlsVersionTestParse02 (void) { DetectTlsVersionData *tls = NULL; tls = DetectTlsVersionParse("2.5"); @@ -582,7 +585,7 @@ static int DetectTlsVersionTestDetect03(void) /** * \brief this function registers unit tests for DetectTlsVersion */ -void DetectTlsVersionRegisterTests(void) +static void DetectTlsVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectTlsVersionTestParse01", DetectTlsVersionTestParse01); From a8975c68e0354a51bfa44e30845e14619224c9dc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 10:32:00 +0100 Subject: [PATCH 2409/2553] detect ssl/tls: use dynamic lists --- src/detect-ssl-state.c | 45 +++++++++++++++++++++++++++++++++------- src/detect-ssl-version.c | 18 +++++++++------- src/detect-tls-version.c | 18 +++++++++------- 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 9cb9c7bc2b4f..88394b579fd2 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -60,26 +60,55 @@ static pcre *parse_regex2; static pcre_extra *parse_regex2_study; static int DetectSslStateMatch(ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, void *, - const Signature *, const SigMatchData *); + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectSslStateSetup(DetectEngineCtx *, Signature *, char *); static void DetectSslStateRegisterTests(void); static void DetectSslStateFree(void *); +static int InspectTlsGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id); + +static int g_tls_generic_list_id = 0; + /** * \brief Registers the keyword handlers for the "ssl_state" keyword. */ void DetectSslStateRegister(void) { sigmatch_table[DETECT_AL_SSL_STATE].name = "ssl_state"; - sigmatch_table[DETECT_AL_SSL_STATE].Match = NULL; - sigmatch_table[DETECT_AL_SSL_STATE].AppLayerMatch = DetectSslStateMatch; + sigmatch_table[DETECT_AL_SSL_STATE].AppLayerTxMatch = DetectSslStateMatch; sigmatch_table[DETECT_AL_SSL_STATE].Setup = DetectSslStateSetup; sigmatch_table[DETECT_AL_SSL_STATE].Free = DetectSslStateFree; sigmatch_table[DETECT_AL_SSL_STATE].RegisterTests = DetectSslStateRegisterTests; DetectSetupParseRegexes(PARSE_REGEX1, &parse_regex1, &parse_regex1_study); DetectSetupParseRegexes(PARSE_REGEX2, &parse_regex2, &parse_regex2_study); + + g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); + + DetectBufferTypeSetDescriptionByName("tls_generic", + "generic ssl/tls inspection"); + + DetectAppLayerInspectEngineRegister("tls_generic", + ALPROTO_TLS, SIG_FLAG_TOSERVER, + InspectTlsGeneric); + DetectAppLayerInspectEngineRegister("tls_generic", + ALPROTO_TLS, SIG_FLAG_TOCLIENT, + InspectTlsGeneric); +} + +static int InspectTlsGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); } /** @@ -97,10 +126,10 @@ void DetectSslStateRegister(void) * \retval 0 No match. */ static int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *alstate, - const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, void *alstate, void *txv, + const Signature *s, const SigMatchCtx *m) { - const DetectSslStateData *ssd = (const DetectSslStateData *)m->ctx; + const DetectSslStateData *ssd = (const DetectSslStateData *)m; SSLState *ssl_state = (SSLState *)alstate; if (ssl_state == NULL) { SCLogDebug("no app state, no match"); @@ -298,7 +327,7 @@ static int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_tls_generic_list_id); return 0; diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index ea8f839c8538..661c6b89bf09 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -61,11 +61,12 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectSslVersionMatch(ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, void *, - const Signature *, const SigMatchData *); + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, char *); static void DetectSslVersionRegisterTests(void); static void DetectSslVersionFree(void *); +static int g_tls_generic_list_id = 0; /** * \brief Registration function for keyword: ssl_version @@ -73,13 +74,14 @@ static void DetectSslVersionFree(void *); void DetectSslVersionRegister(void) { sigmatch_table[DETECT_AL_SSL_VERSION].name = "ssl_version"; - sigmatch_table[DETECT_AL_SSL_VERSION].Match = NULL; - sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerMatch = DetectSslVersionMatch; + sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerTxMatch = DetectSslVersionMatch; sigmatch_table[DETECT_AL_SSL_VERSION].Setup = DetectSslVersionSetup; sigmatch_table[DETECT_AL_SSL_VERSION].Free = DetectSslVersionFree; sigmatch_table[DETECT_AL_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); } /** @@ -94,8 +96,8 @@ void DetectSslVersionRegister(void) * \retval 1 match */ static int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); @@ -103,7 +105,7 @@ static int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, uint16_t ver = 0; uint8_t sig_ver = TLS_UNKNOWN; - const DetectSslVersionData *ssl = (const DetectSslVersionData *)m->ctx; + const DetectSslVersionData *ssl = (const DetectSslVersionData *)m; SSLState *app_state = (SSLState *)state; if (app_state == NULL) { SCLogDebug("no app state, no match"); @@ -298,7 +300,7 @@ static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->type = DETECT_AL_SSL_VERSION; sm->ctx = (void *)ssl; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_tls_generic_list_id); s->alproto = ALPROTO_TLS; return 0; diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index ee7d2c1678d7..198bb6fae00c 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -60,11 +60,12 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectTlsVersionMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, void *, - const Signature *, const SigMatchData *); + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectTlsVersionSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsVersionRegisterTests(void); static void DetectTlsVersionFree(void *); +static int g_tls_generic_list_id = 0; /** * \brief Registration function for keyword: tls.version @@ -74,13 +75,14 @@ void DetectTlsVersionRegister (void) sigmatch_table[DETECT_AL_TLS_VERSION].name = "tls.version"; sigmatch_table[DETECT_AL_TLS_VERSION].desc = "match on TLS/SSL version"; sigmatch_table[DETECT_AL_TLS_VERSION].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsversion"; - sigmatch_table[DETECT_AL_TLS_VERSION].Match = NULL; - sigmatch_table[DETECT_AL_TLS_VERSION].AppLayerMatch = DetectTlsVersionMatch; + sigmatch_table[DETECT_AL_TLS_VERSION].AppLayerTxMatch = DetectTlsVersionMatch; sigmatch_table[DETECT_AL_TLS_VERSION].Setup = DetectTlsVersionSetup; sigmatch_table[DETECT_AL_TLS_VERSION].Free = DetectTlsVersionFree; sigmatch_table[DETECT_AL_TLS_VERSION].RegisterTests = DetectTlsVersionRegisterTests; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); } /** @@ -95,12 +97,12 @@ void DetectTlsVersionRegister (void) * \retval 1 match */ static int DetectTlsVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - const DetectTlsVersionData *tls_data = (const DetectTlsVersionData *)m->ctx; + const DetectTlsVersionData *tls_data = (const DetectTlsVersionData *)m; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -237,7 +239,7 @@ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->type = DETECT_AL_TLS_VERSION; sm->ctx = (void *)tls; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_tls_generic_list_id); s->alproto = ALPROTO_TLS; return 0; From 4ae4fd08024e2a5369cf785e8597a2afbd9a6bc2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 10:35:44 +0100 Subject: [PATCH 2410/2553] lua: use tls_generic list for ssl/tls --- src/detect-lua.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/detect-lua.c b/src/detect-lua.c index a58558943334..d3889d8e27e6 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1033,7 +1033,8 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) SigMatchAppendSMToList(s, sm, list); } } else if (lua->alproto == ALPROTO_TLS) { - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + int list = DetectBufferTypeGetByName("tls_generic"); + SigMatchAppendSMToList(s, sm, list); } else if (lua->alproto == ALPROTO_SSH) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); } else if (lua->alproto == ALPROTO_SMTP) { From 3ee4989ba7c10531d80e17e95bfa2d13951afc20 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 12:45:17 +0100 Subject: [PATCH 2411/2553] ssh: convert app-layer parser to be tx aware Like with SSL, there is only a single 'tx'. --- src/app-layer-ssh.c | 103 ++++++++++++++++++++++++++++++ src/app-layer-ssh.h | 15 ++++- src/detect-ssh-proto-version.c | 3 + src/detect-ssh-software-version.c | 3 + src/output-json-ssh.c | 83 ++++++------------------ 5 files changed, 141 insertions(+), 66 deletions(-) diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index 7eb529407d7f..0b965eb74810 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -494,9 +494,96 @@ static void SSHStateFree(void *state) if (s->srv_hdr.banner_buffer != NULL) SCFree(s->srv_hdr.banner_buffer); + //AppLayerDecoderEventsFreeEvents(&s->decoder_events); + + if (s->de_state != NULL) { + DetectEngineStateFree(s->de_state); + } + SCFree(s); } +static int SSHStateHasTxDetectState(void *state) +{ + SshState *ssh_state = (SshState *)state; + if (ssh_state->de_state) + return 1; + return 0; +} + +static int SSHSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + SshState *ssh_state = (SshState *)state; + ssh_state->de_state = de_state; + return 0; +} + +static DetectEngineState *SSHGetTxDetectState(void *vtx) +{ + SshState *ssh_state = (SshState *)vtx; + return ssh_state->de_state; +} + +static void SSHStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static void *SSHGetTx(void *state, uint64_t tx_id) +{ + SshState *ssh_state = (SshState *)state; + return ssh_state; +} + +static uint64_t SSHGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +static void SSHSetTxLogged(void *state, void *tx, uint32_t logger) +{ + SshState *ssh_state = (SshState *)state; + if (ssh_state) + ssh_state->logged |= logger; +} + +static int SSHGetTxLogged(void *state, void *tx, uint32_t logger) +{ + SshState *ssh_state = (SshState *)state; + if (ssh_state && (ssh_state->logged & logger)) { + return 1; + } + return 0; +} + +static int SSHGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return SSH_STATE_FINISHED; +} + +static int SSHGetAlstateProgress(void *tx, uint8_t direction) +{ + SshState *ssh_state = (SshState *)tx; + + if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE && + ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) { + return SSH_STATE_FINISHED; + } + + if (direction == STREAM_TOSERVER) { + if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE) { + return SSH_STATE_BANNER_DONE; + } + } else { + if (ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) { + return SSH_STATE_BANNER_DONE; + } + } + + return SSH_STATE_IN_PROGRESS; +} + static int SSHRegisterPatternsForProtocolDetection(void) { if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH, @@ -532,6 +619,22 @@ void RegisterSSHParsers(void) AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateAlloc, SSHStateFree); AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_SSH, STREAM_TOSERVER|STREAM_TOCLIENT); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SSH, SSHStateTransactionFree); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateHasTxDetectState, + SSHGetTxDetectState, SSHSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SSH, SSHGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SSH, SSHGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SSH, SSHGetAlstateProgress); + + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHGetTxLogged, SSHSetTxLogged); + + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SSH, + SSHGetAlstateProgressCompletionStatus); } else { // SCLogInfo("Parsed disabled for %s protocol. Protocol detection" // "still on.", proto_name); diff --git a/src/app-layer-ssh.h b/src/app-layer-ssh.h index 4fd59aa9e1d7..bf8d50b94c93 100644 --- a/src/app-layer-ssh.h +++ b/src/app-layer-ssh.h @@ -32,8 +32,6 @@ * must be ciphered, so the parsing finish here */ #define SSH_FLAG_PARSER_DONE 0x02 -#define SSH_FLAG_STATE_LOGGED 0x04 - #define SSH_FLAG_STATE_LOGGED_LUA 0x08 /* MSG_CODE */ @@ -56,6 +54,7 @@ typedef struct SshHeader_ { uint32_t pkt_len; uint8_t padding_len; uint8_t msg_code; + uint16_t banner_len; uint8_t buf[6]; uint8_t buf_offset; uint8_t flags; @@ -63,13 +62,23 @@ typedef struct SshHeader_ { uint8_t *proto_version; uint8_t *software_version; uint8_t *banner_buffer; - uint16_t banner_len; } SshHeader; +enum { + SSH_STATE_IN_PROGRESS, + SSH_STATE_BANNER_DONE, + SSH_STATE_FINISHED, +}; + /** structure to store the SSH state values */ typedef struct SshState_ { SshHeader srv_hdr; SshHeader cli_hdr; + + /* specifies which loggers are done logging */ + uint32_t logged; + + DetectEngineState *de_state; } SshState; void RegisterSSHParsers(void); diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index 322a9137fbf7..96b8c40ec5ca 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -360,6 +360,7 @@ static int DetectSshVersionTestDetect01(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -477,6 +478,7 @@ static int DetectSshVersionTestDetect02(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -592,6 +594,7 @@ static int DetectSshVersionTestDetect03(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index a9eb19267d27..3032b0e6bf37 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -332,6 +332,7 @@ static int DetectSshSoftwareVersionTestDetect01(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -449,6 +450,7 @@ static int DetectSshSoftwareVersionTestDetect02(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -565,6 +567,7 @@ static int DetectSshSoftwareVersionTestDetect03(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 627b2b6f598e..6d356a0024b3 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -89,36 +89,29 @@ void JsonSshLogJSON(json_t *tjs, SshState *ssh_state) } -static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) +static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p, + Flow *f, void *state, void *txptr, uint64_t tx_id) { JsonSshLogThread *aft = (JsonSshLogThread *)thread_data; OutputSshCtx *ssh_ctx = aft->sshlog_ctx; - if (unlikely(p->flow == NULL)) { - return 0; - } - - /* check if we have SSH state or not */ - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_SSH) - goto end; - - SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); + SshState *ssh_state = (SshState *)state; if (unlikely(ssh_state == NULL)) { - goto end; + return 0; } - if (ssh_state->cli_hdr.software_version == NULL || ssh_state->srv_hdr.software_version == NULL) - goto end; + if (ssh_state->cli_hdr.software_version == NULL || + ssh_state->srv_hdr.software_version == NULL) + return 0; json_t *js = CreateJSONHeader((Packet *)p, 1, "ssh");//TODO if (unlikely(js == NULL)) - goto end; + return 0; json_t *tjs = json_object(); if (tjs == NULL) { free(js); - goto end; + return 0; } /* reset */ @@ -132,9 +125,6 @@ static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) json_object_clear(js); json_decref(js); - /* we only log the state once */ - ssh_state->cli_hdr.flags |= SSH_FLAG_STATE_LOGGED; -end: return 0; } @@ -230,6 +220,7 @@ OutputCtx *OutputSshLogInit(ConfNode *conf) output_ctx->data = ssh_ctx; output_ctx->DeInit = OutputSshLogDeinit; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH); return output_ctx; } @@ -267,58 +258,24 @@ OutputCtx *OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) output_ctx->data = ssh_ctx; output_ctx->DeInit = OutputSshLogDeinitSub; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH); return output_ctx; } -/** \internal - * \brief Condition function for SSH logger - * \retval bool true or false -- log now? - */ -static int JsonSshCondition(ThreadVars *tv, const Packet *p) -{ - if (p->flow == NULL) { - return FALSE; - } - - if (!(PKT_IS_TCP(p))) { - return FALSE; - } - - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_SSH) - goto dontlog; - - SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); - if (ssh_state == NULL) { - SCLogDebug("no ssh state, so no logging"); - goto dontlog; - } - - /* we only log the state once */ - if (ssh_state->cli_hdr.flags & SSH_FLAG_STATE_LOGGED) - goto dontlog; - - if (ssh_state->cli_hdr.software_version == NULL || - ssh_state->srv_hdr.software_version == NULL) - goto dontlog; - - /* todo: logic to log once */ - - return TRUE; -dontlog: - return FALSE; -} - void JsonSshLogRegister (void) { /* register as separate module */ - OutputRegisterPacketModule(LOGGER_JSON_SSH, "JsonSshLog", "ssh-json-log", - OutputSshLogInit, JsonSshLogger, JsonSshCondition, JsonSshLogThreadInit, - JsonSshLogThreadDeinit, NULL); + OutputRegisterTxModuleWithProgress(LOGGER_JSON_SSH, + "JsonSshLog", "ssh-json-log", + OutputSshLogInit, ALPROTO_SSH, JsonSshLogger, + SSH_STATE_BANNER_DONE, SSH_STATE_BANNER_DONE, + JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterPacketSubModule(LOGGER_JSON_SSH, "eve-log", "JsonSshLog", - "eve-log.ssh", OutputSshLogInitSub, JsonSshLogger, JsonSshCondition, + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_SSH, + "eve-log", "JsonSshLog", "eve-log.ssh", + OutputSshLogInitSub, ALPROTO_SSH, JsonSshLogger, + SSH_STATE_BANNER_DONE, SSH_STATE_BANNER_DONE, JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL); } From c412352474e64b6e5ea4eb3d9d413ab54e44ae26 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 12:48:59 +0100 Subject: [PATCH 2412/2553] ssh: remove single logger limit --- src/output-json-ssh.c | 16 ---------------- src/output.c | 16 ---------------- src/output.h | 3 --- 3 files changed, 35 deletions(-) diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 6d356a0024b3..db3c8ed0283e 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -173,8 +173,6 @@ static TmEcode JsonSshLogThreadDeinit(ThreadVars *t, void *data) static void OutputSshLogDeinit(OutputCtx *output_ctx) { - OutputSshLoggerDisable(); - OutputSshCtx *ssh_ctx = output_ctx->data; LogFileCtx *logfile_ctx = ssh_ctx->file_ctx; LogFileFreeCtx(logfile_ctx); @@ -185,12 +183,6 @@ static void OutputSshLogDeinit(OutputCtx *output_ctx) #define DEFAULT_LOG_FILENAME "ssh.json" OutputCtx *OutputSshLogInit(ConfNode *conf) { - if (OutputSshLoggerEnable() != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'ssh' logger " - "can be enabled"); - return NULL; - } - LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { SCLogError(SC_ERR_SSH_LOG_GENERIC, "couldn't create new file_ctx"); @@ -226,8 +218,6 @@ OutputCtx *OutputSshLogInit(ConfNode *conf) static void OutputSshLogDeinitSub(OutputCtx *output_ctx) { - OutputSshLoggerDisable(); - OutputSshCtx *ssh_ctx = output_ctx->data; SCFree(ssh_ctx); SCFree(output_ctx); @@ -237,12 +227,6 @@ OutputCtx *OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { OutputJsonCtx *ojc = parent_ctx->data; - if (OutputSshLoggerEnable() != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'ssh' logger " - "can be enabled"); - return NULL; - } - OutputSshCtx *ssh_ctx = SCMalloc(sizeof(OutputSshCtx)); if (unlikely(ssh_ctx == NULL)) return NULL; diff --git a/src/output.c b/src/output.c index befdc58d2a37..7c8c5aaca0e7 100644 --- a/src/output.c +++ b/src/output.c @@ -849,22 +849,6 @@ void OutputDropLoggerDisable(void) drop_loggers--; } -static int ssh_loggers = 0; - -int OutputSshLoggerEnable(void) -{ - if (ssh_loggers) - return -1; - ssh_loggers++; - return 0; -} - -void OutputSshLoggerDisable(void) -{ - if (ssh_loggers) - ssh_loggers--; -} - /** * \brief Register a flag for file rotation notification. * diff --git a/src/output.h b/src/output.h index 32004a69691d..59469f4ae653 100644 --- a/src/output.h +++ b/src/output.h @@ -184,9 +184,6 @@ void OutputDeregisterAll(void); int OutputDropLoggerEnable(void); void OutputDropLoggerDisable(void); -int OutputSshLoggerEnable(void); -void OutputSshLoggerDisable(void); - void OutputRegisterFileRotationFlag(int *flag); void OutputUnregisterFileRotationFlag(int *flag); void OutputNotifyFileRotation(void); From a10b2fdecfee1a92fdbaa170cc1d53730a1ade3d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 13:07:06 +0100 Subject: [PATCH 2413/2553] detect: make ssh detection use dynamic list --- src/detect-lua.c | 3 +- src/detect-ssh-proto-version.c | 32 +++++++++-------- src/detect-ssh-software-version.c | 60 +++++++++++++++++++------------ src/detect-ssh-software-version.h | 1 - 4 files changed, 57 insertions(+), 39 deletions(-) diff --git a/src/detect-lua.c b/src/detect-lua.c index d3889d8e27e6..4d80841623a2 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1036,7 +1036,8 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) int list = DetectBufferTypeGetByName("tls_generic"); SigMatchAppendSMToList(s, sm, list); } else if (lua->alproto == ALPROTO_SSH) { - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + int list = DetectBufferTypeGetByName("ssh_banner"); + SigMatchAppendSMToList(s, sm, list); } else if (lua->alproto == ALPROTO_SMTP) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); } else if (lua->alproto == ALPROTO_DNP3) { diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index 96b8c40ec5ca..ebf8ce0c645f 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -63,11 +63,12 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectSshVersionMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, void *, - const Signature *, const SigMatchData *); + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectSshVersionSetup (DetectEngineCtx *, Signature *, char *); -void DetectSshVersionRegisterTests(void); -void DetectSshVersionFree(void *); +static void DetectSshVersionRegisterTests(void); +static void DetectSshVersionFree(void *); +static int g_ssh_banner_list_id = 0; /** * \brief Registration function for keyword: ssh.protoversion @@ -75,13 +76,14 @@ void DetectSshVersionFree(void *); void DetectSshVersionRegister(void) { sigmatch_table[DETECT_AL_SSH_PROTOVERSION].name = "ssh.protoversion"; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Match = NULL; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].AppLayerMatch = DetectSshVersionMatch; + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].AppLayerTxMatch = DetectSshVersionMatch; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Setup = DetectSshVersionSetup; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Free = DetectSshVersionFree; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].RegisterTests = DetectSshVersionRegisterTests; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + g_ssh_banner_list_id = DetectBufferTypeRegister("ssh_banner"); } /** @@ -96,12 +98,12 @@ void DetectSshVersionRegister(void) * \retval 1 match */ static int DetectSshVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectSshVersionData *ssh = (DetectSshVersionData *)m->ctx; + DetectSshVersionData *ssh = (DetectSshVersionData *)m; SshState *ssh_state = (SshState *)state; if (ssh_state == NULL) { SCLogDebug("no ssh state, no match"); @@ -215,6 +217,11 @@ static int DetectSshVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectSshVersionData *ssh = NULL; SigMatch *sm = NULL; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + return -1; + } + ssh = DetectSshVersionParse(str); if (ssh == NULL) goto error; @@ -225,15 +232,10 @@ static int DetectSshVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - sm->type = DETECT_AL_SSH_PROTOVERSION; sm->ctx = (void *)ssh; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_ssh_banner_list_id); s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_SSH; diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index 3032b0e6bf37..7ab8ecffcab8 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -67,12 +67,22 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectSshSoftwareVersionMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, void *, - const Signature *, const SigMatchData *); + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectSshSoftwareVersionSetup (DetectEngineCtx *, Signature *, char *); -void DetectSshSoftwareVersionRegisterTests(void); -void DetectSshSoftwareVersionFree(void *); -void DetectSshSoftwareVersionRegister(void); +static void DetectSshSoftwareVersionRegisterTests(void); +static void DetectSshSoftwareVersionFree(void *); +static int g_ssh_banner_list_id = 0; + +static int InspectSshBanner(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} /** * \brief Registration function for keyword: ssh.softwareversion @@ -80,13 +90,19 @@ void DetectSshSoftwareVersionRegister(void); void DetectSshSoftwareVersionRegister(void) { sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].name = "ssh.softwareversion"; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Match = NULL; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].AppLayerMatch = DetectSshSoftwareVersionMatch; + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].AppLayerTxMatch = DetectSshSoftwareVersionMatch; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Setup = DetectSshSoftwareVersionSetup; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Free = DetectSshSoftwareVersionFree; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].RegisterTests = DetectSshSoftwareVersionRegisterTests; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + g_ssh_banner_list_id = DetectBufferTypeRegister("ssh_banner"); + + DetectAppLayerInspectEngineRegister("ssh_banner", + ALPROTO_SSH, SIG_FLAG_TOSERVER, InspectSshBanner); + DetectAppLayerInspectEngineRegister("ssh_banner", + ALPROTO_SSH, SIG_FLAG_TOCLIENT, InspectSshBanner); } /** @@ -101,12 +117,12 @@ void DetectSshSoftwareVersionRegister(void) * \retval 1 match */ static int DetectSshSoftwareVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)m->ctx; + DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)m; SshState *ssh_state = (SshState *)state; if (ssh_state == NULL) { SCLogDebug("no ssh state, no match"); @@ -196,6 +212,11 @@ static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, DetectSshSoftwareVersionData *ssh = NULL; SigMatch *sm = NULL; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + return -1; + } + ssh = DetectSshSoftwareVersionParse(str); if (ssh == NULL) goto error; @@ -206,18 +227,13 @@ static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - sm->type = DETECT_AL_SSH_SOFTWAREVERSION; sm->ctx = (void *)ssh; s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_SSH; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_ssh_banner_list_id); return 0; @@ -235,7 +251,7 @@ static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, * * \param id_d pointer to DetectSshSoftwareVersionData */ -void DetectSshSoftwareVersionFree(void *ptr) +static void DetectSshSoftwareVersionFree(void *ptr) { if (ptr == NULL) return; @@ -252,7 +268,7 @@ void DetectSshSoftwareVersionFree(void *ptr) * \test DetectSshSoftwareVersionTestParse01 is a test to make sure that we parse * a software version correctly */ -int DetectSshSoftwareVersionTestParse01 (void) +static int DetectSshSoftwareVersionTestParse01 (void) { DetectSshSoftwareVersionData *ssh = NULL; ssh = DetectSshSoftwareVersionParse("PuTTY_1.0"); @@ -268,7 +284,7 @@ int DetectSshSoftwareVersionTestParse01 (void) * \test DetectSshSoftwareVersionTestParse02 is a test to make sure that we parse * the software version correctly */ -int DetectSshSoftwareVersionTestParse02 (void) +static int DetectSshSoftwareVersionTestParse02 (void) { DetectSshSoftwareVersionData *ssh = NULL; ssh = DetectSshSoftwareVersionParse("\"SecureCRT-4.0\""); @@ -284,7 +300,7 @@ int DetectSshSoftwareVersionTestParse02 (void) * \test DetectSshSoftwareVersionTestParse03 is a test to make sure that we * don't return a ssh_data with an empty value specified */ -int DetectSshSoftwareVersionTestParse03 (void) +static int DetectSshSoftwareVersionTestParse03 (void) { DetectSshSoftwareVersionData *ssh = NULL; ssh = DetectSshSoftwareVersionParse(""); @@ -656,7 +672,7 @@ static int DetectSshSoftwareVersionTestDetect03(void) /** * \brief this function registers unit tests for DetectSshSoftwareVersion */ -void DetectSshSoftwareVersionRegisterTests(void) +static void DetectSshSoftwareVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectSshSoftwareVersionTestParse01", diff --git a/src/detect-ssh-software-version.h b/src/detect-ssh-software-version.h index 70c37c745f91..7cf311167731 100644 --- a/src/detect-ssh-software-version.h +++ b/src/detect-ssh-software-version.h @@ -31,7 +31,6 @@ typedef struct DetectSshSoftwareVersionData_ { /* prototypes */ void DetectSshSoftwareVersionRegister(void); -void DetectSshSoftwareVersionRegisterTests(void); #endif /* __DETECT_SSH_SOFTWARE_VERSION_H__ */ From 96b8100a511b7abeca5a2b801ba26e8a7daef892 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 13:29:07 +0100 Subject: [PATCH 2414/2553] lua: convert lua output to be tx aware --- src/app-layer-ssh.h | 2 -- src/output-lua.c | 81 +++------------------------------------------ 2 files changed, 4 insertions(+), 79 deletions(-) diff --git a/src/app-layer-ssh.h b/src/app-layer-ssh.h index bf8d50b94c93..7fa368812b95 100644 --- a/src/app-layer-ssh.h +++ b/src/app-layer-ssh.h @@ -32,8 +32,6 @@ * must be ciphered, so the parsing finish here */ #define SSH_FLAG_PARSER_DONE 0x02 -#define SSH_FLAG_STATE_LOGGED_LUA 0x08 - /* MSG_CODE */ #define SSH_MSG_NEWKEYS 21 diff --git a/src/output-lua.c b/src/output-lua.c index d9a6dc497a07..081a0bd4417f 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -236,81 +236,6 @@ static int LuaPacketConditionAlerts(ThreadVars *tv, const Packet *p) return FALSE; } -/** \internal - * \brief Packet Logger for lua scripts, for ssh - * - * A single call to this function will run one script for a single - * packet. If it is called, it means that the registered condition - * function has returned TRUE. - * - * The script is called once for each packet. - */ -static int LuaPacketLoggerSsh(ThreadVars *tv, void *thread_data, const Packet *p) -{ - LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data; - - char timebuf[64]; - CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); - - SCMutexLock(&td->lua_ctx->m); - - lua_getglobal(td->lua_ctx->luastate, "log"); - - LuaStateSetThreadVars(td->lua_ctx->luastate, tv); - LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); - LuaStateSetFlow(td->lua_ctx->luastate, p->flow); - - int retval = lua_pcall(td->lua_ctx->luastate, 0, 0, 0); - if (retval != 0) { - SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1)); - } - - SCMutexUnlock(&td->lua_ctx->m); - - SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); - if (ssh_state != NULL) - ssh_state->cli_hdr.flags |= SSH_FLAG_STATE_LOGGED_LUA; - - SCReturnInt(0); -} - -static int LuaPacketConditionSsh(ThreadVars *tv, const Packet *p) -{ - if (p->flow == NULL) { - return FALSE; - } - - if (!(PKT_IS_IPV4(p)) && !(PKT_IS_IPV6(p))) { - return FALSE; - } - - if (!(PKT_IS_TCP(p))) { - return FALSE; - } - - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_SSH) - goto dontlog; - - SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); - if (ssh_state == NULL) { - SCLogDebug("no ssh state, so no request logging"); - goto dontlog; - } - - if (ssh_state->cli_hdr.software_version == NULL || - ssh_state->srv_hdr.software_version == NULL) - goto dontlog; - - /* We only log the state once */ - if (ssh_state->cli_hdr.flags & SSH_FLAG_STATE_LOGGED_LUA) - goto dontlog; - - return TRUE; -dontlog: - return FALSE; -} - /** \internal * \brief Packet Logger for lua scripts, for packets * @@ -883,8 +808,10 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNS); AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); } else if (opts.alproto == ALPROTO_SSH) { - om->PacketLogFunc = LuaPacketLoggerSsh; - om->PacketConditionFunc = LuaPacketConditionSsh; + om->TxLogFunc = LuaTxLogger; + om->alproto = ALPROTO_SSH; + om->tc_log_progress = SSH_STATE_BANNER_DONE; + om->ts_log_progress = SSH_STATE_BANNER_DONE; } else if (opts.alproto == ALPROTO_SMTP) { om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_SMTP; From d9a300cd8c002d1cdfca1d5868cfe06bc2be1179 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 14:48:53 +0100 Subject: [PATCH 2415/2553] detect: move lua smtp support to dynamic list --- src/detect-lua.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/detect-lua.c b/src/detect-lua.c index 4d80841623a2..8c9a4070ff2d 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -98,6 +98,13 @@ static int DetectLuaAppTxMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, static int DetectLuaSetup (DetectEngineCtx *, Signature *, char *); static void DetectLuaRegisterTests(void); static void DetectLuaFree(void *); +static int g_smtp_generic_list_id = 0; + +static int InspectSmtpGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id); /** * \brief Registration function for keyword: lua @@ -115,10 +122,29 @@ void DetectLuaRegister(void) sigmatch_table[DETECT_LUA].Free = DetectLuaFree; sigmatch_table[DETECT_LUA].RegisterTests = DetectLuaRegisterTests; + g_smtp_generic_list_id = DetectBufferTypeRegister("smtp_generic"); + + DetectAppLayerInspectEngineRegister("smtp_generic", + ALPROTO_SMTP, SIG_FLAG_TOSERVER, + InspectSmtpGeneric); + DetectAppLayerInspectEngineRegister("smtp_generic", + ALPROTO_SMTP, SIG_FLAG_TOCLIENT, + InspectSmtpGeneric); + SCLogDebug("registering lua rule option"); return; } +static int InspectSmtpGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} + #define DATATYPE_PACKET (1<<0) #define DATATYPE_PAYLOAD (1<<1) #define DATATYPE_STREAM (1<<2) @@ -1039,7 +1065,7 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) int list = DetectBufferTypeGetByName("ssh_banner"); SigMatchAppendSMToList(s, sm, list); } else if (lua->alproto == ALPROTO_SMTP) { - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_smtp_generic_list_id); } else if (lua->alproto == ALPROTO_DNP3) { int list = DetectBufferTypeGetByName("dnp3"); SigMatchAppendSMToList(s, sm, list); From 402eb645a00ca0063b95eb7558a981ae8a5f12c9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 15:21:32 +0100 Subject: [PATCH 2416/2553] ftp: parser and ftpbounce update Convert parser to TX API. Convert ftpbounce keyword to use that. --- src/app-layer-ftp.c | 79 +++++++++++++++++++++++++++++++++++++++++ src/app-layer-ftp.h | 11 ++++++ src/detect-ftpbounce.c | 80 ++++++++++++++++++++++++------------------ 3 files changed, 136 insertions(+), 34 deletions(-) diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index 974ec2e561bb..7bdd40436934 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -303,6 +303,13 @@ static void FTPStateFree(void *s) SCFree(fstate->line_state[0].db); if (fstate->line_state[1].db) SCFree(fstate->line_state[1].db); + + //AppLayerDecoderEventsFreeEvents(&s->decoder_events); + + if (fstate->de_state != NULL) { + DetectEngineStateFree(fstate->de_state); + } + SCFree(s); #ifdef DEBUG SCMutexLock(&ftp_state_mem_lock); @@ -312,6 +319,64 @@ static void FTPStateFree(void *s) #endif } +static int FTPStateHasTxDetectState(void *state) +{ + FtpState *ssh_state = (FtpState *)state; + if (ssh_state->de_state) + return 1; + return 0; +} + +static int FTPSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + FtpState *ssh_state = (FtpState *)state; + ssh_state->de_state = de_state; + return 0; +} + +static DetectEngineState *FTPGetTxDetectState(void *vtx) +{ + FtpState *ssh_state = (FtpState *)vtx; + return ssh_state->de_state; +} + +static void FTPStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static void *FTPGetTx(void *state, uint64_t tx_id) +{ + FtpState *ssh_state = (FtpState *)state; + return ssh_state; +} + +static uint64_t FTPGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +static int FTPGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return FTP_STATE_FINISHED; +} + +static int FTPGetAlstateProgress(void *tx, uint8_t direction) +{ + FtpState *ftp_state = (FtpState *)tx; + + if (direction == STREAM_TOSERVER && + ftp_state->command == FTP_COMMAND_PORT) { + return FTP_STATE_PORT_DONE; + } + + /* TODO: figure out further progress handling */ + + return FTP_STATE_IN_PROGRESS; +} + + static int FTPRegisterPatternsForProtocolDetection(void) { if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_FTP, @@ -351,6 +416,20 @@ void RegisterFTPParsers(void) FTPParseResponse); AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateAlloc, FTPStateFree); AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOSERVER | STREAM_TOCLIENT); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTP, FTPStateTransactionFree); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateHasTxDetectState, + FTPGetTxDetectState, FTPSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTP, FTPGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress); + + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_FTP, + FTPGetAlstateProgressCompletionStatus); } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); diff --git a/src/app-layer-ftp.h b/src/app-layer-ftp.h index 4a001290d554..de93f5f77398 100644 --- a/src/app-layer-ftp.h +++ b/src/app-layer-ftp.h @@ -24,6 +24,12 @@ #ifndef __APP_LAYER_FTP_H__ #define __APP_LAYER_FTP_H__ +enum { + FTP_STATE_IN_PROGRESS, + FTP_STATE_PORT_DONE, + FTP_STATE_FINISHED, +}; + typedef enum { FTP_COMMAND_UNKNOWN = 0, FTP_COMMAND_ABOR, @@ -123,6 +129,11 @@ typedef struct FtpState_ { uint32_t port_line_len; uint32_t port_line_size; uint8_t *port_line; + + /* specifies which loggers are done logging */ + uint32_t logged; + + DetectEngineState *de_state; } FtpState; void RegisterFTPParsers(void); diff --git a/src/detect-ftpbounce.c b/src/detect-ftpbounce.c index 7895c854fb86..0e2c2a07b583 100644 --- a/src/detect-ftpbounce.c +++ b/src/detect-ftpbounce.c @@ -47,13 +47,19 @@ #include "stream-tcp.h" #include "util-byte.h" -static int DetectFtpbounceALMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, const Signature *, const SigMatchData *); +static int DetectFtpbounceALMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); + static int DetectFtpbounceSetup(DetectEngineCtx *, Signature *, char *); -static int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, - uint32_t ip_orig, uint16_t offset); -void DetectFtpbounceRegisterTests(void); -void DetectFtpbounceFree(void *); +static void DetectFtpbounceRegisterTests(void); +static int g_ftp_request_list_id = 0; + +static int InspectFtpRequest(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id); /** * \brief Registration function for ftpbounce: keyword @@ -63,12 +69,24 @@ void DetectFtpbounceRegister(void) { sigmatch_table[DETECT_FTPBOUNCE].name = "ftpbounce"; sigmatch_table[DETECT_FTPBOUNCE].Setup = DetectFtpbounceSetup; - sigmatch_table[DETECT_FTPBOUNCE].Match = NULL; - sigmatch_table[DETECT_FTPBOUNCE].AppLayerMatch = DetectFtpbounceALMatch; - sigmatch_table[DETECT_FTPBOUNCE].Free = NULL; + sigmatch_table[DETECT_FTPBOUNCE].AppLayerTxMatch = DetectFtpbounceALMatch; sigmatch_table[DETECT_FTPBOUNCE].RegisterTests = DetectFtpbounceRegisterTests; sigmatch_table[DETECT_FTPBOUNCE].flags = SIGMATCH_NOOPT; - return; + + g_ftp_request_list_id = DetectBufferTypeRegister("ftp_request"); + + DetectAppLayerInspectEngineRegister("ftp_request", + ALPROTO_FTP, SIG_FLAG_TOSERVER, InspectFtpRequest); +} + +static int InspectFtpRequest(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); } /** @@ -167,18 +185,19 @@ static int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, * \retval 1 match */ static int DetectFtpbounceALMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, const Signature *s, - const SigMatchData *m) + Flow *f, uint8_t flags, + void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - FtpState *ftp_state =(FtpState *)state; + + FtpState *ftp_state = (FtpState *)state; if (ftp_state == NULL) { SCLogDebug("no ftp state, no match"); SCReturnInt(0); } int ret = 0; - if (ftp_state->command == FTP_COMMAND_PORT) { ret = DetectFtpbounceMatchArgs(ftp_state->port_line, ftp_state->port_line_len, f->src.address.address_un_data32[0], @@ -206,9 +225,14 @@ int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, char *ftpbounces SigMatch *sm = NULL; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_FTP) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + return -1; + } + sm = SigMatchAlloc(); if (sm == NULL) { - goto error;; + return -1; } sm->type = DETECT_FTPBOUNCE; @@ -224,22 +248,11 @@ int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, char *ftpbounces */ sm->ctx = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_FTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_ftp_request_list_id); s->alproto = ALPROTO_FTP; s->flags |= SIG_FLAG_APPLAYER; SCReturnInt(0); - -error: - if (sm != NULL) { - SigMatchFree(sm); - } - SCReturnInt(-1); } #ifdef UNITTESTS @@ -247,20 +260,19 @@ int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, char *ftpbounces /** * \test DetectFtpbounceTestSetup01 is a test for the Setup ftpbounce */ -int DetectFtpbounceTestSetup01(void) +static int DetectFtpbounceTestSetup01(void) { - int res = 0; DetectEngineCtx *de_ctx = NULL; Signature *s = SigAlloc(); - if (s == NULL) - return 0; + FAIL_IF (s == NULL); /* ftpbounce doesn't accept options so the str is NULL */ - res = !DetectFtpbounceSetup(de_ctx, s, NULL); - res &= s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL && s->sm_lists[DETECT_SM_LIST_AMATCH]->type & DETECT_FTPBOUNCE; + FAIL_IF_NOT(DetectFtpbounceSetup(de_ctx, s, NULL) == 0); + FAIL_IF(s->sm_lists[g_ftp_request_list_id] == NULL); + FAIL_IF_NOT(s->sm_lists[g_ftp_request_list_id]->type & DETECT_FTPBOUNCE); SigFree(s); - return res; + PASS; } #include "stream-tcp-reassemble.h" From d318bfc934da5d28bf1b71c159416869c9e7202a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 16:55:43 +0100 Subject: [PATCH 2417/2553] dcerpc: simplify common detect code --- src/app-layer-smb.c | 10 ++--- src/app-layer-smb.h | 3 +- src/detect-dce-iface.c | 20 ++++++++- src/detect-dce-iface.h | 4 ++ src/detect-dce-opnum.c | 3 +- src/detect-engine-dcepayload.c | 4 +- src/detect-engine-state.c | 75 ++++++++-------------------------- 7 files changed, 52 insertions(+), 67 deletions(-) diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index e5c6c10afb24..32ca196a304b 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -670,7 +670,7 @@ static int32_t DataParser(void *smb_state, AppLayerParserState *pstate, int32_t parsed = 0; if (sstate->andx.paddingparsed) { - parsed = DCERPCParser(&sstate->dcerpc, input, input_len); + parsed = DCERPCParser(&sstate->ds.dcerpc, input, input_len); if (parsed == -1 || parsed > sstate->bytecount.bytecountleft || parsed > (int32_t)input_len) { SCReturnInt(-1); } else { @@ -1435,7 +1435,7 @@ static void *SMBStateAlloc(void) SCReturnPtr(NULL, "void"); } - DCERPCInit(&s->dcerpc); + DCERPCInit(&s->ds.dcerpc); SCReturnPtr(s, "void"); } @@ -1448,7 +1448,7 @@ static void SMBStateFree(void *s) SCEnter(); SMBState *sstate = (SMBState *) s; - DCERPCCleanup(&sstate->dcerpc); + DCERPCCleanup(&sstate->ds.dcerpc); SCFree(s); SCReturn; @@ -1705,7 +1705,7 @@ int SMBParserTest02(void) goto end; } - printUUID("BIND", smb_state->dcerpc.dcerpcbindbindack.uuid_entry); + printUUID("BIND", smb_state->ds.dcerpc.dcerpcbindbindack.uuid_entry); result = 1; end: if (alp_tctx != NULL) @@ -2012,7 +2012,7 @@ int SMBParserTest03(void) goto end; } FLOWLOCK_UNLOCK(&f); - printUUID("BIND", smb_state->dcerpc.dcerpcbindbindack.uuid_entry); + printUUID("BIND", smb_state->ds.dcerpc.dcerpcbindbindack.uuid_entry); result = 1; end: if (alp_tctx != NULL) diff --git a/src/app-layer-smb.h b/src/app-layer-smb.h index 48d4fa84308a..8e7ec4fadcb0 100644 --- a/src/app-layer-smb.h +++ b/src/app-layer-smb.h @@ -30,6 +30,7 @@ #include "stream.h" #include "app-layer-nbss.h" #include "app-layer-dcerpc-common.h" +#include "app-layer-dcerpc.h" typedef struct SMBHdr_ { uint8_t protocol[4]; @@ -83,7 +84,7 @@ typedef struct SMBState_ { SMBWordCount wordcount; SMBByteCount bytecount; SMBAndX andx; - DCERPC dcerpc; + DCERPCState ds; uint8_t dcerpc_present; uint8_t data_needed_for_dir; } SMBState; diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 8bdf278f6aaf..5daf7e814fc5 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -229,6 +229,24 @@ static inline int DetectDceIfaceMatchIfaceVersion(uint16_t version, } } +#include "app-layer-smb.h" +DCERPCState *DetectDceGetState(AppProto alproto, void *alstate) +{ + switch(alproto) { + case ALPROTO_DCERPC: + return alstate; + case ALPROTO_SMB: { + SMBState *smb_state = (SMBState *)alstate; + return &smb_state->ds; + } + case ALPROTO_SMB2: + // not implemented + return NULL; + } + + return NULL; +} + /** * \brief App layer match function for the "dce_iface" keyword. * @@ -253,7 +271,7 @@ static int DetectDceIfaceMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, DCERPCUuidEntry *item = NULL; int i = 0; DetectDceIfaceData *dce_data = (DetectDceIfaceData *)m->ctx; - DCERPCState *dcerpc_state = (DCERPCState *)state; + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); if (dcerpc_state == NULL) { SCLogDebug("No DCERPCState for the flow"); SCReturnInt(0); diff --git a/src/detect-dce-iface.h b/src/detect-dce-iface.h index 564cf5522c0a..3eb18b1c726b 100644 --- a/src/detect-dce-iface.h +++ b/src/detect-dce-iface.h @@ -24,6 +24,8 @@ #ifndef __DETECT_DCE_IFACE_H__ #define __DETECT_DCE_IFACE_H__ +#include "app-layer-dcerpc.h" + typedef enum DetectDceIfaceOperators_ { DETECT_DCE_IFACE_OP_NONE = 0, DETECT_DCE_IFACE_OP_LT, @@ -41,4 +43,6 @@ typedef struct DetectDceIfaceData_ { void DetectDceIfaceRegister(void); +DCERPCState *DetectDceGetState(AppProto alproto, void *alstate); + #endif /* __DETECT_DCE_IFACE_H__ */ diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 75b291a4d3eb..124b88aa3bda 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -41,6 +41,7 @@ #include "queue.h" #include "stream-tcp-reassemble.h" #include "detect-dce-opnum.h" +#include "detect-dce-iface.h" #include "util-debug.h" #include "util-unittest.h" @@ -247,7 +248,7 @@ static int DetectDceOpnumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, DetectDceOpnumData *dce_data = (DetectDceOpnumData *)m->ctx; DetectDceOpnumRange *dor = dce_data->range; - DCERPCState *dcerpc_state = (DCERPCState *)state; + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); if (dcerpc_state == NULL) { SCLogDebug("No DCERPCState for the flow"); SCReturnInt(0); diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index aa323d71ed40..cfb60a54fc1d 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -47,6 +47,8 @@ #include "util-unittest.h" #include "util-unittest-helper.h" +#include "detect-dce-iface.h" + /** * \brief Do the content inspection & validation for a signature against dce stub. * @@ -66,7 +68,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, Flow *f, uint8_t flags, void *alstate) { SCEnter(); - DCERPCState *dcerpc_state = (DCERPCState *)alstate; + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, alstate); uint8_t *dce_stub_data = NULL; uint16_t dce_stub_data_len; int r = 0; diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index b64aec418f2a..865d34668def 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -628,20 +628,10 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_DMATCH); - if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { - SMBState *smb_state = (SMBState *)alstate; - if (smb_state->dcerpc_present && - DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, - flags, &smb_state->dcerpc) == 1) { - inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; - dmatch = 1; - } - } else { - if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, - flags, alstate) == 1) { - inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; - dmatch = 1; - } + if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; + dmatch = 1; } } @@ -658,20 +648,10 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, while (1) { if (sigmatch_table[smd->type].AppLayerMatch != NULL) { int match = 0; - if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { - SMBState *smb_state = (SMBState *)alstate; - if (smb_state->dcerpc_present) { - KEYWORD_PROFILING_START; - match = sigmatch_table[smd->type]. - AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, smd); - KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); - } - } else { - KEYWORD_PROFILING_START; - match = sigmatch_table[smd->type]. - AppLayerMatch(tv, det_ctx, f, flags, alstate, s, smd); - KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); - } + KEYWORD_PROFILING_START; + match = sigmatch_table[smd->type]. + AppLayerMatch(tv, det_ctx, f, flags, alstate, s, smd); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); if (match == 0) { break; @@ -968,20 +948,10 @@ static int DoInspectFlowRule(ThreadVars *tv, while(1) { if (sigmatch_table[smd->type].AppLayerMatch != NULL) { int match = 0; - if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { - SMBState *smb_state = (SMBState *)alstate; - if (smb_state->dcerpc_present) { - KEYWORD_PROFILING_START; - match = sigmatch_table[smd->type]. - AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, smd); - KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); - } - } else { - KEYWORD_PROFILING_START; - match = sigmatch_table[smd->type]. - AppLayerMatch(tv, det_ctx, f, flags, alstate, s, smd); - KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); - } + KEYWORD_PROFILING_START; + match = sigmatch_table[smd->type]. + AppLayerMatch(tv, det_ctx, f, flags, alstate, s, smd); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); if (match == 0) break; @@ -1014,22 +984,11 @@ static int DoInspectFlowRule(ThreadVars *tv, void *alstate = FlowGetAppState(f); if (alstate != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_DMATCH); - if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { - SMBState *smb_state = (SMBState *)alstate; - if (smb_state->dcerpc_present && - DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, - flags, &smb_state->dcerpc) == 1) - { - total_matches++; - inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; - } - } else { - if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, - flags, alstate) == 1) - { - total_matches++; - inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; - } + if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, + flags, alstate) == 1) + { + total_matches++; + inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; } } } From 84ba9cf9df9b0693d02dd9f8199e8e71899c881c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 19:03:44 +0100 Subject: [PATCH 2418/2553] smb/dcerpc: use tx api --- src/app-layer-dcerpc.c | 67 ++++++++++++++++++++++++++++++++++++++ src/app-layer-dcerpc.h | 1 + src/app-layer-smb.c | 66 +++++++++++++++++++++++++++++++++++++ src/detect-dce-stub-data.c | 33 ++++--------------- src/detect-engine-state.c | 4 +-- 5 files changed, 142 insertions(+), 29 deletions(-) diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 407ed819f163..38416a50d86d 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -2018,9 +2018,61 @@ static void DCERPCStateFree(void *s) DCERPCCleanup(&sstate->dcerpc); + if (sstate->de_state != NULL) { + DetectEngineStateFree(sstate->de_state); + } + SCFree(s); } +static int DCERPCStateHasTxDetectState(void *state) +{ + DCERPCState *dce_state = (DCERPCState *)state; + if (dce_state->de_state) + return 1; + return 0; +} + +static int DCERPCSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + DCERPCState *dce_state = (DCERPCState *)state; + dce_state->de_state = de_state; + return 0; +} + +static DetectEngineState *DCERPCGetTxDetectState(void *vtx) +{ + DCERPCState *dce_state = (DCERPCState *)vtx; + return dce_state->de_state; +} + +static void DCERPCStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static void *DCERPCGetTx(void *state, uint64_t tx_id) +{ + DCERPCState *dce_state = (DCERPCState *)state; + return dce_state; +} + +static uint64_t DCERPCGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +static int DCERPCGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return 1; +} + +static int DCERPCGetAlstateProgress(void *tx, uint8_t direction) +{ + return 0; +} + static int DCERPCRegisterPatternsForProtocolDetection(void) { if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_DCERPC, @@ -2059,6 +2111,21 @@ void RegisterDCERPCParsers(void) AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCStateAlloc, DCERPCStateFree); AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_DCERPC, STREAM_TOSERVER); + + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCStateTransactionFree); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCStateHasTxDetectState, + DCERPCGetTxDetectState, DCERPCSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCGetAlstateProgress); + + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DCERPC, + DCERPCGetAlstateProgressCompletionStatus); } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); diff --git a/src/app-layer-dcerpc.h b/src/app-layer-dcerpc.h index db90461e044a..5a8410c761a8 100644 --- a/src/app-layer-dcerpc.h +++ b/src/app-layer-dcerpc.h @@ -34,6 +34,7 @@ typedef struct DCERPCState_ { DCERPC dcerpc; uint8_t data_needed_for_dir; + DetectEngineState *de_state; } DCERPCState; void DCERPCInit(DCERPC *dcerpc); diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 32ca196a304b..9c8031261f15 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -1450,10 +1450,62 @@ static void SMBStateFree(void *s) DCERPCCleanup(&sstate->ds.dcerpc); + if (sstate->ds.de_state) { + DetectEngineStateFree(sstate->ds.de_state); + } + SCFree(s); SCReturn; } +static int SMBStateHasTxDetectState(void *state) +{ + SMBState *smb_state = (SMBState *)state; + if (smb_state->ds.de_state) + return 1; + return 0; +} + +static int SMBSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + SMBState *smb_state = (SMBState *)state; + smb_state->ds.de_state = de_state; + return 0; +} + +static DetectEngineState *SMBGetTxDetectState(void *vtx) +{ + SMBState *smb_state = (SMBState *)vtx; + return smb_state->ds.de_state; +} + +static void SMBStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static void *SMBGetTx(void *state, uint64_t tx_id) +{ + SMBState *smb_state = (SMBState *)state; + return smb_state; +} + +static uint64_t SMBGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +static int SMBGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return 1; +} + +static int SMBGetAlstateProgress(void *tx, uint8_t direction) +{ + return 0; +} + #define SMB_PROBING_PARSER_MIN_DEPTH 8 static uint16_t SMBProbingParser(uint8_t *input, uint32_t ilen, uint32_t *offset) @@ -1547,6 +1599,20 @@ void RegisterSMBParsers(void) AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMB, STREAM_TOSERVER, SMBParseRequest); AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMB, STREAM_TOCLIENT, SMBParseResponse); AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMB, SMBStateAlloc, SMBStateFree); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMB, SMBStateTransactionFree); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMB, SMBStateHasTxDetectState, + SMBGetTxDetectState, SMBSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMB, SMBGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMB, SMBGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMB, SMBGetAlstateProgress); + + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SMB, + SMBGetAlstateProgressCompletionStatus); } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection " "still on.", proto_name); diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index aa51dd833398..68d944748a69 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -705,7 +705,6 @@ static int DetectDceStubDataTestParse02(void) */ static int DetectDceStubDataTestParse03(void) { - int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; @@ -1157,8 +1156,7 @@ static int DetectDceStubDataTestParse03(void) StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; @@ -1167,53 +1165,34 @@ static int DetectDceStubDataTestParse03(void) "(msg:\"DCERPC\"; " "dce_stub_data; content:\"|42 42 42 42|\";" "sid:1;)"); - if (s == NULL) - goto end; + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_request, dcerpc_request_len); - if (r != 0) { - SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); dcerpc_state = f.alstate; - if (dcerpc_state == NULL) { - SCLogDebug("no dcerpc state: "); - goto end; - } + FAIL_IF (dcerpc_state == NULL); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 1)); - if (!PacketAlertCheck(p, 1)) - goto end; - - result = 1; - - end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; } static int DetectDceStubDataTestParse04(void) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 865d34668def..18d97d08a889 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -616,9 +616,9 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (next_tx_no_progress) break; } /* for */ - + } /* DCERPC matches */ - } else if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL && + if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL && (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2)) { From f018ae94b0b0a5be16115ea598002124ae0b197a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 20:05:17 +0100 Subject: [PATCH 2419/2553] dce: dynamic lists --- src/detect-dce-iface.c | 159 +++++++++++++++++++---------------------- src/detect-dce-opnum.c | 58 ++++++++------- 2 files changed, 104 insertions(+), 113 deletions(-) diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 5daf7e814fc5..eec29b3e2d9c 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -52,11 +52,19 @@ static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; -static int DetectDceIfaceMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - void *, const Signature *, const SigMatchData *); +static int DetectDceIfaceMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectDceIfaceSetup(DetectEngineCtx *, Signature *, char *); static void DetectDceIfaceFree(void *); static void DetectDceIfaceRegisterTests(void); +static int g_dce_generic_list_id = 0; + +static int InspectDceGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id); /** * \brief Registers the keyword handlers for the "dce_iface" keyword. @@ -65,7 +73,7 @@ void DetectDceIfaceRegister(void) { sigmatch_table[DETECT_DCE_IFACE].name = "dce_iface"; sigmatch_table[DETECT_DCE_IFACE].Match = NULL; - sigmatch_table[DETECT_DCE_IFACE].AppLayerMatch = DetectDceIfaceMatch; + sigmatch_table[DETECT_DCE_IFACE].AppLayerTxMatch = DetectDceIfaceMatch; sigmatch_table[DETECT_DCE_IFACE].Setup = DetectDceIfaceSetup; sigmatch_table[DETECT_DCE_IFACE].Free = DetectDceIfaceFree; sigmatch_table[DETECT_DCE_IFACE].RegisterTests = DetectDceIfaceRegisterTests; @@ -73,8 +81,31 @@ void DetectDceIfaceRegister(void) sigmatch_table[DETECT_DCE_IFACE].flags |= SIGMATCH_PAYLOAD; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + g_dce_generic_list_id = DetectBufferTypeRegister("dce_generic"); + + DetectAppLayerInspectEngineRegister("dce_generic", + ALPROTO_DCERPC, SIG_FLAG_TOSERVER, InspectDceGeneric); + DetectAppLayerInspectEngineRegister("dce_generic", + ALPROTO_SMB, SIG_FLAG_TOSERVER, InspectDceGeneric); + + DetectAppLayerInspectEngineRegister("dce_generic", + ALPROTO_DCERPC, SIG_FLAG_TOCLIENT, InspectDceGeneric); + DetectAppLayerInspectEngineRegister("dce_generic", + ALPROTO_SMB, SIG_FLAG_TOCLIENT, InspectDceGeneric); } +static int InspectDceGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} + + /** * \internal * \brief Parses the argument sent along with the "dce_iface" keyword. @@ -262,15 +293,15 @@ DCERPCState *DetectDceGetState(AppProto alproto, void *alstate) * \retval 0 On no match. */ static int DetectDceIfaceMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); int ret = 0; DCERPCUuidEntry *item = NULL; int i = 0; - DetectDceIfaceData *dce_data = (DetectDceIfaceData *)m->ctx; + DetectDceIfaceData *dce_data = (DetectDceIfaceData *)m; DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); if (dcerpc_state == NULL) { SCLogDebug("No DCERPCState for the flow"); @@ -341,11 +372,16 @@ static int DetectDceIfaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) DetectDceIfaceData *did = NULL; SigMatch *sm = NULL; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + return -1; + } + did = DetectDceIfaceArgParse(arg); if (did == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Error parsing dec_iface option in " "signature"); - goto error; + return -1; } sm = SigMatchAlloc(); @@ -355,12 +391,7 @@ static int DetectDceIfaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->type = DETECT_DCE_IFACE; sm->ctx = (void *)did; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_dce_generic_list_id); s->alproto = ALPROTO_DCERPC; /* Flagged the signature as to inspect the app layer data */ @@ -402,11 +433,11 @@ static int DetectDceIfaceTestParse01(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + temp = s->sm_lists[g_dce_generic_list_id]; did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); @@ -445,11 +476,11 @@ static int DetectDceIfaceTestParse02(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,>1") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + temp = s->sm_lists[g_dce_generic_list_id]; did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); @@ -488,11 +519,11 @@ static int DetectDceIfaceTestParse03(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,<10") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + temp = s->sm_lists[g_dce_generic_list_id]; did = (DetectDceIfaceData *)temp->ctx; result &= 1; for (i = 0; i < 16; i++) { @@ -527,11 +558,11 @@ static int DetectDceIfaceTestParse04(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,!10") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + temp = s->sm_lists[g_dce_generic_list_id]; did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); @@ -567,11 +598,11 @@ static int DetectDceIfaceTestParse05(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,=10") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + temp = s->sm_lists[g_dce_generic_list_id]; did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); @@ -610,11 +641,11 @@ static int DetectDceIfaceTestParse06(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,any_frag") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + temp = s->sm_lists[g_dce_generic_list_id]; did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); @@ -653,11 +684,11 @@ static int DetectDceIfaceTestParse07(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,>1,any_frag") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + temp = s->sm_lists[g_dce_generic_list_id]; did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); @@ -694,11 +725,11 @@ static int DetectDceIfaceTestParse08(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,<1,any_frag") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + temp = s->sm_lists[g_dce_generic_list_id]; did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); @@ -737,7 +768,7 @@ static int DetectDceIfaceTestParse09(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,=1,any_frag") == 0); - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + temp = s->sm_lists[g_dce_generic_list_id]; did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); @@ -776,11 +807,11 @@ static int DetectDceIfaceTestParse10(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,!1,any_frag") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + temp = s->sm_lists[g_dce_generic_list_id]; did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); @@ -831,7 +862,6 @@ static int DetectDceIfaceTestParse11(void) */ static int DetectDceIfaceTestParse12(void) { - int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; @@ -897,103 +927,60 @@ static int DetectDceIfaceTestParse12(void) StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5,=0,any_frag; " "sid:1;)"); - if (s == NULL) - goto end; + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCLogDebug("handling to_server chunk"); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); - if (r != 0) { - SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); dcerpc_state = f.alstate; - if (dcerpc_state == NULL) { - SCLogDebug("no dcerpc state: "); - goto end; - } + FAIL_IF(dcerpc_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 didn't match (1): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); SCLogDebug("handling to_client chunk"); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); - if (r != 0) { - SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(PacketAlertCheck(p, 1)); - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched, but shouldn't have: "); - goto end; - } - - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_request, dcerpc_request_len); - if (r != 0) { - SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sid 1 matched, but shouldn't have: "); - goto end; - } - - result = 1; - -end: + FAIL_IF(!PacketAlertCheck(p, 1)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; } /* Disabled because of bug_753. Would be enabled, once we rewrite diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 124b88aa3bda..f07c921dabee 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -53,11 +53,13 @@ static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; -static int DetectDceOpnumMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - void *, const Signature *, const SigMatchData *); +static int DetectDceOpnumMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectDceOpnumSetup(DetectEngineCtx *, Signature *, char *); static void DetectDceOpnumFree(void *); static void DetectDceOpnumRegisterTests(void); +static int g_dce_generic_list_id = 0; /** * \brief Registers the keyword handlers for the "dce_opnum" keyword. @@ -66,7 +68,7 @@ void DetectDceOpnumRegister(void) { sigmatch_table[DETECT_DCE_OPNUM].name = "dce_opnum"; sigmatch_table[DETECT_DCE_OPNUM].Match = NULL; - sigmatch_table[DETECT_DCE_OPNUM].AppLayerMatch = DetectDceOpnumMatch; + sigmatch_table[DETECT_DCE_OPNUM].AppLayerTxMatch = DetectDceOpnumMatch; sigmatch_table[DETECT_DCE_OPNUM].Setup = DetectDceOpnumSetup; sigmatch_table[DETECT_DCE_OPNUM].Free = DetectDceOpnumFree; sigmatch_table[DETECT_DCE_OPNUM].RegisterTests = DetectDceOpnumRegisterTests; @@ -74,6 +76,8 @@ void DetectDceOpnumRegister(void) sigmatch_table[DETECT_DCE_OPNUM].flags |= SIGMATCH_PAYLOAD; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + g_dce_generic_list_id = DetectBufferTypeRegister("dce_generic"); } /** @@ -240,12 +244,12 @@ static DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) * \retval 0 On no match. */ static int DetectDceOpnumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectDceOpnumData *dce_data = (DetectDceOpnumData *)m->ctx; + DetectDceOpnumData *dce_data = (DetectDceOpnumData *)m; DetectDceOpnumRange *dor = dce_data->range; DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); @@ -291,14 +295,19 @@ static int DetectDceOpnumSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) if (arg == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Error parsing dce_opnum option in " "signature, option needs a value"); - goto error; + return -1; + } + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + return -1; } dod = DetectDceOpnumArgParse(arg); if (dod == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Error parsing dce_opnum option in " "signature"); - goto error; + return -1; } sm = SigMatchAlloc(); @@ -308,12 +317,7 @@ static int DetectDceOpnumSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->type = DETECT_DCE_OPNUM; sm->ctx = (void *)dod; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + SigMatchAppendSMToList(s, sm, g_dce_generic_list_id); s->alproto = ALPROTO_DCERPC; /* Flagged the signature as to inspect the app layer data */ @@ -363,7 +367,7 @@ static int DetectDceOpnumTestParse01(void) result &= (DetectDceOpnumSetup(NULL, s, "12,26,62,61,6513--") == -1); result &= (DetectDceOpnumSetup(NULL, s, "12-14,12,121,62-8") == -1); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { + if (s->sm_lists[g_dce_generic_list_id] != NULL) { SigFree(s); result &= 1; } @@ -381,8 +385,8 @@ static int DetectDceOpnumTestParse02(void) result = (DetectDceOpnumSetup(NULL, s, "12") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; @@ -408,8 +412,8 @@ static int DetectDceOpnumTestParse03(void) result = (DetectDceOpnumSetup(NULL, s, "12-24") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; @@ -435,8 +439,8 @@ static int DetectDceOpnumTestParse04(void) result = (DetectDceOpnumSetup(NULL, s, "12-24,24,62-72,623-635,62,25,213-235") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; @@ -499,8 +503,8 @@ static int DetectDceOpnumTestParse05(void) result = (DetectDceOpnumSetup(NULL, s, "1,2,3,4,5,6,7") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; @@ -563,8 +567,8 @@ static int DetectDceOpnumTestParse06(void) result = (DetectDceOpnumSetup(NULL, s, "1-2,3-4,5-6,7-8") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; @@ -609,8 +613,8 @@ static int DetectDceOpnumTestParse07(void) result = (DetectDceOpnumSetup(NULL, s, "1-2,3-4,5-6,7-8,9") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; From 775e182531e7e744e1bad63916e87400a8a7867b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 20:17:49 +0100 Subject: [PATCH 2420/2553] detect: remove AppLayerMatch API call --- src/detect-bypass.c | 1 - src/detect-byte-extract.c | 1 - src/detect-cipservice.c | 2 - src/detect-dce-stub-data.c | 1 - src/detect-dnp3.c | 4 -- src/detect-dns-query.c | 1 - src/detect-engine-state.c | 86 ++------------------------------- src/detect-file-data.c | 1 - src/detect-http-client-body.c | 1 - src/detect-http-cookie.c | 1 - src/detect-http-hh.c | 1 - src/detect-http-hrh.c | 1 - src/detect-http-method.c | 1 - src/detect-http-raw-header.c | 1 - src/detect-http-raw-uri.c | 1 - src/detect-http-request-line.c | 1 - src/detect-http-response-line.c | 1 - src/detect-http-server-body.c | 1 - src/detect-http-stat-code.c | 1 - src/detect-http-stat-msg.c | 1 - src/detect-http-ua.c | 1 - src/detect-http-uri.c | 1 - src/detect-lua.c | 21 -------- src/detect-modbus.c | 1 - src/detect-pcre.c | 1 - src/detect-pkt-data.c | 1 - src/detect-tls-cert-issuer.c | 1 - src/detect-tls-cert-subject.c | 1 - src/detect-tls-sni.c | 1 - src/detect-uricontent.c | 1 - src/detect-urilen.c | 1 - src/detect.h | 5 -- 32 files changed, 4 insertions(+), 141 deletions(-) diff --git a/src/detect-bypass.c b/src/detect-bypass.c index a92e2822796a..6d77fbefa451 100644 --- a/src/detect-bypass.c +++ b/src/detect-bypass.c @@ -63,7 +63,6 @@ void DetectBypassRegister(void) sigmatch_table[DETECT_BYPASS].desc = "call the bypass callback when the match of a sig is complete"; sigmatch_table[DETECT_BYPASS].url = ""; sigmatch_table[DETECT_BYPASS].Match = DetectBypassMatch; - sigmatch_table[DETECT_BYPASS].AppLayerMatch = NULL; sigmatch_table[DETECT_BYPASS].Setup = DetectBypassSetup; sigmatch_table[DETECT_BYPASS].Free = NULL; sigmatch_table[DETECT_BYPASS].RegisterTests = DetectBypassRegisterTests; diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 1a7a0268cd2c..a6ab72a01694 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -100,7 +100,6 @@ void DetectByteExtractRegister(void) { sigmatch_table[DETECT_BYTE_EXTRACT].name = "byte_extract"; sigmatch_table[DETECT_BYTE_EXTRACT].Match = NULL; - sigmatch_table[DETECT_BYTE_EXTRACT].AppLayerMatch = NULL; sigmatch_table[DETECT_BYTE_EXTRACT].Setup = DetectByteExtractSetup; sigmatch_table[DETECT_BYTE_EXTRACT].Free = DetectByteExtractFree; sigmatch_table[DETECT_BYTE_EXTRACT].RegisterTests = DetectByteExtractRegisterTests; diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c index 1074241d5a1c..6452ffaff622 100644 --- a/src/detect-cipservice.c +++ b/src/detect-cipservice.c @@ -53,7 +53,6 @@ void DetectCipServiceRegister(void) sigmatch_table[DETECT_CIPSERVICE].name = "cip_service"; //rule keyword sigmatch_table[DETECT_CIPSERVICE].desc = "Rules for detecting CIP Service "; sigmatch_table[DETECT_CIPSERVICE].Match = NULL; - sigmatch_table[DETECT_CIPSERVICE].AppLayerMatch = NULL; sigmatch_table[DETECT_CIPSERVICE].Setup = DetectCipServiceSetup; sigmatch_table[DETECT_CIPSERVICE].Free = DetectCipServiceFree; sigmatch_table[DETECT_CIPSERVICE].RegisterTests @@ -315,7 +314,6 @@ void DetectEnipCommandRegister(void) sigmatch_table[DETECT_ENIPCOMMAND].desc = "Rules for detecting EtherNet/IP command"; sigmatch_table[DETECT_ENIPCOMMAND].Match = NULL; - sigmatch_table[DETECT_ENIPCOMMAND].AppLayerMatch = NULL; sigmatch_table[DETECT_ENIPCOMMAND].Setup = DetectEnipCommandSetup; sigmatch_table[DETECT_ENIPCOMMAND].Free = DetectEnipCommandFree; sigmatch_table[DETECT_ENIPCOMMAND].RegisterTests diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index 68d944748a69..418ab8fcafe9 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -59,7 +59,6 @@ void DetectDceStubDataRegister(void) { sigmatch_table[DETECT_DCE_STUB_DATA].name = "dce_stub_data"; sigmatch_table[DETECT_DCE_STUB_DATA].Match = NULL; - sigmatch_table[DETECT_DCE_STUB_DATA].AppLayerMatch = NULL; sigmatch_table[DETECT_DCE_STUB_DATA].Setup = DetectDceStubDataSetup; sigmatch_table[DETECT_DCE_STUB_DATA].Free = NULL; sigmatch_table[DETECT_DCE_STUB_DATA].RegisterTests = DetectDceStubDataRegisterTests; diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 438c38cb3a0a..4fe63ecd226d 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -482,7 +482,6 @@ static void DetectDNP3FuncRegister(void) sigmatch_table[DETECT_AL_DNP3FUNC].name = "dnp3_func"; sigmatch_table[DETECT_AL_DNP3FUNC].alias = "dnp3.func"; sigmatch_table[DETECT_AL_DNP3FUNC].Match = NULL; - sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerTxMatch = DetectDNP3FuncMatch; sigmatch_table[DETECT_AL_DNP3FUNC].Setup = DetectDNP3FuncSetup; sigmatch_table[DETECT_AL_DNP3FUNC].Free = DetectDNP3Free; @@ -499,7 +498,6 @@ static void DetectDNP3IndRegister(void) sigmatch_table[DETECT_AL_DNP3IND].name = "dnp3_ind"; sigmatch_table[DETECT_AL_DNP3IND].alias = "dnp3.ind"; sigmatch_table[DETECT_AL_DNP3IND].Match = NULL; - sigmatch_table[DETECT_AL_DNP3IND].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_DNP3IND].AppLayerTxMatch = DetectDNP3IndMatch; sigmatch_table[DETECT_AL_DNP3IND].Setup = DetectDNP3IndSetup; sigmatch_table[DETECT_AL_DNP3IND].Free = DetectDNP3Free; @@ -516,7 +514,6 @@ static void DetectDNP3ObjRegister(void) sigmatch_table[DETECT_AL_DNP3OBJ].name = "dnp3_obj"; sigmatch_table[DETECT_AL_DNP3OBJ].alias = "dnp3.obj"; sigmatch_table[DETECT_AL_DNP3OBJ].Match = NULL; - sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerTxMatch = DetectDNP3ObjMatch; sigmatch_table[DETECT_AL_DNP3OBJ].Setup = DetectDNP3ObjSetup; sigmatch_table[DETECT_AL_DNP3OBJ].Free = DetectDNP3Free; @@ -540,7 +537,6 @@ static void DetectDNP3DataRegister(void) sigmatch_table[DETECT_AL_DNP3DATA].name = "dnp3_data"; sigmatch_table[DETECT_AL_DNP3DATA].Match = NULL; - sigmatch_table[DETECT_AL_DNP3DATA].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_DNP3DATA].Setup = DetectDNP3DataSetup; sigmatch_table[DETECT_AL_DNP3DATA].Free = NULL; sigmatch_table[DETECT_AL_DNP3DATA].RegisterTests = diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index c8f9690b47b1..815d0059226d 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -70,7 +70,6 @@ void DetectDnsQueryRegister (void) sigmatch_table[DETECT_AL_DNS_QUERY].name = "dns_query"; sigmatch_table[DETECT_AL_DNS_QUERY].desc = "content modifier to match specifically and only on the DNS query-buffer"; sigmatch_table[DETECT_AL_DNS_QUERY].Match = NULL; - sigmatch_table[DETECT_AL_DNS_QUERY].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_DNS_QUERY].Setup = DetectDnsQuerySetup; sigmatch_table[DETECT_AL_DNS_QUERY].Free = NULL; sigmatch_table[DETECT_AL_DNS_QUERY].RegisterTests = DetectDnsQueryRegisterTests; diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 18d97d08a889..c182abde01b1 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -635,57 +635,18 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } } - int amatch = 0; - /* flow based matches */ - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_AMATCH); - smd = s->sm_arrays[DETECT_SM_LIST_AMATCH]; - if (smd != NULL) { - void *alstate = FlowGetAppState(f); - if (alstate == NULL) { - goto end; - } - - while (1) { - if (sigmatch_table[smd->type].AppLayerMatch != NULL) { - int match = 0; - KEYWORD_PROFILING_START; - match = sigmatch_table[smd->type]. - AppLayerMatch(tv, det_ctx, f, flags, alstate, s, smd); - KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); - - if (match == 0) { - break; - } else if (match == 2) { - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - break; - } else if (match == 1 && smd->is_last) { - amatch = 1; - } - } - if (smd->is_last) - break; - smd++; - } - } - /* if AMATCH and/or DMATCH are in use, see if we need to * alert and store the state */ - if ((s->sm_arrays[DETECT_SM_LIST_AMATCH] != NULL || - s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL)) + if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL) { - /* if dmatch in use and match + amatch in use and match - or - if dmatch in use and match + amatch not in use - or - if dmatch not in use + amatch in use and match + /* if dmatch in use and match or sig can't match */ if (inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; } else { - if ((amatch || s->sm_arrays[DETECT_SM_LIST_AMATCH] == NULL) && - (dmatch || s->sm_arrays[DETECT_SM_LIST_DMATCH] == NULL)) + if (dmatch || s->sm_arrays[DETECT_SM_LIST_DMATCH] == NULL) { if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, 0, @@ -936,45 +897,6 @@ static int DoInspectFlowRule(ThreadVars *tv, RULE_PROFILING_START(p); - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_AMATCH); - if (item->nm != NULL) { - void *alstate = FlowGetAppState(f); - if (alstate == NULL) { - RULE_PROFILING_END(det_ctx, s, 0 /* no match */, p); - return -1; - } - - smd = item->nm; - while(1) { - if (sigmatch_table[smd->type].AppLayerMatch != NULL) { - int match = 0; - KEYWORD_PROFILING_START; - match = sigmatch_table[smd->type]. - AppLayerMatch(tv, det_ctx, f, flags, alstate, s, smd); - KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); - - if (match == 0) - break; - else if (match == 2) { - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - break; - } - else if (match == 1) { - total_matches++; - - if (smd->is_last) - full_match = 1; - } - } - if (smd->is_last) - break; - smd++; - } - } else { - /* AMATCH isn't there */ - full_match = 1; - } - /* DCERPC matches */ if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL && (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || @@ -993,7 +915,7 @@ static int DoInspectFlowRule(ThreadVars *tv, } } /* update full_match with DMATCH result */ - if (full_match && s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL) { full_match = ((inspect_flags & DE_STATE_FLAG_DCE_PAYLOAD_INSPECT) != 0); } diff --git a/src/detect-file-data.c b/src/detect-file-data.c index ef245f91520a..da9a011bc7ed 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -60,7 +60,6 @@ void DetectFiledataRegister(void) sigmatch_table[DETECT_FILE_DATA].desc = "make content keywords match on HTTP response body"; sigmatch_table[DETECT_FILE_DATA].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#file-data"; sigmatch_table[DETECT_FILE_DATA].Match = NULL; - sigmatch_table[DETECT_FILE_DATA].AppLayerMatch = NULL; sigmatch_table[DETECT_FILE_DATA].Setup = DetectFiledataSetup; sigmatch_table[DETECT_FILE_DATA].Free = NULL; sigmatch_table[DETECT_FILE_DATA].RegisterTests = DetectFiledataRegisterTests; diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 2273aefbaefd..a158e137b76b 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -73,7 +73,6 @@ void DetectHttpClientBodyRegister(void) sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].desc = "content modifier to match only on HTTP request-body"; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_client-body"; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Setup = DetectHttpClientBodySetup; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Free = DetectHttpClientBodyFree; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].RegisterTests = DetectHttpClientBodyRegisterTests; diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 2b0baeaa21b9..3b9eff786cde 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -76,7 +76,6 @@ void DetectHttpCookieRegister(void) sigmatch_table[DETECT_AL_HTTP_COOKIE].desc = "content modifier to match only on the HTTP cookie-buffer"; sigmatch_table[DETECT_AL_HTTP_COOKIE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-cookie"; sigmatch_table[DETECT_AL_HTTP_COOKIE].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_COOKIE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_COOKIE].Setup = DetectHttpCookieSetup; sigmatch_table[DETECT_AL_HTTP_COOKIE].Free = DetectHttpCookieFree; sigmatch_table[DETECT_AL_HTTP_COOKIE].RegisterTests = DetectHttpCookieRegisterTests; diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 7c943d07d64c..758b978a6fb6 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -74,7 +74,6 @@ void DetectHttpHHRegister(void) sigmatch_table[DETECT_AL_HTTP_HOST].name = "http_host"; sigmatch_table[DETECT_AL_HTTP_HOST].desc = "content modifier to match only on the HTTP hostname"; sigmatch_table[DETECT_AL_HTTP_HOST].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_HOST].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_HOST].Setup = DetectHttpHHSetup; sigmatch_table[DETECT_AL_HTTP_HOST].Free = DetectHttpHHFree; sigmatch_table[DETECT_AL_HTTP_HOST].RegisterTests = DetectHttpHHRegisterTests; diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index 92f504e56676..8b3620a48be2 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -73,7 +73,6 @@ void DetectHttpHRHRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HOST].name = "http_raw_host"; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].desc = "content modifier to match only on the HTTP host header or the raw hostname from the HTTP uri"; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Setup = DetectHttpHRHSetup; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Free = DetectHttpHRHFree; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].RegisterTests = DetectHttpHRHRegisterTests; diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 0cf00f9bcdc4..a4b0feb749d0 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -76,7 +76,6 @@ void DetectHttpMethodRegister(void) sigmatch_table[DETECT_AL_HTTP_METHOD].desc = "content modifier to match only on the HTTP method-buffer"; sigmatch_table[DETECT_AL_HTTP_METHOD].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-method"; sigmatch_table[DETECT_AL_HTTP_METHOD].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_METHOD].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_METHOD].Setup = DetectHttpMethodSetup; sigmatch_table[DETECT_AL_HTTP_METHOD].Free = DetectHttpMethodFree; sigmatch_table[DETECT_AL_HTTP_METHOD].RegisterTests = DetectHttpMethodRegisterTests; diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index 35b9d3ad6286..8b2b394cab02 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -74,7 +74,6 @@ void DetectHttpRawHeaderRegister(void) { sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].name = "http_raw_header"; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetup; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Free = DetectHttpRawHeaderFree; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].RegisterTests = DetectHttpRawHeaderRegisterTests; diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 080586e428b7..367be1d595ad 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -69,7 +69,6 @@ void DetectHttpRawUriRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_URI].desc = "content modifier to match on HTTP uri"; sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_uri-and-http_raw-uri"; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Setup = DetectHttpRawUriSetup; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Free = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].RegisterTests = DetectHttpRawUriRegisterTests; diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 7c8cd3082e7e..4fb495f3efec 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -79,7 +79,6 @@ void DetectHttpRequestLineRegister(void) sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].desc = "content modifier to match only on the HTTP request line"; sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_request-line"; sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Setup = DetectHttpRequestLineSetup; sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].RegisterTests = DetectHttpRequestLineRegisterTests; diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index f7dd062faae7..e9b573b07c30 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -79,7 +79,6 @@ void DetectHttpResponseLineRegister(void) sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].desc = "content modifier to match only on the HTTP response line"; sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_response-line"; sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].Setup = DetectHttpResponseLineSetup; sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].RegisterTests = DetectHttpResponseLineRegisterTests; diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index b2157d8fefc1..eb6f02d31eeb 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -74,7 +74,6 @@ void DetectHttpServerBodyRegister(void) sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].desc = "content modifier to match only on the HTTP response-body"; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_server-body"; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Setup = DetectHttpServerBodySetup; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Free = DetectHttpServerBodyFree; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].RegisterTests = DetectHttpServerBodyRegisterTests; diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index 938ce6e5f98e..308ef9a46fb8 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -77,7 +77,6 @@ void DetectHttpStatCodeRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_CODE].desc = "content modifier to match only on HTTP stat-code-buffer"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_stat-code"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetup; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Free = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].RegisterTests = DetectHttpStatCodeRegisterTests; diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index 57dffbf80721..631fb46ab19e 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -77,7 +77,6 @@ void DetectHttpStatMsgRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_MSG].desc = "content modifier to match on HTTP stat-msg-buffer"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_stat-msg"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetup; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Free = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].RegisterTests = DetectHttpStatMsgRegisterTests; diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index b154806f39ef..9a6df63ae1e7 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -74,7 +74,6 @@ void DetectHttpUARegister(void) sigmatch_table[DETECT_AL_HTTP_USER_AGENT].desc = "content modifier to match only on the HTTP User-Agent header"; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_user-agent"; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Setup = DetectHttpUASetup; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Free = DetectHttpUAFree; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].RegisterTests = DetectHttpUARegisterTests; diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 3ae8f866eb50..67714f884825 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -70,7 +70,6 @@ void DetectHttpUriRegister (void) sigmatch_table[DETECT_AL_HTTP_URI].desc = "content modifier to match specifically and only on the HTTP uri-buffer"; sigmatch_table[DETECT_AL_HTTP_URI].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_uri-and-http_raw-uri"; sigmatch_table[DETECT_AL_HTTP_URI].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_URI].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_URI].Setup = DetectHttpUriSetup; sigmatch_table[DETECT_AL_HTTP_URI].Free = NULL; sigmatch_table[DETECT_AL_HTTP_URI].RegisterTests = DetectHttpUriRegisterTests; diff --git a/src/detect-lua.c b/src/detect-lua.c index 8c9a4070ff2d..87d3e55f9b9a 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -89,8 +89,6 @@ void DetectLuaRegister(void) static int DetectLuaMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); -static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, const Signature *s, const SigMatchData *m); static int DetectLuaAppTxMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, @@ -116,7 +114,6 @@ void DetectLuaRegister(void) sigmatch_table[DETECT_LUA].desc = "match via a lua script"; sigmatch_table[DETECT_LUA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Lua_scripting"; sigmatch_table[DETECT_LUA].Match = DetectLuaMatch; - sigmatch_table[DETECT_LUA].AppLayerMatch = DetectLuaAppMatch; sigmatch_table[DETECT_LUA].AppLayerTxMatch = DetectLuaAppTxMatch; sigmatch_table[DETECT_LUA].Setup = DetectLuaSetup; sigmatch_table[DETECT_LUA].Free = DetectLuaFree; @@ -551,24 +548,6 @@ static int DetectLuaAppMatchCommon (ThreadVars *t, DetectEngineThreadCtx *det_ct SCReturnInt(ret); } -/** - * \brief match the specified lua script in AMATCH - * - * \param t thread local vars - * \param det_ctx pattern matcher thread local data - * \param s signature being inspected - * \param m sigmatch that we will cast into DetectLuaData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchData *m) -{ - return DetectLuaAppMatchCommon(t, det_ctx, f, flags, state, s, m->ctx); -} - /** * \brief match the specified lua script in a list with a tx * diff --git a/src/detect-modbus.c b/src/detect-modbus.c index 56717c475cda..19518e28261c 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -407,7 +407,6 @@ void DetectModbusRegister(void) SCEnter(); sigmatch_table[DETECT_AL_MODBUS].name = "modbus"; sigmatch_table[DETECT_AL_MODBUS].Match = NULL; - sigmatch_table[DETECT_AL_MODBUS].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_MODBUS].Setup = DetectModbusSetup; sigmatch_table[DETECT_AL_MODBUS].Free = DetectModbusFree; sigmatch_table[DETECT_AL_MODBUS].RegisterTests = DetectModbusRegisterTests; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 29106304cc7c..e531d6a2cbff 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -90,7 +90,6 @@ void DetectPcreRegister (void) sigmatch_table[DETECT_PCRE].desc = "match on regular expression"; sigmatch_table[DETECT_PCRE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#pcre-perl-compatible-regular-expressions"; sigmatch_table[DETECT_PCRE].Match = NULL; - sigmatch_table[DETECT_PCRE].AppLayerMatch = NULL; sigmatch_table[DETECT_PCRE].Setup = DetectPcreSetup; sigmatch_table[DETECT_PCRE].Free = DetectPcreFree; sigmatch_table[DETECT_PCRE].RegisterTests = DetectPcreRegisterTests; diff --git a/src/detect-pkt-data.c b/src/detect-pkt-data.c index 8f740636bc96..4bdc3b331541 100644 --- a/src/detect-pkt-data.c +++ b/src/detect-pkt-data.c @@ -53,7 +53,6 @@ void DetectPktDataRegister(void) { sigmatch_table[DETECT_PKT_DATA].name = "pkt_data"; sigmatch_table[DETECT_PKT_DATA].Match = NULL; - sigmatch_table[DETECT_PKT_DATA].AppLayerMatch = NULL; sigmatch_table[DETECT_PKT_DATA].Setup = DetectPktDataSetup; sigmatch_table[DETECT_PKT_DATA].Free = NULL; sigmatch_table[DETECT_PKT_DATA].RegisterTests = DetectPktDataTestRegister; diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index 5928e442c057..f918b301dbbd 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -66,7 +66,6 @@ void DetectTlsIssuerRegister(void) sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].desc = "content modifier to match specifically and only on the TLS cert issuer buffer"; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-cert-issuer"; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Match = NULL; - sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Setup = DetectTlsIssuerSetup; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Free = NULL; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].RegisterTests = DetectTlsIssuerRegisterTests; diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index 8c4936bbd381..affea07ea7b6 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -66,7 +66,6 @@ void DetectTlsSubjectRegister(void) sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].desc = "content modifier to match specifically and only on the TLS cert subject buffer"; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-cert-subject"; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Match = NULL; - sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Setup = DetectTlsSubjectSetup; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Free = NULL; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index 8d3f8333f2a1..a87f0a6e7ef1 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -66,7 +66,6 @@ void DetectTlsSniRegister(void) sigmatch_table[DETECT_AL_TLS_SNI].desc = "content modifier to match specifically and only on the TLS SNI buffer"; sigmatch_table[DETECT_AL_TLS_SNI].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-sni"; sigmatch_table[DETECT_AL_TLS_SNI].Match = NULL; - sigmatch_table[DETECT_AL_TLS_SNI].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_TLS_SNI].Setup = DetectTlsSniSetup; sigmatch_table[DETECT_AL_TLS_SNI].Free = NULL; sigmatch_table[DETECT_AL_TLS_SNI].RegisterTests = DetectTlsSniRegisterTests; diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index 719340e75387..dc77cc9e694c 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -69,7 +69,6 @@ static int g_http_uri_buffer_id = 0; void DetectUricontentRegister (void) { sigmatch_table[DETECT_URICONTENT].name = "uricontent"; - sigmatch_table[DETECT_URICONTENT].AppLayerMatch = NULL; sigmatch_table[DETECT_URICONTENT].Match = NULL; sigmatch_table[DETECT_URICONTENT].Setup = DetectUricontentSetup; sigmatch_table[DETECT_URICONTENT].Free = DetectUricontentFree; diff --git a/src/detect-urilen.c b/src/detect-urilen.c index 02e29395ba93..4e65d0b8313b 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -67,7 +67,6 @@ void DetectUrilenRegister(void) sigmatch_table[DETECT_AL_URILEN].desc = "match on the length of the HTTP uri"; sigmatch_table[DETECT_AL_URILEN].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#urilen"; sigmatch_table[DETECT_AL_URILEN].Match = NULL; - sigmatch_table[DETECT_AL_URILEN].AppLayerMatch = NULL /**< We handle this at detect-engine-uri.c now */; sigmatch_table[DETECT_AL_URILEN].Setup = DetectUrilenSetup; sigmatch_table[DETECT_AL_URILEN].Free = DetectUrilenFree; sigmatch_table[DETECT_AL_URILEN].RegisterTests = DetectUrilenRegisterTests; diff --git a/src/detect.h b/src/detect.h index 3800e75296d2..f448f7163a10 100644 --- a/src/detect.h +++ b/src/detect.h @@ -924,11 +924,6 @@ typedef struct SigTableElmt_ { /** Packet match function pointer */ int (*Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); - /** AppLayer match function pointer */ - int (*AppLayerMatch)(ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t flags, void *alstate, - const Signature *, const SigMatchData *); - /** AppLayer TX match function pointer */ int (*AppLayerTxMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, void *txv, From ad238121e34f78c0a8c6a5eced5edcb4ecb75715 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 20:31:38 +0100 Subject: [PATCH 2421/2553] detect: remove the AMATCH list --- src/detect-app-layer-protocol.c | 2 -- src/detect-dce-stub-data.c | 1 - src/detect-engine.c | 2 -- src/detect-parse.c | 20 -------------------- src/detect.c | 27 +-------------------------- src/detect.h | 3 --- 6 files changed, 1 insertion(+), 54 deletions(-) diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 7e4560ffacbf..5761d2b87ddd 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -355,7 +355,6 @@ static int DetectAppLayerProtocolTest04(void) FAIL_IF(s->alproto != ALPROTO_UNKNOWN); FAIL_IF(s->flags & SIG_FLAG_APPLAYER); - FAIL_IF_NOT(s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL); FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); @@ -382,7 +381,6 @@ static int DetectAppLayerProtocolTest05(void) FAIL_IF(s->alproto != ALPROTO_UNKNOWN); FAIL_IF(s->flags & SIG_FLAG_APPLAYER); - FAIL_IF_NOT(s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL); FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index 418ab8fcafe9..bc4831ebb3fe 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -110,7 +110,6 @@ static int DetectDceStubDataTestParse01(void) Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (dce_stub_data; content:\"1\"; sid:1;)"); FAIL_IF_NULL(s); - FAIL_IF_NOT_NULL(s->sm_lists[DETECT_SM_LIST_AMATCH]); FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_DMATCH]); DetectEngineCtxFree(de_ctx); PASS; diff --git a/src/detect-engine.c b/src/detect-engine.c index 24da42090605..b8ed69605824 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2906,8 +2906,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_PMATCH: return "packet/stream payload"; - case DETECT_SM_LIST_AMATCH: - return "generic app layer"; case DETECT_SM_LIST_DMATCH: return "dcerpc"; case DETECT_SM_LIST_TMATCH: diff --git a/src/detect-parse.c b/src/detect-parse.c index 64aaff96e53a..7bce331188ba 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -141,7 +141,6 @@ const char *DetectListToHumanString(int list) switch (list) { CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); - CASE_CODE_STRING(DETECT_SM_LIST_AMATCH, "app-layer"); CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); @@ -159,7 +158,6 @@ const char *DetectListToString(int list) switch (list) { CASE_CODE(DETECT_SM_LIST_MATCH); CASE_CODE(DETECT_SM_LIST_PMATCH); - CASE_CODE(DETECT_SM_LIST_AMATCH); CASE_CODE(DETECT_SM_LIST_DMATCH); CASE_CODE(DETECT_SM_LIST_TMATCH); CASE_CODE(DETECT_SM_LIST_POSTMATCH); @@ -1461,19 +1459,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } - for (sm = s->init_data->smlists[DETECT_SM_LIST_AMATCH]; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_AL_APP_LAYER_PROTOCOL) - continue; - if (((DetectAppLayerProtocolData *)sm->ctx)->negated) - break; - } - if (sm != NULL && s->alproto != ALPROTO_UNKNOWN) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "We can't have " - "the rule match on a fixed alproto and at the same time" - "have an app-layer-protocol keyword set."); - SCReturnInt(0); - } - /* TCP: pkt vs stream vs depth/offset */ if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) { if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) { @@ -1613,13 +1598,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, } } - if (sig->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) - sig->flags |= SIG_FLAG_APPLAYER; - if (sig->init_data->smlists[DETECT_SM_LIST_DMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->init_data->smlists[DETECT_SM_LIST_AMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; /* for other lists this flag is set when the inspect engines * are registered */ diff --git a/src/detect.c b/src/detect.c index 8f34641d8aab..bd58de6567de 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1914,9 +1914,6 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) - return 0; - /* for now assume that all registered buffer types are incompatible */ const int nlists = DetectBufferTypeMaxId(); for (int i = 0; i < nlists; i++) { @@ -1986,9 +1983,6 @@ static int SignatureIsPDOnly(const Signature *s) if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) - return 0; - /* for now assume that all registered buffer types are incompatible */ const int nlists = DetectBufferTypeMaxId(); for (int i = 0; i < nlists; i++) { @@ -2084,8 +2078,7 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) SCReturnInt(0); } - if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL || - s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { SCReturnInt(0); } @@ -2239,19 +2232,6 @@ static int SignatureCreateMask(Signature *s) } SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_AMATCH] ; sm != NULL; sm = sm->next) { - switch(sm->type) { - case DETECT_AL_URILEN: - case DETECT_AL_HTTP_URI: - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires dce http state"); - break; - case DETECT_AL_APP_LAYER_EVENT: - s->mask |= SIG_MASK_REQUIRE_ENGINE_EVENT; - break; - } - } - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { case DETECT_FLOWBITS: @@ -2390,11 +2370,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires flow"); } - if (s->init_data->smlists[DETECT_SM_LIST_AMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_FLOW; - SCLogDebug("sig requires flow"); - } - if (s->flags & SIG_FLAG_APPLAYER) { s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow"); diff --git a/src/detect.h b/src/detect.h index f448f7163a10..0580fa779af8 100644 --- a/src/detect.h +++ b/src/detect.h @@ -88,9 +88,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_MATCH = 0, DETECT_SM_LIST_PMATCH, - /* list for per flow matches. Deprecated. */ - DETECT_SM_LIST_AMATCH, - /* list for DCE matches */ DETECT_SM_LIST_DMATCH, From 1c02cf454297df4d7f57e02f5f1bd9c3b636c45a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 20:49:32 +0100 Subject: [PATCH 2422/2553] flow: remove unused Flow::de_state --- src/detect-engine-state.c | 222 +------------------------------------- src/detect-engine-state.h | 48 --------- src/detect-engine-uri.c | 31 ------ src/detect.c | 5 - src/flow-util.h | 7 -- src/flow.h | 5 +- 6 files changed, 4 insertions(+), 314 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index c182abde01b1..c499a08fe936 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -126,15 +126,6 @@ static DeStateStore *DeStateStoreAlloc(void) return d; } -static DeStateStoreFlowRules *DeStateStoreFlowRulesAlloc(void) -{ - DeStateStoreFlowRules *d = SCMalloc(sizeof(DeStateStoreFlowRules)); - if (unlikely(d == NULL)) - return NULL; - memset(d, 0, sizeof(DeStateStoreFlowRules)); - - return d; -} static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIntId num) { @@ -203,46 +194,6 @@ static void DeStateSignatureAppend(DetectEngineState *state, return; } -static void DeStateFlowRuleAppend(DetectEngineStateFlow *state, const Signature *s, - const SigMatchData *smd, uint32_t inspect_flags, - uint8_t direction) -{ - int jump = 0; - int i = 0; - DetectEngineStateDirectionFlow *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1]; - DeStateStoreFlowRules *store = dir_state->head; - - if (store == NULL) { - store = DeStateStoreFlowRulesAlloc(); - if (store != NULL) { - dir_state->head = store; - dir_state->tail = store; - } - } else { - jump = dir_state->cnt / DE_STATE_CHUNK_SIZE; - for (i = 0; i < jump; i++) { - store = store->next; - } - if (store == NULL) { - store = DeStateStoreFlowRulesAlloc(); - if (store != NULL) { - dir_state->tail->next = store; - dir_state->tail = store; - } - } - } - - if (store == NULL) - return; - - SigIntId idx = dir_state->cnt++ % DE_STATE_CHUNK_SIZE; - store->store[idx].sid = s->num; - store->store[idx].flags = inspect_flags; - store->store[idx].nm = smd; - - return; -} - static void DeStateStoreStateVersion(Flow *f, const uint8_t alversion, uint8_t direction) { @@ -274,16 +225,6 @@ DetectEngineState *DetectEngineStateAlloc(void) return d; } -DetectEngineStateFlow *DetectEngineStateFlowAlloc(void) -{ - DetectEngineStateFlow *d = SCMalloc(sizeof(DetectEngineStateFlow)); - if (unlikely(d == NULL)) - return NULL; - memset(d, 0, sizeof(DetectEngineStateFlow)); - - return d; -} - void DetectEngineStateFree(DetectEngineState *state) { DeStateStore *store; @@ -303,32 +244,8 @@ void DetectEngineStateFree(DetectEngineState *state) return; } -void DetectEngineStateFlowFree(DetectEngineStateFlow *state) -{ - DeStateStoreFlowRules *store; - DeStateStoreFlowRules *store_next; - int i = 0; - - for (i = 0; i < 2; i++) { - store = state->dir_state[i].head; - while (store != NULL) { - store_next = store->next; - SCFree(store); - store = store_next; - } - } - SCFree(state); - - return; -} - static int HasStoredSigs(Flow *f, uint8_t flags) { - if (f->de_state != NULL && f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1].cnt != 0) { - SCLogDebug("global sigs present"); - return 1; - } - if (AppLayerParserProtocolSupportsTxs(f->proto, f->alproto)) { AppProto alproto = f->alproto; void *alstate = FlowGetAppState(f); @@ -372,18 +289,13 @@ static int HasStoredSigs(Flow *f, uint8_t flags) * * \retval 0 no inspectable state * \retval 1 inspectable state - * \retval 2 inspectable state, but no update */ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, const uint8_t alversion, uint8_t flags) { int r = 0; - if (!(flags & STREAM_EOF) && f->de_state && - f->detect_alversion[flags & STREAM_TOSERVER ? 0 : 1] == alversion) { - SCLogDebug("unchanged state"); - r = 2; - } else if (HasStoredSigs(f, flags)) { + if (HasStoredSigs(f, flags)) { r = 1; } else { r = 0; @@ -391,20 +303,8 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, return r; } -static int StoreState(DetectEngineThreadCtx *det_ctx, - Flow *f, const uint8_t flags, const uint8_t alversion, - const Signature *s, const SigMatchData *smd, - const uint32_t inspect_flags, - const uint16_t file_no_match) +static int StoreState(Flow *f, const uint8_t flags, const uint8_t alversion) { - if (f->de_state == NULL) { - f->de_state = DetectEngineStateFlowAlloc(); - if (f->de_state == NULL) { - return 0; - } - } - - DeStateFlowRuleAppend(f->de_state, s, smd, inspect_flags, flags); DeStateStoreStateVersion(f, alversion, flags); return 1; } @@ -660,8 +560,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } } - StoreState(det_ctx, f, flags, alversion, - s, smd, inspect_flags, file_no_match); + StoreState(f, flags, alversion); } end: det_ctx->tx_id = 0; @@ -873,82 +772,6 @@ static int DoInspectItem(ThreadVars *tv, return 1; } -/** \internal - * \brief Continue Detection for a single "flow" rule (AMATCH) - */ -static int DoInspectFlowRule(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - DeStateStoreFlowRule *item, const uint8_t dir_state_flags, - Packet *p, Flow *f, AppProto alproto, uint8_t flags) -{ - /* flag rules that are either full inspected or unable to match - * in the de_state_sig_array so that prefilter filters them out */ - if (item->flags & (DE_STATE_FLAG_FULL_INSPECT|DE_STATE_FLAG_SIG_CANT_MATCH)) { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - return 0; - } - - uint8_t alert = 0; - uint32_t inspect_flags = item->flags; - int total_matches = 0; - int full_match = 0; - const SigMatchData *smd = NULL; - const Signature *s = de_ctx->sig_array[item->sid]; - - RULE_PROFILING_START(p); - - /* DCERPC matches */ - if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL && - (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || - alproto == ALPROTO_SMB2) && - !(item->flags & DE_STATE_FLAG_DCE_PAYLOAD_INSPECT)) - { - void *alstate = FlowGetAppState(f); - if (alstate != NULL) { - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_DMATCH); - if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, - flags, alstate) == 1) - { - total_matches++; - inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; - } - } - } - /* update full_match with DMATCH result */ - if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL) { - full_match = ((inspect_flags & DE_STATE_FLAG_DCE_PAYLOAD_INSPECT) != 0); - } - - /* check the results */ - if (total_matches > 0 && (full_match || (inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH))) - { - if (full_match) - alert = 1; - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; - } - /* prevent the rule loop from reinspecting this rule */ - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - RULE_PROFILING_END(det_ctx, s, (alert == 1), p); - - /* store the progress in the state */ - item->flags |= inspect_flags; - item->nm = smd; - - if (alert) { - SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); - - if (!(s->flags & SIG_FLAG_NOALERT)) { - PacketAlertAppend(det_ctx, s, p, 0, - PACKET_ALERT_FLAG_STATE_MATCH); - } else { - DetectSignatureApplyActions(p, s); - } - } - - DetectFlowvarProcessList(det_ctx, f); - return 1; -} - void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f, uint8_t flags, @@ -1040,29 +863,6 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } } - /* continue on flow based state rules (AMATCH) */ - if (f->de_state != NULL) { - DetectEngineStateDirectionFlow *dir_state = &f->de_state->dir_state[direction]; - DeStateStoreFlowRules *store = dir_state->head; - /* Loop through stored 'items' (stateful rules) and inspect them */ - for (; store != NULL; store = store->next) { - for (store_cnt = 0; - store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt; - store_cnt++, state_cnt++) - { - DeStateStoreFlowRule *rule = &store->store[store_cnt]; - - int r = DoInspectFlowRule(tv, de_ctx, det_ctx, - rule, dir_state->flags, - p, f, alproto, flags); - if (r < 0) { - goto end; - } - } - } - DeStateStoreStateVersion(f, alversion, flags); - } - end: det_ctx->tx_id = 0; det_ctx->tx_id_set = 0; @@ -1083,22 +883,6 @@ void DeStateUpdateInspectTransactionId(Flow *f, const uint8_t flags) return; } -void DetectEngineStateReset(DetectEngineStateFlow *state, uint8_t direction) -{ - if (state != NULL) { - if (direction & STREAM_TOSERVER) { - state->dir_state[0].cnt = 0; - state->dir_state[0].flags = 0; - } - if (direction & STREAM_TOCLIENT) { - state->dir_state[1].cnt = 0; - state->dir_state[1].flags = 0; - } - } - - return; -} - /** \brief Reset de state for active tx' * To be used on detect engine reload. * \param f write LOCKED flow diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 3fcd7b08e382..9215739841cc 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -31,19 +31,6 @@ * \author Anoop Saldanha */ -/* On DeState and locking. - * - * The DeState is part of a flow, but it can't be protected by the flow lock. - * Reason is we need to lock the DeState data for an entire detection run, - * as we're looping through on "continued" detection and rely on only a single - * detection instance setting it up on first run. We can't keep the entire flow - * locked during detection for performance reasons, it would slow us down too - * much. - * - * So a new lock was introduced. The only part of the process where we need - * the flow lock is obviously when we're getting/setting the de_state ptr from - * to the flow. - */ #ifndef __DETECT_ENGINE_STATE_H__ #define __DETECT_ENGINE_STATE_H__ @@ -96,8 +83,6 @@ #define DE_STATE_MATCH_HAS_NEW_STATE 0x00 #define DE_STATE_MATCH_NO_NEW_STATE 0x80 -/* TX BASED (inspect engines) */ - typedef struct DeStateStoreItem_ { uint32_t flags; SigIntId sid; @@ -120,30 +105,6 @@ typedef struct DetectEngineState_ { DetectEngineStateDirection dir_state[2]; } DetectEngineState; -/* FLOW BASED (AMATCH) */ - -typedef struct DeStateStoreFlowRule_ { - const SigMatchData *nm; - uint32_t flags; - SigIntId sid; -} DeStateStoreFlowRule; - -typedef struct DeStateStoreFlowRules_ { - DeStateStoreFlowRule store[DE_STATE_CHUNK_SIZE]; - struct DeStateStoreFlowRules_ *next; -} DeStateStoreFlowRules; - -typedef struct DetectEngineStateDirectionFlow_ { - DeStateStoreFlowRules *head; - DeStateStoreFlowRules *tail; - SigIntId cnt; - uint8_t flags; -} DetectEngineStateDirectionFlow; - -typedef struct DetectEngineStateFlow_ { - DetectEngineStateDirectionFlow dir_state[2]; -} DetectEngineStateFlow; - /** * \brief Alloc a DetectEngineState object. * @@ -157,7 +118,6 @@ DetectEngineState *DetectEngineStateAlloc(void); * \param state DetectEngineState instance to free. */ void DetectEngineStateFree(DetectEngineState *state); -void DetectEngineStateFlowFree(DetectEngineStateFlow *state); /** * \brief Check if a flow already contains(newly updated as well) de state. @@ -216,14 +176,6 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, */ void DeStateUpdateInspectTransactionId(Flow *f, const uint8_t flags); -/** - * \brief Reset a DetectEngineState state. - * - * \param state Pointer to the state(LOCKED). - * \param direction Direction flags - STREAM_TOSERVER or STREAM_TOCLIENT. - */ -void DetectEngineStateReset(DetectEngineStateFlow *state, uint8_t direction); - void DetectEngineStateResetTxs(Flow *f); void DeStateRegisterTests(void); diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index e6684cff7370..084f9dde3165 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -225,8 +225,6 @@ static int UriTestSig01(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -349,8 +347,6 @@ static int UriTestSig02(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -473,8 +469,6 @@ static int UriTestSig03(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -597,8 +591,6 @@ static int UriTestSig04(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -721,8 +713,6 @@ static int UriTestSig05(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -845,8 +835,6 @@ static int UriTestSig06(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -969,8 +957,6 @@ static int UriTestSig07(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -1093,8 +1079,6 @@ static int UriTestSig08(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -1217,8 +1201,6 @@ static int UriTestSig09(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -1341,8 +1323,6 @@ static int UriTestSig10(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -1466,8 +1446,6 @@ static int UriTestSig11(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -1591,8 +1569,6 @@ static int UriTestSig12(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -1715,8 +1691,6 @@ static int UriTestSig13(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -1840,8 +1814,6 @@ static int UriTestSig14(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -1965,8 +1937,6 @@ static int UriTestSig15(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); @@ -2089,7 +2059,6 @@ static int UriTestSig16(void) } p->alerts.cnt = 0; - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); p->payload = http_buf2; p->payload_len = http_buf2_len; diff --git a/src/detect.c b/src/detect.c index bd58de6567de..780216a30e2f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1105,8 +1105,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh GenericVarFree(pflow->flowvar); pflow->flowvar = NULL; - DetectEngineStateReset(pflow->de_state, - (STREAM_TOSERVER|STREAM_TOCLIENT)); DetectEngineStateResetTxs(pflow); } @@ -1236,9 +1234,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* initialize to 0(DE_STATE_MATCH_HAS_NEW_STATE) */ DeStateDetectContinueDetection(th_v, de_ctx, det_ctx, p, pflow, flow_flags, alproto, alversion); - } else if (has_inspectable_state == 2) { - /* no inspectable state, so pretend we don't have a state at all */ - has_state = 0; } } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); diff --git a/src/flow-util.h b/src/flow-util.h index 8eea21ee4207..c0b8c06967fe 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -61,7 +61,6 @@ (f)->detect_alversion[1] = 0; \ (f)->alparser = NULL; \ (f)->alstate = NULL; \ - (f)->de_state = NULL; \ (f)->sgh_toserver = NULL; \ (f)->sgh_toclient = NULL; \ (f)->flowvar = NULL; \ @@ -102,9 +101,6 @@ (f)->thread_id = 0; \ (f)->detect_alversion[0] = 0; \ (f)->detect_alversion[1] = 0; \ - if ((f)->de_state != NULL) { \ - DetectEngineStateReset((f)->de_state, (STREAM_TOSERVER | STREAM_TOCLIENT)); \ - } \ (f)->sgh_toserver = NULL; \ (f)->sgh_toclient = NULL; \ GenericVarFree((f)->flowvar); \ @@ -118,9 +114,6 @@ SC_ATOMIC_DESTROY((f)->use_cnt); \ \ FLOWLOCK_DESTROY((f)); \ - if ((f)->de_state != NULL) { \ - DetectEngineStateFlowFree((f)->de_state); \ - } \ GenericVarFree((f)->flowvar); \ } while(0) diff --git a/src/flow.h b/src/flow.h index d6660dd00c25..35ba26f589b8 100644 --- a/src/flow.h +++ b/src/flow.h @@ -386,7 +386,7 @@ typedef struct Flow_ /** 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. */ + * stored sgh ptrs are reset. */ uint32_t de_ctx_id; /** Thread ID for the stream/detect portion of this flow */ @@ -401,9 +401,6 @@ typedef struct Flow_ AppLayerParserState *alparser; /**< parser internal state */ void *alstate; /**< application layer state */ - /** detection engine state */ - struct DetectEngineStateFlow_ *de_state; - /** toclient sgh for this flow. Only use when FLOW_SGH_TOCLIENT flow flag * has been set. */ const struct SigGroupHead_ *sgh_toclient; From fe415ae5185e4a985a1c70cf937a949ac4baf9fb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 22 Dec 2016 23:56:48 +0100 Subject: [PATCH 2423/2553] detect: remove DMATCH list --- src/detect-bytejump.c | 22 +++-- src/detect-bytetest.c | 20 ++-- src/detect-content.c | 58 ++++++------ src/detect-dce-stub-data.c | 163 ++++++++++++++++++++++++++++++++- src/detect-engine-dcepayload.c | 87 +++++++++--------- src/detect-engine-dcepayload.h | 4 +- src/detect-engine-state.c | 52 ----------- src/detect-engine-state.h | 7 +- src/detect-engine.c | 2 - src/detect-isdataat.c | 27 +++--- src/detect-parse.c | 7 -- src/detect-pcre.c | 26 +++--- src/detect.c | 5 - src/detect.h | 3 - 14 files changed, 292 insertions(+), 191 deletions(-) diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 246f1faab767..e09e3f7b7cef 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -640,6 +640,7 @@ static void DetectBytejumpFree(void *ptr) #ifdef UNITTESTS #include "util-unittest-helper.h" static int g_file_data_buffer_id = 0; +static int g_dce_stub_data_buffer_id = 0; /** * \test DetectBytejumpTestParse01 is a test to make sure that we return @@ -832,7 +833,7 @@ static int DetectBytejumpTestParse09(void) result &= (DetectBytejumpSetup(NULL, s, "4,0, string, oct, dce") == -1); result &= (DetectBytejumpSetup(NULL, s, "4,0, string, hex, dce") == -1); result &= (DetectBytejumpSetup(NULL, s, "4,0, from_beginning, dce") == -1); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); return result; @@ -865,12 +866,12 @@ static int DetectBytejumpTestParse10(void) goto end; } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTEJUMP); - bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTEJUMP); + bd = (DetectBytejumpData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (!(bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && @@ -892,12 +893,12 @@ static int DetectBytejumpTestParse10(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTEJUMP); - bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTEJUMP); + bd = (DetectBytejumpData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (!(bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && @@ -919,12 +920,12 @@ static int DetectBytejumpTestParse10(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTEJUMP); - bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTEJUMP); + bd = (DetectBytejumpData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if ((bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && @@ -1290,6 +1291,7 @@ static void DetectBytejumpRegisterTests(void) { #ifdef UNITTESTS g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01); UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02); diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index c51483dd8e9c..49e58ad7d205 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -578,6 +578,7 @@ static void DetectBytetestFree(void *ptr) #ifdef UNITTESTS #include "util-unittest-helper.h" static int g_file_data_buffer_id = 0; +static int g_dce_stub_data_buffer_id = 0; /** * \test DetectBytetestTestParse01 is a test to make sure that we return "something" @@ -1020,12 +1021,12 @@ static int DetectBytetestTestParse20(void) goto end; } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTETEST); - bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTETEST); + bd = (DetectBytetestData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (!(bd->flags & DETECT_BYTETEST_DCE) && !(bd->flags & DETECT_BYTETEST_RELATIVE) && (bd->flags & DETECT_BYTETEST_STRING) && @@ -1047,12 +1048,12 @@ static int DetectBytetestTestParse20(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTETEST); - bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTETEST); + bd = (DetectBytetestData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (!(bd->flags & DETECT_BYTETEST_DCE) && !(bd->flags & DETECT_BYTETEST_RELATIVE) && (bd->flags & DETECT_BYTETEST_STRING) && @@ -1074,12 +1075,12 @@ static int DetectBytetestTestParse20(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTETEST); - bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTETEST); + bd = (DetectBytetestData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if ((bd->flags & DETECT_BYTETEST_DCE) && !(bd->flags & DETECT_BYTETEST_RELATIVE) && (bd->flags & DETECT_BYTETEST_STRING) && @@ -1436,6 +1437,7 @@ static void DetectBytetestRegisterTests(void) { #ifdef UNITTESTS g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); UtRegisterTest("DetectBytetestTestParse01", DetectBytetestTestParse01); UtRegisterTest("DetectBytetestTestParse02", DetectBytetestTestParse02); diff --git a/src/detect-content.c b/src/detect-content.c index 9c77013875e4..42fb944738df 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -425,6 +425,7 @@ void DetectContentFree(void *ptr) #ifdef UNITTESTS /* UNITTESTS */ static int g_file_data_buffer_id = 0; +static int g_dce_stub_data_buffer_id = 0; /** * \test DetectCotentParseTest01 this is a test to make sure we can deal with escaped colons @@ -1133,7 +1134,7 @@ static int DetectContentParseTest18(void) s->alproto = ALPROTO_DCERPC; result &= (DetectContentSetup(de_ctx, s, "\"one\"") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); @@ -1142,7 +1143,7 @@ static int DetectContentParseTest18(void) return 0; result &= (DetectContentSetup(de_ctx, s, "\"one\"") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); end: SigFree(s); @@ -1178,13 +1179,13 @@ static int DetectContentParseTest19(void) goto end; } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1207,13 +1208,13 @@ static int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || @@ -1238,13 +1239,13 @@ static int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1256,7 +1257,7 @@ static int DetectContentParseTest19(void) goto end; } result &= (data->offset == 5 && data->depth == 9); - data = (DetectContentData *)s->sm_lists[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || @@ -1279,13 +1280,13 @@ static int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1309,13 +1310,13 @@ static int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || @@ -1339,13 +1340,13 @@ static int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1369,13 +1370,13 @@ static int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1399,13 +1400,13 @@ static int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1427,7 +1428,7 @@ static int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } @@ -2849,6 +2850,7 @@ static void DetectContentRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01); UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02); diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index bc4831ebb3fe..fa9788fd2ada 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -19,6 +19,7 @@ * \file * * \author Anoop Saldanha + * \author Anoop Saldanha * * Implements dce_stub_data keyword */ @@ -31,6 +32,8 @@ #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" #include "flow.h" #include "flow-var.h" @@ -40,7 +43,9 @@ #include "app-layer-dcerpc.h" #include "queue.h" #include "stream-tcp-reassemble.h" + #include "detect-dce-stub-data.h" +#include "detect-dce-iface.h" #include "util-debug.h" @@ -49,9 +54,140 @@ #include "stream-tcp.h" +#define BUFFER_NAME "dce_stub_data" +#define KEYWORD_NAME "dce_stub_data" + static int DetectDceStubDataSetup(DetectEngineCtx *, Signature *, char *); static void DetectDceStubDataRegisterTests(void); +static int g_dce_stub_data_buffer_id = 0; + +/** \brief DCERPC Stub Data Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxDceStubDataRequest(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); + if (dcerpc_state == NULL) + return; + + uint32_t buffer_len = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len; + const uint8_t *buffer = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxDceStubDataRequestRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxDceStubDataRequest, + ALPROTO_DCERPC, 0, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + if (r == 0) { + r = PrefilterAppendTxEngine(sgh, PrefilterTxDceStubDataRequest, + ALPROTO_SMB, 0, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + } + return r; +} + +/** \brief DCERPC Stub Data Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxDceStubDataResponse(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); + if (dcerpc_state == NULL) + return; + + uint32_t buffer_len = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer_len; + const uint8_t *buffer = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxDceStubDataResponseRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxDceStubDataResponse, + ALPROTO_DCERPC, 0, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + if (r == 0) { + r = PrefilterAppendTxEngine(sgh, PrefilterTxDceStubDataResponse, + ALPROTO_SMB, 0, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + } + return r; +} + +static int InspectEngineDceStubData(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + uint32_t buffer_len = 0; + uint8_t *buffer = NULL; + + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); + if (dcerpc_state == NULL) + goto end; + + if (flags & STREAM_TOSERVER) { + buffer_len = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len; + buffer = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer; + } else if (flags & STREAM_TOCLIENT) { + buffer_len = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer_len; + buffer = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer; + } + + if (buffer == NULL ||buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, + dcerpc_state); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + +end: + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} /** * \brief Registers the keyword handlers for the "dce_stub_data" keyword. */ @@ -66,7 +202,26 @@ void DetectDceStubDataRegister(void) sigmatch_table[DETECT_DCE_STUB_DATA].flags |= SIGMATCH_NOOPT; sigmatch_table[DETECT_DCE_STUB_DATA].flags |= SIGMATCH_PAYLOAD; - return; + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxDceStubDataRequestRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxDceStubDataResponseRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_DCERPC, SIG_FLAG_TOSERVER, + InspectEngineDceStubData); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_DCERPC, SIG_FLAG_TOCLIENT, + InspectEngineDceStubData); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SMB, SIG_FLAG_TOSERVER, + InspectEngineDceStubData); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SMB, SIG_FLAG_TOCLIENT, + InspectEngineDceStubData); + + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); } /** @@ -89,7 +244,7 @@ static int DetectDceStubDataSetup(DetectEngineCtx *de_ctx, Signature *s, char *a goto error; } - s->init_data->list = DETECT_SM_LIST_DMATCH; + s->init_data->list = g_dce_stub_data_buffer_id; s->alproto = ALPROTO_DCERPC; s->flags |= SIG_FLAG_APPLAYER; return 0; @@ -110,7 +265,7 @@ static int DetectDceStubDataTestParse01(void) Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (dce_stub_data; content:\"1\"; sid:1;)"); FAIL_IF_NULL(s); - FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_DMATCH]); + FAIL_IF_NULL(s->sm_lists[g_dce_stub_data_buffer_id]); DetectEngineCtxFree(de_ctx); PASS; } diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index cfb60a54fc1d..0ed15ec5f623 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -49,6 +49,9 @@ #include "detect-dce-iface.h" +static int g_dce_stub_data_buffer_id = 0; + +#if 0 /** * \brief Do the content inspection & validation for a signature against dce stub. * @@ -73,7 +76,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, uint16_t dce_stub_data_len; int r = 0; - if (s->sm_arrays[DETECT_SM_LIST_DMATCH] == NULL || dcerpc_state == NULL) { + if (s->sm_arrays[g_dce_stub_data_buffer_id] == NULL || dcerpc_state == NULL) { SCReturnInt(0); } @@ -87,13 +90,13 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[DETECT_SM_LIST_DMATCH], + r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[g_dce_stub_data_buffer_id], f, dce_stub_data, dce_stub_data_len, 0, 0, dcerpc_state); - //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->init_data->smlists[DETECT_SM_LIST_DMATCH], f, + //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->init_data->smlists[g_dce_stub_data_buffer_id], f, //dce_stub_data, dce_stub_data_len, dcerpc_state); if (r == 1) { SCReturnInt(1); @@ -110,13 +113,13 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[DETECT_SM_LIST_DMATCH], + r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[g_dce_stub_data_buffer_id], f, dce_stub_data, dce_stub_data_len, 0, 0, dcerpc_state); - //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->init_data->smlists[DETECT_SM_LIST_DMATCH], f, + //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->init_data->smlists[g_dce_stub_data_buffer_id], f, //dce_stub_data, dce_stub_data_len, dcerpc_state); if (r == 1) { SCReturnInt(1); @@ -125,6 +128,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, SCReturnInt(0); } +#endif /**************************************Unittests*******************************/ @@ -7500,7 +7504,7 @@ static int DcePayloadParseTest25(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } @@ -7623,7 +7627,7 @@ static int DcePayloadParseTest26(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } @@ -7749,7 +7753,7 @@ static int DcePayloadParseTest27(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -7758,7 +7762,7 @@ static int DcePayloadParseTest27(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -7876,7 +7880,7 @@ static int DcePayloadParseTest28(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -7885,7 +7889,7 @@ static int DcePayloadParseTest28(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8005,7 +8009,7 @@ static int DcePayloadParseTest29(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } @@ -8147,7 +8151,7 @@ static int DcePayloadParseTest30(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } @@ -8294,7 +8298,7 @@ static int DcePayloadParseTest31(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -8303,7 +8307,7 @@ static int DcePayloadParseTest31(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -8441,7 +8445,7 @@ static int DcePayloadParseTest32(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -8450,7 +8454,7 @@ static int DcePayloadParseTest32(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -8588,7 +8592,7 @@ static int DcePayloadParseTest33(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -8597,7 +8601,7 @@ static int DcePayloadParseTest33(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -8731,7 +8735,7 @@ static int DcePayloadParseTest34(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -8740,7 +8744,7 @@ static int DcePayloadParseTest34(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -8852,7 +8856,7 @@ static int DcePayloadParseTest35(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -8861,7 +8865,7 @@ static int DcePayloadParseTest35(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; @@ -8940,7 +8944,7 @@ static int DcePayloadParseTest36(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -8949,7 +8953,7 @@ static int DcePayloadParseTest36(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_ISDATAAT) { result = 0; goto end; @@ -9045,7 +9049,7 @@ static int DcePayloadParseTest37(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -9054,7 +9058,7 @@ static int DcePayloadParseTest37(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -9154,7 +9158,7 @@ static int DcePayloadParseTest38(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -9163,7 +9167,7 @@ static int DcePayloadParseTest38(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -9270,7 +9274,7 @@ static int DcePayloadParseTest39(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -9301,7 +9305,7 @@ static int DcePayloadParseTest39(void) result &= (sm->next == NULL); - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || @@ -9359,7 +9363,7 @@ static int DcePayloadParseTest40(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -9368,7 +9372,7 @@ static int DcePayloadParseTest40(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9489,7 +9493,7 @@ static int DcePayloadParseTest41(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -9498,7 +9502,7 @@ static int DcePayloadParseTest41(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9818,11 +9822,11 @@ static int DcePayloadParseTest44(void) "sid:1;)"); FAIL_IF_NULL(s); - FAIL_IF_NULL(s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH]); + FAIL_IF_NULL(s->init_data->smlists_tail[g_dce_stub_data_buffer_id]); FAIL_IF_NULL(s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); /* isdataat:10,relative; */ - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; FAIL_IF(sm->type != DETECT_ISDATAAT); isd = (DetectIsdataatData *)sm->ctx; FAIL_IF(isd->flags & ISDATAAT_RAWBYTES); @@ -9913,7 +9917,7 @@ static int DcePayloadParseTest45(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -9922,7 +9926,7 @@ static int DcePayloadParseTest45(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -10025,7 +10029,7 @@ static int DcePayloadParseTest46(void) goto end; } - if (s->init_data->smlists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } @@ -10034,7 +10038,7 @@ static int DcePayloadParseTest46(void) goto end; } - sm = s->init_data->smlists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; @@ -10108,6 +10112,7 @@ static int DcePayloadParseTest46(void) void DcePayloadRegisterTests(void) { + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); #ifdef UNITTESTS UtRegisterTest("DcePayloadTest01", DcePayloadTest01); diff --git a/src/detect-engine-dcepayload.h b/src/detect-engine-dcepayload.h index da7dfb92996e..d67a3cffe093 100644 --- a/src/detect-engine-dcepayload.h +++ b/src/detect-engine-dcepayload.h @@ -24,8 +24,8 @@ #ifndef __DETECT_ENGINE_DCEPAYLOAD_H__ #define __DETECT_ENGINE_DCEPAYLOAD_H__ -int DetectEngineInspectDcePayload(DetectEngineCtx *, DetectEngineThreadCtx *, - const Signature *, Flow *, uint8_t, void *); +//int DetectEngineInspectDcePayload(DetectEngineCtx *, DetectEngineThreadCtx *, +// const Signature *, Flow *, uint8_t, void *); void DcePayloadRegisterTests(void); diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index c499a08fe936..8a860e982f84 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -303,12 +303,6 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, return r; } -static int StoreState(Flow *f, const uint8_t flags, const uint8_t alversion) -{ - DeStateStoreStateVersion(f, alversion, flags); - return 1; -} - static void StoreStateTxHandleFiles(DetectEngineThreadCtx *det_ctx, Flow *f, DetectEngineState *destate, const uint8_t flags, const uint64_t tx_id, const uint16_t file_no_match) @@ -383,7 +377,6 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, uint16_t file_no_match = 0; uint32_t inspect_flags = 0; int alert_cnt = 0; - int dmatch = 0; SCLogDebug("rule %u", s->id); @@ -517,51 +510,6 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, break; } /* for */ } - /* DCERPC matches */ - if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL && - (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || - alproto == ALPROTO_SMB2)) - { - void *alstate = FlowGetAppState(f); - if (alstate == NULL) { - goto end; - } - - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_DMATCH); - if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, - flags, alstate) == 1) { - inspect_flags |= DE_STATE_FLAG_DCE_PAYLOAD_INSPECT; - dmatch = 1; - } - } - - /* if AMATCH and/or DMATCH are in use, see if we need to - * alert and store the state */ - if (s->sm_arrays[DETECT_SM_LIST_DMATCH] != NULL) - { - /* if dmatch in use and match - or - sig can't match - */ - if (inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) { - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; - } else { - if (dmatch || s->sm_arrays[DETECT_SM_LIST_DMATCH] == NULL) - { - if (!(s->flags & SIG_FLAG_NOALERT)) { - PacketAlertAppend(det_ctx, s, p, 0, - PACKET_ALERT_FLAG_STATE_MATCH); - } else { - DetectSignatureApplyActions(p, s); - } - alert_cnt = 1; - - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; - } - } - - StoreState(f, flags, alversion); - } end: det_ctx->tx_id = 0; det_ctx->tx_id_set = 0; diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 9215739841cc..d1b789da7240 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -53,12 +53,11 @@ #define DE_STATE_FLAG_FULL_INSPECT BIT_U32(0) #define DE_STATE_FLAG_SIG_CANT_MATCH BIT_U32(1) -#define DE_STATE_FLAG_DCE_PAYLOAD_INSPECT BIT_U32(2) -#define DE_STATE_FLAG_FILE_TC_INSPECT BIT_U32(3) -#define DE_STATE_FLAG_FILE_TS_INSPECT BIT_U32(4) +#define DE_STATE_FLAG_FILE_TC_INSPECT BIT_U32(2) +#define DE_STATE_FLAG_FILE_TS_INSPECT BIT_U32(3) /* first bit position after the built-ins */ -#define DE_STATE_FLAG_BASE 5UL +#define DE_STATE_FLAG_BASE 4UL /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine.c b/src/detect-engine.c index b8ed69605824..594e30131933 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2906,8 +2906,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_PMATCH: return "packet/stream payload"; - case DETECT_SM_LIST_DMATCH: - return "dcerpc"; case DETECT_SM_LIST_TMATCH: return "tag"; diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 5a018a5891b9..6eb098141d9c 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -290,6 +290,7 @@ void DetectIsdataatFree(void *ptr) #ifdef UNITTESTS +static int g_dce_stub_data_buffer_id = 0; /** * \test DetectIsdataatTestParse01 is a test to make sure that we return a correct IsdataatData structure @@ -353,14 +354,14 @@ int DetectIsdataatTestParse04(void) s->alproto = ALPROTO_DCERPC; result &= (DetectIsdataatSetup(NULL, s, "30") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); s = SigAlloc(); s->alproto = ALPROTO_DCERPC; /* failure since we have no preceding content/pcre/bytejump */ result &= (DetectIsdataatSetup(NULL, s, "30,relative") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); @@ -393,12 +394,12 @@ int DetectIsdataatTestParse05(void) goto end; } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_ISDATAAT); + data = (DetectIsdataatData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) ) { result = 0; @@ -416,12 +417,12 @@ int DetectIsdataatTestParse05(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_ISDATAAT); + data = (DetectIsdataatData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) ) { result = 0; @@ -439,12 +440,12 @@ int DetectIsdataatTestParse05(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_ISDATAAT); + data = (DetectIsdataatData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || !(data->flags & ISDATAAT_RAWBYTES) ) { result = 0; @@ -459,7 +460,7 @@ int DetectIsdataatTestParse05(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } @@ -628,6 +629,8 @@ int DetectIsdataatTestPacket03 (void) void DetectIsdataatRegisterTests(void) { #ifdef UNITTESTS + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); + UtRegisterTest("DetectIsdataatTestParse01", DetectIsdataatTestParse01); UtRegisterTest("DetectIsdataatTestParse02", DetectIsdataatTestParse02); UtRegisterTest("DetectIsdataatTestParse03", DetectIsdataatTestParse03); diff --git a/src/detect-parse.c b/src/detect-parse.c index 7bce331188ba..6385500f171c 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -141,7 +141,6 @@ const char *DetectListToHumanString(int list) switch (list) { CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); - CASE_CODE_STRING(DETECT_SM_LIST_DMATCH, "dcerpc"); CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress"); @@ -158,7 +157,6 @@ const char *DetectListToString(int list) switch (list) { CASE_CODE(DETECT_SM_LIST_MATCH); CASE_CODE(DETECT_SM_LIST_PMATCH); - CASE_CODE(DETECT_SM_LIST_DMATCH); CASE_CODE(DETECT_SM_LIST_TMATCH); CASE_CODE(DETECT_SM_LIST_POSTMATCH); CASE_CODE(DETECT_SM_LIST_SUPPRESS); @@ -1598,11 +1596,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, } } - if (sig->init_data->smlists[DETECT_SM_LIST_DMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - /* for other lists this flag is set when the inspect engines - * are registered */ - if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) { sig->flags |= SIG_FLAG_TOSERVER; sig->flags |= SIG_FLAG_TOCLIENT; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index e531d6a2cbff..d4e3bbe8a0d0 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -770,6 +770,7 @@ void DetectPcreFree(void *ptr) #ifdef UNITTESTS /* UNITTESTS */ static int g_file_data_buffer_id = 0; static int g_http_header_buffer_id = 0; +static int g_dce_stub_data_buffer_id = 0; /** * \test DetectPcreParseTest01 make sure we don't allow invalid opts 7. @@ -960,7 +961,7 @@ int DetectPcreParseTest10(void) s->alproto = ALPROTO_DCERPC; FAIL_IF_NOT(DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); - FAIL_IF_NOT(s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + FAIL_IF_NOT(s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); @@ -969,7 +970,7 @@ int DetectPcreParseTest10(void) /* failure since we have no preceding content/pcre/bytejump */ FAIL_IF_NOT(DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); - FAIL_IF_NOT(s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + FAIL_IF_NOT(s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); DetectEngineCtxFree(de_ctx); @@ -997,9 +998,9 @@ int DetectPcreParseTest11(void) "pcre:/bamboo/R; sid:1;)"); FAIL_IF(de_ctx == NULL); s = de_ctx->sig_list; - FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL); - FAIL_IF_NOT(s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL); + FAIL_IF_NOT(s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_PCRE); + data = (DetectPcreData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE)); @@ -1010,9 +1011,9 @@ int DetectPcreParseTest11(void) "pcre:/bamboo/R; sid:1;)"); FAIL_IF_NULL(s->next); s = s->next; - FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL); - FAIL_IF_NOT(s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL); + FAIL_IF_NOT(s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_PCRE); + data = (DetectPcreData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE)); @@ -1023,9 +1024,9 @@ int DetectPcreParseTest11(void) "pcre:/bamboo/RB; sid:1;)"); FAIL_IF(s->next == NULL); s = s->next; - FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL); - FAIL_IF_NOT(s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL); + FAIL_IF_NOT(s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_PCRE); + data = (DetectPcreData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; FAIL_IF(!(data->flags & DETECT_PCRE_RAWBYTES) || !(data->flags & DETECT_PCRE_RELATIVE)); @@ -1034,7 +1035,7 @@ int DetectPcreParseTest11(void) "content:\"one\"; pcre:/bamboo/; sid:1;)"); FAIL_IF(s->next == NULL); s = s->next; - FAIL_IF(s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL); + FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] != NULL); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -3312,6 +3313,7 @@ void DetectPcreRegisterTests(void) #ifdef UNITTESTS /* UNITTESTS */ g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01); UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02); diff --git a/src/detect.c b/src/detect.c index 780216a30e2f..4906c52f49ae 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2221,11 +2221,6 @@ static int SignatureCreateMask(Signature *s) SCLogDebug("sig requires payload"); } - if (s->init_data->smlists[DETECT_SM_LIST_DMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_DCE_STATE; - SCLogDebug("sig requires dce state"); - } - SigMatch *sm; for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { diff --git a/src/detect.h b/src/detect.h index 0580fa779af8..2e01c5f3a2b8 100644 --- a/src/detect.h +++ b/src/detect.h @@ -88,9 +88,6 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_MATCH = 0, DETECT_SM_LIST_PMATCH, - /* list for DCE matches */ - DETECT_SM_LIST_DMATCH, - /* base64_data keyword uses some hardcoded logic so consider * built-in * TODO convert to inspect engine */ From 5bafc64c089daaa1d642d8765da5e1eada14641e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 13:57:12 +0100 Subject: [PATCH 2424/2553] detect: unify FileMatch API with other calls --- src/detect-engine-file.c | 4 ++-- src/detect-fileext.c | 6 +++--- src/detect-filemagic.c | 6 +++--- src/detect-filename.c | 6 +++--- src/detect-filesize.c | 6 +++--- src/detect-filestore.c | 4 ++-- src/detect.h | 2 +- src/util-detect-file-hash.c | 4 ++-- src/util-detect-file-hash.h | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index 9464799b4c05..771a4c2983bf 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -152,7 +152,7 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, if (sigmatch_table[smd->type].FileMatch != NULL) { KEYWORD_PROFILING_START; match = sigmatch_table[smd->type]. - FileMatch(tv, det_ctx, f, flags, file, s, smd); + FileMatch(tv, det_ctx, f, flags, file, s, smd->ctx); KEYWORD_PROFILING_END(det_ctx, smd->type, (match > 0)); if (match == 0) { r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; @@ -191,7 +191,7 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, if (fd->scope > FILESTORE_SCOPE_DEFAULT) { KEYWORD_PROFILING_START; match = sigmatch_table[smd->type]. - FileMatch(tv, det_ctx, f, flags, /* no file */NULL, s, smd); + FileMatch(tv, det_ctx, f, flags, /* no file */NULL, s, smd->ctx); KEYWORD_PROFILING_END(det_ctx, smd->type, (match > 0)); if (match == 1) { diff --git a/src/detect-fileext.c b/src/detect-fileext.c index eecc63ffe5d1..a052d97d7523 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -52,7 +52,7 @@ #include "detect-fileext.h" static int DetectFileextMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, const Signature *, const SigMatchData *); + uint8_t, File *, const Signature *, const SigMatchCtx *); static int DetectFileextSetup (DetectEngineCtx *, Signature *, char *); static void DetectFileextRegisterTests(void); static void DetectFileextFree(void *); @@ -92,12 +92,12 @@ void DetectFileextRegister(void) * \retval 1 match */ static int DetectFileextMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { SCEnter(); int ret = 0; - DetectFileextData *fileext = (DetectFileextData *)m->ctx; + DetectFileextData *fileext = (DetectFileextData *)m; if (file->name == NULL) SCReturnInt(0); diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index dbf1dd767e49..34f6c6fca0ce 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -76,7 +76,7 @@ void DetectFilemagicRegister(void) #else /* HAVE_MAGIC */ static int DetectFilemagicMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, const Signature *, const SigMatchData *); + uint8_t, File *, const Signature *, const SigMatchCtx *); static int DetectFilemagicSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilemagicRegisterTests(void); static void DetectFilemagicFree(void *); @@ -179,11 +179,11 @@ int FilemagicThreadLookup(magic_t *ctx, File *file) * \retval 1 match */ static int DetectFilemagicMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { SCEnter(); int ret = 0; - DetectFilemagicData *filemagic = (DetectFilemagicData *)m->ctx; + DetectFilemagicData *filemagic = (DetectFilemagicData *)m; if (file->txid < det_ctx->tx_id) SCReturnInt(0); diff --git a/src/detect-filename.c b/src/detect-filename.c index 67b386b2f76a..fcfff9b3997f 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -53,7 +53,7 @@ #include "app-layer-parser.h" static int DetectFilenameMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, const Signature *, const SigMatchData *); + uint8_t, File *, const Signature *, const SigMatchCtx *); static int DetectFilenameSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilenameRegisterTests(void); static void DetectFilenameFree(void *); @@ -104,12 +104,12 @@ void DetectFilenameRegister(void) * \retval 1 match */ static int DetectFilenameMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { SCEnter(); int ret = 0; - DetectFilenameData *filename = (DetectFilenameData *)m->ctx; + DetectFilenameData *filename = (DetectFilenameData *)m; if (file->name == NULL) SCReturnInt(0); diff --git a/src/detect-filesize.c b/src/detect-filesize.c index 547ea38963e9..af08f48baec4 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -50,7 +50,7 @@ static pcre_extra *parse_regex_study; /*prototypes*/ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, const Signature *s, const SigMatchData *m); + uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m); static int DetectFilesizeSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilesizeFree (void *); static void DetectFilesizeRegisterTests (void); @@ -91,11 +91,11 @@ void DetectFilesizeRegister(void) * \retval 1 match */ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, const Signature *s, const SigMatchData *m) + uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectFilesizeData *fsd = (DetectFilesizeData *)m->ctx; + DetectFilesizeData *fsd = (DetectFilesizeData *)m; int ret = 0; uint64_t file_size = FileTrackedSize(file); diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 6801e8cbf0ac..d64b9b44d881 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -60,7 +60,7 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectFilestoreMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, File *, const Signature *, const SigMatchData *); + Flow *, uint8_t, File *, const Signature *, const SigMatchCtx *); static int DetectFilestoreSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilestoreFree(void *); static void DetectFilestoreRegisterTests(void); @@ -249,7 +249,7 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack * needs to be put behind a api. */ static int DetectFilestoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, const Signature *s, const SigMatchData *m) + uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { uint16_t file_id = 0; diff --git a/src/detect.h b/src/detect.h index 2e01c5f3a2b8..3d3290cdcf44 100644 --- a/src/detect.h +++ b/src/detect.h @@ -927,7 +927,7 @@ typedef struct SigTableElmt_ { int (*FileMatch)(ThreadVars *, /**< thread local vars */ DetectEngineThreadCtx *, Flow *, /**< *LOCKED* flow */ - uint8_t flags, File *, const Signature *, const SigMatchData *); + uint8_t flags, File *, const Signature *, const SigMatchCtx *); /** keyword setup function pointer */ int (*Setup)(DetectEngineCtx *, Signature *, char *); diff --git a/src/util-detect-file-hash.c b/src/util-detect-file-hash.c index e7e157bd9eef..7ee4bd956878 100644 --- a/src/util-detect-file-hash.c +++ b/src/util-detect-file-hash.c @@ -147,11 +147,11 @@ static int HashMatchHashTable(ROHashTable *hash_table, uint8_t *hash, * \retval 1 match */ int DetectFileHashMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchData *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { SCEnter(); int ret = 0; - DetectFileHashData *filehash = (DetectFileHashData *)m->ctx; + DetectFileHashData *filehash = (DetectFileHashData *)m; if (file->txid < det_ctx->tx_id) { SCReturnInt(0); diff --git a/src/util-detect-file-hash.h b/src/util-detect-file-hash.h index b8d50789344e..68fd34dd6fd6 100644 --- a/src/util-detect-file-hash.h +++ b/src/util-detect-file-hash.h @@ -38,7 +38,7 @@ int ReadHashString(uint8_t *, char *, char *, int, uint16_t); int LoadHashTable(ROHashTable *, char *, char *, int, uint32_t); int DetectFileHashMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - File *, const Signature *, const SigMatchData *); + File *, const Signature *, const SigMatchCtx *); int DetectFileHashSetup(DetectEngineCtx *, Signature *, char *, uint32_t, int); void DetectFileHashFree(void *); From 073fcbeb7fb70fbf576eda841c07a4ba0fe0c4cc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 13:59:25 +0100 Subject: [PATCH 2425/2553] detect: move file hash common code --- src/Makefile.am | 2 +- src/{util-detect-file-hash.c => detect-file-hash-common.c} | 2 +- src/{util-detect-file-hash.h => detect-file-hash-common.h} | 0 src/detect-filemd5.c | 2 +- src/detect-filesha1.c | 2 +- src/detect-filesha256.c | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename src/{util-detect-file-hash.c => detect-file-hash-common.c} (99%) rename src/{util-detect-file-hash.h => detect-file-hash-common.h} (100%) diff --git a/src/Makefile.am b/src/Makefile.am index 7d505307dba2..6ddbd1d8f6b3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -142,6 +142,7 @@ detect-engine-threshold.c detect-engine-threshold.h \ detect-engine-uri.c detect-engine-uri.h \ detect-fast-pattern.c detect-fast-pattern.h \ detect-file-data.c detect-file-data.h \ +detect-file-hash-common.c detect-file-hash-common.h \ detect-fileext.c detect-fileext.h \ detect-filemagic.c detect-filemagic.h \ detect-filemd5.c detect-filemd5.h \ @@ -364,7 +365,6 @@ util-decode-asn1.c util-decode-asn1.h \ util-decode-der.c util-decode-der.h \ util-decode-der-get.c util-decode-der-get.h \ util-decode-mime.c util-decode-mime.h \ -util-detect-file-hash.c util-detect-file-hash.h \ util-device.c util-device.h \ util-enum.c util-enum.h \ util-error.c util-error.h \ diff --git a/src/util-detect-file-hash.c b/src/detect-file-hash-common.c similarity index 99% rename from src/util-detect-file-hash.c rename to src/detect-file-hash-common.c index 7ee4bd956878..3e5d433d987c 100644 --- a/src/util-detect-file-hash.c +++ b/src/detect-file-hash-common.c @@ -28,7 +28,7 @@ #include "detect.h" #include "detect-parse.h" -#include "util-detect-file-hash.h" +#include "detect-file-hash-common.h" #include "app-layer-htp.h" diff --git a/src/util-detect-file-hash.h b/src/detect-file-hash-common.h similarity index 100% rename from src/util-detect-file-hash.h rename to src/detect-file-hash-common.h diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index a4f3f56dfe7c..29320832fc3c 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -25,7 +25,7 @@ #include "suricata-common.h" #include "detect-engine.h" -#include "util-detect-file-hash.h" +#include "detect-file-hash-common.h" #include "util-unittest.h" #include "util-unittest-helper.h" diff --git a/src/detect-filesha1.c b/src/detect-filesha1.c index 3bb26b5746a1..84fd68929642 100644 --- a/src/detect-filesha1.c +++ b/src/detect-filesha1.c @@ -26,7 +26,7 @@ #include "suricata-common.h" #include "detect-engine.h" -#include "util-detect-file-hash.h" +#include "detect-file-hash-common.h" #include "util-unittest.h" #include "util-unittest-helper.h" diff --git a/src/detect-filesha256.c b/src/detect-filesha256.c index b95831e7da20..59f06d2f7878 100644 --- a/src/detect-filesha256.c +++ b/src/detect-filesha256.c @@ -26,7 +26,7 @@ #include "suricata-common.h" #include "detect-engine.h" -#include "util-detect-file-hash.h" +#include "detect-file-hash-common.h" #include "util-unittest.h" #include "util-unittest-helper.h" From fa1ef158b21f97472d4006c3e1dcc851cc3b9a0a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 14:45:08 +0100 Subject: [PATCH 2426/2553] detect: small API cleanup --- src/detect.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detect.h b/src/detect.h index 3d3290cdcf44..194ca4a923e9 100644 --- a/src/detect.h +++ b/src/detect.h @@ -940,10 +940,10 @@ typedef struct SigTableElmt_ { uint8_t flags; - char *name; /**< keyword name alias */ - char *alias; /**< name alias */ - char *desc; - char *url; + const char *name; /**< keyword name alias */ + const char *alias; /**< name alias */ + const char *desc; + const char *url; } SigTableElmt; From 14ced15e3662b5b49a1d1325d7997884f3fe37f7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 15:17:19 +0100 Subject: [PATCH 2427/2553] detect: remove unused state file flag --- src/detect-engine-state.c | 1 - src/detect-engine-state.h | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 8a860e982f84..e25accf3fd0a 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -311,7 +311,6 @@ static void StoreStateTxHandleFiles(DetectEngineThreadCtx *det_ctx, Flow *f, DeStateStoreFileNoMatchCnt(destate, file_no_match, flags); if (DeStateStoreFilestoreSigsCantMatch(det_ctx->sgh, destate, flags) == 1) { FileDisableStoringForTransaction(f, flags & (STREAM_TOCLIENT | STREAM_TOSERVER), tx_id); - destate->dir_state[flags & STREAM_TOSERVER ? 0 : 1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED; } } diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index d1b789da7240..9c46d84ef4a2 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -59,10 +59,13 @@ /* first bit position after the built-ins */ #define DE_STATE_FLAG_BASE 4UL -/* state flags */ -#define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 -#define DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW 0x0002 -#define DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW 0x0004 +/* state flags + * + * Used by app-layer-parsers to notify us that new files + * are available in the tx. + */ +#define DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW BIT_U8(0) +#define DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW BIT_U8(1) /* We have 2 possible state values to be used by ContinueDetection() while * trying to figure if we have fresh state to install or not. From dfac5276b8a0a3089a43dbeb52d85d75ab4a7494 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 16:03:08 +0100 Subject: [PATCH 2428/2553] detect: remove unused SIGMATCH_PAYLOAD flag --- src/detect-base64-decode.c | 1 - src/detect-byte-extract.c | 2 -- src/detect-bytejump.c | 2 -- src/detect-bytetest.c | 2 -- src/detect-content.c | 2 -- src/detect-dce-iface.c | 2 -- src/detect-dce-opnum.c | 2 -- src/detect-dce-stub-data.c | 1 - src/detect-depth.c | 2 -- src/detect-distance.c | 2 -- src/detect-dnp3.c | 1 - src/detect-dns-query.c | 1 - src/detect-fast-pattern.c | 1 - src/detect-filesize.c | 1 - src/detect-http-client-body.c | 1 - src/detect-http-cookie.c | 1 - src/detect-http-header-names.c | 1 - src/detect-http-header.c | 1 - src/detect-http-hh.c | 1 - src/detect-http-hrh.c | 1 - src/detect-http-method.c | 1 - src/detect-http-protocol.c | 1 - src/detect-http-raw-header.c | 1 - src/detect-http-raw-uri.c | 1 - src/detect-http-request-line.c | 1 - src/detect-http-response-line.c | 1 - src/detect-http-server-body.c | 1 - src/detect-http-start.c | 1 - src/detect-http-stat-code.c | 1 - src/detect-http-stat-msg.c | 1 - src/detect-http-ua.c | 1 - src/detect-http-uri.c | 1 - src/detect-isdataat.c | 2 -- src/detect-nocase.c | 1 - src/detect-offset.c | 2 -- src/detect-pcre.c | 2 -- src/detect-pktvar.c | 2 -- src/detect-rawbytes.c | 1 - src/detect-replace.c | 2 -- src/detect-template-buffer.c | 1 - src/detect-tls-cert-issuer.c | 1 - src/detect-tls-cert-subject.c | 1 - src/detect-tls-sni.c | 1 - src/detect-uricontent.c | 2 -- src/detect-urilen.c | 1 - src/detect-within.c | 2 -- src/detect.c | 19 ------------------- src/detect.h | 6 ++---- 48 files changed, 2 insertions(+), 84 deletions(-) diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index 5bac625e0f1a..354b85dd99ea 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -48,7 +48,6 @@ void DetectBase64DecodeRegister(void) sigmatch_table[DETECT_BASE64_DECODE].RegisterTests = DetectBase64DecodeRegisterTests; - sigmatch_table[DETECT_BASE64_DECODE].flags |= SIGMATCH_PAYLOAD; sigmatch_table[DETECT_BASE64_DECODE].flags |= SIGMATCH_OPTIONAL_OPT; DetectSetupParseRegexes(decode_pattern, &decode_pcre, &decode_pcre_study); diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index a6ab72a01694..07f358367c5d 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -104,8 +104,6 @@ void DetectByteExtractRegister(void) sigmatch_table[DETECT_BYTE_EXTRACT].Free = DetectByteExtractFree; sigmatch_table[DETECT_BYTE_EXTRACT].RegisterTests = DetectByteExtractRegisterTests; - sigmatch_table[DETECT_BYTE_EXTRACT].flags |= SIGMATCH_PAYLOAD; - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index e09e3f7b7cef..872cd56b060d 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -75,8 +75,6 @@ void DetectBytejumpRegister (void) sigmatch_table[DETECT_BYTEJUMP].Free = DetectBytejumpFree; sigmatch_table[DETECT_BYTEJUMP].RegisterTests = DetectBytejumpRegisterTests; - sigmatch_table[DETECT_BYTEJUMP].flags |= SIGMATCH_PAYLOAD; - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 49e58ad7d205..731ad6f4e6af 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -76,8 +76,6 @@ void DetectBytetestRegister (void) sigmatch_table[DETECT_BYTETEST].Free = DetectBytetestFree; sigmatch_table[DETECT_BYTETEST].RegisterTests = DetectBytetestRegisterTests; - sigmatch_table[DETECT_BYTETEST].flags |= SIGMATCH_PAYLOAD; - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } diff --git a/src/detect-content.c b/src/detect-content.c index 42fb944738df..64904b0168f3 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -59,8 +59,6 @@ void DetectContentRegister (void) sigmatch_table[DETECT_CONTENT].Setup = DetectContentSetup; sigmatch_table[DETECT_CONTENT].Free = DetectContentFree; sigmatch_table[DETECT_CONTENT].RegisterTests = DetectContentRegisterTests; - - sigmatch_table[DETECT_CONTENT].flags |= SIGMATCH_PAYLOAD; } /** diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index eec29b3e2d9c..50e74774016e 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -78,8 +78,6 @@ void DetectDceIfaceRegister(void) sigmatch_table[DETECT_DCE_IFACE].Free = DetectDceIfaceFree; sigmatch_table[DETECT_DCE_IFACE].RegisterTests = DetectDceIfaceRegisterTests; - sigmatch_table[DETECT_DCE_IFACE].flags |= SIGMATCH_PAYLOAD; - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); g_dce_generic_list_id = DetectBufferTypeRegister("dce_generic"); diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index f07c921dabee..5417826ea0c7 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -73,8 +73,6 @@ void DetectDceOpnumRegister(void) sigmatch_table[DETECT_DCE_OPNUM].Free = DetectDceOpnumFree; sigmatch_table[DETECT_DCE_OPNUM].RegisterTests = DetectDceOpnumRegisterTests; - sigmatch_table[DETECT_DCE_OPNUM].flags |= SIGMATCH_PAYLOAD; - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); g_dce_generic_list_id = DetectBufferTypeRegister("dce_generic"); diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index fa9788fd2ada..6318e0dfc5f6 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -200,7 +200,6 @@ void DetectDceStubDataRegister(void) sigmatch_table[DETECT_DCE_STUB_DATA].RegisterTests = DetectDceStubDataRegisterTests; sigmatch_table[DETECT_DCE_STUB_DATA].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_DCE_STUB_DATA].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterTxDceStubDataRequestRegister); diff --git a/src/detect-depth.c b/src/detect-depth.c index a78f8a1b96d5..18453178f9e8 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -51,8 +51,6 @@ void DetectDepthRegister (void) sigmatch_table[DETECT_DEPTH].Setup = DetectDepthSetup; sigmatch_table[DETECT_DEPTH].Free = NULL; sigmatch_table[DETECT_DEPTH].RegisterTests = NULL; - - sigmatch_table[DETECT_DEPTH].flags |= SIGMATCH_PAYLOAD; } static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depthstr) diff --git a/src/detect-distance.c b/src/detect-distance.c index c700675f4ae7..10f65284779f 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -57,8 +57,6 @@ void DetectDistanceRegister(void) sigmatch_table[DETECT_DISTANCE].Setup = DetectDistanceSetup; sigmatch_table[DETECT_DISTANCE].Free = NULL; sigmatch_table[DETECT_DISTANCE].RegisterTests = DetectDistanceRegisterTests; - - sigmatch_table[DETECT_DISTANCE].flags |= SIGMATCH_PAYLOAD; } static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c index 4fe63ecd226d..153e151f8e23 100644 --- a/src/detect-dnp3.c +++ b/src/detect-dnp3.c @@ -543,7 +543,6 @@ static void DetectDNP3DataRegister(void) DetectDNP3DataRegisterTests; sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_PAYLOAD; DetectAppLayerInspectEngineRegister("dnp3_data", ALPROTO_DNP3, SIG_FLAG_TOSERVER, diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 815d0059226d..7269df5fcc37 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -75,7 +75,6 @@ void DetectDnsQueryRegister (void) sigmatch_table[DETECT_AL_DNS_QUERY].RegisterTests = DetectDnsQueryRegisterTests; sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("dns_query", SIG_FLAG_TOSERVER, 2, PrefilterTxDnsQueryRegister); diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index c2ae8166e909..ce492cb45507 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -137,7 +137,6 @@ void DetectFastPatternRegister(void) sigmatch_table[DETECT_FAST_PATTERN].RegisterTests = DetectFastPatternRegisterTests; sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_PAYLOAD; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } diff --git a/src/detect-filesize.c b/src/detect-filesize.c index af08f48baec4..151579f27b92 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -69,7 +69,6 @@ void DetectFilesizeRegister(void) sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup; sigmatch_table[DETECT_FILESIZE].Free = DetectFilesizeFree; sigmatch_table[DETECT_FILESIZE].RegisterTests = DetectFilesizeRegisterTests; - sigmatch_table[DETECT_FILESIZE].flags |= SIGMATCH_PAYLOAD; /** XXX necessary? */ DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index a158e137b76b..d227890e218e 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -78,7 +78,6 @@ void DetectHttpClientBodyRegister(void) sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].RegisterTests = DetectHttpClientBodyRegisterTests; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_PAYLOAD ; DetectAppLayerMpmRegister("http_client_body", SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestBodyRegister); diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 3b9eff786cde..391dce187dd2 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -81,7 +81,6 @@ void DetectHttpCookieRegister(void) sigmatch_table[DETECT_AL_HTTP_COOKIE].RegisterTests = DetectHttpCookieRegisterTests; sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("http_cookie", SIG_FLAG_TOSERVER, 2, PrefilterTxRequestCookieRegister); diff --git a/src/detect-http-header-names.c b/src/detect-http-header-names.c index bdb204d2e15e..1fc8f3546ad1 100644 --- a/src/detect-http-header-names.c +++ b/src/detect-http-header-names.c @@ -380,7 +380,6 @@ void DetectHttpHeaderNamesRegister(void) sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].Setup = DetectHttpHeaderNamesSetup; sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].flags |= SIGMATCH_PAYLOAD ; DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestHeaderNamesRegister); diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 5d2e1ec59d21..635d221c22a5 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -393,7 +393,6 @@ void DetectHttpHeaderRegister(void) sigmatch_table[DETECT_AL_HTTP_HEADER].RegisterTests = DetectHttpHeaderRegisterTests; sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_PAYLOAD ; DetectAppLayerMpmRegister("http_header", SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestHeadersRegister); diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 758b978a6fb6..182a49e68597 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -79,7 +79,6 @@ void DetectHttpHHRegister(void) sigmatch_table[DETECT_AL_HTTP_HOST].RegisterTests = DetectHttpHHRegisterTests; sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_PAYLOAD ; DetectAppLayerMpmRegister("http_host", SIG_FLAG_TOSERVER, 2, PrefilterTxHostnameRegister); diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index 8b3620a48be2..a477a5157033 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -78,7 +78,6 @@ void DetectHttpHRHRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HOST].RegisterTests = DetectHttpHRHRegisterTests; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_PAYLOAD ; DetectAppLayerMpmRegister("http_raw_host", SIG_FLAG_TOSERVER, 2, PrefilterTxHostnameRawRegister); diff --git a/src/detect-http-method.c b/src/detect-http-method.c index a4b0feb749d0..433c343291ff 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -80,7 +80,6 @@ void DetectHttpMethodRegister(void) sigmatch_table[DETECT_AL_HTTP_METHOD].Free = DetectHttpMethodFree; sigmatch_table[DETECT_AL_HTTP_METHOD].RegisterTests = DetectHttpMethodRegisterTests; sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("http_method", SIG_FLAG_TOSERVER, 4, PrefilterTxMethodRegister); diff --git a/src/detect-http-protocol.c b/src/detect-http-protocol.c index fbdf22e9c193..e87b034b5061 100644 --- a/src/detect-http-protocol.c +++ b/src/detect-http-protocol.c @@ -216,7 +216,6 @@ void DetectHttpProtocolRegister(void) sigmatch_table[DETECT_AL_HTTP_PROTOCOL].Setup = DetectHttpProtocolSetup; sigmatch_table[DETECT_AL_HTTP_PROTOCOL].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_PROTOCOL].flags |= SIGMATCH_PAYLOAD ; DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestProtocolRegister); diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index 8b2b394cab02..18872b7b4483 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -79,7 +79,6 @@ void DetectHttpRawHeaderRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].RegisterTests = DetectHttpRawHeaderRegisterTests; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOSERVER, 2, PrefilterTxRequestHeadersRawRegister); diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 367be1d595ad..51df60d1b9e7 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -73,7 +73,6 @@ void DetectHttpRawUriRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_URI].Free = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].RegisterTests = DetectHttpRawUriRegisterTests; sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterTxRawUriRegister); diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index 4fb495f3efec..3d4d69b05801 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -83,7 +83,6 @@ void DetectHttpRequestLineRegister(void) sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].RegisterTests = DetectHttpRequestLineRegisterTests; sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].flags |= SIGMATCH_PAYLOAD ; DetectAppLayerMpmRegister("http_request_line", SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestLineRegister); diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index e9b573b07c30..cb28358c922f 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -83,7 +83,6 @@ void DetectHttpResponseLineRegister(void) sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].RegisterTests = DetectHttpResponseLineRegisterTests; sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].flags |= SIGMATCH_PAYLOAD ; DetectAppLayerMpmRegister("http_response_line", SIG_FLAG_TOCLIENT, 2, PrefilterTxHttpResponseLineRegister); diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index eb6f02d31eeb..145995e83929 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -79,7 +79,6 @@ void DetectHttpServerBodyRegister(void) sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].RegisterTests = DetectHttpServerBodyRegisterTests; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_PAYLOAD; g_file_data_buffer_id = DetectBufferTypeRegister("file_data"); } diff --git a/src/detect-http-start.c b/src/detect-http-start.c index b4149301c68a..1e5836b77baa 100644 --- a/src/detect-http-start.c +++ b/src/detect-http-start.c @@ -305,7 +305,6 @@ void DetectHttpStartRegister(void) sigmatch_table[DETECT_AL_HTTP_START].Setup = DetectHttpStartSetup; sigmatch_table[DETECT_AL_HTTP_START].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_START].flags |= SIGMATCH_PAYLOAD ; DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterTxHttpRequestStartRegister); diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index 308ef9a46fb8..80743c92bae1 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -82,7 +82,6 @@ void DetectHttpStatCodeRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_CODE].RegisterTests = DetectHttpStatCodeRegisterTests; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("http_stat_code", SIG_FLAG_TOCLIENT, 4, PrefilterTxHttpStatCodeRegister); diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index 631fb46ab19e..5ae19559ecd2 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -82,7 +82,6 @@ void DetectHttpStatMsgRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_MSG].RegisterTests = DetectHttpStatMsgRegisterTests; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("http_stat_msg", SIG_FLAG_TOCLIENT, 3, PrefilterTxHttpStatMsgRegister); diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index 9a6df63ae1e7..654e72f05b75 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -79,7 +79,6 @@ void DetectHttpUARegister(void) sigmatch_table[DETECT_AL_HTTP_USER_AGENT].RegisterTests = DetectHttpUARegisterTests; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_PAYLOAD ; DetectAppLayerMpmRegister("http_user_agent", SIG_FLAG_TOSERVER, 2, PrefilterTxUARegister); diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index 67714f884825..64e2c03dd881 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -75,7 +75,6 @@ void DetectHttpUriRegister (void) sigmatch_table[DETECT_AL_HTTP_URI].RegisterTests = DetectHttpUriRegisterTests; sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterTxUriRegister); diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 6eb098141d9c..4d5df7f73811 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -73,8 +73,6 @@ void DetectIsdataatRegister(void) sigmatch_table[DETECT_ISDATAAT].Free = DetectIsdataatFree; sigmatch_table[DETECT_ISDATAAT].RegisterTests = DetectIsdataatRegisterTests; - sigmatch_table[DETECT_ISDATAAT].flags |= SIGMATCH_PAYLOAD; - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } diff --git a/src/detect-nocase.c b/src/detect-nocase.c index 18a392ed59a7..ee0d5bdea0ad 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -55,7 +55,6 @@ void DetectNocaseRegister(void) sigmatch_table[DETECT_NOCASE].RegisterTests = NULL; sigmatch_table[DETECT_NOCASE].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_NOCASE].flags |= SIGMATCH_PAYLOAD; } /** diff --git a/src/detect-offset.c b/src/detect-offset.c index b43cca7723be..f0c84ee838d9 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -50,8 +50,6 @@ void DetectOffsetRegister (void) sigmatch_table[DETECT_OFFSET].Setup = DetectOffsetSetup; sigmatch_table[DETECT_OFFSET].Free = NULL; sigmatch_table[DETECT_OFFSET].RegisterTests = NULL; - - sigmatch_table[DETECT_OFFSET].flags |= SIGMATCH_PAYLOAD; } int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index d4e3bbe8a0d0..cea56672ba71 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -94,8 +94,6 @@ void DetectPcreRegister (void) sigmatch_table[DETECT_PCRE].Free = DetectPcreFree; sigmatch_table[DETECT_PCRE].RegisterTests = DetectPcreRegisterTests; - sigmatch_table[DETECT_PCRE].flags |= SIGMATCH_PAYLOAD; - intmax_t val = 0; if (!ConfGetInt("pcre.match-limit", &val)) { diff --git a/src/detect-pktvar.c b/src/detect-pktvar.c index 930ceeeeaf74..919ea2d878b9 100644 --- a/src/detect-pktvar.c +++ b/src/detect-pktvar.c @@ -51,8 +51,6 @@ void DetectPktvarRegister (void) sigmatch_table[DETECT_PKTVAR].Free = NULL; sigmatch_table[DETECT_PKTVAR].RegisterTests = NULL; - sigmatch_table[DETECT_PKTVAR].flags |= SIGMATCH_PAYLOAD; - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } diff --git a/src/detect-rawbytes.c b/src/detect-rawbytes.c index 5e7e48d9749e..52c53b7f6a1a 100644 --- a/src/detect-rawbytes.c +++ b/src/detect-rawbytes.c @@ -48,7 +48,6 @@ void DetectRawbytesRegister (void) sigmatch_table[DETECT_RAWBYTES].RegisterTests = NULL; sigmatch_table[DETECT_RAWBYTES].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_RAWBYTES].flags |= SIGMATCH_PAYLOAD; } static int DetectRawbytesSetup (DetectEngineCtx *de_ctx, Signature *s, char *nullstr) diff --git a/src/detect-replace.c b/src/detect-replace.c index 08ab84c88746..17f056150588 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -69,8 +69,6 @@ void DetectReplaceRegister (void) sigmatch_table[DETECT_REPLACE].Setup = DetectReplaceSetup; sigmatch_table[DETECT_REPLACE].Free = NULL; sigmatch_table[DETECT_REPLACE].RegisterTests = DetectReplaceRegisterTests; - - sigmatch_table[DETECT_REPLACE].flags |= SIGMATCH_PAYLOAD; } int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *replacestr) diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c index d3838a0490fe..aba807cbe24d 100644 --- a/src/detect-template-buffer.c +++ b/src/detect-template-buffer.c @@ -56,7 +56,6 @@ void DetectTemplateBufferRegister(void) DetectTemplateBufferRegisterTests; sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_PAYLOAD; /* register inspect engines */ DetectAppLayerInspectEngineRegister("template_buffer", diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c index f918b301dbbd..dc4c8b621e33 100644 --- a/src/detect-tls-cert-issuer.c +++ b/src/detect-tls-cert-issuer.c @@ -71,7 +71,6 @@ void DetectTlsIssuerRegister(void) sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].RegisterTests = DetectTlsIssuerRegisterTests; sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("tls_cert_issuer", SIG_FLAG_TOCLIENT, 2, PrefilterTxTlsIssuerRegister); diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c index affea07ea7b6..d6581fca4cb5 100644 --- a/src/detect-tls-cert-subject.c +++ b/src/detect-tls-cert-subject.c @@ -71,7 +71,6 @@ void DetectTlsSubjectRegister(void) sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("tls_cert_subject", SIG_FLAG_TOCLIENT, 2, PrefilterTxTlsSubjectRegister); diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c index a87f0a6e7ef1..195175a70f66 100644 --- a/src/detect-tls-sni.c +++ b/src/detect-tls-sni.c @@ -71,7 +71,6 @@ void DetectTlsSniRegister(void) sigmatch_table[DETECT_AL_TLS_SNI].RegisterTests = DetectTlsSniRegisterTests; sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_PAYLOAD; DetectAppLayerMpmRegister("tls_sni", SIG_FLAG_TOSERVER, 2, PrefilterTxTlsSniRegister); diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index dc77cc9e694c..b541e0873523 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -74,8 +74,6 @@ void DetectUricontentRegister (void) sigmatch_table[DETECT_URICONTENT].Free = DetectUricontentFree; sigmatch_table[DETECT_URICONTENT].RegisterTests = DetectUricontentRegisterTests; - sigmatch_table[DETECT_URICONTENT].flags |= SIGMATCH_PAYLOAD; - g_http_uri_buffer_id = DetectBufferTypeRegister("http_uri"); } diff --git a/src/detect-urilen.c b/src/detect-urilen.c index 4e65d0b8313b..c56993072525 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -70,7 +70,6 @@ void DetectUrilenRegister(void) sigmatch_table[DETECT_AL_URILEN].Setup = DetectUrilenSetup; sigmatch_table[DETECT_AL_URILEN].Free = DetectUrilenFree; sigmatch_table[DETECT_AL_URILEN].RegisterTests = DetectUrilenRegisterTests; - sigmatch_table[DETECT_AL_URILEN].flags |= SIGMATCH_PAYLOAD; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); diff --git a/src/detect-within.c b/src/detect-within.c index 61272e3844e2..b7921a3138a2 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -55,8 +55,6 @@ void DetectWithinRegister(void) sigmatch_table[DETECT_WITHIN].Setup = DetectWithinSetup; sigmatch_table[DETECT_WITHIN].Free = NULL; sigmatch_table[DETECT_WITHIN].RegisterTests = DetectWithinRegisterTests; - - sigmatch_table[DETECT_WITHIN].flags |= SIGMATCH_PAYLOAD; } /** \brief Setup within pattern (content/uricontent) modifier. diff --git a/src/detect.c b/src/detect.c index 4906c52f49ae..494b07b5aa75 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2043,19 +2043,6 @@ static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, const Signature if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { return 1; } -#if 0 - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; - if (sm == NULL) - return 0; - - for (; sm != NULL; sm = sm->next) { - if (sigmatch_table[sm->type].flags & SIGMATCH_PAYLOAD) { - if (!(de_ctx->flags & DE_QUIET)) - SCLogDebug("Signature (%" PRIu32 "): is inspecting payload.", s->id); - return 1; - } - } -#endif return 0; } @@ -3900,12 +3887,6 @@ static void PrintFeatureList(const SigTableElmt *e, char sep) printf("compatible with decoder event only rule"); prev = 1; } - if (flags & SIGMATCH_PAYLOAD) { - if (prev == 1) - printf("%c", sep); - printf("payload inspecting keyword"); - prev = 1; - } if (e->SupportsPrefilter) { if (prev == 1) printf("%c", sep); diff --git a/src/detect.h b/src/detect.h index 194ca4a923e9..5419228dc06c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1089,13 +1089,11 @@ typedef struct SigGroupHead_ { #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) +#define SIGMATCH_NOT_BUILT (1 << 3) /** sigmatch may have options, so the parser should be ready to * deal with both cases */ -#define SIGMATCH_OPTIONAL_OPT (1 << 5) +#define SIGMATCH_OPTIONAL_OPT (1 << 4) enum DetectEngineTenantSelectors { From f1ab6a615378f27000247144652cec9501849eb1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 17:10:18 +0100 Subject: [PATCH 2429/2553] detect: ssh_proto stickybuffer --- src/Makefile.am | 1 + src/detect-ssh-proto.c | 216 +++++++++++++++++++++++++++++++++++++++++ src/detect-ssh-proto.h | 29 ++++++ src/detect.c | 2 + src/detect.h | 1 + 5 files changed, 249 insertions(+) create mode 100644 src/detect-ssh-proto.c create mode 100644 src/detect-ssh-proto.h diff --git a/src/Makefile.am b/src/Makefile.am index 6ddbd1d8f6b3..9ab11b48d57b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -213,6 +213,7 @@ detect-rpc.c detect-rpc.h \ detect-sameip.c detect-sameip.h \ detect-seq.c detect-seq.h \ detect-sid.c detect-sid.h \ +detect-ssh-proto.c detect-ssh-proto.h \ detect-ssh-proto-version.c detect-ssh-proto-version.h \ detect-ssh-software-version.c detect-ssh-software-version.h \ detect-ssl-state.c detect-ssl-state.h \ diff --git a/src/detect-ssh-proto.c b/src/detect-ssh-proto.c new file mode 100644 index 000000000000..185b25b9b0d4 --- /dev/null +++ b/src/detect-ssh-proto.c @@ -0,0 +1,216 @@ +/* Copyright (C) 2007-2016 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. + */ + +/** + * \ingroup sshlayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support ssh_proto sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-ssh.h" + +#define KEYWORD_NAME "ssh_proto" +#define KEYWORD_DOC "ssh-keywords#ssh-protocol" +#define BUFFER_NAME "ssh_protocol" +#define BUFFER_DESC "ssh protocol field" +static int g_buffer_id = 0; + +/** \brief SSH Protocol Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxSshRequestProtocol(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + const SshState *ssh_state = txv; + + if (ssh_state->cli_hdr.proto_version == NULL) + return; + + uint32_t buffer_len = strlen((char *)ssh_state->cli_hdr.proto_version); + const uint8_t *buffer = ssh_state->cli_hdr.proto_version; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxSshRequestProtocolRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxSshRequestProtocol, + ALPROTO_SSH, SSH_STATE_BANNER_DONE, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + return r; +} + +/** \brief SSH Protocol Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxSshResponseProtocol(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + const SshState *ssh_state = txv; + + if (ssh_state->srv_hdr.proto_version == NULL) + return; + + uint32_t buffer_len = strlen((char *)ssh_state->srv_hdr.proto_version); + const uint8_t *buffer = ssh_state->srv_hdr.proto_version; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxSshResponseProtocolRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxSshResponseProtocol, + ALPROTO_SSH, SSH_STATE_BANNER_DONE, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + return r; +} + +static int InspectEngineSshProtocol(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + uint8_t *protocol = NULL; + SshState *ssh_state = alstate; + + if (flags & STREAM_TOSERVER) + protocol = ssh_state->cli_hdr.proto_version; + else if (flags & STREAM_TOCLIENT) + protocol = ssh_state->srv_hdr.proto_version; + if (protocol == NULL) + goto end; + + uint32_t buffer_len = strlen((char *)protocol); + uint8_t *buffer = protocol; + if (buffer == NULL ||buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +static int DetectSshProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_buffer_id; + return 0; +} + +static void DetectSshProtocolSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_SSH_STATE; +} + +void DetectSshProtocolRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_PROTOCOL].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].url = DOC_URL DOC_VERSION "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].Setup = DetectSshProtocolSetup; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].flags |= SIGMATCH_NOOPT ; + + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxSshRequestProtocolRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxSshResponseProtocolRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SSH, SIG_FLAG_TOSERVER, + InspectEngineSshProtocol); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SSH, SIG_FLAG_TOCLIENT, + InspectEngineSshProtocol); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, + BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, + DetectSshProtocolSetupCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-ssh-proto.h b/src/detect-ssh-proto.h new file mode 100644 index 000000000000..b04476e3c874 --- /dev/null +++ b/src/detect-ssh-proto.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 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 + */ + +#ifndef __DETECT_SSH_PROTOCOL_H__ +#define __DETECT_SSH_PROTOCOL_H__ + +void DetectSshProtocolRegister(void); + +#endif /* __DETECT_SSH_PROTOCOL_H__ */ diff --git a/src/detect.c b/src/detect.c index 494b07b5aa75..4d2f2678c2e4 100644 --- a/src/detect.c +++ b/src/detect.c @@ -182,6 +182,7 @@ #include "detect-tls.h" #include "detect-tls-cert-validity.h" #include "detect-tls-version.h" +#include "detect-ssh-proto.h" #include "detect-ssh-proto-version.h" #include "detect-ssh-software-version.h" #include "detect-http-stat-code.h" @@ -4092,6 +4093,7 @@ void SigTableSetup(void) DetectUrilenRegister(); DetectDetectionFilterRegister(); DetectAsn1Register(); + DetectSshProtocolRegister(); DetectSshVersionRegister(); DetectSshSoftwareVersionRegister(); DetectSslStateRegister(); diff --git a/src/detect.h b/src/detect.h index 5419228dc06c..3c6f17acf249 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1249,6 +1249,7 @@ enum { DETECT_AL_HTTP_RAW_HOST, DETECT_AL_HTTP_REQUEST_LINE, DETECT_AL_HTTP_RESPONSE_LINE, + DETECT_AL_SSH_PROTOCOL, DETECT_AL_SSH_PROTOVERSION, DETECT_AL_SSH_SOFTWAREVERSION, DETECT_AL_SSL_VERSION, From 920709fe6f14d094dac9513b5c4346657c4effb7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 23 Dec 2016 17:18:10 +0100 Subject: [PATCH 2430/2553] detect: ssh_software sticky buffer --- src/Makefile.am | 1 + src/detect-ssh-software.c | 216 ++++++++++++++++++++++++++++++++++++++ src/detect-ssh-software.h | 29 +++++ src/detect.c | 2 + src/detect.h | 1 + 5 files changed, 249 insertions(+) create mode 100644 src/detect-ssh-software.c create mode 100644 src/detect-ssh-software.h diff --git a/src/Makefile.am b/src/Makefile.am index 9ab11b48d57b..05e5ef539c77 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -215,6 +215,7 @@ detect-seq.c detect-seq.h \ detect-sid.c detect-sid.h \ detect-ssh-proto.c detect-ssh-proto.h \ detect-ssh-proto-version.c detect-ssh-proto-version.h \ +detect-ssh-software.c detect-ssh-software.h \ detect-ssh-software-version.c detect-ssh-software-version.h \ detect-ssl-state.c detect-ssl-state.h \ detect-ssl-version.c detect-ssl-version.h \ diff --git a/src/detect-ssh-software.c b/src/detect-ssh-software.c new file mode 100644 index 000000000000..528daed4df20 --- /dev/null +++ b/src/detect-ssh-software.c @@ -0,0 +1,216 @@ +/* Copyright (C) 2007-2016 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. + */ + +/** + * \ingroup sshlayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support ssh_software sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-ssh.h" + +#define KEYWORD_NAME "ssh_software" +#define KEYWORD_DOC "ssh-keywords#ssh-software" +#define BUFFER_NAME "ssh_software" +#define BUFFER_DESC "ssh software" +static int g_buffer_id = 0; + +/** \brief SSH Software Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxSshRequestSoftware(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + const SshState *ssh_state = txv; + + if (ssh_state->cli_hdr.software_version == NULL) + return; + + uint32_t buffer_len = strlen((char *)ssh_state->cli_hdr.software_version); + const uint8_t *buffer = ssh_state->cli_hdr.software_version; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxSshRequestSoftwareRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxSshRequestSoftware, + ALPROTO_SSH, SSH_STATE_BANNER_DONE, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + return r; +} + +/** \brief SSH Software Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxSshResponseSoftware(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + const SshState *ssh_state = txv; + + if (ssh_state->srv_hdr.software_version == NULL) + return; + + uint32_t buffer_len = strlen((char *)ssh_state->srv_hdr.software_version); + const uint8_t *buffer = ssh_state->srv_hdr.software_version; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxSshResponseSoftwareRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxSshResponseSoftware, + ALPROTO_SSH, SSH_STATE_BANNER_DONE, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + return r; +} + +static int InspectEngineSshSoftware(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + uint8_t *software = NULL; + SshState *ssh_state = alstate; + + if (flags & STREAM_TOSERVER) + software = ssh_state->cli_hdr.software_version; + else if (flags & STREAM_TOCLIENT) + software = ssh_state->srv_hdr.software_version; + if (software == NULL) + goto end; + + uint32_t buffer_len = strlen((char *)software); + uint8_t *buffer = software; + if (buffer == NULL ||buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +static int DetectSshSoftwareSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_buffer_id; + return 0; +} + +static void DetectSshSoftwareSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_SSH_STATE; +} + +void DetectSshSoftwareRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_SOFTWARE].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].url = DOC_URL DOC_VERSION "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].Setup = DetectSshSoftwareSetup; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].flags |= SIGMATCH_NOOPT ; + + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxSshRequestSoftwareRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxSshResponseSoftwareRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SSH, SIG_FLAG_TOSERVER, + InspectEngineSshSoftware); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SSH, SIG_FLAG_TOCLIENT, + InspectEngineSshSoftware); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, + BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, + DetectSshSoftwareSetupCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-ssh-software.h b/src/detect-ssh-software.h new file mode 100644 index 000000000000..a741b87316a3 --- /dev/null +++ b/src/detect-ssh-software.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 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 + */ + +#ifndef __DETECT_SSH_SOFTWARE_H__ +#define __DETECT_SSH_SOFTWARE_H__ + +void DetectSshSoftwareRegister(void); + +#endif /* __DETECT_SSH_SOFTWARE_H__ */ diff --git a/src/detect.c b/src/detect.c index 4d2f2678c2e4..22db7be12ff8 100644 --- a/src/detect.c +++ b/src/detect.c @@ -184,6 +184,7 @@ #include "detect-tls-version.h" #include "detect-ssh-proto.h" #include "detect-ssh-proto-version.h" +#include "detect-ssh-software.h" #include "detect-ssh-software-version.h" #include "detect-http-stat-code.h" #include "detect-ssl-version.h" @@ -4095,6 +4096,7 @@ void SigTableSetup(void) DetectAsn1Register(); DetectSshProtocolRegister(); DetectSshVersionRegister(); + DetectSshSoftwareRegister(); DetectSshSoftwareVersionRegister(); DetectSslStateRegister(); DetectSslVersionRegister(); diff --git a/src/detect.h b/src/detect.h index 3c6f17acf249..50a735e47c52 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1251,6 +1251,7 @@ enum { DETECT_AL_HTTP_RESPONSE_LINE, DETECT_AL_SSH_PROTOCOL, DETECT_AL_SSH_PROTOVERSION, + DETECT_AL_SSH_SOFTWARE, DETECT_AL_SSH_SOFTWAREVERSION, DETECT_AL_SSL_VERSION, DETECT_AL_SSL_STATE, From 43cc06eabeca8d1bdf8456e98e61d004bf226367 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 26 Oct 2016 13:44:53 +0200 Subject: [PATCH 2431/2553] detect: use engine version instead of id Use engine version based on global detect engine master. This is incremented between reloads. --- src/detect-engine.c | 31 ++++++++++++++++++++++++++----- src/detect-engine.h | 2 ++ src/detect.c | 8 ++++---- src/detect.h | 7 +++++-- src/flow-util.h | 4 ++-- src/flow.h | 4 ++-- src/suricata.c | 1 + 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 594e30131933..bbfec11e530b 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -84,15 +84,13 @@ #define DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT 3000 -static uint32_t detect_engine_ctx_id = 1; - static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt); static int DetectEngineCtxLoadConf(DetectEngineCtx *); static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, - 0, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0}; + 0, 99, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0}; static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len); static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len); @@ -906,7 +904,8 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) if (minimal) { de_ctx->minimal = 1; - de_ctx->id = detect_engine_ctx_id++; + de_ctx->version = DetectEngineGetVersion(); + SCLogDebug("minimal with version %u", de_ctx->version); return de_ctx; } @@ -958,7 +957,8 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) goto error; } - de_ctx->id = detect_engine_ctx_id++; + de_ctx->version = DetectEngineGetVersion(); + SCLogDebug("dectx with version %u", de_ctx->version); return de_ctx; error: if (de_ctx != NULL) { @@ -2054,6 +2054,25 @@ int DetectEngineEnabled(void) return 1; } +uint32_t DetectEngineGetVersion(void) +{ + uint32_t version; + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + version = master->version; + SCMutexUnlock(&master->lock); + return version; +} + +void DetectEngineBumpVersion(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + master->version++; + SCLogDebug("master version now %u", master->version); + SCMutexUnlock(&master->lock); +} + DetectEngineCtx *DetectEngineGetCurrent(void) { DetectEngineMasterCtx *master = &g_master_de_ctx; @@ -2827,6 +2846,8 @@ int DetectEngineReload(SCInstance *suri) /* walk free list, freeing the old_de_ctx */ DetectEnginePruneFreeList(); + DetectEngineBumpVersion(); + SCLogDebug("old_de_ctx should have been freed"); SCLogNotice("rule reload complete"); diff --git a/src/detect-engine.h b/src/detect-engine.h index 9c1c1614a5c3..590d4db6bfe8 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -66,6 +66,8 @@ void DetectEngineResetMaxSigId(DetectEngineCtx *); void DetectEngineRegisterTests(void); const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type); +uint32_t DetectEngineGetVersion(void); +void DetectEngineBumpVersion(void); int DetectEngineAddToMaster(DetectEngineCtx *de_ctx); DetectEngineCtx *DetectEngineGetCurrent(void); DetectEngineCtx *DetectEngineGetByTenantId(int tenant_id); diff --git a/src/detect.c b/src/detect.c index 22db7be12ff8..177daeeae3e7 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1093,17 +1093,17 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } /* live ruleswap check for flow updates */ - if (pflow->de_ctx_id == 0) { + if (pflow->de_ctx_version == 0) { /* first time this flow is inspected, set id */ - pflow->de_ctx_id = de_ctx->id; - } else if (pflow->de_ctx_id != de_ctx->id) { + pflow->de_ctx_version = de_ctx->version; + } else if (pflow->de_ctx_version != de_ctx->version) { /* first time we inspect flow with this de_ctx, reset */ pflow->flags &= ~FLOW_SGH_TOSERVER; pflow->flags &= ~FLOW_SGH_TOCLIENT; pflow->sgh_toserver = NULL; pflow->sgh_toclient = NULL; - pflow->de_ctx_id = de_ctx->id; + pflow->de_ctx_version = de_ctx->version; GenericVarFree(pflow->flowvar); pflow->flowvar = NULL; diff --git a/src/detect.h b/src/detect.h index 50a735e47c52..88c31ddd3cdc 100644 --- a/src/detect.h +++ b/src/detect.h @@ -669,8 +669,8 @@ typedef struct DetectEngineCtx_ { /* 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; + /** version of the detect engine */ + 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 */ @@ -1117,6 +1117,9 @@ typedef struct DetectEngineMasterCtx_ { /** 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; diff --git a/src/flow-util.h b/src/flow-util.h index c0b8c06967fe..dfbba64cb1b9 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -55,7 +55,7 @@ (f)->alproto = 0; \ (f)->alproto_ts = 0; \ (f)->alproto_tc = 0; \ - (f)->de_ctx_id = 0; \ + (f)->de_ctx_version = 0; \ (f)->thread_id = 0; \ (f)->detect_alversion[0] = 0; \ (f)->detect_alversion[1] = 0; \ @@ -97,7 +97,7 @@ (f)->alproto = 0; \ (f)->alproto_ts = 0; \ (f)->alproto_tc = 0; \ - (f)->de_ctx_id = 0; \ + (f)->de_ctx_version = 0; \ (f)->thread_id = 0; \ (f)->detect_alversion[0] = 0; \ (f)->detect_alversion[1] = 0; \ diff --git a/src/flow.h b/src/flow.h index 35ba26f589b8..b12554135d92 100644 --- a/src/flow.h +++ b/src/flow.h @@ -384,10 +384,10 @@ typedef struct Flow_ AppProto alproto_ts; AppProto alproto_tc; - /** detection engine ctx id used to inspect this flow. Set at initial + /** detection engine ctx version used to inspect this flow. Set at initial * inspection. If it doesn't match the currently in use de_ctx, the * stored sgh ptrs are reset. */ - uint32_t de_ctx_id; + uint32_t de_ctx_version; /** Thread ID for the stream/detect portion of this flow */ FlowThreadId thread_id; diff --git a/src/suricata.c b/src/suricata.c index 06ff877662fd..fbe0305531c2 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -2519,6 +2519,7 @@ static void PostConfLoadedDetectSetup(SCInstance *suri) } DetectEngineAddToMaster(de_ctx); + DetectEngineBumpVersion(); } else { /* tell the app layer to consider only the log id */ RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveLogOnly); From 22f3205664f28fb382b979f9ddff5695b8ea66e4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 20 Oct 2016 14:38:33 +0200 Subject: [PATCH 2432/2553] var-names: expose outside of detect engine Until now variable names, such as flowbit names, were local to a detect engine. This made sense as they were only ever used in that context. For the purpose of logging these names, this needs a different approach. The loggers live outside of the detect engine. Also, in the case of reloads and multi-tenancy, there are even multiple detect engines, so it would be even more tricky to access them from the outside. This patch brings a new approach. A any time, there is a single active hash table mapping the variable names and their id's. For multiple tenants the table is shared between tenants. The table is set up in a 'staging' area, where locking makes sure that multiple loading threads don't mess things up. Then when the preparing of a detection engine is ready, but before the detect threads are made aware of the new detect engine, the active varname hash is swapped with the staging instance. For this to work, all the mappings from the 'current' or active mapping are added to the staging table. After the threads have reloaded and the new detection engine is active, the old table can be freed. For multi tenancy things are similar. The staging area is used for setting up until the new detection engines / tenants are applied to the system. This patch also changes the variable 'id'/'idx' field to uint32_t. Due to data structure padding and alignment, this should have no practical drawback while allowing for a lot more vars. --- src/detect-engine.c | 10 +- src/detect-flowbits.c | 40 +++---- src/detect-flowbits.h | 2 +- src/detect-flowint.c | 6 +- src/detect-flowint.h | 2 +- src/detect-flowvar.c | 6 +- src/detect-flowvar.h | 6 +- src/detect-hostbits.c | 7 +- src/detect-lua.c | 4 +- src/detect-lua.h | 4 +- src/detect-pcre.c | 4 +- src/detect-pcre.h | 2 +- src/detect-xbits.c | 2 +- src/detect-xbits.h | 2 +- src/detect.c | 6 +- src/detect.h | 8 +- src/flow-bit.c | 16 +-- src/flow-bit.h | 12 +-- src/flow-var.c | 14 +-- src/flow-var.h | 12 +-- src/host-bit.c | 16 +-- src/host-bit.h | 10 +- src/ippair-bit.c | 16 +-- src/ippair-bit.h | 10 +- src/util-var-name.c | 236 ++++++++++++++++++++++++++++++++++++------ src/util-var-name.h | 16 +-- src/util-var.h | 4 +- 27 files changed, 322 insertions(+), 151 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index bbfec11e530b..db5a9d4197e4 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -934,7 +934,6 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) SigGroupHeadHashInit(de_ctx); MpmStoreInit(de_ctx); ThresholdHashInit(de_ctx); - VariableNameInitHash(de_ctx); DetectParseDupSigHashInit(de_ctx); DetectAddressMapInit(de_ctx); @@ -958,6 +957,7 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) } de_ctx->version = DetectEngineGetVersion(); + VarNameStoreSetupStaging(de_ctx->version); SCLogDebug("dectx with version %u", de_ctx->version); return de_ctx; error: @@ -1033,8 +1033,6 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) SigCleanSignatures(de_ctx); SCFree(de_ctx->app_mpms); de_ctx->app_mpms = NULL; - - VariableNameFreeHash(de_ctx); if (de_ctx->sig_array) SCFree(de_ctx->sig_array); @@ -1067,6 +1065,9 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) DetectPortCleanupList(de_ctx->tcp_whitelist); DetectPortCleanupList(de_ctx->udp_whitelist); + /* freed our var name hash */ + VarNameStoreFree(de_ctx->version); + SCFree(de_ctx); //DetectAddressGroupPrintMemory(); //DetectSigGroupPrintMemory(); @@ -2490,6 +2491,9 @@ int DetectEngineMultiTenantSetup(void) if (DetectLoadersSync() != 0) { goto error; } + + VarNameStoreActivateStaging(); + } else { SCLogDebug("multi-detect not enabled (multi tenancy)"); } diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 41b249efebd5..34d4eaf12127 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -246,7 +246,7 @@ int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) if (unlikely(cd == NULL)) goto error; - cd->idx = VariableNameGetIdx(de_ctx, fb_name, VAR_TYPE_FLOW_BIT); + cd->idx = VarNameStoreSetupAdd(fb_name, VAR_TYPE_FLOW_BIT); cd->cmd = fb_cmd; SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", @@ -360,6 +360,7 @@ static int FlowBitsTestSig01(void) s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)"); FAIL_IF_NOT_NULL(s); + SigGroupBuild(de_ctx); DetectEngineCtxFree(de_ctx); PASS; } @@ -399,6 +400,7 @@ static int FlowBitsTestSig02(void) s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)"); FAIL_IF_NOT_NULL(s); + SigGroupBuild(de_ctx); DetectEngineCtxFree(de_ctx); PASS; @@ -424,6 +426,7 @@ static int FlowBitsTestSig03(void) s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)"); FAIL_IF_NOT_NULL(s); + SigGroupBuild(de_ctx); DetectEngineCtxFree(de_ctx); PASS; } @@ -449,9 +452,10 @@ static int FlowBitsTestSig04(void) s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)"); FAIL_IF_NULL(s); - idx = VariableNameGetIdx(de_ctx, "fbt", VAR_TYPE_FLOW_BIT); + idx = VarNameStoreSetupAdd("fbt", VAR_TYPE_FLOW_BIT); FAIL_IF(idx != 1); + SigGroupBuild(de_ctx); DetectEngineCtxFree(de_ctx); PASS; } @@ -477,6 +481,7 @@ static int FlowBitsTestSig05(void) FAIL_IF_NULL(s); FAIL_IF((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT); + SigGroupBuild(de_ctx); DetectEngineCtxFree(de_ctx); PASS; } @@ -504,7 +509,7 @@ static int FlowBitsTestSig06(void) Flow f; GenericVar flowvar, *gv = NULL; int result = 0; - int idx = 0; + uint32_t idx = 0; memset(p, 0, SIZE_OF_PACKET); memset(&th_v, 0, sizeof(th_v)); @@ -531,15 +536,14 @@ static int FlowBitsTestSig06(void) s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)"); FAIL_IF_NULL(s); + idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", VAR_TYPE_FLOW_BIT); - gv = p->flow->flowvar; - + FAIL_IF_NULL(gv); for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { result = 1; @@ -547,13 +551,9 @@ static int FlowBitsTestSig06(void) } FAIL_IF_NOT(result); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); @@ -583,7 +583,7 @@ static int FlowBitsTestSig07(void) Flow f; GenericVar flowvar, *gv = NULL; int result = 0; - int idx = 0; + uint32_t idx = 0; memset(p, 0, SIZE_OF_PACKET); memset(&th_v, 0, sizeof(th_v)); @@ -611,14 +611,14 @@ static int FlowBitsTestSig07(void) s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)"); FAIL_IF_NULL(s); + idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", VAR_TYPE_FLOW_BIT); - gv = p->flow->flowvar; + FAIL_IF_NULL(gv); for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { @@ -627,13 +627,9 @@ static int FlowBitsTestSig07(void) } FAIL_IF(result); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); @@ -664,7 +660,7 @@ static int FlowBitsTestSig08(void) Flow f; GenericVar flowvar, *gv = NULL; int result = 0; - int idx = 0; + uint32_t idx = 0; memset(p, 0, SIZE_OF_PACKET); memset(&th_v, 0, sizeof(th_v)); @@ -692,14 +688,14 @@ static int FlowBitsTestSig08(void) s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)"); FAIL_IF_NULL(s); + idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", VAR_TYPE_FLOW_BIT); - gv = p->flow->flowvar; + FAIL_IF_NULL(gv); for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { @@ -708,13 +704,9 @@ static int FlowBitsTestSig08(void) } FAIL_IF(result); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); diff --git a/src/detect-flowbits.h b/src/detect-flowbits.h index 8961da3fd898..7d50edb83542 100644 --- a/src/detect-flowbits.h +++ b/src/detect-flowbits.h @@ -34,7 +34,7 @@ #define DETECT_FLOWBITS_CMD_MAX 6 typedef struct DetectFlowbitsData_ { - uint16_t idx; + uint32_t idx; uint8_t cmd; } DetectFlowbitsData; diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 6ceb7ca39e7f..76bcb1a5a7b9 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -104,7 +104,7 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, * return zero(not match). */ if (sfd->targettype == FLOWINT_TARGET_VAR) { - uint16_t tvar_idx = VariableNameGetIdx(det_ctx->de_ctx, sfd->target.tvar.name, VAR_TYPE_FLOW_INT); + uint32_t tvar_idx = VarNameStoreLookupByName(sfd->target.tvar.name, VAR_TYPE_FLOW_INT); fvt = FlowVarGet(p->flow, tvar_idx); /* We don't have that variable initialized yet */ @@ -326,8 +326,8 @@ DetectFlowintData *DetectFlowintParse(DetectEngineCtx *de_ctx, char *rawstr) SCLogError(SC_ERR_MEM_ALLOC, "malloc from strdup failed"); goto error; } - if (de_ctx != NULL) - sfd->idx = VariableNameGetIdx(de_ctx, varname, VAR_TYPE_FLOW_INT); + sfd->idx = VarNameStoreSetupAdd(varname, VAR_TYPE_FLOW_INT); + SCLogDebug("sfd->name %s id %u", sfd->name, sfd->idx); sfd->modifier = modifier; pcre_free_substring(varname); diff --git a/src/detect-flowint.h b/src/detect-flowint.h index 9a18efd50d31..9caf68258cc7 100644 --- a/src/detect-flowint.h +++ b/src/detect-flowint.h @@ -64,7 +64,7 @@ typedef struct DetectFlowintData_ { * against the target */ char *name; /* Internal id of the var */ - uint16_t idx; + uint32_t idx; /* The modifier/operation/condition we are * going to execute */ diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index 46741016b696..c5f838bb6c31 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -166,7 +166,7 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws fd->name = SCStrdup(varname); if (unlikely(fd->name == NULL)) goto error; - fd->idx = VariableNameGetIdx(de_ctx, varname, VAR_TYPE_FLOW_VAR); + fd->idx = VarNameStoreSetupAdd(varname, VAR_TYPE_FLOW_VAR); /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ @@ -194,7 +194,7 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws /** \brief Store flowvar in det_ctx so we can exec it post-match */ -int DetectFlowvarStoreMatch(DetectEngineThreadCtx *det_ctx, uint16_t idx, +int DetectFlowvarStoreMatch(DetectEngineThreadCtx *det_ctx, uint32_t idx, uint8_t *buffer, uint16_t len, int type) { DetectFlowvarList *fs = det_ctx->flowvarlist; @@ -229,7 +229,7 @@ int DetectFlowvarStoreMatch(DetectEngineThreadCtx *det_ctx, uint16_t idx, /** \brief Setup a post-match for flowvar storage * We're piggyback riding the DetectFlowvarData struct */ -int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx) +int DetectFlowvarPostMatchSetup(Signature *s, uint32_t idx) { SigMatch *sm = NULL; DetectFlowvarData *fv = NULL; diff --git a/src/detect-flowvar.h b/src/detect-flowvar.h index c8081385b87a..32222372b4bf 100644 --- a/src/detect-flowvar.h +++ b/src/detect-flowvar.h @@ -26,7 +26,7 @@ typedef struct DetectFlowvarData_ { char *name; - uint16_t idx; + uint32_t idx; uint8_t *content; uint8_t content_len; uint8_t flags; @@ -35,8 +35,8 @@ typedef struct DetectFlowvarData_ { /* prototypes */ void DetectFlowvarRegister (void); -int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx); -int DetectFlowvarStoreMatch(DetectEngineThreadCtx *, uint16_t, uint8_t *, uint16_t, int); +int DetectFlowvarPostMatchSetup(Signature *s, uint32_t idx); +int DetectFlowvarStoreMatch(DetectEngineThreadCtx *, uint32_t, uint8_t *, uint16_t, int); /* For use only by DetectFlowvarProcessList() */ void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f); diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index e2fa800c6f68..bf1b728824d1 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -385,7 +385,7 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) if (unlikely(cd == NULL)) goto error; - cd->idx = VariableNameGetIdx(de_ctx, fb_name, VAR_TYPE_HOST_BIT); + cd->idx = VarNameStoreSetupAdd(fb_name, VAR_TYPE_HOST_BIT); cd->cmd = fb_cmd; cd->tracker = hb_dir; cd->type = VAR_TYPE_HOST_BIT; @@ -752,7 +752,7 @@ static int HostBitsTestSig04(void) s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; hostbits:isset,fbt; content:\"GET \"; sid:1;)"); FAIL_IF_NULL(s); - idx = VariableNameGetIdx(de_ctx, "fbt", VAR_TYPE_HOST_BIT); + idx = VarNameStoreSetupAdd("fbt", VAR_TYPE_HOST_BIT); FAIL_IF(idx != 1); SigGroupBuild(de_ctx); @@ -760,9 +760,6 @@ static int HostBitsTestSig04(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostBitsTestShutdown(); diff --git a/src/detect-lua.c b/src/detect-lua.c index 87d3e55f9b9a..e08490c11df3 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -776,7 +776,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) goto error; } - uint16_t idx = VariableNameGetIdx(de_ctx, (char *)value, VAR_TYPE_FLOW_VAR); + uint32_t idx = VarNameStoreSetupAdd((char *)value, VAR_TYPE_FLOW_VAR); ld->flowvar[ld->flowvars++] = idx; SCLogDebug("script uses flowvar %u with script id %u", idx, ld->flowvars - 1); } @@ -798,7 +798,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) goto error; } - uint16_t idx = VariableNameGetIdx(de_ctx, (char *)value, VAR_TYPE_FLOW_INT); + uint32_t idx = VarNameStoreSetupAdd((char *)value, VAR_TYPE_FLOW_INT); ld->flowint[ld->flowints++] = idx; SCLogDebug("script uses flowint %u with script id %u", idx, ld->flowints - 1); } diff --git a/src/detect-lua.h b/src/detect-lua.h index 16e451e91090..224d6225f305 100644 --- a/src/detect-lua.h +++ b/src/detect-lua.h @@ -42,10 +42,10 @@ typedef struct DetectLuaData { uint32_t flags; AppProto alproto; char *buffername; /* buffer name in case of a single buffer */ - uint16_t flowint[DETECT_LUAJIT_MAX_FLOWINTS]; + uint32_t flowint[DETECT_LUAJIT_MAX_FLOWINTS]; uint16_t flowints; - uint16_t flowvar[DETECT_LUAJIT_MAX_FLOWVARS]; uint16_t flowvars; + uint32_t flowvar[DETECT_LUAJIT_MAX_FLOWVARS]; uint32_t sid; uint32_t rev; uint32_t gid; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index cea56672ba71..353753884204 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -657,9 +657,9 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec } if (pd->capname != NULL) { if (pd->flags & DETECT_PCRE_CAPTURE_PKT) - pd->capidx = VariableNameGetIdx(de_ctx, (char *)pd->capname, VAR_TYPE_PKT_VAR); + pd->capidx = VarNameStoreSetupAdd((char *)pd->capname, VAR_TYPE_PKT_VAR); else if (pd->flags & DETECT_PCRE_CAPTURE_FLOW) - pd->capidx = VariableNameGetIdx(de_ctx, (char *)pd->capname, VAR_TYPE_FLOW_VAR); + pd->capidx = VarNameStoreSetupAdd((char *)pd->capname, VAR_TYPE_FLOW_VAR); } SCLogDebug("pd->capname %s", pd->capname); diff --git a/src/detect-pcre.h b/src/detect-pcre.h index 50b93b052833..3f9ce7557f8c 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -39,7 +39,7 @@ typedef struct DetectPcreData_ { pcre_extra *sd; int opts; uint16_t flags; - uint16_t capidx; + uint32_t capidx; char *capname; } DetectPcreData; diff --git a/src/detect-xbits.c b/src/detect-xbits.c index 664f9451a3d1..a6264ea26709 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -304,7 +304,7 @@ static int DetectXbitParse(DetectEngineCtx *de_ctx, if (unlikely(cd == NULL)) return -1; - cd->idx = VariableNameGetIdx(de_ctx, fb_name, var_type); + cd->idx = VarNameStoreSetupAdd(fb_name, var_type); cd->cmd = fb_cmd; cd->tracker = hb_dir; cd->type = var_type; diff --git a/src/detect-xbits.h b/src/detect-xbits.h index 6794af2d9c56..4f34ef0dfe1e 100644 --- a/src/detect-xbits.h +++ b/src/detect-xbits.h @@ -40,7 +40,7 @@ #define DETECT_XBITS_EXPIRE_DEFAULT 30 typedef struct DetectXbitsData_ { - uint16_t idx; + uint32_t idx; uint8_t cmd; uint8_t tracker; uint32_t expire; diff --git a/src/detect.c b/src/detect.c index 177daeeae3e7..bbfa9ab94b1c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -890,7 +890,7 @@ static void AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(Packet *p, DetectEn } FlowBit *fb = (FlowBit *) gv; - const char *name = VariableIdxGetName(de_ctx, fb->idx, VAR_TYPE_FLOW_BIT); + const char *name = VarNameStoreLookupById(fb->idx, VAR_TYPE_FLOW_BIT); if (name != NULL) { p->debuglog_flowbits_names[i] = SCStrdup(name); if (p->debuglog_flowbits_names[i] == NULL) { @@ -3858,6 +3858,10 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) #endif SCFree(de_ctx->app_mpms); de_ctx->app_mpms = NULL; + + if (!DetectEngineMultiTenantEnabled()) { + VarNameStoreActivateStaging(); + } return 0; } diff --git a/src/detect.h b/src/detect.h index 88c31ddd3cdc..fd609f056b77 100644 --- a/src/detect.h +++ b/src/detect.h @@ -47,6 +47,8 @@ #include "stream.h" +#include "util-var-name.h" + #define DETECT_MAX_RULE_SIZE 8192 /* forward declarations for the structures from detect-engine-sigorder.h */ @@ -495,7 +497,7 @@ typedef struct DetectReplaceList_ { /** list for flowvar store candidates, to be stored from * post-match function */ typedef struct DetectFlowvarList_ { - uint16_t idx; /**< flowvar name idx */ + uint32_t idx; /**< flowvar name idx */ uint16_t len; /**< data len */ int type; /**< type of store candidate POSTMATCH or ALWAYS */ uint8_t *buffer; /**< alloc'd buffer, may be freed by @@ -618,10 +620,6 @@ typedef struct DetectEngineCtx_ { HashListTable *mpm_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; diff --git a/src/flow-bit.c b/src/flow-bit.c index 533bef5cc9df..3662611ec8cf 100644 --- a/src/flow-bit.c +++ b/src/flow-bit.c @@ -43,7 +43,7 @@ #include "util-unittest.h" /* get the flowbit with idx from the flow */ -static FlowBit *FlowBitGet(Flow *f, uint16_t idx) +static FlowBit *FlowBitGet(Flow *f, uint32_t idx) { GenericVar *gv = f->flowvar; for ( ; gv != NULL; gv = gv->next) { @@ -56,7 +56,7 @@ static FlowBit *FlowBitGet(Flow *f, uint16_t idx) } /* add a flowbit to the flow */ -static void FlowBitAdd(Flow *f, uint16_t idx) +static void FlowBitAdd(Flow *f, uint32_t idx) { FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) { @@ -71,7 +71,7 @@ static void FlowBitAdd(Flow *f, uint16_t idx) } } -static void FlowBitRemove(Flow *f, uint16_t idx) +static void FlowBitRemove(Flow *f, uint32_t idx) { FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) @@ -81,17 +81,17 @@ static void FlowBitRemove(Flow *f, uint16_t idx) FlowBitFree(fb); } -void FlowBitSet(Flow *f, uint16_t idx) +void FlowBitSet(Flow *f, uint32_t idx) { FlowBitAdd(f, idx); } -void FlowBitUnset(Flow *f, uint16_t idx) +void FlowBitUnset(Flow *f, uint32_t idx) { FlowBitRemove(f, idx); } -void FlowBitToggle(Flow *f, uint16_t idx) +void FlowBitToggle(Flow *f, uint32_t idx) { FlowBit *fb = FlowBitGet(f, idx); if (fb != NULL) { @@ -101,7 +101,7 @@ void FlowBitToggle(Flow *f, uint16_t idx) } } -int FlowBitIsset(Flow *f, uint16_t idx) +int FlowBitIsset(Flow *f, uint32_t idx) { int r = 0; @@ -113,7 +113,7 @@ int FlowBitIsset(Flow *f, uint16_t idx) return r; } -int FlowBitIsnotset(Flow *f, uint16_t idx) +int FlowBitIsnotset(Flow *f, uint32_t idx) { int r = 0; diff --git a/src/flow-bit.h b/src/flow-bit.h index 633b5ee3d9a9..e6161606fc42 100644 --- a/src/flow-bit.h +++ b/src/flow-bit.h @@ -29,7 +29,7 @@ typedef struct FlowBit_ { uint8_t type; /* type, DETECT_FLOWBITS in this case */ - uint16_t idx; /* name idx */ + uint32_t idx; /* name idx */ GenericVar *next; /* right now just implement this as a list, * in the long run we have think of something * faster. */ @@ -38,10 +38,10 @@ typedef struct FlowBit_ { void FlowBitFree(FlowBit *); void FlowBitRegisterTests(void); -void FlowBitSet(Flow *, uint16_t); -void FlowBitUnset(Flow *, uint16_t); -void FlowBitToggle(Flow *, uint16_t); -int FlowBitIsset(Flow *, uint16_t); -int FlowBitIsnotset(Flow *, uint16_t); +void FlowBitSet(Flow *, uint32_t); +void FlowBitUnset(Flow *, uint32_t); +void FlowBitToggle(Flow *, uint32_t); +int FlowBitIsset(Flow *, uint32_t); +int FlowBitIsnotset(Flow *, uint32_t); #endif /* __FLOW_BIT_H__ */ diff --git a/src/flow-var.c b/src/flow-var.c index 96b3ad3a84ef..d929d5587445 100644 --- a/src/flow-var.c +++ b/src/flow-var.c @@ -51,7 +51,7 @@ static void FlowVarUpdateInt(FlowVar *fv, uint32_t value) * \note flow is not locked by this function, caller is * responsible */ -FlowVar *FlowVarGet(Flow *f, uint16_t idx) +FlowVar *FlowVarGet(Flow *f, uint32_t idx) { GenericVar *gv = f->flowvar; @@ -64,7 +64,7 @@ FlowVar *FlowVarGet(Flow *f, uint16_t idx) } /* add a flowvar to the flow, or update it */ -void FlowVarAddStrNoLock(Flow *f, uint16_t idx, uint8_t *value, uint16_t size) +void FlowVarAddStrNoLock(Flow *f, uint32_t idx, uint8_t *value, uint16_t size) { FlowVar *fv = FlowVarGet(f, idx); if (fv == NULL) { @@ -86,13 +86,13 @@ void FlowVarAddStrNoLock(Flow *f, uint16_t idx, uint8_t *value, uint16_t size) } /* add a flowvar to the flow, or update it */ -void FlowVarAddStr(Flow *f, uint16_t idx, uint8_t *value, uint16_t size) +void FlowVarAddStr(Flow *f, uint32_t idx, uint8_t *value, uint16_t size) { FlowVarAddStrNoLock(f, idx, value, size); } /* add a flowvar to the flow, or update it */ -void FlowVarAddIntNoLock(Flow *f, uint16_t idx, uint32_t value) +void FlowVarAddIntNoLock(Flow *f, uint32_t idx, uint32_t value) { FlowVar *fv = FlowVarGet(f, idx); if (fv == NULL) { @@ -113,7 +113,7 @@ void FlowVarAddIntNoLock(Flow *f, uint16_t idx, uint32_t value) } /* add a flowvar to the flow, or update it */ -void FlowVarAddInt(Flow *f, uint16_t idx, uint32_t value) +void FlowVarAddInt(Flow *f, uint32_t idx, uint32_t value) { FlowVarAddIntNoLock(f, idx, value); } @@ -144,7 +144,7 @@ void FlowVarPrint(GenericVar *gv) FlowVar *fv = (FlowVar *)gv; if (fv->datatype == FLOWVAR_TYPE_STR) { - SCLogDebug("Name idx \"%" PRIu16 "\", Value \"", fv->idx); + SCLogDebug("Name idx \"%" PRIu32 "\", Value \"", fv->idx); for (u = 0; u < fv->data.fv_str.value_len; u++) { if (isprint(fv->data.fv_str.value[u])) SCLogDebug("%c", fv->data.fv_str.value[u]); @@ -153,7 +153,7 @@ void FlowVarPrint(GenericVar *gv) } SCLogDebug("\", Len \"%" PRIu16 "\"\n", fv->data.fv_str.value_len); } else if (fv->datatype == FLOWVAR_TYPE_INT) { - SCLogDebug("Name idx \"%" PRIu16 "\", Value \"%" PRIu32 "\"", fv->idx, + SCLogDebug("Name idx \"%" PRIu32 "\", Value \"%" PRIu32 "\"", fv->idx, fv->data.fv_int.value); } else { SCLogDebug("Unknown data type at flowvars\n"); diff --git a/src/flow-var.h b/src/flow-var.h index e45d803043a7..0f7eeeb9266f 100644 --- a/src/flow-var.h +++ b/src/flow-var.h @@ -47,7 +47,7 @@ typedef struct FlowVarTypeInt_ { /** Generic Flowvar Structure */ typedef struct FlowVar_ { uint8_t type; /* type, DETECT_FLOWVAR in this case */ - uint16_t idx; /* name idx */ + uint32_t idx; /* name idx */ GenericVar *next; /* right now just implement this as a list, * in the long run we have think of something * faster. */ @@ -61,11 +61,11 @@ typedef struct FlowVar_ { /** Flowvar Interface API */ -void FlowVarAddStrNoLock(Flow *, uint16_t, uint8_t *, uint16_t); -void FlowVarAddStr(Flow *, uint16_t, uint8_t *, uint16_t); -void FlowVarAddIntNoLock(Flow *, uint16_t, uint32_t); -void FlowVarAddInt(Flow *, uint16_t, uint32_t); -FlowVar *FlowVarGet(Flow *, uint16_t); +void FlowVarAddStrNoLock(Flow *, uint32_t, uint8_t *, uint16_t); +void FlowVarAddStr(Flow *, uint32_t, uint8_t *, uint16_t); +void FlowVarAddIntNoLock(Flow *, uint32_t, uint32_t); +void FlowVarAddInt(Flow *, uint32_t, uint32_t); +FlowVar *FlowVarGet(Flow *, uint32_t); void FlowVarFree(FlowVar *); void FlowVarPrint(GenericVar *); diff --git a/src/host-bit.c b/src/host-bit.c index 9c4083b02eda..757654f7be72 100644 --- a/src/host-bit.c +++ b/src/host-bit.c @@ -78,7 +78,7 @@ int HostBitsTimedoutCheck(Host *h, struct timeval *ts) } /* get the bit with idx from the host */ -static XBit *HostBitGet(Host *h, uint16_t idx) +static XBit *HostBitGet(Host *h, uint32_t idx) { GenericVar *gv = HostGetStorageById(h, host_bit_id); for ( ; gv != NULL; gv = gv->next) { @@ -91,7 +91,7 @@ static XBit *HostBitGet(Host *h, uint16_t idx) } /* add a flowbit to the flow */ -static void HostBitAdd(Host *h, uint16_t idx, uint32_t expire) +static void HostBitAdd(Host *h, uint32_t idx, uint32_t expire) { XBit *fb = HostBitGet(h, idx); if (fb == NULL) { @@ -114,7 +114,7 @@ static void HostBitAdd(Host *h, uint16_t idx, uint32_t expire) } } -static void HostBitRemove(Host *h, uint16_t idx) +static void HostBitRemove(Host *h, uint32_t idx) { XBit *fb = HostBitGet(h, idx); if (fb == NULL) @@ -128,7 +128,7 @@ static void HostBitRemove(Host *h, uint16_t idx) } } -void HostBitSet(Host *h, uint16_t idx, uint32_t expire) +void HostBitSet(Host *h, uint32_t idx, uint32_t expire) { XBit *fb = HostBitGet(h, idx); if (fb == NULL) { @@ -136,7 +136,7 @@ void HostBitSet(Host *h, uint16_t idx, uint32_t expire) } } -void HostBitUnset(Host *h, uint16_t idx) +void HostBitUnset(Host *h, uint32_t idx) { XBit *fb = HostBitGet(h, idx); if (fb != NULL) { @@ -144,7 +144,7 @@ void HostBitUnset(Host *h, uint16_t idx) } } -void HostBitToggle(Host *h, uint16_t idx, uint32_t expire) +void HostBitToggle(Host *h, uint32_t idx, uint32_t expire) { XBit *fb = HostBitGet(h, idx); if (fb != NULL) { @@ -154,7 +154,7 @@ void HostBitToggle(Host *h, uint16_t idx, uint32_t expire) } } -int HostBitIsset(Host *h, uint16_t idx, uint32_t ts) +int HostBitIsset(Host *h, uint32_t idx, uint32_t ts) { XBit *fb = HostBitGet(h, idx); if (fb != NULL) { @@ -167,7 +167,7 @@ int HostBitIsset(Host *h, uint16_t idx, uint32_t ts) return 0; } -int HostBitIsnotset(Host *h, uint16_t idx, uint32_t ts) +int HostBitIsnotset(Host *h, uint32_t idx, uint32_t ts) { XBit *fb = HostBitGet(h, idx); if (fb == NULL) { diff --git a/src/host-bit.h b/src/host-bit.h index d4bba11abf5b..f125ed09cb51 100644 --- a/src/host-bit.h +++ b/src/host-bit.h @@ -33,9 +33,9 @@ void HostBitRegisterTests(void); int HostHasHostBits(Host *host); int HostBitsTimedoutCheck(Host *h, struct timeval *ts); -void HostBitSet(Host *, uint16_t, uint32_t); -void HostBitUnset(Host *, uint16_t); -void HostBitToggle(Host *, uint16_t, uint32_t); -int HostBitIsset(Host *, uint16_t, uint32_t); -int HostBitIsnotset(Host *, uint16_t, uint32_t); +void HostBitSet(Host *, uint32_t, uint32_t); +void HostBitUnset(Host *, uint32_t); +void HostBitToggle(Host *, uint32_t, uint32_t); +int HostBitIsset(Host *, uint32_t, uint32_t); +int HostBitIsnotset(Host *, uint32_t, uint32_t); #endif /* __HOST_BIT_H__ */ diff --git a/src/ippair-bit.c b/src/ippair-bit.c index b69fec2fd8d7..c617371630d5 100644 --- a/src/ippair-bit.c +++ b/src/ippair-bit.c @@ -78,7 +78,7 @@ int IPPairBitsTimedoutCheck(IPPair *h, struct timeval *ts) } /* get the bit with idx from the ippair */ -static XBit *IPPairBitGet(IPPair *h, uint16_t idx) +static XBit *IPPairBitGet(IPPair *h, uint32_t idx) { GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); for ( ; gv != NULL; gv = gv->next) { @@ -91,7 +91,7 @@ static XBit *IPPairBitGet(IPPair *h, uint16_t idx) } /* add a flowbit to the flow */ -static void IPPairBitAdd(IPPair *h, uint16_t idx, uint32_t expire) +static void IPPairBitAdd(IPPair *h, uint32_t idx, uint32_t expire) { XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) { @@ -114,7 +114,7 @@ static void IPPairBitAdd(IPPair *h, uint16_t idx, uint32_t expire) } } -static void IPPairBitRemove(IPPair *h, uint16_t idx) +static void IPPairBitRemove(IPPair *h, uint32_t idx) { XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) @@ -127,7 +127,7 @@ static void IPPairBitRemove(IPPair *h, uint16_t idx) } } -void IPPairBitSet(IPPair *h, uint16_t idx, uint32_t expire) +void IPPairBitSet(IPPair *h, uint32_t idx, uint32_t expire) { XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) { @@ -135,7 +135,7 @@ void IPPairBitSet(IPPair *h, uint16_t idx, uint32_t expire) } } -void IPPairBitUnset(IPPair *h, uint16_t idx) +void IPPairBitUnset(IPPair *h, uint32_t idx) { XBit *fb = IPPairBitGet(h, idx); if (fb != NULL) { @@ -143,7 +143,7 @@ void IPPairBitUnset(IPPair *h, uint16_t idx) } } -void IPPairBitToggle(IPPair *h, uint16_t idx, uint32_t expire) +void IPPairBitToggle(IPPair *h, uint32_t idx, uint32_t expire) { XBit *fb = IPPairBitGet(h, idx); if (fb != NULL) { @@ -153,7 +153,7 @@ void IPPairBitToggle(IPPair *h, uint16_t idx, uint32_t expire) } } -int IPPairBitIsset(IPPair *h, uint16_t idx, uint32_t ts) +int IPPairBitIsset(IPPair *h, uint32_t idx, uint32_t ts) { XBit *fb = IPPairBitGet(h, idx); if (fb != NULL) { @@ -167,7 +167,7 @@ int IPPairBitIsset(IPPair *h, uint16_t idx, uint32_t ts) return 0; } -int IPPairBitIsnotset(IPPair *h, uint16_t idx, uint32_t ts) +int IPPairBitIsnotset(IPPair *h, uint32_t idx, uint32_t ts) { XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) { diff --git a/src/ippair-bit.h b/src/ippair-bit.h index 44a0ac469c7e..cbc7cb739be8 100644 --- a/src/ippair-bit.h +++ b/src/ippair-bit.h @@ -33,10 +33,10 @@ void IPPairBitRegisterTests(void); int IPPairHasBits(IPPair *host); int IPPairBitsTimedoutCheck(IPPair *h, struct timeval *ts); -void IPPairBitSet(IPPair *, uint16_t, uint32_t); -void IPPairBitUnset(IPPair *, uint16_t); -void IPPairBitToggle(IPPair *, uint16_t, uint32_t); -int IPPairBitIsset(IPPair *, uint16_t, uint32_t); -int IPPairBitIsnotset(IPPair *, uint16_t, uint32_t); +void IPPairBitSet(IPPair *, uint32_t, uint32_t); +void IPPairBitUnset(IPPair *, uint32_t); +void IPPairBitToggle(IPPair *, uint32_t, uint32_t); +int IPPairBitIsset(IPPair *, uint32_t, uint32_t); +int IPPairBitIsnotset(IPPair *, uint32_t, uint32_t); #endif /* __IPPAIR_BIT_H__ */ diff --git a/src/util-var-name.c b/src/util-var-name.c index 73f87d3daded..276b8723dc2e 100644 --- a/src/util-var-name.c +++ b/src/util-var-name.c @@ -26,12 +26,43 @@ #include "suricata-common.h" #include "detect.h" #include "util-hashlist.h" +#include "util-var-name.h" + +/* the way this can be used w/o locking lookups: + * - Lookups use only g_varnamestore_current which is read only + * - Detection setups a new ctx in staging, which will include the 'current' + * entries keeping ID's stable + * - Detection hot swaps staging into current after a new detect engine was + * created. Current remains available through 'old'. + * - When detect reload is complete (threads are all moved over), 'old' can + * be freed. + */ + +typedef struct VarNameStore_ { + HashListTable *names; + HashListTable *ids; + uint32_t max_id; + uint32_t de_ctx_version; /**< de_ctx version 'owning' this */ +} VarNameStore; + +static int initialized = 0; +/* currently VarNameStore that is READ ONLY. This way lookups can + * be done w/o locking or synchronization */ +SC_ATOMIC_DECLARE(VarNameStore *, g_varnamestore_current); + +/* old VarNameStore on the way out */ +static VarNameStore *g_varnamestore_old = NULL; + +/* new VarNameStore that is being prepared. Multiple DetectLoader threads + * may be updating it so a lock is used for synchronization. */ +static VarNameStore *g_varnamestore_staging = NULL; +static SCMutex g_varnamestore_staging_m = SCMUTEX_INITIALIZER; /** \brief Name2idx mapping structure for flowbits, flowvars and pktvars. */ typedef struct VariableName_ { char *name; uint8_t type; /* flowbit, pktvar, etc */ - uint16_t idx; + uint32_t idx; } VariableName; static uint32_t VariableNameHash(HashListTable *ht, void *buf, uint16_t buflen) @@ -98,45 +129,49 @@ static void VariableNameFree(void *data) } /** \brief Initialize the Name idx hash. - * \param de_ctx Ptr to the detection engine ctx. - * \retval -1 in case of error - * \retval 0 in case of success */ -int VariableNameInitHash(DetectEngineCtx *de_ctx) +static VarNameStore *VarNameStoreInit(void) { - de_ctx->variable_names = HashListTableInit(4096, VariableNameHash, VariableNameCompare, VariableNameFree); - if (de_ctx->variable_names == NULL) - return -1; + VarNameStore *v = SCCalloc(1, sizeof(*v)); + if (v == NULL) + return NULL; + + v->names = HashListTableInit(4096, VariableNameHash, VariableNameCompare, VariableNameFree); + if (v->names == NULL) { + SCFree(v); + return NULL; + } - de_ctx->variable_idxs = HashListTableInit(4096, VariableIdxHash, VariableIdxCompare, NULL); - if (de_ctx->variable_idxs == NULL) - return -1; + v->ids = HashListTableInit(4096, VariableIdxHash, VariableIdxCompare, NULL); + if (v->ids == NULL) { + HashListTableFree(v->names); + SCFree(v); + return NULL; + } - de_ctx->variable_names_idx = 0; - return 0; + v->max_id = 0; + return v; } -void VariableNameFreeHash(DetectEngineCtx *de_ctx) +static void VarNameStoreDoFree(VarNameStore *v) { - if (de_ctx->variable_names != NULL) { - HashListTableFree(de_ctx->variable_names); - HashListTableFree(de_ctx->variable_idxs); - de_ctx->variable_names = NULL; - de_ctx->variable_idxs = NULL; + if (v) { + HashListTableFree(v->names); + HashListTableFree(v->ids); + SCFree(v); } - - return; } + /** \brief Get a name idx for a name. If the name is already used reuse the idx. * \param name nul terminated string with the name * \param type variable type * \retval 0 in case of error * \retval idx the idx or 0 */ -uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, const char *name, enum VarTypes type) +static uint32_t VariableNameGetIdx(VarNameStore *v, const char *name, enum VarTypes type) { - uint16_t idx = 0; + uint32_t idx = 0; VariableName *fn = SCMalloc(sizeof(VariableName)); if (unlikely(fn == NULL)) @@ -149,13 +184,14 @@ uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, const char *name, enum VarT if (fn->name == NULL) goto error; - VariableName *lookup_fn = (VariableName *)HashListTableLookup(de_ctx->variable_names, (void *)fn, 0); + VariableName *lookup_fn = (VariableName *)HashListTableLookup(v->names, (void *)fn, 0); if (lookup_fn == NULL) { - de_ctx->variable_names_idx++; + v->max_id++; - idx = fn->idx = de_ctx->variable_names_idx; - HashListTableAdd(de_ctx->variable_names, (void *)fn, 0); - HashListTableAdd(de_ctx->variable_idxs, (void *)fn, 0); + idx = fn->idx = v->max_id; + HashListTableAdd(v->names, (void *)fn, 0); + HashListTableAdd(v->ids, (void *)fn, 0); + SCLogDebug("new registration %s id %u type %u", fn->name, fn->idx, fn->type); } else { idx = lookup_fn->idx; VariableNameFree(fn); @@ -167,13 +203,15 @@ uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, const char *name, enum VarT return 0; } +#if 0 /** \brief Get a name from the idx. * \param idx index of the variable whose name is to be fetched * \param type variable type * \retval NULL in case of error * \retval name of the variable if successful. + * \todo no alloc on lookup */ -const char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, enum VarTypes type) +static const char *VariableIdxGetName(VarNameStore *v, uint32_t idx, enum VarTypes type) { VariableName *fn = SCMalloc(sizeof(VariableName)); if (unlikely(fn == NULL)) @@ -185,7 +223,7 @@ const char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, enum VarTy fn->type = type; fn->idx = idx; - VariableName *lookup_fn = (VariableName *)HashListTableLookup(de_ctx->variable_idxs, (void *)fn, 0); + VariableName *lookup_fn = (VariableName *)HashListTableLookup(v->ids, (void *)fn, 0); if (lookup_fn != NULL) { name = SCStrdup(lookup_fn->name); if (unlikely(name == NULL)) @@ -201,3 +239,141 @@ const char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, enum VarTy VariableNameFree(fn); return NULL; } +#endif +/** \brief setup staging store. Include current store if there is one. + */ +int VarNameStoreSetupStaging(uint32_t de_ctx_version) +{ + SCMutexLock(&g_varnamestore_staging_m); + + if (!initialized) { + SC_ATOMIC_INIT(g_varnamestore_current); + initialized = 1; + } + + if (g_varnamestore_staging != NULL && + g_varnamestore_staging->de_ctx_version == de_ctx_version) { + SCMutexUnlock(&g_varnamestore_staging_m); + return 0; + } + + VarNameStore *nv = VarNameStoreInit(); + if (nv == NULL) { + SCMutexUnlock(&g_varnamestore_staging_m); + return -1; + } + g_varnamestore_staging = nv; + nv->de_ctx_version = de_ctx_version; + + VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current); + if (current) { + /* add all entries from the current hash into this new one. */ + HashListTableBucket *b = HashListTableGetListHead(current->names); + while (b) { + VariableName *var = HashListTableGetListData(b); + + VariableName *newvar = SCCalloc(1, sizeof(*newvar)); + BUG_ON(newvar == NULL); + memcpy(newvar, var, sizeof(*newvar)); + newvar->name = SCStrdup(var->name); + BUG_ON(newvar->name == NULL); + + HashListTableAdd(nv->names, (void *)newvar, 0); + HashListTableAdd(nv->ids, (void *)newvar, 0); + nv->max_id = MAX(nv->max_id, newvar->idx); + SCLogDebug("xfer %s id %u type %u", newvar->name, newvar->idx, newvar->type); + + b = HashListTableGetListNext(b); + } + } + + SCLogDebug("set up staging with detect engine ver %u", nv->de_ctx_version); + SCMutexUnlock(&g_varnamestore_staging_m); + return 0; +} + +const char *VarNameStoreLookupById(const uint32_t id, const enum VarTypes type) +{ + VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current); + BUG_ON(current == NULL); + VariableName lookup = { NULL, type, id }; + VariableName *found = (VariableName *)HashListTableLookup(current->ids, (void *)&lookup, 0); + if (found == NULL) { + return NULL; + } + return found->name; +} + +uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type) +{ + VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current); + BUG_ON(current == NULL); + VariableName lookup = { (char *)name, type, 0 }; + VariableName *found = (VariableName *)HashListTableLookup(current->names, (void *)&lookup, 0); + if (found == NULL) { + return 0; + } + SCLogDebug("found %u for %s type %u", found->idx, name, type); + return found->idx; +} + +/** \brief add to staging or return existing id if already in there */ +uint32_t VarNameStoreSetupAdd(const char *name, const enum VarTypes type) +{ + uint32_t id; + SCMutexLock(&g_varnamestore_staging_m); + id = VariableNameGetIdx(g_varnamestore_staging, name, type); + SCMutexUnlock(&g_varnamestore_staging_m); + return id; +} + +void VarNameStoreActivateStaging(void) +{ + SCMutexLock(&g_varnamestore_staging_m); + if (g_varnamestore_old) { + VarNameStoreDoFree(g_varnamestore_old); + g_varnamestore_old = NULL; + } + g_varnamestore_old = SC_ATOMIC_GET(g_varnamestore_current); + SC_ATOMIC_SET(g_varnamestore_current, g_varnamestore_staging); + g_varnamestore_staging = NULL; + SCMutexUnlock(&g_varnamestore_staging_m); +} + +void VarNameStoreFreeOld(void) +{ + SCMutexLock(&g_varnamestore_staging_m); + SCLogDebug("freeing g_varnamestore_old %p", g_varnamestore_old); + if (g_varnamestore_old) { + VarNameStoreDoFree(g_varnamestore_old); + g_varnamestore_old = NULL; + } + SCMutexUnlock(&g_varnamestore_staging_m); +} + +void VarNameStoreFree(uint32_t de_ctx_version) +{ + SCLogDebug("freeing detect engine version %u", de_ctx_version); + SCMutexLock(&g_varnamestore_staging_m); + if (g_varnamestore_old && g_varnamestore_old->de_ctx_version == de_ctx_version) { + VarNameStoreDoFree(g_varnamestore_old); + g_varnamestore_old = NULL; + SCLogDebug("freeing detect engine version %u: old done", de_ctx_version); + } + + /* if at this point we have a staging area which matches our version + * we didn't complete the setup and are cleaning up the mess. */ + if (g_varnamestore_staging && g_varnamestore_staging->de_ctx_version == de_ctx_version) { + VarNameStoreDoFree(g_varnamestore_staging); + g_varnamestore_staging = NULL; + SCLogDebug("freeing detect engine version %u: staging done", de_ctx_version); + } + + VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current); + if (current && current->de_ctx_version == de_ctx_version) { + VarNameStoreDoFree(current); + SC_ATOMIC_SET(g_varnamestore_current, NULL); + SCLogDebug("freeing detect engine version %u: current done", de_ctx_version); + } + SCMutexUnlock(&g_varnamestore_staging_m); +} diff --git a/src/util-var-name.h b/src/util-var-name.h index 7d2c527a31af..c620d74eb5a4 100644 --- a/src/util-var-name.h +++ b/src/util-var-name.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -24,13 +24,13 @@ #ifndef __UTIL_VAR_NAME_H__ #define __UTIL_VAR_NAME_H__ -int VariableNameInitHash(DetectEngineCtx *); -void VariableNameFreeHash(DetectEngineCtx *); - -uint16_t VariableNameGetIdx(DetectEngineCtx *, - const char *name, enum VarTypes type); -const char *VariableIdxGetName(DetectEngineCtx *, - uint16_t id, enum VarTypes type); +int VarNameStoreSetupStaging(uint32_t de_ctx_version); +const char *VarNameStoreLookupById(const uint32_t id, const enum VarTypes type); +uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type); +uint32_t VarNameStoreSetupAdd(const char *name, const enum VarTypes type); +void VarNameStoreActivateStaging(void); +void VarNameStoreFreeOld(void); +void VarNameStoreFree(uint32_t de_ctx_version); #endif diff --git a/src/util-var.h b/src/util-var.h index 39f2698dc088..3deeaf747912 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -46,13 +46,13 @@ enum VarTypes { typedef struct GenericVar_ { uint8_t type; - uint16_t idx; + uint32_t idx; struct GenericVar_ *next; } GenericVar; typedef struct XBit_ { uint8_t type; /* type, DETECT_XBITS in this case */ - uint16_t idx; /* name idx */ + uint32_t idx; /* name idx */ GenericVar *next; uint32_t expire; } XBit; From e95a0c13447a2241a7f4e34c0c080bc6c421b02c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 21 Oct 2016 18:19:14 +0200 Subject: [PATCH 2433/2553] alert-debug: print flowbit names from VarNameStore --- src/alert-debuglog.c | 36 +++++----------------- src/decode.h | 4 --- src/detect.c | 72 -------------------------------------------- 3 files changed, 8 insertions(+), 104 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 267b8eb81119..0ffbaa91f706 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -78,7 +78,14 @@ static void AlertDebugLogFlowVars(AlertDebugLogThread *aft, const Packet *p) const GenericVar *gv = p->flow->flowvar; uint16_t i; while (gv != NULL) { - if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { + if (gv->type == DETECT_FLOWBITS) { + FlowBit *fb = (FlowBit *)gv; + const char *fbname = VarNameStoreLookupById(fb->idx, VAR_TYPE_FLOW_BIT); + if (fbname) { + MemBufferWriteString(aft->buffer, "FLOWBIT: %s\n", + fbname); + } + } else if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { FlowVar *fv = (FlowVar *) gv; if (fv->datatype == FLOWVAR_TYPE_STR) { @@ -102,32 +109,6 @@ static void AlertDebugLogFlowVars(AlertDebugLogThread *aft, const Packet *p) } } -/** - * \brief Function to log the FlowBits in to alert-debug.log - * - * \param aft Pointer to AltertDebugLog Thread - * \param p Pointer to the packet - * - * \todo const Packet ptr, requires us to change the - * debuglog_flowbits_names logic. - */ -static void AlertDebugLogFlowBits(AlertDebugLogThread *aft, Packet *p) -{ - int i; - for (i = 0; i < p->debuglog_flowbits_names_len; i++) { - if (p->debuglog_flowbits_names[i] != NULL) { - MemBufferWriteString(aft->buffer, "FLOWBIT: %s\n", - p->debuglog_flowbits_names[i]); - } - } - - SCFree(p->debuglog_flowbits_names); - p->debuglog_flowbits_names = NULL; - p->debuglog_flowbits_names_len = 0; - - return; -} - /** * \brief Function to log the PktVars in to alert-debug.log * @@ -237,7 +218,6 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da applayer ? "TRUE" : "FALSE", (p->flow->alproto != ALPROTO_UNKNOWN) ? "TRUE" : "FALSE", p->flow->alproto); AlertDebugLogFlowVars(aft, p); - AlertDebugLogFlowBits(aft, (Packet *)p); /* < no const */ } AlertDebugLogPktVars(aft, p); diff --git a/src/decode.h b/src/decode.h index d11b1cf931dd..d034df0c2493 100644 --- a/src/decode.h +++ b/src/decode.h @@ -552,10 +552,6 @@ typedef struct Packet_ /** data linktype in host order */ int datalink; - /* used to hold flowbits only if debuglog is enabled */ - int debuglog_flowbits_names_len; - const char **debuglog_flowbits_names; - /* tunnel/encapsulation handling */ struct Packet_ *root; /* in case of tunnel this is a ptr * to the 'real' packet, the one we diff --git a/src/detect.c b/src/detect.c index bbfa9ab94b1c..a3441cefcf2f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -856,72 +856,6 @@ static void DebugInspectIds(Packet *p, Flow *f, StreamMsg *smsg) } #endif -static void AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(Packet *p, DetectEngineCtx *de_ctx) -{ -#define MALLOC_JUMP 5 - - int i = 0; - - GenericVar *gv = p->flow->flowvar; - - while (gv != NULL) { - i++; - gv = gv->next; - } - if (i == 0) - return; - - p->debuglog_flowbits_names_len = i; - - p->debuglog_flowbits_names = SCMalloc(sizeof(char *) * - p->debuglog_flowbits_names_len); - if (p->debuglog_flowbits_names == NULL) { - return; - } - memset(p->debuglog_flowbits_names, 0, - sizeof(char *) * p->debuglog_flowbits_names_len); - - i = 0; - gv = p->flow->flowvar; - while (gv != NULL) { - if (gv->type != DETECT_FLOWBITS) { - gv = gv->next; - continue; - } - - FlowBit *fb = (FlowBit *) gv; - const char *name = VarNameStoreLookupById(fb->idx, VAR_TYPE_FLOW_BIT); - if (name != NULL) { - p->debuglog_flowbits_names[i] = SCStrdup(name); - if (p->debuglog_flowbits_names[i] == NULL) { - return; - } - i++; - } - - if (i == p->debuglog_flowbits_names_len) { - p->debuglog_flowbits_names_len += MALLOC_JUMP; - const char **names = SCRealloc(p->debuglog_flowbits_names, - sizeof(char *) * - p->debuglog_flowbits_names_len); - if (names == NULL) { - SCFree(p->debuglog_flowbits_names); - p->debuglog_flowbits_names = NULL; - p->debuglog_flowbits_names_len = 0; - return; - } - p->debuglog_flowbits_names = names; - memset(p->debuglog_flowbits_names + - p->debuglog_flowbits_names_len - MALLOC_JUMP, - 0, sizeof(char *) * MALLOC_JUMP); - } - - gv = gv->next; - } - - return; -} - static inline void DetectPrefilterBuildNonPrefilterList(DetectEngineThreadCtx *det_ctx, SignatureMask mask) { @@ -1582,12 +1516,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh * up again for the next packet. Also return any stream chunk we processed * to the pool. */ if (p->flags & PKT_HAS_FLOW) { - if (debuglog_enabled) { - if (p->alerts.cnt > 0) { - AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(p, de_ctx); - } - } - /* HACK: prevent the wrong sgh (or NULL) from being stored in the * flow's sgh pointers */ if (PKT_IS_ICMPV4(p) && ICMPV4_DEST_UNREACH_IS_VALID(p)) { From ac42a44280b81e161934419492b4551d42f8a9ab Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 21 Oct 2016 18:47:48 +0200 Subject: [PATCH 2434/2553] alert-debug: print flowvar/int names --- src/alert-debuglog.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 0ffbaa91f706..f2854bf8b8f1 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -89,8 +89,10 @@ static void AlertDebugLogFlowVars(AlertDebugLogThread *aft, const Packet *p) FlowVar *fv = (FlowVar *) gv; if (fv->datatype == FLOWVAR_TYPE_STR) { - MemBufferWriteString(aft->buffer, "FLOWVAR idx(%"PRIu32"): ", - fv->idx); + const char *fvname = VarNameStoreLookupById(fv->idx, + VAR_TYPE_FLOW_VAR); + MemBufferWriteString(aft->buffer, "FLOWVAR: \"%s\" => \"", + fvname); for (i = 0; i < fv->data.fv_str.value_len; i++) { if (isprint(fv->data.fv_str.value[i])) { MemBufferWriteString(aft->buffer, "%c", @@ -100,9 +102,12 @@ static void AlertDebugLogFlowVars(AlertDebugLogThread *aft, const Packet *p) fv->data.fv_str.value[i]); } } + MemBufferWriteString(aft->buffer, "\"\n"); } else if (fv->datatype == FLOWVAR_TYPE_INT) { - MemBufferWriteString(aft->buffer, "FLOWVAR idx(%"PRIu32"): " - " %" PRIu32 "\"", fv->idx, fv->data.fv_int.value); + const char *fvname = VarNameStoreLookupById(fv->idx, + VAR_TYPE_FLOW_INT); + MemBufferWriteString(aft->buffer, "FLOWINT: \"%s\" =>" + " %"PRIu32"\n", fvname, fv->data.fv_int.value); } } gv = gv->next; From 017b16d42174f3f7597a41088f1b00e830c2ecbd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 26 Oct 2016 14:35:26 +0200 Subject: [PATCH 2435/2553] detect-pcre: small cleanups --- src/detect-pcre.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 353753884204..8d2e758a83c0 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -77,12 +77,9 @@ static pcre_extra *parse_capture_regex_study; static int pcre_use_jit = 1; #endif -int DetectPcreMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); -int DetectPcreALMatchCookie(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m); -int DetectPcreALMatchMethod(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m); static int DetectPcreSetup (DetectEngineCtx *, Signature *, char *); -void DetectPcreFree(void *); -void DetectPcreRegisterTests(void); +static void DetectPcreFree(void *); +static void DetectPcreRegisterTests(void); void DetectPcreRegister (void) { @@ -747,7 +744,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst SCReturnInt(ret); } -void DetectPcreFree(void *ptr) +static void DetectPcreFree(void *ptr) { if (ptr == NULL) return; @@ -3306,7 +3303,7 @@ static int DetectPcreParseHttpHost(void) /** * \brief this function registers unit tests for DetectPcre */ -void DetectPcreRegisterTests(void) +static void DetectPcreRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); From a0bd15a1c47f64b34604fa3a4b8bd143af0bc1d6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 26 Oct 2016 16:55:34 +0200 Subject: [PATCH 2436/2553] pcre: support multiple captures Support up to 8 substring captures into pkt or flow vars. --- src/detect-engine-sigorder.c | 20 ++++- src/detect-pcre.c | 146 +++++++++++++++++++---------------- src/detect-pcre.h | 10 ++- src/util-error.c | 1 + src/util-error.h | 1 + 5 files changed, 102 insertions(+), 76 deletions(-) diff --git a/src/detect-engine-sigorder.c b/src/detect-engine-sigorder.c index 56b87c9cc614..737e49365353 100644 --- a/src/detect-engine-sigorder.c +++ b/src/detect-engine-sigorder.c @@ -267,8 +267,14 @@ static inline int SCSigGetFlowvarType(Signature *sig) while (sm != NULL) { pd = (DetectPcreData *)sm->ctx; - if (sm->type == DETECT_PCRE && (pd->flags & DETECT_PCRE_CAPTURE_FLOW)) { - write++; + if (sm->type == DETECT_PCRE) { + uint8_t x; + for (x = 0; x < pd->idx; x++) { + if (pd->captypes[x] == VAR_TYPE_FLOW_VAR) { + write++; + break; + } + } } sm = sm->next; @@ -319,8 +325,14 @@ static inline int SCSigGetPktvarType(Signature *sig) while (sm != NULL) { pd = (DetectPcreData *)sm->ctx; - if (sm->type == DETECT_PCRE && (pd->flags & DETECT_PCRE_CAPTURE_PKT)) { - write++; + if (sm->type == DETECT_PCRE) { + uint8_t x; + for (x = 0; x < pd->idx; x++) { + if (pd->captypes[x] == VAR_TYPE_PKT_VAR) { + write++; + break; + } + } } sm = sm->next; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 8d2e758a83c0..b3f7281dcc70 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -213,26 +213,29 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, /* regex matched and we're not negated, * considering it a match */ - SCLogDebug("ret %d capidx %u", ret, pe->capidx); + SCLogDebug("ret %d pe->idx %u", ret, pe->idx); /* see if we need to do substring capturing. */ - if (ret > 1 && pe->capidx != 0) { - SCLogDebug("capturing"); - const char *str_ptr; - ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, 1, &str_ptr); - if (ret) { - if (pe->flags & DETECT_PCRE_CAPTURE_PKT) { - if (p != NULL) { - PktVarAdd(p, pe->capname, (uint8_t *)str_ptr, ret); - } - } else if (pe->flags & DETECT_PCRE_CAPTURE_FLOW) { - if (f != NULL) { - /* store max 64k. Errors are ignored */ - capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; - (void)DetectFlowvarStoreMatch(det_ctx, pe->capidx, - (uint8_t *)str_ptr, capture_len, - DETECT_FLOWVAR_TYPE_POSTMATCH); - } + if (ret > 1 && pe->idx != 0) { + uint8_t x; + for (x = 0; x < pe->idx; x++) { + SCLogDebug("capturing"); + const char *str_ptr; + ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, x+1, &str_ptr); + if (unlikely(ret == 0)) + continue; + + if (pe->captypes[x] == VAR_TYPE_PKT_VAR && p != NULL) { + const char *varname = VarNameStoreLookupById(pe->capids[x], + VAR_TYPE_PKT_VAR); + PktVarAdd(p, varname, (uint8_t *)str_ptr, ret); + + } else if (pe->captypes[x] == VAR_TYPE_FLOW_VAR && f != NULL) { + /* store max 64k. Errors are ignored */ + capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; + (void)DetectFlowvarStoreMatch(det_ctx, pe->capids[x], + (uint8_t *)str_ptr, capture_len, + DETECT_FLOWVAR_TYPE_POSTMATCH); } } } @@ -607,7 +610,11 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec { int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; + memset(&ov, 0, sizeof(ov)); char type_str[16] = ""; + char *orig_right_edge = regexstr + strlen(regexstr); + + SCLogDebug("regexstr %s, pd %p", regexstr, pd); /* take the size of the whole input as buffer size for the string we will * extract below. Add 1 to please Coverity's alloc_strlen test. */ @@ -618,55 +625,57 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec if (de_ctx == NULL) goto error; - SCLogDebug("\'%s\'", regexstr); + while (1) { + SCLogDebug("\'%s\'", regexstr); - ret = pcre_exec(parse_capture_regex, parse_capture_regex_study, regexstr, strlen(regexstr), 0, 0, ov, MAX_SUBSTRINGS); - if (ret < 3) { - return 0; - } + ret = pcre_exec(parse_capture_regex, parse_capture_regex_study, regexstr, strlen(regexstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret < 3) { + return 0; + } - res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, type_str, sizeof(type_str)); - if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - goto error; - } - res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, capture_str, cap_buffer_len); - if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - goto error; - } - if (strlen(capture_str) == 0 || strlen(type_str) == 0) { - goto error; - } + res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, type_str, sizeof(type_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, capture_str, cap_buffer_len); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + if (strlen(capture_str) == 0 || strlen(type_str) == 0) { + goto error; + } - SCLogDebug("type \'%s\'", type_str); - SCLogDebug("capture \'%s\'", capture_str); + SCLogDebug("type \'%s\'", type_str); + SCLogDebug("capture \'%s\'", capture_str); - pd->capname = SCStrdup(capture_str); - if (unlikely(pd->capname == NULL)) - goto error; + if (pd->idx >= DETECT_PCRE_CAPTURE_MAX) { + SCLogError(SC_ERR_VAR_LIMIT, "rule can have maximally %d pkt/flow " + "var captures", DETECT_PCRE_CAPTURE_MAX); + return -1; + } - if (strcmp(type_str, "pkt") == 0) { - pd->flags |= DETECT_PCRE_CAPTURE_PKT; - } else if (strcmp(type_str, "flow") == 0) { - pd->flags |= DETECT_PCRE_CAPTURE_FLOW; - SCLogDebug("flow capture"); - } - if (pd->capname != NULL) { - if (pd->flags & DETECT_PCRE_CAPTURE_PKT) - pd->capidx = VarNameStoreSetupAdd((char *)pd->capname, VAR_TYPE_PKT_VAR); - else if (pd->flags & DETECT_PCRE_CAPTURE_FLOW) - pd->capidx = VarNameStoreSetupAdd((char *)pd->capname, VAR_TYPE_FLOW_VAR); - } + if (strcmp(type_str, "pkt") == 0) { + pd->capids[pd->idx] = VarNameStoreSetupAdd((char *)capture_str, VAR_TYPE_PKT_VAR); + pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR; + SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]); + pd->idx++; + } else if (strcmp(type_str, "flow") == 0) { + pd->capids[pd->idx] = VarNameStoreSetupAdd((char *)capture_str, VAR_TYPE_FLOW_VAR); + pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR; + pd->idx++; + } - SCLogDebug("pd->capname %s", pd->capname); + //SCLogDebug("pd->capname %s", pd->capname); + regexstr += ov[1]; + + if (regexstr >= orig_right_edge) + break; + } return 0; error: - if (pd->capname != NULL) { - SCFree(pd->capname); - pd->capname = NULL; - } return -1; } @@ -708,9 +717,12 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst sm->ctx = (void *)pd; SigMatchAppendSMToList(s, sm, sm_list); - if (pd->capidx != 0) { - if (DetectFlowvarPostMatchSetup(s, pd->capidx) < 0) - goto error_nofree; + uint8_t x; + for (x = 0; x < pd->idx; x++) { + if (pd->captypes[x] == VAR_TYPE_FLOW_VAR) { + if (DetectFlowvarPostMatchSetup(s, pd->capids[x]) < 0) + goto error_nofree; + } } if (!(pd->flags & DETECT_PCRE_RELATIVE)) @@ -751,8 +763,6 @@ static void DetectPcreFree(void *ptr) DetectPcreData *pd = (DetectPcreData *)ptr; - if (pd->capname != NULL) - SCFree(pd->capname); if (pd->re != NULL) pcre_free(pd->re); if (pd->sd != NULL) @@ -3022,7 +3032,7 @@ static int DetectPcreFlowvarCapture01(void) FAIL_IF(!(PacketAlertCheck(p1, 1))); - FlowVar *fv = FlowVarGet(&f, pd->capidx); + FlowVar *fv = FlowVarGet(&f, pd->capids[0]); FAIL_IF(fv == NULL); FAIL_IF(fv->data.fv_str.value_len != ualen1); @@ -3114,7 +3124,7 @@ static int DetectPcreFlowvarCapture02(void) s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; - FAIL_IF(pd1->capidx != pd2->capidx); + FAIL_IF(pd1->capids[0] != pd2->capids[0]); SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); @@ -3136,7 +3146,7 @@ static int DetectPcreFlowvarCapture02(void) FAIL_IF(!(PacketAlertCheck(p1, 1))); - FlowVar *fv = FlowVarGet(&f, pd1->capidx); + FlowVar *fv = FlowVarGet(&f, pd1->capids[0]); FAIL_IF(fv == NULL); if (fv->data.fv_str.value_len != ualen1) { @@ -3230,7 +3240,7 @@ static int DetectPcreFlowvarCapture03(void) s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; - FAIL_IF(pd1->capidx != pd2->capidx); + FAIL_IF(pd1->capids[0] != pd2->capids[0]); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -3249,7 +3259,7 @@ static int DetectPcreFlowvarCapture03(void) FAIL_IF(PacketAlertCheck(p1, 1)); - FlowVar *fv = FlowVarGet(&f, pd1->capidx); + FlowVar *fv = FlowVarGet(&f, pd1->capids[0]); FAIL_IF(fv != NULL); if (alp_tctx != NULL) diff --git a/src/detect-pcre.h b/src/detect-pcre.h index 3f9ce7557f8c..14360c1eefeb 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -27,20 +27,22 @@ #define DETECT_PCRE_RELATIVE 0x00001 #define DETECT_PCRE_RAWBYTES 0x00002 #define DETECT_PCRE_CASELESS 0x00004 -#define DETECT_PCRE_CAPTURE_PKT 0x00008 -#define DETECT_PCRE_CAPTURE_FLOW 0x00010 + #define DETECT_PCRE_MATCH_LIMIT 0x00020 #define DETECT_PCRE_RELATIVE_NEXT 0x00040 #define DETECT_PCRE_NEGATE 0x00080 +#define DETECT_PCRE_CAPTURE_MAX 8 + typedef struct DetectPcreData_ { /* pcre options */ pcre *re; pcre_extra *sd; int opts; uint16_t flags; - uint32_t capidx; - char *capname; + uint8_t idx; + uint8_t captypes[DETECT_PCRE_CAPTURE_MAX]; + uint32_t capids[DETECT_PCRE_CAPTURE_MAX]; } DetectPcreData; /* prototypes */ diff --git a/src/util-error.c b/src/util-error.c index 105add555dc6..4503986fb5c2 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -335,6 +335,7 @@ const char * SCErrorToString(SCError err) CASE_CODE(SC_WARN_REMOVE_FILE); CASE_CODE (SC_ERR_NO_MAGIC_SUPPORT); CASE_CODE (SC_ERR_REDIS); + CASE_CODE (SC_ERR_VAR_LIMIT); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index acaec8162567..59778c5606c4 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -325,6 +325,7 @@ typedef enum { SC_WARN_REMOVE_FILE, SC_ERR_NO_MAGIC_SUPPORT, SC_ERR_REDIS, + SC_ERR_VAR_LIMIT, } SCError; const char *SCErrorToString(SCError); From 5e39486399457b494ea323b71b34ef8dcde47438 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 27 Oct 2016 15:41:10 +0200 Subject: [PATCH 2437/2553] pkt-var: use id instead of name pointer --- src/alert-debuglog.c | 5 +++-- src/decode.h | 2 +- src/detect-pcre.c | 4 +--- src/detect-pktvar.c | 12 ++--------- src/detect-pktvar.h | 4 ++-- src/detect.c | 51 +++++++++++++++----------------------------- src/pkt-var.c | 39 ++++++++++----------------------- src/pkt-var.h | 7 +++--- 8 files changed, 40 insertions(+), 84 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index f2854bf8b8f1..7d0ad0e26171 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -125,8 +125,9 @@ static void AlertDebugLogPktVars(AlertDebugLogThread *aft, const Packet *p) { const PktVar *pv = p->pktvar; - while(pv != NULL) { - MemBufferWriteString(aft->buffer, "PKTVAR: %s\n", pv->name); + while (pv != NULL) { + const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); + MemBufferWriteString(aft->buffer, "PKTVAR: %s\n", varname); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, pv->value, pv->value_len); pv = pv->next; diff --git a/src/decode.h b/src/decode.h index d034df0c2493..6d0ad53ee7c5 100644 --- a/src/decode.h +++ b/src/decode.h @@ -298,7 +298,7 @@ typedef struct PacketEngineEvents_ { } PacketEngineEvents; typedef struct PktVar_ { - const char *name; + uint32_t id; struct PktVar_ *next; /* right now just implement this as a list, * in the long run we have thing of something * faster. */ diff --git a/src/detect-pcre.c b/src/detect-pcre.c index b3f7281dcc70..1fe8af27584d 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -226,9 +226,7 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, continue; if (pe->captypes[x] == VAR_TYPE_PKT_VAR && p != NULL) { - const char *varname = VarNameStoreLookupById(pe->capids[x], - VAR_TYPE_PKT_VAR); - PktVarAdd(p, varname, (uint8_t *)str_ptr, ret); + PktVarAdd(p, pe->capids[x], (uint8_t *)str_ptr, ret); } else if (pe->captypes[x] == VAR_TYPE_FLOW_VAR && f != NULL) { /* store max 64k. Errors are ignored */ diff --git a/src/detect-pktvar.c b/src/detect-pktvar.c index 919ea2d878b9..7a720839d7bf 100644 --- a/src/detect-pktvar.c +++ b/src/detect-pktvar.c @@ -66,7 +66,7 @@ static int DetectPktvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pac int ret = 0; const DetectPktvarData *pd = (const DetectPktvarData *)ctx; - PktVar *pv = PktVarGet(p, pd->name); + PktVar *pv = PktVarGet(p, pd->id); if (pv != NULL) { uint8_t *ptr = SpmSearch(pv->value, pv->value_len, pd->content, pd->content_len); if (ptr != NULL) @@ -92,7 +92,6 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst if (ret != 3) { SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for pktvar.", rawstr); return -1; - } const char *str_ptr; @@ -199,12 +198,7 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst return -1; } - cd->name = SCStrdup(varname); - if (cd->name == NULL) { - SCFree(cd); - if (dubbed) SCFree(str); - return -1; - } + cd->id = VarNameStoreSetupAdd(varname, VAR_TYPE_PKT_VAR); memcpy(cd->content, str, len); cd->content_len = len; @@ -228,8 +222,6 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst if (dubbed) SCFree(str); if (cd) { - if (cd->name) - SCFree(cd->name); SCFree(cd); } if (sm) diff --git a/src/detect-pktvar.h b/src/detect-pktvar.h index e5d1d3a6a116..e6e5211dd6ea 100644 --- a/src/detect-pktvar.h +++ b/src/detect-pktvar.h @@ -25,10 +25,10 @@ #define __DETECT_PKTVAR_H__ typedef struct DetectPktvarData_ { - char *name; - uint8_t *content; + uint32_t id; uint8_t content_len; uint8_t flags; + uint8_t *content; } DetectPktvarData; /* prototypes */ diff --git a/src/detect.c b/src/detect.c index a3441cefcf2f..3797a2272c9f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -5133,59 +5133,42 @@ static int SigTest17 (void) Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketSrcDstPorts((uint8_t *)buf, buflen, IPPROTO_TCP, 12345, 80); + FAIL_IF_NULL(p); ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any $HTTP_PORTS (msg:\"HTTP host cap\"; content:\"Host:\"; pcre:\"/^Host: (?P.*)\\r\\n/m\"; noalert; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any $HTTP_PORTS (msg:\"HTTP host cap\"; content:\"Host:\"; pcre:\"/^Host: (?P.*)\\r\\n/m\"; noalert; sid:1;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - PktVar *pv_hn = PktVarGet(p, "http_host"); - if (pv_hn != NULL) { - if (memcmp(pv_hn->value, "one.example.org", pv_hn->value_len < 15 ? pv_hn->value_len : 15) == 0) - result = 1; - else { - printf("\""); - PrintRawUriFp(stdout, pv_hn->value, pv_hn->value_len); - printf("\" != \"one.example.org\": "); - } - PktVarFree(pv_hn); - } else { - printf("Pkt var http_host not captured: "); - } -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } + uint32_t capid = VarNameStoreLookupByName("http_host", VAR_TYPE_PKT_VAR); + + PktVar *pv_hn = PktVarGet(p, capid); + FAIL_IF_NULL(pv_hn); + + FAIL_IF(pv_hn->value_len != 15); + FAIL_IF_NOT(memcmp(pv_hn->value, "one.example.org", pv_hn->value_len) == 0); + + PktVarFree(pv_hn); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); ConfDeInit(); ConfRestoreContextBackup(); UTHFreePackets(&p, 1); - return result; + + PASS; } static int SigTest18 (void) diff --git a/src/pkt-var.c b/src/pkt-var.c index dcc706959b5d..333f2977bd44 100644 --- a/src/pkt-var.c +++ b/src/pkt-var.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -35,9 +35,10 @@ #include "util-debug.h" /* puts a new value into a pktvar */ -void PktVarUpdate(PktVar *pv, uint8_t *value, uint16_t size) +static void PktVarUpdate(PktVar *pv, uint8_t *value, uint16_t size) { - if (pv->value) SCFree(pv->value); + if (pv->value) + SCFree(pv->value); pv->value = value; pv->value_len = size; } @@ -45,12 +46,12 @@ void PktVarUpdate(PktVar *pv, uint8_t *value, uint16_t size) /* get the pktvar with name 'name' from the pkt * * name is a normal string*/ -PktVar *PktVarGet(Packet *p, const char *name) +PktVar *PktVarGet(Packet *p, uint32_t id) { PktVar *pv = p->pktvar; for (;pv != NULL; pv = pv->next) { - if (pv->name && strcmp(pv->name, name) == 0) + if (pv->id == id) return pv; } @@ -58,23 +59,24 @@ PktVar *PktVarGet(Packet *p, const char *name) } /* add a pktvar to the pkt, or update it */ -void PktVarAdd(Packet *p, const char *name, uint8_t *value, uint16_t size) +void PktVarAdd(Packet *p, uint32_t id, uint8_t *value, uint16_t size) { //printf("Adding packet var \"%s\" with value(%" PRId32 ") \"%s\"\n", name, size, value); - PktVar *pv = PktVarGet(p, name); + PktVar *pv = PktVarGet(p, id); if (pv == NULL) { pv = SCMalloc(sizeof(PktVar)); if (unlikely(pv == NULL)) return; - pv->name = name; + pv->id = id; pv->value = value; pv->value_len = size; pv->next = NULL; PktVar *tpv = p->pktvar; - if (p->pktvar == NULL) p->pktvar = pv; + if (p->pktvar == NULL) + p->pktvar = pv; else { while(tpv) { if (tpv->next == NULL) { @@ -94,7 +96,6 @@ void PktVarFree(PktVar *pv) if (pv == NULL) return; - pv->name = NULL; if (pv->value != NULL) SCFree(pv->value); PktVar *pv_next = pv->next; @@ -104,21 +105,3 @@ void PktVarFree(PktVar *pv) if (pv_next != NULL) PktVarFree(pv_next); } - -void PktVarPrint(PktVar *pv) -{ - uint16_t i; - - if (pv == NULL) - return; - - printf("Name \"%s\", Value \"", pv->name); - for (i = 0; i < pv->value_len; i++) { - if (isprint(pv->value[i])) printf("%c", pv->value[i]); - else printf("\\%02X", pv->value[i]); - } - printf("\", Len \"%" PRIu32 "\"\n", pv->value_len); - - PktVarPrint(pv->next); -} - diff --git a/src/pkt-var.h b/src/pkt-var.h index 613bd1d7e76f..cfdd6f5aee5c 100644 --- a/src/pkt-var.h +++ b/src/pkt-var.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 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 @@ -24,10 +24,9 @@ #ifndef __PKT_VAR_H__ #define __PKT_VAR_H__ -void PktVarAdd(Packet *, const char *, uint8_t *, uint16_t); -PktVar *PktVarGet(Packet *, const char *); +void PktVarAdd(Packet *, uint32_t id, uint8_t *, uint16_t); +PktVar *PktVarGet(Packet *, uint32_t id); void PktVarFree(PktVar *); -void PktVarPrint(PktVar *); #endif /* __PKT_VAR_H__ */ From 0f708d427bbee9708601a8a0557af247a4942f9a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 27 Oct 2016 17:41:38 +0200 Subject: [PATCH 2438/2553] pkt-var: abuse flowvar postmatch logic for pktvars Flowvars were already using a temporary store in the detect thread ctx. Use the same facility for pktvars. The reasons are: 1. packet is not always available, e.g. when running pcre on http buffers. 2. setting of vars should be done post match. Until now it was also possible that it is done on a partial match. --- src/detect-engine-state.c | 2 +- src/detect-flowvar.c | 37 +++++++++++++++++++++---------------- src/detect-flowvar.h | 16 ++++++++-------- src/detect-pcre.c | 23 ++++++++++++++--------- src/detect.c | 22 ++++++++++------------ src/detect.h | 15 ++++++++------- 6 files changed, 62 insertions(+), 53 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index e25accf3fd0a..687e3b397ba6 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -715,7 +715,7 @@ static int DoInspectItem(ThreadVars *tv, SCLogDebug("MATCH: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); } - DetectFlowvarProcessList(det_ctx, f); + DetectVarProcessList(det_ctx, f, p); return 1; } diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index c5f838bb6c31..b0c30d4099b0 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -33,6 +33,7 @@ #include "threads.h" #include "flow.h" #include "flow-var.h" +#include "pkt-var.h" #include "detect-flowvar.h" #include "util-spm.h" @@ -194,10 +195,10 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws /** \brief Store flowvar in det_ctx so we can exec it post-match */ -int DetectFlowvarStoreMatch(DetectEngineThreadCtx *det_ctx, uint32_t idx, +int DetectVarStoreMatch(DetectEngineThreadCtx *det_ctx, uint32_t idx, uint8_t *buffer, uint16_t len, int type) { - DetectFlowvarList *fs = det_ctx->flowvarlist; + DetectVarList *fs = det_ctx->varlist; /* first check if we have had a previous match for this idx */ for ( ; fs != NULL; fs = fs->next) { @@ -216,8 +217,8 @@ int DetectFlowvarStoreMatch(DetectEngineThreadCtx *det_ctx, uint32_t idx, fs->idx = idx; - fs->next = det_ctx->flowvarlist; - det_ctx->flowvarlist = fs; + fs->next = det_ctx->varlist; + det_ctx->varlist = fs; } fs->len = len; @@ -266,29 +267,33 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectFlowvarList *fs, *prev; + DetectVarList *fs, *prev; const DetectFlowvarData *fd; - if (det_ctx->flowvarlist == NULL || p->flow == NULL) + if (det_ctx->varlist == NULL) return 1; fd = (const DetectFlowvarData *)ctx; prev = NULL; - fs = det_ctx->flowvarlist; + fs = det_ctx->varlist; while (fs != NULL) { if (fd->idx == fs->idx) { SCLogDebug("adding to the flow %u:", fs->idx); //PrintRawDataFp(stdout, fs->buffer, fs->len); - FlowVarAddStrNoLock(p->flow, fs->idx, fs->buffer, fs->len); - /* memory at fs->buffer is now the responsibility of - * the flowvar code. */ + if (fs->type == DETECT_VAR_TYPE_FLOW_POSTMATCH && p && p->flow) { + FlowVarAddStrNoLock(p->flow, fs->idx, fs->buffer, fs->len); + /* memory at fs->buffer is now the responsibility of + * the flowvar code. */ + } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && p) { + PktVarAdd(p, fs->idx, fs->buffer, fs->len); + } - if (fs == det_ctx->flowvarlist) { - det_ctx->flowvarlist = fs->next; + if (fs == det_ctx->varlist) { + det_ctx->varlist = fs->next; SCFree(fs); - fs = det_ctx->flowvarlist; + fs = det_ctx->varlist; } else { prev->next = fs->next; SCFree(fs); @@ -307,14 +312,14 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, * - enforce storage for type ALWAYS (vars set from lua) * Only called from DetectFlowvarProcessList() when flowvarlist is not NULL . */ -void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f) +void DetectVarProcessListInternal(DetectVarList *fs, Flow *f, Packet *p) { - DetectFlowvarList *next; + DetectVarList *next; do { next = fs->next; - if (fs->type == DETECT_FLOWVAR_TYPE_ALWAYS) { + if (fs->type == DETECT_VAR_TYPE_ALWAYS) { SCLogDebug("adding to the flow %u:", fs->idx); //PrintRawDataFp(stdout, fs->buffer, fs->len); diff --git a/src/detect-flowvar.h b/src/detect-flowvar.h index 32222372b4bf..59edfc80bc17 100644 --- a/src/detect-flowvar.h +++ b/src/detect-flowvar.h @@ -36,18 +36,18 @@ typedef struct DetectFlowvarData_ { void DetectFlowvarRegister (void); int DetectFlowvarPostMatchSetup(Signature *s, uint32_t idx); -int DetectFlowvarStoreMatch(DetectEngineThreadCtx *, uint32_t, uint8_t *, uint16_t, int); +int DetectVarStoreMatch(DetectEngineThreadCtx *, uint32_t, uint8_t *, uint16_t, int); /* For use only by DetectFlowvarProcessList() */ -void DetectFlowvarProcessListInternal(DetectFlowvarList *fs, Flow *f); -static inline void DetectFlowvarProcessList(DetectEngineThreadCtx *det_ctx, Flow *f) +void DetectVarProcessListInternal(DetectVarList *fs, Flow *f, Packet *p); +static inline void DetectVarProcessList(DetectEngineThreadCtx *det_ctx, Flow *f, Packet *p) { - DetectFlowvarList *fs = det_ctx->flowvarlist; + DetectVarList *fs = det_ctx->varlist; - SCLogDebug("flow %p det_ctx->flowvarlist %p", f, fs); - if (f && fs != NULL) { - det_ctx->flowvarlist = NULL; - DetectFlowvarProcessListInternal(fs, f); + SCLogDebug("flow %p det_ctx->varlist %p", f, fs); + if ((f || p) && fs != NULL) { + det_ctx->varlist = NULL; + DetectVarProcessListInternal(fs, f, p); } } diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 1fe8af27584d..0d0a46756e3f 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -219,21 +219,28 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, if (ret > 1 && pe->idx != 0) { uint8_t x; for (x = 0; x < pe->idx; x++) { - SCLogDebug("capturing"); + SCLogDebug("capturing %u", x); const char *str_ptr; ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, x+1, &str_ptr); if (unlikely(ret == 0)) continue; - if (pe->captypes[x] == VAR_TYPE_PKT_VAR && p != NULL) { - PktVarAdd(p, pe->capids[x], (uint8_t *)str_ptr, ret); + SCLogDebug("data %p/%u, type %u id %u p %p", + str_ptr, ret, pe->captypes[x], pe->capids[x], p); + + if (pe->captypes[x] == VAR_TYPE_PKT_VAR) { + /* store max 64k. Errors are ignored */ + capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; + (void)DetectVarStoreMatch(det_ctx, pe->capids[x], + (uint8_t *)str_ptr, capture_len, + DETECT_VAR_TYPE_PKT_POSTMATCH); } else if (pe->captypes[x] == VAR_TYPE_FLOW_VAR && f != NULL) { /* store max 64k. Errors are ignored */ capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; - (void)DetectFlowvarStoreMatch(det_ctx, pe->capids[x], + (void)DetectVarStoreMatch(det_ctx, pe->capids[x], (uint8_t *)str_ptr, capture_len, - DETECT_FLOWVAR_TYPE_POSTMATCH); + DETECT_VAR_TYPE_FLOW_POSTMATCH); } } } @@ -717,10 +724,8 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst uint8_t x; for (x = 0; x < pd->idx; x++) { - if (pd->captypes[x] == VAR_TYPE_FLOW_VAR) { - if (DetectFlowvarPostMatchSetup(s, pd->capids[x]) < 0) - goto error_nofree; - } + if (DetectFlowvarPostMatchSetup(s, pd->capids[x]) < 0) + goto error_nofree; } if (!(pd->flags & DETECT_PCRE_RELATIVE)) diff --git a/src/detect.c b/src/detect.c index 3797a2272c9f..9207b537c0c7 100644 --- a/src/detect.c +++ b/src/detect.c @@ -549,21 +549,19 @@ int SigMatchSignaturesRunPostMatch(ThreadVars *tv, const Signature *s) { /* run the packet match functions */ - if (s->sm_arrays[DETECT_SM_LIST_POSTMATCH] != NULL) { + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_POSTMATCH]; + if (smd != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_POSTMATCH); - SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_POSTMATCH]; SCLogDebug("running match functions, sm %p", smd); - if (smd != NULL) { - while (1) { - KEYWORD_PROFILING_START; - (void)sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx); - KEYWORD_PROFILING_END(det_ctx, smd->type, 1); - if (smd->is_last) - break; - smd++; - } + while (1) { + KEYWORD_PROFILING_START; + (void)sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) + break; + smd++; } } @@ -1472,7 +1470,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } alerts++; next: - DetectFlowvarProcessList(det_ctx, pflow); + DetectVarProcessList(det_ctx, pflow, p); DetectReplaceFree(det_ctx); RULE_PROFILING_END(det_ctx, s, smatch, p); diff --git a/src/detect.h b/src/detect.h index fd609f056b77..2394ab442ebb 100644 --- a/src/detect.h +++ b/src/detect.h @@ -490,20 +490,21 @@ typedef struct DetectReplaceList_ { } DetectReplaceList; /** only execute flowvar storage if rule matched */ -#define DETECT_FLOWVAR_TYPE_POSTMATCH 1 +#define DETECT_VAR_TYPE_FLOW_POSTMATCH 1 +#define DETECT_VAR_TYPE_PKT_POSTMATCH 2 /** execute flowvar storage even if rule doesn't match (for lua) */ -#define DETECT_FLOWVAR_TYPE_ALWAYS 2 +#define DETECT_VAR_TYPE_ALWAYS 3 /** list for flowvar store candidates, to be stored from * post-match function */ -typedef struct DetectFlowvarList_ { +typedef struct DetectVarList_ { uint32_t idx; /**< flowvar name idx */ uint16_t len; /**< data len */ int type; /**< type of store candidate POSTMATCH or ALWAYS */ uint8_t *buffer; /**< alloc'd buffer, may be freed by post-match, post-non-match */ - struct DetectFlowvarList_ *next; -} DetectFlowvarList; + struct DetectVarList_ *next; +} DetectVarList; typedef struct DetectEngineIPOnlyThreadCtx_ { uint8_t *sig_match_array; /* bit array of sig nums */ @@ -877,8 +878,8 @@ typedef struct DetectEngineThreadCtx_ { /* string to replace */ DetectReplaceList *replist; - /* flowvars to store in post match function */ - DetectFlowvarList *flowvarlist; + /* 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 From 1ba8c2fe3a7cea32f3045d137ee2f4571f3e8ccc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 28 Oct 2016 12:27:35 +0200 Subject: [PATCH 2439/2553] pcre: new way of specifying var names Until now the way to specify a var name in pcre substring capture into pkt and flow vars was to use the pcre named substring support: e.g. /(?P.*)/ This had 2 drawbacks: 1. limitations of the name. The name could be max 32 chars, only have alphanumeric and the underscore characters. This imposed limitations that are not present in flowbits/ints. 2. we didn't actually use the named substrings in pcre through the API. We parsed the names separately. So putting the names in pcre would actually be wasteful. This patch introduces a new way of mapping captures with names: pcre:"/(.*)/, pkt:somename"; pcre:"/([A-z]+) ([0-9]+)/, pkt:somename,flow:anothername"; The order of the captures and the order of the names are mapped 1 on 1. This method is no longer limited by the pcre API's naming limits. The 'flow:' and 'pkt:' prefixes indicate what the type of variable is. It's mandatory to specify one. The old method is still supported as well. --- src/detect-pcre.c | 182 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 148 insertions(+), 34 deletions(-) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 0d0a46756e3f..b4ed145715d0 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -59,6 +59,8 @@ #include "app-layer-parser.h" #include "util-pages.h" +/* pcre named substring capture supports only 32byte names, A-z0-9 plus _ + * and needs to start with non-numeric. */ #define PARSE_CAPTURE_REGEX "\\(\\?P\\<([A-z]+)\\_([A-z0-9_]+)\\>" #define PARSE_REGEX "(? 1) { + int offset = cut_capture - 1; + while (offset) { + SCLogDebug("regexstr[offset] %c", regexstr[offset]); + if (regexstr[offset] == ',' || regexstr[offset] == ' ') { + offset--; + } + else + break; + } + + if (cut_capture == (offset + 1)) { + SCLogDebug("missing separators, assume it's part of the regex"); + } else { + slen = offset + 1; + strlcpy(capture_names, regexstr+cut_capture, capture_names_size); + if (capture_names[strlen(capture_names)-1] == '"') + capture_names[strlen(capture_names)-1] = '\0'; + } + } } - ret = pcre_exec(parse_regex, parse_regex_study, regexstr + pos, slen-pos, + char re[slen]; + ret = pcre_exec(parse_regex, parse_regex_study, regexstr, slen, 0, 0, ov, MAX_SUBSTRINGS); if (ret <= 0) { SCLogError(SC_ERR_PCRE_MATCH, "pcre parse error: %s", regexstr); goto error; } - res = pcre_copy_substring((char *)regexstr + pos, ov, MAX_SUBSTRINGS, + res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, re, slen); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); @@ -334,7 +372,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, } if (ret > 2) { - res = pcre_copy_substring((char *)regexstr + pos, ov, MAX_SUBSTRINGS, + res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, op_str, sizeof(op_str)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); @@ -535,13 +573,18 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, * If we fail because a capture group is later referenced (e.g., \1), * PCRE will let us know. */ - pd->re = pcre_compile2(re, opts | PCRE_NO_AUTO_CAPTURE, &ec, &eb, &eo, NULL); + if (capture_names == NULL || strlen(capture_names) == 0) + opts |= PCRE_NO_AUTO_CAPTURE; + + pd->re = pcre_compile2(re, opts, &ec, &eb, &eo, NULL); if (pd->re == NULL && ec == 15) { // reference to non-existent subpattern + opts &= ~PCRE_NO_AUTO_CAPTURE; pd->re = pcre_compile(re, opts, &eb, &eo, NULL); } - if(pd->re == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", regexstr, eo, eb); + if (pd->re == NULL) { + SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed " + "at offset %" PRId32 ": %s", regexstr, eo, eb); goto error; } @@ -611,16 +654,56 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, /** \internal * \brief check if we need to extract capture settings and set them up if needed */ -static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd) +static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd, + char *capture_names) { int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; memset(&ov, 0, sizeof(ov)); char type_str[16] = ""; char *orig_right_edge = regexstr + strlen(regexstr); + char *name_array[DETECT_PCRE_CAPTURE_MAX] = { NULL }; + int name_idx = 0; + int capture_cnt = 0; SCLogDebug("regexstr %s, pd %p", regexstr, pd); + ret = pcre_fullinfo(pd->re, pd->sd, PCRE_INFO_CAPTURECOUNT, &capture_cnt); + SCLogDebug("ret %d capture_cnt %d", ret, capture_cnt); + if (ret == 0 && capture_cnt && strlen(capture_names) > 0) + { + char *ptr = NULL; + while ((name_array[name_idx] = strtok_r(name_idx == 0 ? capture_names : NULL, " ,", &ptr))){ + if (name_idx > capture_cnt) { + SCLogError(SC_ERR_VAR_LIMIT, "more pkt/flow " + "var capture names than capturing substrings"); + return -1; + } + SCLogDebug("name '%s'", name_array[name_idx]); + + if (strncmp(name_array[name_idx], "flow:", 5) == 0) { + pd->capids[pd->idx] = VarNameStoreSetupAdd(name_array[name_idx]+5, VAR_TYPE_FLOW_VAR); + pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR; + pd->idx++; + + } else if (strncmp(name_array[name_idx], "pkt:", 4) == 0) { + pd->capids[pd->idx] = VarNameStoreSetupAdd(name_array[name_idx]+4, VAR_TYPE_PKT_VAR); + pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR; + SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]); + pd->idx++; + + } else { + SCLogError(SC_ERR_VAR_LIMIT, " pkt/flow " + "var capture names must start with 'pkt:' or 'flow:'"); + return -1; + } + + name_idx++; + if (name_idx >= DETECT_PCRE_CAPTURE_MAX) + break; + } + } + /* take the size of the whole input as buffer size for the string we will * extract below. Add 1 to please Coverity's alloc_strlen test. */ size_t cap_buffer_len = strlen(regexstr) + 1; @@ -672,7 +755,7 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec pd->idx++; } - //SCLogDebug("pd->capname %s", pd->capname); + //SCLogNotice("pd->capname %s", pd->capname); regexstr += ov[1]; if (regexstr >= orig_right_edge) @@ -691,11 +774,12 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst SigMatch *sm = NULL; int ret = -1; int parsed_sm_list = DETECT_SM_LIST_NOTSET; + char capture_names[1024] = ""; - pd = DetectPcreParse(de_ctx, regexstr, &parsed_sm_list); + pd = DetectPcreParse(de_ctx, regexstr, &parsed_sm_list, capture_names, sizeof(capture_names)); if (pd == NULL) goto error; - if (DetectPcreParseCapture(regexstr, de_ctx, pd) < 0) + if (DetectPcreParseCapture(regexstr, de_ctx, pd, capture_names) < 0) goto error; int sm_list = -1; @@ -792,7 +876,7 @@ static int DetectPcreParseTest01 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); @@ -811,7 +895,7 @@ static int DetectPcreParseTest02 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); @@ -830,7 +914,7 @@ static int DetectPcreParseTest03 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); @@ -849,7 +933,7 @@ static int DetectPcreParseTest04 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -869,7 +953,7 @@ static int DetectPcreParseTest05 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -889,7 +973,7 @@ static int DetectPcreParseTest06 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -909,7 +993,7 @@ static int DetectPcreParseTest07 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -929,7 +1013,7 @@ static int DetectPcreParseTest08 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -949,7 +1033,7 @@ static int DetectPcreParseTest09 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); @@ -3287,30 +3371,59 @@ static int DetectPcreParseHttpHost(void) FAIL_IF(de_ctx == NULL); - pd = DetectPcreParse(de_ctx, "/domain\\.com/W", &list); + pd = DetectPcreParse(de_ctx, "/domain\\.com/W", &list, NULL, 0); FAIL_IF(pd == NULL); DetectPcreFree(pd); list = DETECT_SM_LIST_NOTSET; - pd = DetectPcreParse(de_ctx, "/dOmain\\.com/W", &list); + pd = DetectPcreParse(de_ctx, "/dOmain\\.com/W", &list, NULL, 0); FAIL_IF(pd != NULL); /* Uppercase meta characters are valid. */ list = DETECT_SM_LIST_NOTSET; - pd = DetectPcreParse(de_ctx, "/domain\\D+\\.com/W", &list); + pd = DetectPcreParse(de_ctx, "/domain\\D+\\.com/W", &list, NULL, 0); FAIL_IF(pd == NULL); DetectPcreFree(pd); /* This should not parse as the first \ escapes the second \, then * we have a D. */ list = DETECT_SM_LIST_NOTSET; - pd = DetectPcreParse(de_ctx, "/\\\\Ddomain\\.com/W", &list); + pd = DetectPcreParse(de_ctx, "/\\\\Ddomain\\.com/W", &list, NULL, 0); FAIL_IF(pd != NULL); DetectEngineCtxFree(de_ctx); PASS; } +/** + * \brief Test parsing of capture extension + */ +static int DetectPcreParseCaptureTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(content:\"Server: \"; http_header; pcre:\"/(.*)\\r\\n/HR, flow:somecapture\"; content:\"xyz\"; http_header; sid:1;)"); + FAIL_IF(s == NULL); + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(content:\"Server: \"; http_header; pcre:\"/(flow:.*)\\r\\n/HR\"; content:\"xyz\"; http_header; sid:2;)"); + FAIL_IF(s == NULL); + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(content:\"Server: \"; http_header; pcre:\"/([a-z]+)([0-9]+)\\r\\n/HR, flow:somecapture, pkt:anothercap\"; content:\"xyz\"; http_header; sid:3;)"); + FAIL_IF(s == NULL); + + SigGroupBuild(de_ctx); + + uint32_t capid = VarNameStoreLookupByName("somecapture", VAR_TYPE_FLOW_VAR); + FAIL_IF (capid != 1); + capid = VarNameStoreLookupByName("anothercap", VAR_TYPE_PKT_VAR); + FAIL_IF (capid != 2); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ /** @@ -3397,6 +3510,7 @@ static void DetectPcreRegisterTests(void) DetectPcreFlowvarCapture03); UtRegisterTest("DetectPcreParseHttpHost", DetectPcreParseHttpHost); + UtRegisterTest("DetectPcreParseCaptureTest", DetectPcreParseCaptureTest); #endif /* UNITTESTS */ } From 1a2ad059a12910120cd997e76ea75e688747ff7d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 21 Oct 2016 12:55:32 +0200 Subject: [PATCH 2440/2553] eve: log pktvars/flowvars/bits/ints Optionally logs 'vars' into alerts --- src/output-json-alert.c | 11 ++++ src/output-json.c | 121 ++++++++++++++++++++++++++++++++++++++++ src/output-json.h | 1 + suricata.yaml.in | 1 + 4 files changed, 134 insertions(+) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index c589f1213b57..258eeee9ffdd 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -81,6 +81,7 @@ #define LOG_JSON_SMTP 0x040 #define LOG_JSON_TAGGED_PACKETS 0x080 #define LOG_JSON_DNP3 0x100 +#define LOG_JSON_VARS 0x200 #define JSON_STREAM_BUFFER_SIZE 4096 @@ -319,6 +320,10 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } } + if (json_output_ctx->flags & LOG_JSON_VARS) { + JsonAddVars(p, p->flow, js); + } + /* payload */ if (json_output_ctx->flags & (LOG_JSON_PAYLOAD | LOG_JSON_PAYLOAD_BASE64)) { int stream = (p->proto == IPPROTO_TCP) ? @@ -637,7 +642,13 @@ static void XffSetup(AlertJsonOutputCtx *json_output_ctx, ConfNode *conf) const char *smtp = ConfNodeLookupChildValue(conf, "smtp"); const char *tagged_packets = ConfNodeLookupChildValue(conf, "tagged-packets"); const char *dnp3 = ConfNodeLookupChildValue(conf, "dnp3"); + const char *vars = ConfNodeLookupChildValue(conf, "vars"); + if (vars != NULL) { + if (ConfValIsTrue(vars)) { + json_output_ctx->flags |= LOG_JSON_VARS; + } + } if (ssh != NULL) { if (ConfValIsTrue(ssh)) { json_output_ctx->flags |= LOG_JSON_SSH; diff --git a/src/output-json.c b/src/output-json.c index ccf43b692359..7aa7a23aa7ab 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -58,6 +58,8 @@ #include "util-logopenfile.h" #include "util-device.h" +#include "flow-var.h" +#include "flow-bit.h" #ifndef HAVE_LIBJANSSON @@ -92,6 +94,125 @@ void OutputJsonRegister (void) /* Default Sensor ID value */ static int64_t sensor_id = -1; /* -1 = not defined */ +static void JsonAddPacketvars(const Packet *p, json_t *js_vars) +{ + if (p == NULL || p->pktvar == NULL) { + return; + } + json_t *js_pktvars = NULL; + PktVar *pv = p->pktvar; + while (pv != NULL) { + const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); + if (varname) { + if (js_pktvars == NULL) { + js_pktvars = json_object(); + if (js_pktvars == NULL) + break; + } + + uint32_t len = pv->value_len; + uint8_t printable_buf[len + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + pv->value, pv->value_len); + + json_object_set_new(js_pktvars, varname, + json_string((char *)printable_buf)); + } + pv = pv->next; + } + if (js_pktvars) { + json_object_set_new(js_vars, "pktvars", js_pktvars); + } +} + +static void JsonAddFlowvars(const Flow *f, json_t *js_vars) +{ + if (f == NULL || f->flowvar == NULL) { + return; + } + json_t *js_flowvars = NULL; + json_t *js_flowints = NULL; + json_t *js_flowbits = NULL; + GenericVar *gv = f->flowvar; + while (gv != NULL) { + if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { + FlowVar *fv = (FlowVar *)gv; + if (fv->datatype == FLOWVAR_TYPE_STR) { + const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_VAR); + if (varname) { + if (js_flowvars == NULL) { + js_flowvars = json_object(); + if (js_flowvars == NULL) + break; + } + + uint32_t len = fv->data.fv_str.value_len; + uint8_t printable_buf[len + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + fv->data.fv_str.value, fv->data.fv_str.value_len); + + json_object_set_new(js_flowvars, varname, + json_string((char *)printable_buf)); + } + } else if (fv->datatype == FLOWVAR_TYPE_INT) { + const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_INT); + if (varname) { + if (js_flowints == NULL) { + js_flowints = json_object(); + if (js_flowints == NULL) + break; + } + + json_object_set_new(js_flowints, varname, json_integer(fv->data.fv_int.value)); + } + + } + } else if (gv->type == DETECT_FLOWBITS) { + FlowBit *fb = (FlowBit *)gv; + const char *varname = VarNameStoreLookupById(fb->idx, VAR_TYPE_FLOW_BIT); + if (varname) { + if (js_flowbits == NULL) { + js_flowbits = json_object(); + if (js_flowbits == NULL) + break; + } + json_object_set_new(js_flowbits, varname, json_boolean(1)); + } + } + gv = gv->next; + } + if (js_flowbits) { + json_object_set_new(js_vars, "flowbits", js_flowbits); + } + if (js_flowints) { + json_object_set_new(js_vars, "flowints", js_flowints); + } + if (js_flowvars) { + json_object_set_new(js_vars, "flowvars", js_flowvars); + } +} + +void JsonAddVars(const Packet *p, const Flow *f, json_t *js) +{ + if ((p && p->pktvar) || (f && f->flowvar)) { + json_t *js_vars = json_object(); + if (js_vars) { + if (f && f->flowvar) { + JsonAddFlowvars(f, js_vars); + } + if (p && p->pktvar) { + JsonAddPacketvars(p, js_vars); + } + + json_object_set_new(js, "vars", js_vars); + } + } +} + /** \brief jsonify tcp flags field * Only add 'true' fields in an attempt to keep things reasonably compact. */ diff --git a/src/output-json.h b/src/output-json.h index bb7d94de9ee5..c65454921940 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -39,6 +39,7 @@ typedef struct OutputJSONMemBufferWrapper_ { int OutputJSONMemBufferCallback(const char *str, size_t size, void *data); +void JsonAddVars(const Packet *p, const Flow *f, json_t *js); void CreateJSONFlowId(json_t *js, const Flow *f); void JsonTcpFlags(uint8_t flags, json_t *js); json_t *CreateJSONHeader(const Packet *p, int direction_sensative, const char *event_type); diff --git a/suricata.yaml.in b/suricata.yaml.in index eef8799486cb..17090cb9363c 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -168,6 +168,7 @@ outputs: ssh: yes # enable dumping of ssh fields smtp: yes # enable dumping of smtp fields dnp3: yes # enable dumping of DNP3 fields + vars: yes # enable dumping of flowbits and other vars # Enable the logging of tagged packets for rules using the # "tag" keyword. From 5ca4a2e6fe5df41673009d89f2f1e0173b55097c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 28 Oct 2016 23:12:43 +0200 Subject: [PATCH 2441/2553] outputs: vars log EVE addition called 'vars' that logs pkt/flow vars for each packet/flow. --- src/Makefile.am | 1 + src/output-json-vars.c | 277 +++++++++++++++++++++++++++++++++++++++++ src/output-json-vars.h | 32 +++++ src/output.c | 2 + src/suricata-common.h | 1 + src/util-profiling.c | 1 + suricata.yaml.in | 2 + 7 files changed, 316 insertions(+) create mode 100644 src/output-json-vars.c create mode 100644 src/output-json-vars.h diff --git a/src/Makefile.am b/src/Makefile.am index 05e5ef539c77..634ab7aabd0e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -285,6 +285,7 @@ output-json-ssh.c output-json-ssh.h \ output-json-stats.c output-json-stats.h \ output-json-tls.c output-json-tls.h \ output-json-template.c output-json-template.h \ +output-json-vars.c output-json-vars.h \ output-lua.c output-lua.h \ output-packet.c output-packet.h \ output-stats.c output-stats.h \ diff --git a/src/output-json-vars.c b/src/output-json-vars.c new file mode 100644 index 000000000000..c0747ca9ff4b --- /dev/null +++ b/src/output-json-vars.c @@ -0,0 +1,277 @@ +/* Copyright (C) 2013-2016 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 + * + * Logs vars in JSON format. + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "flow.h" +#include "conf.h" + +#include "threads.h" +#include "tm-threads.h" +#include "threadvars.h" +#include "util-debug.h" + +#include "util-misc.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-reference.h" +#include "app-layer-parser.h" +#include "app-layer-dnp3.h" +#include "app-layer-htp.h" +#include "app-layer-htp-xff.h" +#include "util-classification-config.h" +#include "util-syslog.h" +#include "util-logopenfile.h" + +#include "output.h" +#include "output-json.h" + +#include "util-byte.h" +#include "util-privs.h" +#include "util-print.h" +#include "util-proto-name.h" +#include "util-optimize.h" +#include "util-buffer.h" +#include "util-crypt.h" + +#define MODULE_NAME "JsonVarsLog" + +#ifdef HAVE_LIBJANSSON + +#define JSON_STREAM_BUFFER_SIZE 4096 + +typedef struct VarsJsonOutputCtx_ { + LogFileCtx* file_ctx; +} VarsJsonOutputCtx; + +typedef struct JsonVarsLogThread_ { + /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ + LogFileCtx* file_ctx; + MemBuffer *json_buffer; + VarsJsonOutputCtx* json_output_ctx; +} JsonVarsLogThread; + +static int VarsJson(ThreadVars *tv, JsonVarsLogThread *aft, const Packet *p) +{ + json_t *js = CreateJSONHeader((Packet *)p, 0, "vars"); + if (unlikely(js == NULL)) + return TM_ECODE_OK; + + JsonAddVars(p, p->flow, js); + OutputJSONBuffer(js, aft->file_ctx, &aft->json_buffer); + json_object_del(js, "vars"); + json_object_clear(js); + json_decref(js); + + return TM_ECODE_OK; +} + +static int JsonVarsLogger(ThreadVars *tv, void *thread_data, const Packet *p) +{ + JsonVarsLogThread *aft = thread_data; + + return VarsJson(tv, aft, p); +} + +static int JsonVarsLogCondition(ThreadVars *tv, const Packet *p) +{ + if (p->pktvar) { + return TRUE; + } + return FALSE; +} + +#define OUTPUT_BUFFER_SIZE 65535 +static TmEcode JsonVarsLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + JsonVarsLogThread *aft = SCMalloc(sizeof(JsonVarsLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(JsonVarsLogThread)); + if(initdata == NULL) + { + SCLogDebug("Error getting context for EveLogVars. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + aft->json_buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->json_buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + + /** Use the Output Context (file pointer and mutex) */ + VarsJsonOutputCtx *json_output_ctx = ((OutputCtx *)initdata)->data; + aft->file_ctx = json_output_ctx->file_ctx; + aft->json_output_ctx = json_output_ctx; + + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode JsonVarsLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonVarsLogThread *aft = (JsonVarsLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + MemBufferFree(aft->json_buffer); + + /* clear memory */ + memset(aft, 0, sizeof(JsonVarsLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static void JsonVarsLogDeInitCtx(OutputCtx *output_ctx) +{ + VarsJsonOutputCtx *json_output_ctx = (VarsJsonOutputCtx *) output_ctx->data; + if (json_output_ctx != NULL) { + LogFileFreeCtx(json_output_ctx->file_ctx); + SCFree(json_output_ctx); + } + SCFree(output_ctx); +} + +static void JsonVarsLogDeInitCtxSub(OutputCtx *output_ctx) +{ + SCLogDebug("cleaning up sub output_ctx %p", output_ctx); + + VarsJsonOutputCtx *json_output_ctx = (VarsJsonOutputCtx *) output_ctx->data; + + if (json_output_ctx != NULL) { + SCFree(json_output_ctx); + } + SCFree(output_ctx); +} + +#define DEFAULT_LOG_FILENAME "vars.json" + +/** + * \brief Create a new LogFileCtx for "fast" output style. + * \param conf The configuration node for this output. + * \return A LogFileCtx pointer on success, NULL on failure. + */ +static OutputCtx *JsonVarsLogInitCtx(ConfNode *conf) +{ + VarsJsonOutputCtx *json_output_ctx = NULL; + LogFileCtx *logfile_ctx = LogFileNewCtx(); + if (logfile_ctx == NULL) { + SCLogDebug("VarsFastLogInitCtx2: Could not create new LogFileCtx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { + LogFileFreeCtx(logfile_ctx); + return NULL; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + LogFileFreeCtx(logfile_ctx); + return NULL; + } + + json_output_ctx = SCMalloc(sizeof(VarsJsonOutputCtx)); + if (unlikely(json_output_ctx == NULL)) { + LogFileFreeCtx(logfile_ctx); + SCFree(output_ctx); + return NULL; + } + memset(json_output_ctx, 0, sizeof(VarsJsonOutputCtx)); + + json_output_ctx->file_ctx = logfile_ctx; + + output_ctx->data = json_output_ctx; + output_ctx->DeInit = JsonVarsLogDeInitCtx; + + return output_ctx; +} + +/** + * \brief Create a new LogFileCtx for "fast" output style. + * \param conf The configuration node for this output. + * \return A LogFileCtx pointer on success, NULL on failure. + */ +static OutputCtx *JsonVarsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputJsonCtx *ajt = parent_ctx->data; + VarsJsonOutputCtx *json_output_ctx = NULL; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) + return NULL; + + json_output_ctx = SCMalloc(sizeof(VarsJsonOutputCtx)); + if (unlikely(json_output_ctx == NULL)) { + goto error; + } + memset(json_output_ctx, 0, sizeof(VarsJsonOutputCtx)); + + json_output_ctx->file_ctx = ajt->file_ctx; + + output_ctx->data = json_output_ctx; + output_ctx->DeInit = JsonVarsLogDeInitCtxSub; + + return output_ctx; + +error: + if (json_output_ctx != NULL) { + SCFree(json_output_ctx); + } + if (output_ctx != NULL) { + SCFree(output_ctx); + } + + return NULL; +} + +void JsonVarsLogRegister (void) +{ + OutputRegisterPacketModule(LOGGER_JSON_VARS, MODULE_NAME, "vars-json-log", + JsonVarsLogInitCtx, JsonVarsLogger, JsonVarsLogCondition, + JsonVarsLogThreadInit, JsonVarsLogThreadDeinit, NULL); + OutputRegisterPacketSubModule(LOGGER_JSON_VARS, "eve-log", MODULE_NAME, + "eve-log.vars", JsonVarsLogInitCtxSub, JsonVarsLogger, + JsonVarsLogCondition, JsonVarsLogThreadInit, JsonVarsLogThreadDeinit, + NULL); +} + +#else + +void JsonVarsLogRegister (void) +{ +} + +#endif diff --git a/src/output-json-vars.h b/src/output-json-vars.h new file mode 100644 index 000000000000..395fbce09cf8 --- /dev/null +++ b/src/output-json-vars.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2013-2015 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 + * + * Logs alerts in JSON format. + * + */ + +#ifndef __OUTPUT_JSON_VARS_H__ +#define __OUTPUT_JSON_VARS_H__ + +void JsonVarsLogRegister(void); + +#endif /* __OUTPUT_JSON_VARS_H__ */ diff --git a/src/output.c b/src/output.c index 7c8c5aaca0e7..3c509f266246 100644 --- a/src/output.c +++ b/src/output.c @@ -70,6 +70,7 @@ #include "output-json-template.h" #include "output-lua.h" #include "output-json-dnp3.h" +#include "output-json-vars.h" typedef struct RootLogger_ { ThreadInitFunc ThreadInit; @@ -1074,6 +1075,7 @@ void OutputRegisterLoggers(void) /* DNP3. */ JsonDNP3LogRegister(); + JsonVarsLogRegister(); /* Template JSON logger. */ JsonTemplateLogRegister(); diff --git a/src/suricata-common.h b/src/suricata-common.h index c6bf0d16c7b6..05e0d7f39c0b 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -375,6 +375,7 @@ typedef enum { LOGGER_PRELUDE, LOGGER_PCAP, LOGGER_JSON_DNP3, + LOGGER_JSON_VARS, LOGGER_SIZE, } LoggerId; diff --git a/src/util-profiling.c b/src/util-profiling.c index 9cbe49de3556..274805d01f5f 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1360,6 +1360,7 @@ const char * PacketProfileLoggertIdToString(LoggerId id) CASE_CODE (LOGGER_JSON_STATS); CASE_CODE (LOGGER_PRELUDE); CASE_CODE (LOGGER_PCAP); + CASE_CODE (LOGGER_JSON_VARS); default: return "UNKNOWN"; } diff --git a/suricata.yaml.in b/suricata.yaml.in index 17090cb9363c..95f341bcf6bb 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -238,6 +238,8 @@ outputs: # uni-directional flows #- netflow #- dnp3 + # Vars log flowbits and other packet and flow vars + #- vars # alert output for use with Barnyard2 - unified2-alert: From 996112edf5712f593c87dc8741c59ce65b73e07f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 5 Nov 2016 09:02:39 -0400 Subject: [PATCH 2442/2553] pktvars: same name pktvars, key-value vars --- src/decode.h | 4 ++- src/detect-flowvar.c | 40 ++++++++++++++++++--- src/detect-flowvar.h | 5 ++- src/detect-pcre.c | 39 ++++++++++++++++++-- src/detect.h | 2 ++ src/output-json.c | 45 ++++++++++++++++------- src/pkt-var.c | 85 +++++++++++++++++++++++++++----------------- src/pkt-var.h | 3 +- src/util-var.h | 1 + 9 files changed, 170 insertions(+), 54 deletions(-) diff --git a/src/decode.h b/src/decode.h index 6d0ad53ee7c5..d732ce9038b3 100644 --- a/src/decode.h +++ b/src/decode.h @@ -302,8 +302,10 @@ typedef struct PktVar_ { struct PktVar_ *next; /* right now just implement this as a list, * in the long run we have thing of something * faster. */ - uint8_t *value; + uint16_t key_len; uint16_t value_len; + uint8_t *key; + uint8_t *value; } PktVar; #ifdef PROFILING diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index b0c30d4099b0..9f84811a12bd 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -193,9 +193,29 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws return -1; } +/** \brief Store flowvar in det_ctx so we can exec it post-match */ +int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *det_ctx, + uint8_t *key, uint16_t key_len, + uint8_t *buffer, uint16_t len, int type) +{ + DetectVarList *fs = SCCalloc(1, sizeof(*fs)); + if (unlikely(fs == NULL)) + return -1; + + fs->len = len; + fs->type = type; + fs->buffer = buffer; + fs->key = key; + fs->key_len = key_len; + + fs->next = det_ctx->varlist; + det_ctx->varlist = fs; + return 0; +} /** \brief Store flowvar in det_ctx so we can exec it post-match */ -int DetectVarStoreMatch(DetectEngineThreadCtx *det_ctx, uint32_t idx, +int DetectVarStoreMatch(DetectEngineThreadCtx *det_ctx, + uint32_t idx, uint8_t *buffer, uint16_t len, int type) { DetectVarList *fs = det_ctx->varlist; @@ -211,7 +231,7 @@ int DetectVarStoreMatch(DetectEngineThreadCtx *det_ctx, uint32_t idx, } if (fs == NULL) { - fs = SCMalloc(sizeof(*fs)); + fs = SCCalloc(1, sizeof(*fs)); if (unlikely(fs == NULL)) return -1; @@ -278,7 +298,7 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, prev = NULL; fs = det_ctx->varlist; while (fs != NULL) { - if (fd->idx == fs->idx) { + if (fd->idx == 0 || fd->idx == fs->idx) { SCLogDebug("adding to the flow %u:", fs->idx); //PrintRawDataFp(stdout, fs->buffer, fs->len); @@ -286,8 +306,20 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, FlowVarAddStrNoLock(p->flow, fs->idx, fs->buffer, fs->len); /* memory at fs->buffer is now the responsibility of * the flowvar code. */ + } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && fs->key && p) { + /* pkt key/value */ + if (PktVarAddKeyValue(p, (uint8_t *)fs->key, fs->key_len, + (uint8_t *)fs->buffer, fs->len) == -1) + { + SCFree(fs->key); + SCFree(fs->buffer); + /* the rest of fs is freed below */ + } } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && p) { - PktVarAdd(p, fs->idx, fs->buffer, fs->len); + if (PktVarAdd(p, fs->idx, fs->buffer, fs->len) == -1) { + SCFree(fs->buffer); + /* the rest of fs is freed below */ + } } if (fs == det_ctx->varlist) { diff --git a/src/detect-flowvar.h b/src/detect-flowvar.h index 59edfc80bc17..f919c3b031ea 100644 --- a/src/detect-flowvar.h +++ b/src/detect-flowvar.h @@ -36,7 +36,10 @@ typedef struct DetectFlowvarData_ { void DetectFlowvarRegister (void); int DetectFlowvarPostMatchSetup(Signature *s, uint32_t idx); -int DetectVarStoreMatch(DetectEngineThreadCtx *, uint32_t, uint8_t *, uint16_t, int); +int DetectVarStoreMatch(DetectEngineThreadCtx *, + uint32_t, uint8_t *, uint16_t, int); +int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *, + uint8_t *, uint16_t, uint8_t *, uint16_t, int); /* For use only by DetectFlowvarProcessList() */ void DetectVarProcessListInternal(DetectVarList *fs, Flow *f, Packet *p); diff --git a/src/detect-pcre.c b/src/detect-pcre.c index b4ed145715d0..661a254a3e1d 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -230,7 +230,23 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, SCLogDebug("data %p/%u, type %u id %u p %p", str_ptr, ret, pe->captypes[x], pe->capids[x], p); - if (pe->captypes[x] == VAR_TYPE_PKT_VAR) { + if (pe->captypes[x] == VAR_TYPE_PKT_VAR_KV) { + /* get the value, as first capture is the key */ + const char *str_ptr2; + int ret2 = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, x+2, &str_ptr2); + if (unlikely(ret2 == 0)) { + break; + } + /* key length is limited to 256 chars */ + uint16_t key_len = (ret < 0xff) ? (uint16_t)ret : 0xff; + capture_len = (ret2 < 0xffff) ? (uint16_t)ret2 : 0xffff; + + (void)DetectVarStoreMatchKeyValue(det_ctx, + (uint8_t *)str_ptr, key_len, + (uint8_t *)str_ptr2, capture_len, + DETECT_VAR_TYPE_PKT_POSTMATCH); + + } else if (pe->captypes[x] == VAR_TYPE_PKT_VAR) { /* store max 64k. Errors are ignored */ capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; (void)DetectVarStoreMatch(det_ctx, pe->capids[x], @@ -665,6 +681,7 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec char *name_array[DETECT_PCRE_CAPTURE_MAX] = { NULL }; int name_idx = 0; int capture_cnt = 0; + int key = 0; SCLogDebug("regexstr %s, pd %p", regexstr, pd); @@ -681,7 +698,25 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec } SCLogDebug("name '%s'", name_array[name_idx]); - if (strncmp(name_array[name_idx], "flow:", 5) == 0) { + if (strcmp(name_array[name_idx], "pkt:key") == 0) { + key = 1; + SCLogDebug("key-value/key"); + + pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR_KV; + SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]); + pd->idx++; + + } else if (key == 1 && strcmp(name_array[name_idx], "pkt:value") == 0) { + SCLogDebug("key-value/value"); + key = 0; + + /* kv error conditions */ + } else if (key == 0 && strcmp(name_array[name_idx], "pkt:value") == 0) { + return -1; + } else if (key == 1) { + return -1; + + } else if (strncmp(name_array[name_idx], "flow:", 5) == 0) { pd->capids[pd->idx] = VarNameStoreSetupAdd(name_array[name_idx]+5, VAR_TYPE_FLOW_VAR); pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR; pd->idx++; diff --git a/src/detect.h b/src/detect.h index 2394ab442ebb..023b931da41e 100644 --- a/src/detect.h +++ b/src/detect.h @@ -500,7 +500,9 @@ typedef struct DetectReplaceList_ { 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; diff --git a/src/output-json.c b/src/output-json.c index 7aa7a23aa7ab..7db6262d33d1 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -102,23 +102,44 @@ static void JsonAddPacketvars(const Packet *p, json_t *js_vars) json_t *js_pktvars = NULL; PktVar *pv = p->pktvar; while (pv != NULL) { - const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); - if (varname) { + if (pv->key || pv->id > 0) { if (js_pktvars == NULL) { - js_pktvars = json_object(); + js_pktvars = json_array(); if (js_pktvars == NULL) break; } + json_t *js_pair = json_object(); + if (js_pair == NULL) { + break; + } - uint32_t len = pv->value_len; - uint8_t printable_buf[len + 1]; - uint32_t offset = 0; - PrintStringsToBuffer(printable_buf, &offset, - sizeof(printable_buf), - pv->value, pv->value_len); - - json_object_set_new(js_pktvars, varname, - json_string((char *)printable_buf)); + if (pv->key != NULL) { + uint32_t offset = 0; + uint8_t keybuf[pv->key_len + 1]; + PrintStringsToBuffer(keybuf, &offset, + sizeof(keybuf), + pv->key, pv->key_len); + uint32_t len = pv->value_len; + uint8_t printable_buf[len + 1]; + offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + pv->value, pv->value_len); + json_object_set_new(js_pair, (char *)keybuf, + json_string((char *)printable_buf)); + } else { + const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); + uint32_t len = pv->value_len; + uint8_t printable_buf[len + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + pv->value, pv->value_len); + + json_object_set_new(js_pair, varname, + json_string((char *)printable_buf)); + } + json_array_append_new(js_pktvars, js_pair); } pv = pv->next; } diff --git a/src/pkt-var.c b/src/pkt-var.c index 333f2977bd44..a81af35e1af2 100644 --- a/src/pkt-var.c +++ b/src/pkt-var.c @@ -34,15 +34,6 @@ #include "pkt-var.h" #include "util-debug.h" -/* puts a new value into a pktvar */ -static void PktVarUpdate(PktVar *pv, uint8_t *value, uint16_t size) -{ - if (pv->value) - SCFree(pv->value); - pv->value = value; - pv->value_len = size; -} - /* get the pktvar with name 'name' from the pkt * * name is a normal string*/ @@ -58,37 +49,63 @@ PktVar *PktVarGet(Packet *p, uint32_t id) return NULL; } -/* add a pktvar to the pkt, or update it */ -void PktVarAdd(Packet *p, uint32_t id, uint8_t *value, uint16_t size) +/** + * \brief add a key-value pktvar to the pkt + * \retval r 0 ok, -1 error + */ +int PktVarAddKeyValue(Packet *p, uint8_t *key, uint16_t ksize, uint8_t *value, uint16_t size) { - //printf("Adding packet var \"%s\" with value(%" PRId32 ") \"%s\"\n", name, size, value); + PktVar *pv = SCCalloc(1, sizeof(PktVar)); + if (unlikely(pv == NULL)) + return -1; - PktVar *pv = PktVarGet(p, id); - if (pv == NULL) { - pv = SCMalloc(sizeof(PktVar)); - if (unlikely(pv == NULL)) - return; + pv->key = key; + pv->key_len = ksize; + pv->value = value; + pv->value_len = size; - pv->id = id; - pv->value = value; - pv->value_len = size; - pv->next = NULL; + PktVar *tpv = p->pktvar; + if (p->pktvar == NULL) + p->pktvar = pv; + else { + while(tpv) { + if (tpv->next == NULL) { + tpv->next = pv; + return 0; + } + tpv = tpv->next; + } + } + return 0; +} + +/** + * \brief add a key-value pktvar to the pkt + * \retval r 0 ok, -1 error + */ +int PktVarAdd(Packet *p, uint32_t id, uint8_t *value, uint16_t size) +{ + PktVar *pv = SCCalloc(1, sizeof(PktVar)); + if (unlikely(pv == NULL)) + return -1; + + pv->id = id; + pv->value = value; + pv->value_len = size; - PktVar *tpv = p->pktvar; - if (p->pktvar == NULL) - p->pktvar = pv; - else { - while(tpv) { - if (tpv->next == NULL) { - tpv->next = pv; - return; - } - tpv = tpv->next; + PktVar *tpv = p->pktvar; + if (p->pktvar == NULL) + p->pktvar = pv; + else { + while(tpv) { + if (tpv->next == NULL) { + tpv->next = pv; + return 0; } + tpv = tpv->next; } - } else { - PktVarUpdate(pv, value, size); } + return 0; } void PktVarFree(PktVar *pv) @@ -96,6 +113,8 @@ void PktVarFree(PktVar *pv) if (pv == NULL) return; + if (pv->key != NULL) + SCFree(pv->key); if (pv->value != NULL) SCFree(pv->value); PktVar *pv_next = pv->next; diff --git a/src/pkt-var.h b/src/pkt-var.h index cfdd6f5aee5c..0a261c9ffaaf 100644 --- a/src/pkt-var.h +++ b/src/pkt-var.h @@ -24,7 +24,8 @@ #ifndef __PKT_VAR_H__ #define __PKT_VAR_H__ -void PktVarAdd(Packet *, uint32_t id, uint8_t *, uint16_t); +int WARN_UNUSED PktVarAddKeyValue(Packet *, uint8_t *, uint16_t, uint8_t *, uint16_t); +int WARN_UNUSED PktVarAdd(Packet *, uint32_t id, uint8_t *, uint16_t); PktVar *PktVarGet(Packet *, uint32_t id); void PktVarFree(PktVar *); diff --git a/src/util-var.h b/src/util-var.h index 3deeaf747912..ac9de2d3fb47 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -30,6 +30,7 @@ enum VarTypes { VAR_TYPE_PKT_BIT, VAR_TYPE_PKT_INT, VAR_TYPE_PKT_VAR, + VAR_TYPE_PKT_VAR_KV, // key-value VAR_TYPE_FLOW_BIT, VAR_TYPE_FLOW_INT, From b6e4276792b3b48c8db639e98d3de54416e77cf4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Dec 2016 11:16:41 +0100 Subject: [PATCH 2443/2553] hostbits: add list API --- src/host-bit.c | 19 +++++++++++++++++++ src/host-bit.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/src/host-bit.c b/src/host-bit.c index 757654f7be72..6710caebf113 100644 --- a/src/host-bit.c +++ b/src/host-bit.c @@ -181,6 +181,25 @@ int HostBitIsnotset(Host *h, uint32_t idx, uint32_t ts) return 0; } +int HostBitList(Host *h, XBit **iter) +{ + GenericVar *gv = (GenericVar *)*iter; + if (gv == NULL) { + gv = HostGetStorageById(h, host_bit_id); + } else { + gv = gv->next; + } + + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_XBITS) { + *iter = (XBit *)gv; + return 1; + } + } + *iter = NULL; + return 0; +} + /* TESTS */ #ifdef UNITTESTS static int HostBitTest01 (void) diff --git a/src/host-bit.h b/src/host-bit.h index f125ed09cb51..388147dad58c 100644 --- a/src/host-bit.h +++ b/src/host-bit.h @@ -38,4 +38,6 @@ void HostBitUnset(Host *, uint32_t); void HostBitToggle(Host *, uint32_t, uint32_t); int HostBitIsset(Host *, uint32_t, uint32_t); int HostBitIsnotset(Host *, uint32_t, uint32_t); +int HostBitList(Host *, XBit **); + #endif /* __HOST_BIT_H__ */ From 88888c3d8bc2b791e199073f618557a1fe403106 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Dec 2016 14:49:17 +0100 Subject: [PATCH 2444/2553] unix-socket: add/list/remove hostbit commands add-hostbit adds a named hostbit with an expire time in seconds. remove-hostbit removes hostbit by name. add-hostbit, remove-hostbit return success or failure. list-hostbit returns a json array of hostbits with their name and expire time: { "message": { "count": 1, "hostbits": [{ "expire": 3222, "name": "firefox-users" }] }, "return": "OK" } --- src/runmode-unix-socket.c | 254 ++++++++++++++++++++++++++++++++++++++ src/runmode-unix-socket.h | 3 + src/unix-manager.c | 3 + 3 files changed, 260 insertions(+) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 092cadaa9981..7d9ef8ed2670 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -37,6 +37,7 @@ #include "defrag.h" #include "ippair.h" #include "app-layer.h" +#include "host-bit.h" #include "util-profiling.h" @@ -751,6 +752,259 @@ TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data) json_object_set_new(answer, "message", json_string("work in progress")); return TM_ECODE_OK; } + +/** + * \brief Command to add a hostbit + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + */ +TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data_usused) +{ + /* 1 get ip address */ + json_t *jarg = json_object_get(cmd, "ipaddress"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("ipaddress is not an string")); + return TM_ECODE_FAILED; + } + const char *ipaddress = json_string_value(jarg); + + Address a; + struct in_addr in; + memset(&in, 0, sizeof(in)); + if (inet_pton(AF_INET, ipaddress, &in) != 1) { + uint32_t in6[4]; + memset(&in6, 0, sizeof(in6)); + if (inet_pton(AF_INET6, ipaddress, &in) != 1) { + json_object_set_new(answer, "message", json_string("invalid address string")); + return TM_ECODE_FAILED; + } else { + a.family = AF_INET6; + a.addr_data32[0] = in6[0]; + a.addr_data32[1] = in6[1]; + a.addr_data32[2] = in6[2]; + a.addr_data32[3] = in6[3]; + } + } else { + a.family = AF_INET; + a.addr_data32[0] = in.s_addr; + a.addr_data32[1] = 0; + a.addr_data32[2] = 0; + a.addr_data32[3] = 0; + } + + /* 2 get variable name */ + jarg = json_object_get(cmd, "hostbit"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("hostbit is not a string")); + return TM_ECODE_FAILED; + } + const char *hostbit = json_string_value(jarg); + uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT); + if (idx == 0) { + json_object_set_new(answer, "message", json_string("hostbit not found")); + return TM_ECODE_FAILED; + } + + /* 3 get expire */ + jarg = json_object_get(cmd, "expire"); + if (!json_is_integer(jarg)) { + json_object_set_new(answer, "message", json_string("expire is not an integer")); + return TM_ECODE_FAILED; + } + uint32_t expire = json_integer_value(jarg); + + SCLogInfo("add-hostbit: ip %s hostbit %s expire %us", ipaddress, hostbit, expire); + + struct timeval current_time; + TimeGet(¤t_time); + Host *host = HostGetHostFromHash(&a); + if (host) { + HostBitSet(host, idx, current_time.tv_sec + expire); + HostUnlock(host); + + json_object_set_new(answer, "message", json_string("hostbit added")); + return TM_ECODE_OK; + } else { + json_object_set_new(answer, "message", json_string("couldn't create host")); + return TM_ECODE_FAILED; + } +} + +/** + * \brief Command to remove a hostbit + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + */ +TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data_unused) +{ + /* 1 get ip address */ + json_t *jarg = json_object_get(cmd, "ipaddress"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("ipaddress is not an string")); + return TM_ECODE_FAILED; + } + const char *ipaddress = json_string_value(jarg); + + Address a; + struct in_addr in; + memset(&in, 0, sizeof(in)); + if (inet_pton(AF_INET, ipaddress, &in) != 1) { + uint32_t in6[4]; + memset(&in6, 0, sizeof(in6)); + if (inet_pton(AF_INET6, ipaddress, &in) != 1) { + json_object_set_new(answer, "message", json_string("invalid address string")); + return TM_ECODE_FAILED; + } else { + a.family = AF_INET6; + a.addr_data32[0] = in6[0]; + a.addr_data32[1] = in6[1]; + a.addr_data32[2] = in6[2]; + a.addr_data32[3] = in6[3]; + } + } else { + a.family = AF_INET; + a.addr_data32[0] = in.s_addr; + a.addr_data32[1] = 0; + a.addr_data32[2] = 0; + a.addr_data32[3] = 0; + } + + /* 2 get variable name */ + jarg = json_object_get(cmd, "hostbit"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("hostbit is not a string")); + return TM_ECODE_FAILED; + } + + const char *hostbit = json_string_value(jarg); + uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT); + if (idx == 0) { + json_object_set_new(answer, "message", json_string("hostbit not found")); + return TM_ECODE_FAILED; + } + + SCLogInfo("remove-hostbit: %s %s", ipaddress, hostbit); + + Host *host = HostLookupHostFromHash(&a); + if (host) { + HostBitUnset(host, idx); + HostUnlock(host); + json_object_set_new(answer, "message", json_string("hostbit removed")); + return TM_ECODE_OK; + } else { + json_object_set_new(answer, "message", json_string("host not found")); + return TM_ECODE_FAILED; + } +} + +/** + * \brief Command to list hostbits for an ip + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * + * Message looks like: + * {"message": {"count": 1, "hostbits": [{"expire": 3222, "name": "firefox-users"}]}, "return": "OK"} + * + * \retval r TM_ECODE_OK or TM_ECODE_FAILED + */ +TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data_unused) +{ + /* 1 get ip address */ + json_t *jarg = json_object_get(cmd, "ipaddress"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("ipaddress is not an string")); + return TM_ECODE_FAILED; + } + const char *ipaddress = json_string_value(jarg); + + Address a; + struct in_addr in; + memset(&in, 0, sizeof(in)); + if (inet_pton(AF_INET, ipaddress, &in) != 1) { + uint32_t in6[4]; + memset(&in6, 0, sizeof(in6)); + if (inet_pton(AF_INET6, ipaddress, &in) != 1) { + json_object_set_new(answer, "message", json_string("invalid address string")); + return TM_ECODE_FAILED; + } else { + a.family = AF_INET6; + a.addr_data32[0] = in6[0]; + a.addr_data32[1] = in6[1]; + a.addr_data32[2] = in6[2]; + a.addr_data32[3] = in6[3]; + } + } else { + a.family = AF_INET; + a.addr_data32[0] = in.s_addr; + a.addr_data32[1] = 0; + a.addr_data32[2] = 0; + a.addr_data32[3] = 0; + } + + SCLogInfo("list-hostbit: %s", ipaddress); + + struct timeval ts; + memset(&ts, 0, sizeof(ts)); + TimeGet(&ts); + + struct Bit { + uint32_t id; + uint32_t expire; + } bits[256]; + memset(&bits, 0, sizeof(bits)); + int i = 0, use = 0; + + Host *host = HostLookupHostFromHash(&a); + if (!host) { + json_object_set_new(answer, "message", json_string("host not found")); + return TM_ECODE_FAILED; + } + + XBit *iter = NULL; + while (use < 256 && HostBitList(host, &iter) == 1) { + bits[use].id = iter->idx; + bits[use].expire = iter->expire; + use++; + } + HostUnlock(host); + + json_t *jdata = json_object(); + json_t *jarray = json_array(); + if (jarray == NULL || jdata == NULL) { + if (jdata != NULL) + json_decref(jdata); + if (jarray != NULL) + json_decref(jarray); + json_object_set_new(answer, "message", + json_string("internal error at json object creation")); + return TM_ECODE_FAILED; + } + + for (i = 0; i < use; i++) { + json_t *bitobject = json_object(); + if (bitobject == NULL) + continue; + uint32_t expire = 0; + if ((uint32_t)ts.tv_sec < bits[i].expire) + expire = bits[i].expire - (uint32_t)ts.tv_sec; + + const char *name = VarNameStoreLookupById(bits[i].id, VAR_TYPE_HOST_BIT); + if (name == NULL) + continue; + json_object_set_new(bitobject, "name", json_string(name)); + SCLogDebug("xbit %s expire %u", name, expire); + json_object_set_new(bitobject, "expire", json_integer(expire)); + json_array_append_new(jarray, bitobject); + } + + json_object_set_new(jdata, "count", json_integer(i)); + json_object_set_new(jdata, "hostbits", jarray); + json_object_set_new(answer, "message", jdata); + return TM_ECODE_OK; +} #endif /* BUILD_UNIX_SOCKET */ /** diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index 20b0fea496d0..78ef53626514 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -37,6 +37,9 @@ TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *dat TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data); #endif #endif /* __RUNMODE_UNIX_SOCKET_H__ */ diff --git a/src/unix-manager.c b/src/unix-manager.c index 559a8b398019..2e8cf5a94a31 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -932,6 +932,9 @@ static TmEcode UnixManagerThreadInit(ThreadVars *t, void *initdata, void **data) UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("add-hostbit", UnixSocketHostbitAdd, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("remove-hostbit", UnixSocketHostbitRemove, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("list-hostbit", UnixSocketHostbitList, &command, UNIX_CMD_TAKE_ARGS); *data = utd; return TM_ECODE_OK; From 8fde6f967ff2dda8056a69418aa804e6149d79e7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Dec 2016 14:49:40 +0100 Subject: [PATCH 2445/2553] suricatasc: add/list/remove hostbit commands Syntax: add-hostbit Example: add-hostbit 1.2.3.4 blacklist 3600 Syntax: remove-hostbit Example: remove-hostbit 1.2.3.4 blacklist Syntax: list-hostbit Example: list-hostbit 1.2.3.4 --- scripts/suricatasc/src/suricatasc.py | 35 +++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index 1a776a29a0e5..ae62cf205ea3 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -80,7 +80,7 @@ def __call__(self, text, state): class SuricataSC: def __init__(self, sck_path, verbose=False): - self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat','register-tenant','unregister-tenant','register-tenant-handler','unregister-tenant-handler'] + self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat','register-tenant','unregister-tenant','register-tenant-handler','unregister-tenant-handler', 'add-hostbit', 'remove-hostbit', 'list-hostbit'] self.sck_path = sck_path self.verbose = verbose @@ -278,6 +278,39 @@ def parse_command(self, command): arguments = {} arguments["id"] = int(tenantid) arguments["filename"] = filename + elif "add-hostbit" in command: + try: + [cmd, ipaddress, hostbit, expire] = command.split(' ') + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "add-hostbit": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["ipaddress"] = ipaddress + arguments["hostbit"] = hostbit + arguments["expire"] = int(expire) + elif "remove-hostbit" in command: + try: + [cmd, ipaddress, hostbit] = command.split(' ', 2) + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "remove-hostbit": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["ipaddress"] = ipaddress + arguments["hostbit"] = hostbit + elif "list-hostbit" in command: + try: + [cmd, ipaddress] = command.split(' ') + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "list-hostbit": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["ipaddress"] = ipaddress else: cmd = command else: From 71607c905ae67d6e74e52ae2a5e420ae4162bd45 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Dec 2016 15:10:30 +0100 Subject: [PATCH 2446/2553] doc: update unix socket --- doc/userguide/unix-socket.rst | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/doc/userguide/unix-socket.rst b/doc/userguide/unix-socket.rst index 2a4849ddf59d..be7546c7dd4a 100644 --- a/doc/userguide/unix-socket.rst +++ b/doc/userguide/unix-socket.rst @@ -4,14 +4,14 @@ Interacting via Unix Socket Introduction ------------ -Since 1.4 version, Suricata can listen to a unix socket and accept -commands from the user. The exchange protocol is JSON-based and the -format of the message has been done to be generic and it is described -in this commit message. An example script called suricatasc is -provided in the source and installed automatically when updating -Suricata. +Suricata can listen to a unix socket and accept commands from the user. The +exchange protocol is JSON-based and the format of the message has been done +to be generic. -The unix socket is disabled by default. +An example script called suricatasc is provided in the source and installed +automatically when installing/updating Suricata. + +The unix socket is enabled by default if libjansson is available. You need to have libjansson installed: @@ -19,15 +19,14 @@ You need to have libjansson installed: * libjansson-dev - C library for encoding, decoding and manipulating JSON data (dev) * python-simplejson - simple, fast, extensible JSON encoder/decoder for Python -:: +Debian/Ubuntu:: apt-get install libjansson4 libjansson-dev python-simplejson If libjansson is present on the system , unix socket will be compiled -in automatically - when you use "--enable-unix-socket" in your -configure line. +in automatically. -The creation of the socket is activated by setting enabled to yes +The creation of the socket is managed by setting enabled to 'yes' or 'auto' under unix-command in Suricata YAML configuration file: :: From f0af133c5f7c75b5c9abcc397527c45b2e032dad Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Dec 2016 17:09:46 +0100 Subject: [PATCH 2447/2553] flowvar: remove unused DETECT_VAR_TYPE_ALWAYS --- src/detect-flowvar.c | 19 ++++++------------- src/detect.h | 2 -- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index 9f84811a12bd..920ecf651093 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -339,10 +339,9 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, return 1; } -/** \brief Handle flowvar candidate list in det_ctx: - * - clean up the list - * - enforce storage for type ALWAYS (vars set from lua) - * Only called from DetectFlowvarProcessList() when flowvarlist is not NULL . +/** \brief Handle flowvar candidate list in det_ctx: clean up the list + * + * Only called from DetectVarProcessList() when varlist is not NULL. */ void DetectVarProcessListInternal(DetectVarList *fs, Flow *f, Packet *p) { @@ -351,16 +350,10 @@ void DetectVarProcessListInternal(DetectVarList *fs, Flow *f, Packet *p) do { next = fs->next; - if (fs->type == DETECT_VAR_TYPE_ALWAYS) { - SCLogDebug("adding to the flow %u:", fs->idx); - //PrintRawDataFp(stdout, fs->buffer, fs->len); - - FlowVarAddStrNoLock(f, fs->idx, fs->buffer, fs->len); - /* memory at fs->buffer is now the responsibility of - * the flowvar code. */ - } else { - SCFree(fs->buffer); + if (fs->key) { + SCFree(fs->key); } + SCFree(fs->buffer); SCFree(fs); fs = next; } while (fs != NULL); diff --git a/src/detect.h b/src/detect.h index 023b931da41e..acebc9f4ffe0 100644 --- a/src/detect.h +++ b/src/detect.h @@ -492,8 +492,6 @@ typedef struct DetectReplaceList_ { /** only execute flowvar storage if rule matched */ #define DETECT_VAR_TYPE_FLOW_POSTMATCH 1 #define DETECT_VAR_TYPE_PKT_POSTMATCH 2 -/** execute flowvar storage even if rule doesn't match (for lua) */ -#define DETECT_VAR_TYPE_ALWAYS 3 /** list for flowvar store candidates, to be stored from * post-match function */ From 99517cbd53a378a22f2e14063a5ceb00e095d4b9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 6 Nov 2016 16:43:41 -0500 Subject: [PATCH 2448/2553] lua: support key/value flowvars in lua --- src/detect-flowvar.c | 2 +- src/detect-lua-extensions.c | 557 +++++++++++++++++------------------- src/flow-var.c | 50 +++- src/flow-var.h | 9 +- src/output-json.c | 25 +- 5 files changed, 328 insertions(+), 315 deletions(-) diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index 920ecf651093..bd7ff4038cf6 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -303,7 +303,7 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, //PrintRawDataFp(stdout, fs->buffer, fs->len); if (fs->type == DETECT_VAR_TYPE_FLOW_POSTMATCH && p && p->flow) { - FlowVarAddStrNoLock(p->flow, fs->idx, fs->buffer, fs->len); + FlowVarAddIdValue(p->flow, fs->idx, fs->buffer, fs->len); /* memory at fs->buffer is now the responsibility of * the flowvar code. */ } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && fs->key && p) { diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index 06a11569a534..91d1f071e42d 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -72,308 +72,340 @@ #include "util-lua-dnp3.h" static const char luaext_key_ld[] = "suricata:luadata"; -static const char luaext_key_det_ctx[] = "suricata:det_ctx"; -static int LuaGetFlowvar(lua_State *luastate) +/* hack to please scan-build. Even though LuaCallbackError *always* + * returns 2, scan-build doesn't accept it and and generates false + * positives */ +#define LUA_ERROR(msg) \ + LuaCallbackError(luastate, (msg)); \ + return 2 + +static int GetLuaData(lua_State *luastate, DetectLuaData **ret_ld) { - uint16_t idx; - int id; - Flow *f; - FlowVar *fv; - DetectLuaData *ld; + *ret_ld = NULL; - /* need lua data for id -> idx conversion */ + DetectLuaData *ld; lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); lua_gettable(luastate, LUA_REGISTRYINDEX); ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; + LUA_ERROR("internal error: no ld"); } + *ret_ld = ld; + return 0; +} - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate); +static int GetFlow(lua_State *luastate, Flow **ret_f) +{ + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; + LUA_ERROR("no flow"); } + *ret_f = f; + return 0; +} + +static int GetFlowVarById(lua_State *luastate, Flow *f, + FlowVar **ret_fv, _Bool fv_may_be_null, uint32_t *ret_idx) +{ + DetectLuaData *ld = NULL; + if (ret_idx) + *ret_idx = 0; + *ret_fv = NULL; + + /* need lua data for id -> idx conversion */ + int ret = GetLuaData(luastate, &ld); + if (ret != 0) + return ret; - /* need flowvar idx */ if (!lua_isnumber(luastate, 1)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; + LUA_ERROR("flowvar id not a number"); } - id = lua_tonumber(luastate, 1); + int id = lua_tonumber(luastate, 1); if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWVARS) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowvar id out of range"); - return 2; + LUA_ERROR("flowvar id out of range"); } - idx = ld->flowvar[id]; + uint32_t idx = ld->flowvar[id]; if (idx == 0) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowvar id uninitialized"); - return 2; + LUA_ERROR("flowvar id uninitialized"); + } + FlowVar *fv = FlowVarGet(f, idx); + if (!fv_may_be_null && fv == NULL) { + LUA_ERROR("no flow var"); + } + *ret_fv = fv; + if (ret_idx) + *ret_idx = idx; + return 0; +} + +static int GetFlowVarByKey(lua_State *luastate, Flow *f, FlowVar **ret_fv) +{ + *ret_fv = NULL; + + if (!lua_isstring(luastate, 1)) { + LUA_ERROR("flowvar key not a string"); + } + const char *keystr = lua_tostring(luastate, 1); + if (keystr == NULL) { + LUA_ERROR("key is null"); + } + if (!lua_isnumber(luastate, 2)) { + LUA_ERROR("key length not specified"); + } + int keylen = lua_tonumber(luastate, 2); + if (keylen < 0 || keylen > 0xff) { + LUA_ERROR("key len out of range: max 256"); } - fv = FlowVarGet(f, idx); + FlowVar *fv = FlowVarGetByKey(f, (const uint8_t *)keystr, keylen); if (fv == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow var"); - return 2; + LUA_ERROR("no flow var"); } + *ret_fv = fv; + return 0; +} - LuaPushStringBuffer(luastate, (const uint8_t *)fv->data.fv_str.value, - (size_t)fv->data.fv_str.value_len); +static int GetFlowIntById(lua_State *luastate, Flow *f, + FlowVar **ret_fv, _Bool fv_may_be_null, uint32_t *ret_idx) +{ + DetectLuaData *ld = NULL; + if (ret_idx) + *ret_idx = 0; + *ret_fv = NULL; - return 1; + /* need lua data for id -> idx conversion */ + int ret = GetLuaData(luastate, &ld); + if (ret != 0) + return ret; + + if (!lua_isnumber(luastate, 1)) { + LUA_ERROR("flowvar id not a number"); + } + int id = lua_tonumber(luastate, 1); + if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWVARS) { + LUA_ERROR("flowvar id out of range"); + } + uint32_t idx = ld->flowint[id]; + if (idx == 0) { + LUA_ERROR("flowvar id uninitialized"); + } + FlowVar *fv = FlowVarGet(f, idx); + if (!fv_may_be_null && fv == NULL) { + LUA_ERROR("no flow var"); + } + *ret_fv = fv; + if (ret_idx) + *ret_idx = idx; + return 0; +} +static int LuaGetFlowvar(lua_State *luastate) +{ + Flow *f; + FlowVar *fv; + int ret; + + /* need flow */ + ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; + + if (lua_isnumber(luastate, 1)) { + ret = GetFlowVarById(luastate, f, &fv, FALSE, NULL); + if (ret != 0 || fv == NULL) + return ret; + } else if (lua_isstring(luastate, 1)) { + ret = GetFlowVarByKey(luastate, f, &fv); + if (ret != 0 || fv == NULL) + return ret; + } else { + LUA_ERROR("invalid data type as first argument"); + } + + LuaPushStringBuffer(luastate, + (const uint8_t *)fv->data.fv_str.value, + (size_t)fv->data.fv_str.value_len); + return 1; } -int LuaSetFlowvar(lua_State *luastate) +static int LuaSetFlowvarById(lua_State *luastate) { - uint16_t idx; - int id; + uint32_t idx = 0; Flow *f; const char *str; int len; uint8_t *buffer; - DetectEngineThreadCtx *det_ctx; - DetectLuaData *ld; + FlowVar *fv = NULL; - /* need lua data for id -> idx conversion */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); - lua_gettable(luastate, LUA_REGISTRYINDEX); - ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); - if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; + /* need flow */ + int ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; + + ret = GetFlowVarById(luastate, f, &fv, TRUE, &idx); + if (ret != 0) + return ret; + + if (!lua_isstring(luastate, 2)) { + LUA_ERROR("buffer not a string"); + } + str = lua_tostring(luastate, 2); + if (str == NULL) { + LUA_ERROR("buffer is null"); } - /* need det_ctx */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_det_ctx); - lua_gettable(luastate, LUA_REGISTRYINDEX); - det_ctx = lua_touserdata(luastate, -1); - SCLogDebug("det_ctx %p", det_ctx); - if (det_ctx == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no det_ctx"); - return 2; + if (!lua_isnumber(luastate, 3)) { + LUA_ERROR("buffer length not specified"); + } + len = lua_tonumber(luastate, 3); + if (len < 0 || len > 0xffff) { + LUA_ERROR("len out of range: max 64k"); } - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate); - if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; + buffer = SCMalloc(len+1); + if (unlikely(buffer == NULL)) { + LUA_ERROR("out of memory"); } + memcpy(buffer, str, len); + buffer[len] = '\0'; - /* need flowvar idx */ - if (!lua_isnumber(luastate, 1)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; + FlowVarAddIdValue(f, idx, buffer, len); + return 0; +} + +static int LuaSetFlowvarByKey(lua_State *luastate) +{ + Flow *f; + const char *str; + int len; + uint8_t *buffer; + + /* need flow */ + int ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; + + const char *keystr = NULL; + int keylen = 0; + + keystr = lua_tostring(luastate, 1); + if (keystr == NULL) { + LUA_ERROR("key is null"); } - id = lua_tonumber(luastate, 1); - if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWVARS) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowvar id out of range"); - return 2; + if (!lua_isnumber(luastate, 2)) { + LUA_ERROR("key length not specified"); + } + keylen = lua_tonumber(luastate, 2); + if (keylen < 0 || keylen > 0xff) { + LUA_ERROR("key len out of range: max 256"); } - if (!lua_isstring(luastate, 2)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "2nd arg not a string"); - return 2; + if (!lua_isstring(luastate, 3)) { + LUA_ERROR("buffer not a string"); } - str = lua_tostring(luastate, 2); + str = lua_tostring(luastate, 3); if (str == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "null string"); - return 2; + LUA_ERROR("buffer is null"); } - if (!lua_isnumber(luastate, 3)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "3rd arg not a number"); - return 2; + if (!lua_isnumber(luastate, 4)) { + LUA_ERROR("buffer length not specified"); } - len = lua_tonumber(luastate, 3); + len = lua_tonumber(luastate, 4); if (len < 0 || len > 0xffff) { - lua_pushnil(luastate); - lua_pushstring(luastate, "len out of range: max 64k"); - return 2; - } - - idx = ld->flowvar[id]; - if (idx == 0) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowvar id uninitialized"); - return 2; + LUA_ERROR("len out of range: max 64k"); } buffer = SCMalloc(len+1); if (unlikely(buffer == NULL)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "out of memory"); - return 2; + LUA_ERROR("out of memory"); } memcpy(buffer, str, len); buffer[len] = '\0'; - FlowVarAddStr(f, idx, buffer, len); + uint8_t *keybuf = SCMalloc(keylen+1); + if (unlikely(keybuf == NULL)) { + SCFree(buffer); + LUA_ERROR("out of memory"); + } + memcpy(keybuf, keystr, keylen); + keybuf[keylen] = '\0'; + FlowVarAddKeyValue(f, keybuf, keylen, buffer, len); - //SCLogInfo("stored:"); - //PrintRawDataFp(stdout,buffer,len); return 0; } +static int LuaSetFlowvar(lua_State *luastate) +{ + if (lua_isnumber(luastate, 1)) { + return LuaSetFlowvarById(luastate); + } else { + return LuaSetFlowvarByKey(luastate); + } +} + static int LuaGetFlowint(lua_State *luastate) { - uint16_t idx; - int id; Flow *f; FlowVar *fv; - DetectLuaData *ld; uint32_t number; - /* need lua data for id -> idx conversion */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); - lua_gettable(luastate, LUA_REGISTRYINDEX); - ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); - if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; - } - - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate); - if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; - } + /* need flow */ + int ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; - /* need flowint idx */ - if (!lua_isnumber(luastate, 1)) { - SCLogDebug("1st arg not a number"); - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; - } - id = lua_tonumber(luastate, 1); - if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWINTS) { - SCLogDebug("id %d", id); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id out of range"); - return 2; - } - idx = ld->flowint[id]; - if (idx == 0) { - SCLogDebug("idx %u", idx); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id uninitialized"); - return 2; - } + ret = GetFlowIntById(luastate, f, &fv, FALSE, NULL); + if (ret != 0) + return ret; - /* lookup var */ - fv = FlowVarGet(f, idx); - if (fv == NULL) { - SCLogDebug("fv NULL"); - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow var"); - return 2; - } number = fv->data.fv_int.value; /* return value through luastate, as a luanumber */ lua_pushnumber(luastate, (lua_Number)number); - SCLogDebug("retrieved flow:%p idx:%u value:%u", f, idx, number); - return 1; } -int LuaSetFlowint(lua_State *luastate) +static int LuaSetFlowint(lua_State *luastate) { - uint16_t idx; - int id; + uint32_t idx; Flow *f; - DetectEngineThreadCtx *det_ctx; DetectLuaData *ld; - uint32_t number; - lua_Number luanumber; /* need lua data for id -> idx conversion */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); - lua_gettable(luastate, LUA_REGISTRYINDEX); - ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); - if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; - } - - /* need det_ctx */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_det_ctx); - lua_gettable(luastate, LUA_REGISTRYINDEX); - det_ctx = lua_touserdata(luastate, -1); - SCLogDebug("det_ctx %p", det_ctx); - if (det_ctx == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no det_ctx"); - return 2; - } + int ret = GetLuaData(luastate, &ld); + if (ret != 0) + return ret; - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate); - if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; - } + /* need flow */ + ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; /* need flowint idx */ if (!lua_isnumber(luastate, 1)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; + LUA_ERROR("1st arg not a number"); } - id = lua_tonumber(luastate, 1); + int id = lua_tonumber(luastate, 1); if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWVARS) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id out of range"); - return 2; + LUA_ERROR("flowint id out of range"); } if (!lua_isnumber(luastate, 2)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "2nd arg not a number"); - return 2; + LUA_ERROR("2nd arg not a number"); } - luanumber = lua_tonumber(luastate, 2); + lua_Number luanumber = lua_tonumber(luastate, 2); if (luanumber < 0 || id > (double)UINT_MAX) { - lua_pushnil(luastate); - lua_pushstring(luastate, "value out of range, value must be unsigned 32bit int"); - return 2; + LUA_ERROR("value out of range, " + "value must be unsigned 32bit int"); } - number = (uint32_t)luanumber; + uint32_t number = (uint32_t)luanumber; idx = ld->flowint[id]; if (idx == 0) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id uninitialized"); - return 2; + LUA_ERROR("flowint id uninitialized"); } FlowVarAddInt(f, idx, number); @@ -384,56 +416,20 @@ int LuaSetFlowint(lua_State *luastate) static int LuaIncrFlowint(lua_State *luastate) { - uint16_t idx; - int id; + uint32_t idx; Flow *f; FlowVar *fv; - DetectLuaData *ld; uint32_t number; - /* need lua data for id -> idx conversion */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); - lua_gettable(luastate, LUA_REGISTRYINDEX); - ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); - if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; - } - - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate); - if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; - } + /* need flow */ + int ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; - /* need flowint idx */ - if (!lua_isnumber(luastate, 1)) { - SCLogDebug("1st arg not a number"); - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; - } - id = lua_tonumber(luastate, 1); - if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWINTS) { - SCLogDebug("id %d", id); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id out of range"); - return 2; - } - idx = ld->flowint[id]; - if (idx == 0) { - SCLogDebug("idx %u", idx); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id uninitialized"); - return 2; - } + ret = GetFlowIntById(luastate, f, &fv, TRUE, &idx); + if (ret != 0) + return ret; - /* lookup var */ - fv = FlowVarGet(f, idx); if (fv == NULL) { number = 1; } else { @@ -446,63 +442,26 @@ static int LuaIncrFlowint(lua_State *luastate) /* return value through luastate, as a luanumber */ lua_pushnumber(luastate, (lua_Number)number); SCLogDebug("incremented flow:%p idx:%u value:%u", f, idx, number); - return 1; } static int LuaDecrFlowint(lua_State *luastate) { - uint16_t idx; - int id; + uint32_t idx; Flow *f; FlowVar *fv; - DetectLuaData *ld; uint32_t number; - /* need lua data for id -> idx conversion */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); - lua_gettable(luastate, LUA_REGISTRYINDEX); - ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); - if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; - } + /* need flow */ + int ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate); - if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; - } + ret = GetFlowIntById(luastate, f, &fv, TRUE, &idx); + if (ret != 0) + return ret; - /* need flowint idx */ - if (!lua_isnumber(luastate, 1)) { - SCLogDebug("1st arg not a number"); - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; - } - id = lua_tonumber(luastate, 1); - if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWINTS) { - SCLogDebug("id %d", id); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id out of range"); - return 2; - } - idx = ld->flowint[id]; - if (idx == 0) { - SCLogDebug("idx %u", idx); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id uninitialized"); - return 2; - } - - /* lookup var */ - fv = FlowVarGet(f, idx); if (fv == NULL) { number = 0; } else { @@ -515,7 +474,6 @@ static int LuaDecrFlowint(lua_State *luastate) /* return value through luastate, as a luanumber */ lua_pushnumber(luastate, (lua_Number)number); SCLogDebug("decremented flow:%p idx:%u value:%u", f, idx, number); - return 1; } @@ -530,11 +488,6 @@ void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld, DetectEngi lua_pushlightuserdata(lua_state, (void *)ld); lua_settable(lua_state, LUA_REGISTRYINDEX); - /* detection engine thread ctx */ - lua_pushlightuserdata(lua_state, (void *)&luaext_key_det_ctx); - lua_pushlightuserdata(lua_state, (void *)det_ctx); - lua_settable(lua_state, LUA_REGISTRYINDEX); - LuaStateSetFlow(lua_state, f); if (det_ctx->tx_id_set) { diff --git a/src/flow-var.c b/src/flow-var.c index d929d5587445..d4506b9b0356 100644 --- a/src/flow-var.c +++ b/src/flow-var.c @@ -47,6 +47,27 @@ static void FlowVarUpdateInt(FlowVar *fv, uint32_t value) fv->data.fv_int.value = value; } +/** \brief get the flowvar with index 'idx' from the flow + * \note flow is not locked by this function, caller is + * responsible + */ +FlowVar *FlowVarGetByKey(Flow *f, const uint8_t *key, uint16_t keylen) +{ + GenericVar *gv = f->flowvar; + + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_FLOWVAR && gv->idx == 0) { + + FlowVar *fv = (FlowVar *)gv; + if (fv->keylen == keylen && memcmp(key, fv->key, keylen) == 0) { + return fv; + } + } + } + + return NULL; +} + /** \brief get the flowvar with index 'idx' from the flow * \note flow is not locked by this function, caller is * responsible @@ -64,11 +85,30 @@ FlowVar *FlowVarGet(Flow *f, uint32_t idx) } /* add a flowvar to the flow, or update it */ -void FlowVarAddStrNoLock(Flow *f, uint32_t idx, uint8_t *value, uint16_t size) +void FlowVarAddKeyValue(Flow *f, uint8_t *key, uint16_t keysize, uint8_t *value, uint16_t size) +{ + FlowVar *fv = SCCalloc(1, sizeof(FlowVar)); + if (unlikely(fv == NULL)) + return; + + fv->type = DETECT_FLOWVAR; + fv->datatype = FLOWVAR_TYPE_STR; + fv->idx = 0; + fv->data.fv_str.value = value; + fv->data.fv_str.value_len = size; + fv->key = key; + fv->keylen = keysize; + fv->next = NULL; + + GenericVarAppend(&f->flowvar, (GenericVar *)fv); +} + +/* add a flowvar to the flow, or update it */ +void FlowVarAddIdValue(Flow *f, uint32_t idx, uint8_t *value, uint16_t size) { FlowVar *fv = FlowVarGet(f, idx); if (fv == NULL) { - fv = SCMalloc(sizeof(FlowVar)); + fv = SCCalloc(1, sizeof(FlowVar)); if (unlikely(fv == NULL)) return; @@ -85,12 +125,6 @@ void FlowVarAddStrNoLock(Flow *f, uint32_t idx, uint8_t *value, uint16_t size) } } -/* add a flowvar to the flow, or update it */ -void FlowVarAddStr(Flow *f, uint32_t idx, uint8_t *value, uint16_t size) -{ - FlowVarAddStrNoLock(f, idx, value, size); -} - /* add a flowvar to the flow, or update it */ void FlowVarAddIntNoLock(Flow *f, uint32_t idx, uint32_t value) { diff --git a/src/flow-var.h b/src/flow-var.h index 0f7eeeb9266f..7d0d4edb8720 100644 --- a/src/flow-var.h +++ b/src/flow-var.h @@ -56,16 +56,19 @@ typedef struct FlowVar_ { FlowVarTypeStr fv_str; FlowVarTypeInt fv_int; } data; - + uint8_t *key; + uint16_t keylen; } FlowVar; /** Flowvar Interface API */ -void FlowVarAddStrNoLock(Flow *, uint32_t, uint8_t *, uint16_t); -void FlowVarAddStr(Flow *, uint32_t, uint8_t *, uint16_t); +void FlowVarAddIdValue(Flow *, uint32_t id, uint8_t *value, uint16_t size); +void FlowVarAddKeyValue(Flow *f, uint8_t *key, uint16_t keysize, uint8_t *value, uint16_t size); + void FlowVarAddIntNoLock(Flow *, uint32_t, uint32_t); void FlowVarAddInt(Flow *, uint32_t, uint32_t); FlowVar *FlowVarGet(Flow *, uint32_t); +FlowVar *FlowVarGetByKey(Flow *f, const uint8_t *key, uint16_t keylen); void FlowVarFree(FlowVar *); void FlowVarPrint(GenericVar *); diff --git a/src/output-json.c b/src/output-json.c index 7db6262d33d1..95f9b0167dbb 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -160,7 +160,7 @@ static void JsonAddFlowvars(const Flow *f, json_t *js_vars) while (gv != NULL) { if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { FlowVar *fv = (FlowVar *)gv; - if (fv->datatype == FLOWVAR_TYPE_STR) { + if (fv->datatype == FLOWVAR_TYPE_STR && fv->key == NULL) { const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_VAR); if (varname) { if (js_flowvars == NULL) { @@ -179,6 +179,29 @@ static void JsonAddFlowvars(const Flow *f, json_t *js_vars) json_object_set_new(js_flowvars, varname, json_string((char *)printable_buf)); } + } else if (fv->datatype == FLOWVAR_TYPE_STR && fv->key != NULL) { + if (js_flowvars == NULL) { + js_flowvars = json_object(); + if (js_flowvars == NULL) + break; + } + + uint8_t keybuf[fv->keylen + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(keybuf, &offset, + sizeof(keybuf), + fv->key, fv->keylen); + + uint32_t len = fv->data.fv_str.value_len; + uint8_t printable_buf[len + 1]; + offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + fv->data.fv_str.value, fv->data.fv_str.value_len); + + json_object_set_new(js_flowvars, (const char *)keybuf, + json_string((char *)printable_buf)); + } else if (fv->datatype == FLOWVAR_TYPE_INT) { const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_INT); if (varname) { From 4a49260897d05d219673e2282ba96ee37c09e9a8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Dec 2016 17:40:28 +0100 Subject: [PATCH 2449/2553] flowvar: shrink flowvar type by using padded space --- src/flow-bit.h | 1 + src/flow-var.h | 4 ++-- src/util-var.h | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/flow-bit.h b/src/flow-bit.h index e6161606fc42..2362d5180795 100644 --- a/src/flow-bit.h +++ b/src/flow-bit.h @@ -29,6 +29,7 @@ typedef struct FlowBit_ { uint8_t type; /* type, DETECT_FLOWBITS in this case */ + uint8_t pad[3]; uint32_t idx; /* name idx */ GenericVar *next; /* right now just implement this as a list, * in the long run we have think of something diff --git a/src/flow-var.h b/src/flow-var.h index 7d0d4edb8720..f0bcf3c0c3f6 100644 --- a/src/flow-var.h +++ b/src/flow-var.h @@ -47,17 +47,17 @@ typedef struct FlowVarTypeInt_ { /** Generic Flowvar Structure */ typedef struct FlowVar_ { uint8_t type; /* type, DETECT_FLOWVAR in this case */ + uint8_t datatype; + uint16_t keylen; uint32_t idx; /* name idx */ GenericVar *next; /* right now just implement this as a list, * in the long run we have think of something * faster. */ - uint8_t datatype; union { FlowVarTypeStr fv_str; FlowVarTypeInt fv_int; } data; uint8_t *key; - uint16_t keylen; } FlowVar; /** Flowvar Interface API */ diff --git a/src/util-var.h b/src/util-var.h index ac9de2d3fb47..ce491ecdcd82 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -47,12 +47,14 @@ enum VarTypes { typedef struct GenericVar_ { uint8_t type; + uint8_t pad[3]; uint32_t idx; struct GenericVar_ *next; } GenericVar; typedef struct XBit_ { uint8_t type; /* type, DETECT_XBITS in this case */ + uint8_t pad[3]; uint32_t idx; /* name idx */ GenericVar *next; uint32_t expire; From c477c4370e1e2b56b1aebf272bc28bdb0680956f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Dec 2016 11:39:58 +0100 Subject: [PATCH 2450/2553] doc: update for unix socket hostbits --- doc/userguide/rules/xbits.rst | 44 +++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/doc/userguide/rules/xbits.rst b/doc/userguide/rules/xbits.rst index 026e3831813f..3af99cff94d5 100644 --- a/doc/userguide/rules/xbits.rst +++ b/doc/userguide/rules/xbits.rst @@ -25,8 +25,48 @@ Threading Due to subtle timing issues between threads the order of sets and checks can be slightly unpredictible. -Example: create a SSH blacklist -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Unix Socket +----------- + +Hostbits can be added, removed and listed through the unix socket. + +Add:: + + suricatasc -c "add-hostbit " + suricatasc -c "add-hostbit 1.2.3.4 blacklist 3600" + +If an hostbit is added for an existing hostbit, it's expiry timer is updated. + +Remove:: + + suricatasc -c "remove-hostbit " + suricatasc -c "remove-hostbit 1.2.3.4 blacklist" + +List:: + + suricatasc -c "list-hostbit " + suricatasc -c "list-hostbit 1.2.3.4" + +This results in:: + + { + "message": + { + "count": 1, + "hostbits": + [{ + "expire": 89, + "name": "blacklist" + }] + }, + "return": "OK" + } + +Examples +-------- + +Creating a SSH blacklist +^^^^^^^^^^^^^^^^^^^^^^^^ Below is an example of rules incoming to a SSH server. From cc4010343dd495df44d0791f4aadadb63656982e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Dec 2016 10:43:36 +0100 Subject: [PATCH 2451/2553] detect: add and use util func for alproto sets --- src/detect-app-layer-event.c | 16 +++---------- src/detect-byte-extract.c | 7 ++---- src/detect-bytejump.c | 9 ++----- src/detect-bytetest.c | 9 ++----- src/detect-cipservice.c | 21 ++++------------- src/detect-dce-iface.c | 8 +------ src/detect-dce-opnum.c | 8 +------ src/detect-dce-stub-data.c | 12 ++-------- src/detect-ftpbounce.c | 7 +----- src/detect-modbus.c | 7 ++---- src/detect-parse.c | 20 ++++++++++++++++ src/detect-parse.h | 2 ++ src/detect-ssh-proto-version.c | 7 +----- src/detect-ssh-software-version.c | 8 +------ src/detect-ssl-state.c | 12 +++------- src/detect-ssl-version.c | 8 ++----- src/detect-tls-cert-validity.c | 39 +++++++------------------------ src/detect-tls-version.c | 7 ++---- src/detect-tls.c | 36 ++++++---------------------- src/detect-urilen.c | 11 ++------- 20 files changed, 69 insertions(+), 185 deletions(-) diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index c7128c27a751..8658d3955e78 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -336,23 +336,13 @@ static int DetectAppLayerEventSetupP1(DetectEngineCtx *de_ctx, Signature *s, cha sm->type = DETECT_AL_APP_LAYER_EVENT; sm->ctx = (SigMatchCtx *)data; - if (s->alproto != ALPROTO_UNKNOWN) { - if (s->alproto != data->alproto) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains " - "conflicting keywords needing different alprotos"); - goto error; - } - } else { - s->alproto = data->alproto; - } - if (event_type == APP_LAYER_EVENT_TYPE_PACKET) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); } else { - /* We push it to this list temporarily. We deal with - * these in DetectAppLayerEventPrepare(). */ + if (DetectSignatureSetAppProto(s, data->alproto) != 0) + goto error; + SigMatchAppendSMToList(s, sm, g_applayer_events_list_id); - s->flags |= SIG_FLAG_APPLAYER; } return 0; diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 07f358367c5d..0b0f4734777c 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -561,12 +561,9 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *a } if (data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Non dce alproto sig has " - "byte_extract with dce enabled"); + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) goto error; - } - s->alproto = ALPROTO_DCERPC; + if ((data->flags & DETECT_BYTE_EXTRACT_FLAG_STRING) || (data->base == DETECT_BYTE_EXTRACT_BASE_DEC) || (data->base == DETECT_BYTE_EXTRACT_BASE_HEX) || diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 872cd56b060d..8db0adfefba2 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -539,8 +539,8 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts sm_list = DETECT_SM_LIST_PMATCH; } - s->alproto = ALPROTO_DCERPC; - s->flags |= SIG_FLAG_APPLAYER; + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) + goto error; } else if (data->flags & DETECT_BYTEJUMP_RELATIVE) { prev_pm = DetectGetLastSMFromLists(s, @@ -560,11 +560,6 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts } if (data->flags & DETECT_BYTEJUMP_DCE) { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Non dce alproto sig has " - "bytejump with dce enabled"); - goto error; - } if ((data->flags & DETECT_BYTEJUMP_STRING) || (data->flags & DETECT_BYTEJUMP_LITTLE) || (data->flags & DETECT_BYTEJUMP_BIG) || diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 731ad6f4e6af..4ad7f53e8378 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -467,8 +467,8 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts sm_list = DETECT_SM_LIST_PMATCH; } - s->alproto = ALPROTO_DCERPC; - s->flags |= SIG_FLAG_APPLAYER; + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) + goto error; } else if (data->flags & DETECT_BYTETEST_RELATIVE) { prev_pm = DetectGetLastSMFromLists(s, @@ -488,11 +488,6 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *opts } if (data->flags & DETECT_BYTETEST_DCE) { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Non dce alproto sig has " - "bytetest with dce enabled"); - goto error; - } if ((data->flags & DETECT_BYTETEST_STRING) || (data->flags & DETECT_BYTETEST_LITTLE) || (data->flags & DETECT_BYTETEST_BIG) || diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c index 6452ffaff622..de9aa04c4028 100644 --- a/src/detect-cipservice.c +++ b/src/detect-cipservice.c @@ -207,12 +207,8 @@ static int DetectCipServiceSetup(DetectEngineCtx *de_ctx, Signature *s, DetectCipServiceData *cipserviced = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_ENIP) - { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, - "rule contains conflicting keywords."); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_ENIP) != 0) + return -1; cipserviced = DetectCipServiceParse(rulestr); if (cipserviced == NULL) @@ -225,10 +221,7 @@ static int DetectCipServiceSetup(DetectEngineCtx *de_ctx, Signature *s, sm->type = DETECT_CIPSERVICE; sm->ctx = (void *) cipserviced; - s->alproto = ALPROTO_ENIP; - SigMatchAppendSMToList(s, sm, g_cip_buffer_id); - SCReturnInt(0); error: @@ -384,12 +377,8 @@ static int DetectEnipCommandSetup(DetectEngineCtx *de_ctx, Signature *s, DetectEnipCommandData *enipcmdd = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_ENIP) - { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, - "rule contains conflicting keywords."); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_ENIP) != 0) + return -1; enipcmdd = DetectEnipCommandParse(rulestr); if (enipcmdd == NULL) @@ -402,9 +391,7 @@ static int DetectEnipCommandSetup(DetectEngineCtx *de_ctx, Signature *s, sm->type = DETECT_ENIPCOMMAND; sm->ctx = (void *) enipcmdd; - s->alproto = ALPROTO_ENIP; SigMatchAppendSMToList(s, sm, g_enip_buffer_id); - SCReturnInt(0); error: diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index 50e74774016e..e1bf69d4dfc5 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -370,10 +370,8 @@ static int DetectDceIfaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) DetectDceIfaceData *did = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) return -1; - } did = DetectDceIfaceArgParse(arg); if (did == NULL) { @@ -390,10 +388,6 @@ static int DetectDceIfaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->ctx = (void *)did; SigMatchAppendSMToList(s, sm, g_dce_generic_list_id); - - s->alproto = ALPROTO_DCERPC; - /* Flagged the signature as to inspect the app layer data */ - s->flags |= SIG_FLAG_APPLAYER; return 0; error: diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 5417826ea0c7..9098a47150e5 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -296,10 +296,8 @@ static int DetectDceOpnumSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return -1; } - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) return -1; - } dod = DetectDceOpnumArgParse(arg); if (dod == NULL) { @@ -316,10 +314,6 @@ static int DetectDceOpnumSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->ctx = (void *)dod; SigMatchAppendSMToList(s, sm, g_dce_generic_list_id); - - s->alproto = ALPROTO_DCERPC; - /* Flagged the signature as to inspect the app layer data */ - s->flags |= SIG_FLAG_APPLAYER; return 0; error: diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index 6318e0dfc5f6..ee7275dede6e 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -237,19 +237,11 @@ void DetectDceStubDataRegister(void) static int DetectDceStubDataSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, - "rule contains conflicting keywords."); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) + return -1; s->init_data->list = g_dce_stub_data_buffer_id; - s->alproto = ALPROTO_DCERPC; - s->flags |= SIG_FLAG_APPLAYER; return 0; - - error: - return -1; } /************************************Unittests*********************************/ diff --git a/src/detect-ftpbounce.c b/src/detect-ftpbounce.c index 0e2c2a07b583..8e33aaf9d0dc 100644 --- a/src/detect-ftpbounce.c +++ b/src/detect-ftpbounce.c @@ -225,10 +225,8 @@ int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, char *ftpbounces SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_FTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + if (DetectSignatureSetAppProto(s, ALPROTO_FTP) != 0) return -1; - } sm = SigMatchAlloc(); if (sm == NULL) { @@ -249,9 +247,6 @@ int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, char *ftpbounces sm->ctx = NULL; SigMatchAppendSMToList(s, sm, g_ftp_request_list_id); - - s->alproto = ALPROTO_FTP; - s->flags |= SIG_FLAG_APPLAYER; SCReturnInt(0); } diff --git a/src/detect-modbus.c b/src/detect-modbus.c index 19518e28261c..1c84f5778ebf 100644 --- a/src/detect-modbus.c +++ b/src/detect-modbus.c @@ -366,10 +366,8 @@ static int DetectModbusSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) DetectModbus *modbus = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_MODBUS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_MODBUS) != 0) + return -1; if ((modbus = DetectModbusFunctionParse(str)) == NULL) { if ((modbus = DetectModbusAccessParse(str)) == NULL) { @@ -387,7 +385,6 @@ static int DetectModbusSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) sm->ctx = (void *) modbus; SigMatchAppendSMToList(s, sm, g_modbus_buffer_id); - s->alproto = ALPROTO_MODBUS; SCReturnInt(0); diff --git a/src/detect-parse.c b/src/detect-parse.c index 6385500f171c..f2d34f36a6dd 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1193,6 +1193,26 @@ void SigFree(Signature *s) SCFree(s); } +int DetectSignatureSetAppProto(Signature *s, AppProto alproto) +{ + if (alproto == ALPROTO_UNKNOWN || + alproto >= ALPROTO_FAILED) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid alproto %u", alproto); + return -1; + } + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "can't set rule app proto to %s: already set to %s", + AppProtoToString(alproto), AppProtoToString(s->alproto)); + return -1; + } + + s->alproto = alproto; + s->flags |= SIG_FLAG_APPLAYER; + return 0; +} + /** * \internal * \brief build address match array for cache efficient matching diff --git a/src/detect-parse.h b/src/detect-parse.h index 15f509226695..456ef66a03f8 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -70,6 +70,8 @@ SigMatch *DetectGetLastSMFromLists(const Signature *s, ...); SigMatch *DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list, ...); SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...); +int DetectSignatureSetAppProto(Signature *s, AppProto alproto); + /* parse regex setup and free util funcs */ void DetectSetupParseRegexes(const char *parse_str, diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index ebf8ce0c645f..db2371485280 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -217,10 +217,8 @@ static int DetectSshVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectSshVersionData *ssh = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) != 0) return -1; - } ssh = DetectSshVersionParse(str); if (ssh == NULL) @@ -236,9 +234,6 @@ static int DetectSshVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->ctx = (void *)ssh; SigMatchAppendSMToList(s, sm, g_ssh_banner_list_id); - - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_SSH; return 0; error: diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index 7ab8ecffcab8..da5cc5190b88 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -212,10 +212,8 @@ static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, DetectSshSoftwareVersionData *ssh = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) != 0) return -1; - } ssh = DetectSshSoftwareVersionParse(str); if (ssh == NULL) @@ -230,11 +228,7 @@ static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, sm->type = DETECT_AL_SSH_SOFTWAREVERSION; sm->ctx = (void *)ssh; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_SSH; - SigMatchAppendSMToList(s, sm, g_ssh_banner_list_id); - return 0; error: diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 88394b579fd2..1a85ebdc41aa 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -308,12 +308,9 @@ static int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) DetectSslStateData *ssd = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, - "Rule contains conflicting keywords. Have non-tls alproto " - "set for a rule containing \"ssl_state\" keyword"); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + ssd = DetectSslStateParse(arg); if (ssd == NULL) goto error; @@ -325,10 +322,7 @@ static int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->type = DETECT_AL_SSL_STATE; sm->ctx = (SigMatchCtx*)ssd; - s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, g_tls_generic_list_id); - return 0; error: diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index 661c6b89bf09..82ac3632eb8e 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -282,10 +282,8 @@ static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectSslVersionData *ssl = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; ssl = DetectSslVersionParse(str); if (ssl == NULL) @@ -301,8 +299,6 @@ static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->ctx = (void *)ssl; SigMatchAppendSMToList(s, sm, g_tls_generic_list_id); - - s->alproto = ALPROTO_TLS; return 0; error: diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c index 2a868566d507..17e4b32df7c8 100644 --- a/src/detect-tls-cert-validity.c +++ b/src/detect-tls-cert-validity.c @@ -421,6 +421,9 @@ static int DetectTlsExpiredSetup (DetectEngineCtx *de_ctx, Signature *s, SCLogDebug("\'%s\'", rawstr); + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + dd = SCCalloc(1, sizeof(DetectTlsValidityData)); if (dd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Allocation \'%s\' failed", rawstr); @@ -433,12 +436,6 @@ static int DetectTlsExpiredSetup (DetectEngineCtx *de_ctx, Signature *s, if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, - "rule contains conflicting keywords."); - goto error; - } - dd->mode = DETECT_TLS_VALIDITY_EX; dd->type = DETECT_TLS_TYPE_NOTAFTER; dd->epoch = 0; @@ -447,11 +444,7 @@ static int DetectTlsExpiredSetup (DetectEngineCtx *de_ctx, Signature *s, sm->type = DETECT_AL_TLS_EXPIRED; sm->ctx = (void *)dd; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, g_tls_validity_buffer_id); - return 0; error: @@ -479,6 +472,9 @@ static int DetectTlsValidSetup (DetectEngineCtx *de_ctx, Signature *s, SCLogDebug("\'%s\'", rawstr); + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + dd = SCCalloc(1, sizeof(DetectTlsValidityData)); if (dd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Allocation \'%s\' failed", rawstr); @@ -491,12 +487,6 @@ static int DetectTlsValidSetup (DetectEngineCtx *de_ctx, Signature *s, if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, - "rule contains conflicting keywords."); - goto error; - } - dd->mode = DETECT_TLS_VALIDITY_VA; dd->type = DETECT_TLS_TYPE_NOTAFTER; dd->epoch = 0; @@ -505,11 +495,7 @@ static int DetectTlsValidSetup (DetectEngineCtx *de_ctx, Signature *s, sm->type = DETECT_AL_TLS_VALID; sm->ctx = (void *)dd; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, g_tls_validity_buffer_id); - return 0; error: @@ -576,6 +562,9 @@ static int DetectTlsValiditySetup (DetectEngineCtx *de_ctx, Signature *s, SCLogDebug("\'%s\'", rawstr); + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + dd = DetectTlsValidityParse(rawstr); if (dd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Parsing \'%s\' failed", rawstr); @@ -588,12 +577,6 @@ static int DetectTlsValiditySetup (DetectEngineCtx *de_ctx, Signature *s, if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, - "rule contains conflicting keywords."); - goto error; - } - if (type == DETECT_TLS_TYPE_NOTBEFORE) { dd->type = DETECT_TLS_TYPE_NOTBEFORE; sm->type = DETECT_AL_TLS_NOTBEFORE; @@ -608,11 +591,7 @@ static int DetectTlsValiditySetup (DetectEngineCtx *de_ctx, Signature *s, sm->ctx = (void *)dd; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, g_tls_validity_buffer_id); - return 0; error: diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index 198bb6fae00c..1f027b8247b8 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -221,10 +221,8 @@ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectTlsVersionData *tls = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; tls = DetectTlsVersionParse(str); if (tls == NULL) @@ -241,7 +239,6 @@ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s SigMatchAppendSMToList(s, sm, g_tls_generic_list_id); - s->alproto = ALPROTO_TLS; return 0; error: diff --git a/src/detect-tls.c b/src/detect-tls.c index 9a1a2122bfa6..585eabe3c94a 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -319,10 +319,8 @@ static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectTlsData *tls = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; tls = DetectTlsSubjectParse(str); if (tls == NULL) @@ -337,11 +335,7 @@ static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->type = DETECT_AL_TLS_SUBJECT; sm->ctx = (void *)tls; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, g_tls_cert_list_id); - return 0; error: @@ -532,10 +526,8 @@ static int DetectTlsIssuerDNSetup (DetectEngineCtx *de_ctx, Signature *s, char * DetectTlsData *tls = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; tls = DetectTlsIssuerDNParse(str); if (tls == NULL) @@ -550,11 +542,7 @@ static int DetectTlsIssuerDNSetup (DetectEngineCtx *de_ctx, Signature *s, char * sm->type = DETECT_AL_TLS_ISSUERDN; sm->ctx = (void *)tls; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, g_tls_cert_list_id); - return 0; error: @@ -735,10 +723,8 @@ static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, cha DetectTlsData *tls = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; tls = DetectTlsFingerprintParse(str); if (tls == NULL) @@ -753,11 +739,7 @@ static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, cha sm->type = DETECT_AL_TLS_FINGERPRINT; sm->ctx = (void *)tls; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; - SigMatchAppendSMToList(s, sm, g_tls_cert_list_id); - return 0; error: @@ -797,18 +779,14 @@ static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *str { SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) return -1; - } sm = SigMatchAlloc(); if (sm == NULL) return -1; sm->type = DETECT_AL_TLS_STORE; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; s->flags |= SIG_FLAG_TLSSTORE; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); diff --git a/src/detect-urilen.c b/src/detect-urilen.c index c56993072525..65f4b0b24bc1 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -247,11 +247,8 @@ static int DetectUrilenSetup (DetectEngineCtx *de_ctx, Signature *s, char *urile DetectUrilenData *urilend = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " - "alproto set"); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) != 0) + return -1; urilend = DetectUrilenParse(urilenstr); if (urilend == NULL) @@ -267,10 +264,6 @@ static int DetectUrilenSetup (DetectEngineCtx *de_ctx, Signature *s, char *urile else SigMatchAppendSMToList(s, sm, g_http_uri_buffer_id); - /* Flagged the signature as to inspect the app layer data */ - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_HTTP; - SCReturnInt(0); error: From f38087105723f9fc52df24a66858bb4e51109b92 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 28 Nov 2016 15:36:29 +0100 Subject: [PATCH 2452/2553] threads: don't sleep under lock --- src/flow-manager.c | 60 ++++++++++++++++++++++++++++++++-------------- src/tm-threads.c | 53 +++++++++++++++++++++------------------- src/unix-manager.c | 11 ++++++--- 3 files changed, 79 insertions(+), 45 deletions(-) diff --git a/src/flow-manager.c b/src/flow-manager.c index 87292d876d5b..4f92ec2c12ad 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -136,7 +136,6 @@ void FlowDisableFlowManagerThread(void) return; #endif ThreadVars *tv = NULL; - int cnt = 0; /* wake up threads */ uint32_t u; @@ -144,25 +143,37 @@ void FlowDisableFlowManagerThread(void) SCCtrlCondSignal(&flow_manager_ctrl_cond); SCMutexLock(&tv_root_lock); - /* flow manager thread(s) is/are a part of mgmt threads */ tv = tv_root[TVT_MGMT]; - while (tv != NULL) { if (strncasecmp(tv->name, thread_name_flow_mgr, strlen(thread_name_flow_mgr)) == 0) { TmThreadsSetFlag(tv, THV_KILL); - cnt++; + } + tv = tv->next; + } + SCMutexUnlock(&tv_root_lock); - /* value in seconds */ -#define THREAD_KILL_MAX_WAIT_TIME 60 - /* value in microseconds */ -#define WAIT_TIME 100 + double total_wait_time = 0; + /* value in seconds */ + #define THREAD_KILL_MAX_WAIT_TIME 60 + /* value in microseconds */ + #define WAIT_TIME 100 + +again: + SCMutexLock(&tv_root_lock); + + tv = tv_root[TVT_MGMT]; + while (tv != NULL) + { + if (strncasecmp(tv->name, thread_name_flow_mgr, + strlen(thread_name_flow_mgr)) == 0) + { + if (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + SCMutexUnlock(&tv_root_lock); - double total_wait_time = 0; - while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { usleep(WAIT_TIME); total_wait_time += WAIT_TIME / 1000000.0; if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { @@ -171,6 +182,7 @@ void FlowDisableFlowManagerThread(void) "Killing engine", tv->name); exit(EXIT_FAILURE); } + goto again; } } tv = tv->next; @@ -1038,10 +1050,8 @@ void FlowDisableFlowRecyclerThread(void) SCCtrlCondSignal(&flow_recycler_ctrl_cond); SCMutexLock(&tv_root_lock); - /* flow recycler thread(s) is/are a part of mgmt threads */ tv = tv_root[TVT_MGMT]; - while (tv != NULL) { if (strncasecmp(tv->name, thread_name_flow_rec, @@ -1049,22 +1059,36 @@ void FlowDisableFlowRecyclerThread(void) { TmThreadsSetFlag(tv, THV_KILL); cnt++; + } + tv = tv->next; + } + SCMutexUnlock(&tv_root_lock); - /* value in seconds */ + double total_wait_time = 0; + /* value in seconds */ #define THREAD_KILL_MAX_WAIT_TIME 60 - /* value in microseconds */ + /* value in microseconds */ #define WAIT_TIME 100 - double total_wait_time = 0; - while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { - usleep(WAIT_TIME); - total_wait_time += WAIT_TIME / 1000000.0; +again: + SCMutexLock(&tv_root_lock); + tv = tv_root[TVT_MGMT]; + while (tv != NULL) + { + if (strncasecmp(tv->name, thread_name_flow_rec, + strlen(thread_name_flow_rec)) == 0) + { + if (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { SCLogError(SC_ERR_FATAL, "Engine unable to " "disable detect thread - \"%s\". " "Killing engine", tv->name); exit(EXIT_FAILURE); } + SCMutexUnlock(&tv_root_lock); + usleep(WAIT_TIME); + total_wait_time += WAIT_TIME / 1000000.0; + goto again; } } tv = tv->next; diff --git a/src/tm-threads.c b/src/tm-threads.c index bc866aa215dc..b67f3d5c6ed4 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1660,6 +1660,8 @@ void TmThreadDisableReceiveThreads(void) /* wait for it to enter the 'flow loop' stage */ while (!TmThreadsCheckFlag(tv, THV_FLOW_LOOP)) { + SCMutexUnlock(&tv_root_lock); + usleep(WAIT_TIME); total_wait_time += WAIT_TIME / 1000000.0; if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { @@ -1668,6 +1670,7 @@ void TmThreadDisableReceiveThreads(void) "Killing engine", tv->name); exit(EXIT_FAILURE); } + goto again; } } @@ -1743,6 +1746,8 @@ void TmThreadDisablePacketThreads(void) } while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + SCMutexUnlock(&tv_root_lock); + usleep(WAIT_TIME); total_wait_time += WAIT_TIME / 1000000.0; if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { @@ -1751,6 +1756,7 @@ void TmThreadDisablePacketThreads(void) "Killing engine", tv->name); exit(EXIT_FAILURE); } + goto again; } tv = tv->next; @@ -2122,37 +2128,36 @@ TmEcode TmThreadWaitOnThreadInit(void) int i = 0; uint16_t mgt_num = 0; uint16_t ppt_num = 0; - +again: SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { - char started = FALSE; - while (started == FALSE) { - if (TmThreadsCheckFlag(tv, THV_INIT_DONE)) { - started = TRUE; - } else { - /* sleep a little to give the thread some - * time to finish initialization */ - usleep(100); - } + if (!(TmThreadsCheckFlag(tv, THV_INIT_DONE))) { + SCMutexUnlock(&tv_root_lock); + /* sleep a little to give the thread some + * time to finish initialization */ + usleep(100); + goto again; + } - if (TmThreadsCheckFlag(tv, THV_FAILED)) { - SCMutexUnlock(&tv_root_lock); - SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" failed to " - "initialize.", tv->name); - return TM_ECODE_FAILED; - } - if (TmThreadsCheckFlag(tv, THV_CLOSED)) { - SCMutexUnlock(&tv_root_lock); - SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" closed on " - "initialization.", tv->name); - return TM_ECODE_FAILED; - } + if (TmThreadsCheckFlag(tv, THV_FAILED)) { + SCMutexUnlock(&tv_root_lock); + SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" failed to " + "initialize.", tv->name); + return TM_ECODE_FAILED; + } + if (TmThreadsCheckFlag(tv, THV_CLOSED)) { + SCMutexUnlock(&tv_root_lock); + SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" closed on " + "initialization.", tv->name); + return TM_ECODE_FAILED; } - if (i == TVT_MGMT) mgt_num++; - else if (i == TVT_PPT) ppt_num++; + if (i == TVT_MGMT) + mgt_num++; + else if (i == TVT_PPT) + ppt_num++; tv = tv->next; } diff --git a/src/unix-manager.c b/src/unix-manager.c index 2e8cf5a94a31..702b63d46fdb 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -610,8 +610,8 @@ void UnixKillUnixManagerThread(void) ThreadVars *tv = NULL; int cnt = 0; +again: SCCtrlCondSignal(&unix_manager_ctrl_cond); - SCMutexLock(&tv_root_lock); /* flow manager thread(s) is/are a part of mgmt threads */ @@ -623,8 +623,10 @@ void UnixKillUnixManagerThread(void) TmThreadsSetFlag(tv, THV_DEINIT); /* be sure it has shut down */ - while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { + if(!(TmThreadsCheckFlag(tv, THV_CLOSED))) { + SCMutexUnlock(&tv_root_lock); usleep(100); + goto again; } cnt++; } @@ -1037,6 +1039,7 @@ void UnixSocketKillSocketThread(void) { ThreadVars *tv = NULL; +again: SCMutexLock(&tv_root_lock); /* unix manager thread(s) is/are a part of command threads */ @@ -1057,8 +1060,10 @@ void UnixSocketKillSocketThread(void) TmThreadsSetFlag(tv, THV_KILL); TmThreadsSetFlag(tv, THV_DEINIT); /* Be sure it has shut down */ - while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { + if (!TmThreadsCheckFlag(tv, THV_CLOSED)) { + SCMutexUnlock(&tv_root_lock); usleep(100); + goto again; } } tv = tv->next; From f74eff9eacbbe5b1d20369528123b8680fee92cd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 12 Jan 2017 10:19:27 +0100 Subject: [PATCH 2453/2553] threads: address sleep under lock issue --- src/threadvars.h | 1 + src/tm-threads.c | 73 +++++++++++++++++++++++++++++++++--------------- src/tm-threads.h | 1 - 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/threadvars.h b/src/threadvars.h index 80c61cfa0883..82de83bcd820 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -51,6 +51,7 @@ struct TmSlot_; * the engine. This is to force timely handling of maintenance taks like * rule reloads even if no packets are read by the capture method. */ #define THV_CAPTURE_INJECT_PKT (1<<11) +#define THV_DEAD (1 << 12) /**< thread has been joined with pthread_join() */ /** \brief Per thread variable structure */ typedef struct ThreadVars_ { diff --git a/src/tm-threads.c b/src/tm-threads.c index b67f3d5c6ed4..bede1e05a661 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1448,13 +1448,20 @@ void TmThreadRemove(ThreadVars *tv, int type) * * \param tv A ThreadVars instance corresponding to the thread that has to be * killed. + * + * \retval r 1 killed succesfully + * 0 not yet ready, needs another look */ -void TmThreadKillThread(ThreadVars *tv) +static int TmThreadKillThread(ThreadVars *tv) { int i = 0; - if (tv == NULL) - return; + BUG_ON(tv == NULL); + + /* kill only once :) */ + if (TmThreadsCheckFlag(tv, THV_DEAD)) { + return 1; + } if (tv->inq != NULL) { /* we wait till we dry out all the inq packets, before we @@ -1463,8 +1470,8 @@ void TmThreadKillThread(ThreadVars *tv) if (!(strlen(tv->inq->name) == strlen("packetpool") && strcasecmp(tv->inq->name, "packetpool") == 0)) { PacketQueue *q = &trans_q[tv->inq->id]; - while (q->len != 0) { - usleep(1000); + if (q->len != 0) { + return 0; } } } @@ -1475,15 +1482,7 @@ void TmThreadKillThread(ThreadVars *tv) TmThreadsSetFlag(tv, THV_DEINIT); /* to be sure, signal more */ - int cnt = 0; - while (1) { - if (TmThreadsCheckFlag(tv, THV_CLOSED)) { - SCLogDebug("signalled the thread %" PRId32 " times", cnt); - break; - } - - cnt++; - + if (!(TmThreadsCheckFlag(tv, THV_CLOSED))) { if (tv->InShutdownHandler != NULL) { tv->InShutdownHandler(tv); } @@ -1500,8 +1499,7 @@ void TmThreadKillThread(ThreadVars *tv) if (tv->ctrl_cond != NULL ) { pthread_cond_broadcast(tv->ctrl_cond); } - - usleep(100); + return 0; } if (tv->outctx != NULL) { @@ -1511,14 +1509,15 @@ void TmThreadKillThread(ThreadVars *tv) if (tmqh->OutHandlerCtxFree != NULL) { tmqh->OutHandlerCtxFree(tv->outctx); + tv->outctx = NULL; } } - /* join it */ + /* join it and flag it as dead */ pthread_join(tv->t, NULL); SCLogDebug("thread %s stopped", tv->name); - - return; + TmThreadsSetFlag(tv, THV_DEAD); + return 1; } /** \internal @@ -1798,18 +1797,27 @@ TmSlot *TmThreadGetFirstTmSlotForPartialPattern(const char *tm_name) return slots; } +#define MIN_WAIT_TIME 100 void TmThreadKillThreadsFamily(int family) { ThreadVars *tv = NULL; + unsigned int sleep = MIN_WAIT_TIME; - if ((family < 0) || (family >= TVT_MAX)) - return; + BUG_ON((family < 0) || (family >= TVT_MAX)); +again: SCMutexLock(&tv_root_lock); tv = tv_root[family]; while (tv) { - TmThreadKillThread(tv); + int r = TmThreadKillThread(tv); + if (r == 0) { + SCMutexUnlock(&tv_root_lock); + usleep(sleep); + sleep += MIN_WAIT_TIME; /* slowly back off */ + goto again; + } + sleep = MIN_WAIT_TIME; /* reset */ tv = tv->next; } @@ -2128,16 +2136,37 @@ TmEcode TmThreadWaitOnThreadInit(void) int i = 0; uint16_t mgt_num = 0; uint16_t ppt_num = 0; + + uint64_t slept = 0; + again: SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { + if (TmThreadsCheckFlag(tv, (THV_CLOSED|THV_DEAD))) { + SCMutexUnlock(&tv_root_lock); + + SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" failed to " + "initialize: flags %04x", tv->name, + SC_ATOMIC_GET(tv->flags)); + return TM_ECODE_FAILED; + } + if (!(TmThreadsCheckFlag(tv, THV_INIT_DONE))) { SCMutexUnlock(&tv_root_lock); + + if (slept > (120*1000000)) { + SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" failed to " + "initialize in time: flags %04x", tv->name, + SC_ATOMIC_GET(tv->flags)); + return TM_ECODE_FAILED; + } + /* sleep a little to give the thread some * time to finish initialization */ usleep(100); + slept += 100; goto again; } diff --git a/src/tm-threads.h b/src/tm-threads.h index 943b6236a9b8..ff6fd35fd8bb 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -95,7 +95,6 @@ ThreadVars *TmThreadCreateCmdThreadByName(const char *name, char *module, int mucond); TmEcode TmThreadSpawn(ThreadVars *); void TmThreadSetFlags(ThreadVars *, uint8_t); -void TmThreadKillThread(ThreadVars *); void TmThreadKillThreadsFamily(int family); void TmThreadKillThreads(void); void TmThreadClearThreadsFamily(int family); From 511e8049157bb8cc6f313b32da5cf98031437b1e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Feb 2017 15:27:09 +0100 Subject: [PATCH 2454/2553] detect: fix missing unlock in error path --- src/detect-engine.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index db5a9d4197e4..8c0031b8d66d 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2004,9 +2004,10 @@ int DetectRegisterThreadCtxGlobalFuncs(const char *name, } item = SCCalloc(1, sizeof(*item)); - if (unlikely(item == NULL)) + if (unlikely(item == NULL)) { + SCMutexUnlock(&master->lock); return -1; - + } item->InitFunc = InitFunc; item->FreeFunc = FreeFunc; item->name = name; From 2f30adb08aecdb0ad16f13cec2c2f80df58ea007 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Feb 2017 15:36:16 +0100 Subject: [PATCH 2455/2553] detect-lua: setup cleanup, fixing a potential int issue --- src/detect-lua.c | 61 ++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/src/detect-lua.c b/src/detect-lua.c index e08490c11df3..0c00edc8bf0d 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -990,70 +990,65 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) sm->type = DETECT_LUA; sm->ctx = (SigMatchCtx *)lua; + int list = -1; if (lua->alproto == ALPROTO_UNKNOWN) { if (lua->flags & DATATYPE_STREAM) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); + list = DETECT_SM_LIST_PMATCH; else - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); + list = DETECT_SM_LIST_MATCH; + } else if (lua->alproto == ALPROTO_HTTP) { if (lua->flags & DATATYPE_HTTP_RESPONSE_BODY) { - int list = DetectBufferTypeGetByName("file_data"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("file_data"); } else if (lua->flags & DATATYPE_HTTP_REQUEST_BODY) { - int list = DetectBufferTypeGetByName("http_client_body"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("http_client_body"); } else if (lua->flags & DATATYPE_HTTP_URI) { - int list = DetectBufferTypeGetByName("http_uri"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("http_uri"); } else if (lua->flags & DATATYPE_HTTP_URI_RAW) { - int list = DetectBufferTypeGetByName("http_raw_uri"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("http_raw_uri"); } else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE || lua->flags & DATATYPE_HTTP_RESPONSE_COOKIE) { - int list = DetectBufferTypeGetByName("http_cookie"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("http_cookie"); } else if (lua->flags & DATATYPE_HTTP_REQUEST_UA) { - int list = DetectBufferTypeGetByName("http_user_agent"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("http_user_agent"); } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) { - int list = DetectBufferTypeGetByName("http_header"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("http_header"); } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) { - int list = DetectBufferTypeGetByName("http_raw_header"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("http_raw_header"); } else { - int list = DetectBufferTypeGetByName("http_request_line"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("http_request_line"); } } else if (lua->alproto == ALPROTO_DNS) { if (lua->flags & DATATYPE_DNS_RRNAME) { - int list = DetectBufferTypeGetByName("dns_query"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("dns_query"); } else if (lua->flags & DATATYPE_DNS_REQUEST) { - int list = DetectBufferTypeGetByName("dns_request"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("dns_request"); } else if (lua->flags & DATATYPE_DNS_RESPONSE) { - int list = DetectBufferTypeGetByName("dns_response"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("dns_response"); } } else if (lua->alproto == ALPROTO_TLS) { - int list = DetectBufferTypeGetByName("tls_generic"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("tls_generic"); } else if (lua->alproto == ALPROTO_SSH) { - int list = DetectBufferTypeGetByName("ssh_banner"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("ssh_banner"); } else if (lua->alproto == ALPROTO_SMTP) { - SigMatchAppendSMToList(s, sm, g_smtp_generic_list_id); + list = g_smtp_generic_list_id; } else if (lua->alproto == ALPROTO_DNP3) { - int list = DetectBufferTypeGetByName("dnp3"); - SigMatchAppendSMToList(s, sm, list); + list = DetectBufferTypeGetByName("dnp3"); } else { SCLogError(SC_ERR_LUA_ERROR, "lua can't be used with protocol %s", AppLayerGetProtoName(lua->alproto)); goto error; } + if (list == -1) { + SCLogError(SC_ERR_LUA_ERROR, "lua can't be used with protocol %s", + AppLayerGetProtoName(lua->alproto)); + goto error; + } + + SigMatchAppendSMToList(s, sm, list); + return 0; error: From 955c22712708301f17d128889d7f8629037bb20b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Feb 2017 15:38:26 +0100 Subject: [PATCH 2456/2553] detect-ssh: cleanup duplicate code --- src/detect-ssh-proto.c | 9 ++------- src/detect-ssh-software.c | 9 ++------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/detect-ssh-proto.c b/src/detect-ssh-proto.c index 185b25b9b0d4..ac1757388cab 100644 --- a/src/detect-ssh-proto.c +++ b/src/detect-ssh-proto.c @@ -164,13 +164,8 @@ static int InspectEngineSshProtocol(ThreadVars *tv, return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } diff --git a/src/detect-ssh-software.c b/src/detect-ssh-software.c index 528daed4df20..bf2a7e187643 100644 --- a/src/detect-ssh-software.c +++ b/src/detect-ssh-software.c @@ -164,13 +164,8 @@ static int InspectEngineSshSoftware(ThreadVars *tv, return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } From c859d39f4f6948c6cc4282aeb0382b08adf53956 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Feb 2017 15:52:49 +0100 Subject: [PATCH 2457/2553] coverity: suppress CID 1400648 --- src/detect-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect-engine.c b/src/detect-engine.c index 8c0031b8d66d..0df068c52107 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1395,7 +1395,7 @@ static int DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx *det_ct SCMutexLock(&master->lock); if (master->keyword_id > 0) { - det_ctx->global_keyword_ctxs_array = SCCalloc(master->keyword_id, sizeof(void *)); + det_ctx->global_keyword_ctxs_array = (void **)SCCalloc(master->keyword_id, sizeof(void *)); if (det_ctx->global_keyword_ctxs_array == NULL) { SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx"); goto error; From 9da7be81f072bd5ec4e25682595bf7ebab38e9b9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 16 Feb 2017 16:41:06 +0100 Subject: [PATCH 2458/2553] flow-worker: clean up thread init --- src/flow-worker.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/flow-worker.c b/src/flow-worker.c index 84ac31c7be3c..ac0bd484ddac 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -80,35 +80,45 @@ static inline TmEcode FlowUpdate(Packet *p) } } +static TmEcode FlowWorkerThreadDeinit(ThreadVars *tv, void *data); + static TmEcode FlowWorkerThreadInit(ThreadVars *tv, void *initdata, void **data) { FlowWorkerThreadData *fw = SCCalloc(1, sizeof(*fw)); - BUG_ON(fw == NULL); + if (fw == NULL) + return TM_ECODE_FAILED; + SC_ATOMIC_INIT(fw->detect_thread); SC_ATOMIC_SET(fw->detect_thread, NULL); fw->dtv = DecodeThreadVarsAlloc(tv); if (fw->dtv == NULL) { - SC_ATOMIC_DESTROY(fw->detect_thread); - SCFree(fw); + FlowWorkerThreadDeinit(tv, fw); return TM_ECODE_FAILED; } /* setup TCP */ - BUG_ON(StreamTcpThreadInit(tv, NULL, &fw->stream_thread_ptr) != TM_ECODE_OK); + if (StreamTcpThreadInit(tv, NULL, &fw->stream_thread_ptr) != TM_ECODE_OK) { + FlowWorkerThreadDeinit(tv, fw); + return TM_ECODE_FAILED; + } if (DetectEngineEnabled()) { /* setup DETECT */ void *detect_thread = NULL; - BUG_ON(DetectEngineThreadCtxInit(tv, NULL, &detect_thread) != TM_ECODE_OK); + if (DetectEngineThreadCtxInit(tv, NULL, &detect_thread) != TM_ECODE_OK) { + FlowWorkerThreadDeinit(tv, fw); + return TM_ECODE_FAILED; + } SC_ATOMIC_SET(fw->detect_thread, detect_thread); } /* Setup outputs for this thread. */ if (OutputLoggerThreadInit(tv, initdata, &fw->output_thread) != TM_ECODE_OK) { + FlowWorkerThreadDeinit(tv, fw); return TM_ECODE_FAILED; } - + AppLayerRegisterThreadCounters(tv); /* setup pq for stream end pkts */ @@ -142,6 +152,7 @@ static TmEcode FlowWorkerThreadDeinit(ThreadVars *tv, void *data) BUG_ON(fw->pq.len); SCMutexDestroy(&fw->pq.mutex_q); + SC_ATOMIC_DESTROY(fw->detect_thread); SCFree(fw); return TM_ECODE_OK; } From d445b4b5fa5b00382138804eb86fe262d61a0eee Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Feb 2017 12:50:30 +0100 Subject: [PATCH 2459/2553] dce: remove commented out code --- src/detect-engine-dcepayload.c | 6429 -------------------------------- 1 file changed, 6429 deletions(-) diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index 0ed15ec5f623..a680b1e74d62 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -51,6422 +51,11 @@ static int g_dce_stub_data_buffer_id = 0; -#if 0 -/** - * \brief Do the content inspection & validation for a signature against dce stub. - * - * \param de_ctx Detection engine context. - * \param det_ctx Detection engine thread context. - * \param s Signature to inspect. - * \param sm SigMatch to inspect. - * \param f Flow. - * \param flags App layer flags. - * \param state App layer state. - * - * \retval 0 No match. - * \retval 1 Match. - */ -int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, - Flow *f, uint8_t flags, void *alstate) -{ - SCEnter(); - DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, alstate); - uint8_t *dce_stub_data = NULL; - uint16_t dce_stub_data_len; - int r = 0; - - if (s->sm_arrays[g_dce_stub_data_buffer_id] == NULL || dcerpc_state == NULL) { - SCReturnInt(0); - } - - if (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && - dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh != 0) { - /* the request stub and stub_len */ - dce_stub_data = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer; - dce_stub_data_len = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len; - - det_ctx->buffer_offset = 0; - det_ctx->discontinue_matching = 0; - det_ctx->inspection_recursion_counter = 0; - - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[g_dce_stub_data_buffer_id], - f, - dce_stub_data, - dce_stub_data_len, - 0, - 0, dcerpc_state); - //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->init_data->smlists[g_dce_stub_data_buffer_id], f, - //dce_stub_data, dce_stub_data_len, dcerpc_state); - if (r == 1) { - SCReturnInt(1); - } - } - - if (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer != NULL && - dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) { - /* the response stub and stub_len */ - dce_stub_data = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer; - dce_stub_data_len = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer_len; - - det_ctx->buffer_offset = 0; - det_ctx->discontinue_matching = 0; - det_ctx->inspection_recursion_counter = 0; - - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[g_dce_stub_data_buffer_id], - f, - dce_stub_data, - dce_stub_data_len, - 0, - 0, dcerpc_state); - //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->init_data->smlists[g_dce_stub_data_buffer_id], f, - //dce_stub_data, dce_stub_data_len, dcerpc_state); - if (r == 1) { - SCReturnInt(1); - } - } - - SCReturnInt(0); -} -#endif /**************************************Unittests*******************************/ #ifdef UNITTESTS -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -static int DcePayloadTest01(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - uint8_t request3[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x26, 0x65, 0x3c, 0x6e, 0x6d, 0x64, 0x24, 0x39, - 0x56, 0x43, 0x3e, 0x61, 0x5c, 0x54, 0x42, 0x23, - 0x75, 0x6b, 0x71, 0x27, 0x66, 0x2e, 0x6e, 0x3d, - 0x58, 0x23, 0x54, 0x77, 0x3b, 0x52, 0x6b, 0x50, - 0x3b, 0x74, 0x2c, 0x54, 0x25, 0x5c, 0x51, 0x7c, - 0x29, 0x7c, 0x5f, 0x4a, 0x35, 0x5c, 0x3d, 0x3f, - 0x33, 0x55, 0x3b, 0x5a, 0x57, 0x31, 0x59, 0x4f, - 0x6d, 0x6d, 0x7b, 0x3e, 0x38, 0x4d, 0x68, 0x75, - 0x64, 0x21, 0x50, 0x63, 0x47, 0x42, 0x56, 0x39, - 0x6c, 0x6f, 0x61, 0x53, 0x32, 0x56, 0x43, 0x52, - 0x43, 0x67, 0x26, 0x45, 0x28, 0x6b, 0x77, 0x28, - 0x7c, 0x64, 0x61, 0x24, 0x38, 0x6b, 0x59, 0x2a, - 0x4f, 0x6e, 0x5b, 0x57, 0x24, 0x54, 0x33, 0x37, - 0x47, 0x58, 0x4b, 0x58, 0x3d, 0x21, 0x38, 0x7c, - 0x2c, 0x24, 0x5f, 0x67, 0x3a, 0x41, 0x3e, 0x2a, - 0x72, 0x66, 0x2d, 0x6b, 0x66, 0x7b, 0x2b, 0x75, - 0x78, 0x2f, 0x4d, 0x4c, 0x51, 0x70, 0x5d, 0x55, - 0x54, 0x3c, 0x63, 0x46, 0x6b, 0x64, 0x4d, 0x25, - 0x45, 0x21, 0x34, 0x65, 0x48, 0x32, 0x58, 0x4c, - 0x70, 0x4c, 0x4c, 0x75, 0x5c, 0x77, 0x68, 0x78, - 0x34, 0x5c, 0x2d, 0x39, 0x58, 0x3b, 0x40, 0x71, - 0x77, 0x47, 0x32, 0x2e, 0x3c, 0x61, 0x6f, 0x6d, - 0x5f, 0x43, 0x74, 0x36, 0x4f, 0x21, 0x44, 0x66, - 0x36, 0x62, 0x30, 0x29, 0x5a, 0x34, 0x66, 0x4e, - 0x51, 0x23, 0x4e, 0x38, 0x51, 0x78, 0x74, 0x58, - 0x2e, 0x6d, 0x51, 0x49, 0x55, 0x73, 0x2a, 0x71, - 0x3c, 0x74, 0x38, 0x6f, 0x5d, 0x4b, 0x74, 0x68, - 0x65, 0x4a, 0x58, 0x41, 0x55, 0x29, 0x42, 0x69, - 0x55, 0x3b, 0x2b, 0x47, 0x64, 0x3b, 0x77, 0x72, - 0x74, 0x38, 0x53, 0x5c, 0x69, 0x49, 0x49, 0x5b, - 0x31, 0x41, 0x6a, 0x4e, 0x2c, 0x6a, 0x63, 0x3f, - 0x58, 0x4e, 0x25, 0x3e, 0x57, 0x41, 0x61, 0x26, - 0x5e, 0x24, 0x69, 0x7a, 0x38, 0x60, 0x73, 0x70, - 0x7d, 0x63, 0x34, 0x78, 0x4d, 0x50, 0x35, 0x69, - 0x49, 0x22, 0x45, 0x44, 0x3f, 0x6e, 0x75, 0x64, - 0x57, 0x3a, 0x61, 0x60, 0x34, 0x21, 0x61, 0x21, - 0x2a, 0x78, 0x7b, 0x52, 0x43, 0x50, 0x5b, 0x76, - 0x5f, 0x4b, 0x6a, 0x5d, 0x23, 0x5b, 0x57, 0x40, - 0x53, 0x51, 0x33, 0x21, 0x35, 0x7d, 0x31, 0x46, - 0x65, 0x52, 0x28, 0x25, 0x30, 0x5a, 0x37, 0x7c, - 0x2c, 0x3d, 0x2a, 0x48, 0x24, 0x5a, 0x2f, 0x47, - 0x64, 0x73, 0x64, 0x3d, 0x7a, 0x5b, 0x34, 0x5e, - 0x42, 0x22, 0x32, 0x47, 0x6e, 0x58, 0x3b, 0x3e, - 0x25, 0x2f, 0x58, 0x78, 0x42, 0x66, 0x71, 0x56, - 0x2a, 0x66, 0x66, 0x5b, 0x55, 0x35, 0x7a, 0x41, - 0x7c, 0x7c, 0x6a, 0x2d, 0x59, 0x25, 0x22, 0x34, - 0x5a, 0x61, 0x37, 0x48, 0x39, 0x31, 0x4a, 0x55, - 0x6a, 0x68, 0x40, 0x2f, 0x45, 0x69, 0x46, 0x25, - 0x51, 0x7d, 0x4f, 0x71, 0x21, 0x33, 0x55, 0x50, - 0x56, 0x5f, 0x75, 0x27, 0x64, 0x36, 0x7a, 0x39, - 0x40, 0x6a, 0x77, 0x38, 0x5d, 0x39, 0x30, 0x5e, - 0x74, 0x54, 0x24, 0x3f, 0x3d, 0x79, 0x3b, 0x27, - 0x7d, 0x68, 0x7d, 0x40, 0x71, 0x7a, 0x65, 0x54, - 0x50, 0x66, 0x33, 0x3c, 0x42, 0x69, 0x6e, 0x3c, - 0x63, 0x63, 0x69, 0x7a, 0x5e, 0x7b, 0x76, 0x26, - 0x71, 0x6f, 0x4a, 0x6d, 0x70, 0x73, 0x66, 0x3b, - 0x26, 0x70, 0x43, 0x5b, 0x52, 0x4c, 0x6d, 0x51, - 0x2a, 0x66, 0x6c, 0x3e, 0x68, 0x6a, 0x31, 0x41, - 0x79, 0x72, 0x37, 0x47, 0x7d, 0x2b, 0x3c, 0x40, - 0x6b, 0x75, 0x56, 0x70, 0x7b, 0x2d, 0x5f, 0x33, - 0x30, 0x30, 0x21, 0x35, 0x7a, 0x7a, 0x67, 0x48, - 0x5e, 0x3b, 0x73, 0x50, 0x54, 0x47, 0x23, 0x2b, - 0x4c, 0x4e, 0x2f, 0x24, 0x44, 0x34, 0x23, 0x5d, - 0x76, 0x51, 0x5a, 0x73, 0x72, 0x3e, 0x47, 0x77, - 0x40, 0x28, 0x65, 0x2e, 0x2a, 0x75, 0x3c, 0x2a, - 0x27, 0x4a, 0x3f, 0x3c, 0x66, 0x2d, 0x21, 0x79, - 0x2d, 0x2b, 0x78, 0x7c, 0x5a, 0x73, 0x46, 0x6b, - 0x39, 0x65, 0x5e, 0x3d, 0x38, 0x40, 0x32, 0x3e, - 0x21, 0x62, 0x34, 0x41, 0x58, 0x53, 0x67, 0x34, - 0x58, 0x56, 0x61, 0x5b, 0x3e, 0x4e, 0x2c, 0x5b, - 0x73, 0x35, 0x34, 0x35, 0x21, 0x3a, 0x61, 0x5f, - 0x6e, 0x45, 0x78, 0x44, 0x28, 0x23, 0x48, 0x65, - 0x53, 0x47, 0x6e, 0x2c, 0x38, 0x5e, 0x2c, 0x57, - 0x58, 0x30, 0x7a, 0x3b, 0x4b, 0x4a, 0x74, 0x7d, - 0x3e, 0x4d, 0x30, 0x24, 0x76, 0x66, 0x6d, 0x2e, - 0x74, 0x75, 0x28, 0x48, 0x5c, 0x23, 0x6c, 0x46, - 0x27, 0x46, 0x6e, 0x34, 0x63, 0x21, 0x58, 0x54, - 0x50, 0x2f, 0x40, 0x47, 0x40, 0x32, 0x36, 0x48, - 0x5f, 0x7d, 0x4a, 0x41, 0x6e, 0x60, 0x2c, 0x4a, - 0x6a, 0x67, 0x6c, 0x41, 0x27, 0x23, 0x30, 0x48, - 0x6a, 0x49, 0x73, 0x26, 0x77, 0x75, 0x4d, 0x65, - 0x5b, 0x34, 0x79, 0x67, 0x61, 0x5b, 0x5c, 0x2b, - 0x71, 0x3f, 0x62, 0x51, 0x3a, 0x53, 0x42, 0x26, - 0x6f, 0x36, 0x57, 0x3f, 0x2b, 0x34, 0x24, 0x30, - 0x60, 0x55, 0x70, 0x65, 0x70, 0x57, 0x5d, 0x68, - 0x36, 0x52, 0x5d, 0x3f, 0x6a, 0x3a, 0x33, 0x31, - 0x6c, 0x4e, 0x57, 0x79, 0x49, 0x79, 0x69, 0x71, - 0x6f, 0x70, 0x6a, 0x76, 0x4b, 0x2f, 0x33, 0x51, - 0x68, 0x30, 0x2e, 0x77, 0x78, 0x55, 0x2f, 0x53, - 0x52, 0x5e, 0x57, 0x60, 0x3b, 0x6f, 0x69, 0x61, - 0x6c, 0x60, 0x5a, 0x34, 0x5a, 0x35, 0x4b, 0x28, - 0x54, 0x32, 0x6a, 0x35, 0x36, 0x6d, 0x68, 0x47, - 0x5c, 0x74, 0x2e, 0x5f, 0x6c, 0x6d, 0x55, 0x42, - 0x77, 0x64, 0x7d, 0x53, 0x4d, 0x39, 0x2c, 0x41, - 0x42, 0x23, 0x3a, 0x73, 0x40, 0x60, 0x5d, 0x38, - 0x6d, 0x36, 0x56, 0x57, 0x2a, 0x28, 0x3d, 0x3b, - 0x5c, 0x75, 0x35, 0x2d, 0x69, 0x2d, 0x44, 0x51, - 0x27, 0x63, 0x66, 0x33, 0x46, 0x42, 0x2e, 0x36, - 0x6b, 0x7b, 0x2c, 0x23, 0x3b, 0x5a, 0x50, 0x2a, - 0x65, 0x28, 0x3b, 0x3c, 0x51, 0x3f, 0x4d, 0x63, - 0x38, 0x25, 0x74, 0x2e, 0x51, 0x22, 0x31, 0x74, - 0x35, 0x33, 0x23, 0x2d, 0x3f, 0x77, 0x26, 0x2c, - 0x55, 0x6d, 0x27, 0x39, 0x79, 0x76, 0x63, 0x4b, - 0x43, 0x4a, 0x3a, 0x6b, 0x59, 0x55, 0x65, 0x26, - 0x2f, 0x3f, 0x56, 0x67, 0x5a, 0x77, 0x71, 0x22, - 0x51, 0x2b, 0x6d, 0x4c, 0x2c, 0x57, 0x66, 0x76, - 0x37, 0x70, 0x5f, 0x52, 0x29, 0x44, 0x52, 0x22, - 0x57, 0x37, 0x27, 0x79, 0x29, 0x5c, 0x57, 0x3b, - 0x54, 0x3c, 0x3f, 0x53, 0x35, 0x27, 0x5e, 0x7c, - 0x49, 0x77, 0x57, 0x5a, 0x22, 0x76, 0x7c, 0x5b, - 0x2f, 0x53, 0x5e, 0x55, 0x6d, 0x64, 0x67, 0x34, - 0x41, 0x23, 0x76, 0x67, 0x23, 0x78, 0x6a, 0x63, - 0x27, 0x68, 0x43, 0x7d, 0x58, 0x49, 0x2d, 0x79, - 0x2e, 0x75, 0x60, 0x6b, 0x34, 0x48, 0x6f, 0x4a, - 0x6c, 0x48, 0x40, 0x68, 0x5f, 0x35, 0x25, 0x6c, - 0x38, 0x5c, 0x30, 0x32, 0x4c, 0x36, 0x31, 0x29, - 0x74, 0x4a, 0x55, 0x56, 0x6d, 0x4e, 0x23, 0x54, - 0x2e, 0x69, 0x78, 0x61, 0x76, 0x66, 0x22, 0x44, - 0x73, 0x25, 0x44, 0x29, 0x2a, 0x28, 0x3b, 0x67, - 0x48, 0x58, 0x37, 0x4a, 0x76, 0x76, 0x51, 0x4a, - 0x61, 0x70, 0x51, 0x74, 0x40, 0x23, 0x29, 0x63, - 0x69, 0x4a, 0x29, 0x23, 0x34, 0x6a, 0x3b, 0x25, - 0x28, 0x54, 0x45, 0x33, 0x28, 0x44, 0x30, 0x61, - 0x5b, 0x60, 0x51, 0x3f, 0x68, 0x50, 0x70, 0x3d, - 0x58, 0x2e, 0x6e, 0x59, 0x5a, 0x62, 0x66, 0x4d, - 0x7a, 0x2e, 0x37, 0x37, 0x3d, 0x7b, 0x74, 0x79, - 0x48, 0x45, 0x77, 0x56, 0x33, 0x76, 0x71, 0x60, - 0x74, 0x3f, 0x61, 0x22, 0x52, 0x51, 0x71, 0x69 - }; - uint32_t request3_len = sizeof(request3); - - uint8_t request4[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x75, 0x3e, 0x76, 0x3e, 0x66, 0x6b, 0x6b, 0x3e, - 0x6d, 0x59, 0x38, 0x2b, 0x63, 0x4d, 0x2c, 0x73, - 0x54, 0x57, 0x34, 0x25, 0x5b, 0x42, 0x7d, 0x5d, - 0x37, 0x34, 0x2c, 0x79, 0x24, 0x4b, 0x74, 0x73, - 0x25, 0x36, 0x73, 0x3a, 0x2c, 0x55, 0x69, 0x3c, - 0x58, 0x67, 0x33, 0x53, 0x67, 0x5c, 0x61, 0x7b, - 0x44, 0x2e, 0x42, 0x2d, 0x6b, 0x50, 0x55, 0x24, - 0x70, 0x58, 0x60, 0x38, 0x42, 0x45, 0x70, 0x6d, - 0x2f, 0x27, 0x27, 0x2c, 0x21, 0x6d, 0x57, 0x6e, - 0x43, 0x3c, 0x5b, 0x27, 0x7a, 0x34, 0x49, 0x5a, - 0x69, 0x30, 0x3f, 0x6f, 0x77, 0x70, 0x39, 0x2d, - 0x51, 0x74, 0x4b, 0x25, 0x70, 0x51, 0x64, 0x4d, - 0x75, 0x52, 0x5e, 0x3e, 0x37, 0x30, 0x5d, 0x3b, - 0x2c, 0x72, 0x25, 0x6c, 0x6f, 0x79, 0x69, 0x3c, - 0x5b, 0x73, 0x3d, 0x41, 0x28, 0x28, 0x64, 0x60, - 0x4b, 0x7a, 0x2c, 0x4a, 0x6b, 0x3d, 0x2e, 0x6c, - 0x7a, 0x54, 0x70, 0x61, 0x6f, 0x4b, 0x40, 0x28, - 0x59, 0x31, 0x25, 0x21, 0x57, 0x79, 0x4b, 0x31, - 0x6f, 0x4e, 0x71, 0x2b, 0x3c, 0x24, 0x30, 0x28, - 0x3c, 0x61, 0x28, 0x4b, 0x35, 0x61, 0x4d, 0x55, - 0x5e, 0x66, 0x34, 0x5f, 0x61, 0x70, 0x7b, 0x67, - 0x51, 0x55, 0x68, 0x78, 0x26, 0x3a, 0x27, 0x4e, - 0x71, 0x79, 0x4f, 0x67, 0x2c, 0x5a, 0x79, 0x75, - 0x59, 0x3a, 0x33, 0x4a, 0x36, 0x71, 0x72, 0x6d, - 0x49, 0x3e, 0x53, 0x59, 0x2b, 0x2b, 0x27, 0x4e, - 0x50, 0x5d, 0x21, 0x55, 0x64, 0x4b, 0x72, 0x73, - 0x25, 0x55, 0x26, 0x4f, 0x3a, 0x21, 0x54, 0x29, - 0x4f, 0x64, 0x51, 0x59, 0x60, 0x7b, 0x7c, 0x6f, - 0x3e, 0x65, 0x74, 0x6a, 0x5b, 0x52, 0x2c, 0x56, - 0x4e, 0x45, 0x53, 0x4b, 0x7c, 0x38, 0x49, 0x4b, - 0x4e, 0x4f, 0x4a, 0x47, 0x5e, 0x7c, 0x46, 0x3b, - 0x67, 0x2e, 0x43, 0x79, 0x35, 0x55, 0x59, 0x6d, - 0x38, 0x70, 0x2f, 0x59, 0x4f, 0x27, 0x63, 0x40, - 0x66, 0x2d, 0x39, 0x4f, 0x3d, 0x2e, 0x4c, 0x67, - 0x71, 0x7d, 0x34, 0x22, 0x52, 0x4e, 0x36, 0x7b, - 0x2c, 0x39, 0x4d, 0x42, 0x60, 0x75, 0x74, 0x72, - 0x4f, 0x72, 0x68, 0x3a, 0x51, 0x31, 0x2d, 0x21, - 0x4a, 0x35, 0x47, 0x6d, 0x69, 0x3c, 0x50, 0x4c, - 0x59, 0x66, 0x4c, 0x71, 0x24, 0x3a, 0x36, 0x67, - 0x24, 0x5a, 0x59, 0x28, 0x7c, 0x21, 0x5e, 0x77, - 0x68, 0x5e, 0x7b, 0x6e, 0x56, 0x62, 0x36, 0x29, - 0x6f, 0x4f, 0x5d, 0x57, 0x56, 0x2b, 0x75, 0x2a, - 0x2c, 0x69, 0x63, 0x51, 0x74, 0x6e, 0x5e, 0x46, - 0x50, 0x28, 0x2c, 0x3b, 0x32, 0x53, 0x28, 0x78, - 0x59, 0x72, 0x39, 0x5e, 0x44, 0x5c, 0x77, 0x60, - 0x72, 0x44, 0x3b, 0x75, 0x68, 0x39, 0x55, 0x3e, - 0x44, 0x50, 0x76, 0x3c, 0x48, 0x46, 0x43, 0x22, - 0x56, 0x27, 0x21, 0x31, 0x33, 0x4a, 0x5a, 0x74, - 0x41, 0x58, 0x3f, 0x39, 0x29, 0x71, 0x73, 0x30, - 0x57, 0x70, 0x33, 0x62, 0x7b, 0x4a, 0x75, 0x3e, - 0x4d, 0x4c, 0x4e, 0x55, 0x63, 0x38, 0x66, 0x7d, - 0x68, 0x7d, 0x6f, 0x23, 0x55, 0x50, 0x3d, 0x34, - 0x46, 0x5e, 0x2f, 0x55, 0x27, 0x62, 0x68, 0x7c, - 0x6c, 0x21, 0x2b, 0x63, 0x4b, 0x47, 0x6b, 0x6a, - 0x5b, 0x7b, 0x5c, 0x71, 0x37, 0x7c, 0x52, 0x2b, - 0x2f, 0x4a, 0x47, 0x70, 0x78, 0x50, 0x2f, 0x75, - 0x28, 0x4c, 0x60, 0x4c, 0x4c, 0x54, 0x6b, 0x68, - 0x63, 0x4f, 0x47, 0x39, 0x2a, 0x70, 0x51, 0x7d, - 0x28, 0x59, 0x52, 0x46, 0x4b, 0x38, 0x27, 0x49, - 0x50, 0x5d, 0x25, 0x22, 0x5f, 0x48, 0x2c, 0x2f, - 0x67, 0x59, 0x5d, 0x7d, 0x21, 0x3d, 0x72, 0x4f, - 0x5c, 0x5b, 0x41, 0x47, 0x5f, 0x56, 0x69, 0x42, - 0x55, 0x60, 0x68, 0x4b, 0x77, 0x44, 0x4c, 0x3b, - 0x7d, 0x5a, 0x58, 0x43, 0x7a, 0x33, 0x22, 0x58, - 0x58, 0x6f, 0x74, 0x53, 0x57, 0x6d, 0x6e, 0x29, - 0x6b, 0x33, 0x71, 0x68, 0x29, 0x48, 0x67, 0x35, - 0x52, 0x41, 0x6b, 0x36, 0x4f, 0x46, 0x31, 0x24, - 0x73, 0x56, 0x40, 0x48, 0x37, 0x51, 0x24, 0x2a, - 0x59, 0x21, 0x74, 0x76, 0x25, 0x2e, 0x4a, 0x74, - 0x32, 0x29, 0x5f, 0x57, 0x7c, 0x58, 0x30, 0x2c, - 0x7b, 0x70, 0x5b, 0x51, 0x73, 0x27, 0x4a, 0x28, - 0x77, 0x2a, 0x43, 0x28, 0x2e, 0x32, 0x3d, 0x38, - 0x36, 0x2e, 0x6b, 0x40, 0x6c, 0x76, 0x54, 0x66, - 0x4a, 0x5c, 0x25, 0x62, 0x2e, 0x61, 0x48, 0x30, - 0x28, 0x41, 0x40, 0x69, 0x3c, 0x39, 0x36, 0x4b, - 0x64, 0x50, 0x76, 0x3d, 0x52, 0x50, 0x77, 0x33, - 0x3b, 0x65, 0x59, 0x31, 0x5c, 0x48, 0x6a, 0x74, - 0x78, 0x5b, 0x74, 0x60, 0x47, 0x27, 0x60, 0x22, - 0x4a, 0x72, 0x25, 0x34, 0x5d, 0x3a, 0x21, 0x66, - 0x61, 0x7b, 0x34, 0x41, 0x3b, 0x3a, 0x27, 0x44, - 0x48, 0x7c, 0x7a, 0x74, 0x3a, 0x68, 0x59, 0x48, - 0x61, 0x32, 0x49, 0x61, 0x40, 0x22, 0x33, 0x75, - 0x29, 0x76, 0x5b, 0x24, 0x5b, 0x5c, 0x76, 0x5c, - 0x28, 0x75, 0x36, 0x26, 0x2c, 0x65, 0x5e, 0x51, - 0x7b, 0x3a, 0x7d, 0x4f, 0x35, 0x73, 0x6b, 0x5b, - 0x5c, 0x37, 0x35, 0x6b, 0x41, 0x35, 0x40, 0x3a, - 0x22, 0x28, 0x6c, 0x71, 0x46, 0x68, 0x7b, 0x66, - 0x56, 0x24, 0x7c, 0x54, 0x28, 0x30, 0x22, 0x4e, - 0x3c, 0x65, 0x69, 0x36, 0x44, 0x53, 0x3d, 0x6c, - 0x5f, 0x73, 0x6c, 0x6f, 0x5e, 0x27, 0x23, 0x4e, - 0x60, 0x45, 0x2f, 0x3d, 0x37, 0x28, 0x51, 0x29, - 0x77, 0x6a, 0x6b, 0x2a, 0x2a, 0x51, 0x26, 0x4c, - 0x4e, 0x71, 0x77, 0x73, 0x71, 0x2d, 0x5a, 0x2c, - 0x23, 0x3d, 0x5f, 0x62, 0x63, 0x2e, 0x72, 0x2a, - 0x75, 0x66, 0x43, 0x56, 0x5f, 0x21, 0x64, 0x66, - 0x35, 0x3b, 0x7a, 0x45, 0x3f, 0x4f, 0x57, 0x22, - 0x5a, 0x45, 0x65, 0x37, 0x58, 0x5b, 0x43, 0x66, - 0x4f, 0x5d, 0x6e, 0x41, 0x41, 0x62, 0x5e, 0x39, - 0x65, 0x6f, 0x43, 0x4b, 0x5e, 0x51, 0x42, 0x3f, - 0x2d, 0x68, 0x4b, 0x6e, 0x46, 0x6f, 0x21, 0x44, - 0x3c, 0x22, 0x46, 0x31, 0x31, 0x2e, 0x56, 0x2e, - 0x77, 0x48, 0x68, 0x23, 0x4a, 0x36, 0x52, 0x5d, - 0x61, 0x47, 0x71, 0x2e, 0x3a, 0x4a, 0x5b, 0x56, - 0x6b, 0x52, 0x2a, 0x4c, 0x4f, 0x24, 0x34, 0x60, - 0x70, 0x58, 0x7a, 0x76, 0x4b, 0x68, 0x24, 0x5f, - 0x51, 0x6d, 0x75, 0x45, 0x48, 0x21, 0x53, 0x4d, - 0x27, 0x75, 0x5f, 0x50, 0x3e, 0x40, 0x3f, 0x5e, - 0x64, 0x41, 0x5f, 0x68, 0x48, 0x30, 0x71, 0x4b, - 0x66, 0x2c, 0x2f, 0x76, 0x4b, 0x23, 0x46, 0x34, - 0x50, 0x58, 0x52, 0x69, 0x2b, 0x6e, 0x7a, 0x33, - 0x53, 0x43, 0x43, 0x35, 0x54, 0x30, 0x73, 0x63, - 0x3b, 0x43, 0x52, 0x29, 0x45, 0x37, 0x71, 0x79, - 0x5a, 0x26, 0x24, 0x72, 0x73, 0x4e, 0x44, 0x38, - 0x5b, 0x71, 0x36, 0x3a, 0x4f, 0x5b, 0x71, 0x28, - 0x71, 0x79, 0x72, 0x40, 0x6e, 0x51, 0x72, 0x29, - 0x3d, 0x4f, 0x33, 0x22, 0x73, 0x5a, 0x30, 0x71, - 0x58, 0x54, 0x59, 0x48, 0x29, 0x2b, 0x5c, 0x73, - 0x6f, 0x4e, 0x60, 0x2a, 0x72, 0x39, 0x50, 0x59, - 0x6f, 0x48, 0x3e, 0x62, 0x6c, 0x62, 0x49, 0x6c, - 0x2c, 0x3f, 0x43, 0x3f, 0x32, 0x7c, 0x6f, 0x6c, - 0x39, 0x26, 0x26, 0x7b, 0x5d, 0x65, 0x6f, 0x41, - 0x7c, 0x42, 0x2b, 0x65, 0x6f, 0x3e, 0x7b, 0x69, - 0x46, 0x4d, 0x68, 0x68, 0x5a, 0x33, 0x25, 0x5d, - 0x6f, 0x48, 0x7c, 0x77, 0x7d, 0x3f, 0x4e, 0x30, - 0x69, 0x65, 0x28, 0x2e, 0x34, 0x34, 0x41, 0x43, - 0x5e, 0x30, 0x23, 0x3b, 0x60, 0x79, 0x5b, 0x26, - 0x7c, 0x77, 0x3e, 0x43, 0x24, 0x31, 0x3a, 0x56, - 0x24, 0x3c, 0x60, 0x3f, 0x60, 0x55, 0x6a, 0x68 - }; - uint32_t request4_len = sizeof(request4); - - uint8_t request5[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x69, 0x3e, 0x72, 0x44, 0x31, 0x6b, 0x28, 0x2f, - 0x79, 0x37, 0x58, 0x5d, 0x5f, 0x68, 0x71, 0x47, - 0x7a, 0x68, 0x7c, 0x6c, 0x65, 0x3c, 0x74, 0x67, - 0x59, 0x5c, 0x3d, 0x28, 0x65, 0x28, 0x58, 0x74, - 0x44, 0x62, 0x2e, 0x36, 0x54, 0x2f, 0x24, 0x34, - 0x4b, 0x6d, 0x3a, 0x7b, 0x60, 0x71, 0x5a, 0x77, - 0x4a, 0x27, 0x25, 0x70, 0x75, 0x56, 0x78, 0x73, - 0x2e, 0x38, 0x6c, 0x70, 0x66, 0x7b, 0x7b, 0x2d, - 0x78, 0x27, 0x65, 0x63, 0x58, 0x4f, 0x7d, 0x5c, - 0x31, 0x3e, 0x36, 0x6e, 0x65, 0x61, 0x2e, 0x4e, - 0x26, 0x68, 0x2b, 0x33, 0x7d, 0x54, 0x2c, 0x28, - 0x47, 0x3a, 0x31, 0x47, 0x56, 0x32, 0x74, 0x51, - 0x79, 0x65, 0x42, 0x45, 0x60, 0x55, 0x6f, 0x48, - 0x61, 0x23, 0x72, 0x62, 0x74, 0x3a, 0x5a, 0x26, - 0x2d, 0x41, 0x58, 0x62, 0x75, 0x4b, 0x37, 0x2e, - 0x3f, 0x2a, 0x6e, 0x2e, 0x2c, 0x43, 0x6f, 0x53, - 0x5f, 0x48, 0x7a, 0x53, 0x7b, 0x54, 0x28, 0x30, - 0x2b, 0x7a, 0x34, 0x33, 0x28, 0x2b, 0x23, 0x23, - 0x72, 0x38, 0x25, 0x30, 0x35, 0x66, 0x76, 0x46, - 0x2a, 0x57, 0x7a, 0x60, 0x38, 0x5a, 0x26, 0x4f, - 0x78, 0x43, 0x2c, 0x7d, 0x3d, 0x76, 0x7d, 0x66, - 0x48, 0x7d, 0x3e, 0x59, 0x31, 0x58, 0x6b, 0x30, - 0x76, 0x45, 0x6e, 0x70, 0x72, 0x5f, 0x3c, 0x70, - 0x6d, 0x77, 0x42, 0x75, 0x42, 0x73, 0x68, 0x5e, - 0x5f, 0x72, 0x2b, 0x2a, 0x70, 0x38, 0x7a, 0x4c, - 0x58, 0x2e, 0x5e, 0x2d, 0x2d, 0x78, 0x67, 0x5a, - 0x77, 0x34, 0x5a, 0x50, 0x76, 0x2d, 0x2b, 0x77, - 0x37, 0x6e, 0x38, 0x2d, 0x7b, 0x44, 0x78, 0x67, - 0x52, 0x57, 0x79, 0x43, 0x7d, 0x6d, 0x4d, 0x32, - 0x23, 0x37, 0x51, 0x4b, 0x41, 0x60, 0x6e, 0x53, - 0x4e, 0x78, 0x37, 0x37, 0x60, 0x56, 0x64, 0x52, - 0x25, 0x46, 0x53, 0x5f, 0x2b, 0x56, 0x2b, 0x3b, - 0x40, 0x37, 0x33, 0x37, 0x23, 0x43, 0x36, 0x6b, - 0x6b, 0x5d, 0x35, 0x28, 0x7d, 0x6a, 0x2c, 0x68, - 0x28, 0x4b, 0x4a, 0x6c, 0x27, 0x35, 0x51, 0x66, - 0x30, 0x39, 0x28, 0x4d, 0x61, 0x2f, 0x64, 0x36, - 0x59, 0x39, 0x68, 0x4b, 0x24, 0x51, 0x7b, 0x6e, - 0x38, 0x49, 0x55, 0x72, 0x5f, 0x33, 0x5c, 0x26, - 0x45, 0x2f, 0x71, 0x66, 0x33, 0x3d, 0x36, 0x68, - 0x65, 0x48, 0x42, 0x40, 0x58, 0x61, 0x4f, 0x50, - 0x70, 0x5e, 0x3c, 0x5d, 0x56, 0x43, 0x4c, 0x41, - 0x45, 0x54, 0x76, 0x4b, 0x21, 0x25, 0x45, 0x4c, - 0x5e, 0x58, 0x23, 0x7d, 0x34, 0x61, 0x5c, 0x53, - 0x2a, 0x47, 0x37, 0x22, 0x6d, 0x31, 0x42, 0x6e, - 0x22, 0x72, 0x62, 0x55, 0x59, 0x66, 0x28, 0x73, - 0x55, 0x50, 0x5c, 0x6f, 0x52, 0x40, 0x3e, 0x3b, - 0x44, 0x2a, 0x51, 0x3d, 0x4d, 0x47, 0x3a, 0x57, - 0x3e, 0x29, 0x29, 0x7d, 0x40, 0x36, 0x41, 0x3f, - 0x58, 0x77, 0x3b, 0x41, 0x2d, 0x64, 0x5a, 0x72, - 0x7c, 0x7d, 0x30, 0x68, 0x54, 0x34, 0x40, 0x21, - 0x7d, 0x2b, 0x2d, 0x2b, 0x6d, 0x5f, 0x49, 0x57, - 0x68, 0x65, 0x79, 0x2c, 0x21, 0x41, 0x31, 0x55, - 0x27, 0x4d, 0x78, 0x55, 0x2f, 0x61, 0x62, 0x78, - 0x58, 0x25, 0x3a, 0x4b, 0x3e, 0x67, 0x44, 0x7c, - 0x7d, 0x52, 0x3d, 0x3e, 0x3b, 0x62, 0x2d, 0x28, - 0x48, 0x70, 0x2c, 0x79, 0x31, 0x5a, 0x5e, 0x3f, - 0x6a, 0x30, 0x78, 0x41, 0x44, 0x60, 0x4e, 0x63, - 0x63, 0x2e, 0x31, 0x79, 0x2b, 0x47, 0x57, 0x26, - 0x22, 0x6a, 0x46, 0x43, 0x70, 0x30, 0x51, 0x7d, - 0x21, 0x3c, 0x68, 0x74, 0x40, 0x5a, 0x6e, 0x71, - 0x3f, 0x76, 0x73, 0x2e, 0x29, 0x3f, 0x6a, 0x55, - 0x21, 0x72, 0x65, 0x75, 0x5e, 0x6b, 0x39, 0x6e, - 0x3e, 0x76, 0x42, 0x41, 0x65, 0x3f, 0x2b, 0x37, - 0x70, 0x7a, 0x7a, 0x29, 0x50, 0x66, 0x21, 0x67, - 0x3f, 0x54, 0x32, 0x5f, 0x73, 0x27, 0x59, 0x6f, - 0x39, 0x4b, 0x4e, 0x23, 0x54, 0x3b, 0x39, 0x21, - 0x38, 0x41, 0x33, 0x44, 0x57, 0x6b, 0x51, 0x30, - 0x6a, 0x76, 0x62, 0x2c, 0x5c, 0x5e, 0x49, 0x3e, - 0x59, 0x38, 0x5e, 0x4a, 0x59, 0x77, 0x34, 0x25, - 0x4f, 0x76, 0x6a, 0x68, 0x6f, 0x73, 0x7c, 0x3d, - 0x2d, 0x64, 0x6c, 0x7a, 0x3d, 0x2c, 0x26, 0x28, - 0x58, 0x2b, 0x4b, 0x45, 0x68, 0x38, 0x74, 0x63, - 0x7b, 0x4a, 0x63, 0x52, 0x26, 0x54, 0x3c, 0x46, - 0x77, 0x2d, 0x6b, 0x78, 0x63, 0x7b, 0x6a, 0x50, - 0x26, 0x42, 0x62, 0x63, 0x65, 0x6b, 0x63, 0x54, - 0x4d, 0x47, 0x59, 0x48, 0x2e, 0x60, 0x7c, 0x4d, - 0x33, 0x4d, 0x61, 0x72, 0x76, 0x72, 0x21, 0x4d, - 0x2b, 0x43, 0x58, 0x47, 0x4a, 0x36, 0x2d, 0x7b, - 0x32, 0x72, 0x21, 0x78, 0x22, 0x38, 0x2c, 0x7a, - 0x34, 0x44, 0x45, 0x66, 0x31, 0x7b, 0x37, 0x68, - 0x62, 0x65, 0x62, 0x6d, 0x4e, 0x7c, 0x75, 0x38, - 0x2a, 0x73, 0x27, 0x64, 0x33, 0x4f, 0x21, 0x41, - 0x7c, 0x41, 0x3f, 0x60, 0x68, 0x34, 0x72, 0x5b, - 0x38, 0x33, 0x6f, 0x65, 0x3e, 0x5a, 0x7d, 0x25, - 0x49, 0x50, 0x60, 0x36, 0x59, 0x5e, 0x6b, 0x25, - 0x66, 0x7a, 0x7d, 0x71, 0x40, 0x6c, 0x2c, 0x6e, - 0x6a, 0x5a, 0x24, 0x5a, 0x76, 0x21, 0x67, 0x39, - 0x4b, 0x4a, 0x31, 0x24, 0x66, 0x66, 0x2e, 0x58, - 0x43, 0x46, 0x75, 0x6c, 0x47, 0x28, 0x4f, 0x21, - 0x75, 0x77, 0x6f, 0x71, 0x48, 0x3f, 0x4d, 0x4c, - 0x51, 0x37, 0x3b, 0x41, 0x4d, 0x41, 0x48, 0x28, - 0x71, 0x24, 0x2f, 0x7a, 0x22, 0x49, 0x4a, 0x39, - 0x44, 0x43, 0x68, 0x21, 0x3a, 0x34, 0x4e, 0x52, - 0x7a, 0x60, 0x71, 0x61, 0x6d, 0x51, 0x58, 0x2a, - 0x59, 0x4c, 0x4a, 0x59, 0x6b, 0x77, 0x78, 0x2e, - 0x27, 0x78, 0x76, 0x48, 0x4f, 0x46, 0x79, 0x2c, - 0x54, 0x42, 0x7b, 0x2c, 0x52, 0x41, 0x54, 0x2b, - 0x2c, 0x33, 0x6b, 0x70, 0x77, 0x2e, 0x2e, 0x41, - 0x25, 0x7a, 0x48, 0x6e, 0x71, 0x55, 0x6a, 0x43, - 0x5a, 0x2c, 0x6c, 0x76, 0x6d, 0x71, 0x72, 0x4d, - 0x76, 0x5b, 0x7b, 0x22, 0x4b, 0x45, 0x31, 0x30, - 0x26, 0x53, 0x75, 0x3f, 0x26, 0x59, 0x36, 0x2f, - 0x68, 0x4f, 0x34, 0x5e, 0x2b, 0x30, 0x63, 0x68, - 0x7b, 0x32, 0x5e, 0x77, 0x7d, 0x7b, 0x53, 0x5f, - 0x63, 0x53, 0x77, 0x7a, 0x7d, 0x35, 0x28, 0x3e, - 0x41, 0x6f, 0x5b, 0x31, 0x78, 0x7b, 0x2b, 0x51, - 0x23, 0x43, 0x46, 0x6a, 0x32, 0x32, 0x25, 0x45, - 0x57, 0x43, 0x22, 0x50, 0x60, 0x32, 0x70, 0x2e, - 0x79, 0x2e, 0x6b, 0x33, 0x67, 0x6c, 0x43, 0x5b, - 0x3b, 0x68, 0x53, 0x53, 0x6a, 0x48, 0x59, 0x5f, - 0x30, 0x72, 0x7d, 0x6b, 0x37, 0x24, 0x75, 0x52, - 0x50, 0x2b, 0x75, 0x35, 0x24, 0x3b, 0x6e, 0x53, - 0x56, 0x34, 0x23, 0x54, 0x65, 0x4f, 0x78, 0x3e, - 0x46, 0x7d, 0x25, 0x3f, 0x2f, 0x49, 0x6b, 0x49, - 0x47, 0x45, 0x24, 0x38, 0x3b, 0x68, 0x6c, 0x4f, - 0x29, 0x21, 0x50, 0x32, 0x67, 0x47, 0x5a, 0x72, - 0x76, 0x21, 0x39, 0x67, 0x3c, 0x72, 0x47, 0x43, - 0x4a, 0x2e, 0x31, 0x32, 0x34, 0x3c, 0x53, 0x2d, - 0x22, 0x5b, 0x5b, 0x6a, 0x77, 0x75, 0x31, 0x68, - 0x30, 0x45, 0x43, 0x5f, 0x60, 0x5d, 0x56, 0x67, - 0x66, 0x55, 0x6a, 0x72, 0x77, 0x7b, 0x44, 0x61, - 0x22, 0x64, 0x36, 0x39, 0x6e, 0x44, 0x37, 0x54, - 0x45, 0x46, 0x6f, 0x58, 0x35, 0x51, 0x3c, 0x62, - 0x49, 0x3a, 0x50, 0x58, 0x56, 0x5d, 0x77, 0x6f, - 0x56, 0x64, 0x7b, 0x49, 0x39, 0x21, 0x31, 0x2d, - 0x5f, 0x56, 0x56, 0x33, 0x31, 0x69, 0x4a, 0x52, - 0x62, 0x5b, 0x6e, 0x65, 0x7c, 0x3d, 0x31, 0x55, - 0x3d, 0x75, 0x25, 0x61, 0x50, 0x71, 0x45, 0x29 - }; - uint32_t request5_len = sizeof(request5); - - uint8_t request6[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x5b, 0x56, 0x3d, 0x5a, 0x6b, 0x43, 0x73, 0x26, - 0x65, 0x3b, 0x38, 0x79, 0x26, 0x5e, 0x60, 0x59, - 0x40, 0x71, 0x7c, 0x72, 0x28, 0x29, 0x69, 0x32, - 0x72, 0x5a, 0x6c, 0x55, 0x43, 0x65, 0x3f, 0x4a, - 0x21, 0x66, 0x59, 0x30, 0x76, 0x39, 0x21, 0x69, - 0x4b, 0x25, 0x5d, 0x6e, 0x5f, 0x24, 0x2b, 0x38, - 0x70, 0x78, 0x35, 0x7d, 0x39, 0x36, 0x31, 0x72, - 0x44, 0x49, 0x45, 0x3d, 0x25, 0x50, 0x24, 0x3b, - 0x52, 0x27, 0x66, 0x46, 0x5d, 0x4f, 0x34, 0x50, - 0x26, 0x5a, 0x25, 0x3e, 0x3f, 0x34, 0x4b, 0x35, - 0x77, 0x3a, 0x3f, 0x3e, 0x23, 0x4e, 0x30, 0x23, - 0x70, 0x72, 0x33, 0x34, 0x60, 0x2a, 0x4a, 0x32, - 0x6e, 0x29, 0x54, 0x73, 0x5f, 0x26, 0x71, 0x3a, - 0x78, 0x5d, 0x3f, 0x31, 0x48, 0x59, 0x61, 0x44, - 0x5c, 0x38, 0x4f, 0x41, 0x73, 0x67, 0x62, 0x73, - 0x33, 0x52, 0x77, 0x73, 0x57, 0x49, 0x7a, 0x59, - 0x26, 0x21, 0x34, 0x38, 0x2b, 0x5f, 0x5f, 0x37, - 0x74, 0x28, 0x46, 0x3d, 0x43, 0x42, 0x26, 0x66, - 0x63, 0x37, 0x6d, 0x2a, 0x65, 0x3f, 0x71, 0x2d, - 0x4c, 0x72, 0x29, 0x4b, 0x3a, 0x77, 0x64, 0x6a, - 0x6b, 0x42, 0x70, 0x5c, 0x51, 0x38, 0x71, 0x25, - 0x4c, 0x7c, 0x6f, 0x74, 0x71, 0x39, 0x71, 0x25, - 0x3f, 0x62, 0x23, 0x45, 0x5f, 0x77, 0x59, 0x56, - 0x56, 0x67, 0x78, 0x3a, 0x2e, 0x4e, 0x27, 0x59, - 0x65, 0x2f, 0x64, 0x3c, 0x62, 0x40, 0x69, 0x52, - 0x36, 0x49, 0x3e, 0x3b, 0x2c, 0x47, 0x4f, 0x3e, - 0x61, 0x78, 0x2d, 0x45, 0x71, 0x3f, 0x7b, 0x55, - 0x34, 0x36, 0x47, 0x5e, 0x36, 0x51, 0x3d, 0x5a, - 0x4b, 0x75, 0x44, 0x72, 0x61, 0x44, 0x71, 0x4e, - 0x42, 0x6a, 0x2c, 0x34, 0x40, 0x3b, 0x40, 0x31, - 0x31, 0x75, 0x4b, 0x32, 0x71, 0x69, 0x3a, 0x5d, - 0x31, 0x25, 0x53, 0x2a, 0x61, 0x54, 0x68, 0x2a, - 0x76, 0x71, 0x57, 0x67, 0x56, 0x23, 0x7d, 0x70, - 0x7d, 0x28, 0x57, 0x5f, 0x2f, 0x4c, 0x71, 0x2e, - 0x40, 0x63, 0x49, 0x5b, 0x7c, 0x7b, 0x56, 0x76, - 0x77, 0x46, 0x69, 0x56, 0x3d, 0x75, 0x31, 0x3b, - 0x35, 0x40, 0x37, 0x2c, 0x51, 0x37, 0x49, 0x6a, - 0x79, 0x68, 0x53, 0x31, 0x4c, 0x6f, 0x57, 0x4c, - 0x48, 0x31, 0x6a, 0x30, 0x2b, 0x69, 0x30, 0x56, - 0x58, 0x4b, 0x76, 0x3b, 0x60, 0x6d, 0x35, 0x4d, - 0x74, 0x2f, 0x74, 0x2c, 0x54, 0x4f, 0x6e, 0x3f, - 0x38, 0x56, 0x5c, 0x67, 0x2b, 0x4a, 0x35, 0x30, - 0x67, 0x7d, 0x58, 0x24, 0x59, 0x54, 0x48, 0x2e, - 0x28, 0x7d, 0x6e, 0x51, 0x55, 0x68, 0x56, 0x54, - 0x59, 0x31, 0x4a, 0x65, 0x5a, 0x5e, 0x27, 0x76, - 0x76, 0x65, 0x6d, 0x2f, 0x75, 0x63, 0x67, 0x52, - 0x5e, 0x29, 0x58, 0x3d, 0x5c, 0x3f, 0x54, 0x7c, - 0x67, 0x21, 0x6e, 0x75, 0x67, 0x35, 0x77, 0x31, - 0x3d, 0x26, 0x3f, 0x60, 0x45, 0x2d, 0x2b, 0x45, - 0x5d, 0x3f, 0x55, 0x73, 0x59, 0x4c, 0x5e, 0x6c, - 0x30, 0x4a, 0x4e, 0x47, 0x55, 0x42, 0x6a, 0x4b, - 0x32, 0x3c, 0x75, 0x6e, 0x36, 0x51, 0x5f, 0x4c, - 0x68, 0x72, 0x72, 0x27, 0x3b, 0x51, 0x59, 0x7b, - 0x68, 0x7b, 0x3b, 0x54, 0x35, 0x37, 0x7c, 0x44, - 0x43, 0x36, 0x4c, 0x4f, 0x67, 0x62, 0x4e, 0x39, - 0x4b, 0x7a, 0x49, 0x36, 0x68, 0x38, 0x4c, 0x4a, - 0x64, 0x33, 0x35, 0x2f, 0x3e, 0x5c, 0x58, 0x61, - 0x23, 0x5b, 0x50, 0x6e, 0x34, 0x44, 0x60, 0x28, - 0x54, 0x41, 0x5c, 0x31, 0x53, 0x2d, 0x58, 0x58, - 0x54, 0x28, 0x77, 0x51, 0x6f, 0x64, 0x4c, 0x68, - 0x34, 0x79, 0x45, 0x66, 0x2c, 0x26, 0x77, 0x64, - 0x5f, 0x6c, 0x3b, 0x71, 0x28, 0x4d, 0x68, 0x2a, - 0x6b, 0x37, 0x6a, 0x34, 0x51, 0x27, 0x2a, 0x46, - 0x3a, 0x2e, 0x35, 0x21, 0x21, 0x79, 0x51, 0x44, - 0x58, 0x5d, 0x6f, 0x65, 0x6b, 0x76, 0x68, 0x3a, - 0x43, 0x70, 0x36, 0x41, 0x6b, 0x56, 0x64, 0x75, - 0x5b, 0x37, 0x24, 0x56, 0x7c, 0x6e, 0x6c, 0x41, - 0x3a, 0x60, 0x56, 0x38, 0x55, 0x63, 0x77, 0x4d, - 0x6e, 0x50, 0x3c, 0x3d, 0x7a, 0x44, 0x71, 0x42, - 0x4b, 0x55, 0x75, 0x72, 0x61, 0x60, 0x65, 0x6f, - 0x7a, 0x26, 0x64, 0x46, 0x67, 0x74, 0x29, 0x2a, - 0x5b, 0x62, 0x41, 0x28, 0x62, 0x30, 0x34, 0x33, - 0x40, 0x79, 0x7a, 0x38, 0x56, 0x38, 0x73, 0x22, - 0x7a, 0x7d, 0x73, 0x2a, 0x2a, 0x28, 0x2b, 0x63, - 0x27, 0x6f, 0x3d, 0x3e, 0x2c, 0x56, 0x23, 0x32, - 0x4b, 0x3b, 0x58, 0x4d, 0x72, 0x4c, 0x49, 0x6f, - 0x30, 0x76, 0x23, 0x21, 0x21, 0x3c, 0x49, 0x56, - 0x7a, 0x56, 0x79, 0x2f, 0x50, 0x7a, 0x5b, 0x21, - 0x21, 0x4a, 0x48, 0x61, 0x33, 0x52, 0x49, 0x2e, - 0x30, 0x7d, 0x2c, 0x2d, 0x67, 0x23, 0x55, 0x62, - 0x66, 0x52, 0x5a, 0x61, 0x75, 0x63, 0x3c, 0x39, - 0x69, 0x41, 0x31, 0x6b, 0x4e, 0x6f, 0x25, 0x34, - 0x74, 0x30, 0x21, 0x3a, 0x40, 0x72, 0x44, 0x40, - 0x60, 0x4c, 0x53, 0x74, 0x42, 0x64, 0x44, 0x49, - 0x76, 0x67, 0x21, 0x79, 0x36, 0x3c, 0x37, 0x70, - 0x4f, 0x58, 0x29, 0x71, 0x2a, 0x3a, 0x4d, 0x5d, - 0x67, 0x68, 0x52, 0x63, 0x23, 0x24, 0x4b, 0x21, - 0x3f, 0x68, 0x69, 0x6c, 0x66, 0x66, 0x42, 0x28, - 0x59, 0x35, 0x34, 0x6f, 0x2d, 0x6a, 0x25, 0x66, - 0x34, 0x54, 0x5d, 0x50, 0x26, 0x41, 0x22, 0x4f, - 0x34, 0x79, 0x3c, 0x50, 0x68, 0x2d, 0x5f, 0x7b, - 0x63, 0x7d, 0x58, 0x2e, 0x73, 0x46, 0x2f, 0x54, - 0x61, 0x27, 0x74, 0x45, 0x23, 0x72, 0x31, 0x7d, - 0x63, 0x4b, 0x43, 0x5e, 0x44, 0x54, 0x2c, 0x38, - 0x58, 0x24, 0x75, 0x6c, 0x50, 0x3c, 0x23, 0x5f, - 0x35, 0x57, 0x4f, 0x7b, 0x2f, 0x57, 0x29, 0x73, - 0x58, 0x2a, 0x66, 0x3e, 0x49, 0x42, 0x5a, 0x6b, - 0x75, 0x6a, 0x38, 0x3f, 0x73, 0x44, 0x42, 0x46, - 0x2d, 0x39, 0x66, 0x5b, 0x28, 0x3e, 0x63, 0x62, - 0x53, 0x75, 0x65, 0x64, 0x79, 0x32, 0x35, 0x71, - 0x22, 0x6a, 0x7b, 0x41, 0x2b, 0x26, 0x43, 0x79, - 0x58, 0x6f, 0x71, 0x25, 0x24, 0x34, 0x72, 0x5b, - 0x4a, 0x2c, 0x5c, 0x77, 0x23, 0x42, 0x27, 0x6a, - 0x67, 0x51, 0x5f, 0x3c, 0x75, 0x2c, 0x3f, 0x43, - 0x45, 0x5b, 0x48, 0x65, 0x6f, 0x6c, 0x27, 0x65, - 0x21, 0x3e, 0x33, 0x37, 0x5f, 0x2b, 0x2e, 0x24, - 0x22, 0x47, 0x4e, 0x33, 0x5b, 0x7b, 0x21, 0x3c, - 0x53, 0x69, 0x2e, 0x31, 0x3d, 0x48, 0x57, 0x3a, - 0x56, 0x48, 0x6b, 0x47, 0x5d, 0x33, 0x41, 0x6c, - 0x66, 0x4c, 0x61, 0x67, 0x32, 0x69, 0x53, 0x2c, - 0x2f, 0x3e, 0x36, 0x68, 0x37, 0x28, 0x40, 0x21, - 0x76, 0x27, 0x44, 0x26, 0x24, 0x6a, 0x30, 0x75, - 0x2a, 0x73, 0x48, 0x36, 0x52, 0x4a, 0x3b, 0x51, - 0x4e, 0x2f, 0x23, 0x36, 0x4b, 0x49, 0x33, 0x5a, - 0x70, 0x2c, 0x54, 0x5b, 0x67, 0x48, 0x53, 0x5d, - 0x21, 0x3e, 0x6b, 0x52, 0x6a, 0x3c, 0x48, 0x29, - 0x68, 0x27, 0x32, 0x75, 0x61, 0x7c, 0x51, 0x2e, - 0x7b, 0x49, 0x2f, 0x5b, 0x3d, 0x74, 0x5a, 0x28, - 0x26, 0x29, 0x2c, 0x30, 0x54, 0x74, 0x45, 0x55, - 0x4a, 0x3d, 0x39, 0x35, 0x66, 0x56, 0x28, 0x6d, - 0x6e, 0x38, 0x7b, 0x2b, 0x40, 0x31, 0x56, 0x61, - 0x74, 0x2b, 0x79, 0x5f, 0x63, 0x51, 0x53, 0x52, - 0x7d, 0x73, 0x4e, 0x2e, 0x45, 0x3b, 0x22, 0x28, - 0x6c, 0x2b, 0x47, 0x21, 0x50, 0x2a, 0x7c, 0x45, - 0x48, 0x57, 0x3e, 0x2f, 0x6d, 0x66, 0x6c, 0x51, - 0x23, 0x6c, 0x37, 0x4d, 0x4b, 0x4b, 0x66, 0x55, - 0x69, 0x2e, 0x4a, 0x69, 0x71, 0x7c, 0x71, 0x30, - 0x5c, 0x43, 0x46, 0x63, 0x5a, 0x23, 0x75, 0x40 - }; - uint32_t request6_len = sizeof(request6); - - uint8_t request7[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x5d, 0x32, 0x55, 0x71, 0x51, 0x45, 0x4e, 0x54, - 0x34, 0x21, 0x46, 0x77, 0x5e, 0x5b, 0x75, 0x62, - 0x2b, 0x5c, 0x34, 0x26, 0x72, 0x2b, 0x2c, 0x64, - 0x4b, 0x65, 0x56, 0x72, 0x31, 0x7d, 0x6a, 0x5f, - 0x70, 0x26, 0x32, 0x29, 0x7d, 0x21, 0x5b, 0x3e, - 0x5e, 0x53, 0x3d, 0x48, 0x5e, 0x2a, 0x4c, 0x37, - 0x3d, 0x59, 0x79, 0x21, 0x4f, 0x56, 0x79, 0x2a, - 0x4e, 0x28, 0x61, 0x7d, 0x2c, 0x58, 0x2f, 0x78, - 0x5c, 0x3f, 0x5c, 0x42, 0x6d, 0x2f, 0x71, 0x54, - 0x25, 0x31, 0x73, 0x38, 0x6c, 0x31, 0x5a, 0x2e, - 0x42, 0x5b, 0x2d, 0x41, 0x24, 0x4c, 0x37, 0x40, - 0x39, 0x7d, 0x2a, 0x67, 0x60, 0x6a, 0x7a, 0x62, - 0x24, 0x4e, 0x3f, 0x2e, 0x69, 0x35, 0x28, 0x65, - 0x77, 0x53, 0x23, 0x44, 0x59, 0x71, 0x31, 0x5c, - 0x40, 0x5d, 0x3a, 0x27, 0x46, 0x55, 0x30, 0x56, - 0x21, 0x74, 0x3e, 0x73, 0x41, 0x22, 0x52, 0x68, - 0x40, 0x6c, 0x37, 0x3e, 0x62, 0x5a, 0x2e, 0x21, - 0x23, 0x33, 0x27, 0x73, 0x68, 0x26, 0x60, 0x67, - 0x70, 0x58, 0x50, 0x42, 0x58, 0x27, 0x3a, 0x35, - 0x6f, 0x51, 0x62, 0x78, 0x25, 0x2c, 0x7b, 0x66, - 0x34, 0x6a, 0x5a, 0x39, 0x60, 0x70, 0x41, 0x2d, - 0x65, 0x26, 0x5a, 0x67, 0x58, 0x2d, 0x3e, 0x56, - 0x6d, 0x30, 0x4b, 0x4d, 0x5d, 0x45, 0x41, 0x3d, - 0x6e, 0x27, 0x4e, 0x5a, 0x7d, 0x2e, 0x62, 0x4d, - 0x42, 0x70, 0x31, 0x24, 0x73, 0x5c, 0x78, 0x77, - 0x50, 0x73, 0x27, 0x48, 0x3d, 0x35, 0x2c, 0x4b, - 0x40, 0x2d, 0x25, 0x77, 0x5d, 0x3d, 0x6b, 0x50, - 0x6f, 0x57, 0x73, 0x2f, 0x4f, 0x6e, 0x4c, 0x6e, - 0x56, 0x7b, 0x55, 0x3c, 0x6d, 0x60, 0x47, 0x53, - 0x56, 0x39, 0x3b, 0x51, 0x61, 0x71, 0x75, 0x73, - 0x6b, 0x70, 0x58, 0x5f, 0x2c, 0x27, 0x74, 0x49, - 0x2c, 0x2b, 0x53, 0x2d, 0x5b, 0x79, 0x43, 0x34, - 0x39, 0x5a, 0x38, 0x3e, 0x2d, 0x66, 0x70, 0x3d, - 0x49, 0x51, 0x29, 0x4d, 0x5d, 0x4c, 0x57, 0x4a, - 0x2f, 0x41, 0x69, 0x56, 0x57, 0x77, 0x49, 0x58, - 0x75, 0x28, 0x29, 0x4a, 0x6d, 0x54, 0x4f, 0x4f, - 0x3f, 0x58, 0x5f, 0x58, 0x6f, 0x39, 0x22, 0x4d, - 0x5d, 0x31, 0x75, 0x43, 0x2f, 0x7d, 0x31, 0x3d, - 0x4c, 0x4d, 0x76, 0x74, 0x4d, 0x57, 0x3b, 0x56, - 0x57, 0x48, 0x2b, 0x5d, 0x32, 0x67, 0x51, 0x6e, - 0x60, 0x39, 0x6f, 0x64, 0x38, 0x37, 0x52, 0x4b, - 0x52, 0x42, 0x32, 0x4f, 0x24, 0x53, 0x31, 0x6e, - 0x4a, 0x68, 0x2f, 0x28, 0x2e, 0x27, 0x49, 0x75, - 0x77, 0x75, 0x26, 0x47, 0x7c, 0x5d, 0x72, 0x5a, - 0x77, 0x50, 0x2e, 0x6c, 0x27, 0x68, 0x6b, 0x7b, - 0x27, 0x63, 0x21, 0x3d, 0x30, 0x2d, 0x5c, 0x67, - 0x4d, 0x41, 0x79, 0x47, 0x42, 0x50, 0x6d, 0x32, - 0x74, 0x39, 0x62, 0x4d, 0x5f, 0x65, 0x78, 0x4f, - 0x67, 0x3a, 0x60, 0x26, 0x45, 0x61, 0x7c, 0x61, - 0x63, 0x40, 0x46, 0x79, 0x52, 0x47, 0x57, 0x49, - 0x53, 0x4c, 0x48, 0x36, 0x67, 0x47, 0x5c, 0x71, - 0x50, 0x4d, 0x4f, 0x58, 0x26, 0x40, 0x6d, 0x54, - 0x55, 0x67, 0x66, 0x23, 0x70, 0x23, 0x68, 0x70, - 0x4d, 0x2c, 0x7a, 0x3d, 0x60, 0x51, 0x35, 0x64, - 0x56, 0x2f, 0x26, 0x6d, 0x72, 0x6a, 0x59, 0x34, - 0x3a, 0x73, 0x4b, 0x27, 0x33, 0x61, 0x26, 0x45, - 0x61, 0x28, 0x74, 0x22, 0x54, 0x50, 0x2e, 0x39, - 0x6a, 0x2c, 0x27, 0x59, 0x26, 0x73, 0x44, 0x71, - 0x67, 0x4c, 0x37, 0x74, 0x2c, 0x63, 0x52, 0x2a, - 0x60, 0x4f, 0x7b, 0x32, 0x39, 0x21, 0x79, 0x54, - 0x79, 0x6d, 0x28, 0x27, 0x3a, 0x6a, 0x7d, 0x40, - 0x6a, 0x4f, 0x4b, 0x46, 0x61, 0x36, 0x6a, 0x22, - 0x3f, 0x77, 0x2d, 0x6a, 0x3b, 0x73, 0x71, 0x72, - 0x3c, 0x21, 0x2e, 0x3f, 0x33, 0x25, 0x76, 0x64, - 0x64, 0x70, 0x43, 0x32, 0x44, 0x73, 0x61, 0x51, - 0x3c, 0x3b, 0x45, 0x3a, 0x68, 0x46, 0x5b, 0x6e, - 0x36, 0x47, 0x4d, 0x38, 0x26, 0x4f, 0x5c, 0x7d, - 0x73, 0x29, 0x24, 0x78, 0x44, 0x75, 0x40, 0x42, - 0x41, 0x2a, 0x73, 0x2b, 0x24, 0x38, 0x51, 0x67, - 0x36, 0x67, 0x2f, 0x70, 0x58, 0x54, 0x6e, 0x5d, - 0x3b, 0x41, 0x59, 0x76, 0x7d, 0x2d, 0x40, 0x70, - 0x29, 0x4a, 0x4a, 0x31, 0x79, 0x2c, 0x4e, 0x22, - 0x31, 0x59, 0x31, 0x3c, 0x2f, 0x21, 0x29, 0x3f, - 0x65, 0x6c, 0x38, 0x55, 0x4f, 0x27, 0x66, 0x66, - 0x34, 0x45, 0x49, 0x41, 0x56, 0x24, 0x2e, 0x40, - 0x36, 0x23, 0x5a, 0x46, 0x40, 0x23, 0x7b, 0x2d, - 0x69, 0x54, 0x6c, 0x51, 0x58, 0x73, 0x56, 0x60, - 0x5f, 0x60, 0x63, 0x5f, 0x77, 0x6a, 0x4c, 0x2c, - 0x35, 0x39, 0x60, 0x73, 0x63, 0x3e, 0x2d, 0x55, - 0x5a, 0x26, 0x4b, 0x43, 0x3b, 0x56, 0x33, 0x58, - 0x74, 0x51, 0x4f, 0x5c, 0x2a, 0x44, 0x78, 0x66, - 0x78, 0x71, 0x40, 0x29, 0x5e, 0x26, 0x57, 0x51, - 0x49, 0x30, 0x29, 0x73, 0x38, 0x56, 0x6c, 0x41, - 0x78, 0x3d, 0x61, 0x3d, 0x2c, 0x33, 0x46, 0x57, - 0x54, 0x63, 0x3e, 0x79, 0x55, 0x4a, 0x7d, 0x2e, - 0x2a, 0x3c, 0x77, 0x47, 0x35, 0x29, 0x5a, 0x6d, - 0x69, 0x48, 0x6b, 0x73, 0x7d, 0x4f, 0x5f, 0x6f, - 0x3a, 0x7a, 0x4e, 0x54, 0x59, 0x38, 0x62, 0x44, - 0x72, 0x51, 0x57, 0x6a, 0x74, 0x54, 0x4f, 0x77, - 0x6b, 0x66, 0x4a, 0x6b, 0x39, 0x29, 0x69, 0x60, - 0x71, 0x52, 0x6a, 0x32, 0x66, 0x6c, 0x25, 0x76, - 0x27, 0x7a, 0x2c, 0x38, 0x72, 0x4e, 0x5f, 0x40, - 0x26, 0x74, 0x6a, 0x5e, 0x42, 0x38, 0x78, 0x34, - 0x4f, 0x4f, 0x35, 0x27, 0x39, 0x62, 0x52, 0x61, - 0x37, 0x54, 0x47, 0x38, 0x70, 0x31, 0x7a, 0x66, - 0x69, 0x72, 0x24, 0x52, 0x2a, 0x2a, 0x78, 0x72, - 0x2b, 0x2e, 0x2a, 0x57, 0x4a, 0x21, 0x52, 0x3c, - 0x2a, 0x2f, 0x24, 0x58, 0x34, 0x3c, 0x42, 0x5c, - 0x5b, 0x78, 0x27, 0x55, 0x63, 0x58, 0x3e, 0x26, - 0x50, 0x2c, 0x72, 0x60, 0x36, 0x6c, 0x46, 0x58, - 0x63, 0x59, 0x23, 0x2a, 0x2d, 0x63, 0x6a, 0x68, - 0x69, 0x74, 0x3f, 0x49, 0x4f, 0x48, 0x4a, 0x3b, - 0x59, 0x56, 0x77, 0x43, 0x6d, 0x57, 0x28, 0x5f, - 0x39, 0x73, 0x28, 0x74, 0x3c, 0x4f, 0x43, 0x48, - 0x6a, 0x57, 0x5d, 0x41, 0x73, 0x3f, 0x41, 0x7c, - 0x65, 0x5e, 0x2d, 0x38, 0x72, 0x3a, 0x53, 0x3e, - 0x33, 0x47, 0x69, 0x6a, 0x6e, 0x78, 0x67, 0x5d, - 0x35, 0x3b, 0x3f, 0x23, 0x7c, 0x71, 0x3d, 0x7c, - 0x3a, 0x3c, 0x75, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x80, 0x23, 0x00, 0xdf, 0xaf, 0xff, 0x33, - 0x9b, 0x78, 0x70, 0x43, 0xc5, 0x0a, 0x4d, 0x98, - 0x96, 0x02, 0x64, 0x92, 0xc1, 0xee, 0x70, 0x32 - }; - uint32_t request7_len = sizeof(request7); - - uint8_t request8[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x65, 0xc1, 0xef, 0x7b, 0xd6, 0xaa, 0xd6, 0x09, - 0x21, 0xf6, 0xe7, 0xd1, 0x4c, 0xdf, 0x6a, 0x2d, - 0x0a, 0xfb, 0x43, 0xea, 0xda, 0x07, 0x24, 0x84, - 0x88, 0x52, 0x9e, 0xa8, 0xa1, 0x7f, 0x4b, 0x60, - 0xec, 0x94, 0x57, 0x33, 0x06, 0x93, 0x92, 0x25, - 0xd6, 0xac, 0xdc, 0x89, 0x68, 0x5e, 0xbb, 0x32, - 0x2b, 0x17, 0x68, 0xf2, 0x06, 0xb7, 0x86, 0xac, - 0x81, 0xfe, 0x52, 0x27, 0xf5, 0x80, 0x11, 0x0d, - 0x4e, 0x2e, 0x1b, 0xa3, 0x44, 0x8a, 0x58, 0xed, - 0xf3, 0x9c, 0xe9, 0x31, 0x01, 0x72, 0xa6, 0xab, - 0xfa, 0xa8, 0x05, 0x00, 0x37, 0x60, 0x6b, 0x81, - 0xef, 0xf4, 0x96, 0x9a, 0xf7, 0x67, 0x95, 0x27, - 0x7a, 0x25, 0xef, 0x6f, 0x0e, 0xff, 0x2d, 0x15, - 0x7f, 0x23, 0x1c, 0xa7, 0x56, 0x94, 0x4a, 0x18, - 0x98, 0xc6, 0xd8, 0xd2, 0x29, 0x5b, 0x57, 0xb8, - 0x5d, 0x3a, 0x93, 0x58, 0x45, 0x77, 0x36, 0xe3, - 0xd1, 0x36, 0x87, 0xff, 0xe3, 0x94, 0x0f, 0x00, - 0xe6, 0x7c, 0x1a, 0x92, 0xc1, 0x5f, 0x40, 0xc3, - 0xa3, 0x25, 0xce, 0xd4, 0xaf, 0x39, 0xeb, 0x17, - 0xcf, 0x22, 0x43, 0xd9, 0x0c, 0xce, 0x37, 0x86, - 0x46, 0x54, 0xd6, 0xce, 0x00, 0x30, 0x36, 0xae, - 0xf9, 0xb5, 0x2b, 0x11, 0xa0, 0xfe, 0xa3, 0x4b, - 0x2e, 0x05, 0xbe, 0x54, 0xa9, 0xd8, 0xa5, 0x76, - 0x83, 0x5b, 0x63, 0x01, 0x1c, 0xd4, 0x56, 0x72, - 0xcd, 0xdc, 0x4a, 0x1d, 0x77, 0xda, 0x8a, 0x9e, - 0xba, 0xcb, 0x6c, 0xe8, 0x19, 0x5d, 0x68, 0xef, - 0x8e, 0xbc, 0x6a, 0x05, 0x53, 0x0b, 0xc7, 0xc5, - 0x96, 0x84, 0x04, 0xd9, 0xda, 0x4c, 0x42, 0x31, - 0xd9, 0xbd, 0x99, 0x06, 0xf7, 0xa3, 0x0a, 0x19, - 0x49, 0x07, 0x77, 0xf0, 0xdb, 0x7c, 0x43, 0xfa, - 0xb2, 0xad, 0xb0, 0xfa, 0x87, 0x52, 0xba, 0xc9, - 0x94, 0x61, 0xdc, 0xcf, 0x16, 0xac, 0x0f, 0x4a, - 0xa3, 0x6b, 0x5b, 0x6e, 0x27, 0x86, 0x1f, 0xfe, - 0x4d, 0x28, 0x3a, 0xa5, 0x10, 0x54, 0x6d, 0xed, - 0x53, 0xf9, 0x73, 0xc6, 0x6e, 0xa8, 0xc0, 0x97, - 0xcf, 0x56, 0x3b, 0x61, 0xdf, 0xab, 0x83, 0x18, - 0xe8, 0x09, 0xee, 0x6a, 0xb7, 0xf5, 0xc9, 0x62, - 0x55, 0x2d, 0xc7, 0x0c, 0x0d, 0xa0, 0x22, 0xd8, - 0xd4, 0xd6, 0xb2, 0x12, 0x21, 0xd7, 0x73, 0x3e, - 0x41, 0xb0, 0x5c, 0xd4, 0xcf, 0x98, 0xf3, 0x70, - 0xe6, 0x08, 0xe6, 0x2a, 0x4f, 0x24, 0x85, 0xe8, - 0x74, 0xa8, 0x41, 0x5f, 0x0e, 0xfd, 0xf1, 0xf3, - 0xbe, 0x9b, 0x14, 0xfd, 0xc0, 0x73, 0x11, 0xff, - 0xa5, 0x5b, 0x06, 0x34, 0xc3, 0x6c, 0x28, 0x42, - 0x07, 0xfe, 0x8a, 0xa5, 0xbe, 0x72, 0x7a, 0xf7, - 0xfa, 0x25, 0xec, 0x35, 0x5e, 0x98, 0x71, 0x50, - 0x60, 0x35, 0x76, 0x53, 0x40, 0x1a, 0x34, 0xa5, - 0x99, 0x09, 0xa2, 0xc6, 0xca, 0xa5, 0xce, 0x08, - 0x50, 0x45, 0xab, 0x8d, 0xfb, 0xe3, 0xb8, 0xe4, - 0x8a, 0x61, 0x48, 0x14, 0x6e, 0xf7, 0x58, 0x71, - 0xe5, 0x2e, 0xbc, 0x12, 0xd1, 0x25, 0xe9, 0x65, - 0x7a, 0xa1, 0x27, 0xbe, 0x3b, 0x8b, 0xe8, 0xe7, - 0xbc, 0xe1, 0x05, 0xe7, 0x92, 0xeb, 0xb9, 0xdf, - 0x5d, 0x53, 0x74, 0xc0, 0x63, 0x97, 0x80, 0xb8, - 0x3c, 0xae, 0xf3, 0xf2, 0x09, 0x12, 0x81, 0x6c, - 0x69, 0x10, 0x6f, 0xf6, 0xbe, 0x03, 0x7b, 0x88, - 0xcf, 0x26, 0x6b, 0x51, 0x06, 0x23, 0x68, 0x03, - 0xa1, 0xb7, 0xd3, 0x0c, 0xca, 0xbf, 0x29, 0x01, - 0xa9, 0x61, 0x34, 0x75, 0x98, 0x1e, 0x05, 0x59, - 0xb3, 0x46, 0x44, 0xff, 0x2b, 0x98, 0x04, 0x88, - 0x89, 0xfd, 0x7f, 0xd5, 0x19, 0x8a, 0xa6, 0xf3, - 0xd9, 0x44, 0xd5, 0xf9, 0x3a, 0x3c, 0xec, 0xd9, - 0x9b, 0x8c, 0x93, 0x93, 0x2b, 0x44, 0x86, 0x8b, - 0x80, 0x83, 0x23, 0x00, 0xdf, 0xaf, 0xff, 0x33, - 0x9b, 0x78, 0x70, 0x43, 0xf1, 0x55, 0x87, 0xb1, - 0xa1, 0xb3, 0x8e, 0x79, 0x02, 0x70, 0x82, 0x6c, - 0x0b, 0xc1, 0xef, 0x96, 0xf1, 0xef, 0xdd, 0xa2, - 0x69, 0x86, 0xc7, 0x85, 0x09, 0x7e, 0xf0, 0x2f, - 0x8e, 0xa0, 0x5f, 0xea, 0x39, 0x2e, 0x24, 0xf0, - 0x82, 0x30, 0x26, 0xa8, 0xa1, 0x4f, 0xc6, 0x5c, - 0xec, 0x94, 0x87, 0x52, 0x9b, 0x93, 0x92, 0xf3, - 0xa3, 0x1b, 0xc7, 0x8f, 0x9e, 0xb3, 0xbb, 0x32, - 0x2b, 0x17, 0x54, 0xf2, 0x06, 0x0c, 0x86, 0x92, - 0x0f, 0xb8, 0xe0, 0x27, 0x50, 0xaa, 0xeb, 0xf5, - 0x4e, 0x2b, 0x1b, 0xb2, 0x44, 0xe6, 0x58, 0x02, - 0xd7, 0x65, 0xdc, 0x31, 0x01, 0xec, 0xa6, 0xab, - 0xfa, 0xa8, 0x05, 0x00, 0x37, 0x60, 0x4f, 0xa1, - 0x3c, 0x4f, 0x7a, 0x9a, 0x10, 0x67, 0x95, 0xc2, - 0x5b, 0x25, 0xef, 0x76, 0x0e, 0xff, 0x2d, 0x15, - 0x7f, 0x23, 0x1c, 0x77, 0x56, 0x94, 0x4a, 0x18, - 0x98, 0xc6, 0xd8, 0xd2, 0x29, 0x44, 0x57, 0xb8, - 0x40, 0x3a, 0x93, 0x58, 0x45, 0x77, 0x36, 0x36, - 0x07, 0x35, 0x2a, 0xff, 0x00, 0x94, 0x5c, 0x80, - 0xe6, 0x7c, 0x1a, 0x92, 0xc1, 0x5f, 0x40, 0xc3, - 0xbc, 0xf8, 0xce, 0x05, 0x77, 0x39, 0x40, 0x17, - 0xcf, 0x63, 0x43, 0x77, 0x27, 0xce, 0x37, 0x86, - 0x46, 0x54, 0xd6, 0xce, 0x00, 0x30, 0x36, 0xae, - 0x9f, 0x24, 0x2b, 0x5a, 0xa0, 0xfe, 0xa3, 0x4b, - 0x2e, 0x7e, 0xf7, 0x54, 0xa9, 0xd8, 0xa5, 0x76, - 0x83, 0x7b, 0x63, 0x01, 0x1c, 0xd4, 0x56, 0x17, - 0x02, 0xdc, 0x4a, 0x89, 0x77, 0xda, 0x8f, 0x9e, - 0xba, 0xcb, 0x37, 0xe8, 0x19, 0x5d, 0x68, 0x38, - 0x8e, 0xbc, 0x6a, 0x05, 0x53, 0x0b, 0xc7, 0xc5, - 0x96, 0x84, 0x5a, 0xd9, 0x6d, 0x4c, 0x42, 0x31, - 0xd9, 0xf2, 0x99, 0x06, 0xf7, 0x0c, 0x99, 0xbe, - 0x49, 0x07, 0x77, 0xf0, 0x8b, 0x7c, 0x43, 0xfa, - 0xb2, 0xad, 0xb0, 0xfa, 0x87, 0x52, 0xba, 0xc9, - 0x94, 0x61, 0xdc, 0xcf, 0x16, 0xac, 0x0f, 0x4a, - 0xa3, 0x6b, 0x5b, 0x6e, 0x27, 0x86, 0x1f, 0xfe, - 0x4d, 0x28, 0x3a, 0xa5, 0x10, 0x98, 0x6d, 0xed, - 0x53, 0xf9, 0x73, 0xc6, 0xa5, 0xa8, 0xf7, 0x66, - 0xcf, 0x56, 0x3b, 0x61, 0xdf, 0xab, 0x83, 0x18, - 0xe8, 0x09, 0xee, 0x6a, 0xb7, 0xf5, 0xc9, 0x62, - 0x55, 0x2d, 0xc7, 0x0c, 0x0d, 0xa0, 0x22, 0xd8, - 0xd4, 0xd6, 0xb2, 0x12, 0x21, 0xd7, 0x73, 0x3e, - 0x41, 0xb0, 0x5c, 0xd4, 0xcf, 0x98, 0xf3, 0x70, - 0xe6, 0x08, 0xe6, 0x2a, 0x4f, 0x92, 0x85, 0xe8, - 0x74, 0xa8, 0x41, 0x5f, 0x0e, 0xfd, 0xf1, 0xf3, - 0xbe, 0x9b, 0x14, 0xfd, 0xc0, 0x73, 0x11, 0xff, - 0xa5, 0x5b, 0x06, 0x34, 0xc3, 0x5d, 0x28, 0x42, - 0x34, 0xfe, 0x8a, 0xa5, 0xbe, 0x72, 0x7a, 0xf7, - 0xfa, 0x25, 0x2b, 0x35, 0x5e, 0x98, 0x71, 0x50, - 0x2c, 0x35, 0x76, 0x53, 0x4e, 0x1a, 0x34, 0xa5, - 0x99, 0x09, 0xa2, 0xc6, 0xca, 0xa5, 0xce, 0x08, - 0x50, 0x45, 0xab, 0x8d, 0xfb, 0xe3, 0xb8, 0xe4, - 0x8a, 0x61, 0x48, 0x14, 0x6e, 0xf7, 0x58, 0x71, - 0xe5, 0x2e, 0xbc, 0x12, 0xd1, 0x25, 0xe9, 0x65, - 0x7a, 0xa1, 0x27, 0xbe, 0x3b, 0x8b, 0xe8, 0xe7, - 0xbc, 0x77, 0x05, 0xe7, 0x92, 0xeb, 0xb9, 0xdf, - 0x5d, 0x53, 0x74, 0xc0, 0x63, 0x97, 0x80, 0xb8, - 0x3c, 0xae, 0xf3, 0xf2, 0x09, 0x12, 0x81, 0x6c, - 0x69, 0x10, 0x6f, 0xf6, 0xbe, 0x03, 0x7b, 0x88, - 0xcf, 0x26, 0x6b, 0x51, 0x06, 0x23, 0x68, 0x03, - 0xa1, 0xb7, 0xd3, 0x0c, 0xca, 0xbf, 0x29, 0x01, - 0xa9, 0x61, 0x34, 0x75, 0x98, 0x1e, 0x6f, 0x59, - 0xb3, 0x46, 0x44, 0xff, 0x2b, 0x98, 0x04, 0x88, - 0x89, 0xfd, 0x1c, 0xd5, 0x19, 0x8a, 0xa6, 0xf3, - 0xd9, 0x44, 0xd5, 0xf9, 0x79, 0x26, 0x46, 0xf7 - }; - uint32_t request8_len = sizeof(request8); - - uint8_t request9[] = { - 0x05, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xbf, 0xa1, 0x12, 0x73, 0x23, 0x44, 0x86, 0x8b, - 0x50, 0x6a, 0x40, 0x00 - }; - uint32_t request9_len = sizeof(request9); - - TcpSession ssn; - Packet *p[11]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|26 d0 cf 80|\"; distance:0; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|43 5b 67 26 65|\"; distance:0; sid:2;)"; - char *sig3 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|71 69 75 3e|\"; distance:0; sid:3;)"; - char *sig4 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|6a 68 69 3e 72|\"; distance:0; sid:4;)"; - char *sig5 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|61 50 71 45 29 5b 56 3d 5a|\"; distance:0; sid:5;)"; - char *sig6 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|23 75 40 5d 32 55|\"; distance:0; sid:6;)"; - char *sig7 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|ee 70 32 65 c1|\"; distance:0; sid:7;)"; - char *sig8 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|79 26 46 f7 bf a1|\"; distance:0; sid:8;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 11; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig3); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig4); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig5); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig6); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig7); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig8); - s = s->next; - if (s == NULL) - goto end; - - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 3))) { - printf("sid 3 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 4))) { - printf("sid 4 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 5))) { - printf("sid 5 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 6))) { - printf("sid 6 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 7))) { - printf("sid 7 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 8))) { - printf("sid 8 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 3))) { - printf("sid 3 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 4))) { - printf("sid 4 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 5))) { - printf("sid 5 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 6))) { - printf("sid 6 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 7))) { - printf("sid 7 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 8))) { - printf("sid 8 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if ((PacketAlertCheck(p[2], 1))) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 3))) { - printf("sid 3 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 4))) { - printf("sid 4 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 5))) { - printf("sid 5 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 6))) { - printf("sid 6 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 7))) { - printf("sid 7 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 8))) { - printf("sid 8 matched but shouldn't have for packet 2: "); - goto end; - } - - SCLogDebug("sending request 2"); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if (!(PacketAlertCheck(p[3], 1))) { - printf("sid 1 didn't match but should have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 2))) { - printf("sid 2 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 3))) { - printf("sid 3 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 4))) { - printf("sid 4 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 5))) { - printf("sid 5 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 6))) { - printf("sid 6 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 7))) { - printf("sid 7 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 8))) { - printf("sid 8 matched but shouldn't have for packet 3: "); - goto end; - } - - SCLogDebug("sending request 3"); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SCLogDebug("inspecting packet 4"); - SigMatchSignatures(&tv, de_ctx, det_ctx, p[4]); - if ((PacketAlertCheck(p[4], 1))) { - printf("sid 1 matched but shouldn't have for packet 4: "); - goto end; - } - if (!(PacketAlertCheck(p[4], 2))) { - printf("sid 2 didn't match but should have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 3))) { - printf("sid 3 matched but shouldn't have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 4))) { - printf("sid 4 matched but shouldn't have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 5))) { - printf("sid 5 matched but shouldn't have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 6))) { - printf("sid 6 matched but shouldn't have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 7))) { - printf("sid 7 matched but shouldn't have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 8))) { - printf("sid 8 matched but shouldn't have for packet 4: "); - goto end; - } - - SCLogDebug("sending request 4"); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request4, request4_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[5]); - if ((PacketAlertCheck(p[5], 1))) { - printf("sid 1 matched but shouldn't have for packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 2))) { - printf("sid 2 matched but shouldn't have for packet 5: "); - goto end; - } - if (!(PacketAlertCheck(p[5], 3))) { - printf("sid 3 didn't match but should have packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 4))) { - printf("sid 4 matched but shouldn't have for packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 5))) { - printf("sid 5 matched but shouldn't have for packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 6))) { - printf("sid 6 matched but shouldn't have for packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 7))) { - printf("sid 7 matched but shouldn't have for packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 8))) { - printf("sid 8 matched but shouldn't have for packet 5: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request5, request5_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[6]); - if ((PacketAlertCheck(p[6], 1))) { - printf("sid 1 matched but shouldn't have for packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 2))) { - printf("sid 2 matched but shouldn't have for packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 3))) { - printf("sid 3 matched but shouldn't have for packet 6: "); - goto end; - } - if (!(PacketAlertCheck(p[6], 4))) { - printf("sid 4 didn't match but should have packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 5))) { - printf("sid 5 matched but shouldn't have for packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 6))) { - printf("sid 6 matched but shouldn't have for packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 7))) { - printf("sid 7 matched but shouldn't have for packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 8))) { - printf("sid 8 matched but shouldn't have for packet 6: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request6, request6_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[7]); - if ((PacketAlertCheck(p[7], 1))) { - printf("sid 1 matched but shouldn't have for packet 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 2))) { - printf("sid 2 matched but shouldn't have for packet 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 3))) { - printf("sid 3 matched but shouldn't have for packet 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 4))) { - printf("sid 4 matched but shouldn't have for packet 7: "); - goto end; - } - if (!(PacketAlertCheck(p[7], 5))) { - printf("sid 5 didn't match but should have paket 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 6))) { - printf("sid 6 matched but shouldn't have for packet 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 7))) { - printf("sid 7 matched but shouldn't have for packet 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 8))) { - printf("sid 8 matched but shouldn't have for packet 7: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request7, request7_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[8]); - if ((PacketAlertCheck(p[8], 1))) { - printf("sid 1 matched but shouldn't have for packet 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 2))) { - printf("sid 2 matched but shouldn't have for packet 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 3))) { - printf("sid 3 matched but shouldn't have for packet 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 4))) { - printf("sid 4 matched but shouldn't have for packet 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 5))) { - printf("sid 5 matched but shouldn't have for packet 8: "); - goto end; - } - if (!(PacketAlertCheck(p[8], 6))) { - printf("sid 6 didn't match but should have paket 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 7))) { - printf("sid 7 matched but shouldn't have for packet 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 8))) { - printf("sid 8 matched but shouldn't have for packet 8: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request8, request8_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[9]); - if ((PacketAlertCheck(p[9], 1))) { - printf("sid 1 matched but shouldn't have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 2))) { - printf("sid 2 matched but shouldn't have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 3))) { - printf("sid 3 matched but shouldn't have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 4))) { - printf("sid 4 matched but shouldn't have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 5))) { - printf("sid 5 matched but shouldn't have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 6))) { - printf("sid 6 matched but shouldn't have for packet 9: "); - goto end; - } - if (!(PacketAlertCheck(p[9], 7))) { - printf("sid 7 didn't match but should have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 8))) { - printf("sid 8 matched but shouldn't have for packet 9: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request9, request9_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[10]); - if ((PacketAlertCheck(p[10], 1))) { - printf("sid 1 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 2))) { - printf("sid 2 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 3))) { - printf("sid 3 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 4))) { - printf("sid 4 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 5))) { - printf("sid 5 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 6))) { - printf("sid 6 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 7))) { - printf("sid 7 matched but shouldn't have for packet 10: "); - goto end; - } - if (!(PacketAlertCheck(p[10], 8))) { - printf("sid 8 didn't match but should have for paket 10: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 11); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -static int DcePayloadTest02(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "dce_stub_data; content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - p[1]->flowflags &=~ FLOW_PKT_TOSERVER; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (PacketAlertCheck(p[0], 1)) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - if (PacketAlertCheck(p[0], 2)) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if (!(PacketAlertCheck(p[2], 1))) { - printf("sid 1 didn't match but should have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - if (!(PacketAlertCheck(p[3], 2))) { - printf("sid 2 didn't match but should have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -static int DcePayloadTest03(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef4; " - "dce_stub_data; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if ((PacketAlertCheck(p[2], 1))) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - if (!(PacketAlertCheck(p[3], 2))) { - printf("sid 2 didn't match but should have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -static int DcePayloadTest04(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; content:\"|91 27 27 40|\"; distance:0; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if (!(PacketAlertCheck(p[2], 1))) { - printf("sid 1 didn't match but should have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - if (!(PacketAlertCheck(p[3], 2))) { - printf("sid 2 didn't match but should have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -static int DcePayloadTest05(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef4; " - "dce_stub_data; content:\"|91 27 27 40|\"; distance:0; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "dce_stub_data; content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if ((PacketAlertCheck(p[2], 1))) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 2 matched but shouldn't have for packet 3: "); - goto end; - } - if (!(PacketAlertCheck(p[3], 2))) { - printf("sid 2 didn't match but should have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -static int DcePayloadTest06(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; content:\"|91 27 27 30|\"; distance:0; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if ((PacketAlertCheck(p[2], 1))) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - if (!(PacketAlertCheck(p[3], 2))) { - printf("sid 2 didn't match but should have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -static int DcePayloadTest07(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; content:\"|91 27 27 30|\"; distance:0; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|2d 5e 63 35 25|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if ((PacketAlertCheck(p[2], 1))) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 2))) { - printf("sid 2 matched but shouldn't have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Positive test, to test the working of distance and within. - */ -static int DcePayloadTest08(void) -{ -#if 0 - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - TcpSession ssn; - Packet *p[1]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5d 5b 35|\"; distance:0; content:\"|9e a3|\"; " - "distance:0; within:2; sid:1;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 1; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (!(PacketAlertCheck(p[0], 1))) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 1); - return result; -#else - return 1; -#endif -} - -/** - * \test Positive test, to test the working of distance and within. - */ -static int DcePayloadTest09(void) -{ -#if 0 - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x5d, 0x5b, 0x35, 0x46, 0x9e, 0xa3, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - TcpSession ssn; - Packet *p[1]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5d 5b 35|\"; distance:0; content:\"|9e a3|\"; " - "distance:0; within:2; sid:1;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 1; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (!(PacketAlertCheck(p[0], 1))) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 1); - return result; -#else - return 1; -#endif -} - -/** - * \test Positive test, to test the working of distance and within. - */ -static int DcePayloadTest10(void) -{ -#if 0 - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x5d, 0x5b, 0x35, 0x46, 0x9e, 0xa3, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - TcpSession ssn; - Packet *p[1]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|ad 0d|\"; distance:0; content:\"|ad 0d 00|\"; " - "distance:-10; within:3; sid:1;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 1; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (!(PacketAlertCheck(p[0], 1))) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 1); - return result; -#else - return 1; -#endif -} - -/** - * \test Postive test to check the working of disance and within across frags. - */ -static int DcePayloadTest11(void) -{ -#if 0 - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - TcpSession ssn; - Packet *p[2]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|af, 26, d0|\"; distance:0; content:\"|80 98 6d|\"; " - "distance:1; within:3; sid:1;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 2; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if (!(PacketAlertCheck(p[1], 1))) { - printf("sid 1 didn't match but should have for pacekt 1: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 2); - return result; -#else - return 1; -#endif -} - -/** - * \test Negative test the working of contents on stub data with invalid - * distance. - */ -static int DcePayloadTest12(void) -{ -#if 0 /* payload ticks off clamav */ - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - TcpSession ssn; - Packet *p[2]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|af, 26, d0|\"; distance:0; content:\"|80 98 6d|\"; " - "distance:2; within:3; sid:1;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 2; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 2); - return result; -#else - return 1; -#endif -} - -/* Disabled because of bug_753. Would be enabled, once we rewrite - * dce parser */ -#if 0 - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -static int DcePayloadTest13(void) -{ - int result = 0; - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x02, - }; - uint32_t request1_len = sizeof(request1); - - uint8_t response1[] = { - 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, - 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, - 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, - }; - uint32_t response1_len = sizeof(response1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, - 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, - 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, - 0x29, 0x87, 0xea, 0xe9, 0x5c, 0x00, 0x5c, 0x00, - 0xa8, 0xb9, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x54, 0x00, - 0x57, 0x00, 0x41, 0x00, 0x52, 0x00, 0x45, 0x00, - 0x5c, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, - 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, - 0x66, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x57, 0x00, - 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, - 0x77, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x43, 0x00, - 0x75, 0x00, 0x72, 0x00, 0x72, 0x00, 0x65, 0x00, - 0x6e, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, - 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, - 0x6e, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x75, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, - }; - uint32_t request2_len = sizeof(request2); - - uint8_t response2[] = { - 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, - 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, - 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, - }; - uint32_t response2_len = sizeof(response2); - - uint8_t request3[] = { - 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, - 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, - 0x29, 0x87, 0xea, 0xe9, 0x0c, 0x00, 0x0c, 0x00, - 0x98, 0xda, 0x14, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x73, 0x00, 0x61, 0x00, 0x33, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00, - 0x4f, 0x00, 0x53, 0x00, 0x41, 0x00, 0x33, 0x00, - 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - }; - uint32_t request3_len = sizeof(request3); - - uint8_t response3[] = { - 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - }; - uint32_t response3_len = sizeof(response3); - - TcpSession ssn; - Packet *p[8]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|00 02|\"; sid:1;)"; - char *sig2 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|00 75|\"; sid:2;)"; - char *sig3 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|00 18|\"; sid:3;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - /* let the 7 and the 8th packet be dummy packets the client sends to the server */ - for (i = 0; i < 8; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - p[1]->flowflags &=~ FLOW_PKT_TOSERVER; - p[3]->flowflags |= FLOW_PKT_TOCLIENT; - p[3]->flowflags &=~ FLOW_PKT_TOSERVER; - p[5]->flowflags |= FLOW_PKT_TOCLIENT; - p[5]->flowflags &=~ FLOW_PKT_TOSERVER; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, sig1); - if (s == NULL) - goto end; - s = de_ctx->sig_list->next = SigInit(de_ctx, sig2); - if (s == NULL) - goto end; - s = de_ctx->sig_list->next->next = SigInit(de_ctx, sig3); - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (!PacketAlertCheck(p[0], 1) || PacketAlertCheck(p[0], 2) || PacketAlertCheck(p[0], 3)) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[6]); - if (PacketAlertCheck(p[6], 1) || PacketAlertCheck(p[6], 2) || PacketAlertCheck(p[6], 3)) { - printf("sid 1 matched but shouldn't have for packet 6: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response1, response1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if (PacketAlertCheck(p[1], 1) || PacketAlertCheck(p[1], 2) || PacketAlertCheck(p[1], 3)) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - /* we should have a match for the sig once again for the same flow, since - * the detection engine state for the flow has been reset because of a - * fresh transaction */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if (PacketAlertCheck(p[2], 1) || !PacketAlertCheck(p[2], 2) || PacketAlertCheck(p[2], 3)) { - printf("sid 1 didn't match but should have for packet 2: "); - goto end; - } - - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[7]); - if (PacketAlertCheck(p[7], 1) || PacketAlertCheck(p[7], 2) || PacketAlertCheck(p[7], 3)) { - printf("sid 1 matched but shouldn't have for packet 7: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response2, response2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if (PacketAlertCheck(p[3], 1) || PacketAlertCheck(p[3], 2) || PacketAlertCheck(p[3], 3)) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - /* we should have a match for the sig once again for the same flow, since - * the detection engine state for the flow has been reset because of a - * fresh transaction */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[4]); - if (PacketAlertCheck(p[4], 1) || PacketAlertCheck(p[4], 2) || !PacketAlertCheck(p[4], 3)) { - printf("sid 1 didn't match but should have for packet 4: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response3, response3_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[5]); - if (PacketAlertCheck(p[5], 1) || PacketAlertCheck(p[5], 2) || PacketAlertCheck(p[5], 3)) { - printf("sid 1 matched but shouldn't have for packet 5: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 8); - return result; -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -static int DcePayloadTest14(void) -{ - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, - 0x76, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x37, 0x00, - 0x31, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x31, 0x00, - 0x2e, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2e, 0x00, - 0x36, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x84, 0xf9, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x81, 0xbb, 0x7a, 0x36, 0x44, 0x98, 0xf1, 0x35, - 0xad, 0x32, 0x98, 0xf0, 0x38, 0x00, 0x10, 0x03, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x74, 0x73, 0x00, 0x00, - 0x0d, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6e, 0x74, 0x73, 0x76, 0x63, 0x73, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, - 0x64, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x5c, 0x5c, 0x31, 0x37, 0x31, 0x2e, 0x37, 0x31, - 0x2e, 0x38, 0x34, 0x2e, 0x36, 0x37, 0x00, 0x8a, - 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0f, 0x00 - }; - uint32_t request2_len = sizeof(request2); - - uint8_t response2[] = { - 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xd2, 0xc4, 0x88, 0x14, - 0xef, 0x31, 0xbb, 0x4d, 0xa8, 0x13, 0xb7, 0x1b, - 0x47, 0x49, 0xb5, 0xd7, 0x00, 0x00, 0x00, 0x00 - }; - uint32_t response2_len = sizeof(response2); - - TcpSession ssn; - Packet *p[6]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|7f 01|\"; sid:1;)"; - char *sig2 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|3f 00|\"; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 6; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[3]->flowflags |= FLOW_PKT_TOCLIENT; - p[3]->flowflags &=~ FLOW_PKT_TOSERVER; - p[5]->flowflags |= FLOW_PKT_TOCLIENT; - p[5]->flowflags &=~ FLOW_PKT_TOSERVER; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, sig1); - if (s == NULL) - goto end; - s = de_ctx->sig_list->next = SigInit(de_ctx, sig2); - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - /* request 1 */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (!PacketAlertCheck(p[0], 1) || PacketAlertCheck(p[0], 2)) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if (PacketAlertCheck(p[1], 1) || PacketAlertCheck(p[1], 2)) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - - /* bind */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if (PacketAlertCheck(p[2], 1) || PacketAlertCheck(p[2], 2)) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - - /* bind_ack. A new transaction initiation */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if (PacketAlertCheck(p[3], 1) || PacketAlertCheck(p[3], 2)) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - - /* we should have a match for the sig once again for the same flow, since - * the detection engine state for the flow has been reset because of a - * fresh transaction */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[4]); - if (PacketAlertCheck(p[4], 1) || !PacketAlertCheck(p[4], 2)) { - printf("sid 1 didn't match but should have for packet 4: "); - goto end; - } - - /* response */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response2, response2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[5]); - if (PacketAlertCheck(p[5], 1) || PacketAlertCheck(p[5], 2)) { - printf("sid 1 matched but shouldn't have for packet 5: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 6); - return result; -} - -#endif - /** * \test Test the working of byte_test endianness. */ @@ -10115,24 +3704,6 @@ void DcePayloadRegisterTests(void) g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); #ifdef UNITTESTS - UtRegisterTest("DcePayloadTest01", DcePayloadTest01); - UtRegisterTest("DcePayloadTest02", DcePayloadTest02); - UtRegisterTest("DcePayloadTest03", DcePayloadTest03); - UtRegisterTest("DcePayloadTest04", DcePayloadTest04); - UtRegisterTest("DcePayloadTest05", DcePayloadTest05); - UtRegisterTest("DcePayloadTest06", DcePayloadTest06); - UtRegisterTest("DcePayloadTest07", DcePayloadTest07); - UtRegisterTest("DcePayloadTest08", DcePayloadTest08); - UtRegisterTest("DcePayloadTest09", DcePayloadTest09); - UtRegisterTest("DcePayloadTest10", DcePayloadTest10); - UtRegisterTest("DcePayloadTest11", DcePayloadTest11); - UtRegisterTest("DcePayloadTest12", DcePayloadTest12); - /* Disabled because of bug_753. Would be enabled, once we rewrite - * dce parser */ -#if 0 - UtRegisterTest("DcePayloadTest13", DcePayloadTest13, 1); - UtRegisterTest("DcePayloadTest14", DcePayloadTest14, 1); -#endif UtRegisterTest("DcePayloadTest15", DcePayloadTest15); UtRegisterTest("DcePayloadTest16", DcePayloadTest16); UtRegisterTest("DcePayloadTest17", DcePayloadTest17); From 65317ba865bc498ca01c8a146d89b4504c75663d Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 19 Jan 2017 07:15:00 +0100 Subject: [PATCH 2460/2553] output-json: make JSON flags in eve-log user configurable --- src/output-json.c | 3 +-- src/util-logopenfile.c | 29 +++++++++++++++++++++++++++++ src/util-logopenfile.h | 3 +++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index 95f9b0167dbb..7b655f64ca8b 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -481,8 +481,7 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer) }; int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, - JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| - JSON_ESCAPE_SLASH); + file_ctx->json_flags); if (r != 0) return TM_ECODE_OK; diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 636aaab83f5d..da644f7912ca 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -256,6 +256,35 @@ SCConfLogOpenGeneric(ConfNode *conf, if (append == NULL) append = DEFAULT_LOG_MODE_APPEND; + /* JSON flags */ +#ifdef HAVE_LIBJANSSON + log_ctx->json_flags = JSON_PRESERVE_ORDER|JSON_COMPACT| + JSON_ENSURE_ASCII|JSON_ESCAPE_SLASH; + + ConfNode *json_flags = ConfNodeLookupChild(conf, "json"); + + if (json_flags != 0) { + const char *preserve_order = ConfNodeLookupChildValue(json_flags, + "preserve-order"); + if (preserve_order != NULL && ConfValIsFalse(preserve_order)) + log_ctx->json_flags &= ~(JSON_PRESERVE_ORDER); + + const char *compact = ConfNodeLookupChildValue(json_flags, "compact"); + if (compact != NULL && ConfValIsFalse(compact)) + log_ctx->json_flags &= ~(JSON_COMPACT); + + const char *ensure_ascii = ConfNodeLookupChildValue(json_flags, + "ensure-ascii"); + if (ensure_ascii != NULL && ConfValIsFalse(ensure_ascii)) + log_ctx->json_flags &= ~(JSON_ENSURE_ASCII); + + const char *escape_slash = ConfNodeLookupChildValue(json_flags, + "escape-slash"); + if (escape_slash != NULL && ConfValIsFalse(escape_slash)) + log_ctx->json_flags &= ~(JSON_ESCAPE_SLASH); + } +#endif /* HAVE_LIBJANSSON */ + // Now, what have we been asked to open? if (strcasecmp(filetype, "unix_stream") == 0) { /* Don't bail. May be able to connect later. */ diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index cccbba47d054..063e2bfb7452 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -118,6 +118,9 @@ typedef struct LogFileCtx_ { * allow for rotataion. */ uint8_t is_regular; + /* JSON flags */ + size_t json_flags; /* passed to json_dump_callback() */ + /* Flag set when file rotation notification is received. */ int rotation_flag; } LogFileCtx; From 6a382259f8093a5ed1b7c0377f7190db4cea2d9e Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 25 Jan 2017 14:11:49 +0100 Subject: [PATCH 2461/2553] doc: documentation for custom JSON flags in eve-log --- doc/userguide/output/eve/eve-json-output.rst | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/doc/userguide/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst index 104fc10b4643..a960e7e16cd9 100644 --- a/doc/userguide/output/eve/eve-json-output.rst +++ b/doc/userguide/output/eve/eve-json-output.rst @@ -246,3 +246,26 @@ For most output types, you can add multiple: Except for ``drop`` for which only a single logger instance is supported. +JSON flags +~~~~~~~~~~ + +Several flags can be specified to control the JSON output in EVE: + +:: + + outputs: + - eve-log: + json: + # Sort object keys in the same order as they were inserted + preserve-order: yes + + # Make the output more compact + compact: yes + + # Escape all unicode characters outside the ASCII range + ensure-ascii: yes + + # Escape the '/' characters in string with '\/' + escape-slash: yes + +All these flags are enabled by default, and can be modified per EVE instance. From 8c8db1cf0f8dccf0119300addfd2d6a51367e166 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 27 Jan 2017 10:19:01 +0100 Subject: [PATCH 2462/2553] output-json-alert: fix wrongful comments --- src/output-json-alert.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 258eeee9ffdd..031bebb17d7d 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -278,7 +278,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (p->flow != NULL) { uint16_t proto = FlowGetAppProtocol(p->flow); - /* http alert */ + /* tls alert */ if (proto == ALPROTO_TLS) AlertJsonTls(p->flow, js); } @@ -288,7 +288,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (p->flow != NULL) { uint16_t proto = FlowGetAppProtocol(p->flow); - /* http alert */ + /* ssh alert */ if (proto == ALPROTO_SSH) AlertJsonSsh(p->flow, js); } @@ -298,7 +298,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (p->flow != NULL) { uint16_t proto = FlowGetAppProtocol(p->flow); - /* http alert */ + /* smtp alert */ if (proto == ALPROTO_SMTP) { hjs = JsonSMTPAddMetadata(p->flow, pa->tx_id); if (hjs) @@ -314,6 +314,8 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (json_output_ctx->flags & LOG_JSON_DNP3) { if (p->flow != NULL) { uint16_t proto = FlowGetAppProtocol(p->flow); + + /* dnp3 alert */ if (proto == ALPROTO_DNP3) { AlertJsonDnp3(p->flow, js); } From 7293286f2fab12cd674d29d0a5559de03954aa09 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 27 Jan 2017 12:42:08 +0100 Subject: [PATCH 2463/2553] output-json: move code to get 5-tuple to own function Move code to get 5-tuple in JSON object to own function 'JsonFiveTuple'. This enables this code to be reused when printing 'parent' JSON object in output-json-alert. --- src/output-json.c | 142 ++++++++++++++++++++++++++++------------------ src/output-json.h | 1 + 2 files changed, 88 insertions(+), 55 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index 7b655f64ca8b..7b0a1f99a07c 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -280,73 +280,123 @@ void JsonTcpFlags(uint8_t flags, json_t *js) json_object_set_new(js, "cwr", json_true()); } -void CreateJSONFlowId(json_t *js, const Flow *f) -{ - if (f == NULL) - return; - int64_t flow_id = FlowGetId(f); - /* reduce to 51 bits as Javascript and even JSON often seem to - * max out there. */ - flow_id &= 0x7ffffffffffffLL; - json_object_set_new(js, "flow_id", json_integer(flow_id)); -} - -json_t *CreateJSONHeader(const Packet *p, int direction_sensitive, - const char *event_type) +/** + * \brief Add five tuple from packet to JSON object + * + * \param p Packet + * \param direction_sensitive Indicate direction sensitivity + * \param js JSON object + */ +void JsonFiveTuple(const Packet *p, int direction_sensitive, json_t *js) { - char timebuf[64]; char srcip[46], dstip[46]; Port sp, dp; - - json_t *js = json_object(); - if (unlikely(js == NULL)) - return NULL; - - CreateIsoTimeString(&p->ts, timebuf, sizeof(timebuf)); + char proto[16]; srcip[0] = '\0'; dstip[0] = '\0'; + if (direction_sensitive) { if ((PKT_IS_TOSERVER(p))) { if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), + dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), + dstip, sizeof(dstip)); } sp = p->sp; dp = p->dp; } else { if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), + dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), + dstip, sizeof(dstip)); } sp = p->dp; dp = p->sp; } } else { if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), + dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), + dstip, sizeof(dstip)); } sp = p->sp; dp = p->dp; } - char proto[16]; if (SCProtoNameValid(IP_GET_IPPROTO(p)) == TRUE) { strlcpy(proto, known_proto[IP_GET_IPPROTO(p)], sizeof(proto)); } else { snprintf(proto, sizeof(proto), "%03" PRIu32, IP_GET_IPPROTO(p)); } + json_object_set_new(js, "src_ip", json_string(srcip)); + + switch(p->proto) { + case IPPROTO_ICMP: + break; + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + json_object_set_new(js, "src_port", json_integer(sp)); + break; + } + + json_object_set_new(js, "dest_ip", json_string(dstip)); + + switch(p->proto) { + case IPPROTO_ICMP: + break; + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + json_object_set_new(js, "dest_port", json_integer(dp)); + break; + } + + json_object_set_new(js, "proto", json_string(proto)); +} + +void CreateJSONFlowId(json_t *js, const Flow *f) +{ + if (f == NULL) + return; + int64_t flow_id = FlowGetId(f); + /* reduce to 51 bits as Javascript and even JSON often seem to + * max out there. */ + flow_id &= 0x7ffffffffffffLL; + json_object_set_new(js, "flow_id", json_integer(flow_id)); +} + +json_t *CreateJSONHeader(const Packet *p, int direction_sensitive, + const char *event_type) +{ + char timebuf[64]; + + json_t *js = json_object(); + if (unlikely(js == NULL)) + return NULL; + + CreateIsoTimeString(&p->ts, timebuf, sizeof(timebuf)); + /* time & tx */ json_object_set_new(js, "timestamp", json_string(timebuf)); @@ -394,28 +444,10 @@ json_t *CreateJSONHeader(const Packet *p, int direction_sensitive, } } - /* tuple */ - json_object_set_new(js, "src_ip", json_string(srcip)); - switch(p->proto) { - case IPPROTO_ICMP: - break; - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_SCTP: - json_object_set_new(js, "src_port", json_integer(sp)); - break; - } - json_object_set_new(js, "dest_ip", json_string(dstip)); - switch(p->proto) { - case IPPROTO_ICMP: - break; - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_SCTP: - json_object_set_new(js, "dest_port", json_integer(dp)); - break; - } - json_object_set_new(js, "proto", json_string(proto)); + /* 5-tuple */ + JsonFiveTuple(p, direction_sensitive, js); + + /* icmp */ switch (p->proto) { case IPPROTO_ICMP: if (p->icmpv4h) { diff --git a/src/output-json.h b/src/output-json.h index c65454921940..5f42e7657a49 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -42,6 +42,7 @@ int OutputJSONMemBufferCallback(const char *str, size_t size, void *data); void JsonAddVars(const Packet *p, const Flow *f, json_t *js); void CreateJSONFlowId(json_t *js, const Flow *f); void JsonTcpFlags(uint8_t flags, json_t *js); +void JsonFiveTuple(const Packet *, int, json_t *); json_t *CreateJSONHeader(const Packet *p, int direction_sensative, const char *event_type); json_t *CreateJSONHeaderWithTxId(const Packet *p, int direction_sensitive, const char *event_type, uint64_t tx_id); int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer); From 234a3a890bb16141d5fb67b12e239ad52c7edf4c Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 27 Jan 2017 12:50:08 +0100 Subject: [PATCH 2464/2553] output-json-alert: print 'tunnel' JSON object if tunnel Log src_ip, dst_ip and proto for root packet (p->root) if the packet that triggered is inside a tunnel, as JSON object 'tunnel'. Also log recursion depth to indicate the depth of the tunnel. --- src/output-json-alert.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 031bebb17d7d..135ee618edcb 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -218,6 +218,29 @@ void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js) json_object_set_new(js, "alert", ajs); } +static void AlertJsonTunnel(const Packet *p, json_t *js) +{ + json_t *tunnel = json_object(); + if (tunnel == NULL) + return; + + if (p->root == NULL) { + json_decref(tunnel); + return; + } + + /* get a lock to access root packet fields */ + SCMutex *m = &p->root->tunnel_mutex; + + SCMutexLock(m); + JsonFiveTuple((const Packet *)p->root, 0, tunnel); + SCMutexUnlock(m); + + json_object_set_new(tunnel, "depth", json_integer(p->recursion_level)); + + json_object_set_new(js, "tunnel", tunnel); +} + static void AlertJsonPacket(const Packet *p, json_t *js) { unsigned long len = GET_PKT_LEN(p) * 2; @@ -261,6 +284,10 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) /* alert */ AlertJsonHeader(p, pa, js); + if (IS_TUNNEL_PKT(p)) { + AlertJsonTunnel(p, js); + } + if (json_output_ctx->flags & LOG_JSON_HTTP) { if (p->flow != NULL) { uint16_t proto = FlowGetAppProtocol(p->flow); From c810748a60295dab22fa504bf151984244a0ffd7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 16 Feb 2017 13:02:58 -0600 Subject: [PATCH 2465/2553] Makefile: fix race condition in make install-full Use recursive make for the install process so it is executed in a predictable order. Addresses issue: https://redmine.openinfosecfoundation.org/issues/1470 which triggered on OSX/macOS. --- Makefile.am | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index b265b6f2dc5a..d33150fff3b2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,7 +12,10 @@ CLEANFILES = stamp-h[0-9]* install-data-am: @echo "Run 'make install-conf' if you want to install initial configuration files. Or 'make install-full' to install configuration and rules"; -install-full: install install-conf install-rules +install-full: + $(MAKE) install + $(MAKE) install-conf + $(MAKE) install-rules install-conf: install -d "$(DESTDIR)$(e_sysconfdir)" From d8e9e1fd77b1ab47a2a455cc88ea38d74876f76c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 16 Jan 2017 14:45:32 -0600 Subject: [PATCH 2466/2553] unified2: minor cleanups - remove unused arguments and make static --- src/alert-unified2-alert.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 2628676fa644..5f2db257fe72 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -244,11 +244,9 @@ void Unified2AlertRegister(void) /** * \brief Function to close unified2 file * - * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param aun Unified2 thread variable. */ - -int Unified2AlertCloseFile(ThreadVars *t, Unified2AlertThread *aun) +static int Unified2AlertCloseFile(Unified2AlertThread *aun) { if (aun->unified2alert_ctx->file_ctx->fp != NULL) { fclose(aun->unified2alert_ctx->file_ctx->fp); @@ -261,15 +259,13 @@ int Unified2AlertCloseFile(ThreadVars *t, Unified2AlertThread *aun) /** * \brief Function to rotate unified2 file * - * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param aun Unified2 thread variable. * \retval 0 on succces * \retval -1 on failure */ - -int Unified2AlertRotateFile(ThreadVars *t, Unified2AlertThread *aun) +static int Unified2AlertRotateFile(Unified2AlertThread *aun) { - if (Unified2AlertCloseFile(t,aun) < 0) { + if (Unified2AlertCloseFile(aun) < 0) { SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Error: Unified2AlertCloseFile failed"); return -1; @@ -928,7 +924,7 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) SCMutexLock(&aun->unified2alert_ctx->file_ctx->fp_mutex); if ((aun->unified2alert_ctx->file_ctx->size_current + length) > aun->unified2alert_ctx->file_ctx->size_limit) { - if (Unified2AlertRotateFile(t,aun) < 0) { + if (Unified2AlertRotateFile(aun) < 0) { aun->unified2alert_ctx->file_ctx->alerts += i; SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); return -1; @@ -1105,7 +1101,7 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) if ((aun->unified2alert_ctx->file_ctx->size_current + length) > aun->unified2alert_ctx->file_ctx->size_limit) { - if (Unified2AlertRotateFile(tv,aun) < 0) { + if (Unified2AlertRotateFile(aun) < 0) { aun->unified2alert_ctx->file_ctx->alerts += i; SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); return -1; @@ -1920,7 +1916,7 @@ static int Unified2TestRotate01(void) TimeSetIncrementTime(1); - ret = Unified2AlertRotateFile(&tv, data); + ret = Unified2AlertRotateFile(data); if (ret == -1) goto error; From 2c01985e731d97eafb4b644cd78641197093f859 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 16 Jan 2017 16:02:43 -0600 Subject: [PATCH 2467/2553] autoconf - look for stdbool.h --- configure.ac | 2 +- src/suricata-common.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 9129c5fe77ed..57e7253a9baf 100644 --- a/configure.ac +++ b/configure.ac @@ -126,7 +126,7 @@ AC_CHECK_HEADERS([arpa/inet.h assert.h ctype.h errno.h fcntl.h inttypes.h]) AC_CHECK_HEADERS([getopt.h]) AC_CHECK_HEADERS([limits.h netdb.h netinet/in.h poll.h sched.h signal.h]) - AC_CHECK_HEADERS([stdarg.h stdint.h stdio.h stdlib.h string.h strings.h sys/ioctl.h]) + AC_CHECK_HEADERS([stdarg.h stdint.h stdio.h stdlib.h stdbool.h string.h strings.h sys/ioctl.h]) AC_CHECK_HEADERS([syslog.h sys/prctl.h sys/socket.h sys/stat.h sys/syscall.h]) AC_CHECK_HEADERS([sys/time.h time.h unistd.h]) AC_CHECK_HEADERS([sys/ioctl.h linux/if_ether.h linux/if_packet.h linux/filter.h]) diff --git a/src/suricata-common.h b/src/suricata-common.h index 05e0d7f39c0b..7fd68886d848 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -57,6 +57,10 @@ #include #endif +#if HAVE_STDBOOL_H +#include +#endif + #if HAVE_STDARG_H #include #endif From 82f61031499c40b09afd9469a6a042a1c3ce482d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 16 Jan 2017 16:25:56 -0600 Subject: [PATCH 2468/2553] unified2: nostamp and file rotation Give unified2 a nostamp option which will create the file without the timestamp suffix (like Snort's nostamp option). Also register for rotation notification on SIGHUP so the file will be recreated if it is removed by an external rotation program (only when nostamp is used). --- src/alert-unified2-alert.c | 79 ++++++++++++++++++++++++++------------ src/util-logopenfile.h | 3 ++ suricata.yaml.in | 5 +++ 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 5f2db257fe72..1a6f5f567bf0 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -225,7 +225,7 @@ static int Unified2IPv4TypeAlert(ThreadVars *, const Packet *, void *); static int Unified2IPv6TypeAlert(ThreadVars *, const Packet *, void *); static int Unified2PacketTypeAlert(Unified2AlertThread *, const Packet *, uint32_t, int); void Unified2RegisterTests(void); -int Unified2AlertOpenFileCtx(LogFileCtx *, const char *); +static int Unified2AlertOpenFileCtx(LogFileCtx *, const char *, bool); static void Unified2AlertDeInitCtx(OutputCtx *); int Unified2Condition(ThreadVars *tv, const Packet *p); @@ -263,15 +263,15 @@ static int Unified2AlertCloseFile(Unified2AlertThread *aun) * \retval 0 on succces * \retval -1 on failure */ -static int Unified2AlertRotateFile(Unified2AlertThread *aun) +static int Unified2AlertRotateFile(Unified2AlertThread *aun, bool truncate) { if (Unified2AlertCloseFile(aun) < 0) { SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Error: Unified2AlertCloseFile failed"); return -1; } - if (Unified2AlertOpenFileCtx(aun->unified2alert_ctx->file_ctx,aun->unified2alert_ctx-> - file_ctx->prefix) < 0) { + if (Unified2AlertOpenFileCtx(aun->unified2alert_ctx->file_ctx, + aun->unified2alert_ctx->file_ctx->prefix, truncate) < 0) { SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Error: Unified2AlertOpenFileCtx, open new log file failed"); return -1; @@ -787,6 +787,7 @@ static int Unified2PacketTypeAlert(Unified2AlertThread *aun, const Packet *p, ui static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) { Unified2AlertThread *aun = (Unified2AlertThread *)data; + LogFileCtx *file_ctx = aun->unified2alert_ctx->file_ctx; Unified2AlertFileHeader hdr; AlertIPv6Unified2 *phdr; AlertIPv6Unified2 gphdr; @@ -921,19 +922,22 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) phdr->classification_id = htonl(pa->s->class); phdr->priority_id = htonl(pa->s->prio); - SCMutexLock(&aun->unified2alert_ctx->file_ctx->fp_mutex); - if ((aun->unified2alert_ctx->file_ctx->size_current + length) > - aun->unified2alert_ctx->file_ctx->size_limit) { - if (Unified2AlertRotateFile(aun) < 0) { + SCMutexLock(&file_ctx->fp_mutex); + + bool truncate = (file_ctx->size_current + length) > file_ctx->size_limit + ? true : false; + if (truncate || file_ctx->rotation_flag) { + if (Unified2AlertRotateFile(aun, truncate) < 0) { aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } + file_ctx->rotation_flag = 0; } if (Unified2Write(aun) != 1) { - aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + file_ctx->alerts += i; + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } @@ -972,6 +976,7 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) { Unified2AlertThread *aun = (Unified2AlertThread *)data; + LogFileCtx *file_ctx = aun->unified2alert_ctx->file_ctx; Unified2AlertFileHeader hdr; AlertIPv4Unified2 *phdr; AlertIPv4Unified2 gphdr; @@ -1097,20 +1102,22 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) phdr->priority_id = htonl(pa->s->prio); /* check and enforce the filesize limit */ - SCMutexLock(&aun->unified2alert_ctx->file_ctx->fp_mutex); - - if ((aun->unified2alert_ctx->file_ctx->size_current + length) > - aun->unified2alert_ctx->file_ctx->size_limit) { - if (Unified2AlertRotateFile(aun) < 0) { - aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexLock(&file_ctx->fp_mutex); + + bool truncate = (file_ctx->size_current + length) > file_ctx->size_limit + ? true : false; + if (truncate || file_ctx->rotation_flag) { + if (Unified2AlertRotateFile(aun, truncate) < 0) { + file_ctx->alerts += i; + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } + file_ctx->rotation_flag = 0; } if (Unified2Write(aun) != 1) { - aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + file_ctx->alerts += i; + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } @@ -1226,6 +1233,7 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) LogFileCtx* file_ctx = NULL; OutputCtx* output_ctx = NULL; HttpXFFCfg *xff_cfg = NULL; + int nostamp = 0; file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { @@ -1279,6 +1287,13 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) exit(EXIT_FAILURE); } } + + if (ConfGetChildValueBool(conf, "nostamp", &nostamp)) { + if (nostamp) { + SCLogConfig("Disabling unified2 timestamp."); + file_ctx->nostamp = true; + } + } } uint32_t flags = UNIFIED2_ALERT_FLAGS_EMIT_PACKET; @@ -1295,10 +1310,15 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) } } - ret = Unified2AlertOpenFileCtx(file_ctx, filename); + ret = Unified2AlertOpenFileCtx(file_ctx, filename, false); if (ret < 0) goto error; + /* Only register for file rotation if theout is non-timestamped. */ + if (nostamp) { + OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); + } + output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) goto error; @@ -1367,7 +1387,8 @@ static void Unified2AlertDeInitCtx(OutputCtx *output_ctx) * \param prefix Prefix of the log file. * \return -1 if failure, 0 if succesful * */ -int Unified2AlertOpenFileCtx(LogFileCtx *file_ctx, const char *prefix) +static int Unified2AlertOpenFileCtx(LogFileCtx *file_ctx, const char *prefix, + bool truncate) { int ret = 0; char *filename = NULL; @@ -1396,9 +1417,17 @@ int Unified2AlertOpenFileCtx(LogFileCtx *file_ctx, const char *prefix) char *log_dir; log_dir = ConfigGetLogDirectory(); - snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, log_dir, prefix, (uint32_t)ts.tv_sec); + if (file_ctx->nostamp) { + snprintf(filename, PATH_MAX, "%s/%s", log_dir, prefix); + } else { + snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, log_dir, prefix, (uint32_t)ts.tv_sec); + } - file_ctx->fp = fopen(filename, "ab"); + if (truncate) { + file_ctx->fp = fopen(filename, "wb"); + } else { + file_ctx->fp = fopen(filename, "ab"); + } if (file_ctx->fp == NULL) { SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", filename, strerror(errno)); @@ -1916,7 +1945,7 @@ static int Unified2TestRotate01(void) TimeSetIncrementTime(1); - ret = Unified2AlertRotateFile(data); + ret = Unified2AlertRotateFile(data, false); if (ret == -1) goto error; diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 063e2bfb7452..df423c8babc0 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -123,6 +123,9 @@ typedef struct LogFileCtx_ { /* Flag set when file rotation notification is received. */ int rotation_flag; + + /* Set to true if the filename should not be timestamped. */ + bool nostamp; } LogFileCtx; /* Min time (msecs) before trying to reconnect a Unix domain socket */ diff --git a/suricata.yaml.in b/suricata.yaml.in index 95f341bcf6bb..6c5ee19758a8 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -250,6 +250,11 @@ outputs: # is parsed as bytes. #limit: 32mb + # By default unified2 log files have the file creation time (in + # unix epoch format) appended to the filename. Set this to yes to + # disable this behaviour. + #nostamp: no + # Sensor ID field of unified2 alerts. #sensor-id: 0 From 89ba5816dc303d54741bdfd0a3896c7c1ce50d91 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 17 Jan 2017 00:33:17 -0600 Subject: [PATCH 2469/2553] doc: update unified2 section Remove documentation on older unified formats that have been removed. --- doc/userguide/configuration/suricata-yaml.rst | 109 +++++++++--------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index 8feee0f5383e..363114ef2e1c 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -359,66 +359,71 @@ For more advanced configuration options, see :ref:`Eve JSON Output `. -Log output for use with Barnyard (unified.log) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This log only supports IPv4. Its information will be stored in the -default logging directory. This log is designed to be stored in a -binary format on the hard disc, where it will be further processed by -Barnyard. Barnyard can store the output in a database, so Suricata can -work on other important tasks. Barnyard can add the files in the -Mysql-database, send them to Sguil or several other output options. - -There is a size-limit to the log-file: If Suricata generates an alert, -it stores this alert in a unified-file. Suricata keeps continuing -doing that, until the file has reached its limit. Which in the default -case is at 32 MB. At that point Suricata generates a new file and the -process starts all over again. Barnyard keeps on processing these -files. To prevent Suricata from filling up the hard disc, a size limit -is enforced. When the limit is reached, the file will 'role-over', -creating a new file. Barnyard removes old files. To every file, -Suricata adds a time stamp, so it is easy to see which one came first -and which one is the latter. - -:: +Alert output for use with Barnyard2 (unified2.alert) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Unified-log: #The log-name. - enabled: no #This log is not enabled. Set 'yes' to enable. - filename: unified.log #The name of the file in the default logging directory. - limit: 32 #The file size limit in megabytes. +This log format is a binary format compatible with the unified2 output +of another popular IDS format and is designed for use with Barnyard2 +or other tools that consume the unified2 log format. -This output option has been removed in Suricata 1.1rc1 (see ticket -#353). +By default a file with the given filename and a timestamp (unix epoch +format) will be created until the file hits the configured size limit, +then a new file, with a new timestamp will be created. It is the job +of other tools, such as Barnyard2 to cleanup old unified2 files. -Alert output for use with Barnyard (unified.alert) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If the `nostamp` option is set the log file will not have a timestamp +appended. The file will be re-opened on SIGHUP like other log files +allowing external log rotation tools to work as expected. However, if +the limit is reach the file will be deleted and re-opened. -This log only supports IPv4. Its information will be stored in the -default logging directory. For further information read the above -information about ( 2) unified.log) +This output supports IPv6 and IPv4 events. :: - -Unified-alert: #The log-name. - enabled: no #This log is not enabled. Set 'yes' to enable. - filename: unified.alert #The name of the file in the default logging directory. - limit: 32 #The file size limit in megabytes. - -This output option has been removed in Suricata 1.1rc1 (see ticket #353). - -Alert output for use with Barnyard2 (unified2.alert) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This log also supports IPv6 in addition to IPv4. It's information will -be stored in the default logging directory. For further information -read the above information about 2. unified.log. - -:: + - unified2-alert: + enabled: yes - - unified2-alert: #The log-name. - enabled: yes #This log is enabled. Set 'no' to disable. - filename: unified2.alert #The name of the file in the default logging directory. - limit: 32 #The file size limit in megabytes. + # The filename to log to in the default log directory. A + # timestamp in unix epoch time will be appended to the filename + # unless nostamp is set to yes. + filename: unified2.alert + + # File size limit. Can be specified in kb, mb, gb. Just a number + # is parsed as bytes. + #limit: 32mb + + # By default unified2 log files have the file creation time (in + # unix epoch format) appended to the filename. Set this to yes to + # disable this behaviour. + #nostamp: no + + # Sensor ID field of unified2 alerts. + #sensor-id: 0 + + # Include payload of packets related to alerts. Defaults to true, set to + # false if payload is not required. + #payload: yes + + # HTTP X-Forwarded-For support by adding the unified2 extra header or + # overwriting the source or destination IP address (depending on flow + # direction) with the one reported in the X-Forwarded-For HTTP header. + # This is helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. + xff: + enabled: no + # Two operation modes are available, "extra-data" and "overwrite". Note + # that in the "overwrite" mode, if the reported IP address in the HTTP + # X-Forwarded-For header is of a different version of the packet + # received, it will fall-back to "extra-data" mode. + mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For This alert output needs Barnyard2. From 0716199acb3894ca71fce777ac9614c5f81a7e9d Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Thu, 22 Dec 2016 11:36:19 +0100 Subject: [PATCH 2470/2553] output-json-tls: custom tls logging --- src/output-json-tls.c | 231 ++++++++++++++++++++++++++++++++---------- suricata.yaml.in | 3 + 2 files changed, 182 insertions(+), 52 deletions(-) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 0f75547c9cad..485defc4b9b1 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -57,10 +57,36 @@ SC_ATOMIC_DECLARE(unsigned int, cert_id); #define LOG_TLS_DEFAULT 0 #define LOG_TLS_EXTENDED (1 << 0) +#define LOG_TLS_CUSTOM (1 << 1) + +#define LOG_TLS_FIELD_VERSION (1 << 0) +#define LOG_TLS_FIELD_SUBJECT (1 << 1) +#define LOG_TLS_FIELD_ISSUER (1 << 2) +#define LOG_TLS_FIELD_FINGERPRINT (1 << 3) +#define LOG_TLS_FIELD_NOTBEFORE (1 << 4) +#define LOG_TLS_FIELD_NOTAFTER (1 << 5) +#define LOG_TLS_FIELD_SNI (1 << 6) + +typedef struct { + char *name; + uint64_t flag; +} TlsFields; + +TlsFields tls_fields[] = { + { "version", LOG_TLS_FIELD_VERSION }, + { "subject", LOG_TLS_FIELD_SUBJECT }, + { "issuer", LOG_TLS_FIELD_ISSUER }, + { "fingerprint", LOG_TLS_FIELD_FINGERPRINT }, + { "not_before", LOG_TLS_FIELD_NOTBEFORE }, + { "not_after", LOG_TLS_FIELD_NOTAFTER }, + { "sni", LOG_TLS_FIELD_SNI }, + { NULL, -1 } +}; typedef struct OutputTlsCtx_ { LogFileCtx *file_ctx; - uint32_t flags; /** Store mode */ + uint32_t flags; /** Store mode */ + uint64_t fields; /** Store fields */ } OutputTlsCtx; @@ -71,34 +97,37 @@ typedef struct JsonTlsLogThread_ { #define SSL_VERSION_LENGTH 13 -void JsonTlsLogJSONBasic(json_t *js, SSLState *ssl_state) +static void JsonTlsLogSubject(json_t *js, SSLState *ssl_state) { - /* tls.subject */ json_object_set_new(js, "subject", json_string(ssl_state->server_connp.cert0_subject)); +} - /* tls.issuerdn */ +static void JsonTlsLogIssuer(json_t *js, SSLState *ssl_state) +{ json_object_set_new(js, "issuerdn", json_string(ssl_state->server_connp.cert0_issuerdn)); - } -void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) +static void JsonTlsLogFingerprint(json_t *js, SSLState *ssl_state) { - char ssl_version[SSL_VERSION_LENGTH + 1]; - - /* tls.fingerprint */ - json_object_set_new(tjs, "fingerprint", - json_string(state->server_connp.cert0_fingerprint)); + json_object_set_new(js, "fingerprint", + json_string(ssl_state->server_connp.cert0_fingerprint)); +} - /* tls.sni */ - if (state->client_connp.sni) { - json_object_set_new(tjs, "sni", - json_string(state->client_connp.sni)); +static void JsonTlsLogSni(json_t *js, SSLState *ssl_state) +{ + if (ssl_state->client_connp.sni) { + json_object_set_new(js, "sni", + json_string(ssl_state->client_connp.sni)); } +} - /* tls.version */ - switch (state->server_connp.version) { +static void JsonTlsLogVersion(json_t *js, SSLState *ssl_state) +{ + char ssl_version[SSL_VERSION_LENGTH + 1]; + + switch (ssl_state->server_connp.version) { case TLS_VERSION_UNKNOWN: snprintf(ssl_version, SSL_VERSION_LENGTH, "UNDETERMINED"); break; @@ -119,32 +148,97 @@ void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) break; default: snprintf(ssl_version, SSL_VERSION_LENGTH, "0x%04x", - state->server_connp.version); + ssl_state->server_connp.version); break; } - json_object_set_new(tjs, "version", json_string(ssl_version)); + json_object_set_new(js, "version", json_string(ssl_version)); +} - /* tls.notbefore */ - if (state->server_connp.cert0_not_before != 0) { +static void JsonTlsLogNotBefore(json_t *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_not_before != 0) { char timebuf[64]; struct timeval tv; - tv.tv_sec = state->server_connp.cert0_not_before; + tv.tv_sec = ssl_state->server_connp.cert0_not_before; tv.tv_usec = 0; CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); - json_object_set_new(tjs, "notbefore", json_string(timebuf)); + json_object_set_new(js, "notbefore", json_string(timebuf)); } +} - /* tls.notafter */ - if (state->server_connp.cert0_not_after != 0) { +static void JsonTlsLogNotAfter(json_t *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_not_after != 0) { char timebuf[64]; struct timeval tv; - tv.tv_sec = state->server_connp.cert0_not_after; + tv.tv_sec = ssl_state->server_connp.cert0_not_after; tv.tv_usec = 0; CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); - json_object_set_new(tjs, "notafter", json_string(timebuf)); + json_object_set_new(js, "notafter", json_string(timebuf)); } } +void JsonTlsLogJSONBasic(json_t *js, SSLState *ssl_state) +{ + /* tls.subject */ + JsonTlsLogSubject(js, ssl_state); + + /* tls.issuerdn */ + JsonTlsLogIssuer(js, ssl_state); +} + +static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, json_t *js, + SSLState *ssl_state) +{ + /* tls.subject */ + if (tls_ctx->fields & LOG_TLS_FIELD_SUBJECT) + JsonTlsLogSubject(js, ssl_state); + + /* tls.issuerdn */ + if (tls_ctx->fields & LOG_TLS_FIELD_ISSUER) + JsonTlsLogIssuer(js, ssl_state); + + /* tls.fingerprint */ + if (tls_ctx->fields & LOG_TLS_FIELD_FINGERPRINT) + JsonTlsLogFingerprint(js, ssl_state); + + /* tls.sni */ + if (tls_ctx->fields & LOG_TLS_FIELD_SNI) + JsonTlsLogSni(js, ssl_state); + + /* tls.version */ + if (tls_ctx->fields & LOG_TLS_FIELD_VERSION) + JsonTlsLogVersion(js, ssl_state); + + /* tls.notbefore */ + if (tls_ctx->fields & LOG_TLS_FIELD_NOTBEFORE) + JsonTlsLogNotBefore(js, ssl_state); + + /* tls.notafter */ + if (tls_ctx->fields & LOG_TLS_FIELD_NOTAFTER) + JsonTlsLogNotAfter(js, ssl_state); +} + +void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) +{ + JsonTlsLogJSONBasic(tjs, state); + + /* tls.fingerprint */ + JsonTlsLogFingerprint(tjs, state); + + /* tls.sni */ + JsonTlsLogSni(tjs, state); + + /* tls.version */ + JsonTlsLogVersion(tjs, state); + + /* tls.notbefore */ + JsonTlsLogNotBefore(tjs, state); + + /* tls.notafter */ + JsonTlsLogNotAfter(tjs, state); +} + static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *txptr, uint64_t tx_id) { @@ -173,11 +267,18 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, /* reset */ MemBufferReset(aft->buffer); - JsonTlsLogJSONBasic(tjs, ssl_state); - - if (tls_ctx->flags & LOG_TLS_EXTENDED) { + /* log custom fields */ + if (tls_ctx->flags & LOG_TLS_CUSTOM) { + JsonTlsLogJSONCustom(tls_ctx, tjs, ssl_state); + } + /* log extended */ + else if (tls_ctx->flags & LOG_TLS_EXTENDED) { JsonTlsLogJSONExtended(tjs, ssl_state); } + /* log basic */ + else { + JsonTlsLogJSONBasic(tjs, ssl_state); + } json_object_set_new(js, "tls", tjs); @@ -240,6 +341,52 @@ static void OutputTlsLogDeinit(OutputCtx *output_ctx) SCFree(output_ctx); } +static OutputTlsCtx *OutputTlsInitCtx(ConfNode *conf) +{ + OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); + if (unlikely(tls_ctx == NULL)) + return NULL; + + tls_ctx->flags = LOG_TLS_DEFAULT; + tls_ctx->fields = 0; + + if (conf == NULL) + return tls_ctx; + + const char *extended = ConfNodeLookupChildValue(conf, "extended"); + if (extended) { + if (ConfValIsTrue(extended)) { + tls_ctx->flags = LOG_TLS_EXTENDED; + } + } + + ConfNode *custom = ConfNodeLookupChild(conf, "custom"); + if (custom) { + tls_ctx->flags = LOG_TLS_CUSTOM; + ConfNode *field; + TAILQ_FOREACH(field, &custom->head, next) + { + TlsFields *valid_fields = tls_fields; + for ( ; valid_fields->name != NULL; valid_fields++) { + if (strcasecmp(field->val, valid_fields->name) == 0) { + tls_ctx->fields |= valid_fields->flag; + break; + } + } + } + } + + if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) && + (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)) { + SCLogWarning(SC_WARN_DUPLICATE_OUTPUT, + "Both 'certificate' and 'chain' contains the top " + "certificate, so only one of them should be enabled " + "at a time"); + } + + return tls_ctx; +} + #define DEFAULT_LOG_FILENAME "tls.json" OutputCtx *OutputTlsLogInit(ConfNode *conf) { @@ -254,7 +401,7 @@ OutputCtx *OutputTlsLogInit(ConfNode *conf) return NULL; } - OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); + OutputTlsCtx *tls_ctx = OutputTlsInitCtx(conf); if (unlikely(tls_ctx == NULL)) { LogFileFreeCtx(file_ctx); return NULL; @@ -268,17 +415,7 @@ OutputCtx *OutputTlsLogInit(ConfNode *conf) } tls_ctx->file_ctx = file_ctx; - tls_ctx->flags = LOG_TLS_DEFAULT; - - if (conf) { - const char *extended = ConfNodeLookupChildValue(conf, "extended"); - if (extended != NULL) { - if (ConfValIsTrue(extended)) { - tls_ctx->flags = LOG_TLS_EXTENDED; - } - } - } output_ctx->data = tls_ctx; output_ctx->DeInit = OutputTlsLogDeinit; @@ -298,7 +435,7 @@ OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { OutputJsonCtx *ojc = parent_ctx->data; - OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); + OutputTlsCtx *tls_ctx = OutputTlsInitCtx(conf); if (unlikely(tls_ctx == NULL)) return NULL; @@ -309,17 +446,7 @@ OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) } tls_ctx->file_ctx = ojc->file_ctx; - tls_ctx->flags = LOG_TLS_DEFAULT; - - if (conf) { - const char *extended = ConfNodeLookupChildValue(conf, "extended"); - if (extended != NULL) { - if (ConfValIsTrue(extended)) { - tls_ctx->flags = LOG_TLS_EXTENDED; - } - } - } output_ctx->data = tls_ctx; output_ctx->DeInit = OutputTlsLogDeinitSub; diff --git a/suricata.yaml.in b/suricata.yaml.in index 6c5ee19758a8..9db8096eacef 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -206,6 +206,9 @@ outputs: #custom: [a, aaaa, cname, mx, ns, ptr, txt] - tls: extended: yes # enable this for extended logging information + # custom allows to control which tls fields that are included + # in eve-log + #custom: [subject, issuer, fingerprint, sni, version, not_before, not_after] - files: force-magic: no # force logging magic on all logged files # force logging of checksums, available hash functions are md5, From 115b3138cc4723090774f68ac5a43fb91bd971ab Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 13 Jan 2017 12:20:34 +0100 Subject: [PATCH 2471/2553] output-json-tls: log certificate and chain Log entire certificate and certificate chain Base64 encoded. --- src/output-json-tls.c | 65 +++++++++++++++++++++++++++++++++++++++++++ src/util-error.c | 1 + src/util-error.h | 1 + suricata.yaml.in | 2 +- 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 485defc4b9b1..2ef4ef714dbb 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -66,6 +66,8 @@ SC_ATOMIC_DECLARE(unsigned int, cert_id); #define LOG_TLS_FIELD_NOTBEFORE (1 << 4) #define LOG_TLS_FIELD_NOTAFTER (1 << 5) #define LOG_TLS_FIELD_SNI (1 << 6) +#define LOG_TLS_FIELD_CERTIFICATE (1 << 7) +#define LOG_TLS_FIELD_CHAIN (1 << 8) typedef struct { char *name; @@ -80,6 +82,8 @@ TlsFields tls_fields[] = { { "not_before", LOG_TLS_FIELD_NOTBEFORE }, { "not_after", LOG_TLS_FIELD_NOTAFTER }, { "sni", LOG_TLS_FIELD_SNI }, + { "certificate", LOG_TLS_FIELD_CERTIFICATE }, + { "chain", LOG_TLS_FIELD_CHAIN }, { NULL, -1 } }; @@ -178,6 +182,51 @@ static void JsonTlsLogNotAfter(json_t *js, SSLState *ssl_state) } } +static void JsonTlsLogCertificate(json_t *js, SSLState *ssl_state) +{ + if ((ssl_state->server_connp.cert_input == NULL) || + (ssl_state->server_connp.cert_input_len == 0)) { + return; + } + + SSLCertsChain *cert = TAILQ_FIRST(&ssl_state->server_connp.certs); + if (cert == NULL) { + return; + } + + unsigned long len = cert->cert_len * 2; + uint8_t encoded[len]; + if (Base64Encode(cert->cert_data, cert->cert_len, encoded, &len) == + SC_BASE64_OK) { + json_object_set_new(js, "certificate", json_string((char *)encoded)); + } +} + +static void JsonTlsLogChain(json_t *js, SSLState *ssl_state) +{ + if ((ssl_state->server_connp.cert_input == NULL) || + (ssl_state->server_connp.cert_input_len == 0)) { + return; + } + + json_t *chain = json_array(); + if (chain == NULL) { + return; + } + + SSLCertsChain *cert; + TAILQ_FOREACH(cert, &ssl_state->server_connp.certs, next) { + unsigned long len = cert->cert_len * 2; + uint8_t encoded[len]; + if (Base64Encode(cert->cert_data, cert->cert_len, encoded, &len) == + SC_BASE64_OK) { + json_array_append_new(chain, json_string((char *)encoded)); + } + } + + json_object_set_new(js, "chain", chain); +} + void JsonTlsLogJSONBasic(json_t *js, SSLState *ssl_state) { /* tls.subject */ @@ -217,6 +266,14 @@ static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, json_t *js, /* tls.notafter */ if (tls_ctx->fields & LOG_TLS_FIELD_NOTAFTER) JsonTlsLogNotAfter(js, ssl_state); + + /* tls.certificate */ + if (tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) + JsonTlsLogCertificate(js, ssl_state); + + /* tls.chain */ + if (tls_ctx->fields & LOG_TLS_FIELD_CHAIN) + JsonTlsLogChain(js, ssl_state); } void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) @@ -447,6 +504,14 @@ OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) tls_ctx->file_ctx = ojc->file_ctx; + if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) && + (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)) { + SCLogWarning(SC_WARN_DUPLICATE_OUTPUT, + "Both 'certificate' and 'chain' contains the top " + "certificate, so only one of them should be enabled " + "at a time"); + } + output_ctx->data = tls_ctx; output_ctx->DeInit = OutputTlsLogDeinitSub; diff --git a/src/util-error.c b/src/util-error.c index 4503986fb5c2..c9ad9854eb7c 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -333,6 +333,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_DNP3_CONFIG); CASE_CODE (SC_ERR_DIR_OPEN); CASE_CODE(SC_WARN_REMOVE_FILE); + CASE_CODE (SC_WARN_DUPLICATE_OUTPUT); CASE_CODE (SC_ERR_NO_MAGIC_SUPPORT); CASE_CODE (SC_ERR_REDIS); CASE_CODE (SC_ERR_VAR_LIMIT); diff --git a/src/util-error.h b/src/util-error.h index 59778c5606c4..718ba543f4a1 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -326,6 +326,7 @@ typedef enum { SC_ERR_NO_MAGIC_SUPPORT, SC_ERR_REDIS, SC_ERR_VAR_LIMIT, + SC_WARN_DUPLICATE_OUTPUT, } SCError; const char *SCErrorToString(SCError); diff --git a/suricata.yaml.in b/suricata.yaml.in index 9db8096eacef..0222b187e2ab 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -208,7 +208,7 @@ outputs: extended: yes # enable this for extended logging information # custom allows to control which tls fields that are included # in eve-log - #custom: [subject, issuer, fingerprint, sni, version, not_before, not_after] + #custom: [subject, issuer, fingerprint, sni, version, not_before, not_after, certificate, chain] - files: force-magic: no # force logging magic on all logged files # force logging of checksums, available hash functions are md5, From bbd32c141957579119a1e5cd898048a3bb5d733c Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 13 Jan 2017 13:07:59 +0100 Subject: [PATCH 2472/2553] output-json-tls: code cleanup --- src/output-json-tls.c | 64 +++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 2ef4ef714dbb..a8ddf804f9fb 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -54,6 +54,11 @@ SC_ATOMIC_DECLARE(unsigned int, cert_id); #define MODULE_NAME "LogTlsLog" +#define DEFAULT_LOG_FILENAME "tls.json" + +#define OUTPUT_BUFFER_SIZE 65535 + +#define SSL_VERSION_LENGTH 13 #define LOG_TLS_DEFAULT 0 #define LOG_TLS_EXTENDED (1 << 0) @@ -99,8 +104,6 @@ typedef struct JsonTlsLogThread_ { MemBuffer *buffer; } JsonTlsLogThread; -#define SSL_VERSION_LENGTH 13 - static void JsonTlsLogSubject(json_t *js, SSLState *ssl_state) { json_object_set_new(js, "subject", @@ -229,49 +232,49 @@ static void JsonTlsLogChain(json_t *js, SSLState *ssl_state) void JsonTlsLogJSONBasic(json_t *js, SSLState *ssl_state) { - /* tls.subject */ + /* tls subject */ JsonTlsLogSubject(js, ssl_state); - /* tls.issuerdn */ + /* tls issuerdn */ JsonTlsLogIssuer(js, ssl_state); } static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, json_t *js, SSLState *ssl_state) { - /* tls.subject */ + /* tls subject */ if (tls_ctx->fields & LOG_TLS_FIELD_SUBJECT) JsonTlsLogSubject(js, ssl_state); - /* tls.issuerdn */ + /* tls issuerdn */ if (tls_ctx->fields & LOG_TLS_FIELD_ISSUER) JsonTlsLogIssuer(js, ssl_state); - /* tls.fingerprint */ + /* tls fingerprint */ if (tls_ctx->fields & LOG_TLS_FIELD_FINGERPRINT) JsonTlsLogFingerprint(js, ssl_state); - /* tls.sni */ + /* tls sni */ if (tls_ctx->fields & LOG_TLS_FIELD_SNI) JsonTlsLogSni(js, ssl_state); - /* tls.version */ + /* tls version */ if (tls_ctx->fields & LOG_TLS_FIELD_VERSION) JsonTlsLogVersion(js, ssl_state); - /* tls.notbefore */ + /* tls notbefore */ if (tls_ctx->fields & LOG_TLS_FIELD_NOTBEFORE) JsonTlsLogNotBefore(js, ssl_state); - /* tls.notafter */ + /* tls notafter */ if (tls_ctx->fields & LOG_TLS_FIELD_NOTAFTER) JsonTlsLogNotAfter(js, ssl_state); - /* tls.certificate */ + /* tls certificate */ if (tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) JsonTlsLogCertificate(js, ssl_state); - /* tls.chain */ + /* tls chain */ if (tls_ctx->fields & LOG_TLS_FIELD_CHAIN) JsonTlsLogChain(js, ssl_state); } @@ -280,19 +283,19 @@ void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) { JsonTlsLogJSONBasic(tjs, state); - /* tls.fingerprint */ + /* tls fingerprint */ JsonTlsLogFingerprint(tjs, state); - /* tls.sni */ + /* tls sni */ JsonTlsLogSni(tjs, state); - /* tls.version */ + /* tls version */ JsonTlsLogVersion(tjs, state); - /* tls.notbefore */ + /* tls notbefore */ JsonTlsLogNotBefore(tjs, state); - /* tls.notafter */ + /* tls notafter */ JsonTlsLogNotAfter(tjs, state); } @@ -308,12 +311,14 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, } if (ssl_state->server_connp.cert0_issuerdn == NULL || - ssl_state->server_connp.cert0_subject == NULL) + ssl_state->server_connp.cert0_subject == NULL) { return 0; + } json_t *js = CreateJSONHeader((Packet *)p, 1, "tls"); - if (unlikely(js == NULL)) + if (unlikely(js == NULL)) { return 0; + } json_t *tjs = json_object(); if (tjs == NULL) { @@ -346,22 +351,22 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, return 0; } -#define OUTPUT_BUFFER_SIZE 65535 static TmEcode JsonTlsLogThreadInit(ThreadVars *t, void *initdata, void **data) { JsonTlsLogThread *aft = SCMalloc(sizeof(JsonTlsLogThread)); - if (unlikely(aft == NULL)) + if (unlikely(aft == NULL)) { return TM_ECODE_FAILED; + } + memset(aft, 0, sizeof(JsonTlsLogThread)); - if(initdata == NULL) - { - SCLogDebug("Error getting context for EveLogTLS. \"initdata\" argument NULL"); + if (initdata == NULL) { + SCLogDebug("Error getting context for eve-log tls 'initdata' argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } - /* Use the Ouptut Context (file pointer and mutex) */ + /* use the Output Context (file pointer and mutex) */ aft->tlslog_ctx = ((OutputCtx *)initdata)->data; aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); @@ -382,6 +387,7 @@ static TmEcode JsonTlsLogThreadDeinit(ThreadVars *t, void *data) } MemBufferFree(aft->buffer); + /* clear memory */ memset(aft, 0, sizeof(JsonTlsLogThread)); @@ -444,11 +450,10 @@ static OutputTlsCtx *OutputTlsInitCtx(ConfNode *conf) return tls_ctx; } -#define DEFAULT_LOG_FILENAME "tls.json" OutputCtx *OutputTlsLogInit(ConfNode *conf) { LogFileCtx *file_ctx = LogFileNewCtx(); - if(file_ctx == NULL) { + if (file_ctx == NULL) { SCLogError(SC_ERR_TLS_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } @@ -541,4 +546,5 @@ void JsonTlsLogRegister (void) { } -#endif +#endif /* HAVE_LIBJANSSON */ + From e91bb09c9138d6087eec2c09fc648cc06c08ca71 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 17 Jan 2017 12:45:21 +0100 Subject: [PATCH 2473/2553] doc: add documentation for TLS eve-log --- doc/userguide/output/eve/eve-json-format.rst | 58 ++++++++++++++++++++ doc/userguide/output/eve/eve-json-output.rst | 22 ++++++++ 2 files changed, 80 insertions(+) diff --git a/doc/userguide/output/eve/eve-json-format.rst b/doc/userguide/output/eve/eve-json-format.rst index db3d7c96a012..ad328d5403f4 100644 --- a/doc/userguide/output/eve/eve-json-format.rst +++ b/doc/userguide/output/eve/eve-json-format.rst @@ -196,3 +196,61 @@ Example of a DNS answer with an IPv4 (resource record type 'A') return: "ttl":8, "rdata": "199.16.156.6" } + +Event type: TLS +--------------- + +Fields +~~~~~~ + +* "subject": The subject field from the TLS certificate +* "issuer": The issuer field from the TLS certificate + +If extended logging is enabled the following fields are also included: + +* "fingerprint": The (SHA1) fingerprint of the TLS certificate +* "sni": The Server Name Indication (SNI) extension sent by the client +* "version": The SSL/TLS version used +* "notbefore": The NotBefore field from the TLS certificate +* "notafter": The NotAfter field from the TLS certificate + +In addition to this, custom logging also allows the following fields: + +* "certificate": The TLS certificate base64 encoded +* "chain": The entire TLS certificate chain base64 encoded + +Examples +~~~~~~~~ + +Example of regular TLS logging: + +:: + + "tls": { + "subject": "C=US, ST=California, L=Mountain View, O=Google Inc, CN=*.google.com", + "issuerdn": "C=US, O=Google Inc, CN=Google Internet Authority G2" + } + +Example of extended TLS logging: + +:: + + "tls": { + "subject": "C=US, ST=California, L=Mountain View, O=Google Inc, CN=*.google.com", + "issuerdn": "C=US, O=Google Inc, CN=Google Internet Authority G2", + "fingerprint": "8f:51:12:06:a0:cc:4e:cd:e8:a3:8b:38:f8:87:59:e5:af:95:ca:cd", + "sni": "calendar.google.com", + "version": "TLS 1.2", + "notbefore": "2017-01-04T10:48:43", + "notafter": "2017-03-29T10:18:00" + } + +Example of certificate logging using TLS custom logging (subject, sni, certificate): + +:: + + "tls": { + "subject": "C=US, ST=California, L=Mountain View, O=Google Inc, CN=*.googleapis.com + "sni": "www.googleapis.com", + "certificate": "MIIE3TCCA8WgAwIBAgIIQPsvobRZN0gwDQYJKoZIhvcNAQELBQAwSTELMA [...]" + } diff --git a/doc/userguide/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst index a960e7e16cd9..65c74590105e 100644 --- a/doc/userguide/output/eve/eve-json-output.rst +++ b/doc/userguide/output/eve/eve-json-output.rst @@ -80,6 +80,10 @@ The most common way to use this is through 'EVE', which is a firehose approach w #custom: [a, aaaa, cname, mx, ns, ptr, txt] - tls: extended: yes # enable this for extended logging information + # custom allows to control which tls fields that are included + # in eve-log + #custom: [subject, issuer, fingerprint, sni, version, not_before, not_after, certificate, chain] + - files: force-magic: no # force logging magic on all logged files # force logging of checksums, available hash functions are md5, @@ -181,6 +185,24 @@ YAML:: To reduce verbosity the output can be filtered by supplying the record types to be logged under ``custom``. +TLS +~~~ + +TLS records are logged one record per session. + +YAML:: + + - tls: + extended: yes # enable this for extended logging information + # custom allows to control which tls fields that are included + # in eve-log + #custom: [subject, issuer, fingerprint, sni, version, not_before, not_after, certificate, chain] + +The default is to log certificate subject and issuer. If ``extended`` is +enabled, then the log gets more verbose. + +By using ``custom`` it is possible to select which TLS fields to log. + Multiple Logger Instances ~~~~~~~~~~~~~~~~~~~~~~~~~ From b1ad770b36ba2595f77a94e67b0ae86c22d4217c Mon Sep 17 00:00:00 2001 From: David Wharton Date: Mon, 20 Feb 2017 08:27:05 -0500 Subject: [PATCH 2474/2553] doc: removed references to older Suricata versions docs are versioned; references to older Suricata versions undesired. --- doc/userguide/rules/tls-keywords.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/doc/userguide/rules/tls-keywords.rst b/doc/userguide/rules/tls-keywords.rst index a84821ca8da6..3f371f571b3d 100644 --- a/doc/userguide/rules/tls-keywords.rst +++ b/doc/userguide/rules/tls-keywords.rst @@ -87,8 +87,6 @@ Match on negotiated TLS/SSL version. Example values: "1.0", "1.1", "1.2" -Support added in Suricata version 1.3. - tls.subject ----------- @@ -101,8 +99,6 @@ example: tls.subject:"CN=*.googleusercontent.com" -Support added in Suricata version 1.3. - Case sensitve, can't use 'nocase'. Legacy keyword. ``tls_cert_subject`` is the replacement. @@ -119,8 +115,6 @@ example: tls.issuerdn:!"CN=Google-Internet-Authority" -Support added in Suricata version 1.3. - Case sensitve, can't use 'nocase'. Legacy keyword. ``tls_cert_issuer`` is the replacement. @@ -137,8 +131,6 @@ example: tls.fingerprint:!"f3:40:21:48:70:2c:31:bc:b5:aa:22:ad:63:d6:bc:2e:b3:46:e2:5a" -Support added in Suricata version 1.4. - Case sensitive, can't use 'nocase'. The tls.fingerprint buffer is lower case so you must use lower case letters for this to match. @@ -148,8 +140,6 @@ tls.store store TLS/SSL certificate on disk -Support added in Suricata version 1.4. - ssl_state --------- From 1bf7ded224bacace8b7779d76a738c8976e55f58 Mon Sep 17 00:00:00 2001 From: David Wharton Date: Mon, 20 Feb 2017 08:29:59 -0500 Subject: [PATCH 2475/2553] doc: specify buffers that can be used for fast_pattern Updated notes on the following buffers indicating that they can be used for fast_pattern: tls_cert_subject tls_cert_issuer tls_sni --- doc/userguide/rules/tls-keywords.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/userguide/rules/tls-keywords.rst b/doc/userguide/rules/tls-keywords.rst index 3f371f571b3d..e8220c64876c 100644 --- a/doc/userguide/rules/tls-keywords.rst +++ b/doc/userguide/rules/tls-keywords.rst @@ -15,6 +15,8 @@ Examples:: ``tls_cert_subject`` is a 'Sticky buffer'. +``tls_cert_subject`` can be used as ``fast_pattern``. + tls_cert_issuer --------------- @@ -27,6 +29,8 @@ Examples:: ``tls_cert_issuer`` is a 'Sticky buffer'. +``tls_cert_issuer`` can be used as ``fast_pattern``. + tls_sni ------- @@ -39,6 +43,8 @@ Examples:: ``tls_sni`` is a 'Sticky buffer'. +``tls_sni`` can be used as ``fast_pattern``. + tls_cert_notbefore ------------------ From 92db12c3492d1931e346869695351ca1788869e2 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 17 Feb 2017 10:46:43 -0600 Subject: [PATCH 2476/2553] pidfile: fail if the pid file exists Changes the pidfile check function to fail just on the existence of the file to address issue https://redmine.openinfosecfoundation.org/issues/1335 but log a message if the pid file appears to be stale. --- src/util-pidfile.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/util-pidfile.c b/src/util-pidfile.c index a13e54efedaf..a68188b7e616 100644 --- a/src/util-pidfile.c +++ b/src/util-pidfile.c @@ -89,8 +89,13 @@ void SCPidfileRemove(const char *pid_filename) } /** - * \brief Check a pid file (used at the startup) - * This commonly needed by the init scripts + * \brief Check the Suricata pid file (used at the startup) + * + * This commonly needed by the init scripts. + * + * This function will fail if the PID file exists, but tries to log a + * meaningful message if appears Suricata is running, or if the PID + * file appears to be stale. * * \param pointer to the name of the pid file to write (optarg) * @@ -113,15 +118,19 @@ int SCPidfileTestRunning(const char *pid_filename) } if (fscanf(pf, "%d", &pidv) == 1 && kill(pidv, 0) == 0) { - fclose(pf); SCLogError(SC_ERR_INITIALIZATION, - "pid file '%s' exists. Is Suricata already running? Aborting!", - pid_filename); - return -1; + "pid file '%s' exists and Suricata appears to be running. " + "Aborting!", pid_filename); + } else { + SCLogError(SC_ERR_INITIALIZATION, + "pid file '%s' exists but appears stale. " + "Make sure Suricata is not running and then remove %s. " + "Aborting!", + pid_filename, pid_filename); } - if (pf != NULL) - fclose(pf); + fclose(pf); + return -1; } return 0; } From ee7e689b5423295d17f1560e2a3b1a1491cdf314 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Mon, 20 Feb 2017 16:41:18 +0300 Subject: [PATCH 2477/2553] af-packet: write VLAN info for both TPACKET_V2 and V3 --- src/source-af-packet.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 289b92f58d62..035da32065da 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -679,6 +679,8 @@ static TmEcode AFPWritePacket(Packet *p, int version) int socket; uint8_t *pstart; size_t plen; + union thdr h; + uint16_t vlan_tci = 0; if (p->afp_v.copy_mode == AFP_COPY_MODE_IPS) { if (PACKET_TEST_ACTION(p, ACTION_DROP)) { @@ -705,25 +707,35 @@ static TmEcode AFPWritePacket(Packet *p, int version) SCMutexLock(&p->afp_v.peer->sock_protect); socket = SC_ATOMIC_GET(p->afp_v.peer->socket); + h.raw = p->afp_v.relptr; + if (version == TPACKET_V2) { - union thdr h; - h.raw = p->afp_v.relptr; /* Copy VLAN header from ring memory. For post june 2011 kernel we test * the flag. It is not defined for older kernel so we go best effort * and test for non zero value of the TCI header. */ if (h.h2->tp_status & TP_STATUS_VLAN_VALID || h.h2->tp_vlan_tci) { - pstart = GET_PKT_DATA(p) - VLAN_HEADER_LEN; - plen = GET_PKT_LEN(p) + VLAN_HEADER_LEN; - /* move ethernet addresses */ - memmove(pstart, GET_PKT_DATA(p), 2 * ETH_ALEN); - /* write vlan info */ - *(uint16_t *)(pstart + 2 * ETH_ALEN) = htons(0x8100); - *(uint16_t *)(pstart + 2 * ETH_ALEN + 2) = htons(h.h2->tp_vlan_tci); - } else { - pstart = GET_PKT_DATA(p); - plen = GET_PKT_LEN(p); + vlan_tci = h.h2->tp_vlan_tci; } } else { +#ifdef HAVE_TPACKET_V3 + if (h.h3->tp_status & TP_STATUS_VLAN_VALID || h.h3->hv1.tp_vlan_tci) { + vlan_tci = h.h3->hv1.tp_vlan_tci; + } +#else + /* Should not get here */ + BUG_ON(1); +#endif + } + + if (vlan_tci != 0) { + pstart = GET_PKT_DATA(p) - VLAN_HEADER_LEN; + plen = GET_PKT_LEN(p) + VLAN_HEADER_LEN; + /* move ethernet addresses */ + memmove(pstart, GET_PKT_DATA(p), 2 * ETH_ALEN); + /* write vlan info */ + *(uint16_t *)(pstart + 2 * ETH_ALEN) = htons(0x8100); + *(uint16_t *)(pstart + 2 * ETH_ALEN + 2) = htons(vlan_tci); + } else { pstart = GET_PKT_DATA(p); plen = GET_PKT_LEN(p); } From e41a9d637bf0b420d548c2bec0fb26c79c1f5ccf Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Mon, 20 Feb 2017 16:43:10 +0300 Subject: [PATCH 2478/2553] af-packet: get VLAN info for packets in TPACKET_V3 mode --- src/source-af-packet.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 035da32065da..7e981ba24285 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -980,6 +980,13 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc p->livedev = ptv->livedev; p->datalink = ptv->datalink; + if ((!(ptv->flags & AFP_VLAN_DISABLED)) && + (ppd->tp_status & TP_STATUS_VLAN_VALID || ppd->hv1.tp_vlan_tci)) { + p->vlan_id[0] = ppd->hv1.tp_vlan_tci & 0x0fff; + p->vlan_idx = 1; + p->vlanh[0] = NULL; + } + if (ptv->flags & AFP_ZERO_COPY) { if (PacketSetData(p, (unsigned char*)ppd + ppd->tp_mac, ppd->tp_snaplen) == -1) { TmqhOutputPacketpool(ptv->tv, p); From 310b27a196a93b46ea719a51323fd3d4a83bea64 Mon Sep 17 00:00:00 2001 From: Alexander Gozman Date: Mon, 20 Feb 2017 16:47:31 +0300 Subject: [PATCH 2479/2553] af-packet: fix parsing packet in TPACKET_V3 mode AFPParsePacketV3() saved tpacket_block_desc structure instead of tpacket3_hdr. As a result, reconstructed packets were wrong. Bug #2044. --- src/source-af-packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 7e981ba24285..1e25d316bb34 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -992,7 +992,7 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(AFP_FAILURE); } - p->afp_v.relptr = pbd; + p->afp_v.relptr = ppd; p->ReleasePacket = AFPReleasePacketV3; p->afp_v.mpeer = ptv->mpeer; AFPRefSocket(ptv->mpeer); From 2c1a36dd6e56a84bc2894a7e544b1e83651b85bf Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 17 Jan 2017 09:20:25 +0100 Subject: [PATCH 2480/2553] app-layer-tls: decode certificate serial number --- src/app-layer-ssl.c | 2 ++ src/app-layer-ssl.h | 1 + src/app-layer-tls-handshake.c | 15 ++++++++++++ src/util-decode-der-get.c | 45 +++++++++++++++++++++++++++++++++++ src/util-decode-der-get.h | 1 + 5 files changed, 64 insertions(+) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 58f54feea67c..f6839adc5ff2 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -1540,6 +1540,8 @@ void SSLStateFree(void *p) SCFree(ssl_state->client_connp.cert0_subject); if (ssl_state->client_connp.cert0_issuerdn) SCFree(ssl_state->client_connp.cert0_issuerdn); + if (ssl_state->server_connp.cert0_serial) + SCFree(ssl_state->server_connp.cert0_serial); if (ssl_state->client_connp.cert0_fingerprint) SCFree(ssl_state->client_connp.cert0_fingerprint); if (ssl_state->client_connp.sni) diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index d2279e2f2b43..f23757836683 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -149,6 +149,7 @@ typedef struct SSLStateConnp_ { char *cert0_subject; char *cert0_issuerdn; + char *cert0_serial; time_t cert0_not_before; time_t cert0_not_after; char *cert0_fingerprint; diff --git a/src/app-layer-tls-handshake.c b/src/app-layer-tls-handshake.c index 9ae3a1080164..6c3226f2d5bc 100644 --- a/src/app-layer-tls-handshake.c +++ b/src/app-layer-tls-handshake.c @@ -177,6 +177,21 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, } } + rc = Asn1DerGetSerial(cert, buffer, sizeof(buffer), &errcode); + if (rc != 0) { + TLSCertificateErrCodeToWarning(ssl_state, errcode); + } else { + if (i == 0) { + if (ssl_state->server_connp.cert0_serial == NULL) { + ssl_state->server_connp.cert0_serial = SCStrdup(buffer); + } + if (ssl_state->server_connp.cert0_serial == NULL) { + DerFree(cert); + return -1; + } + } + } + rc = Asn1DerGetValidity(cert, ¬_before, ¬_after, &errcode); if (rc != 0) { TLSCertificateErrCodeToWarning(ssl_state, errcode); diff --git a/src/util-decode-der-get.c b/src/util-decode-der-get.c index fc132cf45e2d..3e90788f7459 100644 --- a/src/util-decode-der-get.c +++ b/src/util-decode-der-get.c @@ -37,6 +37,7 @@ #include "util-decode-der.h" #include "util-decode-der-get.h" +static const uint8_t SEQ_IDX_SERIAL[] = { 0, 0 }; static const uint8_t SEQ_IDX_ISSUER[] = { 0, 2 }; static const uint8_t SEQ_IDX_VALIDITY[] = { 0, 3 }; static const uint8_t SEQ_IDX_SUBJECT[] = { 0, 4 }; @@ -241,6 +242,50 @@ int Asn1DerGetValidity(const Asn1Generic *cert, time_t *not_before, return rc; } +int Asn1DerGetSerial(const Asn1Generic *cert, char *buffer, uint32_t length, + uint32_t *errcode) +{ + const Asn1Generic *node; + uint32_t node_len, i; + int rc = -1; + + if (errcode) + *errcode = ERR_DER_MISSING_ELEMENT; + + buffer[0] = '\0'; + + node = Asn1DerGet(cert, SEQ_IDX_SERIAL, sizeof(SEQ_IDX_SERIAL), errcode); + if ((node == NULL) || node->type != ASN1_INTEGER || node->str == NULL) + goto serial_error; + + node_len = strlen(node->str); + + /* make sure the buffer is big enough */ + if (node_len + (node_len / 2) > length) + goto serial_error; + + /* format serial number (e.g. XX:XX:XX:XX:XX) */ + for (i = 0; i < node_len; i++) { + char c[3]; + /* insert separator before each even number */ + if (((i % 2) == 0) && (i != 0)) { + snprintf(c, sizeof(c), ":%c", node->str[i]); + } else { + snprintf(c, sizeof(c), "%c", node->str[i]); + } + + strlcat(buffer, c, length); + } + + if (errcode) + *errcode = 0; + + rc = 0; + +serial_error: + return rc; +} + int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode) { diff --git a/src/util-decode-der-get.h b/src/util-decode-der-get.h index 2d2168aeb3f3..bed1cfebedba 100644 --- a/src/util-decode-der-get.h +++ b/src/util-decode-der-get.h @@ -38,6 +38,7 @@ const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, const uint32_t seqsz, uint32_t *errcode); int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode); +int Asn1DerGetSerial(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode); int Asn1DerGetValidity(const Asn1Generic *cert, time_t *not_before, time_t *not_after, uint32_t *errcode); int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode); From 2b460b8d06390fa12415d23891098d8a9184c0dc Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 17 Jan 2017 09:21:30 +0100 Subject: [PATCH 2481/2553] output-json-lua: log certificate serial number --- src/output-json-tls.c | 29 +++++++++++++++++++++++------ suricata.yaml.in | 2 +- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/output-json-tls.c b/src/output-json-tls.c index a8ddf804f9fb..555c666cc4b7 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -67,12 +67,13 @@ SC_ATOMIC_DECLARE(unsigned int, cert_id); #define LOG_TLS_FIELD_VERSION (1 << 0) #define LOG_TLS_FIELD_SUBJECT (1 << 1) #define LOG_TLS_FIELD_ISSUER (1 << 2) -#define LOG_TLS_FIELD_FINGERPRINT (1 << 3) -#define LOG_TLS_FIELD_NOTBEFORE (1 << 4) -#define LOG_TLS_FIELD_NOTAFTER (1 << 5) -#define LOG_TLS_FIELD_SNI (1 << 6) -#define LOG_TLS_FIELD_CERTIFICATE (1 << 7) -#define LOG_TLS_FIELD_CHAIN (1 << 8) +#define LOG_TLS_FIELD_SERIAL (1 << 3) +#define LOG_TLS_FIELD_FINGERPRINT (1 << 4) +#define LOG_TLS_FIELD_NOTBEFORE (1 << 5) +#define LOG_TLS_FIELD_NOTAFTER (1 << 6) +#define LOG_TLS_FIELD_SNI (1 << 7) +#define LOG_TLS_FIELD_CERTIFICATE (1 << 8) +#define LOG_TLS_FIELD_CHAIN (1 << 9) typedef struct { char *name; @@ -83,6 +84,7 @@ TlsFields tls_fields[] = { { "version", LOG_TLS_FIELD_VERSION }, { "subject", LOG_TLS_FIELD_SUBJECT }, { "issuer", LOG_TLS_FIELD_ISSUER }, + { "serial", LOG_TLS_FIELD_SERIAL }, { "fingerprint", LOG_TLS_FIELD_FINGERPRINT }, { "not_before", LOG_TLS_FIELD_NOTBEFORE }, { "not_after", LOG_TLS_FIELD_NOTAFTER }, @@ -130,6 +132,14 @@ static void JsonTlsLogSni(json_t *js, SSLState *ssl_state) } } +static void JsonTlsLogSerial(json_t *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_serial) { + json_object_set_new(js, "serial", + json_string(ssl_state->server_connp.cert0_serial)); + } +} + static void JsonTlsLogVersion(json_t *js, SSLState *ssl_state) { char ssl_version[SSL_VERSION_LENGTH + 1]; @@ -250,6 +260,10 @@ static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, json_t *js, if (tls_ctx->fields & LOG_TLS_FIELD_ISSUER) JsonTlsLogIssuer(js, ssl_state); + /* tls serial */ + if (tls_ctx->fields & LOG_TLS_FIELD_SERIAL) + JsonTlsLogSerial(js, ssl_state); + /* tls fingerprint */ if (tls_ctx->fields & LOG_TLS_FIELD_FINGERPRINT) JsonTlsLogFingerprint(js, ssl_state); @@ -283,6 +297,9 @@ void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) { JsonTlsLogJSONBasic(tjs, state); + /* tls serial */ + JsonTlsLogSerial(tjs, state); + /* tls fingerprint */ JsonTlsLogFingerprint(tjs, state); diff --git a/suricata.yaml.in b/suricata.yaml.in index 0222b187e2ab..a91d1fe85efb 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -208,7 +208,7 @@ outputs: extended: yes # enable this for extended logging information # custom allows to control which tls fields that are included # in eve-log - #custom: [subject, issuer, fingerprint, sni, version, not_before, not_after, certificate, chain] + #custom: [subject, issuer, serial, fingerprint, sni, version, not_before, not_after, certificate, chain] - files: force-magic: no # force logging magic on all logged files # force logging of checksums, available hash functions are md5, From 2e339aa7911b090c11ecef5869df43faa633e2d2 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 17 Jan 2017 09:22:10 +0100 Subject: [PATCH 2482/2553] tls-log: log certificate serial number --- src/log-tlslog.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/log-tlslog.c b/src/log-tlslog.c index 113a2ccd3bcc..fc1deddae309 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -86,6 +86,9 @@ static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state) if (state->client_connp.sni != NULL) { MemBufferWriteString(aft->buffer, " SNI='%s'", state->client_connp.sni); } + if (state->server_connp.cert0_serial != NULL) { + MemBufferWriteString(aft->buffer, " SERIAL='%s'", state->server_connp.cert0_serial); + } switch (state->server_connp.version) { case TLS_VERSION_UNKNOWN: MemBufferWriteString(aft->buffer, " VERSION='UNDETERMINED'"); From 95864375f2a510b122909923bd0ba0f8c0558d74 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 17 Jan 2017 09:23:30 +0100 Subject: [PATCH 2483/2553] lua: add function to print certificate serial number Add function LuaGetCertSerial to print serial number from TLS certificate. Example: function log (args) serial = TlsGetCertSerial() if serial then file:write(serial .. "\n"); file:flush() end end --- src/util-lua-tls.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/util-lua-tls.c b/src/util-lua-tls.c index 648eb423124e..8472c0f6db4c 100644 --- a/src/util-lua-tls.c +++ b/src/util-lua-tls.c @@ -240,6 +240,38 @@ static int TlsGetSNI(lua_State *luastate) return r; } +static int GetCertSerial(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + if (ssl_state->server_connp.cert0_serial == NULL) + return LuaCallbackError(luastate, "error: no certificate serial"); + + return LuaPushStringBuffer(luastate, + (uint8_t *)ssl_state->server_connp.cert0_serial, + strlen(ssl_state->server_connp.cert0_serial)); +} + +static int TlsGetCertSerial(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertSerial(luastate, f); + + return r; +} + static int GetCertChain(lua_State *luastate, const Flow *f, int direction) { void *state = FlowGetAppState(f); @@ -312,6 +344,9 @@ int LuaRegisterTlsFunctions(lua_State *luastate) lua_pushcfunction(luastate, TlsGetSNI); lua_setglobal(luastate, "TlsGetSNI"); + lua_pushcfunction(luastate, TlsGetCertSerial); + lua_setglobal(luastate, "TlsGetCertSerial"); + lua_pushcfunction(luastate, TlsGetCertChain); lua_setglobal(luastate, "TlsGetCertChain"); From d6508e640a2330722011e4cfc39a36f60f735796 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 20 Feb 2017 08:27:23 +0100 Subject: [PATCH 2484/2553] detect: add (mpm) keyword tls_cert_serial Match on TLS certificate serial number using tls_cert_serial keyword, e.g.: alert tls any any -> any any (msg:"TLS cert serial test"; tls_cert_serial; content:"5C:19:B7:B1:32:3B:1C:A1"; sid:12345;) --- src/Makefile.am | 1 + src/detect-engine-tls.c | 76 ++++++ src/detect-engine-tls.h | 7 + src/detect-tls-cert-serial.c | 467 +++++++++++++++++++++++++++++++++++ src/detect-tls-cert-serial.h | 30 +++ src/detect.c | 2 + src/detect.h | 1 + 7 files changed, 584 insertions(+) create mode 100644 src/detect-tls-cert-serial.c create mode 100644 src/detect-tls-cert-serial.h diff --git a/src/Makefile.am b/src/Makefile.am index 634ab7aabd0e..26541ccedfdb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -97,6 +97,7 @@ detect-dns-query.c detect-dns-query.h \ detect-tls-sni.c detect-tls-sni.h \ detect-tls-cert-issuer.c detect-tls-cert-issuer.h \ detect-tls-cert-subject.c detect-tls-cert-subject.h \ +detect-tls-cert-serial.c detect-tls-cert-serial.h \ detect-dsize.c detect-dsize.h \ detect-engine-address.c detect-engine-address.h \ detect-engine-address-ipv4.c detect-engine-address-ipv4.h \ diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c index 9b0d35b78451..4912da776cee 100644 --- a/src/detect-engine-tls.c +++ b/src/detect-engine-tls.c @@ -271,6 +271,82 @@ int DetectEngineInspectTlsSubject(ThreadVars *tv, return cnt; } +/** \brief TLS Serial Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxTlsSerial(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, const uint64_t idx, + const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + SSLState *ssl_state = f->alstate; + + if (ssl_state->server_connp.cert0_serial == NULL) + return; + + const uint8_t *buffer = (const uint8_t *)ssl_state->server_connp.cert0_serial; + const uint32_t buffer_len = strlen(ssl_state->server_connp.cert0_serial); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxTlsSerialRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxTlsSerial, ALPROTO_TLS, + TLS_STATE_CERT_READY, mpm_ctx, NULL, + "tls_cert_serial"); +} + +/** \brief Do the content inspection and validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags App layer flags + * \param state App layer state + * + * \retval 0 No match + * \retval 1 Match + */ +int DetectEngineInspectTlsSerial(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, + const SigMatchData *smd, Flow *f, + uint8_t flags, void *alstate, void *txv, + uint64_t tx_id) +{ + uint8_t *buffer; + uint32_t buffer_len; + int cnt = 0; + + SSLState *ssl_state = (SSLState *)alstate; + + if (ssl_state->server_connp.cert0_serial == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->server_connp.cert0_serial; + buffer_len = strlen(ssl_state->server_connp.cert0_serial); + + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, buffer, buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + + return cnt; +} + int DetectEngineInspectTlsValidity(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, const SigMatchData *smd, diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h index 573e62d17434..4415ad76af20 100644 --- a/src/detect-engine-tls.h +++ b/src/detect-engine-tls.h @@ -26,6 +26,7 @@ int PrefilterTxTlsSniRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int PrefilterTxTlsIssuerRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxTlsSerialRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -43,6 +44,12 @@ int DetectEngineInspectTlsSubject(ThreadVars *tv, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); +int DetectEngineInspectTlsSerial(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); + int DetectEngineInspectTlsValidity(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, diff --git a/src/detect-tls-cert-serial.c b/src/detect-tls-cert-serial.c new file mode 100644 index 000000000000..4d0a8e4da888 --- /dev/null +++ b/src/detect-tls-cert-serial.c @@ -0,0 +1,467 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls_cert_serial keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-tls.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-spm.h" +#include "util-print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-ssl.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static int DetectTlsSerialSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTlsSerialRegisterTests(void); +static int g_tls_cert_serial_buffer_id = 0; + +/** + * \brief Registration function for keyword: tls_cert_serial + */ +void DetectTlsSerialRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].name = "tls_cert_serial"; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].desc = "content modifier to match the TLS cert serial buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-cert-serial"; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].Match = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].Setup = DetectTlsSerialSetup; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].Free = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].RegisterTests = DetectTlsSerialRegisterTests; + + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].flags |= SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister("tls_cert_serial", SIG_FLAG_TOCLIENT, 2, + PrefilterTxTlsSerialRegister); + + DetectAppLayerInspectEngineRegister("tls_cert_serial", ALPROTO_TLS, + SIG_FLAG_TOCLIENT, DetectEngineInspectTlsSerial); + + g_tls_cert_serial_buffer_id = DetectBufferTypeGetByName("tls_cert_serial"); +} + +/** + * \brief this function setup the tls_cert_serial modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectTlsSerialSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + s->init_data->list = g_tls_cert_serial_buffer_id; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + return 0; +} + +#ifdef UNITTESTS + +/** + * \test Test that a signature containing tls_cert_serial is correctly parsed + * and that the keyword is registered. + */ +static int DetectTlsSerialTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + SigMatch *sm = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tls any any -> any any " + "(msg:\"Testing tls_cert_serial\"; " + "tls_cert_serial; content:\"XX:XX:XX\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + /* sm should not be in the MATCH list */ + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; + FAIL_IF_NOT_NULL(sm); + + sm = de_ctx->sig_list->sm_lists[g_tls_cert_serial_buffer_id]; + FAIL_IF_NULL(sm); + + FAIL_IF(sm->type != DETECT_CONTENT); + FAIL_IF_NOT_NULL(sm->next); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test Test matching for serial in a certificate. + */ +static int DetectTlsSerialTest02(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, + 0x5b, 0x85, 0xd4, 0x40, 0xab, 0xbe, 0xc0, 0xbc, + 0x41, 0xf2, 0x26, 0xf0, 0xfe, 0x21, 0xee, 0x8b, + 0x4c, 0x7e, 0x07, 0xc8, 0xec, 0xd2, 0x00, 0x46, + 0x4c, 0xeb, 0xb7, 0x00, 0x00, 0x16, 0xc0, 0x2b, + 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, + 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, + 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0xff, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, + 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, + 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, + 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, + 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, + 0x14, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, + 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x04, 0x02, 0x02, 0x02 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, + 0xdb, 0xbb, 0x23, 0xcf, 0x0b, 0x43, 0x02, 0x1d, + 0x46, 0x11, 0x27, 0x5c, 0x98, 0xcf, 0x67, 0xe1, + 0x94, 0x3d, 0x62, 0x7d, 0x38, 0x48, 0x21, 0x23, + 0xa5, 0x62, 0x31, 0x00, 0xc0, 0x2f, 0x00, 0x00, + 0x1c, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, + 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, + 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x19, + 0xb7, 0xb1, 0x32, 0x3b, 0x1c, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, + 0x31, 0x33, 0x31, 0x33, 0x32, 0x34, 0x35, 0x32, + 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x30, + 0x35, 0x31, 0x33, 0x31, 0x36, 0x30, 0x30, 0x5a, + 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa5, 0x0a, 0xb9, 0xb1, 0xca, 0x36, 0xd1, 0xae, + 0x22, 0x38, 0x07, 0x06, 0xc9, 0x1a, 0x56, 0x4f, + 0xbb, 0xdf, 0xa8, 0x6d, 0xbd, 0xee, 0x76, 0x16, + 0xbc, 0x53, 0x3c, 0x03, 0x6a, 0x5c, 0x94, 0x50, + 0x87, 0x2f, 0x28, 0xb4, 0x4e, 0xd5, 0x9b, 0x8f, + 0xfe, 0x02, 0xde, 0x2a, 0x83, 0x01, 0xf9, 0x45, + 0x61, 0x0e, 0x66, 0x0e, 0x24, 0x22, 0xe2, 0x59, + 0x66, 0x0d, 0xd3, 0xe9, 0x77, 0x8a, 0x7e, 0x42, + 0xaa, 0x5a, 0xf9, 0x05, 0xbf, 0x30, 0xc7, 0x03, + 0x2b, 0xdc, 0xa6, 0x9c, 0xe0, 0x9f, 0x0d, 0xf1, + 0x28, 0x19, 0xf8, 0xf2, 0x02, 0xfa, 0xbd, 0x62, + 0xa0, 0xf3, 0x02, 0x2b, 0xcd, 0xf7, 0x09, 0x04, + 0x3b, 0x52, 0xd8, 0x65, 0x4b, 0x4a, 0x70, 0xe4, + 0x57, 0xc9, 0x2e, 0x2a, 0xf6, 0x9c, 0x6e, 0xd8, + 0xde, 0x01, 0x52, 0xc9, 0x6f, 0xe9, 0xef, 0x82, + 0xbc, 0x0b, 0x95, 0xb2, 0xef, 0xcb, 0x91, 0xa6, + 0x0b, 0x2d, 0x14, 0xc6, 0x00, 0xa9, 0x33, 0x86, + 0x64, 0x00, 0xd4, 0x92, 0x19, 0x53, 0x3d, 0xfd, + 0xcd, 0xc6, 0x1a, 0xf2, 0x0e, 0x67, 0xc2, 0x1d, + 0x2c, 0xe0, 0xe8, 0x29, 0x97, 0x1c, 0xb6, 0xc4, + 0xb2, 0x02, 0x0c, 0x83, 0xb8, 0x60, 0x61, 0xf5, + 0x61, 0x2d, 0x73, 0x5e, 0x85, 0x4d, 0xbd, 0x0d, + 0xe7, 0x1a, 0x37, 0x56, 0x8d, 0xe5, 0x50, 0x0c, + 0xc9, 0x64, 0x4c, 0x11, 0xea, 0xf3, 0xcb, 0x26, + 0x34, 0xbd, 0x02, 0xf5, 0xc1, 0xfb, 0xa2, 0xec, + 0x27, 0xbb, 0x60, 0xbe, 0x0b, 0xf6, 0xe7, 0x3c, + 0x2d, 0xc9, 0xe7, 0xb0, 0x30, 0x28, 0x17, 0x3d, + 0x90, 0xf1, 0x63, 0x8e, 0x49, 0xf7, 0x15, 0x78, + 0x21, 0xcc, 0x45, 0xe6, 0x86, 0xb2, 0xd8, 0xb0, + 0x2e, 0x5a, 0xb0, 0x58, 0xd3, 0xb6, 0x11, 0x40, + 0xae, 0x81, 0x1f, 0x6b, 0x7a, 0xaf, 0x40, 0x50, + 0xf9, 0x2e, 0x81, 0x8b, 0xec, 0x26, 0x11, 0x3f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x53, 0x30, 0x82, 0x01, 0x4f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, + 0x0b, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x6e, 0x6f, 0x82, 0x09, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xc6, 0x53, 0x87, 0x42, + 0x2d, 0xc8, 0xee, 0x7a, 0x62, 0x1e, 0x83, 0xdb, + 0x0d, 0xe2, 0x32, 0xeb, 0x8b, 0xaf, 0x69, 0x40, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, + 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, + 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, + 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, + 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, + 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, + 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x7b, 0x27, 0x00, 0x46, 0x8f, 0xfd, 0x5b, 0xff, + 0xcb, 0x05, 0x9b, 0xf7, 0xf1, 0x68, 0xf6, 0x9a, + 0x7b, 0xba, 0x53, 0xdf, 0x63, 0xed, 0x11, 0x94, + 0x39, 0xf2, 0xd0, 0x20, 0xcd, 0xa3, 0xc4, 0x98, + 0xa5, 0x10, 0x74, 0xe7, 0x10, 0x6d, 0x07, 0xf8, + 0x33, 0x87, 0x05, 0x43, 0x0e, 0x64, 0x77, 0x09, + 0x18, 0x4f, 0x38, 0x2e, 0x45, 0xae, 0xa8, 0x34, + 0x3a, 0xa8, 0x33, 0xac, 0x9d, 0xdd, 0x25, 0x91, + 0x59, 0x43, 0xbe, 0x0f, 0x87, 0x16, 0x2f, 0xb5, + 0x27, 0xfd, 0xce, 0x2f, 0x35, 0x5d, 0x12, 0xa1, + 0x66, 0xac, 0xf7, 0x95, 0x38, 0x0f, 0xe5, 0xb1, + 0x18, 0x18, 0xe6, 0x80, 0x52, 0x31, 0x8a, 0x66, + 0x02, 0x52, 0x1a, 0xa4, 0x32, 0x6a, 0x61, 0x05, + 0xcf, 0x1d, 0xf9, 0x90, 0x73, 0xf0, 0xeb, 0x20, + 0x31, 0x7b, 0x2e, 0xc0, 0xb0, 0xfb, 0x5c, 0xcc, + 0xdc, 0x76, 0x55, 0x72, 0xaf, 0xb1, 0x05, 0xf4, + 0xad, 0xf9, 0xd7, 0x73, 0x5c, 0x2c, 0xbf, 0x0d, + 0x84, 0x18, 0x01, 0x1d, 0x4d, 0x08, 0xa9, 0x4e, + 0x37, 0xb7, 0x58, 0xc4, 0x05, 0x0e, 0x65, 0x63, + 0xd2, 0x88, 0x02, 0xf5, 0x82, 0x17, 0x08, 0xd5, + 0x8f, 0x80, 0xc7, 0x82, 0x29, 0xbb, 0xe1, 0x04, + 0xbe, 0xf6, 0xe1, 0x8c, 0xbc, 0x3a, 0xf8, 0xf9, + 0x56, 0xda, 0xdc, 0x8e, 0xc6, 0xe6, 0x63, 0x98, + 0x12, 0x08, 0x41, 0x2c, 0x9d, 0x7c, 0x82, 0x0d, + 0x1e, 0xea, 0xba, 0xde, 0x32, 0x09, 0xda, 0x52, + 0x24, 0x4f, 0xcc, 0xb6, 0x09, 0x33, 0x8b, 0x00, + 0xf9, 0x83, 0xb3, 0xc6, 0xa4, 0x90, 0x49, 0x83, + 0x2d, 0x36, 0xd9, 0x11, 0x78, 0xd0, 0x62, 0x9f, + 0xc4, 0x8f, 0x84, 0xba, 0x7f, 0xaa, 0x04, 0xf1, + 0xd9, 0xa4, 0xad, 0x5d, 0x63, 0xee, 0x72, 0xc6, + 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, + 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_serial\"; " + "tls_cert_serial; " + "content:\"5C:19:B7:B1:32:3B:1C:A1\"; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, client_hello, + sizeof(client_hello)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + +#endif /* UNITTESTS */ + +static void DetectTlsSerialRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectTlsSerialTest01", DetectTlsSerialTest01); + UtRegisterTest("DetectTlsSerialTest02", DetectTlsSerialTest02); +#endif /* UNITTESTS */ +} diff --git a/src/detect-tls-cert-serial.h b/src/detect-tls-cert-serial.h new file mode 100644 index 000000000000..9fe018e90872 --- /dev/null +++ b/src/detect-tls-cert-serial.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_TLS_CERT_SERIAL_H__ +#define __DETECT_TLS_CERT_SERIAL_H__ + +/* prototypes */ +void DetectTlsSerialRegister (void); + +#endif /* __DETECT_TLS_CERT_SERIAL_H__ */ diff --git a/src/detect.c b/src/detect.c index 9207b537c0c7..b48bad4ab2b2 100644 --- a/src/detect.c +++ b/src/detect.c @@ -52,6 +52,7 @@ #include "detect-tls-sni.h" #include "detect-tls-cert-issuer.h" #include "detect-tls-cert-subject.h" +#include "detect-tls-cert-serial.h" #include "detect-engine-state.h" #include "detect-engine-analyzer.h" #include "detect-engine-filedata-smtp.h" @@ -3967,6 +3968,7 @@ void SigTableSetup(void) DetectTlsSniRegister(); DetectTlsIssuerRegister(); DetectTlsSubjectRegister(); + DetectTlsSerialRegister(); DetectAppLayerEventRegister(); /* end of order dependent regs */ diff --git a/src/detect.h b/src/detect.h index acebc9f4ffe0..e603d6f356aa 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1288,6 +1288,7 @@ enum { DETECT_AL_TLS_SNI, DETECT_AL_TLS_CERT_ISSUER, DETECT_AL_TLS_CERT_SUBJECT, + DETECT_AL_TLS_CERT_SERIAL, DETECT_AL_MODBUS, DETECT_CIPSERVICE, DETECT_ENIPCOMMAND, From ee9f822b8e14c27f1b0f19fdf64febaa1740c8d3 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Mon, 20 Feb 2017 08:33:49 +0100 Subject: [PATCH 2485/2553] doc: add documentation for tls_cert_serial keyword --- doc/userguide/output/eve/eve-json-format.rst | 2 ++ doc/userguide/output/eve/eve-json-output.rst | 2 +- doc/userguide/rules/tls-keywords.rst | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/doc/userguide/output/eve/eve-json-format.rst b/doc/userguide/output/eve/eve-json-format.rst index ad328d5403f4..7020f705c5e4 100644 --- a/doc/userguide/output/eve/eve-json-format.rst +++ b/doc/userguide/output/eve/eve-json-format.rst @@ -208,6 +208,7 @@ Fields If extended logging is enabled the following fields are also included: +* "serial": The serial number of the TLS certificate * "fingerprint": The (SHA1) fingerprint of the TLS certificate * "sni": The Server Name Indication (SNI) extension sent by the client * "version": The SSL/TLS version used @@ -238,6 +239,7 @@ Example of extended TLS logging: "tls": { "subject": "C=US, ST=California, L=Mountain View, O=Google Inc, CN=*.google.com", "issuerdn": "C=US, O=Google Inc, CN=Google Internet Authority G2", + "serial": "0C:00:99:B7:D7:54:C9:F6:77:26:31:7E:BA:EA:7C:1C", "fingerprint": "8f:51:12:06:a0:cc:4e:cd:e8:a3:8b:38:f8:87:59:e5:af:95:ca:cd", "sni": "calendar.google.com", "version": "TLS 1.2", diff --git a/doc/userguide/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst index 65c74590105e..800bf11750d4 100644 --- a/doc/userguide/output/eve/eve-json-output.rst +++ b/doc/userguide/output/eve/eve-json-output.rst @@ -196,7 +196,7 @@ YAML:: extended: yes # enable this for extended logging information # custom allows to control which tls fields that are included # in eve-log - #custom: [subject, issuer, fingerprint, sni, version, not_before, not_after, certificate, chain] + #custom: [subject, issuer, serial, fingerprint, sni, version, not_before, not_after, certificate, chain] The default is to log certificate subject and issuer. If ``extended`` is enabled, then the log gets more verbose. diff --git a/doc/userguide/rules/tls-keywords.rst b/doc/userguide/rules/tls-keywords.rst index e8220c64876c..583eae24f7a2 100644 --- a/doc/userguide/rules/tls-keywords.rst +++ b/doc/userguide/rules/tls-keywords.rst @@ -31,6 +31,20 @@ Examples:: ``tls_cert_issuer`` can be used as ``fast_pattern``. +tls_cert_serial +--------------- + +Match on the serial number in a certificate. + +Example:: + + alert tls any any -> any any (msg:"match cert serial"; \ + tls_cert_serial; content:"5C:19:B7:B1:32:3B:1C:A1"; sid:200012;) + +``tls_cert_serial`` is a 'Sticky buffer'. + +``tls_cert_serial`` can be used as ``fast_pattern``. + tls_sni ------- From 285b5662050c6a33513f74489226d0c218e73cab Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 17 Jan 2017 09:53:23 +0100 Subject: [PATCH 2486/2553] doc: add documentation for TlsGetCertSerial Lua function --- doc/userguide/output/lua-output.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/userguide/output/lua-output.rst b/doc/userguide/output/lua-output.rst index 158c0505b06f..21e278a5e2d1 100644 --- a/doc/userguide/output/lua-output.rst +++ b/doc/userguide/output/lua-output.rst @@ -457,6 +457,22 @@ Example: end +TlsGetCertSerial +~~~~~~~~~~~~~~~~ + +Get TLS certificate serial number through TlsGetCertSerial. + +Example: + +:: + + function log (args) + serial = TlsGetCertSerial() + if serial then + -- do something + end + end + SSH --- From ddf1bf6518fd2a87a143652944b129f1075766b9 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 17 Feb 2017 11:22:23 -0600 Subject: [PATCH 2487/2553] unified2: unlock using same dereference as lock Addresses Coverity CIDs: 1400797 1400796 Note that the mutex was actually being unlocked, but from a different variable pointing to the same mutex. --- src/alert-unified2-alert.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 1a6f5f567bf0..ca6da8adfc05 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -952,12 +952,12 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) if (ret != 1) { SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno)); aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } fflush(aun->unified2alert_ctx->file_ctx->fp); aun->unified2alert_ctx->file_ctx->alerts++; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); } return 0; @@ -1133,13 +1133,13 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) ret = Unified2PacketTypeAlert(aun, p, event_id, stream); if (ret != 1) { aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } fflush(aun->unified2alert_ctx->file_ctx->fp); aun->unified2alert_ctx->file_ctx->alerts++; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); } return 0; From 0c3f1e2974180f4382ed6c551f1de4a6d2650e56 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 20 Feb 2017 11:52:34 -0600 Subject: [PATCH 2488/2553] logging: move lock into write function All loggers were wrapping just the write in a lock with some updating a counter. This moves the lock into the write function. The log_ctx alerts counter was also removed as many modules have stopped using this and the alert count is available elsewhere. Should satisfy Coverity CID 1400798: CID 1400798 (#1 of 1): Data race condition (MISSING_LOCK) 2. missing_lock: Accessing log_ctx->rotation_flag without holding lock LogFileCtx_.fp_mutex. Elsewhere, "LogFileCtx_.rotation_flag" is accessed with LogFileCtx_.fp_mutex held 4 out of 5 times. Which appears to be a false positive as all calls to SCLogFileWrite were done under lock, but this will make it more explicit. --- src/alert-debuglog.c | 8 -------- src/alert-fastlog.c | 4 ---- src/alert-syslog.c | 8 +------- src/alert-unified2-alert.c | 8 -------- src/log-dnslog.c | 4 ---- src/log-httplog.c | 2 -- src/log-stats.c | 2 -- src/log-tcp-data.c | 2 -- src/log-tlslog.c | 2 -- src/util-logopenfile.c | 6 ++++-- src/util-logopenfile.h | 2 -- 11 files changed, 5 insertions(+), 43 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 7d0ad0e26171..6c56f69973c6 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -304,11 +304,8 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da } } - SCMutexLock(&aft->file_ctx->fp_mutex); aft->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), aft->file_ctx); - aft->file_ctx->alerts += p->alerts.cnt; - SCMutexUnlock(&aft->file_ctx->fp_mutex); return TM_ECODE_OK; } @@ -367,11 +364,8 @@ static TmEcode AlertDebugLogDecoderEvent(ThreadVars *tv, const Packet *p, void * PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, GET_PKT_DATA(p), GET_PKT_LEN(p)); - SCMutexLock(&aft->file_ctx->fp_mutex); aft->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), aft->file_ctx); - aft->file_ctx->alerts += p->alerts.cnt; - SCMutexUnlock(&aft->file_ctx->fp_mutex); return TM_ECODE_OK; } @@ -424,8 +418,6 @@ static void AlertDebugLogExitPrintStats(ThreadVars *tv, void *data) if (aft == NULL) { return; } - - SCLogInfo("(%s) Alerts %" PRIu64 "", tv->name, aft->file_ctx->alerts); } static void AlertDebugLogDeInitCtx(OutputCtx *output_ctx) diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 3fac2f66dfcd..d3f245508535 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -98,12 +98,8 @@ int AlertFastLogCondition(ThreadVars *tv, const Packet *p) static inline void AlertFastLogOutputAlert(AlertFastLogThread *aft, char *buffer, int alert_size) { - SCMutex *file_lock = &aft->file_ctx->fp_mutex; /* Output the alert string and count alerts. Only need to lock here. */ - SCMutexLock(file_lock); - aft->file_ctx->alerts++; aft->file_ctx->Write(buffer, alert_size, aft->file_ctx); - SCMutexUnlock(file_lock); } int AlertFastLogger(ThreadVars *tv, void *data, const Packet *p) diff --git a/src/alert-syslog.c b/src/alert-syslog.c index 869e33acf361..47aca2afc17f 100644 --- a/src/alert-syslog.c +++ b/src/alert-syslog.c @@ -205,10 +205,9 @@ static TmEcode AlertSyslogIPv4(ThreadVars *tv, const Packet *p, void *data) if (p->alerts.cnt == 0) return TM_ECODE_OK; + /* Not sure if this mutex is needed around calls to syslog. */ SCMutexLock(&ast->file_ctx->fp_mutex); - ast->file_ctx->alerts += p->alerts.cnt; - for (i = 0; i < p->alerts.cnt; i++) { const PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { @@ -265,8 +264,6 @@ static TmEcode AlertSyslogIPv6(ThreadVars *tv, const Packet *p, void *data) SCMutexLock(&ast->file_ctx->fp_mutex); - ast->file_ctx->alerts += p->alerts.cnt; - for (i = 0; i < p->alerts.cnt; i++) { const PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { @@ -328,7 +325,6 @@ static TmEcode AlertSyslogDecoderEvent(ThreadVars *tv, const Packet *p, void *da SCMutexLock(&ast->file_ctx->fp_mutex); - ast->file_ctx->alerts += p->alerts.cnt; char temp_buf_hdr[512]; char temp_buf_pkt[65] = ""; char temp_buf_tail[32]; @@ -383,8 +379,6 @@ static void AlertSyslogExitPrintStats(ThreadVars *tv, void *data) if (ast == NULL) { return; } - - SCLogInfo("(%s) Alerts %" PRIu64 "", tv->name, ast->file_ctx->alerts); } static int AlertSyslogCondition(ThreadVars *tv, const Packet *p) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index ca6da8adfc05..8e0dc8de62dd 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -928,7 +928,6 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) ? true : false; if (truncate || file_ctx->rotation_flag) { if (Unified2AlertRotateFile(aun, truncate) < 0) { - aun->unified2alert_ctx->file_ctx->alerts += i; SCMutexUnlock(&file_ctx->fp_mutex); return -1; } @@ -936,7 +935,6 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) } if (Unified2Write(aun) != 1) { - file_ctx->alerts += i; SCMutexUnlock(&file_ctx->fp_mutex); return -1; } @@ -951,12 +949,10 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) ret = Unified2PacketTypeAlert(aun, p, phdr->event_id, stream); if (ret != 1) { SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno)); - aun->unified2alert_ctx->file_ctx->alerts += i; SCMutexUnlock(&file_ctx->fp_mutex); return -1; } fflush(aun->unified2alert_ctx->file_ctx->fp); - aun->unified2alert_ctx->file_ctx->alerts++; SCMutexUnlock(&file_ctx->fp_mutex); } @@ -1108,7 +1104,6 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) ? true : false; if (truncate || file_ctx->rotation_flag) { if (Unified2AlertRotateFile(aun, truncate) < 0) { - file_ctx->alerts += i; SCMutexUnlock(&file_ctx->fp_mutex); return -1; } @@ -1116,7 +1111,6 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) } if (Unified2Write(aun) != 1) { - file_ctx->alerts += i; SCMutexUnlock(&file_ctx->fp_mutex); return -1; } @@ -1132,13 +1126,11 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) (pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0) : 0; ret = Unified2PacketTypeAlert(aun, p, event_id, stream); if (ret != 1) { - aun->unified2alert_ctx->file_ctx->alerts += i; SCMutexUnlock(&file_ctx->fp_mutex); return -1; } fflush(aun->unified2alert_ctx->file_ctx->fp); - aun->unified2alert_ctx->file_ctx->alerts++; SCMutexUnlock(&file_ctx->fp_mutex); } diff --git a/src/log-dnslog.c b/src/log-dnslog.c index 297e98f080c4..2b3658d2e788 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -96,10 +96,8 @@ static void LogQuery(LogDnsLogThread *aft, char *timebuf, char *srcip, char *dst " [**] %s [**] %s:%" PRIu16 " -> %s:%" PRIu16 "\n", record, srcip, sp, dstip, dp); - SCMutexLock(&hlog->file_ctx->fp_mutex); hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); - SCMutexUnlock(&hlog->file_ctx->fp_mutex); } static void LogAnswer(LogDnsLogThread *aft, char *timebuf, char *srcip, char *dstip, Port sp, Port dp, DNSTransaction *tx, DNSAnswerEntry *entry) @@ -159,10 +157,8 @@ static void LogAnswer(LogDnsLogThread *aft, char *timebuf, char *srcip, char *ds " [**] %s:%" PRIu16 " -> %s:%" PRIu16 "\n", srcip, sp, dstip, dp); - SCMutexLock(&hlog->file_ctx->fp_mutex); hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); - SCMutexUnlock(&hlog->file_ctx->fp_mutex); } static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, diff --git a/src/log-httplog.c b/src/log-httplog.c index 775fec636e92..94800005cf4b 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -498,10 +498,8 @@ static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, aft->uri_cnt ++; - SCMutexLock(&hlog->file_ctx->fp_mutex); hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); - SCMutexUnlock(&hlog->file_ctx->fp_mutex); end: SCReturnInt(0); diff --git a/src/log-stats.c b/src/log-stats.c index e82e1edb0ff5..7eb7c2444ac4 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -156,10 +156,8 @@ int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) } } - SCMutexLock(&aft->statslog_ctx->file_ctx->fp_mutex); aft->statslog_ctx->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), aft->statslog_ctx->file_ctx); - SCMutexUnlock(&aft->statslog_ctx->file_ctx->fp_mutex); MemBufferReset(aft->buffer); diff --git a/src/log-tcp-data.c b/src/log-tcp-data.c index 3a791a55dcef..00e18eec85bb 100644 --- a/src/log-tcp-data.c +++ b/src/log-tcp-data.c @@ -161,10 +161,8 @@ static int LogTcpDataLoggerFile(ThreadVars *tv, void *thread_data, const Flow *f PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)data,data_len); - SCMutexLock(&td->file_ctx->fp_mutex); td->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), td->file_ctx); - SCMutexUnlock(&td->file_ctx->fp_mutex); } SCReturnInt(TM_ECODE_OK); } diff --git a/src/log-tlslog.c b/src/log-tlslog.c index fc1deddae309..9e70149f03f8 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -323,10 +323,8 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, aft->tls_cnt++; - SCMutexLock(&hlog->file_ctx->fp_mutex); hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); - SCMutexUnlock(&hlog->file_ctx->fp_mutex); return 0; } diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index da644f7912ca..e62f139d3414 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -127,6 +127,8 @@ static int SCLogUnixSocketReconnect(LogFileCtx *log_ctx) */ static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx) { + SCMutexLock(&log_ctx->fp_mutex); + /* Check for rotation. */ if (log_ctx->rotation_flag) { log_ctx->rotation_flag = 0; @@ -152,6 +154,8 @@ static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ct } } + SCMutexUnlock(&log_ctx->fp_mutex); + return ret; } @@ -671,10 +675,8 @@ int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer) { /* append \n for files only */ MemBufferWriteString(buffer, "\n"); - SCMutexLock(&file_ctx->fp_mutex); file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), MEMBUFFER_OFFSET(buffer), file_ctx); - SCMutexUnlock(&file_ctx->fp_mutex); } #ifdef HAVE_LIBHIREDIS else if (file_ctx->type == LOGFILE_TYPE_REDIS) { diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index df423c8babc0..583ca3a403da 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -109,8 +109,6 @@ typedef struct LogFileCtx_ { uint64_t size_limit; /**< file size limit */ uint64_t size_current; /**< file current size */ - /* Alerts on the module (not on the file) */ - uint64_t alerts; /* flag to avoid multiple threads printing the same stats */ uint8_t flags; From 6585ac4a9faee41663f707fab8d463337ba06629 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 20 Feb 2017 12:00:15 -0600 Subject: [PATCH 2489/2553] logging: remove unused print stats callbacks Remove the ThreadExitPrintStats callback from logging modules that weren't doing anything with it. --- src/alert-debuglog.c | 11 +---------- src/alert-fastlog.c | 14 +------------- src/alert-syslog.c | 17 +---------------- src/log-httplog.c | 13 +------------ src/log-stats.c | 11 +---------- src/log-tcp-data.c | 14 ++------------ 6 files changed, 7 insertions(+), 73 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 6c56f69973c6..74ff0112803f 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -412,14 +412,6 @@ static TmEcode AlertDebugLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -static void AlertDebugLogExitPrintStats(ThreadVars *tv, void *data) -{ - AlertDebugLogThread *aft = (AlertDebugLogThread *)data; - if (aft == NULL) { - return; - } -} - static void AlertDebugLogDeInitCtx(OutputCtx *output_ctx) { if (output_ctx != NULL) { @@ -490,6 +482,5 @@ void AlertDebugLogRegister(void) { OutputRegisterPacketModule(LOGGER_ALERT_DEBUG, MODULE_NAME, "alert-debug", AlertDebugLogInitCtx, AlertDebugLogLogger, AlertDebugLogCondition, - AlertDebugLogThreadInit, AlertDebugLogThreadDeinit, - AlertDebugLogExitPrintStats); + AlertDebugLogThreadInit, AlertDebugLogThreadDeinit, NULL); } diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index d3f245508535..d475a6a38c3a 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -69,7 +69,6 @@ TmEcode AlertFastLogThreadInit(ThreadVars *, void *, void **); TmEcode AlertFastLogThreadDeinit(ThreadVars *, void *); -void AlertFastLogExitPrintStats(ThreadVars *, void *); void AlertFastLogRegisterTests(void); static void AlertFastLogDeInitCtx(OutputCtx *); @@ -80,8 +79,7 @@ void AlertFastLogRegister(void) { OutputRegisterPacketModule(LOGGER_ALERT_FAST, MODULE_NAME, "fast", AlertFastLogInitCtx, AlertFastLogger, AlertFastLogCondition, - AlertFastLogThreadInit, AlertFastLogThreadDeinit, - AlertFastLogExitPrintStats); + AlertFastLogThreadInit, AlertFastLogThreadDeinit, NULL); AlertFastLogRegisterTests(); } @@ -217,16 +215,6 @@ TmEcode AlertFastLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void AlertFastLogExitPrintStats(ThreadVars *tv, void *data) -{ - AlertFastLogThread *aft = (AlertFastLogThread *)data; - if (aft == NULL) { - return; - } - - //SCLogInfo("Fast log output wrote %" PRIu64 " alerts", aft->file_ctx->alerts); -} - /** * \brief Create a new LogFileCtx for "fast" output style. * \param conf The configuration node for this output. diff --git a/src/alert-syslog.c b/src/alert-syslog.c index 47aca2afc17f..8de1d3a9c211 100644 --- a/src/alert-syslog.c +++ b/src/alert-syslog.c @@ -367,20 +367,6 @@ static TmEcode AlertSyslogDecoderEvent(ThreadVars *tv, const Packet *p, void *da return TM_ECODE_OK; } -/** - * \brief Function to print the total alert while closing the engine - * - * \param tv Pointer to the output threadvars - * \param data Pointer to the AlertSyslogThread data - */ -static void AlertSyslogExitPrintStats(ThreadVars *tv, void *data) -{ - AlertSyslogThread *ast = (AlertSyslogThread *)data; - if (ast == NULL) { - return; - } -} - static int AlertSyslogCondition(ThreadVars *tv, const Packet *p) { return (p->alerts.cnt > 0 ? TRUE : FALSE); @@ -407,7 +393,6 @@ void AlertSyslogRegister (void) #ifndef OS_WIN32 OutputRegisterPacketModule(LOGGER_ALERT_SYSLOG, MODULE_NAME, "syslog", AlertSyslogInitCtx, AlertSyslogLogger, AlertSyslogCondition, - AlertSyslogThreadInit, AlertSyslogThreadDeinit, - AlertSyslogExitPrintStats); + AlertSyslogThreadInit, AlertSyslogThreadDeinit, NULL); #endif /* !OS_WIN32 */ } diff --git a/src/log-httplog.c b/src/log-httplog.c index 94800005cf4b..a825ae40232f 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -58,7 +58,6 @@ TmEcode LogHttpLogThreadInit(ThreadVars *, void *, void **); TmEcode LogHttpLogThreadDeinit(ThreadVars *, void *); -void LogHttpLogExitPrintStats(ThreadVars *, void *); static void LogHttpLogDeInitCtx(OutputCtx *); int LogHttpLogger(ThreadVars *tv, void *thread_data, const Packet *, Flow *f, void *state, void *tx, uint64_t tx_id); @@ -67,7 +66,7 @@ void LogHttpLogRegister (void) { OutputRegisterTxModule(LOGGER_HTTP, MODULE_NAME, "http-log", LogHttpLogInitCtx, ALPROTO_HTTP, LogHttpLogger, LogHttpLogThreadInit, - LogHttpLogThreadDeinit, LogHttpLogExitPrintStats); + LogHttpLogThreadDeinit, NULL); } #define LOG_HTTP_MAXN_NODES 64 @@ -566,16 +565,6 @@ TmEcode LogHttpLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void LogHttpLogExitPrintStats(ThreadVars *tv, void *data) -{ - LogHttpLogThread *aft = (LogHttpLogThread *)data; - if (aft == NULL) { - return; - } - - //SCLogInfo("HTTP logger logged %" PRIu32 " requests", aft->uri_cnt); -} - /** \brief Create a new http log LogFileCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful diff --git a/src/log-stats.c b/src/log-stats.c index 7eb7c2444ac4..69fe82d2053c 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -55,7 +55,6 @@ TmEcode LogStatsLogThreadInit(ThreadVars *, void *, void **); TmEcode LogStatsLogThreadDeinit(ThreadVars *, void *); -void LogStatsLogExitPrintStats(ThreadVars *, void *); static void LogStatsLogDeInitCtx(OutputCtx *); typedef struct LogStatsFileCtx_ { @@ -206,14 +205,6 @@ TmEcode LogStatsLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void LogStatsLogExitPrintStats(ThreadVars *tv, void *data) -{ - LogStatsLogThread *aft = (LogStatsLogThread *)data; - if (aft == NULL) { - return; - } -} - /** \brief Create a new http log LogFileCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful @@ -296,5 +287,5 @@ void LogStatsLogRegister (void) { OutputRegisterStatsModule(LOGGER_STATS, MODULE_NAME, "stats", LogStatsLogInitCtx, LogStatsLogger, LogStatsLogThreadInit, - LogStatsLogThreadDeinit, LogStatsLogExitPrintStats); + LogStatsLogThreadDeinit, NULL); } diff --git a/src/log-tcp-data.c b/src/log-tcp-data.c index 00e18eec85bb..c2faa046ee26 100644 --- a/src/log-tcp-data.c +++ b/src/log-tcp-data.c @@ -55,7 +55,6 @@ TmEcode LogTcpDataLogThreadInit(ThreadVars *, void *, void **); TmEcode LogTcpDataLogThreadDeinit(ThreadVars *, void *); -void LogTcpDataLogExitPrintStats(ThreadVars *, void *); static void LogTcpDataLogDeInitCtx(OutputCtx *); int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags); @@ -63,12 +62,10 @@ int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uin void LogTcpDataLogRegister (void) { OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "tcp-data", LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_TCP_DATA, - LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, - LogTcpDataLogExitPrintStats); + LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, NULL); OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "http-body-data", LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_HTTP_BODIES, - LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, - LogTcpDataLogExitPrintStats); + LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, NULL); } typedef struct LogTcpDataFileCtx_ { @@ -224,13 +221,6 @@ TmEcode LogTcpDataLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void LogTcpDataLogExitPrintStats(ThreadVars *tv, void *data) { - LogTcpDataLogThread *aft = (LogTcpDataLogThread *)data; - if (aft == NULL) { - return; - } -} - /** \brief Create a new http log LogFileCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful From db5708f6ad2a9cf622b30feecaa5030554ec1d38 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 17 Mar 2017 11:11:07 -0600 Subject: [PATCH 2490/2553] travis: fix libpcre in mac builds It looks like Travis changed their Mac image and pcre is now installed by default. In case it gets removed again, just unlink it before re-installing so it doesn't fail on install. --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 409ff648e6f6..45c53cda71b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -126,6 +126,10 @@ before_install: - | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update + + # Unlink pcre in case its already installed. + brew unlink pcre || true + brew install pkg-config libmagic libyaml nss nspr jansson libnet lua \ pcre hiredis fi From 205975009ab4dba0130b3a11e927156d5cac8439 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 24 Mar 2017 12:40:18 +0100 Subject: [PATCH 2491/2553] travis: fix pkg-config in mac builds Unlink pkg-config before installing. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 45c53cda71b9..168454fc22ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -129,6 +129,7 @@ before_install: # Unlink pcre in case its already installed. brew unlink pcre || true + brew unlink pkg-config || true brew install pkg-config libmagic libyaml nss nspr jansson libnet lua \ pcre hiredis From 25bd3e28f7f63af1834b72e2045498d82be66182 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 24 Mar 2017 10:15:09 +0100 Subject: [PATCH 2492/2553] qa/appveyor: install libiconv-devel --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 58915eddb2f5..3419d1c98e09 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -31,7 +31,7 @@ init: install: - ps: 'Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP"' - '%CYG_SETUP% -gqnNdO --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" > NUL 2>&1' - - '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages automake,bison,gcc-core,libtool,make,gettext-devel,gettext,intltool,pkg-config,clang,llvm,libpcre-devel,file-devel,wget,zlib-devel,libnss-devel,libnspr-devel,libGeoIP-devel,libyaml-devel,luajit-devel,unzip > NUL 2>&1' + - '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages automake,bison,gcc-core,libtool,make,gettext-devel,gettext,intltool,pkg-config,clang,llvm,libpcre-devel,file-devel,wget,zlib-devel,libnss-devel,libnspr-devel,libGeoIP-devel,libyaml-devel,luajit-devel,unzip,libiconv,libiconv-devel > NUL 2>&1' - '%CYG_BASH% -lc "cygcheck -dc cygwin"' - '%CYG_BASH% -lc "wget https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip && ls && unzip WpdPack_4_1_2.zip"' - '%CYG_BASH% -lc "cp WpdPack/Lib/libpacket.a /usr/lib/"' From a86b7b704217c2772e43c4aacb64bfa807bd0a0e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 22 Feb 2017 16:34:37 +0100 Subject: [PATCH 2493/2553] app-layer: minor debug improvement --- src/app-layer-detect-proto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 92bb37eefc79..338d6e8149bd 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1324,7 +1324,7 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, alproto = AppLayerProtoDetectPPGetProto(f, buf, buflen, ipproto, direction); end: - SCReturnCT(alproto, "AppProto"); + SCReturnUInt(alproto); } static void AppLayerProtoDetectFreeProbingParsers(AppLayerProtoDetectProbingParser *pp) From 2a5b9eb5fa61dfc83547c53e63c8e6b9da36e70e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 17 Feb 2017 16:00:42 +0100 Subject: [PATCH 2494/2553] stream: remove unused variable --- src/detect.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/detect.c b/src/detect.c index b48bad4ab2b2..657f831aed8b 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1365,9 +1365,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh if (sflags & SIG_FLAG_REQUIRE_STREAM) { char pmatch = 0; if (det_ctx->smsg != NULL) { - uint8_t pmq_idx = 0; StreamMsg *smsg_inspect = det_ctx->smsg; - for ( ; smsg_inspect != NULL; smsg_inspect = smsg_inspect->next, pmq_idx++) { + for ( ; smsg_inspect != NULL; smsg_inspect = smsg_inspect->next) { if (DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, pflow, smsg_inspect->data, smsg_inspect->data_len) == 1) { SCLogDebug("match in smsg %p", smsg_inspect); pmatch = 1; From 75129496707434bf3032fed586d47dc7e3619901 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 24 Apr 2016 09:33:54 +0200 Subject: [PATCH 2495/2553] stream: make data pointer in StreamSegmentCallback const --- src/alert-debuglog.c | 2 +- src/alert-unified2-alert.c | 2 +- src/output-json-alert.c | 2 +- src/stream.h | 2 +- src/util-print.c | 2 +- src/util-print.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 74ff0112803f..4ab39c97d0c1 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -136,7 +136,7 @@ static void AlertDebugLogPktVars(AlertDebugLogThread *aft, const Packet *p) /** \todo doc * assume we have aft lock */ -static int AlertDebugPrintStreamSegmentCallback(const Packet *p, void *data, uint8_t *buf, uint32_t buflen) +static int AlertDebugPrintStreamSegmentCallback(const Packet *p, void *data, const uint8_t *buf, uint32_t buflen) { AlertDebugLogThread *aft = (AlertDebugLogThread *)data; diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 8e0dc8de62dd..e29549160d64 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -433,7 +433,7 @@ static int Unified2ForgeFakeIPv6Header(FakeIPv6Hdr *fakehdr, const Packet *p, in /** * \brief Write a faked Packet in unified2 file for each stream segment. */ -static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8_t *buf, uint32_t buflen) +static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, const uint8_t *buf, uint32_t buflen) { int ret = 1; Unified2AlertThread *aun = (Unified2AlertThread *)data; diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 135ee618edcb..89a582cf5068 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -102,7 +102,7 @@ typedef struct JsonAlertLogThread_ { /* Callback function to pack payload contents from a stream into a buffer * so we can report them in JSON output. */ -static int AlertJsonDumpStreamSegmentCallback(const Packet *p, void *data, uint8_t *buf, uint32_t buflen) +static int AlertJsonDumpStreamSegmentCallback(const Packet *p, void *data, const uint8_t *buf, uint32_t buflen) { MemBuffer *payload = (MemBuffer *)data; MemBufferWriteRaw(payload, buf, buflen); diff --git a/src/stream.h b/src/stream.h index dfe5c342e88c..72674f803d1f 100644 --- a/src/stream.h +++ b/src/stream.h @@ -70,7 +70,7 @@ uint16_t StreamMsgQueueGetMinChunkLen(uint8_t); void StreamMsgReturnListToPool(void *); -typedef int (*StreamSegmentCallback)(const Packet *, void *, uint8_t *, uint32_t); +typedef int (*StreamSegmentCallback)(const Packet *, void *, const uint8_t *, uint32_t); int StreamSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); diff --git a/src/util-print.c b/src/util-print.c index 5882b1865ebb..13f19d4978e0 100644 --- a/src/util-print.c +++ b/src/util-print.c @@ -168,7 +168,7 @@ void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen) } void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - uint8_t *src_buf, uint32_t src_buf_len) + const uint8_t *src_buf, uint32_t src_buf_len) { int ch = 0; uint32_t u = 0; diff --git a/src/util-print.h b/src/util-print.h index a696a98aa3c3..674e3d32c453 100644 --- a/src/util-print.h +++ b/src/util-print.h @@ -48,7 +48,7 @@ void PrintRawUriBuf(char *, uint32_t *, uint32_t, void PrintRawJsonFp(FILE *, uint8_t *, uint32_t); void PrintRawDataFp(FILE *, const uint8_t *, uint32_t); void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - uint8_t *src_buf, uint32_t src_buf_len); + const uint8_t *src_buf, uint32_t src_buf_len); void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, uint8_t *src_buf, uint32_t src_buf_len); void PrintRawLineHexBuf(char *, uint32_t, uint8_t *, uint32_t ); From daf39b422bcb1395475f632e8a75a56c5079322b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 26 Feb 2017 18:32:27 +0100 Subject: [PATCH 2496/2553] stream: remove unused stream config member --- src/stream-tcp.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/stream-tcp.h b/src/stream-tcp.h index 2ae304fa472a..e49ab9a8d3e8 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -65,11 +65,6 @@ typedef struct TcpStreamCnf_ { int check_overlap_different_data; int bypass; - /** reassembly -- inline mode - * - * sliding window size for raw stream reassembly - */ - uint32_t reassembly_inline_window; uint8_t flags; uint8_t max_synack_queued; } TcpStreamCnf; From 1de1413863d06f9409d756af64a98f5370fef51b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Feb 2017 12:27:11 +0100 Subject: [PATCH 2497/2553] stream: validate SACK right edge to be in window --- src/stream-tcp-sack.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/stream-tcp-sack.c b/src/stream-tcp-sack.c index d3be60e9200c..ab0ad57faa82 100644 --- a/src/stream-tcp-sack.c +++ b/src/stream-tcp-sack.c @@ -271,13 +271,12 @@ int StreamTcpSackUpdatePacket(TcpStream *stream, Packet *p) goto next; } - /** \todo need a metric to a check for a right edge limit */ -/* - if (SEQ_GT(ntohl(sack_rec->re), stream->next_seq)) { - SCLogDebug("record beyond next_seq %u", stream->next_seq); + if (SEQ_GT(ntohl(sack_rec->re), stream->next_win)) { + SCLogDebug("record %u:%u beyond next_win %u", + ntohl(sack_rec->le), ntohl(sack_rec->re), stream->next_win); goto next; } -*/ + if (SEQ_GEQ(ntohl(sack_rec->le), ntohl(sack_rec->re))) { SCLogDebug("invalid record: le >= re"); goto next; From 4c597bb9e1695078b09faa120954982c83f7aaa1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Feb 2017 18:32:22 +0100 Subject: [PATCH 2498/2553] ippair: use both addresses in hash --- src/ippair.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/ippair.c b/src/ippair.c index 84137ca8fa3c..d7d3440c668a 100644 --- a/src/ippair.c +++ b/src/ippair.c @@ -338,6 +338,31 @@ void IPPairCleanup(void) return; } +/** \brief compare two raw ipv6 addrs + * + * \note we don't care about the real ipv6 ip's, this is just + * to consistently fill the FlowHashKey6 struct, without all + * the ntohl calls. + * + * \warning do not use elsewhere unless you know what you're doing. + * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely + * what you are looking for. + * Copied from FlowHashRawAddressIPv6GtU32 + */ +static inline int IPPairHashRawAddressIPv6GtU32(const uint32_t *a, const uint32_t *b) +{ + int i; + + for (i = 0; i < 4; i++) { + if (a[i] > b[i]) + return 1; + if (a[i] < b[i]) + break; + } + + return 0; +} + /* calculate the hash key for this packet * * we're using: @@ -349,10 +374,32 @@ static uint32_t IPPairGetKey(Address *a, Address *b) uint32_t key; if (a->family == AF_INET) { - uint32_t hash = hashword(&a->addr_data32[0], 1, ippair_config.hash_rand); + uint32_t addrs[2] = { MIN(a->addr_data32[0], b->addr_data32[0]), + MAX(a->addr_data32[0], b->addr_data32[0]) }; + uint32_t hash = hashword(addrs, 2, ippair_config.hash_rand); key = hash % ippair_config.hash_size; } else if (a->family == AF_INET6) { - uint32_t hash = hashword(a->addr_data32, 4, ippair_config.hash_rand); + uint32_t addrs[8]; + if (IPPairHashRawAddressIPv6GtU32(&a->addr_data32[0],&b->addr_data32[0])) { + addrs[0] = b->addr_data32[0]; + addrs[1] = b->addr_data32[1]; + addrs[2] = b->addr_data32[2]; + addrs[3] = b->addr_data32[3]; + addrs[4] = a->addr_data32[0]; + addrs[5] = a->addr_data32[1]; + addrs[6] = a->addr_data32[2]; + addrs[7] = a->addr_data32[3]; + } else { + addrs[0] = a->addr_data32[0]; + addrs[1] = a->addr_data32[1]; + addrs[2] = a->addr_data32[2]; + addrs[3] = a->addr_data32[3]; + addrs[4] = b->addr_data32[0]; + addrs[5] = b->addr_data32[1]; + addrs[6] = b->addr_data32[2]; + addrs[7] = b->addr_data32[3]; + } + uint32_t hash = hashword(addrs, 8, ippair_config.hash_rand); key = hash % ippair_config.hash_size; } else key = 0; From 132e0e21f0599a4b38df24e544882681b0e8d33f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Feb 2017 20:38:41 +0100 Subject: [PATCH 2499/2553] ippair: fix xbits unset memleak --- src/ippair-bit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ippair-bit.c b/src/ippair-bit.c index c617371630d5..8ea1bc4d6ba1 100644 --- a/src/ippair-bit.c +++ b/src/ippair-bit.c @@ -123,6 +123,7 @@ static void IPPairBitRemove(IPPair *h, uint32_t idx) GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); if (gv) { GenericVarRemove(&gv, (GenericVar *)fb); + XBitFree(fb); IPPairSetStorageById(h, ippair_bit_id, gv); } } From 7c0a3b558229274cb12fdd080c132c3f2049f31f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 23 Feb 2017 16:45:32 +0100 Subject: [PATCH 2500/2553] app-layer: fix memleak on bad traffic If state was alloc'd after protocol detection, but then the direction turned out to be wrong, the state would not be freed. --- src/app-layer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app-layer.c b/src/app-layer.c index 5d0fa13581a9..471f358b5d5b 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -145,6 +145,7 @@ static void DisableAppLayer(ThreadVars *tv, Flow *f, Packet *p) { SCLogDebug("disable app layer for flow %p alproto %u ts %u tc %u", f, f->alproto, f->alproto_ts, f->alproto_tc); + FlowCleanupAppLayer(f); StreamTcpDisableAppLayer(f); TcpSession *ssn = f->protoctx; ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; From f1e19b5dd40683a0144642b181298ae94d249b06 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 10 Mar 2017 19:12:32 +0100 Subject: [PATCH 2501/2553] file store: store multiple files if available --- src/output-filedata.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/output-filedata.c b/src/output-filedata.c index 0f2f9e29d73d..7beca04acad9 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -226,7 +226,6 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data) /* all done */ if (flags & OUTPUT_FILEDATA_FLAG_CLOSE) { ff->flags |= FILE_STORED; - break; } } } From dbbf18517378a326e0bd2f72f7ce7d5c2232493a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 26 Feb 2017 19:56:38 +0100 Subject: [PATCH 2502/2553] app-layer: fix gap handling in protocol detection A GAP during protocol detection would lead to all reassembly getting disabled, so also the raw reassembly. In addition, it could prevent the opposing side from doing protocol detection. This patch remove the 'disable reassembly' logic. Stream engine will take the stream with GAP and app-layer will make the proto detection as complete. --- src/app-layer.c | 4 ---- src/stream-tcp-reassemble.c | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index 471f358b5d5b..8cbb86838d59 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -560,7 +560,6 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, AppLayerThreadCtx *app_tctx = ra_ctx->app_tctx; AppProto alproto; - uint8_t dir; int r = 0; SCLogDebug("data_len %u flags %02X", data_len, flags); @@ -571,10 +570,8 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (flags & STREAM_TOSERVER) { alproto = f->alproto_ts; - dir = 0; } else { alproto = f->alproto_tc; - dir = 1; } /* if we don't know the proto yet and we have received a stream @@ -583,7 +580,6 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, * only run the proto detection once. */ if (alproto == ALPROTO_UNKNOWN && (flags & STREAM_GAP)) { StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); - StreamTcpSetSessionNoReassemblyFlag(ssn, dir); SCLogDebug("ALPROTO_UNKNOWN flow %p, due to GAP in stream start", f); } else if (alproto == ALPROTO_UNKNOWN && (flags & STREAM_START)) { diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index a3896435ae67..9632c116bd99 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2903,7 +2903,7 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, /* this function can be directly called by app layer protocol * detection. */ - if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) { + if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY|STREAMTCP_STREAM_FLAG_GAP)) { SCLogDebug("stream no reassembly flag set. Mostly called via " "app proto detection."); SCReturnInt(0); From 15d26f14e16150f3dcc3d238c76eb1eb490e1faa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 1 Mar 2017 23:23:04 +0100 Subject: [PATCH 2503/2553] file-store: fix force store --- src/detect.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/detect.c b/src/detect.c index 657f831aed8b..7b0881ee9548 100644 --- a/src/detect.c +++ b/src/detect.c @@ -895,7 +895,9 @@ static inline void DetectPostInspectFileFlagsUpdate(Flow *pflow, const SigGroupHead *sgh, uint8_t direction) { /* see if this sgh requires us to consider file storing */ - if (sgh == NULL || sgh->filestore_cnt == 0) { + if (!FileForceFilestore() && (sgh == NULL || + sgh->filestore_cnt == 0)) + { FileDisableStoring(pflow, direction); } #ifdef HAVE_MAGIC From 3626ecb4748f7c68fd56d13de1c2e0476f17f892 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 6 Mar 2017 10:54:57 +0100 Subject: [PATCH 2504/2553] bytejump: don't print errors when matching When bytejump was told to convert some payload data to int from a string it would print an error to the screen if the conversion failed. This is unwanted as the payload is controlled by an attacker and printing is expensive. --- src/detect-bytejump.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 8db0adfefba2..272b23ebddd4 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -137,18 +137,18 @@ int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, extbytes = ByteExtractStringUint64(&val, data->base, data->nbytes, (const char *)ptr); if(extbytes <= 0) { - SCLogError(SC_ERR_BYTE_EXTRACT_FAILED,"Error extracting %d bytes " - "of string data: %d", data->nbytes, extbytes); - SCReturnInt(-1); + SCLogDebug("error extracting %d bytes of string data: %d", + data->nbytes, extbytes); + SCReturnInt(0); } } else { int endianness = (flags & DETECT_BYTEJUMP_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN; extbytes = ByteExtractUint64(&val, endianness, data->nbytes, ptr); if (extbytes != data->nbytes) { - SCLogError(SC_ERR_BYTE_EXTRACT_FAILED,"Error extracting %d bytes " - "of numeric data: %d", data->nbytes, extbytes); - SCReturnInt(-1); + SCLogDebug("error extracting %d bytes of numeric data: %d", + data->nbytes, extbytes); + SCReturnInt(0); } } From c961da2dceefd6a82168eadabdcfc624ea8d799a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 28 Feb 2017 00:28:10 +0100 Subject: [PATCH 2505/2553] detect: clean up test --- src/detect.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/detect.c b/src/detect.c index 7b0881ee9548..58c4809559f6 100644 --- a/src/detect.c +++ b/src/detect.c @@ -8798,55 +8798,43 @@ static int SigTestDetectAlertCounter(void) Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - memset(&tv, 0, sizeof(tv)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test counter\"; " "content:\"boo\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); strlcpy(tv.name, "detect_test", sizeof(tv.name)); DetectEngineThreadCtxInit(&tv, de_ctx, (void *)&det_ctx); - /* init counters */ StatsSetupPrivate(&tv); p = UTHBuildPacket((uint8_t *)"boo", strlen("boo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result = (StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 1); + FAIL_IF_NOT(StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 1); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); + FAIL_IF_NOT(StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"roo", strlen("roo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); + FAIL_IF_NOT(StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"laboosa", strlen("laboosa"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 3); + FAIL_IF_NOT(StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 3); UTHFreePackets(&p, 1); -end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test test if the engine set flag to drop pkts of a flow that From 6c6802b9576df68a0d5de7b84339a72918484af5 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Feb 2017 23:39:41 +0100 Subject: [PATCH 2506/2553] detect: simplify state detect code: remove unused params --- src/detect-engine-state.c | 5 ++--- src/detect-engine-state.h | 5 ++--- src/detect.c | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 687e3b397ba6..5e3431b6bf64 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -244,7 +244,7 @@ void DetectEngineStateFree(DetectEngineState *state) return; } -static int HasStoredSigs(Flow *f, uint8_t flags) +static int HasStoredSigs(const Flow *f, const uint8_t flags) { if (AppLayerParserProtocolSupportsTxs(f->proto, f->alproto)) { AppProto alproto = f->alproto; @@ -290,8 +290,7 @@ static int HasStoredSigs(Flow *f, uint8_t flags) * \retval 0 no inspectable state * \retval 1 inspectable state */ -int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, - const uint8_t alversion, uint8_t flags) +int DeStateFlowHasInspectableState(const Flow *f, const uint8_t flags) { int r = 0; diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 9c46d84ef4a2..31bd4132264f 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -125,13 +125,12 @@ void DetectEngineStateFree(DetectEngineState *state); * \brief Check if a flow already contains(newly updated as well) de state. * * \param f Pointer to the flow. - * \param alversino The alversion to check against de_state's. - * \param direction Direction to check. 0 - ts, 1 - tc. + * \param flags direction * * \retval 1 Has state. * \retval 0 Has no state. */ -int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint8_t alversion, uint8_t flags); +int DeStateFlowHasInspectableState(const Flow *f, const uint8_t flags); /** * \brief Match app layer sig list against app state and store relevant match diff --git a/src/detect.c b/src/detect.c index 58c4809559f6..5a2355faa509 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1166,7 +1166,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* stateful app layer detection */ if ((p->flags & PKT_HAS_FLOW) && has_state) { memset(det_ctx->de_state_sig_array, 0x00, det_ctx->de_state_sig_array_len); - int has_inspectable_state = DeStateFlowHasInspectableState(pflow, alproto, alversion, flow_flags); + int has_inspectable_state = DeStateFlowHasInspectableState(pflow, flow_flags); if (has_inspectable_state == 1) { /* initialize to 0(DE_STATE_MATCH_HAS_NEW_STATE) */ DeStateDetectContinueDetection(th_v, de_ctx, det_ctx, p, pflow, From c066f043a5d039318be1f0148d3b34f2cd9aa2e0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Feb 2017 23:44:00 +0100 Subject: [PATCH 2507/2553] detect: remove unused alversion logic --- src/detect-engine-state.c | 15 ++++----------- src/detect-engine-state.h | 7 ++----- src/detect.c | 6 ++---- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 5e3431b6bf64..98e1304c04bb 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -194,12 +194,6 @@ static void DeStateSignatureAppend(DetectEngineState *state, return; } -static void DeStateStoreStateVersion(Flow *f, - const uint8_t alversion, uint8_t direction) -{ - f->detect_alversion[direction & STREAM_TOSERVER ? 0 : 1] = alversion; -} - static void DeStateStoreFileNoMatchCnt(DetectEngineState *de_state, uint16_t file_no_match, uint8_t direction) { de_state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].filestore_cnt += file_no_match; @@ -337,7 +331,7 @@ static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx, * \param check_before_add check for duplicates before adding the sig */ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, - Flow *f, const uint8_t flags, const uint8_t alversion, + Flow *f, const uint8_t flags, const uint64_t tx_id, void *tx, const Signature *s, const SigMatchData *smd, const uint32_t inspect_flags, const uint16_t file_no_match, int check_before_add) @@ -359,7 +353,6 @@ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, if (check_before_add == 0 || DeStateSearchState(destate, flags, s->num) == 0) DeStateSignatureAppend(destate, s, inspect_flags, flags); - DeStateStoreStateVersion(f, alversion, flags); StoreStateTxHandleFiles(det_ctx, f, destate, flags, tx_id, file_no_match); } @@ -369,7 +362,7 @@ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, const uint8_t alversion) + AppProto alproto) { SigMatchData *smd = NULL; uint16_t file_no_match = 0; @@ -496,7 +489,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } /* store */ - StoreStateTx(det_ctx, f, flags, alversion, tx_id, tx, + StoreStateTx(det_ctx, f, flags, tx_id, tx, s, smd, inspect_flags, file_no_match, check_before_add); } else { StoreStateTxFileOnly(det_ctx, f, flags, tx_id, tx, file_no_match); @@ -721,7 +714,7 @@ static int DoInspectItem(ThreadVars *tv, void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, const uint8_t alversion) + AppProto alproto) { uint16_t file_no_match = 0; SigIntId store_cnt = 0; diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 31bd4132264f..224160caf92c 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -143,15 +143,13 @@ int DeStateFlowHasInspectableState(const Flow *f, const uint8_t flags); * \param f Pointer to the flow. * \param flags Flags. * \param alproto App protocol. - * \param alversion Current app layer version. * * \retval >= 0 An integer value indicating the no of matches. */ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p, Flow *f, - uint8_t flags, - AppProto alproto, uint8_t alversion); + uint8_t flags, AppProto alproto); /** * \brief Continue DeState detection of the signatures stored in the state. @@ -162,12 +160,11 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, * \param f Pointer to the flow. * \param flags Flags. * \param alproto App protocol. - * \param alversion Current app layer version. */ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, uint8_t alversion); + AppProto alproto); /** * \brief Update the inspect id. diff --git a/src/detect.c b/src/detect.c index 5a2355faa509..fd729ed39c3f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -978,7 +978,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh uint8_t flow_flags = 0; /* flow/state flags */ const Signature *s = NULL; const Signature *next_s = NULL; - uint8_t alversion = 0; int state_alert = 0; int alerts = 0; int app_decoder_events = 0; @@ -1088,7 +1087,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh flow_flags = FlowGetDisruptionFlags(pflow, flow_flags); has_state = (FlowGetAppState(pflow) != NULL); alproto = FlowGetAppProtocol(pflow); - alversion = AppLayerParserGetStateVersion(pflow->alparser); SCLogDebug("alstate %s, alproto %u", has_state ? "true" : "false", alproto); } else { SCLogDebug("packet doesn't have established flag set (proto %d)", p->proto); @@ -1170,7 +1168,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh if (has_inspectable_state == 1) { /* initialize to 0(DE_STATE_MATCH_HAS_NEW_STATE) */ DeStateDetectContinueDetection(th_v, de_ctx, det_ctx, p, pflow, - flow_flags, alproto, alversion); + flow_flags, alproto); } } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); @@ -1444,7 +1442,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh * can store the tx_id with the alert */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); state_alert = DeStateDetectStartDetection(th_v, de_ctx, det_ctx, s, - p, pflow, flow_flags, alproto, alversion); + p, pflow, flow_flags, alproto); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); if (state_alert == 0) goto next; From a56b4817ef49803d36ca5e14c6ab795c5de8d172 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Feb 2017 23:51:31 +0100 Subject: [PATCH 2508/2553] flow: remove unused alversion fields --- src/flow-util.h | 4 ---- src/flow.h | 3 --- 2 files changed, 7 deletions(-) diff --git a/src/flow-util.h b/src/flow-util.h index dfbba64cb1b9..6258a01959c6 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -57,8 +57,6 @@ (f)->alproto_tc = 0; \ (f)->de_ctx_version = 0; \ (f)->thread_id = 0; \ - (f)->detect_alversion[0] = 0; \ - (f)->detect_alversion[1] = 0; \ (f)->alparser = NULL; \ (f)->alstate = NULL; \ (f)->sgh_toserver = NULL; \ @@ -99,8 +97,6 @@ (f)->alproto_tc = 0; \ (f)->de_ctx_version = 0; \ (f)->thread_id = 0; \ - (f)->detect_alversion[0] = 0; \ - (f)->detect_alversion[1] = 0; \ (f)->sgh_toserver = NULL; \ (f)->sgh_toclient = NULL; \ GenericVarFree((f)->flowvar); \ diff --git a/src/flow.h b/src/flow.h index b12554135d92..a490a82427cb 100644 --- a/src/flow.h +++ b/src/flow.h @@ -392,9 +392,6 @@ typedef struct Flow_ /** Thread ID for the stream/detect portion of this flow */ FlowThreadId thread_id; - /** detect state 'alversion' inspected for both directions */ - uint8_t detect_alversion[2]; - /** application level storage ptrs. * */ From e24eb0f2b17cfa4e96b32ad9f0ff274d639bb685 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 28 Feb 2017 09:38:00 +0100 Subject: [PATCH 2509/2553] app-layer: remove version logic --- src/app-layer-parser.c | 17 +---------------- src/app-layer-parser.h | 1 - 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index d16391d07e22..49975175ebae 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -136,8 +136,6 @@ typedef struct AppLayerParserCtx_ { struct AppLayerParserState_ { uint8_t flags; - /* State version, incremented for each update. Can wrap around. */ - uint8_t version; /* Indicates the current transaction that is being inspected. * We have a var per direction. */ uint64_t inspect_id[2]; @@ -682,12 +680,6 @@ AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alp SCReturnPtr(ptr, "AppLayerDecoderEvents *"); } -uint16_t AppLayerParserGetStateVersion(AppLayerParserState *pstate) -{ - SCEnter(); - SCReturnCT((pstate == NULL) ? 0 : pstate->version, "uint8_t"); -} - FileContainer *AppLayerParserGetFiles(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t direction) { @@ -969,9 +961,6 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow if (pstate == NULL) goto error; } - pstate->version++; - SCLogDebug("app layer parser state version incremented to %"PRIu8, - pstate->version); if (flags & STREAM_EOF) AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF); @@ -1074,9 +1063,6 @@ void AppLayerParserSetEOF(AppLayerParserState *pstate) goto end; AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF); - /* increase version so we will inspect it one more time - * with the EOF flags now set */ - pstate->version++; end: SCReturn; @@ -1304,10 +1290,9 @@ void AppLayerParserStatePrintDetails(AppLayerParserState *pstate) "p->inspect_id[0](%"PRIu64"), " "p->inspect_id[1](%"PRIu64"), " "p->log_id(%"PRIu64"), " - "p->version(%"PRIu8"), " "p->decoder_events(%p).", pstate, p->inspect_id[0], p->inspect_id[1], p->log_id, - p->version, p->decoder_events); + p->decoder_events); SCReturn; } diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index 9cd6d99192f7..29e668ce7f14 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -175,7 +175,6 @@ AppLayerDecoderEvents *AppLayerParserGetDecoderEvents(AppLayerParserState *pstat void AppLayerParserSetDecoderEvents(AppLayerParserState *pstate, AppLayerDecoderEvents *devents); AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id); -uint16_t AppLayerParserGetStateVersion(AppLayerParserState *pstate); FileContainer *AppLayerParserGetFiles(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t direction); int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, From 4f8eacdc692c3ae9e2f03b18a39391c1a038157c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 1 Mar 2017 23:32:21 +0100 Subject: [PATCH 2510/2553] disable-detect: fix needless file hashing When detection is running flags are set on flows to indicate if file hashing is needed. This is based on global output settings and rules. In the case of --disable-detection this was not happening, so all files where hashed with all methods. This has a significant performance impact. This patch adds logic to set the flow flags in --disable-detect mode. --- src/detect.c | 9 +++++++++ src/detect.h | 1 + src/flow-worker.c | 9 +++++++++ 3 files changed, 19 insertions(+) diff --git a/src/detect.c b/src/detect.c index fd729ed39c3f..d30b7905c9da 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2284,6 +2284,15 @@ static int SignatureCreateMask(Signature *s) SCReturnInt(0); } +/** \brief disable file features we don't need + * Called if we have no detection engine. + */ +void DisableDetectFlowFileFlags(Flow *f) +{ + DetectPostInspectFileFlagsUpdate(f, NULL /* no sgh */, STREAM_TOSERVER); + DetectPostInspectFileFlagsUpdate(f, NULL /* no sgh */, STREAM_TOCLIENT); +} + static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) { DetectMpmInitializeBuiltinMpms(de_ctx); diff --git a/src/detect.h b/src/detect.h index e603d6f356aa..93b52bd3c541 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1334,6 +1334,7 @@ int SigGroupBuild(DetectEngineCtx *); int SigGroupCleanup (DetectEngineCtx *de_ctx); void SigAddressPrepareBidirectionals (DetectEngineCtx *); +void DisableDetectFlowFileFlags(Flow *f); char *DetectLoadCompleteSigPath(const DetectEngineCtx *, char *sig_file); int SigLoadSignatures (DetectEngineCtx *, char *, int); void SigTableList(const char *keyword); diff --git a/src/flow-worker.c b/src/flow-worker.c index ac0bd484ddac..b29486e3359e 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -201,6 +201,15 @@ TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, Pac SCLogDebug("packet %"PRIu64" is TCP", p->pcap_cnt); DEBUG_ASSERT_FLOW_LOCKED(p->flow); + /* if detect is disabled, we need to apply file flags to the flow + * here on the first packet. */ + if (detect_thread == NULL && + ((PKT_IS_TOSERVER(p) && (p->flowflags & FLOW_PKT_TOSERVER_FIRST)) || + (PKT_IS_TOCLIENT(p) && (p->flowflags & FLOW_PKT_TOCLIENT_FIRST)))) + { + DisableDetectFlowFileFlags(p->flow); + } + FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_STREAM); StreamTcp(tv, p, fw->stream_thread, &fw->pq, NULL); FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_STREAM); From 44bab885d685b6d63269116e686e25ea2c44be04 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 9 Mar 2017 12:57:40 +0100 Subject: [PATCH 2511/2553] detect: fix ssl_state test --- src/detect-ssl-state.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index 1a85ebdc41aa..841558818849 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -769,8 +769,6 @@ static int DetectSslStateTest07(void) FAIL_IF(PacketAlertCheck(p, 4)); FAIL_IF(!PacketAlertCheck(p, 5)); - PASS; - FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, From b58127edcba10aee00f13e0bb570341b1aad85cd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 13 Mar 2017 13:53:52 +0100 Subject: [PATCH 2512/2553] print: constify input --- src/util-print.c | 2 +- src/util-print.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-print.c b/src/util-print.c index 13f19d4978e0..05ccafa777f2 100644 --- a/src/util-print.c +++ b/src/util-print.c @@ -217,7 +217,7 @@ void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32 } void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - uint8_t *src_buf, uint32_t src_buf_len) + const uint8_t *src_buf, const uint32_t src_buf_len) { uint32_t ch = 0; for (ch = 0; ch < src_buf_len; ch++) { diff --git a/src/util-print.h b/src/util-print.h index 674e3d32c453..5bad4f838529 100644 --- a/src/util-print.h +++ b/src/util-print.h @@ -50,7 +50,7 @@ void PrintRawDataFp(FILE *, const uint8_t *, uint32_t); void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, const uint8_t *src_buf, uint32_t src_buf_len); void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - uint8_t *src_buf, uint32_t src_buf_len); + const uint8_t *src_buf, const uint32_t src_buf_len); void PrintRawLineHexBuf(char *, uint32_t, uint8_t *, uint32_t ); const char *PrintInet(int , const void *, char *, socklen_t); From 1a7c5a01a1a6b2023e14d153f4d787e9e5ad68ee Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 24 Mar 2017 13:59:39 -0600 Subject: [PATCH 2513/2553] travis: macos: unlink all deps, then relink Kind of ugly, but first unlink all dependencies then install. The deps that don't get an upgrade will remain unlinked, so relink all dependencies as relinking an already linked dep does not error out. --- .travis.yml | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 168454fc22ea..5af6abf23407 100644 --- a/.travis.yml +++ b/.travis.yml @@ -127,12 +127,29 @@ before_install: if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update + # Unlink and install each dependency to avoid errors where a + # formula might already be installed but is not the current + # version. + packages="pkg-config libmagic libyaml nss nspr jansson libnet lua pcre hiredis" + for package in $packages; do + if brew ls $package --versions > /dev/null; then + brew unlink $package + fi + done + + # Now install. + brew install $packages + + # Now relink, becuase if a newer version of a package wasn't + # installed above, it will remain unlinked. + brew link $packages + # Unlink pcre in case its already installed. - brew unlink pcre || true - brew unlink pkg-config || true + # brew unlink pcre || true + # brew unlink pkg-config || true - brew install pkg-config libmagic libyaml nss nspr jansson libnet lua \ - pcre hiredis + # brew install pkg-config libmagic libyaml nss nspr jansson libnet lua \ + # pcre hiredis fi - ./qa/travis-libhtp.sh From 1589a154955f2f74044eb9dda758b6adc10d9c3b Mon Sep 17 00:00:00 2001 From: Jon Zeolla Date: Mon, 13 Mar 2017 12:49:04 -0400 Subject: [PATCH 2514/2553] docs: clarify how iprep works --- .../reputation/ipreputation/ip-reputation-format.rst | 12 ++++++++---- .../reputation/ipreputation/ip-reputation-rules.rst | 8 +++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/doc/userguide/reputation/ipreputation/ip-reputation-format.rst b/doc/userguide/reputation/ipreputation/ip-reputation-format.rst index 679d51189eb2..b6bf186a22a8 100644 --- a/doc/userguide/reputation/ipreputation/ip-reputation-format.rst +++ b/doc/userguide/reputation/ipreputation/ip-reputation-format.rst @@ -6,12 +6,12 @@ Description of IP Reputation file formats. For the configuration see :doc:`ip-re Categories file ~~~~~~~~~~~~~~~ -The categories file provides a mapping between a category number, short name and long description. It's a simple CSV file: +The categories file provides a mapping between a category number, short name, and long description. It's a simple CSV file: :: - ,, + ,, Example: @@ -27,9 +27,13 @@ Reputation file ~~~~~~~~~~~~~~~ The reputation file lists a reputation score for hosts in the categories. It's a simple CSV file: -> ,, -The IP is an IPv4 address in the quad-dotted notation. The category is the number as defined in the categories file and the value is a number between 1 and 127. 0 means no data. +:: + + + ,, + +The IP is an IPv4 address in the quad-dotted notation. The category is the number as defined in the categories file. The reputation score is the confidence that this IP is in the specified category, represented by a number between 1 and 127 (0 means no data). Example: diff --git a/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst b/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst index 1fcdfc5ee074..589800fb3eec 100644 --- a/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst +++ b/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst @@ -10,16 +10,16 @@ The iprep directive matches on the IP reputation information for a host. :: - iprep:,,, + iprep:,,, side to check: -cat: the category short name +category: the category short name operator: <, >, = -value: 1-127 +reputation score: 1-127 Example: @@ -28,6 +28,8 @@ Example: alert ip $HOME_NET any -> any any (msg:"IPREP internal host talking to CnC server"; flow:to_server; iprep:dst,CnC,>,30; sid:1; rev:1;) +This rule will alert when a system in $HOME_NET performs a client request while communicating with any IP in the CnC category that has a reputation score set to greater than 30. + IP-only ~~~~~~~ From ce8a65a58e11c1a3371a12226b56e6b9400a6e5f Mon Sep 17 00:00:00 2001 From: Jon Zeolla Date: Mon, 13 Mar 2017 12:51:44 -0400 Subject: [PATCH 2515/2553] docs: fix statement about flow:to_server --- doc/userguide/reputation/ipreputation/ip-reputation-rules.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst b/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst index 589800fb3eec..1808c98f1539 100644 --- a/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst +++ b/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst @@ -28,7 +28,7 @@ Example: alert ip $HOME_NET any -> any any (msg:"IPREP internal host talking to CnC server"; flow:to_server; iprep:dst,CnC,>,30; sid:1; rev:1;) -This rule will alert when a system in $HOME_NET performs a client request while communicating with any IP in the CnC category that has a reputation score set to greater than 30. +This rule will alert when a system in $HOME_NET acts as a client while communicating with any IP in the CnC category that has a reputation score set to greater than 30. IP-only ~~~~~~~ From f56428d996542f27b66ba1cda2477af2a24c50e9 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 17 Feb 2017 16:04:23 -0600 Subject: [PATCH 2516/2553] tcp/udp: fix checksum validation when 0xffff Issue: https://redmine.openinfosecfoundation.org/issues/2041 One approach to fixing this issue to just validate the checksum instead of regenerating it and comparing it. This method is used in some kernels and other network tools. When validating, the current checksum is passed in as an initial argument which will cause the final checksum to be 0 if OK. If generating a checksum, 0 is passed and the result is the generated checksum. --- src/alert-unified2-alert.c | 4 +- src/decode-tcp.c | 20 +++++--- src/decode-tcp.h | 38 ++++++++------ src/decode-udp.c | 22 ++++---- src/decode-udp.h | 36 ++++++++----- src/detect-csum.c | 30 ++++++----- src/detect.c | 102 +++++++++---------------------------- src/flow-timeout.c | 4 +- src/stream-tcp.c | 9 ++-- src/util-checksum.c | 8 +-- 10 files changed, 125 insertions(+), 148 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index e29549160d64..44dcb4d83421 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -634,12 +634,12 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, const FakeIPv6Hdr *fakehdr = (FakeIPv6Hdr *)aun->iphdr; fakehdr->tcph.th_sum = TCPV6CalculateChecksum(fakehdr->ip6h.s_ip6_addrs, - (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr)); + (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr), 0); } else { FakeIPv4Hdr *fakehdr = (FakeIPv4Hdr *)aun->iphdr; fakehdr->tcph.th_sum = TCPCalculateChecksum(fakehdr->ip4h.s_ip_addrs, - (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr)); + (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr), 0); fakehdr->ip4h.ip_csum = IPV4CalculateChecksum((uint16_t *)&fakehdr->ip4h, IPV4_GET_RAW_HLEN(&fakehdr->ip4h)); } diff --git a/src/decode-tcp.c b/src/decode-tcp.c index 51dbfaaa26ac..75e52c27fd5a 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -236,8 +236,9 @@ static int TCPCalculateValidChecksumtest01(void) csum = *( ((uint16_t *)raw_tcp) + 8); - return (csum == TCPCalculateChecksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_tcp, sizeof(raw_tcp))); + FAIL_IF(TCPCalculateChecksum((uint16_t *)raw_ipshdr, + (uint16_t *)raw_tcp, sizeof(raw_tcp), csum) != 0); + PASS; } static int TCPCalculateInvalidChecksumtest02(void) @@ -256,8 +257,9 @@ static int TCPCalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_tcp) + 8); - return (csum != TCPCalculateChecksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_tcp, sizeof(raw_tcp))); + FAIL_IF(TCPCalculateChecksum((uint16_t *) raw_ipshdr, + (uint16_t *)raw_tcp, sizeof(raw_tcp), csum) == 0); + PASS; } static int TCPV6CalculateValidChecksumtest03(void) @@ -279,8 +281,9 @@ static int TCPV6CalculateValidChecksumtest03(void) csum = *( ((uint16_t *)(raw_ipv6 + 70))); - return (csum == TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 32)); + FAIL_IF(TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + (uint16_t *)(raw_ipv6 + 54), 32, csum) != 0); + PASS; } static int TCPV6CalculateInvalidChecksumtest04(void) @@ -302,8 +305,9 @@ static int TCPV6CalculateInvalidChecksumtest04(void) csum = *( ((uint16_t *)(raw_ipv6 + 70))); - return (csum != TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 32)); + FAIL_IF(TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + (uint16_t *)(raw_ipv6 + 54), 32, csum) == 0); + PASS; } /** \test Get the wscale of 2 */ diff --git a/src/decode-tcp.h b/src/decode-tcp.h index c544036bd46e..38b27f6b384e 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -164,26 +164,30 @@ typedef struct TCPVars_ void DecodeTCPRegisterTests(void); /** -------- Inline functions ------- */ -static inline uint16_t TCPCalculateChecksum(uint16_t *, uint16_t *, uint16_t); -static inline uint16_t TCPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t); +static inline uint16_t TCPCalculateChecksum(uint16_t *, uint16_t *, uint16_t, + uint16_t); +static inline uint16_t TCPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t, + uint16_t); /** - * \brief Calculates the checksum for the TCP packet + * \brief Calculate or validate the checksum for the TCP packet * * \param shdr Pointer to source address field from the IP packet. Used as a * part of the pseudoheader for computing the checksum * \param pkt Pointer to the start of the TCP packet * \param tlen Total length of the TCP packet(header + payload) + * \param init The current checksum if validating, 0 if generating. * - * \retval csum Checksum for the TCP packet + * \retval csum For validation 0 will be returned for success, for calculation + * this will be the checksum. */ static inline uint16_t TCPCalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen) + uint16_t tlen, uint16_t init) { uint16_t pad = 0; - uint32_t csum = shdr[0]; + uint32_t csum = init; - csum += shdr[1] + shdr[2] + shdr[3] + htons(6) + htons(tlen); + csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + htons(6) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[9]; @@ -193,7 +197,9 @@ static inline uint16_t TCPCalculateChecksum(uint16_t *shdr, uint16_t *pkt, while (tlen >= 32) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + + pkt[7] + + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; @@ -229,24 +235,26 @@ static inline uint16_t TCPCalculateChecksum(uint16_t *shdr, uint16_t *pkt, } /** - * \brief Calculates the checksum for the TCP packet + * \brief Calculate or validate the checksum for the TCP packet * * \param shdr Pointer to source address field from the IPV6 packet. Used as a * part of the psuedoheader for computing the checksum * \param pkt Pointer to the start of the TCP packet * \param tlen Total length of the TCP packet(header + payload) + * \param init The current checksum if validating, 0 if generating. * - * \retval csum Checksum for the TCP packet + * \retval csum For validation 0 will be returned for success, for calculation + * this will be the checksum. */ static inline uint16_t TCPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen) + uint16_t tlen, uint16_t init) { uint16_t pad = 0; - uint32_t csum = shdr[0]; + uint32_t csum = init; - csum += shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + - shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + - shdr[13] + shdr[14] + shdr[15] + htons(6) + htons(tlen); + csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + + shdr[6] + shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + + shdr[12] + shdr[13] + shdr[14] + shdr[15] + htons(6) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[9]; diff --git a/src/decode-udp.c b/src/decode-udp.c index d45d57f2548e..50ca2397fa56 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -117,9 +117,9 @@ static int UDPV4CalculateValidChecksumtest01(void) csum = *( ((uint16_t *)raw_udp) + 3); - return (csum == UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_udp, - sizeof(raw_udp))); + FAIL_IF(UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, + (uint16_t *)raw_udp, sizeof(raw_udp), csum) != 0); + PASS; } static int UDPV4CalculateInvalidChecksumtest02(void) @@ -144,9 +144,9 @@ static int UDPV4CalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_udp) + 3); - return (csum != UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_udp, - sizeof(raw_udp))); + FAIL_IF(UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, + (uint16_t *)raw_udp, sizeof(raw_udp), csum) == 0); + PASS; } static int UDPV6CalculateValidChecksumtest03(void) @@ -167,8 +167,9 @@ static int UDPV6CalculateValidChecksumtest03(void) csum = *( ((uint16_t *)(raw_ipv6 + 60))); - return (csum == UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 20)); + FAIL_IF(UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + (uint16_t *)(raw_ipv6 + 54), 20, csum) != 0); + PASS; } static int UDPV6CalculateInvalidChecksumtest04(void) @@ -189,8 +190,9 @@ static int UDPV6CalculateInvalidChecksumtest04(void) csum = *( ((uint16_t *)(raw_ipv6 + 60))); - return (csum != UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 20)); + FAIL_IF(UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + (uint16_t *)(raw_ipv6 + 54), 20, csum) == 0); + PASS; } #endif /* UNITTESTS */ diff --git a/src/decode-udp.h b/src/decode-udp.h index 027938f094eb..cc04fa7f8164 100644 --- a/src/decode-udp.h +++ b/src/decode-udp.h @@ -54,26 +54,31 @@ typedef struct UDPHdr_ void DecodeUDPV4RegisterTests(void); /** ------ Inline function ------ */ -static inline uint16_t UDPV4CalculateChecksum(uint16_t *, uint16_t *, uint16_t); -static inline uint16_t UDPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t); +static inline uint16_t UDPV4CalculateChecksum(uint16_t *, uint16_t *, uint16_t, + uint16_t); +static inline uint16_t UDPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t, + uint16_t); /** - * \brief Calculates the checksum for the UDP packet + * \brief Calculate or valid the checksum for the UDP packet * * \param shdr Pointer to source address field from the IP packet. Used as a * part of the psuedoheader for computing the checksum * \param pkt Pointer to the start of the UDP packet * \param hlen Total length of the UDP packet(header + payload) + * \param init For validation this is the UDP checksum, for calculation this + * value should be set to 0. * - * \retval csum Checksum for the UDP packet + * \retval csum For validation 0 will be returned for success, for calculation + * this will be the checksum. */ static inline uint16_t UDPV4CalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen) + uint16_t tlen, uint16_t init) { uint16_t pad = 0; - uint32_t csum = shdr[0]; + uint32_t csum = init; - csum += shdr[1] + shdr[2] + shdr[3] + htons(17) + htons(tlen); + csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + htons(17) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2]; @@ -115,29 +120,32 @@ static inline uint16_t UDPV4CalculateChecksum(uint16_t *shdr, uint16_t *pkt, csum += (csum >> 16); uint16_t csum_u16 = (uint16_t)~csum; - if (csum_u16 == 0) + if (init == 0 && csum_u16 == 0) return 0xFFFF; else return csum_u16; } /** - * \brief Calculates the checksum for the UDP packet + * \brief Calculate or valid the checksum for the UDP packet * * \param shdr Pointer to source address field from the IPV6 packet. Used as a * part of the psuedoheader for computing the checksum * \param pkt Pointer to the start of the UDP packet * \param tlen Total length of the UDP packet(header + payload) + * \param init For validation this is the UDP checksum, for calculation this + * value should be set to 0. * - * \retval csum Checksum for the UDP packet + * \retval csum For validation 0 will be returned for success, for calculation + * this will be the checksum. */ static inline uint16_t UDPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen) + uint16_t tlen, uint16_t init) { uint16_t pad = 0; - uint32_t csum = shdr[0]; + uint32_t csum = init; - csum += shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + + csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + shdr[13] + shdr[14] + shdr[15] + htons(17) + htons(tlen); @@ -181,7 +189,7 @@ static inline uint16_t UDPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, csum += (csum >> 16); uint16_t csum_u16 = (uint16_t)~csum; - if (csum_u16 == 0) + if (init == 0 && csum_u16 == 0) return 0xFFFF; else return csum_u16; diff --git a/src/detect-csum.c b/src/detect-csum.c index a7e5d9ba4ab3..8e3d69391b04 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -338,11 +338,13 @@ static int DetectTCPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, if (p->level4_comp_csum == -1) p->level4_comp_csum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, - (p->payload_len + TCP_GET_HLEN(p))); + (p->payload_len + + TCP_GET_HLEN(p)), + p->tcph->th_sum); - if (p->level4_comp_csum == p->tcph->th_sum && cd->valid == 1) + if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; - else if (p->level4_comp_csum != p->tcph->th_sum && cd->valid == 0) + else if (p->level4_comp_csum != 0 && cd->valid == 0) return 1; else return 0; @@ -433,11 +435,13 @@ static int DetectTCPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, if (p->level4_comp_csum == -1) p->level4_comp_csum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, - (p->payload_len + TCP_GET_HLEN(p))); + (p->payload_len + + TCP_GET_HLEN(p)), + p->tcph->th_sum); - if (p->level4_comp_csum == p->tcph->th_sum && cd->valid == 1) + if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; - else if (p->level4_comp_csum != p->tcph->th_sum && cd->valid == 0) + else if (p->level4_comp_csum != 0 && cd->valid == 0) return 1; else return 0; @@ -529,11 +533,12 @@ static int DetectUDPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, p->level4_comp_csum = UDPV4CalculateChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->udph, (p->payload_len + - UDP_HEADER_LEN) ); + UDP_HEADER_LEN), + p->udph->uh_sum); - if (p->level4_comp_csum == p->udph->uh_sum && cd->valid == 1) + if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; - else if (p->level4_comp_csum != p->udph->uh_sum && cd->valid == 0) + else if (p->level4_comp_csum != 0 && cd->valid == 0) return 1; else return 0; @@ -625,11 +630,12 @@ static int DetectUDPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, p->level4_comp_csum = UDPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->udph, (p->payload_len + - UDP_HEADER_LEN) ); + UDP_HEADER_LEN), + p->udph->uh_sum); - if (p->level4_comp_csum == p->udph->uh_sum && cd->valid == 1) + if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; - else if (p->level4_comp_csum != p->udph->uh_sum && cd->valid == 0) + else if (p->level4_comp_csum != 0 && cd->valid == 0) return 1; else return 0; diff --git a/src/detect.c b/src/detect.c index d30b7905c9da..3ccb3b8e995a 100644 --- a/src/detect.c +++ b/src/detect.c @@ -5821,7 +5821,6 @@ int SigTest26TCPV4Keyword(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); @@ -5852,9 +5851,7 @@ int SigTest26TCPV4Keyword(void) p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; @@ -5862,43 +5859,31 @@ int SigTest26TCPV4Keyword(void) "alert ip any any -> any any " "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list); de_ctx->sig_list->next = SigInit(de_ctx, "alert ip any any -> any any " "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; " "msg:\"tcpv4-csum keyword check(1)\"; " "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list->next); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!(PacketAlertCheck(p1, 1))) { - printf("sig 1 didn't match: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p1, 1))); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!(PacketAlertCheck(p2, 2))) { - printf("sig 2 didn't match: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p2, 2))); - result = 1; -end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); SCFree(p1); SCFree(p2); - return result; + PASS; } /* Test SigTest26TCPV4Keyword but also check for invalid IPV4 checksum */ @@ -6543,16 +6528,12 @@ int SigTest30UDPV4Keyword(void) 0x67, 0x6c, 0x65, 0xc0, 0x27}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; + FAIL_IF_NULL(p1); Packet *p2 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p2 == NULL)) { - SCFree(p1); - return 0; - } + FAIL_IF_NULL(p2); + ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0yyyyyyyyyyyyyyyy\r\n" "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; @@ -6580,9 +6561,7 @@ int SigTest30UDPV4Keyword(void) p2->proto = IPPROTO_UDP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; @@ -6591,45 +6570,32 @@ int SigTest30UDPV4Keyword(void) "(content:\"/one/\"; udpv4-csum:valid; " "msg:\"udpv4-csum keyword check(1)\"; " "sid:1;)"); - if (de_ctx->sig_list == NULL) { - result &= 0; - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list); de_ctx->sig_list->next = SigInit(de_ctx, "alert udp any any -> any any " "(content:\"/one/\"; udpv4-csum:invalid; " "msg:\"udpv4-csum keyword check(1)\"; " "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result &= 0; - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list->next); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) - result &= 1; - else - result &= 0; + FAIL_IF_NOT(PacketAlertCheck(p1, 1)); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) - result &= 1; - else - result &= 0; + FAIL_IF_NOT(PacketAlertCheck(p2, 2)); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: SCFree(p1); SCFree(p2); - return result; + PASS; } int SigTest31NegativeUDPV4Keyword(void) @@ -6783,16 +6749,12 @@ int SigTest32UDPV6Keyword(void) 0x09, 0x01}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; + FAIL_IF_NULL(p1); Packet *p2 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p2 == NULL)) { - SCFree(p1); - return 0; - } + FAIL_IF_NULL(p2); + ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP\r\n" "\r\n\r\n"; @@ -6820,9 +6782,7 @@ int SigTest32UDPV6Keyword(void) p2->proto = IPPROTO_UDP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; @@ -6830,45 +6790,33 @@ int SigTest32UDPV6Keyword(void) "alert udp any any -> any any " "(content:\"/one/\"; udpv6-csum:valid; " "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result &= 0; - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list); de_ctx->sig_list->next = SigInit(de_ctx, "alert udp any any -> any any " "(content:\"/one/\"; udpv6-csum:invalid; " "msg:\"udpv6-csum keyword check(1)\"; " "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result &= 0; - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list->next); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) - result &= 1; - else - result &= 0; + FAIL_IF_NOT(PacketAlertCheck(p1, 1)); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) - result &= 1; - else - result &= 0; + FAIL_IF_NOT(PacketAlertCheck(p2, 2)); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: + SCFree(p1); SCFree(p2); - return result; + PASS; } int SigTest33NegativeUDPV6Keyword(void) diff --git a/src/flow-timeout.c b/src/flow-timeout.c index e62ccd4a2eff..c835413076b8 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -240,14 +240,14 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, if (FLOW_IS_IPV4(f)) { p->tcph->th_sum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, 20); + (uint16_t *)p->tcph, 20, 0); /* calc ipv4 csum as we may log it and barnyard might reject * a wrong checksum */ p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, IPV4_GET_RAW_HLEN(p->ip4h)); } else if (FLOW_IS_IPV6(f)) { p->tcph->th_sum = TCPCalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, 20); + (uint16_t *)p->tcph, 20, 0); } memset(&p->ts, 0, sizeof(struct timeval)); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 2223548fbdc3..aa748701a8a7 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4710,18 +4710,19 @@ static inline int StreamTcpValidateChecksum(Packet *p) p->level4_comp_csum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, (p->payload_len + - TCP_GET_HLEN(p))); + TCP_GET_HLEN(p)), + p->tcph->th_sum); } else if (PKT_IS_IPV6(p)) { p->level4_comp_csum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, (p->payload_len + - TCP_GET_HLEN(p))); + TCP_GET_HLEN(p)), + p->tcph->th_sum); } } - if (p->level4_comp_csum != p->tcph->th_sum) { + if (p->level4_comp_csum != 0) { ret = 0; - SCLogDebug("Checksum of received packet %p is invalid",p); if (p->livedev) { (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1); } else if (p->pcap_cnt) { diff --git a/src/util-checksum.c b/src/util-checksum.c index 455e2f52aa77..8c1c39131dd7 100644 --- a/src/util-checksum.c +++ b/src/util-checksum.c @@ -34,11 +34,11 @@ int ReCalculateChecksum(Packet *p) /* TCP */ p->tcph->th_sum = 0; p->tcph->th_sum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p))); + (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p)), 0); } else if (PKT_IS_UDP(p)) { p->udph->uh_sum = 0; p->udph->uh_sum = UDPV4CalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN)); + (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); } /* IPV4 */ p->ip4h->ip_csum = 0; @@ -49,11 +49,11 @@ int ReCalculateChecksum(Packet *p) if (PKT_IS_TCP(p)) { p->tcph->th_sum = 0; p->tcph->th_sum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p))); + (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p)), 0); } else if (PKT_IS_UDP(p)) { p->udph->uh_sum = 0; p->udph->uh_sum = UDPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN)); + (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); } } From b79a18ea153a8255c4823c4af189154cc5bcccc6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 21 Feb 2017 13:31:41 -0600 Subject: [PATCH 2517/2553] tcp/udp: rename checksum functions for better meaning The TCP/UDP checksum functions no longer just calculate the checksum, they can validate as well as calculate so use a more generic name. --- src/alert-unified2-alert.c | 4 ++-- src/decode-tcp.c | 8 ++++---- src/decode-tcp.h | 14 ++++++------- src/decode-udp.c | 8 ++++---- src/decode-udp.h | 14 ++++++------- src/detect-csum.c | 40 +++++++++++++++++++------------------- src/flow-timeout.c | 4 ++-- src/stream-tcp.c | 20 +++++++++---------- src/util-checksum.c | 8 ++++---- 9 files changed, 58 insertions(+), 62 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 44dcb4d83421..e7f28b3228ea 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -633,12 +633,12 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, const if (PKT_IS_IPV6(p)) { FakeIPv6Hdr *fakehdr = (FakeIPv6Hdr *)aun->iphdr; - fakehdr->tcph.th_sum = TCPV6CalculateChecksum(fakehdr->ip6h.s_ip6_addrs, + fakehdr->tcph.th_sum = TCPV6Checksum(fakehdr->ip6h.s_ip6_addrs, (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr), 0); } else { FakeIPv4Hdr *fakehdr = (FakeIPv4Hdr *)aun->iphdr; - fakehdr->tcph.th_sum = TCPCalculateChecksum(fakehdr->ip4h.s_ip_addrs, + fakehdr->tcph.th_sum = TCPChecksum(fakehdr->ip4h.s_ip_addrs, (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr), 0); fakehdr->ip4h.ip_csum = IPV4CalculateChecksum((uint16_t *)&fakehdr->ip4h, IPV4_GET_RAW_HLEN(&fakehdr->ip4h)); diff --git a/src/decode-tcp.c b/src/decode-tcp.c index 75e52c27fd5a..1ff16e0a7f7e 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -236,7 +236,7 @@ static int TCPCalculateValidChecksumtest01(void) csum = *( ((uint16_t *)raw_tcp) + 8); - FAIL_IF(TCPCalculateChecksum((uint16_t *)raw_ipshdr, + FAIL_IF(TCPChecksum((uint16_t *)raw_ipshdr, (uint16_t *)raw_tcp, sizeof(raw_tcp), csum) != 0); PASS; } @@ -257,7 +257,7 @@ static int TCPCalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_tcp) + 8); - FAIL_IF(TCPCalculateChecksum((uint16_t *) raw_ipshdr, + FAIL_IF(TCPChecksum((uint16_t *) raw_ipshdr, (uint16_t *)raw_tcp, sizeof(raw_tcp), csum) == 0); PASS; } @@ -281,7 +281,7 @@ static int TCPV6CalculateValidChecksumtest03(void) csum = *( ((uint16_t *)(raw_ipv6 + 70))); - FAIL_IF(TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + FAIL_IF(TCPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 32, csum) != 0); PASS; } @@ -305,7 +305,7 @@ static int TCPV6CalculateInvalidChecksumtest04(void) csum = *( ((uint16_t *)(raw_ipv6 + 70))); - FAIL_IF(TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + FAIL_IF(TCPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 32, csum) == 0); PASS; } diff --git a/src/decode-tcp.h b/src/decode-tcp.h index 38b27f6b384e..0621d7ef6176 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -164,10 +164,8 @@ typedef struct TCPVars_ void DecodeTCPRegisterTests(void); /** -------- Inline functions ------- */ -static inline uint16_t TCPCalculateChecksum(uint16_t *, uint16_t *, uint16_t, - uint16_t); -static inline uint16_t TCPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t, - uint16_t); +static inline uint16_t TCPChecksum(uint16_t *, uint16_t *, uint16_t, uint16_t); +static inline uint16_t TCPV6Checksum(uint16_t *, uint16_t *, uint16_t, uint16_t); /** * \brief Calculate or validate the checksum for the TCP packet @@ -181,8 +179,8 @@ static inline uint16_t TCPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t, * \retval csum For validation 0 will be returned for success, for calculation * this will be the checksum. */ -static inline uint16_t TCPCalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen, uint16_t init) +static inline uint16_t TCPChecksum(uint16_t *shdr, uint16_t *pkt, + uint16_t tlen, uint16_t init) { uint16_t pad = 0; uint32_t csum = init; @@ -246,8 +244,8 @@ static inline uint16_t TCPCalculateChecksum(uint16_t *shdr, uint16_t *pkt, * \retval csum For validation 0 will be returned for success, for calculation * this will be the checksum. */ -static inline uint16_t TCPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen, uint16_t init) +static inline uint16_t TCPV6Checksum(uint16_t *shdr, uint16_t *pkt, + uint16_t tlen, uint16_t init) { uint16_t pad = 0; uint32_t csum = init; diff --git a/src/decode-udp.c b/src/decode-udp.c index 50ca2397fa56..d84f96919206 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -117,7 +117,7 @@ static int UDPV4CalculateValidChecksumtest01(void) csum = *( ((uint16_t *)raw_udp) + 3); - FAIL_IF(UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, + FAIL_IF(UDPV4Checksum((uint16_t *) raw_ipshdr, (uint16_t *)raw_udp, sizeof(raw_udp), csum) != 0); PASS; } @@ -144,7 +144,7 @@ static int UDPV4CalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_udp) + 3); - FAIL_IF(UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, + FAIL_IF(UDPV4Checksum((uint16_t *) raw_ipshdr, (uint16_t *)raw_udp, sizeof(raw_udp), csum) == 0); PASS; } @@ -167,7 +167,7 @@ static int UDPV6CalculateValidChecksumtest03(void) csum = *( ((uint16_t *)(raw_ipv6 + 60))); - FAIL_IF(UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + FAIL_IF(UDPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 20, csum) != 0); PASS; } @@ -190,7 +190,7 @@ static int UDPV6CalculateInvalidChecksumtest04(void) csum = *( ((uint16_t *)(raw_ipv6 + 60))); - FAIL_IF(UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + FAIL_IF(UDPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 20, csum) == 0); PASS; } diff --git a/src/decode-udp.h b/src/decode-udp.h index cc04fa7f8164..cfbdc7f23a4b 100644 --- a/src/decode-udp.h +++ b/src/decode-udp.h @@ -54,10 +54,8 @@ typedef struct UDPHdr_ void DecodeUDPV4RegisterTests(void); /** ------ Inline function ------ */ -static inline uint16_t UDPV4CalculateChecksum(uint16_t *, uint16_t *, uint16_t, - uint16_t); -static inline uint16_t UDPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t, - uint16_t); +static inline uint16_t UDPV4Checksum(uint16_t *, uint16_t *, uint16_t, uint16_t); +static inline uint16_t UDPV6Checksum(uint16_t *, uint16_t *, uint16_t, uint16_t); /** * \brief Calculate or valid the checksum for the UDP packet @@ -72,8 +70,8 @@ static inline uint16_t UDPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t, * \retval csum For validation 0 will be returned for success, for calculation * this will be the checksum. */ -static inline uint16_t UDPV4CalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen, uint16_t init) +static inline uint16_t UDPV4Checksum(uint16_t *shdr, uint16_t *pkt, + uint16_t tlen, uint16_t init) { uint16_t pad = 0; uint32_t csum = init; @@ -139,8 +137,8 @@ static inline uint16_t UDPV4CalculateChecksum(uint16_t *shdr, uint16_t *pkt, * \retval csum For validation 0 will be returned for success, for calculation * this will be the checksum. */ -static inline uint16_t UDPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen, uint16_t init) +static inline uint16_t UDPV6Checksum(uint16_t *shdr, uint16_t *pkt, + uint16_t tlen, uint16_t init) { uint16_t pad = 0; uint32_t csum = init; diff --git a/src/detect-csum.c b/src/detect-csum.c index 8e3d69391b04..bef86066cf58 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -336,11 +336,11 @@ static int DetectTCPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, - (p->payload_len + - TCP_GET_HLEN(p)), - p->tcph->th_sum); + p->level4_comp_csum = TCPChecksum(p->ip4h->s_ip_addrs, + (uint16_t *)p->tcph, + (p->payload_len + + TCP_GET_HLEN(p)), + p->tcph->th_sum); if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; @@ -433,11 +433,11 @@ static int DetectTCPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, - (p->payload_len + - TCP_GET_HLEN(p)), - p->tcph->th_sum); + p->level4_comp_csum = TCPV6Checksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->tcph, + (p->payload_len + + TCP_GET_HLEN(p)), + p->tcph->th_sum); if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; @@ -530,11 +530,11 @@ static int DetectUDPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = UDPV4CalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->udph, - (p->payload_len + - UDP_HEADER_LEN), - p->udph->uh_sum); + p->level4_comp_csum = UDPV4Checksum(p->ip4h->s_ip_addrs, + (uint16_t *)p->udph, + (p->payload_len + + UDP_HEADER_LEN), + p->udph->uh_sum); if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; @@ -627,11 +627,11 @@ static int DetectUDPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = UDPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->udph, - (p->payload_len + - UDP_HEADER_LEN), - p->udph->uh_sum); + p->level4_comp_csum = UDPV6Checksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->udph, + (p->payload_len + + UDP_HEADER_LEN), + p->udph->uh_sum); if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; diff --git a/src/flow-timeout.c b/src/flow-timeout.c index c835413076b8..cf0dd622e5a3 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -239,14 +239,14 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, } if (FLOW_IS_IPV4(f)) { - p->tcph->th_sum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, + p->tcph->th_sum = TCPChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, 20, 0); /* calc ipv4 csum as we may log it and barnyard might reject * a wrong checksum */ p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, IPV4_GET_RAW_HLEN(p->ip4h)); } else if (FLOW_IS_IPV6(f)) { - p->tcph->th_sum = TCPCalculateChecksum(p->ip6h->s_ip6_addrs, + p->tcph->th_sum = TCPChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, 20, 0); } diff --git a/src/stream-tcp.c b/src/stream-tcp.c index aa748701a8a7..b3b861bdefb8 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4707,17 +4707,17 @@ static inline int StreamTcpValidateChecksum(Packet *p) if (p->level4_comp_csum == -1) { if (PKT_IS_IPV4(p)) { - p->level4_comp_csum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, - (p->payload_len + - TCP_GET_HLEN(p)), - p->tcph->th_sum); + p->level4_comp_csum = TCPChecksum(p->ip4h->s_ip_addrs, + (uint16_t *)p->tcph, + (p->payload_len + + TCP_GET_HLEN(p)), + p->tcph->th_sum); } else if (PKT_IS_IPV6(p)) { - p->level4_comp_csum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, - (p->payload_len + - TCP_GET_HLEN(p)), - p->tcph->th_sum); + p->level4_comp_csum = TCPV6Checksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->tcph, + (p->payload_len + + TCP_GET_HLEN(p)), + p->tcph->th_sum); } } diff --git a/src/util-checksum.c b/src/util-checksum.c index 8c1c39131dd7..98dc6590ec88 100644 --- a/src/util-checksum.c +++ b/src/util-checksum.c @@ -33,11 +33,11 @@ int ReCalculateChecksum(Packet *p) if (PKT_IS_TCP(p)) { /* TCP */ p->tcph->th_sum = 0; - p->tcph->th_sum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, + p->tcph->th_sum = TCPChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p)), 0); } else if (PKT_IS_UDP(p)) { p->udph->uh_sum = 0; - p->udph->uh_sum = UDPV4CalculateChecksum(p->ip4h->s_ip_addrs, + p->udph->uh_sum = UDPV4Checksum(p->ip4h->s_ip_addrs, (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); } /* IPV4 */ @@ -48,11 +48,11 @@ int ReCalculateChecksum(Packet *p) /* just TCP for IPV6 */ if (PKT_IS_TCP(p)) { p->tcph->th_sum = 0; - p->tcph->th_sum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, + p->tcph->th_sum = TCPV6Checksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p)), 0); } else if (PKT_IS_UDP(p)) { p->udph->uh_sum = 0; - p->udph->uh_sum = UDPV6CalculateChecksum(p->ip6h->s_ip6_addrs, + p->udph->uh_sum = UDPV6Checksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); } } From 63078909d5d279bdff465a98a6ab0a52e6467694 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 21 Feb 2017 13:42:50 -0600 Subject: [PATCH 2518/2553] ipv4: update checksum function to be like tcp/udp Update the IPv4 checksum function to be like the changed TCP/UDP checksum functions for consistency. --- src/alert-unified2-alert.c | 4 ++-- src/decode-ipv4.c | 6 ++++-- src/decode-ipv4.h | 17 ++++++++++------- src/defrag.c | 2 +- src/detect-csum.c | 9 +++++---- src/flow-timeout.c | 4 ++-- src/util-checksum.c | 4 ++-- 7 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index e7f28b3228ea..ac1fa7e29116 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -640,8 +640,8 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, const fakehdr->tcph.th_sum = TCPChecksum(fakehdr->ip4h.s_ip_addrs, (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr), 0); - fakehdr->ip4h.ip_csum = IPV4CalculateChecksum((uint16_t *)&fakehdr->ip4h, - IPV4_GET_RAW_HLEN(&fakehdr->ip4h)); + fakehdr->ip4h.ip_csum = IPV4Checksum((uint16_t *)&fakehdr->ip4h, + IPV4_GET_RAW_HLEN(&fakehdr->ip4h), 0); } /* write out */ diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index c21d22460045..3b5ee6494214 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -1199,7 +1199,8 @@ static int IPV4CalculateValidChecksumtest01(void) csum = *( ((uint16_t *)raw_ipv4) + 5); - return (csum == IPV4CalculateChecksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4))); + FAIL_IF(IPV4Checksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4), csum) != 0); + PASS; } static int IPV4CalculateInvalidChecksumtest02(void) @@ -1213,7 +1214,8 @@ static int IPV4CalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_ipv4) + 5); - return (csum != IPV4CalculateChecksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4))); + FAIL_IF(IPV4Checksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4), csum) == 0); + PASS; } /** diff --git a/src/decode-ipv4.h b/src/decode-ipv4.h index 77af6762bc20..c8f268d054e5 100644 --- a/src/decode-ipv4.h +++ b/src/decode-ipv4.h @@ -181,21 +181,24 @@ typedef struct IPV4Vars_ void DecodeIPV4RegisterTests(void); /** ----- Inline functions ----- */ -static inline uint16_t IPV4CalculateChecksum(uint16_t *, uint16_t); +static inline uint16_t IPV4Checksum(uint16_t *, uint16_t, uint16_t); + /** - * \brief Calculates the checksum for the IP packet + * \brief Calculateor validate the checksum for the IP packet * * \param pkt Pointer to the start of the IP packet * \param hlen Length of the IP header + * \param init The current checksum if validating, 0 if generating. * - * \retval csum Checksum for the IP packet + * \retval csum For validation 0 will be returned for success, for calculation + * this will be the checksum. */ -static inline uint16_t IPV4CalculateChecksum(uint16_t *pkt, uint16_t hlen) +static inline uint16_t IPV4Checksum(uint16_t *pkt, uint16_t hlen, uint16_t init) { - uint32_t csum = pkt[0]; + uint32_t csum = init; - csum += pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[6] + pkt[7] + pkt[8] + - pkt[9]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[6] + pkt[7] + + pkt[8] + pkt[9]; hlen -= 20; pkt += 10; diff --git a/src/defrag.c b/src/defrag.c index 5433ce78607c..5245f43d6547 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -1042,7 +1042,7 @@ BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf, SET_PKT_LEN(p, hlen + content_len); SCFree(pcontent); - p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)GET_PKT_DATA(p), hlen); + p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0); /* Self test. */ if (IPV4_GET_VER(p) != 4) diff --git a/src/detect-csum.c b/src/detect-csum.c index bef86066cf58..7f9c307a79c4 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -242,12 +242,13 @@ static int DetectIPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } if (p->level3_comp_csum == -1) - p->level3_comp_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, - IPV4_GET_HLEN(p)); + p->level3_comp_csum = IPV4Checksum((uint16_t *)p->ip4h, + IPV4_GET_HLEN(p), + p->ip4h->ip_csum); - if (p->level3_comp_csum == p->ip4h->ip_csum && cd->valid == 1) + if (p->level3_comp_csum == 0 && cd->valid == 1) return 1; - else if (p->level3_comp_csum != p->ip4h->ip_csum && cd->valid == 0) + else if (p->level3_comp_csum != 0 && cd->valid == 0) return 1; else return 0; diff --git a/src/flow-timeout.c b/src/flow-timeout.c index cf0dd622e5a3..eb1400022f89 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -243,8 +243,8 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, (uint16_t *)p->tcph, 20, 0); /* calc ipv4 csum as we may log it and barnyard might reject * a wrong checksum */ - p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, - IPV4_GET_RAW_HLEN(p->ip4h)); + p->ip4h->ip_csum = IPV4Checksum((uint16_t *)p->ip4h, + IPV4_GET_RAW_HLEN(p->ip4h), 0); } else if (FLOW_IS_IPV6(f)) { p->tcph->th_sum = TCPChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, 20, 0); diff --git a/src/util-checksum.c b/src/util-checksum.c index 98dc6590ec88..245f3b6908ca 100644 --- a/src/util-checksum.c +++ b/src/util-checksum.c @@ -42,8 +42,8 @@ int ReCalculateChecksum(Packet *p) } /* IPV4 */ p->ip4h->ip_csum = 0; - p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, - IPV4_GET_RAW_HLEN(p->ip4h)); + p->ip4h->ip_csum = IPV4Checksum((uint16_t *)p->ip4h, + IPV4_GET_RAW_HLEN(p->ip4h), 0); } else if (PKT_IS_IPV6(p)) { /* just TCP for IPV6 */ if (PKT_IS_TCP(p)) { From 005a700e543b65db510243814d85f432cc0912d6 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 21 Feb 2017 10:41:57 +0100 Subject: [PATCH 2519/2553] logging: support custom file permissions Support setting file permissions per logger using 'filemode', e.g.: outputs: - eve-log: enabled: yes filetype: regular filename: eve.json filemode: 660 --- src/util-error.c | 1 + src/util-error.h | 1 + src/util-logopenfile.c | 28 ++++++++++++++++++++++++---- src/util-logopenfile.h | 3 +++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/util-error.c b/src/util-error.c index c9ad9854eb7c..197255bd3126 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -337,6 +337,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_NO_MAGIC_SUPPORT); CASE_CODE (SC_ERR_REDIS); CASE_CODE (SC_ERR_VAR_LIMIT); + CASE_CODE (SC_WARN_CHMOD); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 718ba543f4a1..186133fa30a7 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -327,6 +327,7 @@ typedef enum { SC_ERR_REDIS, SC_ERR_VAR_LIMIT, SC_WARN_DUPLICATE_OUTPUT, + SC_WARN_CHMOD, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index e62f139d3414..e10f864e05f0 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -31,6 +31,7 @@ #include "tm-modules.h" /* LogFileCtx */ #include "conf.h" /* ConfNode, etc. */ #include "output.h" /* DEFAULT_LOG_* */ +#include "util-byte.h" #include "util-logopenfile.h" #include "util-logopenfile-tile.h" @@ -168,11 +169,12 @@ static void SCLogFileClose(LogFileCtx *log_ctx) /** \brief open the indicated file, logging any errors * \param path filesystem path to open * \param append_setting open file with O_APPEND: "yes" or "no" + * \param mode permissions to set on file * \retval FILE* on success * \retval NULL on error */ static FILE * -SCLogOpenFileFp(const char *path, const char *append_setting) +SCLogOpenFileFp(const char *path, const char *append_setting, uint32_t mode) { FILE *ret = NULL; @@ -182,9 +184,19 @@ SCLogOpenFileFp(const char *path, const char *append_setting) ret = fopen(path, "w"); } - if (ret == NULL) + if (ret == NULL) { SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", path, strerror(errno)); + } else { + if (mode != 0) { + int r = chmod(path, mode); + if (r < 0) { + SCLogWarning(SC_WARN_CHMOD, "Could not chmod %s to %u: %s", + path, mode, strerror(errno)); + } + } + } + return ret; } @@ -256,6 +268,14 @@ SCConfLogOpenGeneric(ConfNode *conf, if (filetype == NULL) filetype = DEFAULT_LOG_FILETYPE; + const char *filemode = ConfNodeLookupChildValue(conf, "filemode"); + uint32_t mode = 0; + if (filemode != NULL && + ByteExtractStringUint32(&mode, 8, strlen(filemode), + filemode) > 0) { + log_ctx->filemode = mode; + } + const char *append = ConfNodeLookupChildValue(conf, "append"); if (append == NULL) append = DEFAULT_LOG_MODE_APPEND; @@ -302,7 +322,7 @@ SCConfLogOpenGeneric(ConfNode *conf, log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1); } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 || strcasecmp(filetype, "file") == 0) { - log_ctx->fp = SCLogOpenFileFp(log_path, append); + log_ctx->fp = SCLogOpenFileFp(log_path, append, log_ctx->filemode); if (log_ctx->fp == NULL) return -1; // Error already logged by Open...Fp routine log_ctx->is_regular = 1; @@ -367,7 +387,7 @@ int SCConfLogReopen(LogFileCtx *log_ctx) /* Reopen the file. Append is forced in case the file was not * moved as part of a rotation process. */ SCLogDebug("Reopening log file %s.", log_ctx->filename); - log_ctx->fp = SCLogOpenFileFp(log_ctx->filename, "yes"); + log_ctx->fp = SCLogOpenFileFp(log_ctx->filename, "yes", log_ctx->filemode); if (log_ctx->fp == NULL) { return -1; // Already logged by Open..Fp routine. } diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 583ca3a403da..201106cc598b 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -91,6 +91,9 @@ typedef struct LogFileCtx_ { /** The name of the file */ char *filename; + /** File permissions */ + uint32_t filemode; + /** Suricata sensor name */ char *sensor_name; From 3b233876640afa8efa9a2a2798535f256d63ed4d Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 22 Feb 2017 07:54:26 +0100 Subject: [PATCH 2520/2553] doc: add documentation for eve-log file permissions --- doc/userguide/output/eve/eve-json-output.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/userguide/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst index 800bf11750d4..d89430ebef48 100644 --- a/doc/userguide/output/eve/eve-json-output.rst +++ b/doc/userguide/output/eve/eve-json-output.rst @@ -268,6 +268,23 @@ For most output types, you can add multiple: Except for ``drop`` for which only a single logger instance is supported. +File permissions +~~~~~~~~~~~~~~~~ + +Log file permissions can be set individually for each logger. ``filemode`` can be used to +control the permissions of a log file, e.g.: + +:: + + outputs: + - eve-log: + enabled: yes + filename: eve.json + filemode: 600 + +The example above sets the file permissions on ``eve.json`` to 600, which means that it is +only readable and writable by the owner of the file. + JSON flags ~~~~~~~~~~ From 365aa1f3e5a149e74ef4cd18f3c755dea68f9a92 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 10 Mar 2017 07:07:09 +0100 Subject: [PATCH 2521/2553] lua: add SCFlowTimestamps function Add SCFlowTimestamps() to return startts and lastts as seconds and microseconds from flow. Examples: startts, lastts = SCFlowTimestamps() startts_s, lastts_s, startts_us, lastts_us = SCFlowTimestamps() --- src/util-lua-common.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/util-lua-common.c b/src/util-lua-common.c index cb3d2dac4dc5..8cf564274d70 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -215,6 +215,42 @@ static int LuaCallbackPacketTimeString(lua_State *luastate) return LuaCallbackTimeStringPushToStackFromPacket(luastate, p); } +/** \internal + * \brief fill lua stack with flow timestamps + * \param luastate the lua state + * \param startts timestamp of first packet in the flow + * \param lastts timestamp of last packet in the flow + * \retval cnt number of data items placed on the stack + * + * Places: seconds (number), seconds (number), microseconds (number), + * microseconds (number) + */ +static int LuaCallbackFlowTimestampsPushToStack(lua_State *luastate, + const struct timeval *startts, + const struct timeval *lastts) +{ + lua_pushnumber(luastate, (double)startts->tv_sec); + lua_pushnumber(luastate, (double)lastts->tv_sec); + lua_pushnumber(luastate, (double)startts->tv_usec); + lua_pushnumber(luastate, (double)lastts->tv_usec); + return 4; +} + +/** \internal + * \brief Wrapper for getting flow timestamp (as numbers) into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackFlowTimestamps(lua_State *luastate) +{ + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) { + return LuaCallbackError(luastate, "internal error: no flow"); + } + + return LuaCallbackFlowTimestampsPushToStack(luastate, &flow->startts, + &flow->lastts); +} + /** \internal * \brief fill lua stack with time string * \param luastate the lua state @@ -791,6 +827,8 @@ int LuaRegisterFunctions(lua_State *luastate) lua_pushcfunction(luastate, LuaCallbackTuple); lua_setglobal(luastate, "SCPacketTuple"); + lua_pushcfunction(luastate, LuaCallbackFlowTimestamps); + lua_setglobal(luastate, "SCFlowTimestamps"); lua_pushcfunction(luastate, LuaCallbackFlowTimeString); lua_setglobal(luastate, "SCFlowTimeString"); lua_pushcfunction(luastate, LuaCallbackTupleFlow); From 7b1dae625121a2bbfb72054e8bc1aba102356e69 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Fri, 10 Mar 2017 07:23:30 +0100 Subject: [PATCH 2522/2553] doc: add documentation for Lua SCFlowTimestamps --- doc/userguide/output/lua-output.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/userguide/output/lua-output.rst b/doc/userguide/output/lua-output.rst index 21e278a5e2d1..adef654a0543 100644 --- a/doc/userguide/output/lua-output.rst +++ b/doc/userguide/output/lua-output.rst @@ -147,6 +147,17 @@ flow return needs end +SCFlowTimestamps +~~~~~~~~~~~~~~~~ + +Get timestamps (seconds and microseconds) of the first and the last packet from +the flow. + +:: + + startts, lastts = SCFlowTimestamps() + startts_s, lastts_s, startts_us, lastts_us = SCFlowTimestamps() + SCFlowTimeString ~~~~~~~~~~~~~~~~ From 3ca1a29bbd6cfe05f20a9d9717be7b98214a3591 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 20 Mar 2017 10:54:51 -0600 Subject: [PATCH 2523/2553] defrag: fix argument used in macro to match signature "p" was being used in the macro but was not an argument to the macro, but it worked due to the context of the macro. Use the actual macro argument, d2, instead of p. Results in no change to generated code. --- src/defrag-hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defrag-hash.c b/src/defrag-hash.c index 736099c58761..a5355ebda06b 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -407,7 +407,7 @@ static inline uint32_t DefragHashGetKey(Packet *p) CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \ (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && \ CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \ - (d1)->proto == IP_GET_IPPROTO(p) && \ + (d1)->proto == IP_GET_IPPROTO(d2) && \ (d1)->id == (id) && \ (d1)->vlan_id[0] == (d2)->vlan_id[0] && \ (d1)->vlan_id[1] == (d2)->vlan_id[1]) From 3726fd66bee905fcca279d18ffabe2a06659eac7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 29 Mar 2017 11:15:51 +0200 Subject: [PATCH 2524/2553] http: fix body tracking corner case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In some cases, observed with inspect limits 0, the body tracking could get confused. When all chunks were already freed, a new chunk would be considered to be the start of the body. This would overwrite the bodies 'content_len_so_far' tracker, instead of adding to it. This in turn could lead to a assertion abort in the inspection code. This patch redoes the append code to always add the current lenght. It cleans up the code to remove redundant logic. Issue: https://redmine.openinfosecfoundation.org/issues/2078 Reported-By: Jørgen Bøhnsdalen --- src/app-layer-htp-body.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index dfda083b6bef..3520182a6395 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -93,37 +93,25 @@ int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, SCReturnInt(-1); } - if (body->first == NULL) { - /* New chunk */ - bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); - if (bd == NULL) { - SCReturnInt(-1); - } + /* New chunk */ + bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); + if (bd == NULL) { + SCReturnInt(-1); + } - if (StreamingBufferAppend(body->sb, &bd->sbseg, data, len) != 0) { - HTPFree(bd, sizeof(HtpBodyChunk)); - SCReturnInt(-1); - } + if (StreamingBufferAppend(body->sb, &bd->sbseg, data, len) != 0) { + HTPFree(bd, sizeof(HtpBodyChunk)); + SCReturnInt(-1); + } + if (body->first == NULL) { body->first = body->last = bd; - - body->content_len_so_far = len; } else { - bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); - if (bd == NULL) { - SCReturnInt(-1); - } - - if (StreamingBufferAppend(body->sb, &bd->sbseg, data, len) != 0) { - HTPFree(bd, sizeof(HtpBodyChunk)); - SCReturnInt(-1); - } - body->last->next = bd; body->last = bd; - - body->content_len_so_far += len; } + body->content_len_so_far += len; + SCLogDebug("body %p", body); SCReturnInt(0); From 6227d0955f568a79a457b55c59635d97ad34007f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 Apr 2017 16:09:18 +0200 Subject: [PATCH 2525/2553] af-packet: fix cppcheck false positive [src/source-af-packet.c:1903]: (error) Resource leak: fd --- src/source-af-packet.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 1e25d316bb34..2f3191620808 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1886,21 +1886,23 @@ int AFPIsFanoutSupported(void) { #ifdef HAVE_PACKET_FANOUT int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (fd != -1) { - uint16_t mode = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; - uint16_t id = 1; - uint32_t option = (mode << 16) | (id & 0xffff); - int r = setsockopt(fd, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); - close(fd); + if (fd < 0) + return 0; - if (r < 0) { - SCLogPerf("fanout not supported by kernel: %s", strerror(errno)); - return 0; - } - return 1; + uint16_t mode = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; + uint16_t id = 1; + uint32_t option = (mode << 16) | (id & 0xffff); + int r = setsockopt(fd, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); + close(fd); + + if (r < 0) { + SCLogPerf("fanout not supported by kernel: %s", strerror(errno)); + return 0; } -#endif + return 1; +#else return 0; +#endif } static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) From e99be86c660c6f06c31a7001b5d322471e21427b Mon Sep 17 00:00:00 2001 From: Phil Date: Wed, 5 Apr 2017 14:19:51 +0200 Subject: [PATCH 2526/2553] Added HPFeeds Support, adapted from Github: Threatstream/suricata --- configure.ac | 15 + src/Makefile.am | 1 + src/alert-hpfeeds.c | 756 ++++++++++++++++++++++++++++++++++++++++ src/alert-hpfeeds.h | 24 ++ src/output.c | 3 + src/suricata-common.h | 1 + src/tm-modules.c | 1 + src/tm-threads-common.h | 1 + src/util-profiling.c | 1 + suricata.yaml.in | 14 +- 10 files changed, 816 insertions(+), 1 deletion(-) create mode 100644 src/alert-hpfeeds.c create mode 100644 src/alert-hpfeeds.h diff --git a/configure.ac b/configure.ac index 57e7253a9baf..fe77cb6a7698 100644 --- a/configure.ac +++ b/configure.ac @@ -695,6 +695,21 @@ exit 1 fi + # hpfeeds + + AC_CHECK_LIB(hpfeeds, hpf_msg_publish, LHPFEEDS="yes", LHPFEEDS="no") + + if test "$LHPFEEDS" != "no"; then + LIBS="${LIBS} -lhpfeeds" + else + echo + echo " ERROR! hpfeeds not found" + echo " Get it https://github.com/threatstream/hpfeeds" + echo + exit 1 + fi + + # libjansson enable_jansson="no" AC_ARG_WITH(libjansson_includes, diff --git a/src/Makefile.am b/src/Makefile.am index 26541ccedfdb..c47e448e55c8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,6 +9,7 @@ bin_PROGRAMS = suricata suricata_SOURCES = \ alert-debuglog.c alert-debuglog.h \ alert-fastlog.c alert-fastlog.h \ +alert-hpfeeds.c alert-hpfeeds.h \ alert-prelude.c alert-prelude.h \ alert-syslog.c alert-syslog.h \ alert-unified2-alert.c alert-unified2-alert.h \ diff --git a/src/alert-hpfeeds.c b/src/alert-hpfeeds.c new file mode 100644 index 000000000000..96b1a69511c9 --- /dev/null +++ b/src/alert-hpfeeds.c @@ -0,0 +1,756 @@ +/* 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. + */ + +#include +#include + +#include "suricata-common.h" +#include "debug.h" +#include "flow.h" +#include "conf.h" + +#include "threads.h" +#include "tm-threads.h" +#include "threadvars.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-reference.h" + +#include "output.h" +#include "alert-hpfeeds.h" + +#include "util-classification-config.h" +#include "util-debug.h" +#include "util-print.h" +#include "util-proto-name.h" +#include "util-optimize.h" + +#ifndef OS_WIN32 + +#define MODULE_NAME "AlertHPFeeds" +#define HPFEEDS_DEFAULT_PORT 10000 +#define READ_BLOCK_SIZE 32767 +#define BUF_LEN 32 + +#define HPFEEDS_NOK 0 +#define HPFEEDS_AUTH_DONE 1 +#define HPFEEDS_READY 2 + +typedef enum { + S_INIT, + S_AUTH, + S_AUTH_DONE, + S_ERROR, + S_TERMINATE +} hpfeeds_session_state_t; + +/* HPFeeds data used in every thread */ +typedef struct AlertHPFeedsCtx_ { + /* hpfeeds connection parameter */ + char *hpfeeds_host; + char *hpfeeds_ident; + char *hpfeeds_secret; + char *hpfeeds_channel; + intmax_t hpfeeds_port; + + /* Reconnect ?! */ + int reconnect; + + /* socket */ + int sock; + struct pollfd pfd; + + /* Connection status */ + int status; + + /* Mutex used for synchronization */ + SCMutex mutex; +} AlertHPFeedsCtx; + +/* Thread structure */ +typedef struct AlertHPFeedsThread_ { + AlertHPFeedsCtx *ctx; +} AlertHPFeedsThread; + +void HPFeedsPublish(json_t *json, AlertHPFeedsCtx *config); +void HPFeedsConnect(AlertHPFeedsCtx *config, int reconnect); +void HPFeedsCloseConnection(int * sock); + +/** + * \brief Function to clear the memory of the output context + * + * \param output_ctx pointer to the output context to be cleared + */ + +static void AlertHPFeedsDeInitCtx(OutputCtx *output_ctx) +{ + AlertHPFeedsCtx *ctx = (AlertHPFeedsCtx *)output_ctx->data; + + if (ctx->hpfeeds_host) SCFree(ctx->hpfeeds_host); + if (ctx->hpfeeds_ident) SCFree(ctx->hpfeeds_ident); + if (ctx->hpfeeds_secret) SCFree(ctx->hpfeeds_secret); + if (ctx->hpfeeds_channel) SCFree(ctx->hpfeeds_channel); + + HPFeedsCloseConnection(&ctx->sock); + + SCFree(ctx); +} + +/** + * \brief Create a new AlertHPFeedsCtx. + * + * \param conf The configuration node for this output. + * \return A OutputCtx pointer on success, NULL on failure. + */ + +OutputCtx *AlertHPFeedsInitCtx(ConfNode *conf) +{ + OutputCtx *output_ctx; + AlertHPFeedsCtx *ctx; + + ctx = SCMalloc(sizeof(AlertHPFeedsCtx)); + + if (unlikely(ctx == NULL)) + SCReturnPtr(NULL, "AlertHPFeedsCtx"); + + ctx->status = HPFEEDS_NOK; + ctx->hpfeeds_port = HPFEEDS_DEFAULT_PORT; + ctx->sock = -1; + + ConfGetChildValue(conf, "host", &ctx->hpfeeds_host); + ConfGetChildValue(conf, "ident", &ctx->hpfeeds_ident); + ConfGetChildValue(conf, "secret", &ctx->hpfeeds_secret); + ConfGetChildValue(conf, "channel", &ctx->hpfeeds_channel); + ConfGetChildValueInt(conf, "port", &ctx->hpfeeds_port); + ConfGetChildValueBool(conf, "reconnect", &ctx->reconnect); + + SCMutexInit(&ctx->mutex, NULL); + + output_ctx = SCMalloc(sizeof(OutputCtx)); + + if (unlikely(output_ctx == NULL)) { + SCFree(ctx); + SCReturnPtr(NULL, "AlertPHPFeedsCtx"); + } + + output_ctx->data = ctx; + output_ctx->DeInit = AlertHPFeedsDeInitCtx; + + if (ctx->hpfeeds_host && ctx->hpfeeds_ident && ctx->hpfeeds_secret && ctx->hpfeeds_channel) + HPFeedsConnect(ctx, 0); + + SCReturnPtr((void*)output_ctx, "OutputCtx"); +} + +/** + * \brief Function to initialize the AlertHPFeedsThread and sets the output + * context pointer + * + * \param tv Pointer to the threadvars + * \param initdata Pointer to the output context + * \param data pointer to pointer to point to the AlertHPFeedsThread + */ + +static TmEcode AlertHPFeedsThreadInit(ThreadVars *t, void *initdata, void **data) +{ + AlertHPFeedsThread *thread_ctx; + + SCEnter(); + + if(initdata == NULL) + { + SCLogDebug("Error getting context for hpfeeds."); + SCReturnInt(TM_ECODE_FAILED); + } + + thread_ctx = SCMalloc(sizeof(AlertHPFeedsThread)); + + if (unlikely(thread_ctx == NULL)) + SCReturnInt(TM_ECODE_FAILED); + + memset(thread_ctx, 0, sizeof(AlertHPFeedsThread)); + + /** Use the Ouput Context */ + thread_ctx->ctx = ((OutputCtx *)initdata)->data; + + *data = (void *)thread_ctx; + + SCReturnInt(TM_ECODE_OK); + return TM_ECODE_OK; +} + +/** + * \brief Function to deinitialize the AlertHPFeedsThread + * + * \param tv Pointer to the threadvars + * \param data pointer to the AlertHPFeedsThread to be cleared + */ + +static TmEcode AlertHPFeedsThreadDeinit(ThreadVars *t, void *data) +{ + AlertHPFeedsThread *thread_ctx = (AlertHPFeedsThread *)data; + + if (thread_ctx == NULL) + return TM_ECODE_OK; + + /* clear memory */ + memset(thread_ctx, 0, sizeof(AlertHPFeedsThread)); + SCFree(thread_ctx); + + return TM_ECODE_OK; +} + +/* Input is packet and an nine-byte (including NULL) character array. Results + * are put into the character array. + */ + +void CreateTCPFlagString(const Packet * p, char *flagBuffer) +{ + /* parse TCP flags */ + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_CWR) ? '1' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_ECN) ? '2' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_URG) ? 'U' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_ACK) ? 'A' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_PUSH) ? 'P' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_RST) ? 'R' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_SYN) ? 'S' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_FIN) ? 'F' : '*'); + *flagBuffer = '\0'; +} + +/** + * \brief Function which is called to create json alert + * + * \param tv Pointer to the threadvars + * \param p Pointer to the packet + * \param data pointer to the AlertHPFeedsThread + * + * \return On succes return TM_ECODE_OK + */ + +static int CreatePacketData(ThreadVars *tv, const Packet *p, json_t * js) +{ + char srcip[46], dstip[46]; + char construct_buf[BUF_LEN]; + + char timestamp[64]; + struct tm* lt = localtime(&p->ts.tv_sec); + strftime((char*)timestamp, 64, "%Y/%m/%d %H:%M:%S", lt); + + char timestamp_usec[68]; + + snprintf(timestamp_usec, 68, "%s.%d", timestamp, (int)p->ts.tv_usec); + + json_object_set_new(js, "timestamp", json_string((char *)timestamp_usec)); + + srcip[0] = '\0'; + dstip[0] = '\0'; + + /* IPv4/v6 */ + if (PKT_IS_IPV4(p)) { + + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); + + json_object_set_new(js, "destination_ip", json_string(dstip)); + json_object_set_new(js, "source_ip", json_string(srcip)); + + json_object_set_new(js, "ip_tos", json_integer(IPV4_GET_IPTOS(p))); + json_object_set_new(js, "ip_ttl", json_integer(IPV4_GET_IPTTL(p))); + json_object_set_new(js, "ip_id", json_integer(IPV4_GET_IPID(p))); + + + } else if (PKT_IS_IPV6(p)) { + + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); + + json_object_set_new(js, "destination_ip", json_string(dstip)); + json_object_set_new(js, "source_ip", json_string(srcip)); + + } + + char proto[16]; + if (SCProtoNameValid(IP_GET_IPPROTO(p)) == TRUE) { + strlcpy(proto, known_proto[IP_GET_IPPROTO(p)], sizeof(proto)); + } else { + snprintf(proto, sizeof(proto), "%03" PRIu32, IP_GET_IPPROTO(p)); + } + + json_object_set_new(js, "proto", json_string(proto)); + + /* Ethernet */ + if (p->ethh != NULL) { + + snprintf(construct_buf, BUF_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", p->ethh->eth_src[0], + p->ethh->eth_src[1], p->ethh->eth_src[2], p->ethh->eth_src[3], + p->ethh->eth_src[4], p->ethh->eth_src[5]); + json_object_set_new(js, "eth_src", json_string((char *) construct_buf)); + + snprintf(construct_buf, BUF_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", p->ethh->eth_dst[0], + p->ethh->eth_dst[1], p->ethh->eth_dst[2], p->ethh->eth_dst[3], + p->ethh->eth_dst[4], p->ethh->eth_dst[5]); + json_object_set_new(js, "eth_dst", json_string((char *) construct_buf)); + + snprintf(construct_buf, BUF_LEN, "0x%X", ntohs(p->ethh->eth_type)); + json_object_set_new(js, "eth_type", json_string((char *)construct_buf)); + + snprintf(construct_buf, BUF_LEN,"0x%X", p->pktlen); + json_object_set_new(js, "eth_len", json_string((char *)construct_buf)); + } + + + /* TCP */ + if (PKT_IS_TCP(p)) { + + snprintf(construct_buf, BUF_LEN,"0x%X", p->tcph->th_seq); + json_object_set_new(js, "tcp_seq", json_string((char *)construct_buf)); + + snprintf(construct_buf, BUF_LEN, "0x%X", p->tcph->th_ack); + json_object_set_new(js, "tcp_ack", json_string((char *)construct_buf)); + + snprintf(construct_buf, BUF_LEN, "0x%lX", (u_long)ntohl(p->tcph->th_win)); + json_object_set_new(js, "tcp_win", json_string((char *)construct_buf)); + + json_object_set_new(js, "tcp_len", json_integer(TCP_GET_RAW_OFFSET(p->tcph) << 2)); + + json_object_set_new(js, "source_port", json_integer(p->sp)); + json_object_set_new(js, "destination_port", json_integer(p->dp)); + + char tcpflags[9]; + CreateTCPFlagString(p, tcpflags); + json_object_set_new(js, "tcp_flags", json_string((char *)tcpflags)); + } + + /* UDP */ + else if (PKT_IS_UDP(p)) { + json_object_set_new(js, "udp_len", json_integer(UDP_GET_LEN(p))); + json_object_set_new(js, "source_port", json_integer(p->sp)); + json_object_set_new(js, "destination_port", json_integer(p->dp)); + } + + /* ICMPv4/v6 */ + else if (p->proto == IPPROTO_ICMP) { + + if (PKT_IS_ICMPV4(p)) { + + json_object_set_new(js, "icmp_version", json_integer(4)); + json_object_set_new(js, "icmp_id", json_integer(ICMPV4_GET_ID(p))); + json_object_set_new(js, "icmp_seq", json_integer(ICMPV4_GET_SEQ(p))); + json_object_set_new(js, "icmp_type",json_integer(ICMPV4_GET_TYPE(p))); + json_object_set_new(js, "icmp_code",json_integer(ICMPV4_GET_CODE(p))); + + } else if(PKT_IS_ICMPV6(p)) { + + json_object_set_new(js, "icmp_version", json_integer(6)); + json_object_set_new(js, "icmp_id", json_integer(ICMPV6_GET_ID(p))); + json_object_set_new(js, "icmp_seq", json_integer(ICMPV6_GET_SEQ(p))); + json_object_set_new(js, "icmp_type",json_integer(ICMPV6_GET_TYPE(p))); + json_object_set_new(js, "icmp_code",json_integer(ICMPV6_GET_CODE(p))); + } + + } + + return 1; + +} + +static int AlertHPFeedsCondition(ThreadVars *tv, const Packet *p) +{ + return (p->alerts.cnt > 0 ? TRUE : FALSE); +} + +static int AlertHPFeedsLogger(ThreadVars *tv, void *thread_data, const Packet *p) +{ + AlertHPFeedsThread *thread_ctx = (AlertHPFeedsThread *)thread_data; + AlertHPFeedsCtx *ctx = (AlertHPFeedsCtx *)thread_ctx->ctx; + + /* Return if packet is NULL or socket isn't open */ + if(p == NULL || ctx->sock == -1) + return TM_ECODE_OK; + + SCMutex *mtx = &ctx->mutex; + + SCMutexLock(mtx); + + json_t *record = json_object(); + json_object_set_new(record, "sensor", json_string(ctx->hpfeeds_ident)); + + if (!CreatePacketData(tv, p, record)) + { + json_decref(record); + SCMutexUnlock(mtx); + return TM_ECODE_OK; + } + + int i = 0; + + for ( ; i < p->alerts.cnt; i++) { + + const PacketAlert *pa = &p->alerts.alerts[i]; + + if (unlikely(pa->s == NULL)) { + continue; + } + + char *action = "allowed"; + if (pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) { + action = "blocked"; + } else if ((pa->action & ACTION_DROP) && EngineModeIsIPS()) { + action = "blocked"; + } + + json_object_set_new(record, "action", json_string(action)); + + // header + // priority + // classification + + json_object_set_new(record, "signature_id", json_integer(pa->s->id)); + json_object_set_new(record, "signature_rev", json_integer(pa->s->rev)); + json_object_set_new(record, "signature", json_string((pa->s->msg) ? pa->s->msg : "")); + } + + HPFeedsPublish(record, ctx); + + json_decref(record); + + SCMutexUnlock(mtx); + + return TM_ECODE_OK; +} + + +/* == Reused function for hpfeeds == + * + * Functions: HPFeedsReadMsg + * HPFeedsGetError + * HPFeedsCloseConnection + * HPFeedsConnect + * HPFeedsPublish + */ + +u_char *HPFeedsReadMsg(int sock) +{ + u_char *buffer; + int msglen; + + int len; + int templen; + char tempbuf[READ_BLOCK_SIZE]; + + if (read(sock, &msglen, 4) != 4) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal read()"); + return NULL; + } + + if ((buffer = malloc(ntohl(msglen))) == NULL) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal malloc()"); + return NULL; + } + + *(unsigned int *) buffer = msglen; + msglen = ntohl(msglen); + + len = 4; + templen = len; + while ((templen > 0) && (len < msglen)) + { + templen = read(sock, tempbuf, READ_BLOCK_SIZE); + memcpy(buffer + len, tempbuf, templen); + len += templen; + } + + if (len != msglen) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal read()"); + free(buffer); + return NULL; + } + + return buffer; +} + +void HPFeedsGetError(hpf_msg_t *msg, int sock) +{ + + u_char *errmsg; + + if (msg) + { + if ((errmsg = calloc(1, msg->hdr.msglen - sizeof(msg->hdr))) == NULL) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal write()"); + hpf_msg_delete(msg); + return; + } + + memcpy(errmsg, msg->data, ntohl(msg->hdr.msglen) - sizeof(msg->hdr)); + + SCLogNotice("alert-hpfeeds: server error: '%s'", errmsg); + + free(errmsg); + hpf_msg_delete(msg); + } +} + + +void HPFeedsCloseConnection(int *sock) +{ + if (*sock != -1) { + close(*sock); + *sock = -1; + } +} + +void HPFeedsConnect(AlertHPFeedsCtx *config, int reconnect) +{ + + /* socket already on - returning */ + if (config->sock != -1) return; + + hpf_msg_t *msg = NULL; + hpf_chunk_t *chunk; + + unsigned int nonce = 0; + + struct hostent *he; + struct sockaddr_in host; + + memset(&host, 0, sizeof(struct sockaddr_in)); + host.sin_family = AF_INET; + host.sin_port = htons(config->hpfeeds_port); + + if ((he = gethostbyname((char *)config->hpfeeds_host)) == NULL) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal gethostbyname()\n"); + return; + } + + host.sin_addr = *(struct in_addr *) he->h_addr; + + if ((config->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal socket()"); + return; + } + + if (connect(config->sock, (struct sockaddr *) &host, sizeof(host)) == -1) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal connect()"); + return; + } + + /* Set poll fd */ + config->pfd.fd = config->sock; + config->pfd.events = POLLIN; + config->pfd.revents = 0; + + /* Set connection keep alive */ + int optval = 1; + + if(setsockopt(config->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) + { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal setsockopt()"); + HPFeedsCloseConnection(&config->sock); + return; + } + + hpfeeds_session_state_t hpfeeds_state = S_INIT; + + for (;;) + { + + switch (hpfeeds_state) + { + + case S_INIT: + + if ((msg = (hpf_msg_t *) HPFeedsReadMsg(config->sock)) == NULL) { + HPFeedsCloseConnection(&config->sock); + break; + } + + switch (msg->hdr.opcode) + { + + case OP_INFO: + + chunk = hpf_msg_get_chunk((u_char *)msg + sizeof(msg->hdr), ntohl(msg->hdr.msglen) - sizeof(msg->hdr)); + + if (!chunk) + { + SCLogNotice("alert-hpfeeds: invalid message format"); + hpfeeds_state = S_TERMINATE; + break; + } + + nonce = *(unsigned int *) ((u_char *)msg + sizeof(msg->hdr) + chunk->len + 1); + hpfeeds_state = S_AUTH; + + hpf_msg_delete(msg); + break; + + case OP_ERROR: + hpfeeds_state = S_ERROR; + break; + + default: + hpf_msg_delete(msg); + hpfeeds_state = S_TERMINATE; + SCLogNotice("alert-hpfeeds: unknown server message (type %u)", msg->hdr.opcode); + break; + } + + case S_AUTH: + + SCLogNotice("alert-hpfeeds: sending authentication."); + + msg = hpf_msg_auth(nonce, (u_char *) config->hpfeeds_ident, strlen(config->hpfeeds_ident) \ + ,(u_char *) config->hpfeeds_secret, strlen(config->hpfeeds_secret)); + + if (write(config->sock, (u_char *) msg, ntohl(msg->hdr.msglen)) == -1) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal write()"); + hpfeeds_state = S_TERMINATE; + hpf_msg_delete(msg); + break; + } + + if (reconnect == 0) { + + int rv = poll(&config->pfd, 1, 1000); + + if (rv > 0 && config->pfd.revents && POLLIN) + { + hpfeeds_state = S_ERROR; + + msg = (hpf_msg_t *) HPFeedsReadMsg(config->sock); + break; + } + } + + hpfeeds_state = S_AUTH_DONE; + config->status = HPFEEDS_AUTH_DONE; + + SCLogNotice("alert-hpfeeds: authentication done."); + hpf_msg_delete(msg); + + break; + + case S_ERROR: + + if (msg) { + HPFeedsGetError(msg, config->sock); + } + + hpfeeds_state = S_TERMINATE; + break; + + case S_TERMINATE: + default: + HPFeedsCloseConnection(&config->sock); + SCLogNotice("alert-hpfeeds: connection terminated..."); + break; + } + + if (hpfeeds_state == S_AUTH_DONE || config->sock == -1) + break; + } +} + + +void HPFeedsPublish(json_t *json, AlertHPFeedsCtx *config) +{ + + char *data = json_dumps(json, 0); + unsigned int len = strlen(data); + + hpf_msg_t *msg; + + msg = hpf_msg_publish((u_char *)config->hpfeeds_ident, strlen(config->hpfeeds_ident) \ + ,(u_char *)config->hpfeeds_channel, strlen(config->hpfeeds_channel), (u_char *)data, len); + + if (write(config->sock, (char *) msg, ntohl(msg->hdr.msglen)) == -1) { + + SCLogNotice("alert-hpfeeds: Publish failed on write.\n"); + HPFeedsCloseConnection(&config->sock); + + if (config->reconnect) { + HPFeedsConnect(config, config->reconnect); + HPFeedsPublish(json, config); + } + + free(data); + hpf_msg_delete(msg); + + return; + } + + /* Do another socket poll - in case of wrong channel */ + if (config->status != HPFEEDS_READY) + { + + int rv = poll(&config->pfd, 1, 1000); + + if (rv == 0) + { + config->status = HPFEEDS_READY; + SCLogNotice("alert-hpfeeds: Initial publish done.\n"); + } + else if (rv > 0 && config->pfd.revents && POLLIN) + { + + config->status = HPFEEDS_NOK; + hpf_msg_t *error_msg = NULL; + + if ((error_msg = (hpf_msg_t *) HPFeedsReadMsg(config->sock)) != NULL) + { + HPFeedsGetError(error_msg, config->sock); + SCLogNotice("alert-hpfeeds: Failed to publish.\n"); + } + else + { + SCLogNotice("alert-hpfeeds: Something went wrong\n"); + } + + HPFeedsCloseConnection(&config->sock); + } + } + + free(data); + hpf_msg_delete(msg); +} + +#endif /* !OS_WIN32 */ + + + +/** \brief Function to register the AlertHPFeed module */ +void AlertHPFeeds(void) +{ +#ifndef OS_WIN32 + + tmm_modules[TMM_ALERTHPFEEDS].name = MODULE_NAME; + tmm_modules[TMM_ALERTHPFEEDS].ThreadInit = AlertHPFeedsThreadInit; + tmm_modules[TMM_ALERTHPFEEDS].Func = NULL; + tmm_modules[TMM_ALERTHPFEEDS].ThreadDeinit = AlertHPFeedsThreadDeinit; + tmm_modules[TMM_ALERTHPFEEDS].cap_flags = 0; + tmm_modules[TMM_ALERTHPFEEDS].flags = TM_FLAG_LOGAPI_TM; + + OutputRegisterPacketModule(LOGGER_HPFEEDS, MODULE_NAME, "alert-hpfeeds", + AlertHPFeedsInitCtx, AlertHPFeedsLogger, AlertHPFeedsCondition, AlertHPFeedsThreadInit, AlertHPFeedsThreadDeinit, NULL); + +#endif /* !OS_WIN32 */ +} diff --git a/src/alert-hpfeeds.h b/src/alert-hpfeeds.h new file mode 100644 index 000000000000..c6b56ba4a29e --- /dev/null +++ b/src/alert-hpfeeds.h @@ -0,0 +1,24 @@ +/* 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. + */ + +#ifndef __ALERT_HPFEEDS_H__ +#define __ALERT_HPFEEDS_H__ + +void AlertHPFeeds(void); + +#endif /* __ALERT_HPFEEDS_H__ */ + diff --git a/src/output.c b/src/output.c index 3c509f266246..904e631af313 100644 --- a/src/output.c +++ b/src/output.c @@ -41,6 +41,7 @@ #include "output.h" #include "alert-fastlog.h" +#include "alert-hpfeeds.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "alert-prelude.h" @@ -1028,6 +1029,8 @@ void OutputRegisterLoggers(void) LuaLogRegister(); /* fast log */ AlertFastLogRegister(); + /* hpfeeds log */ + AlertHPFeeds(); /* debug log */ AlertDebugLogRegister(); /* prelue log */ diff --git a/src/suricata-common.h b/src/suricata-common.h index 7fd68886d848..76abd710027f 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -360,6 +360,7 @@ typedef enum { LOGGER_JSON_DROP, LOGGER_JSON_SSH, LOGGER_DNS, + LOGGER_HPFEEDS, LOGGER_HTTP, LOGGER_JSON_DNS, LOGGER_JSON_HTTP, diff --git a/src/tm-modules.c b/src/tm-modules.c index 13fa409f196b..061b2838bfa9 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -229,6 +229,7 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_STATSLOGGER); CASE_CODE (TMM_FLOWMANAGER); CASE_CODE (TMM_FLOWRECYCLER); + CASE_CODE (TMM_ALERTHPFEEDS); CASE_CODE (TMM_UNIXMANAGER); CASE_CODE (TMM_DETECTLOADER); CASE_CODE (TMM_RECEIVENETMAP); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 8325687a8322..9669a0e2ea5c 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -64,6 +64,7 @@ typedef enum { TMM_FLOWMANAGER, TMM_FLOWRECYCLER, + TMM_ALERTHPFEEDS, TMM_DETECTLOADER, TMM_UNIXMANAGER, diff --git a/src/util-profiling.c b/src/util-profiling.c index 274805d01f5f..65fe1e35141c 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1342,6 +1342,7 @@ const char * PacketProfileLoggertIdToString(LoggerId id) CASE_CODE (LOGGER_JSON_DROP); CASE_CODE (LOGGER_JSON_SSH); CASE_CODE (LOGGER_DNS); + CASE_CDOE (LOGGER_HPFEEDS); CASE_CODE (LOGGER_HTTP); CASE_CODE (LOGGER_JSON_DNS); CASE_CODE (LOGGER_JSON_HTTP); diff --git a/suricata.yaml.in b/suricata.yaml.in index a91d1fe85efb..ff4784a9b838 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -134,6 +134,17 @@ outputs: append: yes #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + + + # hpfeeds output + - alert-hpfeeds: + enabled: yes + host: 104.131.177.234 + ident: suricata + secret: s3cr3t + channel: suricata.events + reconnect: yes # do we reconnect if publish fails ?! + # Extensible Event Format (nicknamed EVE) event log in JSON format - eve-log: enabled: @e_enable_evelog@ @@ -976,6 +987,7 @@ unix-command: legacy: uricontent: enabled + ## ## Detection settings ## @@ -1549,7 +1561,7 @@ capture: # netmap: # To specify OS endpoint add plus sign at the end (e.g. "eth0+") - - interface: eth2 + - interface: eth0 # Number of receive threads. "auto" uses number of RSS queues on interface. #threads: auto # You can use the following variables to activate netmap tap or IPS mode. From e1bf48c0ee89d16b2fc0867b4958dbad814b55ec Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 5 Apr 2017 15:13:17 +0200 Subject: [PATCH 2527/2553] pool: fix compiler warning clang-4.0 reported: util-pool.c:242:13: warning: logical not is only applied to the left hand side of this bitwise operator [-Wlogical-not-parentheses] if (! pb->flags & POOL_BUCKET_PREALLOCATED) { ^ ~ util-pool.c:242:13: note: add parentheses after the '!' to evaluate the bitwise operator first if (! pb->flags & POOL_BUCKET_PREALLOCATED) { ^ ( ) util-pool.c:242:13: note: add parentheses around left hand side expression to silence this warning if (! pb->flags & POOL_BUCKET_PREALLOCATED) { ^ ( ) util-pool.c:261:13: warning: logical not is only applied to the left hand side of this bitwise operator [-Wlogical-not-parentheses] if (! pb->flags & POOL_BUCKET_PREALLOCATED) { ^ ~ util-pool.c:261:13: note: add parentheses after the '!' to evaluate the bitwise operator first if (! pb->flags & POOL_BUCKET_PREALLOCATED) { ^ ( ) util-pool.c:261:13: note: add parentheses around left hand side expression to silence this warning if (! pb->flags & POOL_BUCKET_PREALLOCATED) { ^ ( ) 2 warnings generated. --- src/util-pool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-pool.c b/src/util-pool.c index dc536df7fff2..4706222d8df2 100644 --- a/src/util-pool.c +++ b/src/util-pool.c @@ -239,7 +239,7 @@ void PoolFree(Pool *p) SCFree(pb->data); } pb->data = NULL; - if (! pb->flags & POOL_BUCKET_PREALLOCATED) { + if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) { SCFree(pb); } } @@ -258,7 +258,7 @@ void PoolFree(Pool *p) } pb->data = NULL; } - if (! pb->flags & POOL_BUCKET_PREALLOCATED) { + if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) { SCFree(pb); } } From b134dfcce71ae6a5ae45bf1ce2e47d024e0d3a7a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 5 Apr 2017 15:19:33 -0400 Subject: [PATCH 2528/2553] modbus: fix compiler warnings about alignment app-layer-modbus.c:1226:39: warning: taking address of packed member 'transactionId' of class or structure 'ModbusHeader_' may result in an unaligned pointer value [-Waddress-of-packed-member] if (ModbusExtractUint16(modbus, &(header->transactionId), input, input_len, &offset) || ^~~~~~~~~~~~~~~~~~~~~ app-layer-modbus.c:1228:39: warning: taking address of packed member 'protocolId' of class or structure 'ModbusHeader_' may result in an unaligned pointer value [-Waddress-of-packed-member] ModbusExtractUint16(modbus, &(header->protocolId), input, input_len, &offset) || ^~~~~~~~~~~~~~~~~~ app-layer-modbus.c:1230:39: warning: taking address of packed member 'length' of class or structure 'ModbusHeader_' may result in an unaligned pointer value [-Waddress-of-packed-member] ModbusExtractUint16(modbus, &(header->length), input, input_len, &offset) || ^~~~~~~~~~~~~~ 3 warnings generated. Bug #2088 --- src/app-layer-modbus.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index cdb47bd86338..97fd4be0d754 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1222,15 +1222,30 @@ static int ModbusParseHeader(ModbusState *modbus, SCEnter(); uint16_t offset = 0; + int r = 0; + + /* can't pass the header fields directly due to alignment (Bug 2088) */ + uint16_t transaction_id = 0; + uint16_t protocol_id = 0; + uint16_t length = 0; + uint8_t unit_id = 0; + /* Transaction Identifier (2 bytes) */ - if (ModbusExtractUint16(modbus, &(header->transactionId), input, input_len, &offset) || + r = ModbusExtractUint16(modbus, &transaction_id, input, input_len, &offset); /* Protocol Identifier (2 bytes) */ - ModbusExtractUint16(modbus, &(header->protocolId), input, input_len, &offset) || + r |= ModbusExtractUint16(modbus, &protocol_id, input, input_len, &offset); /* Length (2 bytes) */ - ModbusExtractUint16(modbus, &(header->length), input, input_len, &offset) || + r |= ModbusExtractUint16(modbus, &length, input, input_len, &offset); /* Unit Identifier (1 byte) */ - ModbusExtractUint8(modbus, &(header->unitId), input, input_len, &offset)) + r |= ModbusExtractUint8(modbus, &unit_id, input, input_len, &offset); + + if (r != 0) { SCReturnInt(-1); + } + header->transactionId = transaction_id; + header->protocolId = protocol_id; + header->length = length; + header->unitId = unit_id; SCReturnInt(0); } From d5a0eb4b2cbfd5e93796e975be25e6304c7a14db Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Apr 2017 08:59:34 +0200 Subject: [PATCH 2529/2553] geoip: fix compiler warning detect-geoip.c:78:40: error: incompatible pointer types assigning to 'int (*)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)' from 'int (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *)' [-Werror,-Wincompatible-pointer-types] sigmatch_table[DETECT_GEOIP].Match = DetectGeoipMatch; ^ ~~~~~~~~~~~~~~~~ 1 error generated. Bug #2045 --- src/detect-geoip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detect-geoip.c b/src/detect-geoip.c index 0b1d29a3d262..1af990c1e492 100644 --- a/src/detect-geoip.c +++ b/src/detect-geoip.c @@ -63,7 +63,7 @@ void DetectGeoipRegister(void) static int DetectGeoipMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); + const Signature *, const SigMatchCtx *); static int DetectGeoipSetup(DetectEngineCtx *, Signature *, char *); static void DetectGeoipRegisterTests(void); static void DetectGeoipDataFree(void *); @@ -165,7 +165,7 @@ static int CheckGeoMatchIPv4(const DetectGeoipData *geoipdata, uint32_t ip) * \retval 1 match */ static int DetectGeoipMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectGeoipData *geoipdata = (const DetectGeoipData *)ctx; int matches = 0; From af174c82bb127481055e7f84bf661e3b6d186ff6 Mon Sep 17 00:00:00 2001 From: fooinha Date: Sat, 3 Dec 2016 12:22:26 +0000 Subject: [PATCH 2530/2553] log: common custom format output --- src/Makefile.am | 1 + src/log-cf-common.c | 283 ++++++++++++++++++++++++++++++++++++++++++++ src/log-cf-common.h | 81 +++++++++++++ src/log-httplog.c | 210 ++++++++++---------------------- src/output.c | 4 + src/util-error.c | 1 + src/util-error.h | 1 + src/util-time.c | 9 ++ src/util-time.h | 11 +- 9 files changed, 449 insertions(+), 152 deletions(-) create mode 100644 src/log-cf-common.c create mode 100644 src/log-cf-common.h diff --git a/src/Makefile.am b/src/Makefile.am index 26541ccedfdb..de7006d05f0f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -261,6 +261,7 @@ log-dnslog.c log-dnslog.h \ log-droplog.c log-droplog.h \ log-file.c log-file.h \ log-filestore.c log-filestore.h \ +log-cf-common.c log-cf-common.h \ log-httplog.c log-httplog.h \ log-pcap.c log-pcap.h \ log-stats.c log-stats.h \ diff --git a/src/log-cf-common.c b/src/log-cf-common.c new file mode 100644 index 000000000000..c85703f8afa4 --- /dev/null +++ b/src/log-cf-common.c @@ -0,0 +1,283 @@ +/* Copyright (C) 2007-2016 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 Paulo Pacheco + * \author Victor Julien + * \author Ignacio Sanchez + * + * Common custom logging format + */ + +#include "log-cf-common.h" +#include "util-print.h" +#include "util-unittest.h" + +/** + * \brief Creates a custom format node + * \retval LogCustomFormatNode * ptr if created + * \retval NULL if failed to allocate + */ +LogCustomFormatNode * LogCustomFormatNodeAlloc() +{ + LogCustomFormatNode * node = SCMalloc(sizeof(LogCustomFormatNode)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to alloc custom format node"); + return NULL; + } + memset(node, '\0', sizeof(LogCustomFormatNode)); + memset(node->data, '\0', LOG_NODE_STRLEN); + + return node; +} + +/** + * \brief Creates a custom format. + * \retval LogCustomFormat * ptr if created + * \retval NULL if failed to allocate + */ +LogCustomFormat * LogCustomFormatAlloc() +{ + LogCustomFormat * cf = SCMalloc(sizeof(LogCustomFormat)); + if (unlikely(cf == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to alloc custom format"); + return NULL; + } + memset(cf, '\0', sizeof(LogCustomFormat)); + + return cf; +} + +/** + * \brief Frees memory held by a custom format node + * \param LogCustomFormatNode * node - node to relaease + */ +void LogCustomFormatNodeFree(LogCustomFormatNode *node) +{ + if (node==NULL) + return; + + SCFree(node); +} + +/** + * \brief Frees memory held by a custom format + * \param LogCustomFormat * cf - format to relaease + */ +void LogCustomFormatFree(LogCustomFormat *cf) +{ + if (cf==NULL) + return; + + for (size_t i = 0; i < cf->cf_n; ++i) { + LogCustomFormatNodeFree(cf->cf_nodes[i]); + } + SCFree(cf); +} + +/** + * \brief Parses and saves format nodes for custom format + * \param LogCustomFormat * cf - custom format to build + * \param const char * format - string with format specification + */ +int LogCustomFormatParse(LogCustomFormat *cf, const char *format) +{ + const char *p, *np; + uint32_t n; + LogCustomFormatNode *node = NULL; + + if (cf==NULL) + return 0; + + if (format==NULL) + return 0; + + p=format; + + for (cf->cf_n = 0; cf->cf_n < LOG_MAXN_NODES-1 && p && *p != '\0';){ + + node = LogCustomFormatNodeAlloc(); + if (node == NULL) { + goto parsererror; + } + node->maxlen = 0; + + if (*p != '%'){ + /* Literal found in format string */ + node->type = LOG_CF_LITERAL; + np = strchr(p, '%'); + if (np == NULL){ + n = LOG_NODE_STRLEN-2; + np = NULL; /* End */ + }else{ + n = np-p; + } + strlcpy(node->data,p,n+1); + p = np; + } else { + /* Non Literal found in format string */ + p++; + if (*p == '[') { /* Check if maxlength has been specified (ie: [25]) */ + p++; + np = strchr(p, ']'); + if (np != NULL) { + if (np-p > 0 && np-p < 10){ + long maxlen = strtol(p,NULL,10); + if (maxlen > 0 && maxlen < LOG_NODE_MAXOUTPUTLEN) { + node->maxlen = (uint32_t) maxlen; + } + } else { + goto parsererror; + } + p = np + 1; + } else { + goto parsererror; + } + } + if (*p == '{') { /* Simple format char */ + np = strchr(p, '}'); + if (np != NULL && np-p > 1 && np-p < LOG_NODE_STRLEN-2) { + p++; + n = np-p; + strlcpy(node->data, p, n+1); + p = np; + } else { + goto parsererror; + } + p++; + } else { + node->data[0] = '\0'; + } + node->type = *p; + if (*p == '%'){ + node->type = LOG_CF_LITERAL; + strlcpy(node->data, "%", 2); + } + p++; + } + LogCustomFormatAddNode(cf, node); + + } + return 1; + +parsererror: + LogCustomFormatNodeFree(node); + return 0; + +} + +/** + * \brief Adds a node to custom format + * \param LogCustomFormat * cf - custom format + * \param LogCustomFormatNode * node - node to add + */ +void LogCustomFormatAddNode(LogCustomFormat *cf, LogCustomFormatNode *node) +{ + if (cf == NULL || node == NULL) + return; + + if (cf->cf_n == LOG_MAXN_NODES) { + SCLogWarning(SC_WARN_LOG_CF_TOO_MANY_NODES, "Too many options for custom format"); + return; + } + +#ifdef DEBUG + SCLogDebug("%d-> n.type=[%d] n.maxlen=[%d] n.data=[%s]", + cf->cf_n, node->type, node->maxlen, node->data); +#endif + + cf->cf_nodes[cf->cf_n] = node; + cf->cf_n++; +} + +/** + * \brief Writes a timestamp with given format into a MemBuffer + * \param MemBuffer * buffer - where to write + * \param const char * fmt - format to be used write timestamp + * \param const struct timeveal *ts - the timetstamp + * + */ +void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const struct timeval *ts) { + + time_t time = ts->tv_sec; + struct tm local_tm; + struct tm *timestamp = SCLocalTime(time, &local_tm); + char buf[128] = {0}; + const char * fmt_to_use = TIMESTAMP_DEFAULT_FORMAT; + + if (fmt && *fmt != '\0') { + fmt_to_use = fmt; + } + + CreateFormattedTimeString (timestamp, fmt_to_use, buf, sizeof(buf)); + PrintRawUriBuf((char *)buffer->buffer, &buffer->offset, + buffer->size, (uint8_t *)buf,strlen(buf)); +} + + +#ifdef UNITTESTS +/** + * \internal + * \brief This test tests default timestamp format + */ +static int LogCustomFormatTest01(void) +{ + + struct tm tm; + tm.tm_sec = 0; + tm.tm_min = 30; + tm.tm_hour = 4; + tm.tm_mday = 13; + tm.tm_mon = 0; + tm.tm_year = 114; + tm.tm_wday = 1; + tm.tm_yday = 13; + tm.tm_isdst = 0; + time_t secs = mktime(&tm); + struct timeval ts = {secs, 0}; + + MemBuffer *buffer = MemBufferCreateNew(62); + if (!buffer) { + return 0; + } + + LogCustomFormatWriteTimestamp(buffer, "", &ts); + /* + * {buffer = "01/13/14-04:30:00", size = 62, offset = 17} + */ + FAIL_IF_NOT( buffer->offset == 17); + FAIL_IF(strcmp((char *)buffer->buffer, "01/13/14-04:30:00") != 0); + + MemBufferFree(buffer); + + return 1; +} + +void LogCustomFormatRegisterTests(void) +{ + UtRegisterTest("LogCustomFormatTest01", LogCustomFormatTest01); +} +#endif /* UNITTESTS */ + +void LogCustomFormatRegister(void) +{ +#ifdef UNITTESTS + LogCustomFormatRegisterTests(); +#endif /* UNITTESTS */ +} diff --git a/src/log-cf-common.h b/src/log-cf-common.h new file mode 100644 index 000000000000..ad66754830e8 --- /dev/null +++ b/src/log-cf-common.h @@ -0,0 +1,81 @@ +/* Copyright (C) 2016 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 + * \author Ignacio Sanchez + * \author Paulo Pacheco + * + * Common custom loggging format + */ + +#ifndef __LOG_CF_COMMON_H__ +#define __LOG_CF_COMMON_H__ + +#define LOG_MAXN_NODES 64 +#define LOG_NODE_STRLEN 256 +#define LOG_NODE_MAXOUTPUTLEN 8192 + +#define TIMESTAMP_DEFAULT_FORMAT "%D-%H:%M:%S" +#define TIMESTAMP_DEFAULT_FORMAT_LEN 62 + +/* Common format nodes */ +#define LOG_CF_NONE "-" +#define LOG_CF_LITERAL '%' +#define LOG_CF_TIMESTAMP 't' +#define LOG_CF_TIMESTAMP_U 'z' +#define LOG_CF_CLIENT_IP 'a' +#define LOG_CF_SERVER_IP 'A' +#define LOG_CF_CLIENT_PORT 'p' +#define LOG_CF_SERVER_PORT 'P' + +/* Line log common separators **/ +#define LOG_CF_STAR_SEPARATOR "[**]" +#define LOG_CF_WRITE_STAR_SEPATATOR(buffer) \ + MemBufferWriteString(buffer, LOG_CF_STAR_SEPARATOR); + +/* Include */ +#include "suricata-common.h" +#include "util-buffer.h" + +typedef struct LogCustomFormatNode_ { + uint32_t type; /**< Node format type. ie: LOG_CF_LITERAL, ... */ + uint32_t maxlen; /**< Maximun length of the data */ + char data[LOG_NODE_STRLEN]; /**< optional data. ie: http header name */ +} LogCustomFormatNode; + + +typedef struct LogCustomFormat_ { + uint32_t cf_n; /**< Total number of custom string format nodes */ + LogCustomFormatNode *cf_nodes[LOG_MAXN_NODES]; /**< Custom format string nodes */ +} LogCustomFormat; + +LogCustomFormatNode * LogCustomFormatNodeAlloc(void); +LogCustomFormat * LogCustomFormatAlloc(void); + +void LogCustomFormatNodeFree(LogCustomFormatNode *node); +void LogCustomFormatFree(LogCustomFormat *cf); + +void LogCustomFormatAddNode(LogCustomFormat *cf, LogCustomFormatNode *node); +int LogCustomFormatParse(LogCustomFormat *cf, const char *format); + +void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const struct timeval *ts); +void LogCustomFormatRegister(void); + +#endif /* __LOG_CF_COMMON_H__ */ diff --git a/src/log-httplog.c b/src/log-httplog.c index a825ae40232f..a26a2f673023 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -49,6 +49,7 @@ #include "util-logopenfile.h" #include "util-time.h" +#include "log-cf-common.h" #define DEFAULT_LOG_FILENAME "http.log" @@ -69,13 +70,6 @@ void LogHttpLogRegister (void) LogHttpLogThreadDeinit, NULL); } -#define LOG_HTTP_MAXN_NODES 64 -#define LOG_HTTP_NODE_STRLEN 256 -#define LOG_HTTP_NODE_MAXOUTPUTLEN 8192 - -#define TIMESTAMP_DEFAULT_FORMAT "%b %d, %Y; %H:%M:%S" -#define LOG_HTTP_CF_NONE "-" -#define LOG_HTTP_CF_LITERAL '%' #define LOG_HTTP_CF_REQUEST_HOST 'h' #define LOG_HTTP_CF_REQUEST_PROTOCOL 'H' #define LOG_HTTP_CF_REQUEST_METHOD 'm' @@ -87,24 +81,12 @@ void LogHttpLogRegister (void) #define LOG_HTTP_CF_RESPONSE_STATUS 's' #define LOG_HTTP_CF_RESPONSE_HEADER 'o' #define LOG_HTTP_CF_RESPONSE_LEN 'B' -#define LOG_HTTP_CF_TIMESTAMP 't' -#define LOG_HTTP_CF_TIMESTAMP_U 'z' -#define LOG_HTTP_CF_CLIENT_IP 'a' -#define LOG_HTTP_CF_SERVER_IP 'A' -#define LOG_HTTP_CF_CLIENT_PORT 'p' -#define LOG_HTTP_CF_SERVER_PORT 'P' - -typedef struct LogHttpCustomFormatNode_ { - uint32_t type; /** Node format type. ie: LOG_HTTP_CF_LITERAL, LOG_HTTP_CF_REQUEST_HEADER */ - uint32_t maxlen; /** Maximun length of the data */ - char data[LOG_HTTP_NODE_STRLEN]; /** optional data. ie: http header name */ -} LogHttpCustomFormatNode; + typedef struct LogHttpFileCtx_ { LogFileCtx *file_ctx; uint32_t flags; /** Store mode */ - uint32_t cf_n; /** Total number of custom string format nodes */ - LogHttpCustomFormatNode *cf_nodes[LOG_HTTP_MAXN_NODES]; /** Custom format string nodes */ + LogCustomFormat *cf; } LogHttpFileCtx; #define LOG_HTTP_DEFAULT 0 @@ -160,49 +142,44 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t htp_header_t *h_request_hdr; htp_header_t *h_response_hdr; - time_t time = ts->tv_sec; - struct tm local_tm; - struct tm *timestamp = SCLocalTime(time, &local_tm); - - for (i = 0; i < httplog_ctx->cf_n; i++) { + for (i = 0; i < httplog_ctx->cf->cf_n; i++) { h_request_hdr = NULL; h_response_hdr = NULL; - switch (httplog_ctx->cf_nodes[i]->type){ - case LOG_HTTP_CF_LITERAL: + + LogCustomFormatNode * node = httplog_ctx->cf->cf_nodes[i]; + if (! node) /* Should never happen */ + continue; + + switch (node->type){ + case LOG_CF_LITERAL: /* LITERAL */ - MemBufferWriteString(aft->buffer, "%s", httplog_ctx->cf_nodes[i]->data); + MemBufferWriteString(aft->buffer, "%s", node->data); break; - case LOG_HTTP_CF_TIMESTAMP: + case LOG_CF_TIMESTAMP: /* TIMESTAMP */ - if (httplog_ctx->cf_nodes[i]->data[0] == '\0') { - strftime(buf, 62, TIMESTAMP_DEFAULT_FORMAT, timestamp); - } else { - strftime(buf, 62, httplog_ctx->cf_nodes[i]->data, timestamp); - } - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)buf,strlen(buf)); + LogCustomFormatWriteTimestamp(aft->buffer, node->data, ts); break; - case LOG_HTTP_CF_TIMESTAMP_U: + case LOG_CF_TIMESTAMP_U: /* TIMESTAMP USECONDS */ - snprintf(buf, 62, "%06u", (unsigned int) ts->tv_usec); + snprintf(buf, 6, "%06u", (unsigned int) ts->tv_usec); PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)buf,strlen(buf)); break; - case LOG_HTTP_CF_CLIENT_IP: + case LOG_CF_CLIENT_IP: /* CLIENT IP ADDRESS */ PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)srcip,strlen(srcip)); break; - case LOG_HTTP_CF_SERVER_IP: + case LOG_CF_SERVER_IP: /* SERVER IP ADDRESS */ PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)dstip,strlen(dstip)); break; - case LOG_HTTP_CF_CLIENT_PORT: + case LOG_CF_CLIENT_PORT: /* CLIENT PORT */ MemBufferWriteString(aft->buffer, "%" PRIu16 "", sp); break; - case LOG_HTTP_CF_SERVER_PORT: + case LOG_CF_SERVER_PORT: /* SERVER PORT */ MemBufferWriteString(aft->buffer, "%" PRIu16 "", dp); break; @@ -213,13 +190,13 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method)); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_URI: /* URI */ if (tx->request_uri != NULL) { - datalen = httplog_ctx->cf_nodes[i]->maxlen; + datalen = node->maxlen; if (datalen == 0 || datalen > bstr_len(tx->request_uri)) { datalen = bstr_len(tx->request_uri); } @@ -227,14 +204,14 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_uri), datalen); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_HOST: /* HOSTNAME */ if (tx->request_hostname != NULL) { - datalen = httplog_ctx->cf_nodes[i]->maxlen; + datalen = node->maxlen; if (datalen == 0 || datalen > bstr_len(tx->request_hostname)) { datalen = bstr_len(tx->request_hostname); } @@ -242,7 +219,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_hostname), datalen); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_PROTOCOL: @@ -252,16 +229,16 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_HEADER: /* REQUEST HEADER */ if (tx->request_headers != NULL) { - h_request_hdr = htp_table_get_c(tx->request_headers, httplog_ctx->cf_nodes[i]->data); + h_request_hdr = htp_table_get_c(tx->request_headers, node->data); } if (h_request_hdr != NULL) { - datalen = httplog_ctx->cf_nodes[i]->maxlen; + datalen = node->maxlen; if (datalen == 0 || datalen > bstr_len(h_request_hdr->value)) { datalen = bstr_len(h_request_hdr->value); } @@ -269,7 +246,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(h_request_hdr->value), datalen); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_COOKIE: @@ -278,19 +255,19 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t h_request_hdr = htp_table_get_c(tx->request_headers, "Cookie"); if (h_request_hdr != NULL) { cvalue_len = GetCookieValue((uint8_t *) bstr_ptr(h_request_hdr->value), - bstr_len(h_request_hdr->value), (char *) httplog_ctx->cf_nodes[i]->data, + bstr_len(h_request_hdr->value), (char *) node->data, &cvalue); } } if (cvalue_len > 0 && cvalue != NULL) { - datalen = httplog_ctx->cf_nodes[i]->maxlen; + datalen = node->maxlen; if (datalen == 0 || datalen > cvalue_len) { datalen = cvalue_len; } PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, cvalue, datalen); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_LEN: @@ -304,17 +281,17 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status)); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_RESPONSE_HEADER: /* RESPONSE HEADER */ if (tx->response_headers != NULL) { h_response_hdr = htp_table_get_c(tx->response_headers, - httplog_ctx->cf_nodes[i]->data); + node->data); } if (h_response_hdr != NULL) { - datalen = httplog_ctx->cf_nodes[i]->maxlen; + datalen = node->maxlen; if (datalen == 0 || datalen > bstr_len(h_response_hdr->value)) { datalen = bstr_len(h_response_hdr->value); } @@ -322,7 +299,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(h_response_hdr->value), datalen); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_RESPONSE_LEN: @@ -331,8 +308,8 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t break; default: /* NO MATCH */ - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); - SCLogDebug("No matching parameter %%%c for custom http log.", httplog_ctx->cf_nodes[i]->type); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + SCLogDebug("No matching parameter %%%c for custom http log.", node->type); break; } } @@ -341,7 +318,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) { - MemBufferWriteString(aft->buffer, " [**] "); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* referer */ htp_header_t *h_referer = NULL; @@ -355,7 +332,8 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) } else { MemBufferWriteString(aft->buffer, ""); } - MemBufferWriteString(aft->buffer, " [**] "); + + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* method */ if (tx->request_method != NULL) { @@ -363,7 +341,7 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method)); } - MemBufferWriteString(aft->buffer, " [**] "); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* protocol */ if (tx->request_protocol != NULL) { @@ -373,7 +351,7 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) } else { MemBufferWriteString(aft->buffer, ""); } - MemBufferWriteString(aft->buffer, " [**] "); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* response status */ if (tx->response_status != NULL) { @@ -396,7 +374,8 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) } /* length */ - MemBufferWriteString(aft->buffer, " [**] %"PRIuMAX" bytes", (uintmax_t)tx->response_message_len); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); + MemBufferWriteString(aft->buffer, "%"PRIuMAX" bytes", (uintmax_t)tx->response_message_len); } static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, Flow *f, HtpState *htp_state, htp_tx_t *tx, uint64_t tx_id, int ipproto) @@ -463,7 +442,7 @@ static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, } else { MemBufferWriteString(aft->buffer, ""); } - MemBufferWriteString(aft->buffer, " [**] "); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* uri */ if (tx->request_uri != NULL) { @@ -471,7 +450,7 @@ static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); } - MemBufferWriteString(aft->buffer, " [**] "); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* user agent */ htp_header_t *h_user_agent = NULL; @@ -490,8 +469,9 @@ static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, } /* ip/tcp header info */ + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); MemBufferWriteString(aft->buffer, - " [**] %s:%" PRIu16 " -> %s:%" PRIu16 "\n", + "%s:%" PRIu16 " -> %s:%" PRIu16 "\n", srcip, sp, dstip, dp); } @@ -572,8 +552,6 @@ TmEcode LogHttpLogThreadDeinit(ThreadVars *t, void *data) OutputCtx *LogHttpLogInitCtx(ConfNode *conf) { LogFileCtx* file_ctx = LogFileNewCtx(); - const char *p, *np; - uint32_t n; if(file_ctx == NULL) { SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; @@ -592,7 +570,6 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf) memset(httplog_ctx, 0x00, sizeof(LogHttpFileCtx)); httplog_ctx->file_ctx = file_ctx; - httplog_ctx->cf_n=0; const char *extended = ConfNodeLookupChildValue(conf, "extended"); const char *custom = ConfNodeLookupChildValue(conf, "custom"); @@ -600,74 +577,17 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf) /* If custom logging format is selected, lets parse it */ if (custom != NULL && customformat != NULL && ConfValIsTrue(custom)) { - p=customformat; + + httplog_ctx->cf = LogCustomFormatAlloc(); + if (!httplog_ctx->cf) { + goto errorfree; + } + httplog_ctx->flags |= LOG_HTTP_CUSTOM; - for (httplog_ctx->cf_n = 0; httplog_ctx->cf_n < LOG_HTTP_MAXN_NODES-1 && p && *p != '\0'; - httplog_ctx->cf_n++){ - httplog_ctx->cf_nodes[httplog_ctx->cf_n] = SCMalloc(sizeof(LogHttpCustomFormatNode)); - if (httplog_ctx->cf_nodes[httplog_ctx->cf_n] == NULL) { - for (n = 0; n < httplog_ctx->cf_n; n++) { - SCFree(httplog_ctx->cf_nodes[n]); - } - LogFileFreeCtx(file_ctx); - SCFree(httplog_ctx); - return NULL; - } - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->maxlen = 0; - - if (*p != '%'){ - /* Literal found in format string */ - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = LOG_HTTP_CF_LITERAL; - np = strchr(p, '%'); - if (np == NULL){ - n = LOG_HTTP_NODE_STRLEN-2; - np = NULL; /* End */ - }else{ - n = np-p; - } - strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data,p,n+1); - p = np; - } else { - /* Non Literal found in format string */ - p++; - if (*p == '[') { /* Check if maxlength has been specified (ie: [25]) */ - p++; - np = strchr(p, ']'); - if (np != NULL) { - if (np-p > 0 && np-p < 10){ - long maxlen = strtol(p,NULL,10); - if (maxlen > 0 && maxlen < LOG_HTTP_NODE_MAXOUTPUTLEN) { - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->maxlen = (uint32_t) maxlen; - } - } else { - goto parsererror; - } - p = np + 1; - } else { - goto parsererror; - } - } - if (*p == '{') { /* Simple format char */ - np = strchr(p, '}'); - if (np != NULL && np-p > 1 && np-p < LOG_HTTP_NODE_STRLEN-2) { - p++; - n = np-p; - strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data, p, n+1); - p = np; - } else { - goto parsererror; - } - p++; - } else { - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data[0] = '\0'; - } - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = *p; - if (*p == '%'){ - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = LOG_HTTP_CF_LITERAL; - strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data, "%", 2); - } - p++; - } + + /* Parsing */ + if ( ! LogCustomFormatParse(httplog_ctx->cf, customformat)) { + goto parsererror; } } else { if (extended == NULL) { @@ -695,12 +615,11 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf) return output_ctx; parsererror: - for (n = 0;n < httplog_ctx->cf_n;n++) { - SCFree(httplog_ctx->cf_nodes[n]); - } + SCLogError(SC_ERR_INVALID_ARGUMENT,"Syntax error in custom http log format string."); +errorfree: + LogCustomFormatFree(httplog_ctx->cf); LogFileFreeCtx(file_ctx); SCFree(httplog_ctx); - SCLogError(SC_ERR_INVALID_ARGUMENT,"Syntax error in custom http log format string."); return NULL; } @@ -708,10 +627,7 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf) static void LogHttpLogDeInitCtx(OutputCtx *output_ctx) { LogHttpFileCtx *httplog_ctx = (LogHttpFileCtx *)output_ctx->data; - uint32_t i; - for (i = 0; i < httplog_ctx->cf_n; i++) { - SCFree(httplog_ctx->cf_nodes[i]); - } + LogCustomFormatFree(httplog_ctx->cf); LogFileFreeCtx(httplog_ctx->file_ctx); SCFree(httplog_ctx); SCFree(output_ctx); diff --git a/src/output.c b/src/output.c index 3c509f266246..6ee3dc15cbaa 100644 --- a/src/output.c +++ b/src/output.c @@ -48,6 +48,7 @@ #include "output-json-alert.h" #include "output-json-flow.h" #include "output-json-netflow.h" +#include "log-cf-common.h" #include "log-droplog.h" #include "output-json-drop.h" #include "log-httplog.h" @@ -1025,6 +1026,9 @@ void OutputRegisterRootLoggers(void) */ void OutputRegisterLoggers(void) { + /* custom format log*/ + LogCustomFormatRegister(); + LuaLogRegister(); /* fast log */ AlertFastLogRegister(); diff --git a/src/util-error.c b/src/util-error.c index 197255bd3126..7b7aa7afc352 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -338,6 +338,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_REDIS); CASE_CODE (SC_ERR_VAR_LIMIT); CASE_CODE (SC_WARN_CHMOD); + CASE_CODE (SC_WARN_LOG_CF_TOO_MANY_NODES); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 186133fa30a7..85e174abbe07 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -328,6 +328,7 @@ typedef enum { SC_ERR_VAR_LIMIT, SC_WARN_DUPLICATE_OUTPUT, SC_WARN_CHMOD, + SC_WARN_LOG_CF_TOO_MANY_NODES, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-time.c b/src/util-time.c index b1726e81c578..0dd00953a1ca 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -208,6 +208,15 @@ void CreateUtcIsoTimeString (const struct timeval *ts, char *str, size_t size) } } +void CreateFormattedTimeString (const struct tm *t, const char *fmt, char *str, size_t size) +{ + if (likely(t != NULL) && likely(fmt != NULL) && likely(str != NULL) ) { + strftime(str, size, fmt, t); + } else { + snprintf(str, size, "ts-error"); + } +} + struct tm *SCUtcTime(time_t timep, struct tm *result) { return gmtime_r(&timep, result); diff --git a/src/util-time.h b/src/util-time.h index fa71cf565b4b..3d76642210c1 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -51,11 +51,12 @@ void TimeModeSetOffline (void); int TimeModeIsLive(void); struct tm *SCLocalTime(time_t timep, struct tm *result); -void CreateTimeString (const struct timeval *ts, char *str, size_t size); -void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size); -void CreateUtcIsoTimeString (const struct timeval *ts, char *str, size_t size); -time_t SCMkTimeUtc (struct tm *tp); -int SCStringPatternToTime (char *string, char **patterns, +void CreateTimeString(const struct timeval *ts, char *str, size_t size); +void CreateIsoTimeString(const struct timeval *ts, char *str, size_t size); +void CreateUtcIsoTimeString(const struct timeval *ts, char *str, size_t size); +void CreateFormattedTimeString(const struct tm *t, const char * fmt, char *str, size_t size); +time_t SCMkTimeUtc(struct tm *tp); +int SCStringPatternToTime(char *string, char **patterns, int num_patterns, struct tm *time); #endif /* __UTIL_TIME_H__ */ From 20d4d400518347407a9c8e05cbda42734300cfb0 Mon Sep 17 00:00:00 2001 From: fooinha Date: Sat, 3 Dec 2016 19:26:16 +0000 Subject: [PATCH 2531/2553] log: tls custom format log --- doc/userguide/output/custom-tls-logging.rst | 43 ++++ doc/userguide/output/index.rst | 1 + src/log-cf-common.c | 13 +- src/log-cf-common.h | 9 + src/log-tlslog.c | 255 ++++++++++++++++---- src/util-time.c | 2 +- suricata.yaml.in | 4 +- 7 files changed, 266 insertions(+), 61 deletions(-) create mode 100644 doc/userguide/output/custom-tls-logging.rst diff --git a/doc/userguide/output/custom-tls-logging.rst b/doc/userguide/output/custom-tls-logging.rst new file mode 100644 index 000000000000..b7031e9073db --- /dev/null +++ b/doc/userguide/output/custom-tls-logging.rst @@ -0,0 +1,43 @@ +Custom tls logging +=================== + +In your Suricata.yaml, find the tls-log section and edit as follows: + +:: + + + - tls-log: + enabled: yes # Log TLS connections. + filename: tls.log # File to store TLS logs. + append: yes + custom: yes # enabled the custom logging format (defined by customformat) + customformat: "%{%D-%H:%M:%S}t.%z %a:%p -> %A:%P %n %n %d %D" + +And in your tls.log file you would get the following, for example: + +:: + + 12/03/16-19:20:14.85859 10.10.10.4:58274 -> 192.0.78.24:443 VERSION='TLS 1.2' suricata-ids.org NOTBEFORE='2016-10-27T20:36:00' NOTAFTER='2017-01-25T20:36:00' + +:: + 12/03/16-19:20:20.36849 10.10.10.4:39472 -> 192.30.253.113:443 VERSION='TLS 1.2' github.com NOTBEFORE='2016-03-10T00:00:00' NOTAFTER='2018-05-17T12:00:00' + + +The list of supported format strings is the following: + +* %n - client SNI +* %v - TLS/SSL version +* %d - certificate date not before +* %D - certificate date not after +* %f - certificate fingerprint SHA1 +* %s - certificate subject +* %i - certificate issuer dn +* %E - extended format +* %{strftime_format}t - timestamp of the TLS transaction in the selected strftime format. ie: 08/28/12-22:14:30 +* %z - precision time in useconds. ie: 693856 +* %a - client IP address +* %p - client port number +* %A - server IP address +* %P - server port number + +Any non printable character will be represented by its byte value in hexadecimal format (\|XX\|, where XX is the hex code) diff --git a/doc/userguide/output/index.rst b/doc/userguide/output/index.rst index e0738e01f3f0..3c1666c100c1 100644 --- a/doc/userguide/output/index.rst +++ b/doc/userguide/output/index.rst @@ -7,3 +7,4 @@ Output lua-output syslog-alerting-comp custom-http-logging + custom-tls-logging diff --git a/src/log-cf-common.c b/src/log-cf-common.c index c85703f8afa4..9a4efb3219c4 100644 --- a/src/log-cf-common.c +++ b/src/log-cf-common.c @@ -36,14 +36,11 @@ */ LogCustomFormatNode * LogCustomFormatNodeAlloc() { - LogCustomFormatNode * node = SCMalloc(sizeof(LogCustomFormatNode)); + LogCustomFormatNode * node = SCCalloc(1, sizeof(LogCustomFormatNode)); if (unlikely(node == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to alloc custom format node"); return NULL; } - memset(node, '\0', sizeof(LogCustomFormatNode)); - memset(node->data, '\0', LOG_NODE_STRLEN); - return node; } @@ -54,13 +51,11 @@ LogCustomFormatNode * LogCustomFormatNodeAlloc() */ LogCustomFormat * LogCustomFormatAlloc() { - LogCustomFormat * cf = SCMalloc(sizeof(LogCustomFormat)); + LogCustomFormat * cf = SCCalloc(1, sizeof(LogCustomFormat)); if (unlikely(cf == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to alloc custom format"); return NULL; } - memset(cf, '\0', sizeof(LogCustomFormat)); - return cf; } @@ -172,14 +167,12 @@ int LogCustomFormatParse(LogCustomFormat *cf, const char *format) p++; } LogCustomFormatAddNode(cf, node); - } return 1; parsererror: LogCustomFormatNodeFree(node); return 0; - } /** @@ -230,7 +223,6 @@ void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const str buffer->size, (uint8_t *)buf,strlen(buf)); } - #ifdef UNITTESTS /** * \internal @@ -238,7 +230,6 @@ void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const str */ static int LogCustomFormatTest01(void) { - struct tm tm; tm.tm_sec = 0; tm.tm_min = 30; diff --git a/src/log-cf-common.h b/src/log-cf-common.h index ad66754830e8..f871a3de35d2 100644 --- a/src/log-cf-common.h +++ b/src/log-cf-common.h @@ -47,9 +47,18 @@ /* Line log common separators **/ #define LOG_CF_STAR_SEPARATOR "[**]" +#define LOG_CF_SPACE_SEPARATOR " " +#define LOG_CF_UNKNOWN_VALUE "-" + #define LOG_CF_WRITE_STAR_SEPATATOR(buffer) \ MemBufferWriteString(buffer, LOG_CF_STAR_SEPARATOR); +#define LOG_CF_WRITE_SPACE_SEPARATOR(buffer) \ + MemBufferWriteString(buffer, LOG_CF_SPACE_SEPARATOR); + +#define LOG_CF_WRITE_UNKNOWN_VALUE(buffer) \ + MemBufferWriteString(buffer, LOG_CF_UNKNOWN_VALUE); + /* Include */ #include "suricata-common.h" #include "util-buffer.h" diff --git a/src/log-tlslog.c b/src/log-tlslog.c index 9e70149f03f8..97158b9daf12 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -21,6 +21,7 @@ * \author Roliers Jean-Paul * \author Eric Leblond * \author Victor Julien + * \author Paulo Pacheco * * Implements TLS logging portion of the engine. The TLS logger is * implemented as a packet logger, as the TLS parser is not transaction @@ -53,6 +54,7 @@ #include "util-logopenfile.h" #include "util-crypt.h" #include "util-time.h" +#include "log-cf-common.h" #define DEFAULT_LOG_FILENAME "tls.log" @@ -63,10 +65,21 @@ #define LOG_TLS_DEFAULT 0 #define LOG_TLS_EXTENDED 1 +#define LOG_TLS_CUSTOM 2 + +#define LOG_TLS_CF_VERSION 'v' +#define LOG_TLS_CF_DATE_NOT_BEFORE 'd' +#define LOG_TLS_CF_DATE_NOT_AFTER 'D' +#define LOG_TLS_CF_SHA1 'f' +#define LOG_TLS_CF_SNI 'n' +#define LOG_TLS_CF_SUBJECT 's' +#define LOG_TLS_CF_ISSUER 'i' +#define LOG_TLS_CF_EXTENDED 'E' typedef struct LogTlsFileCtx_ { LogFileCtx *file_ctx; uint32_t flags; /** Store mode */ + LogCustomFormat *cf; } LogTlsFileCtx; typedef struct LogTlsLogThread_ { @@ -78,58 +91,74 @@ typedef struct LogTlsLogThread_ { MemBuffer *buffer; } LogTlsLogThread; -static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state) +static void LogTlsLogVersion(MemBuffer *buffer, uint16_t version) { - if (state->server_connp.cert0_fingerprint != NULL) { - MemBufferWriteString(aft->buffer, " SHA1='%s'", state->server_connp.cert0_fingerprint); - } - if (state->client_connp.sni != NULL) { - MemBufferWriteString(aft->buffer, " SNI='%s'", state->client_connp.sni); - } - if (state->server_connp.cert0_serial != NULL) { - MemBufferWriteString(aft->buffer, " SERIAL='%s'", state->server_connp.cert0_serial); - } - switch (state->server_connp.version) { + switch (version) { case TLS_VERSION_UNKNOWN: - MemBufferWriteString(aft->buffer, " VERSION='UNDETERMINED'"); + MemBufferWriteString(buffer, "VERSION='UNDETERMINED'"); break; case SSL_VERSION_2: - MemBufferWriteString(aft->buffer, " VERSION='SSLv2'"); + MemBufferWriteString(buffer, "VERSION='SSLv2'"); break; case SSL_VERSION_3: - MemBufferWriteString(aft->buffer, " VERSION='SSLv3'"); + MemBufferWriteString(buffer, "VERSION='SSLv3'"); break; case TLS_VERSION_10: - MemBufferWriteString(aft->buffer, " VERSION='TLSv1'"); + MemBufferWriteString(buffer, "VERSION='TLSv1'"); break; case TLS_VERSION_11: - MemBufferWriteString(aft->buffer, " VERSION='TLS 1.1'"); + MemBufferWriteString(buffer, "VERSION='TLS 1.1'"); break; case TLS_VERSION_12: - MemBufferWriteString(aft->buffer, " VERSION='TLS 1.2'"); + MemBufferWriteString(buffer, "VERSION='TLS 1.2'"); break; default: - MemBufferWriteString(aft->buffer, " VERSION='0x%04x'", - state->server_connp.version); + MemBufferWriteString(buffer, "VERSION='0x%04x'", version); break; } +} + +static void LogTlsLogDate(MemBuffer *buffer, const char *title, time_t *date) +{ + char timebuf[64] = {0}; + struct timeval tv; + tv.tv_sec = *date; + tv.tv_usec = 0; + CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); + MemBufferWriteString(buffer, "%s='%s'", title, timebuf); +} + +static void LogTlsLogString(MemBuffer *buffer, const char *title, const char *value) +{ + MemBufferWriteString(buffer, "%s='%s'", title, value); +} + +static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state) +{ + if (state->server_connp.cert0_fingerprint != NULL) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogString(aft->buffer, "SHA1", state->server_connp.cert0_fingerprint); + } + if (state->client_connp.sni != NULL) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogString(aft->buffer, "SNI", state->client_connp.sni); + } + if (state->server_connp.cert0_serial != NULL) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogString(aft->buffer, "SERIAL", state->server_connp.cert0_serial); + } + + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogVersion(aft->buffer, state->server_connp.version); + if (state->server_connp.cert0_not_before != 0) { - char timebuf[64]; - struct timeval tv; - tv.tv_sec = state->server_connp.cert0_not_before; - tv.tv_usec = 0; - CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); - MemBufferWriteString(aft->buffer, " NOTBEFORE='%s'", timebuf); + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogDate(aft->buffer, "NOTBEFORE", &state->server_connp.cert0_not_before); } if (state->server_connp.cert0_not_after != 0) { - char timebuf[64]; - struct timeval tv; - tv.tv_sec = state->server_connp.cert0_not_after; - tv.tv_usec = 0; - CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); - MemBufferWriteString(aft->buffer, " NOTAFTER='%s'", timebuf); + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogDate(aft->buffer, "NOTAFTER", &state->server_connp.cert0_not_after); } - MemBufferWriteString(aft->buffer, "\n"); } int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len, @@ -215,6 +244,7 @@ static void LogTlsLogDeInitCtx(OutputCtx *output_ctx) { LogTlsFileCtx *tlslog_ctx = (LogTlsFileCtx *) output_ctx->data; LogFileFreeCtx(tlslog_ctx->file_ctx); + LogCustomFormatFree(tlslog_ctx->cf); SCFree(tlslog_ctx); SCFree(output_ctx); } @@ -253,11 +283,28 @@ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf) tlslog_ctx->file_ctx = file_ctx; const char *extended = ConfNodeLookupChildValue(conf, "extended"); - if (extended == NULL) { - tlslog_ctx->flags |= LOG_TLS_DEFAULT; + const char *custom = ConfNodeLookupChildValue(conf, "custom"); + const char *customformat = ConfNodeLookupChildValue(conf, "customformat"); + + /* If custom logging format is selected, lets parse it */ + if (custom != NULL && customformat != NULL && ConfValIsTrue(custom)) { + tlslog_ctx->cf = LogCustomFormatAlloc(); + if (!tlslog_ctx->cf) { + goto tlslog_error; + } + + tlslog_ctx->flags |= LOG_TLS_CUSTOM; + /* Parsing */ + if ( ! LogCustomFormatParse(tlslog_ctx->cf, customformat)) { + goto parser_error; + } } else { - if (ConfValIsTrue(extended)) { - tlslog_ctx->flags |= LOG_TLS_EXTENDED; + if (extended == NULL) { + tlslog_ctx->flags |= LOG_TLS_DEFAULT; + } else { + if (ConfValIsTrue(extended)) { + tlslog_ctx->flags |= LOG_TLS_EXTENDED; + } } } @@ -273,14 +320,119 @@ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf) AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); return output_ctx; - +parser_error: + SCLogError(SC_ERR_INVALID_ARGUMENT,"Syntax error in custom tls log format string."); tlslog_error: + LogCustomFormatFree(tlslog_ctx->cf); SCFree(tlslog_ctx); filectx_error: LogFileFreeCtx(file_ctx); return NULL; } +/* Custom format logging */ +static void LogTlsLogCustom(LogTlsLogThread *aft, SSLState *ssl_state, const struct timeval *ts, + char *srcip, Port sp, char *dstip, Port dp) +{ + LogTlsFileCtx *tlslog_ctx = aft->tlslog_ctx; + uint32_t i; + char buf[6]; + + for (i = 0; i < tlslog_ctx->cf->cf_n; i++) { + + LogCustomFormatNode * node = tlslog_ctx->cf->cf_nodes[i]; + if (! node) /* Should never happen */ + continue; + + switch (node->type){ + case LOG_CF_LITERAL: + /* LITERAL */ + MemBufferWriteString(aft->buffer, "%s", node->data); + break; + case LOG_CF_TIMESTAMP: + /* TIMESTAMP */ + LogCustomFormatWriteTimestamp(aft->buffer, node->data, ts); + break; + case LOG_CF_TIMESTAMP_U: + /* TIMESTAMP USECONDS */ + snprintf(buf, 6, "%06u", (unsigned int) ts->tv_usec); + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)buf,strlen(buf)); + break; + case LOG_CF_CLIENT_IP: + /* CLIENT IP ADDRESS */ + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)srcip,strlen(srcip)); + break; + case LOG_CF_SERVER_IP: + /* SERVER IP ADDRESS */ + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)dstip,strlen(dstip)); + break; + case LOG_CF_CLIENT_PORT: + /* CLIENT PORT */ + MemBufferWriteString(aft->buffer, "%" PRIu16 "", sp); + break; + case LOG_CF_SERVER_PORT: + /* SERVER PORT */ + MemBufferWriteString(aft->buffer, "%" PRIu16 "", dp); + break; + case LOG_TLS_CF_VERSION: + LogTlsLogVersion(aft->buffer, ssl_state->server_connp.version); + break; + case LOG_TLS_CF_DATE_NOT_BEFORE: + LogTlsLogDate(aft->buffer, "NOTBEFORE", &ssl_state->server_connp.cert0_not_before); + break; + case LOG_TLS_CF_DATE_NOT_AFTER: + LogTlsLogDate(aft->buffer, "NOTAFTER", &ssl_state->server_connp.cert0_not_after); + break; + case LOG_TLS_CF_SHA1: + if (ssl_state->server_connp.cert0_fingerprint != NULL) { + MemBufferWriteString(aft->buffer, "%s", + ssl_state->server_connp.cert0_fingerprint); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_SNI: + if (ssl_state->client_connp.sni != NULL) { + MemBufferWriteString(aft->buffer, "%s", + ssl_state->client_connp.sni); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_SUBJECT: + if (ssl_state->server_connp.cert0_subject != NULL) { + MemBufferWriteString(aft->buffer, "%s", + ssl_state->server_connp.cert0_subject); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_ISSUER: + if (ssl_state->server_connp.cert0_issuerdn != NULL) { + MemBufferWriteString(aft->buffer, "%s", + ssl_state->server_connp.cert0_issuerdn); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_EXTENDED: + /* Extended format */ + LogTlsLogExtended(aft, ssl_state); + break; + default: + /* NO MATCH */ + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + SCLogDebug("No matching parameter %%%c for custom tls log.", node->type); + break; + } + } + MemBufferWriteString(aft->buffer, "\n"); +} + + static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) { @@ -299,7 +451,6 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, return 0; } - CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); #define PRINT_BUF_LEN 46 char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; Port sp, dp; @@ -308,17 +459,25 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, return 0; } - MemBufferReset(aft->buffer); - MemBufferWriteString(aft->buffer, - "%s %s:%d -> %s:%d TLS: Subject='%s' Issuerdn='%s'", - timebuf, srcip, sp, dstip, dp, - ssl_state->server_connp.cert0_subject, - ssl_state->server_connp.cert0_issuerdn); - - if (hlog->flags & LOG_TLS_EXTENDED) { - LogTlsLogExtended(aft, ssl_state); + /* Custom format */ + if (hlog->flags & LOG_TLS_CUSTOM) { + LogTlsLogCustom(aft, ssl_state, &p->ts, srcip, sp, dstip, dp); } else { - MemBufferWriteString(aft->buffer, "\n"); + + MemBufferReset(aft->buffer); + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + MemBufferWriteString(aft->buffer, + "%s %s:%d -> %s:%d TLS: Subject='%s' Issuerdn='%s'", + timebuf, srcip, sp, dstip, dp, + ssl_state->server_connp.cert0_subject, + ssl_state->server_connp.cert0_issuerdn); + + if (hlog->flags & LOG_TLS_EXTENDED) { + LogTlsLogExtended(aft, ssl_state); + MemBufferWriteString(aft->buffer, "\n"); + } else { + MemBufferWriteString(aft->buffer, "\n"); + } } aft->tls_cnt++; diff --git a/src/util-time.c b/src/util-time.c index 0dd00953a1ca..b8f646f9ee63 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -210,7 +210,7 @@ void CreateUtcIsoTimeString (const struct timeval *ts, char *str, size_t size) void CreateFormattedTimeString (const struct tm *t, const char *fmt, char *str, size_t size) { - if (likely(t != NULL) && likely(fmt != NULL) && likely(str != NULL) ) { + if (likely(t != NULL && fmt != NULL && str != NULL)) { strftime(str, size, fmt, t); } else { snprintf(str, size, "ts-error"); diff --git a/suricata.yaml.in b/suricata.yaml.in index a91d1fe85efb..df5b146af5d8 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -301,8 +301,10 @@ outputs: enabled: no # Log TLS connections. filename: tls.log # File to store TLS logs. append: yes + #extended: yes # Log extended information like fingerprint + #custom: yes # enabled the custom logging format (defined by customformat) + #customformat: "%{%D-%H:%M:%S}t.%z %a:%p -> %A:%P %v %n %d %D" #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' - #extended: yes # Log extended information like fingerprint # output module to store certificates chain to disk - tls-store: From ff30d924db83734e395c946b84289e30f1e03d49 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 4 Apr 2017 07:51:19 -0600 Subject: [PATCH 2532/2553] unix-socket: return failure on failure UnixManagerThreadInit needs to return a failure code if the socket fails to initialize to avoid entering the UnixManager loop which will continuously fail on the call to bind, as no listening socket was setup. This can occur when the socket fails to initialize due to a permissions error and fatal init errors is not on. --- src/unix-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix-manager.c b/src/unix-manager.c index 702b63d46fdb..5f9a0e49fb09 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -914,7 +914,7 @@ static TmEcode UnixManagerThreadInit(ThreadVars *t, void *initdata, void **data) } else { SCLogWarning(SC_ERR_INITIALIZATION, "Unable to create unix command socket"); - return TM_ECODE_OK; + return TM_ECODE_FAILED; } } From 00cd47b2bf16625346a5681e527cb02a5a752df4 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 29 Mar 2017 14:09:32 -0600 Subject: [PATCH 2533/2553] travis: use new container build infrastructure Migrate to the new Travis container build system. This build system does not allow use of sudo, so required packages must be done declaratively which required reworking how we install packages that are conditional based on the build being done. Mac builds are still done with sudo=true. --- .travis.yml | 124 +++++++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 55 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5af6abf23407..0194a079211b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,29 +1,59 @@ -# Default parameters, even this default build is excluded in the build -# matrix below. We define so Travis doesn't think this is a Ruby -# project. -os: linux +sudo: false language: c -compiler: gcc + +addons: + apt: + # Define the required packages without libjansson so we can do a + # build without libjansson. + packages-without-jansson: &packages-without-jansson + - libpcre3 + - libpcre3-dbg + - libpcre3-dev + - build-essential + - autoconf + - automake + - libtool + - libpcap-dev + - libnet1-dev + - libyaml-0-2 + - libyaml-dev + - zlib1g + - zlib1g-dev + - libcap-ng-dev + - libcap-ng0 + - make + - libmagic-dev + - libnetfilter-queue-dev + - libnetfilter-queue1 + - libnfnetlink-dev + - libnfnetlink0 + - libhiredis-dev + - libjansson-dev + # Now define the default set of packages which is those above, and + # libjansson. + packages: &packages + - *packages-without-jansson + - libjansson-dev # Define the default CFLAGS used by all builds as a YAML anchor. default-cflags: &default-cflags CFLAGS="-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function" -# The default build is Linux with gcc. Add additional builds to the -# matrix here. matrix: - # Exclude the default build so any the builds in the matrix will be done. - exclude: - - os: linux - compiler: gcc include: - # Linux, gcc, cocci tests enabled. + # Linux, gcc, coccinelle. - os: linux compiler: gcc env: - NAME="linux,gcc,cocci" - *default-cflags - - ENABLE_COCCI="yes" + addons: + apt: + sources: + - sourceline: ppa:npalix/coccinelle + packages: + - *packages + - coccinelle # Linux, gcc, -DNDEBUG. - os: linux compiler: gcc @@ -53,24 +83,27 @@ matrix: - *default-cflags - ARGS="--enable-debug" - ENABLE_DEBUG="yes" - # Linux, gcc, no json support. + # Linux, gcc, no jansson. - os: linux compiler: gcc env: - NAME="linux,gcc,no-json" - *default-cflags - - DISABLE_JSON="yes" - # OSX 10.12, XCode 8.1. + addons: + apt: + packages: + - *packages-without-jansson + # OSX 10.12, XCode 8.1 - os: osx compiler: gcc osx_image: xcode8.1 + sudo: true env: - NAME="osx,gcc" - *default-cflags -# Change this to your needs script: - - sh autogen.sh + - sh ./autogen.sh - | if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CFLAGS="${CFLAGS} ${EXTRA_CFLAGS}" @@ -88,41 +121,20 @@ script: --with-libnspr-includes=/usr/local/opt/nspr/include/nspr \ --with-libnspr-libraries=/usr/local/opt/nspr/lib fi - - make # With debug enabled too much output is generated for Travis, so # redirect stderr to a file. - | + # Linux container builds have 2 cores, make use of them. + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + j="-j 2" + fi if [[ "$ENABLE_DEBUG" == "yes" ]]; then - make check 2> stderr.log + make ${j} check 2> stderr.log else - make check + make ${j} check fi -before_install: - - | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - - if [[ "$ENABLE_COCCI" == "yes" ]]; then - sudo add-apt-repository -y ppa:npalix/coccinelle - fi - sudo apt-get update -qq - sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev \ - build-essential autoconf automake libtool libpcap-dev libnet1-dev \ - libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev \ - libcap-ng0 make libmagic-dev libnetfilter-queue-dev \ - libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 \ - libhiredis-dev - - - if [[ "$ENABLE_COCCI" == "yes" ]]; then - sudo apt-get install -y coccinelle - fi - - if [[ "$DISABLE_JSON" != "yes" ]]; then - sudo apt-get install -y libjansson-dev - fi - - fi +before_install: - | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update @@ -130,7 +142,17 @@ before_install: # Unlink and install each dependency to avoid errors where a # formula might already be installed but is not the current # version. - packages="pkg-config libmagic libyaml nss nspr jansson libnet lua pcre hiredis" + packages="" + packages="$packages pkg-config" + packages="$packages libmagic" + packages="$packages libyaml" + packages="$packages nss" + packages="$packages nspr" + packages="$packages jansson" + packages="$packages libnet" + packages="$packages lua" + packages="$packages pcre" + packages="$packages hiredis" for package in $packages; do if brew ls $package --versions > /dev/null; then brew unlink $package @@ -143,13 +165,5 @@ before_install: # Now relink, becuase if a newer version of a package wasn't # installed above, it will remain unlinked. brew link $packages - - # Unlink pcre in case its already installed. - # brew unlink pcre || true - # brew unlink pkg-config || true - - # brew install pkg-config libmagic libyaml nss nspr jansson libnet lua \ - # pcre hiredis fi - ./qa/travis-libhtp.sh - From ca92be896eb51634d1165be30de5e7b6aa5ef4ff Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Sun, 5 Mar 2017 21:17:47 -0600 Subject: [PATCH 2534/2553] defrag: use new unit test macros Also reformat unit test functions to Suricata style. --- src/defrag.c | 700 ++++++++++++++++----------------------------------- 1 file changed, 222 insertions(+), 478 deletions(-) diff --git a/src/defrag.c b/src/defrag.c index 5245f43d6547..94234073e140 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -995,9 +995,8 @@ void DefragDestroy(void) * Allocate a test packet. Nothing to fancy, just a simple IP packet * with some payload of no particular protocol. */ -static Packet * -BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf, - const char content, int content_len) +static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf, + const char content, int content_len) { Packet *p = NULL; int hlen = 20; @@ -1017,7 +1016,6 @@ BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf, ip4h.ip_verhl |= hlen >> 2; ip4h.ip_len = htons(hlen + content_len); ip4h.ip_id = htons(id); - ip4h.ip_off = htons(off); if (mf) ip4h.ip_off = htons(IP_MF | off); else @@ -1073,9 +1071,8 @@ void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, uint16_t hdrextlen, uint16_t plen, uint16_t prev_hdrextlen); -static Packet * -IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off, int mf, - const char content, int content_len) +static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off, + int mf, const char content, int content_len) { Packet *p = NULL; uint8_t *pcontent; @@ -1138,7 +1135,6 @@ IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off, int mf, return p; error: - fprintf(stderr, "Error building test packet.\n"); if (p != NULL) SCFree(p); return NULL; @@ -1148,294 +1144,212 @@ IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off, int mf, * Test the simplest possible re-assembly scenario. All packet in * order and no overlaps. */ -static int -DefragInOrderSimpleTest(void) +static int DefragInOrderSimpleTest(void) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; - int ret = 0; DefragInit(); p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; + FAIL_IF_NULL(p1); p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8); - if (p2 == NULL) - goto end; + FAIL_IF_NULL(p2); p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3); - if (p3 == NULL) - goto end; + FAIL_IF_NULL(p3); - if (Defrag(NULL, NULL, p1, NULL) != NULL) - goto end; - if (Defrag(NULL, NULL, p2, NULL) != NULL) - goto end; + FAIL_IF(Defrag(NULL, NULL, p1, NULL) != NULL); + FAIL_IF(Defrag(NULL, NULL, p2, NULL) != NULL); reassembled = Defrag(NULL, NULL, p3, NULL); - if (reassembled == NULL) { - goto end; - } + FAIL_IF_NULL(reassembled); - if (IPV4_GET_HLEN(reassembled) != 20) { - goto end; - } - if (IPV4_GET_IPLEN(reassembled) != 39) { - goto end; - } + FAIL_IF(IPV4_GET_HLEN(reassembled) != 20); + FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39); /* 20 bytes in we should find 8 bytes of A. */ for (i = 20; i < 20 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'A') { - goto end; - } + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A'); } /* 28 bytes in we should find 8 bytes of B. */ for (i = 28; i < 28 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'B') { - goto end; - } + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B'); } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 36; i < 36 + 3; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'C') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C'); } - ret = 1; - -end: - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); - if (p3 != NULL) - SCFree(p3); - if (reassembled != NULL) - SCFree(reassembled); + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(reassembled); DefragDestroy(); - return ret; + PASS; } /** * Simple fragmented packet in reverse order. */ -static int -DefragReverseSimpleTest(void) +static int DefragReverseSimpleTest(void) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; - int ret = 0; DefragInit(); p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; + FAIL_IF_NULL(p1); p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8); - if (p2 == NULL) - goto end; + FAIL_IF_NULL(p2); p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3); - if (p3 == NULL) - goto end; + FAIL_IF_NULL(p3); - if (Defrag(NULL, NULL, p3, NULL) != NULL) - goto end; - if (Defrag(NULL, NULL, p2, NULL) != NULL) - goto end; + FAIL_IF(Defrag(NULL, NULL, p3, NULL) != NULL); + FAIL_IF(Defrag(NULL, NULL, p2, NULL) != NULL); reassembled = Defrag(NULL, NULL, p1, NULL); - if (reassembled == NULL) - goto end; + FAIL_IF_NULL(reassembled); - if (IPV4_GET_HLEN(reassembled) != 20) - goto end; - if (IPV4_GET_IPLEN(reassembled) != 39) - goto end; + FAIL_IF(IPV4_GET_HLEN(reassembled) != 20); + FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39); /* 20 bytes in we should find 8 bytes of A. */ for (i = 20; i < 20 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'A') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A'); } /* 28 bytes in we should find 8 bytes of B. */ for (i = 28; i < 28 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'B') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B'); } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 36; i < 36 + 3; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'C') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C'); } - ret = 1; -end: - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); - if (p3 != NULL) - SCFree(p3); - if (reassembled != NULL) - SCFree(reassembled); + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(reassembled); DefragDestroy(); - return ret; + PASS; } /** * Test the simplest possible re-assembly scenario. All packet in * order and no overlaps. */ -static int -IPV6DefragInOrderSimpleTest(void) +static int IPV6DefragInOrderSimpleTest(void) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; - int ret = 0; DefragInit(); p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; + FAIL_IF_NULL(p1); p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8); - if (p2 == NULL) - goto end; + FAIL_IF_NULL(p2); p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3); - if (p3 == NULL) - goto end; + FAIL_IF_NULL(p3); - if (Defrag(NULL, NULL, p1, NULL) != NULL) - goto end; - if (Defrag(NULL, NULL, p2, NULL) != NULL) - goto end; + FAIL_IF(Defrag(NULL, NULL, p1, NULL) != NULL); + FAIL_IF(Defrag(NULL, NULL, p2, NULL) != NULL); reassembled = Defrag(NULL, NULL, p3, NULL); - if (reassembled == NULL) - goto end; + FAIL_IF_NULL(reassembled); - if (IPV6_GET_PLEN(reassembled) != 19) - goto end; + FAIL_IF(IPV6_GET_PLEN(reassembled) != 19); /* 40 bytes in we should find 8 bytes of A. */ for (i = 40; i < 40 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'A') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A'); } /* 28 bytes in we should find 8 bytes of B. */ for (i = 48; i < 48 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'B') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B'); } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 56; i < 56 + 3; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'C') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C'); } - ret = 1; -end: - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); - if (p3 != NULL) - SCFree(p3); - if (reassembled != NULL) - SCFree(reassembled); + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(reassembled); DefragDestroy(); - return ret; + PASS; } -static int -IPV6DefragReverseSimpleTest(void) +static int IPV6DefragReverseSimpleTest(void) { DefragContext *dc = NULL; Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; - int ret = 0; DefragInit(); dc = DefragContextNew(); - if (dc == NULL) - goto end; + FAIL_IF_NULL(dc); p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; + FAIL_IF_NULL(p1); p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8); - if (p2 == NULL) - goto end; + FAIL_IF_NULL(p2); p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3); - if (p3 == NULL) - goto end; + FAIL_IF_NULL(p3); - if (Defrag(NULL, NULL, p3, NULL) != NULL) - goto end; - if (Defrag(NULL, NULL, p2, NULL) != NULL) - goto end; + FAIL_IF(Defrag(NULL, NULL, p3, NULL) != NULL); + FAIL_IF(Defrag(NULL, NULL, p2, NULL) != NULL); reassembled = Defrag(NULL, NULL, p1, NULL); - if (reassembled == NULL) - goto end; + FAIL_IF_NULL(reassembled); /* 40 bytes in we should find 8 bytes of A. */ for (i = 40; i < 40 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'A') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A'); } /* 28 bytes in we should find 8 bytes of B. */ for (i = 48; i < 48 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'B') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B'); } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 56; i < 56 + 3; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'C') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C'); } - ret = 1; -end: - if (dc != NULL) - DefragContextDestroy(dc); - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); - if (p3 != NULL) - SCFree(p3); - if (reassembled != NULL) - SCFree(reassembled); + DefragContextDestroy(dc); + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(reassembled); DefragDestroy(); - return ret; + PASS; } -static int -DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) +static int DefragDoSturgesNovakTest(int policy, u_char *expected, + size_t expected_len) { int i; - int ret = 0; DefragInit(); @@ -1511,66 +1425,43 @@ DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) /* Send all but the last. */ for (i = 0; i < 9; i++) { Packet *tp = Defrag(NULL, NULL, packets[i], NULL); - if (tp != NULL) { - SCFree(tp); - goto end; - } - if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) { - goto end; - } + FAIL_IF_NOT_NULL(tp); + FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)); } int overlap = 0; for (; i < 16; i++) { Packet *tp = Defrag(NULL, NULL, packets[i], NULL); - if (tp != NULL) { - SCFree(tp); - goto end; - } + FAIL_IF_NOT_NULL(tp); if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) { overlap++; } } - if (!overlap) { - goto end; - } + FAIL_IF_NOT(overlap); /* And now the last one. */ Packet *reassembled = Defrag(NULL, NULL, packets[16], NULL); - if (reassembled == NULL) { - goto end; - } + FAIL_IF_NULL(reassembled); - if (IPV4_GET_HLEN(reassembled) != 20) { - goto end; - } - if (IPV4_GET_IPLEN(reassembled) != 20 + 192) { - goto end; - } + FAIL_IF(IPV4_GET_HLEN(reassembled) != 20); + FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192); - if (memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0) { - goto end; - } + FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0); SCFree(reassembled); /* Make sure all frags were returned back to the pool. */ - if (defrag_context->frag_pool->outstanding != 0) { - goto end; - } + FAIL_IF(defrag_context->frag_pool->outstanding != 0); - ret = 1; -end: for (i = 0; i < 17; i++) { SCFree(packets[i]); } DefragDestroy(); - return ret; + PASS; } -static int -IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) +static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, + size_t expected_len) { int i; - int ret = 0; DefragInit(); @@ -1646,54 +1537,36 @@ IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) /* Send all but the last. */ for (i = 0; i < 9; i++) { Packet *tp = Defrag(NULL, NULL, packets[i], NULL); - if (tp != NULL) { - SCFree(tp); - goto end; - } - if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) { - goto end; - } + FAIL_IF_NOT_NULL(tp); + FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)); } int overlap = 0; for (; i < 16; i++) { Packet *tp = Defrag(NULL, NULL, packets[i], NULL); - if (tp != NULL) { - SCFree(tp); - goto end; - } + FAIL_IF_NOT_NULL(tp); if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) { overlap++; } } - if (!overlap) - goto end; + FAIL_IF_NOT(overlap); /* And now the last one. */ Packet *reassembled = Defrag(NULL, NULL, packets[16], NULL); - if (reassembled == NULL) - goto end; - if (memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0) - goto end; + FAIL_IF_NULL(reassembled); + FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0); - if (IPV6_GET_PLEN(reassembled) != 192) - goto end; + FAIL_IF(IPV6_GET_PLEN(reassembled) != 192); SCFree(reassembled); /* Make sure all frags were returned to the pool. */ - if (defrag_context->frag_pool->outstanding != 0) { - printf("defrag_context->frag_pool->outstanding %u: ", defrag_context->frag_pool->outstanding); - goto end; - } - - ret = 1; + FAIL_IF(defrag_context->frag_pool->outstanding != 0); -end: for (i = 0; i < 17; i++) { SCFree(packets[i]); } DefragDestroy(); - return ret; + PASS; } static int @@ -1727,11 +1600,12 @@ DefragSturgesNovakBsdTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakBsdTest(void) +static int IPV6DefragSturgesNovakBsdTest(void) { /* Expected data. */ u_char expected[] = { @@ -1761,11 +1635,12 @@ IPV6DefragSturgesNovakBsdTest(void) "QQQQQQQQ" }; - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, sizeof(expected)); + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, + sizeof(expected))); + PASS; } -static int -DefragSturgesNovakLinuxTest(void) +static int DefragSturgesNovakLinuxTest(void) { /* Expected data. */ u_char expected[] = { @@ -1795,11 +1670,12 @@ DefragSturgesNovakLinuxTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakLinuxTest(void) +static int IPV6DefragSturgesNovakLinuxTest(void) { /* Expected data. */ u_char expected[] = { @@ -1829,12 +1705,12 @@ IPV6DefragSturgesNovakLinuxTest(void) "QQQQQQQQ" }; - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, - sizeof(expected)); + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, + sizeof(expected))); + PASS; } -static int -DefragSturgesNovakWindowsTest(void) +static int DefragSturgesNovakWindowsTest(void) { /* Expected data. */ u_char expected[] = { @@ -1864,11 +1740,12 @@ DefragSturgesNovakWindowsTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakWindowsTest(void) +static int IPV6DefragSturgesNovakWindowsTest(void) { /* Expected data. */ u_char expected[] = { @@ -1898,12 +1775,12 @@ IPV6DefragSturgesNovakWindowsTest(void) "QQQQQQQQ" }; - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, - sizeof(expected)); + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, + sizeof(expected))); + PASS; } -static int -DefragSturgesNovakSolarisTest(void) +static int DefragSturgesNovakSolarisTest(void) { /* Expected data. */ u_char expected[] = { @@ -1933,11 +1810,12 @@ DefragSturgesNovakSolarisTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakSolarisTest(void) +static int IPV6DefragSturgesNovakSolarisTest(void) { /* Expected data. */ u_char expected[] = { @@ -1967,12 +1845,12 @@ IPV6DefragSturgesNovakSolarisTest(void) "QQQQQQQQ" }; - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, - sizeof(expected)); + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, + sizeof(expected))); + PASS; } -static int -DefragSturgesNovakFirstTest(void) +static int DefragSturgesNovakFirstTest(void) { /* Expected data. */ u_char expected[] = { @@ -2002,11 +1880,12 @@ DefragSturgesNovakFirstTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakFirstTest(void) +static int IPV6DefragSturgesNovakFirstTest(void) { /* Expected data. */ u_char expected[] = { @@ -2071,11 +1950,12 @@ DefragSturgesNovakLastTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakLastTest(void) +static int IPV6DefragSturgesNovakLastTest(void) { /* Expected data. */ u_char expected[] = { @@ -2105,67 +1985,48 @@ IPV6DefragSturgesNovakLastTest(void) "QQQQQQQQ" }; - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, - sizeof(expected)); + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, + sizeof(expected))); + PASS; } -static int -DefragTimeoutTest(void) +static int DefragTimeoutTest(void) { int i; - int ret = 0; /* Setup a small numberr of trackers. */ - if (ConfSet("defrag.trackers", "16") != 1) { - printf("ConfSet failed: "); - goto end; - } + FAIL_IF_NOT(ConfSet("defrag.trackers", "16")); DefragInit(); /* Load in 16 packets. */ for (i = 0; i < 16; i++) { Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16); - if (p == NULL) - goto end; + FAIL_IF_NULL(p); Packet *tp = Defrag(NULL, NULL, p, NULL); - SCFree(p); - - if (tp != NULL) { - SCFree(tp); - goto end; - } + FAIL_IF_NOT_NULL(tp); } /* Build a new packet but push the timestamp out by our timeout. * This should force our previous fragments to be timed out. */ Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16); - if (p == NULL) - goto end; + FAIL_IF_NULL(p); p->ts.tv_sec += (defrag_context->timeout + 1); Packet *tp = Defrag(NULL, NULL, p, NULL); - - if (tp != NULL) { - SCFree(tp); - goto end; - } + FAIL_IF_NOT_NULL(tp); DefragTracker *tracker = DefragLookupTrackerFromHash(p); - if (tracker == NULL) - goto end; + FAIL_IF_NULL(tracker); - if (tracker->id != 99) - goto end; + FAIL_IF(tracker->id != 99); SCFree(p); - ret = 1; -end: DefragDestroy(); - return ret; + PASS; } /** @@ -2174,84 +2035,65 @@ DefragTimeoutTest(void) * fail. The fix was simple, but this unit test is just to make sure * its not introduced. */ -static int -DefragIPv4NoDataTest(void) +static int DefragIPv4NoDataTest(void) { DefragContext *dc = NULL; Packet *p = NULL; int id = 12; - int ret = 0; DefragInit(); dc = DefragContextNew(); - if (dc == NULL) - goto end; + FAIL_IF_NULL(dc); /* This packet has an offset > 0, more frags set to 0 and no data. */ p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0); - if (p == NULL) - goto end; + FAIL_IF_NULL(p); /* We do not expect a packet returned. */ - if (Defrag(NULL, NULL, p, NULL) != NULL) - goto end; + FAIL_IF(Defrag(NULL, NULL, p, NULL) != NULL); /* The fragment should have been ignored so no fragments should * have been allocated from the pool. */ - if (dc->frag_pool->outstanding != 0) - return 0; + FAIL_IF(dc->frag_pool->outstanding != 0); - ret = 1; -end: - if (dc != NULL) - DefragContextDestroy(dc); - if (p != NULL) - SCFree(p); + DefragContextDestroy(dc); + SCFree(p); DefragDestroy(); - return ret; + PASS; } -static int -DefragIPv4TooLargeTest(void) +static int DefragIPv4TooLargeTest(void) { DefragContext *dc = NULL; Packet *p = NULL; - int ret = 0; DefragInit(); dc = DefragContextNew(); - if (dc == NULL) - goto end; + FAIL_IF_NULL(dc); /* Create a fragment that would extend past the max allowable size * for an IPv4 packet. */ p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71); - if (p == NULL) - goto end; + FAIL_IF_NULL(p); /* We do not expect a packet returned. */ - if (Defrag(NULL, NULL, p, NULL) != NULL) - goto end; - if (!ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE)) - goto end; + FAIL_IF(Defrag(NULL, NULL, p, NULL) != NULL); + + /* We do expect an event. */ + FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE)); /* The fragment should have been ignored so no fragments should have * been allocated from the pool. */ - if (dc->frag_pool->outstanding != 0) - return 0; + FAIL_IF(dc->frag_pool->outstanding != 0); - ret = 1; -end: - if (dc != NULL) - DefragContextDestroy(dc); - if (p != NULL) - SCFree(p); + DefragContextDestroy(dc); + SCFree(p); DefragDestroy(); - return ret; + PASS; } /** @@ -2259,72 +2101,52 @@ DefragIPv4TooLargeTest(void) * re-assembled, are not re-assembled. Just use simple in-order * fragments. */ -static int -DefragVlanTest(void) +static int DefragVlanTest(void) { Packet *p1 = NULL, *p2 = NULL, *r = NULL; - int ret = 0; DefragInit(); p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; + FAIL_IF_NULL(p1); p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8); - if (p2 == NULL) - goto end; + FAIL_IF_NULL(p2); /* With no VLAN IDs set, packets should re-assemble. */ - if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL) - goto end; - if ((r = Defrag(NULL, NULL, p2, NULL)) == NULL) - goto end; + FAIL_IF((r = Defrag(NULL, NULL, p1, NULL)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2, NULL)) == NULL); SCFree(r); /* With mismatched VLANs, packets should not re-assemble. */ p1->vlan_id[0] = 1; p2->vlan_id[0] = 2; - if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL) - goto end; - if ((r = Defrag(NULL, NULL, p2, NULL)) != NULL) - goto end; - - /* Pass. */ - ret = 1; - -end: - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); + FAIL_IF((r = Defrag(NULL, NULL, p1, NULL)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2, NULL)) != NULL); + + SCFree(p1); + SCFree(p2); DefragDestroy(); - return ret; + PASS; } /** * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID. */ -static int -DefragVlanQinQTest(void) +static int DefragVlanQinQTest(void) { Packet *p1 = NULL, *p2 = NULL, *r = NULL; - int ret = 0; DefragInit(); p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; + FAIL_IF_NULL(p1); p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8); - if (p2 == NULL) - goto end; + FAIL_IF_NULL(p2); /* With no VLAN IDs set, packets should re-assemble. */ - if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL) - goto end; - if ((r = Defrag(NULL, NULL, p2, NULL)) == NULL) - goto end; + FAIL_IF((r = Defrag(NULL, NULL, p1, NULL)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2, NULL)) == NULL); SCFree(r); /* With mismatched VLANs, packets should not re-assemble. */ @@ -2332,27 +2154,18 @@ DefragVlanQinQTest(void) p2->vlan_id[0] = 1; p1->vlan_id[1] = 1; p2->vlan_id[1] = 2; - if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL) - goto end; - if ((r = Defrag(NULL, NULL, p2, NULL)) != NULL) - goto end; - - /* Pass. */ - ret = 1; - -end: - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); + FAIL_IF((r = Defrag(NULL, NULL, p1, NULL)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2, NULL)) != NULL); + + SCFree(p1); + SCFree(p2); DefragDestroy(); - return ret; + PASS; } static int DefragTrackerReuseTest(void) { - int ret = 0; int id = 1; Packet *p1 = NULL; DefragTracker *tracker1 = NULL, *tracker2 = NULL; @@ -2362,31 +2175,19 @@ static int DefragTrackerReuseTest(void) /* Build a packet, its not a fragment but shouldn't matter for * this test. */ p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8); - if (p1 == NULL) { - goto end; - } + FAIL_IF_NULL(p1); /* Get a tracker. It shouldn't look like its already in use. */ tracker1 = DefragGetTracker(NULL, NULL, p1); - if (tracker1 == NULL) { - goto end; - } - if (tracker1->seen_last) { - goto end; - } - if (tracker1->remove) { - goto end; - } + FAIL_IF_NULL(tracker1); + FAIL_IF(tracker1->seen_last); + FAIL_IF(tracker1->remove); DefragTrackerRelease(tracker1); /* Get a tracker again, it should be the same one. */ tracker2 = DefragGetTracker(NULL, NULL, p1); - if (tracker2 == NULL) { - goto end; - } - if (tracker2 != tracker1) { - goto end; - } + FAIL_IF_NULL(tracker2); + FAIL_IF(tracker2 != tracker1); DefragTrackerRelease(tracker1); /* Now mark the tracker for removal. It should not be returned @@ -2395,23 +2196,13 @@ static int DefragTrackerReuseTest(void) tracker1->remove = 1; tracker2 = DefragGetTracker(NULL, NULL, p1); - if (tracker2 == NULL) { - goto end; - } - if (tracker2 == tracker1) { - goto end; - } - if (tracker2->remove) { - goto end; - } + FAIL_IF_NULL(tracker2); + FAIL_IF(tracker2 == tracker1); + FAIL_IF(tracker2->remove); - ret = 1; -end: - if (p1 != NULL) { - SCFree(p1); - } + SCFree(p1); DefragDestroy(); - return ret; + PASS; } /** @@ -2425,7 +2216,6 @@ static int DefragTrackerReuseTest(void) */ static int DefragMfIpv4Test(void) { - int retval = 0; int ip_id = 9; Packet *p = NULL; @@ -2434,48 +2224,28 @@ static int DefragMfIpv4Test(void) Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8); Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8); Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8); - if (p1 == NULL || p2 == NULL || p3 == NULL) { - goto end; - } + FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL); p = Defrag(NULL, NULL, p1, NULL); - if (p != NULL) { - goto end; - } + FAIL_IF_NOT_NULL(p); p = Defrag(NULL, NULL, p2, NULL); - if (p != NULL) { - goto end; - } + FAIL_IF_NOT_NULL(p); /* This should return a packet as MF=0. */ p = Defrag(NULL, NULL, p3, NULL); - if (p == NULL) { - goto end; - } + FAIL_IF_NULL(p); /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the * fragments should be in the re-assembled packet. */ - if (IPV4_GET_IPLEN(p) != 36) { - goto end; - } + FAIL_IF(IPV4_GET_IPLEN(p) != 36); - retval = 1; -end: - if (p1 != NULL) { - SCFree(p1); - } - if (p2 != NULL) { - SCFree(p2); - } - if (p3 != NULL) { - SCFree(p3); - } - if (p != NULL) { - SCFree(p); - } + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(p); DefragDestroy(); - return retval; + PASS; } /** @@ -2489,7 +2259,6 @@ static int DefragMfIpv4Test(void) */ static int DefragMfIpv6Test(void) { - int retval = 0; int ip_id = 9; Packet *p = NULL; @@ -2498,48 +2267,28 @@ static int DefragMfIpv6Test(void) Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8); Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8); Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8); - if (p1 == NULL || p2 == NULL || p3 == NULL) { - goto end; - } + FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL); p = Defrag(NULL, NULL, p1, NULL); - if (p != NULL) { - goto end; - } + FAIL_IF_NOT_NULL(p); p = Defrag(NULL, NULL, p2, NULL); - if (p != NULL) { - goto end; - } + FAIL_IF_NOT_NULL(p); /* This should return a packet as MF=0. */ p = Defrag(NULL, NULL, p3, NULL); - if (p == NULL) { - goto end; - } + FAIL_IF_NULL(p); /* For IPv6 the expected length is just the length of the payload * of 2 fragments, so 16. */ - if (IPV6_GET_PLEN(p) != 16) { - goto end; - } + FAIL_IF(IPV6_GET_PLEN(p) != 16); - retval = 1; -end: - if (p1 != NULL) { - SCFree(p1); - } - if (p2 != NULL) { - SCFree(p2); - } - if (p3 != NULL) { - SCFree(p3); - } - if (p != NULL) { - SCFree(p); - } + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(p); DefragDestroy(); - return retval; + PASS; } /** @@ -2564,12 +2313,9 @@ static int DefragTestBadProto(void) FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2, NULL)); FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3, NULL)); - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); - if (p3 != NULL) - SCFree(p3); + SCFree(p1); + SCFree(p2); + SCFree(p3); DefragDestroy(); PASS; @@ -2577,8 +2323,7 @@ static int DefragTestBadProto(void) #endif /* UNITTESTS */ -void -DefragRegisterTests(void) +void DefragRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest); @@ -2619,4 +2364,3 @@ DefragRegisterTests(void) UtRegisterTest("DefragTestBadProto", DefragTestBadProto); #endif /* UNITTESTS */ } - From 7922f9be1bb96654a2b3928bc9a7fa2047490a12 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 6 Mar 2017 11:23:48 -0600 Subject: [PATCH 2535/2553] defrag: (linux) fix an error in overlapping fragments If a subsequent fragment has a lower offset than a previous one and overlaps, trim off the beginning of the previous fragment. Based on an issue reported privately. --- src/defrag.c | 129 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 106 insertions(+), 23 deletions(-) diff --git a/src/defrag.c b/src/defrag.c index 94234073e140..03a681f2b686 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -256,8 +256,9 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) Packet *rp = NULL; /* Should not be here unless we have seen the last fragment. */ - if (!tracker->seen_last) + if (!tracker->seen_last) { return NULL; + } /* Check that we have all the data. Relies on the fact that * fragments are inserted if frag_offset order. */ @@ -330,9 +331,10 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) "fragmented packet, exceeds size of packet buffer."); goto error_remove_tracker; } - if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim, - frag->pkt + frag->data_offset + frag->ltrim, - frag->data_len - frag->ltrim) == -1) { + if (PacketCopyDataOffset(rp, + fragmentable_offset + frag->offset + frag->ltrim, + frag->pkt + frag->data_offset + frag->ltrim, + frag->data_len - frag->ltrim) == -1) { goto error_remove_tracker; } if (frag->offset + frag->data_len > fragmentable_len) @@ -604,9 +606,12 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Frag *prev = NULL, *next; int overlap = 0; + ltrim = 0; if (!TAILQ_EMPTY(&tracker->frags)) { TAILQ_FOREACH(prev, &tracker->frags, next) { - ltrim = 0; + if (prev->skip) { + continue; + } next = TAILQ_NEXT(prev, next); switch (tracker->policy) { @@ -629,21 +634,41 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, } break; case DEFRAG_POLICY_LINUX: - if (frag_offset < prev->offset + prev->data_len) { - if (frag_offset > prev->offset) { - ltrim = prev->offset + prev->data_len - frag_offset; - overlap++; - } - if ((next != NULL) && (frag_end > next->offset)) { - next->ltrim = frag_end - next->offset; - overlap++; - } - if ((frag_offset < prev->offset) && - (frag_end >= prev->offset + prev->data_len)) { - prev->skip = 1; - overlap++; - } - goto insert; + /* Check if new fragment overlaps the end of previous + * fragment, if it does, trim the new fragment. + * + * Old: AAAAAAAA AAAAAAAA AAAAAAAA + * New: BBBBBBBB BBBBBBBB BBBBBBBB + * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB + */ + if (prev->offset + prev->ltrim < frag_offset + ltrim && + prev->offset + prev->data_len > frag_offset + ltrim) { + ltrim += prev->offset + prev->data_len - frag_offset; + overlap++; + } + + /* Check if new fragment overlaps the beginning of + * previous fragment, if it does, tim the previous + * fragment. + * + * Old: AAAAAAAA AAAAAAAA + * New: BBBBBBBB BBBBBBBB BBBBBBBB + * Res: BBBBBBBB BBBBBBBB BBBBBBBB + */ + if (frag_offset + ltrim < prev->offset + prev->ltrim && + frag_end > prev->offset + prev->ltrim) { + prev->ltrim += frag_end - (prev->offset + prev->ltrim); + overlap++; + } + + /* If the new fragment completely overlaps the + * previous fragment, mark the previous to be + * skipped. Re-assembly would succeed without doing + * this, but this will prevent the bytes from being + * copied just to be overwritten. */ + if (frag_offset + ltrim <= prev->offset + prev->ltrim && + frag_end >= prev->offset + prev->data_len) { + prev->skip = 1; } break; case DEFRAG_POLICY_WINDOWS: @@ -705,7 +730,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, } insert: - if (data_len - ltrim <= 0) { + if (ltrim > data_len) { /* Full packet has been trimmed due to the overlap policy. Overlap * already set. */ goto done; @@ -1640,7 +1665,7 @@ static int IPV6DefragSturgesNovakBsdTest(void) PASS; } -static int DefragSturgesNovakLinuxTest(void) +static int DefragSturgesNovakLinuxIpv4Test(void) { /* Expected data. */ u_char expected[] = { @@ -2321,6 +2346,61 @@ static int DefragTestBadProto(void) PASS; } +/** + * \test Test a report Linux overlap issue that doesn't appear to be + * covered by the Sturges/Novak tests above. + */ +static int DefragTestJeremyLinux(void) +{ + char expected[] = "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "BBBBBBBB" + "BBBBBBBB" + "DDDDDDDD" + "DDDDDD"; + + DefragInit(); + default_policy = DEFRAG_POLICY_LINUX; + + int id = 1; + Packet *packets[4]; + int i = 0; + + packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24); + packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48); + packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48); + packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14); + + Packet *r = Defrag(NULL, NULL, packets[0], NULL); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[1], NULL); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[2], NULL); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[3], NULL); + FAIL_IF_NULL(r); + + FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0); + + for (i = 0; i < 4; i++) { + SCFree(packets[i]); + } + SCFree(r); + + DefragDestroy(); + PASS; +} + #endif /* UNITTESTS */ void DefragRegisterTests(void) @@ -2329,7 +2409,8 @@ void DefragRegisterTests(void) UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest); UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest); UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest); - UtRegisterTest("DefragSturgesNovakLinuxTest", DefragSturgesNovakLinuxTest); + UtRegisterTest("DefragSturgesNovakLinuxIpv4Test", + DefragSturgesNovakLinuxIpv4Test); UtRegisterTest("DefragSturgesNovakWindowsTest", DefragSturgesNovakWindowsTest); UtRegisterTest("DefragSturgesNovakSolarisTest", @@ -2362,5 +2443,7 @@ void DefragRegisterTests(void) UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test); UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test); UtRegisterTest("DefragTestBadProto", DefragTestBadProto); + + UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux); #endif /* UNITTESTS */ } From 845e18f25ac840955f2bcc71292d33c3f78107dd Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 6 Mar 2017 14:38:04 -0600 Subject: [PATCH 2536/2553] defrag: (windows) detect more overlaps --- src/defrag.c | 53 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/defrag.c b/src/defrag.c index 03a681f2b686..11cda60e991a 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -672,16 +672,43 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, } break; case DEFRAG_POLICY_WINDOWS: - if (frag_offset < prev->offset + prev->data_len) { - if (frag_offset >= prev->offset) { - ltrim = prev->offset + prev->data_len - frag_offset; - overlap++; - } - if ((frag_offset < prev->offset) && - (frag_end > prev->offset + prev->data_len)) { - prev->skip = 1; - overlap++; - } + /* If new fragment fits inside a previous fragment, drop it. */ + if (frag_offset + ltrim >= prev->offset + ltrim && + frag_end <= prev->offset + prev->data_len) { + overlap++; + goto done; + } + + /* If new fragment starts before and ends after + * previous fragment, drop the previous fragment. */ + if (frag_offset + ltrim < prev->offset + ltrim && + frag_end > prev->offset + prev->data_len) { + prev->skip = 1; + overlap++; + goto insert; + } + + /* Check if new fragment overlaps the end of previous + * fragment, if it does, trim the new fragment. + * + * Old: AAAAAAAA AAAAAAAA AAAAAAAA + * New: BBBBBBBB BBBBBBBB BBBBBBBB + * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB + */ + if (frag_offset + ltrim > prev->offset + prev->ltrim && + frag_offset + ltrim < prev->offset + prev->data_len) { + ltrim += prev->offset + prev->data_len - frag_offset; + overlap++; + goto insert; + } + + /* If new fragment starts at same offset as an + * existing fragment, but ends after it, trim the new + * fragment. */ + if (frag_offset + ltrim == prev->offset + ltrim && + frag_end > prev->offset + prev->data_len) { + ltrim += prev->offset + prev->data_len - frag_offset; + overlap++; goto insert; } break; @@ -1735,7 +1762,7 @@ static int IPV6DefragSturgesNovakLinuxTest(void) PASS; } -static int DefragSturgesNovakWindowsTest(void) +static int DefragSturgesNovakWindowsIpv4Test(void) { /* Expected data. */ u_char expected[] = { @@ -2411,8 +2438,8 @@ void DefragRegisterTests(void) UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest); UtRegisterTest("DefragSturgesNovakLinuxIpv4Test", DefragSturgesNovakLinuxIpv4Test); - UtRegisterTest("DefragSturgesNovakWindowsTest", - DefragSturgesNovakWindowsTest); + UtRegisterTest("DefragSturgesNovakWindowsIpv4Test", + DefragSturgesNovakWindowsIpv4Test); UtRegisterTest("DefragSturgesNovakSolarisTest", DefragSturgesNovakSolarisTest); UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest); From bc480fa8c3fe47f3fe1fea182904f2c17beb4fe3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Apr 2017 13:05:35 +0200 Subject: [PATCH 2537/2553] pcre: disable jit on powerpc64 It appears that both using gcc and clang something gets misoptimised around pcre's jit. So disable jit for now. --- configure.ac | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 57e7253a9baf..91f4925d9d9a 100644 --- a/configure.ac +++ b/configure.ac @@ -552,10 +552,19 @@ [ pcre_jit_available=yes ], [ pcre_jit_available=no ] ) - # bug 1693, libpcre 8.35 is broken and debian jessie is still using that - if test "$libpcre_buggy_found" = "yes"; then - pcre_jit_available="no, libpcre 8.35 blacklisted" - fi + case $host in + *powerpc64*) + # on powerpc64, both gcc and clang lead to SIGILL in + # unittests when jit is enabled. + pcre_jit_available="no, pcre jit disabled for powerpc64" + ;; + *) + # bug 1693, libpcre 8.35 is broken and debian jessie is still using that + if test "$libpcre_buggy_found" = "yes"; then + pcre_jit_available="no, libpcre 8.35 blacklisted" + fi + ;; + esac if test "x$pcre_jit_available" = "xyes"; then AC_MSG_RESULT(yes) From db6c80fd8e4232d963553def0451f191a9c81888 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 14 Feb 2017 08:29:44 +0100 Subject: [PATCH 2538/2553] logging: support date modifiers in log filenames Allow log filenames to contain date modifiers, e.g.: - eve-log: filename: eve-%Y-%m-%d-%H:%M:%S.json --- src/util-logopenfile.c | 36 +++++++++++++++++++++++++++++++----- src/util-time.c | 34 ++++++++++++++++++++++++++++++++++ src/util-time.h | 2 ++ 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index e10f864e05f0..67b57f0f7b71 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -160,6 +160,26 @@ static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ct return ret; } +/** \brief generate filename based on pattern + * \param pattern pattern to use + * \retval char* on success + * \retval NULL on error + */ +static char *SCLogFilenameFromPattern(const char *pattern) +{ + char *filename = SCMalloc(PATH_MAX); + if (filename == NULL) { + return NULL; + } + + int rc = SCTimeToStringPattern(time(NULL), pattern, filename, PATH_MAX); + if (rc != 0) { + return NULL; + } + + return filename; +} + static void SCLogFileClose(LogFileCtx *log_ctx) { if (log_ctx->fp) @@ -178,25 +198,31 @@ SCLogOpenFileFp(const char *path, const char *append_setting, uint32_t mode) { FILE *ret = NULL; + char *filename = SCLogFilenameFromPattern(path); + if (filename == NULL) { + return NULL; + } + if (ConfValIsTrue(append_setting)) { - ret = fopen(path, "a"); + ret = fopen(filename, "a"); } else { - ret = fopen(path, "w"); + ret = fopen(filename, "w"); } if (ret == NULL) { SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", - path, strerror(errno)); + filename, strerror(errno)); } else { if (mode != 0) { - int r = chmod(path, mode); + int r = chmod(filename, mode); if (r < 0) { SCLogWarning(SC_WARN_CHMOD, "Could not chmod %s to %u: %s", - path, mode, strerror(errno)); + filename, mode, strerror(errno)); } } } + SCFree(filename); return ret; } diff --git a/src/util-time.c b/src/util-time.c index b8f646f9ee63..7f6ab49a677b 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -478,3 +478,37 @@ int SCStringPatternToTime (char *string, char **patterns, int num_patterns, return 0; } + +/** + * \brief Convert epoch time to string pattern. + * + * This function converts epoch time to a string based on a pattern. + * + * \param epoch Epoch time. + * \param pattern String pattern. + * \param str Formated string. + * \param size Size of allocated string. + * + * \retval 0 on success. + * \retval 1 on failure. + */ +int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str, size_t size) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); + struct tm *tp = (struct tm *)SCLocalTime(epoch, &tm); + char buffer[PATH_MAX] = { 0 }; + + if (unlikely(tp == NULL)) { + return 1; + } + + int r = strftime(buffer, sizeof(buffer), pattern, tp); + if (r == 0) { + return 1; + } + + strlcpy(str, buffer, size); + + return 0; +} diff --git a/src/util-time.h b/src/util-time.h index 3d76642210c1..ae7ec2f5251a 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -58,6 +58,8 @@ void CreateFormattedTimeString(const struct tm *t, const char * fmt, char *str, time_t SCMkTimeUtc(struct tm *tp); int SCStringPatternToTime(char *string, char **patterns, int num_patterns, struct tm *time); +int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str, + size_t size); #endif /* __UTIL_TIME_H__ */ From 47a5b493d748e899c478ec7f75c4858fee4552ee Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 14 Feb 2017 08:41:40 +0100 Subject: [PATCH 2539/2553] output-json: rotate log file based on time Rotate log file based on time. Support both rotating based on a timer (XXs, XXm, XXd, XXw) and rotating based on a absolute time, like each minute, hour or day. --- src/util-logopenfile.c | 38 +++++++++++++++++++++ src/util-logopenfile.h | 12 +++++-- src/util-time.c | 77 ++++++++++++++++++++++++++++++++++++++++++ src/util-time.h | 2 ++ 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 67b57f0f7b71..cc1f0b1fb96e 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -136,6 +136,14 @@ static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ct SCConfLogReopen(log_ctx); } + if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) { + time_t now = time(NULL); + if (now >= log_ctx->rotate_time) { + SCConfLogReopen(log_ctx); + log_ctx->rotate_time = now + log_ctx->rotate_interval; + } + } + int ret = 0; if (log_ctx->fp == NULL && log_ctx->is_sock) @@ -290,6 +298,36 @@ SCConfLogOpenGeneric(ConfNode *conf, snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); } + /* Rotate log file based on time */ + const char *rotate_int = ConfNodeLookupChildValue(conf, "rotate-interval"); + if (rotate_int != NULL) { + time_t now = time(NULL); + log_ctx->flags |= LOGFILE_ROTATE_INTERVAL; + + /* Use a specific time */ + if (strcmp(rotate_int, "minute") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 60; + } else if (strcmp(rotate_int, "hour") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 3600; + } else if (strcmp(rotate_int, "day") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 86400; + } + + /* Use a timer */ + else { + log_ctx->rotate_interval = SCParseTimeSizeString(rotate_int); + if (log_ctx->rotate_interval == 0) { + SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, + "invalid rotate-interval value"); + exit(EXIT_FAILURE); + } + log_ctx->rotate_time = now + log_ctx->rotate_interval; + } + } + filetype = ConfNodeLookupChildValue(conf, "filetype"); if (filetype == NULL) filetype = DEFAULT_LOG_FILETYPE; diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 201106cc598b..c84acffd4076 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -102,6 +102,13 @@ typedef struct LogFileCtx_ { int sock_type; uint64_t reconn_timer; + /** The next time to rotate log file, if rotate interval is + specified. */ + time_t rotate_time; + + /** The interval to rotate the log file */ + uint64_t rotate_interval; + /**< Used by some alert loggers like the unified ones that append * the date onto the end of files. */ char *prefix; @@ -133,8 +140,9 @@ typedef struct LogFileCtx_ { #define LOGFILE_RECONN_MIN_TIME 500 /* flags for LogFileCtx */ -#define LOGFILE_HEADER_WRITTEN 0x01 -#define LOGFILE_ALERTS_PRINTED 0x02 +#define LOGFILE_HEADER_WRITTEN 0x01 +#define LOGFILE_ALERTS_PRINTED 0x02 +#define LOGFILE_ROTATE_INTERVAL 0x04 LogFileCtx *LogFileNewCtx(void); int LogFileFreeCtx(LogFileCtx *); diff --git a/src/util-time.c b/src/util-time.c index 7f6ab49a677b..3e2b6058bbff 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -512,3 +512,80 @@ int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str, size_t return 0; } + +/** + * \brief Parse string containing time size (1m, 1h, etc). + * + * \param str String to parse. + * + * \retval size on success. + * \retval 0 on failure. + */ +uint64_t SCParseTimeSizeString (const char *str) +{ + uint64_t size = 0; + uint64_t modifier = 1; + char last = str[strlen(str)-1]; + + switch (last) + { + case '0' ... '9': + break; + /* seconds */ + case 's': + break; + /* minutes */ + case 'm': + modifier = 60; + break; + /* hours */ + case 'h': + modifier = 60 * 60; + break; + /* days */ + case 'd': + modifier = 60 * 60 * 24; + break; + /* weeks */ + case 'w': + modifier = 60 * 60 * 24 * 7; + break; + /* invalid */ + default: + return 0; + } + + errno = 0; + size = strtoumax(str, NULL, 10); + if (errno) { + return 0; + } + + return (size * modifier); +} + +/** + * \brief Get seconds until a time unit changes. + * + * \param str String containing time type (minute, hour, etc). + * \param epoch Epoch time. + * + * \retval seconds. + */ +uint64_t SCGetSecondsUntil (const char *str, time_t epoch) +{ + uint64_t seconds = 0; + struct tm tm; + memset(&tm, 0, sizeof(tm)); + struct tm *tp = (struct tm *)SCLocalTime(epoch, &tm); + + if (strcmp(str, "minute") == 0) + seconds = 60 - tp->tm_sec; + else if (strcmp(str, "hour") == 0) + seconds = (60 * (60 - tp->tm_min)) + (60 - tp->tm_sec); + else if (strcmp(str, "day") == 0) + seconds = (3600 * (24 - tp->tm_hour)) + (60 * (60 - tp->tm_min)) + + (60 - tp->tm_sec); + + return seconds; +} diff --git a/src/util-time.h b/src/util-time.h index ae7ec2f5251a..4bf965e729ff 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -60,6 +60,8 @@ int SCStringPatternToTime(char *string, char **patterns, int num_patterns, struct tm *time); int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str, size_t size); +uint64_t SCParseTimeSizeString (const char *str); +uint64_t SCGetSecondsUntil (const char *str, time_t epoch); #endif /* __UTIL_TIME_H__ */ From ffbf8cec162c9f6c77663d4df22e17bd5f8b5a01 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 14 Feb 2017 10:32:33 +0100 Subject: [PATCH 2540/2553] logging: create log directories when needed Recursively create new log directories when needed. This makes it possible to use date modifiers in the file path to create directories based on date, e.g.: /var/log/suricata/2017/02/14/ --- src/util-logopenfile.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index cc1f0b1fb96e..873df9c83570 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -188,6 +188,41 @@ static char *SCLogFilenameFromPattern(const char *pattern) return filename; } +/** \brief recursively create missing log directories + * \param path path to log file + * \retval 0 on success + * \retval -1 on error + */ +static int SCLogCreateDirectoryTree(const char *filepath) +{ + char pathbuf[PATH_MAX]; + char *p; + size_t len = strlen(filepath); + + if (len > PATH_MAX - 1) { + return -1; + } + + strlcpy(pathbuf, filepath, len); + + for (p = pathbuf + 1; *p; p++) { + if (*p == '/') { + /* Truncate, while creating directory */ + *p = '\0'; + + if (mkdir(pathbuf, S_IRWXU | S_IRGRP | S_IXGRP) != 0) { + if (errno != EEXIST) { + return -1; + } + } + + *p = '/'; + } + } + + return 0; +} + static void SCLogFileClose(LogFileCtx *log_ctx) { if (log_ctx->fp) @@ -211,6 +246,12 @@ SCLogOpenFileFp(const char *path, const char *append_setting, uint32_t mode) return NULL; } + int rc = SCLogCreateDirectoryTree(filename); + if (rc < 0) { + SCFree(filename); + return NULL; + } + if (ConfValIsTrue(append_setting)) { ret = fopen(filename, "a"); } else { From 37a12fe799252bde8cc37c187126ca6a2bfae018 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 14 Feb 2017 10:53:34 +0100 Subject: [PATCH 2541/2553] doc: add documentation for eve-log file rotation --- doc/userguide/output/eve/eve-json-output.rst | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/doc/userguide/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst index d89430ebef48..97ede6d94115 100644 --- a/doc/userguide/output/eve/eve-json-output.rst +++ b/doc/userguide/output/eve/eve-json-output.rst @@ -203,6 +203,35 @@ enabled, then the log gets more verbose. By using ``custom`` it is possible to select which TLS fields to log. +Rotate log file +~~~~~~~~~~~~~~~ + +Eve-log can be configured to rotate based on time. + +:: + + outputs: + - eve-log: + filename: eve-%Y-%m-%d-%H:%M.json + rotate-interval: minute + +The example above creates a new log file each minute, where the filename contains +a timestamp. Other supported ``rotate-interval`` values are ``hour`` and ``day``. + +In addition to this, it is also possible to specify the ``rotate-interval`` as a +relative value. One example is to rotate the log file each X seconds. + +:: + + outputs: + - eve-log: + filename: eve-%Y-%m-%d-%H:%M:%S.json + rotate-interval: 30s + +The example above rotates eve-log each 30 seconds. This could be replaced with +``30m`` to rotate every 30 minutes, ``30h`` to rotate every 30 hours, ``30d`` +to rotate every 30 days, or ``30w`` to rotate every 30 weeks. + Multiple Logger Instances ~~~~~~~~~~~~~~~~~~~~~~~~~ From 8b9f84bff2d8bd95030e8d2d4a586a3cd3d2c649 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 14 Feb 2017 10:59:41 +0100 Subject: [PATCH 2542/2553] doc: add documentation for date modifiers in eve-log --- doc/userguide/output/eve/eve-json-output.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/userguide/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst index 97ede6d94115..60279470201d 100644 --- a/doc/userguide/output/eve/eve-json-output.rst +++ b/doc/userguide/output/eve/eve-json-output.rst @@ -203,6 +203,21 @@ enabled, then the log gets more verbose. By using ``custom`` it is possible to select which TLS fields to log. +Date modifiers in filename +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to use date modifiers in the eve-log filename. + +:: + + outputs: + - eve-log: + filename: eve-%s.json + +The example above adds epoch time to the filename. All the date modifiers from the +C library should be supported. See the man page for ``strftime`` for all supported +modifiers. + Rotate log file ~~~~~~~~~~~~~~~ From 59b98649de2fad5594756983b3a86c940a3575c7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 23 Feb 2017 16:22:42 -0600 Subject: [PATCH 2543/2553] logging: don't block on socket writes Writing to a unix socket can cause Suricata to block in the packet path. This could happen if the read-endpoint of the unix socket stays connected, but stops reading, or simply can't read fast enough as part of its event processing. To choose packets over events, do non-blocking socket writes and drop the event if the write would block and update a dropped counter. --- src/util-logopenfile.c | 94 +++++++++++++++++++++++++++++++----------- src/util-logopenfile.h | 4 ++ 2 files changed, 73 insertions(+), 25 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 873df9c83570..2413f5aae70d 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -121,6 +121,57 @@ static int SCLogUnixSocketReconnect(LogFileCtx *log_ctx) return log_ctx->fp ? 1 : 0; } +static int SCLogFileWriteSocket(const char *buffer, int buffer_len, + LogFileCtx *ctx) +{ + int tries = 0; + int ret = 0; + bool reopen = false; + + if (ctx->fp == NULL && ctx->is_sock) { + SCLogUnixSocketReconnect(ctx); + } + +tryagain: + ret = -1; + reopen = 0; + errno = 0; + if (ctx->fp != NULL) { + int fd = fileno(ctx->fp); + ssize_t size = send(fd, buffer, buffer_len, MSG_DONTWAIT); + if (size > -1) { + ret = 0; + } else { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + SCLogDebug("Socket would block, dropping event."); + } else if (errno == EINTR) { + if (tries++ == 0) { + SCLogDebug("Interrupted system call, trying again."); + goto tryagain; + } + SCLogDebug("Too many interrupted system calls, " + "dropping event."); + } else { + /* Some other error. Assume badness and reopen. */ + SCLogDebug("Send failed: %s", strerror(errno)); + reopen = true; + } + } + } + + if (reopen && tries++ == 0) { + if (SCLogUnixSocketReconnect(ctx)) { + goto tryagain; + } + } + + if (ret == -1) { + ctx->dropped++; + } + + return ret; +} + /** * \brief Write buffer to log file. * \retval 0 on failure; otherwise, the return value of fwrite (number of @@ -129,38 +180,31 @@ static int SCLogUnixSocketReconnect(LogFileCtx *log_ctx) static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx) { SCMutexLock(&log_ctx->fp_mutex); + int ret = 0; - /* Check for rotation. */ - if (log_ctx->rotation_flag) { - log_ctx->rotation_flag = 0; - SCConfLogReopen(log_ctx); - } + if (log_ctx->is_sock) { + ret = SCLogFileWriteSocket(buffer, buffer_len, log_ctx); + } else { - if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) { - time_t now = time(NULL); - if (now >= log_ctx->rotate_time) { + /* Check for rotation. */ + if (log_ctx->rotation_flag) { + log_ctx->rotation_flag = 0; SCConfLogReopen(log_ctx); - log_ctx->rotate_time = now + log_ctx->rotate_interval; } - } - - int ret = 0; - if (log_ctx->fp == NULL && log_ctx->is_sock) - SCLogUnixSocketReconnect(log_ctx); - - if (log_ctx->fp) { - clearerr(log_ctx->fp); - ret = fwrite(buffer, buffer_len, 1, log_ctx->fp); - fflush(log_ctx->fp); - - if (ferror(log_ctx->fp) && log_ctx->is_sock) { - /* Error on Unix socket, maybe needs reconnect */ - if (SCLogUnixSocketReconnect(log_ctx)) { - ret = fwrite(buffer, buffer_len, 1, log_ctx->fp); - fflush(log_ctx->fp); + if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) { + time_t now = time(NULL); + if (now >= log_ctx->rotate_time) { + SCConfLogReopen(log_ctx); + log_ctx->rotate_time = now + log_ctx->rotate_interval; } } + + if (log_ctx->fp) { + clearerr(log_ctx->fp); + ret = fwrite(buffer, buffer_len, 1, log_ctx->fp); + fflush(log_ctx->fp); + } } SCMutexUnlock(&log_ctx->fp_mutex); diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index c84acffd4076..5e5d3a001f09 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -134,6 +134,10 @@ typedef struct LogFileCtx_ { /* Set to true if the filename should not be timestamped. */ bool nostamp; + + /* Socket types may need to drop events to keep from blocking + * Suricata. */ + uint64_t dropped; } LogFileCtx; /* Min time (msecs) before trying to reconnect a Unix domain socket */ From 673549e5cf34188a08d7934b1cafa36f2e3bdeb6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 4 Apr 2017 22:21:37 -0600 Subject: [PATCH 2544/2553] eve: log number of events dropped at exit --- src/output-json.c | 5 +++++ src/util-error.c | 1 + src/util-error.h | 1 + 3 files changed, 7 insertions(+) diff --git a/src/output-json.c b/src/output-json.c index 7b0a1f99a07c..5a457cd5046f 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -720,6 +720,11 @@ static void OutputJsonDeInitCtx(OutputCtx *output_ctx) { OutputJsonCtx *json_ctx = (OutputJsonCtx *)output_ctx->data; LogFileCtx *logfile_ctx = json_ctx->file_ctx; + if (logfile_ctx->dropped) { + SCLogWarning(SC_WARN_EVENT_DROPPED, + "%"PRIu64" events were dropped due to slow or " + "disconnected socket", logfile_ctx->dropped); + } LogFileFreeCtx(logfile_ctx); SCFree(json_ctx); SCFree(output_ctx); diff --git a/src/util-error.c b/src/util-error.c index 7b7aa7afc352..99b7e55cf726 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -339,6 +339,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_VAR_LIMIT); CASE_CODE (SC_WARN_CHMOD); CASE_CODE (SC_WARN_LOG_CF_TOO_MANY_NODES); + CASE_CODE (SC_WARN_EVENT_DROPPED); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 85e174abbe07..dbafabe1009a 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -329,6 +329,7 @@ typedef enum { SC_WARN_DUPLICATE_OUTPUT, SC_WARN_CHMOD, SC_WARN_LOG_CF_TOO_MANY_NODES, + SC_WARN_EVENT_DROPPED, } SCError; const char *SCErrorToString(SCError); From 8436a892f95efbe1b01e81d657a52d2210a4f955 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 4 Apr 2017 22:44:21 -0600 Subject: [PATCH 2545/2553] logging: only do non-blocking writes if live If running against a pcap there is no reason to drop events, a blocking socket is fine here. So only do non-blocking writes when running off a live device. --- src/suricata.c | 6 +++++- src/suricata.h | 1 + src/util-logopenfile.c | 8 +++++++- src/util-logopenfile.h | 3 +++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/suricata.c b/src/suricata.c index fbe0305531c2..6cd05f2c8a70 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -197,6 +197,9 @@ volatile uint8_t suricata_ctl_flags = 0; /** Run mode selected */ int run_mode = RUNMODE_UNKNOWN; +/** Is this an offline run mode. */ +int run_mode_offline = 0; + /** Engine mode: inline (ENGINE_MODE_IPS) or just * detection mode (ENGINE_MODE_IDS by default) */ static enum EngineMode g_engine_mode = ENGINE_MODE_IDS; @@ -2342,8 +2345,9 @@ static int FinalizeRunMode(SCInstance *suri, char **argv) default: break; } - /* Set the global run mode */ + /* Set the global run mode and offline flag. */ run_mode = suri->run_mode; + run_mode_offline = suri->offline; if (!CheckValidDaemonModes(suri->daemon, suri->run_mode)) { return TM_ECODE_FAILED; diff --git a/src/suricata.h b/src/suricata.h index 912f33b5d648..aaee9fe535e2 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -194,6 +194,7 @@ int RunmodeGetCurrent(void); int IsRuleReloadSet(int quiet); extern int run_mode; +extern int run_mode_offline; void PreRunInit(const int runmode); void PreRunPostPrivsDropInit(const int runmode); diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 2413f5aae70d..376a77af29eb 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -138,7 +138,7 @@ static int SCLogFileWriteSocket(const char *buffer, int buffer_len, errno = 0; if (ctx->fp != NULL) { int fd = fileno(ctx->fp); - ssize_t size = send(fd, buffer, buffer_len, MSG_DONTWAIT); + ssize_t size = send(fd, buffer, buffer_len, ctx->send_flags); if (size > -1) { ret = 0; } else { @@ -505,6 +505,12 @@ SCConfLogOpenGeneric(ConfNode *conf, return -1; } + /* If a socket and running live, do non-blocking writes. */ + if (log_ctx->is_sock && run_mode_offline == 0) { + SCLogInfo("Setting logging socket of non-blocking in live mode."); + log_ctx->send_flags |= MSG_DONTWAIT; + } + SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, filename); diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 5e5d3a001f09..857f8b821c70 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -122,6 +122,9 @@ typedef struct LogFileCtx_ { /* flag to avoid multiple threads printing the same stats */ uint8_t flags; + /* flags to set when sending over a socket */ + uint8_t send_flags; + /* Flag if file is a regular file or not. Only regular files * allow for rotataion. */ uint8_t is_regular; From 9ff8882cbdaf4ab2dc9f736fdd8ea56dcbe84fb1 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 15 Mar 2017 10:52:57 -0600 Subject: [PATCH 2546/2553] detect: don't consider an empty rule file an error --- src/detect.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/detect.c b/src/detect.c index 3ccb3b8e995a..21bffc78ba6f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -475,10 +475,14 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl ret = ProcessSigFiles(de_ctx, sfile, &sig_stat, &good_sigs, &bad_sigs); SCFree(sfile); - if (ret != 0 || good_sigs == 0) { - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } + if (de_ctx->failure_fatal && ret != 0) { + /* Some rules failed to load, just exit as + * errors would have already been logged. */ + exit(EXIT_FAILURE); + } + + if (good_sigs == 0) { + SCLogConfig("No rules loaded from %s.", file->val); } } } From aca27ff383d74f0eaf78f48d89f88f97f1285dd1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 13 Apr 2017 09:25:11 +0200 Subject: [PATCH 2547/2553] doc: expand on bpf --- .../performance/ignoring-traffic.rst | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/doc/userguide/performance/ignoring-traffic.rst b/doc/userguide/performance/ignoring-traffic.rst index 6e6f0db9f501..01bef3197dd9 100644 --- a/doc/userguide/performance/ignoring-traffic.rst +++ b/doc/userguide/performance/ignoring-traffic.rst @@ -1,9 +1,10 @@ Ignoring Traffic ================ -In some cases there are reasons to ignore certain traffic. Maybe a -trusted host or network, or a site. This document lists some -strategies for ignoring traffic. +In some cases there are reasons to ignore certain traffic. Certain hosts +may be trusted, or perhaps a backup stream should be ignored. + +This document lists some strategies for ignoring traffic. capture filters (BPF) --------------------- @@ -15,6 +16,25 @@ filter 'tcp' will only send tcp packets. If some hosts and or nets need to be ignored, use something like "not (host IP1 or IP2 or IP3 or net NET/24)". +Example:: + + not host 1.2.3.4 + +Capture filters are specified on the commandline after all other options:: + + suricata -i eth0 -v not host 1.2.3.4 + suricata -i eno1 -c suricata.yaml tcp or udp + +Capture filters can be set per interface in the pcap, af-packet, netmap +and pf_ring sections. It can also be put in a file:: + + echo "not host 1.2.3.4" > capture-filter.bpf + suricata -i ens5f0 -F capture-filter.bpf + +Using a capture filter limits what traffic Suricata processes. So the +traffic not seen by Suricata will not be inspected, logged or otherwise +recorded. + pass rules ---------- @@ -28,7 +48,7 @@ Example: pass ip 1.2.3.4 any <> any any (msg:"pass all traffic from/to 1.2.3.4"; sid:1;) -A big difference with capture filters is that logs such as http.log +A big difference with capture filters is that logs such as Eve or http.log are still generated for this traffic. suppress From cee5c9fa605a478db1bcd23493f54938ad614bb2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 13 Apr 2017 09:58:36 +0200 Subject: [PATCH 2548/2553] pcre: on ppc64 disable only for specific versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disable jit only for libpcre 8.39 and 8.40 as those were the buggy versions. Thanks to Zoltán Herczeg. --- configure.ac | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 91f4925d9d9a..5f5ae55ee447 100644 --- a/configure.ac +++ b/configure.ac @@ -554,9 +554,14 @@ case $host in *powerpc64*) - # on powerpc64, both gcc and clang lead to SIGILL in - # unittests when jit is enabled. - pcre_jit_available="no, pcre jit disabled for powerpc64" + PKG_CHECK_MODULES(LIBPCREVERSION, [libpcre = 8.39],[libpcre_ppc64_buggy_found1="yes"],[libprce_ppc64_buggy_found1="no"]) + PKG_CHECK_MODULES(LIBPCREVERSION, [libpcre = 8.40],[libpcre_ppc64_buggy_found2="yes"],[libprce_ppc64_buggy_found2="no"]) + + if test "$libprce_ppc64_buggy_found1" = "yes" || test "$libprce_ppc64_buggy_found2"; then + # on powerpc64, both gcc and clang lead to SIGILL in + # unittests when jit is enabled. + pcre_jit_available="no, pcre 8.39/8.40 jit disabled for powerpc64" + fi ;; *) # bug 1693, libpcre 8.35 is broken and debian jessie is still using that From e69ce30d87f3504b9ddbf1e0c1ea6fe4c7ed6733 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Sun, 9 Apr 2017 22:12:12 -0600 Subject: [PATCH 2549/2553] template script: typo in app-layer setup script Check for ed was failing, as it was actually looking for edx. --- scripts/setup-app-layer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setup-app-layer.sh b/scripts/setup-app-layer.sh index f7fa1ba6709e..73cd89f5b857 100755 --- a/scripts/setup-app-layer.sh +++ b/scripts/setup-app-layer.sh @@ -6,7 +6,7 @@ set -e #set -x # Fail if "ed" is not available. -if ! which edx > /dev/null 2>&1; then +if ! which ed > /dev/null 2>&1; then echo "error: the program \"ed\" is required for this script" exit 1 fi From 1223de42089a9747cef084cf7dd13d18c9b2c044 Mon Sep 17 00:00:00 2001 From: psanders240 Date: Thu, 16 Mar 2017 15:41:16 -0400 Subject: [PATCH 2550/2553] doc: Napatech docs improvement Fix errors and simplify filters. --- doc/userguide/capture-hardware/napatech.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/doc/userguide/capture-hardware/napatech.rst b/doc/userguide/capture-hardware/napatech.rst index fdd1e2bd9c51..2ac4aa685f30 100644 --- a/doc/userguide/capture-hardware/napatech.rst +++ b/doc/userguide/capture-hardware/napatech.rst @@ -106,7 +106,7 @@ Suricata Installation After downloading and extracting the Suricata tarball, you need to run configure to enable Napatech support and prepare for compilation:: - $ ./configure --enable_napatech --with-napatech-includes=/opt/napatech3/include --with-napatech-libraries=/opt/napatech3/lib + $ ./configure --enable-napatech --with-napatech-includes=/opt/napatech3/include --with-napatech-libraries=/opt/napatech3/lib $ make $ make install-full @@ -192,11 +192,7 @@ setup to support both tunneled and non-tunneled traffic. Create a file that cont Setup[numaNode=0] = streamid==5 Setup[numaNode=0] = streamid==6 Setup[numaNode=0] = streamid==7 - HashMode[priority=0; InnerLayer4Type=UDP, TCP, SCTP] = HashInner5TupleSorted - HashMode[priority=1; InnerLayer3Type=IPV4] = HashInner2TupleSorted - HashMode[priority=2; Layer4Type=UDP, TCP, SCTP] = Hash5TupleSorted - HashMode[priority=3; Layer3Type=IPV4] = Hash2TupleSorted - HashMode[priority=4]=HashRoundRobin + HashMode[priority=4]=Hash5TupleSorted Assign[priority=0; streamid=(0..7)]= all Next execute those command using the ntpl tool:: From 618f351210495a38d5d406e4a966f811942ee46c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 9 Apr 2017 21:04:14 +0200 Subject: [PATCH 2551/2553] cleanup: get rid of %llu format specifiers Use more explicit types instead. --- src/defrag-hash.c | 4 ++-- src/defrag-hash.h | 2 +- src/flow-private.h | 2 +- src/flow.c | 4 ++-- src/host.c | 6 +++--- src/host.h | 6 +++--- src/ippair.c | 6 +++--- src/ippair.h | 6 +++--- src/util-coredump-config.c | 6 +++--- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/defrag-hash.c b/src/defrag-hash.c index a5355ebda06b..54206b2c73cc 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -205,7 +205,7 @@ void DefragInitConfig(char quiet) (void) SC_ATOMIC_ADD(defrag_memuse, (defrag_config.hash_size * sizeof(DefragTrackerHashRow))); if (quiet == FALSE) { - SCLogConfig("allocated %llu bytes of memory for the defrag hash... " + SCLogConfig("allocated %"PRIu64" bytes of memory for the defrag hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(defrag_memuse), defrag_config.hash_size, (uintmax_t)sizeof(DefragTrackerHashRow)); @@ -239,7 +239,7 @@ void DefragInitConfig(char quiet) } if (quiet == FALSE) { - SCLogConfig("defrag memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("defrag memory usage: %"PRIu64" bytes, maximum: %"PRIu64, SC_ATOMIC_GET(defrag_memuse), defrag_config.memcap); } diff --git a/src/defrag-hash.h b/src/defrag-hash.h index 2d48393a77c4..5697fdb9582c 100644 --- a/src/defrag-hash.h +++ b/src/defrag-hash.h @@ -85,7 +85,7 @@ typedef struct DefragConfig_ { ((((uint64_t)SC_ATOMIC_GET(defrag_memuse) + (uint64_t)(size)) <= defrag_config.memcap)) DefragConfig defrag_config; -SC_ATOMIC_DECLARE(unsigned long long int,defrag_memuse); +SC_ATOMIC_DECLARE(uint64_t,defrag_memuse); SC_ATOMIC_DECLARE(unsigned int,defragtracker_counter); SC_ATOMIC_DECLARE(unsigned int,defragtracker_prune_idx); diff --git a/src/flow-private.h b/src/flow-private.h index 543170892f5a..9cfcf228637b 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -97,7 +97,7 @@ FlowBucket *flow_hash; FlowConfig flow_config; /** flow memuse counter (atomic), for enforcing memcap limit */ -SC_ATOMIC_DECLARE(long long unsigned int, flow_memuse); +SC_ATOMIC_DECLARE(uint64_t, flow_memuse); #endif /* __FLOW_PRIVATE_H__ */ diff --git a/src/flow.c b/src/flow.c index df4a79a7af6e..728145552b85 100644 --- a/src/flow.c +++ b/src/flow.c @@ -431,7 +431,7 @@ void FlowInitConfig(char quiet) (void) SC_ATOMIC_ADD(flow_memuse, (flow_config.hash_size * sizeof(FlowBucket))); if (quiet == FALSE) { - SCLogConfig("allocated %llu bytes of memory for the flow hash... " + SCLogConfig("allocated %"PRIu64" bytes of memory for the flow hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(flow_memuse), flow_config.hash_size, (uintmax_t)sizeof(FlowBucket)); @@ -459,7 +459,7 @@ void FlowInitConfig(char quiet) if (quiet == FALSE) { SCLogConfig("preallocated %" PRIu32 " flows of size %" PRIuMAX "", flow_spare_q.len, (uintmax_t)(sizeof(Flow) + + FlowStorageSize())); - SCLogConfig("flow memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("flow memory usage: %"PRIu64" bytes, maximum: %"PRIu64, SC_ATOMIC_GET(flow_memuse), flow_config.memcap); } diff --git a/src/host.c b/src/host.c index 8df0cde874e1..276d1b42ee17 100644 --- a/src/host.c +++ b/src/host.c @@ -210,7 +210,7 @@ void HostInitConfig(char quiet) (void) SC_ATOMIC_ADD(host_memuse, (host_config.hash_size * sizeof(HostHashRow))); if (quiet == FALSE) { - SCLogConfig("allocated %llu bytes of memory for the host hash... " + SCLogConfig("allocated %"PRIu64" bytes of memory for the host hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(host_memuse), host_config.hash_size, (uintmax_t)sizeof(HostHashRow)); @@ -237,7 +237,7 @@ void HostInitConfig(char quiet) if (quiet == FALSE) { SCLogConfig("preallocated %" PRIu32 " hosts of size %" PRIu16 "", host_spare_q.len, g_host_size); - SCLogConfig("host memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("host memory usage: %"PRIu64" bytes, maximum: %"PRIu64, SC_ATOMIC_GET(host_memuse), host_config.memcap); } @@ -252,7 +252,7 @@ void HostPrintStats (void) SCLogPerf("hostbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", hostbits_added, hostbits_removed, hostbits_memuse_max); #endif /* HOSTBITS_STATS */ - SCLogPerf("host memory usage: %llu bytes, maximum: %"PRIu64, + SCLogPerf("host memory usage: %"PRIu64" bytes, maximum: %"PRIu64, SC_ATOMIC_GET(host_memuse), host_config.memcap); return; } diff --git a/src/host.h b/src/host.h index e3dd167a2e31..d22f6f32f017 100644 --- a/src/host.h +++ b/src/host.h @@ -129,9 +129,9 @@ typedef struct HostConfig_ { } while (0) HostConfig host_config; -SC_ATOMIC_DECLARE(unsigned long long int,host_memuse); -SC_ATOMIC_DECLARE(unsigned int,host_counter); -SC_ATOMIC_DECLARE(unsigned int,host_prune_idx); +SC_ATOMIC_DECLARE(uint64_t,host_memuse); +SC_ATOMIC_DECLARE(uint32_t,host_counter); +SC_ATOMIC_DECLARE(uint32_t,host_prune_idx); void HostInitConfig(char quiet); void HostShutdown(void); diff --git a/src/ippair.c b/src/ippair.c index d7d3440c668a..29335996d044 100644 --- a/src/ippair.c +++ b/src/ippair.c @@ -206,7 +206,7 @@ void IPPairInitConfig(char quiet) (void) SC_ATOMIC_ADD(ippair_memuse, (ippair_config.hash_size * sizeof(IPPairHashRow))); if (quiet == FALSE) { - SCLogConfig("allocated %llu bytes of memory for the ippair hash... " + SCLogConfig("allocated %"PRIu64" bytes of memory for the ippair hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(ippair_memuse), ippair_config.hash_size, (uintmax_t)sizeof(IPPairHashRow)); @@ -233,7 +233,7 @@ void IPPairInitConfig(char quiet) if (quiet == FALSE) { SCLogConfig("preallocated %" PRIu32 " ippairs of size %" PRIu16 "", ippair_spare_q.len, g_ippair_size); - SCLogConfig("ippair memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("ippair memory usage: %"PRIu64" bytes, maximum: %"PRIu64, SC_ATOMIC_GET(ippair_memuse), ippair_config.memcap); } @@ -248,7 +248,7 @@ void IPPairPrintStats (void) SCLogPerf("ippairbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", ippairbits_added, ippairbits_removed, ippairbits_memuse_max); #endif /* IPPAIRBITS_STATS */ - SCLogPerf("ippair memory usage: %llu bytes, maximum: %"PRIu64, + SCLogPerf("ippair memory usage: %"PRIu64" bytes, maximum: %"PRIu64, SC_ATOMIC_GET(ippair_memuse), ippair_config.memcap); return; } diff --git a/src/ippair.h b/src/ippair.h index 79affc624535..812319e6f8bd 100644 --- a/src/ippair.h +++ b/src/ippair.h @@ -126,9 +126,9 @@ typedef struct IPPairConfig_ { } while (0) IPPairConfig ippair_config; -SC_ATOMIC_DECLARE(unsigned long long int,ippair_memuse); -SC_ATOMIC_DECLARE(unsigned int,ippair_counter); -SC_ATOMIC_DECLARE(unsigned int,ippair_prune_idx); +SC_ATOMIC_DECLARE(uint64_t,ippair_memuse); +SC_ATOMIC_DECLARE(uint32_t,ippair_counter); +SC_ATOMIC_DECLARE(uint32_t,ippair_prune_idx); void IPPairInitConfig(char quiet); void IPPairShutdown(void); diff --git a/src/util-coredump-config.c b/src/util-coredump-config.c index 9555e0fd7103..639abc19597e 100644 --- a/src/util-coredump-config.c +++ b/src/util-coredump-config.c @@ -71,7 +71,7 @@ int32_t CoredumpLoadConfig (void) SCLogInfo ("Illegal core dump size: %s.", dump_size_config); return 0; } - SCLogInfo ("Max dump is %llu", (unsigned long long) max_dump); + SCLogInfo ("Max dump is %"PRIu64, (uint64_t) max_dump); } #if defined OS_WIN32 @@ -165,7 +165,7 @@ int32_t CoredumpLoadConfig (void) new_lim.rlim_max = lim.rlim_max; } if (setrlimit (RLIMIT_CORE, &new_lim) == 0) { - SCLogInfo ("Core dump setting attempted is %llu", (unsigned long long) new_lim.rlim_cur); + SCLogInfo ("Core dump setting attempted is %"PRIu64, (uint64_t) new_lim.rlim_cur); struct rlimit actual_lim; if (getrlimit (RLIMIT_CORE, &actual_lim) == 0) { if (actual_lim.rlim_cur == RLIM_INFINITY) { @@ -177,7 +177,7 @@ int32_t CoredumpLoadConfig (void) } #endif else { - SCLogInfo ("Core dump size set to %llu", (unsigned long long) actual_lim.rlim_cur); + SCLogInfo ("Core dump size set to %"PRIu64, (uint64_t) actual_lim.rlim_cur); } } return 1; From a4dce241516badad534c98a1833ec963914c912a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 10 Apr 2017 09:38:59 +0200 Subject: [PATCH 2552/2553] core dumps: check for sys/resource.h --- configure.ac | 1 + src/util-coredump-config.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index 5f5ae55ee447..b833991b7b4c 100644 --- a/configure.ac +++ b/configure.ac @@ -133,6 +133,7 @@ AC_CHECK_HEADERS([linux/ethtool.h linux/sockios.h]) AC_CHECK_HEADER(glob.h,,[AC_ERROR(glob.h not found ...)]) AC_CHECK_HEADERS([dirent.h fnmatch.h]) + AC_CHECK_HEADERS([sys/resource.h]) AC_CHECK_HEADERS([sys/socket.h net/if.h sys/mman.h linux/if_arp.h], [], [], [[#ifdef HAVE_SYS_SOCKET_H diff --git a/src/util-coredump-config.c b/src/util-coredump-config.c index 639abc19597e..8677211b6064 100644 --- a/src/util-coredump-config.c +++ b/src/util-coredump-config.c @@ -26,7 +26,9 @@ #define _FILE_OFFSET_BITS 64 #include "util-coredump-config.h" #include "conf.h" +#ifdef HAVE_SYS_RESOURCE_H #include +#endif /** * \brief Configures the core dump size. @@ -36,6 +38,7 @@ */ int32_t CoredumpLoadConfig (void) { +#ifdef HAVE_SYS_RESOURCE_H /* get core dump configuration settings for suricata */ char* dump_size_config = NULL; rlim_t max_dump = 0; @@ -202,5 +205,6 @@ int32_t CoredumpLoadConfig (void) } /* failed to set the coredump limit */ SCLogInfo ("Could't set coredump size to %s.", dump_size_config); +#endif /* HAVE_SYS_RESOURCE_H */ return 0; } From 8f15e30a58e2f619555f2bd5ab7eaee7b42e88e2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 10 Apr 2017 09:39:23 +0200 Subject: [PATCH 2553/2553] common: improve byte order and wordsize detection --- src/suricata-common.h | 60 ++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/src/suricata-common.h b/src/suricata-common.h index 7fd68886d848..e8936307978b 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -278,37 +278,61 @@ /** Windows does not define __WORDSIZE, but it uses __X86__ */ #ifndef __WORDSIZE - #if defined(__X86__) || defined(_X86_) - #define __WORDSIZE 32 - #else - #if defined(__X86_64__) || defined(_X86_64_) - #define __WORDSIZE 64 - #endif - #endif - - #ifndef __WORDSIZE - #warning Defaulting to __WORDSIZE 32 + #if defined(__X86__) || defined(_X86_) || defined(_M_IX86) #define __WORDSIZE 32 + #else + #if defined(__X86_64__) || defined(_X86_64_) || \ + defined(__x86_64) || defined(__x86_64__) || \ + defined(__amd64) || defined(__amd64__) + #define __WORDSIZE 64 + #endif #endif #endif +/** if not succesful yet try the data models */ +#ifndef __WORDSIZE + #if defined(_ILP32) || defined(__ILP32__) + #define __WORDSIZE 32 + #endif + #if defined(_LP64) || defined(__LP64__) + #define __WORDSIZE 64 + #endif +#endif + +#ifndef __WORDSIZE + #warning Defaulting to __WORDSIZE 32 + #define __WORDSIZE 32 +#endif + /** darwin doesn't defined __BYTE_ORDER and friends, but BYTE_ORDER */ #ifndef __BYTE_ORDER -#ifdef BYTE_ORDER -#define __BYTE_ORDER BYTE_ORDER -#endif + #if defined(BYTE_ORDER) + #define __BYTE_ORDER BYTE_ORDER + #elif defined(__BYTE_ORDER__) + #define __BYTE_ORDER __BYTE_ORDER__ + #else + #error "byte order not detected" + #endif #endif #ifndef __LITTLE_ENDIAN -#ifdef LITTLE_ENDIAN -#define __LITTLE_ENDIAN LITTLE_ENDIAN -#endif + #if defined(LITTLE_ENDIAN) + #define __LITTLE_ENDIAN LITTLE_ENDIAN + #elif defined(__ORDER_LITTLE_ENDIAN__) + #define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ + #endif #endif #ifndef __BIG_ENDIAN -#ifdef BIG_ENDIAN -#define __BIG_ENDIAN BIG_ENDIAN + #if defined(BIG_ENDIAN) + #define __BIG_ENDIAN BIG_ENDIAN + #elif defined(__ORDER_BIG_ENDIAN__) + #define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ + #endif #endif + +#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) + #error "byte order: can't figure out big or little" #endif #ifndef HAVE_PCRE_FREE_STUDY

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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/configuration/suricata-yaml/threading.png b/doc/sphinx/configuration/suricata-yaml/threading.png new file mode 100644 index 0000000000000000000000000000000000000000..eea27add1e43525245518db4f336bcc8916f8070 GIT binary patch literal 17401 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 Date: Mon, 4 Jan 2016 11:38:06 -0600 Subject: [PATCH 1810/2553] doc: fixup references --- doc/sphinx/configuration/suricata-yaml.rst | 10 +++++++ .../file-extraction/file-extraction.rst | 5 +++- doc/sphinx/file-extraction/md5.rst | 2 ++ .../public-sha1-md5-data-sets.rst | 3 --- doc/sphinx/performance/packet-profiling.rst | 4 +-- doc/sphinx/performance/runmodes.rst | 8 +++--- doc/sphinx/rules/file-keywords.rst | 5 ++-- doc/sphinx/rules/flow-keywords.rst | 13 +++++----- doc/sphinx/rules/http-keywords.rst | 19 ++++++++------ doc/sphinx/rules/http-uri-normalization.rst | 10 +++++++ doc/sphinx/rules/intro.rst | 26 +++++++++---------- doc/sphinx/rules/normalized-buffers.rst | 3 +++ doc/sphinx/rules/payload-keywords.rst | 2 +- doc/sphinx/rules/pcre.rst | 4 +-- doc/sphinx/rules/thresholding.rst | 4 +-- doc/sphinx/setting-up-ipsinline-for-linux.rst | 2 +- 16 files changed, 75 insertions(+), 45 deletions(-) create mode 100644 doc/sphinx/rules/http-uri-normalization.rst diff --git a/doc/sphinx/configuration/suricata-yaml.rst b/doc/sphinx/configuration/suricata-yaml.rst index 8f78cff227e9..7dd34ca81c38 100644 --- a/doc/sphinx/configuration/suricata-yaml.rst +++ b/doc/sphinx/configuration/suricata-yaml.rst @@ -8,6 +8,8 @@ Suricata. This document will explain each option. At the top of the YAML-file you will find % YAML 1.1. Suricata reads the file and identifies the file as YAML. +.. _suricata-yaml-max-pending-packets: + Max-pending-packets ------------------- @@ -64,6 +66,8 @@ It is possible to set the user and group to run Suricata as: group: suri +.. _suricata-yaml-action-order: + Action-order ------------ @@ -952,6 +956,8 @@ seconds. Flow and Stream handling ------------------------ +.. _suricata-yaml-flow-settings: + Flow Settings ~~~~~~~~~~~~~ @@ -1213,6 +1219,8 @@ Limit for the maximum number of asn1 frames to decode (default 256): asn1_max_frames: 256 +.. _suricata-yaml-configure-libhtp: + Configure HTTP (libhtp) ~~~~~~~~~~~~~~~~~~~~~~~ @@ -1692,6 +1700,8 @@ You can set the direction of the classification configuration. classification-file: /etc/suricata/classification.config +.. _suricata-yaml-rule-vars: + Rule-vars ~~~~~~~~~ diff --git a/doc/sphinx/file-extraction/file-extraction.rst b/doc/sphinx/file-extraction/file-extraction.rst index 853cb12ce3d7..2cd9e710f740 100644 --- a/doc/sphinx/file-extraction/file-extraction.rst +++ b/doc/sphinx/file-extraction/file-extraction.rst @@ -82,7 +82,10 @@ Please make sure you choose the appropriate interface name (eth0,eth1,eth5...) Output ~~~~~~ -For file extraction two separate output modules were created: "file-log" and "file-store". They need to be enabled in the [[suricata.yaml]]. For "file-store", the "files" drop dir must be configured. +For file extraction two separate output modules were created: +"file-log" and "file-store". They need to be enabled in the +:doc:`../configuration/suricata-yaml`. For "file-store", the "files" +drop dir must be configured. :: diff --git a/doc/sphinx/file-extraction/md5.rst b/doc/sphinx/file-extraction/md5.rst index 1e38313738a1..419a3970b06f 100644 --- a/doc/sphinx/file-extraction/md5.rst +++ b/doc/sphinx/file-extraction/md5.rst @@ -1,3 +1,5 @@ +.. _md5: + Storing MD5s checksums ====================== diff --git a/doc/sphinx/file-extraction/public-sha1-md5-data-sets.rst b/doc/sphinx/file-extraction/public-sha1-md5-data-sets.rst index 373a52ecc4e2..f5e7d09b3e32 100644 --- a/doc/sphinx/file-extraction/public-sha1-md5-data-sets.rst +++ b/doc/sphinx/file-extraction/public-sha1-md5-data-sets.rst @@ -1,7 +1,4 @@ Public SHA1 MD5 data sets ========================= - - - National Software Reference Library - http://www.nsrl.nist.gov/Downloads.htm diff --git a/doc/sphinx/performance/packet-profiling.rst b/doc/sphinx/performance/packet-profiling.rst index f93deb6c04bb..910f8be4255f 100644 --- a/doc/sphinx/performance/packet-profiling.rst +++ b/doc/sphinx/performance/packet-profiling.rst @@ -27,8 +27,8 @@ sure you enter the following during the configuring stage: ./configure --enable-profiling Find a folder in which you have pcaps. If you do not have pcaps yet, -you can get these with Wireshark. See [[Sniffing Packets with -Wireshark]]. +you can get these with Wireshark. See `Sniffing Packets with Wireshark +`_. Go to the directory of your pcaps. For example: diff --git a/doc/sphinx/performance/runmodes.rst b/doc/sphinx/performance/runmodes.rst index 0927501e12c3..8f05f8de9f38 100644 --- a/doc/sphinx/performance/runmodes.rst +++ b/doc/sphinx/performance/runmodes.rst @@ -10,10 +10,10 @@ another one the output-module. A packet can be processed by more than one thread. The packet will be passed on to the next thread through a queue. Packets will be processed by one thread at a time, but there can be multiple packets being processed at a time by the engine. (see -[[**FIXME** suricata.yaml#max-pending-packets]]) A thread can have one or more -thread-modules. If they have more modules, they can only be active on -a a time. The way threads, modules and queues are arranged together -is called the Runmode. +:ref:`suricata-yaml-max-pending-packets`) A thread can have one or +more thread-modules. If they have more modules, they can only be +active on a a time. The way threads, modules and queues are arranged +together is called the Runmode. Different runmodes ~~~~~~~~~~~~~~~~~~ diff --git a/doc/sphinx/rules/file-keywords.rst b/doc/sphinx/rules/file-keywords.rst index 4f13cceb3cfa..44c5b667a9ec 100644 --- a/doc/sphinx/rules/file-keywords.rst +++ b/doc/sphinx/rules/file-keywords.rst @@ -2,7 +2,8 @@ File Keywords ============= Suricata comes with several rule keywords to match on various file -properties. They depend on properly configured [[**FIXME** File Extraction]]. +properties. They depend on properly configured +:doc:`../file-extraction/file-extraction`. filename -------- @@ -73,7 +74,7 @@ the rule and the scope will be per file. filemd5 ------- -Match file [[**FIXME** MD5]] against list of MD5 checksums. +Match file :ref:`MD5 ` against list of MD5 checksums. Syntax:: diff --git a/doc/sphinx/rules/flow-keywords.rst b/doc/sphinx/rules/flow-keywords.rst index 06658eebcc4c..ba057fd99a46 100644 --- a/doc/sphinx/rules/flow-keywords.rst +++ b/doc/sphinx/rules/flow-keywords.rst @@ -9,12 +9,13 @@ is going to perform, the second part is the name of the flowbit. There are multiple packets that belong to one flow. Suricata keeps those flows in memory. For more information see -[[**FIXME** suricata.yaml#Flow]]. Flowbits can make sure an alert will be -generated when for example two different packets match. An alert will -only be generated when both packets match. So, when the second packet -matches, Suricata has to know if the first packet was a match -too. Flowbits marks the flow if a packet matches so Suricata 'knows' -it should generate an alert when the second packet matches as well. +:ref:`suricata-yaml-flow-settings`. Flowbits can make sure an alert +will be generated when for example two different packets match. An +alert will only be generated when both packets match. So, when the +second packet matches, Suricata has to know if the first packet was a +match too. Flowbits marks the flow if a packet matches so Suricata +'knows' it should generate an alert when the second packet matches as +well. Flowbits have different actions. These are: diff --git a/doc/sphinx/rules/http-keywords.rst b/doc/sphinx/rules/http-keywords.rst index 53aa36c11163..9584014a2fd4 100644 --- a/doc/sphinx/rules/http-keywords.rst +++ b/doc/sphinx/rules/http-keywords.rst @@ -108,8 +108,8 @@ mentioned content modifiers like ``depth``, ``distance``, ``offset``, ``nocase`` and ``within``. To learn more about the difference between ``http_uri`` and -``http_raw_uri``, please read the information about [[**FIXME** -HTTP-uri normalization]]. +``http_raw_uri``, please read the information about +:doc:`http-uri-normalization`. Example of the URI in a HTTP request: @@ -236,8 +236,9 @@ Example of the purpose of ``http_client_body``: .. image:: http-keywords/client_body1.png Note: how much of the request/client body is inspected is controlled -in the [[**FIXME** suricata.yaml#Configure-Libhtp]], in the "libhtp" section, -via the ``request-body-limit`` setting. +in the :ref:`libhtp configuration section +` via the ``request-body-limit`` +setting. http_stat_code -------------- @@ -283,8 +284,9 @@ response body is *gzip* encoded, it is first uncompressed for inspection. Note: how much of the response/server body is inspected is controlled -in your [[**FIXME** suricata.yaml#Configure-Libhtp]], in the "libhtp" section, -via the ``response-body-limit`` setting. +in your :ref:`libhtp configuration section +` via the ``response-body-limit`` +setting. http_host and http_raw_host --------------------------- @@ -322,8 +324,9 @@ content match individually. If the response body is *gzip* encoded, it is first uncompressed for inspection. Note: how much of the response/server body is inspected is controlled -in your [[**FIXME** suricata.yaml#Configure-Libhtp]], in the "libhtp" section -via the ``response-body-limit`` setting. +in your :ref:`libhtp configuration section +` via the ``response-body-limit`` +setting. **NOTE:** In 2.0.x, ``file_data`` is only supported for HTTP server bodies (specified as flow direction **to_client**). Starting with diff --git a/doc/sphinx/rules/http-uri-normalization.rst b/doc/sphinx/rules/http-uri-normalization.rst new file mode 100644 index 000000000000..20d9b14bc69a --- /dev/null +++ b/doc/sphinx/rules/http-uri-normalization.rst @@ -0,0 +1,10 @@ +HTTP-uri normalization +====================== + +The uri has two appearances in Suricata: the raw_uri and the +normalized uri. The space for example can be indicated with the +heximal notation %20. To convert this notation in a space, means +normalizing it. It is possible though to match specific on the +characters %20 in a uri. This means matching on the raw_uri. The +raw_uri and the normalized uri are separate buffers. So, the raw_uri +inspects the raw_uri buffer and can not inspect the normalized buffer. diff --git a/doc/sphinx/rules/intro.rst b/doc/sphinx/rules/intro.rst index e834c31e5901..726c9171a25e 100644 --- a/doc/sphinx/rules/intro.rst +++ b/doc/sphinx/rules/intro.rst @@ -5,11 +5,11 @@ Rules Introduction Signatures play a very important role in Suricata. In most occasions people are using existing rulesets. The most used are `Emerging -Threats `_, `Emerging Threats -Pro `_ and Sourcefire's -`VRT `_. A way to install rules is described -in [[**FIXME** Rule Management with Oinkmaster]]. This Suricata Rules document -explains all about signatures; how to read-, adjust-and create them. +Threats `_, `Emerging Threats Pro +`_ and Sourcefire's `VRT +`_. A way to install rules is described in +:doc:`../oinkmaster`. This Suricata Rules document explains all about +signatures; how to read-, adjust-and create them. A rule/signature consists of the following: @@ -22,8 +22,8 @@ Example of a signature: Action ------ -For more information read 'Action Order' in the -[[**FIXME** suricata.yaml#Action-order]] wiki. +For more information read 'Action Order' see +:ref:`suricata-yaml-action-order`. Example: @@ -54,11 +54,11 @@ Source and destination In source you can assign IP-addresses; IPv4 and IPv6 combined as well as separated. You can also set variables such as HOME_NET. (For more -information see 'Rule-vars' at [[**FIXME** Suricata.yaml#Rule-vars]] in the user -guide.) In the Yaml-file you can set IP-addresses for variables such -as EXTERNAL_NET and HOME_NET. These settings will be used when you use -these variables in a rule. In source and destination you can make use -of signs like ! And [ ]. +information see :ref:`suricata-yaml-rule-vars`. In the Yaml-file you +can set IP-addresses for variables such as EXTERNAL_NET and +HOME_NET. These settings will be used when you use these variables in +a rule. In source and destination you can make use of signs like ! +And [ ]. For example:: @@ -180,4 +180,4 @@ following headlines: * :doc:`http-keywords` * :doc:`dns-keywords` * :doc:`flow-keywords` -* **FIXME** [[IPReputationRules|IP Reputation keyword]] +* :doc:`../reputation/ipreputation/ip-reputation-rules` diff --git a/doc/sphinx/rules/normalized-buffers.rst b/doc/sphinx/rules/normalized-buffers.rst index 111bb9716377..a3a282a95f83 100644 --- a/doc/sphinx/rules/normalized-buffers.rst +++ b/doc/sphinx/rules/normalized-buffers.rst @@ -1,6 +1,9 @@ Normalized Buffers ================== +.. toctree:: + + http-uri-normalization A packet consists of raw data. HTTP and reassembly make a copy of those kinds of packets data. They erase anomalous content, combine diff --git a/doc/sphinx/rules/payload-keywords.rst b/doc/sphinx/rules/payload-keywords.rst index 7af5fc21c9b4..b5f400ac4514 100644 --- a/doc/sphinx/rules/payload-keywords.rst +++ b/doc/sphinx/rules/payload-keywords.rst @@ -285,7 +285,7 @@ another ('def'), see example: The replace modifier has to contain as many characters as the content it replaces. It can only be used with individual packets. It will not -work for [[**FIXME** Normalized Buffers]] like HTTP uri or a content match in +work for :doc:`normalized-buffers` like HTTP uri or a content match in the reassembled stream. The checksums will be recalculated by Suricata and changed after the diff --git a/doc/sphinx/rules/pcre.rst b/doc/sphinx/rules/pcre.rst index a0df46fc3b39..9af548421403 100644 --- a/doc/sphinx/rules/pcre.rst +++ b/doc/sphinx/rules/pcre.rst @@ -64,7 +64,7 @@ Suricata has its own specific pcre modifiers. These are: uri_buffer just like uricontent and content combined with http_uri.U can be combined with /R. Note that R is relative to the previous match so both matches have to be in the HTTP-uri buffer. Read more - about [[**FIXME** HTTP-uri normalization]]. + about :doc:`http-uri-normalization`. .. image:: pcre/pcre3.png @@ -77,7 +77,7 @@ Suricata has its own specific pcre modifiers. These are: * ``I``: Makes pcre match on the HTTP-raw-uri. It matches on the same buffer as http_raw_uri. I can be combined with /R. Note that R is relative to the previous match so both matches have to be in the - HTTP-raw-uri buffer. Read more about [[**FIXME** HTTP-uri normalization]]. + HTTP-raw-uri buffer. Read more about :doc:`http-uri-normalization`. ** FIXME - image is missing on wiki: .. image:: pcre/pcre7.png diff --git a/doc/sphinx/rules/thresholding.rst b/doc/sphinx/rules/thresholding.rst index 2782087db9ae..196f20a3408a 100644 --- a/doc/sphinx/rules/thresholding.rst +++ b/doc/sphinx/rules/thresholding.rst @@ -2,11 +2,11 @@ Rule Thresholding ================= Thresholding can be configured per rule and also globally, see -[[**FIXME** Global-Thresholds]]. +:doc:`../configuration/global-thresholds`. *Note: mixing rule and global thresholds is not supported in 1.3 and before. See bug #425.* For the state of the support in 1.4 see -[[**FIXME** Global-Thresholds#Global-thresholds-vs-rule-thresholds]]. +:ref:`global-thresholds-vs-rule-thresholds` threshold --------- diff --git a/doc/sphinx/setting-up-ipsinline-for-linux.rst b/doc/sphinx/setting-up-ipsinline-for-linux.rst index 0a4b956c87c9..470f2a1748a5 100644 --- a/doc/sphinx/setting-up-ipsinline-for-linux.rst +++ b/doc/sphinx/setting-up-ipsinline-for-linux.rst @@ -4,7 +4,7 @@ Setting up IPS/inline for Linux In this guide will be explained how to work with Suricata in layer3 inline mode and how to set iptables for that purpose. First start with compiling Suricata with NFQ support. For instructions see [[**FIXME** Ubuntu Installation]]. -For more information about NFQ and iptables, see [[**FIXME** suricata.yaml#NFQ]]. +For more information about NFQ and iptables, see :ref:`suricata-yaml-nfq`. To check if you have NFQ enabled in your Suricata, enter the following command: From 2fa4547197d584f36808184d2c696ab172df32ce Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 4 Jan 2016 11:50:09 -0600 Subject: [PATCH 1811/2553] doc: reference fixups --- doc/sphinx/command-line-options.rst | 3 ++- doc/sphinx/dropping-privileges.rst | 8 +++++--- doc/sphinx/performance/packet-profiling.rst | 5 +++-- doc/sphinx/rules/rule-lua-scripting.rst | 3 ++- doc/sphinx/setting-up-ipsinline-for-linux.rst | 7 +++++-- doc/sphinx/what-is-suricata.rst | 2 -- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/doc/sphinx/command-line-options.rst b/doc/sphinx/command-line-options.rst index 2857d5032ad3..80542da49c82 100644 --- a/doc/sphinx/command-line-options.rst +++ b/doc/sphinx/command-line-options.rst @@ -51,8 +51,9 @@ this: --runmode (in combination with the command line opion -i or -r) With the --runmode option you can set the runmode that you would like to use. This command line option can override the - yaml runmode option. For more information about runmodes see: [[Runmodes]]. + yaml runmode option. +For more information about runmodes see: :doc:`performance/runmodes` Unit Tests ~~~~~~~~~~ diff --git a/doc/sphinx/dropping-privileges.rst b/doc/sphinx/dropping-privileges.rst index 6edfa36a1168..bdcd930d631a 100644 --- a/doc/sphinx/dropping-privileges.rst +++ b/doc/sphinx/dropping-privileges.rst @@ -18,9 +18,11 @@ http://people.redhat.com/sgrubb/libcap-ng/ChangeLog make install Download, configure, compile, and install Suricata for your particular -setup. See [[**FIXME** Suricata Installation]] Depending on your environment, -you may need to add the --with-libpcap_ng-libraries and ---with-libpcap_ng-includes options during the configure step. e.g: +setup. See `Suricata Installation +`_. Depending +on your environment, you may need to add the +--with-libpcap_ng-libraries and --with-libpcap_ng-includes options +during the configure step. e.g: :: diff --git a/doc/sphinx/performance/packet-profiling.rst b/doc/sphinx/performance/packet-profiling.rst index 910f8be4255f..3912d26925a2 100644 --- a/doc/sphinx/performance/packet-profiling.rst +++ b/doc/sphinx/performance/packet-profiling.rst @@ -11,8 +11,9 @@ packets take to be processed. It is a way to figure out why certain packets are being processed quicker than others, and this way a good tool for developing Suricata. -Update Suricata by following the steps from [[Installation from -Git]]. Start at the end at +Update Suricata by following the steps from `Installation from Git +`_. Start +at the end at :: diff --git a/doc/sphinx/rules/rule-lua-scripting.rst b/doc/sphinx/rules/rule-lua-scripting.rst index c142eeca5083..91f3de1af8f3 100644 --- a/doc/sphinx/rules/rule-lua-scripting.rst +++ b/doc/sphinx/rules/rule-lua-scripting.rst @@ -2,7 +2,8 @@ Lua Scripting ============= In order to enable Lua scripting, please reference this page before -continuing [[**FIXME** Installation from GIT with luajit]]. +continuing `Installation from GIT with luajit +`_. Syntax: diff --git a/doc/sphinx/setting-up-ipsinline-for-linux.rst b/doc/sphinx/setting-up-ipsinline-for-linux.rst index 470f2a1748a5..0a73c87610be 100644 --- a/doc/sphinx/setting-up-ipsinline-for-linux.rst +++ b/doc/sphinx/setting-up-ipsinline-for-linux.rst @@ -3,8 +3,11 @@ Setting up IPS/inline for Linux In this guide will be explained how to work with Suricata in layer3 inline mode and how to set iptables for that purpose. -First start with compiling Suricata with NFQ support. For instructions see [[**FIXME** Ubuntu Installation]]. -For more information about NFQ and iptables, see :ref:`suricata-yaml-nfq`. +First start with compiling Suricata with NFQ support. For instructions +see `Ubuntu Installation +`_. +For more information about NFQ and iptables, see +:ref:`suricata-yaml-nfq`. To check if you have NFQ enabled in your Suricata, enter the following command: diff --git a/doc/sphinx/what-is-suricata.rst b/doc/sphinx/what-is-suricata.rst index 920f081a7d01..60c1b46efe86 100644 --- a/doc/sphinx/what-is-suricata.rst +++ b/doc/sphinx/what-is-suricata.rst @@ -64,5 +64,3 @@ Ristic of Mod Security fame for the OISF. This integrates and provides very advanced processing of HTTP streams for Suricata. The HTP library is required by the engine, but may also be used independently in a range of applications and tools. - -[[**FIXME** Major Features|Next]] From 398151ac765283e517da29c74e68d5b86a70f7ee Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Tue, 5 Jan 2016 03:16:13 +0100 Subject: [PATCH 1812/2553] doc: added output section (some fixes still to do) --- doc/sphinx/index.rst | 1 + .../output/.custom-http-logging.rst.swp | Bin 0 -> 12288 bytes doc/sphinx/output/.index.rst.swp | Bin 0 -> 12288 bytes doc/sphinx/output/.mongodb.rst.swp | Bin 0 -> 16384 bytes .../output/.syslog-alerting-comp.rst.swp | Bin 0 -> 12288 bytes doc/sphinx/output/custom-http-logging.rst | 54 ++++ doc/sphinx/output/eve/eve-json-examplesjq.rst | 80 ++++++ doc/sphinx/output/eve/eve-json-format.rst | 196 +++++++++++++++ doc/sphinx/output/eve/eve-json-output.rst | 101 ++++++++ doc/sphinx/output/eve/index.rst | 8 + .../.files-json-log-output.rst.swp | Bin 0 -> 12288 bytes .../files-json-log-output.rst | 62 +++++ ...gstash-kibana-and-suricata-json-output.rst | 236 ++++++++++++++++++ .../Logstash1.png | Bin 0 -> 77479 bytes .../Logstash2.png | Bin 0 -> 136602 bytes .../Logstash3.png | Bin 0 -> 29420 bytes .../Logstash4.png | Bin 0 -> 125520 bytes .../Logstash5.png | Bin 0 -> 17819 bytes .../Logstash6.png | Bin 0 -> 83024 bytes .../output/files-json-log-output/mongodb.rst | 97 +++++++ .../output/files-json-log-output/mysql.rst | 36 +++ .../files-json-log-output/postgresql.rst | 80 ++++++ .../script-follow-json.rst | 98 ++++++++ ...seful-queries-for-mysql-and-postgresql.rst | 138 ++++++++++ doc/sphinx/output/index.rst | 11 + doc/sphinx/output/syslog-alerting-comp.rst | 63 +++++ 26 files changed, 1261 insertions(+) create mode 100644 doc/sphinx/output/.custom-http-logging.rst.swp create mode 100644 doc/sphinx/output/.index.rst.swp create mode 100644 doc/sphinx/output/.mongodb.rst.swp create mode 100644 doc/sphinx/output/.syslog-alerting-comp.rst.swp create mode 100644 doc/sphinx/output/custom-http-logging.rst create mode 100644 doc/sphinx/output/eve/eve-json-examplesjq.rst create mode 100644 doc/sphinx/output/eve/eve-json-format.rst create mode 100644 doc/sphinx/output/eve/eve-json-output.rst create mode 100644 doc/sphinx/output/eve/index.rst create mode 100644 doc/sphinx/output/files-json-log-output/.files-json-log-output.rst.swp create mode 100644 doc/sphinx/output/files-json-log-output/files-json-log-output.rst create mode 100644 doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst create mode 100644 doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash1.png create mode 100644 doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash2.png create mode 100644 doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash3.png create mode 100644 doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash4.png create mode 100644 doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash5.png create mode 100644 doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash6.png create mode 100644 doc/sphinx/output/files-json-log-output/mongodb.rst create mode 100644 doc/sphinx/output/files-json-log-output/mysql.rst create mode 100644 doc/sphinx/output/files-json-log-output/postgresql.rst create mode 100644 doc/sphinx/output/files-json-log-output/script-follow-json.rst create mode 100644 doc/sphinx/output/files-json-log-output/useful-queries-for-mysql-and-postgresql.rst create mode 100644 doc/sphinx/output/index.rst create mode 100644 doc/sphinx/output/syslog-alerting-comp.rst diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 23d9abe9b818..02b03ffd64c3 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -16,6 +16,7 @@ Suricata User Guide reputation/index.rst initscripts setting-up-ipsinline-for-linux + output/index.rst file-extraction/file-extraction.rst public-data-sets capture-hardware/index.rst diff --git a/doc/sphinx/output/.custom-http-logging.rst.swp b/doc/sphinx/output/.custom-http-logging.rst.swp new file mode 100644 index 0000000000000000000000000000000000000000..8f40092872278afb4d7fa267bba193d607c7a372 GIT binary patch literal 12288 zcmeHNO^+N$8LmLWcleYD7o-K?&(?YWVTI$mIQm3WTVBg!%7%gHQhDS757wi zs;YNp)-n75IBynA>=uSC}vuFo^}&zFAmZvEwy{o`fExXPt}{j7_dtXSA*^ zJ>UfRE^zBJjC}`q8#n@9{WN1=2cG{FV;=?n_({h80Q>}a4|o&!0`U7!F!np30RH}Q z#{LHU7|4LH0>Akf>I?t@ya^0}uK+Ir-p8MNKf9}Apkv@e!N9&+k+T09CwD*C zrbQu)ppz4lmRuoxU&?eYt}^yA^^U1eR+v+)R%zo%)$@rkzGeSW%i%HcJckL^H&kfI zN(pl=4&jel9v^as2Dp$(E8(h>b8q$j{{OGu*y88izP0@5+}6rYQS+HatS&J-lpu9b_aRG6|^^OmrcR#wnKGm88uKg%~U5c&vh zR-QGg^crm)Om<%x@A;0l>F8>sU?X?6ZL}ECVQ?Vhm>Uc43=%>y9qvQOJp@7%A&r~0 zDZR%Ngvov3+9ieq)cugB@T7l3n*}$y$o+2*WlEv!E(E|MX*Ry{#=Dll3qym`fg#$G zaNM*p$l)%62G*k7Z@Ib}R=$G{eLe$ye$gX+h5+XAZZx2+lO(xLcP6!R^>unns(MLs zG#*_ibDAbeG`LDPMRs4u!$C5@PeM1O5mUX4ePa`<4>os7K6|I$uOXVvjcQcjH=)Mh zJGb5fhgn(Ys68a~H7li73g)Ky=`8`t&+Bkm}}&;!Z&zXT@3?gTF*)mWqQuoZAiS7 zXoo^tFW^qf*r6j^=(|3nWbEN zb7&@<*R?dH7b+O!7nRdy#)Y&6IgQ{J!EC95%Lx4Kwg;?I!n>tuu5&qEHF5IT;=V0x zID*q50eQoFYf-`CGDrMlX2M}IufRFN>4}sPg;a$d{LiVI8XptjbitdG~H2u2VUIl<={^cYK( zi)FN&mxPQ#O=6;CZx|(`ag;=RNqTKJ8H}m_ns39~Q8e7$jgoOXMi{106Fr_rhp>B) zjFP?oDklqV%6yZNf-AUt-}dioBY5AfszPhkpXidGaC$@UnZfN4=Y#T6DSBg^r5!&8cv)?)cH)j z^3k0lK+j)=cnV!py3~8nd!yewNP9YY99@WH#yW5Fj$q){Y6q+uL~I68Yg z^&eHQ;hQV%9bdYzTySK=349?o)#K;Z2ZLy9eNy8S@v+Fq;nZH9VxL=6T5s2RQ{X7j zhL`=Ohp$af@ze<4-wxZ|ey1&Mk5+tMVn-2FO~zRlv?E!C4-=oqM2>vJJ@sA!7JI(m qd|j+3p(NTt?0d~*T&;JDubuF7p8Kk+CYtg0^ph8RJ@B$Qfc*<}VB@y{ literal 0 HcmV?d00001 diff --git a/doc/sphinx/output/.index.rst.swp b/doc/sphinx/output/.index.rst.swp new file mode 100644 index 0000000000000000000000000000000000000000..cfd31020081d4caf33d3442d3e210222119ebdb8 GIT binary patch literal 12288 zcmeI&v2N2q7zgk#tW^QEV;4iEZ08GYB~VZwphLw(_RGbwFHL-w?+jrnOSe8k=RN^T z_r3ue5)+DW3llddX_R$j@G)zTH2$>-8mzNox3`6!vkrSt8Z zq5=XCXcwsbSiD%L-JNH>P`v&0Nwm4~x_uogAOHafKmY;|fB*y_0D*fW;EN8u=eK## zywO^7?fh|VhPXfg0uX=z1Rwwb2tWV=5P$##AaDl-)QIToL!#azet7==zx@CIlgB?e z-#OQuE6zvG2hJJigrhlOU6-@P`NsQv;e6s;az1m=AOHafKmY;|fB*y_009U<00RF> zAc~@?O`TUR6GvvKawYhn`OWN2r@noAv@90Ov*=>tY%Uh3&{s--ceyt<)5I+b`FERQ z`On$<2s mtO)ae?^mhjLBj3iO|p7~K8_=AwJ(#T-zVCy8@;Me+S4z*8lPtX literal 0 HcmV?d00001 diff --git a/doc/sphinx/output/.mongodb.rst.swp b/doc/sphinx/output/.mongodb.rst.swp new file mode 100644 index 0000000000000000000000000000000000000000..e07477ba338a00305b275652c1c539017f66a284 GIT binary patch literal 16384 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/output/.syslog-alerting-comp.rst.swp b/doc/sphinx/output/.syslog-alerting-comp.rst.swp new file mode 100644 index 0000000000000000000000000000000000000000..24ad1a76e335428e22c0bdf8674420fac7e0e2ae GIT binary patch literal 12288 zcmeHN&5smC6faa%RMd!)Xhe&}O<*%0EFVG!{2&AZ2?%kK#G5tU)iVV>U7f1xT_!Pl zQcS#X)c6O8R})Q4JZR912NO+9JaaVh5Ab6Ay;t3{1M=Zj(i7g!Y)$q1_`TnIuQt?h z_xY2j<$>Nlf!C8lJiqPZ^Pe3Wh!2*8P(^BJ`ED=elJT0q+b$vABZd9a*$X-ezV9n% z5*1WGwMpNXV^dt}+bWb*==-V9?Wn7A?Sd&r-Na7Hp7Y`EHrgF60xbf!K%fd)_uyu+ zchB-}`gX^{cDd!Lw{EeqU1||%5oi%;5oi%;5oi%;5oi%;5x7?o2;~OxK7zZi4)C@5 zeZx)f^{?$)i$IG&i$IG&i$IG&i$IG&i$IG&i$IG&i$IIO{}2I{3h@*E_`iNXoX7wF zH-G@(kqn2ZZY~`5p4R;%%^gwWooiaJ6!~6 z3OR)msf$(PY%!s=RF@hTdWsQr$+fWxGG5z}snQc$cvib|^4Mv5R90|cSOqz@rOv7x z2H2fw(;DcbU9c0zS~@ct!+>$PC}eEWLvJ7juE#fm1r{u8t=)s3RqYUM81r(_06_)7P?ovT>42=gG+S+ycjUt1 z#j|goTzqvgDhg^eSRU-%v$#0%qrqU{%dW|~h3zi;(DfxRFD}gabOKls{;HTEzc!{d z3VEfz4Mk3S>u4XjPw>`$Pqg=Hq>;ixy116g%(@AXCuCU*!Hq}trIMh-!<5@nIZvOl zV?s|WQpt$b&-bJ}8IiATCAP@SsB((nmze=cc2>UfiV_D6eI1gBpyF=}HPJFR7m>QC zp+_1d;+Xq&R|k7>i%Y6By#aY3-iFL=o=;6-R=H|LyIX&U2>sjs`hdzg9?zZ&uU3 zg9?`;tj?_J%yAanFP&5ry@foD)$uq-MV=GTQitsXbz}fYkF`>W< zJt$MgVJ{OhrM5$fn9JnMY2t7us{+>wH4%?eO3pUwx$CX_6%@#-A_16B_(9uy@;Dx@ zJ7b4@q|OLlt-IGD7Dd#&d{>T~E^7<`T#|Be^i5$x@1~9f$H?=EDyC35Wv*rhG{UvV zJCU~H>gDcPw-D;y(6C-Ob^YA_O&o_I%KIIPgY5_b7zw;Ot#yZ?l{@q(Axc(GIsFxSDD|FsK;#qf7 z!mOKjK^1(P?c({PsG<6*EUgRj+|jcgdG6FoM^36dm~I$5t%!deHg5qTohHVrNRW|C ztAMigvI&K5{}!YFW)J54oIPsGH>pS4pllnOB(w-GIn|7J=X?`f3HdTjk%O(qqo6bF2qiSrd*@0zdF zlnRLGcB7)q*~xlEqk7_bj#_L@@f#d&CTH{IyahV1PMyT)NFj{J~e@w`kJwhuU16K_lWIz@4G?R?^Xe9yvRDxFNw8=F& zBNN2sRE~Z>YI+Y&HXUwQxgi!tVxpIWPh9yH#X}y_U@3fX6(0(?_jn!R9_mF^*;H_5 zQEOEC6kKnrCOMaAv(g+Z;-Qba0>v_GOtCYEX~_*NhPZRa=3V6ah#aE_*Lc*^2nRH; X-03A&;&eVz-=&vF>lSTt6Q<%HmaB5g literal 0 HcmV?d00001 diff --git a/doc/sphinx/output/custom-http-logging.rst b/doc/sphinx/output/custom-http-logging.rst new file mode 100644 index 000000000000..9ddb5ba80a84 --- /dev/null +++ b/doc/sphinx/output/custom-http-logging.rst @@ -0,0 +1,54 @@ +Custom http logging +=================== + +As of Suricata 1.3.1 you can enable a custom http logging option. + +In your Suricata.yaml, find the http-log section and edit as follows: + + +:: + + + - http-log: + enabled: yes + filename: http.log + custom: yes # enable the custom logging format (defined by custom format) + customformat: "%{%D-%H:%M:%S}t.%z %{X-Forwarded-For}i %{User-agent}i %H %m %h %u %s %B %a:%p -> %A:%P" + append: no + #extended: yes # enable this for extended logging information + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + +And in your http.log file you would get the following, for example: + +:: + + 8/28/12-22:14:21.101619 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:11.0) Gecko/20100101 Firefox/11.0 HTTP/1.1 GET us.cnn.com /video/data/3.0/video/world/2012/08/28/hancocks-korea-typhoon-bolavan.cnn/index.xml 200 16856 192.168.1.91:45111 -> 157.166.255.18:80 + +:: + + 08/28/12-22:14:30.693856 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:11.0) Gecko/20100101 Firefox/11.0 HTTP/1.1 GET us.cnn.com /video/data/3.0/video/showbiz/2012/08/28/conan-reports-from-rnc-convention.teamcoco/index.xml 200 15789 192.168.1.91:45108 -> 157.166.255.18:80 + +It should be noted that each line represents the http request and response all in one, depending on how you specified your custom format. HTTP responses do not get their own line and if you wish to see that information, you will need to modify the custom format to include it using %{header_field}o for example. + +The list of supported format strings is the following: + +* %h - Host HTTP Header (remote host name). ie: google.com +* %H - Request Protocol. ie: HTTP/1.1 +* %m - Request Method. ie: GET +* %u - URL including query string. ie: /search?q=suricata +* %{header_name}i - contents of the defined HTTP Request Header name. ie: + + * %{User-agent}i: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:11.0) Gecko/20100101 Firefox/11.0 + * %{X-Forwarded-For}i: outputs the IP address contained in the X-Forwarded-For HTTP header (inserted by a reverse proxy) + +* %s - return status code. In the case of 301 and 302 it will print the url in brackets. ie: 200 +* %B - response size in bytes. ie: 15789 +* %{header_name}o - contents of the defined HTTP Response Header name +* %{strftime_format]t - timestamp of the HTTP transaction in the selected strftime format. ie: 08/28/12-22:14:30 +* %z - precision time in useconds. ie: 693856 +* %a - client IP address +* %p - client port number +* %A - server IP address +* %P - server port number + +Any non printable character will be represented by its byte value in hexadecimal format (\|XX\|, where XX is the hex code) diff --git a/doc/sphinx/output/eve/eve-json-examplesjq.rst b/doc/sphinx/output/eve/eve-json-examplesjq.rst new file mode 100644 index 000000000000..8bfbf49ef428 --- /dev/null +++ b/doc/sphinx/output/eve/eve-json-examplesjq.rst @@ -0,0 +1,80 @@ +Eve JSON 'jq' Examples +====================== + +The jq tool is very useful for quickly parsing and filtering JSON files. This page is contains various examples of how it can be used with Suricata's Eve.json. + +The basics are discussed here: + +* https://www.stamus-networks.com/2015/05/18/looking-at-suricata-json-events-on-command-line/ + +Colorize output +--------------- + + +:: + + + tail -f eve.json | jq -c '.' + + +DNS NXDOMAIN +------------ + + +:: + + + tail -f eve.json|jq -c 'select(.dns.rcode=="NXDOMAIN")' + +Unique HTTP User Agents +----------------------- + + +:: + + + cat eve.json | jq -s '[.[]|.http.http_user_agent]|group_by(.)|map({key:.[0],value:(.|length)})|from_entries' + +Source: https://twitter.com/mattarnao/status/601807374647750657 + + +Data use for a host +------------------- + + +:: + + + tail -n500000 eve.json | jq -s 'map(select(.event_type=="netflow" and .dest_ip=="192.168.1.3").netflow.bytes)|add'|numfmt --to=iec + 1.3G + +Note: can use a lot of memory. +Source: https://twitter.com/pkt_inspector/status/605524218722148352 + + +Monitor part of the stats +------------------------- + + +:: + + + $ tail -f eve.json | jq -c 'select(.event_type=="stats")|.stats.decoder' + +Inspect Alert Data +------------------ + + +:: + + + cat eve.json | jq -r -c 'select(.event_type=="alert")|.payload'|base64 --decode + +Top 10 Destination Ports +------------------------ + + +:: + + + cat eve.json | jq -c 'select(.event_type=="flow")|[.proto, .dest_port]'|sort |uniq -c|sort -nr|head -n10 diff --git a/doc/sphinx/output/eve/eve-json-format.rst b/doc/sphinx/output/eve/eve-json-format.rst new file mode 100644 index 000000000000..a3d68ef67f46 --- /dev/null +++ b/doc/sphinx/output/eve/eve-json-format.rst @@ -0,0 +1,196 @@ +Eve JSON Format +=============== + +Example: + +:: + + + { + "timestamp": "2009-11-24T21:27:09.534255", + "event_type": "alert", + "src_ip": "192.168.2.7", + "src_port": 1041, + "dest_ip": "x.x.250.50", + "dest_port": 80, + "proto": "TCP", + "alert": { + "action": "allowed", + "gid": 1, + "signature_id" :2001999, + "rev": 9, + "signature": "ET MALWARE BTGrab.com Spyware Downloading Ads", + "category": "A Network Trojan was detected", + "severity": 1 + } + } + +Common Section +-------------- + +All the JSON log types share a common structure: + +:: + + + {"timestamp":"2009-11-24T21:27:09.534255","event_type":"TYPE", ...tuple... ,"TYPE":{ ... type specific content ... }} + +Event types +~~~~~~~~~~~ + +The common part has a field "event_type" to indicate the log type. + +:: + + + "event_type":"TYPE" + +Event type: Alert +----------------- + +Field action +~~~~~~~~~~~~ + +Possible values: "allowed" and "blocked" + +Example: + +:: + + + "action":"allowed" + +Action is set to "allowed" unless a rule used the "drop" action and Suricata is in IPS mode, or when the rule used the "reject" action. + +Event type: HTTP +---------------- + +Fields +~~~~~~ + +* "hostname": The hostname this HTTP event is attributed to +* "url": URL at the hostname that was accessed +* "http_user_agent": The user-agent of the software that was used +* "http_content_type": The type of data returned (ex: application/x-gzip) +* "cookie" + +In addition to these fields, if the extended logging is enabled in the suricata.yaml file the following fields are (can) also included: + +* "length": The content size of the HTTP body +* "status": HTTP statuscode +* "protocol": Protocol / Version of HTTP (ex: HTTP/1.1) +* "http_method": The HTTP method (ex: GET, POST, HEAD) +* "http_refer": The referer for this action + +In addition to the extended logging fields one can also choose to enable/add from 47 additional custom logging HTTP fields enabled in the suricata.yaml file. The additional fields can be enabled as following: + + +:: + + + - eve-log: + enabled: yes + type: file #file|syslog|unix_dgram|unix_stream + filename: eve.json + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + types: + - alert + - http: + extended: yes # enable this for extended logging information + # custom allows additional http fields to be included in eve-log + # the example below adds three additional fields when uncommented + #custom: [Accept-Encoding, Accept-Language, Authorization] + custom: [accept, accept-charset, accept-encoding, accept-language, + accept-datetime, authorization, cache-control, cookie, from, + max-forwards, origin, pragma, proxy-authorization, range, te, via, + x-requested-with, dnt, x-forwarded-proto, accept-range, age, + allow, connection, content-encoding, content-language, + content-length, content-location, content-md5, content-range, + content-type, date, etags, last-modified, link, location, + proxy-authenticate, referrer, refresh, retry-after, server, + set-cookie, trailer, transfer-encoding, upgrade, vary, warning, + www-authenticate] + + +The benefits here of using the extended logging is to see if this action for example was a POST or perhaps if a download of an executable actually returned any bytes. + +Examples +~~~~~~~~ + +Event with non-extended logging: + +:: + + + "http": { + "hostname": "www.digip.org", + "url" :"\/jansson\/releases\/jansson-2.6.tar.gz", + "http_user_agent": "", + "http_content_type": "application\/x-gzip" + } + +Event with extended logging: + +:: + + + "http": { + "hostname": "direkte.vg.no", + "url":".....", + "http_user_agent": "", + "http_content_type": "application\/json", + "http_refer": "http:\/\/www.vg.no\/", + "http_method": "GET", + "protocol": "HTTP\/1.1", + "status":"200", + "length":310 + } + +Event type: DNS +--------------- + +Fields +~~~~~~ + +Outline of fields seen in the different kinds of DNS events: + +* "type": Indicating DNS message type, can be "answer" or "query". +* "id": +* "rrname": Resource Record Name (ex: a domain name) +* "rrtype": Resource Record Type (ex: A, AAAA, NS, PTR) +* "rdata": Resource Data (ex. IP that domain name resolves to) +* "ttl": Time-To-Live for this resource record + + +Examples +~~~~~~~~ + +Example of a DNS query for the IPv4 address of "twitter.com" (resource record type 'A'): + +:: + + + "dns": { + "type": "query", + "id": 16000, + "rrname": "twitter.com", + "rrtype":"A" + } + +Example of a DNS answer with an IPv4 (resource record type 'A') return: + +:: + + + "dns": { + "type": "answer", + "id":16000, + "rrname": "twitter.com", + "rrtype":"A", + "ttl":8, + "rdata": "199.16.156.6" + } diff --git a/doc/sphinx/output/eve/eve-json-output.rst b/doc/sphinx/output/eve/eve-json-output.rst new file mode 100644 index 000000000000..2606f6c92909 --- /dev/null +++ b/doc/sphinx/output/eve/eve-json-output.rst @@ -0,0 +1,101 @@ +Eve JSON Output +=============== + +JSON output + +Starting in 2.0, Suricata can output alerts, http events, dns events, tls events and file info through json. + +The most common way to use this is through 'EVE', which is a firehose approach where all these logs go into a single file. + + +:: + + + outputs: + - eve-log: + enabled: yes + type: file #file|syslog|unix_dgram|unix_stream + filename: eve.json + types: + - alert + - http: + extended: yes # enable this for extended logging information + - dns + - tls: + extended: yes # enable this for extended logging information + - files: + force-magic: no # force logging magic on all logged files + force-md5: no # force logging of md5 checksums + #- drop + - ssh + +Each alert, http log, etc will go into this one file: 'eve.json'. This file can than be processed by Logstash for example. + + +Multiple Logger Instances +~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to have multiple 'EVE' instances, for example the following is valid: + +:: + + + outputs: + - eve-log: + enabled: yes + type: file + filename: eve-ips.json + types: + - alert + - drop + + - eve-log: + enabled: yes + type: file + filename: eve-nsm.json + types: + - http + - dns + - tls + +So here the alerts and drops go into 'eve-ips.json', while http, dns and tls go into 'eve-nsm.json'. + +In addition to this, each log can be handled completely separately: + +:: + + + outputs: + - alert-json-log: + enabled: yes + filename: alert-json.log + - dns-json-log: + enabled: yes + filename: dns-json.log + - drop-json-log: + enabled: yes + filename: drop-json.log + - http-json-log: + enabled: yes + filename: http-json.log + - ssh-json-log: + enabled: yes + filename: ssh-json.log + - tls-json-log: + enabled: yes + filename: tls-json.log + +For most output types, you can add multiple: + +:: + + + outputs: + - alert-json-log: + enabled: yes + filename: alert-json1.log + - alert-json-log: + enabled: yes + filename: alert-json2.log + +Except for drop and tls, for those only one logger instance is supported. diff --git a/doc/sphinx/output/eve/index.rst b/doc/sphinx/output/eve/index.rst new file mode 100644 index 000000000000..bb56991c2a0a --- /dev/null +++ b/doc/sphinx/output/eve/index.rst @@ -0,0 +1,8 @@ +EVE +====== + +.. toctree:: + + eve-json-output + eve-json-format + eve-json-examplesjq diff --git a/doc/sphinx/output/files-json-log-output/.files-json-log-output.rst.swp b/doc/sphinx/output/files-json-log-output/.files-json-log-output.rst.swp new file mode 100644 index 0000000000000000000000000000000000000000..b00f05e585001fc0774948dc0065008081b07522 GIT binary patch literal 12288 zcmeHN&u<$=6rLg#QD}j-f-8fOs#dCZy|&{dM*K>`A*i9P+?I-qKOz3+W9t0*t- zT-n^B%R!&u^E4r+PJMRe=8Hq}eMkr^Q(?RB^^Yb6q9 zSeVKr)YVj!yP>R2Rhw`ka<1FkT9)lxX6^s#4U{(b-rCRb3_RQn)MnCNIYxTjsAGwE zq4hjHdE)ZJ&54iRGvFEU40r}S1D*lTfM>un@Q^WJszc;`#Qex2?w1$OL;rd%n*QM# z@ChOqAN#LAtRQ$c93?T^CgodXqeBwaEk0SEiv< z7}W;rF%s_4@BBplWu^l{>=ehN?G=WmLZMtUpYKcD>5>_74FNQK%Sl7ItJ*vhkQ%O{ zFR8VW1x?_!&DKH=GhwFGkxQ}Doh0lTI~~{gjvaz?MwGRz^%-OVTs5T0$%HEegYmk8 zoUqZJ4nRd4LLgIPs$m$;X0yPSkOop^p-m(>vUy?1OiCwwc2GuF zBS;G*o~4a9NCJY*A@~e}&A=ut1TtvFi12x7-0_6Mwm~`Kn{mDqG^FhlEBu6{=8$1t zP3qk00b*!kLpB3qec^73Rilj?Ww?!`6D74q65TPi{NlJ*SVHJ~gtoMJhqs2byV@N@ z)V2+xP0=%9xeWtdMY@D`E9T2-yu?>ozaI@)KkD| zKX-og`bN`PuuLSj^R?0X<|Z|K*PNwJP0r;UcM657xnA^^(ls$r6#{~lN;^Yb<31aQ z-5`pB&NxiD-Z8QohrM8F9J+ju!ve=ONOZHHW#fGt_mJIu98MG~_)MxDJq}~0P^f%g z_8MzbTt3#EjZ`E-948`3WKi$G#b$=$&^cFjlGF1z96Lp0DrOer(9X08D&fw-o`LqX z!cecfy3%ckwat}|`;EKP$VBGo8MuyA8)3&=(JIIptOR{LR+k(0wMv@7l}^y@tp?p_ zIf#~{W>8c}0ao^%9U}_d&#Y){f#OaCx;s&~9Sw#{-Qkj3J%|Qw@w+&&L)?mMOydQS z+k3{ID16xgN3f{`rzi?{+H~pP(|;~@tXhR0lD)SEoidFsoXS|_0tXl83vs9Q;*7f+ z%hj0&Fi9KhR@KyQfgtp>y(3~)vNldjd#_@>sZ4KX+qt+4aHYidCyp)7R(tWvY~x6^ zi@Cm*Jaqd2!zz4U)R Gl79e$FZbsF literal 0 HcmV?d00001 diff --git a/doc/sphinx/output/files-json-log-output/files-json-log-output.rst b/doc/sphinx/output/files-json-log-output/files-json-log-output.rst new file mode 100644 index 000000000000..036d77f73485 --- /dev/null +++ b/doc/sphinx/output/files-json-log-output/files-json-log-output.rst @@ -0,0 +1,62 @@ +What to do with files-json.log output +===================================== + +.. toctree:: + + script-follow-json + mysql + postgresql + useful-queries-for-mysql-and-postgresql + mongodb + logstash-kibana-and-suricata-json-output + +Suricata has the ability to produce the files-json.log output. +Basically this is a JSON style format output logfile with entries like this: + +:: + + { + "timestamp": "10\/01\/2012-16:52:59.217616", + "ipver": 4, + "srcip": "80.239.217.171", + "dstip": "192.168.42.197", + "protocol": 6, + "sp": 80, + "dp": 32982, + "http_uri": "\/frameworks\/barlesque\/2.11.0\/desktop\/3.5\/style\/main.css", "http_host": "static.bbci.co.uk", "http_referer": "http:\/\/www.bbc.com\/", "filename": "\/frameworks\/barl + esque\/2.11.0\/desktop\/3.5\/style\/main.css", + "magic": "ASCII text, with very long lines, with no line terminators", + "state": "CLOSED", + "md5": "be7db5e9a4416a4123d556f389b7f4b8", + "stored": false, + "size": 29261 + } + +for every single file that crossed your http pipe. +This in general is very helpful and informative. +In this section we are going to try to explore/suggest approaches for putting it to actual use, since it could aggregate millions of entries in just a week. +There are a god few options in general since the JSON style format is pretty common. +http://www.json.org/ + + +This guide offers a couple of approaches - +use of custom created script with MySQL or PostgreSQL import (bulk or continuous) +or importing it directly to MongoDB(native import of JSON files). + +Please read the all the pages before you jump into executing scripts and/or installing/configuring things. +Te guide is written using Ubuntu LTS server 12.04 + +Thee are 3 options in general that we suggest, that we are going to explain here: + +1. import JSON into MySQL +2. import JSON into PostgreSQL +3. import JSON into MongoDB + +The suggested approach is +configure Suricata.yaml +configure your Database +run the script (not applicable to MongoDB) +and then execute queries against the DB to get the big picture. + + +Peter Manev diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst b/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst new file mode 100644 index 000000000000..ebc2aef759ab --- /dev/null +++ b/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output.rst @@ -0,0 +1,236 @@ +Logstash Kibana and Suricata JSON output +======================================== + +With the release of Suricata 2.0rc1 , Suricata introduces all JSON output capability. +What is JSON - http://en.wikipedia.org/wiki/JSON + + +One way to handle easily Suricata's JSON log outputs is through Kibana - http://kibana.org/ : +> Kibana is a highly scalable interface for Logstash (http://logstash.net/) and ElasticSearch (http://www.elasticsearch.org/) that allows you to efficiently search, graph, analyze and otherwise make sense of a mountain of logs. +> + +The installation is very simple/basic start up with minor specifics for ubuntu. You can be up and running, looking through the logs in under 5 min. +The downloads can be found here - http://www.elasticsearch.org/overview/elkdownloads/ + +This is what yo need to do. + +Suricata +--------- + +Make sure your Suricata is compiled/installed with libjansson support enabled: + +:: + + + $ suricata --build-info + This is Suricata version 2.0 RELEASE + Features: NFQ PCAP_SET_BUFF LIBPCAP_VERSION_MAJOR=1 AF_PACKET HAVE_PACKET_FANOUT LIBCAP_NG LIBNET1.1 HAVE_HTP_URI_NORMALIZE_HOOK HAVE_NSS HAVE_LIBJANSSON + ... + libnss support: yes + libnspr support: yes + libjansson support: --> yes <-- + Prelude support: no + PCRE jit: no + libluajit: no + libgeoip: yes + Non-bundled htp: yes + Old barnyard2 support: no + CUDA enabled: no + ... + +If it isn't check out the [[Suricata_installation]] page to install or compile Suricata for your distribution. +**NOTE:** you will need these packages installed -> **libjansson4** and *libjansson-dev* before compilation. + +Configure suricata +------------------ + +In your suricata.yaml + +:: + + + # "United" event log in JSON format + - eve-log: + enabled: yes + type: file #file|syslog|unix_dgram|unix_stream + filename: eve.json + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + types: + - alert + - http: + extended: yes # enable this for extended logging information + - dns + - tls: + extended: yes # enable this for extended logging information + - files: + force-magic: yes # force logging magic on all logged files + force-md5: yes # force logging of md5 checksums + #- drop + - ssh + - smtp + - flow + +Install ELK (elasticsearch, logstash, kibana) +--------------------------------------------- + +First install the dependencies +( +**NOTE:** +ELK recommends running with Oracle Java - how to -> +http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup-service.html#_installing_the_oracle_jdk +) + +Otherwise you can install the openjdk: + + +:: + + + apt-get install apache2 openjdk-7-jdk openjdk-7-jre-headless + +Then download and install the software. + +Make sure you download the latest versions - +http://www.elasticsearch.org/overview/elkdownloads/ +The installation process is simple (for example): + +:: + + + wget https://download.elasticsearch.org/kibana/kibana/kibana-3.0.0.tar.gz + wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.6.1.deb + wget https://download.elastic.co/logstash/logstash/packages/debian/logstash_1.5.3-1_all.deb + + tar -C /var/www/ -xzf kibana-3.0.0.tar.gz + dpkg -i elasticsearch-1.6.1.deb + dpkg -i logstash_1.5.3-1_all.deb + +Logstash configuration +---------------------- + +Create and save a *logstash.conf* file with the following content in the /etc/logstash/conf.d/ directory : + +:: + + + touch /etc/logstash/conf.d/logstash.conf + +Insert the following(make sure the directory path is correct): + +:: + + + input { + file { + path => ["/var/log/suricata/eve.json"] + sincedb_path => ["/var/lib/logstash/"] + codec => json + type => "SuricataIDPS" + } + + } + + filter { + if [type] == "SuricataIDPS" { + date { + match => [ "timestamp", "ISO8601" ] + } + ruby { + code => "if event['event_type'] == 'fileinfo'; event['fileinfo']['type']=event['fileinfo']['magic'].to_s.split(',')[0]; end;" + } + } + + if [src_ip] { + geoip { + source => "src_ip" + target => "geoip" + #database => "/opt/logstash/vendor/geoip/GeoLiteCity.dat" + add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ] + add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}" ] + } + mutate { + convert => [ "[geoip][coordinates]", "float" ] + } + if ![geoip.ip] { + if [dest_ip] { + geoip { + source => "dest_ip" + target => "geoip" + #database => "/opt/logstash/vendor/geoip/GeoLiteCity.dat" + add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ] + add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}" ] + } + mutate { + convert => [ "[geoip][coordinates]", "float" ] + } + } + } + } + } + + output { + elasticsearch { + host => localhost + #protocol => http + } + } + + +Configure the start-up services +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +:: + + + update-rc.d elasticsearch defaults 95 10 + update-rc.d logstash defaults + + service apache2 restart + service elasticsearch start + service logstash start + +Enjoy +----- + +That's all. Now make sure Suricata is running and you have logs written in your JSON log files and you point your browser towards -> + +:: + + + http://localhost/kibana-3.0.0 + +**NOTE:** +Some ready to use templates can be found here: + +* https://github.com/pevma/Suricata-Logstash-Templates + +From here on if you would like to customize and familiarize yourself more with the interface you should read the documentation about Kibana and Logstash. +Please have in mind that this is a very quick(under 5 min) tutorial. You should customize and review the proper way for you of using it as a service and/or consider using *httpS web interface and reversy proxy with some authentication*. + +Some possible customization of the output of Logstash and Kibana - > + + + +.. image:: logstash-kibana-and-suricata-json-output/Logstash1.png + + +.. image:: logstash-kibana-and-suricata-json-output/Logstash2.png + + +.. image:: logstash-kibana-and-suricata-json-output/Logstash3.png + + +.. image:: logstash-kibana-and-suricata-json-output/Logstash4.png + + +.. image:: logstash-kibana-and-suricata-json-output/Logstash5.png + + +.. image:: logstash-kibana-and-suricata-json-output/Logstash6.png + +Peter Manev diff --git a/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash1.png b/doc/sphinx/output/files-json-log-output/logstash-kibana-and-suricata-json-output/Logstash1.png new file mode 100644 index 0000000000000000000000000000000000000000..1d02def2e0c22eb7bd43a42b8ef201f11bafcd13 GIT binary patch literal 77479 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 yzuIPB0}1(C?=%b0OX}rq^iMRzx^MoZ%1qZ literal 0 HcmV?d00001 diff --git a/doc/sphinx/header-keywords/fragbits.png b/doc/sphinx/header-keywords/fragbits.png new file mode 100644 index 0000000000000000000000000000000000000000..30d497f1eb88539bc893da792e95581d0dc3b770 GIT binary patch literal 42764 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%0A48DDc51)&$t8_W+gSNZ4Yhb$Rgx~3K2gnSajq^ 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 JHKNAB{{sgvgo^+G literal 0 HcmV?d00001 diff --git a/doc/sphinx/header-keywords/fragoffset.png b/doc/sphinx/header-keywords/fragoffset.png new file mode 100644 index 0000000000000000000000000000000000000000..a5c1ecec7f3592f41da28dfcfb232a5a17e80cf2 GIT binary patch literal 45033 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/header-keywords/icmp_id.png b/doc/sphinx/header-keywords/icmp_id.png new file mode 100644 index 0000000000000000000000000000000000000000..6db0c5828fd8b889734ca257737d122f0f2d9d3b GIT binary patch literal 19474 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 Q1^@s607*qoM6N<$g5q;^00000 literal 0 HcmV?d00001 diff --git a/doc/sphinx/header-keywords/icmp_type.png b/doc/sphinx/header-keywords/icmp_type.png new file mode 100644 index 0000000000000000000000000000000000000000..7ca579e4588e3a2bbeada172f448bd387414a268 GIT binary patch literal 19622 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 P=w%Inw>Qqe zTPkDoBcpfpbSo8rlGHu%2^qzLHkK}<{2l)}bw{$>+&mTk=tHKQdh>q6g4${^WfhbY zTNkQ3M|*WtX-Xy21WoV@@OK)J3^{o@X3ce&{qB0=i`uT4NC@G+-Mex3(ZqKdl22M~ z+8b3uJALLK=Mx!nK(XICx(&@!Hg<97mT_^N>!_uKG?M5*s;>Q6tqqYNXGxIrx~r)z zjoT@(-}HC$zMJ=>FGTR~)njqksJsTB;%$N^Xo7|;$zQk#M?_xfw>K}JJ$v>n`Ad%E zYtHAF$(fRnM)Btlub)1BmRT&iysGzrnRg_4qu)GxT)?S(7*$y8-QDR}OrX#5gxVdP zS~7CX(hG=~vbnF-sMFFLyP_B7-MrGpi1`27yZ2})(>M;`zh~xckZVfi(ppN}Dyj-T3uAT)fQW+EnDd*s!<79lhqHQ2jhXk^ zKi(NBwdd?PyLR{V`}{Qy=AGlb@7M2rpWpL5@|&f_+*@^3RZ&{|OjdcLq^zoiWhqri zD<$P6C0BpFS4Syjm2G9EB{DfnSxQ;TcC=nCEo)VY`S?)eRX!FG@MIwK{jM~maG)IR7l{{7er37eJxZj}QG+Se>x2$$jcPi=^ zvTf}o0O(_3MxQ@aaD(MiDG_KG@Bly>z53g0kKbJ3C^arv6dWG1b?>FyFA0^+be|9$ zx3{?PeAv7xGb1tyVK#=YJX_Jg&E;yUys%=mhzF!}Z(P`(Yyi+Uw>zA+Q#~-KsIP79 zZ)FKUFU7CfbgYtl_&9z_U`_D>scJ)1gwQ`;-O$q1aIfWJ)fXL&lB#-2>7G!x#qs4G zFCRFM8~a-mw^e-G8rR|K>W1xXc51Bn*?Ih8xsq1I`A_Or-9#<++H&Zoy0J*HX||{5 z7lAQRYdyy}#b!Qul+{R=lsh{{huEp53sw_o!CT{PmOFM5=w=vqWw_ z8;aO&Em(^BjOpHEvpBS2ZhuaQoka{6WBigdG=hdcCEzqR^Iq`ik!HT_d4kM7B zu2uxCTP=6oa(~k#b9yf>LlIpl?B3+W>+7~XWuzo$f0Q_Mh|PtmLrB;DKLGvDEZU2% zKl|FeFaEDWs3%6IsGe;`VV>mXjr?;N&Nk5wOX5?OjpHszs_dY^5Tfej;4wVtva}l^ z9U67Lu=$KRN{v_bjfqGdV(se#_Z0AOkK z_XT#IdupN=e)z6?K+5zIa5F#Km0)5$+HtfIH+#!L=+bWh4|+R~7}A_~x!#@Tw_92} zXuYKgg)rI!O|%EjT~Aw{C&i1W?hJe57&-<5*|Syvj2nb{WMt~)lj{0b9UD96rR&7y z1zRM^QMKv|UeMc&ke1&&SZ@4AQdFS@ypmanO){(Zuy?DJN(OD*)y7@c6->t3zy7@?z3D0Flbnwwe<)*}>Pq4UU- zMa9M0`-gk2LAoZ)lKn{goqrv zRkTo7Kr6G;`8FQ?JL5**(pr~Ymw0HUw@r24v5Wk^I^0Uwq&X&ZSMN_Q+C_qzojrJT{Jv?;~>XEpi z)FUXtc<4{bNwLixJgYI2a?`(L01S;SO${}HueCcfOS~p5X3IH`Md5KD(9|k!rlPXp z(F2+MwTeW;$jm~i|LVaAw3`hYY^bl%d4ppxHYDfZsOZGx^yYT6k?z^K(K-}>u+`V{ z>!hsh>z`|&*G7o^5+NJ-8S7?^HI&vqGV2mmd$)rD;@xO+WW#nrog&3%mU%t7cc`@c?N zh?+fPa>~(>Iz2Jbr~ToHsJl*)uEqdxaQ(#deIn9A#sFYrF+%S}+|af*xu%vz&s_0J zc^fdAJVF{T?eQVcZ~uFm4b+2;&AJgmHrqLKrs)A&eV@5XKEc2w~hHgfMOpLI~pqA%t;* x5W=`Y2qBCcgb>CJLI`2pAcQb(5JK;@KLDY;=eh5)q4fX&002ovPDHLkV1j}v5Jvz2 literal 0 HcmV?d00001 diff --git a/doc/sphinx/header-keywords/icode.png b/doc/sphinx/header-keywords/icode.png new file mode 100644 index 0000000000000000000000000000000000000000..3535e55ac0f74446c84cabfb8c2bb16e0ab2ad0a GIT binary patch literal 16627 zcmafb1x#K+*XG5cxVsm3FaBbsc#+~>+}&Oric4{KcXy|_yIXO0*X_5-pX`_2WY6TD z%srW8005AszKJUV0EEZCx;Q-KKMnMoSN_uwj!KfEK;;C{ z(Z3g1Lm5eN;Nw3fyQ3)Xp9R70n}#C*p!EIcfk!UqwgC=oE-vh=wGp@da8OlVTtQP zNgtM+J;TN!n_jnp%CYs^<6{1x<>Me@6F125ei=Nk0X}QkK@*3@R{1XSYZEm{8k)X1 z+ka&JpZY}an)go?XFKrxe{98Tk^fh_S5hY)Z2s!^4f%4P$43R#O3#8^k%Dk(AIoep z`;zS_hX!@9*8J$)_oD~6ve}!5qobCN^G&Y*us@BJb*+5$ZmFio{g1zw3+bt}EBDq^^HssuD5xa1z%( zK2ZA941s<#_|ypbxH4I3`=PuDdHe(Gb!Kr~cz=qRUkn6L4C`^(-j~GV4$avi;1Ti6 zWR;LTYWaBETK!FHr&BHYb-Qu?M=MBHj%bTuW8K8{jzMcbZD3l9cN$H2b1iVM{vxE;_KJkeoTdNQbXe5)If zUCSyubwS8sIt$?W9Qc9SM!3LIrO1f!&FD5d0t22rc6-srZ`D>i{f|oP9-o<%7V8^v z`N*dYk2^d*@D52wbM?f{;%7M$0flNS3t>b9^OE}5(Sl$8N}nJggz`^`SnVTa9_#PY z@(`GW8W~5Ho#$KMidG5g{Ib83O~`a<0NF)$+`CV$^Ll-?Uor53srbO{mYKV9P@!9YSl0^cQg{U7saG>fI^rRy3Zol|BT8yKMU+Xd=9 z7k+L`|H>Qr%o$K{-?kp=|3y6a_LG;-4T1*i)Q)lyZ}?A5X0M&84l}=^i=rEvgBm~j zG3>D~9_{#57`VWx90%ByguPv7#2%3wBbLV-6mhVo42v{TD3@jqjiSccXqx>oGkcDM z1Q_O1Z)nroWo8J}vlWR}2Ii6DHb)qzx0^#m0>E~<>CeH(LWL#HmMSJ747#_xC~ac* z*ApK7a|^pcNj$UZr_tO*A!kmiQClzFr2;=uDy7hB*;hxyoIp|g?IE-GiVRo>gz0z? zZ7eux+mrriOI~o{AxTt6PfNMcs;&vkS6lCkO}NXZ&dz#1yHS~W8LYB%e-HlR{h)kE zIxE}#Wrf0g0K)JA*l~yY>(>FI_9tEMyRFni%m*Rr@rd-Uor%Z8Wya;WkZJT^GZ)c< zUF~~Q4U^Y{SEB(>SJUXz9F-k(&;YHQkj01+R>7b|RAg!+t0Zhow1R|0L`I`o8yWy) z5~m7XbPo~^j}AnW3cHSrlscGc#@{68Z1i+UKsi$%;%ijsChPw!D8lko0XuHZ=7;=R zH#yG|?yd4`Y58RwcQqQVU^hpMp7Ggd�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 KxvX literal 0 HcmV?d00001 diff --git a/doc/sphinx/header-keywords/id.png b/doc/sphinx/header-keywords/id.png new file mode 100644 index 0000000000000000000000000000000000000000..0285b8e4038bd611731a2bc8aa1042e2cd19c5c3 GIT binary patch literal 55094 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/header-keywords/ip_proto.png b/doc/sphinx/header-keywords/ip_proto.png new file mode 100644 index 0000000000000000000000000000000000000000..1e5bc503d9eb6400da4e0c46955316d5ab5f71ca GIT binary patch literal 21788 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/header-keywords/ipopts.png b/doc/sphinx/header-keywords/ipopts.png new file mode 100644 index 0000000000000000000000000000000000000000..666c17842755c0c5b25b3b0148a5fd84350c59f8 GIT binary patch literal 33790 zcmb5VWl$Z#8a8-v2~G&X-GjTky9al7J-7!8PRPOC-Q6L$26yM+1lI%0z2Dy5s{OY$ z)iw2YzcV${JyYF}bd-vcG%7MaG5`QTm6efD0|20WJ_is4Fuff%-q2n!vYK=2XoOMSGpVSdD9+|a=yBe5ST|Bb~Q z|CjRr>k`olDWL}gyghn5M(=q#G6l+5T*UNHjQr#gBL?mwPmf7eUy~-+6+QLY$0~^U zp?%e7^xq=RzZZ=qd_=%Jb010g!)q0Cp5_aNZ(ls@_W0n01emo2^q~86vW34)D?r8% z;DZdQXIes>(f5AkYU-DXIB&YZtGMR%;2dHj!r~&dS>WclSrdkdkb`avb_rubv1MQ- zmZfK0*GvMjBtz9hBcK3g&eqOck8UE2Ts71H_BjH0`|#H+E}6 z+`MaS?@I`eo|}OCW-qEs3~Ycbhg2YbY-f{A4~u9J|6Zd5RxZ17&vKJ%j1GN9V_iK}R$7^x0ZA1#(n za~802aVT^N4|p6>&_j*fR2HTk=w0oQsBh{Q*P8I?N=6-Yo`sE5X#S>`R;r5 zs~z2-I-~;i3pr5t_sjmNEwPud1v*@~l-iyjOnS%jq^y2Me6suO-WpNE~0j;NI@z*YpWlAd*A@ULd}3p5 zjxrQt&HdKlbI+xG>&3vx7AJn`kO7mITxojNumJKQoa8kaG9GWf18UR~86o3jc ze3gDFVMDpc2WDdz@WF1f3B10)r9F+xGLp{+Dj*25HbJNj`3%KZzr)bn)}s0QZ81d+ zg?;@7o6A8jLsA$)nGsQ}hy0BRSwws*kuIY|C$CIeZXvSycZF|6py2z_ZHlK#HZcJU zeO6^p{kc5FB#tANDd`^HkMk9RaTM(bXpL`Ko)d`P+GaIKhoJ!*hJj z2@8d&P_~g3$h~ILTA1s2KLIWUaLG#QGF)YHkN+T>VJTayzd`fb5RblIH{j6tOyb8V zi1%tAg39zdg_Xbb0d`acYY!7Wh1}CC5#trSaW*!cxB(yoh8XS%$dY+K{p;Dh41mf$xV zgdtJ>%$Mo_zKZxihAML}Sz@@`t~}D6sZVEyO?hfxcdIgrb)cp><1bGC_4h67v;nGn znkVl>Q2+=cMIfKnf{Rt`_mRFVPmE+2xzre8oMWn{qA61}5pKSa;#lRZMAD9Wr6%7C z=N2$}pxqpNd<>BzKp>Ta52cr=#>&(G*!kKlqGzO$*L0%3zgS6L5k5dSE&2X6FI74o z7izA!g~03w@J%9zvWFmN!!Fy~n#4ilm=`8U)KYtS>%PU`^gUEhkZ}JgxUYJwJ}oUcI5>-QhdPI_a6rv6~zhymhF zVVewSl17TSE%^%L>!qp+^gItMT%0xIQA{32MYJ z8ML>ZkkG|?*{c{#q&P(Ra}X+M!bn?lfcI;_M5Rx@o7ZJrz;_L}!%tz>ik2KMn=}gw zfOF^Ld^R)+m(0?~LMD@No%UkT)>6g#X4WR8zV!Q^b6X3z&9`x>rA6i6&AlT&chxo& z;D{FD%Pbg#Z<*~;mFPNx40Zd^1k!TSzP|Y^alF}Ga-N{@(yiVU@8?xH0VNXv^Z)@W z*Yt{5drjnDhTj0uCwxgL0G@Om&JqxQkzoVPjqQP`RxC z!oTc}L_Tn1^ebyj&>ga1SY@Ag*$QAt)R1gH$bJFvY{bDyXT|JA6j^iv8&{L!4C+nEZ63@Mqi@$?$U5y73j6acS=^QluO;;o6oAjT6?bUAwRYg$|AC@f zet+iSz<~Z|3xWqg{k`NT*Am7Pu_%Hc)sFebZyequ3Ge6XRyc)Q>EaCk`V$mf9qR890L=CQf2_VnEH7inZi1_j-X3{RDH{+>yr!lRvY7Ro#1fYLD(G9+YtH!fEf7dN*qJ}7IL&ENRl5ibuR00Rice`VzKH2y z!$z!D^1PkQJSST((WT?ft1@#O<)5^6nwJOVrgb;*=iNG}u!Iua-(tgC1_qyUCr2K$ zRr!7{+#dYQQtC_>5&&#Jqh}wbK3MAd5{)we9hP;PN8vDbmDfoe{{dPpjU^g;K5tRm z-w8$;ZDNrOPnSWlmpfU<8?V^^-Qr+Dfn`AFBYpANrJF4ZKMsLdi?{K5{WU};rM_)4 z4ET7mCgs7{0DwMo4e+Nesdd}tWZS&X^26bJ_u{{mgdmG)PxBxJB-^ttqp`AsZtnAZ z*MYaCj#3mXDg`&8x+3_`rFEB@Gt;?7?`q(j--MX~<$bK<4h~!2#sXMQ+I-owO>=(* zHQ?0{Z{ksJ_RZ--lB-{5LQi z8x41@kiyuf@XzC~3xOp1zloPA^l5@~=t~W<55g3n>g|uO_Cui{X0eud<K&Y0 zFlj6i732Od5uV60pMG&ju4QR9bZGogK(3FzNUIoUu6vm(ERXjG;aVFHf92gs(W)&W zHD}8CWgb*sy<(7Ze%-8>a%#lG*49O0;b^i7EYu~tKJ7}m>DZK0t7Grw^ zIz(xl#~m985fuko-Os*oFTTA;(X=*BX!Ch`z0DMP4Qn{`7f$^g#_N9Gc~lf$ljxLm zuG?dV{dp;iw?ucO7Paw#kNT*vJDv=#1YGN{)w3FlBrsb_Ry>c&*2muM=N(3G5Y0Yd z)vIh<9s%&P{rXOo?k;@R4~d6!hEBJf+W1^JuE8**{~@aXg0BC9u>TL}0%3!>FQjI9 z=Cu->We+k7{tIuiS;UyU(u!_U*)>gvQ7p=&^)&=9Ti9N0d z4rtOFG!b@0>jv}Uob@1O9ggnyVIfYrs@6Wr4Z<7BtQtHCC_#Uva?0-!LMO-fnR2eKVEDBVu49P^nk07n+L0PXIxnYQHGubZ zfS?A6VhQK?^TY9cKCE%liW!;}?xWaF_re$+?#~~e!q)ZuzE2cO@5;I2hzGSOsRPU6 z@HXBI&=tI<^E$pS)Y~fM<(<8%S$2TOc+=-h$Op6MGZJJ6l=@Jm2jr>w@s(;gDwgwET0G*rAWmCv-#s0 zO26z4@lX62v(tT`-?`-PtB4vqENBDDaoD3ZKWXvVely)0oUJ$p$G{xgE0L2USkw< zp840OMi|i1y(_0g0Ad1?Q5o6MQvICX+`Ya|6qFUy?WUasv`f-rZ-WLN&VOPGAgJ1n2? zh`-CO#7O7|hBLi;j5lrZ#qtHsyn-UC1!{M~+eW-AE{A^L7eR#1bc8H7cD^Rlz1(=} z^>FYCUd%vAhYJ|&k&seKJ9odXsIam>-<&+L7S;LIytb~2rIH0{2jDn5^?=77&Z!{> zMB`B4AodwFs$OWc+5&^_3_|ntTBr4OL5ds>La)-(L#HnJ^;9?EGsw8Kg`m+I`~4Q& zAw=-YW`Pwzc++L45X1YZ`|8Fs-hWN!&SSbrS#>Cn-I-^t>V?Yb5roj*_`^Eq^<~FOxI?3J9Lj9X(ajL?0(C?Ll4!SSzvM-x zRW>PB0b8$N6!7wtKhoCWURlRSV1n6wm||lw5VZ8(WuQGNlxTl`yRm@Dg;<5D|GJDy z6?gLb*0Rz^29-N#GkxhVPQ)~gL7{qnSiW~ReryXxBNXL&5?_J>AMsv|8xk|Hgw~Ev zFOu|NJ=L zp5Q}PEuS({o^fUU7R-Tao$+PUXqTpk!*F4Gyp{)r%-u5jXnW z)_xlO_tDy!r!qdpq9%6p&S125H2)2eseawr^hBEmruz>)FDtrx_LEmzS?pAE!P@Sr zUz1*vz#_xFqON(v_g=v~$tL7$b*@e+K#;Qr?Z~I5JSIxvR_JEKC}RLvWc~`X21cMh z|L>laCeocZ5>(fjtENm-!5}h*SyN6A5N?u;a+p0bxB9sHyGQZCGql&gTO~Q(jeFM?fJ3;H+3%G4blrRrOz3S z9~n9RRkv`5aF%s2x*B-%R2n>-m!Hljxp z+}n9E+T;_&@C*CGAU7#9%1b83#nzhE0)N(A5e6}mn^*y$#2JfCRO8g~Z_8eml`|Lo zo9@yJ_|t%ub4toVRLdC+dW@&Qb-<0ad@SA5@xdrhLG3j}v#Tb)ynfQ$G8$Xn9{Ejp zWb(LHBel7E!%5`<5KiykXPi4bWYL(5LqZ)Rn^fKoh;j zbuEKSKvd8y>XK`3#s11^8$oD|j|Bm4B?#U!9vvo~C)WBda44{Bl^xwIu#I$$>FL%o zntpmKT3=N)5nzG~DM{7_XrK1#M-9+Xvm94kfL>{za&d^H6O+zeikOa&%)^`@8YJso zEHYvujfZ8o+O(9=NV3xR)>sGKTC6{`#HmC`w6U{oHy~JfL2*H=Ym6C-_uD2{h=@$h zK=IUwa@&FUB+r%ND6;ej+dDg7Ea)Kz8+Q8_P}9ciWtG{*-eLyZOOBiYJ6nHhr40@| zaq7~kWUQO>FQ8v@=k2Vc5xVnB8Y;2c{ArY{Ff^azbS(wm>ClgJ8TCdrn1;-=hj8iq z?exO-s3qC`u;B@wbx-w^q_?`?8r3VG`0k^Y+X<{J=*TC;l}pIUVPlr4HnrNUWKRy4 z#)gFlDwobl+}ZpO5)j|r73uya)|$a&&+|Svhl`yx{f6HUY^j@ILI;fJS1E6tQ zm(I1;E|m;a`1pAmAF&S|yc7OAppBqfR>?X?%J9n-=by!7;~T zF+tu5lfSF~BM>&nPNGMP%vK{FaXICRmntX1Be)T_4S>4AP~us5(oNLAqvEH)DoNsY z-*q^~IK(j>E7Ld9=53YZ`S|`P=-_yGC=~WI5XAgqai|qf&ZREFr%;^(a@ls`#(G7M$CmD)U*I1QnzOK2qb<=o9OqygO*VjIFlI4d+aH= z!$fTT>NeB;50j#5T)Cc7E``nNX_W#RVx8CkcNx;K}Xieo{2HzZ|)wlKW2vm{2Ab}CD#Eaww zbfHDrk7z4#f1U0K_!OH*AL!6lcD+`WS+}-*>Yn^Oo$|p zG4;W=Ze=ml8a>n z!Q&s(il~=)VSDm#-8J{e86-rgO*&0vx&~AII+yWjcj2-)(>=M8qp09a74p-aEaOV= zUJf*|bbBjgj)ez4D#nK@xmG&IqsHMJr(G3mVivS6Oa-Wte^U`wj-}l(7!qtEA2?j2 z=&8bKQJ*juUQJ!M=+mY9>CNsUv_zFcpBImiTf&;;l{EUXnBc;+`0 z$N029jF7eeem8cjE@S%FppUmppL)}q+A4eVtz>hn#W!aNde!h<=~C!;dpo=ToJ7!z zlwF!+y&4=F&k0n($h{bxKJE4yx2xV~c$>A_SLsUJ@8&gLP?h-=7$E=9Jon`e@9|~s z4Jok>V&wm@B;$%ZJ#}}#@DNNQUgv47 zN{ph+4f#UG9fo0b(SK>xmFaT|f~bq@Om;8SY<&OoC7uxDa^mGMLZ_x^UC7ti7V#=m zSJ-YyZ7m|X=CX#Kam_Gngin~`+L7loE<(zk;Bj{7W;S zNvUHu;(F4Xrpikxyh*-e0~FaWC2{8{roBA{apf7uO)xtd{)>9Q^(DrWwhPEs=i7;G zfsTRC;|%#i!L1R0=475~|m_%Hyi-CuAlGQ>7|%+r=&5hOLR%OU@S;7awJs`E~7fHbbZuXTQN& zEi*aU`DSU+`4iZh`{~cXi<7;N3X#%ep!%qn*S3w@2J3MKaFZ^Jk96>}Da(my6dlW% zUj$KkoNLMx+)xpmBz|i6=0nX^pu)^%XqwIOW~RQ>eeGsG)` zDT)$gun ziMoZoA!xRYdferUKN$Tlqdr^~zXZ>Y(v z^^qNi@+);R1CL=Ux_#Q!dseK%lu27#U&~bgD5R)UE0pU!xoaW0`wd?qzJz!l7ej=-Vk_p5U|4J;V^`y}m)7vtFm^m*qIJ`Chy zpH?P`d_c-}*&?M3)|4P5Qsm$JO2-a9`o**LL$I<_K;7kiuXR(q3NE|X@&NWyzfJY1%=UYh}~%c^Kk5T;>>2 zobAZO_UGJ~K9rEh>+d837y=f4n0iRoaUS|CJSX~R&&E_reW<`+YQa9R?wz=%O>J1Q z)uVGsU*Cm}IEB05j@atY#R|}!pMo`@F4>CFBwGEdbi3AaJt5(GFzMw551JyaLE*-3 z4V600p@Enhl>4qVOzufmy z1#CH-^cvD11gd#$VEnZXT%7<2)@UO2enk*LB)dDOzLZNNT=#`RyuwjNxxvn4E>KIr zaG&iWxP&>c`iZLXlcNW6Yc|<8dySQtR18|V)vL)6kx7nMJm1y}i+)YSL*jM&`+UQ_ z+Vj+parssvIoLvcnN~xPC1V|%`)BY!3iSU`r2jL$>N0?FI}+*k7s*s$s}AJgLT;+? zaS5;Z(c4_gt#PATwOD4uT^^5T#bbJK5Yv+hj>UXar}lu3;iC+7C8apuHTvE%X1ue# z8eu~$Zx18tT5HKVz%=UAcrz`?p=y8msx?S?lxay5KfPCda3K1WWmx~WD89`mMybzd z#lwy3#M&`G78Yz9IwfK-dLr_-SU_NBJsw7Go4)=R33qE2X}xJ&1(I@AjsrCc0m?#~+E0caphd3?BElqcl7m*c>JKFz$UVxm}+|%$Uz+OA4 zVnrezSZzKys=;nTDv$d^o9{93Hit$o4dSMv4t4UTxa8Nbt`VZoU6@8(>eFT~3O8zs zv@P~lI3AjKp-2j#M`F#Qh-wosJG^2t(~JsXAOd@^N(88lbw`g*{?gE0-8-m6gYg=-mSIsI z=@omA-p?Wd#dsrj%BDqCyNa)dYgcNfWFFZiIZmCpC95<0ste7N~?kFGlWqpuO?C$8ZBU_1g~QkaivC{&;+$wGs=yb4Nv09XQa{zV`4yael|R zRJF`^e%c;g(_ZDX1*$II)SuThcTdqCR-a>lUJbWS(AlY>TEsg$!Fnt}}1=+}Cz zG9%3OuU2Q;xH6EE-(=@v*)?4?s0++J8ZtKu9sq4DSZT%p~zne-#Ltz$q}lVdbW%%W(Bgh&4(8wu3pu# zK1PQUv1#}R*~SR6?t0Qa46A5UxT!WNsHO4qe7q1Aw3r?A1Rs#-ZZ&wkt*fNNLrM{B zv~eKSLP676F89b4vdG8{=#451%~)K58|_Uas9e{yQ9NkX?P9N8B%7Ba-9M}Z2?L<}`{-=^$QK??;K340{}#|1 z8~xhS4+f7w`xMH92OTFrLgy@*(q@O)#!yt#`?j_Ha#hD8-JHMJ*Er)*JRX1ZL!Ha~ zl!uAf_T=#D5X=I?4SiPoJl7tI^|RvcW|3H@e3G);b_kN`DT(G}q8aVR==|N$Pj3Al zH%bW|AYs*TgnIAlWNHF%CgiZqYX+3fPTwY41kdL2y4~vfLz|$fh@I<&jMbmZa=X;v zwGL13-P*M1n!6I%O$O|m;2^fyFcl7{{Ix6hyIqK+7a`BZ86`NhcDN{G_3Bx|V+cfY zW*vb&soRb&m>Q|@8utmthL(XFFf6NjYjZFmq5#kw2o_)GTa3baBp{Wh|2w6jJc%|9 za`Ju6rOEJ^;3!-yL6+gEeNH{7}xiy#4X#q8hsq!6dg7aB2 z1r|Y6A{ve{Q#cFXz-@#WSP&mgK$v}m5O?oP1z8qWwMx-%@<8IgJORRWo`Re~?AQ0p znoBSIb|}qaz8NoZo|D#?6t-n*G^!72UofJCS+|Rc?YcEM-~iv$A7UGes(SL7k-~LP zk?GY*9F0*R<$Qma!y?j7;W)VJJyxO>J=}4pPaciq4cDgaa@GBH4}J zq{`Iu3aWPhGnf6q`pR_c;6*H`?t!d%SPOXSi%n?W zyOfVZpW~sy61{sf5T0USXdxJ2=Zo!{!zbnZMGB3vR;>Q?d-GDzIDdu%4aWpx8JDzn zlj>ab+MC{1v*vYv2z(>vdklWtP~$nE(GGAHxTzhwTa399ltQN+HRRx$QCL8*>d2lyZ7zhdd4dFYX`ZK4fij9kG5Uy=o{c;;HDCR2fkwPg@x$X| zDMoLb?_!Y0c*}RSXNeYBTK%W_PVSyXS|}ihaH|VkVdeV01Z`lb_5ST;4JiEm;T$*% zagvL6vG)R6=KaKg{^Qwd{a|Hx$QVoDY^MA2Z{mHk+fh2066u4lH;tv^6=1A0c)dWS z8ilE5p%VyvqNZ!RtR=Vr(Xp88jscNxnjUp5!i~ltI)!xZ+UtK2w6RvOdY<=4v4_5YnBi81>JL# zTHR?k_}uzTQ_@FlC)p|lFVPI`128tLgpHnt%9)Lnt+&|ux`5`x#O33-I@XFw;^N{3 zykJ6!5^i<6K5O#r?Ig*XJ=?5|>+60qPAId&*Nq z2CAIUgqxh?z29b&D1HWfzjhUQPJwasWug`c%Btf7x99%K_K&Z8x)?k$)tu#6qYEmF zh8OH@>ix&zWI}0%;nn#^uCFhuXSTP(&VbZ1s4jOW?@KStlyTgdXzk=yl>b6=^ z#!xj{1k=;%sp0stz)On%PpvcOWd$2R**2j~zWDCPPRTpeHm;`+EN9AXko=s)0)~FSt2iRr=cJ~++?Q@k zM`;6#sc`hmx4ZFL2B$8qK|+G#`p>3+dB1V{aTiypni)z0csTA9fEZ-!1_70&%h}6$ z5lcVJ=_3L=$mUijpZtJ~5oMc5&?+vE+8z7C*WC~KFnv%NH-2Cr%w;#6-VVOD-Rhn7 zd|X~J*uXy-kJAwhxovGIaxSh{eDwrOSxYZ}<6`<&N=_x&2KxAt9dH!l0+K&`;T`cw1bP0rm#6Mehl? zRv4SsBd#+zPUs9>W~VQ6z^~Auq8=8gd1M7SZP^`UaKPrTTLxDXF_GCVMy##z zF*O1HFWF&*GiMGAY}CSIaS%IjCQVZr`_$xp=CBga^;=5GD%#vN*CDvWSBQ14RJ0I? z^E%DjxM3Y_0xRGad={VMf^WX?@)Jc-$rHL|C+0hi6y|3Gvq>gj{N%v`tj{azTv( zp!8|28>B`fsbhhGq3yDnC+LCJV%`{Da)*qtJZR#=va@ccL!TU~jvy_S#=xfi`&T=8J9?GCqn$|qb}iy3 zfYnpqYh`_ykoYZZF73*F6-|JjUkvNzi|mKy)^?mo=H1c4pkO6?go%SqRxF1Y5TQyZ zgV_G)>elv55=hDo!o<1`Ol>sXT4?EVrVz*{Mtak2!({J=gBJZ6xq+z5M|e1>daRa? zxbPo)_?zk15dO`D8Z*eQA9P<41vh?H zG8c-|@k$>Fc9NIwwnjPDaIf$Dw61CYy2Uap+J7l`%k)2uig~bZ5hm{IM&GyzYkgHV z@Z05aST_F)yp7uWesH@;NPpN5TD{b$F#gBlXDmi?3x_QkZ(azjKE~%hF^OGH74~J9 zaKCB7RWYOEVqe37Ficaoc*R>i_Rh1ef1#>(&r{NC2W$X$7&N$8p#k&i1@NAXXMRqe z9o^PR+L@~bEu9#?rUjy$)*1^8ozy;qqoT|j@0!QFNU0U4o%gO2uSB6fm}||0XYH9x z17ZIVb=%kHt-{Ey3@f$?VHI24&@eDIC+>f<-=xY*DQY{h=IQ|*0kJkchYS>?R`YWA>(rvp_4K4a~PIj@tlw)}HO-eZ4JV}X0;k~7D(VSNPD+(Ey`zI*Rb z&zN+?SemL1S=@Vl#q(ho%^iN}4N(0F7yi9_-sxmaCALO#JM*&P`d)S|%=;+bwM9w~ zEVN3#@RJ58)P%pLJwEDcF60YFN21J3wH`a$!)g*WZevF7BI70J`W=F5&OFsYMSyDf^qq>_4NifTa;O&pb@^zky;iP#z z$*kVzFRy}90C|=VcNHa$CY@_|U7#5$d~~Lh(LvPl;BwB_UrZSK0+-=D;tluO9`6?# zy2w0oYBk^JN7d<4kPl0;%cnB`d0XTPi^!Q)hJNYB)@SdM+sI7P3$UNSEi!=ul-*D` zC`~OC^_0$xi#l(w5^C+&$DXaU-pl<7-MV|Xk$WD~>)VO>`u&$s6;IwL7zDDy3+I!a zEN_@EmNb6=g&cWqmrj?FLN1j2eVMNA@~W3qG^mwJ6%>=qYHy$wyg>59tuw5Jx^d_b8USK^#VDX`CGsDDb29qs|QdK zg}blaKHO7Ll$$<-sP5~A8$-i$uL-I9daSFue?b{H4vi9#ab>8F!?W_hFm4)4Xb$c1 z^Fiy%8<71T|7LsoQ%e>GQPtshrzYjj#XywkU0upE22w~|yk4SF_jJ$oca_=Z);sRv z`jL81bm9wkDI*Y-jehkSZd%hP0F5JeVNg2u{9cJ$KQZ=8u;~mQ*AI%7zLFlfKFXY_#EkHlJ2n$iQ!`;>p3!94a zai4CV)*BYtn;;t#Y4FW6_&cg19IXWt8Vm)h*dKh|>w#+3Vyt|q?e@q{vaK&vEkFLw z=WIXtr6;JyXvm?|oVBs{ z(x^sLZ9@Oh#T1{jaa_n$*KonH-D5u2!|B!XpUF5ve$SH;(Rk2G~-|!@xvA#52hwlP#!E*Ixwf%ACFjc)|(uBlZ(U ztywi~{0kO^GZ&#w@ctK-66O*?CDv5vYc9TA$C&^?riClBGeZ1u`oF5J2SDXTfJ6|E zqTa7?BLX;9^TkjR!EqFPm;Q6td+|8e!e|{B&fGWE4#REi=e802%r*lVa%UnmIHIPa zpROI{_4@vvFY?KK;NjM2)8pL31mSrVA|NW+p>Y~Z+(jJF z1$;PNG8;c9i{NWts0`BGi>e5?p7~9~Rzj5M#^OAfJ*)hn|134#W>j_v8?VH^g4}m^ z;NMeTo8G(kfReUubztVN>`{TnrF+di`i$8I!$`U;Y;3!w$^5{q`<*5Qe!lfaYPvd6 z#MEl>sQU6AlKdkoDsOmE+v5b&RsSir|MB;zdwQ}3_}cLkI_UnHM|g}x?fD9ACkri; zp73MIsrR9~&}K^eRE6*<=>1TniY2k>kJXHb_0WV3!|S&dSK~x>Mw4@I{?^bH=3M^t zXH|T!t%Xb^YRYp$UtKD)4=3}25t$m-aB^3kT2I2eK&Xto_7`;eA%LWlS`=F)=fXP3 zIt<=1IZ^vI`FLz9`-1Jv7RfEHmw7U zJ2g?n@8U49U>xB>EbWHjC|q$qeb6*v|IdCreZxo>Zt$G7MJ7xbh8QBaQnrK`3Mvma zGa25kmj|55xwc9bmUKw-b0Pi#k~2ZQm+5l927aDArEFBy(!O9s0dJQy7<(~_zP0N( zW!hz8%N?h&N3Ms8IqD)k-B^8_)^POOaSK&g|FPwF^I9>n&8!O0_s|$!yxq@xK*47h zv-@>su<^Y5E41XA^6zpY`24KTz?YXVrS`udq+!=A65-3~WyD$nu3 z|GI&^DuIM(himVDec~~7m`{(6(Zk?kyzIp5ds>oq=aV8pj9!cDCMqpF{^C6mC+?zn z>NSwzg4pVCagR`#Um-T@539vtYAo=FBYbWCRv`XMO8nF%w0V$NHoI5WHwSr81BmE|p zhiH&6YJR4QTKiLuUC;D!phr&A&o9>VHvtytjlsj-0DE(`Rq)m&~fdV2p9rguVC8J);7zOZ&{!3A*u1X#yW! zm*T9lNW)8;_i|3=1ry5%!&;FSolw6 zK0Gm*{`IC37u$J8_pE;VbNqY2cb&!S#Jv2&B(jiaJh{fNUFDv%{fpt^lsA{gTQ38%jHA~EZ-J%qM}S_a@_n_%8OVS$ysiwPy@wgld1Gwg#Q zzD5t$Qp2SVHSrr6nq;T4qwy`T?bHk&w-Z9@7eBcyAphd8QktSEz0m^sJno{q=n6>A z_@6upA?_D$)4ZJhqNP4(!zI-W3&0~j7fV--jp=xl>8X~c%sS>l0;j}VEOmV=3`rKBsW9RSD#~j@cGoI;K8>drCZ25O#i)UVD zXK~_j_t?beoB?uoC(_;i@9gkO=94;_wHN0!I?s$07uh&gqk4j;S`iWQo#y8aX7%T@ zg2jT1)m1KY>*$nG&vJQ|%>K4&ar|vBzlPhj6cnm zYrjX?Ybz4d9~mI;Y!+z@EJ>5SzHbo}cT#5qX* zg|>U5i=bTkqCX;wF5W0`P2&){9i?$ZI`C=w14spuI}PV0^j!kamh{YIj`(OzjI;mH zcGL%McK4LNhvqcPBElvt4?Q1X#~+wakI2L`LGJ64a-)FjS3obG^NpU1d7>XBaWuo8 zR*d_21PyO|6fif~Zi zeR%a=jH69(ZZPK64&lX!XVxTri_?>_QLx4J_&dsVG883EtB}8Afb2%BOPJVPeoa89 zUW7zSAD_?d=2B0UN2}~?y1M60Z3jvG&+9$&pda(!3|dhDi7NHm-C}bKz=_VBRsbIh zHRVf%vd}s2E+qYOs}!y0B%Q#KjGo5eWmdbI)|Q$-HELv(#ouRGss$^RukbwA z#(~e{@2N*vZ*qs@TK8)=JE)in0ZK*zH3KpzTptfEiuirDnX}N1s@t!fc`0n)&+=jmwv|nB;$4M|&p2%mi8~iR*|0uJytTdqZqK}!l zD0P)v$&-Qci{y1Q52x)iZp?*ISoC0$U_}Zu9FQ&KdqY=PiRuZ4ndkLAW6f)5~oCt5Qz-H83qT(_F+*ozlNF9fcKTe%nPur811;P z;bfg9Ajo$n+_GYa(%FF@2OsJ0>0 zUH=pQV?32XwDRJwOj?23`|Y!gmc)@(D0I{uz9Fr2MIQRN*CcN>n2%opwyLy{LpD%N z-CfkBZ zov!FvxUWF@;27JD{?K!^D*l2{7CqwG)Bb0>OMkn75rdbv3ucm^gjYwAWpf-0Ffuqg zdiL`z9YqGrfej@87XX<+X1}1h6-crS4o(2hx!Mwfew-OX5-fTR97N~eX7n>@T@p1{ zGZ9Pb7ZRD)y=m;mn@yM_EUmk?WQ~8%$$>^dZCcF~RfFm&KC-3$*TmYXw~*zAAqGn8S7X=LcYblrtpN7Cyn~MVx=ABDc9Av3?cuVlt3L)Llku$D>+2BU zjGDvS_(!D1b{pOI&RNIiJg{#4zlw(rlT{BOS7dFj@!eSjwCfe%Z(^zo&`T1ycNKCD zrk#H1n!m+d?=SuKw*WLA*lpU7xw9A6j_Xsm@&n#=Vypq0Dw2g=?sCIvur)wYdfq>F zOb10h6UP7t0sNCk^iLknG?kUFp8xDi$9fNmHwOc}`>pRq)(7 z2q_RCkbp>2se&Tnwby&?*YaL_yLPX=dquCP2uQCHq=phgO(77{d)Z{O{hTxN{;>&! zX2AyGd_R29U3SlznKSd-=Xs_)251Sn{IVP72-1m50TOz2xW;Y;1c(42uvIl8oN$Vl zL)`6ETbJvH+~BM6xPw#@P;~y7jRpH`c58sz1R!Qy|8|hqNl(^ZU4?Ov-3mz68#Jec zAYc$sAjFf(0wEB39KS~7L6v-;ADVDz-@R>Hni6J?mZUy8lNrFFVo6fQj2qUu`psq= zusrY@Xx#YRhVQpx)VS%DTPrF%cqQUhoW?&&g+x)54AJSl+f}irh*ts219TS`yz@v) zhm8_8X50uz(Td78;FQ3MHB0Z#{9*m}3om>4S(fb~%<@XaDWU%#i~%F*=w~N`4P{$$_mzEUS%@qbrEU2C|2y+!Fisnh-0)qV*I z%vBW@aBASRsAliR92%BRxX($23;Ab+jui5fc&c5JyXLBj& zM~oSrE0ObTB?YCFl7279FZ&Yo99jOw-Rn+Krlf1%OYkb+UQ|8gf&XFw^dlb5DZXUI zYah&c{0`n{s9LpT={+<2$GtXg{Pc-)b`*R#`DkFKm%`doQ{|g^pPFUh)aA;(uldMH zxoID4|6qFMnslbCM4vE>3U!16C7>MibY|9do1Y$WFe)2aDm%GZwTeFv%8~{S9vGj^rg2K2Pk#& z9W$1EbkFD8Q~XS*?Z`ns^lGDz7O?j6o2D)Lz`S1T z6T~sS>$}{RW?Od`A;73idS5>bed}((ZEdS}x!j1===?%C<}Yg$L4w(-u(0&BNR_$1 z$4QL=p%@_|n9YrC+K@QK&n14bwN^U?;q-m`D(`UCS>NN-nS%X+P(X+{JG)z3Gyw?; zj#^ufx!e+OjMQm)0C09S*n4^?AWq|}^EM$$L9}!C0gJ5lMa5|lUScN`7>!s~o>F2gs+M6Yj@?JqYmA$>y zZ3+p+CyN=vh`4&J<~GqSP(YYdsf+3xEHfC7lt zuI74)GFtx_1&=sk+vj&aG4hpF;Rb~qCjOHd9}VG#zd&vVCTEcwne)QF#0)|h4*z$~ zuEvJBRBG%DVYn(8po(%`@8!KmNeJW+!wxLFv$69E|%DhjLe^I-hkRK zC1z|?c3hsHk7w7FtTwXT$jJOL7^3nFQ2+phfUGqGS#Bf>f;8|OMIZohQPfmM=2!c( z=-iiZ|B6tt*$Hj}&Wm6W5(>c@Iq{2(%$ZR$;H&X%)H=>m#oX9H%ep6A3MH`}6;?#fTI#$mK;F61x+@8anDdr?r_17=0r2^x&pS+;} z6IMwW_8d0nN+;OX-d7$n8ft2Q)g`;HA3E#U>%MXkKP>$*i&7EW!A<7GQuhU3R=^%lwP zUtZW9i2(x;_Q0IOKmY^^OrObv&)#~TLNaG+Lzw{)yP@6(U(T98X864PtmXe_uu6as zI1c7~IoiK&Z{ng$N32@`uHD1G7;9=SO8Rch@EcWq2wI&H+f{NeMjjyPNlxOcRm?#)Td zrjM96ddT9x`?hxgqNmyg&VybyLw&|{A^`{#TvYO&P&|D}S=uO|02G0%Cc5CJVPE78 z``?tfy&Et_fDo?xcixw`a1!y{ovD2y|9|&jgrNPCQUAM+xBNKxt6^C?%K;-0S|c{x zKJ1H8!@j-Qzr6!60*U}5MZH$kyuH zZN04_G)Hc@E$558;a^^!P_)`pHq`uH-WS&>T|#fmG`^bm#Z4S>B+k$C6`7cole5>o z3{*_`e)OO%#lWDj4db)79@JL8pZ!(d@OcyC4sJW%dO%vES6@A1-k6NF|KS}6hR(ax zucb}angJ&_7<7BCODb=u9ri-WB`-AuNQ1u~>(%1`j4=_z3qP?ZJyMpI2>@7fMQ{1c zn)+CIN(zvHAU1%IY40Q1KYrCV`0<06zE&5ePhEILNUIwV0@NP6Y(jXux-$QbLzg`6 z>RvQ-;k~>7*!)Az;)mVgHy;}Ndijv6Ohq>hE;Ut{p_(16acW$iU^UEDnJNmW$L2I-Z1#^nE#ZFx|^wdcF4N- zju)nXI1oz$Q2yA+d#Q*Ta-J{Ao(lkoxG^CB01V4FycyUXR660ygQIUY?z%m`x(5&f zsVRBkWN(sOHs+P;NUwyok8nf)Bu|D6BxkD6jWX68wS_;?8lD3bx`Q&iA{$(41&9~` z?6Fg7;x7S0!Br1HZOLrnyFjP8ID4AKDuenrpIsQ*-CjsgK7 zI0M=D#Q*qy{nZbgINy#^kaR~TemZ#FGYPAwu@ci2etA>;G_!A%pilt!F@jR$G{)Jze1Y~44I(OOs|HUIDS$DoJ@`%Uqq`vD z60UWp(a9bj`_E3J0#K$XcBJiIDUa}hC^rNehg}!8`kAbzMdt8{jqy_)zTqHI5CMQ% zwGsX1CXhuNG@uf!iWRCJXp2nfjS*1j(S(?~Di8&&xlv-ZE`_Q$3xRe}7i%|lnHwVW zd+0l#P({_`zF8j@?9J!_adz~Xw;8(6-q;9xb!wEJXosn# z!=(!*o}3PpZ5;VpBLKMeC~eqnTOYp1BYTt+c-~fw=oEVLWeEr2%SJ~600qjZDC65S z=%v!+34~Ap$<*5A@`@IZKYHUBD}LLj%hma7y&Wo2-Eh&2gwQm3VRa;twX2m zeG2}`h^~-F_&}5!3S!_LJEvs@Rjkz4FUs2etUdacgCp;7dw!8I*FRWCPJVgeyHjpV zIEg!M>`)0am^u*vCL$odZ%iTpPQpYfiohrC|Jx?tLtpwdmqz_CGYMi2kNdF2UtkDB z#df8Y>y0e);jPi}cBe9rGF@pI{|QFxO8@6cQFV ziJZyNIbq-sggj4#A%r5wIQA(-#?afO6MP9(sby=-UINVcy@dzBmjFm)qP(Y`D=lvBvbrv|9p z005x{;Kx|jLIEz{Z6oBa3lJ9IwMt~q>^EJ^0Pq)o^&aQMR!|td^3IVBass&D&nWCJz z$iK0+A!$1G*a#v8tglUpi`-Dh6Kqwp{?6{>$^`COh3M6+#?Xy`(!LoT#5k;HvM!NT zqh#B<5T(?kKa!K7jD&*)++$66^hgkQ(uvDw`pLj<01kjs>U(2Ta6#mc_qR>{kAx8b zwyAlpy9@OOnGpzeN;<9VQ zYHNW9U;&iAA|gNs;?qVfj*7 zz$4&5ePp4U_iFYH@hX3L@S1lpgMbC#Kv3urAVd{yiNkco&!`0e4uJv!cHfh_yYS>k zgd}HC%+{9@_iyOEodSWqETQOtGbG1_pk>f#wtizkHvor#1K*t=a>m?dFQD2$;%d=I z7#IXth$<`Z4K1JC89Eb2;nw}3trp-BV0+5N22zTMc;Y9KQglHl=^#YWwkG$pA5PR>lT|qF^`p5Dd#!$9_}BY-^eSER zVRz_#hcc5vqM*y$GkS9Rw%Oi?20Kx!uB*Fs@M{(|i-O1ELyryrVx`p>j%^icx4!1m zHzficsn2xQ-;*(atkoxm@7&LFDP>cJ1L?PJgi;cGN6~0&;@%hXivQ20^+oP>UgT|t zlmodpfk=dG}-e%a7M;u)$RYu&w3f@4GvAQQ=Z+0RX$ZS-}YafE9wmKrsLn zc)M9rm?W0LYuFd=|giT9G&Q+5D&91(Xe^!dK`u|ib& zp5gtIFH1R{!0FBq7DE8QNJ^7*hAXQCwd(kLE{&(}Xj~f2$zR8(eI3qH;8Sj{bZeET z76$QdjeoylAW31A6lbWlp!Vxmw%!|2R_|te6FiHm-VaC$-~PpulzlJ7hM28y*`x1h zjEn#P-NBs{luoTq)|!DBDwdJ?YvF_2RduNaR|WYGcS@C}_GWYT*H#sh=ci=3k&*em zk)SJQ{;s%Em8}aQwn`giGx%I^`|@PDk&(F|yj=haE@P6*c-++oS!*s}xp5PKiy{5H z2m~&Un##!hN(cgSuKww-n3=M=fkPl&9G z4Jt@5cMyDYNbXuPGG~yRiLrmY+yDSZz+MC!`aK38D<54TBXbtTIXC1XB_kvACn3v? zjEu~mggg=cE4?g?SRQcSfw+?zyw&b>?a9+~mP{XC_0U*A@)zkU3yiKo_7gvhC1`MbSAIEzEe(XzK^&}rWeN(%44 z%mA}cH*e1BolM@{AB^_a0Dz;Rpy1 zDuxfgLa15O>`V{wZmK;}7m_(yY%g!KCK>(pKmoa1>r0BQHYab02u?}oF>T!b*^y?( zSi1g*D=9jC*l}M33k`b;TViIuo*WnHmM8#dOxKK@(o^fO6G|}vW{|mZXIo=Ep`1D} zB_uuyi4+iW)o(b~=$AM&1qc8FXKg`MYe>?N1fgl`(RxE%lJ?l1-P)+j0s_@Y>S`?6 z-D9ybx{%=1Y$XOtDPoYLsif&xg&<;eU~*_e3S=o>66=bzgbv&M_hI| z>8@M$%v>8X21G=3RJ^>)aLJ6vo^`cX+X1P%TkJid{Vfj4s5MGxsVEgj5AnD#Kp}X{ zZNWe(1!%S;iymABm>`8yWklv>Aq>V&0!dDlzy^#)6k^c6zT%NU@QG_OX2wB z+yv6JVCz!7dBuiyO;W7)IDda@!HYASyV-!4N_@!96}83}{u+8PcENV0V_YJ&xEHt$^UQtI{DCOyAz*(KB$ip2|k zu30v1OoUqiupZv?L$M^0_TmDoHu%cNKhtr5Fw}1S%F3u^-%%PI!a3u+J`QAp5M9&nwguO-^v>=I| zzIA^4Qj{XE%tWJe$5-XC96L@R$f~9 z!>;|`{vRJUDgTzo0{wI?<)v6}2oCWT1puJhq>0|bN0kkokwMy@sD;EOCZ-uAfnwHG z@nflB*pprihyqY9e&)wJsT<6PzHw9P6B^Lf+z0@yI@}vEP4yK?alR+-ltGB?TK&)Q zxc3lsr_D;df^)_`_z;Jnt*R6hs*va~PuWz_dA{Ve>W1coXrHrLMnsYT0TF@V6ZhcHJkVn|0z_TE0ImPe&Ua?J zk&ah*Ctm$p`rrs<{Hz&|25$T8sYT1|O0Ab6e%AQgZe%^FY_-9--*`gWAbf#r!a@iE zP$Ds5qizcub*m(}B*|W};DH@)U(5b;RdnEK14tXho?JCVtQH%q(eThWSu8jJ0GPAi zky4OYzl19uO}Ly$f=h5VZ-4X7f_MHo^NA0f4m-v=hVfX1h+?f)E%x-dekdEb!mrbqJ5VO^JE`b$FF)PO4G5`P|07*naRI57vV}v|^30pg@E0b&)5f|CdHK$jZ;tkA_=@p$}{$Gd6{*6jFV=f^kuzOX#hq|%0tocP=iVs~3( z$>!q4uYUiwZpJ@m_I8d7v!y6?_cR01(3|Fsn?Pao@h;JI#$%C@AQ3xi~Gf zs@AB)9=pqv(w72a_@CN$P6TUrQ?({Ig~NalW_TsTM~=Pz@(-S0X?6+GX< zHz;F9Li#YVdB=s`AE?;z;~TR#eODk6dfeQxHCIy#DxFX7q1``uavY)R$TXkUjT>DU z03nubSbk$t!M-NXl-%(Vc>EHsnsv)wzNPd)B|5GgRBA7;!fJz-Lw=D_lD)^=X~75p zkgIxA3pPcEnj`|8R)d`FE&>36k*lt_7M&J`C!mTM?BB6-hXVmZz_Oj|?@V7&P-F~< zV_31_K#ki0ZU=}qOZnOYi;bLp?H)o17{4JCrX-eq`E0!l5P&fxnhMU2rgl%++zq>$ zs5&wvK$3vdYLKh5uWUkXQO)tPAxe6acl^vL1q3T2)LNnCP$K{!436d>Z9Ve-{ef=X zAWmo9`_Zz^>!UJ8Ym}tDY)ywYCNDroOREb%`FB&<J-LhYc`u`{{8rE}`oD@Kp|as7vXtBcPt28Oc4 z*40$mTz)Wi_NO|YWs+wPOJDNiTel|UO;yw8qd&~orrsIqqo)!mldsp!yZgtll9Q4G zYPWoA506DPryd+aMev#YX27ml-#_0Ol@#A|WL=FIIVEcl^X`Op8^7jb=0t}3 zQv!3LTLs0MFaC`wB&zUsQZd(f5Df z*>k1JdFaT#7FMSO`IOM}9_Fd1p8AC!6$l(NgRS3MHA2{+5!Y!*OWU!7miAU<$mqN~ zp7By5WoUNFpm1~5{`Q7yC-F+2^-@kwB%$DJFL$%4ktvag0sz=r%OrJrL{bvBWGPB{{AlwiwV+&C;N0(A9jIHcyc=K z%Wh05HY87qPmObSHCj8{oDM-7oHg{8w+9UhrGyf~_+?-1qv&ob+u7aa3K{$8*sCUD zi2?vthKEM^wwC_bR9O``_L0G{VtbcgbY=orYg*0TG1*xR1q2i^hQyKMg|_mJhC0?i zcl3QPd#f2jL7zN1B1F@6cvoj@vnJ|_arZxNP@q$ML($f3=^~+7mnfOuP!Oejps%XA zwn`H-Os`U!2G0!8yP8UOm^*EOdH0RKb~+ED`4M)7fbNz!&007k8QGd)7J<2!G6g+%}PN-?F zDs!s`=il+qx~-op!lp;W`pC;}{sdx7U{Icuf%40b*RlyvPzf!zlj0etum18}@D$to zq&F$`bkF`T&#TrHB$%BF3rkNA-<)~VlP4sB`ln}s<5lz25B;K+IqAzk5k;bK##O;* z{fCnu*71*>*6@^4gy8gAo>K9CFHg#Wbz(;83=P${l=+NpNGa{t2>ty^)bHB;UP|U8 zn`~@aXp|2CNVe)Fk4*{r+m<2edRcD%1ja{0xZzKCrp_o6=x5(V=%jZpoOPgQi(eo( zEj`OgHT}gcbH)hsS-*mQ@jsm0&c{D?mJ1;CGllH;5}mO#oT;Y0@13~~(HWbs-~XWg zFDU}rT=?Pkz3!}OH|dq``ojPA=%=I%)+5=S8o;p|8JWLC_9?I_w|r|@`|9ouAG;*R zlsM(;f84Aj^e^5iFC)v1%mCCIpppv(jd^hD*atmM7bPHPco}GNLnw%3;5Uk=ju%5s zFJQp|00}@|ZSz+&{W<%rzams@7r`Zf`yzP26u?If9d@~E$;g}mH3vGyA8g%pyWsVM zP--6dt?7{9vpl$KtK6?-WKOeC5Im9&xdDH$+z^1m7TDHu5wxfPHUU=E$z4lE=2S4i z?TP39T^Sh}nLkOYWMpJyWVw-%k&)%*H$#C^U;(&Ow*Q{({quv~^qK&C-yeM56pR7j zfAXIw{SA8XRPcKur zPg^X+Aoc#KmwxsV@W1}3AqpUvb#1i(2wcZTd=MLd@F-9KjPzyCjC^-c-q-)u@1HdO z)7OEQSJ=t?Jb&)0VoU-y-Kt3Xs46-M2-J+(P)Bue+5jP}PUQIWudS%&;1ij}#mC0H zR}v6_D1f^>Y2_`MHI=(&JthM2-uYml`i_G+6HXqlf6_Rlj7sFSXS^F_w4y?JE~X6v zW%KeuTaFgac}C*Hc3r)la7I7?*c`fhfhG6*{c#b9-nKDXakiW`r>U2$O0wMi78@QT zb>l`;>k)>4TbI}tJyP_nI>f}QdWBbKBLaopFSji$7AP1Gz8Yi(q2~Kg=i&OKY1)Pr zI+|A>6A1uZ+cy7(5{7Czd%@M^j0nmjZ-us6 z8QsS4y-kgSZeW|{`?zvjys881Dq9k+bt*X!8hk4^s_iyO71ACx!KuI=GXYx;`PUZl zZnvcH?~IseSMz{?Z~iXOGN?8bg3Eqjk)}IzlG)!!e`JBlY!~lioXA)rX4sD}?xz4?GgPh9cees-=nk9IZPWn))V(gEj;l(|@-1DcvAf;+#Fm&* z5(2({VMO@`O2zP^_dDaS)l@CD2VQA5aRCQDRS}KUzA8dYYYglRY7MVW$pS(FA!MuY zuiB<`32t3nOH9556c92V{Y`Zm%Wel%mud_% z^MBckA7TgvMhsq^pSJk}tV_35OU4G*Hv$4`-xP6hLCmrl2B*fM5W;polCo<#AfSwv zk-C9M1gk0S3O@9ysiO-3QI{ znEGK4d#$)`$iit>W0=i1yDf53XK)Az01~yu%(d@dB>7%aH)tFn0EUOQ#SOCxI7 z0yaFtnQquVfrKDHEVONI zzHY5q2@vUL{QS0H)muA9oM%Dgpg$z_Q< zE<2Dj6c`0`Z#^{gYX>JExhKobxufU`i3-{IWDs{pw;|Nw715X)0TKX&)@IDnH6HYD zX=X%`?Q8)mVnP5(9%-ch$6jJqXa2Nb?H5O2-|$C>TFqAiq0dL0s!MO4Z)=gmBKWq z|KvJFnXz&;@9Y7LS%&4UJ)VQpu{OV310VwM{vu^M!{b2&0P0dIu;l(JZv@%>YCEj4 zIT8gR0IXj_Y+yhQ0Fc14GFR{{+I>Vr0RR*Kal(!dO^&D90T3VGW(7_0D#!k5#H@<5giItlr*EAvew9Q^P9dcLC1)1 z4jSK%*>+Eq!~tj;M!Z!O9S36h;Q2RcmGQO7mpPO=#Qx+Y6X{X7xgJmA4g^3!QfuHm zlpBNqC=k>YeN9)?YybjC3M~9b^roBKnl-Ja)54+(|K34LEj&@GivN+h=R}K6xXU1ATN)f^HpaV+V7wmMeP6Zb{OZJD2+ai%V%3%Pk^pYVaG)q5tHlrF^9eVtW1 z|M*8ScBvhnyC`Vy1L$?JfA!Qh>1L4Dd+T-HCj!kxH25Rh+ZwXe$o%Fg38UyteQ;OW zgIw29L-qd>H{D?gSSeI5)-tBzDWBO?02I`&{ZQL*_F=3NSb_H>C!qic7@Ot13>CZ7 ztp}(n+rfDx00U*3GX5TQ^bU1b4VccJ_yu{nvC}!Gup~;+I}L{cC;;h7+WMt4b^g8~ zgFpn}!K?5-_3tou!?`)CbGre7Cl5Dg=>$Lkyi-A)(GTq&IiK)I0U!Xx5mZ-5 z5YUqjn(W_Aea*fKefjp@-tR8+ZR|N8n~Ind*58;^xEzz-<3a&}qP-j_b!+^3t3v6i zazO#Wrz6bYSo}2>0Ym@^G}Q&BW;1}36M2Wx2P6OrOwES@b`_%JHw%uoJwT(a-sdSJ zNG-uf+bIG7)EpP7J-SKZ?kxs3@9{rc{h{dY}F4KmZT{M9I5!x!&xM z$C%9TWZiJysO{Uq<*Pfw$2fVSuP@N3<4cTM0jIOOS0!wDx!uV7S1fCZpU5>VkKFrF zb;eZ=a0eZDhv`VG&b+-Z!U$~{_e89HY4Dm|-Fk)hvHi}_XmFfwrZ)xbUy^rs_Ugy8 zTfcM|qg^ajbyul7k2(@wY6|oLa5ypRU-MOrw68Jq(SDcWFDVYneZH*j7>_>cSHrbM2X^BYqiAoE~5F{4FZ+N0Ra@NoG zrOND^b5{K;!?mr$H$c-^;Me3Voi))S4>FnKzR)jE{L&-9!eda^KNADNJu!2wN}{wj zux__KVB+EY|8uhlvC!P6cE=LmcZCMSY+%98A7Bs%qDaMM*u|tlq$pOlE#3uNp0&S+N7%7XIp%X zK&U-riW|&oOCvGnm*&i}d8f0kW>AE8>lhx#w1-3k1prae(`^mSbtn`7fZS$|5AF;c zL{DD5g56yV=i3>SMGycN(i)n=I@>q_wPpOP&QHlp0i7XnK$Y$B)11hv?rFk|sb$ck zRf(BE0HiLZ=-VEe-mCGFSt$i}gr!lSE<*wl%&f#(gK|W$S^b9FbQ%DOw{|#!^Qp*=VfD3uJEwXs>8wOZw{2&NH-FL}O8!vG-G*&=Du&3=LMcpCs9fY~t+cTSlY ze#L2i4K}!{;9@!N=Fn_NStxfc8JRQ0UzU!C%ftWt*o};gjEpQdGBPr<+{nntT%`QE znJK3PzijXC1&#m&E{>YY$oxtO0&=eN#=jy|+-e7l2t60UAS4u$4N%rCcP$y2(B4x>fF4GBRh78^3d1qw?#VDYFCGE&{m`BoN6(QBxV2 za~mM%h8!xEk&*e6kmW{3Mn;w!85x;@1uHkfUkIhZD1ilVIVk{O7IFPEy;C3(i0;1!{h|Fido_ls_Lf6px+{1~e&DtPYZ8YiINkiCE+U|9R!j~_F; z2?9Whz^mRU$)6Da*Qo*k{r&UcQ3N10ZU5+1yWFVX-k!RyQtpbhapZ&g6BMta_dLPEQ#c zcb*&elmf#;=YbU!`wzH9&;$-j9(@^)C?Kd<`;s%@=1BFfl3lwb4ZxDmpDF#|v;Hl_b#e*FV^2i6`9ogCAzBoy<= zd}z&);@vKh(T3-wj2Xj<6aa}e-)%3#qh^dewB$3hMbd`lq~u@1xXru2d9KM$#Rbnd zB~8rEj6b;YU2Vcmu?c>_fvdK#Wc!bHhotmNN*ps?%TWrbvf!m2(+x3Rdk^g>6hR+6 zd`?WXzbH`#yK1*DtgEUfzO?@Y+}ZeqG=Y0BS8?SGwlI zf>pbHlJc}rw&AI%rENfwMsk)N{PqL4=eHa|Zj&C{4bk`006A}4sTnq{_(jz>cpT3|6{8jTlM+Zm{k}} zNG3daj*KJs~L{gZPtg~X-BTGM-hnSP>E`-F&Pi8FrbwaUh=uP=V=E{8}lgBq9IyzIj_EX1f**-O5-@te07N(ivh+o&g^$ml{6 zytGPLY6hHjgMhf*DOWs~GHDz~fl=JN<=(6vMRn81#~{qoy6ur~Y>4y%#Ew&UZ(g;2 z%jo<#KJmU_eg2*w8pe(Z1_rD}Z(97WPmKg{pYJIaDWxP}i+NAfE-?u)xJJtloZ@&5149e?*TDF8uL#a3h_kzJXkU^3M2v!hK%@yELX!#FEfZ}7ir;lxqVZV@srn^U=`98)S(FJHgz=&*YiB*yv? z3TZ=E6GxB!1=toB-na-Zv;h zOhnG~#siy6*6egST}14WFmm@e0MtMPK5z`j08mOP$EuWq!wdjk>5~Hf`)T=+%D`bs zl5>BjuF^8DntSN5@IL;0Lq%; z{aL25xd!7T03du+e1wV+N&#_^6ZG`+>ShQw^hQkjnGYD;6h^~H2ojDLkPu~X zX3D{D9^K)-J}^AaH#{aTH$W7i`PgB^v)Iwtc(@(_Sk`EeY<11;kwIRb^bwSJ>?~Pp z2A13)2APXqSpL~EQ^uTxv?N~5S+|j%zF#NGDzRsLocJ36(WLxQ+h6^@%j)#**?dgU zO^l6~2%PtQ15x7M^7`zGCLv+WT))sLbx+*t6 z$@aq=_Jr9ndLY72m~jYUXYJ1KIYa>fE4^dqew#Wp8QdoYH6*u{QVq|0@>U>{MtNF|F~RH@W`mMS2XiW3}G+N(atYeajcM1;({zxP`H zV$tGf+=3{HUc>JBG(I*EoyZ`JkZ4}>^sENKlrr{e?=Yie#{J?t1S@-woFsykGOEL0 z{k`Hu$&l7FoP#q++=Px|lFX_=w`jFL8dDgNBF1Y+anq#55T+TS|Jv4!=!(%YN;9kLJn z@es#>+KS4Q2X|-3^OS;QJ-qwpVlY$!uc40^7tcLhc}vsUqlr@V-qFxm`t90z z_XZ}e&?(ix=_bFp%Bbr1T^9&M9?kd-4|b?D^<$mr9Zd#y?>sP)Sh4 zO`G1b=JT?m?NPIC`u z<|?(bvDAdqUdd?b02{-BeppwP#ub$rd19fSapfVeFC7k|;*>gewQ zVX_ z`3t32U{#tiShN4#xsJ>sEqj;X^d}6yN9vaS%jo@Yd{%P+0a9eO8ZPl*JOngV>o=w5|kNRLh z`Zzt)zV(fJkEM;zn~>R8I>qoAfBWXGCzsiFh6F0=cdYGDjGZ-W%vnpQj&fDr_Wff^ zf|Exnz+8858&41Zi6jtZnIvoRWXtNw-r5sx1X8pIsf8GDfeVEoGZ5rlhzaBT`Qq zclnYv@6E1G8Rz3AH0)hxQ;dxpe-%)`h7>jX$qz3+;Fon%{v}C7&Zu{u@hcL)2n3Fq z!6x)~7N|a9ipfhUIvtwuOZwFJ#{d8WPDw;TR7Opk?iDtShxI&N%54PcYzy1A=MvB+fEJ@V?|U(E{CZoK**?jhm9T_ z;O{RXRu`FJP*Gh_x^IxFH+n*eA#|`$pwScdPzP$uzTc2}?~{H?<_tHJBxO))Kv=lP zHefY@0deU({z<)|R2@4ZHYuLiI|<_zmVd{XnU^sV1%zn(#-iQg6)%3ycUL>9J~ZdX zArr?ULMieIPKsa{P8XQ$ALK^}_KC_g7}Z=*R!YtgaC8Yo5s)=2|JoZ=KmiaXk}fda zFW9@cMnv)o8SE427cqQ>mtIFC0V_>mIdg|kosLQWbvG38hWLyuOhl3JQ4=1^%FPJ$ z(Tl(tqO-L;7{fD6zIp_RQmP0$>wV_b0VjUOd+Mcb_tt)w{4qIAeI<)s;h(3u>f6lt`=aj#Ly6q3peB~h!HJ14 z^FQyc()Nzpx4$-bX5BgE^#(8a*RKir_v85c?Q#FFwSU?qJk!4K<3)iwzshC*uGj{1 zC|(NPu|MJN#@N?9kMDPJJGw}1*v%s7^j6hdtNYsYT+0a`KSZ%D{#=_nvFFTBncY9X zIt#2=y>abA-I6<-o%LkBjxg>MIDM<=#-j`UKdzrTBBB5A{K_?IW;z$c?-{EU&-=&r zU-ewb`_rGlUjJ8Kx~%H|fB%TGvPXUO=l-Uoq`%_dnx|6r?)a2%v&_Yr=84K2%Ab4P zp}y+q#n!9mjKtHXJhpzVnA9< zSj~O)OwUXRU3#u^b2tGN#R(~wN@kKs%j%GJNx9HOFucW3=GQ+groU=wG@e_n|K}3z%F`$E8;-P6YoNyti=jh!)Y1Tj`OwKVQ0-|xA5(~o_OO0z(hDg95Zj#lgBj@Bj-S(~ zu!Dzu#1N*@EfwO?&I9|w3a~c}F_|3#s~42bnTK=CVyh#kt34+ERDR-tW~ZiQTga!x zCwAv=Q6sy|v_}}<=q8+&7-C>ueRPP){J+9}3GOju1*oSStV}~RKL*l+)uuJg!jqh= zh8TFdXJ;5_@~G4Ljh|-4XE2dtCbPV+#u^H&Xk|P38vcA%9zDj|r3l`?tf!BhD)_u* z4(&Mvqqn)7DvUMRnpX<@qlc!qnw{e6b^0nNiu(h^fmd}ws@0G@o8IlJ1S%c!eGv_1 zu&_gHZ>xjME^$@&j!kzf$$PixbpY<>64%#0w?u;zbr71{pr*_knUp0(EJ_|&7(=EZ6O>vg@r zTiKpI<$6c7bXjONMO_lZ_*WPJDMZ*|ag){3Bd^-F;DG^g4yGxMdyS;!Gpo^x;Z8mKW69v^m8mC5Yt23;^n zlv;mIHU@YRL0wl4WLmm?+l{Ofy`!JvvV$_xdd z99-(L)k-RzmBM?aJNS>xoc%HIC9P|Bvy$iTtJT-EVUx9(wbwsl+`9P36t>#s3GT2C^CS(US?Zxd;qN z9w9-a^~Ry)jK^?0E8zwu%8a}n^47eg$~D5XXS>;{|G5y%yQ=|OnSK-U4$tXxm0rvY;Hy}iMSwIb4d2z9!%+U39rm6p{*kW9?WGP-3fdYfCkNr!Y$Y}+v z?y1+)FaX8|m*)@Odeqi!`aDw;Y5=C<>XoIK z;L$~6qnQGJpddM;3W?KlEqRkV;&{RSjRvLR_n_8YiZ8(lFv;AiTEU+Wj-MBVF$}gy zt_sE}XVCvD7Ozjhc_F~uZYL)dS7kii&1v%FXd~A~2)~c~RV16??ijzRt1{GHvvw~M zYV8r*`EM^jSm`~4n3DD+8`}@*B9_8$2%>AZQ>vNKos6DLwksA@rDFwpQ5Zz(mQc*B z$jjy>=X`Gf5N8w`d%MAOOQm;x>}YWg@_$0f??<+<5xL1)S+IIp9ULj+-1@ko?~4cd z{L+RMhai7%WJC$T^wwi)Z0ZP#EDO@R@~6Ixq!Jn4i|%wSsC>f|{6@nvzq#V|*r2Ao z$ZyP=QS~()AdQe2;|miv^D=)_n8?WUuFNNcII z{3FYE%+9U>GWQT_ZNO6Jf?!!)va2UxO`Mak3jln#c`up8Qz|FFFFqo~gf>z@1K5@) zF9}VO$IsA6O@P0^2HnHzGLpTWe(4c(znfb)4!ahgj8L`Mx5b^~QSnHo?b9K}WAOwT zt!Y-v;*t>(NPi1^XXDJVZB0be&Gn70x-Po|S}50%k|<~C5KNI!&oWHJ{V5dFh4n}i z3+OFJ0yOQ>OPG*x*vP}Shse)a+8VIBbg{@ALesF83!4)hBm@O}y?eu*Zp^147bF>% z^pz>cpJMWSJ| zapaLn>U8b&WDwb&t-}K;gFMJ-ZkL0-